C 参考手册

C89, C95, C99, C11, C17, C23

语言

基本概念
关键词
预处理器
表达式
声明
初始化
函数
语句

头文件

类型支持

程序工具

变参数函数

错误处理

动态内存管理

日期和时间工具

字符串库

以空字符结尾的字符串：
字节 − 多字节 − 宽

算法

数值

常用数学函数
浮点环境 (C99)
伪随机数生成
复数算术 (C99)
泛型数学 (C99)

输入/输出支持

本地化支持

原子操作库 (C11)

线程支持库 (C11)
技术规范

动态内存扩展 (动态内存 TR)
浮点扩展，部分 1 (FP 扩展1 TS)
浮点扩展，部分 4 (FP 扩展4 TS)
外部链接 − 非 ANSI/ISO 库 − 索引 − 符号索引


C11

< c

ISO/IEC 9899:2011 ，又称 C11 ，是先前的 C 标准版本。

过时

移除

  • gets()

新语言特性

  • 多线程环境
    • 原子对象（_Atomic）
    • 线程局部存储（_Thread_local）
  • 增强的对齐支持
    • 对齐查询（_Alignof）
    • 对齐强化（_Alignas）
    • 过对齐类型
  • Unicode 支持
    • u/U 字符常量
    • u8/u/U 字符串字面量
  • 泛型选择表达式（_Generic）
  • 不返回的函数（_Noreturn）
  • 匿名结构体与联合体成员
  • 细粒度的求值顺序
  • 延长临时对象生存期
  • _Static_assert
  • 可分析性

可选特性的功能特性测试宏

  • __STDC_ANALYZABLE__
    • 指示支持可分析性。
  • __STDC_LIB_EXT1__
    • 指示支持边界检查函数。
  • __STDC_NO_ATOMICS__
    • 指示不支持原子对象与原子操作库。
  • __STDC_NO_COMPLEX__
    • 指示不支持复数类型与复数数学函数。
    这些特性在 C99 中为强制。
  • __STDC_NO_THREADS__
    • 指示不支持线程局部存储与线程支持库。
  • __STDC_NO_VLA__
    • 指示不支持非常量长度数组与可变修改类型。
    这些特性在 C99 中为强制。

新的库特性

新的头文件

  • <stdalign.h>
  • <stdatomic.h>
  • <stdnoreturn.h>
  • <threads.h>
  • <uchar.h>

库特性

  • 多线程环境
    • 原子操作库
    • 线程支持库
  • aligned_alloc()
  • UTF-16/32 类型别名
    • char16_t
    • char32_t
  • UTF-16/32 转换函数
    • mbrtoc16()
    • mbrtoc32()
    • c16rtomb()
    • c32rtomb()
  • quick_exit()
  • at_quick_exit()
  • fopen() 与 freopen() 的排他模式（"x"）
  • 边界检查函数
  • timespec
  • timespec_get()
  • CMPLX(F|L)?
  • 新的数值界限宏
    • (FLT|DBL|LDBL)_DECIMAL_DIG
    • (FLT|DBL|LDBL)_TRUE_MIN
    • (FLT|DBL|LDBL)_HAS_SUBNORM
  • 线程局部的 errno

缺陷报告

Template:c/language/history/DR11

编译器支持

Template:c/compiler support/11


C17

< c

ISO/IEC 9899:2018 ，又称 C17/C18 （分别代表完成和出版的年份），是 C 标准的当前版本。

C17 与 C11 相同，除了它将 __STDC_VERSION__ 预定义宏更新到 201710L ，含有数个缺陷报告，以及弃用了一些特性。

过时

弃用

  • ATOMIC_VAR_INIT
  • 对以零大小调用 realloc() 的支持

缺陷报告

C17 中修正的缺陷报告（ 54 个缺陷）
  • DR 400
  • DR 401
  • DR 402
  • DR 403
  • DR 404
  • DR 405
  • DR 406
  • DR 407
  • DR 410
  • DR 412
  • DR 414
  • DR 415
  • DR 416
  • DR 417
  • DR 419
  • DR 423
  • DR 426
  • DR 428
  • DR 429
  • DR 430
  • DR 431
  • DR 433
  • DR 434
  • DR 436
  • DR 437
  • DR 438
  • DR 439
  • DR 441
  • DR 444
  • DR 445
  • DR 447
  • DR 448
  • DR 450
  • DR 452
  • DR 453
  • DR 457
  • DR 458
  • DR 459
  • DR 460
  • DR 462
  • DR 464
  • DR 465
  • DR 468
  • DR 470
  • DR 471
  • DR 472
  • DR 473
  • DR 475
  • DR 477
  • DR 480
  • DR 481
  • DR 485
  • DR 487
  • DR 491


C23

< c

下一代 C 标准。

参见：当前的 C23 国际标准日程。

本节未完成

过时

移除

  • 补码以外的有符号整数表示
  • 旧式函数定义
  • 混合宽字符串字面量拼接
  • 对以零大小调用 realloc() 的支持（行为变为未定义）

弃用

  • 旧功能特性测试宏
    • __STDC_IEC_559__
    • __STDC_IEC_559_COMPLEX__
  • DECIMAL_DIG
  • 下列数值界限宏在 <math.h> 中的定义（应该经由 <limits.h> 使用它们）
    • INFINITY
    • DEC_INFINITY
    • NAN
    • DEC_NAN

新的语言特性

  • 十进制浮点类型（_Decimal32、 _Decimal64 及 _Decimal128）
  • 二进制整数常量
  • u8 字符常量
  • 数位分隔符 '
  • 属性
    • [[deprecated]]
    • [[fallthrough]]
    • [[maybe_unused]]
    • [[nodiscard]]
  • 函数定义中的无名形参
  • 数组类型与其元素类型的等同 cvr 限定
  • 单参数 _Static_assert
  • 标签后随声明和 }
  • 新预处理器指令
    • #elifdef
    • #elifndef
  • 舍入方向的语用
    • STDC FENV_ROUND
    • STDC FENV_DEC_ROUND

可选特性的功能特性测试宏

  • __STDC_IEC_60559_BFP__
    • 指示支持 IEEE-754 二进制浮点算术与要求的数学函数。
    此宏取代 __STDC_IEC_559__ 。
  • __STDC_IEC_60559_DFP__
    • 指示支持 IEEE-754 十进制浮点算术与要求的数学函数。
  • __STDC_IEC_60559_COMPLEX__
    • 指示支持 IEEE-754 复数算术与要求的数学函数。
    此宏取代 __STDC_IEC_559_COMPLEX__ 。

新的库特性

  • 扩展的二进制浮点数学函数
    • 本节未完成
      原因：列表待完成
  • 十进制浮点数学函数
    • 既存和新浮点数学函数的 -dN 变体
    • quantizedN()
    • samequantumdN()
    • quantumdN()
    • llquantexpdN()
    • encodedecdN()
    • decodedecdN()
    • encodebindN()
    • decodebindN()
  • 浮点格式化函数
  • POSIX 函数
    • memccpy()
    • strdup()
    • strndup()
    • asctime_r()
    • ctime_r()
    • gmtime_r()
    • localtime_r()
    • 对 strftime() 与 wcsftime() 的扩展
  • 对 fscanf() 与 fprintf() 函数族的扩展
    • 分别为 [u]intN_t 与 [u]int_fastN_t 的 wN 与 wfN 长度修饰符
    • 分别为 _Decimal32、 _Decimal64 与 _Decimal128 的 H、 D 与 DD 长度修饰符
    • 无符号整数类型的 b 转换说明符
  • timespec_getres()
  • 整数类型宽度的宏常量
  • 浮点类型的额外数值界限宏
  • 库版本测试宏
    • __STDC_VERSION_FENV_H__
    • __STDC_VERSION_MATH_H__
    • __STDC_VERSION_STDINT_H__
    • __STDC_VERSION_STDLIB_H__
    • __STDC_VERSION_TGMATH_H__
    • __STDC_VERSION_TIME_H__
  • _Bool 类型的 true 与 false

缺陷报告

C23 中修正的缺陷报告（ 8 个缺陷）
  • DR 476
  • DR 488
  • DR 494
  • DR 496
  • DR 497
  • DR 499
  • DR 500
  • DR 501

编译器支持

Template:c/compiler support/23


算法

< c
定义于头文件 <stdlib.h>
qsortqsort_s (C11) | 对一个范围内的拥有一定未指定类型的元素排序 (函数)
bsearchbsearch_s (C11) | 在未指定类型的数组中搜索一个元素 (函数)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.5 Searching and sorting utilities (p: 354-356)
  • K.3.6.3 Searching and sorting utilities (p: 607-609)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.5 Searching and sorting utilities (p: 318-319)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.5 Searching and sorting utilities

参阅


bsearch, bsearch_s

< c‎ | algorithm
定义于头文件 <stdlib.h> |  |
void* bsearch( const void *key, const void *ptr, size_t count, size_t size, int (*comp)(const void*, const void*) ); | (1) |
void* bsearch_s( const void *key, const void *ptr, rsize_t count, rsize_t size, int (*comp)(const void *, const void *, void *), void *context ); | (2) | (C11 起)
1) 在 ptr 所指向的数组中寻找等于 key 所指向的元素。该数组含 count 个大小为 size 字节的元素，并且已相对于 key 划分，也就是说，所有比较小于关键目标的元素必须出现于所有比较等于的元素之前，而且所有比较等于关键目标的元素要出现于所有比较大于关键目标的元素之前。完全排序的数组满足这些要求。用 comp 所指向的函数比较元素。若数组未依照与 comp 标准相同的相对于 *key 的升序划分，则行为未定义。
2) 同 (1) ，除了传递给 comp 附加环境参数 context ，并在运行时检测下列错误，并调用当前安装的制约处理函数：
  • count 或 size 大于 RSIZE_MAX
  • key 、 ptr 或 comp 是空指针（除非 count 为零）
同所有边界检查函数， bsearch_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 stdlib.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

若数组包含数个 comp 指示为与欲查找元素相等的元素，则结果返回的具体元素是未指定的。

参数

key | - | 指向要查找的元素的指针
ptr | - | 指向要检验的数组的指针
count | - | 数组的元素数目
size | - | 数组每个元素的字节数
comp | - | 比较函数。若首个参数小于第二个，则返回负整数值，若首个参数大于第二个，则返回正整数值，若两参数等价，则返回零。 将 key 传给首个参数，数组中的元素传给第二个。 比较函数的签名应等价于如下形式： int cmp(const void *a, const void *b); 该函数必须不修改传递给它的对象，而且在调用比较相同对象时必须返回一致的结果，无关乎它们在数组中的位置。 ​
context | - | 附加信息（例如，对照序列），作为第三个参数传递给 comp

返回值

1) 指向与 *key 比较相等的指针，在找不到元素时返回空指针。
2) 同 (1) ，除了在运行时制约违规时也返回空指针。

注意

与名称无关， C 和 POSIX 标准都未要求此函数用二分查找实现，也未保证任何复杂度。

与其他检查边界的函数不同， bsearch_s 不将零大小数组视作运行时制约违规，而是指出找不到元素（另一个接受零大小数组的函数是 qsort_s ）。

在 bsearch_s 之前， bsearch 的用户通常用全局变量传递比较函数的附加语环境。

示例

#include <stdlib.h>
#include <stdio.h>

struct data {
    int nr;
    char const *value;
} dat[] = {
    {1, "Foo"}, {2, "Bar"}, {3, "Hello"}, {4, "World"}
};

int data_cmp(void const *lhs, void const *rhs)
{
    struct data const *const l = lhs;
    struct data const *const r = rhs;

    if (l->nr < r->nr) return -1;
    else if (l->nr > r->nr) return 1;
    else return 0;

    // return (l->nr > r->nr) - (l->nr < r->nr); // 可行的简洁写法
    // return l->nr - r->nr; // 错误的简洁写法（若给出 INT_MIN 就会失败）
}

int main(void)
{
    struct data key = { .nr = 3 };
    struct data const *res = bsearch(&key, dat, sizeof dat / sizeof dat[0],
                                     sizeof dat[0], data_cmp);
    if (res) {
        printf("No %d: %s\n", res->nr, res->value);
    } else {
        printf("No %d not found\n", key.nr);
    }
}

输出：

No 3: Hello

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.5.1 The bsearch function (p: 355)
  • K.3.6.3.1 The bsearch_s function (p: 608-609)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.5.1 The bsearch function (p: 318-319)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.5.1 The bsearch function

参阅

qsortqsort_s
(C11)
 对一个范围内的拥有一定未指定类型的元素排序
(函数)


qsort, qsort_s

< c‎ | algorithm
定义于头文件 <stdlib.h> |  |
void qsort( void *ptr, size_t count, size_t size, int (*comp)(const void *, const void *) ); | (1) |
errno_t qsort_s( void *ptr, rsize_t count, rsize_t size, int (*comp)(const void *, const void *, void *), void *context ); | (2) | (C11 起)
1) 对 ptr 所指向的数组以升序排序。数组包含 count 个长度为 size 字节的元素。用 comp 所指向的函数比较对象。
2) 同 (1) ，除了传递给 comp 附加环境参数 context ，还会在运行时检测下列错误，并调用当前安装的制约处理函数：
  • count 或 size 大于 RSIZE_MAX
  • key 、 ptr 或 comp 是空指针（除非 count 为零）
同所有边界检查函数， qsort_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 stdlib.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

若 comp 指示两元素相等，则它们排序后的结果是未指定的。

参数

ptr | - | 指向待排序的数组的指针
count | - | 数组的元素数目
size | - | 数组每个元素的字节大小
comp | - | 比较函数。若首个参数小于第二个，则返回负整数值，若首个参数大于第二个，则返回正整数值，若两参数等价，则返回零。 比较函数的签名应等价于如下形式： int cmp(const void *a, const void *b); 该函数必须不修改传递给它的对象，而且在调用比较相同对象时必须返回一致的结果，无关乎它们在数组中的位置。 ​
context | - | 附加信息（例如，对照序列），作为第三个参数传递给 comp

返回值

1) （无）
2) 成功时为零，若检测到运行时制约违规，则为非零

注意

与名称无关，C 和 POSIX 标准都未要求此函数用快速排序实现，也未保证任何复杂度或稳定性。

与其他边界检查函数不同， qsort_s 不将零大小数组视作运行时强制违规，而是不修改数组并成功返回（另一个接受零大小数组的函数是 bsearch_s ）。

在 qsort_s 之前，qsort 的用户通常用全局变量来将附加语境传递给比较函数。

示例

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int compare_ints(const void* a, const void* b)
{
    int arg1 = *(const int*)a;
    int arg2 = *(const int*)b;

    if (arg1 < arg2) return -1;
    if (arg1 > arg2) return 1;
    return 0;

    // return (arg1 > arg2) - (arg1 < arg2); // 可行的简写
    // return arg1 - arg2; // 错误的简写（若给出 INT_MIN 则会失败）
}

int main(void)
{
    int ints[] = { -2, 99, 0, -743, 2, INT_MIN, 4 };
    int size = sizeof ints / sizeof *ints;

    qsort(ints, size, sizeof(int), compare_ints);

    for (int i = 0; i < size; i++) {
        printf("%d ", ints[i]);
    }

    printf("\n");
}

输出：

-2147483648 -743 -2 0 2 4 99

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.5.2 The qsort function (p: 355-356)
  • K.3.6.3.2 The qsort_s function (p: 609)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.5.2 The qsort function (p: 319)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.5.2 The qsort function

参阅

bsearchbsearch_s
(C11)
 在未指定类型的数组中搜索一个元素
(函数)


原子操作库

< c

若编译器定义宏常量 __STDC_NO_ATOMICS__(C11) ，则不提供头文件 <stdatomic.h> 、关键词 _Atomic 以及所有列于此的名称。

类型

定义于头文件 <stdatomic.h>
memory_order (C11) | 定义内存顺序制约 (枚举)
atomic_flag (C11) | 免锁布尔标志 (结构体)

宏

定义于头文件 <stdatomic.h>
ATOMIC_BOOL_LOCK_FREEATOMIC_CHAR_LOCK_FREEATOMIC_CHAR16_T_LOCK_FREEATOMIC_CHAR32_T_LOCK_FREEATOMIC_WCHAR_T_LOCK_FREEATOMIC_SHORT_LOCK_FREEATOMIC_INT_LOCK_FREEATOMIC_LONG_LOCK_FREEATOMIC_LLONG_LOCK_FREEATOMIC_POINTER_LOCK_FREE (C11) | 指示给定的原子类型为免锁 (宏常量)
ATOMIC_FLAG_INIT (C11) | 初始化新的 atomic_flag (宏常量)
ATOMIC_VAR_INIT (C11)(C17 中弃用) | 初始化新的原子对象 (宏函数)
kill_dependency (C11) | 打破 memory_order_consume 的依赖链 (宏函数)

函数

定义于头文件 <stdatomic.h>
atomic_flag_test_and_setatomic_flag_test_and_set_explicit (C11) | 设置 atomic_flag 为 true 并返回旧值 (函数)
atomic_flag_clearatomic_flag_clear_explicit (C11) | 设置 atomic_flag 为 false (函数)
atomic_init (C11) | 初始化既存的原子对象 (函数)
atomic_is_lock_free (C11) | 指示原子对象是否免锁 (函数)
atomic_storeatomic_store_explicit (C11) | 存储值到原子对象 (函数)
atomic_loadatomic_load_explicit (C11) | 从原子对象读取值 (函数)
atomic_exchangeatomic_exchange_explicit (C11) | 与原子对象的值交换值 (函数)
atomic_compare_exchange_strongatomic_compare_exchange_strong_explicitatomic_compare_exchange_weakatomic_compare_exchange_weak_explicit (C11) | 若期待旧值则与原子对象交换值，否则读取旧值 (函数)
atomic_fetch_addatomic_fetch_add_explicit (C11) | 原子加法 (函数)
atomic_fetch_subatomic_fetch_sub_explicit (C11) | 原子减法 (函数)
atomic_fetch_oratomic_fetch_or_explicit (C11) | 原子逐位或 (函数)
atomic_fetch_xoratomic_fetch_xor_explicit (C11) | 原子逐位异或 (函数)
atomic_fetch_andatomic_fetch_and_explicit (C11) | 原子逐位与 (函数)
atomic_thread_fence (C11) | 通用的内存顺序依赖的栅栏同步原语 (函数)
atomic_signal_fence (C11) | 线程与执行于同一线程的信号处理函数间的栅栏 (函数)

类型

标准库为核心语言原子类型提供便利 typedef 。

typedef 名 | 完整类型名
atomic_bool | _Atomic _Bool
atomic_char | _Atomic char
atomic_schar | _Atomic signed char
atomic_uchar | _Atomic unsigned char
atomic_short | _Atomic short
atomic_ushort | _Atomic unsigned short
atomic_int | _Atomic int
atomic_uint | _Atomic unsigned int
atomic_long | _Atomic long
atomic_ulong | _Atomic unsigned long
atomic_llong | _Atomic long long
atomic_ullong | _Atomic unsigned long long
atomic_char16_t | _Atomic char16_t
atomic_char32_t | _Atomic char32_t
atomic_wchar_t | _Atomic wchar_t
atomic_int_least8_t | _Atomic int_least8_t
atomic_uint_least8_t | _Atomic uint_least8_t
atomic_int_least16_t | _Atomic int_least16_t
atomic_uint_least16_t | _Atomic uint_least16_t
atomic_int_least32_t | _Atomic int_least32_t
atomic_uint_least32_t | _Atomic uint_least32_t
atomic_int_least64_t | _Atomic int_least64_t
atomic_uint_least64_t | _Atomic uint_least64_t
atomic_int_fast8_t | _Atomic int_fast8_t
atomic_uint_fast8_t | _Atomic uint_fast8_t
atomic_int_fast16_t | _Atomic int_fast16_t
atomic_uint_fast16_t | _Atomic uint_fast16_t
atomic_int_fast32_t | _Atomic int_fast32_t
atomic_uint_fast32_t | _Atomic uint_fast32_t
atomic_int_fast64_t | _Atomic int_fast64_t
atomic_uint_fast64_t | _Atomic uint_fast64_t
atomic_intptr_t | _Atomic intptr_t
atomic_uintptr_t | _Atomic uintptr_t
atomic_size_t | _Atomic size_t
atomic_ptrdiff_t | _Atomic ptrdiff_t
atomic_intmax_t | _Atomic intmax_t
atomic_uintmax_t | _Atomic uintmax_t

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17 Atomics <stdatomic.h> (p: 273-286)
  • 7.31.8 Atomics <stdatomic.h> (p: 455-456)

参阅


ATOMIC_FLAG_INIT

< c‎ | atomic
定义于头文件 <stdatomic.h> |
#define ATOMIC_FLAG_INIT /* unspecified */ | (C11 起)

展开成能用于初始化 atomic_flag 类型为清除状态的初始化器。不用此宏初始化的 atomic_flag 的值未定义。

示例

#include <stdatomic.h>

atomic_flag flag = ATOMIC_FLAG_INIT;

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.1/3 ATOMIC_FLAG_INIT (p: 273)
  • 7.17.8/4 ATOMIC_FLAG_INIT (p: 285)

参阅

ATOMIC_VAR_INIT (C11)(C17 中弃用) | 初始化新的原子对象 (宏函数)
atomic_flag (C11) | 免锁布尔标志 (结构体)


ATOMIC_*_LOCK_FREE

< c‎ | atomic
定义于头文件 <stdatomic.h>
#define ATOMIC_BOOL_LOCK_FREE /* implementation-defined */

#define ATOMIC_CHAR_LOCK_FREE /* implementation-defined */
#define ATOMIC_CHAR16_T_LOCK_FREE /* implementation-defined */
#define ATOMIC_CHAR32_T_LOCK_FREE /* implementation-defined */
#define ATOMIC_WCHAR_T_LOCK_FREE /* implementation-defined */
#define ATOMIC_SHORT_LOCK_FREE /* implementation-defined */
#define ATOMIC_INT_LOCK_FREE /* implementation-defined */
#define ATOMIC_LONG_LOCK_FREE /* implementation-defined */
#define ATOMIC_LLONG_LOCK_FREE /* implementation-defined */

#define ATOMIC_POINTER_LOCK_FREE /* implementation-defined */
 (C11 起)

展开成求值为 0 或 1 或 2 的预处理器常量表达式，它指示对应原子类型（有符号及无符号一同）的免锁属性。

值 | 解释
0 | 该原子类型决不免锁
1 | 该原子类型有时免锁
2 | 该原子类型始终免锁

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.1/3 atomic lock-free macros (p: 273)


ATOMIC_VAR_INIT

< c‎ | atomic
定义于头文件 <stdatomic.h> |
#define ATOMIC_VAR_INIT(value) /* unspecified */ | (C11 起) (C17 中弃用)

展开成能用于初始化类型同 value 的原子对象的表达式。

拥有自动存储期而不显式初始化的原子对象的初始值不确定。不过，静态和线程局域对象的默认（零）初始化产生合法值。

初始化原子对象时，任何同时访问，即使通过原子操作，都是数据竞争（若立即将地址以 memory_order_relaxed 操作传递给另一线程，就可能发生）。

注解

此宏曾是 C11 原子类型设计早期方案的一部分。在 C11 中不需要，于 C17 中弃用，并计划于 C2x 中移除。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C 标准。

DR | 应用于 | 出版时的行为 | 正确行为
DR 485 | C11 | 规范冗余并与核心语言矛盾 | 已更正

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.17.2.1 The ATOMIC_VAR_INIT macro (p: 201)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.2.1 The ATOMIC_VAR_INIT macro (p: 274)

参阅

ATOMIC_FLAG_INIT
(C11)
 初始化新的 atomic_flag
(宏常量)


atomic_compare_exchange_weak, atomic_compare_exchange_strong, atomic_compare_exchange_weak_explicit, atomic_compare_exchange_strong_explicit

< c‎ | atomic
定义于头文件 <stdatomic.h> |  |
_Bool atomic_compare_exchange_strong( volatile A* obj, C* expected, C desired ); | (1) | (C11 起)
_Bool atomic_compare_exchange_weak( volatile A *obj, C* expected, C desired ); | (2) | (C11 起)
_Bool atomic_compare_exchange_strong_explicit( volatile A* obj, C* expected, C desired, memory_order succ, memory_order fail ); | (3) | (C11 起)
_Bool atomic_compare_exchange_weak_explicit( volatile A *obj, C* expected, C desired, memory_order succ, memory_order fail ); | (4) | (C11 起)

原子地比较 obj 所指向对象的内存的内容与 expected 所指向的内存的内容。若它们相等，则以 desired 替换前者（进行读修改写操作）。否则，将 obj 所指向的实际内存内容加载到 *expected （进行加载操作）。

读修改写和加载操作的内存模型分别为 succ 和 fail 。 (1-2) 版本默认使用 memory_order_seq_cst 。

函数的弱形式（ (2) 与 (4) ）允许虚假失败，即表现为如同 *obj != *expected ，即使它们相等。当比较并交换在循环中时，弱版本在某些平台上会生成更好的性能。在弱版本会要求循环而强版本不要求时，最好用强版本。

这是为所有原子对象类型 A 定义的泛型函数。参数为指向 volatile 原子对象的指针，以接受非 volatile 与 volatile （例如内存映射 I/O ）的原子对象，而 volatile 语义在应用此操作时保留。 C 为对应 A 的非原子类型。

泛型函数名是宏或是声明有外部链接的标识符是未指定的。若为访问实际函数压制宏定义（例如像 (atomic_compare_exchange)(...) 这样加括号），或程序定义拥有泛型函数名的外部标识符，则行为未定义。

参数

obj | - | 指向要测试及修改的原子对象的指针
expected | - | 指向期待在原子对象中找到的值的指针
desired | - | 要存储于原子对象的值，若它得到期待
succ | - | 读修改写操作的内存同步顺序，若比较成功。容许所有值。
fail | - | 加载操作的内存同步顺序，若比较失败。不能为 memory_order_release 或 memory_order_acq_rel 且不能指定强于 succ 的顺序

返回值

比较结果：若 *obj 等于 *expected 则为 true ，否则 false 。

注解

atomic_compare_exchange_strong 表现为如同原子地执行下列代码：

if (memcmp(obj, expected, sizeof *obj) == 0) {
    memcpy(obj, &desired, sizeof *obj);
    return true
} else {
    memcpy(expected, obj, sizeof *obj);
    return false;
}

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.7.4 The atomic_compare_exchange generic functions (p: 283-284)

参阅

atomic_exchangeatomic_exchange_explicit
(C11)
 与原子对象的值交换值
(函数)


atomic_exchange, atomic_exchange_explicit

< c‎ | atomic
定义于头文件 <stdatomic.h> |  |
C atomic_exchange( volatile A* obj, C desired ); | (1) | (C11 起)
C atomic_exchange_explicit( volatile A* obj, C desired, memory_order order ); | (2) | (C11 起)

原子地以 desired 替换 obj 所指向的对象的值，并返回 obj 先前所保有的值。此操作是读修改写操作。第一版本按照 memory_order_seq_cst 排序内存访问，第二版本按照 order 排序内存访问。

这是为所有原子对象类型 A 定义的泛型函数。参数为指向 volatile 原子对象的指针，以接受非 volatile 与 volatile （例如内存映射 I/O ）的原子对象，而 volatile 语义在应用此操作时保留。 C 为对应 A 的非原子类型。

泛型函数名是宏或是声明有外部链接的标识符是未指定的。若为访问实际函数压制宏定义（例如像 (atomic_exchange)(...) 这样加括号），或程序定义拥有泛型函数名的外部标识符，则行为未定义。

参数

obj | - | 指向要修改的原子对象的指针
desired | - | 用以替换原子对象的值
order | - | 此操作的内存同步顺序标签：允许所有值

返回值

obj 所指向的原子对象先前所保有的值。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.7.3 The atomic_exchange generic functions (p: 283)

参阅

atomic_compare_exchange_strongatomic_compare_exchange_strong_explicitatomic_compare_exchange_weakatomic_compare_exchange_weak_explicit
(C11)
 若期待旧值则与原子对象交换值，否则读取旧值
(函数)


atomic_fetch_add, atomic_fetch_add_explicit

< c‎ | atomic
定义于头文件 <stdatomic.h> |  |
C atomic_fetch_add( volatile A* obj, M arg ); | (1) | (C11 起)
C atomic_fetch_add_explicit( volatile A* obj, M arg, memory_order order ); | (2) | (C11 起)

以 arg 和 *obj 的旧值的加法结果原子地替换 obj 所指向的值，并返回 *obj 先前保有的值。此操作是读修改写操作。第一版本按照 memory_order_seq_cst 排序内存访问，第二版本按照 order 排序内存访问。

这是为所有原子对象类型 A 定义的泛型函数。参数为指向 volatile 原子对象的指针，以接受非 volatile 与 volatile （例如内存映射 I/O ）的原子对象，而 volatile 语义在应用此操作时保留。 若 A 为原子整数类型则 M 是对应 A 的非原子类型，或若 A 为原子指针类型则 M 为 ptrdiff_t 。

泛型函数名是宏或是声明有外部链接的标识符是未指定的。若为访问实际函数压制宏定义（例如像 (atomic_fetch_add)(...) 这样加括号），或程序定义拥有泛型函数名的外部标识符，则行为未定义。

对于有符号整数类型，定义算术为使用补码表示。无未定义结果。对于指针类型，结果可能是未定义地址，但运算不会另有未定义行为。

参数

obj | - | 指向要修改的原子对象的指针
arg | - | 要加到存储于原子对象中的值的值
order | - | 此操作的内存同步顺序：容许所有值

返回值

obj 所指向的原子对象先前保有的值。

示例

#include <stdio.h>
#include <threads.h>
#include <stdatomic.h>

atomic_int acnt;
int cnt;

int f(void* thr_data)
{
    for(int n = 0; n < 1000; ++n) {
        atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed); // 原子的
        ++cnt; // 未定义行为，实际上会失去一些更新
    }
    return 0;
}

int main(void)
{
    thrd_t thr[10];
    for(int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for(int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);

    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

可能的输出：

The atomic counter is 10000
The non-atomic counter is 9511

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.7.5 The atomic_fetch and modify generic functions (p: 284-285)

参阅

atomic_fetch_subatomic_fetch_sub_explicit
(C11)
 原子减法
(函数)


atomic_fetch_and, atomic_fetch_and_explicit

< c‎ | atomic
定义于头文件 <stdatomic.h> |  |
C atomic_fetch_and( volatile A* obj, M arg ); | (1) | (C11 起)
C atomic_fetch_and_explicit( volatile A* obj, M arg, memory_order order ); | (2) | (C11 起)

以 arg 和 *obj 的旧值逐位与的结果原子地替换 obj 所指向的值，并返回 *obj 先前保有的值。此操作是读-修改-写操作。第一版本按照 memory_order_seq_cst 排序内存访问，第二版本按照 order 排序内存访问。

这是为所有原子对象类型 A 定义的泛型函数。参数为指向 volatile 原子对象的指针，以接受非 volatile 与 volatile （例如内存映射 I/O ）的原子对象，而 volatile 语义在应用此操作时保留。 若 A 为原子整数类型则 M 是对应 A 的非原子类型，或若 A 为原子指针类型则 M 为 ptrdiff_t 。

泛型函数名是宏或是声明有外部链接的标识符是未指定的。若为访问实际函数压制宏定义（例如像 (atomic_fetch_and)(...) 这样加括号），或程序定义拥有泛型函数名的外部标识符，则行为未定义。

参数

obj | - | 指向要修改的原子对象的指针
arg | - | 要逐位与到存储于原子对象中的值的值
order | - | 此操作的内存同步顺序：容许所有值

返回值

obj所指向的原子对象先前保有的值。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.7.5 The atomic_fetch and modify generic functions (p: 284-285)

参阅

atomic_fetch_oratomic_fetch_or_explicit (C11) | 原子逐位或 (函数)
atomic_fetch_xoratomic_fetch_xor_explicit (C11) | 原子逐位异或 (函数)


atomic_fetch_or, atomic_fetch_or_explicit

< c‎ | atomic
定义于头文件 <stdatomic.h> |  |
C atomic_fetch_or( volatile A* obj, M arg ); | (1) | (C11 起)
C atomic_fetch_or_explicit( volatile A* obj, M arg, memory_order order ); | (2) | (C11 起)

以 arg 和 *obj 旧值的逐位或结果原子地替换 obj 所指向的值，并返回 *obj 先前保有的值。此操作是读修改写操作。第一版本按照 memory_order_seq_cst 排序内存访问，第二版本按照 order 排序内存访问。

这是为所有原子对象类型 A 定义的泛型函数。参数为指向 volatile 原子对象的指针，以接受非 volatile 与 volatile （例如内存映射 I/O ）的原子对象，而 volatile 语义在应用此操作时保留。 若 A 为原子整数类型则 M 是对应 A 的非原子类型，或若 A 为原子指针类型则 M 为 ptrdiff_t 。

泛型函数名是宏或是声明有外部链接的标识符是未指定的。若为访问实际函数压制宏定义（例如像 (atomic_fetch_or)(...) 这样加括号），或程序定义拥有泛型函数名的外部标识符，则行为未定义。

参数

obj | - | 指向要修改的原子对象的指针
arg | - | 要逐位或到存储于原子对象中的值的值
order | - | 此操作的内存同步顺序：容许所有值

返回值

obj 所指向的原子对象先前保有的值。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.7.5 The atomic_fetch and modify generic functions (p: 284-285)

参阅

atomic_fetch_andatomic_fetch_and_explicit (C11) | 原子逐位与 (函数)
atomic_fetch_xoratomic_fetch_xor_explicit (C11) | 原子逐位异或 (函数)


atomic_fetch_sub, atomic_fetch_sub_explicit

< c‎ | atomic
定义于头文件 <stdatomic.h> |  |
C atomic_fetch_sub( volatile A* obj, M arg ); | (1) | (C11 起)
C atomic_fetch_sub_explicit( volatile A* obj, M arg, memory_order order ); | (2) | (C11 起)

以 *obj 的旧值减去 arg 的结果原子地替换 obj 的所指向值，并返回 *obj 先前保有的值。此操作是读修改写操作。第一版本按照 memory_order_seq_cst 排序内存访问，第二版本按照 order 排序内存访问。

这是为所有原子对象类型 A 定义的泛型函数。参数为指向 volatile 原子对象的指针，以接受非 volatile 与 volatile （例如内存映射 I/O ）的原子对象，而 volatile 语义在应用此操作时保留。 若 A 为原子整数类型则 M 是对应 A 的非原子类型，或若 A 为原子指针类型则 M 为 ptrdiff_t 。

泛型函数名是宏或是声明有外部链接的标识符是未指定的。若为访问实际函数压制宏定义（例如像 (atomic_fetch_sub)(...) 这样加括号），或程序定义拥有泛型函数名的外部标识符，则行为未定义。

对于有符号整数类型，定义算术为使用补码表示。无未定义结果。对于指针类型，结果可能是未定义地址，但运算不会另有未定义行为。

参数

obj | - | 指向要修改的原子对象的指针
arg | - | 要从存储于原子对象中的值减去的值
order | - | 此操作的内存同步顺序：容许所有值

返回值

obj 所指向的原子对象先前保有的值。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.7.5 The atomic_fetch and modify generic functions (p: 284-285)

参阅

atomic_fetch_addatomic_fetch_add_explicit
(C11)
 原子加法
(函数)


atomic_fetch_xor, atomic_fetch_xor_explicit

< c‎ | atomic
定义于头文件 <stdatomic.h> |  |
C atomic_fetch_xor( volatile A* obj, M arg ); | (1) | (C11 起)
C atomic_fetch_xor_explicit( volatile A* obj, M arg, memory_order order ); | (2) | (C11 起)

以 arg 和 *obj 的旧值逐位异或的结果原子地替换 obj 所指向的值，并返回 *obj 先前保有的值。此操作是读修改写操作。第一版本按照 memory_order_seq_cst 排序内存访问，第二版本按照 order 排序内存访问。

这是为所有原子对象类型 A 定义的泛型函数。参数为指向 volatile 原子对象的指针，以接受非 volatile 与 volatile （例如内存映射 I/O ）的原子对象，而 volatile 语义在应用此操作时保留。 若 A 为原子整数类型则 M 是对应 A 的非原子类型，或若 A 为原子指针类型则 M 为 ptrdiff_t 。

泛型函数名是宏或是声明有外部链接的标识符是未指定的。若为访问实际函数压制宏定义（例如像 (atomic_fetch_xor)(...) 这样加括号），或程序定义拥有泛型函数名的外部标识符，则行为未定义。

参数

obj | - | 指向要修改的原子对象的指针
arg | - | 要逐位异或到存储于原子对象中的值的值
order | - | 此操作的内存同步顺序：容许所有值

返回值

obj 所指向的原子对象先前保有的值。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.7.5 The atomic_fetch and modify generic functions (p: 284-285)

参阅

atomic_fetch_oratomic_fetch_or_explicit (C11) | 原子逐位或 (函数)
atomic_fetch_andatomic_fetch_and_explicit (C11) | 原子逐位与 (函数)


atomic_flag

< c‎ | atomic
定义于头文件 <stdatomic.h> |
struct atomic_flag; | (C11 起)

atomic_flag 是一种原子布尔类型。不同于其他原子类型，它保证是免锁的。不同于 atomic_bool ， atomic_flag 不提供加载或存储操作。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.1/4 atomic_flag (p: 273)
  • 7.17.8 Atomic flag type and operations (p: 285-286)

参阅

ATOMIC_FLAG_INIT (C11) | 初始化新的 atomic_flag (宏常量)
atomic_flag_test_and_setatomic_flag_test_and_set_explicit (C11) | 设置 atomic_flag 为 true 并返回旧值 (函数)
atomic_flag_clearatomic_flag_clear_explicit (C11) | 设置 atomic_flag 为 false (函数)


atomic_flag_clear, atomic_flag_clear_explicit

< c‎ | atomic
定义于头文件 <stdatomic.h> |  |
void atomic_flag_clear( volatile atomic_flag * obj ); | (1) | (C11 起)
void atomic_flag_clear_explicit( volatile atomic_flag * obj, memory_order order ); | (2) | (C11 起)

原子地更改 obj 所指向的 atomic_flag 状态为清除（ false ）。第一版本按照 memory_order_seq_cst 排序内存访问，第二版本根据 order 排序内存访问。

参数为指向 volatile 原子标志的指针，以接受非 volatile 和 volatile （如内存映射 I/O ）的原子标志。

参数

obj | - | 指向要修改的 atomic_flag 对象的指针
order | - | 此操作所用的内存同步顺序：允许所有值

返回值

（无）

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.8.2 The atomic_flag_clear functions (p: 286)

参阅

atomic_flag_test_and_setatomic_flag_test_and_set_explicit
(C11)
 设置 atomic_flag 为 true 并返回旧值
(函数)


atomic_flag_test_and_set, atomic_flag_test_and_set_explicit

< c‎ | atomic
定义于头文件 <stdatomic.h> |  |
_Bool atomic_flag_test_and_set( volatile atomic_flag * obj ); | (1) | (C11 起)
_Bool atomic_flag_test_and_set_explicit( volatile atomic_flag * obj, memory_order order ); | (2) | (C11 起)

原子地更改 obj 所指向的 atomic_flag 的状态为设置（ true ），并返回先前值。第一版本按 memory_order_seq_cst 排序内存访问，第二版本按 order 排序内存访问。

参数是为指向 volatile atomic_flag 的指针，以接受非 volatile 和 volatile （例如映射到内存的 I/O ）的 atomic_flag 。

参数

obj | - | 指向要修改的 atomic_flag 对象的指针
order | - | 此操作所用的内存同步顺序：容许所有值

返回值

obj 所指向的 atomic_flag 的先前值。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.8.1 The atomic_flag_test_and_set functions (p: 285-286)

参阅

atomic_flag_clearatomic_flag_clear_explicit
(C11)
 设置 atomic_flag 为 false
(函数)


atomic_init

< c‎ | atomic
定义于头文件 <stdatomic.h> |
void atomic_init( volatile A* obj, C desired ); | (C11 起)

以值 desired 初始化默认构造的原子对象 obj 。此函数非原子：来自另一线程的共时访问，即使通过原子操作，亦为数据竞争。

这是为所有原子对象类型 A 定义的泛型函数。参数为指向 volatile 原子对象的指针，以接受非 volatile 与 volatile （例如内存映射 I/O ）的原子对象，而 volatile 语义在应用此操作时保留。 C 为对应 A 的非原子类型。

泛型函数名是宏或是声明有外部链接的标识符是未指定的。若为访问实际函数压制宏定义（例如像 (atomic_init)(...) 这样加括号），或程序定义拥有泛型函数名的外部标识符，则行为未定义。

参数

obj | - | 指向要初始化的原子对象的指针
desired | - | 用以初始化原子对象的值

返回值

（无）

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.2.2 The atomic_init generic function (p: 274-275)

参阅

ATOMIC_VAR_INIT
(C11)(C17 中弃用)
 初始化新的原子对象
(宏函数)


atomic_is_lock_free

< c‎ | atomic
定义于头文件 <stdatomic.h> |
_Bool atomic_is_lock_free( const volatile A* obj ); | (C11 起)

确定所有 A 类型对象（obj所指向对象的类型）上的原子操作是否为免锁。在任何给定的程序执行中，调用 atomic_is_lock_free 的结果对于所有同一类型的指针相同。

这是为所有原子对象类型 A 定义的泛型函数。参数为指向 volatile 原子对象的指针，以接受非 volatile 与 volatile （例如内存映射 I/O ）的原子对象，而 volatile 语义在应用此操作时保留。

泛型函数名是宏或是声明有外部链接的标识符是未指定的。若为访问实际函数压制宏定义（例如像 (atomic_is_lock_free)(...) 这样加括号），或程序定义拥有泛型函数名的外部标识符，则行为未定义。

参数

obj - 指向要调查的原子对象的指针

返回值

若所有 A 类型对象的原子操作为免锁，则为 true ，否则为 false 。

注意

C11 在出版时指名此函数针对每个对象，而非每个类型。这已为 DR 465 所订正。

示例

#include <stdio.h>
#include <stdatomic.h>

_Atomic struct A { int a[100]; } a;
_Atomic struct B { int x, y; } b;
int main(void)
{
    printf("_Atomic struct A is lock free? %s\n",
            atomic_is_lock_free(&a) ? "true" : "false");
    printf("_Atomic struct B is lock free? %s\n",
            atomic_is_lock_free(&b) ? "true" : "false");
}

可能的输出：

_Atomic struct A is lock free? false
_Atomic struct B is lock free? true

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.5.1 The atomic_is_lock_free generic function (p: 280)

参阅

ATOMIC_BOOL_LOCK_FREEATOMIC_CHAR_LOCK_FREEATOMIC_CHAR16_T_LOCK_FREEATOMIC_CHAR32_T_LOCK_FREEATOMIC_WCHAR_T_LOCK_FREEATOMIC_SHORT_LOCK_FREEATOMIC_INT_LOCK_FREEATOMIC_LONG_LOCK_FREEATOMIC_LLONG_LOCK_FREEATOMIC_POINTER_LOCK_FREE
(C11)
 指示给定的原子类型为免锁
(宏常量)


atomic_load, atomic_load_explicit

< c‎ | atomic
定义于头文件 <stdatomic.h> |  |
C atomic_load( const volatile A* obj ); | (1) | (C11 起)
C atomic_load_explicit( const volatile A* obj, memory_order order ); | (2) | (C11 起)

原子地加载并返回 obj 所指向的原子对象的当前值。该操作是原子读操作。

第一版本按照 memory_order_seq_cst 排序内存访问，第二版本根按照 order 排序内存访问。 order 必须是 memory_order_relaxed 、 memory_order_consume 、 memory_order_acquire 或 memory_order_seq_cst 之一。否则行为未定义。

这是为所有原子对象类型 A 定义的泛型函数。参数为指向 volatile 原子对象的指针，以接受非 volatile 与 volatile （例如内存映射 I/O ）的原子对象，而 volatile 语义在应用此操作时保留。 C 为对应 A 的非原子类型。

泛型函数名是宏或是声明有外部链接的标识符是未指定的。若为访问实际函数压制宏定义（例如像 (atomic_load)(...) 这样加括号），或程序定义拥有泛型函数名的外部标识符，则行为未定义。

参数

obj | - | 指向要访问的原子对象的指针
order | - | 此操作的内存同步顺序

返回值

obj 所指向原子对象的当前值。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.7.2 The atomic_load generic functions (p: 282)

参阅

atomic_storeatomic_store_explicit
(C11)
 存储值到原子对象
(函数)


atomic_signal_fence

< c‎ | atomic
定义于头文件 <stdatomic.h> |
void atomic_signal_fence( memory_order order ); | (C11 起)

在线程和同一线程上执行的信号处理函数之间，建立以 order 指示的非原子和宽松原子访问的内存同步顺序。这等价于 atomic_thread_fence ，除了不为内存顺序产生 CPU 指令。只会以 order 指示抑制编译器重排指令。例如，拥有释放语义的栅栏阻止移到读或写到后继写入之后，而拥有获得语义的栅栏阻止移动读或写到前驱读取之前。

参数

order - 此栅栏执行的内存顺序

返回值

（无）

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.4.2 The atomic_signal_fence function (p: 279)

参阅

atomic_thread_fence
(C11)
 通用的内存顺序依赖的栅栏同步原语
(函数)


atomic_store, atomic_store_explicit

< c‎ | atomic
定义于头文件 <stdatomic.h> |  |
void atomic_store( volatile A* obj , C desired); | (1) | (C11 起)
void atomic_store_explicit( volatile A* obj, C desired, memory_order order ); | (2) | (C11 起)

原子地以 desired 替换 obj 所指向的原子对象的值。此操作是原子写操作。

第一版本按照 memory_order_seq_cst 排序内存访问，第二版本按照 order 排序内存访问。 order 必须为 memory_order_relaxed 、 memory_order_release 或 memory_order_seq_cst 之一。否则行为未定义。

这是为所有原子对象类型 A 定义的泛型函数。参数为指向 volatile 原子对象的指针，以接受非 volatile 与 volatile （例如内存映射 I/O ）的原子对象，而 volatile 语义在应用此操作时保留。 C 为对应 A 的非原子类型。

泛型函数名是宏或是声明有外部链接的标识符是未指定的。若为访问实际函数压制宏定义（例如像 (atomic_store)(...) 这样加括号），或程序定义拥有泛型函数名的外部标识符，则行为未定义。

参数

obj | - | 指向要修改的原子对象的指针
order | - | 用于此操作的内存同步顺序

返回值

（无）

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.7.1 The atomic_store generic functions (p: 282)

参阅

atomic_loadatomic_load_explicit
(C11)
 从原子对象读取值
(函数)


atomic_thread_fence

< c‎ | atomic
定义于头文件 <stdatomic.h> |
void atomic_thread_fence( memory_order order ); | (C11 起)

按照 order 指示，建立非原子和宽松原子访问的的内存同步顺序，而不进行关联的原子操作。例如，线程 A 中先发生于 memory_order_release 栅栏的所有非原子和宽松原子存储，将同步于与线程 B 中 memory_order_acquire 栅栏之后的对同一位置的非原子和宽松原子加载。

参数

order - 此栅栏执行的内存顺序

返回值

（无）

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.4.1 The atomic_thread_fence function (p: 278-279)

参阅

atomic_signal_fence
(C11)
 线程与执行于同一线程的信号处理函数间的栅栏
(函数)


kill_dependency

< c‎ | atomic
定义于头文件 <stdatomic.h> |
A kill_dependency(A y); | (C11 起)

告知编译器： memory_order_consume 原子加载操作所开始的依赖树不再延伸过 kill_dependency 的返回值；即该参数不把依赖带入返回值。

函数实现为宏。 A 为 y 的类型。

参数

y - 要从依赖树移除返回值的表达式

返回值

返回 y ，它不再是依赖树的一部分。

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.17.3.1 The kill_dependency macro (p: 203-204)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.17.3.1 The kill_dependency macro (p: 278)

参阅


日期和时间工具

< c

函数

时间操纵
定义于头文件 <time.h>
difftime
 计算时间差
(函数)
time
 返回纪元开始经过的当前系统日历时间
(函数)
clock
 返回未加工的程序启动时开始经过的处理器时间
(函数)
timespec_get
(C11)
 返回基于给定时间基底的日历时间
(函数)
timespec_getres
(C23)
 返回基于给定时间基底的日历时间的解析度
(函数)
格式转换
定义于头文件 <time.h>
asctimeasctime_rasctime_s
(C23)(C11)
 将 struct tm 对象转换成文本表示
(函数)
ctimectime_rctime_s
(C23)(C11)
 将 struct time_t 对象转换成文本表示
(函数)
strftime
 将 struct tm 对象转换成自定义文本表示
(函数)
定义于头文件 <wchar.h>
wcsftime
(C95)
 将 struct tm 对象转换成自定义宽字符文本表示
(函数)
定义于头文件 <time.h>
gmtimegmtime_rgmtime_s
(C23)(C11)
 将从纪元开始的时间转换成以协调世界时（UTC）表示的日历时间
(函数)
localtimelocaltime_rlocaltime_s
(C23)(C11)
 将从纪元开始的时间转换成以本地时间表示的日历时间
(函数)
mktime
 将日历时间转换成纪元开始经过的时间
(函数)

常量

定义于头文件 <time.h>
CLOCKS_PER_SEC
 处理器每秒的时间计数
(宏常量)

类型

定义于头文件 <time.h>
tm | 日历时间类型 (结构体)
time_t | 从纪元开始的日历时间类型 (typedef)
clock_t | 从时点开始的处理器时间类型 (typedef)
timespec (C11) | 单位为秒和纳秒的时间 (结构体)

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.27 Date and time <time.h> (p: 284-291)
  • 7.29.5.1 The wcsftime function (p: 320-321)
  • 7.31.14 Date and time <time.h> (p: 333)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27 Date and time <time.h> (p: 388-397)
  • 7.29.5.1 The wcsftime function (p: 439-440)
  • 7.31.14 Date and time <time.h> (p: 456)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.23 Date and time <time.h> (p: 338-347)
  • 7.24.5.1 The wcsftime function (p: 385-386)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.12 DATE AND TIME <time.h>

参阅


CLOCKS_PER_SEC

< c‎ | chrono
定义于头文件 <time.h>
#define CLOCKS_PER_SEC /*implementation defined*/

展开成一个 clock_t 类型的表达式（不必是编译时常量），等于每秒计次数，如 clock() 所返回者。

注意

POSIX 定义 CLOCKS_PER_SEC 为一百万，无关乎 clock 的实际精度。

在 C89 中被标准为 CLOCKS_PER_SEC 之前，此宏有时会以其 IEEE std 1003.1-1988 名称 CLK_TCK 为人所用：该名称未包含于 C89 ，并为 POSIX 自身于 1996 年移除，因为它和 times() 函数所用的给出每秒时钟数的宏 _SC_CLK_TCK 有歧义。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.1/2 Components of time (p: 388)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.23.1/2 Components of time (p: 338)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.12.1 Components of time

参阅

clock | 返回未加工的程序启动时开始经过的处理器时间 (函数)
clock_t | 从时点开始的处理器时间类型 (typedef)


asctime, asctime_r, asctime_s

< c‎ | chrono
定义于头文件 <time.h> |  |
char* asctime ( const struct tm * time_ptr ); | (1) |
char* asctime_r( const struct tm * time_ptr, char* buf ); | (2) | (C23 起)
errno_t asctime_s( char* buf, rsize_t bufsz, const struct tm * time_ptr ); | (3) | (C11 起)
1) 转换日历时间 tm 为以下固定的 25 字符表示形式： Www Mmm dd hh:mm:ss yyyy\n
  • Www ——来自 time_ptr->tm_wday 的星期之日的三字母英文缩写， Mon 、 Tue 、 Wed 、 Thu 、 Fri 、 Sat 、 Sun 之一。
  • Mmm ——来自 time_ptr->tm_mon 的月名的三字母英文缩写， Jan 、 Feb 、 Mar 、 Apr 、 May 、 Jun 、 Jul 、 Aug 、 Sep 、 Oct 、 Nov 、 Dec 之一。
  • dd ——来自 timeptr->tm_mday 的 2 位月之日，如同由 sprintf 以 %2d 打印
  • hh ——来自 timeptr->tm_hour 的 2 位时，如同由 sprintf 以 %.2d 打印
  • mm ——来自 timeptr->tm_min 的 2 位分，如同由 sprintf 以 %.2d 打印
  • ss ——来自 timeptr->tm_sec 的 2 位秒，如同由 sprintf 以 %.2d 打印
  • yyyy ——来自 timeptr->tm_year + 1900 的 4 位年，如同由 sprintf 以 %4d 打印
若 *time_ptr 的任何成员在其正常范围外则行为未定义
若 time_ptr->tm_year 所指示的历年拥有多于 4 位数或小于 1000 年则行为未定义。
函数不支持本地化，且不能移除换行符。
函数修改静态存储且非线程安全。
2) 同 (1) ，除了写入消息到用户提供的存储 buf 中，保证它是空终止的。
若存储始于 buf 的可用大小小于 26 字节则行为未定义。
3) 同 (1) ，除了写入消息到用户提供的存储 buf 中，保证它是空终止的。且在运行是检测下列错误并调用当前安装的制约处理函数：
  • buf 或 time_ptr 为空指针
  • bufsz 小于 26 或大于 RSIZE_MAX
  • 不是所有 *time_ptr 的成员都在其正常范围内
  • time_ptr->tm_year 所指示的年小于 0 或大于 9999
同所有边界检查函数， asctime_s 仅若实现定义 __STDC_LIB_EXT1__ 且用户在包含 time.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

time_ptr | - | 指向指定待打印时间的 tm 对象的指针
buf | - | 指向用户提供的至少有 26 字节的缓冲区的指针
bufsz | - | 用户提供的缓冲区大小

返回值

1) 指向保有如上描述的日期与时间的静态空终止字符串指针。该字符串可能在 asctime 与 ctime 间共享，且可能在每次调用这些函数时被重写。
2) buf ，在返回后指向保有如上描述的日期与时间的静态空终止字符串。
3) 成功时为零，失败时为非零，并设置 buf[0] 为零（除非 buf 为空指针或 bufsz 为零或大于 RSIZE_MAX ）。

注解

asctime 返回指向静态数据的指针从而不是线程安全的。 POSIX 标记此函数为过时并推荐用 strftime 代替。 C 标准亦推荐用 strftime 代替 asctime 、 asctime_r 及 asctime_s 因为 strftime 更灵活且为本地环境相关。

POSIX 限制未定义行为仅为当输出字符串将会长于 25 个字符、当 timeptr->tm_wday 或 timeptr->tm_mon 不在期待范围内，或当 timeptr->tm_year 超出 INT_MAX-1990 。

一些实现处置 timeptr->tm_mday==0 为表示前一月的最后一日。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <time.h>
#include <stdio.h>

int main(void)
{
    struct tm tm = *localtime(&(time_t){time(NULL)});
    printf("%s", asctime(&tm));

#ifdef __STDC_LIB_EXT1__
    char str[26];
    asctime_s(str, sizeof str, &tm);
    printf("%s", str);
#endif
}

可能的输出：

Tue May 26 21:51:50 2015
Tue May 26 21:51:50 2015

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.27.2.1 The asctime function (p: 287)
  • K.3.8.2.1 The asctime_s function (p: 453-454)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.2.1 The asctime function (p: 392-393)
  • K.3.8.2.1 The asctime_s function (p: 624-625)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.23.3.1 The asctime function (p: 341-342)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.12.3.1 The asctime function

参阅

ctimectime_rctime_s (C23)(C11) | 将 struct time_t 对象转换成文本表示 (函数)
strftime | 将 struct tm 对象转换成自定义文本表示 (函数)


clock

< c‎ | chrono
定义于头文件 <time.h>
clock_t clock(void);

返回从关联到进程开始执行的实现定义时期的起，进程所用的粗略处理器时间。将此值除以 CLOCKS_PER_SEC 可转换为秒。

只有两次对 clock 不同调用的返回值的差是有意义的，因为 clock 时期的起始不必与程序起始一致。 clock 时间或许会快于或慢于挂钟时间，这取决于操作系统给予程序的执行资源。例如，若 CPU 为其他进程所共享， clock 时间可能慢于挂钟。另一方面，若当前进程为多线程，而有更多资源可用， clock 时间可能会快于挂钟。

参数

（无）

返回值

程序迄今为止所用的处理器时间。若该信息不可用，或若其值无法表示，则为 ( clock_t )(-1) 。

注解

在兼容 POSIX 的系统上，带时钟 id CLOCK_PROCESS_CPUTIME_ID 的 clock_gettime 提供更高的解析度。

clock() 返回的值会在一些不遵从的实现上回卷。例如在某种实现上，若 clock_t 为有符号 32 位整数而 CLOCKS_PER_SEC 为 1000000 ，则它将在约 2147 秒（约 36 分）后回卷。

示例

此示例演示 clock() 和现实时间之差异。

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <threads.h> // POSIX 中的 pthread.h

// 函数 f() 做一些耗时的工作
int f(void* thr_data) // POSIX 中返回 void*
{
    volatile double d = 0;
    for (int n=0; n<10000; ++n)
       for (int m=0; m<10000; ++m)
           d += d*n*m;
    return 0;
}

int main(void)
{
    struct timespec ts1, tw1; // C11 与 POSIX 皆可
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts1); // POSIX
    clock_gettime(CLOCK_MONOTONIC, &tw1); // POSIX  ；C11 中用 timespec_get
    clock_t t1 = clock();

    thrd_t thr1, thr2;  // C11 ；POSIX 中用 pthread_t
    thrd_create(&thr1, f, NULL); // C11 ； POSIX 中用 pthread_create
    thrd_create(&thr2, f, NULL);
    thrd_join(thr1, NULL); // C11 ； POSIX 中用 pthread_join
    thrd_join(thr2, NULL);

    struct timespec ts2, tw2;
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts2);
    clock_gettime(CLOCK_MONOTONIC, &tw2);
    clock_t t2 = clock();

    double dur = 1000.0*(t2-t1)/CLOCKS_PER_SEC;
    double posix_dur = 1000.0*ts2.tv_sec + 1e-6*ts2.tv_nsec
                       - (1000.0*ts1.tv_sec + 1e-6*ts1.tv_nsec);
    double posix_wall = 1000.0*tw2.tv_sec + 1e-6*tw2.tv_nsec
                       - (1000.0*tw1.tv_sec + 1e-6*tw1.tv_nsec);

    printf("CPU time used (per clock(): %.2f ms\n", dur);
    printf("CPU time used (per clock_gettime()): %.2f ms\n", posix_dur);
    printf("Wall time passed: %.2f ms\n", posix_wall);
}

可能的输出：

CPU time used (per clock(): 1580.00 ms
CPU time used (per clock_gettime()): 1582.76 ms
Wall time passed: 792.13 ms

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.2.1 The clock function (p: 389)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.23.2.1 The clock function (p: 339)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.12.2.1 The clock function

参阅

ctimectime_rctime_s (C23)(C11) | 将 struct time_t 对象转换成文本表示 (函数)
time | 返回纪元开始经过的当前系统日历时间 (函数)


clock_t

< c‎ | chrono
定义于头文件 <time.h>
typedef /* unspecified */ clock_t;

足以表示进程所用的处理器时间的算术 (C11 前)实数 (C11 起)类型。它拥有实现定义的范围和精度。

示例

#include <stdio.h>
#include <time.h>

volatile unsigned sink;
int main (void)
{
  clock_t start = clock();

  for(size_t i=0; i<10000000; ++i)
      sink++;

  clock_t end = clock();
  double cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;

  printf("for loop took %f seconds to execute \n", cpu_time_used);
}

可能的输出：

for loop took 0.033492 seconds to execute

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.1/3 Components of time (p: 388)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.23.1/3 Components of time (p: 338)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.12.1 Components of time

参阅

clock | 返回未加工的程序启动时开始经过的处理器时间 (函数)
CLOCKS_PER_SEC | 处理器每秒的时间计数 (宏常量)


ctime, ctime_r, ctime_s

< c‎ | chrono
定义于头文件 <time.h> |  |
char* ctime ( const time_t * timer ); | (1) |
char* ctime_r( const time_t * timer, char* buf ); | (2) | (C23 起)
errno_t ctime_s( char *buf, rsize_t bufsz, const time_t * timer ); | (3) | (C11 起)
1) 转换从纪元起的给定时间为历法本地时间，再转换为文本表示，如同通过调用 asctime ( localtime (timer))或 asctime (localtime_r(timer, &(struct tm ){0})) (C23 起) 。
2) 同 (1) ，除了函数等价于 asctime_r(localtime_r(timer, &(struct tm ){0}), buf) 。
3) 同 (1) ，除了函数等价于 asctime_s(buf, bufsz, localtime_s(timer, &(struct tm ){0})) 。并在运行时检测下列错误并调用当前安装的制约处理函数：
  • buf 或 timer 为空指针
  • bufsz 小于 26 或大于 RSIZE_MAX
同所有边界检查函数， ctime_s 仅若实现定义 __STDC_LIB_EXT1__ 且用户在包含 time.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

结果字符串拥有下列格式：

Www Mmm dd hh:mm:ss yyyy\n
  • Www ——星期（ Mon 、 Tue 、 Wed 、 Thu 、 Fri 、 Sat 、 Sun 之一）。
  • Mmm ——月份（ Jan 、 Feb 、 Mar 、 Apr 、 May 、 Jun 、 Jul 、 Aug 、 Sep 、 Oct 、 Nov 、 Dec 之一）。
  • dd ——月之日
  • hh ——时
  • mm ——分
  • ss ——秒
  • yyyy ——年

函数不支持本地化。

参数

timer | - | 指向指定待打印时间的 time_t 对象的指针
buf | - | 指向大小至少为 bufsz 的 char 数组首元素的指针
bufsz | - | 输出的最大字节数，常为 buf 所指向的缓冲区的大小

返回值

1) 指向保有日期与时间的文本表示的静态空终止字符串的指针。该字符串可能在 asctime 与 ctime 之间共享，且可能在每次调用任何这些函数时被重写。
2) buf ，在返回后指向保有日期与时间的文本表示的空终止字符串。
2) 成功时为零（该情况下将日期与时间的字符串表示写到 buf 所指向的数组），或在失败时为非零（该情况下始终写入空终止字符到 buf[0] ，除非 buf 为空指针或 bufsz 为零或大于 RSIZE_MAX ）。

注解

ctime 返回指向静态数据的指针且非线程安全。另外，它修改可能与 gmtime 及 localtime 共享的静态 tm 对象。 POSIX 标记此函数为过时并推荐 strftime 代替。 C 标准亦推荐 strftime 代替 ctime 、 ctime_r 和 ctime_s ，因 strftime 更灵活且为本地环境相关。

ctime 与 ctime_r 的行为对于导致字符串长于 25 字符的 time_t 值（例如 10000 年）未定义。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <time.h>
#include <stdio.h>

int main(void)
{
    time_t result = time(NULL);
    printf("%s", ctime(&result));

#ifdef __STDC_LIB_EXT1__
    char str[26];
    ctime_s(str,sizeof str,&result);
    printf("%s", str);
#endif
}

输出：

Tue May 26 21:51:03 2015
Tue May 26 21:51:03 2015

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.27.3.2 The ctime function (p: 287-288)
  • K.3.8.2.2 The ctime_s function (p: 454)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.3.2 The ctime function (p: 393)
  • K.3.8.2.2 The ctime_s function (p: 626)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.23.3.2 The ctime function (p: 342)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.12.3.2 The ctime function

参阅

asctimeasctime_rasctime_s (C23)(C11) | 将 struct tm 对象转换成文本表示 (函数)
strftime | 将 struct tm 对象转换成自定义文本表示 (函数)


difftime

< c‎ | chrono
定义于头文件 <time.h>
double difftime( time_t time_end, time_t time_beg );

以秒数计算二个作为 time_t 对象的日历时间的差（ time_end - time_beg ）。若 time_end 代表先于 time_beg 的时间点，则结果为负。

参数

time_beg, time_end - 待比较的时间

返回值

两时间之差的秒数。

注意

在 POSIX 系统上，time_t 以秒计量，而 difftime 等价于算术减法，但 C 和 C++ 允许小数单位的 time_t 。

示例

以下程序计算从月初开始经过的秒数。

#include <stdio.h>
#include <time.h>

int main(void)
{
    time_t now;
    time(&now);

    struct tm beg;
    beg = *localtime(&now);

    // 设 beg 为月初
    beg.tm_hour = 0;
    beg.tm_min = 0;
    beg.tm_sec = 0;
    beg.tm_mday = 1;

    double seconds = difftime(now, mktime(&beg));

    printf("%.f seconds have passed since the beginning of the month.\n", seconds);

    return 0;
}

输出：

1937968 seconds have passed since the beginning of the month.

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.2.2 The difftime function (p: 390)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.23.2.2 The difftime function (p: 339)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.12.2.2 The difftime function

参阅


gmtime, gmtime_r, gmtime_s

< c‎ | chrono
定义于头文件 <time.h> |  |
struct tm *gmtime ( const time_t *timer ); | (1) |
struct tm *gmtime_r( const time_t *timer, struct tm *buf ); | (2) | (C23 起)
struct tm *gmtime_s( const time_t *restrict timer, struct tm *restrict buf ); | (3) | (C11 起)
1) 转换从纪元开始的给定时间（ time 所指向的 time_t 的值），以 struct tm 格式表示成协调世界时（ UTC ）。存储结果于静态存储，并返回指向静态存储的指针。
2) 同 (1) ，除了函数使用用户为结果提供的存储 buf 。
3) 同 (1) ，除了函数使用用户为结果提供的存储 buf ，还在运行时检测下列错误，并调用当前安装的制约处理函数：
  • timer 或 buf 是空指针
同所有边界检查函数， gmtime_s 仅若实现定义 __STDC_LIB_EXT1__ 且用户在包含 time.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

timer | - | 指向要转换的 time_t 对象的指针
buf | - | 指向要存储结果的 struct tm 对象的指针

返回值

1) 成功时返回指向静态的内部 struct tm 对象的指针，失败时返回空指针。该结构体可能会为 gmtime 、 localtime 以及 ctime 所共享，并于每次调用时被覆盖。
2-3) 成功时返回 buf 指针的副本，错误时返回空指针（可能是一个运行时制约违规或对指定时间到 UTC 的转换失败）。

注解

函数 gmtime 可能不是线程安全的。

POSIX 要求 gmtime 与 gmtime_r 函数若因参数过大而失败，则设置 errno 为 EOVERFLOW 。

Microsoft CRT 中 gmtime_s 的实现与 C 标准不兼容，因为它有相反的参数顺序。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <time.h>
#include <stdio.h>

int main(void)
{
    time_t t = time(NULL);
    printf("UTC:   %s", asctime(gmtime(&t)));
    printf("local: %s", asctime(localtime(&t)));

#ifdef __STDC_LIB_EXT1__
    struct tm buf;
    char str[26];
    asctime_s(str,sizeof str,gmtime_s(&t, &buf));
    printf("UTC:   %s", str);
    asctime_s(str,sizeof str,localtime_s(&t, &buf)));
    printf("local: %s", str);
#endif
}

输出：

UTC:   Tue Feb 17 18:12:09 2015
local: Tue Feb 17 13:12:09 2015
UTC:   Tue Feb 17 18:12:09 2015
local: Tue Feb 17 13:12:09 2015

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.27.3.3 The gmtime function (p: 288)
  • K.3.8.2.3 The gmtime_s function (p: 454-455)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.3.3 The gmtime function (p: 393-394)
  • K.3.8.2.3 The gmtime_s function (p: 626-627)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.23.3.3 The gmtime function (p: 343)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.12.3.3 The gmtime function

参阅

localtimelocaltime_rlocaltime_s
(C23)(C11)
 将从纪元开始的时间转换成以本地时间表示的日历时间
(函数)


localtime, localtime_r, localtime_s

< c‎ | chrono
定义于头文件 <time.h> |  |
struct tm *localtime ( const time_t *timer ); | (1) |
struct tm *localtime_r( const time_t *timer, struct tm *buf ); | (2) | (C23 起)
error_t localtime_s( const time_t *restrict timer, struct tm *restrict buf ); | (3) | (C11 起)
1) 转换给定的纪元起的时间（ timer 所指向的 time_t 值）为以 struct tm 格式表达为本地时间的日历时间。存储结果于静态存储中并返回指向该静态存储的指针。
2) 同 (1) ，除了函数对结果使用用户提供的存储 buf 。
3) 同 (1) ，除了函数对结果使用用户提供的存储 buf 。并且在运行时检测下列错误并调用当前安装的制约处理函数：
  • timer 或 buf 为空指针
同所有边界检查函数， localtime_s 仅若实现定义 __STDC_LIB_EXT1__ 且用户在包含 time.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

timer | - | 指向待转换的 time_t 对象的指针
buf | - | 指向待存储结果的 struct tm 对象的的指针

返回值

1) 成功时为指向静态内部 tm 对象的指针，否则为空指针。该结构体可能在 gmtime 、 localtime 及 ctime 间共享并可能在每次调用时被重写。
2-3) buf 指针的副本，或在错误（可能为运行时制约违规或转换指定时间为日历时间失败）时为空指针

注解

函数 localtime 可以不是线程安全的。

POSIX 要求 localtime 与 localtime_r 若因为参数过大而失败则设置 errno 为 EOVERFLOW 。

POSIX 指定 localtime 与 localtime_r 如同通过调用 tzset 确定时区信息，该函数读取环境变量 TZ 。

Microsoft CRT 中的 localtime_s 实现与 C 标准不兼容，因为它有相反的参数顺序。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <time.h>
#include <stdio.h>

int main(void)
{
    time_t t = time(NULL);
    printf("UTC:   %s", asctime(gmtime(&t)));
    printf("local: %s", asctime(localtime(&t)));

#ifdef __STDC_LIB_EXT1__
    struct tm buf;
    char str[26];
    asctime_s(str,sizeof str,gmtime_s(&t, &buf));
    printf("UTC:   %s", str);
    asctime_s(str,sizeof str,localtime_s(&t, &buf)));
    printf("local: %s", str);
#endif
}

输出：

UTC:   Tue Feb 17 18:12:09 2015
local: Tue Feb 17 13:12:09 2015
UTC:   Tue Feb 17 18:12:09 2015
local: Tue Feb 17 13:12:09 2015

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.27.3.4 The localtime function (p: 288)
  • K.3.8.2.4 The localtime_s function (p: 455)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.3.4 The localtime function (p: 394)
  • K.3.8.2.4 The localtime_s function (p: 627)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.23.3.4 The localtime function (p: 343)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.12.3.4 The localtime function

参阅

gmtimegmtime_rgmtime_s
(C23)(C11)
 将从纪元开始的时间转换成以协调世界时（UTC）表示的日历时间
(函数)


mktime

< c‎ | chrono
定义于头文件 <time.h>
time_t mktime( struct tm * time );

重整化表示成 struct tm 的本地日历时间，并将其转化成从纪元开始经过时间的 time_t 对象格式。忽略 time->tm_wday 与 time->tm_yday 。容许 time 中的值在其正常范围外。

time->tm_isdst 的负值会导致 mktime 尝试确定在指定时间夏时令是否有效。

若转换到 time_t 成功，则修改 time 会被修改。更新 time 的所有域为符合其正确范围的值。用可用于其他域的信息重新计算 time->tm_wday 与 time->tm_yday 。

参数

time - 指向 struct tm 对象的指针，它指定要转换的本地日历时间

返回值

成功时返回表示从纪元开始时间的 time_t 对象，若 time 不能表示成 time_t 对象则返回 -1 （ POSIX 亦要求此情况下存储 EOVERFLOW 于 errno 中）。

注意

若 struct tm 对象是由 POSIX strptime 或等价的函数取得的，则 tm_isdst 的值不确定，并需要在调用 mktime 前显式设置。

示例

#define _POSIX_C_SOURCE 200112L // 为 GCC 的 setenv
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

int main(void)
{
    setenv("TZ", "/usr/share/zoneinfo/America/New_York", 1); // POSIX 限定

    struct tm tm = *localtime(&(time_t){time(NULL)});
    printf("Today is           %s", asctime(&tm));
    printf("(DST is %s)\n", tm.tm_isdst ? "in effect" : "not in effect");
    tm.tm_mon -= 100;  // tm_mon 落在正常范围外
    mktime(&tm);       // tm_dst 不被设为 -1 ；使用今日的 DST 状态
    printf("100 months ago was %s", asctime(&tm));
    printf("(DST was %s)\n", tm.tm_isdst ? "in effect" : "not in effect");
}

输出：

Today is           Fri Apr 22 11:53:36 2016
(DST is in effect)
100 months ago was Sat Dec 22 10:53:36 2007
(DST was not in effect)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.2.3 The mktime function (p: 390-391)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.23.2.3 The mktime function (p: 340-341)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.12.2.3 The mktime function

参阅

localtimelocaltime_rlocaltime_s
(C23)(C11)
 将从纪元开始的时间转换成以本地时间表示的日历时间
(函数)


strftime

< c‎ | chrono
定义于头文件 <time.h> |
size_t strftime( char * str, size_t count, const char * format, const struct tm * time ); | (C99 前)
size_t strftime( char *restrict str, size_t count, const char *restrict format, const struct tm *restrict time ); | (C99 起)

按照格式字符串 format ，转换来自给定的日历时间 time 的日期和时间信息，为空终止多字节字符串 str 。最多写入 count 字节。

参数

str - 指向待输出 char 数组首元素的指针
count - 最大写入字节数
format - 指向指定转换格式的空终止多字节字符串指针。

格式字符串由零或更多个说明符和通常字符（除 % ）构成。所有通常字符，包括空终止字符，都会被复制到输出字符串而不加修改。每个转换说明符都始于 % 字符，可选地跟随 E 或 O 修饰符（若本地环境不支持则忽略），后随决定修饰符行为的字符。下列修饰符格式可用：

转换
说明符 		解释 使用的域
% 写字面的 % 。完整转换说明必须是 %% 。
n
(C99) 		写换行符
t
(C99) 		写水平制表符
年
Y | 以 4 位十进制数写年。 | tm_year
EY
(C99) 		以替用方式写年。例如在 ja_JP 本地环境中，以“平成23年”取代“2011年”。 tm_year
y | 写年的末 2 位十进制数（范围[00,99]）。 | tm_year
Oy
(C99) 		以替用数字系统写年的末 2 位数字。例如在 ja_JP 本地环境中以“十一”取代“11”。 tm_year
Ey
(C99) 		将年写作从本地环境的替用时期 %EC 的偏移（本地环境依赖）。 tm_year
C
(C99) 		写年的首 2 位十进制数（范围 [00,99] ）。 tm_year
EC
(C99) 		以本地环境的替用表示写年份基底（时期），例如 ja_JP 中的“平成”。 tm_year
G
(C99) 		写基于 ISO 8601 的年，即是包含指定星期的年份。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
g
(C99) 		写基于 ISO 8601 的年，即是包含指定星期年份，的后 2 位数（范围 [00,99] ）。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
月
b | 写缩略月名，例如 Oct （本地环境依赖）。 | tm_mon
Ob
(C23) 		以本地环境的替用表示写缩写月名 tm_mon
h
(C99) 		与 b 同意。 tm_mon
B | 写完整月名，例如 October （本地环境依赖）。 | tm_mon
OB
(C23) 		以本地环境的替用表示写适合的完整月名 tm_mon
m | 将月写作十进制数（范围 [01,12] ）。 | tm_mon
Om
(C99) 		以替用数字系统写月。例如 ja_JP 本地环境中“十二”取代“12”。 tm_mon
星期
U | 以十进制数写年的星期（星期日是星期的首日）（范围 [00,53] ）。 | tm_year, tm_wday, tm_yday
OU
(C99) 		以替用数值系统写如同用 %U 的年的星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
W | 以十进制数写年的星期（星期一是星期的首日）（范围 [00,53] ）。 | tm_year, tm_wday, tm_yday
OW
(C99) 		以替用数值系统写如同用 %W 的年的第星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
V
(C99) 		写 ISO 8601 的年的星期（范围[00,53]）。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
OV
(C99) 		以替用数值系统写如同用 %V 的年的星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
年/月之日
j | 以十进制数写年的第几日（范围 [001,366] ）。 | tm_yday
d | 以十进制数写月的第几日（范围 [01,31] ）。 | tm_mday
Od
(C99) 		以替用数字系统写零基的月的第几日。例如 ja_JP 本地环境中“二十七”取代“ 27 ”。

单字符前加空格。

 tm_mday
e
(C99) 		以十进制数写月的第几日（范围[01,31]）。

单数字前加空格。

 tm_mday
Oe
(C99) 		以替用数字系统写一基的月的第几日。例如 ja_JP 本地环境中“二十七”取代“27”。

单字符前加空格。

 tm_mday
星期之日
a | 写缩略的星期日期名，例如 Fri （本地环境依赖）。 | tm_wday
A | 写完整的星期日期名，例如 Friday （本地环境依赖）。 | tm_wday
w | 以十进制数写星期日期，其中星期日是 0 （范围 [0-6] ）。 | tm_wday
Ow
(C99) 		用替用数字系统写星期日期，其中星期日是 0 。例如 ja_JP 本地环境中“二”取代“2”。 tm_wday
u
(C99) 		十进制数写星期日期，其中星期一是 1 （ ISO 8601 格式）（范围 [1-7] ）。 tm_wday
Ou
(C99) 		用替用数字系统写星期日期，其中星期一是 1 。例如 ja_JP 本地环境中“二”取代“2”。 tm_wday
时、分、秒
H | 以十进制数写时， 24 小时制（范围 [00-23] ）。 | tm_hour
OH
(C99) 		以替用数字系统写 24 小时制的时。例如 ja_JP 本地环境中“十八”取代“18”。 tm_hour
I | 以十进制数写时， 12 小时制（范围 [01,12] ）。 | tm_hour
OI
(C99) 		以替用数字系统写 12 小时制的时。例如 ja_JP 本地环境中“六”取代“6”。 tm_hour
M | 以十进制数写分（范围 [00,59] ）。 | tm_min
OM
(C99) 		以替用数字系统写分。例如 ja_JP 本地环境中“二十五”取代“25”。 tm_min
S | 以十进制数写秒（范围 [00,60] ）。 | tm_sec
OS
(C99) 		以替用数字系统写秒。例如 ja_JP 本地环境中“二十四”取代“24”。 tm_sec
其他
c | 写标准日期时间字符串。例如 Sun Oct 17 04:41:13 2010 （本地环境依赖）。 | 全部
Ec
(C99) 		写替用日期时间字符串。例如 ja_JP 本地环境中“平成23年”取代“2011年”。 全部
x | 写本地化的日期表示（本地环境依赖）。 | 全部
Ex
(C99) 		写替用日期表示。例如 ja_JP 本地环境中“平成23年”取代“2011年”。 全部
X | 写本地化的时间表示，例如 18:40:20 或 6:40:20 PM （本地环境依赖）。 | 全部
EX
(C99) 		写替用时间表示（本地环境依赖）。 全部
D
(C99) 		等价于"%m/%d/%y"。 tm_mon, tm_mday, tm_year
F
(C99) 		等价于"%Y-%m-%d"（ ISO 8601 日期格式）。 tm_mon, tm_mday, tm_year
r
(C99) 		写本地化的 12 小时制时间（本地环境依赖）。 tm_hour, tm_min, tm_sec
R
(C99) 		等价于"%H:%M"。 tm_hour, tm_min
T
(C99) 		等价于"%H:%M:%S"（ ISO 8601 时间格式）。 tm_hour, tm_min, tm_sec
p | 写本地化的 a.m. 或 p.m. （本地环境依赖）。 | tm_hour
z
(C99) 		以 ISO 8601 格式（例如 -0430 ）写距 UTC 的偏移，或者倘若时区信息不可用则不写字符。 tm_isdst
Z | 写依赖本地环境的时区名或缩写，或者若时区信息不可用则不写字符。 | tm_isdst

time - 指向指定待格式化时间的 struct tm 对象

返回值

成功时，返回写入 str 所指向的字符数组的字节数，不包含终止 '\0' 。若在能存储整个字符串前抵达 count ，则返回 ​0​ ，写入内容是未定义的。

示例

#include <stdio.h>
#include <time.h>
#include <locale.h>

int main(void)
{
    char buff[70];
    struct tm my_time = { .tm_year=112, // = 2012年
                          .tm_mon=9,    // = 10月
                          .tm_mday=9,   // = 9日
                          .tm_hour=8,   // = 8时
                          .tm_min=10,   // = 10分
                          .tm_sec=20    // = 20秒
    };

    if (strftime(buff, sizeof buff, "%A %c", &my_time)) {
        puts(buff);
    } else {
        puts("strftime failed");
    }

    setlocale(LC_TIME, "el_GR.utf8");

    if (strftime(buff, sizeof buff, "%A %c", &my_time)) {
        puts(buff);
    } else {
        puts("strftime failed");
    }
}

输出：

Sunday Sun Oct  9 08:10:20 2012
Κυριακή Κυρ 09 Οκτ 2012 08:10:20 πμ EST

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.3.5 The strftime function (p: 394-397)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.23.3.5 The strftime function (p: 343-347)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.12.3.5 The strftime function

参阅

asctimeasctime_rasctime_s (C23)(C11) | 将 struct tm 对象转换成文本表示 (函数)
ctimectime_rctime_s (C23)(C11) | 将 struct time_t 对象转换成文本表示 (函数)
wcsftime (C95) | 将 struct tm 对象转换成自定义宽字符文本表示 (函数)


time

< c‎ | chrono
定义于头文件 <time.h>
time_t time( time_t *arg );

返回编码成 time_t 对象的当前日历时间，并将其存储于 arg 指向的 time_t 对象（除非 arg 为空指针）。

参数

arg - 指向将存储时间的 time_t 对象的指针，或空指针

返回值

成功时返回编码成 time_t 对象的当前日历时间。错误时返回 ( time_t )(-1) 。若arg不是空指针，则返回值也会存储于 arg 所指向的对象。

注意

日历时间在 time_t 中的编码是未指定的，但多数系统遵循 POSIX 规定，返回保有从纪元开始至今秒数的整数类型值。 time_t 为32位有符号整数的实现（许多历史上的实现）会在 2038 年出错。

示例

#include <stdio.h>
#include <time.h>
#include <stdint.h>

int main(void)
{
    time_t result = time(NULL);
    if(result != (time_t)(-1))
        printf("The current time is %s(%jd seconds since the Epoch)\n",
               asctime(gmtime(&result)), (intmax_t)result);
}

可能的输出：

The current time is Fri Apr 24 15:05:25 2015
(1429887925 seconds since the Epoch)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.2.4 The time function (p: 391)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.23.2.4 The time function (p: 341)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.12.2.4 The time function

参阅

localtimelocaltime_rlocaltime_s (C23)(C11) | 将从纪元开始的时间转换成以本地时间表示的日历时间 (函数)
gmtimegmtime_rgmtime_s (C23)(C11) | 将从纪元开始的时间转换成以协调世界时（UTC）表示的日历时间 (函数)
timespec_get (C11) | 返回基于给定时间基底的日历时间 (函数)


time_t

< c‎ | chrono
定义于头文件 <time.h>
typedef /* unspecified */ time_t;

足以表示时间的算术 (C11 前)实数 (C11 起)类型。

尽管 C 标准没有定义，它几乎总是一个保有从 UTC 1970 年 1 月 1 日 00:00 开始秒数的整数值（不计闰秒），对应 POSIX 时间。

注意

标准在提及 time_t 类型值时使用用语日历时间。

示例

显示纪元起点。

#include <stdint.h>
#include <stdio.h>
#include <time.h>

int main(void)
{
    time_t epoch = 0;
    printf("%jd seconds since the epoch began\n", (intmax_t)epoch);
    printf("%s", asctime(gmtime(&epoch)));
}

可能的输出：

0 seconds since the epoch began
Thu Jan  1 00:00:00 1970

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.1/3 Components of time (p: 388)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.23.1/3 Components of time (p: 338)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.12.1 Components of time

参阅

time | 返回纪元开始经过的当前系统日历时间 (函数)
localtimelocaltime_rlocaltime_s (C23)(C11) | 将从纪元开始的时间转换成以本地时间表示的日历时间 (函数)
gmtimegmtime_rgmtime_s (C23)(C11) | 将从纪元开始的时间转换成以协调世界时（UTC）表示的日历时间 (函数)


timespec

< c‎ | chrono
定义于头文件 <time.h> |
struct timespec; | (C11 起)

保有时间间隔的结构体，将其拆分成秒数和纳秒数。

成员对象

time_t tv_sec | 整秒数（合法值 >= 0）
long tv_nsec | 纳秒数（合法值为 [0, 999999999] ）

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.1/3 Components of time (p: 388)

参阅

timespec_get (C11) | 返回基于给定时间基底的日历时间 (函数)
tm | 日历时间类型 (结构体)


timespec_get

< c‎ | chrono
定义于头文件 <time.h> |  |
int timespec_get( struct timespec *ts, int base ); | (1) | (C11 起)
#define TIME_UTC /* implementation-defined */ | (2) | (C11 起)
1) 修改 ts 所指向的 struct timespec 对象，以保有以时间基底 base 表示的当前日历时间。
2) 展开成适用作 timespec_get 的 base 参数的值。

实现可以提供其他以 TIME_ 为首的宏常量，以指示时间基底。

若 base 等于 TIME_UTC ，则

  • 设 ts->tv_sec 为实现定义的纪元后的秒数，截断到整数值。
  • 设 ts->tv_nsec 成员为纳秒数的整数值，按照系统时钟的解析度舍入。

参数

ts | - | 指向 struct timespec 类型对象的指针
base | - | TIME_UTC 或其他任何指示时间基底的非零整数值

返回值

成功是返回base的值，否则返回零。

注解

POSIX 函数 clock_gettime(CLOCK_REALTIME, ts) 亦可用于将从纪元开始的时间传达给 struct timespec 。

示例

#include <stdio.h>
#include <time.h>

int main(void)
{
    struct timespec ts;
    timespec_get(&ts, TIME_UTC);
    char buff[100];
    strftime(buff, sizeof buff, "%D %T", gmtime(&ts.tv_sec));
    printf("Current time: %s.%09ld UTC\n", buff, ts.tv_nsec);
}

输出：

Current time: 02/18/15 14:34:03.048508855 UTC

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.27.2.5 The timespec_get function (p: 286)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.2.5 The timespec_get function (p: 390)

参阅

timespec (C11) | 单位为秒和纳秒的时间 (结构体)
timespec_getres (C23) | 返回基于给定时间基底的日历时间的解析度 (函数)
time | 返回纪元开始经过的当前系统日历时间 (函数)


timespec_getres

< c‎ | chrono
定义于头文件 <time.h> |
int timespec_getres( struct timespec *ts, int base ); | (C23 起)

若 ts 为非空且 timespec_get 支持 base ，则修改 *ts 以保有 timespec_get 对 base 提供的时间的解析度。对每个支持的 base ，同一次程序执行期间多次调用 timespec_getres 拥有等同的结果。

参数

ts | - | 指向 struct timespec 类型对象的指针
base | - | TIME_UTC 或另一指示时间基底的非零值

返回值

若支持 base 则为 base 的值，否则为零。

注解

POSIX 函数 clock_getres(clock_id, ts) 亦可用于以 clock_id 所标识的时间的解析度填充 timespec 。

示例

#include <stdio.h>
#include <time.h>

int main(void)
{
    char buff[128];
    struct timespec ts;
    const int res = timespec_getres(&ts, TIME_UTC);
    if (res == TIME_UTC) {
        struct tm timer;
        strftime(buff, sizeof buff, "%D %T", gmtime_r(&ts.tv_sec, &timer));
        printf("Time resolution info: %s.%09ld UTC\n", buff, ts.tv_nsec);
    } else {
        printf("TIME_UTC base is not supported.");
    }
}

可能的输出：

Time resolution info: 01/01/70 00:00:00.000000001 UTC

参阅

timespec (C11) | 单位为秒和纳秒的时间 (结构体)
timespec_get (C11) | 返回基于给定时间基底的日历时间 (函数)
time | 返回纪元开始经过的当前系统日历时间 (函数)


tm

< c‎ | chrono
定义于头文件 <time.h>
struct tm;

保有拆分成其组分的日历日期和时间的结构体。

成员对象

int tm_sec | 分后之秒 – [0, 61] (C99 前)[0, 60] (C99 起)[注 1]
int tm_min | 时后之分 – [0, 59]
int tm_hour | 自午夜起的小时 – [0, 23]
int tm_mday | 月之日 – [1, 31]
int tm_mon | 自 1 月起的月 – [0, 11]
int tm_year | 自 1900 年起的年
int tm_wday | 自星期日起的星期 – [0, 6]
int tm_yday | 从 1 月 1 日起的日 – [0, 365]
int tm_isdst | 夏时令标签。若夏时令有效则此值为正，若无效则为零，若无可用信息则为负。
注意

标准只强制前述成员按任一顺序存在。实现通常对此结构体添加额外的数据成员。

  1. ↑ 范围允许正的闰秒。不允许一分钟有二个闰秒（ C89 的范围 0..61 是缺陷）。

示例

显示日历时间的起点。

#include <stdio.h>
#include <time.h>

int main(void)
{
    struct tm start = {.tm_mday=1};
    mktime(&start);
    printf("%s\n", asctime(&start));
}

可能的输出：

Mon Jan  1 00:00:00 1900

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.27.1/3 Components of time (p: 284)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.27.1/3 Components of time (p: 388)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.23.1/3 Components of time (p: 338)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.12.1 Components of time

参阅

localtimelocaltime_rlocaltime_s (C23)(C11) | 将从纪元开始的时间转换成以本地时间表示的日历时间 (函数)
gmtimegmtime_rgmtime_s (C23)(C11) | 将从纪元开始的时间转换成以协调世界时（UTC）表示的日历时间 (函数)


wcsftime

< c‎ | chrono
定义于头文件 <wchar.h> |
size_t wcsftime( wchar_t* str, size_t count, const wchar_t* format, tm * time ); | (C95 起)

将来自给定的日历时间 time 的日期和时间信息，按照格式字符串 format ，转换成空终止宽字符串 str 。最多写入 count 个宽字符。

参数

str - 指向待输出的 wchar_t 数组首元素的指针
count - 最大写入宽字符数
format - 指向指定转换格式的空终止宽字符串指针。

格式字符串由零或更多个说明符和通常字符（除 % ）构成。所有通常字符，包括空终止字符，都会被复制到输出字符串而不加修改。每个转换说明符都始于 % 字符，可选地跟随 E 或 O 修饰符（若本地环境不支持则忽略），后随决定修饰符行为的字符。下列修饰符格式可用：

转换
说明符 		解释 使用的域
% 写字面的 % 。完整转换说明必须是 %% 。
n
(C99) 		写换行符
t
(C99) 		写水平制表符
年
Y | 以 4 位十进制数写年。 | tm_year
EY
(C99) 		以替用方式写年。例如在 ja_JP 本地环境中，以“平成23年”取代“2011年”。 tm_year
y | 写年的末 2 位十进制数（范围[00,99]）。 | tm_year
Oy
(C99) 		以替用数字系统写年的末 2 位数字。例如在 ja_JP 本地环境中以“十一”取代“11”。 tm_year
Ey
(C99) 		将年写作从本地环境的替用时期 %EC 的偏移（本地环境依赖）。 tm_year
C
(C99) 		写年的首 2 位十进制数（范围 [00,99] ）。 tm_year
EC
(C99) 		以本地环境的替用表示写年份基底（时期），例如 ja_JP 中的“平成”。 tm_year
G
(C99) 		写基于 ISO 8601 的年，即是包含指定星期的年份。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
g
(C99) 		写基于 ISO 8601 的年，即是包含指定星期年份，的后 2 位数（范围 [00,99] ）。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
月
b | 写缩略月名，例如 Oct （本地环境依赖）。 | tm_mon
Ob
(C23) 		以本地环境的替用表示写缩写月名 tm_mon
h
(C99) 		与 b 同意。 tm_mon
B | 写完整月名，例如 October （本地环境依赖）。 | tm_mon
OB
(C23) 		以本地环境的替用表示写适合的完整月名 tm_mon
m | 将月写作十进制数（范围 [01,12] ）。 | tm_mon
Om
(C99) 		以替用数字系统写月。例如 ja_JP 本地环境中“十二”取代“12”。 tm_mon
星期
U | 以十进制数写年的星期（星期日是星期的首日）（范围 [00,53] ）。 | tm_year, tm_wday, tm_yday
OU
(C99) 		以替用数值系统写如同用 %U 的年的星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
W | 以十进制数写年的星期（星期一是星期的首日）（范围 [00,53] ）。 | tm_year, tm_wday, tm_yday
OW
(C99) 		以替用数值系统写如同用 %W 的年的第星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
V
(C99) 		写 ISO 8601 的年的星期（范围[00,53]）。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
OV
(C99) 		以替用数值系统写如同用 %V 的年的星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
年/月之日
j | 以十进制数写年的第几日（范围 [001,366] ）。 | tm_yday
d | 以十进制数写月的第几日（范围 [01,31] ）。 | tm_mday
Od
(C99) 		以替用数字系统写零基的月的第几日。例如 ja_JP 本地环境中“二十七”取代“ 27 ”。

单字符前加空格。

 tm_mday
e
(C99) 		以十进制数写月的第几日（范围[01,31]）。

单数字前加空格。

 tm_mday
Oe
(C99) 		以替用数字系统写一基的月的第几日。例如 ja_JP 本地环境中“二十七”取代“27”。

单字符前加空格。

 tm_mday
星期之日
a | 写缩略的星期日期名，例如 Fri （本地环境依赖）。 | tm_wday
A | 写完整的星期日期名，例如 Friday （本地环境依赖）。 | tm_wday
w | 以十进制数写星期日期，其中星期日是 0 （范围 [0-6] ）。 | tm_wday
Ow
(C99) 		用替用数字系统写星期日期，其中星期日是 0 。例如 ja_JP 本地环境中“二”取代“2”。 tm_wday
u
(C99) 		十进制数写星期日期，其中星期一是 1 （ ISO 8601 格式）（范围 [1-7] ）。 tm_wday
Ou
(C99) 		用替用数字系统写星期日期，其中星期一是 1 。例如 ja_JP 本地环境中“二”取代“2”。 tm_wday
时、分、秒
H | 以十进制数写时， 24 小时制（范围 [00-23] ）。 | tm_hour
OH
(C99) 		以替用数字系统写 24 小时制的时。例如 ja_JP 本地环境中“十八”取代“18”。 tm_hour
I | 以十进制数写时， 12 小时制（范围 [01,12] ）。 | tm_hour
OI
(C99) 		以替用数字系统写 12 小时制的时。例如 ja_JP 本地环境中“六”取代“6”。 tm_hour
M | 以十进制数写分（范围 [00,59] ）。 | tm_min
OM
(C99) 		以替用数字系统写分。例如 ja_JP 本地环境中“二十五”取代“25”。 tm_min
S | 以十进制数写秒（范围 [00,60] ）。 | tm_sec
OS
(C99) 		以替用数字系统写秒。例如 ja_JP 本地环境中“二十四”取代“24”。 tm_sec
其他
c | 写标准日期时间字符串。例如 Sun Oct 17 04:41:13 2010 （本地环境依赖）。 | 全部
Ec
(C99) 		写替用日期时间字符串。例如 ja_JP 本地环境中“平成23年”取代“2011年”。 全部
x | 写本地化的日期表示（本地环境依赖）。 | 全部
Ex
(C99) 		写替用日期表示。例如 ja_JP 本地环境中“平成23年”取代“2011年”。 全部
X | 写本地化的时间表示，例如 18:40:20 或 6:40:20 PM （本地环境依赖）。 | 全部
EX
(C99) 		写替用时间表示（本地环境依赖）。 全部
D
(C99) 		等价于"%m/%d/%y"。 tm_mon, tm_mday, tm_year
F
(C99) 		等价于"%Y-%m-%d"（ ISO 8601 日期格式）。 tm_mon, tm_mday, tm_year
r
(C99) 		写本地化的 12 小时制时间（本地环境依赖）。 tm_hour, tm_min, tm_sec
R
(C99) 		等价于"%H:%M"。 tm_hour, tm_min
T
(C99) 		等价于"%H:%M:%S"（ ISO 8601 时间格式）。 tm_hour, tm_min, tm_sec
p | 写本地化的 a.m. 或 p.m. （本地环境依赖）。 | tm_hour
z
(C99) 		以 ISO 8601 格式（例如 -0430 ）写距 UTC 的偏移，或者倘若时区信息不可用则不写字符。 tm_isdst
Z | 写依赖本地环境的时区名或缩写，或者若时区信息不可用则不写字符。 | tm_isdst

返回值

成功时，返回写入 str 所指向的宽字符数组的字符数，不包含终止 L'\0' 。若在能存储整个字符串前抵达 count ，则返回 ​0​ ，写入内容是未定义的。

示例

#include <stdio.h>
#include <time.h>
#include <wchar.h>
#include <locale.h>

int main(void)
{
    wchar_t buff[40];
    struct tm my_time = { .tm_year=112, // = 2012 年
                          .tm_mon=9,    // = 10 月
                          .tm_mday=9,   // = 9 日
                          .tm_hour=8,   // = 8 时
                          .tm_min=10,   // = 10 分
                          .tm_sec=20    // = 20 秒
    };

    if (wcsftime(buff, sizeof buff, L"%A %c", &my_time)) {
        printf("%ls\n", buff);
    } else {
        puts("wcsftime failed");
    }

    setlocale(LC_ALL, "ja_JP.utf8");

    if (wcsftime(buff, sizeof buff, L"%A %c", &my_time)) {
        printf("%ls\n", buff);
    } else {
        puts("wcsftime failed");
    }
}

输出：

Sunday Sun Oct  9 08:10:20 2012
日曜日 2012年10月09日 08時10分20秒

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.5.1 The wcsftime function (p: 439-440)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.5.1 The wcsftime function (p: 385-386)

参阅

strftime
 将 struct tm 对象转换成自定义文本表示
(函数)


注释

< c

注释的作用是一套代码内文档。插入注释到程序中时，编译器直接忽略它们；它们只是有意地被人类用作读取源码的笔记。

语法

/* 注释 */ | (1) |
// 注释\n | (2) | (C99 起)
1) 通称为“ C 风格”或“多行”注释。
2) 通称为“ C++ 风格”或“单行”注释。

在翻译阶段 3，通过把每段注释替换为单个空白字符，将所有注释从程序中移除。

C 风格

C 风格注释通常用于注释大块文本或小片代码；然而，能用它们注释单行。可以简单地以 /* 和 */ 环绕文本，将文本作为 C 风格注释插入。 C 风格注释告诉编译器忽略 /* 和 */ 间的所有内容。尽管不是 C 标准的一部分， /** 和 */ 常用于指示文档块；这是合法的，因为星号被简单地当做注释的一部分。

除了在字符常量、字符串字面量或注释中，字符 /* 引入一段注释。检验这种注释的内容仅是为了鉴别多字节字符，以及寻找终止注释的 */ 。 C 风格注释不能嵌套。

C++ 风格

C++ 风格注释通常用于注释单行文本或代码；然而，能将它们放在一起组成多行注释。可以简单地将 // 置于文本前，文本后跟随换行符，以将文本作为 C++ 风格注释插入。 C++ 风格注释告诉编译器忽略 // 和换行符间的所有内容。

除了在字符常量、字符串字面量或注释中，字符 // 引入一段注释，它包含所有多字节字符，直至但不包含下个换行符。检验这种注释的内容仅是为了鉴别多字节字符，以及寻找终止注释的换行符。 C++ 风格注释能嵌套：

//  y = f(x);   // 调用算法

C 风格注释可出现在 C++ 风格注释内：

//  y = f(x);   /* 调用算法 */

C++ 风格注释可出现在 C 风格注释内；这是排除一小块源代码的机制：

/*
    y = f(x);   // 调用算法
    z = g(x);
*/

 (C99 起)

注意

因为注释在预处理器阶段前被移除，宏不能用于组成注释，而不终止的 C 风格注释不会从被 #include 的文件中漏出。

/* 试图用宏组成注释。 */
/* 但空格替换字符 "//" 。 */
#ifndef DEBUG
    #define PRINTF //
#else
    #define PRINTF printf
#endif
...
PRINTF("Error in file %s at line %i\n", __FILE__, __LINE__);

除了注释掉，用于排除源码的其他机制是：

#if 0
    puts("this will not be compiled");
    /* 与 C 风格注释不冲突 */
    // 与 C++ 风格注释不冲突
#endif

和

if(0) {
    puts("this will be compiled but not be executed");
    /* 与 C 风格注释不冲突 */
    // 与 C++ 风格注释不冲突
}

C99 中引入 // 注释，在一些罕有场合是破坏性更改：

a = b //*除数：*/ c
+ d; /* C89 编译为 a = b / c + d;
        C99 编译为 a = b + d; */

示例

/*
C 风格注释
能含有多行。
*/

/* 或仅一行。 */

// C++ 风格注释能注释一行。

// 或者，能将
// 它们串在一起。
#include <stdio.h>

int main(void)
{
  // 将不运行下方代码
  // puts("Hello");

  // 将运行下方代码
  puts("Hello");
  return 0;
}

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.4.9 Comments (p: 75)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.4.9 Comments (p: 66)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.1.9 Comments

参阅


当前状况

< c

最近的里程碑：C17 已经发布，C23 正在进行中

C17 已经发布，C23 的工作正在进行中。

本节未完成
原因：重复 C++ 页面中的措辞

当前的时间表在文档 N2864 中。.

你还可以访问 open-std.org 以获取最新的 C 标准委员会的文档。通过阅读这些建议，你可以跟踪 C 的发展趋势，并了解一个很酷的想法是如何变成标准的。但是，这些文档不是也不应该被视为标准文档。

参阅


错误处理

< c

错误号

定义于头文件 <errno.h>
errno | 展开成 POSIX 兼容的线程局域错误编号变量 (宏变量)
E2BIG, EACCES, ..., EXDEV | 标准 POSIX 兼容的错误条件宏 (宏常量)

断言

定义于头文件 <assert.h>
assert | 若用户指定的条件非true，则异常终止程序。可以在发行版本禁用。 (宏函数)
static_assert (C11) | 若常量表达式为假则发布编译诊断 (关键词宏)

边界检查

标准库提供了一些既存函数的边界检查版本（ gets_s 、 fopen_s 、 printf_s 、 strcpy_s 、 wcscpy_s 、 mbstowcs_s 、 qsort_s 、 getenv_s 等）。这些功能是可选的，并且仅若定义 __STDC_LIB_EXT1__ 才可用。下列宏和函数支持此功能。

定义于头文件 <errno.h>
定义于头文件 <stdio.h>
errno_t (C11) | 对 int 的 typedef ，用于自描述性函数返回 errno 值 (typedef)
定义于头文件 <stddef.h>
定义于头文件 <stdio.h>
定义于头文件 <stdlib.h>
定义于头文件 <string.h>
定义于头文件 <time.h>
定义于头文件 <wchar.h>
rsize_t (C11) | 对 size_t 相同类型的 typedef ，用于自描述性函数在运行时检查它们的参数范围 (typedef)
定义于头文件 <stdint.h>
RSIZE_MAX (C11) | 范围检查函数可接受的最大大小，展开成常量或可能在运行时改变的变量（例如，当前分配的内存大小改变时） (宏变量)
定义于头文件 <stdlib.h>
set_constraint_handler_s (C11) | 设置边界检查函数的出错回调 (函数)
abort_handler_s (C11) | 边界检查函数的异常中止回调 (函数)
ignore_handler_s (C11) | 边界检查函数的忽略回调 (函数)

注意：边界检查函数的实现可用于开源库 Safe C 及 Slibc ，还有 Watcom C 的一部分。亦有可用于 Visual Studio 的边界检查函数的不兼容集合。

 (C11 起)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.2 Diagnostics <assert.h> (p: 186-187)
  • 7.5 Errors <errno.h> (p: 205)
  • 7.19 Common definitions <stddef.h> (p: 288)
  • 7.20 Integer types <stdint.h> (p: 289-295)
  • 7.21 Input/output <stdio.h> (p: 296-339)
  • 7.22 General utilities <stdlib.h> (p: 340-360)
  • K.3.1.3 Use of errno (p: 584)
  • K.3.2/2 errno_t (p: 585)
  • K.3.3/2 rsize_t (p: 585)
  • K.3.4/2 RSIZE_MAX (p: 585)
  • 7.31.3 Errors <errno.h> (p: 455)
  • 7.31.10 Integer types <stdint.h> (p: 456)
  • 7.31.11 Input/output <stdio.h> (p: 456)
  • 7.31.12 General utilities <stdlib.h> (p: 456)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.2 Diagnostics <assert.h> (p: 169)
  • 7.5 Errors <errno.h> (p: 186)
  • 7.26.3 Errors <errno.h> (p: 401)
  • 7.26.8 Integer types <stdint.h> (p: 401)
  • 7.26.9 Input/output <stdio.h> (p: 402)
  • 7.26.10 General utilities <stdlib.h> (p: 402)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.2 DIAGNOSTICS <assert.h>
  • 4.1.3 Errors <errno.h>
  • 4.13.1 Errors <errno.h>
  • 4.13.6 Input/output <stdio.h>
  • 4.13.7 General utilities <stdlib.h>

参阅

math_errhandlingMATH_ERRNOMATH_ERREXCEPT
(C99)(C99)(C99)
 定义用于常用数学函数的错误处理机制
(宏常量)


abort_handler_s

< c‎ | error
定义于头文件 <stdlib.h> |
void abort_handler_s( const char * restrict msg, void * restrict ptr, errno_t error ); | (C11 起)

写入必须包含 msg 所指向字符串的实现定义消息到 stderr ，然后调用 abort() 。

指向此函数的指针可以传递给 set_constraint_handler_s 以建立运行时制约违规处理。

同所有边界检查函数， abort_handler_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <stdlib.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

msg | - | 指向要写到标准错误输出的消息的指针
ptr | - | 指向实现定义的对象的指针或空指针。实现定义对象的例子，是给出检测到违规的函数名和检测到违规时的行号的对象
error | - | errno_t 类型的正值

返回值

无；此函数不对其调用者返回

注意

若从未调用 set_constraint_handler_s ，则默认处理函数是实现定义的：可以为 abort_handler_s 、 ignore_handler_s 或另外的实现定义处理函数。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
#ifdef __STDC_LIB_EXT1__
    char dst[2];
    set_constraint_handler_s(ignore_handler_s);
    int r = strcpy_s(dst, sizeof dst, "Too long!");
    printf("dst = \"%s\", r = %d\n", dst, r);
    set_constraint_handler_s(abort_handler_s);
    r = strcpy_s(dst, sizeof dst, "Too long!");
    printf("dst = \"%s\", r = %d\n", dst, r);
#endif
}

可能的输出：

dst = "", r = 22
abort_handler_s was called in response to a runtime-constraint violation.

The runtime-constraint violation was caused by the following expression in strcpy_s:
(s1max <= (s2_len=strnlen_s(s2, s1max)) ) (in string_s.c:62)

Note to end users: This program was terminated as a result
of a bug present in the software. Please reach out to your
software's vendor to get more help.
Aborted

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • K.3.6.1.2 The abort_handler_s function (p: 605)

参阅

ignore_handler_s (C11) | 边界检查函数的忽略回调 (函数)
set_constraint_handler_s (C11) | 设置边界检查函数的出错回调 (函数)


assert

< c‎ | error
定义于头文件 <assert.h>
#ifdef NDEBUG

#define assert(condition) ((void)0)
#else
#define assert(condition) /*implementation defined*/

#endif

宏 assert 的定义依赖于标准库不定义的另一个宏 NDEBUG 。

若 NDEBUG 在包含了 <assert.h> 的源代码中的点定义为宏名，则 assert 不做任何事。

若不定义 NDEBUG ，则 assert 将其参数（必须拥有标量类型）与零比较相等。若相等，则 assert 在标准错误输出上输出实现指定的诊断信息，并调用 abort () 。诊断信息要求包含表达式的文本，还有预定义变量 __func__ 与 (C99 起) 预定义宏 __FILE__、 __LINE__ 的值。

参数

condition - 标量类型表达式

返回值

（无）

注解

没有标准化的添加消息到 assert 错误的接口。一个包含它的方式是使用逗号运算符：

assert(("There are five lights", 2 + 2 == 5));

assert 在 Microsoft CRT 中的实现不遵从 C99 以及后续标准版本，因为其底层函数 ( _wassert ）不接收 __func__ 或等价的替代品。

示例

#include <stdio.h>
// 反注释可禁用 assert()
// #define NDEBUG
#include <assert.h>
#include <math.h>

int main(void)
{
    double x = -1.0;
    assert(x >= 0.0);
    printf("sqrt(x) = %f\n", sqrt(x));

    return 0;
}

输出：

output with NDEBUG not defined:
a.out: main.cpp:10: main: Assertion `x >= 0.0' failed.

output with NDEBUG defined:
sqrt(x) = -nan

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.2.1.1 The assert macro (p: 135)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.2.1.1 The assert macro (p: 186-187)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.2.1.1 The assert macro (p: 169)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.2.1.1 The assert macro

参阅

abort
 引发非正常的程序终止（不清理）
(函数)


errno

< c‎ | error
定义于头文件 <errno.h>
#define errno /*implementation-defined*/

errno 是一个预处理器宏（见后述），展开成线程局域的 (C11 起) int 类型可修改左值。一些标准库函数通过写入正整数到 errno 指定错误。通常，会将 errno 的值设置为错误码之一。错误码作为以字母 E 后随大写字母或数字开始的宏常量，列于 <errno.h> 。

errno 的值在程序启动时为 ​0​ ，而且无论是否出现错误，都允许库函数将正整数写入 errno ，不过库函数决不会将 ​0​ 存储于 errno 。

库函数 perror 和 strerror 能用于获得对应当前 errno 值的错误条件的文本描述。

注解： C11 前， C 标准有矛盾的要求，称 errno 是宏但亦称“不指明 errno 是宏还是声明带外部链接的标识符”。 C11 修正了此错误，要求必须定义它为宏（参阅 WG14 N1338 ）。

示例

#include <stdio.h>
#include <math.h>
#include <errno.h>

void show_errno(void)
{
    const char *err_info = "unknown error";
    switch (errno) {
    case EDOM:
        err_info = "domain error";
        break;
    case EILSEQ:
        err_info = "illegal sequence";
        break;
    case ERANGE:
        err_info = "pole or range error";
        break;
    case 0:
        err_info = "no error";
    }
    fputs(err_info, stdout);
    puts(" occurred");
}

int main(void)
{
    fputs("MATH_ERRNO is ", stdout);
    puts(math_errhandling & MATH_ERRNO ? "set" : "not set");

    errno = 0;
    1.0/0.0;
    show_errno();

    errno = 0;
    acos(+1.1);
    show_errno();

    errno = 0;
    log(0.0);
    show_errno();

    errno = 0;
    sin(0.0);
    show_errno();
}

可能的输出：

MATH_ERRNO is set
no error occurred
domain error occurred
pole or range error occurred
no error occurred

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.5 Errors <errno.h> (p: 205)
  • K.3.1.3 Use of errno (p: 584)
  • K.3.2 Errors <errno.h> (p: 585)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.5 Errors <errno.h> (p: 186)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.1.3 Errors <errno.h>

参阅

E2BIG, EACCES, ..., EXDEV | 标准 POSIX 兼容的错误条件宏 (宏常量)
perror | 显示对应当前错误的字符串到 stderr (函数)
strerrorstrerror_sstrerrorlen_s (C11)(C11) | 返回给定错误码的文本版本 (函数)
math_errhandlingMATH_ERRNOMATH_ERREXCEPT (C99)(C99)(C99) | 定义用于常用数学函数的错误处理机制 (宏常量)


错误号

< c‎ | error

每个定义于 <errno.h> 的宏都展开成 int 类型的整数常量表达式，并且拥有独立的正整数值。下列常量得到定义（实现可以定义更多，只要以 'E' 开始，后随数字或大写字母）：

定义于头文件 <errno.h>
EDOM | 数学参数在定义域外 (宏常量)
EILSEQ (C95) | 非法字节序列 (宏常量)
ERANGE | 结果过大 (宏常量)

注意

POSIX 和 C++ 标准库定义了更多的额外错误常量，而且每一个单独实现可能定义更多，例如 Linux 上的 errno(3) 或 BSD 和 OS X 上的 intro(2) 。

示例

#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <string.h>

int main(void)
{
    errno = 0;
    printf("log(-1.0) = %f\n", log(-1.0));
    printf("%s\n\n",strerror(errno));

    errno = 0;
    printf("log(0.0)  = %f\n", log(0.0));
    printf("%s\n",strerror(errno));
}

可能的输出：

log(-1.0) = nan
Numerical argument out of domain

log(0.0)  = -inf
Numerical result out of range

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.5/2 Errors <errno.h> (p: 205)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.5/2 Errors <errno.h> (p: 186)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.1.3 Errors <errno.h>

参阅

errno | 展开成 POSIX 兼容的线程局域错误编号变量 (宏变量)
perror | 显示对应当前错误的字符串到 stderr (函数)
strerrorstrerror_sstrerrorlen_s (C11)(C11) | 返回给定错误码的文本版本 (函数)


ignore_handler_s

< c‎ | error
定义于头文件 <stdlib.h> |
void ignore_handler_s( const char * restrict msg, void * restrict ptr, errno_t error ); | (C11 起)

该函数会简单返回调用方，而不进行任何动作。

可以传递指向此函数的指针给 set_constraint_handler_s 以建立无任何动作的运行时制约违规处理。

同所有边界检查函数， ignore_handler_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <stdlib.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

msg | - | 指向描述错误的字符串的指针
ptr | - | 指向实现定义的对象的指针或空指针。实现定义对象的例子，是给出检测到违规的函数名和检测到违规时的行号的对象
error | - | 要由调用方函数返回的错误号，若它正好是返回 errno_t 的函数之一

返回值

（无）

注意

若以 ignore_handler_s 为运行时制约违规处理函数，则可通过检验边界检查函数的调用结果检测违规，这对于不同函数可能不同（非零 errno_t ，写入到输出字符串的空字符等等）。

若从不调用 set_constraint_handler_s ，则默认处理是实现定义的：它可以是 abort_handler_s 、 ignore_handler_s 或另外的实现定义处理函数。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
#ifdef __STDC_LIB_EXT1__
    char dst[2];
    set_constraint_handler_s(ignore_handler_s);
    int r = strcpy_s(dst, sizeof dst, "Too long!");
    printf("dst = \"%s\", r = %d\n", dst, r);
    set_constraint_handler_s(abort_handler_s);
    r = strcpy_s(dst, sizeof dst, "Too long!");
    printf("dst = \"%s\", r = %d\n", dst, r);
#endif
}

可能的输出：

dst = "", r = 22
abort_handler_s was called in response to a runtime-constraint violation.

The runtime-constraint violation was caused by the following expression in strcpy_s:
(s1max <= (s2_len=strnlen_s(s2, s1max)) ) (in string_s.c:62)

Note to end users: This program was terminated as a result
of a bug present in the software. Please reach out to your
software's vendor to get more help.
Aborted

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • K.3.6.1.3 The ignore_handler_s function (p: 606)

参阅

abort_handler_s (C11) | 边界检查函数的异常中止回调 (函数)
set_constraint_handler_s (C11) | 设置边界检查函数的出错回调 (函数)


set_constraint_handler_s, constraint_handler_t

< c‎ | error
定义于头文件 <stdlib.h> |
constraint_handler_t set_constraint_handler_s( constraint_handler_t handler ); | (C11 起)

配置所有边界检查函数在运行时制约违规时所调用的处理函数，或将其恢复成默认（若 handler 是空指针）。

此处理函数必须是 constraint_handler_t 的函数指针，定义如下：

定义于头文件 <stdlib.h> |
typedef void (*constraint_handler_t)( const char *restrict msg, void *restrict ptr, errno_t error); | (C11 起)

运行时制约违规发生时，会按照以下参数调用它：

1) 指向描述错误的字符串的指针
2) 指向实现定义的对象的指针或空指针。实现定义对象的例子，是给出检测到违规的函数名和检测到违规时的行号的对象
3) 要由调用方函数返回的错误编号，若它正好是返回 errno_t 的函数之一

若从不调用 set_constraint_handler_s ，则默认处理是实现定义的：它可以是 abort_handler_s 、 ignore_handler_s 或另外的实现定义处理函数。

同所有边界检查函数， set_constraint_handler_s, constraint_handler_t 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <stdlib.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

handler - constraint_handler_t 类型的函数指针或空指针

返回值

指向先前安装运行时制约处理函数的指针（注意：此指针决不会是空指针，因为调用 set_constraint_handler_s( NULL ) 会设置系统默认处理函数）。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
#ifdef __STDC_LIB_EXT1__
    char dst[2];
    set_constraint_handler_s(ignore_handler_s);
    int r = strcpy_s(dst, sizeof dst, "Too long!");
    printf("dst = \"%s\", r = %d\n", dst, r);
    set_constraint_handler_s(abort_handler_s);
    r = strcpy_s(dst, sizeof dst, "Too long!");
    printf("dst = \"%s\", r = %d\n", dst, r);
#endif
}

可能的输出：

dst = "", r = 22
abort_handler_s was called in response to a runtime-constraint violation.

The runtime-constraint violation was caused by the following expression in strcpy_s:
(s1max <= (s2_len=strnlen_s(s2, s1max)) ) (in string_s.c:62)

Note to end users: This program was terminated as a result
of a bug present in the software. Please reach out to your
software's vendor to get more help.
Aborted

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • K.3.6/2 constraint_handler_t (p: 604)
  • K.3.6.1.1 The set_constraint_handler_s function (p: 604-605)

参阅

abort_handler_s (C11) | 边界检查函数的异常中止回调 (函数)
ignore_handler_s (C11) | 边界检查函数的忽略回调 (函数)


static_assert

< c‎ | error
定义于头文件 <assert.h>
#define static_assert _Static_assert

此便利宏展开成关键词 _Static_assert 。

示例

#include <assert.h>
int main(void)
{
    static_assert(2 + 2 == 4, "2+2 isn't 4");      // 良式
    static_assert(sizeof(int) < sizeof(char),
                 "this program requires that int is less than char"); // 编译时错误
}

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.2/3 Diagnostics <assert.h> (p: 186)

参阅


实验性 C 特性

< c

C 标准委员会为未来的标准化出版C语言及库的实验性扩展。

注意：2012以前，此类出版使用 TR （ technical report ，技术报告）格式。自 2012 起 ISO 程序改用 TS （ technical specification ，技术规范）格式。

ISO 编号 | 名称 | 状态 | 链接
ISO/IEC TR 19769:2004 | 支持新字符类型的扩展 | 出版（ ISO 商店） 最终草案： n1040 (2003-11-07) ✔并入 C11 。 |
ISO/IEC TR 24731-1:2007 | 边界检查接口 | 出版（ ISO 商店） 最终草案： n1225 (2007-03-28) ✔并入 C11 。 |
ISO/IEC TR 18037:2008 | 支持嵌入式处理器的扩展 | 出版（ ISO 商店） 最终草案：n1169 (2006-04-04) |
ISO/IEC TR 24732:2009 | 支持十进制浮点算术的扩展 | 出版（ ISO 商店） 最终草案： n1241 (2007-07-05) 为 TS 18661-2:2015 所代替 |
ISO/IEC 24747:2009 | 支持特殊数学函数的扩展 | 出版（ ISO 商店） 草案：n1182 (2006-08-02) |
ISO/IEC TR 24731-2:2010 | 支持动态分配函数的扩展 | 出版于 2010-11-24 （ ISO 商店） 草案： n1248 (2007-08-15) | dynamic
ISO/IEC TS 17961:2013 | 安全编码规则 | 出版于 2013-11-15 （ISO 商店） 草案： n1624 (2012-06-26) TC1 出版于 2016-08-09 （ ISO 商店） |
ISO/IEC TS 18661-1:2014 | 浮点扩展：二进制浮点算术 | 出版于 2014-07-21 （ ISO 商店） 草案： n1778 (2013-11-05) C2x 草案： n2314 (2018-11-12) ✔并入 C23 。 | fpext1
ISO/IEC TS 18661-2:2015 | 浮点扩展：十进制浮点算术 | 出版于 2015-02-11 ，修订于 2015-05-18 （ ISO 商店） C2x 草案： n2341 (2019-02-26) ✔并入 C23 。 |
ISO/IEC TS 18661-3:2015 | 浮点扩展：交流及扩展类型 | 出版于 2015-10-06 （ ISO ISO 商店）。草案： n1945 (2015-06-10) 。 C2x 草案： n2601 (2020-10-15) ✔并入 C23 。 |
ISO/IEC TS 18661-4:2015 | 浮点扩展：补充函数 | 出版于 2015-10-06 （ ISO 商店）。草案： n1950 (2015-06-10) 。 C2x 草案： n2401 (2019-06-23) ✔部分并入 C23 。 | fpext4
ISO/IEC TS 18661-5:2016 | 浮点扩展：补充属性 | 出版于 2016-08-11 （ ISO 商店） 草案： n2004 (2016-03-07) |
ISO/IEC TR 24772-3:2020 | 编程语言 C 的脆弱性描述 | 出版于 2020-05-20 （ ISO 商店）。草案： n2169 (2017-04-07) |
 | 事务性内存 TS | 早期草案： n1961 (2015-09-23) |
ISO/IEC TS 17961:xxxx | 安全编码规则部分 2 | 早期开发，预计发布于 2023 ，可能作为 IS 而非 TS |
ISO/IEC AWI TS 6010 | C 的具备来源的内存对象模型 | 早期草案： n2676 (2021-03-24) |
ISO/IEC TS 21938-1 | 并行扩展部分 1 ：基于线程的并行 | 早期草案： n2170 (2017-09-21) ×（废弃） |
 | 并行扩展部分 2 ：基于向量的并行 | 早期部分草案： n2081 (2016-09-15) ×（废弃） |

参阅


动态内存扩展

< c‎ | experimental

对 C 库的扩展部分 II ：动态分配函数 (Extensions to the C Library Part II: Dynamic Allocation Functions) ， ISO/IEC TR 24731-2:2010 ，为 C 标准库定义下列新组件：

__STDC_ALLOC_LIB__ | 指遵从性等级的 long 类型常量 (宏常量)
定义于头文件 <stdio.h>
fmemopen (动态内存 TR) | 把固定大小的内存缓冲区作为 I/O 流打开 (函数)
open_memstreamopen_wmemstream (动态内存 TR) | 把动态改变大小的内存缓冲区作为 I/O 流打开 (函数)
asprintfaswprintfvasprintfvaswprintf (动态内存 TR) | sprintf 等的变体，写入自动分配的缓冲区并返回指向它的指针 (函数)
getlinegetwlinegetdelimgetwdelim (动态内存 TR) | 从流读入至动态改变大小的缓冲区，直到分隔符/行尾 (函数)
定义于头文件 <string.h>
strdup (动态内存 TR) | 分配字符串的副本 (函数)
strndup (动态内存 TR) | 分配字符串副本，至多到指定的大小 (函数)

此库扩展亦引入赋值分配字符 m ，用于 fscanf 和 fwscanf 函数族中的 %s 、 %[ 及 %c 转换说明符。

注解

函数 fmemopen 、 open_memstream 、 open_wmemstream 、 getdelim 、 getline 、 strdup 、 strndup 及对 fscanf 的扩展于 POSIX (ISO/IEC 9945:2003) 可用。

函数 asprintf 及 vasprintf 于 Linux 标准基础 (Linux Standard Base) (ISO/IEC IS 23360:2006) 可用。


getline, getwline, getdelim, getwdelim

< c‎ | experimental‎ | dynamic
定义于头文件 <stdio.h> |  |
ssize_t getline(char **lineptr, size_t *n, FILE *stream); | (1) | (动态内存 TR)
ssize_t getwline(wchar_t **lineptr, size_t *n, FILE *stream); | (2) | (动态内存 TR)
ssize_t getdelim(char ** restrict lineptr, size_t * restrict n, int delimiter, FILE *stream); | (3) | (动态内存 TR)
ssize_t getwdelim(wchar_t ** restrict lineptr, size_t * restrict n, wint_t delimiter, FILE * stream); | (4) | (动态内存 TR)
1) 表现同 getdelim(lineptr, n, '\n', stream) 。
2) 表现同 getwdelim(lineptr, n, L'\n', stream) 。
3) 如同用 fgetc 从流 stream 读取直至遇到 delimiter ，并将字符存储于 *lineptr 所指向的大小为 *n 的缓冲区，如同用 realloc 自动增加其大小以适应包含分隔符的整个输入，再加上空终止符。 *lineptr 可以为空，该情况下忽略 *n ， getline 如同用 malloc 分配一个新缓冲区。 若 delimiter 拥有 unsigned char 范围外的值且非 EOF ，则行为未定义。
4) 同 (3) ，除了如同以 fgetwc 读入字符，而 delimiter 必须是合法的 wchar_t 或 WEOF 。

若 *lineptr 非空，则若 *lineptr 不是能传递给 free 的指针，或若 *n 小于 *lineptr 所指向内存的被分配大小，则行为未定义。

同所有来自动态内存 TR 的函数， getline 仅若实现定义了 __STDC_ALLOC_LIB__ 且用户在包含 stdio.h 前定义 __STDC_WANT_LIB_EXT2__ 为整数常量 1 才保证可用。

参数

lineptr | - | 指针，指向空指针，或指向指向最初缓冲区的指针
n | - | 指向最初缓冲区大小的指针
delimiter | - | 分隔字符
stream | - | fopen 打开的合法输入流

返回值

存储于缓冲区的字符数，包含分隔符，但排除空终止符。

错误时返回 -1 并设置 stream 上的 feof 或 ferror 。

注意

这些函数等同于其 POSIX 版本，除了允许但不要求在错误时设置 errno 。

示例

#ifdef __STDC_ALLOC_LIB__
#define __STDC_WANT_LIB_EXT2__ 1
#else
#define _POSIX_C_SOURCE 200809L
#endif

#include <stdio.h>
#include <stdlib.h>
void get_y_or_n(void)
{
    char *response = NULL;
    size_t len;
    printf("Continue? [y] n: ");
    if((getline(&response, &len, stdin) < 0) || (len && response[0] == 'n')) {
        free(response);
        exit(0);
    }
    free(response);
    return;
}
int main(void)
{
    get_y_or_n();
}

输出：

Continue? [y] n:

参阅

fgets | 从文件流获取一个字符串 (函数)
getsgets_s (C11 中移除)(C11) | 从 stdin 读取一个字符串 (函数)
fgetws (C95) | 从文件流获取一个宽字符串 (函数)
malloc | 分配内存 (函数)


strdup

< c‎ | experimental‎ | dynamic
定义于头文件 <string.h> |
char * strdup( const char *str1 ); | (动态内存 TR)

返回指向空终止字符串的指针，字符串是 str1 所指向字符串的副本。返回的指针必须传递给 free 以避免内存泄漏。

若错误发生，则返回空指针，并可能设置 errno 。

同所有来自动态内存 TR 的函数， strdup 仅若实现定义了 __STDC_ALLOC_LIB__ 且用户在包含 string.h 前定义 __STDC_WANT_LIB_EXT2__ 为整数常量 1 才保证可用。

参数

str1 - 指向要被复制的空终止字符串的指针

返回值

指向新分配字符串的指针，若出现错误则为空指针。

注解

此函数等同于 POSIX strdup 。

示例

#ifdef __STDC_ALLOC_LIB__
#define __STDC_WANT_LIB_EXT2__ 1
#else
#define _POSIX_C_SOURCE 200809L
#endif

#include <string.h>
#include <assert.h>
#include <stdlib.h>

int main(void)
{
    const char *s1 = "String";
    char *s2 = strdup(s1);
    assert(strcmp(s1, s2) == 0);
    free(s2);
}

参阅

strndup (动态内存 TR) | 分配字符串副本，至多到指定的大小 (函数)
strcpystrcpy_s (C11) | 复制一个字符串给另一个 (函数)
malloc | 分配内存 (函数)


strndup

< c‎ | experimental‎ | dynamic
定义于头文件 <string.h>
char *strndup( const char *str, size_t size );

返回指向空终止字符串的指针，该字符串含有 str 所指向字符串的至多 size 字节的副本。若在其首 size 字节中遇到空终止符，则将它添加到复制的字符串中。

必须传递返回指针给 free ，以避免内存泄漏。

若发生错误，则返回空指针，并可能设置 errno 。

同所有来自动态内存 TR 的函数， strndup 仅若实现定义了 __STDC_ALLOC_LIB__ 且用户在包含 string.h 前定义 __STDC_WANT_LIB_EXT2__ 为整数常量 1 才保证可用。

参数

str | - | 指向要复制的空终止字符串的指针
size | - | 从 str 复制的最大字节数

返回值

指向新分配字符串的指针，若错误发生则为空指针。

注解

此函数等同于 POSIX strndup ，除了允许但不要求它在错误时设置 errno 。

示例

#ifdef __STDC_ALLOC_LIB__
#define __STDC_WANT_LIB_EXT2__ 1
#else
#define _POSIX_C_SOURCE 200809L
#endif

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    const char *s1 = "String";
    char *s2 = strndup(s1, 2);
    printf("strndup(\"String\", 2) == %s\n", s2);
    free(s2);
}

输出：

strndup("String", 2) == St

参阅

strdup (动态内存 TR) | 分配字符串的副本 (函数)
strncpystrncpy_s (C11) | 从一个字符串复制一定数量的字符到另一个 (函数)
malloc | 分配内存 (函数)


浮点扩展部分 1 ：二进制浮点算术

< c‎ | experimental

C 浮点扩展 - 部分 1 ：二进制浮点算术， ISO/IEC TS 18661-1:2014 ，为 C 标准库定义下列新组件，它们为 ISO/IEC/IEEE 60559:2011 （ IEEE-754 的当前版本）所推荐。

__STDC_IEC_60559_BFP__ | long 类型值为 201ymmL 的整数常量，，取代 __STDC_IEC_559__ (宏常量)
__STDC_IEC_60559_COMPLEX__ | long 类型值为 201ymmL 的整数常量，取代 __STDC_IEC_559_COMPLEX__ (宏常量)
定义于头文件 <limits.h>
CHAR_WIDTH SCHAR_WIDTH UCHAR_WIDTHSHRT_WIDTH USHRT_WIDTHINT_WIDTH UINT_WIDTHLONG_WIDTH ULONG_WIDTHLLONG_WIDTH ULLONG_WIDTH (FP 扩展1 TS) | 对应类型的宽度，以位数表示 (宏常量)
定义于头文件 <float.h>
CR_DECIMAL_DIG (FP 扩展1 TS) | 所有受支持二进制浮点类型和字符序列间的转换至多准确舍入到 CR_DECIMAL_DIG 位十进制有效数字（至少是 DECIMAL_DIG + 3 ） (宏常量)
定义于头文件 <fenv.h>
femode_t (FP 扩展1 TS) | 实现支持的动态浮点控制模式的总集，包含动态舍入方向模式 (typedef)
FE_DFL_MODE (FP 扩展1 TS) | 指向默认 femode_t 的指针 (宏常量)
FE_SNANS_ALWAYS_SIGNAL (FP 扩展1 TS) | 若 sNaN 参数导致压制 gNaN 的函数，如 hypot 或 fmax ，引发 FE_INVALID 并返回 gNaN ，则定义此宏（为整数常量 1 ） (宏常量)
fesetexcept (FP 扩展1 TS) | 设置给定的浮点异常标志，并且不导致任何引发它们所产生的副效应 (函数)
fetestexceptflag (FP 扩展1 TS) | 测试给定的标志是否在保存的浮点异常标志表示中 (函数)
fegetmodefesetmode (FP 扩展1 TS) | 整体地获取和设置所有实现的动态浮点控制模式 (函数)
定义于头文件 <stdint.h>
INTn_WIDTH UINTn_WIDTHINT_LEASTn_WIDTH UINT_LEASTn_WIDTHINT_FASTn_WIDTH UINT_FASTn_WIDTHINTPTR_WIDTH UINTPTR_WIDTHINTMAX_WIDTH UINTMAX_WIDTHPTRDIFF_WIDTHSIG_ATOMIC_WIDTHSIZE_WIDTHWCHAR_WIDTH WINT_WIDTH (FP 扩展1 TS) | 对应类型的宽度，以位数表示 (宏常量)
定义于头文件 <stdlib.h>
strfromdstrfromfstrfroml (FP 扩展1 TS) | 用指定的 snprintf 格式转换单个浮点值到字符串 (函数)
定义于头文件 <math.h>
FP_INT_UPWARDFP_INT_DOWNWARDFP_INT_TOWARDZERO FP_INT_TONEARESTFROMZEROFP_INT_TONEAREST (FP 扩展1 TS) | 函数 ceil 、 floor 、 trunc 、 round ，及 roundeven 的舍入方向，适用于 fromfp 系列函数 (宏常量)
FP_LLOGB0 (FP 扩展1 TS) | 若参数为零则 llogb 所返回的值 (宏常量)
FP_LLOGBNAN (FP 扩展1 TS) | 若参数为 NaN 则 llogb 所返回的值 (宏常量)
SNANFSNANSNANL (FP 扩展1 TS) | 各表示 float 、 double 、 long double 的引发信号的 NaN (宏常量)
FP_FAST_FADD FP_FAST_FADDL FP_FAST_DADDLFP_FAST_FSUB FP_FAST_FSUBL FP_FAST_DSUBLFP_FAST_FMUL FP_FAST_FMULL FP_FAST_DMULLFP_FAST_FDIV FP_FAST_FDIVL FP_FAST_DDIVLFP_FAST_FFMA FP_FAST_FFMAL FP_FAST_DFMALFP_FAST_FSQRT FP_FAST_FSQRTL FP_FAST_DSQRTL (FP 扩展1 TS) | 倘若定义，则指示对应的函数执行快于较大类型的等价函数后随到目标类型的转型 (宏常量)
iseqsig (FP 扩展1 TS) | (宏函数)
iscanonical (FP 扩展1 TS) | 测试浮点值是否规范 (宏函数)
issignaling (FP 扩展1 TS) | 测试浮点值是否引发信号的 NaN (宏函数)
issubnormal (FP 扩展1 TS) | 测试浮点值是否非正规 (宏函数)
iszero (FP 扩展1 TS) | 测试浮点值是否为零（正、符、无符号） (宏函数)
fromfpfromfpffromfpl (FP 扩展1 TS) | 用指定舍入方向舍入到有符号整数 (函数)
ufromfpufromfpfufromfpl (FP 扩展1 TS) | 用指定舍入方向舍入到无符号整数 (函数)
fromfpxfromfpxffromfpxl (FP 扩展1 TS) | 用指定舍入方向舍入到有符号整数，报告不准确性 (函数)
ufromfpxufromfpxfufromfpxl (FP 扩展1 TS) | 用指定舍入方向舍入到无符号整数，报告不准确性 (函数)
roundevenroundevenfroundevenl (FP 扩展1 TS) | 舍入到最近值，中间点情况下舍入到偶数 (函数)
llogbllogbfllogbl (FP 扩展1 TS) | 等价于 logb ，除了返回类型是 long (函数)
fmaxmagfmaxmagffmaxmagl (FP 扩展1 TS) | 返回拥有较大绝对值的参数的值 (函数)
fminmagfminmagffminmagl (FP 扩展1 TS) | 返回拥有较小绝对值的参数的值 (函数)
nextupnextupfnextupl (FP 扩展1 TS) | 返回下个较大的可表示浮点值 (函数)
nextdownnextdownfnextdownl (FP 扩展1 TS) | 返回下个较小的可表示浮点值 (函数)
faddfaddldaddl (FP 扩展1 TS) | 如同以无限精度并只舍入一次到目标类型计算 x+y (函数)
fsubfsubldsubl (FP 扩展1 TS) | 如同以无限精度并只舍入一次到目标类型计算 x-y (函数)
fmulfmulldmull (FP 扩展1 TS) | 如同以无限精度并只舍入一次到目标类型计算 x*y (函数)
fdivfdivlddivl (FP 扩展1 TS) | 如同以无限精度并只舍入一次到目标类型计算 x/y (函数)
ffmaffmaldfmal (FP 扩展1 TS) | 如同以无限精度并只舍入一次到目标类型计算 fma (函数)
fsqrtfsqrtldsqrtl (FP 扩展1 TS) | 如同以无限精度并只舍入一次到目标类型计算 sqrt (函数)
totalordertotalorderftotalorderl (FP 扩展1 TS) | 用 ISO 60559 全序关系排序二个浮点值 (函数)
totalordermagtotalordermagftotalordermagl (FP 扩展1 TS) | 用 ISO 60559 全序关系排序二个浮点值 (函数)
canonicalizecanonicalizefcanonicalizel (FP 扩展1 TS) | 获得给定浮点值的 ISO 60559 规范二进制编码 (函数)
getpayloadgetpayloadfgetpayloadl (FP 扩展1 TS) | 从给定的 NaN 值提取出负载 (函数)
setpayloadsetpayloadfsetpayloadl (FP 扩展1 TS) | 以指定负载创建安静的 NaN (函数)
setpayloadsigsetpayloadsigfsetpayloadsigl (FP 扩展1 TS) | 以指定负载创建引发信号的 NaN (函数)
定义于头文件 <tgmath.h>
roundeven (FP 扩展1 TS) | roundeven 的泛型重载 (函数)
llogb (FP 扩展1 TS) | llogb 的泛型重载 (函数)
fmaxmag (FP 扩展1 TS) | fmaxmag 的泛型重载 (函数)
fminmag (FP 扩展1 TS) | fminmag 的泛型重载 (函数)
nextup (FP 扩展1 TS) | nextup 的泛型重载 (函数)
nextdown (FP 扩展1 TS) | nextdown 的泛型重载 (函数)
fromfp (FP 扩展1 TS) | fromfp 的泛型重载 (函数)
ufromfp (FP 扩展1 TS) | ufromfp 的泛型重载 (函数)
fromfpx (FP 扩展1 TS) | fromfpx 的泛型重载 (函数)
ufromfpx (FP 扩展1 TS) | ufromfpx 的泛型重载 (函数)
nextdown (FP 扩展1 TS) | nextdown 的泛型重载 (函数)
totalorder (FP 扩展1 TS) | totalorder 的泛型重载 (函数)
totalordermag (FP 扩展1 TS) | totalordermag 的泛型重载 (函数)
fadd (FP 扩展1 TS) | fadd 的泛型重载 (函数)
dadd (FP 扩展1 TS) | dadd 的泛型重载 (函数)
fsub (FP 扩展1 TS) | fsub 的泛型重载 (函数)
dsub (FP 扩展1 TS) | dsub 的泛型重载 (函数)
fmul (FP 扩展1 TS) | fmul 的泛型重载 (函数)
dmul (FP 扩展1 TS) | dmul 的泛型重载 (函数)
fdiv (FP 扩展1 TS) | fdiv 的泛型重载 (函数)
ddiv (FP 扩展1 TS) | ddiv 的泛型重载 (函数)
ffma (FP 扩展1 TS) | ffma 的泛型重载 (函数)
dfma (FP 扩展1 TS) | dfma 的泛型重载 (函数)
fsqrt (FP 扩展1 TS) | fsqrt 的泛型重载 (函数)
dsqrt (FP 扩展1 TS) | dsqrt 的泛型重载 (函数)

注意

此技术规范弃用标准 C 宏 __STDC_IEC_559__ 及 __STDC_IEC_559_COMPLEX__ 。

仅若在包含对应头文件前定义宏 __STDC_WANT_IEC_60559_BFP_EXT__ ，才声明此扩展添加到 C 库的所有函数和宏。

在对标准库的添加以外， ISO/IEC TS 18661-1:2014 做了一些对语言核心的改动，值得注意的是将浮点控制分割为静态（由新的 #pragma STDC FENV_ROUND 控制）和动态（由 fesetround 控制）。若设置了静态舍入模式，则大多数 math.h 的函数考虑静态舍入模式优先于动态舍入模式。

本节未完成
原因：添加到 pragma 页面或在此完整描述 pragma ？


浮点扩展部分 4 ：补充函数

< c‎ | experimental

C 浮点扩展 - 部分 4 ：补充函数， ISO/IEC TS 18661-4:2015 ，为 C 标准库定义下列新组件，它们为 ISO/IEC/IEEE 60559:2011 （ IEEE-754 的当前版本）所推荐

__STDC_IEC_60559_FUNCS__ | 拥有 long 类型和值 201506L 的整数常量 (宏常量)
定义于头文件 <math.h>
exp2m1 exp2m1f exp2m1lexp2m1fN exp2m1fNxexp2m1dN exp2m1dNx (FP 扩展4 TS) | 计算 2x -1 (函数)
exp10 exp10f exp10lexp10fN exp10fNxexp10dN exp10dNx (FP 扩展4 TS) | 计算 10x (函数)
exp10m1 exp10m1f exp10m1lexp10m1fN exp10m1fNxexp10m1dN exp10m1dNx (FP 扩展4 TS) | 计算 10x -1 (函数)
logp1 logp1f logp1llogp1fN logp1fNxlogp1dN logp1dNx (FP 扩展4 TS) | 计算 ln(1+x) （与 log1p 相同） (函数)
log2p1 log2p1f log2p1llog2p1fN log2p1fNxlog2p1dN log2p1dNx (FP 扩展4 TS) | 计算 log 2(1+x) (函数)
log10p1 log10p1f log10p1llog10p1fN log10p1fNxlog10p1dN log10p1dNx (FP 扩展4 TS) | 计算 log 10(1+x) (函数)
rsqrt rsqrtf rsqrtlrsqrtfN rsqrtfNxrsqrtdN rsqrtdNx (FP 扩展4 TS) | 计算平方根倒数 x-1/2 (函数)
compoundn compoundnf compoundnlcompoundnfN compoundnfNxcompoundndN compoundndNx (FP 扩展4 TS) | 计算复利 (1+x)n (函数)
rootn rootnf rootnlrootnfN rootnfNxrootndN rootndNx (FP 扩展4 TS) | 计算 x 的 n 次方根 x1/n (函数)
pown pownf pownlpownfN pownfNxpowndN powndNx (FP 扩展4 TS) | 计算 x 的 n 次幂，其中 n 为整数 (函数)
powr powrf powrlpowrfN powrfNxpowrdN powrdNx (FP 扩展4 TS) | 计算 x 的 y 次幂 xy (函数)
acospi acospif acospilacospifN acospifNxacospidN acospidNx (FP 扩展4 TS) | 计算 arccos(x)/π （以半圆周为单位度量角） (函数)
asinpi asinpif asinpilasinpifN asinpifNxasinpidN asinpidNx (FP 扩展4 TS) | 计算 arcsin(x)/π （以半圆周为单位度量角） (函数)
atanpi atanpif atanpilatanpifN atanpifNxatanpidN atanpidNx (FP 扩展4 TS) | 计算 arctan(x)/π （以半圆周为单位度量角） (函数)
atan2pi atan2pif atan2pilatan2pifN atan2pifNxatan2pidN atan2pidNx (FP 扩展4 TS) | 计算 arctan(y/x)/π （以半圆周为单位度量角） (函数)
cospi cospif cospilcospifN cospifNxcospidN cospidNx (FP 扩展4 TS) | 计算 cos(πx) （以半圆周为单位度量角） (函数)
sinpi sinpif sinpilsinpifN sinpifNxsinpidN sinpidNx (FP 扩展4 TS) | 计算 sin(πx) （以半圆周为单位度量角） (函数)
tanpi tanpif tanpiltanpifN tanpifNxtanpidN tanpidNx (FP 扩展4 TS) | 计算 tan(πx) （以半圆周为单位度量角） (函数)
reduc_sum reduc_sumf reduc_sumlreduc_sumfN reduc_sumfNxreduc_sumdN reduc_sumdNx (FP 扩展4 TS) | 计算数组的 n 个元素之和 (函数)
reduc_sumabs reduc_sumabsf reduc_sumabslreduc_sumabsfN reduc_sumabsfNxreduc_sumabsdN reduc_sumabsdNx (FP 扩展4 TS) | 计算数组的 n 个元素绝对值之和 (函数)
reduc_sumsq reduc_sumsqf reduc_sumsqlreduc_sumsqfN reduc_sumsqfNxreduc_sumsqdN reduc_sumsqdNx (FP 扩展4 TS) | 计算数组的 n 个元素的平方和 (函数)
reduc_sumprod reduc_sumprodf reduc_sumprodlreduc_sumprodfN reduc_sumprodfNxreduc_sumproddN reduc_sumproddNx (FP 扩展4 TS) | 计算二个数组的各 n 个元素的点积 (函数)
scaled_prod scaled_prodf scaled_prodlscaled_prodfN scaled_prodfNxscaled_proddN scaled_proddNx (FP 扩展4 TS) | 计算数组 n 个元素的积，结果为有效数位值和大小指数 (函数)
scaled_prodsum scaled_prodsumf scaled_prodsumlscaled_prodsumfN scaled_prodsumfNxscaled_prodsumdN scaled_prodsumdNx (FP 扩展4 TS) | 计算二个数组 n 对元素逐对和的积，结果为有效数位值和大小指数 (函数)
scaled_proddiff scaled_proddifff scaled_proddifflscaled_proddifffN scaled_proddifffNxscaled_proddiffdN scaled_proddiffdNx (FP 扩展4 TS) | 计算二个数组 n 对元素逐对差的积，结果为有效数位值和大小指数 (函数)
crexp(可选) (FP 扩展4 TS) | exp 的准确舍入版本 (函数)
crexpm1(可选) (FP 扩展4 TS) | expm1 的准确舍入版本 (函数)
crexp2(可选) (FP 扩展4 TS) | exp2 的准确舍入版本 (函数)
crexp2m1(可选) (FP 扩展4 TS) | exp2m1 的准确舍入版本 (函数)
crexp10(可选) (FP 扩展4 TS) | exp10 的准确舍入版本 (函数)
crexp10m1(可选) (FP 扩展4 TS) | exp10m1 的准确舍入版本 (函数)
crlog(可选) (FP 扩展4 TS) | log 的准确舍入版本 (函数)
crlog2(可选) (FP 扩展4 TS) | log2 的准确舍入版本 (函数)
crlog10(可选) (FP 扩展4 TS) | log10 的准确舍入版本 (函数)
crlog1p(可选) (FP 扩展4 TS) | log1p 的准确舍入版本 (函数)
crlogp1(可选) (FP 扩展4 TS) | logp1 的准确舍入版本 (函数)
crlog2p1(可选) (FP 扩展4 TS) | log2p1 的准确舍入版本 (函数)
crlog10p1(可选) (FP 扩展4 TS) | log10p1 的准确舍入版本 (函数)
crrsqrt(可选) (FP 扩展4 TS) | rsqrt 的准确舍入版本 (函数)
crcompoundn(可选) (FP 扩展4 TS) | compoundn 的准确舍入版本 (函数)
crrootn(可选) (FP 扩展4 TS) | rootn 的准确舍入版本 (函数)
crpown(可选) (FP 扩展4 TS) | pown 的准确舍入版本 (函数)
crpow(可选) (FP 扩展4 TS) | pow 的准确舍入版本 (函数)
crpowr(可选) (FP 扩展4 TS) | powr 的准确舍入版本 (函数)
crsin(可选) (FP 扩展4 TS) | sin 的准确舍入版本 (函数)
crcos(可选) (FP 扩展4 TS) | cos 的准确舍入版本 (函数)
crtan(可选) (FP 扩展4 TS) | tan 的准确舍入版本 (函数)
crsinpi(可选) (FP 扩展4 TS) | sinpi 的准确舍入版本 (函数)
crcospi(可选) (FP 扩展4 TS) | cospi 的准确舍入版本 (函数)
crtanpi(可选) (FP 扩展4 TS) | tanpi 的准确舍入版本 (函数)
crasinpi(可选) (FP 扩展4 TS) | asinpi 的准确舍入版本 (函数)
cracospi(可选) (FP 扩展4 TS) | acospi 的准确舍入版本 (函数)
cracospi(可选) (FP 扩展4 TS) | acospi 的准确舍入版本 (函数)
cratanpi(可选) (FP 扩展4 TS) | atanpi 的准确舍入版本 (函数)
cratan2pi(可选) (FP 扩展4 TS) | atan2pi 的准确舍入版本 (函数)
crasin(可选) (FP 扩展4 TS) | asin 的准确舍入版本 (函数)
cracos(可选) (FP 扩展4 TS) | acos 的准确舍入版本 (函数)
cratan(可选) (FP 扩展4 TS) | atan 的准确舍入版本 (函数)
cratan2(可选) (FP 扩展4 TS) | atan2 的准确舍入版本 (函数)
crsinh(可选) (FP 扩展4 TS) | sinh 的准确舍入版本 (函数)
crcosh(可选) (FP 扩展4 TS) | cosh 的准确舍入版本 (函数)
crtanh(可选) (FP 扩展4 TS) | tanh 的准确舍入版本 (函数)
crasinh(可选) (FP 扩展4 TS) | asinh 的准确舍入版本 (函数)
cracosh(可选) (FP 扩展4 TS) | acosh 的准确舍入版本 (函数)
cratanh(可选) (FP 扩展4 TS) | atanh 的准确舍入版本 (函数)
crhypot(可选) (FP 扩展4 TS) | hypot 的准确舍入版本 (函数)
定义于头文件 <complex.h>
cexp2m1(可选) (FP 扩展4 TS) | exp2m1 的复数版本 (函数)
cexp10(可选) (FP 扩展4 TS) | exp10 的复数版本 (函数)
cexp10m1(可选) (FP 扩展4 TS) | exp10m1 的复数版本 (函数)
clogp1(可选) (FP 扩展4 TS) | logp1 的复数版本 (函数)
clog2p1(可选) (FP 扩展4 TS) | log2p1 的复数版本 (函数)
clog10p1(可选) (FP 扩展4 TS) | log10p1 的复数版本 (函数)
crsqrt (可选) (FP 扩展4 TS) | rsqrt 的复数版本 (函数)
ccompoundn (可选) (FP 扩展4 TS) | compoundn 的复数版本 (函数)
crootn(可选) (FP 扩展4 TS) | rootn 的复数版本 (函数)
cpown (可选) (FP 扩展4 TS) | pown 的复数版本 (函数)
cpowr(可选) (FP 扩展4 TS) | powr 的复数版本 (函数)
cacospi(可选) (FP 扩展4 TS) | acospi 的复数版本 (函数)
casinpi(可选) (FP 扩展4 TS) | asinpi 的复数版本 (函数)
catanpi(可选) (FP 扩展4 TS) | atanpi 的复数版本 (函数)
ccospi(可选) (FP 扩展4 TS) | cospi 的复数版本 (函数)
csinpi(可选) (FP 扩展4 TS) | sinpi 的复数版本 (函数)
ctanpi(可选) (FP 扩展4 TS) | tanpi 的复数版本 (函数)

注意

仅若在包含 math.h 前定义宏 __STDC_WANT_IEC_60559_FUNCS_EXT__ ，才声明此扩展添加到 C 库的所有函数。

仅若在包含 math.h 前定义宏 __STDC_WANT_IEC_60559_DFP_EXT__ ，才定义每个函数的十进制浮点变体。

仅若在包含 math.h 前定义宏 __STDC_WANT_IEC_60559_TYPES_EXT__ ，才定义每个函数的扩展精度变体。

所有函数的准确舍入版本（带 cr- 前缀者）都是可选的。


C 标准库头文件

< c

C 标准库的接口由下列头文件的汇集定义。

<assert.h> | 条件编译宏，将参数与零比较
<complex.h> (C99) | 复数运算
<ctype.h> | 用来确定包含于字符数据中的类型的函数
<errno.h> | 报告错误条件的宏
<fenv.h> (C99) | 浮点环境
<float.h> | 浮点类型的极限
<inttypes.h> (C99) | 整数类型的格式转换
<iso646.h> (C95) | 运算符的替代写法
<limits.h> | 整数类型的范围
<locale.h> | 本地化工具
<math.h> | 常用数学函数
<setjmp.h> | 非局部跳转
<signal.h> | 信号处理
<stdalign.h> (C11) | alignas 与 alignof 便利宏
<stdarg.h> | 可变参数
<stdatomic.h> (C11) | 原子类型
<stdbool.h> (C99) | 布尔类型的宏
<stddef.h> | 常用宏定义
<stdint.h> (C99) | 定宽整数类型
<stdio.h> | 输入/输出
<stdlib.h> | 基础工具：内存管理、程序工具、字符串转换、随机数、算法
<stdnoreturn.h> (C11) | noreturn 便利宏
<string.h> | 字符串处理
<tgmath.h> (C99) | 泛型数学（包装 math.h 和 complex.h 的宏）
<threads.h> (C11) | 线程库
<time.h> | 时间/日期工具
<uchar.h> (C11) | UTF-16 和 UTF-32 字符工具
<wchar.h> (C95) | 扩展多字节和宽字符工具
<wctype.h> (C95) | 用来确定包含于宽字符数据中的类型的函数

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.1.2 Standard headers (p: 131-132)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.1.2 Standard headers (p: 181-182)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.1.2 Standard headers (p: 165)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.1.2 Standard headers

参阅


文件输入/输出

< c

<stdio.h> 头文件提供通用文件操作支持并提供有窄字符输入/输出能力的函数。

<wchar.h> 头文件提供有宽字符输入/输出能力的函数。

I/O 流为 FILE 对象所代表，只能通过 FILE* 类型指针访问及操作。每个流与外部物理设备（文件、标准输入流、打印机、序列端口等）关联。

类型

定义于头文件 <stdio.h>
FILE | 对象类型，足以保有控制 C I/O 流所需的全部信息 (typedef)
fpos_t | 非数组完整对象类型，足以唯一指定文件的位置和多字节剖析状态 (typedef)

预定义标准流

定义于头文件 <stdio.h>
stdinstdoutstderr
 与标准输入流关联的 FILE* 类型表达式
与标准输出流关联的 FILE* 类型表达式
与标准错误输出流关联的 FILE* 类型表达式
(宏常量)

函数

文件访问
定义于头文件 <stdio.h>
fopenfopen_s
(C11)
 打开文件
(函数)
freopenfreopen_s
(C11)
 以不同名称打开既存的文件流
(函数)
fclose
 关闭文件
(函数)
fflush
 将输出流与实际文件同步
(函数)
setbuf
 为文件流设置缓冲区
(函数)
setvbuf
 为文件流设置缓冲区和其大小
(函数)
定义于头文件 <wchar.h>
fwide
(C95)
 将文件流在宽字符I/O和窄字符I/O间切换
(函数)
直接输入/输出
定义于头文件 <stdio.h>
fread
 从文件读取
(函数)
fwrite
 写入到文件
(函数)
无格式输入/输出
窄字符
定义于头文件 <stdio.h>
fgetcgetc
 从文件流获取一个字符
(函数)
fgets
 从文件流获取一个字符串
(函数)
fputcputc
 将一个字符写入文件流
(函数)
fputs
 将一个字符串写入文件流
(函数)
getchar
 从 stdin 读取一个字符
(函数)
getsgets_s
(C11 中移除)(C11)
 从 stdin 读取一个字符串
(函数)
putchar
 将一个字符写入 stdout
(函数)
puts
 将一个字符串写入 stdout
(函数)
ungetc
 将一个字符送回文件流
(函数)
宽字符
定义于头文件 <wchar.h>
fgetwcgetwc
(C95)
 从文件流获取一个宽字符
(函数)
fgetws
(C95)
 从文件流获取一个宽字符串
(函数)
fputwcputwc
(C95)
 将一个宽字符写入文件流
(函数)
fputws
(C95)
 将一个宽字符串写入文件流
(函数)
getwchar
(C95)
 从 stdin 读取一个宽字符
(函数)
putwchar
(C95)
 将一个宽字符写入 stdout
(函数)
ungetwc
(C95)
 将一个宽字符送回文件流
(函数)
有格式输入/输出
窄字符
定义于头文件 <stdio.h>
scanffscanfsscanfscanf_sfscanf_ssscanf_s
(C11)(C11)(C11)
 从stdin、文件流或缓冲区读取格式化输入
(函数)
vscanfvfscanfvsscanfvscanf_svfscanf_svsscanf_s
(C99)(C99)(C99)(C11)(C11)(C11)
 从 stdin 、文件流或缓冲区读取格式化输入
使用可变参数列表
(函数)
printffprintfsprintfsnprintfprintf_sfprintf_ssprintf_ssnprintf_s
(C99)(C11)(C11)(C11)(C11)
 打印格式化输出到 stdout 、文件流或缓冲区
(函数)
vprintfvfprintfvsprintfvsnprintfvprintf_svfprintf_svsprintf_svsnprintf_s
(C99)(C11)(C11)(C11)(C11)
 打印格式化输出到stdout、文件流或缓冲区
使用可变参数列表
(函数)
宽字符
定义于头文件 <wchar.h>
wscanffwscanfswscanfwscanf_sfwscanf_sswscanf_s
(C95)(C95)(C95)(C11)(C11)(C11)
 从stdin、文件流或缓冲区读取格式化宽字符输入
(函数)
vwscanfvfwscanfvswscanfvwscanf_svfwscanf_svswscanf_s
(C99)(C99)(C99)(C11)(C11)(C11)
 从stdin、文件流或缓冲区读取格式化宽字符输入
使用可变参数列表
(函数)
wprintffwprintfswprintfwprintf_sfwprintf_sswprintf_ssnwprintf_s
(C95)(C95)(C95)(C11)(C11)(C11)(C11)
 打印格式化宽字符输出到 stdout 、文件流或缓冲区
(函数)
vwprintfvfwprintfvswprintfvwprintf_svfwprintf_svswprintf_svsnwprintf_s
(C95)(C95)(C95)(C11)(C11)(C11)(C11)
 打印格式化宽字符输出到 stdout 、文件流或缓冲区
使用可变参数列表
(函数)
文件位置
定义于头文件 <stdio.h>
ftell
 返回当前的文件位置指示值
(函数)
fgetpos
 获取文件位置指示器
(函数)
fseek
 将文件位置指示符移动到文件中的指定位置
(函数)
fsetpos
 将文件位置指示器移动到文件中的指定位置
(函数)
rewind
 将文件位置指示器移动到文件首
(函数)
错误处理
定义于头文件 <stdio.h>
clearerr
 清除错误
(函数)
feof
 检查文件结尾
(函数)
ferror
 检查文件错误
(函数)
perror
 显示对应当前错误的字符串到 stderr
(函数)
文件操作
定义于头文件 <stdio.h>
remove
 删除文件
(函数)
rename
 重命名文件
(函数)
tmpfiletmpfile_s
(C11)
 返回指向临时文件的指针
(函数)
tmpnamtmpnam_s
(C11)
 返回唯一的文件名
(函数)

宏常量

定义于头文件 <stdio.h>
EOF
 int 类型的负值整数常量表达式
(宏常量)
FOPEN_MAX
 能同时打开的文件数
(宏常量)
FILENAME_MAX
 保有最长受支持文件名所需的 char 数组大小
(宏常量)
BUFSIZ
 setbuf() 所用的缓冲区大小
(宏常量)
_IOFBF_IOLBF_IONBF
 指示全缓冲 I/O 的 setvbuf() 参数
指示行缓冲 I/O 的 setvbuf() 参数
指示无缓冲 I/O 的 setvbuf() 参数
(宏常量)
SEEK_SETSEEK_CURSEEK_END
 指示从文件首开始寻位的 fseek() 参数
指示从文件当前位置开始寻位的 fseek() 参数
指示从文件尾开始寻位的 fseek() 参数
(宏常量)
TMP_MAXTMP_MAX_S
(C11)
 tmpnam 所能生成的最大独有文件数
tmpnam_s 所能生成的最大独有文件数
(宏常量)
L_tmpnamL_tmpnam_s
(C11)
 保有 tmpnam 结果所需的 char 数组大小
保有 tmpnam_s 结果所需的 char 数组大小
(宏常量)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21 Input/output <stdio.h> (p: 296-339)
  • 7.29 Extended multibyte and wide character utilities <wchar.h> (p: 402-446)
  • 7.31.11 Input/output <stdio.h> (p: 456)
  • 7.31.16 Extended multibyte and wide character utilities <wchar.h> (p: 456)
  • K.3.5 Input/output <stdio.h> (p: 586-603)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19 Input/output <stdio.h> (p: 262-305)
  • 7.24 Extended multibyte and wide character utilities <wchar.h> (p: 348-392)
  • 7.26.9 Input/output <stdio.h> (p: 402)
  • 7.26.12 Extended multibyte and wide character utilities <wchar.h> (p: 402)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9 INPUT/OUTPUT <stdio.h>
  • 4.13.6 Input/output <stdio.h>

参阅


clearerr

< c‎ | io
定义于头文件 <stdio.h>
void clearerr( FILE *stream );

重置给定文件流的错误标志和 EOF 指示器。

参数

stream - 要重置错误标志的文件流

返回值

（无）

示例

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int main(void)
{
    FILE* tmpf = tmpfile();
    fputs("abcde\n", tmpf);
    rewind(tmpf);
    int ch;
    while ((ch=fgetc(tmpf)) != EOF)
          printf("%c", ch);
    assert(feof(tmpf)); // 此循环期待以 eof 终止
    puts("End of file reached");

    clearerr(tmpf);  // 清除 eof

    if (feof(tmpf))
        puts("EOF indicator set");
    else
        puts("EOF indicator cleared\n");
}

输出：

abcde
End of file reached
EOF indicator cleared

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.10.1 The clearerr function (p: 338)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.10.1 The clearerr function (p: 304)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.10.1 The clearerr function

参阅

feof | 检查文件结尾 (函数)
perror | 显示对应当前错误的字符串到 stderr (函数)
ferror | 检查文件错误 (函数)


fclose

< c‎ | io
定义于头文件 <stdio.h>
int fclose( FILE *stream );

关闭给定的文件流。冲入任何未写入的缓冲数据到 OS 。舍弃任何未读取的缓冲数据。

无论操作是否成功，流都不再关联到文件，且由 setbuf 或 setvbuf 分配的缓冲区若存在，则亦被解除关联，并且若使用自动分配则被解分配。

若在 fclose 返回后使用指针 stream 的值则行为未定义。

参数

stream - 需要关闭的文件流

返回值

成功时为 ​0​ ，否则为 EOF 。

示例

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE* fp = fopen("test.txt", "r");
    if(!fp) {
        perror("File opening failed");
        return EXIT_FAILURE;
    }

    int c; // 注意：int，非char，要求处理EOF
    while ((c = fgetc(fp)) != EOF) { // 标准C I/O读取文件循环
       putchar(c);
    }

    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");

    fclose(fp);
}

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.5.1 The fclose function (p: 304)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.5.1 The fclose function (p: 270)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.5.1 The fclose function

参阅

fopenfopen_s (C11) | 打开文件 (函数)
freopenfreopen_s (C11) | 以不同名称打开既存的文件流 (函数)


feof

< c‎ | io
定义于头文件 <stdio.h>
int feof( FILE *stream );

检查是否已抵达给定文件流的结尾。

参数

stream - 要检验的文件流

返回值

若已抵达流尾则为非零值，否则为 ​0​

注意

此函数仅报告最近一次 I/O 操作所报告的流状态，而不检验关联的数据源。例如，若最近一次 I/O 是抵达文件最后字节的 fgetc ，则 feof 返回零。下个 fgetc 失败并更改流状态为文件尾。然后 feof 才返回非零。

典型用法中，输入流处理在任何错误时停止；而 feof 和 ferror 用于区别不同错误条件。

示例

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE* fp = fopen("test.txt", "r");
    if(!fp) {
        perror("File opening failed");
        return EXIT_FAILURE;
    }

    int c; // 注意：int，非char，要求处理EOF
    while ((c = fgetc(fp)) != EOF) { // 标准C I/O读取文件循环
       putchar(c);
    }

    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");

    fclose(fp);
}

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.10.2 The feof function (p: 339)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.10.2 The feof function (p: 305)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.10.2 The feof function

参阅

clearerr | 清除错误 (函数)
perror | 显示对应当前错误的字符串到 stderr (函数)
ferror | 检查文件错误 (函数)


ferror

< c‎ | io
定义于头文件 <stdio.h>
int ferror( FILE *stream );

检查给定文件流的错误。

参数

stream - 要检查的文件流

返回值

若文件流已出现错误则为非零值，否则为 ​0​

示例

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <wchar.h>

int main(void)
{
    char* fname = tmpnam(NULL);
    FILE* f = fopen(fname, "wb");
    fputs("\xff\xff\n", f); // 不是合法的 UTF-8 序列
    fclose(f);

    setlocale(LC_ALL, "en_US.utf8");
    f = fopen(fname, "rb");
    wint_t ch;
    while ((ch=fgetwc(f)) != WEOF) // 试图读作 UTF-8 而失败
          printf("%#x ", ch);

    if (feof(f))
        puts("EOF indicator set");
    if (ferror(f))
        puts("Error indicator set");
}

输出：

Error indicator set

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.10.3 The ferror function (p: 339)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.10.3 The ferror function (p: 305)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.10.3 The ferror function

参阅

clearerr | 清除错误 (函数)
feof | 检查文件结尾 (函数)
perror | 显示对应当前错误的字符串到 stderr (函数)


fflush

< c‎ | io
定义于头文件 <stdio.h>
int fflush( FILE *stream );

对于输出流（及最后操作为输出的更新流），从 stream 的缓冲区写入未写的数据到关联的输出设备。

对于输入流（及最后操作为输入的更新流），行为未定义。

若 stream 是空指针，则冲入所有输出流，包括操作于库包内者，或在其他情况下程序无法直接访问者。

参数

stream - 要写出的文件流

返回值

成功时返回零。否则返回 EOF 并设置文件流的错误指示器。

注意

POSIX通过定义fflush对输入流的效果扩展它的规定，只要该流还表示一个文件或另一个可定位设备：该情况下重寻位 POSIX 文件指针以匹配 C 流指针（这有效地撤销任何读缓冲），并舍弃任何尚未回读的 ungetc 或 ungetwc 的效果。

微软（Microsoft）也通过定义fflush对输入流的效果扩展它的规定：在Visual Studio 2013及以前的版本中， 放弃输入缓冲区；在Visual Studio 2015及以后的版本中，无影响并保留缓冲区.

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.5.2 The fflush function (p: 305)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.5.2 The fflush function (p: 270-271)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.5.2 The fflush function

参阅

fopenfopen_s (C11) | 打开文件 (函数)
fclose | 关闭文件 (函数)


fgetc, getc

< c‎ | io
定义于头文件 <stdio.h> |
int fgetc( FILE *stream ); | (1)
int getc( FILE *stream ); | (2)
1) 从给定的输入流读取下一个字符。
2) 同 fgetc ，除了若 getc 实现为宏，则它可能求值 stream 多于一次，所以实参始终不应为带有副作用的表达式。

参数

stream - 读取字符的来源

返回值

成功时为作为 unsigned char 获得并转换为 int 的字符，失败时为 EOF 。

若文件尾条件导致失败，则另外设置 stream 上的文件尾指示器（见 feof() ）。若某些其他错误导致失败，则设置 stream 上的错误指示器（见 ferror() ）。

示例

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE* fp = fopen("test.txt", "r");
    if(!fp) {
        perror("File opening failed");
        return EXIT_FAILURE;
    }

    int c; // 注意：int，非char，要求处理EOF
    while ((c = fgetc(fp)) != EOF) { // 标准C I/O读取文件循环
       putchar(c);
    }

    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");

    fclose(fp);
}

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.21.7.1 The fgetc function (p: 240-241)
  • 7.21.7.5 The getc function (p: 242)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.7.1 The fgetc function (p: 330)
  • 7.21.7.5 The getc function (p: 332)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.7.1 The fgetc function (p: 296)
  • 7.19.7.5 The getc function (p: 297-298)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.7.1 The fgetc function
  • 4.9.7.5 The getc function

参阅

getchar | 从 stdin 读取一个字符 (函数)
getsgets_s (C11 中移除)(C11) | 从 stdin 读取一个字符串 (函数)
fputcputc | 将一个字符写入文件流 (函数)
ungetc | 将一个字符送回文件流 (函数)


fgetpos

< c‎ | io
定义于头文件 <stdio.h> |
int fgetpos( FILE *stream, fpos_t *pos ); | (C99 前)
int fgetpos( FILE *restrict stream, fpos_t *restrict pos ); | (C99 起)

获得文件流 stream 的文件位置指示器和当前分析状态（若存在），并将它们存储于 pos 所指向的对象。存储的值仅在作为 fsetpos 的输入的情况有意义。

参数

stream | - | 要检验的文件流
pos | - | 指向要存储文件位置指示器到的 fpos_t 对象的指针

返回值

成功时为 ​0​ ，否则非零值。

示例

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int main(void)
{
    // 准备保有 4 个 double 类型值的文件
    enum {SIZE = 4};
    FILE* fp = fopen("test.bin", "wb");
    assert(fp);
    int rc = fwrite((double[SIZE]){1.1, 2.2, 3.3, 4.4}, sizeof(double), SIZE, fp);
    assert(rc == SIZE);
    fclose(fp);

    // 演示使用 fsetpos 返回到文件起始
    fp = fopen("test.bin", "rb");
    fpos_t pos;
    fgetpos(fp, &pos);               // 存储文件起始于 pos
    double d;
    rc = fread(&d, sizeof d, 1, fp); // 读取首个 double
    assert(rc == 1);
    printf("First value in the file: %.1f\n", d);
    fsetpos(fp,&pos);                 // 移动文件位置回文件起始
    rc = fread(&d, sizeof d, 1, fp);  // 再次读取首个 double
    assert(rc == 1);
    printf("First value in the file again: %.1f\n", d);
    fclose(fp);

    // 演示错误处理
    rc = fsetpos(stdin, &pos);
    if(rc) perror("could not fsetpos stdin");
}

输出：

First value in the file: 1.1
First value in the file again: 1.1
could not fsetpos stdin: Illegal seek

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.9.1 The fgetpos function (p: 336)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.9.1 The fgetpos function (p: 302)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.9.1 The fgetpos function

参阅

ftell | 返回当前的文件位置指示值 (函数)
fseek | 将文件位置指示符移动到文件中的指定位置 (函数)
fsetpos | 将文件位置指示器移动到文件中的指定位置 (函数)


fgets

< c‎ | io
定义于头文件 <stdio.h> |
char *fgets( char *str, int count, FILE *stream ); | (C99 前)
char *fgets( char *restrict str, int count, FILE *restrict stream ); | (C99 起)

从给定文件流读取最多 count - 1 个字符并将它们存储于 str 所指向的字符数组。若文件尾出现或发现换行符则终止分析，后一情况下 str 将包含一个换行符。若读入字节且无错误发生，则紧随写入到 str 的最后一个字符后写入空字符。

参数

str | - | 指向 char 数组元素的指针
count | - | 写入的最大字符数（典型的为 str 的长度）
stream | - | 读取数据来源的文件流

返回值

成功时为 str ，失败时为空指针。

若遇到文件尾条件导致了失败，则设置 stream 上的文件尾指示器（见 feof() ）。这仅若它导致未读取字符才是失败，该情况下返回空指针且不改变 str 所指向数组的内容（即不以空字符覆写首字节）。

若某些其他错误导致了失败，则设置 stream 上的错误指示器（见 ferror() ）。 str 所指向的数组内容是不确定的（甚至可以不是空终止）。

注解

POSIX 额外要求若 fgets 遇到异于文件尾条件的失败则设置 errno 。

尽管标准规范在 count<=1 的情况下不明，常见的实现

  • 若 count < 1 则不做任何事并报告错误
  • 若 count == 1 ，则
  • 某些实现不做任何事并报告错误，
  • 其他实现不读内容，存储零于 str[0] 并报告成功

示例

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE* tmpf = tmpfile();
    fputs("Alan Turing\n", tmpf);
    fputs("John von Neumann\n", tmpf);
    fputs("Alonzo Church\n", tmpf);

    rewind(tmpf);

    char buf[8];
    while (fgets(buf, sizeof buf, tmpf) != NULL)
          printf("\"%s\"\n", buf);

    if (feof(tmpf))
       puts("End of file reached");
}

输出：

"Alan Tu"
"ring
"
"John vo"
"n Neuma"
"nn
"
"Alonzo "
"Church
"
End of file reached

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.7.2 The fgets function (p: 331)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.7.2 The fgets function (p: 296)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.7.2 The fgets function

参阅

scanffscanfsscanfscanf_sfscanf_ssscanf_s (C11)(C11)(C11) | 从stdin、文件流或缓冲区读取格式化输入 (函数)
getsgets_s (C11 中移除)(C11) | 从 stdin 读取一个字符串 (函数)
fputs | 将一个字符串写入文件流 (函数)
getlinegetwlinegetdelimgetwdelim (动态内存 TR) | 从流读入至动态改变大小的缓冲区，直到分隔符/行尾 (函数)


fgetwc

< c‎ | io
定义于头文件 <wchar.h> |
wint_t fgetwc( FILE *stream ); | (C95 起)
wint_t getwc( FILE *stream ); | (C95 起)

从给定的输入流读取下个宽字符。 getwc() 可以实现为宏，且可能对 stream 求值超过一次。

参数

stream - 要读取宽字符的流

返回值

来自流的下个宽字符，或若失败则为 WEOF 。

若文件尾条件导致了失败，则额外设置 stream 上的文件尾指示器（见 feof()) ）。若某其他错误导致了失败，则设置 stream 上的错误指示器（见 ferror() ）。

若出现编码错误，则另外设置 errno 为 EILSEQ 。

示例

#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <errno.h>
#include <locale.h>

int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    FILE *fp = fopen("fgetwc.dat", "w");
    if(!fp) {
        perror("Can't open file for writing");
        return EXIT_FAILURE;
    }
    fputs("кошка\n", fp);
    fclose(fp);

    fp = fopen("fgetwc.dat", "r");
    if(!fp) {
        perror("Can't open file for reading");
        return EXIT_FAILURE;
    }
    wint_t wc;
    errno = 0;
    while ((wc = fgetwc(fp)) != WEOF)
        putwchar(wc);

    if (ferror(fp)) {
        if (errno == EILSEQ)
            puts("Character encoding error while reading.");
        else
            puts("I/O error when reading");
    } else if (feof(fp))
        puts("End of file reached successfully");

    fclose(fp);
}

输出：

кошка

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.3.1 The fgetwc function (p: 421-422)
  • 7.29.3.6 The getwc function (p: 424)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.3.1 The fgetwc function (p: 367)
  • 7.24.3.6 The getwc function (p: 369)

参阅

fgetcgetc | 从文件流获取一个字符 (函数)
fgetws (C95) | 从文件流获取一个宽字符串 (函数)
fputwcputwc (C95) | 将一个宽字符写入文件流 (函数)
ungetwc (C95) | 将一个宽字符送回文件流 (函数)


fgetws

< c‎ | io
定义于头文件 <wchar.h> |
wchar_t *fgetws( wchar_t *str, int count, FILE *stream ); | (C95 起) (C99 前)
wchar_t *fgetws( wchar_t * restrict str, int count, FILE * restrict stream ); | (C99 起)

从给定的文件流读取至多 count - 1 个宽字符，并将它们存储于 str 。产生的宽字符串始终是空终止的。若出现文件尾条件或找到换行宽字符则停止分析，后一情况下 str 将含有该宽换行符。

参数

str | - | 要读取字符到的宽字符串
count | - | str 的长度
stream | - | 读取数据来源的文件流

返回值

成功时为 str ，错误时为空指针。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.3.2 The fgetws function (p: 422)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.3.2 The fgetws function (p: 367-368)

参阅

wscanffwscanfswscanfwscanf_sfwscanf_sswscanf_s (C95)(C95)(C95)(C11)(C11)(C11) | 从stdin、文件流或缓冲区读取格式化宽字符输入 (函数)
fgetwcgetwc (C95) | 从文件流获取一个宽字符 (函数)
fputws (C95) | 将一个宽字符串写入文件流 (函数)
getlinegetwlinegetdelimgetwdelim (动态内存 TR) | 从流读入至动态改变大小的缓冲区，直到分隔符/行尾 (函数)


fopen, fopen_s

< c‎ | io
定义于头文件 <stdio.h> |  |
 | (1) |
FILE *fopen( const char *filename, const char *mode ); |  |  | (C99 前)
FILE *fopen( const char *restrict filename, const char *restrict mode ); |  |  | (C99 起)
errno_t fopen_s( FILE *restrict *restrict streamptr, const char *restrict filename, const char *restrict mode); | (2) | (C11 起)
1) 打开 filename 所指示的文件，并返回指向关联到该文件的文件流的指针。 mode 用于确定文件访问模式。
2) 同(1)，除了指向文件流的指针被写入 streamptr ，还在运行时检测下列错误，并调用当前安装的制约处理函数：
  • streamptr 是空指针
  • filename 是空指针
  • mode 是空指针
同所有边界检查函数， fopen_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <stdio.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

filename - 关联到文件系统的文件名
mode - 确定访问模式的空终止字符串
文件访问 模式字符串 | 含义 | 解释 | 若文件已存在的动作 | 若文件不存在的动作
"r" | 读 | 打开文件以读取 | 从头读 | 打开失败
"w" | 写 | 创建文件以写入 | 销毁内容 | 创建新文件
"a" | 后附 | 后附到文件 | 写到结尾 | 创建新文件
"r+" | 读扩展 | 打开文件以读/写 | 从头读 | 错误
"w+" | 写扩展 | 创建文件以读/写 | 销毁内容 | 创建新文件
"a+" | 后附扩展 | 打开文件以读/写 | 写到结尾 | 创建新文件
文件访问模式标签 "b" 可以可选地指定以二进制模式打开文件。此标签仅在 Windows 系统上生效。 在附加文件访问模式下，数据被写入到文件尾，而不考虑文件位置指示器的当前位置。
当文件以更新模式打开时（ '+' 作为上述模式参数值列表的第二或第三个字符），访问流可以进行输入和输出。然而输出不应直接紧随输入，而中间无对 fflush 函数或对文件定位函数（ fseek 、 fsetpos 或 rewind ）的调用，且输入不应直接紧随输出，而中间无对文件定位函数的调用，除非输入操作遇到文件尾。在一些实现中，以更新模式打开（或创建）文本文件可能取代打开（或创建）二进制流。
文件访问模式标签 "x" 可以可选地后附于 "w" 或 "w+" 指定符。若文件存在，则此标签强制函数失败，而不重写它。(C11)
使用 fopen_s 或 freopen_s 时，任何以 "w" 或 "a" 创建的文件的文件访问许可禁止其他用户访问它。文件访问模式标签 "u" 可以可选地前附于任何以为 "w" 或 "a" 始的指定符，以启用默认的 fopen 许可。(C11)
streamptr - 指向存储函数结果的指针的指针（输出参数）

返回值

1) 若成功，则返回指向新文件流的指针。流为完全缓冲，除非 filename 表示一个交互设备。错误时，返回空指针。 POSIX 要求此情况下必须设置 errno 。
2) 若成功，则返回零并将新文件流指针写入 *streamptr 。错误时，返回非零错误码并将空指针写入 *streamptr （除非 streamptr 自身也是空指针）。

注意

filename 的格式是实现定义的，而且不需要表示一个文件（譬如可以是控制台或另一能通过文件系统 API 访问的设备）。在支持的平台上， filename 可以包含绝对或相对路径。

示例

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE* fp = fopen("test.txt", "r");
    if(!fp) {
        perror("File opening failed");
        return EXIT_FAILURE;
    }

    int c; // 注意：int，非char，要求处理EOF
    while ((c = fgetc(fp)) != EOF) { // 标准C I/O读取文件循环
       putchar(c);
    }

    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");

    fclose(fp);
}

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.5.3 The fopen function (p: 305-306)
  • K.3.5.2.1 The fopen_s function (p: 588-590)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.5.3 The fopen function (p: 271-272)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.5.3 The fopen function

参阅

fclose | 关闭文件 (函数)
fflush | 将输出流与实际文件同步 (函数)
freopenfreopen_s (C11) | 以不同名称打开既存的文件流 (函数)


fpos_t

< c‎ | io
定义于头文件 <stdio.h>
typedef /* implementation-defined */ fpos_t ;

fpos_t 是非数组完整对象类型，能用于存储（由 fgetpos ）及恢复（由 fsetpos ） C 流的位置与多字节分析状态（若存在）。

宽面向的 C 流的多字节分析状态以 mbstate_t 对象表示，其值由 fgetpos 作为 fpos_t 对象的值的一部分存储。

 (C95 起)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.1 Introduction (p: 296-298)
  • 7.21.2 Streams (p: 298-299)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.1 Introduction (p: 262-264)
  • 7.19.2 Streams (p: 264-265)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.1 Introduction
  • 4.9.2 Streams

参阅

fgetpos | 获取文件位置指示器 (函数)
fsetpos | 将文件位置指示器移动到文件中的指定位置 (函数)
mbstate_t (C95) | 迭代多字节字符串所需的转换信息 (结构体)


printf, fprintf, sprintf, snprintf, printf_s, fprintf_s, sprintf_s, snprintf_s

< c‎ | io
定义于头文件 <stdio.h> |  |
 | (1) |
int printf( const char *format, ... ); |  |  | (C99 前)
int printf( const char *restrict format, ... ); |  |  | (C99 起)
 | (2) |
int fprintf( FILE *stream, const char *format, ... ); |  |  | (C99 前)
int fprintf( FILE *restrict stream, const char *restrict format, ... ); |  |  | (C99 起)
 | (3) |
int sprintf( char *buffer, const char *format, ... ); |  |  | (C99 前)
int sprintf( char *restrict buffer, const char *restrict format, ... ); |  |  | (C99 起)
int snprintf( char *restrict buffer, int bufsz, const char *restrict format, ... ); | (4) | (C99 起)
int printf_s(const char *restrict format, ...); | (5) | (C11 起)
int fprintf_s( FILE *restrict stream, const char *restrict format, ...); | (6) | (C11 起)
int sprintf_s(char *restrict buffer, rsize_t bufsz, const char *restrict format, ...); | (7) | (C11 起)
int snprintf_s(char *restrict buffer, rsize_t bufsz, const char *restrict format, ...); | (8) | (C11 起)

从给定位置加载数据，转换为字符串等价物，并写结果到各种池。

1) 写结果到 stdout 。
2) 写结果到文件流 stream 。
3) 写结果到字符串 buffer 。
4) 写结果到字符串 buffer 。至多写 buf_size - 1 个字符。产生的字符串会以空字符终止，除非 buf_size 为零。若 buf_size 为零，则不写入任何内容，且 buffer 可以是空指针，然而依旧计算返回值（会写入的字符数，不包含空终止符）并返回。
5-8) 同 (1-4) ，除了在运行时检测下列错误，并调用当前安装的制约处理函数：
  • format 中存在转换说明符 %n
  • 任何一个对应 %s 的参数是空指针
  • format 或 buffer 是空指针
  • bufsz 为零或大于 RSIZE_MAX
  • 在任何一个字符串及字符转换说明符中出现编码错误
  • （仅对于 sprintf_s ）存储于 buffer 的字符串（包括尾随空字符）长度将超出 bufsz
同所有边界检查函数， printf_s, fprintf_s, sprintf_s, snrintf_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <stdio.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

stream - 要写入的输出文件流
buffer - 指向要写入的字符串的指针
bufsz - 最多会写入 bufsz - 1 个字符，再加空终止符
format - 指向指定数据转译方式的空终止多字节字符串的指针。

格式字符串由普通多字节字符（除了 % ）和转换指定构成，前者被复制到输出流而无更改。每个转换指定拥有下列格式：

  • 引入的 % 字符
  • (可选)一或多个修改转换行为的标签：
  • - ：转换结果在域内左校正（默认为右校正）
  • + ：有符号转换的符号始终前置于转换结果（默认结果前置负号仅当它为负）
  • 空格：若有符号转换的结果不以符号开始，或为空，则前置空格于结果。若存在 + 标签则忽略空格。
  • # ：进行替用形式的转换。准确的效果见下表，其他情况下行为未定义。
  • 0 ：对于整数和浮点数转换，使用前导零代替空格字符填充域。对于整数，若显式指定精度，则忽略此标签。对于其他转换，使用此标签导致未定义行为。若存在 - 标签则忽略 0 。
  • (可选)指定最小域宽的整数值或 * 。若有要求，则结果会以空格字符（默认情况）填充，在右校正时于左，左校正时于右。使用 * 的情况下，以一个额外的 int 类型参数指定宽度。若参数值为负数，则它导致指定 - 标签和正域宽。（注意：这是最小宽度：决不被截断值）。
  • (可选)后随整数或 * 或两者皆无的 . 指示转换的精度。在使用 * 的情况下，精度由额外的 int 类型参数指定。若此参数的值为负数，则它被忽略。若既不使用数字亦不使用 * ，则精度采用零。精度的准确效果见下表。
  • (可选)指定参数大小的长度修饰符
  • 转换格式指定符

下列格式指定符可用：

转换
指定符 		解释 参数类型
长度修饰符 hh

(C99)

 h （无） l ll

(C99)

 j

(C99)

 z

(C99)

 t

(C99)

 L
% 写字面的 % 。完整转换指定必须是 %% 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
写单个字符。

参数首先被转换成 unsigned char 。 若使用 l 修饰符，则参数首先被转换成字符串，如同通过以 wchar_t[2] 参数使用 %ls 。

 N/A N/A
int
wint_t
 N/A N/A N/A N/A N/A
s
写字符串

参数必须是指向字符数组首元素的指针 精度指定写入最大的字符数。若未指定精度，则写每个字节直到而不含首个空终止符。 若使用 l 指定符，则参数必须是指向 wchar_t 数组首元素的指针，数组会被转换成 char 数组，如同通过以零初始化转换状态调用 wcrtomb 。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
d
i
转换有符号整数为十进制表示 [-]dddd 。

精度指定出现的最小数位数。默认精度是 1 。
若被转换的值和精度都是 ​0​ ，则转换结果无字符。
signed char
short
int
long
long long
intmax_t
有符号 size_t
ptrdiff_t
 N/A
o
转换无符号整数为八进制表示 oooo 。

精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中精度按需增加，以写入一个前导零。 在此情况下若被转换值和精度都是 ​0​ ，则写入单个 ​0​ 。
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
uintmax_t
size_t
ptrdiff_t 的无符号版本
 N/A
x
X
转换无符号整数为十六进制表示 hhhh 。

x 转换使用字母 abcdef 。
X 转换使用 ABCDEF 。
精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中若被转换值为非零则结果有 0x 或 0X 前缀。

 N/A
u
转换无符号整数为十进制表示 dddd 。

精度指定出现的最小数位数。 默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。

 N/A
f
F
转换浮点数为 [-]ddd.ddd 样式的十进制记法。

精度指定小数点字符后出现的准确数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A
double
double (C99)
 N/A N/A N/A N/A
long double
e
E
转换浮点数为十进制指数记法。

e 转换样式使用 [-]d.ddd e±dd 。
E 转换样式使用 [-]d.ddd E±dd 。
指数至少含二个数位，仅当所需时使用更多数位。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
a
A

(C99)
转换浮点数为十六进制记法。

a 转换样式使用 [-]0x h.hhh p±d 。
A 转换样式使用 [-]0X h.hhh P±d 。
若参数是正规化的浮点值，则首个十六进制数位非 0 。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度足以准确表示该值。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
g
G
转换浮点数为十进制小数或十进制指数记法，依赖于值和精度。

g 转换样式将进行带样式 e 或 f 的转换。
G 转换样式将进行带样式 E 或 F 的转换。
令 P 等于精度，若它非零，若精度未指定则为 6 ，若精度为 ​0​ 则等于 1 。然后，若带样式 E 的转换会有指数 X ，则：

  • 若 P > X ≥ −4 ，则转换带 f 或 F 风格，及精度 P − 1 − X 。
  • 否则，转换带 e 或 E 风格，及精度 P − 1 。

除非要求替用表示，否则末尾零会被移除，且若不留下小数部分则小数点亦被移除。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
n
返回对函数的此调用迄今为止写入的字符数。

结果被写入到参数所指向的值。 该指定不可含有任何标签、域宽或精度。
signed char*
short*
int*
long*
long long*
intmax_t *
有符号 size_t *
ptrdiff_t *
 N/A
p 写定义指针的实现定义字符序列。 N/A N/A void* N/A N/A N/A N/A N/A N/A

浮点转换函数转换无穷大到 inf 或 infinity 。使用哪个是实现定义的。

非数转换成 nan 或 nan(char_sequence) 。使用哪个是实现定义的。

转换 F 、 E 、 G 、 A 替代上面输出 INF 、 INFINITY 、 NAN。

尽管 %c 期待 int 参数，传递 char 是安全的，因为在调用变参数函数时发生整数提升。

定宽整数类型（ int8_t 等）的正确转换指定定义于头文件 <inttypes.h> （尽管 PRIdMAX 、 PRIuMAX 等就是 %jd 、 %ju 等的别名）。

内存写入转换指定符 %n 是安全漏洞的常见目标，这里格式字符串依赖用户输入，而有边界检查的 printf_s 系列函数不支持此转换指定符。

在每个转换指定符的行动后有一个序列点；这允许于同一变量多次存入 %n 的结果，并在同一此调用中打印出先前以 %n 存储的值。

若转换指定非法，则行为未定义。
... - 指定要打印数据的参数。若任何默认参数提升后的参数不拥有对应转换说明符所期待的类型，或若参数数量少于 format 的要求，则行为未定义。若有多于 format 要求的参数，则求值并忽略多出的参数。

返回值

1,2) 传输到输出流的字符数，或若出现输出错误或编码错误（对于字符串和字符转换说明符）则为负值。
3) 写入到 buffer 的字符数（不计空终止字符），或若输出错误或编码错误（对于字符串和字符转换说明符）发生则为负值。
4) 假如忽略 bufsz 则本应写入到 buffer 的字符数（不计空终止字符），或若出现输出错误或编码错误（对于字符串和字符转换说明符）则为负值。
5,6) 传输到输出流的字符数，或若出现输出错误、运行时制约违规错误或编码错误则为负值。
7) 写入到buffer的字符数，不计空终止字符（只要 buffer 不是空指针且 bufsz 非零且不大于 RSIZE_MAX ，就写入它），在运行时制约违规时为零，而在编码错误时为负值。
8) 假如忽略 bufsz 则本应写入 buffer 的字符数的，不包含空终止字符（只要 buffer 不是空指针而 bufsz 非零且不大于 RSIZE_MAX ，就写入它），或若出现输出错误、运行时制约违规错误或编码错误则为负值。

注解

C 标准及POSIX 指定 sprintf 及其变体的行为在参数与目标缓冲区重叠时未定义。示例：

sprintf(dst, "%s and %s", dst, t); // <- 有错：未定义行为

POSIX 规定在错误时设置 errno 。它亦指定额外的转换指定，最值得注意的是对参数重排序的支持（紧随 % 后的 n$ 指示第 n 个参数）。

以零为 bufsz 和空指针为 buffer 调用 snprintf 可用于决定包含输出的缓冲区大小：

const char *fmt = "sqrt(2) = %f";
int sz = snprintf(NULL, 0, fmt, sqrt(2));
char buf[sz + 1]; // 注意为终止空字符 +1
snprintf(buf, sizeof buf, fmt, sqrt(2));

同 snprintf ，但不同于 sprintf_s ， snprintf_s 会将输出截断在 bufsz-1 之内。

示例

#include <stdio.h>

int main(void)
{
    printf("Strings:\n");
    const char* s = "Hello";
    printf("\t.%10s.\n\t.%-10s.\n\t.%*s.\n", s, s, 10, s);

    printf("Characters:\t%c %%\n", 65);

    printf("Integers\n");
    printf("Decimal:\t%i %d %.6i %i %.0i %+i %u\n", 1, 2, 3, 0, 0, 4, -1);
    printf("Hexadecimal:\t%x %x %X %#x\n", 5, 10, 10, 6);
    printf("Octal:\t%o %#o %#o\n", 10, 10, 4);

    printf("Floating point\n");
    printf("Rounding:\t%f %.0f %.32f\n", 1.5, 1.5, 1.3);
    printf("Padding:\t%05.2f %.2f %5.2f\n", 1.5, 1.5, 1.5);
    printf("Scientific:\t%E %e\n", 1.5, 1.5);
    printf("Hexadecimal:\t%a %A\n", 1.5, 1.5);
}

输出：

Strings:
    .     Hello.
    .Hello     .
    .     Hello.
Characters:     A %
Integers
Decimal:        1 2 000003 0  +4 4294967295
Hexadecimal:    5 a A 0x6
Octal:          12 012 04
Floating point
Rounding:       1.500000 2 1.30000000000000004440892098500626
Padding:        01.50 1.50  1.50
Scientific:     1.500000E+00 1.500000e+00
Hexadecimal:    0x1.8p+0 0X1.8P+0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.6.1 The fprintf function (p: 309-316)
  • 7.21.6.3 The printf function (p: 324)
  • 7.21.6.5 The snprintf function (p: 325)
  • 7.21.6.6 The sprintf function (p: 325-326)
  • K.3.5.3.1 The fprintf_s function (p: 591)
  • K.3.5.3.3 The printf_s function (p: 593-594)
  • K.3.5.3.5 The snprintf_s function (p: 594-595)
  • K.3.5.3.6 The sprintf_s function (p: 595-596)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.6.1 The fprintf function (p: 274-282)
  • 7.19.6.3 The printf function (p: 290)
  • 7.19.6.5 The snprintf function (p: 290-291)
  • 7.19.6.6 The sprintf function (p: 291)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.6.1 The fprintf function
  • 4.9.6.3 The printf function
  • 4.9.6.5 The sprintf function

参阅

wprintffwprintfswprintfwprintf_sfwprintf_sswprintf_ssnwprintf_s (C95)(C95)(C95)(C11)(C11)(C11)(C11) | 打印格式化宽字符输出到 stdout 、文件流或缓冲区 (函数)
vprintfvfprintfvsprintfvsnprintfvprintf_svfprintf_svsprintf_svsnprintf_s (C99)(C11)(C11)(C11)(C11) | 打印格式化输出到stdout、文件流或缓冲区 使用可变参数列表 (函数)
fputs | 将一个字符串写入文件流 (函数)
scanffscanfsscanfscanf_sfscanf_ssscanf_s (C11)(C11)(C11) | 从stdin、文件流或缓冲区读取格式化输入 (函数)


fputc, putc

< c‎ | io
定义于头文件 <stdio.h>
int fputc( int ch, FILE *stream );
int putc( int ch, FILE *stream );

写入字符 ch 到给定输出流 stream 。 putc() 可以实现为宏并对 stream 求值超过一次，故对应的参数决不应是有副效应的表达式。

在内部，在写入前将字符转换为 unsigned char 。

参数

ch | - | 要被写入的字符
stream | - | 输出流

参数

ch | - | 要写入的字符
stream | - | 输出流

返回值

成功时，返回被写入字符。

失败时，返回 EOF 并设置 stream 上的错误指示器（见 ferror() ）。

示例

putc带错误检查

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int ret_code = 0;
    for (char c = 'a'; (ret_code != EOF) && (c != 'z'); c++)
        ret_code = putc(c, stdout);

    /* 测试是否抵达 EOF 。 */
    if (ret_code == EOF)
       if (ferror(stdout))
       {
          perror("putc()");
          fprintf(stderr,"putc() failed in file %s at line # %d\n", __FILE__,__LINE__-7);
          exit(EXIT_FAILURE);
       }
    putc('\n', stdout);

    return EXIT_SUCCESS;
}

输出：

abcdefghijklmnopqrstuvwxy

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.7.3 The fputc function (p: 331)
  • 7.21.7.7 The putc function (p: 333)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.7.3 The fputc function (p: 297)
  • 7.19.7.8 The putc function (p: 299)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.7.3 The fputc function
  • 4.9.7.8 The putc function

参阅

putchar
 将一个字符写入 stdout
(函数)


fputs

< c‎ | io
定义于头文件 <stdio.h> |
int fputs( const char *str, FILE *stream ); | (C99 前)
int fputs( const char *restrict str, FILE *restrict stream ); | (C99 起)

将以NULL结尾的字符串 str 的每个字符写入到输出流 stream ，如同通过重复执行 fputc 。

不将 str 的空字符写入。

参数

str | - | 要写入的空终止字符串
stream | - | 输出流

返回值

成功时，返回非负值。

失败时，返回 EOF 并设置 stream 上的错误指示器（见 ferror ）。

注意

相关函数 puts 后附新换行符到输出，而 fputs 写入不修改的字符串。

不同的实现返回不同的非负数：一些返回最后写入的字符，一些返回写入的字符数（或若字符串长于 INT_MAX 则为该值），一些简单地非负常量，例如零。

示例

#include <stdio.h>

int main(void)
{
    int rc = fputs("Hello World", stdout);

    if (rc == EOF)
       perror("fputs()"); // POSIX 要求设置 errno
}

输出：

Hello World

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.7.4 The fputs function (p: 331-332)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.7.4 The fputs function (p: 297)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.7.4 The fputs function

参阅

printffprintfsprintfsnprintfprintf_sfprintf_ssprintf_ssnprintf_s (C99)(C11)(C11)(C11)(C11) | 打印格式化输出到 stdout 、文件流或缓冲区 (函数)
puts | 将一个字符串写入 stdout (函数)
fgets | 从文件流获取一个字符串 (函数)


fputwc, putwc

< c‎ | io
定义于头文件 <wchar.h> |
wint_t fputwc( wchar_t ch, FILE *stream ); | (C95 起)
wint_t putwc( wchar_t ch, FILE *stream ); | (C95 起)

写宽字符 ch 到给定的输出流 stream 。 putwc() 可以实现为宏并可求值 stream 多于一次。

参数

ch | - | 要写入的宽字符
stream | - | 输出流

返回值

成功时返回 ch 的副本。

失败时，返回 WEOF 并设置 stream 上的错误指示器（见 ferror() ）。

若出现编码错误，则另外设置 errno 为 EILSEQ 。

示例

#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <errno.h>

int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");

    errno = 0;
    if (fputwc(L'🍌', stdout) == WEOF) {
        if (errno == EILSEQ)
            puts("Encoding error in fputwc.");
        else
            puts("I/O error in fputwc.");
        return EXIT_FAILURE;
    }
}

输出：

🍌

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.3.3 The fputwc function (p: 422-423)
  • 7.29.3.8 The putwc function (p: 424)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.3.3 The fputwc function (p: 368)
  • 7.24.3.8 The putwc function (p: 370)

参阅

fputcputc | 将一个字符写入文件流 (函数)
fputws (C95) | 将一个宽字符串写入文件流 (函数)
fgetwcgetwc (C95) | 从文件流获取一个宽字符 (函数)


fputws

< c‎ | io
定义于头文件 <wchar.h> |
int fputws( const wchar_t *str, FILE *stream ); | (C95 起) (C99 前)
int fputws( const wchar_t * restrict str, FILE * restrict stream ); | (C99 起)

写入来自空终止宽字符串 str 的每个宽字符到输出流 stream ，如同通过重复执行 fputwc 。

不写入来自 str 的终止宽字符。

参数

str | - | 要写入的空终止宽字符串
stream | - | 输出流

返回值

成功时返回非负值。

失败时，返回 EOF 并设置 stream 上的错误指示器（见 ferror ）。

示例

#include <locale.h>
#include <stdio.h>
#include <wchar.h>

int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    int rc = fputws(L"洗洗睡吧", stdout);

    if (rc == EOF)
       perror("fputws()"); // POSIX 要求设置 errno
}

输出：

洗洗睡吧

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.3.4 The fputws function (p: 423)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.3.4 The fputws function (p: 368)

参阅

fputs | 将一个字符串写入文件流 (函数)
wprintffwprintfswprintfwprintf_sfwprintf_sswprintf_ssnwprintf_s (C95)(C95)(C95)(C11)(C11)(C11)(C11) | 打印格式化宽字符输出到 stdout 、文件流或缓冲区 (函数)
fputws (C95) | 将一个宽字符串写入文件流 (函数)
fgetws (C95) | 从文件流获取一个宽字符串 (函数)


fread

< c‎ | io
定义于头文件 <stdio.h> |
size_t fread( void *buffer, size_t size, size_t count, FILE *stream ); | (C99 前)
size_t fread( void *restrict buffer, size_t size, size_t count, FILE *restrict stream ); | (C99 起)

从给定输入流 stream 读取至多 count 个对象到数组 buffer 中，如同以对每个对象调用 size 次 fgetc ，并按顺序存储结果到转译为 unsigned char 数组的 buffer 中的相继位置。流的文件位置指示器前进读取的字符数。

若出现错误，则流的文件位置指示器的结果值不确定。若读入部分的元素，则元素值不确定。

参数

buffer | - | 指向要读取的数组中首个对象的指针
size | - | 每个对象的字节大小
count | - | 要读取的对象数
stream | - | 读取来源的输入文件流

返回值

成功读取的对象数，若出现错误或文件尾条件，则可能小于 count 。

若 size 或 count 为零，则 fread 返回零且不进行其他动作。

fread 不区别文件尾和错误，而调用者必须用 feof 和 ferror 鉴别出现者为何。

示例

#include <stdio.h>

enum { SIZE = 5 };
int main(void)
{
    double a[SIZE] = {1.,2.,3.,4.,5.};
    FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式
    fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组
    fclose(fp);

    double b[SIZE];
    fp = fopen("test.bin","rb");
    size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
    if(ret_code == SIZE) {
        puts("Array read successfully, contents: ");
        for(int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
        putchar('\n');
    } else { // error handling
       if (feof(fp))
          printf("Error reading test.bin: unexpected end of file\n");
       else if (ferror(fp)) {
           perror("Error reading test.bin");
       }
    }

    fclose(fp);
}

输出：

Array read successfully, contents:
1.000000 2.000000 3.000000 4.000000 5.000000

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.8.1 The fread function (p: 335)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.8.1 The fread function (p: 301)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.8.1 The fread function

参阅

scanffscanfsscanfscanf_sfscanf_ssscanf_s (C11)(C11)(C11) | 从stdin、文件流或缓冲区读取格式化输入 (函数)
fgets | 从文件流获取一个字符串 (函数)
fwrite | 写入到文件 (函数)


freopen, freopen_s

< c‎ | io
定义于头文件 <stdio.h> |  |
 | (1) |
FILE *freopen( const char *filename, const char *mode, FILE *stream ); |  |  | (C99 前)
FILE *freopen( const char *restrict filename, const char *restrict mode, FILE *restrict stream ); |  |  | (C99 起)
errno_t freopen_s( FILE *restrict *restrict newstreamptr, const char *restrict filename, const char *restrict mode, FILE *restrict stream); | (2) | (C11 起)
1) 首先，试图关闭与 stream 关联的文件，忽略任何错误。然后，若 filename 非空，则试图用 mode 打开 filename 所指定的文件，如同用 fopen ，然后将该文件与 stream 所指向的文件流关联。若 filename 为空指针，则函数试图重打开已与 stream 关联的文件（此情况下是否允许模式改变是实现定义的）。
2) 同 (1) ，除了以 fopen_s 中的方式处理 mode ，并将指向文件流的指针写入 newstreamptr ，还在运行时检测下列错误，并调用当前安装的制约处理函数：
  • newstreamptr 是空指针
  • stream 是空指针
  • mode 是空指针
同所有边界检查函数， freopen_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <stdio.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

filename - 要关联到文件流的文件名
mode - 确定文件访问模式的空终止字符串
文件访问 模式字符串 | 含义 | 解释 | 若文件已存在的动作 | 若文件不存在的动作
"r" | 读 | 打开文件以读取 | 从头读 | 打开失败
"w" | 写 | 创建文件以写入 | 销毁内容 | 创建新文件
"a" | 后附 | 后附到文件 | 写到结尾 | 创建新文件
"r+" | 读扩展 | 打开文件以读/写 | 从头读 | 错误
"w+" | 写扩展 | 创建文件以读/写 | 销毁内容 | 创建新文件
"a+" | 后附扩展 | 打开文件以读/写 | 写到结尾 | 创建新文件
文件访问模式标签 "b" 可以可选地指定以二进制模式打开文件。此标签仅在 Windows 系统上生效。 在附加文件访问模式下，数据被写入到文件尾，而不考虑文件位置指示器的当前位置。
当文件以更新模式打开时（ '+' 作为上述模式参数值列表的第二或第三个字符），访问流可以进行输入和输出。然而输出不应直接紧随输入，而中间无对 fflush 函数或对文件定位函数（ fseek 、 fsetpos 或 rewind ）的调用，且输入不应直接紧随输出，而中间无对文件定位函数的调用，除非输入操作遇到文件尾。在一些实现中，以更新模式打开（或创建）文本文件可能取代打开（或创建）二进制流。
文件访问模式标签 "x" 可以可选地后附于 "w" 或 "w+" 指定符。若文件存在，则此标签强制函数失败，而不重写它。(C11)
使用 fopen_s 或 freopen_s 时，任何以 "w" 或 "a" 创建的文件的文件访问许可禁止其他用户访问它。文件访问模式标签 "u" 可以可选地前附于任何以为 "w" 或 "a" 始的指定符，以启用默认的 fopen 许可。(C11)
stream - 要修改的文件流
newstreamptr - 指向函数存储结果所用指针的指针（输出参数）

返回值

1) 成功时为 stream 值的副本，失败时为空指针。
2) 成功时为零（并将 stream 值的副本写入 *newstreamptr ），失败时为非零（并写入空指针到 *newstreamptr ，除非 newstreamptr 自身为空指针）。

注解

freopen 是一旦由 I/O 操作或 fwide 建立面向后，改变文件流窄/宽面向的唯一方式。

freopen 的 Microsoft CRT 版本在 filename 为空指针时不支持任何模式更改并将它当作错误（见文档）。可行的替代方案是非标准函数 _setmode() 。

示例

下列代码重定向 stdout 到文件。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    puts("stdout is printed to console");
    if (freopen("redir.txt", "w", stdout) == NULL)
    {
       perror("freopen() failed");
       return EXIT_FAILURE;
    }
    puts("stdout is redirected to a file"); // 写入 redir.txt
    fclose(stdout);
}

输出：

stdout is printed to console

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.5.4 The freopen function (p: 307)
  • K.3.5.2.2 The freopen_s function (p: 590)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.5.4 The freopen function (p: 272-273)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.5.4 The freopen function

参阅

fopenfopen_s (C11) | 打开文件 (函数)
fclose | 关闭文件 (函数)


scanf, fscanf, sscanf, scanf_s, fscanf_s, sscanf_s

< c‎ | io
定义于头文件 <stdio.h> |  |
 | (1) |
int scanf( const char *format, ... ); |  |  | (C99 前)
int scanf( const char *restrict format, ... ); |  |  | (C99 起)
 | (2) |
int fscanf( FILE *stream, const char *format, ... ); |  |  | (C99 前)
int fscanf( FILE *restrict stream, const char *restrict format, ... ); |  |  | (C99 起)
 | (3) |
int sscanf( const char *buffer, const char *format, ... ); |  |  | (C99 前)
int sscanf( const char *restrict buffer, const char *restrict format, ... ); |  |  | (C99 起)
int scanf_s(const char *restrict format, ...); | (4) | (C11 起)
int fscanf_s( FILE *restrict stream, const char *restrict format, ...); | (5) | (C11 起)
int sscanf_s(const char *restrict buffer, const char *restrict format, ...); | (6) | (C11 起)

从各种资源读取数据，按照 format 转译，并将结果存储到指定位置。

1) 从 stdin 读取数据
2) 从文件流 stream 读取数据
3) 从空终止字符串 buffer 读取数据。抵达字符串结尾等价于 fscanf 的抵达文件尾条件
4-6) 同 (1-3) ，除了 %c 、 %s 及 %[ 转换指定符要求二个参数（通常的指针和指示获取用数组大小的 rsize_t 类型的值，在以 %c 读取单个字符时可以为 1 ），并在运行时检测下列错误，并调用当前安装的制约处理函数：
  • 任何指针类型的参数是为空指针
  • format 、 stream 或 buffer 为空指针
  • %c 、 %s 或 %[ 会写入的字符数，加上空终止字符，要超过提供给这些转换指定符的第二个（ rsize_t ）参数
  • 可选，任何其他可检测错误，例如未知转换指定符
同所有边界检查函数， scanf_s, fscanf_s, sscanf_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <stdio.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

stream - 要读取的输入文件流
buffer - 指向要读取的空终止字符串的指针
format - 指向指定读取输入方式的空终止字符串的指针。

格式字符串由下列内容组成

  • 非空白多字节字符，除了 % ：每个格式字符串中的这种字符处理来自输入流的准确同一字符，或若它与流的下个字符比较不相等则导致函数失败。
  • 空白符：任何格式字符串中的单个空白符处理所有来自输入的可用连续空白符（如同通过于循环中调用 isspace 确定）。注意格式字符串中 "\n" 、 " " 、 "\t\t" 或其他空白无区别。
  • 转换说明：每个转换说明拥有下列格式：
  • 引入用 % 字符
  • (可选)赋值抑制字符 * 。若存在此选项，则此函数不将结果赋值给任何接收用参数。
  • (可选)指定最大域宽的整数数字（大于零），即函数进行在当前转换说明所指定的转换时，允许处理的最大字符数。注意若不提供宽度，则 %s 和 %[ 可能导致缓冲区溢出。
  • (可选)指定接收参数大小的长度修饰符，即实际目标类型。这影响转换准确性和溢出规则。默认目标类型对每个转换类型不同（见下表）。
  • 转换格式说明符

下列格式说明符可用：

转换
说明符 		解释 参数类型
长度修饰符 →
 hh

(C99)

 h （无） l ll

(C99)

 j

(C99)

 z

(C99)

 t

(C99)

 L
% 匹配字面 % 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
匹配一个字符或字符的序列

若使用了宽度说明符，则匹配准确的宽度个字符（该参数必须是指向有充足空间的数组的指针）。不同于 %s 和 %[ ，它不会在数组后附加空字符。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
s
匹配非空白字符的序列（一个字符串）

若使用宽度说明符，则至多匹配宽度个字符，或匹配到首个提前出现的空白符前。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
[集合]
匹配一个来自 集合 的字符的非空字符序列。

若集合的首字符是 ^ ，则匹配所有不在集合中的字符。若集合以 ] 或 ^] 开始，则 ] 字符亦被包含入集合。在扫描集合的非最初位置的字符 - 是否可以指示范围，如 [0-9] ，是实现定义的。若使用宽度说明符，则最多匹配到宽度。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
d
匹配一个十进制整数。

该数的格式同 strtol() 以值 10 为 base 时所期望者
signed char* 或 unsigned char*
signed short* 或 unsigned short*
signed int* 或 unsigned int*
signed long* 或 unsigned long*
signed long long* 或 unsigned long long*
intmax_t * 或 uintmax_t *
size_t *
ptrdiff_t *
 N/A
i
匹配一个整数。

该数的格式同 strtol() 以值 ​0​ 为 base 时所期望者（基底以首个分析的字符确定）
u
匹配一个无符号十进制整数。

该数的格式同 strtoul() 以值 10 为 base 参数时所期望者。
o
匹配一个无符号八进制数。

该数的格式同 strtoul() 以值 8 为 base 参数时所期望者。
x, X
匹配一个无符号十六进制整数。

该数的格式同 strtoul() 以值 16 为 base 参数时所期望者。
n
返回迄今读取的字符数。

不消耗输出。不增加赋值计数。若此说明符拥有赋值抑制运算符，则行为未定义。
a, A(C99)
e, E
f, F
g, G
匹配一个浮点数。

该数的格式同 strtof() 所期望者。

 N/A N/A
float*
double*
 N/A N/A N/A N/A
long double*
p
匹配定义一个指针的实现定义的字符序列。

printf 系列函数应该用 %p 格式说明符产生同样的序列。

 N/A N/A
void**
 N/A N/A N/A N/A N/A N/A

对于每个异于 n 的转换说明符，不超过任何指定域宽，且要么是转换说明符所准确期待，要么是其所期待的前缀的最长输入字符序列，即是从流中消耗的内容。此消耗序列后的首个字符若存在，则保持未读取。若被消耗序列长度为零，或被消耗序列不能转换成上面所指定的项目，则发生匹配失败，除非遇到文件尾、编码错误，或阻止从流输入的读取错误，此情况下此为输入失败。

所有异于 [ 、 c 和 n 的转换说明符，在尝试分析输入前消耗并舍弃所有前导空白字符（如同以调用 isspace 来确定）。这些被消耗的字符不计入指定的最大域宽。

转换说明符 lc 、 ls 和 l[ 进行多字节到宽字符转换，如同如同在转换首字符前，通过用初始化到零的 mbstate_t 对象调用 mbrtowc() 。

转换说明符 s 与 [ 始终在匹配字符之后存储一个空字符。目标数组的大小必须至少比指定域宽大一。

定宽整数类型（ int8_t 等）的正确的转换说明定义于头文件 <inttypes.h> （虽然 SCNdMAX 、 SCNuMAX 等就是 %jd 、 %ju 等的别名）。

在每个转换说明符后有一个序列点；这允许存储多个域到同一“池”变量中。

在分析以无数字指数为结尾的不完整浮点值，如以转换说明符 %f 分析 "100er" 时，消耗序列 "100e" （可能为合法浮点数的最长前缀），并导致匹配错误（被消耗序列不能转换成浮点数），而留下 "r" 。某些既存实现不遵守此规则并回滚，通过消耗 "100" 而留下 "er" ，例如 glibc 漏洞 1765 。

若转换指定非法，则行为未定义。
... - 接收用参数

返回值

1-3) 成功赋值的接收参数的数量（可以为零，在首个接收用参数赋值前匹配失败的情况下），或者若输入在首个接收用参数赋值前发生失败，则为EOF。
4-6) 同 (1-3) ，除了若有运行时制约违规，亦返回 EOF 。

注意

因为多数转换指定符首先消耗掉所有连续空白符，如下的代码

scanf("%d", &a);
scanf("%d", &b);

将读取在不同行上（第二个 %d 会消耗第一个剩下的换行符）或同一行由空格或制表符分隔（第二个 %d 会消耗空格或制表符）的整数。

不消耗前导空白符的转换指定符，如 %c ，可以通过在格式字符串中前置一个空白符令它如此：

scanf("%d", &a);
scanf(" %c", &c); // 消耗 %d 后的所有后继空白符，然后读一个 char

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stddef.h>
#include <locale.h>

int main(void)
{
    int i, j;
    float x, y;
    char str1[10], str2[4];
    wchar_t warr[2];
    setlocale(LC_ALL, "en_US.utf8");

    char input[] = "25 54.32E-1 Thompson 56789 0123 56ß水";
    /* 按下列分析：
       %d ：整数
       %f ：浮点值
       %9s ：最多有 9 个非空白符的字符串
       %2d ： 2 位的整数（数位 5 和 6 ）
       %f ：浮点值（数位 7 、 8 、 9）
       %*d ：不存储于任何位置的整数
       ' ' ：所有连续空白符
       %3[0-9] ：至多有 3 个十进制数字的字符串（数位 5 和 6 ）
       %2lc ：二个宽字符，使用多字节到宽转换  */
    int ret = sscanf(input, "%d%f%9s%2d%f%*d %3[0-9]%2lc",
                     &i, &x, str1, &j, &y, str2, warr);

    printf("Converted %d fields:\ni = %d\nx = %f\nstr1 = %s\n"
           "j = %d\ny = %f\nstr2 = %s\n"
           "warr[0] = U+%x warr[1] = U+%x\n",
           ret, i, x, str1, j, y, str2, warr[0], warr[1]);

#ifdef __STDC_LIB_EXT1__
    int n = sscanf_s(input, "%d%f%s", &i, &x, str1, (rsize_t)sizeof str1);
    // 写 25 到 i ， 5.432 到 x ， 9 个字节 "thompson\0" 到 str1 ，和 3 到 n 。
#endif
}

输出：

Converted 7 fields:
i = 25
x = 5.432000
str1 = Thompson
j = 56
y = 789.000000
str2 = 56
warr[0] = U+df warr[1] = U+6c34

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.6.2 The fscanf function (p: 317-324)
  • 7.21.6.4 The scanf function (p: 325)
  • 7.21.6.7 The sscanf function (p: 326)
  • K.3.5.3.2 The fscanf_s function (p: 592-593)
  • K.3.5.3.4 The scanf_s function (p: 594)
  • K.3.5.3.7 The sscanf_s function (p: 596)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.6.2 The fscanf function (p: 282-289)
  • 7.19.6.4 The scanf function (p: 290)
  • 7.19.6.7 The sscanf function (p: 291)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.6.2 The fscanf function
  • 4.9.6.4 The scanf function
  • 4.9.6.6 The sscanf function

参阅

vscanfvfscanfvsscanfvscanf_svfscanf_svsscanf_s (C99)(C99)(C99)(C11)(C11)(C11) | 从 stdin 、文件流或缓冲区读取格式化输入 使用可变参数列表 (函数)
fgets | 从文件流获取一个字符串 (函数)
printffprintfsprintfsnprintfprintf_sfprintf_ssprintf_ssnprintf_s (C99)(C11)(C11)(C11)(C11) | 打印格式化输出到 stdout 、文件流或缓冲区 (函数)


fseek

< c‎ | io
定义于头文件 <stdio.h>
int fseek( FILE *stream, long offset, int origin );

设置文件流 stream 的文件位置指示器为 offset 所指向的值。

若 stream 以二进制模式打开，则新位置准确地是文件起始后（若 origin 为 SEEK_SET ）或当前文件位置后（若 origin 为 SEEK_CUR ），或文件结尾后（若 origin 为 SEEK_END ）的 offset 字节。不要求二进制流支持 SEEK_END ，尤其是是否输出附加的空字节。

若 stream 以文本模式打开，则仅有的受支持 offset 值为零（可用于任何 origin ）和先前在关联到同一个文件的流上对 ftell 的调用的返回值（仅可用于 SEEK_SET 的 origin ）。

若 stream 为宽面向，则一同应用对文本和二进制流的限制（允许 ftell 的结果与 SEEK_SET 一同使用，并允许零 offset 以 SEEK_SET 和 SEEK_CUR 但非 SEEK_END 为基准）。

除了更改文件位置指示器， fseek 还撤销 ungetc 的效果并清除文件尾状态，若可应用。

若发生读或写错误，则设置流的错误指示器（ ferror ）而不影响文件位置。

参数

stream | - | 要修改的文件流
offset | - | 相对 origin 迁移的字符数
origin | - | offset 所加上的位置。它能拥有下列值之一： SEEK_SET 、 SEEK_CUR 、 SEEK_END

返回值

成功时为 ​0​ ，否则为非零。

注解

在巡位到宽流的非结尾位置后，下个对任意输出函数的调用可能令剩下的文件内容未定义，例如通过输出一个长度不同的多字节序列。

对于文本流， offset 仅有的合法值是 ​0​ （可应用于任意 origin ）和先前 ftell 调用的返回值（仅可应用于 SEEK_SET ）。

POSIX 允许在文件尾之后巡位。若在此巡位后进行输出，则任何间隙中的读取将返回零字节。在文件系统支持的场合，这会创建一个稀疏文件。

POSIX 亦要求 fseek 先进行 fflush ，若有任何未写入数据（但是否恢复迁移状态是实现定义的）。

示例

fseek 带错误检查

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    // 准备浮点值的数组。
    #define SIZE 5
    double A[SIZE] = {1.,2.,3.,4.,5.};
    // 写入数组到文件。
    FILE * fp = fopen("test.bin", "wb");
    fwrite(A,sizeof(double),SIZE,fp);
    fclose (fp);

    // 读浮点值入数组 B。
    double B[SIZE];
    fp = fopen("test.bin","rb");

    // 设置文件位置指示器到第三个浮点值之前。
    if (fseek(fp,sizeof(double)*2L,SEEK_SET) != 0)
    {
       perror("fseek()");
       fprintf(stderr,"fseek() failed in file %s at line # %d\n", __FILE__,__LINE__-5);
       exit(EXIT_FAILURE);
    }

    int ret_code = fread(B,sizeof(double),1,fp);   // 读取一个浮点值
    printf("%.1f\n", B[0]);                        // 打印一个浮点值

    fclose(fp);
    return EXIT_SUCCESS;
}

输出：

3.0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.9.2 The fseek function (p: 336-337)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.9.2 The fseek function (p: 302-303)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.9.2 The fseek function

参阅

fsetpos | 将文件位置指示器移动到文件中的指定位置 (函数)
fgetpos | 获取文件位置指示器 (函数)
ftell | 返回当前的文件位置指示值 (函数)
rewind | 将文件位置指示器移动到文件首 (函数)


fsetpos

< c‎ | io
定义于头文件 <stdio.h>
int fsetpos( FILE *stream, const fpos_t *pos );

按照 pos 所指向的值，设置文件流 stream 的文件位置指示器和多字节分析状态（若存在）。

除了建立新的分析状态和位置，调用此函数还会撤销 ungetc 的效果，并若设置了文件尾状态则清除之。

若读或写出现错误，则设置流的错误指示器（ ferror ）。

参数

stream | - | 要修改的文件流
pos | - | 指向 fpos_t 对象的指针，用作文件位置指示器的新值

返回值

成功时为 ​0​ ，否则为非零值。

注意

在寻位到宽流的非结尾位置后，下个对任何输出函数的调用可能使剩下的文件内容未定义，例如通过输出不同长度的多字节序列。

示例

fsetpos 带错误检查

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    /* 准备一个浮点值的数组。 */
    #define SIZE 5
    double A[SIZE] = {1.,2.,3.,4.,5.};
    /* 写数组到文件。 */
    FILE * fp = fopen("test.bin", "wb");
    fwrite(A,sizeof(double),SIZE,fp);
    fclose (fp);

    /* 读取浮点值到数组B。 */
    double B[SIZE];
    fp = fopen("test.bin","rb");
    fpos_t pos;
    if (fgetpos(fp,&pos) != 0)      /* 当前位置：文件起始 */
    {
       perror("fgetpos()");
       fprintf(stderr,"fgetpos() failed in file %s at line # %d\n", __FILE__,__LINE__-3);
       exit(EXIT_FAILURE);
    }

    int ret_code = fread(B,sizeof(double),1,fp);   /* 读取一个浮点值 */
    /* 当前位置：在读一个浮点值后 */
    printf("%.1f\n", B[0]);   /* 打印一个浮点值 */

    if (fsetpos(fp,&pos) != 0)   /* 重设当前位置为文件起始 */
    {
       if (ferror(fp))
       {
          perror("fsetpos()");
          fprintf(stderr,"fsetpos() failed in file %s at line # %d\n", __FILE__,__LINE__-5);
          exit(EXIT_FAILURE);
       }
    }

    ret_code = fread(B,sizeof(double),1,fp);   /* 重读首个浮点值 */
    printf("%.1f\n", B[0]);                    /* 打印一个浮点值 */
    fclose(fp);

    return EXIT_SUCCESS;
}

输出：

1.0
1.0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.9.3 The fsetpos function (p: 337)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.9.3 The fsetpos function (p: 303)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.9.3 The fsetpos function

参阅

fgetpos | 获取文件位置指示器 (函数)
ftell | 返回当前的文件位置指示值 (函数)
fseek | 将文件位置指示符移动到文件中的指定位置 (函数)


ftell

< c‎ | io
定义于头文件 <stdio.h>
long ftell( FILE *stream );

返回流 stream 的文件位置指示器。

若流以二进制模式打开，则由此函数获得的值是从文件开始的字节数。

若流以文本模式打开，则由此函数返回的值未指定，且仅若作为 fseek() 的输入才有意义。

参数

stream - 要检验的文件流

返回值

成功时为文件位置指示器，若失败发生则为 -1L 。

失败时，设 errno 对象为实现定义的正值。

示例

ftell带错误检查

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    /* 准备浮点值的数组。 */
    #define SIZE 5
    double A[SIZE] = {1.,2.,3.,4.,5.};
    /* 写数组到文件。 */
    FILE * fp = fopen("test.bin", "wb");
    fwrite(A,sizeof(double),SIZE,fp);
    fclose (fp);

    /* 读取浮点值到数组 B。 */
    double B[SIZE];
    fp = fopen("test.bin","rb");
    long int pos = ftell(fp);   /* 位置指示器在文件起始 */
    if (pos == -1L)
    {
       perror("ftell()");
       fprintf(stderr,"ftell() failed in file %s at line # %d\n", __FILE__,__LINE__-4);
       exit(EXIT_FAILURE);
    }
    printf("%ld\n", pos);

    int ret_code = fread(B,sizeof(double),1,fp);   /* 读取一个浮点值 */
    pos = ftell(fp);   /* 读取一个浮点值后的位置指示器 */
    if (pos == -1L)
    {
       perror("ftell()");
       fprintf(stderr,"ftell() failed in file %s at line # %d\n", __FILE__,__LINE__-4);
       exit(EXIT_FAILURE);
    }
    printf("%ld\n", pos);
    printf("%.1f\n", B[0]);   /* 打印浮点值 */

    return EXIT_SUCCESS;
}

输出：

0
8
1.0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.9.4 The ftell function (p: 337-338)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.9.4 The ftell function (p: 303-304)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.9.4 The ftell function

参阅

fgetpos | 获取文件位置指示器 (函数)
fseek | 将文件位置指示符移动到文件中的指定位置 (函数)
fsetpos | 将文件位置指示器移动到文件中的指定位置 (函数)


fwide

< c‎ | io
定义于头文件 <wchar.h> |
int fwide( FILE *stream, int mode ); | (C95 起)

若 mode > 0 ，则试图令 stream 为宽面向。若 mode < 0 ，则试图令 stream 为字节面向。若 mode==0 ，则只查询流的当前面向。

若流的当前面向已决定（通过执行输出或通过之前调用 fwide ），则此函数不做任何事。

参数

stream | - | 指向修改或查询的 C I/O 流的指针
mode | - | 大于零的整数值设置流为宽，小于零的整数值设置流为窄，零为仅查询

返回值

若流在此调用后为面向宽，则为大于零的整数，若流在此调用后为面向字节，则为小于零的整数，若流无面向，则为零。

示例

下列代码设置并重置流面向。

#include <wchar.h>
#include <stdio.h>
#include <stdlib.h>
void try_read(FILE* fp)
{
    int c = fgetc(fp);
    if(c == EOF) puts("narrow character read failed");
    else printf("narrow character read '%c'\n", c);

    wint_t wc = fgetwc(fp);
    if(wc == WEOF) puts("wide character read failed");
    else printf("wide character read '%lc'\n", wc);
}
void show(int n)
{
    if(n == 0) puts("no orientation");
    else if (n < 0) puts("narrow orientation");
    else puts("wide orientation");
}
int main(void)
{
    FILE* fp = fopen("main.cpp","r");
    if (!fp) {
        perror("fopen() failed");
        return EXIT_FAILURE;
    }

    // 新开的流无面向。
    show(fwide(fp, 0));

    // 建立面向字节。
    show(fwide(fp, -1));
    try_read(fp);

    // 只有freopen()能重置流面向。
    if (freopen("main.cpp","r",fp) == NULL)
    {
       perror("freopen() failed");
       return EXIT_FAILURE;
    }

    // 重开的流无面向。
    show(fwide(fp, 0));

    // 建立面向宽。
    show(fwide(fp, 1));
    try_read(fp);

    fclose(fp);
}

可能的输出：

no orientation
narrow orientation
narrow character read '#'
wide character read failed
no orientation
wide orientation
narrow character read failed
wide character read '#'

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.3.5 The fwide function (p: 423)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.3.5 The fwide function (p: 369)

参阅

fopenfopen_s
(C11)
 打开文件
(函数)


wprintf, fwprintf, swprintf, wprintf_s, fwprintf_s, swprintf_s, snwprintf_s

< c‎ | io
定义于头文件 <wchar.h> |  |
 | (1) |
int wprintf( const wchar_t *format, ... ); |  |  | (C95 起) (C99 前)
int wprintf( const wchar_t *restrict format, ... ); |  |  | (C99 起)
 | (2) |
int fwprintf( FILE *stream, const wchar_t* format, ... ); |  |  | (C95 起) (C99 前)
int fwprintf( FILE *restrict stream, const wchar_t *restrict format, ... ); |  |  | (C99 起)
 | (3) |
int swprintf( wchar_t *buffer, size_t bufsz, const wchar_t* format, ... ); |  |  | (C95 起) (C99 前)
int swprintf( wchar_t *restrict buffer, size_t bufsz, const wchar_t *restrict format, ... ); |  |  | (C99 起)
int wprintf_s( const wchar_t *restrict format, ...); | (4) | (C11 起)
int fwprintf_s( FILE *restrict stream, const wchar_t *restrict format, ...); | (5) | (C11 起)
int swprintf_s( wchar_t *restrict buffer, rsize_t bufsz, const wchar_t* restrict format, ...); | (6) | (C11 起)
int snwprintf_s( wchar_t * restrict s, rsize_t n, const wchar_t * restrict format, ...); | (7) | (C11 起)

从给定位置加载数据，将它们转换成宽字符串等价物并将结果写入各种池中。

1) 写结果到 stdout 。
2) 写结果到文件流 stream 。
3) 若bufsz大于零，则写结果到宽字符串buffer。至多允许写入后随空宽字符的bufsz-1个宽字符。若bufsz为零，则不写入任何内容（且buffer可以是空指针）然而返回值（会被写入的宽字符数）被照样计算并返回。
4-6) 同 (1-3) ，除了在运行时检测下列错误，并调用当前安装的制约处理函数：
  • format 中存在转换指定符 %n
  • 任何一个对应 %s 的参数是空指针
  • format 或 buffer 是空指针
  • bufsz 为零或大于 RSIZE_MAX
  • 任何一个字符串及字符转换指定符中出现编码错误
  • （仅对于 swprintf_s ）会写入的宽字符数含空宽字符，将超出 bufsz 。
同所有边界检查函数， wprintf_s, fwprintf_s, swprintf_s, snwprintf_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <wchar.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

stream - 要写入的输出文件流
buffer - 指向要写入的宽字符串的指针
bufsz - 最多会写入 bufsz - 1 个宽字符，再加空终止符
format - 指向指定数据转译方式的空终止宽字符串的指针。

格式字符串由普通宽字符（除了 % ）和转换指定构成，前者被复制到输出流而无更改。每个转换指定拥有下列格式：

  • 引入的 % 字符
  • (可选)一或多个修改转换行为的标签：
  • - ：转换结果在域内左校正（默认为右校正）
  • + ：有符号转换的符号始终前置于转换结果（默认结果前置负号仅当它为负）
  • 空格：若有符号转换的结果不以符号开始，或为空，则前置空格于结果。若存在 + 标签则忽略空格。
  • # ：进行替用形式的转换。准确的效果见下表，其他情况下行为未定义。
  • 0 ：对于整数和浮点数转换，使用前导零代替空格字符填充域。对于整数，若显式指定精度，则忽略此标签。对于其他转换，使用此标签导致未定义行为。若存在 - 标签则忽略 0 。
  • (可选)指定最小域宽的整数值或 * 。若有要求，则结果会以空格字符（默认情况）填充，在右校正时于左，左校正时于右。使用 * 的情况下，以一个额外的 int 类型参数指定宽度。若参数值为负数，则它导致指定 - 标签和正域宽。（注意：这是最小宽度：决不被截断值）。
  • (可选)后随整数或 * 或两者皆无的 . 指示转换的精度。在使用 * 的情况下，精度由额外的 int 类型参数指定。若此参数的值为负数，则它被忽略。若既不使用数字亦不使用 * ，则精度采用零。精度的准确效果见下表。
  • (可选)指定参数大小的长度修饰符
  • 转换格式指定符

下列格式指定符可用：

转换
指定符 		解释 参数类型
长度修饰符 hh

(C99)

 h （无） l ll

(C99)

 j

(C99)

 z

(C99)

 t

(C99)

 L
% 写字面的 % 。完整转换指定必须是 %% 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
写单个字符。

参数首先被转换成 wchar_t ，如同通过调用 btowc 。 若使用 l 修饰符，则 wint_t 参数首先被转换成 wchar_t 。

 N/A N/A
int
wint_t
 N/A N/A N/A N/A N/A
s
写字符串

参数必须为一个指针，指向包含以初始迁移状态开始的，多字节字符序列的字符数组首元素，数组会被转换成宽字符数组，如同通过以零初始化转换状态调用 mbrtowc 。 精度指定写入的最大宽字符数。若未指定精度，则写每个宽字符直到而不含首个空终止符。 若使用 l 指定符，则参数必须是指向 wchar_t 数组首元素的指针。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
d
i
转换有符号整数为十进制表示 [-]dddd 。

精度指定出现的最小数位数。默认精度是 1 。
若被转换的值和精度都是 ​0​ ，则转换结果无字符。
signed char
short
int
long
long long
intmax_t
有符号 size_t
ptrdiff_t
 N/A
o
转换无符号整数为八进制表示 oooo 。

精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中精度按需增加，以写入一个前导零。 在此情况下若被转换值和精度都是 ​0​ ，则写入单个 ​0​ 。
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
uintmax_t
size_t
ptrdiff_t 的无符号版本
 N/A
x
X
转换无符号整数为十六进制表示 hhhh 。

x 转换使用字母 abcdef 。
X 转换使用 ABCDEF 。
精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中若被转换值为非零则结果有 0x 或 0X 前缀。

 N/A
u
转换无符号整数为十进制表示 dddd 。

精度指定出现的最小数位数。 默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。

 N/A
f
F
转换浮点数为 [-]ddd.ddd 样式的十进制记法。

精度指定小数点字符后出现的准确数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A
double
double (C99)
 N/A N/A N/A N/A
long double
e
E
转换浮点数为十进制指数记法。

e 转换样式使用 [-]d.ddd e±dd 。
E 转换样式使用 [-]d.ddd E±dd 。
指数至少含二个数位，仅当所需时使用更多数位。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
a
A

(C99)
转换浮点数为十六进制记法。

a 转换样式使用 [-]0x h.hhh p±d 。
A 转换样式使用 [-]0X h.hhh P±d 。
若参数是正规化的浮点值，则首个十六进制数位非 0 。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度足以准确表示该值。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
g
G
转换浮点数为十进制小数或十进制指数记法，依赖于值和精度。

g 转换样式将进行带样式 e 或 f 的转换。
G 转换样式将进行带样式 E 或 F 的转换。
令 P 等于精度，若它非零，若精度未指定则为 6 ，若精度为 ​0​ 则等于 1 。然后，若带样式 E 的转换会有指数 X ，则：

  • 若 P > X ≥ −4 ，则转换带 f 或 F 风格，及精度 P − 1 − X 。
  • 否则，转换带 e 或 E 风格，及精度 P − 1 。

除非要求替用表示，否则末尾零会被移除，且若不留下小数部分则小数点亦被移除。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
n
返回对函数的此调用迄今为止写入的字符数。

结果被写入到参数所指向的值。 该指定不可含有任何标签、域宽或精度。
signed char*
short*
int*
long*
long long*
intmax_t *
有符号 size_t *
ptrdiff_t *
 N/A
p 写定义指针的实现定义字符序列。 N/A N/A void* N/A N/A N/A N/A N/A N/A

浮点转换函数转换无穷大到 inf 或 infinity 。使用哪个是实现定义的。

非数转换成 nan 或 nan(char_sequence) 。使用哪个是实现定义的。

转换 F 、 E 、 G 、 A 替代上面输出 INF 、 INFINITY 、 NAN。

尽管 %c 期待 int 参数，传递 char 是安全的，因为在调用变参数函数时发生整数提升。

定宽整数类型（ int8_t 等）的正确转换指定定义于头文件 <inttypes.h> （尽管 PRIdMAX 、 PRIuMAX 等就是 %jd 、 %ju 等的别名）。

内存写入转换指定符 %n 是安全漏洞的常见目标，这里格式字符串依赖用户输入，而有边界检查的 printf_s 系列函数不支持此转换指定符。

在每个转换指定符的行动后有一个序列点；这允许于同一变量多次存入 %n 的结果，并在同一此调用中打印出先前以 %n 存储的值。

若转换指定非法，则行为未定义。
... - 指定要打印数据的参数。若任何参数在默认参数提升后不拥有对应转换指定符所期待的类型，或若参数少于 format 所要求的数量，则行为未定义。若有多于 format 所要求的参数，则求值并忽略额外参数

返回值

1,2) 若成功则为写入的宽字符数，若错误发生则为负值。
3) 若成功则为写入的宽字符数（不计空终止宽字符），若编码错误发生或被生成的宽字符数等于或大于 size （含 size 为零时）则为负值。
4,5) 若成功则为写入的宽字符数，若错误发生则为负值。
6) 写入 buffer 的宽字符数（不计空终止符）。编码错误发生和溢出时返回负值。所有其他错误发生时返回零。
7) 假如 bufsz 充分大则本应写入 buffer 的宽字符数（不计空终止符），或者若错误发生则为负值。（即写入成功仅当返回值非负且小于 bufsz ）。

注意

窄字符串提供 snprintf ，它使得确定需求的缓冲区大小可行，不过宽字符串无等价物（在 C11 的 snwprintf_s 前），而为了确定缓冲区大小，程序可能需要调用 swprintf ，检查返回值，并重分配更大的缓冲区，反复尝试直至成功。

不同于 swprintf_s ， snwprintf_s 将截断结果以适应 buffer 所指向的数组，尽管这种截断被多数边界检查函数当做错误。

示例

#include <locale.h>
#include <wchar.h>

int main(void)
{
    char narrow_str[] = "z\u00df\u6c34\U0001f34c";
                    // 或 "zß水🍌"
                    // 或 "\x7a\xc3\x9f\xe6\xb0\xb4\xf0\x9f\x8d\x8c";
    wchar_t warr[29]; // 期待的字符串为 28 字节加 1 个空终止符
    setlocale(LC_ALL, "en_US.utf8");
    swprintf(warr, sizeof warr/sizeof *warr,
              L"Converted from UTF-8: '%s'", narrow_str);
    wprintf(L"%ls\n", warr);
}

输出：

Converted from UTF-8: 'zß水🍌'

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.2.1 The fwprintf function (p: 403-410)
  • 7.29.2.3 The swprintf function (p: 416)
  • 7.29.2.11 The wprintf function (p: 421)
  • K.3.9.1.1 The fwprintf_s function (p: 628)
  • K.3.9.1.4 The swprintf_s function (p: 630-631)
  • K.3.9.1.13 The wprintf_s function (p: 637-638)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.2.1 The fwprintf function (p: 349-356)
  • 7.24.2.3 The swprintf function (p: 362)
  • 7.24.2.11 The wprintf function (p: 366)

参阅

printffprintfsprintfsnprintfprintf_sfprintf_ssprintf_ssnprintf_s (C99)(C11)(C11)(C11)(C11) | 打印格式化输出到 stdout 、文件流或缓冲区 (函数)
vwprintfvfwprintfvswprintfvwprintf_svfwprintf_svswprintf_svsnwprintf_s (C95)(C95)(C95)(C11)(C11)(C11)(C11) | 打印格式化宽字符输出到 stdout 、文件流或缓冲区 使用可变参数列表 (函数)
fputws (C95) | 将一个宽字符串写入文件流 (函数)


fwrite

< c‎ | io
定义于头文件 <stdio.h> |
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream ); | (C99 前)
size_t fwrite( const void *restrict buffer, size_t size, size_t count, FILE *restrict stream ); | (C99 起)

写 count 个来自给定数组 buffer 的对象到输出流stream。如同转译每个对象为 unsigned char 数组，并对每个对象调用 size 次 fputc 以将那些 unsigned char 按顺序写入 stream 一般写入。文件位置指示器前进写入的字节数。

参数

buffer | - | 指向数组中要被写入的首个对象的指针
size | - | 每个对象的大小
count | - | 要被写入的对象数
stream | - | 指向输出流的指针

返回值

成功写入的对象数，若错误发生则可能小于 count 。

若 size 或 count 为零，则 fwrite 返回零并不进行其他行动。

示例

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
enum { SIZE = 5 };
int main(void)
{
    double a[SIZE] = {1, 2, 3, 4, 5};
    FILE *f1 = fopen("file.bin", "wb");
    assert(f1);
    size_t r1 = fwrite(a, sizeof a[0], SIZE, f1);
    printf("wrote %zu elements out of %d requested\n", r1,  SIZE);
    fclose(f1);

    double b[SIZE];
    FILE *f2 = fopen("file.bin", "rb");
    size_t r2 = fread(b, sizeof b[0], SIZE, f2);
    fclose(f2);
    printf("read back: ");
    for(size_t i = 0; i < r2; i++)
        printf("%0.2f ", b[i]);
}

输出：

wrote 5 elements out of 5 requested
read back: 1.00 2.00 3.00 4.00 5.00

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.8.2 The fwrite function (p: 335-336)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.8.2 The fwrite function (p: 301-302)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.8.2 The fwrite function

参阅

printffprintfsprintfsnprintfprintf_sfprintf_ssprintf_ssnprintf_s (C99)(C11)(C11)(C11)(C11) | 打印格式化输出到 stdout 、文件流或缓冲区 (函数)
fputs | 将一个字符串写入文件流 (函数)
fread | 从文件读取 (函数)


wscanf, fwscanf, swscanf, wscanf_s, fwscanf_s, swscanf_s

< c‎ | io
定义于头文件 <wchar.h> |  |
 | (1) |
int wscanf( const wchar_t *format, ... ); |  |  | (C95 起) (C99 前)
int wscanf( const wchar_t *restrict format, ... ); |  |  | (C99 起)
 | (2) |
int fwscanf( FILE *stream, const wchar_t *format, ... ); |  |  | (C95 起) (C99 前)
int fwscanf( FILE *restrict stream, const wchar_t *restrict format, ... ); |  |  | (C99 起)
 | (3) |
int swscanf( const wchar_t *buffer, const wchar_t *format, ... ); |  |  | (C95 起) (C99 前)
int swscanf( const wchar_t *restrict buffer, const wchar_t *restrict format, ... ); |  |  | (C99 起)
int wscanf_s( const wchar_t *restrict format, ...); | (4) | (C11 起)
int fwscanf_s( FILE *restrict stream, const wchar_t *restrict format, ...); | (5) | (C11 起)
int swscanf_s( const wchar_t *restrict s, const wchar_t *restrict format, ...); | (6) | (C11 起)

从各种资源读取数据，按照 format 转译，并存储结果于给定位置。

1) 从 stdin 读取数据。
2) 从文件流 stream 读取数据。
3) 从空终止字符串 buffer 读取数据。抵达字符串结尾等价于 fwscanf 的抵达文件尾条件
4-6) 同 (1-3) ，除了 %c 、 %s 及 %[ 转换指定符要求二个参数（通常的指针和指示获取用数组大小的 rsize_t 类型值，以 %lc 读取单个宽字符时可以为 1 ），及在运行时检测下列错误，并调用当前安装的制约处理函数：
  • 任何指针类型的参数为空指针
  • format 、 stream 或 buffer 为空指针
  • %c 、 %s 或 %[ 要写入的字符数加上空终止字符，会超出提供给这些转换指定符的第二个（ rsize_t ）参数
  • 可选，任何其他可检测错误，例如未知转换指定符
同所有边界检查函数， wscanf_s, fwscanf_s , swscanf_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <wchar.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

stream - 要读取的输入文件流
buffer - 指向要读取的空终止宽字符串的指针
format - 指向指定读取输入方式的空终止宽字符串的指针。

格式字符串由下列内容组成

  • 非空白宽字符，除了 % ：每个格式字符串中的这种字符处理来自输入流的准确同一字符，或若它与流的下个字符比较不相等则导致函数失败。
  • 空白符：任何格式字符串中的单个空白符处理所有来自输入的可用连续空白符（如同通过于循环中调用 iswspace 确定）。注意格式字符串中 "\n" 、 " " 、 "\t\t" 或其他空白无区别。
  • 转换说明：每个转换说明拥有下列格式：
  • 引入用 % 字符
  • (可选)赋值抑制字符 * 。若存在此选项，则此函数不将结果赋值给任何接收用参数。
  • (可选)指定最大域宽的整数数字（大于零），即函数进行在当前转换说明所指定的转换时，允许处理的最大字符数。注意若不提供宽度，则 %s 和 %[ 可能导致缓冲区溢出。
  • (可选)指定接收参数大小的长度修饰符，即实际目标类型。这影响转换准确性和溢出规则。默认目标类型对每个转换类型不同（见下表）。
  • 转换格式说明符

下列格式说明符可用：

转换
说明符 		解释 参数类型
长度修饰符 →
 hh

(C99)

 h （无） l ll

(C99)

 j

(C99)

 z

(C99)

 t

(C99)

 L
% 匹配字面 % 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
匹配一个字符或字符的序列

若使用了宽度说明符，则匹配准确的宽度个宽字符（该参数必须是指向有充足空间的数组的指针）。不同于 %s 和 %[ ，它不会在数组后附加空字符。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
s
匹配非空白字符的序列（一个字符串）

若使用宽度说明符，则至多匹配宽度个字符，或匹配到首个提前出现的空白符前。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
[集合]
匹配一个来自 集合 的字符的非空字符序列。

若集合的首字符是 ^ ，则匹配所有不在集合中的字符。若集合以 ] 或 ^] 开始，则 ] 字符亦被包含入集合。在扫描集合的非最初位置的字符 - 是否可以指示范围，如 [0-9] ，是实现定义的。若使用宽度说明符，则最多匹配到宽度。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
d
匹配一个十进制整数。

该数的格式同 wcstol() 以值 10 为 base 时所期望者
signed char* 或 unsigned char*
signed short* 或 unsigned short*
signed int* 或 unsigned int*
signed long* 或 unsigned long*
signed long long* 或 unsigned long long*
intmax_t * 或 uintmax_t *
size_t *
ptrdiff_t *
 N/A
i
匹配一个整数。

该数的格式同 wcstol() 以值 ​0​ 为 base 时所期望者（基底以首个分析的字符确定）
u
匹配一个无符号十进制整数。

该数的格式同 wcstoul() 以值 10 为 base 参数时所期望者。
o
匹配一个无符号八进制数。

该数的格式同 wcstoul() 以值 8 为 base 参数时所期望者。
x, X
匹配一个无符号十六进制整数。

该数的格式同 wcstoul() 以值 16 为 base 参数时所期望者。
n
返回迄今读取的字符数。

不消耗输出。不增加赋值计数。若此说明符拥有赋值抑制运算符，则行为未定义。
a, A(C99)
e, E
f, F
g, G
匹配一个浮点数。

该数的格式同 wcstof() 所期望者。

 N/A N/A
float*
double*
 N/A N/A N/A N/A
long double*
p
匹配定义一个指针的实现定义的字符序列。

printf 系列函数应该用 %p 格式说明符产生同样的序列。

 N/A N/A
void**
 N/A N/A N/A N/A N/A N/A

对于每个异于 n 的转换说明符，不超过任何指定域宽，且要么是转换说明符所准确期待，要么是其所期待的前缀的最长输入字符序列，即是从流中消耗的内容。此消耗序列后的首个字符若存在，则保持未读取。若被消耗序列长度为零，或被消耗序列不能转换成上面所指定的项目，则发生匹配失败，除非遇到文件尾、编码错误，或阻止从流输入的读取错误，此情况下此为输入失败。

所有异于 [ 、 c 和 n 的转换说明符，在尝试分析输入前消耗并舍弃所有前导空白字符（如同以调用 iswspace 来确定）。这些被消耗的字符不计入指定的最大域宽。

若不使用长度说明符 l ，则转换说明符 c 、 s 和 [ 进行宽到到多字节字符转换，如同在转换首字符前，通过用初始化到零的 mbstate_t 对象调用 wcrtomb() 。

转换说明符 s 与 [ 始终在匹配字符之后存储一个空字符。目标数组的大小必须至少比指定域宽大一。

定宽整数类型（ int8_t 等）的正确的转换说明定义于头文件 <inttypes.h> （虽然 SCNdMAX 、 SCNuMAX 等就是 %jd 、 %ju 等的别名）。

在每个转换说明符后有一个序列点；这允许存储多个域到同一“池”变量中。

在分析以无数字指数为结尾的不完整浮点值，如以转换说明符 %f 分析 "100er" 时，消耗序列 "100e" （可能为合法浮点数的最长前缀），并导致匹配错误（被消耗序列不能转换成浮点数），而留下 "r" 。某些既存实现不遵守此规则并回滚，通过消耗 "100" 而留下 "er" ，例如 glibc 漏洞 1765 。
... - 接收参数

返回值

1-3) 成功赋值的接收参数数量，若在赋值首个接收参数前出现读取失败，则为 EOF 。
4-6) 同 (1-3) ，除了若有运行时制约违规，则亦返回 EOF 。

示例

Example

#include <stdio.h>
#include <wchar.h>
#include <string.h>

#define NUM_VARS   3
#define ERR_READ   2
#define ERR_WRITE  3

int main(void) {
    wchar_t state[64];   // 州
    wchar_t capital[64]; // 首府（州的首府）
    unsigned int population = 0; // 人口
    int elevation = 0;           // 高程
    int age = 0;  // 已设立时间
    float pi = 0; // π（数学常数）
// 交互模式
#if INTERACTIVE_MODE
    // 下列英文释义：输入州名，已设立时间和 π（数学常数）
    wprintf(L"Enter state, age, and pi value: ");
    if (wscanf(L"%ls%d%f", state, &age, &pi) != NUM_VARS) {
        // 输入错误
        fprintf(stderr, "Error reading input.\n");
        return ERR_READ;
    }
#else
   // 下列英文释义：加利福尼亚州 170 3.141592
    wchar_t* input = L"California 170 3.141592";
    if (swscanf(input, L"%ls%d%f", state, &age, &pi) != NUM_VARS) {
        fprintf(stderr, "Error reading input.\n");
        return ERR_READ;
    }
#endif
    wprintf(L"State: %ls\nAge  : %d years\nPi   : %.5f\n\n", state, age, pi);

    FILE* fp = tmpfile();
    if (fp) {
        // 向临时文件写入数据
        // 下列英文释义：宽字符串内容：密西西比州 杰克逊首府 420000 807
        if (!fwprintf(fp, L"Mississippi Jackson 420000 807")) {
            fprintf(stderr, "Error writing to file.\n");
            fclose(fp);
            return ERR_WRITE;
        }
        // 倒回（rewind）文件指针
        rewind(fp);

        // 将数据读入到变量
        fwscanf(fp, L"%ls%ls%u%d", state, capital, &population, &elevation);
        // 下列英文释义：州名 首府 杰克逊人口 (2020年) 最大高程
        wprintf(L"State  : %ls\nCapital: %ls\nJackson population (in 2020): %u\n"
                L"Highest elevation: %dft\n",
                state, capital, population, elevation);
        fclose(fp);
    }
}

可能的输出：

State: California
Age  : 170 years
Pi   : 3.14159

State  : Mississippi
Capital: Jackson
Jackson population (in 2020): 420000
Highest elevation: 807ft

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.2.2 The fwscanf function (p: 410-416)
  • 7.29.2.4 The swscanf function (p: 417)
  • 7.29.2.12 The wscanf function (p: 421)
  • K.3.9.1.2 The fwscanf_s function (p: 628-629)
  • K.3.9.1.5 The swscanf_s function (p: 631)
  • K.3.9.1.14 The wscanf_s function (p: 638)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.2.2 The fwscanf function (p: 356-362)
  • 7.24.2.4 The swscanf function (p: 362)
  • 7.24.2.12 The wscanf function (p: 366-367)

参阅

vwscanfvfwscanfvswscanfvwscanf_svfwscanf_svswscanf_s
(C99)(C99)(C99)(C11)(C11)(C11)
 从stdin、文件流或缓冲区读取格式化宽字符输入
使用可变参数列表
(函数)


getchar

< c‎ | io
定义于头文件 <stdio.h>
int getchar(void);

从 stdin 读取下一个字符。

等价于 getc ( stdin ) 。

参数

（无）

返回值

成功时为获得的字符，失败时为 EOF 。

若失败由文件尾条件产生，则另外设置 stdin 上的文件尾指示器（见 feof() ）。若失败由某些其他错误产生，则设置 stdin 上的错误指示器（见 ferror() ）。

示例

getchar带错误检查

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int ch;
    while ((ch=getchar()) != EOF)   /* 从stdin读/打印"abcde" */
          printf("%c", ch);

    /* 测试抵达EOF的原因。 */
    if (feof(stdin))          /* 若因文件尾条件失败 */
       puts("End of file reached");
    else if (ferror(stdin))   /* 若因某些错误失败      */
         {
            perror("getchar()");
            fprintf(stderr,"getchar() failed in file %s at line # %d\n", __FILE__,__LINE__-9);
            exit(EXIT_FAILURE);
         }

    return EXIT_SUCCESS;
}

输出：

abcde
End of file reached

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.7.6 The getchar function (p: 332)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.7.6 The getchar function (p: 298)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.7.6 The getchar function

参阅

fgetcgetc
 从文件流获取一个字符
(函数)


gets, gets_s

< c‎ | io
定义于头文件 <stdio.h> |  |
char *gets( char *str ); | (1) | (C11 中移除)
char *gets_s( char *str, rsize_t n ); | (2) | (C11 起)
1) 从 stdin 读入 str 所指向的字符数组，直到发现换行符或出现文件尾。在读入数组的最后一个字符后立即写入空字符。换行符被舍弃，但不会存储于缓冲区中。
2) 从 stdin 读取字符直到发现换行符或出现文件尾。至多写入 n-1 个字符到 str 所指向的数组，并始终写入空终止字符（除非 str 是空指针）。若发现换行符，则忽略它并且不将它计入写入缓冲区的字符数。
在运行时检测下列错误并调用当前安装的制约处理函数：
  • n 为零
  • n 大于 RSIZE_MAX
  • str 是空指针
  • 在存储 n-1 个字符到缓冲区后没有遇到换行符或文件尾。}}
任何情况下，gets_s 首先结束读取并忽略来自 stdin 的字符，直到换行符、文件尾条件，或在调用制约处理前的读取错误。
同所有边界检查函数， gets_s 仅若实现定义 __STDC_LIB_EXT1__ 且用户在包含 stdio.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

str | - | 要被写入的字符串
n | - | char数组的最大长度

返回值

成功时为 str ，失败时为空指针。

若文件尾条件导致了失败，则附加设置 stdin 的文件尾指示器（见 feof() ）。若其他某些原因导致了失败，则设置 stdin 的错误指示器（见 ferror() ）。

注解

gets() 函数不进行边界检查，从而此函数对缓冲区溢出攻击极度脆弱。无法安全使用它（除非程序运行的环境限定能出现在 stdin 上的内容）。因此，此函数在 C99 的第三次勘误中被弃用，而在 C11 标准发布时被移除。推荐的替代品是 fgets() 和 gets_s() 。

绝对不要用 gets() 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • K.3.5.4.1 The gets_s function (p: 602-603)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.7.7 The gets function (p: 298)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.7.7 The gets function

参阅

scanffscanfsscanfscanf_sfscanf_ssscanf_s (C11)(C11)(C11) | 从stdin、文件流或缓冲区读取格式化输入 (函数)
fgets | 从文件流获取一个字符串 (函数)
fputs | 将一个字符串写入文件流 (函数)
getlinegetwlinegetdelimgetwdelim (动态内存 TR) | 从流读入至动态改变大小的缓冲区，直到分隔符/行尾 (函数)


getwchar

< c‎ | io
定义于头文件 <wchar.h> |
wint_t getwchar(void); | (C95 起)

从 stdin 读取下一个宽字符。

参数

（无）

返回值

获得的宽字符，或若错误发生或抵达文件尾则为 WEOF 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.3.7 The getwchar function (p: 424)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.3.7 The getwchar function (p: 369-370)

参阅

getchar | 从 stdin 读取一个字符 (函数)
fgetwcgetwc (C95) | 从文件流获取一个宽字符 (函数)


perror

< c‎ | io
定义于头文件 <stdio.h>
void perror( const char *s );

打印当前存储于系统变量 errno 的错误码到 stderr 。

通过连接下列组分构成描述：

  • s 所指向的空终止字节字符串的内容后随 ": " （除非 s 为空指针或 s 所指向字符为空字符）
  • 实现定义的，描述存储于 errno 的错误码的错误消息字符串后随 '\n' 。错误消息字符串等同于 strerror (errno) 的结果。

参数

s - 指向带解释消息的空终止字符串的指针

返回值

（无）

示例

#include <stdio.h>

int main(void)
{
    FILE *f = fopen("non_existent", "r");
    if (f == NULL) {
        perror("fopen() failed");
    } else {
        fclose(f);
    }
}

输出：

fopen() failed: No such file or directory

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.10.4 The perror function (p: 339)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.10.4 The perror function (p: 305)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.10.4 The perror function

参阅

strerrorstrerror_sstrerrorlen_s
(C11)(C11)
 返回给定错误码的文本版本
(函数)


putchar

< c‎ | io
定义于头文件 <stdio.h>
int putchar( int ch );

写字符 ch 到 stdout 。在内部，字符于写入前被转换到 unsigned char 。

等价于 putc (ch, stdout ) 。

参数

ch - 要被写入的字符

返回值

成功时返回写入的字符。

失败时返回 EOF 并设置 stdout 上的错误指示器（见 ferror() ）。

示例

putchar带错误检查

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int ret_code = 0;
    for (char c = 'a'; (ret_code != EOF) && (c != 'z'); c++)
        ret_code = putchar(c);

    /* 测试是否抵达 EOF 。 */
    if (ret_code == EOF)
       if (ferror(stdout))
       {
          fprintf(stderr,"putchar() failed in file %s at line # %d\n", __FILE__,__LINE__-6);
          perror("putchar()");
          exit(EXIT_FAILURE);
       }
    putchar('\n');

    // putchar 返回值不等于参数
    int r = 0x1070;
    printf("\n0x%x\n", r);
    r = putchar(r);
    printf("\n0x%x\n", r);
}

输出：

abcdefghijklmnopqrstuvwxy

0x1070
p
0x70

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.7.8 The putchar function (p: 333)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.7.9 The putchar function (p: 299)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.7.9 The putchar function

参阅

fputcputc
 将一个字符写入文件流
(函数)


puts

< c‎ | io
定义于头文件 <stdio.h>
int puts( const char *str );

写入每个来自空终止字符串 str 的字符及附加换行符 '\n' 到输出流 stdout ，如同以重复执行 putc 写入。

不写入来自 str 的空终止字符。

参数

str - 要写入的字符串

返回值

成功时返回非负值

失败时，返回 EOF 并设置 stdout 的错误指示器（见 ferror() ）。

注意

puts 函数后附一个换行字符到输出，而 fputs 不这么做。

不同的实现返回不同的非负数：一些返回最后写入的字符，一些返回写入的字符数（或若字符串长于 INT_MAX 则返回它），一些简单地返回非负常量。

在重定向 stdout 到文件时，导致 puts 失败的典型原因是用尽了文件系统的空间。

示例

#include <stdio.h>

int main(void)
{
    int rc = puts("Hello World");

    if (rc == EOF)
       perror("puts()"); // POSIX 要求设置 errno
}

输出：

Hello World

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.7.9 The puts function (p: 333)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.7.10 The puts function (p: 299)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.7.10 The puts function

参阅

fputs | 将一个字符串写入文件流 (函数)
printffprintfsprintfsnprintfprintf_sfprintf_ssprintf_ssnprintf_s (C99)(C11)(C11)(C11)(C11) | 打印格式化输出到 stdout 、文件流或缓冲区 (函数)


putwchar

< c‎ | io
定义于头文件 <wchar.h> |
wint_t putwchar( wchar_t ch ); | (C95 起)

写宽字符ch到stdout。

参数

ch - 要被写入的宽字符

返回值

成功时为ch，失败时为WEOF。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.3.9 The putwchar function (p: 425)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.3.9 The putwchar function (p: 370)

参阅

putchar | 将一个字符写入 stdout (函数)
fputwcputwc (C95) | 将一个宽字符写入文件流 (函数)


remove

< c‎ | io
定义于头文件 <stdio.h>
int remove( const char *fname );

删除 fname 所指向的字符串所标识的文件。

若文件为当前进程或另一进程打开，则此函数行为是实现定义的。具体而言， POSIX 系统解链接文件名，到最后一个运行的进程关闭该文件为止，即使这是最后一个到文件的硬链接也不回收文件系统空间。 Windows 不允许删除该文件。

参数

fname - 指向空终止字符串的指针，字符串含标识待删除文件的路径

返回值

成功时为 ​0​ ，错误时为非零值。

注意

POSIX 指定此函数行为的许多额外细节。

示例

#include <stdio.h>
int main(void)
{
    FILE* fp = fopen("file1.txt", "w"); // 创建文件
    if(!fp) { perror("file1.txt"); return 1; }
    puts("Created file1.txt");
    fclose(fp);

    int rc = remove("file1.txt");
    if(rc) { perror("remove"); return 1; }
    puts("Removed file1.txt");

    fp = fopen("file1.txt", "r"); // 错误：文件不存在
    if(!fp) perror("Opening removed file failed");

    rc = remove("file1.txt"); // 错误：文件不存在
    if(rc) perror("Double-remove failed");
}

输出：

Created file1.txt
Removed file1.txt
Opening removed file failed: No such file or directory
Double-remove failed: No such file or directory

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.4.1 The remove function (p: 302)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.4.1 The remove function (p: 268)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.4.1 The remove function

参阅

rename
 重命名文件
(函数)


rename

< c‎ | io
定义于头文件 <stdio.h>
int rename( const char *old_filename, const char *new_filename );

更改文件的文件名。该文件以 old_filename 所指向的字符串标识。新文件名以 new_filename 所指向的字符串标识。

若 new_filename 存在，则行为是实现定义的。

参数

old_filename | - | 指向包含标识要重命名的文件的路径的空终止字符串的指针
new_filename | - | 指向包含文件新路径的空终止字符串的指针

返回值

成功时为 ​0​ ，失败时为非零值。

注意

POSIX 指定许多关于此函数语义的附加细节。

示例

#include <stdio.h>
int main(void)
{
    FILE* fp = fopen("from.txt", "w"); // 创建文件 "from.txt"
    if(!fp) { perror("from.txt"); return 1; }
    fputc('a', fp); // 写入到 "from.txt"
    fclose(fp);

    int rc = rename("from.txt", "to.txt");
    if(rc) { perror("rename"); return 1; }

    fp = fopen("to.txt", "r");
    if(!fp) { perror("to.txt"); return 1; }
    printf("%c\n", fgetc(fp)); // 从 "to.txt" 读取
    fclose(fp);
}

输出：

a

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.4.2 The rename function (p: 302-303)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.4.2 The rename function (p: 268-269)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.4.2 The rename function

参阅

remove
 删除文件
(函数)


rewind

< c‎ | io
定义于头文件 <stdio.h>
void rewind( FILE *stream );

移动文件位置指示器到给定文件流的起始。

函数等价于 fseek (stream, 0, SEEK_SET ); ，除了它清除文件尾和错误指示器。

此函数丢弃任何来自先前对 ungetc 调用的效果。

参数

stream - 要修改的文件流

返回值

（无）

示例

此例演示如何读文件二次

#include <stdio.h>

char str[20];

int main(void)
{
    FILE *f;
    char ch;

    f = fopen("file.txt", "w");
    for (ch = '0'; ch <= '9'; ch++) {
        fputc(ch, f);
    }
    fclose(f);

    f = fopen("file.txt", "r");
    fread(str, 1, 10, f);
    puts(str);

    rewind(f);
    fread(str, 1, 10, f);
    puts(str);
    fclose(f);

    return 0;
}

输出：

0123456789
0123456789

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.9.5 The rewind function (p: 338)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.9.5 The rewind function (p: 304)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.9.5 The rewind function

参阅

fseek
 将文件位置指示符移动到文件中的指定位置
(函数)


setbuf

< c‎ | io
定义于头文件 <stdio.h> |
void setbuf( FILE *stream, char *buffer ); | (C99 前)
void setbuf( FILE *restrict stream, char *restrict buffer ); | (C99 起)

设置用于流操作的内部缓冲区。其长度至少应该为 BUFSIZ 个字符。

若 buffer 非空，则等价于 setvbuf (stream, buffer, _IOFBF, BUFSIZ ) 。

若 buffer 为空，则等价于 setvbuf (stream, NULL, _IONBF, 0) ，这会关闭缓冲。

参数

stream | - | 要设置缓冲区的文件流
buffer | - | 指向文件流所用的缓冲区的指针。若提供空指针，则关闭缓冲。

返回值

无。

注解

若 BUFSIZ 不是适合的缓冲区大小，则能用 setvbuf 更改它。

setvbuf 亦应当用于检测错误，因为 setbuf 不指示成功或失败。

此函数仅可在已将 stream 关联到打开的文件后，但要在任何其他操作（除了对 setbuf/setvbuf 的失败调用）前使用。

一个常见错误是设置 stdin 或 stdout 的缓冲区为生存期在程序终止前结束的数组：

int main(void) {
    char buf[BUFSIZ];
    setbuf(stdin, buf);
} // buf 的生存期结束，未定义行为

示例

setbuf 可用于禁用要求立即输出的流的缓冲。

#include <stdio.h>
#include <threads.h>

int main(void)
{
    setbuf(stdout, NULL); // 无缓冲的 stdout
    putchar('a'); // 若 stdout 无缓冲，则 'a' 立即出现
    thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); // 休眠 1 秒
    putchar('b');
}

输出：

ab

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.5.5 The setbuf function (p: 307-308)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.5.5 The setbuf function (p: 273)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.5.5 The setbuf function

参阅

setvbuf
 为文件流设置缓冲区和其大小
(函数)


setvbuf

< c‎ | io
定义于头文件 <stdio.h> |
int setvbuf( FILE * stream, char * buffer, int mode, size_t size ); | (C99 前)
int setvbuf( FILE *restrict stream, char *restrict buffer, int mode, size_t size ); | (C99 起)

以 mode 所指示值更改给定文件流 stream 的缓冲模式。另外，

  • 若 buffer 为空指针，则重设内部缓冲区大小为 size 。
  • 若 buffer 不是空指针，则指示流使用始于 buffer 而大小为 size 的用户提供缓冲区。必须在 buffer 所指向的数组的生存期结束前（用 fclose ）关闭流。成功调用 setvbuf 后，数组内容不确定，而任何使用它的尝试是未定义行为。

参数

stream - 要设置缓冲的文件流
buffer - 指向要使用的流缓冲区的指针，或若仅更改大小和模式则为空指针
mode - 使用的缓冲模式。它能是下列值之一：
_IOFBF | 全缓冲：当缓冲区为空时，从流读入数据。或者当缓冲区满时，向流写入数据。
_IOLBF | 行缓冲：每次从流中读入一行数据或向流中写入一行数据。
_IONBF | 无缓冲：直接从流中读入数据或直接向流中写入数据，缓冲设置无效。
size - 缓冲区的大小

返回值

成功时为 ​0​ ，失败时为非零。

注意

此函数仅可在已将 stream 关联到打开的文件后，但要在任何其他操作（除了对 setbuf/setvbuf 的失败调用）前使用。

不是所有 size 字节都需要用于缓冲：实际缓冲区大小通常向下取整到 2 的倍数、页面大小的倍数等。

多数实现上，行缓冲仅对终端输入流可用。

一个常见错误是设置 stdin 或 stdout 的缓冲区为生存期在程序终止前结束的数组：

int main(void) {
    char buf[BUFSIZ];
    setbuf(stdin, buf);
} // buf 的生存期结束，未定义行为

期待默认缓冲区大小 BUFSIZ 为实现上文件 I/O 的最高效缓冲区大小，但 POSIX fstat 经常提供更好的估计。

示例

在已知更好的大小时更改缓冲区大小的使用样例。

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

int main(void)
{
    FILE* fp = fopen("test.txt", "r");
    if(fp == NULL) {
       perror("fopen"); return 1;
    }

    struct stat stats;
    if(fstat(fileno(fp), &stats) == -1) { // 仅限 POSIX
        perror("fstat"); return 1;
    }

    printf("BUFSIZ is %d, but optimal block size is %ld\n", BUFSIZ, stats.st_blksize);
    if(setvbuf(fp, NULL, _IOFBF, stats.st_blksize) != 0) {
       perror("setvbuf failed"); // POSIX 版本设置 errno
       return 1;
    }

    int ch;
    while((ch=fgetc(fp)) != EOF); // 读整个文件：用 truss/strace 观察
                                  // 使用的 read(2) syscall

    fclose(fp);
}

可能的输出：

BUFSIZ is 8192, but optimal block size is 65536

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.5.6 The setvbuf function (p: 308)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.5.6 The setvbuf function (p: 273-274)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.5.6 The setvbuf function

参阅

setbuf
 为文件流设置缓冲区
(函数)


stdin, stdout, stderr

< c‎ | io
定义于头文件 <stdio.h> |
#define stdin /* implementation-defined */ | (1)
#define stdout /* implementation-defined */ | (2)
#define stderr /* implementation-defined */ | (3)

预定义三个文本流。这些流在程序启动时隐式打开，且为无面向。

1) 与标准输入流关联，用于读取约定的输入。程序启动时，该流为完全缓冲当且仅当能确定流不引用交互式设备。
2) 与标准输出流关联，用于写入约定的输出。程序启动时，该流为完全缓冲当且仅当能确定流不引用交互式设备。
3) 与标准错误流关联，用于写入诊断输出。程序启动时，该流不为完全缓冲。

何者组成交互式设备是实现定义的。

这些宏展开成 FILE * 类型表达式。

注解

尽管 POSIX 不强制， UNIX 约定是 stdin 与 stdout 若与终端关联则为行缓冲，而 stderr 为无缓冲。

这些宏可能展开成可修改左值。若修改任何这些 FILE * 左值，则对应的流上的后续操作导致未指明或未定义行为。

示例

此示例展示等价于 printf 的函数。

#include <stdarg.h>
#include <stdio.h>

int my_printf(const char * restrict fmt, ...)
{
    va_list vl;
    va_start(vl, fmt);
    int ret = vfprintf(stdout, fmt, vl);
    va_end(vl);
    return ret;
}

int main(void)
{
    my_printf("Rounding:\t%f %.0f %.32f\n", 1.5, 1.5, 1.3);
    my_printf("Padding:\t%05.2f %.2f %5.2f\n", 1.5, 1.5, 1.5);
    my_printf("Scientific:\t%E %e\n", 1.5, 1.5);
    my_printf("Hexadecimal:\t%a %A\n", 1.5, 1.5);
}

可能的输出：

Rounding:       1.500000 2 1.30000000000000004440892098500626
Padding:        01.50 1.50  1.50
Scientific:     1.500000E+00 1.500000e+00
Hexadecimal:    0x1.8p+0 0X1.8P+0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.1 Introduction (p: 296-298)
  • 7.21.2 Streams (p: 298-299)
  • 7.21.2 Files (p: 300-302)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.1 Introduction (p: 262-264)
  • 7.19.2 Streams (p: 264-265)
  • 7.19.2 Files (p: 266-268)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.1 Introduction
  • 4.9.2 Streams
  • 4.9.3 Files

参阅


tmpfile, tmpfile_s

< c‎ | io
定义于头文件 <stdio.h> |  |
FILE *tmpfile(void); | (1) |
errno_t tmpfile_s( FILE * restrict * restrict streamptr); | (2) | (C11 起)
1) 创建并打开一个临时文件。该文件作为二进制文件、更新模式（如同为 fopen 以 "wb+" 模式）打开。该文件的文件名保证在文件系统中唯一。至少可以在程序的生存期内能打开 TMP_MAX 个文件（此极限可能与 tmpnam 共享，并可能为 FOPEN_MAX 所进一步限制）。
2) 同 (1) ，除了至少可以打开 TMP_MAX_S 个文件（此极限可能与 tmpnam_s 共享），而若 streamptr 为空指针，则调用当前安装的制约处理函数。
同所有边界检查函数， tmpfile_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <stdio.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

此函数创建的临时文件在程序正常退出时被关闭并删除。它在程序异常终止时是否被删除是实现定义的。

参数

1) （无）
2) 指向此函数调用将要更新的指针的指针

返回值

1) 指向与文件关联的文件流的指针，或若出现错误则为空指针。
2) 若成功创建并打开文件则为零，若未创建或打开文件，或若 streamptr 为空指针则为非零。另外，成功时存储指向关联文件流的指针到 *streamptr ，而错误时存储空指针值到 *streamptr 。

注解

一些实现（如 Linux ）上，此函数确实从文件系统上创建、打开并立即删除该文件：只要被删除文件的文件开启描述符为程序所管理，该文件就会存在，但只要它被删除，其名就不会出现于任何目录中，从而再无其他进程能打开它。一旦文件描述符被关闭，或一旦程序终止（正常或异常），该文件所占有的空间将被文件系统回收。

一些实现（如 Windows ）上要求提升的权限，因为该函数可能在系统目录中创建临时文件。

示例

#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#include <unistd.h>
int main(void)
{
    FILE* tmpf = tmpfile();
    fputs("Hello, world", tmpf);
    rewind(tmpf);
    char buf[6];
    fgets(buf, sizeof buf, tmpf);
    printf("got back from the file: '%s'\n", buf);

    // 展示临时文件名的 Linux 特定方法
    char fname[FILENAME_MAX], link[FILENAME_MAX] = {0};
    sprintf(fname, "/proc/self/fd/%d", fileno(tmpf));
    if(readlink(fname, link, sizeof link - 1) > 0)
        printf("File name: %s\n", link);
}

可能的输出：

got back from the file: 'Hello'
File name: /tmp/tmpfjptPe5 (deleted)

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.21.4.3 The tmpfile function (p: 222)
  • K.3.5.1.1 The tmpfile_s function (p: 427)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.4.3 The tmpfile function (p: 303)
  • K.3.5.1.1 The tmpfile_s function (p: 586-587)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.4.3 The tmpfile function (p: 269)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.4.3 The tmpfile function

参阅

tmpnamtmpnam_s
(C11)
 返回唯一的文件名
(函数)


tmpnam, tmpnam_s

< c‎ | io
定义于头文件 <stdio.h> |  |
char *tmpnam( char *filename ); | (1) |
errno_t tmpnam_s(char *filename_s, rsize_t maxsize); | (2) | (C11 起)
1) 创建独有的合法文件名（长度不长于 L_tmpnam ）并将它存储于 filename 所指向的字符串。此函数足以生成至多 TMP_MAX 个独有文件名，但它们中的一部分可能正在文件系统中使用，从而不适合作为返回值。
2) 同 (1) ，除了至多可以创建 TMP_MAX_S 个长度不长于 L_tmpnam_s 的文件名，而且在运行时检测下列错误，并调用当前安装的制约处理函数：
  • filename_s 是空指针
  • maxsize 大于 RSIZE_MAX
  • maxsize 小于生成文件名字符串的长度
同所有边界检查函数， tmpnam_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 stdio.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

tmpnam 和 tmpnam_s 修改静态状态（可能会在这些函数间共享），而且不要求是线程安全的。

参数

filename | - | 指向足以保有至少 L_tmpnam 字节的字符数组的指针，将以数组为结果缓冲区。若传递空指针，则返回指向内部静态缓冲区的指针。
filename_s | - | 指向足以保有至少 L_tmpnam_s 字节的字符数组的指针，将以数组为结果缓冲区。
maxsize | - | 允许函数写入的最大字节数（典型地为 filename_s 数组的大小）。

返回值

1) 若 filename 不是空指针则为 filename 。否则为指向内部静态缓冲区的指针。若不能生成适合的文件名，则返回空指针。
2) 成功时返回零并将文件名写入 filename_s 。失败时，返回非零并将空字符写入 filename_s[0] （仅若 filename_s 非空且 maxsize 非零且不大于 RSIZE_MAX ）。

注解

尽管 tmpnam 所生成的文件名难以猜测，却可能是另一个进程在 tmpnam 返回的时刻和此函程序试图使用返回的名称创建文件之间创建的文件的名称。标准函数 tmpfile 和 POSIX 函数 mkstemp 无此问题（仅使用 C 标准库创建一个独有的目录仍然要求使用 tmpnam ）。

POSIX 系统额外定义名称类似的函数 tempnam() ，它提供对目录的选择（默认是可选定义的宏 P_tmpdir ）。

示例

#include <stdio.h>
#include <string.h>

int main(void)
{
    char* name1 = tmpnam(NULL);
    printf("temporary file name: %s\n", name1);

    char name2[L_tmpnam];
    if (tmpnam(name2))
        printf("temporary file name: %s\n", name2);
}

可能的输出：

temporary file name: /tmp/fileRZHMwL
temporary file name: /tmp/file420gSN

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.4.4 The tmpnam function (p: 303-304)
  • K.3.5.1.2 The tmpnam_s function (p: 587-588)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.4.4 The tmpnam function (p: 269-270)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.4.4 The tmpnam function

参阅

tmpfiletmpfile_s
(C11)
 返回指向临时文件的指针
(函数)


ungetc

< c‎ | io
定义于头文件 <stdio.h>
int ungetc( int ch, FILE *stream );

若 ch 不等于 EOF ，则推入字符 ch （转译为 unsigned char ）到与流 stream 关联的输入缓冲区，方式满足从 stream 的后继读取操作将取得该字符。不修改与流关联的外部设备。

流重寻位操作 fseek 、 fsetpos 和 rewind 弃去 ungetc 的效果。

若调用 ungetc 多于一次，而无中间读取或重寻位，则可能失败（换言之，保证大小为 1 的回放缓冲区，但任何更大的缓冲区是实现定义的）。若成功进行多次 ungetc ，则读取操作以 ungetc 的逆序取得回放的字符。

若 ch 等于 EOF ，则操作失败而不影响流。

对 ungetc 的成功调用清除文件尾状态标志 feof 。

在二进制流上对 ungetc 的成功调用将流位置指示器减少一（若流位置指示器为零，则行为不确定）。

在文本流上对 ungetc 的成功调用以未指定方式修改流位置指示器，但保证在以读取操作取得所有回放字符后，流位置指示器等于其在 ungetc 之前的值。

参数

ch | - | 要推入输入流缓冲区的字符
stream | - | 要回放字符到的文件流

返回值

成功时返回 ch 。

失败时返回 EOF ，而给定的流保持不变。

注意

实践中，回放缓冲区的大小会在 4k （ Linux 、 MacOS ）和 4 （ Solaris ）或保证的最小值 1 （ HPUX 、 AIX ）间变化。

若回放的字符等于存在于外部字符序列中该位置的字符，则回放缓冲区的表观大小可以更大（实现可以简单地自减读取的文件位置指示器，并避免维护回放缓冲区）。

示例

展示 ungetc 的原目的：实现 scanf

#include <ctype.h>
#include <stdio.h>

void demo_scanf(const char* fmt, FILE* s) {
    if(*fmt == '%') {
        int c;
        switch(*++fmt) {
            case 'u': while(isspace(c=getc(s))) {} // 跳过空白符
                      unsigned int num = 0;
                      while(isdigit(c)) {
                          num = num*10 + c-'0';
                          c = getc(s);
                      }
                      printf("%%u scanned %u\n", num);
                      ungetc(c, s); // 重处理非数字
            case 'c': c = getc(s);
                      printf("%%c scanned '%c'\n", c);
        }
    }
}

int main(void)
{
    FILE* f = fopen("input.txt", "w+");
    fputs("123x", f);
    rewind(f);
    demo_scanf("%u%c", f);
    fclose(f);
}

输出：

%u scanned 123
%c scanned 'x'

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.7.10 The ungetc function (p: 334)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.7.11 The ungetc function (p: 300)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.7.11 The ungetc function

参阅

fgetcgetc
 从文件流获取一个字符
(函数)


ungetwc

< c‎ | io
定义于头文件 <wchar.h> |
wint_t ungetwc( wint_t ch, FILE *stream ); | (C95 起)

若 ch 不等于 WEOF ，则推入宽字符 ch 到与流 stream 关联的输入缓冲区，方式满足从 stream 的后继读取操作将取得该宽字符。不修改与流关联的外部设备。

流重寻位操作 fseek 、 fsetpos 和 rewind 弃去 ungetwc 的效果。

若调用 ungetwc 多于一次，而无中间读取或重寻位，则可能失败（换言之，保证大小为 1 的回放缓冲区，但任何更大的缓冲区是实现定义的）。若成功进行多次 ungetwc ，则读取操作以 ungetwc 的逆序取得回放的宽字符。

若 ch 等于 WEOF ，则操作失败而不影响流。

对 ungetwc 的成功调用清除文件尾状态标志 feof 。

在流（无论文本还是二进制）上对 ungetwc 的成功调用以未指定方式修改流位置指示器，但保证在以读取操作取得所有回放的宽字符后，流位置指示器等于其在 ungetwc 之前的值。

参数

ch | - | 要被回放的宽字符
stream | - | 要回放宽字符到的文件流

返回值

成功时返回 ch 。

失败时返回 WEOF ，而给定的流保持不变。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.3.10 The ungetwc function (p: 425-426)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.3.10 The ungetwc function (p: 370-371)

参阅

ungetc | 将一个字符送回文件流 (函数)
fgetwcgetwc (C95) | 从文件流获取一个宽字符 (函数)


vprintf, vfprintf, vsprintf, vsnprintf, vprintf_s, vfprintf_s, vsprintf_s, vsnprintf_s

< c‎ | io
定义于头文件 <stdio.h> |  |
 | (1) |
int vprintf( const char *format, va_list vlist ); |  |  | (C99 前)
int vprintf( const char *restrict format, va_list vlist ); |  |  | (C99 起)
 | (2) |
int vfprintf( FILE *stream, const char *format, va_list vlist ); |  |  | (C99 前)
int vfprintf( FILE *restrict stream, const char *restrict format, va_list vlist ); |  |  | (C99 起)
 | (3) |
int vsprintf( char *buffer, const char *format, va_list vlist ); |  |  | (C99 前)
int vsprintf( char *restrict buffer, const char *restrict format, va_list vlist ); |  |  | (C99 起)
int vsnprintf( char *restrict buffer, size_t bufsz, const char *restrict format, va_list vlist ); | (4) | (C99 起)
int vprintf_s( const char *restrict format, va_list arg); | (5) | (C11 起)
int vfprintf_s( FILE *restrict stream, const char *restrict format, va_list arg); | (6) | (C11 起)
int vsprintf_s( char *restrict buffer, rsize_t bufsz, const char *restrict format, va_list arg); | (7) | (C11 起)
int vsnprintf_s(char *restrict buffer, rsize_t bufsz, const char *restrict format, va_list arg); | (8) | (C11 起)

从 vlist 所定义的位置加载数据，将它们转换成字符串等价物，并将结果写入各种池。

1) 写结果到 stdout。
2) 写结果到文件流 stream 。
3) 写结果到字符串 buffer 。
4) 写结果到字符串 buffer 。至多写入 bufsz 个字符。产生的字符串将以空字符终止，除非 bufsz 为零。若 bufsz 为零，则不写入任何内容，且 buffer 可为空指针，然而照样计算并返回返回值（本应写入的字节数，不包含空终止符）。
5-8) 同 (1-4) ，除了在运行时检测下列错误，并调用当前安装的制约处理函数：
  • format 中存在转换说明符 %n
  • 任何一个对应 %s 的参数是空指针
  • format 或 buffer 是空指针
  • bufsz 为零或大于 RSIZE_MAX
  • 任何一个字符串及字符转换说明符中出现编码错误
  • （仅对于 vsprintf_s ）存储于 buffer 的字符串（包括尾随空字符）长度将超出 bufsz
同所有边界检查函数， vprintf_s, vfprintf_s, vsprintf_s, vsnprintf_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <stdio.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

stream - 要写入的输出文件流
buffer - 指向要写入的字符串的指针
bufsz - 至多可以写入 bufsz - 1 个字符，再加上空终止符
format - 指向指定数据转译方式的空终止字符串的指针。

格式字符串由普通多字节字符（除了 % ）和转换指定构成，前者被复制到输出流而无更改。每个转换指定拥有下列格式：

  • 引入的 % 字符
  • (可选)一或多个修改转换行为的标签：
  • - ：转换结果在域内左校正（默认为右校正）
  • + ：有符号转换的符号始终前置于转换结果（默认结果前置负号仅当它为负）
  • 空格：若有符号转换的结果不以符号开始，或为空，则前置空格于结果。若存在 + 标签则忽略空格。
  • # ：进行替用形式的转换。准确的效果见下表，其他情况下行为未定义。
  • 0 ：对于整数和浮点数转换，使用前导零代替空格字符填充域。对于整数，若显式指定精度，则忽略此标签。对于其他转换，使用此标签导致未定义行为。若存在 - 标签则忽略 0 。
  • (可选)指定最小域宽的整数值或 * 。若有要求，则结果会以空格字符（默认情况）填充，在右校正时于左，左校正时于右。使用 * 的情况下，以一个额外的 int 类型参数指定宽度。若参数值为负数，则它导致指定 - 标签和正域宽。（注意：这是最小宽度：决不被截断值）。
  • (可选)后随整数或 * 或两者皆无的 . 指示转换的精度。在使用 * 的情况下，精度由额外的 int 类型参数指定。若此参数的值为负数，则它被忽略。若既不使用数字亦不使用 * ，则精度采用零。精度的准确效果见下表。
  • (可选)指定参数大小的长度修饰符
  • 转换格式指定符

下列格式指定符可用：

转换
指定符 		解释 参数类型
长度修饰符 hh

(C99)

 h （无） l ll

(C99)

 j

(C99)

 z

(C99)

 t

(C99)

 L
% 写字面的 % 。完整转换指定必须是 %% 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
写单个字符。

参数首先被转换成 unsigned char 。 若使用 l 修饰符，则参数首先被转换成字符串，如同通过以 wchar_t[2] 参数使用 %ls 。

 N/A N/A
int
wint_t
 N/A N/A N/A N/A N/A
s
写字符串

参数必须是指向字符数组首元素的指针 精度指定写入最大的字符数。若未指定精度，则写每个字节直到而不含首个空终止符。 若使用 l 指定符，则参数必须是指向 wchar_t 数组首元素的指针，数组会被转换成 char 数组，如同通过以零初始化转换状态调用 wcrtomb 。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
d
i
转换有符号整数为十进制表示 [-]dddd 。

精度指定出现的最小数位数。默认精度是 1 。
若被转换的值和精度都是 ​0​ ，则转换结果无字符。
signed char
short
int
long
long long
intmax_t
有符号 size_t
ptrdiff_t
 N/A
o
转换无符号整数为八进制表示 oooo 。

精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中精度按需增加，以写入一个前导零。 在此情况下若被转换值和精度都是 ​0​ ，则写入单个 ​0​ 。
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
uintmax_t
size_t
ptrdiff_t 的无符号版本
 N/A
x
X
转换无符号整数为十六进制表示 hhhh 。

x 转换使用字母 abcdef 。
X 转换使用 ABCDEF 。
精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中若被转换值为非零则结果有 0x 或 0X 前缀。

 N/A
u
转换无符号整数为十进制表示 dddd 。

精度指定出现的最小数位数。 默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。

 N/A
f
F
转换浮点数为 [-]ddd.ddd 样式的十进制记法。

精度指定小数点字符后出现的准确数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A
double
double (C99)
 N/A N/A N/A N/A
long double
e
E
转换浮点数为十进制指数记法。

e 转换样式使用 [-]d.ddd e±dd 。
E 转换样式使用 [-]d.ddd E±dd 。
指数至少含二个数位，仅当所需时使用更多数位。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
a
A

(C99)
转换浮点数为十六进制记法。

a 转换样式使用 [-]0x h.hhh p±d 。
A 转换样式使用 [-]0X h.hhh P±d 。
若参数是正规化的浮点值，则首个十六进制数位非 0 。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度足以准确表示该值。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
g
G
转换浮点数为十进制小数或十进制指数记法，依赖于值和精度。

g 转换样式将进行带样式 e 或 f 的转换。
G 转换样式将进行带样式 E 或 F 的转换。
令 P 等于精度，若它非零，若精度未指定则为 6 ，若精度为 ​0​ 则等于 1 。然后，若带样式 E 的转换会有指数 X ，则：

  • 若 P > X ≥ −4 ，则转换带 f 或 F 风格，及精度 P − 1 − X 。
  • 否则，转换带 e 或 E 风格，及精度 P − 1 。

除非要求替用表示，否则末尾零会被移除，且若不留下小数部分则小数点亦被移除。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
n
返回对函数的此调用迄今为止写入的字符数。

结果被写入到参数所指向的值。 该指定不可含有任何标签、域宽或精度。
signed char*
short*
int*
long*
long long*
intmax_t *
有符号 size_t *
ptrdiff_t *
 N/A
p 写定义指针的实现定义字符序列。 N/A N/A void* N/A N/A N/A N/A N/A N/A

浮点转换函数转换无穷大到 inf 或 infinity 。使用哪个是实现定义的。

非数转换成 nan 或 nan(char_sequence) 。使用哪个是实现定义的。

转换 F 、 E 、 G 、 A 替代上面输出 INF 、 INFINITY 、 NAN。

尽管 %c 期待 int 参数，传递 char 是安全的，因为在调用变参数函数时发生整数提升。

定宽整数类型（ int8_t 等）的正确转换指定定义于头文件 <inttypes.h> （尽管 PRIdMAX 、 PRIuMAX 等就是 %jd 、 %ju 等的别名）。

内存写入转换指定符 %n 是安全漏洞的常见目标，这里格式字符串依赖用户输入，而有边界检查的 printf_s 系列函数不支持此转换指定符。

在每个转换指定符的行动后有一个序列点；这允许于同一变量多次存入 %n 的结果，并在同一此调用中打印出先前以 %n 存储的值。

若转换指定非法，则行为未定义。
vlist - 包含要打印数据的变量参数列表

返回值

1-3) 若成功则为写入的字符数，若出现错误则为负值。
4) 若成功则为写入的字符数，若出现错误则为负值。若产生的字符串因 bufsz 限制被截断，函数返回假如未强加限制则本应写入的字符数（不包含空终止字节）。
5,6) 传输到输出流的字符数，或若输出错误、运行时制约违规错误、编码错误发生则为负值。
7) 写入 buffer 的字符数，不计空字符（只要 buffer 不是空指针且 bufsz 非零且不大于 RSIZE_MAX ，就会写入它），运行时制约违规时为零，编码错误发生时为负值。
8) 不含空终止字符的（只要 buffer 不是空指针且 bufsz 非零且不大于 RSIZE_MAX ，就会写入它）假如忽略 bufsz 则本应写入 buffer 的字符数，或若出现运行时制约违规或编码错误为负值。

注解

所有这些函数调用 va_arg 至少一次，返回后 vlist 的值不确定。这些函数不调用 va_end ，而这必须由调用方进行。

不同于 vsprintf_s ， vsnprintf_s 将截断结果以适应 buffer 所指向的数组。

示例

#include <stdio.h>
#include <stdarg.h>
#include <time.h>

void debug_log(const char *fmt, ...)
{
    struct timespec ts;
    timespec_get(&ts, TIME_UTC);
    char time_buf[100];
    size_t rc = strftime(time_buf, sizeof time_buf, "%D %T", gmtime(&ts.tv_sec));
    snprintf(time_buf + rc, sizeof time_buf - rc, ".%06ld UTC", ts.tv_nsec / 1000);

    va_list args1;
    va_start(args1, fmt);
    va_list args2;
    va_copy(args2, args1);
    char buf[1+vsnprintf(NULL, 0, fmt, args1)];
    va_end(args1);
    vsnprintf(buf, sizeof buf, fmt, args2);
    va_end(args2);

    printf("%s [debug]: %s\n", time_buf, buf);
}

int main(void)
{
    debug_log("Logging, %d, %d, %d", 1, 2, 3);
}

可能的输出：

02/20/15 21:58:09.072683 UTC [debug]: Logging, 1, 2, 3

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.6.8 The vfprintf function (p: 326-327)
  • 7.21.6.10 The vprintf function (p: 328)
  • 7.21.6.12 The vsnprintf function (p: 329)
  • 7.21.6.13 The vsprintf function (p: 329)
  • K.3.5.3.8 The vfprintf_s function (p: 597)
  • K.3.5.3.10 The vprintf_s function (p: 598-599)
  • K.3.5.3.12 The vsnprintf_s function (p: 600)
  • K.3.5.3.13 The vsprintf_s function (p: 601)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.6.8 The vfprintf function (p: 292)
  • 7.19.6.10 The vprintf function (p: 293)
  • 7.19.6.12 The vsnprintf function (p: 294)
  • 7.19.6.13 The vsprintf function (p: 295)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.9.6.7 The vfprintf function
  • 4.9.6.8 The vprintf function
  • 4.9.6.9 The vsprintf function

参阅

vwprintfvfwprintfvswprintfvwprintf_svfwprintf_svswprintf_svsnwprintf_s (C95)(C95)(C95)(C11)(C11)(C11)(C11) | 打印格式化宽字符输出到 stdout 、文件流或缓冲区 使用可变参数列表 (函数)
printffprintfsprintfsnprintfprintf_sfprintf_ssprintf_ssnprintf_s (C99)(C11)(C11)(C11)(C11) | 打印格式化输出到 stdout 、文件流或缓冲区 (函数)
vscanfvfscanfvsscanfvscanf_svfscanf_svsscanf_s (C99)(C99)(C99)(C11)(C11)(C11) | 从 stdin 、文件流或缓冲区读取格式化输入 使用可变参数列表 (函数)


vscanf, vfscanf, vsscanf, vscanf_s, vfscanf_s, vsscanf_s

< c‎ | io
定义于头文件 <stdio.h> |  |
int vscanf( const char *restrict format, va_list vlist ); | (1) | (C99 起)
int vfscanf( FILE *restrict stream, const char *restrict format, va_list vlist ); | (2) | (C99 起)
int vsscanf( const char *restrict buffer, const char *restrict format, va_list vlist ); | (3) | (C99 起)
int vscanf_s(const char *restrict format, va_list vlist); | (4) | (C11 起)
int vfscanf_s( FILE *restrict stream, const char *restrict format, va_list vlist); | (5) | (C11 起)
int vsscanf_s( const char *restrict buffer, const char *restrict format, va_list vlist); | (6) | (C11 起)

从各种源读取数据，按照 format 转译并存储结果到 vlist 所定义的位置。

1) 从 stdin 读取数据。
2) 从文件流 stream 读取数据。
3) 从空终止字符串 buffer 读取数据。抵达字符串结尾等价于 vfscanf 的抵达文件尾条件
4-6) 同 (1-3) ，除了 %c 、 %s 及 %[ 转换指定符要求二个参数（通常的指针和指示获取用数组大小的 rsize_t 类型值，以 %c 读取单个字符时可以为 1 ），和在运行时检测下列错误，并调用当前安装的制约处理函数：
  • 任何指针类型参数为空指针
  • format 、 stream 或 buffer 为空指针
  • %c 、 %s 或 %[ 本会写入的字符数，加上空终止字符，要超过提供给这些转换指定符的第二个（ rsize_t ）参数
  • 可选，任何其他可检测错误，例如未知转换指定符
同所有边界检查函数， vscanf_s, vfscanf_s, vsscanf_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <stdio.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

stream - 要读取的输入文件流
buffer - 指向要读取的空终止字符串的指针
format - 指向指定读取输入方式的空终止字符串的指针。

格式字符串由下列内容组成

  • 非空白多字节字符，除了 % ：每个格式字符串中的这种字符处理来自输入流的准确同一字符，或若它与流的下个字符比较不相等则导致函数失败。
  • 空白符：任何格式字符串中的单个空白符处理所有来自输入的可用连续空白符（如同通过于循环中调用 isspace 确定）。注意格式字符串中 "\n" 、 " " 、 "\t\t" 或其他空白无区别。
  • 转换说明：每个转换说明拥有下列格式：
  • 引入用 % 字符
  • (可选)赋值抑制字符 * 。若存在此选项，则此函数不将结果赋值给任何接收用参数。
  • (可选)指定最大域宽的整数数字（大于零），即函数进行在当前转换说明所指定的转换时，允许处理的最大字符数。注意若不提供宽度，则 %s 和 %[ 可能导致缓冲区溢出。
  • (可选)指定接收参数大小的长度修饰符，即实际目标类型。这影响转换准确性和溢出规则。默认目标类型对每个转换类型不同（见下表）。
  • 转换格式说明符

下列格式说明符可用：

转换
说明符 		解释 参数类型
长度修饰符 →
 hh

(C99)

 h （无） l ll

(C99)

 j

(C99)

 z

(C99)

 t

(C99)

 L
% 匹配字面 % 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
匹配一个字符或字符的序列

若使用了宽度说明符，则匹配准确的宽度个字符（该参数必须是指向有充足空间的数组的指针）。不同于 %s 和 %[ ，它不会在数组后附加空字符。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
s
匹配非空白字符的序列（一个字符串）

若使用宽度说明符，则至多匹配宽度个字符，或匹配到首个提前出现的空白符前。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
[集合]
匹配一个来自 集合 的字符的非空字符序列。

若集合的首字符是 ^ ，则匹配所有不在集合中的字符。若集合以 ] 或 ^] 开始，则 ] 字符亦被包含入集合。在扫描集合的非最初位置的字符 - 是否可以指示范围，如 [0-9] ，是实现定义的。若使用宽度说明符，则最多匹配到宽度。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
d
匹配一个十进制整数。

该数的格式同 strtol() 以值 10 为 base 时所期望者
signed char* 或 unsigned char*
signed short* 或 unsigned short*
signed int* 或 unsigned int*
signed long* 或 unsigned long*
signed long long* 或 unsigned long long*
intmax_t * 或 uintmax_t *
size_t *
ptrdiff_t *
 N/A
i
匹配一个整数。

该数的格式同 strtol() 以值 ​0​ 为 base 时所期望者（基底以首个分析的字符确定）
u
匹配一个无符号十进制整数。

该数的格式同 strtoul() 以值 10 为 base 参数时所期望者。
o
匹配一个无符号八进制数。

该数的格式同 strtoul() 以值 8 为 base 参数时所期望者。
x, X
匹配一个无符号十六进制整数。

该数的格式同 strtoul() 以值 16 为 base 参数时所期望者。
n
返回迄今读取的字符数。

不消耗输出。不增加赋值计数。若此说明符拥有赋值抑制运算符，则行为未定义。
a, A(C99)
e, E
f, F
g, G
匹配一个浮点数。

该数的格式同 strtof() 所期望者。

 N/A N/A
float*
double*
 N/A N/A N/A N/A
long double*
p
匹配定义一个指针的实现定义的字符序列。

printf 系列函数应该用 %p 格式说明符产生同样的序列。

 N/A N/A
void**
 N/A N/A N/A N/A N/A N/A

对于每个异于 n 的转换说明符，不超过任何指定域宽，且要么是转换说明符所准确期待，要么是其所期待的前缀的最长输入字符序列，即是从流中消耗的内容。此消耗序列后的首个字符若存在，则保持未读取。若被消耗序列长度为零，或被消耗序列不能转换成上面所指定的项目，则发生匹配失败，除非遇到文件尾、编码错误，或阻止从流输入的读取错误，此情况下此为输入失败。

所有异于 [ 、 c 和 n 的转换说明符，在尝试分析输入前消耗并舍弃所有前导空白字符（如同以调用 isspace 来确定）。这些被消耗的字符不计入指定的最大域宽。

转换说明符 lc 、 ls 和 l[ 进行多字节到宽字符转换，如同如同在转换首字符前，通过用初始化到零的 mbstate_t 对象调用 mbrtowc() 。

转换说明符 s 与 [ 始终在匹配字符之后存储一个空字符。目标数组的大小必须至少比指定域宽大一。

定宽整数类型（ int8_t 等）的正确的转换说明定义于头文件 <inttypes.h> （虽然 SCNdMAX 、 SCNuMAX 等就是 %jd 、 %ju 等的别名）。

在每个转换说明符后有一个序列点；这允许存储多个域到同一“池”变量中。

在分析以无数字指数为结尾的不完整浮点值，如以转换说明符 %f 分析 "100er" 时，消耗序列 "100e" （可能为合法浮点数的最长前缀），并导致匹配错误（被消耗序列不能转换成浮点数），而留下 "r" 。某些既存实现不遵守此规则并回滚，通过消耗 "100" 而留下 "er" ，例如 glibc 漏洞 1765 。
vlist - 包含接收参数的变量参数列表

返回值

1-3) 成功赋值的接收参数数量，或者若输入在首个接收参数赋值前发生失败，则为 EOF 。
4-6) 同 (1-3) ，除了若有运行时制约违规，也返回 EOF 。

注解

所有这些函数调用 va_arg 至少一次，返回后 arg 的值不确定。这些函数不调用 va_end ，而这必须由调用方进行。

示例

#include <stdio.h>
#include <stdbool.h>
#include <stdarg.h>

bool checked_sscanf(int count, const char* buf, const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    int rc = vsscanf(buf, fmt, ap);
    va_end(ap);
    return rc == count;
}

int main(void)
{
    int n, m;

    printf("Parsing '1 2'...");
    if(checked_sscanf(2, "1 2", "%d %d", &n, &m))
        puts("success");
    else
        puts("failure");

    printf("Parsing '1 a'...");
    if(checked_sscanf(2, "1 a", "%d %d", &n, &m))
        puts("success");
    else
        puts("failure");
}

输出：

Parsing '1 2'...success
Parsing '1 a'...failure

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.21.6.9 The vfscanf function (p: 327)
  • 7.21.6.11 The vscanf function (p: 328)
  • 7.21.6.14 The vsscanf function (p: 330)
  • K.3.5.3.9 The vfscanf_s function (p: 597-598)
  • K.3.5.3.11 The vscanf_s function (p: 599)
  • K.3.5.3.14 The vsscanf_s function (p: 602)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.19.6.9 The vfscanf function (p: 293)
  • 7.19.6.11 The vscanf function (p: 294)
  • 7.19.6.14 The vsscanf function (p: 295)

参阅

scanffscanfsscanfscanf_sfscanf_ssscanf_s (C11)(C11)(C11) | 从stdin、文件流或缓冲区读取格式化输入 (函数)
vprintfvfprintfvsprintfvsnprintfvprintf_svfprintf_svsprintf_svsnprintf_s (C99)(C11)(C11)(C11)(C11) | 打印格式化输出到stdout、文件流或缓冲区 使用可变参数列表 (函数)


vwprintf, vfwprintf, vswprintf, vwprintf_s, vfwprintf_s, vswprintf_s, vsnwprintf_s

< c‎ | io
定义于头文件 <wchar.h> |  |
 | (1) |
int vwprintf( const wchar_t *format, va_list vlist ); |  |  | (C95 起) (C99 前)
int vwprintf( const wchar_t *restrict format, va_list vlist ); |  |  | (C99 起)
 | (2) |
int vfwprintf( FILE * stream, const wchar_t *format, va_list vlist ); |  |  | (C95 起) (C99 前)
int vfwprintf( FILE *restrict stream, const wchar_t *restrict format, va_list vlist ); |  |  | (C99 起)
 | (3) |
int vswprintf( wchar_t *buffer, size_t bufsz, const wchar_t *format, va_list vlist ); |  |  | (C95 起) (C99 前)
int vswprintf( wchar_t *restrict buffer, size_t bufsz, const wchar_t *restrict format, va_list vlist ); |  |  | (C99 起)
int vwprintf_s( const wchar_t *restrict format, va_list vlist); | (4) | (C11 起)
int vfwprintf_s( FILE * restrict stream, const wchar_t *restrict format, va_list vlist); | (5) | (C11 起)
int vswprintf_s( wchar_t *restrict buffer, rsize_t bufsz, const wchar_t * restrict format, va_list vlist); | (6) | (C11 起)
int vsnwprintf_s( wchar_t *restrict buffer, rsize_t bufsz, const wchar_t *restrict format, va_list vlist); | (7) | (C11 起)

从vlist所定义的位置加载数据，将它们转换成宽字符串等价物，并将结果写入各种池。

1) 写结果到 stdout 。
2) 写结果到文件流 stream 。
3) 写结果到宽字符串 buffer 。至多写入后随空宽字符的 size-1 个宽字符。产生的宽字符串将以空宽字符终止，除非 bufsz 为零。
4-6) 同 (1-3) ，除了在运行时检测下列错误，并调用当前安装的制约处理函数：
  • format 中存在转换指定符 %n
  • 任何一个对应 %s 的参数是空指针
  • format 或 buffer 是空指针
  • bufsz 为零或大于 RSIZE_MAX
  • 在任何一个字符串及字符转换指定符中出现编码错误
  • （仅对于 vswprintf_s ）要存储于 buffer （含尾随宽空字符）的宽字符串长度会超出 bufsz
同所有边界检查函数， vwprintf_s, vfwprintf_s, vswprintf_s, vsnwprintf_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <wchar.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

stream - 要写入的输出宽流
buffer - 指向要写入的宽字符串的指针
bufsz - 写入的最大宽字符数（含空终止宽字符）
format - 指向指定数据转译方式的空终止宽字符串的指针。

格式字符串由普通宽字符（除了 % ）和转换指定构成，前者被复制到输出流而无更改。每个转换指定拥有下列格式：

  • 引入的 % 字符
  • (可选)一或多个修改转换行为的标签：
  • - ：转换结果在域内左校正（默认为右校正）
  • + ：有符号转换的符号始终前置于转换结果（默认结果前置负号仅当它为负）
  • 空格：若有符号转换的结果不以符号开始，或为空，则前置空格于结果。若存在 + 标签则忽略空格。
  • # ：进行替用形式的转换。准确的效果见下表，其他情况下行为未定义。
  • 0 ：对于整数和浮点数转换，使用前导零代替空格字符填充域。对于整数，若显式指定精度，则忽略此标签。对于其他转换，使用此标签导致未定义行为。若存在 - 标签则忽略 0 。
  • (可选)指定最小域宽的整数值或 * 。若有要求，则结果会以空格字符（默认情况）填充，在右校正时于左，左校正时于右。使用 * 的情况下，以一个额外的 int 类型参数指定宽度。若参数值为负数，则它导致指定 - 标签和正域宽。（注意：这是最小宽度：决不被截断值）。
  • (可选)后随整数或 * 或两者皆无的 . 指示转换的精度。在使用 * 的情况下，精度由额外的 int 类型参数指定。若此参数的值为负数，则它被忽略。若既不使用数字亦不使用 * ，则精度采用零。精度的准确效果见下表。
  • (可选)指定参数大小的长度修饰符
  • 转换格式指定符

下列格式指定符可用：

转换
指定符 		解释 参数类型
长度修饰符 hh

(C99)

 h （无） l ll

(C99)

 j

(C99)

 z

(C99)

 t

(C99)

 L
% 写字面的 % 。完整转换指定必须是 %% 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
写单个字符。

参数首先被转换成 wchar_t ，如同通过调用 btowc 。 若使用 l 修饰符，则 wint_t 参数首先被转换成 wchar_t 。

 N/A N/A
int
wint_t
 N/A N/A N/A N/A N/A
s
写字符串

参数必须为一个指针，指向包含以初始迁移状态开始的，多字节字符序列的字符数组首元素，数组会被转换成宽字符数组，如同通过以零初始化转换状态调用 mbrtowc 。 精度指定写入的最大宽字符数。若未指定精度，则写每个宽字符直到而不含首个空终止符。 若使用 l 指定符，则参数必须是指向 wchar_t 数组首元素的指针。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
d
i
转换有符号整数为十进制表示 [-]dddd 。

精度指定出现的最小数位数。默认精度是 1 。
若被转换的值和精度都是 ​0​ ，则转换结果无字符。
signed char
short
int
long
long long
intmax_t
有符号 size_t
ptrdiff_t
 N/A
o
转换无符号整数为八进制表示 oooo 。

精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中精度按需增加，以写入一个前导零。 在此情况下若被转换值和精度都是 ​0​ ，则写入单个 ​0​ 。
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
uintmax_t
size_t
ptrdiff_t 的无符号版本
 N/A
x
X
转换无符号整数为十六进制表示 hhhh 。

x 转换使用字母 abcdef 。
X 转换使用 ABCDEF 。
精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中若被转换值为非零则结果有 0x 或 0X 前缀。

 N/A
u
转换无符号整数为十进制表示 dddd 。

精度指定出现的最小数位数。 默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。

 N/A
f
F
转换浮点数为 [-]ddd.ddd 样式的十进制记法。

精度指定小数点字符后出现的准确数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A
double
double (C99)
 N/A N/A N/A N/A
long double
e
E
转换浮点数为十进制指数记法。

e 转换样式使用 [-]d.ddd e±dd 。
E 转换样式使用 [-]d.ddd E±dd 。
指数至少含二个数位，仅当所需时使用更多数位。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
a
A

(C99)
转换浮点数为十六进制记法。

a 转换样式使用 [-]0x h.hhh p±d 。
A 转换样式使用 [-]0X h.hhh P±d 。
若参数是正规化的浮点值，则首个十六进制数位非 0 。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度足以准确表示该值。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
g
G
转换浮点数为十进制小数或十进制指数记法，依赖于值和精度。

g 转换样式将进行带样式 e 或 f 的转换。
G 转换样式将进行带样式 E 或 F 的转换。
令 P 等于精度，若它非零，若精度未指定则为 6 ，若精度为 ​0​ 则等于 1 。然后，若带样式 E 的转换会有指数 X ，则：

  • 若 P > X ≥ −4 ，则转换带 f 或 F 风格，及精度 P − 1 − X 。
  • 否则，转换带 e 或 E 风格，及精度 P − 1 。

除非要求替用表示，否则末尾零会被移除，且若不留下小数部分则小数点亦被移除。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
n
返回对函数的此调用迄今为止写入的字符数。

结果被写入到参数所指向的值。 该指定不可含有任何标签、域宽或精度。
signed char*
short*
int*
long*
long long*
intmax_t *
有符号 size_t *
ptrdiff_t *
 N/A
p 写定义指针的实现定义字符序列。 N/A N/A void* N/A N/A N/A N/A N/A N/A

浮点转换函数转换无穷大到 inf 或 infinity 。使用哪个是实现定义的。

非数转换成 nan 或 nan(char_sequence) 。使用哪个是实现定义的。

转换 F 、 E 、 G 、 A 替代上面输出 INF 、 INFINITY 、 NAN。

尽管 %c 期待 int 参数，传递 char 是安全的，因为在调用变参数函数时发生整数提升。

定宽整数类型（ int8_t 等）的正确转换指定定义于头文件 <inttypes.h> （尽管 PRIdMAX 、 PRIuMAX 等就是 %jd 、 %ju 等的别名）。

内存写入转换指定符 %n 是安全漏洞的常见目标，这里格式字符串依赖用户输入，而有边界检查的 printf_s 系列函数不支持此转换指定符。

在每个转换指定符的行动后有一个序列点；这允许于同一变量多次存入 %n 的结果，并在同一此调用中打印出先前以 %n 存储的值。

若转换指定非法，则行为未定义。
vlist - 含有待打印数据的可变参数列表

返回值

1,2) 若成功则为写入的宽字符数，若出现错误则为负值。
3) 若成功则为写入的宽字符数，若出现失败则为负值。若生成的字符串因 bufsz 限制被截断，则函数返回假如未强加限制则本应写入的字符数（不含空终止宽字符）。
4,5) 传输到输出流的宽字符数，或若出现输出错误、运行时制约违规错误或编码错误则为负值。
6) 写入 buffer 的宽字符数，不计空宽字符（只要 buffer 非空指针且 bufsz 非零且不大于 RSIZE_MAX/sizeof(wchar_t) ，就写入它），或在运行时制约违规时为零，或在编码错误时为负值。
7) 假如忽略 bufsz 则本应写入 buffer 的宽字符数，不计空宽字符（只要 buffer 不是空指针且 bufsz 非零且不大于 RSIZE_MAX/sizeof(wchar_t) ，就写入它），或若运行时制约违规或编码错误发生则为负值。

注意

所有这些函数调用 va_arg 至少一次，在返回后 vlist 的值不确定。这些函数不调用 va_end ，而必须由调用方进行。

窄字符串提供 vsnprintf ，使得可以确定需求的缓冲区大小可行。不过宽字符串无等价版本（ C11 的 vsnwprintf_s 前），而为确定缓冲区大小，程序可能需要调用 vswprintf ，检查返回值，并重分配更大的缓冲区，反复尝试直至成功。

不同于 vswprintf_s ， vsnwprintf_s 将截断结果以适应 buffer 所指向的数组，尽管这种截断被多数带边界检查函数当做错误。

示例

#include <stdio.h>
#include <time.h>
#include <locale.h>

void debug_wlog(const wchar_t *fmt, ...)
{
    struct timespec ts;
    timespec_get(&ts, TIME_UTC);
    char time_buf[100];
    size_t rc = strftime(time_buf, sizeof time_buf, "%D %T", gmtime(&ts.tv_sec));
    snprintf(time_buf + rc, sizeof time_buf - rc, ".%06ld UTC", ts.tv_nsec / 1000);

    va_list args;
    va_start(args, fmt);
    wchar_t buf[1000];
    int rc2 = vswprintf(buf, sizeof buf / sizeof *buf, fmt, args);
    va_end(args);

    if(rc2 > 0)
       wprintf(L"%s [debug]: %ls\n", time_buf, buf);
    else
       wprintf(L"%s [debug]: (string too long)\n", time_buf);
}

int main(void)
{
    setlocale(LC_ALL, "");
    debug_wlog(L"Logging, %d, %d, %d", 1, 2, 3);
}

可能的输出：

02/20/15 22:12:38.476575 UTC [debug]: Logging, 1, 2, 3

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.2.5 The vfwprintf function (p: 417-418)
  • 7.29.2.7 The vswprintf function (p: 419)
  • 7.29.2.9 The vwprintf function (p: 420)
  • K.3.9.1.6 The vfwprintf_s function (p: 632)
  • K.3.9.1.8 The vsnwprintf_s function (p: 633-634)
  • K.3.9.1.9 The vswprintf_s function (p: 634-635)
  • K.3.9.1.11 The vwprintf_s function (p: 636)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.2.5 The vfwprintf function (p: 363)
  • 7.24.2.7 The vswprintf function (p: 364)
  • 7.24.2.9 The vwprintf function (p: 365)

参阅

vprintfvfprintfvsprintfvsnprintfvprintf_svfprintf_svsprintf_svsnprintf_s (C99)(C11)(C11)(C11)(C11) | 打印格式化输出到stdout、文件流或缓冲区 使用可变参数列表 (函数)
wprintffwprintfswprintfwprintf_sfwprintf_sswprintf_ssnwprintf_s (C95)(C95)(C95)(C11)(C11)(C11)(C11) | 打印格式化宽字符输出到 stdout 、文件流或缓冲区 (函数)


vwscanf, vfwscanf, vswscanf, vwscanf_s, vfwscanf_s, vswscanf_s

< c‎ | io
定义于头文件 <wchar.h> |  |
int vwscanf( const wchar_t *restrict format, va_list vlist ); | (1) | (C99 起)
int vfwscanf( FILE *restrict stream, const wchar_t *restrict format, va_list vlist ); | (2) | (C99 起)
int vswscanf( const wchar_t *restrict buffer, const wchar_t *restrict format, va_list vlist ); | (3) | (C99 起)
int vwscanf_s( const wchar_t *restrict format, va_list vlist ); | (4) | (C11 起)
int vfwscanf_s( FILE *restrict stream, const wchar_t *restrict format, va_list vlist ); | (5) | (C11 起)
int vswscanf_s( const wchar_t *restrict buffer, const wchar_t *restrict format, va_list vlist ); | (6) | (C11 起)

从各种源读取数据，按照 format 转译，并存储结果于 vlist 所定义的位置。

1) 从 stdin 读取数据。
2) 从文件流 stream 读取数据。
3) 从空终止宽字符串 buffer 读取数据。抵达字符串结尾等价于 vfwscanf 的抵达文件尾条件。
4-6) 同 (1-3) ，除了 %c 、 %s 和 %[ 转换指定符要求二个参数（通常的指针和指示获取用数组大小的 rsize_t 类型值，以 %lc 读取单个宽字符时可以为 1 ），及在运行时检测下列错误，并调用当前安装的制约处理函数：
  • 任何指针类型的参数是空指针
  • format 、 stream 或 buffer 是空指针
  • %c 、 %s 或 %[ 要写入的字符数，加上空终止字符，会超过提供给这些转换指定符的第二个（ rsize_t ）参数
  • 可选，任何其他可检测错误，例如未知转换指定符
同所有边界检查函数， vwscanf_s, vfwscanf_s, vswscanf_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <wchar.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

stream - 要读取的输入文件流
buffer - 指向要读取的空终止字宽符串的指针
format - 指向指定读取输入方式的空终止宽字符串的指针。格式字符串由下列内容组成
  • 非空白宽字符，除了 % ：每个格式字符串中的这种字符处理来自输入流的准确同一字符，或若它与流的下个字符比较不相等则导致函数失败。
  • 空白符：任何格式字符串中的单个空白符处理所有来自输入的可用连续空白符（如同通过于循环中调用 iswspace 确定）。注意格式字符串中 "\n" 、 " " 、 "\t\t" 或其他空白无区别。
  • 转换说明：每个转换说明拥有下列格式：
  • 引入用 % 字符
  • (可选)赋值抑制字符 * 。若存在此选项，则此函数不将结果赋值给任何接收用参数。
  • (可选)指定最大域宽的整数数字（大于零），即函数进行在当前转换说明所指定的转换时，允许处理的最大字符数。注意若不提供宽度，则 %s 和 %[ 可能导致缓冲区溢出。
  • (可选)指定接收参数大小的长度修饰符，即实际目标类型。这影响转换准确性和溢出规则。默认目标类型对每个转换类型不同（见下表）。
  • 转换格式说明符

下列格式说明符可用：

转换
说明符 		解释 参数类型
长度修饰符 →
 hh

(C99)

 h （无） l ll

(C99)

 j

(C99)

 z

(C99)

 t

(C99)

 L
% 匹配字面 % 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
匹配一个字符或字符的序列

若使用了宽度说明符，则匹配准确的宽度个宽字符（该参数必须是指向有充足空间的数组的指针）。不同于 %s 和 %[ ，它不会在数组后附加空字符。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
s
匹配非空白字符的序列（一个字符串）

若使用宽度说明符，则至多匹配宽度个字符，或匹配到首个提前出现的空白符前。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
[集合]
匹配一个来自 集合 的字符的非空字符序列。

若集合的首字符是 ^ ，则匹配所有不在集合中的字符。若集合以 ] 或 ^] 开始，则 ] 字符亦被包含入集合。在扫描集合的非最初位置的字符 - 是否可以指示范围，如 [0-9] ，是实现定义的。若使用宽度说明符，则最多匹配到宽度。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
d
匹配一个十进制整数。

该数的格式同 wcstol() 以值 10 为 base 时所期望者
signed char* 或 unsigned char*
signed short* 或 unsigned short*
signed int* 或 unsigned int*
signed long* 或 unsigned long*
signed long long* 或 unsigned long long*
intmax_t * 或 uintmax_t *
size_t *
ptrdiff_t *
 N/A
i
匹配一个整数。

该数的格式同 wcstol() 以值 ​0​ 为 base 时所期望者（基底以首个分析的字符确定）
u
匹配一个无符号十进制整数。

该数的格式同 wcstoul() 以值 10 为 base 参数时所期望者。
o
匹配一个无符号八进制数。

该数的格式同 wcstoul() 以值 8 为 base 参数时所期望者。
x, X
匹配一个无符号十六进制整数。

该数的格式同 wcstoul() 以值 16 为 base 参数时所期望者。
n
返回迄今读取的字符数。

不消耗输出。不增加赋值计数。若此说明符拥有赋值抑制运算符，则行为未定义。
a, A(C99)
e, E
f, F
g, G
匹配一个浮点数。

该数的格式同 wcstof() 所期望者。

 N/A N/A
float*
double*
 N/A N/A N/A N/A
long double*
p
匹配定义一个指针的实现定义的字符序列。

printf 系列函数应该用 %p 格式说明符产生同样的序列。

 N/A N/A
void**
 N/A N/A N/A N/A N/A N/A

对于每个异于 n 的转换说明符，不超过任何指定域宽，且要么是转换说明符所准确期待，要么是其所期待的前缀的最长输入字符序列，即是从流中消耗的内容。此消耗序列后的首个字符若存在，则保持未读取。若被消耗序列长度为零，或被消耗序列不能转换成上面所指定的项目，则发生匹配失败，除非遇到文件尾、编码错误，或阻止从流输入的读取错误，此情况下此为输入失败。

所有异于 [ 、 c 和 n 的转换说明符，在尝试分析输入前消耗并舍弃所有前导空白字符（如同以调用 iswspace 来确定）。这些被消耗的字符不计入指定的最大域宽。

若不使用长度说明符 l ，则转换说明符 c 、 s 和 [ 进行宽到到多字节字符转换，如同在转换首字符前，通过用初始化到零的 mbstate_t 对象调用 wcrtomb() 。

转换说明符 s 与 [ 始终在匹配字符之后存储一个空字符。目标数组的大小必须至少比指定域宽大一。

定宽整数类型（ int8_t 等）的正确的转换说明定义于头文件 <inttypes.h> （虽然 SCNdMAX 、 SCNuMAX 等就是 %jd 、 %ju 等的别名）。

在每个转换说明符后有一个序列点；这允许存储多个域到同一“池”变量中。

在分析以无数字指数为结尾的不完整浮点值，如以转换说明符 %f 分析 "100er" 时，消耗序列 "100e" （可能为合法浮点数的最长前缀），并导致匹配错误（被消耗序列不能转换成浮点数），而留下 "r" 。某些既存实现不遵守此规则并回滚，通过消耗 "100" 而留下 "er" ，例如 glibc 漏洞 1765 。
vlist - 含接收参数的可变参数列表

返回值

1-3) 成功赋值的接收参数数量，或若在赋值首个接收参数前出现读取失败，则为 EOF 。
4-6) 同 (1-3) ，除了若有运行时制约违规，也返回 EOF 。

注意

所有这些函数调用 va_arg 至少一次，在返回后 vlist 的值不确定。这些函数不调用 va_end ，而这必须由调用方进行。

示例

本节未完成
原因：暂无示例

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.2.6 The vfwscanf function (p: 418)
  • 7.29.2.8 The vswscanf function (p: 419)
  • 7.29.2.10 The vwscanf function (p: 420)
  • K.3.9.1.7 The vfwscanf_s function (p: 632-633)
  • K.3.9.1.10 The vswscanf_s function (p: 635-636)
  • K.3.9.1.12 The vwscanf_s function (p: 637)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.2.6 The vfwscanf function (p: 364)
  • 7.24.2.8 The vswscanf function (p: 365)
  • 7.24.2.10 The vwscanf function (p: 366)

参阅

wscanffwscanfswscanfwscanf_sfwscanf_sswscanf_s
(C95)(C95)(C95)(C11)(C11)(C11)
 从stdin、文件流或缓冲区读取格式化宽字符输入
(函数)


C 关键词

< c

这是 C 中保留的关键词列表。因为语言使用这些关键词，故不可重定义它们。

auto
break
case
char
const
continue
default
do
double
else
enum
extern

float
for
goto
if
inline (C99 起)
int
long
register
restrict (C99 起)
return
short

signed
sizeof
static
struct
switch
typedef
union
unsigned
void
volatile
while

_Alignas (C11 起)
_Alignof (C11 起)
_Atomic (C11 起)
_Bool (C99 起)
_Complex (C99 起)
_Decimal128 (C23 起)
_Decimal32 (C23 起)
_Decimal64 (C23 起)
_Generic (C11 起)
_Imaginary (C99 起)
_Noreturn (C11 起)
_Static_assert (C11 起)
_Thread_local (C11 起)

最常见的以下划线开头的关键词通常通过其便利宏来使用：

关键词 | 用作 | 定义于
_Alignas (C11 起) | alignas | stdalign.h
_Alignof (C11 起) | alignof | stdalign.h
_Atomic (C11 起) | atomic_bool. atomic_int, ... | stdatomic.h
_Bool (C99 起) | bool | stdbool.h
_Complex (C99 起) | complex | complex.h
_Decimal128 (C23 起) | （无宏） |
_Decimal32 (C23 起) | （无宏） |
_Decimal64 (C23 起) | （无宏） |
_Generic (C11 起) | （无宏） |
_Imaginary (C99 起) | imaginary | complex.h
_Noreturn (C11 起) | noreturn | stdnoreturn.h
_Static_assert (C11 起) | static_assert | assert.h
_Thread_local (C11 起) | thread_local | threads.h

而且，每个以双下划线 __ 或单下划线后随大写字母为首的名称是受保留的：细节参阅标识符。

注意合字符 <% 、 %> 、 <: 、 :> 、 %: 以及 %:%: 提供表示标准记号的替用方式。

下列记号在用于预处理器指令语境之内时，为预处理器所识别：

if
elif
else
endif

ifdef
ifndef
define
undef

include
line
error
pragma

defined
__has_c_attribute (C23 起)

下列记号用于预处理器指令的语境之外时，为预处理器所识别：

_Pragma (C99 起)

下列的额外关键词被分类为扩展，而且为条件性支持：

asm
fortran

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.4.1 Keywords (p: 42-43)
  • J.5.9 The fortran keyword (p: 422)
  • J.5.10 The asm keyword (p: 422)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.4.1 Keywords (p: 58-59)
  • J.5.9 The fortran keyword (p: 580)
  • J.5.10 The asm keyword (p: 580)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.4.1 Keywords (p: 50)
  • J.5.9 The fortran keyword (p: 514)
  • J.5.10 The asm keyword (p: 514)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.1.1 Keywords
  • G.5.9 The fortran keyword
  • G.5.10 The asm keyword

参阅


C 关键词： _Alignas (C11 起)

< c‎ | keyword

用法

  • _Alignas 对齐指定符。


C 关键词： _Alignof (C11 起)

< c‎ | keyword

用法

  • _Alignof 运算符


C 关键词： _Atomic

< c‎ | keyword

用法

  • 原子类型指定符及限定符


C 关键词： _Bool

< c‎ | keyword

用法

  • 布尔类型：用作该类型的声明


C 关键词： _Complex

< c‎ | keyword

用法

  • _Complex 类型：用作该类型的声明


C 关键词： _Decimal128

< c‎ | keyword

用法

  • _Decimal128 类型：用作该类型的声明


C 关键词： _Decimal32

< c‎ | keyword

用法

  • _Decimal32 类型：用作该类型的声明


C 关键词： _Decimal64

< c‎ | keyword

用法

  • _Decimal64 类型：用作该类型的声明


C 关键词： _Generic

< c‎ | keyword

用法

  • 泛型表达式


C 关键词： _Imaginary

< c‎ | keyword

用法

  • 虚浮点类型指定符


C 关键词： _Noreturn (C11 起)

< c‎ | keyword

用法

  • _Noreturn 函数指定符


C 关键词： _Static_assert

< c‎ | keyword

用法

  • _Static_assert 声明


C 关键词： _Thread_local (C11 起)

< c‎ | keyword

用法

  • 线程存储类限定符。


C 关键词： auto

< c‎ | keyword

用法

  • 无链接的自动存储期类限定符。


C 关键词： break

< c‎ | keyword

用法

  • break 语句：用作该语句的声明


C 关键词： case

< c‎ | keyword

用法

  • switch 语句：用作声明状况的标签


C 关键词： char

< c‎ | keyword

用法

  • 字符类型（ char 、 signed char 以及 unsigned char ）的类型指定符


C 关键词： const

< c‎ | keyword

用法

  • const 类型限定符


C 关键词： continue

< c‎ | keyword

用法

  • continue 语句：用作该语句的声明


C 关键词： default

< c‎ | keyword

用法

  • switch 语句：用作声明该语句的默认标号
  • 泛型表达式：用作默认泛型关联的声明
 (C11 起)


C 关键词： do

< c‎ | keyword

用法

  • do-while 循环：用作该循环的声明


C 关键词： double

< c‎ | keyword

用法

  • double 类型：用作该类型的声明
  • long double 类型：在与 long 结合时用作该类型的声明


C 关键词： else

< c‎ | keyword

用法

  • if 语句：用作另一种分支的声明


C 关键词： enum

< c‎ | keyword

用法

  • 枚举类型的声明


C 关键词： extern

< c‎ | keyword

用法

  • 拥有内部或更常见的外部链接之一的静态存储期类指定符。


C 关键词： float

< c‎ | keyword

用法

  • float 类型：用作该类型的声明


C 关键词： for

< c‎ | keyword

用法

  • for 循环：用作该循环的声明


C 关键词： fortran

< c‎ | keyword

用法

  • 为 Fortran 语言链接而设的条件性支持持类型指定符。可以与函数声明和其他外部声明一同使用，指示调用约定和名称重整适合于与以 Fortran 程序语言书写的翻译单元链接。


C 关键词： goto

< c‎ | keyword

用法

  • goto 语句：用作该语句的声明


C 关键词： if

< c‎ | keyword

用法

  • if 语句：用作 if 语句的声明


C 关键词： inline (C99 起)

< c‎ | keyword

用法

  • inline 函数指定符


C 关键词： int

< c‎ | keyword

用法

  • int 类型：用作该类型的声明


C 关键词： long

< c‎ | keyword

用法

  • long 类型修饰符


C 关键词： register

< c‎ | keyword

用法

  • 无链接的自动存储期类指定符。提示变量将会被重度使用。


C 关键词： restrict

< c‎ | keyword

用法

  • restrict 类型限定符


C 关键词： return

< c‎ | keyword

用法

  • return 语句：用作该语句的声明


C 关键词： short

< c‎ | keyword

用法

  • short 类型修饰符


C 关键词： signed

< c‎ | keyword

用法

  • signed 类型修饰符


C 关键词： sizeof

< c‎ | keyword

用法

  • sizeof 运算符


C 关键词： static

< c‎ | keyword

用法

  • 在文件作用域拥有内部链接，而在块作用域无链接的静态存储期类指定符。
  • 函数参数声明中的静态数组下标。
 (C99 起)


C 关键词： struct

< c‎ | keyword

用法

  • 复合类型的声明


C 关键词： switch

< c‎ | keyword

用法

  • switch 语句：用作该语句的声明


C 关键词： typedef

< c‎ | keyword

用法

  • typedef 声明


C 关键词： union

< c‎ | keyword

用法

  • 联合体类型的声明


C 关键词： unsigned

< c‎ | keyword

用法

  • unsigned 类型修饰符


C 关键词： void

< c‎ | keyword

用法

  • void 类型：用作不完整类型的声明
  • void ：用于无参数或无返回值的函数


C 关键词： volatile

< c‎ | keyword

用法

  • volatile 类型限定符


C 关键词： while

< c‎ | keyword

用法

  • while 循环：用作该循环的声明
  • do-while 循环：用作循环终止条件的声明


C 语言

< c

这是一份关于核心 C 语言构造的参考。

基本概念

注释
ASCII 码表 - 转义序列
翻译阶段
标点
标识符 - 作用域 - 生存期
查找与命名空间
类型 - 算术类型
对象与对齐
main 函数
如同规则
未定义行为
内存模型与数据竞争

关键词

预处理器

#if - #ifdef - #ifndef - #elif
#elifdef - #elifndef (C23)
#define - # - ##
#include - #pragma
#line - #error

语句

if - switch
for
while - do-while
continue - break
goto - return

表达式

值类别
求值顺序与定序
常量及字面量
整数常量
浮点常量
字符常量
字符串字面量
复合字面量 (C99)
常量表达式
隐式转换
运算符
成员访问与间接
逻辑 - 比较
算术 - 赋值
自增减
调用、逗号、三元
sizeof - _Alignof (C11)
转型运算符
运算符优先级
泛型选择 (C11)

初始化

标量
数组
结构体/联合体

声明

指针 - 数组
枚举
存储期与链接
const - volatile - restrict (C99)
struct - union - 位域
_Alignas (C11) - typedef
_Static_assert (C11)
原子类型 (C11)
外部及试探性定义
属性 (C23)

函数

函数声明
函数定义
inline (C99) - _Noreturn (C11)
可变参数

杂项

C 的历史
一致性
内联汇编
信号处理
可分析性 (C11)

参阅


_Alignas

< c‎ | language

出现于声明语法中，作为修改声明对象对齐要求的说明符。

语法

_Alignas ( 表达式 ) | (1) | (C11 起)
_Alignas ( 类型 ) | (2) | (C11 起)
表达式 | - | 任何值为合法对齐或零的整数常量表达式
类型 | - | 任何类型名称

此关键词亦用作便利宏 alignas ，此宏可用于头文件 <stdalign.h> 。

解释

_Alignas 只能在声明不是位域，且不拥有寄存器存储类的对象时使用。它不能用于函数参数声明，亦不能用于 typedef 。

用于声明时，设置被声明对象的对齐要求为

1) 表达式 的结果，除非它是零
2) 类型 的对齐要求，即设置为 _Alignof(type)

除非这会减弱该类型自然拥有的对齐。

若 表达式 求值为零，则此指定符无效果。

多个 _Alignas 说明符出现于同一个声明中时，使用最严格者。

_Alignas 说明符只需要出现于对象定义中，但若任何声明使用 _Alignas ，则它所说明的对齐必须与定义上的 _Alignas 相同。若不同的翻译单元为同一对象说明不同对齐，则行为未定义。

注解

C++ 中， alignas 说明符亦可应用于声明 class/struct/union 类型以及枚举。这在 C 中不受支持，但能通过在成员声明中使用 _Alignas 控制 struct 类型的对齐。

关键词

_Alignas

示例

#include <stdalign.h>
#include <stdio.h>
//  每一个 struct sse_t 类型的对象会在 16 字节边界对齐
// （注意：需要支持 DR 444 ）
struct sse_t
{
  alignas(16) float sse_data[4];
};

// 这种 struct data 的每一个对象都会在 128 字节边界对齐
struct data {
  char x;
  alignas(128) char cacheline[128]; // 过对齐的 char 数组对象，
                                    // 不是过对齐的 char 对象的数组
};

int main(void)
{
    printf("sizeof(data) = %zu (1 byte + 127 bytes padding + 128-byte array)\n",
           sizeof(struct data));

    printf("alignment of sse_t is %zu\n", alignof(struct sse_t));

    alignas(2048) struct data d; // 此 struct data 的实例会更严格地对齐
}

输出：

sizeof(data) = 256 (1 byte + 127 bytes padding + 128-byte array)
alignment of sse_t is 16

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C 标准。

DR | 应用于 | 出版时的行为 | 正确行为
DR 444 | C11 | 结构体与联合体成员中不允许 _Alignas | 允许

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.7.5 Alignment specifier (p: 92)
  • 6.2.8 Alignment of objects (p: 36-37)
  • 7.15 Alignment <stdalign.h> (p: 196)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.5 Alignment specifier (p: 127-128)
  • 6.2.8 Alignment of objects (p: 48-49)
  • 7.15 Alignment <stdalign.h> (p: 268)

参阅


_Alignof 运算符

< c‎ | language

查询其运算数类型的对齐要求。

语法

_Alignof( 类型名 ) (C11 起)

通常通过便利宏 alignof 使用此运算符，该宏于头文件 stdalign.h 提供。

解释

返回 类型名 所指名的类型的对齐要求。若 类型名 为数组类型，则结果为数组元素的对齐要求。 类型名 不能为函数类型或不完整类型。

结果是 size_t 类型整数常量。

不求值运算数（故用作运算数的外部标识符不必有定义）。

若 类型名 为 VLA 类型，则不求值其大小表达式。

注解

一些 C 编译器允许把 _Alignof 用于表达式这种非标准扩展。

关键词

_Alignof

示例

#include <stdio.h>
#include <stddef.h>
#include <stdalign.h>

int main(void)
{
    printf("Alignment of char = %zu\n", alignof(char));
    printf("Alignment of max_align_t = %zu\n", alignof(max_align_t));
    printf("alignof(float[10]) = %zu\n", alignof(float[10]));
    printf("alignof(struct{char c; int n;}) = %zu\n",
            alignof(struct {char c; int n;}));
}

可能的输出：

Alignment of char = 1
Alignment of max_align_t = 16
alignof(float[10]) = 4
alignof(struct{char c; int n;}) = 4

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C 标准。

DR | 应用于 | 出版时的行为 | 正确行为
DR 494 | C11 | 未指明是否求值 _Alignof 中的 VLA 中的大小表达式 | 不求值它

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.5.3.4 The sizeof and _Alignof operators (p: 64-65)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.5.3.4 The sizeof and _Alignof operators (p: 90-91)

参阅

max_align_t (C11) | 对齐要求不小于任何其他标量类型的类型 (typedef)
_Alignas 说明符 (C11) | 设置对象的对齐要求


_Noreturn 函数指定符

< c‎ | language

指明函数不会返回到其调用点。

语法

_Noreturn function_declaration (C11 起)

解释

_Noreturn 关键词出现于函数声明中，指定函数不会由于执行到 return 语句或抵达函数体结尾而返回（可通过执行 longjmp 返回）。若声明 _Noreturn 的函数返回，则行为未定义。若编译器能检测此错误，则推荐编译器诊断。

_Noreturn 指定符可以在同一函数声明中出现多于一次，行为与只出现一次相同。

此指定符通常通过便利宏 noreturn 使用，该宏于头文件 stdnoreturn.h 提供。

关键词

_Noreturn

标准库

下列标准库的函数为 _Noreturn ：

  • abort()
  • exit()
  • _Exit()
  • quick_exit()
  • thrd_exit()
  • longjmp()

示例

#include <stdlib.h>
#include <stdio.h>
#include <stdnoreturn.h>

// 在 i <= 0 时导致未定义行为
// 在 i > 0 时退出
noreturn void stop_now(int i) // 或 _Noreturn void stop_now(int i)
{
    if (i > 0) exit(i);
}

int main(void)
{
  puts("Preparing to stop...");
  stop_now(2);
  puts("This code is never executed.");
}

输出：

Preparing to stop...

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.4 Function specifiers (p: 125-127)
  • 7.23 _Noreturn <stdnoreturn.h> (p: 361)

参阅


静态断言

< c‎ | language

语法

_Static_assert ( 表达式 , 消息 ) | (C11 起)
_Static_assert ( 表达式 ) | (C23 起)
表达式 | - | 任何整数常量表达式
消息 | - | 任何字符串字面量

此关键词亦可用作便利宏 static_assert ，宏于头文件 <assert.h> 可用。

解释

在编译时求值该常量表达式并将它与零比较。若它比较等于零，则发生编译错误，而若提供 消息 ，则编译器必须将它作为错误消息的一部分显示（除了不要求显示基本源码字符集以外的字符）。

否则，若 表达式 不等于零，则什么都不发生；不生成代码。

关键词

_Static_assert

示例

#include <assert.h>
int main(void)
{
    // 测试数学是否正常工作
    static_assert(2 + 2 == 4, "Whoa dude!"); // 或 _Static_assert(...

    // 这会在编译时产生错误。
    static_assert(sizeof(int) < sizeof(char),
                 "this program requires that int is less than char");
}

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.7.10 Static assertions (p: 105)
  • 7.2 Diagnostics <assert.h> (p: 135)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.10 Static assertions (p: 145)
  • 7.2 Diagnostics <assert.h> (p: 186-187)

参阅

assert
 若用户指定的条件非true，则异常终止程序。可以在发行版本禁用。
(宏函数)


算术类型

< c‎ | language

（可参阅类型，以获得类型系统综述，及 C 库提供的类型相关工具列表）

布尔类型

  • _Bool （亦可作为宏 bool 使用） - 类型，足以保有二个值之一： 1 与 0 （亦可作为宏 true 与 false 使用）。

注意，到 _Bool 的转换与到其他整数类型的转换不同： (bool)0.5 求值为 1 ，然而 (int)0.5 求值为 ​0​ 。

 (C99 起)

字符类型

  • signed char - 用作有符号字符表示的类型。
  • unsigned char - 用作无符号字符表示的类型。亦可用于查看对象表示（无修饰内存）。
  • char - 用于字符表示的类型。 与 signed char 或 unsigned char 等价（具体等价于哪个是实现定义的，并且可以通过编译器命令行开关控制），但 char 是独立的类型，与 signed char 及 unsigned char 都不相同。

注意：标准亦定义了 typedef 名 wchar_t 、 char16_t 及 char32_t (C11 起) 以表示宽字符。

整数类型

  • short int （亦可用作 short ，可以用关键词 signed ）
  • unsigned short int （亦可用作 unsigned short ）
  • int （亦可用作 signed int ）
这是平台的最理想整数类型，保证至少为 16 位。当前大多数平台使用 32 位（见后述的数据模型）。
  • unsigned int （亦可用作 unsigned ）， int 的无符号对应者，实现模算术。适合位操作。
  • long int （亦可用作 long ）
  • unsigned long int （亦可用作 unsigned long ）
  • long long int （亦可用作 long long ）
  • unsigned long long int （亦可用作 unsigned long long ）
 (C99 起)

注意：同所有类型说明符，允许任意顺序： unsigned long long int 和 long int unsigned long 指名同一类型。

下表总结所有可用的整数类型及其属性：

类型说明符 | 等价类型 | 数据模型中的位宽
 |  | C 标准 | LP32 | ILP32 | LLP64 | LP64
short | short int | 至少 16 | 16 | 16 | 16 | 16
short int
signed short
signed short int
unsigned short | unsigned short int
unsigned short int
int | int | 至少 16 | 16 | 32 | 32 | 32
signed
signed int
unsigned | unsigned int
unsigned int
long | long int | 至少 32 | 32 | 32 | 32 | 64
long int
signed long
signed long int
unsigned long | unsigned long int
unsigned long int
long long | long long int (C99) | 至少 64 | 64 | 64 | 64 | 64
long long int
signed long long
signed long long int
unsigned long long | unsigned long long int (C99)
unsigned long long int

除了最小位数， C 标准还保证

1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long) 。

注意：这允许极端情形，如字节大小为 64 位，所有类型（包括 char ）均为 64 位宽，而 sizeof 对每个整数类型都返回 1 。

注意：整数算术的定义对于有符号数和无符号数不同。见算数运算符，尤其是整数溢出。

数据模型

每个实现关于基础类型的大小选择被统称为数据模型。有四种广为接受的数据模型：

32 位系统：

  • LP32 或 2/4/4 （ int 为 16 位， long 与指针为 32 位）
  • Win16 API
  • ILP32 或 4/4/4 （ int 、 long 及指针为 32 位）；
  • Win32 API
  • Unix 及类 Unix 系统（ Linux 、 Mac OS X ）

64 位系统：

  • LLP64 或 4/4/8 （ int 及 long 为 32 位，指针为 64 位）
  • Win64 API
  • LP64 或 4/8/8 （ int 为 32 位， long 及指针为 64 位）
  • Unix 与类 Unix 系统（ Linux 、 Mac OS X ）

其他数据模型非常稀有。例如， ILP64 （ 8/8/8 ： int 、 long 及指针均为 64 位）仅出现于某些早期 64 位 Unix 系统（例如 Unicos on Cray ）。

注意从 C99 开始可从 <stdint.h> 中使用准确宽度的整数。

实浮点类型

C 拥有三或六 (C23 起)种表示实浮点值的类型：

  • float - 单精度浮点类型。若支持则匹配 IEEE-754 binary32 格式。
  • double - 双精度浮点类型。若支持则匹配 IEEE-754 binary64 格式。
  • long double - 扩展精度浮点类型。若支持则匹配 IEEE-754 binary128 格式，否则若支持则匹配 IEEE-754 binary64 扩展格式，否则匹配某种精度优于 binary64 而值域至少和 binary64 一样好的非 IEEE-754 扩展浮点格式，否则匹配 IEEE-754 binary64 格式。
    • 一些 HP-UX、 SPARC、 MIPS、 ARM64 和 z/OS 实现使用 binary128 格式。
    • 最知名的 IEEE-754 binary64 扩展格式是 80 位 x87 扩展精度格式。许多 x86 和 x86-64 实现使用它（一个典型的例外是 MSVC ，它将 long double 实现为与 double 相同的格式，即 binary 64）。
若实现预定义宏常量 __STDC_IEC_60559_DFP__ ，则下列十进制浮点类型亦得到支持。
  • _Decimal32 - 表示 IEEE-754 decimal32 格式。
  • _Decimal64 - 表示 IEEE-754 decimal64 格式。
  • _Decimal128 - 表示 IEEE-754 decimal128 格式。
否则，不支持这些十进制浮点类型。
 (C23 起)

浮点类型可以支持特殊值：

  • 无穷大（正与负），见 INFINITY
  • 负零，-0.0。它与正零比较相等，但对于某些算术运算有意义（例如 1.0/0.0 == INFINITY ，但 1.0/-0.0 == -INFINITY ）。
  • 非数（ NaN ），它与任何值比较不相等（包括其自身）。有多种位模式表示 NaN ，见 nan 、 NAN 。注意 C 对（ IEEE-754 所指定的） NaN 信号不作任何留意，并安静处理所有 NaN 。

实浮点数可用与算术运算符 + - / *和来自 math.h 的大量数学函数一同使用。内建运算符和库函数都可能引发浮点异常，并以 math_errhandling 中描述的方式设置 errno 。

浮点表达式可拥有大于其类型所指示的范围和精度，见 FLT_EVAL_METHOD 。赋值、 return 和转型强制将范围和精度变成声明类型所关联者。

浮点表达式亦可被缩略，即仿佛中间值拥有无限范围和精度一般计算，见 #pragma STDC FP_CONTRACT。

一些浮点数上的运算会受到浮点环境的影响，或修改它（最值得注意的是舍入方向）

实浮点类型与整数、复数和虚数类型间的隐式转换有定义。

附加细节、极限和浮点类型属性见浮点类型极限与 math.h 库。

复浮点类型

复浮点类型模仿数学的复数，即可以写成一个实数与一个实数乘虚数单位的和的数： a + bi

三种复数类型是

  • float _Complex （亦可用作float complex，若包含了 <complex.h> ）
  • double _Complex （亦可用作 double complex，若包含了 <complex.h> ）
  • long double _Complex （亦可用作 long double complex ，若包含了 <complex.h> ）

注意：同所有类型说明符，允许任意顺序： long double complex 、 complex long double ，甚至 double complex long 都指名同一类型。

#include <complex.h>
#include <stdio.h>
int main(void)
{
    double complex z = 1 + 2*I;
    z = 1/z;
    printf("1/(1.0+2.0i) = %.1f%+.1fi\n", creal(z), cimag(z));
}

输出：

1/(1.0+2.0i) = 0.2-0.4i

若实现定义了宏常量 __STDC_NO_COMPLEX__ ，则不提供复数类型（还有库头文件 <complex.h> ）。

 (C11 起)

每个复数类型与拥有二个对应实数类型（ float 之于 float complex ，double 之于 double complex ， long double 之于 long double complex ）元素的数组相同的对象表示和对齐要求。数组第一元素保有实部，而第二个元素保有虚部。

float a[4] = {1, 2, 3, 4};
float complex z1, z2;
memcpy(&z1, a, sizeof z1); // z1 成为 1.0 + 2.0i
memcpy(&z2, a+2, sizeof z2); // z2 成为 3.0 + 4.0i

复数可用于算术运算符 + - * 和 / ， complex.h 中为复数定义许多数学函数。内建运算符和库函数都可能引发浮点异常，并按 math_errhandling 中描述的方式设置 errno 。

复数类型中不定义自增和自减。

复数类型中不定义关系运算符（没有“小于”的记号）。

本节未完成
原因：审阅其他操作、链接库
隐式转换定义于复数类型和其他算术类型。

为支持复数算术的一个无限模型， C 认可任何至少有一个无限部分的复数值为无穷大，即使另一部分是 NaN ，保证所有运算符和函数忠实于无穷大的基本属性，并提供 cproj 以映射所有无穷大到标准的一（准确规则见算术运算符）。

#include <stdio.h>
#include <complex.h>
#include <math.h>
int main(void)
{
   double complex z = (1 + 0*I) * (INFINITY + I*INFINITY);
// 教科书公式会给出
// (1+i0)(∞+i∞) ⇒ (1×∞ – 0×∞) + i(0×∞+1×∞) ⇒ NaN + I*NaN
// 但 C 给出复无穷大
   printf("%f + i*%f\n", creal(z), cimag(z));

// 教科书方程会给出
// cexp(∞+iNaN) ⇒ exp(∞)×(cis(NaN)) ⇒ NaN + I*NaN
// 但 C 给出±∞+i*nan
   double complex y = cexp(INFINITY + I*NAN);
   printf("%f + i*%f\n", creal(y), cimag(y));

}

可能的输出：

inf + i*inf
inf + i*nan

C 也会处理多重无穷大，以在可能的地方保留方向信息，不管笛卡尔表示的固有限制：

实无穷大乘虚数单位，会给出对应符号的虚无穷大： i × ∞ = i∞ 。同理， i × (∞ – i∞) = ∞ + i∞ 指示合理的象限。

本节未完成
原因：遣词

虚浮点类型

虚浮点类型模仿数学的虚数，即可以写成实数乘虚数单位的数： bi 三种虚数类型是

  • float _Imaginary （亦可用作 float imaginary ，若包含了 <complex.h> ）
  • double _Imaginary （亦可用作 double imaginary ，若包含了 <complex.h> ）
  • long double _Imaginary （亦可用作 long double imaginary ，若包含了 <complex.h> ）

注意：同所有类型说明符，允许任意顺序： long double imaginary 、 imaginary long double ，甚至 double imaginary long 都指名同一类型。

#include <complex.h>
#include <stdio.h>
int main(void)
{
    double imaginary z = 3*I;
    z = 1/z;
    printf("1/(3.0i) = %+.1fi\n", cimag(z));
}

输出：

1/(3.0i) = -0.3i
推荐实现定义 __STDC_IEC_559_COMPLEX__ ，但不要求支持虚数。 POSIX 推荐检查是否定义宏 _Imaginary_I 以鉴别是否支持虚数。 | (C11 前)
若定义 __STDC_IEC_559_COMPLEX__ (C23 前)__STDC_IEC_60559_COMPLEX__ (C23 起) ，则支持虚数。 | (C11 起)

三种虚数类型各拥有与其对应实数类型（ float 之于 float imaginary ， double 之于 double imaginary ， long double 之于 long double imaginary ）相同的对象表示和对齐要求。

注意：尽管如此，虚数类型是独立的，且与其对应实数类型不兼容，这禁止别名使用。

虚数可用于 算术运算符 + - * 及 / ，并且可与复数和实数混用。 complex.h 中为虚数类型定义多个数学函数。内建运算符和库函数都可能引发浮点异常，并按描述于 math_errhandling 的方式设置 errno 。

自增和自减不定义于虚数类型。

本节未完成
原因：审阅其他操作、链接库
隐式转换定义于虚数类型和其他算术类型之间。

虚数类型零通过自然记号 x + I*y （其中 I 定义为 _Imaginary_I ）表示所有复数成为可能。若无虚数类型，则无法自然地创建一些特殊复数值。例如，若 I 被定义为 _Complex_I ，则书写 0.0 + I*INFINITY 会给出有 NaN 实部的结果，而必须用 CMPLX (0.0, INFINITY) 替代之。拥有负零虚部的数亦然，这对于使用存在分支的库函数有意义，例如 csqrt ：若 I 定义为 _Complex_I，则 1.0 - 0.0*I 结果有正零的虚部，并要求用 CMPLX 或 conj 获得负零虚部。

虚数类型亦会简化实现：若支持虚数则复数乘虚数可以直接实现为二次乘法，而非四次乘法和二次加法。

 (C99 起)

关键词

char, int, short, long, signed, unsigned, float, double. _Bool, _Complex, _Imaginary, _Decimal32, _Decimal64, _Decimal128

取值范围

下表提供常用数值表示的界限的参考。

C23 之前，C 标准曾允许任意的有符号整数表示，而 N 位有符号整数的最小保证范围为从 \(\scriptsize -(2^{N-1}-1)\)-(2N-1
-1) 到 \(\scriptsize +2^{N-1}-1\)+2N-1
-1 （例如有符号 8 位类型为 -127 到 127 ），这对应于反码或原码的界限。

然而，所有通行数据模型（含 ILP32、 LP32、 LP64、 LLP64 全体）和几乎所有的 C 编译器（已知的仅有例外是 UNISYS 的一些编译器）均使用补码表示，而从 C23 起，这是标准所允许的唯一表示，所保证的范围为从 \(\scriptsize -2^{N-1}\)-2N-1
 到 \(\scriptsize +2^{N-1}-1\)+2N-1
-1 （例如有符号 8 位类型为 -128 到 127 ）。

类型 | 位数 | 格式 | 取值范围
近似 | 精确
字符 | 8 | 有符号 | -128 到 127
无符号 | 0 到 255
16 | UTF-16 | 0 到 65535
32 | UTF-32 | 0 到 1114111 (0x10ffff)
整数 | 16 | 有符号 | ± 3.27 · 104 | -32768 到 32767
无符号 | 0 到 6.55 · 104 | 0 到 65535
32 | 有符号 | ± 2.14 · 109 | -2,147,483,648 到 2,147,483,647
无符号 | 0 到 4.29 · 109 | 0 到 4,294,967,295
64 | 有符号 | ± 9.22 · 1018 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
无符号 | 0 到 1.84 · 1019 | 0 到 18,446,744,073,709,551,615
二进制浮点 32 IEEE-754
  • 最小非正规：
    ± 1.401,298,4 · 10-45
  • 最小正规：
    ± 1.175,494,3 · 10-38
  • 最大：
    ± 3.402,823,4 · 1038
  • 最小非正规：
    ±0x1p-149
  • 最小正规：
    ±0x1p-126
  • 最大：
    ±0x1.fffffep+127
64 IEEE-754
  • 最小非正规：
    ± 4.940,656,458,412 · 10-324
  • 最小正规：
    ± 2.225,073,858,507,201,4 · 10-﻿308
  • 最大：
    ± 1.797,693,134,862,315,7 · 10308
  • 最小非正规：
    ±0x1p-1074
  • 最小正规：
    ±0x1p-1022
  • 最大：
    ±0x1.fffffffffffffp+1023
80[注 1] x86
  • 最小非正规：
    ± 3.645,199,531,882,474,602,528
    · 10-4951
  • 最小正规：
    ± 3.362,103,143,112,093,506,263
    · 10-4932
  • 最大：
    ± 1.189,731,495,357,231,765,021
    · 104932
  • 最小非正规：
    ±0x1p-16446
  • 最小正规：
    ±0x1p-16382
  • 最大：
    ±0x1.fffffffffffffffep+16383
128 IEEE-754
  • 最小非正规：
    ± 6.475,175,119,438,025,110,924,
    438,958,227,646,552,5 · 10-4966
  • 最小正规：
    ± 3.362,103,143,112,093,506,262,
    677,817,321,752,602,6 · 10-4932
  • 最大：
    ± 1.189,731,495,357,231,765,085,
    759,326,628,007,016,2 · 104932
  • 最小非正规：
    ±0x1p-16494
  • 最小正规：
    ±0x1p-16382
  • 最大：
    ±0x1.ffffffffffffffffffffffffffff
    p+16383
十进制浮点 32 IEEE-754
  • 最小非正规：
    ± 1 · 10-101
  • 最小正规：
    ± 1 · 10-95
  • 最大：
    ± 9.999'999 · 1096
64 IEEE-754
  • 最小非正规：
    ± 1 · 10-398
  • 最小正规：
    ± 1 · 10-383
  • 最大：
    ± 9.999'999'999'999'999 · 10384
128 IEEE-754
  • 最小非正规：
    ± 1 · 10-6176
  • 最小正规：
    ± 1 · 10-6143
  • 最大：
    ± 9.999'999'999'999'999'999'
    999'999'999'999'999 · 106144
  1. ↑ 在 32/64 位平台上对象表示通常占用 96/128 位。

注意：实际（与保证最小值相对）的范围可在库头文件 <limits.h> 和 <float.h> 中获得

参阅


数组声明

< c‎ | language

数组是由连续无空隙分配的，拥有特定元素类型的对象构成的。这些对象的数目数量（数组大小）在数组生存期间决不改变。

语法

在数组声明的声明文法中，类型指定序列指明元素类型（必须是一个完整对象类型），而声明器拥有形式：

[ static(可选) 限定符(可选) 表达式(可选) ] 属性说明符序列(可选) | (1)
[ 限定符(可选) static(可选) 表达式(可选) ] 属性说明符序列(可选) | (2)
[ 限定符(可选) * ] 属性说明符序列(可选) | (3)
1,2) 生成通常数组语法
3) 声明未指定大小的 VLA （只能出现于函数原型作用域） 其中
表达式 | - | 任何无逗号运算符的表达式，表明数组中的元素数量
限定符 | - | 任意 const 、 restrict 或 volatile 限定符的混合，只允许出现于函数参数列表中；它们对数组参数所转换得到的指针类型赋予限定
属性说明符序列 | - | (C23)可选的属性列表，应用到被声明的数组
float fa[11], *afp[17]; // fa 是 11 个 float 组成的数组
                        // afp 是 17 个指向 float 的指针组成的数组

解释

有几种数组类型变体：已知常量大小的数组、变长度数组，以及未知大小数组。

已知常量大小数组

若数组声明器中的 表达式 为整数常量表达式，拥有大于零的值，且元素类型是一种拥有已知常量大小的类型（即元素不是 VLA ） (C99 起)，则声明器声明已知常量大小的数组：

int n[10]; // 整数常量是常量表达式
char o[sizeof(double)]; // sizeof 是常量表达式
enum { MAX_SZ=100 };
int n[MAX_SZ]; // 枚举常量是常量表达式

已知常量大小的数组可以用数组初始化器提供它们的初始值：

int a[5] = {1,2,3}; // 声明 int[5] 初始化为 1,2,3,0,0
char str[] = "abc"; // 声明 char[4] 初始化为 'a','b','c','\0'

在函数参数列表中，附加性语法元素允许出现于数组声明器内：关键词 static 及 限定符 ，它们可以以任意顺序先于大小表达式出现（它们甚至可以在大小表达式被忽略时出现）。

在每个到数组参数类型在 [ 和 ] 使用关键词 static 的函数的函数调用中，实际参数的值必须是一个指向数组首地址的合法指针，该数组元素数目至少为 表达式 的结果：

void fadd(double a[static 10], const double b[static 10])
{
    for (int i = 0; i < 10; i++) {
        if (a[i] < 0.0) return;
        a[i] += b[i];
    }
}
// 对 fadd 的调用可能进行编译时边界检查
// 并且允许诸如预读取 10 个 double 的优化
int main(void)
{
    double a[10] = {0}, b[20] = {0};
    fadd(a, b); // OK
    double x[5] = {0};
    fadd(x, b); // 未定义行为：数组参数太小
}

若存在 限定符 ，则它们对数组参数类型所转换得的指针类型赋予限定：

int f(const int a[20])
{
 // 此函数中， a 拥有类型 const int* （指向 const int 的指针）
}
int g(const int a[const 20])
{
 // 此函数中， a 拥有类型 const int* const （指向 const int 的 const 指针）
}

这通常用于 restrict 类型限定符：

void fadd(double a[static restrict 10],
          const double b[static restrict 10])
{
    for (int i = 0; i < 10; i++) { // 循环可被打开或重排
        if (a[i] < 0.0) break;
        a[i] += b[i];
    }
}

非常量长度数组

若 表达式 不是整数常量表达式，则数组声明器声明一个非常量大小的数组（ VLA ）。

每次控制流经过该声明时，会求值 表达式 （而且它必须每次求值为大于零的值），然后分配数组（对应地， VLA 的生存期在其声明离开作用域时结束）。 VLA 实例的大小不会在其生存期改变，但在另一次经过同一代码时，它可能被分配不同大小。

{
   int n = 1;
label:;
   int a[n]; // 重分配 10 次，每次拥有不同大小
   printf("The array has %zu elements\n", sizeof a / sizeof *a);
   if (n++ < 10) goto label; // 离开作用域的 VLA 结束其生存期
}

若大小是 * ，则声明是对于未指定大小的 VLA 的。这种声明只能出现于函数原型作用域，并声明一个完整类型的数组。其实，所有函数原型作用域中的 VLA 声明器都被处理成如同用 * 替换 表达式 。

void foo(size_t x, int a[*]);
void foo(size_t x, int a[x])
{
    printf("%zu\n", sizeof a); // 大小同sizeof(int*)
}

非常量长度数组与从它们派生的类型（指向它们的指针，等等）被通称为“可变修改类型”（ VM ）。任何可变修改类型的对象只能声明于块作用域或函数原型作用域中。

extern int n;
int A[n];            // 错误：文件作用域 VLA
extern int (*p2)[n]; // 错误：文件作用域 VM
int B[100];          // OK：文件作用域的已知常量大小数组
void fvla(int m, int C[m][m]); // OK：原型作用域 VLA

VLA 必须拥有自动或分配存储期。指向 VLA 的指针，但不是 VLA 自身亦可拥有静态存储期。 VM 类型不能拥有链接。

void fvla(int m, int C[m][m]) // OK ：块作用域/自动存储期到 VLA 的指针
{
    typedef int VLA[m][m]; // OK ：块作用域 VLA
    int D[m];              // OK ：块作用域/自动存储期 VLA
//  static int E[m]; // 错误：静态存储期 VLA
//  extern int F[m]; // 错误：拥有链接的 VLA
    int (*s)[m];     // OK：块作用域/自动存储期 VM
//  extern int (*r)[m]; // 错误：拥有链接的 VM
    static int (*q)[m] = &B; // 错误 ：静态存储期指针需要静态存储期的B来初始化，
                             // 但无法定义static int B[m];
    static int (*p)[m] = NULL;
    p = &B;
}

可变修改的类型不能是结构体或联合体的成员。

struct tag {
    int z[n]; // 错误： VLA 结构体成员
    int (*y)[n]; // 错误： VM 结构体成员
};
 (C99 起)

若编译器定义宏常量 __STDC_NO_VLA__ 为整数常量 1 ，则不提供 VLA 或 VM 。

 (C11 起)

未知大小数组

若忽略数组声明器中的 表达式，则它声明一个未知大小数组。除了函数参数列表中的情况（这种数组被转换成指针），而且当初始化器可用时，这种类型是一个不完整类型 （注意拥有未指定大小的VLA，以 * 代替大小声明时，它是完整类型） (C99 起)：

extern int x[]; // x 的类型是“边界未知的 int 数组”
int a[] = {1,2,3}; // a 的类型是“ 3 个 int 的数组”

在 struct 定义中，未知大小数组必须出现作最后一个元素（只要有一个具名成员），这种情况下，这是称为柔性数组成员的特殊情形。细节见 struct ：

struct s { int n; double d[]; }; // s.d 是柔性数组成员
struct s *s1 = malloc(sizeof (struct s) + (sizeof (double) * 8)); // 如同 d 是 d[8]

 (C99 起)

限定符

若数组类型声明拥有 const 、 volatile 、或 restrict (C99 起) 限定符（可以通过使用 typedef ），则数组类型无限定，但其元素类型有限定： | (C23 前)
始终认为数组类型与其元素类型有等同的限定，除了始终不认为数组类型有 _Atomic 限定： | (C23 起)
typedef int A[2][3];
const A a = {{4, 5, 6}, {7, 8, 9}}; // const int 的数组的数组
int* pi = a[0]; // 错误： a[0] 拥有类型 const int*
void *unqual_ptr = a; // C23 前 OK ； C23 起错误
// 注： clang 即使在 C89-C17 模式也应用 C++/C23 中的规则

不允许应用 _Atomic 到数组类型，尽管允许原子类型的数组。

typedef int A[2];
// _Atomic A a0 = {0};    // 错误
// _Atomic(A) a1 = {0};   // 错误
_Atomic int a2[2] = {0};  // OK
_Atomic(int) a3[2] = {0}; // OK
 (C11 起)

赋值

数组类型的对象不是可修改左值，尽管它们可以取地址，它们不能出现于赋值运算符的左侧。不过，拥有数组成员的结构体是可修改左值，并可以赋值：

int a[3] = {1,2,3}, b[3] = {4,5,6};
int (*p)[3] = &a; // OK ，可以取地址
// a = b;            // 错误，a 是数组
struct { int c[3]; } s1, s2 = {3,4,5};
s1 = s2; // OK ：可以赋值拥有数组成员的结构体

数组到指针转换

任何数组类型的左值表达式，当用于异于

  • 作为取地址运算符的操作数
  • 作为 sizeof 的操作数
  • 作为用于数组初始化的字符串字面量
  • 作为 _Alignof 的操作数
 (C11 起)

的语境时，会经历到指向其首元素指针的隐式转换。结果为非左值。

若声明数组为 register ，则尝试这么做的程序的行为未定义。

int a[3] = {1,2,3};
int* p = a;
printf("%zu\n", sizeof a); // 打印数组大小
printf("%zu\n", sizeof p); // 打印指针大小

当数组类型用于函数参数列表是，它会转换成对应的指针类型： int f(int a[2]) 和int f(int* a) 声明同一个函数。因为函数实际参数类型为指针类型，使用数组参数的函数调用会进行一个数组到指针转换；参数数组的大小不为被调用函数可得，而必须显式传递：

void f(int a[], int sz) // 实际上声明 void f(int* a, int sz)
{
    for(int i = 0; i < sz; ++i)
       printf("%d\n", a[i]);
}
int main(void)
{
    int a[10];
    f(a, 10); // 转换成 int* ，传递指针
}

多维数组

当数组的元素是另一个数组时，我们称数组是多维的：

// 2 个元素为 3 个 int 的数组的数组
int a[2][3] = {{1,2,3},  // 可视作行主导排列的
               {4,5,6}}; // 2x3 矩阵

注意当应用数组到指针转换是，多维数组被转换成指向其首元素的指针，例如指针到首行：

int a[2][3]; // 2x3 矩阵
int (*p1)[3] = a; // 指向首个 3 个元素行的指针
int b[3][3][3]; // 3x3x3 立方体
int (*p2)[3][3] = a; // 指向首个 3x3 平面的指针

若支持 VLA ，则 (C11 起)多维数组可以在每一维度可变修改：

int n = 10;
int a[n][2*n];
 (C99 起)

注解

不允许零长度数组，即使一些编译器作为扩展提供它们（典型例子是 C99 前的柔性数组成员实现）。

若 VLA 的大小 表达式 拥有副作用，则保证会正确产生副作用，除非它们是 sizeof 表达式的一部分，而结果不依赖副效应：

int n = 5;
size_t sz = sizeof(int (*)[n++]); // n 可以自增也可以不自增

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.7.6.2 Array declarators (p: 94-96)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.6.2 Array declarators (p: 130-132)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.5.2 Array declarators (p: 116-118)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.5.4.2 Array declarators

参阅


数组初始化

< c‎ | language

初始化 数组类型的对象时，初始化器必须是一个字符串字面量（可选地在花括号中），或是一个花括号环绕的被初始化数组成员列表：

= 字符串字面量 | (1) |
= { 表达式 , ... } | (2) | (C99 前)
= { 指派符(可选) 表达式 , ... } | (2) | (C99 起)
1) 字符串字面量初始化器，对应字符及宽字符数组
2) 作为数组成员初始化器的常量 (C99 前)表达式的逗号分隔列表，可以使用形为 [ 常量表达式 ] = 的数组指派符 (C99 起)

可初始化已知大小的数组和未知大小的数组，但不可初始化 VLA (C99 起)。

任何未被显示初始化的数组元素均被零初始化。

从字符串初始化

字符串字面量（可选地在花括号中）可以用作匹配数组类型的初始化器：

  • 通常字符串字面量及 UTF-8 字符串字面量 (C11 起)可用于初始化任何字符类型（ char 、 signed char 、 unsigned char ）的数组。
  • L 前缀的宽字符串字面量可用于初始化任何与 wchar_t 兼容（忽略 cv 限定）的类型的数组。
  • u 前缀宽字符串字面量可用于初始化任何与 char16_t 兼容（忽略 cv 限定）的类型的数组。
  • U 前缀宽字符串字面量可用于初始化任何与 char32_t 兼容（忽略 cv 限定）的类型的数组。
 (C11 起)

字符串字面量的连续字节，或宽字符串字面量的连续宽字符，包含空终止字节/字符，会初始化数组的元素：

char str[] = "abc"; // str 拥有类型 char[4] 并保有 'a', 'b', 'c', '\0'
wchar_t wstr[4] = L"猫"; // wstr 拥有类型 wchar_t[4] 并保有 L'猫', L'\0', L'\0', L'\0'

若数组大小已知，则它可以比字符串字面量的大小少一，此情况下空终止字符被忽略：

char str[3] = "abc"; // str 拥有类型 char[3] 并保有 'a', 'b', 'c'

注意这种数组的内容是可更改的，不同于直接以 char* str = "abc"; 访问字符串常量。

从花括号环绕列表初始化

当数组以花括号环绕的初始化器列表初始化时，首个初始化器初始化序号为零的数组元素（除非指定了指派符） (C99 起)，而每个不含指派符的 (C99 起)后继的初始化器所初始化的数组元素，序号比前一个初始化器所初始化的多一。

int x[] = {1,2,3}; // x 拥有类型 int[3] 并保有 1,2,3
int y[5] = {1,2,3}; // y 拥有类型 int[5] 并保有 1,2,3,0,0
int z[3] = {0}; // z 拥有类型 int[3] 并保有全零

在初始化已知大小数组时，提供多于元素数量的初始化器是错误（除了从字符串字面量初始化字符数组）。

指派符导致接下来的初始化器初始化指派符所描述的数组元素。然后初始化以向前顺序持续，从指派符所描述元素的下一个元素开始。

int n[5] = {[4]=5,[0]=1,2,3,4}; // 保有 1,2,3,4,5

int a[MAX] = { // 开始初始化 a[0] = 1, a[1] = 3, ...
    1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0
};
// 对于 MAX=6 ，数组保有 1,8,6,4,2,0
// 对于 MAX=13 ，数组保有 1,3,5,7,9,0,0,0,8,6,4,2,0（“稀疏数组”）
 (C99 起)

在初始化未知大小的数组时，指派初始化器的最大下标会确定所声明的数组大小。

嵌套数组

若数组的元素是数组、结构体或联合体，则对应的花括号环绕的初始化器列表中的初始化器是任何对于那些成员合法的初始化器，除了它们的花括号可以按如下方式省略：

若嵌套初始化器从左花括号开始，则整个直到其右花括号为止的初始化器初始化对应的数组元素：

int y[4][3] = { // 4 个 3 个 int 的数组的数组（ 4*3 矩阵）
    { 1 },      // 0 行初始化到 {1, 0, 0}
    { 0, 1 },   // 1 行初始化到 {0, 1, 0}
    { [2]=1 },  // 2 行初始化到 {0, 0, 1}
};              // 3 行初始化到 {0, 0, 0}

若嵌套初始化器不从左花括号开始，则只有的来自列表的充足的初始化器会被用于说明子数组、结构体或联合体；任何剩下的初始化器都被留作初始化下一个数组元素：

int y[4][3] = {    // 4 个 3 个 int 的数组的数组（ 4*3 矩阵）
1, 3, 5, 2, 4, 6, 3, 5, 7 // 0 行初始化到 {1, 3, 5}
};                        // 1 行初始化到 {2, 4, 6}
                          // 2 行初始化到 {3, 5, 7}
                          // 3 行初始化到 {0, 0, 0}

struct { int a[3], b; } w[] = { { 1 }, 2 }; // 结构体的数组
   // { 1 } 被视为完整花括号的初始化器，用于数组的 #0 元素
   // 该元素初始化为 { {1, 0, 0}, 0}
   // 2 被视为数组的 #1 元素的首个初始化
   // 该元素初始化为 { {2, 0, 0}, 0}

数组指代器可以嵌套；对于嵌套数组的带方括号常量表达式跟在对于外层数组的带方括号常量表达式之后：

int y[4][3] = {[0][0]=1, [1][1]=1, [2][0]=1};  // 0 行初始化为 {1, 0, 0}
                                               // 1 行初始化为 {0, 1, 0}
                                               // 2 行初始化为 {1, 0, 0}
                                               // 3 行初始化为 {0, 0, 0}
 (C99 起)

注解

数组初始化器中的子表达式求值顺序在 C 中是不定序的（但在从 C++11 开始的 C++ 中不是）：

int n = 1;
int a[2] = {n++, n++}; // 未指明，但是是良定义行为，
                       // n 自增二次（以任意顺序）
                       // a 初始化为 {1, 2} 和为 {2, 1} 均合法
puts((char[4]){'0'+n} + n++); // 未定义行为：
                              // n 的自增和读取是无序的

在 C 中，初始化器的花括号列表不能为空。 C++ 允许空列表：

int a[3] = {0}; // C 与 C++ 中均为清零块作用域数组的合法途径
int a[3] = {}; // C 中非法但在 C++ 中合法的清零块作用域数组的途径

与所有其他初始化一样，在初始化静态或线程局域存储期的数组时，初始化器列表中的每个表达式都必须是常量表达式：

static char* p[2] = {malloc(1), malloc(2)}; // 错误

示例

int main(void)
{
    // 下列四个数组的声明是相同的
    short q1[4][3][2] = {
        { 1 },
        { 2, 3 },
        { 4, 5, 6 }
    };

    short q2[4][3][2] = {1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0, 4, 5, 6};

    short q3[4][3][2] = {
        {
            { 1 },
        },
        {
            { 2, 3 },
        },
        {
            { 4, 5 },
            { 6 },
        }
    };

    short q4[4][3][2] = {1, [1]=2, 3, [2]=4, 5, 6};

    // 下标能与枚举常量关联
    // 使用带指派符的数组：
    enum { RED, GREEN, BLUE };
    const char *nm[] = {
        [RED] = "red",
        [GREEN] = "green",
        [BLUE] = "blue",
    };
}

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.9/12-38 Initialization (p: 140-144)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.8/12-38 Initialization (p: 126-130)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.5.7/12- Initialization


ASCII 码表

< c‎ | language

下表包含所有 128 个 ASCII 码对应的十进制 (dec) 、八进制 (oct) ，十六进制 (hex) 和字符 (ch) 的值。

dec | oct | hex | ch | dec | oct | hex | ch | dec | oct | hex | ch | dec | oct | hex | ch
0 | 0 | 00 | NUL (空) | 32 | 40 | 20 | (空格) | 64 | 100 | 40 | @ | 96 | 140 | 60 | `
1 | 1 | 01 | SOH (标题开始) | 33 | 41 | 21 | ! | 65 | 101 | 41 | A | 97 | 141 | 61 | a
2 | 2 | 02 | STX (正文开始) | 34 | 42 | 22 | " | 66 | 102 | 42 | B | 98 | 142 | 62 | b
3 | 3 | 03 | ETX (正文结束) | 35 | 43 | 23 | # | 67 | 103 | 43 | C | 99 | 143 | 63 | c
4 | 4 | 04 | EOT (传送结束) | 36 | 44 | 24 | $ | 68 | 104 | 44 | D | 100 | 144 | 64 | d
5 | 5 | 05 | ENQ (询问) | 37 | 45 | 25 | % | 69 | 105 | 45 | E | 101 | 145 | 65 | e
6 | 6 | 06 | ACK (确认) | 38 | 46 | 26 | & | 70 | 106 | 46 | F | 102 | 146 | 66 | f
7 | 7 | 07 | BEL (响铃) | 39 | 47 | 27 | ' | 71 | 107 | 47 | G | 103 | 147 | 67 | g
8 | 10 | 08 | BS (退格) | 40 | 50 | 28 | ( | 72 | 110 | 48 | H | 104 | 150 | 68 | h
9 | 11 | 09 | HT (横向制表) | 41 | 51 | 29 | ) | 73 | 111 | 49 | I | 105 | 151 | 69 | i
10 | 12 | 0a | LF (换行) | 42 | 52 | 2a | * | 74 | 112 | 4a | J | 106 | 152 | 6a | j
11 | 13 | 0b | VT (纵向制表) | 43 | 53 | 2b | + | 75 | 113 | 4b | K | 107 | 153 | 6b | k
12 | 14 | 0c | FF (换页) | 44 | 54 | 2c | , | 76 | 114 | 4c | L | 108 | 154 | 6c | l
13 | 15 | 0d | CR (回车) | 45 | 55 | 2d | - | 77 | 115 | 4d | M | 109 | 155 | 6d | m
14 | 16 | 0e | SO (移出) | 46 | 56 | 2e | . | 78 | 116 | 4e | N | 110 | 156 | 6e | n
15 | 17 | 0f | SI (移入) | 47 | 57 | 2f | / | 79 | 117 | 4f | O | 111 | 157 | 6f | o
16 | 20 | 10 | DLE (退出数据链) | 48 | 60 | 30 | 0 | 80 | 120 | 50 | P | 112 | 160 | 70 | p
17 | 21 | 11 | DC1 (设备控制1) | 49 | 61 | 31 | 1 | 81 | 121 | 51 | Q | 113 | 161 | 71 | q
18 | 22 | 12 | DC2 (设备控制2) | 50 | 62 | 32 | 2 | 82 | 122 | 52 | R | 114 | 162 | 72 | r
19 | 23 | 13 | DC3 (设备控制3) | 51 | 63 | 33 | 3 | 83 | 123 | 53 | S | 115 | 163 | 73 | s
20 | 24 | 14 | DC4 (设备控制4) | 52 | 64 | 34 | 4 | 84 | 124 | 54 | T | 116 | 164 | 74 | t
21 | 25 | 15 | NAK (反确认) | 53 | 65 | 35 | 5 | 85 | 125 | 55 | U | 117 | 165 | 75 | u
22 | 26 | 16 | SYN (同步空闲) | 54 | 66 | 36 | 6 | 86 | 126 | 56 | V | 118 | 166 | 76 | v
23 | 27 | 17 | ETB (传输块结束) | 55 | 67 | 37 | 7 | 87 | 127 | 57 | W | 119 | 167 | 77 | w
24 | 30 | 18 | CAN (取消) | 56 | 70 | 38 | 8 | 88 | 130 | 58 | X | 120 | 170 | 78 | x
25 | 31 | 19 | EM (媒介结束) | 57 | 71 | 39 | 9 | 89 | 131 | 59 | Y | 121 | 171 | 79 | y
26 | 32 | 1a | SUB (替换) | 58 | 72 | 3a | : | 90 | 132 | 5a | Z | 122 | 172 | 7a | z
27 | 33 | 1b | ESC (退出) | 59 | 73 | 3b | ; | 91 | 133 | 5b | [ | 123 | 173 | 7b | {
28 | 34 | 1c | FS (文件分隔符) | 60 | 74 | 3c | < | 92 | 134 | 5c | \ | 124 | 174 | 7c | |
29 | 35 | 1d | GS (组分隔符) | 61 | 75 | 3d | = | 93 | 135 | 5d | ] | 125 | 175 | 7d | }
30 | 36 | 1e | RS (记录分隔符) | 62 | 76 | 3e | > | 94 | 136 | 5e | ^ | 126 | 176 | 7e | ~
31 | 37 | 1f | US (单元分隔符) | 63 | 77 | 3f | ? | 95 | 137 | 5f | _ | 127 | 177 | 7f | DEL (删除)

注意：在 Unicode 中， ASCII 字符块被称作 U+0000..U+007F 基础拉丁（ Basic Latin ）。

示例

#include <stdio.h>

int main(void)
{
    puts("Printable ASCII:");
    for (int i = 32; i < 127; ++i) {
        putchar(i);
        putchar(i % 16 == 15 ? '\n' : ' ');
    }
}

可能的输出：

Printable ASCII:
  ! " # $ % & ' ( ) * + , - . /
0 1 2 3 4 5 6 7 8 9 : ; < = > ?
@ A B C D E F G H I J K L M N O
P Q R S T U V W X Y Z [ \ ] ^ _
` a b c d e f g h i j k l m n o
p q r s t u v w x y z { | } ~

参阅


内联汇编

< c‎ | language

内联汇编（常由 asm 关键词引入）给予在 C 程序中嵌入汇编语言源代码的能力。

不同于 C++ 中，内联汇编在 C 中被当作扩展。它是条件性支持及由实现定义的，意思是它可以不存在，而且即使实现有所提供，它也并不拥有固定的含义。

语法

asm ( 字符串字面量 ) ;
本节未完成
原因：写下关于 GCC 扩展汇编语法的注解，因为现在 Intel、IBM、Sun（自 v12 起）等均支持它

解释

这种内联汇编语法为 C++ 标准所接受，而在 C++ 中称为汇编声明。 字符串字面量 通常是以汇编语言编写的短程序，每当执行这条声明时对其执行。不同的 C 编译器拥有差异巨大的汇编声明规则，和与周围的 C 代码之间交互的不同约定。

汇编声明可出现于块（函数体或其他复合语句）内，而且同所有其他声明，此声明亦可出现于块外。

注解

MSVC 在 ARM 与 x64 处理器上不支持内联汇编，而且在 x86 处理器上仅支持由 __asm 引入的形式。

以 GCC 或 Clang 用 ISO C 模式编译（例如以选项 -std=c11 ）时，必须用 __asm__ 代替 asm 。

示例

演示 GCC 提供的二种内联汇编语法。此程序将只在 x86-64 上的 Linux 下正确工作。注意“标准内联汇编”在 C 标准中亦被当作扩展。

#include <stdio.h>

extern int func(void);
// func 的定义以汇编语言书写
__asm__(".globl func\n\t"
        ".type func, @function\n\t"
        "func:\n\t"
        ".cfi_startproc\n\t"
        "movl $7, %eax\n\t"
        "ret\n\t"
        ".cfi_endproc");

int main(void)
{
    int n = func();
    // gcc 的扩展内联汇编
    __asm__ ("leal (%0,%0,4),%0"
           : "=r" (n)
           : "0" (n));
    printf("7*5 = %d\n", n);
    fflush(stdout); // 冲刷是有意的

    // C++ 中的标准内联汇编
    __asm__ ("movq $60, %rax\n\t" // Linux 上的“退出”的系统调用序号
             "movq $2,  %rdi\n\t" // 此程序返回 2
             "syscall");
}

输出：

7*5 = 35

外部链接

  • GCC 内联汇编 HOWTO
  • IBM XL C/C++ 内联汇编
  • Intel C++ 内联汇编
  • Visual Studio 2013 内联汇编器
  • Sun Studio 12 Asm 语句
  • 基于 Itanium 的 HP-UX 的内联汇编

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • J.5.10 The asm keyword (p: 580)
  • C99 标准（ISO/IEC 9899:1999）：
  • J.5.10 The asm keyword (p: 512)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • G.5.10 The asm keyword

参阅


原子类型

< c‎ | language

语法

_Atomic ( 类型名 ) | (1) | (C11 起)
_Atomic 类型名 | (2) | (C11 起)
1) 用作类型说明符；指代新的原子类型
2) 用作类型限定符；指代 类型名 的原子版本。在此作用中，它可以与 const 、 volatile 及 restrict 混合使用。尽管不同于其他限定符， 类型名 的原子版本可能拥有不同的大小、对齐以及对象表示。
类型名 - 任何异于数组或函数的类型。对于 (1) ， t类型名 亦不能为原子或 cvr 限定

头文件 <stdatomic.h> 定义 37 个便利宏，从 atomic_bool 到 atomic_uintmax_t ，它们简化此关键词和内建及库类型的一同使用。

_Atomic const int * p1;  // p 是指向 _Atomic const int 的指针
const atomic_int * p2;   // 同上
const _Atomic(int) * p3; // 同上

解释

原子类型的对象是仅有的免除数据竞争的对象，即它们可以被两个线程共时修改，或先被一个修改再被另一个读取。.

每个原子对象都拥有关联于其自身的修改顺序，即对该对象的完整修改顺序。若从某个线程的视角来看，对于某原子对象M的修改 A 发生先于同一原子对象 M 的修改 B ，则在 M 的修改顺序中 A 的出现先于 B 。

注意即使每个原子对象都有其自身的修改顺序，却无单独的全序；不同线程可能会观测到不同原子对象有相异的修改顺序。

对于所有原子运算，保证有四种连贯：

  • 写写连贯：若原子对象 M 的修改操作 A 先发生于 M 的修改操作 B ，则 M 的修改顺序中 A 出现早于 B 。
  • 读读连贯：若原子对象 M 的值计算 A 先发生于 M 的值计算 B ，且从 M 上的副效应 X 求得 A 值，则 B 所计算得的值要么是 X 所存储的值，要么是 M 上的副效应 Y 所存储的值，其中 Y 在 M 的修改顺序中出现后于 X 。
  • 读写连贯：若原子对象 M 的值计算 A 先发生于 M 上的操作 B ，则从 M 上的副效应 X 求得 A 值，这里 X 在 M 的修改顺序中出现先于 B 。
  • 写读连贯：若在原子对象 M 上的副效应 X 先发生于 M 的值计算 B ，则求值 B 从 X，或从在 M 的修改顺序中出现后于 X 的副效应 Y 求得其值。

一些原子运算亦是同步操作：它们可以拥有附加的释放语义、获取语义，或顺序一致语义。见 memory_order 。

内建的自增减运算符和复合赋值运算符是拥有完全序列一致顺序（如同用 memory_order_seq_cst ）的读-修改-写操作。若想要较不严格的同步语义，则可以用标准库函数替代。

原子属性仅对左值表达式有意义。左值到右值转换（模仿从原子区域到 CPU 寄存器的内存读取）会把原子性及其他限定符剥去。

本节未完成
原因：更多和 memory_order 及原子库页面的综述互动

注解

若编译器定义了宏常量 __STDC_NO_ATOMICS__ ，则不提供关键词 _Atomic 以及 <stdatomic.h> 。

访问原子结构体/联合体的成员是未定义行为。

库类型 sig_atomic_t 不提供线程间同步或内存顺序，仅提供原子性。

volatile 类型不提供线程间同步、内存顺序或原子性。

推荐实现确保对于每个可能的类型 T ， C 中 _Atomic(T) 的表示与 C++ 中 std::atomic<T> 的相同。用于确保原子性与内存顺序的机制应该兼容。

关键词

_Atomic

示例

#include <stdio.h>
#include <threads.h>
#include <stdatomic.h>

atomic_int acnt;
int cnt;

int f(void* thr_data)
{
    for(int n = 0; n < 1000; ++n) {
        ++cnt;
        ++acnt;
        // 对于此例，宽松内存顺序是足够的，例如
        // atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed);
    }
    return 0;
}

int main(void)
{
    thrd_t thr[10];
    for(int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for(int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);

    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

可能的输出：

The atomic counter is 10000
The non-atomic counter is 8644

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.7.2.4 Atomic type specifiers (p: 87)
  • 7.17 Atomics <stdatomic.h> (p: 200-209)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.2.4 Atomic type specifiers (p: 121)
  • 7.17 Atomics <stdatomic.h> (p: 273-286)

参阅


属性说明符序列(C23 起)

< c‎ | language

对类型、对象、表达式等引入实现定义的属性。

[[attr]] [[attr1, attr2, attr3(args)]] [[属性前缀::attr(arg)]]

正式而言，语法是

[[ 属性列表 ]] (C23 起)

其中 属性列表 是零或多个 属性记号 的逗号分隔列表

标准属性 | (1)
属性前缀 :: 标识符 | (2)
标准属性 ( 实参列表 ) | (3)
属性前缀 :: 标识符 ( 实参列表 ) | (4)
1) 标准属性，例如 [[fallthrough]]
2) 有命名空间的属性，例如 [[gnu::unused]]
3) 有实参的标准属性，例如 [[deprecated("reason")]]
4) 有命名空间和实参列表的属性

解释

属性为各种由实现定义的语言扩展（例如 GNU 与 IBM 的语言扩展 __attribute__((...))，微软的语言扩展 __declspec() 等）提供了统一化的语法。

属性可用在 C 程序中的几乎所有位置，而且可应用于几乎所有事物：类型、变量、函数、名字、代码块、整个翻译单元，不过每个特定的属性都仅在实现所容许之处有效：[[expect_true]] 可能是只能与 if，而非与类声明一同使用的属性，[[omp::parallel()]] 可能是应用到代码块或 for 循环，而非到类型 int 等的属性。（请注意这两个属性只是虚构的例子，有关标准与一些非标准属性，见下文）

在声明中，属性可出现在整个声明之前，或直接跟在被声明实体的名字之后，这些情况下它们被组合起来。大多数其他情形中，属性应用于直接位于其之前的实体。

不同于 C++ 中的 alignas 与 [[noreturn]] ， _Alignas 与 _Noreturn 说明符不是属性说明符序列的一部分。

两个连续的方括号记号（[[）只能出现于引入属性说明符之处，或在属性实参之内。

除了以下所列出的标准属性之外，实现还可能支持任意拥有由实现定义的行为的非标准属性。所有实现所未知的属性均被忽略，且不产生错误。

每个 标准属性 均为标准化保留。即每个非标准属性均由实现提供的 属性前缀 冠以前缀，例如 [[gnu::may_alias]] 与 [[clang::no_sanitize]] 。

标准属性

C++ 标准仅定义下列属性。每个名字形如 attr 的标准属性亦能拼写成 __attr__ 而其含义不变。

[[deprecated]](C23) [[deprecated("reason")]](C23) | 指示允许使用声明有此属性的名称或实体，但因 reason 而不鼓励使用。
[[fallthrough]](C23) | 指示从前一 case 标号直落是有意的，而在发生直落时给出警告的编译器不应该为此诊断。
[[nodiscard]](C23) [[nodiscard("reason")]](C23) | 若返回值被舍弃，则鼓励编译器发布警告。
[[maybe_unused]](C23) | 抑制编译器在未使用实体上的警告，若存在。

属性测试

__has_c_attribute( 属性记号 )

检查 属性记号 所指名的属性记号的存在。

对于标准属性，它将展开成该属性被添加到工作草案中时的年份和月份（见下表），特定于厂商的属性则以某个非零整数常量确定。

能在 #if 与 #elif 的表达式中展开 __has_c_attribute 。 #ifdef 、 #ifndef 和 defined 把它当做已定义的宏，但不能在别处使用它。

属性记号 | 属性 | 值 | 标准
deprecated | [[deprecated]] | 201904L | (C23)
fallthrough | [[fallthrough]] | 201904L | (C23)
maybe_unused | [[maybe_unused]] | 201904L | (C23)
nodiscard | [[nodiscard]] | 202003L | (C23)

示例

[[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]]
int f(void); // 声明 f 带四个属性

[[gnu::always_inline, gnu::const, gnu::hot, nodiscard]]
int f(void); // 同上，但用含四个属性的单个属性说明符

int f(void) { return 0; }

int main(void)
{
}

外部链接

  • Clang 中的属性

参阅


C 属性： deprecated (C23 起)

< c‎ | language‎ | attributes

指示声明有此属性的名字或实体被弃用，即允许但因故不鼓励使用。

语法

[[ deprecated ]] [[ __deprecated__ ]] | (1)
[[ deprecated ( 字符串字面量 ) ]] [[ __deprecated__ ( 字符串字面量 ) ]] | (2)
字符串字面量 - 能用于解释弃用的理由并/或提议代替用实体的文本

解释

指示允许使用声明带此属性的名字或实体，但因某原因不鼓励。编译器常对这些情况发出警告。若指定 字符串字面量 ，则通常将它包含于警告中。

下列名字或实体的声明中允许使用这个属性：

  • 结构体/联合体： struct [[deprecated]] S; ，
  • typedef 名： [[deprecated]] typedef S* PS; ，
  • 对象： [[deprecated]] int x; ，
  • 结构体/联合体成员： union U { [[deprecated]] int n; }; ，
  • 函数： [[deprecated]] void f(void); ，
  • 枚举： enum [[deprecated]] E {}; ，
  • 枚举项： enum { A [[deprecated]], B [[deprecated]] = 42 }; 。

声明时未弃用的名字可被重声明为 deprecated。声明为 deprecated 的名字不能通过重声明它而不带此属性变为未弃用。

示例

#include <stdio.h>

[[deprecated]]
void TriassicPeriod(void)
{
    puts("Triassic Period: [251.9 - 208.5] million years ago.");
}

[[deprecated("Use NeogenePeriod() instead.")]]
void JurassicPeriod(void)
{
    puts("Jurassic Period: [201.3 - 152.1] million years ago.");
}

[[deprecated("Use calcSomethingDifferently(int).")]]
int calcSomething(int x)
{
    return x * 2;
}

int main(void)
{
    TriassicPeriod();
    JurassicPeriod();
}

可能的输出：

Triassic Period: [251.9 - 208.5] million years ago.
Jurassic Period: [201.3 - 152.1] million years ago.

prog.c:23:5: warning: 'TriassicPeriod' is deprecated [-Wdeprecated-declarations]
    TriassicPeriod();
    ^
prog.c:3:3: note: 'TriassicPeriod' has been explicitly marked deprecated here
[[deprecated]]
  ^
prog.c:24:5: warning: 'JurassicPeriod' is deprecated: Use NeogenePeriod() instead. [-Wdeprecated-declarations]
    JurassicPeriod();
    ^
prog.c:9:3: note: 'JurassicPeriod' has been explicitly marked deprecated here
[[deprecated("Use NeogenePeriod() instead.")]]
  ^
2 warnings generated.

参阅


C 属性： fallthrough (C23 起)

< c‎ | language‎ | attributes

指示从前一标号直落是有意的，而在发生直落时给出警告的编译器不应诊断它。

语法

[[ fallthrough ]]
[[ __fallthrough__ ]]

解释

仅可用于属性声明以创建直落声明（[[fallthrough]];）。

直落声明仅可用于 switch 语句中，其中要遇到的下个块项（语句、声明或标号）是该 switch 语句的带 case 或 default 标号的语句。

指示从前一标号直落是有意的，而在发生直落时给出警告的编译器不应诊断它。

示例

#include <stdbool.h>

void g(void) {}
void h(void) {}
void i(void) {}

void f(int n) {
  switch (n) {
    case 1:
    case 2:
      g();
     [[fallthrough]];
    case 3: // 直落时不警告
      h();
    case 4: // 编译器可在发生直落时警告
      if(n < 3) {
          i();
          [[fallthrough]]; // OK
      }
      else {
          return;
      }
    case 5:
      while (false) {
        [[fallthrough]]; // 谬构：下一语句不是同一迭代的一部分
      }
    case 6:
      [[fallthrough]]; // 谬构：下一语句不是同一迭代的一部分
  }
}

int main(void) {}

参阅


C 属性： maybe_unused (C23 起)

< c‎ | language‎ | attributes

抑制对未使用实体的警告。

语法

[[ maybe_unused ]]
[[ __maybe_unused__ ]]

解释

此属性能出现在下列实体的声明中：

  • 结构体/联合体： struct [[maybe_unused]] S; ，
  • typedef 名： [[maybe_unused]] typedef S* PS; ，
  • 对象： [[maybe_unused]] int x; ，
  • 结构体/联合体成员： union U { [[maybe_unused]] int n; }; ，
  • 函数： [[maybe_unused]] void f(void); ，
  • 枚举： enum [[maybe_unused]] E {}; ，
  • 枚举项： enum { A [[maybe_unused]], B [[maybe_unused]] = 42 }; 。

若编译器对未使用实体发布警告，则对任何声明为 maybe_unused 的实体抑制该警告。

示例

#include <assert.h>

[[maybe_unused]] void f([[maybe_unused]] _Bool cond1, [[maybe_unused]] _Bool cond2)
{
   [[maybe_unused]] _Bool b = cond1 && cond2;
   assert(b); // 发布模式中， assert 被编译掉，而 b 不被使用
              // 无警告，因为它声明为 [[maybe_unused]]
} // 参数 cond1 与 cond2 不被使用，无警告

int main(void)
{
    f(1, 1);
}

参阅


C 属性： nodiscard (C23 起)

< c‎ | language‎ | attributes

若从转型到 void 以外的弃值表达式，调用声明为 nodiscard 的函数，或调用返回声明 nodiscard 的结构体/联合体/枚举的函数，则鼓励编译器发出警告。

语法

[[ nodiscard ]] [[ __nodiscard__ ]] | (1)
[[ nodiscard ( 字符串字面量 ) ]] [[ __nodiscard__ ( 字符串字面量 ) ]] | (2)
字符串字面量 - 能用于解释为何不应舍弃结果的原理的文本

解释

出现于函数声明、枚举声明或结构体/联合体声明。

若从转型到 void 以外的弃值表达式，

  • 调用声明为 nodiscard 的函数，或
  • 调用返回声明 nodiscard 的结构体/联合体/枚举的函数，

则鼓励编译器发出警告。

若指定 字符串字面量 则通常包含它于警告中。

示例

struct [[nodiscard]] error_info { int status; /*...*/ };
struct error_info enable_missile_safety_mode() { /*...*/ return (struct error_info){0}; }
void launch_missiles() { /*...*/ }
void test_missiles() {
   enable_missile_safety_mode(); // 编译器可能在舍弃 nodiscard 值时警告
   launch_missiles();
}
struct error_info* foo() { static struct error_info e; /*...*/ return &e; }
void f1() {
    foo(); // 不以值返回 nodiscard 类型，无警告
}
// nodiscard( string-literal ):
[[nodiscard("PURE FUN")]] int strategic_value(int x, int y) { return x ^ y; }

int main()
{
    strategic_value(4,2); // compiler may warn on discarding a nodiscard value
    int z = strategic_value(0,0); // OK: return value is not discarded
    return z;
}

可能的输出：

game.cpp:5:4: warning: ignoring return value of function declared with 'nodiscard' attribute
game.cpp:17:5: warning: ignoring return value of function declared with 'nodiscard' attribute: PURE FUN

参阅


未定义行为

< c‎ | language

C 语言标准精确指定了 C 语言程序的可观察行为，除了下列分类之一：

  • 未定义行为 - 程序的该行为没有限制。未定义行为的例子是越过数组边界的访问、有符号整数溢出、空指针解引用、在表达式中超过一次修改标量而其中无顺序点、通过不同类型的指针访问对象，等等。编译器不要求诊断未定义行为（尽管多数简单情形是得到诊断的），且编译后的程序不要求做任何有意义的事。
  • 未指定行为 - 容许二种或多种行为，且不要求实现规范每种行为。例如，求值顺序、同样的字符串字面量是否有别，等。每个未指定行为导致一组合法结果之一，并且可以在同一程序中重复时产生不同结果。
  • 实现定义行为 - 在未指定行为之上，实现规范了如何选择。例如，字节中的位数，或有符号整数右移是算术还是逻辑。
  • 本地环境限定行为 - 依赖于当前选择的本地环境的实现定义行为。例如， islower 对任何 26 个小写拉丁字母外的字符是否返回 true。

（注意：严格遵从的程序不依赖任何未指定、未定义或实现定义行为）

要求编译器对违背任何 C 语法规则或语义约束的任何程序发布诊断消息（错误或警告），即使其行为被指定为未定义或实现定义，或者编译器可提供语言扩展以允许此种程序被接受。另外，不要求对未定义行为诊断。

UB 与优化

因为正确的 C 程序是没有未定义行为的，编译器可以在启用优化的条件下编译确实有 UB 的程序时，生成不期待的结果：

例如，

有符号溢出

int foo(int x) {
    return x+1 > x; // 真或为有符号溢出导致的 UB
}

可以编译成（演示）

foo:
        movl    $1, %eax
        ret

越界访问

int table[4] = {0};
int exists_in_table(int v)
{
    // 在最初的 4 个迭代中返回真或因为越界访问 UB
    for (int i = 0; i <= 4; i++) {
        if (table[i] == v) return 1;
    }
    return 0;
}

可以编译成（演示）

exists_in_table:
        movl    $1, %eax
        ret

未初始化标量

_Bool p; // 未初始化局部变量
if(p) // 访问未初始化标量是 UB
    puts("p is true");
if(!p) // 访问未初始化标量是 UB
    puts("p is false");

可能产生下列输出（可在一个旧版本 gcc 观察到）：

p is true
p is false
size_t f(int x)
{
    size_t a;
    if(x) // x为非零或UB
        a = 42;
    return a;
}

可以编译成（演示）

f:
        mov     eax, 42
        ret

非法标量

int f(void) {
  _Bool b = 0;
  unsigned char* p =(unsigned char*)&b;
  *p = 10;
  // 从 b 读取现在是 UB
  return b == 0;
}

可编译成（演示）

f():
        movl    $11, %eax
        ret

空指针解引用

int foo(int* p) {
    int x = *p;
    if(!p) return x; // 为上述 UB ，或绝不采用此分支
    else return 0;
}
int bar() {
    int* p = NULL;
    return *p;       // 无条件 UB
}

可以编译成（ foo 用 gcc ， bar 用 clang ）

foo:
        xorl    %eax, %eax
        ret
bar:
        retq

访问传递给 realloc 的指针

选择 Clang 以观察示出的输出

#include <stdio.h>
#include <stdlib.h>
int main(void) {
    int *p = (int*)malloc(sizeof(int));
    int *q = (int*)realloc(p, sizeof(int));
    *p = 1; // 访问传递给 realloc 的指针是 UB
    *q = 2;
    if (p == q) // 访问传递给 realloc 的指针是 UB
        printf("%d%d\n", *p, *q);
}

可能的输出：

12

无副效应的无限循环

选择 Clang 以观察示出的输出

#include <stdio.h>

int fermat() {
  const int MAX = 1000;
  int a=1,b=1,c=1;
  // 无副效应的无限循环是 UB
  while (1) {
    if (((a*a*a) == ((b*b*b)+(c*c*c)))) return 1;
    a++;
    if (a>MAX) { a=1; b++; }
    if (b>MAX) { b=1; c++; }
    if (c>MAX) { c=1;}
  }
  return 0;
}

int main(void) {
  if (fermat())
    puts("Fermat's Last Theorem has been disproved.");
  else
    puts("Fermat's Last Theorem has not been disproved.");
}

可能的输出：

Fermat's Last Theorem has been disproved.

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 3.4 Behavior (p: 3-4)
  • 4/2 Undefined behavior (p: 8)
  • C99 标准（ISO/IEC 9899:1999）：
  • 3.4 Behavior (p: 3-4)
  • 4/2 Undefined behavior (p: 7)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 1.6 DEFINITIONS OF TERMS

外部链接

  • 每个 C 程序员都该知道关于未定义行为的事 #1/3
  • 每个 C 程序员都该知道关于未定义行为的事 #2/3
  • 每个 C 程序员都该知道关于未定义行为的事 #3/3
  • 未定义行为能导致时间旅行（在所有事项中，时间旅行可是最惊人的）
  • 了解 C/C++ 中的整数溢出
  • 未定义行为及费马最后定理
  • 空指针的趣事， part 1 （ Linux 2.6.30 中由空指针解引用导致的未定义行为所引发的局部滥用）

参阅


位域

< c‎ | language

声明拥有以位数表示的显式宽度的成员。相邻的位域成员可能被打包，共享和分散到单独的字节。

位域声明是使用下列声明器的结构体或联合体成员声明：

标识符(可选) : 宽度
标识符 | - | 正在声明的位域名称。名称是可选的：无名位域引入一个指定的填充位数
宽度 | - | 一个拥有大于或等于零，且小于或等于底层类型位数的整数常量表达式。大于零时，此为此位域将占据的位数。零值仅允许用于无名位域，并拥有特殊含义：它指定结构体定义中的下个位域会从分配单元边界开始。

解释

位域可以拥有四种类型之一（可为 const 或 volatile 限定）：

  • unsigned int ，对于无符号位域（ unsigned int b:3; 拥有范围 0..7 ）
  • signed int ，对于有符号位域（ signed int b:3; 拥有范围 -4..3 ）
  • int ，对于拥有实现定义符号性的位域（注意这与其他所有地方都表示“ signed int ”的关键词 int 含义不同）。例如， int b:3; 可能拥有 0..7 或 -4..3 范围的值。
  • _Bool ，对于单个位的位域（ bool x:1; 拥有范围 0..1 ），来自它和到它的隐式转换遵循布尔转换规则。
 (C99 起)

可接受额外的实现定义类型。位域是否可以拥有原子类型也是实现定义的。 (C11 起)位域中的位数（ 宽度 ）限制其所能保有的值域：

#include <stdio.h>
struct S {
 // 三位无符号位域，允许值为 0..7
 unsigned int b : 3;
};
int main(void)
{
    struct S s = {7};
    ++s.b; // 无符号溢出
    printf("%d\n", s.b); // 输出： 0
}

允许将多个相邻位域打包在一起（通常如此）：

#include <stdio.h>
struct S {
    // 通常将占用 4 字节：
    // 5 位： b1 的值
    // 11 位：未使用
    // 6 位： b2 的值
    // 2 位： b3 的值
    // 8 位：未使用
    unsigned b1 : 5, : 11, b2 : 6, b3 : 2;
};
int main(void)
{
    printf("%zu\n",sizeof(struct S)); // 通常打印 4
}

拥有零 宽度 的特殊无名位域打破填充：它指定下个位域在始于下个分配单元的起点：

#include <stdio.h>
struct S {
    // 通常将占用 8 字节
    // 5 位： b1 的值
    // 27 位：未使用
    // 6 位： b2 的值
    // 15 位： b3 的值
    // 11 位：未使用
    unsigned b1 : 5;
    unsigned :0; // 开始新的 unsigned int
    unsigned b2 : 6;
    unsigned b3 : 15;
};
int main(void)
{
    printf("%zu\n", sizeof(struct S)); // 通常打印 8
}

因为位域不必在字节的起点开始，故不能取位域的地址。不可能有指向位域的指针。不能对位域使用 sizeof 和 _Alignas (C11 起)。

注解

位域的下列属性未定义：

  • 在位域上调用 offsetof 的效果

位域的下列属性未指定：

  • 保有位域的分配单元的对齐

位域的下列属性为实现定义：

  • int 类型的位域被当做有符号或无符号
  • 是否容许异于 int 、 signed int 、 unsigned int 及 _Bool (C99 起) 类型的位域
  • 是否容许原子类型的位域
 (C11 起)
  • 位域是否能越过分配单元边界
  • 分配单元内位域的顺序（一些平台上位域从左往右打包，其他平台上是从右往左）

尽管 _Bool 的对象表示的位数至少为 CHAR_BIT ， _Bool 类型位域的 宽度 不能大于 1 。

 (C99 起)

C++ 编程语言中，位域的宽度能超出底层类型，并且 int 类型的位域始终为有符号。

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.7.2.1 Structure and union specifiers
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.2.1 Structure and union specifiers
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.2.1 Structure and union specifiers
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.5.2.1 Structure and union specifiers

参阅


break 语句

< c‎ | language

导致外围 for 、 while 或 do-while 循环或 switch 语句终止。

在用条件表达式和条件语句终止循环显得笨拙时使用。

语法

属性说明符序列(可选) break ;
属性说明符序列 - (C23)可选的属性列表，应用到 break 语句

只出现在循环体（ while、 do-while、 for ）的 语句 内，或 switch 的 语句 内。

解释

此语句后，控制被转移到紧随整个循环或 switch 之后的声明或语句，如同由 goto 进行。

关键词

break

注解

break 语句不能用于打破多重嵌套循环。 goto 语句可用于此目的。

示例

#include <stdio.h>

int main(void)
{
    int i = 2;
    switch (i) {
        case 1: printf("1");
        case 2: printf("2");   // i==2 ，故执行始于此 case 标号
        case 3: printf("3");
        case 4:
        case 5: printf("45");
                break;         // 导致后续的 case 终止
        case 6: printf("6");
    }
    printf("\n");

    // 比较来自这二个循环嵌套的输出
    for (int j = 0; j < 2; j++)
        for (int k = 0; k < 5; k++)
            printf("%d%d ", j,k);
    printf("\n");
    for (int j = 0; j < 2; j++) {
        for (int k = 0; k < 5; k++) { // 只有此循环会由 break 退出
            if (k == 2) break;
            printf("%d%d ", j,k);
        }
    }
}

输出：

2345
00 01 02 03 04 10 11 12 13 14
00 01 10 11

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.8.6.3 The break statement (p: 111)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.8.6.3 The break statement (p: 153)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.8.6.3 The break statement (p: 138)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.6.6.3 The break statement

参阅


字符常量

< c‎ | language

语法

' c-char ' | (1) |
u8 ' c-char ' | (2) | (C23 起)
u ' c-char ' | (3) | (C11 起)
U ' c-char ' | (4) | (C11 起)
L ' c-char ' | (5) |
' c-char-sequence ' | (6) |

其中

  • c-char 是以下之一
  • 来自基本源字符集减去单引号（ ' ）、反斜杠（ \ ）或换行符的字符。
  • 转义序列：特殊字符转义 \' \" \? \\ \a \b \f \n \r \t \v 、十六进制转义 \x... 或八进制转义 \... 之一，如转义序列中所定义。
  • 通用字符名， \u... 或 \U... ，如转义序列中所定义。
 (C99 起)
  • c-char-sequence 为二个或更多 c-char 的序列。
1) 单字节整数字符常量，例如 'a' 或 '\n' 或 '\13' 。这种常量拥有 int 类型，和等于 c-char 在执行字符集中作为映射到 int 的 char 类型值的值。若 c-char 不能表示成执行字符集中的单字节，则值是实现定义的。
2) UTF-8 字符常量，例如 u8'a' 。这种常量拥有 unsigned char 类型和等于 c-char 的 ISO 10646 码位值的值，只要该码位值能以单个 UTF-8 编码单元表示（即 c-char 在含上下界的范围 0x0-0x7F 内）。若 c-char 不可表示为单个 UTF-8 编码单元，则程序为非良构。
2) 16 位宽字符常量，例如 u'字' 但非 u'🍌' （ u'\U0001f34c' ）。这种常量拥有 char16_t 类型，和等于 mbrtoc16 所产生的 c-char 于 16 位编码（通常为 UTF-16 ）中值的值。若 c-char 不能表示为，或映射到多于一个 16 位字符，则值是实现定义的。
3) 32 位宽字符常量，例如 U'字' 或 U'🍌' 。这种常量拥有 char32_t 类型，和等于 mbrtoc32 所产生的 c-char 于 32 位编码（通常为 UTF-32 ）中值的值。若 c-char 不能表示为，或映射到多于一个 32 位字符，则值是实现定义的。
4) 宽字符常量，例如 L'β' 或 L'字' 。这种常量拥有 wchar_t 类型，和等于 c-char 在执行宽字符集中的值的值（即 mbtowc 会产生的值）。若 c-char 不能表示为或映射到多于一个宽字符（例如 Windows 上的非 BMP 值，其中 wchar_t 为 16 位），则值是实现定义的。
5) 多字符常量，例如 'AB' 拥有 int 类型和实现定义值。

注解

多字符常量是 C 从 B 编程语言继承而来的。尽管 C 标准不指定，大多数编译器（值得注意的例外是 MSVC ）也如 B 中所指定实现多字符常量：常量中的每个字符的值以大端序零填充右对齐顺序初始化结果整数的相继字节，例如 '\1' 的值为 0x00000001 而 '\1\2\3\4' 的值为 0x01020304 。

C++ 中，可编码的通常字符字面量拥有 char 类型，而非 int 。

不同于整数常量，若 char 有符号，则字符常量可以有负值：这种实现中 '\xFF' 是拥有值 -1 的 int 。

用于 #if 或 #elif 控制表达式时，可能按照源字符集、执行字符集或其他实现定义的字符集转译字符常量。

示例

#include <stddef.h>
#include <stdio.h>
#include <uchar.h>

int main (void)
{
    printf("constant    value     \n");
    printf("--------    ----------\n");

    // 整数字符常量
    int c1='a'; printf("'a':        %#010x\n", c1);
    int c2='🍌'; printf("'🍌':       %#010x\n\n", c2); // 实现定义

    // 多字符常量
    int c3='ab'; printf("'ab':       %#010x\n\n", c3); // 实现定义

    // 16 位宽字符常量
    char16_t uc1 = u'a'; printf("'a':        %#010x\n", (int)uc1);
    char16_t uc2 = u'¢'; printf("'¢':        %#010x\n", (int)uc2);
    char16_t uc3 = u'猫'; printf("'猫':       %#010x\n", (int)uc3);
    // 实现定义（ 🍌 映射到二个 16 位宽字符）
    char16_t uc4 = u'🍌'; printf("'🍌':       %#010x\n\n", (int)uc4);

    // 32 位宽字符常量
    char32_t Uc1 = U'a'; printf("'a':        %#010x\n", (int)Uc1);
    char32_t Uc2 = U'¢'; printf("'¢':        %#010x\n", (int)Uc2);
    char32_t Uc3 = U'猫'; printf("'猫':       %#010x\n", (int)Uc3);
    char32_t Uc4 = U'🍌'; printf("'🍌':       %#010x\n\n", (int)Uc4);

    // 宽字符常量
    wchar_t wc1 = L'a'; printf("'a':        %#010x\n", (int)wc1);
    wchar_t wc2 = L'¢'; printf("'¢':        %#010x\n", (int)wc2);
    wchar_t wc3 = L'猫'; printf("'猫':       %#010x\n", (int)wc3);
    wchar_t wc4 = L'🍌'; printf("'🍌':       %#010x\n\n", (int)wc4);
}

可能的输出：

constant    value
--------    ----------
'a':        0x00000061
'🍌':       0xf09f8d8c

'ab':       0x00006162

'a':        0x00000061
'¢':        0x000000a2
'猫':       0x0000732b
'🍌':       0x0000df4c

'a':        0x00000061
'¢':        0x000000a2
'猫':       0x0000732b
'🍌':       0x0001f34c

'a':        0x00000061
'¢':        0x000000a2
'猫':       0x0000732b
'🍌':       0x0001f34c

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.4.4.4 Character constants (p: 48-50)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.4.4.4 Character constants (p: 67-70)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.4.4.4 Character constants (p: 59-61)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.1.3.4 Character constants

参阅


复合字面量

< c‎ | language

就地构造一个指定类型的无名对象，在只需要一次数组、结构体或联合体变量时使用。

语法

( type ) { initializer-list } (C99 起)

其中

type | - | 指定任何完整对象类型或未知大小的数组的类型名，但不能是 VLA
initializer-list | - | 适合 type 类型变量初始化的初始化器列表

解释

复合字面量构造一个 type 所指定类型的无名对象，并以 initializer-list 的指定初始化之。

复合字面量的类型是 type （除非 type 是未知大小的数组；如在数组初始化中一般从 initializer-list 推导出其大小）。

复合字面量的值类别是左值（能取其地址）。

若复合字面量出现于文件作用域，则其求值所得的无名对象拥有静态存储期，若复合字面量出现于块作用域，则该对象拥有自动存储期（此情况下对象的生存期结束于外围块的结尾）。

注意

字符或宽字符数组类型的 const 限定复合字面量，可能会与字符串字面量共享存储。

(const char []){"abc"} == "abc" // 可以为 1 或 0 ，实现定义

每个复合字面量仅在其作用域内创建一个对象：

int f (void)
{
    struct s {int i;} *p = 0, *q;
    int j = 0;
again:
    q = p, p = &((struct s){ j++ });
    if (j < 2) goto again; // 注意：若使用循环，则其作用域会结束于此，
                           // 这会终止复合字面量的生存期，
                           // 令 p 为悬垂指针
    return p == q && q->i == 1; // 始终返回 1
}

因为复合字面量是无名的，一个复合字面量不能引用自身（一个具名结构体可以包含指向其自身的指针）。

虽然复合字面量的语法和转型相似，重要的区别是转型是非左值表达式，而复合字面量是左值。

示例

int *p = (int[]){2, 4}; // 创建一个无名的 int[2] 类型静态存储数组
                        // 初始数组为值 {2, 4}
                        // 创建指向数组首元素的指针 p
const float *pc = (const float []){1e0, 1e1, 1e2}; // 只读复合字面量

int main(void)
{
    int n = 2, *p = &n;
    p = (int [2]){*p}; // 创建一个无名的 int[2] 类型自动存储数组
                       // 初始化首个元素为之前 *p 所持有的值
                       // 初始化第二个元素为零
                       // 将首元素的地址存储到 p

    struct point {double x,y;};
    void drawline1(struct point from, struct point to);
    void drawline2(struct point *from, struct point *to);
    drawline1((struct point){.x=1, .y=1},  // 创建二个块作用域的结构体
              (struct point){.x=3, .y=4}); // 然后调用 drawline1 ，以值传递
    drawline2(&(struct point){.x=1, .y=1},  // 创建二个块作用域的结构体
              &(struct point){.x=3, .y=4}); // 然后调用 drawline2 ，传递其地址
}

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.5.2.5 Compound literals (p: 85-87)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.5.2.5 Compound literals (p: 75-77)


const 类型限定符

< c‎ | language

C 类型系统中每一个独立的类型在都有数个该类型的限定版本，对应 const 、 volatile 及对于指向对象指针的 restrict 限定符中的一个、两个或全部三个。此页面描述 const 限定符的效果。

编译器可以把声明带 const 限定类型的对象放到只读内存中，而且若程序决不取该 const 对象的地址，则可能完全不存储它。

const 语义仅应用到左值表达式；只要在不要求左值的语境中使用 const 左值表达式，就会丢失其 const 限定符（注意不丢失 volatile 限定符，若它存在）。

指代 const 限定类型对象的左值表达式，和指代拥有至少一个 const 限定类型成员（包含为聚合体或联合体所递归含有的成员）的结构体或联合体的左值表达式，不是可修改左值。具体而言，它们不可赋值：

const int n = 1; // const 类型对象
n = 2; // 错误： n 的类型为 const 限定

int x = 2; // 无限定类型对下
const int* p = &x;
*p = 3; // 错误：左值 *p 的类型为 const 限定

struct {int a; const int b; } s1 = {.b=1}, s2 = {.b=2};
s1 = s2; // 错误： s1 的类型无限定，但它有 const 成员

const 限定的结构体或联合体类型的成员，取得它所属类型的限定版本（在用 . 运算符或 -> 运算符访问时）。

struct s { int i; const int ci; } s;
// s.i 的类型为 int ， s.ci 的类型为 const int
const struct s cs;
// cs.i 和 cs.ci 的类型都是 const int
若以 const 类型限定符声明数组类型（通过使用 typedef ），则数组类型无 const 限定，但其元素类型有。 | (C23 前)
始终认为数组类型与其元素类型同等地拥有 const 限定。 | (C23 起)

若以 const 类型限定符声明函数类型（通过使用 typedef ），则行为未定义。

typedef int A[2][3];
const A a = {{4, 5, 6}, {7, 8, 9}}; // const int 的数组的数组
int* pi = a[0]; // 错误： a[0] 拥有 const int* 类型
void *unqual_ptr = a; // C23 前 OK ； C23 起错误
// 注： clang 即使在 C89-C17 模式也应用 C++/C23 中的规则

const 限定的复合字面量不必指代相异的对象；能与恰好拥有重叠表示的其他复合字面量和字符串字面量一同存储它们。

const int* p1 = (const int[]){1, 2, 3};
const int* p2 = (const int[]){2, 3, 4}; // p2 的值可等于 p1+1
_Bool b = "foobar" + 3 == (const char[]){"bar"}; // b 的值可为 1
 (C99 起)

指向非 const 类型的指针能隐式转换成指向同一或兼容类型的 const 限定版本的指针。能用转型表达式进行逆向转换。

int* p = 0;
const int* cp = p; // OK ：添加限定符（ int 到 const int ）
p = cp; // 错误：舍弃限定符（ const int 到 int ）
p = (int*)cp; // OK ：转型

注意指向指向 T 指针的指针不可转换为指向指向 const T 指针的指针；对于要兼容的二个类型，其限定必须等同。

char *p = 0;
const char **cpp = &p; // 错误： char* 与 const char* 不是兼容类型
char * const *pcp = &p; // OK ：添加限定符（ char * 到 char *const ）

任何修改有 const 限定类型的对象的尝试导致未定义行为。

const int n = 1; // const 限定类型对象
int* p = (int*)&n;
*p = 2; // 未定义行为

函数声明中，关键词 const 可出现在用于声明数组类型函数参数的方括号内。它限定数组类型变换到的指针类型。

下列二个声明声明同一函数：

void f(double x[const], const double y[const]);
void f(double * const x, const double * const y);
 (C99 起)

关键词

const

注解

C 从 C++ 接纳了 const 限定符，但不同于 C++ 中， C 中 const 限定类型的表达式不是常量表达式；它们不可用作 case 标号，或用于初始化静态和线程存储期对象、用作枚举项或位域大小。以之为数组大小是，产生的数组为 VLA 。

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.7.3 Type qualifiers (p: 87-90)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.3 Type qualifiers (p: 121-123)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.3 Type qualifiers (p: 108-110)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 6.5.3 Type qualifiers

参阅


常量表达式

< c‎ | language

表达式的数种变体被称为常量表达式。

预处理器常量表达式

后随 #if 或 #elif 的表达式必须展开成

  • 赋值、自增、自减、函数调用或逗号以外的，参数为预处理器常量表达式的运算符
  • 整数常量
  • 字符常量
  • 特殊预处理器运算符 defined

字符常量在 #if 表达式中求值时，可能以源字符集、执行字符集或某个其他实现定义字符集转译。

#if 表达式中，对有符号类型以 intmax_t 的语义，而对无符号类型以 uintmax_t 的语义进行整数算术。

 (C99 起)

整数常量表达式

整数常量表达式是仅由下列内容组成的表达式

  • 赋值、自增、自减、函数调用或逗号以外的运算符，除了转型运算符只能转型算术类型为整数类型
  • 整数常量
  • 枚举常量
  • 字符常量
  • 浮点常量，但仅若立即以之为转型到整数类型的操作数
  • 操作数非 VLA 的 (C99 起) sizeof 运算符
  • _Alignof 运算符
 (C11 起)

整数常量表达式在编译时求值。下列语境要求被称为整数常量表达式的表达式：

  • 位域的大小
  • 枚举常量的值
  • switch 语句的 case 标号
  • 非 VLA (C99 起)数组的大小
  • 整数到指针隐式转换。
  • 数组指派符的下标
 (C99 起)
  • _Static_assert 的首参数
  • _Alignas 的整数参数
 (C11 起)

静态初始化器

拥有静态和线程局域存储期的对象初始化器中使用的表达式必须是下列表达式之一

1) 算术常量表达式，即由下列内容构成的任何算术类型表达式
  • 赋值、自增、自减、函数调用或逗号以外的运算符，除了转型运算符必须转换算术类型到其他算术类型
  • 整数常量
  • 浮点常量
  • 枚举常量
  • 字符常量
  • 操作数非 VLA 的 (C99 起) sizeof 运算符
  • _Alignof 运算符
 (C11 起)
2) 空指针常量 NULL
3) 地址常量表达式，即
  • 空指针
  • 指代静态存储期的对象的左值，或函数指代器，通过下列方式之一转换为指针
  • 用一元取址运算符
  • 转型整数常量到指针
  • 数组到指针或函数到指针隐式转换
4) 某完整对象类型的地址常量表达式加或减一个整数常量表达式
5) 实现所接受的其他形式之一的常量表达式。

不同于整数常量表达式，不要求静态初始化器在编译时求值；编译器有将这种初始化器转变为在程序启动前调用的可执行代码的自由。

static int i = 2 || 1 / 0; // 初始化 i 为值 1
本节未完成
原因：其他小示例

浮点静态初始化器的值的精度决不低于在运行时执行的同一表达式，但可以高于后者。

浮点常量表达式

不用于静态初始化器中的浮点类型的算术常量表达式，始终如同在运行时求值，受当前舍入影响（若 FENV_ACCESS 为 ON ），并报告 math_errhandling 中指定的错误。

void f(void)
{
#pragma STDC FENV_ACCESS ON
    static float x = 0.0/0.0; // 静态初始化器：不引发异常
    float w[] = { 0.0/0.0 }; // 引发异常
    float y = 0.0/0.0; // 引发异常
    double z = 0.0/0.0; // 引发异常
}

注解

若表达式求值到的值不能以其类型表示，则不能以之为常量表达式。

实现可以接受其他形式的常量表达式。然而，这些常量表达式不被认为是整数常量表达式、算术常量表达式或地址常量表达式，从而不能用于要求这些种类的常量表达式的语境。

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.6 Constant expressions (p: 76-77)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.6 Constant expressions (p: 106-107)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.6 Constant expressions (p: 95-96)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.4 CONSTANT EXPRESSIONS

参阅


continue语句

< c‎ | language

导致跳过整个 for、 while 或 do-while 循环体的剩余部分。

在使用条件语句忽略循环剩余部分显得笨拙时使用。

语法

属性说明符序列(可选) continue ;
属性说明符序列 - (C23)可选的属性列表，应用到 continue 语句

解释

continue 语句导致如同用 goto 跳转到循环体的结尾（它仅能出现在 for、 while 及 do-while 的循环体内）。

对于 while 循环，它表现为

while (/* ... */) {
   // ...
   continue; // 表现为 goto contin;
   // ...
   contin:;
}

对于 do-while 循环，它表现为：

do {
    // ...
    continue; // 表现为 goto contin;
    // ...
    contin:;
} while (/* ... */);

对于 for 循环，它表现为：

for (/* ... */) {
    // ...
    continue; // 表现为 goto contin;
    // ...
    contin:;
}

关键词

continue

示例

#include <stdio.h>

int main(void)
{
    for (int i = 0; i < 10; i++) {
        if (i != 5) continue;
        printf("%d ", i);             // 每次 i != 5 时跳过此语句
    }

    printf("\n");

    for (int j = 0; j < 2; j++) {
        for (int k = 0; k < 5; k++) { // 只有此循环受 continue 影响
            if (k == 3) continue;
            printf("%d%d ", j, k);    // 每次 k == 3 时跳过此语句
        }
    }
}

输出：

5
00 01 02 04 10 11 12 14

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.8.6.2 The continue statement (p: 111)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.8.6.2 The continue statement (p: 153)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.8.6.2 The continue statement (p: 138)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.6.6.2 The continue statement

参阅


声明

< c‎ | language

声明是一个引入一个或多个标识符到程序中，并指定其含义及属性的 C 语言构造。

声明可以出现在任何作用域中。每个声明以分号结束（类似语句），并由两 (C23 前)三 (C23 起)个独立部分组成：

说明符与限定符 声明符与初始化器(可选) ; | (1) |
属性说明符序列 说明符与限定符 声明符与初始化器 ; | (2) | (C23 起)
属性说明符序列 ; | (3) | (C23 起)

其中

说明符与限定符 - 任意顺序的下列内容的空白符分隔列表
  • 类型说明符：
  • void
  • 算术类型名
  • 原子类型名
  • 先前由 typedef 声明引入的名称
  • struct 、 union 或 enum 说明符
  • 零或一个存储类说明符： typedef、 auto、 register、 static、 extern、 _Thread_local
  • 零或多个类型限定符： const 、 volatile、 restrict、 _Atomic
  • （只在声明函数时）零或多个函数说明符： inline 、 _Noreturn
  • 零或多个对齐说明符： _Alignas
声明符与初始化器 - 声明符 的逗号分隔列表（每个声明符提供附加类型信息及/或要声明的标识符）。声明符可伴随初始化器。 enum 、 struct 和 union 声明可忽略 声明符 ，这种情况下它们仅引入枚举常量和/或标签。
属性说明符序列 - (C23)可选的属性列表，应用到被声明的实体，或若单独出现则构成属性声明。
1-2) 简单声明。引入一或多个标识符，它们代表对象、函数、结构体/联合体/枚举标签、 typedef 或枚举常量。
3) 属性声明。不声明任何标识符，并且若标准不指定含义则拥有实现定义的含义。

例如：

int a, *b=NULL; // “ int ”是类型说明符，
                // “ a ”是声明符
                // “ *b ”是声明符而 NULL 是初始化器
const int *f(void); // “ int ”是类型说明符
                    // “ const ”是类型限定符
                    // “ *f(void) ”是声明符
enum COLOR {RED, GREEN, BLUE} c; // “ enum COLOR {RED, GREEN, BLUE} ”是类型说明符
                                 // “ c ”是声明符

一个声明引入的每个标识符类型是通过 类型说明符 所指定的类型及其 声明符 所应用的类型修饰决定的。

属性 (C23 起)可在 说明符与限定符 中出现，该情况下它们应用到前导的说明符所确定的类型。

声明符

每个声明符是下列之一：

标识符 属性说明符序列(可选) | (1)
( 声明符 ) | (2)
* 属性说明符序列(可选) 限定符(可选) 声明符 | (3)
无指针声明符 [ static(可选) 限定符(可选) 表达式 ] 无指针声明符 [ 限定符(可选) * ] | (4)
无指针声明符 ( 形参或标识符 ) | (5)
1) 此声明符引入的标识符。
2) 任何可以放入括号中的声明符；引入指向数组或指向函数指针时要求这么做。
3) 指针声明符：声明 S * cvr D 声明 D 为 cvr 限定指针，指向 S 所确定的类型。
4) 数组声明符：声明 S D[N] 声明 D 为有 N 个 S 所确定类型对象的数组。 无指针声明符 是无括号指针声明符以外的其他任何声明符。
5) 函数声明符：声明 S D(params) 声明 D 为接收参数 params 并返回 S 的函数。 无指针声明符 是无括号指针声明符以外的其他任何声明符。

此语法背后的原因，是当声明符所声明的标识符以与声明符相同的形式出现在表达式中时，它会拥有类型说明符序列所指定的类型。

struct C {
    int member; // “ int ”是类型说明符
                // “ member ”是声明符
} obj, *pObj = &obj;
// “ struct C { int member; } ”是类型说明符
// 声明符“ obj ”定义 struct C 类型的对象
// 声明符“ *pObj ”声明指向 struct C 的指针，
// 初始化器“ = &obj ”提供该指针的初值

int a = 1, *p = NULL, f(void), (*pf)(double);
// 类型说明符是“ int ”
// 声明符“ a ”定义一个 int 类型对象
//   初始化器“=1”提供其初值
// 声明符“ *p ”定义一个指向 int 指针类型的对象
//   初始化器“ =NULL ”提供其初值
// 声明符“ f(void) ”声明接受 void 并返回 int 的函数
// 声明符“ (*pf)(double) ”定义一个指向
//   接受 double 并返回 int 的函数的指针类型对象

int (*(*foo)(double))[3] = NULL;
// 类型说明符是“int”
// 1. 声明符“ (*(*foo)(double))[3] ”是数组声明符：
//    所声明类型是“ 3 个 int 的数组的 /嵌套声明符/ ”
// 2. 嵌套声明符是“ *(*foo)(double)) ”，是指针声明符
//    所声明类型是“ /嵌套声明符/ 指向 3 个 int 的数组的指针”
// 3. 嵌套声明符是“ (*foo)(double) ”，是一个函数声明符
//    所声明类型是“ /嵌套声明符/ 接受 double 并返回指向 3 个 int 的数组的指针的函数”
// 4. 嵌套声明符是“ (*foo) ”，是一个（有括号，函数声明符所要求）指针声明符。
//    所声明类型是“ /嵌套声明符/ 指向接受 double 并返回指向 3 个 int 的数组的指针的函数的指针”
// 5. 嵌套声明符是“ foo ”，是一个标识符。
// 该声明引入一个标识符“ foo ”，以指代一个对象，其类型为
// “指向接受 double 并返回指向 3 个 int 的数组的指针的函数的指针”
// 初始化器“ = NULL ”提供此指针的初值。

// 若在用于声明符形式的表达式使用“foo”，则表达式类型将是int。
int x = (*(*foo)(1.2))[0];

每个不属于其他声明符一部分的声明符结尾是一个顺序点。

所有情况下， 属性说明符序列 均为可选的属性 (C23 起)序列。立即出现在标识符后时，它应用到被声明的对象或函数。

定义

定义是一个提供所有关于其所声明标识符信息的声明。

每个 enum 或 typedef 声明都是定义。

对于函数，包含函数体的声明即是函数定义：

int foo(double); // 声明
int foo(double x){ return x; } // 定义

对于对象，分配其存储的声明（自动或静态，但、非 extern ）即是定义，而一个不分配存储的声明（外部声明）不是。

extern int n; // 声明
int n = 10; // 定义

对于结构体和联合体，指定其成员列表的声明是定义：

struct X; // 声明
struct X { int n; }; // 定义

重声明

若另一个同一标识符的声明在同一作用域的较早部分出现，则声明不可再引入同一标识符，除非

  • 有链接对象（外部或内部）的声明可以重复：
extern int x;
int x = 10; // OK
extern int x; // OK

static int n;
static int n = 10; // OK
static int n; // OK
  • 非 VLA typedef 可以任意重复，只要它指名同一类型：
typedef int int_t;
typedef int int_t; // OK
  • struct 和 union 声明可以重复：
struct X;
struct X { int n; };
struct X;

这些规则会简化头文件的使用。

注解

C89 中，任何复合语句（块作用域）中的声明必须出现在块的开头，在任何语句之前。

而且，C89 中返回 int 的函数可以隐式地用函数调用运算符声明，且使用旧式函数定义时， int 类型的函数参数不必声明。

 (C99 前)

禁止空声明符；简单声明必须拥有至少一个声明符，或声明至少一个 struct/union/enum 标签，或引入至少一个枚举常量。

若声明符的任一部分是非常量长度数组（ VLA ）声明符，则整个声明符的类型被称作“可变修改类型”。根据可变修改类型定义的类型同样是可变修改的（ VM ）。

任何可变修改类型声明只允许出现在块作用域或函数原型作用域，而且不能是任何结构体或联合体的成员。尽管 VLA 只能拥有自动或分配存储期，一个 VM 类型，例如指向 VLA 的指针也可以有静态存储。关于 VM 类型有其他使用限制，见 goto、 switch、 longjmp 。

 (C99 起)

_Static_assert 从 C 文法的视角来看，被认为是声明（故它们可以出现在任何声明能出现的地方），但它们不会引入任何新的标识符，且不遵循声明语法。

 (C11 起)

属性声明亦被认为是声明（故它们可以出现在任何声明能出现的地方），但它们不会引入任何新的标识符。单个无 属性说明符序列 的 ; 不是属性声明，而是语句。

 (C23 起)

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.7 Declarations (p: 78-105)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7 Declarations (p: 108-145)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7 Declarations (p: 97-130)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.5 Declarations

参阅


do-while 循环

< c‎ | language

重复执行 语句 ，直到条件 表达式 的值变为假。此测试在每次迭代后发生。

语法

属性说明符序列(可选) do 语句 while ( 表达式 ) ;
表达式 | - | 任何标量类型的表达式。此表达式在每次迭代后求值，而且若它与零比较相等，则退出循环。
语句 | - | 任何语句，常为一条复合语句，作为循环体
属性说明符序列 | - | (C23)可选的属性列表，应用到循环语句

解释

do-while 语句导致重复执行 语句 （亦称为循环体），直至 表达式 （亦称为控制表达式）与 0 比较相等。不管是正常进入循环体还是以 goto 进入 语句 内部，都会发生重复。

在每次执行 语句 后对 表达式 求值（无论是正常进入还是用 goto ）。若需要在循环体前求值控制表达式，则可以使用 while 循环或 for 循环。

若循环的执行需要在某点终止，则能以 break 语句为终止语句。

若循环的执行需要从循环体的结尾继续，则能以 continue 语句为快捷方式。

若无限循环在其 语句 或 表达式 的任何部分无可观测行为（ I/O 、 volatile 访问、原子或同步操作），则拥有这种循环的程序有未定义行为。这允许编译器优化掉整个不可观测循环，而无需证明他们会结束。仅有的例外是 表达式 为常量表达式的循环： do {...} while(true); 始终是无限循环。

同所有选择和迭代语句， do-while 语句建立块作用域：任何于 表达式 中引入的标识符在语句后离开作用域。

 (C99 起)

注解

通常以布尔和指针表达式为控制表达式。布尔值 false 和任何指针类型的空指针值与零比较相等。

关键词

do, while

示例

#include <stdio.h>
#include <stdlib.h>
enum { SIZE = 8 };
int main(void)
{
    // 平凡示例
    int array[SIZE], n = 0;
    do array[n++] = rand() % 2; // 循环体是单条表达式语句
    while(n < SIZE);
    puts("Array filled!");
    n = 0;
    do { // 循环体是复合语句
        printf("%d ", array[n]);
        ++n;
    } while (n < SIZE);
    printf("\n");

    // 来自 K&R itoa() 的循环。使用了 do-while 循环
    // 因为始终至少要生成一位
    int num = 1234, i=0;
    char s[10];
    do s[i++] = num % 10 + '0'; // 以反转顺序到下个数位
    while ((num /= 10) > 0);
    s[i] = '\0';
    puts(s);
}

可能的输出：

Array filled!
1 0 1 1 1 1 0 0
4321

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.8.5.2 The do statement (p: 109)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.8.5.2 The do statement (p: 151)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.8.5.2 The do statement (p: 136)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.6.5.2 The do statement

参阅


枚举

< c‎ | language

枚举类型是独立的类型，其值为包含所有其显示命名的常量（枚举常量）的底层类型的值。

语法

枚举类型在声明文法中以跟随的枚举说明符作为 类型说明符 声明：

enum 属性声明符序列(可选) 标识符(可选) { 枚举项列表 }

其中 枚举项列表 是 枚举项 的逗号分隔列表（允许尾随的逗号） (C99 起)，每个 枚举项 拥有形式：

枚举常量 属性声明符序列(可选) | (1)
枚举常量 属性声明符序列(可选) = 常量表达式 | (2)

其中

标识符, 枚举常量 - 由此声明引入的标识符
常量表达式 - 整数常量表达式，其值可以以 int 类型的值表示
属性声明符序列 - (C23)可选的属性列表，
  • 若出现在 enum 后则应用到整个枚举，
  • 若出现在 枚举常量 后则应用到 枚举项

与结构体或联合体一样，引入枚举类型和一或多个枚举常量的声明亦可声明一或多个该类型的对象，或从该类型派生的类型的对象。

enum color_t {RED, GREEN, BLUE} c = RED, *cp = &c;
// 引入类型 enum color_t
// 整数常量 RED 、 GREEN 、 BLUE
// 对象 c 拥有类型 enum color_t
// 对象 cp 的类型为指向 enum color_t 的指针

解释

每个出现于枚举说明符体中的 枚举常量 会成为 int 类型的整数常量，并处于包围它的作用域中，而且在凡要求整数常量处可用（例如，作为 case 标号或非 VLA 数组大小）。

enum color { RED, GREEN, BLUE } r = RED;
switch(r) {
case RED:
    puts("red");
    break;
case GREEN:
    puts("green");
    break;
case BLUE:
    puts("blue");
    break;
}

若 枚举常量 后随 = 常量表达式 ，则其值为该常量表达式的值。若 枚举常量 没有后随 = 常量表达式 ，则其值是比同一枚举中前一枚举项的值大一的值。首个枚举项（若它不用 = 常量表达式 ）的值是零。

enum Foo { A, B, C=10, D, E=1, F, G=F+C};
// A=0, B=1, C=10, D=11, E=1, F=2, G=12

若使用 标识符 ，则其自身成为标签命名空间中枚举类型的名称，且需要使用关键词 enum （除非 typedef 到通常命名空间）。

enum color { RED, GREEN, BLUE };
enum color r = RED; // OK
// color x = GREEN: // 错误： color 不在通常命名空间中
typedef enum color color_t;
color_t x = GREEN; // OK

每个枚举类型与如下之一兼容： char 、有符号整数类型或无符号整数类型。对于任何枚举类型，哪一个类型是兼容的是实现定义的，但无论是那种类型，都必须有足以表示该枚举中所有枚举项的值。

枚举类型是整数类型，从而可以用于任何其他整数类型能用之处，包括隐式转换和算术运算符。

enum { ONE = 1, TWO } e;
long n = ONE; // 提升
double d = ONE; // 转换
e = 1.2; // 转换，e 现在是 ONE
e = e + 1; // e 现在是 TWO

注解

不同于 struct 或 union ， C 中没有 enum 的前置声明：

enum Color; // 错误：C 中无 enum 的前置声明
enum Color { RED, GREEN, BLUE };

枚举允许以比 #define 更加便利和结构化的方式生成具名常量；它们可见于调试器，遵循作用域规则，并且参与类型系统。

#define TEN 10
struct S { int x : TEN; }; // OK

或

enum { TEN = 10 };
struct S { int x : TEN; }; // 也 OK

另外，由于 C 中结构体或联合体不建立其作用域，可以在前者的成员说明中引入枚举类型及其枚举常量，而之后其作用域与前者相同。

struct Element {
    int z;
    enum State { SOLID, LIQUID, GAS, PLASMA } state;
} oxygen = { 8, GAS };
// 类型 enum State 与其枚举常量于此保持可见，例如
void foo(void) {
    enum State e = LIQUID; // OK
    printf("%d %d %d ", e, oxygen.state, PLASMA); // 打印 1 2 3
}

示例

#include <stdio.h>

int main(void)
{
    enum TV { FOX = 11, CNN = 25, ESPN = 15, HBO = 22, MAX = 30, NBC = 32 };

    printf("List of cable stations: \n");
    printf(" FOX: \t%2d\n", FOX);
    printf(" HBO: \t%2d\n", HBO);
    printf(" MAX: \t%2d\n", MAX);
}

输出：

List of cable stations:
 FOX:   11
 HBO:   22
 MAX:   30

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.2.5/16 Types (p: 32)
  • 6.7.2.2 Enumeration specifiers (p: 84-85)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.2.5/16 Types (p: 41)
  • 6.7.2.2 Enumeration specifiers (p: 117-118)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.2.5/16 Types (p: 35)
  • 6.7.2.2 Enumeration specifiers (p: 105-106)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.1.2.5 Types
  • 3.5.2.2 Enumeration specifiers

关键词

enum

参阅


转义序列

< c‎ | language

转义序列用于在字符串字面量和字符常量中表示某些特殊字符。

下列转义序列可用。 ISO C 要求诊断是否有任何不列于此的字符出现于反斜杠之后：

转义序列 | 描述 | 表示
简单转义序列
\' | 单引号 | ASCII 编码中为字节 0x27
\" | 双引号 | ASCII 编码中为字节 0x22
\? | 问号 | ASCII 编码中为字节 0x3f
\\ | 反斜杠 | ASCII 编码中为字节 0x5c
\a | 响铃 | ASCII 编码中为字节 0x07
\b | 退格 | ASCII 编码中为字节 0x08
\f | 换页 | ASCII 编码中为字节 0x0c
\n | 换行 | ASCII 编码中为字节 0x0a
\r | 回车 | ASCII 编码中为字节 0x0d
\t | 水平制表 | ASCII 编码中为字节 0x09
\v | 垂直制表 | ASCII 编码中为字节 0x0b
数值转义序列
\nnn | 任意八进制值 | 字节 nnn
\xnn | 任意十六进制值 | 字节 nn
通用字符名
\unnnn (C99 起) | 允许范围中的 Unicode 值 可能生成多个编码单元 | 码位 U+nnnn
\Unnnnnnnn (C99 起) | 允许范围中的 Unicode 值 可能生成多个编码单元 | 码位 U+nnnnnnnn

通用字符名的范围

若通用字符名对应不是 0x24 ($)、 0x40 (@) 或 0x60 (`) 的小于 0xA0 的码位，或代理码位（范围 0xD800-0xDFFF，含两端），则程序为谬构。换言之，基础源字符集的成员与控制字符（在范围 0x0-0x1F 与 0x7F-0x9F 中）不能以通用字符名表达。

对应大于 0x10FFFF 的码位的通用字符名（在 ISO/IEC 10646 中未定义）能用于字符常量与字符串字面量。 C++20 中不允许这种用法。

 (C99 起)

注解

\0 在八进制转义序列中最常用，因为它表示空终止字符串中的空终止字符。

换行符 \n 在用于文本模式 I/O 时有特殊含义：它被转换为 OS 限定的换行表示，通常是字节或字节序列。某些系统替而用长度域标记其文本行。

八进制转义序列拥有三个八进制位的长度限制，但若提前遇到不是合法八进制位的字符，则在首个这种字符处终止。

十六进制转义序列无长度限制，并在首个不是合法十六进制位的字符处终止。若单个十六进制转义序列所表示的值不适于此字符串字面量或字符常量中使用的字符类型（ char、 char16_t、 char32_t (C11 起) 或 wchar_t ），则结果未指定。

窄字符串字面量或 16 位字符串字面量 (C11 起)中的通用字符名可能映射到多于一个编码单元，例如 \U0001f34c 在 UTF-8 中是 4 个 char 编码单元（ \xF0\x9F\x8D\x8C ），而在 UTF-16 中是 2 个 char16_t 编码单元（ \xD83C\xDF4C ） (C11 起)。

 (C99 起)

问号转义序列 \? 用于阻止在字符串字面量内转译三标符：如 "??/" 的字符串被编译成 "\" ，但若如在 "?\?/" 中转义第二个问号，则它变为 "??/" 。

示例

#include <stdio.h>

int main(void)
{
    printf("This\nis\na\ntest\n\nShe said, \"How are you?\"\n");
}

输出：

This
is
a
test

She said, "How are you?"

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 5.2.2 Character display semantics (p: 18-19)
  • 6.4.3 Universal Character names (p: 44)
  • 6.4.4.4 Character constants (p: 48-50)
  • C11 标准（ISO/IEC 9899:2011）：
  • 5.2.2 Character display semantics (p: 24-25)
  • 6.4.3 Universal Character names (p: 61)
  • 6.4.4.4 Character constants (p: 67-70)
  • C99 标准（ISO/IEC 9899:1999）：
  • 5.2.2 Character display semantics (p: 19-20)
  • 6.4.3 Universal Character names (p: 53)
  • 6.4.4.4 Character constants (p: 59-61)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 2.2.2 Character display semantics
  • 3.1.3.4 Character constants

参阅

  • ASCII 码表


表达式

< c‎ | language

表达式是运算符及其操作数的序列，它指定一个运算。

表达式求值可以产生结果（例如求值 2+2 产生结果 4 ，可能产生副效应（例如求值 printf ("%d",4) 会将字符 '4' 送到标准输出流），并可以指代对象或函数。

综述

  • 值类别（左值、非左值对象、函数指代器）将表达式以其值分类
  • 参数和子表达式的求值顺序指定会得到何种中间结果

运算符

常用运算符
赋值 自增
自减 		算术 逻辑 比较 成员
访问 		其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b

a[b]
*a
&a
a->b
a.b

a(...)
a, b
(type) a
? :
sizeof
_Alignof (C11 起)
  • 运算符优先级定义运算符绑定到其参数的顺序
  • 替用表示是一些运算符的替用写法

转换

  • 隐式转换在操作数类型不符合运算符期待时发生。
  • 转型可用于显示将值的类型从一个转到另一个。

其他

  • 常量表达式可以在编译时求值，并用于编译时语境（非 VLA (C99 起)数组大小、静态初始化器等）
  • 泛型选择可以根据参数类型调用不同的表达式
 (C11 起)
  • 浮点表达式可能会引发浮点异常，并报告 math_errhandling 中指定的错误
  • 标准 #pragma ： FENV_ACCESS 、 FP_CONTRACT 及 CX_LIMITED_RANGE 还有浮点求值精度和舍入方向控制浮点表达式求值方式。
 (C99 起)

初等表达式

运算符的操作数可为其他表达式，或初等表达式（例如 1+2*3 中，运算符 + 的操作数是子表达式 2*3 和初等表达式 1 ）。

初等表达式可以是下列之一：

1) 常量及字面量（例如 2 或 "Hello, world" ）
2) 适合的已声明标识符（例如 n 或 printf ）
3) 泛型选择
 (C11 起)

任何在括号中的表达式亦被分类为基础表达式：这保证括号拥有高于任何运算符的优先级。

常量及字面量

某些类型的常量值可用称为字面量（对于左值表达式）和常量（对于右值表达式）的特殊表达式嵌入到 C 程序源代码中，。

  • 整数常量是十进制、八进制或十六进制的整数类型数字。
  • 字符常量是 int 类型，适于转换到字符类型、 char16_t 、 char32_t (C11 起)或 wchar_t 类型的单个字符。
  • 浮点常量是 float 、 double 或 long double 类型值。
  • 字符串字面量是类型为 char[] 、 char16_t[] 、 char32_t[] (C11 起)或 wchar_t[] 的一系列字符，表示空终止字符串。
  • 复合字面量是直接嵌入程序代码的结构体、联合体或数组类型的值。
 (C99 起)

不求值表达式

sizeof 运算符的操作数是不求值的表达式（除非它们是 VLA ） (C99 起)。故而 size_t n = sizeof( printf ("%d", 4)); 不会进行控制台输出。

_Alignof 运算符的操作数、泛型选择的控制表达式及作为 _Alignof 的操作数的 VLA 的大小表达式亦为不求值的表达式。

 (C11 起)

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.5 Expressions (p: 55-75)
  • 6.6 Constant expressions (p: 76-77)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.5 Expressions (p: 76-105)
  • 6.6 Constant expressions (p: 106-107)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.5 Expressions (p: 67-94)
  • 6.6 Constant expressions (p: 95-96)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.3 EXPRESSIONS
  • 3.4 CONSTANT EXPRESSIONS

参阅


浮点常量

< c‎ | language

允许直接在表达式中使用浮点类型值。

语法

浮点常量是非左值表达式，拥有下列形式

有效数字 指数(可选) 后缀(可选)

其中 有效数字 拥有形式

整数(可选) .(可选) 小数(可选)

指数 拥有形式

e | E 指数符号(可选) 数字序列 | (1) |
p | P 指数符号(可选) 数字序列 | (2) | (C99 起)
1) 十进制浮点常量的指数语法
2) 十六进制浮点常量的指数语法

数位间可插入作为分隔符的单引号（'），在编译时忽略它们。

 (C23 起)

解释

若 有效数字 以字符序列 0x 或 0X 开始，则浮点常量为十六进制浮点常量。否则，它是十进制浮点常量。

对于十六进制浮点常量，将 有效数字 转译为十六进制小数，而将指数的 数字序列 转译为有效数字要乘的 2 的整数次幂。

double d = 0x1.2p3; // 十六进制小数 1.2 （十进制 1.125 ）乘 2^3 ，即 9.0
 (C99 起)

对于十进制浮点常量， 有效数字 被转译为十进制小数，而将指数的 数字序列 转译为有效数字要乘的 10 的整数次幂。

double d = 1.2e3; // 十进制小数 1.2 乘 10^3 ，即 1200.0

后缀

无后缀浮点常量拥有 double 类型。若 后缀 为字母 f 或 F ，则浮点常量拥有 float 类型。若 后缀 为 l 或 L ，则浮点常量拥有 long double 类型。

若实现预定义宏 __STDC_IEC_60559_BFP__ ，则额外支持下列后缀与对应的浮点常量：

  • 若 后缀 为 df 或 DF ，则浮点常量拥有 _Decimal32 类型；
  • 若 后缀 为 dd 或 DD ，则浮点常量拥有 _Decimal64 类型；
  • 若 后缀 为 dl 或 DL ，则浮点常量拥有 _Decimal128 类型。

十六进制浮点常量中不允许十进制浮点类型的后缀。

 (C23 起)

可选部分

若有指数而不用小数部分，则可以忽略小数分隔符：

double x = 1e0; // 浮点数 1.0 （不用小数点）

对于十进制浮点常量， 指数 部分是可选的。若忽略它，则小数点不是可选的，而且 整数 或 小数 必须存在。

double x = 1.; // 浮点数 1.0 （小数部分可选）
double y = .1; // 浮点数 0.1 （整数部分可选）

十六进制浮点常量的指数非可选，以避免误认 f 后缀为十六进制数字所导致的歧义结果。

 (C99 起)

可表示值

浮点常量的求值结果是最邻近的可表示值，或紧邻于最邻近可表示值的最大或最小可表示值，以实现定义行为选择（换言之，翻译期的默认浮点方向是实现定义的）。

所有拥有相同源码形式的浮点常量都转换到有相同值的同一内部格式。有不同形式的浮点常量，例如 1.23 与 1.230 ，不需要转换到同一内部格式和值。

若 FLT_EVAL_METHOD 指示，可以转换浮点常量为大于其所指示类型的范围和精度。例如，常量 0.1f 可能在表达式中表现为 0.1L 。

若 FLT_RADIX 为 2，则十六进制浮点常量的求值结果，是浮点常量所表示的正确舍入到目标类型的准确值。

 (C99 起)

拥有相同数值 \(\small x\)x ，但有不同量指数的十进制浮点类型的浮点常量，例如 1230.dd、 1230.0dd 及 1.23e3dd ，拥有可区别的内部表示。

十进制浮点类型的浮点常量的量指数 \(\small q\)q 在可能时，以 \(\small 10^q\)10q
 表示位于 有效数字 最低位的位置的 1 的方式确定。若按以上方式确定的量指数 \(\small q\)q 与系数 \(\small c = x\cdot 10^{-q}\)c=x·10-q
 不能以浮点常量的类型准确表示，则在类型的界限内按需增加 \(\small q\)q ，并对应地减少 \(\small c\)c ，进行需要的舍入。舍入可能导致零或无穷大。若在 \(\small q\)q 抵达最大值后（可能为舍入后的） \(\small c\)c 仍在容许范围外，则产生的浮点常量拥有正无穷大值。

 (C23 起)

注解

默认舍入方向和精度在浮点常量转换成内部表示时有效，而且不会引发浮点异常，即使 #pragma STDC FENV_ACCESS 生效（对于字符串的执行时转换，可使用 strtod ）。注意它和浮点类型的算术常量表达式有别。

浮点常量中的字母是无关大小写的，除了在十进制浮点类型的后缀中不能一同使用大写和小写 (C23 起)： 0x1.ep+3 与 0X1.EP+3 表示同一浮点值 15.0 。

setlocale 中指定的小数点对浮点常量语法无效：小数点始终是点。

不同于整数，不是每个浮点值都能以十进制或十六进制 (C99 起)常量语法表示：宏 NAN 和 INFINITY 以及如 nan 的函数提供生成这些特殊值的方式 (C99 起)。注意 0x1.FFFFFEp128f ，可能作为 IEEE float NaN 出现，实际上它在该格式中溢出到无穷大。

没有负浮点常量；如 -1.2 的表达式被视为算术运算符一元负作用于浮点常量 1.2 。注意可通过 -0.0 构造特殊值负零。

示例

#include <stdio.h>

int main(void)
{
    printf("15.0     = %a\n", 15.0);
    printf("0x1.ep+3 = %f\n", 0x1.ep+3);

    // 超出 double 范围的常量。
    printf("+2.0e+308 --> %g\n",  2.0e+308);
    printf("+1.0e-324 --> %g\n",  1.0e-324);
    printf("-1.0e-324 --> %g\n", -1.0e-324);
    printf("-2.0e+308 --> %g\n", -2.0e+308);
}

输出：

15.0     = 0x1.ep+3
0x1.ep+3 = 15.000000
+2.0e+308 --> inf
+1.0e-324 --> 0
-1.0e-324 --> -0
-2.0e+308 --> -inf

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.4.4.2 Floating constants (p: 47-48)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.4.4.2 Floating constants (p: 65-66)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.4.4.2 Floating constants (p: 57-58)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.1.3.1 Floating constants

参阅


for 循环

< c‎ | language

执行循环。

用作 while 循环的简短等价版本。

语法

属性说明符序列(C23 起)(可选) for ( 初始化子句 ; 条件表达式 ; 迭代表达式 ) 循环语句

解释

表现如下：

  • 初始化子句 可以为表达式或声明 (C99 起)
  • 作为表达式的 初始化子句 在首次求值 条件表达式 前被求值一次，并舍弃其结果。
  • 作为声明的 初始化子句 在整个循环体内都处于作用域内，包括 初始化子句 的剩余部分、整个条件表达式、整个 迭代表达式 及整个循环语句。声明于此声明的变量只允许有 auto 和 register 存储类说明符。
 (C99 起)
  • 条件表达式 在循环体前求值。若表达式的结果是零，则循环立即退出。
  • 迭代表达式 在循环体后求值，并舍弃其结果。求值 迭代表达式 后，将控制转移到 条件表达式。

初始化子句 、 条件表达式 和 迭代表达式 都是可选的。若忽略 条件表达式 ，则它被替换成非零的整数常量，这使得循环不终止：

for(;;) {
   printf("endless loop!");
}

循环语句 不是可选的，但它可以是空语句：

for(int n = 0; n < 10; ++n, printf("%d\n", n))
    ; // 空语句

若需要在某些点终止循环的执行，则可在 循环语句 中的任何位置使用 break 语句。

循环语句 内任何位置使用的 continue 语句会将控制转移到迭代表达式。

若无限循环在其 条件表达式 、 迭代表达式 或 循环语句 的任何部分无可观测行为（ I/O 、 volatile 访问、原子或同步操作），则拥有这种循环的程序有未定义行为。这允许编译器优化掉整个不可观测循环，而无需证明他们会结束。仅有的例外是 条件表达式 被忽略或为常量表达式的循环： for(;;) 始终是无限循环。

同所有选择和迭代语句， for 语句建立块作用域：任何于 初始化子句 、 条件表达式 或 迭代表达式 中引入的标识符在 循环语句 后离开作用域。

 (C99 起)

属性说明符序列 是属性的可选序列，应用到 for 语句。

 (C23 起)

关键词

for

注解

用作 循环语句 的表达式语句建立其自身的，异于 初始化子句 作用域的块作用域，不同于 C++ 中：

for (int i = 0; ; ) {
    long i = 1;   // C 中合法， C++ 中非法
    // ...
}

可以用 goto 进入循环体，以此方式进入循环时，不执行 初始化子句 和 条件表达式 。（若控制抵达循环体尾，则可能出现包括执行 条件表达式 的重复。）

示例

#include <stdio.h>
#include <stdlib.h>
enum { SIZE = 8 };
int main(void)
{
    int array[SIZE];
    for(size_t i = 0 ; i < SIZE; ++i)
        array [i] = rand() % 2;
    printf("Array filled!\n");
    for (size_t i = 0; i < SIZE; ++i)
        printf("%d ", array[i]);
    printf("\n");
}

可能的输出：

Array filled!
1 0 1 1 1 1 0 0

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.8.5.3 The for statement (p: 110)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.8.5.3 The for statement (p: 151)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.8.5.3 The for statement (p: 136)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.6.5.3 The for statement

参阅


函数声明

< c‎ | language

函数声明引入指代函数的标识符，并可选地指定该函数的参数类型（原型）。函数声明（不同于定义）可以出现于块作用域和文件作用域中。

语法

在函数声明的声明文法中， 类型说明符 序列，可选择地由声明器修饰，指代返回类型（可以是任何异于函数和数组的类型），而 声明符 有三种形式：

非指针声明符 ( 形参列表 ) 属性说明符序列(可选) | (1) |
非指针声明符 ( 标识符列表 ) 属性说明符序列(可选) | (2) | (C23 前)
非指针声明符 ( ) 属性说明符序列(可选) | (3) |

其中

非指针声明符 | - | 任何无括号指针声明器以外的声明器。包含于此声明器中的标识符是成为函数指代器的标识符。
形参列表 | - | 为单一关键词 void 或参数的逗号分隔列表，可以以省略号参数结尾。
标识符列表 | - | 标识符的逗号分隔列表，仅在声明器被用作旧式函数定义的一部分的情况下可能
属性说明符序列 | - | (C23)可选的属性列表，应用到函数类型
1) 新式 (C89) 函数声明。此声明不仅引入函数指代器自身，而且还为任何将来的函数调用表达式提供函数原型，强制将使用参数表达式转换成声明参数类型，还有编译时的参数数量检查。
int max(int a, int b); // 声明
int n = max(12.01, 3.14); // OK ：从 double 转换到 int
2) (C23 前) 旧式 (K&R) 函数定义。此声明不引入函数原型，且任何将来的函数调用表达式都将进行默认参数提升，而且若实参数量不匹配形参数量则引起未定义行为。
int max();
int max(a, b)
int a, b; { return a>b?a:b; } // 定义期待 int ；第二个调用是未定义行为
int n = max(true, (char)'a'); // 以二个 int 参数调用 max （提升后）
int n = max(12.01f, 3.14); // 以二个 double 参数调用 max （提升后）
3) 无原型函数声明。此声明不引入原型，除非作为函数定义的一部分，其中它等价于 形参列表 void (C23 起)。

解释

函数的返回类型，由 说明符与限定符 中的类型说明符确定，并且像在声明中一样可以由 声明符 修改，它必须是非数组对象类型或类型 void 。若该函数声明不是定义，则返回类型可以为不完整。返回类型不能有 cvr 限定：为构造函数类型的目的，调整任何有限定返回类型为其无限定版本。

void f(char *s);                    // 返回类型为 void
int sum(int a, int b);              // sum 的返回类型为 int.
int (*foo(const void *p))[3];       // 返回类型是指向 3 个 int 的数组的指针

double const bar(void);             // 声明 double(void) 类型函数
double (*barp)(void) = bar;         // OK ： foop 是指向 double(void) 的指针
double const (*barpc)(void) = barp; // OK ： foopc 亦为指向 double(void) 的指针

函数声明器可以与其他声明器联合，只要他们共享其类型说明符和限定符。

int f(void), *fip(), (*pfi)(), *ap[3]; // 声明二个函数和二个对象
inline int g(int), n; // 错误： inline 说明符仅用于函数
typedef int array_t[3];
array_t a, h(); // 错误：数组类型不能作为函数返回类型

若函数声明器出现于任何函数外，则其引入的标识符拥有文件作用域和外部链接，除非使用 static 或较前的 static 声明可见。若声明出现于另一函数内，则标识符拥有块作用域（且亦拥有外部或内部链接）。

int main(void)
{
    int f(int); // 外部链接，文件作用域
    f(1); // 定义需要程序的某处可用
}

不是函数定义的一部分的声明中， (C23 前)参数不需要命名：

int f(int, int); // 声明
// int f(int, int) { return 7; } // 错误，参数在定义中必须命名
// C23 中允许此定义。

形参列表 中的每个参数是引入单个变量的声明，变量拥有下列额外属性：

  • 声明器中的标识符是可选的（除非此函数声明是函数定义的一部分） (C23 前)
int f(int, double); // OK
int g(int a, double b); // 也 OK
int f(int, double) { return 1; } // 错误：定义必须命名参数
// C23 中允许此定义。
  • 仅有的得到允许的存储类说明符是 register ，而在非定义的函数声明中忽略它
int f(static int x); // 错误
int f(int [static 10]); // OK （数组下标的 static 不是存储类说明符）
  • 任何数组类型的参数都被调整到对应的指针类型，若数组声明器的方括号内有限定符，则它具有限定 (C99 起)。
int f(int[]); // 声明 int f(int*)
int g(const int[10]); // 声明 int g(const int*)
int h(int[const volatile]); // 声明 int h(int * const volatile)
int x(int[*]); // 声明 int x(int*)
  • 任何函数类型的参数都被调整到对应的指针类型
int f(char g(double)); // 声明 int f(char (*g)(double))
int h(int(void)); // 声明 int h(int (*)(void))
  • 参数列表可以以 , ... 终止，细节见变参数函数。
int f(int, ...);
  • 参数不能拥有 void 类型（但可以拥有指向 void 指针类型）。完全由关键词 void 组成的特殊参数列表用于声明不接收参数的函数。
int f(void); // OK
int g(void x); // 错误
  • 任何出现于参数列表中，能被当成 typedef 名或参数名的标识符，都会被当做 typedef 名： int f( size_t, uintptr_t ) 被分析成新式声明器，声明一个函数，它接收二个 size_t 和 uintptr_t 类型的未命名参数，而非开始定义接收二个名为“ size_t ”和“ uintptr_t ”的函数的旧式声明器。
  • 参数列表可以拥有不完整类型而且可以用 VLA 记法 [*] (C99 起)（除了在函数定义中，在数组到指针和函数到指针调整后，参数类型必须完整）

属性说明符序列亦能应用到函数参数。

 (C23 起)

其他函数调用机制上的细节见函数调用运算符，关于从函数返回，见 return 。

注解

不同于 C++ 与函数定义 (C23 起)，声明器 f() 与 f(void) 拥有不同含义：声明符 f(void) 是新式（原型）声明符，声明函数不接收参数。声明符 f() 是声明函数接收未指定数量的参数的声明符（除非用于函数定义）

int f(void); // 声明：不接收参数
int g(); // 声明：接收未知参数

int main(void) {
    f(1); // 编译时错误
    g(2); // 未定义行为
}

int f(void) { return 1; ) // 实际定义
int g(a,b,c,d) int a,b,c,d; { return 2; } // 实际定义

和在函数定义中不同，形参列表可以从 typedef 继承

typedef int p(int q, int r); // p 是函数类型 int(int, int)
p f; // 声明 int f(int, int)

C89 中， 说明符与限定符 是可选的，且若省略它，则函数的返回类型默认为 int （可以由 声明符 修改）。

*f() { // 返回 int* 的函数
   return NULL;
}
 (C99 前)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C 标准。

DR | 应用于 | 出版时的行为 | 正确行为
DR 423 | C89 | 返回类型可以有限定 | 返回类型被隐式除去限定

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.7.6.3 Function declarators (including prototypes) (p: 96-98)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.6.3 Function declarators (including prototypes) (p: 133-136)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.5.3 Function declarators (including prototypes) (p: 118-121)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.5.4.3 Function declarators (including prototypes)

参阅


函数定义

< c‎ | language

函数定义将函数体（声明与语句的序列）与函数名及参数列表关联。不同于函数声明，函数定义只允许在文件作用域（不存在嵌套函数）。

C 支持二种函数定义的形式：

属性说明符序列(可选) 说明符与限定符 形参列表声明符 函数体 | (1) |
说明符与限定符 标识符列表声明符 声明列表 函数体 | (2) | (C23 前)

其中

属性说明符序列 - (C23)可选的属性列表，应用到函数
说明符与限定符 - 下列的组合
  • 类型说明符，可由声明器修改，组成返回类型
  • 存储类说明符，确定标识符的链接（ static 、 extern 或无）
  • 函数说明符（ inline 、 _Noreturn 或无）
形参列表声明符 - 用参数列表指代函数参数的函数类型的声明器
标识符列表声明符 - 用标识符列表指代函数参数的函数类型的声明器
声明列表 - 在 标识符列表声明符 中声明每个参数的声明序列。这些声明不能使用初始化器，而且仅允许 register 作为存储类说明符。
函数体 - 复合语句，是花括号所包括的声明及语句序列，只要调用此函数就会被执行
1) 新式 (C89) 函数定义。此定义引入函数自身，并为任何将来的函数调用表达式提供函数原型，强迫从实参表达式转换到声明形参类型。
int max(int a, int b)
{
    return a>b?a:b;
}

double g(void)
{
    return 0.1;
}
2) (C23 前) 旧式 (K&R) 函数定义。此定义不表现为原型，而任何将来的函数调用表达式将进行默认参数提升。
int max(a, b)
int a, b;
{
    return a>b?a:b;
}
double g()
{
    return 0.1;
}

解释

同函数声明，函数的返回类型由 说明符与限定符 中的类型说明符确定，并像在声明中一样可以由 声明符 修改。返回类型必须是完整的非数组对象类型或 void 类型。若返回类型会有 cvr 限定，则为构造函数类型的目的，将它调整为其无限定版本。

void f(char *s) { puts(s); } // 返回类型为 void
int sum(int a, int b) { return a+b: } // 返回类型为int
int (*foo(const void *p))[3] { // 返回类型是指向 3 个 int 的数组的指针
    return malloc(sizeof(int[3]));
}

同函数声明，为构造函数类型的目的，将参数类型从函数调整到指针，从数组调整到指针，并且为确定兼容函数类型的目的，忽略所有参数类型的顶层 cvr 限定符。

不同于函数声明，不允许无名形参（否则旧式 (K&R) 函数定义中会有冲突），即使不在函数中使用也必须命名它们。仅有的例外是参数列表 (void) 。 | (C23 前)
函数定义中形参可以为无名，因为旧式 (K&R) 函数定义已被移除。函数体内不能以名称访问无名形参。 | (C23 起)
int f(int, int); // 声明
// int f(int, int) { return 7; } // C23 前错误， C23 起 OK
int f(int a, int b) { return 7; } // 定义
int g(void) { return 8; } // OK ： void 不声明参数

在函数体内，每个具名参数都是左值表达式，它们拥有自动存储期和块作用域。参数在内存中的布局（或者它们究竟是否存储于内存中）是未指定的：这是调用约定的一部分。

int main(int ac, char **av)
{
    ac = 2; // 参数是左值
    av = (char *[]){"abc", "def", NULL};
    f(ac, av);
}

函数调用机制上的其他细节见函数调用运算符，关于从函数返回，见 return 。

__func__

在每个 函数体 内，拥有块作用域和静态存储期的预定义变量 __func__ 可用，它如同立即通过以下方式在开花括号后定义：

static const char __func__[] = "function name";

此特殊标识符有时与预定义宏常量 __FILE__ 及 __LINE__ 结合使用，例如为 assert 所用。

 (C99 起)

注解

参数列表必须显式存在于声明器中，不能从 typedef 继承它

typedef int p(int q, int r); // p 是类型为 int(int, int) 的函数
p f { return q + r; } // 错误

C89 中， 说明符与限定符 是可选的，若省略它，则函数返回类型默认为 int （可由 声明符 修改）。

另外，旧式定义不要求在 声明列表 中声明每个参数。任何缺少声明的参数拥有 int 类型

max(a, b) // a 和 b 拥有 int 类型，返回类型为 int
{
    return a>b?a:b;
}
 (C99 前)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C 标准。

DR | 应用于 | 出版时的行为 | 正确行为
DR 423 | C89 | 返回类型可以有限定 | 返回类型被隐式除去限定

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.9.1 Function definitions (p: 113-115)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.9.1 Function definitions (p: 156-158)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.9.1 Function definitions (p: 141-143)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.7.1 Function definitions

参阅


函数

< c‎ | language

函数是将一个标识符（函数名）关联到一条复合语句（函数体）的 C 语言构造。每个 C 程序都从 main 函数开始执行，也从它或者调用其他用户定义函数或库函数终止。

// 函数定义。
// 定义一个名为“ sum ”并拥有函数体“ { return x+y; } ”的函数
int sum(int x, int y)
{
    return x + y;
}

函数可以拥有零或更多个形参，它们为函数调用运算符的实参所初始化，并且以通过其 return 语句向其调用者返回一个值。

int n = sum(1, 2); // 参数 x 和 y 为实参 1 和 2 所初始化

函数体在函数定义中提供。每个被实际调用的函数必需且只需在程序中定义一次 ，除非该函数为 inline (C99 起)。

不可以有嵌套函数（除了一些通过非标准的编译器扩展）：每个函数定义必须出现在文件作用域，而且函数无法访问其来自其调用方的局部变量：

int main(void) // main函数定义
{
    int sum(int, int); // 函数声明（可以出现于任何作用域）
    int x = 1;  // main 的局部变量
    sum(1, 2); // 函数调用

//    int sum(int a, int b) // 错误：不允许嵌套函数
//    {
//        return  a + b;
//    }
}
int sum(int a, int b) // 函数定义
{
//    return x + a + b; //  错误：不能在 sum 中访问 main 的 x
    return a + b;
}

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.7.6.3 Function declarators (including prototypes) (p: 96-98)
  • 6.9.1 Function definitions (p: 113-115)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.6.3 Function declarators (including prototypes) (p: 133-136)
  • 6.9.1 Function definitions (p: 156-158)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.5.3 Function declarators (including prototypes) (p: 118-121)
  • 6.9.1 Function definitions (p: 141-143)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.5.4.3 Function declarators (including prototypes)
  • 3.7.1 Function definitions

参阅


泛型选择

< c‎ | language

提供一种基于控制表达式的类型，在编译时选择数个表达式之一的方法。

语法

_Generic ( 控制表达式 , 关联列表 ) (C11 起)

其中 关联列表 是逗号分隔的关联列表，每个关联拥有语法：

类型名 : 表达式
default : 表达式

其中

类型名 | - | 任何完整的非可变修改的对象类型（即既非 VLA 亦非指向 VLA 的指针）。
关联列表 | - | 任何表达式（除了逗号运算符），若不使用 default 关联，则其类型必须与 类型名 之一兼容，
表达式 | - | 任何类型和值类别的表达式（除了逗号运算符）

关联列表 中的任意二个 类型名 不能指定兼容类型。使用关键词 default 的关联只能有一个。若不使用 default ，且无一 类型名 与控制表达式类型兼容，则程序无法编译。

解释

首先， 控制表达式 的类型经历左值转换。只在类型域中进行转换：它舍弃顶层 cvr 限定符和原子属性，并应用数组到指针/函数到指针变换到控制表达式的类型，而不实例化任何副效应或计算任何值。

将转换后的类型与来自关联列表中的 类型名 比较。

若其类型与关联之一的 类型名 兼容，则泛型选择的类型、值及值类别就是出现于该 类型名 冒号后的表达式的类型、值及值类别。

若无一 类型名 的类型与 控制表达式 兼容，且提供了 default 关联，则泛型的类型、值及值类别就是出现于 default : 标号后的表达式的类型、值及值类别。

注解

决不求值 控制表达式 和未被选择的选项中的 表达式 。

因为左值转换， "abc" 匹配 char* 而非 char[4] ， (int const){0} 匹配 int 而非 const int 。

泛型选择中的 表达式 允许任何值类别，含函数指代器及 void 表达式，而且若它受到选择，则泛型选择自身拥有相同的值类别。

C99 中引入的来自 <tgmath.h> 的泛型数学宏，曾是通过编译器限定的行为实现的。 C11 所引入的泛型选择，给予程序员写相似的类型依赖代码的能力。

泛型选择类似 C++ 中的重载（在编译时基于参数类型选择数个函数之一）。除了它在任意表达式之间选择。

关键词

_Generic, default

示例

#include <stdio.h>
#include <math.h>

// tgmath.h 宏 cbrt 的可能实现
#define cbrt(X) _Generic((X), \
              long double: cbrtl, \
                  default: cbrt,  \
                    float: cbrtf  \
)(X)

int main(void)
{
    double x = 8.0;
    const float y = 3.375;
    printf("cbrt(8.0) = %f\n", cbrt(x)); // 选择默认的 cbrt
    printf("cbrtf(3.375) = %f\n", cbrt(y)); // 将 const float 转换成 float，
                                            // 然后选择 cbrtf
}

输出：

cbrt(8.0) = 2.000000
cbrtf(3.375) = 1.500000

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C 标准。

DR | 应用于 | 出版时的行为 | 正确行为
DR 481 | C11 | 未指定控制表达式是否经历左值转换 | 经历

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.5.1.1 Generic selection (p: 56-57)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.5.1.1 Generic selection (p: 78-79)


goto 语句

< c‎ | language

将控制无条件转移到所欲位置。

在无法用约定的构造将控制转移到所欲位置时使用。

语法

属性说明符序列(可选) goto 标号 ;
标号 | - | goto 语句的目标标号
属性说明符序列 | - | (C23)可选的属性列表，应用到 goto 语句

解释

goto 语句导致无条件跳转（控制的转移）到前附具名 标号 （必须与 goto 语句出现于同一函数中）的语句，除非此跳转会进入非常量长度数组或另一可变修改类型的作用域 (C99 起)。

标号 是一个后随冒号（ : ）和一条语句 (C23 前)的标识符。标号是仅有的拥有函数作用域的标识符：能在其所出现于的函数中的任何位置使用它们（在 goto 语句中）。任何语句前可以有多个标号。

容许进入非可变修改对象的作用域：

goto lab1; // OK ：进入常规变量的作用域
    int n = 5;
lab1:; // 注意未初始化 n ，如同以 int n; 声明

//   goto lab2;   // 错误：进入二个 VM 类型的作用域
     double a[n]; // VLA
     int (*p)[n]; // VM 指针
lab2:

若 goto 离开 VLA 的作用域，则 VLA 会被解分配（而且可能会被再分配，若再度执行其初始化）：

{
   int n = 1;
label:;
   int a[n]; // 重分配 10 次，每次拥有不同的大小
   if (n++ < 10) goto label; // 离开 VM 的作用域
}
 (C99 起)

关键词

goto

注解

因为声明不是语句，在声明前的标号必须使用空语句（紧随冒号后的分号）。同样的规则适用于块结尾前的标号。

 (C23 前)

C++ 在 goto 语句上加上了另外的限制，不过允许标号在声明（它们在 C++ 中是语句）前。

示例

#include <stdio.h>

int main(void)
{
    // goto 可用于简单地离开多层循环
    for (int x = 0; x < 3; x++) {
        for (int y = 0; y < 3; y++) {
            printf("(%d;%d)\n",x,y);
            if (x + y >= 3) goto endloop;
        }
    }
endloop:;
}

输出：

(0;0)
(0;1)
(0;2)
(1;0)
(1;1)
(1;2)

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.8.6.1 The goto statement (p: 110-111)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.8.6.1 The goto statement (p: 152-153)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.8.6.1 The goto statement (p: 137-138)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.6.6.1 The goto statement

参阅


C 的历史

< c‎ | language

早期 C

  • 1969　:基于 BCPL 创建 B ，以作为 Unix 的系统程序语言替代 PDP-7 汇编器
  • 增加运算符 ++ 、 -- 、复合赋值，保持为类 BCPL 的无类型语言
  • 1971 ：于将 B 移植到 PDP-11 时创建 NB （新“ B ”）
  • 类型（ int 、 char 、数组与指针）、数组到指针转换、到机器码的编译
  • 1972 ：语言更名为 C
  • 结构体、运算符 && 及 || 、预处理器、可移植 I/O
  • 1973 ：以 C 重写
  • 无符号整数、 long 、联合体、枚举、增强的类型安全
  • 1978 ： The C Programming Language ，第1版

标准 C

  • 1983 ： ANSI 建立 X3J11 委员会
  • 1988 ： The C Programming Language ，第2版
  • 1989 ： C89 ，ANSI C 标准出版
  1. 代码化的既存实践
  2. 新特性 ：volatile 、 enum 、有符号整数 、 void 、本地环境
  3. 来自 C++ ： const 、函数原型
  • 1990 ： C90 ，ANSI C 标准被接纳为 ISO/IEC 9899-1990
  • 1995 ： C95 （ ISO/IEC 9899 AM1 ）（在线商店）
  1. 极大扩充了宽和多字节字符支持（ wctype.h 、 wchar.h 、对流 I/O 的添加和更改等）
  2. 双标符、 iso646.h
  • 1995 ：技术勘误 1（ ISO/IEC 9899 TCOR1 ）
  • 44 个小更改
  • 1996 ：技术勘误 2（ ISO/IEC 9899 TCOR2 ）
  • 24 个小更改
  • 1999 ：C99 （ ISO/IEC 9899:1999 ）
  1. 新特性： _Bool 、 long long 、 stdint.h 、 inttypes.h 、 restrict 、复合字面量、变长度数组、伸缩数组成员、指派初始化器、 fenv.h 、变参数宏、复数、 __func__ 、十六进制浮点格式（ %a ）、 lconv 的货币格式化、 isblank 、窄与宽字符串字面量的连接、枚举的尾逗号、类函数宏的空参数、 STDC_* pragma 、 va_copy 、 tmpnam 的空返回、 setvbuf 中的空指针、 printf 的 hh 与 ll 长度指定符、 snprintf 、 _Exit 、 tgmath.h 、仿 POSIX strftime 说明符
  2. 来自 C++ ： inline 、声明与代码混合、 for 循环的 init 子句中的声明、 // 注释、源代码中的通用字符名
  3. 移除隐式函数声明和隐式 int
  • 2001 ：技术勘误 1 （ ISO/IEC 9899:1999/Cor.1:2001(E) ）
  • 修正 11 个缺陷
  • 2004 ：技术勘误 2 （ ISO/IEC 9899:1999/Cor.2:2004(E) ）
  • 2004 ：Unicode TR（ ISO/IEC TR 19769:2004 ）（ ISO商店）（2013-11-07 草案）
  • 2007 ：技术勘误 3 （ ISO/IEC 9899:1999/Cor.3:2007(E) ）（ 2007-09-07草案）
  • 弃用 gets
  • 2007 ：边界检查接口 TR（ ISO/IEC TR 24731-1:2007 ）（ ISO 商店）（ 2007-03-28 草案）
  • 2008 ：嵌入式 TR （ ISO/IEC TR 18037:2008 ）（ ISO商店）（ 2003-09-24 草案）
  • 2009 ：十进制浮点数 TR（ ISO/IEC TR 24732:2009 ）（ ISO 商店）（ 2007-07-05 草案）
  • 2009 ：特殊数学函数 TR（ ISO/IEC TR 24747:2009 ）（ ISO 商店）（2006-08-02 草案）
  • 2010 ：动态分配函数 TR（ ISO/IEC TR 24731-2:2010 ）（ ISO 商店）（2007-08-15 草案）
  • 2011 ： C11 （ ISO/IEC 9899:2011 ）（ ISO 商店）（ ANSI 商店）（2011-04-12 草案）
  1. 具线程的内存模型 、 stdatomic.h 、 threads.h 、泛型函数、 _Alignas/_Alignof 、 _Noreturn 、 _Static_assert 、可分析性扩展、对复数和虚数类型的扩展、匿名结构体与联合体、独占文件打开模式、 quick_exit
  2. 移除 gets
  3. 来自边界检查接口 TR ：边界检查接口
  4. 来自 Unicode TR ： char16_t 、 char32_t ，及 uchar.h
  • 2012 ：技术勘误 1 （ ISO/IEC 9899:2011/Cor 1:2012 ）（ ISO 商店）
  • 修正 DR 411
  • 2013 ：安全代码规则 TS （ ISO/IEC TS 17961:2013 ）（ ISO 商店）（ 2012-12-26 草案）
  • 2014 ：FP TS 部分 1 ：二进制浮点算术（ ISO/IEC TS 18661-1:2014 ）（ ISO 商店）（ 2013 草案）
  1. 提供对 C11 的更改（主要对附录 F ），以覆盖所有基本要求及一些 IEC 60559:2011 的推荐（ C11 构建于 IEC 60559:1989 ）
  • 2015 ：FP TS 部分 2 ：十进制浮点算术（ ISO/IEC TS 18661-2:2015 ）（ ISO 商店) ( 2015 草案）
  1. 提供对 C11 的更改，以支持所有要求，加上一些 IEC 60559:2011 对十进制浮点算术的基本推荐。它替代了 ISO/IEC TR 24732:2009 。
  • 2015 ：FP TS 部分 3 ：交换及扩展类型（ ISO/IEC TS 18661-3:2015 ）（ ISO 商店）（ 2015 草案）
  1. 提供对C11的更改，以支持IEC 60559:2011对扩展浮点格式及交换格式的推荐，包括算术和非算术。
  • 2015 ：FP TS 部分 4 ：补充的函数（ ISO/IEC TS 18661-4:2015 ）（ ISO 商店）（ 2015 草案）
  1. 提供对 C11 的更改，以支持所有 IEC 60559:2011 推荐的数学运算，包括 π 单位的三角函数、平方根倒数、复利等。
  • 2016 ：FP TS 部分 5 ：补充的属性（ ISO/IEC TS 18661-5:2016 ）（ ISO 商店）（ 2016 草案）
  1. 提供对 C11 的更改，以支持所有 IEC 60559:2011 推荐的补充属性（求值模型、异常处理、可再现性等）
  • 2018: C17 （ ISO/IEC 9899:2018 ）（ 最终草案）。
主条目： C17
C17 中修正的缺陷报告（ 54 个缺陷）
  • DR 400
  • DR 401
  • DR 402
  • DR 403
  • DR 404
  • DR 405
  • DR 406
  • DR 407
  • DR 410
  • DR 412
  • DR 414
  • DR 415
  • DR 416
  • DR 417
  • DR 419
  • DR 423
  • DR 426
  • DR 428
  • DR 429
  • DR 430
  • DR 431
  • DR 433
  • DR 434
  • DR 436
  • DR 437
  • DR 438
  • DR 439
  • DR 441
  • DR 444
  • DR 445
  • DR 447
  • DR 448
  • DR 450
  • DR 452
  • DR 453
  • DR 457
  • DR 458
  • DR 459
  • DR 460
  • DR 462
  • DR 464
  • DR 465
  • DR 468
  • DR 470
  • DR 471
  • DR 472
  • DR 473
  • DR 475
  • DR 477
  • DR 480
  • DR 481
  • DR 485
  • DR 487
  • DR 491

未来发展

  • 并行 TS （草案 n2017 2016-03-10 ）
  • 事务性内存 TS （草案 n1961 2015-09-23 ）
  • C23 （草案 n2731 2021-10-18 ）
  1. C11 后缺陷报告列表（包含为 C2x 安排者） n2396 (2019-04)
主条目： C23
下个主要 C 语言标准版本
C23 中修正的缺陷报告（ 8 个缺陷）
  • DR 476
  • DR 488
  • DR 494
  • DR 496
  • DR 497
  • DR 499
  • DR 500
  • DR 501

参阅

引用

  • C 语言的发展 Dennis M. Ritchie
  • C99 标准基本原理


if 语句

< c‎ | language

有条件地执行代码。

用于仅若某条件为真才执行代码的场合。

语法

属性说明符序列(可选) if ( 表达式 ) 语句真 | (1)
属性说明符序列(可选) if ( 表达式 ) 语句真 else 语句假 | (2)
属性说明符序列 | - | (C23)可选的属性列表，应用到 if 语句
表达式 | - | 任何标量类型表达式
语句真 | - | 任何语句（常为复合语句），若 表达式 比较不等于 ​0​ 则执行
语句假 | - | 任何语句（常为复合语句），若 表达式 比较等于 ​0​ 则执行

解释

表达式 必须为任何标量类型的表达式。

若 表达式 与整数零比较不相等，则执行 语句真 。

形式 (2) 中，若 表达式 与整数零比较相等，则执行 语句假 。

同所有选择和迭代语句，整个 if 语句拥有其自身的块作用域：

enum {a, b};
int different(void)
{
    if (sizeof(enum {b, a}) != sizeof(int))
        return a; // a == 1
    return b; // C 89中 b == 0 ， C99 中 b == 1
}
 (C99 起)

注解

else 始终与最接近的前接 if 相关联（换言之，若 语句真 也是 if 语句，则内层 if 必须也含有 else 部分）：

int j = 1;
if (i > 1)
   if(j > 2)
       printf("%d > 1 and %d > 2\n", i, j);
    else // 此 else 是 if(j>2) 的一部分，不是 if(i>1) 的部分
       printf("%d > 1 and %d <= 2\n", i, j);

若通过 goto 进入 语句真 ，则不执行 语句假 。

关键词

if, else

示例

#include <stdio.h>

int main(void)
{
    int i = 2;
    if (i > 2) {
        printf("first is true\n");
    } else {
        printf("first is false\n");
    }

    i = 3;
    if (i == 3) printf("i == 3\n");

    if (i != 3) printf("i != 3 is true\n");
    else        printf("i != 3 is false\n");
}

输出：

first is false
i == 3
i != 3 is false

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.8.4.1 The if statement (p: 108-109)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.8.4.1 The if statement (p: 148-149)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.8.4.1 The if statement (p: 133-134)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.6.4.1 The if statement

参阅


初始化

< c‎ | language

对象声明可以通过名为初始化的步骤提供其初始值。

对于每个声明器，若不省略初始化器，则它可以是下列之一：

= 表达式 | (1)
= { 初始化器列表 } | (2)

其中 初始化器列表 是非空的逗号分隔 初始化器 列表（尾逗号可选），这里每个初始化器拥有三种可能形式之一：

表达式 | (1) |
{ 初始化器列表 } | (2) |
指派符列表 = 初始化器 | (3) | (C99 起)

其中 指派符列表 是形式为 [ 常量表达式 ] 的数组指派符列表，或形式为 . 标识符 的结构体/联合体指派符列表；见数组初始化及结构体初始化。

注意：除了初始化器，花括号环绕的 初始化器列表 亦可出现于复合字面量中，它是有下列形式的表达式：

( 类型 ) { 初始化器列表 }
(C99 起)

解释

初始化器指定存储于一个对象中的初始值。

显式初始化

若提供了初始化器，对于

  • 标量类型初始化，见标量初始化。
  • 数组类型初始化，见数组初始化。
  • 结构体及联合体类型初始化，见结构体初始化。

隐式初始化

若未提供初始化器：

  • 拥有自动存储期的对象将被初始化为不确定值（可能是陷阱表示）
  • 拥有静态及线程局域存储期的对象被零初始化。

零初始化

一些情况下，若未显式初始化对象，则零初始化它，即：

  • 指针被初始化成其类型的空指针值
  • 整数类型对象被初始化成无符号的零
  • 浮点类型对象被初始化成正零
  • 数组的所有元素、结构体的所有成员及联合体的首个成员递归地零初始化，外加初始化所有填充位为零
（在空指针值和浮点零拥有全零位表示的平台上，静态对象的这种初始化形式普遍以将其分配到程序映像的 .bss 段实现）

注解

在初始化静态或线程局域存储期的对象时，每个初始化器中的 表达式 都必须是常量表达式或字符串字面量。

初始化器不能用于不完整类型的对象、 VLA 及拥有链接的块作用域对象。

函数形参的初值如同用从函数调用实参赋值，而非初始化一样建立。

若将不确定值用于任何标准库调用的参数，则行为未定义。另外，任意牵涉到不确定值的表达式的值是不确定值（例如 int n; ， n 可能与自身比较不相等，并且它在后续读取中的值可能出现更改）。

C 标准不使用术语零初始化。该术语采纳自 C++ ，并为方便解释而用于此。

C 中无对应 C++ 中值初始化的特殊构造，然而能用 = {0} （或复合字面量中的 (T){0} ） (C99 起)代替，因为 C 标准不允许空结构体、空联合体或零长度数组。

示例

#include <stdlib.h>
int a[2]; //初始化a为{0, 0}
int main(void)
{
    int i;          // 初始化 i 为不确定值
    static int j;   // 初始化 j 为 0
    int k = 1;      // 初始化 k 为 1

    // 初始化 int x[3] 为 1,3,5
    // 初始化 int* p 为 &x[0]
    int x[] = { 1, 3, 5 }, *p = x;

    // 初始化 w （二个结构体的数组）为
    // { { {1,0,0}, 0}, { {2,0,0}, 0} }
    struct {int a[3], b;} w[] = {[0].a = {1}, [1].a[0] = 2};

    // 函数调用表达式可用于局部变量初始化
    char* ptr = malloc(10);
    free(ptr);

//  错误：拥有静态存储期的对象要求常量初始化器
//  static char* ptr = malloc(10);

//  错误：不能初始化 VLA
//  int vla[n] = {0};
}

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.9 Initialization (p: 139-144)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.8 Initialization (p: 125-130)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.5.7 Initialization

参阅


inline 函数说明符

< c‎ | language

声明内联函数。

语法

inline 函数声明 (C99 起)

解释

inline 说明符的目的是提示编译器做优化，譬如函数内联，这通常要求编译方能见到函数的定义。编译器能（并且经常）就优化的目的忽略 inline 说明符的存在与否。

若编译器进行函数内联，则它会以函数体取代所有对它的调用，以避免函数调用的开销（将数据置于栈上和取得结果），这可能会生成更大的可执行文件，因为函数可能会被重复多次。结果同仿函数宏，只是用于该函数的标识符和宏指代可见于定义点的定义，而不指代调用点的定义。

不管是否进行内联，内联函数都保证下列语义：

任何拥有内部链接的函数都可以声明成 static inline ，没有其他限制。

一个非 static 的内联函数不能定义一个非 const 的函数局部 static 对象，并且不能使用文件作用域的 static 对象。

static int x;
inline void f(void)
{
    static int n = 1; // 错误：非 const 的 static 对象在非 static 的 inline 函数中
    int k = x; // 错误：非 static 的 inline 函数访问 static 变量
}

若非 static 函数声明为 inline ，则必须在同一翻译单元中定义它。不使用 extern 的内联定义不会对外部可见，而且不会阻止其他翻译单元定义同一函数。这使得 inline 关键词成了 static 外另一种在头文件定义函数的方式，可以由同一程序的多个翻译单元包含该头文件。

若函数在一些翻译单元中声明为 inline ，它就不需要在处处皆声明为 inline ：至多一个单元会提供常规的非 inline 非 static 函数，或是声明为 extern inline 的函数。称此翻译单元提供外部定义。为避免未定义行为，若在表达式中使用拥有外部链接的函数名，则程序中必须存在一个外部定义，见一个定义规则。

内联函数的地址始终是外部定义的地址，但当以此地址进行函数调用时，调用内联定义（若存在于翻译单元中）还是外部定义是未指定的。定义于内联定义中的 static 对象与定义于外部定义中的 static 对象有别：

inline const char *saddr(void) // 用于此文件内的内联定义
{
    static const char name[] = "saddr";
    return name;
}
int compare_name(void)
{
    return saddr() == saddr(); // 未指定行为，调用可能是外部的
}
extern const char *saddr(void); // 外部定义也会生成

C 程序不应依赖于调用函数的内联版本还是外部版本，否则行为未指定。

关键词

inline

注解

inline 关键词是从 C++ 吸收的，但在 C++ 中，若函数声明为内联，则它必须在每一个翻译单元声明为内联，而且每一个内联函数都必须有准确相同的定义（ C 中，定义可以相异，而依赖这些差异仅导致未指定行为）。另一方面， C++ 允许非 const 的函数局域 static 对象，而且所有来自一个内联函数不同定义版本的函数局部 static 对象都相同，但它们在 C 中不同。

示例

// file test.h
#ifndef TEST_H_INCLUDED
#define TEST_H_INCLUDED
inline int sum (int a, int b)
{
    return a+b;
}
#endif

// 文件 sum.c
#include "test.h"
extern inline int sum (int a, int b); // 提供外部定义

// 文件 test1.c
#include <stdio.h>
#include "test.h"
extern int f(void);

int main(void)
{
    printf("%d\n", sum(1, 2) + f());
}

// 文件 test2.c
#include "test.h"

int f(void)
{
    return sum(2, 3);
}

输出：

8

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.4 Function specifiers (p: 125-127)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.4 Function specifiers (p: 112-113)

参阅


整数常量

< c‎ | language

允许整数类型的值直接用于表达式。

语法

整数常量是拥有下列类型的非左值表达式

十进制常量 整数后缀(可选) | (1) |
八进制常量 整数后缀(可选) | (2) |
十六进制常量 整数后缀(可选) | (3) |
二进制常量 整数后缀(可选) | (4) | (C23 起)

其中

  • 十进制常量 是非零十进制数位（ 1 、 2 、 3 、 4 、 5 、 6 、 7 、 8 、 9 ），跟随零个或更多十进制数字（ 0 、 1 、 2 、 3 、 4 、 5 、 6 、 7 、 8 、 9）
  • 八进制常量 是数字零（ 0 ）跟随零个或更多八进制数位（ 0 、 1 、 2 、 3 、 4 、 5 、 6 、 7 ）
  • 十六进制常量 是字符序列 0x 或字符序列 0X 跟随一个或更多十六进制数位（ 0 、 1 、 2 、 3、 4、 5 、 6 、 7 、 8 、 9 、 a 、 A 、 b 、 B 、 c 、 C 、 d 、 D、 e 、 E 、 f 、 F ）
  • 二进制常量 是字符序列 0b 或字符序列 0B 跟随一个或更多二进制数位（ 0 、 1 ）
  • 整数后缀 ，若提供则可包含下面一或两者，可以任何顺序出现：
  • 无符号后缀 （字符 u 或字符 U ）
  • 长后缀 （字符 l 或字符 L ）或 长长后缀 （字符序列 ll 或 LL ） (C99 起)

数位间可插入作为分隔符的可选的单引号（'）。编译器会忽略它们。

 (C23 起)

解释

1) 十进制整数常量（底 10 ，首位为最高位）。
2) 八进制整数常量（底 8 ，首位为最高位）。
3) 十六进制整数常量（底 16 ，首位为最高位，字母 'a' 到 'f' 表示十进制值 10 到 15 ）。
4) 二进制整数常量（底 2 ，首位为最高位）。

下列对象被初始化为相同值：

int d = 42;
int o = 052;
int x = 0x2a;
int X = 0X2A;
int b = 0b101010; // C23

下列对象也被初始化为相同值：

unsigned long long l1 = 18446744073709550592ull; // C99
unsigned long long l2 = 18'446'744'073'709'550'592llu; // C23
unsigned long long l3 = 1844'6744'0737'0955'0592uLL; // C23
unsigned long long l4 = 184467'440737'0'95505'92LLU; // C23

整数常量的类型

整数常量类型是从依赖数字底和所用 整数后缀 的类型列表中，值所能吻合的首个类型。

允许的整数常量类型
后缀 | 十进制底 | 其他底
无后缀 int

long int
unsigned long int (C99 前)
long long int (C99 起)

 int

unsigned int
long int
unsigned long int
long long int(C99 起)
unsigned long long int(C99 起)
u 或 U unsigned int

unsigned long int
unsigned long long int(C99 起)

 unsigned int

unsigned long int
unsigned long long int(C99 起)
l 或 L long int

unsigned long int(C99 前)
long long int(C99 起)

 long int

unsigned long int
long long int(C99 起)
unsigned long long int(C99 起)
l/L 与 u/U unsigned long int

unsigned long long int(C99 起)

 unsigned long int

unsigned long long int(C99 起)
ll 或 LL long long int(C99 起) long long int(C99 起)

unsigned long long int(C99 起)
ll/LL 与 u/U | unsigned long long int(C99 起) | unsigned long long int(C99 起)

若整数常量过大从而无法符合后缀/底结合所允许的任何类型，且编译器支持扩展整数类型（譬如 __int128 ），则常量可能以扩展整数类型给出；否则程序为谬构。

注解

整数常量中的字母无关大小写： 0xDeAdBaBeU 和 0XdeadBABEu 表示同一个数（一个例外是 long-long-suffix ，必须是 ll 或 LL ，不能是 lL 或 Ll ） (C99 起)。

没有负整数常量。如 -1 的表达式是将一元负运算符应用到常量所表示的值，可能会引起隐式类型转换。

当用于 #if 或 #elif 的控制表达式时，所有有符号整数常量都表现为如同拥有 intmax_t 类型，且所有无符号整数常量都表现为如同有 uintmax_t 类型。

 (C99 起)

整数常量可用于整数常量表达式。

由于最大吞噬规则，以 e 和 E 结束的十六进制整数常量在后随运算符 + 或 - 时，源码中必须以空白符或括号将它们与运算符分隔：

int x = 0xE+2;   // 错误
int y = 0xa+2;   // OK
int z = 0xE +2;  // OK
int q = (0xE)+2; // OK

否则形成一个非法的预处理数字记号，这会进一步导致分析失败。

示例

#include <stdio.h>
#include <inttypes.h>
int main(void)
{
    printf("123 = %d\n", 123);
    printf("0123 = %d\n", 0123);
    printf("0x123 = %d\n", 0x123);
    printf("12345678901234567890ull = %llu\n", 12345678901234567890ull);
    // 类型为 64 位类型（ unsigned long long 或可能的 unsigned long ）
    // 即使无 long 后缀
    printf("12345678901234567890u = %"PRIu64"\n", 12345678901234567890u );

//  printf("%lld\n", -9223372036854775808); // 错误
// 值 9223372036854775808 不能适合 signed long long ，
// 它是无后缀十进制整数常量所允许的最大值

    printf("%llu\n", -9223372036854775808ull );
    // 应用到无符号值的一元减将它从 2^64 减去
    // 这给出无符号 9223372036854775808

    printf("%lld\n", -9223372036854775807ull - 1);
    // 组成有符号值 -9223372036854775808 的正确方式
}

输出：

123 = 123
0123 = 83
0x123 = 291
12345678901234567890ull = 12345678901234567890
12345678901234567890u = 12345678901234567890
9223372036854775808
-9223372036854775808

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.4.4.1 Integer constants (p: 45-46)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.4.4.1 Integer constants (p: 62-64)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.4.4.1 Integer constants (p: 54-56)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.1.3.2 Integer constants

参阅


生存期

< c‎ | language

C 中每个对象存在、拥有常地址、保有其最近一次存储值（除非其值不确定），对于 VLA 还有保有其大小 (C99 起)的程序执行部分，被称作该对象的生存期。

对于声明有自动、静态及线程存储期的对象，生存期等于其存储期（注意非 VLA 和 VLA 自动存储期的区别）。

对于拥有分配存储期的对象，其生存期始于分配函数的返回（包含从 realloc 返回），终于 realloc 或解分配函数的调用。注意因为分配的对象没有声明类型，首次访问该对象所用的左值表达式类型会成为其有效类型。

在生存期外访问对象是未定义行为。

int* foo(void) {
    int a = 17; // a拥有自动存储期
    return &a;
}  // a的生存期结束
int main(void) {
    int* p = foo(); // p 指向生存期结束后的对象（“悬垂指针”）
    int n = *p; // 未定义行为
}

指向生存期结束的对象（或该对象后一位置）的指针拥有不确定值。

临时生存期

非左值表达式所指代的拥有数组成员的结构体和联合体对象（直接为其成员或为嵌套的结构体/联合体成员）拥有临时生存期。临时生存期始于求值指代该对象的表达式，终于下一个序列点 (C11 前)包含它的完整表达式或完整声明器结束 (C11 起)。

任何修改临时生存期对象的尝试会导致未定义行为。

struct T { double a[4]; };
struct T f(void) { return (struct T){3.15}; }
double g1(double* x) { return *x; }
void g2(double* x) { *x = 1.0; }
int main(void)
{
    double d = g1(f().a); // C99 ： UB 访问生存期结束于 g1 开序列点的 a[0]
                          // C11 ： OK ， d 为 3.15
    g2(f().a); // C99 ： UB 修改生存期结束于序列点的 a[0]
               // C11 ： UB 试图修改临时对象
}

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.2.4 Storage durations of objects (p: 38-39)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.2.4 Storage durations of objects (p: 32)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.1.2.4 Storage durations of objects

参阅


主函数

< c‎ | language

每个要在宿主环境运行的编码 C 程序都含有称作 main 的函数定义（非原型），它是函数的受指定起始点。

int main (void) { body } | (1)
int main (int argc, char *argv[]) { body } | (2)
/* 其他实现定义签名 */ (C99 起) | (3)

参数

argc | - | 代表程序所运行的环境传递给程序的参数数量。
argv | - | 指向 argc + 1 个指针的数组的首元素的指针。数组末元素为空指针，而若前面有元素，则它们指向表示从宿主环境传递给程序的参数的字符串。若 argv[0] 不是空指针（或等价地 argc > 0 ），则它指向表示程序名的字符串。若程序名从宿主环境不可用则该字符串为空。

名称 argc 和 argv 表示参数计数和参数向量。参数的名称和类型表示是任意的： int main(int ac, char** av) 同样合法。

main 的常见实现定义形式是 int main(int argc, char *argv[], char *envp[]) ，其中第三参数类型为 char** ，指向指向执行环境变量的指针数组。

返回值

若使用返回语句，则返回值会用作隐式调用 exit() 的参数（细节见下）。值零和 EXIT_SUCCESS 指示成功终止，值 EXIT_FAILURE 指示不成功终止。

解释

在程序启动时，初始化所有静态存储期对象后调用 main 函数。它指明执行于宿主环境（即在操作系统中）的程序入口点。任何独立程序（引导程序、操作系统核心等）的入口点的名称和类型是实现定义的。

主函数的双参数形式允许从执行环境传递任意的多字节字符串（常称作命令行参数）。指针 argv[1] .. argv[argc-1] 指向每个这些字符串的首字符。 argv[0] 指向代表用于调用程序自身的名称的，空终止多字节字符串的首字符（或者若宿主环境不支持此做法，则保证 argv[0][0] 为零）。

若宿主环境不能一同提供大写和小写字母，则转换命令行参数为小写。

字符串可修改，而且任何修改会留存到程序终止时，尽管这些修改不会传播回宿主环境：例如能以 strtok 使用它们。

argv 所指的数组大小至少是 argc+1 ，并保证末元素 argv[argc] 为空指针。

main 函数拥有几个特殊属性：

1) 程序不能提供此函数的原型
2) 若主函数的返回类型与 int 兼容，则从对 main 的初次调用（但不是任何后继、递归调用）返回，等价于以主函数返回值为参数执行 exit 函数（将调用 atexit 所注册的函数，冲入并关闭所有流，删除 tmpfile 所创建的文件，并返还控制给执行环境）。
3)
若 main 函数执行不指定值的 return ，或同样地未执行 return 就抵达结尾的 } ，则返回给宿主环境的终止状态未定义。 | (C99 前)
若 main 函数的返回类型与 int 不兼容（如 void main(void) ），则返回给宿主环境的值未指定。若返回类型与 int 兼容且控制抵达结尾的 } ，则返回给执行环境的值与如同执行 return 0; 的结果相同。 | (C99 起)

示例

演示如何告知程序其寻找输入处及写结果处。 调用： ./a.out indatafile outdatafile

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("argc = %d\n", argc);
    for(int ndx = 0; ndx != argc; ++ndx)
        printf("argv[%d] --> %s\n", ndx,argv[ndx]);
    printf("argv[argc] = %p\n", (void*)argv[argc]);
}

可能的输出：

argc = 3
argv[0] --> ./a.out
argv[1] --> indatafile
argv[2] --> outdatafile
argv[argc] = (nil)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 5.1.2.2.1 Program startup (p: 13)
  • C99 标准（ISO/IEC 9899:1999）：
  • 5.1.2.2.1 Program startup (p: 12)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 5.1.2.2 Hosted environment

参阅


替用运算符及记号

< c‎ | language

C 源代码可以用任何包含 ISO 646:1983 不变量字符集的 8 位字符集书写，即使是非 ASCII 字符集。然而，数个 C 运算符和标点在 ISO 646 代码集外：{, }, [, ], #, \, ^, |, ~。为能使用所有这些符号不存在于其中字符编码（例如德文 DIN 66003 ），有二种可能：另一种使用这些字符集的运算符拼写，或二或三个 ISO 646 兼容字符的特殊组合，会像单个非 ISO 646 字符般转译它们。

运算符宏(C95)

有使用非 ISO 646 字符的替用拼写，作为宏定义于 <iso646.h> ：

定义于头文件 <iso646.h>
基本 | 替用
&& | and (运算符宏)
&= | and_eq (运算符宏)
& | bitand (运算符宏)
| | bitor (运算符宏)
~ | compl (运算符宏)
! | not (运算符宏)
!= | not_eq (运算符宏)
|| | or (运算符宏)
|= | or_eq (运算符宏)
^ | xor (运算符宏)
^= | xor_eq (运算符宏)

字符 & 及 ! 在 ISO-646 下不变，但仍然为这些运算符提供替用写法，以使用这些字符适应更加受限的历史字符集。

没有等于运算符的替用拼写 == ，因为字符 = 已在所有受支持字符集中存在。

替用记号(C95)

下列替用记号是核心语言的一部分，而且在语言的所有方面，每个替用记号表现准确等同于其基本记号，除了其拼写（字符串化运算符可令拼写可见）。双字另种记号有时被称为“双标符”。

基本 | 替用
{ | <%
} | %>
[ | <:
] | :>
# | %:
## | %:%:

三标符

下列三字符组（三标符）在注释前分析并在字符串字面量中得到辨认，而且每个三标符的出现会被对应的基本字符取代：

基本 | 三标符
{ | ??<
} | ??>
[ | ??(
] | ??)
# | ??=
\ | ??/
^ | ??'
| | ??!
~ | ??-

因为三标符在早期处理，故如 // Will the next line be executed?????/ 的注释可以有效地注释掉下一行，且如 "What's going on??!" 的字符串字面量被分析成 "What's going on|" 。

示例

下例演示来自 <iso646.h> 的替用运算符拼写，以及双标符和三标符的使用。 首个命令行参数， argv[1] ，要求用引号标注： ", World!" 。

%:include <stdlib.h>
%:include <stdio.h>
%:include <iso646.h>

int main(int argc, char** argv)
??<
    if (argc > 1 and argv<:1:> not_eq NULL)
    <%
       printf("Hello%s\n", argv<:1:>);
    %>

    return EXIT_SUCCESS;
??>

可能的输出：

Hello, World!

参阅


算术运算符

< c‎ | language

算术运算符应用标准数学运算符到其操作数。

本节未完成
原因：为这个和其他表格考虑更通用的，覆盖多个专题的 ToC
运算符 | 运算符名 | 示例 | 结果
+ | 一元加 | +a | a 提升后的值
- | 一元减 | -a | a 的相反数
+ | 加法 | a + b | a 加 b
- | 减法 | a - b | 从 a 减去 b
* | 乘法 | a * b | a 和 b 的积
/ | 除法 | a / b | a 除以 b 的商
% | 模 | a % b | a 除以 b 的余数
~ | 逐位非 | ~a | a 的逐位非
& | 逐位与 | a & b | a 和 b 的逐位与
| | 逐位或 | a | b | a 和 b 的逐位或
^ | 逐位异或 | a ^ b | a 和 b 的逐位异或
<< | 逐位左移 | a << b | a 左移 b 位
>> | 逐位右移 | a >> b | a 右移 b 位

溢出

无符号整数算术始终进行 modulo 2n
 ，其中 n 是该特定整数中的位数。例如对于 unsigned int ，加一到 UINT_MAX 给出 ​0​ ，而从 ​0​ 减一给出 UINT_MAX 。

有符号算术运算溢出（结果不符合结果类型）时，行为未定义：可以按照表示（典型为补码）的规则回卷，可以在某些平台上或由于编译器选项（例如 gcc 和 clang 中的 -ftrapv ）陷落，或完全被编译器优化掉。

浮点环境

若设置 #pragma STDC FENV_ACCESS 为 ON ，则所有浮点算术运算符遵循当前浮点舍入方向并报告 math_errhandling 中指定的错误，除非它们是静态初始化器的一部分（该情况下不引发浮点异常，而舍入模式为到最接近）。

浮点缩略

除非设置 #pragma STDC FP_CONTRACT 为 OFF ，否则可能如同中间结果拥有无限范围和精度一般进行所有浮点算术，这种优化省略若准确按写法求值表达式，则会观察到的舍入误差和浮点异常。例如，允许以单条融合乘加 CPU 指令实现 (x*y) + z ，或把 a = x*x*x*x; 优化成 tmp = x*x; a = tmp*tmp 。

与缩略无关，浮点算术的中间结果可以拥有异于其类型所指定的范围和精度，见 FLT_EVAL_METHOD 。

一元算术

一元算术运算符表达式拥有形式

+ expression | (1)
- expression | (2)
1) 一元加（提升）
2) 一元减（相反数）

where

expression - 任何算术类型表达式

一元加和一元减都首先应用整数提升到其操作数，然后

  • 一元加返回提升后的值
  • 一元减返回提升后值的相反数（除了 NaN 的相反数是另一 NaN ）

表达式类型为提升后的类型，而值类别为非左值。

注意

在典型（补码）平台上应用到 INT_MIN 、 LONG_MIN 或 LLONG_MIN 时，一元减引起有符号整数溢出所致的未定义行为。

C++ 中一元运算符 + 亦能用于其他内建类型，例如数组和函数，但 C 中不能。

#include <stdio.h>
#include <complex.h>
int main(void)
{
    char c = 'a';
    printf("sizeof char: %zu sizeof int: %zu\n", sizeof c, sizeof +c);

    printf("-1, where 1 is signed: %d\n", -1);
    printf("-1, where 1 is unsigned: %u\n", -1u);

    double complex z = 1 + 2*I;
    printf("-(1+2i) = %.1f%+.1f\n", creal(-z), cimag(-z));
}

可能的输出：

sizeof char: 1 sizeof int: 4
-1, where 1 is signed: -1
-1, where 1 is unsigned: 4294967295
-(1+2i) = -1.0-2.0

加法性运算符

下列加法性算术运算符拥有形式

lhs + rhs | (1)
lhs - rhs | (2)
1) 加法： lhs 与 rhs 必须为下列之一
  • 都拥有算术类型，包含复数和虚数
  • 一个是指向完整对象的指针类型，另一个拥有整数类型
2) 减法： lhs 与 rhs 必须为下列之一
  • 都拥有算术类型，包含复数和虚数
  • lhs 拥有指向完整对象的指针类型， rhs 拥有整数类型
  • 都是指向拥有兼容类型的完整对象指针，忽略限定符

算术加法与减法

若两个操作数都拥有算术类型，则

  • 首先，进行通常算术转换
  • 然后，遵循数学规则，加或减操作数在提升后的值（对于减法，从 lhs 减去 rhs ），除了
  • 若操作数之一为 NaN ，则结果为 NaN
  • 同号无穷大减无穷大为 NaN 并引发 FE_INVALID
  • 正无穷大加负无穷大为 NaN 并引发 FE_INVALID

复数和虚数加减法定义如下（注意若两个操作数均为虚数则结果类型为虚数，而若一个操作数为实数而另一为虚数，则结果为复数，同通常算术转换所指定）：

+ or - | u | iv | u + iv
x | x ± u | x ± iv | (x ± u) ± iv
iy | ±u + iy | i(y ± v) | ±u + i(y ± v)
x + iy | (x ± u) + iy | x + i(y ± v) | (x ± u) + i(y ± v)

// 工作中
// 注意：采用 c/language/conversion 示例的一部分

指针算术

  • 若指针 P 指向下标为 I 的数组元素，则
  • P+N 与 N+P 是指向同一数组中下标为 I+N 的元素的指针
  • P-N 是指向同一数组中下标为 I-N 的元素的指针

仅若原指针和结果指针都指向同一数组中的元素，或该数组的尾后一位置，行为才有定义。注意在 p 指向数组首元素时，执行 p-1 是未定义行为，并且在某些平台上可能失败。

  • 若指针 P1 指向下标为 I 的数组元素（或尾后一位置）而 P2 是指向同一数组的下标为 J 的元素（或尾后一位置），则
  • P1-P2 拥有等于 I-J 的值和 ptrdiff_t 类型（有符号整数类型，最大大小典型地为能声明的最大对象的一半）

仅若结果适合于 ptrdiff_t ，行为才有定义。

为指针算术的目的，把指向非数组元素的对象的指针当做指向大小为 1 的数组首元素的指针。

// 工作中
int n = 4, m = 3;
int a[n][m];     // 4 个 VLA 的 VLA ，每个有 3 个 int
int (*p)[m] = a; // p == &a[0]
p = p + 1;       // p == &a[1] （ VLA 所用的指针算术一如平常）
(*p)[2] = 99;    // 更改 a[1][2]

乘法性运算符

下列乘法性运算符拥有形式

lhs * rhs | (1)
lhs / rhs | (2)
lhs % rhs | (3)
1) 乘法。 lhs 与 rhs 必须拥有算术类型
2) 除法。 lhs 与 rhs 必须拥有算术类型
3) 余数。 lhs 与 rhs 必须拥有整数类型
  • 首先，进行通常算术转换。然后……

乘法

二元运算符 * 遵循通常算术定义，进行其操作数（在通常算术提升后）的乘法，除了

  • 若操作数之一为 NaN ，则结果为 NaN
  • 无穷大乘零给出 NaN 并引发 FE_INVALID
  • 无穷大乘非零给出无穷大（即使对于复参数）

因为 C 中，任何带至少一个无穷大部分的复数值为无穷大，即使另一部分为 NaN ，故通常算术规则不应用于复复乘法。其他浮点操作数的组合遵循下表：

* | u | iv | u + iv
x | xu | i(xv) | (xu) + i(xv)
iy | i(yu) | −yv | (−yv) + i(yu)
x + iy | (xu) + i(yu) | (−yv) + i(xv) | special rules

在无穷大处理外，不允许复数乘法上溢中间结果，除了在设置 #pragma STDC CX_LIMITED_RANGE 为 ON 时，该情况下可以如同 (x+iy)×(u+iv) = (xu-yv)+i(yu+xv) 一般计算值，因为假定了程序员负责限制操作数的范围并处理无穷大。

虽然不允许过度的上溢，复数乘法可能引发虚假的浮点异常（否则实现不上溢版本困难到近乎不可能）。

#include<stdio.h>
#include <stdio.h>
#include <complex.h>
#include <math.h>
int main(void)
{

// TODO 从 C++ 采取一些更简单的情况

   double complex z = (1 + 0*I) * (INFINITY + I*INFINITY);
// 教科书公式会给出
// (1+i0)(∞+i∞) ⇒ (1×∞ – 0×∞) + i(0×∞+1×∞) ⇒ NaN + I*NaN
// 但 C 给出复无穷大
   printf("%f + i*%f\n", creal(z), cimag(z));

// 教科书公式会给出
// cexp(∞+iNaN) ⇒ exp(∞)×(cis(NaN)) ⇒ NaN + I*NaN
// 但 C 给出 ±∞+i*nan
   double complex y = cexp(INFINITY + I*NAN);
   printf("%f + i*%f\n", creal(y), cimag(y));

}

可能的输出：

inf + i*inf
inf + i*nan

除法

二元运算符 / 遵循通常的算术定义，将第一操作数除以第二操作数（在通常算术转换后），除了

  • 通常算术提升后的类型为整数类型时，结果为代数商（非分数），以实现定义方向取整 (C99 前)向零截断 (C99 起)
  • 若操作数之一为 NaN ，则结果为 NaN
  • 若第一操作数为复无穷大，而第二操作数为有限，则 / 运算符的结果为复无穷大
  • 若第一操作数为有限而第二操作数为复无穷大，则 / 运算符的结果为零

因为 C 中，任何带至少一个无穷大部分的复数值为无穷大，即使另一部分为 NaN ，故通常算术规则不应用于复复除法。其他浮点操作数的组合遵循下表：

/ | u | iv
x | x/u | i(−x/v)
iy | i(y/u) | y/v
x + iy | (x/u) + i(y/u) | (y/v) + i(−x/v)

在无穷大处理外，不允许复数除法上溢中间结果，除了在设置 #pragma STDC CX_LIMITED_RANGE 为 ON 时，该情况下可以如同 (x+iy)/(u+iv) = [(xu+yv)+i(yu-xv)]/(u2
+v2
) 一般计算值，因为假定了程序员负责限制操作数的范围并处理无穷大。

虽然不允许过度的上溢，复数除法可能引发虚假的浮点异常（否则实现不上溢版本困难到近乎不可能）。

若第二操作数为零，则行为未定义，除非支持 IEE 浮点算术，且发生浮点除法，则

  • 非零数除以 ±0.0 给出符号正确的无穷大并引发 FE_DIVBYZERO
  • 0.0 除以 0.0 给出 NaN 并引发 FE_INVALID

余数

二元运算符 % 产出第一操作数除以第二操作数（在通常算术转换后）的余数。

余数的符号定义，使得若商 a/b 能以结果类型表示，则 (a/b)*b + a%b == a 。

若第二操作数为零，则行为未定义。

若商 a/b 不能以结果类型表示，则 a/b 和 a%b 的行为都未定义（这表明 INT_MIN%-1 在补码系统上未定义）。

注意：余数运算符不可用于浮点类型上，库函数 fmod 提供该功能。

逐位逻辑

逐位逻辑运算符拥有形式

~ rhs | (1)
lhs & rhs | (2)
lhs | rhs | (3)
lhs ^ rhs | (4)
1) 逐位非
2) 逐位与
3) 逐位或
4) 逐位异或

其中

lhs, rhs - 整数类型表达式

首先，运算符 & 、 ^ 和 | 在两个操作数上进行通常算术转换，而运算符 ~ 在其唯一的操作数上进行整数提升。

然后，逐位应用对应的逻辑运算符；即按照应用到操作数的每位的逻辑运算（或、与、非、异或），设置或清除结果的对应位。

注意：位运算符常用于操作位集和位掩码。

注意：对于无符号类型（提升后），表达式 ~E 等价于结果类型的最大可表示值减 E 的原值。

#include <stdio.h>
#include <stdint.h>
int main(void)
{
    uint16_t mask = 0x00f0;
    uint32_t a = 0x12345678;
    printf("Value: %#x mask: %#x\n"
           "Setting bits:   %#x\n"
           "Clearing bits:  %#x\n"
           "Selecting bits: %#x\n",
           a,mask,(a|mask),(a&~mask),(a&mask));
}

可能的输出：

Value: 0x12345678 mask: 0xf0
Setting bits:   0x123456f8
Clearing bits:  0x12345608
Selecting bits: 0x70

位移运算符

位移运算符表达式拥有形式

lhs << rhs | (1)
lhs >> rhs | (2)
1) lhs 左移 rhs 位
2) lhs 右移 rhs 位

其中

lhs, rhs - 整数类型表达式

首先，在每个操作数上独自进行整数提升（注意：这不同于其他二元算术运算符，它们全都进行通常算术转换）。结果类型为 lhs 在提升后的类型。

对于无符号 lhs ， LHS << RHS 的值是 LHS * 2RHS
 以返回类型最大值加 1 取模（即进行逐位左移，并舍弃移出目标类型的位）。对于有非负值的有符号 lhs ，若值能以 lhs 的提升后类型表示，则 LHS << RHS 的值是 LHS * 2RHS
 ，否则行为未定义。

对于无符号 lhs 和有非负值的有符号 lhs ， LHS >> RHS 的值是 LHS / 2RHS
 的整数部分。对于负的 LHS ， LHS >> RHS 的值是实现定义的，大多数实现中，这进行算术右移（故结果仍为负）。从而在大多数实现中，右移有符号的 LHS 会以原符号位填充新的高位（即若原数非负则为 0 ，而若原数为负则为 1 ）。

任何情况下，若 rhs 为负或大于或等于提升后的 lhs 中的位数，则行为未定义。

#include <stdio.h>
enum {ONE=1, TWO=2};
int main(void)
{
    char c = 0x10;
    unsigned long long ulong_num = 0x123;
    printf("0x123 << 1  = %#llx\n"
           "0x123 << 63 = %#llx\n"   // 对无符号数，溢出截断高位
           "0x10  << 10 = %#x\n",    // char 被提升到 int
           ulong_num << 1, ulong_num << 63, c << 10);
    long long long_num = -1000;
    printf("-1000 >> 1 = %lld\n", long_num >> ONE);  // 实现定义
}

可能的输出：

0x123 << 1  = 0x246
0x123 << 63 = 0x8000000000000000
0x10  << 10 = 0x4000
-1000 >> 1 = -500

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.5.3.3 Unary arithmetic operators (p: 89)
  • 6.5.5 Multiplicative operators (p: 92)
  • 6.5.6 Additive operators (p: 92-94)
  • 6.5.7 Bitwise shift operators (p: 94-95)
  • 6.5.10 Bitwise AND operator (p: 97)
  • 6.5.11 Bitwise exclusive OR operator (p: 98)
  • 6.5.12 Bitwise inclusive OR operator (p: 98)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.5.3.3 Unary arithmetic operators (p: 79)
  • 6.5.5 Multiplicative operators (p: 82)
  • 6.5.6 Additive operators (p: 82-84)
  • 6.5.7 Bitwise shift operators (p: 84-85)
  • 6.5.10 Bitwise AND operator (p: 87)
  • 6.5.11 Bitwise exclusive OR operator (p: 88)
  • 6.5.12 Bitwise inclusive OR operator (p: 88)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.3.3.3 Unary arithmetic operators
  • 3.3.5 Multiplicative operators
  • 3.3.6 Additive operators
  • 3.3.7 Bitwise shift operators
  • 3.3.10 Bitwise AND operator
  • 3.3.11 Bitwise exclusive OR operator
  • 3.3.12 Bitwise inclusive OR operator

参阅

运算符优先级

常用运算符
赋值 自增
自减 		算术 逻辑 比较 成员
访问 		其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b

a[b]
*a
&a
a->b
a.b

a(...)
a, b
(type) a
? :
sizeof
_Alignof (C11 起)


赋值运算符

< c‎ | language

赋值及复合赋值运算符是二元运算符，它们用在其右侧的值修改在其左侧的变量。

运算符 | 运算符名 | 示例 | 描述 | 等价
= | 基本赋值 | a = b | a 变得等于 b | N/A
+= | 加法赋值 | a += b | a 变得等于 a 与 b 的和 | a = a + b
-= | 减法赋值 | a -= b | a 变得等于从 a 减 b 的差 | a = a - b
*= | 乘法赋值 | a *= b | a 变得等于 a 与 b 的积 | a = a * b
/= | 除法赋值 | a /= b | a 变得等于 a 除以 b的商 | a = a / b
%= | 模赋值 | a %= b | a 变得等于 a 除以 b 的余数 | a = a % b
&= | 逐位与赋值 | a &= b | a 变得等于 a 与 b 的逐位或 | a = a & b
|= | 逐位或赋值 | a |= b | a 变得等于 a 与 b 的逐位与 | a = a | b
^= | 逐位异或赋值 | a ^= b | a 变得等于 a 与 b 的逐位异或 | a = a ^ b
<<= | 逐位左移赋值 | a <<= b | a 变得等于 a 左移 b 位 | a = a << b
>>= | 逐位右移赋值 | a >>= b | a 变得等于 a 右移 b 位 | a = a >> b

简单赋值

简单赋值运算符表达式拥有形式

lhs = rhs

其中

lhs | - | 任何完整对象类型的可修改左值表达式
rhs | - | 任何可隐式转换成 lhs 或与 lhs 兼容类型的表达式

赋值进行从 rhs 的值到 lhs 类型的隐式转换，然后用 rhs 转换后的值替换 lhs 所指代对象中的值。

赋值亦返回存储于 lhs 中的相同值（故如 a = b = c 的表达式是可行的）。赋值运算符的值类别是非左值（故如 (a=b)=c 的表达式非法）。

rhs 与 lhs 必须满足下列条件之一：

  • lhs 与 rhs 拥有兼容的 struct 或 union 类型，或……
  • rhs 必须可隐式转换成 lhs ，这表示
  • lhs 与 rhs 均拥有算术类型，此情况下 lhs 可为volatile 限定或原子的
  • lhs 与 rhs 均拥有指向兼容类型的指针类型，或其中一个指针是指向 void 的指针，而转换不为被指向类型添加限定符。 lhs 可以为 volatile 或 restrict 限定，或原子的。
  • lhs 是指针（可以有限定或是原子的），而 rhs 是空指针常量，如 NULL 。
  • lhs 拥有类型 _Bool（可以有限定或是原子的）而 rhs 是指针 。

注意

若 rhs 与 lhs 在内存中重叠（例如它们是同一联合体的成员），则行为未定义，除非重叠是准确的且两者类型兼容。

尽管数组不可赋值，但包裹在结构体内的数组可以赋值给另一个相同（或兼容）的结构体类型。

更新 lhs 的副效应后序于值计算，但 lhs 和 rhs 自己和运算数的求值不是，与通常一样，它们相对于彼此是不定序的（故如 i=++i 的表达式是未定义的）

赋值会剥除浮点表达式的额外范围和精度（见 FLT_EVAL_METHOD ）。

C++ 中，赋值运算符是左值表达式，而 C 中不是

#include <stdio.h>

int main(void)
{
    const char **cpp;
    char *p;
    const char c = 'A';

//  cpp = &p;  // 错误： char** 不能转换为 const char**
    *cpp = &c; // OK ： char* 能转换为 const char*
    *p = 0;    // OK ：空指针常量能转换为任何指针

    int arr1[2] = {1,2}, arr2[2] = {3, 4};
//  arr1 = arr2; // 错误：不能通过数组赋值

    struct s {
         int arr[2]; // 包装于结构体中的数组
    } sam1 = {5, 6}, sam2 = {7, 8};
    sam1 = sam2; // OK ：能赋值包装于结构体中的数组

    printf("%d %d \n",sam1.arr[0],sam1.arr[1]);
}

输出：

7 8

复合赋值

复合赋值运算符表达式拥有形式

lhs op rhs

其中

op | - | one of *=, /= %=, += -=, <<=, >>=, &=, ^=, |=
lhs, rhs | - | 拥有算术类型的表达式（其中 lhs 可以有限定或是原子的），除非 op 是 += 或 -= ，此情况允许接受拥有与 + 和 - 相同限制的指针类型

表达式 lhs @= rhs 与 lhs = lhs @ ( rhs ) 准确相同，除了只求值一次 lhs 。

若 lhs 拥有原子类型，则运算表现为单个带内存顺序 memory_order_seq_cst 的原子读修改写操作

对于整数原子类型，复合赋值运算 @= 等价于：

T1* addr = &lhs;
T2 val = rhs;
T1 old = *addr;
T1 new;
do { new = old @ val } while (!atomic_compare_exchange_strong(addr, &old, new);
 (C11 起)
本节未完成
原因：暂无示例

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.5.16 Assignment operators (p: 101-104)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.5.16 Assignment operators (p: 91-93)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.3.16 Assignment operators

参阅

运算符优先级

常用运算符
赋值 自增
自减 		算术 逻辑 比较 成员
访问 		其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b

a[b]
*a
&a
a->b
a.b

a(...)
a, b
(type) a
? :
sizeof
_Alignof (C11 起)


比较运算符

< c‎ | language

比较运算符是二元运算符，它们测试条件，而若条件逻辑上为真则返回 1 ，若条件为假则返回 0 。

运算符 | 运算符名 | 示例 | 描述
== | 等于 | a == b | a 等于 b
!= | 不等于 | a != b | a 不等于b
< | 小于 | a < b | a 小于 b
> | 大于 | a > b | a 大于 b
<= | 小于或等于 | a <= b | a 小于或等于 b
>= | 大于或等于 | a >= b | a 大于或等于 b

关系运算符

关系运算符表达式拥有形式

lhs < rhs | (1)
lhs > rhs | (2)
lhs <= rhs | (3)
lhs >= rhs | (4)
1) 小于表达式
2) 大于表达式
3) 小于或等于表达式
4) 大于或等于表达式

其中

lhs, rhs - 都拥有实数类型或都拥有指向对象指针类型的表达式

任何关系运算符表达式的类型为 int ，而当指定关系成立时其值（非左值）为 1 ，而当指定关系不成立时其值为 ​0​ 。

若 lhs 和 rhs 是任何实数类型表达式，则

  • 进行通常算术转换
  • 以通常数学意义比较运算数转换后的值（除了正零与负零比较相等，而任何涉及 NaN 的比较返回零）

注意不能用这些运算符比较复数和虚数。

若 lhs 和 rhs 是指针类型表达式，则它们必须都是指向兼容类型对象的指针，除了忽略被指向对象上的限定。

  • 指向非数组元素的指针被当做如同它是指向有一个元素的数组的首元素的指针
  • 若二个指针指向同一对象，或都指向同一数组的尾后一位置，则它们比较相等
  • 若二个数组指向同一数组的不同元素，则指向有较大下标的元素的指针比较大于另一者。
  • 若一个指针指向数组元素，而另一指针指向同一数组的尾后一位置，则尾后一位置指针比较大于前者
  • 若二个指针指向同一结构体的成员，则指向结构体声明中较后声明的成员的指针，比较大于指向较先声明的成员的指针。
  • 指向同一联合体成员的指针比较相等
  • 所有其他指针比较引起未定义行为
#include <assert.h>
int main(void)
{
    assert(1 < 2);
    assert(2+2 <= 4.0); // int 可转换为 double ，二个 4.0 比较相等

    struct { int x,y; } s;
    assert(&s.x < &s.y); // 结构体成员以声明顺序比较

    double d = 0.0/0.0; // NaN
    assert( !(d < d) );
    assert( !(d > d) );
    assert( !(d >= d) );
    assert( !(d >= d) );

    float f = 0.1; // f = 0.100000001490116119384765625
    double g = 0.1; // g = 0.1000000000000000055511151231257827021181583404541015625
    assert(f > g); // 不同值
}

等于运算符

等于运算符拥有形式

lhs == rhs | (1)
lhs != rhs | (2)
1) 等于表达式
2) 不等于表达式

其中

lhs, rhs - 下列表达式之一：
  • 都拥有任何算术类型（包括复数和虚数）
  • 都是指向兼容类型对象或函数的指针，忽略被指向类型的限定符
  • 一个是指向对象指针，而另一个是指向（可有限定的） void
  • 一个是指向对象或函数指针，而另一个是如 NULL 的空指针常量

任何等于运算符表达式的类型为 int ，而当指定关系成立时其值（非左值）为 1 ，而当指定关系不成立时其值为 ​0​ 。

  • 若两个运算数都拥有算术类型，则进行通常算术转换，而以通常数学意义比较结果值（除了正零和负零比较相等，而任何涉及 NaN 值的比较，包括与自身的相等，都返回零）。特别是若复数类型值的实部比较相等且虚部比较相等，则它们相等。
  • 若一个运算数为指针而另一空指针常量，则首先转换空指针常量为该指针的类型（给出空指针值），并以后述方式比较二个指针
  • 若一个运算数是指针而另一者为指向 void 的指针，则转换非 void 指针为指向 void 指针，并以后述方式比较二个指针
  • 若下列为真，则二个指针比较相等：
  • 它们都是其类型的空指针值
  • 它们都是指向相同对象的指针
  • 一个指针指向结构体/联合体/数组对象，而另一个指向其首成员/任何成员/首元素
  • 它们都是指向同一数组末元素后一位置的指针
  • 一个是数组尾后一位置指针，另一个指向（同类型）的相异数组起始，而后一数组在更大的数组或无填充的结构体中后随前一数组

（同关系运算符，指向非数组元素的指针表现同指向大小为 1 的数组元素的指针）

注意

不能自动比较结构体类型对象，而通过 memcmp 比较它们不可靠，因为填充字节可拥有任何值。

因为指针比较能用于指向 void 的指针，故 C 中可定义宏 NULL 为 (void*)0 ，不过 C++ 中这会非法，因为其中 void 指针不可隐式转换为有类型指针。

比较浮点值是否相等时应谨慎，因为许多运算的结果无法准确表示，而必须舍入。实践中，通常以允许最后位置相差一或多个单位的方式比较浮点数。

#include <assert.h>
int main(void)
{
    assert(2+2 == 4.0); // int 可转换为 double ，二个 4.0 比较相等

    int n[2][3] = {1,2,3,4,5,6};
    int* p1 = &n[0][2]; // 第一栏中的最后元素
    int* p2 = &n[1][0]; // 第二栏的起始
    assert(p1+1 == p2); // 比较相等

    double d = 0.0/0.0; // NaN
    assert( d != d ); // NaN 不等于自身

    float f = 0.1; // f = 0.100000001490116119384765625
    double g = 0.1; // g = 0.1000000000000000055511151231257827021181583404541015625
    assert(f != g); // 不同值
}

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.5.8 Relational operators (p: 95-96)
  • 6.5.9 Equality operators (p: 96-97)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.5.8 Relational operators (p: 85-86)
  • 6.5.9 Equality operators (p: 86-87)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.3.8 Relational operators
  • 3.3.9 Equality operators

参阅

运算符优先级

常用运算符
赋值 自增
自减 		算术 逻辑 比较 成员
访问 		其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b

a[b]
*a
&a
a->b
a.b

a(...)
a, b
(type) a
? :
sizeof
_Alignof (C11 起)


自增/自减运算符

< c‎ | language

自增/自减运算符是使对象的值增加/减少 1 的一元运算符。

它们能拥有后缀形式：

expr ++
expr --

还有前缀形式：

++ expr
-- expr

前缀和后缀自增或自减的运算数 expr 必须为整数类型（包含 _Bool 和枚举）、实浮点类型或指针类型的可修改左值。它能为 cvr 限定、无限定或为原子。

后缀自增和自减运算符的结果是 expr 的值。

前缀自增运算符的结果是将值 1 加到 expr 的值的结果：表达式 ++e 等价于 e+=1 。前缀自减运算符的结果从 expr 减去值 1 的结果：表达式 --e 等价于 e-=1 。

自增运算符发动加相应类型的值 1 到运算数的副效应。自减运算符发动从运算数减去相应类型的值 1 的副效应。同其他副效应，这些操作在下个序列点或那之前完成。

int a = 1;
int b = a++; // 存储 1+a （即 2 ）到 a
             // 返回 a 的值（即 1 ）
             // 此行后， b == 1 而 a == 2
a = 1;
int c = ++a; // 存储 1+a （即 2 ）到 a
             // 返回 1+a （即 2 ）
             // 此行后， c == 2 而 a == 2

任何原子对象上的后自增或后自减运算符，是拥有 memory_order_seq_cst 内存顺序的原子读修改写操作。

 (C11 起)

指针算术上的限制，还有应用于运算数的隐式转换见算术运算符。

注意

因为涉及副效应，必须谨慎地使用自增和自减运算符，以避免违背定序规则所致的未定义行为。

自增/自减运算符不对复数或虚数类型定义：加/减实数 1 的通常定义对虚数会无效，而使之对虚数加/减 i 但对复数加/减 1 ，会使得处理 0+yi 和 yi 的方式有别。

不同于 C++ （和 C 的某些实现），自增/自减运算符自身决非左值： &++a 是非法的。

示例

#include <stdlib.h>
#include <stdio.h>

int main(void) {

  int a = 1;
  int b = 1;

  printf("\n");
  printf("original values: a == %d, b == %d\n", a, b);
  printf("result of postfix operators: a++ == %d, b-- == %d\n", a++, b--);
  printf("after postfix operators applied: a == %d, b == %d\n", a, b);

  // 重置 a 与 b 。
  a = 1;
  b = 1;

  printf("\n");
  printf("original values: a == %d, b == %d\n", a, b);
  printf("result of prefix operators: ++a == %d, --b == %d\n", ++a, --b);
  printf("after prefix operators applied: a == %d, b == %d\n", a, b);
}

输出：

original values: a == 1, b == 1
result of postfix operators: a++ == 1, b-- == 1
after postfix operators applied: a == 2, b == 0

original values: a == 1, b == 1
result of prefix operators: ++a == 2, --b == 0
after prefix operators applied: a == 2, b == 0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.5.2.4 Postfix increment and decrement operators (p: 85)
  • 6.5.3.1 Prefix increment and decrement operators (p: 88)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.5.2.4 Postfix increment and decrement operators (p: 75)
  • 6.5.3.1 Prefix increment and decrement operators (p: 78)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.3.2.4 Postfix increment and decrement operators
  • 3.3.3.1 Prefix increment and decrement operators

参阅

运算符优先级

常用运算符
赋值 自增
自减 		算术 逻辑 比较 成员
访问 		其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b

a[b]
*a
&a
a->b
a.b

a(...)
a, b
(type) a
? :
sizeof
_Alignof (C11 起)


逻辑运算符

< c‎ | language

逻辑运算符应用标准布尔代数运算到其运算数。

运算符 | 运算符名 | 示例 | 结果
! | 逻辑非 | !a | a 的逻辑否定
&& | 逻辑与 | a && b | a 与 b 的逻辑与
|| | 逻辑或 | a || b | a 与 b 的逻辑或

逻辑非

逻辑非运算符拥有形式

! expression

其中

expression - 拥有任何标量类型的表达式

逻辑非运算符拥有 int 类型。若 expression 求值为不等于零的整数则其值为 ​0​ 。若 expression 求值为等于零的整数则其值为 1 。（故 !E 与 {{c|(0==E)} 相同）

#include <stdbool.h>
#include <stdio.h>
#include <ctype.h>
int main(void)
{
    bool b = !(2+2 == 4); // 非 true
    printf("!(2+2==4) = %s\n", b ? "true" : "false");

    int n = isspace('a'); // 若 'a' 空格则为零，否则为非零
    int x = !!n; // "bang-bang" ，常用的 C 手法，映射标量为 [0,1]
                 // （所有非零值变为 1 ）
    char *a[2] = {"nonspace", "space"};
    printf("%s\n", a[x]); // 现在能安全地以 x 为 2 个 int 的数组的下标
}

输出：

!(2+2==4) = false
nonspace

逻辑与

逻辑与表达式拥有形式

lhs && rhs

其中

lhs | - | 拥有任何标量类型的表达式
rhs | - | 拥有任何标量类型的表达式，仅若 lhs 比较不等于 ​0​ 才求值

逻辑与运算符拥有 int 类型，而若 lhs 与 rhs 都比较不等于零则拥有值 1 。否则拥有值 ​0​ （若 lhs 或 rhs 之一或两者比较等于零）。

在 lhs 的求值后有序列点。若 lhs 的结果比较等于零，则完全不求值 rhs （是谓短路求值）。

#include <stdbool.h>
#include <stdio.h>
int main(void)
{
    bool b = 2+2==4 && 2*2==4; // b == true

    1 > 2 && puts("this won't print");

    char *p = "abc";
    if(p && *p) // 常用的 C 手法：若 p 非空 *与* 若 p 不指向字符串尾
    {           // （注意拜短路求值所赐，这不会试图解引用空指针）
    // ...      // ……然后做一些字符串处理
    }
}

逻辑或

逻辑或表达式拥有形式

lhs || rhs

其中

lhs | - | 拥有任何标量类型的表达式
rhs | - | 拥有任何标量类型的表达式，仅若 lhs 比较等于 ​0​ 才求值

逻辑或运算符拥有 int 类型，而若 lhs 或 rhs 比较不等于零则拥有值 1 。否则它拥有值 ​0​ （若 lhs 与 rhs 都比较等于零）、

在 lhs 的求值后有序列点。若 lhs 的结果比较不等于零，则完全不求值 rhs （是谓短路求值）。

#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(void)
{
    bool b = 2+2 == 4 || 2+2 == 5; // true
    printf("true or false = %s\n", b ? "true" : "false");

    // 逻辑或能像 perl 的 "or die" 一样使用，只要 rhs 拥有标量类型
    fopen("test.txt", "r") || printf("could not open test.txt: %s\n", strerror(errno));
}

可能的输出：

true or false = true
could not open test.txt: No such file or directory

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.5.3.3 Unary arithmetic operators (p: 89)
  • 6.5.13 Logical AND operator (p: 99)
  • 6.5.14 Logical OR operator (p: 99)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.5.3.3 Unary arithmetic operators (p: 79)
  • 6.5.13 Logical AND operator (p: 89)
  • 6.5.14 Logical OR operator (p: 89)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.3.3.3 Unary arithmetic operators
  • 3.3.13 Logical AND operator
  • 3.3.14 Logical OR operator

参阅

运算符优先级

常用运算符
赋值 自增
自减 		算术 逻辑 比较 成员
访问 		其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b

a[b]
*a
&a
a->b
a.b

a(...)
a, b
(type) a
? :
sizeof
_Alignof (C11 起)


成员访问运算符

< c‎ | language

成员访问运算符允许访问其运算数的成员。

运算符 | 运算符名 | 示例 | 描述
[] | 数组下标 | a[b] | 访问数组 a 的第 b 个元素
* | 指针解引用 | *a | 解引用指针 a 以访问其所指向的对象或函数
& | 取址 | &a | 创建指向对象或函数 a 的指针
. | 成员访问 | a.b | 访问结构体或联合体 a 的成员 b
-> | 通过指针的成员访问 | a->b | 访问 a 所指向的结构体或联合体 的成员 b

下标

数组下标运算符拥有形式

pointer-expression [ integer-expression ] | (1)
integer-expression [ pointer-expression ] | (2)

其中

pointer-expression | - | 指向完整对象指针类型的表达式
integer-expression | - | 整数类型表达式

下标运算符为左值表达式，其类型为 pointer-expression 所指向的对象的类型。

按照定义，下标运算符 E1[E2] 准确等同于 *((E1)+(E2)) 。若 pointer-expression 为数组表达式，则它经历左值到右值转换并成为指向数组首元素的指针。

由于指针与整数间加法的定义，结果是下标等于 integer-expression 结果的数组元素（或若 pointer-expression指向某数组的第 i 个元素，则结果的下标为 i 加上 integer-expression 的结果）。

注意：多维数组上的细节见数组。

#include <stdio.h>
int main(void)
{
    int a[3] = {1,2,3};
    printf("%d %d\n", a[2],  // n == 3
                      2[a]); // 同上， n == 3
    a[2] = 7; // 下标表达式是左值

    int n[2][3] = {1,2,3,4,5,6};
    int (*p)[3] = &n[1]; // n 的元素为数组
    int x = n[1][2]; // 再次应用 [] 到数组 n[1]

    printf("%c %c\n", "abc"[2], 2["abc"]); // 字符串字面量亦是数组
}

输出：

3 3
c c

解引用

解引用或间接表达式拥有形式

* pointer-expression

其中

pointer-expression - an expression of any pointer type

若 pointer-expression 为指向函数指针，则解引用运算符的结果为该函数的函数指代器。

若 pointer-expression 为指向对象指针，则结果为指代被指向对象的左值表达式。

解引用空指针、指向在生存期外的对象的指针（悬垂指针）、错误对齐的指针或拥有不确定值的指针是未定义行为，除非如在 &*E 中一般，通过应用取址运算符到解引用运算符的结果，将它置空。

#include <stdio.h>
int main(void)
{
    int n = 1;
    int* p = &n;
    printf("*p = %d\n", *p); // *p 的值即为存储于 n 的值
    *p = 7; // *p 是左值
    printf("*p = %d\n", *p);
}

输出：

*p = 1
*p = 7

取址

取址运算符拥有形式

& function | (1)
& lvalue-expression | (2)
& * expression | (3)
& expression [ expression ] | (4)
1) 函数地址
2) 对象地址
3) 特殊情况： & 与 * 彼此抵消，均不求值
4) 特殊情况： & 与 [] 中隐含的 * 抵消，只求值 [] 中隐含的加法

其中

lvalue-expression - 拥有任何非位域类型且无 register 存储类的左值表达式

取址运算符产生其运算数的非左值地址，适于初始化指向运算数类型的指针。若运算数为函数指代器 ((1)) ，则结果为指向函数指针。若运算数为对象 ((2)) ，则结果为指向对象指针。

若运算数为解引用运算符，则不进行动作（故可以应用 &* 到空指针），除了结果是非左值。

若运算数是数组下标表达式，则不进行数组到指针转换和加法外的动作，故 &a[N] 对大小为 N 的数组合法（可以获得尾后一位置指针，不能解引用它，但此表达式中解引用被取消）。

int f(char c) { return c;}
int main(void)
{
   int n = 1;
   int *p = &n; // 对象 n 的地址
   int (*fp)(char) = &f; // 函数 f 的地址
   int a[3] = {1,2,3};
   int *beg=a, *end=&a[3]; // 同 end = n+3
}

成员访问

成员访问运算符拥有形式

expression . member-name

其中

expression | - | 结构体或联合体类型表达式
member-name | - | 指名 expression 所指带的结构体或联合体的成员的标识符

成员访问表达式指代其左运算数所指代的 struct 或 union 的具名成员。它拥有与其左运算数相同的值类别。

若左运算为 const 或 volatile 限定，则结果亦有限定。若左运算数为原子对象，则行为未定义。

注意：除了指名结构体或联合体的标识符，下列表达式亦可拥有结构体或联合体类型：赋值、函数调用、逗号运算符、条件运算符和复合字面量。

#include <stdio.h>
struct s {int x;};
struct s f(void) { return (struct s){1}; }
int main(void)
{
    struct s s;
    s.x = 1; // OK ：更改 s 的成员
    int n = f().x; // f() 为 struct s 类型表达式
//  f().x = 1; // 错误：此成员访问表达式非左值

    const struct s sc;
//  sc.x = 3;  // 错误： sc.x 为 const ，不能被赋值

    union { int x; double d; } u = {1};
    u.d = 0.1; // 更改 union 的活跃成员
}

通过指针的成员访问

成员访问表达式拥有形式

expression -> member-name

其中

expression | - | 指向结构体或联合体的指针类型表达式
member-name | - | 指名 expression 所指向的结构体或联合体的成员的标识符

通过指针的成员访问表达式指代其左运算数所指向的 struct 或 union 类型的具名成员。其值类别始终为左值。

若左运算数所指向的类型有 const 或 volatile 限定，则结果亦有限定。若左运算数所指向的类型为原子类型，则行为未定义。

#include <stdio.h>
struct s {int x;};
int main(void)
{
    struct s s={1}, *p = &s;
    p->x = 7; // 通过指针更改 s.x 的值
    printf("%d\n", p->x); // 打印 7
}

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.5.2.1 Array subscripting (p: 80)
  • 6.5.2.3 Structure and union members (p: 82-84)
  • 6.5.3.2 Address and indirection operators (p: 88-89)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.5.2.1 Array subscripting (p: 70)
  • 6.5.2.3 Structure and union members (p: 72-74)
  • 6.5.3.2 Address and indirection operators (p: 78-79)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.3.2.1 Array subscripting
  • 3.3.2.3 Structure and union members
  • 3.3.3.2 Address and indirection operators

参阅

  • 运算符优先级
常用运算符
赋值 自增
自减 		算术 逻辑 比较 成员
访问 		其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b

a[b]
*a
&a
a->b
a.b

a(...)
a, b
(type) a
? :
sizeof
_Alignof (C11 起)


其他运算符

< c‎ | language

不适合任何其他主要类别的运算符的汇集。

本节未完成
原因：为这个和其他表格考虑更通用的，覆盖多个专题的 ToC
运算符 | 运算符名 | 示例 | 描述
(...) | 函数调用 | f(...) | 以令或更多参数调用 f()
, | 逗号运算符 | a, b | 求值表达式 a ，舍弃其返回值并完成任何副效应，然后求值表达式 b ，返回此求值的类型和结果
(type) | 转型 | (type)a | 转型 a 的类型为 type
? : | 条件运算符 | a ? b : c | 若 a 逻辑上为真（不求值为零）则求值表达式 b ，否则求值表达式 c
sizeof | sizeof 运算符 | sizeof a | a 的字节大小
_Alignof (C11 起) | _Alignof 运算符 | _Alignof(type) | type 对齐

函数调用

函数调用表达式拥有形式

expression ( argument-list(可选) )

其中

expression | - | 任何指向函数指针类型表达式（在左值转换后）
argument-list | - | 任何完整对象类型表达式（不能是逗号运算符）的逗号分隔列表。调用不接受参数的函数时可以省略。

函数调用表达式的行为，取决于正在调用的函数的原型是否在调用点处于作用域中。

调用有原型函数

1) 形参数量必须等于实参数量（除非使用省略号形参）。
2) 必须存在如同赋值的隐式转换，将对应实参的无限定类型转换为形参类型。
另外，对于每个在 [ 和 ] 间使用关键词 static 的数组类型形参，实参表达式所指代的数组元素数，必须不少于形参的大小表达式中指定的数量。
 (C99 起)
3) 以未指定顺序无序地求值实参。
4) 进行赋值 (C11 前)初始化 (C11 起)，复制每个实参到对应的函数形参（注意：函数能修改其形参，而这些修改不影响实参， C 函数调用只有以值调用）。
  • 若有尾随省略号形参，则在剩余实参上进行默认参数提升，这使得它们可由 va_list 访问。
5) 执行函数，而其返回值成为函数调用表达式的值（若函数返回 void ，则函数调用表达式为 void 表达式）。
void f(char* p, int x) {}
int main(void)
{
    f("abc", 3.14); // 数组到指针和 float 到 int 转换
}

调用无原型函数

1) 以未指定顺序无序地求值实参。
2) 在每个实参表达式上进行默认参数提升。
3) 进行赋值 (C11 前)初始化 (C11 起)，复制每个实参到对应的函数形参。
4) 执行函数，而其所返回的值成为函数调用表达式的值（若函数返回 void ，则函数调用表达式为 void 表达式）
void f(); // 无原型
int main(void)
{
    f(1, 1.0f); // UB ，除非定义 f 为接收一个 int 和一个 double
}
void f(int a, double c) {}

调用无原型函数的行为未定义，若

  • 实参数量不匹配形参数量
  • 提升后的实参类型与提升后形参类型不兼容，除了
  • 认为相同整数类型的有符号和无符号版本兼容，若参数值能以两个类型表示。
  • 认为指向 void 指针和指向（可有 cvr 限定的）字符类型指针兼容

注意

指代要调用的函数的 expression 和所有参数的求值相对于彼此无序（但在函数开始执行前有一个序列点）

(*pf[f1()]) (f2(), f3() + f4()); // 可以以任何顺序调用 f1 、 f2 、 f3 、 f4

尽管函数调用只对指向函数指针定义，它亦能作用于函数指代器，因为函数到指针隐式转换。

int f(void) { return 1; }
int (*pf)(void) = f;
int main(void)
{
    f();    // 转换 f 为指针，然后调用
    (&f)(); // 创建指向函数指针，然后调用

    pf();    // 调用函数
    (*pf)(); // 获得函数指代器，转换为指针，然后滴啊用、

    (****f)(); // 转换为指针，获得函数，重复 4 次，然后调用
    (****pf)(); // 亦 OK
}

必须用在作用域中的原型调用忽略不使用实参的函数，如 printf （这种函数的原型需要使用尾随省略号形参），以避免未定义行为。

C11 后缺陷报告 DR 427 将在调用有原型的函数时的函数形参准备，从赋值自其对应实参，更改为从其对应实参初始化，以允许 const 限定类型的形参（事实上已允许）。容许的隐式转换仍为如同赋值的转换，因为初始化亦使用这些。

其 expression 完全由一个标识符组成，而未声明该标识符的函数调用表达式，表现为通过将该标识符声明如下

extern int identifier(); // 返回 int 且无原型

故下列完整程序在 C89 中合法：

main() {
    int n = atoi("123"); // 隐式声明 atoi 为 int atoi()
}
 (C99 前)

逗号运算符

逗号运算符表达式拥有形式

lhs , rhs

其中

lhs | - | 任何表达式
rhs | - | 任何异于另一逗号运算符的表达式（换言之，逗号运算符的结合性为从左到右）

首先，求值左运算数 lhs 并舍弃其结果值。

然后，发生序列点，从而 lhs 的所有副效应完成。

然后，求值右运算数 rhs ，而逗号运算符作为非左值返回其结果。

注意

lhs 的类型可为 void （即可为对返回 void 的函数的调用，或能为 转型到 void 的表达式）。

逗号运算符在 C++ 中可为左值，但 C 中决不是。

逗号运算符可返回结构体（其他返回结构体的表达式仅有复合字面量、函数调用、赋值和条件运算符）。

下列语境中，逗号运算符不能出现于表达式的顶层，因为逗号有不同含义：

  • 函数调用中的实参列表
  • 初始化器表达式或初始化器列表
  • 泛型选择

若必须在这种语境中使用逗号运算符，则必须加括号：

// int n = 2,3; // 错误：认为逗号开始下个声明器
// int a[2] = {1,2,3}; // 错误：初始化器多于元素
int n = (2,3), a[2] = {(1,2),3}; // OK

f(a, (t=3, t+2), c); // OK ：存储 3 于 t ，然后以三个参数调用 f

数组边界中亦禁止顶层逗号

// int a[2,3]; // 错误
int a[(2,3)]; // OK ：大小为 3 的 VLA 数组（因为 (2, 3) 不是常量表达式故为 VLA ）

常量表达式中不允许逗号，不管它是否出现于顶层

// static int n = (1,2); // 错误：常量表达式不能调用逗号运算符

转型运算符

见转型运算符

条件运算符

条件运算符表达式拥有形式

condition ? expression-true : expression-false

其中

condition | - | 标量类型表达式
expression-true | - | 若条件比较不等于零则将求值的表达式
expression-false | - | 若条件比较等于零则将求值的表达式

仅允许下列表达式为 expression-true 和 expression-false

  • 二个任何算术类型的表达式
  • 二个相同结构体或联合体类型的表达式
  • 二个 void 类型表达式
  • 二个指针类型表达式，指向兼容的类型，忽略 cvr 限定符
  • 一个表达式是指针而另一个是空指针常量（例如 NULL ）
  • 一个表达式是指向对象指针而另一个是指向 void （可有限定）指针
1) 首先，求值 condition 。此求值后有序列点。
2) 若 condition 的结果比较等于零，则执行 expression-true ，否则执行 exception-false 。
3) 进行从结果到公共类型的转换，转换定义如下：
1) 若表达式拥有算术类型，则公共类型为通常算术转换后的类型
2) 若表达式拥有结构体/联合体类型，则公共类型为结构体/联合体类型
3) 若表达式都是 void ，则整个条件运算符表达式就是 void 表达式
4) 若一个表达式为指针而另一个是空指针常量，则类型为该指针的类型
5) 若两个表达式都是指针，则结果为指向组合两个被指向类型的 cvr 限定符的类型的指针（即若一个指针是 const int* 而另一个是 volatile int* ，则结果为 const volatile int* ），而假如类型不同，则被指向类型为两类型的合成类型。
6) 若一个表达式是指向 void 指针，则结果为指向带组合的 cvr 限定符的 void 的指针。
#define ICE(x) (sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1)))

// 若 x 是整数常量表达式，则宏展开成

 sizeof( 1 ? NULL : (int *) 1)  // (void *)((x)*0l)) -> NULL

// 按照第 (4) 点这进一步转换成

 sizeof(int)

// 若 x 不是整数常量表达式，则宏按照第 (6) 点展开成

 (sizeof(*(void *)(x))           // 因不完整类型而错误

注意

条件运算符决不是左值表达式，尽管它可以返回结构体/联合体类型的对象。其他可以返回结构体的表达式仅有赋值、逗号、函数调用和复合字面量。

注意 C++ 中它可以为左值表达式。

此运算符和赋值的相对优先级上的细节见运算符优先级。

条件运算符拥有从右到左结合性，这允许链式写法

struct vehicle v = arg == 'B' ? bus      :
                   arg == 'A' ? airplane :
                   arg == 'T' ? train    :
                   arg == 'C' ? car      :
                   arg == 'H' ? horse    :
                                feet;

sizeof 运算符

见 sizeof 运算符

_Alignof 运算符

见 _Alignof 运算符

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.5.2.2 Function calls (p: 81-82)
  • 6.5.3.4 The sizeof and _Alignof operators (p: 90-91)
  • 6.5.4 Cast operators (p: 91)
  • 6.5.15 Conditional operator (p: 100)
  • 6.5.17 Comma operator (p: 105)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.5.2.2 Function calls (p: 71-72)
  • 6.5.3.4 The sizeof operator (p: 80-81)
  • 6.5.4 Cast operators (p: 81)
  • 6.5.15 Conditional operator (p: 90-91)
  • 6.5.17 Comma operator (p: 94)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.3.2.2 Function calls
  • 3.3.3.4 The sizeof operator
  • 3.3.4 Cast operators
  • 3.3.15 Conditional operator
  • 3.3.17 Comma operator

参阅

  • 运算符优先级
常用运算符
赋值 自增
自减 		算术 逻辑 比较 成员
访问 		其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b

a[b]
*a
&a
a->b
a.b

a(...)
a, b
(type) a
? :
sizeof
_Alignof (C11 起)


C 运算符优先级

< c‎ | language

下表列出 C 运算符的优先级和结合性。运算符从顶到底以降序列出。

优先级 | 运算符 | 描述 | 结合性
1 | ++ -- | 后缀自增与自减 | 从左到右
 | () | 函数调用
 | [] | 数组下标
 | . | 结构体与联合体成员访问
 | -> | 结构体与联合体成员通过指针访问
 | (type){list} | 复合字面量(C99)
2 | ++ -- | 前缀自增与自减[注 1] | 从右到左
 | + - | 一元加与减
 | ! ~ | 逻辑非与逐位非
 | (type) | 转型
 | * | 间接（解引用）
 | & | 取址
 | sizeof | 取大小[注 2]
 | _Alignof | 对齐要求(C11)
3 | * / % | 乘法、除法及余数 | 从左到右
4 | + - | 加法及减法
5 | << >> | 逐位左移及右移
6 | < <= | 分别为 < 与 ≤ 的关系运算符
 | > >= | 分别为 > 与 ≥ 的关系运算符
7 | == != | 分别为 = 与 ≠ 关系
8 | & | 逐位与
9 | ^ | 逐位异或（排除或）
10 | | | 逐位或（包含或）
11 | && | 逻辑与
12 | || | 逻辑或
13 | ?: | 三元条件[注 3] | 从右到左
14[注 4] | = | 简单赋值
 | += -= | 以和及差赋值
 | *= /= %= | 以积、商及余数赋值
 | <<= >>= | 以逐位左移及右移赋值
 | &= ^= |= | 以逐位与、异或及或赋值
15 | , | 逗号 | 从左到右
  1. ↑ 前缀 ++ 与 -- 的运算数不能是转型。此规则在文法上禁止某些表达式本来也会在语义上非法的表达式。某些编译器忽略此规则并检测语义上的非法。
  2. ↑ sizeof 的运算数不能是类型转型：表达式 sizeof (int) * p 无歧义地转译成 (sizeof(int)) * p ，而非 sizeof((int)*p) 。
  3. ↑ 条件运算符中部（ ? 与 : 之间）的表达式分析为如同加括号：忽略其相对于 ?: 的优先级。
  4. ↑ 赋值运算符的左运算数必须是一元（第 2 级非转型）表达式。此规则在文法上禁止某些表达式本来也会在语义上非法的表达式。从而许多编译器忽略此规则并在语义上检测其非法。例如， e = a < d ? a++ : a = d 是因此规则而无法剖析的表达式。然而许多编译器忽略此规则并将它剖析成 e = ( ((a < d) ? (a++) : a) = d ) ，并给出错误，因为它在语义上非法。

分析表达式时，列于上面表中某行的运算符，将比列于低于它的行中拥有较低优先级的任何运算符，更紧密地绑定到其参数（如同用括号）。例如，表达式 *p++ 被分析为 *(p++) ，而非 (*p)++ 。

拥有相同优先级的运算符以其结合性的方向绑定到其参数。例如表达式 a = b = c 被分析为 a = (b = c) 而非 (a = b) = c ，因为从右到左结合性。

注解

优先级和结合性与求值顺序独立。

标准自身不指定优先级。它们派生自文法。

C++ 中，条件运算符拥有与赋值运算符相同的优先级，而前缀 ++ 与 -- 及赋值运算符无关于其运算数的限制。

结合性规定对于一元运算符是冗余的，且只为完备而显示：一元前缀运算符始终从右到左结合（ sizeof ++*p 为 sizeof(++(*p)) ）而一元后缀运算符始终从左到右结合（ a[1][2]++ 为 ((a[1])[2])++ ）。注意结合性对成员访问运算符有意义，即使在它们与一元后缀运算符组合时： a.b++ 分析为 (a.b)++ 而非 a.(b++) 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • A.2.1 Expressions
  • C99 标准（ISO/IEC 9899:1999）：
  • A.2.1 Expressions
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • A.1.2.1 Expressions

参阅

运行时运算符参数的求值顺序。

常用运算符
赋值 自增
自减 		算术 逻辑 比较 成员
访问 		其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b

a[b]
*a
&a
a->b
a.b

a(...)
a, b
(type) a
? :
sizeof
_Alignof (C11 起)


指针声明

< c‎ | language

指针是一种对象类型，它引用函数或另一种类型的对象，可以添加限定符。指针亦可以不引用任何内容，这通过一个特定的空指针值指示。

语法

在指针声明的声明文法中， 类型说明符 序列指代所指向的类型（可以是函数或对象，可以是不完整类型），而声明符拥有形式：

* 属性说明符序列(可选) 限定符(可选) 声明符

其中 声明符 可以是命名所声明指针的标识符，包括另一个指针声明符（这指示一个指向指针的指针）：

float *p, **pp; // p 是指向 float 的指针
                // pp 是指向指向 float 指针的指针
int (*fp)(int); // fp 是指向类型 int(int) 为函数的指针

出现在 * 与标识符（或另一个嵌套声明符）间的 限定符 将被声明的限定赋予指针类型：

int n;
const int * pc = &n; // pc 是指向 const int 的非 const 指针
// *pc = 2; // 错误：不能通过不带转型的 pc 修改 n
pc = NULL; // OK ： pc 自身可修改

int * const cp = &n; // cp 是一个指向非 const 的 int 的 const 指针
*cp = 2; // OK ：通过 cp 修改 n
// cp = NULL; // 错误： cp 自身不能修改

int * const * pcp = &cp; // 指向指向非 const 的 int 的 const 指针的非 const 指针

属性说明符序列(C23) 为属性的可选列表，应用到被声明的指针。

解释

指针用于间接使用，这是种普遍存在的编程技巧；它们可以用于实现按引用传递语义、访问有动态存储期的对象、实现“可选”类型（使用空指针值）、结构体间的聚合关系、回调（使用指向函数指针）、泛型接口（使用指向 void 的指针）以及其他更多。

指向对象的指针

指向对象的指针可以通过应用于对象类型（可以不完整）表达式的取值运算符初始化：

int n;
int *np = &n; // 指向 int 的指针
int *const *npp = &np; // 指向指向非 const 的 int 的 const 指针的非 const 指针

int a[2];
int (*ap)[2] = &a; // 指向 int 数组的指针

struct S { int n; } s = {1}
int* sp = &s.n; // 指向作为 s 成员的 int 的指针

指针可以出现作间接运算符 （一元 * ）的运算数，它返回标识所指向对象的左值：

int n;
int* p = &n;     // 指针 p 指向 n
*p = 7;         // 存储 7 于 n
printf("%d\n", *p); // 左值到右值转换从 n 读取值

指向 struct 和 union 类型对象的指针亦可作为经由指针成员访问运算符 -> 的左运算数出现。

因为数组到指针隐式转换，指向数组首元素的指针可通过数组类型表达式初始化：

int a[2];
int *p = a; // 指向a[0]

int b[3][3];
int (*row)[3] = b; // 指向b[0]

确定的加减、复合赋值、自增减运算符定义于指向数组元素的指针。

比较运算符在一些情况下定义于指向对象的指针：二个表示相同地址的指针比较相等，二个空指针值比较相等，比较指向同一数组的元素的指针以二个元素的数组下标比较，及指向结构体成员的指针以这些成员声明顺序比较。

许多实现亦提供随意来源指针的严格全序，例如若它们实现在连续（“平直”）的虚拟地址空间上。

指向函数的指针

指向函数的指针可由函数地址初始化。因为函数到指针转换，取址运算符是可选的：

void f(int);
void (*pf1)(int) = &f;
void (*pf2)(int) = f; // 等于&f

不同于函数，指向函数的指针是对象，从而能存储在数组中、复制、赋值、作为参数传递给其他函数等等。

指向函数的指针可以用作函数调用运算符的左运算数；这会调用所指向的函数：

#include <stdio.h>
int f(int n)
{
    printf("%d\n", n);
    return n*n;
}
int main(void)
{
    int (*p)(int) = f;
    int x = p(7);
}

解引用函数指针产生所指向函数的函数指代器：

int f();
int (*p)() = f;    // 指针 p 指向 f
(*p)(); // 通过函数指代器调用函数 f
p();    // 直接通过指针调用 f

等于比较运算符定义于指向函数的指针（若指向相同函数则它们比较相等）。

因为函数类型的兼容性忽略函数参数的顶层限定符，指向仅在参数的顶层限定符有区别的函数指针是可互换的：

int f(int), fc(const int);
int (*pc)(const int) = f; // OK
int (*p)(int) = fc;       // OK
pc = p;                   // OK

指向 void 指针

指向任意类型对象的指针能隐式转换成指向 void 的指针（可选地有 const 或 volatile 限定），反之亦然：

int n=1, *p=&n;
void* pv = p; // int* 到 void*
int* p2 = pv; // void* 到 int*
printf("%d\n", *p2); // 打印 1

指向 void 的指针用于传递未知类型的对象，这在泛型接口中常用： malloc 返回 void* ，qsort 期待用户提供接受二个 const void* 参数的回调。 pthread_create 期待用户提供接受并返回 void* 的回调。所有情况下，调用方负责在使用前将指针转换到正确的类型。

空指针

每种类型的指针都有含有一个该类型的特殊的值，称为空指针值。值为空的指针不指向对象或函数（解引用空指针是未定义行为），而且与所有相同类型的且值以为空的指针比较相等。

为初始化指针为空，或将空值赋给已存在的指针，可以使用空指针常量（ NULL ，或其他任何拥有值零的整数常量）。静态初始化亦将指针初始化到它们的空值。

空指针可以指示对象不存在，或可用于指示错误条件的其他对象。通常，接收指针参数的函数几乎总是需要检查该值是否为空，并对该情况特殊处理（例如， free 在传递空指针时不做任何事）。

注解

尽管任何指向对象的指针能被转型成指向其他类型对象的指针，解引用指向类型异于对象声明类型的指针几乎总是未定义行为。细节见严格别名使用。

可以指示函数，通过不会有别名使用的指针访问对象。细节见 restrict 。

 (C99 起)

数组类型的左值表达式，在大多数语境中使用时，会经历隐式转换到指向数组首元素的指针。细节见数组到指针转换。

char *str = "abc"; // "abc" 是 char[4] 类型的数组， str 是指向 'a' 的指针

指向 char 的指针通常用于表示字符串。为表示合法的字节字符串，指针必须指向作为 char 数组元素的 char ，而且在大于或等于指针所引用元素的下标的某个下标处，必须有零值的 char 。

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.7.6.1 Pointer declarators (p: 93-94)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.6.1 Pointer declarators (p: 130)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.5.1 Pointer declarators (p: 115-116)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.5.4.1 Pointer declarators

参阅


标点

< c‎ | language
本节未完成
原因：修正链接

{ }

  • 在 struct 或 union 定义中划分出结构体声明列表。
  • 在 enum 定义中划分出枚举列表。
  • 划分出复合语句。复合语句可以是函数定义的一部分。
  • 初始化时，划分出初始化器列表。

[ ]

  • 下标运算符。
  • 声明或类型标识中，数组声明符的一部分。
  • 初始化时，指派数组元素。(C99 起)
  • 属性说明符中，划分出属性。 (C23 起)

#

  • 预处理指令起始标志。
  • 字符串化的预处理操作。

##

  • 记号粘贴的预处理操作。

( )

  • 表达式分组，改变结合顺序。
  • 函数调用运算符。
  • sizeof 或 _Alignof (C11 起)表达式中划分出运算对象。
  • 显式类型转换中划分出类型标识。
  • 复合字面量中划分出标识。(C99 起)
  • 声明或类型标识中分组，改变结合顺序。
  • 函数声明（声明或类型标识）中划分出参数列表。
  • if、switch、while、do-while 或 for 语句中，划分出控制块。
  • 仿函数宏定义中，划分出宏参数。
  • defined 或 __has_c_attribute (C23 起)预处理运算符的一部分。
  • 泛型选择表达式的一部分。 (C11 起)
  • _Atomic类型说明符中,划分出类型标识。(C11 起)
  • 静态断言声明中，划分出操作对象。(C11 起)
  • _Alignas说明符中，划分出操作对象。(C11 起)
  • 属性中, 划分出操作对象。(C23 起)

;

  • 如下语法的结束：
  • 语句 (含 for 循环的初始化子句)
  • 声明或 结构体声明列表
  • 分隔 for 循环中的第二和第三子句。

:

  • 条件运算符的一部分。
  • 标签声明的一部分。
  • 标志位域成员声明的 宽度 的起始。
  • 泛型关联中，分隔类型标识或 default 和待选表达式。(C11 起)

...

  • 函数声明的参数列表中, 标志变长参数。
  • 宏定义中, 标志变参数宏。 (C99 起)

?

  • 条件运算符的一部分。

::

  • 在属性中指示属性作用域。(C23 起)

.

  • 成员访问运算符。
  • 在初始化时， 标志 struct/union 成员指派符的起始 (C99 起)

->

  • 成员访问运算符。

~

  • 一元补运算符（又称逐位非运算符）。

!

  • 逻辑非运算符。

+

  • 正号。
  • 加法运算符。

-

  • 负号。
  • 减法运算符。

*

  • 间接引用运算符（也称解引用运算符）。
  • 乘法运算符。
  • 声明符或类型标识中的指针运算符或成员指针运算符。
  • 在函数声明的变长数组声明中的数组长度占位符。 (C99 起)

/

  • 除法运算符。

%

  • 取余运算符（取模运算符）。

^

  • 逐位异或运算符。

&

  • 取地址运算符。
  • 逐位与运算符。

|

  • 逐位或运算符。

=

  • 简单赋值运算符。
  • 在初始化中，分隔对象和初始化列表。
  • 在枚举定义中引入枚举常量的值。

+=

  • 复合赋值运算符。

-=

  • 复合赋值运算符。

*=

  • 复合赋值运算符。

/=

  • 复合赋值运算符。

%=

  • 复合赋值运算符。

^=

  • 复合赋值运算符。

&=

  • 复合赋值运算符。

|=

  • 复合赋值运算符。

==

  • 等于运算符。

!=

  • 不等于运算符。

<

  • 小于运算符。
  • #include指令中标志头文件名起始。

>

  • 大于运算符。
  • #include指令中标志头文件名结束。

<=

  • 小于等于运算符。

>=

  • 大于等于运算符。

&&

  • 逻辑与运算符。

||

  • 逻辑或运算符。

<<

  • 移位运算符。

>>

  • 移位运算符。

<<=

  • 复合赋值运算符。

>>=

  • 复合赋值运算符。

++

  • 自增运算符。

--

  • 自减运算符。

,

  • 逗号运算符。
  • 以下列表的列表分隔符：
  • 声明中声明符列表
  • 初始化 ，包括复合字面量 (C99 起)中的初始化器列表
  • 函数调用中实参列表
  • 枚举声明中的枚举项列表
  • 仿函数宏定义中宏形参列表
  • 泛型选择表达式中泛型关联列表(C11 起)
  • 属性列表(C23 起)
  • 静态断言声明中分隔参数。 (C11 起)
  • 泛型选择表达式中，分隔控制表达式和泛型关联列表。 (C11 起)

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.4.6 Punctuators (p: 52-53)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.4.6 Punctuators (p: 72-73)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.4.6 Punctuators (p: 63-64)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.1.6 Punctuators

参阅

替用表示 (C95) 某些运算符的替用拼写


restrict 类型限定符

< c‎ | language

C 类型系统中每一个独立的类型在都有数个该类型的限定版本，对应 const 、 volatile 及对于指向对象指针的 restrict 限定符中的一个、两个或全部三个。此页面描述 restrict 限定符的效果。

仅有指向对象类型的指针及其（可能多维的）数组 (C23 起)能有 restrict 限定；具体而言，以下是错误的：

  • int restrict *p
  • float (* restrict f9)(void)

restrict 语义仅应用于左值表达式；例如到 restrict 限定指针的类型转换，或返回 restrict 限定指针的函数调用不是左值，从而该限定符无效果。

在每个声明声明了 restrict 指针 P 的块（典型例子是函数体的执行，其中 P 为参数）中，若某个对象可由 P 访问（直接或间接）的对象会被任何手段修改，则该块中所有对该对象（读或写）的访问，都必须经由 P 出现，否则行为未定义：

void f(int n, int * restrict p, int * restrict q)
{
    while(n-- > 0)
        *p++ = *q++; // 通过 *p 修改的对象与通过 *q 读取的无一相同
                     // 编译器可以自由地优化、向量化、做页面映射等等。
}
void g(void)
{
    extern int d[100];
    f(50, d + 50, d); // OK
    f(50, d + 1, d); // 未定义行为： d[1] 被 f 中的 p 和 q 一同访问
}

若对象决不被修改，则它可以被别名引用，并被异于 restrict 限定的指针访问（注意若对象为别名引用的 restrict 限定指针所指，则别名引用可能抑制优化）。

将一个 restrict 指针赋值给另一个是未定义行为，除非将指向外部块的指针赋值给内部块中的指针（包括在调用含 restrict 指针参数的函数时，以 restrict 指针为参数），或从函数返回指针（还有在前一个指针的块已经结束时）：

int* restrict p1 = &a;
int* restrict p2 = &b;
p1 = p2; // 未定义行为

restrict 指针可以自由地赋值给非 restrict 指针，只要编译器还能优化代码，优化机会还是保留就位的：

void f(int n, float * restrict r, float * restrict s) {
   float * p = r, * q = s; // OK
   while(n-- > 0) *p++ = *q++; // 几乎肯定优化成仅如 *r++ = *s++ 一般
}
若以 restrict 类型限定符声明数组类型（通过使用 typedef ），则数组类型无 restrict 限定，但其元素类型有 restrict 限定： | (C23 前)
始终认为数组类型与其元素类型同等地拥有 restrict 限定： | (C23 起)
typedef int *array_t[10];
restrict array_t a; // a 的类型是 int *restrict[10]
// 注： clang 和 icc 以 array_t 不是指针类型为由拒绝
void *unqual_ptr = &a; // C23 前 OK ； C23 起错误
// 注： clang 即使在 C89-C17 模式也应用 C++/C23 中的规则

在函数声明中，关键词 restrict 可以出现于方括号内，用以声明函数参数的数组类型。它对数组所转换得的指针类型赋予限定：

void f(int m, int n, float a[restrict m][n], float b[restrict m][n]);
void g12(int n, float (*p)[n]) {
   f(10, n, p, p+10); // OK
   f(20, n, p, p+10); // 可能是未定义行为（取决于 f 所为）
}

注解

restrict 限定符（像寄存器存储类）是有意使用以促进优化的。而从所有组成一致程序的预处理翻译单元中，删除所有此限定符的实例不会影响其含义（即可观的行为）。

编译器可以忽略任何一个或全部使用 restrict 的别名使用暗示。

欲避免未定义行为，程序员应该确保 restrict 限定指针所做的别名引用断言不会违规。

许多编译器提供作为 restrict 对立面的语言扩展：指示即使指针类型不同，也可以别名使用的属性： may_alias (gcc)

使用模式

restrict 限定指针有几种常用的使用模式：

文件作用域

文件作用域的 restrict 限定指针必须在程序运行期间指向单个数组的元素。该数组对象不可以通过 restrict 指针和通过其声明名称（若有的话）或另一个 restrict 指针两种方式一同引用。

文件作用域 restrict 指针对访问动态分配的全局数组有用； restrict 语义令通过此指针的引用，和通过静态数组的声明名称引用该数组效率相当：

float * restrict a, * restrict b;
float c[100];

int init(int n) {
   float * t = malloc(2*n*sizeof(float));
   a = t;      // a 引用前半
   b = t + n;  // b 引用后半
}
// 编译器可以从 restrict 限定符推断 a 、 b 和 c 都没有潜在的别名引用

函数参数

最广泛的 restrict 限定指针使用，是用作函数参数。

在下例中，编译器可能推断出被修改对象不会有别名引用，从而能更大胆地优化循环。在 f 的入口处，必须提供 restrict 指针对关联数组的独占访问。特别是，在 f 内 b 或 c 都不可以指入 a 所关联的数组，因为它们都不是以基于 a 的指针值赋值的。对于 b ，因为其声明的 const 限定符这是显然的，但对于 c ，需要检查 f 的函数体：

float x[100];
float *c;
void f(int n, float * restrict a, float * const b) {
    int i;
    for ( i=0; i<n; i++ )
       a[i] = b[i] + c[i];
}
void g3(void) {
    float d[100], e[100];
    c = x; f(100,   d,    e); // OK
           f( 50,   d, d+50); // OK
           f( 99, d+1,    d); // 未定义行为
    c = d; f( 99, d+1,    e); // 未定义行为
           f( 99,   e,  d+1); // OK
}

注意将 c 指向 b 所关联的数组是允许的。还要注意，对于这些目的，关联到通常指针的“数组”，仅表示数组对象的那一部分实际上是由该指针引用的。

注意在上例中，编译器能推断 a 和 b 不会别名使用，因为 b 的常性确保这点不会变得依赖函数体。程序员能等价地写 void f(int n, float * a, float const * restrict b) ，该情况下编译器理解无法修改通过 b 引用的对象，而以 b 和 a 一同引用的对象也不会被修改。假如程序员要写 void f(int n, float * restrict a, float * b) ，则编译器不检验函数体就无法推断出 a 和 b 不会别名使用。

通常情况下，最好在函数原型中用 restrict 显式标注所有不会别名使用的指针。

块作用域

一个块作用域的 restrict 限定指针会做一个限于其块内的别名引用断言。它允许局部断言仅应用到重要的块，譬如紧凑循环。它亦使得将使用 restrict 限定指针的函数转换成宏成为可能：

float x[100];
float *c;
#define f3(N, A, B)                                    \
{   int n = (N);                                       \
    float * restrict a = (A);                          \
    float * const    b = (B);                          \
    int i;                                             \
    for ( i=0; i<n; i++ )                              \
        a[i] = b[i] + c[i];                            \
}

结构体成员

作为结构体成员的 restrict 限定指针，所做的别名引用断言作用域，是用于访问该结构体的标识符的作用域。

即使结构体声明于文件作用域，当用以访问此结构体的标识符拥有块作用域时，结构体中的别名引用断言亦拥有块作用域；别名引用断言仅在块执行或函数调用中生效，具体取决于此结构体类型的对象是如何创造的：

struct t {    // restrict 指针断言
   int n;     // 成员指向无交集的存储区。
   float * restrict p;
   float * restrict q;
};

void ff(struct t r, struct t s) {
   struct t u;
   // r 、 s 、 u 拥有块作用域
   // r.p 、 r.q 、 s.p 、 s.q 、 u.p 、 u.q 应该在
   // 每次执行 ff 时全部指向无交集的存储区。
   // ...
}

关键词

restrict

示例

代码生成样例；以 -S （ gcc 、 clang 等）或 /FA （ Visual Studio ）参数编译

int foo(int *a, int *b)
{
    *a = 5;
    *b = 6;
    return *a + *b;
}

int rfoo(int *restrict a, int *restrict b)
{
    *a = 5;
    *b = 6;
    return *a + *b;
}

可能的输出：

# 生成64位Intel平台的代码：
foo:
    movl    $5, (%rdi)    # 存储 5 于 *a
    movl    $6, (%rsi)    # 存储 6 于 *b
    movl    (%rdi), %eax  # 从 *a 读回值，考虑到前面的存储会修改它
    addl    $6, %eax      # 将从 *a 读得的值加 6
    ret

rfoo:
    movl      $11, %eax   # 结果是 11，编译时常量
    movl      $5, (%rdi)  # 存储 5 于 *a
    movl      $6, (%rsi)  # 存储 6 于 *b
    ret

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.7.3.1 Formal definition of restrict (p: 89-90)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.3.1 Formal definition of restrict (p: 123-125)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.3.1 Formal definition of restrict (p: 110-112)


return 语句

< c‎ | language

终止当前函数并返回指定值给调用方函数。

语法

属性说明符序列(可选) return 表达式 ; | (1)
属性说明符序列(可选) return ; | (2)
表达式 | - | 用于初始化函数返回值的表达式
属性说明符序列 | - | (C23)可选的属性列表，应用到 return 语句

解释

1) 求值 表达式 ，终止当前函数，并返回 表达式 的结果给调用方（返回值成为函数调用表达式的值）。仅对函数返回类型非 void 的情形合法。
2) 终止当前函数。仅对函数返回类型为 void 的情形合法。

若 表达式 的类型异于函数的返回类型，则如同赋值一般转换其值为对象，对象类型为函数的返回类型，除了容许对象表示间的重叠：

struct s { double i; } f(void); // 函数返回 struct s
union { struct { int f1; struct s f2; } u1;
        struct { struct s f3; int f4; } u2; } g;
struct s f(void)
{
    return g.u1.f2;
}
int main(void)
{
// g.u2.f3 = g.u1.f2; // 未定义行为（赋值中重叠）
   g.u2.f3 = f();     // 良好定义
}

若返回类型是实浮点类型，则结果可能拥有比新类型所隐含者更大的范围和精度的表示。

抵达返回 void 的函数的末尾等价于 return;。若函数结果用于表达式，则抵达任何其他返回值的函数的结尾为未定义行为（允许舍弃这种返回值）。对于 main，见 main 函数。

在不返回函数中执行 return 语句是未定义行为。

 (C11 起)

关键词

return

示例

本节未完成
原因：改进
#include <stdio.h>

void fa(int i)
{
    if (i == 2)
       return;
    printf("fa():   %d\n", i);
} // 隐含return;

int fb(int i)
{
    if (i > 4)
       return 4;
    printf("fb():   %d\n", i);
    return 2;
}

int main(void)
{
    fa(2);
    fa(1);
    int i = fb(5);   // 返回值 4 用于初始化 i
    i = fb(i);       // 返回值 2 用作赋值的右运算数
    printf("main(): %d\n", i);
}

输出：

fa():   1
fb():   4
main(): 2

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.8.6.4 The return statement (p: 111-112)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.8.6.4 The return statement (p: 154)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.8.6.4 The return statement (p: 139)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.6.6.4 The return statement

参阅


标量初始化

< c‎ | language

在初始化 标量类型对象时，初始化器必须是单个表达式。

标量（包含布尔和枚举类型的整数类型，包含复数和虚数的浮点类型，以及包含指向函数指针的指针类型对象）的初始化器必须是单个表达式，可选地以花括号环绕：

= 表达式 | (1)
= { 表达式 } | (2)

求值该表达式，而其值在如同赋值般转换到对象类型后，成为被初始化对象的初值。

注解

因为应用到转换到规则如同赋值，在确定 表达式 所转换到的类型时，忽略被声明类型上的 const 与 volatile 限定符。

不使用初始化器时应用的规则见初始化。

同所有其他初始化，在初始化静态或线程局域存储期的对象时， 表达式 必须为常量表达式。

表达式 不能为逗号运算符（除非加括号），因为顶层的逗号会被转译为下个声明器的开始。

在初始化浮点类型对象时，对所有拥有自动存储期的对象所作的计算如同在执行时进行，并受当前舍入影响；报告 math_errhandling 中指定的浮点错误。对于拥有静态和线程局域存储期的对象，计算如同在编译时进行，而且不引发异常：

void f(void)
{
#pragma STDC FENV_ACCESS ON
    static float v = 1.1e75; // 不引发异常：静态初始化

    float u[] = { 1.1e75 }; // 引发 FE_INEXACT
    float w = 1.1e75;       // 引发 FE_INEXACT

    double x = 1.1e75; // 可能引发 FE_INEXACT （取决于 FLT_EVAL_METHOD ）
    float y = 1.1e75f; // 可能引发 FE_INEXACT （取决于 FLT_EVAL_METHOD ）

    long double z = 1.1e75; // 不引发异常（转换是准确的）
}

示例

#include <stdbool.h>

int main(void)
{
    _Bool b = true;
    const double d = 3.14;
    int k = 3.15; // 从 double 转换到 int
    int n = {12}, // 可选地花括号
       *p = &n,   // 对自动对象，非常量表达式 OK
       (*fp)(void) = main;
    enum {RED, BLUE} e = RED; // 枚举亦是标量类型
}

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.9/11 Initialization (p: 140)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.8/11 Initialization (p: 126)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 6.5.7 Initialization


作用域

< c‎ | language

C 程序中出现的每个标识符都仅在一些可能不连续的部分可见（即可使用），这些部分被称为其作用域。

在作用域内，标识符仅若在不同命名空间中，才可以指代多于一个实体。

C 拥有四种作用域：

  • 块作用域
  • 文件作用域
  • 函数作用域
  • 函数原型作用域

嵌套作用域

若相同标识符所命名的二个不同实体在同一时刻都在作用域中，且它们属于同一命名空间，则作用域被嵌套（不允许其他形式的作用域重叠），而内层作用域中的声明隐藏外层作用域中的声明：

// 此处的命名空间为通常标识符。

int a;   // 名称 a 的文件作用域始于此

void f(void)
{
    int a = 1; // 名称 a 的块作用域始于此；隐藏文件作用域的 a
    {
      int a = 2;         // 内层 a 的作用域始于此，隐藏外层 a
      printf("%d\n", a); // 内层 a 在作用域中，打印 2
    }                    // 内层 a 的块作用域终于此
    printf("%d\n", a);   // 外层 a 在作用域中，打印 1
}                        // 外层 a 的作用域终于此

void g(int a);   // 名称 a 拥有函数原型作用域；隐藏文件作用域的 a

块作用域

任何在复合语句，包含函数体或出现于 if 、 switch 、 for 、 while 或 do-while 语句中的任何表达式、声明或语句 (C99 起)，或在函数定义内的参数列表中声明的标识符的作用域，在声明点开始，在声明于其中的块或语句的结尾结束。

void f(int n)  // 函数参数 'n' 的作用域开始
{         // 函数体开始
   ++n;   // 'n' 在作用域中并指代函数参数
// int n = 2; // 错误：不能在同一作用域重声明标识符
   for(int n = 0; n<10; ++n) { // 循环局域的 'n' 的作用域开始
       printf("%d\n", n); // 打印 0 1 2 3 4 5 6 7 8 9
   } // 循环局域的 'n' 的作用域结束
     // 函数参数 'n' 回到作用域
   printf("%d\n", n); // 打印参数的值
} // 函数参数 'n' 的作用域结束
int a = n; // 错误：名称 'n' 不在作用域中

C99 前，选择和迭代语句不建立其自身的块作用域（尽管若在语句中使用复合语句，则它拥有其通常的块作用域）：

enum {a, b};
int different(void)
{
    if (sizeof(enum {b, a}) != sizeof(int))
        return a; // a == 1
    return b; // C89 中 b == 0 ， C99 中 b == 1
}
 (C99 起)

块作用域对象默认无链接并拥有自动存储期。注意非 VLA 局部对象的存储期在进入块时开始，但在见到声明前，该标识符不在作用域中且不能访问。

文件作用域

在任何块或参数列表外声明的任何标识符的作用域，在声明点开始，翻译单元尾结束。

int i; // i 的作用域开始
static int g(int a) { return a; } // g 的作用域开始（注意 "a" 拥有块作用域）
int main(void)
{
    i = g(2); // i 和 g 在作用域中
}

文件作用域的标识符默认拥有外部链接和静态存储期。

函数作用域

声明于函数内部的标号（且只有标号），在该函数中的所有位置（所有嵌套块中，其自身声明前后）都在作用域内。注意：任何语句前的冒号字符前的标识符，若不用于其他用途，则隐式声明一个标号。

void f()
{
   {
       goto label; // label 在作用域中，尽管之后才声明
label:;
   }
   goto label; // 标号忽略块作用域
}

void g()
{
    goto label; // 错误： g() 中 label 不在作用域中
}

函数原型作用域

非函数定义的函数声明的参数列表中引入的名称的作用域，在函数声明器的结尾结束。

int f(int n,
      int a[n]); // n 在作用域中并指代第一参数

注意，若声明中有多个或嵌套声明器，则作用域在最近的外围函数声明器的结尾结束：

void f ( // 函数名 'f' 在文件作用域
 long double f,            // 标识符 'f' 现在在作用域中，隐藏文件作用域的 'f'
 char (**a)[10 * sizeof f] // 'f' 指代第一参数，它在作用域中
);

enum{ n = 3 };
int (*(*g)(int n))[n]; // 函数参数 'n' 的作用域在其函数声明器的结尾结束
                       // 数组声明器中，全局 n 在作用域
// （这声明指向返回 3 个 int 的数组的指针的函数的指针）

声明点

结构体、联合体及枚举标签的作用域，在声明该标签的类型指定符中的标签出现后立即开始。

struct Node {
   struct Node* next; // Node 在作用域中并指代此 struct
};

枚举常量的作用域，在枚举项列表中其定义枚举项的出现后立即开始。

enum { x = 12 };
{
    enum { x = x + 1, // 新 x 在逗号前不在作用域中，初始化 x 为 13
           y = x + 1  // 新枚举项 x 现在在作用域中，初始化 y 为 14
         };
}

任何其他标识符的作用域，正好在其声明器结束后和初始化器前开始，若存在初始化器：

int x = 2; // 第一个 'x' 的作用域开始
{
    int x[x]; // 新声明的 x 的作用域在声明器 （ x[x] ）后开始。
              // 在声明器内，外层 'x' 仍在作用域中。
              // 这声明 2 个 int 的 VLA 数组。
}

unsigned char y = 32; // 外层 'y' 的作用域开始
{
    unsigned char y = y;
            // 内层 'y' 的作用域在初始化器（ = y ）前开始
            // 这不会以值 32 初始化内层 'y' ，
            // 这以其自身的不确定值初始化内层 'y'
}

unsigned long factorial(unsigned long n)
// 声明器结束， 'factorial' 从此点开始在作用域中
{
   return n < 2 ? 1 : n * factorial(n - 1); // 递归调用
}

作为特殊情况，非标识符声明的类型名的作用域，被认为正好假如在类型名内未省略标识符，则标识符会出现的位置之后开始。

注意

C89 前，拥有外部链接的标识符在块中引入时，拥有文件作用域，因此不要求 C89 编译器诊断已离开作用域的 extern 标识符的使用（这种使用是未定义行为）。

C 中，循环体内的局部对象，能隐藏声明于 for 循环的初始化子句中的对象（其作用域为嵌套的），但 C++ 中不能如此。

不同于 C++ ， C 无结构体作用域：声明于 struct/union/enum 声明内的名称在结构体声明所在的相同作用域（除了数据成员在其成员命名空间中）：

struct foo {
    struct baz {};
    enum color {RED, BLUE};
};
struct baz b; // baz 在作用域中
enum color x = RED; // color 和 RED 在作用域中

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.2.1 Scopes of identifiers (p: 35-36)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.2.1 Scopes of identifiers (p: 29-30)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.1.2.1 Scopes of identifiers

参阅


sizeof 运算符

< c‎ | language

查询对象或类型的大小

在必须知道对象实际大小时使用

语法

sizeof( 类型 ) | (1)
sizeof 表达式 | (2)

两个版本都返回 size_t 类型值。

解释

1) 返回 类型 的对象表示的字节大小。
2) 返回 表达式 类型的对象表示的字节大小。不应用隐式转换到 表达式 。

注意

取决于计算机架构，字节可能由 8 或更多位构成，准确数作为 CHAR_BIT 所提供。

sizeof(char) 、 sizeof(signed char) 和 sizeof(unsigned char) 始终返回 1 。

sizeof 不能用于函数类型、不完整类型（含void）或位域左值。

应用 sizeof 到 结构体或联合体类型运算数时，结果是这种对象中的总字节数，包含内部和尾随填充。尾随填充使得若对象在数组中，则此数组中下个元素的对齐要求会得到满足，换言之， sizeof(T) 返回 T[] 数组中元素的大小。

若 类型 为 VLA 类型，而更改其表达式的值不影响 sizeof 的结果，则不指定是否求值该大小表达式。

 (C99 起)

除非 表达式 为 VLA ， (C99 起)不求值 表达式 且 sizeof 运算符能在整数常量表达式中使用。

若 表达式 的类型为非常量长度数组类型，则求值 表达式 ，并在运行时计算其所求值的数组大小。

 (C99 起)

任何数组 a ，包含 VLA (C99 起)的元素数可用表达式 sizeof a / sizeof a[0] 确定。注意若 a 拥有指针类型（例如在函数参数类型调整的数组到指针转换后），此表达式会简单地将指针类型中的字节数除以被指向类型中的字节数。

关键词

sizeof

示例

示例输出对应拥有 64 位指针和 32 位 int 的平台

#include <stdio.h>

int main(void)
{
    short x;
    // 类型参数：
    printf("sizeof(float)          = %zu\n", sizeof(float));
    printf("sizeof(void(*)(void))  = %zu\n", sizeof(void(*)(void)));
    printf("sizeof(char[10])       = %zu\n", sizeof(char[10]));
//  printf("sizeof(void(void))     = %zu\n", sizeof(void(void))); // 错误：函数类型
//  printf("sizeof(char[])         = %zu\n", sizeof(char[])); // 错误：不完整类型

    // 表达式参数：
    printf("sizeof 'a'             = %zu\n", sizeof 'a'); // 'a' 的类型为 int
//  printf("sizeof main            = %zu\n", sizeof main); // 错误：函数类型
    printf("sizeof &main           = %zu\n", sizeof &main);
    printf("sizeof \"hello\"         = %zu\n", sizeof "hello"); // 类型为 char[6]
    printf("sizeof x               = %zu\n", sizeof x);   // x 的类型为 short
    printf("sizeof (x+1)           = %zu\n", sizeof(x+1)); // x+1 的类型为 int
}

可能的输出：

sizeof(float)          = 4
sizeof(void(*)(void))  = 8
sizeof(char[10])       = 10
sizeof 'a'             = 4
sizeof &main           = 8
sizeof "hello"         = 6
sizeof x               = 2
sizeof (x+1)           = 4

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.5.3.4 The sizeof and _Alignof operators (p: 90-91)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.5.3.4 The sizeof operator (p: 80-81)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.3.3.4 The sizeof operator

参阅


语句

< c‎ | language

语句是带顺序执行的 C 程序段。任何函数体都是一条复合语句，继而为语句或声明的序列：

int main(void)
{ // 复合语句的开始
    int n = 1; // 声明（非语句）
    n = n+1; // 表达式语句
    printf("n = %d\n", n); // 表达式语句
    return 0; // 返回语句
} // 复合语句之结尾，函数体之结尾

语句有五种类型：

1) 复合语句
2) 表达式语句
3) 选择语句
4) 循环语句
5) 跳转语句

属性说明符序列 (属性说明符序列) 能应用到无标号语句，该情况下（除了表达式语句）属性应用到相应的语句。

 (C23 起)

标号

任何语句都能有标号，通过在语句自身前提供一个跟随冒号的名称。

属性说明符序列(可选)(C23 起) 标识符 : | (1)
属性说明符序列(可选)(C23 起) case 常量表达式 : | (2)
属性说明符序列(可选)(C23 起) default : | (3)
1) goto 语句的目标。
2) switch 语句的 case 标号。
3) switch 语句的默认标号。

任何语句（但非声明）可以前附任意数量的标号，每个都声明一个 标识符 为标号名，标号名必须在闭合的函数中唯一（换言之，标号名拥有函数作用域）。

标号声明自身没有效果，不会以任何方式变更控制流，或修改跟随其后的语句的行为。

标号应当后随语句。 | (C23 前)
标号可以不带其后随语句出现。若标号单独出现在块中，则表现为如同它后随一条空语句。 可选的 属性说明符序列 应用到标号。 | (C23 起)

复合语句

复合语句，或称块，是花括号所包围的语句与声明的序列。

{ 语句 | 声明...(可选) } | (C23 前)
属性说明符序列(可选) { 无标号语句 | 标号 | 声明...(可选) } | (C23 起)

复合语句允许将一组声明和语句组合入一个单元，并将其任何在期待单个语句的场所使用（例如在 if 语句或循环语句中）：

if (expr) // if 语句的开始
{ // 开始块
  int n = 1; // 声明
  printf("%d\n", n); // 表达式语句
} // 块结尾， if 语句结尾

每个复合语句引入其自身的块作用域。

拥有静态存储期的变量的初始化器，及 VLA 声明符在每次控制流经过这些声明时按顺序执行，就像它们是语句一样：

int main(void)
{ // 块的开始
  { // 块的开始
       puts("hello"); // 表达式语句
       int n = printf("abc\n"); // 声明，打印 "abc\n" ，将 4 存入 n
       int a[n*printf("1\n")]; // 声明，打印 "1\n" ，分配 8*sizeof(int)
       printf("%zu\n", sizeof(a)); // 表达式语句
  } // 块结束， n 与 a 的作用域结束
  int n = 7; // n 可以重新使用
}

表达式语句

跟随分号的表达式是一条语句。

表达式(可选) ; | (1) |
属性说明符序列 表达式 ; | (2) | (C23 起)

典型的 C 程序中大多数语句是表达式语句，例如赋值或函数调用。

无表达式的表达式语句被称作空语句。它通常用于提供空循环体给 for 或 while 循环。它亦能用于在复合语句尾部或声明之前携带一个标号：

puts("hello"); // 表达式语句
char *s;
while (*s++ != '\0')
    ; // 空语句

可选的 属性声明符序列 应用到表达式。

后随 ; 的 属性说明符序列 不构成表达式。它替而构成属性声明。

 (C23 起)

选择语句

选择语句根据表达式的值，选择数条语句之一执行。

if ( 表达式 ) 语句 | (1)
if ( 表达式 ) 语句 else 语句 | (2)
switch ( 表达式 ) 语句 | (3)
1) if 语句
2) if 语句带 else 子句
3) switch 语句

循环语句

循环语句重复执行一条语句。

while ( 表达式 ) 语句 | (1)
do 语句 while ( 表达式 ) ; | (2)
for ( 初始化子句 ; 表达式(可选) ; 表达式(可选) ) 语句 | (3)
1) while 循环
2) do-while 循环
3) for 循环

跳转语句

跳转语句无条件地转移控制流。

break ; | (1)
continue ; | (2)
return 表达式(可选) ; | (3)
goto 标识符 ; | (4)
1) break 语句
2) continue 语句
3) return 语句带可选的表达式
4) goto 语句

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.8 Statements and blocks (p: 106-112)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.8 Statements and blocks (p: 146-154)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.8 Statements and blocks (p: 131-139)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.6 STATEMENTS

参阅


字符串字面量

< c‎ | language

原位构造指定字符数组类型的无名对象，在需要内嵌字符串到源代码中时使用。

语法

" 串字符序列 " | (1) |
u8" 串字符序列 " | (2) | (C11 起)
u" 串字符序列 " | (3) | (C11 起)
U" 串字符序列 " | (4) | (C11 起)
L" 串字符序列 " | (5) |

其中

串字符序列 - 零或多个字符，每个或为来自源字符集的多字节字符（不含 " 、 \ 及换行符），或为转义序列中定义的字符转义、十六进制转义、八进制转义或通用字符名 (C99 起)。

1) 字符串字面量：字面量的类型为 char[N] ，其中 N 是以执行窄编码的编码单元数计的字符串的大小，包括空终止符。以执行字符集从 串字符序列 中的下个字符初始化数组的每个 char 元素。
2) UTF-8 字符串字面量：字面量的类型为 char[N] ，其中 N 是以 UTF-8 编码单元数计的字符串大小，包括空终止符。以 UTF-8 编码从 串字符序列 中的下个多字节字符初始化数组中的每个 char 元素。
3) 16 位宽字符串字面量：字面量的类型为 char16_t[N] ，其中 N 是以实现定义的 16 位编码（通常为 UTF-16 ）的编码单元数计的字符串大小，包括空终止符。如同通过在实现定义的本地环境中执行 mbrtoc16 初始化数组的每个 char16_t 元素。
4) 32 位宽字符串字面量：字面量的类型为 char32_t[N] ，其中 N 是以实现定义的 32 位编码（通常为 UTF-32 ）的编码单元数计的字符串大小，包括空终止符。如同通过在实现定义的本地环境中执行 mbrtoc32 初始化数组的每个 char32_t 元素。
5) 宽字符串字面量：字面量的类型为 wchar_t[N] ，其中 N 是以执行宽编码的编码单元数计的字符串大小，包括空终止符。如同通过在实现定义的本地环境中执行 mbstowcs 初始化数组的每个 wchar_t 元素。

解释

首先，在翻译阶段 6 （宏展开后），连接相邻的字符串字面量（即仅为空白符所分隔的字符串字面量）。

仅可连接二个窄或二个宽字符串字面量。

 (C99 前)

若一个字面量无前缀，则结果字符串字面量拥有有前缀字面量所指定的宽度/编码。

L"Δx = %" PRId16 // 在阶段 4 ， PRId16 展开成 "d"
                 // 在阶段 6 ， L"Δx = %" 和 "d" 组成 L"Δx = %d"
 (C99 起)
若二个字符串字面量拥有不同的编码前缀，则连接是实现定义的，除了不能连接 UTF-8 字符串字面量和宽字符串字面量。 | (C11 起) (C23 前)
若二个字符串字面量拥有不同的编码前缀，则连接为非良构。 | (C23 起)

其次，在翻译阶段 7 ，添加空终止字符到每个字符串字面量，然后每个字符串字面量初始化一个拥有静态存储期，长度刚好能容纳字符串字面量的内容加一个空终止符的无名数组。

char* p = "\x12" "3"; // 创建 static char[3] 数组，保有 {'\x12', '3', '\0'}
                      // 设置 p 指向数组的首元素

字符串字面量不可修改（而且实际上可以放在例如 .rodata 的只读内存中）。若程序试图修改字符串字面量组成的静态数组，则行为未定义。

char* p = "Hello";
p[1] = 'M'; // 未定义行为
char a[] = "Hello";
a[1] = 'M'; // OK ： a 不是字符串字面量

既不要求亦不禁止等同的字符串字面量指代内存中的同一位置。而且，重叠的字符串字面量或作为其他字符串字面量子串的字符串字面量可以结合。

"def" == 3+"abcdef"; // 可为 1 或 0 ，实现定义

注解

字符串字面量不必是一条字符串；若字符串字面量拥有内嵌的空字符，则它表示含有多于一条字符串的数组：

char* p = "abc\0def"; // strlen(p) == 3 ，但数组大小为 8

若在字符串字面量中合法十六进制数位后随十六进制转义，则这会作为非法的转义序列导致编译失败，但能以字符串连接为变通方式：

//char* p = "\xfff"; // 错误：十六进制转义在范围外
char* p = "\xff""f"; // OK ：字面量为 char[3] ，保有 {'\xff', 'f', '\0'}

字符串字面量能用于初始化数组，而若数组大小比字符串字面量大小少一，则忽略空终止符：

char a1[] = "abc"; // a1 为 char[4] ，保有 {'a', 'b', 'c', '\0'}
char a2[4] = "abc"; // a2 为 char[4] ，保有 {'a', 'b', 'c', '\0'}
char a3[3] = "abc"; // a3 为 char[3] ，保有 {'a', 'b', 'c'}

字符串字面量 (1) 和宽字符串字面量 (5) 的编码是实现定义的。例如， gcc 用命令行选项 -fexec-charset 和 -fwide-exec-charset 选择它们。

尽管 C11 中允许混合的宽字符串字面量连接，几乎所有编译器都拒绝这种连接（仅有的已知例外是 SDCC ），而其使用经验是未知的。作为结果， C23 中移除了对混合宽字符串字面量连接的允许。

示例

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <uchar.h>
#include <locale.h>
int main(void)
{
    char s1[] = "a猫🍌"; // 或 "a\u732B\U0001F34C"
    char s2[] = u8"a猫🍌";
    char16_t s3[] = u"a猫🍌";
    char32_t s4[] = U"a猫🍌";
    wchar_t s5[] = L"a猫🍌";

    setlocale(LC_ALL, "en_US.utf8");
    printf("  \"%s\" is a char[%zu] holding { ", s1, sizeof s1 / sizeof *s1);
    for(size_t n = 0; n < sizeof s1 / sizeof *s1; ++n)
        printf("%#x ", +(unsigned char)s1[n]);
    puts(" }");
    printf("u8\"%s\" is a char[%zu] holding { ", s2, sizeof s2 / sizeof *s2);
    for(size_t n = 0; n < sizeof s2 / sizeof *s2; ++n)
       printf("%#x ", +(unsigned char)s2[n]);
    puts(" }");
    printf(" u\"a猫🍌\" is a char16_t[%zu] holding { ", sizeof s3 / sizeof *s3);
    for(size_t n = 0; n < sizeof s3 / sizeof *s3; ++n)
       printf("%#x ", s3[n]);
    puts(" }");
    printf(" U\"a猫🍌\" is a char32_t[%zu] holding { ", sizeof s4 / sizeof *s4);
    for(size_t n = 0; n < sizeof s4 / sizeof *s4; ++n)
       printf("%#x ", s4[n]);
    puts(" }");
    printf(" L\"%ls\" is a wchar_t[%zu] holding { ", s5, sizeof s5 / sizeof *s5);
    for(size_t n = 0; n < sizeof s5 / sizeof *s5; ++n)
       printf("%#x ", (unsigned)s5[n]);
    puts(" }");
}

可能的输出：

"a猫🍌" is a char[9] holding { 0x61 0xe7 0x8c 0xab 0xf0 0x9f 0x8d 0x8c 0  }
u8"a猫🍌" is a char[9] holding { 0x61 0xe7 0x8c 0xab 0xf0 0x9f 0x8d 0x8c 0  }
 u"a猫🍌" is a char16_t[5] holding { 0x61 0x732b 0xd83c 0xdf4c 0  }
 U"a猫🍌" is a char32_t[4] holding { 0x61 0x732b 0x1f34c 0  }
 L"a猫🍌" is a wchar_t[4] holding { 0x61 0x732b 0x1f34c 0  }

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.4.5 String literals (p: 50-52)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.4.5 String literals (p: 70-72)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.4.5 String literals (p: 62-63)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.1.4 String literals

参阅


结构体声明

< c‎ | language

结构体是一种由一序列的成员组成的类型，成员的存储以顺序分配于内存中（与联合体相反，联合体是由一个序列的成员组成的类型，成员存储在内存中重叠）。

结构体的类型说明符与联合体（ union ）类型说明符相同，只是所用的关键词有别。

语法

struct 属性说明符序列(可选) 名字(可选) { 结构体声明列表 } | (1)
struct 属性说明符序列(可选) 名字 | (2)
1) 结构体定义：引入一个新类型 struct 名字 并定义其含义
2) 若仅在其自身的行使用，如在 struct 名字 ; 中，声明但不定义 struct name （见下方前置声明）。在其他语境中，命名先前声明的结构体，并且不允许 属性说明符序列 。
名字 | - | 正在定义的结构体名称
结构体声明列表 | - | 任意数量的变量声明、位域声明和静态断言声明。不允许不完整类型的成员和函数类型的成员（除了下面描述的柔性数组成员）
属性说明符序列 | - | (C23) 属性的可选列表，应用到结构体类型

解释

在结构体对象内，其成员的地址（及位域分配单元的地址）按照成员定义的顺序递增。能转型指向结构体的指针为指向其首成员（或者若首成员为位域，则指向其分配单元）的指针。类似地，能转型指向结构体首成员的指针为指向整个结构体的指针。在任意二个成员间和最后的成员后可能存在无名的填充字节，但首成员前不会有。结构体的大小至少与其成员的大小之和一样大。

若结构体定义了至少一个具名成员，则额外声明其最后成员拥有不完整的数组类型。访问柔性数组成员的元素时（在以柔性数组成员名为 . 或 -> 的右侧运算数的表达式中），结构体表现得如同该数组成员拥有为此对象分配的内存中最长的适合大小。若未分配额外存储，则它表现为如同有 1 个元素的数组，除了若访问该元素，或产生指向该元素后一位置指针，则行为未定义。初始化、 sizeof 及赋值运算符忽略柔性数组成员。拥有柔性数组成员的结构体（或拥有可能递归的有柔性数组成员的结构体成员的联合体）不能作为数组元素，或其他结构体的成员出现。

struct s { int n; double d[]; }; // s.d 是柔性数组元素

    struct s t1 = { 0 };         // OK ： d 如同为 double d[1] ，但访问是 UB
    struct s t2 = { 1, { 4.2 } }; // 错误：初始化忽略柔性数组

    // 若 sizeof (double) == 8
    struct s *s1 = malloc(sizeof (struct s) + 64); // 如同 d 为 double d[8]
    struct s *s2 = malloc(sizeof (struct s) + 46); // 如同 d 为 double d[5]

    s1 = malloc(sizeof (struct s) + 10); // 现在如同 d 为 double d[1]
    s2 = malloc(sizeof (struct s) + 6);  // 同上，但访问是 UB
    double *dp = &(s1->d[0]);    //  OK
    *dp = 42;                    //  OK
    dp = &(s2->d[0]);            //  OK
    *dp = 42;                    //  未定义行为

    *s1 = *s2; // 只复制 s.n ，没有任何 s.d 的元素
               // 除了 sizeof (struct s) 中捕获的元素
 (C99 起)

类似联合体，类型为不带 名字 的结构体的无名结构体成员被称作匿名结构体。每个匿名结构体的成员被认为是外围结构体或联合体的成员。若外围结构体或联合体亦为匿名，则递归应用此规则。

struct v {
   union { // 匿名联合体
      struct { int i, j; }; // 匿名结构体
      struct { long k, l; } w;
   };
   int m;
} v1;

v1.i = 2;   // 合法
v1.k = 3;   // 非法：内层结构体非匿名
v1.w.k = 5; // 合法

类似联合体，若不以任何具名成员定义结构体（包含经由匿名嵌套结构体或联合体获得的成员），则程序行为未定义。

 (C11 起)

前置声明

下列形式的声明

struct 属性说明符序列(可选) 名字 ;

隐藏任何先前在标签命名空间中声明的 名字 的含义，并在当前作用域中声明 名字 为新的结构体名，可以在之后定义该结构体。在定义出现之前，此结构体名拥有不完整类型。

这允许结构体彼此引用：

struct y;
struct x { struct y *p; /* ... */ };
struct y { struct x *q; /* ... */ };

注意，亦可只用在另一声明中使用 struct 标签引入新的结构体名，但若先前声明的拥有同名的结构体存在于标签命名空间中，则标签会指代该名称

struct s* p = NULL; // 标签命名一个位置结构体，声明它
struct s { int a; }; // p 所指向的结构体的定义
void g(void)
{
    struct s; // 新的局部 struct s 的前置声明
              // 它隐藏全局 struct s 直至此块结束
    struct s *p;  // 指向局部 struct s 的指针
                  // 若无上面的前置声明，则它会指向文件作用域的 s
    struct s { char* p; }; // 局部 struct s 的定义
}

关键词

struct

注解

涉及结构体初始化器的规则，见结构体初始化。

因为不允许不完整类型的成员，而且结构体类型在其定义结束前不完整，故结构体不能拥有有其自身类型的成员。允许指向其自身类型的指针成员是允许的，而这通常用于实现链表或树的节点。

因为结构体声明不建立作用域，故在 结构体声明列表 中引入的嵌套类型、枚举及枚举项会在定义结构体的外围作用域可见。

示例

#include <stddef.h>
#include <stdio.h>

int main(void)
{
    struct car { char *make; char *model; int year; }; // 声明结构体类型
    // 声明并初始化之前声明的结构体类型的对象
    struct car c = {.year=1923, .make="Nash", .model="48 Sports Touring Car"};
    printf("car: %d %s %s\n", c.year, c.make, c.model);

    // 声明结构体类型、该类型的对象和指向它的指针
    struct spaceship { char *make; char *model; char *year; }
        ship = {"Incom Corporation", "T-65 X-wing starfighter", "128 ABY"},
        *pship = &ship;
    printf("spaceship: %s %s %s\n", ship.year, ship.make, ship.model);

    // 地址以声明顺序递增
    // 可能插入填充字节
    struct A { char a; double b; char c;};
    printf("offset of char a = %zu\noffset of double b = %zu\noffset of char c = %zu\n"
           "sizeof(struct A) = %zu\n", offsetof(struct A, a), offsetof(struct A, b),
           offsetof(struct A, c), sizeof(struct A));
    struct B { char a; char b; double c;};
    printf("offset of char a = %zu\noffset of char b = %zu\noffset of double c = %zu\n"
           "sizeof(struct B) = %zu\n", offsetof(struct B, a), offsetof(struct B, b),
           offsetof(struct B, c), sizeof(struct B));

    // 能转型指向结构体的指针为指向其首成员的指针，反之亦然
    char* pmake = (char*)pship;
    pship = (struct spaceship *)pmake;
}

可能的输出：

car: 1923 Nash 48 Sports Touring Car
spaceship: 128 ABY Incom Corporation T-65 X-wing starfighter
offset of char a = 0
offset of double b = 8
offset of char c = 16
sizeof(struct A) = 24
offset of char a = 0
offset of char b = 1
offset of double c = 8
sizeof(struct B) = 16

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.7.2.1 Structure and union specifiers (p: 81-84)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.2.1 Structure and union specifiers (p: 112-117)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.2.1 Structure and union specifiers (p: 101-104)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.5.2.1 Structure and union specifiers

参阅

  • 结构体及联合体成员访问
  • 位域
  • 结构体初始化


结构体与联合体初始化

< c‎ | language

初始化 struct 或 union 类型对象时，初始化器必须是成员初始化器的非空、花括号环绕、逗号分隔的列表：

= { 表达式 , ... } | (1) |
= { 指派符 表达式 , ... } | (2) | (C99 起)

其中 指派符 是一序列（空白符分隔或相邻的） . 成员 形式的单独成员指派符，和 [ 下标 ] 形式的数组指派符。

隐式地初始化所有未显式初始化的成员均被零初始化。

解释

初始化 union 时，初始化器列表必须只有一个成员，它初始化联合体的首个成员，除非使用指派初始化器 (C99 起)。

union { int x; char c[4]; }
  u = {1},           // 令 u.x 活跃，拥有值 1
 u2 = { .c={'\1'} }; // 令 u2.c 活跃，拥有值 {'\1','\0','\0','\0'}

初始化 struct 时，列表中的首个初始化器初始化首个被声明成员（除非指定了指派符） (C99 起)，而所有后继的无指派符 (C99 起)初始化器，初始化先前表达式所初始化者之后的结构体成员。

struct point {double x,y,z;} p = {1.2, 1.3}; // p.x=1.2, p.y=1.3, p.z=0.0
div_t answer = {.quot = 2, .rem = -1 };      // div_t 中的成员顺序可以不同

指派符导致后随的初始化器初始化该指派符所描述的结构体成员。然后初始化继续按声明顺序向前，从指派符所描述成员的下个成员开始。

struct {int sec,min,hour,day,mon,year;} z
   = {.day=31,12,2014,.sec=30,15,17}; // 初始化 z 为 {30,15,17,31,12,2014}
 (C99 起)

提供多于成员的初始化器是错误。

嵌套初始化

若结构体或联合体的成员是数组、结构体或联合体，则初始化器的花括号环绕列表中的对应初始化器，是对这些成员合法的任何初始化器，除了可以以下列方式省略其括号：

若嵌套初始化器以左花括号开始，则直到其右花括号为止的整个嵌套初始化器，初始化对应的成员对象。每个左开花括号建立一个新的当前对象。当前对象的成员以其自然顺序初始化，除非使用指派符 (C99 起)：数组以下标顺序、结构体成员以声明顺序、仅初始化任何联合体的首个被声明成员。零初始化当前对象内未由闭花括号显式初始化的子对象。

struct example {
    struct addr_t {
       uint32_t port;
    } addr;
    union {
       uint8_t a8[4];
       uint16_t a16[2];
    } in_u;
};
struct example ex = { // struct example 的初始化器列表开始
                     { // ex.addr 的初始化器列表开始
                        80 // 初始化 struct addr_t 的唯一成员
                     }, // ex.addr 的初始化器列表结束
                     { // ex.in_u 的初始化器列表开始
                        {127,0,0,1} // 初始化 union in_u 的首个成员
                     } };

若嵌套初始化器不以左花括号开始，则仅从列表采用足够的初始化器，以用于该成员数组、结构体或联合体的元素或成员；任何剩下的初始化器留待初始化下个结构体成员：

struct example ex = {80, 127, 0, 0, 1}; // 80 初始化 ex.addr.port
                                        // 127 初始化 ex.in_u.a8[0]
                                        // 0 初始化 ex.in_u.a8[1]
                                        // 0 初始化 ex.in_u.a8[2]
                                        // 1 初始化 ex.in_u.a8[3]

嵌套指派符时，成员的指派符后随外围结构体/联合体/数组的指派符。在任何嵌套的方括号初始化器列表中，最外层指派符指代当前对象，而且只在当前对象中选择要初始化的子对象。

struct example ex2 = { // 当前对象为 ex2 ，指派符属于 struct example 的成员
                       .in_u.a8[0]=127, 0, 0, 1, .addr=80};
struct example ex3 = {80, .in_u={ // 更改当前对象为联合体 ex.in_u
                           127,
                           .a8[2]=1 // 此指派符指代 union in_u 的成员
                      } };

若显式初始化任何子对象二次（在使用指派符时可能发生），则使用的初始化器，是较后出现于列表中的初始化器（可能不求值较早的初始化器）：

struct {int n;} s = {printf("a\n"), // 可能打印或跳过它
                     .n=printf("b\n")}; // 始终打印

尽管任何未初始化的子对象都被隐式初始化，若子对象的显式初始化在初始化器列表中出现较早，则同一子对象的隐式初始化决不会覆盖显式初始化（选择 clang 以观察正确的输出）：

#include <stdio.h>
typedef struct { int k; int l; int a[2]; } T;
typedef struct { int i;  T t; } S;
T x = {.l = 43, .k = 42, .a[1] = 19, .a[0] = 18 };
 // 初始化 x 为 {42, 43, {18, 19} }
int main(void)
{
    S l = { 1,          // 初始化 l.i 为 1
           .t = x,      // 初始化 l.t 为 {42, 43, {18, 19} }
           .t.l = 41,   // 更改 l.t 为 {42, 41, {18, 19} }
           .t.a[1] = 17 // 更改 l.t 为 {42, 41, {18, 17} }
          };
    printf("l.t.k is %d\n", l.t.k); // .t = x 显式设置 l.t.k 为 42
                                    // .t.l = 41 会隐式清零 l.t.k
}

输出：

l.t.k is 42

然而，当初始化器以左开花括号开始时，会完全重初始化其当前对象，并忽略其任何子对象的先前的显式初始化器：

struct fred { char s[4]; int n; };
struct fred x[ ] = { { { "abc" }, 1 }, // 初始化 x[0] 为 { {'a','b','c','\0'}, 1 }
                      [0].s[0] = 'q'   // 更改 x[0] 为 { {'q','b','c','\0'}, 1 }
                   };
struct fred y[ ] = { { { "abc" }, 1 }, // 初始化 y[0] 为 { {'a','b','c','\0'}, 1 }
                     [0] = { // 当前对象现在是整个 y[0] 对象
                             .s[0] = 'q'
                            } // 以 { {'q','\0','\0','\0'}, 0 } 替换 y[0]
                    };
 (C99 起)

注解

初始化器列表可拥有尾随的逗号，它被忽略。

struct {double x,y;} p = {1.0,
                          2.0, // 尾随逗号 OK
                          };

C 中，初始化器的花括号列表不能为空（注意 C++ 允许空列表，并且注意 C 中结构体不能为空）：

struct {int n;} s = {0}; // OK
struct {int n;} s = {}; // 错误：初始化器列表不能为空
struct {} s = {}; // 错误：结构体不能为空，初始化器列表不能为空

在初始化任何存储期的聚合体时，初始化器列表中的每个表达式必须都是常量表达式。

 (C99 前)

同所有其他初始化，在初始化静态或线程局域 (C11 起) 存储期的聚合体时，初始化器列表中的每个表达式必须为常量表达式：

static struct {char* p} s = {malloc(1)}; // 错误

任何初始化器中的子表达式求值顺序为非确定顺序（但 C++11 起的 C++ 中不同）：

int n = 1;
struct {int x,y;} p = {n++, n++}; // 未指定，但是良定义的行为：
                                  // n 以任意顺序自增二次
                                  // p 等于 {1,2} 和 {2,1} 都是合法的
 (C99 起)

示例

本节未完成
原因：更多实用的示例，最好初始化某些接头结构体
#include <stdio.h>
#include <time.h>

int main(void)
{
    char buff[70];
    // 指派初始化器简化成员顺序未指定的结构体的使用
    struct tm my_time = { .tm_year=2012-1900, .tm_mon=9, .tm_mday=9,
                          .tm_hour=8, .tm_min=10, .tm_sec=20 };
    strftime(buff, sizeof buff, "%A %c", &my_time);
    puts(buff);
}

可能的输出：

Sunday Sun Oct  9 08:10:20 2012

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.9/12-38 Initialization (p: 140-144)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.8/12-38 Initialization (p: 126-130)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.5.7/9- Initialization

参阅


switch 语句

< c‎ | language

按照整数参数的值执行代码。

在需要按照整数值执行多个分支中的一个或数个之处使用。

语法

属性说明符序列(可选) switch ( 表达式 ) 语句
属性说明符序列 | - | (C23)可选的属性列表，应用到 switch 语句
表达式 | - | 任何整数类型（ char 、有符号或无符号整数，或枚举）表达式
语句 | - | 任何语句（典型为复合语句）。允许在 语句 中有 case: 和 default: 标号，而 break; 语句拥有特殊含义。
case 常量表达式 : 语句 | (1) | (C23 前)
属性说明符序列(可选) case 常量表达式 : 语句(可选) | (1) | (C23 起)
default : 语句 | (2) | (C23 前)
属性说明符序列(可选) default : 语句(可选) | (2) | (C23 起)
常量表达式 | - | 任何整数常量表达式
属性说明符序列 | - | (C23)可选的属性列表，应用到标号

解释

switch 语句体可拥有任意数量的 case: 标号，只要所有 表达式 均为独有（在转换到 表达式 的提升后类型后）。至多可以存在一个 default: 标号（尽管嵌套的 switch 语句可使用其自身的 default: 标号，或拥有常量等于外围 switch 所用的 case: 的标号）。

若 表达式 求值为等于一个 常量表达式 在转换到 表达式 的提升类型后的值，则转移控制到标号为该 常量表达式 的语句。

若 表达式 求值为不匹配任何 case: 标号的值，而存在 default: 标号，则转移控制到标号为 default: 的语句。

若 表达式 求值为不匹配任何 case: 标号的值，且不存在 default: 标号，则不执行 switch 体的任何部分。

在 语句 中的任何位置遇到 break 语句时，跳出语句体：

switch(1) {
    case 1 : puts("1"); // 打印“ 1 ”
    case 2 : puts("2"); // 然后打印“ 2 ”（“继续”）
}
switch(1) {
    case 1 : puts("1"); // 打印“ 1 ”
             break;     // 并退出 switch
    case 2 : puts("2");
             break;
}

同所有选择和迭代语句， switch 语句建立块作用域：任何 表达式 的标识符在 语句 后离开作用域。

若 case: 或 default: 标号在 VLA 或另一拥有可变修改类型的标识符的作用域内，则整个 switch 语句都必须在其作用域内（换言之， VLA 必须在整个 switch 前或最后的标号后声明）：

switch (expr)
{
    int i = 4; // 非 VLA ；声明于此 OK
    f(i); // 决不调用
//  int a[i]; // 错误： VLA 不能声明于此
  case 0:
    i = 17;
default:;
    int a[i]; // 在此声明 VLA OK
    printf("%d\n", i); // 若 expr == 0 则打印 17 ，否则打印不确定值
}
 (C99 起)

关键词

switch, case, default

示例

#include <stdio.h>

void func(int x)
{
   printf("func(%d): ", x);
   switch(x)
   {
      case 1: printf("case 1, ");
      case 2: printf("case 2, ");
      case 3: printf("case 3.\n"); break;
      case 4: printf("case 4, ");
      case 5: printf("case 5, ");
      default: printf("default.\n");
   }
}

int main(void)
{
   for(int i = 1; i < 9; ++i) func(i);
}

输出：

func(1): case 1, case 2, case 3.
func(2): case 2, case 3.
func(3): case 3.
func(4): case 4, case 5, default.
func(5): case 5, default.
func(6): default.
func(7): default.
func(8): default.

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.8.4.2 The switch statement (p: 108-109)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.8.4.2 The switch statement (p: 149-150)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.8.4.2 The switch statement (p: 134-135)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.6.4.2 The switch statement

参阅


类型

< c‎ | language

（内建类型上的更多细节参阅算术类型和 C 库所提供的类型相关的工具列表）

对象、函数和表达式拥有称为类型的属性，它确定存储于对象或表达式求值所得的二进制值的转译方式。

类型分类

C 类型系统由下列类型组成：

  • 类型 void
  • 基本类型
  • 类型 char
  • 有符号整数类型
  • 标准： signed char 、 short 、 int 、 long 、 long long (C99 起)
  • 扩展：实现定义，例如 __int128
 (C99 起)
  • 无符号整数类型
  • 标准： _Bool 、 (C99 起) unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 、unsigned long long (C99 起)
  • 扩展：实现定义，例如 __uint128
 (C99 起)
  • 浮点类型
  • 实浮点类型： float 、 double 、 long double
  • 十进制实浮点类型： _Decimal32 、 _Decimal64 、 _Decimal128
 (C23 起)
  • 复数类型： float _Complex 、 double _Complex 、 long double _Complex
  • 虚数类型： float _Imaginary 、 double _Imaginary 、 long double _Imaginary
 (C99 起)
  • 枚举类型
  • 派生类型
  • 数组类型
  • 结构体类型
  • 联合体类型
  • 函数类型
  • 指针类型
  • 原子类型
 (C11 起)

对于上面列出的每个类型，可以存在数种其类型的限定版本，对应 const 、 volatile 和 restrict 限定符的一、二或全部三个组合（在限定符的语义所允许处）。

类型组别

  • 对象类型：所有不是函数类型的类型
  • 字符类型： char 、 signed char 、 unsigned char
  • 整数类型： char 、有符号整数类型、无符号整数类型、枚举类型
  • 实数类型：整数类型和实浮点类型
  • 算术类型：整数类型和浮点类型
  • 标量类型：算术类型和指针类型
  • 聚合类型：数组类型和结构体类型
  • 派生声明器类型：数组类型、函数类型和指针类型

兼容类型

C 程序中，在不同翻译单元中涉及同一对象或函数的声明，不必拥有相同类型。它们只需要拥有相似的类型，正式而言即兼容类型。同样的规则应用到函数调用和左值访问；实参类型必须与形参类型兼容，而左值表达式类型必须与被访问对象的类型兼容。

类型 T 与 U 兼容，若

  • 它们是同一类型（同名或由 typedef 引入的别名）
  • 它们是兼容的无限定类型的等同 cvr 限定版本
  • 它们是指针类型，并指向兼容类型
  • 它们是数组类型，且
  • 其元素类型兼容，且
  • 若都拥有常量大小，则大小相同。注意：未知边界数组与任何兼容元素类型的数组兼容。 VLA 与任何兼容元素类型的数组兼容。 (C99 起)
  • 它们都是结构体/联合体/枚举类型，且
  • (C99)若一者以标签声明，则另一者必须以同一标签声明。
  • 若它们都是完整类型，则其成员必须在数量上准确对应，以兼容类型声明，并拥有匹配的名称。
  • 另外，若它们都是枚举，则对应成员亦必须拥有相同值。
  • 另外，若它们是结构体或联合体，则
  • 对应的元素必须以同一顺序声明（仅结构体）
  • 对应的位域必须有相同宽度。
  • 一者为枚举类型，而另一者为该枚举的底层类型
  • 它们是函数类型，且
  • 其返回类型兼容
  • 它们都使用参数列表，参数数量（包括省略号的使用）相同，而其对应参数，在应用数组到指针和函数到指针类型调整，及剥除顶层限定符后，拥有相同类型
  • 一个是旧式（无参数）定义，另一个有参数列表，参数列表不使用省略号，而每个参数（在函数参数类型调整后）都与默认参数提升后的对应旧式参数兼容
  • 一个是旧式（无参数）声明，另一个拥有参数列表，参数列表不使用省略号，而所有参数（在函数参数类型调整后）不受默认参数提升影响

类型 char 既不与 signed char 兼容，也不与 unsigned char 兼容。

若涉及同一对象或函数的二个声明不使用兼容类型，则程序的行为未定义。

// 翻译单元 1
struct S {int a;};
extern struct S *x;  // 与 TU2 的 x 兼容，但不与 TU3 的 x 兼容
// 翻译单元 2
struct S;
extern struct S *x; // 与两个 x 兼容
// 翻译单元 3
struct S {float a;};
extern struct S *x; // 与 TU2 的 x 兼容，但不与 TU1 的 x 兼容

// 行为未定义
// 翻译单元 1
#include <stdio.h>
struct s {int i;}; // 与 TU3 的 s 兼容，但不与 TU2 的 s 兼容
extern struct s x = {0}; // 与 TU3 的 x 兼容
extern void f(void); // 与 TU2 的 f 兼容
int main()
{
   f();
   return x.i;
}
// 翻译单元 2
struct s {float f;}; // 与 TU4 的 s 兼容，但不与 TU1 的 s 兼容
extern struct s y = {3.14}; // 与 TU4 的 y 兼容
void f() // 与 TU1 的 f 兼容
{
   return;
}
// 翻译单元 3
struct s {int i;}; // 与 TU1 的 s 兼容，但不与 TU2 的 s 兼容
extern struct s x; // 与 TU1 的 x 兼容
// 翻译单元 4
struct s {float f;}; // 与 TU2 的 s 兼容，但不与 TU1 的 s 兼容
extern struct s y; // 与 TU2 的 y 兼容

// 行为良好定义：只有对象或函数的多个声明，而非类型自身必须拥有兼容类型

注意： C++ 没有兼容类型的概念。在不同翻译单元中声明二个兼容但不等同的类型的 C 程序不是合法的 C++ 程序。

合成类型

合成类型能从二个兼容的类型构造；它是与两个类型兼容，并满足下列条件的类型：

  • 若两个类型均为数组类型，则应用下列规则：
  • 若一个类型是常量大小数组，则合成类型为该大小的数组。
  • 否则，若一个类型是 VLA ，而尚未求值指定其大小的表达式，则行为未定义。
  • 否则，若一个类型为已指定大小的 VLA ，则合成类型为该大小的 VLA 。
  • 否则，若一个类型为未指定大小的 VLA ，则合成类型为未指定大小的 VLA 。
 (C99 起)
  • 否则，两个数组类型都有未知大小，而合成类型为未知大小的数组。
合成类型的元素类型是二个元素类型的合成类型。
  • 若一个类型是有参数类型列表（函数原型）的函数类型，则合成类型为有该参数类型列表的函数原型。
  • 若两个类型均为有参数类型列表的函数类型，则合成类型的参数类型列表中的每个参数类型，是对应参数的合成类型。

这些规则递归地应用到二个类型的派生来源类型。

// 给定一下二个文件作用域声明：
int f(int (*)(), double (*)[3]);
int f(int (*)(char *), double (*)[]);
// 生成的函数合成类型为：
int f(int (*)(char *), double (*)[3]);

对于拥有内部或外部链接，并在其先前声明已经可见的作用域中再次声明的标识符，若先前的声明指定了内部或外部链接，则在后一声明中的标识符类型成为合成类型。

不完整类型

不完整类型是缺乏足以确定其对象大小的信息对象类型。不完整类型可以在翻译单元的某些点完整。

下列类型不完整：

  • 类型 void 。此类型不能完整。
  • 大小未知的数组。之后指定大小的声明能使之完整。
extern char a[]; // a 的类型不完整（这通常出现于头文件）
char a[10];      // a 的类型现在完整（这通常出现于源文件）
  • 内容未知的结构体或联合体类型。在同一作用域的后面，定义同一结构体或联合体的内容的声明能使之完整。
struct node {
  struct node *next; // struct node 在此点不完整
}; // struct node 在此点完整

类型名

可能在异于声明的语境中必须指名类型。这些情况下使用类型名，即 type-specifiers 及 type-qualifiers 后随 declarator 的列表（见声明），它在文法上与会用来声明此类型的单个对象或函数的列表准确相同，除了省略掉标识符：

int n; // 声明 int
sizeof(int); // 使用类型名

int *a[3]; // 声明 3 个指向 int 指针的数组
sizeof(int *[3]); // 使用类型名

int (*p)[3]; // 声明指向 3 个 int 的数组的指针
sizeof(int (*)[3]); // 使用类型名

int (*a)[*] // （在函数参数中）声明指向 VLA 的指针
sizeof(int (*)[*]) // （在函数参数中）使用类型名

int *f(void); // 声明函数
sizeof(int *(void)); // 使用类型名

int (*p)(void); // 声明指向函数指针
sizeof(int (*)(void)); // 使用类型名

int (*const a[])(unsigned int, ...) = {0}; // 声明指向函数指针的数组
sizeof(int (*const [])(unsigned int, ...)); // 使用类型名

除了围绕标识符的冗余括号在类型名中有意义，并表示“不指定参数的函数”：

int (n); // 声明 int 类型的 n
sizeof(int ()); // 使用类型“返回 int 的函数”

类型名用于下列场合：

  • 转型运算符
  • sizeof
  • 复合字面量
 (C99 起)
  • 泛型选择
  • _Alignof
  • _Alignas
  • _Atomic （用作类型指定符时）
 (C11 起)

类型名可引入新类型：

void* p = (void*)(struct X {int i;} *)0;
// 用于转型表达式的 "struct X {int i;}*"
// 引入新类型 "struct X"
struct X x = {1}; // struct X 现在在作用域中

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.2.5 Types (p: 31-33)
  • 6.2.6 Representations of types (p: 31-35)
  • 6.2.7 Compatible type and composite type (p: 35-36)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.2.5 Types (p: 39-43)
  • 6.2.6 Representations of types (p: 44-46)
  • 6.2.7 Compatible type and composite type (p: 47-48)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.2.5 Types (p: 33-37)
  • 6.2.6 Representations of types (p: 37-40)
  • 6.2.7 Compatible type and composite type (p: 40-41)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.1.2.5 Types
  • 3.1.2.6 Compatible type and composite type

参阅


typedef 声明

< c‎ | language

typedef 声明提供一种声明标识符为类型别名的方式，以用于替换可能复杂的类型名。

关键词 typedef 在声明中处于存储类说明符的文法位置，只是它对存储和链接无影响：

typedef int int_t; // 声明 int_t 为类型 int 之别名
typedef char char_t, *char_p, (*fp)(void); // 声明 char_t 为类型 char 之别名
                                           // char_p 为 char* 之别名
                                           // fp 为 char(*)(void) 之别名

解释

若一个声明以 typedef 为存储类说明符，则其中每个声明符都会定义一个标识符为说明类型的别名。因为一个声明中仅允许一个存储类说明符， typedef 声明不能为 static 或 extern 。

typedef 声明不引入另一种类型，它只会建立既存类型的同义词，故而 typedef 名与其所别名引用的类型兼容。 typedef 名与通常标识符，例如枚举项、变量或函数共享通常命名空间。

对 VLA 的 typedef 只能出现在块作用域内。与数组自身的声明不同，数组长度会在每次控制流经过 typedef 声明时求值：

void copyt(int n)
{
    typedef int B[n]; // B 是 VLA ，其长度为 n ，现在求值
    n += 1;
    B a; // a 的长度是 +=1 前的 n
    int b[n]; // a 和 b 长度不同
    for (int i = 1; i < n; i++)
        a[i-1] = b[i];
}
 (C99 起)

注解

typedef 名可以是不完整类型，它会照常变得完整：

typedef int A[]; // A 是 int[]
A a = {1, 2}, b = {3,4,5}; // a 的类型是 int[2] ，b 的类型是 int[3]

typedef声明通常用于将名称从标签命名空间注入到通常命名空间：

typedef struct tnode tnode; // 通常命名空间的 tnode
                            // 为标签命名空间的 tnode之别名
struct tnode {
    int count;
    tnode *left, *right; // 同 struct tnode *left, *right;
}; // 现在 tnode 也是完整类型
tnode s, *sp; // 同 struct tnode s, *sp;

它们可以完全避免使用标签命名空间：

typedef struct { double hi, lo; } range;
range z, *zp;

typedef 名亦常用来简化复杂声明的语法：

// 5 个函数指针的数组，函数返回指向 3 个 int 的数组的指针
int (*(*callbacks[5])(void))[3]

// 与 typedef 相同
typedef int arr_t[3]; // arr_t 是 3 个 int 的数组
typedef arr_t* (*fp)(void); // 指针指向的函数返回 arr_t*
fp callbacks[5];

库常常会将依赖系统或依赖配置的类型暴露成 typedef 名，以对用户或其他库组件提供统一接口：

#if defined(_LP64)
typedef int     wchar_t;
#else
typedef long    wchar_t;
#endif

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.8 Type definitions (p: 137-138)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.7 Type definitions (p: 123-124)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.5.6 Type definitions

关键词

typedef

参阅


联合体声明

< c‎ | language

联合体是由一序列的成员所组成的类型，成员的存储重叠（与结构体相反，结构体是由一序列的成员所构成的类型，成员的存储以顺序分配）。在任一时刻，最多能在联合体中存储其一个成员的值。

联合体的类型说明符与 struct 类型说明符相同，只是所用的关键词有别。

语法

union 属性声明符序列(可选) 名字(可选) { 结构体声明列表 } | (1)
union 属性声明符序列(可选) 名字 | (2)
名字 | - | 正在定义的联合体名称
结构体声明列表 | - | 任意数量的变量声明、位域声明和静态断言声明。不允许不完整类型的成员和函数类型的成员。
属性声明符序列 | - | (C23)可选的属性列表，应用到联合体类型，若这种形式不后随 ; （即不是前置声明）则对于 (2) 不允许。

解释

联合体只大到足以保有其最大成员（亦可能添加额外的尾随填充字节）。其他成员被分配于与该最大成员一部分相同的字节中。

能转型指向联合体的指针为指向它每个成员的指针（若联合体拥有位域成员，则能转型指向联合体的指针为指向位域底层类型的指针）。类似地，指向结构体任何成员的指针都能被转型为指向整个结构体的指针。

若用于访问内容的联合体成员不同于上次用于存储值的成员，则转译被存储值的对象表示为新类型的对象表示（这被称为类型双关）。若新类型的大小大于上次写入的类型大小，则多出的字节内容是未指明的（而且可以是陷阱表示）。

类似结构体，类型为不带 name 的联合体的无名联合体成员被称为匿名联合体。每个匿名联合体的成员被认为是外围结构体或联合体的成员。若外围结构体或联合体亦为匿名，则递归调用此规则。

struct v {
   union { // 匿名联合体
      struct { int i, j; }; // 匿名结构体
      struct { long k, l; } w;
   };
   int m;
} v1;

v1.i = 2;   // 合法
v1.k = 3;   // 非法：内层结构体不是匿名的
v1.w.k = 5; // 合法

类似结构体，若不以任何具名成员（包含经由匿名嵌套结构体或联合体获得的成员）定义联合体，则程序行为未定义。

 (C11 起)

关键词

union

注解

关于结构体和联合体初始化的规则，见结构体初始化。

示例

#include <stdio.h>
#include <stdint.h>
#include <assert.h>

int main(void)
{
    union S {
        uint32_t u32;
        uint16_t u16[2];
        uint8_t  u8;
    } s = {0x12345678}; // s.u32 现为活跃成员
    printf("Union S has size %zu and holds %x\n", sizeof s, s.u32);
    s.u16[0] = 0x0011;  // s.u16 现为活跃成员
    // 从 s.u32 或 s.u8 的读取转译对象表示
//  printf("s.u8 is now %x\n", s.u8); // 未指定，典型结果是 11 或 00
//  printf("s.u32 is now %x\n", s.u32); // 未指定，典型结果是 12340011 或 00115678

    // 指向联合体所有成员的指针彼此间比较相等，也与指向联合体的指针比较相等
    assert((uint8_t*)&s == &s.u8);

    // 此联合体拥有尾随的 3 个填充字节
    union pad {
       char  c[5];   // 占据 5 字节
       float f;      // 占据 4 字节，隐含对齐 4
    } p = {.f = 1.23}; // 大小为 8 以满足 float 的对齐
    printf("size of union of char[5] and float is %zu\n", sizeof p);
}

可能的输出：

Union S has size 4 and holds 12345678
size of union of char[5] and float is 8

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.7.2.1 Structure and union specifiers (p: 81-84)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.2.1 Structure and union specifiers (p: 112-117)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.2.1 Structure and union specifiers (p: 101-104)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.5.2.1 Structure and union specifiers

参阅


变长参数

< c‎ | language

变参数函数是能以不同数目参数调用的函数。

只有新式（原型）函数声明可以为变长参数的。它必须通过出现在参数列表最后的 ... 形式的参数指定，且至少跟随一个具名参数。

//新式声明
int printx(const char* fmt, ...); // 此方法声明的函数
printx("hello world"); // 可能会以一个
printx("a=%d b=%d", a, b); // 或更多参数调用

// int printy(..., const char* fmt); // 错误： ... 必须在最后
// int printz(...); // 错误： ... 必须跟随至少一个具名参数

在函数调用中，每个属于变长参数列表一部分的参数会经历名为默认参数提升的隐式转换。

在函数体内使用变长参数时，这些参数的值必须用 <stdarg.h> 库工具访问：

定义于头文件 <stdarg.h>
va_start | 令函数得以访问可变参数 (宏函数)
va_arg | 访问下一个函数可变参数 (宏函数)
va_copy (C99) | 创造函数可变参数的副本 (宏函数)
va_end | 结束函数可变参数的行程 (宏函数)
va_list | 保有 va_start 、 va_arg 、 va_end 及 va_copy 所需信息 (typedef)

注意

虽然旧式（无原型）函数声明允许后继的函数调用使用任意参数，它们也不允许是变长参数（ C89 起）。这种函数的定义必须指定固定数目的参数，并且不能使用 stdarg.h 中的宏。

//旧式声明
int printx(); // 此方式定义的函数
printx("hello world"); // 可以以一个
printx("a=%d b=%d", a, b); // 或更多参数调用
// 上述调用行为至少有一个是未定义的，取决于函数定义所接收的参数数

示例

#include <stdio.h>
#include <time.h>
#include <stdarg.h>

void tlog(const char* fmt,...)
{
    char msg[50];
    strftime(msg, sizeof msg, "%T", localtime(&(time_t){time(NULL)}));
    printf("[%s] ", msg);
    va_list args;
    va_start(args, fmt);
    vprintf(fmt, args);
    va_end(args);
}

int main(void)
{
   tlog("logging %d %d %d...\n", 1, 2, 3);
}

输出：

[10:21:38] logging 1 2 3...

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.6.3/9 Function declarators (including prototypes) (p: 133)
  • 7.16 Variable arguments <stdarg.h> (p: 269-272)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.5.3/9 Function declarators (including prototypes) (p: 119)
  • 7.15 Variable arguments <stdarg.h> (p: 249-252)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.5.4.3/5 Function declarators (including prototypes)
  • 4.8 VARIABLE ARGUMENTS <stdarg.h>

参阅


volatile 类型限定符

< c‎ | language

C 类型系统中每一个独立的类型在都有数个该类型的限定版本，对应 const 、 volatile 及对于指向对象指针的 restrict 限定符中的一个、两个或全部三个。此页面描述 volatile 限定符的效果。

每一个通过对 volatile 限定类型左值表达式的访问（读与写），对于优化意图都被认为是可观副效应，从而访问会严格按照抽象机的规则求值（即所有写入会在下一个序点之前的某时完成）。这表明在执行的单个线程内，volatile 访问不能被优化掉，亦不能与另一个被顺序点分隔了 volatile 访问的可观副效应重排。

一个非 volatile 值到 volatile 值的转换是无效果的。欲使用 volatile 语义访问非 volatile 对象，必须先将其地址转换成指向 volatile 类型的指针，再通过该指针访问该对象。

任何通过非 volatile 左值结果，对拥有 volatile 限定类型的对象尝试读或写会导致未定义行为：

volatile int n = 1; // volatile 限定类型
int* p = (int*)&n;
int val = *p; // 未定义行为

volatile 限定的结构体或联合体类型，其成员会获取其所属类型的限定（当通过 . 或 -> 运算符时）：

struct s { int i; const int ci; } s;
// s.i 类型是 int，s.ci 的类型是 const int
volatile struct s vs;
// vs.i 和 vs.ci 的类型各是 volatile int 和 const volatile int
若以 volatile 类型限定符声明数组类型（通过使用 typedef ），则数组类型无 volatile 限定，但其元素类型有。 | (C23 前)
始终认为数组类型与其元素类型同等地拥有 volatile 限定。 | (C23 起)

若函数类型声明具有 volatile 类型限定（通过使用 typedef ），则行为未定义。

typedef int A[2][3];
volatile A a = {{4, 5, 6}, {7, 8, 9}}; // volatile int 的数组的数组
int* pi = a[0]; // 错误：a[0] 拥有 volatile int* 类型
void *unqual_ptr = a; // C23 前 OK ； C23 起错误
// 注： clang 即使在 C89-C17 模式也应用 C++/C23 中的规则

在函数声明中，关键词 volatile 可以出现于方括号内，用以声明函数参数的数组类型。它对数组所转换得的指针类型赋予限定。

下列两个声明声明同一函数：

void f(double x[volatile], const double y[volatile]);
void f(double * volatile x, const double * volatile y);
 (C99 起)

指向非 volatile 类型的指针可以隐式转换成指向同一或兼容类型的 volatile 限定版本的指针。逆向转换可以由类型转换表达式进行。

int* p = 0;
volatile int* vp = p; // OK：添加限定符（ int 到 volatile int）
p = vp; // 错误：丢弃限定符（ volatile int 到 int）
p = (int*)vp; // OK：类型转换

注意指向T的二重不可转换成指向volatile T的二重指针；对于要兼容的两个类型，它们的限定必须相同：

char *p = 0;
volatile char **vpp = &p; // 错误： char* 和 volatile char* 不是兼容类型
char * volatile *pvp = &p; // OK，添加限定符（ char* 到 char* volatile ）

volatile 的用法

1) static volatile 对象模仿映射于内存的 I/O 端口，而 static const volatile 对象模仿映射于内存的输入端口，例如实时时钟：
volatile short *ttyport = (volatile short*)TTYPORT_ADDR;
for(int i = 0; i < N; ++i)
    *ttyport = a[i]; // *ttyport 是 volatile short 类型的左值
2) sig_atomic_t 类型的 static volatile 对象用于与 signal 处理交流。
3) 含有对 setjmp 宏调用的函数中的局部 volatile 变量，是在 longjmp 返回后仅有保证恢复其值的局部变量。
4) 另外，volatile 变量可用于禁用某些优化形式，例如禁用死存储消除，或为微基准禁用常量折叠。

注意 volatile 变量不适合线程间交流；它们不提供原子性、同步或内存顺序。读取一个被另一线程未经同步地修改的 volatile 变量，或两个未同步的线程的共时修改，对于一些数据竞争是未定义行为。

关键词

volatile

示例

展示用 volatile 禁用优化

#include <stdio.h>
#include <time.h>

int main(void)
{
    clock_t t = clock();
    double d = 0.0;
    for (int n = 0; n < 10000; ++n)
        for (int m = 0; m < 10000; ++m)
            d += d * n * m; // 读写非 volatile 对象
    printf("Modified a non-volatile variable 100m times. "
           "Time used: %.2f seconds\n",
           (double)(clock() - t)/CLOCKS_PER_SEC);

    t = clock();
    volatile double vd = 0.0;
    for (int n = 0; n < 10000; ++n)
        for (int m = 0; m < 10000; ++m) {
            double prod = vd * n * m; // 读 volatile 对象
            vd += prod; // 读写 volatile 对象
        }
    printf("Modified a volatile variable 100m times. "
           "Time used: %.2f seconds\n",
           (double)(clock() - t)/CLOCKS_PER_SEC);
}

可能的输出：

Modified a non-volatile variable 100m times. Time used: 0.00 seconds
Modified a volatile variable 100m times. Time used: 0.79 seconds

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.7.3 Type qualifiers (p: 87-90)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.7.3 Type qualifiers (p: 121-123)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.7.3 Type qualifiers (p: 108-110)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 6.5.3 Type qualifiers

参阅


while 循环

< c‎ | language

重复执行 语句 ，直到 表达式 的值变得比较等于零。此测试在每次迭代前发生。

语法

属性说明符序列(可选) while ( 表达式 ) 语句
表达式 | - | 任何标量类型 表达式。在每次迭代前求值此表达式，而且若它与零比较相等，则退出循环。
语句 | - | 任何语句，常为一条复合语句，它被用作循环体
属性说明符序列 | - | (C23)可选的属性列表，应用到循环语句

解释

while 导致重复执行 语句 （亦称为循环体），直至 表达式 （亦称为控制表达式）与零比较相等。不管是正常进入循环体还是以 goto 进入 语句 内部，都会发生重复。

表达式的求值在每次执行 语句 前发生（除非用 goto 进入）。若需要在每次循环体后求值控制表达式，可以用 do-while 循环。

若循环的执行需要在某些点终止，则能以 break 语句为作终止语句。

若循环的执行需要从循环体的结尾继续，则能以 continue 语句为快捷方式。

若无限循环在其 语句 或 表达式 的任何部分无可观测行为（ I/O 、 volatile 访问、原子或同步操作），则拥有这种循环的程序有未定义行为。这允许编译器优化掉整个不可观测循环，而无需证明他们会结束。仅有的例外是 表达式 为常量表达式的循环： while(true) 始终是无限循环。

同所有选择和迭代语句， while 语句建立块作用域：任何于 表达式 中引入的标识符在语句后离开作用域。

 (C99 起)

注解

常以布尔和指针表达式为循环控制表达式。布尔值 false 和任何指针类型的空指针值与零比较相等。

关键词

while

示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { SIZE = 8 };
int main(void)
{
    // 平凡示例
    int array[SIZE], n = 0;
    while(n < SIZE) array[n++] = rand() % 2;
    puts("Array filled!");
    n = 0;
    while(n < SIZE) printf("%d ", array[n++]);
    printf("\n");

    // 经典的 strcpy() 实现
    // （从 src 复制空终止字符串到 dst ）
    char src[]="Hello, world", dst[sizeof src], *p=dst, *q=src;
    while(*p++ = *q++)
        ; // 空语句
    puts(dst);
}

输出：

Array filled!
1 0 1 1 1 1 0 0
Hello, world

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.8.5.1 The while statement (p: 109)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.8.5.1 The while statement (p: 151)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.8.5.1 The while statement (p: 136)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.6.5.1 The while statement

参阅


有用的资源

< c

C FAQ

  • C FAQ - 来自 Usenet newsgroup comp.lang.c 的对常问问题的回答

C 语言及库参考

  • JTC1/SC22/WG14 - C 标准委员会，包括草案 C 语言标准、提案及缺陷报告
    • n1124.pdf - C99 草案（含 TC1 与 TC 2 ）
    • n1256.pdf - C99 草案（含 TC1 、 TC2 及 TC 3）
    • n1570.pdf - C11 最终工作草案
    • n2176 (C17 FDIS) - C17/C18 最终草案
    • n2731.pdf - C23 最新工作草案
  • comp.std.c - 关于 C 语言标准的讨论
  • GNU C 手册 - GNU C 编译器所实现的 C 核心语言参考。

C ABI

  • System V ABI ，用于 x86-64 、 Intel386 及 IA MCU 架构
  • Windows x64 ABI
  • PowerPC EABI 32 位嵌入式处理器
  • PowerOpen ABI 旧式 PowerPC 平台
  • ARM ABI ARM 架构

相关标准

  • POSIX.1-2017 - Unix 兼容系统的操作系统 API
  • Linux 帮助页面 - Linux OS API 文档

开源实现

  • 标准库实现
  • GNU libc
  • MUSL
  • Newlib
  • PDClib
  • 编译器
  • GCC
  • LLVM Clang

可能有用

  • C 库列表

参阅


开源 C 库列表

< c‎ | links

此页面的目的是构建开源 C 库的比较列表，使得人们在需要特定功能的实现时，不必浪费时间在网上（ DuckDuckGo 、谷歌、必应等）搜索。

若你知道可能对其他人有用的库，请在此添加到它的链接。能包含者无限制，除了必须能便捷地下载库源码。

以“原态”提供此页面——希望这有用，但不提供任何担保。过时、误导或错误的链接可能出现于此。若你注意到这些错误，则改正它会很有意义。

操作系统

访问控制
  • acl
  • apparmor
扩展属性
  • attr

图形用户界面

  • IUP
  • tiny file dialogs - 单一的 C 跨平台文件（无初始化，无主循环， 6 个形式函数调用）

Gtk+ 工具

  • gtk+
  • gtkhtml
  • appmenu-gtk
  • ghex
  • gtkspell
  • gtksourceview
  • gtkhotkey
  • gucharmap
  • goocanvas

Microsoft Excel

  • libxlsxwriter

音频

编码
  • aften
  • faad2
  • wavpack
基础结构
  • alsa-lib
  • portaudio
CD
  • cdparanoia
语音合成
  • espeak --
  • flite --

视频

编码
  • schroedinger
  • video4linux

文件

  • gmime
  • caos

数学

  • gsl
整数多维插值
  • argyll
线性代数
  • atlas
  • blas
  • eigen
金融
  • ta-lib
快速傅里叶变换（FFT）
  • fftw3
多精度
  • gmp
信号处理
  • liquid-dsp
  • vsipl
  • vsipl++

图形

  • cairo
  • babl
  • SIGIL (Sound, Input, and Graphics Integration Library) - 极易用的 2D 图形、输入及音频跨平台库

进程间

  • dbus-glib
  • dbus
  • dee

数据库

  • berkeley db
  • lmdb

配置

  • libconfig
  • libconfini

交互

  • libcurl
  • libmicrohttpd
  • libsagui
  • gsoap
  • zeromq
  • MQTT-C - Github URL （ MIT 许可）
  • KCP - 快速可靠的 ARQ 协议，帮助应用减少网络延迟。（ MIT 许可）
  • open62541(OPC UA) - Github URL （MPL V2.0 许可）

压缩

  • bzip2
  • zlib

libc

  • bstrlib
  • eglibc
  • musl libc

XML

  • expat
  • gsoap

Javascript

  • gjs

编辑距离

  • edlib

面向对象编程

  • Cello

网络库

  • libpcap(*nix)
  • winpcap(xp~win8?) - 已停止更新，建议只在xp平台上使用
  • npcap(win7~10+) - 在Win7+系统上有更好的性能，详见官网介绍

Web 前端

  • cgit

调试

  • dbg-macro - 一组用于打印并返回表达式的值的宏，对于快速调试来说非常方便。受 Rust 的 dbg!(…) 宏和它的 C++ 变体启发。 (MIT 许可)

参阅


本地化支持

< c
定义于头文件 <locale.h>
setlocale
 获取和设置当前 C 本地环境
(函数)
localeconv
 查询当前本地环境的数值及货币格式化细节
(函数)
lconv
 localeconv 所返回的格式化细节
(结构体)
本地环境类别
LC_ALLLC_COLLATELC_CTYPELC_MONETARYLC_NUMERICLC_TIME
 setlocale 所用的本地环境类别
(宏常量)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.11 Localization <locale.h> (p: 223-230)
  • 7.31.6 Localization <locale.h> (p: 455)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.11 Localization <locale.h> (p: 204-211)
  • 7.26.5 Localization <locale.h> (p: 401)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.4 LOCALIZATION <locale.h>
  • 4.13.3 Localization <locale.h>

参阅


LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME

< c‎ | locale
定义于头文件 <locale.h>
#define LC_ALL /*implementation defined*/
#define LC_COLLATE /*implementation defined*/
#define LC_CTYPE /*implementation defined*/
#define LC_MONETARY /*implementation defined*/
#define LC_NUMERIC /*implementation defined*/
#define LC_TIME /*implementation defined*/

上面每个宏常量都展开成拥有相异值的整数常量表达式，适合用作 setlocale 的首个参数。

常量 | 解释
LC_ALL | 选择整个 C 本地环境
LC_COLLATE | 选择 C 本地环境中的对照类别
LC_CTYPE | 选择 C 本地环境中的字符分类类别
LC_MONETARY | 选择 C 本地环境中的货币格式化类别
LC_NUMERIC | 选择 C 本地环境中的数值格式化类别
LC_TIME | 选择 C 本地环境中的时间格式化类别

<locale.h> 中可以定义附加宏常量，名称以 LC_ 后随至少一个大写字母开始。例如， POSIX 规范要求 LC_MESSAGES （此外还控制 perror 和 strerror ）， ISO/IEC 30112:2014 （ 2014 方案）额外定义 LC_IDENTIFICATION 、 LC_XLITERATE 、 LC_NAME 、 LC_ADDRESS 、 LC_TELEPHONE 、 LC_PAPER 、 LC_MEASUREMENT 和 LC_KEYBOARD ，它们均为 GNU C 库所支持（除了 LC_XLITERATE ）。

注意

glibc 中的本地环境类别

glibc 除了 C 标准要求的 5 个类别外，还额外支持 7 个类别，以及一个默认项：

glibc 本地环境类别常量 | 解释
LC_ADDRESS | 选择 C 本地环境中的邮政地址格式类别
LC_IDENTIFICATION | 选择 C 本地环境中的类别版本与状态
LC_KEYBOARD | 选择 C 本地环境中的键盘鉴别类别
LC_MEASUREMENT | 选择 C 本地环境中的度量系统信息类别
LC_NAME | 选择 C 本地环境中的人名书写格式类别
LC_PAPER | 选择 C 本地环境中的纸张格式类别
LC_TELEPHONE | 选择 C 本地环境中的电话号码格式（和其他电话信息）类别
LANG | 选择尚未指定的类别

其中 LC_ALL 的优先级高于所有特定类别，而每个特定类别都优先于 LANG 。具体而言：

  1. 若设置 LC_ALL 为 "zh_CN.UTF-8" ，则不论 LC_* 和 LANG 原为何值，每个分类都会被设为 "zh_CN.UTF-8" 。
  2. 若未设置 LC_ALL ，而专门设置 LANG 为 "zh_CN.UTF-8" ，并设置某 LC_* 为"en_US.UTF-8" ，则其所对应的本地环境类别被设为 "en_US.UTF-8" 。
  3. 若未设置 LC_ALL 和某些类别的 LC_* ，并设置 LANG 为 "zh_CN.UTF-8" ，则这些 LC_* 所对应的本地环境被设为 "zh_CN.UTF-8" 。

所以，对于不同的目的，应该用不同方式设置本地环境：

  • 例如，若需要纯中文的系统，则可调用 setlocale (LC_ALL, "zh_CN.UTF-8") 或 setlocale (LANG, "zh_CN.UTF-8") 。可以但没必要设置二次。
  • 若只需要输入中文的环境，而其他界面信息和格式为英文，则可使用
setlocale(LC_CTYPE, "zh_CN.UTF-8");
setlocale(LANG, "en_US.UTF-8");
  • 若有特殊的本地环境定制需求，例如使用中文 GBK 字符集、用 ISO-8859-1 字符集的大英数字系统、用 ISO-8859-15 字符集的德国度量系统……，则应逐一设置 LC_* ：
setlocale(LC_TYPE, "zh_CN.GBK/GBK");
setlocale(LC_NUMERIC, "en_GB.ISO-8859-1");
setlocale(LC_MESUREMENT, "de_DE.ISO-8859-15@euro");
// 以及其他类别
  • 若只需要应用默认 "C" （ "POSIX" 为其别名）本地环境，则无需任何设置代码。

示例

#include <stdio.h>
#include <locale.h>
#include <time.h>
#include <wchar.h>

int main(void)
{
    setlocale(LC_ALL, "en_US.UTF-8"); // C 本地环境将为启用 UTF-8 的英文
    setlocale(LC_NUMERIC, "de_DE");   // 小数点将为德文
    setlocale(LC_TIME, "ja_JP");      // 日期/时间格式将为日文
    wchar_t str[100];
    time_t t = time(NULL);
    wcsftime(str, 100, L"%A %c", localtime(&t));
    wprintf(L"Number: %.2f\nDate: %Ls\n", 3.14, str);
}

输出：

Number: 3,14
Date: 月曜日 2011年12月19日 18時04分40秒

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.11/3 Localization <locale.h> (p: 224)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.11/3 Localization <locale.h> (p: 205)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.4 LOCALIZATION <locale.h>

参阅

setlocale
 获取和设置当前 C 本地环境
(函数)


lconv

< c‎ | locale
定义于头文件 <locale.h>
struct lconv;

struct lconv 含有 C 本地环境定义的数值和货币格式化规则。此结构体的对象可由 localeconv 获得。 std::lconv 的成员为 char 类型和 char* 类型值。除了 decimal_point ，每个 char* 成员都可以指向空字符（即为空 C 字符串）。 char 类型成员均为非负数，而且若任一者在当前 C 本地环境中不可用，则为 CHAR_MAX 。

成员对象

非货币数值格式化参数

char* decimal_point | 用作小数点的字符 (公开成员对象)
char* thousands_sep | 用于在小数点前分隔数位组的字符 (公开成员对象)
char* grouping | 字符串，其元素指示数位组的大小 (公开成员对象)

货币数值格式化参数

char* mon_decimal_point | 用作小数点的字符 (公开成员对象)
char* mon_thousands_sep | 用于在小数点前分隔数位组的字符 (公开成员对象)
char* mon_grouping | 字符串，其元素指示数位组的大小 (公开成员对象)
char* positive_sign | 用于指示非负货币量的字符串 (公开成员对象)
char* negative_sign | 用于指示负货币量的字符串 (公开成员对象)

本地货币数值格式化参数

char* currency_symbol | 当前 C 本地环境中用于通货的符号 (公开成员对象)
char frac_digits | 货币量中小数点后显示的位数 (公开成员对象)
char p_cs_precedes | 若 currency_symbol 置于非负值前则为 1 ，于其后则为 ​0​ (公开成员对象)
char n_cs_precedes | 若 currency_symbol 置于负值前则为 1 ，于其后则为 ​0​ (公开成员对象)
char p_sep_by_space | 指示 currency_symbol 、 positive_sign 及非负货币值的分隔 (公开成员对象)
char n_sep_by_space | 指示 currency_symbol 、 positive_sign 及负货币值的分隔 (公开成员对象)
char p_sign_posn | 指示非负货币值中 positive_sign 的位置 (公开成员对象)
char n_sign_posn | 指示负货币值中 negative_sign 的位置 (公开成员对象)

国际货币数值格式化参数

char* int_curr_symbol | 当前 C 本地环境中用作国际通货名的字符串 (公开成员对象)
char int_frac_digits | 国际货币量中小数点后显示的位数 (公开成员对象)
char int_p_cs_precedes (C99) | 若 int_curr_symbol 置于非负值前则为 1 ，于其后则为 ​0​ (公开成员对象)
char int_n_cs_precedes (C99) | 若 int_curr_symbol 置于负值前则为 1 ，于其后则为 ​0​ (公开成员对象)
char int_p_sep_by_space (C99) | 指示 int_curr_symbol 、 positive_sign 及非负国际货币值的分隔 (公开成员对象)
char int_n_sep_by_space (C99) | 指示 int_curr_symbol 、 positive_sign 及负国际货币值的分隔 (公开成员对象)
char int_p_sign_posn (C99) | 指示非负国际货币值中 positive_sign 的位置 (公开成员对象)
char int_n_sign_posn (C99) | 指示负国际货币值中 positive_sign 的位置 (公开成员对象)

按照数值转译 grouping 和 mon_grouping 所指向的 C 字符串。遇到终止 '\0' 时，假设最后见到的值为剩下的数位重复。若遇到 CHAR_MAX ，则不再将数位分组。典型的每次三位分组是 "\003" 。

p_sep_by_space 、 n_sep_by_space 、 int_p_sep_by_space 、 int_n_sep_by_space 的值转译如下：

0 | 通货符号和值间无空格分隔
1 | 符号紧贴通货符号，值为空格所分隔
2 | 符号紧贴值，通货符号为空格所分隔

p_sign_posn 、 n_sign_posn 、 int_p_sign_posn 、 int_n_sign_posn 的值转译如下：

0 | 括号围绕值，并用通货符号表示符号
1 | 符号在值与通货符号前
2 | 符号在值与通货符号后
3 | 符号在通货符号前
4 | 符号在通货符号后

示例

#include <locale.h>
#include <stdio.h>

int main(void)
{
    setlocale(LC_ALL, "ja_JP.UTF-8");
    struct lconv *lc = localeconv();
    printf("Japanese currency symbol: %s(%s)\n", lc->currency_symbol, lc->int_curr_symbol);
}

可能的输出：

Japanese currency symbol: ￥(JPY)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.11/2 Localization <locale.h> (p: 223)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.11/2 Localization <locale.h> (p: 204)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.4 LOCALIZATION <locale.h>

参阅

localeconv
 查询当前本地环境的数值及货币格式化细节
(函数)


localeconv

< c‎ | locale
定义于头文件 <locale.h>
struct lconv *localeconv(void);

localeconv 函数获得指向 struct lconv 类型静态对象的指针，该对象表示当前 C 本地环境的数值和货币格式化规则。

参数

（无）

返回值

指向当前 struct lconv 对象的指针。

注意

通过返回的指针修改对象是未定义行为。

localeconv 修改静态对象，从不同线程调用它而不同步是未定义行为。

示例

#include <locale.h>
#include <stdio.h>

int main(void)
{
    setlocale(LC_ALL, "ja_JP.UTF-8");
    struct lconv* lc = localeconv();
    printf("Japanese currency symbol: %s(%s)\n", lc->currency_symbol, lc->int_curr_symbol);
}

输出：

Japanese currency symbol: ￥(JPY)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.11.2.1 The localeconv function (p: 225-230)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.11.2.1 The localeconv function (p: 206-211)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.4.2.1 The localeconv function

参阅

setlocale | 获取和设置当前 C 本地环境 (函数)
lconv | localeconv 所返回的格式化细节 (结构体)


setlocale

< c‎ | locale
定义于头文件 <locale.h>
char* setlocale( int category, const char* locale);

setlocale 函数安装指定的系统本地环境或其一部分，作为新的 C 本地环境。修改保持效果，并影响所有关乎本地环境的 C 库函数执行，到下次调用 setlocale 为止。若 locale 为空指针，则 setlocale 查询当前 C 本地环境而不修改它。

参数

category | - | 本地环境类别标识符， LC_xxx 宏之一。可为 0 。
locale | - | 系统限定的本地环境标识符。对于操作系统的环境支持字段为命令行“ locale -a ”的合法列出内容值，对于用户偏好的本地环境为 "" ，对于最小本地环境为 "C" 。

返回值

指向窄空终止字符串的指针，它表示应用更改后的 C 本地环境，若存在。或在失败时为空指针。

返回字符串的副本和到 setlocale 的此调用中所用的类别，可在程序的后面用来恢复本地环境到此调用结束时的状态。

注解

程序启动过程中，运行任何用户代码前会执行 setlocale( LC_ALL, "C"); 的等价代码。

尽管返回类型为 char* ，修改被指向的字符是未定义行为。

因为 setlocale修改影响依赖本地环境的函数执行的全局状态，故而一个线程调用它，同时另一个线程执行任何下列函数是未定义行为：fprintf 、 isprint 、 iswdigit 、 localeconv 、 tolower 、 fscanf 、 ispunct 、 iswgraph 、 mblen 、 toupper 、 isalnum 、 isspace 、 iswlower 、 mbstowcs 、 towlower 、 isalpha 、 isupper 、 iswprint 、 mbtowc 、 towupper 、 isblank 、 iswalnum 、 iswpunct 、 setlocale 、 wcscoll 、 iscntrl 、 iswalpha 、 iswspace 、 strcoll 、 wcstod 、 isdigit 、 iswblank 、 iswupper、 strerror 、 wcstombs 、 isgraph 、 iswcntrl 、 iswxdigit 、 strtod 、 wcsxfrm 、 islower 、 iswctype 、 isxdigit 。

POSIX 亦定义名为 "POSIX" 的本地环境，它始终可访问，并准确等于默认的最小 "C" 本地环境。

POSIX 亦指定后继的 setlocale 调用可以非法化返回的指针，而不仅是被指向的字符串内容。

示例

#include <stdio.h>
#include <locale.h>
#include <time.h>
#include <wchar.h>

int main(void)
{
    // C 本地环境将为启用 UTF-8 的英文；
    // 小数点将为德文
    // 日期和时间格式将为日文
    setlocale(LC_ALL, "en_US.UTF-8");
    setlocale(LC_NUMERIC, "de_DE");
    setlocale(LC_TIME, "ja_JP");

    wchar_t str[100];
    time_t t = time(NULL);
    wcsftime(str, 100, L"%A %c", localtime(&t));
    wprintf(L"Number: %.2f\nDate: %ls\n", 3.14, str);
}

可能的输出：

Number: 3,14
Date: 木曜日 2014年11月06日 09時58分56秒

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.11.1.1 The setlocale function (p: 163-164)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.11.1.1 The setlocale function (p: 224-225)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.11.1.1 The setlocale function (p: 205-206)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.4.1.1 The setlocale function

参阅

LC_ALLLC_COLLATELC_CTYPELC_MONETARYLC_NUMERICLC_TIME
 setlocale 所用的本地环境类别
(宏常量)


动态内存管理

< c

函数

定义于头文件 <stdlib.h>
malloc | 分配内存 (函数)
calloc | 分配并清零内存 (函数)
realloc | 扩充之前分配的内存块 (函数)
free | 归还之前分配的内存 (函数)
aligned_alloc (C11) | 分配对齐的内存 (函数)

参阅


aligned_alloc

< c‎ | memory
定义于头文件 <stdlib.h> |
void *aligned_alloc( size_t alignment, size_t size ); | (C11 起)

分配 size 字节未初始化的存储空间，按照 alignment 指定对齐。 size 参数必须是 alignment 的整数倍。

aligned_alloc 是线程安全的：它表现得如同只访问通过其参数可见的内存区域，而非任何静态存储。

令 free 或 realloc 归还一块内存区域的先前调用，同步于令 aligned_alloc 分配相同或部分相同的内存区域的调用。此同步出现于任何解分配函数所做的内存访问之后，和任何通过 aligned_alloc 所做的内存访问之前。所有操作每块特定内存区域的分配及解分配函数拥有单独全序。

参数

alignment | - | 指定对齐。必须是实现支持的合法对齐。
size | - | 分配的字节数。 alignment 的整数倍。

返回值

成功时，返回指向新分配内存的指针。为避免内存泄漏，返回的指针必须用 free() 或 realloc() 解分配。

失败时，返回空指针。

注意

传递不是 alignment 整数倍的 size ，或传递实现不支持的 alignment ，会令函数失败并返回空指针（出版的 C11 指定此为未定义行为，这已经为 DR 460 所更正）。 n2072 提议移除大小限制，使之能在限制性的对齐边界分配小对象（类似 _Alignas ）。

作为“实现支持”的要求一例， POSIX 函数 posix_memalign 接受任何二的幂且为 sizeof(void *) 倍数的 alignment ，而基于 POSIX 的 aligned_alloc 实现继承此要求。

常规的 malloc 为任何对象类型对齐内存（实际上，这表示对齐到 _Alignof( max_align_t ) ）。此函数对于过度对齐的内存分配有用，譬如 SSE 、缓存线路，或是虚拟机页边界。

示例

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int *p1 = malloc(10*sizeof *p1);
    printf("default-aligned addr:   %p\n", (void*)p1);
    free(p1);

    int *p2 = aligned_alloc(1024, 1024*sizeof *p2);
    printf("1024-byte aligned addr: %p\n", (void*)p2);
    free(p2);
}

可能的输出：

default-aligned addr:   0x1e40c20
1024-byte aligned addr: 0x1e41000

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.3.1 The aligned_alloc function (p: 347-348)

参阅


calloc

< c‎ | memory
定义于头文件 <stdlib.h>
void* calloc( size_t num, size_t size );

为 num 个对象的数组分配内存，并初始化所有分配存储中的字节为零。

若分配成功，会返回指向分配内存块最低位（首位）字节的指针，它为任何类型适当地对齐。

若 size 为零，则行为是实现定义的（可返回空指针，或返回不可用于访问存储的非空指针）。

calloc 是线程安全的：它表现得如同只访问通过其参数可见的内存区域，而非任何静态存储。

令 free 或 realloc 解分配一块内存区域的先前调用，同步于令 calloc 分配相同或部分相同的内存区域的调用。这种同步出现于任何解分配函数所做的内存访问之后，和任何 calloc 所做的内存访问之前。所有操作每块特定内存区域的分配及解分配函数拥有单独全序。

 (C11 起)

参数

num | - | 对象数目
size | - | 每个对象的大小

返回值

成功时，返回指向新分配内存的指针。为避免内存泄漏，必须用 free() 或 realloc() 解分配返回的指针。

失败时，返回空指针。

注意

因为对齐需求的缘故，分配的字节数不必等于 num*size 。

初始化所有位为零不保证浮点数或指针被各种初始化为 0.0 或空指针（尽管这在所有常见平台上为真）。

本来（ C89 中），增加对零大小的支持是为了容纳这种代码：

OBJ *p = calloc(0, sizeof(OBJ)); // “零长度”占位符
...
while(1) {
    p = realloc(p, c * sizeof(OBJ)); // 重分配，直至大小稳定
    ... // 可能会修改 c 或跳出循环的代码
}

示例

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int *p1 = calloc(4, sizeof(int));    // 分配并清零 4 个 int 的数组
    int *p2 = calloc(1, sizeof(int[4])); // 等价，直接命名数组类型
    int *p3 = calloc(4, sizeof *p3);     // 等价，免去重复类型名

    if(p2) {
        for(int n=0; n<4; ++n) // 打印数组
            printf("p2[%d] == %d\n", n, p2[n]);
    }

    free(p1);
    free(p2);
    free(p3);
}

输出：

p2[0] == 0
p2[1] == 0
p2[2] == 0
p2[3] == 0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.3.2 The calloc function (p: 348)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.3.1 The calloc function (p: 313)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.3.1 The calloc function

参阅


free

< c‎ | memory
定义于头文件 <stdlib.h>
void free( void* ptr );

解分配之前由 malloc() 、 calloc() 、 aligned_alloc() (C11 起) 或 realloc() 分配的空间。

若 ptr 为空指针，则函数不进行操作。

若 ptr 的值不等于之前从 malloc() 、 calloc() 、 realloc() 或 aligned_alloc() (C11 起) 返回的值，则行为未定义。

若 ptr 所指代的内存区域已经被解分配，则行为未定义，即是说已经以ptr 为参数调用 free() 或 realloc() ，而且没有后继的 malloc() 、 calloc() 或 realloc() 调用以 ptr 为结果。

若在 free() 返回后通过指针 ptr 访问内存，则行为未定义（除非另一个分配函数恰好返回等于 ptr 的值）。

free 是线程安全的：它表现得如同只访问通过其参数可见的内存区域，而非任何静态存储。

令 free 解分配内存区域的调用，同步于任何令分配函数分配相同或部分相同区域的后续调用。这种同步出现于任何解分配函数所做的内存访问后，和任何分配函数所做的内存访问前。所有操作每块特定内存区域的分配及解分配函数拥有单独全序。

 (C11 起)

参数

ptr - 指向要解分配的内存的指针

返回值

（无）

注解

此函数接收空指针（并对其不处理）以减少特例的数量。不管分配成功与否，分配函数返回的指针都能传递给 free() 。

示例

#include <stdlib.h>

int main(void)
{
    int *p1 = malloc(10*sizeof *p1);
    free(p1); // 每一个分配的指针都要释放

    int *p2 = calloc(10, sizeof *p2);
    int *p3 = realloc(p2, 1000*sizeof *p3);
    if(p3) // p3 非空表示 p2 被 realloc 释放
       free(p3);
    else // p3 为空表示 p2 未被释放
       free(p2);
}

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.3.3 The free function (p: 348)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.3.2 The free function (p: 313)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.3.2 The free function

参阅


malloc

< c‎ | memory
定义于头文件 <stdlib.h>
void* malloc( size_t size );

分配 size 字节的未初始化内存。

若分配成功，则返回为任何拥有基础对齐的对象类型对齐的指针。

若 size 为零，则 malloc 的行为是实现定义的。例如可返回空指针。亦可返回非空指针；但不应当解引用这种指针，而且应将它传递给 free 以避免内存泄漏。

malloc 是线程安全的：它表现得如同只访问通过其参数可见的内存区域，而非任何静态存储。

令 free 或 realloc 归还一块内存区域的先前调用，同步于令 malloc 分配相同或部分相同的内存区域的调用。此同步出现于任何通过解分配函数所作的内存访问后，和任何 malloc 所作的内存访问前。所有操作每块特定内存区域的分配和解分配函数有单独全序。

 (C11 起)

参数

size - 要分配的字节数

返回值

成功时，返回指向新分配内存的指针。为避免内存泄漏，必须用 free() 或 realloc() 解分配返回的指针。

失败时，返回空指针。

示例

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int *p1 = malloc(4*sizeof(int));  // 足以分配 4 个 int 的数组
    int *p2 = malloc(sizeof(int[4])); // 等价，直接命名数组类型
    int *p3 = malloc(4*sizeof *p3);   // 等价，免去重复类型名

    if(p1) {
        for(int n=0; n<4; ++n) // 置入数组
            p1[n] = n*n;
        for(int n=0; n<4; ++n) // 打印出来
            printf("p1[%d] == %d\n", n, p1[n]);
    }

    free(p1);
    free(p2);
    free(p3);
}

输出：

p1[0] == 0
p1[1] == 1
p1[2] == 4
p1[3] == 9

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.3.4 The malloc function (p: 349)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.3.3 The malloc function (p: 314)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.3.3 The malloc function

参阅


realloc

< c‎ | memory
定义于头文件 <stdlib.h>
void *realloc( void *ptr, size_t new_size );

重新分配给定的内存区域。它必须是之前为 malloc() 、 calloc() 或 realloc() 所分配，并且仍未被 free 或 realloc 的调用所释放。否则，结果未定义。

重新分配按以下二者之一执行：

a) 可能的话，扩张或收缩 ptr 所指向的已存在内存。内容在新旧大小中的较小者范围内保持不变。若扩张范围，则数组新增部分的内容是未定义的。
b) 分配一个大小为 new_size 字节的新内存块，并复制大小等于新旧大小中较小者的内存区域，然后释放旧内存块。

若无足够内存，则不释放旧内存块，并返回空指针。

若 ptr 为 NULL ，则行为与调用 malloc (new_size) 相同。

若 new_size 为零，则行为是实现定义的（可返回空指针，此情况下可能或可能不释放旧内存，或返回不会用于访问存储的非空指针）。

若 new_size 为零，则行为是实现定义的（可能返回空指针，该情况下可能或可能不释放旧内存，或可能返回某个不能用于访问存储的非空指针）。这种用法被弃用（经由 DR 400 ）。 (C17 起) | (C23 前)
若 new_size 为零，则行为未定义。 | (C23 起)

realloc 是线程安全的：它表现得如同只访问通过其参数可见的内存区域，而非任何静态存储。

先前令 free 或 realloc 归还一块内存区域的调用，同步于任何分配函数的调用，包括分配相同或部分相同内存区域的 realloc 。这种同步出现于任何解分配函数所做的内存访问后，和任何 realloc 所做内存访问前。所有操作一块特定内存区域的分配及解分配函数拥有单独全序。

 (C11 起)

参数

ptr | - | 指向需要重新分配的内存区域的指针
new_size | - | 数组的新大小（字节数）

返回值

成功时，返回指向新分配内存的指针。返回的指针必须用 free() 或 realloc() 归还。原指针 ptr 被非法化，而且任何通过它的访问是未定义行为（即使重分配是就地的）。

失败时，返回空指针。原指针 ptr 保持有效，并需要通过 free() 或 realloc() 归还。

注解

本来（ C89 中），增加对零大小的支持是为了容纳这种代码：

OBJ *p = calloc(0, sizeof(OBJ)); // “零长度”占位
...
while(1) {
    p = realloc(p, c * sizeof(OBJ)); // 重分配，直至大小稳定
    ... // 可能会修改 c 或跳出循环的代码
}

示例

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int *pa = malloc(10 * sizeof *pa); // 分配 10 个 int 的数组
    if(pa) {
        printf("%zu bytes allocated. Storing ints: ", 10*sizeof(int));
        for(int n = 0; n < 10; ++n)
            printf("%d ", pa[n] = n);
    }

    int *pb = realloc(pa, 1000000 * sizeof *pb); // 重分配数组更大的大小
    if(pb) {
        printf("\n%zu bytes allocated, first 10 ints are: ", 1000000*sizeof(int));
        for(int n = 0; n < 10; ++n)
            printf("%d ", pb[n]); // 展示数组
        free(pb);
    } else { // 若 realloc 失败，则需要返回原指针
        free(pa);
    }
}

输出：

40 bytes allocated. Storing ints: 0 1 2 3 4 5 6 7 8 9
4000000 bytes allocated, first 10 ints are: 0 1 2 3 4 5 6 7 8 9

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.22.3.5 The realloc function (p: 254)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.3.5 The realloc function (p: 349)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.3.4 The realloc function (p: 314)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.3.4 The realloc function

参阅


数值

< c

C 数值库包含常用数学函数和类型，还支持随机数生成。

常用数学函数

头文件 math.h 提供标准 C 库数学函数，例如 fabs 、 sqrt 和 sin 。

浮点环境

头文件 fenv.h 定义关系到异常浮点状态的标志和函数，例如溢出和除以零。

伪随机数生成

头文件 stdlib.h 亦包含经由 srand 和 rand 生成的 C 风格随机数。

复数算术

头文件 complex.h 提供关于复数的类型和函数。

泛型数学

头文件 tgmath.h 为函数提供某些名为 XXX 的宏：

  • 实函数：
  • float 变体 XXXf
  • double 变体 XXX
  • long double 变体 XXXl
  • 复函数：
  • float _Complex 变体 cXXXf
  • double _Complex 变体 cXXX
  • long double _Complex 变体 cXXXl

参阅


复数算术

< c‎ | numeric

若实现定义了宏常量 __STDC_NO_COMPLEX__ ，则不提供头文件 <complex.h> 、复数类型以及此处列出的所有名称。

 (C11 起)

C 编程语言从 C99 开始支持三种内建类型 double _Complex、 float _Complex 及 long double _Complex 的复数数学运算（见 _Complex ）。包含头文件 <complex.h> 时，三种复数类型亦可通过 double complex、 float complex、 long double complex 使用。

除了复数类型，还支持三种虚数类型： double _Imaginary、 float _Imaginary 及 long double _Imaginary （见 _Imaginary ）。包含头文件 <complex.h> 时，三种虚数类型亦可通过 double imaginary、 float imaginary 及 long double imaginary 使用。

标准算术运算符 +, -, *, / 可用于实数、复数及虚数类型的任意混合。

推荐编译器定义 __STDC_IEC_559_COMPLEX__ ，但并不强制要求其支持虚数。 POSIX 推荐检查是否定义宏 _Imaginary_I 以鉴别是否支持虚数。 | (C99 起) (C11 前)
若定义 __STDC_IEC_559_COMPLEX__ 或 __STDC_IEC_60559_COMPLEX__ (C23 起) ，则支持虚数。 | (C11 起)
定义于头文件 <complex.h>
类型
imaginary
(C99)
 虚数类型宏
(关键词宏)
complex
(C99)
 复数类型宏
(关键词宏)
虚数常量
_Imaginary_I
(C99)
 虚数单位常量 i
(宏常量)
_Complex_I
(C99)
 复数单位常量 i
(宏常量)
I
(C99)
 复数或虚数单位常量 i
(宏常量)
操作
CMPLXCMPLXFCMPLXL
(C11)(C11)(C11)
 由实部和虚部构建复数
(宏函数)
crealcrealfcreall
(C99)(C99)(C99)
 计算复数的实部
(函数)
cimagcimagfcimagl
(C99)(C99)(C99)
 计算复数的虚部
(函数)
cabscabsfcabsl
(C99)(C99)(C99)
 计算复数的模（绝对值）
(函数)
cargcargfcargl
(C99)(C99)(C99)
 计算复数的辐角
(函数)
conjconjfconjl
(C99)(C99)(C99)
 计算共轭复数
(函数)
cprojcprojfcprojl
(C99)(C99)(C99)
 计算黎曼球上的投影
(函数)
指数函数
cexpcexpfcexpl
(C99)(C99)(C99)
 计算复数的 e 底指数
(函数)
clogclogfclogl
(C99)(C99)(C99)
 计算复数的自然对数
(函数)
幂函数
cpowcpowfcpowl
(C99)(C99)(C99)
 计算复数幂函数
(函数)
csqrtcsqrtfcsqrtl
(C99)(C99)(C99)
 计算复数平方根
(函数)
三角函数
csincsinfcsinl
(C99)(C99)(C99)
 计算复数正弦
(函数)
ccosccosfccosl
(C99)(C99)(C99)
 计算复数余弦
(函数)
ctanctanfctanl
(C99)(C99)(C99)
 计算复数正切
(函数)
casincasinfcasinl
(C99)(C99)(C99)
 计算复数反正弦
(函数)
cacoscacosfcacosl
(C99)(C99)(C99)
 计算复数反余弦
(函数)
catancatanfcatanl
(C99)(C99)(C99)
 计算复数反正切
(函数)
双曲函数
csinhcsinhfcsinhl
(C99)(C99)(C99)
 计算复数双曲正弦
(函数)
ccoshccoshfccoshl
(C99)(C99)(C99)
 计算复双曲余弦
(函数)
ctanhctanhfctanhl
(C99)(C99)(C99)
 计算复数双曲正切
(函数)
casinhcasinhfcasinhl
(C99)(C99)(C99)
 计算复数反双曲正弦
(函数)
cacoshcacoshfcacoshl
(C99)(C99)(C99)
 计算复数反双曲余弦
(函数)
catanhcatanhfcatanhl
(C99)(C99)(C99)
 计算复数反双曲正切
(函数)

注解

下列函数名为 <complex.h> 的未来扩充而潜在 (C23 起)保留，并且在包含该头文件的程序中不可使用： cerf、 cerfc、 cexp2 、 cexpm1、 clog10、 clog1p、 clog2、 clgamma、 ctgamma、 csinpi、 ccospi、 ctanpi、 casinpi、 cacospi、 catanpi、 ccompoundn、 cpown、 cpowr、 crootn、 crsqrt、 cexp10m1、 cexp10、 cexp2m1、 clog10p1、 clog2p1、 clogp1 (C23 起) ，还有它们带 -f 及 -l 后缀的变体。

尽管 C 标准以“复弧双曲正弦（ complex arc hyperbolic sine ）”等名称指名反双曲函数，双曲函数的反函数却是面积函数。它们的参数是双曲扇形的面积，而非弧长。正确名称是“复反双曲正弦”等等。一些作者会使用“复面积双曲正弦（ complex area hyperbolic sine ）”等名称。

若组分的一部分是无穷大，则复数或虚数为无穷大，即使另一组分是 NaN 。

若双组分都不是无穷大或 NaN ，则复数或虚数是有限的。

若双组分皆为正零或负零，则复数或虚数为零。

示例

#include <stdio.h>
#include <complex.h>
#include <tgmath.h>

int main(void)
{
    double complex z1 = I * I;     // 虚数单位平方
    printf("I * I = %.1f%+.1fi\n", creal(z1), cimag(z1));

    double complex z2 = pow(I, 2); // 虚数单位平方
    printf("pow(I, 2) = %.1f%+.1fi\n", creal(z2), cimag(z2));

    double PI = acos(-1);
    double complex z3 = exp(I * PI); // 欧拉公式
    printf("exp(I*PI) = %.1f%+.1fi\n", creal(z3), cimag(z3));

    double complex z4 = 1+2*I, z5 = 1-2*I; // 共轭
    printf("(1+2i)*(1-2i) = %.1f%+.1fi\n", creal(z4*z5), cimag(z4*z5));
}

输出：

I * I = -1.0+0.0i
pow(I, 2) = -1.0+0.0i
exp(I*PI) = -1.0+0.0i
(1+2i)*(1-2i) = 5.0+0.0i

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.10.8.3/1/2 __STDC_NO_COMPLEX__ (p: 128)
  • 6.10.8.3/1/2 __STDC_IEC_559_COMPLEX__ (p: 128)
  • 7.3 Complex arithmetic <complex.h> (p: 136-144)
  • 7.25 Type-generic math <tgmath.h> (p: 272-273)
  • 7.31.1 Complex arithmetic <complex.h> (p: 391)
  • Annex G (normative) IEC 60559-compatible complex arithmetic (p: 469-479)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.10.8.3/1/2 __STDC_NO_COMPLEX__ (p: 177)
  • 6.10.8.3/1/2 __STDC_IEC_559_COMPLEX__ (p: 177)
  • 7.3 Complex arithmetic <complex.h> (p: 188-199)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • 7.31.1 Complex arithmetic <complex.h> (p: 455)
  • Annex G (normative) IEC 60559-compatible complex arithmetic (p: 532-545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.10.8/2 __STDC_IEC_559_COMPLEX__ (p: 161)
  • 7.3 Complex arithmetic <complex.h> (p: 170-180)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • 7.26.1 Complex arithmetic <complex.h> (p: 401)
  • Annex G (informative) IEC 60559-compatible complex arithmetic (p: 467-480)

参阅


CMPLXF, CMPLX, CMPLXL

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |
float complex CMPLXF( float real, float imag ); | (C11 起)
double complex CMPLX( double real, double imag ); | (C11 起)
long double complex CMPLXL( long double real, long double imag ); | (C11 起)

每个宏都展开成求值为指定复数类型值的表达式，其实部值为（转换到指定参数类型的） real ，其虚部值为（转换到指定参数类型的） imag 。

该表达式适合用作有静态或线程期间存储的对象的初始化器，只要表达式 real 和 imag 都同样适合。

参数

real | - | 待返回复数的实部
imag | - | 待返回复数的虚部

返回值

以 real 和 imag 为实部和虚部组合成的复数。

注意

这些宏被定义为如同支持虚数类型（即使实际上不支持，而且不定义 _Imaginary_I ），且如同定义如下：

#define CMPLX(x, y) ((double complex)((double)(x) + _Imaginary_I * (double)(y)))
#define CMPLXF(x, y) ((float complex)((float)(x) + _Imaginary_I * (float)(y)))
#define CMPLXL(x, y) ((long double complex)((long double)(x) + \
                      _Imaginary_I * (long double)(y)))

示例

#include <stdio.h>
#include <complex.h>

int main(void)
{
    double complex z = CMPLX(0.0, -0.0);
    printf("z = %.1f%+.1fi\n", creal(z), cimag(z));
}

输出：

z = 0.0-0.0i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.9.3 The CMPLX macros (p: 197)

参阅

_Imaginary_I
(C99)
 虚数单位常量 i
(宏常量)


_Complex_I

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |
#define _Complex_I /* unspecified */ | (C99 起)

_Complex_I 宏展开成类型 const float _Complex 的值，其值为虚数单位。

注意

可在 I 非法时，譬如程序已取消定义它时使用此宏。

不同于 _Imaginary_I 及 CMPLX 不同，用此宏构造复数会失去虚数组分的零的符号位。

示例

#include <stdio.h>
#include <complex.h>

#undef I
#define J _Complex_I // 可用于重定义 I

int main(void)
{
    // 可用于构建复数
    double complex z = 1.0 + 2.0 * _Complex_I;
    printf("1.0 + 2.0 * _Complex_I = %.1f%+.1fi\n", creal(z), cimag(z));

    // 零的符号不会被保留
    double complex z2 = 0.0 + -0.0 * _Complex_I;
    printf("0.0 + -0.0 * _Complex_I = %.1f%+.1fi\n", creal(z2), cimag(z2));
}

可能的输出：

1.0 + 2.0 * _Complex_I = 1.0+2.0i
0.0 + -0.0 * _Complex_I = 0.0+0.0i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.1/4 _Complex_I (p: 188)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.1/2 _Complex_I (p: 170)

参阅

_Imaginary_I (C99) | 虚数单位常量 i (宏常量)
I (C99) | 复数或虚数单位常量 i (宏常量)


I

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |
#define I /* unspecified */ | (C99 起)

I 宏展开成 _Complex_I 或 _Imaginary_I 。若实现不支持虚数类型，则该宏始终展开成 _Complex_I 。

一个程序可以取消定义，并能在紧随其后重定义宏 I 。

注意

该宏名字不是 i ，虽然这是数学上的虚数单位名称。因为 i 已经用于大量 C 程序中，例如作为循环变量。

宏 I 常用于组成复数，通过如 x + y*I 的表达式。 若 I 被定义成 _Complex_I ，则该表达式在 y 为 -0.0 时创建虚部为 +0.0 的值，这对拥有分支的复变函数有显著影响。宏 CMPLX 提供精确构造复数的方法。

GCC 提供了一种不可移植的扩展，它允许通过在实数字面量后指定后缀 i ： 1.0fi 、 1.0i 及 1.0li 是 GNU C 中的虚数单位。 C++14 起，类似的方式是标准 C++ 的一部分（ 1.0if 、 1.0i 及 1.0il 是 C++ 中的虚数单位）。

示例

#include <stdio.h>
#include <complex.h>

int main(void)
{
    printf("I = %.1f%+.1fi\n", creal(I), cimag(I));

    double complex z1 = I * I;     // 虚数单位平方
    printf("I * I = %.1f%+.1fi\n", creal(z1), cimag(z1));

    double complex z = 1.0 + 2.0*I; // 在 C11 前组成复数的通常途径
    printf("z = %.1f%+.1fi\n", creal(z), cimag(z));
}

输出：

I = 0.0+1.0i
I * I = -1.0+0.0i
z = 1.0+2.0i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.1/6 I (p: 188)
  • G.6/1 I (p: 537)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.1/4 I (p: 170)
  • G.6/1 I (p: 472)

参阅

_Imaginary_I (C99) | 虚数单位常量 i (宏常量)
_Complex_I (C99) | 复数单位常量 i (宏常量)
CMPLXCMPLXFCMPLXL (C11)(C11)(C11) | 由实部和虚部构建复数 (宏函数)


_Imaginary_I

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |
#define _Imaginary_I /* unspecified */ | (C99 起)

_Imaginary_I 宏展开成类型 const float _Imaginary 的值，其值为虚数单位。

同 C 中的纯虚数支持，仅若支持虚数才定义此宏。

推荐编译器定义 __STDC_IEC_559_COMPLEX__ ，但并不强制要求其支持虚数。 POSIX 推荐检查是否定义宏 _Imaginary_I 以鉴别是否支持虚数。 | (C99 起) (C11 前)
若定义 __STDC_IEC_559_COMPLEX__ ，则支持虚数。 | (C11 起)

注意

此宏允许从其实部和虚部精确地构成复数，例如用 (double complex )((double)x + _Imaginary_I * (double)y) 。此模式在 C11 中作为 CMPLX 标准化。注意若使用了 _Complex_I ，则允许此表达式在虚数位置将负零转变成正零。

示例

#include <stdio.h>
#include <complex.h>

int main(void)
{
    double complex z = 0.0 + -0.0 * _Imaginary_I;
    printf("z = %.1f%+.1fi\n", creal(z), cimag(z));
}

输出：

z = 0.0-0.0i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.1/5 _Imaginary_I (p: 188)
  • G.6/1 _Imaginary_I (p: 537)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.1/3 _Imaginary_I (p: 170)
  • G.6/1 _Imaginary_I (p: 472)

参阅

_Complex_I (C99) | 复数单位常量 i (宏常量)
I (C99) | 复数或虚数单位常量 i (宏常量)


cabsf, cabs, cabsl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float cabsf( float complex z ); | (1) | (C99 起)
double cabs( double complex z ); | (2) | (C99 起)
long double cabsl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define fabs( z ) | (4) | (C99 起)
1-3) 计算复数 z 的绝对值。
4) 泛型宏：若 z 拥有 long double complex 或 long double imaginary 类型，则调用 cabsl 。若 z 拥有 float complex 或 float imaginary 类型，则调用 cabsf 。若 z 拥有 double complex 或 double imaginary 类型，则调用 cabs 。对于实数和整数类型，调用对应版本的 fabs 。

参数

z - 复参数

返回值

若不出现错误，则返回 z 的绝对值（范数、模）。

如同函数实现为 hypot ( creal (z), cimag (z)) 一般处理错误和特殊情况。

示例

#include <stdio.h>
#include <complex.h>

int main(void)
{
    double complex z = 1.0 + 1.0*I;
    printf("%.1f%+.1fi cartesian is rho=%f theta=%f polar\n",
           creal(z), cimag(z), cabs(z), carg(z));
}

输出：

1.0+1.0i cartesian is rho=1.414214 theta=0.785398 polar

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.8.1 The cabs functions (p: 195)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.8.1 The cabs functions (p: 177)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

cargcargfcargl (C99)(C99)(C99) | 计算复数的辐角 (函数)
abslabsllabs (C99) | 计算整数值的绝对值（ \(\small{|x|}\)|x| ） (函数)
fabsfabsffabsl (C99)(C99) | 计算浮点值的绝对值（ \(\small{|x|}\)|x| ） (函数)
hypothypotfhypotl (C99)(C99)(C99) | 计算两个给定数平方和的平方根 （ \(\scriptsize{\sqrt{x^2+y^2} }\)√x2 +y2 ） (函数)


cacosf, cacos, cacosl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex cacosf( float complex z ); | (1) | (C99 起)
double complex cacos( double complex z ); | (2) | (C99 起)
long double complex cacosl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define acos( z ) | (4) | (C99 起)
1-3) 计算 z 的复弧（反）余弦，分支切割在沿实轴的区间 [−1,+1] 外。
4) 泛型宏：若 z 拥有 long double complex 类型，则调用 cacosl 。若 z 拥有 double complex 类型，则调用 cacos ，若 z 拥有 float complex 类型，则调用 cacosf 。若 z 为实数或整数，则宏调用对应的实数函数（ acosf 、 acos 、 acosl ）。若 z 为虚数，则宏调用对应的复数版本。

参数

z - 复参数

返回值

若不出现错误，则返回 z 的复弧（反）余弦，于沿实轴的范围 [0 ; ∞) 且于沿虚轴的范围 [−iπ ; iπ] 中。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • cacos( conj (z)) == conj (cacos(z))
  • 若 z 为 ±0+0i ，则结果为 π/2-0i
  • 若 z 为 ±0+NaNi ，则结果为 π/2+NaNi
  • 若 z 为 x+∞i （对于任何有限 x ），则结果为 π/2-∞i
  • 若 z 为 x+NaNi （对于任何有限非零 x ），则结果为 NaN+NaNi 并可能引发 FE_INVALID 。
  • 若 z 为 -∞+yi （对于任何有限正 y ），则结果为 π-∞i
  • 若 z 为 +∞+yi （对于任何有限正 y ），则结果为 +0-∞i
  • 若 z 为 -∞+∞i ，则结果为 3π/4-∞i
  • 若 z 为 +∞+∞i ，则结果为 π/4-∞i
  • 若 z 为 ±∞+NaNi ，则结果为 NaN±∞i （虚部符号未指定）
  • 若 z 为 NaN+yi （对于任何有限 y ），则结果为 NaN+NaNi 并可能引发 FE_INVALID
  • 若 z 为 NaN+∞i ，则结果为 NaN-∞i
  • 若 z 为 NaN+NaNi ，则结果为 NaN+NaNi

注解

反余弦（或弧余弦）是多值函数，要求复平面上的分支切割。约定将分支切割置于实轴的线段 (-∞,-1) 和 (1,∞) 上。

弧（反）余弦主值的数学定义是 acos z =
1
2
π + iln(iz + √1-z2
) 。

对于任何 z ， acos(z) = π - acos(-z) 。

示例

#include <stdio.h>
#include <math.h>
#include <complex.h>

int main(void)
{
    double complex z = cacos(-2);
    printf("cacos(-2+0i) = %f%+fi\n", creal(z), cimag(z));

    double complex z2 = cacos(conj(-2)); // 或 CMPLX(-2, -0.0)
    printf("cacos(-2-0i) (the other side of the cut) = %f%+fi\n", creal(z2), cimag(z2));

    // 对于任何 z ， acos(z) = pi - acos(-z)
    double pi = acos(-1);
    double complex z3 = ccos(pi-z2);
    printf("ccos(pi - cacos(-2-0i) = %f%+fi\n", creal(z3), cimag(z3));
}

输出：

cacos(-2+0i) = 3.141593-1.316958i
cacos(-2-0i) (the other side of the cut) = 3.141593+1.316958i
ccos(pi - cacos(-2-0i) = 2.000000+0.000000i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.5.1 The cacos functions (p: 190)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.6.1.1 The cacos functions (p: 539)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.5.1 The cacos functions (p: 172)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.6.1.1 The cacos functions (p: 474)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

casincasinfcasinl (C99)(C99)(C99) | 计算复数反正弦 (函数)
catancatanfcatanl (C99)(C99)(C99) | 计算复数反正切 (函数)
ccosccosfccosl (C99)(C99)(C99) | 计算复数余弦 (函数)
acosacosfacosl (C99)(C99) | 计算反余弦（ \({\small\arccos{x} }\)arccos(x) ） (函数)


cacoshf, cacosh, cacoshl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex cacoshf( float complex z ); | (1) | (C99 起)
double complex cacosh( double complex z ); | (2) | (C99 起)
long double complex cacoshl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define acosh( z ) | (4) | (C99 起)
1-3) 计算复数值 z 的复反双曲余弦，分支切割在沿实轴小于 1 的值上。
4) 泛型宏：若 z 拥有 long double complex 类型，则调用 cacoshl 。若 z 拥有 double complex 类型，则调用 cacosh 。若 z 拥有 float complex 类型，则调用 cacoshf 。若 z 为实数或整数，则宏调用对应的实函数（ acoshf 、 acosh 、 acoshl ）。若 z 为虚数，则宏调用对应的复数版本，而返回类型为复数。

参数

z - 复参数

返回值

z 的复反双曲余弦，沿实轴在区间 [0; ∞) 中，而沿虚轴在区间 [−iπ; +iπ] 中。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • cacosh( conj (z)) == conj (cacosh(z))
  • 若 z 为 ±0+0i ，则结果为 +0+iπ/2
  • 若 z 为 +x+∞i （对于任何有限 x ），则结果为 +∞+iπ/2
  • 若 z 为 +x+NaNi （对于任何非零有限 x ），结果为 NaN+NaNi 并可能引发 FE_INVALID
  • 若 z 为 0+NaNi ，则结果为 NaN±iπ/2 ，其中虚部符号未指定
  • 若 z 为 -∞+yi （对于任何有限正 y ），则结果为 +∞+iπ
  • 若 z 为 +∞+yi （对于任何有限正 y ），则结果为 +∞+0i
  • 若 z 为 -∞+∞i ，则结果为 +∞+3iπ/4
  • 若 z 为 ±∞+NaNi ，则结果为 +∞+NaNi
  • 若 z 为 NaN+yi （对于任何有限 y ），则结果为 NaN+NaNi 并可能引发 FE_INVALID 。
  • 若 z 为 NaN+∞i ，则结果为 +∞+NaNi
  • 若 z 为 NaN+NaNi ，则结果为 NaN+NaNi

注意

尽管 C 标准命名此函数为“复弧双曲余弦”，双曲函数的反函数是面积函数。其参数为双曲扇形的面积，而非弧长。正确名称是“复反双曲余弦”，和更少见的“复面积双曲余弦”。

反双曲余弦是多值函数，在复平面上要求分支切割。约定将分支切割置于实轴的线段 (-∞,+1) 上。

复反双曲余弦主值的数学定义是 acosh z = ln(z + √z+1 √z-1) 。

对于任何 z ， acosh(z) =
√z-1
√1-z
acos(z) ，或在复平面上半部简单地为 i acos(z) 。

示例

#include <stdio.h>
#include <complex.h>

int main(void)
{
    double complex z = cacosh(0.5);
    printf("cacosh(+0.5+0i) = %f%+fi\n", creal(z), cimag(z));

    double complex z2 = conj(0.5); // 或 C11 中的 cacosh(CMPLX(0.5, -0.0))
    printf("cacosh(+0.5-0i) (the other side of the cut) = %f%+fi\n", creal(z2), cimag(z2));

    // 在上半平面， acosh(z) = i*acos(z)
    double complex z3 = casinh(1+I);
    printf("casinh(1+1i) = %f%+fi\n", creal(z3), cimag(z3));
    double complex z4 = I*casin(1+I);
    printf("I*asin(1+1i) = %f%+fi\n", creal(z4), cimag(z4));
}

输出：

cacosh(+0.5+0i) = 0.000000-1.047198i
cacosh(+0.5-0i) (the other side of the cut) = 0.500000-0.000000i
casinh(1+1i) = 1.061275+0.666239i
I*asin(1+1i) = -1.061275+0.666239i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.6.1 The cacosh functions (p: 192)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.6.2.1 The cacosh functions (p: 539-540)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.6.1 The cacosh functions (p: 174)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.6.2.1 The cacosh functions (p: 474-475)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

cacoscacosfcacosl (C99)(C99)(C99) | 计算复数反余弦 (函数)
casinhcasinhfcasinhl (C99)(C99)(C99) | 计算复数反双曲正弦 (函数)
catanhcatanhfcatanhl (C99)(C99)(C99) | 计算复数反双曲正切 (函数)
ccoshccoshfccoshl (C99)(C99)(C99) | 计算复双曲余弦 (函数)
acoshacoshfacoshl (C99)(C99)(C99) | 计算反双曲余弦（ \({\small\operatorname{arcosh}{x} }\)arcosh(x) ） (函数)


cargf, carg, cargl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float cargf( float complex z ); | (1) | (C99 起)
double carg( double complex z ); | (2) | (C99 起)
long double cargl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define carg( z ) | (4) | (C99 起)
1-3) 计算 z 的辐角（又称相位角），分支切割沿负实轴。
4) 泛型宏：若 z 拥有 long double complex 、 long double imaginary 或 long double 类型，则调用 cargl 。若 z 拥有 float complex 、 float imaginary 或 float 类型，则调用 cargf 。若 z 拥有 double complex 、 double imaginary 、 double 或任何整数类型，则调用 carg 。

参数

z - 复参数

返回值

若不出现错误，则返回 z 在 [−π; π] 区间中的相位角。

如同函数实现为 atan2 ( cimag (z), creal (z)) 一般处理错误和特殊情况。

示例

#include <stdio.h>
#include <complex.h>

int main(void)
{
    double complex z1 = 1.0+0.0*I;
    printf("phase angle of %.1f%+.1fi is %f\n", creal(z1), cimag(z1), carg(z1));

    double complex z2 = 0.0+1.0*I;
    printf("phase angle of %.1f%+.1fi is %f\n", creal(z2), cimag(z2), carg(z2));

    double complex z3 = -1.0+0.0*I;
    printf("phase angle of %.1f%+.1fi is %f\n", creal(z3), cimag(z3), carg(z3));

    double complex z4 = conj(z3); // 或 CMPLX(-1, -0.0)
    printf("phase angle of %.1f%+.1fi (the other side of the cut) is %f\n",
             creal(z4), cimag(z4), carg(z4));
}

输出：

phase angle of 1.0+0.0i is 0.000000
phase angle of 0.0+1.0i is 1.570796
phase angle of -1.0+0.0i is 3.141593
phase angle of -1.0-0.0i (the other side of the cut) is -3.141593

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.9.1 The carg functions (p: 196)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.9.1 The carg functions (p: 178)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

cabscabsfcabsl (C99)(C99)(C99) | 计算复数的模（绝对值） (函数)
atan2atan2fatan2l (C99)(C99) | 计算反正切，以符号确定象限 (函数)


casinf, casin, casinl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex casinf( float complex z ); | (1) | (C99 起)
double complex casin( double complex z ); | (2) | (C99 起)
long double complex casinl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define asin( z ) | (4) | (C99 起)
1-3) 计算 z 的复弧（反）正弦，分支切割在沿实轴的 [−1,+1] 区间外。
4) 泛型宏：若 z 拥有 long double complex 类型，则调用 casinl 若 z 拥有 double complex 类型，则调用 casin ，若 z 拥有 float complex 类型，则调用 casinf 。若 z 为实数或整数，则宏调用对应的实数函数（ asinf 、 asin 、 asinl ）。若 z 为虚数，则宏调用函数 asinh 的对应实数版本，实现公式 asin(iy) = i asinh(y) ，而宏的返回类型为虚数。

参数

z - 复参数

返回值

若不出现错误，则返回 z 的复弧正弦，在沿虚轴无界，沿实轴在区间 [−π/2; +π/2] 中的条状范围中。

如同运算以 -I * casinh (I*z) 实现一般处理错误和特殊情况。

注意

反正弦（或弧正弦）是多值函数，且在复平面上要求分支切割。约定将分支切割置于实轴上的线段 (-∞,-1) 和 (1,∞) 上。

弧（反）正弦主值的数学定义是 asin z = -iln(iz + √1-z2
) 。

对于任何 z ， asin(z) = acos(-z) -
π
2
。

示例

#include <stdio.h>
#include <math.h>
#include <complex.h>

int main(void)
{
    double complex z = casin(-2);
    printf("casin(-2+0i) = %f%+fi\n", creal(z), cimag(z));

    double complex z2 = casin(conj(-2)); // 或 CMPLX(-2, -0.0)
    printf("casin(-2-0i) (the other side of the cut) = %f%+fi\n", creal(z2), cimag(z2));

    // 对于任何 z ， asin(z) = acos(-z) - pi/2
    double pi = acos(-1);
    double complex z3 = csin(cacos(conj(-2))-pi/2);
    printf("csin(cacos(-2-0i)-pi/2) = %f%+fi\n", creal(z3), cimag(z3));
}

输出：

casin(-2+0i) = -1.570796+1.316958i
casin(-2-0i) (the other side of the cut) = -1.570796-1.316958i
csin(cacos(-2-0i)-pi/2) = 2.000000+0.000000i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.5.2 The casin functions (p: 190)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.5.2 The casin functions (p: 172)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

cacoscacosfcacosl (C99)(C99)(C99) | 计算复数反余弦 (函数)
catancatanfcatanl (C99)(C99)(C99) | 计算复数反正切 (函数)
csincsinfcsinl (C99)(C99)(C99) | 计算复数正弦 (函数)
asinasinfasinl (C99)(C99) | 计算反正弦（ \({\small\arcsin{x} }\)arcsin(x) ） (函数)


casinhf, casinh, casinhl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex casinhf( float complex z ); | (1) | (C99 起)
double complex casinh( double complex z ); | (2) | (C99 起)
long double complex casinhl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define asinh( z ) | (4) | (C99 起)
1-3) 计算 z 的复反双曲正弦，分支切割在沿虚轴的 [−i; +i] 区间外。
4) 泛型宏：若 z 拥有类型 long double complex ，则调用 casinhl 。若 z 拥有类型 double complex ，则调用 casinh ，若 z 拥有类型 float complex ，则调用 casinhf 。若 z 为实数或整数，则宏调用对应的实数函数（ asinhf 、 asinh 、 asinhl ）。若 z 为虚数，则宏调用函数 asin 的对应实数版本，实现公式 asinh(iy) = i asin(y) ，而返回类型为虚数。

参数

z - 复参数

返回值

若不出现错误，则返回 z 的复反双曲正弦，在沿实轴数学上无界，沿虚轴在区间 [−iπ/2; +iπ/2] 中的条状范围中。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • casinh( conj (z)) == conj (casinh(z))
  • casinh(-z) == -casinh(z)
  • 若 z 为 +0+0i ，则结果为 +0+0i
  • 若 z 为 x+∞i （对于任何有限正 x ），则结果为 +∞+π/2
  • 若 z 为 x+NaNi （对于任何有限 x ），则结果为 NaN+NaNi 并可能引发 FE_INVALID
  • 若 z 为 +∞+yi （对于任何有限正 y ），结果为 +∞+0i
  • 若 z 为 +∞+∞i ，则结果为 +∞+iπ/4
  • 若 z 为 +∞+NaNi ，则结果为 +∞+NaNi
  • 若 z 为 NaN+0i ，则结果为 NaN+0i
  • 若 z 为 NaN+yi （对于任何有限非零 y ），则结果为 NaN+NaNi 并可能引发 FE_INVALID
  • 若 z 为 NaN+∞i ，则结果为 ±∞+NaNi （实部符号未指定）
  • 若 z 为 NaN+NaNi ，则结果为 NaN+NaNi

注意

尽管 C 标准命名此函数为“复弧双曲正弦”函数，双曲函数的反函数仍是面积函数。其参数是双曲扇形的面积，而非弧长。正确的名称是“复反双曲正弦”或较不常用的“复面积双曲正弦”。

反双曲正弦是多值函数，而在复平面上要求分支切割。约定将分支置于虚轴的线段 (-i∞,-i) 和 (i,i∞) 上。

反双曲正弦主值的数学定义是 asinh z = ln(z + √1+z2
) 。

对于任何 z ， asinh(z) =
asin(iz)
i
。

示例

#include <stdio.h>
#include <complex.h>

int main(void)
{
    double complex z = casinh(0+2*I);
    printf("casinh(+0+2i) = %f%+fi\n", creal(z), cimag(z));

    double complex z2 = casinh(-conj(2*I)); // 或 C11 中的 casinh(CMPLX(-0.0, 2))
    printf("casinh(-0+2i) (the other side of the cut) = %f%+fi\n", creal(z2), cimag(z2));

    // 对于任何 z ， asinh(z) = asin(iz)/i
    double complex z3 = casinh(1+2*I);
    printf("casinh(1+2i) = %f%+fi\n", creal(z3), cimag(z3));
    double complex z4 = casin((1+2*I)*I)/I;
    printf("casin(i * (1+2i))/i = %f%+fi\n", creal(z4), cimag(z4));
}

输出：

casinh(+0+2i) = 1.316958+1.570796i
casinh(-0+2i) (the other side of the cut) = -1.316958+1.570796i
casinh(1+2i) = 1.469352+1.063440i
casin(i * (1+2i))/i =  1.469352+1.063440i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.6.2 The casinh functions (p: 192-193)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.6.2.2 The casinh functions (p: 540)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.6.2 The casinh functions (p: 174-175)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.6.2.2 The casinh functions (p: 475)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

cacoshcacoshfcacoshl (C99)(C99)(C99) | 计算复数反双曲余弦 (函数)
catanhcatanhfcatanhl (C99)(C99)(C99) | 计算复数反双曲正切 (函数)
csinhcsinhfcsinhl (C99)(C99)(C99) | 计算复数双曲正弦 (函数)
asinhasinhfasinhl (C99)(C99)(C99) | 计算反双曲正弦（ \({\small\operatorname{arsinh}{x} }\)arsinh(x) ） (函数)


catanf, catan, catanl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex catanf( float complex z ); | (1) | (C99 起)
double complex catan( double complex z ); | (2) | (C99 起)
long double complex catanl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define atan( z ) | (4) | (C99 起)
1-3) 计算 z 的复弧（反）正切，分支切割在沿虚轴的 [−i,+i] 区间外。
4) 泛型宏：若 z 拥有 long double complex 类型，则调用 catanl 。若 z 拥有 double complex 类型，则调用 catan 。若 z 拥有 float complex 类型，则调用 catanf 。若 z 为实数或整数，则宏调用对应的实数函数（ atanf 、 atan 、 atanl ）。若 z 为虚数，则宏调用函数 atanh 的对应实数版本，实现公式 atan(iy) = i atanh(y) ，而宏的返回类型为虚数。

参数

z - 复参数

返回值

若不发生错误，则返回 z 的复弧（反）正切，在沿虚轴无界，沿实轴在区间 [−π/2; +π/2] 内的条状范围中。

按照如同以 -I * catanh (I*z) 实现运算一般处理错误和特殊情况。

注意

反正切（或弧正切）是多值函数而要求复平面上的分支切割。约定分支切割置于虚轴的线段 (-∞i,-i) 和 (+i,+∞i) 上。

反正切主值的数学定义是 atan z = -
1
2
i [ln(1 - iz) - ln (1 + iz] 。

示例

#include <stdio.h>
#include <float.h>
#include <complex.h>

int main(void)
{
    double complex z = catan(2*I);
    printf("catan(+0+2i) = %f%+fi\n", creal(z), cimag(z));

    double complex z2 = catan(-conj(2*I)); // 或 CMPLX(-0.0, 2)
    printf("catan(-0+2i) (the other side of the cut) = %f%+fi\n", creal(z2), cimag(z2));

    double complex z3 = 2*catan(2*I*DBL_MAX); // 或 CMPLX(0, INFINITY)
    printf("2*catan(+0+i*Inf) = %f%+fi\n", creal(z3), cimag(z3));
}

输出：

catan(+0+2i) = 1.570796+0.549306i
catan(-0+2i) (the other side of the cut) = -1.570796+0.549306i
2*catan(+0+i*Inf) = 3.141593+0.000000i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.5.3 The catan functions (p: 191)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.5.3 The catan functions (p: 173)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

casincasinfcasinl (C99)(C99)(C99) | 计算复数反正弦 (函数)
cacoscacosfcacosl (C99)(C99)(C99) | 计算复数反余弦 (函数)
ctanctanfctanl (C99)(C99)(C99) | 计算复数正切 (函数)
atanatanfatanl (C99)(C99) | 计算反正切（ \({\small\arctan{x} }\)arctan(x) ） (函数)


catanhf, catanh, catanhl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex catanhf( float complex z ); | (1) | (C99 起)
double complex catanh( double complex z ); | (2) | (C99 起)
long double complex catanhl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define atanh( z ) | (4) | (C99 起)
1-3) 计算 z 的复反双曲正切，其分支切割为沿实轴的 [−1; +1] 区间外部。
4) 泛型宏：若 z 拥有 long double complex 类型，则调用 catanhl 。若 z 拥有 double complex 类型，则调用 catanh ，若 z 拥有 float complex 类型，则调用 catanhf 。若 z 为实数或整数，则该宏调用对应的实函数（ atanhf 、 atanh 、 atanhl ）。若为虚数 z ，则该宏调用 atan 的对应实数版本，实现等式 atanh(iy) = i atan(y) ，而返回类型是虚数。

参数

z - 复参数

返回值

若不发生错误，则返回 z 的复反双曲正切，范围在数学上为沿着实轴无界的半条，沿着虚轴为区间 [−iπ/2; +iπ/2] 。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • catanh( conj (z)) == conj (catanh(z))
  • catanh(-z) == -catanh(z)
  • 若 z 为 +0+0i ，则结果为 +0+0i
  • 若 z 为 +0+NaNi ，则结果为 +0+NaNi
  • 若 z 为 +1+0i ，则结果为 +∞+0i 并引发 FE_DIVBYZERO
  • 若 z 为 x+∞i （对于任何有限正 x ） ，则结果为 +0+iπ/2
  • 若 z 为 x+NaNi （对于任何有限非零的 x ），则结果为 NaN+NaNi 并可能引发 FE_INVALID
  • 若 z 为 +∞+yi （对于任何有限的 y ），则结果为 +0+iπ/2
  • 若 z 为 +∞+∞i ，则结果为 +0+iπ/2
  • 若 z 为 +∞+NaNi, the result is +0+NaNi
  • 若 z 为 NaN+yi （对于任何有限的 y ），则结果为 NaN+NaNi 并可能引发 FE_INVALID
  • 若 z 为 NaN+∞i ，则结果为 ±0+iπ/2 （实部的符号未指定）
  • 若 z 为 NaN+NaNi ，则结果为 NaN+NaNi

注意

尽管 C 标准命名此函数为“复弧双曲正切”，双曲函数的反函数却是面积函数。其参数是双曲扇形的面积，而非弧长。正确的名称是“复反双曲正切”，和较少见的“复面积双曲正切”。

反双曲正切是多值函数，并要求复平面上的分支切割。我们约定将分支切割置于实轴的划分线 (-∞,-1] 和 [+1,+∞) 。

反双曲正切的主值的数学定义是 atanh z =
ln(1+z)-ln(z-1)
2
。

对于任何 z ， atanh(z) =
atan(iz)
i
。

示例

#include <stdio.h>
#include <complex.h>

int main(void)
{
    double complex z = catanh(2);
    printf("catanh(+2+0i) = %f%+fi\n", creal(z), cimag(z));

    double complex z2 = catanh(conj(2)); // 或 C11 中的 catanh(CMPLX(2, -0.0))
    printf("catanh(+2-0i) (the other side of the cut) = %f%+fi\n", creal(z2), cimag(z2));

    // 对于任何 z ， atanh(z) = atan(iz)/i
    double complex z3 = catanh(1+2*I);
    printf("catanh(1+2i) = %f%+fi\n", creal(z3), cimag(z3));
    double complex z4 = catan((1+2*I)*I)/I;
    printf("catan(i * (1+2i))/i = %f%+fi\n", creal(z4), cimag(z4));
}

输出：

catanh(+2+0i) = 0.549306+1.570796i
catanh(+2-0i) (the other side of the cut) = 0.549306-1.570796i
catanh(1+2i) = 0.173287+1.178097i
catan(i * (1+2i))/i = 0.173287+1.178097i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.6.3 The catanh functions (p: 193)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.6.2.3 The catanh functions (p: 540-541)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.6.3 The catanh functions (p: 175)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.6.2.3 The catanh functions (p: 475-476)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

casinhcasinhfcasinhl (C99)(C99)(C99) | 计算复数反双曲正弦 (函数)
cacoshcacoshfcacoshl (C99)(C99)(C99) | 计算复数反双曲余弦 (函数)
ctanhctanhfctanhl (C99)(C99)(C99) | 计算复数双曲正切 (函数)
atanhatanhfatanhl (C99)(C99)(C99) | 计算反双曲正切（ \({\small\operatorname{artanh}{x} }\)artanh(x) ） (函数)


ccosf, ccos, ccosl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex ccosf( float complex z ); | (1) | (C99 起)
double complex ccos( double complex z ); | (2) | (C99 起)
long double complex ccosl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define cos( z ) | (4) | (C99 起)
1-3) 计算 z 的复余弦。
4) 泛型宏：若 z拥有 long double complex 类型，则调用 ccosl ，若 z 拥有 double complex 类型，则调用 ccos ，若 z 拥有 float complex 类型，则调用 ccosf 。若 z 为实数或整数，则此宏调用对应的实函数（ cosf 、 cos 、 cosl ）。若 z 是虚数，则此宏调用对应版本的 cosh 函数，实现公式 cos(iy) = cosh(y) ，而返回类型是实数。

参数

z - 复参数

返回值

若无错误发生，则返回 z 的复余弦。

错误和特殊情况如同操作以 ccosh (I*z) 实现一般。

注意

余弦在复平面上是整函数，而且无分支切割。

余弦的数学定义是 cos z =
eiz
+e-iz
2
。

示例

#include <stdio.h>
#include <math.h>
#include <complex.h>

int main(void)
{
    double complex z = ccos(1);  // 表现如同沿着实轴的实余弦
    printf("cos(1+0i) = %f%+fi ( cos(1)=%f)\n", creal(z), cimag(z), cos(1));

    double complex z2 = ccos(I); // 表现如同沿着虚轴的实 cosh
    printf("cos(0+1i) = %f%+fi (cosh(1)=%f)\n", creal(z2), cimag(z2), cosh(1));
}

输出：

cos(1+0i) = 0.540302-0.000000i ( cos(1)=0.540302)
cos(0+1i) = 1.543081-0.000000i (cosh(1)=1.543081)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.5.4 The ccos functions (p: 191)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.5.4 The ccos functions (p: 173)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

csincsinfcsinl (C99)(C99)(C99) | 计算复数正弦 (函数)
ctanctanfctanl (C99)(C99)(C99) | 计算复数正切 (函数)
cacoscacosfcacosl (C99)(C99)(C99) | 计算复数反余弦 (函数)
coscosfcosl (C99)(C99) | 计算余弦（ \({\small\cos{x} }\)cos(x) ） (函数)


ccoshf, ccosh, ccoshl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex ccoshf( float complex z ); | (1) | (C99 起)
double complex ccosh( double complex z ); | (2) | (C99 起)
long double complex ccoshl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define cosh( z ) | (4) | (C99 起)
1-3) 计算 z 的复双曲余弦。
4) 泛型宏：若 z 拥有 long double complex 类型，则调用 ccoshl 。若 z 拥有 double complex 类型，则调用 ccosh 。若 z 拥有 float complex 类型，则调用 ccoshf 。若 z 为实数或整数，则宏调用对应的实数函数（ coshf 、 cosh 、 coshl ）。若 z 为虚数，则宏调用函数 cos 的对应实数版本，实现公式 cosh(iy) = cos(y) ，而返回类型为实数。

参数

z - 复参数

返回值

若不发生错误，则返回 z 的复双曲余弦。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则，

  • ccosh( conj (z)) == conj (ccosh(z))
  • ccosh(z) == ccosh(-z)
  • 若 z 为 +0+0i ，则结果为 1+0i
  • 若 z 为 +0+∞i ，则结果为 NaN±0i （虚部符号未指定）并引发 FE_INVALID
  • 若 z 为 +0+NaNi ，则结果为 NaN±0i （虚部符号未指定）
  • 若 z 为 x+∞i （对于任何有限非零 x ），则结果为 NaN+NaNi 并引发 FE_INVALID
  • 若 z 为 x+NaNi （对于任何有限非零 x ），则结果为 NaN+NaNi 并可能引发 FE_INVALID
  • 若 z 为 +∞+0i, 则结果为 +∞+0i
  • 若 z 为 +∞+yi （对于任何有限非零 y ），则结果为 +∞cis(y)
  • 若 z 为 +∞+∞i, 则结果为 ±∞+NaNi （实部符号未指定）并引发 FE_INVALID
  • 若 z 为 +∞+NaN, 则结果为 +∞+NaN
  • 若 z 为 NaN+0i, 则结果为 NaN±0i （虚部符号未指定）
  • 若 z 为 NaN+yi （对于任何有限非零 y ），则结果为 NaN+NaNi 并可能引发 FE_INVALID
  • 若 z 为 NaN+NaNi ，则结果为 NaN+NaNi

其中 cis(y) 为 cos(y) + i sin(y) 。

注意

双曲余弦的数学定义是 cosh z =
ez
+e-z
2
。

双曲余弦在复平面上是整函数，而无分支切割。它相对于虚部是周期的，周期为 2πi 。

示例

#include <stdio.h>
#include <math.h>
#include <complex.h>

int main(void)
{
    double complex z = ccosh(1);  // 表现如沿实轴的 cosh
    printf("cosh(1+0i) = %f%+fi (cosh(1)=%f)\n", creal(z), cimag(z), cosh(1));

    double complex z2 = ccosh(I); // 表现如沿虚轴的实余弦
    printf("cosh(0+1i) = %f%+fi ( cos(1)=%f)\n", creal(z2), cimag(z2), cos(1));
}

输出：

cosh(1+0i) = 1.543081+0.000000i (cosh(1)=1.543081)
cosh(0+1i) = 0.540302+0.000000i ( cos(1)=0.540302)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.6.4 The ccosh functions (p: 193)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.6.2.4 The ccosh functions (p: 541)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.6.4 The ccosh functions (p: 175)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.6.2.4 The ccosh functions (p: 476)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

csinhcsinhfcsinhl (C99)(C99)(C99) | 计算复数双曲正弦 (函数)
ctanhctanhfctanhl (C99)(C99)(C99) | 计算复数双曲正切 (函数)
cacoshcacoshfcacoshl (C99)(C99)(C99) | 计算复数反双曲余弦 (函数)
coshcoshfcoshl (C99)(C99) | 计算双曲余弦（ \({\small\cosh{x} }\)cosh(x) ） (函数)


cexpf, cexp, cexpl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex cexpf( float complex z ); | (1) | (C99 起)
double complex cexp( double complex z ); | (2) | (C99 起)
long double complex cexpl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define exp( z ) | (4) | (C99 起)
1-3) 计算复数的 z 的底 e 指数。
4) 泛型宏：若 z 拥有 long double complex 类型，则调用 cexpl ，若 z 拥有 double complex 类型，则调用 cexp ，若 z 拥有 float complex 类型，则调用 cexpf 。若 z 是实浮点数或整数，则该宏调用对应的实函数（ expf 、 exp 、 expl ）。若 z 是虚数，则调用对应的复参数版本。

参数

z - 复参数

返回值

若不出现错误，则返回 e 的 z 次幂， ez
 。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持IEEE浮点算术，则

  • cexp( conj (z)) == conj (cexp(z))
  • 若 z 为 ±0+0i ，则结果是1+0i；
  • 若 z 为 x+∞i （对于任何有限 x），则结果是 NaN+NaNi并引发 FE_INVALID ；
  • 若 z 为 x+NaNi （对于任何有限 x），则结果是 NaN+NaNi 并可能引发 FE_INVALID ；
  • 若 z 为 +∞+0i ，则结果是+∞+0i；
  • 若 z 为 -∞+yi （对任何有限 y），则结果是 +0cis(y) ；
  • 若 z 为 +∞+yi （对于任何有限非零 y），则结果是 +∞cis(y) ；
  • 若 z 为 -∞+∞i ，则结果是 ±0±0i （符号未指定）
  • 若 z 为 +∞+∞i ，则结果是 ±∞+NaNi 并引发 FE_INVALID （实部符号未指定）；
  • 若 z 为 -∞+NaNi ，则结果是 ±0±0i （符号未指定）；
  • 若 z 为 +∞+NaNi ，则结果是 ±∞+NaNi （实部符号未指定）；
  • 若 z 为 NaN+0i ，则结果是 NaN+0i ；
  • 若 z 为 NaN+yi （对于任意非零 y ），则结果是 NaN+NaNi 并可能引发 FE_INVALID ；
  • 若 z 为 NaN+NaNi ，则结果是 NaN+NaNi ；

其中 cis(y) 为 cos(y) + i sin(y) 。

注意

复指数函数 ez
 对于自变量 z = x+iy 的值等于 ex
 cis(y) ，或 ex
 (cos(y) + i sin(y)) 。

指数函数在复平面上是整函数且无分支切割。

示例

#include <stdio.h>
#include <math.h>
#include <complex.h>

int main(void)
{
    double PI = acos(-1);
    double complex z = cexp(I * PI); // 欧拉公式
    printf("exp(i*pi) = %.1f%+.1fi\n", creal(z), cimag(z));

}

输出：

exp(i*pi) = -1.0+0.0i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.7.1 The cexp functions (p: 194)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.6.3.1 The cexp functions (p: 543)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.7.1 The cexp functions (p: 176)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.6.3.1 The cexp functions (p: 478)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

clogclogfclogl (C99)(C99)(C99) | 计算复数的自然对数 (函数)
expexpfexpl (C99)(C99) | 计算 e 的给定次幂 （ \({\small e^x}\)ex ） (函数)


cimagf, cimag, cimagl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float cimagf( float complex z ); | (1) | (C99 起)
double cimag( double complex z ); | (2) | (C99 起)
long double cimagl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define cimag( z ) | (4) | (C99 起)
1-3) 返回 z 的虚部。
4) 泛型宏：若 z 拥有 long double complex 、 long double imaginary 或 long double 类型，则调用 cimagl 。若 z 拥有 float complex 、 float imaginary 或 float 类型，则调用 cimagf 。若 z 拥有 double complex 、 double imaginary 、 double 或任何整数类型，则调用 cimag 。

参数

z - 复参数

返回值

z 的虚部。

此函数对所有可行输入完全指明，而且不受制于任何描述于 math_errhandling 的错误。

注意

对于任何复数变量 z ， z == creal (z) + I*cimag(z) 。

示例

#include <stdio.h>
#include <complex.h>

int main(void)
{
    double complex z = 1.0 + 2.0*I;
    printf("%f%+fi\n", creal(z), cimag(z));
}

输出：

1.000000+2.000000i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.9.2 The cimag functions (p: 197)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.9.2 The cimag functions (p: 178-179)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

crealcrealfcreall
(C99)(C99)(C99)
 计算复数的实部
(函数)


clogf, clog, clogl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex clogf( float complex z ); | (1) | (C99 起)
double complex clog( double complex z ); | (2) | (C99 起)
long double complex clogl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define log( z ) | (4) | (C99 起)
1-3) 计算 z 的复自然（底 e ）对数，分支切割沿负实轴。
4) 泛型宏：若 z 拥有 long double complex 类型，则调用 clogl ，若 z 拥有 double complex 类型，则调用 clog ，若 z 拥有 float complex 类型，则调用 clogf 。若 z 为实数或整数，则该宏调用对应的实数函数（ logf 、 log 、 logl ）。若 z 为虚数，则调用对应的复数版本。

参数

z - 复参数

返回值

若不发生错误，则返回 z 的复自然对数，在沿虚轴为区间 [−iπ, +iπ] ，沿实轴为数学上无界的条状范围中。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • 考虑虚部符号，函数连续到分支切割上
  • clog( conj (z)) == conj (clog(z))
  • 若 z 为 -0+0i ，则结果为 -∞+πi 并引发 FE_DIVBYZERO
  • 若 z 为 +0+0i ，则结果为 -∞+0i 并引发 FE_DIVBYZERO
  • 若 z 为 x+∞i （对于任何有限 x ），则结果为 +∞+πi/2
  • 若 z 为 x+NaNi （对于任何有限 x ），则结果为 NaN+NaNi 并可能引发 FE_INVALID
  • 若 z 为 -∞+yi （对于任何有限正 y ），则结果为 +∞+πi
  • 若 z 为 +∞+yi （对于任何有限正 y ），则结果为 +∞+0i
  • 若 z 为 -∞+∞i ，则结果为 +∞+3πi/4
  • 若 z 为 +∞+∞i ，则结果为 +∞+πi/4
  • 若 z 为 ±∞+NaNi ，则结果为 +∞+NaNi
  • 若 z 为 NaN+yi （对于任何有限 y ），则结果为 NaN+NaNi 并可能引发 FE_INVALID
  • 若 z 为 NaN+∞i ，则结果为 +∞+NaNi
  • 若 z 为 NaN+NaNi ，则结果为 NaN+NaNi

注意

拥有极坐标表示 (r,θ) 的复数 z 的自然对数等于 ln r + i(θ+2nπ) ，其主值为 ln r + iθ 。

示例

#include <stdio.h>
#include <math.h>
#include <complex.h>

int main(void)
{
    double complex z = clog(I); // r = 1, θ = pi/2
    printf("2*log(i) = %.1f%+fi\n", creal(2*z), cimag(2*z));

    double complex z2 = clog(sqrt(2)/2 + sqrt(2)/2*I); // r = 1, θ = pi/4
    printf("4*log(sqrt(2)/2+sqrt(2)i/2) = %.1f%+fi\n", creal(4*z2), cimag(4*z2));

    double complex z3 = clog(-1); // r = 1, θ = pi
    printf("log(-1+0i) = %.1f%+fi\n", creal(z3), cimag(z3));

    double complex z4 = clog(conj(-1)); // 或 C11 中的 clog(CMPLX(-1, -0.0))
    printf("log(-1-0i) (the other side of the cut) = %.1f%+fi\n", creal(z4), cimag(z4));
}

输出：

2*log(i) = 0.0+3.141593i
4*log(sqrt(2)/2+sqrt(2)i/2) = 0.0+3.141593i
log(-1+0i) = 0.0+3.141593i
log(-1-0i) (the other side of the cut) = 0.0-3.141593i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.7.2 The clog functions (p: 195)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.6.3.2 The clog functions (p: 543-544)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.7.2 The clog functions (p: 176-177)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.6.3.2 The clog functions (p: 478-479)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

cexpcexpfcexpl (C99)(C99)(C99) | 计算复数的 e 底指数 (函数)
loglogflogl (C99)(C99) | 计算自然对数（底为 e ）（ \({\small \ln{x} }\)ln(x) ） (函数)


complex

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |
#define complex _Complex | (C99 起)

此宏展开成标识复数类型的类型指定符。

程序可以取消定义，随后也可以重定义 complex 宏。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.1/4 complex (p: 188)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.1/2 complex (p: 170)

参阅

imaginary
(C99)
 虚数类型宏
(关键词宏)


conjf, conj, conjl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex conjf( float complex z ); | (1) | (C99 起)
double complex conj( double complex z ); | (2) | (C99 起)
long double complex conjl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define conj( z ) | (4) | (C99 起)
1-3) 通过反转虚部的符号计算 z 的共轭复数。
4) 泛型宏：若 z 拥有 long double complex 、 long double imaginary 或 long double 类型，则调用 conjl 。若 z 拥有 float complex 、 float imaginary 或 float 类型，则调用 conjf 。若 z 拥有 double complex 、 double imaginary 、 double 或任何整数类型，则调用 conj 。

参数

z - 复参数

返回值

z 的共轭复数。

注意

在不实现 I 为 _Imaginary_I 的 C99 实现上，可用 conj 获得拥有负零虚部的复数。 C11 中，宏 CMPLX 用于此目的。

示例

#include <stdio.h>
#include <complex.h>

int main(void)
{
    double complex z = 1.0 + 2.0*I;
    double complex z2 = conj(z);
    printf("The conjugate of %.1f%+.1fi is %.1f%+.1fi\n",
            creal(z), cimag(z), creal(z2), cimag(z2));

    printf("Their product is %.1f%+.1fi\n", creal(z*z2), cimag(z*z2));
}

输出：

The conjugate of 1.0+2.0i is 1.0-2.0i
Their product is 5.0+0.0i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.9.4 The conj functions (p: 198)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.9.3 The conj functions (p: 179)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅


cpowf, cpow, cpowl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex cpowf( float complex x, float complex y ); | (1) | (C99 起)
double complex cpow( double complex x, double complex y ); | (2) | (C99 起)
long double complex cpowl( long double complex x, long double complex y ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define pow( x, y ) | (4) | (C99 起)
1-3) 计算复幂函数 xy
 ，首参数的分支切割沿负实轴。
4) 泛型宏。若任何参数拥有 long double complex 类型，则调用 cpowl 。若任何参数拥有 double complex 类型，则调用 cpow ，若任何参数拥有 float complex 类型，则调用 cpowf 。若参数为实数或整数，则宏调用对应的实函数（ powf 、 pow 、 powl ） 。若参数为虚数，则调用对应的复数版本。

参数

x, y - 复参数

返回值

若不出现错误，则返回复幂 xy
 。

错误和特殊情况按照如同以 cexp (y* clog (x)) 实现运算一般处理，除了允许实现更细致地处理特殊情况。

示例

#include <stdio.h>
#include <complex.h>

int main(void)
{
    double complex z = cpow(1.0+2.0*I, 2);
    printf("(1+2i)^2 = %.1f%+.1fi\n", creal(z), cimag(z));

    double complex z2 = cpow(-1, 0.5);
    printf("(-1+0i)^0.5 = %.1f%+.1fi\n", creal(z2), cimag(z2));

    double complex z3 = cpow(conj(-1), 0.5); // 切割的另一侧
    printf("(-1-0i)^0.5 = %.1f%+.1fi\n", creal(z3), cimag(z3));

    double complex z4 = cpow(I, I); // i^i = exp(-pi/2)
    printf("i^i = %f%+fi\n", creal(z4), cimag(z4));
}

输出：

(1+2i)^2 = -3.0+4.0i
(-1+0i)^0.5 = 0.0+1.0i
(-1-0i)^0.5 = 0.0-1.0i
i^i = 0.207880+0.000000i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.8.2 The cpow functions (p: 195-196)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.6.4.1 The cpow functions (p: 544)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.8.2 The cpow functions (p: 177)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.6.4.1 The cpow functions (p: 479)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

csqrtcsqrtfcsqrtl (C99)(C99)(C99) | 计算复数平方根 (函数)
powpowfpowl (C99)(C99) | 计算一个数的给定次幂（ \(\small{x^y}\)xy ） (函数)


cprojf, cproj, cprojl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex cprojf( float complex z ); | (1) | (C99 起)
double complex cproj( double complex z ); | (2) | (C99 起)
long double complex cprojl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define cproj( z ) | (4) | (C99 起)
1-3) 计算 z 在黎曼球面上的投影。
4) 泛型宏：若 z 拥有 long double complex 、 long double imaginary 或 long double 类型，则调用 cprojl 。若 z 拥有 float complex 、 float imaginary 或 float 类型，则调用 cprojf 。若 z 拥有 double complex 、 double imaginary 、 double 或任何整数类型，则调用 cproj 。

对于绝大多数 z ， cproj(z)==z ，但所有复无穷大，即使是一部为无穷大而另一部为 NaN 者，都变为正实无穷大， INFINITY+0.0*I 或 INFINITY-0.0*I 。虚部（零）的符号为 cimag (z) 的符号。

参数

z - 复参数

返回值

z 在黎曼球面上的投影。

此函数为所有可行输入完整指定，并且不受制于任何描述于 math_errhandling 的错误。

注解

cproj 函数通过将所有无穷大映射到一（给出或采用虚部零的符号），帮助用户模拟黎曼球面，而且它应该在任何操作，特别是比较之前使用，比较可能对任何其他无穷大给出虚假结果。

示例

#include <stdio.h>
#include <complex.h>
#include <math.h>

int main(void)
{
    double complex z1 = cproj(1 + 2*I);
    printf("cproj(1+2i) = %.1f%+.1fi\n", creal(z1),cimag(z1));

    double complex z2 = cproj(INFINITY+2.0*I);
    printf("cproj(Inf+2i) = %.1f%+.1fi\n", creal(z2),cimag(z2));

    double complex z3 = cproj(INFINITY-2.0*I);
    printf("cproj(Inf-2i) = %.1f%+.1fi\n", creal(z3),cimag(z3));
}

输出：

cproj(1+2i) = 1.0+2.0i
cproj(Inf+2i) = inf+0.0i
cproj(Inf-2i) = inf-0.0i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.9.5 The cproj functions (p: 198)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.9.4 The cproj functions (p: 179)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅


crealf, creal, creall

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float crealf( float complex z ); | (1) | (C99 起)
double creal( double complex z ); | (2) | (C99 起)
long double creall( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define creal( z ) | (4) | (C99 起)
1-3) 返回 z 的实部。
4) 泛型宏：若 z 拥有 long double complex 、 long double imaginary 或 long double 类型，则调用 creall 。若 z 拥有 float complex 、 float imaginary 或 float 类型，则调用 crealf。若z 拥有 double complex 、 double imaginary 或 double 类型，或任何整数类型，则调用 creal 。

参数

z - 复参数

返回值

z的实部

此函数对所有可能输入指明，而且不受制于任何描述于 math_errhandling 的错误。

注意

对于任何复变量 z ， z == creal(z) + I* cimag (z) 。

示例

#include <stdio.h>
#include <complex.h>

int main(void)
{
    double complex z = 1.0 + 2.0*I;
    printf("%f%+fi\n", creal(z), cimag(z));
}

输出：

1.000000+2.000000i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.9.6 The creal functions (p: 198-199)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.9.5 The creal functions (p: 180)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

cimagcimagfcimagl
(C99)(C99)(C99)
 计算复数的虚部
(函数)


csinf, csin, csinl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex csinf( float complex z ); | (1) | (C99 起)
double complex csin( double complex z ); | (2) | (C99 起)
long double complex csinl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define sin( z ) | (4) | (C99 起)
1-3) 计算 z 的复正弦。
4) 泛型宏：若 z 拥有 long double complex 类型，则调用 csinl 。若 z 拥有 double complex 类型，则调用 csin ，若 z 拥有 float complex 类型，则调用 csinf 。若 z 为实数或整数，则该宏调用对应的实数函数（ sinf 、 sin 、 sinl ）。若 z 是虚数，则该宏调用函数 sinh 的对应实数版本，实现公式 sin(iy) = i sinh(y) ，且宏的返回类型为虚数。

参数

z - 复参数

返回值

若无错误发生，则为 z 的复正弦。

错误和特殊情况的处理如同运算以 -I * csinh (I*z) 实现。

注意

正弦在复平面上是整函数，而且没有分支切割。

正弦的数学定义是 sin z =
eiz
-e-iz
2i
。

示例

#include <stdio.h>
#include <math.h>
#include <complex.h>

int main(void)
{
    double complex z = csin(1);  // 表现如同沿着实轴的实数正弦
    printf("sin(1+0i) = %f%+fi ( sin(1)=%f)\n", creal(z), cimag(z), sin(1));

    double complex z2 = csin(I); // 表现如同沿着虚轴的sinh
    printf("sin(0+1i) = %f%+fi (sinh(1)=%f)\n", creal(z2), cimag(z2), sinh(1));
}

输出：

sin(1+0i) = 0.841471+0.000000i ( sin(1)=0.841471)
sin(0+1i) = 0.000000+1.175201i (sinh(1)=1.175201)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.5.5 The csin functions (p: 191-192)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.5.5 The csin functions (p: 173)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

ccosccosfccosl (C99)(C99)(C99) | 计算复数余弦 (函数)
ctanctanfctanl (C99)(C99)(C99) | 计算复数正切 (函数)
casincasinfcasinl (C99)(C99)(C99) | 计算复数反正弦 (函数)
sinsinfsinl (C99)(C99) | 计算正弦（ \({\small\sin{x} }\)sin(x) ） (函数)


csinhf, csinh, csinhl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex csinhf( float complex z ); | (1) | (C99 起)
double complex csinh( double complex z ); | (2) | (C99 起)
long double complex csinhl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define sinh( z ) | (4) | (C99 起)
1-3) 计算 z 的复双曲正弦。
4) 泛型宏：若 z 拥有 long double complex 类型，则调用 csinl 。若 z 拥有 double complex 类型，则调用 csin 。若 z 拥有 float complex 类型，则调用 csinf 。若 z 为实数或整数，则该宏调用对应的实函数（ sinf 、 sin 、 sinl ）。若 z 为虚数，则该宏调用函数 sinh 的对应实版本，实现公式 sinh(iy) = i sin(y) ，而返回类型为虚数。

参数

z - 复参数

返回值

若不出现错误，则返回 z 的复双曲正弦。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • csinh( conj (z)) == conj (csinh(z))
  • csinh(z) == -csinh(-z)
  • 若 z 为 +0+0i ，则结果为 +0+0i
  • 若 z 为 +0+∞i ，则结果为 ±0+NaNi （实部符号未指定）并引发 FE_INVALID
  • 若 z 为 +0+NaNi ，则结果为 ±0+NaNi
  • 若 z 为 x+∞i （对于任何有限正 x ），则结果为 NaN+NaNi 并引发 FE_INVALID
  • 若 z 为 x+NaNi （对于任何有限正 x ），则结果为 NaN+NaNi 并可能引发 FE_INVALID
  • 若 z 为 +∞+0i ，则结果为 +∞+0i
  • 若 z 为 +∞+yi （对于任何有限正 y ），则结果为 +∞cis(y)
  • 若 z 为 +∞+∞i ，则结果为 ±∞+NaNi （实部符号未指定）并引发 FE_INVALID
  • 若 z 为 +∞+NaNi ，则结果为 ±∞+NaNi （实部符号未指定）
  • 若 z 为 NaN+0i ，则结果为 NaN+0i
  • 若 z 为 NaN+yi （对于任何有限非零 y ），则结果为 NaN+NaNi 并可能引发 FE_INVALID
  • 若 z 为 NaN+NaNi ，则结果为 NaN+NaNi

其中 cis(y) 为 cos(y) + i sin(y) 。

注意

双曲正弦的数学定义是 sinh z =
ez
-e-z
2
。

双曲正弦在复平面上是整函数而无分支切割。它相对于虚部是周期的，周期为 2πi 。

示例

#include <stdio.h>
#include <math.h>
#include <complex.h>

int main(void)
{
    double complex z = csinh(1);  // 表现类似沿实轴的 sinh
    printf("sinh(1+0i) = %f%+fi (sinh(1)=%f)\n", creal(z), cimag(z), sinh(1));

    double complex z2 = csinh(I); // 表现类似沿虚轴的正弦
    printf("sinh(0+1i) = %f%+fi ( sin(1)=%f)\n", creal(z2), cimag(z2), sin(1));
}

输出：

sinh(1+0i) = 1.175201+0.000000i (sinh(1)=1.175201)
sinh(0+1i) = 0.000000+0.841471i ( sin(1)=0.841471)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.6.5 The csinh functions (p: 194)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.6.2.5 The csinh functions (p: 541-542)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.6.5 The csinh functions (p: 175-176)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.6.2.5 The csinh functions (p: 476-477)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

ccoshccoshfccoshl (C99)(C99)(C99) | 计算复双曲余弦 (函数)
ctanhctanhfctanhl (C99)(C99)(C99) | 计算复数双曲正切 (函数)
casinhcasinhfcasinhl (C99)(C99)(C99) | 计算复数反双曲正弦 (函数)
sinhsinhfsinhl (C99)(C99) | 计算双曲正弦（ \({\small\sinh{x} }\)sinh(x) ） (函数)


csqrtf, csqrt, csqrtl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex csqrtf( float complex z ); | (1) | (C99 起)
double complex csqrt( double complex z ); | (2) | (C99 起)
long double complex csqrtl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define sqrt( z ) | (4) | (C99 起)
1-3) 计算 z 的复平方根，分支切割沿负实轴。
4) 泛型宏：若 z 拥有 long double complex 类型，则调用 csqrtl 。若 z 拥有 double complex 类型，则调用 csqrt ，若 z 拥有 float complex 类型，则调用 csqrtf 。若 z 为实数或整数，则宏调用对应的实数函数（ sqrtf 、 sqrt 、 sqrtl ）。若 z 为虚数，则调用对应的复数版本。

参数

z - 复参数

返回值

若不出现错误，则返回 z 的平方根，在包含虚轴的右半平面中（沿实轴为 [0; +∞) ，而沿虚轴为 (−∞; +∞) ）。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • 考虑虚部符号，函数连续到分支切割上。
  • csqrt( conj (z)) == conj (csqrt(z))
  • 若 z 为 ±0+0i ，则结果为 +0+0i
  • 若 z 为 x+∞i ，则结果为 +∞+∞i ，即使 x 为 NaN
  • 若 z 为 x+NaNi ，则结果为 NaN+NaNi （除非 x 为 ±∞ ）并可能引发 FE_INVALID
  • 若 z 为 -∞+yi ，则对于有限正 y 结果为 +0+∞i
  • 若 z 为 +∞+yi ，则对于有限正 y 结果为 +∞+0i)
  • 若 z 为 -∞+NaNi ，则结果为 NaN±∞i （虚部符号未指定）
  • 若 z 为 +∞+NaNi ，则结果为 +∞+NaNi
  • 若 z 为 NaN+yi ，则结果为 NaN+NaNi 并可能引发 FE_INVALID
  • 若 z 为 NaN+NaNi ，则结果为 NaN+NaNi

示例

#include <stdio.h>
#include <complex.h>

int main(void)
{
    double complex z1 = csqrt(-4);
    printf("Square root of -4 is %.1f%+.1fi\n", creal(z1), cimag(z1));

    double complex z2 = csqrt(conj(-4)); // 或 C11 中的 CMPLX(-4, -0.0)
    printf("Square root of -4-0i, the other side of the cut, is "
           "%.1f%+.1fi\n", creal(z2), cimag(z2));
}

输出：

Square root of -4 is 0.0+2.0i
Square root of -4-0i, the other side of the cut, is 0.0-2.0i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.8.3 The csqrt functions (p: 196)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.6.4.2 The csqrt functions (p: 544)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.8.3 The csqrt functions (p: 178)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.6.4.2 The csqrt functions (p: 479)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

cpowcpowfcpowl (C99)(C99)(C99) | 计算复数幂函数 (函数)
sqrtsqrtfsqrtl (C99)(C99) | 计算平方根（ \(\small{\sqrt{x} }\)√x ） (函数)


ctanf, ctan, ctanl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex ctanf( float complex z ); | (1) | (C99 起)
double complex ctan( double complex z ); | (2) | (C99 起)
long double complex ctanl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define tan( z ) | (4) | (C99 起)
1-3) 计算 z 的复正切。
4) 泛型宏：若 z 拥有 long double complex 类型，则调用 ctanl 。若 z 拥有 double complex 类型，则调用 ctan 。若 z 拥有 float complex 类型，则调用 ctanf 。若 z 为实数或整数，则该宏调用对应的实函数（ tanf 、 tan 、 tanl ）。若 z 为虚数，则该宏调用函数 tanh 的对应实版本，实现公式 tan(iy) = i tanh(y) ，而返回类型为虚数。

参数

z - 复参数

返回值

若无错误发生，则返回 z 的复正切。

错误和特殊情况如同运算实现为 -i * ctanh (i*z) 一般处理，其中 i 是虚数单位。

注意

正切是复平面上的解析函数，而无分支切割。它对于实部是周期的，周期为 πi ，而且沿实轴有一阶极点，位于坐标 (π(1/2 + n), 0) 。然而无常用浮点表示能准确表示 π/2 ，故而没有值使得极点错误出现。

正切的数学定义是 tan z =
i(e-iz
-eiz
)
e-iz
+eiz
。

示例

#include <stdio.h>
#include <math.h>
#include <complex.h>

int main(void)
{
    double complex z = ctan(1);  // 表现类似沿实轴的实正切
    printf("tan(1+0i) = %f%+fi ( tan(1)=%f)\n", creal(z), cimag(z), tan(1));

    double complex z2 = ctan(I); // 表现类似沿虚轴的 tanh
    printf("tan(0+1i) = %f%+fi (tanh(1)=%f)\n", creal(z2), cimag(z2), tanh(1));
}

输出：

tan(1+0i) = 1.557408+0.000000i ( tan(1)=1.557408)
tan(0+1i) = 0.000000+0.761594i (tanh(1)=0.761594)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.5.6 The ctan functions (p: 192)
  • 7.25 Type-generic complex <tgmath.h> (p: 373-375)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.5.6 The ctan functions (p: 174)
  • 7.22 Type-generic complex <tgcomplex.h> (p: 335-337)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

ctanhctanhfctanhl (C99)(C99)(C99) | 计算复数双曲正切 (函数)
csincsinfcsinl (C99)(C99)(C99) | 计算复数正弦 (函数)
ccosccosfccosl (C99)(C99)(C99) | 计算复数余弦 (函数)
catancatanfcatanl (C99)(C99)(C99) | 计算复数反正切 (函数)
tantanftanl (C99)(C99) | 计算正切（ \({\small\tan{x} }\)tan(x) ） (函数)


ctanhf, ctanh, ctanhl

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |  |
float complex ctanhf( float complex z ); | (1) | (C99 起)
double complex ctanh( double complex z ); | (2) | (C99 起)
long double complex ctanhl( long double complex z ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define tanh( z ) | (4) | (C99 起)
1-3) 计算 z 的复双曲正切。
4) 泛型宏：若 z 拥有 long double complex 类型，则调用 ctanhl 。若 z 拥有 double complex 类型，则调用 ctanh 。若 z 拥有 float complex 类型，则调用 ctanhf 。若 z 为实数或整数，则宏调用对应的实函数（ tanhf 、 tanh 、 tanhl ）。若 z 为虚数，则宏调用函数 tan 的对应实数版本，实现公式 tanh(iy) = i tan(y) ，而返回类型为虚数。

参数

z - 复参数

返回值

若不出现错误，则返回 z 的复双曲正切。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • ctanh( conj (z)) == conj (ctanh(z))
  • ctanh(-z) == -ctanh(z)
  • 若 z 为 +0+0i ，则结果为 +0+0i
  • 若 z 为 x+∞i （对于任何[1]有限 x ），结果为 NaN+NaNi 并引发 FE_INVALID
  • 若 z 为 x+NaN （对于任何[2]有限 x ），则结果为 NaN+NaNi 并可能引发 FE_INVALID 。
  • 若 z 为 +∞+yi （对于任何有限正 y ），则结果为 1+0i
  • 若 z 为 +∞+∞i ，则结果为 1±0i （虚部符号未指定）
  • 若 z 为 +∞+NaNi ，则结果为 1±0i （虚部符号未指定）
  • 若 z 为 NaN+0i ，则结果为 NaN+0i
  • 若 z 为 NaN+yi （对于任何非零 y ），则结果为 NaN+NaNi 并可能引发 FE_INVALID 。
  • 若 z 为 NaN+NaNi ，则结果为 NaN+NaNi 。
  1. ↑ 由 DR471 ，这只对非零 x 成立。若 z 为 0+∞i ，则结果应为 0+NaNi 。
  2. ↑ 由 DR471 ，这只对非零 x 成立。若 z 为 0+NaNi ，则结果应为 0+NaNi 。

注意

双曲正切的数学定义是 tanh z =
ez
-e-z
ez
+e-z
。

双曲正切是复平面上的解析函数且无分支切割。它对于虚部是周期的，周期为 πi ，而且沿虚轴有一阶极点，位于坐标 (0, π(1/2 + n)) 。然而无常用浮点表示能准确表示 π/2 ，故没有参数值能导致极点错误。

示例

#include <stdio.h>
#include <math.h>
#include <complex.h>

int main(void)
{
    double complex z = ctanh(1);  // 表现类似沿实轴的 tanh
    printf("tanh(1+0i) = %f%+fi (tanh(1)=%f)\n", creal(z), cimag(z), tanh(1));

    double complex z2 = ctanh(I); // 表现类似沿虚轴的正切
    printf("tanh(0+1i) = %f%+fi ( tan(1)=%f)\n", creal(z2), cimag(z2), tan(1));
}

输出：

tanh(1+0i) = 0.761594+0.000000i (tanh(1)=0.761594)
tanh(0+1i) = 0.000000+1.557408i ( tan(1)=1.557408)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.6.6 The ctanh functions (p: 194)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • G.6.2.6 The ctanh functions (p: 542)
  • G.7 Type-generic math <tgmath.h> (p: 545)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.6.6 The ctanh functions (p: 176)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • G.6.2.6 The ctanh functions (p: 477)
  • G.7 Type-generic math <tgmath.h> (p: 480)

参阅

csinhcsinhfcsinhl (C99)(C99)(C99) | 计算复数双曲正弦 (函数)
ccoshccoshfccoshl (C99)(C99)(C99) | 计算复双曲余弦 (函数)
catanhcatanhfcatanhl (C99)(C99)(C99) | 计算复数反双曲正切 (函数)
tanhtanhftanhl (C99)(C99) | 计算双曲正切（ \({\small\tanh{x} }\)tanh(x) ） (函数)


imaginary

< c‎ | numeric‎ | complex
定义于头文件 <complex.h> |
#define imaginary _Imaginary | (C99 起)

此宏展开成关键词 _Imaginary 。

这是一个便利宏，使你能用 float imaginary 、 double imaginary 及 long double imaginary 作为书写三种纯虚数 C 类型 float _Imaginary 、 double _Imaginary 以及 long double _Imaginary 的替用方式。

同 C 中的任意纯虚数支持，仅若支持虚数才定义此宏。

推荐编译器定义 __STDC_IEC_559_COMPLEX__ ，但并不强制要求其支持虚数。 POSIX 推荐检查是否定义宏 _Imaginary_I 以鉴别是否支持虚数。 | (C99 起) (C11 前)
若定义 __STDC_IEC_559_COMPLEX__ ，则支持虚数。 | (C11 起)

注意

允许程序取消定义，而且可在之后重定义 imaginary 宏。

示例

#include <stdio.h>
#include <complex.h>

int main(void)
{
    double imaginary i = 2.0*I; // 纯虚数
    double f = 1.0; // 纯实数
    double complex z = f + i; // 复数
    printf("z = %.1f%+.1fi\n", creal(z), cimag(z));
}

输出：

z = 1.0+2.0i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.3.1/5 imaginary (p: 188)
  • G.6/1 imaginary (p: 537)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.3.1/3 imaginary (p: 170)
  • G.6/1 imaginary (p: 472)

参阅

complex
(C99)
 复数类型宏
(关键词宏)


浮点环境

< c‎ | numeric

浮点环境是浮点状态标志及实现所支持的控制模式的集合。它是线程局域的，每个线程从亲线程继承其浮点环境的初始状态。浮点运算会修改指示反常值或补助信息的浮点状态标志。浮点控制模式影响浮点运算的结果。

仅若设置 #pragma STDC FENV_ACCESS 为 ON ，浮点环境的访问及修改才有意义。否则具体实现可以自由地假设浮点控制模式始终是默认值，而且浮点状态标志始终不被检测或修改。实际上，当前只有少数编译器，如 HP aCC 、 Oracle Studio 和 IBM XL 显式支持 #pragma ，但总之多数编译器允许有意义地访问浮点环境。

类型

定义于头文件 <fenv.h>
fenv_t | 表示整体浮点环境的类型
fexcept_t | 集中表示所有浮点异常状态标志的类型

函数

feclearexcept (C99) | 清除指定的浮点异常状态标志 (函数)
fetestexcept (C99) | 确认设置了哪些浮点异常状态标志 (函数)
feraiseexcept (C99) | 引发指定的浮点异常状态标志 (函数)
fegetexceptflagfesetexceptflag (C99)(C99) | 将指定的浮点异常状态标志从指定的浮点环境获取，再设置到指定浮点环境的操作。 (函数)
fegetroundfesetround (C99)(C99) | 获得或设置数字的舍入方向 (函数)
fegetenvfesetenv (C99)(C99) | 保存或恢复当前浮点环境，包括异常的标志和数字的舍弃模式 (函数)
feholdexcept (C99) | 保存当前环境的异常状态标志，再清除所有异常状态标志，并忽略所有未来错误 (函数)
feupdateenv (C99) | 恢复之前保存的浮点环境，并引发之前已经引发过的异常，使其存在于当前内存环境中 (函数)

宏

FE_ALL_EXCEPTFE_DIVBYZEROFE_INEXACTFE_INVALIDFE_OVERFLOWFE_UNDERFLOW (C99) | 浮点异常 (宏常量)
FE_DOWNWARDFE_TONEARESTFE_TOWARDZEROFE_UPWARD (C99) | 浮点舍入方向 (宏常量)
FE_DFL_ENV (C99) | 默认浮点环境 (宏常量)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.6 Floating-point environment <fenv.h> (p: 206-215)
  • 7.31.4 Floating-point environment <fenv.h> (p: 455)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.6 Floating-point environment <fenv.h> (p: 187-196)

参阅


FE_DFL_ENV

< c‎ | numeric‎ | fenv
定义于头文件 <fenv.h> |
#define FE_DFL_ENV /*implementation defined*/ | (C99 起)

宏常量 FE_DFL_ENV 展开成 const fenv_t* 类型表达式，指向默认浮点环境，即在程序启动时加载的浮点环境的完整副本。

实现可以支持以 FE_ 后随大写字母开始，且拥有 const fenv_t* 类型的附加宏。

示例

#include <stdio.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON

void show_fe_exceptions(void)
{
    printf("current exceptions raised: ");
    if(fetestexcept(FE_DIVBYZERO))     printf(" FE_DIVBYZERO");
    if(fetestexcept(FE_INEXACT))       printf(" FE_INEXACT");
    if(fetestexcept(FE_INVALID))       printf(" FE_INVALID");
    if(fetestexcept(FE_OVERFLOW))      printf(" FE_OVERFLOW");
    if(fetestexcept(FE_UNDERFLOW))     printf(" FE_UNDERFLOW");
    if(fetestexcept(FE_ALL_EXCEPT)==0) printf(" none");
    printf("\n");
}

void show_fe_rounding_method(void)
{
    printf("current rounding method:    ");
    switch (fegetround()) {
           case FE_TONEAREST:  printf ("FE_TONEAREST");  break;
           case FE_DOWNWARD:   printf ("FE_DOWNWARD");   break;
           case FE_UPWARD:     printf ("FE_UPWARD");     break;
           case FE_TOWARDZERO: printf ("FE_TOWARDZERO"); break;
           default:            printf ("unknown");
    };
    printf("\n");
}

void show_fe_environment(void)
{
    show_fe_exceptions();
    show_fe_rounding_method();
}

int main(void)
{
    printf("On startup:\n");
    show_fe_environment();

    // 更改环境
    fesetround(FE_DOWNWARD);     // 更改舍入模式
    feraiseexcept(FE_INVALID);   // 引发异常
    printf("\nBefore restoration:\n");
    show_fe_environment();

    fesetenv(FE_DFL_ENV);    // 恢复
    printf("\nAfter restoring default environment:\n");
    show_fe_environment();
}

输出：

On startup:
current exceptions raised:  none
current rounding method:    FE_TONEAREST

Before restoration:
current exceptions raised:  FE_INVALID
current rounding method:    FE_DOWNWARD

After restoring default environment:
current exceptions raised:  none
current rounding method:    FE_TONEAREST

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.6/9 Floating-point environment <fenv.h> (p: 208)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.6/8 Floating-point environment <fenv.h> (p: 188-189)

参阅

fegetenvfesetenv (C99)(C99) | 保存或恢复当前浮点环境，包括异常的标志和数字的舍弃模式 (函数)
feupdateenv (C99) | 恢复之前保存的浮点环境，并引发之前已经引发过的异常，使其存在于当前内存环境中 (函数)


FE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW, FE_ALL_EXCEPT

< c‎ | numeric‎ | fenv
定义于头文件 <fenv.h> |
#define FE_DIVBYZERO /*implementation defined power of 2*/ | (C99 起)
#define FE_INEXACT /*implementation defined power of 2*/ | (C99 起)
#define FE_INVALID /*implementation defined power of 2*/ | (C99 起)
#define FE_OVERFLOW /*implementation defined power of 2*/ | (C99 起)
#define FE_UNDERFLOW /*implementation defined power of 2*/ | (C99 起)
#define FE_ALL_EXCEPT FE_DIVBYZERO | FE_INEXACT | \ FE_INVALID | FE_OVERFLOW | \ FE_UNDERFLOW | (C99 起)

所有这些宏常量（除了 FE_ALL_EXCEPT ）都展开成值为 2 的相异次幂整数常量表达式，唯一地鉴别所有受支持浮点异常。每个宏仅若受支持才得到定义。

宏常量 FE_ALL_EXCEPT 展开成所有其他 FE_* 的逐位或，且始终有定义，若实现不支持浮点异常，则为零。

常量 | 定义
FE_DIVBYZERO | 出现于之前浮点运算的极点错误
FE_INEXACT | 不准确结果：必须舍入以存储之前浮点运算的结果
FE_INVALID | 出现于之前浮点运算的定义域错误
FE_OVERFLOW | 之前浮点运算的结果过大而无法表示
FE_UNDERFLOW | 之前浮点运算的结果为有精度损失的非正规值
FE_ALL_EXCEPT | 所有受支持浮点异常的逐位或

实现可于 <fenv.h> 定义附加宏常量以鉴别附加浮点异常。所有这种常量都以 FE_ 后随至少一个大写字母开始。

更多细节见 math_errhandling 。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON
void show_fe_exceptions(void)
{
    printf("exceptions raised:");
    if(fetestexcept(FE_DIVBYZERO)) printf(" FE_DIVBYZERO");
    if(fetestexcept(FE_INEXACT))   printf(" FE_INEXACT");
    if(fetestexcept(FE_INVALID))   printf(" FE_INVALID");
    if(fetestexcept(FE_OVERFLOW))  printf(" FE_OVERFLOW");
    if(fetestexcept(FE_UNDERFLOW)) printf(" FE_UNDERFLOW");
    feclearexcept(FE_ALL_EXCEPT);
    printf("\n");
}

int main(void)
{
    printf("MATH_ERREXCEPT is %s\n",
           math_errhandling & MATH_ERREXCEPT ? "set" : "not set");

    printf("0.0/0.0 = %f\n", 0.0/0.0);
    show_fe_exceptions();

    printf("1.0/0.0 = %f\n", 1.0/0.0);
    show_fe_exceptions();

    printf("1.0/10.0 = %f\n", 1.0/10.0);
    show_fe_exceptions();

    printf("sqrt(-1) = %f\n", sqrt(-1));
    show_fe_exceptions();

    printf("DBL_MAX*2.0 = %f\n", DBL_MAX*2.0);
    show_fe_exceptions();

    printf("nextafter(DBL_MIN/pow(2.0,52),0.0) = %.1f\n",
                      nextafter(DBL_MIN/pow(2.0,52),0.0));
    show_fe_exceptions();
}

可能的输出：

MATH_ERREXCEPT is set
0.0/0.0 = nan
exceptions raised: FE_INVALID
1.0/0.0 = inf
exceptions raised: FE_DIVBYZERO
1.0/10.0 = 0.100000
exceptions raised: FE_INEXACT
sqrt(-1) = -nan
exceptions raised: FE_INVALID
DBL_MAX*2.0 = inf
exceptions raised: FE_INEXACT FE_OVERFLOW
nextafter(DBL_MIN/pow(2.0,52),0.0) = 0.0
exceptions raised: FE_INEXACT FE_UNDERFLOW

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.6/6 Floating-point environment <fenv.h> (p: 207)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.6/5 Floating-point environment <fenv.h> (p: 188)

参阅

math_errhandlingMATH_ERRNOMATH_ERREXCEPT
(C99)(C99)(C99)
 定义用于常用数学函数的错误处理机制
(宏常量)


FE_DOWNWARD, FE_TONEAREST, FE_TOWARDZERO, FE_UPWARD

< c‎ | numeric‎ | fenv
定义于头文件 <fenv.h> |
#define FE_DOWNWARD /*implementation defined*/ | (C99 起)
#define FE_TONEAREST /*implementation defined*/ | (C99 起)
#define FE_TOWARDZERO /*implementation defined*/ | (C99 起)
#define FE_UPWARD /*implementation defined*/ | (C99 起)

每个这种宏常量都展开成非负常量表达式，可被 fesetround 或 fegetround 用于指示受支持的浮点舍入模式之一。实现可于 <fenv.h> 定义另外的舍入模式常量，它应以 FE_ 后随至少一个大写字母开始。每个宏仅若受支持才得到定义。

大多数实现中，这些宏常量的展开值等于 FLT_ROUNDS 和 float_round_style 的值。

常量 | 解释
FE_DOWNWARD | 向负无穷大舍入
FE_TONEAREST | 向最接近可表示值舍入
FE_TOWARDZERO | 向零舍入
FE_UPWARD | 向正无穷大舍入

实现可支持另外的舍入模式。

当前舍入模式影响下列结果：

  • 常量表达式以外的浮点数算术运算符结果
double x = 1;
x/10; // 0.09999999999999999167332731531132594682276248931884765625
   // 或 0.1000000000000000055511151231257827021181583404541015625
  • 标准库数学函数的返回值
sqrt(2); // 1.41421356237309492343001693370752036571502685546875
      // 或 1.4142135623730951454746218587388284504413604736328125
  • 浮点到浮点的隐式转换及转换类型
double d = 1 + DBL_EPSILON;
float f = d; //  1.00000000000000000000000
           // 或 1.00000011920928955078125
  • 字符串转换，如 strtod 或 printf
strtof("0.1", NULL); // 0.0999999940395355224609375
                  // 或 0.100000001490116119384765625
  • 库舍入函数 nearbyint 、 rint 、 lrint
lrint(2.1); // 2 或 3

当前舍入模式不影响：

  • 浮点到整数的隐式转换或转型（始终向零）
  • 编译时执行的常量表达式中浮点算术运算符的结果（始终向最接近）
  • 库函数 round 、 lround 、 llround 、 ceil 、 floor 、 trunc

同任何浮点环境功能，仅若设置了 #pragma STDC FENV_ACCESS ON 才保证舍入。

示例

#include <stdio.h>
#include <stdlib.h>
#include <fenv.h>
#include <math.h>
int main()
{
#pragma STDC FENV_ACCESS ON
    fesetround(FE_DOWNWARD);
    puts("rounding down: ");
    printf("           pi = %.22f\n", acosf(-1));
    printf("strtof(\"1.1\") = %.22f\n", strtof("1.1", NULL));
    printf("    rint(2.1) = %.22f\n\n", rintf(2.1));
    fesetround(FE_UPWARD);
    puts("rounding up: ");
    printf("           pi = %.22f\n", acosf(-1));
    printf("strtof(\"1.1\") = %.22f\n", strtof("1.1", NULL));
    printf("    rint(2.1) = %.22f\n", rintf(2.1));
}

输出：

rounding down:
           pi = 3.1415925025939941406250
strtof("1.1") = 1.0999999046325683593750
    rint(2.1) = 2.0000000000000000000000

rounding up:
           pi = 3.1415927410125732421875
strtof("1.1") = 1.1000000238418579101563
    rint(2.1) = 3.0000000000000000000000

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.6/8 Floating-point environment <fenv.h> (p: 207)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.6/7 Floating-point environment <fenv.h> (p: 188)

参阅

fegetroundfesetround
(C99)(C99)
 获得或设置数字的舍入方向
(函数)


feclearexcept

< c‎ | numeric‎ | fenv
定义于头文件 <fenv.h> |
int feclearexcept( int excepts ); | (C99 起)

尝试清除列于位掩码参数 excepts 的浮点异常，该参数值为浮点异常宏的逐位或。

参数

excepts - 列出带清除的异常标志的位掩码

返回值

若成功清除所有指明的异常，或若 excepts 为零则返回 ​0​ 。错误时返回非零。

示例

#include <fenv.h>
#include <stdio.h>
#include <math.h>
#include <float.h>

/*
 * 可能的hypot实现，它会活用许多高级浮点特性。
 */
double hypot_demo(double a, double b) {
  const int range_problem = FE_OVERFLOW | FE_UNDERFLOW;
  feclearexcept(range_problem);
  // 尝试快速算法
  double result = sqrt(a * a + b * b);
  if (!fetestexcept(range_problem))  // 未上溢或下溢
    return result;                   // 返回结果
  // 做更多复杂计算以避免上溢或下溢
  int a_exponent,b_exponent;
  frexp(a, &a_exponent);
  frexp(b, &b_exponent);

  if (a_exponent - b_exponent > DBL_MAX_EXP)
    return fabs(a) + fabs(b);        // 我们可以忽略小值
  // 令fabs(a)的规模接近1
  double a_scaled = scalbn(a, -a_exponent);
  double b_scaled = scalbn(b, -a_exponent);
  // 现在上溢和下溢是不可能的
  result = sqrt(a_scaled * a_scaled + b_scaled * b_scaled);
  // 撤销规模化
  return scalbn(result, a_exponent);
}

int main(void)
{
  // 通常情况选择较快的路线
  printf("hypot(%f, %f) = %f\n", 3.0, 4.0, hypot_demo(3.0, 4.0));
  // 极限情形会选择较慢但更准确的路线
  printf("hypot(%e, %e) = %e\n", DBL_MAX / 2.0,
                                DBL_MAX / 2.0,
                                hypot_demo(DBL_MAX / 2.0, DBL_MAX / 2.0));

  return 0;
}

输出：

hypot(3.000000, 4.000000) = 5.000000
hypot(8.988466e+307, 8.988466e+307) = 1.271161e+308

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.6.2.1 The feclearexcept function (p: 209)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.6.2.1 The feclearexcept function (p: 190)

参阅

fetestexcept
(C99)
 确认设置了哪些浮点异常状态标志
(函数)


fegetenv, fesetenv

< c‎ | numeric‎ | fenv
定义于头文件 <fenv.h> |  |
int fegetenv( fenv_t* envp ); | (1) | (C99 起)
int fesetenv( const fenv_t* envp ); | (2) | (C99 起)

1) 试图存储浮点环境的状态于 envp 所指向的对象。

2) 试图从 envp 所指向的对象建立浮点环境状态。对象的值必须是以先前调用 feholdexcept 或 fegetenv 获得值或是浮点宏常量。若 envp 中设置了任何浮点状态标志，则环境中标志变为被设置（然后可用 fetestexcept 测试），但不引发对应的浮点异常（执行持续而不中断）。

参数

envp - 指向 fenv_t 类型对象的指针，该对象保有浮点环境的状态

返回值

成功时返回 ​0​ ，否则返回非零。

示例

#include <stdio.h>
#include <math.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON

void show_fe_exceptions(void)
{
    printf("current exceptions raised: ");
    if(fetestexcept(FE_DIVBYZERO))     printf(" FE_DIVBYZERO");
    if(fetestexcept(FE_INEXACT))       printf(" FE_INEXACT");
    if(fetestexcept(FE_INVALID))       printf(" FE_INVALID");
    if(fetestexcept(FE_OVERFLOW))      printf(" FE_OVERFLOW");
    if(fetestexcept(FE_UNDERFLOW))     printf(" FE_UNDERFLOW");
    if(fetestexcept(FE_ALL_EXCEPT)==0) printf(" none");
    printf("\n");
}

void show_fe_rounding_method(void)
{
    printf("current rounding method:    ");
    switch (fegetround()) {
           case FE_TONEAREST:  printf ("FE_TONEAREST");  break;
           case FE_DOWNWARD:   printf ("FE_DOWNWARD");   break;
           case FE_UPWARD:     printf ("FE_UPWARD");     break;
           case FE_TOWARDZERO: printf ("FE_TOWARDZERO"); break;
           default:            printf ("unknown");
    };
    printf("\n");
}

void show_fe_environment(void)
{
    show_fe_exceptions();
    show_fe_rounding_method();
}

int main(void)
{
    fenv_t curr_env;
    int rtn;

    /* 显示默认环境。 */
    show_fe_environment();
    printf("\n");

    /* 在默认环境下做一些计算。 */
    printf("+11.5 -> %+4.1f\n", rint(+11.5)); /* 两整数的中央值 */
    printf("+12.5 -> %+4.1f\n", rint(+12.5)); /* 两整数的中央值 */
    show_fe_environment();
    printf("\n");

    /* 保存当前环境。 */
    rtn = fegetenv(&curr_env);

    /* 以新舍入方法进行一些计算。 */
    feclearexcept(FE_ALL_EXCEPT);
    fesetround(FE_DOWNWARD);
    printf("1.0/0.0 = %f\n", 1.0/0.0);
    printf("+11.5 -> %+4.1f\n", rint(+11.5));
    printf("+12.5 -> %+4.1f\n", rint(+12.5));
    show_fe_environment();
    printf("\n");

    /* 恢复先前环境。 */
    rtn = fesetenv(&curr_env);
    show_fe_environment();

    return 0;
}

输出：

current exceptions raised: none
current rounding method:   FE_TONEAREST

+11.5 -> +12.0
+12.5 -> +12.0
current exceptions raised: FE_INEXACT
current rounding method:   FE_TONEAREST

1.0/0.0 = inf
+11.5 -> +11.0
+12.5 -> +12.0
current exceptions raised: FE_DIVBYZERO FE_INEXACT
current rounding method:   FE_DOWNWARD

current exceptions raised: FE_INEXACT
current rounding method:   FE_TONEAREST

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.6.4.1 The fegetenv function (p: 213)
  • 7.6.4.3 The fesetenv function (p: 214)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.6.4.1 The fegetenv function (p: 194)
  • 7.6.4.3 The fesetenv function (p: 195)

参阅

feholdexcept (C99) | 保存当前环境的异常状态标志，再清除所有异常状态标志，并忽略所有未来错误 (函数)
feupdateenv (C99) | 恢复之前保存的浮点环境，并引发之前已经引发过的异常，使其存在于当前内存环境中 (函数)
FE_DFL_ENV (C99) | 默认浮点环境 (宏常量)


fegetexceptflag, fesetexceptflag

< c‎ | numeric‎ | fenv
定义于头文件 <fenv.h> |  |
int fegetexceptflag( fexcept_t* flagp, int excepts ); | (1) | (C99 起)
int fesetexceptflag( const fexcept_t* flagp, int excepts ); | (2) | (C99 起)

1) 试图获得列于位掩码参数 excepts 的浮点异常标志的完整内容，它是浮点异常宏的逐位或。

2) 试图从 flagp 复制列于 excepts 的浮点异常标志到浮点环境。不引发任何异常，只修改标志。

浮点异常标志的完整内容不必是指示是否引发或清除异常的布尔值。例如，它可以是结构体，包含布尔状态和触发了异常的代码地址。这些函数获得所有这种内容，并以实现定义格式于 flagp 获得/存储它。

参数

flagp | - | 指向将要存储或读取标志位置的 fexcept_t 对象的指针
excepts | - | 列出要获取/设置的异常的位掩码

返回值

成功时返回 ​0​ ，否则返回非零。

示例

#include <stdio.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON

void show_fe_exceptions(void)
{
    printf("current exceptions raised: ");
    if(fetestexcept(FE_DIVBYZERO))     printf(" FE_DIVBYZERO");
    if(fetestexcept(FE_INEXACT))       printf(" FE_INEXACT");
    if(fetestexcept(FE_INVALID))       printf(" FE_INVALID");
    if(fetestexcept(FE_OVERFLOW))      printf(" FE_OVERFLOW");
    if(fetestexcept(FE_UNDERFLOW))     printf(" FE_UNDERFLOW");
    if(fetestexcept(FE_ALL_EXCEPT)==0) printf(" none");
    printf("\n");
}

int main(void)
{
    fexcept_t excepts;

    /* 设置“当前”异常标志集合。 */
    feraiseexcept(FE_INVALID);
    show_fe_exceptions();

    /* 保存当前异常标志。 */
    fegetexceptflag(&excepts,FE_ALL_EXCEPT);

    /* 临时引发二个其他异常。 */
    feclearexcept(FE_ALL_EXCEPT);
    feraiseexcept(FE_OVERFLOW | FE_INEXACT);
    show_fe_exceptions();

    /* 恢复先前的异常标志。 */
    fesetexceptflag(&excepts,FE_ALL_EXCEPT);
    show_fe_exceptions();

    return 0;
}

输出：

current exceptions raised: FE_INVALID
current exceptions raised: FE_INEXACT FE_OVERFLOW
current exceptions raised: FE_INVALID

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.6.2.2 The fegetexceptflag function (p: 210)
  • 7.6.2.4 The fesetexceptflag function (p: 211)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.6.2.2 The fegetexceptflag function (p: 191)
  • 7.6.2.4 The fesetexceptflag function (p: 192)

参阅


feholdexcept

< c‎ | numeric‎ | fenv
定义于头文件 <fenv.h> |
int feholdexcept( fenv_t* envp ); | (C99 起)

首先，保存当前浮点环境到 envp 所指向的对象（类似 fegetenv ），然后清除所有浮点状态标志，再安装不停止模式：未来的浮点异常将不中断执行（不会陷落），直至以 feupdateenv 或 fesetenv 还原浮点状态。

此函数可用于必须从调用方隐藏它可能引发的浮点异常的子程序的起始。若只是必须抑制某些异常而必须报告其他，则通常在清除不想要的异常后，通过调用 feupdateenv 结束不停止模式。

参数

envp - 指向 fenv_t 类型对象的指针，将存储浮点环境于其中

返回值

成功时返回 ​0​ ，否则返回非零。

示例

#include <stdio.h>
#include <fenv.h>
#include <float.h>

#pragma STDC FENV_ACCESS ON

void show_fe_exceptions(void)
{
    printf("current exceptions raised: ");
    if(fetestexcept(FE_DIVBYZERO))     printf(" FE_DIVBYZERO");
    if(fetestexcept(FE_INEXACT))       printf(" FE_INEXACT");
    if(fetestexcept(FE_INVALID))       printf(" FE_INVALID");
    if(fetestexcept(FE_OVERFLOW))      printf(" FE_OVERFLOW");
    if(fetestexcept(FE_UNDERFLOW))     printf(" FE_UNDERFLOW");
    if(fetestexcept(FE_ALL_EXCEPT)==0) printf(" none");
    printf("\n");
}

double x2 (double x)   /* 乘二 */
{
    fenv_t curr_excepts;

    /* 保存并清除当前浮点异常。 */
    feholdexcept(&curr_excepts);

    /* 引发不准确和上溢异常。 */
    printf("In x2():  x = %f\n", x=x*2.0);
    show_fe_exceptions();
    feclearexcept(FE_INEXACT);   /* 从调用方隐藏不准确异常 */

    /* 将调用方的异常（ FE_INVALID ）并入剩下的 x2 的异常（ FE_OVERFLOW）。 */
    feupdateenv(&curr_excepts);
    return x;
}

int main(void)
{
    feclearexcept(FE_ALL_EXCEPT);
    feraiseexcept(FE_INVALID);   /* 一些有非法参数的计算 */
    show_fe_exceptions();
    printf("x2(DBL_MAX) = %f\n", x2(DBL_MAX));
    show_fe_exceptions();

    return 0;
}

输出：

current exceptions raised:  FE_INVALID
In x2():  x = inf
current exceptions raised:  FE_INEXACT FE_OVERFLOW
x2(DBL_MAX) = inf
current exceptions raised:  FE_INVALID FE_OVERFLOW

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.6.4.2 The feholdexcept function (p: 213-214)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.6.4.2 The feholdexcept function (p: 194-195)

参阅

feupdateenv (C99) | 恢复之前保存的浮点环境，并引发之前已经引发过的异常，使其存在于当前内存环境中 (函数)
fegetenvfesetenv (C99)(C99) | 保存或恢复当前浮点环境，包括异常的标志和数字的舍弃模式 (函数)
FE_DFL_ENV (C99) | 默认浮点环境 (宏常量)


feraiseexcept

< c‎ | numeric‎ | fenv
定义于头文件 <fenv.h> |
int feraiseexcept( int excepts ); | (C99 起)

尝试引发所有列于 excepts （浮点异常宏的逐位或）的浮点异常。若异常之一为 FE_OVERFLOW 或 FE_UNDERFLOW ，则此函数可以额外引发 FE_INEXACT 。异常的引发顺序未指定，除了 FE_OVERFLOW 和 FE_UNDERFLOW 一定先于 FE_INEXACT 引发。

参数

excepts - 列出所有要引发的异常标志的位掩码

返回值

若引发了所有列出的异常，则返回 ​0​ ，否则返回非零值。

示例

#include <stdio.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON

void show_fe_exceptions(void)
{
    printf("current exceptions raised: ");
    if(fetestexcept(FE_DIVBYZERO))     printf(" FE_DIVBYZERO");
    if(fetestexcept(FE_INEXACT))       printf(" FE_INEXACT");
    if(fetestexcept(FE_INVALID))       printf(" FE_INVALID");
    if(fetestexcept(FE_OVERFLOW))      printf(" FE_OVERFLOW");
    if(fetestexcept(FE_UNDERFLOW))     printf(" FE_UNDERFLOW");
    if(fetestexcept(FE_ALL_EXCEPT)==0) printf(" none");
    feclearexcept(FE_ALL_EXCEPT);
    printf("\n");
}

double some_computation(void)
{
    /* 计算达到引发上溢的状态。 */
    int r = feraiseexcept(FE_OVERFLOW | FE_INEXACT);
    printf("feraiseexcept() %s\n", (r?"fails":"succeeds"));
    return 0.0;
}

int main(void)
{
    some_computation();
    show_fe_exceptions();

    return 0;
}

输出：

feraiseexcept() succeeds
current exceptions raised:  FE_INEXACT FE_OVERFLOW

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.6.2.3 The feraiseexcept function (p: 210)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.6.2.3 The feraiseexcept function (p: 191)

参阅

feclearexcept (C99) | 清除指定的浮点异常状态标志 (函数)
fetestexcept (C99) | 确认设置了哪些浮点异常状态标志 (函数)


fegetround, fesetround

< c‎ | numeric‎ | fenv
定义于头文件 <fenv.h> |  |
int fesetround( int round ); | (1) | (C99 起)
int fegetround(void); | (2) | (C99 起)
1) 试图建立等于参数 round 的浮点舍入方向，期待参数为浮点舍入宏之一。
2) 返回对应当前舍入方向的浮点舍入宏。

参数

round - 舍入方向，浮点舍入宏之一

返回值

1) 成功时为 ​0​ ，否则为非零。

2) 描述当前舍入方向的浮点舍入宏，或若不能确定方向则为负值

注意

当前舍入方向反映最近的 fesetround 的效果，亦能以 FLT_ROUNDS 查询。

示例

#include <stdio.h>
#include <math.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON
void show_fe_current_rounding_method(void)
{
    printf("current rounding method:  ");
    switch (fegetround()) {
           case FE_TONEAREST:  printf ("FE_TONEAREST");  break;
           case FE_DOWNWARD:   printf ("FE_DOWNWARD");   break;
           case FE_UPWARD:     printf ("FE_UPWARD");     break;
           case FE_TOWARDZERO: printf ("FE_TOWARDZERO"); break;
           default:            printf ("unknown");
    };
    printf("\n");
}

int main(void)
{
    /* 默认舍入方法 */
    show_fe_current_rounding_method();
    printf("+11.5 -> %+4.1f\n", rint(+11.5)); /* 两整数的中央值 */
    printf("+12.5 -> %+4.1f\n", rint(+12.5)); /* 两整数的中央值 */

    /* 保存舍入方法。 */
    int curr_method = fegetround();

    /* 临时更改当前舍入方法。 */
    fesetround(FE_DOWNWARD);
    show_fe_current_rounding_method();
    printf("+11.5 -> %+4.1f\n", rint(+11.5));
    printf("+12.5 -> %+4.1f\n", rint(+12.5));

    /* 恢复舍入方法。 */
    fesetround(curr_method);
    show_fe_current_rounding_method();

    return 0;
}

可能的输出：

current rounding method:  FE_TONEAREST
+11.5 -> +12.0
+12.5 -> +12.0
current rounding method:  FE_DOWNWARD
+11.5 -> +11.0
+12.5 -> +12.0
current rounding method:  FE_TONEAREST

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.6.3.1 The fegetround function (p: 212)
  • 7.6.3.2 The fesetround function (p: 212-213)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.6.3.1 The fegetround function (p: 193)
  • 7.6.3.2 The fesetround function (p: 193-194)

参阅

nearbyintnearbyintfnearbyintl (C99)(C99)(C99) | 用当前舍入模式取整到整数 (函数)
rintrintfrintllrintlrintflrintlllrintllrintfllrintl (C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99) | 使用当前舍入模式取整到整数，若结果有误则产生异常 (函数)


fetestexcept

< c‎ | numeric‎ | fenv
定义于头文件 <fenv.h> |
int fetestexcept( int excepts ); | (C99 起)

确定当前设置了哪个指定的浮点异常子集。参数 excepts 是浮点异常宏的逐位或。

参数

excepts - 列出待测试异常标志的位掩码

返回值

包含于 excepts 而且对应于当前设置的浮点异常中的浮点异常宏的逐位或。

示例

#include <stdio.h>
#include <math.h>
#include <fenv.h>
#include <float.h>

#pragma STDC FENV_ACCESS ON

void show_fe_exceptions(void)
{
    printf("current exceptions raised: ");
    if(fetestexcept(FE_DIVBYZERO))     printf(" FE_DIVBYZERO");
    if(fetestexcept(FE_INEXACT))       printf(" FE_INEXACT");
    if(fetestexcept(FE_INVALID))       printf(" FE_INVALID");
    if(fetestexcept(FE_OVERFLOW))      printf(" FE_OVERFLOW");
    if(fetestexcept(FE_UNDERFLOW))     printf(" FE_UNDERFLOW");
    if(fetestexcept(FE_ALL_EXCEPT)==0) printf(" none");
    printf("\n");
}

int main(void)
{
    /* 显示默认浮点标志集合。 */
    show_fe_exceptions();

    /* 进行一些引发浮点异常的计算。 */
    printf("1.0/0.0     = %f\n", 1.0/0.0);        /* FE_DIVBYZERO            */
    printf("1.0/10.0    = %f\n", 1.0/10.0);       /* FE_INEXACT              */
    printf("sqrt(-1)    = %f\n", sqrt(-1));       /* FE_INVALID              */
    printf("DBL_MAX*2.0 = %f\n", DBL_MAX*2.0);    /* FE_INEXACT FE_OVERFLOW  */
    printf("nextafter(DBL_MIN/pow(2.0,52),0.0) = %.1f\n",
           nextafter(DBL_MIN/pow(2.0,52),0.0));   /* FE_INEXACT FE_UNDERFLOW */
    show_fe_exceptions();

    return 0;
}

输出：

current exceptions raised:  none
1.0/0.0     = inf
1.0/10.0    = 0.100000
sqrt(-1)    = -nan
DBL_MAX*2.0 = inf
nextafter(DBL_MIN/pow(2.0,52),0.0) = 0.0
current exceptions raised:  FE_DIVBYZERO FE_INEXACT FE_INVALID FE_OVERFLOW FE_UNDERFLOW

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.6.2.5 The fetestexcept function (p: 211-212)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.6.2.5 The fetestexcept function (p: 192-193)

参阅

feclearexcept
(C99)
 清除指定的浮点异常状态标志
(函数)


feupdateenv

< c‎ | numeric‎ | fenv
定义于头文件 <fenv.h> |
int feupdateenv( const fenv_t* envp ); | (C99 起)

首先，回忆当前引发的浮点异常，然后从 envp 所指向的对象恢复浮点环境（类似 fesetenv ），再引发保存的浮点异常。

此函数可用于结束先前调用 feholdexcept 建立的不停止模式。

参数

envp - 指向 fenv_t 类型对象的指针，对象为之前到 feholdexcept 或 fegetenv 的调用所设，或等于 FE_DFL_ENV

返回值

成功时为 ​0​ ，否则为非零。

示例

#include <stdio.h>
#include <fenv.h>
#include <float.h>

#pragma STDC FENV_ACCESS ON

void show_fe_exceptions(void)
{
    printf("current exceptions raised: ");
    if(fetestexcept(FE_DIVBYZERO))     printf(" FE_DIVBYZERO");
    if(fetestexcept(FE_INEXACT))       printf(" FE_INEXACT");
    if(fetestexcept(FE_INVALID))       printf(" FE_INVALID");
    if(fetestexcept(FE_OVERFLOW))      printf(" FE_OVERFLOW");
    if(fetestexcept(FE_UNDERFLOW))     printf(" FE_UNDERFLOW");
    if(fetestexcept(FE_ALL_EXCEPT)==0) printf(" none");
    printf("\n");
}

double x2 (double x)   /* 乘二 */
{
    fenv_t curr_excepts;

    /* 保存并清理当前浮点环境。 */
    feholdexcept(&curr_excepts);

    /* 引发不准确和溢出异常。 */
    printf("In x2():  x = %f\n", x=x*2.0);
    show_fe_exceptions();
    feclearexcept(FE_INEXACT);   /* 从调用方隐藏不准确异常 */

    /* 将调用方的异常（FE_INVALID）并入        */
    /* 剩下的x2的异常（FE_OVERFLOW）。 */
    feupdateenv(&curr_excepts);
    return x;
}

int main(void)
{
    feclearexcept(FE_ALL_EXCEPT);
    feraiseexcept(FE_INVALID);   /* 一些带有非法参数的计算 */
    show_fe_exceptions();
    printf("x2(DBL_MAX) = %f\n", x2(DBL_MAX));
    show_fe_exceptions();

    return 0;
}

输出：

current exceptions raised:  FE_INVALID
In x2():  x = inf
current exceptions raised:  FE_INEXACT FE_OVERFLOW
x2(DBL_MAX) = inf
current exceptions raised:  FE_INVALID FE_OVERFLOW

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.6.4.4 The feupdateenv function (p: 214-215)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.6.4.4 The feupdateenv function (p: 195-196)

参阅

feholdexcept (C99) | 保存当前环境的异常状态标志，再清除所有异常状态标志，并忽略所有未来错误 (函数)
fegetenvfesetenv (C99)(C99) | 保存或恢复当前浮点环境，包括异常的标志和数字的舍弃模式 (函数)
FE_DFL_ENV (C99) | 默认浮点环境 (宏常量)


常用数学函数

< c‎ | numeric

函数

定义于头文件 <stdlib.h>
abslabsllabs
(C99)
 计算整数值的绝对值（ \(\small{|x|}\)|x| ）
(函数)
divldivlldiv
(C99)
 计算整数除法的商和余数
(函数)
定义于头文件 <inttypes.h>
imaxabs
(C99)
 计算整数值的绝对值（ \(\small{|x|}\)|x| ）
(函数)
imaxdiv
(C99)
 计算整数除法的商和余数
(函数)
定义于头文件 <math.h>
基本运算
fabsfabsffabsl
(C99)(C99)
 计算浮点值的绝对值（ \(\small{|x|}\)|x| ）
(函数)
fmodfmodffmodl
(C99)(C99)
 计算浮点除法运算的余数
(函数)
remainderremainderfremainderl
(C99)(C99)(C99)
 计算浮点除法运算的带符号余数
(函数)
remquoremquofremquol
(C99)(C99)(C99)
 计算除法运算的带符号余数，以及商的后三位
(函数)
fmafmaffmal
(C99)(C99)(C99)
 计算结合的乘加运算
(函数)
fmaxfmaxffmaxl
(C99)(C99)(C99)
 确定两个浮点值的较大者
(函数)
fminfminffminl
(C99)(C99)(C99)
 确定两个浮点值的较小者
(函数)
fdimfdimffdiml
(C99)(C99)(C99)
 确定两个浮点值的非负数差（ \({\small\max{(0, x-y)} }\)max(0, x-y) ）
(函数)
nannanfnanl
(C99)(C99)(C99)
 返回 NaN （非数）
(函数)
指数函数
expexpfexpl
(C99)(C99)
 计算 e 的给定次幂 （ \({\small e^x}\)ex ）
(函数)
exp2exp2fexp2l
(C99)(C99)(C99)
 计算 2 的给定次幂（ \({\small 2^x}\)2x ）
(函数)
expm1expm1fexpm1l
(C99)(C99)(C99)
 计算 e 的给定次幂减一（ \({\small e^x-1}\)ex-1 ）
(函数)
loglogflogl
(C99)(C99)
 计算自然对数（底为 e ）（ \({\small \ln{x} }\)ln(x) ）
(函数)
log10log10flog10l
(C99)(C99)
 计算常用对数 （底为 10 ）（ \({\small \log_{10}{x} }\)log10(x) ）
(函数)
log2log2flog2l
(C99)(C99)(C99)
 计算底为 2 的对数（ \({\small \log_{2}{x} }\)log2(x) ）
(函数)
log1plog1pflog1pl
(C99)(C99)(C99)
 计算给定数加 1 的自然对数（底为 e ）（ \({\small \ln{(1+x)} }\)ln(1+x) ）
(函数)
幂函数
powpowfpowl
(C99)(C99)
 计算一个数的给定次幂（ \(\small{x^y}\)xy ）
(函数)
sqrtsqrtfsqrtl
(C99)(C99)
 计算平方根（ \(\small{\sqrt{x} }\)√x ）
(函数)
cbrtcbrtfcbrtl
(C99)(C99)(C99)
 计算立方根（ \(\small{\sqrt[3]{x} }\)3√x ）
(函数)
hypothypotfhypotl
(C99)(C99)(C99)
 计算两个给定数平方和的平方根 （ \(\scriptsize{\sqrt{x^2+y^2} }\)√x2
+y2
 ）
(函数)
三角函数
sinsinfsinl
(C99)(C99)
 计算正弦（ \({\small\sin{x} }\)sin(x) ）
(函数)
coscosfcosl
(C99)(C99)
 计算余弦（ \({\small\cos{x} }\)cos(x) ）
(函数)
tantanftanl
(C99)(C99)
 计算正切（ \({\small\tan{x} }\)tan(x) ）
(函数)
asinasinfasinl
(C99)(C99)
 计算反正弦（ \({\small\arcsin{x} }\)arcsin(x) ）
(函数)
acosacosfacosl
(C99)(C99)
 计算反余弦（ \({\small\arccos{x} }\)arccos(x) ）
(函数)
atanatanfatanl
(C99)(C99)
 计算反正切（ \({\small\arctan{x} }\)arctan(x) ）
(函数)
atan2atan2fatan2l
(C99)(C99)
 计算反正切，以符号确定象限
(函数)
双曲函数
sinhsinhfsinhl
(C99)(C99)
 计算双曲正弦（ \({\small\sinh{x} }\)sinh(x) ）
(函数)
coshcoshfcoshl
(C99)(C99)
 计算双曲余弦（ \({\small\cosh{x} }\)cosh(x) ）
(函数)
tanhtanhftanhl
(C99)(C99)
 计算双曲正切（ \({\small\tanh{x} }\)tanh(x) ）
(函数)
asinhasinhfasinhl
(C99)(C99)(C99)
 计算反双曲正弦（ \({\small\operatorname{arsinh}{x} }\)arsinh(x) ）
(函数)
acoshacoshfacoshl
(C99)(C99)(C99)
 计算反双曲余弦（ \({\small\operatorname{arcosh}{x} }\)arcosh(x) ）
(函数)
atanhatanhfatanhl
(C99)(C99)(C99)
 计算反双曲正切（ \({\small\operatorname{artanh}{x} }\)artanh(x) ）
(函数)
误差及伽马函数
erferfferfl
(C99)(C99)(C99)
 计算误差函数
(函数)
erfcerfcferfcl
(C99)(C99)(C99)
 计算补误差函数
(函数)
tgammatgammaftgammal
(C99)(C99)(C99)
 计算伽马函数
(函数)
lgammalgammaflgammal
(C99)(C99)(C99)
 计算伽马函数的自然对数（底为 e ）
(函数)
临近整数的浮点运算
ceilceilfceill
(C99)(C99)
 计算不小于给定值的最小整数
(函数)
floorfloorffloorl
(C99)(C99)
 计算不大于给定值的最大整数
(函数)
trunctruncftruncl
(C99)(C99)(C99)
 取整到绝对值不大于给定值的最接近整数
(函数)
roundroundfroundllroundlroundflroundllroundllroundfllroundl
(C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99)
 取整到最接近的整数，在相邻整数正中间时取远离零的数
(函数)
nearbyintnearbyintfnearbyintl
(C99)(C99)(C99)
 用当前舍入模式取整到整数
(函数)
rintrintfrintllrintlrintflrintlllrintllrintfllrintl
(C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99)
 使用当前舍入模式取整到整数，若结果有误则产生异常
(函数)
浮点数操作函数
frexpfrexpffrexpl
(C99)(C99)
 将数拆分成有效数字和 2 的幂次
(函数)
ldexpldexpfldexpl
(C99)(C99)
 将数乘以 2 的幂
(函数)
modfmodffmodfl
(C99)(C99)
 把一个数拆分成整数和小数部分
(函数)
scalbnscalbnfscalbnlscalblnscalblnfscalblnl
(C99)(C99)(C99)(C99)(C99)(C99)
 高效计算一个数乘 FLT_RADIX 的幂
(函数)
ilogbilogbfilogbl
(C99)(C99)(C99)
 提取给定数的指数（结果为整数）
(函数)
logblogbflogbl
(C99)(C99)(C99)
 提取给定数的指数（结果为浮点数）
(函数)
nextafternextafterfnextafterlnexttowardnexttowardfnexttowardl
(C99)(C99)(C99)(C99)(C99)(C99)
 确定到给定值方向的下一个可表示的浮点数值
(函数)
copysigncopysignfcopysignl
(C99)(C99)(C99)
 从一个给定值的绝对值和另一个给定值的符号产生值
(函数)
分类及比较
fpclassify
(C99)
 对给定的浮点值分类
(宏函数)
isfinite
(C99)
 检查给定数是否具有有限值
(宏函数)
isinf
(C99)
 检查给定数是否是无穷大
(宏函数)
isnan
(C99)
 检查给定数是否为 NaN
(宏函数)
isnormal
(C99)
 检查给定数是否正规
(宏函数)
signbit
(C99)
 检查给定数是不是负数
(宏函数)
isgreater
(C99)
 检查第一个浮点参数是否大于第二个
(宏函数)
isgreaterequal
(C99)
 检查第一个浮点参数是否大于等于第二个
(宏函数)
isless
(C99)
 检查第一个浮点参数是否小于第二个
(宏函数)
islessequal
(C99)
 检查第一个浮点参数是否小于或等于第二个
(宏函数)
islessgreater
(C99)
 检查第一个浮点参数是否小于或大于第二个
(宏函数)
isunordered
(C99)
 检查两个浮点数值是否无序
(宏函数)

类型

定义于头文件 <stdlib.h>
div_t | div 函数返回的结构体类型 (typedef)
ldiv_t | ldiv 函数返回的结构体类型 (typedef)
lldiv_t | lldiv 函数返回的结构体类型 (typedef)
定义于头文件 <inttypes.h>
imaxdiv_t | imaxdiv 函数返回的结构体类型 (typedef)
定义于头文件 <math.h>
float_t (C99) | 宽度至少等于 float 的最高效浮点类型 (typedef)
double_t (C99) | 宽度至少等于 double 的最高效浮点类型 (typedef)

宏常量

定义于头文件 <math.h>
HUGE_VALFHUGE_VALHUGE_VALL
(C99)(C99)
 分别指示过大而无法以 float 、 double 和 long double 表示的值（无穷大）
(宏常量)
INFINITY
(C99)
 求值为正无穷大或保证溢出 float 的值
(宏常量)
NAN
(C99)
 求值为 float 类型的安静 NaN
(宏常量)
FP_FAST_FMAFFP_FAST_FMAFP_FAST_FMAL
(C99)(C99)(C99)
 指示 fma 函数与运算数的一次乘法和一次加法相比，执行速度相当或更快
(宏常量)
FP_ILOGB0FP_ILOGBNAN
(C99)(C99)
 分别求值为当 x 为 0 或 NaN 时的 ilogb(x)
(宏常量)
math_errhandlingMATH_ERRNOMATH_ERREXCEPT
(C99)(C99)(C99)
 定义用于常用数学函数的错误处理机制
(宏常量)
分类
FP_NORMALFP_SUBNORMALFP_ZEROFP_INFINITEFP_NAN
(C99)(C99)(C99)(C99)(C99)
 指示浮点数类别
(宏常量)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.8 Format conversion of integer types <inttypes.h> (p: 217-220)
  • 7.12 Mathematics <math.h> (p: 231-261)
  • 7.22 General utilities <stdlib.h> (p: 340-360)
  • 7.31.5 Format conversion of integer types <inttypes.h> (p: 455)
  • 7.31.12 General utilities <stdlib.h> (p: 456)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.8 Format conversion of integer types <inttypes.h> (p: 198-201)
  • 7.12 Mathematics <math.h> (p: 212-242)
  • 7.20 General utilities <stdlib.h> (p: 306-324)
  • 7.26.4 Format conversion of integer types <inttypes.h> (p: 401)
  • 7.26.10 General utilities <stdlib.h> (p: 402)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5 MATHEMATICS <math.h>
  • 4.10 GENERAL UTILITIES <stdlib.h>
  • 4.13.4 Mathematics <math.h>
  • 7.13.7 General utilities <stdlib.h>

参阅


FP_NORMAL, FP_SUBNORMAL, FP_ZERO, FP_INFINITE, FP_NAN

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define FP_NORMAL /*implementation defined*/ | (C99 起)
#define FP_SUBNORMAL /*implementation defined*/ | (C99 起)
#define FP_ZERO /*implementation defined*/ | (C99 起)
#define FP_INFINITE /*implementation defined*/ | (C99 起)
#define FP_NAN /*implementation defined*/ | (C99 起)

FP_NORMAL 、 FP_SUBNORMAL 、 FP_ZERO 、 FP_INFINITE 、 FP_NAN 宏各代表一个独自的浮点数类别。它们都展开成整数常量表达式。

常量 | 解释
FP_NORMAL | 指示值为正规，即不是无穷大、非正规、非数或零
FP_SUBNORMAL | 指示值为非正规
FP_ZERO | 指示值为正或负零
FP_INFINITE | 指示值无法以底层类型表示（正或负无穷大）
FP_NAN | 指示值是非数（ NaN ）

示例

#include <stdio.h>
#include <math.h>
#include <float.h>

const char *show_classification(double x) {
    switch(fpclassify(x)) {
        case FP_INFINITE:  return "Inf";
        case FP_NAN:       return "NaN";
        case FP_NORMAL:    return "normal";
        case FP_SUBNORMAL: return "subnormal";
        case FP_ZERO:      return "zero";
        default:           return "unknown";
    }
}
int main(void)
{
    printf("1.0/0.0 is %s\n", show_classification(1/0.0));
    printf("0.0/0.0 is %s\n", show_classification(0.0/0.0));
    printf("DBL_MIN/2 is %s\n", show_classification(DBL_MIN/2));
    printf("-0.0 is %s\n", show_classification(-0.0));
    printf(" 1.0 is %s\n", show_classification(1.0));
}

输出：

1.0/0.0 is Inf
0.0/0.0 is NaN
DBL_MIN/2 is subnormal
-0.0 is zero
 1.0 is normal

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12/6 FP_NORMAL, ... (p: 232)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12/6 FP_NORMAL, ... (p: 213)

参阅

fpclassify
(C99)
 对给定的浮点值分类
(宏函数)


HUGE_VALF, HUGE_VAL, HUGE_VALL

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define HUGE_VALF /*implementation defined*/ | (C99 起)
#define HUGE_VAL /*implementation defined*/ |
#define HUGE_VALL /*implementation defined*/ | (C99 起)

HUGE_VALF 、 HUGE_VAL 和 HUGE_VALL 宏展开成正浮点常量表达式，它们比较等于上溢情况中浮点函数和运算符的返回值（见 math_errhandling ）。

常量 | 解释
HUGE_VALF | 展开成指示上溢的正 float 表达式
HUGE_VAL | 展开成指示上溢的正 double 表达式，不必可表示为 float
HUGE_VALL | 展开成指示上溢的正 long double 表达式，不必可表示为 float 或 double

在支持浮点无穷大的平台上，这些宏始终分别展开成 float 、 double 和 long double 的正无穷大。

示例

#include <math.h>
#include <stdio.h>
int main(void)
{
    double result = 1.0/0.0;
    printf("1.0/0.0 = %f\n", result);
    if (result == HUGE_VAL)
        puts("1.0/0.0 == HUGE_VAL\n");
}

可能的输出：

1.0/0.0 = inf
1.0/0.0 == HUGE_VAL

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12/3 HUGE_VAL, HUGE_VALF, HUGE_VALL (p: 231)
  • F.10/2 HUGE_VAL, HUGE_VALF, HUGE_VALL (p: 517)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12/3 HUGE_VAL, HUGE_VALF, HUGE_VALL (p: 212)
  • F.9/2 HUGE_VAL, HUGE_VALF, HUGE_VALL (p: 454)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5 HUGE_VAL

参阅

INFINITY
(C99)
 求值为正无穷大或保证溢出 float 的值
(宏常量)


INFINITY

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define INFINITY /*implementation defined*/ | (C99 起)

若实现支持浮点无穷大，则宏 INFINITY 展开成求值为正或无符号无穷大的 float 类型常量表达式。

若实现不支持浮点无穷大，则宏 INFINITY 展开成保证在编译时上溢 float 的正值，而此宏的使用生成编译器警告。

用于打印无穷大的风格是实现定义的。

示例

显示用于打印无穷大的风格及其 IEEE 格式。

#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>

int main(void)
{
    double f = INFINITY;
    uint64_t fn; memcpy(&fn, &f, sizeof f);
    printf("INFINITY:   %f %" PRIx64 "\n", f, fn);
}

可能的输出：

INFINITY:   inf 7ff0000000000000

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12/4 INFINITY (p: 231-232)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12/4 INFINITY (p: 212-213)

参阅

isinf (C99) | 检查给定数是否是无穷大 (宏函数)
HUGE_VALFHUGE_VALHUGE_VALL (C99)(C99) | 分别指示过大而无法以 float 、 double 和 long double 表示的值（无穷大） (宏常量)


abs, labs, llabs, imaxabs

< c‎ | numeric‎ | math
定义于头文件 <stdlib.h> |
int abs( int n ); |
long labs( long n ); |
long long llabs( long long n ); | (C99 起)
定义于头文件 <inttypes.h> |
intmax_t imaxabs( intmax_t n ); | (C99 起)

计算整数的绝对值。若返回类型无法表示结果，则行为未定义。

参数

n - 整数值

返回值

n 的绝对值（即 |n| ），若它能表示。

注意

在补码中，最负的值的绝对值处于对应整数范围外，例如对于 32 位补码类型整数， INT_MIN 为 -2147483648 ，但其绝对值应有的结果是 2147483648 ，大于 INT_MAX ，其值为 2147483647 。

示例

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int main(void)
{
    printf("abs(+3) = %d\n", abs(+3));
    printf("abs(-3) = %d\n", abs(-3));

//  printf("%+d\n", abs(INT_MIN)); // 在补码系统上是未定义行为
}

输出：

abs(+3) = 3
abs(-3) = 3

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.8.2.1 The imaxabs function (p: 218)
  • 7.22.6.1 The abs, labs and llabs functions (p: 356)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.8.2.1 The imaxabs function (p: 199-200)
  • 7.20.6.1 The abs, labs and llabs functions (p: 320)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.6.1 The abs function
  • 4.10.6.3 The labs function

参阅

fabsfabsffabsl (C99)(C99) | 计算浮点值的绝对值（ \(\small{|x|}\)|x| ） (函数)
cabscabsfcabsl (C99)(C99)(C99) | 计算复数的模（绝对值） (函数)


acos, acosf, acosl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float acosf( float arg ); | (1) | (C99 起)
double acos( double arg ); | (2) |
long double acosl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define acos( arg ) | (4) | (C99 起)
1-3) 计算 arg 的弧（反）余弦主值。
4) 泛型宏：若参数拥有 long double 类型，则调用 acosl 。否则，若参数拥有整数类型或 double 类型，则调用 acos 。否则调用 acosf 。若参数为复数，则宏调用对应的复数函数（ cacosf 、 cacos 、 cacosl ）。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 于范围 [0 ; π] 中的弧（反）余弦（ arccos(arg) ）。

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 在范围 [-1.0; 1.0] 外则出现定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 +1 ，则返回值 +0 。
  • 若 |arg| > 1 ，则返回定义域错误并返回 NaN 。
  • 若参数为 NaN ，则返回 NaN 。

示例

#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <fenv.h>
#include <string.h>

#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("acos(-1) = %f\n", acos(-1));
    printf("acos(0.0) = %f 2*acos(0.0) = %f\n", acos(0), 2*acos(0));
    printf("acos(0.5) = %f 3*acos(0.5) = %f\n", acos(0.5), 3*acos(0.5));
    printf("acos(1) = %f\n", acos(1));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("acos(1.1) = %f\n", acos(1.1));
    if(errno == EDOM) perror("    errno == EDOM");
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID raised");
}

可能的输出：

acos(-1) = 3.141593
acos(0.0) = 1.570796 2*acos(0.0) = 3.141593
acos(0.5) = 1.047198 3*acos(0.5) = 3.141593
acos(1) = 0.000000
acos(1.1) = nan
    errno == EDOM: Numerical argument out of domain
    FE_INVALID raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.4.1 The acos functions (p: 238)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.1.1 The acos functions (p: 518)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.4.1 The acos functions (p: 218)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.1.1 The acos functions (p: 455)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.2.1 The acos function

参阅

asinasinfasinl (C99)(C99) | 计算反正弦（ \({\small\arcsin{x} }\)arcsin(x) ） (函数)
atanatanfatanl (C99)(C99) | 计算反正切（ \({\small\arctan{x} }\)arctan(x) ） (函数)
atan2atan2fatan2l (C99)(C99) | 计算反正切，以符号确定象限 (函数)
coscosfcosl (C99)(C99) | 计算余弦（ \({\small\cos{x} }\)cos(x) ） (函数)
cacoscacosfcacosl (C99)(C99)(C99) | 计算复数反余弦 (函数)


acosh, acoshf, acoshl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float acoshf( float arg ); | (1) | (C99 起)
double acosh( double arg ); | (2) | (C99 起)
long double acoshl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define acosh( arg ) | (4) | (C99 起)
1-3) 计算 arg 的反双曲余弦。
4) 泛型宏：若参数拥有 long double 类型，则调用 acoshl 。否则，若参数拥有整数类型或 double 类型，则调用 acosh 。否则调用 acoshf 。若参数为复数，则宏调用对应的复数函数（ cacoshf 、 cacosh 、 cacoshl ）。

参数

arg - 表示双曲扇形面积的浮点值

返回值

若不出现错误，则返回 arg 在区间 [0, +∞] 上的反双曲余弦（ cosh-1
(arg) 或 arcosh(arg) ）。

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

错误处理

报告 math_errhandling 中指定的错误。

若参数小于 1 ，则出现定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数小于 1 ，则引发 FE_INVALID 并返回 NaN
  • 若参数为 1 ，则返回 +0
  • 若参数为 +∞ ，则返回 +∞
  • 若参数为 NaN ，则返回 NaN

注意

尽管 C 标准命名此函数为“弧双曲余弦”，双曲函数的反函数仍是面积函数。其参数是双曲扇形的面积，而非弧长。正确的名称是“反双曲余弦”（ POSIX 所用）或“面积双曲余弦”。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <errno.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("acosh(1) = %f\nacosh(10) = %f\n", acosh(1), acosh(10));
    printf("acosh(DBL_MAX) = %f\nacosh(Inf) = %f\n", acosh(DBL_MAX), acosh(INFINITY));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("acosh(0.5) = %f\n", acosh(0.5));
    if(errno == EDOM)         perror("    errno == EDOM");
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID raised");
}

可能的输出：

acosh(1) = 0.000000
acosh(10) = 2.993223
acosh(DBL_MAX) = 710.475860
acosh(Inf) = inf
acosh(0.5) = -nan
    errno == EDOM: Numerical argument out of domain
    FE_INVALID raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.5.1 The acosh functions (p: 240)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.2.1 The acosh functions (p: 520)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.5.1 The acosh functions (p: 221)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.2.1 The acosh functions (p: 457)

参阅

asinhasinhfasinhl (C99)(C99)(C99) | 计算反双曲正弦（ \({\small\operatorname{arsinh}{x} }\)arsinh(x) ） (函数)
atanhatanhfatanhl (C99)(C99)(C99) | 计算反双曲正切（ \({\small\operatorname{artanh}{x} }\)artanh(x) ） (函数)
coshcoshfcoshl (C99)(C99) | 计算双曲余弦（ \({\small\cosh{x} }\)cosh(x) ） (函数)
cacoshcacoshfcacoshl (C99)(C99)(C99) | 计算复数反双曲余弦 (函数)

外部链接

Weisstein, Eric W. “反双曲余弦”来自 MathWorld--A Wolfram Web Resource 。


asin, asinf, asinl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float asinf( float arg ); | (1) | (C99 起)
double asin( double arg ); | (2) |
long double asinl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define asin( arg ) | (4) | (C99 起)
1-3) 计算 arg 的弧（反）正弦主值。
4) 泛型宏：若参数拥有 long double 类型，则调用 asinl 。否则，若参数拥有整数类型或 double 类型，则调用 asin 。否则调用 asinf 。若参数为复数，则宏调用对应的复数函数（ casinf 、 casin 、 casinl ）。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 在范围 [-
π
2
; +
π
2
] 中的弧（反）正弦（ arcsin(arg) ）。

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 在范围 [-1.0; 1.0] 外则出现定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回不修改的参数。
  • 若 |arg| > 1 ，则出现定义域错误并返回 NaN 。
  • 若参数为 NaN ，则返回 NaN 。

示例

#include <math.h>
#include <stdio.h>
#include <errno.h>
#include <fenv.h>
#include <string.h>

#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("asin( 1.0) = %+f, 2*asin( 1.0)=%+f\n", asin(1), 2*asin(1));
    printf("asin(-0.5) = %+f, 6*asin(-0.5)=%+f\n", asin(-0.5), 6*asin(-0.5));
    // 特殊值
    printf("asin(0.0) = %1f, asin(-0.0)=%f\n", asin(+0.0), asin(-0.0));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("asin(1.1) = %f\n", asin(1.1));
    if(errno == EDOM) perror("    errno == EDOM");
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID raised");
}

可能的输出：

asin( 1.0) = +1.570796, 2*asin( 1.0)=+3.141593
asin(-0.5) = -0.523599, 6*asin(-0.5)=-3.141593
asin(0.0) = 0.000000, asin(-0.0)=-0.000000
asin(1.1) = nan
    errno == EDOM: Numerical argument out of domain
    FE_INVALID raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.4.2 The asin functions (p: 238)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.1.2 The asin functions (p: 518)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.4.2 The asin functions (p: 219)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.1.2 The asin functions (p: 456)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.2.2 The asin function

参阅

acosacosfacosl (C99)(C99) | 计算反余弦（ \({\small\arccos{x} }\)arccos(x) ） (函数)
atanatanfatanl (C99)(C99) | 计算反正切（ \({\small\arctan{x} }\)arctan(x) ） (函数)
atan2atan2fatan2l (C99)(C99) | 计算反正切，以符号确定象限 (函数)
sinsinfsinl (C99)(C99) | 计算正弦（ \({\small\sin{x} }\)sin(x) ） (函数)
casincasinfcasinl (C99)(C99)(C99) | 计算复数反正弦 (函数)


asinh, asinhf, asinhl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float asinhf( float arg ); | (1) | (C99 起)
double asinh( double arg ); | (2) | (C99 起)
long double asinhl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define asinh( arg ) | (4) | (C99 起)
1-3) 计算 arg 的反双曲正弦。
4) 泛型宏：若参数拥有 long double 类型，则调用 asinhl 。否则，若参数拥有整数类型或 double 类型，则调用 asinh 。否则调用 asinhf 。若参数为复数，则宏调用对应的复数函数（ casinhf 、 casinh 、 casinhl ）。

参数

arg - 表示双曲扇形面积的浮点值

返回值

若不发生错误，则返回 arg 的反双曲正弦（ sinh-1
(arg) 或 arsinh(arg) ）。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 或 ±∞ ，则返回不修改的参数
  • 若参数为 NaN ，则返回 NaN

注意

尽管 C 标准命名此函数为“弧双曲正弦”，双曲函数的反函数仍是面积函数。其参数为双曲扇形的面积，而非弧长。正确的名称是“反双曲正弦”（ POSIX 所用）或“面积双曲正弦”。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    printf("asinh(1) = %f\nasinh(-1) = %f\n", asinh(1), asinh(-1));
    // 特殊值
    printf("asinh(+0) = %f\nasinh(-0) = %f\n", asinh(0.0), asinh(-0.0));
}

输出：

asinh(1) = 0.881374
asinh(-1) = -0.881374
asinh(+0) = 0.000000
asinh(-0) = -0.000000

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.5.2 The asinh functions (p: 240-241)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.2.2 The asinh functions (p: 520)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.5.2 The asinh functions (p: 221)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.2.2 The asinh functions (p: 457)

参阅

acoshacoshfacoshl (C99)(C99)(C99) | 计算反双曲余弦（ \({\small\operatorname{arcosh}{x} }\)arcosh(x) ） (函数)
atanhatanhfatanhl (C99)(C99)(C99) | 计算反双曲正切（ \({\small\operatorname{artanh}{x} }\)artanh(x) ） (函数)
sinhsinhfsinhl (C99)(C99) | 计算双曲正弦（ \({\small\sinh{x} }\)sinh(x) ） (函数)
casinhcasinhfcasinhl (C99)(C99)(C99) | 计算复数反双曲正弦 (函数)

外部链接

Weisstein, Eric W. “反双曲正弦”来自 MathWorld--A Wolfram Web Resource 。


atan, atanf, atanl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float atanf( float arg ); | (1) | (C99 起)
double atan( double arg ); | (2) |
long double atanl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define atan( arg ) | (4) | (C99 起)
1-3) 计算 arg 的弧（反）正切主值。
4) 泛型宏：若参数拥有 long double 类型，则调用 atanl 。否则，若参数拥有整数类型或 double 类型，则调用 atan 。否则调用 atanf 。若参数为复数，则宏调用对应的复数函数（ catanf 、 catan 、 catanl ）。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 在 [-
π
2
; +
π
2
] 弧度范围中的弧（反）正切（ arctan(arg) ）。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回不修改的参数
  • 若参数为 +∞ ，则返回 +π/2
  • 若参数为 -∞ ，则返回 -π/2
  • 若参数为 NaN ，则返回 NaN

注意

POSIX 指定在下溢情况下，返回不修改的 arg ，而若不支持如此，则返回不大于 DBL_MIN 、 FLT_MIN 和 LDBL_MIN 的实现定义值。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    printf("atan(1) = %f, 4*atan(1)=%f\n", atan(1), 4*atan(1));
    // 特殊值
    printf("atan(Inf) = %f, 2*atan(Inf) = %f\n", atan(INFINITY), 2*atan(INFINITY));
    printf("atan(-0.0) = %+f, atan(+0.0) = %+f\n", atan(-0.0), atan(0));
}

输出：

atan(1) = 0.785398, 4*atan(1)=3.141593
atan(Inf) = 1.570796, 2*atan(Inf) = 3.141593
atan(-0.0) = -0.000000, atan(+0.0) = +0.000000

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.4.3 The atan functions (p: 238-239)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.1.3 The atan functions (p: 519)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.4.3 The atan functions (p: 219)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.1.3 The atan functions (p: 456)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.2.3 The atan function

参阅

atan2atan2fatan2l (C99)(C99) | 计算反正切，以符号确定象限 (函数)
asinasinfasinl (C99)(C99) | 计算反正弦（ \({\small\arcsin{x} }\)arcsin(x) ） (函数)
acosacosfacosl (C99)(C99) | 计算反余弦（ \({\small\arccos{x} }\)arccos(x) ） (函数)
tantanftanl (C99)(C99) | 计算正切（ \({\small\tan{x} }\)tan(x) ） (函数)
catancatanfcatanl (C99)(C99)(C99) | 计算复数反正切 (函数)


atan2, atan2f, atan2l

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float atan2f( float y, float x ); | (1) | (C99 起)
double atan2( double y, double x ); | (2) |
long double atan2l( long double y, long double x ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define atan2( arg ) | (4) | (C99 起)
1-3) 计算 y/x 的弧（反）正切，以参数符号确定正确的象限。
4) 泛型宏：若任何参数拥有 long double 类型，则调用 atan2l 。否则，若任何参数拥有整数类型或 double 类型，则调用 atan2 。否则调用 atan2f 。

参数

x, y - 浮点值

返回值

若不出现错误，则返回 y/x 在 [-π ; +π] 弧度范围中的弧（反）正切（ arctan(
y
x
) ）。
Y 参数
返回值
X 参数

若出现定义域错误，则返回实现定义值。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若 x 与 y 均为零则可能出现定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若 x 与 y 均为零，则定义域错误不出现
  • 若 x 与 y 均为零，则也不出现值域错误
  • 若 y 为零，则不出现极点错误
  • 若 y 为 ±0 且 x 为负或 -0 ，则返回 ±π
  • 若 y 为 ±0 且 x 为正或 +0 ，则返回 ±0
  • 若 y 为 ±∞ 且 x 有限，则返回 ±π/2
  • 若 y 为 ±∞ 且 x 为 -∞ ，则返回 ±3π/4
  • 若 y 为 ±∞ 且 x 为 +∞ ，则返回 ±π/4
  • 若 x 为 ±0 且 y 为负，则返回 -π/2
  • 若 x 为 ±0 且 y 为正，则返回 +π/2
  • 若 x 为 -∞ 且 y 为正有限，则返回 +π
  • 若 x 为 -∞ 且 y 为负有限，则返回 -π
  • 若 x 为 +∞ 且 y 为正有限，则返回 +0
  • 若 x 为 +∞ 且 y 为负有限，则返回 -0
  • 若 x 为 NaN 或 y 为 NaN ，则返回 NaN

注意

atan2(y, x) 等价于 carg (x + I*y) 。

POSIX 指定在下溢情况下，返回不修改的 arg ，而若不支持如此，则返回不大于 DBL_MIN 、 FLT_MIN 和 LDBL_MIN 的实现定义值。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    // 正常用法：二个参数的符号确定象限
    // atan2(1,1) = +pi/4 ，第 I 象限
    printf("(+1,+1) cartesian is (%f,%f) polar\n", hypot( 1, 1), atan2( 1, 1));
    // atan2(1, -1) = +3pi/4 ，第 II 象限
    printf("(+1,-1) cartesian is (%f,%f) polar\n", hypot( 1,-1), atan2( 1,-1));
    // atan2(-1,-1) = -3pi/4 ，第 III 象限
    printf("(-1,-1) cartesian is (%f,%f) polar\n", hypot(-1,-1), atan2(-1,-1));
    // atan2(-1,-1) = -pi/4 ，第 IV 象限
    printf("(-1,+1) cartesian is (%f,%f) polar\n", hypot(-1, 1), atan2(-1, 1));

    // 特殊值
    printf("atan2(0, 0) = %f atan2(0, -0)=%f\n", atan2(0,0), atan2(0,-0.0));
    printf("atan2(7, 0) = %f atan2(7, -0)=%f\n", atan2(7,0), atan2(7,-0.0));
}

输出：

(+1,+1) cartesian is (1.414214,0.785398) polar
(+1,-1) cartesian is (1.414214,2.356194) polar
(-1,-1) cartesian is (1.414214,-2.356194) polar
(-1,+1) cartesian is (1.414214,-0.785398) polar
atan2(0, 0) = 0.000000 atan2(0, -0)=3.141593
atan2(7, 0) = 1.570796 atan2(7, -0)=1.570796

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.4.4 The atan2 functions (p: 239)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.1.4 The atan2 functions (p: 519)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.4.4 The atan2 functions (p: 219)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.1.4 The atan2 functions (p: 456)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.2.4 The atan2 function

参阅

asinasinfasinl (C99)(C99) | 计算反正弦（ \({\small\arcsin{x} }\)arcsin(x) ） (函数)
acosacosfacosl (C99)(C99) | 计算反余弦（ \({\small\arccos{x} }\)arccos(x) ） (函数)
atanatanfatanl (C99)(C99) | 计算反正切（ \({\small\arctan{x} }\)arctan(x) ） (函数)
cargcargfcargl (C99)(C99)(C99) | 计算复数的辐角 (函数)


atanh, atanhf, atanhl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float atanhf( float arg ); | (1) | (C99 起)
double atanh( double arg ); | (2) | (C99 起)
long double atanhl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define atanh( arg ) | (4) | (C99 起)
1-3) 计算 arg 的反双曲正切。
4) 泛型宏：若参数拥有 long double 类型，则调用 atanhl 。否则，若参数拥有整数类型或 double 类型，则调用 atanh 。否则调用 atanhf 。若参数为复数，则调用对应的复函数（ catanhf 、 catanh 、 catanhl ）。

参数

arg - 表示双曲扇形面积的浮点值

返回值

若不出现错误，则返回 arg 的反双曲正切（ tanh-1
(arg) 或 artanh(arg) ）。

若出现定义域错误，则返回实现定义值（若支持则为 NaN ）。

若出现极点错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL （带正确符号）。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若参数不在区间 [-1, +1] 中，则出现值域错误。

若参数为 ±1 ，则出现极点错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回不修改的参数。
  • 若参数为 ±1 ，则返回 ±∞ 并引发 FE_DIVBYZERO 。
  • 若 |arg|>1 ，则返回 NaN 并引发 FE_INVALID 。
  • 若参数为 NaN ，则返回 NaN 。

注意

尽管 C 标准命名此函数为“弧双曲正切”，双曲函数的反函数是面积函数。其参数为双曲扇形的面积，而非弧。正确的名称为“反双曲正切”（ POSIX 所用）或“面积双曲正切”。

POSIX 指定在下溢的情况下，返回不修改的 arg ，而且若不支持，则返回不大于 DBL_MIN 、 FLT_MIN 和 LDBL_MIN 的值。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <errno.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("atanh(0) = %f\natanh(-0) = %f\n", atanh(0), atanh(-0.0));
    printf("atanh(0.9) = %f\n", atanh(0.9));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("atanh(-1) = %f\n", atanh(-1));
    if(errno == ERANGE) perror("    errno == ERANGE");
    if(fetestexcept(FE_DIVBYZERO)) puts("    FE_DIVBYZERO raised");
}

可能的输出：

atanh(0) = 0.000000
atanh(-0) = -0.000000
atanh(0.9) = 1.472219
atanh(-1) = -inf
    errno == ERANGE: Numerical result out of range
    FE_DIVBYZERO raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.5.3 The atanh functions (p: 241)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.2.3 The atanh functions (p: 520)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.5.3 The atanh functions (p: 221-222)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.2.3 The atanh functions (p: 457)

参阅

asinhasinhfasinhl (C99)(C99)(C99) | 计算反双曲正弦（ \({\small\operatorname{arsinh}{x} }\)arsinh(x) ） (函数)
acoshacoshfacoshl (C99)(C99)(C99) | 计算反双曲余弦（ \({\small\operatorname{arcosh}{x} }\)arcosh(x) ） (函数)
tanhtanhftanhl (C99)(C99) | 计算双曲正切（ \({\small\tanh{x} }\)tanh(x) ） (函数)
catanhcatanhfcatanhl (C99)(C99)(C99) | 计算复数反双曲正切 (函数)

外部链接

Weisstein, Eric W. “反双曲正切。”来自 MathWorld--A Wolfram Web Resource 。


cbrt, cbrtf, cbrtl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float cbrtf( float arg ); | (1) | (C99 起)
double cbrt( double arg ); | (2) | (C99 起)
long double cbrtl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define cbrt( arg ) | (4) | (C99 起)
1-3) 计算 arg 的立方根。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 cbrtl 。否则，若 arg 拥有整数类型或 double 类型，则调用 cbrt 。否则，调用 cbrtf 。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 的立方根（ \(\small{\sqrt[3]{arg} }\)3√arg ）。

若出现下溢所致的错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 或 ±∞ ，则返回不更改的参数
  • 若参数为 NaN ，则返回 NaN 。

注解

cbrt(arg) 不等价于 pow (arg, 1.0/3) ，因为有理数 \(\small{\frac1{3} }\)
1
3
通常不等于 1.0/3 并且 pow 不能求负底数的小数次幂。另外 cbrt(arg) 常给出比 pow (arg, 1.0/3) 更精确的结果（见示例）。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    // 正常使用
    printf("cbrt(729) = %f\n", cbrt(729));
    printf("cbrt(-0.125) = %f\n", cbrt(-0.125));
    // 特殊值
    printf("cbrt(-0) = %f\n", cbrt(-0.0));
    printf("cbrt(+inf) = %f\n", cbrt(INFINITY));
    // 精度
    printf("cbrt(343)      = %.*f\n", DBL_DECIMAL_DIG, cbrt(343));
    printf("pow(343,1.0/3) = %.*f\n", DBL_DECIMAL_DIG, pow(343, 1.0/3));
}

可能的输出：

cbrt(729) = 9.000000
cbrt(-0.125) = -0.500000
cbrt(-0) = -0.000000
cbrt(+inf) = inf
cbrt(343)      = 7.00000000000000000
pow(343,1.0/3) = 6.99999999999999911

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.7.1 The cbrt functions (p: 247)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.4.1 The cbrt functions (p: 524)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.7.1 The cbrt functions (p: 228)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.4.1 The cbrt functions (p: 460)

参阅

powpowfpowl (C99)(C99) | 计算一个数的给定次幂（ \(\small{x^y}\)xy ） (函数)
sqrtsqrtfsqrtl (C99)(C99) | 计算平方根（ \(\small{\sqrt{x} }\)√x ） (函数)
hypothypotfhypotl (C99)(C99)(C99) | 计算两个给定数平方和的平方根 （ \(\scriptsize{\sqrt{x^2+y^2} }\)√x2 +y2 ） (函数)


ceil, ceilf, ceill

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float ceilf( float arg ); | (1) | (C99 起)
double ceil( double arg ); | (2) |
long double ceill( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define ceil( arg ) | (4) | (C99 起)
1-3) 计算不小于 arg 的最小整数值。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 ceill 。否则，若 arg 拥有整数类型或 double 类型，则调用 ceil 。否则，调用 ceilf 。

参数

arg - 返回值

返回值

若不出现错误，则返回不小于 arg 的最小整数值，即 ⌈arg⌉ 。

返回值
参数

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 当前舍入模式无效。
  • 若 arg 为 ±∞ ，则返回不修改的参数
  • 若 arg 为 ±0 ，则返回不修改的参数
  • 若 arg 为 NaN ，则返回 NaN

注意

舍入非整数有限值时，可以（但不要求）引发 FE_INEXACT 。

所有标准浮点格式中的最大可表示浮点值都是准确的整数，故此函数自身决不上溢；然而存储于整数对象时，结果可以溢出任何整数类型（包含 intmax_t ）。

此函数（ double 参数的）表现如同（除了不引发 FE_INEXACT 的自由）实现如下

#include <math.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
double ceil(double x)
{
    double result;
    int save_round = fegetround();
    fesetround(FE_UPWARD);
    result = rint(x); // 或 nearbyint
    fesetround(save_round);
    return result;
}

示例

#include <math.h>
#include <stdio.h>
int main(void)
{
    printf("ceil(+2.4) = %+.1f\n", ceil(2.4));
    printf("ceil(-2.4) = %+.1f\n", ceil(-2.4));
    printf("ceil(-0.0) = %+.1f\n", ceil(-0.0));
    printf("ceil(-Inf) = %+f\n",   ceil(-INFINITY));
}

可能的输出：

ceil(+2.4) = +3.0
ceil(-2.4) = -2.0
ceil(-0.0) = -0.0
ceil(-Inf) = -inf

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.9.1 The ceil functions (p: 251)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.6.1 The ceil functions (p: 526)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.9.1 The ceil functions (p: 231-232)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.6.1 The ceil functions (p: 462-463)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.6.1 The ceil function

参阅

floorfloorffloorl (C99)(C99) | 计算不大于给定值的最大整数 (函数)
trunctruncftruncl (C99)(C99)(C99) | 取整到绝对值不大于给定值的最接近整数 (函数)
roundroundfroundllroundlroundflroundllroundllroundfllroundl (C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99) | 取整到最接近的整数，在相邻整数正中间时取远离零的数 (函数)
nearbyintnearbyintfnearbyintl (C99)(C99)(C99) | 用当前舍入模式取整到整数 (函数)
rintrintfrintllrintlrintflrintlllrintllrintfllrintl (C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99) | 使用当前舍入模式取整到整数，若结果有误则产生异常 (函数)


copysign, copysignf, copysignl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float copysignf( float x, float y ); | (1) | (C99 起)
double copysign( double x, double y ); | (2) | (C99 起)
long double copysignl( long double x, long double y ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define copysign(x, y) | (4) | (C99 起)
1-3) 以 x 的绝对值和 y 的符号合成浮点值。
4) 泛型宏：若任何参数拥有 long double 类型，则调用 copysignl 。否则，若任何参数拥有整数类型或 double 类型，则调用 copysign 。否则，调用 copysignf 。

参数

x, y - 浮点值

返回值

若不出现错误，则返回拥有 x 的绝对值和 y 的符号的浮点值。

若 x 为 NaN ，则返回拥有 y 的符号的 NaN 。

若 y 为 -0 ，则仅若实现支持与算术运算一致的有符号零，结果才为负。

错误处理

此函数不受制于任何指定于 math_errhandling 的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 返回值是准确的（决不引发 FE_INEXACT ），且与当前舍入模式独立。

注意

copysign 是操纵 NaN 值符号的唯一可移植方式（为检验 NaN 的符号，亦可用 signbit ）。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    printf("copysign(1.0,+2.0)      = %+.1f\n", copysign(1.0,+2.0));
    printf("copysign(1.0,-2.0)      = %+.1f\n", copysign(1.0,-2.0));
    printf("copysign(INFINITY,-2.0) = %f\n",    copysign(INFINITY,-2.0));
    printf("copysign(NAN,-2.0)      = %f\n",    copysign(NAN,-2.0));
}

可能的输出：

copysign(1.0,+2.0)      = +1.0
copysign(1.0,-2.0)      = -1.0
copysign(INFINITY,-2.0) = -inf
copysign(NAN,-2.0)      = -nan

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.11.1 The copysign functions (p: 255)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.8.1 The copysign functions (p: 529)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.11.1 The copysign functions (p: 236)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.8.1 The copysign functions (p: 465)

参阅

fabsfabsffabsl (C99)(C99) | 计算浮点值的绝对值（ \(\small{|x|}\)|x| ） (函数)
signbit (C99) | 检查给定数是不是负数 (宏函数)


cos, cosf, cosl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float cosf( float arg ); | (1) | (C99 起)
double cos( double arg ); | (2) |
long double cosl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define cos( arg ) | (4) | (C99 起)
1-3) 计算 arg （以弧度计量）的余弦。
4) 泛型宏：若参数拥有 long double 类型，则调用 cosl 。否则，若参数拥有整数类型或 double 类型，则调用 cos 。否则，调用 cosf 、若参数为复数，则该宏调用对应的复函数（ ccosf 、 ccos 、 ccosl ）。

参数

arg - 以弧度表示角的浮点值

返回值

若不出现错误，则返回 arg 的余弦（ cos(arg) ），在范围 [-1 ; +1] 中。

若 arg 的绝对值很大，则结果可能拥有少量或无有效数字。

 (C99 前)

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

若出现下溢所致的值域错误，则返回（舍入后的）正确的结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），

  • 则若参数为 ±0 ，则结果为 1.0
  • 若参数为 ±∞ ，则返回 NaN 并引发 FE_INVALID
  • 若参数为 NaN ，则返回 NaN

注意

参数为无穷大的情况不被指定为 C 中的定义域错误，但被定义为 POSIX 中的定义域错误。

示例

#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON
int main(void)
{
    double pi = acos(-1);
    // 典型用法
    printf("cos(pi/3) = %f\n", cos(pi/3));
    printf("cos(pi/2) = %f\n", cos(pi/2));
    printf("cos(-3*pi/4) = %f\n", cos(-3*pi/4));
    // 特殊值
    printf("cos(+0) = %f\n", cos(0.0));
    printf("cos(-0) = %f\n", cos(-0.0));
    // 错误处理
    feclearexcept(FE_ALL_EXCEPT);
    printf("cos(INFINITY) = %f\n", cos(INFINITY));
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID raised");
}

可能的输出：

cos(pi/3) = 0.500000
cos(pi/2) = 0.000000
cos(-3*pi/4) = -0.707107
cos(+0) = 1.000000
cos(-0) = 1.000000
cos(INFINITY) = -nan
    FE_INVALID raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.4.5 The cos functions (p: 239)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.1.5 The cos functions (p: 519)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.4.5 The cos functions (p: 220)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.1.5 The cos functions (p: 456)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.2.5 The cos function

参阅

sinsinfsinl (C99)(C99) | 计算正弦（ \({\small\sin{x} }\)sin(x) ） (函数)
tantanftanl (C99)(C99) | 计算正切（ \({\small\tan{x} }\)tan(x) ） (函数)
acosacosfacosl (C99)(C99) | 计算反余弦（ \({\small\arccos{x} }\)arccos(x) ） (函数)
ccosccosfccosl (C99)(C99)(C99) | 计算复数余弦 (函数)


cosh, coshf, coshl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float coshf( float arg ); | (1) | (C99 起)
double cosh( double arg ); | (2) |
long double coshl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define cosh( arg ) | (4) | (C99 起)
1-3) 计算 arg 的双曲余弦。
4) 泛型宏：若参数拥有 long double 类型，则调用 coshl 。否则，若参数拥有整数类型或 double 类型，则调用 cosh 。否则调用 coshf 。若参数为复数，则宏调用对应的复数函数（ ccoshf 、 ccosh 、 ccoshl ）。

参数

arg - 表示双曲角的浮点值

返回值

若不出现错误，则返回 arg 的双曲余弦（ cosh(arg) 或
earg
+e-arg
2
）。

若出现上溢所致的值域错误，则返回 +HUGE_VAL 、 +HUGE_VALF 或 +HUGE_VALL 。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 1
  • 若参数为 ±∞ ，则返回 +∞
  • 若参数为 NaN ，则返回 NaN

注意

对于 IEEE 兼容的 double 类型，若 |arg| > 710.5 ，则 cosh(arg) 上溢。

示例

#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("cosh(1) = %f\ncosh(-1)= %f\n", cosh(1), cosh(-1));
    printf("log(sinh(1) + cosh(1))=%f\n", log(sinh(1)+cosh(1)));
    // 特殊值
    printf("cosh(+0) = %f\ncosh(-0) = %f\n", cosh(0.0), cosh(-0.0));
    // 错误处理
    errno=0; feclearexcept(FE_ALL_EXCEPT);
    printf("cosh(710.5) = %f\n", cosh(710.5));
    if(errno == ERANGE) perror("    errno == ERANGE");
    if(fetestexcept(FE_OVERFLOW)) puts("    FE_OVERFLOW raised");
}

可能的输出：

cosh(1) = 1.543081
cosh(-1)= 1.543081
log(sinh(1) + cosh(1))=1.000000
cosh(+0) = 1.000000
cosh(-0) = 1.000000
cosh(710.5) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.5.4 The cosh functions (p: 241)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.2.4 The cosh functions (p: 520)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.5.4 The cosh functions (p: 222)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.2.4 The cosh functions (p: 457)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.3.1 The cosh function

参阅

sinhsinhfsinhl (C99)(C99) | 计算双曲正弦（ \({\small\sinh{x} }\)sinh(x) ） (函数)
tanhtanhftanhl (C99)(C99) | 计算双曲正切（ \({\small\tanh{x} }\)tanh(x) ） (函数)
acoshacoshfacoshl (C99)(C99)(C99) | 计算反双曲余弦（ \({\small\operatorname{arcosh}{x} }\)arcosh(x) ） (函数)
ccoshccoshfccoshl (C99)(C99)(C99) | 计算复双曲余弦 (函数)


div, ldiv, lldiv, imaxdiv

< c‎ | numeric‎ | math
定义于头文件 <stdlib.h> |  |
div_t div( int x, int y ); | (1) |
ldiv_t ldiv( long x, long y ); | (2) |
lldiv_t lldiv( long long x, long long y ); | (3) | (C99 起)
定义于头文件 <inttypes.h> |  |
imaxdiv_t imaxdiv( intmax_t x, intmax_t y ); | (4) | (C99 起)

计算分子 x 除以分母 y 的商和余数。

同时计算商和余数。商为舍弃小数部分（向零取整）的代数商。余数满足 quot * y + rem == x 的值。 | (C99 前)
同时计算商（表达式 x/y 的结果）和余数（表达式 x%y 的结果）。 | (C99 起)

参数

x, y - 整数值

返回值

若余数和商都能表示成对应类型的对象（分别为 div_t 、 ldiv_t 、 lldiv_t 、 imaxdiv_t ），则将两者作为返回作为定义如下的 div_t 、 ldiv_t 、 lldiv_t 、 imaxdiv_t 类型对象返回：

div_t

struct div_t { int quot; int rem; };

或

struct div_t { int rem; int quot; };

ldiv_t

struct ldiv_t { long quot; long rem; };

或

struct ldiv_t { long rem; long quot; };

lldiv_t

struct lldiv_t { long long quot; long long rem; };

或

struct lldiv_t { long long rem; long long quot; };

imaxdiv_t

struct imaxdiv_t { intmax_t quot; intmax_t rem; };

或

struct imaxdiv_t { intmax_t rem; intmax_t quot; };

若余数或商无法表示，则行为未定义。

注意

C99 前，若运算数之一为负，则内建的除法和取余运算符中的商取整方向和余数符号是实现定义的，但它在 div 和 ldiv 中良好定义。

多数平台上，单条 CPU 指令获得商和余数，而此函数可以活用这点，尽管编译器通常能在适合处合并临近的 / 和 % 。

示例

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

// 只为演示：不检查缓冲区溢出
void itoa(int n, int base, char* buf)
{
    div_t dv = {.quot = n};
    char* p = buf;
    do {
        dv = div(dv.quot, base);
        *p++ = "0123456789abcdef"[abs(dv.rem)];
    } while(dv.quot);
    if(n<0) *p++ = '-';
    *p-- = '\0';
    while(buf < p) { char c = *p; *p-- = *buf; *buf++ = c; } // 反转
}

int main(void)
{
    char buf[100];
    itoa(12346, 10, buf);
    printf("%s\n", buf);
    itoa(-12346, 10, buf);
    printf("%s\n", buf);
    itoa(65535, 16, buf);
    printf("%s\n", buf);
}

输出：

12346
-12346
ffff

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.8.2.2 The imaxdiv function (p: 219)
  • 7.22.6.2 The div, ldiv and lldiv functions (p: 356)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.8.2.2 The imaxdiv function (p: 200)
  • 7.20.6.2 The div, ldiv and lldiv functions (p: 320)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10 div_t, ldiv_t
  • 4.10.6.2 The div function
  • 4.10.6.4 The ldiv function

参阅

fmodfmodffmodl (C99)(C99) | 计算浮点除法运算的余数 (函数)
remainderremainderfremainderl (C99)(C99)(C99) | 计算浮点除法运算的带符号余数 (函数)
remquoremquofremquol (C99)(C99)(C99) | 计算除法运算的带符号余数，以及商的后三位 (函数)


erf, erff, erfl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float erff( float arg ); | (1) | (C99 起)
double erf( double arg ); | (2) | (C99 起)
long double erfl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define erf( arg ) | (4) | (C99 起)
1-3) 计算 arg 的误差函数。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 erfl 。否则若 arg 拥有整数类型或 double 类型，则调用 erf 。否则调用 erff 。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 的误差函数的值，即 \(\frac{2}{\sqrt{\pi} }\int_{0}^{arg}{e^{-{t^2} }\mathsf{d}t}\)
2
√π
∫arg
0 e-t2
dt 。 若因下溢出现值域错误，则返回（舍入后的）正确结果，即 \(\frac{2\cdot arg}{\sqrt{\pi} }\)
2*arg
√π
。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 ±0
  • 若参数为 ±∞ ，则返回 ±1
  • 若参数为 NaN ，则返回 NaN

注解

若 |arg| < DBL_MIN *( sqrt (π)/2) 则保证下溢。

\({\operatorname{erf}(\frac{x}{\sigma \sqrt{2} })\)erf(
x
σ√2
) 是测量结果小于与平均数相差 \(x\)x 的值的概率，其误差服从标准差为 \(\sigma\)σ 的正态分布。

示例

#include <stdio.h>
#include <math.h>
double phi(double x1, double x2)
{
    return (erf(x2/sqrt(2)) - erf(x1/sqrt(2)))/2;
}
int main(void)
{
    puts("normal variate probabilities:");
    for(int n=-4; n<4; ++n)
        printf("[%2d:%2d]: %5.2f%%\n", n, n+1, 100*phi(n, n+1));

    puts("special values:");
    printf("erf(-0) = %f\n", erf(-0.0));
    printf("erf(Inf) = %f\n", erf(INFINITY));
}

输出：

normal variate probabilities:
[-4:-3]:  0.13%
[-3:-2]:  2.14%
[-2:-1]: 13.59%
[-1: 0]: 34.13%
[ 0: 1]: 34.13%
[ 1: 2]: 13.59%
[ 2: 3]:  2.14%
[ 3: 4]:  0.13%
special values:
erf(-0) = -0.000000
erf(Inf) = 1.000000

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.8.1 The erf functions (p: 249)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.5.1 The erf functions (p: 525)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.8.1 The erf functions (p: 230)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.5.1 The erf functions (p: 462)

参阅

erfcerfcferfcl
(C99)(C99)(C99)
 计算补误差函数
(函数)

外部链接

Weisstein, Eric W. "Erf." From MathWorld--A Wolfram Web Resource.


erfc, erfcf, erfcl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float erfcf( float arg ); | (1) | (C99 起)
double erfc( double arg ); | (2) | (C99 起)
long double erfcl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define erfc( arg ) | (4) | (C99 起)
1-3) 计算 arg 的补误差函数，即 1.0-erf(arg) ，但对于大的 arg 无精度损失。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 erfcl 。否则，若 arg 拥有整数类型或 double 类型，则调用 erfc 。否则，调用 erfcf 。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 的补误差函数的值，即 \(\frac{2}{\sqrt{\pi} }\int_{arg}^{\infty}{e^{-{t^2} }\mathsf{d}t}\)
2
√π
∫∞
arg e-t2
dt 或 \({\small 1-\operatorname{erf}(arg)}\)1-erf(arg) 。

若出现源于下溢的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 +∞ ，则返回 +0
  • 若参数为 -∞ ，则返回 2
  • 若参数为 NaN ，则返回 NaN

注解

对于 IEEE 兼容的 double 类型，若 arg > 26.55 则保证下溢。

示例

#include <stdio.h>
#include <math.h>

double normalCDF(double x) // Phi(-∞, x) 又称为 N(x)
{
    return erfc(-x/sqrt(2))/2;
}
int main(void)
{
    puts("normal cumulative distribution function:");
    for(double n=0; n<1; n+=0.1)
        printf("normalCDF(%.2f) %5.2f%%\n", n, 100*normalCDF(n));

    puts("special values:");
    printf("erfc(-Inf) = %f\n", erfc(-INFINITY));
    printf("erfc(Inf) = %f\n", erfc(INFINITY));
}

输出：

normal cumulative distribution function:
normalCDF(0.00) 50.00%
normalCDF(0.10) 53.98%
normalCDF(0.20) 57.93%
normalCDF(0.30) 61.79%
normalCDF(0.40) 65.54%
normalCDF(0.50) 69.15%
normalCDF(0.60) 72.57%
normalCDF(0.70) 75.80%
normalCDF(0.80) 78.81%
normalCDF(0.90) 81.59%
normalCDF(1.00) 84.13%
special values:
erfc(-Inf) = 2.000000
erfc(Inf) = 0.000000

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.8.2 The erfc functions (p: 249-250)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.5.2 The erfc functions (p: 525)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.8.2 The erfc functions (p: 230)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.5.2 The erfc functions (p: 462)

参阅

erferfferfl
(C99)(C99)(C99)
 计算误差函数
(函数)

外部链接

Weisstein, Eric W. "Erfc." 来自 MathWorld--A Wolfram Web Resource 。


exp, expf, expl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float expf( float arg ); | (1) | (C99 起)
double exp( double arg ); | (2) |
long double expl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define exp( arg ) | (4) | (C99 起)
1-3) 计算 e （欧拉数， 2.7182818 ）的 arg 次幂。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 expl 。否则，若 arg 拥有整数类型或 double 类型，则调用 exp 。否则调用 expf 。若 arg 为复数或虚数，则宏调用对应的复数函数（ cexpf 、 cexp 、 cexpl ）。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 的底 e 指数（ earg
 ）。

若出现上溢所致的值域错误，则返回 +HUGE_VAL 、 +HUGE_VALF 或 +HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 1
  • 若参数为 -∞ ，则返回 +0
  • 若参数为 +∞ ，则返回 +∞
  • 若参数为 NaN ，则返回 NaN

注意

对于 IEEE 兼容的 double 类型，若 709.8 < arg 则保证上溢，而若 arg < -708.4 则保证下溢。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <errno.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("exp(1) = %f\n", exp(1));
    printf("FV of $100, continuously compounded at 3%% for 1 year = %f\n",
            100*exp(0.03));
    // 特殊值
    printf("exp(-0) = %f\n", exp(-0.0));
    printf("exp(-Inf) = %f\n", exp(-INFINITY));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("exp(710) = %f\n", exp(710));
    if(errno == ERANGE) perror("    errno == ERANGE");
    if(fetestexcept(FE_OVERFLOW)) puts("    FE_OVERFLOW raised");
}

可能的输出：

exp(1) = 2.718282
FV of $100, continuously compounded at 3% for 1 year = 103.045453
exp(-0) = 1.000000
exp(-Inf) = 0.000000
exp(710) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.6.1 The exp functions (p: 242)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.3.1 The exp functions (p: 520)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.6.1 The exp functions (p: 223)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.3.1 The exp functions (p: 458)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.4.1 The exp function

参阅

exp2exp2fexp2l (C99)(C99)(C99) | 计算 2 的给定次幂（ \({\small 2^x}\)2x ） (函数)
expm1expm1fexpm1l (C99)(C99)(C99) | 计算 e 的给定次幂减一（ \({\small e^x-1}\)ex-1 ） (函数)
loglogflogl (C99)(C99) | 计算自然对数（底为 e ）（ \({\small \ln{x} }\)ln(x) ） (函数)
cexpcexpfcexpl (C99)(C99)(C99) | 计算复数的 e 底指数 (函数)


exp2, exp2f, exp2l

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float exp2f( float n ); | (1) | (C99 起)
double exp2( double n ); | (2) | (C99 起)
long double exp2l( long double n ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define exp2( n ) | (4) | (C99 起)
1-3) 计算 2 的给定 n 次幂。
4) 泛型宏，若 n 拥有 long double 类型，则调用 exp2l 。否则，若 n 用有整数类型或 double 类型，则调用 exp2 。否则调用 exp2f 。

参数

n - 浮点值

返回值

若不出现错误，则返回 n 的底 2 指数（ 2n
 ）。

若出现上溢所致的值域错误，则返回 +HUGE_VAL 、 +HUGE_VALF 或 +HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 1
  • 若参数为 -∞ ，则返回 +0
  • 若参数为 +∞ ，则返回 +∞
  • 若参数为 NaN ，则返回 NaN

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <errno.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("exp2(5) = %f\n", exp2(5));
    printf("exp2(0.5) = %f\n", exp2(0.5));
    printf("exp2(-4) = %f\n", exp2(-4));
    // 特殊值
    printf("exp2(-0.9) = %f\n", exp2(-0.9));
    printf("exp2(-Inf) = %f\n", exp2(-INFINITY));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("exp2(1024) = %f\n", exp2(1024));
    if(errno == ERANGE) perror("    errno == ERANGE");
    if(fetestexcept(FE_OVERFLOW)) puts("    FE_OVERFLOW raised");
}

可能的输出：

exp2(5) = 32.000000
exp2(0.5) = 1.414214
exp2(-4) = 0.062500
exp2(-0.9) = 0.535887
exp2(-Inf) = 0.000000
exp2(1024) = Inf
    errno == ERANGE: Result too large
    FE_OVERFLOW raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.6.2 The exp2 functions (p: 242-243)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.3.2 The exp2 functions (p: 521)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.6.2 The exp2 functions (p: 223)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.3.2 The exp2 functions (p: 458)

参阅

expexpfexpl (C99)(C99) | 计算 e 的给定次幂 （ \({\small e^x}\)ex ） (函数)
expm1expm1fexpm1l (C99)(C99)(C99) | 计算 e 的给定次幂减一（ \({\small e^x-1}\)ex-1 ） (函数)
log2log2flog2l (C99)(C99)(C99) | 计算底为 2 的对数（ \({\small \log_{2}{x} }\)log2(x) ） (函数)


expm1, expm1f, expm1l

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float expm1f( float arg ); | (1) | (C99 起)
double expm1( double arg ); | (2) | (C99 起)
long double expm1l( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define expm1( arg ) | (4) | (C99 起)
1-3) 计算 e （欧拉数， 2.7182818 ）的给定 arg 次幂减 1.0 。若 arg 接近零，则此函数比表达式 exp (arg)-1.0 更精确。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 expm1l 。否则，若 arg 拥有整数类型或 double 类型，则调用 expm1 。否则调用 expm1f 。

参数

arg - 浮点值

返回值

若不出现错误则返回 earg
-1 。

若出现上溢所致的值域错误，则返回 +HUGE_VAL 、 +HUGE_VALF 或 +HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回不修改的参数
  • 若参数为 -∞ ，则返回 -1
  • 若参数为 +∞ ，则返回 +∞
  • 若参数为 NaN ，则返回 NaN

注意

函数 expm1 和 log1p 对于金融计算有用：例如在计算小的日利率时： (1+x)n
-1 能表示为 expm1(n * log1p (x)) 。这些函数亦简化书写精确的反双曲函数。

对于 IEEE 兼容的 double 类型，若 709.8 < arg 则保证上溢。

注意

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <errno.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("expm1(1) = %f\n", expm1(1));
    printf("Interest earned in 2 days on $100, compounded daily at 1%%\n"
           " on a 30/360 calendar = %f\n",
           100*expm1(2*log1p(0.01/360)));
    printf("exp(1e-16)-1 = %g, but expm1(1e-16) = %g\n",
           exp(1e-16)-1, expm1(1e-16));
    // 特殊值
    printf("expm1(-0) = %f\n", expm1(-0.0));
    printf("expm1(-Inf) = %f\n", expm1(-INFINITY));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("expm1(710) = %f\n", expm1(710));
    if(errno == ERANGE) perror("    errno == ERANGE");
    if(fetestexcept(FE_OVERFLOW)) puts("    FE_OVERFLOW raised");
}

可能的输出：

expm1(1) = 1.718282
Interest earned in 2 days on $100, compounded daily at 1%
 on a 30/360 calendar = 0.005556
exp(1e-16)-1 = 0, but expm1(1e-16) = 1e-16
expm1(-0) = -0.000000
expm1(-Inf) = -1.000000
expm1(710) = inf
    errno == ERANGE: Result too large
    FE_OVERFLOW raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.6.3 The expm1 functions (p: 243)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.3.3 The expm1 functions (p: 521)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.6.3 The expm1 functions (p: 223-224)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.3.3 The expm1 functions (p: 458)

参阅

expexpfexpl (C99)(C99) | 计算 e 的给定次幂 （ \({\small e^x}\)ex ） (函数)
exp2exp2fexp2l (C99)(C99)(C99) | 计算 2 的给定次幂（ \({\small 2^x}\)2x ） (函数)
log1plog1pflog1pl (C99)(C99)(C99) | 计算给定数加 1 的自然对数（底为 e ）（ \({\small \ln{(1+x)} }\)ln(1+x) ） (函数)


fabs, fabsf, fabsl, fabsd32, fabsd64, fabsd128

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float fabsf( float arg ); | (1) | (C99 起)
double fabs( double arg ); | (2) |
long double fabsl( long double arg ); | (3) | (C99 起)
_Decimal32 fabsd32( _Decimal32 arg ); | (4) | (C23 起)
_Decimal64 fabsd64( _Decimal64 arg ); | (5) | (C23 起)
_Decimal128 fabsd128( _Decimal128 arg ); | (6) | (C23 起)
定义于头文件 <tgmath.h> |  |
#define fabs( arith ) | (7) | (C99 起)
1-6) 计算浮点值 arg 的绝对值。

拥有十进制浮点参数的函数当且仅当实现预定义 __STDC_IEC_60559_DFP__ （即实现支持十进制浮点数）才被声明。

 (C23 起)
7) 泛型宏：若实参拥有 _Decimal128、 _Decimal64、 _Decimal32、 (C23 起)long double、 double 或 float 类型，则分别调用 fabsd128、 fabsd64、 fabsd32、 (C23 起)fabsl、 fabs 或 fabsf 。否则若实参拥有整数类型，则调用 fabs 。否则若实参为复数，则宏调用对应的复函数（ cabsf、 cabs、 cabsl ）。否则行为未定义。

参数

arg | - | 浮点值
arith | - | 浮点或整数值

返回值

若成功，则返回 arg 的绝对值（ \(\small |arg| \)|arg| ）。值是准确的，且不依赖任何舍入模式。

错误处理

此函数不受制于任何指定于 math_errhandling 的错误条件。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 +0
  • 若参数为 ±∞ ，则返回 +∞
  • 若参数为 NaN ，则返回 NaN

示例

#include <stdio.h>
#include <math.h>

/* 此数值积分假定所有面积均为正。 */
#define PI 3.14159
double num_int (double a, double b,
                double f(double),
                unsigned n) {
    if (a == b) return 0.0;
    if (n == 0) n=1;   /* 避免除以零 */
    double h = (b-a)/n;
    double sum = 0.0;
    for (unsigned k=0; k < n; ++k)
        sum += h*fabs(f(a+k*h));
    return sum;
}

int main(void)
{
    printf("fabs(+3) = %f\n", fabs(+3.0));
    printf("fabs(-3) = %f\n", fabs(-3.0));
    // 特殊值
    printf("fabs(-0) = %f\n", fabs(-0.0));
    printf("fabs(-Inf) = %f\n", fabs(-INFINITY));

    printf("%f\n", num_int(0.0,2*PI,sin,100000));

}

输出：

fabs(+3) = 3.000000
fabs(-3) = 3.000000
fabs(-0) = 0.000000
fabs(-Inf) = inf
4.000000

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.12.7.2 The fabs functions (p: 181)
  • 7.25 Type-generic math <tgmath.h> (p: 272-273)
  • F.10.4.2 The fabs functions (p: 382)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.7.2 The fabs functions (p: 248)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.4.2 The fabs functions (p: 524)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.7.2 The fabs functions (p: 228-229)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.4.2 The fabs functions (p: 460)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.6.2 The fabs function

参阅

abslabsllabs (C99) | 计算整数值的绝对值（ \(\small{|x|}\)|x| ） (函数)
copysigncopysignfcopysignl (C99)(C99)(C99) | 从一个给定值的绝对值和另一个给定值的符号产生值 (函数)
signbit (C99) | 检查给定数是不是负数 (宏函数)
cabscabsfcabsl (C99)(C99)(C99) | 计算复数的模（绝对值） (函数)


fdim

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float fdimf( float x, float y ); | (1) | (C99 起)
double fdim( double x, double y ); | (2) | (C99 起)
long double fdiml( long double x, long double y ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define fdim( x, y ) | (4) | (C99 起)
1-3) 返回 x 与 y 间的正差，即若 x>y 则返回 x-y ，否则（若 x≤y ）返回 +0 。
4) 泛型宏：若任何参数拥有 long double 类型，则调用 fdiml 。否则，若任何参数拥有整数类型或 double 类型，则调用 fdim 。否则调用 fdimf 。

参数

x, y - 浮点值

返回值

若成功，则返回 x 与 y 间的正差。

若出现上溢所致的值域错误，则返回 +HUGE_VAL 、 +HUGE_VALF 或 +HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若任一参数为 NaN ，则返回 NaN

注意

等价于 fmax (x-y, 0) ，除了 NaN 处理要求。

示例

#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("fdim(4, 1) = %f, fdim(1, 4)=%f\n", fdim(4,1), fdim(1,4));
    printf("fdim(4,-1) = %f, fdim(1,-4)=%f\n", fdim(4,-1), fdim(1,-4));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("fdim(1e308, -1e308) = %f\n", fdim(1e308, -1e308));
    if(errno == ERANGE) perror("    errno == ERANGE");
    if(fetestexcept(FE_OVERFLOW)) puts("    FE_OVERFLOW raised");
}

可能的输出：

fdim(4, 1) = 3.000000, fdim(1, 4)=0.000000
fdim(4,-1) = 5.000000, fdim(1,-4)=5.000000
fdim(1e308, -1e308) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.12.1 The fdim functions (p: 257)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.9.1 The fdim functions (p: 530)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.12.1 The fdim functions (p: 238)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.9.1 The fdim functions (p: 466)

参阅

abslabsllabs (C99) | 计算整数值的绝对值（ \(\small{|x|}\)|x| ） (函数)
fmaxfmaxffmaxl (C99)(C99)(C99) | 确定两个浮点值的较大者 (函数)


float_t, double_t

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
typedef /*implementation defined*/ float_t | (C99 起)
typedef /*implementation defined*/ double_t | (C99 起)

float_t 和 double_t 类型分别是至少与 float 和 double 一样宽的浮点类型，并满足 double_t 至少与 float_t 一样宽。 FLT_EVAL_METHOD 的值确定 float_t 和 double_t 的类型。

FLT_EVAL_METHOD | 解释
0 | float_t 和 double_t 分别等价于 float 和 double
1 | float_t 和 double_t 都等价于 double
2 | float_t 和 double_t 都等价于 long double
其他 | float_t 和 double_t 均为实现定义

示例

#include <float.h>
#include <math.h>
#include <stdio.h>

int main(void)
{
    printf("%d\n", FLT_EVAL_METHOD);
    printf("%zu  %zu\n", sizeof(float),sizeof(float_t));
    printf("%zu  %zu\n", sizeof(double),sizeof(double_t));
    return 0;
}

可能的输出：

0
4  4
8  8

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12 Mathematics <math.h> (p: 231)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12 Mathematics <math.h> (p: 212)


floor, floorf, floorl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float floorf( float arg ); | (1) | (C99 起)
double floor( double arg ); | (2) |
long double floorl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define floor( arg ) | (4) | (C99 起)
1-3) 计算不大于 arg 的最大整数值。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 floorl 。否则，若 arg 用有整数类型或 double 类型，则调用 floor 。否则调用 floorf 。

参数

arg - 浮点值

返回值

若不出现错误，则返回不大于 arg 的最大整数值，即 ⌊arg⌋ 。

返回值
参数

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 当前舍入方式无效。
  • 若 arg 为 ±∞ ，则返回不修改的参数
  • 若 arg 为 ±0 ，则返回不修改的参数
  • 若 arg 为 NaN ，则返回 NaN

注意

在舍入非整数有限值时可以（但不要求）引发 FE_INEXACT 。

所有标准浮点格式中，最大可表示浮点值准确地为整数，故此函数自身决不上溢；然而存储于整数对象时，结果可能溢出任何整数类型（包含 intmax_t ）。

示例

#include <math.h>
#include <stdio.h>
int main(void)
{
    printf("floor(+2.7) = %+.1f\n", floor(2.7));
    printf("floor(-2.7) = %+.1f\n", floor(-2.7));
    printf("floor(-0.0) = %+.1f\n", floor(-0.0));
    printf("floor(-Inf) = %+f\n",   floor(-INFINITY));
}

可能的输出：

floor(+2.7) = +2.0
floor(-2.7) = -3.0
floor(-0.0) = -0.0
floor(-Inf) = -inf

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.9.2 The floor functions (p: 251)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.6.2 The floor functions (p: 526)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.9.2 The floor functions (p: 232)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.6.2 The floor functions (p: 463)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.6.3 The floor function

参阅

ceilceilfceill (C99)(C99) | 计算不小于给定值的最小整数 (函数)
trunctruncftruncl (C99)(C99)(C99) | 取整到绝对值不大于给定值的最接近整数 (函数)
roundroundfroundllroundlroundflroundllroundllroundfllroundl (C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99) | 取整到最接近的整数，在相邻整数正中间时取远离零的数 (函数)


fma, fmaf, fmal

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float fmaf( float x, float y, float z ); | (1) | (C99 起)
double fma( double x, double y, double z ); | (2) | (C99 起)
long double fmal( long double x, long double y, long double z ); | (3) | (C99 起)
#define FP_FAST_FMA /* implementation-defined */ | (4) | (C99 起)
#define FP_FAST_FMAF /* implementation-defined */ | (5) | (C99 起)
#define FP_FAST_FMAL /* implementation-defined */ | (6) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define fma( x, y, z ) | (7) | (C99 起)
1-3) 计算 (x*y) + z ，如同用无限精度，而仅舍入一次到结果类型。
4-6) 若定义宏常量 FP_FAST_FMAF 、 FP_FAST_FMA 或 FP_FAST_FMAL ，则对应函数 fmaf 、 fma 或 fmal 分别求值快于（并且精度高于） float 、 double 和 long double 参数的表达式 x*y+z 。若定义，则这些宏求值为整数 1 。
7) 泛型宏：若任何参数拥有 long double 类型，则调用 fmal 。否则若任何参数拥有整数类型或 double 类型，则调用 fma 。否则调用fmaf。

参数

x, y, z - 浮点值

返回值

若成功，则返回 (x*y) + z 的值，如同计算为无限精度再舍入一次以适合目标类型（或者说是作为单次三元浮点运算计算）。

若出现上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若 x 为零而 y 为无穷大或 x 为无穷大而 y 为零，且 z 非 NaN ，则返回 NaN 并引发 FE_INVALID
  • 若 x 为零而 y 为无穷大或 x 为无穷大而 y 为零，且 z 为 NaN ，则返回 NaN 并可能引发 FE_INVALID
  • 若 x*y 为准确的无穷大且 z 为带相反符号的无穷大，则返回 NaN 并引发 FE_INVALID
  • 若 x 或 y 为 NaN ，则返回 NaN
  • 若 z 为 NaN ，且 x*y 不是 0*Inf 或 Inf*0 ，则返回 NaN （而无 FE_INVALID ）

注意

此运算经常在硬件中实现为融合乘加 CPU 指令。若硬件支持，则期待定义相应的 FP_FAST_FMA* 宏，但多数实现即使在不定义这些宏时也利用该 CPU 指令。

POSIX 另外指定被指定为返回 FE_INVALID 的情形是定义域错误。

由于其无限的中间精度， fma 是其他正确舍入数学运算，如 sqrt 或甚至除法（在 CPU 不支持的平台上，例如 Itanium ）的常用构建块。

同所有浮点表达式，表达式 (x*y) + z 可编译为融合乘加，除非 #pragma STDC FP_CONTRACT 为关闭。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    // 演示 fma 和内建运算符间的区别
    double in = 0.1;
    printf("0.1 double is %.23f (%a)\n", in, in);
    printf("0.1*10 is 1.0000000000000000555112 (0x8.0000000000002p-3),"
           " or 1.0 if rounded to double\n");
    double expr_result = 0.1 * 10 - 1;
    printf("0.1 * 10 - 1 = %g : 1 subtracted after "
           "intermediate rounding to 1.0\n", expr_result);
    double fma_result = fma(0.1, 10, -1);
    printf("fma(0.1, 10, -1) = %g (%a)\n", fma_result, fma_result);

    // fma 用于 double-double
    printf("\nin double-double arithmetic, 0.1 * 10 is representable as ");
    double high = 0.1 * 10;
    double low = fma(0.1, 10, -high);
    printf("%g + %g\n\n", high, low);

    // 错误处理
    feclearexcept(FE_ALL_EXCEPT);
    printf("fma(+Inf, 10, -Inf) = %f\n", fma(INFINITY, 10, -INFINITY));
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID raised");
}

可能的输出：

0.1 double is 0.10000000000000000555112 (0x1.999999999999ap-4)
0.1*10 is 1.0000000000000000555112 (0x8.0000000000002p-3), or 1.0 if rounded to double
0.1 * 10 - 1 = 0 : 1 subtracted after intermediate rounding to 1.0
fma(0.1, 10, -1) = 5.55112e-17 (0x1p-54)

in double-double arithmetic, 0.1 * 10 is representable as 1 + 5.55112e-17

fma(+Inf, 10, -Inf) = -nan
    FE_INVALID raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.13.1 The fma functions (p: 258)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.10.1 The fma functions (p: 530)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.13.1 The fma functions (p: 239)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.10.1 The fma functions (p: 466)

参阅

remainderremainderfremainderl (C99)(C99)(C99) | 计算浮点除法运算的带符号余数 (函数)
remquoremquofremquol (C99)(C99)(C99) | 计算除法运算的带符号余数，以及商的后三位 (函数)


fmax, fmaxf, fmaxl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float fmaxf( float x, float y ); | (1) | (C99 起)
double fmax( double x, double y ); | (2) | (C99 起)
long double fmaxl( long double x, long double y ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define fmax( x, y ) | (4) | (C99 起)
1-3) 返回二个浮点参数的较大者，把 NaNs 当做缺失数据（在 NaN 和数值间选择数值）。
4) 泛型宏：若任一参数拥有 long double 类型，则调用 fmaxl 。否则，若任一参数拥有整数类型或 double 类型，则调用 fmax 。否则调用 fmaxf 。

参数

x, y - 浮点值

返回值

若成功，则返回二个浮点值的较大者。返回值准确且不依赖任何舍入模式。

错误处理

此函数不受制于任何指定于 math_errhandling 的错误条件。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若二个参数之一为 NaN ，则返回另一参数的值
  • 仅若二个参数均为 NaN ，才返回 NaN

注意

不要求此函数对零的符号敏感，尽管某些实现额外强制若一个参数是 +0 而另一个是 -0 ，则返回 +0 。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    printf("fmax(2,1)    = %f\n", fmax(2,1));
    printf("fmax(-Inf,0) = %f\n", fmax(-INFINITY,0));
    printf("fmax(NaN,-1) = %f\n", fmax(NAN,-1));
}

输出：

fmax(2,1)    = 2.000000
fmax(-Inf,0) = 0.000000
fmax(NaN,-1) = -1.000000

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.12.2 The fmax functions (p: 257-258)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.9.2 The fmax functions (p: 530)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.12.2 The fmax functions (p: 238-239)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.9.2 The fmax functions (p: 466)

参阅

isgreater (C99) | 检查第一个浮点参数是否大于第二个 (宏函数)
fminfminffminl (C99)(C99)(C99) | 确定两个浮点值的较小者 (函数)


fmin, fminf, fminl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float fminf( float x, float y ); | (1) | (C99 起)
double fmin( double x, double y ); | (2) | (C99 起)
long double fminl( long double x, long double y ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define fmin( x, y ) | (4) | (C99 起)
1-3) 返回二个浮点参数的较小者，把 NaNs 当做缺失数据（在 NaN 和数值间选择数值）。
4) 泛型宏：若任一参数拥有 long double 类型，则调用 fmaxl 。否则，若任一参数拥有整数类型或 double 类型，则调用 fmax 。否则调用 fmaxf 。

参数

x, y - 浮点值

返回值

若成功，则返回二个浮点值的较小者。返回值准确且不依赖任何舍入模式。

错误处理

此函数不受制于任何指定于 math_errhandling 的错误条件。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若二个参数之一为 NaN ，则返回另一参数的值
  • 仅若二个参数均为 NaN ，才返回 NaN

注意

不要求此函数对零的符号敏感，尽管某些实现额外强制若一个参数是 +0 而另一个是 -0 ，则返回 -0 。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    printf("fmin(2,1)    = %f\n", fmin(2,1));
    printf("fmin(-Inf,0) = %f\n", fmin(-INFINITY,0));
    printf("fmin(NaN,-1) = %f\n", fmin(NAN,-1));
}

可能的输出：

fmin(2,1)    = 1.000000
fmin(-Inf,0) = -inf
fmin(NaN,-1) = -1.000000

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.12.3 The fmin functions (p: 258)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.9.3 The fmin functions (p: 530)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.12.3 The fmin functions (p: 239)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.9.3 The fmin functions (p: 466)

参阅

isless (C99) | 检查第一个浮点参数是否小于第二个 (宏函数)
fmaxfmaxffmaxl (C99)(C99)(C99) | 确定两个浮点值的较大者 (函数)


fmod, fmodf, fmodl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float fmodf( float x, float y ); | (1) | (C99 起)
double fmod( double x, double y ); | (2) |
long double fmodl( long double x, long double y ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define fmod( x, y ) | (4) | (C99 起)
1-3) 计算除法运算 x/y 的浮点余数。
4) 泛型宏：若任何参数拥有 long double 类型则调用 fmodl 。否则，若任何参数拥有整数类型或 double 类型则调用 fmod 。否则调用 fmodf 。

此函数计算的除法 x/y 的浮点余数是 x - n*y 的准确值，其中 n 是截断小数部分的 x/y 。

返回值与 x 拥有相同符号，且绝对值小于 y 。

参数

x, y - 浮点值

返回值

若成功，则返回定义于上的除法 x/y 的浮点余数。

若出现定义域错误，则返回实现定义值（受支持的平台上为 NaN ）。

若出现下溢所指定值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若 y 为零则可能发生定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），

  • 若 x 为 ±0 且 y 非零，则返回 ±0
  • 若 x 为 ±∞ 且 y 非 NaN ，则返回 NaN 并引发 FE_INVALID
  • 若 y 为 ±0 且 x 非 NaN ，则返回 NaN 并引发 FE_INVALID
  • 若 y 为 ±∞ 且 x 有限，则返回 x 。
  • 若任一参数为 NaN ，则返回 NaN 。

注意

POSIX 要求若 x 为无穷大或 y 为零则出现定义域错误。

fmod ，但不是 remainder ，适于安静地包装浮点类型到无符号整数类型： (0.0 <= (y = fmod( rint (x), 65536.0 )) ? y : 65536.0 + y) 在范围 [-0.0 .. 65535.0] 内，它对应 unsigned short ，但 remainder ( rint (x), 65536.0) 在范围 [-32767.0, +32768.0] 内，它在 signed short 的范围外。

fmod 的 double 版本表现为如同实现如下：

double fmod(double x, double y)
{
#pragma STDC FENV_ACCESS ON
    double result = remainder(fabs(x), (y = fabs(y)));
    if (signbit(result)) result += y;
    return copysign(result, x);
}

示例

#include <stdio.h>
#include <math.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("fmod(+5.1, +3.0) = %.1f\n", fmod(5.1,3));
    printf("fmod(-5.1, +3.0) = %.1f\n", fmod(-5.1,3));
    printf("fmod(+5.1, -3.0) = %.1f\n", fmod(5.1,-3));
    printf("fmod(-5.1, -3.0) = %.1f\n", fmod(-5.1,-3));

    // 特殊值
    printf("fmod(+0.0, 1.0) = %.1f\n", fmod(0, 1));
    printf("fmod(-0.0, 1.0) = %.1f\n", fmod(-0.0, 1));
    printf("fmod(+5.1, Inf) = %.1f\n", fmod(5.1, INFINITY));

    // 错误处理
    feclearexcept(FE_ALL_EXCEPT);
    printf("fmod(+5.1, 0) = %.1f\n", fmod(5.1, 0));
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID raised");
}

可能的输出：

fmod(+5.1, +3.0) = 2.1
fmod(-5.1, +3.0) = -2.1
fmod(+5.1, -3.0) = 2.1
fmod(-5.1, -3.0) = -2.1
fmod(+0.0, 1.0) = 0.0
fmod(-0.0, 1.0) = -0.0
fmod(+5.1, Inf) = 5.1
fmod(+5.1, 0) = nan
    FE_INVALID raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.10.1 The fmod functions (p: 254)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.7.1 The fmod functions (p: 528)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.10.1 The fmod functions (p: 235)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.7.1 The fmod functions (p: 465)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.6.4 The fmod function

参阅

divldivlldiv (C99) | 计算整数除法的商和余数 (函数)
remainderremainderfremainderl (C99)(C99)(C99) | 计算浮点除法运算的带符号余数 (函数)
remquoremquofremquol (C99)(C99)(C99) | 计算除法运算的带符号余数，以及商的后三位 (函数)


fpclassify

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define fpclassify(arg) /* implementation defined */ | (C99 起)

归类浮点值 arg 到下列类别中：零、非正规、正规、无穷大、 NaN 或实现定义类别。该宏返回整数值。

忽略 FLT_EVAL_METHOD ：即使以多于参数类型的范围和精度对它求值，首先仍将它转换到其语义类型，然后分类基于该类型：正规的 long double 值可能在转换到 double 时变为非正规，而在转换到 float 时变为零。

参数

arg - 浮点值

返回值

指明 arg 类别的 FP_INFINITE 、 FP_NAN 、 FP_NORMAL 、 FP_SUBNORMAL 、 FP_ZERO 或实现定义类型之一。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>

const char *show_classification(double x) {
    switch(fpclassify(x)) {
        case FP_INFINITE:  return "Inf";
        case FP_NAN:       return "NaN";
        case FP_NORMAL:    return "normal";
        case FP_SUBNORMAL: return "subnormal";
        case FP_ZERO:      return "zero";
        default:           return "unknown";
    }
}
int main(void)
{
    printf("1.0/0.0 is %s\n", show_classification(1/0.0));
    printf("0.0/0.0 is %s\n", show_classification(0.0/0.0));
    printf("DBL_MIN/2 is %s\n", show_classification(DBL_MIN/2));
    printf("-0.0 is %s\n", show_classification(-0.0));
    printf("1.0 is %s\n", show_classification(1.0));
}

输出：

1.0/0.0 is Inf
0.0/0.0 is NaN
DBL_MIN/2 is subnormal
-0.0 is zero
1.0 is normal

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.3.1 The fpclassify macro (p: 235)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.3.1 The fpclassify macro (p: 216)

参阅

isfinite (C99) | 检查给定数是否具有有限值 (宏函数)
isinf (C99) | 检查给定数是否是无穷大 (宏函数)
isnan (C99) | 检查给定数是否为 NaN (宏函数)
isnormal (C99) | 检查给定数是否正规 (宏函数)


frexp, frexpf, frexpl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float frexpf( float arg, int* exp ); | (1) | (C99 起)
double frexp( double arg, int* exp ); | (2) |
long double frexpl( long double arg, int* exp ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define frexp( arg, exp ) | (4) | (C99 起)
1-3) 分解给定的浮点值 x 为正规化小数和二的整数幂。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 frexpl 。否则，若 arg 拥有整数类型或 double 类型，则调用 frexp 。否则调用 frexpf 。

参数

arg | - | 浮点值
exp | - | 指向要存储指数到的整数的指针

返回值

若 arg 为零，则返回零并存储零于 *exp 。

否则（若 arg 非零），若不出现错误，则返回范围 (-1;-0.5], [0.5; 1) 中的值 x ，并存储整数值为 * exp ，满足 x×2(*exp)
=arg 。

若存储于 *exp 的值在 int 范围外，则行为未指定。

若 arg 不是浮点数，则行为未指定。

错误处理

此函数不受制于任何指定于 math_errhandling 的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若 arg 为 ±0 ，则返回不修改的参数，并存储 0 于 * exp 。
  • 若 arg 为 ±∞ ，则返回它，并存储未指定值于 * exp 。
  • 若 arg 为 NaN ，则返回 NaN ，并存储未指定值于 * exp 。
  • 不引发浮点异常。
  • 若 FLT_RADIX 为 2 （或 2 的幂），则返回值准确，忽略当前舍入模式。

注意

二进制系统（其中 FLT_RADIX 为 2 ）上， frexp 可实现为

{
    *exp = (value == 0) ? 0 : (int)(1 + logb(value));
    return scalbn(value, -(*exp));
}

函数 frexp 与其对偶 ldexp 能一起用于操纵浮点数的表示，而无需直接的位操作。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>

int main(void)
{
    double f = 123.45;
    printf("Given the number %.2f or %a in hex,\n", f, f);

    double f3;
    double f2 = modf(f, &f3);
    printf("modf() makes %.0f + %.2f\n", f3, f2);

    int i;
    f2 = frexp(f, &i);
    printf("frexp() makes %f * 2^%d\n", f2, i);

    i = ilogb(f);
    printf("logb()/ilogb() make %f * %d^%d\n", f/scalbn(1.0, i), FLT_RADIX, i);
}

可能的输出：

Given the number 123.45 or 0x1.edccccccccccdp+6 in hex,
modf() makes 123 + 0.45
frexp() makes 0.964453 * 2^7
logb()/ilogb() make 1.92891 * 2^6

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.6.4 The frexp functions (p: 243)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.3.4 The frexp functions (p: 521)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.6.4 The frexp functions (p: 224)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.3.4 The frexp functions (p: 458)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.4.2 The frexp function

参阅

ldexpldexpfldexpl (C99)(C99) | 将数乘以 2 的幂 (函数)
logblogbflogbl (C99)(C99)(C99) | 提取给定数的指数（结果为浮点数） (函数)
ilogbilogbfilogbl (C99)(C99)(C99) | 提取给定数的指数（结果为整数） (函数)
modfmodffmodfl (C99)(C99) | 把一个数拆分成整数和小数部分 (函数)


hypot, hypotf, hypotl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float hypotf( float x, float y ); | (1) | (C99 起)
double hypot( double x, double y ); | (2) | (C99 起)
long double hypotl( long double x, long double y ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define hypot( x, y ) | (4) | (C99 起)
1-3) 计算 x 与 y 平方和的平方根，而不会在计算的中间阶段有过度的上溢或下溢。
4) 泛型宏：若任何参数拥有 long double 类型，则调用函数的 long double 版本。否则，若任何参数拥有整数类型或 double 类型，则调用函数的 double 版本。否则，调用函数的 float 版本。

此函数计算的值是直角边长度为 x 和 y 的直角三角形的斜边长，或点 (x,y) 距原点 (0,0) 的距离，或复数 x+iy 的绝对值。

参数

x | - | 浮点值
y | - | 浮点值

返回值

若不出现错误，则返回直角三角形的斜边， \(\scriptsize{\sqrt{x^2+y^2} }\)√x2
+y2
 。

若出现上溢所致的值域错误，则返回 +HUGE_VAL 、 +HUGE_VALF 或 +HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • hypot(x, y) 、 hypot(y, x) 及 hypot(x, -y) 等价
  • 若参数之一为 ±0 ，则 hypot 等价于以非零参数调用 fabs
  • 若参数之一为 ±∞ ，则 hypot 返回 +∞ ，即使另一参数为 NaN
  • 否则，若任何参数为 NaN ，则返回 NaN

注意

实现通常保证小于 1 ulp （最后位置单位）的精度： GNU 、 BSD 、 Open64 。

hypot(x, y) 等价于 cabs (x + I*y) 。

POSIX 指定仅若二个参数均为非正规且正确结果亦为非正规才可以出现下溢（这禁止朴素实现）。

hypot(INFINITY, NAN) 返回 +∞ ，但 sqrt (INFINITY*INFINITY+NAN*NAN) 返回 NaN 。

示例

#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <fenv.h>
#include <float.h>

#pragma STDC FENV_ACCESS ON
int main(void)
{
    // 典型用法
    printf("(1,1) cartesian is (%f,%f) polar\n", hypot(1,1), atan2(1,1));
    // 特殊值
    printf("hypot(NAN,INFINITY) = %f\n", hypot(NAN,INFINITY));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("hypot(DBL_MAX,DBL_MAX) = %f\n", hypot(DBL_MAX,DBL_MAX));
    if(errno == ERANGE)         perror("    errno == ERANGE");
    if(fetestexcept(FE_OVERFLOW)) puts("    FE_OVERFLOW raised");
}

可能的输出：

(1,1) cartesian is (1.414214,0.785398) polar
hypot(NAN,INFINITY) = inf
hypot(DBL_MAX,DBL_MAX) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.7.3 The hypot functions (p: 248)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.4.3 The hypot functions (p: 524)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.7.3 The hypot functions (p: 229)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.4.3 The hypot functions (p: 461)

参阅

powpowfpowl (C99)(C99) | 计算一个数的给定次幂（ \(\small{x^y}\)xy ） (函数)
sqrtsqrtfsqrtl (C99)(C99) | 计算平方根（ \(\small{\sqrt{x} }\)√x ） (函数)
cbrtcbrtfcbrtl (C99)(C99)(C99) | 计算立方根（ \(\small{\sqrt[3]{x} }\)3√x ） (函数)
cabscabsfcabsl (C99)(C99)(C99) | 计算复数的模（绝对值） (函数)


ilogb, ilogbf, ilogbl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
int ilogbf( float arg ); | (1) | (C99 起)
int ilogb( double arg ); | (2) | (C99 起)
int ilogbl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define ilogb( arg ) | (4) | (C99 起)
定义于头文件 <math.h> |  |
#define FP_ILOGB0 /*implementation-defined*/ | (5) | (C99 起)
#define FP_ILOGBNAN /*implementation-defined*/ | (6) | (C99 起)
1-3) 从浮点参数 arg 提取独立于基底的无偏指数，并将它作为有符号整数值返回。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 ilogbl 。否则，若 arg 拥有整数类型或 double 类型，则调用 ilogb 。否则调用 ilogbf 。
5) 展开成整数常量表达式，值为 INT_MIN 或 - INT_MAX 。
6) 展开成整数常量表达式，值为 INT_MIN 或 + INT_MAX 。

正式而言，无偏指数是非零 arg 的 log
r|arg| 的整数部分，作为有符号整数值，其中 r 是 FLT_RADIX 。

参数

arg - 浮点值

返回值

若不出现错误，则返回作为 int 值的 arg 的无偏指数。

若 arg 为零，则返回 FP_ILOGB0 。

若 arg 为无穷大，则返回 INT_MAX 。

若 arg 为 NaN ，则返回 FP_ILOGBNAN 。

若正确结果大于 INT_MAX 或小于 INT_MIN ，则返回值未指定，且可能出现定义域或值域错误。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 为零、无穷大或 NaN ，则可能出现定义域错误或值域错误。

若正确结果大于 INT_MAX 或小于 INT_MIN ，则可能出现定义域错误或值域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若正确结果大于 INT_MAX 或小于 INT_MIN ，则引发 FE_INVALID 。
  • 若 arg 为 ±0 、 ±∞ 或 NaN ，则引发 FE_INVALID 。
  • 所有其他情况下，结果是准确的（决不引发 FE_INEXACT ）并且忽略当前舍入模式。

注意

若 arg 不是零、无穷大或 NaN ，则返回的值准确等价于 (int) logb (arg) 。

POSIX 要求若 arg 为零、无穷大、 NaN 或若正确结果在 int 的范围外则出现定义于错误。

POSIX 亦要求在 XSI 一致的系统上，正确结果大于 INT_MAX 时返回值为 INT_MAX ，而正确结果小于 INT_MIN 时返回值为 INT_MIN 。

在所有已知平台上正确结果都能表示成 int 。对于要出现溢出的情况， INT_MAX 必须小于 LDBL_MAX_EXP *log2( FLT_RADIX ) 或 INT_MIN 必须大于 LDBL_MIN_EXP- LDBL_MANT_DIG )*log2( FLT_RADIX ) 。

ilogb 所返回的指数值始终比 frexp 所返回的小 1 ，因为不同的正规化要求：对于 ilogb 返回的指数 e ， |arg*r-e
| 在 1 与 r 之间（典型地在 1 与 2 之间），但 frexp 返回的指数 e ， |arg*2-e
| 在 0.5 与 1 之间。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON
int main(void)
{
    double f = 123.45;
    printf("Given the number %.2f or %a in hex,\n", f, f);

    double f3;
    double f2 = modf(f, &f3);
    printf("modf() makes %.0f + %.2f\n", f3, f2);

    int i;
    f2 = frexp(f, &i);
    printf("frexp() makes %f * 2^%d\n", f2, i);

    i = ilogb(f);
    printf("logb()/ilogb() make %f * %d^%d\n", f/scalbn(1.0, i), FLT_RADIX, i);

    // 错误处理
    feclearexcept(FE_ALL_EXCEPT);
    printf("ilogb(0) = %d\n", ilogb(0));
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID raised");
}

可能的输出：

Given the number 123.45 or 0x1.edccccccccccdp+6 in hex,
modf() makes 123 + 0.45
frexp() makes 0.964453 * 2^7
logb()/ilogb() make 1.92891 * 2^6
ilogb(0) = -2147483648
    FE_INVALID raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12/8 Mathematics <math.h> (p: 232)
  • 7.12.6.5 The ilogb functions (p: 244)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.3.5 The ilogb functions (p: 521)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12/8 Mathematics <math.h> (p: 213)
  • 7.12.6.5 The ilogb functions (p: 224-225)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.3.5 The ilogb functions (p: 458)

参阅

frexpfrexpffrexpl (C99)(C99) | 将数拆分成有效数字和 2 的幂次 (函数)
logblogbflogbl (C99)(C99)(C99) | 提取给定数的指数（结果为浮点数） (函数)
scalbnscalbnfscalbnlscalblnscalblnfscalblnl (C99)(C99)(C99)(C99)(C99)(C99) | 高效计算一个数乘 FLT_RADIX 的幂 (函数)


isfinite

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define isfinite(arg) /* implementation defined */ | (C99 起)

确定给定的浮点数 arg 是否拥有有限值，即它是正规、非正规或零，但不是无穷大或 NaN 。该宏返回整数值。

忽略 FLT_EVAL_METHOD ：即使以多于参数类型的范围和精度对它求值，首先仍将它转换到其语义类型，然后分类基于该类型。

参数

arg - 浮点值

返回值

若 arg 拥有有限值则返回非零整数值，否则返回 ​0​ 。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>

int main(void)
{
    printf("isfinite(NAN)         = %d\n", isfinite(NAN));
    printf("isfinite(INFINITY)    = %d\n", isfinite(INFINITY));
    printf("isfinite(0.0)         = %d\n", isfinite(0.0));
    printf("isfinite(DBL_MIN/2.0) = %d\n", isfinite(DBL_MIN/2.0));
    printf("isfinite(1.0)         = %d\n", isfinite(1.0));
    printf("isfinite(exp(800))    = %d\n", isfinite(exp(800)));
}

可能的输出：

isfinite(NAN)         = 0
isfinite(INFINITY)    = 0
isfinite(0.0)         = 1
isfinite(DBL_MIN/2.0) = 1
isfinite(1.0)         = 1
isfinite(exp(800))    = 0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.3.2 The isfinite macro (p: 236)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.3.2 The isfinite macro (p: 216-217)

参阅

fpclassify (C99) | 对给定的浮点值分类 (宏函数)
isinf (C99) | 检查给定数是否是无穷大 (宏函数)
isnan (C99) | 检查给定数是否为 NaN (宏函数)
isnormal (C99) | 检查给定数是否正规 (宏函数)


isgreater

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define isgreater(x, y) /* implementation defined */ | (C99 起)

确定浮点数 x 是否大于浮点数 y ，而不设置浮点异常。

参数

x | - | 浮点值
y | - | 浮点值

返回值

若 x > y 则为非零整数值，否则为 ​0​ 。

注意

若一或两个参数为 NaN ，则内建的 operator> 对浮点数可能引发 FE_INVALID 。此宏是 operator> 的“安静”版本。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    printf("isgreater(2.0,1.0)      = %d\n", isgreater(2.0,1.0));
    printf("isgreater(1.0,2.0)      = %d\n", isgreater(1.0,2.0));
    printf("isgreater(INFINITY,1.0) = %d\n", isgreater(INFINITY,1.0));
    printf("isgreater(1.0,NAN)      = %d\n", isgreater(1.0,NAN));

    return 0;
}

可能的输出：

isgreater(2.0,1.0)      = 1
isgreater(1.0,2.0)      = 0
isgreater(INFINITY,1.0) = 1
isgreater(1.0,NAN)      = 0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.14.1 The isgreater macro (p: 259)
  • F.10.11 Comparison macros (p: 531)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.14.1 The isgreater macro (p: 240)

参阅

isless
(C99)
 检查第一个浮点参数是否小于第二个
(宏函数)


isgreaterequal

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define isgreaterequal(x, y) /* implementation defined */ | (C99 起)

确定浮点数 x 是否大于或等于浮点数 y ，而不设置浮点异常。

参数

x | - | 浮点值
y | - | 浮点值

返回值

若 x >= y 则为非零整数值，否则为 ​0​ 。

注意

若一或两个参数为 NaN ，则内建的 operator>= 对浮点数可能引发 FE_INVALID 。此宏是 operator>= 的“安静”版本。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    printf("isgreaterequal(2.0,1.0)      = %d\n", isgreaterequal(2.0,1.0));
    printf("isgreaterequal(1.0,2.0)      = %d\n", isgreaterequal(1.0,2.0));
    printf("isgreaterequal(1.0,1.0)      = %d\n", isgreaterequal(1.0,1.0));
    printf("isgreaterequal(INFINITY,1.0) = %d\n", isgreaterequal(INFINITY,1.0));
    printf("isgreaterequal(1.0,NAN)      = %d\n", isgreaterequal(1.0,NAN));

    return 0;
}

可能的输出：

isgreaterequal(2.0,1.0)      = 1
isgreaterequal(1.0,2.0)      = 0
isgreaterequal(1.0,1.0)      = 1
isgreaterequal(INFINITY,1.0) = 1
isgreaterequal(1.0,NAN)      = 0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.14.2 The isgreaterequal macro (p: 259-260)
  • F.10.11 Comparison macros (p: 531)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.14.2 The isgreaterequal macro (p: 240-241)

参阅

islessequal
(C99)
 检查第一个浮点参数是否小于或等于第二个
(宏函数)


isinf

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define isinf(arg) /* implementation defined */ | (C99 起)

确定给定的浮点数 arg 是否正或负无穷大。该宏返回整数值。

忽略 FLT_EVAL_METHOD ：即使以多于参数类型的范围和精度对它求值，首先仍将它转换到其语义类型，然后分类基于该类型。

参数

arg - 浮点值

返回值

若 arg 拥有无穷大值则为返回非零整数值，否则返回 ​0​ 。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>

int main(void)
{
    printf("isinf(NAN)         = %d\n", isinf(NAN));
    printf("isinf(INFINITY)    = %d\n", isinf(INFINITY));
    printf("isinf(0.0)         = %d\n", isinf(0.0));
    printf("isinf(DBL_MIN/2.0) = %d\n", isinf(DBL_MIN/2.0));
    printf("isinf(1.0)         = %d\n", isinf(1.0));
    printf("isinf(exp(800))    = %d\n", isinf(exp(800)));
}

可能的输出：

isinf(NAN)         = 0
isinf(INFINITY)    = 1
isinf(0.0)         = 0
isinf(DBL_MIN/2.0) = 0
isinf(1.0)         = 0
isinf(exp(800))    = 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.3.3 The isinf macro (p: 236)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.3.3 The isinf macro (p: 217)

参阅

fpclassify (C99) | 对给定的浮点值分类 (宏函数)
isfinite (C99) | 检查给定数是否具有有限值 (宏函数)
isnan (C99) | 检查给定数是否为 NaN (宏函数)
isnormal (C99) | 检查给定数是否正规 (宏函数)


isless

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define isless(x, y) /* implementation defined */ | (C99 起)

确定浮点数 x 是否小于浮点数 y ，而不设置浮点异常。

参数

x | - | 浮点值
y | - | 浮点值

返回值

若 x < y 则为非零整数值，否则为 ​0​ 。

注意

若一或两个参数为 NaN ，则内建的 operator< 对浮点数可能引发 FE_INVALID 。此宏是 operator< 的“安静”版本。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    printf("isless(2.0,1.0)      = %d\n", isless(2.0,1.0));
    printf("isless(1.0,2.0)      = %d\n", isless(1.0,2.0));
    printf("isless(INFINITY,1.0) = %d\n", isless(INFINITY,1.0));
    printf("isless(1.0,NAN)      = %d\n", isless(1.0,NAN));

    return 0;
}

可能的输出：

isless(2.0,1.0)      = 0
isless(1.0,2.0)      = 1
isless(INFINITY,1.0) = 0
isless(1.0,NAN)      = 0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.14.3 The isless macro (p: 260)
  • F.10.11 Comparison macros (p: 531)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.14.3 The isless macro (p: 241)

参阅

isgreater
(C99)
 检查第一个浮点参数是否大于第二个
(宏函数)


islessequal

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define islessequal(x, y) /* implementation defined */ | (C99 起)

确定浮点数 x 是否小于或等于浮点数 y ，而不设置浮点异常。

参数

x | - | 浮点值
y | - | 浮点值

返回值

若 x <= y 则为非零整数值，否则为 ​0​ 。

注意

若一或两个参数为 NaN ，则内建的 operator<= 对浮点数可能引发 FE_INVALID 。此宏是 operator<= 的“安静”版本。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    printf("islessequal(2.0,1.0)      = %d\n", islessequal(2.0,1.0));
    printf("islessequal(1.0,2.0)      = %d\n", islessequal(1.0,2.0));
    printf("islessequal(1.0,1.0)      = %d\n", islessequal(1.0,1.0));
    printf("islessequal(INFINITY,1.0) = %d\n", islessequal(INFINITY,1.0));
    printf("islessequal(1.0,NAN)      = %d\n", islessequal(1.0,NAN));

    return 0;
}

可能的输出：

islessequal(2.0,1.0)      = 0
islessequal(1.0,2.0)      = 1
islessequal(1.0,1.0)      = 1
islessequal(INFINITY,1.0) = 0
islessequal(1.0,NAN)      = 0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.14.4 The islessequal macro (p: 260)
  • F.10.11 Comparison macros (p: 531)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.14.4 The islessequal macro (p: 241)

参阅

isgreaterequal
(C99)
 检查第一个浮点参数是否大于等于第二个
(宏函数)


islessgreater

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define islessgreater(x, y) /* implementation defined */ | (C99 起)

确定浮点数 x 是否小于或大于浮点数 y ，而不设置浮点异常。

参数

x | - | 浮点值
y | - | 浮点值

返回值

若 x < y || x > y 则为非零整数值，否则为 ​0​ 。

注意

若一或两个参数为 NaN ，则内建的 operator< 和 operator> 可能对浮点数引发 FE_INVALID 。此宏是表达式 x < y || x > y 的“安静”版本。宏不会对 x 和 y 求值两次。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    printf("islessgreater(2.0,1.0)      = %d\n", islessgreater(2.0,1.0));
    printf("islessgreater(1.0,2.0)      = %d\n", islessgreater(1.0,2.0));
    printf("islessgreater(1.0,1.0)      = %d\n", islessgreater(1.0,1.0));
    printf("islessgreater(INFINITY,1.0) = %d\n", islessgreater(INFINITY,1.0));
    printf("islessgreater(1.0,NAN)      = %d\n", islessgreater(1.0,NAN));

    return 0;
}

可能的输出：

islessgreater(2.0,1.0)      = 1
islessgreater(1.0,2.0)      = 1
islessgreater(1.0,1.0)      = 0
islessgreater(INFINITY,1.0) = 1
islessgreater(1.0,NAN)      = 0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.14.5 The islessgreater macro (p: 261)
  • F.10.11 Comparison macros (p: 531)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.14.5 The islessgreater macro (p: 241-242)

参阅

isless (C99) | 检查第一个浮点参数是否小于第二个 (宏函数)
isgreater (C99) | 检查第一个浮点参数是否大于第二个 (宏函数)


isnan

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define isnan(arg) /* implementation defined */ | (C99 起)

确定给定的浮点数 arg 是否非数（ NaN ）值。该宏返回整数值。

忽略 FLT_EVAL_METHOD ：即使以多于参数类型的范围和精度对它求值，首先仍将它转换到其语义类型，然后分类基于该类型。

参数

arg - 浮点值

返回值

若 arg 为 NaN 则为非零整数值，否则为 ​0​ 。

注意

有多个拥有不同符号位和载荷的不同 NaN 值，参阅 nan 。

NaN 值决不与自身或其他 NaN 值比较相等。复制 NaN 可能改变其位模式。

另一种测试浮点值是否 NaN 的方式是与自身比较： _Bool is_nan(double x) { return x != x; } 。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>

int main(void)
{
    printf("isnan(NAN)         = %d\n", isnan(NAN));
    printf("isnan(INFINITY)    = %d\n", isnan(INFINITY));
    printf("isnan(0.0)         = %d\n", isnan(0.0));
    printf("isnan(DBL_MIN/2.0) = %d\n", isnan(DBL_MIN/2.0));
    printf("isnan(0.0 / 0.0)   = %d\n", isnan(0.0/0.0));
    printf("isnan(Inf - Inf)   = %d\n", isnan(INFINITY - INFINITY));
}

可能的输出：

isnan(NAN)         = 1
isnan(INFINITY)    = 0
isnan(0.0)         = 0
isnan(DBL_MIN/2.0) = 0
isnan(0.0 / 0.0)   = 1
isnan(Inf - Inf)   = 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.3.4 The isnan macro (p: 236-237)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.3.4 The isnan macro (p: 217)

参阅

nannanfnanl (C99)(C99)(C99) | 返回 NaN （非数） (函数)
fpclassify (C99) | 对给定的浮点值分类 (宏函数)
isfinite (C99) | 检查给定数是否具有有限值 (宏函数)
isinf (C99) | 检查给定数是否是无穷大 (宏函数)
isnormal (C99) | 检查给定数是否正规 (宏函数)
isunordered (C99) | 检查两个浮点数值是否无序 (宏函数)


isnormal

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define isnormal(arg) /* implementation defined */ | (C99 起)

确定给定的浮点数 arg 是否正规，即它不是零、非正规、无穷大或 NaN 。该宏返回整数值。

忽略 FLT_EVAL_METHOD ：即使以多于参数类型的范围和精度对它求值，首先仍将它转换到其语义类型，然后分类基于该类型。

参数

arg - 浮点值

返回值

若 arg 正规则为非零整数值，否则为 ​0​ 。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>

int main(void)
{
    printf("isnormal(NAN)         = %d\n", isnormal(NAN));
    printf("isnormal(INFINITY)    = %d\n", isnormal(INFINITY));
    printf("isnormal(0.0)         = %d\n", isnormal(0.0));
    printf("isnormal(DBL_MIN/2.0) = %d\n", isnormal(DBL_MIN/2.0));
    printf("isnormal(1.0)         = %d\n", isnormal(1.0));
}

输出：

isnormal(NAN)         = 0
isnormal(INFINITY)    = 0
isnormal(0.0)         = 0
isnormal(DBL_MIN/2.0) = 0
isnormal(1.0)         = 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.3.5 The isnormal macro (p: 237)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.3.5 The isnormal macro (p: 217-218)

参阅

fpclassify (C99) | 对给定的浮点值分类 (宏函数)
isfinite (C99) | 检查给定数是否具有有限值 (宏函数)
isinf (C99) | 检查给定数是否是无穷大 (宏函数)
isnan (C99) | 检查给定数是否为 NaN (宏函数)


isunordered

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define isunordered(x, y) /* implementation defined */ | (C99 起)

确定浮点数 x 与 y 是否无序，即一或两个是 NaN ，从而无法有意义地彼此比较。

参数

x | - | 浮点值
y | - | 浮点值

返回值

若 x 或 y 为 NaN 则为非零整数值，否则为 ​0​ 。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    printf("isunordered(NAN,1.0) = %d\n", isunordered(NAN,1.0));
    printf("isunordered(1.0,NAN) = %d\n", isunordered(1.0,NAN));
    printf("isunordered(NAN,NAN) = %d\n", isunordered(NAN,NAN));
    printf("isunordered(1.0,0.0) = %d\n", isunordered(1.0,0.0));

    return 0;
}

可能的输出：

isunordered(NAN,1.0) = 1
isunordered(1.0,NAN) = 1
isunordered(NAN,NAN) = 1
isunordered(1.0,0.0) = 0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.14.6 The isunordered macro (p: 261)
  • F.10.11 Comparison macros (p: 531)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.14.6 The isunordered macro (p: 242)

参阅

fpclassify (C99) | 对给定的浮点值分类 (宏函数)
isnan (C99) | 检查给定数是否为 NaN (宏函数)


ldexp, ldexpf, ldexpl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float ldexpf( float arg, int exp ); | (1) | (C99 起)
double ldexp( double arg, int exp ); | (2) |
long double ldexpl( long double arg, int exp ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define ldexp( arg, exp ) | (4) | (C99 起)
1-3) 将浮点值 arg 乘以 2 的 exp 次幂。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 ldexpl 。否则，若 arg 拥有整数类型或 double 类型，则调用 ldexp 。否则调用 ldexpf 。

参数

arg | - | 浮点值
exp | - | 整数值

返回值

若不出现错误，则返回 arg 乘 2 的 exp 次幂（ arg×2exp
 ）。

若出现上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 决不引发 FE_INEXACT ，除非出现值域错误（结果准确）
  • 忽略当前舍入模式，除非出现值域错误
  • 若 arg 为 ±0 ，则返回不修改的参数
  • 若 arg 为 ±∞ ，则返回不修改的参数
  • 若 exp 为 0 ，则返回不修改的 arg
  • 若 arg 为 NaN ，则返回 NaN

注意

二进制系统上（其中 FLT_RADIX 为 2 ）， ldexp 等价于 scalbn 。

函数 ldexp （“加载指数”）与其对偶 frexp 能一同用于操纵浮点数的表示，而无需直接的位操作。

多数实现上， ldexp 效率低于用通常算术运算符乘或除以二的幂。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <errno.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("ldexp(7, -4) = %f\n", ldexp(7, -4));
    printf("ldexp(1, -1074) = %g (minimum positive subnormal double)\n",
            ldexp(1, -1074));
    printf("ldexp(nextafter(1,0), 1024) = %g (largest finite double)\n",
            ldexp(nextafter(1,0), 1024));
    // 特殊值
    printf("ldexp(-0, 10) = %f\n", ldexp(-0.0, 10));
    printf("ldexp(-Inf, -1) = %f\n", ldexp(-INFINITY, -1));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("ldexp(1, 1024) = %f\n", ldexp(1, 1024));
    if(errno == ERANGE) perror("    errno == ERANGE");
    if(fetestexcept(FE_OVERFLOW)) puts("    FE_OVERFLOW raised");
}

可能的输出：

ldexp(7, -4) = 0.437500
ldexp(1, -1074) = 4.94066e-324 (minimum positive subnormal double)
ldexp(nextafter(1,0), 1024) = 1.79769e+308 (largest finite double)
ldexp(-0, 10) = -0.000000
ldexp(-Inf, -1) = -inf
ldexp(1, 1024) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.6.6 The ldexp functions (p: 244)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.3.6 The ldexp functions (p: 522)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.6.6 The ldexp functions (p: 225)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.3.6 The ldexp functions (p: 459)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.4.3 The ldexp function

参阅

frexpfrexpffrexpl (C99)(C99) | 将数拆分成有效数字和 2 的幂次 (函数)
scalbnscalbnfscalbnlscalblnscalblnfscalblnl (C99)(C99)(C99)(C99)(C99)(C99) | 高效计算一个数乘 FLT_RADIX 的幂 (函数)


lgamma, lgammaf, lgammal

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float lgammaf( float arg ); | (1) | (C99 起)
double lgamma( double arg ); | (2) | (C99 起)
long double lgammal( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define lgamma( arg ) | (4) | (C99 起)
1-3) 计算 arg 的伽马函数绝对值的自然对数。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 lgammal 。否则，若 arg 拥有整数类型或 double 类型，则调用 lgamma 。否则调用lgammaf 。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 的伽马函数的自然对数，即 \(\log_{e}|{\int_0^\infty t^{arg-1} e^{-t} \mathsf{d}t}|\)log
e|∫∞
0 t arg-1
 e-t dt| 。

若出现极点错误，则返回 +HUGE_VAL 、 +HUGE_VALF 或 +HUGE_VALL 。

若出现上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 为零或为小于零的整数，则可能出现极点错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 1 ，则返回 +0 。
  • 若参数为 2 ，则返回 +0 。
  • 若参数为 ±0 ，则返回 +∞ 并引发 FE_DIVBYZERO 。
  • 若参数为负整数，则返回 +∞ 并引发 FE_DIVBYZERO 。
  • 若参数为 ±∞ ，则返回 +∞ 。
  • 若参数为 NaN ，则返回 NaN 。

注意

若 arg 为自然数，则 lgamma(arg) 是 arg-1 阶乘的自然对数。

lgamma 的 POSIX 版本不是线程安全的：每次执行函数都会存储 arg 的伽马函数的符号于静态外部变量 signgam 。一些实现提供 lgamma_r ，它接收指向 singgam 的用户提供存储的指针为第二参数，而且是线程安全的。

多数实现中有名为 gamma 的非标准函数，但其定义不一致。例如， gamma 的 glibc 和 4.2BSD 版本执行 lgamma ，但 gamma 的 4.4BSD 版本执行 tgamma 。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <errno.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("lgamma(10) = %f, log(9!)=%f\n", lgamma(10), log(2*3*4*5*6*7*8*9));
    double pi = acos(-1);
    printf("lgamma(0.5) = %f, log(sqrt(pi)) = %f\n", log(sqrt(pi)), lgamma(0.5));
    // 特殊值
    printf("lgamma(1) = %f\n", lgamma(1));
    printf("lgamma(+Inf) = %f\n", lgamma(INFINITY));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("lgamma(0) = %f\n", lgamma(0));
    if(errno == ERANGE) perror("    errno == ERANGE");
    if(fetestexcept(FE_DIVBYZERO)) puts("    FE_DIVBYZERO raised");
}

可能的输出：

lgamma(10) = 12.801827, log(9!)=12.801827
lgamma(0.5) = 0.572365, log(sqrt(pi)) = 0.572365
lgamma(1) = 0.000000
lgamma(+Inf) = inf
lgamma(0) = inf
    errno == ERANGE: Numerical result out of range
    FE_DIVBYZERO raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.8.3 The lgamma functions (p: 250)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.5.3 The lgamma functions (p: 525)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.8.3 The lgamma functions (p: 231)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.5.3 The lgamma functions (p: 462)

参阅

tgammatgammaftgammal
(C99)(C99)(C99)
 计算伽马函数
(函数)

外部链接

Weisstein, Eric W. “对数伽马函数”来自 MathWorld--A Wolfram Web Resource 。


log, logf, logl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float logf( float arg ); | (1) | (C99 起)
double log( double arg ); | (2) |
long double logl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define log( arg ) | (4) | (C99 起)
1-3) 计算 arg 的自然（底 e ）对数。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 logl 。否则，若 arg 拥有整数类型或 double 类型，则调用 log 。否则，调用 logf 。若 arg 为复数或序数，则宏调用对应的复数函数（ clogf 、 clog 、 clogl ）。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 的自然（底 e ）对数（ ln(arg) 或log
e(arg) ）。

若出现定义域错误，则返回实现定义值（支持的平台上为 NaN ）。

若出现极点错误，则返回 -HUGE_VAL 、 -HUGE_VALF 或 -HUGE_VALL 。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 小于零则出现定义域错误。

若 arg 为零则可能出现极点错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 -∞ 并引发 FE_DIVBYZERO 。
  • 若参数为 1 ，则返回 +0 。
  • 若参数为负数，则返回 NaN 并引发 FE_INVALID 。
  • 若参数为 +∞ ，则返回 +∞ 。
  • 若参数为 NaN ，则返回 NaN 。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <errno.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("log(1) = %f\n", log(1));
    printf("base-5 logarithm of 125 = %f\n", log(125)/log(5));
    // 特殊值
    printf("log(1) = %f\n", log(1));
    printf("log(+Inf) = %f\n", log(INFINITY));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("log(0) = %f\n", log(0));
    if(errno == ERANGE) perror("    errno == ERANGE");
    if(fetestexcept(FE_DIVBYZERO)) puts("    FE_DIVBYZERO raised");
}

输出：

log(1) = 0.000000
base-5 logarithm of 125 = 3.000000
log(1) = 0.000000
log(+Inf) = inf
log(0) = -inf
    errno == ERANGE: Numerical result out of range
    FE_DIVBYZERO raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.6.7 The log functions (p: 244-245)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.3.7 The log functions (p: 522)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.6.7 The log functions (p: 225)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.3.7 The log functions (p: 459)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.4.4 The log function

参阅

log10log10flog10l (C99)(C99) | 计算常用对数 （底为 10 ）（ \({\small \log_{10}{x} }\)log10(x) ） (函数)
log2log2flog2l (C99)(C99)(C99) | 计算底为 2 的对数（ \({\small \log_{2}{x} }\)log2(x) ） (函数)
log1plog1pflog1pl (C99)(C99)(C99) | 计算给定数加 1 的自然对数（底为 e ）（ \({\small \ln{(1+x)} }\)ln(1+x) ） (函数)
expexpfexpl (C99)(C99) | 计算 e 的给定次幂 （ \({\small e^x}\)ex ） (函数)
clogclogfclogl (C99)(C99)(C99) | 计算复数的自然对数 (函数)


log10, log10f, log10l

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float log10f( float arg ); | (1) | (C99 起)
double log10( double arg ); | (2) |
long double log10l( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define log10( arg ) | (4) | (C99 起)
1-3) 计算 arg 的常用（底 10 ）对数。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 log10l 。否则，若 arg 拥有整数类型或 double 类型，则调用 log10 。否则调用 log10f 。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 的常用（底 10 ）对数（ log
10(arg) 或 lg(arg) ）。

若出现定义域错误，则返回实现定义值（支持的平台上为 NaN ）。

若出现极点错误，则返回 -HUGE_VAL 、 -HUGE_VALF 或 -HUGE_VALL 。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 小于零则出现定义域错误。

若 arg 为零则可能出现极点错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 -∞ 并引发 FE_DIVBYZERO 。
  • 若参数为 1 ，则返回 +0 。
  • 若参数为负数，则返回 NaN 并引发 FE_INVALID 。
  • 若参数为 +∞ ，则返回 +∞ 。
  • 若参数为 NaN ，则返回 NaN 。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <errno.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("log10(1000) = %f\n", log10(1000));
    printf("log10(0.001) = %f\n", log10(0.001));
    printf("base-5 logarithm of 125 = %f\n", log10(125)/log10(5));
    // 特殊值
    printf("log10(1) = %f\n", log10(1));
    printf("log10(+Inf) = %f\n", log10(INFINITY));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("log10(0) = %f\n", log10(0));
    if(errno == ERANGE) perror("    errno == ERANGE");
    if(fetestexcept(FE_DIVBYZERO)) puts("    FE_DIVBYZERO raised");
}

可能的输出：

log10(1000) = 3.000000
log10(0.001) = -3.000000
base-5 logarithm of 125 = 3.000000
log10(1) = 0.000000
log10(+Inf) = inf
log10(0) = -inf
    errno == ERANGE: Numerical result out of range
    FE_DIVBYZERO raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.6.8 The log10 functions (p: 245)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.3.8 The log10 functions (p: 522)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.6.8 The log10 functions (p: 225-226)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.3.8 The log10 functions (p: 459)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.4.5 The log10 function

参阅

loglogflogl (C99)(C99) | 计算自然对数（底为 e ）（ \({\small \ln{x} }\)ln(x) ） (函数)
log2log2flog2l (C99)(C99)(C99) | 计算底为 2 的对数（ \({\small \log_{2}{x} }\)log2(x) ） (函数)
log1plog1pflog1pl (C99)(C99)(C99) | 计算给定数加 1 的自然对数（底为 e ）（ \({\small \ln{(1+x)} }\)ln(1+x) ） (函数)


log1p, log1pf, log1pl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float log1pf( float arg ); | (1) | (C99 起)
double log1p( double arg ); | (2) | (C99 起)
long double log1pl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define log1p( arg ) | (4) | (C99 起)
1-3) 计算 1+arg 的自然（底 e ）对数。若 arg 接近零，则此函数比表达式 log (1+arg) 更精确。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 log1pl 。否则，若 arg 拥有整数类型或 double 类型，则调用 log1p 。否则调用 log1pf 。

参数

arg - 浮点值

返回值

若不出现错误则返回 ln(1+arg) 。

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

若出现极点错误，则返回 -HUGE_VAL 、 -HUGE_VALF 或 -HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 小于 -1 则出现定义域错误。

若 arg 为 -1 则可能出现极点错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回不修改的参数。
  • 若参数为 -1 ，则返回 -∞ 并引发 FE_DIVBYZERO 。
  • 若参数小于 -1 ，则返回 NaN 并引发 FE_INVALID 。
  • 若参数为 +∞ ，则返回 +∞ 。
  • 若参数为 NaN ，则返回 NaN 。

注意

函数 expm1 和 log1p 对于金融计算有用：例如在计算小的日利率时： (1+x)n
-1 能表示为 expm1 (n * log1p(x)) 。这些函数亦简化书写精确的反双曲函数。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <errno.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("log1p(0) = %f\n", log1p(0));
    printf("Interest earned in 2 days on $100, compounded daily at 1%%\n"
           " on a 30/360 calendar = %f\n",
           100*expm1(2*log1p(0.01/360)));
    printf("log(1+1e-16) = %g, but log1p(1e-16) = %g\n",
           log(1+1e-16), log1p(1e-16));
    // 特殊值
    printf("log1p(-0) = %f\n", log1p(-0.0));
    printf("log1p(+Inf) = %f\n", log1p(INFINITY));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("log1p(-1) = %f\n", log1p(-1));
    if(errno == ERANGE) perror("    errno == ERANGE");
    if(fetestexcept(FE_DIVBYZERO)) puts("    FE_DIVBYZERO raised");
}

可能的输出：

log1p(0) = 0.000000
Interest earned in 2 days on $100, compounded daily at 1%
 on a 30/360 calendar = 0.005556
log(1+1e-16) = 0, but log1p(1e-16) = 1e-16
log1p(-0) = -0.000000
log1p(+Inf) = Inf
log1p(-1) = -Inf
    errno == ERANGE: Result too large
    FE_DIVBYZERO raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.6.9 The log1p functions (p: 245)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.3.9 The log1p functions (p: 522)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.6.9 The log1p functions (p: 226)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.3.9 The log1p functions (p: 459)

参阅

loglogflogl (C99)(C99) | 计算自然对数（底为 e ）（ \({\small \ln{x} }\)ln(x) ） (函数)
log10log10flog10l (C99)(C99) | 计算常用对数 （底为 10 ）（ \({\small \log_{10}{x} }\)log10(x) ） (函数)
log2log2flog2l (C99)(C99)(C99) | 计算底为 2 的对数（ \({\small \log_{2}{x} }\)log2(x) ） (函数)
expm1expm1fexpm1l (C99)(C99)(C99) | 计算 e 的给定次幂减一（ \({\small e^x-1}\)ex-1 ） (函数)


log2, log2f, log2l

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float log2f( float arg ); | (1) | (C99 起)
double log2( double arg ); | (2) | (C99 起)
long double log2l( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define log2( arg ) | (4) | (C99 起)
1-3) 计算 arg 的底 2 对数。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 log2l 。否则，若 arg 拥有整数类型或 double 类型，则调用 log2 。否则调用 log2f 。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 的底 2 对数（ log
2(arg) 或 lb(arg) ）。

若出现定义域错误，则返回实现定义值（支持的平台上为 NaN ）。

若出现极点错误，则返回 -HUGE_VAL 、 -HUGE_VALF 或 -HUGE_VALL 。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 小于零则出现定义域错误。

若 arg 为零则可能出现极点错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 -∞ 并引发 FE_DIVBYZERO 。
  • 若参数为 1 ，则返回 +0 。
  • 若参数为负数，则返回 NaN 并引发 FE_INVALID 。
  • 若参数为 +∞ ，则返回 +∞ 。
  • 若参数为 NaN ，则返回 NaN 。

注意

对于整数 arg ，二进制对数能转译成输入中最高位 1 的零底下标。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <errno.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("log2(65536) = %f\n", log2(65536));
    printf("log2(0.125) = %f\n", log2(0.125));
    printf("log2(0x020f) = %f (highest set bit is in position 9)\n", log2(0x020f));
    printf("base-5 logarithm of 125 = %f\n", log2(125)/log2(5));
    // 特殊值
    printf("log2(1) = %f\n", log2(1));
    printf("log2(+Inf) = %f\n", log2(INFINITY));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("log2(0) = %f\n", log2(0));
    if(errno == ERANGE) perror("    errno == ERANGE");
    if(fetestexcept(FE_DIVBYZERO)) puts("    FE_DIVBYZERO raised");
}

可能的输出：

log2(65536) = 16.000000
log2(0.125) = -3.000000
log2(0x020f) = 9.041659 (highest set bit is in position 9)
base-5 logarithm of 125 = 3.000000
log2(1) = 0.000000
log2(+Inf) = inf
log2(0) = -inf
    errno == ERANGE: Numerical result out of range
    FE_DIVBYZERO raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.6.10 The log2 functions (p: 246)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.3.10 The log2 functions (p: 522)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.6.10 The log2 functions (p: 226)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.3.10 The log2 functions (p: 459)

参阅

loglogflogl (C99)(C99) | 计算自然对数（底为 e ）（ \({\small \ln{x} }\)ln(x) ） (函数)
log10log10flog10l (C99)(C99) | 计算常用对数 （底为 10 ）（ \({\small \log_{10}{x} }\)log10(x) ） (函数)
log1plog1pflog1pl (C99)(C99)(C99) | 计算给定数加 1 的自然对数（底为 e ）（ \({\small \ln{(1+x)} }\)ln(1+x) ） (函数)
exp2exp2fexp2l (C99)(C99)(C99) | 计算 2 的给定次幂（ \({\small 2^x}\)2x ） (函数)


logb, logbf, logbl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float logbf( float arg ); | (1) | (C99 起)
double logb( double arg ); | (2) | (C99 起)
long double logbl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define logb( arg ) | (4) | (C99 起)
1-3) 从浮点参数 arg 提取独立于基底的无偏指数，并将它作为浮点值返回。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 logbl 。否则，若 arg 拥有整数类型或 double 类型，则调用 logb 。否则调用 logbf 。

正式而言，无偏指数是非零 arg 的 log
r|arg| 的有符号整数部分（此函数作为浮点值返回），其中 r 是 FLT_RADIX 。若 arg 为非正规，则当做它如同已正规化。

参数

arg - 浮点值

返回值

若不出现错误，则返回作为有符号浮点值的 arg 的无偏指数。

若出现定义域错误，则返回实现定义值。

若出现极点错误，则返回 -HUGE_VAL 、 -HUGE_VALF 或 -HUGE_VALL 。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 为零则可能出现定义域或值域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若 arg 为 ±0 ，则返回 -∞ 并引发 FE_DIVBYZERO 。
  • 若 arg 为 ±∞ ，则返回 +∞ 。
  • 若 arg 为 NaN ，则返回 NaN 。
  • 所有其他情况下，结果是准确的（决不引发 FE_INEXACT ）且忽略当前舍入模式。

注意

POSIX 要求若 arg 为 ±0 则出现极点错误。

logb 所返回的指数值始终比 frexp 所返回的小 1 ，因为不同的正规化要求：对于 logb 返回的指数 e ， |arg*r-e
| 在 1 与 r 之间（典型地在 1 与 2 之间），但 frexp 返回的指数 e ， |arg*2-e
| 在 0.5 与 1 之间。

示例

比较不同的浮点分解函数。

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON
int main(void)
{
    double f = 123.45;
    printf("Given the number %.2f or %a in hex,\n", f, f);

    double f3;
    double f2 = modf(f, &f3);
    printf("modf() makes %.0f + %.2f\n", f3, f2);

    int i;
    f2 = frexp(f, &i);
    printf("frexp() makes %f * 2^%d\n", f2, i);

    i = logb(f);
    printf("logb()/logb() make %f * %d^%d\n", f/scalbn(1.0, i), FLT_RADIX, i);

    // 错误处理
    feclearexcept(FE_ALL_EXCEPT);
    printf("logb(0) = %f\n", logb(0));
    if(fetestexcept(FE_DIVBYZERO)) puts("    FE_DIVBYZERO raised");
}

可能的输出：

Given the number 123.45 or 0x1.edccccccccccdp+6 in hex,
modf() makes 123 + 0.45
frexp() makes 0.964453 * 2^7
logb()/logb() make 1.928906 * 2^6
logb(0) = -Inf
    FE_DIVBYZERO raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.6.11 The logb functions (p: 246)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.3.11 The logb functions (p: 522)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.6.11 The logb functions (p: 227)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.3.11 The logb functions (p: 459)

参阅

frexpfrexpffrexpl (C99)(C99) | 将数拆分成有效数字和 2 的幂次 (函数)
ilogbilogbfilogbl (C99)(C99)(C99) | 提取给定数的指数（结果为整数） (函数)
scalbnscalbnfscalbnlscalblnscalblnfscalblnl (C99)(C99)(C99)(C99)(C99)(C99) | 高效计算一个数乘 FLT_RADIX 的幂 (函数)


MATH_ERRNO, MATH_ERREXCEPT, math_errhandling

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define MATH_ERRNO 1 | (C99 起)
#define MATH_ERREXCEPT 2 | (C99 起)
#define math_errhandling /*implementation defined*/ | (C99 起)

宏常量 math_errhandling 展开成 int 类型的表达式，要么等于 MATH_ERRNO ，要么等于 MATH_ERREXCEPT ，要么等于其逐位或（ MATH_ERRNO | MATH_ERREXCEPT ）。

math_errhandling 的值指示浮点运算符和函数所进行的错误处理：

常量 | 解释
MATH_ERREXCEPT | 指示使用浮点异常： <fenv.h> 中至少定义了 FE_DIVBYZERO 、 FE_INVALID 及 FE_OVERFLOW 。
MATH_ERRNO | 指明浮点运算使用变量 errno 报告错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则要求 math_errhandling & MATH_ERREXCEPT 非零。

识别下列浮点错误条件：

条件 | 解释 | errno | 浮点异常 | 示例
定义域错误 | 参数在该运算的数学上的定义域之外（每个函数的描述列出了要求的定义域错误） | EDOM | FE_INVALID | acos (2)
极点错误 | 函数的数学结果恰是无限大或未定义 | ERANGE | FE_DIVBYZERO | log (0.0) 、 1.0/0.0
上溢所致的值域错误 | 数学结果有限，但舍入后变为无限，或在向下舍入后变成最大可表示有限值 | ERANGE | FE_OVERFLOW | pow ( DBL_MAX,2)
下溢所致的值域错误 | 结果非零，但因为舍入变为零，或变成非正规并有精度损失 | ERANGE 或不改变（实现定义） | FE_UNDERFLOW 或无（实现定义） | DBL_TRUE_MIN/2
结果不准确 | 结果必须被舍入到目标类型 | 不改变 | FE_INEXACT或无（未指定） | sqrt (2) 、 1.0/10.0

注意

通常， FE_INEXACT 是否为数学库函数所引发是未指定的，但这可以显式指定于函数的描述（例如 rint vs nearbyint ）。

C99 前，浮点异常是未指定的，要求对于任何定义于错误发生 EDOM ，要求对上溢和实现定义的下溢发生 ERANGE 。

示例

#include <stdio.h>
#include <fenv.h>
#include <math.h>
#include <errno.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("MATH_ERRNO is %s\n", math_errhandling & MATH_ERRNO ? "set" : "not set");
    printf("MATH_ERREXCEPT is %s\n",
           math_errhandling & MATH_ERREXCEPT ? "set" : "not set");
    feclearexcept(FE_ALL_EXCEPT);
    errno = 0;
    printf("log(0) = %f\n", log(0));
    if(errno == ERANGE)
        perror("errno == ERANGE");
    if(fetestexcept(FE_DIVBYZERO))
        puts("FE_DIVBYZERO (pole error) reported");
}

可能的输出：

MATH_ERRNO is set
MATH_ERREXCEPT is set
log(0) = -inf
errno = ERANGE: Numerical result out of range
FE_DIVBYZERO (pole error) reported

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12/9 MATH_ERRNO, MATH_ERREXCEPT, math_errhandling (p: 233)
  • F.10/4 MATH_ERREXCEPT, math_errhandling (p: 517)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12/9 MATH_ERRNO, MATH_ERREXCEPT, math_errhandling (p: 214)
  • F.9/4 MATH_ERREXCEPT, math_errhandling> (p: 454)

参阅

FE_ALL_EXCEPTFE_DIVBYZEROFE_INEXACTFE_INVALIDFE_OVERFLOWFE_UNDERFLOW (C99) | 浮点异常 (宏常量)
errno | 展开成 POSIX 兼容的线程局域错误编号变量 (宏变量)


modf, modff, modfl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float modff( float arg, float* iptr ); | (1) | (C99 起)
double modf( double arg, double* iptr ); | (2) |
long double modfl( long double arg, long double* iptr ); | (3) | (C99 起)
1-3) 分解给定的浮点值 arg 为整数和分数部分，每个都拥有与 arg 相同的类型和符号。（以浮点格式）存储整数部分于 iptr 所指向的对象。

参数

arg | - | 浮点值
iptr | - | 指向要存储整数部分的目标的浮点值的指针

返回值

若不出现错误，则返回与 x 相同符号的 x 小数部分。将整数部分放进 iptr 所指向的值。

返回值和存储于 *iptr 的值的和给出 arg （允许舍入）。

错误处理

此函数不受制于任何指定于 math_errhandling 的错误。

若实现支持 IEE 浮点算术（ IEC 60559 ），则

  • 若 arg 为 ±0 ，则返回 ±0 ，并存储 ±0 于 *iptr 。
  • 若 arg 为 ±∞ ，则返回 ±0 ，并存储 ±∞ 于 *iptr 。
  • 若 arg 为 NaN ，则返回 NaN ，并存储 NaN 于 *iptr 。
  • 返回值是准确的，忽略当前舍入模式。

注意

此函数表现为如同实现如下：

double modf(double value, double *iptr)
{
#pragma STDC FENV_ACCESS ON
    int save_round = fegetround();
    fesetround(FE_TOWARDZERO);
    *iptr = std::nearbyint(value);
    fesetround(save_round);
    return copysign(isinf(value) ? 0.0 : value - (*iptr), value);
}

示例

#include <stdio.h>
#include <math.h>
#include <float.h>

int main(void)
{
    double f = 123.45;
    printf("Given the number %.2f or %a in hex,\n", f, f);

    double f3;
    double f2 = modf(f, &f3);
    printf("modf() makes %.2f + %.2f\n", f3, f2);

    int i;
    f2 = frexp(f, &i);
    printf("frexp() makes %f * 2^%d\n", f2, i);

    i = ilogb(f);
    printf("logb()/ilogb() make %f * %d^%d\n", f/scalbn(1.0, i), FLT_RADIX, i);

    // 特殊值
    f2 = modf(-0.0, &f3);
    printf("modf(-0) makes %.2f + %.2f\n", f3, f2);
    f2 = modf(-INFINITY, &f3);
    printf("modf(-Inf) makes %.2f + %.2f\n", f3, f2);
}

可能的输出：

Given the number 123.45 or 0x1.edccccccccccdp+6 in hex,
modf() makes 123.00 + 0.45
frexp() makes 0.964453 * 2^7
logb()/ilogb() make 1.92891 * 2^6
modf(-0) makes -0.00 + -0.00
modf(-Inf) makes -INF + -0.00

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.6.12 The modf functions (p: 246-247)
  • F.10.3.12 The modf functions (p: 523)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.6.12 The modf functions (p: 227)
  • F.9.3.12 The modf functions (p: 460)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.4.6 The modf function

参阅

trunctruncftruncl
(C99)(C99)(C99)
 取整到绝对值不大于给定值的最接近整数
(函数)


NAN

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define NAN /*implementation defined*/ | (C99 起)

宏 NAN 展开成求值为安静非数（ QNaN ）的 float 类型常量表达式。若实现不支持 QNaN ，则不定义此宏。

用于打印 NaN 的风格是实现定义的。

注意

有许多不同的 NaN 值，区别于其载荷与其符号位。宏 NAN 所生成的 NaN 的载荷与符号位的内容是实现定义的。

示例

显示用于打印 NaN 的风格和 IEEE 格式。

#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>

int main(void)
{
    double f = NAN;
    uint64_t fn; memcpy(&fn, &f, sizeof f);
    printf("NAN:   %f %" PRIx64 "\n", f, fn);
}

可能的输出：

NAN:   nan 7ff8000000000000

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12/5 NAN (p: 232)
  • F.10/11/13 NAN (p: 518)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12/5 NAN (p: 213)
  • F.9/11/13 NAN (p: 455)

参阅

nannanfnanl (C99)(C99)(C99) | 返回 NaN （非数） (函数)
isnan (C99) | 检查给定数是否为 NaN (宏函数)


nearbyint, nearbyintf, nearbyintl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float nearbyintf( float arg ); | (1) | (C99 起)
double nearbyint( double arg ); | (2) | (C99 起)
long double nearbyintl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define nearbyint( arg ) | (4) | (C99 起)
1-3) 以当前舍入模式，舍入浮点参数 arg 到浮点格式的整数值。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 nearbyintl 。否则，若 arg 拥有整数类型或 double 类型，则调用 nearbyint 。否则调用 nearbyintf 。

参数值

arg - 浮点值

返回值

返回 arg 按照当前舍入模式的最接近整数值。

错误处理

此函数不受制于任何指定于 math_errhandling 的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 决不引发 FE_INEXACT
  • 若 arg 为 ±∞ ，则返回不修改的参数
  • 若 arg 为 ±0 ，则返回不修改的参数
  • 若 arg 为 NaN ，则返回 NaN

注意

nearbyint 和 rint 之间仅有的区别是 nearbyint 决不引发 FE_INEXACT 。

所有标准浮点格式中，最大可表示浮点值都是整数，故 nearbyint 自身决不溢出；然而存储结果于整数对象时，结果可能溢出任何整数类型（包含 intmax_t ）。

若当前舍入模式为 FE_TONEAREST ，则此函数在中点情况向偶数舍入（同 rint ，但不同于 round ）。

示例

#include <stdio.h>
#include <math.h>
#include <fenv.h>

int main(void)
{
#pragma STDC FENV_ACCESS ON
    fesetround(FE_TONEAREST);
    printf("rounding to nearest:\nnearbyint(+2.3) = %+.1f  ", nearbyint(2.3));
    printf("nearbyint(+2.5) = %+.1f  ", nearbyint(2.5));
    printf("nearbyint(+3.5) = %+.1f\n", nearbyint(3.5));
    printf("nearbyint(-2.3) = %+.1f  ", nearbyint(-2.3));
    printf("nearbyint(-2.5) = %+.1f  ", nearbyint(-2.5));
    printf("nearbyint(-3.5) = %+.1f\n", nearbyint(-3.5));

    fesetround(FE_DOWNWARD);
    printf("rounding down: \nnearbyint(+2.3) = %+.1f  ", nearbyint(2.3));
    printf("nearbyint(+2.5) = %+.1f  ", nearbyint(2.5));
    printf("nearbyint(+3.5) = %+.1f\n", nearbyint(3.5));
    printf("nearbyint(-2.3) = %+.1f  ", nearbyint(-2.3));
    printf("nearbyint(-2.5) = %+.1f  ", nearbyint(-2.5));
    printf("nearbyint(-3.5) = %+.1f\n", nearbyint(-3.5));

    printf("nearbyint(-0.0) = %+.1f\n", nearbyint(-0.0));
    printf("nearbyint(-Inf) = %+.1f\n", nearbyint(-INFINITY));
}

输出：

rounding to nearest:
nearbyint(+2.3) = +2.0  nearbyint(+2.5) = +2.0  nearbyint(+3.5) = +4.0
nearbyint(-2.3) = -2.0  nearbyint(-2.5) = -2.0  nearbyint(-3.5) = -4.0
rounding down:
nearbyint(+2.3) = +2.0  nearbyint(+2.5) = +2.0  nearbyint(+3.5) = +3.0
nearbyint(-2.3) = -3.0  nearbyint(-2.5) = -3.0  nearbyint(-3.5) = -4.0
nearbyint(-0.0) = -0.0
nearbyint(-Inf) = -inf

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.9.3 The nearbyint functions (p: 251-252)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.6.3 The nearbyint functions (p: 526)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.9.3 The nearbyint functions (p: 232)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.6.3 The nearbyint functions (p: 463)

参阅

rintrintfrintllrintlrintflrintlllrintllrintfllrintl (C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99) | 使用当前舍入模式取整到整数，若结果有误则产生异常 (函数)
roundroundfroundllroundlroundflroundllroundllroundfllroundl (C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99) | 取整到最接近的整数，在相邻整数正中间时取远离零的数 (函数)
fegetroundfesetround (C99)(C99) | 获得或设置数字的舍入方向 (函数)


nextafter, nextafterf, nextafterl, nexttoward, nexttowardf, nexttowardl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float nextafterf( float from, float to ); | (1) | (C99 起)
double nextafter( double from, double to ); | (2) | (C99 起)
long double nextafterl( long double from, long double to ); | (3) | (C99 起)
float nexttowardf( float from, long double to ); | (4) | (C99 起)
double nexttoward( double from, long double to ); | (5) | (C99 起)
long double nexttowardl( long double from, long double to ); | (6) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define nextafter(from, to) | (7) | (C99 起)
#define nexttoward(from, to) | (8) | (C99 起)
1-3) 首先，转换两个参数为函数的类型，然后返回 from 于 to 方向的下个可表示值。若 from 等于 to ，则返回 to 。
4-6) 首先，转换两个参数为函数的类型，然后返回 from 于 to 方向的下个可表示值。若 from 等于 to ，则返回从 long double 转换到函数返回类型的 to ，而不带范围或精度的损失。
7) 泛型宏：若任何参数拥有 long double 类型，则调用 nextafterl 。否则，若任何参数拥有整数类型或 double 类型，则调用 nextafter 。否则调用 nextafterf 。
8) 泛型宏：若任何参数拥有 long double 类型，则调用 nexttowardl 。否则，若任何参数拥有整数类型或 double 类型，则调用 nexttoward 。否则调用 nexttowardf 。

参数

from, to - 浮点值

返回值

若不出现错误，则返回 from 于 to 的方向的下个可表示值。若 from 等于 to ，则返回 to ，转换到函数的类型。

若出现上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL （所带符号同 from ）。

若出现下溢所致的值域错误，则返回正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若 from 有限，但期待的结果无限，则引发 FE_INEXACT 和 FE_OVERFLOW 。
  • 若 from 不等于 to 且结果为非正规或零，则引发 FE_INEXACT 和 FE_UNDERFLOW 。
  • 任何情况下，返回值独立于当前舍入模式。
  • 若 from 或 to 为 NaN ，则返回 NaN

注解

POSIX 指定上溢和下溢条件是值域错误（可以设置 errno ）。

IEC 60559 推荐凡在 from==to 时返回 from 。这些函数替而返回 to ，这使得围绕零的行为一致： nextafter(-0.0, +0.0) 返回 +0.0 而 nextafter(+0.0, -0.0) 返回 –0.0 。

nextafter 常通过操纵 IEEE 表示实现（ glibc ）（ musl ）。

示例

#include <math.h>
#include <stdio.h>
#include <float.h>
#include <fenv.h>

int main(void)
{
    float from1 = 0, to1 = nextafterf(from1, 1);
    printf("The next representable float after %.2f is %.20g (%a)\n", from1, to1, to1);

    float from2 = 1, to2 = nextafterf(from2, 2);
    printf("The next representable float after %.2f is %.20f (%a)\n", from2, to2, to2);

    double from3 = nextafter(0.1, 0), to3 = 0.1;
    printf("The number 0.1 lies between two valid doubles:\n"
           "    %.56f (%a)\nand %.55f  (%a)\n", from3, from3, to3, to3);

    // nextafter 和 nexttoward 间的差异：
    long double dir = nextafterl(from1, 1); // 第一个非正规 long double
    float x = nextafterf(from1, dir); // 首先转换 dir 为 float ，给出 0
    printf("Using nextafter, next float after %.2f (%a) is %.20g (%a)\n",
           from1, from1, x, x);
    x = nexttowardf(from1, dir);
    printf("Using nexttoward, next float after %.2f (%a) is %.20g (%a)\n",
           from1, from1, x, x);

    // 特殊值
    {
        #pragma STDC FENV_ACCESS ON
        feclearexcept(FE_ALL_EXCEPT);
        double from4 = DBL_MAX, to4 = nextafter(from4, INFINITY);
        printf("The next representable double after %.2g (%a) is %.23f (%a)\n",
               from4, from4, to4, to4);
        if(fetestexcept(FE_OVERFLOW)) puts("   raised FE_OVERFLOW");
        if(fetestexcept(FE_INEXACT)) puts("   raised FE_INEXACT");
    } // 结束 FENV_ACCESS 块

    float from5 = 0.0, to5 = nextafter(from5, -0.0);
    printf("nextafter(+0.0, -0.0) gives %.2g (%a)\n", to5, to5);
}

输出：

The next representable float after 0.00 is 1.4012984643248170709e-45 (0x1p-149)
The next representable float after 1.00 is 1.00000011920928955078 (0x1.000002p+0)
The number 0.1 lies between two valid doubles:
    0.09999999999999999167332731531132594682276248931884765625 (0x1.9999999999999p-4)
and 0.1000000000000000055511151231257827021181583404541015625  (0x1.999999999999ap-4)
Using nextafter, next float after 0.00 (0x0p+0) is 0 (0x0p+0)
Using nexttoward, next float after 0.00 (0x0p+0) is 1.4012984643248170709e-45 (0x1p-149)
The next representable double after 1.8e+308 (0x1.fffffffffffffp+1023) is inf (inf)
   raised FE_OVERFLOW
   raised FE_INEXACT
nextafter(+0.0, -0.0) gives -0 (-0x0p+0)

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.12.11.3 The nextafter functions (p: 187)
  • 7.12.11.4 The nexttoward functions (p: 187)
  • 7.25 Type-generic math <tgmath.h> (p: 272-273)
  • F.10.8.3 The nextafter functions (p: 386)
  • F.10.8.4 The nexttoward functions (p: 386)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.11.3 The nextafter functions (p: 256)
  • 7.12.11.4 The nexttoward functions (p: 257)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.8.3 The nextafter functions (p: 529)
  • F.10.8.4 The nexttoward functions (p: 529)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.11.3 The nextafter functions (p: 237)
  • 7.12.11.4 The nexttoward functions (p: 238)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.8.3 The nextafter functions (p: 466)
  • F.9.8.4 The nexttoward functions (p: 466)

参阅


pow, powf, powl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float powf( float base, float exponent ); | (1) | (C99 起)
double pow( double base, double exponent ); | (2) |
long double powl( long double base, long double exponent ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define pow( base, exponent ) | (4) | (C99 起)
1-3) 计算 base 的 exponent 次幂。
4) 泛型宏：若任何参数拥有 long double 类型，则调用 powl 。否则，若任何参数拥有整数类型或 double 类型，则调用 pow 。否则调用 powf 。若至少一个参数为复数或虚数，则宏调用对应的复函数（ cpowf 、 cpow 、 cpowl ）。

参数

base | - | 作为底的浮点值
exponent | - | 作为指数的浮点值

返回值

若不出现错误，则返回 base 的 exponent 次幂（ baseexponent
 ）。

若出现定义域错误，则返回实现定义值（支持的平台上为 NaN ）。

若出现极点错误或上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若 base 有限且为负，且 exponent 有限且为非整数，则出现定义域错误，并可能出现值域错误。

若 base 为零且 exponent 为零，则可能出现定义域错误。

若 base 为零且 exponent 为负，则可能出现定义域错误或极点错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • pow(+0, exponent) ，其中 exponent 为负奇数，返回 +∞ 并引发 FE_DIVBYZERO
  • pow(-0, exponent) ，其中 exponent 为负奇数，返回 -∞ 并引发 FE_DIVBYZERO
  • pow(±0, exponent) ，其中 exponent 为有限负数，且为偶数或非整数，则返回 +∞ 并引发 FE_DIVBYZERO
  • pow(±0, -∞) 返回 +∞ 并可能引发 FE_DIVBYZERO (C23 前)
  • pow(+0, exponent) ，其中 exponent 为正奇数，返回 +0
  • pow(-0, exponent) ，其中 exponent 为正奇数，返回 -0
  • pow(±0, exponent) ，其中 exponent 为正非整数或正偶数，返回 +0
  • pow(-1, ±∞) returns 1
  • pow(+1, exponent) 对于任何 exponent 返回 1 ，即使 exponent 为 NaN
  • pow(base, ±0) 对于任何 base 返回 1 ，即使 base 为 NaN
  • pow(base, exponent) 返回 NaN 并引发 FE_INVALID ，若 base 为有限负数且 exponent 为有限非整数。
  • pow(base, -∞) 对任何 |base|<1 返回 +∞
  • pow(base, -∞) 对任何 |base|>1 返回 +0
  • pow(base, +∞) 对任何 |base|<1 返回 +0
  • pow(base, +∞) 对任何 |base|>1 返回 +∞
  • pow(-∞, exponent) 返回 -0 ，若 exponent 为负奇整数
  • pow(-∞, exponent) 返回 +0 ，若 exponent 为负非整数或负偶数
  • pow(-∞, exponent) 返回 -∞ ，若 exponent 为正奇整数
  • pow(-∞, exponent) 返回 +∞ ，若 exponent 为正非整数或正偶数
  • pow(+∞, exponent) 对任何 exponent 返回 +0
  • pow(+∞, exponent) 对任何 exponent 返回 +∞
  • 除了指定于上处，若任何参数为 NaN ，则返回 NaN

注解

尽管 pow 不能获得负数的开方根，也为 exponent 为 1/3 的常用情况提供了 cbrt 。

示例

#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON
int main(void)
{
    // 典型使用
    printf("pow(2, 10) = %f\n", pow(2,10));
    printf("pow(2, 0.5) = %f\n", pow(2,0.5));
    printf("pow(-2, -3) = %f\n", pow(-2,-3));
    // 特殊值
    printf("pow(-1, NAN) = %f\n", pow(-1,NAN));
    printf("pow(+1, NAN) = %f\n", pow(+1,NAN));
    printf("pow(INFINITY, 2) = %f\n", pow(INFINITY, 2));
    printf("pow(INFINITY, -1) = %f\n", pow(INFINITY, -1));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("pow(-1, 1/3) = %f\n", pow(-1, 1.0/3));
    if(errno == EDOM)         perror("    errno == EDOM");
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID raised");

    feclearexcept(FE_ALL_EXCEPT);
    printf("pow(-0, -3) = %f\n", pow(-0.0, -3));
    if(fetestexcept(FE_DIVBYZERO)) puts("    FE_DIVBYZERO raised");
}

可能的输出：

pow(2, 10) = 1024.000000
pow(2, 0.5) = 1.414214
pow(-2, -3) = -0.125000
pow(-1, NAN) = nan
pow(+1, NAN) = 1.000000
pow(INFINITY, 2) = inf
pow(INFINITY, -1) = 0.000000
pow(-1, 1/3) = -nan
    errno == EDOM: Numerical argument out of domain
    FE_INVALID raised
pow(-0, -3) = -inf
    FE_DIVBYZERO raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.7.4 The pow functions (p: 248-249)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.4.4 The pow functions (p: 524-525)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.7.4 The pow functions (p: 229)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.4.4 The pow functions (p: 461)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.5.1 The pow function

参阅

sqrtsqrtfsqrtl (C99)(C99) | 计算平方根（ \(\small{\sqrt{x} }\)√x ） (函数)
cbrtcbrtfcbrtl (C99)(C99)(C99) | 计算立方根（ \(\small{\sqrt[3]{x} }\)3√x ） (函数)
hypothypotfhypotl (C99)(C99)(C99) | 计算两个给定数平方和的平方根 （ \(\scriptsize{\sqrt{x^2+y^2} }\)√x2 +y2 ） (函数)
cpowcpowfcpowl (C99)(C99)(C99) | 计算复数幂函数 (函数)


remainder, remainderf, remainderl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float remainderf( float x, float y ); | (1) | (C99 起)
double remainder( double x, double y ); | (2) | (C99 起)
long double remainderl( long double x, long double y ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define remainder( x, y ) | (4) | (C99 起)
1-3@) 计算浮点除法运算 x/y 的 IEEE 余数。
4) 泛型宏：若任何参数拥有 long double 类型，则调用 remainderl 。否则若任何参数拥有整数类型或 double 类型，则调用 remainder 。否则调用 remainderf 。

此函数所计算的除法运算 x/y 的 IEEE 浮点余数，准确地为值 x - n*y ，其中值 n 是最接近 x/y 准确值的整数值。 |n-x/y| = ½ 时，选择作为偶数的 n 。

与 std::fmod() 相反，不保证返回值拥有与 x 相同的符号。

若返回值是 0 ，则它拥有与 x 相同的符号。

参数

x, y - 浮点值

返回值

若成功，则返回定义如上的除法 x/y 浮点余数。

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

若出现下溢所致的值域错误，则返回正确结果。

若 y 为零但不出现定义域错误，则返回零。

错误处理

报告 math_errhandling 中指定的错误。

若 y 为零则可能出现定义域错误。

若实现支持 IEEE 浮点算术 （ IEC 60559 ），则

  • 当前舍入模式无效。
  • 决不引发 FE_INEXACT ，结果始终准确。
  • 若 x 为 ±∞ 且 y 非 NaN ，则返回 NaN 并引发 FE_INVALID 。
  • 若 y 为 ±0 且 x 非 NaN ，则返回 NaN 并引发 FE_INVALID 。
  • 若任一参数为 NaN ，则返回 NaN 。

注意

POSIX 要求若 x 为无穷大或 y 为零则出现定义域错误。

fmod ，但不是 remainder ，适于安静地包装浮点类型到无符号整数类型： (0.0 <= (y = fmod ( rint (x), 65536.0 )) ? y : 65536.0 + y) 在范围 [-0.0 .. 65535.0] 内，它对应 unsigned short ，但 remainder( rint (x), 65536.0) 在范围 [-32767.0, +32768.0] 内，它在 signed short 的范围外。

示例

#include <stdio.h>
#include <math.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("remainder(+5.1, +3.0) = %.1f\n", remainder(5.1,3));
    printf("remainder(-5.1, +3.0) = %.1f\n", remainder(-5.1,3));
    printf("remainder(+5.1, -3.0) = %.1f\n", remainder(5.1,-3));
    printf("remainder(-5.1, -3.0) = %.1f\n", remainder(-5.1,-3));

    // 特殊值
    printf("remainder(-0.0, 1.0) = %.1f\n", remainder(-0.0, 1));
    printf("remainder(+5.1, Inf) = %.1f\n", remainder(5.1, INFINITY));

    // 错误处理
    feclearexcept(FE_ALL_EXCEPT);
    printf("remainder(+5.1, 0) = %.1f\n", remainder(5.1, 0));
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID raised");
}

输出：

remainder(+5.1, +3.0) = -0.9
remainder(-5.1, +3.0) = 0.9
remainder(+5.1, -3.0) = -0.9
remainder(-5.1, -3.0) = 0.9
remainder(+0.0, 1.0) = 0.0
remainder(-0.0, 1.0) = -0.0
remainder(+5.1, Inf) = 5.1
remainder(+5.1, 0) = -nan
    FE_INVALID raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.10.2 The remainder functions (p: 254-255)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.7.2 The remainder functions (p: 529)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.10.2 The remainder functions (p: 235)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.7.2 The remainder functions (p: 465)

参阅

divldivlldiv (C99) | 计算整数除法的商和余数 (函数)
fmodfmodffmodl (C99)(C99) | 计算浮点除法运算的余数 (函数)
remquoremquofremquol (C99)(C99)(C99) | 计算除法运算的带符号余数，以及商的后三位 (函数)


remquo, remquof, remquol

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float remquof( float x, float y, int *quo ); | (1) | (C99 起)
double remquo( double x, double y, int *quo ); | (2) | (C99 起)
long double remquol( long double x, long double y, int *quo ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define remquo( x, y, quo ) | (4) | (C99 起)
1-3) 计算除法运算 x/y 的浮点余数，如 remainder() 函数所为。另外，将存储 x/y 的至少最低三位及符号于 quo ，这足以确定结果在周期中的八分位。
4) 泛型宏：若任何非指针参数拥有 long double 类型，则调用 remquol 。否则，若任何非指针参数拥有整数类型或 double 类型，则调用 remquo 。否则，调用 remquof 。

参数

x, y | - | 浮点值
quo | - | 指向存储 x/y 的符号和某些位的整数的指针

返回值

若成功，则返回定义于 remainder 的 x/y 的余数，并存储 x/y 的符号和至少后三位有效数字于 *quo （正式而言，存储的值的符号是 x/y 的符号，而绝对值与 x/y 的整数商的绝对值对于 modulo 2n
 同余，其中 n 是实现定义的大于或等于 3 的整数）。

若 y 为零，则存储于 *quo 的值未指定。

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

若出现下溢所致的值域错误，则若支持非正规值则返回正确结果。

若 y 为零，但不出现定义域错误，则返回零。

错误处理

报告 math_errhandling 中指定的错误。

若 y 为零则可能出现定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 当前舍入模式无效。
  • 决不引发 FE_INEXACT 。
  • 若 x 为 ±∞ 且 y 非 NaN ，则返回 NaN 并引发 FE_INVALID 。
  • 若 y 为 ±0 且 x 非 NaN ，则返回 NaN 并引发 FE_INVALID 。
  • 若 x 或 y 为 NaN ，则返回 NaN 。

注意

POSIX 要求若 x 为无穷大或 y 为零则出现定义域错误。

此函数在实现周期可准确表示为浮点值的周期函数时有用：对非常大的 x 计算 sin(πx) 时，直接调用 sin 可能导致巨大误差，但若首先以 remquo 减小参数，则商的低位可用来确定结果在周期中的八分位，同时余数可用来计算拥有高精度的值。

某些平台上硬件支持此运算（而例如在 Intel CPU 上， FPREM1 在完成时于商中准确保留 3 位精度）。

示例

#include <stdio.h>
#include <math.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON
double cos_pi_x_naive(double x)
{
    double pi = acos(-1);
    return cos(pi * x);
}
// 周期为 2 ，值为 (0;0.5) 正， (0.5;1.5) 负， (1.5,2) 正
double cos_pi_x_smart(double x)
{
    int quadrant;
    double rem = remquo(x, 1, &quadrant);
    quadrant = (unsigned)quadrant % 4; // 保留 2 位以确定象限

    double pi = acos(-1);
    switch(quadrant) {
        case 0: return cos(pi * rem);
        case 1: return -cos(pi * rem);
        case 2: return -cos(pi * rem);
        case 3: return cos(pi * rem);
    };
}
int main(void)
{
    printf("cos(pi * 0.25) = %f\n", cos_pi_x_naive(0.25));
    printf("cos(pi * 1.25) = %f\n", cos_pi_x_naive(1.25));
    printf("cos(pi * 1000000000000.25) = %f\n", cos_pi_x_naive(1000000000000.25));
    printf("cos(pi * 1000000000001.25) = %f\n", cos_pi_x_naive(1000000000001.25));
    printf("cos(pi * 1000000000000.25) = %f\n", cos_pi_x_smart(1000000000000.25));
    printf("cos(pi * 1000000000001.25) = %f\n", cos_pi_x_smart(1000000000001.25));
    // 错误处理
    feclearexcept(FE_ALL_EXCEPT);
    int quo;
    printf("remquo(+Inf, 1) = %.1f\n", remquo(INFINITY, 1, &quo));
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID raised");
}

可能的输出：

cos(pi * 0.25) = 0.707107
cos(pi * 1.25) = -0.707107
cos(pi * 1000000000000.25) = 0.707123
cos(pi * 1000000000001.25) = -0.707117
cos(pi * 1000000000000.25) = 0.707107
cos(pi * 1000000000001.25) = -0.707107
remquo(+Inf, 1) = -nan
    FE_INVALID raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.10.3 The remquo functions (p: 255)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.7.3 The remquo functions (p: 529)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.10.3 The remquo functions (p: 236)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.7.3 The remquo functions (p: 465)

参阅

divldivlldiv (C99) | 计算整数除法的商和余数 (函数)
fmodfmodffmodl (C99)(C99) | 计算浮点除法运算的余数 (函数)
remainderremainderfremainderl (C99)(C99)(C99) | 计算浮点除法运算的带符号余数 (函数)


rint, rintf, rintl, lrint, lrintf, lrintl, llrint, llrintf, llrintl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float rintf( float arg ); | (1) | (C99 起)
double rint( double arg ); | (2) | (C99 起)
long double rintl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define rint( arg ) | (4) | (C99 起)
定义于头文件 <math.h> |  |
long lrintf( float arg ); | (5) | (C99 起)
long lrint( double arg ); | (6) | (C99 起)
long lrintl( long double arg ); | (7) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define lrint( arg ) | (8) | (C99 起)
定义于头文件 <math.h> |  |
long long llrintf( float arg ); | (9) | (C99 起)
long long llrint( double arg ); | (10) | (C99 起)
long long llrintl( long double arg ); | (11) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define llrint( arg ) | (12) | (C99 起)
1-3) 用当前舍入模式，舍入浮点参数 arg 为整数值（以浮点格式）。
5-7, 9-11) 用当前舍入模式，舍入浮点参数 arg 为整数值。
4,8,12) 泛型宏：若 arg 拥有 long double 类型，，则调用 rintl 、 lrintl 、 llrintl 。否则若 arg 拥有整数或 double 类型，则调用 rint 、 lrint 、 llrint 。否则分别调用 rintf 、 lrintf 、 llrintf 。

参数

arg - 浮点值

返回值

若不出现错误，则按照当前舍入模式的最接近整数值。

错误处理

报告 math_errhandling 中指定的错误。

若 lrint 或 llrint 的结果在返回类型的可表示范围外，则可能出现定义域错误或值域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

对于 rint 函数：
  • 若 arg 为 ±∞ ，则返回不修改的参数
  • 若 arg 为 ±0 ，则返回不修改的参数
  • 若 arg 为 NaN ，则返回 NaN
对于 lrint 和 llrint 函数：
  • 若 arg 为 ±∞ ，则引发 FE_INVALID 并返回实现定义值
  • 若舍入结果在返回类型范围外，则引发 FE_INVALID 并返回实现定义值
  • 若 arg 为 NaN ，则引发 FE_INVALID 并返回实现定义值

注意

POSIX 指定 lrint 或 llrint 引发 FE_INEXACT 的所有情况都是定义域错误。

如指定于 math_errhandling ， rint 在舍入非整数有限值时可以（但不在非 IEEE 浮点平台上要求）引发 FE_INEXACT 。

rint 和 nearbyint 间仅有的区别是 nearbyint 决不引发 FE_INEXACT 。

所有标准浮点格式中，最大可表示浮点值都是准确的整数，故 rint 自身决不上溢；然而在存储结果于整数对象时，结果可能溢出任何整数类型（包含 intmax_t ）。

若当前舍入模式为……

  • FE_DOWNWARD ，则 rint 等价于 floor 。
  • FE_UPWARD ，则 rint 等价于 ceil 。
  • FE_TOWARDZERO ，则 rint 等价于 trunc 。
  • FE_TONEAREST ，则 rint 在中点情况和 round 的区别是前者始终舍入到偶数，而非远离零。

示例

#include <stdio.h>
#include <math.h>
#include <fenv.h>
#include <limits.h>

int main(void)
{
#pragma STDC FENV_ACCESS ON
    fesetround(FE_TONEAREST);
    printf("rounding to nearest (halfway cases to even):\n"
           "rint(+2.3) = %+.1f  ", rint(2.3));
    printf("rint(+2.5) = %+.1f  ", rint(2.5));
    printf("rint(+3.5) = %+.1f\n", rint(3.5));
    printf("rint(-2.3) = %+.1f  ", rint(-2.3));
    printf("rint(-2.5) = %+.1f  ", rint(-2.5));
    printf("rint(-3.5) = %+.1f\n", rint(-3.5));

    fesetround(FE_DOWNWARD);
    printf("rounding down: \nrint(+2.3) = %+.1f  ", rint(2.3));
    printf("rint(+2.5) = %+.1f  ", rint(2.5));
    printf("rint(+3.5) = %+.1f\n", rint(3.5));
    printf("rint(-2.3) = %+.1f  ", rint(-2.3));
    printf("rint(-2.5) = %+.1f  ", rint(-2.5));
    printf("rint(-3.5) = %+.1f\n", rint(-3.5));
    printf("rounding down with lrint: \nlrint(+2.3) = %ld  ", lrint(2.3));
    printf("lrint(+2.5) = %ld  ", lrint(2.5));
    printf("lrint(+3.5) = %ld\n", lrint(3.5));
    printf("lrint(-2.3) = %ld  ", lrint(-2.3));
    printf("lrint(-2.5) = %ld  ", lrint(-2.5));
    printf("lrint(-3.5) = %ld\n", lrint(-3.5));

    printf("lrint(-0.0) = %ld\n", lrint(-0.0));
    printf("lrint(-Inf) = %ld\n", lrint(-INFINITY)); // 引发 FE_INVALID

    // 错误处理
    feclearexcept(FE_ALL_EXCEPT);
    printf("rint(1.1) = %.1f\n", rint(1.1));
    if(fetestexcept(FE_INEXACT)) puts("    FE_INEXACT was raised");

    feclearexcept(FE_ALL_EXCEPT);
    printf("lrint(LONG_MIN-2048.0) = %ld\n", lrint(LONG_MIN-2048.0));
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID was raised");
}

可能的输出：

rounding to nearest (halfway cases to even):
rint(+2.3) = +2.0  rint(+2.5) = +2.0  rint(+3.5) = +4.0
rint(-2.3) = -2.0  rint(-2.5) = -2.0  rint(-3.5) = -4.0
rounding down:
rint(+2.3) = +2.0  rint(+2.5) = +2.0  rint(+3.5) = +3.0
rint(-2.3) = -3.0  rint(-2.5) = -3.0  rint(-3.5) = -4.0
rounding down with lrint:
lrint(+2.3) = 2  lrint(+2.5) = 2  lrint(+3.5) = 3
lrint(-2.3) = -3  lrint(-2.5) = -3  lrint(-3.5) = -4
lrint(-0.0) = 0
lrint(-Inf) = -9223372036854775808
rint(1.1) = 1.0
    FE_INEXACT was raised
lrint(LONG_MIN-2048.0) = -9223372036854775808
    FE_INVALID was raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.9.4 The rint functions (p: 252)
  • 7.12.9.5 The lrint and llrint functions (p: 252)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.6.4 The rint functions (p: 527)
  • F.10.6.5 The lrint and llrint functions (p: 527)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.9.4 The rint functions (p: 232-233)
  • 7.12.9.5 The lrint and llrint functions (p: 233)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.6.4 The rint functions (p: 463)
  • F.9.6.5 The lrint and llrint functions (p: 463)

参阅

trunctruncftruncl (C99)(C99)(C99) | 取整到绝对值不大于给定值的最接近整数 (函数)
nearbyintnearbyintfnearbyintl (C99)(C99)(C99) | 用当前舍入模式取整到整数 (函数)
fegetroundfesetround (C99)(C99) | 获得或设置数字的舍入方向 (函数)


round, roundf, roundl, lround, lroundf, lroundl, llround, llroundf, llroundl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float roundf( float arg ); | (1) | (C99 起)
double round( double arg ); | (2) | (C99 起)
long double roundl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define round( arg ) | (4) | (C99 起)
定义于头文件 <math.h> |  |
long lroundf( float arg ); | (5) | (C99 起)
long lround( double arg ); | (6) | (C99 起)
long lroundl( long double arg ); | (7) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define lround( arg ) | (8) | (C99 起)
定义于头文件 <math.h> |  |
long long llroundf( float arg ); | (9) | (C99 起)
long long llround( double arg ); | (10) | (C99 起)
long long llroundl( long double arg ); | (11) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define llround( arg ) | (12) | (C99 起)
1-3) 计算与 arg 最邻近的整数值（以浮点格式），中点情况取远离零者，无关乎当前舍入模式。
5-7, 9-11) 计算与 arg 最邻近的整数值（以整数格式），中点情况取远离零者，无关乎当前舍入模式。
4,8,12) 泛型宏：若 arg 拥有 long double 类型，则分别调用 roundl 、 lroundl 、 llroundl 。否则，若 arg 拥有整数类型或 double 类型，则分别调用 round 、 lround 、 llround 。否则分别调用 roundf, lroundf, llroundf 。

参数

arg - 浮点值

返回值

若不出现错误，则与返回 arg 的最邻近整数值，中点情况取远离零者，

返回值
math-round away zero.svg
参数

若出现定义域错误，则返回实现定义值。

错误处理

报告 math_errhandling 中指定的错误。

若 lround 或 llround 的结果在返回类型的可表示范围外，则可能出现定义域错误或值域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），

对于 round 、 roundf 及 roundl 函数：
  • 当前舍入模式无效。
  • 若 arg 为 ±∞ ，则返回不修改的该值
  • 若 arg 为 ±0 ，则返回不修改的该值
  • 若 arg 为 NaN ，则返回 NaN
对于 lround 与 llround 函数族：
  • 决不引发 FE_INEXACT
  • 当前舍入模式无效。
  • 若 arg 为 ±∞ ，则引发 FE_INVALID 并返回实现定义值
  • 若舍入结果在返回类型的范围外，则引发 FE_INVALID 并返回实现定义值
  • 若 arg 为 NaN ，则引发 FE_INVALID 并返回实现定义值

注意

round 在舍入非整数有限值时，可以（但不要求）引发 FE_INEXACT 。

所有标准浮点格式中，最大可表示浮点值均为准确的整数，故 round 自身决不上溢；然而在存储于整数对象时，结果可能溢出任何整数类型（包含 intmax_t ）。

POSIX 指定 lround 或 llround 引发 FE_INEXACT 的所有情况都是定义域错误。

round 的 double 版本如同实现如下：

#include <math.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
double round(double x)
{
    fenv_t save_env;
    feholdexcept(&save_env);
    double result = rint(x);
    if (fetestexcept(FE_INEXACT)) {
        fesetround(FE_TOWARDZERO);
        result = rint(copysign(0.5 + fabs(x), x));
    }
    feupdateenv(&save_env);
    return result;
}

示例

#include <stdio.h>
#include <math.h>
#include <fenv.h>
#include <limits.h>

#pragma STDC FENV_ACCESS ON

int main(void)
{
    // round
    printf("round(+2.3) = %+.1f  ", round(2.3));
    printf("round(+2.5) = %+.1f  ", round(2.5));
    printf("round(+2.7) = %+.1f\n", round(2.7));
    printf("round(-2.3) = %+.1f  ", round(-2.3));
    printf("round(-2.5) = %+.1f  ", round(-2.5));
    printf("round(-2.7) = %+.1f\n", round(-2.7));

    printf("round(-0.0) = %+.1f\n", round(-0.0));
    printf("round(-Inf) = %+f\n",   round(-INFINITY));

    // lround
    printf("lround(+2.3) = %ld  ", lround(2.3));
    printf("lround(+2.5) = %ld  ", lround(2.5));
    printf("lround(+2.7) = %ld\n", lround(2.7));
    printf("lround(-2.3) = %ld  ", lround(-2.3));
    printf("lround(-2.5) = %ld  ", lround(-2.5));
    printf("lround(-2.7) = %ld\n", lround(-2.7));

    printf("lround(-0.0) = %ld\n", lround(-0.0));
    printf("lround(-Inf) = %ld\n", lround(-INFINITY)); // FE_INVALID 引发

    // 错误处理
    feclearexcept(FE_ALL_EXCEPT);
    printf("lround(LONG_MAX+1.5) = %ld\n", lround(LONG_MAX+1.5));
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID was raised");
}

可能的输出：

round(+2.3) = +2.0  round(+2.5) = +3.0  round(+2.7) = +3.0
round(-2.3) = -2.0  round(-2.5) = -3.0  round(-2.7) = -3.0
round(-0.0) = -0.0
round(-Inf) = -inf
lround(+2.3) = 2  lround(+2.5) = 3  lround(+2.7) = 3
lround(-2.3) = -2  lround(-2.5) = -3  lround(-2.7) = -3
lround(-0.0) = 0
lround(-Inf) = -9223372036854775808
lround(LONG_MAX+1.5) = -9223372036854775808
    FE_INVALID was raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.9.6 The round functions (p: 253)
  • 7.12.9.7 The lround and llround functions (p: 253)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.6.6 The round functions (p: 527)
  • F.10.6.7 The lround and llround functions (p: 528)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.9.6 The round functions (p: 233)
  • 7.12.9.7 The lround and llround functions (p: 234)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.6.6 The round functions (p: 464)
  • F.9.6.7 The lround and llround functions (p: 464)

参阅

floorfloorffloorl (C99)(C99) | 计算不大于给定值的最大整数 (函数)
ceilceilfceill (C99)(C99) | 计算不小于给定值的最小整数 (函数)
trunctruncftruncl (C99)(C99)(C99) | 取整到绝对值不大于给定值的最接近整数 (函数)


scalbn, scalbnf, scalbnl, scalbln, scalblnf, scalblnl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float scalbnf( float arg, int exp ); | (1) | (C99 起)
double scalbn( double arg, int exp ); | (2) | (C99 起)
long double scalbnl( long double arg, int exp ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define scalbn( arg, exp ) | (4) | (C99 起)
定义于头文件 <math.h> |  |
float scalblnf( float arg, long exp ); | (5) | (C99 起)
double scalbln( double arg, long exp ); | (6) | (C99 起)
long double scalblnl( long double arg, long exp ); | (7) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define scalbln( arg, exp ) | (8) | (C99 起)
1-3,5-7) 将浮点值 arg 乘以 FLT_RADIX 的 exp 次幂。
4,8) 泛型宏：若 arg 拥有 long double 类型，则调用 scalbnl 或 scalblnl 。否则，若 arg 拥有整数类型或 double 类型，则调用 scalbn 或 scalbln 。否则调用 scalbnf 或 scalblnf 。

参数

arg | - | 浮点值
exp | - | 整数值

返回值

若不出现错误，则返回 arg 乘 FLT_RADIX 的 exp 次幂（ arg×FLT_RADIXexp
 ）。

若出现上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 决不引发 FE_INEXACT ，除非出现值域错误（结果准确）
  • 忽略当前舍入模式，除非出现值域错误
  • 若 arg 为 ±0 ，则返回不修改的参数
  • 若 arg 为 ±∞ ，则返回不修改的参数
  • 若 exp 为 0 ，则返回不修改的 arg
  • 若 arg 为 NaN ，则返回 NaN

注意

二进制系统上（其中 FLT_RADIX 为 2 ）， scalbn 等价于 ldexp 。

尽管指定 scalbn 和 scalbln 高效进行运算，多数实现上它们的效率低于用算术运算符乘或除以二的幂。

提供 scalbln 函数，因为从最小正浮点值放大到最大正有限值的因子可能大于标准保证的 INT_MAX 32767 。特别是对于 80 位 long double ，因子是 32828 。

GNU 实现不设置 errno ，无关乎 math_errhandling 。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <errno.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("scalbn(7, -4) = %f\n", scalbn(7, -4));
    printf("scalbn(1, -1074) = %g (minimum positive subnormal double)\n",
            scalbn(1, -1074));
    printf("scalbn(nextafter(1,0), 1024) = %g (largest finite double)\n",
            scalbn(nextafter(1,0), 1024));
    // 特殊值
    printf("scalbn(-0, 10) = %f\n", scalbn(-0.0, 10));
    printf("scalbn(-Inf, -1) = %f\n", scalbn(-INFINITY, -1));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("scalbn(1, 1024) = %f\n", scalbn(1, 1024));
    if(errno == ERANGE) perror("    errno == ERANGE");
    if(fetestexcept(FE_OVERFLOW)) puts("    FE_OVERFLOW raised");
}

可能的输出：

scalbn(7, -4) = 0.437500
scalbn(1, -1074) = 4.94066e-324 (minimum positive subnormal double)
scalbn(nextafter(1,0), 1024) = 1.79769e+308 (largest finite double)
scalbn(-0, 10) = -0.000000
scalbn(-Inf, -1) = -inf
scalbn(1, 1024) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.6.13 The scalbn functions (p: 247)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.3.13 The scalbn functions (p: 523)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.6.13 The scalbn functions (p: 228)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.3.13 The scalbn functions (p: 460)

参阅

frexpfrexpffrexpl (C99)(C99) | 将数拆分成有效数字和 2 的幂次 (函数)
ldexpldexpfldexpl (C99)(C99) | 将数乘以 2 的幂 (函数)


signbit

< c‎ | numeric‎ | math
定义于头文件 <math.h> |
#define signbit(arg) /* implementation defined */ | (C99 起)

确定给定的浮点数 arg 是否为负。该宏返回整数值。

参数

arg - 浮点值

返回值

若arg为负，则返回非零整数值，否则返回​0​。

注意

此宏检测零、无穷大和 NaN 的符号。 signbit 是检验 NaN 符号的唯二可移植方式，另一方式是 copysign 。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    printf("signbit(+0.0) = %d\n", signbit(+0.0));
    printf("signbit(-0.0) = %d\n", signbit(-0.0));
}

可能的输出：

signbit(+0.0) = 0
signbit(-0.0) = 128

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.3.6 The signbit macro (p: 237)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.3.6 The signbit macro (p: 218)

参阅

fabsfabsffabsl (C99)(C99) | 计算浮点值的绝对值（ \(\small{|x|}\)|x| ） (函数)
copysigncopysignfcopysignl (C99)(C99)(C99) | 从一个给定值的绝对值和另一个给定值的符号产生值 (函数)


sin, sinf, sinl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float sinf( float arg ); | (1) | (C99 起)
double sin( double arg ); | (2) |
long double sinl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define sin( arg ) | (4) | (C99 起)
1-3) 计算 arg （以弧度度量）的正弦。
4) 泛型宏：若参数拥有 long double 类型，则调用 sinl 。否则，若参数拥有整数类型或 double 类型，则调用 sin 。否则调用 sinf 。若参数是复数，则该宏调用对应的复函数（ csinf 、 csin 、 csinl ）。

参数

arg - 以弧度表示角的浮点值

返回值

若不发生错误，则返回 arg 的正弦（ sin(arg) ），于范围 [-1 ; +1] 中。

若 arg 的绝对值很大，结果可能拥有少量或无有效数字。

 (C99 前)

若发生定义域错误，则返回实现定义的值（受支持的平台上为 NaN ）。

若发生下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数是 ±0 ，则返回不修改的参数
  • 若参数是 ±∞ ，则返回 NaN 并引发 FE_INVALID
  • 若参数是 NaN ，则返回 NaN

注意

参数为无穷大的情况不指定为 C 中的定义域错误，但它被指定为 POSIX 中的定义域错误。

POSIX 亦指定在溢出的情况下，返回不修改的 arg ，而且若不支持如此，则返回实现定义的不大于 DBL_MIN 、 FLT_MIN 及 LDBL_MIN 的值。

示例

#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON
int main(void)
{
    double pi = acos(-1);
    // 典型使用
    printf("sin(pi/6) = %f\n", sin(pi/6));
    printf("sin(pi/2) = %f\n", sin(pi/2));
    printf("sin(-3*pi/4) = %f\n", sin(-3*pi/4));
    // 特殊值
    printf("sin(+0) = %f\n", sin(0.0));
    printf("sin(-0) = %f\n", sin(-0.0));
    // 错误处理
    feclearexcept(FE_ALL_EXCEPT);
    printf("sin(INFINITY) = %f\n", sin(INFINITY));
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID raised");
}

可能的输出：

sin(pi/6) = 0.500000
sin(pi/2) = 1.000000
sin(-3*pi/4) = -0.707107
sin(+0) = 0.000000
sin(-0) = -0.000000
sin(INFINITY) = -nan
    FE_INVALID raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.4.6 The sin functions (p: 239-240)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.1.6 The sin functions (p: 519)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.4.6 The sin functions (p: 220)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.1.6 The sin functions (p: 456)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.2.6 The sin function

参阅

coscosfcosl (C99)(C99) | 计算余弦（ \({\small\cos{x} }\)cos(x) ） (函数)
tantanftanl (C99)(C99) | 计算正切（ \({\small\tan{x} }\)tan(x) ） (函数)
asinasinfasinl (C99)(C99) | 计算反正弦（ \({\small\arcsin{x} }\)arcsin(x) ） (函数)
csincsinfcsinl (C99)(C99)(C99) | 计算复数正弦 (函数)


sinh, sinhf, sinhl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float sinhf( float arg ); | (1) | (C99 起)
double sinh( double arg ); | (2) |
long double sinhl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define sinh( arg ) | (4) | (C99 起)
1-3) 计算 arg 的双曲正弦。
4) 泛型宏：若参数拥有 long double 类型，则调用 sinhl 。否则，若参数拥有整数类型或 double 类型，则调用 sinh 。否则调用 sinhf 。若参数为复数，则宏调用对应的复数函数（ csinhf 、 csinh 、 csinhl ）。

参数

arg - 表示双曲角的浮点值

返回值

若不出现错误，则返回 arg 的双曲正弦（ sinh(arg) 或
earg
-e-arg
2
）。

若出现上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 或 ±∞ ，则返回不修改的参数
  • 若参数为 NaN ，则返回 NaN

注意

POSIX 指定在下溢情况下，返回不修改的 arg ，而若不支持如此，则返回不大于 DBL_MIN 、 FLT_MIN 和 LDBL_MIN 的实现定义值。

示例

#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("sinh(1) = %f\nsinh(-1)=%f\n", sinh(1), sinh(-1));
    printf("log(sinh(1) + cosh(1))=%f\n", log(sinh(1)+cosh(1)));
    // 特殊值
    printf("sinh(+0) = %f\nsinh(-0)=%f\n", sinh(0.0), sinh(-0.0));
    // 错误处理
    errno=0; feclearexcept(FE_ALL_EXCEPT);
    printf("sinh(710.5) = %f\n", sinh(710.5));
    if(errno == ERANGE) perror("    errno == ERANGE");
    if(fetestexcept(FE_OVERFLOW)) puts("    FE_OVERFLOW raised");
}

可能的输出：

sinh(1) = 1.175201
sinh(-1)=-1.175201
log(sinh(1) + cosh(1))=1.000000
sinh(+0) = 0.000000
sinh(-0)=-0.000000
sinh(710.5) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.5.5 The sinh functions (p: 241-242)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.2.5 The sinh functions (p: 520)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.5.5 The sinh functions (p: 222)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.2.5 The sinh functions (p: 457)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.3.2 The sinh function

参阅

coshcoshfcoshl (C99)(C99) | 计算双曲余弦（ \({\small\cosh{x} }\)cosh(x) ） (函数)
tanhtanhftanhl (C99)(C99) | 计算双曲正切（ \({\small\tanh{x} }\)tanh(x) ） (函数)
asinhasinhfasinhl (C99)(C99)(C99) | 计算反双曲正弦（ \({\small\operatorname{arsinh}{x} }\)arsinh(x) ） (函数)
csinhcsinhfcsinhl (C99)(C99)(C99) | 计算复数双曲正弦 (函数)


sqrt, sqrtf, sqrtl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float sqrtf( float arg ); | (1) | (C99 起)
double sqrt( double arg ); | (2) |
long double sqrtl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define sqrt( arg ) | (4) | (C99 起)
1-3) 计算 arg 的平方根。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 sqrtl 。否则，若 arg 拥有整数类型或 double 类型，则调用 sqrt 。否则调用 sqrtf 。若 arg 为复数或虚数，则宏调用对应复数函数（ csqrtf 、 csqrt 、 csqrtl ）。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 的平方根（ \({\small \sqrt{arg} }\)√arg ）。

若出现定义域错误，则返回实现定义值（支持的平台上为 NaN ）。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 小于零则出现定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数小于 -0 ，则引发 FE_INVALID 并返回 NaN 。
  • 若参数为 +∞ 或 ±0 ，则返回不修改的参数。
  • 若参数为 NaN ，则返回 NaN 。

注解

IEEE 标准要求 sqrt 为准确。其他要求为准确的运算只有算术运算符和函数 fma 。舍入到返回类型后（用默认舍入模式）， sqrt 的结果与无限精度结果不可辨别。换言之，误差小于 0.5 ulp 。其他函数，含 pow ，不受这种制约。

示例

#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON

int main(void)
{
    // 正常使用
    printf("sqrt(100) = %f\n", sqrt(100));
    printf("sqrt(2) = %f\n", sqrt(2));
    printf("golden ratio = %f\n", (1+sqrt(5))/2);
    // 特殊值
    printf("sqrt(-0) = %f\n", sqrt(-0.0));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("sqrt(-1.0) = %f\n", sqrt(-1));
    if(errno == EDOM) perror("    errno == EDOM");
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID was raised");
}

可能的输出：

sqrt(100) = 10.000000
sqrt(2) = 1.414214
golden ratio = 1.618034
sqrt(-0) = -0.000000
sqrt(-1.0) = -nan
    errno = EDOM: Numerical argument out of domain
    FE_INVALID was raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.7.5 The sqrt functions (p: 249)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.4.5 The sqrt functions (p: 525)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.7.5 The sqrt functions (p: 229-230)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.4.5 The sqrt functions (p: 462)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.5.2 The sqrt function

参阅

powpowfpowl (C99)(C99) | 计算一个数的给定次幂（ \(\small{x^y}\)xy ） (函数)
cbrtcbrtfcbrtl (C99)(C99)(C99) | 计算立方根（ \(\small{\sqrt[3]{x} }\)3√x ） (函数)
hypothypotfhypotl (C99)(C99)(C99) | 计算两个给定数平方和的平方根 （ \(\scriptsize{\sqrt{x^2+y^2} }\)√x2 +y2 ） (函数)
csqrtcsqrtfcsqrtl (C99)(C99)(C99) | 计算复数平方根 (函数)


tan, tanf, tanl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float tanf( float arg ); | (1) | (C99 起)
double tan( double arg ); | (2) |
long double tanl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define tan( arg ) | (4) | (C99 起)
1-3) 计算 arg （以弧度度量）的正切。
4) 泛型宏：若参数拥有 long double 类型，则调用 tanl 。否则，若参数拥有整数类型或 double 类型，则调用 tan 。否则调用 tanf 。若参数为复数，则宏调用对应的复数函数（ ctanf 、 ctan 、 ctanl ）。

参数

arg - 以弧度表示角的浮点值

返回值

若不出现错误，则返回 arg 的正切（ tan(arg) ）。

若 arg 的绝对值很大，则结果可能有较少或无有效数字。

 (C99 前)

若出现定义域错误，则返回实现定义值（受支持平台为 NaN ）。

若发生下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算数（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回不修改的参数
  • 若参数为 ±∞ ，则返回 NaN 并引发 FE_INVALID
  • 若参数为 NaN ，则返回 NaN

注意

C 中参数为无限大的情况未被指定为定义域错误，但它被定义为 POSIX 中的定义域错误。

函数在 π(1/2 + n) 有数学上的极点；然而无常用浮点表示能准确表示 π/2 ，故而没有值使得极点错误出现。

示例

#include <stdio.h>
#include <math.h>
#include <errno.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON
int main(void)
{
    double pi = acos(-1);
    // 典型用法
    printf("tan  (pi/4) = %+f\n", tan(  pi/4)); //   45°
    printf("tan(3*pi/4) = %+f\n", tan(3*pi/4)); //  135°
    printf("tan(5*pi/4) = %+f\n", tan(5*pi/4)); // -135°
    printf("tan(7*pi/4) = %+f\n", tan(7*pi/4)); //  -45°
    // 特殊值
    printf("tan(+0) = %f\n", tan(0.0));
    printf("tan(-0) = %f\n", tan(-0.0));
    // 错误处理
    feclearexcept(FE_ALL_EXCEPT);
    printf("tan(INFINITY) = %f\n", tan(INFINITY));
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID raised");
}

可能的输出：

tan  (pi/4) = +1.000000
tan(3*pi/4) = -1.000000
tan(5*pi/4) = +1.000000
tan(7*pi/4) = -1.000000
tan(+0) = 0.000000
tan(-0) = -0.000000
tan(INFINITY) = -nan
    FE_INVALID raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.4.7 The tan functions (p: 240)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.1.7 The tan functions (p: 519)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.4.7 The tan functions (p: 220)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.1.7 The tan functions (p: 457)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.2.7 The tan function

参阅

sinsinfsinl (C99)(C99) | 计算正弦（ \({\small\sin{x} }\)sin(x) ） (函数)
coscosfcosl (C99)(C99) | 计算余弦（ \({\small\cos{x} }\)cos(x) ） (函数)
atanatanfatanl (C99)(C99) | 计算反正切（ \({\small\arctan{x} }\)arctan(x) ） (函数)
ctanctanfctanl (C99)(C99)(C99) | 计算复数正切 (函数)


tanh, tanhf, tanhl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float tanhf( float arg ); | (1) | (C99 起)
double tanh( double arg ); | (2) |
long double tanhl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define tanh( arg ) | (4) | (C99 起)
1-3) 计算 arg 的双曲正切。
4) 泛型宏：若参数拥有 long double 类型，则调用 tanhl 。否则，若参数拥有整数类型或 double 类型，则调用 tanh 。否则调用 tanhf 若参数为复数，则宏调用对应的复数函数（ ctanhf 、 ctanh 、 ctanhl ）。

参数

arg - 表示双曲角的浮点值

返回值

若不出现错误，则返回 arg 的双曲正切（ tanh(arg) 或
earg
-e-arg
earg
+e-arg
）。

若发生下溢所致的错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 ±0
  • 若参数为 ±∞ ，则返回 ±1
  • 若参数为 NaN ，则返回 NaN

注意

POSIX 指定在下溢的情况中，返回不修改的 arg ，而且若不支持这么做，则返回不大于 DBL_MIN 、 FLT_MIN 和 LDBL_MIN 的实现定义值。

示例

#include <stdio.h>
#include <math.h>

int main(void)
{
    printf("tanh(1) = %f\ntanh(-1) = %f\n", tanh(1), tanh(-1));
    printf("tanh(0.1)*sinh(0.2)-cosh(0.2) = %f\n", tanh(0.1) * sinh(0.2) - cosh(0.2));
    // 特殊值
    printf("tanh(+0) = %f\ntanh(-0) = %f\n", tanh(0.0), tanh(-0.0));
}

输出：

tanh(1) = 0.761594
tanh(-1) = -0.761594
tanh(0.1)*sinh(0.2)-cosh(0.2) = -1.000000
tanh(+0) = 0.000000
tanh(-0) = -0.000000

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.5.6 The tanh functions (p: 242)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.2.6 The tanh functions (p: 520)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.5.6 The tanh functions (p: 222-223)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.2.6 The tanh functions (p: 457)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.5.3.3 The tanh function

参阅

sinhsinhfsinhl (C99)(C99) | 计算双曲正弦（ \({\small\sinh{x} }\)sinh(x) ） (函数)
coshcoshfcoshl (C99)(C99) | 计算双曲余弦（ \({\small\cosh{x} }\)cosh(x) ） (函数)
atanhatanhfatanhl (C99)(C99)(C99) | 计算反双曲正切（ \({\small\operatorname{artanh}{x} }\)artanh(x) ） (函数)
ctanhctanhfctanhl (C99)(C99)(C99) | 计算复数双曲正切 (函数)


tgamma, tgammaf, tgammal

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float tgammaf( float arg ); | (1) | (C99 起)
double tgamma( double arg ); | (2) | (C99 起)
long double tgammal( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define tgamma( arg ) | (4) | (C99 起)
1-3) 计算 arg 的伽马函数。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 tgammal 。否则，若 arg 拥有整数类型或 double 类型，则调用 tgamma 。否则调用 tgammaf 。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 的 Γ 函数值，即 \(\Gamma(\mathtt{arg}) = \displaystyle\int_0^\infty\!\! t^{\mathtt{arg}-1} e^{-t}\, dt\)∫∞
0 t arg-1
 e-t dt 。

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

若出现极点错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

若出现上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误

若 arg 为零或为小于零的整数，则可能出现极点或定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 ±∞ 并引发 FE_DIVBYZERO
  • 若参数为负整数，则返回 NaN 并引发 FE_INVALID
  • 若参数为 -∞ ，则返回 NaN 并引发 FE_INVALID
  • 若参数为 +∞ ，则返回 +∞
  • 若参数为 NaN ，则返回 NaN

注解

若 arg 为自然数，则 tgamma(arg) 为 arg-1 的阶乘。许多实现若参数是足够小的整数，则计算准确的整数域阶乘。

对于 IEEE 兼容的 double 类型，若 0 < x < 1/DBL_MAX 或 x > 171.7 则发生上溢。

POSIX 要求若参数为零则出现极点错误，但在参数为负整数时出现定义域错误。它亦指定在将来，对于负整数，定义域错误可能被替换成浮点错误（这些情况下返回值将从 NaN 更改为 ±∞ ）。

多数实现中有名为 gamma 的非标准函数，但其定义不一致。例如， gamma 的 glibc 和 4.2BSD 版本执行 lgamma ，但 gamma 的 4.4BSD 版本执行 tgamma 。

示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <errno.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    printf("tgamma(10) = %f, 9!=%f\n", tgamma(10), 2*3*4*5*6*7*8*9.0);
    printf("tgamma(0.5) = %f, sqrt(pi) = %f\n", sqrt(acos(-1)), tgamma(0.5));
    // 特殊值
    printf("tgamma(+Inf) = %f\n", tgamma(INFINITY));
    // 错误处理
    errno = 0; feclearexcept(FE_ALL_EXCEPT);
    printf("tgamma(-1) = %f\n", tgamma(-1));
    if(errno == ERANGE) perror("    errno == ERANGE");
    else if(errno == EDOM)   perror("    errno == EDOM");
    if(fetestexcept(FE_DIVBYZERO)) puts("    FE_DIVBYZERO raised");
    else if(fetestexcept(FE_INVALID)) puts("    FE_INVALID raised");
}

可能的输出：

tgamma(10) = 362880.000000, 9!=362880.000000
tgamma(0.5) = 1.772454, sqrt(pi) = 1.772454
tgamma(+Inf) = inf
tgamma(-1) = nan
    errno == EDOM: Numerical argument out of domain
    FE_INVALID raised

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.8.4 The tgamma functions (p: 250)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.5.4 The tgamma functions (p: 525)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.8.4 The tgamma functions (p: 231)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.5.4 The tgamma functions (p: 462)

参阅

lgammalgammaflgammal
(C99)(C99)(C99)
 计算伽马函数的自然对数（底为 e ）
(函数)

外部链接

Weisstein, Eric W. “伽马函数”来自 MathWorld--A Wolfram Web Resource 。


trunc, truncf, truncl

< c‎ | numeric‎ | math
定义于头文件 <math.h> |  |
float truncf( float arg ); | (1) | (C99 起)
double trunc( double arg ); | (2) | (C99 起)
long double truncl( long double arg ); | (3) | (C99 起)
定义于头文件 <tgmath.h> |  |
#define trunc( arg ) | (4) | (C99 起)
1-3) 计算绝对值不大于 arg 的最接近整数。
4) 泛型宏：若 arg 拥有 long double 类型，则调用 truncl 。否则，若 arg 拥有整数类型或 double 类型，则调用 trunc 。否则，调用 truncf 。

参数

arg - 浮点值

返回值

若不发生错误，则返回绝对值不大于 arg 的最接近整数值（换言之，将 arg 向零舍入）。

返回值
参数

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 当前舍入模式无效。
  • 若 arg 为 ±∞ ，则返回不修改的参数。
  • 若 arg 为 ±0 ，则返回不修改的参数。
  • 若 arg 为 NaN ，则返回 NaN

注意

截断非整数有限值时可以（但不要求）引发 FE_INEXACT 。

所有标准浮点格式中，最大可表示浮点值均为准确的整数，故此函数自身决不上溢；然而存储结果于整数对象时，结果可以溢出任何整数类型（包含 intmax_t ）。

从浮点到整数类型的隐式转换始终向零舍入，但它被限制于能表示成目标类型的值。

示例

#include <math.h>
#include <stdio.h>
int main(void)
{
    printf("trunc(+2.7) = %+.1f\n", trunc(2.7));
    printf("trunc(-2.7) = %+.1f\n", trunc(-2.7));
    printf("trunc(-0.0) = %+.1f\n", trunc(-0.0));
    printf("trunc(-Inf) = %+f\n",   trunc(-INFINITY));
}

可能的输出：

trunc(+2.7) = +2.0
trunc(-2.7) = -2.0
trunc(-0.0) = -0.0
trunc(-Inf) = -inf

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.12.9.8 The trunc functions (p: 253-254)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.6.8 The trunc functions (p: 528)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.12.9.8 The trunc functions (p: 234)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.6.8 The trunc functions (p: 464)

参阅

floorfloorffloorl (C99)(C99) | 计算不大于给定值的最大整数 (函数)
ceilceilfceill (C99)(C99) | 计算不小于给定值的最小整数 (函数)
roundroundfroundllroundlroundflroundllroundllroundfllroundl (C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99)(C99) | 取整到最接近的整数，在相邻整数正中间时取远离零的数 (函数)


伪随机数生成

< c‎ | numeric
定义于头文件 <stdlib.h>
rand | 产生一个伪随机数 (函数)
srand | 播种伪随机数生成器 (函数)
RAND_MAX | rand () 生成的最大可能值 (宏常量)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.2 Pseudo-random sequence generation functions (p: 346-347)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.2 Pseudo-random sequence generation functions (p: 312-313)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.2 Pseudo-random sequence generation functions

参阅


RAND_MAX

< c‎ | numeric‎ | random
定义于头文件 <stdlib.h>
#define RAND_MAX /*implementation defined*/

展开成等于函数 rand() 最大返回值的整数常量表达式。此值为实现定义。标准保证此值至少为 32767 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22/3 General utilities <stdlib.h> (p: 340)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20/3 General utilities <stdlib.h> (p: 306)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10 GENERAL UTILITIES <stdlib.h>

参阅

rand | 产生一个伪随机数 (函数)
srand | 播种伪随机数生成器 (函数)


rand

< c‎ | numeric‎ | random
定义于头文件 <stdlib.h>
int rand();

返回 ​0​ 与 RAND_MAX 间的随机整数值（包含 0 与 RAND_MAX ）。

srand() 播种 rand() 所用的伪随机数生成器。若在任何对 srand() 的调用前使用 rand() ，则 rand() 表现如同它以 srand(1) 播种。每次以 srand() 播种 rand() 时，它必须产生相同的值数列。

不保证 rand() 为线程安全。

参数

（无）

返回值

​0​ 与 RAND_MAX 间包含边界的随机整数值。

注意

无对产生的随机数质量的保证。过去，某些 rand() 的实现在随机性、分布和产生的数列周期中有严重缺陷（在一个广为人知的例子中，最低位在调用间简单地于 1 和 0 间改变）。不推荐将 rand() 用于严肃的随机数生成需求，如加密。

POSIX 要求 rand 所用的伪随机数生成器的周期至少为 232
 。

POSIX 提供 rand 的线程安全版本，名为 rand_r ，它由于 drand48 函数族而过时。

示例

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
    srand(time(NULL)); // 以当前时间为随机生成器的种子
    int random_variable = rand();
    printf("Random value on [0,%d]: %d\n", RAND_MAX, random_variable);

    // 扔 6 面色子 20 次
    for (int n = 0; n != 20; ++n) {
        int x = 7;
        while(x > 6)
            x = 1 + rand() / ((RAND_MAX + 1u) / 6); // 注意： 1 + rand() % 6 有偏差！
        printf("%d ", x);
    }
}

可能的输出：

Random value on [0,2147483647]: 448749574
3 1 3 1 4 2 2 1 3 6 4 4 3 1 6 2 3 2 6 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.2.1 The rand function (p: 346)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.2.1 The rand function (p: 312)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.2.1 The rand function

参阅

srand | 播种伪随机数生成器 (函数)
RAND_MAX | rand() 生成的最大可能值 (宏常量)


srand

< c‎ | numeric‎ | random
定义于头文件 <stdlib.h>
void srand( unsigned seed );

以值 seed 播种 rand() 所用的随机数生成器。

若在任何到 srand() 的调用前使用 rand() ，则 rand() 表现为如同它被以 srand(1) 播种。

每次以同一 seed 播种 rand() 时，它必须产生相同的值数列。

srand() 不保证为线程安全。

参数

seed 种子值 -

返回值

（无）

注意

通常来说，应该只播种一次随机数生成器，在程序开始出，任何到 rand() 的调用前。不应重复播种，或每次冀愿生成新一批随机数时重播种。

标准实践是使用以 time (0) 为种子调用的结果。然而 time() 返回 time_t 值，而不保证 time_t 是整数类型。尽管实践中，主流实现都定义 time_t 为整数类型，且此亦为 POSIX 所要求。

示例

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
    srand(time(0)); // 以当前时间为随机数生成器的种子
    int random_variable = rand();
    printf("Random value on [0,%d]: %d\n", RAND_MAX, random_variable);
}

可能的输出：

Random value on [0 2147483647]: 1373858591

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.2.2 The srand function (p: 346-347)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.2.2 The srand function (p: 312-313)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.2.2 The srand function

参阅

rand | 产生一个伪随机数 (函数)
RAND_MAX | rand () 生成的最大可能值 (宏常量)


泛型数学

< c‎ | numeric

头文件 <tgmath.h> 包含头文件 <math.h> 及 <complex.h> ，并定义了几种泛型宏。这些宏会根据参数类型决定要调用的实际函数。

对于每个宏，在<math.h>无后缀版函数中，所对应的实数类型为 double 的参数，即是所谓的泛型参数。（例如，pow的两个参数都是泛型参数，但scalbn只有第一个参数是泛型参数）

如下所述，使用 <tgmath.h> 宏时，传递给泛型参数的参数类型，会决定宏所选择的参数。若参数的类型与所选函数的参数类型不兼容，则行为未定义。（例如，若将复数参数传入实数限定的 tgmath 宏： float complex fc; ceil (fc) 或 double complex dc; double d; fmax (dc, d) 就是未定义行为的例子）

注意：泛型宏在 C99 中曾以实现定义行为实现，但 C11 关键词 _Generic 使得以可移植方式实现这些宏成为可能。

复数/实数泛型宏

对于所有拥有实数及复数对应的函数，存在泛型宏，调用下列函数之一：

  • 实数函数：
  • float 变体 XXXf
  • double 变体 XXX
  • long double 变体 XXXl
  • 复数函数：
  • float 变体 cXXXf
  • double 变体 cXXX
  • long double 变体 cXXXl

上述规则的一个例外是 fabs 宏（见下表）。

调用的函数按以下方式决定：

  • 若泛型参数的任一参数为虚数，则行为会在每个函数参考页面上各自指定。（具体而言， sin 、 cos 、 tan 、 sinh 、 cosh 、 tanh 、 asin 、 atan 、 asinh 及 atanh 调用实数函数， sin 、 cos 、 tan 、 sinh 、 tanh 、 asin 、 atan 、 asinh 及 atanh 的返回类型是虚数，而 cosh 与 cosh 的返回类型是实数）
  • 若泛型参数的任一参数为复数，则复数函数会得到调用，否则会调用实数函数。
  • 若泛型参数的任一参数为 long double ，则调用 long double 变体。否则，若任一参数是 double 或整数，则调用 double 变体。否则会调用 float 变体。

泛型宏如下所示：

泛型宏 | 实数函数变体 |  |  | 复数函数变体
 | float | double | long double | float | double | long double
fabs | fabsf | fabs | fabsl | cabsf | cabs | cabsl
exp | expf | exp | expl | cexpf | cexp | cexpl
log | logf | log | logl | clogf | clog | clogl
pow | powf | pow | powl | cpowf | cpow | cpowl
sqrt | sqrtf | sqrt | sqrtl | csqrtf | csqrt | csqrtl
sin | sinf | sin | sinl | csinf | csin | csinl
cos | cosf | cos | cosl | ccosf | ccos | ccosl
tan | tanf | tan | tanl | ctanf | ctan | ctanl
asin | asinf | asin | asinl | casinf | casin | casinl
acos | acosf | acos | acosl | cacosf | cacos | cacosl
atan | atanf | atan | atanl | catanf | catan | catanl
sinh | sinhf | sinh | sinhl | csinhf | csinh | csinhl
cosh | coshf | cosh | coshl | ccoshf | ccosh | ccoshl
tanh | tanhf | tanh | tanhl | ctanhf | ctanh | ctanhl
asinh | asinhf | asinh | asinhl | casinhf | casinh | casinhl
acosh | acoshf | acosh | acoshl | cacoshf | cacosh | cacoshl
atanh | atanhf | atanh | atanhl | catanhf | catanh | catanhl

实数限定函数

对于所有无复数对应的函数，除 modf 外都存在泛型宏 XXX ，它会调用实数函数变体的中的一种：

  • float 变体 XXXf
  • double 变体 XXX
  • long double 变体 XXXl

以下列方式确定调用的函数：

  • 若泛型参数的任一参数为 long double ，则调用 long double 变体。否则，若泛型参数的任一参数是 double ，则调用 double 变体。否则调用 float 变体。
泛型宏 | 实数函数变体
 | float | double | long double
atan2 | atan2f | atan2 | atan2l
cbrt | cbrtf | cbrt | cbrtl
ceil | ceilf | ceil | ceill
copysign | copysignf | copysign | copysignl
erf | erff | erf | erfl
erfc | erfcf | erfc | erfcl
exp2 | exp2f | exp2 | exp2l
expm1 | expm1f | expm1 | expm1l
fdim | fdimf | fdim | fdiml
floor | floorf | floor | floorl
fma | fmaf | fma | fmal
fmax | fmaxf | fmax | fmaxl
fmin | fminf | fmin | fminl
fmod | fmodf | fmod | fmodl
frexp | frexpf | frexp | frexpl
hypot | hypotf | hypot | hypotl
ilogb | ilogbf | ilogb | ilogbl
ldexp | ldexpf | ldexp | ldexpl
lgamma | lgammaf | lgamma | lgammal
llrint | llrintf | llrint | llrintl
llround | llroundf | llround | llroundl
log10 | log10f | log10 | log10l
log1p | log1pf | log1p | log1pl
log2 | log2f | log2 | log2l
logb | logbf | logb | logbl
lrint | lrintf | lrint | lrintl
lround | lroundf | lround | lroundl
nearbyint | nearbyintf | nearbyint | nearbyintl
nextafter | nextafterf | nextafter | nextafterl
nexttoward | nexttowardf | nexttoward | nexttowardl
remainder | remainderf | remainder | remainderl
remquo | remquof | remquo | remquol
rint | rintf | rint | rintl
round | roundf | round | roundl
scalbln | scalblnf | scalbln | scalblnl
scalbn | scalbnf | scalbn | scalbnl
tgamma | tgammaf | tgamma | tgammal
trunc | truncf | trunc | truncl

复数限定函数

对于所有没有实数对应的复数函数，存在泛型宏 cXXX ，它会调用复数函数的变体：

  • float complex 变体 cXXXf
  • double complex 变体 cXXX
  • long double complex 变体 cXXXl

调用的函数按以下方式决定：

  • 若泛型参数的任一参数为实数、复数或虚数，则调用适当的复数函数。
泛型宏 | 复数函数变体
 | float | double | long double
carg | cargf | carg | cargl
conj | conjf | conj | conjl
creal | crealf | creal | creall
cimag | cimagf | cimag | cimagl
cproj | cprojf | cproj | cprojl

示例

#include <stdio.h>
#include <tgmath.h>

int main(void)
{
    int i = 2;
    printf("sqrt(2) = %f\n", sqrt(i)); // 参数类型为 int，调用 sqrt

    float f = 0.5;
    printf("sin(0.5f) = %f\n", sin(f));   // 参数类型为 float，调用 sinf

    float complex dc = 1 + 0.5*I;
    float complex z = sqrt(dc);      // 参数类型为 float complex，调用 csqrtf
    printf("sqrt(1 + 0.5i) = %f+%fi\n",
           creal(z),  // 参数类型为 float complex ，调用 crealf
           cimag(z)); // 参数类型为 float complex ，调用 cimagf
}

输出：

sqrt(2) = 1.414214
sin(0.5f) = 0.479426
sqrt(1 + 0.5i) = 1.029086+0.242934i

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)


预处理器

< c

预处理器于翻译阶段 4 执行，在编译之前。预处理的结果是将被传递给实际编译器的单个文件.

指令

预处理指令控制预处理器的行为。每个指令占据一行，且拥有下列格式：

  • # 字符
  • 预处理指令（define、undef、include、if、ifdef、ifndef、else、elif、elifdef、elifndef (C23 起)、endif、line、error、pragma 之一）[1]
  • 实参（取决于指令）
  • 换行符

允许空指令（跟随换行符的 # ），而它无效果。

能力

预处理器拥有源文件翻译能力：

  • 有条件编译源文件的某些部分（由 #if、#ifdef、#ifndef、#else、#elif、elifdef、elifndef (C23 起) 和 #endif 指令控制）。
  • 替换文本宏，可以连接或加引标识符（以指令 #define 和 #undef ，运算符 # 和 ## 控制）。
  • 包含其他文件（以指令 #include 控制）。
  • 导致错误（以指令 #error 控制）。

能控制预处理器的下列方面：

  • 实现定义行为（以指令 #pragma 及运算符 _Pragma (C99 起)控制）。
  • 文件名与行信息，可用于预处理器（以指令 #line 控制）。

脚注

  1. ↑ 这些指令是标准定义的。标准不定义其他指令的行为：它们可以被忽略、拥有一些有用的含义或导致编译时错误。即使忽略，也会在预处理器完成工作时将它们从源码中移除。一种常用的非标准扩展是 #warning 指令，它在编译期间放出一条用户定义的消息。

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.10 Preprocessing directives (p: 117-129)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.10 Preprocessing directives (p: 160-178)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.10 Preprocessing directives (p: 145-162)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.8 PREPROCESSING DIRECTIVES

参阅


条件包含

< c‎ | preprocessor

预处理器支持有条件地编译源文件的某些部分。这一行为由 #if、#else、#elif、#ifdef、#ifndef、#elifdef、#elifndef (C23 起) 与 #endif 指令所控制。

语法

#if 表达式 |
#ifdef 标识符 |
#ifndef 标识符 |
#elif 表达式 |
#elifdef 标识符 | (C23 起)
#elifndef 标识符 | (C23 起)
#else |
#endif |

解释

条件预处理块由 #if、#ifdef 或 #ifndef 指令开始，然后可选地包含任意多个 #elif、#elifdef 或 #elifndef (C23 起) 指令，接下来是最多一个可选的 #else 指令，并以 #endif 指令结束。嵌套的条件预处理块会被单独处理。

各个 #if、#ifdef、#ifndef、#elif、#elifdef、#elifndef (C23 起) 和 #else 指令所控制的代码块在第一个不属于内部嵌套的条件预处理块的 #elif、#elifdef、#elifndef (C23 起)、#else 或 #endif 指令处结束。

#if、#ifdef 和 #ifndef 指令测试其所指定的条件（见下文），如果条件求值为真，则编译其控制的代码块。此时后续的 #else、#elifdef、#elifndef (C23 起) 和 #elif 指令将被忽略。否则，如果所指定的条件求值为假，则跳过其所控制的代码块，然后处理后续的 #else、#elifdef、#elifndef (C23 起) 或 #elif 指令（如果存在）。若后续指令为 #else，则 #else 指令所控制的代码块将会无条件地进行编译。否则，#elif、#elifdef 或 #elifndef (C23 起) 指令按照与 #if 指令相同的方式执行：即测试条件是否满足，并根据其结果决定编译或跳过其所控制的代码块，并在后一种情况下继续处理后续的 #elif、#elifdef、#elifndef (C23 起) 和 #else 指令。条件预处理块以 #endif 指令结束。

条件的求值

#if, #elif

表达式 是常量表达式，仅使用常量和用 #define 指令定义的标识符。任何非常量，未以 #define 指令定义的标识符，求值为0。

表达式可以含有形式为 defined 标识符 或 defined (标识符) 的一元运算符，若用 #define 指令定义了该 标识符 ，则返回 1 ，否则返回 0 。若 表达式 求值为非零值，则包含该控制代码块并跳过其他。若所用的任何标识符不是常量，则用 ​0​ 替换它。

预处理器语境中， __has_c_attribute 表达式检测给定属性记号是否受支持及其受支持版本。见属性测试。

 (C23 起)

注： DR 412 前，“#if cond1 ... #elif cond2”和“#if cond1 ... #else”后面跟着“#if cond3”是不同的，因为当 cond1 为真时第二个 #if 将被跳过，且 cond3 并不需要是良构的，而 #elif 中的 cond2 则必须是合法的表达式。 DR 412 开始，引领跳过的代码块的 #elif 也被跳过。

组合指令

检查标识符是否被定义为宏名。

“#ifdef 标识符”与“#if defined 标识符”实质上等价。

“#ifndef 标识符”与“#if !defined 标识符”实质上等价。

“#elifdef 标识符”与“#elif defined 标识符”实质上等价。

“#elifndef 标识符”与“#elif !defined 标识符”实质上等价。

 (C23 起)

示例

#define ABCD 2
#include <stdio.h>

int main(void)
{

#ifdef ABCD
    printf("1: yes\n");
#else
    printf("1: no\n");
#endif

#ifndef ABCD
    printf("2: no1\n");
#elif ABCD == 2
    printf("2: yes\n");
#else
    printf("2: no2\n");
#endif

#if !defined(DCBA) && (ABCD < 2*4-3)
    printf("3: yes\n");
#endif
}

输出：

1: yes
2: yes
3: yes

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C 标准。

DR | 应用于 | 出版时的行为 | 正确行为
DR 412 | C++14 | 要求失败的 #elif 中的表达式合法 | 跳过失败的 #elif

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.10.1 Conditional inclusion (p: 118-119)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.10.1 Conditional inclusion (p: 162-164)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.10.1 Conditional inclusion (p: 147-149)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.8.1 Conditional inclusion

参阅


错误指令

< c‎ | preprocessor

显示给定的错误消息，并令程序为病式。

语法

#error 错误消息

解释

实现在遇到 #error 指令后，显示诊断消息 错误消息 ，并令程序为病式（停止编译）。

错误消息 可由多个词组成，不必在引号中。

示例

#if __STDC__ != 1
#error "Not a standard compliant compiler"
#endif

#include <stdio.h>

int main (void)
{
    printf("It is a Standard compiler conforming to ISO C Standard !!");
}

可能的输出：

It is a Standard compiler conforming to ISO C Standard !!

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.10.5 Error directive (p: 174)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.10.5 Error directive (p: 159)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.8.5 Error directive

参阅


实现定义行为控制

< c‎ | preprocessor

由 #pragma 指令控制实现定义行为。

语法

#pragma 语用形参 | (1) |
_Pragma ( 字符串字面量 ) | (2) | (C99 起)
1) 以实现定义方式行动（除非 语用形参 是后述的标准 pragma 之一）。
2) 移除 字符串字面量 的编码前缀（若存在）、外层引号，及开头/尾随空白符，将每个 \" 以 " ，每个 \\ 以 \ 替换，然后记号化结果（如翻译阶段 3 中），再如同在 (1) 中输出到 #pragma 一般使用结果。

解释

pragma 指令控制编译器的实现指定行为，如禁用编译器警告或更改对齐要求。忽略任何不被识别的 pragma 。

标准 pragma

语言标准定义下列三个 pragma ：

#pragma STDC FENV_ACCESS 实参 | (1) | (C99 起)
#pragma STDC FP_CONTRACT 实参 | (2) | (C99 起)
#pragma STDC CX_LIMITED_RANGE 实参 | (3) | (C99 起)

其中 实参 是 ON 、 OFF 和 DEFAULT 之一。

1) 若设为 ON ，则告知编译器程序将访问或修改浮点环境，这意味着禁用可能推翻标志测试和模式更改（例如，全局共用子表达式删除、代码移动，及常量折叠）的优化。默认值为实现定义，通常是 OFF 。
2) 允许缩略浮点表达式，即忽略舍入错误和浮点异常的优化，被观察成表达式以如同书写方式准确求值。例如，允许 (x*y) + z 的实现使用单条融合乘加CPU指令。默认值为实现定义，通常是 ON 。
3) 告知编译器复数的乘法、除法，及绝对值可以用简化的数学公式 (x+iy)×(u+iv) = (xu-yv)+i(yu+xv) 、 (x+iy)/(u+iv) = [(xu+yv)+i(yu-xv)]/(u2
+v2
) ，及 |x+iy| = √x2
+y2
 ，不考虑中间溢出的可能性。换言之，程序员保证传递给这些函数的值范围是受限的。默认值为 OFF 。

注意：不支持这些 pragma 的编译器可能提供等价的编译时选项，例如 gcc 的 -fcx-limited-range 和 -ffp-contract 。

非标准 pragma

#pragma once

#pragma once 是受到绝大多数现代编译器支持的非标准语用。当某个头文件中包含它时，指示编译器只对其分析一次，即使它在同一源文件中（直接或间接）被包含了多次也是如此。

阻止同一头文件的多次包含的标准方式是使用包含防护：

#ifndef LIBRARY_FILENAME_H
#define LIBRARY_FILENAME_H
// 头文件的内容
#endif /* LIBRARY_FILENAME_H */

从而在任何翻译单元中，该头文件除首次以外被包含时都被排除出编译。所有现代编译器都记录头文件使用了包含防护的事实，只要该防护仍有定义，再遇到该头文件时就不再分析它。（例子见 gcc ）

使用 #pragma once 时，同一个头文件可以变为

#pragma once
// 头文件的内容

不同于头文件防护，这条语用使得错误地在多个文件中使用相同的宏名变得不可能。另一方面，因为带 #pragma once 的文件是基于其文件系统层次的身份所排除的，所以若头文件在项目中有多个位置，则这不能防止包含它两次。

#pragma pack

此 pragma 族控制后继定义的结构体和联合体的最大对齐。

#pragma pack(实参) | (1)
#pragma pack() | (2)
#pragma pack(push) | (3)
#pragma pack(push, 实参) | (4)
#pragma pack(pop) | (5)

其中 arg 实参是小的 2 的幂，指定以字节计的新对齐。

1) 设置当前对齐为值 实参 。
2) 设置当前对齐为默认值（由命令行选项指定）。
3) 推入当前对齐的值到内部栈。
4) 推入当前对齐的值到内部栈然后设置当前对齐为值 实参 。
5) 从内部栈弹出顶条目然后设置（恢复）当前对齐为该值。

#pragma pack 可以指定结构体的对齐，然而它不能使结构体过对齐。

参阅 GCC 与 MSVC 的特定细节。

本节未完成
原因：解释此语用在数据成员的效果还有使用它们的优势与劣势。参考源：
  • Stack Overflow
本节未完成
原因：暂无示例

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.10.9 Pragma operator (p: 129)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.10.9 Pragma operator (p: 178)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.10.6 Pragma directive (p: 159)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.8.6 Pragma directive

参阅

外部链接

  • Visual Studio 2019 的 C++ pragma
  • GCC 接受的 Pragma
  • IBM AIX XL C 16.1 的单独 pragma 描述及标准 pragma
  • Sun Studio 11 C++ 用户手册的 Appendix B. Pragmas
  • Intel C++ compiler pragmas
  • HP aCC compiler pragmas


源文件包含

< c‎ | preprocessor

包含另一源文件，到当前源文件中立即在指令下一行的位置。

语法

#include <文件名> | (1)
#include "文件名" | (2)

解释

将 文件名 所标识的源文件包含到当前源文件中紧随指令后的一行。

1) 以实现定义行为搜索文件。此语法的意图是搜索实现控制下的文件。典型实现仅搜索标准包含目录。标准 C++ 库和标准 C 库被隐式包含于这些标准包含目录。用户通常能通过编译器选项控制标准包含目录。

2) 以实现定义行为搜索文件。此语法的意图是搜索不在实现控制下的文件。典型实现首先于当前文件所在的目录搜索，然后仅若找不到该文件，才在 (1) 中的标准包含目录搜索。

在找不到文件的情况下，程序为病式。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.10.2 Source file inclusion (p: 164-166)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.10.2 Source file inclusion (p: 149-151)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.8.2 Source file inclusion

参阅

c/header C 标准库头文件列表


文件名和行信息

< c‎ | preprocessor

在预处理器中更改当前行号和文件名。

语法

#line 行号 | (1)
#line 行号 "文件名" | (2)

解释

1) 更改当前预处理器行号为 行号 。从此点开始，宏 __LINE__ 的出现会展开成 行号 加上自此遇到的实际代码行数。
2) 亦将当前预处理器文件名更改为 文件名 。此点后宏 __FILE__ 的每次出现将生成 文件名 。

任何预处理器记号（宏常量及表达式）都允许出现为 #line 的参数，只要它们展开成合法的十进制整数，可以后随一个合法的字符串。

行号 必须是至少有一个十进制位的序列（否则程序为病式），并且始终按十进制转译（即使它以 0 开始）。

若 行号 为 0 或大于 32767 (C99 前)2147483647 (C99 起) ，则行为未定义。

注意

一些自动代码生成工具从以其他语言书写的文件产生 C 源文件，它们会使用此指令。该情况下，它们可能插入引用原始（人类可读）源文件的行号和文件名的 #line 指令到生成的 C 文件中。

后随指令 #line __LINE__ 的行号是实现定义的（该情况下 __LINE__ 能展开成二个可选值：迄今为止所见的换行符数，或迄今为止所见的换行符数加上结束 #line 指令的换行符）

示例

#include <assert.h>
#define FNAME "test.c"
int main(void)
{
#line 777 FNAME
        assert(2+2 == 5);
}

可能的输出：

test: test.c:777: int main(): Assertion `2+2 == 5' failed.

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 6.10.4 Line control (p: 173)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.10.4 Line control (p: 158)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.8.4 Line control

参阅


替换文本宏

< c‎ | preprocessor

预处理器支持文本宏替换及类函数文本宏替换。

语法

#define 标识符 替换列表(可选) | (1) |
#define 标识符( 形参 ) 替换列表 | (2) |
#define 标识符( 形参, ... ) 替换列表 | (3) | (C99 起)
#define 标识符( ... ) 替换列表 | (4) | (C99 起)
#undef 标识符 | (5) |

解释

#define 指令

#define 指令定义 标识符 为宏，即它们指示编译器将所有 标识符 的后继出现替换为 替换列表 ，可以可选地附加地处理。若已定义该标识符为任何类型的宏，则程序为病式，除非定义相同。

仿对象宏

仿对象宏将所定义的 标识符 的每次出现替换为 替换列表 。 #define 指令的版本 (1) 准确地如此表现。

仿函数宏

仿函数宏将所定义的 标识符 的每次出现替换为 替换列表 ，额外地接受数个参数，它们会替换 替换列表 中任何 形参 的对应出现。

仿函数宏的调用语法与函数调用语法相似：每个宏名实例后跟一个作为下个预处理记号的 ( ，引入被 替换列表 所替换的记号序列，序列由匹配的 ) 记号终止，跳过中间已匹配的左右括号对。

实参数量必须与宏定义中（ 形参 ）的实参数量相同，否则程序为病式。若标识符不在函数记号中，即它自身不后随括号，则决不替换它。

#define 指令的版本 (2) 定义简单的仿函数宏。

#define 指令的版本 (3) 定义有可变数量实参的仿函数宏。能用 __VA_ARGS__ 标识符访问额外实参，然后该标识符被实参替换。

#define 指令的版本 (4) 定义有可变数量实参的仿函数宏，但没有常规参数。只能用 __VA_ARGS__ 标识符访问实参，然后该标识符被实参替换。

注意：若仿函数宏的实参包含逗号，且未为匹配的左右括号对所保护（例如 macro(array[x = y, x + 1]) 或 atomic_store (p, (struct S){ a, b }); ），则将逗号转译为宏实参分隔符，这导致编译失败，原因为实参数量不合。

# 与 ## 运算符

在仿函数宏中， 替换列表 中标识符前的 # 运算符对标识符做形参替换，并将结果环绕在引号中，等效地创建一个字符串字面量。而且，预处理器会添加反斜杠，以转义环绕内嵌字符串字面量的引号，若存在，并按需在字符串中双写反斜杠。它移除所有前导和尾随空白符，且将任何文本中部的空白符序列（但非内嵌字符串字面量中的）缩减成单个空格。此运算被称作“字符串化”。若字符串化的结果不是合法字符串字面量，则行为未定义。

# 出现在 __VA_ARGS__ 前时，将整个展开的 __VA_ARGS__ 放入引号：

#define showlist(...) puts(#__VA_ARGS__)
showlist();            // 展开成 puts("")
showlist(1, "x", int); // 展开成 puts("1, \"x\", int")
 (C99 起)

替换列表 中任意二个相继标识符间的 ## 运算符对二个标识符进行参数替换，然后连接结果。此运算被称作“连接”或“记号粘贴”。只可以粘贴有一同组成合法记号的记号：组成较长标识符的标识符、组成数字的数位或组成 += 的运算符 + 与 = 。不能通过粘贴 / 与 * 创建注释，因为注释被认为在宏替换前移除。若连接的结果不是合法记号，则行为未定义。

注意：一些编译器提供允许 ## 出现在逗号后和 __VA_ARGS__ 前的扩展，在此情况下 ## 在 __VA_ARGS__ 非空时无效，但在 __VA_ARGS__ 为空时移除逗号：这使得可以定义如 fprintf (stderr, format, ##__VA_ARGS__) 的宏。

#undef 指令

#undef 指令解除定义 标识符 ，即它取消先前 #define 对 标识符 的定义。若标识符无与之关联的宏，则忽略此指令。

预定义宏

下列宏名称预定义于任意翻译单元中：

__STDC__
 展开成整数常量 1 。 此宏是用以指示一致实现的
(宏常量)
__STDC_VERSION__
(C95)
 展开成 long 类型的整数常量，其值随着 C 标准的每个版本递增：
  • 199409L (C95)
  • 199901L (C99)
  • 201112L (C11)
  • 201710L (C17)
    (宏常量)
__STDC_HOSTED__
(C99)
 若实现有宿主（在操作系统下运行），则展开成整数常量 1 ，若为独立的（不在操作系统中运行）则展开成 ​0​
(宏常量)
__FILE__
 展开成当前文件名，为字符串字面量，可用 #line 指令更改
(宏常量)
__LINE__
 展开成源文件行号，为整数常量，可用 #line 指令更改
(宏常量)
__DATE__
 展开成翻译的日期，格式为 "Mmm dd yyyy" 的字符串字面量。月份名如同以 asctime 生成，而若月之日期小于 10 则 "dd" 的首字符为空格
(宏常量)
__TIME__
 展开成翻译的时间，格式为 "hh:mm:ss" 的字符串字面量，如同 asctime () 所生成
(宏常量)

实现可能预定义下列额外宏名：

__STDC_ISO_10646__ (C99) | 若 wchar_t 使用 Unicode ，则展开成形式为 yyyymmL 的整数常量，日期指示受支持的 Unicode 最近版本 (宏常量)
__STDC_IEC_559__ (C99) | 若支持 IEC 60559 则展开成 1 (弃用) (C23 起) (宏常量)
__STDC_IEC_559_COMPLEX__ (C99) | 若支持 IEC 60559 复数算术则展开成 1 (弃用) (C23 起) (宏常量)
__STDC_UTF_16__ (C11) | 若 char16_t 使用 UTF-16 则展开成 1 (宏常量)
__STDC_UTF_32__ (C11) | 若 char32_t 使用 UTF-32 则展开成 1 (宏常量)
__STDC_MB_MIGHT_NEQ_WC__ (C99) | 若 'x' == L'x' 可能对基础字符集的成员为 false 则展开成 1 ，例如在基于 EBCDIC 的， wchar_t 使用 Unicode 的系统上 (宏常量)
__STDC_ANALYZABLE__ (C11) | 若支持可分析性则展开成 1 (宏常量)
__STDC_LIB_EXT1__ (C11) | 若支持边界检查接口则展开成整数常量 201112L (宏常量)
__STDC_NO_ATOMICS__ (C11) | 若不支持原子类型和原子操作库则展开成 1 (宏常量)
__STDC_NO_COMPLEX__ (C11) | 若不支持复数类型和复数运算库则展开成 1 (宏常量)
__STDC_NO_THREADS__ (C11) | 若不支持多线程则展开成 1 (宏常量)
__STDC_NO_VLA__ (C11) | 若不支持非常量长度数组则展开成 1 (宏常量)
__STDC_IEC_60559_BFP__ (C23) | 若支持 IEC 60559 二进制浮点算术则展开成 202ymmL （日期待定） (宏常量)
__STDC_IEC_60559_DFP__ (C23) | 若支持 IEC 60559 十进制浮点算术则展开成 202ymmL （日期待定） (宏常量)
__STDC_IEC_60559_COMPLEX__ (C23) | 若支持 IEC 60559 复数算术则展开成 202ymmL （日期待定） (宏常量)

这些宏的值（除了 __FILE__ 和 __LINE__ ）在整个翻译单元中保持常量。尝试重定义或解除定义这些宏导致未定义行为。

预定义对象 __func__ （细节见函数定义）不是预处理器宏，尽管有时与 __FILE__ 及 __LINE__ 一同使用它，例如通过 assert 。

 (C99 起)

示例

#include <stdio.h>

// 制造函数工厂并使用之
#define FUNCTION(name, a) int fun_##name(int x) { return (a)*x;}

FUNCTION(quadruple, 4)
FUNCTION(double, 2)

#undef FUNCTION
#define FUNCTION 34
#define OUTPUT(a) puts( #a )

int main(void)
{
    printf("quadruple(13): %d\n", fun_quadruple(13) );
    printf("double(21): %d\n", fun_double(21) );
    printf("%d\n", FUNCTION);
    OUTPUT(million);               // 注意缺少引号
}

输出：

quadruple(13): 52
double(21): 42
34
million

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 6.10.3 Macro replacement (p: 121-126)
  • 6.10.8 Predefined macro names (p: 127-129)
  • C11 标准（ISO/IEC 9899:2011）：
  • 6.10.3 Macro replacement (p: 166-173)
  • 6.10.8 Predefined macro names (p: 175-176)
  • C99 标准（ISO/IEC 9899:1999）：
  • 6.10.3 Macro replacement (p: 151-158)
  • 6.10.8 Predefined macro names (p: 160-161)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 3.8.3 Macro replacement
  • 3.8.8 Predefined macro names

参阅


程序支持工具

< c

终止程序

下列函数管理程序终止和资源清理。

定义于头文件 <stdlib.h>
abort | 引发非正常的程序终止（不清理） (函数)
exit | 引发正常的程序终止并清理 (函数)
quick_exit (C11) | 引发正常的程序终止但不完全清理 (函数)
_Exit (C99) | 引发正常的程序终止但不清理 (函数)
atexit | 注册一个要在调用 exit() 时调用的函数 (函数)
at_quick_exit (C11) | 注册要在调用 quick_exit 时调用的函数 (函数)
EXIT_SUCCESSEXIT_FAILURE | 表示程序的执行结果 (宏常量)

访问环境

system | 调用宿主环境的命令处理器 (函数)
getenvgetenv_s (C11) | 访问环境变量列表 (函数)

信号

提供几个为信号管理的函数和常量宏。

定义于头文件 <signal.h>
signal
 为特定的信号设置信号处理函数
(函数)
raise
 运行特定信号的信号处理函数
(函数)
sig_atomic_t
 用于从异步信号处理函数访问原子实体的整数类型
(typedef)
SIG_DFLSIG_IGN
 定义信号处理策略
(宏常量)
SIG_ERR
 遇到错误
(宏常量)
信号类型
SIGABRTSIGFPESIGILLSIGINTSIGSEGVSIGTERM
 定义信号类型
(宏常量)

非局部跳转

定义于头文件 <setjmp.h>
setjmp
 保存环境
(宏函数)
longjmp
 跳转到指定位置
(函数)
类型
jmp_buf
 执行环境类型
(typedef)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.13 Nonlocal jumps <setjmp.h> (p: 262-264)
  • 7.14 Signal handling <signal.h> (p: 265-267)
  • 7.22 General utilities <stdlib.h> (p: 340-360)
  • 7.31.7 Signal handling <signal.h> (p: 455)
  • 7.31.12 General utilities <stdlib.h> (p: 456)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.13 Nonlocal jumps <setjmp.h> (p: 243-245)
  • 7.14 Signal handling <signal.h> (p: 246-248)
  • 7.20 General utilities <stdlib.h> (p: 306-324)
  • 7.26.6 Signal handling <signal.h> (p: 401)
  • 7.26.10 General utilities <stdlib.h> (p: 402)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.6 NON-LOCAL JUMPS <setjmp.h>
  • 4.7 SIGNAL HANDLING <signal.h>
  • 4.10 GENERAL UTILITIES <stdlib.h>
  • 4.13.5 Signal handling <signal.h>
  • 7.13.7 General utilities <stdlib.h>

参阅


EXIT_SUCCESS, EXIT_FAILURE

< c‎ | program
定义于头文件 <stdlib.h>
#define EXIT_SUCCESS /*implementation defined*/
#define EXIT_FAILURE /*implementation defined*/

EXIT_SUCCESS 和 EXIT_FAILURE 宏展开成能用作 exit 参数的整数表达式（从而作为从 main 函数返回的值），并指示程序执行状态。

常量 | 解释
EXIT_SUCCESS | 程序执行成功
EXIT_FAILURE | 程序执行不成功

注意

EXIT_SUCCESS 和值零都能指示程序执行成功的状态，尽管并不要求 EXIT_SUCCESS 等于零。

示例

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *fp = fopen("data.txt","r");
    if (fp == NULL)
    {
       fprintf(stderr,"fopen() failed in file %s at line # %d", __FILE__,__LINE__);
       exit(EXIT_FAILURE);
    }

    /* 正常进程持续至此。 */
    fclose(fp);
    printf("Normal Return\n");

    return EXIT_SUCCESS;
}

输出：

fopen() failed in file main.cpp at line # 9

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22/3 General utilities <stdlib.h> (p: 340)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20/3 General utilities <stdlib.h> (p: 306)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10 General utilities <stdlib.h>

参阅


SIG_ERR

< c‎ | program
定义于头文件 <signal.h>
#define SIG_ERR /* implementation defined */

void (*)(int) 类型值。为 signal 所返回时，指示出现了错误。

示例

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void signal_handler(int signal)
{
    printf("Received signal %d\n", signal);
}

int main(void)
{
    /* 安装信号处理函数。 */
    if (signal(SIGTERM, signal_handler) == SIG_ERR)
    {
        printf("Error while installing a signal handler.\n");
        exit(EXIT_FAILURE);
    }

    printf("Sending signal %d\n", SIGTERM);
    if (raise(SIGTERM) != 0)
    {
        printf("Error while raising the SIGTERM signal.\n");
        exit(EXIT_FAILURE);
    }

    printf("Exit main()\n");
    return EXIT_SUCCESS;
}

输出：

Sending signal 15
Received signal 15
Exit main()

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.14/3 Signal handling <signal.h> (p: 265)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.14/3 Signal handling <signal.h> (p: 246)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.7 SIGNAL HANDLING <signal.h>

参阅

signal
 为特定的信号设置信号处理函数
(函数)


SIG_DFL, SIG_IGN

< c‎ | program
定义于头文件 <signal.h>
#define SIG_DFL /*implementation defined*/
#define SIG_IGN /*implementation defined*/

SIG_DFL 和 SIG_IGN 宏展开成不等于任何函数地址的整数表达式。宏定义用于 signal () 函数的信号处理策略。

常量 | 解释
SIG_DFL | 默认信号处理
SIG_IGN | 忽略信号

示例

#include <signal.h>
#include <stdio.h>

int main(void)
{
    /* 使用默认信号处理 */
    raise(SIGTERM);
    printf("Exit main()\n");   /* 决不抵达 */
}

输出：

示例

#include <signal.h>
#include <stdio.h>

int main(void)
{
    /* 忽略信号 */
    signal(SIGTERM, SIG_IGN);
    raise(SIGTERM);
    printf("Exit main()\n");
}

输出：

Exit main()

引用

  • C11 标准（ISO/IEC 9899:2011）：
    •

  • 7.14/3 Signal handling <signal.h> (p: 265)
    •

  • C99 标准（ISO/IEC 9899:1999）：
    •

  • 7.14/3 Signal handling <signal.h> (p: 246)
    •

  • C89/C90 标准（ISO/IEC 9899:1990）：
    •

  • 4.7 SIGNAL HANDLING <signal.h>
    •

参阅


SIGTERM, SIGSEGV, SIGINT, SIGILL, SIGABRT, SIGFPE

< c‎ | program
定义于头文件 <signal.h>
#define SIGTERM /*implementation defined*/
#define SIGSEGV /*implementation defined*/
#define SIGINT /*implementation defined*/
#define SIGILL /*implementation defined*/
#define SIGABRT /*implementation defined*/
#define SIGFPE /*implementation defined*/

上面每个宏常量都展开成拥有相异值的整数常量表达式，表示发送给程序的不同信号。

常量 | 解释
SIGTERM | 发送给程序的终止请求
SIGSEGV | 非法内存访问（段错误）
SIGINT | 外部中断，通常为用户所发动
SIGILL | 非法程序映像，例如非法指令
SIGABRT | 异常终止条件，例如 abort() 所起始的
SIGFPE | 错误的算术运算，如除以零

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.14/3 Signal handling <signal.h> (p: 265)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.14/3 Signal handling <signal.h> (p: 246)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.7 SIGNAL HANDLING <signal.h>

参阅

signal | 为特定的信号设置信号处理函数 (函数)
raise | 运行特定信号的信号处理函数 (函数)


_Exit

< c‎ | program
定义于头文件 <stdlib.h> |
void _Exit( int exit_code ); | (C99 起) (C11 前)
_Noreturn void _Exit( int exit_code ); | (C11 起)

导致出现程序正常终止，而不完全清理资源。

不调用传递给 at_quick_exit() 或 atexit() 的函数。是否以未写入数据冲入打开的流、关闭打开的流或移除临时文件是实现定义的。

若 exit_code 为 0 或 EXIT_SUCCESS ，则将指示成功终止的状态返回给宿主环境。若 exit_code 为 EXIT_FAILURE ，则返回指示不成功终止的实现定义状态。其他情况下返回实现定义的状态值。

参数

exit_code - 程序的退出状态

返回值

（无）

示例

#include <stdlib.h>
#include <stdio.h>

/* _Exit 不调用 atexit 所注册的函数。 */
void f1(void)
{
    puts("pushed first");
}

void f2(void)
{
    puts("pushed second");
}

int main(void)
{
    printf("Enter main()\n");
    atexit(f1);
    atexit(f2);
    fflush(stdout);   /* _Exit 可能不冲入未写入的缓冲数据 */
    _Exit(0);
}

输出：

Enter main()

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.4.5 The _Exit function (p: 352)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.4.4 The _Exit function (p: 316)

参阅

abort | 引发非正常的程序终止（不清理） (函数)
exit | 引发正常的程序终止并清理 (函数)


abort

< c‎ | program
定义于头文件 <stdlib.h> |
void abort(void); | (C11 前)
_Noreturn void abort(void); | (C11 起)

导致程序异常终止，除非传递给 signal 的信号处理函数正在捕捉 SIGABRT ，而该处理函数不返回。

不调用传递给 atexit() 的函数。是否关闭打开的资源，例如文件，是实现定义的。向宿主环境返回指示不成功执行的实现定义状态。

参数

（无）

返回值

（无）

注解

POSIX 指定 abort() 函数撤除阻塞，或忽略 SIGABRT 信号。

某些编译器内建子程序，例如 __builtin_trap （ gcc、 clang 及 icc ）或 __debugbreak （ msvc ），能用于尽可能快地终止程序。

示例

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *fp = fopen("data.txt","r");
    if (fp == NULL) {
       fprintf(stderr, "error opening file data.txt in function main()\n");
       abort();
    }

    /* 正常处理持续至此。 */
    fclose(fp);
    printf("Normal Return\n");
    return 0;
}

输出：

error opening file data.txt in function main()

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.22.4.1 The abort function (p: 255)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.4.1 The abort function (p: 350)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.4.1 The abort function (p: 315)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.4.1 The abort function

参阅

exit | 引发正常的程序终止并清理 (函数)
atexit | 注册一个要在调用 exit() 时调用的函数 (函数)
quick_exit (C11) | 引发正常的程序终止但不完全清理 (函数)


at_quick_exit

< c‎ | program
定义于头文件 <stdlib.h> |
int at_quick_exit( void (*func)(void) ); | (C11 起)

注册 func 所指向的函数，使它在程序快速终止（通过 quick_exit ）时得到调用。

at_quick_exit 是线程安全的：从多个线程调用此函数不会导入数据竞争。实现应当支持注册至少 32 个函数。

参数

func - 指向要在程序快速终止调用的函数的指针

返回值

若注册成功则为 ​0​ ，否则为非零值。

示例

#include <stdlib.h>
#include <stdio.h>

void f1(void)
{
    puts("pushed first");
    fflush(stdout);
}

void f2(void)
{
    puts("pushed second");
}

int main(void)
{
    at_quick_exit(f1);
    at_quick_exit(f2);
    quick_exit(0);
}

输出：

pushed second
pushed first

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.4.3 The at_quick_exit function (p: 351)

参阅

atexit
 注册一个要在调用 exit() 时调用的函数
(函数)


atexit

< c‎ | program
定义于头文件 <stdlib.h>
int atexit( void (*func)(void) );

注册 func 所指向的函数，使它在程序正常终止（通过 exit() 或从 main() 返回）时得到调用。将以注册顺序的逆序调用这些函数，即首先执行最后调用的函数。

可以注册同一函数多于一次。

atexit 是线程安全的：多个线程调用此函数不会引入数据竞争。

标准保证至少支持注册 32 个函数。准确极限是实现定义的。

参数

func - 指向要在程序正常终止时调用的函数的指针

返回值

若注册成功则为 ​0​ ，否则为非零值。

示例

#include <stdlib.h>
#include <stdio.h>

void f1(void)
{
    puts("pushed first");
}

void f2(void)
{
    puts("pushed second");
}

int main(void)
{
    atexit(f1);
    atexit(f2);
}

输出：

pushed second
pushed first

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.4.2 The atexit function (p: 350)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.4.2 The atexit function (p: 315)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.4.2 The atexit function

参阅

at_quick_exit
(C11)
 注册要在调用 quick_exit 时调用的函数
(函数)


exit

< c‎ | program
定义于头文件 <stdlib.h> |
void exit( int exit_code ); | (C11 前)
_Noreturn void exit( int exit_code ); | (C11 起)

导致正常程序终止出现。

进行几个清理步骤：

  • 以注册的逆序调用传递给 atexit 的函数
  • 冲入并关闭所有 C 流
  • 移除 tmpfile 创建的文件
  • 将控制返回给宿主环境。若 exit_code 为零或 EXIT_SUCCESS ，则返回指示成功终止的实现定义状态。若 exit_code 为 EXIT_FAILURE ，则返回指示不成功终止的实现定义状态。其他情况下返回实现定义的状态值。

注解

不调用由 at_quick_exit 注册的函数。

若程序调用 exit 多于一次，或它调用 exit 和 quick_exit ，则行为未定义。

若在调用由 atexit 注册的函数期间，以 longjmp 退出该函数，则行为未定义。

从 main 函数返回时，无论是通过 return 语句还是抵达函数尾，都会将 return 语句的参数（或若使用隐式返回，则为 ​0​ ）作为 exit_code 传递，执行 exit() 。

参数

exit_code - 程序的退出状态

返回值

（无）

示例

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *fp = fopen("data.txt","r");
    if (fp == NULL) {
       fprintf(stderr, "error opening file data.txt in function main()\n");
       exit(1);
    }
    fclose(fp);
    printf("Normal Return\n");
}

可能的输出：

error opening file data.txt in function main()

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.4.4 The exit function (p: 351-352)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.4.3 The exit function (p: 315-316)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.4.3 The exit function

参阅

abort | 引发非正常的程序终止（不清理） (函数)
atexit | 注册一个要在调用 exit() 时调用的函数 (函数)
quick_exit (C11) | 引发正常的程序终止但不完全清理 (函数)


getenv, getenv_s

< c‎ | program
定义于头文件 <stdlib.h> |  |
char *getenv( const char *name ); | (1) |
errno_t getenv_s( size_t *restrict len, char *restrict value, rsize_t valuesz, const char *restrict name ); | (2) | (C11 起)
1) 在宿主指定的环境列表中，查找名为 name 的环境变量，并返回关联到匹配环境变量的字符串。环境变量的集合及修改它的方法是实现定义的。
此函数不保证是线程安全的。另一个对 getenv 的调用，和对 POSIX 函数 setenv() 、 unsetenv() 及putenv() 的调用，可能会使先前的调用返回的指针非法，或者修改先前调用所得的字符串。
修改 getenv 返回的字符串会引起未定义行为。
2) 同 (1) ，除了将环境变量的值写入用户提供的缓冲区 value （除非它为 NULL ），而且将写入的字节数存储于用户提供的位置 *len （除非它为 NULL ）。若环境变量未设置于环境中，则 *len 会被写入零（除非是 NULL ），且 '\0' 会被写入 value[0] （除非是 NULL ）。另外，在运行时检测下列错误并调用当前安装的制约处理函数
  • name 是空指针
  • valuesz 大于 RSIZE_MAX
  • value 是空指针且 valuesz 非零
同所有边界检查函数， getenv_s 仅若实现定义 __STDC_LIB_EXT1__ 且用户在包含 stdlib.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

name | - | 标识要查找的环境变量名称的空终止字符串
len | - | 指向用户提供的位置， getenv_s 将会在其中存储环境变量的长度
value | - | 指向用户提供的字符数组， getenv_s 将会在其中存储环境变量内容
valuesz | - | 允许 getenv_s 对目标写入的最大字节数（缓冲区大小）

返回值

1) 标识环境变量的值的字符串，若找不到该环境变量则为空指针。
2) 若找到环境变量则为零，若找不到该环境变量或发生运行时强制违规，则为非零。错误的情况下，将 *len 写入零（除非 len 为空指针）。

注解

POSIX 系统上，亦可通过全局变量 environ 访问环境变量，它于 <unistd.h> 中声明为 extern char **environ; ，并可通过可选的 main 函数第三参数 envp 访问。

以空指针为 value ，以零为 valuesz 调用 getenv_s ，可用于确定保有整个结果所需的缓冲区大小。

示例

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    const char *name = "PATH";
    const char *env_p = getenv(name);
    if (env_p)
        printf("%s = %s\n", name, env_p);
}

可能的输出：

PATH = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.4.6 The getenv function (p: 352-353)
  • K.3.6.2.1 The getenv_s function (p: 606-607)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.4.5 The getenv function (p: 317)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.4.4 The getenv function

参阅


jmp_buf

< c‎ | program
定义于头文件 <setjmp.h>
typedef /* unspecified */ jmp_buf;

jmp_buf 类型是适合于存储并恢复调用环境的数组类型。存储的信息足以恢复程序在当前块的执行和该块的调用。浮点状态标志、打开的文件或其他任何数据不存储于 jmp_buf 类型对象中。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.13/2 Nonlocal jumps <setjmp.h> (p: 262)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.13/2 Nonlocal jumps <setjmp.h> (p: 243)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.6 NON-LOCAL JUMPS <setjmp.h>

参阅

setjmp | 保存环境 (宏函数)
longjmp | 跳转到指定位置 (函数)


longjmp

< c‎ | program
定义于头文件 <setjmp.h> |
void longjmp( jmp_buf env, int status ); | (C11 前)
_Noreturn void longjmp( jmp_buf env, int status ); | (C11 起)

载入先前调用 setjmp 保存的执行环境 env 。此函数不返回。转移控制流到设置 env 的宏 setjmp 的调用方。该 setjmp 会返回作为 status 传递的值。

若调用 setjmp 的函数已退出（通过返回或通过另一到栈上更高处的 longjmp ），则行为未定义。换言之，只有调用栈间的长跳转是允许的。

跨线程跳转（若调用 setjmp 的函数被另一线程执行）亦是未定义行为。

 (C11 起)

若在调用 setjmp 时， VLA 或其他可变修改类型变量在作用域中，并且控制流离开了该作用域，则 longjmp 到该 setjmp 将引发未定义行为，即使控制流仍然留在该函数内。

在上溯栈的途中， longjmp 不会解分配任何 VLA ，若其的生存期以此方式终结，则会出现内存泄漏：

void g(int n)
{
    int a[n]; // a 仍为已分配
    h(n); // 不返回
}
void h(int n)
{
    int b[n]; // b 仍为已分配
    longjmp(buf, 2); // 可能因为 h 的 b 和 g 的 a 导致内存泄漏
}
 (C99 起)

参数

env | - | 引用 setjmp 所保存的程序执行状态的变量
status | - | 要从 setjmp 返回的值。若它等于 ​0​ ，则以 1 替代使用

返回值

（无）

注意

longjmp 是有意用以处理未期待的错误条件的，该条件下函数无法有意义地返回。这与其他编程语言中的异常处理相似。

示例

#include <stdio.h>
#include <setjmp.h>
#include <stdnoreturn.h>

jmp_buf jump_buffer;

noreturn void a(int count)
{
    printf("a(%d) called\n", count);
    longjmp(jump_buffer, count+1); // 将在 setjmp 外返回 count+1
}

int main(void)
{
    volatile int count = 0; // 必须为 setjmp 声明 volatile 对象
    if (setjmp(jump_buffer) != 9)
        a(count++);
}

输出：

a(0) called
a(1) called
a(2) called
a(3) called
a(4) called
a(5) called
a(6) called
a(7) called
a(8) called

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.13.2.1 The longjmp macro (p: 263-264)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.13.2.1 The longjmp macro (p: 244-245)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.6.2.1 The longjmp function

参阅

setjmp
 保存环境
(宏函数)


quick_exit

< c‎ | program
定义于头文件 <stdlib.h> |
_Noreturn void quick_exit( int exit_code ); | (C11 起)

导致程序正常终止，而不完全清理资源。

以注册顺序的逆序调用传递给 at_quick_exit 的函数。调用完注册的函数后，调用 _Exit (exit_code) 。

参数

exit_code - 程序的退出状态

返回值

（无）

示例

#include <stdlib.h>
#include <stdio.h>

void f1(void)
{
    puts("pushed first");
    fflush(stdout);
}

void f2(void)
{
    puts("pushed second");
}

int main(void)
{
    at_quick_exit(f1);
    at_quick_exit(f2);
    quick_exit(0);
}

输出：

pushed second
pushed first

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.4.7 The quick_exit function (p: 353)

参阅

abort | 引发非正常的程序终止（不清理） (函数)
atexit | 注册一个要在调用 exit() 时调用的函数 (函数)
at_quick_exit (C11) | 注册要在调用 quick_exit 时调用的函数 (函数)


raise

< c‎ | program
定义于头文件 <signal.h>
int raise( int sig );

发送 sig 给程序。调用以 signal() 指定的信号处理函数。

若仍未用 signal() 设置用户定义的信号处理策略，则忽略信号还是调用默认处理函数是实现定义的。

参数

sig - 要发送的信号。能为实现定义值或下列值之一：
SIGABRTSIGFPESIGILLSIGINTSIGSEGVSIGTERM
 定义信号类型
(宏常量)

返回值

成功时为 ​0​ ，失败时为非零。

示例

#include <signal.h>
#include <stdio.h>

void signal_handler(int signal)
{
    printf("Received signal %d\n", signal);
}

int main(void)
{
    // 安装信号处理函数。
    signal(SIGTERM, signal_handler);

    printf("Sending signal %d\n", SIGTERM);
    raise(SIGTERM);
    printf("Exit main()\n");
}

输出：

Sending signal 15
Received signal 15
Exit main()

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.14.2.1 The raise function (p: 267)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.14.2.1 The raise function (p: 248)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.7.2.1 The raise function

参阅

signal
 为特定的信号设置信号处理函数
(函数)


setjmp

< c‎ | program
定义于头文件 <setjmp.h>
#define setjmp(env) /* implementation-defined */

将当前执行环境保存到 jmp_buf 类型对象 env 。此对象可在之后被 longjmp 函数用来恢复当前执行环境。即当调用 longjmp 函数时，执行将从传递给 longjmp 的 jmp_buf 对象所构建的特定调用点继续。该情况下 setjmp 返回传递给 longjmp 的值。

setjmp 的调用必须只出现在下列语境之一中：

  • 选择或迭代语句（ if 、 switch 、 for 、 while 、 do-while ）的完整控制表达式
switch(setjmp(env)) { ..
  • 比较或相等运算符的一个运算数，另一运算数为整数常量表达式，产生的表达式为选择或迭代语句的完整控制表达式
if(setjmp(env) > 10) { ...
  • 一元 ! 运算符的运算数，其结果为选择或迭代语句的完整控制表达式
while(!setjmp(env)) { ...
  • 表达式语句的完整表达式（可以将其转型到 void ）。
setjmp(env);

若 setjmp 出现于其他语境中，则行为未定义。

一旦返回到 setjmp 的作用域，所有可访问对象、浮点状态标志及其他抽象机组件拥有与在执行 longjmp 时相同的值，除了含有 setjmp 调用的函数中的非 volatile 局部对象，在 setjmp 调用后更改它们，则其值不确定。

参数

env - 要保存程序执行状态的对象。

返回值

若原初代码调用该宏，则返回 ​0​ ，并保存执行环境到 env 。

若进行了非局部跳转则可返回非零值。返回值与传递给 longjmp 者相同。

注解

上述要求禁止在数据流中使用 setjmp 的返回值（例如以之初始化或赋值对象）。只能将返回值用于控制流或舍弃。

示例

#include <stdio.h>
#include <setjmp.h>
#include <stdnoreturn.h>

jmp_buf jump_buffer;

noreturn void a(int count)
{
    printf("a(%d) called\n", count);
    longjmp(jump_buffer, count+1); // 将从 setjmp 外 count+1
}

int main(void)
{
    volatile int count = 0; // setjmp 作用域内要修改的局部变量必须为 volatile
    if (setjmp(jump_buffer) != 9) // 在一个 if 内与常数比较
        a(count++);
}

输出：

a(0) called
a(1) called
a(2) called
a(3) called
a(4) called
a(5) called
a(6) called
a(7) called
a(8) called

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.13.1.1 The setjmp macro (p: 262-263)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.13.1.1 The setjmp macro (p: 243-244)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.6.1 The setjmp macro

参阅

longjmp
 跳转到指定位置
(函数)


sig_atomic_t

< c‎ | program
定义于头文件 <signal.h>
typedef /* unspecified */ sig_atomic_t;

即使缺少信号所做的异步中断，亦能作为原子实体访问的整数类型。

示例

#include <signal.h>
#include <stdio.h>

volatile sig_atomic_t gSignalStatus = 0;

void signal_handler(int signal)
{
    gSignalStatus = signal;
}

int main(void)
{
    /* 安装信号处理函数 */
    signal(SIGINT, signal_handler);

    printf("SignalValue:   %d\n", gSignalStatus);
    printf("Sending signal %d\n", SIGINT);
    raise(SIGINT);
    printf("SignalValue:   %d\n", gSignalStatus);
}

可能的输出：

SignalValue:   0
Sending signal 2
SignalValue:   2

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.14/2 Signal handling <signal.h> (p: 265)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.14/2 Signal handling <signal.h> (p: 246)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.7 SIGNAL HANDLING <signal.h>

参阅

signal
 为特定的信号设置信号处理函数
(函数)


signal

< c‎ | program
定义于头文件 <signal.h>
void (*signal( int sig, void (*handler) (int))) (int);

设置信号 sig 的错误处理函数。能设置错误处理函数，使得将出现默认处理、忽略信号或调用用户定义函数。

当设置信号处理为一个函数，而信号出现时，是否立即在信号处理函数开始前调用 signal(sig, SIG_DFL ) 是实现定义的。而且，实现能阻止某个实现定义的信号集在信号处理函数运行时出现。

参数

sig - 设置给信号处理函数的信号。能为实现定义的值或下列值之一：
SIGABRTSIGFPESIGILLSIGINTSIGSEGVSIGTERM
 定义信号类型
(宏常量)

handler - 信号处理函数。必须是下列之一：
  • SIG_DFL 宏。将信号处理函数默认设为默认信号处理函数。
  • SIG_IGN 宏。忽略信号。
  • 函数指针。函数签名必须等价于如下形式：
void fun(int sig);

返回值

成功时为之前设置的信号处理，失败时为 SIG_ERR （一些实现上能禁用设置信号处理函数）。

信号处理函数

安装为信号处理函数的用户定义函数上，强制了下列限制。

若用户定义函数在处理 SIGFPE 、 SIGILL 或 SIGSEGV 时返回，则行为未定义。

若作为 abort 或 raise 的结果调用了信号处理函数，则若信号处理函数调用 raise ，则行为未定义。

若信号处理函数不是作为 abort 或 raise 的结果调用（换言之，信号处理是异步的），则在下列场合行为未定义

  • 信号处理在调用任何标准库内的函数，除了
  • abort
  • _Exit
  • quick_exit
  • 以当前处理信号的编号为第一参数，调用 signal （异步处理函数能重注册其自身，但不能注册其他信号）。
  • 来自 stdatomic.h 的原子函数，若原子参数为免锁
  • atomic_is_lock_free （以任何类型的原子参数）
  • 信号处理函数使用任何拥有静态或线程局域 (C11 起) 存储期 ，且非免锁原子的 (C11 起)对象，除了赋值给静态 volatile sig_atomic_t 对象。

进入信号处理函数时，浮点环境状态和所有对象的值是未指定的，除了

  • volatile sig_atomic_t 类型对象
  • 免锁原子类型对象(C11 起)
  • 通过 atomic_signal_fence 使之可见的副效应(C11 起)

从信号处理函数返回时，信号处理函数所修改的任何对象的值，除了 volatile sig_atomic_t 及免锁原子 (C11 起)对象，均为未定义。

若 signal 被用于多线程程序，则行为未定义。不要求它是线程安全的。

注解

POSIX 要求 signal 为线程安全的，而且能从任何信号处理函数调用异步信号安全（ async-signal-safe ）库函数列表中的函数。

除了 abort 和 raise 后， POSIX 还指定 kill 、 pthread_kill 以及 sigqueue 生成同步信号。

POSIX 推荐用 sigaction 替代 signal ，因为其受指定的行为，还有其关乎在执行信号处理函数时投递信号的重要实现变更。

示例

#include <signal.h>
#include <stdio.h>

volatile sig_atomic_t gSignalStatus;

void signal_handler(int signal)
{
  gSignalStatus = signal;
}

int main(void)
{
  signal(SIGINT, signal_handler);

  printf("SignalValue: %d\n", gSignalStatus);
  printf("Sending signal: %d\n", SIGINT);
  raise(SIGINT);
  printf("SignalValue: %d\n", gSignalStatus);
}

输出：

SignalValue: 0
Sending signal: 2
SignalValue: 2

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.14.1.1 The signal function (p: 266-267)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.14.1.1 The signal function (p: 247-248)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.7.1.1 The signal function

参阅

raise
 运行特定信号的信号处理函数
(函数)


system

< c‎ | program
定义于头文件 <stdlib.h>
int system( const char *command );

以参数 command 调用宿主环境的命令处理器。返回实现定义值（通常是被调用程序所返回的值）。

若 command 是空指针，则检查宿主环境是否有命令处理器，并若且仅若命令处理器存在才返回非零。

参数

command - 标识要运行于命令处理器的命令的字符串。若给出空指针，则检查其存在性

返回值

实现定义值。若 command 为空指针，则若且唯若命令处理器存在才返回非零值。

注意

POSIX 系统上，可用 WEXITSTATUS 和 WSTOPSIG 分解返回值。

相关的 POSIX 函数 popen 令 command 生成的输出对调用方可用。

示例

此示例中有 unix 命令 date +%A 的系统调用：

#include <stdlib.h>

int main(void) {
    system("date +%A");
}

可能的输出：

Wednesday

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.4.8 The system function (p: 353-354)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.4.6 The system function (p: 317)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.4.5 The system function

参阅


字符串库

< c

空终止字节字符串管理

空终止多字节字符串管理

空终止宽字符串管理

参阅


空终止字节字符串

< c‎ | string

空终止字节字符串（ NTBS ）是尾随零值字节（空终止字符）的非零字节序列。字节字符串中的每个字节都是一些字符集的编码。例如，字符数组 {'\x63','\x61','\x74','\0'} 是一个以 ASCII 编码表示字符串 "cat" 的 NTBS 。

函数

字符分类
定义于头文件 <ctype.h>
isalnum
 检查一个字符是否是字母或数字
(函数)
isalpha
 检查一个字符是否是英文字母
(函数)
islower
 检查一个字符是否是小写字母
(函数)
isupper
 检查一个字符是否是大写字母
(函数)
isdigit
 检查字符是否为数字
(函数)
isxdigit
 检查一个字符是否是十六进制的字符
(函数)
iscntrl
 检查一个字符是否是控制字符
(函数)
isgraph
 检查一个字符是否是可显示的字符
(函数)
isspace
 检查一个字符是否是空白字符
(函数)
isblank
(C99)
 检查一个字符是否是空格字符
(函数)
isprint
 检查一个字符是否是可打印字符
(函数)
ispunct
 检查一个字符是否是一个标点符号
(函数)
字符操作
tolower
 将字符转换成小写
(函数)
toupper
 将字符转换成大写
(函数)

注意：将来可能添加以 to 或 is 后随小写字母起始的新增函数到头文件 ctype.h ，故不应于包含该头文件的程序中定义这些函数。

ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
转换成数值格式
定义于头文件 <stdlib.h>
atof
 将字节字符串转换成浮点值
(函数)
atoiatolatoll
(C99)
 将字节字符串转换成整数值
(函数)
strtolstrtoll
(C99)
 将字节字符串转换成整数值
(函数)
strtoul strtoull
(C99)
 将字节字符串转换成无符号整数值
(函数)
strtofstrtodstrtold
(C99)(C99)
 将字节字符串转换成浮点值
(函数)
定义于头文件 <inttypes.h>
strtoimaxstrtoumax
(C99)(C99)
 将字节字符串转换成 intmax_t 或 uintmax_t
(函数)
字符串操作
定义于头文件 <string.h>
strcpystrcpy_s
(C11)
 复制一个字符串给另一个
(函数)
strncpystrncpy_s
(C11)
 从一个字符串复制一定数量的字符到另一个
(函数)
strcatstrcat_s
(C11)
 连接两个字符串
(函数)
strncatstrncat_s
(C11)
 连接两个字符串的一定数量字符
(函数)
strxfrm
 变换字符串，使得 strcmp 会产生同 strcoll 的结果
(函数)
strdup
(C23)
 分配字符串的副本
(函数)
strndup
(C23)
 分配拥有指定大小的字符串副本
(函数)
字符串检验
定义于头文件 <string.h>
strlenstrnlen_s
(C11)
 返回给定字符串的长度
(函数)
strcmp
 比较两个字符串
(函数)
strncmp
 比较两个字符串的一定数量字符
(函数)
strcoll
 比较两个字符串，根据当前本地环境
(函数)
strchr
 查找字符的首次出现
(函数)
strrchr
 查找字符的最后一次出现
(函数)
strspn
 返回由另一个字符串中的字符分割的最大起始段长度
(函数)
strcspn
 返回另一个字符串所不具有的字符分割的最大起始段长度
(函数)
strpbrk
 查找一个字符串中的任意一个字符在另一个字符串中的首个位置
(函数)
strstr
 查找子串字符的首次出现
(函数)
strtokstrtok_s
(C11)
 查找字节字符串中的下一个记号
(函数)
字符数组操作
定义于头文件 <string.h>
memchr
 在数组中搜索字符的首次出现
(函数)
memcmp
 比较两块缓冲区
(函数)
memsetmemset_s
(C11)
 以字符填充缓冲区
(函数)
memcpymemcpy_s
(C11)
 将一个缓冲区复制到另一个
(函数)
memmovememmove_s
(C11)
 将一个缓冲区移动到另一个
(函数)
memccpy
(C23)
 复制一个缓冲区到另一个，在指定的分隔符后停止
(函数)
杂项
定义于头文件 <string.h>
strerrorstrerror_sstrerrorlen_s
(C11)(C11)
 返回给定错误码的文本版本
(函数)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4 Character handling <ctype.h> (p: 200-204)
  • 7.8 Format conversion of integer types <inttypes.h> (p: 217-220)
  • 7.22 General utilities <stdlib.h> (p: 340-360)
  • 7.24 String handling <string.h> (p: 362-372)
  • 7.31.2 Character handling <ctype.h> (p: 455)
  • 7.31.5 Format conversion of integer types <inttypes.h> (p: 455)
  • 7.31.12 General utilities <stdlib.h> (p: 456)
  • 7.31.13 String handling <string.h> (p: 456)
  • K.3.6 General utilities <stdlib.h> (p: 604=613)
  • K.3.7 String handling <string.h> (p: 614-623)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4 Character handling <ctype.h> (p: 181-185)
  • 7.8 Format conversion of integer types <inttypes.h> (p: 198-201)
  • 7.20 General utilities <stdlib.h> (p: 306-324)
  • 7.21 String handling <string.h> (p: 325-334)
  • 7.26.2 Character handling <ctype.h> (p: 401)
  • 7.26.4 Format conversion of integer types <inttypes.h> (p: 401)
  • 7.26.10 General utilities <stdlib.h> (p: 402)
  • 7.26.11 String handling <string.h> (p: 402)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.3 CHARACTER HANDLING <ctype.h>
  • 4.10 GENERAL UTILITIES <stdlib.h>
  • 4.11 STRING HANDLING <string.h>
  • 4.13.2 Character handling <ctype.h>
  • 4.13.7 General utilities <stdlib.h>
  • 4.13.8 String handling <string.h>

参阅


atof

< c‎ | string‎ | byte
定义于头文件 <stdlib.h>
double atof( const char* str );

转译 str 所指向的字节字符串中的浮点值。

函数会舍弃任何空白符（由 std:: isspace () 确定），直至找到首个非空白符。然后它会取用尽可能多的字符，以构成合法的浮点数表示，并将它们转换成浮点值。合法的浮点值可以为下列之一：

  • 十进制浮点数表达式。它由下列部分组成：
  • (可选) 正或负号
  • 非空的十进制数字序列，可选地包含一个小数点字符（由当前的 C 本地环境确定）（定义有效数字）
  • (可选) e 或 E ，并跟随可选的正或负号，以及非空十进制数字序列（以 10 为底定义指数）
  • 十六进制浮点数表达式。它由下列部分组成：
  • (可选) 正或负号
  • 0x 或 0X
  • 非空的十六进制数字序列，选地包含一个小数点字符（由当前的 C 本地环境确定）（定义有效数字）
  • (可选) p 或 P ，并跟随可选的正或负号，以及非空十进制数字序列（以 2 为底定义指数）
  • 无穷大表达式。它由下列部分组成：
  • (可选) 正或负号
  • INF 或 INFINITY ，忽略大小写
  • 非数（NaN）表达式。它由下列部分组成：
  • (可选) 正或负号
  • NAN 或 NAN(char_sequence) ，忽略 NAN 部分的大小写。 char_sequence 只能由数字、拉丁字母和下划线构成。结果是一个静态的 NaN 浮点值。
 (C99 起)
  • 任何其他可由当前 C 本地环境接受的表达式

参数

str - 指向待转译的空终止字符串的指针

返回值

成功时返回代表 str 内容的 double 值。若转换的值在返回值范围外，则返回值未定义。若无可进行的转换，则返回 0.0 。

示例

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
    printf("%g\n", atof("  -0.0000000123junk"));
    printf("%g\n", atof("0.012"));
    printf("%g\n", atof("15e16"));
    printf("%g\n", atof("-0x1afp-2"));
    printf("%g\n", atof("inF"));
    printf("%g\n", atof("Nan"));
    printf("%g\n", atof("1.0e+309"));   // UB ：超出 double 范围
    printf("%g\n", atof("0.0"));
    printf("%g\n", atof("junk"));       // 无可进行的转换
}

可能的输出：

-1.23e-08
0.012
1.5e+17
-107.75
inf
nan
inf
0
0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.1.1 The atof function (p: 341)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.1.1 The atof function (p: 307)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.1.1 The atof function

参阅

strtofstrtodstrtold
(C99)(C99)
 将字节字符串转换成浮点值
(函数)


atoi, atol, atoll

< c‎ | string‎ | byte
定义于头文件 <stdlib.h> |
int atoi( const char *str ); |
long atol( const char *str ); |
long long atoll( const char *str ); | (C99 起)

转译 str 所指的字节字符串中的整数值。

舍弃任何空白符，直至找到首个非空白符，然后接收尽可能多的字符以组成合法的整数表示，并转换之为整数值。合法的整数值含下列部分：

  • (可选) 正或负号
  • 数位

参数

str - 指向要转译的空终止字符串的指针

返回值

成功时为对应 str 内容的整数值。若转换的值落在对应的返回类型范围外，则返回值未定义。若无法进行转换，则返回 ​0​ 。

示例

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    printf("%i\n", atoi(" -123junk"));
    printf("%i\n", atoi("0"));
    printf("%i\n", atoi("junk"));         // 无可进行的转换
    printf("%i\n", atoi("2147483648"));   // UB ：在 int 范围外
}

输出：

-123
0
0
-2147483648

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.1.2 The atoi, atol, and atoll functions (p: 341)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.1.2 The atoi, atol, and atoll functions (p: 307)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.1.2 The atoi function
  • 4.10.1.3 The atol function

参阅

strtolstrtoll (C99) | 将字节字符串转换成整数值 (函数)
strtoul strtoull (C99) | 将字节字符串转换成无符号整数值 (函数)


isalnum

< c‎ | string‎ | byte
定义于头文件 <ctype.h>
int isalnum( int ch );

检查给定的字符是否为当前 C 本地环境所分类的字母数字字符。在默认本地环境中，下列字符为字母数字：

  • 数字（ 0123456789 ）
  • 大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）
  • 小写字母（ abcdefghijklmnopqrstuvwxyz ）

若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为字母数字字符，则为非零，否则为 0 。

示例

演示以不同的本地环境（操作系统限定）使用 isalnum() 。

#include <stdio.h>
#include <ctype.h>
#include <locale.h>

int main(void)
{
    unsigned char c = '\xdf'; // ISO-8859-1 中的德文字母 ß

    printf("isalnum('\\xdf') in default C locale returned %d\n", !!isalnum(c));

    if(setlocale(LC_CTYPE, "de_DE.iso88591"))
        printf("isalnum('\\xdf') in ISO-8859-1 locale returned %d\n", !!isalnum(c));
}

可能的输出：

isalnum('\xdf') in default C locale returned 0
isalnum('\xdf') in ISO-8859-1 locale returned 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4.1.1 The isalnum function (p: 200)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4.1.1 The isalnum function (p: 181)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.3.1.1 The isalnum function

参阅

iswalnum
(C95)
 检查宽字符是否为字母或数字
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


isalpha

< c‎ | string‎ | byte
定义于头文件 <ctype.h>
int isalpha( int ch );

检查给定字符是否字母字符，即是大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）或小写字母（ abcdefghijklmnopqrstuvwxyz ）。

在异于 "C" 的本地环境中，字母字符是 isupper() 或 islower() 对其返回非零值的字符，或任何其他被本地环境认为是字母的字符。任何情况下， iscntrl() 、 isdigit() 、 ispunct() 及 isspace() 将对此字符返回零。

若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为字母字符则为非零值，否则为零。

示例

演示以不同的本地环境使用 isalpha() （操作系统限定）。

#include <ctype.h>
#include <stdio.h>
#include <locale.h>

int main(void)
{
    unsigned char c = '\xdf'; // ISO-8859-1 的德文字母 ß

    printf("isalpha('\\xdf') in default C locale returned %d\n", !!isalpha(c));

    setlocale(LC_CTYPE, "de_DE.iso88591");
    printf("isalpha('\\xdf') in ISO-8859-1 locale returned %d\n", !!isalpha(c));
}

输出：

isalpha('\xdf') in default C locale returned 0
isalpha('\xdf') in ISO-8859-1 locale returned 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4.1.2 The isalpha function (p: 200-201)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4.1.2 The isalpha function (p: 181-182)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.3.1.2 The isalpha function

参阅

iswalpha
(C95)
 检查宽字符是否为字母
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


isblank

< c‎ | string‎ | byte
定义于头文件 <ctype.h> |
int isblank( int ch ); | (C99 起)

检查给定的字符在当前的 C 本地环境中是否空格符。在默认 C 本地环境中，只有空格（ 0x20 ）与水平制表符（ 0x09 ）被分类为空格符。

若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为空格符则为非零值，否则为零。

示例

#include <stdio.h>
#include <ctype.h>
#include <limits.h>

int main(void)
{
    for (int ndx=0; ndx<=UCHAR_MAX; ndx++)
        if (isblank(ndx)) printf("0x%02x\n", ndx);
}

输出：

0x09
0x20

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.4.1.3 The isblank function (p: 145)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4.1.3 The isblank function (p: 201)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4.1.3 The isblank function (p: 182)

参阅

iswblank
(C99)
 检查宽字符是否为空格
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


iscntrl

< c‎ | string‎ | byte
定义于头文件 <ctype.h>
int iscntrl( int ch );

检查给定字符是否为控制字符，即编码 0x00-0x1F 及 0x7F 。

若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为控制字符则为非零，否则为零。

示例

#include <stdio.h>
#include <ctype.h>
#include <locale.h>

int main(void)
{
    unsigned char c = '\x94'; // ISO-8859-1 的控制码 CCH
    printf("In the default C locale, \\x94 is %sa control character\n",
           iscntrl(c) ? "" : "not " );
    setlocale(LC_ALL, "en_GB.iso88591");
    printf("In ISO-8859-1 locale, \\x94 is %sa control character\n",
           iscntrl(c) ? "" : "not " );
}

输出：

In the default C locale, \x94 is not a control character
In ISO-8859-1 locale, \x94 is a control character

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4.1.4 The iscntrl function (p: 201)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4.1.4 The iscntrl function (p: 182)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.3.1.3 The iscntrl function

参阅

iswcntrl
(C95)
 检查宽字符是否为控制字符
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


isdigit

< c‎ | string‎ | byte
定义于头文件 <ctype.h>
int isdigit( int ch );

检查给定的字符是否数字字符（ 0123456789 ）。

若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为数字则为非零值，否则为零。

注意

isdigit 与 isxdigit 是仅有的不受当前安装的 C 本地环境影响的标准窄字符分类函数，尽管一些实现（例如 Microsoft 于 1252 代码页）可能将额外的单字节字符分类为数字。

示例

#include <stdio.h>
#include <ctype.h>
#include <limits.h>

int main(void)
{
    for (int ndx=0; ndx<=UCHAR_MAX; ndx++)
        if (isdigit(ndx)) printf("%c", ndx);
    printf("\n");
}

输出：

0123456789

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4.1.5 The isdigit function (p: 201)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4.1.5 The isdigit function (p: 182)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.3.1.4 The isdigit function

参阅

iswdigit
(C95)
 检查宽字符是否为数字
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


isgraph

< c‎ | string‎ | byte
定义于头文件 <ctype.h>
int isgraph( int ch );

检查给定的字符是否拥有图形表示，即它是数字（ 0123456789 ）、大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）、小写字母（ abcdefghijklmnopqrstuvwxyz ）或标点字符（ !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ），或任何指定于当前 C 本地环境的图形字符之一。

若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

参数

ch - 要分类的字符

返回值

若字符拥有图像表示，则为非零，否则为零。

示例

#include <stdio.h>
#include <ctype.h>
#include <locale.h>

int main(void)
{
    unsigned char c = '\xb6'; // ISO-8859-1 的字符 ¶
    printf("In the default C locale, \\xb6 is %sgraphical\n",
           isgraph(c) ? "" : "not " );
    setlocale(LC_ALL, "en_GB.iso88591");
    printf("In ISO-8859-1 locale, \\xb6 is %sgraphical\n",
           isgraph(c) ? "" : "not " );
}

输出：

In the default C locale, \xb6 is not graphical
In ISO-8859-1 locale, \xb6 is graphical

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4.1.6 The isgraph function (p: 201-202)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4.1.6 The isgraph function (p: 182-183)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.3.1.5 The isgraph function

参阅

iswgraph
(C95)
 检查宽字符是否为图形字符
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


islower

< c‎ | string‎ | byte
定义于头文件 <ctype.h>
int islower( int ch );

检查给定字符是否按照当前 C 本地环境分类为小写字符。默认 "C" 本地环境中， islower 仅对小写字母（ abcdefghijklmnopqrstuvwxyz ）返回非零值。

若 islower 返回非零值，则保证同一 C 本地环境中 iscntrl 、 isdigit 、 ispunct 和 isspace 对同一字符返回零。

若 ch 不可表示为 unsigned char 且不等于 EOF 则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为小写字母则为非零值，否则为零。

示例

#include <stdio.h>
#include <ctype.h>
#include <locale.h>

int main(void)
{
    unsigned char c = '\xe5'; // ISO-8859-1 的字母 å
    printf("In the default C locale, \\xe5 is %slowercase\n",
           islower(c) ? "" : "not " );
    setlocale(LC_ALL, "en_GB.iso88591");
    printf("In ISO-8859-1 locale, \\xe5 is %slowercase\n",
           islower(c) ? "" : "not " );
}

输出：

In the default C locale, \xe5 is not lowercase
In ISO-8859-1 locale, \xe5 is lowercase

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4.1.7 The islower function (p: 202)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4.1.7 The islower function (p: 183)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.3.1.6 The islower function

参阅

iswlower
(C95)
 检查宽字符是否为小写
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


isprint

< c‎ | string‎ | byte
定义于头文件 <ctype.h>
int isprint( int ch );

检查给定的字符能否被打印，即为数字（ 0123456789 ）、大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）、小写字母（ abcdefghijklmnopqrstuvwxyz ）、标点字符（ !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ）或空格之一，或任何当前 C 本地环境分类为可打印的字符。

若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

参数

ch - 要分类的字符

返回值

若字符能被打印则为非零，否则为零。

示例

#include <stdio.h>
#include <ctype.h>
#include <locale.h>

int main(void)
{
    unsigned char c = '\xa0'; // ISO-8859-1 的无中断空格
    printf("In the default C locale, \\xa0 is %sprintable\n", isprint(c)?"":"not ");
    setlocale(LC_ALL, "en_GB.iso88591");
    printf("In ISO-8859-1 locale, \\xa0 is %sprintable\n", isprint(c)?"":"not ");
}

输出：

In the default C locale, \xa0 is not printable
In ISO-8859-1 locale, \xa0 is printable

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4.1.8 The isprint function (p: 202)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4.1.8 The isprint function (p: 183)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.3.1.7 The isprint function

参阅

iswprint
(C95)
 检查宽字符是否为打印字符
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


ispunct

< c‎ | string‎ | byte
定义于头文件 <ctype.h>
int ispunct( int ch );

检查给定的字符是否为当前 C 本地环境分类为标点字符。默认 C 本地环境分类字符 !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ 为标点。

若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为标点字符则为非零值，否则为零。

示例

#include <stdio.h>
#include <ctype.h>
#include <locale.h>

int main(void)
{
    unsigned char c = '\xd7'; // ISO-8859-1的字符×（乘号）
    printf("In the default C locale, \\xd7 is %spunctuation\n",
           ispunct(c) ? "" : "not " );
    setlocale(LC_ALL, "en_GB.iso88591");
    printf("In ISO-8859-1 locale, \\xd7 is %spunctuation\n",
           ispunct(c) ? "" : "not " );
}

输出：

In the default C locale, \xd7 is not punctuation
In ISO-8859-1 locale, \xd7 is punctuation

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4.1.9 The ispunct function (p: 202)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4.1.9 The ispunct function (p: 183)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.3.1.8 The ispunct function

参阅

iswpunct
(C95)
 检查宽字符是否为标点符号
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


isspace

< c‎ | string‎ | byte
定义于头文件 <ctype.h>
int isspace( int ch );

检查给定的字符是否空白符，即空格（ 0x20 ）、换行（ 0x0a ）、回车（ 0x0d ）、水平制表符（ 0x09 ）或垂直制表符（ 0x0b ）之一。

若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为空白符则为非零值，否则为零。

示例

#include <stdio.h>
#include <ctype.h>
#include <limits.h>

int main(void)
{
    for (int ndx=0; ndx<=UCHAR_MAX; ndx++)
        if (isspace(ndx)) printf("0x%02x\n", ndx);
}

输出：

0x09
0x0a
0x0b
0x0c
0x0d
0x20

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4.1.10 The isspace function (p: 202-203)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4.1.10 The isspace function (p: 183-184)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.3.1.9 The isspace function

参阅

iswspace
(C95)
 检查宽字符是否为空白符
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


isupper

< c‎ | string‎ | byte
定义于头文件 <ctype.h>
int isupper( int ch );

根据当前C本地环境检查给定字符是否大写字母。在默认 "C" 本地环境中， isupper 仅对大写拉丁字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）返回非零值。

若 isupper返回非零，则保证 iscntrl 、 isdigit、 ispunct 及isspace 在同一 C 本地环境中对同一字符返回零。

若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为大写字母则为非零值，否则为零。

示例

#include <stdio.h>
#include <ctype.h>
#include <locale.h>

int main(void)
{
    unsigned char c = '\xc6'; // ISO-8859-1的 字母 Æ
    printf("In the default C locale, \\xc6 is %suppercase\n",
           isupper(c) ? "" : "not " );
    setlocale(LC_ALL, "en_GB.iso88591");
    printf("In ISO-8859-1 locale, \\xc6 is %suppercase\n",
           isupper(c) ? "" : "not " );
}

输出：

In the default C locale, \xc6 is not uppercase
In ISO-8859-1 locale, \xc6 is uppercase

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4.1.11 The isupper function (p: 203)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4.1.11 The isupper function (p: 184)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.3.1.10 The isupper function

参阅

iswupper
(C95)
 检查宽字符是否为大写
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


isxdigit

< c‎ | string‎ | byte
定义于头文件 <ctype.h>
int isxdigit( int ch );

检查给定的字符是否十六进制数字字符（ 0123456789abcdefABCDEF ）或被分类为十六进制数字字符。

若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为十六进制数字数字则为非零值，否则为零。

注意

isdigit 和 isxdigit 是仅有的不受当前安装的 C 本地环境影响的标准窄字符分类函数。尽管某些实现（例如 Microsoft 在 1252 代码页）可能分类另外的单字节字符为数字。

示例

#include <stdio.h>
#include <ctype.h>
#include <limits.h>

int main(void)
{
    for (int ndx=0; ndx<=UCHAR_MAX; ndx++)
        if (isxdigit(ndx)) printf("%c", ndx);
    printf("\n");
}

输出：

0123456789ABCDEFabcdef

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4.1.12 The isxdigit function (p: 203)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4.1.12 The isxdigit function (p: 184)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.3.1.11 The isxdigit function

参阅

iswxdigit
(C95)
 检查宽字符是否为十六进制字符
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


memccpy

< c‎ | string‎ | byte
定义于头文件 <string.h> |
void *memccpy(void * restrict dest, const void * restrict src, int c, size_t count); | (C23 起)

从 src 所指向的对象复制字符到 dest 所指向的对象，在满足接下来的任何两个条件之一后停止：

  • 复制了 count 个字符
  • 找到（并复制）了字符 (unsigned char)c 。

转译 src 与 dest 对象为 unsigned char 的数组。

若符合任何以下条件则行为未定义：

  • 出现越过 dest 数组结尾的访问
  • 对象重叠（这违反 restrict 契约）
  • dest 或 src 为非法或空指针值

参数

dest | - | 指向要复制的对象的指针
src | - | 指向复制来源对象的指针
c | - | 终止字符，首先转换成 unsigned char
count | - | 要复制的字符数

返回值

若找到字符 (unsigned char)c 则 memccpy 返回 dest 中 (unsigned char)c 后一字符的指针，否则返回空指针。

注解

函数等同于 POSIX memccpy 。

memccpy(dest, src, 0, count) 表现类似 strncpy (dest, src, count) ，除了前者返回指向被写入缓冲区的末尾的指针，并且不会以零填充目标数组。从而 memccpy 对高效连接多个字符串有用。

char bigString[1000];
char* end = bigString + sizeof bigString;

char* p = memccpy(bigString, "John, ", 0, sizeof bigString);
if (p) p = memccpy(p - 1, "Paul, ", 0, end - p);
if (p) p = memccpy(p - 1, "George, ", 0, end - p);
if (p) p = memccpy(p - 1, "Joel ", 0, end - p);

puts(bigString); // John, Paul, George, Joel

示例

#include <ctype.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
    const char src[] = "Stars: Altair, Sun, Vega.";
    const char terminal[] = {':', ' ', ',', '.', '!'};
    char dest[sizeof src];
    const char alt = '@';

    for (size_t i = 0; i != sizeof terminal; ++i) {

        void *to = memccpy(dest, src, terminal[i], sizeof dest);

        printf("Terminal '%c' (%s):\t\"", terminal[i], to ? "found" : "absent");

        // 若找不到 `terminal` 字符 - 打印整个 `dest`
        to = to ? to : dest + sizeof dest;

        for (char *from = dest; from != to; ++from)
            putchar(isprint(*from) ? *from : alt);

        puts("\"");
    }

    puts("\n" "Separate star names from distances (ly):");
    const char *star_distance[] = {
        "Arcturus : 37", "Vega : 25", "Capella : 43", "Rigel : 860", "Procyon : 11"
    };
    char names_only[64];
    char *first = names_only;
    char *last = names_only + sizeof names_only;

    for (size_t t = 0; t != (sizeof star_distance)/(sizeof star_distance[0]); ++t) {
        if (first) {
            first = memccpy(first, star_distance[t], ' ', last - first);
        } else break;
    }
    if (first) {
        *first = '\0';
        puts(names_only);
    } else {
        puts("Buffer is too small.");
    }
}

输出：

Terminal ':' (found):   "Stars:"
Terminal ' ' (found):   "Stars: "
Terminal ',' (found):   "Stars: Altair,"
Terminal '.' (found):   "Stars: Altair, Sun, Vega."
Terminal '!' (absent):  "Stars: Altair, Sun, Vega.@"

Separate star names from distances (ly):
Arcturus Vega Capella Rigel Procyon

参阅

memcpymemcpy_s (C11) | 将一个缓冲区复制到另一个 (函数)
wmemcpywmemcpy_s (C95)(C11) | 在两个不重叠的数组间复制一定数量的宽字符 (函数)
memmovememmove_s (C11) | 将一个缓冲区移动到另一个 (函数)
strcpystrcpy_s (C11) | 复制一个字符串给另一个 (函数)
strcatstrcat_s (C11) | 连接两个字符串 (函数)


memchr

< c‎ | string‎ | byte
定义于头文件 <string.h>
void* memchr( const void* ptr, int ch, size_t count );

在 ptr 所指向对象的首 count 个字符（每个都转译成 unsigned char ）中寻找 ch （在如同以 (unsigned char)ch 转换到 unsigned char 后）的首次出现。

若访问出现于被搜索的数组结尾后，则行为未定义。若 ptr 为空指针则行为未定义。

此函数表现如同它按顺序读取字符，并立即于找到匹配的字符时停止：若 ptr 所指向的字符数组小于 count ，但在数组中找到匹配，则行为良好定义。

 (C11 起)

参数

ptr | - | 指向要检验的对象的指针
ch | - | 要搜索的字符
count | - | 要检验的最大字符数

返回值

指向字符位置的指针，或若找不到该字符则为空指针。

示例

#include <stdio.h>
#include <string.h>

int main(void)
{
    char str[] = "ABCDEFG";
    char *ps = memchr(str,'D',strlen(str));
    if (ps != NULL)
       printf ("search character found:  %s\n", ps);
    else
       printf ("search character not found\n");

    return 0;
}

输出：

search character found:  DEFG

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.5.1 The memchr function (p: 367)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.5.1 The memchr function (p: 330)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.5.1 The memchr function

参阅

strchr
 查找字符的首次出现
(函数)


memcmp

< c‎ | string‎ | byte
定义于头文件 <string.h>
int memcmp( const void* lhs, const void* rhs, size_t count );

比较 lhs 和 rhs 所指向对象的首 count 个字节。比较按字典序进行。

结果的符号是在被比较对象中相异的首对字节的值（都转译成 unsigned char ）的差。

若在 lhs 和 rhs 所指向的任一对象结尾后出现访问，则行为未定义。若 lhs 或 rhs 为空指针则行为未定义。

参数

lhs, rhs | - | 指向要比较的对象的指针
count | - | 要检验的字节数

返回值

若 lhs 以字典序出现前于 rhs 则为负值。

若 lhs 与 rhs 比较相等，或 count 为零则为零。

若 lhs 以字典序出现后于 rhs 则为正值。

注意

此函数读取对象表示，而非对象值，而且典型地只对字节数组有意义：结构体可以含有填充字节而其值不确定，存储于联合体最近存储成员后的任何字节的值是不确定的，且一个类型可以对相同值拥有二种或多种表示（对于 +0 和 -0 或 +0.0 和 –0.0 的相异编码、类型中不确定填充位）。

示例

#include <stdio.h>
#include <string.h>

void demo(const char* lhs, const char* rhs, size_t sz)
{
    for(size_t n = 0; n < sz; ++n)
        putchar(lhs[n]);

    int rc = memcmp(lhs, rhs, sz);
    const char *rel = rc < 0 ? " precedes " : rc > 0 ? " follows " : " compares equal ";
    fputs(rel, stdout);

    for(size_t n = 0; n < sz; ++n)
        putchar(rhs[n]);
    puts(" in lexicographical order");
}

int main(void)
{
    char a1[] = {'a','b','c'};
    char a2[sizeof a1] = {'a','b','d'};

    demo(a1, a2, sizeof a1);
    demo(a2, a1, sizeof a1);
    demo(a1, a1, sizeof a1);
}

输出：

abc precedes abd in lexicographical order
abd follows abc in lexicographical order
abc compares equal to abc in lexicographical order

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.4.1 The memcmp function (p: 365)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.4.1 The memcmp function (p: 328)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.4.1 The memcmp function

参阅

strcmp | 比较两个字符串 (函数)
strncmp | 比较两个字符串的一定数量字符 (函数)


memcpy, memcpy_s

< c‎ | string‎ | byte
定义于头文件 <string.h> |  |
 | (1) |
void* memcpy( void *dest, const void *src, size_t count ); |  |  | (C99 前)
void* memcpy( void *restrict dest, const void *restrict src, size_t count ); |  |  | (C99 起)
errno_t memcpy_s( void *restrict dest, rsize_t destsz, const void *restrict src, rsize_t count ); | (2) | (C11 起)
1) 从 src 所指向的对象复制 count 个字符到 dest 所指向的对象。两个对象都被转译成 unsigned char 的数组。
若访问发生在 dest 数组结尾后则行为未定义。若对象重叠（这违背 restrict 契约） (C99 起)，则行为未定义。若 dest 或 src 为非法或空指针则行为未定义。
2) 同 (1) ，除了错误时导致清零整个目标范围 [dest, dest+destsz) （若 dest 与 destsz 均合法），它在运行时检测下列错误，并调用当前安装的制约处理函数：
  • dest 或 src 为空指针
  • destsz 或 count 大于 RSIZE_MAX
  • count 大于 destsz （会发生缓冲区溢出）
  • 源和目标对象重叠
若 dest 所指向的字符数组大小 < count <= destsz 则行为未定义；换言之，错误的 destsz 值不暴露行将发生的缓冲区溢出。
同所有边界检查函数， memcpy_s 仅若实现定义 __STDC_LIB_EXT1__ 且用户在包含 string.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dest | - | 指向要复制的对象的指针
destsz | - | 目标中要修改的最大字节数（典型地为目标对象的大小）
src | - | 指向复制来源对象的指针
count | - | 复制的字节数

返回值

1) 返回 dest 的副本，本质为更底层操作的临时内存地址，在实际操作中不建议直接使用此地址，操作完成以后，真正有意义的地址是 dest 本身。
2) 成功时返回零，错误时返回非零。在错误时，若 dest 不是空指针且 destsz 合法，则还会写入 destsz 个零字节到目标数组。

注解

memcpy 可用于设置分配函数所获得对象的有效类型。

memcpy 是最快的内存到内存复制子程序。它通常比必须扫描其所复制数据的 strcpy ，或必须预防以处理重叠输入的 memmove 更高效。

许多 C 编译器将适合的内存复制循环变换为 memcpy 调用。

在严格别名使用禁止检验同一内存为二个不同类型的值处，可用 memcpy 转换值。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    // 简单用法
    char source[] = "once upon a midnight dreary...", dest[4];
    memcpy(dest, source, sizeof dest);
    for(size_t n = 0; n < sizeof dest; ++n)
        putchar(dest[n]);

    // 设置分配的内存的有效类型为 int
    int *p = malloc(3*sizeof(int));   // 分配的内存无有效类型
    int arr[3] = {1,2,3};
    memcpy(p,arr,3*sizeof(int));      // 分配的内存现在拥有有效类型

    // reinterpreting data
    double d = 0.1;
//    int64_t n = *(int64_t*)(&d); // 严格别名使用违规
    int64_t n;
    memcpy(&n, &d, sizeof d); // OK
    printf("\n%a is %" PRIx64 " as an int64_t\n", d, n);

#ifdef __STDC_LIB_EXT1__
    set_constraint_handler_s(ignore_handler_s);
    char src[] = "aaaaaaaaaa";
    char dst[] = "xyxyxyxyxy";
    int r = memcpy_s(dst,sizeof dst,src,5);
    printf("dst = \"%s\", r = %d\n", dst,r);
    r = memcpy_s(dst,5,src,10);            // count 大于 destsz
    printf("dst = \"");
    for(size_t ndx=0; ndx<sizeof dst; ++ndx) {
        char c = dst[ndx];
        c ? printf("%c", c) : printf("\\0");
    }
    printf("\", r = %d\n", r);
#endif
}

可能的输出：

once
0x1.999999999999ap-4 is 3fb999999999999a as an int64_t
dst = "aaaaayxyxy", r = 0
dst = "\0\0\0\0\0yxyxy", r = 22

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.2.1 The memcpy function (p: 362)
  • K.3.7.1.1 The memcpy_s function (p: 614)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.2.1 The memcpy function (p: 325)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.2.1 The memcpy function

参阅

memccpy (C23) | 复制一个缓冲区到另一个，在指定的分隔符后停止 (函数)
memmovememmove_s (C11) | 将一个缓冲区移动到另一个 (函数)
wmemcpywmemcpy_s (C95)(C11) | 在两个不重叠的数组间复制一定数量的宽字符 (函数)


memmove, memmove_s

< c‎ | string‎ | byte
定义于头文件 <string.h> |  |
void* memmove( void* dest, const void* src, size_t count ); | (1) |
errno_t memmove_s(void *dest, rsize_t destsz, const void *src, rsize_t count); | (2) | (C11 起)
1) 从 src 所指向的对象复制 count 个字节到 dest 所指向的对象。两个对象都被转译成 unsigned char 的数组。对象可以重叠：如同复制字符到临时数组，再从该数组到 dest 一般发生复制。
若出现 dest 数组末尾后的访问则行为未定义。若 dest 或 src 为非法或空指针则行为未定义。
2) 同 (1) ，除了错误时清零整个范围 [dest, dest+destsz) （若 dest 和 destsz 均合法）。它在运行时检测下列错误，并调用当前安装的制约处理函数：
  • dest 或 src 为空指针
  • destsz 或 count 大于 RSIZE_MAX
  • count 大于 destsz （会出现溢出）
若 dest 所指向的字符数组大小 < count <= destsz 则行为未定义；换言之， destsz 的错误值不暴露行将发生的缓冲区溢出。
同所有边界检查函数， memmove_s 仅若实现定义 __STDC_LIB_EXT1__ 且用户在包含 string.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dest | - | 指向复制目的对象的指针
destsz | - | 要于目标修改的最大字节数（典型地为目的对象的大小）
src | - | 指向复制来源对象的指针
count | - | 要复制的字节数

返回值

1) 返回 dest 的副本，本质为更底层操作的临时内存地址，在实际操作中不建议直接使用此地址，操作完成以后，真正有意义的地址是dest本身。
2) 成功时返回零，失败时返回非零值。在失败时，若 dest 不是空指针且 destsz 合法，则亦会写入 destsz 个零字节到目标数组。

注解

memmove 可用于设置由分配函数获得的对象的有效类型。

尽管说明了“如同”使用临时缓冲区，此函数的实际实现不会带来二次复制或额外内存的开销。常用方法（ glibc 和 bsd libc ）是若目标在源之前开始，则从缓冲区开始正向复制，否则从末尾反向复制，完全无重叠时回落到更高效的 memcpy 。

在严格别名时用禁止检验同一内存为二个不同类型的值时，可使用 memmove 转换值。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    char str[] = "1234567890";
    puts(str);
    memmove(str+4, str+3, 3); // 从 [4,5,6] 复制到 [5,6,7]
    puts(str);

    // 设置分配的内存的有效类型为 int
    int *p = malloc(3*sizeof(int));   // 分配的内存无有效类型
    int arr[3] = {1,2,3};
    memmove(p,arr,3*sizeof(int));     // 分配的内存现在拥有有效类型

    // 转译数据
    double d = 0.1;
//    int64_t n = *(int64_t*)(&d); // 严格别名使用违规
    int64_t n;
    memmove(&n, &d, sizeof d); // OK
    printf("%a is %" PRIx64 " as an int64_t\n", d, n);

#ifdef __STDC_LIB_EXT1__
    set_constraint_handler_s(ignore_handler_s);
    char src[] = "aaaaaaaaaa";
    char dst[] = "xyxyxyxyxy";
    int r = memmove_s(dst,sizeof dst,src,5);
    printf("dst = \"%s\", r = %d\n", dst,r);
    r = memmove_s(dst,5,src,10);            //  count 大于 destsz
    printf("dst = \"");
    for(size_t ndx=0; ndx<sizeof dst; ++ndx) {
        char c = dst[ndx];
        c ? printf("%c", c) : printf("\\0");
    }
    printf("\", r = %d\n", r);
#endif
}

可能的输出：

1234567890
1234456890
0x1.999999999999ap-4 is 3fb999999999999a as an int64_t
dst = "aaaaayxyxy", r = 0
dst = "\0\0\0\0\0yxyxy", r = 22

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.24.2.2 The memmove function (p: 264)
  • K.3.7.1.2 The memmove_s function (p: 446)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.2.2 The memmove function (p: 363)
  • K.3.7.1.2 The memmove_s function (p: 615)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.2.2 The memmove function (p: 326)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.2.2 The memmove function

参阅

memcpymemcpy_s (C11) | 将一个缓冲区复制到另一个 (函数)
wmemmovewmemmove_s (C95)(C11) | 在两个可能重叠的数组间复制一定数量的宽字符 (函数)


memset, memset_s

< c‎ | string‎ | byte
定义于头文件 <string.h> |  |
void *memset( void *dest, int ch, size_t count ); | (1) |
errno_t memset_s( void *dest, rsize_t destsz, int ch, rsize_t count ); | (2) | (C11 起)
1) 复制值 ch （如同以 (unsigned char)ch 转换到 unsigned char 后）到 dest 所指向对象的首 count 个字节。
若出现 dest 数组结尾后的访问则行为未定义。若 dest 为空指针则行为未定义。
2) 同 (1) ，除了若 dest 与 destsz 自身有效，则存储 ch 于目标范围 [dest, dest+destsz) 的每个位置后，在运行时检测下列错误，并调用当前安装的制约处理函数：
  • dest 是空指针
  • destsz 或 count 大于 RSIZE_MAX
  • count 大于 destsz （会发生缓冲区溢出）
若 dest 所指向的字符数组大小 < count <= destsz; 则行为未定义，换言之，错误的 destsz 值不暴露行将发生的缓冲区溢出。
同所有边界检查函数， memset_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 string.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dest | - | 指向要填充的对象的指针
ch | - | 填充字节
count | - | 要填充的字节数
destsz | - | 目标数组的大小

返回值

1) dest 的副本，本质为更底层操作的临时内存地址，在实际操作中不建议直接使用此地址，操作完成以后，真正有意义的地址是dest本身。
2) 成功时为零，失败时为非零。在失败时，若 dest 不是空指针且 destsz 合法，则亦写入 destsz 个填充字节 ch 到目标数组。

注意

若 memset 所修改的对象在其生存期的剩余部分不再被访问，则此函数可以被优化掉（在如同规则下）（例如 gcc 漏洞 8537 ）。为此，此函数不能用于擦洗内存（例如以令填充存储密码的数组）。对 memset_s 禁止此优化：保证进行内存写。该问题的第三方解决方案包含 FreeBSD explicit_bzero 或 Microsoft SecureZeroMemory 。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    char str[] = "ghghghghghghghghghghgh";
    puts(str);
    memset(str,'a',5);
    puts(str);

#ifdef __STDC_LIB_EXT1__
    set_constraint_handler_s(ignore_handler_s);
    int r = memset_s(str, sizeof str, 'b', 5);
    printf("str = \"%s\", r = %d\n", str, r);
    r = memset_s(str, 5, 'c', 10);   // count 大于 destsz
    printf("str = \"%s\", r = %d\n", str, r);
#endif
}

可能的输出：

ghghghghghghghghghghgh
aaaaahghghghghghghghgh
str = "bbbbbhghghghghghghghgh", r = 0
str = "ccccchghghghghghghghgh", r = 22

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.6.1 The memset function (p: 371)
  • K.3.7.4.1 The memset_s function (p: 621-622)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.6.1 The memset function (p: 333)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.6.1 The memset function

参阅

memcpymemcpy_s (C11) | 将一个缓冲区复制到另一个 (函数)
wmemset (C95) | 将给定的宽字符复制到宽字符数组的所有位置 (函数)


strcat, strcat_s

< c‎ | string‎ | byte
定义于头文件 <string.h> |  |
 | (1) |
char *strcat( char *dest, const char *src ); |  |  | (C99 前)
char *strcat( char *restrict dest, const char *restrict src ); |  |  | (C99 起)
errno_t strcat_s(char *restrict dest, rsize_t destsz, const char *restrict src); | (2) | (C11 起)
1) 后附 src 所指向的空终止字节字符串的副本到 dest 所指向的空终止字节字符串的结尾。字符 src[0] 替换 dest 末尾的空终止符。产生的字节字符串是空终止的。
若目标数组对于 src 和 dest 的内容以及空终止符不够大，则行为未定义。若字符串重叠，则行为未定义。若 dest 或 src 不是指向空终止字节字符串的指针，则行为未定义。
2) 同 (1) ，除了它可用未指定值破坏目标数组的剩余部分（从最后写入字符到 destsz ），以及在运行时检测下列错误，并调用当前安装的制约处理函数：
  • src 或 dest 为空指针
  • destsz 为零或大于 RSIZE_MAX
  • dest 的首 destsz 个字节中无空终止符
  • 会出现截断（ dest 末尾的可用空间不能适应 src 的每个字符，包括空终止符）
  • 源与目标字符串间会出现重叠
若 dest 所指向的字符数组大小 < strlen (dest)+ strlen (src)+1 <= destsz 则行为未定义；换言之， destsz 的错误值不暴露行将发生的缓冲区溢出。
同所有边界检查函数， strcat_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 string.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dest | - | 指向要后附到的空终止字节字符串的指针
src | - | 指向作为复制来源的空终止字节字符串的指针
destsz | - | 要写入的最大字符数，典型地为目标缓冲区的大小

返回值

1) 返回 dest 的副本。
2) 成功时返回零。错误时返回非零。错误时，亦写入零到 dest[0] （除非 dest 为空指针，或 destsz 为零或大于 RSIZE_MAX ）。

注解

因为 strcat 需要在每次调用时找到 dest 的结尾，故用 strcat 将多个字符串连接成一体是低效的。

为提升效率，允许 strcat_s 从最后被写入字符到 destsz 破坏目标数组：它可以用多字节块复制，然后检查空字节。

函数 strcat_s 类似 BSD 函数 strlcat ，除了

  • strlcat 截断源字符串以适合目标
  • strlcat 不进行所有 strcat_s 进行的运行时检查
  • 若调用失败，则 strlcat 不设置目标为空字符串或调用处理函数，而令失败显著。

尽管 strcat_s 由于潜在安全风险禁止截断，还可以用带边界检查的 strncat_s 截断字符串。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char str[50] = "Hello ";
    char str2[50] = "World!";
    strcat(str, str2);
    strcat(str, " ...");
    strcat(str, " Goodbye World!");
    puts(str);

#ifdef __STDC_LIB_EXT1__
    set_constraint_handler_s(ignore_handler_s);
    int r = strcat_s(str, sizeof str, " ... ");
    printf("str = \"%s\", r = %d\n", str, r);
    r = strcat_s(str, sizeof str, " and this is too much");
    printf("str = \"%s\", r = %d\n", str, r);
#endif
}

可能的输出：

Hello World! ... Goodbye World!
str = "Hello World! ... Goodbye World! ... ", r = 0
str = "", r = 22

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.3.1 The strcat function (p: 364)
  • K.3.7.2.1 The strcat_s function (p: 617-618)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.3.1 The strcat function (p: 327)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.3.1 The strcat function

参阅

strncatstrncat_s (C11) | 连接两个字符串的一定数量字符 (函数)
strcpystrcpy_s (C11) | 复制一个字符串给另一个 (函数)


strchr

< c‎ | string‎ | byte
定义于头文件 <string.h>
char *strchr( const char *str, int ch );

寻找 ch （如同用 (char)ch 转换成 char 后）在 str 所指向的空终止字节字符串（转译每个字符为 unsigned char ）中的首次出现位置。终止空字符被认为是字符串的一部分，并且能在寻找 '\0' 时找到。

若 str 不是指向空终止字节字符串的指针，则行为未定义。

参数

str | - | 指向待分析的空终止字节字符串的指针
ch | - | 要搜索的字符

返回值

指向 str 找到的字符的指针，若未找到该字符则为空指针。

示例

#include <stdio.h>
#include <string.h>

int main(void)
{
  const char *str = "Try not. Do, or do not. There is no try.";
  char target = 'T';
  const char *result = str;

  while((result = strchr(result, target)) != NULL) {
    printf("Found '%c' starting at '%s'\n", target, result);
    ++result; // result 自增，否则我们会找到相同位置的目标
  }
}

输出：

Found 'T' starting at 'Try not. Do, or do not. There is no try.'
Found 'T' starting at 'There is no try.'

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.5.2 The strchr function (p: 367-368)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.5.2 The strchr function (p: 330)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.5.2 The strchr function

参阅

memchr | 在数组中搜索字符的首次出现 (函数)
strrchr | 查找字符的最后一次出现 (函数)
strpbrk | 查找一个字符串中的任意一个字符在另一个字符串中的首个位置 (函数)


strcmp

< c‎ | string‎ | byte
定义于头文件 <string.h>
int strcmp( const char *lhs, const char *rhs );

以字典序比较二个空终止字节字符串。

结果的符号是被比较的字符串中首对不同字符（都转译成 unsigned char ）的值间的差的符号。

若 lhs 或 rhs 不是指向空终止字节字符串的指针，则行为未定义。

参数

lhs, rhs - 指向要比较的空终止字节字符串的指针

返回值

若字典序中 lhs 先出现于 rhs 则为负值。

若 lhs 与 rhs 比较相等则为零。

若字典序中 lhs 后出现于 rhs 则为正值。

注意

不同于 strcoll 和 strxfrm ，此函数不考虑本地环境。

示例

#include <string.h>
#include <stdio.h>

void demo(const char* lhs, const char* rhs)
{
    int rc = strcmp(lhs, rhs);
    const char *rel = rc < 0 ? "precedes" : rc > 0 ? "follows" : "equals";
    printf("[%s] %s [%s]\n", lhs, rel, rhs);
}

int main(void)
{
    const char* string = "Hello World!";
    demo(string, "Hello!");
    demo(string, "Hello");
    demo(string, "Hello there");
    demo("Hello, everybody!" + 12, "Hello, somebody!" + 11);
}

输出：

[Hello World!] precedes [Hello!]
[Hello World!] follows [Hello]
[Hello World!] precedes [Hello there]
[body!] equals [body!]

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.4.2 The strcmp function (p: 365-366)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.4.2 The strcmp function (p: 328-329)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.4.2 The strcmp function

参阅

strncmp | 比较两个字符串的一定数量字符 (函数)
wcscmp (C95) | 比较两个宽字符串 (函数)
memcmp | 比较两块缓冲区 (函数)
strcoll | 比较两个字符串，根据当前本地环境 (函数)


strcoll

< c‎ | string‎ | byte
定义于头文件 <string.h>
int strcoll( const char *lhs, const char *rhs );

按照 LC_COLLATE 类别所定义的当前本地环境，比较二个空终止字节字符串。

参数

lhs, rhs - 指向要比较的空终止字节字符串的指针

返回值

若 lhs 小于（前趋） rhs 则为负值。

若 lhs 等于 rhs 则为 ​0​ 。

若 lhs 大于（后随） rhs 则为负值。

注意

对照顺序为字典顺序：国家字母表（其等价类）中字母的位置拥有高于其大小写或变体的优先级。在等价类内，小写字符先于其大写等价物对照，而且本地环境限定的顺序可能应用到有发音符号的字符。一些本地环境中，字符组作为单个对照单元比较。例如， "ch" 在捷克语中后随 "h" 而前趋 "i" ， "dzs" 在匈牙利语中后随 "dz" 而前趋 "g" 。

示例

#include <stdio.h>
#include <string.h>
#include <locale.h>

int main(void)
{
    setlocale(LC_COLLATE, "cs_CZ.iso88592");

    const char* s1 = "hrnec";
    const char* s2 = "chrt";

    printf("In the Czech locale: ");
    if(strcoll(s1, s2) < 0)
         printf("%s before %s\n", s1, s2);
    else
         printf("%s before %s\n", s2, s1);

    printf("In lexicographical comparison: ");
    if(strcmp(s1, s2) < 0)
         printf("%s before %s\n", s1, s2);
    else
         printf("%s before %s\n", s2, s1);
}

输出：

In the Czech locale: hrnec before chrt
In lexicographical comparison: chrt before hrnec

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.4.3 The strcoll function (p: 366)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.4.3 The strcoll function (p: 329)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.4.3 The strcoll function

参阅

wcscoll (C95) | 根据当前本地环境比较两个宽字符串 (函数)
strxfrm | 变换字符串，使得 strcmp 会产生同 strcoll 的结果 (函数)
wcsxfrm (C95) | 变换宽字符串，使得 wcscmp 会产生与 wcscoll 相同的结果 (函数)
strcmp | 比较两个字符串 (函数)


strcpy, strcpy_s

< c‎ | string‎ | byte
定义于头文件 <string.h> |  |
 | (1) |
char *strcpy( char *dest, const char *src ); |  |  | (C99 前)
char *strcpy( char *restrict dest, const char *restrict src ); |  |  | (C99 起)
errno_t strcpy_s(char *restrict dest, rsize_t destsz, const char *restrict src); | (2) | (C11 起)
1) 复制 src 所指向的空终止字节字符串，包含空终止符，到首元素为 dest 所指的字符数组。
若 dest 数组长度不足则行为未定义。若字符串覆盖则行为未定义。若 dest 不是指向字符数组的指针或 src 不是指向空终止字节字符串的指针则行为未定义。
2) 同 (1) ，除了它可能以未指定值破坏目标数组的剩余部分，而且会在运行时检测下列错误，并调用当前安装的制约处理函数：
  • src 或 dest 为空指针
  • destsz 为零或大于 RSIZE_MAX
  • destsz 小于或等于 strnlen_s(src, destsz) ；换言之，会发生截断
  • 源与目标字符串间会发生重叠
若 dest 所指的字符数组大小 <= strnlen_s(src, destsz) < destsz 则行为未定义；换言之， destsz 的错误值不暴露行将发生的缓冲区溢出。
同所有边界检查函数， strcpy_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <string.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dest | - | 指向要写入的字符数组的指针
src | - | 指向要复制的空终止字节字符串的指针
destsz | - | 写入的最大字符数，典型地为目标缓冲区的大小

返回值

1) 返回 dest 的副本
2) 成功时返回零，失败时返回非零。而且失败时向 dest[0] 写入零（除非 dest 是空指针或 destsz 为零或大于 RSIZE_MAX ）。

注意

为提升效率，允许 strcpy_s 破坏至多 destsz 个目标数组上次写入的字符：它可能先复制多字节块再检查空字节。

函数 strcpy_s 类似 BSD 函数 strlcpy ，除了

  • strlcpy 截断源字符串以适应目标（这有安全风险）
  • strlcpy 不全部进行 strcpy_s 所进行的运行时检查
  • strlcpy 不会通过设置目标为空字符串或调用处理函数，以令失败显著。

尽管 strcpy_s 因潜在的安全风险禁止截断，也还可以用使用边界检查的 strncpy_s 替而进行截断字符串。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char *src = "Take the test.";
//  src[0] = 'M' ; // 这会是未定义行为
    char dst[strlen(src) + 1]; // +1 以适应空终止符
    strcpy(dst, src);
    dst[0] = 'M'; // OK
    printf("src = %s\ndst = %s\n", src, dst);

#ifdef __STDC_LIB_EXT1__
    set_constraint_handler_s(ignore_handler_s);
    int r = strcpy_s(dst, sizeof dst, src);
    printf("dst = \"%s\", r = %d\n", dst, r);
    r = strcpy_s(dst, sizeof dst, "Take even more tests.");
    printf("dst = \"%s\", r = %d\n", dst, r);
#endif
}

可能的输出：

src = Take the test.
dst = Make the test.
dst = "Take the test.", r = 0
dst = "", r = 22

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.2.3 The strcpy function (p: 363)
  • K.3.7.1.3 The strcpy_s function (p: 615-616)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.2.3 The strcpy function (p: 326)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.2.3 The strcpy function

参阅

strncpystrncpy_s (C11) | 从一个字符串复制一定数量的字符到另一个 (函数)
memcpymemcpy_s (C11) | 将一个缓冲区复制到另一个 (函数)
wcscpywcscpy_s (C95)(C11) | 将一个宽字符串复制给另一个 (函数)
strdup (动态内存 TR) | 分配字符串的副本 (函数)


strcspn

< c‎ | string‎ | byte
定义于头文件 <string.h>
size_t strcspn( const char *dest, const char *src );

返回 dest 所指向的空终止字节字符串的最大起始段长度，该段只由 src 所指向的空终止字节字符串中找不到的字符组成。

若 dest 或 src 不是指向空终止字节字符串的指针，则行为未定义。

参数

dest | - | 指向要分析的空终止字节字符串的指针
src | - | 指向含有要搜索字符的空终止字节字符串的指针

返回值

仅由 src 所指向的空终止字节字符串中找不到的字符组成的最大起始段长度。

注意

函数名代表“补集段 (complementary span) ”，因为函数搜索 src 中找不到的字符，即 src 的补集。

示例

#include <string.h>
#include <stdio.h>

int main(void)
{
    const char *string = "abcde312$#@";
    const char *invalid = "*$#";

    size_t valid_len = strcspn(string, invalid);
    if(valid_len != strlen(string))
       printf("'%s' contains invalid chars starting at position %zu\n",
               string, valid_len);
}

输出：

'abcde312$#@' contains invalid chars starting at position 8

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.5.3 The strcspn function (p: 368)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.5.3 The strcspn function (p: 331)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.5.3 The strcspn function

参阅

strspn | 返回由另一个字符串中的字符分割的最大起始段长度 (函数)
wcscspn (C95) | 返回仅由不出现于另一个宽字符串中的宽字符分隔的最长首段长度 (函数)
strpbrk | 查找一个字符串中的任意一个字符在另一个字符串中的首个位置 (函数)


strdup

< c‎ | string‎ | byte
定义于头文件 <string.h> |
char *strdup( const char *src ); | (C23 起)

返回指向作为 src 所指向的字符串的副本的空终止字节字符串的指针。如同通过调用 malloc 获得新字符串的空间。必须将返回的指针传递给 free 以避免内存泄漏。

若出现错误，则返回空指针值并可能设置 errno 。

参数

src - 指向要复制的空终止字节字符串的指针

返回值

指向新分配的字符串的指针，或若出现错误则为空指针值。

注解

该函数等同于 POSIX strdup 。

示例

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    const char *s1 = "Duplicate me!";
    char *s2 = strdup(s1);
    printf("s2 = \"%s\"\n", s2);
    free(s2);
}

输出：

s2 = "Duplicate me!"

参阅

strndup (C23) | 分配拥有指定大小的字符串副本 (函数)
strcpystrcpy_s (C11) | 复制一个字符串给另一个 (函数)
malloc | 分配内存 (函数)
free | 归还之前分配的内存 (函数)


strerror, strerror_s, strerrorlen_s

< c‎ | string‎ | byte
定义于头文件 <string.h> |  |
char* strerror( int errnum ); | (1) |
errno_t strerror_s( char *buf, rsize_t bufsz, errno_t errnum ); | (2) | (C11 起)
size_t strerrorlen_s( errno_t errnum ); | (3) | (C11 起)
1) 返回指向系统错误码 errnum 的文本表示的指针，它等同于 perror() 会打印的描述。
errnum 通常获得自 errno 对象，不过函数接受任何 int 类型值。字符串的内容是本地环境限定的。
程序必须不修改返回的字符串，但对 strerror 函数的后继调用可能重写该字符串。不要求 strerror 为线程安全。实现可以返回指向静态只读字符串字面量的不同指针，或反复返回指向静态缓冲区的同一指针， strerror 放置字符串于该缓冲区中。
2) 同 (1) ，除了将消息复制到用户提供的存储 buf 中。不写入多于 bufsz-1 个字符，缓冲区始终为空终止的。若消息必须被截断，且 bufsz 大于 3 ，则只写入 bufsz-4 个字符，并在空终止符前前附字符 "..." 。另外，在运行时检测下列错误，并调用当前安装的制约处理函数：
  • buf 为空指针
  • bufsz 为零或大于 RSIZE_MAX
若到 buf 的写入出现在数组末尾后则行为未定义，这在 buf 所指向的缓冲区大小写小于错误消息的字符数，且小于 bufsz 时发生。
3) 计算若以 errnum 调用则 strerror_s 本会写入的，本地环境限定错误消息的不截断长度。长度不包含空终止符。
同所有边界检查函数， strerror_s, strerrorlen_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 string.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

errnum | - | 指代错误码的整数值
buf | - | 指向用户提供的缓冲区的指针
bufsz | - | 用户提供的缓冲区的大小

返回值

1) 指向对应 errno 错误码 errnum 的空终止字节串的指针。
2) 若整个消息完整存储于 buf 则为零，否则为非零。
3) strerror_s 会返回的消息长度（不包含空终止符）

注意

POSIX 允许对 strerror 的后继调用非法化先前调用所返回的指针值。它亦指定控制这些消息的 LC_MESSAGES 本地环境平面。

strerror_s 是仅有的允许截断的带边界检查函数，因为提供尽可能多的关于失败的信息被视为更加令人满意。 POSIX 亦为类似目的定义 strerror_r 。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <locale.h>

int main(void)
{
    FILE *fp = fopen(tmpnam((char[L_tmpnam]){0}), "r");
    if(fp==NULL) {
        printf("File opening error: %s\n", strerror(errno));
        setlocale(LC_MESSAGES, "de_DE.utf8");
        printf("Now in German: %s\n", strerror(errno));
#ifdef __STDC_LIB_EXT1__
        setlocale(LC_ALL, "zh_CN.utf8"); // printf 需要多字节输出的 CTYPE
        size_t errmsglen = strerrorlen_s(errno) + 1;
        char errmsg[errmsglen];
        strerror_s(errmsg, errmsglen, errno);
        printf("Now in Chinese: %s\n", errmsg);
#endif
    }
}

可能的输出：

File opening error: No such file or directory
Now in German: Datei oder Verzeichnis nicht gefunden
Now in Chinese: 没有那个文件或目录

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.6.2 The strerror function (p: 371)
  • K.3.7.4.2 The strerror_s function (p: 622)
  • K.3.7.4.3 The strerrorlen_s function (p: 623)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.6.2 The strerror function (p: 334)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.6.2 The strerror function

参阅

perror | 显示对应当前错误的字符串到 stderr (函数)
errno | 展开成 POSIX 兼容的线程局域错误编号变量 (宏变量)


strlen, strnlen_s

< c‎ | string‎ | byte
定义于头文件 <string.h> |  |
size_t strlen( const char *str ); | (1) |
size_t strnlen_s( const char *str, size_t strsz ); | (2) | (C11 起)
1) 返回给定空终止字符串的长度，即首元素为 str 所指，且不包含首个空字符的字符数组中的字符数。
若 str 不是指向空终止字节字符串的指针则行为未定义。
2) 同 (1) ，除了若 str 为空指针则返回零，而若在 str 的首 strsz 个字节找不到空字符则返回 strsz 。
若 str 指向缺少空字符的字符数组且该字符数组的大小 < strsz 则行为未定义；换言之， strsz 的错误值不会暴露行将来临的缓冲区溢出。
同所有边界检查函数， strnlen_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <string.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。。

参数

str | - | 指向要检测的空终止字符串的指针
strsz | - | 要检测的最大字符数量

返回值

1) 空终止字节字符串 str 的长度。
2) 成功时为空终止字节字符串 str 的长度，若 str 是空指针则为零，若找不到空字符则为 strsz 。

注意

strnlen_s 与 wcsnlen_s 是仅有的不调用运行时制约处理的边界检查函数。它们是用于提供空终止字符串受限制支持的纯功能函数。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#include <stdio.h>

int main(void)
{
    const char str[] = "How many characters does this string contain?";

    printf("without null character: %zu\n", strlen(str));
    printf("with null character:    %zu\n", sizeof str);

#ifdef __STDC_LIB_EXT1__
    printf("without null character: %zu\n", strnlen_s(str, sizeof str));
#endif
}

输出：

without null character: 45
with null character:    46
without null character: 45

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.6.3 The strlen function (p: 372)
  • K.3.7.4.4 The strnlen_s function (p: 623)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.6.3 The strlen function (p: 334)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.6.3 The strlen function

参阅

wcslenwcsnlen_s (C95)(C11) | 返回宽字符串的长度 (函数)
mblen | 返回下一个多字节字符的字节数 (函数)


strncat, strncat_s

< c‎ | string‎ | byte
定义于头文件 <string.h> |  |
 | (1) |
char *strncat( char *dest, const char *src, size_t count ); |  |  | (C99 前)
char *strncat( char *restrict dest, const char *restrict src, size_t count ); |  |  | (C99 起)
errno_t strncat_s(char *restrict dest, rsize_t destsz, const char *restrict src, rsize_t count); | (2) | (C11 起)
1) 后附来自 src 所指向的字符数组的至多 count 个字符，到 dest 所指向的空终止字节字符串的末尾，若找到空字符则停止。字符 src[0] 替换位于 dest 末尾的空终止符。始终后附终止空字符到末尾（故函数可写入的最大字节数是 count+1 ）。
若目标数组没有对于 dest 和 src 的首 count 个字符加上终止空字符的足够空间，则行为未定义。若源与目标对象重叠，则行为未定义。若 dest 不是指向空终止字节字符串的指针，或 src 不是指向字符数组的指针，则行为未定义。
2) 同 (1) ，除了函数可以可用未指定值破坏目标数组的剩余部分（从最后写入字符到 destsz ），以及在运行时检测下列错误，并调用当前安装的制约处理函数：
  • src 或 dest 为空指针
  • destsz 或 count 为零或大于 RSIZE_MAX
  • dest 的首 destsz 个字节中无空字符
  • 会出现截断： count 与 src 长度的较小者，会超出 dest 的空终止符和 destsz 之间的可用空间。
  • 源与目标字符串之间会出现重叠
若 dest 所指向的字符数组大小 < strnlen(dest,destsz)+strnlen(src,count)+1 < destsz 则行为未定义；换言之， destsz 的错误值不暴露行将发生的缓冲区溢出。若 src 所指向的字符数组大小 < strnlen(src,count) < destsz ；换言之， count 的错误值不暴露行将发生的缓冲区溢出。
同所有边界检查函数， strncat_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 string.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dest | - | 指向要后附到的空终止字节字符串的指针
src | - | 指向作为复制来源的字符数组的指针
count | - | 要复制的最大字符数
destsz | - | 目标缓冲区的大小

返回值

1) 返回 dest 的副本。
2) 成功时返回零。错误时返回非零。错误时，亦写入零到 dest[0] （除非 dest 为空指针，或 destsz 为零或大于 RSIZE_MAX ）。

注解

因为 strncat 需要在每次调用时找到 dest 的结尾，故用 strncat 将多个字符串连接成一体是低效的。

尽管截断以适应目标缓冲区是安全风险，从而是 strncat_s 的运行时制约违规，还是可以通过指定 count 等于目标数组大小减一获取截断行为：这将一如往常地复制首 count 个字节并后附空终止符： strncat_s(dst, sizeof dst, src, (sizeof dst)-strnlen_s(dst, sizeof dst)-1); 。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char str[50] = "Hello ";
    char str2[50] = "World!";
    strcat(str, str2);
    strncat(str, " Goodbye World!", 3);
    puts(str);

#ifdef __STDC_LIB_EXT1__
    set_constraint_handler_s(ignore_handler_s);
    char s1[100] = "good";
    char s5[1000] = "bye";
    int r1 = strncat_s(s1, 100, s5, 1000); // r1 为 0 ， s1 保有 "goodbye\0"
    printf("s1 = %s, r1 = %d\n", s1, r1);
    char s2[6] = "hello";
    int r2 = strncat_s(s2, 6, "", 1); // r2 为 0 ， s2 保有 "hello\0"
    printf("s2 = %s, r2 = %d\n", s2, r2);
    char s3[6] = "hello";
    int r3 = strncat_s(s3, 6, "X", 2); // r3 非零， s3 保有 "\0"
    printf("s3 = %s, r3 = %d\n", s3, r3);
    // the strncat_s truncation idiom:
    char s4[7] = "abc";
    int r4 = strncat_s(s4, 7, "defghijklmn", 3); // r 为 0 ， s4 保有 "abcdef\0"
    printf("s4 = %s, r4 = %d\n", s4, r4);
#endif
}

可能的输出：

Hello World! Go
s1 = goodbye, r1 = 0
s2 = hello, r2 = 0
s3 = , r3 = 22
s4 = abcdef, r4 = 0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.3.2 The strncat function (p: 364-365)
  • K.3.7.2.2 The strncat_s function (p: 618-620)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.3.2 The strncat function (p: 327-328)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.3.2 The strncat function

参阅

strcatstrcat_s (C11) | 连接两个字符串 (函数)
strcpystrcpy_s (C11) | 复制一个字符串给另一个 (函数)


strncmp

< c‎ | string‎ | byte
定义于头文件 <string.h>
int strncmp( const char *lhs, const char *rhs, size_t count );

比较二个可能空终止的数组的至多 count 个字符。按字典序进行比较。不比较后随空字符的字符。

结果的符号是被比较的数组中首对字符（都转译成 unsigned char ）的值间的差的符号。

若出现越过 lhs 或 rhs 结尾的访问，则行为未定义。若 lhs 或 rhs 为空指针，则行为未定义。

参数

lhs, rhs | - | 指向要比较的可能空终止的数组的指针
count | - | 要比较的最大字符数

返回值

若字典序中 lhs 先出现于 rhs 则为负值。

若 lhs 与 rhs 比较相等，或若 count 为零，则为零。

若字典序中 lhs 后出现于 rhs 则为正值。

注解

不同于 strcoll 和 strxfrm ，此函数不考虑本地环境。

示例

#include <string.h>
#include <stdio.h>

void demo(const char* lhs, const char* rhs, int sz)
{
    int rc = strncmp(lhs, rhs, sz);
    if(rc == 0)
        printf("First %d chars of [%s] equal [%s]\n", sz, lhs, rhs);
    else if(rc < 0)
        printf("First %d chars of [%s] precede [%s]\n", sz, lhs, rhs);
    else if(rc > 0)
        printf("First %d chars of [%s] follow [%s]\n", sz, lhs, rhs);

}
int main(void)
{
    const char* string = "Hello World!";
    demo(string, "Hello!", 5);
    demo(string, "Hello", 10);
    demo(string, "Hello there", 10);
    demo("Hello, everybody!" + 12, "Hello, somebody!" + 11, 5);
}

输出：

First 5 chars of [Hello World!] equal [Hello!]
First 10 chars of [Hello World!] follow [Hello]
First 10 chars of [Hello World!] precede [Hello there]
First 5 chars of [body!] equal [body!]

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.4.4 The strncmp function (p: 366)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.4.4 The strncmp function (p: 329)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.4.4 The strncmp function

参阅

strcmp | 比较两个字符串 (函数)
wcsncmp (C95) | 比较来自两个宽字符串的一定量字符 (函数)
memcmp | 比较两块缓冲区 (函数)
strcoll | 比较两个字符串，根据当前本地环境 (函数)


strncpy, strncpy_s

< c‎ | string‎ | byte
定义于头文件 <string.h> |  |
 | (1) |
char *strncpy( char *dest, const char *src, size_t count ); |  |  | (C99 前)
char *strncpy( char *restrict dest, const char *restrict src, size_t count ); |  |  | (C99 起)
errno_t strncpy_s(char *restrict dest, rsize_t destsz, const char *restrict src, rsize_t count); | (2) | (C11 起)
1) 复制 src 所指向的字符数组的至多 count 个字符（包含空终止字符，但不包含后随空字符的任何字符）到 dest 所指向的字符数组。
若在完全复制整个 src 数组前抵达 count ，则结果的字符数组不是空终止的。
若在复制来自 src 的空终止字符后未抵达 count ，则写入额外的空字符到 dest ，直至写入总共 count 个字符。
若字符数组重叠，若 dest 或 src 不是指向字符数组的指针（包含若 dest 或 src 为空指针），若 dest 所指向的数组大小小于 count ，或若 src 所指向的数组大小小于 count 且它不含空字符，则行为未定义。
2) 同 (1) ，除了函数不持续写入零到目标数组以填满 count ，它在写入空终止字符后停止（若源中无空字符，则它于 dest[count] 写入一个然后停止）。并且在运行时检测下列错误并调用当前安装的制约处理函数：
  • src 或 dest 是空指针
  • destsz 零或大于 RSIZE_MAX
  • count 大于 RSIZE_MAX
  • count 大于或等于 destsz ，但 destsz 小于或等于 strnlen_s(src, count) ，换言之，会出现截断
  • 源和目标字符串间会出现重叠
若 dest 所指的字符数组大小 < strnlen_s(src, destsz) <= destsz 则行为未定义；换言之，错误的 destsz 值不暴露行将发生的缓冲区溢出。若 src 所指的字符数组大小 < strnlen_s(src, count) < destsz 则行为未定义；换言之，错误的 count 值不暴露行将发生的缓冲区溢出。
同所有边界检查函数， strncpy_s 仅若实现定义 __STDC_LIB_EXT1__ 且用户在包含 string.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dest | - | 指向要复制到的字符数组的指针
src | - | 指向复制来源的字符数组的指针
count | - | 要复制的最大字符数
destsz | - | 目标缓冲区的大小

返回值

1) 返回 dest 的副本
2) 成功时返回零，错误时返回非零。而且，在错误时写入零到 dest[0] （除非 dest 为空指针，或 destsz 为零或大于 RSIZE_MAX ），而且可能以未指定值破坏目标数组的剩余部分。

注解

按 C11 后的 DR 468 更正， strncpy_s 不同于 strcpy_s ，仅若错误发生才被允许破坏目标数组的剩余部分。

不同于 strncpy ， strncpy_s 不以零填充目标数组。这是转换既存代码到边界检查版本的常见错误源。

尽管适合目标缓冲区的截断是安全风险，从而是 strncpy_s 的运行时制约违规，还是可通过指定 count 等于目标数组大小减一以获取截断行为：它会复制首 count 个字节，并照常添加空终止符： strncpy_s(dst, sizeof dst, src, (sizeof dst)-1);

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char src[] = "hi";
    char dest[6] = "abcdef"; // 无空字符
    strncpy(dest, src, 5); // 写入五个字符 'h', 'i', '\0', '\0', '\0' 到 dest
    printf("strncpy(dest, src, 5) to a 6-byte dest gives : ");
    for(size_t n = 0; n < sizeof dest; ++n) {
        char c = dest[n];
        c ? printf("'%c' ", c) : printf("'\\0' ");
    }

    printf("\nstrncpy(dest2, src, 2) to a 2-byte dst gives : ");
    char dest2[2];
    strncpy(dest2, src, 2); // 截断：写入二个字符 'h', 'i', 到 dest2
    for (size_t n = 0; n < sizeof dest2; ++n) {
        char c = dest2[n];
        c ? printf("'%c' ", c) : printf("'\\0' ");
    }
    printf("\n");

#ifdef __STDC_LIB_EXT1__
    set_constraint_handler_s(ignore_handler_s);
    char dst1[6], src1[100] = "hello";
    int r1 = strncpy_s(dst1, 6, src1, 100);      // 写入 0 到 r1 ， 6 个字符到 dst1
    printf("dst1 = \"%s\", r1 = %d\n", dst1,r1); // 'h','e','l','l','o','\0' 到 dst1

    char dst2[5], src2[7] = {'g','o','o','d','b','y','e'};
    int r2 = strncpy_s(dst2, 5, src2, 7);        // 复制溢出目标数组
    printf("dst2 = \"%s\", r2 = %d\n", dst2,r2); // 写入非零到 r2 ， '\0' 到 dst2[0]

    char dst3[5];
    int r3 = strncpy_s(dst3, 5, src2, 4);        // 写入 0 到 r3 ， 5 个字符到 dst3
    printf("dst3 = \"%s\", r3 = %d\n", dst3,r3); // 'g', 'o', 'o', 'd', '\0' 到 dst3
#endif
}

可能的输出：

strncpy(dest, src, 5) to a 6-byte dst gives : 'h' 'i' '\0' '\0' '\0' 'f'
strncpy(dest2, src, 2) to a 2-byte dst gives : 'h' 'i'
dst1 = "hello", r1 = 0
dst2 = "", r2 = 22
dst3 = "good", r3 = 0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.2.4 The strncpy function (p: 363-364)
  • K.3.7.1.4 The strncpy_s function (p: 616-617)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.2.4 The strncpy function (p: 326-327)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.2.4 The strncpy function

参阅

strcpystrcpy_s (C11) | 复制一个字符串给另一个 (函数)
memcpymemcpy_s (C11) | 将一个缓冲区复制到另一个 (函数)
strndup (动态内存 TR) | 分配字符串副本，至多到指定的大小 (函数)


strndup

< c‎ | string‎ | byte
定义于头文件 <string.h> |
char *strndup( const char *src, size_t size ); | (C23 起)

返回指向含有来自 src 所指向的字符串的至多 size 个字节的副本的空终止字节字符串的指针。如同通过调用 malloc 获得新字符串的空间。若在首 size 个字节中未遇到空终止符，则将它后附到复制的字符串。

必须将返回的指针传递给 free 以避免内存泄漏。

若出现错误，则返回空指针值并可能设置 errno 。

参数

src | - | 指向要复制的空终止字节字符串的指针
size | - | 要从 src 复制的最大字节数

返回值

指向新分配的字符串的指针，或若出现错误则为空指针值。

注解

函数等同于 POSIX strndup ，除了允许但不要求它在错误时设置 errno 。

示例

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    const size_t n = 3;

    const char *src = "Replica";
    char *dup = strndup(src, n);
    printf("strndup(\"%s\", %lu) == \"%s\"\n", src, n, dup);
    free(dup);

    src = "Hi";
    dup = strndup(src, n);
    printf("strndup(\"%s\", %lu) == \"%s\"\n", src, n, dup);
    free(dup);

    const char arr[] = {'A','B','C','D'}; // NB ：无尾随 '\0'
    dup = strndup(arr, n);
    printf("strndup({'A','B','C','D'}, %lu) == \"%s\"\n", n, dup);
    free(dup);
}

输出：

strndup("Replica", 3) == "Rep"
strndup("Hi", 3) == "Hi"
strndup({'A','B','C','D'}, 3) == "ABC"

参阅

strdup (C23) | 分配字符串的副本 (函数)
strcpystrcpy_s (C11) | 复制一个字符串给另一个 (函数)
malloc | 分配内存 (函数)
free | 归还之前分配的内存 (函数)


strpbrk

< c‎ | string‎ | byte
定义于头文件 <string.h>
char* strpbrk( const char* dest, const char* breakset );

在 dest 所指向的空终止字节串中，扫描来自 breakset 所指向的空终止字节串的任何字符，并返回指向该字符的指针。

若 dest 或 breakset 不是指向空终止字节字符串的指针则行为未定义。

参数

dest | - | 指向要分析的空终止字节字符串的指针
breakset | - | 指向含要搜索的字符的空终止字节字符串的指针

返回值

指向 dest 中首个亦在 breakset 中的字符的指针，或若这种字符不存在则为空指针。

注意

名称代表“字符串指针打断 (string pointer break) ”，因为它返回指向首个分隔符（“打断”）的指针。

示例

#include <stdio.h>
#include <string.h>

int main(void)
{
    const char* str = "hello world, friend of mine!";
    const char* sep = " ,!";

    unsigned int cnt = 0;
    do {
       str = strpbrk(str, sep); // 寻找分隔符
       if(str) str += strspn(str, sep); // 跳过分隔符
       ++cnt; // 增加词计数
    } while(str && *str);

    printf("There are %d words\n", cnt);
}

输出：

There are 5 words

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.5.4 The strpbrk function (p: 368)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.5.4 The strpbrk function (p: 331)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.5.4 The strpbrk function

参阅

strcspn | 返回另一个字符串所不具有的字符分割的最大起始段长度 (函数)
strchr | 查找字符的首次出现 (函数)
strtokstrtok_s (C11) | 查找字节字符串中的下一个记号 (函数)


strrchr

< c‎ | string‎ | byte
定义于头文件 <string.h>
char *strrchr( const char *str, int ch );

寻找 ch （如同用 (char)ch 转换到 char 后）在 str 所指向的空终止字节串中（将每个字符转译成 unsigned char ）的最后出现。若搜索 '\0' ，则认为终止空字符为字符串的一部分，而且能找到。

若 str 不是指向空终止字节串的指针，则行为未定义。

参数

str | - | 指向要分析的空终止字节字符串的指针
ch | - | 要搜索的字符

返回值

指向 str 中找到的字符的指针，或若找不到这种字符则为空指针。

示例

#include <string.h>
#include <stdio.h>

int main(void)
{
    char szSomeFileName[] = "foo/bar/foobar.txt";
    char *pLastSlash = strrchr(szSomeFileName, '/');
    char *pszBaseName = pLastSlash ? pLastSlash + 1 : szSomeFileName;
    printf("Base Name: %s", pszBaseName);
}

输出：

Base Name: foobar.txt

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.5.5 The strrchr function (p: 368-369)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.5.5 The strrchr function (p: 331)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.5.5 The strrchr function

参阅

strchr | 查找字符的首次出现 (函数)
strpbrk | 查找一个字符串中的任意一个字符在另一个字符串中的首个位置 (函数)


strspn

< c‎ | string‎ | byte
定义于头文件 <string.h>
size_t strspn( const char *dest, const char *src );

返回 dest 所指向的空终止字节串的最大起始段（ span ）长度，段仅由 src 所指向的空终止字节字符串中找到的字符组成。

若 dest 或 src 不是指向空终止字节字符串的指针，则行为未定义。

参数

dest | - | 指向要分析的空终止字节字符串的指针
src | - | 指向含有要搜索的字符的空终止字节字符串的指针

返回值

仅由来自 src 所指向的空终止字节字符串的字符组成的最大起始段长度。

示例

#include <string.h>
#include <stdio.h>

int main(void)
{
    const char *string = "abcde312$#@";
    const char *low_alpha = "qwertyuiopasdfghjklzxcvbnm";

    size_t spnsz = strspn(string, low_alpha);
    printf("After skipping initial lowercase letters from '%s'\n"
           "The remainder is '%s'\n", string, string+spnsz);
}

输出：

After skipping initial lowercase letters from 'abcde312$#@'
The remainder is '312$#@'

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.5.6 The strspn function (p: 369)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.5.6 The strspn function (p: 332)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.5.6 The strspn function

参阅

strcspn | 返回另一个字符串所不具有的字符分割的最大起始段长度 (函数)
wcsspn (C95) | 返回仅由另一个宽字符串中出现的宽字符分隔的最长首段长度 (函数)
strpbrk | 查找一个字符串中的任意一个字符在另一个字符串中的首个位置 (函数)


strstr

< c‎ | string‎ | byte
定义于头文件 <string.h>
char *strstr( const char* str, const char* substr );

查找 substr 所指的空终止字节字符串在 str 所指的空终止字节字符串中的首次出现。不比较空终止字符。

若 str 或 substr 不是指向空终止字节字符串的指针，则行为未定义。

参数

str | - | 指向要检验的空终止字节字符串的指针
substr | - | 指向要查找的空终止字节字符串的指针

返回值

指向于 str 中找到的子串首字符的指针，或若找不到该子串则为空指针。若 substr 指向空字符串，则返回 str 。

示例

#include <string.h>
#include <stdio.h>

void find_str(char const* str, char const* substr)
{
    char* pos = strstr(str, substr);
    if(pos) {
        printf("found the string '%s' in '%s' at position: %ld\n", substr, str, pos - str);
    } else {
        printf("the string '%s' was not found in '%s'\n", substr, str);
    }
}

int main(void)
{
    char* str = "one two three";
    find_str(str, "two");
    find_str(str, "");
    find_str(str, "nine");
    find_str(str, "n");

    return 0;
}

输出：

found the string 'two' in 'one two three' at position: 4
found the string '' in 'one two three' at position: 0
the string 'nine' was not found in 'one two three'
found the string 'n' in 'one two three' at position: 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.5.7 The strstr function (p: 369)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.5.7 The strstr function (p: 332)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.5.7 The strstr function

参阅

strchr | 查找字符的首次出现 (函数)
strrchr | 查找字符的最后一次出现 (函数)


strtof, strtod, strtold

< c‎ | string‎ | byte
定义于头文件 <stdlib.h> |
float strtof( const char *restrict str, char **restrict str_end ); | (C99 起)
double strtod( const char *str, char **str_end ); | (C99 前)
double strtod( const char *restrict str, char **restrict str_end ); | (C99 起)
long double strtold( const char *restrict str, char **restrict str_end ); | (C99 起)

转译 str 所指向的字节字符串中的浮点值。

函数会舍弃任何空白符（由 std:: isspace () 确定），直至找到首个非空白符。然后它会取用尽可能多的字符，以构成合法的浮点数表示，并将它们转换成浮点值。合法的浮点值可以为下列之一：

  • 十进制浮点数表达式。它由下列部分组成：
  • (可选) 正或负号
  • 非空的十进制数字序列，可选地包含一个小数点字符（由当前的 C 本地环境确定）（定义有效数字）
  • (可选) e 或 E ，并跟随可选的正或负号，以及非空十进制数字序列（以 10 为底定义指数）
  • 十六进制浮点数表达式。它由下列部分组成：
  • (可选) 正或负号
  • 0x 或 0X
  • 非空的十六进制数字序列，选地包含一个小数点字符（由当前的 C 本地环境确定）（定义有效数字）
  • (可选) p 或 P ，并跟随可选的正或负号，以及非空十进制数字序列（以 2 为底定义指数）
  • 无穷大表达式。它由下列部分组成：
  • (可选) 正或负号
  • INF 或 INFINITY ，忽略大小写
  • 非数（NaN）表达式。它由下列部分组成：
  • (可选) 正或负号
  • NAN 或 NAN(char_sequence) ，忽略 NAN 部分的大小写。 char_sequence 只能由数字、拉丁字母和下划线构成。结果是一个静态的 NaN 浮点值。
 (C99 起)
  • 任何其他可由当前 C 本地环境接受的表达式

函数设置 str_end 所指向的指针指向最后被转译字符的后一字符，若 str_end 为空指针，则忽略它。

参数

str | - | 指向要转译的空终止字节字符串的指针
str_end | - | 指向指向字符指针的指针。

返回值

成功时为对应 str 内容的浮点值。若转换出的值落在对应返回类型的范围外，则发生值域错误并返回 HUGE_VAL 、 HUGE_VALF 或 HUGE_VALL 。若无法进行转换，则返回 ​0​ 并将 *str_end 设为 str 。

示例

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

int main(void)
{
    // 带错误处理的剖析
    const char *p = "111.11 -2.22 Nan nan(2) inF 0X1.BC70A3D70A3D7P+6  1.18973e+4932zzz";
    printf("Parsing '%s':\n", p);
    char *end;
    for (double f = strtod(p, &end); p != end; f = strtod(p, &end))
    {
        printf("'%.*s' -> ", (int)(end-p), p);
        p = end;
        if (errno == ERANGE){
            printf("range error, got ");
            errno = 0;
        }
        printf("%f\n", f);
    }

    // 无错误处理的剖析
    printf("\"  -0.0000000123junk\"  -->  %g\n", strtod("  -0.0000000123junk", NULL));
    printf("\"junk\"                 -->  %g\n", strtod("junk", NULL));
}

可能的输出：

Parsing '111.11 -2.22 Nan inF 0X1.BC70A3D70A3D7P+6  1.18973e+4932zzz':
'111.11' -> 111.110000
' -2.22' -> -2.220000
' Nan' -> nan
' nan(2)' -> nan
' inF' -> inf
' 0X1.BC70A3D70A3D7P+6' -> 111.110000
'  1.18973e+4932' -> range error, got inf
"  -0.0000000123junk"  -->  -1.23e-08
"junk"                 -->  0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.1.3 The strtod, strtof, and strtold functions (p: 342-344)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.1.3 The strtod, strtof, and strtold functions (p: 308-310)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.1.4 The strtod function

参阅

atof | 将字节字符串转换成浮点值 (函数)
wcstofwcstodwcstold (C99)(C95)(C99) | 将宽字符串转换成浮点值 (函数)


strtoimax, strtoumax

< c‎ | string‎ | byte
定义于头文件 <inttypes.h> |
intmax_t strtoimax( const char *restrict nptr, char **restrict endptr, int base ); | (C99 起)
uintmax_t strtoumax( const char *restrict nptr, char **restrict endptr, int base ); | (C99 起)

转译 nptr 所指向的字节字符串中的值。

舍弃所有空白符（以调用 isspace() 鉴别），直到找到首个非空白符，然后取尽可能多的字符组成底 n （其中 n=base ）的整数表示，并将它们转换成一个整数值。合法的整数值由下列部分组成：

  • (可选)正或负号
  • (可选)指示八进制底的前缀（ 0 ）（仅当底为 8 或 ​0​ 时应用）
  • (可选)指示十六进制底的前缀（ 0x 或 0X ）（仅当底为 16 或 ​0​ 时应用）
  • 一个数字序列

底的合法集是 {0,2,3,...,36} 。合法数字集对于底 2 整数是 {0,1}，对于底3整数是 {0,1,2} ，以此类推。对于大于 10 的底，合法数字包含字母字符，从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。

当前安装的 C 本地环境可能接受另外的数字格式。

若 base 为 ​0​ ，则自动检测数值进制：若前缀为 0 ，则底为八进制，若前缀为 0x 或 0X ，则底为十六进制，否则底为十进制。

若符号是输入序列的一部分，则对从数字序列计算得来的数字值取反，如同用结果类型的一元减。

此函数设置 endptr 所指向的指针指向最后一个转译字符的后一字符。若 endptr 为空指针，则忽略它。

若 nptr 为空字符串或无期待的形式，则不进行转换，并（若 enptr 非空指针）将 nptr 存储于 endptr 所指向的对象。

参数

str | - | 指向要被转译的空终止字符串的指针
str_end | - | 指向指向字符的指针的指针。
base | - | 被转译整数值的底

返回值

  • 若成功，则返回对应 str 内容的整数值。
  • 若整数值落在对应的返回类型范围外，则发生值域错误（设置 errno 为 ERANGE ），并返回 INTMAX_MAX 、 INTMAX_MIN 、 UINTMAX_MAX 或 ​0​ 中的最接近者。
  • 若无法进行转换，则返回 ​0​ 。

示例

#include <stdio.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>

int main(void)
{

    char* endptr;

    printf("%ld\n", strtoimax(" -123junk",&endptr,10)); /* 底 10          */
    printf("%ld\n", strtoimax("11111111",&endptr,2));   /* 底 2           */
    printf("%ld\n", strtoimax("XyZ",&endptr,36));       /* 底 36          */
    printf("%ld\n", strtoimax("010",&endptr,0));        /* 八进制自动检测   */
    printf("%ld\n", strtoimax("10",&endptr,0));         /* 十进制自动检测   */
    printf("%ld\n", strtoimax("0x10",&endptr,0));       /* 十六进制自动检测 */

    /* 值域错误                 */
    /* LONG_MAX+1 --> LONG_MAX */
    errno = 0;
    printf("%ld\n", strtoimax("9223372036854775808",&endptr,10));
    printf("%s\n", strerror(errno));

    return 0;
}

输出：

-123
255
44027
8
10
16
9223372036854775807
Numerical result out of range

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.8.2.3 The strtoimax and strtoumax functions (p: 219)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.8.2.3 The strtoimax and strtoumax functions (p: 200)

参阅

wcstoimaxwcstoumax (C99)(C99) | 将宽字符串转换成 intmax_t 或 uintmax_t (函数)
strtolstrtoll (C99) | 将字节字符串转换成整数值 (函数)
strtoul strtoull (C99) | 将字节字符串转换成无符号整数值 (函数)


strtok, strtok_s

< c‎ | string‎ | byte
定义于头文件 <string.h> |  |
 | (1) |
char *strtok( char *str, const char *delim ); |  |  | (C99 前)
char *strtok( char *restrict str, const char *restrict delim ); |  |  | (C99 起)
char *strtok_s(char *restrict str, rsize_t *restrict strmax, const char *restrict delim, char **restrict ptr); | (2) | (C11 起)
1) 寻找 str 所指向的空终止字节字符串中的下个记号。由 delim 所指向的空终止字节字符串鉴别分隔字符。
此函数被设计为调用多次以从同一字符串获得相继的记号。
  • 若 str 不是空指针，则调用被当做 strtok 对此特定字符串的首次调用。函数搜索首个不含于 delim 的字符。
  • 若找不到这种字符，则 str 中完全没有记号，而函数返回空指针。
  • 若找到这种字符，则它是记号的起始。然后函数从该点搜索首个含于 delim 的字符。
  • 若找不到这种字符，则 str 只有一个记号，而将来对 strtok 的调用将返回空指针
  • 若找到这种字符，则用空字符 '\0' 替换它，并将指向下个字符的指针存储于静态位置，以为后继调用所用。
  • 然后函数返回指向记号起始的指针
  • 若 str 为空指针，则将调用当做对 strtok 的后继调用，函数从先前调用中它剩下的位置开始。行为如同将先前存储的指针作为 str 传递。
若str 或 delim 不是指向空终止字节字符串的指针，则行为未定义。
2) 同 (1) ，除了在每步时，写入 str 中留待查看的字符数到 *strmax ，并写入记号化器的初始状态到 *ptr 。重复的调用（以空 str ）必须传递先前的调用用以存储值的 strmax 和 ptr 。另外，在运行时检测下列错误并调用当前安装的制约处理函数，而不存储任何内容到 ptr 所指向的对象：
  • strmax 、 delim 或 ptr 为空指针
  • 非首次调用（以 str ）时， *ptr 为空指针
  • 首次调用时， *strmax 为零或大于 RSIZE_MAX
  • 对记号尾的搜索抵达源字符串的结尾（由 *strmax 的初值测量）而未遇到空终止符
若 str 指向的字符数组缺少空终止符，而 strmax 指向的值大于该字符数组长度，则行为未定义。
同所有边界检查函数， strtok_s 仅若实现定义 __STDC_LIB_EXT1__ 且用户在包含 string.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

str | - | 指向要记号化的空终止字节字符串的指针
delim | - | 指向标识分隔符的空终止字节字符串的指针
strmax | - | 指向最初保有 str 长度的对象指针： strtok_s 存储留待检验的字符数
ptr | - | 指向 char* 类型对象的指针， strtok_s 以之存储其内部状态

返回值

返回指向下个记号起始的指针，或若无更多记号则返回空指针。

注解

此函数是破坏性的：它写入 '\0' 字符到字符串 str 的元素。特别是，不能以字符串字面量为 strtok 的首参数。

每次对 strtok 的调用都会修改静态对象：它不是线程安全的。

不同于大多数其他记号化器， strtok 中的分隔符能对于后继记号不同，而且甚至能依赖于先前记号的内容。

strtok_s 函数异于 POSIX strtok_r 函数，前者通过在被记号化的字符串外部存储，和检查运行时制约来防护。

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#include <stdio.h>

int main(void)
{
    char input[] = "A bird came down the walk";
    printf("Parsing the input string '%s'\n", input);
    char *token = strtok(input, " ");
    while(token) {
        puts(token);
        token = strtok(NULL, " ");
    }

    printf("Contents of the input string now: '");
    for(size_t n = 0; n < sizeof input; ++n)
        input[n] ? putchar(input[n]) : fputs("\\0", stdout);
    puts("'");

#ifdef __STDC_LIB_EXT1__
    char str[] = "A bird came down the walk";
    rsize_t strmax = sizeof str;
    const char *delim = " ";
    char *next_token;
    printf("Parsing the input string '%s'\n", str);
    token = strtok_s(str, &strmax, delim, &next_token);
    while(token) {
        puts(token);
        token = strtok_s(NULL, &strmax, delim, &next_token);
    }

    printf("Contents of the input string now: '");
    for(size_t n = 0; n < sizeof str; ++n)
        str[n] ? putchar(str[n]) : fputs("\\0", stdout);
    puts("'");
#endif
}

可能的输出：

Parsing the input string 'A bird came down the walk'
A
bird
came
down
the
walk
Contents of the input string now: 'A\0bird\0came\0down\0the\0walk\0'
Parsing the input string 'A bird came down the walk'
A
bird
came
down
the
walk
Contents of the input string now: 'A\0bird\0came\0down\0the\0walk\0'

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.5.8 The strtok function (p: 369-370)
  • K.3.7.3.1 The strtok_s function (p: 620-621)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.5.8 The strtok function (p: 332-333)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.5.8 The strtok function

参阅

strpbrk | 查找一个字符串中的任意一个字符在另一个字符串中的首个位置 (函数)
strcspn | 返回另一个字符串所不具有的字符分割的最大起始段长度 (函数)
strspn | 返回由另一个字符串中的字符分割的最大起始段长度 (函数)
wcstokwcstok_s (C95)(C11) | 查找宽字符串中的下一个记号 (函数)


strtol, strtoll

< c‎ | string‎ | byte
定义于头文件 <stdlib.h> |
long strtol( const char *str, char **str_end, int base ); | (C99 前)
long strtol( const char *restrict str, char **restrict str_end, int base ); | (C99 起)
long long strtoll( const char *restrict str, char **restrict str_end, int base ); | (C99 起)

转译 str 所指的字节字符串中的整数值。

舍弃所有空白符（以调用 isspace() 鉴别），直到找到首个非空白符，然后取尽可能多的字符组成底 n （其中 n=base ）的整数表示，并将它们转换成一个整数值。合法的整数值由下列部分组成：

  • (可选)正或负号
  • (可选)指示八进制底的前缀（ 0 ）（仅当底为 8 或 ​0​ 时应用）
  • (可选)指示十六进制底的前缀（ 0x 或 0X ）（仅当底为 16 或 ​0​ 时应用）
  • 一个数字序列

底的合法集是 {0,2,3,...,36} 。合法数字集对于底 2 整数是 {0,1}，对于底3整数是 {0,1,2} ，以此类推。对于大于 10 的底，合法数字包含字母字符，从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。

当前安装的 C 本地环境可能接受另外的数字格式。

若 base 为 ​0​ ，则自动检测数值进制：若前缀为 0 ，则底为八进制，若前缀为 0x 或 0X ，则底为十六进制，否则底为十进制。

若符号是输入序列的一部分，则对从数字序列计算得来的数字值取反，如同用结果类型的一元减。

函数设置 str_end 所指向的指针指向最后被转译字符的后一字符。若 str_end 为空指针，则忽略它。

若 str 为空或无期待的形式，则不进行转换，并（若 str_end 不是空指针）将 str 的值存储于 str_end 所指的对象。

参数

str | - | 指向要被转译的空终止字符串的指针
str_end | - | 指向指向字符指针的指针。
base | - | 被转译整数值的底

返回值

  • 若成功，则返回对应 str 内容的整数值。
  • 若被转换值落在对应返回类型的范围外，则发生值域错误（设 errno 为 ERANGE ）并返回 LONG_MAX 、 LONG_MIN 、 LLONG_MAX 或 LLONG_MIN 。
  • 若无法进行转换，则返回 ​0​ 。

示例

#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    // 带错误处理的剖析
    const char *p = "10 200000000000000000000000000000 30 -40 junk";
    printf("Parsing '%s':\n", p);

    for (;;)
    {
        // 库函数调用能设置 errno 为任何非零值，无关乎是否有错误，
        // 故为检查 strtol 设置的错误，需要清除它
        errno = 0;
        char *end;
        const long i = strtol(p, &end, 10);
        if (p == end)
            break;

        const bool range_error = errno == ERANGE;
        printf("Extracted '%.*s', strtol returned %ld.", (int)(end-p), p, i);
        p = end;

        if (range_error)
            printf(" Range error occurred.");

        putchar('\n');
    }

    printf("Unextracted leftover: '%s'\n\n", p);

    // 不带错误处理的剖析
    printf("\"1010\" in binary  --> %ld\n", strtol("1010", NULL, 2));
    printf("\"12\"   in octal   --> %ld\n", strtol("12",   NULL, 8));
    printf("\"A\"    in hex     --> %ld\n", strtol("A",    NULL, 16));
    printf("\"junk\" in base-36 --> %ld\n", strtol("junk", NULL, 36));
    printf("\"012\"  in auto-detected base --> %ld\n", strtol("012",  NULL, 0));
    printf("\"0xA\"  in auto-detected base --> %ld\n", strtol("0xA",  NULL, 0));
    printf("\"junk\" in auto-detected base --> %ld\n", strtol("junk", NULL, 0));
}

可能的输出：

Parsing '10 200000000000000000000000000000 30 -40 junk':
Extracted '10', strtol returned 10.
Extracted ' 200000000000000000000000000000', strtol returned 9223372036854775807. Range error occurred.
Extracted ' 30', strtol returned 30.
Extracted ' -40', strtol returned -40.
Unextracted leftover: ' junk'

"1010" in binary  --> 10
"12"   in octal   --> 10
"A"    in hex     --> 10
"junk" in base-36 --> 926192
"012"  in auto-detected base --> 10
"0xA"  in auto-detected base --> 10
"junk" in auto-detected base --> 0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.1.4 The strtol, strtoll, strtoul, and strtoull functions (p: 344-345)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.1.4 The strtol, strtoll, strtoul, and strtoull functions (p: 310-311)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.1.5 The strtol function

参阅

atoiatolatoll (C99) | 将字节字符串转换成整数值 (函数)
strtoul strtoull (C99) | 将字节字符串转换成无符号整数值 (函数)
wcstolwcstoll (C95)(C99) | 将宽字符串转换成整数值 (函数)
wcstoulwcstoull (C95)(C99) | 将宽字符串转换成无符号整数值 (函数)


strtoul, strtoull

< c‎ | string‎ | byte
定义于头文件 <stdlib.h> |
unsigned long strtoul( const char *str, char **str_end, int base ); | (C99 前)
unsigned long strtoul( const char *restrict str, char **restrict str_end, int base ); | (C99 起)
unsigned long long strtoull( const char *restrict str, char **restrict str_end, int base ); | (C99 起)

转译 str 所指的字符串中的无符号整数值。

舍弃所有空白符（以调用 isspace() 鉴别），直到找到首个非空白符，然后取尽可能多的字符组成底 n （其中 n=base ）的无符号整数表示，并将它们转换成一个整数值。合法的无符号整数值由下列部分组成：

  • (可选)正或负号
  • (可选)指示八进制底的前缀（ 0 ）（仅当底为 8 或 ​0​ 时应用）
  • (可选)指示十六进制底的前缀（ 0x 或 0X ）（仅当底为 16 或 ​0​ 时应用）
  • 一个数字序列

底的合法集是 {0,2,3,...,36} 。合法数字集对于底 2 整数是 {0,1}，对于底3整数是 {0,1,2} ，以此类推。对于大于 10 的底，合法数字包含字母字符，从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。

当前安装的 C 本地环境可能接受另外的数字格式。

若 base 为 ​0​ ，则自动检测数值进制：若前缀为 0 ，则底为八进制，若前缀为 0x 或 0X ，则底为十六进制，否则底为十进制。

若符号是输入序列的一部分，则对从数字序列计算得来的数字值取反，如同用结果类型的一元减，它对无符号整数应用回卷规则。

函数设置 str_end 所指向的指针指向最后一个被转译字符的后一字符。若 str_end 为空指针，则忽略它。

参数

str | - | 指向要被转译的空终止字符串的指针
str_end | - | 指向指向字符的指针的指针。
base | - | 被转译整数值的底

返回值

成功时为对应 str 内容的整数值。若被转换值落在对应返回类型的范围外，则发生值域错误（ errno 被设为 ERANGE ）并返回 ULONG_MAX 或 ULLONG_MAX 。若无转换可进行，则返回 ​0​ 。

示例

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

int main(void)
{
    const char *p = "10 200000000000000000000000000000 30 -40";
    printf("Parsing '%s':\n", p);
    char *end;
    for (unsigned long i = strtoul(p, &end, 10);
         p != end;
         i = strtoul(p, &end, 10))
    {
        printf("'%.*s' -> ", (int)(end-p), p);
        p = end;
        if (errno == ERANGE){
            printf("range error, got ");
            errno = 0;
        }
        printf("%lu\n", i);
    }
}

输出：

Parsing '10 200000000000000000000000000000 30 -40':
'10' -> 10
' 200000000000000000000000000000' -> range error, got 18446744073709551615
' 30' -> 30
' -40' -> 18446744073709551576

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.1.4 The strtol, strtoll, strtoul, and strtoull functions (p: 344-345)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.1.4 The strtol, strtoll, strtoul, and strtoull functions (p: 310-311)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.1.6 The strtoul function

参阅

wcstoulwcstoull (C95)(C99) | 将宽字符串转换成无符号整数值 (函数)
atoiatolatoll (C99) | 将字节字符串转换成整数值 (函数)
strtolstrtoll (C99) | 将字节字符串转换成整数值 (函数)


strxfrm

< c‎ | string‎ | byte
定义于头文件 <string.h> |
size_t strxfrm( char *dest, const char *src, size_t count ); | (C99 前)
size_t strxfrm( char *restrict dest, const char *restrict src, size_t count ); | (C99 起)

变换 src 所指向的空终止字节字符串为实现定义形式，满足当前 C 本地环境中，以 strcmp 比较二个变换后字符串给出与用 strcoll 比较源字符串相同的结果。

将变换后字符串的首 count 个字符写入目标，包含空终止字符，并返回排除空终止字符的完整转换后字符串的长度。

若 dest 数组不够大则行为未定义。若 dest 与 src 重叠则行为未定义。

若 count 为 ​0​ ，则允许 dest 为空指针。

在以同一字符串或字符串集合进行多个本地环境依赖的比较时，使用此函数，因为仅用 strxfrm 变换所有字符串一次，而以 strcmp 进行后继比较更为高效。

注意

能接收整个变换后字符串的正确缓冲区长度为 1+strxfrm( NULL, src, 0) 。

参数

dest | - | 指向将写入变换后的字符串的数组首元素的指针
src | - | 指向要变换的空终止字节字符串首元素的指针
count | - | 要写入的最大字符数

返回值

变换后的字符串长度，不包含空终止字符。

示例

#include <stdio.h>
#include <string.h>
#include <locale.h>

int main(void)
{
    setlocale(LC_COLLATE, "cs_CZ.iso88592");

    const char *in1 = "hrnec";
    char out1[1+strxfrm(NULL, in1, 0)];
    strxfrm(out1, in1, sizeof out1);

    const char *in2 = "chrt";
    char out2[1+strxfrm(NULL, in2, 0)];
    strxfrm(out2, in2, sizeof out2);

    printf("In the Czech locale: ");
    if(strcmp(out1, out2) < 0)
         printf("%s before %s\n",in1, in2);
    else
         printf("%s before %s\n",in2, in1);

    printf("In lexicographical comparison: ");
    if(strcmp(in1, in2)<0)
         printf("%s before %s\n",in1, in2);
    else
         printf("%s before %s\n",in2, in1);

}

输出：

In the Czech locale: hrnec before chrt
In lexicographical comparison: chrt before hrnec

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.24.4.5 The strxfrm function (p: 366-367)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.21.4.5 The strxfrm function (p: 329-330)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.11.4.5 The strxfrm function

参阅

strcoll | 比较两个字符串，根据当前本地环境 (函数)
wcscoll (C95) | 根据当前本地环境比较两个宽字符串 (函数)
strcmp | 比较两个字符串 (函数)
wcsxfrm (C95) | 变换宽字符串，使得 wcscmp 会产生与 wcscoll 相同的结果 (函数)


tolower

< c‎ | string‎ | byte
定义于头文件 <ctype.h>
int tolower( int ch );

按照当前安装的 C 本地环境所定义的规则，转换给定字符为小写。

默认 "C" 本地环境中，以分别小写字母 ABCDEFGHIJKLMNOPQRSTUVWXYZ 替换大写字母 abcdefghijklmnopqrstuvwxyz 。

参数

ch - 要转换的字符。若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

返回值

ch 的小写版本，或若当前 C 本地环境中无小写版本，则返回不修改的 ch 。

示例

#include <stdio.h>
#include <ctype.h>
#include <locale.h>
#include <limits.h>

int main(void)
{
    /* 在默认本地环境： */
    unsigned char l;
    for (unsigned char u=0; u<UCHAR_MAX; u++) {
        l = tolower(u);
        if (l!=u) printf("%c%c ", u,l);
    }
    printf("\n\n");

    unsigned char c = '\xb4'; // ISO-8859-15 的字符 Ž
                              // 但在 ISO-8859-1为 ´ （锐音符）
    unsigned char c2 = c;   // 为打印
    setlocale(LC_ALL, "en_US.iso88591");
    printf("in iso8859-1, tolower('0x%x') gives 0x%x\n", c2, tolower(c));
    setlocale(LC_ALL, "en_US.iso885915");
    printf("in iso8859-15, tolower('0x%x') gives 0x%x\n", c2, tolower(c));
}

输出：

Aa Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk Ll Mm Nn Oo Pp Qq Rr Ss Tt Uu Vv Ww Xx Yy Zz

in iso8859-1, tolower('0xb4') gives 0xb4
in iso8859-15, tolower('0xb4') gives 0xb8

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4.2.1 The tolower function (p: 203)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4.2.1 The tolower function (p: 184)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.3.2.1 The tolower function

参阅

toupper | 将字符转换成大写 (函数)
towlower (C95) | 将宽字符转换为小写 (函数)


toupper

< c‎ | string‎ | byte
定义于头文件 <ctype.h>
int toupper( int ch );

按照当前安装的 C 本地环境所定义的字符转换规则，转换给定字符为大写。

默认 "C" 本地环境中，分别以大写字母 ABCDEFGHIJKLMNOPQRSTUVWXYZ 替换下列小写字母 abcdefghijklmnopqrstuvwxyz 。

参数

ch - 要转化的字符。若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

返回值

被转换的字符，或若无大写版本列于当前 C 本地环境，则为不修改的 ch 。

示例

#include <stdio.h>
#include <ctype.h>
#include <locale.h>
#include <limits.h>

int main(void)
{
    /* 在默认本地环境： */
    unsigned char u;
    for (unsigned char l=0; l<UCHAR_MAX; l++) {
        u = toupper(l);
        if (l!=u) printf("%c%c ", l,u);
    }
    printf("\n\n");

    unsigned char c = '\xb8'; // ISO-8859-15 中的字母 ž
                              // 但在 ISO-8859-1 中为 ¸ （下加符）
    unsigned char c2 = c;   // 为打印
    setlocale(LC_ALL, "en_US.iso88591");
    printf("in iso8859-1, toupper('0x%x') gives 0x%x\n", c2, toupper(c));
    setlocale(LC_ALL, "en_US.iso885915");
    printf("in iso8859-15, toupper('0x%x') gives 0x%x\n", c2, toupper(c));
}

输出：

aA bB cC dD eE fF gG hH iI jJ kK lL mM nN oO pP qQ rR sS tT uU vV wW xX yY zZ

in iso8859-1, toupper('0xb8') gives 0xb8
in iso8859-15, toupper('0xb8') gives 0xb4

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.4.2.2 The toupper function (p: 204)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.4.2.2 The toupper function (p: 185)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.3.2.2 The toupper function

参阅

tolower | 将字符转换成小写 (函数)
towupper (C95) | 将宽字符转换为大写 (函数)


空终止多字节字符串

< c‎ | string

空终止多字节字符串（ NTMBS ），或称“多字节字符串”，是后面跟随一个零值字节（空终止字符'\0'）的一串非零字节。

每个存储于字符串中的字符可能占用多于一个字节。在多字节字符串中，用于表示字符的编码是本地环境限定的：它可以是 UTF-8 、 GB18030 、 EUC-JP 、 Shift-JIS 等等。例如，字符数组 {'\xe4','\xbd','\xa0','\xe5','\xa5','\xbd','\0'} 是一个以 UTF-8 多字节编码表示字符串 "你好" 的 NTMBS ：前三字节编码字符 "你" ，后三字节编码字符 "好" 。用 GB18030 编码的相同字符串是字符数组 {'\xc4', '\xe3', '\xba', '\xc3', '\0'} ，其中两个字符都编码成双字符序列。

一些多字节字符串中，任何给定的多字节字符序列可能会根据前置的字节序列表示不同的字符，这个前置序列称为“迁移序列”。此类编码是依赖状态的：需要当前迁移状态来转译每一个字符。若起始和终止为初始迁移状态， NTMBS 才是合法的：即若多字节编码使用迁移序列，则字符串结束前的整个序列必须为未迁移序列。这类编码的例子是 BOCU-1 和 SCSU 。

多字节字符串与空终止字节字符串（ NTBS ）布局兼容，即是说，可以使用同样的工具存储、复制和检验，除了计算字符数的情况。若正确的本地环境正在发挥作用，则输入/输出函数亦可控制多字节字符串。运用下列依赖本地环境的函数，多字节字符串可以与宽字符串相互转换：

多字节/宽字符转换

定义于头文件 <stdlib.h>
mblen | 返回下一个多字节字符的字节数 (函数)
mbtowc | 将下一个多字节字符转换成宽字符 (函数)
wctombwctomb_s (C11) | 将宽字符转换成其多字节表示 (函数)
mbstowcsmbstowcs_s (C11) | 将窄多字节字符串转换成宽字符串 (函数)
wcstombswcstombs_s (C11) | 将宽字符串转换成窄多字节字符串 (函数)
定义于头文件 <wchar.h>
mbsinit (C95) | 检查 mbstate_t 对象是否表示初始迁移状态 (函数)
btowc (C95) | 将单字节窄字符加宽成宽字符，倘若可能 (函数)
wctob (C95) | 将宽字符收窄成单字节窄字符，倘若可能 (函数)
mbrlen (C95) | 给定状态，返回下一个多字节字符的字节数 (函数)
mbrtowc (C95) | 给定状态，将下一个多字节字符转换成宽字符 (函数)
wcrtombwcrtomb_s (C95)(C11) | 给定状态，将宽字符转换成其多字节表示 (函数)
mbsrtowcsmbsrtowcs_s (C95)(C11) | 给定状态，将窄多字节字符串转换成宽字符串 (函数)
wcsrtombswcsrtombs_s (C95)(C11) | 给定状态，将宽字符串转换成窄多字节字符串 (函数)
定义于头文件 <uchar.h>
mbrtoc16 (C11) | 从窄多字节字符串生成下一个16位宽字符 (函数)
c16rtomb (C11) | 将16位宽字符转换成窄多字节字符串 (函数)
mbrtoc32 (C11) | 从窄多字节字符串生成下一个32位宽字符 (函数)
c32rtomb (C11) | 将32位宽字符转换成窄多字节字符串 (函数)

类型

定义于头文件 <wchar.h>
mbstate_t (C95) | 迭代多字节字符串所需的转换信息 (结构体)
定义于头文件 <uchar.h>
char16_t (C11) | 16 位宽字符类型 (typedef)
char32_t (C11) | 32 位宽字符类型 (typedef)

宏

定义于头文件 <limits.h>
MB_LEN_MAX | 多字节字符的最大字节数 (宏常量)
定义于头文件 <stdlib.h>
MB_CUR_MAX | 当前C本地环境中的多字节字符最大字节数 (宏变量)
定义于头文件 <uchar.h>
__STDC_UTF_16__ (C11) | 指示 mbrtoc16 及 c16rtomb 使用 UTF-16 编码 (宏常量)
__STDC_UTF_32__ (C11) | 指示 mbrtoc32 及 c32rtomb 使用 UTF-32 编码 (宏常量)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.10 Sizes of integer types <limits.h> (p: 222)
  • 7.22 General utilities <stdlib.h> (p: 340-360)
  • 7.28 Unicode utilities <uchar.h> (p: 398-401)
  • 7.29 Extended multibyte and wide character utilities <wchar.h> (p: 402-446)
  • 7.31.12 General utilities <stdlib.h> (p: 456)
  • 7.31.16 Extended multibyte and wide character utilities <wchar.h> (p: 456)
  • K.3.6 General utilities <stdlib.h> (p: 604-614)
  • K.3.9 Extended multibyte and wide character utilities <wchar.h> (p: 627-651)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.10 Sizes of integer types <limits.h> (p: 203)
  • 7.20 General utilities <stdlib.h> (p: 306-324)
  • 7.24 Extended multibyte and wide character utilities <wchar.h> (p: 348-392)
  • 7.26.10 General utilities <stdlib.h> (p: 402)
  • 7.26.12 Extended multibyte and wide character utilities <wchar.h> (p: 402)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.1.4 Limits <float.h> and <limits.h>
  • 4.10 GENERAL UTILITIES <stdlib.h>
  • 4.13.7 General utilities <stdlib.h>

参阅


btowc

< c‎ | string‎ | multibyte
定义于头文件 <wchar.h> |
wint_t btowc( int c ); | (C95 起)

加宽单字节字符 c （转译成 unsigned char ）为其宽字符等价。

大多数多字节字符编码用单字节码表示来自 ASCII 字符集的字符。此函数可以可用于转换这些字符为 wchar_t 。

参数

c - 要加宽的单字节字符

返回值

若 c 为 EOF 则返回 WEOF 。

若 (unsigned char)c 在初始迁移状态为合法单字节字符，则返回 c 的宽字符表示，否则返回 WEOF 。

示例

#include <stdio.h>
#include <wchar.h>
#include <locale.h>
#include <assert.h>

void try_widen(unsigned char c)
{
    wint_t w = btowc(c);
    if(w != WEOF)
        printf("The single-byte character %#x widens to %#x\n", c, w);
    else
        printf("The single-byte character %#x failed to widen\n", c);
}

int main(void)
{
    char *loc = setlocale(LC_ALL, "lt_LT.iso88594");
    assert(loc);
    printf("In Lithuanian ISO-8859-4 locale:\n");
    try_widen('A');
    try_widen('\xdf'); // ISO-8859-4 的德文字母 ß （ U+00df ）
    try_widen('\xf9'); // ISO-8859-4 的立陶宛文字母 ų （ U+0173 ）

    setlocale(LC_ALL, "lt_LT.utf8");
    printf("In Lithuanian UTF-8 locale:\n");
    try_widen('A');
    try_widen('\xdf');
    try_widen('\xf9');
}

可能的输出：

In Lithuanian ISO-8859-4 locale:
The single-byte character 0x41 widens to 0x41
The single-byte character 0xdf widens to 0xdf
The single-byte character 0xf9 widens to 0x173
In Lithuanian UTF-8 locale:
The single-byte character 0x41 widens to 0x41
The single-byte character 0xdf failed to widen
The single-byte character 0xf9 failed to widen

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.6.1.1 The btowc function (p: 441)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.6.1.1 The btowc function (p: 387)

参阅

wctob
(C95)
 将宽字符收窄成单字节窄字符，倘若可能
(函数)


c16rtomb

< c‎ | string‎ | multibyte
定义于头文件 <uchar.h> |
size_t c16rtomb( char * restrict s, char16_t c16, mbstate_t * restrict ps ); | (C11 起)

从变长 16 位宽字符表示（典型地为 UTF-16 ）转换单个编码点到其多字节窄字符表示。

若 s 不是空指针且 c16 是合法的编码点变长编码中的最后一个 16 位编码单元，则函数确定存储该编码点所需的字节数（包含任何迁移序列，并考虑当前多字节转换状态 *ps ），并存储多字节表示于首元素为 s 所指向的字符数组，若必要则更新 *ps 。此函数最能写入 MB_CUR_MAX 个字节。

若 s 是空指针，则调用等价于对于某内部缓冲区 buf 的 c16rtomb(buf, u'\0', ps) 。

若 c16 是空宽字符 u'\0' ，则存储空字节，前附恢复到初始迁移状态所需的任何迁移序列，并更新 *ps 以表示初始迁移状态。

若 c16 不是宽字符的 16 位表示中最终编码单元，则不写入 s 所指向的数组，只更新 *ps 。

若定义宏 __STDC_UTF_16__ ，则此函数所用的 16 位编码是 UTF-16 ；否则，它是实现定义的。任何情况下，此函数所用的宽字符编码为当前活跃的 C 本地环境所指定。

参数

s | - | 指向将存储多字节字符的窄字符数组的指针
c16 | - | 要转换的 16 位宽字符
ps | - | 指向转译多字节字符串时所用转换状态对象的指针

返回值

成功时，返回写入首元素为 s 所指向的字符数组的字节数（包含任何迁移序列）。此值可以是 ​0​ ，例如在处理多 char16_t 单元序列的前导 char16_t 单元时（在处理 UTF-16 代理对中的前导代理时出现）。

失败时（若 c16 不是合法的 16 位编码单元），则返回 -1 ，并存储 EILSEQ 于 errno ，把 *ps 置于未指定状态。

注意

在 C11 刚发布时，不同于转换变宽多字节（如 UTF-8 ）到变宽 16 位（如 UTF-16 ）编码的 mbrtoc16 ，此函数只能转换单个单元的 16 位编码，这表示尽管此函数的原目的如此，它仍不能转换 UTF-16 到 UTF-8 。这为 C11 后的缺陷报告 DR488 所更正。

示例

注意：此示例假设应用缺陷报告 488 的修复

#include <stdio.h>
#include <locale.h>
#include <uchar.h>
#include <stdlib.h>

mbstate_t state;
int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    char16_t in[] = u"zß水🍌"; // 或 "z\u00df\u6c34\U0001F34C"
    size_t in_sz = sizeof in / sizeof *in;

    printf("Processing %zu UTF-16 code units: [ ", in_sz);
    for(size_t n = 0; n < in_sz; ++n) printf("%#x ", in[n]);
    puts("]");

    char out[MB_CUR_MAX * in_sz];
    char *p = out;
    for(size_t n = 0; n < in_sz; ++n) {
        size_t rc = c16rtomb(p, in[n], &state);
        if(rc == (size_t)-1) break;
        p += rc;
    }

    size_t out_sz = p - out;
    printf("into %zu UTF-8 code units: [ ", out_sz);
    for(size_t x = 0; x < out_sz; ++x) printf("%#x ", +(unsigned char)out[x]);
    puts("]");
}

输出：

Processing 6 UTF-16 code units: [ 0x7a 0xdf 0x6c34 0xd83c 0xdf4c 0 ]
into 11 UTF-8 code units: [ 0x7a 0xc3 0x9f 0xe6 0xb0 0xb4 0xf0 0x9f 0x8d 0x8c 0 ]

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.28.1.2 The c16rtomb function (p: 399-400)

参阅

mbrtoc16
(C11)
 从窄多字节字符串生成下一个16位宽字符
(函数)


c32rtomb

< c‎ | string‎ | multibyte
定义于头文件 <uchar.h> |
size_t c32rtomb( char * restrict s, char32_t c32, mbstate_t * restrict ps ); | (C11 起)

将单个编码点从变长 32 位宽字符表示（但典型地是 UTF-32 ）转换到其窄多字节字符表示。

若 s 不是空指针，则函数确定存储 c32 的多字节字符表示所需的字节数（包含任何迁移序列，并考虑当前的多字节转换状态 *ps ），并存储多字节字符表示于首元素为 s 所指向的字符数组，按需更新 *ps 。此函数至多能写 MB_CUR_MAX 个字符。

若 s 是空指针，则调用等价于对某内部存储 buf 的 c32rtomb(buf, U'\0', ps) 。

若 c32 是空宽字符 U'\0' ，则存储空字节，前附恢复到初始迁移状态所需的任何迁移序列，并更新转换状态参数 *ps 以表示初始迁移状态。

若定义宏 __STDC_UTF_32__ ，则此函数使用的 32 位编码是 UTF-32 ；否则它是实现定义的。任何情况下，此函数所用的多字节字符编码为当前活跃的 C 本地环境所指定。

参数

s | - | 指向将存储多字节字符的窄字符数组的指针
c32 | - | 要转换的 32 位宽字符
ps | - | 指向转译多字节字符串所用的转换状态对象的指针

返回值

成功时，返回写入首元素为 s 所指向的字符数组的字节数（包含任何迁移序列）。此值可为 ​0​ ，例如在处理多 char32_t 单元序列中的前导 char32_t 单元时（ UTF-32 中不出现）。

失败时（若 c32 不是合法的 32 位宽字符），返回 -1 ，存储 EILSEQ 于 errno ，并置 *ps 于未指定状态。

示例

#include <stdio.h>
#include <locale.h>
#include <uchar.h>
#include <stdlib.h>

mbstate_t state;
int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    char32_t in[] = U"zß水🍌"; // 或 "z\u00df\u6c34\U0001F34C"
    size_t in_sz = sizeof in / sizeof *in;

    printf("Processing %zu UTF-32 code units: [ ", in_sz);
    for(size_t n = 0; n < in_sz; ++n) printf("%#x ", in[n]);
    puts("]");

    char out[MB_CUR_MAX * in_sz];
    char *p = out;
    for(size_t n = 0; n < in_sz; ++n) {
        size_t rc = c32rtomb(p, in[n], &state);
        if(rc == (size_t)-1) break;
        p += rc;
    }

    size_t out_sz = p - out;
    printf("into %zu UTF-8 code units: [ ", out_sz);
    for(size_t x = 0; x < out_sz; ++x) printf("%#x ", +(unsigned char)out[x]);
    puts("]");
}

输出：

Processing 5 UTF-32 code units: [ 0x7a 0xdf 0x6c34 0x1f34c 0 ]
into 11 UTF-8 code units: [ 0x7a 0xc3 0x9f 0xe6 0xb0 0xb4 0xf0 0x9f 0x8d 0x8c 0 ]

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.28.1.4 The c32rtomb function (p: 401)

参阅

mbrtoc32
(C11)
 从窄多字节字符串生成下一个32位宽字符
(函数)


char16_t

< c‎ | string‎ | multibyte
定义于头文件 <uchar.h> |
typedef uint_least16_t char16_t; | (C11 起)
定义于头文件 <stdint.h> |
typedef /*implementation-defined*/ uint_least16_t ; | (C99 起)

char16_t 是用于 16 位宽字符的无符号整数类型，与 uint_least16_t 为同一类型。

uint_least16_t 是至少拥有 16 位宽度的最小无符号整数。

注意

任何给定平台上，类型 char16_t 的宽度可能大于 16 位，但存储于 char16_t 类型对象中的实际值将始终拥有 16 位宽度。

示例

#include <uchar.h>
#include <stdio.h>

int main(void)
{
    char16_t wcs[] = u"zß水🍌"; // 或 "z\u00df\u6c34\U0001f34c"
    size_t wcs_sz = sizeof wcs / sizeof *wcs;
    printf("%zu UTF-16 code units: [ ", wcs_sz);
    for (size_t n = 0; n < wcs_sz; ++n) printf("%#x ", wcs[n]);
    printf("]\n");
}

可能的输出：

6 UTF-16 code units: [ 0x7a 0xdf 0x6c34 0xd83c 0xdf4c 0 ]

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.28 Unicode utilities <uchar.h> (p: 398)
  • 7.20.1.2 Minimum-width integer types (p: 290)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.18.1.2 Minimum-width integer types (p: 256)

参阅


char32_t

< c‎ | string‎ | multibyte
定义于头文件 <uchar.h> |
typedef uint_least32_t char32_t; | (C11 起)
定义于头文件 <stdint.h> |
typedef /*implementation-defined*/ uint_least32_t ; | (C99 起)

char32_t 是用于 32 位宽字符的无符号整数类型，与 uint_least32_t 为同一类型。

uint_least32_t 是至少拥有 32 位的最小无符号整数类型。

注意

任何给定平台上，类型 char32_t 的宽度可能大于 32 位，但存储于 char32_t 类型对象中的实际值将始终拥有 32 位宽度。

示例

#include <uchar.h>
#include <stdio.h>

int main(void)
{
    char32_t wc[] = U"zß水🍌"; // 或 "z\u00df\u6c34\U0001f34c"
    size_t wc_sz = sizeof wc / sizeof *wc;
    printf("%zu UTF-32 code units: [ ", wc_sz);
    for (size_t n = 0; n < wc_sz; ++n) printf("%#x ", wc[n]);
    printf("]\n");
}

可能的输出：

5 UTF-32 code units: [ 0x7a 0xdf 0x6c34 0x1f34c 0 ]

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.28 Unicode utilities <uchar.h> (p: 398)
  • 7.20.1.2 Minimum-width integer types (p: 290)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.18.1.2 Minimum-width integer types (p: 256)

参阅


mblen

< c‎ | string‎ | multibyte
定义于头文件 <stdlib.h>
int mblen( const char* s, size_t n );

确定 s 指向其首字节的多字节字符的字节大小。

若 s 是空指针，则重置全局转换状态并 (C23 前)确定是否使用迁移序列。

此函数等价于调用 mbtowc ((wchar_t*)0, s, n) ，除了 mbtowc 的转换状态不受影响。

参数

s | - | 指向多字节字符的指针
n | - | s中能被检验的字节数限制

返回值

若 s 不是空指针，则返回多字节字符所含的字节数，或若 s 所指的首字节不组成合法多字节字符则返回 -1 ，或若 s 指向空字符 '\0' 则返回 ​0​ 。

若 s 是空指针，则重置内部转换状态为初始迁移状态， (C23 前)若当前多字节编码非状态依赖（不使用迁移序列）则返回 ​0​ ，或者若当前多字节编码为状态依赖（使用迁移序列）则返回非零。

注解

每次对 mblen 的调用更新内部全局转换状态（ mbstate_t 类型的静态对象，只为此函数所知）。若多字节编码使用迁移状态，则必须留意以避免回撤或多次扫描。任何情况下，多线程不应无同步地调用 mblen ：可用 mbrlen 代替。 | (C23 前)
不允许 mblen 拥有内部状态。 | (C23 起)

示例

#include <string.h>
#include <stdlib.h>
#include <locale.h>
#include <stdio.h>

// 多字节字符串的字符数是 mblen() 的和
// 注意：更简单的手段是 mbstowcs(NULL, str, sz)
size_t strlen_mb(const char* ptr)
{
    size_t result = 0;
    const char* end = ptr + strlen(ptr);
    mblen(NULL, 0); // 重置转换状态
    while(ptr < end) {
        int next = mblen(ptr, end - ptr);
        if(next == -1) {
           perror("strlen_mb");
           break;
        }
        ptr += next;
        ++result;
    }
    return result;
}

void dump_bytes(const char* str)
{
    const char* end = str + strlen(str);
    for (; str != end; ++str) {
        printf("%02X ", (unsigned char)str[0]);
    }
    printf("\n");
}

int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    const char* str = "z\u00df\u6c34\U0001f34c";
    printf("The string \"%s\" consists of %zu characters, but %zu bytes: ",
            str, strlen_mb(str), strlen(str));
    dump_bytes(str);
}

可能的输出：

The string "zß水🍌" consists of 4 characters, but 10 bytes: 7A C3 9F E6 B0 B4 F0 9F 8D 8C

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.22.7.1 The mblen function (p: 260)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.7.1 The mblen function (p: 357)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.7.1 The mblen function (p: 321)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.7.1 The mblen function

参阅

mbtowc | 将下一个多字节字符转换成宽字符 (函数)
mbrlen (C95) | 给定状态，返回下一个多字节字符的字节数 (函数)


mbrlen

< c‎ | string‎ | multibyte
定义于头文件 <wchar.h> |
size_t mbrlen( const char *s, size_t n, mbstate_t *ps ); | (C95 起) (C99 前)
size_t mbrlen( const char *restrict s, size_t n, mbstate_t *restrict ps ); | (C99 起)

给定当前转换状态 ps ，确定 s 所指向的剩余多字节字符的字节大小。

此函数等价于对于某个隐藏的 mbstate_t 类型对象 internal 调用 mbrtowc ( NULL, s, n, ps?ps:&internal) ，除了只求值 ps 一次。

参数

s | - | 指向多字节字符串首元素的指针
n | - | s 中能检验的字节数限制
ps | - | 指向保有转换状态的对象的指针

返回值

应用下个首个可用者：

  • ​0​ ，若接下来 n 个或更少字节组成空字符，或 s 为空指针。两种情况下都重置转换状态。
  • 字节数 [1...n] ，这些字节组成合法的多字节字符。
  • ( size_t )-2 ，若接下来 n 个字节是可能合法的多字节字符的一部分，但在检验所有 n 个字节后仍不完整
  • ( size_t )-1 ，若出现编码错误。设置 errno 的值为 EILSEQ ；转换状态未指定。

示例

#include <locale.h>
#include <string.h>
#include <stdio.h>
#include <wchar.h>

int main(void)
{
    // 允许 mbrlen() 以 UTF-8 多字节编码工作
    setlocale(LC_ALL, "en_US.utf8");
    // UTF-8 窄多字节编码
    const char* str = u8"水";
    size_t sz = strlen(str);

    mbstate_t mb;
    memset(&mb, 0, sizeof mb);
    int len1 = mbrlen(str, 1, &mb);
    if(len1 == -2)
        printf("The first 1 byte of %s is an incomplete multibyte char"
               " (mbrlen returns -2)\n", str);

    int len2 = mbrlen(str+1, sz-1, &mb);
    printf("The remaining %zu  bytes of %s hold %d bytes of the multibyte"
           " character\n", sz-1, str, len2);

    printf("Attempting to call mbrlen() in the middle of %s while in initial"
           " shift state returns %zd\n", str, mbrlen(str+1, sz-1, &mb));
}

输出：

The first 1 byte of 水 is an incomplete multibyte char (mbrlen returns -2)
The remaining 2  bytes of 水 hold 2 bytes of the multibyte character
Attempting to call mbrlen() in the middle of 水 while in initial shift state returns -1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.6.3.1 The mbrlen function (p: 442)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.6.3.1 The mbrlen function (p: 388)

参阅

mbrtowc (C95) | 给定状态，将下一个多字节字符转换成宽字符 (函数)
mblen | 返回下一个多字节字符的字节数 (函数)


mbrtoc16

< c‎ | string‎ | multibyte
定义于头文件 <uchar.h> |
size_t mbrtoc16( char16_t * restrict pc16, const char * restrict s, size_t n, mbstate_t * restrict ps ); | (C11 起)

从单个编码点的多字节字符表示将它转换成其变长 16 位宽字符（典型地为 UTF-16 ）表示。

若 s 不是空指针，则审查从 s 所指的字节开始的多字节字符串的至多 n 个字节，以检查完成下个多字节字符的字节数（包含任何迁移序列）。若函数确定 s 中下个多字节字符完整且合法，则将它转换到对应的 16 位宽字符，并将它存储于 *pc16 （若 pc16 非空）。

若 *s 中的宽字符对应多 char16_t 序列（例如 UTF-16 中的代理对），则在首次调用此函数后更新 *ps ，以令下次到 mbrtoc16 的调用将写出额外的 char16_t ，而不考虑 *s 。

若 s 是空指针，则忽略 n 与 pc16 的值，而调用等价于 mbrtoc16( NULL, "", 1, ps) 。

若产生的宽字符是空字符，则转换状态 *ps 表示初始迁移状态。

若定义 __STDC_UTF_16__ 宏，则此函数使用的 16 位编码是 UTF-16 ；否则它是实现定义的。任何情况下，此函数所用的多字节字符编码为当前活跃的 C 本地环境所指定。

参数

pc16 | - | 指向将写入产生的 16-bit 宽字符的位置的指针
s | - | 指向用作输入的多字节字符串的指针
n | - | 能检验的字节数上的限制
ps | - | 指向转译多字节字符串时所用转换状态对象的指针

返回值

下列首个能应用者：

  • 若从 s 转换的字符是空字符（并存储于 *pc16 ，若它非空），则为 ​0​ 。
  • 成功从 s 转换的多字节字符的字节数 [1...n] 。
  • 若下个 char16_t 组成多 char16_t 字符，并已写入 *pc16 ，则为 ( size_t )-3 。此情况下不从输入处理字节。
  • 若接下来 n 个字符组成不完整，但到此还合法的多字节字符，则为 ( size_t )-2 。不写入 *pc16 。
  • 若出现编码错误则为 ( size_t )-1 。不写入 *pc16 ，存储值 EILSEQ 于 errno ，且 *ps 状态未指定。

示例

#include <stdio.h>
#include <locale.h>
#include <uchar.h>
#include <stdint.h>

mbstate_t state;
int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    char in[] = u8"zß水🍌"; // 或 "z\u00df\u6c34\U0001F34C"
    size_t in_sz = sizeof in / sizeof *in;

    printf("Processing %zu UTF-8 code units: [ ", in_sz);
    for(size_t n = 0; n < in_sz; ++n) printf("%#x ", (unsigned char)in[n]);
    puts("]");

    char16_t out[in_sz];
    char *p_in = in, *end = in + in_sz;
    char16_t *p_out = out;
    size_t rc;
    while((rc = mbrtoc16(p_out, p_in, end - p_in, &state)))
    {
        if(rc == (size_t)-3) // UTF-16 中的代理对
            p_out += 1;
        else if(rc <= SIZE_MAX / 2) {
            p_in += rc;
            p_out += 1;
        } else break;
    }

    size_t out_sz = p_out - out + 1;
    printf("into %zu UTF-16 code units: [ ", out_sz);
    for(size_t x = 0; x < out_sz; ++x) printf("%#x ", out[x]);
    puts("]");
}

输出：

Processing 11 UTF-8 code units: [ 0x7a 0xc3 0x9f 0xe6 0xb0 0xb4 0xf0 0x9f 0x8d 0x8c 0 ]
into 6 UTF-16 code units: [ 0x7a 0xdf 0x6c34 0xd83c 0xdf4c 0 ]

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.28.1.1 The mbrtoc16 function (p: 398-399)

参阅

c16rtomb
(C11)
 将16位宽字符转换成窄多字节字符串
(函数)


mbrtoc32

< c‎ | string‎ | multibyte
定义于头文件 <uchar.h> |
size_t mbrtoc32( char32_t restrict * pc32, const char * restrict s, size_t n, mbstate_t * restrict ps ); | (C11 起)

从窄多字符编码转换编码点到其变长 32 位宽字符表示（但典型地为 UTF-32 ）。

若 s 不是空指针，则审查以 s 所指向的字节开始的多字节字符串的至多 n 个字节，以确定完成下个多字节字符所需的字节数（包含任何迁移序列）。若函数确定 s 中下个多字节字符完整且合法，则将它转换成对应的 32 位宽字符并存储于 *pc32 （若 pc32 非空）。

若 *s 中下个多字节字符对应多 char32_t 序列（对于 UTF-32 不可能），则在首次调用此函数后更新 *ps ，以满足下次到 mbrtoc32 的调用将写出附加的 char32_t ，而不考虑 *s 。

若 s 是空指针，则忽略 n 与 pc32 的值，而调用等价于 mbrtoc32( NULL, "", 1, ps) 。

若产生的宽字符是空字符，则转换状态 *ps 表示初始迁移状态。

若定义宏 __STDC_UTF_32__ ，则此函数所用的 32 位编码是 UTF-32 ；否则它是实现定义的。任何情况下，此函数所用的多字节编码为当前活跃的 C 本地环境所指定。

参数

pc32 | - | 指向将写入产生的 32 位宽字符的位置的指针
s | - | 指向用作输入的多字节字符串的指针
n | - | s 中能检验的字节数上的限制
ps | - | 指向转译多字节字符串时所用的转换状态对象的指针

返回值

下列首个应用者：

  • 若从 s 转换的字符为空字符（并存储于 *pc32 中，若它非空）则为 ​0​ 。
  • 成功从 s 转换的多字节字符的字节数 [1...n] 。
  • 若现已将来自多 char32_t 字符的下个 char32_t 写入 *pc32 ，则为 ( size_t )-3 。此情况下不从输入处理字节。
  • 若接下来 n 个字节组成不完整，但到此仍合法的多字节字符则为 ( size_t )-2 。不写入内容到 *pc32 。
  • 若出现编码错误则为 ( size_t )-1 。不写入内容到 *pc32 ，存储 EILSEQ 于 errno 且 *ps 的值未指定。

示例

#include <stdio.h>
#include <locale.h>
#include <string.h>
#include <uchar.h>
#include <assert.h>

mbstate_t state;
int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    char in[] = u8"zß水🍌"; // 或 "z\u00df\u6c34\U0001F34C"
    size_t in_sz = sizeof in / sizeof *in;

    printf("Processing %zu UTF-8 code units: [ ", in_sz);
    for(size_t n = 0; n < in_sz; ++n) printf("%#x ", (unsigned char)in[n]);
    puts("]");

    char32_t out[in_sz];
    char *p_in = in, *end = in + in_sz;
    char32_t *p_out = out;
    size_t rc;
    while((rc = mbrtoc32(p_out, p_in, end - p_in, &state)))
    {
        assert(rc != (size_t)-3); // UTF-32 中无代理对
        if(rc > ((size_t)-1) / 2) break;
        p_in += rc;
        p_out += 1;
    }

    size_t out_sz = p_out - out + 1;
    printf("into %zu UTF-32 code units: [ ", out_sz);
    for(size_t x = 0; x < out_sz; ++x) printf("%#x ", out[x]);
    puts("]");
}

输出：

Processing 11 UTF-8 code units: [ 0x7a 0xc3 0x9f 0xe6 0xb0 0xb4 0xf0 0x9f 0x8d 0x8c 0 ]
into 5 UTF-32 code units: [ 0x7a 0xdf 0x6c34 0x1f34c 0 ]

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.28.1.3 The mbrtoc32 function (p: 400-401)

参阅

c32rtomb
(C11)
 将32位宽字符转换成窄多字节字符串
(函数)


mbrtowc

< c‎ | string‎ | multibyte
定义于头文件 <wchar.h> |
size_t mbrtowc( wchar_t* pwc, const char* s, size_t n, mbstate_t * ps ); | (C95 起) (C99 前)
size_t mbrtowc( wchar_t * restrict pwc, const char * restrict s, size_t n, mbstate_t * restrict ps); | (C99 起)

转换窄多字节字符为宽字符。

若 s 不是空指针，则从 s 所指向的字节起，审查多字节字符串的至多 n 个字节，以确定完成下个多字节字符（包含任何迁移序列）的字节数。若该函数确定 s 的下个多字节字符完整且合法，则将它转换为对应的宽字符，并存储之于 *pwc （若 pwc 非空）。

若 s 是空指针，则忽略 n 和 pwc 的值，调用等价于 mbrtowc( NULL, "", 1, ps) 。

若产生的宽字符是空字符，则存储于 *ps 的转换状态为初始迁移状态。

参数

pwc | - | 指向要写入结果宽字符位置的指针
s | - | 指向用作输入的多字节字符串的指针
n | - | s 中能被检验的字节数限制
ps | - | 指向转译多字节字符串时的转换状态的指针

返回值

应用下列最前者：

  • 若自 s 转换的字符为空字符，则为 ​0​ （且存储于pwc若它非空）
  • 成功 s 从转换的多字节字符 [1...n] 的字节数
  • 若接下来的 n 字节组成不完整，但该部分合法的宽字符，则为 ( size_t )-2 。不写入 *pwc 。
  • 若出现编码错误则为 ( size_t )-1 。不写入 *pwc ，存储值 EILSEQ 于 errno ，并且置 *ps 的值为未指定。

示例

#include <stdio.h>
#include <locale.h>
#include <string.h>
#include <wchar.h>

// 打印多字节字符串到宽面向的 stdout
// 等价于 wprintf(L"%s\n", ptr);
void print_mb(const char* ptr)
{
    mbstate_t state;
    memset(&state, 0, sizeof state);
    const char* end = ptr + strlen(ptr);
    int len;
    wchar_t wc;
    while((len = mbrtowc(&wc, ptr, end-ptr, &state)) > 0) {
        wprintf(L"Next %d bytes are the character %lc \n", len, wc);
        ptr += len;
    }
}

int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    // UTF-8 窄多字符编码
    print_mb(u8"z\u00df\u6c34\U0001F34C"); // 或 u8"zß水🍌"
}

输出：

Next 1 bytes are the character z
Next 2 bytes are the character ß
Next 3 bytes are the character 水
Next 4 bytes are the character 🍌

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.6.3.2 The mbrtowc function (p: 443)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.6.3.2 The mbrtowc function (p: 389)

参阅

mbtowc | 将下一个多字节字符转换成宽字符 (函数)
wcrtombwcrtomb_s (C95)(C11) | 给定状态，将宽字符转换成其多字节表示 (函数)


mbsinit

< c‎ | string‎ | multibyte
定义于头文件 <wchar.h> |
int mbsinit( const mbstate_t * ps); | (C95 起)

若 ps 不是空指针，则 mbsinit 函数确定其所指向的 mbstate_t 对象是否描述初始迁移状态。

注意

尽管零初始化的 mbstate_t 始终表示初始转换状态，亦可能有其他 mbstate_t 值表示初始转换状态。

参数

ps - 指向要检验的 mbstate_t 对象的指针

返回值

若 ps 不是空指针且不表示初始迁移状态则为 ​0​ ，否则为非零。

示例

#include <locale.h>
#include <string.h>
#include <stdio.h>
#include <wchar.h>

int main(void)
{
    // 允许mbrlen()作用于UTF-8多字节字符串
    setlocale(LC_ALL, "en_US.utf8");
    // UTF-8 narrow multibyte encoding
    const char* str = u8"水"; // 或 u8"\u6c34" 或 "\xe6\xb0\xb4"
    static mbstate_t mb; // 零初始化
    (void)mbrlen(&str[0], 1, &mb);
    if (!mbsinit(&mb)) {
        printf("After processing the first 1 byte of %s,\n"
               "the conversion state is not initial\n\n", str);
    }

    (void)mbrlen(&str[1], strlen(str), &mb);
    if (mbsinit(&mb)) {
        printf("After processing the remaining 2 bytes of %s,\n"
               "the conversion state is initial conversion state\n", str);
    }
}

输出：

After processing the first 1 byte of 水,
the conversion state is not initial

After processing the remaining 2 bytes of 水,
the conversion state is initial conversion state

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.6.2.1 The mbsinit function (p: 441-442)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.6.2.1 The mbsinit function (p: 387-388)

参阅

mbstate_t
(C95)
 迭代多字节字符串所需的转换信息
(结构体)


mbsrtowcs, mbsrtowcs_s

< c‎ | string‎ | multibyte
定义于头文件 <wchar.h> |  |
 | (1) |
size_t mbsrtowcs( wchar_t* dst, const char** src, size_t len, mbstate_t * ps ); |  |  | (C95 起) (C99 前)
size_t mbsrtowcs( wchar_t *restrict dst, const char **restrict src, size_t len, mbstate_t *restrict ps ); |  |  | (C99 起)
errno_t mbsrtowcs_s( size_t *restrict retval, wchar_t *restrict dst, rsize_t dstsz, const char **restrict src, rsize_t len, mbstate_t *restrict ps); | (2) | (C11 起)
1) 转换始于 *ps 所描述的转换状态，来自首元素为 *src 所指向的数组的空终止多字节字符序列，到其宽字符表示。若 dst 非空，则存储转换后的字符于 dst 所指向的 wchar_t 数组的相继元素。不写入多于 len 个宽字符到目标数组。如同以调用 mbrtowc 转换每个多字节字符。若满足下列条件则转换终止：
  • 转换并存储了多字节空字符。设置 *src 为空指针值并令 *ps 表示初始迁移状态。
  • 遇到任何非法多字节字符（按照当前 C 本地环境）。设置 *src 指向首个未转换的多字节字符的起始。
  • 将存储的下个宽字符将超出 len 。设置 *src 指向首个未转换的多字节字符的起始。若 dst 为空指针则不检查此条件。
2) 同 (1) ，除了
  • 函数返回其结果为输出参数 retval
  • 若在写入 len 个宽字符后未写入宽字符到 dst ，则存储 L'\0' 于 dst[len] ，这表示写入总计 len+1 个宽字符
  • 函数从空终止符到 dstsz 之间破坏目标数组
  • 若 src 与 dst 重叠，则行为未指定。
  • 在运行时检测下列错误并调用当前安装的制约处理函数：
  • retval 、 ps 、 src 或 *src 为空指针
  • dstsz 或 len 大于 RSIZE_MAX/sizeof(wchar_t) （除非 dst 为空）
  • dstsz 非空（除非 dst 为空）
  • *src 数组中的首 dstsz 个多字节字符中无空字符，且 len 大于 dstsz （除非 dst 为空）
同所有边界检查函数， mbsrtowcs_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 wchar.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dst | - | 指向将存储结果的宽字符数组的指针
src | - | 指向空终止多字节字符串首元素的指针
len | - | dst 所指向的字符数组中可用的宽字符数
ps | - | 指向转换状态对象的指针
dstsz | - | 将写入的最大宽字符数（ dst 数组大小）
retval | - | 指向存储结果的 size_t 对象的指针

返回值

1) 成功时返回写入字符数组的宽字符数，排除终止的 L'\0' 。若 dst 为空指针，则返回假如给定无限定长度则本会写入的宽字符数。转换错误时（若遇到非法多字节字符）返回 ( size_t )-1 ，存储 EILSEQ 于 errno ，并令 *ps 留在未指定状态。
2) 成功时为零（该情况下将写入或本会写入 dst 的宽字符数存储于 *retval ），错误时为非零。在运行时制约违规的情况下，存储 ( size_t )-1 于 *retval （除非 retval 为空）并设置 dst[0] 为 L'\0' （除非 dst 为空或 dstmax 为零或大于 RSIZE_MAX ）。

示例

#include <stdio.h>
#include <locale.h>
#include <wchar.h>
#include <string.h>

void print_as_wide(const char* mbstr)
{
    mbstate_t state;
    memset(&state, 0, sizeof state);
    size_t len = 1 + mbsrtowcs(NULL, &mbstr, 0, &state);
    wchar_t wstr[len];
    mbsrtowcs(&wstr[0], &mbstr, len, &state);
    wprintf(L"Wide string: %ls \n", wstr);
    wprintf(L"The length, including L'\\0': %d\n", len);
}

int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    print_as_wide(u8"z\u00df\u6c34\U0001f34c"); // u8"zß水🍌"
}

输出：

Wide string: zß水🍌
The length, including L'\0': 5

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.6.4.1 The mbsrtowcs function (p: 445)
  • K.3.9.3.2.1 The mbsrtowcs_s function (p: 648-649)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.6.4.1 The mbsrtowcs function (p: 391)

参阅

mbstowcsmbstowcs_s (C11) | 将窄多字节字符串转换成宽字符串 (函数)
mbrtowc (C95) | 给定状态，将下一个多字节字符转换成宽字符 (函数)
wcsrtombswcsrtombs_s (C95)(C11) | 给定状态，将宽字符串转换成窄多字节字符串 (函数)


mbstate_t

< c‎ | string‎ | multibyte
定义于头文件 <uchar.h> | (C11 起)
定义于头文件 <wchar.h> |
struct mbstate_t; | (C95 起)

类型 mbstate_t 是平凡非数组类型，能表示任何能出现于实现定义的受支持多字节编码规则集合的转换状态。 mbstate_t 的零初始化值表示初始转换状态，尽管亦可能存在 mbstate_t 的其他值表示初始转换状态。

mbstate_t 的可行实现是一个结构体类型，保有表示不完整多字节字符的数组、指示数组中已处理字节数和当前迁移状态的表示。

由于可能的数据竞争，不从多个线程以空指针为 mbstate_t* 参数调用下列函数而不同步： mbrlen 、 mbrtowc 、 mbsrtowcs 、 mbtowc 、 wcrtomb 、 wcsrtombs 、 wctomb 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.1/2 Introduction (p: 402)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.1/2 Introduction (p: 348)

参阅

mbsinit
(C95)
 检查 mbstate_t 对象是否表示初始迁移状态
(函数)


mbstowcs, mbstowcs_s

< c‎ | string‎ | multibyte
定义于头文件 <stdlib.h> |  |
 | (1) |
size_t mbstowcs( wchar_t *dst, const char *src, size_t len) |  |  | (C99 前)
size_t mbstowcs( wchar_t *restrict dst, const char *restrict src, size_t len) |  |  | (C99 起)
errno_t mbstowcs_s( size_t *restrict retval, wchar_t *restrict dst, rsize_t dstsz, const char *restrict src, rsize_t len); | (2) | (C11 起)
1) 转换来自从首元素为 src 所指的数组的多字节字符串为其宽字符表示。被转换的字符存储于 dst 所指向数组的相继元素。写入目标数组的宽字符数不多于 len 。
如同以对 mbtowc 的调用转换每个字符，除了 mbtowc 转换状态不受影响。若满足任一条件则转换停止：
* 转换并存储了多字节空字符。
* 遇到（当前 C 本地环境中的）非法多字节字符。
* 本要存储的下个宽字符会超出 len 。
若 src 与 dst 重叠，则行为未定义
2) 同 (1) ，除了
* 转换如同以 mbrtowc ，而非 mbtowc
* 函数用输出参数 retval 返回结果
* 若在写入 len 个宽字符后未写入空字符到 dst ，则存储 L'\0' 于 dst[len] ，这表示总计写入 len+1 个宽字符
* 若 dst 是空指针，则存储本会产生的宽字符数于 *retval
* 函数从空终止到 dstsz 为止破坏目标数组
* 若 src 与 dst 重叠，则行为未指定。
* 在运行时检测下列错误，并调用当前安装的制约处理函数：
  • retval 或 src 是空指针
  • dstsz 或 len 大于 RSIZE_MAX/sizeof(wchar_t) （除非 dst 为空）
  • dstsz 非零（除非 dst 为空）
  • src 数组中的首 dstsz 个多字节中无空字符且 len 大于 dstsz （除非 dst 为空）
同所有边界检查函数， mbstowcs_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 stdlib.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

注意

多数实现中， mbstowcs 更新 mbstate_t 类型的全局静态对象，因为它通过字符串处理，而且不能由二个线程同时调用， mbsrtowcs 应当用于这种情况。

POSIX 指定一个常见扩展：若 dst 是空指针，则此函数返回假若转换则写入 dst 的宽字符数。同样的行为对于 mbstowcs_s 和 mbsrtowcs 是标准。

参数

dst | - | 指向要存储宽字符串的宽字符数组的指针
src | - | 指向要转换的空终止多字节字符串的首元素的指针
len | - | dst 所指向的数组中的可用宽字节数
dstsz | - | 将写入的最大宽字节数（ dst 数组的大小）
retval | - | 指向将存储结果的 size_t 对象的指针

返回值

1) 成功时，返回目标数组的宽字符数，不含终止符 L'\0' 。转换错误时（若遇到非法多字节字符），返回 ( size_t )-1 。
2) 成功时为零（该情况下写入或本该写入到 dst 的不含终止零的宽字符存储于 *retval ），错误时为非零，在运行时制约违规的情况，存储 ( size_t )-1 于 *retval （除非 retval 为空）并设置 dst[0] 为 L'\0' （除非 dst 为空或 dstmax 为零或大于 RSIZE_MAX ）

示例

#include <stdio.h>
#include <locale.h>
#include <stdlib.h>
#include <wchar.h>

int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    const char* mbstr = u8"z\u00df\u6c34\U0001F34C"; // or u8"zß水🍌"
    wchar_t wstr[5];
    mbstowcs(wstr, mbstr, 5);
    wprintf(L"MB string: %s\n", mbstr);
    wprintf(L"Wide string: %ls\n", wstr);
}

输出：

MB string: zß水🍌
Wide string: zß水🍌

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.8.1 The mbstowcs function (p: 359)
  • K.3.6.5.1 The mbstowcs_s function (p: 611-612)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.8.1 The mbstowcs function (p: 323)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.8.1 The mbstowcs function

参阅

mbsrtowcsmbsrtowcs_s (C95)(C11) | 给定状态，将窄多字节字符串转换成宽字符串 (函数)
wcstombswcstombs_s (C11) | 将宽字符串转换成窄多字节字符串 (函数)


mbtowc

< c‎ | string‎ | multibyte
定义于头文件 <stdlib.h> |
int mbtowc( wchar_t *pwc, const char *s, size_t n ) | (C99 前)
int mbtowc( wchar_t *restrict pwc, const char *restrict s, size_t n ) | (C99 起)

将 s 指向其首字节的多字节字符转换成宽字符，若 pwc 非空则写入 *pwc 。

若 s 为空指针，则重置全局转换状态并确定是否使用迁移序列。

注意

每次对 mbtowc 的调用更新内部全局转换状态（ mbstate_t 类型的静态对象，只为此函数所知）。若多字节编码使用迁移状态，则必须留意以避免回撤或多次扫描。任何情况下，多线程不应调用 mbtowc 而不同步：可用 mbrtowc 代替。

参数

pwc | - | 指向输出用宽字符的指针
s | - | 指向多字节字符的指针
n | - | s 中能被检验的字节数的限制

返回值

若 s 不是空指针，则返回多字节字符所含的字节数，或若 s 所指的首字节不组成合法多字节字符则返回 -1 ，或若 s 指向空字符 '\0' 则返回 ​0​ 。

若 s 是空指针，则重置内部转换状态为初始迁移状态，并若当前多字节编码非状态依赖（不使用迁移序列）则返回 ​0​ ，或若当前多字节编码为状态依赖（使用迁移序列）则返回非零值。

示例

#include <stdio.h>
#include <locale.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>

// 打印多字节字符串到宽面向的 stdout
// 等价于 wprintf(L"%s\n", ptr);
void print_mb(const char* ptr)
{
    mbtowc(NULL, 0, 0); // 重置初始转换状态
    const char* end = ptr + strlen(ptr);
    int ret;
    for (wchar_t wc; (ret = mbtowc(&wc, ptr, end-ptr)) > 0; ptr+=ret) {
        wprintf(L"%lc", wc);
    }
    wprintf(L"\n");
}

int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    // UTF-8 窄多字节编码
    print_mb(u8"z\u00df\u6c34\U0001F34C"); // 或 u8"zß水🍌"
}

输出：

zß水🍌

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.7.2 The mbtowc function (p: 358)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.7.2 The mbtowc function (p: 322)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.7.2 The mbtowc function

参阅

mbrtowc (C95) | 给定状态，将下一个多字节字符转换成宽字符 (函数)
mblen | 返回下一个多字节字符的字节数 (函数)


wcrtomb, wcrtomb_s

< c‎ | string‎ | multibyte
定义于头文件 <wchar.h> |  |
 | (1) |
size_t wcrtomb( char *s, wchar_t wc, mbstate_t *ps); |  |  | (C95 起)
size_t wcrtomb( char *restrict s, wchar_t wc, mbstate_t *restrict ps); |  |  | (C99 起)
errno_t wcrtomb_s( size_t *restrict retval, char *restrict s, rsize_t ssz, wchar_t wc, mbstate_t *restrict ps); | (2) | (C11 起)

转换宽字符为其窄多字节表示。

1) 若 s 不是空指针，则函数检测存储 wc 的多字节字符表示所需的字节数（包含任何迁移序列，并考虑当前多字节转换状态 *ps ，并存储多字节字符表示于首元素为 s 所指向的字符数组，按需更新 *ps 。此函数至多能写入 MB_CUR_MAX 字节。
若 s 为空指针，则调用等价于对某内部缓冲区 buf 的 wcrtomb(buf, L'\0', ps) 。
若 wc 是空宽字符 L'\0' ，则存储空字节，前接任何恢复到初始迁移状态所需的迁移序列，并更新转换状态参数 *ps 以表示其初始迁移状态。
若定义环境宏 __STDC_ISO_10646__ ，则 wchar_t 类型的值与 Unicode 要求集（典型地为 UTF-32 编码）中字符的短标识符相同；否则它是实现定义的。任何情况下，此函数所用的多字节字符编码为当前活跃的 C 本地环境所指定。
2) 同 (1) ，除了
若 s 为空指针，则调用等价于用内部变量 retval 和 buf （其大小大于 MB_CUR_MAX ）的 wcrtomb_s(&retval, buf, sizeof buf, L'\0', ps)
返回结果于输出参数 retval
在运行时检测下列错误，并调用当前安装的制约处理函数：
  • retval 或 ps 为空指针。
  • ssz 为零或大于 RSIZE_MAX （除非 s 为空）
  • ssz 小于会写入的字节数（除非 s 为空）
  • s 为空指针但 ssz 非零
同所有边界检查函数， wcrtomb_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 wchar.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

s | - | 指向窄字符数组的指针，其中将存储多字节字符串
wc | - | 要转换的宽字符
ps | - | 指向转译多字节字符串时所用的转换状态对象的指针
ssz | - | 要写入的最大字节数（缓冲区 s 的大小）
retval | - | 指向输出参数的指针，将存储结果于其中（多字节字符串的字节数，包含任何迁移序列）

返回值

1) 成功时，返回写入首元素为 s 所指向的字符数组的字节数（包含任何迁移序列）。
失败时（若 wc 不是合法宽字符），返回 ( size_t )-1 ，存储 EILSEQ 于 errno ，并使 *ps 留在未指定状态。
2) 成功时返回零。失败时返回非零，该情况下，设置 s[0] 为 '\0' （除非 s 为空或 ssz 为零或大于 RSIZE_MAX ）并设置 *retval 为 ( size_t )-1 （除非 retval 为空）。

示例

#include <stdio.h>
#include <locale.h>
#include <string.h>
#include <wchar.h>
#include <stdlib.h>

int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    mbstate_t state;
    memset(&state, 0, sizeof state);
    wchar_t in[] = L"zß水🍌"; // 或 "z\u00df\u6c34\U0001F34C"
    size_t in_sz = sizeof in / sizeof *in;

    printf("Processing %zu wchar_t units: [ ", in_sz);
    for(size_t n = 0; n < in_sz; ++n) printf("%#x ", in[n]);
    puts("]");

    char out[MB_CUR_MAX * in_sz];
    char *p = out;
    for(size_t n = 0; n < in_sz; ++n) {
        size_t rc = wcrtomb(p, in[n], &state);
        if(rc == (size_t)-1) break;
        p += rc;
    }

    size_t out_sz = p - out;
    printf("into %zu UTF-8 code units: [ ", out_sz);
    for(size_t x = 0; x < out_sz; ++x) printf("%#x ", +(unsigned char)out[x]);
    puts("]");
}

输出：

Processing 5 wchar_t units: [ 0x7a 0xdf 0x6c34 0x1f34c 0 ]
into 11 UTF-8 code units: [ 0x7a 0xc3 0x9f 0xe6 0xb0 0xb4 0xf0 0x9f 0x8d 0x8c 0 ]

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.6.3.3 The wcrtomb function (p: 444)
  • K.3.9.3.1.1 The wcrtomb_s function (p: 647-648)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.6.3.3 The wcrtomb function (p: 390)

参阅

wctombwctomb_s (C11) | 将宽字符转换成其多字节表示 (函数)
mbrtowc (C95) | 给定状态，将下一个多字节字符转换成宽字符 (函数)


wcsrtombs, wcsrtombs_s

< c‎ | string‎ | multibyte
定义于头文件 <wchar.h> |  |
 | (1) |
size_t wcsrtombs( char *dst, const wchar_t **src, size_t len, mbstate_t * ps ); |  |  | (C95 起) (C99 前)
size_t wcsrtombs( char *restrict dst, const wchar_t **restrict src, size_t len, mbstate_t *restrict ps ); |  |  | (C99 起)
errno_t wcsrtombs_s( size_t *restrict retval, char *restrict dst, rsize_t dstsz, const wchar_t **restrict src, rsize_t len, mbstate_t *restrict ps); | (2) | (C11 起)
1) 转换来自元素为 *src 所指向的宽字符序列为其窄多字节表示，始于 *ps 所描述的转换状态。若 dst 非空，则存储转换后的字符于 dst 所指向的字符数组的相接元素。不写入多于 len 个字节到目标数组。如同以调用 wcrtomb 转换每个字符。若遇到下列条件则停止转换：
  • 转换并存储了空字符 L'\0' 。此情况下存储的字节是反迁移序列（若需要）后随 '\0' ，设置 *src 为空指针值并令 *ps 表示初始迁移状态。
  • 找到当前 C 本地环境中不对应合法字符的 wchar_t 。设置 *src 指向首个未转换的宽字符。
  • 下个多字节字符将超出 len 。设置 *src 指向首个未转换的宽字符。若 dst 为空指针则不检查此条件。
2) 同 (1) ，除了
  • 函数返回其结果为输出参数 retval
  • 若转换停止而不写入空字符，则函数将存储 '\0' 于 dst 的下个字节，它可以是 dst[len] 或 dst[dstsz] ，两者的先到来者（表示总共可能写入 len+1/dstsz+1 字节）。此情况下，在终止空字符前可以无反迁移序列。
  • 函数从终止空字符 dstsz 到位置破坏数组
  • 若 src 与 dst 重叠，则行为未指定。
  • 在运行时检测下列错误并调用当前安装的制约处理函数：
  • retval 、 ps 、 src 或 *src 为空指针
  • dstsz 或 len 大于 RSIZE_MAX （除非 dst 为空）
  • dstsz 非零（除非 dst 为空）
  • len 大于 dstsz 且转换在抵达 dstsz 时于 src 数组中未遇到空字符或编码错误（除非 dst 为空）
同所有边界检查函数， wcsrtombs_s 仅若实现定义 __STDC_LIB_EXT1__ 且用户在包含 wchar.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dst | - | 指向窄字符数组的指针，其中将存储多字节字符
src | - | 指向指向空终止宽字符串首元素的指针的指针
len | - | dst 所指向的数组中可用的字节数
ps | - | 指向转换状态对象的指针
dstsz | - | 将写入的最大字节数（ dst 数组的大小）
retval | - | 指向将存储结果于其中的 size_t 对象的指针

返回值

1) 成功时，返回写入首元素为 dst 所指向的字符数组的字节数（包含任何迁移序列，但不包含终止 '\0' ）。若 ds 为空指针，则返回本会写入的字节数。错误时（若遇到非法宽字符），返回 ( size_t )-1 ，存储 EILSEQ 于 errno ，并令 *ps 留在未指定状态。
2) 成功时返回零（该情况下将不包含终止零写入或本会写入到 dst 的字符数存储于 *retval ），错误时返回非零。在运行时制约违规的情况下，存储 ( size_t )-1 于 *retval （除非 retval 为空）并设置 dst[0] 为 '\0' （除非 dst 为空或 dstmax 为零或大于 RSIZE_MAX ）。

示例

#include <stdio.h>
#include <locale.h>
#include <string.h>
#include <wchar.h>

void print_wide(const wchar_t* wstr)
{
    mbstate_t state;
    memset(&state, 0, sizeof state);
    size_t len = 1 + wcsrtombs(NULL, &wstr, 0, &state);
    char mbstr[len];
    wcsrtombs(mbstr, &wstr, len, &state);
    printf("Multibyte string: %s\n", mbstr);
    printf("Length, including '\\0': %d\n", len);
}

int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    print_wide(L"z\u00df\u6c34\U0001f34c"); // 或 L"zß水🍌"
}

输出：

Multibyte string: zß水🍌
Length, including '\0': 11

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.6.4.2 The wcsrtombs function (p: 446)
  • K.3.9.3.2.2 The wcsrtombs_s function (p: 649-651)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.6.4.2 The wcsrtombs function (p: 392)

参阅

wcstombswcstombs_s (C11) | 将宽字符串转换成窄多字节字符串 (函数)
wcrtombwcrtomb_s (C95)(C11) | 给定状态，将宽字符转换成其多字节表示 (函数)
mbsrtowcsmbsrtowcs_s (C95)(C11) | 给定状态，将窄多字节字符串转换成宽字符串 (函数)


wcstombs, wcstombs_s

< c‎ | string‎ | multibyte
定义于头文件 <stdlib.h> |  |
 | (1) |
size_t wcstombs( char *dst, const wchar_t *src, size_t len ); |  |  | (C99 前)
size_t wcstombs( char *restrict dst, const wchar_t *restrict src, size_t len ); |  |  | (C99 起)
errno_t wcstombs_s( size_t *restrict retval, char *restrict dst, rsize_t dstsz, const wchar_t *restrict src, rsize_t len ); | (2) | (C11 起)
1) 转换来自首元素为 src 所指向的数组到其始于初始迁移状态的多字节表示。转换出的字符被存储于 dst 所指向的数组的相继元素。写入目标数组的字节数不多于 len 。
如同以调用 wctomb 每个字符，除了 wctomb 的转换状态不受影响。若满足下列条件则转换停止：
* 转换并存储空字符 L'\0' 。此情况下存储的字节为无迁移序列（若需要）后随 '\0' ，
* 找到当前 C 本地环境中不对应合法字符的 wchar_t 。
* 下个要存储的多字节字符会超出 len 。
若 src 与 dst 重叠，则行为未指定。
2) 同 (1) ，除了
* 转换如同以 wcrtomb ，而非 wctomb
* 函数将其结果作为输出参数 retval 返回
* 若转换停止而不写入控制符，则函数将在 dst 中的下个字符，可以是 dst[len] 或 dst[dstsz] 的先到来者，存储 '\0' （表示可能写入总计至多 len+1/dsz+1 个字符）。该情况下，空终止前不写入无迁移序列。
* 若 dst 是空指针，则将本会产生的字节数存储于 *retval
* 函数从空终止起到 dstsz 前为止破坏目标数组
* 若 src 与 dst 重叠，则行为未指定。
* 在运行时检测下列错误，并调用当前安装的制约处理函数：
  • retval 或 src 是空指针
  • dstsz 或 len 大于 RSIZE_MAX （除非 dst 为空）
  • dstsz 非零（除非 dst 为空）
  • len 大于 dstsz 且直到抵达 dstsz 时，转换未于 src 数组遇到空字符或编码错误（除非 dst 为空）
同所有边界检查函数， wcstombs_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 stdlib.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

注意

大多数实现中， wcstombs 在处理过字符串时更新 mbstate_t 类型的全局静态对象，而且不能为二个线程同时调用，这种情况下应使用 wcsrtombs 或 wcstombs_s 。

POSIX 指定一个常见扩展：若 dst 是空指针，则此函数返回假设转换则会写入 dst 的字节数。类似行为对于 wcsrtombs 和 wcstombs_s 是标准。

参数

dst | - | 指向窄字符数组的指针，其中将存储多字节字符
src | - | 指向要转换的空终止宽字符串首字符的指针
len | - | dst 所指向数组中的可用字节数
dstsz | - | 将写入的最大字节数（ dst 数组的大小）
retval | - | 指向 size_t 对象的指针，其中将存储结果

返回值

1) 成功时，返回写入首元素为 dst 所指向的字符数组的字节数（包含任何迁移序列，但不含终止的 '\0' ）。转换错误时（若遇到非法宽字符），返回 ( size_t )-1 。
2) 成功时返回零（该情况下，将被或本应写入 dst 的字节数，排除终止零，存储于 *retval ），错误时返回非零。运行时制约违规的情况下，存储 ( size_t )-1 于 *retval （除非 retval 为空）并设置 dst[0] 为 '\0' （除非 dst 为空或 dstmax 为零或大于 RSIZE_MAX ）。

示例

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>

int main(void)
{
    // 4 wide characters
    const wchar_t src[] = L"z\u00df\u6c34\U0001f34c";
    // 它们于 UTF-8 占用 10 个字节
    char dst[11];

    setlocale(LC_ALL, "en_US.utf8");
    printf("wide-character string: '%ls'\n",src);
    for (size_t ndx=0; ndx < sizeof src/sizeof src[0]; ++ndx)
        printf("   src[%2zu] = %#8x\n", ndx, src[ndx]);

    int rtn_val = wcstombs(dst, src, sizeof dst);
    printf("rtn_val = %d\n", rtn_val);
    if (rtn_val > 0)
        printf("multibyte string:  '%s'\n",dst);
    for (size_t ndx=0; ndx<sizeof dst; ++ndx)
        printf("   dst[%2zu] = %#2x\n", ndx, (unsigned char)dst[ndx]);
}

输出：

wide-character string: 'zß水🍌'
   src[ 0] =     0x7a
   src[ 1] =     0xdf
   src[ 2] =   0x6c34
   src[ 3] =  0x1f34c
   src[ 4] =        0
rtn_val = 10
multibyte string:  'zß水🍌'
   dst[ 0] = 0x7a
   dst[ 1] = 0xc3
   dst[ 2] = 0x9f
   dst[ 3] = 0xe6
   dst[ 4] = 0xb0
   dst[ 5] = 0xb4
   dst[ 6] = 0xf0
   dst[ 7] = 0x9f
   dst[ 8] = 0x8d
   dst[ 9] = 0x8c
   dst[10] =  0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.8.2 The wcstombs function (p: 360)
  • K.3.6.5.2 The wcstombs_s function (p: 612-614)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.8.2 The wcstombs function (p: 324)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.8.2 The wcstombs function

参阅

wcsrtombswcsrtombs_s (C95)(C11) | 给定状态，将宽字符串转换成窄多字节字符串 (函数)
mbstowcsmbstowcs_s (C11) | 将窄多字节字符串转换成宽字符串 (函数)


wctob

< c‎ | string‎ | multibyte
定义于头文件 <wchar.h> |
int wctob( wint_t c ); | (C95 起)

若宽字符 c 的多字节字符等价在初始迁移状态为单字节，则窄化它。

这典型地对来自 ASCII 字符集的字符可行，因为大多数多字节编码（如 UTF-8 ）用单字节编码这些字符。

参数

c - 要窄化的宽字符

返回值

若 c 不表示在初始迁移状态长度为 1 的多字节字符，则返回 EOF 。

否则，返回 c 作为 unsigned char 的单字节表示，并转换为 int 。

示例

#include <locale.h>
#include <wchar.h>
#include <stdio.h>
#include <assert.h>

void try_narrowing(wchar_t c)
{
    int cn = wctob(c);
    if(cn != EOF)
        printf("%#x narrowed to %#x\n", c, cn);
    else
        printf("%#x could not be narrowed\n", c);
}

int main(void)
{
    char* utf_locale_present = setlocale(LC_ALL, "th_TH.utf8");
    assert(utf_locale_present);
    puts("In Thai UTF-8 locale:");
    try_narrowing(L'a');
    try_narrowing(L'๛');

    char* tis_locale_present = setlocale(LC_ALL, "th_TH.tis620");
    assert(tis_locale_present);
    puts("In Thai TIS-620 locale:");
    try_narrowing(L'a');
    try_narrowing(L'๛');
}

可能的输出：

In Thai UTF-8 locale:
0x61 narrowed to 0x61
0xe5b could not be narrowed
In Thai TIS-620 locale:
0x61 narrowed to 0x61
0xe5b narrowed to 0xfb

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.6.1.2 The wctob function (p: 441)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.6.1.2 The wctob function (p: 387)

参阅

btowc
(C95)
 将单字节窄字符加宽成宽字符，倘若可能
(函数)


wctomb, wctomb_s

< c‎ | string‎ | multibyte
定义于头文件 <stdlib.h> |  |
int wctomb( char *s, wchar_t wc ); | (1) |
errno_t wctomb_s(int *restrict status, char *restrict s, rsize_t ssz, wchar_t wc); | (2) | (C11 起)
1) 转换宽字符 wc 为多字节编码，并存储之（含迁移状态）于 s 指向其首元素的字符数组。存储字节数不多于 MB_CUR_MAX 。
若 wc 是空字符，则将空字符写入 s ，之前可以有需要恢复初始迁移状态的任何迁移状态。
若 s 是空指针，则此函数重设全局转换状态并确定是否使用迁移序列。
2) 同 (1) ，除了结果被返回到输出参数 status ，在运行时检测下列错误，并调用当前安装的制约处理函数：
  • ssz 小于会被写入的字节数（除非 s 为空）
  • ssz 大于 RSIZE_MAX （除非 s 为空）
  • s 为空指针但 ssz 非零
同所有边界检查函数， wctomb_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 <stdlib.h> 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

注意

每次对 wctomb 的调用更新全局转换状态（ mbstate_t 类型的静态对象，只为此函数所知）。若多字节编码使用迁移状态，则此函数不可重入。任何情况下，多个线程不应调用 wctomb 而不同步：可使用 wcrtomb 或 wctomb_s 代替。

不同于大多数边界检查函数， wctomb_s 不以空字符终止其输出，因为它被设计以用于逐字节处理的循环。

参数

s | - | 指向输出用字符数组的指针
wc | - | 要转换的宽字符
ssz | - | 要写入 s 的最大字节数（数组 s 的大小）
status | - | 指向结果（多字节序列长度或迁移序列状态）存储位置的输出参数的指针

返回值

1) 若 s 非空指针，则返回 wc 的多字节表示所含的字节数，或者若 wc 非合法字符则为 -1 。
若 s 是空指针，则重设内部转换状态以表示初始迁移状态，并若当前多字节编码非状态依赖（不使用迁移序列）则返回 ​0​ ，或者若当前多字节编码为状态依赖（使用迁移序列）则返回非零值。
2) 成功时为零，此情况下存储 wc 的多字节表示于 s ，并存储其长度于 *status ，或若 s 为空，则存储迁移序列状态于 *status 。编码错误或运行时制约错误发生时为非零，此情况下存储 ( size_t )-1 于 *status 。存储于 *status 的值决不超过 MB_CUR_MAX 。

示例

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>

void demo(wchar_t wc)
{
    printf("State-dependent encoding?   %d\n", wctomb(NULL, wc));

    char mb[MB_CUR_MAX];
    int len = wctomb(mb,wc);
    printf("wide char '%lc' -> multibyte char '", wc);
    for (int idx = 0; idx < len; ++idx)
        printf("%#2x ", (unsigned char)mb[idx]);
    printf("'\n");
}

int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    printf("MB_CUR_MAX = %zu\n", MB_CUR_MAX);
    demo(L'A');
    demo(L'\u00df');
    demo(L'\U0001d10b');
}

可能的输出：

MB_CUR_MAX = 6
State-dependent encoding?   0
wide char 'A' -> multibyte char '0x41 '
State-dependent encoding?   0
wide char 'ß' -> multibyte char '0xc3 0x9f '
State-dependent encoding?   0
wide char '𝄋' -> multibyte char '0xf0 0x9d 0x84 0x8b '

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.22.7.3 The wctomb function (p: 358-359)
  • K.3.6.4.1 The wctomb_s function (p: 610-611)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.20.7.3 The wctomb function (p: 322-323)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.10.7.3 The wctomb function

参阅

mbtowc | 将下一个多字节字符转换成宽字符 (函数)
wcrtombwcrtomb_s (C95)(C11) | 给定状态，将宽字符转换成其多字节表示 (函数)


空终止宽字符串

< c‎ | string

空终止宽字符串（ NTWS ）是以空字符为结尾的合法宽字符序列。

函数

字符分类
定义于头文件 <wctype.h>
iswalnum
(C95)
 检查宽字符是否为字母或数字
(函数)
iswalpha
(C95)
 检查宽字符是否为字母
(函数)
iswlower
(C95)
 检查宽字符是否为小写
(函数)
iswupper
(C95)
 检查宽字符是否为大写
(函数)
iswdigit
(C95)
 检查宽字符是否为数字
(函数)
iswxdigit
(C95)
 检查宽字符是否为十六进制字符
(函数)
iswcntrl
(C95)
 检查宽字符是否为控制字符
(函数)
iswgraph
(C95)
 检查宽字符是否为图形字符
(函数)
iswspace
(C95)
 检查宽字符是否为空白符
(函数)
iswblank
(C99)
 检查宽字符是否为空格
(函数)
iswprint
(C95)
 检查宽字符是否为打印字符
(函数)
iswpunct
(C95)
 检查宽字符是否为标点符号
(函数)
iswctype
(C95)
 按照指定的 LC_CTYPE 类别分类宽字符
(函数)
wctype
(C95)
 查找当前 C 本地环境中的字符分类类别
(函数)
字符操作
定义于头文件 <wctype.h>
towlower
(C95)
 将宽字符转换为小写
(函数)
towupper
(C95)
 将宽字符转换为大写
(函数)
towctrans
(C95)
 按照指定的 LC_TYPE 映射分类进行字符映射
(函数)
wctrans
(C95)
 查找当前 C 本地环境中的字符映射类别
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
转换成数值格式
定义于头文件 <wchar.h>
wcstolwcstoll
(C95)(C99)
 将宽字符串转换成整数值
(函数)
wcstoulwcstoull
(C95)(C99)
 将宽字符串转换成无符号整数值
(函数)
wcstofwcstodwcstold
(C99)(C95)(C99)
 将宽字符串转换成浮点值
(函数)
定义于头文件 <inttypes.h>
wcstoimaxwcstoumax
(C99)(C99)
 将宽字符串转换成 intmax_t 或 uintmax_t
(函数)
字符串操作
定义于头文件 <wchar.h>
wcscpywcscpy_s
(C95)(C11)
 将一个宽字符串复制给另一个
(函数)
wcsncpywcsncpy_s
(C95)(C11)
 将一定量的宽字符从一个字符串复制到另一个
(函数)
wcscatwcscat_s
(C95)(C11)
 将一个宽字符串的副本后附于另一个
(函数)
wcsncatwcsncat_s
(C95)(C11)
 将一定量宽字符串从一个宽字符串后附到另一个
(函数)
wcsxfrm
(C95)
 变换宽字符串，使得 wcscmp 会产生与 wcscoll 相同的结果
(函数)
字符串检验
定义于头文件 <wchar.h>
wcslenwcsnlen_s
(C95)(C11)
 返回宽字符串的长度
(函数)
wcscmp
(C95)
 比较两个宽字符串
(函数)
wcsncmp
(C95)
 比较来自两个宽字符串的一定量字符
(函数)
wcscoll
(C95)
 根据当前本地环境比较两个宽字符串
(函数)
wcschr
(C95)
 查找宽字符在宽字符串中的首次出现
(函数)
wcsrchr
(C95)
 查找宽字符在宽字符串中的最后一次出现
(函数)
wcsspn
(C95)
 返回仅由另一个宽字符串中出现的宽字符分隔的最长首段长度
(函数)
wcscspn
(C95)
 返回仅由不出现于另一个宽字符串中的宽字符分隔的最长首段长度
(函数)
wcspbrk
(C95)
 查找一个宽字符串中的任何字符在另一个宽字符串中的首个位置
(函数)
wcsstr
(C95)
 查找一个宽字符串在另一个宽字符串中的首次出现
(函数)
wcstokwcstok_s
(C95)(C11)
 查找宽字符串中的下一个记号
(函数)
宽字符数组操作
定义于头文件 <wchar.h>
wmemcpywmemcpy_s
(C95)(C11)
 在两个不重叠的数组间复制一定数量的宽字符
(函数)
wmemmovewmemmove_s
(C95)(C11)
 在两个可能重叠的数组间复制一定数量的宽字符
(函数)
wmemcmp
(C95)
 比较两个数组中一定数量的宽字符
(函数)
wmemchr
(C95)
 在宽字符数组中查找宽字符的首次出现
(函数)
wmemset
(C95)
 将给定的宽字符复制到宽字符数组的所有位置
(函数)

类型

定义于头文件 <stddef.h>
定义于头文件 <stdlib.h>
定义于头文件 <wchar.h>
wchar_t | 可保有任何合法宽字符的整数类型 (typedef)
定义于头文件 <wchar.h>
定义于头文件 <wctype.h>
wint_t (C95) | 可保有任何合法宽字符，并至少多出一个值的整数类型 (typedef)
定义于头文件 <wctype.h>
wctrans_t (C95) | 保有本地环境特定的字符映射的标量类型 (typedef)
wctype_t (C95) | 保有本地环境特定的字符分类的标量类型 (typedef)

宏

定义于头文件 <wchar.h>
定义于头文件 <wctype.h>
WEOF (C95) | 用于指示错误的 wint_t 类型的非字符值 (宏常量)
定义于头文件 <wchar.h>
定义于头文件 <stdint.h>
WCHAR_MIN (C95) | wchar_t 的最小合法值 (宏常量)
WCHAR_MAX (C95) | wchar_t 的最大合法值 (宏常量)

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.19 Common definitions <stddef.h> (p: 288)
  • 7.29 Extended multibyte and wide character utilities <wchar.h> (p: 402-446)
  • 7.30 Wide character classification and mapping utilities <wctype.h> (p: 447-454)
  • 7.31.16 Extended multibyte and wide character utilities <wchar.h> (p: 456)
  • 7.31.17 Wide character classification and mapping utilities <wctype.h> (p: 457)
  • K.3.3 Common definitions <stddef.h> (p: 585)
  • K.3.9 Extended multibyte and wide character utilities <wchar.h> (p: 627-651)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.17 Common definitions <stddef.h> (p: 254)
  • 7.24 Extended multibyte and wide character utilities <wchar.h> (p: 348-392)
  • 7.25 Wide character classification and mapping utilities <wctype.h> (p: 393-400)
  • 7.26.12 Extended multibyte and wide character utilities <wchar.h> (p: 402)
  • 7.26.13 Wide character classification and mapping utilities <wctype.h> (p: 402)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.1.5 Common definitions <stddef.h>

参阅


iswalnum

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
int iswalnum( wint_t ch ); | (C95 起)

检查给定宽字符是否字母数字，即数字（ 0123456789 ）、大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）、小写字母（ abcdefghijklmnopqrstuvwxyz ）或任何限定于当前本地环境的字母数字字符。

参数

ch - 宽字符

返回值

若宽字符是字母数字字符则为非零值，否则为零。

注意

ISO 30112 指定哪些 Unicode 字符包含于 POSIX 字母数字类别。

示例

#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>

int main(void)
{
    wchar_t c = L'\u13ad'; // 切罗基字母 HA ('Ꭽ')
    printf("in the default locale, iswalnum(%#x) = %d\n", c, !!iswalnum(c));
    setlocale(LC_ALL, "en_US.utf8");
    printf("in Unicode locale, iswalnum(%#x) = %d\n", c, !!iswalnum(c));
}

输出：

in the default locale, iswalnum(0x13ad) = 0
in Unicode locale, iswalnum(0x13ad) = 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.2.1.1 The iswalnum function (p: 448)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.2.1.1 The iswalnum function (p: 394)

参阅

isalnum
 检查一个字符是否是字母或数字
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


iswalpha

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
int iswalpha( wint_t ch ); | (C95 起)

检查给定字符是否字母字符，即大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）、小写字母（ abcdefghijklmnopqrstuvwxyz ）或任何限定于当前本地环境的字母字符。

参数

ch - 宽字符

返回值

若宽字符为字母字符则为非零值，否则为 0 。

注意

ISO 30112 指定哪些 Unicode 字符包含于 POSIX 字母类别。

示例

#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>

int main(void)
{
    wchar_t c = L'\u0b83'; // 泰米尔符号 Visarga ('ஃ')
    printf("in the default locale, iswalpha(%#x) = %d\n", c, !!iswalpha(c));
    setlocale(LC_ALL, "en_US.utf8");
    printf("in Unicode locale, iswalpha(%#x) = %d\n", c, !!iswalpha(c));
}

输出：

in the default locale, iswalpha(0xb83) = 0
in Unicode locale, iswalpha(0xb83) = 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.2.1.2 The iswalpha function (p: 448-449)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.2.1.2 The iswalpha function (p: 394-395)

参阅

isalpha
 检查一个字符是否是英文字母
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


iswblank

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
int iswblank( wint_t ch ); | (C99 起)

检查给定的宽字符是否被当前 C 本地环境分类作空格符（即用于在句中分隔单词的空白符）。默认 C 本地环境中，只有空格（ 0x20 ）和水平制表符（ 0x09 ）是空格符。

参数

ch - 宽字符

返回值

若宽字符是空格符则为非零值，否则为零。

注意

ISO 30112 定义 POSIX 空格字符为 Unicode 字符 U+0009 、 U+0020 、 U+1680 、 U+180E 、 U+2000..U+2006 、 U+2008 、 U+200A 、 U+205F 及 U+3000 。

示例

#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>

int main(void)
{
    wchar_t c = L'\u3000'; // 表意空格（ '　' ）
    printf("in the default locale, iswblank(%#x) = %d\n", c, !!iswblank(c));
    setlocale(LC_ALL, "en_US.utf8");
    printf("in Unicode locale, iswblank(%#x) = %d\n", c, !!iswblank(c));
}

输出：

in the default locale, iswblank(0x3000) = 0
in Unicode locale, iswblank(0x3000) = 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.2.1.3 The iswblank function (p: 449)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.2.1.3 The iswblank function (p: 395)

参阅

isblank
(C99)
 检查一个字符是否是空格字符
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


iswcntrl

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
int iswcntrl( wint_t ch ); | (C95 起)

检查给定的宽字符是否为控制字符，即控制码 0x00-0x1F 和 0x7F 及任何限定于当前本地环境的控制字符。

参数

ch - 宽字符

返回值

若宽字符为控制字符则为非零值，否则为零。

注意

ISO 30112 定义 POSIX 控制字符为 Unicode 字符 U+0000..U+001F 、 U+007F..U+009F 、 U+2028 及 U+2029 （ Unicode 类 Cc 、 Zl 及 Zp ）。

示例

#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>

int main(void)
{
    wchar_t c = L'\u2028'; // Unicode 字符“行分隔符”
    printf("in the default locale, iswcntrl(%#x) = %d\n", c, !!iswcntrl(c));
    setlocale(LC_ALL, "en_US.utf8");
    printf("in Unicode locale, iswcntrl(%#x) = %d\n", c, !!iswcntrl(c));
}

输出：

in the default locale, iswcntrl(0x2028) = 0
in Unicode locale, iswcntrl(0x2028) = 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.2.1.4 The iswcntrl function (p: 449)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.2.1.4 The iswcntrl function (p: 395)

参阅

iscntrl
 检查一个字符是否是控制字符
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


iswctype

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
int iswctype( wint_t wc, wctype_t desc ); | (C95 起)

用 desc 所标识的当前 C 本地环境的 LC_TYPE 类别分类宽字符 wc 。

参数

wc | - | 要分类的宽字符
desc | - | 从调用 std::wctype 获得的 LC_CTYPE 类别

返回值

若字符 ch 拥有当前 C 本地环境的 LC_CTYPE 平面 desc 所标识的属性则为非零值，否则为零。

示例

#include <locale.h>
#include <wchar.h>
#include <wctype.h>
#include <stdio.h>
const char* classify(wchar_t wc, const char* cat)
{
    return iswctype(wc, wctype(cat)) ? "true" : "false";
}
int main(void)
{
    setlocale(LC_ALL, "ja_JP.UTF-8");
    puts("The character \u6c34 is...");
    const char* cats[] = {"digit", "alpha", "space", "cntrl", "jkanji"};
    for(int n = 0; n < 5; ++n)
        printf("%s? %s\n", cats[n], classify(L'\u6c34', cats[n]));
}

输出：

The character 水 is...
digit? false
alpha? true
space? false
cntrl? false
jkanji? true

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.2.2.1 The iswctype function (p: 451-452)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.2.2.1 The iswctype function (p: 397-398)

参阅

wctype
(C95)
 查找当前 C 本地环境中的字符分类类别
(函数)


iswdigit

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
int iswdigit( wint_t ch ); | (C95 起)

检查给定的宽字符（若窄化）是否对应十进制数字 0123456789 之一。

参数

ch - 宽字符

返回值

若宽字符为数字字符则为非零值，否则为零。

注意

iswdigit 与 iswxdigit 是仅有的不受当前安装的C本地环境影响的标准宽字符分类函数。

示例

一些本地环境提供额外的检测非 ASCII 数字的字符类

#include <stdio.h>
#include <wctype.h>
#include <wchar.h>
#include <locale.h>

void test(wchar_t a3, wchar_t u3, wchar_t j3)
{
    printf("        '%lc' '%lc' '%lc'\n", a3, u3, j3);
    printf("iswdigit %d    %d   %d\n",
           !!iswdigit(a3), !!iswdigit(u3), !!iswdigit(j3));
    printf("jdigit:  %d    %d   %d\n", !!iswctype(a3, wctype("jdigit")),
          !!iswctype(u3, wctype("jdigit")),
          !!iswctype(j3, wctype("jdigit")));
}

int main(void)
{
    wchar_t a3 = L'3';  // ASCII 数字 3
    wchar_t u3 = L'三'; // CJK 数字 3
    wchar_t j3 = L'３'; // 全角数字 3

    setlocale(LC_ALL, "en_US.utf8");
    puts("In American locale:");
    test(a3, u3, j3);

    setlocale(LC_ALL, "ja_JP.utf8");
    puts("\nIn Japanese locale:");
    test(a3, u3, j3);
}

输出：

In American locale:
        '3' '三' '３'
iswdigit 1    0   0
jdigit:  0    0   0

In Japanese locale:
        '3' '三' '３'
iswdigit 1    0   0
jdigit:  0    0   1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.2.1.5 The iswdigit function (p: 449)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.2.1.5 The iswdigit function (p: 395)

参阅

isdigit
 检查字符是否为数字
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


iswgraph

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
int iswgraph( wint_t ch ); | (C95 起)

检查给定的宽字符是否拥有图形表示，即是数字（ 0123456789 ）、大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）、小写字母（ abcdefghijklmnopqrstuvwxyz ）、标点字符（ !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ）之一或任何限定于当前 C 本地环境的图形字符。

参数

ch - 宽字符

返回值

若给定字符拥有图形表示则为非零，否则为零。

注意

ISO 30112 指定哪些 Unicode 字符包含于 POSIX 图像类别。

示例

#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>

int main(void)
{
    wchar_t c = L'\u2602'; // Unicode 字符伞 ('☂')
    printf("in the default locale, iswgraph(%#x) = %d\n", c, !!iswgraph(c));
    setlocale(LC_ALL, "en_US.utf8");
    printf("in Unicode locale, iswgraph(%#x) = %d\n", c, !!iswgraph(c));
}

输出：

in the default locale, iswgraph(0x2602) = 0
in Unicode locale, iswgraph(0x2602) = 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.2.1.6 The iswgraph function (p: 449-450)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.2.1.6 The iswgraph function (p: 395-396)

参阅

isgraph
 检查一个字符是否是可显示的字符
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


iswlower

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
int iswlower( wint_t ch ); | (C95 起)

检查给定宽字符是否小写字母，即 abcdefghijklmnopqrstuvwxyz 或任何当前本地环境指定的小写字母之一。

参数

ch - wide character

返回值

若宽字符是小写字母则为非零值，否则为零。

注意

ISO 30112 指定哪些 Unicode 字符包含于 POSIX 小写类别。

示例

#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>

int main(void)
{
    wchar_t c = L'\u0444'; // 西里尔小写字母ef（'ф'）
    printf("in the default locale, iswlower(%#x) = %d\n", c, !!iswlower(c));
    setlocale(LC_ALL, "en_US.utf8");
    printf("in Unicode locale, iswlower(%#x) = %d\n", c, !!iswlower(c));
}

输出：

in the default locale, iswlower(0x444) = 0
in Unicode locale, iswlower(0x444) = 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.2.1.7 The iswlower function (p: 450)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.2.1.7 The iswlower function (p: 396)

参阅

islower
 检查一个字符是否是小写字母
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


iswprint

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
int iswprint( wint_t ch ); | (C95 起)

检查给定的宽字符是否能被打印，即它是数字（ 0123456789 ）、大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）、小写字母（ abcdefghijklmnopqrstuvwxyz ）、标点字符（ !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ）、空格或任何限定于当前 C 本地环境指定的可打印字符之一。

参数

ch - 宽字符

返回值

若宽字符能被打印则为非零，否则为零。

注意

ISO 30112 指定哪些 Unicode 字符包含于 POSIX 打印类别。

示例

#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>

int main(void)
{
    wchar_t c = L'\u2002'; // Unicode 字符 'EN SPACE'
    printf("in the default locale, iswprint(%#x) = %d\n", c, !!iswprint(c));
    setlocale(LC_ALL, "en_US.utf8");
    printf("in Unicode locale, iswprint(%#x) = %d\n", c, !!iswprint(c));
    wchar_t c2 = L'\x82'; // 容许的打断
    printf("in Unicode locale, iswprint(%#x) = %d\n", c2, !!iswprint(c2));
}

输出：

in the default locale, iswprint(0x2002) = 0
in Unicode locale, iswprint(0x2002) = 1
in Unicode locale, iswprint(0x82) = 0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.2.1.8 The iswprint function (p: 450)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.2.1.8 The iswprint function (p: 396)

参阅

isprint
 检查一个字符是否是可打印字符
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


iswpunct

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
int iswpunct( wint_t ch ); | (C95 起)

检查给定宽字符是否标点字符，即它是 !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ 或任何当前本地环境限定的标点字符之一。

参数

ch - 宽字符

返回值

若宽字符是标点字符则为非零，否则为非零。

注意

ISO 30112 指定哪些 Unicode 字符包含于 POSIX 标点类别。

示例

#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>

int main(void)
{
    wchar_t c = L'\u2051'; // 双星号 ('⁑')
    printf("in the default locale, iswpunct(%#x) = %d\n", c, !!iswpunct(c));
    setlocale(LC_ALL, "en_US.utf8");
    printf("in Unicode locale, iswpunct(%#x) = %d\n", c, !!iswpunct(c));
}

输出：

in the default locale, iswpunct(0x2051) = 0
in Unicode locale, iswpunct(0x2051) = 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.2.1.9 The iswpunct function (p: 450)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.2.1.9 The iswpunct function (p: 396)

参阅

ispunct
 检查一个字符是否是一个标点符号
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


iswspace

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
int iswspace( wint_t ch ); | (C95 起)

检查给定的宽字符是否空白符，即空格（ 0x20 ）、换页符（ 0x0c ）、换行符（ 0x0a ）、回车（ 0x0d ）、水平制表符（ 0x09 ）、垂直制表符（ 0x0b ）或任何当前本地环境指定的空白符之一。

参数

ch - 宽字符

返回值

若宽字符为空白符则为非零值，否则为零。

注意

ISO 30112 定义 POSIX 空格符为 Unicode 字符 U+0009..U+000D 、 U+0020 、 U+1680 、 U+180E 、 U+2000..U+2006 、 U+2008..U+200A 、 U+2028 、 U+2029 、 U+205F 及 U+3000 。

示例

#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>

int main(void)
{
    wchar_t c = L'\u2003'; // Unicode 字符 'EM SPACE'
    printf("in the default locale, iswspace(%#x) = %d\n", c, !!iswspace(c));
    setlocale(LC_ALL, "en_US.utf8");
    printf("in Unicode locale, iswspace(%#x) = %d\n", c, !!iswspace(c));
}

输出：

in the default locale, iswspace(0x2003) = 0
in Unicode locale, iswspace(0x2003) = 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.2.1.10 The iswspace function (p: 450-451)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.2.1.10 The iswspace function (p: 396-397)

参阅

isspace
 检查一个字符是否是空白字符
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


iswupper

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
int iswupper( wint_t ch ); | (C95 起)

检查给定宽字符是否大写字母，即 ABCDEFGHIJKLMNOPQRSTUVWXYZ 或任何当前本地环境限定的大写字母之一。

参数

ch - 宽字符

返回值

若宽字符为大写字母则为非零值，否则为零。

注意

ISO 30112 指定哪些 Unicode 字符包含于 POSIX 大写类别。

示例

#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>

int main(void)
{
    wchar_t c = L'\u053d'; // 亚美尼亚文大写字母 xeh ('Խ')
    printf("in the default locale, iswupper(%#x) = %d\n", c, !!iswupper(c));
    setlocale(LC_ALL, "en_US.utf8");
    printf("in Unicode locale, iswupper(%#x) = %d\n", c, !!iswupper(c));
}

输出：

in the default locale, iswupper(0x53d) = 0
in Unicode locale, iswupper(0x53d) = 1

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.2.1.11 The iswupper function (p: 451)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.2.1.11 The iswupper function (p: 397)

参阅

isupper
 检查一个字符是否是大写字母
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


iswxdigit

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
int iswxdigit( wint_t ch ); | (C95 起)

检查给定的宽字符（若窄化）是否对应十六进制数字字符，即 0123456789abcdefABCDEF 之一。

参数

ch - 宽字符

返回值

若宽字符为十六进制数字字符则为非零值，否则为零。

注意

iswdigit 与 iswxdigit 是仅有的不受当前安装的 C 本地环境影响的标准宽字符分类函数。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.2.1.12 The iswxdigit function (p: 451)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.2.1.12 The iswxdigit function (p: 397)

参阅

isxdigit
 检查一个字符是否是十六进制的字符
(函数)
ASCII值 (十六进制) |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
0 - 8 | 0x00-0x08 | 控制码 (NUL等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | 0x09 | 制表符 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10 - 13 | 0x0A-0x0D | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14 - 31 | 0x0E-0x1F | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | 0x20 | 空格 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33 - 47 | 0x21-0x2F | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48 - 57 | 0x30-0x39 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58 - 64 | 0x3a-0x40 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65 - 70 | 0x41-0x46 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71 - 90 | 0x47-0x5A | GHIJKLMNOPQRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91 - 96 | 0x5B-0x60 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97 -102 | 0x61-0x66 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103-122 | 0x67-0x7A | ghijklmnopqrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123-126 | 0x7B-0x7E | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | 0x7F | 退格符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


towctrans

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
wint_t towctrans( wint_t wc, wctrans_t desc ); | (C95 起)

用 desc 所标识的当前 C 本地环境的 LC_TYPE 映射宽字符 wc 。

参数

wc | - | 要映射的宽字符
desc | - | LC_CTYPE映射，从对wctrans的调用获得

返回值

ch 的被映射值，使用当前 C 本地环境的 LC_TYPE 中的 desc 标识的映射。

示例

#include <locale.h>
#include <wctype.h>
#include <wchar.h>
#include <stdio.h>

int main(void)
{
    setlocale(LC_ALL, "ja_JP.UTF-8");
    wchar_t kana[] = L"ヒラガナ";
    size_t sz = sizeof kana / sizeof *kana;
    wchar_t hira[sz];
    for(size_t n = 0; n < sz; ++n)
        hira[n] = towctrans(kana[n], wctrans("tojhira"));
    printf("katakana characters %ls are %ls in hiragana\n", kana, hira);
}

输出：

katakana characters ヒラガナ are ひらがな in hiragana

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.3.2.1 The towctrans function (p: 454)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.3.2,1 The towctrans function (p: 400)

参阅

wctrans
(C95)
 查找当前 C 本地环境中的字符映射类别
(函数)


towlower

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
wint_t towlower( wint_t wc ); | (C95 起)

若可能，则转换给定宽字符为小写。

参数

ch - 要转换的宽字符

返回值

ch 的小写版本，或若无小写版本列于当前 C 本地环境，则为不修改的 ch 。

注意

此函数只能进行 1:1 字符映射，例如希腊大写字母 'Σ' 拥有二个小写形式，依赖在词中的位置： 'σ' 与 'ς' 。此情况下，不能用对 towlower 的调用获得正确的小写形式。

ISO 30112 指定此映射包含哪些 Unicode 字符对。

示例

#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>

int main(void)
{
    wchar_t wc = L'\u0190'; // 拉丁文大写字母开 E ('Ɛ')
    printf("in the default locale, towlower(%#x) = %#x\n", wc, towlower(wc));
    setlocale(LC_ALL, "en_US.utf8");
    printf("in Unicode locale, towlower(%#x) = %#x\n", wc, towlower(wc));
}

输出：

in the default locale, towlower(0x190) = 0x190
in Unicode locale, towlower(0x190) = 0x25b

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.3.1.1 The towlower function (p: 453)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.3.1.1 The towlower function (p: 399)

参阅

towupper (C95) | 将宽字符转换为大写 (函数)
tolower | 将字符转换成小写 (函数)


towupper

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
wint_t towupper( wint_t wc ); | (C95 起)

若可能则转换给定的宽字符为大写。

参数

ch - 要转换的宽字符

返回值

ch 的大写版本，或若无大写版本列于当前 C 本地环境，则为不修改的 ch 。

注意

此函数只能进行 1:1 映射，例如 'ß' 的大写形式（有一些例外）是双字符字符串 "SS" ，它无法通过 towupper 获得。

ISO 30112 指定此映射包含哪些 Unicode 字符对。

示例

#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>

int main(void)
{
    wchar_t wc =  L'\u017f'; // 拉丁文小写字母长 S ('ſ')
    printf("in the default locale, towupper(%#x) = %#x\n", wc, towupper(wc));
    setlocale(LC_ALL, "en_US.utf8");
    printf("in Unicode locale, towupper(%#x) = %#x\n", wc, towupper(wc));
}

输出：

in the default locale, towupper(0x17f) = 0x17f
in Unicode locale, towupper(0x17f) = 0x53

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.3.1.2 The towupper function (p: 453)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.3.1.2 The towupper function (p: 399)

参阅

towlower (C95) | 将宽字符转换为小写 (函数)
toupper | 将字符转换成大写 (函数)


wcscat, wcscat_s

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |  |
 | (1) |
wchar_t *wcscat( wchar_t *dest, const wchar_t *src ); |  |  | (C95 起) (C99 前)
wchar_t *wcscat(wchar_t *restrict dest, const wchar_t *restrict src); |  |  | (C99 起)
errno_t wcscat_s(wchar_t *restrict dest, rsize_t destsz, const wchar_t *restrict src); | (2) | (C11 起)
1) 后附 src 所指向的空终止宽字符串的副本到 dest 所指向的空终止宽字符串的结尾。宽字符 src[0] 替换 dest 末尾的空终止符。产生的宽字符串是空终止的。若目标数组对于 src 和 dest 的内容以及终止空宽字符不够大，则行为未定义。若字符串重叠，则行为未定义。
2) 同 (1)，除了它可用未指定值破坏目标数组的剩余部分（从最后写入的宽字符到 destsz ），以及在运行时检测下列错误，并调用当前安装的制约处理函数：
  • src 或 dest 为空指针
  • destsz 为零或大于 RSIZE_MAX/sizeof(wchar_t)
  • dest 的首 destsz 个宽字符中无空终止符
  • 会出现截断（ dest 末尾的可用空间不能适应 src 的每个宽字符，包括空终止符）
  • 源与目标字符串间会出现重叠
同所有边界检查函数， wcscat_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 wchar.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dest | - | 指向要后附到的空终止宽字符串的指针
src | - | 指向作为复制来源的空终止宽字符串的指针
destsz | - | 要写入的最大字符数，典型地为目标缓冲区的大小

返回值

1) 返回 dest 的副本。
2) 成功时返回零。错误时返回非零。错误时，亦写入 L'\0' 到 dest[0] （除非 dest 为空指针，或 destsz 为零或大于 RSIZE_MAX/sizeof(wchar_t) ）。

示例

#include <wchar.h>
#include <stdio.h>
#include <locale.h>

int main(void)
{
    wchar_t str[50] = L"Земля, прощай.";
    wcscat(str, L" ");
    wcscat(str, L"В добрый путь.");
    setlocale(LC_ALL, "en_US.utf8");
    printf("%ls", str);
}

输出：

Земля, прощай. В добрый путь.

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.3.1 The wcscat function (p: 432)
  • K.3.9.2.2.1 The wcscat_s function (p: 642-643)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.3.1 The wcscat function (p: 378)

参阅

wcsncatwcsncat_s (C95)(C11) | 将一定量宽字符串从一个宽字符串后附到另一个 (函数)
strcatstrcat_s (C11) | 连接两个字符串 (函数)
wcscpywcscpy_s (C95)(C11) | 将一个宽字符串复制给另一个 (函数)


wcschr

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
wchar_t* wcschr( const wchar_t* str, wchar_t ch ); | (C95 起)

寻找宽字符 ch 在 str 所指向的宽字符串中的首次出现。

参数

str | - | 指向待分析的空终止宽字符的指针
ch | - | 要搜索的宽字符

返回值

指向 str 中找到的字符的指针，或若找不到这种字符则为空指针。

示例

#include <wchar.h>
#include <stdio.h>
#include <locale.h>

int main(void)
{
    wchar_t arr[] = L"招き猫 кошка";
    wchar_t *cat = wcschr(arr, L'猫');
    wchar_t *dog = wcschr(arr, L'犬');

    setlocale(LC_ALL, "en_US.utf8");
    if(cat)
        printf("The character 猫 found at position %td\n", cat-arr);
    else
        puts("The character 猫 not found");

    if(dog)
        printf("The character 犬 found at position %td\n", dog-arr);
    else
        puts("The character 犬 not found");
}

输出：

The character 猫 found at position 2
The character 犬 not found

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.5.1 The wcschr function (p: 435)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.5.1 The wcschr function (p: 381)

参阅

wcsrchr (C95) | 查找宽字符在宽字符串中的最后一次出现 (函数)
wcspbrk (C95) | 查找一个宽字符串中的任何字符在另一个宽字符串中的首个位置 (函数)


wcscmp

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
int wcscmp( const wchar_t *lhs, const wchar_t *rhs ); | (C95 起)

以字典序比较二个空终止宽字符串。

结果的符号是被比较的字符串中，首对相异宽字符间的差值符号。

若 lhs 或 rhs 不是指向空终止宽字符串的指针，则行为未定义。

参数

lhs, rhs - 指向待比较的空终止宽字符串的指针

返回值

若字典序中 lhs 先出现于 rhs 则为负值。

若 lhs 与 rhs 比较相等则为零。

若字典序中 lhs 后出现于 rhs 则为负值。

注意

不同于 wcscoll ，此函数不考虑本地环境。而且在一同使用来自不同的 Unicode 块的字符时，或编码单元不匹配任何对照顺序时，顺序可能无意义。

示例

#include <wchar.h>
#include <stdio.h>
#include <locale.h>

void demo(const wchar_t* lhs, const wchar_t* rhs)
{
    int rc = wcscmp(lhs, rhs);
    const char *rel = rc < 0 ? "precedes" : rc > 0 ? "follows" : "equals";

    setlocale(LC_ALL, "en_US.utf8");
    printf("[%ls] %s [%ls]\n", lhs, rel, rhs);
}

int main(void)
{
    const wchar_t* string = L"どうもありがとうございます";
    demo(string, L"どうも");
    demo(string, L"助かった");
    demo(string + 9, L"ありがとうございます" + 6);
}

可能的输出：

[どうもありがとうございます] follows [どうも]
[どうもありがとうございます] precedes [助かった]
[ざいます] equals [ざいます]

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.4.1 The wcscmp function (p: 433)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.4.1 The wcscmp function (p: 379)

参阅

wcsncmp (C95) | 比较来自两个宽字符串的一定量字符 (函数)
wmemcmp (C95) | 比较两个数组中一定数量的宽字符 (函数)
strcmp | 比较两个字符串 (函数)
wcscoll (C95) | 根据当前本地环境比较两个宽字符串 (函数)


wcscoll

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
int wcscoll( const wchar_t *lhs, const wchar_t *rhs ); | (C95 起)

按照 LC_COLLATE 类别所定义的当前安装的本地环境，比较二个空终止宽字符串。

参数

lhs, rhs - 指向要比较的空终止宽字符串的指针

返回值

若 lhs 小于（前趋） rhs 则为负值。

若 lhs 等于 rhs 则为 ​0​ 。

若 lhs 大于（后随） rhs 则为负值。

注意

对照顺序为字典顺序：国家字母表（其等价类）中字母的位置拥有高于其大小写或变体的优先级。在等价类内，小写字符先于其大写等价物对照，而且本地环境限定的顺序可能应用到有发音符号的字符。一些本地环境中，字符组作为单个对照单元比较。例如， "ch" 在捷克语中后随 "h" 而前趋 "i" ， "dzs" 在匈牙利语中后随 "dz" 而前趋 "g" 。

示例

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

void try_compare(const wchar_t* p1, const wchar_t* p2)
{
    if(wcscoll(p1, p2) < 0)
        printf("%ls before %ls\n", p1, p2);
    else
        printf("%ls before %ls\n", p2, p1);
}

int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");
    printf("In the American locale: ");
    try_compare(L"hrnec", L"chrt");

    setlocale(LC_COLLATE, "cs_CZ.utf8");
    printf("In the Czech locale: ");
    try_compare(L"hrnec", L"chrt");

    setlocale(LC_COLLATE, "en_US.utf8");
    printf("In the American locale: ");
    try_compare(L"år", L"ängel");

    setlocale(LC_COLLATE, "sv_SE.utf8");
    printf("In the Swedish locale: ");
    try_compare(L"år", L"ängel");
}

可能的输出：

In the American locale: chrt before hrnec
In the Czech locale: hrnec before chrt
In the American locale: ängel before år
In the Swedish locale: år before ängel

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.4.2 The wcscoll function (p: 433-434)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.4.2 The wcscoll function (p: 379-380)

参阅

strcoll | 比较两个字符串，根据当前本地环境 (函数)
wcsxfrm (C95) | 变换宽字符串，使得 wcscmp 会产生与 wcscoll 相同的结果 (函数)
wcscmp (C95) | 比较两个宽字符串 (函数)


wcscpy, wcscpy_s

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |  |
 | (1) |
wchar_t *wcscpy( wchar_t *dest, const wchar_t *src ); |  |  | (C95 起) (C99 前)
wchar_t *wcscpy( wchar_t *restrict dest, const wchar_t *restrict src ); |  |  | (C99 起)
errno_t wcscpy_s( wchar_t *restrict dest, rsize_t destsz, const wchar_t *restrict src ); | (2) | (C11 起)
1) 复制 src 所指向的宽字符串（包含空终止宽字符）到 dest 所指向的宽字符数组。若 dest 数组不够大则行为未定义。若字符串重叠则行为未定义。
2) 同 (1) ，除了它可用未指定值破坏目标数组的剩余部分，及在运行时检测下列错误，并调用当前安装的制约处理函数：
  • src 或 dest 为空指针
  • destsz 为零或大于 RSIZE_MAX / sizeof(wchar_t)
  • destsz 小于或等于 wcsnlen_s(src, destsz) ，换言之会发生阶段
  • 源与目标字符串间会发生重叠
同所有边界检查函数， wcscpy_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 wchar.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dest | - | 指向复制目标的宽字符数组的指针
src | - | 指向复制来源的空终止宽字符串的指针
destsz | - | 要写入的最大字符数，典型地为目标缓冲区的大小

返回值

1) 返回 dest 的副本
2) 成功时返回零，失败时返回非零。失败时，亦会写入 L'\0' 到 dest[0] （除非 dest 为空指针或为零或大于 RMAX_SIZE / sizeof(wchar_t) ）。

示例

#include <wchar.h>
#include <stdio.h>
#include <locale.h>

int main(void)
{
    wchar_t *src = L"犬 means dog";
//  src[0] = L'狗' ; // 这会是未定义行为
    wchar_t dst[wcslen(src) + 1]; // 为适应空终止符 +1
    wcscpy(dst, src);
    dst[0] = L'狗'; // OK

    setlocale(LC_ALL, "en_US.utf8");
    printf("src = %ls\ndst = %ls\n", src, dst);
}

输出：

src = 犬 means dog
dst = 狗 means dog

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.1.2 The wcscpy function (p: 430)
  • K.3.9.2.1.1 The wcscpy_s function (p: 639)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.1.2 The wcscpy function (p: 376)

参阅

wcsncpywcsncpy_s (C95)(C11) | 将一定量的宽字符从一个字符串复制到另一个 (函数)
wmemcpywmemcpy_s (C95)(C11) | 在两个不重叠的数组间复制一定数量的宽字符 (函数)
strcpystrcpy_s (C11) | 复制一个字符串给另一个 (函数)


wcscspn

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
size_t wcscspn( const wchar_t* dest, const wchar_t* src ); | (C95 起)

返回 dest 所指向的宽字符串的，仅由 src 所指向的宽字符串中找不到的字符组成的最大起始段的长度。

参数

dest | - | 指向要分析的空终止宽字符串的指针
src | - | 指向含待搜索字符的空终止宽字符串的指针

返回值

仅由 src 所指向的宽字符串中找不到的字符组成的最大起始段长度。

示例

#include <locale.h>
#include <wchar.h>

int main(void)
{
    wchar_t dest[] = L"白猫 黑狗 甲虫";
    /*                      └───┐   */
    const wchar_t *src = L"甲虫,黑狗";

    const size_t len = wcscspn(dest, src);
    dest[len] = L'\0'; /* 终止字符串，以便显示 */

    setlocale(LC_ALL, "en_US.utf8");
    wprintf(L"The length of maximum initial segment is %td.\n"
            L"The segment is \"%ls\".\n", len, dest);
}

输出：

The length of maximum initial segment is 3.
The segment is "白猫 ".

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.5.2 The wcscspn function (p: 435-436)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.5.2 The wcscspn function (p: 381-382)

参阅

wcsspn (C95) | 返回仅由另一个宽字符串中出现的宽字符分隔的最长首段长度 (函数)
wcspbrk (C95) | 查找一个宽字符串中的任何字符在另一个宽字符串中的首个位置 (函数)


wcslen, wcsnlen_s

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |  |
size_t wcslen( const wchar_t *str ); | (1) | (C95 起)
size_t wcsnlen_s(const wchar_t *str, size_t strsz); | (2) | (C11 起)
1) 返回宽字符串的长度，即空终止宽字符之前的非空宽字符数。
2) 同 (1) ，除了若 str 为空指针则函数返回零，而若在 src 的首 strsz 个宽字符中找不到空宽字符则返回 strsz 。
同所有边界检查函数， wcsnlen_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 wchar.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

str | - | 指向要检验的空终止宽字符串的指针
strsz | - | 要检验的最大宽字符数

返回值

1) 空终止宽字符串 str 的长度。
2) 成功时为空终止宽字符串 str 的长度，若 str 为空指针则为零，若找不到空宽字符则为 strsz 。

注意

strnlen_s 和 wcsnlen_s 是仅有的不调用运行时制约处理的边界检查函数。它们是纯工具函数，用于为非空终止字符串提供有限制支持。

示例

#include <wchar.h>
#include <stdio.h>

int main(void)
{
    wchar_t str[] = L"How many wide characters does this string contain?";

    printf("without null character: %zu\n", wcslen(str));
    printf("with null character: %zu\n", sizeof str / sizeof *str);
}

输出：

without null character: 50
with null character: 51

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.6.1 The wcslen function (p: 439)
  • K.3.9.2.4.1 The wcsnlen_s function (p: 646-647)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.6.1 The wcslen function (p: 385)

参阅

strlenstrnlen_s
(C11)
 返回给定字符串的长度
(函数)


wcsncat, wcsncat_s

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |  |
 | (1) |
wchar_t *wcsncat( wchar_t *dest, const wchar_t *src, size_t count ); |  |  | (C95 起) (C99 前)
wchar_t *wcsncat( wchar_t *restrict dest, const wchar_t *restrict src, size_t count ); |  |  | (C99 起)
errno_t wcsncat_s( wchar_t *restrict dest, rsize_t destsz, const wchar_t *restrict src, rsize_t count ); | (2) | (C11 起)
1) 后附来自 src 所指向的宽字符串的至多 count 个宽字符，到 dest 所指向的字符串末尾，若找到空字符则停止。宽字符 src[0] 替换位于 dest 末尾的空终止符。始终后附终止空字符到末尾（故函数可写入的最大宽字符数是 count+1 ）。
若目标数组没有对于 dest 和 src 的内容加上终止空宽字符足够的空间，则行为未定义。
若字符串重叠则行为未定义。
2) 同 (1) ，除了此函数可以可用未指定值破坏目标数组的剩余部分（从最后写入宽字符到 destsz ），以及在运行时检测下列错误，并调用当前安装的制约处理函数：
  • src 或 dest 为空指针
  • destsz 或 count 为零或大于 RSIZE_MAX/sizeof(wchar_t)
  • dest 的首 destsz 个宽字符中无空宽字符
  • 会出现截断： count 与 src 长度的较小者，会超出 dest 的空终止符和 destsz 之间的可用空间。
  • 源与目标字符串之间会出现重叠
同所有边界检查函数， wcsncat_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 wchar.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dest | - | 指向要后附到的空终止宽字符串的指针
src | - | 指向作为复制来源的宽字符数组的指针
count | - | 要复制的最大宽字符数
destsz | - | 目标缓冲区的大小

返回值

1) 返回 dest 的副本。
2) 成功时返回零。错误时返回非零。错误时，亦写入 L'\0' 到 dest[0] （除非 dest 为空指针，或 destsz 为零或大于 RSIZE_MAX/sizeof(wchar_t) ）。

注意

尽管截断以适应目标缓冲区是安全风险，从而是 wcsncat_s 的运行时制约违规，还是可以通过指定 count 等于目标数组大小减一获取截断行为：这将一如往常地复制首 count 个宽字符并后附空终止符： wcsncat_s(dst, sizeof dst/sizeof *dst, src, (sizeof dst/sizeof *dst)-wcsnlen_s(dst, sizeof dst/sizeof *dst)-1); 。

示例

#include <wchar.h>
#include <stdio.h>
#include <locale.h>

int main(void)
{
    wchar_t str[50] = L"Земля, прощай.";
    wcsncat(str, L" ", 1);
    wcsncat(str, L"В добрый путь.", 8); // 只后附首 8 个宽字符
    setlocale(LC_ALL, "en_US.utf8");
    printf("%ls", str);
}

可能的输出：

Земля, прощай. В добрый

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.3.2 The wcsncat function (p: 432-433)
  • K.3.9.2.2.2 The wcsncat_s function (p: 643-644)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.3.2 The wcsncat function (p: 378-379)

参阅

wcscatwcscat_s (C95)(C11) | 将一个宽字符串的副本后附于另一个 (函数)
strncatstrncat_s (C11) | 连接两个字符串的一定数量字符 (函数)
wcscpywcscpy_s (C95)(C11) | 将一个宽字符串复制给另一个 (函数)


wcsncmp

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
int wcsncmp( const wchar_t* lhs, const wchar_t* rhs, size_t count ); | (C95 起)

比较二个空终止宽字符串的至多 count 个字符。按字典序进行比较。

结果的符号是被比较的字符串中首对宽字符的值间的差的符号。

若 lhs 或 rhs 不是指向空终止字符串的指针则行为未定义。

参数

lhs, rhs | - | 指向要比较的空终止宽字符串的指针
count | - | 要比较的最大字符数

返回值

若字典序中 lhs 先出现于 rhs 则为负值。

若 lhs 与 rhs 比较相等，或若 count 为零，则为零。

若字典序中 lhs 后出现于 rhs 则为负值。

注意

不同于 wcscoll 和 wcsxfrm ，此函数不考虑本地环境。

示例

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

void demo(const wchar_t *lhs, const wchar_t *rhs, int sz)
{
    int rc = wcsncmp(lhs, rhs, sz);
    if(rc == 0)
        printf("First %d characters of [%ls] equal [%ls]\n", sz, lhs, rhs);
    else if(rc < 0)
        printf("First %d characters of [%ls] precede [%ls]\n", sz, lhs, rhs);
    else if(rc > 0)
        printf("First %d characters of [%ls] follow [%ls]\n", sz, lhs, rhs);
}

int main(void)
{
    const wchar_t *str1 = L"안녕하세요";
    const wchar_t *str2 = L"안녕히 가십시오";

    setlocale(LC_ALL, "en_US.utf8");
    demo(str1, str2, 5);
    demo(str2, str1, 8);
    demo(str1, str2, 2);
}

输出：

First 5 characters of [안녕하세요] precede [안녕히 가십시오]
First 8 characters of [안녕히 가십시오] follow [안녕하세요]
First 2 characters of [안녕하세요] equal [안녕히 가십시오]

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.4.3 The wcsncmp function (p: 434)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.4.3 The wcsncmp function (p: 380)

参阅

wcscmp (C95) | 比较两个宽字符串 (函数)
wmemcmp (C95) | 比较两个数组中一定数量的宽字符 (函数)
wcscoll (C95) | 根据当前本地环境比较两个宽字符串 (函数)


wcsncpy, wcsncpy_s

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |  |
 | (1) |
wchar_t* wcsncpy( wchar_t* dest, const wchar_t* src, size_t count ); |  |  | (C95 起) (C99 前)
wchar_t *wcsncpy(wchar_t *restrict dest, const wchar_t *restrict src, size_t n); |  |  | (C99 起)
errno_t wcsncpy_s( wchar_t *restrict dest, rsize_t destsz, const wchar_t *restrict src, rsize_t n); | (2) | (C11 起)
1) 复制 src 所指向的宽字符串的至多 count 个字符（包含终止空宽字符）到 dest 所指向的宽字符数组。
若在完全复制整个 src 数组前抵达 count ，则产生的宽字符数组不是空终止的。
若在复制来自 src 的终止空宽字符后未抵达 count ，则写入额外的空宽字符到 dest ，直至写入总共 count 个字符。
若字符串重叠，则行为未定义。
2) 同 (1) ，除了函数不持续写入零到目标数组以填满 count ，它在写入终止空宽字符后停止（若源中无空宽字符，则它于 dest[count] 写入一个然后停止） 。并在运行时检测下列错误，并调用当前安装的制约处理函数：
  • src 或 dest 为空指针
  • destsz 或 count 为零或大于 RSIZE_MAX/sizeof(wchar_t)
  • count 大于或等于 destsz ，但 destsz 小于或等于 wcsnlen_s(src, count) ，换言之，会出现截断
  • 源与目标字符串间会出现重叠
同所有边界检查函数， wcsncpy_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 wchar.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dest | - | 指向要复制到的宽字符数组的指针
src | - | 指向复制来源的宽字符串的指针
count | - | 要复制的最大宽字符数
destsz | - | 目标缓冲区的大小

返回值

1) 返回 dest 的副本。
2) 成功时返回零，错误时返回非零。而且，在错误时写入 L'\0' 到 dest[0] （除非 dest 为空指针，或 destsz 为零或大于 RSIZE_MAX/sizeof(wchar_t) ），而且可能以未指定值破坏目标数组的剩余部分。

注意

典型用法中， count 是目标数组中的元素数。

尽管适合目标缓冲区的截断是安全风险，从而是 wcsncpy_s 的运行时制约违规，还是可通过指定 count 等于目标数组大小减一获取截断行为：它将复制首 count 个宽字符，并照常后附空宽终止符： wcsncpy_s(dst, sizeof dst / sizeof *dst, src, (sizeof dst / sizeof *dst)-1); 。

示例

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main(void)
{
    wchar_t src[] = L"わゐ";
    wchar_t dest[6] = {L'あ', L'い', L'う', L'え', L'お'};

    wcsncpy(dest, src, 4); // 这将复制 わゐ 并重复 L'\0' 二次

    puts("The contents of dest are: ");
    setlocale(LC_ALL, "en_US.utf8");
    for(wchar_t* p = dest; p-dest < sizeof dest / sizeof *dest; ++p) {
        if(*p)
            printf("%lc ", *p);
        else
            printf("\\0 ");
    }
}

可能的输出：

The contents of dest are:
わ ゐ \0 \0 お \0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.2.2 The wcsncpy function (p: 431)
  • K.3.9.2.1.2 The wcsncpy_s function (p: 640-641)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.2.2 The wcsncpy function (p: 377)

参阅

wcscpywcscpy_s (C95)(C11) | 将一个宽字符串复制给另一个 (函数)
wmemcpywmemcpy_s (C95)(C11) | 在两个不重叠的数组间复制一定数量的宽字符 (函数)
strncpystrncpy_s (C11) | 从一个字符串复制一定数量的字符到另一个 (函数)


wcspbrk

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
wchar_t* wcspbrk( const wchar_t* dest, const wchar_t* str ); | (C95 起)

在 dest 所指向的宽字符串中，寻找首个亦在 str 所指向的宽字符串中的字符。

参数

dest | - | 指向要分析的空终止宽字符串的指针
src | - | 指向含有待搜索字符的空终止宽字符串的指针

返回值

指向 dest 中首个亦在 str 中的首个字符的指针，或若这种字符不存在则为空指针。

注解

名字代表“宽字符串指针打断 (wide character string pointer break) ”，因为它返回指向首个分隔符（“打断”）的指针。

示例

#include <stdio.h>
#include <wchar.h>

int main(void)
{
    const wchar_t* str = L"Hello world, friend of mine!";
    const wchar_t* sep = L" ,!";

    unsigned int cnt = 0;
    do {
       str = wcspbrk(str, sep); // 寻找分隔符
       if (str) str += wcsspn(str, sep); // 跳过分隔符
       ++cnt; // 增加词计数
    } while (str && *str);

    wprintf(L"There are %u words.\n", cnt);
}

输出：

There are 5 words.

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.5.3 The wcspbrk function (p: 436)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.5.3 The wcspbrk function (p: 382)

参阅

wcscspn (C95) | 返回仅由不出现于另一个宽字符串中的宽字符分隔的最长首段长度 (函数)
wcschr (C95) | 查找宽字符在宽字符串中的首次出现 (函数)
strpbrk | 查找一个字符串中的任意一个字符在另一个字符串中的首个位置 (函数)


wcsrchr

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
wchar_t* wcsrchr( const wchar_t* str, wchar_t ch ); | (C95 起)

寻找宽字符 ch 在 str 所指向的空终止宽字符串中的最后一次出现。

参数

str | - | 指向要分析的空终止宽字符串的指针
ch | - | 要搜索的宽字符

返回值

指向 str 中找到的字符的指针，或若找不到这种字符则为空指针。

示例

#include <wchar.h>
#include <stdio.h>
#include <locale.h>

int main(void)
{
    wchar_t arr[] = L"白猫 黒猫 кошки";
    wchar_t *cat = wcsrchr(arr, L'猫');
    wchar_t *dog = wcsrchr(arr, L'犬');

    setlocale(LC_ALL, "en_US.utf8");
    if(cat) // 在位置%td处找到“猫”字
        printf("The character 猫 found at position %td\n", cat-arr);
    else    // 没有找到“猫”字
        puts("The character 猫 not found");

    if(dog) // 在位置%td处找到“犬”字
        printf("The character 犬 found at position %td\n", dog-arr);
    else    // 没有找到“犬”字
        puts("The character 犬 not found");
}

输出：

The character 猫 found at position 4
The character 犬 not found

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.5.4 The wcsrchr function (p: 436)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.5.4 The wcsrchr function (p: 382)

参阅

wcschr (C95) | 查找宽字符在宽字符串中的首次出现 (函数)
wcspbrk (C95) | 查找一个宽字符串中的任何字符在另一个宽字符串中的首个位置 (函数)


wcsspn

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
size_t wcsspn( const wchar_t* dest, const wchar_t* src ); | (C95 起)

返回 dest 所指向的空终止宽字符串的，仅由在 src 所指向的宽字符串中找到的字符组成的最大起始段的长度。

参数

dest | - | 指向要分析的空终止宽字符串的指针
src | - | 指向含有要搜索的字符的空终止宽字符串的指针

返回值

仅由来自 src 所指向的宽字符串的字符组成的最大起始段长度。

示例

#include <locale.h>
#include <wchar.h>

int main(void)
{
    wchar_t dest[] = L"白猫 黑狗 甲虫";
    const wchar_t src[] = L" 狗猫 白黑 ";
    const size_t len = wcsspn(dest, src);
    dest[len] = L'\0'; /* 终止字符串，以便显示*/

    setlocale(LC_ALL, "en_US.utf8");
    wprintf(L"The length of maximum initial segment is %td.\n"
            L"The segment is \"%ls\".\n", len, dest);
}

输出：

The length of maximum initial segment is 6.
The segment is "白猫 黑狗 ".

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.5.5 The wcsspn function (p: 436)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.5.5 The wcsspn function (p: 382)

参阅

wcscspn (C95) | 返回仅由不出现于另一个宽字符串中的宽字符分隔的最长首段长度 (函数)
wcspbrk (C95) | 查找一个宽字符串中的任何字符在另一个宽字符串中的首个位置 (函数)


wcsstr

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
wchar_t* wcsstr( const wchar_t* dest, const wchar_t* src ); | (C95 起)

寻找 dest 所指的空终止宽字符串在 src 所指的空终止宽字符串中的首次出现。不比较空终止字符。

若 src 或 dest 不是指向空终止字节字符串的指针，则行为未定义。

参数

dest | - | 指向要检验的空终止字节字符串的指针
src | - | 指向要搜索的空终止宽字符串的指针

返回值

指向于 dest 中找到的子串首字符的指针，或若找不到该子串则为空指针。若 src 指向空字符串，则返回 dest 。

示例

#include <stdio.h>
#include <locale.h>
#include <wchar.h>

int main(void)
{
    setlocale(LC_ALL, "ru_RU.UTF-8");

    wchar_t str[5][64] = {
        L"Строка, где есть подстрока 'но'.",
        L"Строка, где такой подстроки нет.",
        L"Он здесь.",
        L"Здесь он.",
        L"Его нет."
    };

    for (size_t i = 0; i < 5; ++i) {
        if (wcsstr(str[i], L"но")) {
            wprintf(L"%ls\n", str[i]);
        }
    }
}

输出：

Строка, где есть подстрока 'но'.

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.5.6 The wcsstr function (p: 437)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.5.6 The wcsstr function (p: 383)

参阅

wcschr (C95) | 查找宽字符在宽字符串中的首次出现 (函数)
wcsrchr (C95) | 查找宽字符在宽字符串中的最后一次出现 (函数)


wcstof, wcstod, wcstold

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
float wcstof( const wchar_t * restrict str, wchar_t ** restrict str_end ); | (C99 起)
double wcstod( const wchar_t * str, wchar_t ** str_end ); | (C95 起) (C99 前)
double wcstod( const wchar_t * restrict str, wchar_t ** restrict str_end ); | (C99 起)
long double wcstold( const wchar_t * restrict str, wchar_t ** restrict str_end ); | (C99 起)

转译 str 所指向的宽字符串中的浮点值。

函数会舍弃任何空白符（由 std:: iswspace () 确定），直至找到首个非空白符。然后它会取用尽可能多的字符，以构成合法的浮点数表示，并将它们转换成浮点值。合法的浮点值可以为下列之一：

  • 十进制浮点数表达式。它由下列部分组成：
  • (可选) 正或负号
  • 非空的十进制数字序列，可选地包含一个小数点字符（由当前的 C 本地环境确定）（定义有效数字）
  • (可选) e 或 E ，并跟随可选的正或负号，以及非空十进制数字序列（以 10 为底定义指数）
  • 十六进制浮点数表达式。它由下列部分组成：
  • (可选) 正或负号
  • 0x 或 0X
  • 非空的十六进制数字序列，选地包含一个小数点字符（由当前的 C 本地环境确定）（定义有效数字）
  • (可选) p 或 P ，并跟随可选的正或负号，以及非空十进制数字序列（以 2 为底定义指数）
  • 无穷大表达式。它由下列部分组成：
  • (可选) 正或负号
  • INF 或 INFINITY ，忽略大小写
  • 非数（NaN）表达式。它由下列部分组成：
  • (可选) 正或负号
  • NAN 或 NAN(char_sequence) ，忽略 NAN 部分的大小写。 char_sequence 只能由数字、拉丁字母和下划线构成。结果是一个静态的 NaN 浮点值。
 (C99 起)
  • 任何其他可由当前 C 本地环境接受的表达式

函数设置 str_end 所指向的指针为指向最后被转译宽字符的后一字符。若 str_end 为空指针，则忽略它。

参数

str | - | 指向要转译的空终止宽字符串的指针
str_end | - | 指向指向宽字符指针的指针。

返回值

成功时为对应 str 内容的浮点值。若转换得到的值落在对应返回类型的范围外，则发生值域错误并返回 HUGE_VAL 、 HUGE_VALF 或 HUGE_VALL 。若不能进行转换，则返回 ​0​ 。

示例

#include <stdio.h>
#include <errno.h>
#include <wchar.h>

int main(void)
{
    const wchar_t *p = L"111.11 -2.22 0X1.BC70A3D70A3D7P+6  1.18973e+4932zzz";
    printf("Parsing L\"%ls\":\n", p);
    wchar_t *end;
    for (double f = wcstod(p, &end); p != end; f = wcstod(p, &end))
    {
        printf("'%.*ls' -> ", (int)(end-p), p);
        p = end;
        if (errno == ERANGE){
            printf("range error, got ");
            errno = 0;
        }
        printf("%f\n", f);
    }
}

输出：

Parsing L"111.11 -2.22 0X1.BC70A3D70A3D7P+6  1.18973e+4932zzz":
'111.11' -> 111.110000
' -2.22' -> -2.220000
' 0X1.BC70A3D70A3D7P+6' -> 111.110000
'  1.18973e+4932' -> range error, got inf

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.1.1 The wcstod, wcstof, and wcstold functions (p: 426-428)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.1.1 The wcstod, wcstof, and wcstold functions (p: 372-374)

参阅

strtofstrtodstrtold
(C99)(C99)
 将字节字符串转换成浮点值
(函数)


wcstoimax, wcstoumax

< c‎ | string‎ | wide
定义于头文件 <inttypes.h> |
intmax_t wcstoimax( const wchar_t *restrict nptr, wchar_t **restrict endptr, int base ); | (C99 起)
uintmax_t wcstoumax( const wchar_t *restrict nptr, wchar_t **restrict endptr, int base ); | (C99 起)

转译 nptr 所指向的宽字符串中的整数值。

舍弃所有空白符（以调用 isspace() 鉴别），直到找到首个非空白符，然后取尽可能多的字符组成底 n （其中 n=base ）的无符号整数表示，并将它们转换成一个整数值。合法的无符号整数值由下列部分组成：

  • (可选)正或负号
  • (可选)指示八进制底的前缀（ 0 ）（仅当底为 8 或 ​0​ 时应用）
  • (可选)指示十六进制底的前缀（ 0x 或 0X ）（仅当底为 16 或 ​0​ 时应用）
  • 一个数字序列

底的合法集是 {0,2,3,...,36} 。合法数字集对于底 2 整数是 {0,1}，对于底3整数是 {0,1,2} ，以此类推。对于大于 10 的底，合法数字包含字母字符，从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。

当前安装的 C 本地环境可能接受另外的数字格式。

若 base 为 ​0​ ，则自动检测数值进制：若前缀为 0 ，则底为八进制，若前缀为 0x 或 0X ，则底为十六进制，否则底为十进制。

若符号是输入序列的一部分，则对从数字序列计算得来的数字值取反，如同用结果类型的一元减，它对无符号整数应用回卷规则。

函数将 endptr 所指向的指针设为指向最后转译的宽字符的后一宽字符。若 endptr 为空指针，则忽略它。

参数

nptr | - | 指向待转译的空终止宽字符串的指针
endptr | - | 指向宽字符指针的指针
base | - | 转译整数值的基底

返回值

成功时返回代表 str 内容的整数值。若转得的值落在对应类型之外，则出现值域错误，并返回 INTMAX_MAX 、 INTMAX_MIN 、 UINTMAX_MAX 或 ​0​ 中的最接近者。若无法进行转换，则返回 ​0​ 。

示例

#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>

int main(void)
{
  wchar_t* endptr;

  wprintf(L"%ld\n", wcstoimax(L" -123junk", &endptr, 10)); // 十进制
  wprintf(L"%ld\n", wcstoimax(L"11111111", &endptr, 2));   // 二进制
  wprintf(L"%ld\n", wcstoimax(L"XyZ", &endptr, 36));       // 三十六进制
  wprintf(L"%ld\n", wcstoimax(L"010", &endptr, 0));        // 八进制自动检测
  wprintf(L"%ld\n", wcstoimax(L"10", &endptr, 0));         // 十进制自动检测
  wprintf(L"%ld\n", wcstoimax(L"0x10", &endptr, 0));       // 十六进制自动检测

  // 值域错误
  // LONG_MAX+1 --> LONG_MAX
  errno = 0;
  wprintf(L"%ld\n", wcstoimax(L"9223372036854775808", &endptr, 10));
  wprintf(L"%s\n", strerror(errno));
}

输出：

-123
255
44027
8
10
16
9223372036854775807
Numerical result out of range

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.8.2.4 The wcstoimax and wcstoumax functions (p: 220)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.8.2.4 The wcstoimax and wcstoumax functions (p: 201)

参阅

strtoimaxstrtoumax (C99)(C99) | 将字节字符串转换成 intmax_t 或 uintmax_t (函数)
wcstolwcstoll (C95)(C99) | 将宽字符串转换成整数值 (函数)
wcstoulwcstoull (C95)(C99) | 将宽字符串转换成无符号整数值 (函数)


wcstok, wcstok_s

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |  |
 | (1) |
wchar_t* wcstok( wchar_t* str, const wchar_t* delim, wchar_t **ptr ); |  |  | (C95 起) (C99 前)
wchar_t *wcstok(wchar_t * restrict str, const wchar_t * restrict delim, wchar_t **restrict ptr); |  |  | (C99 起)
wchar_t *wcstok_s( wchar_t *restrict str, rsize_t *restrict strmax, const wchar_t *restrict delim, wchar_t **restrict ptr); | (2) | (C11 起)
1) 寻找 str 所指向的空终止宽字符串中的下个记号。以 delim 所指向的空终止宽字符串鉴别分隔符。
此函数被设计为调用多次以从同一字符串获得相继的记号。
  • 若 str != NULL ，则调用被当做 wcstok 首次对此具体宽字符的调用。函数搜索首个不含于 delim 的字符。
  • 若找不到这种宽字符，则 str 中完全无记号，而函数返回空指针。
  • 若找到这种宽字符，则它是记号起始。然后函数从该点搜索首个含于 delim 的宽字符。
  • 若找不到这种宽字符，则 str 只有一个记号，而对 wcstok 的将来调用将返回空指针
  • 若找到这种宽字符，则以空宽字符 L'\0' 替换它，并存储分析状态（典型地为指向后一宽字符的指针）于用户提供位置 *ptr 。
  • 然后函数返回指向记号起始的指针
  • 若 str == NULL ，则调用被当作对 wcstok 的后继调用：函数从带同一 *ptr 的先前调用所留下的位置开始持续。行为与如同将指向后随上次检测的记号的宽字符的指针作为 str 传递相同。
2) 同 (1) 除了在每步时，写入 str 中留待查看的字符数到 *strmax 。 重复的调用（以空 str ）必须传递先前的调用用以存储值的 strmax 和 ptr 。并且在运行时检测下列错误，并调用当前安装的制约处理函数：
  • strmax 、 delim 或 ptr 为空指针
  • 在非首次调用（以空 str ）时， *ptr 为空指针
  • 首次调用时， *strmax 为零或大于 RSIZE_MAX/sizeof(wchar_t)
  • 对记号的搜索抵达源字符串结尾（以 *strmax 的初值测量），而未遇到空终止符
同所有边界检查函数， wcstok_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 wchar.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

str | - | 指向要记号化的空终止宽字符串的指针
delim | - | 指向标识分隔符的空终止宽字符串的指针
ptr | - | 指向 wchar_t* 类型对象的指针， wcstok 和 wcstok_s 以之存储分析器的内部状态
strmax | - | 指向最初保有 str 大小的对象： wcstok_s 存储留待检验的字符数

返回值

返回指向下个记号起始的指针，或若无更多记号则为空指针。

注意

此函数是破坏性的：它写入 L'\0' 字符于字符串 str 的元素。特别是，宽字符串字面量不能用作 wcstok 的首参数。

不同于 strtok ， wcstok 不更新静态存储：它存储分析状态于用户提供的位置。

不同于大多数其他记号化器， wcstok 中的分隔符能对于后继记号不同，而且甚至能依赖于先前记号的内容。

示例

#include <wchar.h>
#include <stdio.h>

int main(void)
{
    wchar_t input[] = L"A bird came down the walk";
    printf("Parsing the input string '%ls'\n", input);
    wchar_t *buffer;
    wchar_t *token = wcstok(input, L" ", &buffer);
    while(token) {
        printf("%ls\n", token);
        token = wcstok(NULL, L" ", &buffer);
    }

    printf("Contents of the input string now: '");
    for(size_t n = 0; n < sizeof input / sizeof *input; ++n)
        input[n] ? printf("%lc", input[n]) : printf("\\0");
    puts("'");
}

输出：

Parsing the input string 'A bird came down the walk'
A
bird
came
down
the
walk
Contents of the input string now: 'A\0bird\0came\0down\0the\0walk\0'

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.5.7 The wcstok function (p: 437-438)
  • K.3.9.2.3.1 The wcstok_s function (p: 645-646)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.5.7 The wcstok function (p: 383-384)

参阅

strtokstrtok_s
(C11)
 查找字节字符串中的下一个记号
(函数)


wcstol, wcstoll

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
long wcstol( const wchar_t * str, wchar_t ** str_end, int base ); | (C95 起) (C99 前)
long wcstol( const wchar_t * str, wchar_t ** restrict str_end, int base ); | (C99 起)
long long wcstoll( const wchar_t * restrict str, wchar_t ** restrict str_end, int base ); | (C99 起)

转译 str 所指向的宽字符串中的整数值。

舍弃所有空白符（以调用 isspace() 鉴别），直到找到首个非空白符，然后取尽可能多的字符组成底 n （其中 n=base ）的整数表示，并将它们转换成一个整数值。合法的整数值由下列部分组成：

  • (可选)正或负号
  • (可选)指示八进制底的前缀（ 0 ）（仅当底为 8 或 ​0​ 时应用）
  • (可选)指示十六进制底的前缀（ 0x 或 0X ）（仅当底为 16 或 ​0​ 时应用）
  • 一个数字序列

底的合法集是 {0,2,3,...,36} 。合法数字集对于底 2 整数是 {0,1}，对于底3整数是 {0,1,2} ，以此类推。对于大于 10 的底，合法数字包含字母字符，从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。

当前安装的 C 本地环境可能接受另外的数字格式。

若 base 为 ​0​ ，则自动检测数值进制：若前缀为 0 ，则底为八进制，若前缀为 0x 或 0X ，则底为十六进制，否则底为十进制。

若符号是输入序列的一部分，则对从数字序列计算得来的数字值取反，如同用结果类型的一元减。

函数设置 str_end 所指向的指针指向最后一个被转译字符的后一宽字符。若 str_end 为空指针，则忽略之。

参数

str | - | 指向要转译的空终止宽字符串的指针
str_end | - | 指向指向宽字符的指针的指针
base | - | 被转译整数值的底

返回值

成功时为对应 str 内容的整数值。若转换得到的值落在对应类型的范围外，则发生值域错误并返回 LONG_MAX 、 LONG_MIN 、 LLONG_MAX 或 LLONG_MIN 。若不能进行转换，则返回 ​0​ 。

示例

#include <stdio.h>
#include <errno.h>
#include <wchar.h>

int main(void)
{
    const wchar_t *p = L"10 200000000000000000000000000000 30 -40";
    printf("Parsing L'%ls':\n", p);
    wchar_t *end;
    for (long i = wcstol(p, &end, 10);
         p != end;
         i = wcstol(p, &end, 10))
    {
        printf("'%.*ls' -> ", (int)(end-p), p);
        p = end;
        if (errno == ERANGE){
            printf("range error, got ");
            errno = 0;
        }
        printf("%ld\n", i);
    }
}

输出：

Parsing L'10 200000000000000000000000000000 30 -40':
'10' -> 10
' 200000000000000000000000000000' -> range error, got 9223372036854775807
' 30' -> 30
' -40' -> -40

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.1.2 The wcstol, wcstoll, wcstoul, and wcstoull functions (p: 429-430)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.1.2 The wcstol, wcstoll, wcstoul, and wcstoull functions (p: 375-376)

参阅

strtolstrtoll (C99) | 将字节字符串转换成整数值 (函数)
wcstoulwcstoull (C95)(C99) | 将宽字符串转换成无符号整数值 (函数)


wcstoul, wcstoull

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
unsigned long wcstoul( const wchar_t* str, wchar_t** str_end, int base ); | (C95 起) (C99 前)
unsigned long wcstoul( const wchar_t * restrict str, wchar_t ** restrict str_end, int base ); | (C99 起)
unsigned long long wcstoull( const wchar_t * restrict str, wchar_t ** restrict str_end, int base ); | (C99 起)

转译 str 所指向的宽字符串中的无符号整数值。

舍弃所有空白符（以调用 isspace() 鉴别），直到找到首个非空白符，然后取尽可能多的字符组成底 n （其中 n=base ）的无符号整数表示，并将它们转换成一个整数值。合法的无符号整数值由下列部分组成：

  • (可选)正或负号
  • (可选)指示八进制底的前缀（ 0 ）（仅当底为 8 或 ​0​ 时应用）
  • (可选)指示十六进制底的前缀（ 0x 或 0X ）（仅当底为 16 或 ​0​ 时应用）
  • 一个数字序列

底的合法集是 {0,2,3,...,36} 。合法数字集对于底 2 整数是 {0,1}，对于底3整数是 {0,1,2} ，以此类推。对于大于 10 的底，合法数字包含字母字符，从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。

当前安装的 C 本地环境可能接受另外的数字格式。

若 base 为 ​0​ ，则自动检测数值进制：若前缀为 0 ，则底为八进制，若前缀为 0x 或 0X ，则底为十六进制，否则底为十进制。

若符号是输入序列的一部分，则对从数字序列计算得来的数字值取反，如同用结果类型的一元减，它对无符号整数应用回卷规则。

函数设置 str_end 所指向的指针指向最后被转译字符的后一宽字符。若 str_end 为空指针，则忽略它。

参数

str | - | 指向要转译的空终止宽字符串的指针
str_end | - | 指向指向宽字符的指针的指针
base | - | 被转译整数值的底

返回值

成功时为对应 str 内容的整数值。若转换后的值落在对应返回类型的范围外，则出现值域错误并返回 ULONG_MAX 和 ULLONG_MAX 。若不能进行转换，则返回 ​0​ 。

示例

#include <stdio.h>
#include <errno.h>
#include <wchar.h>

int main(void)
{
    const wchar_t *p = L"10 200000000000000000000000000000 30 40";
    printf("Parsing L'%ls':\n", p);
    wchar_t *end;
    for (unsigned long i = wcstoul(p, &end, 10);
         p != end;
         i = wcstoul(p, &end, 10))
    {
        printf("'%.*ls' -> ", (int)(end-p), p);
        p = end;
        if (errno == ERANGE){
            printf("range error, got ");
            errno = 0;
        }
        printf("%lu\n", i);
    }
}

输出：

Parsing '10 200000000000000000000000000000 30 40':
'10' -> 10
' 200000000000000000000000000000' -> range error, got 18446744073709551615
' 30' -> 30
' 40' -> 40

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.1.2 The wcstol, wcstoll, wcstoul, and wcstoull functions (p: 429-430)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.1.2 The wcstol, wcstoll, wcstoul, and wcstoull functions (p: 375-376)

参阅

strtoul strtoull (C99) | 将字节字符串转换成无符号整数值 (函数)
wcstolwcstoll (C95)(C99) | 将宽字符串转换成整数值 (函数)


wcsxfrm

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
size_t wcsxfrm( wchar_t* dest, const wchar_t* src, size_t count ); | (C95 起) (C99 前)
size_t wcsxfrm( wchar_t* restrict dest, const wchar_t* restrict src, size_t count ); | (C99 起)

变换 src 所指向的空终止宽字符串为实现定义形式，满足在当前 C 本地环境中，用 wcscmp 比较二个变换后的字符串给出的结果与用 wcscoll 比较源字符串者相同。

将变换后字符串的首 count 个字符写入目标，包含空终止符，并返回完整的变换后字符串长度，排除空终止符。

若 count 为 ​0​ ，则允许 dest 为空指针。

注意

能接收整个变换后字符串的正确缓冲区长度是 1+wcsxfrm( NULL, src, 0) 。

在以同一宽字符串或宽字符串集进行本地环境依赖比较时使用此函数，因为只用 wcsxfrm 变换所有字符串一次，再以 wcscmp 进行后续比较更为高效。

参数

dest | - | 指向要写入变换后字符串到的空终止宽字符数组首元素的指针
src | - | 指向要变换的空终止宽字符串的指针
count | - | 要输出的最大字符数

返回值

变换后的空终止宽字符串的长度，不包含空终止字符。

示例

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main(void)
{
    setlocale(LC_ALL, "sv_SE.utf8");

    const wchar_t *in1 = L"\u00e5r";
    wchar_t out1[1+wcsxfrm(NULL, in1, 0)];
    wcsxfrm(out1, in1, sizeof out1/sizeof *out1);

    const wchar_t *in2 = L"\u00e4ngel";
    wchar_t out2[1+wcsxfrm(NULL, in2, 0)];
    wcsxfrm(out2, in2, sizeof out2/sizeof *out2);

    printf("In the Swedish locale: ");
    if(wcscmp(out1, out2) < 0)
         printf("%ls before %ls\n", in1, in2);
    else
         printf("%ls before %ls\n", in2, in1);

    printf("In lexicographical comparison: ");
    if(wcscmp(in1, in2) < 0)
         printf("%ls before %ls\n", in1, in2);
    else
         printf("%ls before %ls\n", in2, in1);
}

输出：

In the Swedish locale: år before ängel
In lexicographical comparison: ängel before år

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.4.4 The wcsxfrm function (p: 434-435)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.4.4 The wcsxfrm function (p: 380-381)

参阅

strcoll | 比较两个字符串，根据当前本地环境 (函数)
wcscoll (C95) | 根据当前本地环境比较两个宽字符串 (函数)
wcscmp (C95) | 比较两个宽字符串 (函数)
strxfrm | 变换字符串，使得 strcmp 会产生同 strcoll 的结果 (函数)


wctrans

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
wctrans_t wctrans( const char* str ); | (C95 起)

构造 wctrans_t 类型值，它描述宽字符映射的 LC_CTYPE 类别。它可以是标准映射，或如 "tojhira" 或 "tojkata" 的本地环境限定映射之一。

参数

str - 保有所欲映射名的 C 字符串。

下列 str 的值在所有 C 本地环境中受到支持：

str 的值 | 效果
"toupper" | 标识 towupper 所用的映射
"tolower" | 标识 towlower 所用的映射

返回值

wctrans_t 值，适合由 towctrans 用来根据当前 C 本地环境的具名映射映射宽字符，或若 str 不指名当前 C 本地环境所支持的映射则为零。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.3.2.2 The wctrans function (p: 454)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.3.2,2 The wctrans function (p: 400)

参阅

towctrans
(C95)
 按照指定的 LC_TYPE 映射分类进行字符映射
(函数)


wctype

< c‎ | string‎ | wide
定义于头文件 <wctype.h> |
wctype_t wctype( const char* str ); | (C95 起)

构造 wctype_t 类型值，它描述宽字符分类的 LC_CTYPE 类别。它可以是标准分类类别之一，或本地环境限定的类别，例如 "jkanji" 。

参数

str - 保有所欲类别名的 C 字符串

str 的下列值在所有 C 本地环境中得到支持：

str 的值 | 效果
"alnum" | 标识 iswalnum 所用的类别
"alpha" | 标识 iswalpha 所用的类别
"blank" | 标识 iswblank 所用的类别(C99)
"cntrl" | 标识 iswcntrl 所用的类别
"digit" | 标识 iswdigit 所用的类别
"graph" | 标识 iswgraph 所用的类别
"lower" | 标识 iswlower 所用的类别
"print" | 标识 iswprint 所用的类别
"space" | 标识 iswspace 所用的类别
"upper" | 标识 iswupper 所用的类别
"xdigit" | 标识 iswxdigit 所用的类别

返回值

wctype_t 值，适合由 iswctype 用以按照当前 C 本地环境的具名类别分类宽字符，或若str 不指名当前 C 本地环境支持的类别则为零。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.30.2.2.2 The wctype function (p: 452)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.25.2.2.2 The wctype function (p: 398)

参阅

iswctype
(C95)
 按照指定的 LC_CTYPE 类别分类宽字符
(函数)


wmemchr

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
wchar_t *wmemchr( const wchar_t *ptr, wchar_t ch, size_t count ); | (C95 起)

于 ptr 所指向的宽字符数组或任何兼容类型的整数数组的首 count 个宽字符中，定位宽字符 ch 的首次出现。

若 count 为零，则函数返回空指针。

参数

ptr | - | 指向要检验的宽字符数组的指针
ch | - | 要搜索的宽字符
count | - | 要检验的宽字符数

返回值

指向宽字符位置的指针，或若找不到这种字符则为空指针。

示例

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main(void)
{
    wchar_t str[] = L"诺不轻信，故人不负我\0诺不轻许，故我不负人。";
    size_t sz = sizeof str / sizeof *str;

    wchar_t target = L'许';
    wchar_t* result = wmemchr(str, target, sz);

    if (result) {
        setlocale(LC_ALL, "en_US.utf8");
        printf("Found '%lc' at position %td\n",target, result - str);
    }
}

可能的输出：

Found '许' at position 14

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.5.8 The wmemchr function (p: 438)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.5.8 The wmemchr function (p: 384)

参阅

memchr | 在数组中搜索字符的首次出现 (函数)
wcschr (C95) | 查找宽字符在宽字符串中的首次出现 (函数)


wmemcmp

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
int wmemcmp( const wchar_t *lhs, const wchar_t *rhs, size_t count ); | (C95 起)

比较 lhs 和 rhs 所指向的宽字符（或兼容整数类型）数组的首 count 个宽字符。按字典序比较。

结果的符号是在被比较数组中相异的首对宽字符值的差。

若 count 为零，则不做任何事。

参数

lhs, rhs | - | 指向要比较的宽字符数组的指针
count | - | 要检验的宽字符数

返回值

若 lhs 中首个相异的宽字符小于 rhs 中对应的宽字符则为负值：字典序中 lhs 先于 rhs 。

若 lhs 和 rhs 的全部 count 个宽字符相等则为 ​0​ 。

若 lhs 中首个相异的宽字符大于 rhs 中对应的宽字符则为正值：字典序中 rhs 先于 lhs 。

注意

此函数不考虑本地环境，且不注意其所检验的 wchar_t 对象的值：亦会比较空字符和非法宽字符。

示例

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

void demo(const wchar_t* lhs, const wchar_t* rhs, size_t sz)
{
    for(size_t n = 0; n < sz; ++n) putwchar(lhs[n]);
    int rc = wmemcmp(lhs, rhs, sz);
    if(rc == 0)
        wprintf(L" compares equal to ");
    else if(rc < 0)
        wprintf(L" precedes ");
    else if(rc > 0)
        wprintf(L" follows ");
    for(size_t n = 0; n < sz; ++n) putwchar(rhs[n]);
    wprintf(L" in lexicographical order\n");
}

int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");

    wchar_t a1[] = {L'α',L'β',L'γ'};
    wchar_t a2[] = {L'α',L'β',L'δ'};

    size_t sz = sizeof a1 / sizeof *a1;
    demo(a1, a2, sz);
    demo(a2, a1, sz);
    demo(a1, a1, sz);
}

输出：

αβγ precedes αβδ in lexicographical order
αβδ follows αβγ in lexicographical order
αβγ compares equal to αβγ in lexicographical order

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.4.5 The wmemcmp function (p: 435)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.4.5 The wmemcmp function (p: 381)

参阅

wcscmp (C95) | 比较两个宽字符串 (函数)
memcmp | 比较两块缓冲区 (函数)
wcsncmp (C95) | 比较来自两个宽字符串的一定量字符 (函数)


wmemcpy, wmemcpy_s

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |  |
 | (1) |
wchar_t* wmemcpy( wchar_t* dest, const wchar_t* src, size_t count ); |  |  | (C95 起) (C99 前)
wchar_t *wmemcpy(wchar_t *restrict dest, const wchar_t *restrict src, size_t count ); |  |  | (C99 起)
errno_t wmemcpy_s( wchar_t *restrict dest, rsize_t destsz, const wchar_t *restrict src, rsize_t count ); | (2) | (C11 起)
1) 从 src 所指向的宽字符数组准确复制 count 个相继的宽字符到 dest 所指向的宽字符数组。若对象重叠，则行为未定义。若 count 为零，则函数不做任何事。
2) 同 (1) ，除了在运行时检测下列错误，并调用当前安装的制约处理函数：
  • src 或 dest 是空指针
  • destsz 或 count 大于 RSIZE_MAX/sizeof(wchar_t)
  • count 大于 destsz （会发生溢出）
  • 源和目标数组间会发生重叠
同所有边界检查函数， wmemcpy_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 wchar.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dest | - | 指向复制目标宽字符数组的指针
src | - | 指向复制来源宽字符数组的指针
count | - | 要复制的宽字符数
destsz | - | 要写入的最大宽字符数（目标缓冲区的大小）

返回值

1) 返回 dest 的副本
2) 成功时返回零，错误时返回非零。在错误时，亦以空宽字符 L'\0' 填充整个 dst ，直到而不包含 dst+dstsz （除非 dest 为空或 destsz 大于 RSIZE_MAX/sizeof(wchar_t) ）

注意

此函数对字节字符串的类似版本是 strncpy ，而非 strcpy。

此函数不考虑本地环境，而且不关心其所复制的 wchar_t 对象的值：亦复制空字符还有非法字符。

示例

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main(void)
{
    wchar_t from1[] = L"नमस्ते";
    size_t sz1 = sizeof from1 / sizeof *from1;
    wchar_t from2[] = L"Բարև";
    size_t sz2 = sizeof from2 / sizeof *from2;
    wchar_t to[sz1 + sz2];
    wmemcpy(to, from1, sz1); // 复制 from1 ，沿着其空终止符
    wmemcpy(to + sz1, from2, sz2); // 后附 from2 ，沿着其空终止符

    setlocale(LC_ALL, "en_US.utf8");
    printf("Wide array contains: ");
    for(size_t n = 0; n < sizeof to / sizeof *to; ++n)
        if(to[n])
            printf("%lc", to[n]);
        else
            printf("\\0");
    printf("\n");
}

可能的输出：

Wide array contains: नमस्ते\0Բարև\0

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.2.3 The wmemcpy function (p: 431)
  • K.3.9.2.1.3 The wmemcpy_s function (p: 641)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.2.3 The wmemcpy function (p: 377)

参阅

wmemmovewmemmove_s (C95)(C11) | 在两个可能重叠的数组间复制一定数量的宽字符 (函数)
strncpystrncpy_s (C11) | 从一个字符串复制一定数量的字符到另一个 (函数)


wmemmove, wmemmove_s

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |  |
wchar_t* wmemmove( wchar_t* dest, const wchar_t* src, size_t count ); | (1) | (C95 起)
errno_t wmemmove_s( wchar_t *dest, rsize_t destsz, const wchar_t *src, rsize_t count); | (2) | (C11 起)
1) 准确地从 src 所指向的宽字符数组复制 count 个相继的宽字符到 dest 所指向的宽字符数组。若 count 为零，则函数不做任何事。数组可以重叠：如同复制宽字符到临时宽字符数组，再从临时数组到 dest 一般发生复制。
2) 同 (1) ，除了在运行时检测下列错误，并调用当前安装的制约处理函数：
  • src 或 dest 为空指针
  • destsz 或 count 大于 RSIZE_MAX/sizeof(wchar_t)
  • count 大于 destsz （会出现溢出）
同所有边界检查函数， wmemmove_s 仅若实现定义了 __STDC_LIB_EXT1__ ，且用户在包含 wchar.h 前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。

参数

dest | - | 指向复制目标宽字符数组的指针
src | - | 指向复制来源宽字符数组的指针
destsz | - | 写入的最大宽字符数（目标缓冲区大小）
count | - | 要复制的宽字符数

返回值

1) 返回 dest 的副本。
2) 成功时返回零，错误时返回非零。而且在错误时，以空宽字符 L'\0' 填充整个 dst ，直到且不包含 dst+dstsz （除非 dest 为空或 destsz 大于 RSIZE_MAX/sizeof(wchar_t) ）

注意

此函数不考虑本地环境，并且不注意其所复制的 wchar_t 对象的值：亦会复制空字符和非法字符。

示例

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main(void)
{
    setlocale(LC_ALL, "en_US.utf8");

    wchar_t str[] = L"αβγδεζηθικλμνξοπρστυφχψω";
    printf("%ls\n", str);
    wmemmove(str+4, str+3, 3); // 从 [δεζ] 复制到 [εζη]
    printf("%ls\n", str);
}

输出：

αβγδεζηθικλμνξοπρστυφχψω
αβγδδεζθικλμνξοπρστυφχψω

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.2.4 The wmemmove function (p: 432)
  • K.3.9.2.1.4 The wmemmove_s function (p: 642)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.2.4 The wmemmove function (p: 378)

参阅

memmovememmove_s (C11) | 将一个缓冲区移动到另一个 (函数)
wmemcpywmemcpy_s (C95)(C11) | 在两个不重叠的数组间复制一定数量的宽字符 (函数)


wmemset

< c‎ | string‎ | wide
定义于头文件 <wchar.h> |
wchar_t *wmemset( wchar_t *dest, wchar_t ch, size_t count ); | (C95 起)

复制宽字符 ch 到 dest 所指向的宽字符数组（或兼容类型的整数数组）的首 count 个宽字符。

若出现溢出，则行为未定义。

若 count 为零，则函数不做任何事。

参数

dest | - | 指向要填充的宽字符数组的指针
ch | - | 填充的宽字符
count | - | 要填充的宽字符数

返回值

返回 dest 的副本

注意

此函数不受本地环境影响，且不注意其写入的 wchar_t 对象的值：亦写入空字符还有非法宽字符。

示例

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main(void)
{
    wchar_t ar[10] = L"1234567890"; // 数组中无尾随空字符
    wmemset(ar, L'\U0001f34c', 5); // 以 🍌 替换 [12345]
    wmemset(ar+5, L'蕉', 5); // 以 蕉 替换 [67890]

    setlocale(LC_ALL, "en_US.utf8");
    for(size_t n = 0; n < sizeof ar/sizeof *ar; ++n)
        putwchar(ar[n]);
    putwchar(L'\n');
}

输出：

🍌🍌🍌🍌🍌蕉蕉蕉蕉蕉

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.29.4.6.2 The wmemset function (p: 439)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.24.4.6.2 The wmemset function (p: 385)

参阅

memsetmemset_s (C11) | 以字符填充缓冲区 (函数)
wmemcpywmemcpy_s (C95)(C11) | 在两个不重叠的数组间复制一定数量的宽字符 (函数)


符号索引

< c

此页面尝试列出来自标准库的所有可用符号。符号书写如下：

  • 函数和仿函数宏名带 () 。
  • 泛型函数名标记带 (泛型) 。

_ A B C D E F G H I J L M N O P Q R S T U V W

宏

_ (下划线)

_Exit() (C99 起)

A

abort()
abort_handler_s() (C11 起)
abs()
acos()
acosf() (C99 起)
acosh() (C99 起)
acoshf() (C99 起)
acoshl() (C99 起)
acosl() (C99 起)
aligned_alloc() (C11 起)
asctime()
asctime_r() (C23 起)
asctime_s() (C11 起)
asin()
asinf() (C99 起)
asinh() (C99 起)
asinhf() (C99 起)
asinhl() (C99 起)
asinl() (C99 起)
at_quick_exit() (C11 起)
atan()
atan2()
atan2f() (C99 起)
atan2l() (C99 起)
atanf() (C99 起)
atanh() (C99 起)
atanhf() (C99 起)
atanhl() (C99 起)
atanl() (C99 起)
atexit()
atof()
atoi()
atol()
atoll() (C99 起)

atomic_type

atomic_bool (C11 起)
atomic_char (C11 起)
atomic_char16_t (C11 起)
atomic_char32_t (C11 起)
atomic_int (C11 起)
atomic_int_fast16_t (C11 起)
atomic_int_fast32_t (C11 起)
atomic_int_fast64_t (C11 起)
atomic_int_fast8_t (C11 起)
atomic_int_least16_t (C11 起)
atomic_int_least32_t (C11 起)
atomic_int_least64_t (C11 起)
atomic_int_least8_t (C11 起)
atomic_intmax_t (C11 起)
atomic_intptr_t (C11 起)
atomic_llong (C11 起)
atomic_long (C11 起)
atomic_ptrdiff_t (C11 起)
atomic_schar (C11 起)
atomic_short (C11 起)
atomic_size_t (C11 起)
atomic_uchar (C11 起)
atomic_uint (C11 起)
atomic_uint_fast16_t (C11 起)
atomic_uint_fast32_t (C11 起)
atomic_uint_fast64_t (C11 起)
atomic_uint_fast8_t (C11 起)
atomic_uint_least16_t (C11 起)
atomic_uint_least32_t (C11 起)
atomic_uint_least64_t (C11 起)
atomic_uint_least8_t (C11 起)
atomic_uintmax_t (C11 起)
atomic_uintptr_t (C11 起)
atomic_ullong (C11 起)
atomic_ulong (C11 起)
atomic_ushort (C11 起)
atomic_wchar_t (C11 起)

atomic_compare_exchange_strong() (泛型) (C11 起)
atomic_compare_exchange_strong_explicit() (泛型) (C11 起)
atomic_compare_exchange_weak() (泛型) (C11 起)
atomic_compare_exchange_weak_explicit() (泛型) (C11 起)
atomic_exchange() (泛型) (C11 起)
atomic_exchange_explicit() (泛型) (C11 起)
atomic_fetch_add() (泛型) (C11 起)
atomic_fetch_add_explicit() (泛型) (C11 起)
atomic_fetch_and() (泛型) (C11 起)
atomic_fetch_and_explicit() (泛型) (C11 起)
atomic_fetch_or() (泛型) (C11 起)
atomic_fetch_or_explicit() (泛型) (C11 起)
atomic_fetch_sub() (泛型) (C11 起)
atomic_fetch_sub_explicit() (泛型) (C11 起)
atomic_fetch_xor() (泛型) (C11 起)
atomic_fetch_xor_explicit() (泛型) (C11 起)
atomic_flag (C11 起)
atomic_flag_clear() (C11 起)
atomic_flag_clear_explicit() (C11 起)
atomic_flag_test_and_set() (C11 起)
atomic_flag_test_and_set_explicit() (C11 起)
atomic_init() (泛型) (C11 起)
atomic_is_lock_free() (泛型) (C11 起)
atomic_load() (泛型) (C11 起)
atomic_load_explicit() (泛型) (C11 起)
atomic_signal_fence() (C11 起)
atomic_store() (泛型) (C11 起)
atomic_store_explicit() (泛型) (C11 起)
atomic_thread_fence() (C11 起)

B

bsearch()
bsearch_s() (C11 起)
btowc() (C95 起)

C

c16rtomb() (C11 起)
c32rtomb() (C11 起)
cabs() (C99 起)
cabsf() (C99 起)
cabsl() (C99 起)
cacos() (C99 起)
cacosf() (C99 起)
cacosh() (C99 起)
cacoshf() (C99 起)
cacoshl() (C99 起)
cacosl() (C99 起)
call_once() (C11 起)
calloc()
carg() (C99 起)
cargf() (C99 起)
cargl() (C99 起)
casin() (C99 起)
casinf() (C99 起)
casinh() (C99 起)
casinhf() (C99 起)
casinhl() (C99 起)
casinl() (C99 起)
catan() (C99 起)
catanf() (C99 起)
catanh() (C99 起)
catanhf() (C99 起)
catanhl() (C99 起)
catanl() (C99 起)
cbrt() (C99 起)
cbrtf() (C99 起)
cbrtl() (C99 起)
ccos() (C99 起)
ccosf() (C99 起)
ccosh() (C99 起)
ccoshf() (C99 起)
ccoshl() (C99 起)
ccosl() (C99 起)
ceil()
ceilf() (C99 起)
ceill() (C99 起)
cexp() (C99 起)
cexpf() (C99 起)
cexpl() (C99 起)
char16_t (C11 起)
char32_t (C11 起)
cimag() (C99 起)
cimagf() (C99 起)
cimagl() (C99 起)
clearerr()
clock()
clock_t
clog() (C99 起)
clogf() (C99 起)
clogl() (C99 起)
cnd_broadcast() (C11 起)
cnd_destroy() (C11 起)
cnd_init() (C11 起)
cnd_signal() (C11 起)
cnd_t (C11 起)
cnd_timedwait() (C11 起)
cnd_wait() (C11 起)
conj() (C99 起)
conjf() (C99 起)
conjl() (C99 起)
constraint_handler_t (C11 起)
copysign() (C99 起)
copysignf() (C99 起)
copysignl() (C99 起)
cos()
cosf() (C99 起)
cosh()
coshf() (C99 起)
coshl() (C99 起)
cosl() (C99 起)
cpow() (C99 起)
cpowf() (C99 起)
cpowl() (C99 起)
cproj() (C99 起)
cprojf() (C99 起)
cprojl() (C99 起)
creal() (C99 起)
crealf() (C99 起)
creall() (C99 起)
csin() (C99 起)
csinf() (C99 起)
csinh() (C99 起)
csinhf() (C99 起)
csinhl() (C99 起)
csinl() (C99 起)
csqrt() (C99 起)
csqrtf() (C99 起)
csqrtl() (C99 起)
ctan() (C99 起)
ctanf() (C99 起)
ctanh() (C99 起)
ctanhf() (C99 起)
ctanhl() (C99 起)
ctanl() (C99 起)
ctime()
ctime_r() (C23 起)
ctime_s() (C11 起)

D

difftime()
div()
div_t
double_t (C99 起)

E

erf() (C99 起)
erfc() (C99 起)
erfcf() (C99 起)
erfcl() (C99 起)
erff() (C99 起)
erfl() (C99 起)
errno_t (C11 起)
exit()
exp()
exp2() (C99 起)
exp2f() (C99 起)
exp2l() (C99 起)
expf() (C99 起)
expl() (C99 起)
expm1() (C99 起)
expm1f() (C99 起)
expm1l() (C99 起)

F

fabs()
fabsf() (C99 起)
fabsl() (C99 起)
fclose()
fdim() (C99 起)
fdimf() (C99 起)
fdiml() (C99 起)
feclearexcept() (C99 起)
fegetenv() (C99 起)
fegetexceptflag() (C99 起)
fegetround() (C99 起)
feholdexcept() (C99 起)
fenv_t (C99 起)
feof()
feraiseexcept() (C99 起)
ferror()
fesetenv() (C99 起)
fesetexceptflag() (C99 起)
fesetround() (C99 起)
fetestexcept() (C99 起)
feupdateenv() (C99 起)
fexcept_t (C99 起)
fflush()
fgetc()
fgetpos()
fgets()
fgetwc() (C95 起)
fgetws() (C95 起)
FILE
float_t (C99 起)
floor()
floorf() (C99 起)
floorl() (C99 起)
fma() (C99 起)
fmaf() (C99 起)
fmal() (C99 起)
fmax() (C99 起)
fmaxf() (C99 起)
fmaxl() (C99 起)
fmin() (C99 起)
fminf() (C99 起)
fminl() (C99 起)
fmod()
fmodf() (C99 起)
fmodl() (C99 起)
fopen()
fopen_s() (C11 起)
fpos_t
fprintf()
fprintf_s() (C11 起)
fputc()
fputs()
fputwc() (C95 起)
fputws() (C95 起)
fread()
free()
freopen()
freopen_s() (C11 起)
frexp()
frexpf() (C99 起)
frexpl() (C99 起)
fscanf()
fscanf_s() (C11 起)
fseek()
fsetpos()
ftell()
fwide() (C95 起)
fwprintf() (C95 起)
fwprintf_s() (C11 起)
fwrite()
fwscanf() (C95 起)
fwscanf_s() (C11 起)

G

getc()
getchar()
getenv()
getenv_s() (C11 起)
gets() (C11 中移除)
gets_s() (C11 起)
getwc() (C95 起)
getwchar() (C95 起)
gmtime()
gmtime_r() (C23 起)
gmtime_s() (C11 起)

H

hypot() (C99 起)
hypotf() (C99 起)
hypotl() (C99 起)

I

ignore_handler_s() (C11 起)
ilogb() (C99 起)
ilogbf() (C99 起)
ilogbl() (C99 起)
imaxabs() (C99 起)
imaxdiv() (C99 起)
imaxdiv_t (C99 起)

intwidth_t

int_fast16_t (C99 起)
int_fast32_t (C99 起)
int_fast64_t (C99 起)
int_fast8_t (C99 起)
int_least16_t (C99 起)
int_least32_t (C99 起)
int_least64_t (C99 起)
int_least8_t (C99 起)
int16_t (C99 起)
int32_t (C99 起)
int64_t (C99 起)
int8_t (C99 起)
intmax_t (C99 起)
intptr_t (C99 起)

isalnum()
isalpha()
isblank() (C99 起)
iscntrl()
isdigit()
isgraph()
islower()
isprint()
ispunct()
isspace()
isupper()
iswalnum() (C95 起)
iswalpha() (C95 起)
iswblank() (C99 起)
iswcntrl() (C95 起)
iswctype() (C95 起)
iswdigit() (C95 起)
iswgraph() (C95 起)
iswlower() (C95 起)
iswprint() (C95 起)
iswpunct() (C95 起)
iswspace() (C95 起)
iswupper() (C95 起)
iswxdigit() (C95 起)
isxdigit()

J

jmp_buf

L

labs()
lconv
ldexp()
ldexpf() (C99 起)
ldexpl() (C99 起)
ldiv()
ldiv_t
lgamma() (C99 起)
lgammaf() (C99 起)
lgammal() (C99 起)
llabs() (C99 起)
lldiv() (C99 起)
lldiv_t (C99 起)
llrint() (C99 起)
llrintf() (C99 起)
llrintl() (C99 起)
llround() (C99 起)
llroundf() (C99 起)
llroundl() (C99 起)
localeconv()
localtime()
localtime_r() (C23 起)
localtime_s() (C11 起)
log()
log10()
log10f() (C99 起)
log10l() (C99 起)
log1p() (C99 起)
log1pf() (C99 起)
log1pl() (C99 起)
log2() (C99 起)
log2f() (C99 起)
log2l() (C99 起)
logb() (C99 起)
logbf() (C99 起)
logbl() (C99 起)
logf() (C99 起)
logl() (C99 起)
longjmp()
lrint() (C99 起)
lrintf() (C99 起)
lrintl() (C99 起)
lround() (C99 起)
lroundf() (C99 起)
lroundl() (C99 起)

M

malloc()
max_align_t (C11 起)
mblen()
mbrlen() (C95 起)
mbrtoc16() (C11 起)
mbrtoc32() (C11 起)
mbrtowc() (C95 起)
mbsinit() (C95 起)
mbsrtowcs() (C95 起)
mbsrtowcs_s() (C11 起)
mbstate_t (C95 起)
mbstowcs() (C95 起)
mbstowcs_s() (C11 起)
mbtowc()
memccpy() (C23 起)
memchr()
memcmp()
memcpy()
memcpy_s() (C11 起)
memmove()
memmove_s() (C11 起)
memory_order (C11 起)
memory_order_acq_rel (C11 起)
memory_order_acquire (C11 起)
memory_order_consume (C11 起)
memory_order_relaxed (C11 起)
memory_order_release (C11 起)
memory_order_seq_cst (C11 起)
memset()
memset_s() (C11 起)
mktime()
modf()
modff() (C99 起)
modfl() (C99 起)
mtx_destroy() (C11 起)
mtx_init() (C11 起)
mtx_lock() (C11 起)
mtx_plain (C11 起)
mtx_recursive (C11 起)
mtx_t (C11 起)
mtx_timed (C11 起)
mtx_timedlock() (C11 起)
mtx_trylock() (C11 起)
mtx_unlock() (C11 起)

N

nan() (C99 起)
nanf() (C99 起)
nanl() (C99 起)
nearbyint() (C99 起)
nearbyintf() (C99 起)
nearbyintl() (C99 起)
nextafter() (C99 起)
nextafterf() (C99 起)
nextafterl() (C99 起)
nexttoward() (C99 起)
nexttowardf() (C99 起)
nexttowardl() (C99 起)

O

once_flag (C11 起)

P

perror()
pow()
powf() (C99 起)
powl() (C99 起)
printf()
printf_s() (C11 起)
ptrdiff_t
putc()
putchar()
puts()
putwc() (C95 起)
putwchar() (C95 起)

Q

qsort()
qsort_s() (C11 起)
quick_exit() (C11 起)

R

raise()
rand()
realloc()
remainder() (C99 起)
remainderf() (C99 起)
remainderl() (C99 起)
remove()
remquo() (C99 起)
remquof() (C99 起)
remquol() (C99 起)
rename()
rewind()
rint() (C99 起)
rintf() (C99 起)
rintl() (C99 起)
round() (C99 起)
roundf() (C99 起)
roundl() (C99 起)
rsize_t (C11 起)

S

scalbln() (C99 起)
scalblnf() (C99 起)
scalblnl() (C99 起)
scalbn() (C99 起)
scalbnf() (C99 起)
scalbnl() (C99 起)
scanf()
scanf_s() (C11 起)
set_constraint_handler_s() (C11 起)
setbuf()
setlocale()
setvbuf()
sig_atomic_t
signal()
sin()
sinf() (C99 起)
sinh()
sinhf() (C99 起)
sinhl() (C99 起)
sinl() (C99 起)
size_t
snprintf() (C99 起)
snprintf_s() (C11 起)
snwprintf_s() (C11 起)
sprintf()
sprintf_s() (C11 起)
sqrt()
sqrtf() (C99 起)
sqrtl() (C99 起)
srand()
sscanf()
sscanf_s() (C11 起)
strcat()
strcat_s() (C11 起)
strchr()
strcmp()
strcoll()
strcpy()
strcpy_s() (C11 起)
strcspn()
strdup() (C23 起)
strerror()
strerror_s() (C11 起)
strerrorlen_s() (C11 起)
strftime()
strlen()
strncat()
strncat_s() (C11 起)
strncmp()
strncpy()
strncpy_s() (C11 起)
strndup() (C23 起)
strnlen_s() (C11 起)
strpbrk()
strrchr()
strspn()
strstr()
strtod()
strtof() (C99 起)
strtoimax() (C99 起)
strtok()
strtok_s() (C11 起)
strtol()
strtold()
strtoll() (C99 起)
strtoul()
strtoull() (C99 起)
strtoumax() (C99 起)
strxfrm()
swprintf() (C95 起)
swprintf_s() (C11 起)
swscanf() (C95 起)
swscanf_s() (C11 起)
system()

T

tan()
tanf() (C99 起)
tanh() (C99 起)
tanhf() (C99 起)
tanhl() (C99 起)
tanl() (C99 起)
tgamma() (C99 起)
tgammaf() (C99 起)
tgammal() (C99 起)
thrd_busy (C11 起)
thrd_create() (C11 起)
thrd_current() (C11 起)
thrd_detach() (C11 起)
thrd_equal() (C11 起)
thrd_error (C11 起)
thrd_exit() (C11 起)
thrd_join() (C11 起)
thrd_nomem (C11 起)
thrd_sleep() (C11 起)
thrd_start_t (C11 起)
thrd_success (C11 起)
thrd_t (C11 起)
thrd_timedout (C11 起)
thrd_yield() (C11 起)
time()
time_t
timespec (C11 起)
timespec_get() (C11 起)
timespec_getres() (C23 起)
tm
tmpfile()
tmpfile_s() (C11 起)
tmpnam()
tmpnam_s() (C11 起)
tolower()
toupper()
towctrans() (C95 起)
towlower() (C95 起)
towupper() (C95 起)
trunc() (C99 起)
truncf() (C99 起)
truncl() (C99 起)
tss_create() (C11 起)
tss_delete() (C11 起)
tss_dtor_t (C11 起)
tss_get() (C11 起)
tss_set() (C11 起)
tss_t (C11 起)

U

uintwidth_t

uint_fast16_t (C99 起)
uint_fast32_t (C99 起)
uint_fast64_t (C99 起)
uint_fast8_t (C99 起)
uint_least16_t (C99 起)
uint_least32_t (C99 起)
uint_least64_t (C99 起)
uint_least8_t (C99 起)
uint16_t (C99 起)
uint32_t (C99 起)
uint64_t (C99 起)
uint8_t (C99 起)
uintmax_t (C99 起)
uintptr_t (C99 起)

ungetc()
ungetwc() (C95 起)

V

vfprintf()
vfprintf_s() (C11 起)
vfscanf() (C99 起)
vfscanf_s() (C11 起)
vfwprintf() (C95 起)
vfwprintf_s() (C11 起)
vfwscanf() (C99 起)
vfwscanf_s() (C11 起)
vprintf()
vprintf_s() (C11 起)
vscanf() (C99 起)
vscanf_s() (C11 起)
vsnprintf() (C99 起)
vsnprintf_s() (C11 起)
vsnwprintf_s() (C11 起)
vsprintf()
vsprintf_s() (C11 起)
vsscanf() (C99 起)
vsscanf_s() (C11 起)
vswprintf() (C95 起)
vswprintf_s() (C11 起)
vswscanf() (C99 起)
vswscanf_s() (C11 起)
vwprintf() (C95 起)
vwprintf_s() (C11 起)
vwscanf() (C99 起)
vwscanf_s() (C11 起)

W

wchar_t
wcrtomb() (C95 起)
wcrtomb_s() (C11 起)
wcscat() (C95 起)
wcscat_s() (C11 起)
wcschr() (C95 起)
wcscmp() (C95 起)
wcscoll() (C95 起)
wcscpy() (C95 起)
wcscpy_s() (C11 起)
wcscspn() (C95 起)
wcsftime() (C95 起)
wcslen() (C95 起)
wcsncat() (C95 起)
wcsncat_s() (C11 起)
wcsncmp() (C95 起)
wcsncpy() (C95 起)
wcsncpy_s() (C11 起)
wcsnlen_s() (C11 起)
wcspbrk() (C95 起)
wcsrchr() (C95 起)
wcsrtombs() (C95 起)
wcsrtombs_s() (C11 起)
wcsspn() (C95 起)
wcsstr() (C95 起)
wcstod() (C95 起)
wcstof() (C99 起)
wcstoimax() (C99 起)
wcstok() (C95 起)
wcstok_s() (C11 起)
wcstol() (C95 起)
wcstold() (C99 起)
wcstoll() (C99 起)
wcstombs()
wcstombs_s() (C11 起)
wcstoul() (C95 起)
wcstoull() (C99 起)
wcstoumax() (C99 起)
wcsxfrm() (C95 起)
wctob() (C95 起)
wctomb()
wctomb_s() (C11 起)
wctrans() (C95 起)
wctrans_t (C95 起)
wctype() (C95 起)
wctype_t (C95 起)
wint_t (C95 起)
wmemchr() (C95 起)
wmemcmp() (C95 起)
wmemcpy() (C95 起)
wmemcpy_s() (C11 起)
wmemmove() (C95 起)
wmemmove_s() (C11 起)
wmemset() (C95 起)
wprintf() (C95 起)
wprintf_s() (C11 起)
wscanf() (C95 起)
wscanf_s() (C11 起)

参阅


宏符号索引

< c‎ | symbol index

此页面尝试列出所有来自标准库的可用宏符号。符号书写如下：

  • 仿函数宏名带 () 。
  • 泛型宏名标记为 (泛型) 。

_ A B C D E F H I K L M N O P R S T U V W X

_ (下划线)

__alignas_is_defined (C11 起)
__alignof_is_defined (C11 起)
__bool_true_false_are_defined (C99 起)
_Complex_I (C99 起)
_Imaginary_I (C99 起)
_IOFBF
_IOLBF
_IONBF

A

acos() (泛型) (C99 起)
acosh() (泛型) (C99 起)
alignas (关键词宏) (C11 起)
alignof (关键词宏) (C11 起)
and (运算符宏) (C95 起)
and_eq (运算符宏) (C95 起)
asin() (泛型) (C99 起)
asinh() (泛型) (C99 起)
assert()
atan() (泛型) (C99 起)
atan2() (泛型) (C99 起)
atanh() (泛型) (C99 起)

ATOMIC_TYPE_LOCK_FREE

ATOMIC_BOOL_LOCK_FREE (C11 起)
ATOMIC_CHAR_LOCK_FREE (C11 起)
ATOMIC_CHAR16_T_LOCK_FREE (C11 起)
ATOMIC_CHAR32_T_LOCK_FREE (C11 起)
ATOMIC_INT_LOCK_FREE (C11 起)
ATOMIC_LONG_LOCK_FREE (C11 起)
ATOMIC_POINTER_LOCK_FREE (C11 起)
ATOMIC_LLONG_LOCK_FREE (C11 起)
ATOMIC_SHORT_LOCK_FREE (C11 起)
ATOMIC_WCHAR_T_LOCK_FREE (C11 起)

ATOMIC_FLAG_INIT (C11 起)
ATOMIC_VAR_INIT() (C11 起)(C17 中弃用)

B

bitand (运算符宏) (C95 起)
bitor (运算符宏) (C95 起)
bool (关键词宏) (C99 起)
BOOL_WIDTH (C23 起)
BUFSIZ

C

carg() (泛型) (C99 起)
cbrt() (泛型) (C99 起)
ceil() (泛型) (C99 起)
CHAR_BIT
CHAR_MAX
CHAR_MIN
CHAR_WIDTH (C23 起)
cimag() (泛型) (C99 起)
CLOCKS_PER_SEC
CMPLX() (C11 起)
CMPLXF() (C11 起)
CMPLXL() (C11 起)
compl (运算符宏) (C95 起)
complex (关键词宏) (C99 起)
conj() (泛型) (C99 起)
copysign() (泛型) (C99 起)
cos() (泛型) (C99 起)
cosh() (泛型) (C99 起)
cproj() (泛型) (C99 起)
creal() (泛型) (C99 起)

D

DBL_DECIMAL_DIG (C11 起)
DBL_DIG
DBL_EPSILON
DBL_HAS_SUBNORM (C11 起)
DBL_MANT_DIG
DBL_MAX
DBL_MAX_10_EXP
DBL_MAX_EXP
DBL_MIN
DBL_MIN_10_EXP
DBL_MIN_EXP
DBL_TRUE_MIN (C11 起)
DECIMAL_DIG (C99 起)

E

EDOM
EILSEQ (C95 起)
EOF
ERANGE
erf() (泛型) (C99 起)
erfc() (泛型) (C99 起)
errno (宏变量)
EXIT_FAILURE
EXIT_SUCCESS
exp() (泛型) (C99 起)
exp2() (泛型) (C99 起)
expm1() (泛型) (C99 起)

F

fabs() (泛型) (C99 起)
false (C99 起)
fdim() (泛型) (C99 起)
FE_ALL_EXCEPT (C99 起)
FE_DFL_ENV (C99 起)
FE_DIVBYZERO (C99 起)
FE_DOWNWARD (C99 起)
FE_INEXACT (C99 起)
FE_INVALID (C99 起)
FE_OVERFLOW (C99 起)
FE_TONEAREST (C99 起)
FE_TOWARDZERO (C99 起)
FE_UNDERFLOW (C99 起)
FE_UPWARD (C99 起)
FILENAME_MAX
floor() (泛型) (C99 起)
FLT_DECIMAL_DIG (C11 起)
FLT_DIG
FLT_EPSILON
FLT_EVAL_METHOD (C99 起)
FLT_HAS_SUBNORM (C11 起)
FLT_MANT_DIG
FLT_MAX
FLT_MAX_10_EXP
FLT_MAX_EXP
FLT_MIN
FLT_MIN_10_EXP
FLT_MIN_EXP
FLT_RADIX
FLT_ROUNDS
FLT_TRUE_MIN (C11 起)
fma() (泛型) (C99 起)
fmax() (泛型) (C99 起)
fmin() (泛型) (C99 起)
fmod() (泛型) (C99 起)
FOPEN_MAX
FP_FAST_FMA (C99 起)
FP_FAST_FMAF (C99 起)
FP_FAST_FMAL (C99 起)
FP_ILOGB0 (C99 起)
FP_ILOGBNAN (C99 起)
FP_INFINITE (C99 起)
FP_NAN (C99 起)
FP_NORMAL (C99 起)
FP_SUBNORMAL (C99 起)
FP_ZERO (C99 起)
fpclassify() (C99 起)
frexp() (泛型) (C99 起)

H

HUGE_VAL
HUGE_VALF (C99 起)
HUGE_VALL (C99 起)
hypot() (泛型) (C99 起)

I

I (C99 起)
ilogb() (泛型) (C99 起)
imaginary (关键词宏) (C99 起)
INFINITY (C99 起)

INTWIDTH_MAX

INT_FAST16_MAX (C99 起)
INT_FAST32_MAX (C99 起)
INT_FAST64_MAX (C99 起)
INT_FAST8_MAX (C99 起)
INT_LEAST16_MAX (C99 起)
INT_LEAST32_MAX (C99 起)
INT_LEAST64_MAX (C99 起)
INT_LEAST8_MAX (C99 起)
INT16_MAX (C99 起)
INT32_MAX (C99 起)
INT64_MAX (C99 起)
INT8_MAX (C99 起)
INTMAX_MAX (C99 起)
INTPTR_MAX (C99 起)
INTWIDTH_MIN

INT_FAST16_MIN (C99 起)
INT_FAST32_MIN (C99 起)
INT_FAST64_MIN (C99 起)
INT_FAST8_MIN (C99 起)
INT_LEAST16_MIN (C99 起)
INT_LEAST32_MIN (C99 起)
INT_LEAST64_MIN (C99 起)
INT_LEAST8_MIN (C99 起)
INT16_MIN (C99 起)
INT32_MIN (C99 起)
INT64_MIN (C99 起)
INT8_MIN (C99 起)
INTMAX_MIN (C99 起)
INTPTR_MIN (C99 起)
UINTWIDTH_WIDTH

UINT_FAST16_WIDTH (C23 起)
UINT_FAST32_WIDTH (C23 起)
UINT_FAST64_WIDTH (C23 起)
UINT_FAST8_WIDTH (C23 起)
UINT_LEAST16_WIDTH (C23 起)
UINT_LEAST32_WIDTH (C23 起)
UINT_LEAST64_WIDTH (C23 起)
UINT_LEAST8_WIDTH (C23 起)
UINT16_WIDTH (C23 起)
UINT32_WIDTH (C23 起)
UINT64_WIDTH (C23 起)
UINT8_WIDTH (C23 起)
UINTMAX_WIDTH (C23 起)
UINTPTR_WIDTH (C23 起)

INT_MAX
INT_MIN
INT_WIDTH (C23 起)
INT16_C() (C99 起)
INT32_C() (C99 起)
INT64_C() (C99 起)
INT8_C() (C99 起)
INTMAX_C() (C99 起)
isfinite() (C99 起)
isgreater() (C99 起)
isgreaterequal() (C99 起)
isinf() (C99 起)
isless() (C99 起)
islessequal() (C99 起)
islessgreater() (C99 起)
isnan() (C99 起)
isnormal() (C99 起)
isunordered() (C99 起)

K

kill_dependency() (C11 起)

L

L_tmpnam
L_tmpnam_s (C11 起)
LC_ALL
LC_COLLATE
LC_CTYPE
LC_MONETARY
LC_NUMERIC
LC_TIME
LDBL_DECIMAL_DIG (C11 起)
LDBL_DIG
LDBL_EPSILON
LDBL_HAS_SUBNORM (C11 起)
LDBL_MANT_DIG
LDBL_MAX
LDBL_MAX_10_EXP
LDBL_MAX_EXP
LDBL_MIN
LDBL_MIN_10_EXP
LDBL_MIN_EXP
LDBL_TRUE_MIN (C11 起)
ldexp() (泛型) (C99 起)
lgamma() (泛型) (C99 起)
LLONG_MAX (C99 起)
LLONG_MIN (C99 起)
LLONG_WIDTH (C23 起)
llrint() (泛型) (C99 起)
llround() (泛型) (C99 起)
log() (泛型) (C99 起)
log10() (泛型) (C99 起)
log1p() (泛型) (C99 起)
log2() (泛型) (C99 起)
logb() (泛型) (C99 起)
LONG_MAX
LONG_MIN
LONG_WIDTH (C23 起)
lrint() (泛型) (C99 起)
lround() (泛型) (C99 起)

M

MATH_ERREXCEPT (C99 起)
math_errhandling (C99 起)
MATH_ERRNO (C99 起)
MB_CUR_MAX (宏变量)
MB_LEN_MAX

N

NAN (C99 起)
nearbyint() (泛型) (C99 起)
nextafter() (泛型) (C99 起)
nexttoward() (泛型) (C99 起)
noreturn (关键词宏) (C11 起)
not (运算符宏) (C95 起)
not_eq (运算符宏) (C95 起)
NULL

O

offsetof()
ONCE_FLAG_INIT (C11 起)
or (运算符宏) (C95 起)
or_eq (运算符宏) (C95 起)

P

pow() (泛型) (C99 起)

PRI{d i o u x X}WIDTH (宏字符串)

PRId16 (C99 起)
PRId32 (C99 起)
PRId64 (C99 起)
PRId8 (C99 起)
PRIdFAST16 (C99 起)
PRIdFAST32 (C99 起)
PRIdFAST64 (C99 起)
PRIdFAST8 (C99 起)
PRIdLEAST16 (C99 起)
PRIdLEAST32 (C99 起)
PRIdLEAST64 (C99 起)
PRIdLEAST8 (C99 起)
PRIdMAX (C99 起)
PRIdPTR (C99 起)
PRIi16 (C99 起)
PRIi32 (C99 起)
PRIi64 (C99 起)
PRIi8 (C99 起)
PRIiFAST16 (C99 起)
PRIiFAST32 (C99 起)
PRIiFAST64 (C99 起)
PRIiFAST8 (C99 起)
PRIiLEAST16 (C99 起)
PRIiLEAST32 (C99 起)
PRIiLEAST64 (C99 起)
PRIiLEAST8 (C99 起)
PRIiMAX (C99 起)
PRIiPTR (C99 起)
PRIo16 (C99 起)
PRIo32 (C99 起)
PRIo64 (C99 起)
PRIo8 (C99 起)
PRIoFAST16 (C99 起)
PRIoFAST32 (C99 起)
PRIoFAST64 (C99 起)
PRIoFAST8 (C99 起)
PRIoLEAST16 (C99 起)
PRIoLEAST32 (C99 起)
PRIoLEAST64 (C99 起)
PRIoLEAST8 (C99 起)
PRIoMAX (C99 起)
PRIoPTR (C99 起)
PRIu16 (C99 起)
PRIu32 (C99 起)
PRIu64 (C99 起)
PRIu8 (C99 起)
PRIuFAST16 (C99 起)
PRIuFAST32 (C99 起)
PRIuFAST64 (C99 起)
PRIuFAST8 (C99 起)
PRIuLEAST16 (C99 起)
PRIuLEAST32 (C99 起)
PRIuLEAST64 (C99 起)
PRIuLEAST8 (C99 起)
PRIuMAX (C99 起)
PRIuPTR (C99 起)
PRIx16 (C99 起)
PRIX16 (C99 起)
PRIx32 (C99 起)
PRIX32 (C99 起)
PRIx64 (C99 起)
PRIX64 (C99 起)
PRIx8 (C99 起)
PRIX8 (C99 起)
PRIxFAST16 (C99 起)
PRIXFAST16 (C99 起)
PRIxFAST32 (C99 起)
PRIXFAST32 (C99 起)
PRIxFAST64 (C99 起)
PRIXFAST64 (C99 起)
PRIxFAST8 (C99 起)
PRIXFAST8 (C99 起)
PRIxLEAST16 (C99 起)
PRIXLEAST16 (C99 起)
PRIxLEAST32 (C99 起)
PRIXLEAST32 (C99 起)
PRIxLEAST64 (C99 起)
PRIXLEAST64 (C99 起)
PRIxLEAST8 (C99 起)
PRIXLEAST8 (C99 起)
PRIxMAX (C99 起)
PRIXMAX (C99 起)
PRIxPTR (C99 起)
PRIXPTR (C99 起)

PTRDIFF_MAX (C99 起)
PTRDIFF_MIN (C99 起)
PTRDIFF_WIDTH (C23 起)

R

RAND_MAX
remainder() (泛型) (C99 起)
remquo() (泛型) (C99 起)
rint() (泛型) (C99 起)
round() (泛型) (C99 起)
RSIZE_MAX (宏变量) (C11 起)

S

scalbln() (泛型) (C99 起)
scalbn() (泛型) (C99 起)
SCHAR_MAX
SCHAR_MIN
SCHAR_WIDTH (C23 起)

SCN{d i o u x}WIDTH (宏字符串)

SCNd16 (C99 起)
SCNd32 (C99 起)
SCNd64 (C99 起)
SCNd8 (C99 起)
SCNdFAST16 (C99 起)
SCNdFAST32 (C99 起)
SCNdFAST64 (C99 起)
SCNdFAST8 (C99 起)
SCNdLEAST16 (C99 起)
SCNdLEAST32 (C99 起)
SCNdLEAST64 (C99 起)
SCNdLEAST8 (C99 起)
SCNdMAX (C99 起)
SCNdPTR (C99 起)
SCNi16 (C99 起)
SCNi32 (C99 起)
SCNi64 (C99 起)
SCNi8 (C99 起)
SCNiFAST16 (C99 起)
SCNiFAST32 (C99 起)
SCNiFAST64 (C99 起)
SCNiFAST8 (C99 起)
SCNiLEAST16 (C99 起)
SCNiLEAST32 (C99 起)
SCNiLEAST64 (C99 起)
SCNiLEAST8 (C99 起)
SCNiMAX (C99 起)
SCNiPTR (C99 起)
SCNo16 (C99 起)
SCNo32 (C99 起)
SCNo64 (C99 起)
SCNo8 (C99 起)
SCNoFAST16 (C99 起)
SCNoFAST32 (C99 起)
SCNoFAST64 (C99 起)
SCNoFAST8 (C99 起)
SCNoLEAST16 (C99 起)
SCNoLEAST32 (C99 起)
SCNoLEAST64 (C99 起)
SCNoLEAST8 (C99 起)
SCNoMAX (C99 起)
SCNoPTR (C99 起)
SCNu16 (C99 起)
SCNu32 (C99 起)
SCNu64 (C99 起)
SCNu8 (C99 起)
SCNuFAST16 (C99 起)
SCNuFAST32 (C99 起)
SCNuFAST64 (C99 起)
SCNuFAST8 (C99 起)
SCNuLEAST16 (C99 起)
SCNuLEAST32 (C99 起)
SCNuLEAST64 (C99 起)
SCNuLEAST8 (C99 起)
SCNuMAX (C99 起)
SCNuPTR (C99 起)
SCNx16 (C99 起)
SCNx32 (C99 起)
SCNx64 (C99 起)
SCNx8 (C99 起)
SCNxFAST16 (C99 起)
SCNxFAST32 (C99 起)
SCNxFAST64 (C99 起)
SCNxFAST8 (C99 起)
SCNxLEAST16 (C99 起)
SCNxLEAST32 (C99 起)
SCNxLEAST64 (C99 起)
SCNxLEAST8 (C99 起)
SCNxMAX (C99 起)
SCNxPTR (C99 起)

SEEK_CUR
SEEK_END
SEEK_SET
setjmp()
SHRT_MAX
SHRT_MIN
SHRT_WIDTH (C23 起)
SIG_ATOMIC_MAX (C99 起)
SIG_ATOMIC_MIN (C99 起)
SIG_ATOMIC_WIDTH (C23 起)
SIG_DFL
SIG_ERR
SIG_IGN
SIGABRT
SIGFPE
SIGILL
SIGINT
signbit() (C99 起)
SIGSEGV
SIGTERM
sin() (泛型) (C99 起)
sinh() (泛型) (C99 起)
SIZE_MAX (C99 起)
SIZE_WIDTH (C23 起)
sqrt() (泛型) (C99 起)
static_assert (关键词宏) (C11 起)
stderr
stdin
stdout

T

tan() (泛型) (C99 起)
tanh() (泛型) (C99 起)
tgamma() (泛型) (C99 起)
thread_local (关键词宏) (C11 起)
TIME_UTC (C11 起)
TMP_MAX
TMP_MAX_S (C11 起)
true (C99 起)
trunc() (泛型) (C99 起)
TSS_DTOR_ITERATIONS (C11 起)

U

UCHAR_MAX
UCHAR_WIDTH (C23 起)

UINTWIDTH_MAX

UINT_FAST16_MAX (C99 起)
UINT_FAST32_MAX (C99 起)
UINT_FAST64_MAX (C99 起)
UINT_FAST8_MAX (C99 起)
UINT_LEAST16_MAX (C99 起)
UINT_LEAST32_MAX (C99 起)
UINT_LEAST64_MAX (C99 起)
UINT_LEAST8_MAX (C99 起)
UINT16_MAX (C99 起)
UINT32_MAX (C99 起)
UINT64_MAX (C99 起)
UINT8_MAX (C99 起)
UINTMAX_MAX (C99 起)
UINTPTR_MAX (C99 起)
INTWIDTH_WIDTH

INT_FAST16_WIDTH (C23 起)
INT_FAST32_WIDTH (C23 起)
INT_FAST64_WIDTH (C23 起)
INT_FAST8_WIDTH (C23 起)
INT_LEAST16_WIDTH (C23 起)
INT_LEAST32_WIDTH (C23 起)
INT_LEAST64_WIDTH (C23 起)
INT_LEAST8_WIDTH (C23 起)
INT16_WIDTH (C23 起)
INT32_WIDTH (C23 起)
INT64_WIDTH (C23 起)
INT8_WIDTH (C23 起)
INTMAX_WIDTH (C23 起)
INTPTR_WIDTH (C23 起)

UINT_MAX
UINT_WIDTH (C23 起)
UINT16_C() (C99 起)
UINT32_C() (C99 起)
UINT64_C() (C99 起)
UINT8_C() (C99 起)
UINTMAX_C() (C99 起)
ULLONG_MAX (C99 起)
ULLONG_WIDTH (C23 起)
ULONG_MAX
ULONG_WIDTH (C23 起)
USHRT_MAX
USHRT_WIDTH (C23 起)

V

va_arg()
va_copy() (C99 起)
va_end()
va_list
va_start()

W

WCHAR_MAX (C99 起)
WCHAR_MIN (C99 起)
WCHAR_WIDTH (C23 起)
WEOF (C95 起)
WINT_MAX (C99 起)
WINT_MIN (C99 起)
WINT_WIDTH (C23 起)

X

xor (运算符宏) (C95 起)
xor_eq (运算符宏) (C95 起)

参阅


线程支持库

< c

若编译器定义宏常量 __STDC_NO_THREADS__(C11) ，则不提供头文件 <threads.h> 和所有列于此的名称。

线程

定义于头文件 <threads.h>
thrd_t | 实现定义的标识线程的完整对象类型
thrd_create (C11) | 创建线程 (函数)
thrd_equal (C11) | 检查二个标识符是否表示同一线程 (函数)
thrd_current (C11) | 获取当前线程标识符 (函数)
thrd_sleep (C11) | 在给定的时间段内暂停调用方线程的执行 (函数)
thrd_yield (C11) | 让出当前时间片段 (函数)
thrd_exit (C11) | 终止调用方线程 (函数)
thrd_detach (C11) | 分离线程 (函数)
thrd_join (C11) | 阻塞到线程终止为止 (函数)
thrd_successthrd_timedoutthrd_busythrd_nomemthrd_error (C11) | 指示线程错误状态 (常量)
thrd_start_t (C11) | 函数指针类型 int(*)(void*) 的 typedef ，为 thrd_create 所用 (typedef)

互斥

定义于头文件 <threads.h>
mtx_t 互斥标识符
mtx_init
(C11)
 创建互斥
(函数)
mtx_lock
(C11)
 阻塞到锁定互斥为止
(函数)
mtx_timedlock
(C11)
 阻塞到锁定互斥或时限经过为止
(函数)
mtx_trylock
(C11)
 锁定互斥，若已锁定则返回而不阻塞
(函数)
mtx_unlock
(C11)
 解锁互斥
(函数)
mtx_destroy
(C11)
 销毁互斥
(函数)
mtx_plainmtx_recursivemtx_timed
(C11)(C11)(C11)
 定义互斥的类型
(枚举)
一次调用
call_once
(C11)
 准确地一次调用函数
(函数)

条件变量

定义于头文件 <threads.h>
cnd_t | 条件变量标识符
cnd_init (C11) | 创建条件变量 (函数)
cnd_signal (C11) | 除阻一个阻塞于条件变量上的线程 (函数)
cnd_broadcast (C11) | 除阻所有阻塞于条件变量上的线程 (函数)
cnd_wait (C11) | 在条件变量上阻塞 (函数)
cnd_timedwait (C11) | 在条件变量上阻塞一段时长 (函数)
cnd_destroy (C11) | 销毁条件变量 (函数)

线程局域存储

定义于头文件 <threads.h>
thread_local (C11) | 线程局域存储类宏 (关键词宏)
tss_t | 线程特定存储的指针
TSS_DTOR_ITERATIONS (C11) | 析构器被调用的最大次数 (宏常量)
tss_dtor_t (C11) | 函数指针类型 void(*)(void*) ，用作 TSS 析构器 (typedef)
tss_create (C11) | 以给定的析构器，创建线程特定存储指针 (函数)
tss_get (C11) | 从线程特定存储读取 (函数)
tss_set (C11) | 写入线程特定存储 (函数)
tss_delete (C11) | 释放给定的线程特定存储指针所保有的资源 (函数)

保留标识符

以 cnd_ 、 mtx_ 、 thrd_ 或 tss_ 后随一个小写字母开始的函数名、类型名和枚举常量可能被添加到 C 标准的未来修订版中 <threads.h> 头文件中的声明，而可移植的程序不该使用这些标识符。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26 Threads <threads.h> (p: 376-387)
  • 7.31.15 Threads <threads.h> (p: 456)

参阅


call_once, once_flag, ONCE_FLAG_INIT

< c‎ | thread
定义于头文件 <threads.h> |  |
void call_once( once_flag * flag, void (*func)(void) ); | (1) | (C11 起)
typedef /* unspecified */ once_flag | (2) | (C11 起)
#define ONCE_FLAG_INIT /* unspecified */ | (3) | (C11 起)
1) 准确调用函数 func 一次，即使从多个线程调用。函数 func 的完成与先前或后继的用同一 flag 对象的对 call_once 调用同步。
2) 足以保有 call_once 所用标志的完整对象类型。
3) 展开成能用于初始化 once_flag 类型对象的值。

参数

flag | - | 指向用于确保只调用一次 func 的 call_once 对象的指针
func | - | 只执行一次的函数

返回值

（无）

注意

此函数的 POSIX 等价物是 pthread_once 。

示例

#include <stdio.h>
#include <threads.h>

void do_once(void) {
    puts("called once");
}

static once_flag flag = ONCE_FLAG_INIT;
int func(void* data)
{
    call_once(&flag, do_once);
}

int main(void)
{
    thrd_t t1, t2, t3, t4;
    thrd_create(&t1, func, NULL);
    thrd_create(&t2, func, NULL);
    thrd_create(&t3, func, NULL);
    thrd_create(&t4, func, NULL);

    thrd_join(t1, NULL);
    thrd_join(t2, NULL);
    thrd_join(t3, NULL);
    thrd_join(t4, NULL);
}

输出：

called once

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.2.1 The call_once function (p: 378)
  • 7.26.1/3 ONCE_FLAG_INIT (p: 376)

参阅


TSS_DTOR_ITERATIONS

< c‎ | thread
定义于头文件 <threads.h> |
#define TSS_DTOR_ITERATIONS /* unspecified */ | (C11 起)

展开成正的整数常量表达式，它定义 thrd_exit 将对线程局域存储指针调用析构器的最大次数。

此常量等价于 POSIX 的 PTHREAD_DESTRUCTOR_ITERATIONS 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.1/3 TSS_DTOR_ITERATIONS (p: 376)


cnd_broadcast

< c‎ | thread
定义于头文件 <threads.h> |
int cnd_broadcast( cnd_t *cond ); | (C11 起)

除阻所有当前在 cond 所指向的条件变量上等待的线程。若无被阻塞的线程，则不做任何事并返回 thrd_success 。

参数

cond - 指向条件变量的指针

返回值

若成功则为 thrd_success ，否则为 thrd_error 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.3.1 The cnd_broadcast function (p: 378)

参阅

cnd_signal
(C11)
 除阻一个阻塞于条件变量上的线程
(函数)


cnd_destroy

< c‎ | thread
定义于头文件 <threads.h> |
void cnd_destroy( cnd_t * cond ); | (C11 起)

销毁 cond 所指向的条件变量。

若有线程在 cond 上等待，则行为未定义。

参数

cond - 指向要销毁的条件变量的指针

返回值

（无）

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.3.2 The cnd_destroy function (p: 378-379)

参阅


cnd_init

< c‎ | thread
定义于头文件 <threads.h> |
int cnd_init( cnd_t * cond ); | (C11 起)

初始化新的条件变量。设置 cond 所指的对象为标识该条件变量的值。

参数

cond - 指针，指向要存储条件变量标识符到的对象

返回值

若成功创建条件变量则为 thrd_success 。否则若内存量不足则返回 thrd_nomem ，若出现其他错误则返回 thrd_error 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.3.3 The cnd_init function (p: 379)

参阅


cnd_signal

< c‎ | thread
定义于头文件 <threads.h> |
int cnd_signal( cnd_t *cond ); | (C11 起)

除阻当前在 cond 所指向的条件变量上等待的一个线程。若无线程被阻塞，则不做任何事并返回 thrd_success 。

参数

cond - 指向条件变量的指针

返回值

若成功则为 thrd_success ，否则为 thrd_error 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.3.4 The cnd_signal function (p: 379)

参阅

cnd_broadcast
(C11)
 除阻所有阻塞于条件变量上的线程
(函数)


cnd_timedwait

< c‎ | thread
定义于头文件 <threads.h> |
int cnd_timedwait( cnd_t * restrict cond, mtx_t * restrict mutex, const struct timespec* restrict time_point ); | (C11 起)

原子地解锁 mutex 所指向的互斥，并在 cond 所指向的条件变量上阻塞，直到线程被 cnd_signal 或 cnd_broadcast 发信号，或直至抵达 time_point 所指向的基于 TIME_UTC 的时间点，或直至虚假唤醒出现。在函数返回前重新锁定该互斥。

若调用方线程未锁定该互斥，则行为未定义。

参数

cond | - | 指向要在上面阻塞的条件变量的指针
mutex | - | 指向要在阻塞期间解锁的互斥的指针
time_point | - | 指向指定等待时限时间的对象的指针

返回值

若成功则为 thrd_success ，若在锁定互斥前抵达时限则为 thrd_timedout ，若出现错误则为 thrd_error 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.3.5 The cnd_timedwait function (p: 379-380)

参阅

cnd_wait
(C11)
 在条件变量上阻塞
(函数)


cnd_wait

< c‎ | thread
定义于头文件 <threads.h> |
int cnd_wait( cnd_t * cond, mtx_t * mutex ); | (C11 起)

原子地解锁 mutex 所指向的互斥，并在 cond 所指向的条件变量上阻塞，直至线程被 cnd_signal 或 cnd_broadcast 发信号，或直至虚假唤醒出现。在此函数返回前，重新锁定该互斥。

若调用方线程未锁定该互斥，则行为未定义。

参数

cond | - | 指向要在上面阻塞的条件变量的指针
mutex | - | 指向要在阻塞期解锁的互斥的指针

返回值

若成功则为 thrd_success ，否则为 thrd_error 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.3.6 The cnd_wait function (p: 380)

参阅

cnd_timedwait
(C11)
 在条件变量上阻塞一段时长
(函数)


mtx_destroy

< c‎ | thread
定义于头文件 <threads.h> |
void mtx_destroy( mtx_t *mutex ); | (C11 起)

销毁 mutex 所指向的互斥。

若有线程在 mutex 上等待，则行为未定义。

参数

mutex - 指向要销毁的互斥的指针

返回值

（无）

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.4.1 The mtx_destroy function (p: 380)

参阅


mtx_init

< c‎ | thread
定义于头文件 <threads.h> |
int mtx_init( mtx_t * mutex, int type ); | (C11 起)

创建新的拥有 type 类型的互斥。设置 mutex 所指向的对象为新创建互斥的标识符。

type 必须拥有下列值之一：

  • mtx_plain - 创建简单的，非递归互斥。
  • mtx_timed - 创建非递归的，支持时间限制的互斥。
  • mtx_plain | mtx_recursive - 创建递归互斥。
  • mtx_timed | mtx_recursive - 创建递归的支持时限的互斥。

参数

mutex | - | 指向要初始化的互斥的指针
type | - | 互斥的类型

返回值

若成功则为 thrd_success ，否则为 thrd_error 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.4.2 The mtx_init function (p: 381)

参阅


mtx_lock

< c‎ | thread
定义于头文件 <threads.h> |
int mtx_lock( mtx_t * mutex ); | (C11 起)

阻塞当前线程，直至锁定 mutex 所指向的互斥。

若该互斥已被当前线程锁定且非递归，则行为未定义。

先前在同一互斥上对 mtx_unlock 的调用同步于此操作，而且任何给定互斥上的所有锁定/解锁操作构成单独全序（类似原子对象的修改顺序）。

参数

mutex - 指向要锁定的互斥的指针

返回值

若成功则为 thrd_success ，否则为 thrd_error 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.4.3 The mtx_lock function (p: 381)

参阅

mtx_timedlock (C11) | 阻塞到锁定互斥或时限经过为止 (函数)
mtx_trylock (C11) | 锁定互斥，若已锁定则返回而不阻塞 (函数)
mtx_unlock (C11) | 解锁互斥 (函数)


mtx_timedlock

< c‎ | thread
定义于头文件 <threads.h> |
int mtx_timedlock( mtx_t *restrict mutex, const struct timespec *restrict time_point ); | (C11 起)

阻塞当前线程，直到 mutex 所指向的互斥被锁，或直到抵达 time_point 所指向的基于 TIME_UTC 的时间点。

若当前线程已经锁定该互斥且该互斥非递归，则行为未定义。

若该互斥不支持时限，则行为未定义。

先前在同一互斥上对 mtx_unlock 的调用同步于此操作（若此操作成功），而且任何给定的互斥上的所有锁定/解锁组成单独全序（类似原子对象上的修改顺序）。

参数

mutex | - | 指向要锁定的互斥的指针
time_point | - | 指向要等待到的时限时间点的指针

返回值

若成功则为 thrd_success ，若已在锁定互斥前抵达时限则为 thrd_timedout ，若出现错误则为 thrd_error 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.4.4 The mtx_timedlock function (p: 381-382)

参阅

mtx_lock (C11) | 阻塞到锁定互斥为止 (函数)
mtx_trylock (C11) | 锁定互斥，若已锁定则返回而不阻塞 (函数)
mtx_unlock (C11) | 解锁互斥 (函数)


mtx_trylock

< c‎ | thread
定义于头文件 <threads.h> |
int mtx_trylock( mtx_t *mutex ); | (C11 起)

尝试锁定 mutex 所指向的互斥而不阻塞。若该互斥已被锁定则立即返回。

同一互斥上对 mtx_unlock 的先前调用同步于此操作（若此操作成功），而且任何给定互斥上的所有锁定/解锁操作构成单独全序（类似于原子对象上的修改顺序）。

参数

mutex - 指向要锁定的互斥的指针

返回值

若成功则为 thrd_success ，若已锁定该互斥或由于获取可用互斥的虚假失败则为 thrd_busy ，若出现错误则为 thrd_error 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C 标准。

DR | 应用于 | 出版时的行为 | 正确行为
DR 470 | C11 | 不允许 mtx_trylock 虚假地失败 | 允许

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.26.4.5 The mtx_trylock function (p: 278-279)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.4.5 The mtx_trylock function (p: 382)

参阅

mtx_lock (C11) | 阻塞到锁定互斥为止 (函数)
mtx_timedlock (C11) | 阻塞到锁定互斥或时限经过为止 (函数)
mtx_unlock (C11) | 解锁互斥 (函数)


mtx_plain, mtx_recursive, mtx_timed

< c‎ | thread
定义于头文件 <threads.h> |
enum { mtx_plain = /* unspecified */, mtx_recursive = /* unspecified */, mtx_timed = /* unspecified */ }; | (C11 起)

传递给 mtx_init 时，标识要创建的互斥类型。

常量 | 解释
mtx_plain | 平常互斥
mtx_recursive | 递归互斥
mtx_timed | 定时互斥

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.1/5 mtx_plain, mtx_recursive, mtx_timed (p: 377)

参阅

mtx_init
(C11)
 创建互斥
(函数)


mtx_unlock

< c‎ | thread
定义于头文件 <threads.h> |
int mtx_unlock( mtx_t *mutex ); | (C11 起)

解锁 mutex 所指向的互斥。

若调用方线程未锁定该互斥，则行为未定义。

在同一互斥上，此函数同步于后继的 mtx_lock 、 mtx_trylock 或 mtx_timedlock 。何给定互斥上的所有锁/解锁操作构成单独全序（类似原子对象上的修改顺序）。

参数

mutex - 指向要解锁的互斥的指针

返回值

若成功则为 thrd_success ，否则为 thrd_error 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.4.6 The mtx_unlock function (p: 382)

参阅

mtx_lock (C11) | 阻塞到锁定互斥为止 (函数)
mtx_timedlock (C11) | 阻塞到锁定互斥或时限经过为止 (函数)
mtx_trylock (C11) | 锁定互斥，若已锁定则返回而不阻塞 (函数)


thrd_create

< c‎ | thread
定义于头文件 <threads.h> |
int thrd_create( thrd_t *thr, thrd_start_t func, void *arg ); | (C11 起)

创建一个执行函数 func 的新线程，以 func(arg) 调用此函数。

若成功，则设置 thr 所指向的对象为新线程的标识符。

此函数的完成同步于线程的开始。

参数

thr | - | 指向放置新线程标识符的内存位置的指针
func | - | 要执行的函数
arg | - | 传递给函数的参数

返回值

若新线程创建成功则为 thrd_success 。否则若内存不足则返回 thrd_nomem ，若出现其他错误则返回 thrd_error 。

注意

一旦线程完结并融合或脱附，则可能重新使用线程标识符。

类型 thrd_start_t 是 int(*)(void*) 的 typedef ，有别于 POSIX 的等价版本 void*(*)(void*) 。

将所有所有线程特定存储值（见 tss_create ）初始化为 NULL 。

从函数 func 返回等价于以等于 func 返回值的参数调用 thrd_exit 。

示例

#include<stdio.h>
#include<assert.h>
#include<threads.h>

int hello_word_thrd_fn(void *arg){
    printf("%lu, %s\n", thrd_current(), __func__);
}

int main(){
    thrd_t th;
    int status = thrd_create(&th, hello_word_thrd_fn, NULL);
    assert(("hello word thrd create error!!\n", status == thrd_success));

    thrd_join(th, NULL);
    printf("%lu, %s\n", thrd_current(), __func__);
}

/* 如果你尝试用 gcc 编译，记得链接线程库
   gcc xx.c -o xx -lpthread
*/

输出：

139833338058304, hello_word_thrd_fn
139833338062656, main

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.5.1 The thrd_create function (p: 383)

参阅

thrd_detach (C11) | 分离线程 (函数)
thrd_join (C11) | 阻塞到线程终止为止 (函数)


thrd_current

< c‎ | thread
定义于头文件 <threads.h> |
thrd_t thrd_current(void); | (C11 起)

返回调用方线程的标识符。

参数

（无）

返回值

调用方线程的标识符。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.5.2 The thrd_current function (p: 383)

参阅


thrd_detach

< c‎ | thread
定义于头文件 <threads.h> |
int thrd_detach( thrd_t thr ); | (C11 起)

将 thr 所标识的线程从当前环境中分离。一旦该线程退出，就自动释放其保有的资源。

参数

thr - 要分离的线程的标识符

返回值

若成功则为 thrd_success ，否则为 thrd_error 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.5.3 The thrd_detach function (p: 383-384)

参阅

thrd_join
(C11)
 阻塞到线程终止为止
(函数)


thrd_equal

< c‎ | thread
定义于头文件 <threads.h> |
int thrd_equal( thrd_t lhs, thrd_t rhs ); | (C11 起)

检查 lhs 与 rhs 是否表示同一线程。

参数

lhs, rhs - 要比较的线程

返回值

若 lhs 与 rhs 表示同一线程则为非零值，否则为 ​0​ 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.5.4 The thrd_equal function (p: 384)

参阅


thrd_success, thrd_timedout, thrd_busy, thrd_nomem, thrd_error

< c‎ | thread
定义于头文件 <threads.h> |
enum { thrd_success = /* unspecified */, thrd_nomem = /* unspecified */, thrd_timedout = /* unspecified */, thrd_busy = /* unspecified */, thrd_error = /* unspecified */ }; | (C11 起)

鉴别线程状态和错误。

常量 | 解释
thrd_success | 指示成功的返回值
thrd_timedout | 指示时间用尽的返回值
thrd_busy | 指示因资源暂时不可用而不成功的返回值
thrd_nomem | 指示因内存耗尽而不成功的返回值
thrd_error | 指示不成功的返回值

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.1/5 thrd_success, thrd_timedout, ... (p: 377)


thrd_exit

< c‎ | thread
定义于头文件 <threads.h> |
_Noreturn void thrd_exit( int res ); | (C11 起)

首先，对于每个以非空析构器创建，关联值非空的（见 tss_create ）线程特定存储关键， thrd_exit 设置与关键关联的值为 NULL ，然后以该关键的先前值调用析构器。析构器的调用顺序是未指定的。

若在此后，有剩余关键拥有非空的析构器和值（例如若析构器执行了 tss_set ），则至多重复 TSS_DTOR_ITERATIONS 次处理。

最后， thrd_exit 函数终止调用方线程的执行，并设置其结果码为 res 。

若程序中的最后线程以 thrd_exit 退出，则如同通过以 EXIT_SUCCESS 为参数调用 exit 一般终止整个程序（故 atexit 所注册的函数在最后线程的环境中执行）。

参数

res - 要返回的值

返回值

（无）

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.5.5 The thrd_exit function (p: 384)

参阅

thrd_join (C11) | 阻塞到线程终止为止 (函数)
thrd_detach (C11) | 分离线程 (函数)


thrd_join

< c‎ | thread
定义于头文件 <threads.h> |
int thrd_join( thrd_t thr, int *res ); | (C11 起)

阻塞当前线程，直到 thr 所标识的线程完成执行。

若 res 不是空指针，则将该线程的结果码放置到 res 所指向的位置。

该线程的终止同步于此函数的完成。

若该线程之前已被另一线程分离或合并，则行为未定义。

参数

thr | - | 要合并的线程的标识符
res | - | 放置结果码到的位置

返回值

若成功则为 thrd_success ，否则为 thrd_error 。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.5.6 The thrd_join function (p: 384-385)

参阅

thrd_detach (C11) | 分离线程 (函数)
thrd_exit (C11) | 终止调用方线程 (函数)


thrd_sleep

< c‎ | thread
定义于头文件 <threads.h> |
int thrd_sleep( const struct timespec* duration, struct timespec* remaining ); | (C11 起)

阻塞当前线程的执行，至少直至经过 duration 所指向的基于 TIME_UTC 的时长。

若收到不忽略的信号（ signal ），则可以较早地从休眠恢复，。此情况下，若 remaining 非 NULL ，则存储剩余时长到 remaining 所指向的对象中。

参数

duration | - | 指向要休眠的时长的指针
remaining | - | 指向要放置中断剩余时间的对象的指针。可为 NULL ，此情况下忽略它

返回值

成功休眠时为 ​0​，若出现信号则为 -1 ，若出现错误则为其他负值。

注意

duration 和 remaining 可以指向相同对象，这会简化函数在信号后的重新运行。

实际休眠时间可能长于请求，因为它会被向上舍入到计时器的粒度，而且还因为调度和环境切换开销。

此函数的 POSIX 等价版本是 nanosleep 。

示例

#include <threads.h>
#include <time.h>
#include <stdio.h>

int main(void)
{
    printf("Time: %s", ctime(&(time_t){time(NULL)}));
    thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); // 睡眠 1 秒
    printf("Time: %s", ctime(&(time_t){time(NULL)}));
}

输出：

Time: Mon Feb  2 16:18:41 2015
Time: Mon Feb  2 16:18:42 2015

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.5.7 The thrd_sleep function (p: 385)

参阅

thrd_yield
(C11)
 让出当前时间片段
(函数)


thrd_yield

< c‎ | thread
定义于头文件 <threads.h> |
void thrd_yield(void); | (C11 起)

向实现提供一个重新安排线程执行的提示，允许其他线程运行。

参数

（无）

返回值

（无）

注意

此函数的准确行为取决于实现，特别是使用中的 OS 编排机制和系统状态。例如，先进先出的实时调度器（ Linux 的SCHED_FIFO ）会悬停当前线程，并将它放在准备运行的同优先级线程队列尾部（而若无在同优先级的线程，则 yield 无效）。

此函数的 POSIX 等价版本是 sched_yield 。

示例

#include <stdio.h>
#include <time.h>
#include <threads.h>

// 工具函数：微秒单位的 timespec 差
double usdiff(struct timespec s, struct timespec e)
{
    double sdiff = difftime(e.tv_sec, s.tv_sec);
    long nsdiff = e.tv_nsec - s.tv_nsec;
    if(nsdiff < 0) return 1000000*(sdiff-1) + (1000000000L+nsdiff)/1000.0;
    else return 1000000*(sdiff) + nsdiff/1000.0;
}

// 在让出时等待
void sleep_100us()
{
    struct timespec start, end;
    timespec_get(&start, TIME_UTC);
    do {
        thrd_yield();
        timespec_get(&end, TIME_UTC);
    } while(usdiff(start, end) < 100.0);
}

int main()
{
    struct timespec start, end;
    timespec_get(&start, TIME_UTC);
    sleep_100us();
    timespec_get(&end, TIME_UTC);
    printf("Waited for %.3f us\n", usdiff(start, end));
}

可能的输出：

Waited for 100.344 us

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.5.8 The thrd_yield function (p: 385)

参阅

thrd_sleep
(C11)
 在给定的时间段内暂停调用方线程的执行
(函数)


thread_local

< c‎ | thread
定义于头文件 <threads.h> |
#define thread_local _Thread_local | (C11 起)

便利宏，用于指定对象拥有线程局域存储期。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.1/3 thread_local (p: 376)


tss_create

< c‎ | thread
定义于头文件 <threads.h> |
int tss_create( tss_t * tss_key, tss_dtor_t destructor ); | (C11 起)

创建新的线程特定存储关键，并将它存储于 tss_key 所指向的对象。尽管不同线程可能使用相同的关键值，由 tss_set 绑定到关键的值在每个线程基础上维护，并且在调用方线程的生命中保持存在。

所有既存线程中，新建的关键被关联到值 NULL ，而在创建线程时，将所有 TSS 关键关联的值被初始化为 NULL 。

若 destructor 不是空指针，则亦关联在 thrd_exit （但不是 tss_delete 且不是在以 exit 终止程序时）释放存储时调用的析构器。

在线程特定存储的析构器内调用 tss_create 导致未定义行为。

参数

tss_key | - | 指向要存储新的线程特定存储关键的内存位置的指针
destructor | - | 指向要在线程退出时调用的函数的指针

注意

此函数的 POSIX 等价版本是 pthread_key_create 。

返回值

若成功则为 thrd_success ，否则为 thrd_error 。

示例

本节未完成
原因：改进，最好为启发寻找 POSIX 示例
int thread_func(void *arg) {
    tss_t key;
    if (thrd_success == tss_create(&key, free)) {
        tss_set(key, malloc(4)); // 在 TSS 上存储指针
        // ...
    }
} // 对 TSS 上存储的指针调用 free()

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.6.1 The tss_create function (p: 386)


tss_delete

< c‎ | thread
定义于头文件 <threads.h> |
void tss_delete( tss_t tss_id ); | (C11 起)

销毁 tss_id 所标识的线程特定存储。

若以 tss_create 注册了一个析构器，则不调用它（仅在线程退出时调用，无论是由 thrd_exit 还是通过从线程函数返回）。程序员负责确保在调用 tss_delete 前，每个知晓 tss_id 的线程都进行了必要的清理。

若在另一线程执行 tss_id 的析构器时调用 tss_delete ，则这是否会更改关联析构器的调用次数是未指定的。

若在调用方线程执行析构器时调用 tss_delete ，则与 tss_id 关联的析构器将不会在此线程上再次执行。

参数

tss_id - 先前 tss_create 所返回，且仍未被 tss_delete 删除的线程特定存储关键

返回值

（无）

注意

此函数的 POSIX 等价版本是 pthread_key_delete 。

tss_delete 决不调用析构器，是因为正常情况下，有意令原先设置析构器所将处理的值（经由 tss_set ）的同一线程执行（线程退出时调用）析构器，而且析构器甚至可能依赖该线程所见的该值或其他线程特定数据。执行 tss_delete 的线程对其他线程的 TSS 无访问权限。即使可能对每个线程的与 tss_id 关联的值调用析构器，若仅为检验该线程中此 TSS 的值是否为空， tss_delete 也必须与每个线程同步（仅对非空值调用析构器）。

示例

本节未完成
原因：暂无示例

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.6.2 The tss_delete function (p: 386)


tss_get

< c‎ | thread
定义于头文件 <threads.h> |
void *tss_get( tss_t tss_key ); | (C11 起)

返回 tss_key 所标识的，当前线程的线程特定存储中保有的值。不同线程可能获取同一关键所标识的不同值。

线程启动时（见 thrd_create ），与所有 TSS 关键关联的值均为 NULL 。可以用 tss_set 将相异的值置入线程指定存储。

参数

tss_key - 从 tss_create 获得，且未被 tss_delete 删除的线程特定存储关键

返回值

成功时为值，失败时为 NULL 。

注意

此函数的 POSIX 等价版本是 pthread_getspecific 。

示例

本节未完成
原因：暂无示例

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.6.3 The tss_get function (p: 386)

参阅

tss_set
(C11)
 写入线程特定存储
(函数)


tss_set

< c‎ | thread
定义于头文件 <threads.h> |
int tss_set( tss_t tss_id, void *val ); | (C11 起)

设置当前线程的 tss_id 所标识的线程特定存储的值为 val 。不同线程可以设置不同值给同一关键。

若析构器可用，则不调用它。

参数

tss_id | - | 从 tss_create 获得，且未被 tss_delete 删除的线程特定存储关键
val | - | 要设置给线程特定存储的值

返回值

若成功则为 thrd_success ，否则为 thrd_error 。

注意

此函数的 POSIX 等价版本为 pthread_setspecific 。

TSS 的典型用法是存储指向动态分配内存块的指针，这些内存块为调用方线程的使用保留。

可以在 TSS 析构器中调用 tss_set 。若 TSS 存储中析构器以非 NULL 值退出，则 thrd_exit 会重试析构器至多 TSS_DTOR_ITERATIONS 次，之后存储将丢失。

示例

本节未完成
原因：改进，最好为启发寻找 POSIX 示例
int thread_func(void *arg) {
    tss_t key;
    if (thrd_success == tss_create(&key, free)) {
        tss_set(key, malloc(4)); // 在 TSS 上存储指针
        // ...
    }
} // 对 TSS 上存储的指针调用 free()

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.26.6.4 The tss_set function (p: 387)

参阅

tss_get
(C11)
 从线程特定存储读取
(函数)


类型支持

< c

基本类型

语言定义的基础类型

附加基本类型及便利宏

定义于头文件 <stddef.h>
size_t | sizeof 运算符返回的无符号整数类型 (typedef)
ptrdiff_t | 两个指针相减返回的有符号整数类型 (typedef)
NULL | 实现定义的空指针常量 (宏常量)
max_align_t (C11) | 对齐要求不小于任何其他标量类型的类型 (typedef)
offsetof | 从指定结构体类型的起始到指定成员的字节位移 (宏函数)
定义于头文件 <stdbool.h>
bool (C99) | 便利宏，展开成 _Bool (关键词宏)
true (C99) | 展开成整数常量 1 (C23 前) ((_Bool)+1u) (C23 起) (宏常量)
false (C99) | 展开成整数常量 0 (C23 前) ((_Bool)+0u) (C23 起) (宏常量)
__bool_true_false_are_defined (C99) | 展开成整数常量 1 (宏常量)
定义于头文件 <stdalign.h>
alignas (C11) | 便利宏，展开成关键词 _Alignas (关键词宏)
alignof (C11) | 便利宏，展开成关键词 _Alignof (关键词宏)
__alignas_is_defined (C11) | 展开成整数常量 1 (宏常量)
__alignof_is_defined (C11) | 展开成整数常量 1 (宏常量)
定义于头文件 <stdnoreturn.h>
noreturn (C11) | 便利宏，展开成 _Noreturn (关键词宏)

定宽整数类型 (C99 起)

数值极限

注解

true 与 false 的类型为 int 而非 _Bool 。

 (C99 起)
(C23 前)

程序可以解除定义，并且可以在之后重新定义宏 bool 、 true 与 false 。然而这种能力是一项弃用的特性。

 (C99 起)

示例

#include <stdio.h>
#include <stdbool.h>
#include <stdalign.h>

int main(void)
{
    printf("%d\n%d\n%d\n", true && false, true || false, !false);
    printf("%zu\n", alignof(char));
}

输出：

0
1
1
1

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.15 Alignment <stdalign.h> (p: 196)
  • 7.18 Boolean type and values <stdbool.h> (p: 210)
  • 7.19 Common definitions <stddef.h> (p: 211)
  • 7.23 _Noreturn <stdnoreturn.h> (p: 263)
  • 7.31.9 Boolean type and values <stdbool.h> (p: 332)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.15 Alignment <stdalign.h> (p: 268)
  • 7.18 Boolean type and values <stdbool.h> (p: 287)
  • 7.19 Common definitions <stddef.h> (p: 288)
  • 7.23 _Noreturn <stdnoreturn.h> (p: 361)
  • 7.31.9 Boolean type and values <stdbool.h> (p: 456)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.18 Boolean type and values <stdbool.h> (p: 253)
  • 7.19 Common definitions <stddef.h> (p: 254)
  • 7.26.7 Boolean type and values <stdbool.h> (p: 401)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.1.5 Common definitions <stddef.h>

参阅


NULL

< c‎ | types
定义于头文件 <stddef.h>
定义于头文件 <string.h>
定义于头文件 <wchar.h>
定义于头文件 <time.h>
定义于头文件 <locale.h>
定义于头文件 <stdio.h>
定义于头文件 <stdlib.h>
#define NULL /*implementation-defined*/

宏 NULL 是实现定义的空指针常量，可为

  • 值为 ​0​ 的整数常量表达式
  • 转型为 void* 的值为 ​0​ 的整数常量表达式

空指针常量能转换为任何类型；转换结果是该类型的空指针值。

可能的实现

// 兼容 C++ ：
#define NULL 0
// 不兼容 C++ ：
#define NULL (10*2 - 20)
#define NULL ((void*)0)

示例

#include <stdlib.h>
#include <stdio.h>
int main(void)
{
    // 能设置任何类型指针为 NULL
    int* p = NULL;
    struct S *s = NULL;
    void(*f)(int, double) = NULL;

    // 多数返回指针的函数用空指针指示错误
    char *ptr = malloc(10);
    if (ptr == NULL) printf("Out of memory");
    free(ptr);
}

参阅


定宽整数类型 (C99 起)

< c‎ | types

类型

定义于头文件 <stdint.h>
int8_tint16_tint32_tint64_t (可选) | 分别为宽度恰为 8、16、32 和 64 位的有符号整数类型 无填充位并对负值使用补码 （仅若实现支持该类型才提供） (typedef)
int_fast8_tint_fast16_tint_fast32_tint_fast64_t | 分别为宽度至少有 8、16、32 和 64 位的最快的有符号整数类型 (typedef)
int_least8_tint_least16_tint_least32_tint_least64_t | 分别为宽度至少有 8、16、32 和 64 位的最小的有符号整数类型 (typedef)
intmax_t | 最大宽度的有符号整数类型 (typedef)
intptr_t (可选) | 足以保有指针的有符号整数类型 (typedef)
uint8_tuint16_tuint32_tuint64_t (可选) | 宽度恰为 8、16、32 和 64 位的无符号整数类型 （仅若实现支持该类型才提供） (typedef)
uint_fast8_tuint_fast16_tuint_fast32_tuint_fast64_t | 分别为宽度至少有 8、16、32 和 64 位的最快无符号整数类型 (typedef)
uint_least8_tuint_least16_tuint_least32_tuint_least64_t | 分别为宽度至少有 8、16、32 和 64 位的最小无符号整数类型 (typedef)
uintmax_t | 最大宽度的无符号整数类型 (typedef)
uintptr_t (可选) | 足以保有指针的无符号整数类型 (typedef)

实现可在 N 不是 8、 16、 32 或 64 时定义 typedef 名 intN_t、 int_fastN_t、 int_leastN_t、 uintN_t、 uint_fastN_t 及 uint_leastN_t 。形为 intN_t 的 typedef 名仅若实现支持有该宽度而无填充的整数类型才可以得以定义。从而 uint24_t 代表宽度准确地为 24 位的无符号整数类型。

下面列出的每个宏当且仅当实现定义对应的 typedef 名时才得以定义。宏 INTN_C 与 UINTN_C 分别对应 typedef 名 int_leastN_t 与 uint_leastN_t 。

宏常量

定义于头文件 <stdint.h>
有符号整数：宽度
INT8_WIDTHINT16_WIDTHINT32_WIDTHINT64_WIDTH
(C23)(可选)
 int8_t、int16_t、int32_t、int64_t 类型对象的位宽（准确地为 8、16、32、64）
(宏常量)
INT_FAST8_WIDTHINT_FAST16_WIDTHINT_FAST32_WIDTHINT_FAST64_WIDTH
(C23)
 int_fast8_t、int_fast16_t、int_fast32_t、int_fast64_t 类型对象的位宽
(宏常量)
INT_LEAST8_WIDTHINT_LEAST16_WIDTHINT_LEAST32_WIDTHINT_LEAST64_WIDTH
(C23)
 int_least8_t、int_least16_t、int_least32_t、int_least64_t 类型对象的位宽
(宏常量)
INTPTR_WIDTH
(C23)(可选)
 intptr_t 类型对象的位宽
(宏常量)
INTMAX_WIDTH
(C23)
 intmax_t 类型对象的位宽
(宏常量)
有符号整数：最小值
INT8_MININT16_MININT32_MININT64_MIN
(可选)
 int8_t、int16_t、int32_t、int64_t 类型对象的最小值
(宏常量)
INT_FAST8_MININT_FAST16_MININT_FAST32_MININT_FAST64_MIN
 int_fast8_t、int_fast16_t、int_fast32_t、int_fast64_t 类型对象的最小值
(宏常量)
INT_LEAST8_MININT_LEAST16_MININT_LEAST32_MININT_LEAST64_MIN
 int_least8_t、int_least16_t、int_least32_t、int_least64_t 类型对象的最小值
(宏常量)
INTPTR_MIN
(可选)
 intptr_t 类型对象的最小值
(宏常量)
INTMAX_MIN
 intmax_t 类型对象的最小值
(宏常量)
有符号整数：最大值
INT8_MAXINT16_MAXINT32_MAXINT64_MAX
(可选)
 int8_t、int16_t、int32_t、int64_t 类型对象的最大值
(宏常量)
INT_FAST8_MAXINT_FAST16_MAXINT_FAST32_MAXINT_FAST64_MAX
 int_fast8_t、int_fast16_t、int_fast32_t、int_fast64_t 类型对象的最大值
(宏常量)
INT_LEAST8_MAXINT_LEAST16_MAXINT_LEAST32_MAXINT_LEAST64_MAX
 int_least8_t、int_least16_t、int_least32_t、int_least64_t 类型对象的最大值
(宏常量)
INTPTR_MAX
(可选)
 intptr_t 类型对象的最大值
(宏常量)
INTMAX_MAX
 intmax_t 类型对象的最大值
(宏常量)
无符号整数：宽度
UINT8_WIDTHUINT16_WIDTHUINT32_WIDTHUINT64_WIDTH
(C23)(可选)
 uint8_t、uint16_t、uint32_t、uint64_t 类型对象的位宽（准确地为 8、16、32、64）
(宏常量)
UINT_FAST8_WIDTHUINT_FAST16_WIDTHUINT_FAST32_WIDTHUINT_FAST64_WIDTH
(C23)
 uint_fast8_t、uint_fast16_t、uint_fast32_t、uint_fast64_t 类型对象的位宽
(宏常量)
UINT_LEAST8_WIDTHUINT_LEAST16_WIDTHUINT_LEAST32_WIDTHUINT_LEAST64_WIDTH
(C23)
 uint_least8_t、uint_least16_t、uint_least32_t、uint_least64_t 类型对象的位宽
(宏常量)
UINTPTR_WIDTH
(C23)(可选)
 uintptr_t 类型对象的位宽
(宏常量)
UINTMAX_WIDTH
(C23)
 uintmax_t 类型对象的位宽
(宏常量)
无符号整数：最大值
UINT8_MAXUINT16_MAXUINT32_MAXUINT64_MAX
(可选)
 uint8_t、uint16_t、uint32_t、uint64_t 类型对象的最大值
(宏常量)
UINT_FAST8_MAXUINT_FAST16_MAXUINT_FAST32_MAXUINT_FAST64_MAX
 uint_fast8_t、uint_fast16_t、uint_fast32_t、uint_fast64_t 类型对象的最大值
(宏常量)
UINT_LEAST8_MAXUINT_LEAST16_MAXUINT_LEAST32_MAXUINT_LEAST64_MAX
 uint_least8_t、uint_least16_t、uint_least32_t、uint_least64_t 类型对象的最大值
(宏常量)
UINTPTR_MAX
(可选)
 uintptr_t 类型对象的最大值
(宏常量)
UINTMAX_MAX
 uintmax_t 类型对象的最大值
(宏常量)

最小宽度整数常量的函数宏

定义于头文件 <stdint.h>
INT8_CINT16_CINT32_CINT64_C | 展开成拥有以其参数指定的值和类型分别为 int_least8_t 、 int_least16_t 、 int_least32_t 、 int_least64_t 的整数常量表达式 (宏函数)
INTMAX_C | 展开成拥有以其参数指定的值和 intmax_t 类型的整数常量表达式 (宏函数)
UINT8_CUINT16_CUINT32_CUINT64_C | 展开成拥有以其参数指定的值，类型分别为 uint_least8_t 、 uint_least16_t 、 uint_least32_t 、 uint_least64_t 的整数常量表达式 (宏函数)
UINTMAX_C | 展开成拥有以其参数指定的值和 uintmax_t 类型的整数常量表达式 (宏函数)
#include <stdint.h>
UINT64_C(0x123) // 可以展开成 0x123ULL 或 0x123UL

格式宏常量

定义于头文件 <inttypes.h>

fprintf 系列函数的格式常量

此处列出的每个 PRI 宏当且仅当实现定义对应的 typedef 名才得以定义。

int 或 unsigned int 的等价者 | 描述 | 数据类型的宏
 |  | [u]intx_t | [u]int_leastx_t | [u]int_fastx_t | [u]intmax_t | [u]intptr_t
d | 有符号十进制整数值的输出 | PRIdx | PRIdLEASTx | PRIdFASTx | PRIdMAX | PRIdPTR
i |  | PRIix | PRIiLEASTx | PRIiFASTx | PRIiMAX | PRIiPTR
u | 无符号十进制整数值的输出 | PRIux | PRIuLEASTx | PRIuFASTx | PRIuMAX | PRIuPTR
o | 无符号八进制整数值的输出 | PRIox | PRIoLEASTx | PRIoFASTx | PRIoMAX | PRIoPTR
x | 无符号小写十六进制整数值的输出 | PRIxx | PRIxLEASTx | PRIxFASTx | PRIxMAX | PRIxPTR
X | 无符号大写十六进制整数值的输出 | PRIXx | PRIXLEASTx | PRIXFASTx | PRIXMAX | PRIXPTR

fscanf 系列函数的格式常量

此处列出的每个 SCN 宏当且仅当实现定义对应的 typedef 名且拥有适合该类型的 fscanf 长度修饰符才得以定义。

int 或 unsigned int 的等价者 | 描述 | 数据类型的宏
 |  | [u]intx_t | [u]int_leastx_t | [u]int_fastx_t | [u]intmax_t | [u]intptr_t
d | 有符号十进制整数值的输入 | SCNdx | SCNdLEASTx | SCNdFASTx | SCNdMAX | SCNdPTR
i | 有符号整数值的输入（以首个剖析的字符确定基底） | SCNix | SCNiLEASTx | SCNiFASTx | SCNiMAX | SCNiPTR
u | 无符号十进制整数值的输入 | SCNux | SCNuLEASTx | SCNuFASTx | SCNuMAX | SCNuPTR
o | 无符号八进制整数值的输入 | SCNox | SCNoLEASTx | SCNoFASTx | SCNoMAX | SCNoPTR
x | 无符号十六进制值类型的输入 | SCNxx | SCNxLEASTx | SCNxFASTx | SCNxMAX | SCNxPTR

示例

#include <stdio.h>
#include <inttypes.h>

int main(void)
{
    printf("%zu\n", sizeof(int64_t));
    printf("%s\n", PRId64);
    printf("%+"PRId64"\n", INT64_MIN);
    printf("%+"PRId64"\n", INT64_MAX);

    int64_t n = 7;
    printf("%+"PRId64"\n", n);
}

可能的输出：

8
lld
-9223372036854775808
+9223372036854775807
+7

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 7.8.1 Macros for format specifiers (p: 158-159)
  • 7.18 Integer types <stdint.h> (p: 212-216)
  • C11 标准（ISO/IEC 9899:2011）：
  • 7.8.1 Macros for format specifiers (p: 217-218)
  • 7.18 Integer types <stdint.h> (p: 289-295)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.8.1 Macros for format specifiers (p: 198-199)
  • 7.18 Integer types <stdint.h> (p: 255-261)

参阅

  • 算术类型


数值极限

< c‎ | types

库类型极限

定义于头文件 <stdint.h>
PTRDIFF_WIDTH (C23) | ptrdiff_t 类型对象的位宽 (宏常量)
PTRDIFF_MIN (C99) | ptrdiff_t 类型对象的最小值 (宏常量)
PTRDIFF_MAX (C99) | ptrdiff_t 类型对象的最大值 (宏常量)
SIZE_WIDTH (C23) | size_t 类型对象的位宽 (宏常量)
SIZE_MAX (C99) | size_t 类型对象的最大值 (宏常量)
SIG_ATOMIC_WIDTH (C23) | sig_atomic_t 类型对象的位宽 (宏常量)
SIG_ATOMIC_MIN (C99) | sig_atomic_t 类型对象的最小值 (宏常量)
SIG_ATOMIC_MAX (C99) | sig_atomic_t 类型对象的最大值 (宏常量)
WINT_WIDTH (C23) | wint_t 类型对象的位宽 (宏常量)
WINT_MIN (C99) | wint_t 类型对象的最小值 (宏常量)
WINT_MAX (C99) | wint_t 类型对象的最大值 (宏常量)
定义于头文件 <wchar.h>
定义于头文件 <stdint.h>
WCHAR_WIDTH (C23) | wchar_t 类型对象的位宽 (宏常量)
WCHAR_MIN (C99) | wchar_t 类型对象的最小值 (宏常量)
WCHAR_MAX (C99) | wchar_t 类型对象的最大值 (宏常量)

注意：自立实现可能缺少 sig_atomic_t 与/或 wint_t typedef 名，此情况下相应地缺少 SIG_ATOMIC_* 与/或 WINT_* 宏。

示例

#include <stdio.h>
#include <stdint.h>
#include <wchar.h>

int main(void)
{
    printf("PTRDIFF_MIN    = %td\n", PTRDIFF_MIN);
    printf("PTRDIFF_MAX    = %+td\n", PTRDIFF_MAX);
    printf("SIZE_MAX       = %zu\n", SIZE_MAX);
    printf("SIG_ATOMIC_MIN = %+jd\n",(intmax_t)SIG_ATOMIC_MIN);
    printf("SIG_ATOMIC_MAX = %+jd\n",(intmax_t)SIG_ATOMIC_MAX);
    printf("WCHAR_MIN      = %+jd\n",(intmax_t)WCHAR_MIN);
    printf("WCHAR_MAX      = %+jd\n",(intmax_t)WCHAR_MAX);
    printf("WINT_MIN       = %jd\n", (intmax_t)WINT_MIN);
    printf("WINT_MAX       = %jd\n", (intmax_t)WINT_MAX);
}

可能的输出：

PTRDIFF_MIN    = -9223372036854775808
PTRDIFF_MAX    = +9223372036854775807
SIZE_MAX       = 18446744073709551615
SIG_ATOMIC_MIN = -2147483648
SIG_ATOMIC_MAX = +2147483647
WCHAR_MIN      = -2147483648
WCHAR_MAX      = +2147483647
WINT_MIN       = 0
WINT_MAX       = 4294967295

整数类型极限

定义于头文件 <limits.h>
BOOL_WIDTH (C23) | _Bool 的位宽 (宏常量)
CHAR_BIT | 字节的位数 (宏常量)
CHAR_WIDTH (C23) | char 的位宽，同 CHAR_BIT (宏常量)
MB_LEN_MAX | 多字节字符的最大字节数 (宏常量)
CHAR_MIN | char 的最小值 (宏常量)
CHAR_MAX | char 的最大值 (宏常量)
SCHAR_WIDTHSHRT_WIDTHINT_WIDTHLONG_WIDTHLLONG_WIDTH (C23)(C23)(C23)(C23)(C23) | 分别为 signed char、short、int、long 及 long long 的位宽 (宏常量)
SCHAR_MINSHRT_MININT_MINLONG_MINLLONG_MIN (C99) | 分别为 signed char、short、int、long 及 long long 的最小值 (宏常量)
SCHAR_MAXSHRT_MAXINT_MAXLONG_MAXLLONG_MAX (C99) | 分别为 signed char、short、int、long 及 long long 的最大值 (宏常量)
UCHAR_WIDTHUSHRT_WIDTHUINT_WIDTHULONG_WIDTHULLONG_WIDTH (C23)(C23)(C23)(C23)(C23) | 分别为 unsigned char、unsigned short、unsigned int、unsigned long 及 unsigned long long 的位宽 (宏常量)
UCHAR_MAXUSHRT_MAXUINT_MAXULONG_MAXULLONG_MAX (C99) | 分别为 unsigned char、unsigned short、unsigned int、 unsigned long 及 unsigned long long 的最大值 (宏常量)

示例

#include <stdio.h>
#include <limits.h>

int main(void)
{
    printf("CHAR_BIT   = %d\n", CHAR_BIT);
    printf("MB_LEN_MAX = %d\n", MB_LEN_MAX);
    printf("\n");

    printf("CHAR_MIN   = %+d\n", CHAR_MIN);
    printf("CHAR_MAX   = %+d\n", CHAR_MAX);
    printf("SCHAR_MIN  = %+d\n", SCHAR_MIN);
    printf("SCHAR_MAX  = %+d\n", SCHAR_MAX);
    printf("UCHAR_MAX  = %u\n",  UCHAR_MAX);
    printf("\n");

    printf("SHRT_MIN   = %+d\n", SHRT_MIN);
    printf("SHRT_MAX   = %+d\n", SHRT_MAX);
    printf("USHRT_MAX  = %u\n",  USHRT_MAX);
    printf("\n");

    printf("INT_MIN    = %+d\n", INT_MIN);
    printf("INT_MAX    = %+d\n", INT_MAX);
    printf("UINT_MAX   = %u\n",  UINT_MAX);
    printf("\n");

    printf("LONG_MIN   = %+ld\n", LONG_MIN);
    printf("LONG_MAX   = %+ld\n", LONG_MAX);
    printf("ULONG_MAX  = %lu\n",  ULONG_MAX);
    printf("\n");

    printf("LLONG_MIN  = %+lld\n", LLONG_MIN);
    printf("LLONG_MAX  = %+lld\n", LLONG_MAX);
    printf("ULLONG_MAX = %llu\n",  ULLONG_MAX);
    printf("\n");
}

可能的输出：

CHAR_BIT   = 8
MB_LEN_MAX = 16

CHAR_MIN   = -128
CHAR_MAX   = +127
SCHAR_MIN  = -128
SCHAR_MAX  = +127
UCHAR_MAX  = 255

SHRT_MIN   = -32768
SHRT_MAX   = +32767
USHRT_MAX  = 65535

INT_MIN    = -2147483648
INT_MAX    = +2147483647
UINT_MAX   = 4294967295

LONG_MIN   = -9223372036854775808
LONG_MAX   = +9223372036854775807
ULONG_MAX  = 18446744073709551615

LLONG_MIN  = -9223372036854775808
LLONG_MAX  = +9223372036854775807
ULLONG_MAX = 18446744073709551615

浮点类型极限

定义于头文件 <float.h>
FLT_RADIX | 用于表示所有三种浮点数类型的底（整数基） (宏常量)
DECIMAL_DIG (C99) | 将 long double转换成十进制小数，再转回 long double 而保持同一值，至少需要 DECIMAL_DIG 位小数：此乃 long double 序列化/反序列化所需的十进制精度 (宏常量)
FLT_DECIMAL_DIGDBL_DECIMAL_DIGLDBL_DECIMAL_DIG (C11) | 将 float/double/long double 转换成十进制小数再转换回同一值，至少需要 FLT_DECIMAL_DIG/DBL_DECIMAL_DIG/LDBL_DECIMAL_DIG 位小数：此乃浮点值序列化/反序列化所需的十进制精度。标准定义至少为 6 、 10 、 10 ， 而 IEEE float 为 9 ， IEEE double 为 17 。（见 C++ 模仿 max_digits10 ） (宏常量)
FLT_MINDBL_MINLDBL_MIN | 分别为 float 、 double 及 long double 的最小正规正值 (宏常量)
FLT_TRUE_MINDBL_TRUE_MINLDBL_TRUE_MIN (C11) | 分别为 float 、 double 和 long double 的最小正值 (宏常量)
FLT_MAXDBL_MAXLDBL_MAX | 分别为 float 、 double 和 long double 的最大有限正值 (宏常量)
FLT_EPSILONDBL_EPSILONLDBL_EPSILON | 分别为 1.0 与下一个可表示的float 、 double 和 long double 值之差 (宏常量)
FLT_DIGDBL_DIGLDBL_DIG | 保证能从文本转换为 float/double/long double 再转换回文本，而不会发生改变或上溢出的十进制位数（细节见 C++ 模仿 digits10 ） (宏常量)
FLT_MANT_DIGDBL_MANT_DIGLDBL_MANT_DIG | 分别为 float 、 double 和 long double 所能表示而不损失精度的，浮点尾数中的 FLT_RADIX 底位数 (宏常量)
FLT_MIN_EXPDBL_MIN_EXPLDBL_MIN_EXP | 分别为对应 float 、 double 和 long double 的最小负整数，使得 FLT_RADIX 的该数减一次幂为正规 (宏常量)
FLT_MIN_10_EXPDBL_MIN_10_EXPLDBL_MIN_10_EXP | 分别为对应 float 、 double 和 long double 的最小负整数，使得 10 的该数减一次幂为正规的 (宏常量)
FLT_MAX_EXPDBL_MAX_EXPLDBL_MAX_EXP | 分别为能够使 FLT_RADIX 的该整数减一次幂为可表示的有限的 float、double 与 long double 的最大正整数 (宏常量)
FLT_MAX_10_EXPDBL_MAX_10_EXPLDBL_MAX_10_EXP | 分别为能够使 10 的该整数减一次幂为可表示的有限的 float、double 与 long double 的最大正整数 (宏常量)
FLT_ROUNDS | 浮点算术的舍入模式，等于 float_round_style (宏常量)
FLT_EVAL_METHOD (C99) | 中间结果所用的扩展精度： 0 表示不使用， 1 表示用 double 替代 float ， 2 表示使用 long double (宏常量)
FLT_HAS_SUBNORMDBL_HAS_SUBNORMLDBL_HAS_SUBNORM (C11) | 类型是否支持非正规（非正规）数： -1 为不确定， 0 为不支持， 1 为支持 (宏常量)

示例

#include <stdio.h>
#include <float.h>
#include <math.h>

int main(void)
{
    printf("FLT_RADIX    = %d\n", FLT_RADIX);
    printf("DECIMAL_DIG  = %d\n", DECIMAL_DIG);
    printf("FLT_MIN      = %e\n", FLT_MIN);
    printf("FLT_MAX      = %e\n", FLT_MAX);
    printf("FLT_EPSILON  = %e\n", FLT_EPSILON);
    printf("FLT_DIG      = %d\n", FLT_DIG);
    printf("FLT_MANT_DIG = %d\n", FLT_MANT_DIG);
    printf("FLT_MIN_EXP  = %d\n",  FLT_MIN_EXP);
    printf("FLT_MIN_10_EXP  = %d\n",  FLT_MIN_10_EXP);
    printf("FLT_MAX_EXP     = %d\n",  FLT_MAX_EXP);
    printf("FLT_MAX_10_EXP  = %d\n",  FLT_MAX_10_EXP);
    printf("FLT_ROUNDS      = %d\n",  FLT_ROUNDS);
    printf("FLT_EVAL_METHOD = %d\n",  FLT_EVAL_METHOD);
    printf("FLT_HAS_SUBNORM = %d\n",  FLT_HAS_SUBNORM);
}

可能的输出：

FLT_RADIX    = 2
DECIMAL_DIG  = 37
FLT_MIN      = 1.175494e-38
FLT_MAX      = 3.402823e+38
FLT_EPSILON  = 1.192093e-07
FLT_DIG      = 6
FLT_MANT_DIG = 24
FLT_MIN_EXP  = -125
FLT_MIN_10_EXP  = -37
FLT_MAX_EXP     = 128
FLT_MAX_10_EXP  = 38
FLT_ROUNDS      = 1
FLT_EVAL_METHOD = 1
FLT_HAS_SUBNORM = 1

引用

  • C17 标准（ISO/IEC 9899:2018）：
  • 5.2.4.2 Numerical limits (p: 20-27)
  • 7.20.3 Limits of other integer types (p: 215-216)
  • C11 标准（ISO/IEC 9899:2011）：
  • 5.2.4.2 Numerical limits (p: 26-34)
  • 7.20.3 Limits of other integer types (p: 293-294)
  • C99 标准（ISO/IEC 9899:1999）：
  • 5.2.4.2 Numerical limits (p: 21-28)
  • 7.18.3 Limits of other integer types (p: 259-260)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 2.2.4.2 Numerical limits

参阅


FLT_EVAL_METHOD

< c‎ | types‎ | limits
定义于头文件 <float.h> |
#define FLT_EVAL_METHOD /* implementation defined */ | (C99 起)

指定从浮点常量和除了赋值、转型及库函数调用的所有运算（运算符、运算数的隐式转换）获得的浮点值的范围和精度。

值 | 解释
-1 外的负值 | 实现定义行为
-1 | 默认精度未知
0 | 以所用类型的范围和精度进行所有运算和常量求值。而且， float_t 和 double_t 分别等价于 float 和 double
1 | 以 double 的范围和精度进行所有运算和常量求值。而且， float_t 和 double_t 都等价于 double
2 | 以 long double 的范围和精度进行所有运算和常量求值。而且， float_t 和 double_t 都等价于 long double

注意

无关乎 FLT_EVAL_METHOD 的值，任何浮点表达式都可以被缩短，即如同所有中间结果拥有无限范围和精度一般进行（除非关闭 #pragma STDC FP_CONTRACT ）

转型和复制会剥除任何额外的范围和精度：这模拟从扩展精度 FPU 寄存器存储值到标准大小内存位置的动作。

参阅


FLT_ROUNDS

< c‎ | types‎ | limits
定义于头文件 <float.h>
#define FLT_ROUNDS /* implementation defined */

返回当前浮点算术运算的舍入方向。

值 | 解释
-1 | 默认舍入方向未知
0 | 向零， FE_TOWARDZERO
1 | 向最近值， FE_TONEAREST
2 | 向正无穷大， FE_UPWARD
3 | 向负无穷大， FE_DOWNWARD
其他值 | 实现定义行为

注意

能用 fesetround 更改舍入模式，而 FLT_ROUNDS 反映更改。

参阅

fegetroundfesetround
(C99)(C99)
 获得或设置数字的舍入方向
(函数)


max_align_t

< c‎ | types
定义于头文件 <stddef.h> |
typedef /*implementation-defined*/ max_align_t; | (C11 起)

max_align_t 是对齐要求至少和其他任何一种标量类型一样严格（一样大）的类型。

注意

如 malloc 的分配函数所返回的指针为任意对象对齐，这表示它们至少和 max_align_t 一样严格。

max_align_t 通常是最大标量类型的同义词，在大多数平台上为 long double ，其对齐要求为 8 或 16 。

示例

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>

int main(void)
{
    size_t a = _Alignof(max_align_t);
    printf("Alignment of max_align_t is %zu (%#zx)\n", a, a);

    void *p = malloc(123);
    printf("The address obtained from malloc(123) is %#" PRIxPTR"\n",
            (uintptr_t)p);
    free(p);
}

可能的输出：

Alignment of max_align_t is 16 (0x10)
The address obtained from malloc(123) is 0x1fa67010

参阅


offsetof

< c‎ | types
定义于头文件 <stddef.h>
#define offsetof(type, member) /*implementation-defined*/

宏 offsetof 展开成 size_t 类型的整数常量表达式，其值为从指定类型对象起始到其指定子对象的偏移，若填充存在则包含之。

给定拥有静态存储期的 type 类型对象 o ， &(o.member) 应当为地址常量表达式并指向 o 的子对象。否则行为未定义。

若在 type 中定义新类型，则行为未定义。

 (C23 起)

注解

若将 offsetof 应用到位域成员，则行为未定义，因为不能取位域的地址。

不限制 member 为直接成员。它能指代给定成员的子对象，例如数组成员的元素。

尽管 C23 中指定在 offsetof 中定义新类型为未定义行为，这种用法在较早模式的实现中也仅受到部分支持： offsetof(struct Foo { int a; }, a) 通常得到支持，但 offsetof(struct Foo { int a, b; }, a) 不如此，因为 struct Foo 定义中的逗号。

示例

#include <stdio.h>
#include <stddef.h>

struct S {
    char c;
    double d;
};

int main(void)
{
    printf("the first element is at offset %zu\n", offsetof(struct S, c));
    printf("the double is at offset %zu\n", offsetof(struct S, d));
}

可能的输出：

the first element is at offset 0
the double is at offset 8

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C 标准。

DR | 应用于 | 出版时的行为 | 正确行为
DR 496 | C89 | 仅提及结构体与结构体成员 | 亦支持联合体与其他子对象

参阅

size_t
 sizeof 运算符返回的无符号整数类型
(typedef)


ptrdiff_t

< c‎ | types
定义于头文件 <stddef.h>
typedef /*implementation-defined*/ ptrdiff_t;

ptrdiff_t 是二个指针相减结果所拥有的有符号整数类型。

ptrdiff_t 的位宽不小于 17 。

 (C99 起)

注解

ptrdiff_t 用于指针算术和数组下标，若可能使用负值。使用其他类型，如 int 的程序，可能会例如下标超过 INT_MAX 时，或若依赖 32 位模算术时失败，譬如在 64 位系统上。

只有指向同一数组元素（包括指向数组尾后一个位置）的指针可以相减。

若数组足够大（大于 PTRDIFF_MAX 个元素，但小于 SIZE_MAX 个元素），则二个指针间的距离可能无法以 ptrdiff_t 表示，这二个指针相减的结果未定义。

对于短于 PTRDIFF_MAX 的 char 数组， ptrdiff_t 表现同 size_t 的有符号对应：它能存储任何类型的数组大小，而且在大多数平台上是 intptr_t 的同义词。

示例

#include <stdio.h>
#include <stddef.h>
#include <stdint.h>

int main(void)
{
    const size_t N = 100;
    int numbers[N];

    printf("PTRDIFF_MAX = %ld\n", PTRDIFF_MAX);
    int *p1=&numbers[18], *p2=&numbers[23];
    ptrdiff_t diff = p2-p1;
    printf("p2-p1 = %td\n", diff);

    return 0;
}

可能的输出：

PTRDIFF_MAX = 9223372036854775807
p2-p1 = 5

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.19 Common definitions <stddef.h> (p: 288)
  • 7.20.3 Limits of other integer types (p: 293)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.17 Common definitions <stddef.h> (p: 253)
  • 7.18.3 Limits of other integer types (p: 258)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.1.6 Common definitions <stddef.h>

参阅

size_t | sizeof 运算符返回的无符号整数类型 (typedef)
offsetof | 从指定结构体类型的起始到指定成员的字节位移 (宏函数)


size_t

< c‎ | types
定义于头文件 <stddef.h> |
定义于头文件 <stdio.h> |
定义于头文件 <stdlib.h> |
定义于头文件 <string.h> |
定义于头文件 <time.h> |
定义于头文件 <uchar.h> | (C11 起)
定义于头文件 <wchar.h> | (C95 起)
typedef /*implementation-defined*/ size_t; |

size_t 是 sizeof 、 _Alignof (C11 起) 和 offsetof 的结果的无符号整数类型，定义取决于数据模型。

size_t 的位宽不小于 16 。

 (C99 起)

注解

size_t 能存储理论上可行的任何类型（包括数组）对象的最大大小。

size_t 通常用于数组下标和循环计数。将如 unsigned int 的其他类型用作数组下标的的程序，可能在 64 位系统上失败，例如在下标超过 UINT_MAX 时，或若依赖 32 位模算术。

示例

#include <stdio.h>
#include <stddef.h>
#include <stdint.h>

int main(void)
{
    const size_t N = 100;
    int numbers[N];
    for (size_t ndx = 0; ndx < N; ++ndx)
        numbers[ndx] = ndx;
    printf("SIZE_MAX = %zu\n", SIZE_MAX);
    size_t size = sizeof numbers;
    printf("size = %zu\n", size);
}

可能的输出：

SIZE_MAX = 18446744073709551615
size = 400

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.19 Common definitions <stddef.h> (p: 288)
  • 7.20.3 Limits of other integer types (p: 293)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.17 Common definitions <stddef.h> (p: 253)
  • 7.18.3 Limits of other integer types (p: 258)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.1.6 Common definitions <stddef.h>

参阅

ptrdiff_t | 两个指针相减返回的有符号整数类型 (typedef)
offsetof | 从指定结构体类型的起始到指定成员的字节位移 (宏函数)


变参数函数

< c

变参数函数是使用可变数量参数的函数（例如 printf ）。

变参数函数使用在其最后一个参数后加省略号声明，例如 int printf (const char* format, ...); 。语法和自动参数转换的额外细节见可变参数。

从函数体内使用以下工具访问可变参数：

宏
定义于头文件 <stdarg.h>
va_start
 令函数得以访问可变参数
(宏函数)
va_arg
 访问下一个函数可变参数
(宏函数)
va_copy
(C99)
 创造函数可变参数的副本
(宏函数)
va_end
 结束函数可变参数的行程
(宏函数)
类型
va_list
 保有 va_start 、 va_arg 、 va_end 及 va_copy 所需信息
(typedef)

示例

打印不同类型的值。

#include <stdio.h>
#include <stdarg.h>

void simple_printf(const char* fmt, ...)
{
    va_list args;
    va_start(args, fmt);

    while (*fmt != '\0') {
        if (*fmt == 'd') {
            int i = va_arg(args, int);
            printf("%d\n", i);
        } else if (*fmt == 'c') {
            // 将提升 'char' 类型值为 'int'
            // C 中字符常量自身为 'int' 类型
            int c = va_arg(args, int);
            printf("%c\n", c);
        } else if (*fmt == 'f') {
            double d = va_arg(args, double);
            printf("%f\n", d);
        }
        ++fmt;
    }

    va_end(args);
}

int main(void)
{
    simple_printf("dcff", 3, 'a', 1.999, 42.5);
}

输出：

3
a
1.999000
42.50000

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.16 Variable arguments <stdarg.h> (p: 269-272)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.15 Variable arguments <stdarg.h> (p: 249-252)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.8 VARIABLE ARGUMENTS <stdarg.h>

参阅


va_arg

< c‎ | variadic
定义于头文件 <stdarg.h>
T va_arg( va_list ap, T );

va_arg 宏展开成 T 类型的表达式，表达式对应来自 va_list ap 的下个参数。

调用 va_arg 前，必须调用 va_start 或 va_copy 初始化 ap ，中间不能有 va_end 调用。每次调用 va_arg 宏都会修改 ap ，令它指向下一个可变参数。

若在 ap 中无更多参数时调用 va_arg ，或若 ap 中的下个参数（提升后）与 T 的类型不兼容，则行为未定义，除非：

  • 一个类型是有符号整数类型，另一类型是对应的无符号整数类型，而且值可以被两类型一同表示；或
  • 一个类型是指向 void 的指针，而另一个是指向字符类型的指针。

参数

ap | - | va_list 类型实例
T | - | ap 中下个参数的类型

展开值

ap 中的下个可变参数。

示例

#include <stdio.h>
#include <stdarg.h>
#include <math.h>

double stddev(int count, ...)
{
    double sum = 0;
    double sum_sq = 0;
    va_list args;
    va_start(args, count);
    for (int i = 0; i < count; ++i) {
        double num = va_arg(args, double);
        sum += num;
        sum_sq += num*num;
    }
    va_end(args);
    return sqrt(sum_sq/count - (sum/count)*(sum/count));
}

int main(void)
{
    printf("%f\n", stddev(4, 25.0, 27.3, 26.9, 25.7));
}

输出：

0.920258

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.16.1.1 The va_arg macro (p: 269-270)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.15.1.1 The va_arg macro (p: 249-250)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.8.1.2 The va_arg macro

参阅

va_copy (C99) | 创造函数可变参数的副本 (宏函数)
va_end | 结束函数可变参数的行程 (宏函数)
va_list | 保有 va_start 、 va_arg 、 va_end 及 va_copy 所需信息 (typedef)
va_start | 令函数得以访问可变参数 (宏函数)


va_copy

< c‎ | variadic
定义于头文件 <stdarg.h> |
void va_copy( va_list dest, va_list src ); | (C99 起)

va_copy 宏把 src 复制到 dest 。

在函数返回，或 dest 的任何再初始化（通过调用 va_start 或 va_copy ）前，应该对 dest 调用 va_end 。

参数

dest | - | 待初始化的 va_list类型对象
src | - | 将用以初始化 dest 的源 va_list

展开值

（无）

示例

#include <stdio.h>
#include <stdarg.h>
#include <math.h>

double sample_stddev(int count, ...)
{
    /* 以 args1 计算平均数。 */
    double sum = 0;
    va_list args1;
    va_start(args1, count);
    va_list args2;
    va_copy(args2, args1);   /* 复制 va_list 对象 */
    for (int i = 0; i < count; ++i) {
        double num = va_arg(args1, double);
        sum += num;
    }
    va_end(args1);
    double mean = sum / count;

    /* 以args2和平均数计算标准差。 */
    double sum_sq_diff = 0;
    for (int i = 0; i < count; ++i) {
        double num = va_arg(args2, double);
        sum_sq_diff += (num-mean) * (num-mean);
    }
    va_end(args2);
    return sqrt(sum_sq_diff / count);
}

int main(void)
{
    printf("%f\n", sample_stddev(4, 25.0, 27.3, 26.9, 25.7));
}

可能的输出：

0.920258

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.16.1.2 The va_copy macro (p: 270)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.15.1.2 The va_copy macro (p: 250)

参阅

va_start | 令函数得以访问可变参数 (宏函数)
va_arg | 访问下一个函数可变参数 (宏函数)
va_end | 结束函数可变参数的行程 (宏函数)
va_list | 保有 va_start 、 va_arg 、 va_end 及 va_copy 所需信息 (typedef)


va_end

< c‎ | variadic
定义于头文件 <stdarg.h>
void va_end( va_list ap );

va_end 宏 va_start 或 va_copy 的调用所初始化的 ap 对象的清理。 va_end 可以修改 ap 的值，使得它不再能使用。

若无对应的对 va_start 或 va_copy 调用，或在调用 va_start 或 va_copy 的函数返回前没有调用 va_end ，则行为未定义。

参数

ap - 待清理的 va_list 类型实例

展开值

（无）

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.16.1.3 The va_end macro (p: 270-271)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.15.1.3 The va_end macro (p: 250-251)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.8.1.3 The va_end macro

参阅

va_start | 令函数得以访问可变参数 (宏函数)
va_copy (C99) | 创造函数可变参数的副本 (宏函数)
va_arg | 访问下一个函数可变参数 (宏函数)
va_list | 保有 va_start 、 va_arg 、 va_end 及 va_copy 所需信息 (typedef)


va_list

< c‎ | variadic
定义于头文件 <stdarg.h>
/* unspecified */ va_list;

va_list 是一个完整对象类型，适于保有宏 va_start 、 va_copy 、 va_arg 及 va_end 所需的信息。

若创建 va_list 的实例并传递给另一个函数，且在该函数中通过 va_arg 使用它，则在调用方函数中的任何后继调用必须前接对 va_end 的调用。

传递指向 va_list 对象的指针给另一个函数，并使用该函数返回后使用指针所指对象是合法的。

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.16/3 Variable arguments <stdarg.h> (p: 269)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.15/3 Variable arguments <stdarg.h> (p: 249)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.8 VARIABLE ARGUMENTS <stdarg.h>

参阅

va_start | 令函数得以访问可变参数 (宏函数)
va_copy (C99) | 创造函数可变参数的副本 (宏函数)
va_arg | 访问下一个函数可变参数 (宏函数)
va_end | 结束函数可变参数的行程 (宏函数)


va_start

< c‎ | variadic
定义于头文件 <stdarg.h>
void va_start( va_list ap, parmN );

va_start 宏使函数能访问parmN后的可变参数。

应该在任何对 va_arg 的调用前，以合法的 va_list 对象 ap 调用 va_start 。

若 parmN 声明带有 register 存储类指定符、数组类型、函数类型，或与默认参数提升结果类型不兼容的类型，则行为未定义。

参数

ap | - | va_list 类型实例
parmN | - | 首个可变参数前的参数名

展开值

（无）

示例

#include <stdio.h>
#include <stdarg.h>

int add_nums(int count, ...)
{
    int result = 0;
    va_list args;
    va_start(args, count);
    for (int i = 0; i < count; ++i) {
        result += va_arg(args, int);
    }
    va_end(args);
    return result;
}

int main(void)
{
    printf("%d\n", add_nums(4, 25, 25, 50, 50));
}

可能的输出：

150

引用

  • C11 标准（ISO/IEC 9899:2011）：
  • 7.16.1.4 The va_start macro (p: 271-272)
  • C99 标准（ISO/IEC 9899:1999）：
  • 7.15.1.4 The va_start macro (p: 251-252)
  • C89/C90 标准（ISO/IEC 9899:1990）：
  • 4.8.1.1 The va_start macro

参阅

va_arg | 访问下一个函数可变参数 (宏函数)
va_copy (C99) | 创造函数可变参数的副本 (宏函数)
va_end | 结束函数可变参数的行程 (宏函数)
va_list | 保有 va_start 、 va_arg 、 va_end 及 va_copy 所需信息 (typedef)


C++ 参考手册

C++98, C++03, C++11, C++14, C++17, C++20, C++23 │ 编译器支持 C++11, C++14, C++17, C++20, C++23

自立实现

语言

基本概念
关键词
预处理器
表达式
声明
初始化
函数
语句
类
重载
模板
异常

头文件

具名要求

功能特性测试宏 (C++20)

语言支持库

源代码信息 (C++20)
类型支持 − 特性 (C++11)
程序工具
协程支持 (C++20)
三路比较 (C++20)
numeric_limits − type_info
initializer_list (C++11)

概念库 (C++20)

诊断库

通用工具库

智能指针和分配器
unique_ptr (C++11)
shared_ptr‏‎‏‎ (C++11)
日期和时间
函数对象 − hash (C++11)
字符串转换 (C++17)
工具函数
pair − tuple (C++11)
optional (C++17) − any (C++17)
variant (C++17) − format (C++20)
basic_stacktrace (C++23)

字符串库

basic_string
basic_string_view (C++17)
空终止字符串：
字节 − 多字节 − 宽

容器库

array (C++11) − vector − deque
map − unordered_map (C++11)
set − unordered_set (C++11)
priority_queue − span (C++20)
其他容器：
顺序 − 关联
无序关联 − 适配器

迭代器库

范围库 (C++20)

算法库

数值库

常用数学函数
数学特殊函数 (C++17)
数学常数 (C++20)
数值算法
伪随机数生成
浮点环境 (C++11)
位操纵 (C++20)
complex − valarray
ratio (C++11)

本地化库

输入/输出库

基于流的 I/O
同步输出 (C++20)
I/O 操纵符

文件系统库 (C++17)

正则表达式库 (C++11)

basic_regex − 算法

原子操作库 (C++11)

atomic − atomic_flag
atomic_ref (C++20)

线程支持库 (C++11)

thread‏‎ − mutex‏‎
condition_variable‏‎
技术规范

标准库扩展 (库基础 TS)

resource_adaptor — invocation_type

标准库扩展 v2 (库基础 TS v2)

propagate_const — ostream_joiner — randint
observer_ptr — 检测手法

标准库扩展 v3 (库基础 TS v3)

scope_exit — scope_fail — scope_success — unique_resource

并发库扩展 (并发 TS) — 事务性内存 (TM TS)
反射 (反射 TS)
外部链接 − 非 ANSI/ISO 库 − 索引 − std 符号索引


C++11

< cpp

C++11 是 C++ 的第二个主要版本（前一个是 C++98 而后一个是 C++17 ），并且是从 C++98 起的最重要更新。它引入了大量更改，标准化了既有实践，并改进了对 C++ 程序员可用的抽象。

在它最终由 ISO 在 2011 年 8 月 12 日承认前，人们曾使用名称 'C++0x' ，因为它曾被期待在 2010 年之前发布。 C++03 与 C++11 期间花了 8 年时间，故而这是迄今为止最长的版本间隔。从那时起， C++ 规则地每 3 年更新一次。

本节未完成
原因：更详细的描述

下列功能特性被并入 C++11 ：

  • 来自 TR1 ： TR1 的全部，除了数学特殊函数。
  • 来自 Boost ：线程库、 exception_ptr、 error_code 与 error_condition、迭代器改进（ std::begin、 std::end、 std::next、 std::prev ）
  • 来自 C ： C 风格 Unicode 转换函数

核心语言功能特性

  • auto 与 decltype
  • 预置与弃置的函数
  • final 与 override
  • 尾随返回类型
  • 右值引用
  • 移动构造函数与移动赋值运算符
  • 有作用域枚举
  • constexpr 与字面类型
  • 列表初始化
  • 委托与继承的构造函数
  • 花括号或等号初始化器
  • nullptr
  • long long
  • char16_t 与 char32_t
  • 类型别名
  • 变参数模板
  • 推广的（非平凡）联合体
  • 推广的 POD （平凡类型与标准布局类型）
  • Unicode 字符串字面量
  • 用户定义字面量
  • 属性
  • lambda 表达式
  • noexcept 说明符与 noexcept 运算符
  • alignof 与 alignas
  • 多线程内存模型
  • 线程局部存储
  • GC 接口
  • 范围 for （基于 Boost 库）
  • static_assert （基于 Boost 库）
本节未完成

库功能特性

头文件

  • <typeindex>
  • <type_traits>
  • <chrono>
  • <initializer_list>
  • <tuple>
  • <scoped_allocator>
  • <cstdint>
  • <cinttypes>
  • <system_error>
  • <cuchar>
  • <array>
  • <forward_list>
  • <unordered_set>
  • <unordered_map>
  • <random>
  • <ratio>
  • <cfenv>
  • <regex>
  • <atomic>
  • <thread>
  • <mutex>
  • <future>
  • <condition_variable>

库功能特性

  • 原子操作库
  • emplace() 与其他遍及既存标准库所有部分的右值引用使用
  • std::unique_ptr
  • std::move_iterator
  • std::initializer_list
  • 有状态及有作用域分配器
  • std::forward_list
  • chrono 库
  • ratio 库
  • 新算法
  • Unicode 转换平台
  • thread library
  • std::function
  • std::exception_ptr
  • std::error_code 与 std::error_condition
  • 迭代器改进：
  • std::begin
  • std::end
  • std::next
  • std::prev
  • Unicode 转换函数
本节未完成

缺陷报告

C++11 中修正的缺陷报告（核心 741 个，库 868 个）
  • CWG#4
  • CWG#5
  • CWG#8
  • CWG#9
  • CWG#10
  • CWG#11
  • CWG#16
  • CWG#28
  • CWG#29
  • CWG#39
  • CWG#44
  • CWG#45
  • CWG#54
  • CWG#58
  • CWG#60
  • CWG#62
  • CWG#63
  • CWG#70
  • CWG#77
  • CWG#78
  • CWG#86
  • CWG#87
  • CWG#96
  • CWG#106
  • CWG#112
  • CWG#113
  • CWG#115
  • CWG#118
  • CWG#119
  • CWG#122
  • CWG#124
  • CWG#125
  • CWG#136
  • CWG#139
  • CWG#140
  • CWG#141
  • CWG#143
  • CWG#158
  • CWG#160
  • CWG#162
  • CWG#172
  • CWG#175
  • CWG#177
  • CWG#180
  • CWG#184
  • CWG#195
  • CWG#197
  • CWG#198
  • CWG#199
  • CWG#201
  • CWG#204
  • CWG#207
  • CWG#208
  • CWG#214
  • CWG#215
  • CWG#216
  • CWG#218
  • CWG#220
  • CWG#221
  • CWG#222
  • CWG#224
  • CWG#226
  • CWG#228
  • CWG#237
  • CWG#239
  • CWG#244
  • CWG#245
  • CWG#246
  • CWG#248
  • CWG#252
  • CWG#254
  • CWG#256
  • CWG#257
  • CWG#258
  • CWG#259
  • CWG#261
  • CWG#262
  • CWG#263
  • CWG#270
  • CWG#272
  • CWG#273
  • CWG#274
  • CWG#275
  • CWG#276
  • CWG#277
  • CWG#280
  • CWG#281
  • CWG#283
  • CWG#284
  • CWG#286
  • CWG#288
  • CWG#289
  • CWG#291
  • CWG#295
  • CWG#296
  • CWG#298
  • CWG#299
  • CWG#300
  • CWG#301
  • CWG#302
  • CWG#305
  • CWG#306
  • CWG#309
  • CWG#317
  • CWG#318
  • CWG#319
  • CWG#320
  • CWG#322
  • CWG#323
  • CWG#324
  • CWG#326
  • CWG#327
  • CWG#328
  • CWG#329
  • CWG#331
  • CWG#335
  • CWG#336
  • CWG#337
  • CWG#339
  • CWG#341
  • CWG#345
  • CWG#348
  • CWG#349
  • CWG#351
  • CWG#352
  • CWG#353
  • CWG#354
  • CWG#355
  • CWG#357
  • CWG#362
  • CWG#364
  • CWG#366
  • CWG#367
  • CWG#368
  • CWG#370
  • CWG#372
  • CWG#373
  • CWG#374
  • CWG#377
  • CWG#378
  • CWG#379
  • CWG#381
  • CWG#382
  • CWG#383
  • CWG#385
  • CWG#387
  • CWG#389
  • CWG#390
  • CWG#391
  • CWG#392
  • CWG#394
  • CWG#396
  • CWG#397
  • CWG#398
  • CWG#400
  • CWG#401
  • CWG#403
  • CWG#404
  • CWG#406
  • CWG#407
  • CWG#408
  • CWG#409
  • CWG#410
  • CWG#413
  • CWG#414
  • CWG#415
  • CWG#416
  • CWG#417
  • CWG#420
  • CWG#421
  • CWG#424
  • CWG#425
  • CWG#427
  • CWG#428
  • CWG#429
  • CWG#430
  • CWG#431
  • CWG#432
  • CWG#433
  • CWG#436
  • CWG#437
  • CWG#438
  • CWG#439
  • CWG#441
  • CWG#442
  • CWG#443
  • CWG#446
  • CWG#447
  • CWG#448
  • CWG#450
  • CWG#451
  • CWG#452
  • CWG#454
  • CWG#457
  • CWG#458
  • CWG#460
  • CWG#463
  • CWG#464
  • CWG#466
  • CWG#468
  • CWG#470
  • CWG#474
  • CWG#475
  • CWG#477
  • CWG#479
  • CWG#480
  • CWG#481
  • CWG#484
  • CWG#485
  • CWG#486
  • CWG#488
  • CWG#490
  • CWG#491
  • CWG#492
  • CWG#493
  • CWG#494
  • CWG#495
  • CWG#497
  • CWG#499
  • CWG#500
  • CWG#502
  • CWG#505
  • CWG#506
  • CWG#508
  • CWG#509
  • CWG#510
  • CWG#513
  • CWG#514
  • CWG#515
  • CWG#516
  • CWG#517
  • CWG#518
  • CWG#519
  • CWG#520
  • CWG#521
  • CWG#522
  • CWG#524
  • CWG#525
  • CWG#526
  • CWG#527
  • CWG#530
  • CWG#531
  • CWG#532
  • CWG#534
  • CWG#537
  • CWG#538
  • CWG#540
  • CWG#541
  • CWG#542
  • CWG#543
  • CWG#546
  • CWG#547
  • CWG#551
  • CWG#556
  • CWG#557
  • CWG#558
  • CWG#559
  • CWG#561
  • CWG#564
  • CWG#568
  • CWG#569
  • CWG#570
  • CWG#571
  • CWG#572
  • CWG#573
  • CWG#575
  • CWG#576
  • CWG#580
  • CWG#582
  • CWG#587
  • CWG#588
  • CWG#589
  • CWG#590
  • CWG#592
  • CWG#594
  • CWG#598
  • CWG#599
  • CWG#601
  • CWG#602
  • CWG#603
  • CWG#604
  • CWG#605
  • CWG#606
  • CWG#608
  • CWG#611
  • CWG#612
  • CWG#613
  • CWG#614
  • CWG#615
  • CWG#618
  • CWG#619
  • CWG#620
  • CWG#621
  • CWG#624
  • CWG#625
  • CWG#626
  • CWG#628
  • CWG#629
  • CWG#630
  • CWG#632
  • CWG#633
  • CWG#634
  • CWG#637
  • CWG#638
  • CWG#639
  • CWG#641
  • CWG#642
  • CWG#644
  • CWG#645
  • CWG#647
  • CWG#648
  • CWG#649
  • CWG#650
  • CWG#651
  • CWG#652
  • CWG#653
  • CWG#654
  • CWG#655
  • CWG#656
  • CWG#657
  • CWG#658
  • CWG#659
  • CWG#660
  • CWG#661
  • CWG#663
  • CWG#664
  • CWG#665
  • CWG#666
  • CWG#667
  • CWG#668
  • CWG#671
  • CWG#672
  • CWG#674
  • CWG#676
  • CWG#677
  • CWG#678
  • CWG#679
  • CWG#680
  • CWG#681
  • CWG#683
  • CWG#684
  • CWG#685
  • CWG#686
  • CWG#688
  • CWG#690
  • CWG#691
  • CWG#692
  • CWG#693
  • CWG#694
  • CWG#695
  • CWG#696
  • CWG#699
  • CWG#700
  • CWG#701
  • CWG#702
  • CWG#703
  • CWG#704
  • CWG#705
  • CWG#707
  • CWG#709
  • CWG#710
  • CWG#711
  • CWG#713
  • CWG#714
  • CWG#715
  • CWG#716
  • CWG#717
  • CWG#719
  • CWG#720
  • CWG#721
  • CWG#722
  • CWG#726
  • CWG#730
  • CWG#731
  • CWG#732
  • CWG#734
  • CWG#735
  • CWG#737
  • CWG#738
  • CWG#740
  • CWG#741
  • CWG#743
  • CWG#744
  • CWG#746
  • CWG#749
  • CWG#750
  • CWG#751
  • CWG#752
  • CWG#753
  • CWG#754
  • CWG#756
  • CWG#757
  • CWG#758
  • CWG#759
  • CWG#760
  • CWG#761
  • CWG#762
  • CWG#763
  • CWG#764
  • CWG#765
  • CWG#766
  • CWG#767
  • CWG#768
  • CWG#769
  • CWG#770
  • CWG#771
  • CWG#772
  • CWG#773
  • CWG#774
  • CWG#775
  • CWG#776
  • CWG#777
  • CWG#778
  • CWG#779
  • CWG#782
  • CWG#784
  • CWG#785
  • CWG#786
  • CWG#787
  • CWG#788
  • CWG#789
  • CWG#790
  • CWG#792
  • CWG#793
  • CWG#796
  • CWG#797
  • CWG#798
  • CWG#799
  • CWG#801
  • CWG#803
  • CWG#804
  • CWG#805
  • CWG#806
  • CWG#808
  • CWG#809
  • CWG#810
  • CWG#811
  • CWG#812
  • CWG#814
  • CWG#815
  • CWG#816
  • CWG#817
  • CWG#818
  • CWG#820
  • CWG#823
  • CWG#828
  • CWG#830
  • CWG#831
  • CWG#832
  • CWG#833
  • CWG#834
  • CWG#835
  • CWG#837
  • CWG#838
  • CWG#840
  • CWG#842
  • CWG#845
  • CWG#846
  • CWG#847
  • CWG#850
  • CWG#853
  • CWG#854
  • CWG#855
  • CWG#858
  • CWG#860
  • CWG#861
  • CWG#862
  • CWG#863
  • CWG#864
  • CWG#865
  • CWG#869
  • CWG#872
  • CWG#873
  • CWG#874
  • CWG#876
  • CWG#877
  • CWG#879
  • CWG#880
  • CWG#882
  • CWG#883
  • CWG#884
  • CWG#886
  • CWG#887
  • CWG#888
  • CWG#891
  • CWG#892
  • CWG#896
  • CWG#898
  • CWG#899
  • CWG#904
  • CWG#905
  • CWG#906
  • CWG#908
  • CWG#910
  • CWG#913
  • CWG#915
  • CWG#919
  • CWG#920
  • CWG#921
  • CWG#922
  • CWG#923
  • CWG#924
  • CWG#926
  • CWG#927
  • CWG#928
  • CWG#929
  • CWG#930
  • CWG#931
  • CWG#932
  • CWG#933
  • CWG#934
  • CWG#935
  • CWG#936
  • CWG#938
  • CWG#939
  • CWG#940
  • CWG#941
  • CWG#942
  • CWG#945
  • CWG#946
  • CWG#948
  • CWG#950
  • CWG#951
  • CWG#953
  • CWG#955
  • CWG#956
  • CWG#957
  • CWG#959
  • CWG#960
  • CWG#961
  • CWG#962
  • CWG#963
  • CWG#964
  • CWG#965
  • CWG#966
  • CWG#968
  • CWG#969
  • CWG#970
  • CWG#971
  • CWG#972
  • CWG#973
  • CWG#976
  • CWG#978
  • CWG#979
  • CWG#980
  • CWG#981
  • CWG#983
  • CWG#984
  • CWG#985
  • CWG#986
  • CWG#988
  • CWG#989
  • CWG#990
  • CWG#991
  • CWG#993
  • CWG#994
  • CWG#995
  • CWG#996
  • CWG#997
  • CWG#999
  • CWG#1000
  • CWG#1004
  • CWG#1006
  • CWG#1009
  • CWG#1010
  • CWG#1011
  • CWG#1012
  • CWG#1015
  • CWG#1016
  • CWG#1017
  • CWG#1018
  • CWG#1020
  • CWG#1022
  • CWG#1025
  • CWG#1029
  • CWG#1030
  • CWG#1031
  • CWG#1032
  • CWG#1033
  • CWG#1034
  • CWG#1035
  • CWG#1036
  • CWG#1037
  • CWG#1042
  • CWG#1043
  • CWG#1044
  • CWG#1047
  • CWG#1051
  • CWG#1054
  • CWG#1055
  • CWG#1056
  • CWG#1057
  • CWG#1060
  • CWG#1061
  • CWG#1062
  • CWG#1063
  • CWG#1064
  • CWG#1065
  • CWG#1066
  • CWG#1068
  • CWG#1069
  • CWG#1070
  • CWG#1071
  • CWG#1072
  • CWG#1073
  • CWG#1074
  • CWG#1075
  • CWG#1079
  • CWG#1080
  • CWG#1081
  • CWG#1082
  • CWG#1083
  • CWG#1086
  • CWG#1087
  • CWG#1088
  • CWG#1090
  • CWG#1091
  • CWG#1094
  • CWG#1095
  • CWG#1096
  • CWG#1098
  • CWG#1099
  • CWG#1100
  • CWG#1101
  • CWG#1102
  • CWG#1103
  • CWG#1104
  • CWG#1105
  • CWG#1106
  • CWG#1107
  • CWG#1109
  • CWG#1111
  • CWG#1112
  • CWG#1113
  • CWG#1114
  • CWG#1115
  • CWG#1117
  • CWG#1119
  • CWG#1120
  • CWG#1121
  • CWG#1122
  • CWG#1123
  • CWG#1125
  • CWG#1126
  • CWG#1127
  • CWG#1128
  • CWG#1129
  • CWG#1130
  • CWG#1131
  • CWG#1133
  • CWG#1134
  • CWG#1135
  • CWG#1136
  • CWG#1137
  • CWG#1138
  • CWG#1139
  • CWG#1140
  • CWG#1142
  • CWG#1144
  • CWG#1145
  • CWG#1146
  • CWG#1147
  • CWG#1148
  • CWG#1149
  • CWG#1151
  • CWG#1152
  • CWG#1153
  • CWG#1154
  • CWG#1155
  • CWG#1156
  • CWG#1158
  • CWG#1159
  • CWG#1160
  • CWG#1161
  • CWG#1164
  • CWG#1165
  • CWG#1166
  • CWG#1167
  • CWG#1168
  • CWG#1169
  • CWG#1170
  • CWG#1171
  • CWG#1173
  • CWG#1174
  • CWG#1175
  • CWG#1176
  • CWG#1177
  • CWG#1178
  • CWG#1180
  • CWG#1181
  • CWG#1182
  • CWG#1183
  • CWG#1184
  • CWG#1185
  • CWG#1186
  • CWG#1187
  • CWG#1188
  • CWG#1189
  • CWG#1190
  • CWG#1191
  • CWG#1192
  • CWG#1193
  • CWG#1194
  • CWG#1195
  • CWG#1196
  • CWG#1197
  • CWG#1198
  • CWG#1199
  • CWG#1201
  • CWG#1202
  • CWG#1204
  • CWG#1206
  • CWG#1207
  • CWG#1208
  • CWG#1210
  • CWG#1212
  • CWG#1214
  • CWG#1215
  • CWG#1216
  • CWG#1218
  • CWG#1219
  • CWG#1220
  • CWG#1224
  • CWG#1225
  • CWG#1229
  • CWG#1231
  • CWG#1232
  • CWG#1233
  • CWG#1234
  • CWG#1235
  • CWG#1236
  • CWG#1237
  • CWG#1238
  • CWG#1239
  • CWG#1240
  • CWG#1241
  • CWG#1242
  • CWG#1243
  • CWG#1244
  • CWG#1245
  • CWG#1246
  • LWG#23
  • LWG#44
  • LWG#49
  • LWG#76
  • LWG#91
  • LWG#92
  • LWG#98
  • LWG#103
  • LWG#109
  • LWG#117
  • LWG#118
  • LWG#120
  • LWG#123
  • LWG#130
  • LWG#136
  • LWG#149
  • LWG#153
  • LWG#165
  • LWG#167
  • LWG#171
  • LWG#179
  • LWG#180
  • LWG#182
  • LWG#183
  • LWG#184
  • LWG#185
  • LWG#186
  • LWG#187
  • LWG#198
  • LWG#200
  • LWG#201
  • LWG#202
  • LWG#206
  • LWG#214
  • LWG#221
  • LWG#225
  • LWG#226
  • LWG#228
  • LWG#229
  • LWG#230
  • LWG#231
  • LWG#232
  • LWG#233
  • LWG#234
  • LWG#235
  • LWG#237
  • LWG#238
  • LWG#239
  • LWG#240
  • LWG#241
  • LWG#242
  • LWG#243
  • LWG#247
  • LWG#248
  • LWG#250
  • LWG#251
  • LWG#252
  • LWG#253
  • LWG#254
  • LWG#256
  • LWG#258
  • LWG#259
  • LWG#260
  • LWG#261
  • LWG#262
  • LWG#263
  • LWG#264
  • LWG#265
  • LWG#266
  • LWG#268
  • LWG#270
  • LWG#271
  • LWG#272
  • LWG#273
  • LWG#274
  • LWG#275
  • LWG#276
  • LWG#278
  • LWG#280
  • LWG#281
  • LWG#282
  • LWG#283
  • LWG#284
  • LWG#285
  • LWG#286
  • LWG#288
  • LWG#291
  • LWG#292
  • LWG#294
  • LWG#295
  • LWG#296
  • LWG#297
  • LWG#298
  • LWG#300
  • LWG#301
  • LWG#303
  • LWG#305
  • LWG#306
  • LWG#307
  • LWG#308
  • LWG#310
  • LWG#311
  • LWG#312
  • LWG#315
  • LWG#316
  • LWG#317
  • LWG#318
  • LWG#319
  • LWG#320
  • LWG#321
  • LWG#322
  • LWG#324
  • LWG#325
  • LWG#327
  • LWG#328
  • LWG#329
  • LWG#331
  • LWG#333
  • LWG#334
  • LWG#335
  • LWG#336
  • LWG#337
  • LWG#338
  • LWG#339
  • LWG#340
  • LWG#341
  • LWG#343
  • LWG#345
  • LWG#346
  • LWG#347
  • LWG#349
  • LWG#352
  • LWG#353
  • LWG#354
  • LWG#355
  • LWG#358
  • LWG#359
  • LWG#360
  • LWG#362
  • LWG#363
  • LWG#364
  • LWG#365
  • LWG#369
  • LWG#370
  • LWG#371
  • LWG#373
  • LWG#375
  • LWG#376
  • LWG#379
  • LWG#380
  • LWG#381
  • LWG#383
  • LWG#384
  • LWG#386
  • LWG#387
  • LWG#389
  • LWG#391
  • LWG#395
  • LWG#396
  • LWG#400
  • LWG#401
  • LWG#402
  • LWG#403
  • LWG#404
  • LWG#405
  • LWG#406
  • LWG#407
  • LWG#409
  • LWG#410
  • LWG#411
  • LWG#412
  • LWG#413
  • LWG#414
  • LWG#415
  • LWG#416
  • LWG#419
  • LWG#420
  • LWG#422
  • LWG#425
  • LWG#426
  • LWG#427
  • LWG#428
  • LWG#430
  • LWG#431
  • LWG#432
  • LWG#434
  • LWG#435
  • LWG#436
  • LWG#438
  • LWG#441
  • LWG#442
  • LWG#443
  • LWG#444
  • LWG#445
  • LWG#448
  • LWG#449
  • LWG#453
  • LWG#455
  • LWG#456
  • LWG#457
  • LWG#460
  • LWG#461
  • LWG#464
  • LWG#465
  • LWG#467
  • LWG#468
  • LWG#469
  • LWG#471
  • LWG#473
  • LWG#474
  • LWG#475
  • LWG#478
  • LWG#482
  • LWG#485
  • LWG#488
  • LWG#495
  • LWG#496
  • LWG#497
  • LWG#498
  • LWG#505
  • LWG#507
  • LWG#508
  • LWG#518
  • LWG#519
  • LWG#520
  • LWG#521
  • LWG#522
  • LWG#524
  • LWG#525
  • LWG#527
  • LWG#530
  • LWG#531
  • LWG#533
  • LWG#534
  • LWG#535
  • LWG#537
  • LWG#538
  • LWG#539
  • LWG#540
  • LWG#541
  • LWG#542
  • LWG#543
  • LWG#545
  • LWG#550
  • LWG#551
  • LWG#552
  • LWG#556
  • LWG#559
  • LWG#561
  • LWG#562
  • LWG#563
  • LWG#564
  • LWG#565
  • LWG#566
  • LWG#567
  • LWG#574
  • LWG#575
  • LWG#576
  • LWG#577
  • LWG#578
  • LWG#581
  • LWG#586
  • LWG#589
  • LWG#593
  • LWG#594
  • LWG#595
  • LWG#596
  • LWG#607
  • LWG#608
  • LWG#609
  • LWG#610
  • LWG#611
  • LWG#612
  • LWG#613
  • LWG#616
  • LWG#618
  • LWG#619
  • LWG#620
  • LWG#621
  • LWG#622
  • LWG#623
  • LWG#624
  • LWG#625
  • LWG#628
  • LWG#629
  • LWG#630
  • LWG#634
  • LWG#635
  • LWG#638
  • LWG#640
  • LWG#643
  • LWG#646
  • LWG#650
  • LWG#651
  • LWG#652
  • LWG#654
  • LWG#655
  • LWG#658
  • LWG#659
  • LWG#660
  • LWG#661
  • LWG#664
  • LWG#665
  • LWG#666
  • LWG#671
  • LWG#672
  • LWG#673
  • LWG#674
  • LWG#675
  • LWG#676
  • LWG#677
  • LWG#678
  • LWG#679
  • LWG#680
  • LWG#681
  • LWG#682
  • LWG#685
  • LWG#687
  • LWG#688
  • LWG#689
  • LWG#691
  • LWG#692
  • LWG#693
  • LWG#694
  • LWG#695
  • LWG#696
  • LWG#697
  • LWG#698
  • LWG#699
  • LWG#700
  • LWG#703
  • LWG#704
  • LWG#705
  • LWG#706
  • LWG#709
  • LWG#710
  • LWG#711
  • LWG#712
  • LWG#713
  • LWG#714
  • LWG#715
  • LWG#716
  • LWG#719
  • LWG#720
  • LWG#722
  • LWG#723
  • LWG#724
  • LWG#727
  • LWG#728
  • LWG#732
  • LWG#734
  • LWG#740
  • LWG#742
  • LWG#743
  • LWG#744
  • LWG#746
  • LWG#749
  • LWG#752
  • LWG#753
  • LWG#755
  • LWG#756
  • LWG#758
  • LWG#759
  • LWG#761
  • LWG#762
  • LWG#765
  • LWG#766
  • LWG#767
  • LWG#768
  • LWG#769
  • LWG#770
  • LWG#771
  • LWG#772
  • LWG#774
  • LWG#775
  • LWG#776
  • LWG#777
  • LWG#778
  • LWG#779
  • LWG#780
  • LWG#781
  • LWG#782
  • LWG#783
  • LWG#786
  • LWG#787
  • LWG#788
  • LWG#789
  • LWG#792
  • LWG#793
  • LWG#794
  • LWG#798
  • LWG#800
  • LWG#801
  • LWG#803
  • LWG#804
  • LWG#805
  • LWG#806
  • LWG#807
  • LWG#808
  • LWG#809
  • LWG#810
  • LWG#811
  • LWG#813
  • LWG#814
  • LWG#815
  • LWG#816
  • LWG#817
  • LWG#818
  • LWG#819
  • LWG#820
  • LWG#821
  • LWG#823
  • LWG#824
  • LWG#825
  • LWG#827
  • LWG#828
  • LWG#829
  • LWG#834
  • LWG#835
  • LWG#836
  • LWG#838
  • LWG#842
  • LWG#843
  • LWG#844
  • LWG#845
  • LWG#846
  • LWG#847
  • LWG#848
  • LWG#850
  • LWG#852
  • LWG#853
  • LWG#854
  • LWG#856
  • LWG#857
  • LWG#858
  • LWG#859
  • LWG#860
  • LWG#861
  • LWG#865
  • LWG#866
  • LWG#868
  • LWG#869
  • LWG#870
  • LWG#871
  • LWG#872
  • LWG#874
  • LWG#875
  • LWG#876
  • LWG#878
  • LWG#880
  • LWG#881
  • LWG#882
  • LWG#883
  • LWG#884
  • LWG#885
  • LWG#886
  • LWG#888
  • LWG#889
  • LWG#890
  • LWG#891
  • LWG#893
  • LWG#894
  • LWG#896
  • LWG#897
  • LWG#898
  • LWG#899
  • LWG#900
  • LWG#904
  • LWG#907
  • LWG#908
  • LWG#909
  • LWG#911
  • LWG#920
  • LWG#921
  • LWG#922
  • LWG#923
  • LWG#924
  • LWG#925
  • LWG#929
  • LWG#931
  • LWG#932
  • LWG#934
  • LWG#938
  • LWG#939
  • LWG#940
  • LWG#943
  • LWG#944
  • LWG#947
  • LWG#948
  • LWG#949
  • LWG#950
  • LWG#951
  • LWG#953
  • LWG#954
  • LWG#956
  • LWG#957
  • LWG#958
  • LWG#960
  • LWG#962
  • LWG#963
  • LWG#964
  • LWG#965
  • LWG#966
  • LWG#967
  • LWG#968
  • LWG#970
  • LWG#974
  • LWG#975
  • LWG#976
  • LWG#978
  • LWG#981
  • LWG#982
  • LWG#983
  • LWG#984
  • LWG#985
  • LWG#986
  • LWG#987
  • LWG#990
  • LWG#991
  • LWG#993
  • LWG#994
  • LWG#997
  • LWG#998
  • LWG#999
  • LWG#1004
  • LWG#1006
  • LWG#1011
  • LWG#1012
  • LWG#1014
  • LWG#1019
  • LWG#1021
  • LWG#1030
  • LWG#1033
  • LWG#1034
  • LWG#1037
  • LWG#1038
  • LWG#1039
  • LWG#1040
  • LWG#1043
  • LWG#1044
  • LWG#1045
  • LWG#1046
  • LWG#1047
  • LWG#1048
  • LWG#1049
  • LWG#1050
  • LWG#1054
  • LWG#1055
  • LWG#1065
  • LWG#1066
  • LWG#1070
  • LWG#1071
  • LWG#1073
  • LWG#1075
  • LWG#1079
  • LWG#1088
  • LWG#1089
  • LWG#1090
  • LWG#1093
  • LWG#1094
  • LWG#1095
  • LWG#1097
  • LWG#1098
  • LWG#1100
  • LWG#1103
  • LWG#1104
  • LWG#1106
  • LWG#1108
  • LWG#1110
  • LWG#1113
  • LWG#1114
  • LWG#1116
  • LWG#1117
  • LWG#1118
  • LWG#1122
  • LWG#1123
  • LWG#1126
  • LWG#1129
  • LWG#1130
  • LWG#1131
  • LWG#1133
  • LWG#1134
  • LWG#1135
  • LWG#1136
  • LWG#1137
  • LWG#1138
  • LWG#1143
  • LWG#1144
  • LWG#1145
  • LWG#1146
  • LWG#1147
  • LWG#1151
  • LWG#1152
  • LWG#1157
  • LWG#1158
  • LWG#1159
  • LWG#1160
  • LWG#1161
  • LWG#1162
  • LWG#1163
  • LWG#1165
  • LWG#1166
  • LWG#1170
  • LWG#1171
  • LWG#1172
  • LWG#1174
  • LWG#1177
  • LWG#1178
  • LWG#1180
  • LWG#1181
  • LWG#1182
  • LWG#1183
  • LWG#1185
  • LWG#1187
  • LWG#1189
  • LWG#1191
  • LWG#1192
  • LWG#1193
  • LWG#1194
  • LWG#1195
  • LWG#1196
  • LWG#1197
  • LWG#1198
  • LWG#1199
  • LWG#1204
  • LWG#1205
  • LWG#1206
  • LWG#1207
  • LWG#1208
  • LWG#1209
  • LWG#1210
  • LWG#1211
  • LWG#1212
  • LWG#1215
  • LWG#1216
  • LWG#1218
  • LWG#1220
  • LWG#1221
  • LWG#1222
  • LWG#1225
  • LWG#1226
  • LWG#1227
  • LWG#1229
  • LWG#1231
  • LWG#1234
  • LWG#1237
  • LWG#1240
  • LWG#1241
  • LWG#1244
  • LWG#1245
  • LWG#1247
  • LWG#1248
  • LWG#1249
  • LWG#1250
  • LWG#1252
  • LWG#1253
  • LWG#1254
  • LWG#1255
  • LWG#1256
  • LWG#1257
  • LWG#1258
  • LWG#1260
  • LWG#1261
  • LWG#1262
  • LWG#1264
  • LWG#1266
  • LWG#1267
  • LWG#1268
  • LWG#1269
  • LWG#1270
  • LWG#1271
  • LWG#1272
  • LWG#1273
  • LWG#1274
  • LWG#1275
  • LWG#1276
  • LWG#1277
  • LWG#1278
  • LWG#1279
  • LWG#1280
  • LWG#1281
  • LWG#1283
  • LWG#1284
  • LWG#1285
  • LWG#1286
  • LWG#1287
  • LWG#1288
  • LWG#1290
  • LWG#1291
  • LWG#1292
  • LWG#1293
  • LWG#1294
  • LWG#1295
  • LWG#1297
  • LWG#1298
  • LWG#1299
  • LWG#1300
  • LWG#1303
  • LWG#1304
  • LWG#1305
  • LWG#1306
  • LWG#1307
  • LWG#1309
  • LWG#1310
  • LWG#1311
  • LWG#1312
  • LWG#1316
  • LWG#1319
  • LWG#1321
  • LWG#1322
  • LWG#1323
  • LWG#1324
  • LWG#1325
  • LWG#1326
  • LWG#1327
  • LWG#1328
  • LWG#1329
  • LWG#1332
  • LWG#1333
  • LWG#1334
  • LWG#1335
  • LWG#1337
  • LWG#1338
  • LWG#1339
  • LWG#1340
  • LWG#1344
  • LWG#1345
  • LWG#1346
  • LWG#1347
  • LWG#1349
  • LWG#1353
  • LWG#1354
  • LWG#1355
  • LWG#1356
  • LWG#1357
  • LWG#1360
  • LWG#1362
  • LWG#1363
  • LWG#1364
  • LWG#1365
  • LWG#1366
  • LWG#1367
  • LWG#1368
  • LWG#1370
  • LWG#1372
  • LWG#1377
  • LWG#1378
  • LWG#1379
  • LWG#1380
  • LWG#1381
  • LWG#1382
  • LWG#1383
  • LWG#1384
  • LWG#1385
  • LWG#1386
  • LWG#1387
  • LWG#1388
  • LWG#1389
  • LWG#1390
  • LWG#1391
  • LWG#1392
  • LWG#1393
  • LWG#1394
  • LWG#1397
  • LWG#1399
  • LWG#1400
  • LWG#1401
  • LWG#1402
  • LWG#1403
  • LWG#1404
  • LWG#1405
  • LWG#1407
  • LWG#1408
  • LWG#1409
  • LWG#1410
  • LWG#1412
  • LWG#1414
  • LWG#1416
  • LWG#1417
  • LWG#1418
  • LWG#1420
  • LWG#1421
  • LWG#1423
  • LWG#1424
  • LWG#1425
  • LWG#1426
  • LWG#1427
  • LWG#1428
  • LWG#1429
  • LWG#1430
  • LWG#1431
  • LWG#1432
  • LWG#1435
  • LWG#1436
  • LWG#1437
  • LWG#1438
  • LWG#1439
  • LWG#1440
  • LWG#1441
  • LWG#1445
  • LWG#1447
  • LWG#1448
  • LWG#1449
  • LWG#1453
  • LWG#1455
  • LWG#1457
  • LWG#1460
  • LWG#1462
  • LWG#1464
  • LWG#1465
  • LWG#1466
  • LWG#1467
  • LWG#1468
  • LWG#1469
  • LWG#1474
  • LWG#1478
  • LWG#1479
  • LWG#1480
  • LWG#1481
  • LWG#1482
  • LWG#1487
  • LWG#1490
  • LWG#1491
  • LWG#1492
  • LWG#1494
  • LWG#1497
  • LWG#1498
  • LWG#1501
  • LWG#1502
  • LWG#1504
  • LWG#1505
  • LWG#1507
  • LWG#1508
  • LWG#1513
  • LWG#1514
  • LWG#1515
  • LWG#1516
  • LWG#1517
  • LWG#1518
  • LWG#1519
  • LWG#1520
  • LWG#1522
  • LWG#1523
  • LWG#1524
  • LWG#1525
  • LWG#2000
  • LWG#2001
  • LWG#2002
  • LWG#2004
  • LWG#2007
  • LWG#2008
  • LWG#2014
  • LWG#2017
  • LWG#2019
  • LWG#2020
  • LWG#2022
  • LWG#2023
  • LWG#2024
  • LWG#2025
  • LWG#2027
  • LWG#2029
  • LWG#2030
  • LWG#2031
  • LWG#2032
  • LWG#2034
  • LWG#2037
  • LWG#2041
  • LWG#2042

编译器支持

主条目： C++ 编译器支持

C++11 核心语言功能特性

C++11 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc | HP aCC | Digital Mars C++
C99 预处理器 | N1653 | 4.3 | 是 | 19.0 (2015)* (部分)* 19.26* | 是 | 4.1 | 11.1 | 10.1 | 5.9 | 是 | 8.4 | 2015 | 7.0 | A.06.25 | 是
static_assert | N1720 | 4.3 | 2.9 | 16.0* | 是 | 4.1 | 11.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 | 8.52
右角括号 | N1757 | 4.3 | 是 | 14.0* | 是 | 4.1 | 11.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
扩展的 friend 声明 | N1791 | 4.7 | 2.9 | 16.0* (部分) 18.0* | 是 | 4.1 | 11.1 (部分) 12.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
long long | N1811 | 是 | 是 | 14.0* | 是 | 是 | 是 | 是 | 是 | 是 | 8.4 | 2015 | 7.0 | 是 | 是
类型特征的编译器支持 | N1836 | 4.3 | 3.0 | 14.0* | 是 | 4.0 | 10.0 | 13.1.3 | 5.13 | 是 | 8.4 | 2015 |  | 6.16 |
auto | N1984 | 4.4 | 是 | 16.0* | 是 | 3.9 | 11.0 (v0.9) 12.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
委托构造函数 | N1986 | 4.7 | 3.0 | 18.0* | 是 | 4.7 | 14.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
extern template | N1987 | 3.3 | 是 | 12.0* | 是 | 3.9 | 9.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
constexpr | N2235 | 4.6 | 3.1 | 19.0 (2015)* | 是 | 4.6 | 13.0 (部分) 14.0 | 12.1 (部分) 13.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
模板别名 | N2258 | 4.7 | 3.0 | 18.0* | 是 | 4.2 | 12.1 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
char16_t 与 char32_t | N2249 | 4.4 | 2.9 | 19.0 (2015)* | 是 | 4.4 | 12.1* 14.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 | 8.52
alignas | N2341 | 4.8 | 3.0 | 19.0 (2015)* | 是 | 4.8 | 15.0 | 13.1.2* | 5.13 | 是 | 8.6 | 2015 | 7.0 |  |
alignof | N2341 | 4.5 | 2.9 | 19.0 (2015)* | 是 | 4.8 | 15.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
默认化与被删除的函数 | N2346 | 4.4 | 3.0 | 18.0* | 是 | 4.1 | 12.0 | 13.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
强类型 enum | N2347 | 4.4 | 2.9 | 17.0* | 是 | 4.0 | 13.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
原子操作 | N2427 | 4.4 | 3.1 | 17.0* | 是 | Yes | 13.0 | 13.1.2* | 5.14 | 是 | 8.4 | 2015 |  |  |
nullptr | N2431 | 4.6 | 2.9 | 16.0* | 是 | 4.2 | 12.1 | 13.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 | 8.52
显式转换运算符 | N2437 | 4.5 | 3.0 | 18.0* | 是 | 4.4 | 13.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
引用限定符 | N2439 | 4.8.1 | 2.9 | 19.0 (2015)* | 是 | 4.7 | 14.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
Unicode 字符串字面量 | N2442 | 4.4 | 3.0 | 19.0 (2015)* | 是 | 4.7 | 11.0* | 10.1* 13.1.1* | 5.7 | 是 | 8.4 | 2015 | 7.0 | A.06.28 | 8.52
未处理的字符串字面量 | N2442 | 4.5 | 是 | 18.0* | 是 | 4.7 | 14.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 | 8.52
内联命名空间 | N2535 | 4.4 | 2.9 | 19.0 (2015)* | 是 | 4.5 | 14.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
继承构造函数 | N2540 | 4.8 | 3.3 | 19.0 (2015)* | 是 | 4.8 | 15.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
尾随的函数返回类型 | N2541 | 4.4 | 2.9 | 16.0* | 是 | 4.1 | 12.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
无限制的联合体 | N2544 | 4.6 | 3.0 | 19.0 (2015)* | 是 | 4.6 | 14.0* | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
变参数模板 | N2242 N2555 | 4.3 (N2242) 4.4 | 2.9 | 18.0* | 是 | 4.3 (N2242) 4.3 | 12.1 | 11.1 (N2242) | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
表达式 SFINAE | N2634 | 4.4 | 2.9 | 19.14* | 是 | 4.2 | 12.1 |  |  | 是 | 8.4 | 2015 | 7.0 |  |
局部与无名类型作为模板形参 | N2657 | 4.5 | 2.9 | 16.0* | 是 | 4.2 | 12.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
线程局部存储 | N2659 | 4.4 (部分) 4.8 | 3.3* | 16.0* (部分) 19.0 (2015)* | 是 | 4.8 | 11.1 (部分) 15.0* | 10.1 (部分)* 13.1.2 (部分)* | 5.9 (部分) | 是 | 8.4 | 2015 |  |  | 8.52 (部分)
带并发的动态初始化与析构（魔法静态变量） | N2660 | 4.3 | 2.9 | 19.0 (2015)* | 是 | Yes | 11.1* | 13.1.2* | 5.13 | 是 | 8.4 | 2015 |  | A.06.25 |
垃圾收集与基于可达性的泄漏检测 | N2670 |  |  |  |  |  |  |  |  |  |  |  |  |  |
初始化器列表 | N2672 | 4.4 | 3.1 | 18.0* | 是 | 4.5 | 13.0 (部分) 14.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
非静态数据成员初始化器 | N2756 | 4.7 | 3.0 | 18.0* | 是 | 4.6 | 14.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
属性 | N2761 | 4.8 | 3.3 | 19.0 (2015)* | 是 | 4.2 | 12.1 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
前置 enum 声明 | N2764 | 4.6 | 3.1 | 17.0* | 是 | 4.5 | 11.1 (部分) 14.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
用户定义的字面量 | N2765 | 4.7 | 3.1 | 19.0 (2015)* | 是 | 4.8 | 15.0 | 13.1.2* | 5.14 | 是 | 8.4 | 2015 | 7.0 |  |
右值引用 | N2118 N2844 CWG1138 | 4.3 (N2118) 4.5 | 2.9 | 16.0* (N2844) 17.0* | 是 | 4.5 | 11.1 (N2118) 12.0 (N2844) 14.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0* | A.06.25 |
Lambda 表达式 | N2550 N2658 N2927 | 4.5 | 3.1 | 16.0* (N2658) 17.0* | 是 | 4.1 | 12.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
范围 for 循环 | N2930 | 4.6 | 3.0 | 17.0* | 是 | 4.5 | 13.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
noexcept | N3050 | 4.6 | 3.0 | 19.0 (2015)* | 是 | 4.5 | 14.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
默认化的移动特殊成员 函数 | N3053 | 4.6 | 3.0 | 19.0 (2015)* | 是 | 4.5 | 14.0 |  | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
override 与 final | N2928 N3206 N3272 | 4.7 | 2.9 | 14.0* (部分) 17.0* | 是 | 4.8 | 12.0 (N2928) 14.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
decltype | N2343 N3276 | 4.3 (N2343) 4.8.1 | 2.9 | 16.0* | 是 | 4.2 (N2343) 4.8 | 11.0 (N2343) 12.0 | 11.1 (N2343) | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 | 8.52 (N2343)
C++11 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc | HP aCC | Digital Mars C++

C++11 库功能特性

C++11 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
类型特征 | N1836 | 4.3 | 3.0 | 14.0* | 是 | 5.13 | 是 | 8.4
垃圾收集与基于可达性的泄漏检测（库支持） | N2670 | 6 (无操作) | 3.4 (无操作) | 19.0 (2015)* (无操作) | 是 (无操作) |  |  |
金额、时间及十六进制浮点 I/O 操纵符 | N2071 N2072 | 5 | 3.8 | 19.0 (2015)* | 是 | 5.15 |  |
C++11 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库

* - 在版本号上停留可以查看注记

  • 可运行的 C++11 示例


C++14

< cpp
本节未完成

新语言功能特性

  • 变量模板
  • 泛型 lambda
  • lambda 初始化捕获
  • new/delete 消除
  • constexpr 函数上放松的限制
  • 二进制字面量
  • 数位分隔符
  • 函数的返回类型推导
  • 带默认成员初始化器的聚合类。

新库功能特性

  • std::make_unique
  • std::shared_timed_mutex 与 std::shared_lock
  • std::integer_sequence
  • std::exchange
  • std::quoted
  • 及其他既存库设施的许多小改进，例如
    • 某些算法的双范围重载
    • 类型特征的类型别名版本
    • basic_string、 duration 与 complex 的用户定义字面量
    • 等等
本节未完成

缺陷报告

C++14 中修正的缺陷报告（核心 276 个，库 158 个）
  • CWG#129
  • CWG#223
  • CWG#240
  • CWG#292
  • CWG#312
  • CWG#332
  • CWG#342
  • CWG#344
  • CWG#388
  • CWG#462
  • CWG#482
  • CWG#483
  • CWG#496
  • CWG#535
  • CWG#539
  • CWG#565
  • CWG#577
  • CWG#583
  • CWG#597
  • CWG#616
  • CWG#623
  • CWG#631
  • CWG#675
  • CWG#712
  • CWG#729
  • CWG#739
  • CWG#755
  • CWG#903
  • CWG#912
  • CWG#974
  • CWG#975
  • CWG#977
  • CWG#1003
  • CWG#1013
  • CWG#1024
  • CWG#1048
  • CWG#1059
  • CWG#1093
  • CWG#1213
  • CWG#1226
  • CWG#1227
  • CWG#1250
  • CWG#1251
  • CWG#1260
  • CWG#1261
  • CWG#1262
  • CWG#1264
  • CWG#1265
  • CWG#1267
  • CWG#1268
  • CWG#1269
  • CWG#1270
  • CWG#1275
  • CWG#1282
  • CWG#1287
  • CWG#1288
  • CWG#1290
  • CWG#1293
  • CWG#1295
  • CWG#1296
  • CWG#1297
  • CWG#1298
  • CWG#1301
  • CWG#1302
  • CWG#1305
  • CWG#1306
  • CWG#1307
  • CWG#1308
  • CWG#1310
  • CWG#1311
  • CWG#1312
  • CWG#1313
  • CWG#1318
  • CWG#1320
  • CWG#1321
  • CWG#1324
  • CWG#1327
  • CWG#1328
  • CWG#1329
  • CWG#1330
  • CWG#1333
  • CWG#1336
  • CWG#1340
  • CWG#1344
  • CWG#1345
  • CWG#1346
  • CWG#1347
  • CWG#1350
  • CWG#1352
  • CWG#1354
  • CWG#1355
  • CWG#1357
  • CWG#1358
  • CWG#1359
  • CWG#1361
  • CWG#1362
  • CWG#1363
  • CWG#1364
  • CWG#1365
  • CWG#1366
  • CWG#1367
  • CWG#1368
  • CWG#1369
  • CWG#1370
  • CWG#1372
  • CWG#1374
  • CWG#1375
  • CWG#1376
  • CWG#1380
  • CWG#1381
  • CWG#1382
  • CWG#1383
  • CWG#1385
  • CWG#1387
  • CWG#1388
  • CWG#1392
  • CWG#1394
  • CWG#1398
  • CWG#1399
  • CWG#1401
  • CWG#1402
  • CWG#1405
  • CWG#1406
  • CWG#1408
  • CWG#1409
  • CWG#1410
  • CWG#1411
  • CWG#1412
  • CWG#1413
  • CWG#1415
  • CWG#1416
  • CWG#1417
  • CWG#1418
  • CWG#1423
  • CWG#1424
  • CWG#1425
  • CWG#1428
  • CWG#1431
  • CWG#1435
  • CWG#1437
  • CWG#1438
  • CWG#1439
  • CWG#1440
  • CWG#1441
  • CWG#1442
  • CWG#1447
  • CWG#1449
  • CWG#1450
  • CWG#1453
  • CWG#1454
  • CWG#1455
  • CWG#1456
  • CWG#1457
  • CWG#1458
  • CWG#1460
  • CWG#1462
  • CWG#1464
  • CWG#1466
  • CWG#1471
  • CWG#1472
  • CWG#1473
  • CWG#1475
  • CWG#1476
  • CWG#1477
  • CWG#1479
  • CWG#1480
  • CWG#1481
  • CWG#1482
  • CWG#1487
  • CWG#1489
  • CWG#1491
  • CWG#1493
  • CWG#1494
  • CWG#1495
  • CWG#1502
  • CWG#1503
  • CWG#1504
  • CWG#1506
  • CWG#1507
  • CWG#1508
  • CWG#1509
  • CWG#1510
  • CWG#1511
  • CWG#1512
  • CWG#1514
  • CWG#1515
  • CWG#1516
  • CWG#1522
  • CWG#1527
  • CWG#1528
  • CWG#1531
  • CWG#1532
  • CWG#1533
  • CWG#1535
  • CWG#1537
  • CWG#1538
  • CWG#1539
  • CWG#1541
  • CWG#1543
  • CWG#1544
  • CWG#1550
  • CWG#1551
  • CWG#1553
  • CWG#1556
  • CWG#1557
  • CWG#1559
  • CWG#1560
  • CWG#1562
  • CWG#1563
  • CWG#1567
  • CWG#1569
  • CWG#1570
  • CWG#1575
  • CWG#1576
  • CWG#1579
  • CWG#1583
  • CWG#1587
  • CWG#1588
  • CWG#1592
  • CWG#1593
  • CWG#1595
  • CWG#1597
  • CWG#1598
  • CWG#1601
  • CWG#1604
  • CWG#1605
  • CWG#1607
  • CWG#1608
  • CWG#1611
  • CWG#1612
  • CWG#1613
  • CWG#1618
  • CWG#1629
  • CWG#1648
  • CWG#1649
  • CWG#1658
  • CWG#1660
  • CWG#1662
  • CWG#1664
  • CWG#1666
  • CWG#1669
  • CWG#1673
  • CWG#1674
  • CWG#1681
  • CWG#1684
  • CWG#1687
  • CWG#1689
  • CWG#1690
  • CWG#1691
  • CWG#1692
  • CWG#1693
  • CWG#1707
  • CWG#1716
  • CWG#1717
  • CWG#1732
  • CWG#1737
  • CWG#1738
  • CWG#1739
  • CWG#1740
  • CWG#1741
  • CWG#1746
  • CWG#1747
  • CWG#1759
  • CWG#1760
  • CWG#1762
  • CWG#1764
  • CWG#1765
  • CWG#1767
  • CWG#1769
  • CWG#1770
  • CWG#1772
  • CWG#1773
  • CWG#1775
  • CWG#1778
  • CWG#1786
  • CWG#1787
  • LWG#1214
  • LWG#1450
  • LWG#2003
  • LWG#2005
  • LWG#2009
  • LWG#2010
  • LWG#2011
  • LWG#2012
  • LWG#2013
  • LWG#2015
  • LWG#2018
  • LWG#2021
  • LWG#2028
  • LWG#2033
  • LWG#2039
  • LWG#2044
  • LWG#2045
  • LWG#2047
  • LWG#2048
  • LWG#2049
  • LWG#2050
  • LWG#2052
  • LWG#2054
  • LWG#2053
  • LWG#2056
  • LWG#2057
  • LWG#2058
  • LWG#2061
  • LWG#2064
  • LWG#2065
  • LWG#2066
  • LWG#2067
  • LWG#2069
  • LWG#2071
  • LWG#2074
  • LWG#2075
  • LWG#2078
  • LWG#2080
  • LWG#2081
  • LWG#2083
  • LWG#2085
  • LWG#2086
  • LWG#2087
  • LWG#2091
  • LWG#2092
  • LWG#2093
  • LWG#2094
  • LWG#2096
  • LWG#2097
  • LWG#2098
  • LWG#2099
  • LWG#2100
  • LWG#2102
  • LWG#2103
  • LWG#2104
  • LWG#2105
  • LWG#2109
  • LWG#2110
  • LWG#2112
  • LWG#2120
  • LWG#2122
  • LWG#2123
  • LWG#2128
  • LWG#2130
  • LWG#2132
  • LWG#2135
  • LWG#2138
  • LWG#2140
  • LWG#2141
  • LWG#2142
  • LWG#2143
  • LWG#2144
  • LWG#2145
  • LWG#2147
  • LWG#2148
  • LWG#2149
  • LWG#2150
  • LWG#2159
  • LWG#2162
  • LWG#2163
  • LWG#2165
  • LWG#2169
  • LWG#2172
  • LWG#2174
  • LWG#2175
  • LWG#2176
  • LWG#2177
  • LWG#2180
  • LWG#2182
  • LWG#2185
  • LWG#2186
  • LWG#2187
  • LWG#2188
  • LWG#2190
  • LWG#2193
  • LWG#2194
  • LWG#2196
  • LWG#2197
  • LWG#2200
  • LWG#2203
  • LWG#2205
  • LWG#2207
  • LWG#2209
  • LWG#2210
  • LWG#2211
  • LWG#2213
  • LWG#2222
  • LWG#2225
  • LWG#2229
  • LWG#2231
  • LWG#2235
  • LWG#2240
  • LWG#2246
  • LWG#2247
  • LWG#2249
  • LWG#2252
  • LWG#2257
  • LWG#2258
  • LWG#2263
  • LWG#2268
  • LWG#2271
  • LWG#2272
  • LWG#2275
  • LWG#2278
  • LWG#2280
  • LWG#2284
  • LWG#2285
  • LWG#2288
  • LWG#2291
  • LWG#2293
  • LWG#2298
  • LWG#2299
  • LWG#2300
  • LWG#2301
  • LWG#2304
  • LWG#2306
  • LWG#2308
  • LWG#2313
  • LWG#2314
  • LWG#2315
  • LWG#2316
  • LWG#2317
  • LWG#2320
  • LWG#2322
  • LWG#2323
  • LWG#2324
  • LWG#2329
  • LWG#2330
  • LWG#2332
  • LWG#2339
  • LWG#2341
  • LWG#2344
  • LWG#2346
  • LWG#2350
  • LWG#2356
  • LWG#2357
  • LWG#2359
  • LWG#2360

编译器支持

主条目： C++ 编译器支持

C++14 核心语言功能特性

C++14 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc
按语境转换的遣词调整 | N3323 | 4.9 | 3.4 | 18.0* | 是 | 4.9 | 16.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 16.1 | 9.0
二进制字面量 | N3472 | 4.3 (GNU) 4.9 | 2.9 | 19.0 (2015)* | 是 | 4.10 | 11.0 | 13.1.2* | 5.14 | 10.3 | 8.6 | 2015 | 9.0
decltype(auto)，普通函数的返回类型推导 | N3638 | 4.8 (部分)* 4.9 | 是 | 19.0 (2015)* | 是 | 4.9 | 15.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 16.1 | 9.0
带初始化/泛化的 lambda 捕获 (init-capture) | N3648 | 4.5 (部分) 4.9 | 3.4 | 19.0 (2015)* | 是 | 4.10 | 15.0 | 16.1.1* | 5.15 | 10.3 | 8.6 | 16.1 | 9.0
泛型 lambda 表达式 | N3649 | 4.9 | 3.4 | 19.0 (2015)* | 是 | 4.10 | 16.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 16.1 | 9.0
变量模板 | N3651 | 5 | 3.4 | 19.0 (Update 2)* | 是 | 4.11 | 17.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 17.4 | 9.0
扩展的 constexpr | N3652 | 5 | 3.4 | 19.10* | 是 | 4.11 | 17.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 17.4 | 9.0
带成员初始化器的聚合体 (NSDMI) | N3653 | 5 | 3.3 | 19.10* | 是 | 4.9 | 16.0 | 16.1.1* | 5.14 | 10.3 | 8.6 | 16.1 | 9.0
忽略/扩展内存分配 | N3664 | N/A | 3.4 | N/A | 是 | N/A | N/A | N/A | N/A | 10.3 | 8.6 | 17.4 | N/A
[[deprecated]] 属性 | N3760 | 4.9 | 3.4 | 19.0 (2015)* | 是 | 4.9 | 15.0* 16.0 | 13.1.2* | 5.14 | 10.3 | 8.6 | 16.1 | 9.0
具大小解分配 | N3778 | 5 | 3.4 | 19.0 (2015)* | 是 | 4.10.1 | 17.0 | 16.1.1* | 5.14 | 10.3 | 8.6 | 16.1 |
单引号作为数位分隔符 | N3781 | 4.9 | 3.4 | 19.0 (2015)* | 是 | 4.10 | 16.0 | 13.1.2* | 5.14 | 10.3 | 8.6 | 2015 | 9.0
C++14 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc

C++14 库功能特性

C++14 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
<complex> 的 constexpr | N3302 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
通透的运算符函数对象 | N3421 | 4.9 | 3.4 | 18.0* | 是 | 5.15 | 10.3 | 8.6
std::result_of 与 SFINAE | N3462 | 5 | 是 | 19.0 (Update 2)* | 是 | 5.15 | 10.3 | 8.6
<chrono> 的 constexpr | N3469 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
<array> 的 constexpr | N3470 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
<initializer_list> 、 <utility> 和 <tuple> 的 constexpr | N3471 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
改进的 std::integral_constant | N3545 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
<chrono> 和 <string> 的用户定义字面量 | N3642 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
空向前迭代器 | N3644 | 5 (部分) | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::quoted | N3654 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::make_unique | N3656 | 4.9 | 3.4 | 18.0* | 是 | 5.15 | 10.3 | 8.6
异质关联查找 | N3657 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::integer_sequence | N3658 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::shared_timed_mutex | N3659 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::exchange | N3668 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
修正无 const 的 constexpr 成员函数 | N3669 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::get<T>() | N3670 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
双范围的 std::equal 、 std::is_permutation 、 std::mismatch | N3671 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
C++14 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库

* - 在版本号上停留可以查看注记

  • 可运行的 c++14 示例


C++17

< cpp
本节未完成

以下特性已被合入 C++17 中：

  1. 从技术规范中：文件系统库、库基础 v1 （包括 optional 、 any 、 basic_string_view 、多态分配器、搜索器、 apply）。并行库 v1 (包括 执行策略、 reduce 、 inclusive_scan 、 exclusive_scan)，但不包括 exception_list 。从特殊数学函数 IS 中：数学特殊函数。从库基础 v2 中： std::gcd 、 std::lcm 。
  2. 从 C11 中：std::aligned_alloc 、 std::timespec_get

过时

移除

auto_ptr 、 之前已被声明弃用的函数对象、 std::random_shuffle 、 std::unexpected 、 过时的 iostream 别名、 三标符、 register 关键字, bool 类型的自增操作

弃用

std::iterator 、 std::raw_storage_iterator 、 std::get_temporary_buffer 、 std::is_literal_type 、 std::result_of 、 整个 <codecvt> 头文件

新的语言特性

  • 折叠表达式
  • 类模板实参推导
  • auto 占位的非类型模板形参
  • 编译期的 constexpr if 语句
  • inline 变量
  • 结构化绑定
  • if 和 switch 语句中的初始化器
  • u8-char
  • 简化的嵌套命名空间
  • using 声明语句可以声明多个名称
  • 将 noexcept 作为类型系统的一部分
  • 新的求值顺序规则
  • 强制的复制消除
  • lambda 表达式捕获 *this
  • constexpr 的 lambda 表达式
  • 属性命名空间不必重复
  • 新属性 [[fallthrough]] [[nodiscard]] 和 [[maybe_unused]]
  • __has_include

新的头文件

  • <any>
  • <optional>
  • <variant>
  • <memory_resource>
  • <string_view>
  • <charconv>
  • <execution>
  • <filesystem>

新的库特性

工具类型

  • tuple ：
    • apply
    • deduction_guides
    • make_from_tuple
  • variant
  • as_const
  • searchers
  • optional
  • any
  • not_fn

内存管理

  • 未初始化内存算法
    • destroy_at
    • destroy
    • destroy_n
    • uninitialized_move
    • uninitialized_value_construct

  • weak_from_this
  • memory_resource 与 polymorphic_allocator
  • aligned_alloc
  • 通透的 owner_less
  • shared_ptr 的数组支持
  • 带有显式对齐的分配函数

编译时编程

  • byte
  • conjunction/disjunction/negation
  • 类型特征变量模板（xxx_v）
  • is_swappable
  • is_invocable
  • is_aggregate
  • has_unique_object_representations

算法

  • clamp
  • 并行算法与执行策略
  • reduce
  • inclusive_scan
  • exclusive_scan
  • gcd
  • lcm

迭代器与容器

  • map/set extract 与 map/set merge
  • map/unordered_map try_emplace 与 insert_or_assign
  • 连续迭代器
  • 非成员 size/empty/data

数值

  • 数学特殊函数
  • 三维 hypot

其他

  • launder
  • to_chars/from_chars
  • is_always_lock_free
  • scoped_lock
  • 缓存线接口
  • uncaught_exceptions
  • timespec_get
  • duration 与 time_point 的取整函数

缺陷报告

C++17 中修正的缺陷报告（核心 290 个，库 363 个）
  • CWG#92
  • CWG#150
  • CWG#212
  • CWG#238
  • CWG#242
  • CWG#253
  • CWG#314
  • CWG#330
  • CWG#343
  • CWG#393
  • CWG#426
  • CWG#591
  • CWG#609
  • CWG#636
  • CWG#727
  • CWG#987
  • CWG#1021
  • CWG#1116
  • CWG#1247
  • CWG#1274
  • CWG#1284
  • CWG#1292
  • CWG#1309
  • CWG#1315
  • CWG#1338
  • CWG#1343
  • CWG#1351
  • CWG#1356
  • CWG#1391
  • CWG#1395
  • CWG#1397
  • CWG#1446
  • CWG#1465
  • CWG#1467
  • CWG#1484
  • CWG#1490
  • CWG#1492
  • CWG#1496
  • CWG#1518
  • CWG#1552
  • CWG#1558
  • CWG#1561
  • CWG#1571
  • CWG#1572
  • CWG#1573
  • CWG#1589
  • CWG#1591
  • CWG#1596
  • CWG#1600
  • CWG#1603
  • CWG#1614
  • CWG#1615
  • CWG#1622
  • CWG#1630
  • CWG#1631
  • CWG#1633
  • CWG#1638
  • CWG#1639
  • CWG#1645
  • CWG#1652
  • CWG#1653
  • CWG#1657
  • CWG#1672
  • CWG#1677
  • CWG#1683
  • CWG#1686
  • CWG#1694
  • CWG#1696
  • CWG#1705
  • CWG#1708
  • CWG#1710
  • CWG#1712
  • CWG#1715
  • CWG#1719
  • CWG#1722
  • CWG#1734
  • CWG#1736
  • CWG#1744
  • CWG#1748
  • CWG#1750
  • CWG#1751
  • CWG#1752
  • CWG#1753
  • CWG#1756
  • CWG#1757
  • CWG#1758
  • CWG#1766
  • CWG#1774
  • CWG#1776
  • CWG#1777
  • CWG#1779
  • CWG#1780
  • CWG#1782
  • CWG#1784
  • CWG#1788
  • CWG#1791
  • CWG#1793
  • CWG#1794
  • CWG#1795
  • CWG#1796
  • CWG#1797
  • CWG#1799
  • CWG#1800
  • CWG#1802
  • CWG#1804
  • CWG#1805
  • CWG#1806
  • CWG#1807
  • CWG#1809
  • CWG#1810
  • CWG#1811
  • CWG#1812
  • CWG#1813
  • CWG#1814
  • CWG#1815
  • CWG#1816
  • CWG#1819
  • CWG#1823
  • CWG#1824
  • CWG#1825
  • CWG#1830
  • CWG#1832
  • CWG#1834
  • CWG#1838
  • CWG#1843
  • CWG#1846
  • CWG#1847
  • CWG#1848
  • CWG#1850
  • CWG#1851
  • CWG#1852
  • CWG#1858
  • CWG#1860
  • CWG#1861
  • CWG#1863
  • CWG#1865
  • CWG#1866
  • CWG#1870
  • CWG#1872
  • CWG#1873
  • CWG#1874
  • CWG#1875
  • CWG#1877
  • CWG#1878
  • CWG#1881
  • CWG#1882
  • CWG#1885
  • CWG#1886
  • CWG#1887
  • CWG#1888
  • CWG#1891
  • CWG#1892
  • CWG#1895
  • CWG#1899
  • CWG#1902
  • CWG#1903
  • CWG#1909
  • CWG#1911
  • CWG#1916
  • CWG#1920
  • CWG#1922
  • CWG#1925
  • CWG#1926
  • CWG#1929
  • CWG#1930
  • CWG#1932
  • CWG#1940
  • CWG#1941
  • CWG#1942
  • CWG#1946
  • CWG#1949
  • CWG#1951
  • CWG#1952
  • CWG#1955
  • CWG#1956
  • CWG#1958
  • CWG#1959
  • CWG#1961
  • CWG#1963
  • CWG#1966
  • CWG#1967
  • CWG#1971
  • CWG#1975
  • CWG#1978
  • CWG#1981
  • CWG#1988
  • CWG#1990
  • CWG#1991
  • CWG#1992
  • CWG#1995
  • CWG#1999
  • CWG#2000
  • CWG#2001
  • CWG#2004
  • CWG#2006
  • CWG#2008
  • CWG#2010
  • CWG#2011
  • CWG#2012
  • CWG#2015
  • CWG#2016
  • CWG#2017
  • CWG#2019
  • CWG#2022
  • CWG#2024
  • CWG#2026
  • CWG#2027
  • CWG#2031
  • CWG#2032
  • CWG#2033
  • CWG#2038
  • CWG#2039
  • CWG#2040
  • CWG#2041
  • CWG#2044
  • CWG#2046
  • CWG#2047
  • CWG#2052
  • CWG#2061
  • CWG#2063
  • CWG#2064
  • CWG#2066
  • CWG#2068
  • CWG#2069
  • CWG#2071
  • CWG#2075
  • CWG#2076
  • CWG#2079
  • CWG#2082
  • CWG#2084
  • CWG#2085
  • CWG#2091
  • CWG#2093
  • CWG#2094
  • CWG#2095
  • CWG#2096
  • CWG#2098
  • CWG#2099
  • CWG#2100
  • CWG#2101
  • CWG#2104
  • CWG#2106
  • CWG#2107
  • CWG#2109
  • CWG#2113
  • CWG#2120
  • CWG#2122
  • CWG#2124
  • CWG#2129
  • CWG#2130
  • CWG#2137
  • CWG#2140
  • CWG#2141
  • CWG#2143
  • CWG#2145
  • CWG#2146
  • CWG#2147
  • CWG#2153
  • CWG#2154
  • CWG#2155
  • CWG#2156
  • CWG#2157
  • CWG#2163
  • CWG#2167
  • CWG#2171
  • CWG#2174
  • CWG#2175
  • CWG#2176
  • CWG#2180
  • CWG#2184
  • CWG#2191
  • CWG#2196
  • CWG#2198
  • CWG#2201
  • CWG#2205
  • CWG#2206
  • CWG#2211
  • CWG#2214
  • CWG#2218
  • CWG#2220
  • CWG#2224
  • CWG#2247
  • CWG#2248
  • CWG#2251
  • CWG#2259
  • CWG#2262
  • CWG#2268
  • CWG#2271
  • CWG#2272
  • CWG#2276
  • #LWG839
  • #LWG1041
  • #LWG1150
  • #LWG1169
  • #LWG1201
  • #LWG1526
  • #LWG2016
  • #LWG2051
  • #LWG2059
  • #LWG2062
  • #LWG2063
  • #LWG2072
  • #LWG2076
  • #LWG2101
  • #LWG2106
  • #LWG2108
  • #LWG2111
  • #LWG2118
  • #LWG2119
  • #LWG2127
  • #LWG2129
  • #LWG2133
  • #LWG2156
  • #LWG2160
  • #LWG2166
  • #LWG2168
  • #LWG2170
  • #LWG2179
  • #LWG2181
  • #LWG2192
  • #LWG2208
  • #LWG2212
  • #LWG2217
  • #LWG2218
  • #LWG2219
  • #LWG2221
  • #LWG2223
  • #LWG2224
  • #LWG2228
  • #LWG2230
  • #LWG2232
  • #LWG2233
  • #LWG2234
  • #LWG2239
  • #LWG2241
  • #LWG2244
  • #LWG2245
  • #LWG2250
  • #LWG2259
  • #LWG2260
  • #LWG2261
  • #LWG2266
  • #LWG2273
  • #LWG2274
  • #LWG2276
  • #LWG2294
  • #LWG2296
  • #LWG2309
  • #LWG2310
  • #LWG2312
  • #LWG2325
  • #LWG2328
  • #LWG2336
  • #LWG2340
  • #LWG2343
  • #LWG2353
  • #LWG2354
  • #LWG2361
  • #LWG2364
  • #LWG2365
  • #LWG2367
  • #LWG2368
  • #LWG2369
  • #LWG2370
  • #LWG2376
  • #LWG2377
  • #LWG2378
  • #LWG2380
  • #LWG2384
  • #LWG2385
  • #LWG2387
  • #LWG2391
  • #LWG2393
  • #LWG2394
  • #LWG2396
  • #LWG2397
  • #LWG2399
  • #LWG2400
  • #LWG2401
  • #LWG2403
  • #LWG2404
  • #LWG2406
  • #LWG2407
  • #LWG2408
  • #LWG2411
  • #LWG2415
  • #LWG2419
  • #LWG2420
  • #LWG2422
  • #LWG2424
  • #LWG2425
  • #LWG2426
  • #LWG2427
  • #LWG2428
  • #LWG2433
  • #LWG2434
  • #LWG2435
  • #LWG2436
  • #LWG2437
  • #LWG2438
  • #LWG2439
  • #LWG2440
  • #LWG2441
  • #LWG2442
  • #LWG2443
  • #LWG2445
  • #LWG2447
  • #LWG2448
  • #LWG2450
  • #LWG2454
  • #LWG2455
  • #LWG2456
  • #LWG2458
  • #LWG2459
  • #LWG2460
  • #LWG2462
  • #LWG2464
  • #LWG2465
  • #LWG2466
  • #LWG2467
  • #LWG2468
  • #LWG2469
  • #LWG2470
  • #LWG2473
  • #LWG2475
  • #LWG2476
  • #LWG2477
  • #LWG2482
  • #LWG2483
  • #LWG2484
  • #LWG2485
  • #LWG2486
  • #LWG2487
  • #LWG2488
  • #LWG2489
  • #LWG2492
  • #LWG2495
  • #LWG2501
  • #LWG2502
  • #LWG2503
  • #LWG2505
  • #LWG2510
  • #LWG2514
  • #LWG2519
  • #LWG2520
  • #LWG2523
  • #LWG2529
  • #LWG2531
  • #LWG2534
  • #LWG2536
  • #LWG2537
  • #LWG2540
  • #LWG2542
  • #LWG2543
  • #LWG2544
  • #LWG2545
  • #LWG2548
  • #LWG2549
  • #LWG2550
  • #LWG2554
  • #LWG2556
  • #LWG2557
  • #LWG2559
  • #LWG2560
  • #LWG2562
  • #LWG2565
  • #LWG2566
  • #LWG2567
  • #LWG2569
  • #LWG2571
  • #LWG2572
  • #LWG2576
  • #LWG2577
  • #LWG2578
  • #LWG2579
  • #LWG2581
  • #LWG2582
  • #LWG2583
  • #LWG2584
  • #LWG2585
  • #LWG2586
  • #LWG2587
  • #LWG2589
  • #LWG2590
  • #LWG2591
  • #LWG2596
  • #LWG2598
  • #LWG2663
  • #LWG2664
  • #LWG2665
  • #LWG2667
  • #LWG2669
  • #LWG2670
  • #LWG2671
  • #LWG2672
  • #LWG2673
  • #LWG2674
  • #LWG2676
  • #LWG2677
  • #LWG2678
  • #LWG2679
  • #LWG2680
  • #LWG2681
  • #LWG2683
  • #LWG2684
  • #LWG2685
  • #LWG2686
  • #LWG2687
  • #LWG2688
  • #LWG2689
  • #LWG2694
  • #LWG2696
  • #LWG2698
  • #LWG2699
  • #LWG2704
  • #LWG2706
  • #LWG2707
  • #LWG2709
  • #LWG2710
  • #LWG2711
  • #LWG2712
  • #LWG2715
  • #LWG2716
  • #LWG2718
  • #LWG2719
  • #LWG2720
  • #LWG2721
  • #LWG2722
  • #LWG2723
  • #LWG2724
  • #LWG2725
  • #LWG2726
  • #LWG2727
  • #LWG2728
  • #LWG2729
  • #LWG2732
  • #LWG2734
  • #LWG2735
  • #LWG2736
  • #LWG2738
  • #LWG2739
  • #LWG2740
  • #LWG2742
  • #LWG2744
  • #LWG2747
  • #LWG2748
  • #LWG2749
  • #LWG2752
  • #LWG2753
  • #LWG2754
  • #LWG2755
  • #LWG2756
  • #LWG2757
  • #LWG2758
  • #LWG2759
  • #LWG2760
  • #LWG2763
  • #LWG2765
  • #LWG2767
  • #LWG2768
  • #LWG2769
  • #LWG2770
  • #LWG2771
  • #LWG2773
  • #LWG2776
  • #LWG2777
  • #LWG2778
  • #LWG2781
  • #LWG2782
  • #LWG2784
  • #LWG2785
  • #LWG2786
  • #LWG2787
  • #LWG2788
  • #LWG2789
  • #LWG2790
  • #LWG2791
  • #LWG2793
  • #LWG2794
  • #LWG2795
  • #LWG2796
  • #LWG2798
  • #LWG2799
  • #LWG2801
  • #LWG2802
  • #LWG2803
  • #LWG2804
  • #LWG2805
  • #LWG2806
  • #LWG2807
  • #LWG2809
  • #LWG2810
  • #LWG2812
  • #LWG2817
  • #LWG2824
  • #LWG2825
  • #LWG2826
  • #LWG2830
  • #LWG2834
  • #LWG2835
  • #LWG2837
  • #LWG2838
  • #LWG2842
  • #LWG2850
  • #LWG2853
  • #LWG2855
  • #LWG2857
  • #LWG2861
  • #LWG2862
  • #LWG2863
  • #LWG2864
  • #LWG2866
  • #LWG2867
  • #LWG2868
  • #LWG2869
  • #LWG2872
  • #LWG2873
  • #LWG2874
  • #LWG2875
  • #LWG2876
  • #LWG2877
  • #LWG2878
  • #LWG2879
  • #LWG2880
  • #LWG2882
  • #LWG2887
  • #LWG2888
  • #LWG2889
  • #LWG2890
  • #LWG2895
  • #LWG2900
  • #LWG2901
  • #LWG2903
  • #LWG2904
  • #LWG2905
  • #LWG2908
  • #LWG2911
  • #LWG2912
  • #LWG2913
  • #LWG2914
  • #LWG2915
  • #LWG2917
  • #LWG2918
  • #LWG2919
  • #LWG2920
  • #LWG2921
  • #LWG2924
  • #LWG2925
  • #LWG2926
  • #LWG2927
  • #LWG2928
  • #LWG2934
  • #LWG2956

编译器支持

主条目： C++ 编译器支持

C++17 核心语言功能特性

C++17 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc
直接列表初始化的新 auto 规则 | N3922 | 5 | 3.8 | 19.0 (2015)* | 是 | 4.10.1 | 17.0 |  |  | 10.3 |  | 17.7 |
无消息的 static_assert | N3928 | 6 | 2.5 | 19.10* | 是 | 4.12 | 18.0 |  |  | 10.3 |  | 17.7 |
模板模板形参中的 typename | N4051 | 5 | 3.5 | 19.0 (2015)* | 是 | 4.10.1 | 17.0 |  |  | 10.3 |  | 17.7 |
移除三标符 | N4086 | 5 | 3.5 | 16.0* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
嵌套命名空间定义 | N4230 | 6 | 3.6 | 19.0 (Update 3)* | 是 | 4.12 | 17.0 |  |  | 10.3 |  | 17.7 |
命名空间和枚举项的属性 | N4266 | 4.9 (部分)* 6 | 3.6 | 19.0 (2015)* | 是 | 4.11 | 17.0 |  |  | 10.3 |  | 17.7 |
u8 字符字面量 | N4267 | 6 | 3.6 | 19.0 (2015)* | 是 | 4.11 | 17.0 |  |  | 10.3 |  | 17.7 |
允许所有非类型模板实参的常量求值 | N4268 | 6 | 3.6 | 19.12* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
折叠表达式 | N4295 | 6 | 3.6 | 19.12* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
一元折叠表达式和空形参包 | P0036R0 | 6 | 3.9 | 19.12* | 是 | 4.14 |  |  |  | 10.3 |  |  |
移除 register 关键字的已弃用用法 | P0001R1 | 7 | 3.8 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
移除已弃用的 operator++(bool) | P0002R1 | 7 | 3.8 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
令异常规定为类型系统的一部分 | P0012R1 | 7 | 4 | 19.12* | 是 | 4.14 | 19.0 |  |  | 10.3 |  |  |
有基类的类的聚合初始化 | P0017R1 | 7 | 3.9 | 19.14* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
预处理器条件中的 __has_include | P0061R1 | 5 | 是 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
DR ：继承构造函数的新规定 (DR1941 等) | P0136R1 | 7 | 3.9 | 19.14* | 是 | 6.1 |  |  |  | 10.3 |  | 19.1 |
*this 的 lambda 捕获 | P0018R3 | 7 | 3.9 | 19.11* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
枚举的直接列表初始化 | P0138R2 | 7 | 3.9 | 19.11* | 是 | 4.14 | 18.0 |  |  | 10.3 |  |  |
constexpr lambda 表达式 | P0170R1 | 7 | 5 | 19.11* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
基于范围 for 的相异 begin 和 end 类型 | P0184R0 | 6 | 3.9 | 19.10* | 是 | 4.12 | 18.0 |  |  | 10.3 |  | 17.7 |
[[fallthrough]] 属性 | P0188R1 | 7 | 3.9 | 19.10* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
[[nodiscard]] 属性 | P0189R1 | 7 | 3.9 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
[[maybe_unused]] 属性 | P0212R1 | 7 | 3.9 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
十六进制浮点字面量 | P0245R1 | 3.0 | 是 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
使用属性命名空间而不重复 | P0028R4 | 7 | 3.9 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
过对齐数据的动态内存分配 | P0035R4 | 7 | 4 | 19.12* | 10.0.0* | 4.14 |  |  |  | 10.3 |  |  |
类模板实参推导 | P0091R3 | 7 | 5 | 19.14* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  | 19.1 |
具有 auto 类型的非类型模板形参 | P0127R2 | 7 | 4 | 19.14* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  | 19.1 |
受保证的复制消除 | P0135R1 | 7 | 4 | 19.13* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  | 19.1 |
替换含引用成员的类对象 | P0137R1 | 7 | 6 | 19.14* | 是 | 5.0 |  |  |  | 10.3 |  |  |
更严格的表达式求值顺序 | P0145R3 | 7 | 4 | 19.14* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
结构化绑定 | P0217R3 | 7 | 4 | 19.11* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
忽略未知属性 | P0283R2 | 是 | 3.9 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
constexpr if 语句 | P0292R2 | 7 | 3.9 | 19.11* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
if 和 switch 的初始化语句 | P0305R1 | 7 | 3.9 | 19.11* | 是 | 4.14 | 18.0 |  |  | 10.3 |  | 18.1 |
inline 变量 | P0386R2 | 7 | 3.9 | 19.12* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
移除动态异常说明 | P0003R5 | 7 | 4 | 19.10* | 是 | 4.14 | 19.0 |  |  | 10.3 |  |  |
using 声明中的包展开 | P0195R2 | 7 | 4 | 19.14* | 是 | 5.0 |  |  |  | 10.3 |  |  |
DR ：模板模板实参的匹配排除了兼容的模板 | P0522R0 | 7 | 4 | 19.12* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
C++17 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc

C++17 库功能特性

C++17 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Intel 并行 STL | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
std::void_t | N3911 | 6 | 3.6 | 19.0 (2015)* | 是 | N/A |  | 10.3 |
std::uncaught_exceptions() | N4259 | 6 | 3.7 | 19.0 (2015)* | 是 | N/A |  | 10.3 |
std::size() 、 std::empty() 与 std::data() | N4280 | 6 | 3.6 | 19.0 (2015)* | 是 | N/A |  | 10.3 |
改进 std::pair 与 std::tuple | N4387 | 6 | 4 | 19.0 (Update 2)* | 是 | N/A |  | 10.3 |
std::bool_constant | N4389 | 6 | 3.7 | 19.0 (2015)* | 是 | N/A |  | 10.3 |
std::shared_mutex （无时限） | N4508 | 6 | 3.7 | 19.0 (Update 2)* | 是 | N/A |  | 10.3 |
类型特性变量模板 | P0006R0 | 7 | 3.8 | 19.0 (Update 2)* | 是 | N/A |  | 10.3 |
逻辑运算符类型特性 | P0013R1 | 6 | 3.8 | 19.0 (Update 2)* | 是 | N/A |  | 10.3 |
标准化并行 TS | P0024R2 | 9* |  | 19.14* |  | 18.0* |  |  |
std::clamp() | P0025R0 | 7 | 3.9 | 19.0 (Update 3)* | 10.0.0* | N/A |  | 10.3 |
硬件干涉大小 | P0154R1 |  |  | 19.11* |  | N/A |  |  |
(nothrow-)swappable 特性 | P0185R1 | 7 | 3.9 | 19.0 (Update 3)* | 10.0.0* | N/A |  | 10.3 |
文件系统库 | P0218R1 | 8 | 7 | 19.14* | 11.0.0* | N/A |  | 10.3 |
std::string_view | N3921 P0220R1 | 7 | 4 | 19.10* | 10.0.0* | N/A |  | 10.3 |
std::any | P0220R1 | 7 | 4 | 19.10* | 10.0.0* | N/A |  | 10.3 |
std::optional | P0220R1 | 7 | 4 | 19.10* | 10.0.0* | N/A |  | 10.3 |
多态内存资源 | P0220R1 | 9 |  | 19.13* |  | N/A |  | 10.3 |
数学特殊函数 | P0226R1 | 7 |  | 19.14* |  | N/A |  | 10.3 |
C++17 应指代 C11 而非 C99 | P0063R3 | 9 | 7 | 19.0 (2015)* (部分)* |  | N/A |  | 10.3 |
接合 map 与 set | P0083R3 | 7 | 8 | 19.12* | 10.0.0* | N/A |  |  |
std::variant | P0088R3 | 7 | 4 | 19.10* | 10.0.0* | N/A |  | 10.3 |
std::make_from_tuple() | P0209R2 | 7 | 3.9 | 19.10* | 是 | N/A |  | 10.3 |
std::has_unique_object_representations | P0258R2 | 7 | 6 | 19.11* | 是 | N/A |  | 10.3 |
std::gcd() 与 std::lcm() | P0295R0 | 7 | 4 | 19.11* | 是 | N/A |  | 10.3 |
std::not_fn | P0005R4 P0358R1 | 7 | 3.9 | 19.12* |  | N/A |  | 10.3 |
初等字符串转换 | P0067R5 | 8 (无浮点) | 7 (无浮点) | 19.14* (无浮点)* 19.24* |  | N/A |  |  |
有数组支持的 std::shared_ptr 与 std::weak_ptr | P0414R2 | 7 | 11 | 19.12* |  | N/A |  | 10.3 |
std::scoped_lock | P0156R2 | 7 | 5 | 19.11* | 是 | N/A |  | 10.3 |
std::byte | P0298R3 | 7 | 5 | 19.11* | 是 | N/A |  | 10.3 |
std::is_aggregate | LWG2911 | 7 | 5 | 19.15* | 是 | N/A |  | 10.3 |
C++17 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Intel 并行 STL | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库

* - 在版本号上停留可以查看注记

  • C++17 可行样例


C++20

< cpp

C++ 标准的下一主要修订版

本节未完成

新的语言特性

  • 特性测试宏
  • 三路比较运算符 <=> 和 operator==() = default
  • 指派初始化器
  • 范围 for 中的初始化语句和初始化器
  • char8_t
  • [[no_unique_address]]
  • [[likely]]
  • [[unlikely]]
  • lambda 初始化捕获中的包展开
  • 移除了在多种上下文语境中，使用 typename 关键字以消除类型歧义的要求
  • consteval 、 constinit
  • 更为宽松的 constexpr 要求
  • 规定有符号整数以补码实现
  • 使用圆括号的聚合初始化
  • 协程
  • 模块
  • 限定与概念
  • 缩略函数模板
  • DR ：数组 new 可推导数组长度

新的库特性

新的头文件

  • <concepts>
  • <coroutine>
  • <compare>
  • <version>
  • <source_location>
  • <format>
  • <span>
  • <ranges>
  • <bit>
  • <numbers>
  • <syncstream>

线程支持库中：

  • <stop_token>
  • <semaphore>
  • <latch>
  • <barrier>

库特性

  • 库特性测试宏
  • 格式化库
  • 日历和时区库
  • std::source_location
  • std::span
  • std::endian
  • 针对数组的 std::make_shared 支持
  • std::remove_cvref
  • std::to_address
  • 浮点类型和 shared_ptr 的原子对象
  • std::barrier 、 std::latch 和 std::counting_semaphore
  • std::jthread 和线程取消类
  • std::osyncstream
  • std::u8string 和其他 char8_t 的使用
  • <algorithm> 、 <utility> 、 <complex> 中设施的 constexpr 化
  • std::string::starts_with / ends_with 与 std::string_view::starts_with / ends_with
  • assume_aligned
  • bind_front
  • c8rtomb/mbrtoc8
  • make_obj_using_allocator 等
  • std::make_shared_for_overwrite/std::make_unique_for_overwrite
  • 无序关联容器中的异质查找
  • std::polymoprhic_allocator 的额外成员函数和 std::byte 作为其默认模板实参
  • std::execution::unseq
  • std::midpoint 和 std::lerp
  • std::ssize
  • std::is_bounded_array
  • 范围
  • 统一容器擦除 （std::erase/std::erase_if）
  • 数学常数

缺陷报告

C++20 中修正的缺陷报告（核心 158 个，库 345 个）
  • CWG#555
  • CWG#581
  • CWG#682
  • CWG#943
  • CWG#1076
  • CWG#1271
  • CWG#1299
  • CWG#1331
  • CWG#1332
  • CWG#1426
  • CWG#1469
  • CWG#1523
  • CWG#1581
  • CWG#1621
  • CWG#1632
  • CWG#1636
  • CWG#1640
  • CWG#1646
  • CWG#1704
  • CWG#1728
  • CWG#1781
  • CWG#1836
  • CWG#1857
  • CWG#1859
  • CWG#1862
  • CWG#1893
  • CWG#1910
  • CWG#1912
  • CWG#1913
  • CWG#1931
  • CWG#1937
  • CWG#1938
  • CWG#1943
  • CWG#1983
  • CWG#2020
  • CWG#2045
  • CWG#2051
  • CWG#2053
  • CWG#2059
  • CWG#2080
  • CWG#2081
  • CWG#2083
  • CWG#2088
  • CWG#2092
  • CWG#2103
  • CWG#2112
  • CWG#2126
  • CWG#2133
  • CWG#2164
  • CWG#2170
  • CWG#2177
  • CWG#2207
  • CWG#2226
  • CWG#2227
  • CWG#2229
  • CWG#2233
  • CWG#2234
  • CWG#2235
  • CWG#2237
  • CWG#2241
  • CWG#2249
  • CWG#2253
  • CWG#2254
  • CWG#2255
  • CWG#2256
  • CWG#2257
  • CWG#2260
  • CWG#2266
  • CWG#2267
  • CWG#2273
  • CWG#2277
  • CWG#2278
  • CWG#2280
  • CWG#2282
  • CWG#2285
  • CWG#2287
  • CWG#2289
  • CWG#2290
  • CWG#2292
  • CWG#2293
  • CWG#2294
  • CWG#2295
  • CWG#2299
  • CWG#2300
  • CWG#2303
  • CWG#2305
  • CWG#2307
  • CWG#2309
  • CWG#2310
  • CWG#2313
  • CWG#2315
  • CWG#2317
  • CWG#2318
  • CWG#2321
  • CWG#2322
  • CWG#2323
  • CWG#2330
  • CWG#2332
  • CWG#2336
  • CWG#2338
  • CWG#2339
  • CWG#2342
  • CWG#2343
  • CWG#2346
  • CWG#2347
  • CWG#2351
  • CWG#2352
  • CWG#2353
  • CWG#2354
  • CWG#2356
  • CWG#2358
  • CWG#2359
  • CWG#2360
  • CWG#2365
  • CWG#2366
  • CWG#2368
  • CWG#2371
  • CWG#2372
  • CWG#2373
  • CWG#2374
  • CWG#2376
  • CWG#2378
  • CWG#2379
  • CWG#2380
  • CWG#2381
  • CWG#2382
  • CWG#2384
  • CWG#2385
  • CWG#2386
  • CWG#2387
  • CWG#2390
  • CWG#2394
  • CWG#2399
  • CWG#2400
  • CWG#2404
  • CWG#2406
  • CWG#2411
  • CWG#2414
  • CWG#2416
  • CWG#2418
  • CWG#2419
  • CWG#2422
  • CWG#2424
  • CWG#2426
  • CWG#2427
  • CWG#2429
  • CWG#2430
  • CWG#2431
  • CWG#2432
  • CWG#2433
  • CWG#2436
  • CWG#2437
  • CWG#2439
  • CWG#2441
  • CWG#2442
  • CWG#2445
  • CWG#2446
  • CWG#2447
  • LWG#1052
  • LWG#1203
  • LWG#2040
  • LWG#2055
  • LWG#2070
  • LWG#2089
  • LWG#2139
  • LWG#2151
  • LWG#2154
  • LWG#2155
  • LWG#2164
  • LWG#2183
  • LWG#2184
  • LWG#2243
  • LWG#2292
  • LWG#2318
  • LWG#2334
  • LWG#2412
  • LWG#2444
  • LWG#2498
  • LWG#2499
  • LWG#2511
  • LWG#2593
  • LWG#2597
  • LWG#2682
  • LWG#2693
  • LWG#2741
  • LWG#2780
  • LWG#2783
  • LWG#2797
  • LWG#2800
  • LWG#2808
  • LWG#2814
  • LWG#2816
  • LWG#2821
  • LWG#2831
  • LWG#2832
  • LWG#2836
  • LWG#2840
  • LWG#2841
  • LWG#2843
  • LWG#2849
  • LWG#2851
  • LWG#2856
  • LWG#2859
  • LWG#2870
  • LWG#2894
  • LWG#2897
  • LWG#2899
  • LWG#2929
  • LWG#2932
  • LWG#2935
  • LWG#2936
  • LWG#2937
  • LWG#2938
  • LWG#2940
  • LWG#2941
  • LWG#2942
  • LWG#2943
  • LWG#2944
  • LWG#2945
  • LWG#2946
  • LWG#2948
  • LWG#2950
  • LWG#2951
  • LWG#2952
  • LWG#2953
  • LWG#2954
  • LWG#2955
  • LWG#2957
  • LWG#2958
  • LWG#2961
  • LWG#2964
  • LWG#2965
  • LWG#2966
  • LWG#2968
  • LWG#2969
  • LWG#2970
  • LWG#2972
  • LWG#2974
  • LWG#2975
  • LWG#2976
  • LWG#2977
  • LWG#2978
  • LWG#2979
  • LWG#2980
  • LWG#2981
  • LWG#2982
  • LWG#2988
  • LWG#2989
  • LWG#2993
  • LWG#2995
  • LWG#2996
  • LWG#2998
  • LWG#2999
  • LWG#3000
  • LWG#3001
  • LWG#3004
  • LWG#3005
  • LWG#3006
  • LWG#3007
  • LWG#3008
  • LWG#3009
  • LWG#3012
  • LWG#3013
  • LWG#3014
  • LWG#3015
  • LWG#3017
  • LWG#3018
  • LWG#3022
  • LWG#3023
  • LWG#3024
  • LWG#3025
  • LWG#3026
  • LWG#3030
  • LWG#3031
  • LWG#3034
  • LWG#3035
  • LWG#3037
  • LWG#3038
  • LWG#3039
  • LWG#3040
  • LWG#3041
  • LWG#3042
  • LWG#3043
  • LWG#3045
  • LWG#3048
  • LWG#3050
  • LWG#3051
  • LWG#3054
  • LWG#3055
  • LWG#3058
  • LWG#3061
  • LWG#3062
  • LWG#3065
  • LWG#3067
  • LWG#3070
  • LWG#3074
  • LWG#3075
  • LWG#3076
  • LWG#3077
  • LWG#3079
  • LWG#3080
  • LWG#3083
  • LWG#3087
  • LWG#3091
  • LWG#3094
  • LWG#3096
  • LWG#3100
  • LWG#3101
  • LWG#3102
  • LWG#3103
  • LWG#3104
  • LWG#3110
  • LWG#3111
  • LWG#3112
  • LWG#3113
  • LWG#3115
  • LWG#3116
  • LWG#3119
  • LWG#3122
  • LWG#3125
  • LWG#3127
  • LWG#3128
  • LWG#3129
  • LWG#3130
  • LWG#3131
  • LWG#3132
  • LWG#3133
  • LWG#3137
  • LWG#3140
  • LWG#3141
  • LWG#3144
  • LWG#3145
  • LWG#3147
  • LWG#3148
  • LWG#3149
  • LWG#3150
  • LWG#3151
  • LWG#3153
  • LWG#3154
  • LWG#3156
  • LWG#3158
  • LWG#3160
  • LWG#3168
  • LWG#3169
  • LWG#3173
  • LWG#3175
  • LWG#3176
  • LWG#3178
  • LWG#3179
  • LWG#3180
  • LWG#3182
  • LWG#3183
  • LWG#3184
  • LWG#3185
  • LWG#3186
  • LWG#3187
  • LWG#3190
  • LWG#3191
  • LWG#3194
  • LWG#3196
  • LWG#3198
  • LWG#3199
  • LWG#3200
  • LWG#3201
  • LWG#3202
  • LWG#3206
  • LWG#3208
  • LWG#3209
  • LWG#3212
  • LWG#3213
  • LWG#3218
  • LWG#3221
  • LWG#3222
  • LWG#3224
  • LWG#3225
  • LWG#3226
  • LWG#3228
  • LWG#3230
  • LWG#3231
  • LWG#3232
  • LWG#3233
  • LWG#3235
  • LWG#3237
  • LWG#3238
  • LWG#3239
  • LWG#3241
  • LWG#3242
  • LWG#3243
  • LWG#3244
  • LWG#3245
  • LWG#3246
  • LWG#3247
  • LWG#3248
  • LWG#3250
  • LWG#3251
  • LWG#3252
  • LWG#3253
  • LWG#3254
  • LWG#3255
  • LWG#3256
  • LWG#3257
  • LWG#3259
  • LWG#3260
  • LWG#3262
  • LWG#3264
  • LWG#3266
  • LWG#3269
  • LWG#3270
  • LWG#3272
  • LWG#3273
  • LWG#3274
  • LWG#3276
  • LWG#3277
  • LWG#3278
  • LWG#3279
  • LWG#3280
  • LWG#3281
  • LWG#3282
  • LWG#3284
  • LWG#3285
  • LWG#3286
  • LWG#3290
  • LWG#3291
  • LWG#3292
  • LWG#3294
  • LWG#3295
  • LWG#3296
  • LWG#3299
  • LWG#3300
  • LWG#3301
  • LWG#3302
  • LWG#3303
  • LWG#3304
  • LWG#3307
  • LWG#3310
  • LWG#3313
  • LWG#3314
  • LWG#3315
  • LWG#3316
  • LWG#3317
  • LWG#3318
  • LWG#3319
  • LWG#3320
  • LWG#3321
  • LWG#3322
  • LWG#3323
  • LWG#3324
  • LWG#3325
  • LWG#3326
  • LWG#3327
  • LWG#3328
  • LWG#3329
  • LWG#3330
  • LWG#3331
  • LWG#3332
  • LWG#3334
  • LWG#3335
  • LWG#3336
  • LWG#3338
  • LWG#3340
  • LWG#3345
  • LWG#3346
  • LWG#3347
  • LWG#3348
  • LWG#3349
  • LWG#3350
  • LWG#3351
  • LWG#3352
  • LWG#3354
  • LWG#3355
  • LWG#3356
  • LWG#3358
  • LWG#3359
  • LWG#3360
  • LWG#3362
  • LWG#3363
  • LWG#3364
  • LWG#3367
  • LWG#3368
  • LWG#3369
  • LWG#3371
  • LWG#3372
  • LWG#3373
  • LWG#3374
  • LWG#3375
  • LWG#3377
  • LWG#3379
  • LWG#3380
  • LWG#3381
  • LWG#3382
  • LWG#3383
  • LWG#3384
  • LWG#3385
  • LWG#3386
  • LWG#3387
  • LWG#3388
  • LWG#3389
  • LWG#3390
  • LWG#3393
  • LWG#3395
  • LWG#3396
  • LWG#3397
  • LWG#3398

编译器支持情况

主条目： C++ 编译器支持

C++20 核心语言功能特性

C++20 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc
允许 lambda 捕获 [=, this] | P0409R2 | 8 | 6 | 19.22* | 10.0.0* | 5.1 |  |  |  |  |  | 20.7 |
__VA_OPT__ | P0306R4 P1042R1 | 8 (部分)* 10 | 9 | 19.25* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
指派初始化器 | P0329R4 | 4.7 (部分)* 8 | 3.0 (部分)* 10 | 19.21* | (部分)* | 5.1 |  |  |  |  |  | 20.7 |
泛型 lambda 的模板形参列表 | P0428R2 | 8 | 9 | 19.22* | 11.0.0* | 5.1 |  |  |  |  |  | 20.7 |
位域的默认成员初始化器 | P0683R1 | 8 | 6 | 19.25* | 10.0.0* | 5.1 |  |  |  |  |  | 20.7 |
类模板实参推导中的 intializer_list 构造函数 | P0702R1 | 8 | 6 | 19.14* | 是 | 5.0 |  |  |  |  |  | 20.7 |
const& 限定的成员指针 | P0704R1 | 8 | 6 | 19.14* | 是 | 5.0 |  |  |  |  |  | 20.7 |
概念 | P0734R0 | 6 (仅 TS) 10 | 10 | 19.23* (部分)* |  |  |  |  |  |  |  | 20.11 |
不求值语境中的 lambda | P0315R4 | 9 |  | 19.28 (16.8)* |  |  |  |  |  |  |  |  |
三路比较运算符 | P0515R3 | 10 | 8 (部分) 10 | 19.20* |  | 5.1 |  |  |  |  |  | 20.7 |
DR ：简化隐式 lambda 捕获 | P0588R1 | 8 |  | 19.24* |  | 5.1 |  |  |  |  |  | 20.7 |
基于范围的 for 的初始化语句 | P0614R1 | 9 | 8 | 19.25* | 11.0.0* | 6.0 |  |  |  |  |  | 20.11 |
可默认构造与可赋值的无状态 lambda | P0624R2 | 9 | 8 | 19.22* | 10.0.1* | 5.1 |  |  |  |  |  |  |
预置复制构造函数与 const 的不匹配 | P0641R2 | 9 | 8 | 19.0 (2015)* | 10.0.1* | 5.1 |  |  |  |  |  | 20.7 |
特化上的访问检查 | P0692R1 | 是 | 8 (部分) | 19.26* | 10.0.1* (部分) | 5.1 |  |  |  |  |  | 20.7 |
ADL 与不可见的函数模板 | P0846R0 | 9 | 9 | 19.21* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
DR：指定 constexpr 函数定义何时为常量求值所需要 | P0859R0 | 5.2 (部分)* 9 | 8 | 19.27* (部分)* |  |  |  |  |  |  |  |  |
属性 [[likely]] 与 [[unlikely]] | P0479R5 | 9 | 12 | 19.26* |  | 5.1 |  |  |  |  |  | 20.7 |
使 typename 更可选 | P0634R3 | 9 |  | 19.29 (16.10)* |  | 5.1 |  |  |  |  |  | 20.7 |
Lambda 初始化捕获中的包展开 | P0780R2 | 9 | 9 | 19.22* | 11.0.3* | 6.1 |  |  |  |  |  | 20.11 |
属性 [[no_unique_address]] | P0840R2 | 9 | 9 | 19.28 (16.9)** | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
条件性平凡的特殊成员函数 | P0848R3 | 10 |  | 19.28 (16.8)* |  | 6.1 |  |  |  |  |  | 20.11 |
DR：放松结构化绑定定制点查找规则 | P0961R1 | 8 | 8 | 19.21* | 10.0.1* | 5.1 |  |  |  |  |  |  |
DR：放松范围 for 循环定制点查找规则 | P0962R1 | 8 |  |  |  | 5.1 |  |  |  |  |  |  |
DR ：允许到可访问成员的结构化绑定 | P0969R0 | 8 | 8 | 19.21* | 10.0.1* | 5.1 |  |  |  |  |  |  |
销毁的 operator delete | P0722R3 | 9 | 6 | 19.27* | 10.0.0* | 6.1 |  |  |  |  |  |  |
非类型模板形参非类型模板形参中的类类型 | P0732R2 | 9 | 12 (部分) | 19.26*(部分)* 19.28 (16.9)* |  | 6.2 |  |  |  |  |  |  |
弃用经由 [=] 隐式捕获 this | P0806R2 | 9 | 7 | 19.22* |  | 5.1 |  |  |  |  |  | 20.7 |
explicit(bool) | P0892R2 | 9 | 9 | 19.24* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
集成功能特性测试宏 | P0941R2 | 5 | 3.4 | 19.15* (部分) 19.20* | 是 | 5.0 |  |  |  |  |  | 20.7 |
禁止有用户声明构造函数的聚合体 | P1008R1 | 9 | 8 | 19.20* | 10.0.1* | 5.1 |  |  |  |  |  | 20.7 |
constexpr 虚函数 | P1064R0 | 9 | 9 | 19.28 (16.9)* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
比较的一致性改进 | P1120R0 | 10 | 8 (部分) 10 | 19.22* | 10.0.1* (部分) | 5.1 |  |  |  |  |  | 20.7 |
char8_t | P0482R6 | 9 | 7 | 19.22* | 10.0.0* | 5.1 |  |  |  |  |  | 20.7 |
std::is_constant_evaluated() | P0595R2 | 9 | 9 | 19.25* | 11.0.3* | 5.1 | 19.1 |  |  |  |  |  |
constexpr 函数中的 try-catch 块 | P1002R1 | 9 | 8 | 19.25* | 10.0.1* | 5.1 |  |  |  |  |  | 20.7 |
立即函数（consteval） | P1073R3 | 10 (部分)* 11 | 11 (部分) | 19.28 (16.8)** (部分) 19.29 (16.10)* |  | 5.1 |  |  |  |  |  | 20.7 |
嵌套内联命名空间 | P1094R2 | 9 | 8 | 19.27* | 10.0.1* | 5.1 |  |  |  |  |  | 20.7 |
有约束 声明的另一种手段 | P1141R2 | 10 | 10 | 19.26* (部分) 19.28 (16.9)* |  | 6.1 |  |  |  |  |  | 20.11 |
有符号整数为补码 | P1236R1 | 9 |  | 是 | 11.0.3* | N/A |  |  |  |  |  | 是 |
constexpr dynamic_cast 及多态 typeid | P1327R1 | 10 | 9 | 19.29 (16.10)* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
在 constexpr 内更改联合体的活跃成员 | P1330R0 | 9 | 9 | 19.10* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
协程 | P0912R5 | 10 | 8 (部分) | 19.0 (2015)* (部分) 19.10* (仅 TS) 19.28 (16.8)* | 10.0.1* (部分) | 5.1 |  |  |  |  |  |  |
括号形式的聚合体初始化 | P0960R3 | 10 |  | 19.28 (16.8)* |  | 5.1 |  |  |  |  |  | 20.7 |
DR： new 表达式中的数组大小推导 | P1009R2 | 11 | 9 | 19.27* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
模块 | P1103R3 | 11 (部分) | 8 (部分) | 19.0 (2015)* (部分) 19.10* (仅 TS) 19.28 (16.8)* | 10.0.1* (部分) |  |  |  |  |  |  |  |
更强的 Unicode 要求 | P1041R4 P1139R2 | 10 | 是 | 19.0 (2015)* (P1041R4) 19.26* (P1139R2) | 是 | N/A |  |  |  |  |  |  |
<=> != == | P1185R2 | 10 | 10 | 19.22* |  | 5.1 |  |  |  |  |  | 20.7 |
DR ：拥有不同异常说明的显式默认化函数 | P1286R2 | 10 | 9 | 19.28 (16.8)* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
结构化绑定的 lambda 捕获与存储类说明符 | P1091R3 P1381R1 | 10 | 8 (部分) | 19.11*(P1381R1) 19.24*(P1091R3) | 10.0.1* (部分) | 5.1 |  |  |  |  |  | 20.7 |
容许转换到未知边界数组 | P0388R4 | 10 |  | 19.27* |  | 6.0 |  |  |  |  |  | 20.11 |
constexpr 容器操作 | P0784R7 | 10 | 10 | 19.28 (16.9)* |  | 6.0 |  |  |  |  |  | 20.11 |
弃用 volatile 的某些用法 | P1152R4 | 10 | 10 | 19.27* |  | 6.0 |  |  |  |  |  | 20.11 |
constinit | P1143R2 | 10 | 10 | 19.29 (16.10)* |  | 6.1 |  |  |  |  |  | 20.11 |
弃用下标中的逗号运算符 | P1161R3 | 10 | 9 | 19.25* | 11.0.3* | 6.0 |  |  |  |  |  | 20.11 |
带消息的 [[nodiscard]] | P1301R4 | 10 | 9 | 19.25* | 11.0.3* | 6.0 |  |  |  |  |  | 20.11 |
constexpr 函数中的平凡默认初始化 | P1331R2 | 10 | 10 | 19.27* |  | 6.1 |  |  |  |  |  | 20.11 |
constexpr 函数中的不求值 asm 声明 | P1668R1 | 10 | 10 | 19.28 (16.9)* |  | 6.1 |  |  |  |  |  | 20.11 |
using enum | P1099R5 | 11 | 13 | 19.24* |  | 6.3 |  |  |  |  |  |  |
对指定的比较类别合成三路比较 | P1186R3 | 11 | 10 | 19.24* |  | 6.0 |  |  |  |  |  | 20.11 |
DR：构造函数的 [[nodiscard]] | P1771R1 | 10 | 9 | 19.24* | 11.0.3* | 6.0 |  |  |  |  |  | 20.11 |
别名模板的类模板实参推导 | P1814R0 | 10 |  | 19.27* |  |  |  |  |  |  |  |  |
聚合类的类模板实参推导 | P1816R0 P2082R1 | 10(P1816R0) 11(P2082R1) |  | 19.27* |  |  |  |  |  |  |  |  |
DR ：更多局部对象与右值引用的隐式移动 | P1825R0 | 11* | 13 | 19.24* |  | 6.0 |  |  |  |  |  | 20.11 |
允许默认化按值比较 | P1946R0 | 10 | 10 | 19.25* |  | 6.1 |  |  |  |  |  | 20.11 |
移除 std::weak_equality 与 std::strong_equality | P1959R0 | 10 | 10 | 19.25* |  | 6.1 |  |  |  |  |  | 20.11 |
非类型模板形参的不一致 | P1907R1 | 10 (部分) 11 | 12 (部分) | 19.26* |  | 6.2 |  |  |  |  |  |  |
DR：伪析构函数终结对象生存期 | P0593R6 | 11 | 11 | 是 |  | N/A |  |  |  |  |  |  |
DR ：应认为从 T* 到 bool 的转换为窄化 | P1957R2 | 10* 11* | 11 | 19.27* |  | 6.1 |  |  |  |  |  |  |
C++20 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc

C++20 库功能特性

C++20 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
std::endian | P0463R1 | 8 | 7 | 19.22* | 10.0.0* |  |  |
扩展 std::make_shared() 以支持数组 | P0674R1 |  |  | 19.27* |  |  |  |
浮点原子类型 | P0020R6 | 10 |  | 19.22* |  |  |  |
同步缓冲（std::basic_osyncstream） | P0053R7 | 11 |  | 19.29 (16.10)* |  |  |  |
<algorithm> 与 <utility> 的 constexpr | P0202R3 | 10 | 8 (部分) 12 | 19.26* | 10.0.1* (部分) |  |  |
<complex> 的更多 constexpr | P0415R1 | 9 | 7 (部分) | 19.27* | 10.0.0* (部分) |  |  |
使 std::memory_order 为有作用域枚举 | P0439R0 | 9 | 9 | 19.25* | 11.0.3* |  |  |
字符串 前缀与后缀检查： string (_view) ::starts_with/ends_with | P0457R2 | 9 | 6 | 19.21* | 10.0.0* |  |  |
=operator<=> 的库支持 <compare> | P0768R1 | 10 | 7 (部分) 12 | 19.20* (部分) 19.28 (16.9)* | 10.0.0* (部分) |  |  |
std::remove_cvref | P0550R2 | 9 | 6 | 19.20* | 10.0.0* |  |  |
标准库中的 [[nodiscard]] | P0600R1 | 9 | 7 (部分) | 19.13* (部分) 19.22* | 10.0.0* (部分) |  |  |
于数值算法使用 std::move | P0616R0 | 9 | 12 | 19.23* |  |  |  |
转换指针为裸指针的工具 | P0653R2 | 8 | 6 | 19.22* | 是 |  |  |
原子 std::shared_ptr 与 std::weak_ptr | P0718R2 |  |  | 19.27* |  |  |  |
std::span | P0122R7 | 10 | 7 | 19.26* | 10.0.0* |  |  |
日历与时区 | P0355R7 | 11 (部分) | 7 (部分) | 19.29 (16.10)* | 10.0.0* (部分) |  |  |
<version> | P0754R2 | 9 | 7 | 19.22* | 10.0.0* |  |  |
比较无序容器 | P0809R0 |  | 是 | 16.0* | 是 |  |  |
常量表达式迭代器 (ConstexprIterator) 要求 | P0858R0 | 9 |  | 19.11* |  |  |  |
std::basic_string::reserve() 不应收缩 | P0966R1 | 11 | 8 | 19.25* | 10.0.1* |  |  |
带填充位的原子比较交换 | P0528R3 |  |  | 19.28 (16.8)* |  |  |  |
std::atomic_ref | P0019R8 | 10 |  | 19.28 (16.8)* |  |  |  |
关联容器的 contains() 成员函数，如 std::map::contains() | P0458R2 | 9 | 9 (部分)* 13 | 19.21* | 11.0.3* |  |  |
DR ：逐片构造的受保证复制消除 | P0475R1 | 9 | 是 | 19.29 (16.10)* | 是 |  |  |
std::bit_cast() | P0476R2 | 11 |  | 19.27* |  |  |  |
整数的 2 的幂的运算： std::bit_ceil()、 std::bit_floor()、 std::bit_width()、 std::has_single_bit() | P0556R3 P1956R1 | 9 (P0556R3) 10 (P1956R1) | 9 (P0556R3) 12 (P1956R1) | 19.25* (P0556R3)* 19.27* (P1956R1)* 19.28 (16.8)* |  |  |  |
改进擦除式算法的返回值 | P0646R1 | 9 | 10 | 19.21* |  |  |  |
std::destroying_delete | P0722R3 | 9 | 9 | 19.27* | 11.0.3* |  |  |
std::is_nothrow_convertible | P0758R1 | 9 | 9 | 19.23* | 11.0.3* |  |  |
添加 std::shift_left/right 到 <algorithm> | P0769R2 | 10 | 12 | 19.21* |  |  |  |
std::swap() 与 swap 相关函数的 constexpr | P0879R0 | 10 | 12 (部分) 13 | 19.26* |  |  |  |
std::type_identity | P0887R1 | 9 | 8 | 19.21* | 10.0.1* |  |  |
概念库 | P0898R3 | 10 | 13 | 19.23* |  |  |  |
std::array 的 constexpr 比较运算符 | P1023R0 | 10 | 8 | 19.27* | 10.0.1* |  |  |
std::unwrap_ref_decay 与 std::unwrap_reference | P0318R1 | 9 | 8 | 19.21* | 10.0.1* |  |  |
std::bind_front() | P0356R5 | 9 | 13 | 19.25* |  |  |  |
不完整类型的 std::reference_wrapper | P0357R3 | 9 | 8 | 19.26* | 10.0.1* |  |  |
修正 operator>>(basic_istream&, CharT*) | P0487R1 | 11 | 8 | 19.23* | 10.0.1* |  |  |
char8_t 的库支持 | P0482R6 | 9 | 8 (部分)* | 19.22* |  |  |  |
实现使用分配器 构造的工具函数 | P0591R4 | 9 |  | 19.29 (16.10)* |  |  |  |
DR： std::variant 与 std::optional 应传播复制/移动平凡性 | P0602R4 | 8.3 | 8 | 19.11* | 10.0.1* |  |  |
理智的 std::variant 转换构造函数 | P0608R3 | 10 | 9 | 19.29 (16.10)* | 11.0.3* |  |  |
std::function 的移动构造函数应为 noexcept | P0771R1 | 7.2 | 6 | 19.22* | 是 |  |  |
一个 范围 提案 | P0896R4 | 10 | 13 (部分) | 19.29 (16.10)* |  |  |  |
无序容器的异质查找 | P0919R3 P1690R1 | 11 | 12 | 19.23* (P0919R3) 19.25* (P1690R1) |  |  |  |
<chrono> zero()、 min() 及 max() 应为 noexcept | P0972R0 | 9 | 8 | 19.14* | 10.0.1* |  |  |
std::pointer_traits 中的 constexpr | P1006R1 | 9 | 8 | 19.26* | 10.0.1* |  |  |
std::assume_aligned() | P1007R3 | 9* 11 |  | 19.28 (16.9)* |  |  |  |
使用默认初始化的智能指针创建（如 make_unique_for_overwrite） | P1020R1 P1973R1 |  |  | 19.28 (16.9)* |  |  |  |
杂项 constexpr 小部分 | P1032R1 | 10 | 13 | 19.28 (16.8)* |  |  |  |
移除 std::span 的比较运算符 | P1085R2 | 10 | 8 | 19.26* | 10.0.1* |  |  |
使 operator+(basic_string) 的有状态分配器传播更加一致 | P1165R1 | 10 |  | 19.26* |  |  |  |
一致容器擦除，如 std::erase(std::vector) 或 std::erase_if(std::map) | P1209R0 P1115R3 | 9 (P1209R0) 10 (P1115R3) | 8 (P1209R0) 11 (P1115R3) | 19.25* (P1209R0) 19.27* (P1115R3) | 10.0.1* (P1209R0) |  |  |
标准库头文件单元 | P1502R1 | 11 |  | 19.29 (16.10)* |  |  |  |
polymorphic_allocator<> 作为词汇类型 | P0339R6 | 9 |  | 19.28 (16.9)* |  |  |  |
std::execution::unseq | P1001R2 | 9 |  | 19.28 (16.8)* |  |  |  |
std::lerp() 与 std::midpoint() | P0811R3 | 9 | 9 | 19.23* (部分) 19.28 (16.8)* | 11.0.3* |  |  |
std::span 的实用性增强 | P1024R3 | 10 | 9 | 19.26* | 11.0.3* |  |  |
DR：使 create_directory() 自发 | P1164R1 | 8.3 | 12 | 19.20* |  |  |  |
std::ssize() 与 std::span 的无符号长度 | P1227R2 | 10 | 9 | 19.25* | 11.0.3* |  |  |
有界及无界数组特征 | P1357R1 | 9 | 9 | 19.25* | 11.0.3* |  |  |
std::to_array() | P0325R4 | 10 | 10 | 19.25* |  |  |  |
std::basic_stringbuf 缓冲的有效访问 | P0408R7 | 11 |  | 19.29 (16.10)* |  |  |  |
布局 兼容性与指针 可互转换性特征 | P0466R5 |  |  | 19.29 (16.10)** |  |  |  |
位操作： std:: rotl()、 rotr()、 countl_zero()、 countl_one()、 countr_zero()、 countr_one()、 popcount() | P0553R4 | 9 | 9 | 19.25** 19.28 (16.8)* | 11.0.3* |  |  |
数学常数 | P0631R8 | 10 | 11 | 19.25* |  |  |  |
文本格式化 | P0645R10 |  |  | 19.29 (16.10)* |  |  |  |
std::stop_token 与 std::jthread | P0660R10 | 10 |  | 19.28 (16.9)* |  |  |  |
constexpr std::allocator 及相关工具 | P0784R7 | 10 | 12 | 19.29 (16.10)* |  |  |  |
constexpr std::string | P0980R1 |  |  | 19.29 (16.10)* |  |  |  |
constexpr std::vector | P1004R2 |  |  | 19.29 (16.10)* |  |  |  |
输入范围适配器 | P1035R7 | 10 |  | 19.29 (16.10)* |  |  |  |
constexpr std::invoke() 及相关工具 | P1065R2 | 10 | 12 | 19.28 (16.8)* |  |  |  |
原子等待与提醒、 std::counting_semaphore 、 std::latch 及 std::barrier | P1135R6 | 11 | 11 | 19.28 (16.8)* |  |  |  |
std::source_location | P1208R6 | 11 |  | 19.29 (16.10)* |  |  |  |
添加 <=> 到标准库 | P1614R2 | 10 |  | 19.29 (16.10)* |  |  |  |
std::atomic 与 std::atomic_flag 的 constexpr 默认构造函数 | P0883R2 | 10 | 13 | 19.26* |  |  |  |
数值算法的 constexpr | P1645R1 | 10 | 12 | 19.26* |  |  |  |
安全整数比较 | P0586R2 | 10 | 13 | 19.27* |  |  |  |
C++20 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库

* - 在版本号上停留可以查看注记

  • C++20 可行样例


C++23

< cpp

下一代C++标准

本节未完成

新的语言特性

新的库特性

缺陷报告

编译器支持情况

主条目： C++ 编译器支持

C++23 核心语言功能特性

C++23 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc
（有符号） size_t 的字面量后缀 | P0330R8 | 11 | 13 |  |  |  |  |  |  |  |  |  |
使 () 对 lambda 更可选 | P1102R2 | 11 | 13 |  |  |  |  |  |  |  |  |  |
if consteval | P1938R3 | 12 | 14 |  |  |  |  |  |  |  |  |  |
移除垃圾收集支持 | P2186R2 | 12 |  |  |  |  |  |  |  |  |  |  |
DR：C++ 标识符语法使用 Unicode 标准附录 31 | P1949R7 | 12 | 14 |  |  |  |  |  |  |  |  |  |
DR：允许重复属性 | P2156R1 | 11 | 13 |  |  |  |  |  |  |  |  |  |
static_assert 与 constexpr if 中的窄化按语境转换 | P1401R5 | 9 | 13 (部分)* 14 |  |  |  |  |  |  |  |  |  |
在拼接行前剔除空白符 | P2223R2 | 是 | 是 |  | 是 |  |  |  |  |  |  |  |
使声明顺序布局强制 | P1847R4 | 是 | 是 | 是 | 是 |  |  |  |  |  |  |  |
移除混合宽字符串字面量连接 | P2201R1 | 是 | 是 | 是 | 是 |  | 是 |  |  |  |  |  |
C++23 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc

C++23 库功能特性

C++23 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
栈踪库 | P0881R7 |  |  |  |  |  |  |
<stdatomic.h> | P0943R6 |  |  |  |  |  |  |
std::is_scoped_enum | P1048R1 | 11 | 12 | 19.30* |  |  |  |
basic_string/basic_string_view 的 contains() | P1679R3 | 11 | 12 |  |  |  |  |
std::to_underlying | P1682R3 | 11 | 13 |  |  |  |  |
std::variant 的派生类的 std::visit | P2162R2 |  | 13 | 19.20** |  |  |  |
放松 time_point<>::clock 的要求 | P2212R2 | N/A |  | N/A |  |  |  |
DR：条件性借用范围 | P2017R1 |  |  | 19.30* |  |  |  |
DR：修复输入范围适配器与 std::counted_iterator | P2259R1 |  |  |  |  |  |  |
在分配器接口中提供大小反馈 | P0401R6 |  |  |  |  |  |  |
<spanstream> ：以 std::span 为基础的字符串流 | P0448R4 |  |  |  |  |  |  |
std::out_ptr()、 std::inout_ptr() | P1132R8 |  |  |  |  |  |  |
constexpr type_info::operator==() | P1328R1 |  |  |  |  |  |  |
std::stack 与 std::queue 的迭代器对构造函数 | P1425R4 |  |  |  |  |  |  |
容器推导指引中分配器的非推导语境 | P1518R2 |  |  |  |  |  |  |
ranges::starts_with() 与 ranges::ends_with() | P1659R3 | 11 |  |  |  |  |  |
禁止 basic_string 与 basic_string_view 从 nullptr 构造 | P2166R1 |  |  |  |  |  |  |
std::invoke_r() | P2136R3 |  |  |  |  |  |  |
basic_string_view 的范围构造函数 | P1989R2 |  |  |  |  |  |  |
pair 的转发构造函数的默认模板实参 | P1951R1 |  |  |  |  |  |  |
移除垃圾收集与基于可达性的泄漏检测（库支持） | P2186R2 |  |  |  |  |  |  |
DR：join_view 应结合所有范围 | P2328R1 |  |  |  |  |  |  |
DR：view 不要求 default_initializable | P2325R3 |  |  |  |  |  |  |
DR：范围适配器对象按值绑定实参 | P2281R1 |  |  | 19.29 (16.10)* |  |  |  |
DR：std::optional 与 std::variant 的 constexpr | P2231R1 |  |  |  |  |  |  |
DR：std::format() 改进 | P2216R3 |  |  |  |  |  |  |
DR：lazy_split_view 与重新设计的 split_view | P2210R2 |  |  |  |  |  |  |
C++23 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库

* - 在版本号上停留可以查看注记


算法库

< cpp

算法库提供大量用途的函数（例如查找、排序、计数、操作），它们在元素范围上操作。注意范围定义为 [first, last) ，其中 last 指代要查询或修改的最后元素的后一个元素。

受约束算法

C++20 在命名空间 std::ranges 中提供大多数算法的受约束版本，能以迭代器-哨位对或单个 range 参数指定范围，并且支持投影和指向成员指针可调用对象。另外更改了大多数算法的返回类型，以返回算法执行过程中计算的所有潜在有用信息。

std::vector<int> v = {7, 1, 4, 0, -1};
std::ranges::sort(v); // 受约束算法
 (C++20 起)
执行策略

大多数算法拥有接受执行策略的重载。标准算法库提供几种执行策略，并提供对应执行策略的类型和对象。用户可以静态地选择执行策略，通过以对应类型的执行策略对象为参数，调用并行算法。

标准库实现（但不是用户）可以定义附加的执行策略作为扩展。以实现定义类型的执行策略对象调用的并行算法的语义是实现定义的。

允许算法的并行版本（除了 std::for_each 与 std::for_each_n ）从范围进行任意的元素复制，只要 std::is_trivially_copy_constructible_v <T> 与 std::is_trivially_destructible_v <T> 均为 true ，其中 T 是元素的类型。

定义于头文件 <execution>
定义于命名空间 std::execution
sequenced_policyparallel_policyparallel_unsequenced_policyunsequenced_policy (C++17)(C++17)(C++17)(C++20) | 执行策略类型 (类)
seqparpar_unsequnseq (C++17)(C++17)(C++17)(C++20) | 全局执行策略对象 (常量)
定义于命名空间 std
is_execution_policy (C++17) | 测试一个类是否表示某种执行策略 (类模板)
 (C++17 起)
不修改序列的操作
定义于头文件 <algorithm>
all_ofany_ofnone_of
(C++11)(C++11)(C++11)
 检查谓词是否对范围中所有、任一或无元素为 true
(函数模板)
ranges::all_ofranges::any_ofranges::none_of
(C++20)(C++20)(C++20)
 检查谓词是否对范围中所有、任一或无元素为 true
(niebloid)
for_each
 应用函数到范围中的元素
(函数模板)
ranges::for_each
(C++20)
 应用函数到范围中的元素
(niebloid)
for_each_n
(C++17)
 应用一个函数对象到序列的前 n 个元素
(函数模板)
ranges::for_each_n
(C++20)
 应用函数对象到序列的首 n 个元素
(niebloid)
countcount_if
 返回满足指定判别标准的元素数
(函数模板)
ranges::countranges::count_if
(C++20)(C++20)
 返回满足指定判别标准的元素数
(niebloid)
mismatch
 寻找两个范围出现不同的首个位置
(函数模板)
ranges::mismatch
(C++20)
 寻找两个范围出现不同的首个位置
(niebloid)
findfind_iffind_if_not
(C++11)
 寻找首个满足特定判别标准的元素
(函数模板)
ranges::findranges::find_ifranges::find_if_not
(C++20)(C++20)(C++20)
 寻找首个满足特定判别标准的元素
(niebloid)
find_end
 在特定范围中寻找最后出现的元素序列
(函数模板)
ranges::find_end
(C++20)
 在特定范围中寻找最后出现的元素序列
(niebloid)
find_first_of
 搜索元素集合中的任意元素
(函数模板)
ranges::find_first_of
(C++20)
 搜索元素集合中的任一元素
(niebloid)
adjacent_find
 查找首对相邻的相同（或满足给定谓词的）元素
(函数模板)
ranges::adjacent_find
(C++20)
 查找首对相邻的相同（或满足给定谓词的）元素
(niebloid)
search
 搜索一个元素范围
(函数模板)
ranges::search
(C++20)
 搜索一个元素范围
(niebloid)
search_n
 在范围中搜索一定量的某个元素的连续副本
(函数模板)
ranges::search_n
(C++20)
 在范围中搜索一定量的某个元素的连续副本
(niebloid)
ranges::starts_with
(C++23)
 检查一个范围是否始于另一范围
(niebloid)
ranges::ends_with
(C++23)
 检查一个范围是否终于另一范围
(niebloid)
修改序列的操作
定义于头文件 <algorithm>
copycopy_if
(C++11)
 将某一范围的元素复制到一个新的位置
(函数模板)
ranges::copyranges::copy_if
(C++20)(C++20)
 将某一范围的元素复制到一个新的位置
(niebloid)
copy_n
(C++11)
 将一定数目的元素复制到一个新的位置
(函数模板)
ranges::copy_n
(C++20)
 将一定数目的元素复制到一个新的位置
(niebloid)
copy_backward
 按从后往前的顺序复制一个范围内的元素
(函数模板)
ranges::copy_backward
(C++20)
 按从后往前的顺序复制一个范围内的元素
(niebloid)
move
(C++11)
 将某一范围的元素移动到一个新的位置
(函数模板)
ranges::move
(C++20)
 将某一范围的元素移动到一个新的位置
(niebloid)
move_backward
(C++11)
 按从后往前的顺序移动某一范围的元素到新的位置
(函数模板)
ranges::move_backword
(C++20)
 按从后往前的顺序移动某一范围的元素到新的位置
(niebloid)
fill
 将一个给定值复制赋值给一个范围内的每个元素
(函数模板)
ranges::fill
(C++20)
 将一个给定值复制赋值给一个范围内的每个元素
(niebloid)
fill_n
 将一个给定值复制赋值给一个范围内的 N 个元素
(函数模板)
ranges::fill_n
(C++20)
 将一个值复制赋值给一定量的元素
(niebloid)
transform
 将一个函数应用于某一范围的各个元素，并在目标范围存储结果
(函数模板)
ranges::transform
(C++20)
 将一个函数应用于某一范围的各个元素
(niebloid)
generate
 将相继的函数调用结果赋值给一个范围中的每个元素
(函数模板)
ranges::generate
(C++20)
 保存函数结果到一个范围中
(niebloid)
generate_n
 将相继的函数调用结果赋值给一个范围中的 N 个元素
(函数模板)
ranges::generate_n
(C++20)
 保存 N 次函数应用的结果
(niebloid)
removeremove_if
 移除满足特定判别标准的元素
(函数模板)
ranges::removeranges::remove_if
(C++20)(C++20)
 移除满足特定判别标准的元素
(niebloid)
remove_copyremove_copy_if
 复制一个范围的元素，忽略满足特定判别标准的元素
(函数模板)
ranges::remove_copyranges::remove_copy_if
(C++20)(C++20)
 复制一个范围的元素，忽略满足特定判别标准的元素
(niebloid)
replacereplace_if
 将所有满足特定判别标准的值替换为另一个值
(函数模板)
ranges::replaceranges::replace_if
(C++20)(C++20)
 将所有满足特定判别标准的值替换为另一个值
(niebloid)
replace_copyreplace_copy_if
 复制一个范围内的元素，并将满足特定判别标准的元素替换为另一个值
(函数模板)
ranges::replace_copyranges::replace_copy_if
(C++20)(C++20)
 复制一个范围内的元素，并将满足特定判别标准的元素替换为另一个值
(niebloid)
swap
 交换两个对象的值
(函数模板)
swap_ranges
 交换两个范围的元素
(函数模板)
ranges::swap_ranges
(C++20)
 交换两个范围的元素
(niebloid)
iter_swap
 交换两个迭代器所指向的元素
(函数模板)
reverse
 逆转范围中的元素顺序
(函数模板)
ranges::reverse
(C++20)
 逆转范围中的元素顺序
(niebloid)
reverse_copy
 创建一个范围的逆向副本
(函数模板)
ranges::revserse_copy
(C++20)
 创建一个范围的逆向副本
(niebloid)
rotate
 旋转范围中的元素顺序
(函数模板)
ranges::rotate
(C++20)
 旋转范围中的元素顺序
(niebloid)
rotate_copy
 复制并旋转元素范围
(函数模板)
ranges::rotate_copy
(C++20)
 复制并旋转元素范围
(niebloid)
shift_leftshift_right
(C++20)
 迁移范围中的元素
(函数模板)
random_shuffleshuffle
(C++17 前)(C++11)
 随机重排范围中的元素
(函数模板)
ranges::shuffle
(C++20)
 随机重排范围中的元素
(niebloid)
sample
(C++17)
 从一个序列中随机选择 n 个元素
(函数模板)
ranges::sample
(C++20)
 从序列中随机选择 n 个元素
(niebloid)
unique
 移除范围内的连续重复元素
(函数模板)
ranges::unique
(C++20)
 移除范围中的连续重复元素
(niebloid)
unique_copy
 创建某范围的不含连续重复元素的副本
(函数模板)
ranges::unique_copy
(C++20)
 创建某范围的不含连续重复元素的副本
(niebloid)
划分操作
定义于头文件 <algorithm>
is_partitioned
(C++11)
 判断范围是否已按给定的谓词划分
(函数模板)
ranges::is_partitioned
(C++20)
 判断范围是否已按给定的谓词划分
(niebloid)
partition
 将范围中的元素分为两组
(函数模板)
ranges::partition
(C++20)
 将范围中的元素分为二组
(niebloid)
partition_copy
(C++11)
 复制一个范围，将各元素分为两组
(函数模板)
ranges::partition_copy
(C++20)
 复制一个范围，将各元素分为二组
(niebloid)
stable_partition
 将元素分为两组，同时保留其相对顺序
(函数模板)
ranges::stable_partition
(C++20)
 将元素分成二组，同时保持其相对顺序
(niebloid)
partition_point
(C++11)
 定位已划分范围的划分点
(函数模板)
ranges::partition_point
(C++20)
 定位已划分范围的划分点
(niebloid)
排序操作
定义于头文件 <algorithm>
is_sorted
(C++11)
 检查范围是否已按升序排列
(函数模板)
ranges::is_sorted
(C++20)
 检查范围是否以升序排序
(niebloid)
is_sorted_until
(C++11)
 找出最大的已排序子范围
(函数模板)
ranges::is_sorted_until
(C++20)
 寻找最大的已排序子范围
(niebloid)
sort
 将范围按升序排序
(函数模板)
ranges::sort
(C++20)
 将范围按升序排序
(niebloid)
partial_sort
 排序一个范围的前 N 个元素
(函数模板)
ranges::partial_sort
(C++20)
 排序一个范围的前 N 个元素
(niebloid)
partial_sort_copy
 对范围内的元素进行复制并部分排序
(函数模板)
ranges::partial_sort_copy
(C++20)
 对范围内的元素进行复制并部分排序
(niebloid)
stable_sort
 将范围内的元素排序，同时保持相等的元素之间的顺序
(函数模板)
ranges::stable_sort
(C++20)
 将范围内的元素排序，同时保持相等的元素之间的顺序
(niebloid)
nth_element
 将给定的范围部分排序，确保其按给定元素划分
(函数模板)
ranges::nth_element
(C++20)
 将给定的范围部分排序，确保其按给定元素划分
(niebloid)
二分搜索操作（在已排序范围上）
定义于头文件 <algorithm>
lower_bound
 返回指向第一个不小于给定值的元素的迭代器
(函数模板)
ranges::lower_bound
(C++20)
 返回指向首个不小于给定值的元素的迭代器
(niebloid)
upper_bound
 返回指向第一个大于给定值的元素的迭代器
(函数模板)
ranges::upper_bound
(C++20)
 返回指向首个大于某值的元素的迭代器
(niebloid)
binary_search
 确定元素是否存在于某范围中
(函数模板)
ranges::binary_search
(C++20)
 确定元素是否存在于某范围中
(niebloid)
equal_range
 返回匹配特定键值的元素范围
(函数模板)
ranges::equal_ranges
(C++20)
 返回匹配特定值的元素范围
(niebloid)
其他已排序范围上的操作
定义于头文件 <algorithm>
merge
 归并两个已排序的范围
(函数模板)
ranges::merge
(C++20)
 归并二个已排序范围
(niebloid)
inplace_merge
 就地归并两个有序范围
(函数模板)
ranges::inplace_merge
(C++20)
 在原位归并两个有序范围
(niebloid)
集合操作（在已排序范围上）
定义于头文件 <algorithm>
includes
 若一个序列是另一个的子列则返回 true
(函数模板)
ranges::includes
(C++20)
 若一个序列是另一个的子列则返回 true
(niebloid)
set_difference
 计算两个集合的差集
(函数模板)
ranges::set_difference
(C++20)
 计算两个集合的差集
(niebloid)
set_intersection
 计算两个集合的交集
(函数模板)
ranges::set_intersection
(C++20)
 计算两个集合的交集
(niebloid)
set_symmetric_difference
 计算两个集合的对称差
(函数模板)
ranges::set_symmetric_difference
(C++20)
 计算两个集合的对称差
(niebloid)
set_union
 计算两个集合的并集
(函数模板)
ranges::set_union
(C++20)
 计算两个集合的并集
(niebloid)
堆操作
定义于头文件 <algorithm>
is_heap
 检查给定范围是否为一个最大堆
(函数模板)
ranges::is_heap
(C++20)
 检查给定范围是否为最大堆
(niebloid)
is_heap_until
(C++11)
 查找能成为最大堆的最大子范围
(函数模板)
ranges::is_heap_until
(C++20)
 寻找能成为最大堆的最大子范围
(niebloid)
make_heap
 从一个元素范围创建出一个最大堆
(函数模板)
ranges::make_heap
(C++20)
 从一个元素范围创建出一个最大堆
(niebloid)
push_heap
 将一个元素加入到一个最大堆
(函数模板)
ranges::push_heap
(C++20)
 将一个元素加入到一个最大堆
(niebloid)
pop_heap
 从最大堆中移除最大元素
(函数模板)
ranges::pop_heap
(C++20)
 从最大堆中移除最大元素
(niebloid)
sort_heap
 将一个最大堆变成一个按升序排序的元素范围
(函数模板)
ranges::sort_heap
(C++20)
 将一个最大堆变成一个按升序排序的元素范围
(niebloid)
最小/最大操作
定义于头文件 <algorithm>
max
 返回各给定值中的较大者
(函数模板)
ranges::max
(C++20)
 返回给定值的较大者
(niebloid)
max_element
 返回范围内的最大元素
(函数模板)
ranges::max_element
(C++20)
 返回范围中的最大元素
(niebloid)
min
 返回各给定值中的较小者
(函数模板)
ranges::min
(C++20)
 返回给定值的较小者
(niebloid)
min_element
 返回范围内的最小元素
(函数模板)
ranges::min_element
(C++20)
 返回范围中的最小元素
(niebloid)
minmax
(C++11)
 返回两个元素的较小和较大者
(函数模板)
ranges::minmax
(C++20)
 返回两个元素的较小和较大者
(niebloid)
minmax_element
(C++11)
 返回范围内的最小元素和最大元素
(函数模板)
ranges::minmax_element
(C++20)
 返回范围中的最小和最大元素
(niebloid)
clamp
(C++17)
 在一对边界值间夹逼一个值
(函数模板)
ranges::clamp
(C++20)
 在一对边界值间夹一个值
(niebloid)
比较操作
定义于头文件 <algorithm>
equal
 确定两个元素集合是否是相同的
(函数模板)
ranges::equal
(C++20)
 确定两个元素集合是否是相同的
(niebloid)
lexicographical_compare
 当一个范围按字典顺序小于另一个范围时，返回 true
(函数模板)
ranges::lexicographical_compare
(C++20)
 当一个范围按字典顺序小于另一个范围时，返回 true
(niebloid)
lexicographical_compare_three_way
(C++20)
 用三路比较比较两个范围
(函数模板)
排列操作
定义于头文件 <algorithm>
is_permutation
(C++11)
 判断一个序列是否为另一个序列的排列
(函数模板)
ranges::is_permutation
(C++20)
 确定一个序列是否为另一序列的重排
(niebloid)
next_permutation
 产生某个元素范围的按字典顺序的下一个较大的排列
(函数模板)
ranges::next_permutation
(C++20)
 产生某个元素范围的按字典序下一个较大的排列
(niebloid)
prev_permutation
 产生某个元素范围的按字典顺序的下一个较小的排列
(函数模板)
ranges::prev_permutation
(C++20)
 产生某个元素范围的按字典序下一个较小的排列
(niebloid)
数值运算
定义于头文件 <numeric>
iota
(C++11)
 用从起始值开始连续递增的值填充一个范围
(函数模板)
accumulate
 对一个范围内的元素求和
(函数模板)
inner_product
 计算两个范围的元素的内积
(函数模板)
adjacent_difference
 计算范围内各相邻元素之间的差
(函数模板)
partial_sum
 计算范围内元素的部分和
(函数模板)
reduce
(C++17)
 类似 std::accumulate，但不依序执行
(函数模板)
exclusive_scan
(C++17)
 类似 std::partial_sum，第 i 个和中排除第 i 个输入
(函数模板)
inclusive_scan
(C++17)
 类似 std::partial_sum，第 i 个和中包含第 i 个输入
(函数模板)
transform_reduce
(C++17)
 应用一个函数对象，然后以乱序规约
(函数模板)
transform_exclusive_scan
(C++17)
 应用一个函数对象，然后进行排除扫描
(函数模板)
transform_inclusive_scan
(C++17)
 应用一个函数对象，然后进行包含扫描
(函数模板)
未初始化内存上的操作
定义于头文件 <memory>
uninitialized_copy
 将范围内的对象复制到未初始化的内存区域
(函数模板)
ranges::uninitialized_copy
(C++20)
 复制元素范围到未初始化的内存区域
(niebloid)
uninitialized_copy_n
(C++11)
 将指定数量的对象复制到未初始化的内存区域
(函数模板)
ranges::uninitialized_copy_n
(C++20)
 复制一定量元素到未初始化的内存区域
(niebloid)
uninitialized_fill
 复制一个对象到以范围定义的未初始化内存区域
(函数模板)
ranges::uninitialized_fill
(C++20)
 复制一个对象到范围所定义的未初始化的内存区域
(niebloid)
uninitialized_fill_n
 复制一个对象到以起点和计数定义的未初始化内存区域
(函数模板)
ranges::uninitialized_fill_n
(C++20)
 复制一个对象到起始与计数所定义的未初始化的内存区域
(niebloid)
uninitialized_move
(C++17)
 移动一个范围的对象到未初始化的内存区域
(函数模板)
ranges::uninitialized_move
(C++20)
 移动对象范围到未初始化的内存区域
(niebloid)
uninitialized_move_n
(C++17)
 移动一定数量对象到未初始化内存区域
(函数模板)
ranges::uninitialized_move_n
(C++20)
 移动一定量对象到未初始化的内存区域
(niebloid)
uninitialized_default_construct
(C++17)
 在范围所定义的未初始化的内存区域以默认初始化构造对象
(函数模板)
ranges::uninitialized_default_construct
(C++20)
 在范围所定义的未初始化的内存区域以默认初始化构造对象
(niebloid)
uninitialized_default_construct_n
(C++17)
 在起始和计数所定义的未初始化内存区域用默认初始化构造对象
(函数模板)
ranges::uninitialized_default_construct_n
(C++20)
 在起始与计数所定义的未初始化的内存区域以默认初始化构造对象
(niebloid)
uninitialized_value_construct
(C++17)
 在范围所定义的未初始化内存中用值初始化构造对象
(函数模板)
ranges::uninitialized_value_construct
(C++20)
 在范围所定义的未初始化的内存区域以值初始化构造对象
(niebloid)
uninitialized_value_construct_n
(C++17)
 在起始和计数所定义的未初始化内存区域以值初始化构造对象
(函数模板)
ranges::uninitialized_value_construct_n
(C++20)
 在起始与计数所定义的未初始化的内存区域以值初始化构造对象
(niebloid)
destroy
(C++17)
 销毁一个范围中的对象
(函数模板)
ranges::destroy
(C++20)
 销毁范围中的元素
(niebloid)
destroy_n
(C++17)
 销毁范围中一定数量的对象
(函数模板)
ranges::destroy_n
(C++20)
 销毁范围中一定量的元素
(niebloid)
destroy_at
(C++17)
 销毁在给定地址的对象
(函数模板)
ranges::destroy_at
(C++20)
 销毁位于给定地址的元素
(niebloid)
construct_at
(C++20)
 在给定地址创建对象
(函数模板)
ranges::construct_at
(C++20)
 在给定地址创建对象
(niebloid)
C 库
定义于头文件 <cstdlib>
qsort
 对未指定类型的元素的一个范围进行排序
(函数)
bsearch
 在未指定类型的数组中搜索元素
(函数)

参阅


std::accumulate

< cpp‎ | algorithm
定义于头文件 <numeric> |
 | (1)
template< class InputIt, class T > T accumulate( InputIt first, InputIt last, T init ); |  | (C++20 前)
template< class InputIt, class T > constexpr T accumulate( InputIt first, InputIt last, T init ); |  | (C++20 起)
 | (2)
template< class InputIt, class T, class BinaryOperation > T accumulate( InputIt first, InputIt last, T init, BinaryOperation op ); |  | (C++20 前)
template< class InputIt, class T, class BinaryOperation > constexpr T accumulate( InputIt first, InputIt last, T init, BinaryOperation op ); |  | (C++20 起)

计算给定值 init 与给定范围 [first, last) 中元素的和。第一版本用 operator+ ，第二版本用二元函数 op 求和元素，均将 std::move 应用到其左侧运算数 (C++20 起)。

op 必须无副作用。 | (C++11 前)
op 必须不非法化涉及范围的任何迭代器，含尾迭代器，且不修改其所涉及范围的任何元素及 *last 。 | (C++11 起)

参数

first, last | - | 要求和的元素范围
init | - | 和的初值
op | - | 被使用的二元函数对象。接收当前积累值 a （初始化为 init ）和当前元素 b 的二元运算符。 该函数的签名应当等价于： Ret fun(const Type1 &a, const Type2 &b); 签名中并不需要有 const &。 类型 Type1 必须使得 T 类型的对象能隐式转换到 Type1 。类型 Type2 必须使得 InputIt 类型的对象能在解引用后隐式转换到 Type2 。 类型 Ret 必须使得 T 类型对象能被赋 Ret 类型值。 ​
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- T 必须满足可复制赋值 (CopyAssignable) 和 可复制构造 (CopyConstructible) 的要求。

返回值

1) 给定值与给定范围中的元素的和。
2) 给定范围在 op 上左折叠的结果

注解

std::accumulate 进行左折叠。为进行右折叠，必须逆转二元运算符的参数顺序，并使用逆序迭代器。

最常见的错误

在 init 的类型上进行 op ，这能引入不期望的元素转换，例如 std::accumulate(v.begin(), v.end(), 0) 在 v 为 std::vector <double> 时给出错误的结果。

可能的实现

版本一
template<class InputIt, class T>
constexpr // C++20 起
T accumulate(InputIt first, InputIt last, T init)
{
    for (; first != last; ++first) {
        init = std::move(init) + *first; // C++20 起有 std::move
    }
    return init;
}
版本二
template<class InputIt, class T, class BinaryOperation>
constexpr // C++20 起
T accumulate(InputIt first, InputIt last, T init,
             BinaryOperation op)
{
    for (; first != last; ++first) {
        init = op(std::move(init), *first); // C++20 起有 std::move
    }
    return init;
}

示例

#include <iostream>
#include <vector>
#include <numeric>
#include <string>
#include <functional>

int main()
{
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    int sum = std::accumulate(v.begin(), v.end(), 0);

    int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());

    auto dash_fold = [](std::string a, int b) {
                         return std::move(a) + '-' + std::to_string(b);
                     };

    std::string s = std::accumulate(std::next(v.begin()), v.end(),
                                    std::to_string(v[0]), // 用首元素开始
                                    dash_fold);

    // 使用逆向迭代器右折叠
    std::string rs = std::accumulate(std::next(v.rbegin()), v.rend(),
                                     std::to_string(v.back()), // 用首元素开始
                                     dash_fold);

    std::cout << "sum: " << sum << '\n'
              << "product: " << product << '\n'
              << "dash-separated string: " << s << '\n'
              << "dash-separated string (right-folded): " << rs << '\n';
}

输出：

sum: 55
product: 3628800
dash-separated string: 1-2-3-4-5-6-7-8-9-10
dash-separated string (right-folded): 10-9-8-7-6-5-4-3-2-1

参阅

adjacent_difference | 计算范围内各相邻元素之间的差 (函数模板)
inner_product | 计算两个范围的元素的内积 (函数模板)
partial_sum | 计算范围内元素的部分和 (函数模板)
reduce (C++17) | 类似 std::accumulate，但不依序执行 (函数模板)


std::adjacent_difference

< cpp‎ | algorithm
定义于头文件 <numeric>
(1)
template< class InputIt, class OutputIt >

OutputIt adjacent_difference( InputIt first, InputIt last,

OutputIt d_first );
 (C++20 前)
template< class InputIt, class OutputIt >

constexpr OutputIt adjacent_difference( InputIt first, InputIt last,

OutputIt d_first );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >

ForwardIt2 adjacent_difference( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 d_first );
 (2) (C++17 起)
(3)
template< class InputIt, class OutputIt, class BinaryOperation >

OutputIt adjacent_difference( InputIt first, InputIt last,

OutputIt d_first, BinaryOperation op );
 (C++20 前)
template< class InputIt, class OutputIt, class BinaryOperation >

constexpr OutputIt adjacent_difference( InputIt first, InputIt last,

OutputIt d_first, BinaryOperation op );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class BinaryOperation >

ForwardIt2 adjacent_difference( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 d_first, BinaryOperation op );
 (4) (C++17 起)

计算 [first, last) 范围中每对相邻元素的第二个和第一个的差，并写入它们到始于 d_first + 1 的范围。写入不修改的 *first 副本到 *d_first 。

1,3) 首先，创建类型为 InputIt 的 value_type 的积累器 acc ，以 *first 初始化，并赋值为 *d_first 的结果。然后，对于 [first + 1, last) 中按顺序的每个迭代器 i ，创建类型为 InputIt 的 value_type 的对象 val ，以 *i 初始化，计算 val - acc (C++20 前)val - std::move(acc) (C++20 起) （重载 (1) ）或 op(val, acc) (C++20 前)op(val, std::move(acc)) (C++20 起) （重载 (3) ），赋值结果到 *(d_first + (i - first)) ，并从 val 移动赋值到 acc 。
first 可以等于 d_first 。
2,4) 进行 *d_first = *first; 。对每个 [1, last - first - 1] 中的 d ，赋值 *(first + d) - *(first + d - 1) （重载 (2) ）或 op(*(first + d), *(first + d - 1)) （重载 (4) ）给 *(d_first + d) 。按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。。
若输入与输出范围以任何方式重叠则行为未定义。

等价操作：

*(d_first)   = *first;
*(d_first+1) = *(first+1) - *(first);
*(d_first+2) = *(first+2) - *(first+1);
*(d_first+3) = *(first+3) - *(first+2);
...
op 必须无副效应。 | (C++11 前)
op 必须不非法化涉及范围的任何迭代器，含尾迭代器，或修改该范围的任何元素。 | (C++11 起)

参数

first, last - 元素范围
d_first - 目标范围的起始
policy - 所用的执行策略。细节见执行策略。
op - 被使用的二元函数对象。

该函数的签名应当等价于：

Ret fun(const Type1 &a, const Type2 &b);

签名中并不需要有 const &。
类型 Type1 与 Type2 必须使得 iterator_traits<InputIt>::value_type 类型的对象能隐式转换到这两个类型。 类型 Ret 必须使得 OutputIt 类型对象能被解引用并能被赋 Ret 类型值。 ​
类型要求
-
InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。InputIt 的值类型必须可移动赋值 (MoveAssignable) 且可从 *first 的类型构造
-
OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。acc （积累的值）和 val - acc 或 op(val, acc) (C++20 前)val - std::move(acc) 或 op(val, std::move(acc)) (C++20 起) 结果都必须可写入 OutputIt
-
ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。*first 、 *first - *first （对于 (2) ）和 op(*first, *first) （对于 (4) ）的结果必须可写入 ForwardIt2 。

返回值

指向最后被写入元素后一位置的迭代器。

注解

若 first == last ，则此函数无效果并且只会返回 d_first 。

复杂度

恰好应用 (last - first) - 1 次二元运算。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class InputIt, class OutputIt>
constexpr // C++20 起
OutputIt adjacent_difference(InputIt first, InputIt last,
                             OutputIt d_first)
{
    if (first == last) return d_first;

    typedef typename std::iterator_traits<InputIt>::value_type value_t;
    value_t acc = *first;
    *d_first = acc;
    while (++first != last) {
        value_t val = *first;
        *++d_first = val - std::move(acc); // C++20 起有 std::move
        acc = std::move(val);
    }
    return ++d_first;
}
版本二
template<class InputIt, class OutputIt, class BinaryOperation>
constexpr // C++20 起
OutputIt adjacent_difference(InputIt first, InputIt last,
                             OutputIt d_first, BinaryOperation op)
{
    if (first == last) return d_first;

    typedef typename std::iterator_traits<InputIt>::value_type value_t;
    value_t acc = *first;
    *d_first = acc;
    while (++first != last) {
        value_t val = *first;
        *++d_first = op(val, std::move(acc)); // C++20 起有 std::move
        acc = std::move(val);
    }
    return ++d_first;
}

示例

#include <numeric>
#include <vector>
#include <iostream>
#include <functional>

int main()
{
    // 默认实现——二个项之间的差

    std::vector<int> v{2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
    std::adjacent_difference(v.begin(), v.end(), v.begin());

    for (auto n : v) {
        std::cout << n << ' ';
    }
    std::cout << '\n';

    // 斐波那契
    // 注意，列表中下一项是当前迭代的结果

    v = std::vector<int>(10);
    v[0] = 1;

    std::adjacent_difference(v.begin(), v.end() - 1, v.begin() + 1, std::plus<int>());

    for (auto n : v) {
        std::cout << n << ' ';
    }
    std::cout << '\n';
}

输出：

2 2 2 2 2 2 2 2 2 2
1 1 2 3 5 8 13 21 34 55

参阅

partial_sum | 计算范围内元素的部分和 (函数模板)
accumulate | 对一个范围内的元素求和 (函数模板)


std::adjacent_find

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class ForwardIt >
ForwardIt adjacent_find( ForwardIt first, ForwardIt last );
 (C++20 前)
template< class ForwardIt >
constexpr ForwardIt adjacent_find( ForwardIt first, ForwardIt last );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt >

ForwardIt adjacent_find( ExecutionPolicy&& policy,

ForwardIt first, ForwardIt last );
 (2) (C++17 起)
(3)
template< class ForwardIt, class BinaryPredicate>
ForwardIt adjacent_find( ForwardIt first, ForwardIt last, BinaryPredicate p );
 (C++20 前)
template< class ForwardIt, class BinaryPredicate>
constexpr ForwardIt adjacent_find( ForwardIt first, ForwardIt last, BinaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class BinaryPredicate>

ForwardIt adjacent_find( ExecutionPolicy&& policy,

ForwardIt first, ForwardIt last, BinaryPredicate p );
 (4) (C++17 起)

在范围 [first, last) 中搜索二个相继的相等元素。

1) 用 operator== 比较元素。
3) 用给定的二元谓词 p 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要检验的元素范围
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若元素应被当做相等则返回 ​true 的二元谓词。 谓词函数的签名应等价于如下： bool pred(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 ForwardIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

指向首对等同元素的首个元素的迭代器，即首个满足 *it == *(it+1) （第一版本）或 p(*it, *(it + 1)) != false（第二版本） 的迭代器 it 。

若找不到这种元素，则返回 last 。

复杂度

1,3) 准确应用 min((result-first)+1, (last-first)-1) 次谓词，其中 result 是返回值。
2,4) 应用 O(last-first) 次对应的谓词。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class ForwardIt>
ForwardIt adjacent_find(ForwardIt first, ForwardIt last)
{
    if (first == last) {
        return last;
    }
    ForwardIt next = first;
    ++next;
    for (; next != last; ++next, ++first) {
        if (*first == *next) {
            return first;
        }
    }
    return last;
}
版本二
template<class ForwardIt, class BinaryPredicate>
ForwardIt adjacent_find(ForwardIt first, ForwardIt last,
                        BinaryPredicate p)
{
    if (first == last) {
        return last;
    }
    ForwardIt next = first;
    ++next;
    for (; next != last; ++next, ++first) {
        if (p(*first, *next)) {
            return first;
        }
    }
    return last;
}

示例

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v1{0, 1, 2, 3, 40, 40, 41, 41, 5};

    auto i1 = std::adjacent_find(v1.begin(), v1.end());

    if (i1 == v1.end()) {
        std::cout << "no matching adjacent elements\n";
    } else {
        std::cout << "the first adjacent pair of equal elements at: "
                  << std::distance(v1.begin(), i1) << '\n';
    }

    auto i2 = std::adjacent_find(v1.begin(), v1.end(), std::greater<int>());
    if (i2 == v1.end()) {
        std::cout << "The entire vector is sorted in ascending order\n";
    } else {
        std::cout << "The last element in the non-decreasing subsequence is at: "
                  << std::distance(v1.begin(), i2) << '\n';
    }
}

输出：

The first adjacent pair of equal elements at: 4
The last element in the non-decreasing subsequence is at: 7

参阅

unique
 移除范围内的连续重复元素
(函数模板)


std::all_of, std::any_of, std::none_of

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class InputIt, class UnaryPredicate > bool all_of( InputIt first, InputIt last, UnaryPredicate p ); |  |  | (C++11 起) (C++20 前)
template< class InputIt, class UnaryPredicate > constexpr bool all_of( InputIt first, InputIt last, UnaryPredicate p ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate > bool all_of( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryPredicate p ); | (2) | (C++17 起)
 | (3) |
template< class InputIt, class UnaryPredicate > bool any_of( InputIt first, InputIt last, UnaryPredicate p ); |  |  | (C++11 起) (C++20 前)
template< class InputIt, class UnaryPredicate > constexpr bool any_of( InputIt first, InputIt last, UnaryPredicate p ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate > bool any_of( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryPredicate p ); | (4) | (C++17 起)
 | (5) |
template< class InputIt, class UnaryPredicate > bool none_of( InputIt first, InputIt last, UnaryPredicate p ); |  |  | (C++11 起) (C++20 前)
template< class InputIt, class UnaryPredicate > constexpr bool none_of( InputIt first, InputIt last, UnaryPredicate p ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate > bool none_of( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryPredicate p ); | (6) | (C++17 起)
1) 检查一元谓词 p 是否对范围 [first, last) 中所有元素返回 true 。
3) 检查一元谓词 p 是否对范围 [first, last) 中至少一个元素返回 true 。
5) 检查一元谓词 p 是否不对范围 [first, last) 中任何元素返回 true 。
2,4,6) 同 (1,3,5) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要检验的元素范围
policy | - | 所用的执行策略。细节见执行策略。
p | - | 一元谓词。 对每个（可为 const 的） VT 类型参数 v ，其中 VT 是 InputIt 的值类型，表达式 p(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 VT& 类型参数，亦不允许 VT ，除非对 VT 而言移动等价于复制 (C++11 起)。 ​
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- UnaryPredicate 必须满足谓词 (Predicate) 的要求。

返回值

1-2) 若一元谓词对范围中所有元素返回 true 则为 true ，否则为 false 。若范围为空则返回 true 。
3-4) 若一元谓词对范围中至少一个元素返回 true 则为 true ，否则为 false 。若范围为空则返回 false 。
5-6) 若一元谓词不对范围中任何元素返回 true 则为 true ，否则为 false 。若范围为空则返回 true 。

复杂度

1,3,5) 至多应用谓词 last - first 次
2,4,6) 应用谓词 O(last-first) 次

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

参阅 all_of 在 libstdc++ 与 libc++ 中的实现。

参阅 any_of 在 libstdc++ 与 libc++ 中的实现。

参阅 none_of 在 libstdc++ 与 libc++ 中的实现。

版本一
template< class InputIt, class UnaryPredicate >
bool all_of(InputIt first, InputIt last, UnaryPredicate p)
{
    return std::find_if_not(first, last, p) == last;
}
版本二
template< class InputIt, class UnaryPredicate >
bool any_of(InputIt first, InputIt last, UnaryPredicate p)
{
    return std::find_if(first, last, p) != last;
}
版本三
template< class InputIt, class UnaryPredicate >
bool none_of(InputIt first, InputIt last, UnaryPredicate p)
{
    return std::find_if(first, last, p) == last;
}

示例

#include <vector>
#include <numeric>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <functional>

int main()
{
    std::vector<int> v(10, 2);
    std::partial_sum(v.cbegin(), v.cend(), v.begin());
    std::cout << "Among the numbers: ";
    std::copy(v.cbegin(), v.cend(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';

    if (std::all_of(v.cbegin(), v.cend(), [](int i){ return i % 2 == 0; })) {
        std::cout << "All numbers are even\n";
    }
    if (std::none_of(v.cbegin(), v.cend(), std::bind(std::modulus<int>(),
                                                     std::placeholders::_1, 2))) {
        std::cout << "None of them are odd\n";
    }
    struct DivisibleBy
    {
        const int d;
        DivisibleBy(int n) : d(n) {}
        bool operator()(int n) const { return n % d == 0; }
    };

    if (std::any_of(v.cbegin(), v.cend(), DivisibleBy(7))) {
        std::cout << "At least one number is divisible by 7\n";
    }
}

输出：

Among the numbers: 2 4 6 8 10 12 14 16 18 20
All numbers are even
None of them are odd
At least one number is divisible by 7

参阅

ranges::all_ofranges::any_ofranges::none_of
(C++20)(C++20)(C++20)
 检查谓词是否对范围中所有、任一或无元素为 true
(niebloid)


std::binary_search

< cpp‎ | algorithm
定义于头文件 <algorithm> |
 | (1)
template< class ForwardIt, class T > bool binary_search( ForwardIt first, ForwardIt last, const T& value ); |  | (C++20 前)
template< class ForwardIt, class T > constexpr bool binary_search( ForwardIt first, ForwardIt last, const T& value ); |  | (C++20 起)
 | (2)
template< class ForwardIt, class T, class Compare > bool binary_search( ForwardIt first, ForwardIt last, const T& value, Compare comp ); |  | (C++20 前)
template< class ForwardIt, class T, class Compare > constexpr bool binary_search( ForwardIt first, ForwardIt last, const T& value, Compare comp ); |  | (C++20 起)

检查等价于 value 的元素是否出现于范围 [first, last) 中。

对于要成功的 std::binary_search ，范围 [first, last) 必须至少相对于 value 部分有序，即它必须满足下列所有要求：

  • 已相对 element < value 或 comp(element, value) 划分
  • 已相对 !(value < element) 或 !comp(value, element) 划分（即所有令此表达式为 true 的元素必须前趋所有令此表达式为 false 的元素）
  • 对于所有元素，若 element < value 或 comp(element, value) 为 true ，则 !(value < element) 或 !comp(value, element) 亦为 true

完全排序的范围满足这些判别标准。

第一版本用 operator< 比较元素，第二版本用给定的比较函数 comp 。

参数

first, last | - | 要检验的元素范围
value | - | 要与元素比较的值
comp | - | 若第一参数小于（即先序于）第二个则返回 ​true 的二元谓词。 谓词函数的签名应等价于如下： bool pred(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 必须使得 ForwardIt 类型的对象能在解引用后隐式转换到 Type1 。类型 Type2 必须使得 T 类型的对象能隐式转换到 Type2 。 ​
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- Compare 必须满足二元谓词 (BinaryPredicate) 的要求。不要求满足 比较 (Compare) 。

返回值

若找到等于 value 的元素则为 true ，否则为 false 。

复杂度

进行的比较次数与 first 和 last 间的距离成对数（至多 log
2(last - first) + O(1) 次比较）。然而，对于非老式随机访问迭代器 (LegacyRandomAccessIterator) ，迭代次自增次数为线性。

可能的实现

版本一
template<class ForwardIt, class T>
bool binary_search(ForwardIt first, ForwardIt last, const T& value)
{
    first = std::lower_bound(first, last, value);
    return (!(first == last) && !(value < *first));
}
版本二
template<class ForwardIt, class T, class Compare>
bool binary_search(ForwardIt first, ForwardIt last, const T& value, Compare comp)
{
    first = std::lower_bound(first, last, value, comp);
    return (!(first == last) && !(comp(value, *first)));
}

示例

#include <iostream>
#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> haystack {1, 3, 4, 5, 9};
    std::vector<int> needles {1, 2, 3};

    for (auto needle : needles) {
        std::cout << "Searching for " << needle << '\n';
        if (std::binary_search(haystack.begin(), haystack.end(), needle)) {
            std::cout << "Found " << needle << '\n';
        } else {
            std::cout << "no dice!\n";
        }
    }
}

输出：

Searching for 1
Found 1
Searching for 2
no dice!
Searching for 3
Found 3

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 270 | C++98 | 曾要求 Compare 为严格弱序 | 只需要划分；容许异相比较

参阅

equal_range
 返回匹配特定键值的元素范围
(函数模板)


std::bsearch

< cpp‎ | algorithm
定义于头文件 <cstdlib>
void* bsearch( const void* key, const void* ptr, std::size_t count,

std::size_t size, /*compare-pred*/* comp );
void* bsearch( const void* key, const void* ptr, std::size_t count,

std::size_t size, /*c-compare-pred*/* comp );
 (1)
extern "C++" using /*compare-pred*/ = int(const void*, const void*); // 仅用于阐释
extern "C" using /*c-compare-pred*/ = int(const void*, const void*); // 仅用于阐释
 (2)

在 ptr 所指向的数组中寻找等于 key 所指向的元素的元素。数组含有 count 个 size 字节的元素，且必须相对于 key 所指向的对象划分，即所有比较小于它的元素必须先出现于比较等于它的元素，而比较等于它者必须先出现于所有比较大于该关键对象的元素。完全排序的数组满足这些要求。用 comp 所指的函数比较数组元素。

若数组未以按照 comp 所用的相同原则相对于 key 升序划分则行为未定义。

若数组含有数个 comp 会指示等于被搜索元素的元素，则函数返回哪个元素是未指定的。

参数

key | - | 指向要搜索的元素的指针
ptr | - | 指向要检验的数组的指针
count | - | 数组中元素的数量
size | - | 数组中每个元素的大小，以字节表示
comp | - | 比较函数。若首个参数小于第二个，则返回负整数值，若首个参数大于第二个，则返回正整数值，若两参数等价，则返回零。作为首参数传递 key ，作为第二参数传递来自数组的元素。 比较函数的签名应等价于如下形式： int cmp(const void *a, const void *b); 该函数必须不修改传递给它的对象，而且在调用比较相同对象时必须返回一致的结果，无关乎它们在数组中的位置。 ​

返回值

指向找到的元素的指针，或若找不到元素则为空指针。

注解

无关乎名称， C 或 POSIX 标准都不要求此函数用二分查找实现，或进行任何复杂度保证。

C++ 标准库提供的二个重载不同，因为参数 comp 类型有别（语言链接是类型的一部分）。

示例

#include <iostream>
#include <cstdlib>
#include <array>

template <typename T>
int compare(const void *a, const void *b) {
    const auto &arg1 = *(static_cast<const T*>(a));
    const auto &arg2 = *(static_cast<const T*>(b));
    const auto cmp = arg1 <=> arg2;
    return cmp < 0 ? -1
        :  cmp > 0 ? +1
        :  0;
}

int main() {
    std::array arr { 1, 2, 3, 4, 5, 6, 7, 8 };

    for (const int key : { 4, 8, 9 }) {

        const int* p = static_cast<int*>(
            std::bsearch(&key,
                arr.data(),
                arr.size(),
                sizeof(decltype(arr)::value_type),
                compare<int>));

        std::cout << "value " << key;
        (p) ? std::cout << " found at position " << (p - arr.data()) << '\n'
            : std::cout << " not found\n";
    }
}

输出：

value 4 found at position 3
value 8 found at position 7
value 9 not found

参阅

qsort | 对未指定类型的元素的一个范围进行排序 (函数)
equal_range | 返回匹配特定键值的元素范围 (函数模板)


std::clamp

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
template<class T> constexpr const T& clamp( const T& v, const T& lo, const T& hi ); | (1) | (C++17 起)
template<class T, class Compare> constexpr const T& clamp( const T& v, const T& lo, const T& hi, Compare comp ); | (2) | (C++17 起)
1) 若 v 小于 lo ，则返回 lo ；若 v 大于 hi ，则返回 hi ；否则返回 v 。使用 operator< 比较值。
2) 同 (1) ，不过使用 comp 比较值。

若 lo 的值大于 hi 则行为未定义。

参数

v | - | 要夹住的值
lo,hi | - | 夹 v 的边界
comp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若 lo 小于 v 且 v 小于 hi，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 T 类型的对象能隐式转换到这两个类型。 ​
类型要求
- 为使用重载 (1) ， T 必须满足可小于比较 (LessThanComparable) 的要求。然而若避免了 NaN ，则 T 能为浮点类型。

返回值

若 v 小于 lo 到则为 lo 的引用，若 hi 小于 v 则为到 hi 的引用，否则为到 v 的引用。

复杂度

至多二次比较

可能的实现

版本一
template<class T>
constexpr const T& clamp( const T& v, const T& lo, const T& hi )
{
    assert( !(hi < lo) );
    return v < lo ? lo : hi < v ? hi : v;
}
版本二
template<class T, class Compare>
constexpr const T& clamp( const T& v, const T& lo, const T& hi, Compare comp )
{
    assert( !comp(hi, lo) );
    return comp(v, lo) ? lo : comp(hi, v) ? hi : v;
}

注解

若参数之一是临时量，而该参数被返回，则以引用捕获 std::clamp 的结果会产生一个悬垂引用：
int n = -1;
const int& r = std::clamp(n, 0, 255);
// r 悬垂

若 v 与边界之一比较相等，则返回到 v 的引用，而非到边界者。

示例

#include <cstdint>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <random>

int main()
{
    std::mt19937 g(std::random_device{}());
    std::uniform_int_distribution<> d(-300, 300);
    std::cout << " raw   clamped to int8_t   clamped to uint8_t\n";
    for(int n = 0; n < 5; ++n) {
        int v = d(g);
        std::cout << std::setw(4) << v
                  << std::setw(20) << std::clamp(v, INT8_MIN, INT8_MAX)
                  << std::setw(21) << std::clamp(v, 0, UINT8_MAX) << '\n';
    }
}

可能的输出：

.raw   clamped to int8_t   clamped to uint8_t
 168                 127                  168
 128                 127                  128
-137                -128                    0
  40                  40                   40
 -66                 -66                    0

参阅

min | 返回各给定值中的较小者 (函数模板)
max | 返回各给定值中的较大者 (函数模板)
in_range (C++20) | 检查整数值是否在给定整数类型的范围内 (函数模板)
ranges::clamp (C++20) | 在一对边界值间夹一个值 (niebloid)


std::copy, std::copy_if

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class InputIt, class OutputIt > OutputIt copy( InputIt first, InputIt last, OutputIt d_first ); |  |  | (C++20 前)
template< class InputIt, class OutputIt > constexpr OutputIt copy( InputIt first, InputIt last, OutputIt d_first ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 > ForwardIt2 copy( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last, ForwardIt2 d_first ); | (2) | (C++17 起)
 | (3) |
template< class InputIt, class OutputIt, class UnaryPredicate > OutputIt copy_if( InputIt first, InputIt last, OutputIt d_first, UnaryPredicate pred ); |  |  | (C++11 起) (C++20 前)
template< class InputIt, class OutputIt, class UnaryPredicate > constexpr OutputIt copy_if( InputIt first, InputIt last, OutputIt d_first, UnaryPredicate pred ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class UnaryPredicate > ForwardIt2 copy_if( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last, ForwardIt2 d_first, UnaryPredicate pred ); | (4) | (C++17 起)

复制 [first, last) 所定义的范围中的元素到始于 d_first 的另一范围。

1) 复制范围 [first, last) 中的所有元素，从首元素开始逐次到末元素。若 d_first 在范围 [first, last) 中则行为未定义。此情况下可用 std::copy_backward 代替。
3) 仅复制谓词 pred 对其返回 true 的元素。保持被复制元素的相对顺序。若源与目标范围重叠则行为未定义。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要复制的元素范围
d_first | - | 目标范围的起始。
policy | - | 所用的执行策略。细节见执行策略。
pred | - | 对所要求的元素则返回 ​true 的一元谓词。 对每个（可为 const 的） VT 类型参数 v ，其中 VT 是 InputIt 的值类型，表达式 pred(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 VT& 类型参数，亦不允许 VT ，除非对 VT 而言移动等价于复制 (C++11 起)。 ​
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- UnaryPredicate 必须满足谓词 (Predicate) 的要求。

返回值

指向目标范围中最后复制元素的下个元素的输出迭代器。

复杂度

1-2) 准确赋值 (last - first) 次
3-4) 准确应用 (last - first) 次谓词， ​0​ 和 (last - first) 之间次赋值（对于每个谓词返回 true 的元素赋值，取决于谓词和输入数据）

对于带 ExecutionPolicy 的重载，若 ForwardIt1 的值类型非可移动构造 (MoveConstructible) 则有性能开销。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

实践中，若 value_type 为可平凡复制 (TriviallyCopyable) 而迭代器类型满足老式连续迭代器 (LegacyContiguousIterator) ，则 std::copy 避免多次赋值并使用大批量复制函数，如 std::memmove 。

复制重叠的范围时， std::copy 在复制到左侧（目标范围起始在源范围之外）时适合，而 std::copy_backward 在复制到右侧（目标范围结尾在源范围之外）时适合。

可能的实现

版本一
template<class InputIt, class OutputIt>
OutputIt copy(InputIt first, InputIt last,
              OutputIt d_first)
{
    while (first != last) {
        *d_first++ = *first++;
    }
    return d_first;
}
版本二
template<class InputIt, class OutputIt, class UnaryPredicate>
OutputIt copy_if(InputIt first, InputIt last,
                 OutputIt d_first, UnaryPredicate pred)
{
    while (first != last) {
        if (pred(*first))
            *d_first++ = *first;
        ++first;
    }
    return d_first;
}

示例

下列代码用 copy 复制一个 vector 的内容到另一个，并显示结果 vector ：

#include <algorithm>
#include <iostream>
#include <vector>
#include <iterator>
#include <numeric>

int main()
{
    std::vector<int> from_vector(10);
    std::iota(from_vector.begin(), from_vector.end(), 0);

    std::vector<int> to_vector;
    std::copy(from_vector.begin(), from_vector.end(),
              std::back_inserter(to_vector));
// 或可选地，
//  std::vector<int> to_vector(from_vector.size());
//  std::copy(from_vector.begin(), from_vector.end(), to_vector.begin());
// 任一方式都等价于
//  std::vector<int> to_vector = from_vector;

    std::cout << "to_vector contains: ";

    std::copy(to_vector.begin(), to_vector.end(),
              std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';

    std::cout << "odd numbers in to_vector are: ";

    std::copy_if(to_vector.begin(), to_vector.end(),
                 std::ostream_iterator<int>(std::cout, " "),
                 [](int x) { return (x % 2) == 1; });
    std::cout << '\n';
}

输出：

to_vector contains: 0 1 2 3 4 5 6 7 8 9
odd numbers in to_vector are: 1 3 5 7 9

参阅

copy_backward | 按从后往前的顺序复制一个范围内的元素 (函数模板)
reverse_copy | 创建一个范围的逆向副本 (函数模板)
copy_n (C++11) | 将一定数目的元素复制到一个新的位置 (函数模板)
fill | 将一个给定值复制赋值给一个范围内的每个元素 (函数模板)
remove_copyremove_copy_if | 复制一个范围的元素，忽略满足特定判别标准的元素 (函数模板)


std::copy_backward

< cpp‎ | algorithm
定义于头文件 <algorithm> |
template< class BidirIt1, class BidirIt2 > BidirIt2 copy_backward( BidirIt1 first, BidirIt1 last, BidirIt2 d_last ); | (C++20 前)
template< class BidirIt1, class BidirIt2 > constexpr BidirIt2 copy_backward( BidirIt1 first, BidirIt1 last, BidirIt2 d_last ); | (C++20 起)

复制来自 [first, last) 所定义范围的元素，到终于 d_last 的范围。以逆序复制元素（首先复制末元素），但保持其相对顺序。

若 d_last 在 (first, last] 中则行为未定义。该情况下必须用 std::copy 取代 std::copy_backward 。

参数

first, last | - | 要复制的元素范围
d_last | - | 目标范围的结尾。
类型要求
- BidirIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求。

返回值

指向最后复制元素的迭代器。

复杂度

准确赋值 last - first 次。

注意

复制重叠的范围时， std::copy 在复制到左侧（目标范围的起始在源范围外）时适合，而 std::copy_backward 在复制到右侧（目标范围的结尾在源范围外）时适合。

可能的实现

template< class BidirIt1, class BidirIt2 >
BidirIt2 copy_backward(BidirIt1 first, BidirIt1 last, BidirIt2 d_last)
{
    while (first != last) {
        *(--d_last) = *(--last);
    }
    return d_last;
}

示例

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> from_vector;
    for (int i = 0; i < 10; i++) {
        from_vector.push_back(i);
    }

    std::vector<int> to_vector(15);

    std::copy_backward(from_vector.begin(), from_vector.end(), to_vector.end());

    std::cout << "to_vector contains: ";
    for (auto i: to_vector) {
        std::cout << i << " ";
    }
 }

输出：

to_vector contains: 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9

参阅

copycopy_if
(C++11)
 将某一范围的元素复制到一个新的位置
(函数模板)


std::copy_n

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class InputIt, class Size, class OutputIt > OutputIt copy_n( InputIt first, Size count, OutputIt result ); |  |  | (C++11 起) (C++20 前)
template< class InputIt, class Size, class OutputIt > constexpr OutputIt copy_n( InputIt first, Size count, OutputIt result ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class Size, class ForwardIt2 > ForwardIt2 copy_n( ExecutionPolicy&& policy, ForwardIt1 first, Size count, ForwardIt2 result ); | (2) | (C++17 起)
1) 若 count>0 ，则准确复制来自始于 first 的范围的 count 个值到始于 result 的范围。正式而言，对于每个非负整数 i < n 进行 *(result + i) = *(first + i) 。范围的重叠在形式上是允许的，但是会导致结果的顺序不可预测。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。。

参数

first | - | 复制来源的元素范围起始
count | - | 要复制的元素数
result | - | 目标范围起始
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

复制

若 count>0 则为指向目标范围中最后被复制元素后一元素的迭代器，否则为 result 。

复杂度

若 count>0 ，则准确赋值 count 次。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template< class InputIt, class Size, class OutputIt>
OutputIt copy_n(InputIt first, Size count, OutputIt result)
{
    if (count > 0) {
        *result++ = *first;
        for (Size i = 1; i < count; ++i) {
            *result++ = *++first;
        }
    }
    return result;
}

示例

#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>

int main()
{
    std::string in = "1234567890";
    std::string out;

    std::copy_n(in.begin(), 4, std::back_inserter(out));
    std::cout << out << '\n';
}

输出：

1234

参阅

copycopy_if
(C++11)
 将某一范围的元素复制到一个新的位置
(函数模板)


std::count, std::count_if

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class InputIt, class T >

typename iterator_traits<InputIt>::difference_type

count( InputIt first, InputIt last, const T &value );
 (C++20 前)
template< class InputIt, class T >

constexpr typename iterator_traits<InputIt>::difference_type

count( InputIt first, InputIt last, const T &value );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class T >

typename iterator_traits<ForwardIt>::difference_type

count( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, const T &value );
 (2) (C++17 起)
(3)
template< class InputIt, class UnaryPredicate >

typename iterator_traits<InputIt>::difference_type

count_if( InputIt first, InputIt last, UnaryPredicate p );
 (C++20 前)
template< class InputIt, class UnaryPredicate >

constexpr typename iterator_traits<InputIt>::difference_type

count_if( InputIt first, InputIt last, UnaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >

typename iterator_traits<ForwardIt>::difference_type

count_if( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryPredicate p );
 (4) (C++17 起)

返回范围 [first, last) 中满足特定判别标准的元素数。

1) 计数等于 value 的元素。
3) 计数谓词 p 对其返回 true 的元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要检验的元素范围
value | - | 要搜索的值
policy | - | 所用的执行策略。细节见执行策略。
p | - | 对要求的元素则返回 ​true 的一元谓词。 对每个（可为 const 的） VT 类型参数 v ，其中 VT 是 InputIt 的值类型，表达式 p(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 VT& 类型参数，亦不允许 VT ，除非对 VT 而言移动等价于复制 (C++11 起)。 ​
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

满足条件的元素数。

复杂度

准确 last - first 次比较/应用谓词。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

对于无任何额外判别标准的 [first, last) 中的元素数，见 std::distance 。

可能的实现

参阅 count 在 libstdc++ 与 libc++ 中的实现。

参阅 count_if 在 libstdc++ 与 libc++ 中的实现。

版本一
template<class InputIt, class T>
typename iterator_traits<InputIt>::difference_type
    count(InputIt first, InputIt last, const T& value)
{
    typename iterator_traits<InputIt>::difference_type ret = 0;
    for (; first != last; ++first) {
        if (*first == value) {
            ret++;
        }
    }
    return ret;
}
版本二
template<class InputIt, class UnaryPredicate>
typename iterator_traits<InputIt>::difference_type
    count_if(InputIt first, InputIt last, UnaryPredicate p)
{
    typename iterator_traits<InputIt>::difference_type ret = 0;
    for (; first != last; ++first) {
        if (p(*first)) {
            ret++;
        }
    }
    return ret;
}

示例

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{ 1, 2, 3, 4, 4, 3, 7, 8, 9, 10 };

    // 确定 std::vector 中有多少个整数匹配目标值。
    int target1 = 3;
    int target2 = 5;
    int num_items1 = std::count(v.begin(), v.end(), target1);
    int num_items2 = std::count(v.begin(), v.end(), target2);
    std::cout << "number: " << target1 << " count: " << num_items1 << '\n';
    std::cout << "number: " << target2 << " count: " << num_items2 << '\n';

    // 用 lambda 表达式计量能被 3 整除的元素数。
    int num_items3 = std::count_if(v.begin(), v.end(), [](int i){return i % 3 == 0;});
    std::cout << "number divisible by three: " << num_items3 << '\n';
}

输出：

number: 3 count: 2
number: 5 count: 0
number divisible by three: 3

参阅

distance | 返回两个迭代器间的距离 (函数模板)
ranges::countranges::count_if (C++20)(C++20) | 返回满足指定判别标准的元素数 (niebloid)


std::equal

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class InputIt1, class InputIt2 >

bool equal( InputIt1 first1, InputIt1 last1,

InputIt2 first2 );
 (C++20 前)
template< class InputIt1, class InputIt2 >

constexpr bool equal( InputIt1 first1, InputIt1 last1,

InputIt2 first2 );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >

bool equal( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1,

ForwardIt2 first2 );
 (2) (C++17 起)
(3)
template< class InputIt1, class InputIt2, class BinaryPredicate >

bool equal( InputIt1 first1, InputIt1 last1,

InputIt2 first2, BinaryPredicate p );
 (C++20 前)
template< class InputIt1, class InputIt2, class BinaryPredicate >

constexpr bool equal( InputIt1 first1, InputIt1 last1,

InputIt2 first2, BinaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2,

class BinaryPredicate >
bool equal( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1,

ForwardIt2 first2, BinaryPredicate p );
 (4) (C++17 起)
(5)
template< class InputIt1, class InputIt2 >

bool equal( InputIt1 first1, InputIt1 last1,

InputIt2 first2, InputIt2 last2 );
 (C++14 起)
(C++20 前)
template< class InputIt1, class InputIt2 >

constexpr bool equal( InputIt1 first1, InputIt1 last1,

InputIt2 first2, InputIt2 last2 );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >

bool equal( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1,

ForwardIt2 first2, ForwardIt2 last2 );
 (6) (C++17 起)
(7)
template< class InputIt1, class InputIt2, class BinaryPredicate >

bool equal( InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2,

BinaryPredicate p );
 (C++14 起)
(C++20 前)
template< class InputIt1, class InputIt2, class BinaryPredicate >

constexpr bool equal( InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2,

BinaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2,

class BinaryPredicate >
bool equal( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1,
ForwardIt2 first2, ForwardIt2 last2,

BinaryPredicate p );
 (8) (C++17 起)
1,3) 如果范围 [first1, last1) 和范围 [first2, first2 + (last1 - first1)) 相等，返回 true ，否则返回 false
5,7) 如果范围 [first1, last1) 和范围 [first2, last2) 相等，返回 true ，否则返回 false
2,4,6,8) 同 (1,3,5,7) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

两个范围相等的条件是：对于范围 [first1, last1) 内的每个迭代器 i ， *i 等于 *(first2 + (i - first1)) 。重载形式 (1,2,5,6) 用 operator== 判定两个元素是否相等，而重载形式 (3,4,7,8) 用给定的谓词函数。

参数

first1, last1 | - | 进行比较的第一个范围
first2, last2 | - | 进行比较的第二个范围
p | - | 若元素应被当做相等则返回 ​true 的二元谓词。 谓词函数的签名应等价于如下： bool pred(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 InputIt1 与 InputIt2 类型的对象在解引用后分别能隐式转换到 Type1 与 Type2 。 ​
类型要求
- InputIt1, InputIt2 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

5-8) 如果范围 [first1, last1) 的长度不等于范围 [first2, last2) 的长度则返回 false 。

如果两个范围内的元素都相等，则返回 true 。

否则返回 false 。

注解

std::equal 不可应用到由 std::unordered_set 、 std::unordered_multiset 、 std::unordered_map 或 std::unordered_multimap 的迭代器构成的范围，因为即使此类容器存储相同的元素，在容器内元素存储的顺序也可能不同。

比较整个容器是否相等时，针对该容器的 operator== 重载通常是更好的选择。

复杂度

1,2) 最多 last1 - first1 次调用相应的谓词函数。
3,4) 最多 min(last1 - first1, last2 - first2) 次调用相应的谓词函数。

然而，若 InputIt1 和 InputIt2 满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求，且 last1 - first1 != last2 - first2 则不调用谓词函数。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class InputIt1, class InputIt2>
bool equal(InputIt1 first1, InputIt1 last1,
           InputIt2 first2)
{
    for (; first1 != last1; ++first1, ++first2) {
        if (!(*first1 == *first2)) {
            return false;
        }
    }
    return true;
}
版本二
template<class InputIt1, class InputIt2, class BinaryPredicate>
bool equal(InputIt1 first1, InputIt1 last1,
           InputIt2 first2, BinaryPredicate p)
{
    for (; first1 != last1; ++first1, ++first2) {
        if (!p(*first1, *first2)) {
            return false;
        }
    }
    return true;
}
版本三
template<class InputIt1, class InputIt2>
bool equal(InputIt1 first1, InputIt1 last1,
           InputIt2 first2, InputIt2 last2 )
{
    if (distance(first1,last1) != distance(first2,last2)
        return false;
    for (; first1 != last1, first2 != last2; ++first1, ++first2) {
        if (!(*first1 == *first2)) {
            return false;
        }
    }
    return true;
}
版本四
template< class InputIt1, class InputIt2, class BinaryPredicate >
bool equal( InputIt1 first1, InputIt1 last1,
            InputIt2 first2, InputIt2 last2,
            BinaryPredicate p )
{
    if (distance(first1,last1) != distance(first2,last2)
        return false;
    for (; first1 != last1, first2 != last2; ++first1, ++first2) {
        if (!p(*first1, *first2)) {
            return false;
        }
    }
    return true;
}

示例

下面的代码使用 equal() 来测试字符串是否是回文

#include <iostream>
#include <algorithm>
#include <string>

void test(const std::string& s)
{
    if(std::equal(s.begin(), s.begin() + s.size()/2, s.rbegin())) {
        std::cout << "\"" << s << "\" is a palindrome\n";
    } else {
        std::cout << "\"" << s << "\" is not a palindrome\n";
    }
}
int main()
{
    test("radar");
    test("hello");
}

输出：

"radar" is a palindrome
"hello" is not a palindrome

参阅

findfind_iffind_if_not (C++11) | 寻找首个满足特定判别标准的元素 (函数模板)
lexicographical_compare | 当一个范围按字典顺序小于另一个范围时，返回 true (函数模板)
mismatch | 寻找两个范围出现不同的首个位置 (函数模板)
search | 搜索一个元素范围 (函数模板)


std::equal_range

< cpp‎ | algorithm
定义于头文件 <algorithm> |
 | (1)
template< class ForwardIt, class T > std::pair <ForwardIt,ForwardIt> equal_range( ForwardIt first, ForwardIt last, const T& value ); |  | (C++20 前)
template< class ForwardIt, class T > constexpr std::pair <ForwardIt,ForwardIt> equal_range( ForwardIt first, ForwardIt last, const T& value ); |  | (C++20 起)
 | (2)
template< class ForwardIt, class T, class Compare > std::pair <ForwardIt,ForwardIt> equal_range( ForwardIt first, ForwardIt last, const T& value, Compare comp ); |  | (C++20 前)
template< class ForwardIt, class T, class Compare > constexpr std::pair <ForwardIt,ForwardIt> equal_range( ForwardIt first, ForwardIt last, const T& value, Compare comp ); |  | (C++20 起)

返回范围 [first, last) 中含有所有等价于 value 的元素的范围。

范围 [first, last) 必须至少相对于 value 有序，即它必须满足下列所有要求：

  • 已相对 element < value 或 comp(element, value) 划分（即所有令该表达式为 true 的元素必须前趋所有令此表达式为 false 的元素）
  • 已相对 !(value < element) 或 !comp(value, element) 划分
  • 对于所有元素，若 element < value 或 comp(element, value) 为 true ，则 !(value < element) 或 !comp(value, element) 亦为 true

完全排序的范围满足这些判别标准。

以二个迭代器定义返回的范围，一个指向首个不小于 value 的元素，而另一个指向首个大于 value 的元素。可替而用 std::lower_bound() 获得第一迭代器，用 std::upper_bound() 获得第二迭代器。

第一版本用 operator< 比较元素，第二版本用给定的比较函数 comp 。

参数

first, last | - | 要检验的元素范围
value | - | 要与元素比较的值
comp | - | 若第一参数小于（即先序于）第二个则返回 ​true 的二元谓词。 谓词函数的签名应等价于如下： bool pred(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 必须使得 ForwardIt 类型的对象能在解引用后隐式转换到 Type1 。类型 Type2 必须使得 T 类型的对象能隐式转换到 Type2 。 ​
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- Compare 必须满足二元谓词 (BinaryPredicate) 的要求。不要求满足 比较 (Compare) 。

返回值

含有定义所需范围的一对迭代器的 std::pair ，第一迭代器指向首个不小于 value 的元素，而第二迭代器指向首个大于 value 的元素。

若无元素不小于 value ，则 last 作为第一元素返回。类似地，若无元素大于 value ，则 last 作为第二元素返回。

复杂度

进行的比较次数与 first 和 last 间的距离成对数（至多 log
2(last - first) + O(1) 次比较）。然而，对于非老式随机访问迭代器 (LegacyRandomAccessIterator) ，迭代次自增次数为线性。

可能的实现

版本一
template<class ForwardIt, class T>
std::pair<ForwardIt,ForwardIt>
    equal_range(ForwardIt first, ForwardIt last,
                const T& value)
{
    return std::make_pair(std::lower_bound(first, last, value),
                          std::upper_bound(first, last, value));
}
版本二
template<class ForwardIt, class T, class Compare>
std::pair<ForwardIt,ForwardIt>
    equal_range(ForwardIt first, ForwardIt last,
                const T& value, Compare comp);
{
    return std::make_pair(std::lower_bound(first, last, value, comp),
                          std::upper_bound(first, last, value, comp));
}

示例

版本一
template<class ForwardIt, class T>
std::pair<ForwardIt,ForwardIt>
    equal_range(ForwardIt first, ForwardIt last,
                const T& value)
{
    return std::make_pair(std::lower_bound(first, last, value),
                          std::upper_bound(first, last, value));
}
版本二
template<class ForwardIt, class T, class Compare>
std::pair<ForwardIt,ForwardIt>
    equal_range(ForwardIt first, ForwardIt last,
                const T& value, Compare comp)
{
    return std::make_pair(std::lower_bound(first, last, value, comp),
                          std::upper_bound(first, last, value, comp));
}

Example

#include <algorithm>
#include <vector>
#include <iostream>

struct S
{
    int number;
    char name;
    // 注：此比较运算符忽略 name
    bool operator< ( const S& s ) const { return number < s.number; }
};

int main()
{
    // 注：无序，仅相对定义如下的 S 划分
    const std::vector<S> vec = { {1,'A'}, {2,'B'}, {2,'C'}, {2,'D'}, {4,'G'}, {3,'F'} };

    const S value = {2, '?'};

    std::cout << "Compare using S::operator<(): ";
    const auto p = std::equal_range(vec.begin(), vec.end(), value);

    for ( auto i = p.first; i != p.second; ++i )
        std::cout << i->name << ' ';

    std::cout << "\n" "Using heterogeneous comparison: ";
    struct Comp
    {
        bool operator() ( const S& s, int i ) const { return s.number < i; }
        bool operator() ( int i, const S& s ) const { return i < s.number; }
    };

    const auto p2 = std::equal_range(vec.begin(),vec.end(), 2, Comp{});

    for ( auto i = p2.first; i != p2.second; ++i )
        std::cout << i->name << ' ';
}

输出：

Compare using S::operator<(): B C D
Using heterogeneous comparison: B C D

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 270 | C++98 | 曾要求 Compare 为严格弱序 | 只需要划分；容许异相比较

参阅

lower_bound | 返回指向第一个不小于给定值的元素的迭代器 (函数模板)
upper_bound | 返回指向第一个大于给定值的元素的迭代器 (函数模板)
binary_search | 确定元素是否存在于某范围中 (函数模板)
partition | 将范围中的元素分为两组 (函数模板)
equal | 确定两个元素集合是否是相同的 (函数模板)
ranges::equal_ranges (C++20) | 返回匹配特定值的元素范围 (niebloid)


std::exclusive_scan

< cpp‎ | algorithm
定义于头文件 <numeric>
(1)
template< class InputIt, class OutputIt, class T >

OutputIt exclusive_scan( InputIt first, InputIt last,

OutputIt d_first, T init );
 (C++17 起)
(C++20 前)
template< class InputIt, class OutputIt, class T >

constexpr OutputIt exclusive_scan( InputIt first, InputIt last,

OutputIt d_first, T init );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T >

ForwardIt2 exclusive_scan( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 d_first, T init);
 (2) (C++17 起)
(3)
template< class InputIt, class OutputIt,

class T, class BinaryOperation >
OutputIt exclusive_scan( InputIt first, InputIt last,

OutputIt d_first, T init, BinaryOperation binary_op );
 (C++17 起)
(C++20 前)
template< class InputIt, class OutputIt,

class T, class BinaryOperation >
constexpr OutputIt exclusive_scan( InputIt first, InputIt last,

OutputIt d_first, T init, BinaryOperation binary_op );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2,

class T, class BinaryOperation >
ForwardIt2 exclusive_scan( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 d_first, T init, BinaryOperation binary_op );
 (4) (C++17 起)

用 binary_op （或对于重载 (1-2) 是 std::plus <>() ）计算范围 [first, last) 上排除性前缀和，以 init 为初始值，并写入结果到从 d_first 开始的范围。“排除性”表示第 i 个输入元素不包含于第 i 个和。

正式而言，用对于 [first, first + (i - d_first)) 中的每个 j 在 binary_op 上的广义非交换和 init, *j... 的值，通过 [d_first, d_first + (last - first)) 中的每个迭代器赋值。

其中广义非交换和 GNSUM(op, a
1, ..., a
N) 定义如下：

  • 若 N=1 ，则为 a
    1
  • 若 N > 1 ，则为 op(GNSUM(op, a
    1    , ..., a
    K    ), GNSUM(op, a
    M    , ..., a
    N    ))     ，对于任何 1 < K+1 = M ≤ N 中的 K

换言之，和运算可能以任意顺序进行，而且若 binary_op 非结合，则行为是非确定的。

重载 (2,4) 按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

binary_op 不应非法化范围 [first, last) 或 [d_first, d_first + (last - first)) 中的迭代器（含尾迭代器）或子范围，亦不应修改其中的元素。否则行为未定义。

参数

first, last | - | 要求和的元素范围
d_first | - | 目标范围的起始；可以等于 first
policy | - | 所用的执行策略。细节见执行策略。
init | - | 初始值
binary_op | - | 将应用到解引用输入迭代器的结果、其他 binary_op 的结果和 init 的二元函数对象 (FunctionObject) 。
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- T 必须满足可移动构造 (MoveConstructible) 的要求。且 binary_op(init, *first) 、 binary_op(init, init) 及 binary_op(*first, *first) 必须能转换到 T

返回值

指向最后写入元素的后一元素的迭代器。

复杂度

O(last - first) 次应用二元运算

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

示例

#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>

int main()
{
  std::vector data {3, 1, 4, 1, 5, 9, 2, 6};

  std::cout << "exclusive sum: ";
  std::exclusive_scan(data.begin(), data.end(),
                      std::ostream_iterator<int>(std::cout, " "),
                      0);
  std::cout << "\ninclusive sum: ";
  std::inclusive_scan(data.begin(), data.end(),
                      std::ostream_iterator<int>(std::cout, " "));

  std::cout << "\n\nexclusive product: ";
  std::exclusive_scan(data.begin(), data.end(),
                      std::ostream_iterator<int>(std::cout, " "),
                      1, std::multiplies<>{});
  std::cout << "\ninclusive product: ";
  std::inclusive_scan(data.begin(), data.end(),
                      std::ostream_iterator<int>(std::cout, " "),
                      std::multiplies<>{});
}

输出：

exclusive sum: 0 3 4 8 9 14 23 25
inclusive sum: 3 4 8 9 14 23 25 31

exclusive product: 1 3 3 12 12 60 540 1080
inclusive product: 3 3 12 12 60 540 1080 6480

参阅

adjacent_difference | 计算范围内各相邻元素之间的差 (函数模板)
accumulate | 对一个范围内的元素求和 (函数模板)
partial_sum | 计算范围内元素的部分和 (函数模板)
transform_exclusive_scan (C++17) | 应用一个函数对象，然后进行排除扫描 (函数模板)
inclusive_scan (C++17) | 类似 std::partial_sum，第 i 个和中包含第 i 个输入 (函数模板)


std::execution::seq, std::execution::par, std::execution::par_unseq, std::execution::unseq

< cpp‎ | algorithm
定义于头文件 <execution>
inline constexpr std::execution::sequenced_policy seq { /* unspecified */ };
 (C++17 起)
inline constexpr std::execution::parallel_policy par { /* unspecified */ };
 (C++17 起)
inline constexpr std::execution::parallel_unsequenced_policy par_unseq
{ /* unspecified */ };
 (C++17 起)
inline constexpr std::execution::unsequenced_policy unseq { /* unspecified */ };
 (C++20 起)

std::execution::seq 、 std::execution::par 、 std::execution::par_unseq 及 std::execution::unseq 分别是执行策略类型 std::execution::sequenced_policy 、 std::execution::parallel_policy 、 std::execution::parallel_unsequenced_policy 与 std::execution::unsequenced_policy 的实例。它们用于指定并行算法的执行策略——即允许的并行类型。

标准库的实现可以提供附加的执行策略。（可能的未来额外策略包含 std::parallel::cuda 和 std::parallel::opencl ）

参阅

sequenced_policyparallel_policyparallel_unsequenced_policyunsequenced_policy
(C++17)(C++17)(C++17)(C++20)
 执行策略类型
(类)


std::execution::sequenced_policy, std::execution::parallel_policy, std::execution::parallel_unsequenced_policy, std::execution::unsequenced_policy

< cpp‎ | algorithm
定义于头文件 <execution> |  |
class sequenced_policy { /* unspecified */ }; | (1) | (C++17 起)
class parallel_policy { /* unspecified */ }; | (2) | (C++17 起)
class parallel_unsequenced_policy { /* unspecified */ }; | (3) | (C++17 起)
class unsequenced_policy { /* unspecified */ }; | (4) | (C++20 起)
1) 以该执行策略类型为一种独有类型，对并行算法重载消歧义，并要求并行算法的执行可以不并行化。以此策略调用（通常以 std::execution::seq 指定）的并行算法中，元素访问函数的调用在调用方线程中是非确定顺序的。
2) 以该执行策略类型为一种独有类型，对并行算法重载消歧义，并指示并行算法的执行可以并行化。以此策略调用（通常以 std::execution::par 指定）的并行算法中，元素访问函数的调用允许在调用方线程，或由库隐式创建的线程中执行，以支持并行算法执行。任何执行于同一线程中的这种调用彼此间是非确定顺序的，
3) 以该执行策略类型为一种独有类型，对并行算法重载消歧义，并指示并行算法的执行可以并行化、向量化，或在线程间迁移（例如用亲窃取的调度器）。容许以此策略调用的并行算法中的元素访问函数调用在未指定线程中以无序方式执行，并相对于每个线程中的另一调用无顺序。
4) 以该执行策略类型为一种独有类型，对并行算法重载消歧义，并指示可将算法的指向向量化，例如在单个线程上使用在多个数据项上操作的指令指执行。

在执行这写执行策略的并行算法的过程中，若元素访问函数的调用因未捕捉的异常退出，则调用 std::terminate ，但实现可以定义以其他方式处理异常的额外执行策略。

注解

在使用并行执行策略时，程序员负责避免数据竞争和死锁：

int a[] = {0,1};
std::vector<int> v;
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int i) {
  v.push_back(i*2+1); // 错误：数据竞争
});
std::atomic<int> x{0};
int a[] = {1,2};
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int) {
  x.fetch_add(1, std::memory_order_relaxed);
  while (x.load(std::memory_order_relaxed) == 1) { } // 错误：假设执行顺序
});
int x = 0;
std::mutex m;
int a[] = {1,2};
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int) {
  std::lock_guard<std::mutex> guard(m);
  ++x; // 正确
});

无顺序执行策略是函数调用彼此间无顺序的仅有情况，这意味着它们可以穿插。 C++ 的所有其他情况中，它们都是非确定顺序的（不能穿插）。因此，在使用这些策略时，不允许用户分配或解分配内存、使用非免锁的 std::atomic 特化、获得互斥或通常而言进行任何向量化不安全操作（向量化不安全函数是与其他函数同步的函数，例如 std::mutex::unlock 与前一 std::mutex::lock 同步）

int x = 0;
std::mutex m;
int a[] = {1,2};
std::for_each(std::execution::par_unseq, std::begin(a), std::end(a), [&](int) {
  std::lock_guard<std::mutex> guard(m); // 错误： lock_guard 构造函数调用 m.lock()
  ++x;
});

若实现无法并行化或向量化（例如由于资源不足），则所有标准执行策略都能回落到按顺序执行。

参阅

seqparpar_unsequnseq
(C++17)(C++17)(C++17)(C++20)
 全局执行策略对象
(常量)


std::fill

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class ForwardIt, class T > void fill( ForwardIt first, ForwardIt last, const T& value ); |  |  | (C++20 前)
template< class ForwardIt, class T > constexpr void fill( ForwardIt first, ForwardIt last, const T& value ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class T > void fill( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, const T& value ); | (2) | (C++17 起)
1) 赋值给定的 value 给 [first, last) 中的元素。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要修改的元素范围
value | - | 要赋的值
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

（无）

复杂度

准确赋值 last - first 次。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template< class ForwardIt, class T >
void fill(ForwardIt first, ForwardIt last, const T& value)
{
    for (; first != last; ++first) {
        *first = value;
    }
}

示例

下列代码用 fill() 设置 int 的 vector 的所有元素为 -1 ：

#include <algorithm>
#include <vector>
#include <iostream>

int main()
{
    std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

    std::fill(v.begin(), v.end(), -1);

    for (auto elem : v) {
        std::cout << elem << " ";
    }
    std::cout << "\n";
}

输出：

-1 -1 -1 -1 -1 -1 -1 -1 -1 -1

参阅

fill_n | 将一个给定值复制赋值给一个范围内的 N 个元素 (函数模板)
copycopy_if (C++11) | 将某一范围的元素复制到一个新的位置 (函数模板)
generate | 将相继的函数调用结果赋值给一个范围中的每个元素 (函数模板)
transform | 将一个函数应用于某一范围的各个元素，并在目标范围存储结果 (函数模板)
ranges::fill (C++20) | 将一个给定值复制赋值给一个范围内的每个元素 (niebloid)


std::fill_n

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class OutputIt, class Size, class T > void fill_n( OutputIt first, Size count, const T& value ); |  |  | (C++11 前)
template< class OutputIt, class Size, class T > OutputIt fill_n( OutputIt first, Size count, const T& value ); |  |  | (C++11 起) (C++20 前)
template< class OutputIt, class Size, class T > constexpr OutputIt fill_n( OutputIt first, Size count, const T& value ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class Size, class T > ForwardIt fill_n( ExecutionPolicy&& policy, ForwardIt first, Size count, const T& value ); | (2) | (C++17 起)
1) 若 count > 0 ，则赋值给定的 value 给始于 的范围的首 count 个元素。否则不做任何事。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。。

参数

first | - | 要修改的元素范围起始
count | - | 要修改的元素数
value | - | 要赋的值
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

（无） | (C++11 前)
若 count > 0 则为指向最后赋值元素后一位置的迭代器，否则为 first 。 | (C++11 起)

复杂度

对于 count > 0 ，准确赋值 count 次。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class OutputIt, class Size, class T>
OutputIt fill_n(OutputIt first, Size count, const T& value)
{
    for (Size i = 0; i < count; ++i) {
        *first++ = value;
    }
    return first;
}

示例

下列代码用 fill_n() 赋值 -1 给 int 的 vector 的前一半：

#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>

int main()
{
    std::vector<int> v1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

    std::fill_n(v1.begin(), 5, -1);

    std::copy(begin(v1), end(v1), std::ostream_iterator<int>(std::cout, " "));
    std::cout << "\n";
}

输出：

-1 -1 -1 -1 -1 5 6 7 8 9

参阅

fill | 将一个给定值复制赋值给一个范围内的每个元素 (函数模板)
ranges::fill_n (C++20) | 将一个值复制赋值给一定量的元素 (niebloid)


std::find, std::find_if, std::find_if_not

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class InputIt, class T >
InputIt find( InputIt first, InputIt last, const T& value );
 (C++20 前)
template< class InputIt, class T >
constexpr InputIt find( InputIt first, InputIt last, const T& value );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class T >

ForwardIt find( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,

const T& value );
 (2) (C++17 起)
(3)
template< class InputIt, class UnaryPredicate >

InputIt find_if( InputIt first, InputIt last,

UnaryPredicate p );
 (C++20 前)
template< class InputIt, class UnaryPredicate >

constexpr InputIt find_if( InputIt first, InputIt last,

UnaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >

ForwardIt find_if( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,

UnaryPredicate p );
 (4) (C++17 起)
(5)
template< class InputIt, class UnaryPredicate >

InputIt find_if_not( InputIt first, InputIt last,

UnaryPredicate q );
 (C++11 起)
(C++20 前)
template< class InputIt, class UnaryPredicate >

constexpr InputIt find_if_not( InputIt first, InputIt last,

UnaryPredicate q );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >

ForwardIt find_if_not( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,

UnaryPredicate q );
 (6) (C++17 起)

返回指向范围 [first, last) 中满足特定判别标准的首个元素的迭代器：

1) find 搜索等于 value 的元素。
3) find_if 搜索谓词 p 对其返回 true 的元素。
5) find_if_not 搜索谓词 q 对其返回 false 的元素。
2,4,6) 同 (1,3,5) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要检验的元素范围
value | - | 要与元素比较的值
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若为要求的元素则返回 ​true 的一元谓词。 对每个（可为 const 的） VT 类型参数 v ，其中 VT 是 InputIt 的值类型，表达式 p(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 VT& 类型参数，亦不允许 VT ，除非对 VT 而言移动等价于复制 (C++11 起)。 ​
q | - | 若为要求的元素则返回 ​false 的一元谓词。 对每个（可为 const 的） VT 类型参数 v ，其中 VT 是 InputIt 的值类型，表达式 q(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 VT& 类型参数，亦不允许 VT ，除非对 VT 而言移动等价于复制 (C++11 起)。 ​
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- UnaryPredicate 必须满足谓词 (Predicate) 的要求。

返回值

指向首个满足条件的迭代器，或若找不到这种元素则为 last 。

复杂度

至多应用 last - first 次谓词。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class InputIt, class T>
InputIt find(InputIt first, InputIt last, const T& value)
{
    for (; first != last; ++first) {
        if (*first == value) {
            return first;
        }
    }
    return last;
}
版本二
template<class InputIt, class UnaryPredicate>
InputIt find_if(InputIt first, InputIt last, UnaryPredicate p)
{
    for (; first != last; ++first) {
        if (p(*first)) {
            return first;
        }
    }
    return last;
}
版本三
template<class InputIt, class UnaryPredicate>
InputIt find_if_not(InputIt first, InputIt last, UnaryPredicate q)
{
    for (; first != last; ++first) {
        if (!q(*first)) {
            return first;
        }
    }
    return last;
}

注解

若你没有 C++11 ，则 std::find_if_not 的等价版本是以取反的谓词使用 std::find_if 。

template<class InputIt, class UnaryPredicate>
InputIt find_if_not(InputIt first, InputIt last, UnaryPredicate q)
{
    return std::find_if(first, last, std::not1(q));
}

示例

以下示例在给定的 std::vector 中查找整数。

#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>

int main()
{
    std::vector<int> v{1, 2, 3, 4};
    int n1 = 3;
    int n2 = 5;
    auto is_even = [](int i){ return i%2 == 0; };

    auto result1 = std::find(begin(v), end(v), n1);
    auto result2 = std::find(begin(v), end(v), n2);
    auto result3 = std::find_if(begin(v), end(v), is_even);

    (result1 != std::end(v))
        ? std::cout << "v contains " << n1 << '\n'
        : std::cout << "v does not contain " << n1 << '\n';

    (result2 != std::end(v))
        ? std::cout << "v contains " << n2 << '\n'
        : std::cout << "v does not contain " << n2 << '\n';

    (result3 != std::end(v))
        ? std::cout << "v contains an even number: " << *result3 << '\n'
        : std::cout << "v does not contain even numbers\n";
}

输出：

v contains 3
v does not contain 5
v contains an even number: 2

参阅

adjacent_find | 查找首对相邻的相同（或满足给定谓词的）元素 (函数模板)
find_end | 在特定范围中寻找最后出现的元素序列 (函数模板)
find_first_of | 搜索元素集合中的任意元素 (函数模板)
mismatch | 寻找两个范围出现不同的首个位置 (函数模板)
search | 搜索一个元素范围 (函数模板)
ranges::findranges::find_ifranges::find_if_not (C++20)(C++20)(C++20) | 寻找首个满足特定判别标准的元素 (niebloid)


std::find_end

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class ForwardIt1, class ForwardIt2 >

ForwardIt1 find_end( ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last );
 (C++20 前)
template< class ForwardIt1, class ForwardIt2 >

constexpr ForwardIt1 find_end( ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >

ForwardIt1 find_end( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last );
 (2) (C++17 起)
(3)
template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >

ForwardIt1 find_end( ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );
 (C++20 前)
template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >

constexpr ForwardIt1 find_end( ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class BinaryPredicate >

ForwardIt1 find_end( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );
 (4) (C++17 起)

在范围 [first, last) 中搜索序列 [s_first, s_last) 的最后一次出现。

1) 用 operator== 比较元素。
3) 用给定的二元谓词 p 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要检验的元素范围
s_first, s_last | - | 要搜索的元素范围
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若元素应被当做相等则返回 ​true 的二元谓词。 谓词函数的签名应等价于如下： bool pred(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 ForwardIt1 与 ForwardIt2 类型的对象在解引用后分别能隐式转换到 Type1 与 Type2 。 ​
类型要求
- ForwardIt1 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

指向范围 [first, last) 中 [s_first, s_last) 最后一次出现的起始的迭代器。

若找不到这种序列，则返回 last 。 | (C++11 前)
若 [s_first, s_last) 为空或若找不到这种序列，则返回 last 。 | (C++11 起)

复杂度

至多比较 \(\scriptsize S\cdot(N-S+1)\)S·(N-S+1) 次，其中 \(\scriptsize S\)S 为 std::distance (first2, last2) 而 \(\scriptsize N\)N 为 std::distance (first1, last1) 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class ForwardIt1, class ForwardIt2>
ForwardIt1 find_end(ForwardIt1 first, ForwardIt1 last,
                    ForwardIt2 s_first, ForwardIt2 s_last)
{
    if (s_first == s_last)
        return last;
    ForwardIt1 result = last;
    while (true) {
        ForwardIt1 new_result = std::search(first, last, s_first, s_last);
        if (new_result == last) {
            break;
        } else {
            result = new_result;
            first = result;
            ++first;
        }
    }
    return result;
}
版本二
template<class ForwardIt1, class ForwardIt2, class BinaryPredicate>
ForwardIt1 find_end(ForwardIt1 first, ForwardIt1 last,
                    ForwardIt2 s_first, ForwardIt2 s_last,
                    BinaryPredicate p)
{
    if (s_first == s_last)
        return last;
    ForwardIt1 result = last;
    while (true) {
        ForwardIt1 new_result = std::search(first, last, s_first, s_last, p);
        if (new_result == last) {
            break;
        } else {
            result = new_result;
            first = result;
            ++first;
        }
    }
    return result;
}

示例

下列代码用 find_end() 搜索二个不同的数列。

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4};
    std::vector<int>::iterator result;

    std::vector<int> t1{1, 2, 3};

    result = std::find_end(v.begin(), v.end(), t1.begin(), t1.end());
    if (result == v.end()) {
        std::cout << "subsequence not found\n";
    } else {
        std::cout << "last subsequence is at: "
                  << std::distance(v.begin(), result) << "\n";
    }

    std::vector<int> t2{4, 5, 6};
    result = std::find_end(v.begin(), v.end(), t2.begin(), t2.end());
    if (result == v.end()) {
        std::cout << "subsequence not found\n";
    } else {
        std::cout << "last subsequence is at: "
                  << std::distance(v.begin(), result) << "\n";
    }
}

输出：

last subsequence is at: 8
subsequence not found

参阅

search | 搜索一个元素范围 (函数模板)
includes | 若一个序列是另一个的子列则返回 true (函数模板)
adjacent_find | 查找首对相邻的相同（或满足给定谓词的）元素 (函数模板)
findfind_iffind_if_not (C++11) | 寻找首个满足特定判别标准的元素 (函数模板)
find_first_of | 搜索元素集合中的任意元素 (函数模板)
search_n | 在范围中搜索一定量的某个元素的连续副本 (函数模板)
ranges::find_end (C++20) | 在特定范围中寻找最后出现的元素序列 (niebloid)


std::find_first_of

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class ForwardIt1, class ForwardIt2 >

ForwardIt1 find_first_of( ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last );
 (C++11 前)
template< class InputIt, class ForwardIt >

InputIt find_first_of( InputIt first, InputIt last,

ForwardIt s_first, ForwardIt s_last );
 (C++11 起)
(C++20 前)
template< class InputIt, class ForwardIt >

constexpr InputIt find_first_of( InputIt first, InputIt last,

ForwardIt s_first, ForwardIt s_last );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >

ForwardIt1 find_first_of( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last );
 (2) (C++17 起)
(3)
template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >

ForwardIt1 find_first_of( ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );
 (C++11 前)
template< class InputIt, class ForwardIt, class BinaryPredicate >

InputIt find_first_of( InputIt first, InputIt last,

ForwardIt s_first, ForwardIt s_last, BinaryPredicate p );
 (C++11 起)
(C++20 前)
template< class InputIt, class ForwardIt, class BinaryPredicate >

constexpr InputIt find_first_of( InputIt first, InputIt last,

ForwardIt s_first, ForwardIt s_last, BinaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class BinaryPredicate >

ForwardIt1 find_first_of( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt last,

ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );
 (4) (C++17 起)

在范围 [first, last) 中搜索范围 [s_first, s_last) 中的任何元素。

1) 用 operator== 比较元素。
3) 用给定的二元谓词 p 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要检验的元素范围
s_first, s_last | - | 要搜索的元素范围
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若元素应被当做相等则返回 ​true 的二元谓词。 谓词函数的签名应等价于如下： bool pred(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 ForwardIt1 与 ForwardIt2 类型的对象在解引用后分别能隐式转换到 Type1 与 Type2 。 ​
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt1 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

指向范围 [first, last) 中等于来自范围 [s_first; s_last) 中一个元素的首个元素。若找不到这种元素，则返回 last 。

复杂度

至多做 (S*N) 次比较，其中 S = distance(s_first, s_last) 而 N = distance(first, last) 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class InputIt, class ForwardIt>
InputIt find_first_of(InputIt first, InputIt last,
                      ForwardIt s_first, ForwardIt s_last)
{
    for (; first != last; ++first) {
        for (ForwardIt it = s_first; it != s_last; ++it) {
            if (*first == *it) {
                return first;
            }
        }
    }
    return last;
}
版本二
template<class InputIt, class ForwardIt, class BinaryPredicate>
InputIt find_first_of(InputIt first, InputIt last,
                      ForwardIt s_first, ForwardIt s_last,
                      BinaryPredicate p)
{
    for (; first != last; ++first) {
        for (ForwardIt it = s_first; it != s_last; ++it) {
            if (p(*first, *it)) {
                return first;
            }
        }
    }
    return last;
}

示例

下列代码在 int 的 vector 中搜索任何一个指定的整数：

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{0, 2, 3, 25, 5};
    const auto t = {3, 19, 10, 2};

    auto result = std::find_first_of(v.begin(), v.end(), t.begin(), t.end());

    if (result == v.end()) {
        std::cout << "no elements of v were equal to 3, 19, 10 or 2\n";
    } else {
        std::cout << "found a match at "
                  << std::distance(v.begin(), result) << "\n";
    }
 }

输出：

found a match at 1

参阅

findfind_iffind_if_not (C++11) | 寻找首个满足特定判别标准的元素 (函数模板)
ranges::find_first_of (C++20) | 搜索元素集合中的任一元素 (niebloid)


std::for_each

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class InputIt, class UnaryFunction > UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f ); |  |  | (C++20 前)
template< class InputIt, class UnaryFunction > constexpr UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class UnaryFunction2 > void for_each( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryFunction2 f ); | (2) | (C++17 起)
1) 按顺序应用给定的函数对象 f 到解引用范围 [first, last) 中每个迭代器的结果。
2) 应用给定的函数对象 f 到解引用范围 [first, last) 中每个迭代器的结果（不必按顺序）。按照 policy 执行算法。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

对于两个重载，若迭代器类型为可变，则 f 可以通过解引用后的迭代器修改范围的元素。若 f 返回结果，则忽略结果。

不同于其余并行算法，不允许 for_each 复制序列中的元素，即使它们为可平凡复制。

参数

first, last | - | 要应用函数到的范围
policy | - | 所用的执行策略。细节见执行策略。
f | - | 函数对象，要应用于解引用范围 [first, last) 中每个迭代器结果的函数 函数签名应当等价于如下者： void fun(const Type &a); 签名不必拥有 const & 。 类型 Type 必须使得 InputIt 类型对象能在解引用后隐式转换到 Type 。 ​
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- UnaryFunction 必须满足可移动构造 (MoveConstructible) 的要求。不必为 可复制构造 (CopyConstructible) 。
- UnaryFunction2 必须满足可复制构造 (CopyConstructible) 的要求。

返回值

1) f (C++11 前) std::move(f) (C++11 起)
2) （无）

复杂度

准确应用 last - first 次 f 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

参阅 libstdc++ 、 libc++ 及 MSVC stdlib 中的实现。

template<class InputIt, class UnaryFunction>
UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f)
{
    for (; first != last; ++first) {
        f(*first);
    }
    return f; // C++11 起隐式移动
}

示例

下列代码用 lambda 函数自增 vector 的所有元素，然后用函数对象中的重载 operator() 计算其和。注意推荐用更适合的算法 std::accumulate 计算和。

#include <vector>
#include <algorithm>
#include <iostream>

struct Sum
{
    void operator()(int n) { sum += n; }
    int sum{0};
};

int main()
{
    std::vector<int> nums{3, 4, 2, 8, 15, 267};

    auto print = [](const int& n) { std::cout << " " << n; };

    std::cout << "before:";
    std::for_each(nums.cbegin(), nums.cend(), print);
    std::cout << '\n';

    std::for_each(nums.begin(), nums.end(), [](int &n){ n++; });

    // 对每个数调用 Sum::operator()
    Sum s = std::for_each(nums.begin(), nums.end(), Sum());

    std::cout << "after: ";
    std::for_each(nums.cbegin(), nums.cend(), print);
    std::cout << '\n';
    std::cout << "sum: " << s.sum << '\n';
}

输出：

before: 3 4 2 8 15 267
after:  4 5 3 9 16 268
sum: 305

参阅

transform | 将一个函数应用于某一范围的各个元素，并在目标范围存储结果 (函数模板)
for_each_n (C++17) | 应用一个函数对象到序列的前 n 个元素 (函数模板)
ranges::for_each (C++20) | 应用函数到范围中的元素 (niebloid)
范围 for 循环 (C++11) | 执行范围上的循环


std::for_each_n

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class InputIt, class Size, class UnaryFunction > InputIt for_each_n( InputIt first, Size n, UnaryFunction f ); |  |  | (C++17 起) (C++20 前)
template< class InputIt, class Size, class UnaryFunction > constexpr InputIt for_each_n( InputIt first, Size n, UnaryFunction f ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class Size, class UnaryFunction2 > ForwardIt for_each_n( ExecutionPolicy&& policy, ForwardIt first, Size n, UnaryFunction2 f ); | (2) | (C++17 起)
1) 按顺序应用给定的函数对象 f 到解引用范围 [first, first + n) 中每个迭代器的结果。
2) 应用给定的函数对象 f 到解引用范围 [first, first + n) 中每个迭代器的结果（不必按顺序）。按照 policy 执行算法。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

对于两种重载，若迭代器是可变的，则 f 可以通过解引用的迭代器修改范围中的元素。若 f 返回结果，则忽略结果。若 n 小于零，则行为未定义。

不同于其余并行算法，不允许 for_each_n 复制序列中的元素，即使它们为可平凡复制。

参数

first | - | 要应用函数的范围起始
n | - | 要应用函数的元素个数
policy | - | 所用的执行策略。细节见执行策略。
f | - | 函数对象， 应用到范围 [first, first + n) 中每个迭代器解引用结果 函数签名应当等价于如下者： void fun(const Type &a); 签名不必拥有 const & 。 类型 Type 必须使得 InputIt 类型对象能在解引用后隐式转换到 Type 。 ​
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- UnaryFunction 必须满足可移动构造 (MoveConstructible) 的要求。不必为可复制构造 (CopyConstructible) 。
- UnaryFunction2 必须满足可复制构造 (CopyConstructible) 的要求。

返回值

first + n

复杂度

正好 n 次应用 f

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

参阅 libstdc++ 与 libc++ 中的实现。

template<class InputIt, class Size, class UnaryFunction>
InputIt for_each_n(InputIt first, Size n, UnaryFunction f)
{
    for (Size i = 0; i < n; ++first, (void) ++i) {
        f(*first);
    }
    return first;
}

示例

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> ns{1, 2, 3, 4, 5};
    for (auto n: ns) std::cout << n << ", ";
    std::cout << '\n';
    std::for_each_n(ns.begin(), 3, [](auto& n){ n *= 2; });
    for (auto n: ns) std::cout << n << ", ";
    std::cout << '\n';
}

输出：

1, 2, 3, 4, 5,
2, 4, 6, 4, 5,

参阅

transform | 将一个函数应用于某一范围的各个元素，并在目标范围存储结果 (函数模板)
范围 for 循环 (C++11) | 执行范围上的循环
for_each | 应用函数到范围中的元素 (函数模板)


std::generate

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class ForwardIt, class Generator > void generate( ForwardIt first, ForwardIt last, Generator g ); |  |  | (C++20 前)
template< class ForwardIt, class Generator > constexpr void generate( ForwardIt first, ForwardIt last, Generator g ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class Generator > void generate( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, Generator g ); | (2) | (C++17 起)
1) 以给定函数对象 g 所生成的值赋值范围 [first, last) 中的每个元素。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last - 要生成的元素范围
policy - 所用的执行策略。细节见执行策略。
g - 将要调用的生成器函数。

签名应等价于如下：

Ret fun();

类型 Ret 必须使得 ForwardIt 类型对象能被解引用并能被赋 Ret 类型值。 ​
类型要求
-
ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

（无）

复杂度

准确 std::distance (first, last) 次调用 g() 及赋值。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class ForwardIt, class Generator>
constexpr // Since C++20
void generate(ForwardIt first, ForwardIt last, Generator g)
{
    while (first != last) {
        *first++ = g();
    }
}

示例

#include <algorithm>
#include <iostream>
#include <vector>

int f()
{
    static int i;
    return ++i;
}

int main()
{
    std::vector<int> v(5);
    auto print = [&] {
        for (std::cout << "v: "; auto iv: v)
            std::cout << iv << " ";
        std::cout << "\n";
    };

    std::generate(v.begin(), v.end(), f);
    print();

    // 以来自 lambda 函数的值 0,1,2,3,4 初始化
    // 等价于 std::iota(v.begin(), v.end(), 0);
    std::generate(v.begin(), v.end(), [n = 0] () mutable { return n++; });
    print();
}

输出：

v: 1 2 3 4 5
v: 0 1 2 3 4

参阅

fill | 将一个给定值复制赋值给一个范围内的每个元素 (函数模板)
generate_n | 将相继的函数调用结果赋值给一个范围中的 N 个元素 (函数模板)
iota (C++11) | 用从起始值开始连续递增的值填充一个范围 (函数模板)
ranges::generate (C++20) | 保存函数结果到一个范围中 (niebloid)


std::generate_n

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class OutputIt, class Size, class Generator >
void generate_n( OutputIt first, Size count, Generator g );
 (C++11 前)
template< class OutputIt, class Size, class Generator >
OutputIt generate_n( OutputIt first, Size count, Generator g );
 (C++11 起)
(C++20 前)
template< class OutputIt, class Size, class Generator >
constexpr OutputIt generate_n( OutputIt first, Size count, Generator g );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt , class Size, class Generator >

ForwardIt generate_n( ExecutionPolicy&& policy, ForwardIt first,

Size count, Generator g );
 (2) (C++17 起)
1) 若 count>0 ，则赋值给定函数对象 g 所生成的值给始于 first 的范围的首 count 个元素。否则不做任何事。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first - 要生成的元素范围起始
count - 要生成的元素数
policy - 所用的执行策略。细节见执行策略。
g - 将要调用的生成器函数。

签名应等价于如下：

Ret fun();

类型 Ret 必须使得 OutputIt 类型对象能被解引用并能被赋 Ret 类型值。 ​
类型要求
-
OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
-
ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

（无） | (C++11 前)
若 count>0 则为最后被赋值元素后一位置的迭代器。否则为 first 。 | (C++11 起)

复杂度

对于 count>0 ，准确 count 次调用 g() 和赋值。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template< class OutputIt, class Size, class Generator >
constexpr // C++20 起
OutputIt  // C++11 前为 void
Ogenerate_n( OutputIt first, Size count, Generator g )
{
    for( Size i = 0; i < count; ++i ) {
        *first++ = g();
    }
    return first;
}

示例

#include <random>
#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    std::mt19937 rng; // 默认构造，以固定的种子播种
    std::generate_n(std::ostream_iterator<std::mt19937::result_type>(std::cout, " "),
                    5, std::ref(rng));
    std::cout << '\n';
}

输出：

3499211612 581869302 3890346734 3586334585 545404204

参阅

fill_n | 将一个给定值复制赋值给一个范围内的 N 个元素 (函数模板)
generate | 将相继的函数调用结果赋值给一个范围中的每个元素 (函数模板)
ranges::generate_n (C++20) | 保存 N 次函数应用的结果 (niebloid)


std::includes

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class InputIt1, class InputIt2 >

bool includes( InputIt1 first1, InputIt1 last1,

InputIt2 first2, InputIt2 last2 );
 (C++20 前)
template< class InputIt1, class InputIt2 >

constexpr bool includes( InputIt1 first1, InputIt1 last1,

InputIt2 first2, InputIt2 last2 );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >

bool includes( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1,

ForwardIt2 first2, ForwardIt2 last2 );
 (2) (C++17 起)
(3)
template< class InputIt1, class InputIt2, class Compare >

bool includes( InputIt1 first1, InputIt1 last1,

InputIt2 first2, InputIt2 last2, Compare comp );
 (C++20 前)
template< class InputIt1, class InputIt2, class Compare >

constexpr bool includes( InputIt1 first1, InputIt1 last1,

InputIt2 first2, InputIt2 last2, Compare comp );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class Compare >

bool includes( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1,

ForwardIt2 first2, ForwardIt2 last2, Compare comp );
 (4) (C++17 起)

若已排序范围 [first2, last2) 是已排序范围 [first1, last1) 的子序列则返回 true 。（子序列不必相接。）

1) 两个范围都必须以 operator< 排序。
3) 两个范围都必须以给定的比较函数 comp 排序。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first1, last1 | - | 要检验的已排序元素范围
first2, last2 | - | 要搜索的已排序元素范围
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 InputIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- InputIt1, InputIt2 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

若 [first2, last2) 是 [first1, last1) 的子序列则为 true ；否则为 false 。

复杂度

至多比较 \(\scriptsize 2 \cdot (N_1+N_2-1)\)2·(N1+N2-1) 次，其中 \(\scriptsize N_1\)N1 为 std::distance (first1, last1) 而 \(\scriptsize N_2\)N2 为 std::distance (first2, last2) 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class InputIt1, class InputIt2>
bool includes(InputIt1 first1, InputIt1 last1,
              InputIt2 first2, InputIt2 last2)
{
    for (; first2 != last2; ++first1)
    {
        if (first1 == last1 || *first2 < *first1)
            return false;
        if ( !(*first1 < *first2) )
            ++first2;
    }
    return true;
}
版本二
template<class InputIt1, class InputIt2, class Compare>
bool includes(InputIt1 first1, InputIt1 last1,
              InputIt2 first2, InputIt2 last2, Compare comp)
{
    for (; first2 != last2; ++first1)
    {
        if (first1 == last1 || comp(*first2, *first1))
            return false;
        if (!comp(*first1, *first2))
            ++first2;
    }
    return true;
}

示例

#include <iostream>
#include <algorithm>
#include <cctype>

template<class Os, class Co> Os& operator<<(Os& os, const Co& v) {
  for (auto i : v) os << i << ' ';
  return os << '\t';
}

int main()
{
  const auto
    v1 = {'a', 'b', 'c', 'f', 'h', 'x'},
    v2 = {'a', 'b', 'c'},
    v3 = {'a', 'c'},
    v4 = {'a', 'a', 'b'},
    v5 = {'g'},
    v6 = {'a', 'c', 'g'},
    v7 = {'A', 'B', 'C'};

  auto no_case = [](char a, char b) { return std::tolower(a) < std::tolower(b); };

  std::cout
    << v1 << "\nincludes:\n" << std::boolalpha
    << v2 << ": " << std::includes(v1.begin(), v1.end(), v2.begin(), v2.end()) << '\n'
    << v3 << ": " << std::includes(v1.begin(), v1.end(), v3.begin(), v3.end()) << '\n'
    << v4 << ": " << std::includes(v1.begin(), v1.end(), v4.begin(), v4.end()) << '\n'
    << v5 << ": " << std::includes(v1.begin(), v1.end(), v5.begin(), v5.end()) << '\n'
    << v6 << ": " << std::includes(v1.begin(), v1.end(), v6.begin(), v6.end()) << '\n'
    << v7 << ": " << std::includes(v1.begin(), v1.end(), v7.begin(), v7.end(), no_case)
          << " (case-insensitive)\n";
}

输出：

a b c f h x
includes:
a b c   : true
a c     : true
a a b   : false
g       : false
a c g   : false
A B C   : true (case-insensitive)

参阅

set_difference | 计算两个集合的差集 (函数模板)
search | 搜索一个元素范围 (函数模板)
ranges::includes (C++20) | 若一个序列是另一个的子列则返回 true (niebloid)


std::inclusive_scan

< cpp‎ | algorithm
定义于头文件 <numeric>
(1)
template< class InputIt, class OutputIt >

OutputIt inclusive_scan( InputIt first,

InputIt last, OutputIt d_first );
 (C++17 起)
(C++20 前)
template< class InputIt, class OutputIt >

constexpr OutputIt inclusive_scan( InputIt first,

InputIt last, OutputIt d_first );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >

ForwardtIt2 inclusive_scan( ExecutionPolicy&& policy, ForwardIt1 first,

ForwardIt1 last, ForwardIt2 d_first );
 (2) (C++17 起)
(3)
template< class InputIt, class OutputIt, class BinaryOperation >

OutputIt inclusive_scan( InputIt first, InputIt last,

OutputIt d_first, BinaryOperation binary_op );
 (C++17 起)
(C++20 前)
template< class InputIt, class OutputIt, class BinaryOperation >

constexpr OutputIt inclusive_scan( InputIt first, InputIt last,

OutputIt d_first, BinaryOperation binary_op );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2,

class BinaryOperation >
ForwardIt2 inclusive_scan( ExecutionPolicy&& policy,
ForwardIt1 first, ForwardIt1 last,

ForwardIt2 d_first, BinaryOperation binary_op );
 (4) (C++17 起)
(5)
template< class InputIt, class OutputIt, class BinaryOperation, class T >

OutputIt inclusive_scan( InputIt first, InputIt last, OutputIt d_first,

BinaryOperation binary_op, T init );
 (C++17 起)
(C++20 前)
template< class InputIt, class OutputIt, class BinaryOperation, class T >

constexpr OutputIt inclusive_scan( InputIt first, InputIt last, OutputIt d_first,

BinaryOperation binary_op, T init );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2,

class BinaryOperation, class T >
ForwardIt2 inclusive_scan( ExecutionPolicy&& policy,
ForwardIt1 first, ForwardIt1 last, ForwardIt2 d_first,

BinaryOperation binary_op, T init );
 (6) (C++17 起)

用 binary_op （或对于重载 (1-2) 则是 std::plus <>() ）对范围 [first, last) 计算包含性前缀和运算，以 init 为初始值（若提供），并将结果写入从 d_first 开始的范围。“包含性”意味着第 i 个输入元素包含于第 i 个和。

正式而言，通过每个 [d_first, d_first + (last - first)) 中的迭代器 i ，以下列值赋值：

  • 重载 (1-4) 为，对于每个区间 [first, first + (i - d_first + 1)) 中的 j ， *j... 在 binary_op 上的广义非交换和
  • 重载 (5-6) 为，对于每个区间 [first, first + (i - d_first + 1)) 中的 j ， init, *j... 在 binary_op 上的广义非交换和

其中广义非交换和 GNSUM(op, a
1, ..., a
N) 定义如下：

  • 若 N=1 ，则为 a
    1
  • 若 N > 1 ，则为 op(GNSUM(op, a
    1    , ..., a
    K    ), GNSUM(op, a
    M    , ..., a
    N    ))     ，对于任何 1 < K+1 = M ≤ N 中的 K

换言之，和运算可能以任意顺序进行，而且若 binary_op 非结合，则行为是非确定的。

重载 (2,4,6) 按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

binary_op 不应非话法范围 [first, last) 或 [d_first, d_first + (last - first)) 中的迭代器（含尾迭代器）或子范围，亦不应修改其中的元素。否则行为未定义。

参数

first, last | - | 要求和的元素范围
d_first | - | 目标范围的起始，可以等于 first
policy | - | 所用的执行策略。细节见执行策略。
init | - | 初始值（可选）
binary_op | - | 将应用到解引用输入迭代器结果、其他 binary_op 结果和 init （若提供）的二元函数对象 (FunctionObject) 。
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 若不提供 init ，则 decltype(first) 的值类型必须为可移动构造 (MoveConstructible) 且 binary_op(*first, *first) 必须可转换成 decltype(first) 的值类型。
- T （若提供 init ） 必须满足可移动构造 (MoveConstructible) 的要求。binary_op(init, *first) 、 binary_op(init, init) 及 binary_op(*first, *first) 都必须能转换到 T

返回值

指向最后写入元素后一位的迭代器。

复杂度

O(last - first) 次应用二元运算

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

示例

#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>

int main()
{
  std::vector data {3, 1, 4, 1, 5, 9, 2, 6};

  std::cout << "exclusive sum: ";
  std::exclusive_scan(data.begin(), data.end(),
                      std::ostream_iterator<int>(std::cout, " "),
                      0);
  std::cout << "\ninclusive sum: ";
  std::inclusive_scan(data.begin(), data.end(),
                      std::ostream_iterator<int>(std::cout, " "));

  std::cout << "\n\nexclusive product: ";
  std::exclusive_scan(data.begin(), data.end(),
                      std::ostream_iterator<int>(std::cout, " "),
                      1, std::multiplies<>{});
  std::cout << "\ninclusive product: ";
  std::inclusive_scan(data.begin(), data.end(),
                      std::ostream_iterator<int>(std::cout, " "),
                      std::multiplies<>{});
}

输出：

exclusive sum: 0 3 4 8 9 14 23 25
inclusive sum: 3 4 8 9 14 23 25 31

exclusive product: 1 3 3 12 12 60 540 1080
inclusive product: 3 3 12 12 60 540 1080 6480

参阅

adjacent_difference | 计算范围内各相邻元素之间的差 (函数模板)
accumulate | 对一个范围内的元素求和 (函数模板)
partial_sum | 计算范围内元素的部分和 (函数模板)
transform_inclusive_scan (C++17) | 应用一个函数对象，然后进行包含扫描 (函数模板)
exclusive_scan (C++17) | 类似 std::partial_sum，第 i 个和中排除第 i 个输入 (函数模板)


std::inner_product

< cpp‎ | algorithm
定义于头文件 <numeric> |
 | (1)
template< class InputIt1, class InputIt2, class T > T inner_product( InputIt1 first1, InputIt1 last1, InputIt2 first2, T init ); |  | (C++20 前)
template< class InputIt1, class InputIt2, class T > constexpr T inner_product( InputIt1 first1, InputIt1 last1, InputIt2 first2, T init ); |  | (C++20 起)
 | (2)
template<class InputIt1, class InputIt2, class T, class BinaryOperation1, class BinaryOperation2> T inner_product( InputIt1 first1, InputIt1 last1, InputIt2 first2, T init, BinaryOperation1 op1, BinaryOperation2 op2 ); |  | (C++20 前)
template<class InputIt1, class InputIt2, class T, class BinaryOperation1, class BinaryOperation2> constexpr T inner_product( InputIt1 first1, InputIt1 last1, InputIt2 first2, T init, BinaryOperation1 op1, BinaryOperation2 op2 ); |  | (C++20 起)

计算内积（即积之和）或在范围 [first1, last1) 和始于 first2 的范围上进行有序映射/规约操作。

1) 以初值 init 初始化积累器 acc ，然后
以表达式 acc = acc + *first1 * *first2 修改它，再以表达式 acc = acc + *(first1+1) * *(first2+1) 修改它，以此类推 | (C++20 前)
以表达式 acc = std::move(acc) + *first1 * *first2 修改它，再以表达式 acc = std::move(acc) + *(first1+1) * *(first2+1) 修改它，以此类推 | (C++20 起)
直至抵达 last1 。对于 + 与 * 的内建含义，此算法计算二个范围的内积。
2) 以初值 init 初始化积累器 acc ，然后
以表达式 acc = op1(acc, op2(*first1, *first2)) 修改它，再以表达式 acc = op1(acc, op2(*(first1+1), *(first2+1))) 修改它，以此类推 | (C++20 前)
以表达式 acc = op1(std::move(acc), op2(*first1, *first2)) 修改它，再以表达式 acc = op1(std::move(acc), op2(*(first1+1), *(first2+1))) 修改它，以此类推 | (C++20 起)
直至抵达 last1 。
op1 或 op2 必须无副作用。 | (C++11 前)
op1 或 op2 必须不非法化所涉及范围的任何迭代器，含尾迭代器或修改该范围的任何元素。 | (C++11 起)

参数

first1, last1 | - | 元素范围
first2 | - | 第二个元素范围的起始
init | - | 积的和的初值
op1 | - | 被使用的二元函数对象。此“和”函数接收 op2 所返回的值和当前积累器的值，并产生存储于积累器的新值。 该函数的签名应当等价于： Ret fun(const Type1 &a, const Type2 &b); 签名中并不需要有 const &。 类型 Type1 与 Type2 必须使得 T 与 Type3 类型的对象各能隐式转换成 Type1 与 Type2 。 类型 Ret 必须使得 T 类型对象能被赋 Ret 类型值。 ​
op2 | - | 被使用的二元函数对象。此“积”函数从每个范围接收一个值并产生新值。 该函数的签名应当等价于： Ret fun(const Type1 &a, const Type2 &b); 签名中并不需要有 const &。 类型 Type1 与 Type2 必须使得 InputIt1 与 InputIt2 类型的对象在解引用后分别能隐式转换到 Type1 与 Type2 。 类型 Ret 必须使得 Type3 类型对象能被赋 Ret 类型值。 ​
类型要求
- InputIt1, InputIt2 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- T 必须满足可复制赋值 (CopyAssignable) 和 可复制构造 (CopyConstructible) 的要求。

返回值

上述 acc 的最终值。

可能的实现

版本一
template<class InputIt1, class InputIt2, class T>
constexpr // C++20 起
T inner_product(InputIt1 first1, InputIt1 last1,
                InputIt2 first2, T init)
{
    while (first1 != last1) {
         init = std::move(init) + *first1 * *first2; // C++20 起有 std::move
         ++first1;
         ++first2;
    }
    return init;
}
版本二
template<class InputIt1, class InputIt2,
         class T,
         class BinaryOperation1, class BinaryOperation2>
constexpr // C++20 起
T inner_product(InputIt1 first1, InputIt1 last1,
                InputIt2 first2, T init,
                BinaryOperation1 op1,
                BinaryOperation2 op2)
{
    while (first1 != last1) {
         init = op1(std::move(init), op2(*first1, *first2)); // C++20 起有 std::move
         ++first1;
         ++first2;
    }
    return init;
}

注意

此算法的可并行版本 std::transform_reduce 要求 op1 与 op2 可交换并可结合，但 std::inner_product 不作这种要求，且始终以给定顺序进行操作。

示例

#include <numeric>
#include <iostream>
#include <vector>
#include <functional>
int main()
{
    std::vector<int> a{0, 1, 2, 3, 4};
    std::vector<int> b{5, 4, 2, 3, 1};

    int r1 = std::inner_product(a.begin(), a.end(), b.begin(), 0);
    std::cout << "Inner product of a and b: " << r1 << '\n';

    int r2 = std::inner_product(a.begin(), a.end(), b.begin(), 0,
                                std::plus<>(), std::equal_to<>());
    std::cout << "Number of pairwise matches between a and b: " <<  r2 << '\n';
}

输出：

Inner product of a and b: 21
Number of pairwise matches between a and b: 2

参阅

transform_reduce (C++17) | 应用一个函数对象，然后以乱序规约 (函数模板)
accumulate | 对一个范围内的元素求和 (函数模板)
partial_sum | 计算范围内元素的部分和 (函数模板)


std::inplace_merge

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
template< class BidirIt > void inplace_merge( BidirIt first, BidirIt middle, BidirIt last ); | (1) |
template< class ExecutionPolicy, class BidirIt > void inplace_merge( ExecutionPolicy&& policy, BidirIt first, BidirIt middle, BidirIt last ); | (2) | (C++17 起)
template< class BidirIt, class Compare> void inplace_merge( BidirIt first, BidirIt middle, BidirIt last, Compare comp ); | (3) |
template< class ExecutionPolicy, class BidirIt, class Compare> void inplace_merge( ExecutionPolicy&& policy, BidirIt first, BidirIt middle, BidirIt last, Compare comp ); | (4) | (C++17 起)

归并二个相继的已排序范围 [first, middle) 及 [middle, last) 为一个已排序范围 [first, last) 。

若对于任何指向序列的迭代器 it 与任何使得 it + n 为指向序列元素的合法迭代器的非负整数 n ， comp(*(it + n), *it) 求值为 false ，则称序列 [first, last) 相对于 comp 已排序。

此归并是稳定的，意思是对于原先二个范围中的等价元素。来自第一范围的元素（保持其原顺序）先于来自第二范围的元素（保持其原顺序）。

1) 用 operator< 比较元素，且范围必须对于同关系已排序。
3) 用给定的二元比较函数 comp 比较元素，且范围必须对于同关系已排序。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first | - | 第一个已排序范围的起始
middle | - | 第一个已排序范围的结尾及第二个已排序范围的起始
last | - | 第二个已排序范围的结尾
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 BidirIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- BidirIt 必须满足值可交换 (ValueSwappable) 和 老式双向迭代器 (LegacyBidirectionalIterator) 的要求。
- 解引用 BidirIt 结果的类型必须满足可移动赋值 (MoveAssignable) 和可移动构造 (MoveConstructible) 的要求。

返回值

（无）

复杂度

给定 N = std::distance (first, last)} ，

1,3) 若附加内存可用则准确为 N-1 次比较。若内存不足，则为 O(N log N) 次比较。
2,4) O(N log N) 次比较。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

此函数试图分配临时缓冲区。若分配失败，则选择较低效的算法。

可能的实现

参阅 libstdc++ 与 libc++ 中的实现。

示例

下列代码为归并排序的一种实现。

#include <vector>
#include <iostream>
#include <algorithm>

template<class Iter>
void merge_sort(Iter first, Iter last)
{
    if (last - first > 1) {
        Iter middle = first + (last - first) / 2;
        merge_sort(first, middle);
        merge_sort(middle, last);
        std::inplace_merge(first, middle, last);
    }
}

int main()
{
    std::vector<int> v{8, 2, -2, 0, 11, 11, 1, 7, 3};
    merge_sort(v.begin(), v.end());
    for(auto n : v) {
        std::cout << n << ' ';
    }
    std::cout << '\n';
}

输出：

-2 0 1 2 3 7 8 11 11

参阅

merge | 归并两个已排序的范围 (函数模板)
sort | 将范围按升序排序 (函数模板)
stable_sort | 将范围内的元素排序，同时保持相等的元素之间的顺序 (函数模板)


std::iota

< cpp‎ | algorithm
定义于头文件 <numeric> |
template< class ForwardIt, class T > void iota( ForwardIt first, ForwardIt last, T value ); | (C++11 起) (C++20 前)
template< class ForwardIt, class T > constexpr void iota( ForwardIt first, ForwardIt last, T value ); | (C++20 起)

以始于 value 并重复地求值 ++value 的顺序递增值填充范围 [first, last) 。

等价操作：

*(d_first)   = value;
*(d_first+1) = ++value;
*(d_first+2) = ++value;
*(d_first+3) = ++value;
...

参数

first, last | - | 以 value 开始，按顺序递增填充的值的范围
value | - | 要存储的初始值，表达式 ++value 必须为良式

返回值

（无）

复杂度

正好 last - first 次自增与赋值。

可能的实现

template<class ForwardIterator, class T>
constexpr // C++20 起
void iota(ForwardIterator first, ForwardIterator last, T value)
{
    while(first != last) {
        *first++ = value;
        ++value;
    }
}

注解

此函数命名来源于编程语言 APL 中的整数函数 ⍳ 。它是 C++98 所不曾包含的 STL 组件之一，但最终于 C++11 进入了标准库。

示例

下列代码应用 std::shuffle 到 std::list 迭代器的 vector ，因为不能直接应用 std::shuffle 到 std::list 。用 std::iota 填充二个容器。

#include <algorithm>
#include <iostream>
#include <list>
#include <numeric>
#include <random>
#include <vector>

int main()
{
    std::list<int> l(10);
    std::iota(l.begin(), l.end(), -4);

    std::vector<std::list<int>::iterator> v(l.size());
    std::iota(v.begin(), v.end(), l.begin());

    std::shuffle(v.begin(), v.end(), std::mt19937{std::random_device{}()});

    std::cout << "Contents of the list: ";
    for(auto n: l) std::cout << n << ' ';
    std::cout << '\n';

    std::cout << "Contents of the list, shuffled: ";
    for(auto i: v) std::cout << *i << ' ';
    std::cout << '\n';
}

可能的输出：

Contents of the list: -4 -3 -2 -1 0 1 2 3 4 5
Contents of the list, shuffled: 0 -1 3 4 -4 1 -2 -3 2 5

参阅

fill | 将一个给定值复制赋值给一个范围内的每个元素 (函数模板)
generate | 将相继的函数调用结果赋值给一个范围中的每个元素 (函数模板)


std::is_execution_policy

< cpp‎ | algorithm
定义于头文件 <execution> |
template< class T > struct is_execution_policy; | (C++17 起)

检查 T 是否标准或实现定义的执行策略类型。

若 T 是标准执行策略类型或实现定义的执行策略类型，则提供等于 true 的成员常量 value 。否则， value 等于 false 。

添加 is_execution_policy 或 is_execution_policy_v 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助模板

定义于头文件 <execution> |
template< class T > inline constexpr bool is_execution_policy_v = std::is_execution_policy<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 是标准或实现定义的执行策略类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

参阅

sequenced_policyparallel_policyparallel_unsequenced_policyunsequenced_policy (C++17)(C++17)(C++17)(C++20) | 执行策略类型 (类)
seqparpar_unsequnseq (C++17)(C++17)(C++17)(C++20) | 全局执行策略对象 (常量)


std::is_heap

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class RandomIt > bool is_heap( RandomIt first, RandomIt last ); |  |  | (C++11 起) (C++20 前)
template< class RandomIt > constexpr bool is_heap( RandomIt first, RandomIt last ); |  |  | (C++20 起)
template< class ExecutionPolicy, class RandomIt > bool is_heap( ExecutionPolicy&& policy, RandomIt first, RandomIt last ); | (2) | (C++17 起)
 | (3) |
template< class RandomIt, class Compare > bool is_heap( RandomIt first, RandomIt last, Compare comp ); |  |  | (C++11 起) (C++20 前)
template< class RandomIt, class Compare > constexpr bool is_heap( RandomIt first, RandomIt last, Compare comp ); |  |  | (C++20 起)
template< class ExecutionPolicy, class RandomIt, class Compare > bool is_heap( ExecutionPolicy&& policy, RandomIt first, RandomIt last, Compare comp ); | (4) | (C++17 起)

检查范围 [first, last) 中的元素是否为最大堆。

1) 用 operator< 比较元素。
3) 用给定的二元比较函数 comp 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要检验的元素范围
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若首个参数小于第二个，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 RandomIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- RandomIt 必须满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。

返回值

若范围为最大堆则为 true ，否则为 false 。

复杂度

与 first 和 last 间的距离成线性

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

最大堆是拥有下列属性的元素范围 [f,l) ：

  • 设 N = l - f ，对于所有 0 < i < N ， f[floor(
    i-1
    2
    )] 不小于 f[i] 。
  • 可用 std::push_heap () 添加新元素。
  • 可用 std::pop_heap () 移除首元素。

示例

#include <iostream>
#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> v { 3, 1, 4, 1, 5, 9 };

    std::cout << "initially, v: ";
    for (auto i : v) std::cout << i << ' ';
    std::cout << '\n';

    if (!std::is_heap(v.begin(), v.end())) {
        std::cout << "making heap...\n";
        std::make_heap(v.begin(), v.end());
    }

    std::cout << "after make_heap, v: ";
    for (auto i : v) std::cout << i << ' ';
    std::cout << '\n';
}

输出：

initially, v: 3 1 4 1 5 9
making heap...
after make_heap, v: 9 5 4 1 1 3

参阅

is_heap_until
(C++11)
 查找能成为最大堆的最大子范围
(函数模板)


std::is_heap_until

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class RandomIt > RandomIt is_heap_until( RandomIt first, RandomIt last ); |  |  | (C++11 起) (C++20 前)
template< class RandomIt > constexpr RandomIt is_heap_until( RandomIt first, RandomIt last ); |  |  | (C++20 起)
template< class ExecutionPolicy, class RandomIt > RandomIt is_heap_until( ExecutionPolicy&& policy, RandomIt first, RandomIt last ); | (2) | (C++17 起)
 | (3) |
template< class RandomIt, class Compare > RandomIt is_heap_until( RandomIt first, RandomIt last, Compare comp ); |  |  | (C++11 起) (C++20 前)
template< class RandomIt, class Compare > constexpr RandomIt is_heap_until( RandomIt first, RandomIt last, Compare comp ); |  |  | (C++20 起)
template< class ExecutionPolicy, class RandomIt, class Compare > RandomIt is_heap_until( ExecutionPolicy&& policy, RandomIt first, RandomIt last, Compare comp ); | (4) | (C++17 起)

检验范围 [first, last) 并寻找始于 first 且为最大堆的最大范围。

1) 用 operator< 比较元素。
3) 用给定的二元比较函数 comp 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要检验的元素范围
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若首个参数小于第二个，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 RandomIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- RandomIt 必须满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。

返回值

始于 first 且为最大堆的最大范围上界。即满足范围 [first, it) 是最大堆的最末迭代器 it 。

复杂度

与 first 和 last 间的距离成线性。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

最大堆是拥有下列属性的元素范围 [f,l) ：

  • 设 N = l - f ，对于所有 0 < i < N ， f[floor(
    i-1
    2
    )] 不小于 f[i] 。
  • 可用 std::push_heap () 添加新元素。
  • 可用 std::pop_heap () 移除首元素。

示例

#include <iostream>
#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> v { 3, 1, 4, 1, 5, 9 };

    std::make_heap(v.begin(), v.end());

    // 很可能扰乱堆
    v.push_back(2);
    v.push_back(6);

    auto heap_end = std::is_heap_until(v.begin(), v.end());

    std::cout << "all of v: ";
    for (auto i : v) std::cout << i << ' ';
    std::cout << '\n';

    std::cout << "only heap: ";
    for (auto i = v.begin(); i != heap_end; ++i) std::cout << *i << ' ';
    std::cout << '\n';
}

输出：

all of v:  9 5 4 1 1 3 2 6
only heap: 9 5 4 1 1 3 2

参阅

is_heap
 检查给定范围是否为一个最大堆
(函数模板)


std::is_partitioned

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class InputIt, class UnaryPredicate > bool is_partitioned( InputIt first, InputIt last, UnaryPredicate p ); |  |  | (C++11 起) (C++20 前)
template< class InputIt, class UnaryPredicate > constexpr bool is_partitioned( InputIt first, InputIt last, UnaryPredicate p ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate > bool is_partitioned( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryPredicate p ); | (2) | (C++17 起)
1) 若范围 [first, last) 中的所有满足 p 的元素都出现在所有不满足的元素前则返回 true 。若 [first, last) 为空亦返回 true 。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要检查的元素范围
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若期待在范围开始找到该元素则返回 ​true 的一元谓词。 对每个（可为 const 的） VT 类型参数 v ，其中 VT 是 InputIt 的值类型，表达式 p(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 VT& 类型参数，亦不允许 VT ，除非对 VT 而言移动等价于复制 (C++11 起)。 ​
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。而其值类型必须可转换为 UnaryPredicate 的参数类型
- UnaryPredicate 必须满足谓词 (Predicate) 的要求。

返回值

若范围 [first, last) 为空或以 p 划分则为 true 。否则为 false 。

复杂度

至多应用 std::distance(first, last) 次 p 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template< class InputIt, class UnaryPredicate >
bool is_partitioned(InputIt first, InputIt last, UnaryPredicate p)
{
    for (; first != last; ++first)
        if (!p(*first))
            break;
    for (; first != last; ++first)
        if (p(*first))
            return false;
    return true;
}

示例

#include <algorithm>
#include <array>
#include <iostream>

int main()
{
    std::array<int, 9> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    auto is_even = [](int i){ return i % 2 == 0; };
    std::cout.setf(std::ios_base::boolalpha);
    std::cout << std::is_partitioned(v.begin(), v.end(), is_even) << ' ';

    std::partition(v.begin(), v.end(), is_even);
    std::cout << std::is_partitioned(v.begin(), v.end(), is_even) << ' ';

    std::reverse(v.begin(), v.end());
    std::cout << std::is_partitioned(v.begin(), v.end(), is_even);
}

输出：

false true false

参阅

partition | 将范围中的元素分为两组 (函数模板)
partition_point (C++11) | 定位已划分范围的划分点 (函数模板)


std::is_permutation

< cpp‎ | algorithm
定义于头文件 <algorithm> |
 | (1)
template< class ForwardIt1, class ForwardIt2 > bool is_permutation( ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2 ); |  | (C++11 起) (C++20 前)
template< class ForwardIt1, class ForwardIt2 > constexpr bool is_permutation( ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2 ); |  | (C++20 起)
 | (2)
template< class ForwardIt1, class ForwardIt2, class BinaryPredicate > bool is_permutation( ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, BinaryPredicate p ); |  | (C++11 起) (C++20 前)
template< class ForwardIt1, class ForwardIt2, class BinaryPredicate > constexpr bool is_permutation( ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, BinaryPredicate p ); |  | (C++20 起)
 | (3)
template< class ForwardIt1, class ForwardIt2 > bool is_permutation( ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2 ); |  | (C++14 起) (C++20 前)
template< class ForwardIt1, class ForwardIt2 > constexpr bool is_permutation( ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2 ); |  | (C++20 起)
 | (4)
template< class ForwardIt1, class ForwardIt2, class BinaryPredicate > bool is_permutation( ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, BinaryPredicate p ); |  | (C++14 起) (C++20 前)
template< class ForwardIt1, class ForwardIt2, class BinaryPredicate > constexpr bool is_permutation( ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, BinaryPredicate p ); |  | (C++20 起)

若存在范围 [first1, last1) 中元素的排列，使得该范围等于 [first2,last2) ，则返回 true ，若不给出，则其中 last2 代表 first2 + (last1 - first1) 。

1,3) 用 operator== 比较元素。若它不是等价关系则行为未定义。
2,4) 用给定的二元谓词 p 比较元素。若它不是等价关系则行为未定义。

参数

first1, last1 | - | 要比较的元素范围
first2, last2 | - | 要比较的第二范围
p | - | 若应把元素当做相等则返回 ​true 的二元谓词。 谓词函数的签名应等价于如下： bool pred(const Type &a, const Type &b); Type 应是 ForwardIt1 和 ForwardIt2 两者的值类型。签名不必有 const & ，但函数必须不修改传递给它的对象。 ​
类型要求
- ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- ForwardIt1 与 ForwardIt2 必须拥有相同的值类型。

返回值

若范围 [first1, last1) 是 [first2, last2) 的排列则为 true 。

复杂度

至多应用 \(\scriptsize \mathcal{O}(N^2)\)O(N2) 次谓词，或若序列已经相等，则准确应用 \(\scriptsize N\)N 次，其中 \(\scriptsize N\)N 为 std::distance (first1, last1) 。

然而，若 ForwardIt1 和 ForwardIt2 满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求且 std::distance (first1, last1) != std::distance (first2, last2) ，则不应用谓词。 排列关系是等价关系。

注解

std::is_permutation 能用于按照其名称地测试重排算法（例如排序、打乱、划分）的正确性。若 x 为原范围而 y 是重排后范围则 std::is_permutation(x, y) == true 表示 y 由可能位于其他位置的“相同”元素组成。

可能的实现

template<class ForwardIt1, class ForwardIt2>
bool is_permutation(ForwardIt1 first, ForwardIt1 last,
                    ForwardIt2 d_first)
{
   // 跳过公共前缀
   std::tie(first, d_first) = std::mismatch(first, last, d_first);
   // 在 rest 上迭代，计数 [d_first, d_last) 中出现多少次
   // 每个来自 [first, last) 的元素
   if (first != last) {
       ForwardIt2 d_last = d_first;
       std::advance(d_last, std::distance(first, last));
       for (ForwardIt1 i = first; i != last; ++i) {
            if (i != std::find(first, i, *i)) continue; // 已经遇到此 *i

            auto m = std::count(d_first, d_last, *i);
            if (m==0 || std::count(i, last, *i) != m) {
                return false;
            }
        }
    }
    return true;
}

示例

#include <iostream>
#include <algorithm>

template<typename Os, typename V>
Os& operator<< (Os& os, V const& v) {
    os << "{ ";
    for (auto const& e : v) os << e << ' ';
    return os << "}";
}

int main()
{
    static constexpr auto v1 = {1,2,3,4,5};
    static constexpr auto v2 = {3,5,4,1,2};
    static constexpr auto v3 = {3,5,4,1,1};

    std::cout << v2 << " is a permutation of " << v1 << ": " << std::boolalpha
              << std::is_permutation(v1.begin(), v1.end(), v2.begin()) << '\n'
              << v3 << " is a permutation of " << v1 << ": " << std::boolalpha
              << std::is_permutation(v1.begin(), v1.end(), v3.begin()) << '\n';
}

输出：

{ 3 5 4 1 2 } is a permutation of { 1 2 3 4 5 }: true
{ 3 5 4 1 1 } is a permutation of { 1 2 3 4 5 }: false

参阅

next_permutation | 产生某个元素范围的按字典顺序的下一个较大的排列 (函数模板)
prev_permutation | 产生某个元素范围的按字典顺序的下一个较小的排列 (函数模板)
equivalence_relation (C++20) | 指定 relation 施加等价关系 (概念)
ranges::is_permutation (C++20) | 确定一个序列是否为另一序列的重排 (niebloid)


std::is_sorted

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class ForwardIt >
bool is_sorted( ForwardIt first, ForwardIt last );
 (C++11 起)
(C++20 前)
template< class ForwardIt >
constexpr bool is_sorted( ForwardIt first, ForwardIt last );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt >
bool is_sorted( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last );
 (2) (C++17 起)
(3)
template< class ForwardIt, class Compare >
bool is_sorted( ForwardIt first, ForwardIt last, Compare comp );
 (C++11 起)
(C++20 前)
template< class ForwardIt, class Compare >
constexpr bool is_sorted( ForwardIt first, ForwardIt last, Compare comp );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class Compare >

bool is_sorted( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,

Compare comp );
 (4) (C++17 起)

检查 [first, last) 中的元素是否以不降序排序。

若对于任何指向序列的迭代器 it 与任何使得 it + n 为指向序列元素的合法迭代器的非负整数 n ， comp(*(it + n), *it) 求值为 false ，则称序列相对于 comp 已排序。

1) 用 operator< 比较元素。
3) 用给定的二元比较函数 comp 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要检验的元素范围
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 ForwardIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

若范围中的元素已按不降序排序则为 true 。

复杂度

与 first 和 last 间的距离成线性。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class ForwardIt>
bool is_sorted(ForwardIt first, ForwardIt last)
{
    return std::is_sorted_until(first, last) == last;
}
版本二
template<class ForwardIt, class Compare>
bool is_sorted(ForwardIt first, ForwardIt last, Compare comp)
{
    return std::is_sorted_until(first, last, comp) == last;
}

注解

std::is_sorted 对空范围及长为 1 的范围均返回 true 。

示例

#include <iostream>
#include <algorithm>
#include <iterator>
int main()
{
    int digits[] = {3, 1, 4, 1, 5};

    for (auto i : digits) std::cout << i << ' ';
    std::cout << ": is_sorted: " << std::boolalpha
              << std::is_sorted(std::begin(digits), std::end(digits)) << '\n';

    std::sort(std::begin(digits), std::end(digits));

    for (auto i : digits) std::cout << i << ' ';
    std::cout << ": is_sorted: "
              << std::is_sorted(std::begin(digits), std::end(digits)) << '\n';
}

输出：

3 1 4 1 5 : is_sorted: false
1 1 3 4 5 : is_sorted: true

参阅

is_sorted_until
(C++11)
 找出最大的已排序子范围
(函数模板)


std::is_sorted_until

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class ForwardIt >
ForwardIt is_sorted_until( ForwardIt first, ForwardIt last );
 (C++11 起)
(C++20 前)
template< class ForwardIt >
constexpr ForwardIt is_sorted_until( ForwardIt first, ForwardIt last );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt >

ForwardIt is_sorted_until( ExecutionPolicy&& policy,

ForwardIt first, ForwardIt last );
 (2) (C++17 起)
(3)
template< class ForwardIt, class Compare >

ForwardIt is_sorted_until( ForwardIt first, ForwardIt last,

Compare comp );
 (C++11 起)
(C++20 前)
template< class ForwardIt, class Compare >

constexpr ForwardIt is_sorted_until( ForwardIt first, ForwardIt last,

Compare comp );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class Compare >

ForwardIt is_sorted_until( ExecutionPolicy&& policy,

ForwardIt first, ForwardIt last, Compare comp );
 (4) (C++17 起)

检验范围 [first, last) ，并寻找始于 first 且其中元素已以不降序排序的最大范围。

若对于任何指向序列的迭代器 it 与任何使得 it + n 为指向序列元素的合法迭代器的非负整数 n ， comp(*(it + n), *it) 求值为 false ，则称序列相对于 comp 已排序。

1) 用 operator< 比较元素。
3) 用给定的二元比较函数 comp 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要检验的元素范围
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 ForwardIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

始于 first 且其中元素已以升序排序的最大范围。即满足范围 [first, it) 已排序的最后迭代器 it 。

复杂度

与 first 和 last 间的距离成线性。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

参阅 libstdc++ 与 libc++ 中的实现。

版本一
template<class ForwardIt>
ForwardIt is_sorted_until(ForwardIt first, ForwardIt last)
{
    return is_sorted_until(first, last, std::less<>());
}
版本二
template <class ForwardIt, class Compare>
ForwardIt is_sorted_until(ForwardIt first, ForwardIt last, Compare comp)
{
    if (first != last) {
        ForwardIt next = first;
        while (++next != last) {
            if (comp(*next, *first))
                return next;
            first = next;
        }
    }
    return last;
}

注解

std::is_sorted_until 对空范围及长为 1 的范围均返回 last 。

示例

#include <iostream>
#include <algorithm>
#include <iterator>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 g(rd());
    const int N = 6;
    int nums[N] = {3, 1, 4, 1, 5, 9};

    const int min_sorted_size = 4;
    int sorted_size = 0;
    do {
        std::shuffle(nums, nums + N, g);
        int *sorted_end = std::is_sorted_until(nums, nums + N);
        sorted_size = std::distance(nums, sorted_end);

        for (auto i : nums) std::cout << i << ' ';
        std::cout << " : " << sorted_size << " initial sorted elements\n";
    } while (sorted_size < min_sorted_size);
}

可能的输出：

4 1 9 5 1 3  : 1 initial sorted elements
4 5 9 3 1 1  : 3 initial sorted elements
9 3 1 4 5 1  : 1 initial sorted elements
1 3 5 4 1 9  : 3 initial sorted elements
5 9 1 1 3 4  : 2 initial sorted elements
4 9 1 5 1 3  : 2 initial sorted elements
1 1 4 9 5 3  : 4 initial sorted elements

参阅

is_sorted
(C++11)
 检查范围是否已按升序排列
(函数模板)


std::iter_swap

< cpp‎ | algorithm
定义于头文件 <algorithm> |
template< class ForwardIt1, class ForwardIt2 > void iter_swap( ForwardIt1 a, ForwardIt2 b ); | (C++20 前)
template< class ForwardIt1, class ForwardIt2 > constexpr void iter_swap( ForwardIt1 a, ForwardIt2 b ); | (C++20 起)

交换给定的迭代器所指向的元素的值。

参数

a, b - 指向要交换的元素的迭代器
类型要求
-
ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
-
*a, *b 必须满足可交换 (Swappable) 的要求。

返回值

（无）

复杂度

常数

可能的实现

template<class ForwardIt1, class ForwardIt2>
constexpr void iter_swap(ForwardIt1 a, ForwardIt2 b) // C++20 起为 constexpr
{
   using std::swap;
   swap(*a, *b);
}

示例

下面是选择排序在 C++ 中的实现

#include <random>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>

template<class ForwardIt>
void selection_sort(ForwardIt begin, ForwardIt end)
{
    for (ForwardIt i = begin; i != end; ++i)
        std::iter_swap(i, std::min_element(i, end));
}

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dist(-10, 10);
    std::vector<int> v;
    std::generate_n(back_inserter(v), 20, bind(dist, gen));

    std::cout << "Before sort: ";
    for(auto e : v) std::cout << e << " ";

    selection_sort(v.begin(), v.end());

    std::cout << "\nAfter sort: ";
    for(auto e : v) std::cout << e << " ";
    std::cout << '\n';
}

输出：

Before sort: -7 6 2 4 -1 6 -9 -1 2 -5 10 -9 -5 -3 -5 -3 6 6 1 8
After sort: -9 -9 -7 -5 -5 -5 -3 -3 -1 -1 1 2 2 4 6 6 6 6 8 10

参阅

swap | 交换两个对象的值 (函数模板)
swap_ranges | 交换两个范围的元素 (函数模板)


std::lexicographical_compare

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class InputIt1, class InputIt2 >

bool lexicographical_compare( InputIt1 first1, InputIt1 last1,

InputIt2 first2, InputIt2 last2 );
 (C++20 前)
template< class InputIt1, class InputIt2 >

constexpr bool lexicographical_compare( InputIt1 first1, InputIt1 last1,

InputIt2 first2, InputIt2 last2 );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >

bool lexicographical_compare( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1,

ForwardIt2 first2, ForwardIt2 last2 );
 (2) (C++17 起)
(3)
template< class InputIt1, class InputIt2, class Compare >

bool lexicographical_compare( InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2,

Compare comp );
 (C++20 前)
template< class InputIt1, class InputIt2, class Compare >

constexpr bool lexicographical_compare( InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2,

Compare comp );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class Compare >

bool lexicographical_compare( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1,
ForwardIt2 first2, ForwardIt2 last2,

Compare comp );
 (4) (C++17 起)

检查第一个范围 [first1, last1) 是否按字典序小于第二个范围 [first2, last2) 。

1) 用 operator< 比较元素。
3) 用给定的二元比较函数 comp 比较函数。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。。

字典序比较是拥有下列属性的操作：

  • 逐元素比较二个范围。
  • 首个不匹配元素定义范围是否按字典序小于或大于另一个。
  • 若一个范围是另一个的前缀，则较短的范围小于另一个。
  • 若二个范围拥有等价元素和相同长度，则范围按字典序相等。
  • 空范围按字典序小于任何非空范围。
  • 二个空范围按字典序相等。

参数

first1, last1 | - | 要检验的第一个元素范围
first2, last2 | - | 要检验的第二个元素范围
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若首个参数小于第二个，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 InputIt1 与 InputIt2 类型的对象在解引用后能隐式转换到 Type1 与 Type2 两者。 ​
类型要求
- InputIt1, InputIt2 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

若第一范围按字典序小于第二个则为 true 。

复杂度

至多应用 2·min(N1, N2) 次比较运算，其中 N1 = std::distance (first1, last1) 而 N2 = std::distance (first2, last2) 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class InputIt1, class InputIt2>
bool lexicographical_compare(InputIt1 first1, InputIt1 last1,
                             InputIt2 first2, InputIt2 last2)
{
    for ( ; (first1 != last1) && (first2 != last2); ++first1, (void) ++first2 ) {
        if (*first1 < *first2) return true;
        if (*first2 < *first1) return false;
    }
    return (first1 == last1) && (first2 != last2);
}
版本二
template<class InputIt1, class InputIt2, class Compare>
bool lexicographical_compare(InputIt1 first1, InputIt1 last1,
                             InputIt2 first2, InputIt2 last2,
                             Compare comp)
{
    for ( ; (first1 != last1) && (first2 != last2); ++first1, (void) ++first2 ) {
        if (comp(*first1, *first2)) return true;
        if (comp(*first2, *first1)) return false;
    }
    return (first1 == last1) && (first2 != last2);
}

示例

#include <algorithm>
#include <iostream>
#include <vector>
#include <random>

int main()
{
    std::vector<char> v1 {'a', 'b', 'c', 'd'};
    std::vector<char> v2 {'a', 'b', 'c', 'd'};

    std::mt19937 g{std::random_device{}()};
    while (!std::lexicographical_compare(v1.begin(), v1.end(),
                                         v2.begin(), v2.end())) {
        for (auto c : v1) std::cout << c << ' ';
        std::cout << ">= ";
        for (auto c : v2) std::cout << c << ' ';
        std::cout << '\n';

        std::shuffle(v1.begin(), v1.end(), g);
        std::shuffle(v2.begin(), v2.end(), g);
    }

    for (auto c : v1) std::cout << c << ' ';
    std::cout << "< ";
    for (auto c : v2) std::cout << c << ' ';
    std::cout << '\n';
}

可能的输出：

a b c d >= a b c d
d a b c >= c b d a
b d a c >= a d c b
a c d b < c d a b

参阅

equal
 确定两个元素集合是否是相同的
(函数模板)


std::lexicographical_compare_three_way

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
template< class InputIt1, class InputIt2, class Cmp > constexpr auto lexicographical_compare_three_way( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Cmp comp) -> decltype(comp(*first1, *first2)); | (1) | (C++20 起)
template< class InputIt1, class InputIt2 > constexpr auto lexicographical_compare_three_way( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2); | (2) | (C++20 起)

用三路比较，以字典序比较二个范围 [first1, last1) 和 [first2, last2) ，并产生最强可应用比较类别类型的结果。

1) 返回两个范围中首对按照 comp 不等价的元素间的序，若它们存在，否则（若一个范围按照 comp 等价于另一个范围的前缀）返回两个范围长度间的序。
2) 等价于：
return std::lexicographical_compare_three_way(
    first1, last1, first2, last2, std::compare_three_way());

参数

first1, last1 | - | 要检验的第一元素范围
first2, last2 | - | 要检验的第二元素范围
comp | - | 函数对象类型。若其返回类型不是三个比较类别类型（ std::strong_ordering、 std::weak_ordering 或 std::partial_ordering ）之一则程序非良构。
类型要求
- InputIt1, InputIt2 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

定义如上的比较类别类型的值。

复杂度

至多应用 N 次 comp ，其中 N 为两范围长度的较小者。

可能的实现

template< class I1, class I2, class Cmp >
constexpr auto lexicographical_compare_three_way( I1 f1, I1 l1, I2 f2, I2 l2, Cmp comp )
    -> decltype(comp(*f1, *f2))
{
    using ret_t = decltype(comp(*f1, *f2));
    static_assert(std::disjunction_v<
                      std::is_same<ret_t, std::strong_ordering>,
                      std::is_same<ret_t, std::weak_ordering>,
                      std::is_same<ret_t, std::partial_ordering>>,
                  "The return type must be a comparison category type.");

    bool exhaust1 = (f1 == l1);
    bool exhaust2 = (f2 == l2);
    for (; !exhaust1 && !exhaust2; exhaust1 = (++f1 == l1), exhaust2 = (++f2 == l2))
        if (auto c = comp(*f1, *f2); c != 0)
            return c;

    return !exhaust1 ? std::strong_ordering::greater :
           !exhaust2 ? std::strong_ordering::less :
                       std::strong_ordering::equal;
}

示例

#include <algorithm>
#include <cctype>
#include <compare>
#include <iomanip>
#include <iostream>
#include <string_view>
#include <utility>
using namespace std::literals;

void show_result(std::string_view s1, std::string_view s2, std::strong_ordering o)
{
    std::cout << quoted(s1) << " is ";
    (o < 0) ? std::cout << "less than " :
    (o > 0) ? std::cout << "greater than " :
              std::cout << "equal to ";
    std::cout << quoted(s2) << '\n';
}

int main()
{
    auto cmp_icase = [](char x, char y) {
        const auto ux { std::toupper(x) };
        const auto uy { std::toupper(y) };
        return (ux < uy) ? std::strong_ordering::less:
               (ux > uy) ? std::strong_ordering::greater:
                           std::strong_ordering::equal;
    };

    for (const auto& [s1, s2] : { std::pair{"one"sv, "ONE"sv},
                                           {"two"sv, "four"sv},
                                           {"three"sv, "two"sv} }) {
        const auto res = std::lexicographical_compare_three_way(
            s1.cbegin(), s1.cend(), s2.cbegin(), s2.cend(), cmp_icase);
        show_result(s1, s2, res);
    }
}

输出：

"one" is equal to "ONE"
"two" is greater than "four"
"three" is less than "two"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3410 | C++20 | 要求了额外的迭代器间比较 | 移除该要求

参阅

lexicographical_compare | 当一个范围按字典顺序小于另一个范围时，返回 true (函数模板)
compare_three_way (C++20) | 实现 x <=> y 的函数对象 (类)
ranges::lexicographical_compare (C++20) | 当一个范围按字典顺序小于另一个范围时，返回 true (niebloid)


std::lower_bound

< cpp‎ | algorithm
定义于头文件 <algorithm> |
 | (1)
template< class ForwardIt, class T > ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value ); |  | (C++20 前)
template< class ForwardIt, class T > constexpr ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value ); |  | (C++20 起)
 | (2)
template< class ForwardIt, class T, class Compare > ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value, Compare comp ); |  | (C++20 前)
template< class ForwardIt, class T, class Compare > constexpr ForwardIt lower_bound( ForwardIt first, ForwardIt last, const T& value, Compare comp ); |  | (C++20 起)

返回指向范围 [first, last) 中首个不小于（即大于或等于） value 的元素的迭代器，或若找不到这种元素则返回 last 。

范围 [first, last) 必须已相对于表达式 element < value 或 comp(element, value) 划分，即所有令该表达式为 true 的元素必须前趋所有令该表达式为 false 的元素。完全排序的范围满足此判别标准。

第一版本用 operator< 比较元素，第二版本用给定的比较函数 comp 。

参数

first, last | - | 定义要检验的已部分排序范围的迭代器
value | - | 要与元素比较的值
comp | - | 若第一参数小于（即先序于）第二个则返回 ​true 的二元谓词。 谓词函数的签名应等价于如下： bool pred(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 必须使得 ForwardIt 类型的对象能在解引用后隐式转换到 Type1 。类型 Type2 必须使得 T 类型的对象能隐式转换到 Type2 。 ​
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- Compare 必须满足二元谓词 (BinaryPredicate) 的要求。不要求满足 比较 (Compare) 。

返回值

指向首个不小于 value 的元素的迭代器，或若找不到这种元素则为 last 。

复杂度

进行的比较次数与 first 和 last 间的距离成对数（至多 log
2(last - first) + O(1) 次比较）。然而，对于非老式随机访问迭代器 (LegacyRandomAccessIterator) ，迭代次自增次数为线性。

可能的实现

版本一
template<class ForwardIt, class T>
ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value)
{
    ForwardIt it;
    typename std::iterator_traits<ForwardIt>::difference_type count, step;
    count = std::distance(first, last);

    while (count > 0) {
        it = first;
        step = count / 2;
        std::advance(it, step);
        if (*it < value) {
            first = ++it;
            count -= step + 1;
        }
        else
            count = step;
    }
    return first;
}
版本二
template<class ForwardIt, class T, class Compare>
ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value, Compare comp)
{
    ForwardIt it;
    typename std::iterator_traits<ForwardIt>::difference_type count, step;
    count = std::distance(first, last);

    while (count > 0) {
        it = first;
        step = count / 2;
        std::advance(it, step);
        if (comp(*it, value)) {
            first = ++it;
            count -= step + 1;
        }
        else
            count = step;
    }
    return first;
}

示例

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> data = { 1, 2, 4, 5, 5, 6 };

    for (int i = 0; i < 8; ++i) {
        // 搜索首个不小于 i 的元素
        auto lower = std::lower_bound(data.begin(), data.end(), i);

        std::cout << i << " <= ";
        if (lower != data.end())
            std::cout << *lower << " at index " << std::distance(data.begin(), lower);
        else
            std::cout << "not found";
        std::cout << '\n';
    }
}

输出：

0 <= 1 at index 0
1 <= 1 at index 0
2 <= 2 at index 1
3 <= 4 at index 2
4 <= 4 at index 2
5 <= 5 at index 3
6 <= 6 at index 5
7 <= not found

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 270 | C++98 | 曾要求 Compare 为严格弱序 | 只需要划分；容许异相比较

参阅

equal_range | 返回匹配特定键值的元素范围 (函数模板)
upper_bound | 返回指向第一个大于给定值的元素的迭代器 (函数模板)
partition | 将范围中的元素分为两组 (函数模板)
partition_point (C++11) | 定位已划分范围的划分点 (函数模板)


std::make_heap

< cpp‎ | algorithm
定义于头文件 <algorithm> |
 | (1)
template< class RandomIt > void make_heap( RandomIt first, RandomIt last ); |  | (C++20 前)
template< class RandomIt > constexpr void make_heap( RandomIt first, RandomIt last ); |  | (C++20 起)
 | (2)
template< class RandomIt, class Compare > void make_heap( RandomIt first, RandomIt last, Compare comp ); |  | (C++20 前)
template< class RandomIt, class Compare > constexpr void make_heap( RandomIt first, RandomIt last, Compare comp ); |  | (C++20 起)

在范围 [first, last) 中构造最大堆。函数第一版本用 operator< 比较元素，第二版本用给定的比较函数 comp 。

参数

first, last | - | 制作堆来源的元素范围
comp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若首个参数小于第二个，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 RandomIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- RandomIt 必须满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。
- 解引用 RandomIt 结果的类型必须满足可移动赋值 (MoveAssignable) 和可移动构造 (MoveConstructible) 的要求。

返回值

（无）

复杂度

至多 3* std::distance (first, last) 次比较。

注意

最大堆是拥有下列属性的元素范围 [f,l) ：

  • 设 N = l - f ，对于所有 0 < i < N ， f[floor(
    i-1
    2
    )] 不小于 f[i] 。
  • 可用 std::push_heap () 添加新元素。
  • 可用 std::pop_heap () 移除首元素。

示例

#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>

int main()
{
    std::cout << "Max heap:\n";

    std::vector<int> v { 3, 2, 4, 1, 5, 9 };

    std::cout << "initially, v: ";
    for (auto i : v) std::cout << i << ' ';
    std::cout << '\n';

    std::make_heap(v.begin(), v.end());

    std::cout << "after make_heap, v: ";
    for (auto i : v) std::cout << i << ' ';
    std::cout << '\n';

    std::pop_heap(v.begin(), v.end());

    std::cout << "after pop_heap, v: ";
    for (auto i : v) std::cout << i << ' ';
    std::cout << '\n';

    auto top = v.back();
    v.pop_back();
    std::cout << "former top element: " << top << '\n';

    std::cout << "after removing the former top element, v: ";
    for (auto i : v) std::cout << i << ' ';
    std::cout << '\n' << '\n';

    std::cout << "Min heap:\n";

    std::vector<int> v1 { 3, 2, 4, 1, 5, 9 };

    std::cout << "initially, v1: ";
    for (auto i : v1) std::cout << i << ' ';
    std::cout << '\n';

    std::make_heap(v1.begin(), v1.end(), std::greater<>{});

    std::cout << "after make_heap, v1: ";
    for (auto i : v1) std::cout << i << ' ';
    std::cout << '\n';

    std::pop_heap(v1.begin(), v1.end(), std::greater<>{});

    std::cout << "after pop_heap, v1: ";
    for (auto i : v1) std::cout << i << ' ';
    std::cout << '\n';

    auto top1 = v1.back();
    v1.pop_back();
    std::cout << "former top element: " << top1 << '\n';

    std::cout << "after removing the former top element, v1: ";
    for (auto i : v1) std::cout << i << ' ';
    std::cout << '\n';
}

输出：

Max heap:
initially, v: 3 2 4 1 5 9
after make_heap, v: 9 5 4 1 2 3
after pop_heap, v: 5 3 4 1 2 9
former top element: 9
after removing the former top element, v: 5 3 4 1 2

Min heap:
initially, v1: 3 2 4 1 5 9
after make_heap, v1: 1 2 4 3 5 9
after pop_heap, v1: 2 3 4 9 5 1
former top element: 1
after removing the former top element, v1: 2 3 4 9 5

参阅

sort_heap | 将一个最大堆变成一个按升序排序的元素范围 (函数模板)
priority_queue | 适配一个容器以提供优先级队列 (类模板)
greater | 实现 x > y 的函数对象 (类模板)


std::max

< cpp‎ | algorithm
定义于头文件 <algorithm> |
 | (1)
template< class T > const T& max( const T& a, const T& b ); |  | (C++14 前)
template< class T > constexpr const T& max( const T& a, const T& b ); |  | (C++14 起)
 | (2)
template< class T, class Compare > const T& max( const T& a, const T& b, Compare comp ); |  | (C++14 前)
template< class T, class Compare > constexpr const T& max( const T& a, const T& b, Compare comp ); |  | (C++14 起)
 | (3)
template< class T > T max( std::initializer_list <T> ilist ); |  | (C++11 起) (C++14 前)
template< class T > constexpr T max( std::initializer_list <T> ilist ); |  | (C++14 起)
 | (4)
template< class T, class Compare > T max( std::initializer_list <T> ilist, Compare comp ); |  | (C++11 起) (C++14 前)
template< class T, class Compare > constexpr T max( std::initializer_list <T> ilist, Compare comp ); |  | (C++14 起)

返回给定值中的较大者。

1-2) 返回 a 与 b 的较大者。
3-4) 返回 initializer_list ilist 中值的最大者。

(1,3) 版本用 operator< 比较元素， (2,4) 版本用给定的比较函数 comp 。

参数

a, b | - | 要比较的值
ilist | - | 拥有要比较的值的 initializer_list
cmp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若若 a 小于 b ，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 T 类型的对象能隐式转换到这两个类型。 ​
类型要求
- 为使用重载 (1,3) ， T 必须满足可小于比较 (LessThanComparable) 的要求。
- 为使用重载 (3,4) ， T 必须满足可复制构造 (CopyConstructible) 的要求。

返回值

1-2) a 与 b 的较大者。若它们等价，则返回 a 。
3-4) ilist 中的最大值。若有数个等价于最大者的值，则返回最左侧的这种值。

复杂度

1-2) 准确一次比较
3-4) 准确 ilist.size() - 1 次比较

可能的实现

版本一
template<class T>
const T& max(const T& a, const T& b)
{
    return (a < b) ? b : a;
}
版本二
template<class T, class Compare>
const T& max(const T& a, const T& b, Compare comp)
{
    return (comp(a, b)) ? b : a;
}
版本三
template< class T >
T max( std::initializer_list<T> ilist)
{
    return *std::max_element(ilist.begin(), ilist.end());
}
版本四
template< class T, class Compare >
T max( std::initializer_list<T> ilist, Compare comp )
{
    return *std::max_element(ilist.begin(), ilist.end(), comp);
}

注意

若参数之一是临时量，而该参数被返回，则以引用捕获 std::max 的结果会产生一个悬垂引用：

int n = 1;
const int& r = std::max(n-1, n+1);
// r 悬垂

示例

#include <algorithm>
#include <iostream>
#include <string>

int main()
{
    std::cout << "larger of 1 and 9999: " << std::max(1, 9999) << '\n'
              << "larger of 'a', and 'b': " << std::max('a', 'b') << '\n'
              << "longest of \"foo\", \"bar\", and \"hello\": " <<
                  std::max( { "foo", "bar", "hello" },
                            [](const std::string& s1, const std::string& s2) {
                                 return s1.size() < s2.size();
                             }) << '\n';
}

输出：

larger of 1 and 9999: 9999
larger of 'a', and 'b': b
longest of "foo", "bar", and "hello": hello

参阅

min | 返回各给定值中的较小者 (函数模板)
minmax (C++11) | 返回两个元素的较小和较大者 (函数模板)
max_element | 返回范围内的最大元素 (函数模板)
clamp (C++17) | 在一对边界值间夹逼一个值 (函数模板)


std::max_element

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class ForwardIt > ForwardIt max_element(ForwardIt first, ForwardIt last ); |  |  | (C++17 前)
template< class ForwardIt > constexpr ForwardIt max_element(ForwardIt first, ForwardIt last ); |  |  | (C++17 起)
template< class ExecutionPolicy, class ForwardIt > ForwardIt max_element(ExecutionPolicy&& policy, ForwardIt first, ForwardIt last ); | (2) | (C++17 起)
 | (3) |
template< class ForwardIt, class Compare > ForwardIt max_element(ForwardIt first, ForwardIt last, Compare comp ); |  |  | (C++17 前)
template< class ForwardIt, class Compare > constexpr ForwardIt max_element(ForwardIt first, ForwardIt last, Compare comp ); |  |  | (C++17 起)
template< class ExecutionPolicy, class ForwardIt, class Compare > ForwardIt max_element(ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, Compare comp ); | (4) | (C++17 起)

寻找范围 [first, last) 中的最大元素。

1) 用 operator< 比较元素。
3) 用给定的二元比较函数 comp 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 定义要检验范围的向前迭代器
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若首个参数小于第二个，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 ForwardIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

指向范围 [first, last) 中最大元素的迭代器。若范围中有多个元素等价于最大元素，则返回指向首个这种元素的迭代器。若范围为空则返回 last 。

复杂度

准确比较 max(N-1,0) 次，其中 N = std::distance (first, last) 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class ForwardIt>
ForwardIt max_element(ForwardIt first, ForwardIt last)
{
    if (first == last) {
        return last;
    }
    ForwardIt largest = first;
    ++first;
    for (; first != last; ++first) {
        if (*largest < *first) {
            largest = first;
        }
    }
    return largest;
}
版本二
template<class ForwardIt, class Compare>
ForwardIt max_element(ForwardIt first, ForwardIt last,
                      Compare comp)
{
    if (first == last) {
        return last;
    }
    ForwardIt largest = first;
    ++first;
    for (; first != last; ++first) {
        if (comp(*largest, *first)) {
            largest = first;
        }
    }
    return largest;
}

示例

#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>

static bool abs_compare(int a, int b)
{
    return (std::abs(a) < std::abs(b));
}

int main()
{
    std::vector<int> v{ 3, 1, -14, 1, 5, 9 };
    std::vector<int>::iterator result;

    result = std::max_element(v.begin(), v.end());
    std::cout << "max element at: " << std::distance(v.begin(), result) << '\n';

    result = std::max_element(v.begin(), v.end(), abs_compare);
    std::cout << "max element (absolute) at: " << std::distance(v.begin(), result) << '\n';
}

输出：

max element at: 5
max element (absolute) at: 2

参阅

min_element | 返回范围内的最小元素 (函数模板)
minmax_element (C++11) | 返回范围内的最小元素和最大元素 (函数模板)
max | 返回各给定值中的较大者 (函数模板)


std::merge

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class InputIt1, class InputIt2, class OutputIt > OutputIt merge( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first ); |  |  | (C++20 前)
template< class InputIt1, class InputIt2, class OutputIt > constexpr OutputIt merge( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class ForwardIt3 > ForwardIt3 merge( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, ForwardIt3 d_first ); | (2) | (C++17 起)
 | (3) |
template< class InputIt1, class InputIt2, class OutputIt, class Compare > OutputIt merge( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Compare comp ); |  |  | (C++20 前)
template< class InputIt1, class InputIt2, class OutputIt, class Compare > constexpr OutputIt merge( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Compare comp ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class ForwardIt3, class Compare> ForwardIt3 merge( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, ForwardIt3 d_first, Compare comp ); | (4) | (C++17 起)

归并二个已排序范围 [first1, last1) 和 [first2, last2) 到始于 d_first 的一个已排序范围中。

若对于任何指向序列的迭代器 it 与任何使得 it + n 为指向序列元素的合法迭代器的非负整数 n ， comp(*(it + n), *it) 求值为 false ，则称序列相对于 comp 已排序。

1) 用 operator< 比较元素。
3) 用给定的二元比较函数 comp 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

此归并是稳定的，意思是对于原范围中的等价元素，来自第一范围的元素（保持其原顺序）先于来自第二范围的元素（保持其原顺序）。

若目标范围与输入范围之一重叠，则行为未定义（输入范围可相互重叠）。

参数

first1, last1 | - | 要归并的元素的第一范围
first2, last2 | - | 要归并到元素的第二范围
d_first | - | 目标范围的起始
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 InputIt1 与 InputIt2 类型的对象在解引用后能隐式转换到 Type1 与 Type2 两者。 ​
类型要求
- InputIt1, InputIt2 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt1, ForwardIt2, ForwardIt3 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。

返回值

指向最后复制元素后一元素的迭代器。

复杂度

1,3) 至多 std::distance (first1, last1) + std::distance (first2, last2) - 1 次比较。
2,4) O( std::distance (first1, last1) + std::distance (first2, last2)) 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

此算法进行类似 std::set_union 所做的任务。都消耗二个已排序输入范围，并产生拥有来自两个输入的元素的输出。此二算法的区别在于处理来自二个输入的比较等价（见可小于比较 (LessThanComparable) 上的注解）的值。若任何等价的值在第一范围出现 n 次，在第二范围出现 m 次，则 std::merge 会输出所有 n+m 次出现，而 std::set_union 将只输出 std::max (n, m) 次。故 std::merge 准确输出 std::distance (first1, last1) + std::distance (first2, last2) 个值，而 std::set_union 可能产生得更少。

可能的实现

参阅 libstdc++ 与 libc++ 中的实现。

版本一
template<class InputIt1, class InputIt2, class OutputIt>
OutputIt merge(InputIt1 first1, InputIt1 last1,
               InputIt2 first2, InputIt2 last2,
               OutputIt d_first)
{
    for (; first1 != last1; ++d_first) {
        if (first2 == last2) {
            return std::copy(first1, last1, d_first);
        }
        if (*first2 < *first1) {
            *d_first = *first2;
            ++first2;
        } else {
            *d_first = *first1;
            ++first1;
        }
    }
    return std::copy(first2, last2, d_first);
}
版本二
template<class InputIt1, class InputIt2,
         class OutputIt, class Compare>
OutputIt merge(InputIt1 first1, InputIt1 last1,
               InputIt2 first2, InputIt2 last2,
               OutputIt d_first, Compare comp)
{
    for (; first1 != last1; ++d_first) {
        if (first2 == last2) {
            return std::copy(first1, last1, d_first);
        }
        if (comp(*first2, *first1)) {
            *d_first = *first2;
            ++first2;
        } else {
            *d_first = *first1;
            ++first1;
        }
    }
    return std::copy(first2, last2, d_first);
}

示例

#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
#include <random>
#include <functional>

int main()
{
    // 以随机数填充 vector
    std::random_device rd;
    std::mt19937 mt(rd());
    std::uniform_int_distribution<> dis(0, 9);

    std::vector<int> v1(10), v2(10);
    std::generate(v1.begin(), v1.end(), std::bind(dis, std::ref(mt)));
    std::generate(v2.begin(), v2.end(), std::bind(dis, std::ref(mt)));

    // 排序
    std::sort(v1.begin(), v1.end());
    std::sort(v2.begin(), v2.end());

    // 输出 v1
    std::cout << "v1 : ";
    std::copy(v1.begin(), v1.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';

    // 输出 v2
    std::cout << "v2 : ";
    std::copy(v2.begin(), v2.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';

    // 归并
    std::vector<int> dst;
    std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(dst));

    // 输出
    std::cout << "dst: ";
    std::copy(dst.begin(), dst.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
}

可能的输出：

v1 : 0 1 3 4 4 5 5 8 8 9
v2 : 0 2 2 3 6 6 8 8 8 9
dst: 0 0 1 2 2 3 3 4 4 5 5 6 6 8 8 8 8 8 9 9

参阅

inplace_merge | 就地归并两个有序范围 (函数模板)
is_sorted (C++11) | 检查范围是否已按升序排列 (函数模板)
set_union | 计算两个集合的并集 (函数模板)
sort | 将范围按升序排序 (函数模板)
stable_sort | 将范围内的元素排序，同时保持相等的元素之间的顺序 (函数模板)
ranges::merge (C++20) | 归并二个已排序范围 (niebloid)


std::min

< cpp‎ | algorithm
定义于头文件 <algorithm> |
 | (1)
template< class T > const T& min( const T& a, const T& b ); |  | (C++14 前)
template< class T > constexpr const T& min( const T& a, const T& b ); |  | (C++14 起)
 | (2)
template< class T, class Compare > const T& min( const T& a, const T& b, Compare comp ); |  | (C++14 前)
template< class T, class Compare > constexpr const T& min( const T& a, const T& b, Compare comp ); |  | (C++14 起)
 | (3)
template< class T > T min( std::initializer_list <T> ilist ); |  | (C++11 起) (C++14 前)
template< class T > constexpr T min( std::initializer_list <T> ilist ); |  | (C++14 起)
 | (4)
template< class T, class Compare > T min( std::initializer_list <T> ilist, Compare comp ); |  | (C++11 起) (C++14 前)
template< class T, class Compare > constexpr T min( std::initializer_list <T> ilist, Compare comp ); |  | (C++14 起)

返回给定值中的较小者。

1-2) 返回 a 与 b 的较小者。
3-4) 返回 initializer_list ilist 中值的最小者。

(1,3) 版本用 operator< 比较元素， (2,4) 版本用给定的比较函数 comp 。

参数

a, b | - | 要比较的值
ilist | - | 拥有要比较的值的 initializer_list
cmp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若 a 小于 b ，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 T 类型的对象能隐式转换到这两个类型。 ​
类型要求
- 为使用重载 (1,3) ， T 必须满足可小于比较 (LessThanComparable) 的要求。
- 为使用重载 (3,4) ， T 必须满足可复制构造 (CopyConstructible) 的要求。

返回值

1-2) a 与 b 的较小者。若值等价，则返回 a 。
3-4) ilist 中的最小值。若有数个等价于最小者的值，则返回最左侧的这种值。

复杂度

1-2) 准确一次比较
3-4) 准确 ilist.size() - 1 次比较

可能的实现

版本一
template<class T>
const T& min(const T& a, const T& b)
{
    return (b < a) ? b : a;
}
版本二
template<class T, class Compare>
const T& min(const T& a, const T& b, Compare comp)
{
    return (comp(b, a)) ? b : a;
}
版本三
template<class T>
T min( std::initializer_list<T> ilist)
{
    return *std::min_element(ilist.begin(), ilist.end());
}
版本四
template<class T, class Compare>
T min(std::initializer_list<T> ilist, Compare comp)
{
    return *std::min_element(ilist.begin(), ilist.end(), comp);
}

警告

若参数之一是临时量，而该参数被返回，则以引用捕获 std::min 的结果会产生一个悬垂引用：

int n = 1;
const int& r = std::min(n-1, n+1);
// r 悬垂

示例

#include <algorithm>
#include <iostream>
#include <string_view>

int main()
{
    std::cout << "smaller of 1 and 9999 is " << std::min(1, 9999) << '\n'
              << "smaller of 'a', and 'b' is '" << std::min('a', 'b') << "'\n"
              << "shortest of \"foo\", \"bar\", and \"hello\" is \""
              << std::min({ "foo", "bar", "hello" },
                          [](const std::string_view s1, const std::string_view s2) {
                              return s1.size() < s2.size();
                          }) << "\"\n";
}

输出：

smaller of 1 and 9999 is 1
smaller of 'a', and 'b' is 'a'
shortest of "foo", "bar", and "hello" is "foo"

参阅

max | 返回各给定值中的较大者 (函数模板)
minmax (C++11) | 返回两个元素的较小和较大者 (函数模板)
min_element | 返回范围内的最小元素 (函数模板)
clamp (C++17) | 在一对边界值间夹逼一个值 (函数模板)


std::min_element

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class ForwardIt >
ForwardIt min_element( ForwardIt first, ForwardIt last );
 (C++17 前)
template< class ForwardIt >
constexpr ForwardIt min_element( ForwardIt first, ForwardIt last );
 (C++17 起)
template< class ExecutionPolicy, class ForwardIt >

ForwardIt min_element( ExecutionPolicy&& policy,

ForwardIt first, ForwardIt last );
 (2) (C++17 起)
(3)
template< class ForwardIt, class Compare >
ForwardIt min_element( ForwardIt first, ForwardIt last, Compare comp );
 (C++17 前)
template< class ForwardIt, class Compare >
constexpr ForwardIt min_element( ForwardIt first, ForwardIt last, Compare comp );
 (C++17 起)
template< class ExecutionPolicy, class ForwardIt, class Compare >

ForwardIt min_element( ExecutionPolicy&& policy,

ForwardIt first, ForwardIt last, Compare comp );
 (4) (C++17 起)

寻找范围 [first, last) 中的最小元素。

1) 用 operator< 比较元素。
3) 用给定的二元比较函数 comp 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 定义要检验范围的向前迭代器
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若a 小于 b ，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 ForwardIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

指向范围 [first, last) 中最小元素的迭代器。若范围中有多个元素等价于最小元素，则返回指向首个这种元素的迭代器。若范围为空则返回 last 。

复杂度

准确比较 max(N-1,0) 次，其中 N = std::distance (first, last) 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class ForwardIt>
ForwardIt min_element(ForwardIt first, ForwardIt last)
{
    if (first == last) return last;

    ForwardIt smallest = first;
    ++first;
    for (; first != last; ++first) {
        if (*first < *smallest) {
            smallest = first;
        }
    }
    return smallest;
}
版本二
template<class ForwardIt, class Compare>
ForwardIt min_element(ForwardIt first, ForwardIt last, Compare comp)
{
    if (first == last) return last;

    ForwardIt smallest = first;
    ++first;
    for (; first != last; ++first) {
        if (comp(*first, *smallest)) {
            smallest = first;
        }
    }
    return smallest;
}

示例

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{3, 1, 4, 1, 5, 9};

    std::vector<int>::iterator result = std::min_element(std::begin(v), std::end(v));
    std::cout << "min element at: " << std::distance(std::begin(v), result);
}

输出：

min element at: 1

参阅

max_element | 返回范围内的最大元素 (函数模板)
minmax_element (C++11) | 返回范围内的最小元素和最大元素 (函数模板)
min | 返回各给定值中的较小者 (函数模板)


std::minmax

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class T >
std::pair <const T&,const T&> minmax( const T& a, const T& b );
 (C++11 起)
(C++14 前)
template< class T >
constexpr std::pair <const T&,const T&> minmax( const T& a, const T& b );
 (C++14 起)
(2)
template< class T, class Compare >

std::pair <const T&,const T&> minmax( const T& a, const T& b,

Compare comp );
 (C++11 起)
(C++14 前)
template< class T, class Compare >

constexpr std::pair <const T&,const T&> minmax( const T& a, const T& b,

Compare comp );
 (C++14 起)
(3)
template< class T >
std::pair <T,T> minmax( std::initializer_list <T> ilist);
 (C++11 起)
(C++14 前)
template< class T >
constexpr std::pair <T,T> minmax( std::initializer_list <T> ilist);
 (C++14 起)
(4)
template< class T, class Compare >
std::pair <T,T> minmax( std::initializer_list <T> ilist, Compare comp );
 (C++11 起)
(C++14 前)
template< class T, class Compare >
constexpr std::pair <T,T> minmax( std::initializer_list <T> ilist, Compare comp );
 (C++14 起)

返回给定值的最小和最大者。

1-2) 返回到 a 的 b 较小和较大者的引用。
3-4) 返回 initializer_list ilist 中值的最小和最大者。

(1,3) 版本用 operator< 比较值，而 (2,4) 版本用给定的比较函数 comp 。

参数

a, b | - | 要比较的值
ilist | - | 含要比较的值的 initializer_list
comp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若首个参数小于第二个，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 T 类型的对象能隐式转换到这两个类型。 ​
类型要求
- 为使用重载 (1,3) ， T 必须满足可小于比较 (LessThanComparable) 的要求。
- 为使用重载 (3,4) ， T 必须满足可复制构造 (CopyConstructible) 的要求。

返回值

1-2) 若 a<b 或若 a 等价于 b 则返回 std::pair <const T&, const T&>(a, b) 的结果。若 b<a 则返回 std::pair <const T&, const T&>(b, a) 的结果。
3-4) 以 ilist 中最小元素为第一元素，最大元素为第二元素的 pair 。若有数个元素等价于最小者，则返回最左的这种元素。若有数个元素等价于最大者，则返回最右的这种元素。

复杂度

1-2) 准确一次比较
3-4) 至多 ilist.size() * 3 / 2 次比较

可能的实现

版本一
template<class T>
constexpr std::pair<const T&, const T&> minmax( const T& a, const T& b )
{
    return (b < a) ? std::pair<const T&, const T&>(b, a)
                   : std::pair<const T&, const T&>(a, b);
}
版本二
template<class T, class Compare>
constexpr std::pair<const T&, const T&> minmax( const T& a, const T& b, Compare comp )
{
    return comp(b, a) ? std::pair<const T&, const T&>(b, a)
                      : std::pair<const T&, const T&>(a, b);
}
版本三
template< class T >
constexpr std::pair<T, T> minmax( std::initializer_list<T> ilist )
{
    auto p = std::minmax_element(ilist.begin(), ilist.end());
    return std::pair(*p.first, *p.second);
}
版本四
template< class T, class Compare >
constexpr std::pair<T, T> minmax( std::initializer_list<T> ilist, Compare comp )
{
    auto p = std::minmax_element(ilist.begin(), ilist.end(), comp);
    return std::pair(*p.first, *p.second);
}

注解

对于重载 (1,2) ，若参数之一为临时量，则返回的引用在包含对 minmax 调用的完整表达式结尾变为悬垂引用：

int n = 1;
auto p = std::minmax(n, n+1);
int m = p.first; // ok
int x = p.second; // 未定义行为

// 注意结构化绑定有同样的问题
auto [mm, xx] = std::minmax(n, n+1);
xx; // 未定义行为

示例

#include <algorithm>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>

int main()
{
    std::vector<int> v {3, 1, 4, 1, 5, 9, 2, 6};
    std::srand(std::time(0));
    std::pair<int, int> bounds = std::minmax(std::rand() % v.size(),
                                             std::rand() % v.size());

    std::cout << "v[" << bounds.first << "," << bounds.second << "]: ";
    for (int i = bounds.first; i < bounds.second; ++i) {
        std::cout << v[i] << ' ';
    }
    std::cout << '\n';
}

可能的输出：

v[2,7]: 4 1 5 9 2

参阅

min | 返回各给定值中的较小者 (函数模板)
max | 返回各给定值中的较大者 (函数模板)
minmax_element (C++11) | 返回范围内的最小元素和最大元素 (函数模板)
ranges::minmax (C++20) | 返回两个元素的较小和较大者 (niebloid)


std::minmax_element

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class ForwardIt >

std::pair <ForwardIt,ForwardIt>

minmax_element( ForwardIt first, ForwardIt last );
 (C++11 起)
(C++17 前)
template< class ForwardIt >

constexpr std::pair <ForwardIt,ForwardIt>

minmax_element( ForwardIt first, ForwardIt last );
 (C++17 起)
template< class ExecutionPolicy, class ForwardIt >

std::pair <ForwardIt,ForwardIt>

minmax_element( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last );
 (2) (C++17 起)
(3)
template< class ForwardIt, class Compare >

std::pair <ForwardIt,ForwardIt>

minmax_element( ForwardIt first, ForwardIt last, Compare comp );
 (C++11 起)
(C++17 前)
template< class ForwardIt, class Compare >

constexpr std::pair <ForwardIt,ForwardIt>

minmax_element( ForwardIt first, ForwardIt last, Compare comp );
 (C++17 起)
template< class ExecutionPolicy, class ForwardIt, class Compare >

std::pair <ForwardIt,ForwardIt>

minmax_element( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, Compare comp );
 (4) (C++17 起)

寻找范围 [first, last) 中最小和最大的元素。

1) 用 operator< 比较元素。
3) 用给定的二元比较函数 comp 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。。

参数

first, last | - | 定义要检验的元素范围的迭代器
policy | - | 所用的执行策略。细节见执行策略。
cmp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若若 *a 小于 *b ，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 ForwardIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

以指向最小元素的迭代器为第一元素，以指向最大元素的迭代器为第二元素的 pair 。若范围为空则返回 std::make_pair (first, first) 。若多个元素等价于最小元素，则返回指向首个这种元素的迭代器。若多个元素等价于最大元素，则返回指向最后一个这种元素的迭代器。

复杂度

至多应用谓词 max(floor(3/2(N−1)), 0) 次，其中 N = std::distance (first, last) 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

此算法不仅在效率上异于 std::make_pair ( std::min_element (), std::max_element ()) ，而且此算法寻找最后的最大元素，而 std::max_element 寻找首个最大元素。

可能的实现

版本一
template<class ForwardIt>
std::pair<ForwardIt, ForwardIt>
    minmax_element(ForwardIt first, ForwardIt last)
{
    using value_type = typename std::iterator_traits<ForwardIt>::value_type;
    return std::minmax_element(first, last, std::less<value_type>());
}
版本二
template<class ForwardIt, class Compare>
std::pair<ForwardIt, ForwardIt>
    minmax_element(ForwardIt first, ForwardIt last, Compare comp)
{
    auto min = first, max = first;

    if (first == last || ++first == last)
        return {min, max};

    if (comp(*first, *min)) {
        min = first;
    } else {
        max = first;
    }

    while (++first != last) {
        auto i = first;
        if (++first == last) {
            if (comp(*i, *min)) min = i;
            else if (!(comp(*i, *max))) max = i;
            break;
        } else {
            if (comp(*first, *i)) {
                if (comp(*first, *min)) min = first;
                if (!(comp(*i, *max))) max = i;
            } else {
                if (comp(*i, *min)) min = i;
                if (!(comp(*first, *max))) max = first;
            }
        }
    }
    return {min, max};
}

示例

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v = { 3, 9, 1, 4, 2, 5, 9 };

    auto result = std::minmax_element(v.begin(), v.end());
    std::cout << "min element at: " << (result.first - v.begin()) << '\n';
    std::cout << "max element at: " << (result.second - v.begin()) << '\n';
}

输出：

min element at: 2
max element at: 6

参阅

min_element | 返回范围内的最小元素 (函数模板)
max_element | 返回范围内的最大元素 (函数模板)


std::mismatch

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class InputIt1, class InputIt2 >

std::pair <InputIt1,InputIt2>
mismatch( InputIt1 first1, InputIt1 last1,

InputIt2 first2 );
 (C++20 前)
template< class InputIt1, class InputIt2 >

constexpr std::pair <InputIt1,InputIt2>
mismatch( InputIt1 first1, InputIt1 last1,

InputIt2 first2 );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >

std::pair <ForwardIt1,ForwardIt2>
mismatch( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1,

ForwardIt2 first2 );
 (2) (C++17 起)
(3)
template< class InputIt1, class InputIt2, class BinaryPredicate >

std::pair <InputIt1,InputIt2>
mismatch( InputIt1 first1, InputIt1 last1,
InputIt2 first2,

BinaryPredicate p );
 (C++20 前)
template< class InputIt1, class InputIt2, class BinaryPredicate >

constexpr std::pair <InputIt1,InputIt2>
mismatch( InputIt1 first1, InputIt1 last1,
InputIt2 first2,

BinaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2,

class BinaryPredicate >
std::pair <ForwardIt1,ForwardIt2>
mismatch( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1,
ForwardIt2 first2,

BinaryPredicate p );
 (4) (C++17 起)
(5)
template< class InputIt1, class InputIt2 >

std::pair <InputIt1,InputIt2>
mismatch( InputIt1 first1, InputIt1 last1,

InputIt2 first2, InputIt2 last2 );
 (C++14 起)
(C++20 前)
template< class InputIt1, class InputIt2 >

constexpr std::pair <InputIt1,InputIt2>
mismatch( InputIt1 first1, InputIt1 last1,

InputIt2 first2, InputIt2 last2 );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >

std::pair <ForwardIt1,ForwardIt2>
mismatch( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1,

ForwardIt2 first2, ForwardIt2 last2 );
 (6) (C++17 起)
(7)
template< class InputIt1, class InputIt2, class BinaryPredicate >

std::pair <InputIt1,InputIt2>
mismatch( InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2,

BinaryPredicate p );
 (C++14 起)
(C++20 前)
template< class InputIt1, class InputIt2, class BinaryPredicate >

constexpr std::pair <InputIt1,InputIt2>
mismatch( InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2,

BinaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2,

class BinaryPredicate >
std::pair <ForwardIt1,ForwardIt2>
mismatch( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1,
ForwardIt2 first2, ForwardIt2 last2,

BinaryPredicate p );
 (8) (C++17 起)

返回来自二个范围：一个以 [first1, last1) 定义而另一个以 [first2,last2) 定义，的首个不匹配对。若不提供 last2 （重载 (1-4) ），则它指代 first2 + (last1 - first1) 。

1,5) 用 operator== 比较元素。
3,7) 用给定的二元谓词 p 比较元素。
2,4,6,8) 同 (1,3,5,7) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first1, last1 | - | 第一元素范围
first2, last2 | - | 第二元素范围
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若元素应被当做相等则返回 ​true 的二元谓词。 谓词函数的签名应等价于如下： bool pred(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 InputIt1 与 InputIt2 类型的对象在解引用后分别能隐式转换到 Type1 与 Type2 。 ​
类型要求
- InputIt1 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- InputIt2 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt1 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- BinaryPredicate 必须满足二元谓词 (BinaryPredicate) 的要求。

返回值

拥有指向首二个不相等元素的迭代器的 std::pair 。

若比较抵达 last1 时未找到不匹配，则 pair 保有 last1 和来自第二范围的对应迭代器。若第二范围短于第一范围则行为未定义。 | (C++14 前)
若比较抵达 last1 或 last2 中首先发生者时未找到不匹配，则 pair 保有尾迭代器和来自另一范围的对应迭代器。 | (C++14 起)

复杂度

1-4) 至多 last1 - first1 次应用 operator== 或谓词 p 。
5-8) 至多 min(last1 - first1, last2 - first2) 次应用 operator== 或谓词 p 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class InputIt1, class InputIt2>
std::pair<InputIt1, InputIt2>
    mismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2)
{
    while (first1 != last1 && *first1 == *first2) {
        ++first1, ++first2;
    }
    return std::make_pair(first1, first2);
}
版本二
template<class InputIt1, class InputIt2, class BinaryPredicate>
std::pair<InputIt1, InputIt2>
    mismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2, BinaryPredicate p)
{
    while (first1 != last1 && p(*first1, *first2)) {
        ++first1, ++first2;
    }
    return std::make_pair(first1, first2);
}
版本三
template<class InputIt1, class InputIt2>
std::pair<InputIt1, InputIt2>
    mismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2)
{
    while (first1 != last1 && first2 != last2 && *first1 == *first2) {
        ++first1, ++first2;
    }
    return std::make_pair(first1, first2);
}
版本四
template<class InputIt1, class InputIt2, class BinaryPredicate>
std::pair<InputIt1, InputIt2>
    mismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPredicate p)
{
    while (first1 != last1 && first2 != last2 && p(*first1, *first2)) {
        ++first1, ++first2;
    }
    return std::make_pair(first1, first2);
}

示例

此程序确定同时在给定字符串起始与在其结尾按逆序同时找到的最长子串（可能重叠）。

#include <iostream>
#include <string>
#include <algorithm>

std::string mirror_ends(const std::string& in)
{
    return std::string(in.begin(),
                       std::mismatch(in.begin(), in.end(), in.rbegin()).first);
}

int main()
{
    std::cout << mirror_ends("abXYZba") << '\n'
              << mirror_ends("abca") << '\n'
              << mirror_ends("aba") << '\n';
}

输出：

ab
a
aba

参阅

equal | 确定两个元素集合是否是相同的 (函数模板)
findfind_iffind_if_not (C++11) | 寻找首个满足特定判别标准的元素 (函数模板)
lexicographical_compare | 当一个范围按字典顺序小于另一个范围时，返回 true (函数模板)
search | 搜索一个元素范围 (函数模板)


std::move

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class InputIt, class OutputIt > OutputIt move( InputIt first, InputIt last, OutputIt d_first ); |  |  | (C++11 起) (C++20 前)
template< class InputIt, class OutputIt > constexpr OutputIt move( InputIt first, InputIt last, OutputIt d_first ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 > ForwardIt2 move( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last, ForwardIt2 d_first ); | (2) | (C++17 起)
1) 移动范围 [first, last) 中的元素到始于 d_first 的另一范围，从首元素开始逐次到末元素。此操作后被移动范围中的元素将仍然含有适合类型的合法值，但不必与移动前的值相同。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。。

参数

first, last | - | 要移动的元素范围
d_first | - | 目标范围起始。若 d_first 在范围 [first, last) 中则行为未定义。此情况下可用 std::move_backward 代替 std::move 。
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

指向最后移动元素后一位置的迭代器（ d_first + (last - first) ）。

复杂度

准确移动赋值 last - first 次。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class InputIt, class OutputIt>
OutputIt move(InputIt first, InputIt last, OutputIt d_first)
{
    while (first != last) {
        *d_first++ = std::move(*first++);
    }
    return d_first;
}

注解

移动重叠的范围时， std::move 在移动到左侧（目标范围的起始在源范围外）时适合，而 std::move_backward 在移动到右侧（目标范围的结尾在源范围外）时适合。

示例

下列代码从一个容器移动 thread 对象（自身不可复制）到另一个。

#include <iostream>
#include <vector>
#include <list>
#include <iterator>
#include <thread>
#include <chrono>

void f(int n)
{
    std::this_thread::sleep_for(std::chrono::seconds(n));
    std::cout << "thread " << n << " ended" << '\n';
}

int main()
{
    std::vector<std::thread> v;
    v.emplace_back(f, 1);
    v.emplace_back(f, 2);
    v.emplace_back(f, 3);
    std::list<std::thread> l;
    // copy() 无法编译，因为 std::thread 不可复制

    std::move(v.begin(), v.end(), std::back_inserter(l));
    for (auto& t : l) t.join();
}

输出：

thread 1 ended
thread 2 ended
thread 3 ended

参阅

move_backward (C++11) | 按从后往前的顺序移动某一范围的元素到新的位置 (函数模板)
move (C++11) | 获得右值引用 (函数模板)
ranges::move (C++20) | 将某一范围的元素移动到一个新的位置 (niebloid)


std::move_backward

< cpp‎ | algorithm
定义于头文件 <algorithm> |
template< class BidirIt1, class BidirIt2 > BidirIt2 move_backward( BidirIt1 first, BidirIt1 last, BidirIt2 d_last ); | (C++11 起) (C++20 前)
template< class BidirIt1, class BidirIt2 > constexpr BidirIt2 move_backward( BidirIt1 first, BidirIt1 last, BidirIt2 d_last ); | (C++20 起)

移动来自范围 [first, last) 的元素到终于 d_last 的另一范围。以逆序移动元素（首先复制末元素），但保持其相对顺序。

若 d_last 在 (first, last] 内则行为未定义。该情况下必须用 std::move 代替 std::move_backward 。

参数

first, last | - | 要移动的元素范围
d_last | - | 目标范围结尾
类型要求
- BidirIt1, BidirIt2 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求。

返回值

目标范围中的迭代器，指向最后移动的元素。

复杂度

准确移动赋值 last - first 次。

可能的实现

template< class BidirIt1, class BidirIt2 >
BidirIt2 move_backward(BidirIt1 first,
                                     BidirIt1 last,
                                     BidirIt2 d_last)
{
    while (first != last) {
        *(--d_last) = std::move(*(--last));
    }
    return d_last;
}

注解

移动重叠的范围时， std::move 适合向左移动（目标范围的起始在源范围外）时，而 std::move_backward 适合向右移动（目标范围的结尾在源范围外）时。

示例

#include <algorithm>
#include <vector>
#include <string>
#include <iostream>

int main()
{
    std::vector<std::string> src{"foo", "bar", "baz"};
    std::vector<std::string> dest(src.size());

    std::cout << "src: ";
    for (const auto &s : src)
    {
        std::cout << s << ' ';
    }
    std::cout << "\ndest: ";
    for (const auto &s : dest)
    {
        std::cout << s << ' ';
    }
    std::cout << '\n';

    std::move_backward(src.begin(), src.end(), dest.end());

    std::cout << "src: ";
    for (const auto &s : src)
    {
        std::cout << s << ' ';
    }
    std::cout << "\ndest: ";
    for (const auto &s : dest)
    {
        std::cout << s << ' ';
    }
    std::cout << '\n';
}

输出：

src: foo bar baz
dest:
src:
dest: foo bar baz

参阅

move (C++11) | 将某一范围的元素移动到一个新的位置 (函数模板)
ranges::move_backword (C++20) | 按从后往前的顺序移动某一范围的元素到新的位置 (niebloid)


std::next_permutation

< cpp‎ | algorithm
定义于头文件 <algorithm> |
 | (1)
template< class BidirIt > bool next_permutation( BidirIt first, BidirIt last ); |  | (C++20 前)
template< class BidirIt > constexpr bool next_permutation( BidirIt first, BidirIt last ); |  | (C++20 起)
 | (2)
template< class BidirIt, class Compare > bool next_permutation( BidirIt first, BidirIt last, Compare comp ); |  | (C++20 前)
template< class BidirIt, class Compare > constexpr bool next_permutation( BidirIt first, BidirIt last, Compare comp ); |  | (C++20 起)

变换范围 [first, last) 为来自所有按相对于 operator< 或 comp 的字典序的下个排列。若这种排列存在则返回 true ，否则变换范围为首个排列（如同用 std::sort(first, last) ）并返回 false 。

参数

first, last | - | 要重排的元素范围
comp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若首个参数小于第二个，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 BidirIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- BidirIt 必须满足值可交换 (ValueSwappable) 和 老式双向迭代器 (LegacyBidirectionalIterator) 的要求。

返回值

若新排列按字典序大于旧者则为 true 。若抵达最后重排并重置范围为首个排列则为 false 。

异常

任何从迭代器操作或元素交换抛出的异常。

复杂度

至多 N/2 次交换，其中 N = std::distance (first, last) 。

典型实现在排列的整个序列上，平均每次调用使用约 3 次比较和 1.5 次交换。

注解

实现（例如 MSVC STL ）可能在迭代器类型满足老式连续迭代器 (LegacyContiguousIterator) ，并且交换其值类型不调用非平凡的特殊成员函数或 ADL 所找到的 swap 时启用向量化。

可能的实现

template<class BidirIt>
bool next_permutation(BidirIt first, BidirIt last)
{
    if (first == last) return false;
    BidirIt i = last;
    if (first == --i) return false;

    while (true) {
        BidirIt i1, i2;

        i1 = i;
        if (*--i < *i1) {
            i2 = last;
            while (!(*i < *--i2))
                ;
            std::iter_swap(i, i2);
            std::reverse(i1, last);
            return true;
        }
        if (i == first) {
            std::reverse(first, last);
            return false;
        }
    }
}

示例

下列代码打印字符串 "aba" 的全部三种排列

#include <algorithm>
#include <string>
#include <iostream>

int main()
{
    std::string s = "aba";
    std::sort(s.begin(), s.end());
    do {
        std::cout << s << '\n';
    } while(std::next_permutation(s.begin(), s.end()));
}

输出：

aab
aba
baa

参阅

is_permutation (C++11) | 判断一个序列是否为另一个序列的排列 (函数模板)
prev_permutation | 产生某个元素范围的按字典顺序的下一个较小的排列 (函数模板)
ranges::next_permutation (C++20) | 产生某个元素范围的按字典序下一个较大的排列 (niebloid)


std::nth_element

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class RandomIt >
void nth_element( RandomIt first, RandomIt nth, RandomIt last );
 (C++20 前)
template< class RandomIt >
constexpr void nth_element( RandomIt first, RandomIt nth, RandomIt last );
 (C++20 起)
template< class ExecutionPolicy, class RandomIt >

void nth_element( ExecutionPolicy&& policy,

RandomIt first, RandomIt nth, RandomIt last );
 (2) (C++17 起)
(3)
template< class RandomIt, class Compare >

void nth_element( RandomIt first, RandomIt nth, RandomIt last,

Compare comp );
 (C++20 前)
template< class RandomIt, class Compare >

constexpr void nth_element( RandomIt first, RandomIt nth, RandomIt last,

Compare comp );
 (C++20 起)
template< class ExecutionPolicy, class RandomIt, class Compare >

void nth_element( ExecutionPolicy&& policy,
RandomIt first, RandomIt nth, RandomIt last,

Compare comp );
 (4) (C++17 起)

nth_element 是部分排序算法，它重排 [first, last) 中元素，使得：

  • nth 所指向的元素被更改为假如 [first, last) 已排序则该位置会出现的元素。
  • 这个新的 nth 元素前的所有元素小于或等于新的 nth 元素后的所有元素。

更正式而言， nth_element 以升序部分排序范围 [first, last) ，使得对于任何范围 [first, nth) 中的 i 和任何范围 [nth, last) 中的 j ，都满足条件 !(*j < *i) （对于 (1-2) ，对 (3-4) 则为 comp(*j, *i) == false ）。置于 nth 位置的元素则准确地是假如完全排序范围则应出现于此位置的元素。

nth 可以是尾迭代器，此情况下函数无效果。

1) 用 operator< 比较元素。
3) 用给定的二元比较函数 comp 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 定义待排序范围的随机访问迭代器
nth | - | 定义排序划分点的随机访问迭代器
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 RandomIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- RandomIt 必须满足值可交换 (ValueSwappable) 和 老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。
- 解引用 RandomIt 结果的类型必须满足可移动赋值 (MoveAssignable) 和可移动构造 (MoveConstructible) 的要求。

返回值

（无）

复杂度

1,3) 平均与 std::distance (first, last) 成线性。
2,4) O(N) 次应用谓词和 O(N log N) 次交换，其中 N = last - first 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

典型地使用内省选择算法，尽管允许其他拥有适合平均情况复杂度的选择算法。

可能的实现

参阅 libstdc++ 与 libc++ 中的实现。

示例

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

int main()
{
    std::vector<int> v{5, 6, 4, 3, 2, 6, 7, 9, 3};

    std::nth_element(v.begin(), v.begin() + v.size()/2, v.end());
    std::cout << "The median is " << v[v.size()/2] << '\n';

    std::nth_element(v.begin(), v.begin()+1, v.end(), std::greater<int>());
    std::cout << "The second largest element is " << v[1] << '\n';
}

输出：

The median is 5
The second largest element is 7

参阅

partial_sort_copy | 对范围内的元素进行复制并部分排序 (函数模板)
stable_sort | 将范围内的元素排序，同时保持相等的元素之间的顺序 (函数模板)
sort | 将范围按升序排序 (函数模板)


std::partial_sort

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class RandomIt >
void partial_sort( RandomIt first, RandomIt middle, RandomIt last );
 (C++20 前)
template< class RandomIt >
constexpr void partial_sort( RandomIt first, RandomIt middle, RandomIt last );
 (C++20 起)
template< class ExecutionPolicy, class RandomIt >

void partial_sort( ExecutionPolicy&& policy,

RandomIt first, RandomIt middle, RandomIt last );
 (2) (C++17 起)
(3)
template< class RandomIt, class Compare >

void partial_sort( RandomIt first, RandomIt middle, RandomIt last,

Compare comp );
 (C++20 前)
template< class RandomIt, class Compare >

constexpr void partial_sort( RandomIt first, RandomIt middle, RandomIt last,

Compare comp );
 (C++20 起)
template< class ExecutionPolicy, class RandomIt, class Compare >

void partial_sort( ExecutionPolicy&& policy,
RandomIt first, RandomIt middle, RandomIt last,

Compare comp );
 (4) (C++17 起)

重排元素，使得范围 [first, middle) 含有范围 [first, last) 中已排序的 middle - first 个最小元素。

不保证保持相等的元素顺序。范围 [middle, last) 中剩余的元素顺序未指定。

1) 用 operator< 比较元素。
3) 用给定的二元比较函数 comp 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 定义范围的随机访问迭代器
middle | - | 定义要排序的末元素的随机访问迭代器
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 RandomIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- RandomIt 必须满足值可交换 (ValueSwappable) 和 老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。
- 解引用 RandomIt 结果的类型必须满足可移动赋值 (MoveAssignable) 和可移动构造 (MoveConstructible) 的要求。

返回值

（无）

复杂度

约 (last-first)log(middle-first) 次应用 cmp 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

示例

#include <algorithm>
#include <functional>
#include <array>
#include <iostream>

int main()
{
    std::array<int, 10> s{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};

    std::partial_sort(s.begin(), s.begin() + 3, s.end());
    for (int a : s) {
        std::cout << a << " ";
    }
}

可能的输出：

0 1 2 7 8 6 5 9 4 3

参阅

nth_element | 将给定的范围部分排序，确保其按给定元素划分 (函数模板)
partial_sort_copy | 对范围内的元素进行复制并部分排序 (函数模板)
stable_sort | 将范围内的元素排序，同时保持相等的元素之间的顺序 (函数模板)
sort | 将范围按升序排序 (函数模板)


std::partial_sort_copy

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class InputIt, class RandomIt >

RandomIt partial_sort_copy( InputIt first, InputIt last,

RandomIt d_first, RandomIt d_last );
 (C++20 前)
template< class InputIt, class RandomIt >

constexpr RandomIt partial_sort_copy( InputIt first, InputIt last,

RandomIt d_first, RandomIt d_last );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class RandomIt >

RandomIt partial_sort_copy( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,

RandomIt d_first, RandomIt d_last );
 (2) (C++17 起)
(3)
template< class InputIt, class RandomIt, class Compare >

RandomIt partial_sort_copy( InputIt first, InputIt last,
RandomIt d_first, RandomIt d_last,

Compare comp );
 (C++20 前)
template< class InputIt, class RandomIt, class Compare >

constexpr RandomIt partial_sort_copy( InputIt first, InputIt last,
RandomIt d_first, RandomIt d_last,

Compare comp );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class RandomIt, class Compare >

RandomIt partial_sort_copy( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
RandomIt d_first, RandomIt d_last,

Compare comp );
 (4) (C++17 起)

以升序排序范围 [first, last) 中的某些元素，存储结果于范围 [d_first, d_last) 。

至多将 d_last - d_first 个元素放置并排序到范围 [d_first, d_first + n) 中。其中 n 是要排序的元素数（ n = min(last - first, d_last - d_first) ）。不保证保持相等元素的顺序。

1) 用 operator< 比较元素。
3) 用给定的二元比较函数 comp 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。。

参数

first, last | - | 要排序的元素范围
d_first, d_last | - | 定义目标范围的随机访问迭代器
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 RandomIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- RandomIt 必须满足值可交换 (ValueSwappable) 和 老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。
- 解引用 RandomIt 结果的类型必须满足可移动赋值 (MoveAssignable) 和可移动构造 (MoveConstructible) 的要求。

返回值

指向定义已排序范围上界的元素的迭代器，即 d_first + min(last - first, d_last - d_first) 。

复杂度

O(N·log(min(D,N)) 次应用 cmp ，其中 N = std::distance (first, last) ， D = std::distance (d_first, d_last) 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

参阅 libstdc++ 与 libc++ 中的实现。

示例

下列代码排序 int 的 vector 并将它们复制到较小和较大的 vector 中。

#include <algorithm>
#include <vector>
#include <functional>
#include <iostream>

int main()
{
    std::vector<int> v0{4, 2, 5, 1, 3};
    std::vector<int> v1{10, 11, 12};
    std::vector<int> v2{10, 11, 12, 13, 14, 15, 16};
    std::vector<int>::iterator it;

    it = std::partial_sort_copy(v0.begin(), v0.end(), v1.begin(), v1.end());

    std::cout << "Writing to the smaller vector in ascending order gives: ";
    for (int a : v1) {
        std::cout << a << " ";
    }
    std::cout << '\n';
    if(it == v1.end())
        std::cout << "The return value is the end iterator\n";

    it = std::partial_sort_copy(v0.begin(), v0.end(), v2.begin(), v2.end(),
                                std::greater<int>());

    std::cout << "Writing to the larger vector in descending order gives: ";
    for (int a : v2) {
        std::cout << a << " ";
    }
    std::cout << '\n' << "The return value is the iterator to " << *it << '\n';
}

输出：

Writing to the smaller vector in ascending order gives: 1 2 3
The return value is the end iterator
Writing to the larger vector in descending order gives: 5 4 3 2 1 15 16
The return value is the iterator to 15

参阅

partial_sort | 排序一个范围的前 N 个元素 (函数模板)
sort | 将范围按升序排序 (函数模板)
stable_sort | 将范围内的元素排序，同时保持相等的元素之间的顺序 (函数模板)


std::partial_sum

< cpp‎ | algorithm
定义于头文件 <numeric> |
 | (1)
template< class InputIt, class OutputIt > OutputIt partial_sum( InputIt first, InputIt last, OutputIt d_first ); |  | (C++20 前)
template< class InputIt, class OutputIt > constexpr OutputIt partial_sum( InputIt first, InputIt last, OutputIt d_first ); |  | (C++20 起)
 | (2)
template< class InputIt, class OutputIt, class BinaryOperation > OutputIt partial_sum( InputIt first, InputIt last, OutputIt d_first, BinaryOperation op ); |  | (C++20 前)
template< class InputIt, class OutputIt, class BinaryOperation > constexpr OutputIt partial_sum( InputIt first, InputIt last, OutputIt d_first, BinaryOperation op ); |  | (C++20 起)

计算范围 [first, last) 的子范围中元素的部分和，并写入到始于 d_first 的范围。第一版本用 operator+ ，第二版本用给定的二元函数 op 对元素求和，均将 std::move 应用到其左侧运算数 (C++20 起)。

等价运算：

*(d_first)   = *first;
*(d_first+1) = *first + *(first+1);
*(d_first+2) = *first + *(first+1) + *(first+2);
*(d_first+3) = *first + *(first+1) + *(first+2) + *(first+3);
...
op 必须无副作用。 | (C++11 前)
op 必须不非法化涉及范围的任何迭代器，含尾迭代器，或修改该范围的任何元素。 | (C++11 起)

参数

first, last - 要求和的元素范围
d_first - 目标范围起始；可以等于 first
op - 被使用的二元函数对象。

该函数的签名应当等价于：

Ret fun(const Type1 &a, const Type2 &b);

签名中并不需要有 const &。
类型 Type1 必须使得 iterator_traits<InputIt>::value_type 类型的对象能隐式转换到 Type1 。类型 Type2 必须使得 InputIt 类型的对象能在解引用后隐式转换到 Type2 。 类型 Ret 必须使得 iterator_traits<InputIt>::value_type 类型对象能被赋 Ret 类型值。 ​
类型要求
-
InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
-
OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。

返回值

指向最后被写入元素后一元素的迭代器。

复杂度

恰好应用 (last - first) - 1 次二元运算

可能的实现

版本一
template<class InputIt, class OutputIt>
constexpr // C++20 起
OutputIt partial_sum(InputIt first, InputIt last,
                     OutputIt d_first)
{
    if (first == last) return d_first;

    typename std::iterator_traits<InputIt>::value_type sum = *first;
    *d_first = sum;

    while (++first != last) {
       sum = std::move(sum) + *first; // C++20 起有 std::move
       *++d_first = sum;
    }
    return ++d_first;

    // 或 C++14 起：
    // return std::partial_sum(first, last, d_first, std::plus<>());
}
版本二
template<class InputIt, class OutputIt, class BinaryOperation>
constexpr // C++20 起
OutputIt partial_sum(InputIt first, InputIt last,
                     OutputIt d_first, BinaryOperation op)
{
    if (first == last) return d_first;

    typename std::iterator_traits<InputIt>::value_type sum = *first;
    *d_first = sum;

    while (++first != last) {
       sum = op(std::move(sum), *first); // C++20 起有 std::move
       *++d_first = sum;
    }
    return ++d_first;
}

示例

#include <numeric>
#include <vector>
#include <iostream>
#include <iterator>
#include <functional>

int main()
{
    std::vector<int> v = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; // 或 std::vector<int>v(10, 2);

    std::cout << "The first 10 even numbers are: ";
    std::partial_sum(v.begin(), v.end(),
                     std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';

    std::partial_sum(v.begin(), v.end(), v.begin(), std::multiplies<int>());
    std::cout << "The first 10 powers of 2 are: ";
    for (auto n : v) {
        std::cout << n << " ";
    }
    std::cout << '\n';
}

输出：

The first 10 even numbers are: 2 4 6 8 10 12 14 16 18 20
The first 10 powers of 2 are: 2 4 8 16 32 64 128 256 512 1024

参阅

adjacent_difference | 计算范围内各相邻元素之间的差 (函数模板)
accumulate | 对一个范围内的元素求和 (函数模板)
inclusive_scan (C++17) | 类似 std::partial_sum，第 i 个和中包含第 i 个输入 (函数模板)
exclusive_scan (C++17) | 类似 std::partial_sum，第 i 个和中排除第 i 个输入 (函数模板)


std::partition

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class BidirIt, class UnaryPredicate >
BidirIt partition( BidirIt first, BidirIt last, UnaryPredicate p );
 (C++11 前)
template< class ForwardIt, class UnaryPredicate >
ForwardIt partition( ForwardIt first, ForwardIt last, UnaryPredicate p );
 (C++11 起)
(C++20 前)
template< class ForwardIt, class UnaryPredicate >
constexpr ForwardIt partition( ForwardIt first, ForwardIt last, UnaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >

ForwardIt partition( ExecutionPolicy&& policy,

ForwardIt first, ForwardIt last, UnaryPredicate p );
 (2) (C++17 起)
1) 重排序范围 [first, last) 中的元素，使得谓词 p 对其返回 true 的元素前于谓词 p 对其返回 false 的元素。不保持相对顺序。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要重排序的元素范围
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若元素应在顺序中先于其他元素则返回 ​true 的一元谓词。 对每个（可为 const 的） VT 类型参数 v ，其中 VT 是 ForwardIt 的值类型，表达式 p(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 VT& 类型参数，亦不允许 VT ，除非对 VT 而言移动等价于复制 (C++11 起)。 ​
类型要求
- BidirIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求。
- ForwardIt 必须满足值可交换 (ValueSwappable) 和 老式向前迭代器 (LegacyForwardIterator) 的要求。然而，若 ForwardIt 亦满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求则操作更高效
- UnaryPredicate 必须满足谓词 (Predicate) 的要求。

返回值

指向第二组元素首元素的迭代器。

复杂度

给定 N = std::distance (first,last) ，

1) 准确 N 次应用谓词。若 ForwardIt 满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求则至多交换 N/2 次，否则至多交换 N 次。
2) O(N log N) 次交换，及 O(N) 次应用谓词。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class ForwardIt, class UnaryPredicate>
ForwardIt partition(ForwardIt first, ForwardIt last, UnaryPredicate p)
{
    first = std::find_if_not(first, last, p);
    if (first == last) return first;

    for (ForwardIt i = std::next(first); i != last; ++i) {
        if (p(*i)) {
            std::iter_swap(i, first);
            ++first;
        }
    }
    return first;
}

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <forward_list>

template <class ForwardIt>
 void quicksort(ForwardIt first, ForwardIt last)
 {
    if(first == last) return;
    auto pivot = *std::next(first, std::distance(first,last)/2);
    ForwardIt middle1 = std::partition(first, last,
                         [pivot](const auto& em){ return em < pivot; });
    ForwardIt middle2 = std::partition(middle1, last,
                         [pivot](const auto& em){ return !(pivot < em); });
    quicksort(first, middle1);
    quicksort(middle2, last);
 }

int main()
{
    std::vector<int> v = {0,1,2,3,4,5,6,7,8,9};
    std::cout << "Original vector:\n    ";
    for (int elem : v)
        std::cout << elem << ' ';

    auto it = std::partition(v.begin(), v.end(), [](int i){return i % 2 == 0;});

    std::cout << "\nPartitioned vector:\n    ";
    std::copy(std::begin(v), it, std::ostream_iterator<int>(std::cout, " "));
    std::cout << " * ";
    std::copy(it, std::end(v), std::ostream_iterator<int>(std::cout, " "));

    std::forward_list<int> fl = {1, 30, -4, 3, 5, -4, 1, 6, -8, 2, -5, 64, 1, 92};
    std::cout << "\nUnsorted list:\n    ";
    for (int n : fl)
        std::cout << n << ' ';
    std::cout << '\n';

    quicksort(std::begin(fl), std::end(fl));
    std::cout << "Sorted using quicksort:\n    ";
    for(int fi : fl) std::cout << fi << ' ';
    std::cout << '\n';
}

输出：

Original vector:
    0 1 2 3 4 5 6 7 8 9
Partitioned vector:
    0 8 2 6 4  *  5 3 7 1 9
Unsorted list:
    1 30 -4 3 5 -4 1 6 -8 2 -5 64 1 92
Sorted using quicksort:
    -8 -5 -4 -4 1 1 1 2 3 5 6 30 64 92

参阅

is_partitioned (C++11) | 判断范围是否已按给定的谓词划分 (函数模板)
stable_partition | 将元素分为两组，同时保留其相对顺序 (函数模板)


std::partition_copy

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class InputIt, class OutputIt1, class OutputIt2, class UnaryPredicate > std::pair <OutputIt1, OutputIt2> partition_copy( InputIt first, InputIt last, OutputIt1 d_first_true, OutputIt2 d_first_false, UnaryPredicate p ); |  |  | (C++11 起) (C++20 前)
template< class InputIt, class OutputIt1, class OutputIt2, class UnaryPredicate > constexpr std::pair <OutputIt1, OutputIt2> partition_copy( InputIt first, InputIt last, OutputIt1 d_first_true, OutputIt2 d_first_false, UnaryPredicate p ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class ForwardIt3, class UnaryPredicate > std::pair <ForwardIt2, ForwardIt3> partition_copy( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last, ForwardIt2 d_first_true, ForwardIt3 d_first_false, UnaryPredicate p ); | (2) | (C++17 起)
1) 从范围 [first, last) 复制元素到二个不同范围，取决于谓词 p 的返回值。复制满足谓词 p 的元素到始于 d_first_true 的范围。复制剩余元素到始于 d_first_false 的范围。
若输入范围与任一输出范围重叠，则行为未定义。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要排序的元素范围
d_first_true | - | 满足 p 的元素的输出范围起始
d_first_false | - | 不满足 p 的元素的输出范围起始
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若元素应置于 d_first_true 中则返回 ​true 的一元谓词。 对每个（可为 const 的） VT 类型参数 v ，其中 VT 是 InputIt 的值类型，表达式 p(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 VT& 类型参数，亦不允许 VT ，除非对 VT 而言移动等价于复制 (C++11 起)。 ​
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- 解引用 InputIt 结果的类型必须满足可复制赋值 (CopyAssignable) 的要求。
- OutputIt1, OutputIt2 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1, ForwardIt2, ForwardIt3 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。ForwardIt1 的值类型必须为可复制赋值 (CopyAssignable) ，可写入到 ForwardIt2 和 ForwardIt3 ，并且可转换为 UnaryPredicate 的参数类型
- UnaryPredicate 必须满足谓词 (Predicate) 的要求。

返回值

从指向 d_first_true 范围结尾的迭代器和指向 d_first_false 范围结尾的迭代器构造的 std::pair 。

复杂度

准确应用 distance(first, last) 次 p 。

对于带 ExecutionPolicy 的重载，若 ForwardIt 的值类型非可复制构造 (CopyConstructible) ，则可能有性能开销。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class InputIt, class OutputIt1,
         class OutputIt2, class UnaryPredicate>
std::pair<OutputIt1, OutputIt2>
    partition_copy(InputIt first, InputIt last,
                   OutputIt1 d_first_true, OutputIt2 d_first_false,
                   UnaryPredicate p)
{
    while (first != last) {
        if (p(*first)) {
            *d_first_true = *first;
            ++d_first_true;
        } else {
            *d_first_false = *first;
            ++d_first_false;
        }
        ++first;
    }
    return std::pair<OutputIt1, OutputIt2>(d_first_true, d_first_false);
}

示例

#include <iostream>
#include <algorithm>
#include <utility>

int main()
{
    int arr [10] = {1,2,3,4,5,6,7,8,9,10};
    int true_arr [5] = {0};
    int false_arr [5] = {0};

    std::partition_copy(std::begin(arr), std::end(arr), std::begin(true_arr), std::begin(false_arr),
                        [] (int i) {return i > 5;});

    std::cout << "true_arr: ";
    for (auto x : true_arr) {
        std::cout << x << ' ';
    }
    std::cout << '\n';

    std::cout << "false_arr: ";
    for (auto x : false_arr) {
        std::cout << x << ' ';
    }
    std::cout << '\n';

    return 0;

}

输出：

true_arr: 6 7 8 9 10
false_arr: 1 2 3 4 5

参阅

partition | 将范围中的元素分为两组 (函数模板)
stable_partition | 将元素分为两组，同时保留其相对顺序 (函数模板)
copycopy_if (C++11) | 将某一范围的元素复制到一个新的位置 (函数模板)
remove_copyremove_copy_if | 复制一个范围的元素，忽略满足特定判别标准的元素 (函数模板)


std::partition_point

< cpp‎ | algorithm
定义于头文件 <algorithm> |
template< class ForwardIt, class UnaryPredicate > ForwardIt partition_point( ForwardIt first, ForwardIt last, UnaryPredicate p ); | (C++11 起) (C++20 前)
template< class ForwardIt, class UnaryPredicate > constexpr ForwardIt partition_point( ForwardIt first, ForwardIt last, UnaryPredicate p ); | (C++20 起)

检验（如同用 std::partition 的）划分范围 [first, last) ，并定位第一划分的结尾，即首个不满足 p 的元素，或若所有元素满足 p 则为 last 。

参数

first, last | - | 要检验的元素被划分范围
p | - | 对于在范围起始找到的元素则返回 ​true 的一元谓词。 对每个（可为 const 的） VT 类型参数 v ，其中 VT 是 ForwardIt 的值类型，表达式 p(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 VT& 类型参数，亦不允许 VT ，除非对 VT 而言移动等价于复制 (C++11 起)。 ​
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- UnaryPredicate 必须满足谓词 (Predicate) 的要求。

返回值

[first, last) 内第一划分结尾后的迭代器，或若所有元素满足 p 则为 last 。

复杂度

给定 N = std::distance (first, last) ，应用 O(log N) 次谓词 p 。

然而，对于非老式随机访问迭代器 (LegacyRandomAccessIterator) ，迭代器自增次数为 O(N) 。

注解

此算法是 std::lower_bound 的更通用化的形式，能用 std::partition_point 以 [&](auto const& e) { return e < value; } 为谓词表达它。

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>

int main()
{
    std::array<int, 9> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    auto is_even = [](int i){ return i % 2 == 0; };
    std::partition(v.begin(), v.end(), is_even);

    auto p = std::partition_point(v.begin(), v.end(), is_even);

    std::cout << "Before partition:\n    ";
    std::copy(v.begin(), p, std::ostream_iterator<int>(std::cout, " "));
    std::cout << "\nAfter partition:\n    ";
    std::copy(p, v.end(), std::ostream_iterator<int>(std::cout, " "));
}

输出：

Before partition:
    8 2 6 4
After partition:
    5 3 7 1 9

参阅

is_sorted (C++11) | 检查范围是否已按升序排列 (函数模板)
lower_bound | 返回指向第一个不小于给定值的元素的迭代器 (函数模板)


std::pop_heap

< cpp‎ | algorithm
定义于头文件 <algorithm> |
 | (1)
template< class RandomIt > void pop_heap( RandomIt first, RandomIt last ); |  | (C++20 前)
template< class RandomIt > constexpr void pop_heap( RandomIt first, RandomIt last ); |  | (C++20 起)
 | (2)
template< class RandomIt, class Compare > void pop_heap( RandomIt first, RandomIt last, Compare comp ); |  | (C++20 前)
template< class RandomIt, class Compare > constexpr void pop_heap( RandomIt first, RandomIt last, Compare comp ); |  | (C++20 起)

交换在位置 first 的值和在位置 last-1 的值，并令子范围 [first, last-1) 变为堆。这拥有从范围 [first, last) 所定义的堆移除首个元素的效果。

函数的首个版本使用 operator< 比较元素，这使堆成为最大堆。第二版本使用给定的比较函数 comp 。

参数

first, last | - | 定义要修改的合法非空堆的元素范围
comp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若首个参数小于第二个，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 RandomIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- RandomIt 必须满足值可交换 (ValueSwappable) 和 老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。
- 解引用 RandomIt 结果的类型必须满足可移动赋值 (MoveAssignable) 和可移动构造 (MoveConstructible) 的要求。

返回值

（无）

复杂度

至多 2×log(N) 次比较，其中 N= std::distance (first, last).

注意

最大堆是拥有下列属性的元素范围 [f,l) ：

  • 设 N = l - f ，对于所有 0 < i < N ， f[floor(
    i-1
    2
    )] 不小于 f[i] 。
  • 可用 std::push_heap () 添加新元素。
  • 可用 std::pop_heap() 移除首元素。

示例

#include <iostream>
#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> v { 3, 1, 4, 1, 5, 9 };

    std::make_heap(v.begin(), v.end());

    std::cout << "v: ";
    for (auto i : v) std::cout << i << ' ';
    std::cout << '\n';

    std::pop_heap(v.begin(), v.end()); // 移动最大元素到结尾

    std::cout << "after pop_heap: ";
    for (auto i : v) std::cout << i << ' ';
    std::cout << '\n';

    int largest = v.back();
    v.pop_back();  // 实际移出最大元素
    std::cout << "largest element: " << largest << '\n';

    std::cout << "heap without largest: ";
    for (auto i : v) std::cout << i << ' ';
    std::cout << '\n';
}

输出：

v: 9 5 4 1 1 3
after pop_heap: 5 3 4 1 1 9
largest element: 9
heap without largest: 5 3 4 1 1

参阅

push_heap | 将一个元素加入到一个最大堆 (函数模板)
make_heap | 从一个元素范围创建出一个最大堆 (函数模板)


std::prev_permutation

< cpp‎ | algorithm
定义于头文件 <algorithm> |
 | (1)
template< class BidirIt > bool prev_permutation( BidirIt first, BidirIt last); |  | (C++20 前)
template< class BidirIt > constexpr bool prev_permutation( BidirIt first, BidirIt last); |  | (C++20 起)
 | (2)
template< class BidirIt, class Compare > bool prev_permutation( BidirIt first, BidirIt last, Compare comp); |  | (C++20 前)
template< class BidirIt, class Compare > constexpr bool prev_permutation( BidirIt first, BidirIt last, Compare comp); |  | (C++20 起)

变换范围 [first, last) 为来自于相对于 operator< 或 comp 的字典序的所有排列集合的上个排列。若这种排列存在则返回 true ，否则变换范围为末排列（如同用 std::sort(first, last); std::reverse(first, last); ）并返回 false 。

参数

first, last | - | 要重排的元素范围
comp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若首个参数小于第二个，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 BidirIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- BidirIt 必须满足值可交换 (ValueSwappable) 和 老式双向迭代器 (LegacyBidirectionalIterator) 的要求。

返回值

若新排列按字典序前趋旧排列则为 true 。若抵达首个排列并重置范围为最末排列则为 false 。

异常

任何从迭代器操作或元素交换抛出的异常。

复杂度

至多 (last-first)/2 次交换。

典型实现在排列的整个序列上，平均每次调用使用约 3 次比较和 1.5 次交换。

注解

实现（例如 MSVC STL ）可能在迭代器类型满足老式连续迭代器 (LegacyContiguousIterator) ，并且交换其值类型不调用非平凡的特殊成员函数或 ADL 所找到的 swap 时启用向量化。

可能的实现

template<class BidirIt>
bool prev_permutation(BidirIt first, BidirIt last)
{
    if (first == last) return false;
    BidirIt i = last;
    if (first == --i) return false;

    while (1) {
        BidirIt i1, i2;

        i1 = i;
        if (*i1 < *--i) {
            i2 = last;
            while (!(*--i2 < *i))
                ;
            std::iter_swap(i, i2);
            std::reverse(i1, last);
            return true;
        }
        if (i == first) {
            std::reverse(first, last);
            return false;
        }
    }
}

示例

下列代码以逆序打印字符串 "abc" 的所有六个排列

#include <algorithm>
#include <string>
#include <iostream>
#include <functional>
int main()
{
    std::string s="abc";
    std::sort(s.begin(), s.end(), std::greater<char>());
    do {
        std::cout << s << ' ';
    } while(std::prev_permutation(s.begin(), s.end()));
    std::cout << '\n';
}

输出：

cba cab bca bac acb abc

参阅

is_permutation (C++11) | 判断一个序列是否为另一个序列的排列 (函数模板)
next_permutation | 产生某个元素范围的按字典顺序的下一个较大的排列 (函数模板)
ranges::prev_permutation (C++20) | 产生某个元素范围的按字典序下一个较小的排列 (niebloid)


std::push_heap

< cpp‎ | algorithm
定义于头文件 <algorithm> |
 | (1)
template< class RandomIt > void push_heap( RandomIt first, RandomIt last ); |  | (C++20 前)
template< class RandomIt > constexpr void push_heap( RandomIt first, RandomIt last ); |  | (C++20 起)
 | (2)
template< class RandomIt, class Compare > void push_heap( RandomIt first, RandomIt last, Compare comp ); |  | (C++20 前)
template< class RandomIt, class Compare > constexpr void push_heap( RandomIt first, RandomIt last, Compare comp ); |  | (C++20 起)

插入位于位置 last-1 的元素到范围 [first, last-1) 所定义的最大堆中。函数的第一版本用 operator< 比较元素，第二版本用给定的比较函数 comp 。

参数

first, last | - | 定义要修改的堆的元素范围
comp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若首个参数小于第二个，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 RandomIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- RandomIt 必须满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。
- 解引用 RandomIt 结果的类型必须满足可移动赋值 (MoveAssignable) 和可移动构造 (MoveConstructible) 的要求。

返回值

（无）

复杂度

至多 log(N) 次比较，其中 N= std::distance (first, last) 。

注意

最大堆是拥有下列属性的元素范围 [f,l) ：

  • 设 N = l - f ，对于所有 0 < i < N ， f[floor(
    i-1
    2
    )] 不小于 f[i] 。
  • 可用 std::push_heap() 添加新元素。
  • 可用 std::pop_heap () 移除首元素。

示例

#include <iostream>
#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> v { 3, 1, 4, 1, 5, 9 };

    std::make_heap(v.begin(), v.end());

    std::cout << "v: ";
    for (auto i : v) std::cout << i << ' ';
    std::cout << '\n';

    v.push_back(6);

    std::cout << "before push_heap: ";
    for (auto i : v) std::cout << i << ' ';
    std::cout << '\n';

    std::push_heap(v.begin(), v.end());

    std::cout << "after push_heap: ";
    for (auto i : v) std::cout << i << ' ';
    std::cout << '\n';
}

输出：

v: 9 5 4 1 1 3
before push_heap: 9 5 4 1 1 3 6
after push_heap:  9 5 6 1 1 3 4

参阅

pop_heap | 从最大堆中移除最大元素 (函数模板)
make_heap | 从一个元素范围创建出一个最大堆 (函数模板)


std::qsort

< cpp‎ | algorithm
定义于头文件 <cstdlib>
void qsort( void *ptr, std::size_t count, std::size_t size, /*compare-pred*/* comp );
void qsort( void *ptr, std::size_t count, std::size_t size, /*c-compare-pred*/* comp );
 (1)
extern "C++" using /*compare-pred*/ = int(const void*, const void*); // 仅用于阐释
extern "C" using /*c-compare-pred*/ = int(const void*, const void*); // 仅用于阐释
 (2)

以升序排序 ptr 所指向的给定数组。数组含 count 个 size 字节大小的元素。用 comp 所指向的函数比较对象。

若 comp 指示二个元素等价，则其顺序未指定。

若数组元素类型不是简旧数据类型 (PODType) (C++11 前)可平凡复制 (TriviallyCopyable) 类型 (C++11 起)，则行为未定义。

参数

ptr | - | 指向要排序的数组的指针
count | - | 数组元素数
size | - | 数组中元素的大小，以字节表示
comp | - | 比较函数。若首个参数小于第二个，则返回负整数值，若首个参数大于第二个，则返回正整数值，若两参数等价，则返回零。 比较函数的签名应等价于如下形式： int cmp(const void *a, const void *b); 该函数必须不修改传递给它的对象，而且在调用比较相同对象时必须返回一致的结果，无关乎它们在数组中的位置。 ​

返回值

（无）

注解

无关乎名称， C++、 C 及 POSIX 都不要求此函数用快速排序实现或作出任何复杂度和稳定性保证。

C++ 标准库提供的二个重载不同，因为参数 comp 类型有别（语言链接是类型的一部分）。

示例

下列代码用 qsort() 排序整数数组。

#include <iostream>
#include <cstdlib>
#include <climits>
#include <compare>
#include <array>

int main() {
    std::array a { -2, 99, 0, -743, INT_MAX, 2, INT_MIN, 4 };

    std::qsort(
        a.data(),
        a.size(),
        sizeof(decltype(a)::value_type),
        [](const void* x, const void* y) {
            const int arg1 = *static_cast<const int*>(x);
            const int arg2 = *static_cast<const int*>(y);
            const auto cmp = arg1 <=> arg2;
            if (cmp < 0) return -1;
            if (cmp > 0) return 1;
            return 0;
        });

    for (int ai : a)
        std::cout << ai << ' ';
}

输出：

-2147483648 -743 -2 0 2 4 99

参阅

bsearch | 在未指定类型的数组中搜索元素 (函数)
sort | 将范围按升序排序 (函数模板)
is_trivial (C++11) | 检查类型是否平凡 (类模板)


std::random_shuffle, std::shuffle

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
template< class RandomIt > void random_shuffle( RandomIt first, RandomIt last ); | (1) | (C++14 中弃用) (C++17 中移除)
 | (2) |
template< class RandomIt, class RandomFunc > void random_shuffle( RandomIt first, RandomIt last, RandomFunc& r ); |  |  | (C++11 前)
template< class RandomIt, class RandomFunc > void random_shuffle( RandomIt first, RandomIt last, RandomFunc&& r ); |  |  | (C++11 起) (C++14 中弃用) (C++17 中移除)
template< class RandomIt, class URBG > void shuffle( RandomIt first, RandomIt last, URBG&& g ); | (3) | (C++11 起)

重排序给定范围 [first, last) 中的元素，使得这些元素的每个排列拥有相等的出现概率。

1) 随机数生成器是实现定义的，但经常使用函数 std::rand 。
2) 随机数生成器为函数对象 r 。
3) 随机数生成器为函数对象 g 。

参数

first, last | - | 要随机打乱的元素范围
r | - | 函数对象。若以 r(n) 调用，则返回可转换为 std::iterator_traits <RandomIt>::difference_type 的在区间 [0,n) 中随机选取的值
g | - | 均匀随机位生成器 (UniformRandomBitGenerator) ，其结果类型可隐式转换为 std::iterator_traits <RandomIt>::difference_type
类型要求
- RandomIt 必须满足值可交换 (ValueSwappable) 和 老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。
- std::remove_reference_t<URBG> 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

（无）

复杂度

与 first 和 last 间的距离成线性。

注意

标准未钦定实现，故即使你用准确相同的 RandomFunc 或 URBG ，也可能通过不同的标准库实现得到不同结果。

可能的实现

版本一
template< class RandomIt >
void random_shuffle( RandomIt first, RandomIt last )
{
    typename std::iterator_traits<RandomIt>::difference_type i, n;
    n = last - first;
    for (i = n-1; i > 0; --i) {
        using std::swap;
        swap(first[i], first[std::rand() % (i+1)]);
        // rand() % (i+1) 实际上不准确，因为生成的数对于多数 i 值不均匀分布。
        // 正确实现将实际上需要重新实现 C++11 std::uniform_distributtion ，
        // 这超出了此示例的范畴。
    }
}
版本二
template<class RandomIt, class RandomFunc>
void random_shuffle(RandomIt first, RandomIt last, RandomFunc&& r)
{
    typename std::iterator_traits<RandomIt>::difference_type i, n;
    n = last - first;
    for (i = n-1; i > 0; --i) {
        using std::swap;
        swap(first[i], first[r(i+1)]);
    }
}
版本三
template<class RandomIt, class URBG>
void shuffle(RandomIt first, RandomIt last, URBG&& g)
{
    typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
    typedef std::uniform_int_distribution<diff_t> distr_t;
    typedef typename distr_t::param_type param_t;

    distr_t D;
    diff_t n = last - first;
    for (diff_t i = n-1; i > 0; --i) {
        using std::swap;
        swap(first[i], first[D(g, param_t(0, i))]);
    }
}

示例

下列代码随机打乱整数 1..10 ：

#include <random>
#include <algorithm>
#include <iterator>
#include <iostream>

int main()
{
    std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    std::random_device rd;
    std::mt19937 g(rd());

    std::shuffle(v.begin(), v.end(), g);

    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << "\n";
}

可能的输出：

8 6 10 4 2 3 7 1 9 5

参阅

next_permutation | 产生某个元素范围的按字典顺序的下一个较大的排列 (函数模板)
prev_permutation | 产生某个元素范围的按字典顺序的下一个较小的排列 (函数模板)


受约束算法 (C++20 起)

< cpp‎ | algorithm

C++20 在命名空间 std::ranges 中提供大多数算法的受约束版本，能以迭代器-哨位对或单个 range 参数指定范围，并且支持投影和指向成员指针可调用对象。另外更改了大多数算法的返回类型，以返回算法执行过程中计算的所有潜在有用信息。

受约束算法

定义于头文件 <algorithm>
定义于命名空间 std::ranges
不修改序列的操作
ranges::all_ofranges::any_ofranges::none_of
(C++20)(C++20)(C++20)
 检查谓词是否对范围中所有、任一或无元素为 true
(niebloid)
ranges::for_each
(C++20)
 应用函数到范围中的元素
(niebloid)
ranges::for_each_n
(C++20)
 应用函数对象到序列的首 n 个元素
(niebloid)
ranges::countranges::count_if
(C++20)(C++20)
 返回满足指定判别标准的元素数
(niebloid)
ranges::mismatch
(C++20)
 寻找两个范围出现不同的首个位置
(niebloid)
ranges::equal
(C++20)
 确定两个元素集合是否是相同的
(niebloid)
ranges::lexicographical_compare
(C++20)
 当一个范围按字典顺序小于另一个范围时，返回 true
(niebloid)
ranges::findranges::find_ifranges::find_if_not
(C++20)(C++20)(C++20)
 寻找首个满足特定判别标准的元素
(niebloid)
ranges::find_end
(C++20)
 在特定范围中寻找最后出现的元素序列
(niebloid)
ranges::find_first_of
(C++20)
 搜索元素集合中的任一元素
(niebloid)
ranges::adjacent_find
(C++20)
 查找首对相邻的相同（或满足给定谓词的）元素
(niebloid)
ranges::search
(C++20)
 搜索一个元素范围
(niebloid)
ranges::search_n
(C++20)
 在范围中搜索一定量的某个元素的连续副本
(niebloid)
ranges::starts_with
(C++23)
 检查一个范围是否始于另一范围
(niebloid)
ranges::ends_with
(C++23)
 检查一个范围是否终于另一范围
(niebloid)
修改序列的操作
ranges::copyranges::copy_if
(C++20)(C++20)
 将某一范围的元素复制到一个新的位置
(niebloid)
ranges::copy_n
(C++20)
 将一定数目的元素复制到一个新的位置
(niebloid)
ranges::copy_backward
(C++20)
 按从后往前的顺序复制一个范围内的元素
(niebloid)
ranges::move
(C++20)
 将某一范围的元素移动到一个新的位置
(niebloid)
ranges::move_backword
(C++20)
 按从后往前的顺序移动某一范围的元素到新的位置
(niebloid)
ranges::fill
(C++20)
 将一个给定值复制赋值给一个范围内的每个元素
(niebloid)
ranges::fill_n
(C++20)
 将一个值复制赋值给一定量的元素
(niebloid)
ranges::transform
(C++20)
 将一个函数应用于某一范围的各个元素
(niebloid)
ranges::generate
(C++20)
 保存函数结果到一个范围中
(niebloid)
ranges::generate_n
(C++20)
 保存 N 次函数应用的结果
(niebloid)
ranges::removeranges::remove_if
(C++20)(C++20)
 移除满足特定判别标准的元素
(niebloid)
ranges::remove_copyranges::remove_copy_if
(C++20)(C++20)
 复制一个范围的元素，忽略满足特定判别标准的元素
(niebloid)
ranges::replaceranges::replace_if
(C++20)(C++20)
 将所有满足特定判别标准的值替换为另一个值
(niebloid)
ranges::replace_copyranges::replace_copy_if
(C++20)(C++20)
 复制一个范围内的元素，并将满足特定判别标准的元素替换为另一个值
(niebloid)
ranges::swap_ranges
(C++20)
 交换两个范围的元素
(niebloid)
ranges::reverse
(C++20)
 逆转范围中的元素顺序
(niebloid)
ranges::revserse_copy
(C++20)
 创建一个范围的逆向副本
(niebloid)
ranges::rotate
(C++20)
 旋转范围中的元素顺序
(niebloid)
ranges::rotate_copy
(C++20)
 复制并旋转元素范围
(niebloid)
ranges::shuffle
(C++20)
 随机重排范围中的元素
(niebloid)
ranges::sample
(C++20)
 从序列中随机选择 n 个元素
(niebloid)
ranges::unique
(C++20)
 移除范围中的连续重复元素
(niebloid)
ranges::unique_copy
(C++20)
 创建某范围的不含连续重复元素的副本
(niebloid)
划分操作
ranges::is_partitioned
(C++20)
 判断范围是否已按给定的谓词划分
(niebloid)
ranges::partition
(C++20)
 将范围中的元素分为二组
(niebloid)
ranges::partition_copy
(C++20)
 复制一个范围，将各元素分为二组
(niebloid)
ranges::stable_partition
(C++20)
 将元素分成二组，同时保持其相对顺序
(niebloid)
ranges::partition_point
(C++20)
 定位已划分范围的划分点
(niebloid)
排序操作
ranges::is_sorted
(C++20)
 检查范围是否以升序排序
(niebloid)
ranges::is_sorted_until
(C++20)
 寻找最大的已排序子范围
(niebloid)
ranges::sort
(C++20)
 将范围按升序排序
(niebloid)
ranges::partial_sort
(C++20)
 排序一个范围的前 N 个元素
(niebloid)
ranges::partial_sort_copy
(C++20)
 对范围内的元素进行复制并部分排序
(niebloid)
ranges::stable_sort
(C++20)
 将范围内的元素排序，同时保持相等的元素之间的顺序
(niebloid)
ranges::nth_element
(C++20)
 将给定的范围部分排序，确保其按给定元素划分
(niebloid)
二分搜索操作（在已排序范围上）
ranges::lower_bound
(C++20)
 返回指向首个不小于给定值的元素的迭代器
(niebloid)
ranges::upper_bound
(C++20)
 返回指向首个大于某值的元素的迭代器
(niebloid)
ranges::binary_search
(C++20)
 确定元素是否存在于某范围中
(niebloid)
ranges::equal_ranges
(C++20)
 返回匹配特定值的元素范围
(niebloid)
集合操作（在已排序范围上）
ranges::merge
(C++20)
 归并二个已排序范围
(niebloid)
ranges::inplace_merge
(C++20)
 在原位归并两个有序范围
(niebloid)
ranges::includes
(C++20)
 若一个序列是另一个的子列则返回 true
(niebloid)
ranges::set_difference
(C++20)
 计算两个集合的差集
(niebloid)
ranges::set_intersection
(C++20)
 计算两个集合的交集
(niebloid)
ranges::set_symmetric_difference
(C++20)
 计算两个集合的对称差
(niebloid)
ranges::set_union
(C++20)
 计算两个集合的并集
(niebloid)
堆操作
ranges::is_heap
(C++20)
 检查给定范围是否为最大堆
(niebloid)
ranges::is_heap_until
(C++20)
 寻找能成为最大堆的最大子范围
(niebloid)
ranges::make_heap
(C++20)
 从一个元素范围创建出一个最大堆
(niebloid)
ranges::push_heap
(C++20)
 将一个元素加入到一个最大堆
(niebloid)
ranges::pop_heap
(C++20)
 从最大堆中移除最大元素
(niebloid)
ranges::sort_heap
(C++20)
 将一个最大堆变成一个按升序排序的元素范围
(niebloid)
最小/最大操作
ranges::max
(C++20)
 返回给定值的较大者
(niebloid)
ranges::max_element
(C++20)
 返回范围中的最大元素
(niebloid)
ranges::min
(C++20)
 返回给定值的较小者
(niebloid)
ranges::min_element
(C++20)
 返回范围中的最小元素
(niebloid)
ranges::minmax
(C++20)
 返回两个元素的较小和较大者
(niebloid)
ranges::minmax_element
(C++20)
 返回范围中的最小和最大元素
(niebloid)
ranges::clamp
(C++20)
 在一对边界值间夹一个值
(niebloid)
排列操作
ranges::is_permutation
(C++20)
 确定一个序列是否为另一序列的重排
(niebloid)
ranges::next_permutation
(C++20)
 产生某个元素范围的按字典序下一个较大的排列
(niebloid)
ranges::prev_permutation
(C++20)
 产生某个元素范围的按字典序下一个较小的排列
(niebloid)

受约束的未初始化内存算法

定义于头文件 <memory>
定义于命名空间 std::ranges
ranges::uninitialized_copy (C++20) | 复制元素范围到未初始化的内存区域 (niebloid)
ranges::uninitialized_copy_n (C++20) | 复制一定量元素到未初始化的内存区域 (niebloid)
ranges::uninitialized_fill (C++20) | 复制一个对象到范围所定义的未初始化的内存区域 (niebloid)
ranges::uninitialized_fill_n (C++20) | 复制一个对象到起始与计数所定义的未初始化的内存区域 (niebloid)
ranges::uninitialized_move (C++20) | 移动对象范围到未初始化的内存区域 (niebloid)
ranges::uninitialized_move_n (C++20) | 移动一定量对象到未初始化的内存区域 (niebloid)
ranges::uninitialized_default_construct (C++20) | 在范围所定义的未初始化的内存区域以默认初始化构造对象 (niebloid)
ranges::uninitialized_default_construct_n (C++20) | 在起始与计数所定义的未初始化的内存区域以默认初始化构造对象 (niebloid)
ranges::uninitialized_value_construct (C++20) | 在范围所定义的未初始化的内存区域以值初始化构造对象 (niebloid)
ranges::uninitialized_value_construct_n (C++20) | 在起始与计数所定义的未初始化的内存区域以值初始化构造对象 (niebloid)
ranges::destroy (C++20) | 销毁范围中的元素 (niebloid)
ranges::destroy_n (C++20) | 销毁范围中一定量的元素 (niebloid)
ranges::destroy_at (C++20) | 销毁位于给定地址的元素 (niebloid)
ranges::construct_at (C++20) | 在给定地址创建对象 (niebloid)

返回类型

定义于头文件 <algorithm>
定义于命名空间 std::ranges
ranges::in_fun_result (C++20) | 提供存储一个迭代器与一个函数对象为单个单元的方式 (类模板)
ranges::in_in_result (C++20) | 提供存储二个迭代器为单个单元的方式 (类模板)
ranges::in_out_result (C++20) | 提供存储二个迭代器为单个单元的方式 (类模板)
ranges::in_in_out_result (C++20) | 提供存储三个迭代器为单个单元的方式 (类模板)
ranges::in_out_out_result (C++20) | 提供存储三个迭代器为单个单元的方式 (类模板)
ranges::min_max_result (C++20) | 提供存储二个同类型对象或引用为单个单元的方式 (类模板)
ranges::in_found_result (C++20) | 提供存储一个迭代器与一个布尔标志为单个单元的方式 (类模板)


std::ranges::adjacent_find

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity,

std::indirect_binary_predicate<
std::projected<I, Proj>,
std::projected<I, Proj>> Pred = ranges::equal_to >

constexpr I adjacent_find( I first, S last, Pred pred = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::forward_range R, class Proj = std::identity,

std::indirect_binary_predicate<
std::projected<ranges::iterator_t<R>, Proj>,
std::projected<ranges::iterator_t<R>, Proj>> Pred = ranges::equal_to >
constexpr ranges::borrowed_iterator_t<R>

adjacent_find( R&& r, Pred pred = {}, Proj proj = {} );
 (2) (C++20 起)

搜索范围 [first, last) 中二个连续的相等元素。

1) 用 pred （在以投影 proj 投影后）比较元素。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要检验的范围
r | - | 要检验的范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

指向首对等同元素的前一者的迭代器，即首个使得 bool( std::invoke (pred, std::invoke (proj1, *it), std::invoke (proj, *(it + 1)))) 为 true 的 it 。

若找不到这种元素，则返回等于 last 的迭代器。

复杂度

准确应用 min((result-first)+1, (last-first)-1) 次谓词与投影，其中 result 是返回值。

可能的实现

struct adjacent_find_fn {
  template< std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
            std::indirect_binary_predicate<
                std::projected<I, Proj>,
                std::projected<I, Proj>> Pred = ranges::equal_to >
  constexpr I operator()( I first, S last, Pred pred = {}, Proj proj = {} ) const
  {
      if (first == last) {
          return first;
      }
      auto next = ranges::next(first);
      for (; next != last; ++next, ++first) {
          if (std::invoke(pred, std::invoke(proj, *first), std::invoke(proj, *next))) {
              return first;
          }
      }
      return first;
  }

  template< ranges::forward_range R, class Proj = std::identity,
            std::indirect_binary_predicate<
                std::projected<ranges::iterator_t<R>, Proj>,
                std::projected<ranges::iterator_t<R>, Proj>> Pred = ranges::equal_to >
  constexpr ranges::borrowed_iterator_t<R>
    operator()( R&& r, Pred pred = {}, Proj proj = {} ) const
  {
    return (*this)(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
  }
};

inline constexpr adjacent_find_fn adjacent_find;

示例

#include <algorithm>
#include <iostream>
#include <vector>
#include <functional>

int main()
{
    std::vector<int> v1{0, 1, 2, 3, 40, 40, 41, 41, 5};
    //                              ^^          ^^
    namespace ranges = std::ranges;

    auto i1 = ranges::adjacent_find(v1.begin(), v1.end());
    if (i1 == v1.end()) {
        std::cout << "No matching adjacent elements\n";
    } else {
        std::cout << "The first adjacent pair of equal elements is at ["
                  << ranges::distance(v1.begin(), i1) << "] == " << *i1 << '\n';
    }

    auto i2 = ranges::adjacent_find(v1, ranges::greater());
    if (i2 == v1.end()) {
        std::cout << "The entire vector is sorted in ascending order\n";
    } else {
        std::cout << "The last element in the non-decreasing subsequence is at ["
                  << ranges::distance(v1.begin(), i2) << "] == " << *i2 << '\n';
    }
}

输出：

The first adjacent pair of equal elements is at [4] == 40
The last element in the non-decreasing subsequence is at [7] == 41

参阅

ranges::unique (C++20) | 移除范围中的连续重复元素 (niebloid)
adjacent_find | 查找首对相邻的相同（或满足给定谓词的）元素 (函数模板)


std::ranges::all_of, std::ranges::any_of, std::ranges::none_of

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S,

class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred >

constexpr bool all_of( I first, S last, Pred pred, Proj proj = {} );
 (1) (C++20 起)
template< ranges::input_range R, class Proj = std::identity,

std::indirect_unary_predicate<
std::projected<ranges::iterator_t<R>,Proj>> Pred >

constexpr bool all_of( R&& r, Pred pred, Proj proj = {} );
 (2) (C++20 起)
template< std::input_iterator I, std::sentinel_for<I> S,

class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred >

constexpr bool any_of( I first, S last, Pred pred, Proj proj = {} );
 (3) (C++20 起)
template< ranges::input_range R, class Proj = std::identity,

std::indirect_unary_predicate<
std::projected<ranges::iterator_t<R>,Proj>> Pred >

constexpr bool any_of( R&& r, Pred pred, Proj proj = {} );
 (4) (C++20 起)
template< std::input_iterator I, std::sentinel_for<I> S,

class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred >

constexpr bool none_of( I first, S last, Pred pred, Proj proj = {} );
 (5) (C++20 起)
template< ranges::input_range R, class Proj = std::identity,

std::indirect_unary_predicate<
std::projected<ranges::iterator_t<R>,Proj>> Pred >

constexpr bool none_of( R&& r, Pred pred, Proj proj = {} );
 (6) (C++20 起)
1) 检查一元谓词 pred 是否对范围 [first, last) 中的所有元素（以投影 proj 投影后）返回 true 。
3) 检查一元谓词 pred 是否对范围 [first, last) 中至少一个元素（以投影 proj 投影后）返回 true 。
5) 检查一元谓词 pred 是否不对范围 [first, last) 中任何元素（以投影 proj 投影后）返回 true 。
2,4,6) 同 (1,3,5) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要检验的元素范围
r | - | 要检验的元素范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

1-2) 若 std::invoke (pred, std::invoke (proj, *i)) != false 对范围中的每个迭代器 i 成立则为 true ，否则为 false 。若范围为空则返回 true 。
3-4) 若 std::invoke (pred, std::invoke (proj, *i)) != false 对范围中的至少一个迭代器 i 成立则为 true ，否则为 false 。若范围为空则返回 false 。
5-6) 若 std::invoke (pred, std::invoke (proj, *i)) == false 对范围中的每个迭代器 i 成立则为 true ，否则为 false 。若范围为空则返回 true 。

复杂度

至多应用 last - first 次谓词和投影。

可能的实现

版本一
struct all_of_fn {
  template< std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
            std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
  constexpr bool operator()( I first, S last, Pred pred, Proj proj = {} ) const
  {
    return ranges::find_if_not(first, last, std::ref(pred), std::ref(proj)) == last;
  }

  template< ranges::input_range R, class Proj = std::identity,
            std::indirect_unary_predicate<
              std::projected<ranges::iterator_t<R>,Proj>> Pred >
  constexpr bool operator()( R&& r, Pred pred, Proj proj = {} ) const
  {
    return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
  }
};

inline constexpr all_of_fn all_of;
版本二
struct any_of_fn {
  template< std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
            std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
  constexpr bool operator()( I first, S last, Pred pred, Proj proj = {} ) const
  {
    return ranges::find_if(first, last, std::ref(pred), std::ref(proj)) != last;
  }

  template< ranges::input_range R, class Proj = std::identity,
            std::indirect_unary_predicate<
              std::projected<ranges::iterator_t<R>,Proj>> Pred >
  constexpr bool operator()( R&& r, Pred pred, Proj proj = {} ) const
  {
    return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
  }
};

inline constexpr any_of_fn any_of;
版本三
struct none_of_fn {
  template< std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
            std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
  constexpr bool operator()( I first, S last, Pred pred, Proj proj = {} ) const
  {
    return ranges::find_if(first, last, std::ref(pred), std::ref(proj)) == last;
  }

  template< ranges::input_range R, class Proj = std::identity,
            std::indirect_unary_predicate<
              std::projected<ranges::iterator_t<R>,Proj>> Pred >
  constexpr bool operator()( R&& r, Pred pred, Proj proj = {} ) const
  {
    return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
  }
};

inline constexpr none_of_fn none_of;

示例

#include <vector>
#include <numeric>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <functional>

namespace ranges = std::ranges;

int main()
{
    std::vector<int> v(10, 2);
    std::partial_sum(v.cbegin(), v.cend(), v.begin());
    std::cout << "Among the numbers: ";
    ranges::copy(v, std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';

    if (ranges::all_of(v.cbegin(), v.cend(), [](int i){ return i % 2 == 0; })) {
        std::cout << "All numbers are even\n";
    }
    if (ranges::none_of(v, std::bind(std::modulus<int>(), std::placeholders::_1, 2))) {
        std::cout << "None of them are odd\n";
    }

    auto DivisibleBy = [](int d)
    {
        return [d](int m) { return m % d == 0; };
    };

    if (ranges::any_of(v, DivisibleBy(7))) {
        std::cout << "At least one number is divisible by 7\n";
    }
}

输出：

Among the numbers: 2 4 6 8 10 12 14 16 18 20
All numbers are even
None of them are odd
At least one number is divisible by 7

参阅

all_ofany_ofnone_of
(C++11)(C++11)(C++11)
 检查谓词是否对范围中所有、任一或无元素为 true
(函数模板)


std::ranges::binary_search

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I, std::sentinel_for<I> S, class T,

class Proj = std::identity,
std::indirect_strict_weak_order<
const T*,
std::projected<I, Proj>> Comp = ranges::less >
constexpr bool

binary_search( I first, S last, const T& value, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::forward_range R, class T, class Proj = std::identity,

std::indirect_strict_weak_order<
const T*,
std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less >
constexpr bool

binary_search( R&& r, const T& value, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)
1) 检查等价于 value 的元素是否在范围 [first, last) 内出现。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

对于需要成功的 ranges::binary_search ，范围 [first, last) 必须至少以相对 value 部分有序，即他必须满足下列要求：

  • 相对于 std::invoke (comp, std::invoke (proj, element), value) 已划分（即该表达式对其为 true 的所有元素在该表达式对其为 false 的所有元素之前）
  • 相对于 ! std::invoke (comp, value, std::invoke (proj, element)) 已划分
  • 对于所有元素，若 std::invoke (comp, std::invoke (proj, element), value) 为 true 则 ! std::invoke (comp, value, std::invoke (proj, element)) 为 true 。

完全排序的范围符合这些判别标准。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要检验的元素范围
r | - | 要检验的元素范围
value | - | 与元素比较的值
comp | - | 应用到投影后元素的比较函数
proj | - | 应用到元素的投影

返回值

若找到等于 value 的元素则为 true ，否则为 false 。

复杂度

进行的比较与投影次数与 first 和 last 间的距离成对数（至多投影与比较 log
2(last - first) + O(1) 次）。然而，对于不实现 std::random_access_iterator 的迭代器，迭代器自增次数为线性。

可能的实现

struct binary_search_fn {
    template<std::forward_iterator I, std::sentinel_for<I> S, class T,
             class Proj = std::identity,
             std::indirect_strict_weak_order<
                 const T*,
                 std::projected<I, Proj>> Comp = ranges::less>
    constexpr bool
    operator()(I first, S last, const T& value, Comp comp = {}, Proj proj = {}) const
    {
        first = std::lower_bound(first, last, value, comp);
        return (!(first == last) && !(comp(value, *first)));
    }

    template<ranges::forward_range R, class T, class Proj = std::identity,
             std::indirect_strict_weak_order<
                const T*,
                std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less>
    constexpr bool operator()(R&& r, const T& value, Comp comp = {}, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r), ranges::end(r), value,
                       std::ref(comp), std::ref(proj));
    }
};

inline constexpr binary_search_fn binary_search;

示例

#include <iostream>
#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> haystack {1, 3, 4, 5, 9};
    std::vector<int> needles {1, 2, 3};

    for (auto needle : needles) {
        std::cout << "Searching for " << needle << '\n';
        if (ranges::binary_search(haystack, needle)) {
            std::cout << "Found " << needle << '\n';
        } else {
            std::cout << "no dice!\n";
        }
    }
}

输出：

Searching for 1
Found 1
Searching for 2
no dice!
Searching for 3
Found 3

参阅

ranges::equal_ranges (C++20) | 返回匹配特定值的元素范围 (niebloid)
binary_search | 确定元素是否存在于某范围中 (函数模板)


std::ranges::clamp

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< class T, class Proj = std::identity,

std::indirect_strict_weak_order<std::projected<const T*, Proj>> Comp = ranges::less >

constexpr const T& clamp( const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {} );
 (C++20 起)

若 v 比较小于 lo 则返回 lo ；否则若 hi 比较小于 v 则返回 hi ；否则返回 v 。

若 lo 的被投影值大于 hi 则行为未定义。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

v | - | 待夹的值
lo, hi | - | 用以夹 v 的边界
comp | - | 应用到投影后元素的比较
proj | - | 应用到 v 、 lo 及 hi 的投影

返回值

若 v 的被投影值小于 lo 的被投影值则为到 lo 的引用，若 hi 的被投影值小于 v 的被投影值则为 hi 到的引用，否则为到 v 的引用。

复杂度

至多应用二次比较和三次投影。

可能的实现

struct clamp_fn {
  template<class T, class Proj = std::identity,
           std::indirect_strict_weak_order<std::projected<const T*, Proj>> Comp = ranges::less>
  constexpr const T& operator()(const T& v, const T& lo, const T& hi,
                                Comp comp = {}, Proj proj = {}) const
  {
      auto&& pv = std::invoke(proj, v);

      return std::invoke(comp, std::forward<decltype(pv)>(pv), std::invoke(proj, lo)) ? lo
           : std::invoke(comp, std::invoke(proj, hi), std::forward<decltype(pv)>(pv)) ? hi : v;
  }
};

inline constexpr clamp_fn clamp;

注解

若参数之一是临时量，而该参数被返回，则以引用捕获 std::ranges::clamp 的结果会产生一个悬垂引用：
int n = 1;
const int& r = std::ranges::clamp(n-1, n+1);
// r 悬垂

若 v 与任一边界比较等价，则返回到 v 而非到边界的引用。

示例

#include <algorithm>
#include <cstdint>
#include <iostream>
#include <iomanip>
#include <string>

using namespace std::literals;

int main()
{
    std::cout << " raw   clamped to int8_t   clamped to uint8_t\n";
    for(int const v: {-129, -128, -1, 0, 42, 127, 128, 255, 256}) {
        std::cout << std::setw(04) << v
                  << std::setw(20) << std::ranges::clamp(v, INT8_MIN, INT8_MAX)
                  << std::setw(21) << std::ranges::clamp(v, 0, UINT8_MAX) << '\n';
    }
    std::cout << '\n';

    // 投影函数
    const auto stoi = [](std::string s) { return std::stoi(s); };

    // 同上，但用字符串
    for(std::string const v: {"-129", "-128", "-1", "0", "42", "127", "128", "255", "256"}) {
        std::cout << std::setw(04) << v
                  << std::setw(20) << std::ranges::clamp(v, "-128"s, "127"s, {}, stoi)
                  << std::setw(21) << std::ranges::clamp(v, "0"s, "255"s, {}, stoi) << '\n';
    }
}

输出：

 raw   clamped to int8_t   clamped to uint8_t
-129                -128                    0
-128                -128                    0
  -1                  -1                    0
   0                   0                    0
  42                  42                   42
 127                 127                  127
 128                 127                  128
 255                 127                  255
 256                 127                  255

-129                -128                    0
-128                -128                    0
  -1                  -1                    0
   0                   0                    0
  42                  42                   42
 127                 127                  127
 128                 127                  128
 255                 127                  255
 256                 127                  255

参阅

ranges::min (C++20) | 返回给定值的较小者 (niebloid)
ranges::max (C++20) | 返回给定值的较大者 (niebloid)
in_range (C++20) | 检查整数值是否在给定整数类型的范围内 (函数模板)
clamp (C++17) | 在一对边界值间夹逼一个值 (函数模板)


std::ranges::copy, std::ranges::copy_if, std::ranges::copy_result, std::ranges::copy_if_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O >

requires std::indirectly_copyable<I, O>

constexpr ranges::copy_result<I, O> copy( I first, S last, O result );
 (1) (C++20 起)
template< ranges::input_range R, std::weakly_incrementable O >

requires std::indirectly_copyable<ranges::iterator_t<R>, O>
constexpr ranges::copy_result<ranges::borrowed_iterator_t<R>, O>

copy( R&& r, O result );
 (2) (C++20 起)
template< std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O,

class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
requires std::indirectly_copyable<I, O>
constexpr ranges::copy_if_result<I, O>

copy_if( I first, S last, O result, Pred pred, Proj proj = {} );
 (3) (C++20 起)
template< ranges::input_range R, std::weakly_incrementable O,

class Proj = std::identity,
std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
requires std::indirectly_copyable<ranges::iterator_t<R>, O>
constexpr ranges::copy_if_result<ranges::borrowed_iterator_t<R>, O>

copy_if( R&& r, O result, Pred pred, Proj proj = {} );
 (4) (C++20 起)
辅助类型
template < class I, class O >
using copy_result = ranges::in_out_result<I, O>;
 (5) (C++20 起)
template < class I, class O >
using copy_if_result = ranges::in_out_result<I, O>;
 (6) (C++20 起)

复制 [first, last) 所定义的范围中的元素到始于 result 的另一范围。

1) 复制始于 first 并持续到 last - 1 的范围 [first, last) 中的元素。若 result 在范围 [first, last) 内则行为未定义。此情况下，可用 ranges::copy_backward 代替。
3) 仅复制谓词 pred 对其返回 true 的元素。保持复制的元素顺序。若源与目标范围重叠则行为未定义。
2,4) 同 (1,3) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要复制的元素范围
r | - | 要复制的元素范围
result | - | 目标范围的起始
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

含有等于 last 的输入迭代器和指向最后复制元素后一位置的输出迭代器的 ranges::in_out_result 。

复杂度

1-2) 准确赋值 (last - first) 次。
3-4) 准确应用 (last - first) 次谓词与投影，并赋值 ​0​ 到 (last - first) 之间次（对每个谓词返回 true 的元素赋值，取决于谓词与输入数据）。

注解

实践中， std::ranges::copy 的实现若值类型为可平凡复制 (TriviallyCopyable) 且迭代器类型满足 contiguous_iterator ，则避免多次赋值并使用如 std::memmove 的大块复制函数。

复制重叠的范围时， std::ranges::copy 在向左复制（目标范围的起始在源范围外）时适合，而 std::ranges::copy_backward 在向右复制（目标范围的末尾在源范围外）时适合。

可能的实现

版本一
struct copy_fn {
  template< std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O >
  requires std::indirectly_copyable<I, O>
  constexpr ranges::copy_result<I, O> operator()( I first, S last, O result ) const
  {
      for (; first != last; ++first, (void)++result) {
          *result = *first;
      }
      return {std::move(first), std::move(result)};
  }

  template< ranges::input_range R, std::weakly_incrementable O >
  requires std::indirectly_copyable<ranges::iterator_t<R>, O>
  constexpr ranges::copy_result<ranges::borrowed_iterator_t<R>, O>
  operator()( R&& r, O result ) const
  {
      return (*this)(ranges::begin(r), ranges::end(r), std::move(result));
  }
};

inline constexpr copy_fn copy;
版本二
struct copy_if_fn {
  template< std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O,
            class Proj = std::identity,
            std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
  requires std::indirectly_copyable<I, O>
  constexpr ranges::copy_if_result<I, O>
  operator()( I first, S last, O result, Pred pred, Proj proj = {} ) const
  {
      for (; first != last; ++first) {
          if (std::invoke(pred, std::invoke(proj, *first))) {
              *result = *first;
              ++result;
          }
      }

      return {std::move(first), std::move(result)};
  }

  template< ranges::input_range R, std::weakly_incrementable O,
            class Proj = std::identity,
            std::indirect_unary_predicate<
                std::projected<ranges::iterator_t<R>, Proj>> Pred >
  requires std::indirectly_copyable<ranges::iterator_t<R>, O>
  constexpr ranges::copy_if_result<ranges::borrowed_iterator_t<R>, O>
  operator()( R&& r, O result, Pred pred, Proj proj = {} ) const
  {
      return (*this)(ranges::begin(r), ranges::end(r),
                     std::move(result),
                     std::ref(pred), std::ref(proj));
  }
};

inline constexpr copy_if_fn copy_if;

示例

下列代码用 copy 复制 vector 的内容到另一 vector 并显示结果 vector ：

#include <algorithm>
#include <iostream>
#include <vector>
#include <iterator>
#include <numeric>

int main()
{
    std::vector<int> from_vector(10);
    std::iota(from_vector.begin(), from_vector.end(), 0);

    std::vector<int> to_vector;

    namespace ranges = std::ranges;
    ranges::copy(from_vector.begin(), from_vector.end(),
                 std::back_inserter(to_vector));
// 或者另外使用
//  std::vector<int> to_vector(from_vector.size());
//  ranges::copy(from_vector.begin(), from_vector.end(), to_vector.begin());
// 都等价于
//  std::vector<int> to_vector = from_vector;

    std::cout << "to_vector contains: ";

    ranges::copy(to_vector, std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';

    std::cout << "odd numbers in to_vector are: ";

    ranges::copy_if(to_vector, std::ostream_iterator<int>(std::cout, " "),
                 [](int x) { return (x % 2) == 1; });
    std::cout << '\n';
}

输出：

to_vector contains: 0 1 2 3 4 5 6 7 8 9
odd numbers in to_vector are: 1 3 5 7 9

参阅

ranges::copy_backward (C++20) | 按从后往前的顺序复制一个范围内的元素 (niebloid)
ranges::revserse_copy (C++20) | 创建一个范围的逆向副本 (niebloid)
ranges::copy_n (C++20) | 将一定数目的元素复制到一个新的位置 (niebloid)
ranges::fill (C++20) | 将一个给定值复制赋值给一个范围内的每个元素 (niebloid)
ranges::remove_copyranges::remove_copy_if (C++20)(C++20) | 复制一个范围的元素，忽略满足特定判别标准的元素 (niebloid)
copycopy_if (C++11) | 将某一范围的元素复制到一个新的位置 (函数模板)


std::ranges::copy_backward, std::ranges::copy_backward_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::bidirectional_iterator I1, std::sentinel_for<I1> S1,

std::bidirectional_iterator I2 >
requires std::indirectly_copyable<I1, I2>
constexpr copy_backward_result<I1, I2>

copy_backward( I1 first, S1 last, I2 result );
 (1) (C++20 起)
template< ranges::bidirectional_range R, std::bidirectional_iterator I >

requires std::indirectly_copyable<ranges::iterator_t<R>, I>
constexpr copy_backward_result<ranges::borrowed_iterator_t<R>, I>

copy_backward( R&& r, I result );
 (2) (C++20 起)
辅助类型
template< class I1, class I2 >
using copy_backward_result = ranges::in_out_result<I1, I2>;
 (3) (C++20 起)
1) 从 [first, last) 所定义的复制移动元素到另一范围 [result - N, result) ，其中 N = ranges::distance(first, last) 。按逆序复制元素（首先移动末元素），但保持其相对顺序。若 result 在 (first, last] 内则行为未定义。此情况下可用 std::ranges::move 代替。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first | - | 要复制的元素范围的起始
last | - | 要复制元素范围的末尾
r | - | 要复制的元素范围
result | - | 目标范围的末尾

返回值

{last, result - N} 。

复杂度

准确赋值 N 次。

注解

复制重叠的范围时， ranges::copy 适合向左复制（目标范围的起始在源范围外），而 ranges::copy_backward 适合向右复制（目标范围的末尾在源范围外）。

可能的实现

struct copy_backward_fn {
    template<std::bidirectional_iterator I1, std::sentinel_for<I1> S1,
             std::bidirectional_iterator I2>
      requires std::indirectly_copyable<I1, I2>
          constexpr ranges::copy_backward_result<I1, I2>
              operator()( I1 first, S1 last, I2 result ) const {
                  I1 last1{ ranges::next(first, std::move(last)) };
                  for (I1 i{ last1 }; i != first; *--result = *--i);
                  return { std::move(last1), std::move(result) };
              }

    template<ranges::bidirectional_range R, std::bidirectional_iterator I>
        requires std::indirectly_copyable<ranges::iterator_t<R>, I>
            constexpr ranges::copy_backward_result<ranges::borrowed_iterator_t<R>, I>
                operator()( R&& r, I result ) const {
                    return (*this)(ranges::begin(r), ranges::end(r), std::move(result));
                }
};

inline constexpr copy_backward_fn copy_backward{};

示例

#include <algorithm>
#include <iostream>
#include <ranges>
#include <string_view>
#include <vector>

void print(std::string_view rem, std::ranges::forward_range auto const& r) {
    for (std::cout << rem << ": "; auto const& elem : r)
        std::cout << elem << ' ';
    std::cout << '\n';
}

int main()
{
    const auto src = {1, 2, 3, 4};
    print("src", src);

    std::vector<int> dst (src.size() + 2);
    std::ranges::copy_backward(src, dst.end());
    print("dst", dst);

    std::ranges::fill(dst, 0);
    const auto [in, out] =
        std::ranges::copy_backward(src.begin(), src.end() - 2, dst.end());
    print("dst", dst);

    std::cout
        << "(in - src.begin) == " << std::distance(src.begin(), in) << '\n'
        << "(out - dst.begin) == " << std::distance(dst.begin(), out) << '\n';
}

输出：

src: 1 2 3 4
dst: 0 0 1 2 3 4
dst: 0 0 0 0 1 2
(in - src.begin) == 2
(out - dst.begin) == 4

参阅

ranges::copyranges::copy_if (C++20)(C++20) | 将某一范围的元素复制到一个新的位置 (niebloid)
ranges::copy_n (C++20) | 将一定数目的元素复制到一个新的位置 (niebloid)
ranges::remove_copyranges::remove_copy_if (C++20)(C++20) | 复制一个范围的元素，忽略满足特定判别标准的元素 (niebloid)
ranges::replace_copyranges::replace_copy_if (C++20)(C++20) | 复制一个范围内的元素，并将满足特定判别标准的元素替换为另一个值 (niebloid)
ranges::revserse_copy (C++20) | 创建一个范围的逆向副本 (niebloid)
ranges::rotate_copy (C++20) | 复制并旋转元素范围 (niebloid)
ranges::unique_copy (C++20) | 创建某范围的不含连续重复元素的副本 (niebloid)
ranges::move (C++20) | 将某一范围的元素移动到一个新的位置 (niebloid)
ranges::move_backword (C++20) | 按从后往前的顺序移动某一范围的元素到新的位置 (niebloid)
copy_backward | 按从后往前的顺序复制一个范围内的元素 (函数模板)


std::ranges::copy_n, std::ranges::copy_n_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::weakly_incrementable O >

requires std::indirectly_copyable<I, O>
constexpr copy_n_result<I, O>

copy_n( I first, std::iter_difference_t<I> n, O result );
 (1) (C++20 起)
辅助类型
template< class I, class O >
using copy_n_result = ranges::in_out_result<I, O>;
 (2) (C++20 起)
1) 通过对 [0, n) 中的每个整数进行 *(result + i) = *(first + i) ，准确复制 n 个来自始于 first 的范围的值到始于 result 的范围。若 result 在范围 [first, first + n) 内则行为未定义（在此情况下可能可以用 ranges::copy_backward 代替）。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first | - | 要复制的元素范围的起始
n | - | 要复制的元素数
result | - | 目标范围的起始

返回值

ranges::copy_n_result{first + n, result + n} ，或更正式地，含有一个等于 ranges::next(first, n) 的 std::input_iterator 迭代器与一个等于 ranges::next(result, n) 的 std::weakly_incrementable 迭代器的 ranges::in_out_result 类型值。

复杂度

准确赋值 n 次。

注解

实践中，若值类型为可平凡复制 (TriviallyCopyable) 并且迭代器类型满足 contiguous_iterator ，则 std::ranges::copy_n 的实现可以用如 std::memmove 的整块复制函数避免多次赋值。另外，这种复制加速可以由编译优化注入。

在复制重叠的范围时， std::ranges::copy_n 适合向左复制（目标范围的起始在源范围外），而 std::ranges::copy_backward 适合向右复制（目标范围的末尾在源范围外）。

可能的实现

struct copy_n_fn {
  template<std::input_iterator I, std::weakly_incrementable O>
    requires std::indirectly_copyable<I, O>
    constexpr ranges::copy_n_result<I, O>
    operator()(I first, std::iter_difference_t<I> n, O result) const {
        for (std::iter_difference_t<I> i{}; i != n; ++i, ++first, ++result)
            *result = *first;
        return {std::move(first), std::move(result)};
    }
};

inline constexpr copy_n_fn copy_n{};

示例

#include <algorithm>
#include <iterator>
#include <iostream>
#include <iomanip>
#include <string>
#include <string_view>

int main()
{
    const std::string_view in {"ABCDEFGH"};
    std::string out;

    std::ranges::copy_n(in.begin(), 4, std::back_inserter(out));
    std::cout << std::quoted(out) << '\n';

    out = "abcdefgh";
    const auto res = std::ranges::copy_n(in.begin(), 5, out.begin());
    std::cout
        << "*(res.in): '" << *(res.in) << "', distance: "
        << std::distance(std::begin(in), res.in) << '\n'
        << "*(res.out): '" << *(res.out) << "', distance: "
        << std::distance(std::begin(out), res.out) << '\n';
}

输出：

"ABCD"
*(res.in): 'F', distance: 5
*(res.out): 'f', distance: 5

参阅

ranges::copyranges::copy_if (C++20)(C++20) | 将某一范围的元素复制到一个新的位置 (niebloid)
ranges::copy_backward (C++20) | 按从后往前的顺序复制一个范围内的元素 (niebloid)
ranges::remove_copyranges::remove_copy_if (C++20)(C++20) | 复制一个范围的元素，忽略满足特定判别标准的元素 (niebloid)
ranges::replace_copyranges::replace_copy_if (C++20)(C++20) | 复制一个范围内的元素，并将满足特定判别标准的元素替换为另一个值 (niebloid)
ranges::revserse_copy (C++20) | 创建一个范围的逆向副本 (niebloid)
ranges::rotate_copy (C++20) | 复制并旋转元素范围 (niebloid)
ranges::unique_copy (C++20) | 创建某范围的不含连续重复元素的副本 (niebloid)
ranges::move (C++20) | 将某一范围的元素移动到一个新的位置 (niebloid)
ranges::move_backword (C++20) | 按从后往前的顺序移动某一范围的元素到新的位置 (niebloid)
copy_n (C++11) | 将一定数目的元素复制到一个新的位置 (函数模板)


std::ranges::count, std::ranges::count_if

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S,

class T, class Proj = std::identity >
requires std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>,
const T*>
constexpr std::iter_difference_t<I>

count( I first, S last, const T& value, Proj proj = {} );
 (1) (C++20 起)
template< ranges::input_range R, class T, class Proj = std::identity >

requires std::indirect_binary_predicate<ranges::equal_to,
std::projected<ranges::iterator_t<R>, Proj>,
const T*>

constexpr ranges::range_difference_t<R> count( R&& r, const T& value, Proj proj = {} );
 (2) (C++20 起)
template< std::input_iterator I, std::sentinel_for<I> S,

class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
constexpr std::iter_difference_t<I>

count_if( I first, S last, Pred pred = {}, Proj proj = {} );
 (3) (C++20 起)
template< ranges::input_range R, class Proj = std::identity,

std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
constexpr ranges::range_difference_t<R>

count_if( R&& r, Pred pred = {}, Proj proj = {} );
 (4) (C++20 起)

返回范围 [first, last) 中满足特定判别标准的的元素数。

1) 计数等于 value 的元素数。
3) 计数谓词 p 对其返回 true 的元素数。
2,4) 同 (1,3) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要检验的元素范围
r | - | 要检验的元素范围
value | - | 要搜索的值
pred | - | 应用到被投影元素的谓词
proj | - | 应用到元素的投影

返回值

范围中满足条件的元素数。

复杂度

准确比较和应用投影 last - first 次。

注解

对于无任何判别标准的范围中的元素数，见 std::ranges::distance 。

可能的实现

版本一
struct count_fn {
  template< std::input_iterator I, std::sentinel_for<I> S,
          class T, class Proj = std::identity >
  requires std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>,
                                        const T*>
  constexpr std::iter_difference_t<I>
    operator()( I first, S last, const T& value, Proj proj = {} ) const
  {
    std::iter_difference_t<I> counter = 0;
    for (; first != last; ++first) {
      if (std::invoke(proj, *first) == value)
      {
        ++counter;
      }
    }

    return counter;
  }

  template< ranges::input_range R, class T, class Proj = std::identity >
  requires std::indirect_binary_predicate<ranges::equal_to,
                                          std::projected<ranges::iterator_t<R>, Proj>,
                                          const T*>
  constexpr ranges::range_difference_t<R>
    operator()( R&& r, const T& value, Proj proj = {} ) const
  {
    return (*this)(ranges::begin(r), ranges::end(r), value, std::ref(proj));
  }
};

inline constexpr count_fn count;
版本二
struct count_if_fn {
  template< std::input_iterator I, std::sentinel_for<I> S,
            class Proj = std::identity,
            std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
  constexpr std::iter_difference_t<I>
    operator()( I first, S last, Pred pred = {}, Proj proj = {} ) const
  {
    std::iter_difference_t<I> counter = 0;
    for (; first != last; ++first) {
      if (std::invoke(pred, std::invoke(proj, *first)))
      {
        ++counter;
      }
    }

    return counter;
  }

  template< ranges::input_range R, class Proj = std::identity,
            std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
  constexpr ranges::range_difference_t<R>
    operator()( R&& r, Pred pred = {}, Proj proj = {} ) const
  {
    return (*this)(ranges::begin(r), ranges::end(r),
                   std::ref(pred), std::ref(proj));
  }
};

inline constexpr count_if_fn count_if;

示例

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{ 1, 2, 3, 4, 4, 3, 7, 8, 9, 10 };

    namespace ranges = std::ranges;

    // 确定 std::vector 中有多少整数匹配目标值。
    int target1 = 3;
    int target2 = 5;
    int num_items1 = ranges::count(v.begin(), v.end(), target1);
    int num_items2 = ranges::count(v, target2);
    std::cout << "number: " << target1 << " count: " << num_items1 << '\n';
    std::cout << "number: " << target2 << " count: " << num_items2 << '\n';

    // 用 lambda 表达式计数被 3 整除的元素。
    int num_items3 = ranges::count_if(v.begin(), v.end(), [](int i){return i % 3 == 0;});
    std::cout << "number divisible by three: " << num_items3 << '\n';

    // 用 lambda 表达式计数被 11 整除的元素。
    int num_items11 = ranges::count_if(v, [](int i){return i % 11 == 0;});
    std::cout << "number divisible by eleven: " << num_items11 << '\n';
}

输出：

number: 3 count: 2
number: 5 count: 0
number divisible by three: 3
number divisible by eleven: 0

参阅

ranges::distance (C++20) | 返回迭代器与哨位间的距离，或范围起始与结尾间的距离 (niebloid)
ranges::take_while_viewviews::take_while (C++20) | 由另一 view 的到首个谓词返回 false 为止的起始元素组成的 view (类模板) (范围适配器对象)
countcount_if | 返回满足指定判别标准的元素数 (函数模板)


std::ranges::ends_with

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template<std::input_iterator I1, std::sentinel_for<I1> S1,

std::input_iterator I2, std::sentinel_for<I2> S2,
class Pred = ranges::equal_to,
class Proj1 = std::identity, class Proj2 = std::identity>
requires (std::forward_iterator<I1> || std::sized_sentinel_for<S1, I1>) &&
(std::forward_iterator<I2> || std::sized_sentinel_for<S2, I2>) &&
std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr bool ends_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},

Proj1 proj1 = {}, Proj2 proj2 = {});
 (1) (C++23 起)
template<ranges::input_range R1, ranges::input_range R2,

class Pred = ranges::equal_to,
class Proj1 = std::identity, class Proj2 = std::identity>
requires (ranges::forward_range<R1> || ranges::sized_range<R1>) &&
(ranges::forward_range<R2> || ranges::sized_range<R2>) &&
std::indirectly_comparable<ranges::iterator_t<R1>,
ranges::iterator_t<R2>,
Pred, Proj1, Proj2>
constexpr bool ends_with(R1&& r1, R2&& r2, Pred pred = {},

Proj1 proj1 = {}, Proj2 proj2 = {});
 (2) (C++23 起)

检查第二范围是否匹配第一范围的后缀。

1) 令 N1 与 N2 分别为 ranges::distance(first1, last1) 与 ranges::distance(first2, last2) 。若 N1 < N2 则返回 false 。否则，当且仅当 [first2, last2) 范围中的每个元素均等于 [first1 + N1 - N2, last1) 中的对应元素才返回 true 。通过应用二元谓词 pred 到分别由 proj1 与 proj2 投影的两个范围中的元素进行比较。
2) 同， (1) ，但以 r1 与 r2 为源范围，如同以 ranges::begin(r1) 为 first1 ，以 ranges:begin(r2) 为 first2 ，以 ranges::end(r1) 为 last1 ，并以 ranges::end(r2) 为 last2 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 要检验的元素范围
r1 | - | 要检验的元素范围
first2, last2 | - | 要用作后缀的元素范围
r2 | - | 要用作后缀的元素范围
pred | - | 比较投影后元素的二元谓词
proj1 | - | 应用到要检验的元素范围的投影
proj2 | - | 应用到要用作后缀的元素范围的投影

返回值

若第二范围匹配第一范围的后缀则为 true ，否则为 false 。

复杂度

线性：至多应用 min(N1, N2) 次谓词和两个投影。若 N1 < N2 则不应用谓词和两个投影。

若 N1 与 N2 均能以常数时间计算（即两个迭代器-哨位类型对均实现 sized_sentinel_for ，或两个范围类型均实现 sized_range ）且 N1 < N2 ，则时间复杂度为常数。

可能的实现

struct ends_with_fn {
  template<std::input_iterator I1, std::sentinel_for<I1> S1,
           std::input_iterator I2, std::sentinel_for<I2> S2,
           class Pred = ranges::equal_to,
           class Proj1 = std::identity, class Proj2 = std::identity>
    requires (std::forward_iterator<I1> || std::sized_sentinel_for<S1, I1>) &&
             (std::forward_iterator<I2> || std::sized_sentinel_for<S2, I2>) &&
             std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                            Proj1 proj1 = {}, Proj2 proj2 = {}) const {
    const auto n1 = ranges::distance(first1, last1);
    const auto n2 = ranges::distance(first2, last2);

    if (n1 < n2)
      return false;
    ranges::advance(first1, n1 - n2);
    return ranges::equal(std::move(first1), std::move(last1),
                         std::move(first2), std::move(last2),
                         std::move(pred), std::move(proj1), std::move(proj2));
  }

  template<ranges::input_range R1, ranges::input_range R2,
           class Pred = ranges::equal_to,
           class Proj1 = std::identity, class Proj2 = std::identity>
    requires (ranges::forward_range<R1> || ranges::sized_range<R1>) &&
             (ranges::forward_range<R2> || ranges::sized_range<R2>) &&
             std::indirectly_comparable<ranges::iterator_t<R1>,
                                        ranges::iterator_t<R2>,
                                        Pred, Proj1, Proj2>
  constexpr bool operator()(R1&& r1, R2&& r2, Pred pred = {},
                            Proj1 proj1 = {}, Proj2 proj2 = {}) const {
    return (*this)(ranges::begin(r1), ranges::end(r1),
                   ranges::begin(r2), ranges::end(r2),
                   std::move(pred), std::move(proj1), std::move(proj2));
  }
};

inline constexpr ends_with_fn ends_with{};

示例

#include <array>
#include <algorithm>
#include <iostream>

int main()
{
    std::cout
        << std::boolalpha
        << std::ranges::ends_with("static_cast", "cast") << '\n'
        << std::ranges::ends_with("const_cast", "cast") << '\n'
        << std::ranges::ends_with("reinterpret_cast", "cast") << '\n'
        << std::ranges::ends_with("dynamic_cast", "cast") << '\n'
        << std::ranges::ends_with("move", "cast") << '\n'
        << std::ranges::ends_with("move_if_noexcept", "cast") << '\n'
        << std::ranges::ends_with("forward", "cast") << '\n'
        << std::ranges::ends_with("as_const", "cast") << '\n'
        << std::ranges::ends_with("bit_cast", "cast") << '\n'
        << std::ranges::ends_with("to_underlying", "cast") << '\n';
        << std::ranges::ends_with(std::array{1,2,3,4}, std::array{3,4}) << '\n'
        << std::ranges::ends_with(std::array{1,2,3,4}, std::array{4,5}) << '\n';
}

输出：

true
true
true
true
false
false
false
false
true
false

参阅

ranges::starts_with (C++23) | 检查一个范围是否始于另一范围 (niebloid)
ends_with (C++20) | 检查 string 是否终于给定后缀 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
ends_with (C++20) | 检查 string_view 是否终于给定后缀 (std::basic_string_view<CharT,Traits> 的公开成员函数)


std::ranges::equal

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I1, std::sentinel_for<I1> S1,

std::input_iterator I2, std::sentinel_for<I2> S2,
class Pred = ranges::equal_to,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr bool equal( I1 first1, S1 last1, I2 first2, S2 last2,

Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {} );
 (1) (C++20 起)
template< ranges::input_range R1, ranges::input_range R2,

class Pred = ranges::equal_to,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::indirectly_comparable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
Pred, Proj1, Proj2>
constexpr bool equal( R1&& r1, R2&& r2, Pred pred = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (2) (C++20 起)
1) 若范围 [first1, last1) 的被投影值等于范围 [first2, last2) 的被投影值则返回 true ，否则返回 false 。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

若二个范围拥有相同数量的元素，且每对被投影元素都满足 pred ，则认为它们相等，即 std::invoke (pred, std::invoke (proj1, *first1), std::invoke (proj2, *first2)) 对范围中的所有对应元素对都返回 true 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 定义要比较的第一元素范围的迭代器-哨位对
r1 | - | 要比较的第一元素范围
first2, last2 | - | 定义要比较的第一元素范围的迭代器-哨位对
r2 | - | 要比较的第二元素范围
pred | - | 应用到投影后元素的谓词
proj1 | - | 应用到第一元素范围的投影
proj2 | - | 应用到第二元素范围的投影

返回值

若范围 [first1, last1) 的长度不等于范围 [first2, last2) 的长度，则返回 false 。

若二个范围中的元素在投影后相等，则返回 true 。

否则返回 false 。

注解

不应用 ranges::equal 比较由来自 std::unordered_set 、 std::unordered_multiset 、 std::unordered_map 或 std::unordered_multimap 的迭代器组成的范围，因为即使二个容器存储相同元素，元素在容器中的存储顺序亦可以相异。

比较整个容器相等时，通常偏好对应容器的 operator== 。

复杂度

至多应用 min(last1 - first1, last2 - first2) 次谓词和对应的投影。

然而，若 S1 与 S2 均分别与其迭代器实现 std::sized_sentinel_for ，且 last1 - first1 != last2 - first2 ，则不应用谓词（无需查看任何元素即可检测出大小不合）。

可能的实现

struct equal_fn {
  template<std::input_iterator I1, std::sentinel_for<I1> S1,
           std::input_iterator I2, std::sentinel_for<I2> S2,
           class Pred = ranges::equal_to,
           class Proj1 = std::identity, class Proj2 = std::identity>
    requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  constexpr bool
  operator()(I1 first1, S1 last1, I2 first2, S2 last2,
             Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
  {
      if (ranges::distance(first1, last1) != ranges::distance(first2, last2)) {
        return false;
      }

      for (; first1 != last1; ++first1, (void)++first2) {
          if (!std::invoke(pred, std::invoke(proj1, *first1), std::invoke(proj2, *first2))) {
              return false;
          }
      }
      return true;
  }

  template<ranges::input_range R1, std::input_range R2,
           class Pred = ranges::equal_to,
           class Proj1 = std::identity, class Proj2 = std::identity>
    requires std::indirectly_comparable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
                                        Pred, Proj1, Proj2>
  constexpr bool
  operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
  {
      return (*this)(ranges::begin(r1), ranges::end(r1),
                     ranges::begin(r2), ranges::end(r2),
                     std::ref(pred), std::ref(proj1), std::ref(proj2));
  }
};

inline constexpr equal_fn equal;

示例

下列代码用 equal() 测试字符串是否为回文

#include <algorithm>
#include <iostream>
#include <string_view>
#include <ranges>

bool is_palindrome(const std::string_view s)
{
    namespace views = std::views;
    auto forward = s | views::take(s.size() / 2);
    auto backward = s | views::reverse | views::take(s.size() / 2);
    return std::ranges::equal(forward, backward);
}

void test(const std::string_view s)
{
    std::cout << "\"" << s << "\" is"
        << (is_palindrome(s) ? "" : "not")
        << " a palindrome\n";
}

int main()
{
    test("radar");
    test("hello");
}

输出：

"radar" is a palindrome
"hello" is not a palindrome

参阅

ranges::findranges::find_ifranges::find_if_not (C++20)(C++20)(C++20) | 寻找首个满足特定判别标准的元素 (niebloid)
ranges::lexicographical_compare (C++20) | 当一个范围按字典顺序小于另一个范围时，返回 true (niebloid)
ranges::mismatch (C++20) | 寻找两个范围出现不同的首个位置 (niebloid)
ranges::search (C++20) | 搜索一个元素范围 (niebloid)
equal | 确定两个元素集合是否是相同的 (函数模板)


std::ranges::equal_range

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I, std::sentinel_for<I> S,

class T, class Proj = std::identity,
std::indirect_strict_weak_order<
const T*,
std::projected<I, Proj>> Comp = ranges::less >
constexpr ranges::subrange<I>

equal_range(I first, S last, const T& value, Comp comp = {}, Proj proj = {});
 (1) (C++20 起)
template< std::forward_range R, class T, class Proj = std::identity,

std::indirect_strict_weak_order<
const T*,
std::projected<std::iterator_t<R>, Proj>> Comp = ranges::less >
constexpr ranges::borrowed_subrange_t<R>

equal_range(R&& r, const T& value, Comp comp = {}, Proj proj = {});
 (2) (C++20 起)
1) 返回范围 [first, last) 中含有所有等价于 value 的元素的范围的视图。

范围 [first, last) 必须至少相对于 value 有序，即它必须满足下列所有要求：

  • 已相对 element < value 或 comp(element, value) 划分（即所有令该表达式为 true 的元素必须前趋所有令此表达式为 false 的元素）
  • 已相对 !(value < element) 或 !comp(value, element) 划分
  • 对于所有元素，若 element < value 或 comp(element, value) 为 true ，则 !(value < element) 或 !comp(value, element) 亦为 true

完全排序的范围满足这些判别标准。

返回的视图从二个迭代器构造，第一个指向首个不小于 value 的元素，而第二个指向首个大于 value 的元素。可替而用 std::ranges::lower_bound() 获得第一迭代器，用 std::ranges::upper_bound() 获得第二迭代器。

2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要检验的元素范围
r | - | 要检验的元素范围
value | - | 要比较的元素
comp | - | 第一参数是否小于（即先序于）第二个
proj | - | 应用到元素的投影

返回值

含有定义所需范围的迭代器对的 std::ranges::subrange ，第一迭代器指向首个不小于 value 的元素而第二迭代器指向首个大于 value 的元素。

若无元素小于 value ，则返回尾迭代器（等于 last 或 ranges::end(r) 的迭代器）作为第一迭代器。类似地若无元素大于 value ，则返回尾迭代器作为第二迭代器。

复杂度

进行的比较次数与 first 与 last 间的距离成对数（至多 2 * log
2(last - first) + O(1) 次比较）。然而，对于不实现 random_access_iterator 的迭代器，迭代器自增次数为线性。

可能的实现

struct equal_range_fn {
    template< std::forward_iterator I, std::sentinel_for<I> S,
              class T, class Proj = std::identity,
              std::indirect_strict_weak_order<
                  const T*,
                  std::projected<I, Proj>> Comp = ranges::less >
    constexpr ranges::subrange<I>
    operator()(I first, S last, const T& value, Comp comp = {}, Proj proj = {}) const
    {
        return ranges::subrange(
            ranges::lower_bound(first, last, value, std::ref(comp), std::ref(proj)),
            ranges::upper_bound(first, last, value, std::ref(comp), std::ref(proj)));
    }

    template< ranges::forward_range R, class T, class Proj = std::identity,
              std::indirect_strict_weak_order<
                  const T*,
                  std::projected<std::ranges::iterator_t<R>, Proj>> Comp = ranges::less >
    constexpr ranges::borrowed_subrange_t<R>
    operator()(R&& r, const T& value, Comp comp = {}, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r), ranges::end(r), value,
                       std::ref(comp), std::ref(proj));
    }
};

inline constexpr equal_range_fn equal_range;

示例

#include <algorithm>
#include <compare>
#include <vector>
#include <iostream>

struct S
{
    int number;
    char name;
    // 注：这些比较运算符忽略名称
    friend bool operator==  ( const S s1, const S s2 ) { return s1.number == s2.number; }
    friend auto operator<=> ( const S s1, const S s2 ) { return s1.number <=> s2.number; }
};

int main()
{
    // 注：非有序，仅按照定义如下的 S 划分
    std::vector<S> vec = { {1,'A'}, {2,'B'}, {2,'C'}, {2,'D'}, {4, 'D'}, {4,'G'}, {3,'F'} };

    S value = {2, '?'};

    namespace ranges = std::ranges;

    {
        auto p = ranges::equal_range(vec, value);

        for ( auto i : p )
            std::cout << i.name << ' ';
    }
    {
        auto p = ranges::equal_range(vec.begin(), vec.end(), value);

        for ( auto i = p.begin(); i != p.end(); ++i )
            std::cout << i->name << ' ';
    }

    std::cout << '\n';

    {
        auto p = ranges::equal_range(vec, 'D', ranges::less{}, &S::name);

        for ( auto i : p )
            std::cout << i.name << ' ';
    }
    {
        auto p = ranges::equal_range(vec.begin(),vec.end(), 'D', ranges::less{}, &S::name);

        for ( auto i = p.begin(); i != p.end(); ++i )
            std::cout << i->name << ' ';
    }
}

输出：

B C D B C D
D D D D

参阅

ranges::lower_bound (C++20) | 返回指向首个不小于给定值的元素的迭代器 (niebloid)
ranges::upper_bound (C++20) | 返回指向首个大于某值的元素的迭代器 (niebloid)
ranges::binary_search (C++20) | 确定元素是否存在于某范围中 (niebloid)
ranges::partition (C++20) | 将范围中的元素分为二组 (niebloid)
equal_range | 返回匹配特定键值的元素范围 (函数模板)


std::ranges::fill

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< class T, std::output_iterator<const T&> O, std::sentinel_for<O> S >
constexpr O fill( O first, S last, const T& value );
 (1) (C++20 起)
template< class T, ranges::output_range<const T&> R >
constexpr ranges::borrowed_iterator_t<R> fill( R&& r, const T& value );
 (2) (C++20 起)
1) 赋给定值 value 给范围 [first, last) 中的元素。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要修改的元素范围
r | - | 要修改的元素范围
value | - | 要赋的值

返回值

比较等于 last 的输出迭代器。

复杂度

准确赋值 last - first 次。

可能的实现

struct fill_fn {
  template< class T, std::output_iterator<const T&> O, std::sentinel_for<O> S >
  constexpr O operator()( O first, S last, const T& value ) const
  {
      while (first != last) {
          *first++ = value;
      }

      return first;
  }

  template< class T, ranges::output_range<const T&> R >
  constexpr ranges::borrowed_iterator_t<R> operator()( R&& r, const T& value ) const
  {
    return (*this)(ranges::begin(r), ranges::end(r), value);
  }
};

示例

以下代码用 fill() 设置 int 的 vector 的所有元素为 -1 ：

#include <algorithm>
#include <vector>
#include <iostream>

int main()
{
    std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

    namespace ranges = std::ranges;
    ranges::fill(v.begin(), v.end(), -1);

    for (auto elem : v) {
        std::cout << elem << " ";
    }
    std::cout << "\n";

    ranges::fill(v, 10);

    for (auto elem : v) {
        std::cout << elem << " ";
    }
    std::cout << "\n";
}

输出：

-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
10 10 10 10 10 10 10 10 10 10

参阅

ranges::fill_n (C++20) | 将一个值复制赋值给一定量的元素 (niebloid)
ranges::copyranges::copy_if (C++20)(C++20) | 将某一范围的元素复制到一个新的位置 (niebloid)
ranges::generate (C++20) | 保存函数结果到一个范围中 (niebloid)
ranges::transform (C++20) | 将一个函数应用于某一范围的各个元素 (niebloid)
fill | 将一个给定值复制赋值给一个范围内的每个元素 (函数模板)


std::ranges::fill_n

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< class T, std::output_iterator<const T&> O >
constexpr O fill_n( O first, std::iter_difference_t<O> n, const T& value );
 (C++20 起)

赋值给定的 value 给范围 [first, first + n) 中的所有元素。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first | - | 要修改的元素范围的起始
n | - | 要修改的元素数
value | - | 要赋的值

返回值

比较等于 first + n 的迭代器。

复杂度

准确赋值 n 次。

可能的实现

struct fill_n_fn {
  template<class T, std::output_iterator<const T&> O>
    constexpr O operator()(O first, std::iter_difference_t<O> n, const T& value) const {
      for (std::iter_difference_t<O> i{}; i != n; *first = value, ++first, ++i);
      return first;
    }
};

inline constexpr fill_n_fn fill_n{};

示例

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

auto print(const auto& v) {
    for (const auto& elem : v) {
        std::cout << elem << " ";
    }
    std::cout << '\n';
}

int main()
{
    constexpr auto n{8};

    std::vector<std::string> v(n, "░░");
    print(v);

    std::ranges::fill_n(v.begin(), n, "▓▓");
    print(v);
}

输出：

░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░
▓▓ ▓▓ ▓▓ ▓▓ ▓▓ ▓▓ ▓▓ ▓▓

参阅

ranges::fill (C++20) | 将一个给定值复制赋值给一个范围内的每个元素 (niebloid)
ranges::copy_n (C++20) | 将一定数目的元素复制到一个新的位置 (niebloid)
ranges::generate (C++20) | 保存函数结果到一个范围中 (niebloid)
ranges::transform (C++20) | 将一个函数应用于某一范围的各个元素 (niebloid)
fill_n | 将一个给定值复制赋值给一个范围内的 N 个元素 (函数模板)


std::ranges::find, std::ranges::find_if, std::ranges::find_if_not

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S,

class T, class Proj = std::identity >
requires std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>,
const T*>

constexpr I find( I first, S last, const T& value, Proj proj = {} );
 (1) (C++20 起)
template< ranges::input_range R, class T, class Proj = std::identity >

requires std::indirect_binary_predicate<ranges::equal_to,
std::projected<ranges::iterator_t<R>, Proj>,
const T*>

constexpr ranges::borrowed_iterator_t<R> find( R&& r, const T& value, Proj proj = {} );
 (2) (C++20 起)
template< std::input_iterator I, std::sentinel_for<I> S,

class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred >

constexpr I find_if( I first, S last, Pred pred, Proj proj = {} );
 (3) (C++20 起)
template< ranges::input_range R, class Proj = std::identity,

std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
constexpr ranges::borrowed_iterator_t<R>

find_if( R&& r, Pred pred, Proj proj = {} );
 (4) (C++20 起)
template< std::input_iterator I, std::sentinel_for<I> S,

class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred >

constexpr I find_if_not( I first, S last, Pred pred, Proj proj = {} );
 (5) (C++20 起)
template< ranges::input_range R, class Proj = std::identity,

std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
constexpr ranges::borrowed_iterator_t<R>

find_if_not( R&& r, Pred pred, Proj proj = {} );
 (6) (C++20 起)

返回范围 [first, last) 中首个满足特定判别标准的元素：

1) find 搜索等于 value 的元素。
3) find_if 搜索谓词 pred 对其返回 true 的元素。
5) find_if_not 搜索谓词 pred 对其返回 false 的元素。
2,4,6) 同 (1,3,5) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要检验的范围
r | - | 要检验的范围
value | - | 要与元素比较的值
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

指向满足条件的首个元素的迭代器，或若找不到这种元素则为等于 last 的迭代器。

复杂度

至多应用 last - first 次谓词与投影。

可能的实现

版本一
struct find_fn {
  template< std::input_iterator I, std::sentinel_for<I> S,
            class T, class Proj = std::identity >
  requires std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>,
                                          const T*>
  constexpr I operator()( I first, S last, const T& value, Proj proj = {} ) const
  {
      for (; first != last; ++first) {
          if (std::invoke(proj, *first) == value) {
              return first;
          }
      }
      return first;
  }

  template< ranges::input_range R, class T, class Proj = std::identity >
  requires std::indirect_binary_predicate<ranges::equal_to,
                                          std::projected<ranges::iterator_t<R>, Proj>,
                                          const T*>
  constexpr ranges::borrowed_iterator_t<R>
    operator()( R&& r, const T& value, Proj proj = {} ) const
  {
     return (*this)(ranges::begin(r), ranges::end(r), value, std::ref(proj));
  }
};

inline constexpr find_fn find;
版本二
struct find_if_fn {
  template< std::input_iterator I, std::sentinel_for<I> S,
            class Proj = std::identity,
            std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
  constexpr I operator()( I first, S last, Pred pred = {}, Proj proj = {} ) const
  {
      for (; first != last; ++first) {
          if (std::invoke(pred, std::invoke(proj, *first))) {
              return first;
          }
      }
      return first;
  }

  template< ranges::input_range R, class Proj = std::identity,
            std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
  constexpr ranges::borrowed_iterator_t<R>
    operator()( R&& r, Pred pred = {}, Proj proj = {} ) const
  {
    return (*this)(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
  }
};

inline constexpr find_if_fn find_if;
版本三
struct find_if_not_fn {
  template< std::input_iterator I, std::sentinel_for<I> S,
            class Proj = std::identity,
            std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
  constexpr I operator()( I first, S last, Pred pred = {}, Proj proj = {} ) const
  {
      for (; first != last; ++first) {
          if (!std::invoke(pred, std::invoke(proj, *first))) {
              return first;
          }
      }
      return first;
  }

  template< ranges::input_range R, class Proj = std::identity,
            std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
  constexpr ranges::borrowed_iterator_t<R>
    operator()( R&& r, Pred pred = {}, Proj proj = {} ) const
  {
    return (*this)(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
  }
};

inline constexpr find_if_not_fn find_if_not;

示例

以下示例在 int 的 vector 中寻找 int 。

#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>

int main()
{
    int n1 = 3;
    int n2 = 5;

    std::vector<int> v{4, 1, 3, 2};

    namespace ranges = std::ranges;

    auto result1 = ranges::find(v, n1);
    auto result2 = ranges::find(v.begin(), v.end(), n2);

    if (result1 != v.end()) {
        std::cout << "v contains: " << n1 << '\n';
    } else {
        std::cout << "v does not contain: " << n1 << '\n';
    }

    if (result2 != v.end()) {
        std::cout << "v contains: " << n2 << '\n';
    } else {
        std::cout << "v does not contain: " << n2 << '\n';
    }

    auto is_even = [](int x) { return x % 2 == 0; };
    auto divides_13 = [](int x) { return x % 13 == 0; };

    auto result3 = ranges::find_if(v.begin(), v.end(), is_even);
    auto result4 = ranges::find_if(v, divides_13);
    if (result3 != v.end()) {
      std::cout << "First even element in v: " << *result3 << '\n';
    } else {
      std::cout << "No even elements in v\n";
    }

    if (result4 != v.end()) {
      std::cout << "First element divisible by 13 in v: " << *result4 << '\n';
    } else {
      std::cout << "No elements in v are divisible by 13\n";
    }

    auto result5 = ranges::find_if_not(v.begin(), v.end(), divides_13);
    auto result6 = ranges::find_if_not(v, is_even);
    if (result5 != v.end()) {
      std::cout << "First element indivisible by 13 in v: " << *result5 << '\n';
    } else {
      std::cout << "No elements in v are divisible by 13\n";
    }

    if (result6 != v.end()) {
      std::cout << "First odd element in v: " << *result6 << '\n';
    } else {
      std::cout << "No even elements in v\n";
    }
}

输出：

v contains: 3
v does not contain: 5
First even element in v: 4
No elements in v are divisible by 13
First element indivisible by 13 in v: 4
First odd element in v: 1

参阅

ranges::adjacent_find (C++20) | 查找首对相邻的相同（或满足给定谓词的）元素 (niebloid)
ranges::find_end (C++20) | 在特定范围中寻找最后出现的元素序列 (niebloid)
ranges::find_first_of (C++20) | 搜索元素集合中的任一元素 (niebloid)
ranges::mismatch (C++20) | 寻找两个范围出现不同的首个位置 (niebloid)
ranges::search (C++20) | 搜索一个元素范围 (niebloid)
findfind_iffind_if_not (C++11) | 寻找首个满足特定判别标准的元素 (函数模板)


std::ranges::find_end

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I1, std::sentinel_for<I1> S1,

std::forward_iterator I2, std::sentinel_for<I2> S2,
class Pred = ranges::equal_to,
class Proj1 = std::identity,
class Proj2 = std::identity >
requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr ranges::subrange<I1>
find_end( I1 first1, S1 last1, I2 first2, S2 last2,

Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {} );
 (1) (C++20 起)
template< ranges::forward_range R1, ranges::forward_range R2,

class Pred = ranges::equal_to,
class Proj1 = std::identity,
class Proj2 = std::identity >
requires std::indirectly_comparable<ranges::iterator_t<R1>,
ranges::iterator_t<R2>,
Pred, Proj1, Proj2>
constexpr ranges::borrowed_subrange_t<R1>
find_end( R1&& r1, R2&& r2, Pred pred = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (2) (C++20 起)
1) 搜索序列 [first2, last2) 在范围 [first1, last1) 中的最后出现，在分别以proj1 与 proj2 投影后。用二元谓词 pred 比较投影后的元素。
2) 同 (1) ，但以 r1 为第一源范围并以 r2 为第二源范围，如同以 ranges::begin(r1) 为 first1 ，以 ranges::end(r1) 为 last1 ， ranges::begin(r2) 为 first2 ，并以 ranges::end(r2) 为 last2 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 要检验的元素范围（又称草堆）
first2, last2 | - | 要搜索的元素范围（又称针）
r1 | - | 要检验的元素范围（又称草堆）
r2 | - | 要搜索的元素范围（又称针）
pred | - | 比较元素的二元谓词
proj1 | - | 应用到第一范围中元素的投影
proj2 | - | 应用到第二范围中元素的投影

返回值

1) 以表达式 {i, i + (i == last1 ? 0 : last2 - first2)} 初始化的 ranges::subrange<I1> 值，该范围代表序列 [first2, last2) 在范围 [first1, last1) 中的最后一次出现（在以 proj1 与 proj2 投影后）。若 [first2, last2) 为空或找不到该序列，则等效地以 {last1, last1} 初始化返回值。
2) 同 (1) ，除了返回类型为 ranges::borrowed_subrange_t<R1> 。

复杂度

至多应用 \(\scriptsize S\cdot(N-S+1)\)S·(N-S+1) 次谓词和对应的每次投影，其中对于 (1) \(\scriptsize S\)S 为 ranges::distance(first2, last2) 而 \(\scriptsize N\)N 为 ranges::distance(first1, last1) ，或对于 (2) \(\scriptsize S\)S 为 ranges::distance(r2) 而 \(\scriptsize N\)N 为 ranges::distance(r1) 。

注解

若输入迭代器实现 std::bidirectional_iterator ，则实现可以通过从末尾到起始搜索改进效率。实现 std::random_access_iterator 可能提升比较速度。然而所有这些不改变最坏情况的理论复杂度。

可能的实现

struct find_end_fn {

  template<std::forward_iterator I1, std::sentinel_for<I1> S1,
           std::forward_iterator I2, std::sentinel_for<I2> S2,
           class Pred = ranges::equal_to,
           class Proj1 = std::identity, class Proj2 = std::identity>
    requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr ranges::subrange<I1>
        operator()(I1 first1, S1 last1,
                   I2 first2, S2 last2, Pred pred = {},
                   Proj1 proj1 = {}, Proj2 proj2 = {}) const
  {
      if (first2 == last2) {
          auto last_it = ranges::next(first1, last1);
          return {last_it, last_it};
      }
      auto result = ranges::search(
          std::move(first1), last1, first2, last2, pred, proj1, proj2);

      if (result.empty()) return result;

      for (;;) {
          auto new_result = ranges::search(
              std::next(result.begin()), last1, first2, last2, pred, proj1, proj2);
          if (new_result.empty())
              return result;
          else
              result = std::move(new_result);
      }
  }

  template<ranges::forward_range R1, ranges::forward_range R2,
           class Pred = ranges::equal_to,
           class Proj1 = std::identity,
           class Proj2 = std::identity>
  requires std::indirectly_comparable<ranges::iterator_t<R1>,
                                      ranges::iterator_t<R2>,
                                      Pred, Proj1, Proj2>
  constexpr ranges::borrowed_subrange_t<R1>
    operator()(R1&& r1, R2&& r2, Pred pred = {},
               Proj1 proj1 = {}, Proj2 proj2 = {}) const
    {
        return (*this)(ranges::begin(r1), ranges::end(r1),
                       ranges::begin(r2), ranges::end(r2),
                       std::move(pred),
                       std::move(proj1), std::move(proj2));
    }
};

inline constexpr find_end_fn find_end{};

示例

#include <algorithm>
#include <array>
#include <cctype>
#include <iostream>
#include <ranges>
#include <string_view>

void print(const auto haystack, const auto needle)
{
    const auto pos = std::distance(haystack.begin(), needle.begin());
    std::cout << "In \"";
    for (const auto c : haystack) { std::cout << c; }
    std::cout << "\" found \"";
    for (const auto c : needle) { std::cout << c; }
    std::cout << "\" at position [" << pos << ".." << pos + needle.size() << ")\n"
        << std::string(4 + pos, ' ') << std::string(needle.size(), '^') << '\n';
}

int main()
{
    using namespace std::literals;
    constexpr auto secret{"password password word..."sv};
    constexpr auto wanted{"password"sv};

    constexpr auto found1 = std::ranges::find_end(
        secret.cbegin(), secret.cend(), wanted.cbegin(), wanted.cend());
    print(secret, found1);

    constexpr auto found2 = std::ranges::find_end(secret, "word"sv);
    print(secret, found2);

    const auto found3 = std::ranges::find_end(secret, "ORD"sv,
        [](const char x, const char y) { // 用二元谓词
            return std::tolower(x) == std::tolower(y);
        });
    print(secret, found3);

    const auto found4 = std::ranges::find_end(secret, "SWORD"sv, {}, {},
        [](char c) { return std::tolower(c); }); // 投影第二范围
    print(secret, found4);

    static_assert(std::ranges::find_end(secret, "PASS"sv).empty()); // => 找不到
}

输出：

In "password password word..." found "password" at position [9..17)
             ^^^^^^^^
In "password password word..." found "word" at position [18..22)
                      ^^^^
In "password password word..." found "ord" at position [19..22)
                       ^^^
In "password password word..." found "sword" at position [12..17)
                ^^^^^

参阅

find_end | 在特定范围中寻找最后出现的元素序列 (函数模板)
ranges::adjacent_find (C++20) | 查找首对相邻的相同（或满足给定谓词的）元素 (niebloid)
ranges::findranges::find_ifranges::find_if_not (C++20)(C++20)(C++20) | 寻找首个满足特定判别标准的元素 (niebloid)
ranges::find_first_of (C++20) | 搜索元素集合中的任一元素 (niebloid)
ranges::search (C++20) | 搜索一个元素范围 (niebloid)
ranges::search_n (C++20) | 在范围中搜索一定量的某个元素的连续副本 (niebloid)


std::ranges::find_first_of

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I1, std::sentinel_for<I1> S1,

std::forward_iterator I2, std::sentinel_for<I2> S2,
class Pred = ranges::equal_to,
class Proj1 = std::identity,
class Proj2 = std::identity >
requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr I1 find_first_of( I1 first1, S1 last1, I2 first2, S2 last2,

Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {} );
 (1) (C++20 起)
template< ranges::input_range R1, ranges::forward_range R2,

class Pred = ranges::equal_to,
class Proj1 = std::identity,
class Proj2 = std::identity >
requires std::indirectly_comparable<ranges::iterator_t<R1>,
ranges::iterator_t<R2>,
Pred, Proj1, Proj2>
constexpr ranges::borrowed_iterator_t<R1>
find_first_of( R1&& r1, R2&& r2, Pred pred = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (2) (C++20 起)
1) 在范围 [first1, last1) 中搜索任何范围 [first2, last2) 中的元素，分别以 proj1 与 proj2 投影范围。用二元谓词 pred 比较投影后的元素。
2) 同 (1) ，但以 r1 为第一源范围并以 r2 为第二源范围，如同以 ranges::begin(r1) 为 first1 ，以 ranges::end(r1) 为 last1 ，以 ranges::begin(r2) 为 first2 ，并以 ranges::end(r2) 为 last2 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 要检验的元素范围（又称草堆）
first2, last2 | - | 要搜索的元素范围（又称针）
r1 | - | 要检验的元素范围（又称草堆）
r2 | - | 要搜索的元素范围（又称针）
pred | - | 比较元素的二元谓词
proj1 | - | 应用到第一范围中元素的投影
proj2 | - | 应用到第二范围中元素的投影

返回值

指向范围 [first1, last1) 中首个在投影后等于来自范围 [first2, last2) 中元素的迭代器。若找不到这种元素，则返回等于 last1 的迭代器。

复杂度

至多应用 (S*N) 次比较和各自的投影，其中
(1) S = ranges::distance(first2, last2) 而 N = ranges::distance(first1, last1) ；
(2) S = ranges::size(r2) 而 N = ranges::size(r1) 。

可能的实现

struct find_first_of_fn {

  template<std::input_iterator I1, std::sentinel_for<I1> S1,
           std::forward_iterator I2, std::sentinel_for<I2> S2,
           class Pred = ranges::equal_to,
           class Proj1 = std::identity,
           class Proj2 = std::identity>
  requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  constexpr I1 operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                          Proj1 proj1 = {}, Proj2 proj2 = {}) const {
    for (; first1 != last1; ++first1)
      for (auto i = first2; i != last2; ++i)
        if (std::invoke(pred, std::invoke(proj1, *first1), std::invoke(proj2, *i)))
          return first1;
    return first1;
  }

  template<ranges::input_range R1, ranges::forward_range R2,
           class Pred = ranges::equal_to,
           class Proj1 = std::identity,
           class Proj2 = std::identity>
    requires std::indirectly_comparable<ranges::iterator_t<R1>,
                                        ranges::iterator_t<R2>,
                                        Pred, Proj1, Proj2>
    constexpr ranges::borrowed_iterator_t<R1>
      operator()(R1&& r1, R2&& r2, Pred pred = {},
                 Proj1 proj1 = {}, Proj2 proj2 = {}) const {
      return (*this)(ranges::begin(r1), ranges::end(r1),
                     ranges::begin(r2), ranges::end(r2),
                     std::move(pred), std::move(proj1), std::move(proj2));
    }
};

inline constexpr find_first_of_fn find_first_of{};

示例

#include <algorithm>
#include <iostream>
#include <iterator>

int main()
{
    namespace rng = std::ranges;

    constexpr static auto haystack = {1, 2, 3, 4};
    constexpr static auto needles  = {0, 3, 4, 3};

    constexpr auto found1 = rng::find_first_of(haystack.begin(), haystack.end(),
                                               needles.begin(), needles.end());
    static_assert(std::distance(haystack.begin(), found1) == 2);

    constexpr auto found2 = rng::find_first_of(haystack, needles);
    static_assert(std::distance(haystack.begin(), found2) == 2);

    constexpr static auto negatives = {-6, -3, -4, -3};
    constexpr auto not_found = rng::find_first_of(haystack, negatives);
    static_assert(not_found == haystack.end());

    constexpr auto found3 = rng::find_first_of(haystack, negatives,
        [](int x, int y) { return x == -y; }); // 使用二元比较器
    static_assert(std::distance(haystack.begin(), found3) == 2);

    struct P { int x, y; };
    constexpr static auto p1 = { P{1, -1}, P{2, -2}, P{3, -3}, P{4, -4} };
    constexpr static auto p2 = { P{5, -5}, P{6, -3}, P{7, -5}, P{8, -3} };

    // 仅比较 P::y 数据成员，通过投影它们：
    const auto found4 = rng::find_first_of(p1, p2, {}, &P::y, &P::y);
    std::cout << "First equivalent element {" << found4->x << ", " << found4->y
              << "} was found at position " << std::distance(p1.begin(), found4)
              << ".\n";
}

输出：

First equavalent element {3, -3} was found at position 2.

参阅

find_first_of | 搜索元素集合中的任意元素 (函数模板)
ranges::adjacent_find (C++20) | 查找首对相邻的相同（或满足给定谓词的）元素 (niebloid)
ranges::findranges::find_ifranges::find_if_not (C++20)(C++20)(C++20) | 寻找首个满足特定判别标准的元素 (niebloid)
ranges::find_end (C++20) | 在特定范围中寻找最后出现的元素序列 (niebloid)
ranges::search (C++20) | 搜索一个元素范围 (niebloid)
ranges::search_n (C++20) | 在范围中搜索一定量的某个元素的连续副本 (niebloid)


std::ranges::for_each

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity,

std::indirectly_unary_invocable<std::projected<I, Proj>> Fun >

constexpr ranges::for_each_result<I, Fun> for_each( I first, S last, Fun f, Proj proj = {} );
 (1) (C++20 起)
template< ranges::input_range R, class Proj = std::identity,

std::indirectly_unary_invocable<std::projected<ranges::iterator_t<R>, Proj>> Fun >
constexpr ranges::for_each_result<ranges::borrowed_iterator_t<R>, Fun>

for_each( R&& r, Fun f, Proj proj = {} );
 (2) (C++20 起)
辅助类型
template< class I, class F >
using for_each_result = ranges::in_fun_result<I, F>;
 (3) (C++20 起)
1) 将给定的函数对象 f 应用于范围 [first, last) 中每个迭代器投影的值的结果，按顺序排列。
2) 与 (1) 相同，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

对于两个重载，如果迭代器的类型是可变的，则 f 可能会解引用的迭代器去修改范围中的元素。如果 f 会返回结果，则忽略此结果。

参数

first, last | - | 代表要应用函数到的范围的迭代器-哨位对
r | - | 要将函数应用到的元素范围
f | - | 应用到投影后范围的元素
proj | - | 应用范围的投影

返回值

{std::ranges::next(std::move(first), last), std::move(f)}

复杂度

准确应用 last - first 次 f 和 proj

可能的实现

struct for_each_fn {
  template<std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
           std::indirectly_unary_invocable<std::projected<I, Proj>> Fun>
  constexpr ranges::for_each_result<I, Fun>
  operator()(I first, S last, Fun f, Proj proj = {}) const
  {
    for (; first != last; ++first) {
      std::invoke(f, std::invoke(proj, *first));
    }
    return {std::move(first), std::move(f)};
  }

  template<ranges::input_range R, class Proj = std::identity,
           std::indirectly_unary_invocable<std::projected<ranges::iterator_t<R>, Proj>> Fun>
  constexpr ranges::for_each_result<ranges::borrowed_iterator_t<R>, Fun>
  operator()(R&& r, Fun f, Proj proj = {}) const
  {
    return (*this)(ranges::begin(r), ranges::end(r), std::move(f), std::ref(proj));
  }
};

inline constexpr for_each_fn for_each;

示例

下述的示例用 lambda 表达式递增 vector 所有的元素，然后用函数对象中重载的 operator() 计算它们的和。注意，要计算总和的话，建议使用专用的算法 std::accumulate 。

#include <algorithm>
#include <cassert>
#include <iostream>
#include <string>
#include <utility>
#include <vector>

struct Sum
{
    void operator()(int n) { sum += n; }
    int sum{0};
};

int main()
{
    std::vector<int> nums{3, 4, 2, 8, 15, 267};

    auto print = [](const auto& n) { std::cout << ' ' << n; };

    namespace ranges = std::ranges;
    std::cout << "before:";
    ranges::for_each(std::as_const(nums), print);
    print('\n');

    ranges::for_each(nums, [](int& n){ ++n; });

    // 对每个数调用 Sum::operator()
    auto [i, s] = ranges::for_each(nums.begin(), nums.end(), Sum());
    assert(i == nums.end());

    std::cout << "after: ";
    ranges::for_each(nums.cbegin(), nums.cend(), print);

    std::cout << "\n" "sum: " << s.sum << '\n';

    using pair = std::pair<int, std::string>;
    std::vector<pair> pairs{{1,"one"}, {2,"two"}, {3,"three"}};

    std::cout << "project the pair::first: ";
    ranges::for_each(pairs, print, [](const pair& p) { return p.first; });

    std::cout << "\n" "project the pair::second:";
    ranges::for_each(pairs, print, &pair::second);
    print('\n');
}

输出：

before: 3 4 2 8 15 267
after:  4 5 3 9 16 268
sum: 305
project the pair::first:  1 2 3
project the pair::second: one two tree

参阅

范围 for 循环 (C++11) | 执行范围上的循环
ranges::transform (C++20) | 将一个函数应用于某一范围的各个元素 (niebloid)
ranges::for_each_n (C++20) | 应用函数对象到序列的首 n 个元素 (niebloid)
for_each | 应用函数到范围中的元素 (函数模板)


std::ranges::for_each_n, std::ranges::for_each_n_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, class Proj = identity,

std::indirectly_unary_invocable<std::projected<I, Proj>> Fun >
constexpr for_each_n_result<I, Fun>

for_each_n( I first, std::iter_difference_t<I> n, Fun f, Proj proj = {});
 (1) (C++20 起)
辅助类型
template< class I, class F >
using for_each_n_result = ranges::in_fun_result<I, F>;
 (2) (C++20 起)
1) 按顺序应用给定的函数对象 f 到用 proj 投影的解引用范围 [first, first + n) 中的每个迭代器的结果。

若迭代器类型可变，则 f 可能通过解引用的迭代器修改范围中的匀速。若 f 返回结果，则忽略结果，若 n 小于零，则行为未定义。 此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first | - | 代表要应用函数到的范围起始的迭代器
n | - | 要应用函数到的元素数
f | - | 应用到投影后范围 [first, first + n) 的函数
proj | - | 应用到元素的投影

返回值

对象 {first + n, std::move(f)} ，其中 first + n 可能求值为 std::ranges::next(std::move(first), n) ，取决于迭代器类别。

复杂度

准确应用 n 次 f 与 proj 。

注解

namespace::ranges 中的重载要求 Fun 实现 copy_constructible 。

可能的实现

struct for_each_n_fn {
  template<std::input_iterator I, class Proj = std::identity,
           std::indirectly_unary_invocable<std::projected<I, Proj>> Fun>
    constexpr for_each_n_result<I, Fun>
      operator()(I first, std::iter_difference_t<I> n, Fun fun, Proj proj = Proj{}) const
      {
        for (; n-- > 0; ++first) {
          std::invoke(fun, std::invoke(proj, *first));
        }
        return {std::move(first), std::move(fun)};
      }
};

inline constexpr for_each_n_fn for_each_n{};

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <ranges>
#include <string_view>

struct P {
    int first; char second;
    friend std::ostream& operator<< (std::ostream& os, const P& p) {
        return os << '{' << p.first << ",'" << p.second << "'}";
    }
};

auto print = [](std::string_view name, auto const& v) {
    std::cout << name << ": ";
    for (auto n = v.size(); const auto& e: v) {
        std::cout << e << (--n ? ", " : "\n");
    }
};

int main()
{
    std::array a{1, 2, 3, 4, 5};
    print("a", a);
    // 对前三个数取相反数：
    std::ranges::for_each_n(a.begin(), 3, [](auto& n) { n *= -1; });
    print("a", a);

    std::array s{ P{1,'a'}, P{2, 'b'}, P{3, 'c'}, P{4, 'd'} };
    print("s", s);
    // 用投影对数据成员 'pair::first' 取相反数：
    std::ranges::for_each_n(s.begin(), 2, [](auto& x) { x *= -1; }, &P::first);
    print("s", s);
    // 用投影大写化数据成员 'pair::second' ：
    std::ranges::for_each_n(s.begin(), 3, [](auto& c) { c -= 'a'-'A'; }, &P::second);
    print("s", s);
}

输出：

a: 1, 2, 3, 4, 5
a: -1, -2, -3, 4, 5
s: {1,'a'}, {2,'b'}, {3,'c'}, {4,'d'}
s: {-1,'a'}, {-2,'b'}, {3,'c'}, {4,'d'}
s: {-1,'A'}, {-2,'B'}, {3,'C'}, {4,'d'}

参阅

范围 for 循环 (C++11) | 执行范围上的循环
ranges::for_each (C++20) | 应用函数到范围中的元素 (niebloid)
for_each_n (C++17) | 应用一个函数对象到序列的前 n 个元素 (函数模板)
for_each | 应用函数到范围中的元素 (函数模板)


std::ranges::generate

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_or_output_iterator O, std::sentinel_for<O> S,

std::copy_constructible F >
requires std::invocable<F&> && std::indirectly_writable<O, std::invoke_result_t<F&>>
constexpr O

generate( O first, S last, F gen );
 (1) (C++20 起)
template< class R, std::copy_constructible F >

requires std::invocable<F&> && ranges::output_range<R, std::invoke_result_t<F&>>
constexpr ranges::borrowed_iterator_t<R>

generate( R&& r, F gen );
 (2) (C++20 起)
1) 对范围 [first, last) 中的每个元素赋值连续调用函数对象 gen 的结果。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要修改的元素范围
r | - | 要修改的元素范围
gen | - | 生成器函数对象

返回值

比较等于 last 的迭代器。

复杂度

准确调用 ranges::distance(first, last) 次 gen() 以及赋值。

可能的实现

struct generate_fn {
  template<std::input_or_output_iterator O, std::sentinel_for<O> S,
           std::copy_constructible F>
    requires std::invocable<F&> && std::indirectly_writable<O, std::invoke_result_t<F&>>
      constexpr O operator()( O first, S last, F gen ) const {
        for (; first != last; *first = std::invoke(gen), ++first);
        return first;
      }
  template<class R, std::copy_constructible F>
    requires std::invocable<F&> && ranges::output_range<R, std::invoke_result_t<F&>>
      constexpr ranges::borrowed_iterator_t<R> operator()( R&& r, F gen ) const {
        return (*this)(ranges::begin(r), ranges::end(r), std::move(gen));
      }
};

inline constexpr generate_fn generate{};

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <random>
#include <string_view>

auto dice() {
    static std::uniform_int_distribution<int> distr{1, 6};
    static std::random_device device;
    static std::mt19937 engine{device()};
    return distr(engine);
}

void iota(auto& v, int n) {
    std::ranges::generate(v, [&n] () mutable { return n++; });
}

void print(std::string_view comment, const auto& v) {
    for (std::cout << comment; int i : v) { std::cout << i << ' '; }
    std::cout << '\n';
}

int main()
{
    std::array<int, 8> v;

    std::ranges::generate(v.begin(), v.end(), dice);
    print("dice: ", v);
    std::ranges::generate(v, dice);
    print("dice: ", v);

    iota(v, 1);
    print("iota: ", v);
}

可能的输出：

dice: 4 3 1 6 6 4 5 5
dice: 4 2 5 3 6 2 6 2
iota: 1 2 3 4 5 6 7 8

参阅

ranges::generate_n (C++20) | 保存 N 次函数应用的结果 (niebloid)
ranges::fill (C++20) | 将一个给定值复制赋值给一个范围内的每个元素 (niebloid)
ranges::fill_n (C++20) | 将一个值复制赋值给一定量的元素 (niebloid)
ranges::transform (C++20) | 将一个函数应用于某一范围的各个元素 (niebloid)
generate | 将相继的函数调用结果赋值给一个范围中的每个元素 (函数模板)


std::ranges::generate_n

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template<std::input_or_output_iterator O, std::copy_constructible F>

requires std::invocable<F&> && std::indirectly_writable<O, std::invoke_result_t<F&>>

constexpr O generate_n( O first, std::iter_difference_t<O> n, F gen );
 (C++20 起)

若 0 < n 则对范围 [first, first + n) 中的每个元素赋值连续调用函数对象 gen 的结果，否则不做任何事。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first | - | 要修改的元素范围起始
n | - | 要修改的元素数
gen | - | 生成器函数对象

返回值

若 0 < count 则为末元素后一位置迭代器，否则为 first 。

复杂度

准确调用 n 次 gen() 以及赋值。

可能的实现

struct generate_n_fn {
  template<std::input_or_output_iterator O, std::copy_constructible F>
    requires std::invocable<F&> && std::indirectly_writable<O, std::invoke_result_t<F&>>
      constexpr O operator()( O first, std::iter_difference_t<O> n, F gen ) const {
        for (; n-- > 0; *first = std::invoke(gen), ++first);
        return first;
      }
};

inline constexpr generate_n_fn generate_n{};

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <random>
#include <string_view>

auto dice() {
    static std::uniform_int_distribution<int> distr{1, 6};
    static std::random_device engine;
    static std::mt19937 noise{engine()};
    return distr(noise);
}

void print(const auto& v, std::string_view comment) {
    for (int i : v) { std::cout << i << ' '; }
    std::cout << "(" << comment << ")\n";
}

int main()
{
    std::array<int, 8> v;

    std::ranges::generate_n(v.begin(), v.size(), dice);
    print(v, "dice");

    std::ranges::generate_n(v.begin(), v.size(), [n{0}] () mutable { return n++; });
    // 与 std::iota(v.begin(), v.end(), 0); 效果相同
    print(v, "iota");
}

可能的输出：

5 5 2 2 6 6 3 5 (dice)
0 1 2 3 4 5 6 7 (iota)

参阅

ranges::generate (C++20) | 保存函数结果到一个范围中 (niebloid)
ranges::fill (C++20) | 将一个给定值复制赋值给一个范围内的每个元素 (niebloid)
ranges::fill_n (C++20) | 将一个值复制赋值给一定量的元素 (niebloid)
ranges::transform (C++20) | 将一个函数应用于某一范围的各个元素 (niebloid)
generate_n | 将相继的函数调用结果赋值给一个范围中的 N 个元素 (函数模板)


std::ranges::includes

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I1, std::sentinel_for<I1> S1,

std::input_iterator I2, std::sentinel_for<I2> S2,
class Proj1 = std::identity, class Proj2 = std::identity,
std::indirect_strict_weak_order<
std::projected<I1, Proj1>,
std::projected<I2, Proj2>> Comp = ranges::less >
constexpr bool includes( I1 first1, S1 last1, I2 first2, S2 last2,

Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {} )
 (1) (C++20 起)
template< ranges::input_range R1, ranges::input_range R2,

class Proj1 = std::identity, class Proj2 = std::identity,
std::indirect_strict_weak_order<
std::projected<ranges::iterator_t<R1>, Proj1>,
std::projected<ranges::iterator_t<R2>, Proj2>> Comp = ranges::less >
constexpr bool includes( R1&& r1, R2&& r2, Comp comp = {},

Proj1 proj1 = {}, Proj2 proj2 = {} )
 (2) (C++20 起)
1) 若已排序范围 [first2, last2) 的投影是已排序范围 [first1, last1) 的投影的子序列则返回 true 。
2) 同 (1) ，但以 r1 与 r2 为源范围，如同分别以 ranges::begin(r1) 与 ranges::begin(r2) 为 first1 与 first2 ，并分别以 ranges::end(r1) 与 ranges::end(r2) 为 last1 与 last2 。

两个范围都必须按照给定的比较函数 comp 排序。子序列不需要连续。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 待检验的已排序的元素范围
r1 | - | 待检验的已排序的元素范围
first2, last2 | - | 待搜索的已排序的元素范围
r2 | - | 待搜索的已排序的元素范围
comp | - | 应用到投影后元素的谓词
proj1 | - | 应用到第一范围中元素的投影
proj2 | - | 应用到第二范围中元素的投影

返回值

若 [first2, last2) 是 [first1, last1) 的子序列则为 true ；否则为 false 。

复杂度

至多比较 \(\scriptsize 2 \cdot (N_1+N_2-1)\)2·(N1+N2-1) 次，其中 \(\scriptsize N_1\)N1 为 ranges::distance(r1) 而 \(\scriptsize N_2\)N2 为 ranges::distance(r2) 。

可能的实现

struct includes_fn {
  template<std::input_iterator I1, std::sentinel_for<I1> S1,
           std::input_iterator I2, std::sentinel_for<I2> S2,
           class Proj1 = std::identity, class Proj2 = std::identity,
           std::indirect_strict_weak_order<
               std::projected<I1, Proj1>,
               std::projected<I2, Proj2>> Comp = ranges::less>
  constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2,
                          Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
  {
      for (; first2 != last2; ++first1)
      {
          if (first1 == last1 && comp(*first2, *first1))
              return false;
          if (!comp(*first1, *first2))
              ++first2;
      }
      return true;
  }

  template<ranges::input_range R1, ranges::input_range R2,
           class Proj1 = std::identity, class Proj2 = std::identity,
           std::indirect_strict_weak_order<
               std::projected<ranges::iterator_t<R1>, Proj1>,
               std::projected<ranges::iterator_t<R2>, Proj2>> Comp = ranges::less>
  constexpr bool operator()(R1&& r1, R2&& r2, Comp comp = {},
                            Proj1 proj1 = {}, Proj2 proj2 = {}) const
  {
    return (*this)(ranges::begin(r1), ranges::end(r1),
                   ranges::begin(r2), ranges::end(r2),
                   std::ref(comp), std::ref(proj1), std::ref(proj2));
  }
};

inline constexpr auto includes = includes_fn{};

示例

#include <iostream>
#include <algorithm>
#include <cctype>

template <class Os, class R> Os& operator<<(Os& os, const R& r) {
  for (const auto& e : r) os << e << ' ';
  return os << '\t';
}

int main()
{
  const auto
    v1 = {'a', 'b', 'c', 'f', 'h', 'x'},
    v2 = {'a', 'b', 'c'},
    v3 = {'a', 'c'},
    v4 = {'a', 'a', 'b'},
    v5 = {'g'},
    v6 = {'a', 'c', 'g'},
    v7 = {'A', 'B', 'C'};

  auto no_case = [](char a, char b) { return std::tolower(a) < std::tolower(b); };
  namespace ranges = std::ranges;
  std::cout
    << v1 << "\nincludes:\n" << std::boolalpha
    << v2 << ": " << ranges::includes(v1.begin(), v1.end(), v2.begin(), v2.end()) << '\n'
    << v3 << ": " << ranges::includes(v1, v3) << '\n'
    << v4 << ": " << ranges::includes(v1, v4) << '\n'
    << v5 << ": " << ranges::includes(v1, v5) << '\n'
    << v6 << ": " << ranges::includes(v1, v6) << '\n'
    << v7 << ": " << ranges::includes(v1, v7, no_case)
          << " (case-insensitive)\n";
}

输出：

a b c f h x
includes:
a b c   : true
a c     : true
a a b   : false
g       : false
a c g   : false
A B C   : true (case-insensitive)

参阅

ranges::set_difference (C++20) | 计算两个集合的差集 (niebloid)
ranges::search (C++20) | 搜索一个元素范围 (niebloid)
includes | 若一个序列是另一个的子列则返回 true (函数模板)


std::ranges::inplace_merge

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::bidirectional_iterator I, std::sentinel_for<I> S,

class Comp = ranges::less, class Proj = std::identity >
requires std::sortable<I, Comp, Proj>

I inplace_merge( I first, I middle, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::bidirectional_range R, class Comp = ranges::less,

class Proj = std::identity >
requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
ranges::borrowed_iterator_t<R>

inplace_merge( R&& r, ranges::iterator_t<R> middle, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)

归并二个已排序范围 [first, middle) 与 [middle, last) 到一个已排序范围 [first, last) 中。

称序列为按照比较器 comp 与投影 proj 已排序，若对应任何指向序列的迭代器 it 与任何使得 it + n 为指向序列元素的合法迭代器的非负整数 n ， std::invoke (comp, std::invoke (proj, *(it + n)), std::invoke (proj, *it))) 求值为 false 。

此归并函数是稳定的，这表示对于原在二个范围中的等价元素，来自第一范围的元素（保持其原顺序）先于来自第二范围的元素（保持其原顺序）。

1) 用给定的二元比较函数 comp 与投影对象 proj 比较元素，而范围必须按同样方式排序。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first | - | 第一已排序范围的起始
middle | - | 第一范围的末尾与第二范围的起始
last | - | 第二已排序范围的末尾
r | - | 要原位归并的元素范围
comp | - | 应用到投影后元素的比较器
proj | - | 应用到范围中元素的投影

返回值

等于 last 的迭代器。

复杂度

若额外内存可用则准确比较 N−1 次，其中 N = ranges::distance(first, last) 。否则比较 \(\scriptsize \mathcal{O}(N\cdot\log{(N)})\)𝓞(N•log(N)) 次。另外在两种情况下都进行二倍次数的投影。

注解

此函数尝试分配临时缓冲区。若分配失败，则选择较低效的算法。

可能的实现

此实现仅展示无额外内存可用时使用的较慢的算法。参阅 MSVC STL 与 libstdc++ 中的实现。

struct inplace_merge_fn {
    template<std::bidirectional_iterator I, std::sentinel_for<I> S,
             class Comp = ranges::less, class Proj = std::identity>
        requires std::sortable<I, Comp, Proj>
    I operator()(I first, I middle, S last, Comp comp = {}, Proj proj = {}) const {
        I last_it = ranges::next(middle, last);
        inplace_merge_slow(first, middle, last_it,
                           ranges::distance(first, middle),
                           ranges::distance(middle, last_it);
                           std::ref(comp), std::ref(proj));
        return last_it;
    }

    template<ranges::bidirectional_range R, class Comp = ranges::less,
             class Proj = std::identity>
        requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
    ranges::borrowed_iterator_t<R>
    operator()(R&& r, ranges::iterator_t<R> middle,
               Comp comp = {}, Proj proj = {}) const {
        return (*this)(ranges::begin(r), std::move(middle), ranges::end(r),
                       std::move(comp), std::move(proj));
    }

private:
    template<std::bidirectional_iterator I, class Comp, class Proj>
        requires std::sortable<I, Comp, Proj>
    static void inplace_merge_slow(I first, I middle, I last, std::iter_difference_t<I> n1,
                                   std::iter_difference_t<I> n2, Comp comp, Proj proj)
    {
        if (n1 == 0 || n2 == 0)
            return;
        if (n1 + n2 == 2)
           if (comp(proj(*middle), proj(*first))) {
               ranges::iter_swap(first, middle);
               return;
           }

        I cut1 = first;
        I cut2 = middle;
        std::iter_difference_t<I> d1{};
        std::iter_difference_t<I> d2{};

        if (n1 > n2) {
            d1 = n1 / 2;
            ranges::advance(cut1, d1);
            cut2 = ranges::lower_bound(middle, last, *cut1,
                                       std::ref(comp), std::ref(proj));
            d2 = ranges::distance(middle, cut2);
        }
        else {
            d2 = n2 / 2;
            ranges::advance(cut2, d2);
            cut1 = ranges::upper_bound(first, middle, *cut2,
                                       std::ref(comp), std::ref(proj));
            d1 = ranges::distance(first, cut1);
        }

        I new_middle = ranges::rotate(cut1, middle, cut2);

        inplace_merge_slow(first, cut1, new_middle, d1, d2,
                           std::ref(comp), std::ref(proj));
        inplace_merge_slow(new_middle, cut2, last, n1 - d1, n2 - d2,
                           std::ref(comp), std::ref(proj));
    }
};

inline constexpr inplace_merge_fn inplace_merge{};

示例

#include <algorithm>
#include <complex>
#include <functional>
#include <iostream>
#include <iterator>
#include <vector>

void print(auto const& v, auto const& rem, int middle = -1)
{
    for (int i{}; auto n : v)
        std::cout << (i++ == middle ? "│ " : "") << n << ' ';
    std::cout << rem << '\n';
}

template <std::random_access_iterator I, std::sentinel_for<I> S>
requires std::sortable<I>
void merge_sort(I first, S last)
{
    if (last - first > 1) {
        I middle {first + (last - first) / 2};
        merge_sort(first, middle);
        merge_sort(middle, last);
        std::ranges::inplace_merge(first, middle, last);
    }
}

int main()
{
    // 定制归并排序演示
    std::vector v {8, 2, 0, 4, 9, 8, 1, 7, 3};
    print(v, ": before sort");
    merge_sort(v.begin(), v.end());
    print(v, ": after sort\n");

    // 以比较函数对象和投影归并
    using CI = std::complex<int>;
    std::vector<CI> r { {0,1}, {0,2}, {0,3}, {1,1}, {1,2} };
    const auto middle { std::ranges::next(r.begin(), 3) };
    auto comp { std::ranges::less{} };
    auto proj { [](CI z) { return z.imag(); } };

    print(r, ": before merge", middle - r.begin());
    std::ranges::inplace_merge(r, middle, comp, proj);
    print(r, ": after merge");
}

输出：

8 2 0 4 9 8 1 7 3 : before sort
0 1 2 3 4 7 8 8 9 : after sort

(0,1) (0,2) (0,3) │ (1,1) (1,2) : before merge
(0,1) (1,1) (0,2) (1,2) (0,3) : after merge

参阅

ranges::merge (C++20) | 归并二个已排序范围 (niebloid)
ranges::set_union (C++20) | 计算两个集合的并集 (niebloid)
ranges::is_sorted (C++20) | 检查范围是否以升序排序 (niebloid)
ranges::sort (C++20) | 将范围按升序排序 (niebloid)
inplace_merge | 就地归并两个有序范围 (函数模板)


std::ranges::is_heap

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::random_access_iterator I, std::sentinel_for<I> S,

class Proj = std::identity, std::indirect_strict_weak_order<
std::projected<I, Proj>> Comp = ranges::less >

constexpr bool is_heap( I first, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::random_access_range R, class Proj = std::identity,

std::indirect_strict_weak_order<std::projected<ranges::iterator_t<R>, Proj>>
Comp = ranges::less >

constexpr bool is_heap( R&& r, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)

检查范围 [first, last) 中的元素是否为最大堆。

1) 用给定的二元比较函数 comp 与投影对象 proj 比较元素。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要检验的元素范围
r | - | 要检验的元素范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

若范围为最大堆则为 true ，否则为 false 。

复杂度

与 first 和 last 间的距离成线性。

注解

最大堆是按照比较器 comp 与投影 proj 排列的元素范围 [f, l) ，拥有下列属性：

  • 令 N == l - f ，对于所有 0 < i < N ， p == f[(i - 1) / 2] 和 q == f[i] ，表达式 std::invoke (comp, std::invoke (proj, p), std::invoke (proj, q)) 求值为 false 。
  • 能用 ranges::push_heap() 在 \(\scriptsize \mathcal{O}(\log N)\)𝓞(log N) 时间内添加新元素。
  • 能用 ranges::pop_heap() 在 \(\scriptsize \mathcal{O}(\log N)\)𝓞(log N) 时间内移除首元素。

可能的实现

struct is_heap_fn {
    template< std::random_access_iterator I, std::sentinel_for<I> S,
              class Proj = std::identity, std::indirect_strict_weak_order<
              std::projected<I, Proj>> Comp = ranges::less >
    constexpr bool operator()( I first, S last, Comp comp = {}, Proj proj = {} ) const {
        return (last == ranges::is_heap_until(first, last, std::move(comp), std::move(proj)));
    }

    template< ranges::random_access_range R, class Proj = std::identity,
              std::indirect_strict_weak_order<std::projected<ranges::iterator_t<R>, Proj>>
              Comp = ranges::less >
    constexpr bool operator()( R&& r, Comp comp = {}, Proj proj = {} ) const {
        return (*this)(ranges::begin(r), ranges::end(r), std::move(comp), std::move(proj));
    }
};

inline constexpr is_heap_fn is_heap{};

示例

#include <algorithm>
#include <bit>
#include <cmath>
#include <iostream>
#include <vector>

void out(const auto& what, int n = 1) { while (n-- > 0) std::cout << what; }

void draw_heap(auto const& v);

int main()
{
    std::vector<int> v { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8 };

    out("initially, v:\n");
    for (auto i : v) std::cout << i << ' ';
    out('\n');

    if (!std::ranges::is_heap(v)) {
        out("making heap...\n");
        std::ranges::make_heap(v);
    }

    out("after make_heap, v:\n");
    for (auto t{1U}; auto i : v) {
        std::cout << i << (std::has_single_bit(++t) ? " │ " : " ");
    }

    out("\n" "corresponding binary tree is:\n");
    draw_heap(v);
}

void draw_heap(auto const& v)
{
    auto bails = [](int n, int w) {
        auto b = [](int w) { out("┌"), out("─", w), out("┴"), out("─", w), out("┐"); };
        n /= 2;
        if (!n) return;
        for (out(' ', w); n-- > 0; ) b(w), out(' ', w + w + 1);
        out('\n');
    };
    auto data = [](int n, int w, auto& first, auto last) {
        for(out(' ', w); n-- > 0 && first != last; ++first)
            out(*first), out(' ', w + w + 1);
        out('\n');
    };
    auto tier = [&](int t, int m, auto& first, auto last) {
        const int n {1 << t};
        const int w {(1 << (m - t - 1)) - 1};
        bails(n, w), data(n, w, first, last);
    };
    const int m {static_cast<int>(std::ceil(std::log2(1 + v.size())))};
    auto first {v.cbegin()};
    for (int i{}; i != m; ++i) { tier(i, m, first, v.cend()); }
}

输出：

initially, v:
3 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 2 3 8
making heap...
after make_heap, v:
9 │ 8 9 │ 6 5 8 9 │ 3 5 3 5 3 4 7 2 │ 1 2 3 1
corresponding binary tree is:
               9
       ┌───────┴───────┐
       8               9
   ┌───┴───┐       ┌───┴───┐
   6       5       8       9
 ┌─┴─┐   ┌─┴─┐   ┌─┴─┐   ┌─┴─┐
 3   5   3   5   3   4   7   2
┌┴┐ ┌┴┐ ┌┴┐ ┌┴┐ ┌┴┐ ┌┴┐ ┌┴┐ ┌┴┐
1 2 3 1

参阅

ranges::is_heap_until (C++20) | 寻找能成为最大堆的最大子范围 (niebloid)
ranges::make_heap (C++20) | 从一个元素范围创建出一个最大堆 (niebloid)
ranges::push_heap (C++20) | 将一个元素加入到一个最大堆 (niebloid)
ranges::pop_heap (C++20) | 从最大堆中移除最大元素 (niebloid)
ranges::sort_heap (C++20) | 将一个最大堆变成一个按升序排序的元素范围 (niebloid)
is_heap | 检查给定范围是否为一个最大堆 (函数模板)


std::ranges::is_heap_until

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::random_access_iterator I, std::sentinel_for<I> S,

class Proj = std::identity, std::indirect_strict_weak_order<
std::projected<I, Proj>> Comp = ranges::less >

constexpr I is_heap_until( I first, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::random_access_range R, class Proj = std::identity,

std::indirect_strict_weak_order<std::projected<ranges::iterator_t<R>, Proj>>
Comp = ranges::less >
constexpr ranges::borrowed_iterator_t<R>

is_heap_until( R&& r, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)

检验范围 [first, last) 并寻找始于 first 且为最大堆的最大范围。

1) 用给定的二元比较函数 comp 和投影对象 proj 比较元素。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要检验的元素范围
r | - | 要检验的元素范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

始于 first 并为最大堆的最大范围的上界。即尾迭代器 it ，使得范围 [first, it) 相对于 comp 与 proj 为最大堆。

复杂度

与 first 和 last 间的距离成线性。

注解

最大堆是按照比较器 comp 与投影 proj 排列的元素范围 [f, l) ，拥有下列属性：

  • 令 N == l - f ，对于所有 0 < i < N ， p == f[(i - 1) / 2] 和 q == f[i] ，表达式 std::invoke (comp, std::invoke (proj, p), std::invoke (proj, q)) 求值为 false 。
  • 能用 ranges::push_heap() 在 \(\scriptsize \mathcal{O}(\log N)\)𝓞(log N) 时间内添加新元素。
  • 能用 ranges::pop_heap() 在 \(\scriptsize \mathcal{O}(\log N)\)𝓞(log N) 时间内移除首元素。

可能的实现

struct is_heap_until_fn {
    template< std::random_access_iterator I, std::sentinel_for<I> S,
              class Proj = std::identity, std::indirect_strict_weak_order<
              std::projected<I, Proj>> Comp = ranges::less >
    constexpr I
    operator()( I first, S last, Comp comp = {}, Proj proj = {} ) const {
        std::iter_difference_t<I> n {ranges::distance(first, last)}, dad {0}, son {1};
        for (; son != n; ++son) {
            if (std::invoke(comp, std::invoke(proj, *(first + dad)),
                                  std::invoke(proj, *(first + son)))) {
                return first + son;
            } else if ((son % 2) == 0) {
                ++dad;
            }
        }
        return first + n;
    }

    template< ranges::random_access_range R, class Proj = std::identity,
              std::indirect_strict_weak_order<std::projected<ranges::iterator_t<R>, Proj>>
              Comp = ranges::less >
    constexpr ranges::borrowed_iterator_t<R>
    operator()( R&& r, Comp comp = {}, Proj proj = {} ) const {
        return (*this)(ranges::begin(r), ranges::end(r), std::move(comp), std::move(proj));
    }
};

inline constexpr is_heap_until_fn is_heap_until{};

示例

此示例将给定的 vector 重置为（平衡）二叉树。

#include <algorithm>
#include <cmath>
#include <iostream>
#include <iterator>
#include <vector>

void out(const auto& what, int n = 1) { while (n-- > 0) std::cout << what; }

void draw_bin_tree(auto first, auto last);

int main()
{
    std::vector<int> v { 3, 1, 4, 1, 5, 9, };
    std::ranges::make_heap(v);

    // probably mess up the heap
    v.push_back(2);
    v.push_back(6);

    out("v after make_heap and push_back: \n");
    draw_bin_tree(v.begin(), v.end());

    out("the max-heap prefix of v: \n");
    const auto heap_end = std::ranges::is_heap_until(v);
    draw_bin_tree(v.begin(), heap_end);
}

void draw_bin_tree(auto first, auto last)
{
    auto bails = [](int n, int w) {
        auto b = [](int w) { out("┌"), out("─", w), out("┴"), out("─", w), out("┐"); };
        n /= 2;
        if (!n) return;
        for (out(' ', w); n-- > 0; ) b(w), out(' ', w + w + 1);
        out('\n');
    };
    auto data = [](int n, int w, auto& first, auto last) {
        for(out(' ', w); n-- > 0 && first != last; ++first)
            out(*first), out(' ', w + w + 1);
        out('\n');
    };
    auto tier = [&](int t, int m, auto& first, auto last) {
        const int n {1 << t};
        const int w {(1 << (m - t - 1)) - 1};
        bails(n, w), data(n, w, first, last);
    };
    const auto size {std::ranges::distance(first, last)};
    const int m {static_cast<int>(std::ceil(std::log2(1 + size)))};
    for (int i{}; i != m; ++i) { tier(i, m, first, last); }
}

输出：

v after make_heap and push_back:
       9
   ┌───┴───┐
   5       4
 ┌─┴─┐   ┌─┴─┐
 1   1   3   2
┌┴┐ ┌┴┐ ┌┴┐ ┌┴┐
6
the max-heap prefix of v:
   9
 ┌─┴─┐
 5   4
┌┴┐ ┌┴┐
1 1 3 2

参阅

ranges::is_heap (C++20) | 检查给定范围是否为最大堆 (niebloid)
ranges::make_heap (C++20) | 从一个元素范围创建出一个最大堆 (niebloid)
ranges::push_heap (C++20) | 将一个元素加入到一个最大堆 (niebloid)
ranges::pop_heap (C++20) | 从最大堆中移除最大元素 (niebloid)
ranges::sort_heap (C++20) | 将一个最大堆变成一个按升序排序的元素范围 (niebloid)
is_heap_until (C++11) | 查找能成为最大堆的最大子范围 (函数模板)


std::ranges::is_partitioned

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity,

std::indirect_unary_predicate<std::projected<I, Proj>> Pred >

constexpr bool is_partitioned( I first, S last, Pred pred, Proj proj = {} );
 (1) (C++20 起)
template< ranges::input_range R, class Proj = std::identity,

std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >

constexpr bool is_partitioned( R&& r, Pred pred, Proj proj = {} );
 (2) (C++20 起)
1) 若范围 [first, last) 中在投影后满足谓词 p 的所有元素都在不满足的所有元素之前出现则返回 true 。若范围 [first, last) 为空则亦返回 true 。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 代表待检验的元素范围的迭代器-哨位对
r | - | 待检验的元素范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到谓词的投影

返回值

若 [first, last) 为空或为 p 所划分则为 true 。否则为 false 。

复杂度

至多应用 ranges::distance(first, last) 次 pred 和 proj 。

可能的实现

struct is_partitioned_fn {
  template<std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
           std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
  constexpr bool operator()(I first, S last, Pred pred, Proj proj = {}) const
  {
    for (; first != last; ++first) {
      if (!std::invoke(pred, std::invoke(proj, *first))) {
        break;
      }
    }

    for (; first != last; ++first) {
      if (std::invoke(pred, std::invoke(proj, *first))) {
        return false;
      }
    }

    return true;
  }

  template<ranges::input_range R, class Proj = std::identity,
           std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred>
  constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const
  {
    return (*this)(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
  }
};

inline constexpr auto is_partitioned = is_partitioned_fn();

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <utility>

int main()
{
    std::array<int, 9> v;

    auto is_even = [](int i){ return i % 2 == 0; };
    auto print = [&](bool o) {
        for (int x : v) std::cout << x << ' ';
        std::cout << (o ? "=> " : "=> not ") << "partitioned\n";
    };

    std::iota(v.begin(), v.end(), 1);
    print(std::ranges::is_partitioned(v, is_even));

    std::ranges::partition(v, is_even);
    print(std::ranges::is_partitioned(std::as_const(v), is_even));

    std::ranges::reverse(v);
    print(std::ranges::is_partitioned(v.cbegin(), v.cend(), is_even));
    print(std::ranges::is_partitioned(v.crbegin(), v.crend(), is_even));
}

输出：

1 2 3 4 5 6 7 8 9 => not partitioned
2 4 6 8 5 3 7 1 9 => partitioned
9 1 7 3 5 8 6 4 2 => not partitioned
9 1 7 3 5 8 6 4 2 => partitioned

参阅

ranges::partition (C++20) | 将范围中的元素分为二组 (niebloid)
ranges::partition_point (C++20) | 定位已划分范围的划分点 (niebloid)
is_partitioned (C++11) | 判断范围是否已按给定的谓词划分 (函数模板)


std::ranges::is_permutation

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template<std::forward_iterator I1, std::sentinel_for<I1> S1,

std::forward_iterator I2, std::sentinel_for<I2> S2,
class Proj1 = std::identity, class Proj2 = std::identity,
std::indirect_equivalence_relation<std::projected<I1, Proj1>,
std::projected<I2, Proj2>>
Pred = ranges::equal_to>
constexpr bool is_permutation(I1 first1, S1 last1, I2 first2, S2 last2,

Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
 (1) (C++20 起)
template<ranges::forward_range R1, ranges::forward_range R2,

class Proj1 = std::identity, class Proj2 = std::identity,
std::indirect_equivalence_relation<std::projected<ranges::iterator_t<R1>, Proj1>,
std::projected<ranges::iterator_t<R2>, Proj2>>
Pred = ranges::equal_to>
constexpr bool is_permutation(R1&& r1, R2&& r2, Pred pred = {},

Proj1 proj1 = {}, Proj2 proj2 = {});
 (2) (C++20 起)
1) 若存在范围 [first1, last1) 中的元素的排列使得该范围等于 [first2, last2) （在应用对应的投影 Proj1 和 Proj2 后，并以 Pred 为比较器）则返回 true 。否则返回 false 。
2) 同 (1) ，但以 r1 为第一源范围并以 r2 为第二源范围，如同以 ranges::begin(r1) 为 first1 ，以 ranges::end(r1) 为 last1 ，以 ranges::begin(r2) 为 first2 ，并以 ranges::end(r2) 为 last2 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 第一元素范围
first2, last2 | - | 第二元素范围
r1 | - | 第一元素范围
r2 | - | 第二元素范围
pred | - | 应用到投影后元素的谓词
proj1 | - | 应用到第一范围中元素的投影
proj2 | - | 应用到第一范围中元素的投影

返回值

若范围 [first1, last1) 为 [first2, last2) 的重排列则为 true 。

复杂度

至多应用 \(\scriptsize \mathcal{O}(N^2)\)O(N2) 次谓词和每个投影，或若序列已经相等则准确应用 \(\scriptsize N\)N 次，其中 \(\scriptsize N\)N 为 ranges::distance(first1, last1) 。 然而若 ranges::distance(first1, last1) != ranges::distance(first2, last2) ，则不应用谓词和投影。

注解

排列关系是等价关系。

ranges::is_permutation 能用于按照其名称地测试重排算法（例如排序、打乱、划分）的正确性。若 x 为原范围而 y 是重排后范围则 std::is_permutation (x, y) == true 表示 y 由可能位于其他位置的“相同”元素组成。

可能的实现

struct is_permutation_fn
{
  template<std::forward_iterator I1, std::sentinel_for<I1> S1,
           std::forward_iterator I2, std::sentinel_for<I2> S2,
           class Proj1 = std::identity, class Proj2 = std::identity,
           std::indirect_equivalence_relation<std::projected<I1, Proj1>,
                                              std::projected<I2, Proj2>>
                                                  Pred = ranges::equal_to>
  constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2,
                            Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const {
    // 跳过公共前缀
    auto ret = std::ranges::mismatch(first1, last1, first2, last2,
                                     std::ref(pred), std::ref(proj1), std::ref(proj2));
    first1 = ret.in1, first2 = ret.in2;

    // 在剩余部分迭代，统计每个来自 [first1, last1) 中的元素在 [first2, last2) 中出现多少次
    for (auto i{ first1 }; i != last1; ++i) {
        const auto i_proj{ std::invoke(proj1, *i) };
        auto i_cmp = [&]<typename T>(T&& t) {
            return std::invoke(pred, i_proj, std::forward<T>(t));
        };

        if (i != ranges::find_if(first1, i, i_cmp, proj1))
          continue; // 已检查过此 *i

        if (const auto m{ ranges::count_if(first2, last2, i_cmp, proj2) };
            m == 0 or m != ranges::count_if(i, last1, i_cmp, proj1))
            return false;
    }
    return true;
  }

  template<ranges::forward_range R1, ranges::forward_range R2,
       class Proj1 = std::identity, class Proj2 = std::identity,
       std::indirect_equivalence_relation<std::projected<ranges::iterator_t<R1>, Proj1>,
                                          std::projected<ranges::iterator_t<R2>, Proj2>>
                                              Pred = ranges::equal_to>
          constexpr bool operator()(R1&& r1, R2&& r2, Pred pred = {},
                                    Proj1 proj1 = {}, Proj2 proj2 = {}) const {
    return (*this)(ranges::begin(r1), ranges::end(r1),
                   ranges::begin(r2), ranges::end(r2),
                   std::move(pred), std::move(proj1), std::move(proj2));
  }
};

inline constexpr is_permutation_fn is_permutation{};

示例

#include <algorithm>
#include <array>
#include <cmath>
#include <iostream>
#include <ranges>

auto& operator<< (auto& os, std::ranges::forward_range auto const& v) {
    os << "{ ";
    for (auto const& e : v) os << e << ' ';
    return os << "}";
}

int main()
{
    static constexpr auto r1 = {1,2,3,4,5};
    static constexpr auto r2 = {3,5,4,1,2};
    static constexpr auto r3 = {3,5,4,1,1};

    static_assert(
        std::ranges::is_permutation(r1, r1) &&
        std::ranges::is_permutation(r1, r2) &&
        std::ranges::is_permutation(r2, r1) &&
        std::ranges::is_permutation(r1.begin(), r1.end(), r2.begin(), r2.end())
        );

    std::cout
        << std::boolalpha
        << "is_permutation( " << r1 << ", " << r2 << " ): "
        << std::ranges::is_permutation(r1, r2) << '\n'
        << "is_permutation( " << r1 << ", " << r3 << " ): "
        << std::ranges::is_permutation(r1, r3) << '\n'

        << "is_permutation with custom predicate and projections: "
        << std::ranges::is_permutation(
            std::array{ -14, -11, -13, -15, -12 },  // 第一范围
            std::array{ 'F', 'E', 'C', 'B', 'D' },  // 第二范围
            [](int x, int y) { return abs(x) == abs(y); }, // 谓词
            [](int x) { return x + 10; },           // 第一范围的投影
            [](char y) { return int(y - 'A'); })    // 第二范围的投影
        << '\n';
}

输出：

is_permutation( { 1 2 3 4 5 }, { 3 5 4 1 2 } ): true
is_permutation( { 1 2 3 4 5 }, { 3 5 4 1 1 } ): false
is_permutation with custom predicate and projections: true

参阅

ranges::next_permutation (C++20) | 产生某个元素范围的按字典序下一个较大的排列 (niebloid)
ranges::prev_permutation (C++20) | 产生某个元素范围的按字典序下一个较小的排列 (niebloid)
is_permutation (C++11) | 判断一个序列是否为另一个序列的排列 (函数模板)
next_permutation | 产生某个元素范围的按字典顺序的下一个较大的排列 (函数模板)
prev_permutation | 产生某个元素范围的按字典顺序的下一个较小的排列 (函数模板)
equivalence_relation (C++20) | 指定 relation 施加等价关系 (概念)


std::ranges::is_sorted

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity,

std::indirect_strict_weak_order<std::projected<I, Proj>> Comp = ranges::less >

constexpr bool is_sorted( I first, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::forward_range R, class Proj = std::identity,

std::indirect_strict_weak_order<
std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less >

constexpr bool is_sorted( R&& r, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)

检查范围 [first, last) 中的元素是否按不降序排序。

若对于任何指向序列的迭代器 it 与任何使得 it + n 为指向序列元素的合法迭代器的非负整数 n ， std::invoke (comp, std::invoke (proj, *(it + n)), std::invoke (proj, *it)) 求值为 false ，则称序列相对于比较器 comp 已排序。

1) 用给定的二元比较函数 comp 比较元素。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 定义要检查是否已排序的范围的迭代器-哨位对
r | - | 要检查是否已排序的范围
comp | - | 应用到投影后元素的比较函数
proj | - | 应用到元素的投影

返回值

若投影后元素已按照 comp 排序则为 true 。

复杂度

与 first 和 last 间的距离成线性。

可能的实现

struct is_sorted_fn {
  template<std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
           std::indirect_strict_weak_order<std::projected<I, Proj>> Comp = ranges::less>
  constexpr bool operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
  {
      return ranges::is_sorted_until(first, last, comp, proj) == last;
  }

  template<ranges::forward_range R, class Proj = std::identity,
           std::indirect_strict_weak_order<
               std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less>
  constexpr bool operator()(R&& r, Comp comp = {}, Proj proj = {}) const
  {
      return (*this)(ranges::begin(r), ranges::end(r),
                     std::ref(comp), std::ref(proj));
  }
};

inline constexpr is_sorted_fn is_sorted;

注解

ranges::is_sorted 对空范围及长度为一的范围返回 true 。

示例

#include <algorithm>
#include <iostream>
#include <iterator>

int main()
{
    std::array<int, 5> digits = {3, 1, 4, 1, 5};

    ranges::copy(digits, std::ostream_iterator<int>(std::cout, " "));
    std::cout << ": is_sorted: " << std::boolalpha
              << ranges::is_sorted(digits) << '\n';

    ranges::sort(digits);

    ranges::copy(digits, std::ostream_iterator<int>(std::cout, " "));
    std::cout << ": is_sorted: "
              << ranges::is_sorted(ranges::begin(digits), ranges::end(digits)) << '\n';
}

输出：

3 1 4 1 5 : is_sorted: false
1 1 3 4 5 : is_sorted: true

参阅

ranges::is_sorted_until (C++20) | 寻找最大的已排序子范围 (niebloid)
is_sorted (C++11) | 检查范围是否已按升序排列 (函数模板)


std::ranges::is_sorted_until

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity,

std::indirect_strict_weak_order<std::projected<I, Proj>> Comp = ranges::less >

constexpr I is_sorted_until( I first, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< std::forward_range R, class Proj = std::identity,

std::indirect_strict_weak_order<
std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less >
constexpr ranges::borrowed_iterator_t<R>

is_sorted_until( R&& r, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)

检验范围 [first, last) 并寻找始于 first 且元素按不降序排序的最大范围。

若对于任何指向序列的迭代器 it 与任何使得 it + n 为指向序列元素的合法迭代器的非负整数 n ， std::invoke (comp, std::invoke (proj, *(it + n)), std::invoke (proj, *it)) 求值为 false ，则称序列相对于比较器 comp 已排序。

1) 用给定的二元比较函数 comp 比较元素。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 定义要寻找其已排序上界的范围的迭代器-哨位对
r | - | 要寻找其已排序上界的范围
comp | - | 应用到投影后元素的比较函数
proj | - | 应用到元素的投影

返回值

始于 first ，且元素按不降序排序的最大范围的上界。即使得范围 [first, it) 已排序的最末迭代器 it 。

复杂度

与 first 和 last 间的距离成线性。

可能的实现

struct is_sorted_until_fn {
  template<std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
           std::indirect_strict_weak_order<std::projected<I, Proj>> Comp = ranges::less>
  constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
  {
      if (first == last) {
          return first;
      }

      auto next = first;
      while (++next != last) {
          if (std::invoke(comp, std::invoke(proj, *next), std::invoke(proj, *first))) {
              return next;
          }
          first = next;
      }

      return first;
  }

  template< ranges::forward_range R, class Proj = std::identity,
          std::indirect_strict_weak_order<
              std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less >
  constexpr ranges::borrowed_iterator_t<R>
  operator()( R&& r, Comp comp = {}, Proj proj = {} ) const
  {
      return (*this)(ranges::begin(r), ranges::end(r),
                     std::ref(comp), std::ref(proj));
  }
};

inline constexpr is_sorted_until_fn is_sorted_until;

注解

ranges::is_sorted_until 对空范围和长度为 1 的范围返回等于 last 的迭代器。

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 g{rd()};
    std::array nums {3, 1, 4, 1, 5, 9};

    constexpr int min_sorted_size = 4;
    int sorted_size = 0;
    do {
        std::ranges::shuffle(nums, g);
        const auto sorted_end = std::ranges::is_sorted_until(nums);
        sorted_size = std::ranges::distance(nums.begin(), sorted_end);

        std::ranges::copy(nums, std::ostream_iterator<int>(std::cout, " "));
        std::cout << " : " << sorted_size << " leading sorted element(s)\n";
    } while (sorted_size < min_sorted_size);
}

可能的输出：

4 1 9 5 1 3  : 1 leading sorted element(s)
4 5 9 3 1 1  : 3 leading sorted element(s)
9 3 1 4 5 1  : 1 leading sorted element(s)
1 3 5 4 1 9  : 3 leading sorted element(s)
5 9 1 1 3 4  : 2 leading sorted element(s)
4 9 1 5 1 3  : 2 leading sorted element(s)
1 1 4 9 5 3  : 4 leading sorted element(s)

参阅

ranges::is_sorted (C++20) | 检查范围是否以升序排序 (niebloid)
is_sorted_until (C++11) | 找出最大的已排序子范围 (函数模板)


std::ranges::lexicographical_compare

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I1, std::sentinel_for<I1> S1,

std::input_iterator I2, std::sentinel_for<I2> S2,
class Proj1 = std::identity, class Proj2 = std::identity,
std::indirect_strict_weak_order<
std::projected<I1, Proj1>,
std::projected<I2, Proj2>> Comp = ranges::less >
constexpr bool lexicographical_compare( I1 first1, S1 last1, I2 first2, S2 last2,

Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {} );
 (1) (C++20 起)
template< ranges::input_range R1, ranges::input_range R2,

class Proj1 = std::identity, class Proj2 = std::identity,
std::indirect_strict_weak_order<
std::projected<ranges::iterator_t<R1>, Proj1>,
std::projected<ranges::iterator_t<R2>, Proj2>> Comp = ranges::less >
constexpr bool lexicographical_compare( R1&& r1, R2&& r2, Comp comp = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (2) (C++20 起)

检查第一范围 [first1, last1) 是否按字典序小于第二范围 [first2, last2) 。

1) 用给定的二元比较函数 comp 比较元素。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

字典序比较是拥有下列属性的操作：

  • 按元素逐个比较二个范围。
  • 首个不匹配元素定义范围按字典序小于或大于另一个。
  • 若一个范围是另一个的前缀，则较短的范围按字典序小于另一个。
  • 若二个范围拥有等价的元素与相同长度，则范围按字典序相等。
  • 空范围按字典序小于任何非空范围。
  • 二个空范围按字典序相等。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 要检验的第一元素范围
r1 | - | 要检验的第一元素范围
first2, last2 | - | 要检验的第二元素范围
r2 | - | 要检验的第二元素范围
comp | - | 应用到投影后元素的比较函数
proj1 | - | 应用到第一元素范围的投影
proj2 | - | 应用到第二元素范围的投影

返回值

若第一范围按字典序小于第二范围则为 true 。

复杂度

至多应用 2·min(N1, N2) 次比较与对应的投影，其中 N1 = ranges::distance(first1, last1) 而 N2 = ranges::distance(first2, last2) 。

可能的实现

struct lexicographical_compare_fn {
  template<std::input_iterator I1, std::sentinel_for<I1> S1,
           std::input_iterator I2, std::sentinel_for<I2> S2,
           class Proj1 = std::identity, class Proj2 = std::identity,
           std::indirect_strict_weak_order<
              std::projected<I1, Proj1>,
              std::projected<I2, Proj2>> Comp = ranges::less>
  constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2,
                            Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
  {
      for ( ; (first1 != last1) && (first2 != last2); ++first1, (void) ++first2 ) {
          if (std::invoke(comp, std::invoke(proj1, *first1), std::invoke(proj2, *first2))) {
              return true;
          }
          if (std::invoke(comp, std::invoke(proj2, *first2), std::invoke(proj1, *first1))) {
              return false;
          }
      }
      return (first1 == last1) && (first2 != last2);
  }

  template< ranges::input_range R1, ranges::input_range R2,
            class Proj1 = std::identity, class Proj2 = std::identity,
            std::indirect_strict_weak_order<
               std::projected<ranges::iterator_t<R1>, Proj1>,
               std::projected<ranges::iterator_t<R2>, Proj2>> Comp = ranges::less >
  constexpr bool operator()(R1&& r1, R2&& r2, Comp comp = {},
                            Proj1 proj1 = {}, Proj2 proj2 = {}) const
  {
      return (*this)(ranges::begin(r1), ranges::end(r1),
                     ranges::begin(r2), ranges::end(r2),
                     std::ref(comp), std::ref(proj1), std::ref(proj2));
  }
};

inline constexpr lexicographical_compare_fn lexicographical_compare;

示例

#include <algorithm>
#include <iterator>
#include <iostream>
#include <vector>
#include <random>

int main()
{
    std::vector<char> v1 {'a', 'b', 'c', 'd'};
    std::vector<char> v2 {'a', 'b', 'c', 'd'};

    namespace ranges = std::ranges;

    std::mt19937 g{std::random_device{}()};
    while (!ranges::lexicographical_compare(v1, v2)) {
        ranges::copy(v1, std::ostream_iterator<char>(std::cout, " "));
        std::cout << ">= ";
        ranges::copy(v2, std::ostream_iterator<char>(std::cout, " "));
        std::cout << '\n';

        ranges::shuffle(v1, g);
        ranges::shuffle(v2, g);
    }

    ranges::copy(v1, std::ostream_iterator<char>(std::cout, " "));
    std::cout << "< ";
    ranges::copy(v2, std::ostream_iterator<char>(std::cout, " "));
    std::cout << '\n';
}

可能的输出：

a b c d >= a b c d
d a b c >= c b d a
b d a c >= a d c b
a c d b < c d a b

参阅

ranges::equal (C++20) | 确定两个元素集合是否是相同的 (niebloid)
lexicographical_compare | 当一个范围按字典顺序小于另一个范围时，返回 true (函数模板)


std::ranges::lower_bound

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I, std::sentinel_for<I> S,

class T, class Proj = std::identity,
std::indirect_strict_weak_order<
const T*,
std::projected<I, Proj>> Comp = ranges::less >
constexpr I

lower_bound( I first, S last, const T& value, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::forward_range R, class T, class Proj = std::identity,

std::indirect_strict_weak_order<
const T*,
std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less >
constexpr ranges::borrowed_iterator_t<R>

lower_bound( R&& r, const T& value, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)
1) 返回指向范围 [first, last) 中首个不小于（即大于或等于） value 的元素的迭代器，或若找不到这种元素返回 last 。 范围 [first, last) 必须已按照表达式 comp(element, value) 划分，即所有该表达式对其为 true 的元素必须前趋所有该表达式对其为 false 的元素。完全排序的范围符合此判别标准。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 定义要检验的部分有序范围的迭代器-哨位对
r | - | 要检验的部分有序范围
value | - | 要与元素比较的值
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

指向首个不小于 value 的元素的迭代器，或若找不到这种元素则为 last 。

复杂度

比较和应用投影的次数与 first 和 last 之间的距离成对数（至多比较和应用投影 log
2(last - first) + O(1) 次）。然而，对于不实现 random_access_iterator 的迭代器，迭代器自增次数为线性。

可能的实现

struct lower_bound_fn {
  template<std::forward_iterator I, std::sentinel_for<I> S,
           class T, class Proj = std::identity,
           std::indirect_strict_weak_order<
               const T*,
               std::projected<I, Proj>> Comp = ranges::less>
  constexpr I operator()( I first, S last, const T& value,
                          Comp comp = {}, Proj proj = {} ) const
  {
      I it;
      std::iter_difference_t<I> count, step;
      count = std::ranges::distance(first, last);

      while (count > 0) {
          it = first;
          step = count / 2;
          ranges::advance(it, step, last);
          if (comp(*it, value)) {
              first = ++it;
              count -= step + 1;
          }
          else {
              count = step;
          }
      }
      return first;
  }

  template<ranges::forward_range R, class T, class Proj = std::identity,
           std::indirect_strict_weak_order<
               const T*,
               std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less>
  constexpr ranges::borrowed_iterator_t<R>
  operator()( R&& r, const T& value, Comp comp = {}, Proj proj = {} ) const
  {
    return (*this)(ranges::begin(r), ranges::end(r), value,
                   std::ref(comp), std::ref(proj));
  }
};

inline constexpr lower_bound_fn lower_bound;

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

namespace ranges = std::ranges;

template<std::forward_iterator I, std::sentinel_for<I> S, class T,
         class Proj = std::identity,
         std::indirect_strict_weak_order<
               const T*,
               std::projected<I, Proj>> Comp = ranges::less>
I binary_find(I first, S last, const T& value, Comp comp = {}, Proj proj = {})
{
    first = ranges::lower_bound(first, last, value, comp, proj);
    return first != last && !comp(value, *first) ? first : last;
}

int main()
{
    std::vector<int> data = { 1, 1, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6 };

    auto lower = ranges::lower_bound(data, 4);
    auto upper = ranges::upper_bound(data, 4);

    ranges::copy(lower, upper, std::ostream_iterator<int>(std::cout, " "));

    std::cout << '\n';

    // 经典二分搜索，仅若存在才返回值

    data = { 1, 2, 4, 6, 9, 10 };

    auto it = binary_find(data.cbegin(), data.cend(), 4); //< 选择 '5' 将返回 end()

    if(it != data.cend())
      std::cout << *it << " found at index "<< ranges::distance(data.cbegin(), it);

    return 0;
}

输出：

4 4 4
4 found at index 2

参阅

ranges::equal_ranges (C++20) | 返回匹配特定值的元素范围 (niebloid)
ranges::partition (C++20) | 将范围中的元素分为二组 (niebloid)
ranges::partition_point (C++20) | 定位已划分范围的划分点 (niebloid)
ranges::upper_bound (C++20) | 返回指向首个大于某值的元素的迭代器 (niebloid)
lower_bound | 返回指向第一个不小于给定值的元素的迭代器 (函数模板)


std::ranges::make_heap

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::random_access_iterator I, std::sentinel_for<I> S,

class Comp = ranges::less, class Proj = std::identity >
requires std::sortable<I, Comp, Proj>
constexpr I

make_heap( I first, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::random_access_range R, class Comp = ranges::less,

class Proj = std::identity >
requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
constexpr ranges::borrowed_iterator_t<R>

make_heap( R&& r, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)

在范围 [first, last) 中构造最大堆。

1) 用二元比较函数 comp 与投影对象 proj 比较元素。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要作出堆的元素范围
r | - | 要作出堆的元素范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

等于 last 的迭代器。

复杂度

给定 N = ranges::distance(first, last) ，至多比较 \(\scriptsize 3\cdot N\)3•N 次，投影 \(\scriptsize 6\cdot N\)6•N 次。

注解

最大堆是按照比较器 comp 与投影 proj 排列的元素范围 [f, l) ，拥有下列属性：

  • 令 N == l - f ，对于所有 0 < i < N ， p == f[(i - 1) / 2] 和 q == f[i] ，表达式 std::invoke (comp, std::invoke (proj, p), std::invoke (proj, q)) 求值为 false 。
  • 能用 ranges::push_heap() 在 \(\scriptsize \mathcal{O}(\log N)\)𝓞(log N) 时间内添加新元素。
  • 能用 ranges::pop_heap() 在 \(\scriptsize \mathcal{O}(\log N)\)𝓞(log N) 时间内移除首元素。

示例

#include <algorithm>
#include <vector>
#include <cmath>
#include <functional>
#include <iostream>

void draw_heap(auto const& v);
void out(const auto& what, int n = 1) { while (n-- > 0) std::cout << what; }
void print(auto rem, auto const& v) {
    out(rem);
    for (auto e : v) { out(e), out(' '); }
    out('\n');
}

int main()
{
    std::vector h {1, 6, 1, 8, 0, 3, 3, 9, 8, 8, 7, 4, 9, 8, 9};
    print("source: ", h);

    std::ranges::make_heap(h);
    print("\n" "max-heap: ", h);
    draw_heap(h);

    std::ranges::make_heap(h, std::greater{});
    print("\n" "min-heap: ", h);
    draw_heap(h);
}

void draw_heap(auto const& v)
{
    auto bails = [](int n, int w) {
        auto b = [](int w) { out("┌"), out("─", w), out("┴"), out("─", w), out("┐"); };
        if (!(n /= 2)) return;
        for (out(' ', w); n-- > 0; ) b(w), out(' ', w + w + 1);
        out('\n');
    };
    auto data = [](int n, int w, auto& first, auto last) {
        for(out(' ', w); n-- > 0 && first != last; ++first)
            out(*first), out(' ', w + w + 1);
        out('\n');
    };
    auto tier = [&](int t, int m, auto& first, auto last) {
        const int n {1 << t};
        const int w {(1 << (m - t - 1)) - 1};
        bails(n, w), data(n, w, first, last);
    };
    const int m {static_cast<int>(std::ceil(std::log2(1 + v.size())))};
    auto first {v.cbegin()};
    for (int i{}; i != m; ++i) { tier(i, m, first, v.cend()); }
}

输出：

source: 1 6 1 8 0 3 3 9 8 8 7 4 9 8 9

max-heap: 9 8 9 8 8 4 9 6 1 0 7 1 3 8 3
       9
   ┌───┴───┐
   8       9
 ┌─┴─┐   ┌─┴─┐
 8   8   4   9
┌┴┐ ┌┴┐ ┌┴┐ ┌┴┐
6 1 0 7 1 3 8 3

min-heap: 0 1 1 8 6 3 3 9 8 8 7 4 9 8 9
       0
   ┌───┴───┐
   1       1
 ┌─┴─┐   ┌─┴─┐
 8   6   3   3
┌┴┐ ┌┴┐ ┌┴┐ ┌┴┐
9 8 8 7 4 9 8 9

参阅

ranges::is_heap (C++20) | 检查给定范围是否为最大堆 (niebloid)
ranges::is_heap_until (C++20) | 寻找能成为最大堆的最大子范围 (niebloid)
ranges::push_heap (C++20) | 将一个元素加入到一个最大堆 (niebloid)
ranges::pop_heap (C++20) | 从最大堆中移除最大元素 (niebloid)
ranges::sort_heap (C++20) | 将一个最大堆变成一个按升序排序的元素范围 (niebloid)
make_heap | 从一个元素范围创建出一个最大堆 (函数模板)


std::ranges::max

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< class T, class Proj = std::identity,

std::indirect_strict_weak_order<
std::projected<const T*, Proj>> Comp = ranges::less >

constexpr const T& max( const T& a, const T& b, Comp comp = {}, Proj proj = {} );
 (C++20 起)
template< class T, class Proj = std::identity,

std::indirect_strict_weak_order<
std::projected<const T*, Proj>> Comp = ranges::less >

constexpr const T& max( std::initializer_list <T> r, Comp comp = {}, Proj proj = {} );
 (C++20 起)
template< ranges::input_range R, class Proj = std::identity,

std::indirect_strict_weak_order<
std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less >
requires std::indirectly_copyable_storable<ranges::iterator_t<R>, ranges::range_value_t<R>*>

constexpr ranges::range_value_t<R> max( R&& r, Comp comp = {}, Proj proj = {} );
 (C++20 起)

返回给定的被投影值的较大者。

1) 返回 a 与 b 的较大者。
2) 返回 initializer_list r 中的首个最大值。
3) 返回范围 r 中的首个最大值。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

a, b | - | 要比较的值
r | - | 要比较的值的范围
comp | - | 应用到投影后元素的比较
proj | - | 应用到元素的投影

返回值

1) a 与 b 的较大值，按照其各自的被投影值。若它们等价则返回 a 。
2-3) r 中按照投影的最大值。若数个值等价于最大值，则返回最左者。若范围为空（由 ranges::distance(r) 确定）则行为未定义。

复杂度

1) 准确比较一次。
2-3) 准确比较 ranges::distance(r) - 1 次。

可能的实现

struct max_fn {
  template<class T, class Proj = std::identity,
           std::indirect_strict_weak_order<
               std::projected<const T*, Proj>> Comp = ranges::less>
  constexpr
  const T& operator()(const T& a, const T& b, Comp comp = {}, Proj proj = {}) const
  {
      return std::invoke(comp, std::invoke(proj, a), std::invoke(proj, b)) ? b : a;
  }

  template<class T, class Proj = std::identity,
           std::indirect_strict_weak_order<
               std::projected<const T*, Proj>> Comp = ranges::less>
  constexpr
  const T& operator()(std::initializer_list<T> r, Comp comp = {}, Proj proj = {}) const
  {
    return *ranges::max_element(r, std::ref(comp), std::ref(proj));
  }

  template<ranges::input_range R, class Proj = std::identity,
           std::indirect_strict_weak_order<
                std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less>
  requires std::indirectly_copyable_storable<ranges::iterator_t<R>,
                                             ranges::range_value_t<R>*>
  constexpr
  ranges::range_value_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
  {
      return *ranges::max_element(r, std::ref(comp), std::ref(proj));
  }
};

inline constexpr max_fn max;

注解

若参数之一是临时量，而该参数被返回，则以引用捕获 std::ranges::max 的结果会产生一个悬垂引用：

int n = 1;
const int& r = std::ranges::max(n-1, n+1);
// r 悬垂

示例

#include <algorithm>
#include <iostream>
#include <string>

int main()
{
    namespace ranges = std::ranges;
    using namespace std::string_view_literals;
    std::cout << "larger of 1 and 9999: " << ranges::max(1, 9999) << '\n'
              << "larger of 'a', and 'b': '" << ranges::max('a', 'b') << "'\n"
              << "longest of \"foo\", \"bar\", and \"hello\": \""
              << ranges::max({ "foo"sv, "bar"sv, "hello"sv }, {},
                             &std::string_view::size) << "\"\n";
}

输出：

larger of 1 and 9999: 9999
larger of 'a', and 'b': 'b'
longest of "foo", "bar", and "hello": "hello"

参阅

ranges::min (C++20) | 返回给定值的较小者 (niebloid)
ranges::minmax (C++20) | 返回两个元素的较小和较大者 (niebloid)
ranges::max_element (C++20) | 返回范围中的最大元素 (niebloid)
ranges::clamp (C++20) | 在一对边界值间夹一个值 (niebloid)
max | 返回各给定值中的较大者 (函数模板)


std::ranges::max_element

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity,

std::indirect_strict_weak_order<std::projected<I, Proj>> Comp = ranges::less >

constexpr I max_element( I first, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::forward_range R, class Proj = std::identity,

std::indirect_strict_weak_order<
std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less >
constexpr ranges::borrowed_iterator_t<R>

max_element( R&& r, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)
1) 寻找范围 [first, last) 中的最大元素。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 代表待检验范围的迭代器-哨位对
r | - | 待检验的范围
comp | - | 应用到投影后元素的比较
proj | - | 应用到元素的投影

返回值

指向范围 [first, last) 中最大元素的迭代器。若范围中数个元素等价于最大元素，则返回指向首个这种元素的迭代器。若范围为空则返回 first 。

复杂度

准确比较 max(N-1,0) 次，其中 N = ranges::distance(first, last) 。

可能的实现

struct max_element_fn {
  template<std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
           std::indirect_strict_weak_order<std::projected<I, Proj>> Comp = ranges::less>
  constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
  {
    if (first == last) {
      return last;
    }

    auto largest = first;
    ++first;
    for (; first != last; ++first) {
        if (std::invoke(comp, std::invoke(proj, *largest), std::invoke(proj, *first))) {
            largest = first;
        }
    }
    return largest;
  }

  template<ranges::forward_range R, class Proj = std::identity,
           std::indirect_strict_weak_order<
               std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less>
  constexpr ranges::borrowed_iterator_t<R>
  operator()(R&& r, Comp comp = {}, Proj proj = {}) const
  {
    return (*this)(ranges::begin(r), ranges::end(r), std::ref(comp), std::ref(proj));
  }
};

inline constexpr max_element_fn max_element;

示例

#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>

static bool abs_compare(int a, int b)
{
    return (std::abs(a) < std::abs(b));
}

int main()
{
    std::vector<int> v{ 3, 1, -14, 1, 5, 9 };

    namespace ranges = std::ranges;
    auto result = ranges::max_element(v.begin(), v.end());
    std::cout << "max element at: " << ranges::distance(v.begin(), result) << '\n';

    result = ranges::max_element(v, abs_compare);
    std::cout << "max element (absolute) at: " << ranges::distance(v.begin(), result) << '\n';
}

输出：

max element at: 5
max element (absolute) at: 2

参阅

ranges::min_element (C++20) | 返回范围中的最小元素 (niebloid)
ranges::minmax_element (C++20) | 返回范围中的最小和最大元素 (niebloid)
ranges::max (C++20) | 返回给定值的较大者 (niebloid)
max_element | 返回范围内的最大元素 (函数模板)


std::ranges::merge, std::ranges::merge_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I1, std::sentinel_for<I1> S1,

std::input_iterator I2, std::sentinel_for<I2> S2,
std::weakly_incrementable O, class Comp = ranges::less,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::mergeable<I1, I2, O, Comp, Proj1, Proj2>
constexpr merge_result<I1, I2, O>
merge( I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (1) (C++20 起)
template< ranges::input_range R1, ranges::input_range R2,

std::weakly_incrementable O, class Comp = ranges::less,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::mergeable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
O, Comp, Proj1, Proj2>
constexpr merge_result<ranges::borrowed_iterator_t<R1>,
ranges::borrowed_iterator_t<R2>, O>
merge( R1&& r1, R2&& r2, O result, Comp comp = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (2) (C++20 起)
辅助类型
template<class I1, class I2, class O>
using merge_result = ranges::in_in_out_result<I1, I2, O>;
 (3) (C++20 起)

将两个已排序范围 [first1, last1) 和 [first2, last2) 归并为一个开始于 result 的已排序范围。

一个序列被称为关于 comp 已排序，如果对于任何指向该序列的迭代器 it 和任何非负整数 n ，令 it + n 为一个指向该序列中的对象的有效迭代器， std::invoke (comp, std::invoke (proj2, *(it + n)), std::invoke (proj1, *it))) 等价于 false 。

1) 用二元比较函数 comp 进行对象的比较。
2) 同 (1) ，但是以 r1 为第一个范围并以 r2 为第二个范围, 如同以 ranges::begin(r1) 为 first1 ，以 ranges::end(r1) 为 last1 ，以 ranges::begin(r2) 为 first2 ，并以 ranges::end(r2) 为 last2 。

若目标范围与任一输入范围重叠则行为未定义（输入范围可以彼此重叠）。

这个归并函数是 稳定的，意味着对于两个范围中的等价对象，来自第一个范围的对象(保持本身的排序状况) 将排在第二个范围当中的对象之前（保持其原先顺序）。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 第一已排序的输入范围
first2, last2 | - | 第二已排序的输入范围
result | - | 输出范围的起始
comp | - | 应用到投影后元素的比较器
proj1 | - | 应用到第一范围中元素的投影
proj2 | - | 应用到第二范围中元素的投影

返回值

{last1, last2, result_last}，其中 result_last 为被构造的范围末尾。

复杂度

最多 N−1 次比较和投影的应用，其中 N = ranges::distance(first1, last1) + ranges::distance(first2, last12)。

注解

此算法进行与 ranges::set_union 相似的任务。两者都使用两个已排序的范围产生一个包含两者的对象的已排序范围。两个算法的不同之处在于在两个输入范围当中的比较等价的值的处理方法（可以参考可小于比较 (LessThanComparable) 上的注解）。如果任何相等的值出现了 n 次于第一个范围而 m 次于第二个， ranges::merge 将会输出全部的 n+m 次出现，但是ranges::set_union 只会输出 max(n, m) 次。所以 ranges::merge 输出恰好 N 个数值而 ranges::set_union 会输出更少。

可能的实现

struct merge_fn {
    template< std::input_iterator I1, std::sentinel_for<I1> S1,
              std::input_iterator I2, std::sentinel_for<I2> S2,
              std::weakly_incrementable O, class Comp = ranges::less,
              class Proj1 = std::identity, class Proj2 = std::identity >
    requires std::mergeable<I1, I2, O, Comp, Proj1, Proj2>
    constexpr ranges::merge_result<I1, I2, O>
    operator()( I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {},
                Proj1 proj1 = {}, Proj2 proj2 = {} ) const {
        for (; !(first1 == last1 or first2 == last2); ++result) {
            if (std::invoke(comp, std::invoke(proj2, *first2), std::invoke(proj1, *first1)))
                *result = *first2, ++first2;
            else
                *result = *first1, ++first1;
        }
        auto ret1 {ranges::copy(std::move(first1), std::move(last1), std::move(result))};
        auto ret2 {ranges::copy(std::move(first2), std::move(last2), std::move(ret1.out))};
        return { std::move(ret1.in), std::move(ret2.in), std::move(ret2.out) };
    }

    template< ranges::input_range R1, ranges::input_range R2, std::weakly_incrementable O,
              class Comp = ranges::less,
              class Proj1 = std::identity, class Proj2 = std::identity >
    requires std::mergeable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
             O, Comp, Proj1, Proj2>
    constexpr ranges::merge_result<ranges::borrowed_iterator_t<R1>,
              ranges::borrowed_iterator_t<R2>, O>
    operator()( R1&& r1, R2&& r2, O result, Comp comp = {},
                Proj1 proj1 = {}, Proj2 proj2 = {} ) const {
        return (*this)(ranges::begin(r1), ranges::end(r1),
                       ranges::begin(r2), ranges::end(r2),
                       std::move(result), std::move(comp),
                       std::move(proj1), std::move(proj2));
    }
};

inline constexpr merge_fn merge{};

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

void print(const auto& in1, const auto& in2, auto first, auto last) {
    std::cout << "{ ";
    for (const auto& e : in1) { std::cout << e << ' '; }
    std::cout << "} +\n{ ";
    for (const auto& e : in2) { std::cout << e << ' '; }
    std::cout << "} =\n{ ";
    while (!(first == last)) { std::cout << *first++ << ' '; }
    std::cout << "}\n\n";
}

int main()
{
    std::vector<int> in1, in2, out;

    in1 = {1, 2, 3, 4, 5};
    in2 = {      3, 4, 5, 6, 7};
    out.resize(in1.size() + in2.size());
    const auto ret = std::ranges::merge(in1, in2, out.begin());
    print(in1, in2, out.begin(), ret.out);

    in1 = {1, 2, 3, 4, 5, 5, 5};
    in2 = {      3, 4, 5, 6, 7};
    out.clear();
    out.reserve(in1.size() + in2.size());
    std::ranges::merge(in1, in2, std::back_inserter(out));
    print(in1, in2, out.cbegin(), out.cend());
}

输出：

{ 1 2 3 4 5 } +
{ 3 4 5 6 7 } =
{ 1 2 3 3 4 4 5 5 6 7 }

{ 1 2 3 4 5 5 5 } +
{ 3 4 5 6 7 } =
{ 1 2 3 3 4 4 5 5 5 5 6 7 }

参阅

ranges::inplace_merge (C++20) | 在原位归并两个有序范围 (niebloid)
ranges::is_sorted (C++20) | 检查范围是否以升序排序 (niebloid)
ranges::set_union (C++20) | 计算两个集合的并集 (niebloid)
ranges::sort (C++20) | 将范围按升序排序 (niebloid)
ranges::stable_sort (C++20) | 将范围内的元素排序，同时保持相等的元素之间的顺序 (niebloid)
merge | 归并两个已排序的范围 (函数模板)


std::ranges::min

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< class T, class Proj = std::identity,

std::indirect_strict_weak_order<
std::projected<const T*, Proj>> Comp = ranges::less >

constexpr const T& min( const T& a, const T& b, Comp comp = {}, Proj proj = {} );
 (C++20 起)
template< class T, class Proj = std::identity,

std::indirect_strict_weak_order<
std::projected<const T*, Proj>> Comp = ranges::less >

constexpr const T& min( std::initializer_list <T> r, Comp comp = {}, Proj proj = {} );
 (C++20 起)
template< ranges::input_range R, class Proj = std::identity,

std::indirect_strict_weak_order<
std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less >
requires std::indirectly_copyable_storable<ranges::iterator_t<R>, ranges::range_value_t<R>*>

constexpr ranges::range_value_t<R> min( R&& r, Comp comp = {}, Proj proj = {} );
 (C++20 起)

返回给定的投影后值的较小者。

1) 返回 a 与 b 的较小者。
2) 返回 initializer_list r 的首个最小元素。
3) 返回范围 r 中国的首个最小值。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

a, b | - | 要比较的对象
r | - | 要比较的元素的范围
comp | - | 应用到投影后元素的比较
proj | - | 应用到元素的投影

返回值

1) a 与 b 的根据投影的较小者。若它们等价，则返回 a 。
2-3) r 中根据投影的最小元素。若有数个值等价于最小者，则返回最左的元素。若范围为空（由 ranges::distance(r) 确定）则行为未定义。

复杂度

1) 准确比较一次。
2-3) 准确比较 ranges::distance(r) - 1 次。

可能的实现

struct min_fn {
  template<class T, class Proj = std::identity,
           std::indirect_strict_weak_order<
               std::projected<const T*, Proj>> Comp = ranges::less>
  constexpr
  const T& operator()(const T& a, const T& b, Comp comp = {}, Proj proj = {}) const
  {
      return std::invoke(comp, std::invoke(proj, a), std::invoke(proj, b)) ? a : b;
  }

  template<class T, class Proj = std::identity,
           std::indirect_strict_weak_order<
               std::projected<const T*, Proj>> Comp = ranges::less>
  constexpr
  const T& operator()(std::initializer_list<T> r, Comp comp = {}, Proj proj = {}) const
  {
    return *ranges::min_element(r, std::ref(comp), std::ref(proj));
  }

  template<ranges::input_range R, class Proj = std::identity,
           std::indirect_strict_weak_order<
                std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less>
  requires std::indirectly_copyable_storable<ranges::iterator_t<R>,
                                             ranges::range_value_t<R>*>
  constexpr
  ranges::range_value_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const
  {
      return *ranges::min_element(r, std::ref(comp), std::ref(proj));
  }
};

inline constexpr min_fn min;

注解

若参数之一是临时量，而该参数被返回，则以引用捕获 std::ranges::min 的结果会产生一个悬垂引用：

int n = 1;
const int& r = std::ranges::min(n-1, n+1);
// r 悬垂

示例

#include <algorithm>
#include <iostream>
#include <string>

int main()
{
    namespace ranges = std::ranges;
    using namespace std::string_view_literals;
    std::cout << "smaller of 1 and 9999: " << ranges::min(1, 9999) << '\n'
              << "smaller of 'a', and 'b': " << ranges::min('a', 'b') << '\n'
              << "shortest of \"foo\", \"bar\", and \"hello\": " <<
                  ranges::min({ "foo"sv, "bar"sv, "hello"sv }, {}, &std::string_view::size) << '\n';
}

输出：

smaller of 1 and 9999: 1
smaller of 'a', and 'b': a
shortest of "foo", "bar", and "hello": foo

参阅

ranges::max (C++20) | 返回给定值的较大者 (niebloid)
ranges::minmax (C++20) | 返回两个元素的较小和较大者 (niebloid)
ranges::min_element (C++20) | 返回范围中的最小元素 (niebloid)
ranges::clamp (C++20) | 在一对边界值间夹一个值 (niebloid)
min | 返回各给定值中的较小者 (函数模板)


std::ranges::min_element

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity,

std::indirect_strict_weak_order<std::projected<I, Proj>> Comp = ranges::less >

constexpr I min_element( I first, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::forward_range R, class Proj = std::identity,

std::indirect_strict_weak_order<
std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less >
constexpr ranges::borrowed_iterator_t<R>

min_element( R&& r, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)
1) 寻找范围 [first, last) 中的最小元素。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 代表待检验范围的迭代器-哨位对
r | - | 待检验范围
comp | - | 应用到投影后元素的比较
proj | - | 应用到元素的投影

返回值

指向范围 [first, last) 中最小元素的迭代器。若数个元素等价于最小元素，则返回指向首个这种元素的迭代器。若范围为空则返回 first 。

复杂度

准确应用 max(N-1,0) 次比较，其中 N = ranges::distance(first, last) 。

可能的实现

struct min_element_fn {
  template<std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
           std::indirect_strict_weak_order<std::projected<I, Proj>> Comp = ranges::less>
  constexpr I operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
  {
    if (first == last) {
      return last;
    }

    auto smallest = first;
    ++first;
    for (; first != last; ++first) {
        if (!std::invoke(comp, std::invoke(proj, *smallest), std::invoke(proj, *first))) {
            smallest = first;
        }
    }
    return smallest;
  }

  template<ranges::forward_range R, class Proj = std::identity,
           std::indirect_strict_weak_order<
               std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less>
  constexpr ranges::borrowed_iterator_t<R>
  operator()(R&& r, Comp comp = {}, Proj proj = {}) const
  {
    return (*this)(ranges::begin(r), ranges::end(r), std::ref(comp), std::ref(proj));
  }
};

inline constexpr min_element_fn min_element;

示例

#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>

static bool abs_compare(int a, int b)
{
    return (std::abs(a) < std::abs(b));
}

int main()
{
    std::vector<int> v{ 3, 1, -14, 1, 5, 9 };

    namespace ranges = std::ranges;
    auto result = ranges::min_element(v.begin(), v.end());
    std::cout << "min element at: " << ranges::distance(v.begin(), result) << '\n';

    result = ranges::min_element(v, abs_compare);
    std::cout << "min element (absolute) at: " << ranges::distance(v.begin(), result) << '\n';
}

输出：

min element at: 2
min element (absolute) at: 1

参阅

ranges::max_element (C++20) | 返回范围中的最大元素 (niebloid)
ranges::minmax_element (C++20) | 返回范围中的最小和最大元素 (niebloid)
ranges::max (C++20) | 返回给定值的较大者 (niebloid)
min_element | 返回范围内的最小元素 (函数模板)


std::ranges::minmax, std::ranges::minmax_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< class T, class Proj = std::identity,

std::indirect_strict_weak_order<
std::projected<const T*, Proj>> Comp = ranges::less >
constexpr ranges::minmax_result<const T&>

minmax( const T& a, const T& b, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< class T, class Proj = std::identity,

std::indirect_strict_weak_order<
std::projected<const T*, Proj>> Comp = ranges::less >
constexpr ranges::minmax_result<const T&>

minmax( std::initializer_list <T> r, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)
template< ranges::input_range R, class Proj = std::identity,

std::indirect_strict_weak_order<
std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less >
requires std::indirectly_copyable_storable<ranges::iterator_t<R>, ranges::range_value_t<R>*>
constexpr ranges::minmax_result<ranges::range_value_t<R>>

minmax( R&& r, Comp comp = {}, Proj proj = {} );
 (3) (C++20 起)
辅助类型
template< class T >
using minmax_result = ranges::min_max_result<T>;
 (4) (C++20 起)

返回给定的投影后值的最小者与最大者。

1) 返回 a 与 b 的较小者与较大者的引用。
2) 返回 initializer_list r 中的最小与最大值。
3) 返回范围 r 中的最小与最大值。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

Parameters

a, b | - | 要比较的值
r | - | 要比较的非空的值范围
comp | - | 应用到投影后元素的值
proj | - | 应用到元素的投影

返回值

1) 若按照被投影值 b 小于 a ，则为 {b, a} ；否则返回 {a, b} 。
2-3) {s, l} ，其中 s 与 l 分别为 r 中分别按照其被投影值的的最小与最大值。若数个值等价于最小与最大，则返回最左的最小值与最右的最大值。若范围为空（由 ranges::distance(r) 确定）则行为未定义。

复杂度

1) 至多比较一次并投影二次。
2-3) 至多比较 3 / 2 * ranges::distance(r) 次并且应用两倍次数的投影。

可能的实现

struct minmax_fn {
  template<class T, class Proj = std::identity,
           std::indirect_strict_weak_order<
               std::projected<const T*, Proj>> Comp = ranges::less>
  constexpr ranges::minmax_result<const T&> operator()(
      const T& a, const T& b, Comp comp = {}, Proj proj = {}) const
  {
      if (std::invoke(comp, std::invoke(proj, b), std::invoke(proj, a))) {
          return {b, a};
      }

      return {a, b};
  }

  template<class T, class Proj = std::identity,
           std::indirect_strict_weak_order<
               std::projected<const T*, Proj>> Comp = ranges::less>
  constexpr ranges::minmax_result<const T&> operator()(
      std::initializer_list<T> r, Comp comp = {}, Proj proj = {}) const
  {
    auto result = ranges::minmax_element(r, std::ref(comp), std::ref(proj));
    return {std::move(*result.min), std::move(*result.max)};
  }

  template<ranges::input_range R, class Proj = std::identity,
           std::indirect_strict_weak_order<
                std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less>
  requires std::indirectly_copyable_storable<ranges::iterator_t<R>,
                                             ranges::range_value_t<R>*>
  constexpr ranges::minmax_result<ranges::range_value_t<R>> operator()(
      R&& r, Comp comp = {}, Proj proj = {}) const
  {
      auto result = ranges::minmax_element(r, std::ref(comp), std::ref(proj));
      return {std::move(*result.min), std::move(*result.max)};
  }
};

inline constexpr minmax_fn minmax;

注解

对于重载 (1,2) ，若参数之一为临时量，则返回的引用在含有对 minmax 的该调用的完全表达式结束后变为悬垂引用。

int n = 1;
auto p = ranges::minmax(n, n+1);
int m = p.first; // ok
int x = p.second; // 未定义行为

示例

#include <algorithm>
#include <iostream>
#include <random>
#include <vector>

int main()
{
    std::vector<int> v{3, 1, 4, 9, 1, 5, 9, 2, 6};
    std::mt19937_64 generator;
    namespace ranges = std::ranges;
    std::uniform_int_distribution<> distribution(0, ranges::distance(v));

    auto bounds = ranges::minmax(distribution(generator), distribution(generator));

    std::cout << "v[" << bounds.min << ":" << bounds.max << "]: ";
    for (int i = bounds.min; i < bounds.max; ++i) {
        std::cout << v[i] << ' ';
    }

    std::cout << '\n';

    auto [min, max] = ranges::minmax(v);
    std::cout << "smallest: " << min << '\n'
              << "largest: " << max << '\n';
}

可能的输出：

v[2:7]: 4 9 1 5 9
smallest: 1
largest: 9

参阅

ranges::min (C++20) | 返回给定值的较小者 (niebloid)
ranges::max (C++20) | 返回给定值的较大者 (niebloid)
ranges::minmax_element (C++20) | 返回范围中的最小和最大元素 (niebloid)
ranges::clamp (C++20) | 在一对边界值间夹一个值 (niebloid)
minmax (C++11) | 返回两个元素的较小和较大者 (函数模板)


std::ranges::minmax_element

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity,

std::indirect_strict_weak_order<std::projected<I, Proj>> Comp = ranges::less >
constexpr ranges::minmax_result<I>

minmax_element( I first, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::forward_range R, class Proj = std::identity,

std::indirect_strict_weak_order<
std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less >
constexpr ranges::minmax_result<ranges::borrowed_iterator_t<R>>

minmax_element( R&& r, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)
1) 寻找范围 [first, last) 中的最小与最大元素。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 指代待检验范围的迭代器-哨位对
r | - | 待检验范围
comp | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

由指向最小元素的迭代器作为第一元素，指向最大元素作为第二元素组成的对象。若范围为空则返回 {first, first} 。若数个元素等价于最小元素，则返回指向首个这种元素的迭代器。若数个元素等价于最大元素，则返回指向最后一个这种元素的迭代器。

复杂度

至多应用 max(floor((3/2)*(N−1)), 0) 次比较和两倍次数的投影，其中 N = ranges::distance(first, last) 。

可能的实现

struct minmax_element_fn {
  template<std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
           std::indirect_strict_weak_order<std::projected<I, Proj>> Comp = ranges::less>
  constexpr ranges::minmax_result<I> operator()(I first, S last, Comp comp = {}, Proj proj = {}) const
  {
    auto min = first, max = first;

    if (first == last || ++first == last) {
      return {min, max};
    }

    if (std::invoke(comp, std::invoke(proj, *first), std::invoke(proj, *min))) {
      min = first;
    } else {
      max = first;
    }

    while (++first != last) {
      auto i = first;
      if (++first == last) {
        if (std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, *min))) {
            min = i;
        }
        else if (!(std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, *max)))) {
            max = i;
        }
        break;
      } else {
        if (std::invoke(comp, std::invoke(proj, *first), std::invoke(proj, *i))) {
          if (std::invoke(comp, std::invoke(proj, *first), std::invoke(proj, *min))) {
            min = first;
          }
          if (!(std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, *max)))) {
            max = i;
          }
        } else {
          if (std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, *min))) {
            min = i;
          }
          if (!(std::invoke(comp, std::invoke(proj, *first), std::invoke(proj, *max)))) {
            max = first;
          }
        }
      }
    }
    return {min, max};
  }

  template<ranges::forward_range R, class Proj = std::identity,
           std::indirect_strict_weak_order<
               std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less>
  constexpr ranges::minmax_result<ranges::borrowed_iterator_t<R>>
  operator()(R&& r, Comp comp = {}, Proj proj = {}) const
  {
    return (*this)(ranges::begin(r), ranges::end(r), std::ref(comp), std::ref(proj));
  }
};

inline constexpr minmax_element_fn minmax_element;

示例

#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>

int main() {
    const auto v = { 3, 9, 1, 4, 2, 5, 9 };
    const auto [min, max] = std::ranges::minmax_element(v);

    std::cout << "min = " << *min << ", max = " << *max << '\n';
}

输出：

min = 1, max = 9

参阅

ranges::min_element (C++20) | 返回范围中的最小元素 (niebloid)
ranges::max_element (C++20) | 返回范围中的最大元素 (niebloid)
ranges::minmax (C++20) | 返回两个元素的较小和较大者 (niebloid)
minmax_element (C++11) | 返回范围内的最小元素和最大元素 (函数模板)


std::ranges::mismatch, std::ranges::mismatch_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I1, std::sentinel_for<I1> S1,

std::input_iterator I2, std::sentinel_for<I2> S2,
class Pred = ranges::equal_to,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr ranges::mismatch_result<I1, I2>
mismatch( I1 first1, S1 last1, I2 first2, S2 last2,

Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {} );
 (1) (C++20 起)
template< ranges::input_range R1, ranges::input_range R2,

class Pred = ranges::equal_to,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::indirectly_comparable<
ranges::iterator_t<R1>, ranges::iterator_t<R2>, Pred, Proj1, Proj2>
constexpr ranges::mismatch_result<ranges::borrowed_iterator_t<R1>,
ranges::borrowed_iterator_t<R2>>

mismatch( R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {} );
 (2) (C++20 起)
辅助类型
template<class I1, class I2>
using mismatch_result = ranges::in_in_result<I1, I2>;
 (3) (C++20 起)

返回首个投影后元素的不匹配对，它们来自两个范围：一个以 [first1, last1) 或 r1 定义而另一个以 [first2,last2) 或 r2 定义。

1) 用给定的二元谓词 p 比较元素。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 代表第一待比较元素范围的迭代器-哨位对
r1 | - | 第一待比较元素范围
first2, last2 | - | 代表第二待比较元素范围的迭代器-哨位对
r2 | - | 第二待比较元素范围
pred | - | 应用到投影后元素的谓词
proj1 | - | 应用到第一元素范围的投影
proj2 | - | 应用到第二元素范围的投影

返回值

拥有指向首二个不相等元素的迭代器的 ranges::mismatch_result 。

若比较抵达 last1 或 last2 ，无论何者先发生，都未找到不匹配，则对象保有尾迭代器与来自另一范围的对应迭代器。

复杂度

至多应用 min(last1 - first1, last2 - first2) 次谓词与对应的投影。

可能的实现

struct mismatch_fn {
  template<std::input_iterator I1, std::sentinel_for<I1> S1,
           std::input_iterator I2, std::sentinel_for<I2> S2,
           class Pred = ranges::equal_to,
           class Proj1 = std::identity, class Proj2 = std::identity>
    requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  constexpr std::mismatch_result<I1, I2>
  operator()(I1 first1, S1 last1, I2 first2, S2 last2,
             Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
  {
      for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
          if (!std::invoke(pred, std::invoke(proj1, *first1), std::invoke(proj2, *first2))) {
            break;
          }
      }
      return {first1, first2};
  }

  template<ranges::input_range R1, ranges::input_range R2,
           class Pred = ranges::equal_to,
           class Proj1 = std::identity, class Proj2 = std::identity >
  requires std::indirectly_comparable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
                                      Pred, Proj1, Proj2>
  constexpr
    ranges::mismatch_result<ranges::borrowed_iterator_t<R1>, ranges::borrowed_iterator_t<R2>>
  operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
  {
     return (*this)(ranges::begin(r1), ranges::end(r1),
                    ranges::begin(r2), ranges::end(r2),
                    std::ref(pred), std::ref(proj1), std::ref(proj2));
  }
};

inline constexpr mismatch_fn mismatch;

示例

此程序确定同时在给定字符串的首端与在末端逆序找到的最长子串（可能重叠）

#include <algorithm>
#include <cstddef>
#include <iostream>
#include <ranges>
#include <string_view>

constexpr std::string_view mirror_ends(const std::string_view in)
{
    const auto end = std::ranges::mismatch(in, in | std::views::reverse).in1;
    const std::size_t length = std::ranges::distance(in.begin(), end);
    return { in.cbegin(), length };
}

int main()
{
    std::cout << mirror_ends("abXYZba") << '\n'
              << mirror_ends("abca") << '\n'
              << mirror_ends("ABBA") << '\n'
              << mirror_ends("level") << '\n';

    using namespace std::literals::string_view_literals;

    static_assert("123"sv == mirror_ends("123!@#321"));
    static_assert("radar"sv == mirror_ends("radar"));
}

输出：

ab
a
ABBA
level

参阅

ranges::equal (C++20) | 确定两个元素集合是否是相同的 (niebloid)
ranges::findranges::find_ifranges::find_if_not (C++20)(C++20)(C++20) | 寻找首个满足特定判别标准的元素 (niebloid)
ranges::lexicographical_compare (C++20) | 当一个范围按字典顺序小于另一个范围时，返回 true (niebloid)
ranges::search (C++20) | 搜索一个元素范围 (niebloid)
mismatch | 寻找两个范围出现不同的首个位置 (函数模板)


std::ranges::move, std::ranges::move_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O >

requires std::indirectly_movable<I, O>
constexpr move_result<I, O>

move( I first, S last, O result );
 (1) (C++20 起)
template< ranges::input_range R, std::weakly_incrementable O >

requires std::indirectly_movable<ranges::iterator_t<R>, O>
constexpr move_result<ranges::borrowed_iterator_t<R>, O>

move( R&& r, O result );
 (2) (C++20 起)
辅助类型
template< class I, class O >
using move_result = ranges::in_out_result<I, O>;
 (3) (C++20 起)
1) 赋值 [first, last) 所定义的范围重点元素到始于 result 的另一范围。 若 result 在范围 [first, last) 内则行为未定义。此情况下可能可以用 ranges::move_backward 代替。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

被移动的范围的元素将仍然含有适当类型的合法值，但不必为与移动前相同的值。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first | - | 要移动的元素范围的起始
last | - | 要移动元素范围的末尾
r | - | 要移动的元素范围
result | - | 目标范围的起始

复杂度

{last, result + N} ，其中

1) N = ranges::distance(first, last) ；
2) N = ranges::distance(r) 。

复杂度

准确赋值 N 次。

注解

移动重叠的范围时， ranges::move 适合向左移动（目标范围的起始在源范围外），而 ranges::move_backward 适合向右移动（目标范围的末尾在源范围外）。

可能的实现

struct move_fn {
  template<std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O>
    requires std::indirectly_movable<I, O>
      constexpr ranges::move_result<I, O>
        operator()( I first, S last, O result ) const {
          for (; first != last; ++first, ++result)
            *result = ranges::iter_move(first);
          return {std::move(first), std::move(result)};
        }
  template<ranges::input_range R, std::weakly_incrementable O>
    requires std::indirectly_movable<ranges::iterator_t<R>, O>
      constexpr ranges::move_result<ranges::borrowed_iterator_t<R>, O>
        operator()( R&& r, O result ) const {
          return (*this)(ranges::begin(r), ranges::end(r), std::move(result));
        }
};

inline constexpr move_fn move{};

示例

以下代码从一个容器移动线程对象（它们自身不可复制）到另一容器。

#include <algorithm>
#include <iostream>
#include <vector>
#include <list>
#include <iterator>
#include <thread>
#include <chrono>
using namespace std::literals::chrono_literals;

void f(std::chrono::milliseconds n)
{
    std::this_thread::sleep_for(n);
    std::cout << "thread with n=" << n.count() << "ms ended" << std::endl;
}

int main()
{
    std::vector<std::jthread> v;
    v.emplace_back(f, 400ms);
    v.emplace_back(f, 600ms);
    v.emplace_back(f, 800ms);

    std::list<std::jthread> l;

    // std::ranges::copy() 不能编译，因为 std::jthread 不可复制
    std::ranges::move(v, std::back_inserter(l));
}

输出：

thread with n=400ms ended
thread with n=600ms ended
thread with n=800ms ended

参阅

ranges::move_backword (C++20) | 按从后往前的顺序移动某一范围的元素到新的位置 (niebloid)
ranges::copyranges::copy_if (C++20)(C++20) | 将某一范围的元素复制到一个新的位置 (niebloid)
ranges::copy_backward (C++20) | 按从后往前的顺序复制一个范围内的元素 (niebloid)
move (C++11) | 将某一范围的元素移动到一个新的位置 (函数模板)
move (C++11) | 获得右值引用 (函数模板)


std::ranges::move_backward, std::ranges::move_backward_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::bidirectional_iterator I1, std::sentinel_for<I1> S1,

std::bidirectional_iterator I2 >
requires std::indirectly_movable<I1, I2>
constexpr move_backward_result<I1, I2>

move_backward( I1 first, S1 last, I2 result );
 (1) (C++20 起)
template< ranges::bidirectional_range R, std::bidirectional_iterator I >

requires std::indirectly_movable<ranges::iterator_t<R>, I>
constexpr move_backward_result<ranges::borrowed_iterator_t<R>, I>

move_backward( R&& r, I result );
 (2) (C++20 起)
辅助类型
template< class I, class O >
using move_backward_result = ranges::in_out_result<I, O>;
 (3) (C++20 起)
1) 从 [first, last) 所定义的范围移动元素到另一范围 [result - N, result) ，其中 N = ranges::distance(first, last) 。按逆序移动元素（首先移动末元素），但保持其相对顺序。若 result 在 (first, last] 内则行为未定义。此情况下可用 ranges::move 代替。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

被移动的范围的元素将仍然含有适当类型的合法值，但不必为与移动前相同的值，如同对每个 0 ≤ n < N 中的整数 n 使用 *(result - n) = ranges::iter_move(last - n) 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first | - | 要移动的元素范围的起始
last | - | 要移动元素范围的末尾
r | - | 要移动的元素范围
result | - | 目标范围的末尾

返回值

{last, result - N} 。

复杂度

1) 准确移动赋值 N 次。
2) 准确移动赋值 ranges::distance(r) 次。

注解

移动重叠的范围时， ranges::move 适合向左移动（目标范围的起始在源范围外），而 ranges::move_backward 适合向右移动（目标范围的末尾在源范围外）。

可能的实现

struct move_backward_fn {
  template<std::bidirectional_iterator I1, std::sentinel_for<I1> S1,
           std::bidirectional_iterator I2>
    requires std::indirectly_movable<I1, I2>
      constexpr ranges::move_backward_result<I1, I2>
        operator()( I1 first, S1 last, I2 result ) const {
          auto i {last};
          for (; i != first; *--result = ranges::iter_move(--i));
          return {std::move(last), std::move(result)};
        }

  template<ranges::bidirectional_range R, std::bidirectional_iterator I>
    requires std::indirectly_movable<ranges::iterator_t<R>, I>
      constexpr ranges::move_backward_result<ranges::borrowed_iterator_t<R>, I>
        operator()( R&& r, I result ) const {
          return (*this)(ranges::begin(r), ranges::end(r), std::move(result));
        }
};

inline constexpr move_backward_fn move_backward{};

示例

#include <algorithm>
#include <iostream>
#include <string>
#include <string_view>
#include <vector>

using Vec = std::vector<std::string>;

void print(std::string_view rem, Vec const& vec) {
    std::cout << rem << "[" << vec.size() << "]: ";
    for (const std::string& s : vec)
        std::cout << (s.size() ? s : std::string{"·"}) << ' ';
    std::cout << '\n';
}

int main()
{
    Vec a{"▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"};
    Vec b(a.size());

    print("Before move:\n" "a", a);
    print("b", b);

    std::ranges::move_backward(a, b.end());

    print("\n" "Move a >> b:\n" "a", a);
    print("b", b);

    std::ranges::move_backward(b.begin(), b.end(), a.end());
    print("\n" "Move b >> a:\n" "a", a);
    print("b", b);

    std::ranges::move_backward(a.begin(), a.begin()+3, a.end());
    print("\n" "Overlapping move a[0, 3) >> a[5, 8):\n" "a", a);
}

可能的输出：

Before move:
a[8]: ▁ ▂ ▃ ▄ ▅ ▆ ▇ █
b[8]: · · · · · · · ·

Move a >> b:
a[8]: · · · · · · · ·
b[8]: ▁ ▂ ▃ ▄ ▅ ▆ ▇ █

Move b >> a:
a[8]: ▁ ▂ ▃ ▄ ▅ ▆ ▇ █
b[8]: · · · · · · · ·

Overlapping move a[0, 3) >> a[5, 8):
a[8]: · · · ▄ ▅ ▁ ▂ ▃

参阅

ranges::move (C++20) | 将某一范围的元素移动到一个新的位置 (niebloid)
ranges::copyranges::copy_if (C++20)(C++20) | 将某一范围的元素复制到一个新的位置 (niebloid)
ranges::copy_backward (C++20) | 按从后往前的顺序复制一个范围内的元素 (niebloid)
move (C++11) | 将某一范围的元素移动到一个新的位置 (函数模板)
move (C++11) | 获得右值引用 (函数模板)


std::ranges::next_permutation, std::ranges::next_permutation_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template<std::bidirectional_iterator I, std::sentinel_for<I> S,

class Comp = ranges::less, class Proj = std::identity>
requires std::sortable<I, Comp, Proj>
constexpr ranges::next_permutation_result<I>

next_permutation(I first, S last, Comp comp = {}, Proj proj = {});
 (1) (C++20 起)
template<ranges::bidirectional_range R, class Comp = ranges::less,

class Proj = std::identity>
requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
constexpr ranges::next_permutation_result<ranges::borrowed_iterator_t<R>>

next_permutation(R&& r, Comp comp = {}, Proj proj = {});
 (2) (C++20 起)
辅助类型
template<class I>
using next_permutation_result = ranges::in_found_result<I>;
 (3) (C++20 起)
1) 将范围 [first, last) 变换到下个排列，其中所有排列的集合词法上相对于比较函数对象 comp 和投影函数对象 proj 定序。若存在“下个排列”则返回 {last, true} ；否则将范围变换到词法上的首个排列，如同用 ranges::sort(first, last, comp, proj) ，并返回 {last, false} 。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要重排的元素范围
r | - | 要重排的元素范围
comp | - | 若第一参数小于第二个则返回 true 的比较函数对象
proj | - | 应用到元素的投影

返回值

1) 若新排列词法上大于旧者则为 ranges::next_permutation_result<I>{last, true} 。若抵达最后的排列并重置范围为首排列则为 ranges::next_permutation_result<I>{last, false} 。
2) 同 (1) ，除了返回类型为 ranges::next_permutation_result<ranges::borrowed_iterator_t<R>> 。

异常

任何从迭代器操作或元素交换抛出的异常。

复杂度

至多交换 \(\scriptsize N/2\)N/2 次，其中 \(\scriptsize N\)N 在情况 (1) 中为 ranges::distance(first, last) ，在情况 (2) 中为 ranges::distance(r) 。在整个重排序列中，典型实现平均每次调用使用 3 次比较和 1.5 次交换。

注解

实现（例如 MSVC STL ）可能在迭代器类型实现 contiguous_iterator ，并且交换其值类型不调用非平凡的特殊成员函数或 ADL 所找到的 swap 时启用向量化。

可能的实现

struct next_permutation_fn {
  template<std::bidirectional_iterator I, std::sentinel_for<I> S,
           class Comp = ranges::less, class Proj = std::identity>
    requires std::sortable<I, Comp, Proj>
      constexpr ranges::next_permutation_result<I>
        operator()(I first, S last, Comp comp = {}, Proj proj = {}) const {
            // 检查序列是否拥有至少二个元素
            if (first == last)
                return {std::move(first), false};
            I i_last {ranges::next(first, last)};
            I i {i_last};
            if (first == --i)
                return {std::move(i_last), false};
            // 主“重排”循环
            for (;;) {
                I i1 {i};
                if (std::invoke(comp, std::invoke(proj, *--i), std::invoke(proj, *i1))) {
                    I j {i_last};
                    while (!std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, *--j)))
                    { }
                    std::iter_swap(i, j);
                    std::reverse(i1, i_last);
                    return {std::move(i_last), true};
                }
                // 耗尽重排“空格”
                if (i == first) {
                    std::reverse(first, i_last);
                    return {std::move(i_last), false};
                }
            }
        }

  template<ranges::bidirectional_range R, class Comp = ranges::less,
           class Proj = std::identity>
    requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
      constexpr ranges::next_permutation_result<ranges::borrowed_iterator_t<R>>
        operator()(R&& r, Comp comp = {}, Proj proj = {}) const {
          return (*this)(ranges::begin(r), ranges::end(r),
                         std::move(comp), std::move(proj));
        }
};

inline constexpr next_permutation_fn next_permutation{};

示例

#include <algorithm>
#include <array>
#include <compare>
#include <functional>
#include <iostream>
#include <string>

struct S {
    char c;
    int i;
    auto operator<=>(const S&) const = default;
    friend std::ostream& operator<< (std::ostream& os, const S& s) {
        return os << "{'" << s.c << "', " << s.i << "}";
    }
};

auto print = [](auto const& v, char term = ' ') {
    std::cout << "{ ";
    for (const auto& e: v) { std::cout << e << ' '; }
    std::cout << '}' << term;
};

int main()
{
    std::cout << "Generate all permutations (iterators case):\n";
    std::string s{"abc"};
    do { print(s); } while(std::ranges::next_permutation(s.begin(), s.end()).found);

    std::cout << "\n" "Generate all permutations (range case):\n";
    std::array a{'a', 'b', 'c'};
    do { print(a); } while(std::ranges::next_permutation(a).found);

    std::cout << "\n" "Generate all permutations using comparator:\n";
    using namespace std::literals;
    std::array z{ "█"s, "▄"s, "▁"s };
    do { print(z); } while(std::ranges::next_permutation(z, std::greater()).found);

    std::cout << "\n" "Generate all permutations using projection:\n";
    std::array<S, 3> r{ S{'A',3}, S{'B',2}, S{'C',1} };
    do { print(r, '\n'); }
    while(std::ranges::next_permutation(r, {}, &S::c).found);
}

输出：

Generate all permutations (iterators case):
{ a b c } { a c b } { b a c } { b c a } { c a b } { c b a }
Generate all permutations (range case):
{ a b c } { a c b } { b a c } { b c a } { c a b } { c b a }
Generate all permutations using comparator:
{ █ ▄ ▁ } { █ ▁ ▄ } { ▄ █ ▁ } { ▄ ▁ █ } { ▁ █ ▄ } { ▁ ▄ █ }
Generate all permutations using projection:
{ {'A', 3} {'B', 2} {'C', 1} }
{ {'A', 3} {'C', 1} {'B', 2} }
{ {'B', 2} {'A', 3} {'C', 1} }
{ {'B', 2} {'C', 1} {'A', 3} }
{ {'C', 1} {'A', 3} {'B', 2} }
{ {'C', 1} {'B', 2} {'A', 3} }

参阅

ranges::prev_permutation (C++20) | 产生某个元素范围的按字典序下一个较小的排列 (niebloid)
ranges::is_permutation (C++20) | 确定一个序列是否为另一序列的重排 (niebloid)
next_permutation | 产生某个元素范围的按字典顺序的下一个较大的排列 (函数模板)
prev_permutation | 产生某个元素范围的按字典顺序的下一个较小的排列 (函数模板)
is_permutation (C++11) | 判断一个序列是否为另一个序列的排列 (函数模板)


std::ranges::nth_element

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::random_access_iterator I, std::sentinel_for<I> S,

class Comp = ranges::less, class Proj = std::identity >
requires std::sortable<I, Comp, Proj>
constexpr I

nth_element( I first, I nth, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::random_access_range R, class Comp = ranges::less,

class Proj = std::identity >
requires std::sortable<iterator_t<R>, Comp, Proj>
constexpr ranges::borrowed_iterator_t<R>

nth_element( R&& r, iterator_t<R> nth, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)

重排 [first, last) 中的元素使得：

  • nth 所指向的元素被更改为假设 [first, last) 按照 comp 与 proj 排序则会在该位置出现的元素。
  • 所有在此新的 nth 元素前的元素小于或等于新的 nth 后的元素。即对于每个分别在范围 [first, nth) 与 [nth, last) 中的迭代器 i 与 j ，表达式 std::invoke (comp, std::invoke (proj, *j), std::invoke (proj, *i)) 求值为 false.
  • 若 nth == last 则此函数无效果。
1) 用给定的二元比较函数对象 comp 与投影对象 proj 比较元素。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要重排序的元素范围
r | - | 要重排序的元素范围
nth | - | 定义划分点的迭代器
comp | - | 用于比较投影后元素的比较器
proj | - | 应用到元素的投影

返回值

1) 等于 last 的迭代器。
2) 若 r 为左值或拥有 borrowed_range 类型则同 (1) 。否则返回 std::ranges::dangling 。

复杂度

平均与 ranges::distance(first, last) 成线性。

注解

使用的算法常为内省选择，尽管允许其他拥有适合的平均情况复杂度的选择算法。

可能的实现

参阅 MSVC STL 与 libstdc++ 中的实现。

示例

#include <algorithm>
#include <array>
#include <functional>
#include <iostream>
#include <ranges>
#include <string_view>

void print(std::string_view rem, std::ranges::input_range auto const& a)
{
    for (std::cout << rem; const auto e : a)
        std::cout << e << ' ';
    std::cout << "\n";
}

int main()
{
    std::array v{5, 6, 4, 3, 2, 6, 7, 9, 3};
    print("Before nth_element: ", v);

    std::ranges::nth_element(v, v.begin() + v.size()/2);
    print("After nth_element:  ", v);
    std::cout << "The median is: " << v[v.size()/2] << '\n';

    std::ranges::nth_element(v, v.begin() + 1, std::greater<int>());
    print("After nth_element:  ", v);
    std::cout << "The second largest element is: " << v[1] << '\n';
    std::cout << "The largest element is: " << v[0] << "\n\n";

    using namespace std::literals;
    std::array names {
        "Diva"sv, "Cornelius"sv, "Munro"sv, "Rhod"sv,
        "Zorg"sv, "Korben"sv, "Bender"sv, "Leeloo"sv,
    };
    print("Before nth_element: ", names);
    auto fifth_element {std::ranges::next(names.begin(), 4)};
    std::ranges::nth_element(names, fifth_element);
    print("After nth_element:  ", names);
    std::cout << "The 5th element is: " << *fifth_element << '\n';
}

输出：

Before nth_element: 5 6 4 3 2 6 7 9 3
After nth_element:  2 3 3 4 5 6 6 7 9
The median is: 5
After nth_element:  9 7 6 6 5 4 3 3 2
The second largest element is: 7
The largest element is: 9

Before nth_element: Diva Cornelius Munro Rhod Zorg Korben Bender Leeloo
After nth_element:  Diva Cornelius Bender Korben Leeloo Rhod Munro Zorg
The 5th element is: Leeloo

参阅

ranges::max_element (C++20) | 返回范围中的最大元素 (niebloid)
ranges::min_element (C++20) | 返回范围中的最小元素 (niebloid)
ranges::partition (C++20) | 将范围中的元素分为二组 (niebloid)
ranges::partial_sort (C++20) | 排序一个范围的前 N 个元素 (niebloid)
nth_element | 将给定的范围部分排序，确保其按给定元素划分 (函数模板)


std::ranges::partial_sort

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template <std::random_access_iterator I, std::sentinel_for<I> S,

class Comp = ranges::less, class Proj = std::identity>
requires std::sortable<I, Comp, Proj>
constexpr I

partial_sort( I first, I middle, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template <ranges::random_access_range R, class Comp = ranges::less,

class Proj = std::identity>
requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
constexpr ranges::borrowed_iterator_t<R>

partial_sort( R&& r, ranges::iterator_t<R> middle, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)
1) 重排元素使得范围 [first, middle) 含有范围 [first, last) 中 middle - first 个最小的元素。
不保证保持相等元素的顺序。范围 [middle, last) 中剩余元素的顺序未指定。
用给定的二元比较函数 comp 比较，用 proj 函数对象投影元素。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 定义要排序的范围的迭代器-哨位对
r | - | 要排序的范围
middle | - | 定义要排序的末元素的迭代器
comp | - | 应用到投影后元素的比较器
proj | - | 应用到元素的投影

返回值

等于 last 的迭代器。

复杂度

\(\scriptsize \mathcal{O}(N\cdot\log{(M)})\)𝓞(N·log(M)) 次比较和二倍次数的投影，其中 \(\scriptsize N\)N 为 ranges::distance(first, last) ， \(\scriptsize M\)M 为 ranges::distance(first, middle) 。

可能的实现

struct partial_sort_fn {
    template <std::random_access_iterator I, std::sentinel_for<I> S,
             class Comp = ranges::less, class Proj = std::identity>
    requires std::sortable<I, Comp, Proj>
    constexpr I
    operator()( I first, I middle, S last, Comp comp = {}, Proj proj = {} ) const {
        if (first == middle) return ranges::next(first, last);
        ranges::make_heap(first, middle, comp, proj);
        auto it {middle};
        for (; it != last; ++it) {
            if (std::invoke(comp, std::invoke(proj, *it), std::invoke(proj, *first))) {
                ranges::pop_heap(first, middle, comp, proj);
                ranges::iter_swap(middle - 1, it);
                ranges::push_heap(first, middle, comp, proj);
            }
        }
        ranges::sort_heap(first, middle, comp, proj);
        return it;
    }

    template <ranges::random_access_range R, class Comp = ranges::less,
             class Proj = std::identity>
    requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
    constexpr ranges::borrowed_iterator_t<R>
    operator()( R&& r, ranges::iterator_t<R> middle, Comp comp = {}, Proj proj = {} ) const {
        return (*this)(ranges::begin(r), std::move(middle), ranges::end(r),
                       std::move(comp), std::move(proj));
    }
};

inline constexpr partial_sort_fn partial_sort{};

示例

#include <algorithm>
#include <functional>
#include <iostream>
#include <string>
#include <vector>

void print(const auto& v) {
    for (const char e : v) { std::cout << e << ' '; }
    std::cout << '\n';
}

void underscore(int n) {
    while (n-- > 0) { std::cout << "^ "; }
    std::cout << '\n';
}

int main()
{
    static_assert('A' < 'a');
    std::vector<char> v{'x', 'P', 'y', 'C', 'z', 'w', 'P', 'o'};
    print(v);
    std::ranges::partial_sort(v, v.begin() + 3);
    print(v); underscore(3);

    static_assert('1' < 'a');
    std::string s{"3a1b41c5"};
    print(s);
    std::ranges::partial_sort(s.begin(), s.begin() + 3, s.end(), std::greater{});
    print(s); underscore(3);
}

输出：

x P y C z w P o
C P P y z x w o
^ ^ ^
3 a 1 b 4 1 c 5
c b a 1 3 1 4 5
^ ^ ^

参阅

ranges::partial_sort_copy (C++20) | 对范围内的元素进行复制并部分排序 (niebloid)
ranges::sort (C++20) | 将范围按升序排序 (niebloid)
ranges::stable_sort (C++20) | 将范围内的元素排序，同时保持相等的元素之间的顺序 (niebloid)
ranges::nth_element (C++20) | 将给定的范围部分排序，确保其按给定元素划分 (niebloid)
ranges::make_heap (C++20) | 从一个元素范围创建出一个最大堆 (niebloid)
ranges::pop_heap (C++20) | 从最大堆中移除最大元素 (niebloid)
ranges::push_heap (C++20) | 将一个元素加入到一个最大堆 (niebloid)
ranges::sort_heap (C++20) | 将一个最大堆变成一个按升序排序的元素范围 (niebloid)
partial_sort | 排序一个范围的前 N 个元素 (函数模板)


std::ranges::partial_sort_copy, std::ranges::partial_sort_copy_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I1, std::sentinel_for<I1> S1,

std::random_access_iterator I2, std::sentinel_for<I2> S2,
class Comp = ranges::less, class Proj1 = std::identity,
class Proj2 = std::identity >
requires std::indirectly_copyable<I1, I2> && std::sortable<I2, Comp, Proj2> &&
std::indirect_strict_weak_order<Comp, std::projected<I1, Proj1>,
std::projected<I2, Proj2>>
constexpr partial_sort_copy_result<I1, I2>
partial_sort_copy( I1 first, S1 last, I2 result_first, S2 result_last,

Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {} );
 (1) (C++20 起)
template< ranges::input_range R1, ranges::random_access_range R2,

class Comp = ranges::less, class Proj1 = std::identity,
class Proj2 = std::identity >
requires std::indirectly_copyable<ranges::iterator_t<R1>, ranges::iterator_t<R2>> &&
std::sortable<ranges::iterator_t<R2>, Comp, Proj2> &&
std::indirect_strict_weak_order<Comp, std::projected<ranges::iterator_t<R1>,
Proj1>, std::projected<ranges::iterator_t<R2>, Proj2>>
constexpr partial_sort_copy_result<ranges::borrowed_iterator_t<R1>,
ranges::borrowed_iterator_t<R2>>
partial_sort_copy( R1&& r, R2&& result_r, Comp comp = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (2) (C++20 起)
辅助类型
template<class I, class O>
using partial_sort_copy_result = ranges::in_out_result<I, O>;
 (3) (C++20 起)

复制来自源范围 [first, last) 的首 N 个元素，如同它按照 comp 与 proj1 部分排序，到目标范围 [result_first, result_first + N) ，其中 \(\scriptsize N = \min{(L_1, L_2)}\)N = min(L₁, L₂) ， \(\scriptsize L_1\)L₁ 等于 ranges::distance(first, last) 而 \(\scriptsize L_2\)L₂ 等于 ranges::distance(result_first, result_last) 。

不保证保持相等元素的顺序。

1) 用函数对象 proj1 投影源范围元素，并用函数对象 proj2 投影目标元素。
2) 同 (1) ，但以 r 为源范围并以 result_r 为目标范围，如同以 ranges::begin(r) 为 first ，以 ranges::end(r) 为 last ，以 ranges::begin(result_r) 为 result_first ，并以 ranges::end(result_r) 为 result_last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 定义复制来源的源范围的迭代器-哨位对
r | - | 复制来源的源范围
result_first, result_last | - | 定义目标范围的迭代器-哨位对
result_r | - | 目标范围
comp | - | 应用到投影后元素的比较
proj1 | - | 应用到源范围元素的投影
proj2 | - | 应用到目标范围元素的投影

返回值

等于 {last, result_first + N} 的对象。

复杂度

至多比较 \(\scriptsize L_1 \cdot \log{(N)}\)L₁•log(N) 次，投影 \(\scriptsize 2 \cdot L_1 \cdot \log{(N)}\)2•L₁•log(N) 次。

可能的实现

struct partial_sort_copy_fn {
    template< std::input_iterator I1, std::sentinel_for<I1> S1,
              std::random_access_iterator I2, std::sentinel_for<I2> S2,
              class Comp = ranges::less, class Proj1 = std::identity,
              class Proj2 = std::identity >
    requires  std::indirectly_copyable<I1, I2> && std::sortable<I2, Comp, Proj2> &&
              std::indirect_strict_weak_order<Comp, std::projected<I1, Proj1>,
              std::projected<I2, Proj2>>
    constexpr ranges::partial_sort_copy_result<I1, I2>
    operator()( I1 first, S1 last, I2 result_first, S2 result_last,
                Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {} ) const {
        if (result_first == result_last) {
            return {std::move(ranges::next(std::move(first), std::move(last))),
                    std::move(result_first)};
        }

        auto out_last {result_first};
        // 复制首 N 个元素
        for (; !(first == last or out_last == result_last); ++out_last, ++first) {
            *out_last = *first;
        }
        // 转换 N 个复制的元素为最大堆
        ranges::make_heap(result_first, out_last, comp, proj2);

        // 处理剩余的输入范围（若存在），保持堆属性
        for (; first != last; ++first) {
            if (std::invoke(comp, std::invoke(proj1, *first), std::invoke(proj2, *result_first))) {
                // 弹出最大项并塞入新找到的较小项
                ranges::pop_heap(result_first, out_last, comp, proj2);
                *(out_last - 1) = *first;
                ranges::push_heap(result_first, out_last, comp, proj2);
            }
        }

        // 输出范围中首 N 个元素仍为堆——转换之为已排序范围
        ranges::sort_heap(result_first, out_last, comp, proj2);

        return {std::move(first), std::move(out_last)};
    }

    template< ranges::input_range R1, ranges::random_access_range R2,
              class Comp = ranges::less, class Proj1 = std::identity,
              class Proj2 = std::identity >
    requires  std::indirectly_copyable<ranges::iterator_t<R1>, ranges::iterator_t<R2>> &&
              std::sortable<ranges::iterator_t<R2>, Comp, Proj2> &&
              std::indirect_strict_weak_order<Comp, std::projected<ranges::iterator_t<R1>,
              Proj1>, std::projected<ranges::iterator_t<R2>, Proj2>>
    constexpr ranges::partial_sort_copy_result<ranges::borrowed_iterator_t<R1>,
              ranges::borrowed_iterator_t<R2>>
    operator()( R1&& r, R2&& result_r, Comp comp = {},
                Proj1 proj1 = {}, Proj2 proj2 = {} ) const {
        return (*this)(ranges::begin(r), ranges::end(r),
                       ranges::begin(result_r), ranges::end(result_r),
                       std::move(comp), std::move(proj1), std::move(proj2));
    }
};

inline constexpr partial_sort_copy_fn partial_sort_copy{};

示例

#include <algorithm>
#include <forward_list>
#include <functional>
#include <iostream>
#include <ranges>
#include <string_view>
#include <vector>

void print(std::string_view rem, std::ranges::input_range auto const& v)
{
    for (std::cout << rem; const auto& e : v)
        std::cout << e << ' ';
    std::cout << '\n';
}

int main()
{
    const std::forward_list source{4, 2, 5, 1, 3};

    print("Write to the smaller vector in ascending order: ", "");

    std::vector dest1{10, 11, 12};
    print("const source list: ", source);
    print("destination range: ", dest1);
    std::ranges::partial_sort_copy(source, dest1);
    print("partial_sort_copy: ", dest1);

    print("Write to the larger vector in descending order:", "");

    std::vector dest2{10, 11, 12, 13, 14, 15, 16};
    print("const source list: ", source);
    print("destination range: ", dest2);
    std::ranges::partial_sort_copy(source, dest2, std::greater{});
    print("partial_sort_copy: ", dest2);
}

输出：

Write to the smaller vector in ascending order:
const source list: 4 2 5 1 3
destination range: 10 11 12
partial_sort_copy: 1 2 3
Write to the larger vector in descending order:
const source list: 4 2 5 1 3
destination range: 10 11 12 13 14 15 16
partial_sort_copy: 5 4 3 2 1 15 16

参阅

ranges::partial_sort (C++20) | 排序一个范围的前 N 个元素 (niebloid)
ranges::sort (C++20) | 将范围按升序排序 (niebloid)
ranges::stable_sort (C++20) | 将范围内的元素排序，同时保持相等的元素之间的顺序 (niebloid)
ranges::sort_heap (C++20) | 将一个最大堆变成一个按升序排序的元素范围 (niebloid)
ranges::make_heap (C++20) | 从一个元素范围创建出一个最大堆 (niebloid)
ranges::push_heap (C++20) | 将一个元素加入到一个最大堆 (niebloid)
ranges::pop_heap (C++20) | 从最大堆中移除最大元素 (niebloid)
partial_sort_copy | 对范围内的元素进行复制并部分排序 (函数模板)


std::ranges::partition

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::permutable I, std::sentinel_for<I> S, class Proj = std::identity,

std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
constexpr ranges::subrange<I>

partition( I first, S last, Pred pred, Proj proj = {} );
 (1) (C++20 起)
template<ranges::forward_range R, class Proj = std::identity,

std::indirect_unary_predicate<
std::projected<ranges::iterator_t<R>, Proj>> Pred>
requires std::permutable<ranges::iterator_t<R>>
constexpr ranges::borrowed_subrange_t<R>

partition(R&& r, Pred pred, Proj proj = {});
 (2) (C++20 起)
1) 重排范围 [first, last) 中的元素，使谓词 pred 对其投影 proj 返回 true 的所有元素在谓词 pred 对其投影 proj 返回 false 的所有元素之前。不保持等价元素的相对顺序。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要重排的范围
r | - | 要重排的范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到谓词的投影

返回值

始于指向第二组首元素的迭代器，终于等于 last 的迭代器的 subrange 。若 r 是非 borrowed_range 类型的右值则 (2) 返回 std::ranges::dangling 。

复杂度

给定 N = ranges::distance(first,last) 。

准确应用 N 次谓词与投影，若 I 实现 ranges::bidirectional_iterator 则至多交换 N/2 次，否则至多交换 N 次。

可能的实现

struct partition_fn {
  template<std::permutable I, std::sentinel_for<I> S, class Proj = std::identity,
           std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
  constexpr ranges::subrange<I>
  operator()(I first, S last, Pred pred, Proj proj = {}) const
  {
      first = ranges::find_if_not(first, last, std::ref(pred), std::ref(proj));
      if (first == last) {
          return {first, first};
      }

      auto begin = first;
      for (auto i = ranges::next(first); i != last; ++i) {
          if (std::invoke(pred, std::invoke(proj, *i))) {
              ranges::iter_swap(i, first);
              ++first;
          }
      }
      return {std::move(begin), std::move(first)};
  }

  template<ranges::forward_range R, class Proj = std::identity,
           std::indirect_unary_predicate<
               std::projected<ranges::iterator_t<R>, Proj>> Pred>
  requires std::permutable<ranges::iterator_t<R>>
  constexpr ranges::borrowed_subrange_t<R>
  operator()(R&& r, Pred pred, Proj proj = {}) const
  {
    return (*this)(ranges::begin(r), ranges::end(r),
                   std::ref(pred), std::ref(proj));
  }
};

inline constexpr partition_fn partition;

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <forward_list>

namespace ranges = std::ranges;

template <std::permutable I, std::sentinel_for<I> S>
void quicksort(I first, S last)
{
   if(first == last) {
       return;
   }

   auto pivot = *ranges::next(first, ranges::distance(first,last)/2, last);
   auto middle1 = ranges::partition(first, last, [pivot](const auto& em){
       return em < pivot;
   });
   auto middle2 = ranges::partition(middle1, last, [pivot](const auto& em){
       return !(pivot < em);
   });
   quicksort(first, middle1);
   quicksort(middle2, last);
}

int main()
{
    std::vector<int> v = {0,1,2,3,4,5,6,7,8,9};
    std::cout << "Original vector:\n    ";
    for(int elem : v) {
        std::cout << elem << ' ';
    }

    auto it = ranges::partition(v, [](int i){return i % 2 == 0;});

    std::cout << "\nPartitioned vector:\n    ";
    ranges::copy(ranges::begin(v), it, std::ostream_iterator<int>(std::cout, " "));
    std::cout << " * ";
    ranges::copy(it, ranges::end(v), std::ostream_iterator<int>(std::cout, " "));

    std::forward_list<int> fl = {1, 30, -4, 3, 5, -4, 1, 6, -8, 2, -5, 64, 1, 92};
    std::cout << "\nUnsorted list:\n    ";
    for(int n : fl) {
        std::cout << n << ' ';
    }
    std::cout << '\n';

    quicksort(ranges::begin(fl), ranges::end(fl));
    std::cout << "Sorted using quicksort:\n    ";
    for(int fi : fl) {
        std::cout << fi << ' ';
    }
    std::cout << '\n';
}

输出：

Original vector:
    0 1 2 3 4 5 6 7 8 9
Partitioned vector:
    0  * 2 4 6 8
Unsorted list:
    1 30 -4 3 5 -4 1 6 -8 2 -5 64 1 92
Sorted using quicksort:
    -4 -4 -8 -5 1 1 3 2 5 1 30 64 6 92

参阅

ranges::is_partitioned (C++20) | 判断范围是否已按给定的谓词划分 (niebloid)
ranges::stable_partition (C++20) | 将元素分成二组，同时保持其相对顺序 (niebloid)
partition | 将范围中的元素分为两组 (函数模板)


std::ranges::partition_copy, std::ranges::partition_copy_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S,

std::weakly_incrementable O1, std::weakly_incrementable O2,
class Proj = std::identity, std::indirect_unary_predicate<
std::projected<I, Proj>> Pred >
requires std::indirectly_copyable<I, O1> && std::indirectly_copyable<I, O2>
constexpr partition_copy_result<I, O1, O2>

partition_copy( I first, S last, O1 out_true, O2 out_false, Pred pred, Proj proj = {} );
 (1) (C++20 起)
template< ranges::input_range R, std::weakly_incrementable O1, std::weakly_incrementable O2,

class Proj = std::identity,
std::indirect_unary_predicate<std::projected<iterator_t<R>, Proj>> Pred >
requires std::indirectly_copyable<ranges::iterator_t<R>, O1> &&
std::indirectly_copyable<ranges::iterator_t<R>, O2>
constexpr partition_copy_result<ranges::borrowed_iterator_t<R>, O1, O2>

partition_copy( R&& r, O1 out_true, O2 out_false, Pred pred, Proj proj = {} );
 (2) (C++20 起)
辅助类型
template<class I, class O1, class O2>
using partition_copy_result = ranges::in_out_out_result<I, O1, O2>;
 (3) (C++20 起)
1) 从输入范围 [first, last) 复制元素到二个不同的取决于谓词 pred 所返回的值输出范围。复制在由 proj 投影后满足 pred 的元素到始于 out_true 的范围。复制剩余元素到始于 out_false 的范围。
前条件：输入范围不与任一输出范围重叠。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要自之复制的输入元素范围
r | - | 要自之复制的输入元素范围
out_true | - | 满足 pred 的输出元素范围的起始
out_false | - | 不满足 pred 的输出元素范围的起始
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

等于 {last, o1, o2} 的对象，其中 o1 与 o2 分别为复制完成后两个输出范围的末尾。

复杂度

准确应用 ranges::distance(first, last) 次对应的谓词 comp 和任何投影 proj 。

可能的实现

struct partition_copy_fn {
  template <std::input_iterator I, std::sentinel_for<I> S,
           std::weakly_incrementable O1, std::weakly_incrementable O2,
           class Proj = std::identity, std::indirect_unary_predicate<
           std::projected<I, Proj>> Pred>
  requires std::indirectly_copyable<I, O1> && std::indirectly_copyable<I, O2>
  constexpr ranges::partition_copy_result<I, O1, O2>
  operator()( I first, S last, O1 out_true, O2 out_false, Pred pred, Proj proj = {} ) const {
      for (; first != last; ++first)
          if (!!std::invoke(pred, std::invoke(proj, *first)))
              *out_true = *first, ++out_true;
          else
              *out_false = *first, ++out_false;
      return {std::move(first), std::move(out_true), std::move(out_false)};
  }

  template<ranges::input_range R, std::weakly_incrementable O1, std::weakly_incrementable O2,
           class Proj = std::identity,
           std::indirect_unary_predicate<std::projected<iterator_t<R>, Proj>> Pred>
  requires std::indirectly_copyable<ranges::iterator_t<R>, O1> &&
           std::indirectly_copyable<ranges::iterator_t<R>, O2>
  constexpr ranges::partition_copy_result<ranges::borrowed_iterator_t<R>, O1, O2>
  operator()( R&& r, O1 out_true, O2 out_false, Pred pred, Proj proj = {} ) const {
      return (*this)(ranges::begin(r), ranges::end(r), std::move(out_true),
                     std::move(out_false), std::move(pred), std::move(proj));
  }
};

inline constexpr partition_copy_fn partition_copy{};

示例

#include <algorithm>
#include <cctype>
#include <iostream>
#include <vector>
#include <iterator>

int main()
{
    const auto in = {'N', '3', 'U', 'M', '1', 'B', '4', 'E', '1', '5', 'R', '9'};

    std::vector<int> o1(size(in)), o2(size(in));

    auto pred = [](char c){ return std::isalpha(c); };

    auto ret = std::ranges::partition_copy(in, o1.begin(), o2.begin(), pred);

    std::ostream_iterator<char> cout {std::cout, " "};
    std::cout << "in = ";
    std::ranges::copy(in, cout);
    std::cout << "\no1 = ";
    std::copy(o1.begin(), ret.out1, cout);
    std::cout << "\no2 = ";
    std::copy(o2.begin(), ret.out2, cout);
    std::cout << '\n';
}

输出：

in = N 3 U M 1 B 4 E 1 5 R 9
o1 = N U M B E R
o2 = 3 1 4 1 5 9

参阅

ranges::partition (C++20) | 将范围中的元素分为二组 (niebloid)
ranges::stable_partition (C++20) | 将元素分成二组，同时保持其相对顺序 (niebloid)
ranges::copyranges::copy_if (C++20)(C++20) | 将某一范围的元素复制到一个新的位置 (niebloid)
ranges::remove_copyranges::remove_copy_if (C++20)(C++20) | 复制一个范围的元素，忽略满足特定判别标准的元素 (niebloid)
partition_copy (C++11) | 复制一个范围，将各元素分为两组 (函数模板)


std::ranges::partition_point

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity,

std::indirect_unary_predicate<std::projected<I, Proj>> Pred >

constexpr I partition_point( I first, S last, Pred pred, Proj proj = {} );
 (1) (C++20 起)
template< ranges::forward_range R, class Proj = std::identity,

std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
constexpr ranges::borrowed_iterator_t<R>

partition_point( R&& r, Pred pred, Proj proj = {} );
 (2) (C++20 起)

检验已划分（如同用 ranges::partition ）范围 [first, last) 或 r 并定位第一划分的结尾，即不满足 pred 的被投影元素，或若所有投影后元素均满足 pred 则为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 定义要检验的部分排序范围的迭代器-哨位对
r | - | 要检验的部分排序范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

[first, last) 内第一划分的尾后位置迭代器，或若所有投影后元素均满足 pred 则为等于 last 的迭代器。

复杂度

给定 N = ranges::distance(first, last) ，应用 O(log N) 次谓词 pred 与投影 proj 。

然而，若哨位不实现 std::sized_sentinel_for<I> ，则迭代器自增次数为 O(N) 。

注解

此算法是 ranges::lower_bound 的更通用的形式，能用 ranges::partition_point 用 [&](auto const& e) { return std::invoke (pred, e, value); }); 为谓词表达它。

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>

int main()
{
    std::array v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    namespace ranges = std::ranges;
    auto is_even = [](int i){ return i % 2 == 0; };
    ranges::partition(v, is_even);

    auto p = ranges::partition_point(v.begin(), v.end(), is_even);

    std::cout << "Before partition:\n    ";
    ranges::copy(v.begin(), p, std::ostream_iterator<int>(std::cout, " "));
    std::cout << "\nAfter partition:\n    ";
    ranges::copy(p, v.end(), std::ostream_iterator<int>(std::cout, " "));
}

输出：

Before partition:
    8 2 6 4
After partition:
    5 3 7 1 9

参阅

ranges::is_sorted (C++20) | 检查范围是否以升序排序 (niebloid)
ranges::lower_bound (C++20) | 返回指向首个不小于给定值的元素的迭代器 (niebloid)
partition_point (C++11) | 定位已划分范围的划分点 (函数模板)


std::ranges::pop_heap

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::random_access_iterator I, std::sentinel_for<I> S,

class Comp = ranges::less, class Proj = std::identity >
requires std::sortable<I, Comp, Proj>
constexpr I

pop_heap( I first, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::random_access_range R, class Comp = ranges::less,

class Proj = std::identity >
requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
constexpr ranges::borrowed_iterator_t<R>

pop_heap( R&& r, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)

交换在位置 first 的值与在位置 last-1 的值并使子范围 [first, last-1) 为最大堆。这拥有从范围 [first, last) 所定义的堆移除首元素的效果。

1) 用给定的二元比较函数 comp 与投影对象 proj 比较元素。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 定义要修改的非空堆的元素范围
r | - | 定义要修改的非空堆的元素范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

等于 last 的迭代器。

复杂度

给定 N = ranges::distance(first, last) ，至多比较 \(\scriptsize 2\log{(N)}\)2log(N) 次，投影 \(\scriptsize 4\log{(N)}\)4log(N) 次。

注解

最大堆是按照比较器 comp 与投影 proj 排列的元素范围 [f, l) ，拥有下列属性：

  • 令 N == l - f ，对于所有 0 < i < N ， p == f[(i - 1) / 2] 和 q == f[i] ，表达式 std::invoke (comp, std::invoke (proj, p), std::invoke (proj, q)) 求值为 false 。
  • 能用 ranges::push_heap() 在 \(\scriptsize \mathcal{O}(\log N)\)𝓞(log N) 时间内添加新元素。
  • 能用 ranges::pop_heap() 在 \(\scriptsize \mathcal{O}(\log N)\)𝓞(log N) 时间内移除首元素。

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
#include <string_view>

template <class I = int*>
void print(std::string_view rem, I first = {}, I last = {},
           std::string_view term = "\n")
{
    for (std::cout << rem; first != last; ++first) {
        std::cout << *first << ' ';
    }
    std::cout << term;
}

int main()
{
    std::array v { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3 };
    print("initially, v: ", v.cbegin(), v.cend());

    std::ranges::make_heap(v);
    print("make_heap, v: ", v.cbegin(), v.cend());

    print("convert heap into sorted array:");
    for (auto n {std::ssize(v)}; n >= 0; --n) {
        std::ranges::pop_heap(v.begin(), v.begin() + n);
        print("[ ", v.cbegin(), v.cbegin() + n, "]  ");
        print("[ ", v.cbegin() + n, v.cend(), "]\n");
    }
}

输出：

initially, v: 3 1 4 1 5 9 2 6 5 3
make_heap, v: 9 6 4 5 5 3 2 1 1 3
convert heap into sorted array:
[ 6 5 4 3 5 3 2 1 1 9 ]  [ ]
[ 5 5 4 3 1 3 2 1 6 ]  [ 9 ]
[ 5 3 4 1 1 3 2 5 ]  [ 6 9 ]
[ 4 3 3 1 1 2 5 ]  [ 5 6 9 ]
[ 3 2 3 1 1 4 ]  [ 5 5 6 9 ]
[ 3 2 1 1 3 ]  [ 4 5 5 6 9 ]
[ 2 1 1 3 ]  [ 3 4 5 5 6 9 ]
[ 1 1 2 ]  [ 3 3 4 5 5 6 9 ]
[ 1 1 ]  [ 2 3 3 4 5 5 6 9 ]
[ 1 ]  [ 1 2 3 3 4 5 5 6 9 ]
[ ]  [ 1 1 2 3 3 4 5 5 6 9 ]

参阅

ranges::push_heap (C++20) | 将一个元素加入到一个最大堆 (niebloid)
ranges::is_heap (C++20) | 检查给定范围是否为最大堆 (niebloid)
ranges::is_heap_until (C++20) | 寻找能成为最大堆的最大子范围 (niebloid)
ranges::make_heap (C++20) | 从一个元素范围创建出一个最大堆 (niebloid)
ranges::sort_heap (C++20) | 将一个最大堆变成一个按升序排序的元素范围 (niebloid)
pop_heap | 从最大堆中移除最大元素 (函数模板)


std::ranges::prev_permutation, std::ranges::prev_permutation_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template<std::bidirectional_iterator I, std::sentinel_for<I> S,

class Comp = ranges::less, class Proj = std::identity>
requires std::sortable<I, Comp, Proj>
constexpr ranges::prev_permutation_result<I>

prev_permutation(I first, S last, Comp comp = {}, Proj proj = {});
 (1) (C++20 起)
template<ranges::bidirectional_range R, class Comp = ranges::less,

class Proj = std::identity>
requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
constexpr ranges::prev_permutation_result<ranges::borrowed_iterator_t<R>>

prev_permutation(R&& r, Comp comp = {}, Proj proj = {});
 (2) (C++20 起)
辅助类型
template<class I>
using prev_permutation_result = ranges::in_found_result<I>;
 (3) (C++20 起)
1) 变换范围 [first, last) 到前一排列，其中所有排列的集合在词法上相对按照函数对象 comp 与投影函数对象 proj 定序。若存在“前一排列”则返回 {last, true} ；否则变换范围到词法上的末排列（如同用 ranges::sort(first, last, comp, proj); ranges::reverse(first, last); ），并返回 {last, false} 。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要重排的元素范围
r | - | 要重排的元素范围
comp | - | 若第一参数小于第二个则返回 true 的比较函数对象
proj | - | 应用到元素的投影

返回值

1) 若新排列词法上小于旧者则为 ranges::prev_permutation_result<I>{last, true} 。若抵达首个排列并设置范围为末排列则为 ranges::prev_permutation_result<I>{last, false} 。
2) 同 (1) ，除了返回类型为 ranges::prev_permutation_result<ranges::borrowed_iterator_t<R>> 。

异常

任何从迭代器操作或元素交换抛出的异常。

复杂度

至多交换 \(\scriptsize N/2\)N/2 次，其中 \(\scriptsize N\)N 在情况 (1) 中为 ranges::distance(first, last) ，在情况 (2) 中为 ranges::distance(r) 。在整个重排序列中，典型实现平均每次调用使用 3 次比较和 1.5 次交换。

注解

实现（例如 MSVC STL ）可能在迭代器类型实现 contiguous_iterator ，并且交换其值类型不调用非平凡的特殊成员函数或 ADL 所找到的 swap 时启用向量化。

可能的实现

struct prev_permutation_fn {
  template<std::bidirectional_iterator I, std::sentinel_for<I> S,
           class Comp = ranges::less, class Proj = std::identity>
    requires std::sortable<I, Comp, Proj>
      constexpr ranges::prev_permutation_result<I>
        operator()(I first, S last, Comp comp = {}, Proj proj = {}) const {
            // 检查序列是否拥有至少二个元素
            if (first == last)
                return {std::move(first), false};
            auto i {first};
            ++i;
            if (i == last)
              return {std::move(i), false};
            auto i_last {ranges::next(first, last)};
            i = i_last;
            --i;
            // 主“重排”循环
            for (;;) {
                auto i1 {i};
                --i;
                if (std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, *i1))) {
                    auto j {i_last};
                    while (!std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, *--j)))
                    { }
                    ranges::iter_swap(i, j);
                    ranges::reverse(i1, last);
                    return {std::move(i_last), true};
                }
                // 耗尽重排“空格”
                if (i == first) {
                    ranges::reverse(first, last);
                    return {std::move(i_last), false};
                }
            }
        }

  template<ranges::bidirectional_range R, class Comp = ranges::less,
           class Proj = std::identity>
    requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
      constexpr ranges::prev_permutation_result<ranges::borrowed_iterator_t<R>>
        operator()(R&& r, Comp comp = {}, Proj proj = {}) const {
          return (*this)(ranges::begin(r), ranges::end(r),
                         std::move(comp), std::move(proj));
        }
};

inline constexpr prev_permutation_fn prev_permutation{};

示例

#include <algorithm>
#include <array>
#include <compare>
#include <functional>
#include <iostream>
#include <string>

struct S {
    char c;
    int i;
    auto operator<=>(const S&) const = default;
    friend std::ostream& operator<< (std::ostream& os, const S& s) {
        return os << "{'" << s.c << "', " << s.i << "}";
    }
};

auto print = [](auto const& v, char term = ' ') {
    std::cout << "{ ";
    for (const auto& e: v) { std::cout << e << ' '; }
    std::cout << '}' << term;
};

int main()
{
    std::cout << "Generate all permutations (iterators case):\n";
    std::string s{"cba"};
    do { print(s); } while(std::ranges::prev_permutation(s.begin(), s.end()).found);

    std::cout << "\n" "Generate all permutations (range case):\n";
    std::array a{'c', 'b', 'a'};
    do { print(a); } while(std::ranges::prev_permutation(a).found);

    std::cout << "\n" "Generate all permutations using comparator:\n";
    using namespace std::literals;
    std::array z{ "▁"s, "▄"s, "█"s };
    do { print(z); } while(std::ranges::prev_permutation(z, std::greater()).found);

    std::cout << "\n" "Generate all permutations using projection:\n";
    std::array<S, 3> r{ S{'C',1}, S{'B',2}, S{'A',3} };
    do { print(r, '\n'); }
    while(std::ranges::prev_permutation(r, {}, &S::c).found);
}

输出：

Generate all permutations (iterators case):
{ c b a } { c a b } { b c a } { b a c } { a c b } { a b c }
Generate all permutations (range case):
{ c b a } { c a b } { b c a } { b a c } { a c b } { a b c }
Generate all permutations using comparator:
{ ▁ ▄ █ } { ▁ █ ▄ } { ▄ ▁ █ } { ▄ █ ▁ } { █ ▁ ▄ } { █ ▄ ▁ }
Generate all permutations using projection:
{ {'C', 1} {'B', 2} {'A', 3} }
{ {'C', 1} {'A', 3} {'B', 2} }
{ {'B', 2} {'C', 1} {'A', 3} }
{ {'B', 2} {'A', 3} {'C', 1} }
{ {'A', 3} {'C', 1} {'B', 2} }
{ {'A', 3} {'B', 2} {'C', 1} }

参阅

ranges::next_permutation (C++20) | 产生某个元素范围的按字典序下一个较大的排列 (niebloid)
ranges::is_permutation (C++20) | 确定一个序列是否为另一序列的重排 (niebloid)
next_permutation | 产生某个元素范围的按字典顺序的下一个较大的排列 (函数模板)
prev_permutation | 产生某个元素范围的按字典顺序的下一个较小的排列 (函数模板)
is_permutation (C++11) | 判断一个序列是否为另一个序列的排列 (函数模板)


std::ranges::push_heap

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::random_access_iterator I, std::sentinel_for<I> S,

class Comp = ranges::less, class Proj = std::identity >
requires std::sortable<I, Comp, Proj>
constexpr I

push_heap( I first, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::random_access_range R, class Comp = ranges::less,

class Proj = std::identity >
requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
constexpr ranges::borrowed_iterator_t<R>

push_heap( R&& r, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)

插入位于位置 last-1 的元素到范围 [first, last-1) 所定义的最大堆中。

1) 用给定的二元比较函数 comp 与投影对象 proj 比较元素。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 定义要修改的堆的元素范围
r | - | 定义要修改的堆的元素范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

等于 last 的迭代器。

复杂度

给定 N = ranges::distance(first, last) ，至多比较 \(\scriptsize \log{(N)}\)log(N) 次，投影 \(\scriptsize 2\log{(N)}\)2log(N) 次。

注解

最大堆是按照比较器 comp 与投影 proj 排列的元素范围 [f, l) ，拥有下列属性：

  • 令 N == l - f ，对于所有 0 < i < N ， p == f[(i - 1) / 2] 和 q == f[i] ，表达式 std::invoke (comp, std::invoke (proj, p), std::invoke (proj, q)) 求值为 false 。
  • 能用 ranges::push_heap() 在 \(\scriptsize \mathcal{O}(\log N)\)𝓞(log N) 时间内添加新元素。
  • 能用 ranges::pop_heap() 在 \(\scriptsize \mathcal{O}(\log N)\)𝓞(log N) 时间内移除首元素。

可能的实现

struct push_heap_fn {
    template< std::random_access_iterator I, std::sentinel_for<I> S,
              class Comp = ranges::less, class Proj = std::identity >
    requires std::sortable<I, Comp, Proj>
    constexpr I
    operator()( I first, S last, Comp comp = {}, Proj proj = {} ) const {
        const auto n {ranges::distance(first, last)};
        const auto length {n};
        if (n > 1) {
            I last {first + n};
            n = (n - 2) / 2;
            I i {first + n};
            if (std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, *--last))) {
                std::iter_value_t<I> v {ranges::iter_move(last)};
                do {
                    *last = ranges::iter_move(i);
                    last = i;
                    if (n == 0) break;
                    n = (n - 1) / 2;
                    i = first + n;
                } while (std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, v)));
                *last = std::move(v);
            }
        }
        return first + length;
    }

    template< ranges::random_access_range R, class Comp = ranges::less,
              class Proj = std::identity >
    requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
    constexpr ranges::borrowed_iterator_t<R>
    operator()( R&& r, Comp comp = {}, Proj proj = {} ) const {
        return (*this)(ranges::begin(r), ranges::end(r), std::move(comp), std::move(proj));
    }
};

inline constexpr push_heap_fn push_heap{};

示例

#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>

void out(const auto& what, int n = 1) {
    while (n-- > 0)
        std::cout << what;
}

void print(auto rem, auto const& v) {
    out(rem);
    for (auto e : v) { out(e), out(' '); }
    out('\n');
}

void draw_heap(auto const& v);

int main()
{
    std::vector<int> v { 1, 6, 1, 8, 0, 3, };
    print("source vector v: ", v);

    std::ranges::make_heap(v);
    print("after make_heap: ", v);
    draw_heap(v);

    v.push_back(9);

    print("before push_heap: ", v);
    draw_heap(v);

    std::ranges::push_heap(v);
    print("after push_heap: ", v);
    draw_heap(v);
}

void draw_heap(auto const& v)
{
    auto bails = [](int n, int w) {
        auto b = [](int w) { out("┌"), out("─", w), out("┴"), out("─", w), out("┐"); };
        if (!(n /= 2)) return;
        for (out(' ', w); n-- > 0; ) b(w), out(' ', w + w + 1);
        out('\n');
    };
    auto data = [](int n, int w, auto& first, auto last) {
        for(out(' ', w); n-- > 0 && first != last; ++first)
            out(*first), out(' ', w + w + 1);
        out('\n');
    };
    auto tier = [&](int t, int m, auto& first, auto last) {
        const int n {1 << t};
        const int w {(1 << (m - t - 1)) - 1};
        bails(n, w), data(n, w, first, last);
    };
    const int m {static_cast<int>(std::ceil(std::log2(1 + v.size())))};
    auto first {v.cbegin()};
    for (int i{}; i != m; ++i) { tier(i, m, first, v.cend()); }
}

输出：

source vector v: 1 6 1 8 0 3
after make_heap: 8 6 3 1 0 1
   8
 ┌─┴─┐
 6   3
┌┴┐ ┌┴┐
1 0 1
before push_heap: 8 6 3 1 0 1 9
   8
 ┌─┴─┐
 6   3
┌┴┐ ┌┴┐
1 0 1 9
after push_heap: 9 6 8 1 0 1 3
   9
 ┌─┴─┐
 6   8
┌┴┐ ┌┴┐
1 0 1 3

参阅

ranges::is_heap (C++20) | 检查给定范围是否为最大堆 (niebloid)
ranges::is_heap_until (C++20) | 寻找能成为最大堆的最大子范围 (niebloid)
ranges::make_heap (C++20) | 从一个元素范围创建出一个最大堆 (niebloid)
ranges::pop_heap (C++20) | 从最大堆中移除最大元素 (niebloid)
ranges::sort_heap (C++20) | 将一个最大堆变成一个按升序排序的元素范围 (niebloid)
push_heap | 将一个元素加入到一个最大堆 (函数模板)


std::ranges::remove, std::ranges::remove_if

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::permutable I, std::sentinel_for<I> S, class T, class Proj = std::identity >

requires std::indirect_binary_predicate<
ranges::equal_to, std::projected<I, Proj>, const T*>
constexpr ranges::subrange<I>

remove( I first, S last, const T& value, Proj proj = {} );
 (1) (C++20 起)
template< ranges::forward_range R, class T, class Proj = std::identity >

requires std::permutable<ranges::iterator_t<R>> &&
std::indirect_binary_predicate<
ranges::equal_to, std::projected<ranges::iterator_t<R>, Proj>, const T*>
constexpr ranges::borrowed_subrange_t<R>

remove( R&& r, const T& value, Proj proj = {} );
 (2) (C++20 起)
template< std::permutable I, std::sentinel_for<I> S, class Proj = std::identity,

std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
constexpr ranges::subrange<I>

remove_if( I first, S last, Pred pred, Proj proj = {} );
 (3) (C++20 起)
template< ranges::forward_range R, class Proj = std::identity,

std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
requires std::permutable<ranges::iterator_t<R>>
constexpr ranges::borrowed_subrange_t<R>

remove_if( R&& r, Pred pred, Proj proj = {} );
 (4) (C++20 起)

从范围 [first, last) 移除所有满足特定判别标准的元素，并返回子范围 [ret, last) ，其中 ret 是范围新末尾的尾后迭代器。

1) 移除所有等于 value 的元素，用 std::invoke (proj, *i) == value 比较。
3) 移除所有使得 std::invoke (pred, std::invoke (proj, *i)) 返回 true 的元素。
2,4) 同 (1,3) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

通过使未被移除的元素出现在范围起始这种方式，迁移（方式为移动赋值）范围中元素，来进行移除。保持剩余元素的相对顺序而容器的物理大小保持不变。指向新的逻辑结尾与物理结尾之间的迭代器仍然可解引用，但元素自身拥有未指定的值（经由可移动赋值 (MoveAssignable) 的后条件）。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要处理的元素范围
r | - | 要处理的元素范围
value | - | 要移除的元素的值
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

{ret, last} ，其中 [first, ret) 是移除后作为结果的子范围，而子范围 [ret, last) 中的元素在合法但未指定的状态。

复杂度

准确应用 N 次对应谓词和任何投影，其中 N = ranges::distance(first, last) ，及最坏情况下 N-1 次移动操作。

注解

调用 ranges::remove 常后随容器的 erase 成员函数，它擦除未指定值并减小容器的物理大小以匹配其新的逻辑大小。这两个调用一并被称为擦除-移除手法，它可通过对所有标准序列容器重载的 std::erase 自由函数，或对所有标准容器重载的 std::erase_if 自由函数达成。

名称类似的容器成员函数 list::remove、 list::remove_if、 forward_list::remove 及 forward_list::remove_if 擦除被移除的元素。

这些算法通常不能用于如 std::set 与 std::map 的关联容器，因为其迭代器类型不解引用为可移动赋值 (MoveAssignable) 类型（这些容器中的键不可修改）。

因为 ranges::remove 按引用接收 value ，若它是到范围 [first, last) 中元素的引用则函数可能有非期待的行为。

可能的实现

版本一
struct remove_fn {
  template<std::permutable I, std::sentinel_for<I> S, class T, class Proj = std::identity>
    requires std::indirect_binary_predicate<
        ranges::equal_to, std::projected<I, Proj>, const T*>
      constexpr ranges::subrange<I>
        operator()( I first, S last, const T& value, Proj proj = {} ) const {
            first = ranges::find(std::move(first), last, value, proj);
            if (first != last) {
                for (I i { std::next(first) }; i != last; ++i) {
                    if (value != std::invoke(proj, *i)) {
                        *first = ranges::iter_move(i);
                        ++first;
                    }
                }
            }
            return {first, last};
        }

  template<ranges::forward_range R, class T, class Proj = std::identity>
    requires std::permutable<ranges::iterator_t<R>> &&
               std::indirect_binary_predicate<
                 ranges::equal_to, std::projected<ranges::iterator_t<R>, Proj>, const T*>
      constexpr ranges::borrowed_subrange_t<R>
        operator()( R&& r, const T& value, Proj proj = {} ) const {
          return (*this)(ranges::begin(r), ranges::end(r), value, std::move(proj));
        }
};

inline constexpr remove_fn remove{};
版本二
struct remove_if_fn {
  template<std::permutable I, std::sentinel_for<I> S, class Proj = std::identity,
           std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
    constexpr ranges::subrange<I>
      operator()( I first, S last, Pred pred, Proj proj = {} ) const {
          first = ranges::find_if(std::move(first), last, pred, proj);
          if (first != last) {
              for (I i { std::next(first) }; i != last; ++i) {
                  if (!std::invoke(pred, std::invoke(proj, *i))) {
                      *first = ranges::iter_move(i);
                      ++first;
                  }
              }
          }
          return {first, last};
      }

  template<ranges::forward_range R, class Proj = std::identity,
           std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred>
    requires std::permutable<ranges::iterator_t<R>>
      constexpr ranges::borrowed_subrange_t<R>
        operator()( R&& r, Pred pred, Proj proj = {} ) const {
          return (*this)(ranges::begin(r), ranges::end(r), pred, std::move(proj));
        }
  };

inline constexpr remove_if_fn remove_if{};

示例

#include <algorithm>
#include <cctype>
#include <iomanip>
#include <iostream>

int main()
{
    std::string ndr{"N o _ D i a g n o s t i c _ R e q u i r e d"};
    std::cout << std::quoted(ndr) << " -> ";
    const auto ret1 = std::ranges::remove(ndr, ' ');
    ndr.erase(ret1.begin(), ret1.end());
    std::cout << std::quoted(ndr) << "\n\n";

    auto rm = [](char c) { return std::islower(c) or std::isspace(c); };
    std::string sfinae{"Substitution Failure Is Not An Error"};
    std::cout << std::quoted(sfinae) << " -> ";
    const auto ret2 = std::ranges::remove_if(sfinae, rm);
    sfinae.erase(ret2.begin(), ret2.end());
    std::cout << std::quoted(sfinae) << '\n';
}

输出：

"N o _ D i a g n o s t i c _ R e q u i r e d" -> "No_Diagnostic_Required"

"Substitution Failure Is Not An Error" -> "SFINAE"

参阅

ranges::remove_copyranges::remove_copy_if (C++20)(C++20) | 复制一个范围的元素，忽略满足特定判别标准的元素 (niebloid)
ranges::unique (C++20) | 移除范围中的连续重复元素 (niebloid)
removeremove_if | 移除满足特定判别标准的元素 (函数模板)


std::ranges::remove_copy, std::ranges::remove_copy_if, std::ranges::remove_copy_result, std::ranges::remove_copy_if_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O,

class T, class Proj = std::identity >
requires std::indirectly_copyable<I, O> &&
std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>, const T*>
constexpr remove_copy_result<I, O>

remove_copy( I first, S last, O result, const T& value, Proj proj = {} );
 (1) (C++20 起)
template< ranges::input_range R, std::weakly_incrementable O, class T,

class Proj = std::identity >
requires std::indirectly_copyable<ranges::iterator_t<R>, O> &&
std::indirect_binary_predicate<ranges::equal_to,
std::projected<ranges::iterator_t<R>, Proj>, const T*>
constexpr remove_copy_result<ranges::borrowed_iterator_t<R>, O>

remove_copy( R&& r, O result, const T& value, Proj proj = {} );
 (2) (C++20 起)
template< std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O,

class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
requires std::indirectly_copyable<I, O>
constexpr remove_copy_if_result<I, O>

remove_copy_if( I first, S last, O result, Pred pred, Proj proj = {} );
 (3) (C++20 起)
template< ranges::input_range R, std::weakly_incrementable O, class Proj = std::identity,

std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
requires std::indirectly_copyable<ranges::iterator_t<R>, O>
constexpr remove_copy_if_result<ranges::borrowed_iterator_t<R>, O>

remove_copy_if( R&& r, O result, Pred pred, Proj proj = {} );
 (4) (C++20 起)
辅助类型
template<class I, class O>
using remove_copy_result = ranges::in_out_result<I, O>;
 (5) (C++20 起)
template<class I, class O>
using remove_copy_if_result = ranges::in_out_result<I, O>;
 (6) (C++20 起)

复制来自源范围 [first, last) 的元素到始于 result 的目标范围，忽略（在由 proj 投影后）满足特定判别标准的元素。若源范围与目标范围重叠则行为未定义。

1) 忽略所有等于 value 的元素。
3) 忽略所有谓词 pred 对其返回 true 的元素。
2,4) 同 (1,3) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 源元素范围
r | - | 源元素范围
result | - | 目标范围的起始
value | - | 不复制的元素的值
comp | - | 比较投影后元素的二元谓词
proj | - | 应用到元素的投影

返回值

{last, result + N} ，其中 N 是复制的元素数。

复杂度

准确应用 ranges::distance(first, last) 次对应的谓词 comp 与任何投影 proj 。

注解

算法是稳定的，即保持被复制元素的相对顺序。

可能的实现

版本一
struct remove_copy_fn {
  template <std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O,
           class T, class Proj = std::identity>
  requires std::indirectly_copyable<I, O> &&
           std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>, const T*>
  constexpr ranges::remove_copy_result<I, O>
  operator()( I first, S last, O result, const T& value, Proj proj = {} ) const {
      for (; !(first == last); ++first) {
          if (value != std::invoke(proj, *first)) {
              *result = *first;
              ++result;
          }
      }
      return {std::move(first), std::move(result)};
  }

  template <ranges::input_range R, std::weakly_incrementable O, class T,
           class Proj = std::identity>
  requires std::indirectly_copyable<ranges::iterator_t<R>, O> &&
           std::indirect_binary_predicate<ranges::equal_to,
           std::projected<ranges::iterator_t<R>, Proj>, const T*>
  constexpr ranges::remove_copy_result<ranges::borrowed_iterator_t<R>, O>
  operator()( R&& r, O result, const T& value, Proj proj = {} ) const {
      return (*this)(ranges::begin(r), ranges::end(r), std::move(result), value,
                     std::move(proj));
  }
};
inline constexpr remove_copy_fn remove_copy{};
版本二
struct remove_copy_if_fn {
  template <std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O,
           class Proj = std::identity,
           std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
  requires std::indirectly_copyable<I, O>
  constexpr ranges::remove_copy_if_result<I, O>
  operator()( I first, S last, O result, Pred pred, Proj proj = {} ) const {
      for (; first != last; ++first) {
          if (false == std::invoke(pred, std::invoke(proj, *first))) {
              *result = *first;
              ++result;
          }
      }
      return {std::move(first), std::move(result)};
  }

  template <ranges::input_range R, std::weakly_incrementable O, class Proj = std::identity,
           std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred>
  requires std::indirectly_copyable<ranges::iterator_t<R>, O>
  constexpr ranges::remove_copy_if_result<ranges::borrowed_iterator_t<R>, O>
  operator()( R&& r, O result, Pred pred, Proj proj = {} ) const {
      return (*this)(ranges::begin(r), ranges::end(r), std::move(result), std::move(pred),
                     std::move(proj));
  }
};
inline constexpr remove_copy_if_fn remove_copy_if_{};

示例

#include <algorithm>
#include <array>
#include <complex>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <string_view>
#include <vector>

void print(const auto rem, const auto& v) {
    std::cout << rem << ' ';
    for (const auto& e : v) { std::cout << e << ' '; };
    std::cout << '\n';
}

int main()
{
    // 从给定的字符串滤出散列记号。
    const std::string_view str{ "#Small #Buffer #Optimization" };
    std::cout << "before: " << std::quoted(str) << "\n";

    std::cout << "after:  \"";
    std::ranges::remove_copy(str.begin(), str.end(),
                             std::ostream_iterator<char>(std::cout), '#');
    std::cout << "\"\n";

    // 仅复制有正虚部的复数
    using Ci = std::complex<int>;
    constexpr std::array<Ci, 5> source{
        Ci{1,0}, Ci{0,1}, Ci{2,-1}, Ci{3,2}, Ci{4,-3}
    };
    std::vector<std::complex<int>> target;

    std::ranges::remove_copy_if(source,
        std::back_inserter(target),
        [](int imag){ return imag <= 0; },
        [](Ci z){ return z.imag(); }
    );

    print("source:", source);
    print("target:", target);
}

输出：

before: "#Small #Buffer #Optimization"
after:  "Small Buffer Optimization"
source: (1,0) (0,1) (2,-1) (3,2) (4,-3)
target: (0,1) (3,2)

参阅

ranges::removeranges::remove_if (C++20)(C++20) | 移除满足特定判别标准的元素 (niebloid)
ranges::copyranges::copy_if (C++20)(C++20) | 将某一范围的元素复制到一个新的位置 (niebloid)
ranges::copy_n (C++20) | 将一定数目的元素复制到一个新的位置 (niebloid)
ranges::copy_backward (C++20) | 按从后往前的顺序复制一个范围内的元素 (niebloid)
ranges::replace_copyranges::replace_copy_if (C++20)(C++20) | 复制一个范围内的元素，并将满足特定判别标准的元素替换为另一个值 (niebloid)
ranges::revserse_copy (C++20) | 创建一个范围的逆向副本 (niebloid)
ranges::rotate_copy (C++20) | 复制并旋转元素范围 (niebloid)
ranges::unique_copy (C++20) | 创建某范围的不含连续重复元素的副本 (niebloid)
remove_copyremove_copy_if | 复制一个范围的元素，忽略满足特定判别标准的元素 (函数模板)


std::ranges::replace, std::ranges::replace_if

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S, class T1, class T2,

class Proj = std::identity >
requires std::indirectly_writable<I, const T2&> && std::indirect_binary_predicate<
ranges::equal_to, std::projected<I, Proj>, const T1*>
constexpr I

replace( I first, S last, const T1& old_value, const T2& new_value, Proj proj = {} );
 (1) (C++20 起)
template< ranges::input_range R, class T1, class T2, class Proj = std::identity >

requires std::indirectly_writable<ranges::iterator_t<R>, const T2&> &&
std::indirect_binary_predicate<ranges::equal_to,
std::projected<ranges::iterator_t<R>, Proj>, const T1*>
constexpr ranges::borrowed_iterator_t<R>

replace( R&& r, const T1& old_value, const T2& new_value, Proj proj = {} );
 (2) (C++20 起)
template< std::input_iterator I, std::sentinel_for<I> S, class T,

class Proj = std::identity, std::indirect_unary_predicate<
std::projected<I, Proj>> Pred >
requires std::indirectly_writable<I, const T&>
constexpr I

replace_if( I first, S last, Pred pred, const T& new_value, Proj proj = {} );
 (3) (C++20 起)
template< ranges::input_range R, class T, class Proj = std::identity,

std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
requires std::indirectly_writable<ranges::iterator_t<R>, const T&>
constexpr ranges::borrowed_iterator_t<R>

replace_if( R&& r, Pred pred, const T& new_value, Proj proj = {} );
 (4) (C++20 起)

以 new_value 替换范围中 [first, last) 所有满足特定判别标准的元素。

1) 替换所有等于 old_value 的元素。用 std::invoke (proj, *i) == old_value 比较。
3) 替换所有谓词 pred 对其求值为 true 的元素，其中求值的表达式为 std::invoke (pred, std::invoke (proj, *i)) 。
2,4) 同 (1,3) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要处理的元素范围
r | - | 要处理的元素范围
old_value | - | 要替换的元素的值
new_value | - | 要用作替换品的值
pred | - | 应用到投影后元素的谓词
proj | - | 应用到谓词的投影

返回值

等于 last 的迭代器。

复杂度

准确应用 ranges::distance(first, last) 次对应的谓词 comp 与任何投影 proj 。

注解

由于算法按引用接收 old_value 与 new_value ，它可能在任一参数为到范围 [first, last) 中元素的引用时有非期待的行为。

可能的实现

版本一
struct replace_fn {
    template <std::input_iterator I, std::sentinel_for<I> S, class T1, class T2,
             class Proj = std::identity>
    requires std::indirectly_writable<I, const T2&> && std::indirect_binary_predicate<
              ranges::equal_to, std::projected<I, Proj>, const T1*>
    constexpr I
    operator() ( I first, S last, const T1& old_value, const T2& new_value,
                 Proj proj = {} ) const {
        for (; first != last; ++first) {
            if (old_value == std::invoke(proj, *first)) {
                *first = new_value;
            }
        }
        return first;
    }

    template <ranges::input_range R, class T1, class T2, class Proj = std::identity>
    requires std::indirectly_writable<ranges::iterator_t<R>, const T2&> &&
             std::indirect_binary_predicate<ranges::equal_to,
             std::projected<ranges::iterator_t<R>, Proj>, const T1*>
    constexpr ranges::borrowed_iterator_t<R>
    operator() ( R&& r, const T1& old_value, const T2& new_value, Proj proj = {} ) const {
        return (*this)(ranges::begin(r), ranges::end(r), old_value,
                       new_value, std::move(proj));
    }
};

inline constexpr replace_fn replace{};
版本二
struct replace_if_fn {
    template <std::input_iterator I, std::sentinel_for<I> S, class T,
             class Proj = std::identity, std::indirect_unary_predicate<
             std::projected<I, Proj>> Pred>
    requires std::indirectly_writable<I, const T&>
    constexpr I
    operator() ( I first, S last, Pred pred, const T& new_value, Proj proj = {} ) const {
        for (; first != last; ++first) {
            if (!!std::invoke(pred, std::invoke(proj, *first))) {
                *first = new_value;
            }
        }
        return std::move(first);
    }

    template <ranges::input_range R, class T, class Proj = std::identity,
             std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred>
    requires std::indirectly_writable<ranges::iterator_t<R>, const T&>
    constexpr ranges::borrowed_iterator_t<R>
    operator() ( R&& r, Pred pred, const T& new_value, Proj proj = {} ) const {
        return (*this)(ranges::begin(r), ranges::end(r), std::move(pred),
                       new_value, std::move(proj));
    }
};

inline constexpr replace_if_fn replace_if{};

示例

#include <algorithm>
#include <array>
#include <iostream>

int main()
{
    auto print = [](const auto& v) {
        for (const auto& e : v) { std::cout << e << ' '; }
        std::cout << '\n';
    };

    std::array p{1, 6, 1, 6, 1, 6};
    print(p);
    std::ranges::replace(p, 6, 9);
    print(p);

    std::array q{1, 2, 3, 6, 7, 8, 4, 5};
    print(q);
    std::ranges::replace_if(q, [](int x){ return 5 < x; }, 5);
    print(q);
}

输出：

1 6 1 6 1 6
1 9 1 9 1 9
1 2 3 6 7 8 4 5
1 2 3 5 5 5 4 5

参阅

ranges::replace_copyranges::replace_copy_if (C++20)(C++20) | 复制一个范围内的元素，并将满足特定判别标准的元素替换为另一个值 (niebloid)
replacereplace_if | 将所有满足特定判别标准的值替换为另一个值 (函数模板)


std::ranges::replace_copy, std::ranges::replace_copy_if, std::ranges::replace_copy_result, std::ranges::replace_copy_if_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S, class T1, class T2,

std::output_iterator<const T2&> O, class Proj = std::identity >
requires std::indirectly_copyable<I, O> &&
std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>,
const T1*>
constexpr replace_copy_result<I, O>
replace_copy( I first, S last, O result, const T1& old_value, const T2& new_value,

Proj proj = {} );
 (1) (C++20 起)
template< ranges::input_range R, class T1, class T2,

std::output_iterator<const T2&> O, class Proj = std::identity >
requires std::indirectly_copyable<ranges::iterator_t<R>, O> &&
std::indirect_binary_predicate<ranges::equal_to,
std::projected<ranges::iterator_t<R>, Proj>, const T1*>
constexpr replace_copy_result<ranges::borrowed_iterator_t<R>, O>
replace_copy( R&& r, O result, const T1& old_value, const T2& new_value,

Proj proj = {} );
 (2) (C++20 起)
template< std::input_iterator I, std::sentinel_for<I> S, class T,

std::output_iterator<const T&> O,
class Proj = std::identity, std::indirect_unary_predicate<
std::projected<I, Proj>> Pred >
requires std::indirectly_copyable<I, O>
constexpr replace_copy_if_result<I, O>
replace_copy_if( I first, S last, O result, Pred pred, const T& new_value,

Proj proj = {} );
 (3) (C++20 起)
template< ranges::input_range R, class T, std::output_iterator<const T&> O,

class Proj = std::identity,
std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
requires std::indirectly_copyable<ranges::iterator_t<R>, O>
constexpr replace_copy_if_result<ranges::borrowed_iterator_t<R>, O>
replace_copy_if( R&& r, O result, Pred pred, const T& new_value,

Proj proj = {} );
 (4) (C++20 起)
辅助类型
template< class I, class O >
using replace_copy_result = ranges::in_out_result<I, O>;
 (5) (C++20 起)
template< class I, class O >
using replace_copy_if_result = ranges::in_out_result<I, O>;
 (6) (C++20 起)

从源范围 [first, last) 复制元素到始于 result 的目标范围，以 new_value 替换所欲满足特定标准的元素。若源范围与目标范围重叠则行为未定义。

1) 替换所有等于 old_value 的元素，用 std::invoke (proj, *(first + (i - result))) == old_value 比较。
3) 替换所有谓词 pred 对其求值为 true 的元素，其中求值的表达式为 std::invoke (pred, std::invoke (proj, *(first + (i - result)))) 。
2,4) 同 (1,3) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要复制的元素范围
r | - | 要复制的元素范围
result | - | 目标范围的起始
old_value | - | 要替换的元素的值
new_value | - | 用作替换品的值
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

{last, result + N} ，其中

1,3) N = ranges::distance(first, last) ；
2,4) N = ranges::distance(r) 。

复杂度

准确应用 N 次对应的谓词 comp 与投影 proj 。

可能的实现

版本一
struct replace_copy_fn {
    template <std::input_iterator I, std::sentinel_for<I> S, class T1, class T2,
             std::output_iterator<const T2&> O, class Proj = std::identity>
    requires std::indirectly_copyable<I, O> &&
             std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>,
             const T1*>
    constexpr ranges::replace_copy_result<I, O>
    operator()( I first, S last, O result, const T1& old_value, const T2& new_value,
                Proj proj = {} ) const {
        for (; first != last; ++first, ++result) {
            *result = (std::invoke(proj, *first) == old_value) ? new_value : *first;
        }
        return {std::move(first), std::move(result)};
    }

    template <ranges::input_range R, class T1, class T2,
             std::output_iterator<const T2&> O, class Proj = std::identity>
    requires std::indirectly_copyable<ranges::iterator_t<R>, O> &&
             std::indirect_binary_predicate<ranges::equal_to,
             std::projected<ranges::iterator_t<R>, Proj>, const T1*>
    constexpr ranges::replace_copy_result<ranges::borrowed_iterator_t<R>, O>
    operator()( R&& r, O result, const T1& old_value, const T2& new_value,
                Proj proj = {} ) const {
        return (*this)(ranges::begin(r), ranges::end(r), std::move(result),
                       old_value, new_value, std::move(proj));
    }
};

inline constexpr replace_copy_fn replace_copy{};
版本二
struct replace_copy_if_fn {
    template <std::input_iterator I, std::sentinel_for<I> S, class T,
             std::output_iterator<const T&> O,
             class Proj = std::identity, std::indirect_unary_predicate<
             std::projected<I, Proj>> Pred>
    requires std::indirectly_copyable<I, O>
    constexpr ranges::replace_copy_if_result<I, O>
    operator()( I first, S last, O result, Pred pred, const T& new_value,
                Proj proj = {} ) const {
        for (; first != last; ++first, ++result) {
             *result = std::invoke(pred, std::invoke(proj, *first)) ? new_value : *first;
        }
        return {std::move(first), std::move(result)};
    }

    template <ranges::input_range R, class T, std::output_iterator<const T&> O,
             class Proj = std::identity,
             std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred>
    requires std::indirectly_copyable<ranges::iterator_t<R>, O>
    constexpr ranges::replace_copy_if_result<ranges::borrowed_iterator_t<R>, O>
    operator()( R&& r, O result, Pred pred, const T& new_value,
                Proj proj = {} ) const {
        return (*this)(ranges::begin(r), ranges::end(r), std::move(result),
                       std::move(pred), new_value, std::move(proj));
    }
};

inline constexpr replace_copy_if_fn replace_copy_if{};

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <vector>

int main()
{
    auto print = [](const auto rem, const auto& v) {
        for (std::cout << rem << ": "; const auto& e : v)
            std::cout << e << ' ';
        std::cout << '\n';
    };

    std::vector<int> o;

    std::array p{1, 6, 1, 6, 1, 6};
    o.resize(p.size());
    print("p", p);
    std::ranges::replace_copy(p, o.begin(), 6, 9);
    print("o", o);

    std::array q{1, 2, 3, 6, 7, 8, 4, 5};
    o.resize(q.size());
    print("q", q);
    std::ranges::replace_copy_if(q, o.begin(), [](int x){ return 5 < x; }, 5);
    print("o", o);
}

输出：

p: 1 6 1 6 1 6
o: 1 9 1 9 1 9
q: 1 2 3 6 7 8 4 5
o: 1 2 3 5 5 5 4 5

参阅

ranges::replaceranges::replace_if (C++20)(C++20) | 将所有满足特定判别标准的值替换为另一个值 (niebloid)
replace_copyreplace_copy_if | 复制一个范围内的元素，并将满足特定判别标准的元素替换为另一个值 (函数模板)


std::ranges::in_found_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm> |
template <class I> struct in_found_result; | (C++20 起)

ranges::in_found_result 是类模板，提供存储一个迭代器和一个布尔标志为单个单元的方式。

此类模板无基类或显示如下的声明的数据成员，从而它适合用于结果化绑定。

此类模板的所有特殊成员函数均为隐式声明，这使得特化为聚合类，并传播数据成员上的操作的平凡性、潜在抛出性及 constexpr 性质。

模板形参

I - ranges::in_found_result 所存储的迭代器类型

数据成员

std::ranges::in_found_result::in

[[no_unique_address]] I in;

值（假定为迭代器）

std::ranges::in_found_result::found

bool found;

布尔标志（可能显示是否找到对应的范围）

成员函数

std::ranges::in_found_result::operator in_found_result<I2>

template<class I2>

requires std::convertible_to<const I&, I2>

constexpr operator in_found_result<I2>() const &;
 (1)
template<class I2>

requires std::convertible_to<I, I2>

constexpr operator in_found_result<I2>() &&;
 (2)

通过从 *this 的每个数据成员构造结果的对应成员，转换 *this 为结果。

1) 等价于 return {in, found}; 。
2) 等价于 return {std::move(in), found}; 。

标准库

下列标准库函数以 ranges::in_found_result 为返回类型：

算法函数
ranges::next_permutation
(C++20)
 产生某个元素范围的按字典序下一个较大的排列
(niebloid)
ranges::prev_permutation
(C++20)
 产生某个元素范围的按字典序下一个较小的排列
(niebloid)

概要

namespace std::ranges {
    template<class I>
    struct in_found_result {
        [[no_unique_address]] I in;
        bool found;

        template<class I2>
        requires std::convertible_to<const I&, I2>
        constexpr operator in_found_result<I2>() const & {
            return {in, found};
        }

        template<class I2>
        requires std::convertible_to<I, I2>
        constexpr operator in_found_result<I2>() && {
            return {std::move(in), found};
        }
    };
}

注解

每个使用此返回类型族的标准库算法声明新的别名类型，例如 using merge_result = in_in_out_result<I1, I2, O>; 。

这些别名族的名称由添加 "_result" 到算法名组成。故 std::ranges::merge 的返回类型能命名为 std::ranges::merge_result 。

不同于 std::pair 与 std::tuple ，此类模板的拥有名字有意义的数据成员。

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <ranges>

int main()
{
    int v[] { 1, 2, 3 };

    const auto result = std::ranges::next_permutation(v);

    std::ranges::for_each(std::cbegin(v), result.in, [](int e){std::cout << e << ' ';});

    std::cout << std::boolalpha << "\n" "result.found: " << result.found << '\n';
}

输出：

1 3 2
result.found = true

参阅

pair | 实现二元组，即一对值 (类模板)
tuple (C++11) | 实现固定大小的容器，它保有类型可以相异的元素 (类模板)


std::ranges::in_fun_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm> |
template <class I, class F> struct in_fun_result; | (C++20 起)

ranges::in_fun_result 是类模板，提供存储一个迭代器和一个函数对象为单个单元的方式。

此类模板无基类或显示如下的声明的数据成员，从而它适合用于结果化绑定。

此类模板的所有特殊成员函数均为隐式声明，这使得特化为聚合类，并传播数据成员上的操作的平凡性、潜在抛出性及 constexpr 性质。

模板形参

I | - | ranges::in_fun_result 存储的迭代器类型
F | - | ranges::in_fun_result 存储的函数对象类型

数据成员

std::ranges::in_fun_result::in

[[no_unique_address]] I in;

值（假设为迭代器）

std::ranges::in_fun_result::fun

[[no_unique_address]] F fun;

值（假设为函数对象）

成员函数

std::ranges::in_fun_result::operator in_fun_result<I2, F2>

template<class I2, class F2>

requires std::convertible_to<const I&, I2> && std::convertible_to<const F&, F2>

constexpr operator in_fun_result<I2, F2>() const &;
 (1)
template<class I2, class F2>

requires std::convertible_to<I, I2> && std::convertible_to<F, F2>

constexpr operator in_fun_result<I2, F2>() &&;
 (2)

通过从 *this 的每个数据成员构造结果的对应成员，转换 *this 为结果。

1) 等价于 return {in, fun}; 。
2) 等价于 return {std::move(in), std::move(fun)}; 。

标准库

下列标准库函数以 ranges::in_fun_result 为返回类型：

算法函数
ranges::for_each
(C++20)
 应用函数到范围中的元素
(niebloid)
ranges::for_each_n
(C++20)
 应用函数对象到序列的首 n 个元素
(niebloid)

概要

namespace std::ranges {
    template<class I, class F>
    struct in_fun_result {
        [[no_unique_address]] I in;
        [[no_unique_address]] F fun;

        template<class I2, class F2>
        requires std::convertible_to<const I&, I2> && std::convertible_to<const F&, F2>
        constexpr operator in_fun_result<I2, F2>() const & {
            return {in, fun};
        }

        template<class I2, class F2>
        requires std::convertible_to<I, I2> && std::convertible_to<F, F2>
        constexpr operator in_fun_result<I2, F2>() && {
            return {std::move(in), std::move(fun)};
        }
    };
}

注解

每个使用此返回类型族的标准库算法声明新的别名类型，例如 using merge_result = in_in_out_result<I1, I2, O>; 。

这些别名族的名称由添加 "_result" 到算法名组成。故 std::ranges::merge 的返回类型能命名为 std::ranges::merge_result 。

不同于 std::pair 与 std::tuple ，此类模板的拥有名字有意义的数据成员。

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <ranges>

int main()
{
    int v[] { 1, 2, 3 };

    const auto [last, negate] = std::ranges::for_each_n(v, std::size(v),
        [](int& x) { return x = -x; });

    const auto result = std::ranges::for_each(std::cbegin(v), last,
        [](int x) { std::cout << x << ' '; });
    std::cout << "│ ";

    std::ranges::for_each(v, negate);
    std::ranges::for_each(v, result.fun);
    std::cout << '\n';
}

输出：

-1 -2 -3 │ 1 2 3

参阅

pair | 实现二元组，即一对值 (类模板)
tuple (C++11) | 实现固定大小的容器，它保有类型可以相异的元素 (类模板)


std::ranges::in_in_out_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm> |
template <class I1, class I2, class O> struct in_in_out_result; | (C++20 起)

ranges::in_in_out_result 是类模板，提供存储三个迭代器为单个单元的方式。

此类模板无基类或显示如下的声明的数据成员，从而它适合用于结果化绑定。

此类模板的所有特殊成员函数均为隐式声明，这使得特化为聚合类，并传播数据成员上的操作的平凡性、潜在抛出性及 constexpr 性质。

模板形参

I1, I2, O - ranges::in_in_out_result 所存储的迭代器类型

数据成员

std::ranges::in_in_out_result::in1

[[no_unique_address]] I1 in1;

值（假定为迭代器）

std::ranges::in_in_out_result::in2

[[no_unique_address]] I2 in2;

值（假定为迭代器）

std::ranges::in_in_out_result::out

[[no_unique_address]] O out;

值（假定为迭代器）

成员函数

std::ranges::in_in_out_result::operator in_in_out_result<II1, II2, OO>

template<class II1, class II2, class OO>

requires std::convertible_to<const I1&, II1> &&
std::convertible_to<const I2&, II2> &&
std::convertible_to<const O&, OO>

constexpr operator in_in_out_result<II1, II2, OO>() const &;
 (1)
template<class II1, class II2, class OO>

requires std::convertible_to<I1, II1> &&
std::convertible_to<I2, II2> &&
std::convertible_to<O, OO>

constexpr operator in_in_out_result<II1, II2, OO>() &&;
 (2)

通过从 *this 的每个数据成员构造结果的对应成员，转换 *this 为结果。

1) 等价于 return {in1, in2, out}; 。
2) 等价于 return {std::move(in1), std::move(in2), std::move(out)}; 。

标准库

下列标准库函数以 ranges::in_in_out_result 为返回类型：

算法函数
ranges::transform
(C++20)
 将一个函数应用于某一范围的各个元素
(niebloid)
ranges::merge
(C++20)
 归并二个已排序范围
(niebloid)
ranges::set_union
(C++20)
 计算两个集合的并集
(niebloid)
ranges::set_intersection
(C++20)
 计算两个集合的交集
(niebloid)
ranges::set_symmetric_difference
(C++20)
 计算两个集合的对称差
(niebloid)

概要

namespace std::ranges {
    template<class I1, class I2, class O>
    struct in_in_out_result {
        [[no_unique_address]] I1 in1;
        [[no_unique_address]] I2 in2;
        [[no_unique_address]] O  out;

        template<class II1, class II2, class OO>
        requires std::convertible_to<const I1&, II1> &&
                 std::convertible_to<const I2&, II2> &&
                 std::convertible_to<const O&, OO>
        constexpr operator in_in_out_result<II1, II2, OO>() const & {
            return {in1, in2, out};
        }

        template<class II1, class II2, class OO>
        requires std::convertible_to<I1, II1> &&
                 std::convertible_to<I2, II2> &&
                 std::convertible_to<O, OO>
        constexpr operator in_in_out_result<II1, II2, OO>() && {
            return {std::move(in1), std::move(in2), std::move(out)};
        }
    };
}

注解

每个使用此返回类型族的标准库算法声明新的别名类型，例如 using merge_result = in_in_out_result<I1, I2, O>; 。

这些别名族的名称由添加 "_result" 到算法名组成。故 std::ranges::merge 的返回类型能命名为 std::ranges::merge_result 。

不同于 std::pair 与 std::tuple ，此类模板的拥有名字有意义的数据成员。

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
#include <ranges>

void print(auto rem, auto first, auto last) {
    for (std::cout << rem << ": "; first != last; ++first)
        std::cout << *first << ' ';
    std::cout << '\n';
}

int main()
{
    constexpr static auto in1 = {1, 2, 3, 4, 5, 5};
    constexpr static auto in2 = {3, 4, 5, 6, 7};
    std::array<int, std::size(in1) + std::size(in2)> out;

    const auto result = std::ranges::merge(in1, in2, out.begin());
    print("in1", in1.begin(), result.in1);
    print("in2", in2.begin(), result.in2);
    print("out", out.begin(), result.out);
}

输出：

in1: 1 2 3 4 5 5
in2: 3 4 5 6 7
out: 1 2 3 3 4 4 5 5 5 6 7

参阅

pair | 实现二元组，即一对值 (类模板)
tuple (C++11) | 实现固定大小的容器，它保有类型可以相异的元素 (类模板)


std::ranges::in_in_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm> |
template<class I1, class I2> struct in_in_result; | (C++20 起)

ranges::in_in_result 是类模板，提供存储二个迭代器为单个单元的方式。

此类模板无基类或显示如下的声明的数据成员，从而它适合用于结果化绑定。

此类模板的所有特殊成员函数均为隐式声明，这使得特化为聚合类，并传播数据成员上的操作的平凡性、潜在抛出性及 constexpr 性质。

模板形参

I1, I2 - ranges::in_in_result 所存储的迭代器类型

数据成员

std::ranges::in_in_result::in1

[[no_unique_address]] I1 in1;

值（假定为迭代器）

std::ranges::in_in_result::in2

[[no_unique_address]] I2 in2;

值（假定为迭代器）

成员函数

std::ranges::in_in_result::operator in_in_result<II1, II2>

template<class II1, class II2>

requires std::convertible_to<const I1&, II1> && std::convertible_to<const I2&, II2>

constexpr operator in_in_result<II1, II2>() const &;
 (1)
template<class II1, class II2>

requires std::convertible_to<I1, II1> && std::convertible_to<I2, II2>

constexpr operator in_in_result<II1, II2>() &&;
 (2)

通过从 *this 的每个数据成员构造结果的对应成员，转换 *this 为结果。

1) 等价于 return {in1, in2}; 。
2) 等价于 return {std::move(in1), std::move(in2)}; 。

标准库

下列标准库函数以 ranges::in_in_result 为返回类型：

算法函数
ranges::mismatch
(C++20)
 寻找两个范围出现不同的首个位置
(niebloid)
ranges::swap_ranges
(C++20)
 交换两个范围的元素
(niebloid)

概要

namespace std::ranges {
    template<class I1, class I2>
    struct in_in_result {
        [[no_unique_address]] I1 in1;
        [[no_unique_address]] I2 in2;

        template<class II1, class II2>
        requires std::convertible_to<const I1&, II1> && std::convertible_to<const I2&, II2>
        constexpr operator in_in_result<II1, II2>() const & {
            return {in1, in2};
        }

        template<class II1, class II2>
        requires std::convertible_to<I1, II1> && std::convertible_to<I2, II2>
        constexpr operator in_in_result<II1, II2>() && {
            return {std::move(in1), std::move(in2)};
        }
    };
}

注解

每个使用此返回类型族的标准库算法声明新的别名类型，例如 using merge_result = in_in_out_result<I1, I2, O>; 。

这些别名族的名称由添加 "_result" 到算法名组成。故 std::ranges::merge 的返回类型能命名为 std::ranges::merge_result 。

不同于 std::pair 与 std::tuple ，此类模板的拥有名字有意义的数据成员。

示例

#include <algorithm>
#include <iostream>
#include <ranges>

int main()
{
    constexpr static auto in1 = {1, 2, 3, 4};
    constexpr static auto in2 = {1, 2, 4, 5};

    constexpr auto result { std::ranges::mismatch(in1, in2) };

    static_assert(2 == std::ranges::distance(in1.begin(), result.in1));
    static_assert(2 == std::ranges::distance(in2.begin(), result.in2));
}

参阅

pair | 实现二元组，即一对值 (类模板)
tuple (C++11) | 实现固定大小的容器，它保有类型可以相异的元素 (类模板)


std::ranges::in_out_out_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm> |
template <class I, class O1, class O2> struct in_out_out_result; | (C++20 起)

ranges::in_out_out_result 是类模板，提供存储三个迭代器为单个单元的方式。

此类模板无基类或显示如下的声明的数据成员，从而它适合用于结果化绑定。

此类模板的所有特殊成员函数均为隐式声明，这使得特化为聚合类，并传播数据成员上的操作的平凡性、潜在抛出性及 constexpr 性质。

模板形参

I, O1, O2 - ranges::in_out_out_result 所存储的对象类型

数据成员

std::ranges::in_out_out_result::in

[[no_unique_address]] I in;

值（假定为迭代器）

std::ranges::in_out_out_result::out1

[[no_unique_address]] O1 out1;

值（假定为迭代器）

std::ranges::in_out_out_result::out2

[[no_unique_address]] O2 out2;

值（假定为迭代器）

成员函数

std::ranges::in_out_out_result::operator in_out_out_result<II, OO1, OO2>

template<class II, class OO1, class OO2>

requires std::convertible_to<const I&, II> &&
std::convertible_to<const O1&, OO1> &&
std::convertible_to<const O2&, OO2>

constexpr operator in_out_out_result<II, OO1, OO2>() const &;
 (1)
template<class II, class OO1, class OO2>

requires std::convertible_to<I, II> &&
std::convertible_to<O1, OO1> &&
std::convertible_to<O2, OO2>

constexpr operator in_out_out_result<II, OO1, OO2>() &&;
 (2)

通过从 *this 的每个数据成员构造结果的对应成员，转换 *this 为结果。

1) 等价于 return {in, out1, out2}; 。
2) 等价于 return {std::move(in), std::move(out1), std::move(out2)}; 。

标准库

下列标准库函数以 ranges::in_out_out_result 为返回类型：

算法函数
ranges::partition_copy
(C++20)
 复制一个范围，将各元素分为二组
(niebloid)

概要

namespace std::ranges {
    template<class I, class O1, class O2>
    struct in_out_out_result {
        [[no_unique_address]] I  in;
        [[no_unique_address]] O1 out1;
        [[no_unique_address]] O2 out2;

        template<class II, class OO1, class OO2>
        requires std::convertible_to<const I&, II> &&
                 std::convertible_to<const O1&, OO1> &&
                 std::convertible_to<const O2&, OO2>
        constexpr operator in_out_out_result<II, OO1, OO2>() const & {
            return {in, out1, out2};
        }

        template<class II, class OO1, class OO2>
        requires std::convertible_to<I, II> &&
                 std::convertible_to<O1, OO1> &&
                 std::convertible_to<O2, OO2>
        constexpr operator in_out_out_result<II, OO1, OO2>() && {
            return {std::move(in), std::move(out1), std::move(out2)};
        }
    };
}

注解

每个使用此返回类型族的标准库算法声明新的别名类型，例如 using merge_result = in_in_out_result<I1, I2, O>; 。

这些别名族的名称由添加 "_result" 到算法名组成。故 std::ranges::merge 的返回类型能命名为 std::ranges::merge_result 。

不同于 std::pair 与 std::tuple ，此类模板的拥有名字有意义的数据成员。

示例

#include <algorithm>
#include <array>
#include <cctype>
#include <iostream>
#include <iterator>
#include <ranges>
#include <string_view>

void print(std::string_view rem, auto first, auto last) {
    for (std::cout << rem << ": { "; first != last; ++first)
        std::cout << *first << ' ';
    std::cout << "}\n";
}

int main()
{
    constexpr std::string_view in{"TvEeNcStOoRr"};
    std::array<char, in.size()> o1, o2;

    const auto result = std::ranges::partition_copy(in, o1.begin(), o2.begin(),
        [](char c){ return std::isupper(c); });

    print("in", in.begin(), result.in);
    print("o1", o1.begin(), result.out1);
    print("o2", o2.begin(), result.out2);
}

输出：

in: { T v E e N c S t O o R r }
o1: { T E N S O R }
o2: { v e c t o r }

参阅

pair | 实现二元组，即一对值 (类模板)
tuple (C++11) | 实现固定大小的容器，它保有类型可以相异的元素 (类模板)


std::ranges::in_out_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm> |
template <class I, class O> struct in_out_result; | (C++20 起)

ranges::in_out_result 是类模板，提供存储二个迭代器为单个单元的方式。

此类模板无基类或显示如下的声明的数据成员，从而它适合用于结果化绑定。

此类模板的所有特殊成员函数均为隐式声明，这使得特化为聚合类，并传播数据成员上的操作的平凡性、潜在抛出性及 constexpr 性质。

模板形参

I, O - ranges::in_out_result 所存储的对象类型

数据成员

std::ranges::in_out_result::in

[[no_unique_address]] I in;

值（假定为迭代器）

std::ranges::in_out_result::out

[[no_unique_address]] O out;

值（假定为迭代器）

成员函数

std::ranges::in_out_result::operator in_out_result<I2, O2>

template<class I2, class O2>

requires std::convertible_to<const I&, I2> && std::convertible_to<const O&, O2>

constexpr operator in_out_result<I2, O2>() const &;
 (1)
template<class I2, class O2>

requires std::convertible_to<I, I2> && std::convertible_to<O, O2>

constexpr operator in_out_result<I2, O2>() &&;
 (2)

通过从 *this 的每个数据成员构造结果的对应成员，转换 *this 为结果。

1) 等价于 return {in, out}; 。
2) 等价于 return {std::move(in), std::move(out)}; 。

标准库

下列标准库函数以 ranges::in_out_result 为返回类型：

算法函数
ranges::copyranges::copy_if
(C++20)(C++20)
 将某一范围的元素复制到一个新的位置
(niebloid)
ranges::copy_n
(C++20)
 将一定数目的元素复制到一个新的位置
(niebloid)
ranges::copy_backward
(C++20)
 按从后往前的顺序复制一个范围内的元素
(niebloid)
ranges::move
(C++20)
 将某一范围的元素移动到一个新的位置
(niebloid)
ranges::move_backword
(C++20)
 按从后往前的顺序移动某一范围的元素到新的位置
(niebloid)
ranges::transform
(C++20)
 将一个函数应用于某一范围的各个元素
(niebloid)
ranges::replace_copyranges::replace_copy_if
(C++20)(C++20)
 复制一个范围内的元素，并将满足特定判别标准的元素替换为另一个值
(niebloid)
ranges::remove_copyranges::remove_copy_if
(C++20)(C++20)
 复制一个范围的元素，忽略满足特定判别标准的元素
(niebloid)
ranges::unique_copy
(C++20)
 创建某范围的不含连续重复元素的副本
(niebloid)
ranges::revserse_copy
(C++20)
 创建一个范围的逆向副本
(niebloid)
ranges::rotate_copy
(C++20)
 复制并旋转元素范围
(niebloid)
ranges::partial_sort_copy
(C++20)
 对范围内的元素进行复制并部分排序
(niebloid)
ranges::set_difference
(C++20)
 计算两个集合的差集
(niebloid)
未初始化内存函数
ranges::uninitialized_copy
(C++20)
 复制元素范围到未初始化的内存区域
(niebloid)
ranges::uninitialized_copy_n
(C++20)
 复制一定量元素到未初始化的内存区域
(niebloid)
ranges::uninitialized_move
(C++20)
 移动对象范围到未初始化的内存区域
(niebloid)
ranges::uninitialized_move_n
(C++20)
 移动一定量对象到未初始化的内存区域
(niebloid)

概要

namespace std::ranges {
    template<class I, class O>
    struct in_out_result {
        [[no_unique_address]] I in;
        [[no_unique_address]] O out;

        template<class I2, class O2>
        requires std::convertible_to<const I&, I2> && std::convertible_to<const O&, O2>
        constexpr operator in_out_result<I2, O2>() const & {
            return {in, out};
        }

        template<class I2, class O2>
        requires std::convertible_to<I, I2> && std::convertible_to<O, O2>
        constexpr operator in_out_result<I2, O2>() && {
            return {std::move(in), std::move(out)};
        }
    };
}

注解

每个使用此返回类型族的标准库算法声明新的别名类型，例如 using merge_result = in_in_out_result<I1, I2, O>; 。

这些别名族的名称由添加 "_result" 到算法名组成。故 std::ranges::merge 的返回类型能命名为 std::ranges::merge_result 。

不同于 std::pair 与 std::tuple ，此类模板的拥有名字有意义的数据成员。

示例

#include <algorithm>
#include <array>
#include <cctype>
#include <iostream>
#include <ranges>

int main()
{
    constexpr char in[] = "transform" "\n";
    std::array<char, sizeof(in)> out;

    const auto result = std::ranges::transform(in, out.begin(),
        [](char c) { return std::toupper(c); });

    auto print = [](char c) { std::cout << c; };
    std::ranges::for_each(std::cbegin(in), result.in, print);
    std::ranges::for_each(out.cbegin(), result.out, print);
}

输出：

transform
TRANSFORM

参阅

pair | 实现二元组，即一对值 (类模板)
tuple (C++11) | 实现固定大小的容器，它保有类型可以相异的元素 (类模板)


std::ranges::min_max_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm> |
template <class T> struct min_max_result; | (C++20 起)

ranges::min_max_result 是类模板，提供存储二个同类型对象或引用为单个单元的方式。

此类模板无基类或显示如下的声明的数据成员，从而它适合用于结果化绑定。

此类模板的所有特殊成员函数均为隐式声明，这使得特化为聚合类，并传播数据成员上的操作的平凡性、潜在抛出性及 constexpr 性质。

模板形参

T - ranges::min_max_result 所存储的对象或引用的类型

数据成员

std::ranges::min_max_result::min

[[no_unique_address]] T min;

可能为到范围中最小元素的引用、指向它的迭代器或其副本。

std::ranges::min_max_result::max

[[no_unique_address]] T max;

可能为到范围中最大元素的引用、指向它的迭代器或其副本。

成员函数

std::ranges::min_max_result::operator min_max_result<T2>

template<class T2>

requires std::convertible_to<const T&, T2>

constexpr operator min_max_result<T2>() const &;
 (1)
template<class T2>

requires std::convertible_to<T, T2>

constexpr operator min_max_result<T2>() &&;
 (2)

通过从 *this 的每个数据成员构造结果的对应成员，转换 *this 为结果。

1) 等价于 return {min, max}; 。
2) 等价于 return {std::move(min), std::move(max)}; 。

标准库

下列标准库函数以 ranges::min_max_result 为返回类型：

算法函数
ranges::minmax
(C++20)
 返回两个元素的较小和较大者
(niebloid)
ranges::minmax_element
(C++20)
 返回范围中的最小和最大元素
(niebloid)

概要

namespace std::ranges {
    template<class T>
    struct min_max_result {
        [[no_unique_address]] T min;
        [[no_unique_address]] T max;

        template<class T2>
        requires std::convertible_to<const T&, T2>
        constexpr operator min_max_result<T2>() const & {
            return {min, max};
        }

        template<class T2>
        requires std::convertible_to<T, T2>
        constexpr operator min_max_result<T2>() && {
            return {std::move(min), std::move(max)};
        }
    };
}

注解

每个使用此返回类型族的标准库算法声明新的别名类型，例如 using merge_result = in_in_out_result<I1, I2, O>; 。

这些别名族的名称由添加 "_result" 到算法名组成。故 std::ranges::merge 的返回类型能命名为 std::ranges::merge_result 。

不同于 std::pair 与 std::tuple ，此类模板的拥有名字有意义的数据成员。

示例

#include <algorithm>
#include <ranges>

int main()
{
    constexpr static auto v = {3, 1, 4, 1, 5, 9, 2};
    {
        constexpr auto result = std::ranges::minmax(v);
        static_assert(1 == result.min && 9 == result.max);
    }
    {
        constexpr auto result = std::ranges::minmax_element(v);
        static_assert(1 == *result.min && 9 == *result.max);
    }
}

参阅

pair | 实现二元组，即一对值 (类模板)
tuple (C++11) | 实现固定大小的容器，它保有类型可以相异的元素 (类模板)


std::ranges::reverse

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::bidirectional_iterator I, std::sentinel_for<I> S >

requires std::permutable<I>
constexpr I

reverse( I first, S last );
 (1) (C++20 起)
template< ranges::bidirectional_range R >

requires std::permutable<ranges::iterator_t<R>>
constexpr ranges::borrowed_iterator_t<R>

reverse( R&& r );
 (2) (C++20 起)
1) 逆转范围 [first, last) 中的元素顺序。
表现如同对每个 0 ≤ i < (last-first)/2 中的整数 i 应用 ranges::iter_swap 到每对迭代器 first+i, last-i-1 。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要逆转的元素范围
r | - | 要逆转的元素范围

返回值

等于 last 的迭代器。

复杂度

准确交换 (last - first)/2 次。

注解

实现（例如 MSVC STL ）可能在迭代器类型实现 contiguous_iterator ，并且交换其值类型不调用非平凡的特殊成员函数或 ADL 所找到的 swap 时启用向量化。

可能的实现

参阅 libstdc++ 与 MSVC STL 中的实现。

struct reverse_fn {
  template<std::bidirectional_iterator I, std::sentinel_for<I> S>
    requires std::permutable<I>
      constexpr I operator()( I first, S last ) const {
          auto last2{ ranges::next(first, last) };
          for (auto tail{ last2 }; !(first == tail or first == --tail); ++first) {
              ranges::iter_swap(first, tail);
          }
          return last2;
      }

  template<ranges::bidirectional_range R>
    requires std::permutable<ranges::iterator_t<R>>
      constexpr ranges::borrowed_iterator_t<R>
        operator()( R&& r ) const {
            return (*this)(ranges::begin(r), ranges::end(r));
        }
};

inline constexpr reverse_fn reverse{};

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <string>

int main()
{
    std::string s{"ABCDEF"};
    std::cout << s << " → ";
    std::ranges::reverse(s.begin(), s.end());
    std::cout << s << " → ";
    std::ranges::reverse(s);
    std::cout << s << " │ ";

    std::array a{1, 2, 3, 4, 5};
    for(auto e : a) { std::cout << e << ' '; }
    std::cout << "→ ";
    std::ranges::reverse(a);
    for(auto e : a) { std::cout << e << ' '; }
    std::cout << '\n';
}

输出：

ABCDEF → FEDCBA → ABCDEF │ 1 2 3 4 5 → 5 4 3 2 1

参阅

ranges::revserse_copy (C++20) | 创建一个范围的逆向副本 (niebloid)
ranges::reverse_viewviews::reverse (C++20) | 以逆序迭代另一双向视图上的元素的 view (类模板) (范围适配器对象)
reverse | 逆转范围中的元素顺序 (函数模板)


std::ranges::reverse_copy, std::ranges::reverse_copy_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::bidirectional_iterator I, std::sentinel_for<I> S,

std::weakly_incrementable O >
requires std::indirectly_copyable<I, O>
constexpr reverse_copy_result<I, O>

reverse_copy( I first, S last, O result );
 (1) (C++20 起)
template< ranges::bidirectional_range R, std::weakly_incrementable O >

requires std::indirectly_copyable<ranges::iterator_t<R>, O>
constexpr reverse_copy_result<ranges::borrowed_iterator_t<R>, O>

reverse_copy( R&& r, O result );
 (2) (C++20 起)
辅助类型
template< class I, class O >
using reverse_copy_result = ranges::in_out_result<I, O>;
 (3) (C++20 起)
1) 从源范围 [first, last) 复制元素到目标范围 [result, result + N) ，其中 N 为 N = ranges::distance(first, last) ，方式使得新范围中的元素处于逆序。表现如同通过对 [0, N) 中的每个整数 i 执行一次赋值 *(result + N - 1 - i) = *(first + i) 。若源与目标范围重叠则行为未定义。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要复制的元素范围
r | - | 要复制的元素范围
result | - | 目标范围的起始

返回值

{last, result + N} 。

复杂度

准确赋值 N 次。

注解

实现（例如 MSVC STL ）可能在两个迭代器类型均实现 contiguous_iterator 并拥有同一值类型，且值类型为可平凡复制 (TriviallyCopyable) 时启用向量化。

可能的实现

参阅 MSVC STL 与 libstdc++ 中的实现。

struct reverse_copy_fn {
  template<std::bidirectional_iterator I, std::sentinel_for<I> S,
           std::weakly_incrementable O>
    requires std::indirectly_copyable<I, O>
      constexpr ranges::reverse_copy_result<I, O>
        operator() ( I first, S last, O result ) const {
            auto ret = ranges::next(first, last);
            for (; last != first; *result = *--last, ++result);
            return {std::move(ret), std::move(result)};
        }

  template<ranges::bidirectional_range R, std::weakly_incrementable O>
    requires std::indirectly_copyable<ranges::iterator_t<R>, O>
      constexpr ranges::reverse_copy_result<ranges::borrowed_iterator_t<R>, O>
        operator() ( R&& r, O result ) const {
          return (*this)(ranges::begin(r), ranges::end(r), std::move(result));
        }
};

inline constexpr reverse_copy_fn reverse_copy{};

示例

#include <algorithm>
#include <iostream>
#include <string>

int main()
{
    std::string x{"12345"}, y(x.size(), ' ');
    std::cout << x << " → ";
    std::ranges::reverse_copy(x.begin(), x.end(), y.begin());
    std::cout << y << " → ";
    std::ranges::reverse_copy(y, x.begin());
    std::cout << x << '\n';
}

输出：

12345 → 54321 → 12345

参阅

ranges::reverse (C++20) | 逆转范围中的元素顺序 (niebloid)
reverse_copy | 创建一个范围的逆向副本 (函数模板)


std::ranges::rotate

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::permutable I, std::sentinel_for<I> S >

constexpr ranges::subrange<I>

rotate( I first, I middle, S last );
 (1) (C++20 起)
template< ranges::forward_range R >

requires std::permutable<ranges::iterator_t<R>>
constexpr ranges::borrowed_subrange_t<R>

rotate( R&& r, ranges::iterator_t<R> middle );
 (2) (C++20 起)
1) 在元素范围上进行左旋。具体而言， ranges::rotate 交换范围 [first, last) 中的元素使得元素 *middle 成为新范围的起始，而 *(middle - 1) 成为新的末元素。
若 [first, last) 不是合法范围或 middle 不在 [first, last) 中则行为未定义。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要旋转的元素范围
r | - | 要旋转的元素范围
middle | - | 指向要出现在旋转后范围起始的元素的迭代器

返回值

{new_first, last} ，其中 new_first 与 ranges::next(first, ranges::distance(middle, last)) 比较相等，并指代 first 所指向的元素的新位置。

复杂度

最坏为线性： ranges::distance(first, last) 次交换。

注解

在常见实现上，若 I 实现 bidirectional_iterator 或（更好的） random_access_iterator 则 ranges::rotate 有更高的效率。

实现（例如 MSVC STL ）可能在迭代器类型实现 contiguous_iterator ，并且交换其值类型不调用非平凡的特殊成员函数或 ADL 所找到的 swap 时启用向量化。

可能的实现

参阅 libstdc++ 与 MSVC STL 中的实现。

struct rotate_fn {
  template<std::permutable I, std::sentinel_for<I> S>
    constexpr ranges::subrange<I>
      operator() ( I first, I middle, S last ) const {
        if (first == middle) {
          auto last_it{std::next(first, last)};
          return {last_it, last_it};
        }
        if (middle == last)
          return {std::move(first), std::move(middle)};

        if constexpr (std::bidirectional_iterator<I>) {
          ranges::reverse(fist, middle);
          auto last_it{ranges::next(first, last)};
          ranges::reverse(middle, last_it);

          if constexpr (std::random_access_iterator<I>) {
            ranges::reverse(first, last_it);
            return {first + (last_it - middle), std::move(last_it)};
          }
          else {
            auto mid_last{last_it};
            do {
              ranges::iter_swap(first, --mid_last);
              ++first;
            }
            while (first != middle && mid_last != middle);
            ranges::reverse(first, mid_last);

            if (first == middle)
              return {std::move(mid_last), std::move(last_it)};
            else
              return {std::move(first), std::move(last_it)};
          }
        }
        else { // I 仅为 forward_iterator
          auto next_it{middle};
          do { // rotate 第一循环
            ranges::iter_swap(first, next_it);
            ++first;
            ++next_it;
            if (first == middle)
              middle = next_it;
          }
          while (next_it != last);

          auto new_first{first};
          while (middle != last) { // rotate 后继循环
            next_it = middle;
            do {
              ranges::iter_swap(first, next_it);
              ++first;
              ++next_it;
              if (first == middle)
                middle = next_it;
            }
            while (next_it != last);
          }

          return {std::move(new_first), std::move(middle)};
        }
      }

  template<ranges::forward_range R>
    requires std::permutable<ranges::iterator_t<R>>
      constexpr ranges::borrowed_subrange_t<R>
        operator() ( R&& r, ranges::iterator_t<R> middle ) const {
          return (*this)(ranges::begin(r), std::move(middle), ranges::end(r));
        }
};

inline constexpr rotate_fn rotate{};

示例

rotate 算法能用作许多其他算法的公共构建块，例如插入排序：

#include <algorithm>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>

int main()
{
    std::string s(16, ' ');

    for (int k{}; k != 5; ++k) {
        std::iota(s.begin(), s.end(), 'A');
        std::ranges::rotate(s, s.begin() + k);
        std::cout << "Rotate left (" << k << "): " << s << '\n';
    }

    std::cout << '\n';

    for (int k{}; k != 5; ++k) {
        std::iota(s.begin(), s.end(), 'A');
        std::ranges::rotate(s, s.end() - k);
        std::cout << "Rotate right (" << k << "): " << s << '\n';
    }

    std::cout << "\n" "Insertion sort using `rotate`, step-by-step:\n";

    s = {'2', '4', '2', '0', '5', '9', '7', '3', '7', '1'};

    for (auto i = s.begin(); i != s.end(); ++i) {
        std::cout << "i = " << std::ranges::distance(s.begin(), i) << ": ";
        std::ranges::rotate(std::ranges::upper_bound(s.begin(), i, *i), i, i + 1);
        std::cout << s << '\n';
    }
    std::cout << (std::ranges::is_sorted(s) ? "Sorted!" : "Not sorted.") << '\n';
}

输出：

Rotate left (0): ABCDEFGHIJKLMNOP
Rotate left (1): BCDEFGHIJKLMNOPA
Rotate left (2): CDEFGHIJKLMNOPAB
Rotate left (3): DEFGHIJKLMNOPABC
Rotate left (4): EFGHIJKLMNOPABCD

Rotate right (0): ABCDEFGHIJKLMNOP
Rotate right (1): PABCDEFGHIJKLMNO
Rotate right (2): OPABCDEFGHIJKLMN
Rotate right (3): NOPABCDEFGHIJKLM
Rotate right (4): MNOPABCDEFGHIJKL

Insertion sort using `rotate`, step-by-step:
i = 0: 2420597371
i = 1: 2420597371
i = 2: 2240597371
i = 3: 0224597371
i = 4: 0224597371
i = 5: 0224597371
i = 6: 0224579371
i = 7: 0223457971
i = 8: 0223457791
i = 9: 0122345779
Sorted!

参阅

ranges::rotate_copy (C++20) | 复制并旋转元素范围 (niebloid)
ranges::reverse (C++20) | 逆转范围中的元素顺序 (niebloid)
rotate | 旋转范围中的元素顺序 (函数模板)


std::ranges::rotate_copy, std::ranges::rotate_copy_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O >

requires std::indirectly_copyable<I, O>
constexpr rotate_copy_result<I, O>

rotate_copy( I first, I middle, S last, O result );
 (1) (C++20 起)
template< ranges::forward_range R, std::weakly_incrementable O >

requires std::indirectly_copyable<ranges::iterator_t<R>, O>
constexpr rotate_copy_result<ranges::borrowed_iterator_t<R>, O>

rotate_copy( R&& r, ranges::iterator_t<R> middle, O result );
 (2) (C++20 起)
辅助类型
template< class I, class O >
using rotate_copy_result = in_out_result<I, O>;
 (3) (C++20 起)
1) 从源范围 [first, last) 复制元素到始于 result 的目标范围，使得元素 *middle 称为目标范围的首个元素，而 *(middle - 1) 成为末元素。结果为目标范围含有源范围的左旋转副本。
若 [first, middle) 或 [middle, last) 不是合法范围，或若源与目标范围重叠，则行为未定义。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要复制的源元素范围
r | - | 要复制的源元素范围
middle | - | 指向应该出现在目标范围起始的元素的迭代器
result | - | 目标范围的起始

返回值

{last, result + N} ，其中 N = ranges::distance(first, last) 。

复杂度

线性：准确赋值 N 次。

注解

若值类型为可平凡复制 (TriviallyCopyable) 且迭代器类型满足 contiguous_iterator ，则 ranges::rotate_copy 的实现通常通过使用如 std::memmove 的“大块复制”函数避免多次赋值。

可能的实现

参阅 libstdc++ 与 MSVC STL 中的实现。

struct rotate_copy_fn {
  template<std::forward_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O>
    requires std::indirectly_copyable<I, O>
    constexpr ranges::rotate_copy_result<I, O>
      operator() ( I first, I middle, S last, O result ) const {
          auto c1{ ranges::copy(middle, std::move(last), std::move(result)) };
          auto c2{ ranges::copy(std::move(first), std::move(middle), std::move(c1.out)) };
          return { std::move(c1.in), std::move(c2.out) };
      }

  template<ranges::forward_range R, std::weakly_incrementable O>
    requires std::indirectly_copyable<ranges::iterator_t<R>, O>
    constexpr ranges::rotate_copy_result<ranges::borrowed_iterator_t<R>, O>
      operator() ( R&& r, ranges::iterator_t<R> middle, O result ) const {
          return (*this)(ranges::begin(r), std::move(middle),
                         ranges::end(r), std::move(result));
      }
};

inline constexpr rotate_copy_fn rotate_copy{};

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> src {1, 2, 3, 4, 5};
    std::vector<int> dest(src.size());
    auto pivot = std::ranges::find(src, 3);

    std::ranges::rotate_copy(src, pivot, dest.begin());
    for (int i : dest) { std::cout << i << ' '; }
    std::cout << '\n';

    // 直接复制旋转结果到 std::cout
    pivot = std::ranges::find(dest, 1);
    std::ranges::rotate_copy(dest, pivot, std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
}

输出：

3 4 5 1 2
1 2 3 4 5

参阅

ranges::rotate (C++20) | 旋转范围中的元素顺序 (niebloid)
ranges::copyranges::copy_if (C++20)(C++20) | 将某一范围的元素复制到一个新的位置 (niebloid)
rotate_copy | 复制并旋转元素范围 (函数模板)


std::ranges::sample

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S,

std::weakly_incrementable O, class Gen >
requires (std::forward_iterator<I> or
std::random_access_iterator<O>) &&
std::indirectly_copyable<I, O> &&
std::uniform_random_bit_generator< std::remove_reference_t <Gen>>

O sample( I first, S last, O out, std::iter_difference_t<I> n, Gen&& gen );
 (1) (C++20 起)
template< ranges::input_range R, std::weakly_incrementable O, class Gen >

requires (ranges::forward_range<R> || std::random_access_iterator<O>) &&
std::indirectly_copyable<ranges::iterator_t<R>, O> &&
std::uniform_random_bit_generator< std::remove_reference_t <Gen>>

O sample( R&& r, O out, ranges::range_difference_t<R> n, Gen&& gen );
 (2) (C++20 起)
1) 从序列 [first, last) 选择 M = min(n, last - first) 个元素（无替代）使得每个可能的样本拥有相等的出现概率，并将那些选择的元素写到始于 out 的范围中。
仅若 I 实现 std::forward_iterator 算法才稳定（保持被选择元素的相对顺序）。
若 out 在 [first, last) 中则行为未定义。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 从中采样的范围（总体）
r | - | 从中采样的范围（总体）
out | - | 用以写入样本的输出迭代器
n | - | 要抽取的样本数
gen | - | 用作随机性源的随机数生成器

返回值

等于 out + M 的迭代器，即结果采样范围的末尾。

复杂度

线性： 𝓞(last - first) 。

注解

此函数可能实现选择抽样或蓄水池抽样。

可能的实现

struct sample_fn {
  template<std::input_iterator I, std::sentinel_for<I> S,
           std::weakly_incrementable O, class Gen>
    requires (std::forward_iterator<I> or
              std::random_access_iterator<O>) &&
              std::indirectly_copyable<I, O> &&
              std::uniform_random_bit_generator<std::remove_reference_t<Gen>>
      O operator()( I first, S last, O out, std::iter_difference_t<I> n, Gen&& gen ) const {
          using diff_t = std::iter_difference_t<I>;
          using distrib_t = std::uniform_int_distribution<diff_t>;
          using param_t = typename distrib_t::param_type;
          distrib_t D{};

          if constexpr (std::forward_iterator<I>) {
              // 此分支保持样本元素“稳定性”
              auto rest {ranges::distance(first, last)};
              for (n = ranges::min(n, rest); n != 0; ++first) {
                  if (D(gen, param_t(0, --rest)) < n) {
                      *out++ = *first;
                      --n;
                  }
              }
              return out;
          } else { // D 为 random_access_iterator
              diff_t sample_size{};
              // 复制 [first, first + M) 元素到“随机访问”输出
              for (; first != last && sample_size != n; ++first) {
                  out[sample_size++] = *first;
              }
              // 以随机选择的值重写某些复制的元素
              for (auto pop_size {sample_size}; first != last; ++first, ++pop_size) {
                  const auto i {D(gen, param_t{0, pop_size})};
                  if (i < n) out[i] = *first;
              }
              return out + sample_size;
          }
      }

  template<ranges::input_range R, std::weakly_incrementable O, class Gen>
    requires (ranges::forward_range<R> or std::random_access_iterator<O>) &&
              std::indirectly_copyable<ranges::iterator_t<R>, O> &&
              std::uniform_random_bit_generator<std::remove_reference_t<Gen>>
      O operator()( R&& r, O out, ranges::range_difference_t<R> n, Gen&& gen ) const {
          return (*this)(ranges::begin(r), ranges::end(r), std::move(out), n,
                         std::forward<Gen>(gen));
      }
};

inline constexpr sample_fn sample{};

示例

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <random>
#include <vector>

void print(auto const& rem, auto const& v) {
    std::cout << rem << " = [" << std::size(v) << "] { ";
    for (auto const& e : v) {
        std::cout << e << ' ';
    }
    std::cout << "}\n";
}

int main()
{
    const auto in = {1, 2, 3, 4, 5, 6};
    print("in", in);

    std::vector<int> out;
    const int max = in.size() + 2;
    auto gen = std::mt19937{std::random_device{}()};

    for (int n{}; n != max; ++n) {
        out.clear();
        std::ranges::sample(in, std::back_inserter(out), n, gen);
        std::cout << "n = " << n;
        print(", out", out);
    }
}

可能的输出：

in = [6] { 1 2 3 4 5 6 }
n = 0, out = [0] { }
n = 1, out = [1] { 5 }
n = 2, out = [2] { 4 5 }
n = 3, out = [3] { 2 3 5 }
n = 4, out = [4] { 2 4 5 6 }
n = 5, out = [5] { 1 2 3 5 6 }
n = 6, out = [6] { 1 2 3 4 5 6 }
n = 7, out = [6] { 1 2 3 4 5 6 }

参阅

ranges::shuffle (C++20) | 随机重排范围中的元素 (niebloid)
sample (C++17) | 从一个序列中随机选择 n 个元素 (函数模板)


std::ranges::search

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I1, std::sentinel_for<I1> S1,

std::forward_iterator I2, std::sentinel_for<I2> S2,
class Pred = ranges::equal_to,
class Proj1 = std::identity,
class Proj2 = std::identity >
requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr ranges::subrange<I1>
search( I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (1) (C++20 起)
template< ranges::forward_range R1, ranges::forward_range R2,

class Pred = ranges::equal_to,
class Proj1 = std::identity,
class Proj2 = std::identity>
requires std::indirectly_comparable<ranges::iterator_t<R1>,
ranges::iterator_t<R2>, Pred, Proj1, Proj2>
constexpr ranges::borrowed_subrange_t<R1>

search( R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {} );
 (2) (C++20 起)
1) 在范围 [first1, last1) 中搜索元素序列 [first2, last2) 的首次出现。在分别用 proj1 与 proj2 投影后用二元谓词 pred 比较元素。
2) 同 (1) ，但以 r1 为第一范围并以 r2 为第二范围，如同以 ranges::begin(r1) 为 first1 ，以 ranges::end(r1) 为 last1 ，以 ranges::begin(r2) 为 first2 ，并以 ranges::end(r2) 为 last2 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 要检验的元素范围（又称草堆）
first2, last2 | - | 要搜索的元素范围（又称针）
r1 | - | 要检验的元素范围（又称草堆）
r2 | - | 要搜索的元素范围（又称针）
pred | - | 应用到投影后元素的谓词
proj1 | - | 应用到第一范围中元素的投影
proj2 | - | 应用到第二范围中元素的投影

返回值

1) 返回作为序列 [first2, last2) （又称针），在分别应用 proj1 与 proj2 到两个序列的元素，再应用二元谓词 pred 比较投影后元素之后，于范围 [first1, last1) （又称草堆）中首次出现的 ranges::subrange 值。

若找不到这种序列，则返回 ranges::subrange{last1, last1} 。

若待搜索范围（又称针）为空，即 first2 == last2 ，则返回 ranges::subrange{first1, first1} 。
2) 同 (1) ，但返回类型为 ranges::borrowed_subrange_t<R1> 。

复杂度

至多应用 S*N 次对应的谓词和各自的投影，其中
(1) S = ranges::distance(first2, last2) 而 N = ranges::distance(first1, last1) ；
(2) S = ranges::distance(r2) 而 N = ranges::distance(r1) 。

可能的实现

struct search_fn
{
  template<std::forward_iterator I1, std::sentinel_for<I1> S1,
         std::forward_iterator I2, std::sentinel_for<I2> S2,
         class Pred = ranges::equal_to,
         class Proj1 = std::identity,
         class Proj2 = std::identity>
  requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  constexpr ranges::subrange<I1>
    operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
               Proj1 proj1 = {}, Proj2 proj2 = {}) const {
        for (;; ++first1) {
          I1 it1 = first1;
          for (I2 it2 = first2;; ++it1, ++it2) {
            if (it2 == last2) return {first1, it1};
            if (it1 == last1) return {it1, it1};
            if (!std::invoke(pred, std::invoke(proj1, *it1), std::invoke(proj2, *it2)))
              break;
          }
        }
    }

  template<ranges::forward_range R1, ranges::forward_range R2,
         class Pred = ranges::equal_to,
         class Proj1 = std::identity,
         class Proj2 = std::identity>
  requires std::indirectly_comparable<ranges::iterator_t<R1>,
                                      ranges::iterator_t<R2>, Pred, Proj1, Proj2>
  constexpr ranges::borrowed_subrange_t<R1>
    operator()(R1&& r1, R2&& r2, Pred pred = {},
               Proj1 proj1 = {}, Proj2 proj2 = {}) const {
      return (*this)(ranges::begin(r1), ranges::end(r1),
                     ranges::begin(r2), ranges::end(r2),
                     std::move(pred), std::move(proj1), std::move(proj2));
    }
};

inline constexpr search_fn search{};

示例

#include <algorithm>
#include <cctype>
#include <iostream>
#include <iterator>
#include <string_view>

using namespace std::literals;

void print(int id, const auto& haystack, const auto& needle, const auto& found) {
    std::cout << id << "). search(\"" << haystack << "\", \"" << needle << "\"); ";
    const auto first = std::distance(haystack.begin(), found.begin());
    const auto last = std::distance(haystack.begin(), found.end());
    if (found.empty()) {
        std::cout << "not found;";
    } else {
        std::cout << "found: \"";
        for (const auto x: found) { std::cout << x; }
        std::cout << "\";";
    }
    std::cout << " subrange: {" << first << ", " << last << "}\n";
}

int main()
{
    constexpr auto haystack {"abcd abcd"sv};
    constexpr auto needle {"bcd"sv};

    // 搜索使用迭代器对 begin()/end() ：
    constexpr auto found1 = std::ranges::search(
        haystack.begin(), haystack.end(),
        needle.begin(), needle.end());
    print(1, haystack, needle, found1);

    // 搜索使用范围 r1、 r2 ：
    constexpr auto found2 = std::ranges::search(haystack, needle);
    print(2, haystack, needle, found2);

    // ‘针’范围为空：
    constexpr auto none {""sv};
    constexpr auto found3 = std::ranges::search(haystack, none);
    print(3, haystack, none, found3);

    // 不会找到‘针’范围：
    constexpr auto awl {"efg"sv};
    constexpr auto found4 = std::ranges::search(haystack, awl);
    print(4, haystack, awl, found4);

    // 搜索使用定制比较器与投影：
    constexpr auto bodkin {"234"sv};
    auto found5 = std::ranges::search(haystack, bodkin,
        [](const int x, const int y) { return x == y; }, // pred
        [](const int x) { return std::toupper(x); }, // proj1
        [](const int y) { return y + 'A' - '1'; } // proj2
        );
    print(5, haystack, bodkin, found5);
}

输出：

1). search("abcd abcd", "bcd"); found: "bcd"; subrange: {1, 4}
2). search("abcd abcd", "bcd"); found: "bcd"; subrange: {1, 4}
3). search("abcd abcd", ""); not found; subrange: {0, 0}
4). search("abcd abcd", "efg"); not found; subrange: {9, 9}
5). search("abcd abcd", "234"); found: "bcd"; subrange: {1, 4}

参阅

ranges::adjacent_find (C++20) | 查找首对相邻的相同（或满足给定谓词的）元素 (niebloid)
ranges::findranges::find_ifranges::find_if_not (C++20)(C++20)(C++20) | 寻找首个满足特定判别标准的元素 (niebloid)
ranges::find_end (C++20) | 在特定范围中寻找最后出现的元素序列 (niebloid)
ranges::find_first_of (C++20) | 搜索元素集合中的任一元素 (niebloid)
ranges::includes (C++20) | 若一个序列是另一个的子列则返回 true (niebloid)
ranges::mismatch (C++20) | 寻找两个范围出现不同的首个位置 (niebloid)
ranges::search_n (C++20) | 在范围中搜索一定量的某个元素的连续副本 (niebloid)
search | 搜索一个元素范围 (函数模板)


std::ranges::search_n

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I, std::sentinel_for<I> S, class T,

class Pred = ranges::equal_to, class Proj = std::identity >
requires std::indirectly_comparable<I, const T*, Pred, Proj>
constexpr ranges::subrange<I>
search_n( I first, S last, std::iter_difference_t<I> count,

const T& value, Pred pred = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::forward_range R, class T, class Pred = ranges::equal_to,

class Proj = std::identity >
requires std::indirectly_comparable<ranges::iterator_t<R>, const T*, Pred, Proj>
constexpr ranges::borrowed_subrange_t<R>
search_n( R&& r, ranges::range_difference_t<R> count,

const T& value, Pred pred = {}, Proj proj = {} );
 (2) (C++20 起)
1) 在范围 [first, last) 中搜索首个 count 元素的序列，其投影后的值按照二元谓词 pred 等于给定的值 value 。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要检验的元素范围（又称草堆）
r | - | 要检验的元素范围（又称草堆）
count | - | 要搜索的序列长度
value | - | 要搜索的值（又称针）
pred | - | 比较投影后元素与 value 的二元谓词
proj | - | 应用到要检验的范围的元素的投影

返回值

1) 返回含有范围 [first, last) 中指代找到的序列的一对迭代器的 std::ranges::subrange 。

若找不到这种序列，则返回 std::ranges::subrange{last, last} 。

若 count ≤ 0 则返回 std::ranges::subrange{first, first} 。
2) 同 (1) ，但返回类型为 ranges::borrowed_subrange_t<R> 。

复杂度

线性：至多应用 ranges::distance(first, last) 次谓词与投影。

注解

若迭代器实现 std::random_access_iterator 则实现可以提升平均搜索效率。

可能的实现

struct search_n_fn
{
  template<std::forward_iterator I, std::sentinel_for<I> S, class T,
           class Pred = ranges::equal_to, class Proj = std::identity>
    requires std::indirectly_comparable<I, const T*, Pred, Proj>
      constexpr ranges::subrange<I>
        operator()(I first, S last, std::iter_difference_t<I> count,
                   const T& value, Pred pred = {}, Proj proj = {}) const {
          if (count <= 0)
            return {first, first};
          for (; first != last; ++first) {
            if (std::invoke(pred, std::invoke(proj, *first), value)) {
              I start = first;
              std::iter_difference_t<I> n{1};
              for (;;) {
                if (n++ == count)
                  return {start, std::next(first)}; // 找到
                if (++first == last)
                  return {first, first}; // 找不到
                if (!std::invoke(pred, std::invoke(proj, *first), value))
                  break; // not equ to value
              }
            }
          }
          return {first, first};
        }

  template<ranges::forward_range R, class T, class Pred = ranges::equal_to,
           class Proj = std::identity>
    requires std::indirectly_comparable<ranges::iterator_t<R>, const T*, Pred, Proj>
      constexpr ranges::borrowed_subrange_t<R>
        operator()(R&& r, ranges::range_difference_t<R> count,
                   const T& value, Pred pred = {}, Proj proj = {}) const {
            return (*this)(ranges::begin(r), ranges::end(r),
                           std::move(count), value,
                           std::move(pred), std::move(proj));
        }
};

inline constexpr search_n_fn search_n{};

示例

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <string>

int main()
{
    static constexpr auto nums = {1, 2, 2, 3, 4, 1, 2, 2, 2, 1};
    constexpr int count{ 3 };
    constexpr int value{ 2 };

    constexpr auto result1 = std::ranges::search_n(
        nums.begin(), nums.end(), count, value
    );
    static_assert( // 找到
        result1.size() == count &&
        std::distance(nums.begin(), result1.begin()) == 6 &&
        std::distance(nums.begin(), result1.end()) == 9
    );

    constexpr auto result2 = std::ranges::search_n(nums, count, value);
    static_assert( // 找到
        result2.size() == count &&
        std::distance(nums.begin(), result2.begin()) == 6 &&
        std::distance(nums.begin(), result2.end()) == 9
    );

    constexpr auto result3 = std::ranges::search_n(nums, count, /* value */ 5);
    static_assert( // 找不到
        result3.size() == 0 &&
        result3.begin() == result3.end() &&
        result3.end() == nums.end()
    );

    constexpr auto result4 = std::ranges::search_n(nums, /* count */ 0, /* value */ 1);
    static_assert( // 找不到
        result4.size() == 0 &&
        result4.begin() == result4.end() &&
        result4.end() == nums.begin()
    );

    constexpr char symbol{'B'};
    std::cout << std::boolalpha << "Find a sub-sequence: "
              << std::quoted(std::string(count, symbol)) << '\n';

    auto result5 = std::ranges::search_n(nums, count, symbol,
        [](const char x, const char y) { // 二元谓词
            const bool o{ x == y };
            std::cout << "bin_op(" << x << ", " << y << ") == " << o << "\n";
            return o;
        },
        [](const int z) { return 'A' + z - 1; } // 投影数字 -> ASCII
    );

    std::cout << "Found: " << !result5.empty() << '\n';
}

输出：

Find a sub-sequence: "BBB"
bin_op(A, B) == false
bin_op(B, B) == true
bin_op(B, B) == true
bin_op(C, B) == false
bin_op(D, B) == false
bin_op(A, B) == false
bin_op(B, B) == true
bin_op(B, B) == true
bin_op(B, B) == true
Found: true

参阅

ranges::adjacent_find (C++20) | 查找首对相邻的相同（或满足给定谓词的）元素 (niebloid)
ranges::findranges::find_ifranges::find_if_not (C++20)(C++20)(C++20) | 寻找首个满足特定判别标准的元素 (niebloid)
ranges::find_end (C++20) | 在特定范围中寻找最后出现的元素序列 (niebloid)
ranges::find_first_of (C++20) | 搜索元素集合中的任一元素 (niebloid)
ranges::includes (C++20) | 若一个序列是另一个的子列则返回 true (niebloid)
ranges::mismatch (C++20) | 寻找两个范围出现不同的首个位置 (niebloid)
ranges::search (C++20) | 搜索一个元素范围 (niebloid)
search_n | 在范围中搜索一定量的某个元素的连续副本 (函数模板)


std::ranges::set_difference, std::ranges::set_difference_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I1, std::sentinel_for<I1> S1,

std::input_iterator I2, std::sentinel_for<I2> S2,
std::weakly_incrementable O, class Comp = ranges::less,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::mergeable<I1, I2, O, Comp, Proj1, Proj2>
constexpr set_difference_result<I1, O>
set_difference( I1 first1, S1 last1, I2 first2, S2 last2,
O result, Comp comp = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (1) (C++20 起)
template< ranges::input_range R1, ranges::input_range R2,

std::weakly_incrementable O, class Comp = ranges::less,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::mergeable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
O, Comp, Proj1, Proj2>
constexpr set_difference_result<ranges::borrowed_iterator_t<R1>, O>
set_difference( R1&& r1, R2&& r2, O result, Comp comp = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (2) (C++20 起)
辅助类型
template<class I, class O>
using set_difference_result = ranges::in_out_result<I, O>;
 (3) (C++20 起)

从已排序的输入范围 [first1, last1) 赋值在已排序的输入范围 [first2, last2) 中找不到的元素到始于 result 的输出范围。

若

  • 输入范围未分别相对于 comp 与 proj1 或 proj2 排序，或
  • 结果范围与任一输入范围重叠，

则行为未定义。

1) 用给定的二元比较函数 comp 比较元素。
2) 同 (1) ，但以 r1 为第一范围，并以 r2 为第二范围，如同以 ranges::begin(r1) 为 first1 ，以 ranges::end(r1) 为 last1 ，以 ranges::begin(r2) 为 first2 ，并以 ranges::end(r2) 为 last2 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 第一已排序输入范围
first2, last2 | - | 第二已排序输入范围
r1 | - | 第一已排序输入范围
r2 | - | 第二已排序输入范围
result | - | 目标范围的起始
comp | - | 应用到投影后元素的比较器
proj1 | - | 应用到第一范围元素的投影
proj2 | - | 应用到第二范围元素的投影

返回值

{last1, result_last} ，其中 result_last 为被构造范围末尾。

复杂度

至多比较和应用每个投影 \(\scriptsize 2\cdot(N_1+N_2)-1\)2·(N
1+N
2)-1 次，其中 \(\scriptsize N_1\)N
1 与 \(\scriptsize N_2\)N
2 分别为 ranges::distance(first1, last1) 与 ranges::distance(first2, last2) 。

可能的实现

struct set_difference_fn {
    template< std::input_iterator I1, std::sentinel_for<I1> S1,
              std::input_iterator I2, std::sentinel_for<I2> S2,
              std::weakly_incrementable O, class Comp = ranges::less,
              class Proj1 = std::identity, class Proj2 = std::identity >
    requires std::mergeable<I1, I2, O, Comp, Proj1, Proj2>
    constexpr ranges::set_difference_result<I1, O>
    operator()( I1 first1, S1 last1, I2 first2, S2 last2,
                O result, Comp comp = {},
                Proj1 proj1 = {}, Proj2 proj2 = {} ) const {
        while (!(first1 == last1 or first2 == last2)) {
            if (std::invoke(comp, std::invoke(proj1, *first1),
                                  std::invoke(proj2, *first2))) {
                *result = *first1; ++first1; ++result;
            }
            else if (std::invoke(comp, std::invoke(proj2, *first2),
                                 std::invoke(proj1, *first1))) {
                ++first2;
            }
            else {
                ++first1; ++first2;
            }
        }
        return ranges::copy(std::move(first1), std::move(last1), std::move(result));
    }

    template< ranges::input_range R1, ranges::input_range R2,
              std::weakly_incrementable O, class Comp = ranges::less,
              class Proj1 = std::identity, class Proj2 = std::identity >
    requires std::mergeable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
             O, Comp, Proj1, Proj2>
    constexpr ranges::set_difference_result<
              ranges::borrowed_iterator_t<R1>, O>
    operator()( R1&& r1, R2&& r2, O result, Comp comp = {},
                Proj1 proj1 = {}, Proj2 proj2 = {} ) const {
        return (*this)(ranges::begin(r1), ranges::end(r1),
                       ranges::begin(r2), ranges::end(r2),
                       std::move(result), std::move(comp),
                       std::move(proj1), std::move(proj2));
    }
};

inline constexpr set_difference_fn set_difference{};

示例

#include <algorithm>
#include <cassert>
#include <iostream>
#include <iterator>
#include <string_view>
#include <vector>

auto print = [](const auto& v, std::string_view end = "") {
    for (std::cout << "{ "; auto i : v) std::cout << i << ' ';
    std::cout << "} " << end;
};

struct Order // 拥有非常有趣的数据的类
{
    int order_id;

    friend std::ostream& operator<<(std::ostream& os, const Order& ord) {
        return os << "{" << ord.order_id << "},";
    }
};

int main()
{
    const auto v1 = {1, 2, 5, 5, 5, 9};
    const auto v2 = {2, 5, 7};
    std::vector<int> diff;

    std::ranges::set_difference(v1, v2, std::back_inserter(diff));
    print(v1, "∖ ");
    print(v2, "= ");
    print(diff, "\n");

    // 我们想知道哪些顺序在旧和新状态之间“改变了”：
    const std::vector<Order> old_orders { {1}, {2}, {5}, {9}, };
    const std::vector<Order> new_orders { {2}, {5}, {7}, };
    std::vector<Order> cut_orders(old_orders.size() + new_orders.size());

    auto [old_orders_end, cut_orders_last] =
        std::ranges::set_difference(old_orders, new_orders,
                                    cut_orders.begin(), {},
                                    &Order::order_id, &Order::order_id);
    assert(old_orders_end == old_orders.end());

    std::cout << "old orders = "; print(old_orders, "\n");
    std::cout << "new orders = "; print(new_orders, "\n");
    std::cout << "cut orders = "; print(cut_orders, "\n");
    cut_orders.erase(cut_orders_last, end(cut_orders));
    std::cout << "cut orders = "; print(cut_orders, "\n");
}

输出：

{ 1 2 5 5 5 9 } ∖ { 2 5 7 } = { 1 5 5 9 }
old orders = { {1}, {2}, {5}, {9}, }
new orders = { {2}, {5}, {7}, }
cut orders = { {1}, {9}, {0}, {0}, {0}, {0}, {0}, }
cut orders = { {1}, {9}, }

参阅

ranges::set_union (C++20) | 计算两个集合的并集 (niebloid)
ranges::set_intersection (C++20) | 计算两个集合的交集 (niebloid)
ranges::set_symmetric_difference (C++20) | 计算两个集合的对称差 (niebloid)
ranges::includes (C++20) | 若一个序列是另一个的子列则返回 true (niebloid)
set_difference | 计算两个集合的差集 (函数模板)


std::ranges::set_intersection, std::ranges::set_intersection_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I1, std::sentinel_for<I1> S1,

std::input_iterator I2, std::sentinel_for<I2> S2,
std::weakly_incrementable O, class Comp = ranges::less,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::mergeable<I1, I2, O, Comp, Proj1, Proj2>
constexpr set_intersection_result<I1, I2, O>
set_intersection( I1 first1, S1 last1, I2 first2, S2 last2,
O result, Comp comp = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (1) (C++20 起)
template< ranges::input_range R1, ranges::input_range R2,

std::weakly_incrementable O, class Comp = ranges::less,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::mergeable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
O, Comp, Proj1, Proj2>
constexpr set_intersection_result<ranges::borrowed_iterator_t<R1>,
ranges::borrowed_iterator_t<R2>, O>
set_intersection( R1&& r1, R2&& r2, O result, Comp comp = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (2) (C++20 起)
辅助类型
template< class I1, class I2, class O >
using set_intersection_result = ranges::in_in_out_result<I1, I2, O>;
 (3) (C++20 起)

构造一个开始于 result 的，由同时可以在两个已排序的范围 [first1, last1) 和 [first2, last2) 当中找到的元素组成的已排序范围。如果某个元素可以在 [first1, last1) 找到 m 次，在 [first2, last2) 找到 n 次，则会从第一个范围中拷贝开头的 min(m, n) 个元素到 result 。等价元素的先后序列会保持不变。

行为未定义，如果

  • 输入的范围并没有分别相对于 comp 和 proj1 或 proj2 排序，或
  • 生成的范围和任一输入范围重叠。
1) 使用二元比较函数 comp 比较元素。
2) 如同 (1) ，但以 r1 为第一个范围并以 r2 为第二个范围, 如同以 ranges::begin(r1) 为 first1 ，以 ranges::end(r1) 为 last1 ，以 ranges::begin(r2) 为 first2 ，并以 ranges::end(r2) 为 last2 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 迭代器-哨位对，代表输入的第一个已排序的范围
first2, last2 | - | 迭代器-哨位对，代表输入的第二个已排序的范围
r1 | - | 第一个已排序的范围
r2 | - | 第二个已排序的范围
result | - | 输出范围的起始
comp | - | 对投影后的元素使用的比较
proj1 | - | 对第一个范围的元素使用的投影
proj2 | - | 对第二个范围的元素使用的投影

返回值

{last1, last2, result_last} ，其中 result_last 是被构造的范围的终点。

复杂度

最多 \(\scriptsize 2\cdot(N_1+N_2)-1\)2·(N
1+N
2)-1 次比较与对投影的应用，其中 \(\scriptsize N_1\)N
1 和\(\scriptsize N_2\)N
2 分别是 ranges::distance(first1, last1) 和 ranges::distance(first2, last2) 。

可能的实现

struct set_intersection_fn {
    template< std::input_iterator I1, std::sentinel_for<I1> S1,
              std::input_iterator I2, std::sentinel_for<I2> S2,
              std::weakly_incrementable O, class Comp = ranges::less,
              class Proj1 = std::identity, class Proj2 = std::identity >
    requires std::mergeable<I1, I2, O, Comp, Proj1, Proj2>
    constexpr ranges::set_union_result<I1, I2, O>
    operator()( I1 first1, S1 last1, I2 first2, S2 last2,
                O result, Comp comp = {},
                Proj1 proj1 = {}, Proj2 proj2 = {} ) const {
        while (!(first1 == last1 or first2 == last2)) {
            if (std::invoke(comp, std::invoke(proj1, *first1), std::invoke(proj2, *first2)))
                ++first1;
            else if (std::invoke(comp, std::invoke(proj2, *first2), std::invoke(proj1, *first1)))
                ++first2;
            else
                *result = *first1, ++first1, ++first2, ++result;
        }
        return {ranges::next(std::move(first1), std::move(last1)),
                ranges::next(std::move(first2), std::move(last2)),
                std::move(result)};
    }

    template< ranges::input_range R1, ranges::input_range R2,
              std::weakly_incrementable O, class Comp = ranges::less,
              class Proj1 = std::identity, class Proj2 = std::identity >
    requires std::mergeable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
             O, Comp, Proj1, Proj2>
    constexpr ranges::set_intersection_result<ranges::borrowed_iterator_t<R1>,
              ranges::borrowed_iterator_t<R2>, O>
    operator()( R1&& r1, R2&& r2, O result, Comp comp = {},
                Proj1 proj1 = {}, Proj2 proj2 = {} ) const {
        return (*this)(ranges::begin(r1), ranges::end(r1),
                       ranges::begin(r2), ranges::end(r2),
                       std::move(result), std::move(comp),
                       std::move(proj1), std::move(proj2));
    }
};

inline constexpr set_intersection_fn set_intersection{};

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

void print(const auto& v, const auto& rem) {
    std::cout << "{ ";
    for (const auto& e : v)
        std::cout << e << ' ';
    std::cout << "}" << rem;
}

int main()
{
    const auto in1 = {1, 2, 2, 3, 4, 5, 6 };
    const auto in2 = {2, 2, 3, 3, 5, 7};
    std::vector<int> out;

    std::ranges::set_intersection(in1, in2, std::back_inserter(out));

    print(in1, " ∩ "), print(in2, " = "), print(out, "\n");
}

输出：

{ 1 2 2 3 4 5 6 } ∩ { 2 2 3 3 5 7 } = { 2 2 3 5 }

参阅

ranges::set_union (C++20) | 计算两个集合的并集 (niebloid)
ranges::set_difference (C++20) | 计算两个集合的差集 (niebloid)
ranges::set_symmetric_difference (C++20) | 计算两个集合的对称差 (niebloid)
ranges::includes (C++20) | 若一个序列是另一个的子列则返回 true (niebloid)
set_intersection | 计算两个集合的交集 (函数模板)


std::ranges::set_symmetric_difference, std::ranges::set_symmetric_difference_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I1, std::sentinel_for<I1> S1,

std::input_iterator I2, std::sentinel_for<I2> S2,
std::weakly_incrementable O, class Comp = ranges::less,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::mergeable<I1, I2, O, Comp, Proj1, Proj2>
constexpr set_symmetric_difference_result<I1, I2, O>
set_symmetric_difference( I1 first1, S1 last1, I2 first2, S2 last2,
O result, Comp comp = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (1) (C++20 起)
template< ranges::input_range R1, ranges::input_range R2,

std::weakly_incrementable O, class Comp = ranges::less,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::mergeable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
O, Comp, Proj1, Proj2>
constexpr set_symmetric_difference_result<ranges::borrowed_iterator_t<R1>,
ranges::borrowed_iterator_t<R2>, O>
set_symmetric_difference( R1&& r1, R2&& r2, O result, Comp comp = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (2) (C++20 起)
辅助类型
template<class I1, class I2, class O>
using set_symmetric_difference_result = ranges::in_in_out_result<I1, I2, O>;
 (3) (C++20 起)

计算二个已排序范围的对称差：赋值在一个但非两个范围中找到的元素到始于 result 的范围。结果范围亦已排序。

若在 [first1, last1) 中找到某元素 m 次并在 [first2, last2) 中找到 n 次，则它将被准确复制 │m-n│ 次到 result 。若 m>n ，则从 [first1,last1) 复制最后 m-n 个这些元素，否则从 [first2,last2) 复制最后 n-m 个元素。结果范围不能与任一输入范围重叠。

若

  • 输入范围未分别相对于 comp 与 proj1 或 proj2 排序，或
  • 结果范围与任一输入范围重叠，

则行为未定义。

1) 用给定的二元比较函数 comp 比较元素。
2) 同 (1) ，但以 r1 为第一范围，并以 r2 为第二范围，如同以 ranges::begin(r1) 为 first1 ，以 ranges::end(r1) 为 last1 ，以 ranges::begin(r2) 为 first2 ，并以 ranges::end(r2) 为 last2 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 第一已排序输入范围
first2, last2 | - | 第二已排序输入范围
r1 | - | 第一已排序输入范围
r2 | - | 第二已排序输入范围
result | - | 目标范围的起始
comp | - | 应用到投影后元素的比较器
proj1 | - | 应用到第一范围元素的投影
proj2 | - | 应用到第二范围元素的投影

返回值

{last1, result_last} ，其中 result_last 为被构造范围末尾。

复杂度

至多比较和应用每个投影 \(\scriptsize 2\cdot(N_1+N_2)-1\)2·(N
1+N
2)-1 次，其中 \(\scriptsize N_1\)N
1 与 \(\scriptsize N_2\)N
2 分别为 ranges::distance(first1, last1) 与 ranges::distance(first2, last2) 。

可能的实现

struct set_symmetric_difference_fn {
    template< std::input_iterator I1, std::sentinel_for<I1> S1,
              std::input_iterator I2, std::sentinel_for<I2> S2,
              std::weakly_incrementable O, class Comp = ranges::less,
              class Proj1 = std::identity, class Proj2 = std::identity >
    requires std::mergeable<I1, I2, O, Comp, Proj1, Proj2>
    constexpr ranges::set_symmetric_difference_result<I1, I2, O>
    operator()( I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {},
                Proj1 proj1 = {}, Proj2 proj2 = {} ) const {
        while (!(first1 == last1 or first2 == last2)) {
            if (std::invoke(comp, std::invoke(proj1, *first1),
                                  std::invoke(proj2, *first2))) {
                *result = *first1; ++first1; ++result;
            }
            else if (std::invoke(comp, std::invoke(proj2, *first2),
                                       std::invoke(proj1, *first1))) {
                *result = *first2; ++first2; ++result;
            }
            else {
                ++first1; ++first2;
            }
        }
        auto res1 {ranges::copy(std::move(first1), std::move(last1), std::move(result))};
        auto res2 {ranges::copy(std::move(first2), std::move(last2), std::move(res1.out))};
        return {std::move(res1.in), std::move(res2.in), std::move(res2.out)};
    }

    template< ranges::input_range R1, ranges::input_range R2,
              std::weakly_incrementable O, class Comp = ranges::less,
              class Proj1 = std::identity, class Proj2 = std::identity >
    requires std::mergeable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
             O, Comp, Proj1, Proj2>
    constexpr ranges::set_symmetric_difference_result<
              ranges::borrowed_iterator_t<R1>, ranges::borrowed_iterator_t<R2>, O>
    operator()( R1&& r1, R2&& r2, O result, Comp comp = {},
                Proj1 proj1 = {}, Proj2 proj2 = {} ) const {
        return (*this)(ranges::begin(r1), ranges::end(r1),
                       ranges::begin(r2), ranges::end(r2),
                       std::move(result), std::move(comp),
                       std::move(proj1), std::move(proj2));
    }
};

inline constexpr set_symmetric_difference_fn set_symmetric_difference{};

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

void visualize_this(const auto& v, int min = 1, int max = 9) {
    for (auto i{min}; i <= max; ++i) {
        std::ranges::binary_search(v, i) ? std::cout << i : std::cout << '.';
        std::cout << ' ';
    }
    std::cout << '\n';
}

int main()
{
    const auto in1 = {1, 3, 4,    6, 7, 9};
    const auto in2 = {1,    4, 5, 6,    9};

    std::vector<int> out;

    std::ranges::set_symmetric_difference(in1, in2, std::back_inserter(out));

    visualize_this(in1);
    visualize_this(in2);
    visualize_this(out);
}

输出：

1 . 3 4 . 6 7 . 9
1 . . 4 5 6 . . 9
. . 3 . 5 . 7 . .

参阅

ranges::set_union (C++20) | 计算两个集合的并集 (niebloid)
ranges::set_difference (C++20) | 计算两个集合的差集 (niebloid)
ranges::set_intersection (C++20) | 计算两个集合的交集 (niebloid)
ranges::includes (C++20) | 若一个序列是另一个的子列则返回 true (niebloid)
set_symmetric_difference | 计算两个集合的对称差 (函数模板)


std::ranges::set_union, std::ranges::set_union_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I1, std::sentinel_for<I1> S1,

std::input_iterator I2, std::sentinel_for<I2> S2,
std::weakly_incrementable O, class Comp = ranges::less,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::mergeable<I1, I2, O, Comp, Proj1, Proj2>
constexpr set_union_result<I1, I2, O>
set_union( I1 first1, S1 last1, I2 first2, S2 last2,
O result, Comp comp = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (1) (C++20 起)
template< ranges::input_range R1, ranges::input_range R2,

std::weakly_incrementable O, class Comp = ranges::less,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::mergeable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
O, Comp, Proj1, Proj2>
constexpr set_union_result<ranges::borrowed_iterator_t<R1>,
ranges::borrowed_iterator_t<R2>, O>
set_union( R1&& r1, R2&& r2, O result, Comp comp = {},

Proj1 proj1 = {}, Proj2 proj2 = {} );
 (2) (C++20 起)
辅助类型
template<class I1, class I2, class O>
using set_union_result = ranges::in_in_out_result<I1, I2, O>;
 (3) (C++20 起)

构造始于 result 的，由来自一或两个已排序的输入范围 [first1, last1) 与 [first2, last2) 的元素组成的已排序范围。

若在 [first1, last1) 中找到 m 次并在 [first2, last2) 中找到 n 次某元素，则将从 [first1, last1) 复制 m 个元素到 result ，保持顺序，然后将从 [first2, last2) 复制恰好 max(n-m, 0) 个元素到 result ，亦保持顺序。

若

  • 输入范围未分别按 comp 和 proj1 或 proj2 排序，或
  • 输入范围与输出范围重叠，

则行为未定义。

1) 用给定的二元比较函数 comp 比较元素。
2) 同 (1) ，但以 r1 为第一范围并以 r2 为第二范围，如同以 ranges::begin(r1) 为 first1 ，以 ranges::end(r1) 为 last1 ，以 ranges::begin(r2) 为 first2 并以 ranges::end(r2) 为 last2 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 第一已排序输入范围
first2, last2 | - | 第二已排序输入范围
r1 | - | 第一已排序输入范围
r2 | - | 第二已排序输入范围
result | - | 输出范围的起始
comp | - | 应用到投影后元素的谓词
proj1 | - | 应用到第一范围元素的投影
proj2 | - | 应用到第二范围元素的投影

返回值

{last1, last2, result_last} ，其中 result_last 为构造的范围的末尾。

复杂度

至多比较和应用每个投影 \(\scriptsize 2\cdot(N_1+N_2)-1\)2·(N
1+N
2)-1 次，其中 \(\scriptsize N_1\)N
1 与 \(\scriptsize N_2\)N
2 分别为 ranges::distance(first1, last1) 与 ranges::distance(first2, last2) 。

注解

此算法进行与 ranges::merge 所做的类似的任务。两者都消费已排序的输入范围并产生拥有来自两个范围的元素的已排序输出。这两个算法间的区别是处理来自两个输入范围的比较等价的值（见可小于比较 (LessThanComparable) 上的注解）。若任何等价的值在第一范围中出现 n 次，在第二范围出现 m ，则 ranges::merge 将输出所有 n+m 次出现，而 ranges::set_union 会只输出 std::max (n, m) 次。故 ranges::merge 准确地输出 \(\scriptsize (N_1+N_2)\)(N
1+N
2) 个值，而 ranges::set_union 可能产生较少的值。

可能的实现

struct set_union_fn {
    template< std::input_iterator I1, std::sentinel_for<I1> S1,
              std::input_iterator I2, std::sentinel_for<I2> S2,
              std::weakly_incrementable O, class Comp = ranges::less,
              class Proj1 = std::identity, class Proj2 = std::identity >
    requires std::mergeable<I1, I2, O, Comp, Proj1, Proj2>
    constexpr ranges::set_union_result<I1, I2, O>
    operator()( I1 first1, S1 last1, I2 first2, S2 last2,
                O result, Comp comp = {},
                Proj1 proj1 = {}, Proj2 proj2 = {} ) const {
        for (; !(first1 == last1 or first2 == last2); ++result) {
            if (std::invoke(comp, std::invoke(proj1, *first1),
                                  std::invoke(proj2, *first2))) {
                *result = *first1; ++first1;
            }
            else if (std::invoke(comp, std::invoke(proj2, *first2),
                                       std::invoke(proj1, *first1))) {
                *result = *first2; ++first2;
            }
            else {
                *result = *first1; ++first1; ++first2;
            }
        }
        auto res1 = ranges::copy(std::move(first1), std::move(last1), std::move(result));
        auto res2 = ranges::copy(std::move(first2), std::move(last2), std::move(res1.out));
        return {std::move(res1.in), std::move(res2.in), std::move(res2.out)};
    }

    template< ranges::input_range R1, ranges::input_range R2,
              std::weakly_incrementable O, class Comp = ranges::less,
              class Proj1 = std::identity, class Proj2 = std::identity >
    requires std::mergeable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
             O, Comp, Proj1, Proj2>
    constexpr ranges::set_union_result<ranges::borrowed_iterator_t<R1>,
              ranges::borrowed_iterator_t<R2>, O>
    operator()( R1&& r1, R2&& r2, O result, Comp comp = {},
                Proj1 proj1 = {}, Proj2 proj2 = {} ) const {
        return (*this)(ranges::begin(r1), ranges::end(r1),
                       ranges::begin(r2), ranges::end(r2),
                       std::move(result), std::move(comp),
                       std::move(proj1), std::move(proj2));
    }
};

inline constexpr set_union_fn set_union{};

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

void print(const auto& in1, const auto& in2, auto first, auto last) {
    std::cout << "{ ";
    for (const auto& e : in1) { std::cout << e << ' '; }
    std::cout << "} ∪ { ";
    for (const auto& e : in2) { std::cout << e << ' '; }
    std::cout << "} =\n{ ";
    while (!(first == last)) { std::cout << *first++ << ' '; }
    std::cout << "}\n\n";
}

int main()
{
    std::vector<int> in1, in2, out;

    in1 = {1, 2, 3, 4, 5};
    in2 = {      3, 4, 5, 6, 7};
    out.resize(in1.size() + in2.size());
    const auto ret = std::ranges::set_union(in1, in2, out.begin());
    print(in1, in2, out.begin(), ret.out);

    in1 = {1, 2, 3, 4, 5, 5, 5};
    in2 = {      3, 4, 5, 6, 7};
    out.clear();
    out.reserve(in1.size() + in2.size());
    std::ranges::set_union(in1, in2, std::back_inserter(out));
    print(in1, in2, out.cbegin(), out.cend());
}

输出：

{ 1 2 3 4 5 } ∪ { 3 4 5 6 7 } =
{ 1 2 3 4 5 6 7 }

{ 1 2 3 4 5 5 5 } ∪ { 3 4 5 6 7 } =
{ 1 2 3 4 5 5 5 6 7 }

参阅

ranges::set_difference (C++20) | 计算两个集合的差集 (niebloid)
ranges::set_intersection (C++20) | 计算两个集合的交集 (niebloid)
ranges::set_symmetric_difference (C++20) | 计算两个集合的对称差 (niebloid)
ranges::merge (C++20) | 归并二个已排序范围 (niebloid)
ranges::includes (C++20) | 若一个序列是另一个的子列则返回 true (niebloid)
set_union | 计算两个集合的并集 (函数模板)


std::ranges::shuffle

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::random_access_iterator I, std::sentinel_for<I> S, class Gen >

requires std::permutable<I> &&
std::uniform_random_bit_generator< std::remove_reference_t <Gen>>

I shuffle( I first, S last, Gen&& gen );
 (1) (C++20 起)
template< ranges::random_access_range R, class Gen >

requires std::permutable<ranges::iterator_t<R>> &&
std::uniform_random_bit_generator< std::remove_reference_t <Gen>>

ranges::borrowed_iterator_t<R> shuffle( R&& r, Gen&& gen );
 (2) (C++20 起)
1) 重排给定范围 [first, last) 中的元素以使得那些元素的每个可能排列拥有相等的出现概率。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要随机打乱的范围
r | - | 要随机打乱的范围
gen | - | 随机数生成器

返回值

等于 last 的迭代器。

复杂度

准确交换 (last - first) - 1 次。

可能的实现

struct shuffle_fn {
  template<std::random_access_iterator I, std::sentinel_for<I> S, class Gen>
    requires std::permutable<I> &&
             std::uniform_random_bit_generator<std::remove_reference_t<Gen>>
      I operator()( I first, S last, Gen&& gen ) const {
          using diff_t = std::iter_difference_t<I>;
          using distr_t = std::uniform_int_distribution<diff_t>;
          using param_t = typename distr_t::param_type;
          distr_t D;
          const auto n{ last - first };
          for (diff_t i{}; i != n; ++i) {
              ranges::iter_swap(first + i, first + D(gen, param_t(0, i)));
          }
          return ranges::next(first, last);
      }

  template<ranges::random_access_range R, class Gen>
    requires std::permutable<ranges::iterator_t<R>> &&
             std::uniform_random_bit_generator<std::remove_reference_t<Gen>>
      ranges::borrowed_iterator_t<R> operator()( R&& r, Gen&& gen ) const {
          return (*this)(ranges::begin(r), ranges::end(r), std::move(gen));
      }
};

inline constexpr shuffle_fn shuffle{};

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <random>

void print(const auto& a) {
    for (const auto e : a) { std::cout << e << ' '; }
    std::cout << "\n";
}

int main()
{
    std::array a{'A', 'B', 'C', 'D', 'E', 'F'};
    print(a);

    std::random_device rd;
    std::mt19937 gen{rd()};

    for (int i{}; i != 3; ++i) {
        std::ranges::shuffle(a, gen);
        print(a);
    }
}

可能的输出：

A B C D E F
F E A C D B
E C B F A D
B A E C F D

参阅

ranges::next_permutation (C++20) | 产生某个元素范围的按字典序下一个较大的排列 (niebloid)
ranges::prev_permutation (C++20) | 产生某个元素范围的按字典序下一个较小的排列 (niebloid)
random_shuffleshuffle (C++17 前)(C++11) | 随机重排范围中的元素 (函数模板)


std::ranges::sort

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::random_access_iterator I, std::sentinel_for<I> S,

class Comp = ranges::less, class Proj = std::identity >
requires sortable<I, Comp, Proj>

constexpr I sort( I first, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< std::random_access_range R, class Comp = ranges::less,

class Proj = std::identity >
requires sortable<ranges::iterator_t<R>, Comp, Proj>

constexpr ranges::iterator_t<R> sort( R&& r, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)

以不降序排序范围[first, last) 中的元素。不保证保持等价元素的顺序。 若对于任何指向序列的迭代器 it 与任何使得 it + n 为指向序列元素的合法迭代器的非负整数 n ， std::invoke (comp, std::invoke (proj, *(it + n)), std::invoke (proj, *it)) 求值为 false ，则称序列相对于比较器 comp 已排序。

1) 用给定的二元比较函数 comp 比较元素。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 定义要排序的范围的迭代器-哨位对
r | - | 要排序的范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到谓词的投影

返回值

等于 last 的迭代器。

复杂度

\(\scriptsize \mathcal{O}(N\cdot\log{(N)})\)𝓞(N·log(N)) 次比较与投影，其中 N = ranges::distance(first, last) 。

可能的实现

注意典型实现使用内省排序。参阅 MSVC STL 与 libstdc++ 中的实现。

struct sort_fn {
    template< std::random_access_iterator I, std::sentinel_for<I> S,
              class Comp = ranges::less, class Proj = std::identity >
    requires std::sortable<I, Comp, Proj>
    constexpr I
    operator()( I first, S last, Comp comp = {}, Proj proj = {} ) const {
        if (first == last)
            return first;

        I last_iter = ranges::next(first, last);
        ranges::make_heap(first, last_iter, std::ref(comp), std::ref(proj));
        ranges::sort_heap(first, last_iter, std::ref(comp), std::ref(proj));

        return last_iter;
    }

    template< ranges::random_access_range R, class Comp = ranges::less,
              class Proj = std::identity >
    requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
    constexpr ranges::borrowed_iterator_t<R>
    operator()( R&& r, Comp comp = {}, Proj proj = {} ) const {
        return (*this)(ranges::begin(r), ranges::end(r), std::move(comp), std::move(proj));
    }
};

inline constexpr sort_fn sort{};

示例

#include <algorithm>
#include <array>
#include <functional>
#include <iomanip>
#include <iostream>

void print(auto const& seq) {
    for (auto const& elem : seq) {
        std::cout << elem << ' ';
    }
    std::cout << '\n';
}

struct Particle {
    std::string name; double mass; // MeV
    template<class Os> friend
    Os& operator<< (Os& os, Particle const& p) {
        return os << "\n" << std::left
                  << std::setw(8) << p.name
                  << " : " << p.mass;
    }
};

int main()
{
    std::array s = {5, 7, 4, 2, 8, 6, 1, 9, 0, 3};

    namespace ranges = std::ranges;

    // 用默认 operator< 排序
    ranges::sort(s);
    print(s);

    // 用标准库比较函数对象排序
    ranges::sort(s, ranges::greater());
    print(s);

    // 用定制函数对象排序
    struct {
        bool operator()(int a, int b) const {
            return a < b;
        }
    } customLess;
    ranges::sort(s.begin(), s.end(), customLess);
    print(s);

    // 用 lambda 表达式排序
    ranges::sort(s, [](int a, int b) {
        return a > b;
    });
    print(s);

    // 用投影排序
    Particle particles[] {
        {"Electron", 0.511}, {"Muon", 105.66}, {"Tau", 1776.86},
        {"Positron", 0.511}, {"Proton", 938.27}, {"Neutron", 939.57},
    };
    ranges::sort(particles, {}, &Particle::name); //< 按 name 排序
    print(particles);
    ranges::sort(particles, {}, &Particle::mass); //< 按 mass 排序
    print(particles);
}

输出：

0 1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1 0

Electron : 0.511
Muon     : 105.66
Neutron  : 939.57
Positron : 0.511
Proton   : 938.27
Tau      : 1776.86

Electron : 0.511
Positron : 0.511
Muon     : 105.66
Proton   : 938.27
Neutron  : 939.57
Tau      : 1776.86

参阅

ranges::partial_sort (C++20) | 排序一个范围的前 N 个元素 (niebloid)
ranges::stable_sort (C++20) | 将范围内的元素排序，同时保持相等的元素之间的顺序 (niebloid)
ranges::partition (C++20) | 将范围中的元素分为二组 (niebloid)
sort | 将范围按升序排序 (函数模板)


std::ranges::sort_heap

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::random_access_iterator I, std::sentinel_for<I> S,

class Comp = ranges::less, class Proj = std::identity >
requires std::sortable<I, Comp, Proj>
constexpr I

sort_heap( I first, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::random_access_range R, class Comp = ranges::less,

class Proj = std::identity >
requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
constexpr ranges::borrowed_iterator_t<R>

sort_heap( R&& r, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)

转换最大堆 [first, last) 为按升序排序的范围。产生的范围不再拥有堆属性。

1) 用给定的二元比较函数 comp 与投影对象 proj 比较元素。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要排序的元素范围
r | - | 要排序的元素范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

等于 last 的迭代器。

复杂度

给定 N = ranges::distance(first, last) ，至多比较 \(\scriptsize 2N\log{(N)}\)2Nlog(N) 次，投影 \(\scriptsize 4N\log{(N)}\)4Nlog(N) 次。

注解

最大堆是按照比较器 comp 与投影 proj 排列的元素范围 [f, l) ，拥有下列属性：

  • 令 N == l - f ，对于所有 0 < i < N ， p == f[(i - 1) / 2] 和 q == f[i] ，表达式 std::invoke (comp, std::invoke (proj, p), std::invoke (proj, q)) 求值为 false 。
  • 能用 ranges::push_heap() 在 \(\scriptsize \mathcal{O}(\log N)\)𝓞(log N) 时间内添加新元素。
  • 能用 ranges::pop_heap() 在 \(\scriptsize \mathcal{O}(\log N)\)𝓞(log N) 时间内移除首元素。

可能的实现

struct sort_heap_fn {
    template< std::random_access_iterator I, std::sentinel_for<I> S,
              class Comp = ranges::less, class Proj = std::identity >
    requires std::sortable<I, Comp, Proj>
    constexpr I
    operator()( I first, S last, Comp comp = {}, Proj proj = {} ) const {
        auto ret {ranges::next(first, last)};
        for (; first != last; --last) {
            ranges::pop_heap(first, last, comp, proj);
        }
        return ret;
    }

    template< ranges::random_access_range R, class Comp = ranges::less,
              class Proj = std::identity >
    requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
    constexpr ranges::borrowed_iterator_t<R>
    operator()( R&& r, Comp comp = {}, Proj proj = {} ) const {
        return (*this)(ranges::begin(r), ranges::end(r), std::move(comp), std::move(proj));
    }
};

inline constexpr sort_heap_fn sort_heap{};

示例

#include <algorithm>
#include <array>
#include <iostream>

void print(auto const& rem, auto const& v)
{
    std::cout << rem;
    for (const auto i : v)
        std::cout << i << ' ';
    std::cout << '\n';
}

int main()
{
    std::array v {3, 1, 4, 1, 5, 9};
    print("original array:  ", v);

    std::ranges::make_heap(v);
    print("after make_heap: ", v);

    std::ranges::sort_heap(v);
    print("after sort_heap: ", v);
}

输出：

original array:  3 1 4 1 5 9
after make_heap: 9 5 4 1 1 3
after sort_heap: 1 1 3 4 5 9

参阅

ranges::is_heap (C++20) | 检查给定范围是否为最大堆 (niebloid)
ranges::is_heap_until (C++20) | 寻找能成为最大堆的最大子范围 (niebloid)
ranges::make_heap (C++20) | 从一个元素范围创建出一个最大堆 (niebloid)
ranges::pop_heap (C++20) | 从最大堆中移除最大元素 (niebloid)
ranges::push_heap (C++20) | 将一个元素加入到一个最大堆 (niebloid)
sort_heap | 将一个最大堆变成一个按升序排序的元素范围 (函数模板)


std::ranges::stable_partition

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template<std::bidirectional_iterator I, std::sentinel_for<I> S, class Proj = std::identity,

std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
requires std::permutable<I>
ranges::subrange<I>

stable_partition( I first, S last, Pred pred, Proj proj = {} );
 (1) (C++20 起)
template<ranges::bidirectional_range R, class Proj = std::identity,

std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred>
requires std::permutable<ranges::iterator_t<R>>
ranges::borrowed_subrange_t<R>

stable_partition( R&& r, Pred pred, Proj proj = {} );
 (2) (C++20 起)
1) 重排序范围 [first, last) 中的元素，使得所有谓词 pred 对 proj 投影后返回 true 的元素在所有谓词 pred 对 proj 投影后返回 false 的元素之前。算法是稳定的，即保持元素的相对顺序。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要重排序的元素范围
r | - | 要重排序的元素范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

1) 等于 {pivot, last} 的对象，其中 pivot 是指向第二群首元素的迭代器。
2) 若 r 为左值或拥有 borrowed_range 类型则同 (1) 。否则返回 std::ranges::dangling.

复杂度

给定 N = ranges::distance(first, last) ，复杂度最坏为 \(\scriptsize N\cdot\log{(N)}\)N·log(N) 次交换，而在使用额外内存时仅 \(\scriptsize \mathcal{O}(N)\)𝓞(N) 次交换。准确应用 \(\scriptsize N\)N 次谓词 pred 和投影 proj 。

注解

此函数尝试分配临时缓冲区。若分配失败，则选择效率较低的算法。

可能的实现

此实现不使用额外内存缓冲区而这样可能较为低效。参阅 MSVC STL 与 libstdc++ 中的实现。

struct stable_partition_fn {
    template<std::bidirectional_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
             std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
    requires std::permutable<I>
    ranges::subrange<I>
    operator()( I first, S last, Pred pred, Proj proj = {} ) const {
        first = ranges::find_if_not(first, last, pred, proj);
        I mid = first;
        while (mid != last) {
            mid = ranges::find_if(mid, last, pred, proj);
            if (mid == last) break;
            I last2 = ranges::find_if_not(mid, last, pred, proj);
            ranges::rotate(first, mid, last2);
            first = ranges::next(first, ranges::distance(mid, last2));
            mid = last2;
        }
        return {std::move(first), std::move(mid)};
    }

    template<ranges::bidirectional_range R, class Proj = std::identity,
             std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred>
    requires std::permutable<ranges::iterator_t<R>>
    ranges::borrowed_subrange_t<R>
    operator()( R&& r, Pred pred, Proj proj = {} ) const {
        return (*this)(ranges::begin(r), ranges::end(r), std::move(pred), std::move(proj));
    }
};

inline constexpr stable_partition_fn stable_partition{};

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

namespace rng = std::ranges;

template <std::permutable I, std::sentinel_for<I> S>
constexpr void stable_sort(I first, S last)
{
    if (first == last)
        return;

    auto pivot = *rng::next(first, rng::distance(first, last) / 2, last);
    auto left = [pivot](const auto& em) { return em < pivot; };
    auto tail1 = rng::stable_partition(first, last, left);
    auto right = [pivot](const auto& em) { return !(pivot < em); };
    auto tail2 = rng::stable_partition(tail1, right);

    stable_sort(first, tail1.begin());
    stable_sort(tail2.begin(), tail2.end());
}

void print(const auto rem, auto first, auto last, bool end = true) {
    std::cout << rem;
    for (; first != last; ++first) { std::cout << *first << ' '; }
    std::cout << (end ? "\n" : "");
}

int main()
{
    const auto original = { 9, 6, 5, 2, 3, 1, 7, 8 };

    std::vector<int> vi;
    auto even = [](int x) { return 0 == (x % 2); };

    print("Original vector:\t", original.begin(), original.end(), "\n");

    vi = original;
    const auto ret1 = rng::stable_partition(vi, even);
    print("Stable partitioned:\t", vi.begin(), ret1.begin(), 0);
    print("│ ", ret1.begin(), ret1.end());

    vi = original;
    const auto ret2 = rng::partition(vi, even);
    print("Partitioned:\t\t", vi.begin(), ret2.begin(), 0);
    print("│ ", ret2.begin(), ret2.end());

    vi = {16, 30, 44, 30, 15, 24, 10, 18, 12, 35};
    print("Unsorted vector: ", vi.begin(), vi.end());

    stable_sort(rng::begin(vi), rng::end(vi));
    print("Sorted vector:   ", vi.begin(), vi.end());
}

可能的输出：

Original vector:        9 6 5 2 3 1 7 8
Stable partitioned:     6 2 8 │ 9 5 3 1 7
Partitioned:            8 6 2 │ 5 3 1 7 9
Unsorted vector: 16 30 44 30 15 24 10 18 12 35
Sorted vector:   10 12 15 16 18 24 30 30 35 44

参阅

ranges::partition (C++20) | 将范围中的元素分为二组 (niebloid)
ranges::partition_copy (C++20) | 复制一个范围，将各元素分为二组 (niebloid)
ranges::is_partitioned (C++20) | 判断范围是否已按给定的谓词划分 (niebloid)
stable_partition | 将元素分为两组，同时保留其相对顺序 (函数模板)


std::ranges::stable_sort

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::random_access_iterator I, std::sentinel_for<I> S,

class Comp = ranges::less, class Proj = std::identity >
requires std::sortable<I, Comp, Proj>

I stable_sort( I first, S last, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::random_access_range R, class Comp = ranges::less,

class Proj = std::identity >
requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
ranges::borrowed_iterator_t<R>

stable_sort( R&& r, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)

以非降序排序范围 [first, last) 中的元素。等价元素的顺序是稳定的，即保证得到保持。

称序列为按照比较器 comp 与投影 proj 已排序，若对应任何指向序列的迭代器 it 与任何使得 it + n 为指向序列元素的合法迭代器的非负整数 n ， std::invoke (comp, std::invoke (proj, *(it + n)), std::invoke (proj, *it))) 求值为 false 。

1) 用给定的二元比较函数 comp 比较元素。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 定义待排序范围的迭代器-哨位对
r | - | 待排序范围
comp | - | 应用到投影后元素的比较器
proj | - | 应用到元素的投影

返回值

等于 last 的迭代器。

复杂度

若额外内存可用则比较 \(\scriptsize N\cdot\log{(N)}\)N·log(N) 次；其中 \(\scriptsize N\)N 为 ranges::distance(first, last) 。否则比较 \(\scriptsize N\cdot\log^2{(N)}\)N·log²(N) 次。两种情况下都进行二倍数量的投影。

可能的实现

此实现仅展示无额外内存可用时使用的较慢的算法。参阅 MSVC STL 与 libstdc++ 中的实现。

struct stable_sort_fn {
    template< std::random_access_iterator I, std::sentinel_for<I> S,
              class Comp = ranges::less, class Proj = std::identity >
    requires std::sortable<I, Comp, Proj>
    I operator()( I first, S last, Comp comp = {}, Proj proj = {} ) const {
        auto count   = ranges::distance(first, last);
        auto mid     = first + count / 2;
        auto last_it = first + count;

        if (count <= 1)
            return last_it;

        (*this)(first, mid, std::ref(comp), std::ref(proj));
        (*this)(mid, last_it, std::ref(comp), std::ref(proj));

        ranges::inplace_merge(first, mid, last_it);

        return last_it;
    }

    template< ranges::random_access_range R, class Comp = ranges::less,
              class Proj = std::identity >
    requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
    ranges::borrowed_iterator_t<R>
    operator()( R&& r, Comp comp = {}, Proj proj = {} ) const {
        return (*this)(ranges::begin(r), ranges::end(r), std::move(comp), std::move(proj));
    }
};

inline constexpr stable_sort_fn stable_sort{};

示例

#include <algorithm>
#include <array>
#include <functional>
#include <iomanip>
#include <iostream>

void print(auto const& seq) {
    for (auto const& elem : seq)
        std::cout << elem << ' ';
    std::cout << '\n';
}

struct Particle {
    std::string name; double mass; // MeV
    friend std::ostream& operator<< (std::ostream& os, Particle const& p) {
        return os << "\n" << std::left << std::setw(8) << p.name << " : " << p.mass;
    }
};

int main()
{
    std::array s {5, 7, 4, 2, 8, 6, 1, 9, 0, 3};

    // 以默认的 operator< 排序
    std::ranges::stable_sort(s);
    print(s);

    // 以标准库比较函数对象排序
    std::ranges::stable_sort(s, std::ranges::greater());
    print(s);

    // 以定制函数对象排序
    struct {
        bool operator()(int a, int b) const {
            return a < b;
        }
    } customLess;
    std::ranges::stable_sort(s.begin(), s.end(), customLess);
    print(s);

    // 以 lambda 表达式排序
    std::ranges::stable_sort(s, [](int a, int b) {
        return a > b;
    });
    print(s);

    // 以投影排序
    Particle particles[] {
        {"Electron", 0.511}, {"Muon", 105.66}, {"Tau", 1776.86},
        {"Positron", 0.511}, {"Proton", 938.27}, {"Neutron", 939.57},
    };
    print(particles);
    std::ranges::stable_sort(particles, {}, &Particle::name); //< sort by name
    print(particles);
    std::ranges::stable_sort(particles, {}, &Particle::mass); //< sort by mass
    print(particles);
}

输出：

0 1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1 0

Electron : 0.511
Muon     : 105.66
Tau      : 1776.86
Positron : 0.511
Proton   : 938.27
Neutron  : 939.57

Electron : 0.511
Muon     : 105.66
Neutron  : 939.57
Positron : 0.511
Proton   : 938.27
Tau      : 1776.86

Electron : 0.511
Positron : 0.511
Muon     : 105.66
Proton   : 938.27
Neutron  : 939.57
Tau      : 1776.86

参阅

ranges::sort (C++20) | 将范围按升序排序 (niebloid)
ranges::partial_sort (C++20) | 排序一个范围的前 N 个元素 (niebloid)
ranges::stable_partition (C++20) | 将元素分成二组，同时保持其相对顺序 (niebloid)
stable_sort | 将范围内的元素排序，同时保持相等的元素之间的顺序 (函数模板)


std::ranges::starts_with

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template<std::input_iterator I1, std::sentinel_for<I1> S1,

std::input_iterator I2, std::sentinel_for<I2> S2,
class Pred = ranges::equal_to,
class Proj1 = std::identity, class Proj2 = std::identity>
requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr bool starts_with(I1 first1, S1 last1, I2 first2, S2 last2,

Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
 (1) (C++23 起)
template<ranges::input_range R1, ranges::input_range R2,

class Pred = ranges::equal_to,
class Proj1 = std::identity, class Proj2 = std::identity>
requires std::indirectly_comparable<ranges::iterator_t<R1>,
ranges::iterator_t<R2>,
Pred, Proj1, Proj2>
constexpr bool starts_with(R1&& r1, R2&& r2,

Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
 (2) (C++23 起)

检查第二范围是否匹配第一范围的前缀。

1) 令 N1 与 N2 分别代表范围 [first1, last1) 与 [first2, last2) 的大小。若 N1 < N2 则返回 false 。否则，当且仅当 [first2, last2) 范围中的每个元素均等于 [first1, first1 + N2) 中的对应元素才返回 true 。通过应用二元谓词 pred 到分别由 proj1 与 proj2 投影的两个范围中的元素进行比较。
2) 同， (1) ，但以 r1 与 r2 为源范围，如同以 ranges::begin(r1) 为 first1 ，以 ranges:begin(r2) 为 first2 ，以 ranges::end(r1) 为 last1 ，并以 ranges::end(r2) 为 last2 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 要检验的元素范围
r1 | - | 要检验的元素范围
first2, last2 | - | 要用作前缀的元素范围
r2 | - | 要用作前缀的元素范围
pred | - | 比较投影后元素的二元谓词
proj1 | - | 应用到要检验的元素范围的投影
proj2 | - | 应用到要用作前缀的元素范围的投影

返回值

若第二范围匹配第一范围的前缀则为 true ，否则为 false 。

复杂度

线性：至多应用 min(N1, N2) 次谓词和两个投影。

可能的实现

struct starts_with_fn {
  template<std::input_iterator I1, std::sentinel_for<I1> S1,
           std::input_iterator I2, std::sentinel_for<I2> S2,
           class Pred = ranges::equal_to,
           class Proj1 = std::identity, class Proj2 = std::identity>
    requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2,
                            Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const {
    return ranges::mismatch(std::move(first1), last1, std::move(first2), last2,
                            std::move(pred), std::move(proj1), std::move(proj2)
                           ).in2 == last2;
  }

  template<ranges::input_range R1, ranges::input_range R2,
           class Pred = ranges::equal_to,
           class Proj1 = std::identity, class Proj2 = std::identity>
    requires std::indirectly_comparable<ranges::iterator_t<R1>,
                                        ranges::iterator_t<R2>,
                                        Pred, Proj1, Proj2>
  constexpr bool operator()(R1&& r1, R2&& r2,
                            Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const {
    return (*this)(ranges::begin(r1), ranges::end(r1),
                   ranges::begin(r2), ranges::end(r2),
                   std::move(pred), std::move(proj1), std::move(proj2));
  }
};

inline constexpr starts_with_fn starts_with{};

示例

#include <string_view>
#include <algorithm>
#include <iostream>
#include <ranges>

int main()
{
    using namespace std::literals;

    constexpr auto ascii_upper = [](char8_t c)
    {
        return u8'a' <= c && c <= u8'z' ? static_cast<char8_t>(c + u8'A' - u8'a') : c;
    };

    constexpr auto cmp_ignore_case = [=](char8_t x, char8_t y)
    {
        return ascii_upper(x) == ascii_upper(y);
    };

    static_assert(std::ranges::starts_with("const_cast", "const"sv));
    static_assert(std::ranges::starts_with("constexpr", "const"sv));
    static_assert(!std::ranges::starts_with("volatile", "const"sv));

    std::cout
        << std::boolalpha
        << std::ranges::starts_with(u8"Constantinopolis", u8"constant"sv,
                                    {}, ascii_upper, ascii_upper) << ' '
        << std::ranges::starts_with(u8"Istanbul", u8"constant"sv,
                                    {}, ascii_upper, ascii_upper) << ' '
        << std::ranges::starts_with(u8"Metropolis", u8"metro"sv,
                                    cmp_ignore_case) << ' '
        << std::ranges::starts_with(u8"Acropolis", u8"metro"sv,
                                    cmp_ignore_case) << '\n';

    constexpr static auto v = { 1, 3, 5, 7, 9 };
    constexpr auto odd = [](int x) { return x % 2; };
    static_assert( std::ranges::starts_with( v, std::views::iota(1)
                                              | std::views::filter(odd)
                                              | std::views::take(3) ) );
}

输出：

true false true false

参阅

ranges::ends_with (C++23) | 检查一个范围是否终于另一范围 (niebloid)
ranges::mismatch (C++20) | 寻找两个范围出现不同的首个位置 (niebloid)
starts_with (C++20) | 检查 string 是否始于给定前缀 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
starts_with (C++20) | 检查 string_view 是否始于给定前缀 (std::basic_string_view<CharT,Traits> 的公开成员函数)


std::ranges::swap_ranges, std::ranges::swap_ranges_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I1, std::sentinel_for<I1> S1,

std::input_iterator I2, std::sentinel_for<I2> S2 >
requires std::indirectly_swappable<I1, I2>
constexpr swap_ranges_result<I1, I2>

swap_ranges( I1 first1, S1 last1, I2 first2, S2 last2 );
 (1) (C++20 起)
template< ranges::input_range R1, ranges::input_range R2 >

requires std::indirectly_swappable<ranges::iterator_t<R1>, ranges::iterator_t<R2>>
constexpr swap_ranges_result<ranges::borrowed_iterator_t<R1>,
ranges::borrowed_iterator_t<R2>>

swap_ranges( R1&& r1, R2&& r2 );
 (2) (C++20 起)
辅助类型
template< class I1, class I2 >
using swap_ranges_result = ranges::in_in_result<I1, I2>;
 (3) (C++20 起)
1) 在第一范围 [first1, first1 + M) 与第二范围 [first2, first2 + M) 间交换元素，其中 M = ranges::min(ranges::distance(first1, last1), ranges::distance(first2, last2)) 。
范围 [first1, last1) 与 [first2, last2) 必须不重叠。
2) 同 (1) ，但以 r1 为第一范围并以 r2 为第二范围，如同以 ranges::begin(r1) 为 first1 ，以 ranges::end(r1) 为 last1 ，以 ranges::begin(r2) 为 first2 ，并以 ranges::end(r2) 为 last2 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 要交换的第一范围
first2, last2 | - | 要交换的第二范围
r1 | - | 要交换的第一范围
r2 | - | 要交换的第二范围

返回值

1{first1 + M, first2 + M} 。

复杂度

准确交换 M 次。

注解

实现（例如 MSVC STL ）可能在迭代器类型实现 contiguous_iterator ，并且交换其值类型不调用非平凡的特殊成员函数或 ADL 所找到的 swap 时启用向量化。

可能的实现

struct swap_ranges_fn {

  template<std::input_iterator I1, std::sentinel_for<I1> S1,
           std::input_iterator I2, std::sentinel_for<I2> S2>
    requires std::indirectly_swappable<I1, I2>
      constexpr ranges::swap_ranges_result<I1, I2>
        operator() ( I1 first1, S1 last1, I2 first2, S2 last2 ) const {
            for (; !(first1 == last1 or first2 == last2); ++first1, ++first2)
                ranges::iter_swap(first1, first2);
            return {std::move(first1), std::move(first2)};
        }

  template<ranges::input_range R1, ranges::input_range R2>
    requires std::indirectly_swappable<ranges::iterator_t<R1>, ranges::iterator_t<R2>>
      constexpr ranges::swap_ranges_result<ranges::borrowed_iterator_t<R1>,
                                           ranges::borrowed_iterator_t<R2>>
        operator() ( R1&& r1, R2&& r2 ) const {
            return (*this)(ranges::begin(r1), ranges::end(r1),
                           ranges::begin(r2), ranges::end(r2));
        }
};

inline constexpr swap_ranges_fn swap_ranges{};

示例

#include <algorithm>
#include <iostream>
#include <list>
#include <string_view>
#include <vector>

auto print(std::string_view name, auto const& seq, std::string_view term = "\n") {
    std::cout << name << " : ";
    for (const auto& elem : seq)
        std::cout << elem << ' ';
    std::cout << term;
}

int main()
{
    std::vector<char>  p {'A', 'B', 'C', 'D', 'E'};
    std::list<char>    q {'1', '2', '3', '4', '5', '6'};

    print("p", p);
    print("q", q, "\n\n");

    // 交换 p[0, 2) 与 q[1, 3):
    std::ranges::swap_ranges(p.begin(),
                             p.begin() + 4,
                             std::ranges::next(q.begin(), 1),
                             std::ranges::next(q.begin(), 3));
    print("p", p);
    print("q", q, "\n\n");

    // 交换 p[0, 5) 与 q[0, 5):
    std::ranges::swap_ranges(p, q);

    print("p", p);
    print("q", q);
}

输出：

p : A B C D E
q : 1 2 3 4 5 6

p : 2 3 C D E
q : 1 A B 4 5 6

p : 1 A B 4 5
q : 2 3 C D E 6

参阅

iter_swap (C++20) | 交换两个可解引用对象所引用的值 (定制点对象)
ranges::swap (C++20) | 交换两个对象的值 (定制点对象)
swap_ranges | 交换两个范围的元素 (函数模板)
iter_swap | 交换两个迭代器所指向的元素 (函数模板)
swap | 交换两个对象的值 (函数模板)


std::ranges::transform, std::ranges::unary_transform_result, std::ranges::binary_transfor_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O,

std::copy_constructible F, class Proj = std::identity >
requires std::indirectly_writable<O,
std::indirect_result_t<F&, std::projected<I, Proj>>>
constexpr ranges::unary_transform_result<I, O>

transform( I first1, S last1, O result, F op, Proj proj = {} );
 (1) (C++20 起)
template< ranges::input_range R, std::weakly_incrementable O,

std::copy_constructible F, class Proj = std::identity >
requires std::indirectly_writable<
O,
std::indirect_result_t<F&, std::projected<ranges::iterator_t<R>, Proj>>>
constexpr ranges::unary_transform_result<ranges::borrowed_iterator_t<R>, O>

transform( R&& r, O result, F op, Proj proj = {} );
 (2) (C++20 起)
template< std::input_iterator I1, std::sentinel_for<I1> S1,

std::input_iterator I2, std::sentinel_for<I2> S2,
std::weakly_incrementable O,
std::copy_constructible F,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::indirectly_writable<
O,
std::indirect_result_t<F&,
std::projected<I1, Proj1>,
std::projected<I2, Proj2>>>
constexpr ranges::binary_transform_result<I1, I2, O>
transform( I1 first1, S1 last1, I2 first2, S2 last2, O result,

F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {} );
 (3) (C++20 起)
template< std::input_range R1,

std::input_range R2,
std::weakly_incrementable O,
std::copy_constructible F,
class Proj1 = std::identity, class Proj2 = std::identity >
requires std::indirectly_writable<
O,
std::indirect_result_t<
F&,
std::projected<ranges::iterator_t<R1>, Proj>,
std::projected<ranges::iterator_t<R2>, Proj>>>
constexpr ranges::binary_transform_result<ranges::borrowed_iterator_t<R1>,
ranges::borrowed_iterator_t<R2>, O>

transform( R1&& r1, R2&& r2, O result, F binary_op, Proj proj = {} );
 (4) (C++20 起)
辅助类型
template < class I, class O >
using unary_transform_result = ranges::in_out_result<I, O>;
 (5) (C++20 起)
template < class I1, class I2, class O >
using binary_transform_result = ranges::in_in_out_result<I1, I2, O>;
 (6) (C++20 起)

ranges::transform 应用给定的函数到范围并存储结果于始于 result 的另一范围。

1) 应用一元运算 op 到 [first1, last1) 所定义的范围（在以投影 proj 投影后）。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。
3) 应用二元运算 binary_op 到来自二个范围的元素：一个由 [first1, last1) 定义而另一个由 [first2, last2) 定义（在分别以投影 proj1 与 proj2 投影后）。
4) 同 (3) ，但以 r1 为第一源范围，如同以 ranges::begin(r1) 为 first1 并以 ranges::end(r1) 为 last1 ，而对 r2 也类似。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first1, last1 | - | 要变换的元素范围
r, r1 | - | 要变换的元素范围 {{par | first2, last2 |要变换的第二元素范围}
r2 | - | 要变换的第二元素范围
result | - | 目标范围的起始，可以等于 first1 或 first2
op, binary_op | - | 应用到投影后元素的操作
proj1 | - | 应用到第一范围中的元素的投影
proj2 | - | 应用到第二范围中的元素的投影

返回值

1-2) unary_transform_result ，含有等于 last 的输入迭代器与指向最后变换元素后一元素的输出迭代器。
3-4) binary_transform_result ，含有分别作为 in1 与 in2 的指向来自范围 [first1, last1) 与 [first2, last2) 的最后变换元素的输入迭代器，与作为 out 的指向最后变换元素后一元素的输出迭代器。

复杂度

1-2) 准确应用 last1 - first1 次 op 与 proj 。
3-4) 准确应用 min(last1 - first1, last2 - first2) 次 binary_op 与投影。

可能的实现

struct transform_fn {
  template< std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O,
            std::copy_constructible F, class Proj = std::identity >
  requires std::indirectly_writable<O, std::indirect_result_t<F&, std::projected<I, Proj>>>
  constexpr ranges::unary_transform_result<I, O>
    operator()( I first1, S last1, O result, F op, Proj proj = {} ) const
  {
      for (; first1 != last1; ++first1, (void)++result) {
          *result = std::invoke(op, std::invoke(proj, *first1));
      }

      return {first1, result};
  }

  template< ranges::input_range R, std::weakly_incrementable O,
            std::copy_constructible F, class Proj = std::identity >
  requires std::indirectly_writable<
               O,
               std::indirect_result_t<F&, std::projected<ranges::iterator_t<R>, Proj>>>
  constexpr ranges::unary_transform_result<ranges::borrowed_iterator_t<R>, O>
    operator()( R&& r, O result, F op, Proj proj = {} ) const
  {
    return (*this)(ranges::begin(r), ranges::end(r), result, std::ref(proj));
  }

  template< std::input_iterator I1, std::sentinel_for<I1> S1,
            std::input_iterator I2, std::sentinel_for<I2> S2,
            std::weakly_incrementable O,
            std::copy_constructible F,
            class Proj1 = std::identity, class Proj2 = std::identity >
  requires std::indirectly_writable<
               O,
               std::indirect_result_t<F&,
                                      std::projected<I1, Proj1>,
                                      std::projected<I2, Proj2>>>
  constexpr ranges::binary_transform_result<I1, I2, O>
    operator()( I1 first1, S1 last1, I2 first2, S2 last2, O result,
                F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {} ) const
  {
    for (; first1 != last1 && first2 != last2; ++first1, (void)++first2, (void)++result) {
      *result = std::invoke(binary_op,
                            std::invoke(proj1, *first1),
                            std::invoke(proj2, *first2));
    }

    return {first1, first2, result};
  }

  template< ranges::input_range R1, ranges::input_range R2,
            std::weakly_incrementable O, std::copy_constructible F,
            class Proj1 = std::identity, class Proj2 = std::identity >
  requires std::indirectly_writable<
               O,
               std::projected<ranges::iterator_t<R1>, Proj1>,
               std::projected<ranges::iterator_t<R2>, Proj2>>>
  constexpr ranges::binary_transform_result<ranges::borrowed_iterator_t<R1>,
                                            ranges::borrowed_iterator_t<R2>, O>
    operator()( R1&& r1, R2&& r2, O result,
                F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {} ) const
  {
    return (*this)(ranges::begin(r1), ranges::end(r1),
                   ranges::begin(r2), ranges::end(r2),
                   result, std::ref(binary_op),
                   std::ref(proj1), std::ref(proj2));
  }
};

inline constexpr transform_fn transform;

注解

std::ranges::transform 不保证按顺序应用 op 或 binary_op 。为按顺序应用函数导序列或应用修改元素的函数到序列，请用 std::ranges::for_each 。

示例

下列代码用 transform 以 toupper 函数原地转换为大写然后变换每个 char 为其序数值：

#include <algorithm>
#include <cctype>
#include <functional>
#include <iostream>
#include <string>
#include <vector>

int main()
{
    std::string s("hello");

    namespace ranges = std::ranges;

    ranges::transform(s.begin(), s.end(), s.begin(),
                   [](unsigned char c) -> unsigned char { return std::toupper(c); });

    std::vector<std::size_t> ordinals;
    ranges::transform(s, std::back_inserter(ordinals),
                      [](unsigned char c) -> std::size_t { return c; });

    std::cout << s << ':';
    for (auto ord : ordinals) {
       std::cout << ' ' << ord;
    }

    ranges::transform(ordinals, ordinals, ordinals.begin(), std::plus{});

    std::cout << '\n';
    for (auto ord : ordinals) {
       std::cout << ord << ' ';
    }
    std::cout << '\n';
}

输出：

HELLO: 72 69 76 76 79
144 138 152 152 158

参阅

ranges::for_each (C++20) | 应用函数到范围中的元素 (niebloid)
ranges::transform_viewviews::transform (C++20) | 对序列的每个元素应用某个变换函数的 view (类模板) (范围适配器对象)
transform | 将一个函数应用于某一范围的各个元素，并在目标范围存储结果 (函数模板)


std::ranges::unique

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::permutable I, std::sentinel_for<I> S, class Proj = std::identity,

std::indirect_equivalence_relation<std::projected<I, Proj>>
C = ranges::equal_to >
constexpr ranges::subrange<I>

unique( I first, S last, C comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::forward_range R, class Proj = std::identity,

std::indirect_equivalence_relation<std::projected<ranges::iterator_t<R>, Proj>>
C = ranges::equal_to >
requires std::permutable<ranges::iterator_t<R>>
constexpr ranges::borrowed_subrange_t<R>

unique( R&& r, C comp = {}, Proj proj = {} );
 (2) (C++20 起)
1) 从来自范围 [first, last) 的每个连续的等价元素组消除首个以外的全部元素，并返回子范围 [ret, last) ，其中 ret 是新范围的尾后迭代器。
若 std::invoke (comp, std::invoke (proj, *(i - 1)), std::invoke (proj, *i)) == true 则认为二个连续元素 *(i - 1) 与 *i 等价，其中 i 是范围 [first + 1, last) 中的迭代器。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要处理的元素范围
r | - | 要处理的元素范围
comp | - | 比较投影后元素的二元谓词
proj | - | 应用到元素的投影

返回值

返回 {ret, last} ，其中 ret 是新范围末尾的尾后迭代器。

复杂度

对于非空范围，准确应用 ranges::distance(first, last) - 1 次相应的谓词 comp ，并且应用投影 proj 的次数不多于其二倍。

注解

由迁移（通过移动赋值的手段）范围中的元素进行移除，使得未被移除的元素出现在范围起始。保持元素的相对顺序并且不改变容器的物理大小。 [ret, last) 中的迭代器（若存在）仍然可解引用，但元素自身拥有未指定值（如可移动赋值 (MoveAssignable) 后条件所要求）。

对 ranges::unique 的调用有时后随容器的 erase 成员函数，这擦除未指定值并减少容器的物理大小以匹配其新的逻辑大小。此二调用一并实现擦除-移除手法。

可能的实现

struct unique_fn {
  template<std::permutable I, std::sentinel_for<I> S, class Proj = std::identity,
           std::indirect_equivalence_relation<std::projected<I, Proj>> C = ranges::equal_to>
    constexpr ranges::subrange<I>
      operator() ( I first, S last, C comp = {}, Proj proj = {} ) const {
          first = ranges::adjacent_find(first, last, comp, proj);
          if (first == last)
              return {first, first};
          auto i {first};
          ++first;
          while (++first != last)
              if (!std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, *first)))
                  *++i = std::move(*first);
          return {++i, first};
      }

  template<ranges::forward_range R, class Proj = std::identity,
           std::indirect_equivalence_relation<std::projected<ranges::iterator_t<R>, Proj>>
             C = ranges::equal_to>
    requires std::permutable<ranges::iterator_t<R>>
      constexpr ranges::borrowed_subrange_t<R>
        operator() ( R&& r, C comp = {}, Proj proj = {} ) const {
            return (*this)(ranges::begin(r), ranges::end(r),
                           std::move(comp), std::move(proj));
        }
};

inline constexpr unique_fn unique{};

示例

#include <algorithm>
#include <cmath>
#include <complex>
#include <iostream>
#include <vector>

struct id { int i; explicit id(int i) : i{i} {} };

void print(id i, const auto& v) {
    std::cout << "@" << i.i << ": ";
    std::ranges::for_each(v, [](auto const& e) { std::cout << e << ' '; });
    std::cout << '\n';
}

int main()
{
    // 含数个重复元素的 vector
    std::vector<int> v{1, 2, 1, 1, 3, 3, 3, 4, 5, 4};

    print(id{1}, v);

    // 移除连续（相接）的副本
    auto ret = std::ranges::unique(v);
    // v 现在保有 {1 2 1 3 4 5 4 x x x} ，其中 'x' 不确定
    v.erase(ret.begin(), ret.end());
    print(id{2}, v);

    // sort 后随 unique ，移除所有副本
    std::ranges::sort(v); // {1 1 2 3 4 4 5}
    print(id{3}, v);

    auto [first, last] = std::ranges::unique(v.begin(), v.end());
    // v 现在保有 {1 2 3 4 5 x x} ，其中 'x' 不确定
    v.erase(first, last);
    print(id{4}, v);

    // 以定制比较与投影 unique
    std::vector<std::complex<int>> vc{ {1, 1}, {-1, 2}, {-2, 3}, {2, 4}, {-3, 5} };
    print(id{5}, vc);

    auto ret2 = std::ranges::unique(vc,
        [](int x, int y) { return std::abs(x) == std::abs(y); }, // comp
        [](std::complex<int> z) { return z.real(); }             // proj
    );
    vc.erase(ret2.begin(), ret2.end());
    print(id{6}, vc);
}

输出：

@1: 1 2 1 1 3 3 3 4 5 4
@2: 1 2 1 3 4 5 4
@3: 1 1 2 3 4 4 5
@4: 1 2 3 4 5
@5: (1,1) (-1,2) (-2,3) (2,4) (-3,5)
@6: (1,1) (-2,3) (-3,5)

参阅

ranges::unique_copy (C++20) | 创建某范围的不含连续重复元素的副本 (niebloid)
ranges::adjacent_find (C++20) | 查找首对相邻的相同（或满足给定谓词的）元素 (niebloid)
ranges::removeranges::remove_if (C++20)(C++20) | 移除满足特定判别标准的元素 (niebloid)
unique | 移除范围内的连续重复元素 (函数模板)
unique | 删除连续的重复元素 (std::list<T,Allocator> 的公开成员函数)
unique (C++11) | 删除连续的重复元素 (std::forward_list<T,Allocator> 的公开成员函数)


std::ranges::unique_copy, std::ranges::unique_copy_result

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O,

class Proj = std::identity,
std::indirect_equivalence_relation<std::projected<I, Proj>> C = ranges::equal_to >
requires std::indirectly_copyable<I, O> && (std::forward_iterator<I> ||
(std::input_iterator<O> && std::same_as<std::iter_value_t<I>,
std::iter_value_t<O>>) || std::indirectly_copyable_storable<I, O>)
constexpr unique_copy_result<I, O>

unique_copy( I first, S last, O result, C comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::input_range R, std::weakly_incrementable O, class Proj = std::identity,

std::indirect_equivalence_relation<std::projected<ranges::iterator_t<R>,
Proj>> C = ranges::equal_to >
requires std::indirectly_copyable<ranges::iterator_t<R>, O> &&
(std::forward_iterator<ranges::iterator_t<R>> ||
(std::input_iterator<O> && std::same_as<ranges::range_value_t<R>,
std::iter_value_t<O>>) ||
std::indirectly_copyable_storable<ranges::iterator_t<R>, O>)
constexpr unique_copy_result<ranges::borrowed_iterator_t<R>, O>

unique_copy( R&& r, O result, C comp = {}, Proj proj = {} );
 (2) (C++20 起)
辅助类型
template<class I, class O>
using unique_copy_result = ranges::in_out_result<I, O>;
 (3) (C++20 起)
1) 从源范围 [first, last) 复制元素到始于 result 的目标范围，使得无连续的元素比较相等。只复制每群相等元素中的第一个。
范围 [first, last) 与 [result, result + N) 必须不重叠。 N = ranges::distance(first, last).
认为二个连续元素 *(i - 1) 与 *i 比较相等，若 std::invoke (comp, std::invoke (proj, *(i - 1)), std::invoke (proj, *i)) == true ，其中 i 为范围 [first + 1, last) 中的迭代器。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 源元素范围
r | - | 源元素范围
result | - | 目标元素范围
comp | - | 比较投影后元素的谓词
proj | - | 应用到谓词的投影

返回值

{last, result + N} 。

复杂度

准确应用 N - 1 次对应的谓词 comp 并应用不多于其次数二倍的投影 proj 。

可能的实现

参阅 libstdc++ 与 MSVC STL （及第三方库： cmcstl2、 NanoRange 和 range-v3 ）中的实现。

struct unique_copy_fn {
  template<std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O,
         class Proj = std::identity,
         std::indirect_equivalence_relation<std::projected<I, Proj>> C = ranges::equal_to>
    requires std::indirectly_copyable<I, O> && (std::forward_iterator<I> or
               (std::input_iterator<O> && std::same_as<std::iter_value_t<I>,
                 std::iter_value_t<O>>) or std::indirectly_copyable_storable<I, O>)
      constexpr ranges::unique_copy_result<I, O>
        operator() ( I first, S last, O result, C comp = {}, Proj proj = {} ) const {
            if (!(first == last)) {
                std::iter_value_t<I> value = *first;
                *result = value;
                ++result;
                while (!(++first == last)) {
                    auto&& value2 = *first;
                    if (!std::invoke(comp, std::invoke(proj, value2),
                             std::invoke(proj, value))) {
                        value = std::forward<decltype(value2)>(value2);
                        *result = value;
                        ++result;
                    }
                }
            }

            return {std::move(first), std::move(result)};
        }

  template<ranges::input_range R, std::weakly_incrementable O, class Proj = std::identity,
           std::indirect_equivalence_relation<std::projected<ranges::iterator_t<R>,
             Proj>> C = ranges::equal_to>
    requires std::indirectly_copyable<ranges::iterator_t<R>, O> &&
               (std::forward_iterator<ranges::iterator_t<R>> or
               (std::input_iterator<O> && std::same_as<ranges::range_value_t<R>,
                 std::iter_value_t<O>>) ||
               std::indirectly_copyable_storable<ranges::iterator_t<R>, O>)
      constexpr ranges::unique_copy_result<ranges::borrowed_iterator_t<R>, O>
        operator() ( R&& r, O result, C comp = {}, Proj proj = {} ) const {
            return (*this)(ranges::begin(r), ranges::end(r), std::move(result),
                           std::move(comp), std::move(proj));
        }
};

inline constexpr unique_copy_fn unique_copy{};

示例

#include <algorithm>
#include <cmath>
#include <iostream>
#include <iterator>
#include <list>
#include <string>
#include <type_traits>

void print(const auto& rem, const auto& v) {
    using V = std::remove_cvref_t<decltype(v)>;
    constexpr bool sep {std::is_same_v<typename V::value_type, int>};
    std::cout << rem << std::showpos;
    for (const auto& e : v) std::cout << e << (sep ? " " : "");
    std::cout << '\n';
}

int main()
{
    std::string s1 {"The      string    with many       spaces!"};
    print("s1: ", s1);

    std::string s2;
    std::ranges::unique_copy(
        s1.begin(), s1.end(), std::back_inserter(s2),
        [](char c1, char c2){ return c1 == ' ' && c2 == ' '; }
    );
    print("s2: ", s2);

    const auto v1 = { -1, +1, +2, -2, -3, +3, -3, };
    print("v1: ", v1);
    std::list<int> v2;
    std::ranges::unique_copy(
        v1, std::back_inserter(v2),
        {}, // 默认比较器 std::ranges::equal_to
        [](int x) { return std::abs(x); } // 投影
    );
    print("v2: ", v2);
}

输出：

s1: The      string    with many       spaces!
s2: The string with many spaces!
v1: -1 +1 +2 -2 -3 +3 -3
v2: -1 +2 -3

参阅

ranges::unique (C++20) | 移除范围中的连续重复元素 (niebloid)
ranges::copyranges::copy_if (C++20)(C++20) | 将某一范围的元素复制到一个新的位置 (niebloid)
ranges::adjacent_find (C++20) | 查找首对相邻的相同（或满足给定谓词的）元素 (niebloid)
unique_copy | 创建某范围的不含连续重复元素的副本 (函数模板)


std::ranges::upper_bound

< cpp‎ | algorithm‎ | ranges
定义于头文件 <algorithm>
调用签名
template< std::forward_iterator I, std::sentinel_for<I> S,

class T, class Proj = std::identity,
std::indirect_strict_weak_order<
const T*,
std::projected<I, Proj>> Comp = ranges::less >
constexpr I

upper_bound( I first, S last, const T& value, Comp comp = {}, Proj proj = {} );
 (1) (C++20 起)
template< ranges::forward_range R, class T, class Proj = std::identity,

std::indirect_strict_weak_order<
const T*,
std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less >
constexpr ranges::borrowed_iterator_t<R>

upper_bound( R&& r, const T& value, Comp comp = {}, Proj proj = {} );
 (2) (C++20 起)
1) 返回指向范围 [first, last) 中首个大于 value 的元素的迭代器，或若找不到这种元素返回 last 。 范围 [first, last) 必须已按照表达式 !comp(value, element) 划分，即所有该表达式对其为 true 的元素必须前趋所有该表达式对其为 false 的元素。完全排序的范围符合此判别标准。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 定义要检验的部分有序范围的迭代器-哨位对
r | - | 要检验的部分有序范围
value | - | 要与元素比较的值
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

指向首个大于 value 的元素的迭代器，或若找不到这种元素则为 last 。

复杂度

比较和应用投影的次数与 first 和 last 之间的距离成对数（至多比较和应用投影 log
2(last - first) + O(1) 次）。然而，对于不实现 random_access_iterator 的迭代器，迭代器自增次数为线性。

可能的实现

struct upper_bound_fn {
  template<std::forward_iterator I, std::sentinel_for<I> S,
           class T, class Proj = std::identity,
           std::indirect_strict_weak_order<
               const T*,
               std::projected<I, Proj>> Comp = ranges::less>
  constexpr I operator()( I first, S last, const T& value,
                          Comp comp = {}, Proj proj = {} ) const
  {
      I it;
      std::iter_difference_t<I> count, step;
      count = ranges::distance(first, last);

      while (count > 0) {
          it = first;
          step = count / 2;
          ranges::advance(it, step, last);
          if (!comp(value, *it)) {
              first = ++it;
              count -= step + 1;
          }
          else {
              count = step;
          }
      }
      return first;
  }

  template<ranges::forward_range R, class T, class Proj = std::identity,
           std::indirect_strict_weak_order<
               const T*,
               std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less>
  constexpr ranges::borrowed_iterator_t<R>
  operator()( R&& r, const T& value, Comp comp = {}, Proj proj = {} ) const
  {
    return (*this)(ranges::begin(r), ranges::end(r), value,
                   std::ref(comp), std::ref(proj));
  }
};

inline constexpr upper_bound_fn upper_bound;

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> data = { 1, 1, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6 };

    {
        auto lower = ranges::lower_bound(data.begin(), data.end(), 4);
        auto upper = ranges::upper_bound(data.begin(), data.end(), 4);

        ranges::copy(lower, upper, std::ostream_iterator<int>(std::cout, " "));
        std::cout << '\n';
    }
    {
        auto lower = ranges::lower_bound(data, 3);
        auto upper = ranges::upper_bound(data, 3);

        ranges::copy(lower, upper, std::ostream_iterator<int>(std::cout, " "));
        std::cout << '\n';
    }
}

输出：

4 4 4
3 3 3 3

参阅

ranges::equal_ranges (C++20) | 返回匹配特定值的元素范围 (niebloid)
ranges::lower_bound (C++20) | 返回指向首个不小于给定值的元素的迭代器 (niebloid)
ranges::partition (C++20) | 将范围中的元素分为二组 (niebloid)
upper_bound | 返回指向第一个大于给定值的元素的迭代器 (函数模板)


std::reduce

< cpp‎ | algorithm
定义于头文件 <numeric>
(1)
template<class InputIt>

typename std::iterator_traits <InputIt>::value_type reduce(

InputIt first, InputIt last);
 (C++17 起)
(C++20 前)
template<class InputIt>

constexpr typename std::iterator_traits <InputIt>::value_type reduce(

InputIt first, InputIt last);
 (C++20 起)
template<class ExecutionPolicy, class ForwardIt>

typename std::iterator_traits <ForwardIt>::value_type reduce(
ExecutionPolicy&& policy,

ForwardIt first, ForwardIt last);
 (2) (C++17 起)
(3)
template<class InputIt, class T>
T reduce(InputIt first, InputIt last, T init);
 (C++17 起)
(C++20 前)
template<class InputIt, class T>
constexpr T reduce(InputIt first, InputIt last, T init);
 (C++20 起)
template<class ExecutionPolicy, class ForwardIt, class T>

T reduce(ExecutionPolicy&& policy,

ForwardIt first, ForwardIt last, T init);
 (4) (C++17 起)
(5)
template<class InputIt, class T, class BinaryOp>
T reduce(InputIt first, InputIt last, T init, BinaryOp binary_op);
 (C++17 起)
(C++17 前)
template<class InputIt, class T, class BinaryOp>
constexpr T reduce(InputIt first, InputIt last, T init, BinaryOp binary_op);
 (C++17 起)
template<class ExecutionPolicy, class ForwardIt, class T, class BinaryOp>

T reduce(ExecutionPolicy&& policy,

ForwardIt first, ForwardIt last, T init, BinaryOp binary_op);
 (6) (C++17 起)
1) 同 reduce(first, last, typename std::iterator_traits <InputIt>::value_type{})
3) 同 reduce(first, last, init, std::plus <>())
5) 在 binary_op 上以初值 init 规约范围 [first; last) ，可能以未指定方式排序聚合。
2,4,6) 同 (1,3,5) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

若 binary_op 非结合或非交换，则行为非确定。

若 binary_op 修改 [first; last] 中任何元素或非法化范围中任何迭代器，含尾迭代器，则行为未定义。

参数

first, last | - | 要应用算法的元素范围
init | - | 广义和的初值
policy | - | 使用的执行策略。细节见执行策略。
binary_op | - | 将以未指定顺序应用于解引用输入迭代器结果、其他 binary_op 结果及 init 上的二元函数对象 (FunctionObject) 。
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- T 必须满足可移动构造 (MoveConstructible) 的要求。而且 binary_op(init, *first) 、 binary_op(*first, init) 、 binary_op(init, init) 及 binary_op(*first, *first) 必须可转换到 T 。

返回值

init 及 *first 、 *(first+1) 、…… *(last-1) 在 binary_op 上的广义和，

其中广义和 GSUM(op, a
1, ..., a
N) 定义如下：

  • 若 N=1 ，则为 a
    1
  • 若 N > 1 ，则为 op(GSUM(op, b
    1    , ..., b
    K    ), GSUM(op, b
    M    , ..., b
    N    ))     ，其中
  • b
    1    , ..., b
    N     可以是任何 a1, ..., aN 的排列，且
  • 1 < K+1 = M ≤ N

换言之， reduce 表现类似 std::accumulate ，除了范围中的元素可能以任意顺序分组并重排。

复杂度

O(last - first) 次应用 binary_op.

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

若范围为空，则返回不修改的 init 。

示例

reduce 与 std::accumulate 间并行的比较：

#include <iostream>
#include <chrono>
#include <vector>
#include <numeric>
#include <execution>

int main()
{
    std::vector<double> v(10'000'007, 0.5);

    {
        auto t1 = std::chrono::high_resolution_clock::now();
        double result = std::accumulate(v.begin(), v.end(), 0.0);
        auto t2 = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double, std::milli> ms = t2 - t1;
        std::cout << std::fixed << "std::accumulate result " << result
                  << " took " << ms.count() << " ms\n";
    }

    {
        auto t1 = std::chrono::high_resolution_clock::now();
        double result = std::reduce(std::execution::par, v.begin(), v.end());
        auto t2 = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double, std::milli> ms = t2 - t1;
        std::cout << "std::reduce result "
                  << result << " took " << ms.count() << " ms\n";
    }
}

可能的输出：

std::accumulate result 5000003.50000 took 12.7365 ms
std::reduce result 5000003.50000 took 5.06423 ms

参阅

accumulate | 对一个范围内的元素求和 (函数模板)
transform | 将一个函数应用于某一范围的各个元素，并在目标范围存储结果 (函数模板)
transform_reduce (C++17) | 应用一个函数对象，然后以乱序规约 (函数模板)


std::remove, std::remove_if

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class ForwardIt, class T >
ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );
 (C++20 前)
template< class ForwardIt, class T >
constexpr ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class T >

ForwardIt remove( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,

const T& value );
 (2) (C++17 起)
(3)
template< class ForwardIt, class UnaryPredicate >
ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPredicate p );
 (C++20 前)
template< class ForwardIt, class UnaryPredicate >
constexpr ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >

ForwardIt remove_if( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,

UnaryPredicate p );
 (4) (C++17 起)

从范围 [first, last) 移除所有满足特定判别标准的元素，并返回范围新结尾的尾后迭代器。

1) 移除所有等于 value 的元素，用 operator== 比较它们。
3) 移除所有 p 对于它返回 true 的元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

通过使未被移除的元素出现在范围起始这种方式，迁移（方式为复制赋值 (C++11 前)移动赋值 (C++11 起)）范围中元素，来进行移除。保持剩余元素的相对顺序而容器的物理大小保持不变。指向新的逻辑结尾与物理结尾之间的迭代器仍然可解引用，但元素自身拥有未指定的值（经由可移动赋值 (MoveAssignable) 的后条件）。

参数

first, last | - | 要处理的元素范围
value | - | 要移除的元素值
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若应该移除元素则返回 ​true 的一元谓词。 对每个（可为 const 的） VT 类型参数 v ，其中 VT 是 ForwardIt 的值类型，表达式 p(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 VT& 类型参数，亦不允许 VT ，除非对 VT 而言移动等价于复制 (C++11 起)。 ​
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 解引用 ForwardIt 结果的类型必须满足可移动赋值 (MoveAssignable) 的要求。
- UnaryPredicate 必须满足谓词 (Predicate) 的要求。

返回值

新值范围的尾后迭代器（若它不是 end ，则它指向未指定值，而此迭代器与 end 之间的迭代器所指向的任何值亦然）。

复杂度

准确应用 std::distance (first, last) 次谓词。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

调用 std::remove 常后随容器的 erase 成员函数，它擦除未指定值并减小容器的物理大小以匹配其新的逻辑大小。这两个调用一并被称为擦除-移除手法 ，它可通过对所有标准序列容器重载的 std::erase 自由函数，或对所有标准容器重载的 std::erase_if 自由函数达成 (C++20 起)。

同名的容器成员函数 list::remove、 list::remove_if、 forward_list::remove 及 forward_list::remove_if 擦除被移除的元素。

这些算法通常不能用于如 std::set 与 std::map 的关联容器，因为其迭代器类型不解引用为可移动赋值 (MoveAssignable) 类型（这些容器中的键不可修改）。

标准库亦于 <cstdio> 定义 std::remove 的重载，它接收 const char* 的重载并用于删除文件。

因为 std::remove 以引用接收 value ，若引用到范围 [first, last) 中的元素，则它可能有不可预期的行为。

可能的实现

版本一
template< class ForwardIt, class T >
ForwardIt remove(ForwardIt first, ForwardIt last, const T& value)
{
    first = std::find(first, last, value);
    if (first != last)
        for(ForwardIt i = first; ++i != last; )
            if (!(*i == value))
                *first++ = std::move(*i);
    return first;
}
版本二
template<class ForwardIt, class UnaryPredicate>
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p)
{
    first = std::find_if(first, last, p);
    if (first != last)
        for(ForwardIt i = first; ++i != last; )
            if (!p(*i))
                *first++ = std::move(*i);
    return first;
}

示例

下列代码从 string 移除所有空格，通过迁移所有非空格字符到左侧，再擦除其他内容。这是擦除移除手法的样例。

#include <algorithm>
#include <string>
#include <iostream>
#include <cctype>

int main()
{
    std::string str1 = "Text with some   spaces";
    str1.erase(std::remove(str1.begin(), str1.end(), ' '),
               str1.end());
    std::cout << str1 << '\n';

    std::string str2 = "Text\n with\tsome \t  whitespaces\n\n";
    str2.erase(std::remove_if(str2.begin(),
                              str2.end(),
                              [](unsigned char x){return std::isspace(x);}),
               str2.end());
    std::cout << str2 << '\n';
}

输出：

Textwithsomespaces
Textwithsomewhitespaces

参阅

remove_copyremove_copy_if | 复制一个范围的元素，忽略满足特定判别标准的元素 (函数模板)
unique | 移除范围内的连续重复元素 (函数模板)
ranges::removeranges::remove_if (C++20)(C++20) | 移除满足特定判别标准的元素 (niebloid)


std::remove_copy, std::remove_copy_if

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class InputIt, class OutputIt, class T >

OutputIt remove_copy( InputIt first, InputIt last, OutputIt d_first,

const T& value );
 (C++20 前)
template< class InputIt, class OutputIt, class T >

constexpr OutputIt remove_copy( InputIt first, InputIt last, OutputIt d_first,

const T& value );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T >

ForwardIt2 remove_copy( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 d_first, const T& value );
 (2) (C++17 起)
(3)
template< class InputIt, class OutputIt, class UnaryPredicate >

OutputIt remove_copy_if( InputIt first, InputIt last, OutputIt d_first,

UnaryPredicate p );
 (C++20 前)
template< class InputIt, class OutputIt, class UnaryPredicate >

constexpr OutputIt remove_copy_if( InputIt first, InputIt last, OutputIt d_first,

UnaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class UnaryPredicate >

ForwardIt2 remove_copy_if( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 d_first, UnaryPredicate p );
 (4) (C++17 起)

复制来自范围 [first, last) 的元素到始于 d_first 的另一范围，省略满足特定判别标准的元素。源与目标范围不能重叠。

1) 忽略所有等于 value 的元素。
3) 忽略所有谓词 p 对其返回 true 的元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要复制的元素范围
d_first | - | 目标范围的起始。
value | - | 不复制的元素的值
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- UnaryPredicate 必须满足谓词 (Predicate) 的要求。

返回值

指向最后被复制元素的迭代器。

复杂度

准确应用 last - first 次谓词。

对拥有 ExecutionPolicy 的重载，若 ForwardIt1 的值类型非可移动构造 (MoveConstructible) 则有性能开销。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class InputIt, class OutputIt, class T>
OutputIt remove_copy(InputIt first, InputIt last,
                     OutputIt d_first, const T& value)
{
    for (; first != last; ++first) {
        if (!(*first == value)) {
            *d_first++ = *first;
        }
    }
    return d_first;
}
版本二
template<class InputIt, class OutputIt, class UnaryPredicate>
OutputIt remove_copy_if(InputIt first, InputIt last,
                        OutputIt d_first, UnaryPredicate p)
{
    for (; first != last; ++first) {
        if (!p(*first)) {
            *d_first++ = *first;
        }
    }
    return d_first;
}

示例

下列代码输出字符串并临时擦除空格。

#include <algorithm>
#include <iterator>
#include <string>
#include <iostream>
int main()
{
    std::string str = "Text with some   spaces";
    std::cout << "before: " << str << "\n";

    std::cout << "after:  ";
    std::remove_copy(str.begin(), str.end(),
                     std::ostream_iterator<char>(std::cout), ' ');
    std::cout << '\n';
}

输出：

before: Text with some   spaces
after:  Textwithsomespaces

参阅

removeremove_if | 移除满足特定判别标准的元素 (函数模板)
copycopy_if (C++11) | 将某一范围的元素复制到一个新的位置 (函数模板)
partition_copy (C++11) | 复制一个范围，将各元素分为两组 (函数模板)


std::replace, std::replace_if

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class ForwardIt, class T >

void replace( ForwardIt first, ForwardIt last,

const T& old_value, const T& new_value );
 (C++20 前)
template< class ForwardIt, class T >

constexpr void replace( ForwardIt first, ForwardIt last,

const T& old_value, const T& new_value );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class T >

void replace( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,

const T& old_value, const T& new_value );
 (2) (C++17 起)
(3)
template< class ForwardIt, class UnaryPredicate, class T >

void replace_if( ForwardIt first, ForwardIt last,

UnaryPredicate p, const T& new_value );
 (C++20 前)
template< class ForwardIt, class UnaryPredicate, class T >

constexpr void replace_if( ForwardIt first, ForwardIt last,

UnaryPredicate p, const T& new_value );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate, class T >

void replace_if( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,

UnaryPredicate p, const T& new_value );
 (4) (C++17 起)

以 new_value 替换范围 [first, last) 中所有满足特定判别标准的元素。

1) 替换所有等于 old_value 的元素。
3) 替换所有谓词 p 对其返回 true 的元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。。

参数

first, last | - | 要处理的元素范围
old_value | - | 要被替换的元素值
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若应该替换元素则返回 ​true 的一元谓词。 对每个（可为 const 的） VT 类型参数 v ，其中 VT 是 ForwardIt 的值类型，表达式 p(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 VT& 类型参数，亦不允许 VT ，除非对 VT 而言移动等价于复制 (C++11 起)。 ​
new_value | - | 用作替换者的值
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- UnaryPredicate 必须满足谓词 (Predicate) 的要求。

返回值

（无）

复杂度

准确应用 last - first 次谓词。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

算法以引用接收 old_value 和 new_value ，故若任一者是到范围 [first, last) 中元素的引用，则算法能有不期待的行为。

可能的实现

版本一
template<class ForwardIt, class T>
void replace(ForwardIt first, ForwardIt last,
             const T& old_value, const T& new_value)
{
    for (; first != last; ++first) {
        if (*first == old_value) {
            *first = new_value;
        }
    }
}
版本二
template<class ForwardIt, class UnaryPredicate, class T>
void replace_if(ForwardIt first, ForwardIt last,
                UnaryPredicate p, const T& new_value)
{
    for (; first != last; ++first) {
        if(p(*first)) {
            *first = new_value;
        }
    }
}

示例

下列代码首先在 int 的 vector 中以 88 替换 8 的所有出现，然后以 55 替换所有小于 5 的值。

#include <algorithm>
#include <array>
#include <iostream>
#include <functional>

int main()
{
    std::array<int, 10> s{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};

    std::replace(s.begin(), s.end(), 8, 88);

    for (int a : s) {
        std::cout << a << " ";
    }
    std::cout << '\n';

    std::replace_if(s.begin(), s.end(),
                    std::bind(std::less<int>(), std::placeholders::_1, 5), 55);
    for (int a : s) {
        std::cout << a << " ";
    }
    std::cout << '\n';
}

输出：

5 7 4 2 88 6 1 9 0 3
5 7 55 55 88 6 55 9 55 55

参阅

replace_copyreplace_copy_if | 复制一个范围内的元素，并将满足特定判别标准的元素替换为另一个值 (函数模板)
ranges::replaceranges::replace_if (C++20)(C++20) | 将所有满足特定判别标准的值替换为另一个值 (niebloid)


std::replace_copy, std::replace_copy_if

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class InputIt, class OutputIt, class T >

OutputIt replace_copy( InputIt first, InputIt last, OutputIt d_first,

const T& old_value, const T& new_value );
 (C++20 前)
template< class InputIt, class OutputIt, class T >

constexpr OutputIt replace_copy( InputIt first, InputIt last, OutputIt d_first,

const T& old_value, const T& new_value );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T >

ForwardIt2 replace_copy( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 d_first, const T& old_value, const T& new_value );
 (2) (C++17 起)
(3)
template< class InputIt, class OutputIt, class UnaryPredicate, class T >

OutputIt replace_copy_if( InputIt first, InputIt last, OutputIt d_first,

UnaryPredicate p, const T& new_value );
 (C++20 前)
template< class InputIt, class OutputIt, class UnaryPredicate, class T >

constexpr OutputIt replace_copy_if( InputIt first, InputIt last, OutputIt d_first,

UnaryPredicate p, const T& new_value );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class UnaryPredicate, class T >

ForwardIt2 replace_copy_if( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 d_first, UnaryPredicate p, const T& new_value );
 (4) (C++17 起)

复制来自范围 [first, last) 的元素到始于 d_first 的范围，并以 new_value 替换所有满足特定判别标准的元素。源与目标范围不能重叠。

1) 替换所有等于 old_value 的元素。
3) 替换所有谓词 p 对其满足 true 的元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要复制的元素范围
d_first | - | 目标范围的起始
old_value | - | 要被替换的元素值
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若应该替换元素则返回 ​true 的一元谓词。 对每个（可为 const 的） VT 类型参数 v ，其中 VT 是 InputIt 的值类型，表达式 p(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 VT& 类型参数，亦不允许 VT ，除非对 VT 而言移动等价于复制 (C++11 起)。 ​
new_value | - | 用作替换者的元素值
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

指向最后复制元素后一元素的迭代器。

复杂度

准确应用 last - first 次谓词。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class InputIt, class OutputIt, class T>
OutputIt replace_copy(InputIt first, InputIt last, OutputIt d_first,
                      const T& old_value, const T& new_value)
{
    for (; first != last; ++first) {
        *d_first++ = (*first == old_value) ? new_value : *first;
    }
    return d_first;
}
版本二
template<class InputIt, class OutputIt,
         class UnaryPredicate, class T>
OutputIt replace_copy_if(InputIt first, InputIt last, OutputIt d_first,
                         UnaryPredicate p, const T& new_value)
{
    for (; first != last; ++first) {
        *d_first++ = p( *first ) ? new_value : *first;
    }
    return d_first;
}

示例

下列代码打印 vector ，同时临时替换所有超过 5 的值为 99 。

#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>
#include <functional>

int main()
{
    std::vector<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
    std::replace_copy_if(v.begin(), v.end(),
                         std::ostream_iterator<int>(std::cout, " "),
                         [](int n){return n > 5;}, 99);
    std::cout << '\n';
}

输出：

5 99 4 2 99 99 1 99 0 3

参阅

replacereplace_if | 将所有满足特定判别标准的值替换为另一个值 (函数模板)
removeremove_if | 移除满足特定判别标准的元素 (函数模板)
ranges::replace_copyranges::replace_copy_if (C++20)(C++20) | 复制一个范围内的元素，并将满足特定判别标准的元素替换为另一个值 (niebloid)


std::reverse

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class BidirIt > void reverse( BidirIt first, BidirIt last ); |  |  | (C++20 前)
template< class BidirIt > constexpr void reverse( BidirIt first, BidirIt last ); |  |  | (C++20 起)
template< class ExecutionPolicy, class BidirIt > void reverse( ExecutionPolicy&& policy, BidirIt first, BidirIt last ); | (2) | (C++17 起)
1) 反转 [first, last) 范围中的元素顺序
表现如同应用 std::iter_swap 到对于非负 i < (last-first)/2 的每对迭代器 first+i, (last-i) - 1
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要反转的元素的范围
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- BidirIt 必须满足值可交换 (ValueSwappable) 和 老式双向迭代器 (LegacyBidirectionalIterator) 的要求。

返回值

（无）

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

复杂度

恰好交换 (last - first)/2 次。

注解

实现（例如 MSVC STL ）可能在迭代器类型满足老式连续迭代器 (LegacyContiguousIterator) ，并且交换其值类型不调用非平凡的特殊成员函数或 ADL 所找到的 swap 时启用向量化。

可能的实现

参阅 libstdc++ 、 libc++ 和 MSVC STL 中的实现。

template<class BidirIt>
constexpr // C++20 起
void reverse(BidirIt first, BidirIt last)
{
    using iter_cat = typename std::iterator_traits<BidirIt>::iterator_category;

    // 能在 C++14 和更早的模式中使用标签派发，
    // 例如调用 reverse_impl(first, last, iter_cat()) 。
    if constexpr (std::is_base_of_v<std::random_access_iterator_tag, iter_cat>) {
        if (first == last)
            return;
        for (--last; first < last; (void)++first, --last) {
            std::iter_swap(first, last);
        }
    }
    else {
        while ((first != last) && (first != --last)) {
            std::iter_swap(first++, last);
        }
    }
}

示例

#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    std::vector<int> v{1,2,3};
    std::reverse(std::begin(v), std::end(v));
    for(auto e : v) std::cout << e;
    std::cout << '\n';

    int a[] = {4, 5, 6, 7};
    std::reverse(std::begin(a), std::end(a));
    for(auto e : a) std::cout << e;
}

输出：

321
7654

参阅

reverse_copy | 创建一个范围的逆向副本 (函数模板)
ranges::reverse (C++20) | 逆转范围中的元素顺序 (niebloid)


std::reverse_copy

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class BidirIt, class OutputIt >
OutputIt reverse_copy( BidirIt first, BidirIt last, OutputIt d_first );
 (C++20 前)
template< class BidirIt, class OutputIt >
constexpr OutputIt reverse_copy( BidirIt first, BidirIt last, OutputIt d_first );
 (C++20 起)
template< class ExecutionPolicy, class BidirIt, class ForwardIt >

ForwardIt reverse_copy( ExecutionPolicy&& policy,

BidirIt first, BidirIt last, ForwardIt d_first );
 (2) (C++17 起)
1) 复制来自范围 [first, last) 的元素到始于 d_first 的新范围，使得新范围中元素以逆序排列。
表现如同通过对于每个非负的 i < (last - first) 执行一次赋值 *(d_first + (last - first) - 1 - i) = *(first + i) 。
若源与目标范围（分别为 [first, last) 和 [d_first, d_first+(last-first)) ）重叠，则行为未定义。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要复制的元素范围
d_first | - | 新范围的起始
类型要求
- BidirIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

指向最后被复制元素后一元素的迭代器。

复杂度

准确赋值 last - first 次。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

实现（例如 MSVC STL ）可能在两个迭代器类型均满足老式连续迭代器 (LegacyContiguousIterator) 并拥有同一值类型，且值类型为可平凡复制 (TriviallyCopyable) 时启用向量化。

可能的实现

参阅 libstdc++、 libc++ 和 MSVC STL 中的实现。

template<class BidirIt, class OutputIt>
constexpr // C++20 起
OutputIt reverse_copy(BidirIt first, BidirIt last, OutputIt d_first)
{
    while (first != last) {
        *(d_first++) = *(--last);
    }
    return d_first;
}

示例

#include <vector>
#include <iostream>
#include <algorithm>

int main()
{
    std::vector<int> v({1,2,3});
    for (const auto& value : v) {
        std::cout << value << " ";
    }
    std::cout << '\n';

    std::vector<int> destination(3);
    std::reverse_copy(std::begin(v), std::end(v), std::begin(destination));
    for (const auto& value : destination) {
        std::cout << value << " ";
    }
    std::cout << '\n';
}

输出：

1 2 3
3 2 1

参阅

reverse | 逆转范围中的元素顺序 (函数模板)
ranges::revserse_copy (C++20) | 创建一个范围的逆向副本 (niebloid)


std::rotate

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class ForwardIt >
void rotate( ForwardIt first, ForwardIt n_first, ForwardIt last );
 (C++11 前)
template< class ForwardIt >
ForwardIt rotate( ForwardIt first, ForwardIt n_first, ForwardIt last );
 (C++11 起)
(C++20 前)
template< class ForwardIt >
constexpr ForwardIt rotate( ForwardIt first, ForwardIt n_first, ForwardIt last );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt >

ForwardIt rotate( ExecutionPolicy&& policy,

ForwardIt first, ForwardIt n_first, ForwardIt last );
 (2) (C++17 起)
1) 进行元素范围上的左旋转。
具体而言， std::rotate 交换范围 [first, last) 中的元素，方式满足元素 n_first 成为新范围的首个元素，而 n_first - 1 成为最后元素。
此函数的前提条件是 [first, n_first) 和 [n_first, last) 为合法范围。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first | - | 原范围的起始
n_first | - | 应出现在旋转后范围起始的元素
last | - | 原范围的结尾
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- ForwardIt 必须满足值可交换 (ValueSwappable) 和 老式向前迭代器 (LegacyForwardIterator) 的要求。
- 解引用 ForwardIt 结果的类型必须满足可移动赋值 (MoveAssignable) 和可移动构造 (MoveConstructible) 的要求。

返回值

（无） | (C++11 前)
指向 first 指向的元素所在的新位置的迭代器。等于 first + (last - n_first) 。 | (C++11 起)

复杂度

与 first 和 last 间的距离成线性。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

在常见实现上，若 ForwardIt 满足老式双向迭代器 (LegacyBidirectionalIterator) 或（更好的）老式随机访问迭代器 (LegacyRandomAccessIterator) 则 ranges::rotate 有更高的效率。

实现（例如 MSVC STL ）可能在迭代器类型满足老式连续迭代器 (LegacyContiguousIterator) ，并且交换其值类型不调用非平凡的特殊成员函数或 ADL 所找到的 swap 时启用向量化。

可能的实现

参阅 libstdc++、 libc++ 和 MSVC STL 中的实现。

template<class ForwardIt>
constexpr // C++20 起
ForwardIt // C++11 前为 void
rotate(ForwardIt first, ForwardIt n_first, ForwardIt last)
{
   if(first == n_first) return last;
   if(n_first == last) return first;

   auto read      = n_first;
   auto write     = first;
   auto next_read = first; // "read" 撞击 "last" 时的读取位置

   while(read != last) {
      if(write == next_read) next_read = read; // 跟踪 "first" 所至
      std::iter_swap(write++, read++);
   }

   // 旋转剩余序列到位置中
   (rotate)(write, next_read, last);
   return write;
}

示例

std::rotate 是许多算法中的公共构建块。此示例演示插入排序。

#include <vector>
#include <iostream>
#include <algorithm>

auto print = [](auto const& remark, auto const& v) {
    std::cout << remark;
    for (int n: v)
        std::cout << n << ' ';
    std::cout << '\n';
};

int main()
{
    std::vector<int> v{2, 4, 2, 0, 5, 10, 7, 3, 7, 1};

    print("before sort:\t\t", v);

    // 插入排序
    for (auto i = v.begin(); i != v.end(); ++i) {
        std::rotate(std::upper_bound(v.begin(), i, *i), i, i+1);
    }

    print("after sort:\t\t", v);

    // 简单向左旋转
    std::rotate(v.begin(), v.begin() + 1, v.end());

    print("simple rotate left:\t", v);

    // 简单向右旋转
    std::rotate(v.rbegin(), v.rbegin() + 1, v.rend());

    print("simple rotate right:\t", v);
}

输出：

before sort:            2 4 2 0 5 10 7 3 7 1
after sort:             0 1 2 2 3 4 5 7 7 10
simple rotate left:     1 2 2 3 4 5 7 7 10 0
simple rotate right:    0 1 2 2 3 4 5 7 7 10

参阅

rotate_copy | 复制并旋转元素范围 (函数模板)
ranges::rotate (C++20) | 旋转范围中的元素顺序 (niebloid)


std::rotate_copy

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class ForwardIt, class OutputIt > OutputIt rotate_copy( ForwardIt first, ForwardIt n_first, ForwardIt last, OutputIt d_first ); |  |  | (C++20 前)
template< class ForwardIt, class OutputIt > constexpr OutputIt rotate_copy( ForwardIt first, ForwardIt n_first, ForwardIt last, OutputIt d_first ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 > ForwardIt2 rotate_copy( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 n_first, ForwardIt1 last, ForwardIt2 d_first ); | (2) | (C++17 起)
1) 从范围 [first, last) 复制元素到始于 d_first 的另一范围，使得 *n_first 成为新范围的首元素，而 *(n_first - 1) 成为末元素。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要复制的元素范围
n_first | - | 指向 [first, last) 中应出现在新范围起始的元素的迭代器
d_first | - | 目标范围的起始
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- ForwardIt, ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。

返回值

指向最后被复制元素后一元素的输出迭代器。

复杂度

与 first 和 last 间的距离成线性。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

参阅 libstdc++、 libc++ 与 MSVC STL 中的实现。

template<class ForwardIt, class OutputIt>
constexpr // C++20 起
OutputIt rotate_copy(ForwardIt first, ForwardIt n_first,
                           ForwardIt last, OutputIt d_first)
{
    d_first = std::copy(n_first, last, d_first);
    return std::copy(first, n_first, d_first);
}

示例

#include <algorithm>
#include <vector>
#include <iostream>

int main()
{
    std::vector<int> src = {1, 2, 3, 4, 5};
    auto pivot = std::find(src.begin(), src.end(), 3);
    std::vector<int> dest(src.size());

    std::rotate_copy(src.begin(), pivot, src.end(), dest.begin());

    for (const auto &i : dest) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
}

输出：

3 4 5 1 2

参阅

rotate | 旋转范围中的元素顺序 (函数模板)
ranges::rotate_copy (C++20) | 复制并旋转元素范围 (niebloid)


std::sample

< cpp‎ | algorithm
定义于头文件 <algorithm> |
template< class PopulationIterator, class SampleIterator, class Distance, class URBG > SampleIterator sample( PopulationIterator first, PopulationIterator last, SampleIterator out, Distance n, URBG&& g); | (C++17 起)

从序列 [first; last) 选择 n 个元素（无替换），使得每个样本拥有相等的出现概率，并写入这些被选择元素到输出迭代器 out 。用随机数生成器 g 生成随机数。

若 n 大于序列中的元素数量，则选择 last-first 个元素。

算法仅若 PopulationIterator 满足老式向前迭代器 (LegacyForwardIterator) 要求才稳定（保持被选择元素 的顺序）。

若 out 在 [first; last) 中则行为未定义。

参数

first, last | - | 一对组成自其采样的范围（总体）的迭代器
out | - | 写入样本的输出迭代器
n | - | 要抽取的样本数
g | - | 用作随机源的随机数生成器
类型要求
- PopulationIterator 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- SampleIterator 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- 若 PopulationIterator 不满足老式向前迭代器 (LegacyForwardIterator) ，则 SampleIterator 还必须满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求
- PopulationIterator的 value_type 必须可写入到 out
- Distance 必须是整数类型
- std::remove_reference_t <URBG> 必须满足均匀随机位生成器 (UniformRandomBitGenerator) ，且其返回类型必须可转换为 Distance

返回值

在输出最后样本后返回 out 的副本，即采样范围的结尾。

复杂度

与 std::distance (first,last) 成线性

注解

此函数可以实现选择抽样或蓄水池抽样。

可能的实现

参阅 libstdc++、 libc++ 与 MSVC STL 中的实现。

示例

#include <iostream>
#include <random>
#include <string>
#include <iterator>
#include <algorithm>

int main()
{
    std::string in = "hgfedcba", out;
    std::sample(in.begin(), in.end(), std::back_inserter(out),
                5, std::mt19937{std::random_device{}()});
    std::cout << "five random letters out of " << in << " : " << out << '\n';
}

可能的输出：

five random letters out of hgfedcba: gfcba

参阅

random_shuffleshuffle
(C++17 前)(C++11)
 随机重排范围中的元素
(函数模板)


std::search

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class ForwardIt1, class ForwardIt2 >

ForwardIt1 search( ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last );
 (C++20 前)
template< class ForwardIt1, class ForwardIt2 >

constexpr ForwardIt1 search( ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >

ForwardIt1 search( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last );
 (2) (C++17 起)
(3)
template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >

ForwardIt1 search( ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );
 (C++20 前)
template< class ForwardIt1, class ForwardIt2, class BinaryPredicate >

constexpr ForwardIt1 search( ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class BinaryPredicate >

ForwardIt1 search( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 s_first, ForwardIt2 s_last, BinaryPredicate p );
 (4) (C++17 起)
(5)
template<class ForwardIt, class Searcher>

ForwardIt search( ForwardIt first, ForwardIt last,

const Searcher& searcher );
 (C++17 起)
(C++20 前)
template<class ForwardIt, class Searcher>

constexpr ForwardIt search( ForwardIt first, ForwardIt last,

const Searcher& searcher );
 (C++20 起)
1-4) 搜索范围 [first, last - (s_last - s_first)) 中元素子序列 [s_first, s_last) 的首次出现。
1) 元素用 operator== 比较。
3) 元素用给定的二元谓词 p 比较。
2,4) 同 (1,3) ，但按 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。
5) 在序列 [first, last) 中搜索 searcher 构造函数中指定的模式。等效地执行 return searcher(first, last).first; 。搜索器 (Searcher) 不必为可复制构造 (CopyConstructible) 。

标准库提供下列搜索器：

default_searcher (C++17) | 标准 C++ 库搜索算法实现 (类模板)
boyer_moore_searcher (C++17) | Boyer-Moore 搜索算法实现 (类模板)
boyer_moore_horspool_searcher (C++17) | Boyer-Moore-Horspool 搜索算法实现 (类模板)
 (C++17 起)

参数

first, last | - | 要检验的元素范围
s_first, s_last | - | 要搜索的元素范围
policy | - | 所用的执行策略。细节见执行策略。
searcher | - | 封装搜索算法和搜索模式的搜索器
p | - | 若元素应被当做相等则返回 ​true 的二元谓词。 谓词函数的签名应等价于如下： bool pred(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 ForwardIt1 与 ForwardIt2 类型的对象在解引用后分别能隐式转换到 Type1 与 Type2 。 ​
类型要求
- ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- Searcher 必须满足搜索器 (Searcher) 的要求。

返回值

1-4) 指向范围中 [first, last - (s_last - s_first)) ，首个子序列 [s_first, s_last) 起始的迭代器。若找不到这种子序列，则返回 last 。
若 [s_first, s_last) 为空，则返回 first 。 (C++11 起)
5) 返回 searcher.operator() 的结果，即指向找到的子串位置的迭代器，或若找不到则为 last 。

复杂度

1-4) 至多 S*N 次搜索，其中 S = std::distance (s_first, s_last) 而 N = std::distance (first, last) 。
5) 依赖于搜索器

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class ForwardIt1, class ForwardIt2>
ForwardIt1 search(ForwardIt1 first, ForwardIt1 last,
                        ForwardIt2 s_first, ForwardIt2 s_last)
{
    for (; ; ++first) {
        ForwardIt1 it = first;
        for (ForwardIt2 s_it = s_first; ; ++it, ++s_it) {
            if (s_it == s_last) {
                return first;
            }
            if (it == last) {
                return last;
            }
            if (!(*it == *s_it)) {
                break;
            }
        }
    }
}
版本二
template<class ForwardIt1, class ForwardIt2, class BinaryPredicate>
ForwardIt1 search(ForwardIt1 first, ForwardIt1 last,
                        ForwardIt2 s_first, ForwardIt2 s_last,
                        BinaryPredicate p)
{
    for (; ; ++first) {
        ForwardIt1 it = first;
        for (ForwardIt2 s_it = s_first; ; ++it, ++s_it) {
            if (s_it == s_last) {
                return first;
            }
            if (it == last) {
                return last;
            }
            if (!p(*it, *s_it)) {
                break;
            }
        }
    }
}

示例

#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
#include <functional>

template<typename Container>
bool in_quote(const Container& cont, const std::string& s)
{
    return std::search(cont.begin(), cont.end(), s.begin(), s.end()) != cont.end();
}

int main()
{
    std::string str = "why waste time learning, when ignorance is instantaneous?";
    // str.find() 也能使用
    std::cout << std::boolalpha << in_quote(str, "learning") << '\n'
                                << in_quote(str, "lemming")  << '\n';

    std::vector<char> vec(str.begin(), str.end());
    std::cout << std::boolalpha << in_quote(vec, "learning") << '\n'
                                << in_quote(vec, "lemming")  << '\n';

    // C++17 重载演示：
    std::string in = "Lorem ipsum dolor sit amet, consectetur adipiscing elit,"
                     " sed do eiusmod tempor incididunt ut labore et dolore magna aliqua";
    std::string needle = "pisci";
    auto it = std::search(in.begin(), in.end(),
                   std::boyer_moore_searcher(
                       needle.begin(), needle.end()));
    if(it != in.end())
        std::cout << "The string " << needle << " found at offset "
                  << it - in.begin() << '\n';
    else
        std::cout << "The string " << needle << " not found\n";
}

输出：

true
false
true
false
The string pisci found at offset 43

参阅

find_end | 在特定范围中寻找最后出现的元素序列 (函数模板)
includes | 若一个序列是另一个的子列则返回 true (函数模板)
equal | 确定两个元素集合是否是相同的 (函数模板)
findfind_iffind_if_not (C++11) | 寻找首个满足特定判别标准的元素 (函数模板)
lexicographical_compare | 当一个范围按字典顺序小于另一个范围时，返回 true (函数模板)
mismatch | 寻找两个范围出现不同的首个位置 (函数模板)
search_n | 在范围中搜索一定量的某个元素的连续副本 (函数模板)
default_searcher (C++17) | 标准 C++ 库搜索算法实现 (类模板)
boyer_moore_searcher (C++17) | Boyer-Moore 搜索算法实现 (类模板)
boyer_moore_horspool_searcher (C++17) | Boyer-Moore-Horspool 搜索算法实现 (类模板)


std::search_n

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class ForwardIt, class Size, class T >
ForwardIt search_n( ForwardIt first, ForwardIt last, Size count, const T& value );
 (C++20 前)
template< class ForwardIt, class Size, class T >
constexpr ForwardIt search_n( ForwardIt first, ForwardIt last, Size count, const T& value );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class Size, class T >
ForwardIt search_n( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, Size count, const T& value );
 (2) (C++17 起)
(3)
template< class ForwardIt, class Size, class T, class BinaryPredicate >

ForwardIt search_n( ForwardIt first, ForwardIt last, Size count, const T& value,

BinaryPredicate p );
 (C++20 前)
template< class ForwardIt, class Size, class T, class BinaryPredicate >

constexpr ForwardIt search_n( ForwardIt first, ForwardIt last, Size count, const T& value,

BinaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class Size, class T, class BinaryPredicate >

ForwardIt search_n( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, Size count, const T& value,

BinaryPredicate p );
 (4) (C++17 起)

在范围 [first, last) 中搜索 count 个等同元素的序列，每个都等于给定的值 value 。

1) 用 operator== 比较元素。
3) 用给定的二元谓词 p 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要检验的元素范围
count | - | 要搜索的序列长度
value | - | 要搜索的元素值
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若元素应被当做相等则返回 ​true 的二元谓词。 谓词函数的签名应等价于如下： bool pred(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 必须使得 ForwardIt 类型的对象能在解引用后隐式转换到 Type1 。类型 Type2 必须使得 T 类型的对象能隐式转换到 Type2 。 ​
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

指向范围 [first, last) 中找到的序列起始的迭代器。若找不到这种序列，则返回 last 。

若 count 为零或负，则返回 first 。

复杂度

至多应用 last - first 次谓词。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class ForwardIt, class Size, class T>
ForwardIt search_n(ForwardIt first, ForwardIt last,
                    Size count, const T& value)
{
    if (count <= 0) {
        return first;
    }

    for(; first != last; ++first) {
        if (!(*first == value)) {
            continue;
        }

        ForwardIt candidate = first;
        Size cur_count = 0;

        while (true) {
            ++cur_count;
            if (cur_count >= count) {
                // 成功
                return candidate;
            }
            ++first;
            if (first == last) {
                // 穷尽列表
                return last;
            }
            if (!(*first == value)) {
                // 栏中过少
                break;
            }
        }
    }
    return last;
}
版本二
template<class ForwardIt, class Size, class T, class BinaryPredicate>
ForwardIt search_n(ForwardIt first, ForwardIt last,
                    Size count, const T& value, BinaryPredicate p)
{
    if (count <= 0) {
        return first;
    }

    for(; first != last; ++first) {
        if (!p(*first, value)) {
            continue;
        }

        ForwardIt candidate = first;
        Size cur_count = 0;

        while (true) {
            ++cur_count;
            if (cur_count >= count) {
                // 成功
                return candidate;
            }
            ++first;
            if (first == last) {
                // 穷尽列表
                return last;
            }
            if (!p(*first, value)) {
                // 栏中过少
                break;
            }
        }
    }
    return last;
}

示例

#include <iostream>
#include <algorithm>
#include <iterator>

template <class Container, class Size, class T>
bool consecutive_values(const Container& c, Size count, const T& v)
{
  return std::search_n(std::begin(c),std::end(c),count,v) != std::end(c);
}

int main()
{
   const char sequence[] = "1001010100010101001010101";

   std::cout << std::boolalpha;
   std::cout << "Has 4 consecutive zeros: "
             << consecutive_values(sequence,4,'0') << '\n';
   std::cout << "Has 3 consecutive zeros: "
             << consecutive_values(sequence,3,'0') << '\n';
}

输出：

Has 4 consecutive zeros: false
Has 3 consecutive zeros: true

参阅

find_end | 在特定范围中寻找最后出现的元素序列 (函数模板)
findfind_iffind_if_not (C++11) | 寻找首个满足特定判别标准的元素 (函数模板)
search | 搜索一个元素范围 (函数模板)


std::set_difference

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class InputIt1, class InputIt2, class OutputIt > OutputIt set_difference( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first ); |  |  | (C++20 前)
template< class InputIt1, class InputIt2, class OutputIt > constexpr OutputIt set_difference( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class ForwardIt3 > ForwardIt3 set_difference( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, ForwardIt3 d_first ); | (2) | (C++17 起)
 | (3) |
template< class InputIt1, class InputIt2, class OutputIt, class Compare > OutputIt set_difference( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Compare comp ); |  |  | (C++20 前)
template< class InputIt1, class InputIt2, class OutputIt, class Compare > constexpr OutputIt set_difference( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Compare comp ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class ForwardIt3, class Compare > ForwardIt3 set_difference( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, ForwardIt3 d_first, Compare comp ); | (4) | (C++17 起)

复制来自已排序范围 [first1, last1) 并且不在已排序范围 [first2, last2) 中找到的元素到始于 d_first 的范围。

结果范围亦已排序。单独对待等价元素，即若某元素在 [first1, last1) 中找到 n 次而在 [first2, last2) 中找到 m 次，则准确复制它 std::max (m-n, 0) 次到 d_first 。结果范围不能与任一输入范围重叠。

1) 用 operator< 比较元素，而范围必须对于相同者排序。
3) 用给定的二元比较函数 comp 比较元素，而范围必须对于相同者排序。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first1, last1 | - | 要检验的元素范围
first2, last2 | - | 要搜索的元素范围
d_first | - | 目标范围的起始
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 InputIt1 与 InputIt2 类型的对象在解引用后能隐式转换到 Type1 与 Type2 两者。 ​
类型要求
- InputIt1, InputIt2 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1, ForwardIt2, ForwardIt3 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

构造的范围的尾后迭代器。

复杂度

至多比较 \(\scriptsize 2\cdot(N_1+N_2)-1\)2·(N
1+N
2)-1 次，其中 \(\scriptsize N_1\)N
1 与 \(\scriptsize N_2\)N
2 分别为 std::distance (first1, last1) 与 std::distance (first2, last2) 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class InputIt1, class InputIt2, class OutputIt>
OutputIt set_difference(InputIt1 first1, InputIt1 last1,
                        InputIt2 first2, InputIt2 last2,
                        OutputIt d_first)
{
    while (first1 != last1) {
        if (first2 == last2) return std::copy(first1, last1, d_first);

        if (*first1 < *first2) {
            *d_first++ = *first1++;
        } else {
            if (! (*first2 < *first1)) {
                ++first1;
            }
            ++first2;
        }
    }
    return d_first;
}
版本二
template<class InputIt1, class InputIt2,
         class OutputIt, class Compare>
OutputIt set_difference( InputIt1 first1, InputIt1 last1,
                         InputIt2 first2, InputIt2 last2,
                         OutputIt d_first, Compare comp)
{
    while (first1 != last1) {
        if (first2 == last2) return std::copy(first1, last1, d_first);

        if (comp(*first1, *first2)) {
            *d_first++ = *first1++;
        } else {
            if (!comp(*first2, *first1)) {
                ++first1;
            }
            ++first2;
        }
    }
    return d_first;
}

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

auto print = [](const auto& v, const char* end = "") {
    std::cout << "{ ";
    for (auto i : v) std::cout << i << ' ';
    std::cout << "} " << end;
};

struct Order // 拥有某些有趣数据的类
{
    int order_id;
};

std::ostream& operator<<(std::ostream& os, const Order& ord)
{
    return os << "order=" << ord.order_id << ',';
}

int main() {
    const std::vector<int> v1 {1, 2, 5, 5, 5, 9};
    const std::vector<int> v2 {2, 5, 7};
    std::vector<int> diff;

    std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(),
                        std::inserter(diff, diff.begin()));
    print(v1, "∖ ");
    print(v2, "= ");
    print(diff, "\n");

    // 我们想知道哪些顺序在旧和新状态之间“改变了”：
    std::vector<Order> old_orders { {1}, {2}, {5}, {9} };
    std::vector<Order> new_orders { {2}, {5}, {7} };
    std::vector<Order> changed_orders;

    std::set_difference(old_orders.begin(), old_orders.end(),
                        new_orders.begin(), new_orders.end(),
                        std::back_inserter(changed_orders),
                        [](auto& a, auto& b) { return a.order_id < b.order_id; });

    std::cout << "old orders = "; print(old_orders, "\n");
    std::cout << "new orders = "; print(new_orders, "\n");
    std::cout << "changed    = "; print(changed_orders, "\n");
}

输出：

{ 1 2 5 5 5 9 } ∖ { 2 5 7 } = { 1 5 5 9 }
old orders = { order=1, order=2, order=5, order=9, }
new orders = { order=2, order=5, order=7, }
changed    = { order=1, order=9, }

参阅

includes | 若一个序列是另一个的子列则返回 true (函数模板)
set_symmetric_difference | 计算两个集合的对称差 (函数模板)
ranges::set_difference (C++20) | 计算两个集合的差集 (niebloid)


std::set_intersection

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class InputIt1, class InputIt2, class OutputIt > OutputIt set_intersection( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first ); |  |  | (C++20 前)
template< class InputIt1, class InputIt2, class OutputIt > constexpr OutputIt set_intersection( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class ForwardIt3 > ForwardIt3 set_intersection( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, ForwardIt3 d_first ); | (2) | (C++17 起)
 | (3) |
template< class InputIt1, class InputIt2, class OutputIt, class Compare > OutputIt set_intersection( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Compare comp ); |  |  | (C++20 前)
template< class InputIt1, class InputIt2, class OutputIt, class Compare > constexpr OutputIt set_intersection( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Compare comp ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class ForwardIt3, class Compare > ForwardIt3 set_intersection( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, ForwardIt3 d_first, Compare comp ); | (4) | (C++17 起)

构造始于 d_first ，由在两个已排序范围 [first1, last1) 与 [first2, last2) 中都找到的元素构成的已排序范围。若某元素在 [first1, last1) 中找到 m 而在 [first2, last2) 中找到 n 次，则从第一范围复制首 std::min (m, n) 个元素到目标范围。保持等价元素的顺序。结果范围不能与任一输入范围重叠。

@1用 operator< 比较元素，而范围必须相对同一标准已排序。

3) 用给定的二元比较函数 comp 比较元素，而范围必须相对同一标准已排序。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first1, last1 | - | 要检验的第一元素范围
first2, last2 | - | 要检验的第二元素范围
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 InputIt1 与 InputIt2 类型的对象在解引用后能隐式转换到 Type1 与 Type2 两者。 ​
类型要求
- InputIt1, InputIt2 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1, ForwardIt2, ForwardIt3 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

构造范围的尾后迭代器。

复杂度

至多比较 \(\scriptsize 2\cdot(N_1+N_2)-1\)2·(N
1+N
2)-1 次，其中 \(\scriptsize N_1\)N
1 与 \(\scriptsize N_2\)N
2 分别为 std::distance (first1, last1) 与 std::distance (first2, last2) 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class InputIt1, class InputIt2, class OutputIt>
OutputIt set_intersection(InputIt1 first1, InputIt1 last1,
                          InputIt2 first2, InputIt2 last2,
                          OutputIt d_first)
{
    while (first1 != last1 && first2 != last2) {
        if (*first1 < *first2) {
            ++first1;
        } else  {
            if (!(*first2 < *first1)) {
                *d_first++ = *first1++;
            }
            ++first2;
        }
    }
    return d_first;
}
版本二
template<class InputIt1, class InputIt2,
         class OutputIt, class Compare>
OutputIt set_intersection(InputIt1 first1, InputIt1 last1,
                          InputIt2 first2, InputIt2 last2,
                          OutputIt d_first, Compare comp)
{
    while (first1 != last1 && first2 != last2) {
        if (comp(*first1, *first2)) {
            ++first1;
        } else {
            if (!comp(*first2, *first1)) {
                *d_first++ = *first1++;
            }
            ++first2;
        }
    }
    return d_first;
}

示例

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
    std::vector<int> v1{1,2,3,4,5,6,7,8};
    std::vector<int> v2{        5,  7,  9,10};
    std::sort(v1.begin(), v1.end());
    std::sort(v2.begin(), v2.end());

    std::vector<int> v_intersection;

    std::set_intersection(v1.begin(), v1.end(),
                          v2.begin(), v2.end(),
                          std::back_inserter(v_intersection));
    for(int n : v_intersection)
        std::cout << n << ' ';
}

输出：

5 7

参阅

set_union | 计算两个集合的并集 (函数模板)
ranges::set_intersection (C++20) | 计算两个集合的交集 (niebloid)


std::set_symmetric_difference

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class InputIt1, class InputIt2, class OutputIt > OutputIt set_symmetric_difference( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first ); |  |  | (C++20 前)
template< class InputIt1, class InputIt2, class OutputIt > constexpr OutputIt set_symmetric_difference( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class ForwardIt3 > ForwardIt3 set_symmetric_difference( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, ForwardIt3 d_first ); | (2) | (C++17 起)
 | (3) |
template< class InputIt1, class InputIt2, class OutputIt, class Compare > OutputIt set_symmetric_difference( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Compare comp ); |  |  | (C++20 前)
template< class InputIt1, class InputIt2, class OutputIt, class Compare > constexpr OutputIt set_symmetric_difference( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Compare comp ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class ForwardIt3, class Compare > ForwardIt3 set_symmetric_difference( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, ForwardIt3 d_first, Compare comp ); | (2) | (C++17 起)

计算二个已排序范围的对称差：复制在任一范围中，但不在两个范围中找到的元素，到始于 d_first 的范围。结果范围亦为已排序。

若某元素在 [first1, last1) 中找到 m 次而在 [first2, last2) 中找到 n 次，则将准确复制它 std::abs(m-n) 次到 d_first 。若 m>n ，则从 [first1,last1) 复制末尾的 m-n 个元素，否则从 [first2,last2) 复制末尾的 n-m 个元素。结果范围不能与任一输入范围重叠。

1) 用 operator< 比较元素，而范围必须相对于相同标准已排序。
3) 用给定的二元比较函数 comp 比较元素，而范围必须相对相同标准已排序。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first1, last1 | - | 第一个输入的已排序范围
first2, last2 | - | 第二个输入的已排序范围
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 InputIt1 与 InputIt2 类型的对象在解引用后能隐式转换到 Type1 与 Type2 两者。 ​
类型要求
- InputIt1, InputIt2 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1, ForwardIt2, ForwardIt3 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

构造范围的尾后迭代器。

复杂度

至多比较和应用每个投影 \(\scriptsize 2\cdot(N_1+N_2)-1\)2·(N
1+N
2)-1 次，其中 \(\scriptsize N_1\)N
1 与 \(\scriptsize N_2\)N
2 分别为 std::distance (first1, last1) 与 std::distance (first2, last2) 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class InputIt1, class InputIt2, class OutputIt>
OutputIt set_symmetric_difference(InputIt1 first1, InputIt1 last1,
                                  InputIt2 first2, InputIt2 last2,
                                  OutputIt d_first)
{
    while (first1 != last1) {
        if (first2 == last2) return std::copy(first1, last1, d_first);

        if (*first1 < *first2) {
            *d_first++ = *first1++;
        } else {
            if (*first2 < *first1) {
                *d_first++ = *first2;
            } else {
                ++first1;
            }
            ++first2;
        }
    }
    return std::copy(first2, last2, d_first);
}
版本二
template<class InputIt1, class InputIt2,
         class OutputIt, class Compare>
OutputIt set_symmetric_difference(InputIt1 first1, InputIt1 last1,
                                  InputIt2 first2, InputIt2 last2,
                                  OutputIt d_first, Compare comp)
{
    while (first1 != last1) {
        if (first2 == last2) return std::copy(first1, last1, d_first);

        if (comp(*first1, *first2)) {
            *d_first++ = *first1++;
        } else {
            if (comp(*first2, *first1)) {
                *d_first++ = *first2;
            } else {
                ++first1;
            }
            ++first2;
        }
    }
    return std::copy(first2, last2, d_first);
}

示例

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
    std::vector<int> v1{1,2,3,4,5,6,7,8     };
    std::vector<int> v2{        5,  7,  9,10};
    std::sort(v1.begin(), v1.end());
    std::sort(v2.begin(), v2.end());

    std::vector<int> v_symDifference;

    std::set_symmetric_difference(
        v1.begin(), v1.end(),
        v2.begin(), v2.end(),
        std::back_inserter(v_symDifference));

    for(int n : v_symDifference)
        std::cout << n << ' ';
}

输出：

1 2 3 4 6 8 9 10

参阅

includes | 若一个序列是另一个的子列则返回 true (函数模板)
set_difference | 计算两个集合的差集 (函数模板)
set_union | 计算两个集合的并集 (函数模板)
set_intersection | 计算两个集合的交集 (函数模板)
ranges::set_symmetric_difference (C++20) | 计算两个集合的对称差 (niebloid)


std::set_union

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class InputIt1, class InputIt2, class OutputIt > OutputIt set_union( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first ); |  |  | (C++20 前)
template< class InputIt1, class InputIt2, class OutputIt > constexpr OutputIt set_union( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class ForwardIt3 > ForwardIt3 set_union( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, ForwardIt3 d_first ); | (2) | (C++17 起)
 | (3) |
template< class InputIt1, class InputIt2, class OutputIt, class Compare > OutputIt set_union( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Compare comp ); |  |  | (C++20 前)
template< class InputIt1, class InputIt2, class OutputIt, class Compare > constexpr OutputIt set_union( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt d_first, Compare comp ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class ForwardIt3, class Compare > ForwardIt3 set_union( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, ForwardIt3 d_first, Compare comp ); | (4) | (C++17 起)

构造始于 d_first ，由存在于一或两个已排序范围 [first1, last1) 和 [first2, last2) 中的所有元素构成的已排序范围。

若某元素在 [first1, last1) 中找到 m 次并在 [first2, last2) 中找到 n 次，则将从 [first1, last1) 保持顺序复制全部 m 个元素到 d_first ，并从 [first2, last2) 保持顺序复制 std::max (n-m, 0) 个元素到 d_first 。

结果范围不能与任一输入范围重叠。

1) 用 operator< 比较元素，而范围必须相对于相同标准已排序。
3) 用给定的二元比较函数 comp 比较元素，而范围必须相对相同标准已排序。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first1, last1 | - | 第一个输入的已排序范围
first2, last2 | - | 第二个输入的已排序范围
d_first | - | 输出范围的起始
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 InputIt1 与 InputIt2 类型的对象在解引用后能隐式转换到 Type1 与 Type2 两者。 ​
类型要求
- InputIt1, InputIt2 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt1, ForwardIt2, ForwardIt3 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。

返回值

构造范围的尾后迭代器。

复杂度

至多比较 \(\scriptsize 2\cdot(N_1+N_2)-1\)2·(N
1+N
2)-1 次，其中 \(\scriptsize N_1\)N
1 与 \(\scriptsize N_2\)N
2 分别为 std::distance (first1, last1) 与 std::distance (first2, last2) 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

此算法进行的任务与 std::merge 所为相似。两个算法都消耗二个输入范围，并以来自两个输入的元素产生一个已排序输出。此二个算法间的区别在于处理来自两个输入范围的比较等价的值（见可小于比较 (LessThanComparable) 的注意）。若任何等价的值第一范围中出现 n 次，在第二范围中出现 m 次，则 std::merge 会生成全部 n+m 次出现，而 std::set_union 会仅输出 std::max (n, m) 次。故 std::merge 准确输入 std::distance (first1, last1) + std::distance (first2, last2) 个值，而 std::set_union 可能产生较少的值。

可能的实现

版本一
template<class InputIt1, class InputIt2, class OutputIt>
OutputIt set_union(InputIt1 first1, InputIt1 last1,
                   InputIt2 first2, InputIt2 last2,
                   OutputIt d_first)
{
    for (; first1 != last1; ++d_first) {
        if (first2 == last2)
            return std::copy(first1, last1, d_first);
        if (*first2 < *first1) {
            *d_first = *first2++;
        } else {
            *d_first = *first1;
            if (!(*first1 < *first2))
                ++first2;
            ++first1;
        }
    }
    return std::copy(first2, last2, d_first);
}
版本二
template<class InputIt1, class InputIt2,
         class OutputIt, class Compare>
OutputIt set_union(InputIt1 first1, InputIt1 last1,
                   InputIt2 first2, InputIt2 last2,
                   OutputIt d_first, Compare comp)
{
    for (; first1 != last1; ++d_first) {
        if (first2 == last2)
            return std::copy(first1, last1, d_first);
        if (comp(*first2, *first1)) {
            *d_first = *first2++;
        } else {
            *d_first = *first1;
            if (!comp(*first1, *first2))
                ++first2;
            ++first1;
        }
    }
    return std::copy(first2, last2, d_first);
}

示例

带 vector 的示例：

#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>

int main()
{
    {
        std::vector<int> v1 = {1, 2, 3, 4, 5};
        std::vector<int> v2 = {      3, 4, 5, 6, 7};
        std::vector<int> dest1;

        std::set_union(v1.begin(), v1.end(),
                       v2.begin(), v2.end(),
                       std::back_inserter(dest1));

        for (const auto &i : dest1) {
            std::cout << i << ' ';
        }
        std::cout << '\n';
    }
    {
        std::vector<int> v1 = {1, 2, 3, 4, 5, 5, 5};
        std::vector<int> v2 = {      3, 4, 5, 6, 7};
        std::vector<int> dest1;

        std::set_union(v1.begin(), v1.end(),
                       v2.begin(), v2.end(),
                       std::back_inserter(dest1));

        for (const auto &i : dest1) {
            std::cout << i << ' ';
        }
        std::cout << '\n';
    }
}

输出：

1 2 3 4 5 6 7
1 2 3 4 5 5 5 6 7

参阅

includes | 若一个序列是另一个的子列则返回 true (函数模板)
merge | 归并两个已排序的范围 (函数模板)
set_difference | 计算两个集合的差集 (函数模板)
set_intersection | 计算两个集合的交集 (函数模板)
set_symmetric_difference | 计算两个集合的对称差 (函数模板)
ranges::set_union (C++20) | 计算两个集合的并集 (niebloid)


std::shift_left, std::shift_right

< cpp‎ | algorithm
定义于头文件 <algorithm>
template< class ForwardIt >

constexpr ForwardIt shift_left( ForwardIt first, ForwardIt last,

typename std::iterator_traits <ForwardIt>::difference_type n );
 (1) (C++20 起)
template< class ExecutionPolicy, class ForwardIt >

ForwardIt shift_left( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,

typename std::iterator_traits <ForwardIt>::difference_type n );
 (2) (C++20 起)
template< class ForwardIt >

constexpr ForwardIt shift_right( ForwardIt first, ForwardIt last,

typename std::iterator_traits <ForwardIt>::difference_type n );
 (3) (C++20 起)
template< class ExecutionPolicy, class ForwardIt >

ForwardIt shift_right( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,

typename std::iterator_traits <ForwardIt>::difference_type n );
 (4) (C++20 起)

将范围 [first, last) 中的元素迁移 n 个位置。

1) 向范围开端迁移元素。若 n <= 0 || n >= last - first 则无效果。若 n < 0 则行为未定义。否则，对于每个 [0, last - first - n) 中的整数 i ，移动原于位置 first + n + i 的元素到位置 first + i 。以 i 从 ​0​ 开始递增的顺序进行移动。
3) 向范围结尾迁移元素。若 n <= 0 || n >= last - first 则无效果。若 n < 0 则行为未定义。否则对于每个 [0, last - first - n) 中的整数 i ，移动原于位置 first + i 的元素到位置 first + n + i 。若 ForwardIt 满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求，则以 i 从 last - first - n - 1 开始递减的顺序进行移动。
2,4) 分别同 (1) 与 (3) ，但按照 policy 执行并可能以任何顺序进行移动。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> 为 true 才参与重载决议。

在原范围但不在新范围中的元素被置于合法但未指定的状态。

参数

first | - | 原范围的开端
last | - | 原范围的结尾
n | - | 要迁移的位置数
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 对于重载 (3-4) ForwardIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求或值可交换 (ValueSwappable) 的要求。
- 解引用 ForwardIt 结果的类型必须满足可移动赋值 (MoveAssignable) 的要求。

返回值

1-2) 结果范围的结尾。若 n 小于 last - first ，则返回 first + (last - first - n) 。否则返回 first 。
3-4) 结果范围的开始。若 n 小于 last - first ，则返回 first + n 。否则返回 last 。

复杂度

1-2) 至多 std::distance (first, last) - n 次赋值。
3-4) 至多 std::distance (first, last) - n 次赋值或交换。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

示例

#include <iostream>
#include <algorithm>
#include <vector>

struct S {
    int value{0};
    bool specified_state{true};

    S(int v = 0) : value{v} {}
    S(S const& rhs) = default;
    S(S&& rhs) { *this = std::move(rhs); }
    S& operator=(S const& rhs) = default;
    S& operator=(S&& rhs) {
        if (this != &rhs) {
            value = rhs.value;
            specified_state = rhs.specified_state;
            rhs.specified_state = false;
        }
        return *this;
    }
};

std::ostream& operator<< (std::ostream& os, std::vector<S> const& v) {
    for (const auto& s : v)
        s.specified_state ? os << s.value << ' ' : os << "? ";
    return os << '\n';
}

int main()
{
    std::vector<S> v{1,2,3,4,5,6,7};

    std::shift_left(v.begin(), v.end(), 8);  // 无效果： n >= last - first
    std::cout << v;
//  std::shift_left(v.begin(), v.end(), -3); // UB ：例如分段错误。
    std::shift_left(v.begin(), v.end(), +3); // OK
    std::cout << v;

    std::shift_right(v.begin(), v.end(), 2); // OK
    std::cout << v;
}

输出：

1 2 3 4 5 6 7
4 5 6 7 ? ? ?
? ? 4 5 6 7 ?

参阅

move (C++11) | 将某一范围的元素移动到一个新的位置 (函数模板)
move_backward (C++11) | 按从后往前的顺序移动某一范围的元素到新的位置 (函数模板)
rotate | 旋转范围中的元素顺序 (函数模板)


std::sort

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
 | (1) |
template< class RandomIt > void sort( RandomIt first, RandomIt last ); |  |  | (C++20 前)
template< class RandomIt > constexpr void sort( RandomIt first, RandomIt last ); |  |  | (C++20 起)
template< class ExecutionPolicy, class RandomIt > void sort( ExecutionPolicy&& policy, RandomIt first, RandomIt last ); | (2) | (C++17 起)
 | (3) |
template< class RandomIt, class Compare > void sort( RandomIt first, RandomIt last, Compare comp ); |  |  | (C++20 前)
template< class RandomIt, class Compare > constexpr void sort( RandomIt first, RandomIt last, Compare comp ); |  |  | (C++20 起)
template< class ExecutionPolicy, class RandomIt, class Compare > void sort( ExecutionPolicy&& policy, RandomIt first, RandomIt last, Compare comp ); | (4) | (C++17 起)

以不降序排序范围 [first, last) 中的元素。不保证维持相等元素的顺序。

若对于任何指向序列的迭代器 it 与任何使得 it + n 为指向序列元素的合法迭代器的非负整数 n ， comp(*(it + n), *it) 求值为 false ，则称序列相对于 comp 已排序。

1) 用 operator< 比较元素。
3) 用给定的二元比较函数 comp 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要排序的元素范围
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 RandomIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- RandomIt 必须满足值可交换 (ValueSwappable) 和 老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。
- 解引用 RandomIt 结果的类型必须满足可移动赋值 (MoveAssignable) 和可移动构造 (MoveConstructible) 的要求。
- Compare 必须满足比较 (Compare) 的要求。

返回值

（无）

复杂度

平均 O(N·log(N)) 次比较，其中 N = std::distance (first, last) 。 | (C++11 前)
O(N·log(N)) 次比较，其中 N = std::distance (first, last) 。 | (C++11 起)

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

参阅 libstdc++ 与 libc++ 中的实现。

示例

#include <algorithm>
#include <functional>
#include <array>
#include <iostream>

int main()
{
    std::array<int, 10> s = {5, 7, 4, 2, 8, 6, 1, 9, 0, 3};

    // 用默认的 operator< 排序
    std::sort(s.begin(), s.end());
    for (auto a : s) {
        std::cout << a << " ";
    }
    std::cout << '\n';

    // 用标准库比较函数对象排序
    std::sort(s.begin(), s.end(), std::greater<int>());
    for (auto a : s) {
        std::cout << a << " ";
    }
    std::cout << '\n';

    // 用自定义函数对象排序
    struct {
        bool operator()(int a, int b) const
        {
            return a < b;
        }
    } customLess;
    std::sort(s.begin(), s.end(), customLess);
    for (auto a : s) {
        std::cout << a << " ";
    }
    std::cout << '\n';

    // 用 lambda 表达式排序
    std::sort(s.begin(), s.end(), [](int a, int b) {
        return b < a;
    });
    for (auto a : s) {
        std::cout << a << " ";
    }
    std::cout << '\n';
}

输出：

0 1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1 0

参阅

partial_sort | 排序一个范围的前 N 个元素 (函数模板)
stable_sort | 将范围内的元素排序，同时保持相等的元素之间的顺序 (函数模板)
ranges::sort (C++20) | 将范围按升序排序 (niebloid)


std::sort_heap

< cpp‎ | algorithm
定义于头文件 <algorithm> |
 | (1)
template< class RandomIt > void sort_heap( RandomIt first, RandomIt last ); |  | (C++20 前)
template< class RandomIt > constexpr void sort_heap( RandomIt first, RandomIt last ); |  | (C++20 起)
 | (2)
template< class RandomIt, class Compare > void sort_heap( RandomIt first, RandomIt last, Compare comp ); |  | (C++20 前)
template< class RandomIt, class Compare > constexpr void sort_heap( RandomIt first, RandomIt last, Compare comp ); |  | (C++20 起)

转换最大堆 [first, last) 为以升序排序的范围。产生的范围不再拥有堆属性。

函数的第一版本用 operator< 比较元素，第二版本用给定的比较函数 comp 比较。

参数

first, last | - | 要排序的元素范围
comp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若首个参数小于第二个，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 RandomIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- RandomIt 必须满足值可交换 (ValueSwappable) 和 老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。
- 解引用 RandomIt 结果的类型必须满足可移动赋值 (MoveAssignable) 和可移动构造 (MoveConstructible) 的要求。

返回值

（无）

返回值

至多 2×N×log(N) 次比较，其中 N= std::distance (first, last) 。

注意

最大堆是拥有下列属性的元素范围 [f,l) ：

  • 设 N = l - f ，对于所有 0 < i < N ， f[floor(
    i-1
    2
    )] 不小于 f[i] 。
  • 可用 std::push_heap () 添加新元素。
  • 可用 std::pop_heap () 移除首元素。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2444 | C++98 | 复杂度要求在因子 2 上曾有错误 | 已更正

可能的实现

版本一
template< class RandomIt >
void sort_heap( RandomIt first, RandomIt last )
{
    while (first != last)
        std::pop_heap(first, last--);
}
版本二
template< class RandomIt, class Compare >
void sort_heap( RandomIt first, RandomIt last, Compare comp )
{
    while (first != last)
        std::pop_heap(first, last--, comp);
}

示例

#include <algorithm>
#include <vector>
#include <iostream>

int main()
{
    std::vector<int> v = {3, 1, 4, 1, 5, 9};

    std::make_heap(v.begin(), v.end());

    std::cout << "heap:\t";
    for (const auto &i : v) {
        std::cout << i << ' ';
    }

    std::sort_heap(v.begin(), v.end());

    std::cout << "\nsorted:\t";
    for (const auto &i : v) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
}

输出：

heap:   9 4 5 1 1 3
sorted: 1 1 3 4 5 9

参阅

make_heap
 从一个元素范围创建出一个最大堆
(函数模板)


std::stable_partition

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
template< class BidirIt, class UnaryPredicate > BidirIt stable_partition( BidirIt first, BidirIt last, UnaryPredicate p ); | (1) |
template< class ExecutionPolicy, class BidirIt, class UnaryPredicate > BidirIt stable_partition( ExecutionPolicy&& policy, BidirIt first, BidirIt last, UnaryPredicate p ); | (2) | (C++17 起)
1) 重排序范围 [first, last) 中的元素，使得所有谓词 p 对其返回 true 的元素先于谓词 p 对其返回 false 的元素。保持元素的相对顺序。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要重排序的元素范围
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若元素应先序于其他元素则返回 ​true 的一元谓词。 对每个（可为 const 的） VT 类型参数 v ，其中 VT 是 BidirIt 的值类型，表达式 p(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 VT& 类型参数，亦不允许 VT ，除非对 VT 而言移动等价于复制 (C++11 起)。 ​
类型要求
- BidirIt 必须满足值可交换 (ValueSwappable) 和 老式双向迭代器 (LegacyBidirectionalIterator) 的要求。
- 解引用 BidirIt 结果的类型必须满足可移动赋值 (MoveAssignable) 和可移动构造 (MoveConstructible) 的要求。
- UnaryPredicate 必须满足谓词 (Predicate) 的要求。

返回值

指向第二范围首元素的迭代器

复杂度

给定 N = std::distance (first, last) ，

1) 若有充足内存，则准确应用 N 次谓词及交换 O(N) 次。若内存不充足，则至多交换 N log N 次。
2) O(N log N) 次交换及应用 O(N) 次谓词。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

此函数试图分配临时缓冲区。若分配失败，则选择较低效的算法。

libc++ 与 libstdc++ 中的实现亦作为扩展接受老式向前迭代器 (LegacyForwardIterator) 所代表的范围。

示例

#include <iostream>
#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> v{0, 0, 3, 0, 2, 4, 5, 0, 7};
    std::stable_partition(v.begin(), v.end(), [](int n){return n>0;});
    for (int n : v) {
        std::cout << n << ' ';
    }
    std::cout << '\n';
}

输出：

3 2 4 5 7 0 0 0 0

参阅

partition
 将范围中的元素分为两组
(函数模板)


std::stable_sort

< cpp‎ | algorithm
定义于头文件 <algorithm> |  |
template< class RandomIt > void stable_sort( RandomIt first, RandomIt last ); | (1) |
template< class ExecutionPolicy, class RandomIt > void stable_sort( ExecutionPolicy&& policy, RandomIt first, RandomIt last ); | (2) | (C++17 起)
template< class RandomIt, class Compare > void stable_sort( RandomIt first, RandomIt last, Compare comp ); | (3) |
template< class ExecutionPolicy, class RandomIt, class Compare > void stable_sort( ExecutionPolicy&& policy, RandomIt first, RandomIt last, Compare comp ); | (4) | (C++17 起)

以不降序排序范围 [first, last) 中的元素。保证保持等价元素的顺序。

若对于任何指向序列的迭代器 it 与任何使得 it + n 为指向序列元素的合法迭代器的非负整数 n ， comp(*(it + n), *it) 求值为 false ，则称序列相对于 comp 已排序。

1) 用 operator< 比较元素。
3) 用给定的比较函数 comp 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要排序的元素范围
policy | - | 所用的执行策略。细节见执行策略。
comp | - | 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 RandomIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- RandomIt 必须满足值可交换 (ValueSwappable) 和 老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。
- 解引用 RandomIt 结果的类型必须满足可移动赋值 (MoveAssignable) 和可移动构造 (MoveConstructible) 的要求。

返回值

（无）

复杂度

应用 cmp O(N·log(N)2) 次，其中 N = std::distance (first, last) 。若额外内存可用，则复杂度为 O(N·log(N)) 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

此函数试图分配等于待排序序列长度的临时缓冲区。若分配失败，则选择较低效的算法。

可能的实现

参阅 libstdc++ 与 libc++ 中的实现。

示例

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

struct Employee {
    int age;
    std::string name;  // 不参与比较
};

bool operator<(const Employee &lhs, const Employee &rhs) {
    return lhs.age < rhs.age;
}

int main()
{
    std::vector<Employee> v =
    {
        {108, "Zaphod"},
        {32, "Arthur"},
        {108, "Ford"},
    };

    std::stable_sort(v.begin(), v.end());

    for (const auto &e : v)
        std::cout << e.age << ", " << e.name << '\n';
}

输出：

32, Arthur
108, Zaphod
108, Ford

参阅

partial_sort | 排序一个范围的前 N 个元素 (函数模板)
sort | 将范围按升序排序 (函数模板)


std::swap

< cpp‎ | algorithm
定义于头文件 <algorithm>
(C++11 前)
定义于头文件 <utility>
(C++11 起)
定义于头文件 <string_view>
(C++17 起)
(1)
template< class T >
void swap( T& a, T& b );
 (C++11 前)
template< class T >
void swap( T& a, T& b ) noexcept(/* see below */);
 (C++11 起)
(C++20 前)
template< class T >
constexpr void swap( T& a, T& b ) noexcept(/* see below */);
 (C++20 起)
(2)
template< class T2, std::size_t N >
void swap( T2 (&a)[N], T2 (&b)[N]) noexcept(/* see below */);
 (C++11 起)
(C++20 前)
template< class T2, std::size_t N >
constexpr void swap( T2 (&a)[N], T2 (&b)[N]) noexcept(/* see below */);
 (C++20 起)

交换给定值

1) 交换 a 与 b 。此重载仅若 std::is_move_constructible_v <T> && std::is_move_assignable_v <T> 为 true 才参与重载决议。 (C++17 起)
2) 交换 a 与 b 数组。等效于调用 std::swap_ranges (a, a+N, b) 。此重载仅若 std::is_swappable_v <T2> 为 true 才参与重载决议。 (C++17 起)

参数

a, b - 要交换的值
类型要求
-
T 必须满足可移动赋值 (MoveAssignable) 和 可移动构造 (MoveConstructible) 的要求。
-
T2 必须满足可交换 (Swappable) 的要求。

返回值

（无）

异常

1)
（无） | (C++11 前)
noexcept 说明： noexcept( std::is_nothrow_move_constructible <T>::value && std::is_nothrow_move_assignable <T>::value ) | (C++11 起)
2)
noexcept 说明： noexcept(noexcept(swap(*a, *b))) 异常规定中标识符 swap 的查找在通常查找规则的所找到的任何内容外，还会找到此函数模板，这使得异常规定等价于 C++17 std::is_nothrow_swappable 。 | (C++11 起) (C++17 前)
noexcept 说明： noexcept( std::is_nothrow_swappable_v <T2>) | (C++17 起)

复杂度

1) 常量
2) 与 N 成线性

特化

std::swap 可以对程序定义类型在命名空间 std 中特化，但 ADL 不会寻找这些特化（命名空间 std 不是与程序定义类型关联的空间）。

 (C++20 前)

令程序定义类型可交换的期待方式是在与该类型相同的命名空间中提供非成员函数 swap ：细节见可交换 (Swappable) 。

标准库已提供下列重载：

std::swap(std::pair) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::tuple) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::shared_ptr) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::weak_ptr) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::unique_ptr) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::function) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::basic_string) | 特化 std::swap 算法 (函数模板)
std::swap(std::array) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::deque) | 特化 std::swap 算法 (函数模板)
std::swap(std::forward_list) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::list) | 特化 std::swap 算法 (函数模板)
std::swap(std::vector) | 特化 std::swap 算法 (函数模板)
std::swap(std::map) | 特化 std::swap 算法 (函数模板)
std::swap(std::multimap) | 特化 std::swap 算法 (函数模板)
std::swap(std::set) | 特化 std::swap 算法 (函数模板)
std::swap(std::multiset) | 特化 std::swap 算法 (函数模板)
std::swap(std::unordered_map) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::unordered_multimap) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::unordered_set) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::unordered_multiset) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::queue) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::priority_queue) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::stack) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::valarray) (C++11) | 特化 std::swap() 算法 (函数模板)
std::swap(std::basic_stringbuf) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::basic_istringstream) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::basic_ostringstream) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::basic_stringstream) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::basic_filebuf) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::basic_ifstream) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::basic_ofstream) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::basic_fstream) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::basic_syncbuf) (C++20) | 特化 std::swap 算法 (函数模板)
std::swap(std::basic_regex) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::match_results) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::thread) (C++11) | 特化 std::swap 算法 (函数)
std::swap(std::unique_lock) (C++11) | std::swap 对 unique_lock 的特化 (函数模板)
std::swap(std::promise) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::packaged_task) (C++11) | 特化 std::swap 算法 (函数模板)
std::swap(std::optional) (C++17) | 特化 std::swap 算法 (函数模板)
std::swap(std::any) (C++17) | 特化 std::swap 算法 (函数)
std::swap(std::variant) (C++17) | 特化 std::swap 算法 (函数模板)
std::swap(std::filesystem::path) | 交换二个路径 (函数)

示例

#include <algorithm>
#include <iostream>

int main()
{
   int a = 5, b = 3;

   // 前
   std::cout << a << ' ' << b << '\n';

   std::swap(a,b);

   // 后
   std::cout << a << ' ' << b << '\n';
}

输出：

5 3
3 5

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2554 | C++11 | 因为名称查找问题，交换多维数组无法为 noexcept | 使之可能

参阅

iter_swap | 交换两个迭代器所指向的元素 (函数模板)
swap_ranges | 交换两个范围的元素 (函数模板)
exchange (C++14) | 将实参替换为一个新值，并返回其先前值 (函数模板)


std::swap_ranges

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class ForwardIt1, class ForwardIt2 >

ForwardIt2 swap_ranges( ForwardIt1 first1, ForwardIt1 last1,

ForwardIt2 first2 );
 (C++20 前)
template< class ForwardIt1, class ForwardIt2 >

constexpr ForwardIt2 swap_ranges( ForwardIt1 first1, ForwardIt1 last1,

ForwardIt2 first2 );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >

ForwardIt2 swap_ranges( ExecutionPolicy&& policy,

ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2 );
 (2) (C++17 起)
1) 在范围 [first1, last1) 和始于 first2 的另一范围间交换元素。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。。

参数

first1, last1 | - | 要交换的第一个元素范围
first2 | - | 要交换的第二个元素范围的起始
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- ForwardIt1 与 ForwardIt2 解引用的类型必须满足可交换 (Swappable) 的要求

返回值

指向始于 first2 的范围中被交换的最末元素后一元素的迭代器。

复杂度

与 first1 和 last1 的距离成线性

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

实现（例如 MSVC STL ）可能在迭代器类型满足老式连续迭代器 (LegacyContiguousIterator) ，并且交换其值类型不调用非平凡的特殊成员函数或 ADL 所找到的 swap 时启用向量化。

可能的实现

template<class ForwardIt1, class ForwardIt2>
ForwardIt2 swap_ranges(ForwardIt1 first1,
                             ForwardIt1 last1,
                             ForwardIt2 first2)
{
    while (first1 != last1) {
        std::iter_swap(first1++, first2++);
    }
    return first2;
}

示例

演示来自不同容器的子范围交换

#include <algorithm>
#include <list>
#include <vector>
#include <iostream>
int main()
{
    std::vector<int> v = {1, 2, 3, 4, 5};
    std::list<int> l = {-1, -2, -3, -4, -5};

    std::swap_ranges(v.begin(), v.begin()+3, l.begin());

    for(int n : v)
       std::cout << n << ' ';
    std::cout << '\n';
    for(int n : l)
       std::cout << n << ' ';
    std::cout << '\n';
}

输出：

-1 -2 -3 4 5
1 2 3 -4 -5

参阅

iter_swap | 交换两个迭代器所指向的元素 (函数模板)
swap | 交换两个对象的值 (函数模板)
ranges::swap_ranges (C++20) | 交换两个范围的元素 (niebloid)


std::transform

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class InputIt, class OutputIt, class UnaryOperation >

OutputIt transform( InputIt first1, InputIt last1, OutputIt d_first,

UnaryOperation unary_op );
 (C++20 前)
template< class InputIt, class OutputIt, class UnaryOperation >

constexpr OutputIt transform( InputIt first1, InputIt last1, OutputIt d_first,

UnaryOperation unary_op );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class UnaryOperation >

ForwardIt2 transform( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1,

ForwardIt2 d_first, UnaryOperation unary_op );
 (2) (C++17 起)
(3)
template< class InputIt1, class InputIt2, class OutputIt, class BinaryOperation >

OutputIt transform( InputIt1 first1, InputIt1 last1, InputIt2 first2,

OutputIt d_first, BinaryOperation binary_op );
 (C++20 前)
template< class InputIt1, class InputIt2, class OutputIt, class BinaryOperation >

constexpr OutputIt transform( InputIt1 first1, InputIt1 last1, InputIt2 first2,

OutputIt d_first, BinaryOperation binary_op );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class ForwardIt3, class BinaryOperation >

ForwardIt3 transform( ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1,

ForwardIt2 first2, ForwardIt3 d_first, BinaryOperation binary_op );
 (4) (C++17 起)

std::transform 应用给定的函数到范围并存储结果于始于 d_first 的另一范围。

1) 应用一元函数 unary_op 到 [first1, last1) 所定义的范围。
3) 应用二元函数 binary_op 到来自二个范围的元素对：一个以 [first1, last1) 定义，而另一个始于 first2 。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。
unary_op 和 binary_op 必须无副作用。 | (C++11 前)
unary_op 和 binary_op 必须不非法化所涉及范围的任何迭代器，包含尾迭代器，或修改该范围的任何元素。 | (C++11 起)

参数

first1, last1 | - | 要变换的第一元素范围
first2 | - | 要变换的第二元素范围的起始
d_first | - | 目标范围的起始，可以等于 first1 或 first2
policy | - | 所用的执行策略。细节见执行策略。
unary_op | - | 将要应用的一元算符函数。 函数签名应等价于如下者： Ret fun(const Type &a); 签名不必有 const & 。 类型 Type 必须使得 InputIt 类型对象能在解引用后隐式转换到 Type 。 类型 Ret 必须使得 OutputIt 类型对象能被解引用并能被赋 Ret 类型值。 ​
binary_op | - | 被使用的二元函数对象。 该函数的签名应当等价于： Ret fun(const Type1 &a, const Type2 &b); 签名中并不需要有 const &。 类型 Type1 与 Type2 必须使得 InputIt1 与 InputIt2 类型的对象在解引用后分别能隐式转换到 Type1 与 Type2 。 类型 Ret 必须使得 OutputIt 类型对象能被解引用并能被赋 Ret 类型值。 ​
类型要求
- InputIt, InputIt1, InputIt2 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1, ForwardIt2, ForwardIt3 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

指向最后一个变换的元素的输出迭代器。

复杂度

1-2) 准确应用 std::distance (first1, last1) 次 unary_op 。
3-4) 准确应用 std::distance (first1, last1) 次 binary_op 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

版本一
template<class InputIt, class OutputIt, class UnaryOperation>
OutputIt transform(InputIt first1, InputIt last1, OutputIt d_first,
                   UnaryOperation unary_op)
{
    while (first1 != last1) {
        *d_first++ = unary_op(*first1++);
    }
    return d_first;
}
版本二
template<class InputIt1, class InputIt2,
         class OutputIt, class BinaryOperation>
OutputIt transform(InputIt1 first1, InputIt1 last1, InputIt2 first2,
                   OutputIt d_first, BinaryOperation binary_op)
{
    while (first1 != last1) {
        *d_first++ = binary_op(*first1++, *first2++);
    }
    return d_first;
}

注解

std::transform 不保证按顺序应用 unary_op 或 binary_op 。为按顺序应用函数到数列，或应用修改序列元素的函数，应使用 std::for_each 。

示例

下列代码用 transform ，以 toupper 函数原地转换字符串为大写，然后转换每个 char 为其序数值：

#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
#include <vector>

int main()
{
    std::string s("hello");
    std::transform(s.begin(), s.end(), s.begin(),
                   [](unsigned char c) -> unsigned char { return std::toupper(c); });

    std::vector<std::size_t> ordinals;
    std::transform(s.begin(), s.end(), std::back_inserter(ordinals),
                   [](unsigned char c) -> std::size_t { return c; });

    std::cout << s << ':';
    for (auto ord : ordinals) {
       std::cout << ' ' << ord;
    }

    std::transform(ordinals.cbegin(), ordinals.cend(), ordinals.cbegin(),
                   ordinals.begin(), std::plus<>{});

    std::cout << '\n';
    for (auto ord : ordinals) {
       std::cout << ord << ' ';
    }
    std::cout << '\n';
}

输出：

HELLO: 72 69 76 76 79
144 138 152 152 158

参阅

for_each
 应用函数到范围中的元素
(函数模板)


std::transform_exclusive_scan

< cpp‎ | algorithm
定义于头文件 <numeric> |  |
 | (1) |
template< class InputIt, class OutputIt, class T, class BinaryOperation, class UnaryOperation> OutputIt transform_exclusive_scan( InputIt first, InputIt last, OutputIt d_first, T init, BinaryOperation binary_op, UnaryOperation unary_op); |  |  | (C++17 起) (C++20 前)
template< class InputIt, class OutputIt, class T, class BinaryOperation, class UnaryOperation> constexpr OutputIt transform_exclusive_scan( InputIt first, InputIt last, OutputIt d_first, T init, BinaryOperation binary_op, UnaryOperation unary_op); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T, class BinaryOperation, class UnaryOperation > ForwardIt2 transform_exclusive_scan( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last, ForwardIt2 d_first, T init, BinaryOperation binary_op, UnaryOperation unary_op ); | (2) | (C++17 起)

以 unary_op 变换范围 [first, last) 中的每个元素，然后在结果范围上用 binary_op 以 init 为初值计算排除前缀和，并写入结果到始于 d_first 的范围。“排除”表示第 i 个元素不包含于第 i 个和。

形式上，对于每个 [first, first + (i - d_first)) 中的 j ，通过 [d_first, d_first + (last - first)) 中每个 i 赋 init, unary_op(*j)... 在 binary_op 上的广义非交换和的值，

其中广义非交换和 GNSUM(op, a
1, ..., a
N) 定义如下：

  • 若 N=1 ，则为 a
    1
  • 若 N > 1 ，则为 op(GNSUM(op, a
    1    , ..., a
    K    ), GNSUM(op, a
    M    , ..., a
    N    ))     对于 1 < K+1 = M ≤ N 中的任何 K

换言之，和运算能以任意顺序进行，且若 binary_op 非结合，则行为是非确定的。

重载 (2) 按照 policy 执行，此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

unary_op 与 binary_op 不应非法化范围 [first, last) 或 [d_first, d_first + (last - first)) 中的迭代器（包含尾迭代器）或子范围，或修改其中的元素。否则行为未定义。

参数

first, last | - | 要求和的范围
d_first | - | 目标范围的起始，可以等于 first
policy | - | 所用的执行策略。细节见执行策略。
init | - | 初值
unary_op | - | 一元函数对象 (FunctionObject) ，将要被应用到输入范围中的每个元素。返回类型必须可接受为 binary_op 的输入。
binary_op | - | 二元函数对象 (FunctionObject) ，将应用于 unary_op 的结果、其他 binary_op 的结果，还有 init 。
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- T 必须满足可移动构造 (MoveConstructible) 的要求。binary_op(init, unary_op(*first)) 、 binary_op(init, init) 和 binary_op(unary_op(*first), unary_op(*first)) 都必须可转换为 T 。

返回值

指向最后写入元素后一位置元素的迭代器。

复杂度

应用 O(last - first) 次 binary_op 和 unary_op 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

不应用 unary_op 到 init 。

示例

#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>

int main()
{
  auto times_10 = [](int x) { return x * 10; };
  std::vector data {3, 1, 4, 1, 5, 9, 2, 6};

  std::cout << "10 times exclusive sum: ";
  std::transform_exclusive_scan(data.begin(), data.end(),
                                std::ostream_iterator<int>(std::cout, " "),
                                0, std::plus<int>{}, times_10);
  std::cout << "\n10 times inclusive sum: ";
  std::transform_inclusive_scan(data.begin(), data.end(),
                                std::ostream_iterator<int>(std::cout, " "),
                                std::plus<int>{}, times_10);
}

输出：

10 times exclusive sum: 0 30 40 80 90 140 230 250
10 times inclusive sum: 30 40 80 90 140 230 250 310

参阅

partial_sum | 计算范围内元素的部分和 (函数模板)
exclusive_scan (C++17) | 类似 std::partial_sum，第 i 个和中排除第 i 个输入 (函数模板)
transform_inclusive_scan (C++17) | 应用一个函数对象，然后进行包含扫描 (函数模板)


std::transform_inclusive_scan

< cpp‎ | algorithm
定义于头文件 <numeric> |  |
 | (1) |
template< class InputIt, class OutputIt, class BinaryOperation, class UnaryOperation > OutputIt transform_inclusive_scan( InputIt first, InputIt last, OutputIt d_first, BinaryOperation binary_op, UnaryOperation unary_op ); |  |  | (C++17 起) (C++20 前)
template< class InputIt, class OutputIt, class BinaryOperation, class UnaryOperation > constexpr OutputIt transform_inclusive_scan( InputIt first, InputIt last, OutputIt d_first, BinaryOperation binary_op, UnaryOperation unary_op ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class BinaryOperation, class UnaryOperation > ForwardIt2 transform_inclusive_scan( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last, ForwardIt2 d_first, BinaryOperation binary_op, UnaryOperation unary_op ); | (2) | (C++17 起)
 | (3) |
template< class InputIt, class OutputIt, class BinaryOperation, class UnaryOperation, class T > OutputIt transform_inclusive_scan( InputIt first, InputIt last, OutputIt d_first, BinaryOperation binary_op, UnaryOperation unary_op, T init ); |  |  | (C++17 起) (C++20 前)
template< class InputIt, class OutputIt, class BinaryOperation, class UnaryOperation, class T > constexpr OutputIt transform_inclusive_scan( InputIt first, InputIt last, OutputIt d_first, BinaryOperation binary_op, UnaryOperation unary_op, T init ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class BinaryOperation, class UnaryOperation, class T > ForwardIt2 transform_inclusive_scan( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last, ForwardIt2 d_first, BinaryOperation binary_op, UnaryOperation unary_op, T init ); | (4) | (C++17 起)

以 unary_op 变换范围 [first, last) 中的每个元素，然后用 binary_op 在范围上计算包含前缀和，可选地以 init 为初值，并写结果到始于 d_first 的范围。“包含”表明第 i 个元素包含于第 i 个和。

形式上，通过每个 [d_first, d_first + (last - first)) 中的迭代器 i 赋以下值

  • 对于重载 (1-2) ，对于 [first, first + (i - d_first + 1)) 中每个 j ，为 unary_op(*j)... 在 binary_op 上的的广义非交换和，
  • 对于重载 (3-4) ，对于 [first, first + (i - d_first + 1)) 中每个 j ，为 init, unary_op(*j)... 在 binary_op 上的广义非交换和，

其中广义非交换和 GNSUM(op, a
1, ..., a
N) 定义如下：

  • 若 N=1 ，则为 a
    1
  • 若 N > 1 ，则为 op(GNSUM(op, a
    1    , ..., a
    K    ), GNSUM(op, a
    M    , ..., a
    N    ))     ，对于任何 1 < K+1 = M ≤ N 的 K

换言之，能以任意顺序进行和运算，而若 binary_op 非结合则行为为非确定的。

重载 (2, 4) 按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

unary_op 与 binary_op 不应非法化范围 [first, last) 或 [d_first, d_first + (last - first)) 中的迭代器（含尾迭代器）或子范围，不修改其中的元素。否则行为未定义。

参数

first, last | - | 求和的元素范围
d_first | - | 目标范围起始；可以等于 first
policy | - | 所用的执行策略。细节见执行策略。
init | - | 初值
unary_op | - | 一元函数对象 (FunctionObject) ，将要被应用到输入范围中的每个元素。返回类型必须可接受为 binary_op 的输入。
binary_op | - | 二元函数对象 (FunctionObject) ，将应用于 unary_op 的结果、其他 binary_op 的结果，还有 init ，若提供它。
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 若不提供 init ，则 decltype(first) 的值类型必须为可移动构造 (MoveConstructible) 而 binary_op(unary_op(*first), unary_op(*first)) 必须可转换成 decltype(first) 的值类型
- T （若提供 init ） 必须满足可移动构造 (MoveConstructible) 的要求。binary_op(init, unary_op(*first)) 、 binary_op(init, init) 和 binary_op(unary_op(*first), unary_op(*first)) 都必须可转换为 T

返回值

指向最后被写入元素后一位置的迭代器。

复杂度

每个 binary_op 和 unary_op 应用 O(last - first) 次。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

不应用 unary_op 到 init 。

不同于 std::transform_exclusive_scan ，参数 init 出现于最后，因为它对此函数是可选的。

示例

#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>

int main()
{
  auto times_10 = [](int x) { return x * 10; };
  std::vector data {3, 1, 4, 1, 5, 9, 2, 6};

  std::cout << "10 times exclusive sum: ";
  std::transform_exclusive_scan(data.begin(), data.end(),
                                std::ostream_iterator<int>(std::cout, " "),
                                0, std::plus<int>{}, times_10);
  std::cout << "\n10 times inclusive sum: ";
  std::transform_inclusive_scan(data.begin(), data.end(),
                                std::ostream_iterator<int>(std::cout, " "),
                                std::plus<int>{}, times_10);
}

输出：

10 times exclusive sum: 0 30 40 80 90 140 230 250
10 times inclusive sum: 30 40 80 90 140 230 250 310

参阅

partial_sum | 计算范围内元素的部分和 (函数模板)
transform | 将一个函数应用于某一范围的各个元素，并在目标范围存储结果 (函数模板)
inclusive_scan (C++17) | 类似 std::partial_sum，第 i 个和中包含第 i 个输入 (函数模板)
transform_exclusive_scan (C++17) | 应用一个函数对象，然后进行排除扫描 (函数模板)


std::transform_reduce

< cpp‎ | algorithm
定义于头文件 <numeric> |  |
 | (1) |
template<class InputIt1, class InputIt2, class T> T transform_reduce(InputIt1 first1, InputIt1 last1, InputIt2 first2, T init); |  |  | (C++17 起) (C++20 前)
template<class InputIt1, class InputIt2, class T> constexpr T transform_reduce(InputIt1 first1, InputIt1 last1, InputIt2 first2, T init); |  |  | (C++20 起)
 | (2) |
template <class InputIt1, class InputIt2, class T, class BinaryOp1, class BinaryOp2> T transform_reduce(InputIt1 first1, InputIt1 last1, InputIt2 first2, T init, BinaryOp1 binary_op1, BinaryOp2 binary_op2); |  |  | (C++17 起) (C++20 前)
template <class InputIt1, class InputIt2, class T, class BinaryOp1, class BinaryOp2> constexpr T transform_reduce(InputIt1 first1, InputIt1 last1, InputIt2 first2, T init, BinaryOp1 binary_op1, BinaryOp2 binary_op2); |  |  | (C++20 起)
 | (3) |
template<class InputIt, class T, class BinaryOp, class UnaryOp> T transform_reduce(InputIt first, InputIt last, T init, BinaryOp binop, UnaryOp unary_op); |  |  | (C++17 起) (C++20 前)
template<class InputIt, class T, class BinaryOp, class UnaryOp> constexpr T transform_reduce(InputIt first, InputIt last, T init, BinaryOp binop, UnaryOp unary_op); |  |  | (C++20 起)
template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T> T transform_reduce(ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, T init); | (4) | (C++17 起)
template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T, class BinaryOp1, class BinaryOp2> T transform_reduce(ExecutionPolicy&& policy, ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, T init, BinaryOp1 binary_op1, BinaryOp2 binary_op2); | (5) | (C++17 起)
template<class ExecutionPolicy, class ForwardIt, class T, class BinaryOp, class UnaryOp> T transform_reduce(ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, T init, BinaryOp binary_op, UnaryOp unary_op); | (6) | (C++17 起)
1) 等价于 transform_reduce(first1, last1, first2, init, std::plus<>(), std::multiplies<>()); ，默认的 std::inner_product 的等效并行版本
2) 应用 binary_op2 到来自范围 [first; last) 和始于 first2 的范围的每对元素，并在 binary_op1 上与初始值 init 一同规约结果（可以以未指定行为重排聚合）
3) 应用 unary_op 到范围 [first; last) 中的每个元素，并在 binary_op 上与初始值 init 一同规约结果（可以以未指定行为重排聚合）。
4-6) 同 (1-3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

若 binary_op/binary_op2 为非交换或非结合则行为不确定。

若 unary_op 、 binary_op 、 binary_op1 或 binary_op2 修改输入范围中的任何元素或非法化范围中的任何迭代器，含尾迭代器，则行为未定义。

参数

first, last | - | 要应用算法的元素范围
init | - | 广义和的初始值
policy | - | 使用的执行策略，细节见执行策略。
unary_op | - | 将应用于输入范围的每个元素的一元函数对象 (FunctionObject) 。返回类型必须可为 binary_op 的输入所接受
binary_op | - | 将以未指定顺序应用于 unary_op 的结果、其他 binary_op 的结果和 init 的二元函数对象 (FunctionObject) 。
类型要求
- 为使用重载 (3,6) ， T 必须满足可移动构造 (MoveConstructible) 的要求。且表达式 binary_op(init, unary_op(*first)) 、 binary_op(unary_op(*first), init) 、 binary_op(init, init) 和 binary_op(unary_op(*first), unary_op(*first)) 的结果必须可转换为 T
- 为使用重载 (2,5) ， T 必须满足可移动构造 (MoveConstructible) 的要求。且表达式 binary_op1(init, binary_op2(*first1, *first2)) 、 binary_op1(binary_op2(*first1, *first2), init) 、 binary_op1(init, init) 和 binary_op1(binary_op2(*first1, *first2), binary_op2(*first1, *first2)) 的结果必须可转换为 T
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

2) init 和 binary_op2(*first,*first2) 、 binary_op2(*(first+1),*(first2+1)) ……在 binary_op1 上的广义和
3) init 和 unary_op(*first) 、 unary_op(*(first+1)) …… unary_op(*(last-1)) 在 binary_op 上的广义和，

其中广义和 GSUM(op, a
1, ..., a
N) 定义如下：

  • 若 N=1 ，则为 a
    1
  • 若 N > 1 ，则为 op(GSUM(op, b
    1    , ..., b
    K    ), GSUM(op, b
    M    , ..., b
    N    ))     ，其中
  • b
    1    , ..., b
    N     可以是 a1, ..., aN 的任意重排，若
  • 1 < K+1 = M ≤ N

换言之， unary_op 或 binary_op1 的结果能以任意顺序组合排列。

复杂度

1,2,4,5) 各使用 O(last1 - first1) 次 binary_op1 和 binary_op2 。
3,6) 各使用 O(last - first) 次 unary_op 和 binary_op 。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

在一元-二元重载 (3,6) 中， unary_op 不应用到 init

若 first == last 或 first1 == last1 ，则返回不修改的 init

示例

transform_reduce 能用于并行化的 std::inner_product ：

#include <vector>
#include <functional>
#include <iostream>
#include <numeric>
#include <execution>

int main()
{
    std::vector<double> xvalues(10007, 1.0), yvalues(10007, 1.0);

    double result = std::transform_reduce(
        std::execution::par,
        xvalues.begin(), xvalues.end(),
        yvalues.begin(), 0.0
    );
    std::cout << result << '\n';
}

输出：

10007

参阅

accumulate | 对一个范围内的元素求和 (函数模板)
transform | 将一个函数应用于某一范围的各个元素，并在目标范围存储结果 (函数模板)
reduce (C++17) | 类似 std::accumulate，但不依序执行 (函数模板)


std::unique

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class ForwardIt >
ForwardIt unique( ForwardIt first, ForwardIt last );
 (C++20 前)
template< class ForwardIt >
constexpr ForwardIt unique( ForwardIt first, ForwardIt last );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt >
ForwardIt unique( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last );
 (2) (C++17 起)
(3)
template< class ForwardIt, class BinaryPredicate >
ForwardIt unique( ForwardIt first, ForwardIt last, BinaryPredicate p );
 (C++20 前)
template< class ForwardIt, class BinaryPredicate >
constexpr ForwardIt unique( ForwardIt first, ForwardIt last, BinaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class BinaryPredicate >

ForwardIt unique( ExecutionPolicy&& policy,

ForwardIt first, ForwardIt last, BinaryPredicate p );
 (4) (C++17 起)

从来自范围 [first, last) 的相继等价元素组消除首元素外的元素，并返回范围的新逻辑结尾的尾后迭代器。

通过用覆写要被擦除的元素的方式迁移范围中的元素进行移除。

1) 用 operator== 比较元素。若它不是等价关系则行为未定义。
3) 用给定的谓词 p 比较元素。若它不是等价关系则行为未定义。
2,4) 同 (1,3) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要处理的元素范围
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若元素应被当做相等则返回 ​true 的二元谓词。 谓词函数的签名应等价于如下： bool pred(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 ForwardIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 解引用 ForwardIt 结果的类型必须满足可移动赋值 (MoveAssignable) 的要求。

返回值

指向范围新结尾的 ForwardIt 。

复杂度

对于非空范围，准确应用 std::distance (first,last) -1 次对应的谓词。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

保持剩余元素的相对顺序，且不更改容器的物理大小。指向范围的新逻辑结尾和物理结尾之间元素的迭代器仍然可解引用，但元素自身拥有未指定值。调用 unique 后有时会调用容器的 erase 成员函数，它擦除未指定值并减小容器的物理大小，以匹配其新的逻辑大小。

可能的实现

参阅 libstdc++、 libc++ 和 MSVC STL 中的实现。

版本一
template<class ForwardIt>
ForwardIt unique(ForwardIt first, ForwardIt last)
{
    if (first == last)
        return last;

    ForwardIt result = first;
    while (++first != last) {
        if (!(*result == *first) && ++result != first) {
            *result = std::move(*first);
        }
    }
    return ++result;
}
版本二
template<class ForwardIt, class BinaryPredicate>
ForwardIt unique(ForwardIt first, ForwardIt last, BinaryPredicate p)
{
    if (first == last)
        return last;

    ForwardIt result = first;
    while (++first != last) {
        if (!p(*result, *first) && ++result != first) {
            *result = std::move(*first);
        }
    }
    return ++result;
}

示例

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <cctype>

int main()
{
    // 含有数个重复元素的 vector
    std::vector<int> v{1,2,1,1,3,3,3,4,5,4};

    // 移除相继（毗邻）的重复元素
    auto last = std::unique(v.begin(), v.end());
    // v 现在保有 {1 2 1 3 4 5 4 x x x} ，其中 x 不确定
    v.erase(last, v.end());
    for (int i : v)
      std::cout << i << " ";
    std::cout << "\n";

    // sort 后 unique 以移除所有重复
    std::sort(v.begin(), v.end()); // {1 1 2 3 4 4 5}
    last = std::unique(v.begin(), v.end());
    // v 现在保有 {1 2 3 4 5 x x} ，其中 'x' 不确定
    v.erase(last, v.end());
    for (int i : v)
      std::cout << i << " ";
    std::cout << "\n";
}

输出：

1 2 1 3 4 5 4
1 2 3 4 5

参阅

adjacent_find | 查找首对相邻的相同（或满足给定谓词的）元素 (函数模板)
unique_copy | 创建某范围的不含连续重复元素的副本 (函数模板)
removeremove_if | 移除满足特定判别标准的元素 (函数模板)
unique | 删除连续的重复元素 (std::list<T,Allocator> 的公开成员函数)
unique (C++11) | 删除连续的重复元素 (std::forward_list<T,Allocator> 的公开成员函数)
ranges::unique (C++20) | 移除范围中的连续重复元素 (niebloid)


std::unique_copy

< cpp‎ | algorithm
定义于头文件 <algorithm>
(1)
template< class InputIt, class OutputIt >

OutputIt unique_copy( InputIt first, InputIt last,

OutputIt d_first );
 (C++20 前)
template< class InputIt, class OutputIt >

constexpr OutputIt unique_copy( InputIt first, InputIt last,

OutputIt d_first );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >

ForwardIt2 unique_copy( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 d_first );
 (2) (C++17 起)
(3)
template< class InputIt, class OutputIt, class BinaryPredicate >

OutputIt unique_copy( InputIt first, InputIt last,

OutputIt d_first, BinaryPredicate p );
 (C++20 前)
template< class InputIt, class OutputIt, class BinaryPredicate >

constexpr OutputIt unique_copy( InputIt first, InputIt last,

OutputIt d_first, BinaryPredicate p );
 (C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class BinaryPredicate >

ForwardIt2 unique_copy( ExecutionPolicy&& policy, ForwardIt1 first, ForwardIt1 last,

ForwardIt2 d_first, BinaryPredicate p );
 (4) (C++17 起)

从范围 [first, last) 复制元素到始于 d_first 的另一范围，使得无连续的相等元素。只复制每组等价元素的首元素。

1) 用 operator== 比较元素。
3) 用给定的二元谓词 p 比较元素。
2,4) 同 (1,3) ，但按照 policy 执行。这些重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要处理的元素范围
d_first | - | 目标范围的起始
policy | - | 所用的执行策略。细节见执行策略。
p | - | 若元素应被当做相等则返回 ​true 的二元谓词。 谓词函数的签名应等价于如下： bool pred(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 InputIt 类型的对象能在解引用后隐式转换到这两个类型。 ​
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- ForwardIt1, ForwardIt2 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 解引用 InputIt 结果的类型必须满足可复制赋值 (CopyAssignable) 的要求。若 InputIt 不满足老式向前迭代器 (LegacyForwardIterator) 。
- 解引用 InputIt 结果的类型必须满足可复制构造 (CopyConstructible) 的要求。若 InputIt 或 OutputIt 均不满足老式向前迭代器 (LegacyForwardIterator) ，或若 InputIt 不满足老式向前迭代器 (LegacyForwardIterator) 且 InputIt 的 value_type 异于 OutputIt 。

返回值

指向最后被写入元素后一元素的输出迭代器。

复杂度

对于非空范围，准确应用 std::distance (first, last) - 1 次对应谓词。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

注解

若 InputIt 满足老式向前迭代器 (LegacyForwardIterator) ，则此函数重读取输入，以检测重复。

否则，若 OutputIt 满足老式向前迭代器 (LegacyForwardIterator) ，且 InputIt 的 value_type 与 OutputIt 的相同，则此函数比较 *d_first 与 *first 。

否则，此函数比较 *first 和局部元素副本。

对有 ExecutionPolicy 的重载，若 ForwardIterator1 的值类型非可复制构造 (CopyConstructible) 及可复制赋值 (CopyAssignable) 则有性能开销。

可能的实现

参阅 libstdc++ 与 libc++ 中的实现。

示例

#include <string>
#include <iostream>
#include <algorithm>
#include <iterator>

int main()
{
    std::string s1 = "The      string    with many       spaces!";
    std::cout << "before: " << s1 << '\n';

    std::string s2;
    std::unique_copy(s1.begin(), s1.end(), std::back_inserter(s2),
                     [](char c1, char c2){ return c1 == ' ' && c2 == ' '; });

    std::cout << "after:  " << s2 << '\n';
}

输出：

before: The      string    with many       spaces!
after:  The string with many spaces!

参阅

adjacent_find | 查找首对相邻的相同（或满足给定谓词的）元素 (函数模板)
unique | 移除范围内的连续重复元素 (函数模板)
copycopy_if (C++11) | 将某一范围的元素复制到一个新的位置 (函数模板)
ranges::unique_copy (C++20) | 创建某范围的不含连续重复元素的副本 (niebloid)


std::upper_bound

< cpp‎ | algorithm
定义于头文件 <algorithm> |
 | (1)
template< class ForwardIt, class T > ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value ); |  | (C++20 前)
template< class ForwardIt, class T > constexpr ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value ); |  | (C++20 起)
 | (2)
template< class ForwardIt, class T, class Compare > ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value, Compare comp ); |  | (C++20 前)
template< class ForwardIt, class T, class Compare > constexpr ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value, Compare comp ); |  | (C++20 起)

返回指向范围 [first, last) 中首个大于 value 的元素的迭代器，或若找不到这种元素则返回 last 。

范围 [first, last) 必须已相对于表达式 !(value < element) 或 !comp(value, element) 划分，即所有令此表达式为 true 的元素必须前趋所有令此表达式为 false 的元素。完全排序的范围满足此判别标准。

第一版本用 operator< 比较元素，第二版本用给定的比较函数 comp 。

参数

first, last | - | 要检验的元素范围
value | - | 要与元素比较的值
comp | - | 若第一参数小于（即先序于）第二个则返回 ​true 的二元谓词。 谓词函数的签名应等价于如下： bool pred(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。 类型 Type1 必须使得 T 类型的对象能隐式转换到 Type1 。类型 Type2 必须使得 ForwardIt 类型的对象能在解引用后隐式转换到 Type2 。 ​
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- Compare 必须满足二元谓词 (BinaryPredicate) 的要求。不要求满足 比较 (Compare) 。

返回值

指向首个大于 value 的元素的迭代器，或若找不到这种元素则为 last 。

复杂度

进行的比较次数与 first 和 last 间的距离成对数（至多 log
2(last - first) + O(1) 次比较）。然而，对于非老式随机访问迭代器 (LegacyRandomAccessIterator) ，迭代次自增次数为线性。

可能的实现

版本一
template<class ForwardIt, class T>
ForwardIt upper_bound(ForwardIt first, ForwardIt last, const T& value)
{
    ForwardIt it;
    typename std::iterator_traits<ForwardIt>::difference_type count, step;
    count = std::distance(first,last);

    while (count > 0) {
        it = first;
        step = count / 2;
        std::advance(it, step);
        if (!(value < *it)) {
            first = ++it;
            count -= step + 1;
        }
        else
            count = step;
    }
    return first;
}
版本二
template<class ForwardIt, class T, class Compare>
ForwardIt upper_bound(ForwardIt first, ForwardIt last, const T& value, Compare comp)
{
    ForwardIt it;
    typename std::iterator_traits<ForwardIt>::difference_type count, step;
    count = std::distance(first,last);

    while (count > 0) {
        it = first;
        step = count / 2;
        std::advance(it, step);
        if (!comp(value, *it)) {
            first = ++it;
            count -= step + 1;
        }
        else
            count = step;
    }
    return first;
}

示例

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> data = { 1, 2, 4, 5, 5, 6 };

    for (int i = 0; i < 7; ++i) {
        // 搜索首个大于 i 的元素
        auto upper = std::upper_bound(data.begin(), data.end(), i);

        std::cout << i << " < ";
        if (upper != data.end())
            std::cout << *upper << " at index " << std::distance(data.begin(), upper);
        else
            std::cout << "not found";
        std::cout << '\n';
    }
}

输出：

0 < 1 at index 0
1 < 2 at index 1
2 < 4 at index 2
3 < 4 at index 2
4 < 5 at index 3
5 < 6 at index 5
6 < not found

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 270 | C++98 | 曾要求 Compare 为严格弱序 | 只需要划分；容许异相比较

参阅

equal_range | 返回匹配特定键值的元素范围 (函数模板)
lower_bound | 返回指向第一个不小于给定值的元素的迭代器 (函数模板)
partition | 将范围中的元素分为两组 (函数模板)


原子操作库

< cpp

原子库为细粒度的原子操作提供组件，允许无锁并发编程。涉及同一对象的每个原子操作，相对于任何其他原子操作是不可分的。原子对象不具有数据竞争。

定义于头文件 <atomic>
原子类型
atomic
(C++11)
 atomic 类模板及其针对布尔、整型和指针类型的特化
(类模板)
atomic_ref
(C++20)
 提供非原子对象上的原子操作
(类模板)
原子类型上的操作
atomic_is_lock_free
(C++11)
 检查对该原子类型的操作是否是无锁的
(函数模板)
atomic_storeatomic_store_explicit
(C++11)(C++11)
 原子地以非原子实参替换原子对象的值
(函数模板)
atomic_loadatomic_load_explicit
(C++11)(C++11)
 原子地获得存储于原子对象的值
(函数模板)
atomic_exchangeatomic_exchange_explicit
(C++11)(C++11)
 原子地以非原子实参的值替换原子对象的值，并返回该原子对象的旧值
(函数模板)
atomic_compare_exchange_weakatomic_compare_exchange_weak_explicitatomic_compare_exchange_strongatomic_compare_exchange_strong_explicit
(C++11)(C++11)(C++11)(C++11)
 原子地比较原子对象和非原子实参的值，若相等则进行 atomic_exchange，若不相等则进行 atomic_load
(函数模板)
atomic_fetch_addatomic_fetch_add_explicit
(C++11)(C++11)
 将非原子值加到原子对象，并获得原子对象的先前值
(函数模板)
atomic_fetch_subatomic_fetch_sub_explicit
(C++11)(C++11)
 从原子对象减去非原子值，并获得原子对象的先前值
(函数模板)
atomic_fetch_andatomic_fetch_and_explicit
(C++11)(C++11)
 将原子对象替换为与非原子实参逻辑与的结果，并获得原子对象的先前值
(函数模板)
atomic_fetch_oratomic_fetch_or_explicit
(C++11)(C++11)
 将原子对象替换为与非原子实参逻辑或的结果，并获得原子对象的先前值
(函数模板)
atomic_fetch_xoratomic_fetch_xor_explicit
(C++11)(C++11)
 将原子对象替换为与非原子实参逻辑异或的结果，并获得原子对象的先前值
(函数模板)
atomic_waitatomic_wait_explicit
(C++20)(C++20)
 阻塞线程直至被提醒且原子值更改
(函数模板)
atomic_notify_one
(C++20)
 提醒一个在 atomic_wait 中阻塞的线程
(函数模板)
atomic_notify_all
(C++20)
 提醒所有在 atomic_wait 中阻塞的线程
(函数模板)
标志类型及操作
atomic_flag
(C++11)
 免锁的布尔原子类型
(类)
atomic_flag_test_and_setatomic_flag_test_and_set_explicit
(C++11)(C++11)
 原子地设置标志为 true 并返回其先前值
(函数)
atomic_flag_clearatomic_flag_clear_explicit
(C++11)(C++11)
 原子地设置标志值为 false
(函数)
atomic_flag_testatomic_flag_test_explicit
(C++20)(C++20)
 原子地返回标志的值
(函数)
atomic_flag_waitatomic_flag_wait_explicit
(C++20)(C++20)
 阻塞线程，直至被提醒且标志更改
(函数)
atomic_flag_notify_one
(C++20)
 提醒一个在 atomic_flag_wait 中阻塞的线程
(函数)
atomic_flag_notify_all
(C++20)
 提醒所有在 atomic_flag_wait 中阻塞的线程
(函数)
初始化
atomic_init
(C++11)(C++20 中弃用)
 对默认构造的原子对象进行非原子初始化
(函数模板)
ATOMIC_VAR_INIT
(C++11)(C++20 中弃用)
 静态存储期的原子对象的常量初始化
(宏函数)
ATOMIC_FLAG_INIT
(C++11)(C++20 中弃用)
 将 std::atomic_flag 初始化为 false
(宏常量)
内存同步顺序
memory_order
(C++11)
 为给定的原子操作定义内存顺序约束
(枚举)
kill_dependency
(C++11)
 从 std::memory_order_consume 依赖树移除指定对象
(函数模板)
atomic_thread_fence
(C++11)
 通用的依赖内存顺序的栅栏同步原语
(函数)
atomic_signal_fence
(C++11)
 线程与执行于同一线程的信号处理函数间的栅栏
(函数)

原子类型的 C 兼容性

定义于头文件 <stdatomic.h>
_Atomic
(C++23)
 使得 _Atomic(T) 等同于 std::atomic <T> 的兼容性宏
(宏函数)

<stdatomic.h> 以外的 C++ 标准库头文件不提供 _Atomic 宏或任何非宏的全局命名空间声明。

 (C++23 起)

参阅


ATOMIC_FLAG_INIT

< cpp‎ | atomic
定义于头文件 <atomic> |
#define ATOMIC_FLAG_INIT /* implementation-defined */ | (C++11 起) (C++20 中弃用)

定义能以语句 std::atomic_flag v = ATOMIC_FLAG_INIT; 用于初始化 std::atomic_flag 以清除（置 false ）状态的初始化器。它能否用于其他初始化语境中是未指定的。

若标志拥有静态存储期，则此初始化为静态。

这是初始化 std::atomic_flag 为确定值的唯一方式：任何其他初始化后它保有的值是未指定的。 | (C++20 前)
此宏不再有必要且被弃用，因为 std::atomic_flag 的默认构造函数初始化它为清除状态。 | (C++20 起)

示例

#include <atomic>

std::atomic_flag static_flag = ATOMIC_FLAG_INIT; // 静态初始化，
// 保证在静态对象的动态初始化期间可用。

int main()
{
    std::atomic_flag automatic_flag = ATOMIC_FLAG_INIT; // 保证能工作
//    std::atomic_flag another_flag(ATOMIC_FLAG_INIT); // 未指定
}

参阅

atomic_flag
(C++11)
 免锁的布尔原子类型
(类)


ATOMIC_VAR_INIT

< cpp‎ | atomic
定义于头文件 <atomic> |
#define ATOMIC_VAR_INIT(value) /* implementation-defined */ | (C++11 起) (C++20 中弃用)

展开成能用于初始化能从 value 初始化的 std::atomic 对象的表达式。若原子对象拥有静态存储期，则此初始化为常量初始化。

注解

从另一线程在初始化期间访问，即使通过原子操作，也是数据竞争（若立即传递地址给带 std::memory_order_relaxed 操作的另一线程则可以发生）。

此宏主要为与 C 的兼容性提供；它表现与 std::atomic 的构造函数相同。

示例

#include <atomic>
#include <iostream>

int main()
{
    std::atomic<int> a = ATOMIC_VAR_INIT(1);
    // std::atomic<int> a(1);   // 仅 C++ 的替用品
    std::cout << "Initialized std::atomic<int> as: " << a << '\n';
}

输出：

Initialized std::atomic<int> as: 1

参阅

atomic_init (C++11)(C++20 中弃用) | 对默认构造的原子对象进行非原子初始化 (函数模板)
(构造函数) | 构造原子对象 (std::atomic<T> 的公开成员函数)


std::atomic

< cpp‎ | atomic
定义于头文件 <atomic> |  |
template< class T > struct atomic; | (1) | (C++11 起)
template< class U > struct atomic<U*>; | (2) | (C++11 起)
定义于头文件 <memory> |  |
template<class U> struct atomic< std::shared_ptr <U>>; | (3) | (C++20 起)
template<class U> struct atomic< std::weak_ptr <U>>; | (4) | (C++20 起)
定义于头文件 <stdatomic.h> |  |
#define _Atomic(T) /* see below */ | (5) | (C++23 起)

每个 std::atomic 模板的实例化和全特化定义一个原子类型。若一个线程写入原子对象，同时另一线程从它读取，则行为良好定义（数据竞争的细节见内存模型）。

另外，对原子对象的访问可以建立线程间同步，并按 std::memory_order 所对非原子内存访问定序。

std::atomic 既不可复制亦不可移动。

兼容性宏 _Atomic 于头文件 <stdatomic.h> 中提供，使得两者均良构时 _Atomic(T) 等同于 std::atomic<T> 。

未指定包含 <stdatomic.h> 时命名空间 std 中的任何声明可用。

 (C++23 起)

特化

主模板

主 std::atomic 模板可用任何满足可复制构造 (CopyConstructible) 及可复制赋值 (CopyAssignable) 的可平凡复制 (TriviallyCopyable) 类型 T 特化。若下列任何值为 false 则程序为谬构：

  • std::is_trivially_copyable <T>::value
  • std::is_copy_constructible <T>::value
  • std::is_move_constructible <T>::value
  • std::is_copy_assignable <T>::value
  • std::is_move_assignable <T>::value

std::atomic<bool> 使用初等模板。它保证是标准布局结构体。

部分特化

标准库为下列类型提供 std::atomic 模板的特化，它们拥有初等模板所不拥有的额外属性：

2) 对所有指针类型的部分特化 std::atomic<U*> 。这些特化拥有标准布局、平凡默认构造函数 (C++20 前)和平凡析构函数。除了为所有原子类型提供的操作，这些特化额外支持适合指针类型的原子算术运算，例如 fetch_add 、 fetch_sub 。

3-4) 为 std::shared_ptr 和 std::weak_ptr 提供部分特化 std::atomic< std::shared_ptr <U>> 和 std::atomic< std::weak_ptr <U>> 。

细节见 std::atomic<std::shared_ptr> 和 std::atomic<std::weak_ptr> 。

 (C++20 起)

对整数类型的特化

以下列整数类型之一实例化时， std::atomic 提供适合于整数类型的额外原子操作，例如 fetch_add 、 fetch_sub 、 fetch_and 、 fetch_or 、 fetch_xor ：

  • 字符类型 char 、 char8_t (C++20 起)、 char16_t 、 char32_t 和 wchar_t ；
  • 标准有符号整数类型： signed char 、 short 、 int 、 long 和 long long ；
  • 标准无符号整数类型： unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 和 unsigned long long ；
  • 任何头文件 <cstdint> 中的 typedef 所需的额外整数类型。

另外，结果的 std::atomic<Integral> 特化拥有标准布局、平凡默认构造函数 (C++20 前)和平凡析构函数。定义有符号整数算术为使用补码；无未定义结果。

对浮点类型的特化

以浮点类型 float 、 double 和 long double 之一实例化时， std::atomic 提供适合于浮点类型的额外原子操作，例如 fetch_add 和 fetch_sub 。

另外，结果的 std::atomic<Floating> 特化拥有标准布局和平凡析构函数。

无操作导致未定义行为，即使结果不能以浮点类型表示。有效的浮点环境可能不同于调用方线程的浮点环境。

 (C++20 起)

类型别名

为 bool 和所有上面列出的整数类型提供如下类型别名：

所有 std::atomic<Integral> 别名
atomic_bool
(C++11)
 std::atomic<bool>
(typedef)
atomic_char
(C++11)
 std::atomic<char>
(typedef)
atomic_schar
(C++11)
 std::atomic<signed char>
(typedef)
atomic_uchar
(C++11)
 std::atomic<unsigned char>
(typedef)
atomic_short
(C++11)
 std::atomic<short>
(typedef)
atomic_ushort
(C++11)
 std::atomic<unsigned short>
(typedef)
atomic_int
(C++11)
 std::atomic<int>
(typedef)
atomic_uint
(C++11)
 std::atomic<unsigned int>
(typedef)
atomic_long
(C++11)
 std::atomic<long>
(typedef)
atomic_ulong
(C++11)
 std::atomic<unsigned long>
(typedef)
atomic_llong
(C++11)
 std::atomic<long long>
(typedef)
atomic_ullong
(C++11)
 std::atomic<unsigned long long>
(typedef)
atomic_char8_t
(C++20)
 std::atomic<char8_t>
(typedef)
atomic_char16_t
(C++11)
 std::atomic<char16_t>
(typedef)
atomic_char32_t
(C++11)
 std::atomic<char32_t>
(typedef)
atomic_wchar_t
(C++11)
 std::atomic<wchar_t>
(typedef)
atomic_int8_t
(C++11)(可选)
 std::atomic< std::int8_t >
(typedef)
atomic_uint8_t
(C++11)(可选)
 std::atomic< std::uint8_t >
(typedef)
atomic_int16_t
(C++11)(可选)
 std::atomic< std::int16_t >
(typedef)
atomic_uint16_t
(C++11)(可选)
 std::atomic< std::uint16_t >
(typedef)
atomic_int32_t
(C++11)(可选)
 std::atomic< std::int32_t >
(typedef)
atomic_uint32_t
(C++11)(可选)
 std::atomic< std::uint32_t >
(typedef)
atomic_int64_t
(C++11)(可选)
 std::atomic< std::int64_t >
(typedef)
atomic_uint64_t
(C++11)(可选)
 std::atomic< std::uint64_t >
(typedef)
atomic_int_least8_t
(C++11)
 std::atomic< std::int_least8_t >
(typedef)
atomic_uint_least8_t
(C++11)
 std::atomic< std::uint_least8_t >
(typedef)
atomic_int_least16_t
(C++11)
 std::atomic< std::int_least16_t >
(typedef)
atomic_uint_least16_t
(C++11)
 std::atomic< std::uint_least16_t >
(typedef)
atomic_int_least32_t
(C++11)
 std::atomic< std::int_least32_t >
(typedef)
atomic_uint_least32_t
(C++11)
 std::atomic< std::uint_least32_t >
(typedef)
atomic_int_least64_t
(C++11)
 std::atomic< std::int_least64_t >
(typedef)
atomic_uint_least64_t
(C++11)
 std::atomic< std::uint_least64_t >
(typedef)
atomic_int_fast8_t
(C++11)
 std::atomic< std::int_fast8_t >
(typedef)
atomic_uint_fast8_t
(C++11)
 std::atomic< std::uint_fast8_t >
(typedef)
atomic_int_fast16_t
(C++11)
 std::atomic< std::int_fast16_t >
(typedef)
atomic_uint_fast16_t
(C++11)
 std::atomic< std::uint_fast16_t >
(typedef)
atomic_int_fast32_t
(C++11)
 std::atomic< std::int_fast32_t >
(typedef)
atomic_uint_fast32_t
(C++11)
 std::atomic< std::uint_fast32_t >
(typedef)
atomic_int_fast64_t
(C++11)
 std::atomic< std::int_fast64_t >
(typedef)
atomic_uint_fast64_t
(C++11)
 std::atomic< std::uint_fast64_t >
(typedef)
atomic_intptr_t
(C++11)(可选)
 std::atomic< std::intptr_t >
(typedef)
atomic_uintptr_t
(C++11)(可选)
 std::atomic< std::uintptr_t >
(typedef)
atomic_size_t
(C++11)
 std::atomic< std::size_t >
(typedef)
atomic_ptrdiff_t
(C++11)
 std::atomic< std::ptrdiff_t >
(typedef)
atomic_intmax_t
(C++11)
 std::atomic< std::intmax_t >
(typedef)
atomic_uintmax_t
(C++11)
 std::atomic< std::uintmax_t >
(typedef)
特殊用途类型别名
atomic_signed_lock_free
(C++20)
 免锁且对于等待/提醒最高效的有符号整数原子类型
(typedef)
atomic_unsigned_lock_free
(C++20)
 免锁且对于等待/提醒最高效的无符号整数原子类型
(typedef)

注意： std::atomic_intN_t 、 std::atomic_uintN_t 、 std::atomic_intptr_t 及 atomic_uintptr_t 分别若且唯若定义了 std::intN_t 、 std::uintN_t 、 std::intptr_t 及 std::uintptr_t 才有定义。

std::atomic_signed_lock_free 与 std::atomic_unsigned_lock_free 在自立实现中可选。

 (C++20 起)

成员类型

成员类型 | 定义
value_type | T (无论是否特化)
difference_type | value_type (仅对 atomic<Integral> 和 atomic<Floating> (C++20 起) 特化) std::ptrdiff_t (仅对 atomic<U*> 特化)

difference_type 不在初等 atomic 模板中，或不在对 std::shared_ptr 和 std::weak_ptr 的部分特化中定义。

成员函数

(构造函数)
 构造原子对象
(公开成员函数)
operator=
 存储值于原子对象
(公开成员函数)
is_lock_free
 检查原子对象是否免锁
(公开成员函数)
store
 原子地以非原子对象替换原子对象的值
(公开成员函数)
load
 原子地获得原子对象的值
(公开成员函数)
operator T
 从原子对象加载值
(公开成员函数)
exchange
 原子地替换原子对象的值并获得它先前持有的值
(公开成员函数)
compare_exchange_weakcompare_exchange_strong
 原子地比较原子对象与非原子参数的值，若相等则进行交换，若不相等则进行加载
(公开成员函数)
wait
(C++20)
 阻塞线程直至被提醒且原子值更改
(公开成员函数)
notify_one
(C++20)
 提醒至少一个在原子对象上的等待中阻塞的线程
(公开成员函数)
notify_all
(C++20)
 提醒所有在原子对象上的等待中阻塞的线程
(公开成员函数)

常量
is_always_lock_free
[静态] (C++17)
 指示该类型是否始终免锁
(公开静态成员常量)

特化成员函数

fetch_add | 原子地将参数加到存储于原子对象的值，并返回先前保有的值 (公开成员函数)
fetch_sub | 原子地从存储于原子对象的值减去参数，并获得先前保有的值 (公开成员函数)
fetch_and | 原子地进行参数和原子对象的值的逐位与，并获得先前保有的值 (公开成员函数)
fetch_or | 原子地进行参数和原子对象的值的逐位或，并获得先前保有的值 (公开成员函数)
fetch_xor | 原子地进行参数和原子对象的值的逐位异或，并获得先前保有的值 (公开成员函数)
operator++operator++(int)operator--operator--(int) | 令原子值增加或减少一 (公开成员函数)
operator+=operator-=operator&=operator|=operator^= | 加、减，或与原子值进行逐位与、或、异或 (公开成员函数)

注解

存在等价于 std::atomic 所有成员函数的非成员函数模板。这些非成员函数可以额外对非 std::atomic 特化的类型重载，但不能保证原子性。标准库中仅有的这种类型是 std::shared_ptr <U> 。

C 中 _Atomic 是关键词并用于提供原子类型。

推荐实现确保对于每个可能的类型 T ， C 中 _Atomic(T) 的表示与 C++ 中 std::atomic<T> 的相同。用于确保原子性与内存顺序的机制应该兼容。

gcc 和 clang 上，此处描述的某些功能要求通过 -latomic 链接。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2441 | C++11 | 可选的定宽整数类型的原子版本的 typedef 缺失 | 已添加
P0558R1 | C++11 | 某些原子类型函数的模板实参推导可能意外失败； 提供了非法指针操作 | 实质上重写了规范： 提供了成员 typedef value_type 与 difference_type
LWG 3012 | C++11 | std::atomic<T> 对任何可平凡复制但非可复制的 T 容许 | 禁止这种特化

参阅

atomic_flag (C++11) | 免锁的布尔原子类型 (类)
std::atomic<std::shared_ptr> (C++20) | 原子共享指针 (类模板特化)
std::atomic<std::weak_ptr> (C++20) | 原子弱指针 (类模板特化)


std::atomic<T>::atomic

< cpp‎ | atomic‎ | atomic
 | (1) |
atomic() noexcept = default; |  |  | (C++11 起) (C++20 前)
constexpr atomic() noexcept( std::is_nothrow_default_constructible_v <T>); |  |  | (C++20 起)
constexpr atomic( T desired ) noexcept; | (2) | (C++11 起)
atomic( const atomic& ) = delete; | (3) | (C++11 起)

构造新的原子对象：

1) 默认构造函数是平凡的：不发生静态和线程局域对象的零初始化以外的初始化。 std::atomic_init 可用于完成初始化。 | (C++20 前)
1) 值初始化底层对象（即用 T()) ）。该初始化非原子。若 std::is_default_constructible_v <T> 为 false 则默认构造函数的使用为谬构。 | (C++20 起)
2) 以 desired 初始化底层值。该初始化非原子。
3) 原子对象非可复制构造 (CopyConstructible) 。

参数

desired - 用以初始化的值

注解

默认初始化的 std::atomic <T> 不含 T 对象，它仅有的合法用法是析构和以 std::atomic_init 初始化，见 LWG 2334 。

 (C++20 前)


std::atomic<T>::compare_exchange_weak, std::atomic<T>::compare_exchange_strong

< cpp‎ | atomic‎ | atomic
定义于头文件 <atomic>
(1) | (C++11 起)
bool compare_exchange_weak( T& expected, T desired,

std::memory_order success,

std::memory_order failure ) noexcept;
bool compare_exchange_weak( T& expected, T desired,

std::memory_order success,

std::memory_order failure ) volatile noexcept;
(2) | (C++11 起)
bool compare_exchange_weak( T& expected, T desired,

std::memory_order order =

std::memory_order_seq_cst ) noexcept;
bool compare_exchange_weak( T& expected, T desired,

std::memory_order order =

std::memory_order_seq_cst ) volatile noexcept;
(3) | (C++11 起)
bool compare_exchange_strong( T& expected, T desired,

std::memory_order success,

std::memory_order failure ) noexcept;
bool compare_exchange_strong( T& expected, T desired,

std::memory_order success,

std::memory_order failure ) volatile noexcept;
(4) | (C++11 起)
bool compare_exchange_strong( T& expected, T desired,

std::memory_order order =

std::memory_order_seq_cst ) noexcept;
bool compare_exchange_strong( T& expected, T desired,

std::memory_order order =

std::memory_order_seq_cst ) volatile noexcept;

原子地比较 *this 和 expected 的对象表示 (C++20 前)值表示 (C++20 起)，而若它们逐位相等，则以 desired 替换前者（进行读修改写操作）。否则，将 *this 中的实际值加载进 expected （进行加载操作）。

读修改写和加载操作的内存模型分别为 success 和 failure 。在 (2) 和 (4) 版本中， order 用于读修改写操作和加载操作，除了若 order == std::memory_order_acq_rel 或 order == std::memory_order_release ，则加载操作分别使用 std::memory_order_acquire 和 std::memory_order_relaxed 。

若 std::atomic <T>::is_always_lock_free 为 false 则 volatile 限定版本被弃用。

 (C++20 起)

参数

expected | - | 到期待在原子对象中找到的值的引用。若比较失败则被存储 *this 的实际值。
desired | - | 若符合期待则存储于原子对象的值
success | - | 若比较成功，则读修改写操作所用的内存同步顺序。容许所有值。
failure | - | 若比较失败，则加载操作所用的内存同步顺序。不能为 std::memory_order_release 或 std::memory_order_acq_rel ，且不能指定强于 success 的顺序 (C++17 前)
order | - | 两个操作所用的内存同步顺序

返回值

若成功更改底层原子值则为 true ，否则为 false 。

注解

比较和复制是逐位的（类似 std::memcmp 和 std::memcpy ）；不使用构造函数、赋值运算符或比较运算符。

允许函数的弱形式 (1-2) 虚假地失败，即表现如同 *this != expected ，纵使它们相等。比较和交换在循环中时，弱版本在有的平台上会产出更好的性能。

弱版本比较和交换会要求循环，而强版本不要求时，推荐用强版本，除非 T 的对象表示可包含填充位、 (C++20 前)陷阱位或为同一值提供多个对象表示（例如浮点 NaN ）。这些情况下，弱比较和交换典型地可用，因为它在一些稳定对象表示上快速收敛。

若有参与 union 某些成员，但非其他成员的值表示的位，则比较和交换可能始终失败，因为这种填充位在不参与活跃成员的值表示时拥有不确定值。

忽略决不参与对象值表示的填充位。

 (C++20 起)

示例

比较和交换操作通常用作无锁数据结构的基本建筑块

#include <atomic>
template<typename T>
struct node
{
    T data;
    node* next;
    node(const T& data) : data(data), next(nullptr) {}
};

template<typename T>
class stack
{
    std::atomic<node<T>*> head;
 public:
    void push(const T& data)
    {
      node<T>* new_node = new node<T>(data);

      // 放 head 的当前值到 new_node->next 中
      new_node->next = head.load(std::memory_order_relaxed);

      // 现在令 new_node 为新的 head ，但若 head 不再是
      // 存储于 new_node->next 的值（某些其他线程必须在刚才插入结点）
      // 则放新的 head 到 new_node->next 中并再尝试
      while(!head.compare_exchange_weak(new_node->next, new_node,
                                        std::memory_order_release,
                                        std::memory_order_relaxed))
          ; // 循环体为空

// 注意：上述使用至少在这些版本不是线程安全的
// 先于 4.8.3 的 GCC （漏洞 60272 ），先于 2014-05-05 的 clang （漏洞 18899 ）
// 先于 2014-03-17 的 MSVC （漏洞 819819 ）。下面是变通方法：
//      node<T>* old_head = head.load(std::memory_order_relaxed);
//      do {
//          new_node->next = old_head;
//       } while(!head.compare_exchange_weak(old_head, new_node,
//                                           std::memory_order_release,
//                                           std::memory_order_relaxed));
    }
};
int main()
{
    stack<int> s;
    s.push(1);
    s.push(2);
    s.push(3);
}

演示 compare_exchange_strong 如何要么更改原子对象的值，要么将变量用于比较。

本节未完成
原因：强 CAS 的更实际用法会更好，例如在 Concurrency in Action 使用它的地方
#include <atomic>
#include <iostream>

std::atomic<int>  ai;

int  tst_val= 4;
int  new_val= 5;
bool exchanged= false;

void valsout()
{
    std::cout << "ai= " << ai
              << "  tst_val= " << tst_val
              << "  new_val= " << new_val
              << "  exchanged= " << std::boolalpha << exchanged
              << "\n";
}

int main()
{
    ai= 3;
    valsout();

    // tst_val != ai   ==>  tst_val 被修改
    exchanged= ai.compare_exchange_strong( tst_val, new_val );
    valsout();

    // tst_val == ai   ==>  ai 被修改
    exchanged= ai.compare_exchange_strong( tst_val, new_val );
    valsout();
}

输出：

ai= 3  tst_val= 4  new_val= 5  exchanged= false
ai= 3  tst_val= 3  new_val= 5  exchanged= false
ai= 5  tst_val= 3  new_val= 5  exchanged= true

参阅

atomic_compare_exchange_weakatomic_compare_exchange_weak_explicitatomic_compare_exchange_strongatomic_compare_exchange_strong_explicit
(C++11)(C++11)(C++11)(C++11)
 原子地比较原子对象和非原子实参的值，若相等则进行 atomic_exchange，若不相等则进行 atomic_load
(函数模板)


std::atomic<T>::exchange

< cpp‎ | atomic‎ | atomic
 | (C++11 起)
T exchange( T desired, std::memory_order order = std::memory_order_seq_cst ) noexcept;
T exchange( T desired, std::memory_order order = std::memory_order_seq_cst ) volatile noexcept;

原子地以 desired 替换底层值。操作为读-修改-写操作。根据 order 的值影响内存。

若 std::atomic <T>::is_always_lock_free 为 false 则 volatile 限定版本被弃用。

 (C++20 起)

参数

desired | - | 要赋值的值
order | - | 要强加的内存顺序制约

返回值

调用前原子对象的值。

参阅

atomic_exchangeatomic_exchange_explicit
(C++11)(C++11)
 原子地以非原子实参的值替换原子对象的值，并返回该原子对象的旧值
(函数模板)


std::atomic<T>::fetch_add

< cpp‎ | atomic‎ | atomic
仅为 atomic<Integral>(C++11) 与 atomic<Floating>(C++20) 模板特化的成员
(1)
T fetch_add( T arg,
std::memory_order order = std::memory_order_seq_cst ) noexcept;
T fetch_add( T arg,
std::memory_order order = std::memory_order_seq_cst ) volatile noexcept;
仅为 atomic<T*> 模板特化的成员
(2)
T* fetch_add( std::ptrdiff_t arg,
std::memory_order order = std::memory_order_seq_cst ) noexcept;
T* fetch_add( std::ptrdiff_t arg,
std::memory_order order = std::memory_order_seq_cst ) volatile noexcept;

原子地以值和 arg 的算术加法结果替换当前值。运算是读修改写操作。按照 order 的值影响内存。

对于有符号 Integral 类型，定义算术为使用补码。无未定义结果。

对于 T* 类型，结果可能为未定义的地址，但此外运算无未定义行为。

对于浮点类型，有影响的浮点环境可能异于调用方线程的浮点环境。操作不必遵循对应的 std::numeric_limits 特性，但鼓励这么做。若结果不是其类型所能表示的值，则结果未指定，但此外操作无未定义行为。

若 std::atomic <T>::is_always_lock_free 为 false 则 volatile 限定版本被弃用。

 (C++20 起)

参数

arg | - | 算术加法的另一参数
order | - | 强制的内存顺序制约

返回值

*this 的修改顺序中，立即前趋此函数效应的值。

示例

#include <iostream>
#include <thread>
#include <atomic>

std::atomic<long long> data;
void do_work()
{
    data.fetch_add(1, std::memory_order_relaxed);
}

int main()
{
    std::thread th1(do_work);
    std::thread th2(do_work);
    std::thread th3(do_work);
    std::thread th4(do_work);
    std::thread th5(do_work);

    th1.join();
    th2.join();
    th3.join();
    th4.join();
    th5.join();

    std::cout << "Result:" << data << '\n';
}

输出：

Result:5

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0558R1 | C++11 | 曾容许指向 cv void 或函数的指针 | 使之为谬构

参阅

atomic_fetch_addatomic_fetch_add_explicit
(C++11)(C++11)
 将非原子值加到原子对象，并获得原子对象的先前值
(函数模板)


std::atomic<T>::fetch_and

< cpp‎ | atomic‎ | atomic
 | (C++11 起) (仅为 atomic<Integral> 模板特化的成员)
T fetch_and( T arg, std::memory_order order = std::memory_order_seq_cst ) noexcept;
T fetch_and( T arg, std::memory_order order = std::memory_order_seq_cst ) volatile noexcept;

原子地以值和 arg 逐位与的结果替换当前值。运算是读修改写操作。按照 order 的值影响内存。

若 std::atomic <T>::is_always_lock_free 为 false 则 volatile 限定版本被弃用。

 (C++20 起)

参数

arg | - | 逐位与的另一参数
order | - | 强制的内存顺序制约

返回值

*this 的修改顺序中立即前趋此函数效果的值。

参阅

atomic_fetch_andatomic_fetch_and_explicit
(C++11)(C++11)
 将原子对象替换为与非原子实参逻辑与的结果，并获得原子对象的先前值
(函数模板)


std::atomic<T>::fetch_or

< cpp‎ | atomic‎ | atomic
 | (C++11 起) (仅为 atomic<Integral> 模板特化的成员)
T fetch_or( T arg, std::memory_order order = std::memory_order_seq_cst ) noexcept;
T fetch_or( T arg, std::memory_order order = std::memory_order_seq_cst ) volatile noexcept;

原子地以值和 arg 逐位或的结果替换当前值。运算为读修改写操作。按照 order 的值影响内存。

若 std::atomic <T>::is_always_lock_free 为 false 则 volatile 限定版本被弃用。

 (C++20 起)

参数

arg | - | 逐位或的另一参数
order | - | 强制的内存顺序制约

返回值

*this 的修改顺序中立即前趋此函数效果的值。

参阅

atomic_fetch_oratomic_fetch_or_explicit
(C++11)(C++11)
 将原子对象替换为与非原子实参逻辑或的结果，并获得原子对象的先前值
(函数模板)


std::atomic<T>::fetch_sub

< cpp‎ | atomic‎ | atomic
仅为 atomic<Integral>(C++11) 与 atomic<Floating>(C++20) 模板特化的成员
(1)
T fetch_sub( T arg,
std::memory_order order = std::memory_order_seq_cst ) noexcept;
T fetch_sub( T arg,
std::memory_order order = std::memory_order_seq_cst ) volatile noexcept;
仅为 atomic<T*> 模板特化的成员
(2)
T* fetch_sub( std::ptrdiff_t arg,
std::memory_order order = std::memory_order_seq_cst ) noexcept;
T* fetch_sub( std::ptrdiff_t arg,
std::memory_order order = std::memory_order_seq_cst ) volatile noexcept;

以值和 arg 的算术减法结果原子地替换当前值。操作是读修改写操作。按照 order 的值影响内存。

对于有符号 Integral 类型，定义算术为使用补码表示。无未定义结果。

对于 T* 类型，结果可能是未定义地址，但此外操作不会有未定义行为。若 T 不是对象类型则程序为谬构。

对于浮点类型，有影响的浮点环境可能异于调用方线程的浮点环境。操作不必遵循对应的 std::numeric_limits 特性，但鼓励这么做。若结果不是其类型所能表示的值，则结果未指定，但此外操作不会有未定义行为。

若 std::atomic <T>::is_always_lock_free 为 false 则 volatile 限定版本被弃用。

 (C++20 起)

参数

arg | - | 算术减法的另一参数
order | - | 强制的内存顺序制约

返回值

*this 的修改顺序中立即前趋此函数效果的值。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0558R1 | C++11 | 曾容许指向 cv void 或函数的指针 | 使之为谬构

参阅

atomic_fetch_subatomic_fetch_sub_explicit
(C++11)(C++11)
 从原子对象减去非原子值，并获得原子对象的先前值
(函数模板)


std::atomic<T>::fetch_xor

< cpp‎ | atomic‎ | atomic
 | (C++11 起) (仅为 atomic<Integral> 模板特化的成员)
T fetch_xor( T arg, std::memory_order order = std::memory_order_seq_cst ) noexcept;
T fetch_xor( T arg, std::memory_order order = std::memory_order_seq_cst ) volatile noexcept;

原子地以值和 arg 逐位异或的结果替换当前值。运算是读修改写操作。按照 order 的值影响内存。

若 std::atomic <T>::is_always_lock_free 为 false 则 volatile 限定版本被弃用。

 (C++20 起)

参数

arg | - | 逐位异或的另一参数
order | - | 强制的内存顺序制约

返回值

*this 的修改顺序中立即前趋此函数效果的值。

参阅

atomic_fetch_xoratomic_fetch_xor_explicit
(C++11)(C++11)
 将原子对象替换为与非原子实参逻辑异或的结果，并获得原子对象的先前值
(函数模板)


std::atomic<T>::is_always_lock_free

< cpp‎ | atomic‎ | atomic
static constexpr bool is_always_lock_free = /*implementation-defined*/; | (C++17 起)

若此原子类型始终为无锁则为 true ，若它决不或有时为无锁则为 false 。

此常量的值等于有定义处的宏 ATOMIC_xxx_LOCK_FREE 、成员函数 is_lock_free 和非成员函数 std::atomic_is_lock_free 。

注意

无此静态成员常量的非成员函数等价物，因为非成员函数接收指向原子类型的指针，从而在常量表达式中无用。

参阅

is_lock_free | 检查原子对象是否免锁 (公开成员函数)
atomic_is_lock_free (C++11) | 检查对该原子类型的操作是否是无锁的 (函数模板)
is_always_lock_free [静态] (C++17) | 指示该类型是否始终免锁 (公开静态成员常量)


std::atomic<T>::is_lock_free

< cpp‎ | atomic‎ | atomic
 | (C++11 起)
bool is_lock_free() const noexcept;
bool is_lock_free() const volatile noexcept;

检查此类型所有对象上的原子操作是否免锁。

参数

（无）

返回值

若此类型所有对象上的原子操作免锁则为 true ，否则为 false 。

注意

std::atomic_flag 以外的所有原子类型可用互斥或其他锁定操作实现，而不一定用免锁的原子 CPU 指令。亦允许原子类型有时免锁，例如若给定架构上仅对齐的内存访问是天然原子的，则同类型的错误对齐对象必须用锁。

C++ 标准推荐（但不要求）免锁操作亦为免地址，即适用于使用共享内存的进程间交流。

示例

#include <iostream>
#include <utility>
#include <atomic>

struct A { int a[100]; };
struct B { int x, y; };
int main()
{
    std::cout << std::boolalpha
              << "std::atomic<A> is lock free? "
              << std::atomic<A>{}.is_lock_free() << '\n'
              << "std::atomic<B> is lock free? "
              << std::atomic<B>{}.is_lock_free() << '\n';
}

可能的输出：

std::atomic<A> is lock free? false
std::atomic<B> is lock free? true

参阅

atomic_is_lock_free (C++11) | 检查对该原子类型的操作是否是无锁的 (函数模板)
atomic_is_lock_free(std::shared_ptr) | 对 std::shared_ptr 特化原子操作 (函数模板)
is_always_lock_free [静态] (C++17) | 指示该类型是否始终免锁 (公开静态成员常量)


std::atomic<T>::load

< cpp‎ | atomic‎ | atomic
 | (C++11 起)
T load( std::memory_order order = std::memory_order_seq_cst ) const noexcept;
T load( std::memory_order order = std::memory_order_seq_cst ) const volatile noexcept;

原子地加载并返回原子变量的当前值。按照 order 的值影响内存。

order 必须是 std::memory_order_relaxed 、 std::memory_order_consume 、 std::memory_order_acquire 或 std::memory_order_seq_cst 之一。否则行为未定义。

若 std::atomic <T>::is_always_lock_free 为 false 则 volatile 限定版本被弃用。

 (C++20 起)

参数

order - 强制的内存顺序

返回值

原子变量的当前值。

参阅

operator T | 从原子对象加载值 (公开成员函数)
atomic_loadatomic_load_explicit (C++11)(C++11) | 原子地获得存储于原子对象的值 (函数模板)


std::atomic<T>::notify_all

< cpp‎ | atomic‎ | atomic

 | (C++20 起)
void notify_all() noexcept;
void notify_all() volatile noexcept;

进行原子提醒操作

除阻所有被 *this 上的原子等待操作（即 wait() ）阻塞的线程，若有；否则不做任何事。

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

示例

本节未完成
原因：暂无示例

参阅

wait (C++20) | 阻塞线程直至被提醒且原子值更改 (公开成员函数)
atomic_waitatomic_wait_explicit (C++20)(C++20) | 阻塞线程直至被提醒且原子值更改 (函数模板)
atomic_notify_one (C++20) | 提醒一个在 atomic_wait 中阻塞的线程 (函数模板)


std::atomic<T>::notify_one

< cpp‎ | atomic‎ | atomic

 | (C++20 起)
void notify_one() noexcept;
void notify_one() volatile noexcept;

进行原子提醒操作。

若有线程被 *this 上的原子等待操作（即 wait() ）阻塞，则除阻至少一个这种线程；否则不做任何事。

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

示例

本节未完成
原因：暂无示例

参阅

wait (C++20) | 阻塞线程直至被提醒且原子值更改 (公开成员函数)
atomic_waitatomic_wait_explicit (C++20)(C++20) | 阻塞线程直至被提醒且原子值更改 (函数模板)
atomic_notify_one (C++20) | 提醒一个在 atomic_wait 中阻塞的线程 (函数模板)


std::atomic<T>::operator=

< cpp‎ | atomic‎ | atomic
 | (1) | (C++11 起)
T operator=( T desired ) noexcept; |  |  |  |
T operator=( T desired ) volatile noexcept; |  |  | (1) | (C++11 起)
 | (2) | (C++11 起)
atomic& operator=( const atomic& ) = delete; |  |  |  |
atomic& operator=( const atomic& ) volatile = delete; |  |  |  |
1) 原子地赋 desired 给值原子变量。等价于 store(desired) 。若 std::atomic <T>::is_always_lock_free 为 false 则 volatile 限定版本被弃用。 (C++20 起)
2) 原子变量非可复制赋值 (CopyAssignable) 。

参数

desired - 要赋值的值

返回值

desired 。

注解

不同于大多数赋值运算符，原子类型的赋值运算符不返回到其左侧参数的引用。它们会返回存储值的副本。

参阅

(构造函数)
 构造原子对象
(公开成员函数)


std::atomic<T>::operator T()

< cpp‎ | atomic‎ | atomic
 | (C++11 起)
operator T() const noexcept;
operator T() const volatile noexcept;

原子地加载并返回原子变量的当前值。等价于 load() 。

若 std::atomic <T>::is_always_lock_free 为 false 则 volatile 限定版本被弃用。

 (C++20 起)

参数

（无）

返回值

原子变量的当前值。

参阅

load
 原子地获得原子对象的值
(公开成员函数)


std::atomic<T>::operator++,++(int),--,--(int)

< cpp‎ | atomic‎ | atomic
T operator++() noexcept;
T operator++() volatile noexcept;
 (1) (仅为 atomic<Integral> 模板特化的成员)
(C++11 起)
T* operator++() noexcept;
T* operator++() volatile noexcept;
 (1) (仅为 atomic<T*> 模板特化的成员)
(C++11 起)
T operator++( int ) noexcept;
T operator++( int ) volatile noexcept;
 (2) (仅为 atomic<Integral> 模板特化的成员)
(C++11 起)
T* operator++( int ) noexcept;
T* operator++( int ) volatile noexcept;
 (2) (仅为 atomic<T*> 模板特化的成员)
(C++11 起)
T operator--() noexcept;
T operator--() volatile noexcept;
 (3) (仅为 atomic<Integral> 模板特化的成员)
(C++11 起)
T* operator--() noexcept;
T* operator--() volatile noexcept;
 (3) (仅为 atomic<T*> 模板特化的成员)
(C++11 起)
T operator--( int ) noexcept;
T operator--( int ) volatile noexcept;
 (4) (仅为 atomic<Integral> 模板特化的成员)
(C++11 起)
T* operator--( int ) noexcept;
T* operator--( int ) volatile noexcept;
 (4) (仅为 atomic<T*> 模板特化的成员)
(C++11 起)

原子地自增或自减当前值。操作为读-修改-写操作。

1) 进行原子前自增。等价于 fetch_add(1)+1 。
2) 进行原子后自增。等价于 fetch_add(1) 。
3) 进行原子前自减。等价于 fetch_sub(1)-1 。
4) 进行原子后自减。等价于 fetch_sub(1) 。

对于有符号整数类型，算术定义为使用补码表示。无未定义结果。对于 T* 类型，结果可能为未定义地址，但此外这些操作不会有未定义行为。

若 std::atomic <T>::is_always_lock_free 为 false 则 volatile 限定版本被弃用。

 (C++20 起)

参数

（无）

返回值

1,3) 修改后的原子变量的值。正式地说， *this 的修改顺序中自增/自减值的结果立即前趋于此函数的效果。
2,4) 修改前的原子变量的值。正式地说， *this 的修改顺序中值立即前趋于此函数的效果。

注解

不同于大多数前自增和自减运算符，原子类型的前自增和自减运算符不返回被修改对象的引用。它们替而返回存储值的副本。

参阅

fetch_add | 原子地将参数加到存储于原子对象的值，并返回先前保有的值 (公开成员函数)
fetch_sub | 原子地从存储于原子对象的值减去参数，并获得先前保有的值 (公开成员函数)
operator+=operator-=operator&=operator|=operator^= | 加、减，或与原子值进行逐位与、或、异或 (公开成员函数)


std::atomic<T>::operator+=,-=,&=,|=,^=

< cpp‎ | atomic‎ | atomic
仅为 atomic<Integral>(C++11) 与 atomic<Floating>(C++20) 模板特化的成员 |
 | (1)
T operator+=( T arg ) noexcept;
T operator+=( T arg ) volatile noexcept;
仅为 atomic<T*> 模板特化的成员 |
 | (1)
T* operator+=( std::ptrdiff_t arg ) noexcept;
T* operator+=( std::ptrdiff_t arg ) volatile noexcept;
仅为 atomic<Integral>(C++11) 与 atomic<Floating>(C++20) 模板特化的成员 |
 | (2)
T operator-=( T arg ) noexcept;
T operator-=( T arg ) volatile noexcept;
仅为 atomic<T*> 模板特化的成员 |
 | (2)
T* operator-=( std::ptrdiff_t arg ) noexcept;
T* operator-=( std::ptrdiff_t arg ) volatile noexcept;
仅为 atomic<Integral> 模板特化的成员 |
 | (3)
T operator&=( T arg ) noexcept;
T operator&=( T arg ) volatile noexcept;
 | (4)
T operator|=( T arg ) noexcept;
T operator|=( T arg ) volatile noexcept;
 | (5)
T operator^=( T arg ) noexcept;
T operator^=( T arg ) volatile noexcept;

原子地以涉及先前值和 arg 的计算结果替换当前值。操作是读-修改-写操作。

1) 进行原子加法。等价于 fetch_add(arg) + arg 。
2) 进行原子减法。等价于 fetch_sub(arg) - arg 。
3) 进行原子逐位与。等价于 fetch_and(arg) & arg 。
4) 进行原子逐位或。等价于 fetch_or(arg) | arg 。
5) 进行原子逐位异或。等价于 fetch_xor(arg) ^ arg 。

对于有符号整数类型，算术定义为使用补码表示。无未定义结果。

对于 T* 类型，结果可能为未定义地址，但此外操作不会有未定义行为。若 T 不是对象类型则程序为谬构。

对于浮点类型，有影响的浮点环境可能异于调用方线程的浮点环境。操作不必遵循对应的 std::numeric_limits 特性，但鼓励这么做。若结果不是其类型所能表示的值，则结果未指定，但此外操作不会有未定义行为。

若 std::atomic <T>::is_always_lock_free 为 false 则 volatile 限定版本被弃用。

 (C++20 起)

参数

arg - 算术运算的参数

返回值

返回值（即应用对应二元运算符到 *this 的修改顺序中立即前趋于成员对应函数效果的值）

注解

不同于大多数复合赋值运算符，原子类型的复合赋值运算符不返回到其左侧运算数的引用。它们替而返回存储的值的副本。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0558R1 | C++11 | 曾容许指向 cv void 或函数的指针 | 使之为谬构

参阅

operator++operator++(int)operator--operator--(int)
 令原子值增加或减少一
(公开成员函数)


std::atomic<T>::store

< cpp‎ | atomic‎ | atomic
 | (C++11 起)
void store( T desired, std::memory_order order = std::memory_order_seq_cst ) noexcept;
void store( T desired, std::memory_order order = std::memory_order_seq_cst ) volatile noexcept;

原子地以 desired 替换当前值。按照 order 的值影响内存。

order 必须是 std::memory_order_relaxed 、 std::memory_order_release 或 std::memory_order_seq_cst 之一。否则行为未定义。

若 std::atomic <T>::is_always_lock_free 为 false 则 volatile 限定版本被弃用。

 (C++20 起)

参数

desired | - | 存储到原子变量中的值
order | - | 强制的内存顺序

返回值

（无）

参阅

operator= | 存储值于原子对象 (公开成员函数)
atomic_storeatomic_store_explicit (C++11)(C++11) | 原子地以非原子实参替换原子对象的值 (函数模板)


std::atomic<T>::wait

< cpp‎ | atomic‎ | atomic

 | (C++20 起)
void wait( T old, std::memory_order order = std::memory_order::seq_cst ) const noexcept;
void wait( T old, std::memory_order order = std::memory_order::seq_cst ) const volatile noexcept;

进行原子等待操作。表现为如同进行下列步骤：

  • 比较 this->test(order) 的值表示与 old 。
    • 若它们相等，则阻塞直至 *this 被 notify_one() 或 notify_all() 提醒，或线程被虚假地除阻。

这些函数保证仅若值更改才返回，即使底层实现虚假地除阻。

参数

old | - | 要检测 atomic 的对象不再含有的值
order | - | 此操作所用的内存同步顺序：必须不是 std::memory_order::release 或 std::memory_order::acq_rel

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

由于 ABA 问题，可能错失从 old 到另一值再回到 old 的更改，而不除阻。

比较是逐位的（类似 std::memcmp ）；不使用比较运算符。忽略决不参与对象值表示的填充位。

示例

本节未完成
原因：暂无示例

参阅

notify_one (C++20) | 提醒至少一个在原子对象上的等待中阻塞的线程 (公开成员函数)
notify_all (C++20) | 提醒所有在原子对象上的等待中阻塞的线程 (公开成员函数)
atomic_notify_one (C++20) | 提醒一个在 atomic_wait 中阻塞的线程 (函数模板)
atomic_notify_all (C++20) | 提醒所有在 atomic_wait 中阻塞的线程 (函数模板)


std::atomic_compare_exchange_weak, std::atomic_compare_exchange_strong, std::atomic_compare_exchange_weak_explicit, std::atomic_compare_exchange_strong_explicit

< cpp‎ | atomic
定义于头文件 <atomic>
(1) | (C++11 起)
template< class T >

bool atomic_compare_exchange_weak( std::atomic <T>* obj,
typename std::atomic <T>::value_type* expected,

typename std::atomic <T>::value_type desired ) noexcept;
template< class T >

bool atomic_compare_exchange_weak( volatile std::atomic <T>* obj,
typename std::atomic <T>::value_type* expected,

typename std::atomic <T>::value_type desired ) noexcept;
(2) | (C++11 起)
template< class T >

bool atomic_compare_exchange_strong( std::atomic <T>* obj,
typename std::atomic <T>::value_type* expected,

typename std::atomic <T>::value_type desired ) noexcept;
template< class T >

bool atomic_compare_exchange_strong( volatile std::atomic <T>* obj,
typename std::atomic <T>::value_type* expected,

typename std::atomic <T>::value_type desired ) noexcept;
(3) | (C++11 起)
template< class T >

bool atomic_compare_exchange_weak_explicit( std::atomic <T>* obj,
typename std::atomic <T>::value_type* expected,
typename std::atomic <T>::value_type desired,
std::memory_order succ,

std::memory_order fail ) noexcept;
template< class T >

bool atomic_compare_exchange_weak_explicit( volatile std::atomic <T>* obj,
typename std::atomic <T>::value_type* expected,
typename std::atomic <T>::value_type desired,
std::memory_order succ,

std::memory_order fail ) noexcept;
(4) | (C++11 起)
template< class T >

bool atomic_compare_exchange_strong_explicit( std::atomic <T>* obj,
typename std::atomic <T>::value_type* expected,
typename std::atomic <T>::value_type desired,
std::memory_order succ,

std::memory_order fail ) noexcept;
template< class T >

bool atomic_compare_exchange_strong_explicit( volatile std::atomic <T>* obj,
typename std::atomic <T>::value_type* expected,
typename std::atomic <T>::value_type desired,
std::memory_order succ,

std::memory_order fail ) noexcept;

原子地比较 obj 所指向对象与 expected 所指向对象的对象表示 (C++20 前)值表示 (C++20 起)，而若它们逐位相等，则以 desired 替换前者（进行读修改写操作）。否则，将 obj 所指向对象的实际值加载到 *expected （进行加载操作）。复制如同以 std::memcpy 进行。

读-修改-写和加载操作的内存模型各为 succ 和 fail 。 (1-2) 版本默认使用 std::memory_order_seq_cst 。

这些函数用 std::atomic 的成员函数定义：

1) obj->compare_exchange_weak(*expected, desired)
2) obj->compare_exchange_strong(*expected, desired)
3) obj->compare_exchange_weak(*expected, desired, succ, fail)
4) obj->compare_exchange_strong(*expected, desired, succ, fail)

参数

obj | - | 指向要测试和修改的原子对象的指针
expected | - | 指向期待在原子对象中找到的值的指针
desired | - | 若满足期待，则要存储于原子对象的值
succ | - | 若比较成功则用于读-修改-写操作的内存同步顺序。容许所有值。
fail | - | 若比较失败则用于加载操作的内存同步顺序。不能是 std::memory_order_release 或 std::memory_order_acq_rel 且不能指定强于 succ 的顺序 (C++17 前)

返回值

比较结果：若 *obj 等于 *expected 则为 true ，否则 false 。

注意

函数的弱形式（ (1) 与 (3) ）允许虚假地失败，即表现为如同 *obj != *expected ，即使它们相等。当比较并交换在循环中时，弱版本在某些平台上会生成更好的性能。

在弱版本会要求循环而强版本不要求时，更偏好强版本，除非 T 的对象表示可能包含t填充位、 (C++20 前)陷阱位，或者为一个值提供多个对象表示（例如浮点 NaN ）。这些情况下，弱的比较并交换经常有用，因为它在某些稳定对象表示上快速收敛。

若有些位参与 union 某些成员，但非其他成员的值表示，则比较和交换可能始终失败，因为这种填充位在不参与活跃成员的值表示时拥有不确定值。

忽略决不参与对象值表示的填充位。

 (C++20 起)

示例

比较并交换操作常用作无锁数据结构的基础构建块

#include <atomic>

template<class T>
struct node
{
    T data;
    node* next;
    node(const T& data) : data(data), next(nullptr) {}
};

template<class T>
class stack
{
    std::atomic<node<T>*> head;
 public:
    void push(const T& data)
    {
        node<T>* new_node = new node<T>(data);

        // 将 head 的当前值放入 new_node->next
        new_node->next = head.load(std::memory_order_relaxed);

        // 现在令 new_node 为新的 head ，
        // 但若 head 不再是存储于 new_node->next 者
        // （某些其他线程必须已在现在插入结点）
        // 则将新的 head 放入 new_node->next 并重试
        while(!std::atomic_compare_exchange_weak_explicit(
                                &head,
                                &new_node->next,
                                new_node,
                                std::memory_order_release,
                                std::memory_order_relaxed))
                ; // 循环体为空
// 注意：上述循环非线程安全，至少在
// 早于 4.8.3 的 GCC （ bug 60272 ），早于 2014-05-05 的 clang （ bug 18899）
// 早于 2014-03-17 的 MSVC （ bug 819819 ）。变通方法见成员函数版本
    }
};

int main()
{
    stack<int> s;
    s.push(1);
    s.push(2);
    s.push(3);
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0558R1 | C++11 | 曾要求准确类型匹配，因为从多个参数推导 T | 仅从 atomic 参数推导 T

参阅

compare_exchange_weakcompare_exchange_strong | 原子地比较原子对象与非原子参数的值，若相等则进行交换，若不相等则进行加载 (std::atomic<T> 的公开成员函数)
atomic_exchangeatomic_exchange_explicit (C++11)(C++11) | 原子地以非原子实参的值替换原子对象的值，并返回该原子对象的旧值 (函数模板)
std::atomic_compare_exchange_weak(std::shared_ptr) std::atomic_compare_exchange_strong(std::shared_ptr)
(C++20 中弃用)
 为 std::shared_ptr 特化原子操作
(函数模板)


std::atomic_exchange, std::atomic_exchange_explicit

< cpp‎ | atomic
定义于头文件 <atomic>
(1) | (C++11 起)
template< class T >

T atomic_exchange( std::atomic <T>* obj,

typename std::atomic <T>::value_type desr ) noexcept;
template< class T >

T atomic_exchange( volatile std::atomic <T>* obj,

typename std::atomic <T>::value_type desr ) noexcept;
(2) | (C++11 起)
template< class T >

T atomic_exchange_explicit( std::atomic <T>* obj,
typename std::atomic <T>::value_type desr,

std::memory_order order ) noexcept;
template< class T >

T atomic_exchange_explicit( volatile std::atomic <T>* obj,
typename std::atomic <T>::value_type desr,

std::memory_order order ) noexcept;
1) 原子地以 desr 的值替换 obj 所指向的值，并返回 obj 先前保有的值，如同以 obj->exchange(desr) 。
2) 原子地以 desr 的值替换 obj 所指向的值，并返回 obj 先前保有的值，如同以 obj->exchange(desr, order) 。

参数

obj | - | 指向要修改的原子对象的指针
desr | - | 要存储于原子对象的值
order | - | 此操作所用的内存同步顺序：容许所有值。

返回值

obj 所指向的原子对象先前保有的值。

示例

能以原子替换操作在用户空间实现自旋锁互斥，类似 std::atomic_flag_test_and_set ：

#include <thread>
#include <vector>
#include <iostream>
#include <atomic>

std::atomic<bool> lock(false); // 锁定时保有 true
                               // 解锁时保有 false

void f(int n)
{
    for (int cnt = 0; cnt < 100; ++cnt) {
        while(std::atomic_exchange_explicit(&lock, true, std::memory_order_acquire))
             ; // 自旋直至获得
        std::cout << "Output from thread " << n << '\n';
        std::atomic_store_explicit(&lock, false, std::memory_order_release);
    }
}
int main()
{
    std::vector<std::thread> v;
    for (int n = 0; n < 10; ++n) {
        v.emplace_back(f, n);
    }
    for (auto& t : v) {
        t.join();
    }
}

输出：

Output from thread 2
Output from thread 6
Output from thread 7
...< 准确 1000 行 >...

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0558R1 | C++11 | 曾要求准确类型匹配，因为从多个参数推导 T | 仅从 atomic 参数推导 T

参阅

exchange | 原子地替换原子对象的值并获得它先前持有的值 (std::atomic<T> 的公开成员函数)
atomic_compare_exchange_weakatomic_compare_exchange_weak_explicitatomic_compare_exchange_strongatomic_compare_exchange_strong_explicit (C++11)(C++11)(C++11)(C++11) | 原子地比较原子对象和非原子实参的值，若相等则进行 atomic_exchange，若不相等则进行 atomic_load (函数模板)
std::atomic_exchange(std::shared_ptr) std::atomic_exchange_explicit(std::shared_ptr)
(C++20 中弃用)
 为 std::shared_ptr 特化原子运算
(函数模板)


std::atomic_fetch_add, std::atomic_fetch_add_explicit

< cpp‎ | atomic
定义于头文件 <atomic>
(1)
template< class T >

T atomic_fetch_add( std::atomic <T>* obj,

typename std::atomic <T>::difference_type arg ) noexcept;
template< class T >

T atomic_fetch_add( volatile std::atomic <T>* obj,

typename std::atomic <T>::difference_type arg ) noexcept;
(2)
template< class T >

T atomic_fetch_add_explicit( std::atomic <T>* obj,
typename std::atomic <T>::difference_type arg,

std::memory_order order ) noexcept;
template< class T >

T atomic_fetch_add_explicit( volatile std::atomic <T>* obj,
typename std::atomic <T>::difference_type arg,

std::memory_order order ) noexcept;

进行原子加法。

原子地加 arg 到 obj 所指向的值，并返回 obj 先前保有的值。如同执行下列内容一般进行运算：

1) obj->fetch_add(arg)
2) obj->fetch_add(arg, order)

参数

obj | - | 指向要修改的原子对象的指针
arg | - | 要加到存储于原子对象的值的值
order | - | 此操作所用的内存同步顺序：容许所有值。

返回值

*obj 的修改顺序中，立即前趋此函数效应的值。

可能的实现

template< class T >
T atomic_fetch_add( std::atomic<T>* obj, typename std::atomic<T>::difference_type arg )
{
    return obj->fetch_add(arg);
}

示例

单写者/多读者锁能用 fetch_add 制作。注意此过分简化的实现不是免锁的。

#include <string>
#include <thread>
#include <vector>
#include <iostream>
#include <atomic>
#include <chrono>

// cnt 的含义：
// 10 ：无活跃读者或写者
// 1...9 ：有 9...1 个读者活跃。写者被阻塞
// 0 ： fetch_sub 和 fetch_add 间的临时值在读者锁中
// -1 ：有活跃写者。读者被阻塞。
const int N = 10; // 允许九个共时读者
std::atomic<int> cnt = ATOMIC_VAR_INIT(N);

std::vector<int> data;

void reader(int id)
{
    for(;;)
    {
        // 锁定
        while(std::atomic_fetch_sub(&cnt, 1) <= 0)
            std::atomic_fetch_add(&cnt, 1);
        // 读取
        if(!data.empty())
            std::cout << (  "reader " + std::to_string(id)
                          + " sees " + std::to_string(*data.rbegin()) + '\n');
        if(data.size() == 100)
            break;
        // 解锁
        std::atomic_fetch_add(&cnt, 1);
        // 暂停
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
}

void writer()
{
    for(int n = 0; n < 100; ++n)
    {
        // 锁定
        while(std::atomic_fetch_sub(&cnt, N+1) != N)
            std::atomic_fetch_add(&cnt, N+1);
        // 写入
        data.push_back(n);
        std::cout << "writer pushed back " << n << '\n';
        // 解锁
        std::atomic_fetch_add(&cnt, N+1);
        // 暂停
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
}

int main()
{
    std::vector<std::thread> v;
    for (int n = 0; n < N; ++n) {
        v.emplace_back(reader, n);
    }
    v.emplace_back(writer);
    for (auto& t : v) {
        t.join();
    }
}

输出：

writer pushed back 0
reader 8 sees 0
reader 3 sees 0
reader 1 sees 0
<...>
reader 2 sees 99
reader 6 sees 99
reader 1 sees 99

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0558R1 | C++11 | 曾要求准确类型匹配，因为从多个参数推导 T | 仅从 atomic 参数推导 T

参阅

fetch_add | 原子地将参数加到存储于原子对象的值，并返回先前保有的值 (std::atomic<T> 的公开成员函数)
atomic_fetch_subatomic_fetch_sub_explicit (C++11)(C++11) | 从原子对象减去非原子值，并获得原子对象的先前值 (函数模板)


std::atomic_fetch_and, std::atomic_fetch_and_explicit

< cpp‎ | atomic
定义于头文件 <atomic>
(1) | (C++11 起)
template< class T >

T atomic_fetch_and( std::atomic <T>* obj,

typename std::atomic <T>::value_type arg ) noexcept;
template< class T >

T atomic_fetch_and( volatile std::atomic <T>* obj,

typename std::atomic <T>::value_type arg ) noexcept;
(2) | (C++11 起)
template< class T >

T atomic_fetch_and_explicit( std::atomic <T>* obj,
typename std::atomic <T>::value_type arg,

std::memory_order order) noexcept;
template< class T >

T atomic_fetch_and_explicit( volatile std::atomic <T>* obj,
typename std::atomic <T>::value_type arg,

std::memory_order order) noexcept;

原子地以 obj 的旧值和 arg 的逐位与替换 obj 所指向的值。返回 obj 先前保有的值。

如同执行下列内容一般进行操作：

1) obj->fetch_and(arg)
2) obj->fetch_and(arg, order)

若 std::atomic<T> 无 fetch_and 成员（此成员仅对整数类型提供），则程序为病式。

参数

obj | - | 指向要修改的对象的指针。为了原子操作的目的， bool 不是整数 (Integral) 类型。
arg | - | 与存储于原子对象的值逐位与的值
order | - | 此操作所用的内存同步顺序：容许所有值。

返回值

*obj 的修改顺序中立即前趋此函数效果的值。

可能的实现

template< class T >
T atomic_fetch_and(std::atomic<T>* obj, typename std::atomic<T>::value_type arg ) noexcept
{
    return obj->fetch_and(arg);
}

示例

#include <iostream>
#include <atomic>
#include <thread>
#include <chrono>
#include <functional>

// 仅为演示目的的二元信号量
// 此乃简单却有意义的示例：若无线程则原子操作为不必要。
class Semaphore {
    std::atomic_char m_signaled;
  public:
    Semaphore(bool initial = false)
    {
        m_signaled = initial;
    }
    // 阻塞直至信号量被发信
    void take()
    {
        while (!std::atomic_fetch_and(&m_signaled, false)) {
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }

    void put()
    {
        std::atomic_fetch_or(&m_signaled, true);
    }
};

class ThreadedCounter {
    static const int N = 100;
    static const int REPORT_INTERVAL = 10;
    int m_count;
    bool m_done;
    Semaphore m_count_sem;
    Semaphore m_print_sem;

    void count_up()
    {
        for (m_count = 1; m_count <= N; m_count++) {
            if (m_count % REPORT_INTERVAL == 0) {
                if (m_count == N) m_done = true;
                m_print_sem.put(); // 对打印发信，使之发生
                m_count_sem.take(); // 等待直至打印完成进展
            }
        }
        std::cout << "count_up() done\n";
        m_done = true;
        m_print_sem.put();
    }

    void print_count()
    {
        do {
            m_print_sem.take();
            std::cout << m_count << '\n';
            m_count_sem.put();
        } while (!m_done);
        std::cout << "print_count() done\n";
    }

  public:
    ThreadedCounter() : m_done(false) {}
    void run()
    {
        auto print_thread = std::thread(&ThreadedCounter::print_count, this);
        auto count_thread = std::thread(&ThreadedCounter::count_up, this);
        print_thread.join();
        count_thread.join();
    }
};

int main()
{
    ThreadedCounter m_counter;
    m_counter.run();
}

输出：

10
20
30
40
50
60
70
80
90
100
print_count() done
count_up() done

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0558R1 | C++11 | 曾要求准确类型匹配，因为从多个参数推导 T | 仅从 atomic 参数推导 T

参阅

fetch_and | 原子地进行参数和原子对象的值的逐位与，并获得先前保有的值 (std::atomic<T> 的公开成员函数)
atomic_fetch_oratomic_fetch_or_explicit (C++11)(C++11) | 将原子对象替换为与非原子实参逻辑或的结果，并获得原子对象的先前值 (函数模板)
atomic_fetch_xoratomic_fetch_xor_explicit (C++11)(C++11) | 将原子对象替换为与非原子实参逻辑异或的结果，并获得原子对象的先前值 (函数模板)


std::atomic_fetch_or, std::atomic_fetch_or_explicit

< cpp‎ | atomic
定义于头文件 <atomic>
(1) | (C++11 起)
template< class T >

T atomic_fetch_or( std::atomic <T>* obj,

typename std::atomic <T>::value_type arg ) noexcept;
template< class T >

T atomic_fetch_or( volatile std::atomic <T>* obj,

typename std::atomic <T>::value_type arg ) noexcept;
(2) | (C++11 起)
template< class T >

T atomic_fetch_or_explicit( std::atomic <T>* obj,
typename std::atomic <T>::value_type arg,

std::memory_order order) noexcept;
template< class T >

T atomic_fetch_or_explicit( volatile std::atomic <T>* obj,
typename std::atomic <T>::value_type arg,

std::memory_order order) noexcept;

原子地以 obj 的旧值和 arg 逐位或的结果替换 obj 所指向的值。返回 obj 先前保有的值。

如同执行下列内容一般进行运算：

1) obj->fetch_or(arg)
2) obj->fetch_or(arg, order)

若 std::atomic<T> 无 fetch_or 成员（此成员仅对整数类型提供），则程序为病式。

参数

obj | - | 指向要修改的原子对象的指针
arg | - | 要与原子对象中的值逐位或的值
order | - | 此操作所用的内存同步顺序：容许所有值。

返回值

*obj 的修改顺序中立即前趋此函数效果的值。

可能的实现

template< class T >
T atomic_fetch_or( std::atomic<T>* obj, typename std::atomic<T>::value_type  arg )
{
    return obj->fetch_or(arg);
}

示例

#include <iostream>
#include <atomic>
#include <thread>
#include <chrono>
#include <functional>

// 仅为演示目的的二元信号量
// 此乃简单却有意义的示例：若无线程则原子操作为不必要。
class Semaphore {
    std::atomic_char m_signaled;
  public:
    Semaphore(bool initial = false)
    {
        m_signaled = initial;
    }
    // 阻塞直至信号量被发信
    void take()
    {
        while (!std::atomic_fetch_and(&m_signaled, false)) {
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }

    void put()
    {
        std::atomic_fetch_or(&m_signaled, true);
    }
};

class ThreadedCounter {
    static const int N = 100;
    static const int REPORT_INTERVAL = 10;
    int m_count;
    bool m_done;
    Semaphore m_count_sem;
    Semaphore m_print_sem;

    void count_up()
    {
        for (m_count = 1; m_count <= N; m_count++) {
            if (m_count % REPORT_INTERVAL == 0) {
                if (m_count == N) m_done = true;
                m_print_sem.put(); // 对打印发信，使之发生
                m_count_sem.take(); // 等待直至打印完成进展
            }
        }
        std::cout << "count_up() done\n";
        m_done = true;
        m_print_sem.put();
    }

    void print_count()
    {
        do {
            m_print_sem.take();
            std::cout << m_count << '\n';
            m_count_sem.put();
        } while (!m_done);
        std::cout << "print_count() done\n";
    }

  public:
    ThreadedCounter() : m_done(false) {}
    void run()
    {
        auto print_thread = std::thread(&ThreadedCounter::print_count, this);
        auto count_thread = std::thread(&ThreadedCounter::count_up, this);
        print_thread.join();
        count_thread.join();
    }
};

int main()
{
    ThreadedCounter m_counter;
    m_counter.run();
}

输出：

10
20
30
40
50
60
70
80
90
100
print_count() done
count_up() done

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0558R1 | C++11 | 曾要求准确类型匹配，因为从多个参数推导 T | 仅从 atomic 参数推导 T

参阅

fetch_or | 原子地进行参数和原子对象的值的逐位或，并获得先前保有的值 (std::atomic<T> 的公开成员函数)
atomic_fetch_andatomic_fetch_and_explicit (C++11)(C++11) | 将原子对象替换为与非原子实参逻辑与的结果，并获得原子对象的先前值 (函数模板)
atomic_fetch_xoratomic_fetch_xor_explicit (C++11)(C++11) | 将原子对象替换为与非原子实参逻辑异或的结果，并获得原子对象的先前值 (函数模板)


std::atomic_fetch_sub, std::atomic_fetch_sub_explicit

< cpp‎ | atomic
定义于头文件 <atomic>
(1)
template< class T >

T atomic_fetch_sub( std::atomic <T>* obj,

typename std::atomic <T>::difference_type arg ) noexcept;
template< class T >

T atomic_fetch_sub( volatile std::atomic <T>* obj,

typename std::atomic <T>::difference_type arg ) noexcept;
(2)
template< class T >

T atomic_fetch_sub_explicit( std::atomic <T>* obj,
typename std::atomic <T>::difference_type arg,

std::memory_order order ) noexcept;
template< class T >

T atomic_fetch_sub_explicit( volatile std::atomic <T>* obj,
typename std::atomic <T>::difference_type arg,

std::memory_order order ) noexcept;

进行原子减法。

原子地从 obj 所指向的值减去 arg ，并返回 obj 先前保有的值。如同执行下列内容一样进行运算：

1) obj->fetch_sub(arg)
2) obj->fetch_sub(arg, order)

参数

obj | - | 指向要修改的原子对象的指针
arg | - | 要从存储于原子对象的值减去的值
order | - | 此操作所用的内存同步顺序：容许所有值。

返回值

*obj 的修改顺序中立即前趋此函数效果的值。

可能的实现

template< class T >
T atomic_fetch_sub( std::atomic<T>* obj,
                    typename std::atomic<T>::difference_type arg ) noexcept
{
    return obj->fetch_sub(arg);
}

示例

多个线程可用 fetch_sub 同时处理有下标的容器

#include <string>
#include <thread>
#include <vector>
#include <iostream>
#include <atomic>
#include <numeric>

const int N = 10000;
std::atomic<int> cnt;
std::vector<int> data(N);

void reader(int id)
{
    for (;;) {
        int idx = atomic_fetch_sub_explicit(&cnt, 1, std::memory_order_relaxed);
        if (idx >= 0) {
            std::cout << "reader " << std::to_string(id) << " processed item "
                      << std::to_string(data[idx]) << '\n';
        } else {
            std::cout << "reader " << std::to_string(id) << " done\n";
            break;
        }
    }
}

int main()
{
    std::iota(data.begin(), data.end(), 1);
    cnt = data.size() - 1;

    std::vector<std::thread> v;
    for (int n = 0; n < 10; ++n) {
        v.emplace_back(reader, n);
    }
    for (auto& t : v) {
        t.join();
    }
}

输出：

reader 2 processed item 10000
reader 6 processed item 9994
reader 4 processed item 9996
reader 6 processed item 9992
<....>
reader 0 done
reader 5 done
reader 3 done
reader 9 done

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0558R1 | C++11 | 曾要求准确类型匹配，因为从多个参数推导 T | 仅从 atomic 参数推导 T

参阅

fetch_sub | 原子地从存储于原子对象的值减去参数，并获得先前保有的值 (std::atomic<T> 的公开成员函数)
atomic_fetch_addatomic_fetch_add_explicit (C++11)(C++11) | 将非原子值加到原子对象，并获得原子对象的先前值 (函数模板)


std::atomic_fetch_xor, std::atomic_fetch_xor_explicit

< cpp‎ | atomic
定义于头文件 <atomic>
(1) | (C++11 起)
template< class T >

T atomic_fetch_xor( std::atomic <T>* obj,

typename std::atomic <T>::value_type arg ) noexcept;
template< class T >

T atomic_fetch_xor( volatile std::atomic <T>* obj,

typename std::atomic <T>::value_type arg ) noexcept;
(2) | (C++11 起)
template< class T >

T atomic_fetch_xor_explicit( std::atomic <T>* obj,
typename std::atomic <T>::value_type arg,

std::memory_order order) noexcept;
template< class T >

T atomic_fetch_xor_explicit( volatile std::atomic <T>* obj,
typename std::atomic <T>::value_type arg,

std::memory_order order) noexcept;

原子地以 obj 的旧值和 arg 的逐位异或结果替换 obj 所指向的值。返回 obj 先前保有的值。

如同执行下列内容一般进行运算：

1) obj->fetch_xor(arg)
2) obj->fetch_xor(arg, order)

若 std::atomic<T> 无 fetch_xor 成员（此成员仅对整数类型提供），则程序为病式。

参数

obj | - | 指向要修改的原子对象的指针
arg | - | 要和存储于原子对象的值逐位异或的值
order | - | 此操作所用的内存同步书顺序：容许所有值。

返回值

*obj 的修改顺序中立即前趋此函数效果的值。

可能的实现

template< class T >
T atomic_fetch_xor( std::atomic<T>* obj, typename std::atomic<T>::value_type arg )
{
    return obj->fetch_xor(arg);
}

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0558R1 | C++11 | 曾要求准确类型匹配，因为从多个参数推导 T | 仅从 atomic 参数推导 T

参阅

fetch_xor | 原子地进行参数和原子对象的值的逐位异或，并获得先前保有的值 (std::atomic<T> 的公开成员函数)
atomic_fetch_oratomic_fetch_or_explicit (C++11)(C++11) | 将原子对象替换为与非原子实参逻辑或的结果，并获得原子对象的先前值 (函数模板)
atomic_fetch_andatomic_fetch_and_explicit (C++11)(C++11) | 将原子对象替换为与非原子实参逻辑与的结果，并获得原子对象的先前值 (函数模板)


std::atomic_flag

< cpp‎ | atomic
定义于头文件 <atomic> |
class atomic_flag; | (C++11 起)

std::atomic_flag 是原子布尔类型。不同于所有 std::atomic 的特化，它保证是免锁的。不同于 std::atomic <bool> ， std::atomic_flag 不提供加载或存储操作。

成员函数

(构造函数) | 构造 atomic_flag (公开成员函数)
operator= | 赋值运算符 (公开成员函数)
clear | 原子地设置标志为 false (公开成员函数)
test_and_set | 原子地设置标志为 true 并获得其先前值 (公开成员函数)
test (C++20) | 原子地返回标志的值 (公开成员函数)
wait (C++20) | 阻塞线程直至被提醒且原子值更改 (公开成员函数)
notify_one (C++20) | 提醒至少一个在原子对象上的等待中阻塞的线程 (公开成员函数)
notify_all (C++20) | 提醒所有在原子对象上的等待中阻塞的线程 (公开成员函数)

示例

可于用户空间用 atomic_flag 实现自旋互斥

#include <thread>
#include <vector>
#include <iostream>
#include <atomic>

std::atomic_flag lock = ATOMIC_FLAG_INIT;

void f(int n)
{
    for (int cnt = 0; cnt < 100; ++cnt) {
        while (lock.test_and_set(std::memory_order_acquire))  // 获得锁
             ; // 自旋
        std::cout << "Output from thread " << n << '\n';
        lock.clear(std::memory_order_release);               // 释放锁
    }
}

int main()
{
    std::vector<std::thread> v;
    for (int n = 0; n < 10; ++n) {
        v.emplace_back(f, n);
    }
    for (auto& t : v) {
        t.join();
    }
}

输出：

Output from thread 2
Output from thread 6
Output from thread 7
...<exactly 1000 lines>...

参阅

atomic_flag_test_and_setatomic_flag_test_and_set_explicit (C++11)(C++11) | 原子地设置标志为 true 并返回其先前值 (函数)
atomic_flag_clearatomic_flag_clear_explicit (C++11)(C++11) | 原子地设置标志值为 false (函数)
atomic_flag_waitatomic_flag_wait_explicit (C++20)(C++20) | 阻塞线程，直至被提醒且标志更改 (函数)
atomic_flag_notify_one (C++20) | 提醒一个在 atomic_flag_wait 中阻塞的线程 (函数)
atomic_flag_notify_all (C++20) | 提醒所有在 atomic_flag_wait 中阻塞的线程 (函数)


std::atomic_flag::atomic_flag

< cpp‎ | atomic‎ | atomic flag
定义于头文件 <atomic> |  |
 | (1) |
atomic_flag() noexcept = default; |  |  | (C++11 起) (C++20 前)
constexpr atomic_flag() noexcept; |  |  | (C++20 起)
atomic_flag( const atomic_flag& ) = delete; | (2) | (C++11 起)

构造新的 std::atomic_flag 。

1) 平凡默认构造函数，初始化 std::atomic_flag 为未指定状态。 | (C++20 前)
1) 初始化 std::atomic_flag 为清除状态。 | (C++20 起)
2) 复制构造函数被删除； std::atomic_flag 不可复制。

另外， std::atomic_flag 能以表达式 ATOMIC_FLAG_INIT 值初始化。对于拥有静态存储期的 atomic_flag ，这保证静态初始化：标志能用于静态对象的构造函数中。此宏不再有必要且被弃用。 (C++20 起)

参阅

ATOMIC_FLAG_INIT
(C++11)(C++20 中弃用)
 将 std::atomic_flag 初始化为 false
(宏常量)


std::atomic_flag::clear

< cpp‎ | atomic‎ | atomic flag
定义于头文件 <atomic> |  |
void clear( std::memory_order order = std::memory_order_seq_cst ) volatile noexcept; | (1) | (C++11 起)
void clear( std::memory_order order = std::memory_order_seq_cst ) noexcept; | (2) | (C++11 起)

原子地更改 std::atomic_flag 的状态为清除（ false ）。

参数

order - 此操作的内存同步顺序（不能为 std::memory_order_consume 、 std::memory_order_acquire 或 std::memory_order_acq_rel ）

参阅

test_and_set | 原子地设置标志为 true 并获得其先前值 (公开成员函数)
atomic_flag_clearatomic_flag_clear_explicit (C++11)(C++11) | 原子地设置标志值为 false (函数)
memory_order (C++11) | 为给定的原子操作定义内存顺序约束 (枚举)


std::atomic_flag::notify_all

< cpp‎ | atomic‎ | atomic flag

 | (C++20 起)
void notify_all() noexcept;
void notify_all() volatile noexcept;

进行原子提醒操作

除阻所有被 *this 上的原子等待操作（即 wait() ）阻塞的线程，若有；否则不做任何事。

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

示例

本节未完成
原因：暂无示例

参阅

wait (C++20) | 阻塞线程直至被提醒且原子值更改 (公开成员函数)
atomic_flag_waitatomic_flag_wait_explicit (C++20)(C++20) | 阻塞线程，直至被提醒且标志更改 (函数)
atomic_flag_notify_one (C++20) | 提醒一个在 atomic_flag_wait 中阻塞的线程 (函数)


std::atomic_flag::notify_one

< cpp‎ | atomic‎ | atomic flag

 | (C++20 起)
void notify_one() noexcept;
void notify_one() volatile noexcept;

进行原子提醒操作。

若有线程被 *this 上的原子等待操作（即 wait() ）阻塞，则除阻至少一个这种线程；否则不做任何事。

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

示例

本节未完成
原因：暂无示例

参阅

wait (C++20) | 阻塞线程直至被提醒且原子值更改 (公开成员函数)
atomic_flag_waitatomic_flag_wait_explicit (C++20)(C++20) | 阻塞线程，直至被提醒且标志更改 (函数)
atomic_flag_notify_one (C++20) | 提醒一个在 atomic_flag_wait 中阻塞的线程 (函数)


std::atomic_flag::operator=

< cpp‎ | atomic‎ | atomic flag
定义于头文件 <atomic> |  |
atomic_flag& operator=( const atomic_flag& ) = delete; | (1) | (C++11 起)
atomic_flag& operator=( const atomic_flag& ) volatile = delete; | (2) | (C++11 起)

std::atomic_flag 不可赋值，其赋值运算符被删除。


std::atomic_flag::test

< cpp‎ | atomic‎ | atomic flag
 | (C++20 起)
bool test( std::memory_order order = std::memory_order::seq_cst ) const volatile noexcept;
bool test( std::memory_order order = std::memory_order::seq_cst ) const noexcept;

原子地读取 *this 的值并返回该值。

参数

order - 此操作使用的内存同步顺序：必须不为 std::memory_order::release 或 std::memory_order::acq_rel

示例

本节未完成
原因：暂无示例

参阅

atomic_flag_testatomic_flag_test_explicit
(C++20)(C++20)
 原子地返回标志的值
(函数)


std::atomic_flag::test_and_set

< cpp‎ | atomic‎ | atomic flag
定义于头文件 <atomic> |  |
bool test_and_set( std::memory_order order = std::memory_order_seq_cst ) volatile noexcept; | (1) | (C++11 起)
bool test_and_set( std::memory_order order = std::memory_order_seq_cst ) noexcept; | (2) | (C++11 起)

原子地更改 std::atomic_flag 的状态为设置（ true ）并返回它先前保有的值。

参数

order - 此操作的内存同步顺序

参阅

clear | 原子地设置标志为 false (公开成员函数)
atomic_flag_test_and_setatomic_flag_test_and_set_explicit (C++11)(C++11) | 原子地设置标志为 true 并返回其先前值 (函数)
memory_order (C++11) | 为给定的原子操作定义内存顺序约束 (枚举)


std::atomic_flag::wait

< cpp‎ | atomic‎ | atomic flag

 | (C++20 起)
void wait( bool old, std::memory_order order = std::memory_order::seq_cst ) const noexcept;
void wait( bool old, std::memory_order order = std::memory_order::seq_cst ) const volatile noexcept;

进行原子等待操作。表现为如同进行下列步骤：

  • 比较 this->test(order) 与 old 。
    • 若它们相等，则阻塞直至 *this 被 notify_one() 或 notify_all() 提醒，或线程被虚假地除阻。

这些函数保证仅若值更改才返回，即使底层实现虚假地除阻。

参数

old | - | 要检测 atomic_flag 的对象不再含有的值
order | - | 此操作所用的内存同步顺序：必须不是 std::memory_order::release 或 std::memory_order::acq_rel

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

由于 ABA 问题，可能错失从 old 到另一值再回到 old 的更改，而不除阻。

示例

本节未完成
原因：暂无示例

参阅

notify_one (C++20) | 提醒至少一个在原子对象上的等待中阻塞的线程 (公开成员函数)
notify_all (C++20) | 提醒所有在原子对象上的等待中阻塞的线程 (公开成员函数)
atomic_flag_notify_one (C++20) | 提醒一个在 atomic_flag_wait 中阻塞的线程 (函数)
atomic_flag_notify_all (C++20) | 提醒所有在 atomic_flag_wait 中阻塞的线程 (函数)


std::atomic_flag_clear, std::atomic_flag_clear_explicit

< cpp‎ | atomic
定义于头文件 <atomic>
(1) | (C++11 起)
void atomic_flag_clear( volatile std::atomic_flag * p ) noexcept;
void atomic_flag_clear( std::atomic_flag * p ) noexcept;
(2) | (C++11 起)
void atomic_flag_clear_explicit( volatile std::atomic_flag * p,
std::memory_order order ) noexcept;
void atomic_flag_clear_explicit( std::atomic_flag * p,
std::memory_order order ) noexcept;

原子地更改 p 所指向的 std::atomic_flag 为清除（ false ）。

参数

p | - | 指向要访问的 std::atomic_flag 的指针
order | - | 此操作所用的内存同步顺序，只容许 std::memory_order_relaxed 、 std::memory_order_release 或 std::memory_order_seq_cst 。

返回值

无。

可能的实现

版本一
void atomic_flag_clear(volatile std::atomic_flag* p)
{
    p->clear();
}
版本二
void atomic_flag_clear(std::atomic_flag* p)
{
    p->clear();
}
版本三
void atomic_flag_clear_explicit(volatile std::atomic_flag* p,
                                std::memory_order order)
{
    p->clear(order);
}
版本四
void atomic_flag_clear_explicit(std::atomic_flag* p,
                                std::memory_order order)
{
    p->clear(order);
}

参阅

atomic_flag (C++11) | 免锁的布尔原子类型 (类)
atomic_flag_test_and_setatomic_flag_test_and_set_explicit (C++11)(C++11) | 原子地设置标志为 true 并返回其先前值 (函数)
memory_order (C++11) | 为给定的原子操作定义内存顺序约束 (枚举)


std::atomic_flag_notify_all

< cpp‎ | atomic
定义于头文件 <atomic> |
 | (C++20 起)
template< class T > void atomic_flag_notify_all( std::atomic_flag <T>* object ) noexcept;
template< class T > void atomic_flag_notify_all( volatile std::atomic_flag <T>* object ) noexcept;

进行原子提醒操作。

除阻所有被 上的原子等待操作（即 std::atomic_flag_wait() 、 std::atomic_flag_wait_explicit() 或 std::atomic_flag::wait() ）阻塞的线程，若有；否则不做任何事。

等价于 object->notify_all() 。

参数

object - 指向待提醒的 atomic_flag 对象的指针

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

示例

本节未完成
原因：暂无示例

参阅

notify_one (C++20) | 提醒至少一个在原子对象上的等待中阻塞的线程 (std::atomic_flag 的公开成员函数)
notify_all (C++20) | 提醒所有在原子对象上的等待中阻塞的线程 (std::atomic_flag 的公开成员函数)
atomic_flag_waitatomic_flag_wait_explicit (C++20)(C++20) | 阻塞线程，直至被提醒且标志更改 (函数)
atomic_flag_notify_one (C++20) | 提醒一个在 atomic_flag_wait 中阻塞的线程 (函数)


std::atomic_flag_notify_one

< cpp‎ | atomic
定义于头文件 <atomic> |
 | (C++20 起)
template< class T > void atomic_flag_notify_one( std::atomic_flag <T>* object ) noexcept;
template< class T > void atomic_flag_notify_one( volatile std::atomic_flag <T>* object ) noexcept;

进行原子提醒操作。

若有线程被 *object 上的原子等待操作（即 std::atomic_flag_wait() 、 std::atomic_flag_wait_explicit() 或 std::atomic_flag::wait() ）阻塞，则除阻至少一个这种线程；否则不做任何事。

等价于 object->notify_one() 。

参数

object - 指向待提醒的 atomic_flag 对象的指针

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

示例

本节未完成
原因：暂无示例

参阅

notify_one (C++20) | 提醒至少一个在原子对象上的等待中阻塞的线程 (std::atomic_flag 的公开成员函数)
notify_all (C++20) | 提醒所有在原子对象上的等待中阻塞的线程 (std::atomic_flag 的公开成员函数)
atomic_flag_notify_all (C++20) | 提醒所有在 atomic_flag_wait 中阻塞的线程 (函数)


std::atomic_flag_test, std::atomic_flag_test_explicit

< cpp‎ | atomic
定义于头文件 <atomic>
(1) | (C++20 起)
bool atomic_flag_test( const volatile std::atomic_flag * object ) noexcept;
bool atomic_flag_test( const std::atomic_flag * object ) noexcept;
(2) | (C++20 起)
bool atomic_flag_test_explicit( const volatile std::atomic_flag * object,
std::memory_order order ) noexcept;
bool atomic_flag_test_explicit( const std::atomic_flag * object,
std::memory_order order ) noexcept;

原子地读取 *object 的值并返回该值。

1) 等价于 object->test( std::memory_order_seq_cst ) 。
2) 等价于 object->test(order) 。

参数

object | - | 指向要读取的 atomic_flag 对象的指针
order | - | 此操作使用的内存同步顺序：必须不为 std::memory_order::release 或 std::memory_order::acq_rel

返回值

原子地读取的值。

示例

本节未完成
原因：暂无示例

参阅

test
(C++20)
 原子地返回标志的值
(std::atomic_flag 的公开成员函数)


std::atomic_flag_test_and_set, std::atomic_flag_test_and_set_explicit

< cpp‎ | atomic
定义于头文件 <atomic>
(1) | (C++11 起)
bool atomic_flag_test_and_set( volatile std::atomic_flag * p ) noexcept;
bool atomic_flag_test_and_set( std::atomic_flag * p ) noexcept;
(2) | (C++11 起)
bool atomic_flag_test_and_set_explicit( volatile std::atomic_flag * p,
std::memory_order order ) noexcept;
bool atomic_flag_test_and_set_explicit( std::atomic_flag * p,
std::memory_order order ) noexcept;

原子地更改 p 所指向的 std::atomic_flag 的状态为设置（ true ），并返回其先前所保有的值。

参数

p | - | 指向要访问的 std::atomic_flag 的指针
order | - | 此操作所用的内存同步顺序

返回值

p 所指向的标志先前保有的值

可能的实现

版本一
bool atomic_flag_test_and_set(volatile std::atomic_flag* p)
{
    return p->test_and_set();
}
版本二
bool atomic_flag_test_and_set(std::atomic_flag* p)
{
    return p->test_and_set();
}
版本三
bool atomic_flag_test_and_set_explicit(volatile std::atomic_flag* p,
                                       std::memory_order order)
{
    return p->test_and_set(order);
}
版本四
bool atomic_flag_test_and_set_explicit(std::atomic_flag* p,
                                       std::memory_order order)
{
    return p->test_and_set(order);
}

示例

能用 atomic_flag 在用户空间实现自旋锁互斥

#include <thread>
#include <vector>
#include <iostream>
#include <atomic>

std::atomic_flag lock = ATOMIC_FLAG_INIT;

void f(int n)
{
    for (int cnt = 0; cnt < 100; ++cnt) {
        while(std::atomic_flag_test_and_set_explicit(&lock, std::memory_order_acquire))
             ; // 自旋直至获得锁
        std::cout << "Output from thread " << n << '\n';
        std::atomic_flag_clear_explicit(&lock, std::memory_order_release);
    }
}

int main()
{
    std::vector<std::thread> v;
    for (int n = 0; n < 10; ++n) {
        v.emplace_back(f, n);
    }
    for (auto& t : v) {
        t.join();
    }
}

输出：

Output from thread 2
Output from thread 6
Output from thread 7
...< 准确 1000 行 >...

参阅

atomic_flag (C++11) | 免锁的布尔原子类型 (类)
atomic_flag_clearatomic_flag_clear_explicit (C++11)(C++11) | 原子地设置标志值为 false (函数)
memory_order (C++11) | 为给定的原子操作定义内存顺序约束 (枚举)


std::atomic_flag_wait, std::atomic_flag_wait_explicit

< cpp‎ | atomic
定义于头文件 <atomic> |  |
 | (1) | (C++20 起)
template< class T > void atomic_flag_wait( const atomic_flag* object, bool old ) noexcept;
template< class T > void atomic_flag_wait( const volatile atomic_flag* object, bool old ) noexcept;
 | (2) | (C++20 起)
template< class T > void atomic_flag_wait_explicit( const atomic_flag* object, bool old, std::memory_order order ) noexcept;
template< class T > void atomic_flag_wait_explicit( const volatile atomic_flag* object, bool old, std::memory_order order ) noexcept;

进行原子等待操作。

比较 object->test( std::memory_order_seq_cst ) 或 object->test(order) 与 old ，而若它们逐位相等则阻塞直至加载结果的值表示更改或 *this 被 std::atomic_flag::notify_one() 或 std::atomic_flag::notify_all() 提醒（或线程被虚假地除阻）。

1) 等价于 object->wait(old, std::memory_order_seq_cst ) 。
2) 等价于 object->wait(old, order) 。

这些函数保证仅若值更改才返回，即使底层实现虚假地除阻。

参数

object | - | 指向要检查并在其上等待的原子标志的指针
old | - | 要检测的原子标志象不再含有的值
order | - | 此操作所用的内存同步顺序：必须不是 std::memory_order::release 或 std::memory_order::acq_rel

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

由于 ABA 问题，可能错失从 old 到另一值再回到 old 的更改，而不除阻。

示例

notify_one (C++20) | 提醒至少一个在原子对象上的等待中阻塞的线程 (std::atomic_flag 的公开成员函数)
notify_all (C++20) | 提醒所有在原子对象上的等待中阻塞的线程 (std::atomic_flag 的公开成员函数)
atomic_flag_notify_one (C++20) | 提醒一个在 atomic_flag_wait 中阻塞的线程 (函数)
atomic_flag_notify_all (C++20) | 提醒所有在 atomic_flag_wait 中阻塞的线程 (函数)


std::atomic_init

< cpp‎ | atomic
定义于头文件 <atomic>
template< class T >

void atomic_init( std::atomic <T>* obj,

typename std::atomic <T>::value_type desired ) noexcept;
 (C++11 起)
(C++20 中弃用)
template< class T >

void atomic_init( volatile std::atomic <T>* obj,

typename std::atomic <T>::value_type desired ) noexcept;
 (C++11 起)
(C++20 中弃用)

以值 desired 初始化默认构造的原子对象 obj 。函数非原子：来自其他线程的并发访问，即使通过原子操作，也是数据竞争。

若 obj 不是默认构造的，则行为未定义。

若在同一 obj 上调用函数二次，则行为未定义。

参数

obj | - | 指向要初始化的原子对象的指针
desired | - | 用以初始化原子对象的值

返回值

（无）

注解

为与 C 兼容提供此函数。若不要求兼容性，可通过其默认构造函数初始化 std::atomic 。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0558R1 | C++11 | 曾要求准确类型匹配，因为从多个参数推导 T | 仅从 atomic 参数推导 T

参阅

ATOMIC_VAR_INIT (C++11)(C++20 中弃用) | 静态存储期的原子对象的常量初始化 (宏函数)
(构造函数) | 构造原子对象 (std::atomic<T> 的公开成员函数)


std::atomic_is_lock_free, ATOMIC_xxx_LOCK_FREE

< cpp‎ | atomic
定义于头文件 <atomic>
(1) (C++11 起)
template< class T >
bool atomic_is_lock_free( const volatile std::atomic <T>* obj ) noexcept;
template< class T >
bool atomic_is_lock_free( const std::atomic <T>* obj ) noexcept;
#define ATOMIC_BOOL_LOCK_FREE /* unspecified */

#define ATOMIC_CHAR_LOCK_FREE /* unspecified */
#define ATOMIC_CHAR16_T_LOCK_FREE /* unspecified */
#define ATOMIC_CHAR32_T_LOCK_FREE /* unspecified */
#define ATOMIC_WCHAR_T_LOCK_FREE /* unspecified */
#define ATOMIC_SHORT_LOCK_FREE /* unspecified */
#define ATOMIC_INT_LOCK_FREE /* unspecified */
#define ATOMIC_LONG_LOCK_FREE /* unspecified */
#define ATOMIC_LLONG_LOCK_FREE /* unspecified */

#define ATOMIC_POINTER_LOCK_FREE /* unspecified */
 (2) (C++11 起)
#define ATOMIC_CHAR8_T_LOCK_FREE /* unspecified */
 (3) (C++20 起)
1) 如同通过调用 obj->is_lock_free() ，确定 obj 所指向的原对象是否免锁地实现。任何给定的程序执行中，免锁查询的结果对于所有同类型的原子对象相同。
2) 展开成整数常量表达式，其值
  • 对于决不免锁的内建原子类型为 ​0​ ；
  • 对于有时免锁的内建原子类型为 1 ；
  • 对于始终免锁的内建原子类型为 2 。

参数

obj - 指向要检验的原子对象的指针

返回值

若 *obj 为免锁原子对象则为 true ，否则 false 。

注解

std::atomic_flag 以外的所有原子类型可用互斥或其他锁定操作实现，而不一定用免锁的原子 CPU 指令。亦允许原子类型有时免锁，例如若给定架构上仅对齐的内存访问是天然原子的，则同类型的错误对齐对象必须用锁。

C++ 标准推荐（但不要求）免锁操作亦为免地址，即适用于使用共享内存的进程间交流。

示例

#include <iostream>
#include <utility>
#include <atomic>

struct A { int a[100]; };
struct B { int x, y; };
int main()
{
    std::atomic<A> a;
    std::atomic<B> b;
    std::cout << std::boolalpha
              << "std::atomic<A> is lock free? "
              << std::atomic_is_lock_free(&a) << '\n'
              << "std::atomic<B> is lock free? "
              << std::atomic_is_lock_free(&b) << '\n';
}

可能的输出：

std::atomic<A> is lock free? false
std::atomic<B> is lock free? true

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3249 | C++11 | atomic_is_lock_free 通过指针说明，这有歧义并可能接受非法指针值 | 通过原子对象说明

参阅

is_lock_free | 检查原子对象是否免锁 (std::atomic<T> 的公开成员函数)
std::atomic_is_lock_free(std::shared_ptr) | 对 std::shared_ptr 特化的原子操作 (函数模板)
atomic_flag (C++11) | 免锁的布尔原子类型 (类)
is_always_lock_free [静态] (C++17) | 指示该类型是否始终免锁 (std::atomic<T> 的公开静态成员常量)


std::atomic_load, std::atomic_load_explicit

< cpp‎ | atomic
定义于头文件 <atomic>
(1) | (C++11 起)
template< class T >
T atomic_load( const std::atomic <T>* obj ) noexcept;
template< class T >
T atomic_load( const volatile std::atomic <T>* obj ) noexcept;
(2) | (C++11 起)
template< class T >

T atomic_load_explicit( const std::atomic <T>* obj,

std::memory_order order ) noexcept;
template< class T >

T atomic_load_explicit( const volatile std::atomic <T>* obj,

std::memory_order order ) noexcept;
1) 如同用 obj->load() 原子地获得 obj 所指向的值。
2) 如同用 obj->load(order) 原子地获得 obj 所指向的值。

参数

obj | - | 指向要加载的原子对象的指针
order | - | 此操作所用的内存同步顺序：只容许 std::memory_order_relaxed 、 std::memory_order_consume 、 std::memory_order_acquire 和 std::memory_order_seq_cst 。

返回值

obj 所指向的原子对象所保有的值。

参阅

load | 原子地获得原子对象的值 (std::atomic<T> 的公开成员函数)
atomic_storeatomic_store_explicit (C++11)(C++11) | 原子地以非原子实参替换原子对象的值 (函数模板)
memory_order (C++11) | 为给定的原子操作定义内存顺序约束 (枚举)
std::atomic_load(std::shared_ptr) std::atomic_load_explicit(std::shared_ptr)
(C++20 中弃用)
 为 std::shared_ptr 特化原子操作
(函数模板)


std::atomic_notify_all

< cpp‎ | atomic
定义于头文件 <atomic> |
 | (C++20 起)
template< class T > void atomic_notify_all( std::atomic <T>* object );
template< class T > void atomic_notify_all( volatile std::atomic <T>* object );

进行原子提醒操作。

除阻所有被 上的原子等待操作（即 std::atomic_wait() 、 std::atomic_wait_explicit() 或 std::atomic::wait() ）阻塞的线程，若有；否则不做任何事。

等价于 object->notify_all() 。

参数

object - 指向待提醒的 atomic 对象的指针

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

示例

本节未完成
原因：暂无示例

参阅

notify_one (C++20) | 提醒至少一个在原子对象上的等待中阻塞的线程 (std::atomic<T> 的公开成员函数)
notify_all (C++20) | 提醒所有在原子对象上的等待中阻塞的线程 (std::atomic<T> 的公开成员函数)
atomic_waitatomic_wait_explicit (C++20)(C++20) | 阻塞线程直至被提醒且原子值更改 (函数模板)
atomic_notify_one (C++20) | 提醒一个在 atomic_wait 中阻塞的线程 (函数模板)


std::atomic_notify_one

< cpp‎ | atomic
定义于头文件 <atomic> |
 | (C++20 起)
template< class T > void atomic_notify_one( std::atomic <T>* object );
template< class T > void atomic_notify_one( volatile std::atomic <T>* object );

进行原子提醒操作。

若有线程阻塞于 *object 上的原子等待操作（即 std::atomic_wait() 、 std::atomic_wait_explicit() 或 std::atomic::wait() ），则除阻至少一个这种线程；否则不做任何事。

等价于 object->notify_one() 。

参数

object - 指向待提醒的原子对象的指针

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

示例

本节未完成
原因：暂无示例

参阅

notify_one (C++20) | 提醒至少一个在原子对象上的等待中阻塞的线程 (std::atomic<T> 的公开成员函数)
notify_all (C++20) | 提醒所有在原子对象上的等待中阻塞的线程 (std::atomic<T> 的公开成员函数)
atomic_notify_all (C++20) | 提醒所有在 atomic_wait 中阻塞的线程 (函数模板)
atomic_waitatomic_wait_explicit (C++20)(C++20) | 阻塞线程直至被提醒且原子值更改 (函数模板)


std::atomic_ref

< cpp‎ | atomic
定义于头文件 <atomic> |  |
template< class T > struct atomic_ref; | (1) | (C++20 起)
template< class T > struct atomic_ref<T*>; | (2) | (C++20 起)

std::atomic_ref 类模板应用原子操作到其所引用的对象。在 atomic_ref 对象的生存期中，认为其所引用的对象是原子对象。若一个线程写入原子对象，同时另一线程从它读取，则行为良好定义（数据竞争上的细节见内存模型）。另外，对原子对象的访问可以建立线程间同步，和按 std::memory_order 所指定排序非原子内存访问。

对象的生存期必须超出所有引用该对象的 atomic_ref 的生存期。任何 atomic_ref 实例引用存在的对象时，必须只通过这些 atomic_ref 实例排他地访问该对象。 atomic_ref 对象所引用对象的任何子对象均不可同时为任何其他 atomic_ref 对象所引用。

通过 atomic_ref 应用到对象的原子操作，相对于通过任何其他引用同一对象的 atomic_ref 应用的操作是原子的。

std::atomic_ref 为可复制构造 (CopyConstructible) 。

类似语言引用，常性对 atomic_ref 为浅——可通过 const atomic_ref 对象修改被引用的值。

特化

初等模板

初等 std::atomic_ref 模板可以用任何可平凡复制 (TriviallyCopyable) 类型 T （包括 bool ）实例化：

struct Counters { int a; int b; } counter; // 用户定义的可平凡复制类型
std::atomic_ref<Counters> cnt(counter);    // 对用户定义类型的特化

指针类型的部分特化

标准库提供 std::atomic_ref 模板对所有指针类型的部分特化。在对所有原子类型提供的操作外，这些特化额外支持适合指针类型的原子操作，如 fetch_add 、 fetch_sub 。

整数类型的特化

以下列整数类型之一实例化时， std::atomic_ref 提供适合整数类型的原子操作，如 fetch_add 、 fetch_sub 、 fetch_and 、 fetch_or 、 fetch_xor ：

  • 字符类型 char 、 char8_t 、 char16_t 、 char32_t 及 wchar_t ；
  • 标准有符号整数类型： signed char 、 short 、 int 、 long 及 long long ；
  • 标准无符号整数类型： unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 及 unsigned long long ；
  • 任何头文件 <cstdint> 中的 typedef 所需的额外整数类型。

定义有符号整数算术为使用补码；无未定义结果。

浮点类型的特化

以浮点类型 float 、 double 和 long double 之一实例化时， std::atomic_ref 提供适合浮点类型的额外原子操作，如 fetch_add 和 fetch_sub 。

没有操作导致未定义行为，即使结果不可以浮点类型表示。有影响的浮点环境可能异于调用方线程的浮点环境。

成员类型

成员类型 | 定义
value_type | 见下方
difference_type | value_type (仅对于 atomic_ref<Integral> 及 atomic_ref<Floating> 特化) std::ptrdiff_t (仅对于 atomic_ref<T*> 特化)

对于每个 std::atomic_ref<X> （无论是否特化）， std::atomic_ref<X>::value_type 均为 X 。

初等 atomic_ref 模板中不定义 difference_type 。

成员函数

(构造函数)
 构造 atomic_ref 对象
(公开成员函数)
operator=
 存储值到 atomic_ref 对象所引用的对象中
(公开成员函数)
is_lock_free
 检查该 atomic_ref 对象是否免锁
(公开成员函数)
store
 原子地以非原子参数替换被引用对象的值
(公开成员函数)
load
 原子地获得被引用对象的值
(公开成员函数)
operator T
 从被引用对象加载值
(公开成员函数)
exchange
 原子地替换被引用对象的值并获得先前保有的值
(公开成员函数)
compare_exchange_weakcompare_exchange_strong
 原子地与非原子参数比较被引用值，而若相等则进行原子交换，否则进行原子加载
(公开成员函数)
wait
(C++20)
 阻塞线程直至被提醒且原子值更改
(公开成员函数)
notify_one
(C++20)
 提醒至少一个在原子对象上的等待中阻塞的线程
(公开成员函数)
notify_all
(C++20)
 提醒所有在原子对象上的等待中阻塞的线程
(公开成员函数)

常量
is_always_lock_free
[静态]
 指示该类型为始终免锁
(公开静态成员常量)
required_alignment
[静态]
 指示被 atomic_ref 引用所要求的对齐
(公开静态成员常量)

特化的成员函数

fetch_add | 原子地将参数加到存储于被引用对象的值，并获得先前保有的值 (公开成员函数)
fetch_sub | 原子地从存储于被引用对象的值减去参数，并获得先前保有的值 (公开成员函数)
fetch_and | 原子地在参数和被引用对象的值间进行逐位与，并获得先前保有的值 (公开成员函数)
fetch_or | 原子地在参数和被引用对象的值间进行逐位或，并获得先前保有的值 (公开成员函数)
fetch_xor | 原子地在参数和被引用对象的值间进行逐位异或，并获得先前保有的值 (公开成员函数)
operator++operator++(int)operator--operator--(int) | 原子地将被引用对象增加或减少一 (公开成员函数)
operator+=operator-=operator&=operator|=operator^= | 原子地和被引用值加、减或者进行逐位与、或、异或 (公开成员函数)

参阅

atomic
(C++11)
 atomic 类模板及其针对布尔、整型和指针类型的特化
(类模板)


std::atomic_ref<T>::atomic_ref

< cpp‎ | atomic‎ | atomic ref
explicit atomic_ref( T& obj ); | (2) | (C++20 起)
atomic_ref( const atomic_ref& ref ) noexcept; | (3) | (C++20 起)

构造新的 atomic_ref 对象。

1) 构造引用对象 obj 的 atomic_ref 对象。若 obj 未对齐到 required_alignment 则行为未定义。
2) 构造引用 ref 所引用对象的 atomic_ref 对象。

参数

obj | - | 到对象的引用
ref | - | 要复制的另一 atomic_ref 对象


std::atomic_ref<T>::compare_exchange_weak, std::atomic_ref<T>::compare_exchange_strong

< cpp‎ | atomic‎ | atomic ref
bool compare_exchange_weak( T& expected, T desired,

std::memory_order success,

std::memory_order failure ) const noexcept;
 (1) (C++20 起)
bool compare_exchange_weak( T& expected, T desired,

std::memory_order order =

std::memory_order_seq_cst ) const noexcept;
 (2) (C++20 起)
bool compare_exchange_strong( T& expected, T desired,

std::memory_order success,

std::memory_order failure ) const noexcept;
 (3) (C++20 起)
bool compare_exchange_strong( T& expected, T desired,

std::memory_order order =

std::memory_order_seq_cst ) const noexcept;
 (4) (C++20 起)

原子地比较被引用对象的值表示与 expected 的值表示，而若它们逐位相等，则以 desired 替换前者（进行读修改写操作）。否则，加载存储于被引用对象的实际值到 expected 中（进行加载操作）。

读修改写和加载操作的内存模型分别是 success 和 failure 。在 (2) 和 (4) 版本中， order 同时用于读修改写操作和加载操作，除了若 order == std::memory_order_acq_rel 或 order == std::memory_order_release ，则分别将 std::memory_order_acquire 和 std::memory_order_relaxed 用于加载操作。

参数

expected | - | 到期待在 atomic_ref 所引用对象中找到的值的引用
desired | - | 若满足期待则要存储于被引用对象中的值
success | - | 若比较成功则用于读修改写操作的内存同步顺序。容许所有值。
failure | - | 若比较失败则用于加载操作的内存同步顺序。不能为 std::memory_order_release 或 std::memory_order_acq_rel
order | - | 两个操作的内存同步顺序

返回值

若成功更改被引用数据则为 true ，否则为 false 。

注解

比较和复制是逐位的（类似 std::memcmp 和 std::memcpy ）；不使用构造函数、赋值运算符或比较运算符。

允许弱形式 (1-2) 虚假地失败，即表现为 *this != expected ，即使它们相等。比较并交换在循环中时，弱版本在某些平台上将产生较好的性能。

弱比较并交换会要求循环，而强版本不会要求时，最好用强版本，除非 T 的对象表示可能包含陷阱位，或相同值有多种对象表示（例如浮点 NaN ）。那些情况下，弱比较并交换通常能用，因为它在某些稳定的对象表示上快速收敛。

若有参与 union 某些成员，但非其他成员的值表示的位，则比较并交换可能始终失败，因为这种填充位在不参与活跃成员的值表示时拥有不确定值。

忽略决不参与对象值表示的填充位。

示例

本节未完成
原因：暂无示例


std::atomic_ref<T>::exchange

< cpp‎ | atomic‎ | atomic ref
T exchange( T desired, std::memory_order order = std::memory_order_seq_cst ) const noexcept; | (C++20 起)

原子地以 desired 替换被引用对象的值。该操作是读修改写操作。按照 order 的值影响内存。

参数

desired | - | 要赋值的值
order | - | 要施加的内存顺序制约

返回值

调用前被引用对象的值。


std::atomic_ref<T>::fetch_add

< cpp‎ | atomic‎ | atomic ref
仅为 atomic_ref<Integral> 与 atomic_ref<Floating> 模板特化的成员
T fetch_add( T arg,
std::memory_order order = std::memory_order_seq_cst ) const noexcept;
 (1)
仅为 atomic_ref<T*> 模板特化的成员
T* fetch_add( std::ptrdiff_t arg,
std::memory_order order = std::memory_order_seq_cst ) const noexcept;
 (2)

原子地以值和 arg 的算术加法结果替换当前被引用对象的值。此操作为读修改写操作。按照 order 的值影响内存。

对于有符号整数类型，定义算术为使用补码。无未定义结果。

对于浮点类型，有效的浮点环境可能异于调用方线程的浮点环境。不需要操作服从对应的 std::numeric_limits 特性，但鼓励这么做。若结果不是其类型的可表示值，则结果未指定，但操作不会另有未定义行为。

对于 T* 类型，结果可以为未定义的地址，但操作不会另有未定义行为。若 T 不是对象类型则程序为谬构。

参数

arg | - | 算术加法的另一参数
order | - | 施加的内存顺序制约

返回值

被引用对象立即于此函数效果前的值。

示例

本节未完成
原因：暂无示例


std::atomic_ref<T>::fetch_and

< cpp‎ | atomic‎ | atomic ref
T fetch_and( T arg, std::memory_order order = std::memory_order_seq_cst ) const noexcept; | (C++20 起) (仅为 atomic_ref<Integral> 模板特化的成员)

原子地以值和 arg 的逐位与结果替换被引用对象的当前值。此操作是读修改写操作。按照 order 的值影响内存。

参数

arg | - | 逐位与的另一参数
order | - | 要施加的内存制约

返回值

被引用对象立即于此函数效果前的值。


std::atomic_ref<T>::fetch_or

< cpp‎ | atomic‎ | atomic ref
T fetch_or( T arg, std::memory_order order = std::memory_order_seq_cst ) const noexcept; | (C++20 起) (仅为 atomic_ref<Integral> 模板特化的成员)

原子地以值和 arg 的逐位或结果替换被引用对象的当前值。此操作是读修改写操作。按照 order 的值影响内存。

参数

arg | - | 逐位或的另一参数
order | - | 要施加的内存制约

返回值

被引用对象立即于此函数效果前的值。


std::atomic_ref<T>::fetch_sub

< cpp‎ | atomic‎ | atomic ref
仅为 atomic_ref<Integral> 与 atomic_ref<Floating> 模板特化的成员
T fetch_sub( T arg,
std::memory_order order = std::memory_order_seq_cst ) const noexcept;
 (1)
仅为 atomic_ref<T*> 模板特化的成员
T* fetch_sub( std::ptrdiff_t arg,
std::memory_order order = std::memory_order_seq_cst ) const noexcept;
 (2)

原子地以值和 arg 的算术减法结果替换当前被引用对象的值。此操作为读修改写操作。按照 order 的值影响内存。

对于有符号整数类型，定义算术为使用补码。无未定义结果。

对于浮点类型，有效的浮点环境可能异于调用方线程的浮点环境。不需要操作服从对应的 std::numeric_limits 特性，但鼓励这么做。若结果不是其类型的可表示值，则结果未指定，但操作不会另有未定义行为。

对于 T* 类型，结果可以为未定义的地址，但操作不会另有未定义行为。若 T 不是对象类型则程序为谬构。

参数

arg | - | 算术减法的另一参数
order | - | 施加的内存顺序制约

返回值

被引用对象立即于此函数效果前的值。

示例

本节未完成
原因：暂无示例


std::atomic_ref<T>::fetch_xor

< cpp‎ | atomic‎ | atomic ref
T fetch_xor( T arg, std::memory_order order = std::memory_order_seq_cst ) const noexcept; | (C++20 起) (仅为 atomic_ref<Integral> 模板特化的成员)

原子地以值和 arg 的逐位异或结果替换被引用对象的当前值。此操作是读修改写操作。按照 order 的值影响内存。

参数

arg | - | 逐位异或的另一参数
order | - | 要施加的内存制约

返回值

被引用对象立即于此函数效果前的值。


std::atomic_ref<T>::is_always_lock_free

< cpp‎ | atomic‎ | atomic ref
static constexpr bool is_always_lock_free = /*implementation-defined*/; | (C++20 起)

若此 atomic_ref 类型始终免锁则为 true ，而若它决不或有时免锁则为 false 。

此常量的值与成员函数 is_lock_free 的结果一致。

参阅

is_lock_free
 检查该 atomic_ref 对象是否免锁
(公开成员函数)


std::atomic_ref<T>::is_lock_free

< cpp‎ | atomic‎ | atomic ref
bool is_lock_free() const noexcept; | (C++20 起)

检查此对象上的原子操作是否免锁。

参数

（无）

返回值

若此对象上的原子操作为免锁则为 true ，否则为 false 。

注解

std::atomic_flag 以外的所有原子类型可能会被用互斥或其他锁定操作实现，而不一定用免锁的原子 CPU 指令。亦允许原子类型有时免锁，例如若给定架构上仅对齐的内存访问是原生原子的，则同类型的错误对齐对象必须用锁。

C++ 标准推荐（但不要求）免锁操作亦为免地址，即适用于使用共享内存的进程间交流。

示例

本节未完成
原因：暂无示例

参阅

is_always_lock_free
[静态]
 指示该类型为始终免锁
(公开静态成员常量)


std::atomic_ref<T>::load

< cpp‎ | atomic‎ | atomic ref
T load( std::memory_order order = std::memory_order_seq_cst ) const noexcept; | (C++20 起)

原子地加载并返回被引用对象的当前值。按照 order 的值影响内存。

order 必须是 std::memory_order_relaxed 、 std::memory_order_consume 、 std::memory_order_acquire 或 std::memory_order_seq_cst 之一。否则行为未定义。

参数

order - 要施加的内存顺序制约

返回值

被引用对象的当前值。

参阅

operator T
 从被引用对象加载值
(公开成员函数)


std::atomic_ref<T>::notify_all

< cpp‎ | atomic‎ | atomic ref

 | (C++20 起)
void notify_all() const noexcept;
void notify_all() const volatile noexcept;

进行原子提醒操作

除阻所有被 *this 上的原子等待操作（即 wait() ）阻塞的线程，若有；否则不做任何事。

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

示例

本节未完成
原因：暂无示例

参阅

wait (C++20) | 阻塞线程直至被提醒且原子值更改 (公开成员函数)
atomic_waitatomic_wait_explicit (C++20)(C++20) | 阻塞线程直至被提醒且原子值更改 (函数模板)
atomic_notify_one (C++20) | 提醒一个在 atomic_wait 中阻塞的线程 (函数模板)


std::atomic_ref<T>::notify_one

< cpp‎ | atomic‎ | atomic ref

 | (C++20 起)
void notify_one() const noexcept;
void notify_one() const volatile noexcept;

进行原子提醒操作。

若有线程被 *this 上的原子等待操作（即 wait() ）阻塞，则除阻至少一个这种线程；否则不做任何事。

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

示例

本节未完成
原因：暂无示例

参阅

wait (C++20) | 阻塞线程直至被提醒且原子值更改 (公开成员函数)
atomic_waitatomic_wait_explicit (C++20)(C++20) | 阻塞线程直至被提醒且原子值更改 (函数模板)
atomic_notify_one (C++20) | 提醒一个在 atomic_wait 中阻塞的线程 (函数模板)


std::atomic_ref<T>::operator=

< cpp‎ | atomic‎ | atomic ref
T operator=( T desired ) const noexcept; | (1)
atomic_ref& operator=( const atomic_ref& ) = delete; | (2)
1) 原子地赋值 desired 给被引用对象。等价于 store(desired) 。
2) atomic_ref 非可复制赋值 (CopyAssignable) 。

参数

desired - 要赋的值

返回值

desired 。

注解

不同于大多数赋值运算符， atomic_ref 的赋值运算符不返回到其左侧运算数的引用。它替而返回存储的值的副本。

参阅

(构造函数)
 构造 atomic_ref 对象
(公开成员函数)


std::atomic_ref<T>::operator T

< cpp‎ | atomic‎ | atomic ref
operator T() const noexcept; | (C++20 起)

原子地加载并返回被引用对象的当前值。等价于 load() 。

参数

（无）

返回值

被引用对象的当前值。

参阅

load
 原子地获得被引用对象的值
(公开成员函数)


std::atomic_ref<T>::operator++,++(int),--,--(int)

< cpp‎ | atomic‎ | atomic ref
仅为 atomic_ref<Integral> 与 atomic_ref<T*> 模板特化的成员 |  |
value_type operator++() const noexcept; | (1) | (C++20 起)
value_type operator++(int) const noexcept; | (2) | (C++20 起)
value_type operator--() const noexcept; | (3) | (C++20 起)
value_type operator--(int) const noexcept; | (4) | (C++20 起)

原子地自增或自减被引用对象的当前值。这些操作是读修改写操作。

1) 进行前自增。等价于 return fetch_add(1) + 1; 。
2) 进行后自增。等价于 return fetch_add(1); 。
3) 进行前自减。等价于 return fetch_sub(1) - 1; 。
4) 进行后自减。等价于 return fetch_sub(1); 。

对于有符号整数 (Integral) 类型，定义算术为使用补码。无未定义结果。

对于 T* 类型，结果可为未定义地址，但操作不会另有未定义行为。若 T 不是对象类型则行为未定义。

参数

（无）

返回值

1,3) 被引用对象在修改后的值。
2,4) 被引用对象在修改前的值。

注解

不同于大多数前自增和前自减运算符， atomic_ref 的前自增和前自减运算符不返回到被修改对象的引用。它们替而返回存储的值的副本。

参阅

fetch_add | 原子地将参数加到存储于被引用对象的值，并获得先前保有的值 (公开成员函数)
fetch_sub | 原子地从存储于被引用对象的值减去参数，并获得先前保有的值 (公开成员函数)
operator+=operator-=operator&=operator|=operator^= | 原子地和被引用值加、减或者进行逐位与、或、异或 (公开成员函数)


std::atomic_ref<T>::operator+=,-=,&=,|=,^=

< cpp‎ | atomic‎ | atomic ref
仅为 atomic_ref<Integral> 与 atomic_ref<Floating> 模板特化的成员 |
T operator+=( T arg ) const noexcept; | (1)
仅为 atomic_ref<T*> 模板特化的成员 |
T* operator+=( std::ptrdiff_t arg ) const noexcept; | (1)
仅为 atomic_ref<Integral> 与 atomic_ref<Floating> 模板特化的成员 |
T operator-=( T arg ) const noexcept; | (1)
仅为 atomic_ref<T*> 模板特化的成员 |
T* operator-=( std::ptrdiff_t arg ) const noexcept; | (1)
仅为 atomic_ref<Integral> 模板特化的成员 |
T operator&=( T arg ) const noexcept; | (3)
T operator|=( T arg ) const noexcept; | (4)
T operator^=( T arg ) const noexcept; | (5)

原子地以涉及先前值和 arg 的运算的结果替换被引用对象的当前值。这些操作是读修改写操作。

1) 进行原子加法。等价于 return fetch_add(arg) + arg; 。
2) 进行原子减法。等价于 return fetch_sub(arg) - arg; 。
3) 进行原子逐位与。等价于 return fetch_and(arg) & arg; 。
4) 进行原子逐位或。等价于 return fetch_or(arg) | arg; 。
5) 进行原子逐位异或。等价于 return fetch_xor(arg) ^ arg; 。

对于有符号整数类型，定义算术为使用补码。无未定义结果。

对于浮点类型，有效的浮点环境可能异于调用方线程的浮点环境。不需要操作服从对应的 std::numeric_limits 特性，但鼓励这么做。若结果不是其类型的可表示值，则结果未指定，但操作不会另有未定义行为。

对于 T* 类型，结果可以为未定义的地址，但操作不会另有未定义行为。若 T 不是对象类型则程序为谬构。

参数

arg - 算术运算的参数

返回值

结果值（即应用对应的二元运算符到立即在对应的成员函数效果之前的值的结果）。

注解

不同于大多数复合赋值运算符， atomic_ref 的复合赋值运算符不返回到其左侧参数的引用。它们替而返回存储的值的副本。

参阅

operator++operator++(int)operator--operator--(int)
 原子地将被引用对象增加或减少一
(公开成员函数)


std::atomic_ref<T>::required_alignment

< cpp‎ | atomic‎ | atomic ref
static constexpr std::size_t required_alignment= /*implementation-defined*/; | (C++20 起)

required_alignment 的值是要被原子引用所引用的对象所需的对齐要求，至少为 alignof(T) 。

注解

硬件可能要求要被引用 atomic_ref<T> 的对象拥有比其他 T 对象更严格的要求，而 atomic_ref 上的操作是否免锁能依赖于被引用对象的对齐。


std::atomic_ref<T>::store

< cpp‎ | atomic‎ | atomic ref
void store( T desired, std::memory_order order = std::memory_order_seq_cst ) const noexcept; | (C++20 起)

原子地以 desired 替换当前被引用对象的值。按照 order 的值影响内存。

order 必须是 std::memory_order_relaxed 、 std::memory_order_release 或 std::memory_order_seq_cst 之一。否则行为未定义。

参数

desired | - | 要存入被引用对象的值
order | - | 要施加的内存顺序

返回值

（无）

示例

operator=
 存储值到 atomic_ref 对象所引用的对象中
(公开成员函数)


std::atomic_ref<T>::wait

< cpp‎ | atomic‎ | atomic ref

 | (C++20 起)
void wait( T old, std::memory_order order = std::memory_order::seq_cst ) const noexcept;
void wait( T old, std::memory_order order = std::memory_order::seq_cst ) const volatile noexcept;

进行原子等待操作。表现为如同进行下列步骤：

  • 比较 this->test(order) 的值表示与 old 。
    • 若它们相等，则阻塞直至 *this 被 notify_one() 或 notify_all() 提醒，或线程被虚假地除阻。

这些函数保证仅若值更改才返回，即使底层实现虚假地除阻。

参数

old | - | 要检测 atomic_ref 的对象不再含有的值
order | - | 此操作所用的内存同步顺序：必须不是 std::memory_order::release 或 std::memory_order::acq_rel

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

由于 ABA 问题，可能错失从 old 到另一值再回到 old 的更改，而不除阻。

比较是逐位的（类似 std::memcmp ）；不使用比较运算符。忽略决不参与对象值表示的填充位。

示例

本节未完成
原因：暂无示例

参阅

notify_one (C++20) | 提醒至少一个在原子对象上的等待中阻塞的线程 (公开成员函数)
notify_all (C++20) | 提醒所有在原子对象上的等待中阻塞的线程 (公开成员函数)
atomic_notify_one (C++20) | 提醒一个在 atomic_wait 中阻塞的线程 (函数模板)
atomic_notify_all (C++20) | 提醒所有在 atomic_wait 中阻塞的线程 (函数模板)


std::atomic_signal_fence

< cpp‎ | atomic
定义于头文件 <atomic> |
extern "C" void atomic_signal_fence( std::memory_order order ) noexcept; | (C++11 起)

在线程和同一线程上执行的信号处理函数之间，建立以 order 指示的非原子和宽松原子访问的内存同步顺序。这等价于 std::atomic_thread_fence ，除了不为内存顺序产生 CPU 指令。只会以 order 指示抑制编译器重排指令。例如，拥有释放语义的栅栏阻止移到读或写到后继写入之后，而拥有获得语义的栅栏阻止移动读或写到前驱读取之前。

参数

order - 此栅栏执行的内存顺序

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

memory_order (C++11) | 为给定的原子操作定义内存顺序约束 (枚举)
atomic_thread_fence (C++11) | 通用的依赖内存顺序的栅栏同步原语 (函数)


std::atomic_store, std::atomic_store_explicit

< cpp‎ | atomic
定义于头文件 <atomic>
(1) | (C++11 起)
template< class T >

void atomic_store( std::atomic <T>* obj,

typename std::atomic <T>::value_type desr ) noexcept;
template< class T >

void atomic_store( volatile std::atomic <T>* obj,

typename std::atomic <T>::value_type desr ) noexcept;
(2) | (C++11 起)
template< class T >

void atomic_store_explicit( std::atomic <T>* obj,
typename std::atomic <T>::value_type desr,

std::memory_order order) noexcept;
template< class T >

void atomic_store_explicit( volatile std::atomic <T>* obj,
typename std::atomic <T>::value_type desr,

std::memory_order order) noexcept;
1) 如同用 obj->store(desr) 原子地以 desr 的值替换 obj 所指向的值。
2) 如同用 obj->store(desr, order) 原子地以 desr 的值替换 obj 所指向的值。

参数

obj | - | 指向要修改的原子对象的指针
desr | - | 要存储于原子对象的值
order | - | 此操作所用的内存同步顺序：只容许 std::memory_order_relaxed 、 std::memory_order_release 和 std::memory_order_seq_cst 。

返回值

（无）

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0558R1 | C++11 | 曾要求准确类型匹配，因为从多个参数推导 T | 仅从 atomic 参数推导 T

参阅

store | 原子地以非原子对象替换原子对象的值 (std::atomic<T> 的公开成员函数)
atomic_loadatomic_load_explicit (C++11)(C++11) | 原子地获得存储于原子对象的值 (函数模板)
memory_order (C++11) | 为给定的原子操作定义内存顺序约束 (枚举)
std::atomic_store(std::shared_ptr) std::atomic_store_explicit(std::shared_ptr)
(C++20 中弃用)
 为 std::shared_ptr 特化原子操作
(函数模板)


std::atomic_thread_fence

< cpp‎ | atomic
定义于头文件 <atomic> |
extern "C" void atomic_thread_fence( std::memory_order order ) noexcept; | (C++11 起)

建立非原子和宽松原子访问的以 order 指示的内存同步顺序，而无关联的原子操作。

栅栏原子同步

线程 A 中的释放栅栏 F 同步于线程 B 中的原子获得操作 Y ，若

  • 存在原子存储 X （带任何内存顺序）
  • Y 读取 X 所写入的值（或会为 X 所引领的释放序列所写入的值，若 X 是释放操作）
  • F 在线程 A 中先序于 X

此情况下，所有线程 A 中先序于 F 的非原子和宽松原子存储将先发生于线程 B 中所有 Y 后的，来自同一位置的非原子和宽松原子加载。

原子栅栏同步

线程 A 中的原子释放操作 X 同步于线程 B 中的获得栅栏 F ，若

  • 存在原子读取 Y （带任何内存顺序）
  • Y 读取 X （或 X 所引领的释放序列）所写入的值
  • Y 在线程 B 中先序于 F

此情况下，线程 A 中所有先序于 X 的非原子和宽松原子存储，将先发生于线程 B 中所有 F 后的，来自同一位置的非原子和宽松原子加载。

栅栏栅栏同步

线程 A 中的释放栅栏 FA 同步于线程 B 中的获得栅栏 FB ，若

  • 存在原子对象 M ，
  • 线程 A 中存在修改 M 的原子写入 X （带任何内存顺序）
  • 线程 A 中 FA 先序于 X
  • 线程 B 中存在原子读取 Y （带任何内存顺序）
  • Y 读取 X 所写入的值（或会为 X 所引领的释放序列所写入的值，若 X 是释放操作）
  • 线程 B 中 Y 先序于 FB

此情况下，线程 A 中所有先序于 FA 的非原子和宽松原子存储，将先发生于线程 B 中所有 FB 后的，来自同一位置的非原子和宽松原子加载。

参数

order - 此栅栏所执行的内存顺序

返回值

（无）

注意

atomic_thread_fence 强加的同步制约强于带同一 std::memory_order 的原子存储操作。在原子存储释放操作阻止所有前驱写入被移动到存储释放之后的同时，带 memory_order_release 顺序的 atomic_thread_fence 还阻止所有前驱写入被移动到后继存储之后。

栅栏栅栏同步能用于添加同步到数个宽松原子操作的序列，例如

// 全局
std::string computation(int);
void print( std::string );

std::atomic<int> arr[3] = { -1, -1, -1 };
std::string data[1000] // 非原子数据

// 线程 A ，计算 3 个值
void ThreadA( int v0, int v1, int v2 )
{
//assert( 0 <= v0, v1, v2 < 1000 );
data[v0] = computation(v0);
data[v1] = computation(v1);
data[v2] = computation(v2);
std::atomic_thread_fence(std::memory_order_release);
std::atomic_store_explicit(&arr[0], v0, std::memory_order_relaxed);
std::atomic_store_explicit(&arr[1], v1, std::memory_order_relaxed);
std::atomic_store_explicit(&arr[2], v2, std::memory_order_relaxed);
}

// 线程 B ，打印已经计算的 0 与 3 之间的值。
void ThreadB()
{
int v0 = std::atomic_load_explicit(&arr[0], std::memory_order_relaxed);
int v1 = std::atomic_load_explicit(&arr[1], std::memory_order_relaxed);
int v2 = std::atomic_load_explicit(&arr[2], std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);
// v0 、 v1 、 v2 可能全部或部分结果为 -1 。
// 其他情况下读取非原子数据是安全的，因为栅栏：
if( v0 != -1 ) { print( data[v0] ); }
if( v1 != -1 ) { print( data[v1] ); }
if( v2 != -1 ) { print( data[v2] ); }
}

示例

扫描邮箱数组，并只处理我们打算处理的一个，而无不必要的同步。 此示例使用原子栅栏同步。

const int num_mailboxes = 32;
std::atomic<int> mailbox_receiver[num_mailboxes];
std::string mailbox_data[num_mailboxes];

// 写者线程更新非原子共享数据
// 然后更新 mailbox_receiver[i] 如下
mailbox_data[i] = ...;
std::atomic_store_explicit(&mailbox_receiver[i], receiver_id, std::memory_order_release);

// 读者线程需要检查所有 mailbox[i] ，但只需与一个同步
for (int i = 0; i < num_mailboxes; ++i) {
    if (std::atomic_load_explicit(&mailbox_receiver[i], std::memory_order_relaxed) == my_id) {
        std::atomic_thread_fence(std::memory_order_acquire); // 恰与一个写者同步
        do_work( mailbox_data[i] ); // 保证观测到 atomic_store_explicit()
                    // 之前写者线程所做的任何事
    }
 }

参阅

memory_order (C++11) | 为给定的原子操作定义内存顺序约束 (枚举)
atomic_signal_fence (C++11) | 线程与执行于同一线程的信号处理函数间的栅栏 (函数)


std::atomic_wait, std::atomic_wait_explicit

< cpp‎ | atomic
定义于头文件 <atomic>
(1) | (C++20 起)
template< class T >

void atomic_wait( const std::atomic <T>* object,

typename std::atomic <T>::value_type old ) noexcept;
template< class T >

void atomic_wait( const volatile std::atomic <T>* object,

typename std::atomic <T>::value_type old ) noexcept;
(2) | (C++20 起)
template< class T >

void atomic_wait_explicit( const std::atomic <T>* object,
typename std::atomic <T>::value_type old,

std::memory_order order ) noexcept;
template< class T >

void atomic_wait_explicit( const volatile std::atomic <T>* object,
typename std::atomic <T>::value_type old,

std::memory_order order ) noexcept;

进行原子等待操作。表现为重复进行下列步骤：

  • 比较 object->load( std::memory_order_seq_cst ) 或 object->load(order) 与 old 的值表示。
    • 若它们逐位相等则阻塞直至 *this 被 std::atomic::notify_one() 或 std::atomic::notify_all() 提醒，或线程被虚假地除阻。
    • 否则返回。

允许这些函数虚假地除阻，即由于值更改或提醒之外的原因返回。

1) 等价于 object->wait(old, std::memory_order_seq_cst ) 。
2) 等价于 object->wait(old, order) 。

参数

object | - | 指向要检查并在其上等待的原子对象的指针
old | - | 要检测的原子对象不再含有的值
order | - | 此操作所用的内存同步顺序：必须不是 std::memory_order::release 或 std::memory_order::acq_rel

返回值

（无）

注解

更改检测的这种形式通常比简单轮询或纯自旋锁高效。

由于 ABA 问题，可能错失从 old 到另一值再回到 old 的更改，而不除阻。

比较是逐位的（类似 std::memcpy ）；不使用比较运算符。忽略决不参与对象值表示的填充位。

示例

本节未完成
原因：暂无示例

参阅

notify_one (C++20) | 提醒至少一个在原子对象上的等待中阻塞的线程 (std::atomic<T> 的公开成员函数)
notify_all (C++20) | 提醒所有在原子对象上的等待中阻塞的线程 (std::atomic<T> 的公开成员函数)
atomic_notify_one (C++20) | 提醒一个在 atomic_wait 中阻塞的线程 (函数模板)
atomic_notify_all (C++20) | 提醒所有在 atomic_wait 中阻塞的线程 (函数模板)


std::kill_dependency

< cpp‎ | atomic
定义于头文件 <atomic> |
template< class T > T kill_dependency( T y ) noexcept; | (C++11 起)

告诉编译器 std::memory_order_consume 原子加载操作所开始的依赖树不会扩张过 std::kill_dependency 的返回值；即参数不会将依赖携带进返回值。

这可用于在依赖链离开函数作用域（而函数无 [[carries_dependency]] 属性）时，避免不必要的 std::memory_order_acquire 栅栏。

参数

y - 要从依赖树移除其返回值的表达式

返回值

返回 y ，它不再是依赖树的一部分。

示例

file1.cpp:
struct foo { int* a; int* b; };
std::atomic<struct foo*> foo_head[10];
int foo_array[10][10];

// 消费操作开始依赖链，它将脱离此函数
[[carries_dependency]] struct foo* f(int i) {
    return foo_head[i].load(memory_order_consume);
}

// 依赖链通过有参数进入此函数，而在函数前被杀掉（故不发生额外的获得操作）
int g(int* x, int* y [[carries_dependency]]) {
    return std::kill_dependency(foo_array[*x][*y]);
}
file2.cpp:
[[carries_dependency]] struct foo* f(int i);
int g(int* x, int* y [[carries_dependency]]);

int c = 3;
void h(int i) {
    struct foo* p;
    p = f(i); // f 内开始的依赖链持续进入 p ，而无过度的获得
    do_something_with(g(&c, p->a)); // p->b 不从缓存进口
    do_something_with(g(p->a, &c)); // 左参数无 carries_dependency 属性：
                                    // 可能发生内存获得栅栏
                                    // p->b 在进入 g() 前变为可见
}

参阅

memory_order
(C++11)
 为给定的原子操作定义内存顺序约束
(枚举)


std::memory_order

< cpp‎ | atomic
定义于头文件 <atomic>
typedef enum memory_order {

memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst

} memory_order;
 (C++11 起)
(C++20 前)
enum class memory_order : /*unspecified*/ {

relaxed, consume, acquire, release, acq_rel, seq_cst
};
inline constexpr memory_order memory_order_relaxed = memory_order::relaxed;
inline constexpr memory_order memory_order_consume = memory_order::consume;
inline constexpr memory_order memory_order_acquire = memory_order::acquire;
inline constexpr memory_order memory_order_release = memory_order::release;
inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel;

inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst;
 (C++20 起)

std::memory_order 指定内存访问，包括常规的非原子内存访问，如何围绕原子操作排序。在没有任何制约的多处理器系统上，多个线程同时读或写数个变量时，一个线程能观测到变量值更改的顺序不同于另一个线程写它们的顺序。其实，更改的顺序甚至能在多个读取线程间相异。一些类似的效果还能在单处理器系统上出现，因为内存模型允许编译器变换。

库中所有原子操作的默认行为提供序列一致顺序（见后述讨论）。该默认行为可能有损性能，不过可以给予库的原子操作额外的 std::memory_order 参数，以指定附加制约，在原子性外，编译器和处理器还必须强制该操作。

常量

定义于头文件 <atomic>
值 | 解释
memory_order_relaxed | 宽松操作：没有同步或顺序制约，仅对此操作要求原子性（见下方宽松顺序）。
memory_order_consume | 有此内存顺序的加载操作，在其影响的内存位置进行消费操作：当前线程中依赖于当前加载的该值的读或写不能被重排到此加载前。其他释放同一原子变量的线程的对数据依赖变量的写入，为当前线程所可见。在大多数平台上，这只影响到编译器优化（见下方释放消费顺序）。
memory_order_acquire | 有此内存顺序的加载操作，在其影响的内存位置进行获得操作：当前线程中读或写不能被重排到此加载前。其他释放同一原子变量的线程的所有写入，能为当前线程所见（见下方释放获得顺序）。
memory_order_release | 有此内存顺序的存储操作进行释放操作：当前线程中的读或写不能被重排到此存储后。当前线程的所有写入，可见于获得该同一原子变量的其他线程（见下方释放获得顺序），并且对该原子变量的带依赖写入变得对于其他消费同一原子对象的线程可见（见下方释放消费顺序）。
memory_order_acq_rel | 带此内存顺序的读修改写操作既是获得操作又是释放操作。当前线程的读或写内存不能被重排到此存储前或后。所有释放同一原子变量的线程的写入可见于修改之前，而且修改可见于其他获得同一原子变量的线程。
memory_order_seq_cst | 有此内存顺序的加载操作进行获得操作，存储操作进行释放操作，而读修改写操作进行获得操作和释放操作，再加上存在一个单独全序，其中所有线程以同一顺序观测到所有修改（见下方序列一致顺序）。

正式描述

线程间同步和内存顺序决定表达式的求值和副效应如何在不同的执行线程间排序。它们用下列术语定义：

先序于

在同一线程中，求值 A 可以先序于求值 B ，如求值顺序中所描述。

携带依赖

在同一线程中，若下列任一为真，则先序于求值 B 的求值 A 可能也会将依赖带入 B （即 B 依赖于 A ）

1) A 的值被用作 B 的运算数，除了
a) B 是对 std::kill_dependency 的调用
b) A是内建 && 、 || 、 ?: 或 , 运算符的左运算数。
2) A 写入标量对象 M，B 从 M 读取
3) A 将依赖携带入另一求值 X ，而 X 将依赖携带入 B

修改顺序

对任何特定的原子变量的修改，以限定于此一原子变量的单独全序出现。

对所有原子操作保证下列四个要求：

1) 写写连贯：若修改某原子对象 M 的求值 A （写操作）先发生于修改 M 的求值 B ，则 A 在 M 的修改顺序中早于 B 出现。
2) 读读连贯：若某原子对象 M 的值计算 A （读操作）先发生于对 M 的值计算 B ，且 A 的值来自对 M 的写操作 X ，则 B 的值要么是 X 所存储的值，要么是在 M 的修改顺序中后于 X 出现的 M 上的副效应 Y 所存储的值。
3) 读写连贯：若某原子对象 M 的值计算 A （读操作）先发生于 M 上的操作 B （写操作），则 A 的值来自 M 的修改顺序中早于 B 出现的副效应 X （写操作）。
4) 写读连贯：若原子对象 M 上的副效应 X （写操作）先发生于 M 的值计算 B （读操作），则求值 B 应从 X 或从 M 的修改顺序中后随 X 的副效应 Y 取得其值。

释放序列

在原子对象 M 上执行一次释放操作 A 之后， M 的修改顺序的最长连续子序列由下列内容组成

1) 由执行 A 的同一线程所执行的写操作
 (C++20 前)
2) 任何线程对 M 的原子的读-修改-写操作

被称为以 A 为首的释放序列。

依赖先序于

在线程间，若下列任一为真，则求值 A 依赖先序于求值 B

1) A 在某原子对象 M 上进行释放操作，而不同的线程中， B 在同一原子对象 M 上进行消费操作，而 B 读取 A 所引领的释放序列的任何部分 (C++20 前)所写入的值。
2) A 依赖先序于 X 且 X 携带依赖到 B 。

线程间先发生于

在线程间，若下列任一为真，则求值 A 线程间先发生于求值 B

1) A 同步于 B
2) A 依赖先序于 B
3) A 同步于某求值 X ，而 X 先序于 B
4) A 先序于某求值 X ，而 X 线程间先发生于 B
5) A 线程间先发生于某求值 X ，而 X 线程间先发生于 B

先发生于

无关乎线程，若下列任一为真，则求值 A 先发生于求值 B ：

1) A 先序于 B
2) A 线程间先发生于 B

要求实现确保先发生于关系是非循环的，若有必要则引入额外的同步（若引入消费操作，它才可能为必要，见 Batty 等）。

若一次求值修改一个内存位置，而其他求值读或修改同一内存位置，且至少一个求值不是原子操作，则程序的行为未定义（程序有数据竞争），除非这两个求值之间存在先发生于关系。

简单先发生于

无关乎线程，若下列之一为真，则求值 A 简单先发生于求值 B ：

1) A 先序于 B
2) A 同步于 B
3) A 简单先发生于 X ，而 X 简单先发生于 B

注：不计消费操作，则简单先发生于与强先发生于关系是相同的。

 (C++20 起)

强先发生于

无关乎线程，若下列之一为真，则求值 A 强先发生于求值 B ：

1) A 先序于 B 2) A 同步于 B 3) A 强先发生于 X ，而 X 强先发生于 B | (C++20 前)
1) A 先序于 B 2) A 同步于 B ，且 A 与 B 均为序列一致的原子操作 3) A 先序于 X ， X 简单先发生于 Y ，而 Y 先序于 B 4) A 强先发生于 X ，而 X 强先发生于 B 注：非正式而言，若 A 强先发生于 B ，则在所有环境中 A 均显得在 B 之前得到求值。 注：强先发生于排除消费操作。 | (C++20 起)

可见副效应

若下列皆为真，则标量 M 上的副效应 A （写入）相对于 M 上的值计算（读取）可见：

1) A 先发生于 B
2) 没有其他对 M 的副效应 X 满足 A 先发生于 X 且 X 先发生于 B

若副效应 A 相对于值计算 B 可见，则修改顺序中，满足 B 不先发生于它的对 M 的副效应的最长相接子集，被称为副效应的可见序列。（ B 所确定的 M 的值，将是这些副效应之一所存储的值）

注意：线程间同步可归结为避免数据竞争（通过建立先发生于关系），及定义在何种条件下哪些副效应成为可见。

消费操作

带 memory_order_consume 或更强标签的原子加载是消费操作。注意 std::atomic_thread_fence 会施加比消费操作更强的同步要求。

获得操作

带 memory_order_acquire 或更强标签的原子加载是获得操作。互斥体 (Mutex) 上的 lock() 操作亦为获得操作。注意 std::atomic_thread_fence 会施加比获得操作更强的同步要求。

释放操作

带 memory_order_release 或更强标签的原子存储是释放操作。互斥体 (Mutex) 上的 unlock() 操作亦为释放操作。注意 std::atomic_thread_fence 会施加比释放操作更强的同步要求。

解释

宽松顺序

带标签 memory_order_relaxed 的原子操作无同步操作；它们不会在共时的内存访问间强加顺序。它们只保证原子性和修改顺序一致性。

例如，对于最初为零的 x 和 y ，

// 线程 1 ：
r1 = y.load(std::memory_order_relaxed); // A
x.store(r1, std::memory_order_relaxed); // B
// 线程 2 ：
r2 = x.load(std::memory_order_relaxed); // C
y.store(42, std::memory_order_relaxed); // D

允许产生结果 r1 == 42 && r2 == 42 ，因为即使线程 1 中 A 先序于 B 且线程 2 中 C 先序于 D ，却没有制约避免 y 的修改顺序中 D 先出现于 A ，而 x 的修改顺序中 B 先出现于 C 。 D 在 y 上的副效应，可能可见于线程 1 中的加载 A ，同时 B 在 x 上的副效应，可能可见于线程 2 中的加载 C 。

即使使用宽松内存模型，也不允许“无中生有”的值循环地依赖于其各自的计算，例如，对于最初为零的 x 和 y ，

// 线程1：
r1 = x.load(std::memory_order_relaxed);
if (r1 == 42) y.store(r1, std::memory_order_relaxed);
// 线程2：
r2 = y.load(memory_order_relaxed);
if (r2 == 42) x.store(42, std::memory_order_relaxed);

不允许产生结果 r1 == 42 && r2 == 42 ，因为存储 42 于 y 只在存储 42 于 x 后有可能，这又循环依赖于存储 42 于 y 。注意 C++14 前规范曾在技术上允许，但不推荐实现者如此实现。

 (C++14 起)

宽松内存顺序的典型使用是计数器自增，例如 std::shared_ptr 的引用计数器，因为这只要求原子性，但不要求顺序或同步（注意 std::shared_ptr 计数器自减要求与析构函数进行获得释放同步）

#include <vector>
#include <iostream>
#include <thread>
#include <atomic>

std::atomic<int> cnt = {0};

void f()
{
    for (int n = 0; n < 1000; ++n) {
        cnt.fetch_add(1, std::memory_order_relaxed);
    }
}

int main()
{
    std::vector<std::thread> v;
    for (int n = 0; n < 10; ++n) {
        v.emplace_back(f);
    }
    for (auto& t : v) {
        t.join();
    }
    std::cout << "Final counter value is " << cnt << '\n';
}

输出：

Final counter value is 10000

释放获得顺序

若线程 A 中的一个原子存储带标签 memory_order_release ，而线程 B 中来自同一变量的原子加载带标签 memory_order_acquire ，则从线程 A 的视角先发生于原子存储的所有内存写入（非原子及宽松原子的），在线程 B 中成为可见副效应，即一旦原子加载完成，则保证线程 B 能观察到线程 A 写入内存的所有内容。

同步仅建立在释放和获得同一原子对象的线程之间。其他线程可能看到与被同步线程的一者或两者相异的内存访问顺序。

在强顺序系统（ x86 、 SPARC TSO 、 IBM 主框架）上，释放获得顺序对于多数操作是自动进行的。无需为此同步模式添加额外的 CPU 指令，只有某些编译器优化受影响（例如，编译器被禁止将非原子存储移到原子存储-释放后，或将非原子加载移到原子加载-获得前）。在弱顺序系统（ ARM 、 Itanium 、 Power PC ）上，必须使用特别的 CPU 加载或内存栅栏指令。

互斥锁（例如 std::mutex 或原子自旋锁）是释放获得同步的例子：线程 A 释放锁而线程 B 获得它时，发生于线程 A 环境的临界区（释放之前）中的所有事件，必须对于执行同一临界区的线程 B （获得之后）可见。

#include <thread>
#include <atomic>
#include <cassert>
#include <string>

std::atomic<std::string*> ptr;
int data;

void producer()
{
    std::string* p  = new std::string("Hello");
    data = 42;
    ptr.store(p, std::memory_order_release);
}

void consumer()
{
    std::string* p2;
    while (!(p2 = ptr.load(std::memory_order_acquire)))
        ;
    assert(*p2 == "Hello"); // 绝无问题
    assert(data == 42); // 绝无问题
}

int main()
{
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join(); t2.join();
}

下例演示三个线程间传递性的释放获得顺序

#include <thread>
#include <atomic>
#include <cassert>
#include <vector>

std::vector<int> data;
std::atomic<int> flag = {0};

void thread_1()
{
    data.push_back(42);
    flag.store(1, std::memory_order_release);
}

void thread_2()
{
    int expected=1;
    while (!flag.compare_exchange_strong(expected, 2, std::memory_order_acq_rel)) {
        expected = 1;
    }
}

void thread_3()
{
    while (flag.load(std::memory_order_acquire) < 2)
        ;
    assert(data.at(0) == 42); // 决不出错
}

int main()
{
    std::thread a(thread_1);
    std::thread b(thread_2);
    std::thread c(thread_3);
    a.join(); b.join(); c.join();
}

释放消费顺序

若线程 A 中的原子存储带标签 memory_order_release 而线程 B 中来自同一对象的读取存储值的原子加载带标签 memory_order_consume ，则线程 A 视角中先发生于原子存储的所有内存写入（非原子和宽松原子的），会在线程 B 中该加载操作所携带依赖进入的操作中变成可见副效应，即一旦完成原子加载，则保证线程B中，使用从该加载获得的值的运算符和函数，能见到线程 A 写入内存的内容。

同步仅在释放和消费同一原子对象的线程间建立。其他线程能见到与被同步线程的一者或两者相异的内存访问顺序。

所有异于 DEC Alpha 的主流 CPU 上，依赖顺序是自动的，无需为此同步模式产生附加的 CPU 指令，只有某些编译器优化收益受影响（例如，编译器被禁止牵涉到依赖链的对象上的推测性加载）。

此顺序的典型使用情况，涉及对很少被写入的数据结构（安排表、配置、安全策略、防火墙规则等）的共时读取，和有指针中介发布的发布者-订阅者情形，即当生产者发布消费者能通过其访问信息的指针之时：无需令生产者写入内存的所有其他内容对消费者可见（这在弱顺序架构上可能是昂贵的操作）。这种场景的例子之一是 rcu 解引用。

细粒度依赖链控制可参阅 std::kill_dependency 及 [[carries_dependency]] 。

注意到 2015 年 2 月为止没有产品编译器跟踪依赖链：均将消费操作提升为获得操作。

释放消费顺序的规范正在修订中，而且暂时不鼓励使用 memory_order_consume 。

 (C++17 起)

此示例演示用于指针中介的发布的依赖定序同步：int data不由数据依赖关系关联到指向字符串的指针，从而其值在消费者中未定义。

#include <thread>
#include <atomic>
#include <cassert>
#include <string>

std::atomic<std::string*> ptr;
int data;

void producer()
{
    std::string* p  = new std::string("Hello");
    data = 42;
    ptr.store(p, std::memory_order_release);
}

void consumer()
{
    std::string* p2;
    while (!(p2 = ptr.load(std::memory_order_consume)))
        ;
    assert(*p2 == "Hello"); // 绝无出错： *p2 从 ptr 携带依赖
    assert(data == 42); // 可能也可能不会出错： data 不从 ptr 携带依赖
}

int main()
{
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join(); t2.join();
}

序列一致顺序

带标签 memory_order_seq_cst 的原子操作不仅以与释放/获得顺序相同的方式排序内存（在一个线程中先发生于存储的任何结果都变成进行加载的线程中的可见副效应），还对所有带此标签的内存操作建立单独全序。

正式而言，

每个加载原子对象 M 的 memory_order_seq_cst 操作 B ，观测到以下之一：

  • 修改 M 的上个操作 A 的结果，A 在单独全序中先出现于 B
  • 或若存在这种 A ，则 B 可能观测到某些 M 的修改结果，这些修改非 memory_order_seq_cst 而且不先发生于 A
  • 或若不存在这种 A ，则 B 可能观测到某些 M 的无关联修改，这些修改非 memory_order_seq_cst

若存在 memory_order_seq_cst的 std::atomic_thread_fence 操作 X 先序于 B ，则 B 观测到以下之一：

  • 在单独全序中先出现于 X 的上个 M 的 memory_order_seq_cst 修改
  • 在单独全序中后出现于它的某些 M 的无关联修改

设有一对 M 上的原子操作，称之为 A 和 B ，这里 A 写入、 B 读取 M 的值，若存在二个 memory_order_seq_cst 的 std::atomic_thread_fence X 和 Y ，且若 A 先序于 X ， Y 先序于 B ，且 X 在单独全序中先出现于 Y ，则 B 观测到二者之一：

  • A 的效应
  • 某些在 M 的修改顺序中后出现于 A 的无关联修改

设有一对 M 上的原子操作，称之为 A 和 B ，若符合下列条件之一，则 M 的修改顺序中 B 先发生于 A

  • 存在一个 memory_order_seq_cst 的 std::atomic_thread_fence X ，它满足 A 先序于 X ，且 X 在单独全序中先出现于 B
  • 或者，存在一个 memory_order_seq_cst 的 std::atomic_thread_fence Y ，它满足 Y 先序于 B ，且 A 在单独全序中先出现于 Y
  • 或者，存在 memory_order_seq_cst 的 std::atomic_thread_fence X 和 Y ，它们满足 A 先序于 X ， Y 先序于 B ，且 X 在单独全序中先出现于 Y

注意这表明：

1) 只要不带 memory_order_seq_cst 标签的原子操作进入局面，则立即丧失序列一致性
2) 序列一致栅栏仅为栅栏自身建立全序，而不为通常情况下的原子操作建立（先序于不是跨线程关系，不同于先发生于）
 (C++20 前)

正式而言，

某原子对象 M 上的原子操作连贯先序于 M 上的另一原子操作 B ，若下列任一为真：

1) A 是修改，而 B 读取 A 所存储的值
2) A 在 M 的修改顺序中前于 B
3) A 读取原子操作 X 所存储的值，而 X 在修改顺序中前于 B ，且 A 与 B 不是同一读修改写操作
4) A 连贯先序于 X ，而 X 连贯先序于 B

所有 memory_order_seq_cst 操作，包括栅栏上，有单独全序 S ，它满足下列制约：

1) 若 A 与 B 为 memory_order_seq_cst 操作，而 A 强先发生于 B ，则 A 在 S 中前于 B
2) 对于对象 M 上的每对原子操作 A 与 B ，其中 A 连贯先序于 B ：
a) 若 A 与 B 都是 memory_order_seq_cst 操作，则 S 中 A 前于 B
b) 若 A 是 memory_order_seq_cst 操作，而 B 先发生于 memory_order_seq_cst 栅栏 Y ，则 S 中 A 前于 Y
c) 若 memory_order_seq_cst 栅栏 X 先发生于 A ，而 B 为 memory_order_seq_cst 操作，则 S 中 X 前于 B
d) 若 memory_order_seq_cst 栅栏 X 先发生于 A ，而 B 先发生于 memory_order_seq_cst 栅栏 Y ，则 S 中 X 前于 Y

正式定义确保：

1) 单独全序与任何原子对象的修改顺序一致
2) memory_order_seq_cst 加载从最后的 memory_order_seq_cst 修改，或从某个不先发生于顺序中之前的 memory_order_seq_cst 修改操作的非 memory_order_seq_cst 修改之一获取其值。

单独全序可能与先发生于不一致。这允许 memory_order_acquire 与 memory_order_release 在某些 CPU 上的更高效实现。当 memory_order_acquire 及 memory_order_release 与 memory_order_seq_cst 混合时，这能产生惊异的结果。

例如，对于初值为零的 x 与 y ，

// 线程 1 ：
x.store(1, std::memory_order_seq_cst); // A
y.store(1, std::memory_order_release); // B
// 线程 2 ：
r1 = y.fetch_add(1, std::memory_order_seq_cst); // C
r2 = y.load(std::memory_order_relaxed); // D
// 线程 3 ：
y.store(3, std::memory_order_seq_cst); // E
r3 = x.load(std::memory_order_seq_cst); // F

允许这些操作产生 r1 == 1 && r2 == 3 && r3 == 0 的结果，其中 A 先发生于 C ，但 memory_order_seq_cst 的单独全序 C-E-F-A 中 C 前于 A （见 Lahav 等）。

注意：

1) 一旦不带 memory_order_seq_cst 标签的原子操作进入局面，程序的序列一致保证就会立即丧失
2) 多数情况下， memory_order_seq_cst 原子操作相对于同一线程所进行的其他原子操作可重排
 (C++20 起)

若在多生产者-多消费者的情形中，且所有消费者都必须以相同顺序观察到所有生产者的动作出现，则可能必须有序列顺序。

全序列顺序在所有多核系统上要求完全的内存栅栏 CPU 指令。这可能成为性能瓶颈，因为它强制受影响的内存访问传播到每个核心。

此示例演示序列一直顺序为必要的场合。任何其他顺序都可能触发assert，因为可能令线程c和d观测到原子对象x和y以相反顺序更改。

#include <thread>
#include <atomic>
#include <cassert>

std::atomic<bool> x = {false};
std::atomic<bool> y = {false};
std::atomic<int> z = {0};

void write_x()
{
    x.store(true, std::memory_order_seq_cst);
}

void write_y()
{
    y.store(true, std::memory_order_seq_cst);
}

void read_x_then_y()
{
    while (!x.load(std::memory_order_seq_cst))
        ;
    if (y.load(std::memory_order_seq_cst)) {
        ++z;
    }
}

void read_y_then_x()
{
    while (!y.load(std::memory_order_seq_cst))
        ;
    if (x.load(std::memory_order_seq_cst)) {
        ++z;
    }
}

int main()
{
    std::thread a(write_x);
    std::thread b(write_y);
    std::thread c(read_x_then_y);
    std::thread d(read_y_then_x);
    a.join(); b.join(); c.join(); d.join();
    assert(z.load() != 0);  // 决不发生
}

与 volatile 的关系

在执行线程中，不能将通过 volatile 泛左值的访问（读和写）重排到同线程内先序于或后序于它的可观测副效应（包含其他 volatile 访问）后，但不保证另一线程观察到此顺序，因为 volatile 访问不建立线程间同步。

另外， volatile 访问不是原子的（共时的读和写是数据竞争），且不排序内存（非 volatile 内存访问可以自由地重排到 volatile 访问前后）。

一个值得注意的例外是 Visual Studio ，其中默认设置下，每个 volatile 写拥有释放语义，而每个 volatile 读拥有获得语义（ MSDN ），故而可将 volatile 对象用于线程间同步。标准的 volatile 语义不可应用于多线程编程，尽管它们在应用到 sig_atomic_t 对象时，足以与例如运行于同一线程的 std::signal 处理函数交流。

参阅

外部链接

  • MOESI 协议
本节未完成
原因：我们在 QPI 、 MOESI 可能还有 Dragon 上找下好参考
  • x86-TSO ： x86 多处理器上严格而有用的程序员模型，P. Sewell 等， 2010
  • ARM 及 POWER 宽松内存模型的入门教程， P. Sewell 等 ， 2012
  • MESIF ：点对点互联的两跳缓存一致性协议， J.R. Goodman, H.H.J. Hum ， 2009


日期和时间工具

< cpp

C++ 包含对二类时间操作的支持：

  • chrono 库，以各种精度跟踪时间的类型的灵活汇集（如 std::chrono::time_point ）。
  • C 风格日期和时间工具（如 std::time ）。

std::chrono 库

chrono 库定义三种主要类型以及工具函数和常用 typedef 。

  • 时钟
  • 时长
  • 时间点

时钟

时钟由起点（或纪元）及计次频率组成。例如，时钟可以拥有 1970 年 1 月 1 日的纪元，和每一秒的计次。 C++ 定义数种时钟类型：

定义于头文件 <chrono>
定义于命名空间 std::chrono
system_clock (C++11) | 来自系统范畴实时时钟的挂钟时间 (类)
steady_clock (C++11) | 决不会调整的单调时钟 (类)
high_resolution_clock (C++11) | 拥有可用的最短嘀嗒周期的时钟 (类)
is_clockis_clock_v (C++20) | 确定类型是否为时钟 (Clock) (类模板) (变量模板)
utc_clock (C++20) | 协调世界时 (UTC) 的时钟 (Clock) (类)
tai_clock (C++20) | 国际原子时 (TAI) 的时钟 (Clock) (类)
gps_clock (C++20) | GPS 时间的时钟 (Clock) (类)
file_clock (C++20) | 用于文件时间的时钟 (Clock) (typedef)
local_t (C++20) | 表示本地时间的伪时钟 (类)

时间点

时间点是从特定时钟的纪元开始经过的时间时长。

定义于头文件 <chrono>
定义于命名空间 std::chrono
time_point (C++11) | 时间中的点 (类模板)
clock_time_conversion (C++20) | 定义如何转换一个时钟的时间点为另一个的特性类 (类模板)
clock_cast (C++20) | 转换一个时钟的时间点为另一个 (函数模板)

时长

时长由时间跨度组成，定义为某时间单位的某个计次数。例如，“ 42 秒”可表示为由 42 个 1 秒时间点位的计次所组成的时长。

定义于头文件 <chrono>
定义于命名空间 std::chrono
duration
(C++11)
 时间区间
(类模板)

当天时刻

hh_mm_ss 只要可能就将表示自午夜起经过时间的时长分割成时、分、秒和秒的小数部分。它主要是格式化工具。

定义于头文件 <chrono>
定义于命名空间 std::chrono
hh_mm_ss (C++20) | 表示当天时刻 (类模板)
is_amis_pmmake12make24 (C++20) | 在 12 时和 24 时格式当天时刻之间翻译 (函数)

日历

定义于头文件 <chrono>
定义于命名空间 std::chrono
last_spec (C++20) | 指示一个月中最后日期或星期的标签类 (类)
day (C++20) | 表示月之日期 (类)
month (C++20) | 表示年之月份 (类)
year (C++20) | 表示格里高利历中的年 (类)
weekday (C++20) | 表示格里高利历中星期之日 (类)
weekday_indexed (C++20) | 表示月份的第 n 个 weekday (类)
weekday_last (C++20) | 表示月份的最后一个 weekday (类)
month_day (C++20) | 表示特定 month 的特定 day (类)
month_day_last (C++20) | 表示特定 month 的最后一日 (类)
month_weekday (C++20) | 表示特定 month 的第 n 个 weekday (类)
month_weekday_last (C++20) | 表示特定 month 的最后一个 weekday (类)
year_month (C++20) | 表示特定 year 的特定 month (类)
year_month_day (C++20) | 表示特定的 year 、 month 和 day (类)
year_month_day_last (C++20) | 表示特定 year 和 month 的最后一日 (类)
year_month_weekday (C++20) | 表示特定 year 和 month 的第 n 个 weekday (类)
year_month_weekday_last (C++20) | 表示特定 year 和 month 的最后一个 weekday (类)
operator/ (C++20) | 创建格里高利历日期的约定语法 (函数)

时区

定义于头文件 <chrono>
定义于命名空间 std::chrono
tzdb (C++20) | 描述 IANA 时区数据库的副本 (类)
tzdb_list (C++20) | 表示 tzdb 的链表 (类)
get_tzdbget_tzdb_listreload_tzdbremote_version (C++20) | 访问和控制全球时区数据库信息 (函数)
locate_zone (C++20) | 定位基于其名称的 time_zone (函数)
current_zone (C++20) | 返回当前的 time_zone (函数)
time_zone (C++20) | 表示时区 (类)
sys_info (C++20) | 表示在特定时间点的关于时区的信息 (类)
local_info (C++20) | 表示关于从本地时间转换到 UNIX 时间的信息 (类)
choose (C++20) | 选择应如何解析歧义的本地时间 (枚举)
zoned_traits (C++20) | zoned_time 所用的时区指针的特性类 (类模板)
zoned_time (C++20) | 表示时区和时间点 (类)
leap_second (C++20) | 含有关于插入闰秒的信息 (类)
time_zone_link (C++20) | 表示时区的替用名 (类)
nonexistent_local_time (C++20) | 抛出以报告本地时间不存在的异常 (类)
ambiguous_local_time (C++20) | 抛出以报告本地时间有歧义的异常 (类)

chrono I/O

定义于头文件 <chrono>
定义于命名空间 std::chrono
parse
(C++20)
 从流分析 chrono 对象
(函数模板)

C 风格日期与时间库

亦提供 C 风格日期与时间函数，例如 std::time_t 、 std::difftime 和 CLOCKS_PER_SEC 。

示例

此示例显式关于函数调用执行时间的信息：

#include <iostream>
#include <chrono>

long fibonacci(unsigned n)
{
    if (n < 2) return n;
    return fibonacci(n-1) + fibonacci(n-2);
}

int main()
{
    auto start = std::chrono::steady_clock::now();
    std::cout << "f(42) = " << fibonacci(42) << '\n';
    auto end = std::chrono::steady_clock::now();
    std::chrono::duration<double> elapsed_seconds = std::chrono::duration<double>(end-start);

    std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";
}

可能的输出：

f(42) = 267914296
elapsed time: 2.25517s


std::chrono::ambiguous_local_time

< cpp‎ | chrono
定义于头文件 <chrono> |
class ambiguous_local_time; | (C++20 起)

定义要作为异常抛出的对象类型，以报告试图转换有歧义的 std::chrono::local_time 为 std::chrono::sys_time 而不指定 std::chrono::choose （如 choose::earliest 或 choose::latest ）。

std::chrono::time_zone::to_sys 和调用它的函数（例如接收 std::chrono::zoned_time 的 std::chrono::local_time 构造函数）抛出此异常。

cpp/error/exception cpp/error/runtime error std-chrono-ambiguous local time-inheritance.svg

继承图

成员函数

(构造函数) | 构造异常对象 (公开成员函数)
operator= | 替换异常对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::chrono::ambiguous_local_time::ambiguous_local_time

template< class Duration >

ambiguous_local_time(const std::chrono::local_time<Duration>& tp,

const std::chrono::local_info& i);
 (1) (C++20 起)
ambiguous_local_time( const ambiguous_local_time& other ) noexcept;
 (2) (C++20 起)

构造异常对象。

1) what() 所返回的解释字符串等价于下列代码后 os.str() 所产生者：
std::ostringstream os;
os << tp << " is ambiguous.  It could be\n"
   << tp << ' ' << i.first.abbrev << " == "
   << tp - i.first.offset << " UTC or\n"
   << tp << ' ' << i.second.abbrev  << " == "
   << tp - i.second.offset  << " UTC";
若 i.result != std::chrono::local_info::ambiguous 则行为未定义。
2) 复制构造函数。若 *this 与 other 均拥有动态类型 std::chrono::ambiguous_local_time 则 std::strcmp (what(), other.what()) == 0 。

参数

tp | - | 试图转换的时间点
i | - | 描述转换尝试的结果的 std::chrono::local_info
other | - | 要复制的另一 ambiguous_local_time

异常

可能抛出 std::bad_alloc

注解

因为不容许复制派生自 std::exception 的标准库类抛出异常，此信息通常在内部存储为分离分配的引用计数字符串。

std::chrono::ambiguous_locale_time::operator=

ambiguous_locale_time& operator=( const ambiguous_locale_time& other ) noexcept; | (C++20 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::chrono::ambiguous_locale_time 则赋值后 std::strcmp (what(), other.what()) == 0 。

参数

other - 用以赋值的另一异常对象

返回值

*this

std::chrono::ambiguous_locale_time::what

virtual const char* what() const noexcept; | (C++20 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::runtime_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)


C 日期和时间工具

< cpp‎ | chrono

函数

定义于头文件 <ctime>
时间操作
difftime
 计算时间之间的差
(函数)
time
 返回自纪元起计的系统当前时间
(函数)
clock
 返回自程序启动时起的原始处理器时钟时间
(函数)
timespec_get
(C++17)
 返回基于给定时间基底的日历时间
(函数)
格式转换
asctime
 转换 tm 对象为文本表示
(函数)
ctime
 转换 time_t 对象为文本表示
(函数)
strftime
 转换 tm 对象到自定义的文本表示
(函数)
wcsftime
 转换 tm 对象为定制的宽字符串文本表示
(函数)
gmtime
 转换纪元起时间为以协调世界时表示的日历时间
(函数)
localtime
 转换纪元起时间为以本地时间表示的日历时间
(函数)
mktime
 转换日历时间为纪元起的时间
(函数)

常量

CLOCKS_PER_SEC
 每秒的处理器始时钟嘀嗒数
(宏常量)

类型

tm | 日历时间类型 (类)
time_t | 从纪元起的时间类型 (typedef)
clock_t | 进程运行时间 (typedef)
timespec (C++17) | 以秒和纳秒表示的时间 (结构体)

参阅


CLOCKS_PER_SEC

< cpp‎ | chrono‎ | c
定义于头文件 <ctime>
#define CLOCKS_PER_SEC /*implementation defined*/

展开成 std::clock_t 类型表达式，值等于每秒 std::clock() 所返回的时钟计次数（不必是编译时常量）。

注意

POSIX 定义 CLOCKS_PER_SEC 为一百万，无关乎 std::clock() 的实际精度。

参阅

clock | 返回自程序启动时起的原始处理器时钟时间 (函数)
clock_t | 进程运行时间 (typedef)


std::asctime

< cpp‎ | chrono‎ | c
定义于头文件 <ctime>
char* asctime( const std::tm * time_ptr );

转换给定日历时间 std::tm 为拥有下列固定 25 字符形式的文本表示： Www Mmm dd hh:mm:ss yyyy\n

  • Www ——星期之日的三字母英文缩写，来自 time_ptr->tm_wday ，为 Mon 、 Tue 、 Wed 、 Thu 、 Fri 、 Sat 、 Sun 之一。
  • Mmm ——月名的三字母英文缩写，来自 time_ptr->tm_mon ，为 Jan 、 Feb 、 Mar 、 Apr 、 May 、 Jun 、 Jul 、 Aug 、 Sep 、 Oct 、 Nov 、 Dec 之一。
  • dd —— 2 位数月之日 ，来自 timeptr->tm_mday ，如同 sprintf 用 %2d 打印
  • hh —— 2 位小时，来自 timeptr->tm_hour ，如同 sprintf 用 %.2d 打印
  • mm —— 2 位分，来自 timeptr->tm_min ，如同 sprintf 用 %.2d 打印
  • ss —— 2 位秒，来自 timeptr->tm_sec ，如同 sprintf 用 %.2d 打印
  • yyyy —— 4 位年，来自 timeptr->tm_year + 1900 ，如同 sprintf 用 %4d 打印

若 *time_ptr 的任何成员在其正常范围外，则行为未定义。

若 time_ptr->tm_year 所指示的日历年份多于 4 位数字或小于 1000 年，则行为未定义。

函数不支持本地化，而写不能移除换行符。

函数修改静态存储，而且不是线程安全的。

参数

time_ptr - 指向指定要打印时间的 std::tm 对象的指针

返回值

指向空终止字符串的指针，字符串保有日期和时间的文本表示。字符串可能在 std::asctime 与 std::ctime 之间共享，而且可能在每次调用任何这些函数时被重写。

注意

此函数返回指向静态数据的指针，且非线程安全。 POSIX 标记此函数为过时，并推荐使用 std::strftime 替代。

POSIX 限制了仅当输出字符串将长于 25 字符时、 timeptr->tm_wday 或 timeptr->tm_mon 不在预期范围时，或 timeptr->tm_year 超过 INT_MAX-1990 时是未定义行为。

一些实现把 timeptr->tm_mday==0 处理成上个月最后一天的含义。

示例

#include <ctime>
#include <iostream>

int main()
{
    std::time_t result = std::time(NULL);
    std::cout << std::asctime(std::localtime(&result));
}

输出：

Mon Apr  3 20:26:26 2017

参阅

ctime | 转换 time_t 对象为文本表示 (函数)
strftime | 转换 tm 对象到自定义的文本表示 (函数)
put_time (C++11) | 按照指定格式格式化并输出日期/时间值 (函数模板)


std::clock

< cpp‎ | chrono‎ | c
定义于头文件 <ctime>
std::clock_t clock();

返回进程从关联到程序执行的实现定义时期开始，所用的粗略处理器时间。为转换结果为秒，可将它除以 CLOCKS_PER_SEC 。

只有二次不同的 std::clock 调用所返回的值之差才有意义，因为 std::clock 时期的开始不必与程序的起始一致。 std::clock 可能前进快于或慢于现实时间，取决于操作系统给予程序的执行资源。例如，若与其他进程共享 CPU ，则 std::clock 时间的前进可能慢于现实时间。另一方面，若当前进程为多线程，且多于一个执行核心可用，则 std::clock 时间的前进可能快于现实时间。

参数

（无）

返回值

程序迄今为止所用的处理器时间。若该信息不可用，或若其值无法表示，则为 std::clock_t (-1) 。

异常

不抛出。

注解

在兼容 POSIX 的系统上，带时钟 id CLOCK_PROCESS_CPUTIME_ID 的 clock_gettime 提供更高的解析度。

clock() 返回的值会在一些不遵从的实现上回卷。例如在某种实现上，若 std::clock_t 为有符号 32 位整数而 CLOCKS_PER_SEC 为 1000000 ，则它将在约 2147 秒（约 36 分）后回卷。

示例

此示例演示 clock() 时间与真实时间的差异

#include <iostream>
#include <iomanip>
#include <chrono>
#include <ctime>
#include <thread>

// 函数 f() 做一些耗时工作
void f()
{
    volatile double d = 0;
    for(int n=0; n<10000; ++n)
       for(int m=0; m<10000; ++m) {
           double diff = d*n*m;
           d = diff + d;
       }
}

int main()
{
    std::clock_t c_start = std::clock();
    auto t_start = std::chrono::high_resolution_clock::now();
    std::thread t1(f);
    std::thread t2(f); // 在二个线程上调用 f()
    t1.join();
    t2.join();
    std::clock_t c_end = std::clock();
    auto t_end = std::chrono::high_resolution_clock::now();

    std::cout << std::fixed << std::setprecision(2) << "CPU time used: "
              << 1000.0 * (c_end - c_start) / CLOCKS_PER_SEC << " ms\n"
              << "Wall clock time passed: "
              << std::chrono::duration<double, std::milli>(t_end-t_start).count()
              << " ms\n";
}

可能的输出：

CPU time used: 1590.00 ms
Wall clock time passed: 808.23 ms

参阅

ctime | 转换 time_t 对象为文本表示 (函数)
time | 返回自纪元起计的系统当前时间 (函数)


std::clock_t

< cpp‎ | chrono‎ | c
定义于头文件 <ctime>
typedef /* unspecified */ clock_t;

足以表示实现定义范围和精度的进程运行时间的算术类型。

参阅

clock | 返回自程序启动时起的原始处理器时钟时间 (函数)
CLOCKS_PER_SEC | 每秒的处理器始时钟嘀嗒数 (宏常量)


std::ctime

< cpp‎ | chrono‎ | c
定义于头文件 <ctime>
char* ctime( const std::time_t * time );

转换给定的从纪元起时间为日历时间，再转换为文本表示，如同通过调用 std::asctime ( std::localtime (time)) 。 产生的字符串拥有如下格式：

Www Mmm dd hh:mm:ss yyyy\n
  • Www - 星期（ Mon 、 Tue 、 Wed 、 Thu 、 Fri 、 Sat 、 Sun 之一）。
  • Mmm - 月份（ Jan 、 Feb 、 Mar 、 Apr 、 May 、 Jun 、 Jul 、 Aug 、 Sep 、 Oct 、 Nov 、 Dec 之一）。
  • dd - 月之日
  • hh - 时
  • mm - 分
  • ss - 秒
  • yyyy - 年

函数不支持本地化。

参数

time - 指向指定要打印时间的 std::time_t 对象

返回值

返回指向静态空终止字符串的指针，字符串保有上述的日期和时间的文本表示。字符串可以在 std::asctime 和 std::ctime 间共享，并且可以被每次对这些函数的调用重写。

注意

ctime 返回指向静态数据的指针，而且非线程安全。另外它修改可能会为 std::gmtime 及 std::localtime 所共享的静态 std::tm 对象。 POSIX 标记此函数标为过时，并推荐用 std::strftime 替代。

对于导致字符串长于 25 字符（例如， 10000 年）的 time_t 的值， ctime 的行为可能未定义。

示例

#include <ctime>
#include <iostream>

int main()
{
    std::time_t result = std::time(nullptr);
    std::cout << std::ctime(&result);
}

输出：

Tue Dec 27 17:21:29 2011

参阅

asctime | 转换 tm 对象为文本表示 (函数)
strftime | 转换 tm 对象到自定义的文本表示 (函数)
put_time (C++11) | 按照指定格式格式化并输出日期/时间值 (函数模板)


std::difftime

< cpp‎ | chrono‎ | c
定义于头文件 <ctime>
double difftime( std::time_t time_end, std::time_t time_beg );

以秒计算二个作为 std::time_t 对象的日历时间差（ time_end - time_beg ）。若 time_end 指代 time_beg 之前的时间点，则结果为负。

参数

time_beg, time_end - 要比较的时间

返回值

以秒表示的二个时间的差。

注意

POSIX 系统上， std::time_t 以秒度量，而 difftime 等价于算术减法，但 C 和 C++ 允许 time_t 有分数单位。

示例

#include <iostream>
#include <ctime>

int main()
{
    std::time_t start = std::time(NULL);
    volatile double d;

    // 一些耗时操作
    for (int n=0; n<10000; ++n) {
        for (int m=0; m<100000; ++m) {
           d += d*n*m;
        }
    }

    std::cout << "Wall time passed: "
              << std::difftime(std::time(NULL), start) << " s.\n";
}

输出：

Wall time passed: 7 s.

参阅

duration
(C++11)
 时间区间
(类模板)


std::gmtime

< cpp‎ | chrono‎ | c
定义于头文件 <ctime>
std::tm * gmtime( const std::time_t * time );

将给定作为 std::time_t 值的从纪元起时间转换为以协调世界时（ UTC ）表达的日历时间。

参数

time - 指向要转换的 time_t 对象的指针

返回值

成功时为指向静态内部 std::tm 对象的指针，否则为 NULL 。该结构体可能在 std::gmtime 、 std::localtime 和 std::ctime 之间共享，并可能在每次调用时被覆盖。

注意

此函数可能不是线程安全的。

POSIX 要求若此函数因参数过大而失败，则设置 errno 为 EOVERFLOW 。

示例

#include <iostream>
#include <iomanip>
#include <ctime>

int main()
{
    std::time_t t = std::time(nullptr);
    std::cout << "UTC:   " << std::put_time(std::gmtime(&t), "%c %Z") << '\n';
    std::cout << "local: " << std::put_time(std::localtime(&t), "%c %Z") << '\n';
}

输出：

UTC:   Wed Dec 28 11:44:28 2011 GMT
local: Wed Dec 28 06:44:28 2011 EST

参阅

localtime
 转换纪元起时间为以本地时间表示的日历时间
(函数)


std::localtime

< cpp‎ | chrono‎ | c
定义于头文件 <ctime>
std::tm * localtime( const std::time_t *time );

转换作为 std::time_t 值的从纪元起时间到以本地时间表达的日历时。

参数

time - 指向要转换的 time_t 对象的指针

返回值

成功时为指向内部静态 std::tm 对象的指针，否则为 NULL 。该结构体可能在 std::gmtime 、 std::localtime 和 std::ctime 之间共享，而且可能在每次调用时被覆盖。

注意

此函数可能不是线程安全的。

POSIX 要求若此函数因参数过大而失败，则设置 errno 为 EOVERFLOW 。

POSIX 指定此函数如同以调用 tzset 确定时区信息，该函数调用环境变量 TZ 。

示例

#include <iostream>
#include <iomanip>
#include <ctime>
#include <stdlib.h> // 定义 putenv 于 POSIX

int main()
{
    std::time_t t = std::time(nullptr);
    std::cout << "UTC:       " << std::put_time(std::gmtime(&t), "%c %Z") << '\n';
    std::cout << "local:     " << std::put_time(std::localtime(&t), "%c %Z") << '\n';
    // POSIX 限定：
    std::string tz = "TZ=Asia/Singapore";
    putenv(tz.data());
    std::cout << "Singapore: " << std::put_time(std::localtime(&t), "%c %Z") << '\n';
}

输出：

UTC:       Fri Sep 15 14:16:29 2017 GMT
local:     Fri Sep 15 14:16:29 2017 UTC
Singapore: Fri Sep 15 22:16:29 2017 SGT

参阅

gmtime
 转换纪元起时间为以协调世界时表示的日历时间
(函数)


std::mktime

< cpp‎ | chrono‎ | c
定义于头文件 <ctime>
std::time_t mktime( std::tm * time );

转换本地日历时间为从纪元起的时间，作为 time_t 对象。忽略 time->tm_wday 与 time->tm_yday 。容许 time 中的值在其正常范围外。

time->tm_isdst 的负值会导致 mktime 尝试确定在指定时间夏时令是否有效。

若转换到 time_t 成功，则修改 time 会被修改。更新 time 的所有域为符合其正确范围的值。用可用于其他域的信息重新计算 time->tm_wday 与 time->tm_yday 。

参数

time - 指向 std::tm 对象的指针，它指定要转换的本地日历时间

返回值

成功时为表示从纪元开始时间的 std::time_t 对象，若 time 不能表示成 std::time_t 对象则返回 -1 （ POSIX 亦要求此情况下存储 EOVERFLOW 于 errno 中）。

注意

若 std::tm 对象从 std::get_time 或 POSIX strptime 获得，则 tm_isdst 的值不确定，而且需要在调用 mktime 前显式设置。

示例

显示 100 个月前的时间。

#include <iostream>
#include <iomanip>
#include <ctime>
#include <stdlib.h>

int main()
{
    setenv("TZ", "/usr/share/zoneinfo/America/New_York", 1); // POSIX 限定

    std::time_t t = std::time(nullptr);
    std::tm tm = *std::localtime(&t);
    std::cout << "Today is           " << std::put_time(&tm, "%c %Z")
              << " and DST is " << (tm.tm_isdst ? "in effect" : "not in effect") << '\n';
    tm.tm_mon -= 100;  // tm_mon 现在在正常范围外
    std::mktime(&tm);  // tm_dst 不被设为 -1 ；使用今日的 DST 状态
    std::cout << "100 months ago was " << std::put_time(&tm, "%c %Z")
              << " and DST was " << (tm.tm_isdst ? "in effect" : "not in effect") << '\n';
}

输出：

Today is           Fri Apr 22 11:40:36 2016 EDT and DST is in effect
100 months ago was Sat Dec 22 10:40:36 2007 EST and DST was not in effect

参阅

localtime
 转换纪元起时间为以本地时间表示的日历时间
(函数)


std::strftime

< cpp‎ | chrono‎ | c
定义于头文件 <ctime>
std::size_t strftime( char* str, std::size_t count, const char* format, const std::tm * time );

按照格式字符串 format ，转换来自给定的日历时间 time 的日期和时间信息，为空终止多字节字符串 str 。最多写入 count 字节。

参数

str - 指向输出用的字符数组首元素的指针
count - 写入的最大字节数
format - 指向空终止多字节字符串的指针，字符串指定转换格式。

格式字符串由零或更多个说明符和通常字符（除 % ）构成。所有通常字符，包括空终止字符，都会被复制到输出字符串而不加修改。每个转换说明符都始于 % 字符，可选地跟随 E 或 O 修饰符（若本地环境不支持则忽略），后随决定修饰符行为的字符。下列修饰符格式可用：

转换
说明符 		解释 使用的域
% 写字面的 % 。完整转换说明必须是 %% 。
n
(C++11) 		写换行符
t
(C++11) 		写水平制表符
年
Y | 以 4 位十进制数写年。 | tm_year
EY
(C++11) 		以替用方式写年。例如在 ja_JP 本地环境中，以“平成23年”取代“2011年”。 tm_year
y | 写年的末 2 位十进制数（范围[00,99]）。 | tm_year
Oy
(C++11) 		以替用数字系统写年的末 2 位数字。例如在 ja_JP 本地环境中以“十一”取代“11”。 tm_year
Ey
(C++11) 		将年写作从本地环境的替用时期 %EC 的偏移（本地环境依赖）。 tm_year
C
(C++11) 		写年的首 2 位十进制数（范围 [00,99] ）。 tm_year
EC
(C++11) 		以本地环境的替用表示写年份基底（时期），例如 ja_JP 中的“平成”。 tm_year
G
(C++11) 		写基于 ISO 8601 的年，即是包含指定星期的年份。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
g
(C++11) 		写基于 ISO 8601 的年，即是包含指定星期年份，的后 2 位数（范围 [00,99] ）。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
月
b | 写缩略月名，例如 Oct （本地环境依赖）。 | tm_mon
h
(C++11) 		与 b 同意。 tm_mon
B | 写完整月名，例如 October （本地环境依赖）。 | tm_mon
m | 将月写作十进制数（范围 [01,12] ）。 | tm_mon
Om
(C++11) 		以替用数字系统写月。例如 ja_JP 本地环境中“十二”取代“12”。 tm_mon
星期
U | 以十进制数写年的星期（星期日是星期的首日）（范围 [00,53] ）。 | tm_year, tm_wday, tm_yday
OU
(C++11) 		以替用数值系统写如同用 %U 的年的星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
W | 以十进制数写年的星期（星期一是星期的首日）（范围 [00,53] ）。 | tm_year, tm_wday, tm_yday
OW
(C++11) 		以替用数值系统写如同用 %W 的年的第星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
V
(C++11) 		写 ISO 8601 的年的星期（范围[00,53]）。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
OV
(C++11) 		以替用数值系统写如同用 %V 的年的星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
年/月之日
j | 以十进制数写年的第几日（范围 [001,366] ）。 | tm_yday
d | 以十进制数写月的第几日（范围 [01,31] ）。 | tm_mday
Od
(C++11) 		以替用数字系统写零基的月的第几日。例如 ja_JP 本地环境中“二十七”取代“ 27 ”。

单字符前加空格。

 tm_mday
e
(C++11) 		以十进制数写月的第几日（范围[01,31]）。

单数字前加空格。

 tm_mday
Oe
(C++11) 		以替用数字系统写一基的月的第几日。例如 ja_JP 本地环境中“二十七”取代“27”。

单字符前加空格。

 tm_mday
星期之日
a | 写缩略的星期日期名，例如 Fri （本地环境依赖）。 | tm_wday
A | 写完整的星期日期名，例如 Friday （本地环境依赖）。 | tm_wday
w | 以十进制数写星期日期，其中星期日是 0 （范围 [0-6] ）。 | tm_wday
Ow
(C++11) 		用替用数字系统写星期日期，其中星期日是 0 。例如 ja_JP 本地环境中“二”取代“2”。 tm_wday
u
(C++11) 		十进制数写星期日期，其中星期一是 1 （ ISO 8601 格式）（范围 [1-7] ）。 tm_wday
Ou
(C++11) 		用替用数字系统写星期日期，其中星期一是 1 。例如 ja_JP 本地环境中“二”取代“2”。 tm_wday
时、分、秒
H | 以十进制数写时， 24 小时制（范围 [00-23] ）。 | tm_hour
OH
(C++11) 		以替用数字系统写 24 小时制的时。例如 ja_JP 本地环境中“十八”取代“18”。 tm_hour
I | 以十进制数写时， 12 小时制（范围 [01,12] ）。 | tm_hour
OI
(C++11) 		以替用数字系统写 12 小时制的时。例如 ja_JP 本地环境中“六”取代“6”。 tm_hour
M | 以十进制数写分（范围 [00,59] ）。 | tm_min
OM
(C++11) 		以替用数字系统写分。例如 ja_JP 本地环境中“二十五”取代“25”。 tm_min
S | 以十进制数写秒（范围 [00,60] ）。 | tm_sec
OS
(C++11) 		以替用数字系统写秒。例如 ja_JP 本地环境中“二十四”取代“24”。 tm_sec
其他
c | 写标准日期时间字符串。例如 Sun Oct 17 04:41:13 2010 （本地环境依赖）。 | 全部
Ec
(C++11) 		写替用日期时间字符串。例如 ja_JP 本地环境中“平成23年”取代“2011年”。 全部
x | 写本地化的日期表示（本地环境依赖）。 | 全部
Ex
(C++11) 		写替用日期表示。例如 ja_JP 本地环境中“平成23年”取代“2011年”。 全部
X | 写本地化的时间表示，例如 18:40:20 或 6:40:20 PM （本地环境依赖）。 | 全部
EX
(C++11) 		写替用时间表示（本地环境依赖）。 全部
D
(C++11) 		等价于"%m/%d/%y"。 tm_mon, tm_mday, tm_year
F
(C++11) 		等价于"%Y-%m-%d"（ ISO 8601 日期格式）。 tm_mon, tm_mday, tm_year
r
(C++11) 		写本地化的 12 小时制时间（本地环境依赖）。 tm_hour, tm_min, tm_sec
R
(C++11) 		等价于"%H:%M"。 tm_hour, tm_min
T
(C++11) 		等价于"%H:%M:%S"（ ISO 8601 时间格式）。 tm_hour, tm_min, tm_sec
p | 写本地化的 a.m. 或 p.m. （本地环境依赖）。 | tm_hour
z
(C++11) 		以 ISO 8601 格式（例如 -0430 ）写距 UTC 的偏移，或者倘若时区信息不可用则不写字符。 tm_isdst
Z | 写依赖本地环境的时区名或缩写，或者若时区信息不可用则不写字符。 | tm_isdst

time - 指向待转换日期和时间信息的指针

返回值

成功时，返回写入 str 所指向的字符数组的字节数，不包含终止 '\0' 。若在能存储整个字符串前抵达 count ，则返回 ​0​ ，写入内容是未定义的。

示例

#include <ctime>
#include <iostream>
#include <locale>

int main()
{
    std::locale::global(std::locale("ja_JP.utf8"));
    std::time_t t = std::time(NULL);
    char mbstr[100];
    if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&t))) {
        std::cout << mbstr << '\n';
    }
}

输出：

火曜日 2011年12月27日 17時39分03秒

See also

asctime | 转换 tm 对象为文本表示 (函数)
ctime | 转换 time_t 对象为文本表示 (函数)
wcsftime | 转换 tm 对象为定制的宽字符串文本表示 (函数)
put_time (C++11) | 按照指定格式格式化并输出日期/时间值 (函数模板)


std::time

< cpp‎ | chrono‎ | c
定义于头文件 <ctime>
std::time_t time( std::time_t * arg );

返回编码为 std::time_t 对象的当前日历时间，并将它存储于 arg 所指向的对象，除非 arg 是空指针。

参数

arg - 指向要存储时间的 std::time_t 对象的指针，或空指针

返回值

成功时为编码为 std::time_t 的当前日历时间，错误时为 ( std::time_t )(-1) 。若 arg 非空，则亦存储返回值于 arg 所指向的对象。

注意

日历时间在 std::time_t 中的编码是未指定的，但多数系统遵循 POSIX 规定，返回保有从纪元开始至今秒数的整数类型值。 std::time_t 为32位有符号整数的实现（许多历史上的实现）会在 2038 年出错。

示例

#include <ctime>
#include <iostream>

int main()
{
    std::time_t result = std::time(nullptr);
    std::cout << std::asctime(std::localtime(&result))
              << result << " seconds since the Epoch\n";
}

输出：

Wed Sep 21 10:27:52 2011
1316615272 seconds since the Epoch

参阅

localtime | 转换纪元起时间为以本地时间表示的日历时间 (函数)
gmtime | 转换纪元起时间为以协调世界时表示的日历时间 (函数)
system_clock (C++11) | 来自系统范畴实时时钟的挂钟时间 (类)


std::time_t

< cpp‎ | chrono‎ | c
定义于头文件 <ctime>
typedef /* 未说明 */ time_t;

足以表示时间的算术类型。

虽然标准中没有给出定义，但是该类型几乎总是整数类型，表示自 1970 年 1 月 1 日 00:00 UTC 以来所经过的秒数（不计闰秒），对应 POSIX 时间。

参阅

time | 返回自纪元起计的系统当前时间 (函数)
localtime | 转换纪元起时间为以本地时间表示的日历时间 (函数)
gmtime | 转换纪元起时间为以协调世界时表示的日历时间 (函数)


std::timespec

< cpp‎ | chrono‎ | c
定义于头文件 <ctime> |
struct timespec; | (C++17 起)

保有时长的结构体，拆分成秒和纳秒。

成员对象

std::time_t tv_sec | 整秒 – >= 0
long tv_nsec | 纳秒 – [0, 999999999]

参阅

timespec_get (C++17) | 返回基于给定时间基底的日历时间 (函数)
tm | 日历时间类型 (类)


std::timespec_get

< cpp‎ | chrono‎ | c
定义于头文件 <ctime> |  |
int timespec_get( std::timespec * ts, int base ); | (1) | (C++17 起)
#define TIME_UTC /* implementation-defined */ | (2) | (C++17 起)
1) 修改 ts 所指向的 std::timespec 对象，以保有时间基底 base 中的当前日历时间。
2) 展开成适合用作 std::timespec_get 的 base 参数的值。

实现可提供其他以 TIME_ 起始的宏常量，以指示另外的时间基底。

若 base 为 TIME_UTC ，则

  • 设 ts->tv_sec 为从实现定义的纪元开始的秒数，截断到整数值
  • 设 ts->tv_nsec 成员为纳秒的整数，取整到系统时钟的分辨率

参数

ts | - | 指向 std::timespec 类型对象的指针
base | - | TIME_UTC 或另一指示时间基底的非零整数值

返回值

若成功则为 base 的值，否则为零。

注解

POSIX 函数 clock_gettime(CLOCK_REALTIME, ts) 亦可用于将从纪元开始的时间植入 std::timespec 。

示例

#include <cstdio>
#include <ctime>

int main()
{
    std::timespec ts;
    std::timespec_get(&ts, TIME_UTC);
    char buff[100];
    std::strftime(buff, sizeof buff, "%D %T", std::gmtime(&ts.tv_sec));
    std::printf("Current time: %s.%09ld UTC\n", buff, ts.tv_nsec);
}

可能的输出：

Current time: 06/24/16 20:07:42.949494132 UTC

参阅

timespec (C++17) | 以秒和纳秒表示的时间 (结构体)
time | 返回自纪元起计的系统当前时间 (函数)


std::tm

< cpp‎ | chrono‎ | c
定义于头文件 <ctime>
struct tm;

保有拆分到组分的日历日期和时间的结构体。

成员对象

int tm_sec | 分后之秒 – [0, 61] (C++11 前)[0, 60] (C++11 起)[注 1] (公开成员对象)
int tm_min | 时后之分 – [0, 59] (公开成员对象)
int tm_hour | 自午夜起之时 – [0, 23] (公开成员对象)
int tm_mday | 月之日 – [1, 31] (公开成员对象)
int tm_mon | 自一月起之月 – [0, 11] (公开成员对象)
int tm_year | 自 1900 起之年 (公开成员对象)
int tm_wday | 自星期日起之日 – [0, 6] (公开成员对象)
int tm_yday | 自一月 1 日起之日 – [0, 365] (公开成员对象)
int tm_isdst | 夏令时标志。值若夏令时有效则为正，若无效则为零，若无可用信息则为负 (公开成员对象)
注意

标准只强制前述成员按任一顺序存在。实现通常对此结构体添加额外的数据成员。

  1. ↑ 范围允许正闰秒。不允许同一分钟内的二个闰秒（ C89 中错误地引入范围 0..61 ，而在 C99 中更正）

示例

展示日历时间。

#include <ctime>
#include <iostream>

int main()
{
    std::tm start{};
    start.tm_mday = 1;

    std::mktime(&start);
    std::cout << std::asctime(&start)
              << "sizeof(std::tm) = "
              << sizeof(std::tm) << '\n';
}

可能的输出：

Mon Jan  1 00:00:00 1900
sizeof(std::tm) = 56

参阅

localtime | 转换纪元起时间为以本地时间表示的日历时间 (函数)
gmtime | 转换纪元起时间为以协调世界时表示的日历时间 (函数)


std::wcsftime

< cpp‎ | chrono‎ | c
定义于头文件 <cwchar>
std::size_t wcsftime( wchar_t* str, std::size_t count, const wchar_t* format, const std::tm * time );

按照格式字符串 format ，转换自给定的日历时间 time 的日期和时间信息，为空终止宽字符串 str 。最多写入 count 个宽字符。

参数

str - 指向待输出的 wchar_t 数组首元素的指针
count - 最大写入宽字符数
format - 指向指定转换格式的空终止宽字符串指针。

格式字符串由零或更多个说明符和通常字符（除 % ）构成。所有通常字符，包括空终止字符，都会被复制到输出字符串而不加修改。每个转换说明符都始于 % 字符，可选地跟随 E 或 O 修饰符（若本地环境不支持则忽略），后随决定修饰符行为的字符。下列修饰符格式可用：

转换
说明符 		解释 使用的域
% 写字面的 % 。完整转换说明必须是 %% 。
n
(C++11) 		写换行符
t
(C++11) 		写水平制表符
年
Y | 以 4 位十进制数写年。 | tm_year
EY
(C++11) 		以替用方式写年。例如在 ja_JP 本地环境中，以“平成23年”取代“2011年”。 tm_year
y | 写年的末 2 位十进制数（范围[00,99]）。 | tm_year
Oy
(C++11) 		以替用数字系统写年的末 2 位数字。例如在 ja_JP 本地环境中以“十一”取代“11”。 tm_year
Ey
(C++11) 		将年写作从本地环境的替用时期 %EC 的偏移（本地环境依赖）。 tm_year
C
(C++11) 		写年的首 2 位十进制数（范围 [00,99] ）。 tm_year
EC
(C++11) 		以本地环境的替用表示写年份基底（时期），例如 ja_JP 中的“平成”。 tm_year
G
(C++11) 		写基于 ISO 8601 的年，即是包含指定星期的年份。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
g
(C++11) 		写基于 ISO 8601 的年，即是包含指定星期年份，的后 2 位数（范围 [00,99] ）。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
月
b | 写缩略月名，例如 Oct （本地环境依赖）。 | tm_mon
h
(C++11) 		与 b 同意。 tm_mon
B | 写完整月名，例如 October （本地环境依赖）。 | tm_mon
m | 将月写作十进制数（范围 [01,12] ）。 | tm_mon
Om
(C++11) 		以替用数字系统写月。例如 ja_JP 本地环境中“十二”取代“12”。 tm_mon
星期
U | 以十进制数写年的星期（星期日是星期的首日）（范围 [00,53] ）。 | tm_year, tm_wday, tm_yday
OU
(C++11) 		以替用数值系统写如同用 %U 的年的星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
W | 以十进制数写年的星期（星期一是星期的首日）（范围 [00,53] ）。 | tm_year, tm_wday, tm_yday
OW
(C++11) 		以替用数值系统写如同用 %W 的年的第星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
V
(C++11) 		写 ISO 8601 的年的星期（范围[00,53]）。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
OV
(C++11) 		以替用数值系统写如同用 %V 的年的星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
年/月之日
j | 以十进制数写年的第几日（范围 [001,366] ）。 | tm_yday
d | 以十进制数写月的第几日（范围 [01,31] ）。 | tm_mday
Od
(C++11) 		以替用数字系统写零基的月的第几日。例如 ja_JP 本地环境中“二十七”取代“ 27 ”。

单字符前加空格。

 tm_mday
e
(C++11) 		以十进制数写月的第几日（范围[01,31]）。

单数字前加空格。

 tm_mday
Oe
(C++11) 		以替用数字系统写一基的月的第几日。例如 ja_JP 本地环境中“二十七”取代“27”。

单字符前加空格。

 tm_mday
星期之日
a | 写缩略的星期日期名，例如 Fri （本地环境依赖）。 | tm_wday
A | 写完整的星期日期名，例如 Friday （本地环境依赖）。 | tm_wday
w | 以十进制数写星期日期，其中星期日是 0 （范围 [0-6] ）。 | tm_wday
Ow
(C++11) 		用替用数字系统写星期日期，其中星期日是 0 。例如 ja_JP 本地环境中“二”取代“2”。 tm_wday
u
(C++11) 		十进制数写星期日期，其中星期一是 1 （ ISO 8601 格式）（范围 [1-7] ）。 tm_wday
Ou
(C++11) 		用替用数字系统写星期日期，其中星期一是 1 。例如 ja_JP 本地环境中“二”取代“2”。 tm_wday
时、分、秒
H | 以十进制数写时， 24 小时制（范围 [00-23] ）。 | tm_hour
OH
(C++11) 		以替用数字系统写 24 小时制的时。例如 ja_JP 本地环境中“十八”取代“18”。 tm_hour
I | 以十进制数写时， 12 小时制（范围 [01,12] ）。 | tm_hour
OI
(C++11) 		以替用数字系统写 12 小时制的时。例如 ja_JP 本地环境中“六”取代“6”。 tm_hour
M | 以十进制数写分（范围 [00,59] ）。 | tm_min
OM
(C++11) 		以替用数字系统写分。例如 ja_JP 本地环境中“二十五”取代“25”。 tm_min
S | 以十进制数写秒（范围 [00,60] ）。 | tm_sec
OS
(C++11) 		以替用数字系统写秒。例如 ja_JP 本地环境中“二十四”取代“24”。 tm_sec
其他
c | 写标准日期时间字符串。例如 Sun Oct 17 04:41:13 2010 （本地环境依赖）。 | 全部
Ec
(C++11) 		写替用日期时间字符串。例如 ja_JP 本地环境中“平成23年”取代“2011年”。 全部
x | 写本地化的日期表示（本地环境依赖）。 | 全部
Ex
(C++11) 		写替用日期表示。例如 ja_JP 本地环境中“平成23年”取代“2011年”。 全部
X | 写本地化的时间表示，例如 18:40:20 或 6:40:20 PM （本地环境依赖）。 | 全部
EX
(C++11) 		写替用时间表示（本地环境依赖）。 全部
D
(C++11) 		等价于"%m/%d/%y"。 tm_mon, tm_mday, tm_year
F
(C++11) 		等价于"%Y-%m-%d"（ ISO 8601 日期格式）。 tm_mon, tm_mday, tm_year
r
(C++11) 		写本地化的 12 小时制时间（本地环境依赖）。 tm_hour, tm_min, tm_sec
R
(C++11) 		等价于"%H:%M"。 tm_hour, tm_min
T
(C++11) 		等价于"%H:%M:%S"（ ISO 8601 时间格式）。 tm_hour, tm_min, tm_sec
p | 写本地化的 a.m. 或 p.m. （本地环境依赖）。 | tm_hour
z
(C++11) 		以 ISO 8601 格式（例如 -0430 ）写距 UTC 的偏移，或者倘若时区信息不可用则不写字符。 tm_isdst
Z | 写依赖本地环境的时区名或缩写，或者若时区信息不可用则不写字符。 | tm_isdst

time - 指向要转换的日期和时间信息的指针

返回值

成功时，返回写入 str 所指向的宽字符数组的字符数，不包含终止 L'\0' 。若在能存储整个字符串前抵达 count ，则返回 ​0​ ，写入内容是未定义的。

注意

#include <ctime>
#include <cwchar>
#include <iostream>
#include <locale>

int main()
{
    std::locale::global(std::locale("ja_JP.utf8"));
    std::time_t t = std::time(NULL);
    wchar_t wstr[100];
    if(std::wcsftime(wstr, 100, L"%A %c", std::localtime(&t))) {
        std::wcout << wstr << '\n';
    }
}

输出：

火曜日 2011年12月27日 17時43分13秒

参阅

strftime | 转换 tm 对象到自定义的文本表示 (函数)
put_time (C++11) | 按照指定格式格式化并输出日期/时间值 (函数模板)


std::chrono::choose

< cpp‎ | chrono
定义于头文件 <chrono> |
enum class choose { earliest, latest }; | (C++20 起)

能将有作用域枚举 choose 传递给 std::chrono::time_zone 和 std::chrono::zoned_time 的一些成员函数，以确定如何解析歧义或不存在的本地时间。传递 choose::earliest 导致返回较早的时间点，而传递 choose::latest 导致返回较迟的时间点。（对于不存在的本地时间，二个时间点是等同的。）

若不传递 choose 且遇到有歧义或不存在的本地时间，则将抛出 std::chrono::ambiguous_local_time 或 std::chrono::nonexistent_local_time 异常（其中的适用者）。


std::chrono::clock_cast

< cpp‎ | chrono
定义于头文件 <chrono> |
template <class Dest, class Source, class Duration> auto clock_cast(const std::chrono::time_point <Source, Duration>& t); | (C++20 起)

转换时钟 Source 的时间点 t 为时钟 Dest 的等价时间点，必要时以 std::chrono::system_clock 和/或 std::chrono::utc_clock 作为中介。

  • 若表达式 std::chrono::clock_time_conversion<Dest, Source>{}(t) 为良构，则返回该表达式的结果。
  • 否则，若下列二个表达式至少有一个为良构，则
  • 若二个表达式均为良构，则转换有歧义，而程序为谬构。
  • 否则，二个表达式恰有一个为良构；返回该表达式的结果。
1) std::chrono::clock_time_conversion<Dest, std::chrono::system_clock >{}(
std::chrono::clock_time_conversion< std::chrono::system_clock, Source>{}(t))
2) std::chrono::clock_time_conversion<Dest, std::chrono::utc_clock>{}(
std::chrono::clock_time_conversion<std::chrono::utc_clock, Source>{}(t))
  • 否则，若下列二个表达式至少有一个为良构，则
  • 若两个表达式均为良构，则转换有歧义，而程序为谬构。
  • 否则，二个表达式恰有一个为良构；返回该表达式的结果。
1) std::chrono::clock_time_conversion<Dest, std::chrono::utc_clock>{}(

std::chrono::clock_time_conversion<std::chrono::utc_clock, std::chrono::system_clock >{}(

std::chrono::clock_time_conversion< std::chrono::system_clock, Source>{}(t)))
2) std::chrono::clock_time_conversion<Dest, std::chrono::system_clock >{}(

std::chrono::clock_time_conversion< std::chrono::system_clock, std::chrono::utc_clock>{}(

std::chrono::clock_time_conversion<std::chrono::utc_clock, Source>{}(t)))
  • 否则，此函数不参与重载决议。

返回值

上面确定的转换结果。

示例

本节未完成
原因：暂无示例

参阅

clock_time_conversion
(C++20)
 定义如何转换一个时钟的时间点为另一个的特性类
(类模板)


std::chrono::clock_time_conversion

< cpp‎ | chrono
定义于头文件 <chrono> |
template<class Dest, class Source> struct clock_time_conversion { }; | (C++20 起)

std::chrono::clock_time_conversion 是特性类，指定如何转换 Source 时钟的 std::chrono::time_point 到 Dest 时钟的时间点。它通过提供 const 可调用的，接受 std::chrono::time_point <Source, Duration> 类型参数并返回表示等价时间点的 std::chrono::time_point <Dest, OtherDuration> 的 operator() 进行转换。以对每个特化有所变化的方式，计算返回时间点的时长。通常只通过 std::chrono::clock_cast 间接使用 clock_time_conversion 。

程序可以特化 clock_time_conversion ，若至少一个模板形参是用户定义类型。

初等模板是空 struct 。标准定义下列特化：

template<class Clock> struct clock_time_conversion<Clock, Clock>; | (1) | (C++20 起)
template<> struct clock_time_conversion< std::chrono::system_clock, std::chrono::system_clock >; | (2) | (C++20 起)
template<> struct clock_time_conversion<std::chrono::utc_clock, std::chrono::utc_clock>; | (3) | (C++20 起)
template<> struct clock_time_conversion< std::chrono::system_clock, std::chrono::utc_clock>; | (4) | (C++20 起)
template<> struct clock_time_conversion<std::chrono::utc_clock, std::chrono::system_clock >; | (5) | (C++20 起)
template<class Clock> struct clock_time_conversion<Clock, std::chrono::system_clock >; | (6) | (C++20 起)
template<class Clock> struct clock_time_conversion< std::chrono::system_clock, Clock>; | (7) | (C++20 起)
template<class Clock> struct clock_time_conversion<Clock, std::chrono::utc_clock>; | (8) | (C++20 起)
template<class Clock> struct clock_time_conversion<std::chrono::utc_clock, Clock>; | (9) | (C++20 起)
1-3) 恒等转换： operator() 返回参数的副本。
4-5) std::chrono::sys_time 与 std::chrono::utc_time 间的转换： operator() 分别调用 std::chrono::utc_clock::to_sys 和 std::chrono::utc_clock::from_sys 。
6-7) Clock 支持 from_sys 和 to_sys 时，来自和到 std::chrono::sys_time 的转换： operator() 分别调用 Clock::to_sys 和 Clock::from_sys 。
8-9) Clock 支持 from_utc 和 to_utc 时，来自和到 std::chrono::utc_time 的转换： operator() 分别调用 Clock::to_utc 和 Clock::from_utc 。

成员函数

每个特化都有隐式声明的默认构造函数、复制构造函数、移动构造函数、复制赋值运算符、移动赋值运算符和析构函数。

std::chrono::clock_time_conversion::operator()

template <class Duration>

std::chrono::time_point <Clock, Duration>

operator()(const std::chrono::time_point <Clock, Duration>& t) const;
 (1) (特化 (1) 的成员)
template <class Duration>

std::chrono::sys_time<Duration>

operator()(const std::chrono::sys_time<Duration> & t) const;
 (2) (特化 (2) 的成员)
template <class Duration>

std::chrono::utc_time<Duration>

operator()(const std::chrono::utc_time<Duration>& t) const;
 (3) (特化 (3) 的成员)
template <class Duration>

std::chrono::sys_time<Duration>

operator()(const std::chrono::utc_time<Duration>& t) const;
 (4) (特化 (4) 的成员)
template <class Duration>

std::chrono::utc_time<Duration>

operator()(const std::chrono::sys_time<Duration>& t) const;
 (5) (特化 (5) 的成员)
template <class Duration>

auto operator()(const std::chrono::sys_time<Duration>& t) const

-> decltype(Clock::from_sys(t));
 (6) (特化 (6) 的成员)
template <class Duration>

auto operator()(const std::chrono::time_point <SourceClock, Duration>& t) const

-> decltype(Clock::to_sys(t));
 (7) (特化 (7) 的成员)
template <class Duration>

auto operator()(const std::chrono::utc_time<Duration>& t) const

-> decltype(Clock::from_utc(t));
 (8) (特化 (8) 的成员)
template <class Duration>

auto operator()(const std::chrono::time_point <Clock, Duration>& t) const

-> decltype(Clock::to_utc(t));
 (9) (特化 (9) 的成员)

转换参数 std::chrono::time_point 为目标时钟。

1-3) 恒等转换。返回不更改的 t 。
4) 返回 std::chrono::utc_clock::to_sys(t) 。
5) 返回 std::chrono::utc_clock::from_sys(t) 。
6) 返回 Clock::from_sys(t) 。此重载仅若表达式 Clock::from_sys(t) 为良式才参与重载决议。若 Clock::from_sys(t) 不返回 std::chrono::time_point <Clock, Duration> ，其中 Duration 是 std::chrono::duration 的某个合法特化，则程序为病式。
7) 返回 Clock::to_sys(t) 。此重载仅若表达式 Clock::to_sys(t) 为良式才参与重载决议。若 Clock::to_sys(t) 不返回 std::chrono::sys_time<Duration> ，其中 Duration 是 std::chrono::duration 的某个合法特化，则程序为病式。
8) Returns Clock::from_utc(t) 。此重载仅若表达式 Clock::from_utc(t) 为良式才参与重载决议。若 Clock::from_utc(t)不返回 std::chrono::time_point <Clock, Duration> ，其中 Duration 是 std::chrono::duration 的某个合法特化，则程序为病式。
9) 返回 Clock::to_utc(t) 。此重载仅若表达式 Clock::to_utc(t) 为良式才参与重载决议。若 Clock::to_utc(t) 不返回 std::chrono::utc_time<Duration> ，其中 Duration 是 std::chrono::duration 的某个合法特化，则程序为病式。

参数

t - 要转化的时间点

返回值

上述的转换结果：

1-3) t 。
4) std::chrono::utc_clock::to_sys(t) 。
5) std::chrono::utc_clock::from_sys(t) 。
6) Clock::from_sys(t) 。
7) Clock::to_sys(t) 。
8) Clock::from_utc(t) 。
9) Clock::to_utc(t) 。

参阅

clock_cast
(C++20)
 转换一个时钟的时间点为另一个
(函数模板)


std::chrono::current_zone

< cpp‎ | chrono
定义于头文件 <chrono> |
const std::chrono::time_zone* current_zone(); | (C++20 起)

从时区数据库获得本地时区的便利函数。等价于 std::chrono::get_tzdb().current_zone() 。

异常

若这次调用是对时区数据库的首次引用且无法初始化时区数据库，则抛出 std::runtime_error 。

注意

若对此函数的调用是对时区数据库的首次引用，则它将导致初始化时区数据库。

参阅

current_zone | 返回本地时区 (std::chrono::tzdb 的公开成员函数)
get_tzdbget_tzdb_listreload_tzdbremote_version (C++20) | 访问和控制全球时区数据库信息 (函数)


std::chrono::day

< cpp‎ | chrono
定义于头文件 <chrono> |
class day; | (C++20 起)

类 day 表示月中的日。其正常范围为 [1, 31] ，但它可以保有 [0, 255] 中的任何数。

day 为可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 day (公开成员函数)
operator++operator++(int)operator--operator--(int) | 自增或自减 day (公开成员函数)
operator+=operator-= | 加或减日数 (公开成员函数)
operator unsigned | 获得存储的日期值 (公开成员函数)
ok | 检查存储的日期值是否在正常范围中 (公开成员函数)

非成员函数

operator==operator<=> (C++20) | 比较二个 day 值 (函数)
operator+operator- (C++20) | 加或减日数和 day ，或求二个 day 间的差 (函数)
operator<< (C++20) | 输出 day 到流 (函数模板)
from_stream (C++20) | 按照提供的格式从流分析 day (函数模板)

辅助类

std::formatter<std::chrono::day>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 day
(类模板特化)

字面量

定义于内联命名空间 std::literals::chrono_literals
operator""d
(C++20)
 表示月内日期的 std::chrono::day 字面量
(函数)


std::chrono::day::day

< cpp‎ | chrono‎ | day
day() = default; | (1) | (C++20 起)
explicit constexpr day(unsigned d) noexcept; | (2) | (C++20 起)

构造 day 对象。

1) 默认构造函数将日期值保持未初始化。
2) 若 d <= 255 ，则构造保有日期值 d 的 day 对象。否则值未指定。


std::chrono::day::ok

< cpp‎ | chrono‎ | day
constexpr bool ok() const noexcept; | (C++20 起)

检查存储于 *this 中的日期是否在合法范围，即 [1, 31] 中。

返回值

若存储于 *this 的日期值在范围 [1, 31] 中则为 true 。否则为 false 。


std::chrono::day::operator+=, std::chrono::day::operator-=

< cpp‎ | chrono‎ | day
constexpr day& operator+=(const std::chrono::days& d) noexcept; | (1) | (C++20 起)
constexpr day& operator-=(const std::chrono::days& d) noexcept; | (2) | (C++20 起)

从日期值加或减 d.count() 日。

1) 等价于 *this = *this + d;
2) 等价于 *this = *this - d;

返回值

到修改后的此 day 的引用

注意

若结果会在范围 [0, 255] 外，则实际存储值未指定。

示例

#include <cassert>
#include <chrono>

int main()
{
    std::chrono::day d {15};

    d += std::chrono::days(2);
    assert(d == std::chrono::day(17));

    d -= std::chrono::days{3};
    assert(d == std::chrono::day(14));
}

参阅

operator++operator++(int)operator--operator--(int) | 自增或自减 day (公开成员函数)
operator+operator- (C++20) | 加或减日数和 day ，或求二个 day 间的差 (函数)


std::chrono::operator+, std::chrono::operator- (std::chrono::day)

< cpp‎ | chrono‎ | day
constexpr std::chrono::day operator+(const std::chrono::day& d,
const std::chrono::days& ds) noexcept;
 (1) (C++20 起)
constexpr std::chrono::day operator+(const std::chrono::days& ds,
const std::chrono::day& d) noexcept;
 (2) (C++20 起)
constexpr std::chrono::day operator-(const std::chrono::day& d,
const std::chrono::days& ds) noexcept;
 (3) (C++20 起)
constexpr std::chrono::days operator-(const std::chrono::day& x,
const std::chrono::day& y) noexcept;
 (4) (C++20 起)
1-2) 加 ds.count() 日到 d 。
3) 从 d 减去 ds.count() 日。
4) 以 days 计算二个 day x 与 y 间的差。

返回值

1-2) std::chrono::day(unsigned(d) + ds.count())
3) std::chrono::day(unsigned(d) - ds.count())
4) std::chrono::days(int(unsigned(x)) - int(unsigned(y)))

注意

对于 (1-3) ，若结果会在范围 [0, 255] 外，则实际存储值未指定。

示例

#include <chrono>
#include <cassert>

int main()
{
    std::chrono::day d {15};

    d = d + std::chrono::days(2);
    assert(d == std::chrono::day(17));

    d = d - std::chrono::days(3);
    assert(d == std::chrono::day(14));

    constexpr std::chrono::days ds = std::chrono::day(16) - std::chrono::day(14);
    static_assert(ds == std::chrono::days(2));
}

参阅

operator++operator++(int)operator--operator--(int) | 自增或自减 day (公开成员函数)
operator+=operator-= | 加或减日数 (公开成员函数)


std::chrono::operator==,<=>(std::chrono::day)

< cpp‎ | chrono‎ | day
定义于头文件 <chrono>
constexpr bool operator==( const std::chrono::day& x,
const std::chrono::day& y ) noexcept;
 (1) (C++20 起)
constexpr std::strong_ordering operator<=>( const std::chrono::day& x,
const std::chrono::day& y ) noexcept;
 (2) (C++20 起)

比较二个 std::chrono::day x 和 y 。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

返回值

1) unsigned(x) == unsigned(y)
2) unsigned(x) <=> unsigned(y)

示例

#include <iostream>
#include <chrono>

int main()
{
    std::chrono::day d1{15};
    std::chrono::day d2{20};

    d1 == d2 ? std::cout << "d1 and d2 are equal\n"
             : std::cout << "d1 and d2 are not equal\n";

    using namespace std::literals::chrono_literals;

    std::cout << std::boolalpha
              << (6d < 9d) << ' ' << (6d == 6d) << ' ' << (6d <= 9d) << ' '
              << (9d > 6d) << ' ' << (9d != 6d) << ' ' << (9d >= 6d) << '\n';
}

输出：

d1 and d2 are not equal
true true true true true true


std::chrono::day::operator++, std::chrono::day::operator--

< cpp‎ | chrono‎ | day
constexpr day& operator++(); | (1) | (C++20 起)
constexpr day operator++(int); | (2) | (C++20 起)
constexpr day& operator--(); | (3) | (C++20 起)
constexpr day operator--(int); | (4) | (C++20 起)

从日期值加或减 1 。

1-2) 进行 *this += std::chrono::days{1};
3-4) 进行 *this -= std::chrono::days{1};

参数

（无）

返回值

1,3) 到修改后的此 day 的引用
2,4) 修改前所作的 day 副本

注意

若结果会在范围 [0, 255] 外，则实际存储值未指定。

示例

#include <cassert>
#include <chrono>

int main()
{
    std::chrono::day d {15};

    ++d;
    assert(d == std::chrono::day(16));

    --d;
    assert(d == std::chrono::day(15));
}

参阅

operator+=operator-= | 加或减日数 (公开成员函数)
operator+operator- (C++20) | 加或减日数和 day ，或求二个 day 间的差 (函数)


std::chrono::operator<<(std::chrono::day)

< cpp‎ | chrono‎ | day
template <class CharT, class Traits>

std::basic_ostream <CharT, Traits>&

operator<<( std::basic_ostream <CharT, Traits>& os, const std::chrono::day& d);
 (C++20 起)

由格式化为十进制数的存储于 d 的日期值，若结果会为单个十进制位则带前导零，构成 std::basic_string<CharT> s 。然后若 !d.ok() 则后附 " is not a valid day" 到格式化的字符串。插入该字符串到 os 中。

等价于

return os << (d.ok() ?
std::format(STATICALLY_WIDEN<CharT>("{:%d}"), d) :
std::format(STATICALLY_WIDEN<CharT>("{:%d} is not a valid day"), d));

其中 STATICALLY_WIDEN<CharT>("...") 若 CharT 为 char 则为 "..." ，而若 CharT 为 wchar_t 则为 L"..." 。

返回值

os 。

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::day> (C++20) | std::formatter 的特化，按照提供的格式格式化 day (类模板特化)


std::chrono::day::operator unsigned

< cpp‎ | chrono‎ | day
explicit constexpr operator unsigned() const noexcept; | (C++20 起)

返回存储于 *this 的日期值。

返回值

存储于 *this 的日期值。


std::chrono::duration

< cpp‎ | chrono
定义于头文件 <chrono> |
template< class Rep, class Period = std::ratio <1> > class duration; | (C++11 起)

类模板 std::chrono::duration 表示时间间隔。

它由 Rep 类型的计次数和计次周期组成，其中计次周期是一个编译期有理数常量，表示从一个计次到下一个的秒数。

存储于 duration 的数据仅有 Rep 类型的计次数。若 Rep 是浮点数，则 duration 能表示小数的计次数。 Period 被包含为时长类型的一部分，且只在不同时长间转换时使用。

成员类型

成员类型 | 定义
rep | Rep ，表示计次数的算术类型
period | Period (C++17 前)typename Period::type (C++17 起) ，表示计次周期的 std::ratio （即每秒的次数）

成员函数

(构造函数) | 构造新 duration (公开成员函数)
operator= | 赋值内容 (公开成员函数)
count | 返回计次的计数 (公开成员函数)
zero [静态] | 返回特殊时长值零 (公开静态成员函数)
min [静态] | 返回特殊时长值最小值 (公开静态成员函数)
max [静态] | 返回特殊时长值最大值 (公开静态成员函数)
operator+operator- | 实现一元 + 和一元 - (公开成员函数)
operator++operator++(int)operator--operator--(int) | 递增或递减滴答计数 (公开成员函数)
operator+=operator-=operator*=operator/=operator%= | 实现二个时长间的复合赋值 (公开成员函数)

非成员函数

operator+operator-operator*operator/operator% (C++11) | 实现以时长为实参的算术运算 (函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=> (C++11)(C++11)(C++20 中移除)(C++11)(C++11)(C++11)(C++11)(C++20) | 比较两个时长 (函数模板)
duration_cast (C++11) | 转换时长到另一个拥有不同嘀嗒间隔的时长 (函数模板)
floor(std::chrono::duration) (C++17) | 以向下取整的方式，将一个时长转换为另一个时长 (函数模板)
ceil(std::chrono::duration) (C++17) | 以向上取整的方式，将一个时长转换为另一个时长 (函数模板)
round(std::chrono::duration) (C++17) | 转换时长到另一个时长，就近取整，偶数优先 (函数模板)
abs(std::chrono::duration) (C++17) | 获取时长的绝对值 (函数模板)
operator<< (C++20) | 进行 duration 上的流输出 (函数模板)
from_stream (C++20) | 按照提供的格式，从流分析 duration (函数模板)

辅助类型

类型 | 定义
std::chrono::nanoseconds | duration</*至少 64 位的有符号整数类型*/, std::nano >
std::chrono::microseconds | duration</*至少 55 位的有符号整数类型*/, std::micro >
std::chrono::milliseconds | duration</*至少 45 位的有符号整数类型*/, std::milli >
std::chrono::seconds | duration</*至少 35 位的有符号整数类型*/>
std::chrono::minutes | duration</*至少 29 位的有符号整数类型*/, std::ratio <60>>
std::chrono::hours | duration</*至少 23 位的有符号整数类型*/, std::ratio <3600>>
std::chrono::days (C++20 起) | duration</*至少 25 位的有符号整数类型*/, std::ratio <86400>>
std::chrono::weeks (C++20 起) | duration</*至少 22 位的有符号整数类型*/, std::ratio <604800>>
std::chrono::months (C++20 起) | duration</*至少 20 位的有符号整数类型*/, std::ratio <2629746>>
std::chrono::years (C++20 起) | duration</*至少 17 位的有符号整数类型*/, std::ratio <31556952>>

注意：到 hours 为止的每个预定义时长类型至少涵盖 ±292 年的范围。

每个预定义时长类型 days 、 weeks 、 months 和 years 至少涵盖 ±40000 年范围。 years 等于 365.2425 days （格里高利年的平均长度）。 months 等于 30.436875 days （ years 的准确的 1/12 ）。

 (C++20 起)

辅助类

std::common_type<std::chrono::duration> (C++11) | 特化 std::common_type 特征 (类模板特化)
treat_as_floating_point (C++11) | 指示时长可转换为拥有不同计次的时长 (类模板)
duration_values (C++11) | 构造给定类型计次的零、最小及最大值 (类模板)
std::formatter<std::chrono::duration> (C++20) | std::formatter 的特化，按提供的格式格式化 duration (类模板特化)

字面量

定义于内联命名空间 std::literals::chrono_literals
operator""h (C++14) | 表示小时的 std::chrono::duration 字面量 (函数)
operator""min (C++14) | 表示分钟的 std::chrono::duration 字面量 (函数)
operator""s (C++14) | 表示秒的 std::chrono::duration 字面量 (函数)
operator""ms (C++14) | 表示毫秒的 std::chrono::duration 字面量 (函数)
operator""us (C++14) | 表示微秒的 std::chrono::duration 字面量 (函数)
operator""ns (C++14) | 表示纳秒的 std::chrono::duration 字面量 (函数)

注意：字面量后缀 d 和 y 不指代 days 和 years ，而是分别指代 day 和 year 。

 (C++20 起)

示例

此示例演示如何定义几种自定义时长类型及在类型间转换：

#include <iostream>
#include <chrono>

constexpr auto year = 31556952ll; // 格里高利历年的平均秒数

int main()
{
    using shakes = std::chrono::duration<int, std::ratio<1, 100000000>>;
    using jiffies = std::chrono::duration<int, std::centi>;
    using microfortnights = std::chrono::duration<float, std::ratio<14*24*60*60, 1000000>>;
    using nanocenturies = std::chrono::duration<float, std::ratio<100*year, 1000000000>>;

    std::chrono::seconds sec(1);

    std::cout << "1 second is:\n";

    // 无精度损失的整数尺度转换：无转型
    std::cout << std::chrono::microseconds(sec).count() << " microseconds\n"
              << shakes(sec).count() << " shakes\n"
              << jiffies(sec).count() << " jiffies\n";

    // 有精度损失的整数尺度转换：需要转型
    std::cout << std::chrono::duration_cast<std::chrono::minutes>(sec).count()
              << " minutes\n";

    // 浮点尺度转换：无转型
    std::cout << microfortnights(sec).count() << " microfortnights\n"
              << nanocenturies(sec).count() << " nanocenturies\n";
}

输出：

1 second is:
1000000 microseconds
100000000 shakes
100 jiffies
0 minutes
0.82672 microfortnights
0.316887 nanocenturies


std::chrono::abs(std::chrono::duration)

< cpp‎ | chrono‎ | duration
定义于头文件 <chrono> |
template <class Rep, class Period> constexpr std::chrono::duration <Rep, Period> abs( std::chrono::duration <Rep, Period> d ); | (C++17 起)

返回时期 d 的绝对值。具体而言，若 d >= d.zero() ，则返回 d ，否则返回 -d 。

该函数不参与重载决议，除非 std::numeric_limits <Rep>::is_signed 为 true 。

参数

d - 时期

返回值

d 的绝对值

可能的实现

template <class Rep, class Period, class = std::enable_if_t<
   std::chrono::duration<Rep, Period>::min() < std::chrono::duration<Rep, Period>::zero()>>
constexpr std::chrono::duration<Rep, Period> abs(std::chrono::duration<Rep, Period> d)
{
    return d >= d.zero() ? d : -d;
}

示例

#include <iostream>
#include <chrono>

int main()
{
    using namespace std::chrono;

    static_assert(abs(-42s) == std::chrono::abs(42s));

    std::cout << "abs(+3min) = " << abs(3min).count() << '\n'
              << "abs(-3min) = " << abs(-3min).count() << '\n';
}

输出：

abs(+3min) = 3
abs(-3min) = 3

参阅

operator+operator- | 实现一元 + 和一元 - (公开成员函数)
abs(int)labsllabs (C++11) | 计算整数值的绝对值（ \(\small{|x|}\)|x| ） (函数)


std::chrono::ceil(std::chrono::duration)

< cpp‎ | chrono‎ | duration
定义于头文件 <chrono> |
template <class ToDuration, class Rep, class Period> constexpr ToDuration ceil(const std::chrono::duration <Rep, Period>& d); | (C++17 起)

返回可表示为 ToDuration 的大于或等于 d 的最小时长 t 。

函数不参与重载决议，除非 ToDuration 是 std::chrono::duration 的特化。

参数

d - 要转换的时长

返回值

向上取整到 ToDuration 类型时长的 d 。

可能的实现

namespace detail {
template<class> inline constexpr bool is_duration_v = false;
template<class Rep, class Period> inline constexpr bool is_duration_v<
    std::chrono::duration<Rep, Period>> = true;
}

template <class To, class Rep, class Period,
          class = std::enable_if_t<detail::is_duration_v<To>>>
constexpr To ceil(const std::chrono::duration<Rep, Period>& d)
{
    To t = std::chrono::duration_cast<To>(d);
    if (t < d)
        return t + To{1};
    return t;
}

示例

#include <iostream>
#include <chrono>

int main()
{
    using namespace std::chrono_literals;
    using Min = std::chrono::minutes;

    std::cout
        << std::showpos
        << "ceil(+2.4min) = " << std::chrono::ceil<Min>(+2.4min).count() << "min\n"
        << "ceil(-2.4min) = " << std::chrono::ceil<Min>(-2.4min).count() << "min\n"
        << "ceil(+0.0min) = " << std::chrono::ceil<Min>(+0.0min).count() << "min\n";
}

输出：

ceil(+2.4min) = +3min
ceil(-2.4min) = -2min
ceil(+0.0min) = +0min

参阅

duration_cast (C++11) | 转换时长到另一个拥有不同嘀嗒间隔的时长 (函数模板)
floor(std::chrono::duration) (C++17) | 以向下取整的方式，将一个时长转换为另一个时长 (函数模板)
round(std::chrono::duration) (C++17) | 转换时长到另一个时长，就近取整，偶数优先 (函数模板)
ceil(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，向上取整 (函数模板)
ceilceilfceill (C++11)(C++11) | 不小于给定值的最接近整数值 (函数)


std::common_type(std::chrono::duration)

< cpp‎ | chrono‎ | duration
定义于头文件 <chrono>
template <class Rep1, class Period1, class Rep2, class Period2>

struct common_type< std::chrono::duration <Rep1, Period1>,
std::chrono::duration <Rep2, Period2>> {
typedef std::chrono::duration <
typename std::common_type <Rep1, Rep2>::type, /*see note*/> type;

};
 (C++11 起)

暴露名为 type 的类型，它是二个 std::chrono::duration 的共用类型，其周期为 Period1 与 Period2 的最大公约数。

注解

产生的时长的周期能通过构成 Period1::num 和 Period2::num 的最大公约数与 Period1::den 和 Period2::den 的最小公倍数的 ratio 计算。

示例

#include <iostream>
#include <chrono>

// std::chrono 已找到最大公约数，类似使用 std::common_type<> 。
// 我们令类型推导外化。

template <typename T,typename S>
auto durationDiff(const T& t, const S& s)  -> typename std::common_type<T,S>::type
{
    typedef typename std::common_type<T,S>::type Common;
    return Common(t) - Common(s);
}

int main()
{
    typedef std::chrono::milliseconds milliseconds;
    typedef std::chrono::microseconds microseconds;

    auto ms = milliseconds(30);
    auto us = microseconds(1100);

    std::cout << ms.count() << "ms - " << us.count() << "us = "
              << durationDiff(ms,us).count() <<  "\n";
}

输出：

30ms - 1100us = 28900

参阅

common_type
(C++11)
 确定一组类型的公共类型
(类模板)


std::chrono::duration<Rep,Period>::count

< cpp‎ | chrono‎ | duration
constexpr rep count() const;

返回此 duration 的计次数。

参数

（无）

返回值

此 duration 的计次数。

示例

#include <chrono>
#include <iostream>
int main()
{
    std::chrono::milliseconds ms{3}; // 3 毫秒
    // 从 3 毫秒构造 6000 微秒
    std::chrono::microseconds us = 2*ms;
    // 使用分数计次的 30Hz 时钟
    std::chrono::duration<double, std::ratio<1, 30>> hz30(3.5);

    std::cout <<  "3 ms duration has " << ms.count() << " ticks\n"
              <<  "6000 us duration has " << us.count() << " ticks\n"
              <<  "3.5 30Hz duration has " << hz30.count() << " ticks\n";
}

输出：

3 ms duration has 3 ticks
6000 us duration has 6000 ticks
3.5 30Hz duration has 3.5 ticks

参阅

duration_cast
(C++11)
 转换时长到另一个拥有不同嘀嗒间隔的时长
(函数模板)


std::chrono::duration<Rep,Period>::duration

< cpp‎ | chrono‎ | duration
constexpr duration() = default; | (1) | (C++11 起)
duration( const duration& ) = default; | (2) | (C++11 起)
template< class Rep2 > constexpr explicit duration( const Rep2& r ); | (3) | (C++11 起)
template< class Rep2, class Period2 > constexpr duration( const duration<Rep2,Period2>& d ); | (4) | (C++11 起)

从数个可选数据源之一构造新的 duration 。

1) 默认构造函数设为默认。
2) 复制构造函数设为默认（进行计次数的逐位复制）。
3) 构造拥有计次 r 的时长。注意此构造函数仅若 const Rep2& （参数类型）能隐式转换为 rep （时长的计次类型）且满足下列条件才参与重载决议
  • std::chrono::treat_as_floating_point <rep>::value 为 true ，或
  • std::chrono::treat_as_floating_point <Rep2>::value 为 false 。
（即，拥有整数计次的时长不能从浮点值构造，但拥有浮点计次的时长能从整数值构造）
4) 通过转换 d 到确切的周期和计次构造时长，如同用 std::chrono::duration_cast <duration>(d).count() 。为避免转换时截断，此构造函数参与重载决议，仅若转换因数的计算（用 std::ratio_divide <Period2, Period> ）不溢出且：
  • std::chrono::treat_as_floating_point <rep>::value == true
或：
  • std::ratio_divide <Period2, period>::den == 1 ，且
  • std::chrono::treat_as_floating_point <Rep2>::value == false 。
（即要么时长使用浮点计次，要么 Period2 能为period整除）

参数

r | - | 计次数
d | - | 从之复制的时长

示例

下列代码展示数个如何构造时长的示例（合法者与非法者）：

#include <chrono>
int main()
{
    std::chrono::hours h(1); // 一小时
    std::chrono::milliseconds ms{3}; // 3 毫秒
    std::chrono::duration<int, std::kilo> ks(3); // 3000 秒

    // 错误： treat_as_floating_point<int>::value == false,
    // 此时长只允许整数计次
//  std::chrono::duration<int, std::kilo> d3(3.5);

    // 使用小数计次的 30Hz 钟
    std::chrono::duration<double, std::ratio<1, 30>> hz30(3.5);

    // 从 3 毫秒构造 3000 微秒
    std::chrono::microseconds us = ms;
    // error: 1/1000000 is not divisible by 1/1000
//  std::chrono::milliseconds ms2 = us
    std::chrono::duration<double, std::milli> ms2 = us; // 3.0 毫秒
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3050 | C++11 | 可转换性制约使用非 const 亡值 | 替而使用 const 左值

参阅

operator=
 赋值内容
(公开成员函数)


std::chrono::duration_cast

< cpp‎ | chrono‎ | duration
定义于头文件 <chrono> |
template <class ToDuration, class Rep, class Period> constexpr ToDuration duration_cast(const std::chrono::duration <Rep,Period>& d); | (C++11 起)

转换 std::chrono::duration 为不同类型 ToDuration 的时长。 函数不参与重载决议，除非 ToDuration 是 std::chrono::duration 的特化。

不使用隐式转换。可能的情况下避免乘法和除法，若在编译时已知一或多个参数为 1 。以最宽的可用类型进行计算，而如同用 static_cast 到结果类型的转换，只在完成时进行。

参数

d - 要转换的 duration

返回值

转换为 ToDuration 类型时长的 d 。

注解

在源周期能准确地为目标周期所整除的场合（例如小时到分钟），浮点时长和整数时长间转型能经由 std::chrono::duration 构造函数隐式进行，无需 duration_cast 。

从浮点时长转型到整数时长，在浮点值为 NaN 、无穷大或过大而无法以目标的整数类型表示时，导致未定义行为。否则转型到整数时长受制于截断，同任何到整数类型到 static_cast 。

示例

此示例度量函数的执行时间

#include <iostream>
#include <chrono>
#include <ratio>
#include <thread>

void f()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    auto t1 = std::chrono::high_resolution_clock::now();
    f();
    auto t2 = std::chrono::high_resolution_clock::now();

    // 整数时长：要求 duration_cast
    auto int_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);

    // 小数时长：不要求 duration_cast
    std::chrono::duration<double, std::milli> fp_ms = t2 - t1;

    std::cout << "f() took " << fp_ms.count() << " ms, "
              << "or " << int_ms.count() << " whole milliseconds\n";
}

可能的输出：

f() took 1000.23 ms, or 1000 whole milliseconds

参阅

duration (C++11) | 时间区间 (类模板)
time_point_cast (C++11) | 转换时间点为同一时钟上拥有不同时长的另一时间点 (函数模板)
floor(std::chrono::duration) (C++17) | 以向下取整的方式，将一个时长转换为另一个时长 (函数模板)
ceil(std::chrono::duration) (C++17) | 以向上取整的方式，将一个时长转换为另一个时长 (函数模板)
round(std::chrono::duration) (C++17) | 转换时长到另一个时长，就近取整，偶数优先 (函数模板)


std::chrono::floor(std::chrono::duration)

< cpp‎ | chrono‎ | duration
定义于头文件 <chrono> |
template <class ToDuration, class Rep, class Period> constexpr ToDuration floor(const std::chrono::duration <Rep, Period>& d); | (C++17 起)

返回可表示为 ToDuration 的小于或等于 d 的最大时长 t 。

函数不参与重载决议，除非 ToDuration 是 std::chrono::duration 的特化。

参数

d - 要转换的时长

返回值

向下取整到 ToDuration 类型时长的 d 。

可能的实现

namespace detail {
template<class> inline constexpr bool is_duration_v = false;
template<class Rep, class Period> inline constexpr bool is_duration_v<
    std::chrono::duration<Rep, Period>> = true;
}

template <class To, class Rep, class Period,
          class = std::enable_if_t<detail::is_duration_v<To>>>
constexpr To floor(const duration<Rep, Period>& d)
{
    To t = std::chrono::duration_cast<To>(d);
    if (t > d)
        return t - To{1};
    return t;
}

示例

#include <iostream>
#include <iomanip>
#include <chrono>

int main()
{
    using namespace std::chrono_literals;
    using Sec = std::chrono::seconds;
    for (std::cout << "Duration\tFloor\tRound\tCeil\n"
                      "(ms)\t\t(sec)\t(sec)\t(sec)\n";
        auto const d: {
            +4999ms, +5000ms, +5001ms, +5499ms, +5500ms, +5999ms,
            -4999ms, -5000ms, -5001ms, -5499ms, -5500ms, -5999ms, }) {
        std::cout << std::showpos << d.count() << "\t\t"
                  << std::chrono::floor<Sec>(d).count() << '\t'
                  << std::chrono::round<Sec>(d).count() << '\t'
                  << std::chrono::ceil <Sec>(d).count() << '\n';
    }
}

输出：

Duration   Floor   Round   Ceil
(ms)       (sec)   (sec)   (sec)
+4999      +4      +5      +5
+5000      +5      +5      +5
+5001      +5      +5      +6
+5499      +5      +5      +6
+5500      +5      +6      +6
+5999      +5      +6      +6
-4999      -5      -5      -4
-5000      -5      -5      -5
-5001      -6      -5      -5
-5499      -6      -5      -5
-5500      -6      -6      -5
-5999      -6      -6      -5

参阅

duration_cast (C++11) | 转换时长到另一个拥有不同嘀嗒间隔的时长 (函数模板)
ceil(std::chrono::duration) (C++17) | 以向上取整的方式，将一个时长转换为另一个时长 (函数模板)
round(std::chrono::duration) (C++17) | 转换时长到另一个时长，就近取整，偶数优先 (函数模板)
floor(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，向下取整 (函数模板)
floorfloorffloorl (C++11)(C++11) | 不大于给定值的最接近整数 (函数)


std::chrono::duration<Rep,Period>::max

< cpp‎ | chrono‎ | duration
static constexpr duration max(); | (C++20 前)
static constexpr duration max() noexcept; | (C++20 起)

返回拥有最大可能值的时长。

若时长表示 rep 要求某个其他实现返回最大长度的时长，则可特化 std::chrono::duration_values 以返回所欲值。

参数

（无）

返回值

返回 duration( std::chrono::duration_values <rep>::max()) 。

参阅

zero [静态] | 返回特殊时长值零 (公开静态成员函数)
min [静态] | 返回特殊时长值最小值 (公开静态成员函数)


std::chrono::duration<Rep,Period>::min

< cpp‎ | chrono‎ | duration
static constexpr duration min(); | (C++20 前)
static constexpr duration min() noexcept; | (C++20 起)

返回拥有最低可能值的时长。

若时长的表示 rep 要求某个其他实现返回最小长度的时长，则可特化 std::chrono::duration_values 以返回所欲值。

参数

（无）

返回值

返回 duration( std::chrono::duration_values <rep>::min()) 。

参阅

zero [静态] | 返回特殊时长值零 (公开静态成员函数)
max [静态] | 返回特殊时长值最大值 (公开静态成员函数)


std::chrono::duration<Rep,Period>::operator=

< cpp‎ | chrono‎ | duration
duration& operator=( const duration &other ) = default; | (C++11 起)

赋值一个 duration 的内容到另一个。

参数

other - 复制来源的 duration

参阅

(构造函数)
 构造新 duration
(公开成员函数)


std::chrono::duration<Rep,Period>::operator+(unary), std::chrono::duration<Rep,Period>::operator-(unary)

< cpp‎ | chrono‎ | duration
 | (1)
constexpr duration operator+() const; |  | (C++17 前)
constexpr std::common_type_t <duration> operator+() const; |  | (C++17 起)
 | (2)
constexpr duration operator-() const; |  | (C++17 前)
constexpr std::common_type_t <duration> operator-() const; |  | (C++17 起)

实现 duration 的一元加和一元减。

若 rep_ 为 duration 对象中保有计次数的成员变量，而 D 是返回类型，则

1) 等价于 return D(*this);
2) 等价于 return D(-rep_);

参数

（无）

返回值

1) 此 duration 对象的副本
2) 此 duration 对象的副本，对其计次数取反

示例

#include <chrono>
#include <iostream>

int main()
{
    std::chrono::seconds s1(10);
    std::chrono::seconds s2 = -s1;

    std::cout << "negated 10 seconds are " << s2.count() << " seconds\n";
}

输出：

negated 10 seconds are -10 seconds

参阅

operator++operator++(int)operator--operator--(int) | 递增或递减滴答计数 (公开成员函数)
operator+operator-operator*operator/operator% (C++11) | 实现以时长为实参的算术运算 (函数模板)


std::chrono::duration<Rep,Period>::operator++, std::chrono::duration<Rep,Period>::operator--

< cpp‎ | chrono‎ | duration
 | (1)
duration& operator++(); |  | (C++17 前)
constexpr duration& operator++(); |  | (C++17 起)
 | (2)
duration operator++(int); |  | (C++17 前)
constexpr duration operator++(int); |  | (C++17 起)
 | (3)
duration& operator--(); |  | (C++17 前)
constexpr duration& operator--(); |  | (C++17 起)
 | (4)
duration operator--(int); |  | (C++17 前)
constexpr duration operator--(int); |  | (C++17 起)

自增或自减此 duration 的计次数。

若 rep_ 是 duration 对象中保有计次数的成员变量，则

1) 等价于 ++rep_; return *this;
2) 等价于 return duration(rep_++)
3) 等价于 --rep_; return *this;
4) 等价于 return duration(rep_--);

参数

（无）

返回值

1,3) 到修改后的此 duration 的引用
2,4) 修改前所做的 duration 副本

示例

#include <chrono>
#include <iostream>

int main()
{
    std::chrono::hours h(1);
    std::chrono::minutes m = ++h;
    m--;
    std::cout << m.count() << " minutes\n";
}

输出：

119 minutes

参阅

operator+=operator-=operator*=operator/=operator%= | 实现二个时长间的复合赋值 (公开成员函数)
operator+operator-operator*operator/operator% (C++11) | 实现以时长为实参的算术运算 (函数模板)


std::chrono::duration<Rep,Period>::operator+=, -=, *=, /=, %=

< cpp‎ | chrono‎ | duration
 | (1)
duration& operator+=(const duration& d); |  | (C++17 前)
constexpr duration& operator+=(const duration& d); |  | (C++17 起)
 | (2)
duration& operator-=(const duration& d); |  | (C++17 前)
constexpr duration& operator-=(const duration& d); |  | (C++17 起)
 | (3)
duration& operator*=(const rep& rhs); |  | (C++17 前)
constexpr duration& operator*=(const rep& rhs); |  | (C++17 起)
 | (4)
duration& operator/=(const rep& rhs); |  | (C++17 前)
constexpr duration& operator/=(const rep& rhs); |  | (C++17 起)
 | (5)
duration& operator%=(const rep& rhs); |  | (C++17 前)
constexpr duration& operator%=(const rep& rhs); |  | (C++17 起)
 | (6)
duration& operator%=(const duration& rhs); |  | (C++17 前)
constexpr duration& operator%=(const duration& rhs); |  | (C++17 起)

在二个拥有同一周期的时长或时长和计次值之间进行复合赋值。

若 rep_ 是此 duration 对象中保有计次数的成员变量，则

1) 等价于 rep_ += d.count(); return *this;
2) 等价于 rep_ -= d.count(); return *this;
3) 等价于 rep_ *= rhs; return *this;
4) 等价于 rep_ /= rhs; return *this;
5) 等价于 rep_ %= rhs; return *this;
6) 等价于 rep_ %= d.count(); return *this;

参数

d | - | 运算符右侧的 duration
rhs | - | 运算符右侧的计次数

返回值

到修改后的此 duration 的引用

示例

#include <chrono>
#include <iostream>

int main()
{
    std::chrono::minutes m(11);
    m *= 2;
    m += std::chrono::hours(10); // 小时可隐式转换成分
    std::cout << m.count() << " minutes equals "
              << std::chrono::duration_cast<std::chrono::hours>(m).count()
              << " hours and ";
    m %= std::chrono::hours(1);
    std::cout << m.count() << " minutes\n";
}

输出：

622 minutes equals 10 hours and 22 minutes

参阅

operator++operator++(int)operator--operator--(int) | 递增或递减滴答计数 (公开成员函数)
operator+operator-operator*operator/operator% (C++11) | 实现以时长为实参的算术运算 (函数模板)


operator+,-,*,/,%(std::chrono::duration)

< cpp‎ | chrono‎ | duration
template< class Rep1, class Period1, class Rep2, class Period2 > typename std::common_type <duration<Rep1,Period1>, duration<Rep2,Period2>>::type constexpr operator+( const duration<Rep1,Period1>& lhs, const duration<Rep2,Period2>& rhs ); | (1)
template< class Rep1, class Period1, class Rep2, class Period2 > typename std::common_type <duration<Rep1,Period1>, duration<Rep2,Period2>>::type constexpr operator-( const duration<Rep1,Period1>& lhs, const duration<Rep2,Period2>& rhs ); | (2)
template< class Rep1, class Period, class Rep2 > duration<typename std::common_type <Rep1,Rep2>::type, Period> constexpr operator*( const duration<Rep1,Period>& d, const Rep2& s ); | (3)
template< class Rep1, class Rep2, class Period > duration<typename std::common_type <Rep1,Rep2>::type, Period> constexpr operator*( const Rep1& s, const duration<Rep2,Period>& d ); | (4)
template< class Rep1, class Period, class Rep2 > duration<typename std::common_type <Rep1,Rep2>::type, Period> constexpr operator/( const duration<Rep1,Period>& d, const Rep2& s ); | (5)
template< class Rep1, class Period1, class Rep2, class Period2 > typename std::common_type <Rep1,Rep2>::type constexpr operator/( const duration<Rep1,Period1>& lhs, const duration<Rep2,Period2>& rhs ); | (6)
template< class Rep1, class Period, class Rep2 > duration<typename std::common_type <Rep1,Rep2>::type, Period> constexpr operator%( const duration<Rep1, Period>& d, const Rep2& s ); | (7)
template< class Rep1, class Period1, class Rep2, class Period2 > typename std::common_type <duration<Rep1,Period1>, duration<Rep2,Period2>>::type constexpr operator%( const duration<Rep1,Period1>& lhs, const duration<Rep2,Period2>& rhs ); | (8)

在二个时长或时长和计次数之间进行基本算术运算。

1) 转换二个时长到其共用类型，并创建计次数为转换后计次数之和的时长。
2) 转换二个时长到其共用类型，并创建计次数为转换后从 lhs 的计次数减去 rhs 的计次数的时长。
3-4) 转换时长 d 到其 rep 为 Rep1 与 Rep2 之间的共用类型的时长，并将转换后的计次数乘 s 。这些重载仅若 s 可转换到 typename std::common_type <Rep1, Rep2>::type 才参与重载决议。
5) 转换时长 d 到其 rep 为 Rep1 与 Rep2 之间的共用类型的时长，并将转换后的计次数除以 s 。此重载仅若 s 可转换到 typename std::common_type <Rep1, Rep2>::type 且 Rep2 不是 duration 的特化才参与重载决议。
6) 转换二个时长到其共用类型，并将 lhs 转换后的计次数除以 rhs 转换后的计次数。注意此运算符的返回值不是时长。
7) 转换时长 d 到其 rep 为 Rep1 与 Rep2 之间的共用类型的时长，并创建计次数为此时长的计次数除以 s 的时长。此重载仅若 s 可转换到 typename std::common_type <Rep1, Rep2>::type 且 Rep2 不是 duration 的特化才参与重载决议。
8) 转换二个时长到其共用类型，并创建计次数为转换后计次数取余的时长。

参数

lhs | - | 运算符左侧的 duration
rhs | - | 运算符右侧的 duration
d | - | 混合参数运算符的时长参数
s | - | 混合参数运算符的计次参数

返回值

假设 CD 为函数返回类型且 CR<A, B> = std::common_type <A, B>::type ，则：

1) CD(CD(lhs).count() + CD(rhs).count())
2) CD(CD(lhs).count() - CD(rhs).count())
3-4) CD(CD(d).count() * s)
5) CD(CD(d).count() / s).
6) CD(lhs).count() / CD(rhs).count() （此运算符的返回类型非 duration ）
7) CD(CD(d).count() % s)
8) CD(CD(lhs).count() % CD(rhs).count())

示例

#include <chrono>
#include <iostream>
int main()
{
    // 简单算术
    std::chrono::seconds s = std::chrono::hours(1)
                             + 2*std::chrono::minutes(10)
                             + std::chrono::seconds(70)/10;

    std::cout << "1 hour + 2*10 min + 70/10 sec = " << s.count() << " seconds\n";

    // 时长除以一个数和时长除以另一时长的区别
    std::cout << "Dividing that by 2 minutes gives "
              << s / std::chrono::minutes(2) << '\n';
    std::cout << "Dividing that by 2 gives "
              << (s / 2).count() << " seconds\n";

   // 余数运算符在确定此特定时长在时间框架的场合有用，
   // 例如，拆分它为时、分和秒：
   std::cout << s.count() << " seconds is "
             << std::chrono::duration_cast<std::chrono::hours>(
                    s
                ).count() << " hours, "
             << std::chrono::duration_cast<std::chrono::minutes>(
                    s % std::chrono::hours(1)
                ).count() << " minutes, "
             << std::chrono::duration_cast<std::chrono::seconds>(
                    s % std::chrono::minutes(1)
                ).count() << " seconds\n";
}

输出：

1 hour + 2*10 min + 70/10 sec = 4807 seconds
Dividing that by 2 minutes gives 40
Dividing that by 2 gives 2403 seconds
4807 seconds is 1 hours, 20 minutes, 7 seconds

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3050 | C++11 | 可转换性制约使用非 const 亡值 | 替而使用 const 左值


operator==,!=,<,<=,>,>=,<=>(std::chrono::duration)

< cpp‎ | chrono‎ | duration
template <class Rep1, class Period1, class Rep2, class Period2>

constexpr bool operator==(const std::chrono::duration <Rep1, Period1>& lhs,

const std::chrono::duration <Rep2, Period2>& rhs);
 (1) (C++11 起)
template <class Rep1, class Period1, class Rep2, class Period2>

constexpr bool operator!=(const std::chrono::duration <Rep1, Period1>& lhs,

const std::chrono::duration <Rep2, Period2>& rhs);
 (2) (C++11 起)
(C++20 前)
template <class Rep1, class Period1, class Rep2, class Period2>

constexpr bool operator<(const std::chrono::duration <Rep1, Period1>& lhs,

const std::chrono::duration <Rep2, Period2>& rhs);
 (3) (C++11 起)
template <class Rep1, class Period1, class Rep2, class Period2>

constexpr bool operator<=(const std::chrono::duration <Rep1, Period1>& lhs,

const std::chrono::duration <Rep2, Period2>& rhs);
 (4) (C++11 起)
template <class Rep1, class Period1, class Rep2, class Period2>

constexpr bool operator>(const std::chrono::duration <Rep1, Period1>& lhs,

const std::chrono::duration <Rep2, Period2>& rhs);
 (5) (C++11 起)
template <class Rep1, class Period1, class Rep2, class Period2>

constexpr bool operator>=(const std::chrono::duration <Rep1, Period1>& lhs,

const std::chrono::duration <Rep2, Period2>& rhs);
 (6) (C++11 起)
template <class Rep1, class Period1, class Rep2, class Period2>

requires std::three_way_comparable< std::common_type_t <Rep1, Rep2>>
constexpr auto operator<=>(const std::chrono::duration <Rep1, Period1>& lhs,

const std::chrono::duration <Rep2, Period2>& rhs);
 (7) (C++20 起)

比较二个时长。 令 CT 为 std::common_type < std::chrono::duration <Rep1, Period1>, std::chrono::duration <Rep2, Period2>>::type ：

1-2) 检查 lhs 与 rhs 是否相等，即以两个 duration 的共用类型表示的计次数是否相等。
3-6) 比较 lhs 与 rhs ，即比较两个 duration 的共用类型表示的计次数。
7) 比较 lhs 与 rhs ，即比较两个 duration 的共用类型表示的计次数。从 CT(lhs).count() <=> CT(rhs).count() 推导返回类型。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs | - | 运算符左侧的 duration
rhs | - | 运算符右侧的 duration

返回值

1) CT(lhs).count() == CT(rhs).count()
2) !(lhs == rhs)
3) CT(lhs).count() < CT(rhs).count()
4) !(rhs < lhs)
5) rhs < lhs
6) !(lhs < rhs)
7) CT(lhs).count() <=> CT(rhs).count()

示例

#include <chrono>
#include <iostream>
int main()
{
    if(std::chrono::seconds(2) == std::chrono::milliseconds(2000))
        std::cout <<  "2 s == 2000 ms\n";
    else
        std::cout <<  "2 s != 2000 ms\n";

    if(std::chrono::seconds(61) > std::chrono::minutes(1))
        std::cout <<  "61 s > 1 min\n";
    else
        std::cout <<  "61 s <= 1 min\n";

}

输出：

2 s == 2000 ms
61 s > 1 min


std::chrono::operator<< (std::chrono::duration)

< cpp‎ | chrono‎ | duration
定义于头文件 <chrono>
template <class CharT, class Traits, class Rep, class Period>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::duration <Rep, Period>& d);
 (C++20 起)

插入 d 的文本表示到 os 中，若 CharT 既非 char 亦非 wchar_t ，或若 Rep 既非浮点类型亦非转换等级大于或等于 short 的类型，则行为未定义。

表现如同它实现为

std::basic_ostringstream<CharT, Traits> s;
s.flags(os.flags());
s.imbue(os.getloc());
s.precision(os.precision());
s << d.count() << units_suffix; // 见后述
return os << s.str();

换言之，流标志、本地环境和精度由流确定，但用整个输出字符串确定任何填充。

units_suffix 基于按照下表的 Period::type 确定。

Period::type | 后缀
std::atto | as
std::femto | fs
std::pico | ps
std::nano | ns
std::micro | µs (U+00B5) 或 us ，使用何者是实现定义的
std::milli | ms
std::centi | cs
std::deci | ds
std::ratio<1> | s
std::deca | das
std::hecto | hs
std::kilo | ks
std::mega | Ms
std::giga | Gs
std::tera | Ts
std::peta | Ps
std::exa | Es
std::ratio<60> | min
std::ratio<3600> | h
std::ratio<86400> | d
非以上之一，且 Period::type::den == 1 | [num]s
非以上之一 | [num/den]s

对于表中最后二行，后缀中的 num 和 den 分别是格式化为不带前导零的 Period::type::num 和 Period::type::den 。

返回值

到流的引用，即 os 。

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::duration> (C++20) | std::formatter 的特化，按提供的格式格式化 duration (类模板特化)
operator<<operator>> | 执行字符串的流输入与输出 (函数模板)
to_string (C++11) | 转换整数或浮点值为 string (函数)
to_wstring (C++11) | 转换整数或浮点值为 wstring (函数)


std::chrono::round(std::chrono::duration)

< cpp‎ | chrono‎ | duration
定义于头文件 <chrono> |
template <class ToDuration, class Rep, class Period> constexpr ToDuration round( const std::chrono::duration <Rep, Period>& d ); | (C++17 起)

返回可表示为 ToDuration 的最接近 d 的 t 。若有二个此种值，则返回偶数值（即使得 t % 2 == 0 的值 t ）。

函数不参与重载，除非 ToDuration 是 std::chrono::duration 的特化且 std::chrono::treat_as_floating_point_v<typename ToDuration::rep> 为 false

参数

d - 要转换的时期

返回值

取整到 ToDuration 类型的最接近时期的 d ，两值正中的情况取到偶数。

可能的实现

namespace detail {
template<class> inline constexpr bool is_duration_v = false;
template<class Rep, class Period> inline constexpr bool is_duration_v<
    std::chrono::duration<Rep, Period>> = true;
}

template <class To, class Rep, class Period,
          class = std::enable_if_t<detail::is_duration_v<To> &&
                 !std::chrono::treat_as_floating_point_v<typename To::rep>>>
constexpr To round(const std::chrono::duration<Rep, Period>& d)
{
    To t0 = std::chrono::floor<To>(d);
    To t1 = t0 + To{1};
    auto diff0 = d - t0;
    auto diff1 = t1 - d;
    if (diff0 == diff1) {
        if (t0.count() & 1)
            return t1;
        return t0;
    } else if (diff0 < diff1) {
        return t0;
    }
    return t1;
}

示例

#include <iostream>
#include <iomanip>
#include <chrono>

int main()
{
    using namespace std::chrono_literals;
    using Sec = std::chrono::seconds;
    for (std::cout << "Duration\tFloor\tRound\tCeil\n"
                      "(ms)\t\t(sec)\t(sec)\t(sec)\n";
        auto const d: {
            +4999ms, +5000ms, +5001ms, +5499ms, +5500ms, +5999ms,
            -4999ms, -5000ms, -5001ms, -5499ms, -5500ms, -5999ms, }) {
        std::cout << std::showpos << d.count() << "\t\t"
                  << std::chrono::floor<Sec>(d).count() << '\t'
                  << std::chrono::round<Sec>(d).count() << '\t'
                  << std::chrono::ceil <Sec>(d).count() << '\n';
    }
}

输出：

Duration   Floor   Round   Ceil
(ms)       (sec)   (sec)   (sec)
+4999      +4      +5      +5
+5000      +5      +5      +5
+5001      +5      +5      +6
+5499      +5      +5      +6
+5500      +5      +6      +6
+5999      +5      +6      +6
-4999      -5      -5      -4
-5000      -5      -5      -5
-5001      -6      -5      -5
-5499      -6      -5      -5
-5500      -6      -6      -5
-5999      -6      -6      -5

参阅

duration_cast (C++11) | 转换时长到另一个拥有不同嘀嗒间隔的时长 (函数模板)
floor(std::chrono::duration) (C++17) | 以向下取整的方式，将一个时长转换为另一个时长 (函数模板)
ceil(std::chrono::duration) (C++17) | 以向上取整的方式，将一个时长转换为另一个时长 (函数模板)
round(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，就近取整，偶数优先 (函数模板)
roundroundfroundllroundlroundflroundlllroundllroundfllroundl (C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11) | 最接近整数，中间情况下向远离零舍入 (函数)


std::chrono::duration<Rep,Period>::zero

< cpp‎ | chrono‎ | duration
static constexpr duration zero(); | (C++20 前)
static constexpr duration zero() noexcept; | (C++20 起)

返回零长度时长。

若时长的表示 rep 要求其他某个实现返回零长时长，则能特化 std::chrono::duration_values 以返回所欲值。

参数

（无）

返回值

返回 duration( std::chrono::duration_values <rep>::zero())

示例

#include <chrono>
#include <ratio>
int main() {
    static_assert((std::chrono::hours::zero() == std::chrono::nanoseconds::zero()) &&
                  (std::chrono::duration<short, std::nano>::zero() ==
                   std::chrono::duration<int, std::deci>::zero()) &&
                  (std::chrono::duration<short, std::deca>::zero() ==
                   std::chrono::duration<long, std::exa>::zero()) &&
                  (std::chrono::duration<long, std::atto>::zero().count() ==
                   std::chrono::duration<float, std::exa>::zero().count()));
}

参阅

min [静态] | 返回特殊时长值最小值 (公开静态成员函数)
max [静态] | 返回特殊时长值最大值 (公开静态成员函数)


std::chrono::duration_values

< cpp‎ | chrono
定义于头文件 <chrono> |
template <class Rep> struct duration_values; | (C++11 起)

std::chrono::duration_values 类型定义三个常用时长：

  • std::chrono::duration_values::zero
  • std::chrono::duration_values::min
  • std::chrono::duration_values::max

std::chrono::duration 中的 zero 、 min 和 max 方法转发其工作到这些方法。

能特化此类型，若表示 Rep 要求特定实现以返回这些时长对象。

成员函数

zero [静态] | 返回零长度表示 (公开静态成员函数)
min [静态] | 返回最小可能表示 (公开静态成员函数)
max [静态] | 返回最大可能表示 (公开静态成员函数)


std::chrono::duration_values<Rep>::max

< cpp‎ | chrono‎ | duration values
static constexpr Rep max(); | (C++20 前)
static constexpr Rep max() noexcept; | (C++20 起)

返回最大可能表示。

参数

（无）

返回值

返回 std::numeric_limits <Rep>::max() 。

参阅

max [静态] | 返回特殊时长值最大值 (std::chrono::duration<Rep,Period> 的公开静态成员函数)
zero [静态] | 返回零长度表示 (公开静态成员函数)
min [静态] | 返回最小可能表示 (公开静态成员函数)


std::chrono::duration_values<Rep>::min

< cpp‎ | chrono‎ | duration values
static constexpr Rep min(); | (C++20 前)
static constexpr Rep min() noexcept; | (C++20 起)

返回最低的可能表示。

参数

（无）

返回值

返回 std::numeric_limits <Rep>::lowest() 。

参阅

min [静态] | 返回特殊时长值最小值 (std::chrono::duration<Rep,Period> 的公开静态成员函数)
zero [静态] | 返回零长度表示 (公开静态成员函数)
max [静态] | 返回最大可能表示 (公开静态成员函数)


std::chrono::duration_values<Rep>::zero

< cpp‎ | chrono‎ | duration values
static constexpr Rep zero(); | (C++20 前)
static constexpr Rep zero() noexcept; | (C++20 起)

返回零长度表示。

参数

（无）

返回值

返回 Rep(0)

参阅

zero [静态] | 返回特殊时长值零 (std::chrono::duration<Rep,Period> 的公开静态成员函数)
min [静态] | 返回最小可能表示 (公开静态成员函数)
max [静态] | 返回最大可能表示 (公开静态成员函数)


std::chrono::file_clock

< cpp‎ | chrono
定义于头文件 <chrono> |
using file_clock = /* see below */; | (C++20 起)

std::chrono::file_clock 是用于 std::filesystem::file_time_type 的时钟的别名。不指定其纪元。

时间点族

定义于命名空间 std::chrono |
template<class Duration> using file_time = std::chrono::time_point <std::chrono::file_clock, Duration>; | (C++20 起)
operator<<(std::chrono::file_time) (C++20) | 进行 file_time 上的流输出 (函数模板)
from_stream(std::chrono::file_time) (C++20) | 按照给定的格式从流分析 file_time (函数模板)
std::formatter<std::chrono::file_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 file_time (类模板特化)

成员类型

成员类型 | 定义
rep | 表示时钟时长中计次数的有符号算术类型
period | 表示时钟计次周期的 std::ratio 类型，单位为秒
duration | std::chrono::duration <rep, period> ，足以表示负时长
time_point | std::chrono::time_point <std::chrono::file_clock>

成员常量

constexpr bool is_steady
[静态]
 若时间间隔计次始终为常数，即纵使在调整了外部时钟的情况下，调用 now() 的返回值亦单调递增，则为 true ；否则为 false
(公开静态成员常量)

成员函数

file_clock 提供下列二对静态成员函数中的一对：

  • to_utc 与 from_utc ；或
  • to_sys 与 from_sys 。
now [静态] | 返回表示当前时间点的 std::chrono::time_point (公开静态成员函数)
to_utcfrom_utc [静态] (可选) | 在 file_time 与 utc_time 之间转换 (公开静态成员函数)
to_sysfrom_sys [静态] (可选) | 在 file_time 与 sys_time 之间转换 (公开静态成员函数)


std::chrono::file_clock::now

< cpp‎ | chrono‎ | file clock

static std::chrono::time_point <std::chrono::file_clock> now() noexcept; | (C++20 起)

返回表示当前时间的时间点。

参数

（无）

返回值

表示当前时间的时间点。

示例

#include <iostream>
#include <vector>
#include <numeric>
#include <chrono>

volatile int sink;
int main()
{
    for (auto size = 1ull; size < 1000000000ull; size *= 100) {
        // 记录开始时间
        auto start = std::chrono::file_clock::now();
        // 做一些工作
        std::vector<int> v(size, 42);
        sink = std::accumulate(v.begin(), v.end(), 0u); // 确保其副效应
        // 记录结束时间
        auto end = std::chrono::file_clock::now();
        std::chrono::duration<double> diff = end-start;
        std::cout << "Time to fill and iterate a vector of "
                  << size << " ints : " << diff.count() << " s\n";
    }
}

可能的输出：

Time to fill and iterate a vector of 1 ints : 2.43e-07 s
Time to fill and iterate a vector of 100 ints : 4.1e-07 s
Time to fill and iterate a vector of 10000 ints : 2.519e-05 s
Time to fill and iterate a vector of 1000000 ints : 0.00207669 s
Time to fill and iterate a vector of 100000000 ints : 0.423087 s


std::chrono::operator<<(std::chrono::file_time)

< cpp‎ | chrono‎ | file clock

定义于头文件 <chrono>
template <class CharT, class Traits, class Duration>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::file_time<Duration>& tp);
 (C++20 起)

输出 tp 到流 os 中，如同用 os << std::format(STATICALLY_WIDEN<CharT>("{:L%F %T}"), tp) ，其中 STATICALLY_WIDEN<CharT>("{:L%F %T}") 若 CharT 为 char 则为 "{:L%F %T}" ，而若 CharT 为 wchar_t 则为 L"{:L%F %T}" 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

std::formatter<std::chrono::file_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 file_time (类模板特化)
format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)


std::chrono::file_clock::to_sys, std::chrono::file_clock::from_sys

< cpp‎ | chrono‎ | file clock
template <class Duration>

static std::chrono::sys_time</*see below*/>

to_sys(const std::chrono::file_time<Duration>& t);
 (1) (C++20 起)
(可选)
template <class Duration>

static std::chrono::file_time</*see below*/>

from_sys(const std::chrono::sys_time<Duration>& t);
 (2) (C++20 起)
(可选)
1) 转换 file_time t 为表示同一时间点的 sys_time 。
2) 转换 sys_time t 为表示同一时间点的 file_time 。

从 Duration 以未指定方式计算返回类型的时长。

这些函数模板是可选的：实现可以替而选择提供 to_utc 和 from_utc 。

返回值

1) 与参数表示相同时间点的 sys_time 。
2) 与参数表示相同时间点的 file_time 。

注意

用户代码通常应使用 std::chrono::clock_cast ，它对时钟间转换提供通用接口，而非直接调用这些函数。

参阅

to_utcfrom_utc [静态] (可选) | 在 file_time 与 utc_time 之间转换 (公开静态成员函数)
clock_cast (C++20) | 转换一个时钟的时间点为另一个 (函数模板)


std::chrono::file_clock::to_utc, std::chrono::file_clock::from_utc

< cpp‎ | chrono‎ | file clock
template <class Duration>

static std::chrono::utc_time</*see below*/>

to_utc(const std::chrono::file_time<Duration>& t);
 (1) (C++20 起)
(可选)
template <class Duration>

static std::chrono::file_time</*see below*/>

from_utc(const std::chrono::utc_time<Duration>& t);
 (2) (C++20 起)
(可选)
1) 转换 file_time t 为表示同一时间点的 utc_time 。
2) 转换 utc_time t 为表示同一时间点的 file_time 。

从 Duration 以未指定方式计算返回类型的时长。

这些函数模板是可选的：实现可以替而选择提供 to_sys 和 from_sys 。

返回值

1) 与参数表示相同时间点的 utc_time 。
2) 与参数表示相同时间点的 file_time 。

注意

用户代码通常应使用 std::chrono::clock_cast ，它对时钟间转换提供通用接口，而非直接调用这些函数。

参阅

to_sysfrom_sys [静态] (可选) | 在 file_time 与 sys_time 之间转换 (公开静态成员函数)
clock_cast (C++20) | 转换一个时钟的时间点为另一个 (函数模板)


std::chrono::gps_clock

< cpp‎ | chrono
定义于头文件 <chrono> |
class gps_clock; | (C++20 起)

时钟 std::chrono::gps_clock 是表示全球定位系统 (Global Positioning System, GPS) 时间的时钟 (Clock) 。它度量从 1980 年 1 月 6 日 00:00:00 UTC 开始的时间。

不插入闰秒到 GPS 中。从而每插入一次闰秒到 UTC 中， UTC 就多落后 GPS 一秒。迄至 2017 年 12 月， UTC 落后 GPS 18 秒，反映出 1980 到 2017 年间插入了 18 闰秒。从而 2018-01-01 00:00:00 UTC 等价于 2018-01-01 00:00:18 GPS 。 GPS 恒定地落后 TAI 19 秒。

gps_clock 满足时钟 (Clock) 要求。它不满足平凡时钟 (TrivialClock) 要求，除非实现能保证 now() 不抛异常。

时间点族

定义于命名空间 std::chrono |
template<class Duration> using gps_time = std::chrono::time_point <std::chrono::gps_clock, Duration>; | (C++20 起)
using gps_seconds = gps_time< std::chrono::seconds >; | (C++20 起)
operator<<(std::chrono::gps_time) (C++20) | 进行 gps_time 上的流输出 (函数模板)
from_stream(std::chrono::gps_time) (C++20) | 按照给定的格式从流分析 gps_time (函数模板)
std::formatter<std::chrono::gps_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 gps_time (类模板特化)

成员类型

成员类型 | 定义
rep | 表示时钟时长中计次数的有符号算术类型
period | 表示时钟计次周期的 std::ratio 类型，单位为秒
duration | std::chrono::duration <rep, period> ，足以表示负时长
time_point | std::chrono::time_point <std::chrono::gps_clock>

成员常量

constexpr bool is_steady
[静态]
 若时间间隔计次始终为常数，即纵使在调整了外部时钟的情况下，调用 now() 的返回值亦单调递增，则为 true ；否则为 false
(公开静态成员常量)

成员函数

now [静态] | 返回表示当前时间点的 std::chrono::time_point (公开静态成员函数)
to_utc [静态] | 转换 gps_time 为 utc_time (公开静态成员函数)
from_utc [静态] | 转换 utc_time 为 gps_time (公开静态成员函数)


std::chrono::gps_clock::from_utc

< cpp‎ | chrono‎ | gps clock
template <class Duration>

static std::chrono::gps_time< std::common_type_t <Duration, std::chrono::seconds >>

from_utc(const std::chrono::utc_time<Duration>&) noexcept;
 (C++20 起)

转换 utc_time t 为表示相同时间点的 gps_time 。

返回值

与 t 表示相同时间点的 std::chrono::gps_time ，如同以从 t.time_since_epoch() 构造返回类型的值，并减去 315964809s 一般计算。 （ 315964809 是时钟 gps_clock 的纪元 1980-01-06 00:00:00 UTC 和时钟 utc_clock 的纪元 1970-01-01 00:00:00 UTC 间的秒数。）

参阅

to_utc [静态] | 转换 gps_time 为 utc_time (公开静态成员函数)
clock_cast (C++20) | 转换一个时钟的时间点为另一个 (函数模板)


std::chrono::gps_clock::now

< cpp‎ | chrono‎ | gps clock

static std::chrono::time_point <std::chrono::gps_clock> now(); | (C++20 起)

返回表示当前时间的时间点。 如同以 std::chrono::gps_clock::from_utc(std::chrono::utc_clock::now()) 计算结果。实现可以用更精确的 GPS 时间值。

参数

（无）

返回值

表示当前时间的时间点。

示例

#include <iostream>
#include <vector>
#include <numeric>
#include <chrono>

volatile int sink;
int main()
{
    for (auto size = 1ull; size < 1000000000ull; size *= 100) {
        // 记录开始时间
        auto start = std::chrono::gps_clock::now();
        // 做一些工作
        std::vector<int> v(size, 42);
        sink = std::accumulate(v.begin(), v.end(), 0u); // 确保其副效应
        // 记录结束时间
        auto end = std::chrono::gps_clock::now();
        std::chrono::duration<double> diff = end-start;
        std::cout << "Time to fill and iterate a vector of "
                  << size << " ints : " << diff.count() << " s\n";
    }
}

可能的输出：

Time to fill and iterate a vector of 1 ints : 2.43e-07 s
Time to fill and iterate a vector of 100 ints : 4.1e-07 s
Time to fill and iterate a vector of 10000 ints : 2.519e-05 s
Time to fill and iterate a vector of 1000000 ints : 0.00207669 s
Time to fill and iterate a vector of 100000000 ints : 0.423087 s


std::chrono::operator<<(std::chrono::gps_time)

< cpp‎ | chrono‎ | gps clock

定义于头文件 <chrono>
template <class CharT, class Traits, class Duration>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::gps_time<Duration>& tp);
 (C++20 起)

输出 tp 到流 os 中，如同用 os << std::format(STATICALLY_WIDEN<CharT>("{:L%F %T}"), tp) ，其中 STATICALLY_WIDEN<CharT>("{:L%F %T}") 若 CharT 为 char 则为 "{:L%F %T}" ，而若 CharT 为 wchar_t 则为 L"{:L%F %T}" 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

std::formatter<std::chrono::gps_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 gps_time (类模板特化)
format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)


std::chrono::gps_clock::to_utc

< cpp‎ | chrono‎ | gps clock
template <class Duration>

static std::chrono::utc_time< std::common_type_t <Duration, std::chrono::seconds >>

to_utc(const std::chrono::gps_time<Duration>& t) noexcept;
 (C++20 起)

转换 gps_time t 为表示同一时间点的 utc_time 。

返回值

与 t 表示相同时间点的 std::chrono::utc_time ，如同从 t.time_since_epoch() 构造返回类型的值并加上 315964809s 一般计算。（ 315964809 是时钟 gps_clock 的纪元 1980-01-06 00:00:00 UTC 和时钟 utc_clock 的纪元 1970-01-01 00:00:00 UTC 间的秒数。）

参阅

from_utc [静态] | 转换 utc_time 为 gps_time (公开静态成员函数)
clock_cast (C++20) | 转换一个时钟的时间点为另一个 (函数模板)


std::chrono::hh_mm_ss

< cpp‎ | chrono
定义于头文件 <chrono> |
template< class Duration > class hh_mm_ss; | (C++20 起)

类模板 hh_mm_ss 将 std::chrono::duration 分割成如 时:分:秒 的“拆分”时刻，拆分的精度由 Duration 模板形参确定。它主要是格式化工具。

Duration 必须是 std::chrono::duration 的特化，否则程序非良构。

成员常量

constexpr unsigned fractional_width
[静态]
 范围 [0, 18] 中的最小可能整数，使得 precision （见后述）将准确地表达 Duration{1} 的值，或若无这种整数则为 6
(公开静态成员常量)

成员类型

成员类型 定义
precision std::chrono::duration<std::common_type_t<Duration::rep, std::chrono::seconds::rep>, std::ratio<1, 10fractional_width
>>

成员函数

(构造函数) | 构造 hh_mm_ss (公开成员函数)
is_negativehoursminutessecondssubseconds | 获得拆分时刻的组分 (公开成员函数)
operator precisionto_duration | 获得存储的 std::chrono::duration (公开成员函数)

非成员函数

operator<<
(C++20)
 输出 hh_mm_ss 到流中
(函数模板)

辅助类

std::formatter<std::chrono::hh_mm_ss>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 hh_mm_ss
(类模板特化)


std::chrono::hh_mm_ss<Duration>::is_negative, std::chrono::hh_mm_ss<Duration>::hours, std::chrono::hh_mm_ss<Duration>::minutes, std::chrono::hh_mm_ss<Duration>::seconds, std::chrono::hh_mm_ss<Duration>::subseconds

< cpp‎ | chrono‎ | hh mm ss
constexpr bool is_negative() const noexcept; | (1)
constexpr std::chrono::hours hours() const noexcept; | (2)
constexpr std::chrono::minutes minutes() const noexcept; | (3)
constexpr std::chrono::seconds seconds() const noexcept; | (4)
constexpr precision subseconds() const noexcept; | (5)

获得存储的“拆分”时间的组分。

返回值

令 d 为表示的时长：

1) 若 d 为负则为 true ，否则为 false 。
2) std::chrono::duration_cast < std::chrono::hours >(abs(d)) 。
3) std::chrono::duration_cast < std::chrono::minutes >(abs(d) - hours()) 。
4) std::chrono::duration_cast < std::chrono::seconds >(abs(d) - hours() - minutes()) 。
5) 若 std::chrono::treat_as_floating_point_v<precision::rep> 为 true 则为 abs(d) - hours() - minutes() - seconds() ；否则为 std::chrono::duration_cast <precision>(abs(d) - hours() - minutes() - seconds()) 。

示例

本节未完成
原因：暂无示例


std::chrono::hh_mm_ss<Duration>::operator precision, std::chrono::hh_mm_ss<Duration>::to_duration

< cpp‎ | chrono‎ | hh mm ss
constexpr explicit operator precision() const noexcept; | (1)
constexpr precision to_duration() const noexcept; | (2)

返回表示的时长。

返回值

表示的时长。

示例

本节未完成
原因：暂无示例


std::chrono::hh_mm_ss<Duration>::hh_mm_ss

< cpp‎ | chrono‎ | hh mm ss
constexpr hh_mm_ss() noexcept : hh_mm_ss{Duration::zero()} {} | (1)
explicit constexpr hh_mm_ss( Duration d ); | (2)

构造 hh_mm_ss 对象。

1) 构造对应 Duration::zero() 的 hh_mm_ss 对象。
2) 构造对应 d 的 hh_mm_ss 对象：
  • is_negative() 返回 d < Duration::zero() 。
  • hours() 返回 std::chrono::duration_cast < std::chrono::hours >(abs(d)) 。
  • minutes() 返回 std::chrono::duration_cast < std::chrono::minutes >(abs(d) - hours()) 。
  • seconds() 返回
    std::chrono::duration_cast < std::chrono::seconds >(abs(d) - hours() - minutes()) 。
  • 若 std::chrono::treat_as_floating_point_v<precision::rep> 为 true 则 subseconds() 返回 abs(d) - hours() - minutes() - seconds() ；否则返回 std::chrono::duration_cast <precision>(abs(d) - hours() - minutes() - seconds()) 。

参数

d - 要拆分的时长。

示例

本节未完成
原因：暂无示例


std::chrono::operator<<(std::chrono::hh_mm_ss)

< cpp‎ | chrono‎ | hh mm ss
定义于头文件 <chrono>
template< class CharT, class Traits, class Duration >

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::hh_mm_ss<Duration>& t );
 (C++20 起)

输出 t 到流 os 中。

等价于 return os << std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{:%T}"), hms); ，其中 STATICALLY_WIDEN<CharT>("{:L%T}") 若 CharT 为 char 则为 "{:L%T}" ，而若 CharT 为 wchar_t 则为 L"{:L%T}" 。

参数

os | - | 输出流。
t | - | 要输出的当天时刻。

返回值

os 。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::hh_mm_ss> (C++20) | std::formatter 的特化，按照提供的格式格式化 hh_mm_ss (类模板特化)


std::chrono::high_resolution_clock

< cpp‎ | chrono
定义于头文件 <chrono> |
class high_resolution_clock; | (C++11 起)

类 std::chrono::high_resolution_clock 表示实现提供的拥有最小计次周期的时钟。它可以是 std::chrono::system_clock 或 std::chrono::steady_clock 的别名，或第三个独立时钟。

std::chrono::high_resolution_clock 满足平凡时钟 (TrivialClock) 的要求。

成员类型

成员类型 | 定义
rep | 表示时钟的时期中计次数的算术类型
period | 表示时钟计次周期的 std::ratio 类型，单位为秒
duration | std::chrono::duration <rep, period>
time_point | std::chrono::time_point <std::chrono::high_resolution_clock>

成员常量

constexpr bool is_steady
[静态]
 若时间间隔计次始终为常量，即纵使在外部时钟调整的情况下，调用 now() 的返回值亦单调递增，则为 true ，否则为 false
(公开静态成员常量)

成员函数

now
[静态]
 返回表示时钟当前值的 std::chrono::time_point
(公开静态成员函数)

注解

high_resolution_clock 在不同标准库实现之间实现并不一致，尽量不要使用。通常它只是 std::chrono::steady_clock 或 std::chrono::system_clock 的别名——它是 system_clock 时不是单调的（即时间能后退），但具体实现取决于库或配置。例如：对于 gcc 的 libstdc++ 它是 system_clock ，对于 MSVC 它是 steady_clock ，而对于 clang 的 libc++ 它取决于配置。

通常用户应该直接使用 std::chrono::steady_clock 或 std::chrono::system_clock 代替 std::chrono::high_resolution_clock ：对时长度量使用 steady_clock ，对壁钟时间使用 system_clock 。

参阅

system_clock (C++11) | 来自系统范围实时时钟的壁钟时间 (类)
steady_clock (C++11) | 决不调整的单调时钟 (类)


std::chrono::high_resolution_clock::now

< cpp‎ | chrono‎ | high resolution clock

static std::chrono::time_point < std::chrono::high_resolution_clock > now() noexcept; | (C++11 起)

返回表示当前时间的时间点。

参数

（无）

返回值

表示当前时间的时间点。

示例

#include <iostream>
#include <vector>
#include <numeric>
#include <chrono>

volatile int sink;
int main()
{
    for (auto size = 1ull; size < 1000000000ull; size *= 100) {
        // 记录开始时间
        auto start = std::chrono::high_resolution_clock::now();
        // 做一些工作
        std::vector<int> v(size, 42);
        sink = std::accumulate(v.begin(), v.end(), 0u); // 确保其副效应
        // 记录结束时间
        auto end = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double> diff = end-start;
        std::cout << "Time to fill and iterate a vector of "
                  << size << " ints : " << diff.count() << " s\n";
    }
}

可能的输出：

Time to fill and iterate a vector of 1 ints : 2.43e-07 s
Time to fill and iterate a vector of 100 ints : 4.1e-07 s
Time to fill and iterate a vector of 10000 ints : 2.519e-05 s
Time to fill and iterate a vector of 1000000 ints : 0.00207669 s
Time to fill and iterate a vector of 100000000 ints : 0.423087 s


std::chrono::is_am, std::chrono::is_pm, std::chrono::make12, std::chrono::make24

< cpp‎ | chrono
定义于头文件 <chrono>
constexpr bool is_am( const std::chrono::hours & h ) noexcept;
 (1) (C++20 起)
constexpr bool is_pm( const std::chrono::hours & h ) noexcept;
 (2) (C++20 起)
constexpr std::chrono::hours make12( const std::chrono::hours & h ) noexcept;
 (3) (C++20 起)
constexpr std::chrono::hours make24( const std::chrono::hours & h,
bool is_pm ) noexcept;
 (4) (C++20 起)

这些函数辅助在 12 时格式与 24 时格式的日之时间之间翻译。

1) 检测 24 时格式时间是否为 a.m. （ ante meridiem ，午前）。
2) 检测 24 时格式时间是否为 p.m. （ post meridiem ，午后）。
3) 返回 24 时格式时间的 12 时等价版本。
4) 返回 12 时格式时间 h 的 24 时等价版本，其中 is_pm 确定时间是否为 p.m. 。

参数

h | - | 要检测的 12 时或 24 时格式时间
is_pm | - | 确定 12 时格式时间是否为 p.m.

返回值

1) 0h <= h && h <= 11h。
2) 12h <= h && h <= 23h。
3) 若 h 在范围 [0h, 23h] 内，则返回范围 [1h, 12h] 内的 12 时等价版本。否则返回值未指定。
4) 若 h 在范围 [1h, 12h] 内，则返回范围 [0h, 11h] 内的 24 时等价版本，若 is_pm 为 false ，否则结果在范围 [12h, 23h] 内。否则返回值未指定。

示例

#include <iostream>
#include <iomanip>
#include <utility>
#include <chrono>

int main()
{
    using namespace std::chrono;

    static_assert(
        is_am(10h) &&  is_am(11h) && !is_am(12h) && !is_am(23h) &&
       !is_pm(10h) && !is_pm(11h) &&  is_pm(12h) &&  is_pm(23h)
    );

    std::cout << "make12():\n";

    for (const hours hh : { 0h, 1h, 11h, 12h, 13h, 23h }) {
        const hours am{make12(hh)};
        std::cout << std::setw(2) << hh.count() << "h == "
                  << std::setw(2) << am.count() << (is_am(hh) ? "h a.m.\n" : "h p.m.\n");
    }

    std::cout << "\nmake24():\n";

    using p = std::pair<hours, bool>;

    for (const auto& [hh, pm] : { p{1h, 0}, p{12h, 0}, p{1h, 1}, p{12h, 1} }) {
        std::cout << std::setw(2) << hh.count()
                  << (pm ? "h p.m." : "h a.m.")
                  << " == " << std::setw(2)
                  << make24(hh, pm).count() << "h\n";
    }
}

输出：

make12():
 0h == 12h a.m.
 1h ==  1h a.m.
11h == 11h a.m.
12h == 12h p.m.
13h ==  1h p.m.
23h == 11h p.m.

make24():
 1h a.m. ==  1h
12h a.m. ==  0h
 1h p.m. == 13h
12h p.m. == 12h


std::chrono::is_clock

< cpp‎ | chrono
定义于头文件 <chrono> |
template< class T > struct is_clock; | (C++20 起)

若 T 满足时钟 (Clock) 要求，则提供等于 true 的成员常量 value ，对于任何其他类型， value 为 false 。

为此特性的目的，实现确定类型不能满足时钟 (Clock) 要求的外延是未指定的，除了至少 T 不应当具备时钟 (Clock) 的资格，除非它满足所有下列条件：

  • qualified-id T::rep 、 T::period 、 T::duration 和 T::time_point 均合法并且每个都代表一个类型；
  • 表达式 T::is_steady 和 T::now() 在当做不求值运算数时均为良构。

添加 is_clock 或 is_clock_v 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_clock_v = is_clock<T>::value; | (C++20 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 满足时钟 (Clock) 要求则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template<class>
struct is_clock : std::false_type {};

template<class T>
    requires
        requires {
            typename T::rep;
            typename T::period;
            typename T::duration;
            typename T::time_point;
            T::is_steady;
            T::now();
        }
struct is_clock<T> : std::true_type {};


std::chrono::last_spec, std::chrono::last

< cpp‎ | chrono
定义于头文件 <chrono>
struct last_spec

{
explicit last_spec() = default;

};
 (C++20 起)
inline constexpr last_spec last{};
 (C++20 起)

last_spec 是用于与其他日历类型合取，以指示序列中最后一项的空标签类型。依赖于语境，它可以指示月的最后一日（如在对于 2018 年二月的最后一日，即 2018-02-28 的 2018y/February/last 中）或月中的星期的最后一日（如在对于 2018 年二月最后一个星期日，即 2018-02-25 的 2018/February/Sunday[last] 中）。

示例

#include <iostream>
#include <chrono>

int main()
{
    std::cout << std::boolalpha;

    constexpr auto mdl {std::chrono::June/std::chrono::last};
    std::cout << (mdl == std::chrono::month_day_last(std::chrono::month(6))) << ' ';

    constexpr auto ymwdl {std::chrono::year(2023)/
                          std::chrono::December/
                          std::chrono::Tuesday[std::chrono::last]
                         };
    std::cout << (ymwdl == std::chrono::year_month_weekday_last(
                           std::chrono::year(2023),
                           std::chrono::month(12),
                           std::chrono::weekday_last(std::chrono::Tuesday))
                           ) << '\n';
}

输出：

true true


std::chrono::leap_second

< cpp‎ | chrono
定义于头文件 <chrono> |
class leap_second; | (C++20 起)

类 leap_second 表示日期和插入闰秒的时间。

用户不能构造 leap_second 对象，除了通过从既存的 leap_second 对象复制。库实现在初始化时区数据库时创建 leap_second 对象，并提供对这些对象的 const 访问。

leap_second 拥有默认化的复制构造函数和默认化的复制赋值运算符。

成员函数

date
 获得插入闰秒的时间
(公开成员函数)

非成员函数

operator==operator<operator<=operator>operator>=operator<=>
(C++20)
 比较二个 leap_second 值或一个 leap_second 值与一个 sys_time
(函数模板)


std::chrono::leap_second::date

< cpp‎ | chrono‎ | leap second
constexpr std::chrono::sys_seconds date() const noexcept;

获得日期和插入闰秒的时间。

返回值

表示日期和插入闰秒时间的 std::chrono::sys_seconds 。


std::chrono::operator==,<,<=,>,>=,<=>(std::chrono::leap_second)

< cpp‎ | chrono‎ | leap second
定义于头文件 <chrono>
constexpr bool operator==( const std::chrono::leap_second& x,
const std::chrono::leap_second& y ) noexcept;
 (1) (C++20 起)
constexpr std::strong_ordering operator<=>( const std::chrono::leap_second& x,
const std::chrono::leap_second& y ) noexcept;
 (2) (C++20 起)
template< class Duration >

constexpr bool operator==( const std::chrono::leap_second& x,

const std::chrono::sys_time<Duration>& y ) noexcept;
 (3) (C++20 起)
template< class Duration >

constexpr bool operator< ( const std::chrono::leap_second& x,

const std::chrono::sys_time<Duration>& y ) noexcept;
 (4) (C++20 起)
template< class Duration >

constexpr bool operator< ( const std::chrono::sys_time<Duration>& x,

const std::chrono::leap_second& y ) noexcept;
 (5) (C++20 起)
template< class Duration >

constexpr bool operator> ( const std::chrono::leap_second& x,

const std::chrono::sys_time<Duration>& y ) noexcept;
 (6) (C++20 起)
template< class Duration >

constexpr bool operator> ( const std::chrono::sys_time<Duration>& x,

const std::chrono::leap_second& y ) noexcept;
 (7) (C++20 起)
template< class Duration >

constexpr bool operator<=( const std::chrono::leap_second& x,

const std::chrono::sys_time<Duration>& y ) noexcept;
 (8) (C++20 起)
template< class Duration >

constexpr bool operator<=( const std::chrono::sys_time<Duration>& x,

const std::chrono::leap_second& y ) noexcept;
 (9) (C++20 起)
template< class Duration >

constexpr bool operator>=( const std::chrono::leap& x,

const std::chrono::sys_time<Duration>& y ) noexcept;
 (10) (C++20 起)
template< class Duration >

constexpr bool operator>=( const std::chrono::sys_time<Duration>& x,

const std::chrono::leap_second& y ) noexcept;
 (11) (C++20 起)
template< class Duration >

requires std::three_way_comparable_with<
std:chrono::sys_seconds, std::chrono::sys_time<Duration>>
constexpr auto operator<=>( const std::chrono::leap_second& x,

const std::chrono::sys_time<Duration>& y ) noexcept;
 (12) (C++20 起)

比较对象 x 与 y 所表示的日期和时间。

(12) 的返回类型从 x.date() <=> y 推导，从而为 std::chrono::seconds 与 Duration 的三路比较结果类型。

!= 运算符从 operator== 合成。

返回值

1) x.date() == y.date()
2) x.date() <=> y.date()
3) x.date() == y
4) x.date() < y
5) x < y.date()
6) x.date() > y
7) x > y.date()
8) x.date() <= y
9) x <= y.date()
10) x.date() >= y
11) x >= y.date()
12) x.date() <=> y


std::chrono::local_info

< cpp‎ | chrono
定义于头文件 <chrono> |
struct local_info; | (C++20 起)

类 local_info 描述转换 std::chrono::local_time 为 std::chrono::sys_time 的结果。

  • 若转换结果唯一，则 result == local_info::unique ，以正确的 std::chrono::sys_info 填充 first ，并零初始化 second 。
  • 若 local_time 不存在，则 result == local_info::nonexistent ，以恰在 local_time 前结束的 std::chrono::sys_info 填充 first ，并以恰在 local_time 后开始的 std::chrono::sys_info 填充 second 。
  • 若 local_time 有歧义，则 result == local_info::ambiguous ，以恰在 local_time 后结束的 std::chrono::sys_info 填充 first ，并以恰在 local_time 前开始的 std::chrono::sys_info 填充 second 。

这是低层数据结构；从 local_time 到 sys_time 的典型转换将隐式使用它，而非显式。

成员常量

名称 | 值
constexpr int unique [静态] | 0 (公开静态成员常量)
constexpr int nonexistent [静态] | 1 (公开静态成员常量)
constexpr int ambiguous [静态] | 2 (公开静态成员常量)

成员对象

成员对象 | 类型
result | int
first, second | std::chrono::sys_info

非成员函数

operator<<
(C++20)
 输出 local_info 对象到流中
(函数模板)

辅助类

std::formatter<std::chrono::local_info>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 local_info
(类模板特化)


std::chrono::operator<< (std::chrono::local_info)

< cpp‎ | chrono‎ | local info
定义于头文件 <chrono>
template<class CharT, class Traits>

std::basic_ostream <CharT, Traits>& operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::local_info& r);
 (C++20 起)

插入 r 的文本表示到 os 中。准确格式未指定。

返回值

os 。


std::chrono::local_t

< cpp‎ | chrono
定义于头文件 <chrono> |
struct local_t {}; | (C++20 起)

类 local_t 是用作 std::chrono::time_point 的第一模板实参的伪时钟，用于指定指示时间点表示相对于仍未指定的时区的本地时间。 local_time 支持流操作和时间点算术的全集。

时间点族

定义于命名空间 std::chrono |
template<class Duration> using local_time = std::chrono::time_point <std::chrono::local_t, Duration>; | (C++20 起)
using local_seconds = local_time< std::chrono::seconds >; | (C++20 起)
using local_days = local_time<std::chrono::days>; | (C++20 起)
operator<<(std::chrono::local_time) (C++20) | 进行 local_time 上的流输出 (函数模板)
from_stream(std::chrono::local_time) (C++20) | 按照给定的格式从流分析 local_time (函数模板)
std::formatter<std::chrono::local_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 local_time (类模板特化)


std::chrono::operator<<(std::chrono::local_time)

< cpp‎ | chrono‎ | local t
template <class CharT, class Traits, class Duration>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::local_time<Duration>& tp);
 (C++20 起)

如同用 os << std::chrono::sys_time<Duration>(tp.time_since_epoch()); 输出 tp 到流 os 中。

返回值

os 。

参阅

operator<<(std::chrono::sys_time)
(C++20)
 进行 sys_time 上的流输出
(函数模板)


std::chrono::locate_zone

< cpp‎ | chrono
定义于头文件 <chrono> |
const std::chrono::time_zone* locate_zone( std::string_view tz_name); | (C++20 起)

在时区数据库中定位时区的便利函数。等价于 std::chrono::get_tzdb().locate_zone(tz_name) 。

异常

若找不到指定的时区，或若这次调用是对时区数据库的首次引用且无法初始化时区数据库，则抛出 std::runtime_error 。

注意

若对此函数的调用是对时区数据库的首次引用，则它将导致初始化时区数据库。

参阅

locate_zone | 以给定的名称定位时区 (std::chrono::tzdb 的公开成员函数)
get_tzdbget_tzdb_listreload_tzdbremote_version (C++20) | 访问和控制全球时区数据库信息 (函数)


std::chrono::month

< cpp‎ | chrono
定义于头文件 <chrono> |
class month; | (C++20 起)
inline constexpr std::chrono::month January{1}; | (C++20 起)
inline constexpr std::chrono::month February{2}; | (C++20 起)
inline constexpr std::chrono::month March{3}; | (C++20 起)
inline constexpr std::chrono::month April{4}; | (C++20 起)
inline constexpr std::chrono::month May{5}; | (C++20 起)
inline constexpr std::chrono::month June{6}; | (C++20 起)
inline constexpr std::chrono::month July{7}; | (C++20 起)
inline constexpr std::chrono::month August{8}; | (C++20 起)
inline constexpr std::chrono::month September{9}; | (C++20 起)
inline constexpr std::chrono::month October{10}; | (C++20 起)
inline constexpr std::chrono::month November{11}; | (C++20 起)
inline constexpr std::chrono::month December{12}; | (C++20 起)

类 month 表示年中的月。其正常范围为 [1, 12] ，但它可保有 [0, 255] 中的任何数。在 std::chrono 命名空间中为年的十二个月份定义十二个具名常量。

month 是可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 month (公开成员函数)
operator++operator++(int)operator--operator--(int) | 自增或自减 month (公开成员函数)
operator+=operator-= | 加或减月数 (公开成员函数)
operator unsigned | 取得存储的月份值 (公开成员函数)
ok | 检查存储的月份值是否在正常范围中 (公开成员函数)

非成员函数

operator==operator<=> (C++20) | 比较二个 month 值 (函数)
operator+operator- (C++20) | 进行 month 上的算术 (函数)
operator<< (C++20) | 输出 month 到流中 (函数模板)
from_stream (C++20) | 按照提供的格式从流分析 month (函数模板)

辅助类

std::formatter<std::chrono::month>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 month
(类模板特化)


std::chrono::month::month

< cpp‎ | chrono‎ | month
month() = default; | (1) | (C++20 起)
explicit constexpr month(unsigned m) noexcept; | (2) | (C++20 起)

构造 month 对象。

1) 默认构造函数使得月份值未初始化。
2) 若 m <= 255 ，则构造保有月份值 m 的 month 对象。否则保有的值未指定。


std::chrono::month::ok

< cpp‎ | chrono‎ | month
constexpr bool ok() const noexcept; | (C++20 起)

检查存储于 *this 的月份值是否在合法范围，即 [1, 12] 中。

返回值

若存储于 *this 的月份值在范围 [1, 12] 中则为 true 。否则为 false 。


std::chrono::month::operator+=, std::chrono::month::operator-=

< cpp‎ | chrono‎ | month
constexpr std::chrono::month& operator+=(const std::chrono::months& m) noexcept; | (1) | (C++20 起)
constexpr std::chrono::month& operator+=(const std::chrono::months& m) noexcept; | (2) | (C++20 起)

对月份值加或减 m.count() ，将结果对 12 取余，规约成范围 [1, 12] 中的整数。

1) 进行 *this = *this + m;
2) 进行 *this = *this - m;

返回值

到修改后的此 month 的引用。

注意

调用这些函数之一后，若运算中不出现溢出则 ok() 始终为 true 。

示例

#include <iostream>
#include <chrono>

int main()
{
    std::cout << std::boolalpha;

    std::chrono::month m {6};
    m += std::chrono::months(2);
    std::cout << (m == std::chrono::month(8)) << ' '
              << (m == std::chrono::August) << ' ';

    m -= std::chrono::months(3);
    std::cout << (m == std::chrono::month(5)) << ' '
              << (m == std::chrono::May) << ' ';

    m = std::chrono::October;
    m += std::chrono::months{8}; // ((10 += 8 == 18) % 12) == 6;
    std::cout << (m == std::chrono::June) << ' ';

    m -= std::chrono::months{std::chrono::December - std::chrono::February}; // -= 10
    // (6 -= 10) == -4; -4 % 12 == (12-4) == 8
    std::cout << (m == std::chrono::August) << '\n';
}

输出：

true true true true true true

参阅

operator++operator++(int)operator--operator--(int) | 自增或自减 month (公开成员函数)
operator+operator- (C++20) | 进行 month 上的算术 (函数)


std::chrono::operator+, std::chrono::operator- (std::chrono::month)

< cpp‎ | chrono‎ | month
constexpr std::chrono::month operator+(const std::chrono::month& m,
const std::chrono::months& ms) noexcept;
 (1) (C++20 起)
constexpr std::chrono::month operator+(const std::chrono::months& ms,
const std::chrono::month& m) noexcept;
 (2) (C++20 起)
constexpr std::chrono::month operator-(const std::chrono::month& m,
const std::chrono::months& ms) noexcept;
 (3) (C++20 起)
constexpr std::chrono::months operator-(const std::chrono::month& m1,
const std::chrono::month& m2) noexcept;
 (4) (C++20 起)
1-2) 将 ms.count() 个月加到 m 。通过首先求值 static_cast<long long>(unsigned(m)) + (ms.count() - 1) ，将它对 12 取余变成 [0, 11] 范围中的整数，再加 1 ，计算结果中保有的月份值。
3) 从 m 减去 ms.count() 个月并返回结果。等价于 return m + -ms; 。
4) 若 m1.ok() 与 m2.ok() 均为 true ，则返回 std::chrono::months 值 m ，使得 m.count() 在范围 [0, 11] 中且 m2 + m == m1 。否则返回值未指定。

返回值

1-3) 保有按上述方式计算的月份值的 std::chrono::month 。
4) 表示 m1 与 m2 间距离的 std::chrono::months 。

注意

只要计算不溢出， (1-3) 就始终返回合法的月份，即使 m.ok() 为 false 。

二个 month 值相减的结果是 std::chrono::months 类型的时长。时长单位表示格里高利月的平均长度，而产生的时长与运算数所表示的具体月分的日数无关。例如 std::chrono::seconds (std::chrono::April - std::chrono::March) 不是三月中的秒数 (2678400s) ，而是 2629746s (30.436875 days) 。

示例

#include <cassert>
#include <chrono>

int main()
{
    std::chrono::month m {6};

    m = m + std::chrono::months(2);
    assert(m == std::chrono::month(8));

    m = m - std::chrono::months(3);
    assert(m == std::chrono::month(5));

    constexpr std::chrono::months ms = std::chrono::month(8) - std::chrono::month(6);
    static_assert(ms == std::chrono::months(2));
}

参阅

operator++operator++(int)operator--operator--(int) | 自增或自减 month (公开成员函数)
operator+=operator-= | 加或减月数 (公开成员函数)


std::chrono::operator==,<=>(std::chrono::month)

< cpp‎ | chrono‎ | month
定义于头文件 <chrono>
constexpr bool operator==( const std::chrono::month& x,
const std::chrono::month& y ) noexcept;
 (1) (C++20 起)
constexpr std::strong_ordering operator<=>( const std::chrono::month& x,
const std::chrono::month& y ) noexcept;
 (2) (C++20 起)

比较二个 std::chrono::month x 与 y 。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

返回值

1) unsigned(x) == unsigned(y)
2) unsigned(x) <=> unsigned(y)

示例

#include <iostream>
#include <chrono>

int main()
{
    constexpr std::chrono::month m1{6};
    constexpr std::chrono::month m2{8};

    std::cout << std::boolalpha
        << (m1 < m2) << ' ' << (m1 == m1) << ' ' << (m1 <= m2) << ' '
        << (m2 > m1) << ' ' << (m2 != m1) << ' ' << (m2 >= m1) << '\n';
}

输出：

true true true true true true


std::chrono::month::operator++, std::chrono::month::operator--

< cpp‎ | chrono‎ | month
constexpr std::chrono::month& operator++() noexcept; | (1) | (C++20 起)
constexpr std::chrono::month operator++(int) noexcept; | (2) | (C++20 起)
constexpr std::chrono::month& operator--() noexcept; | (3) | (C++20 起)
constexpr std::chrono::month operator--(int) noexcept; | (4) | (C++20 起)

对月份值加或减 1 ，将结果对 12 取余，规约成范围 [1, 12] 中的整数。

1-2) 进行 *this += std::chrono::months{1};
3-4) 进行 *this -= std::chrono::months{1};

参数

（无）

返回值

1,3) 到修改后的此 month 的引用。
2,4) 修改前所作的 month 的副本。

注意

调用这些函数之一后， ok() 始终为 true 。

参数

#include <cassert>
#include <iostream>
#include <chrono>

int main()
{
    std::chrono::month m {6};

    ++m;
    assert(m == std::chrono::month(7));

    --m;
    assert(m == std::chrono::month(6));

    m = std::chrono::December;
    m++; // 进入一月
    assert(m.ok());
    std::cout << unsigned(m) << '\n';

    m = std::chrono::January;
    m--; // 回到十二月
    assert(m.ok());
    std::cout << unsigned(m) << '\n';
}

输出：

1
12

参阅

operator+=operator-= | 加或减月数 (公开成员函数)
operator+operator- (C++20) | 进行 month 上的算术 (函数)


std::chrono::operator<<(std::chrono::month)

< cpp‎ | chrono‎ | month
定义于头文件 <chrono>
template <class CharT, class Traits>

std::basic_ostream <CharT, Traits>&

operator<<( std::basic_ostream <CharT, Traits>& os, const std::chrono::month& m);
 (C++20 起)

若 !m.ok() ，则插入 unsigned(m) 后随 " is not a valid month" 到 os 。否则，构成由 m 所表示的月的，以与 os 关联的本地环境确定的缩写月份名组成的 std::basic_string<CharT> s ，并插入 s 到 os 中。

等价于

return os << (m.ok() ?
std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{:L%b}"), m) :
std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{} is not a valid month"), unsigned(m)));

其中 STATICALLY_WIDEN<CharT>("...") 若 CharT 为 char 则为 "..." ，而若 CharT 为 wchar_t 则为 L"..." 。

返回值

os 。

注解

此 operator<< 主要为调试用途而设，对于格式化上的控制，请用 std::format 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::month> (C++20) | std::formatter 的特化，按照提供的格式格式化 month (类模板特化)


std::chrono::month::operator unsigned

< cpp‎ | chrono‎ | month
explicit constexpr operator unsigned() const noexcept; | (C++20 起)

返回存储于 *this 的月份值。

返回值

存储于 *this 的月份值。


std::chrono::month_day

< cpp‎ | chrono
定义于头文件 <chrono> |
class month_day; | (C++20 起)

类 month_day 表示待指定年的特定月的特定日。

month_day 是可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 month_day (公开成员函数)
monthday | 取得存储的 month 和 day 值 (公开成员函数)
ok | 检查 month_day 是否合法 (公开成员函数)

非成员函数

operator==operator<=> (C++20) | 比较二个 month_day 值 (函数)
operator<< (C++20) | 输出 month_day 到流中 (函数模板)
from_stream (C++20) | 按照提供的格式从流分析 month_day (函数模板)

辅助类

std::formatter<std::chrono::month_day>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 month_day
(类模板特化)


std::chrono::month_day::month, std::chrono::month_day::day

< cpp‎ | chrono‎ | month day
constexpr std::chrono::month month() const noexcept; | (1) | (C++20 起)
constexpr std::chrono::day day() const noexcept; | (1) | (C++20 起)

取得存储于此 month_day 对象的月和日期值。

1) 返回存储的 std::chrono::month 值。
2) 返回存储的 std::chrono::day 值。


std::chrono::month_day::month_day

< cpp‎ | chrono‎ | month day
month_day() = default; | (1) | (C++20 起)
constexpr month_day(const std::chrono::month& m, const std::chrono::day& d) noexcept; | (2) | (C++20 起)

构造 month_day 。

1) 默认构造函数保留存储的月和日期值未初始化。
2) 构造存储月 m 和日 d 的 month_day 。

注意

更方便的构造 month_day 的方式是用 operator/ ，例如 std::chrono::April/1 。

参阅

operator/
(C++20)
 创建格里高利历日期的约定语法
(函数)


std::chrono::month_day::ok

< cpp‎ | chrono‎ | month day
constexpr bool ok() const noexcept; | (C++20 起)

确定此 month_day 是否存储合法的月日组合。

若 month() 表示合法月份（ month().ok() == true ）， unsigned{day()} >= 1 且 unsigned{day()} <= D ，其中 D 为 month() 所表示的月中的日数，则组合合法。二月中的日数被认为是 29 。

返回值

若月和日的组合合法则为 true ，否则为 false 。


std::chrono::operator==,<=>(std::chrono::month_day)

< cpp‎ | chrono‎ | month day
定义于头文件 <chrono>
constexpr bool operator==( const std::chrono::month_day& x,
const std::chrono::month_day& y ) noexcept;
 (1) (C++20 起)
constexpr std::strong_ordering operator!=( const std::chrono::month_day& x,
const std::chrono::month_day& y ) noexcept;
 (2) (C++20 起)

比较二个 month_day 值。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

返回值

1) x.month() == y.month() && x.day() == y.day()
2) x.month() <=> y.month() != 0 ? x.month() <=> y.month() : x.day() <=> y.day()

示例

#include <iostream>
#include <chrono>

int main()
{
    constexpr auto md1 {std::chrono::August/15};
    constexpr auto md2 {std::chrono::month(8)/std::chrono::day(15)};
    std::cout << std::boolalpha << (md1 == md2) << '\n';

    static_assert(md1 <= md2);
}

输出：

true


std::chrono::operator<<(std::chrono::month_day)

< cpp‎ | chrono‎ | month day
定义于头文件 <chrono>
template< class CharT, class Traits >

std::basic_ostream <CharT, Traits>&

operator<<( std::basic_ostream <CharT, Traits>& os, const std::chrono::month_day& md );
 (C++20 起)

插入 md 的文本表示到流 os 中，如同用

os << std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{:L}/{}"), md.month(), md.day())

其中 STATICALLY_WIDEN<CharT>("{:L}/{}") 若 CharT 为 char 则为 "{:L}/{}" ，而若 CharT 为 wchar_t 则为 L"{:L}/{}" 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::month_day> (C++20) | std::formatter 的特化，按照提供的格式格式化 month_day (类模板特化)


std::chrono::month_day_last

< cpp‎ | chrono
定义于头文件 <chrono> |
class month_day_last; | (C++20 起)

类 month_day_last 表示某个待指定年的特定月的最后一日。

month_day_last 是可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 month_day_last (公开成员函数)
month | 访问存储的 month (公开成员函数)
ok | 检查存储的 month 是否合法 (公开成员函数)

非成员函数

operator==operator<=> (C++20) | 比较二个 month_day_last 值 (函数)
operator<< (C++20) | 输出 month_day_last 到流中 (函数模板)

辅助类

std::formatter<std::chrono::month_day_last>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 month_day_last
(类模板特化)


std::chrono::month_day_last::month

< cpp‎ | chrono‎ | month day last
constexpr std::chrono::month month() const noexcept; | (C++20 起)

取得存储于 *this 的 std::chrono::month 对象副本。

返回值

存储于 *this 的 std::chrono::month 对象副本。


std::chrono::month_day_last::month_day_last

< cpp‎ | chrono‎ | month day last
explicit constexpr month_day_last(const std::chrono::month& m) noexcept; | (C++20 起)

构造表示月份 m 最后一日的 month_day_last 对象。

注意

更方便的构造 month_day_last 的方式是用 operator/ ，如 std::chrono::April/std::chrono::last 。

参阅

operator/
(C++20)
 创建格里高利历日期的约定语法
(函数)


std::chrono::month_day_last::ok

< cpp‎ | chrono‎ | month day last
constexpr bool ok() const noexcept; | (C++20 起)

检查存储于 *this 的 month 对象是否合法。

返回值

month().ok()


std::chrono::operator==,<=>(std::chrono::month_day_last)

< cpp‎ | chrono‎ | month day last
定义于头文件 <chrono>
constexpr bool operator==( const std::chrono::month_day_last& x,
const std::chrono::month_day_last& y ) noexcept;
 (1) (C++20 起)
constexpr std::strong_ordering operator<=>( const std::chrono::month_day_last& x,
const std::chrono::month_day_last& y ) noexcept;
 (2) (C++20 起)

比较二个 month_day_last 值 x 与 y 。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

返回值

1) x.month() == y.month()
2) x.month() <=> y.month()

示例

#include <iostream>
#include <chrono>

int main()
{
    constexpr auto mdl1 {std::chrono::February/std::chrono::last};
    constexpr std::chrono::month_day_last mdl2 {std::chrono::month(2)};
    std::cout << std::boolalpha << (mdl1 == mdl2) << '\n';

    static_assert(mdl1 <= mdl2);
}

输出：

true


std::chrono::operator<<(std::chrono::month_day_last)

< cpp‎ | chrono‎ | month day last
定义于头文件 <chrono>
template <class CharT, class Traits>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::month_day_last& mdl );
 (C++20 起)

输出 mdl 的文本表示到 os 中，如同用

os << std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{:L}/last"), mdl.month());

其中 STATICALLY_WIDEN<CharT>("{:L}/last") 若 CharT 为 char 则为 "..." ，而若 CharT 为 wchar_t 则为 L"{:L}/last" 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::month_day> (C++20) | std::formatter 的特化，按照提供的格式格式化 month_day (类模板特化)


std::chrono::month_weekday

< cpp‎ | chrono
定义于头文件 <chrono> |
class month_weekday; | (C++20 起)

类 month_weekday 表示某个待指定年的特定月的第 n 个星期之日。

month_weekday 是可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 month_weekday (公开成员函数)
monthweekday_indexed | 取得存储的 month 和 weekday_indexed 值 (公开成员函数)
ok | 检查所含的 month 与 weekday_indexed 是否均合法 (公开成员函数)

非成员函数

operator== (C++20) | 比较二个 month_weekday 值 (函数)
operator<< (C++20) | 输出 month_weekday 到流中 (函数模板)

辅助类

std::formatter<std::chrono::month_weekday>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 month_weekday
(类模板特化)


std::chrono::month_weekday::month, std::chrono::month_weekday::weekday_indexed

< cpp‎ | chrono‎ | month weekday
constexpr std::chrono::month month() const noexcept; | (1) | (C++20 起)
constexpr std::chrono::weekday_indexed weekday_indexed() const noexcept; | (2) | (C++20 起)

取得存储于 *this 的 month 和 weekday_indexed 对象的副本。

返回值

1) 存储于 *this 的 std::chrono::month 对象副本。
2) 存储于 *this 的 std::chrono::weekday_indexed 对象副本。


std::chrono::month_weekday::month_weekday

< cpp‎ | chrono‎ | month weekday
constexpr month_weekday(const std::chrono::month& m,
const std::chrono::weekday_indexed& wdi) noexcept;
 (C++20 起)

构造存储 month m 和 weekday_indexed wdi 的 month_weekday 对象。

注意

更方便的构造 month_weekday 的方法是用 operator/ ，如 std::chrono::April/std::chrono::Sunday[2] 。

参阅

operator/
(C++20)
 创建格里高利历日期的约定语法
(函数)


std::chrono::month_weekday::ok

< cpp‎ | chrono‎ | month weekday
constexpr bool ok() const noexcept; | (C++20 起)

检查所含的 month 和 weekday_indexed 对象是否均合法。

返回值

month().ok() && weekday_indexed().ok()


std::chrono::operator==(std::chrono::month_weekday)

< cpp‎ | chrono‎ | month weekday
定义于头文件 <chrono>
constexpr bool operator==(const std::chrono::month_weekday& x,
const std::chrono::month_weekday& y) noexcept;
 (C++20 起)

比较二个 month_weekday 值 x 与 y 。

!= 运算符从 operator== 合成。

返回值

x.month() == y.month() && x.weekday_indexed() == y.weekday_indexed() 。

示例

#include <iostream>
#include <chrono>

int main()
{
    constexpr auto mwdi1 {std::chrono::March/std::chrono::Friday[1]};
    constexpr std::chrono::month_weekday mwdi2 {std::chrono::month(3),
                                                std::chrono::weekday(5)[1]};
    std::cout << std::boolalpha << (mwdi1 == mwdi2) << '\n';
}

输出：

true


std::chrono::operator<<(std::chrono::month_weekday)

< cpp‎ | chrono‎ | month weekday
定义于头文件 <chrono>
template <class CharT, class Traits>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::month_weekday& mwd );
 (C++20 起)

输出 mwd 的文本表示到 os 中，如同用

os << std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{:L}/{:L}"),
mwd.month(), mwd.weekday_indexed());

其中 STATICALLY_WIDEN<CharT>("{:L}/{:L}") 若 CharT 为 char 则为 "{:L}/{:L}" ，而若 CharT 为 wchar_t 则为 L"{:L}/{:L}" 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::month> (C++20) | std::formatter 的特化，按照提供的格式格式化 month (类模板特化)


std::chrono::month_weekday_last

< cpp‎ | chrono
定义于头文件 <chrono> |
class month_weekday_last; | (C++20 起)

类 month_weekday_last 表示某个待指定年的特定月的最后一个星期之日。

month_weekday_last 是可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 month_weekday_last (公开成员函数)
monthweekday_last | 取得存储的 month 和 weekday_last 值 (公开成员函数)
ok | 检查所含的 month 和 weekday_last 是否合法 (公开成员函数)

非成员函数

operator== (C++20) | 比较二个 month_weekday_last 值 (函数)
operator<< (C++20) | 输出 month_weekday_last 到流中 (函数模板)

辅助类

std::formatter<std::chrono::month_weekday_last>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 month_weekday_last
(类模板特化)


std::chrono::month_weekday_last::month, std::chrono::month_weekday_last::weekday_last

< cpp‎ | chrono‎ | month weekday last
constexpr std::chrono::month month() const noexcept; | (1) | (C++20 起)
constexpr std::chrono::weekday_last weekday_last() const noexcept; | (2) | (C++20 起)

取得存储于 *this 的 month 和 weekday_last 对象副本。

返回值

1) 存储于 *this 的 std::chrono::month 对象副本。
2) 存储于 *this 的 std::chrono::weekday_last 对象副本。


std::chrono::month_weekday_last::month_weekday_last

< cpp‎ | chrono‎ | month weekday last
constexpr month_weekday_last(const std::chrono::month& m,
const std::chrono::weekday_last& wdl) noexcept;
 (C++20 起)

构造存储 month m 和 weekday_last wdl 的 month_weekday_last 对象。

注意

更方便的构造 month_weekday_last 的方式是用 operator/ ，例如 std::chrono::April/std::chrono::Sunday[std::chrono::last] 。

参阅

operator/
(C++20)
 创建格里高利历日期的约定语法
(函数)


std::chrono::month_weekday_last::ok

< cpp‎ | chrono‎ | month weekday last
constexpr bool ok() const noexcept; | (C++20 起)

检查所含的 month 和 weekday_last 对象是否均合法。

返回值

month().ok() && weekday_last().ok()


std::chrono::operator==(std::chrono::month_weekday_last)

< cpp‎ | chrono‎ | month weekday last
定义于头文件 <chrono>
constexpr bool operator==(const std::chrono::month_weekday_last& x,
const std::chrono::month_weekday_last& y) noexcept;
 (C++20 起)

比较二个 month_weekday_last 值 x 和 y 。

!= 运算符从 operator== 合成。

返回值

x.month() == y.month() && x.weekday_last() == y.weekday_last() 。

示例

#include <iostream>
#include <chrono>

int main()
{
    constexpr auto mwdl1 {std::chrono::March/std::chrono::Friday[std::chrono::last]};
    constexpr std::chrono::month_weekday_last mwdl2 {
                  std::chrono::March,
                  std::chrono::Friday[std::chrono::last]
              };
    static_assert(mwdl1 == mwdl2);
    std::cout << "Test passed.\n";
}

输出：

Test passed.


std::chrono::operator<<(std::chrono::month_weekday_last)

< cpp‎ | chrono‎ | month weekday last
定义于头文件 <chrono>
template <class CharT, class Traits>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::month_weekday_last& mwdl );
 (C++20 起)

输出 mwdl 的文本表示到 os 中，如同用

os << std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{:L}/{:L}"),
mwdl.month(), mwdl.weekday_last());

其中 STATICALLY_WIDEN<CharT>("{:L}/{:L}") 若 CharT 为 char 则为 "{:L}/{:L}" ，而若 CharT 为 wchar_t 则为 L"{:L}/{:L}" 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::month> (C++20) | std::formatter 的特化，按照提供的格式格式化 month (类模板特化)


std::chrono::nonexistent_local_time

< cpp‎ | chrono
定义于头文件 <chrono> |
class nonexistent_local_time; | (C++20 起)

定义要作为异常抛出的对象类型，以报告试图转换不存在的 std::chrono::local_time 为 std::chrono::sys_time 而不指定 std::chrono::choose （如 choose::earliest 或 choose::latest ）。

std::chrono::time_zone::to_sys 和调用它的函数（例如接收 std::chrono::zoned_time 的 std::chrono::local_time 构造函数）抛出此异常。

cpp/error/exception cpp/error/runtime error std-chrono-nonexistent local time-inheritance.svg

继承图

成员函数

(构造函数) | 构造异常对象 (公开成员函数)
operator= | 替换异常对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::chrono::nonexistent_local_time::nonexistent_local_time

template< class Duration >

nonexistent_local_time( const std::chrono::local_time<Duration>& tp,

const std::chrono::local_info& i );
 (1) (C++20 起)
nonexistent_local_time( const nonexistent_local_time& other ) noexcept;
 (2) (C++20 起)

构造异常对象。

1) what() 所返回的解释字符串等价于下列代码后 os.str() 所产生者：
std::ostringstream os;
os << tp << " is in a gap between\n"
   << std::chrono::local_seconds(i.first.end.time_since_epoch()) + i.first.offset
   << ' ' << i.first.abbrev << " and\n"
   << std::chrono::local_seconds(i.second.begin.time_since_epoch()) + i.second.offset
   << ' ' << i.second.abbrev
   << " which are both equivalent to\n"
   << i.first.end << " UTC";
若 i.result != std::chrono::local_info::nonexistent 则行为未定义。
2) 复制构造函数。若 *this 与 other 均拥有动态类型 std::chrono::nonexistent_local_time 则 std::strcmp (what(), other.what()) == 0 。

参数

tp | - | 试图转换的时间点
i | - | 描述转换尝试的结果的 std::chrono::local_info
other | - | 要复制的另一 nonexistent_local_time

异常

可能抛出 std::bad_alloc

注解

因为不容许复制派生自 std::exception 的标准库类抛出异常，此信息通常在内部存储为分离分配的引用计数字符串。

std::chrono::nonexistent_locale_time::operator=

nonexistent_locale_time& operator=( const nonexistent_locale_time& other ) noexcept; | (C++20 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::chrono::nonexistent_locale_time 则赋值后 std::strcmp (what(), other.what()) == 0 。

参数

other - 用以赋值的另一异常对象

返回值

*this

std::chrono::nonexistent_locale_time::what

virtual const char* what() const noexcept; | (C++20 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::runtime_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)


std::literals::chrono_literals::operator""d

< cpp‎ | chrono
定义于头文件 <chrono> |  |
constexpr std::chrono::day operator ""d(unsigned long long d) noexcept; | (1) | (C++20 起)

组成表示日历中月的日期的 std::chrono::day 字面量。

参数

d - 日期值

返回值

存储 d 的 std::chrono::day 。若 d > 255 ，则存储值未指定。

可能的实现

constexpr std::chrono::day operator ""d(unsigned long long d) noexcept
{
    return std::chrono::day(d);
}

注意

此运算符声明于命名空间 std::literals::chrono_literals ，其中 literals 与 chrono_literals 为内联命名空间。能通过 using namespace std::literals 、 using namespace std::chrono_literals 及 using namespace std::literals::chrono_literals 取得对此运算符的访问。

另外，在命名空间 std::chrono 中，标准库提供 using namespace literals::chrono_literals; 指令，故若程序员使用 using namespace std::chrono; 取得对 chrono 库中的类的访问，则对应的字面量运算符亦变为可见。

示例

#include <iostream>
#include <chrono>

int main()
{
    using namespace std::literals::chrono_literals;

    std::cout << static_cast<unsigned>(42d) << ' '
              << static_cast<unsigned>(256d) << ' ' // unspecified
              << static_cast<unsigned>(298d) << '\n'; // unspecified
}

可能的输出：

42 0 42

参阅

(构造函数)
 构造 day
(std::chrono::day 的公开成员函数)


std::literals::chrono_literals::operator""h

< cpp‎ | chrono
定义于头文件 <chrono>
constexpr chrono::hours operator "" h(unsigned long long hrs);
 (1) (C++14 起)
constexpr chrono::duration</*unspecified*/, std::ratio <3600,1>>
operator "" h(long double hrs);
 (2) (C++14 起)

组成表示小时的 std::chrono::duration 字面量。

1) 整数字面量，准确返回 std::chrono::hours (hrs)
2) 浮点字面量，返回等价于 std::chrono::hours 的浮点时期

参数

hrs - 小时数

返回值

std::chrono::duration 字面量。

可能的实现

constexpr std::chrono::hours operator ""h(unsigned long long h)
{
    return std::chrono::hours(h);
}
constexpr std::chrono::duration<long double, ratio<3600,1>> operator ""h(long double h)
{
    return std::chrono::duration<long double, std::ratio<3600,1>>(h);
}

注意

这些运算符声明于命名空间 std::literals::chrono_literals ，其中 literals 与 chrono_literals 为内联命名空间。能通过 using namespace std::literals 、 using namespace std::chrono_literals 及 using namespace std::literals::chrono_literals 取得对这些运算符的访问。

另外，在命名空间 std::chrono 中，标准库提供 using namespace literals::chrono_literals; 指令，故若程序员使用 using namespace std::chrono; 取得对 chrono 库中的类的访问，则对应的字面量运算符亦变为可见。

示例

#include <iostream>
#include <chrono>

int main()
{
    using namespace std::chrono_literals;
    auto day = 24h;
    auto halfhour = 0.5h;
    std::cout << "one day is " << day.count() << " hours\n"
              << "half an hour is " << halfhour.count() << " hours\n";
}

输出：

one day is 24 hours
half an hour is 0.5 hours

参阅

(构造函数)
 构造新 duration
(std::chrono::duration<Rep,Period> 的公开成员函数)


std::literals::chrono_literals::operator""min

< cpp‎ | chrono
定义于头文件 <chrono>
constexpr chrono::minutes operator "" min(unsigned long long mins);
 (1) (C++14 起)
constexpr chrono::duration</*unspecified*/, ratio<60,1>>
operator "" min(long double mins);
 (2) (C++14 起)

组成表示分的 std::chrono::duration 字面量。

1) 整数字面量，准确返回 std::chrono::minutes (mins) 。
2) 浮点字面量，返回等价于 std::chrono::minutes 的浮点时长。

参数

minutes - 分钟数

返回值

std::chrono::duration 字面量。

可能的实现

constexpr std::chrono::minutes operator ""min(unsigned long long m)
{
    return std::chrono::minutes(m);
}
constexpr std::chrono::duration<long double,
                                std::ratio<60,1>> operator ""min(long double m)
{
    return std::chrono::duration<long double, ratio<60,1>> (m);
}

注意

这些运算符声明于命名空间 std::literals::chrono_literals ，其中 literals 与 chrono_literals 为内联命名空间。能通过 using namespace std::literals 、 using namespace std::chrono_literals 及 using namespace std::literals::chrono_literals 取得对这些运算符的访问。

另外，在命名空间 std::chrono 中，标准库提供 using namespace literals::chrono_literals; 指令，故若程序员使用 using namespace std::chrono; 取得对 chrono 库中的类的访问，则对应的字面量运算符亦变为可见。

示例

#include <iostream>
#include <chrono>

int main()
{
    using namespace std::chrono_literals;
    auto lesson = 45min;
    auto halfmin = 0.5min;
    std::cout << "one lesson is " << lesson.count() << " minutes\n"
              << "half a minute is " << halfmin.count() << " minutes\n";
}

输出：

one lesson is 45 minutes
half a minute is 0.5 minutes

参阅

(构造函数)
 构造新 duration
(std::chrono::duration<Rep,Period> 的公开成员函数)


std::literals::chrono_literals::operator""ms

< cpp‎ | chrono
定义于头文件 <chrono>
constexpr std::chrono::milliseconds operator "" ms(unsigned long long ms);
 (1) (C++14 起)
constexpr std::chrono::duration </*unspecified*/,
std::milli > operator "" ms(long double ms);
 (2) (C++14 起)

组成表示毫秒的 std::chrono::duration 字面量。

1) 整数字面量，准确返回 std::chrono::milliseconds (ms) 。
2) 浮点字面量，返回等价于 std::chrono::milliseconds 的浮点时长。

参数

ms - 毫秒数

返回值

std::chrono::duration 字面量。

可能的实现

constexpr std::chrono::milliseconds operator ""ms(unsigned long long ms)
{
    return std::chrono::milliseconds(ms);
}
constexpr std::chrono::duration<long double, std::milli> operator ""ms(long double ms)
{
    return std::chrono::duration<long double, std::milli>(ms);
}

注意

这些运算符声明于命名空间 std::literals::chrono_literals ，其中 literals 与 chrono_literals 为内联命名空间。能通过 using namespace std::literals 、 using namespace std::chrono_literals 及 using namespace std::literals::chrono_literals 取得对这些运算符的访问。

另外，在命名空间 std::chrono 中，标准库提供 using namespace literals::chrono_literals; 指令，故若程序员使用 using namespace std::chrono; 取得对 chrono 库中的类的访问，则对应的字面量运算符亦变为可见。

示例

#include <iostream>
#include <chrono>

int main()
{
    using namespace std::chrono_literals;
    auto d1 = 250ms;
    std::chrono::milliseconds d2 = 1s;
    std::cout << "250ms = " << d1.count() << " milliseconds\n"
              << "1s = " << d2.count() << " milliseconds\n";
}

输出：

250ms = 250 milliseconds
1s = 1000 milliseconds

参阅

(构造函数)
 构造新 duration
(std::chrono::duration<Rep,Period> 的公开成员函数)


std::literals::chrono_literals::operator""ns

< cpp‎ | chrono
定义于头文件 <chrono>
constexpr std::chrono::nanoseconds operator "" ns(unsigned long long nsec);
 (1) (C++14 起)
constexpr std::chrono::duration </*unspecified*/,
std::nano > operator "" ns(long double nsec);
 (2) (C++14 起)

组成表示纳秒的 std::chrono::duration 字面量。

1) 整数字面量，准确返回 std::chrono::nanoseconds (nsec) 。
2) 浮点字面量，返回等价于 std::chrono::nanoseconds 的浮点时长。

参数

nsec - 纳秒数

返回值

std::chrono::duration 字面量。

可能的实现

constexpr std::chrono::nanoseconds operator ""ns(unsigned long long ns)
{
    return std::chrono::nanoseconds(ns);
}
constexpr std::chrono::duration<long double, std::nano> operator ""ns(long double ns)
{
    return std::chrono::duration<long double, std::nano>(ns);
}

注意

这些运算符声明于命名空间 std::literals::chrono_literals ，其中 literals 与 chrono_literals 为内联命名空间。能通过 using namespace std::literals 、 using namespace std::chrono_literals 及 using namespace std::literals::chrono_literals 取得对这些运算符的访问。

另外，在命名空间 std::chrono 中，标准库提供 using namespace literals::chrono_literals; 指令，故若程序员使用 using namespace std::chrono; 取得对 chrono 库中的类的访问，则对应的字面量运算符亦变为可见。

示例

#include <iostream>
#include <chrono>

int main()
{
    using namespace std::chrono_literals;
    auto d1 = 250ns;
    std::chrono::nanoseconds d2 = 1us;
    std::cout << "250ns = " << d1.count() << " nanoseconds\n"
              << "1us = " << d2.count() << " nanoseconds\n";
}

输出：

250ns = 250 nanoseconds
1us = 1000 nanoseconds

参阅

(构造函数)
 构造新 duration
(std::chrono::duration<Rep,Period> 的公开成员函数)


std::literals::chrono_literals::operator""s

< cpp‎ | chrono
定义于头文件 <chrono> |  |
constexpr chrono::seconds operator "" s(unsigned long long secs); | (1) | (C++14 起)
constexpr chrono::duration</*unspecified*/> operator "" s(long double secs); | (2) | (C++14 起)

组成表示秒的 std::chrono::duration 字面量。

1) 整数字面量，准确返回 std::chrono::seconds (secs) 。
2) 浮点字面量，返回等价于 std::chrono::seconds 的浮点时长。

参数

secs - 秒数

返回值

std::chrono::duration 字面量。

可能的实现

constexpr std::chrono::seconds operator ""s(unsigned long long s)
{
    return std::chrono::seconds(s);
}
constexpr std::chrono::duration<long double> operator ""s(long double s)
{
    return std::chrono::duration<long double>(s);
}

注意

这些运算符声明于命名空间 std::literals::chrono_literals ，其中 literals 与 chrono_literals 为内联命名空间。能通过 using namespace std::literals 、 using namespace std::chrono_literals 及 using namespace std::literals::chrono_literals 取得对这些运算符的访问。

另外，在命名空间 std::chrono 中，标准库提供 using namespace literals::chrono_literals; 指令，故若程序员使用 using namespace std::chrono; 取得对 chrono 库中的类的访问，则对应的字面量运算符亦变为可见。

std::string 亦定义 operator""s ，表示 std::string 类型字面量对象，但它是字符串字面量： 10s 是十秒，而 "10"s 是二字符 string 。

示例

#include <iostream>
#include <chrono>

int main()
{
    using namespace std::chrono_literals;
    auto halfmin = 30s;
    std::cout << "half a minute is " << halfmin.count() << " seconds\n"
              << "a minute and a half is " << (1min + 30s).count() << " seconds\n";
}

输出：

half a minute is 30 seconds
a minute and a half is 90 seconds

参阅

(构造函数)
 构造新 duration
(std::chrono::duration<Rep,Period> 的公开成员函数)


std::literals::chrono_literals::operator""us

< cpp‎ | chrono
定义于头文件 <chrono>
constexpr std::chrono::microseconds operator "" us(unsigned long long us);
 (1) (C++14 起)
constexpr std::chrono::duration </*unspecified*/,
std::micro > operator "" us(long double us);
 (2) (C++14 起)

组成表示微秒的 std::chrono::duration 。

1) 整数字面量，准确返回 std::chrono::microseconds (us) 。
2) 浮点字面量，返回等价于 std::chrono::microseconds 的浮点时长。

参数

us - 微秒数

返回值

std::chrono::duration 字面量。

可能的实现

constexpr std::chrono::microseconds operator ""us(unsigned long long us)
{
    return std::chrono::microseconds(us);
}
constexpr std::chrono::duration<long double, std::micro> operator ""us(long double us)
{
    return std::chrono::duration<long double, std::micro>(us);
}

注意

这些运算符声明于命名空间 std::literals::chrono_literals ，其中 literals 与 chrono_literals 为内联命名空间。能通过 using namespace std::literals 、 using namespace std::chrono_literals 及 using namespace std::literals::chrono_literals 取得对这些运算符的访问。

另外，在命名空间 std::chrono 中，标准库提供 using namespace literals::chrono_literals; 指令，故若程序员使用 using namespace std::chrono; 取得对 chrono 库中的类的访问，则对应的字面量运算符亦变为可见。

示例

#include <iostream>
#include <chrono>

int main()
{
    using namespace std::chrono_literals;
    auto d1 = 250us;
    std::chrono::microseconds d2 = 1ms;
    std::cout << "250us = " << d1.count() << " microseconds\n"
              << "1ms = " << d2.count() << " microseconds\n";
}

输出：

250us = 250 microseconds
1ms = 1000 microseconds

参阅

(构造函数)
 构造新 duration
(std::chrono::duration<Rep,Period> 的公开成员函数)


std::literals::chrono_literals::operator""y

< cpp‎ | chrono
定义于头文件 <chrono> |  |
constexpr std::chrono::year operator ""y(unsigned long long y) noexcept; | (1) | (C++20 起)

构成表示外推格里高利历中年份的 std::chrono::year 字面量。

参数

y - 年份值

返回值

从 int(y) 初始化的 std::chrono::year 。若转型结果不在 [-32767, 32767] 中，则存储值未指定。

可能的实现

constexpr std::chrono::year operator ""y(unsigned long long y) noexcept
{
    return std::chrono::year(static_cast<int>(y));
}

注解

此运算符声明于命名空间 std::literals::chrono_literals ，其中 literals 与 chrono_literals 为内联命名空间。能通过 using namespace std::literals 、 using namespace std::chrono_literals 及 using namespace std::literals::chrono_literals 取得对此运算符的访问。

另外，在命名空间 std::chrono 中，标准库提供 using namespace literals::chrono_literals; 指令，故若程序员使用 using namespace std::chrono; 取得对 chrono 库中的类的访问，则对应的字面量运算符亦变为可见。

示例

#include <iostream>
#include <chrono>

int main()
{
    using namespace std::literals;

    std::cout
        << int(2020y) << ' '
        << int(-220y) << ' '
        << int(3000y) << ' '
        << int(32768y) << ' '    // 未指定
        << int(65578y) << '\n';  // 未指定
}

可能的输出：

2020 -220 3000 -32768 42

参阅

(构造函数)
 构造 year
(std::chrono::year 的公开成员函数)


std::chrono::operator/ (日历)

< cpp‎ | chrono
定义于头文件 <chrono>
year_month
constexpr auto operator/(const std::chrono::year& y,

const std::chrono::month& m) noexcept

-> std::chrono::year_month;
 (1) (C++20 起)
constexpr auto operator/(const std::chrono::year& y, int m) noexcept
-> std::chrono::year_month;
 (2) (C++20 起)
month_day
constexpr auto operator/(const std::chrono::month& m,

const std::chrono::day& d) noexcept

-> std::chrono::month_day;
 (3) (C++20 起)
constexpr auto operator/(const std::chrono::month& m, int d) noexcept
-> std::chrono::month_day;
 (4) (C++20 起)
constexpr auto operator/(int m, const std::chrono::day& d) noexcept
-> std::chrono::month_day;
 (5) (C++20 起)
constexpr auto operator/(const std::chrono::day& d,

const std::chrono::month& m) noexcept

-> std::chrono::month_day;
 (6) (C++20 起)
constexpr auto operator/(const std::chrono::day& d, int m) noexcept
-> std::chrono::month_day;
 (7) (C++20 起)
month_day_last
constexpr auto operator/(const std::chrono::month& m,

std::chrono::last_spec) noexcept

-> std::chrono::month_day_last;
 (8) (C++20 起)
constexpr auto operator/(int m, std::chrono::last_spec) noexcept
-> std::chrono::month_day_last;
 (9) (C++20 起)
constexpr auto operator/(std::chrono::last_spec,

const std::chrono::month& m) noexcept

-> std::chrono::month_day_last;
 (10) (C++20 起)
constexpr auto operator/(std::chrono::last_spec, int m) noexcept
-> std::chrono::month_day_last;
 (11) (C++20 起)
month_weekday
constexpr auto operator/(const std::chrono::month& m,

const std::chrono::weekday_indexed& wdi) noexcept

-> std::chrono::month_weekday;
 (12) (C++20 起)
constexpr auto operator/(int m, const std::chrono::weekday_indexed& wdi) noexcept
-> std::chrono::month_weekday;
 (13) (C++20 起)
constexpr auto operator/(const std::chrono::weekday_indexed& wdi,

const std::chrono::month& m) noexcept

-> std::chrono::month_weekday;
 (14) (C++20 起)
constexpr auto operator/(const std::chrono::weekday_indexed& wdi, int m) noexcept
-> std::chrono::month_weekday;
 (15) (C++20 起)
month_weekday_last
constexpr auto operator/(const std::chrono::month& m,

const std::chrono::weekday_last& wdl) noexcept

-> std::chrono::month_weekday_last;
 (16) (C++20 起)
constexpr auto operator/(int m, const std::chrono::weekday_last& wdl) noexcept
-> std::chrono::month_weekday_last;
 (17) (C++20 起)
constexpr auto operator/(const std::chrono::weekday_last& wdl,

const std::chrono::month& m) noexcept

-> std::chrono::month_weekday_last;
 (18) (C++20 起)
constexpr auto operator/(const std::chrono::weekday_last& wdl, int m) noexcept
-> std::chrono::month_weekday_last;
 (19) (C++20 起)
year_month_day
constexpr auto operator/(const std::chrono::year_month& ym,

const std::chrono::day& d) noexcept

-> std::chrono::year_month_day;
 (20) (C++20 起)
constexpr auto operator/(const std::chrono::year_month& ym, int d) noexcept
-> std::chrono::year_month_day;
 (21) (C++20 起)
constexpr auto operator/(const std::chrono::year& y,

const std::chrono::month_day& md) noexcept

-> std::chrono::year_month_day;
 (22) (C++20 起)
constexpr auto operator/(int y, const std::chrono::month_day& md) noexcept
-> std::chrono::year_month_day;
 (23) (C++20 起)
constexpr auto operator/(const std::chrono::month_day& md,

const std::chrono::year& y) noexcept

-> std::chrono::year_month_day;
 (24) (C++20 起)
constexpr auto operator/(const std::chrono::month_day& md, int y) noexcept
-> std::chrono::year_month_day;
 (25) (C++20 起)
year_month_day_last
constexpr auto operator/(const std::chrono::year_month& ym,

std::chrono::last_spec) noexcept

-> std::chrono::year_month_day_last;
 (26) (C++20 起)
constexpr auto operator/(const std::chrono::year& y,

const std::chrono::month_day_last& mdl) noexcept

-> std::chrono::year_month_day_last;
 (27) (C++20 起)
constexpr auto operator/(int y, const std::chrono::month_day_last& mdl) noexcept
-> std::chrono::year_month_day_last;
 (28) (C++20 起)
constexpr auto operator/(const std::chrono::month_day_last& mdl,

const std::chrono::year& y) noexcept

-> std::chrono::year_month_day_last;
 (29) (C++20 起)
constexpr auto operator/(const std::chrono::month_day_last& mdl, int y) noexcept
-> std::chrono::year_month_day_last;
 (30) (C++20 起)
year_month_weekday
constexpr auto operator/(const std::chrono::year_month& ym,

const std::chrono::weekday_indexed& wdi) noexcept

-> std::chrono::year_month_weekday;
 (31) (C++20 起)
constexpr auto operator/(const std::chrono::year& y,

const std::chrono::month_weekday& mwd) noexcept

-> std::chrono::year_month_weekday;
 (32) (C++20 起)
constexpr auto operator/(int y, const std::chrono::month_weekday& mwd) noexcept
-> std::chrono::year_month_weekday;
 (33) (C++20 起)
constexpr auto operator/(const std::chrono::month_weekday& mwd,

const std::chrono::year& y) noexcept

-> std::chrono::year_month_weekday;
 (34) (C++20 起)
constexpr auto operator/(const std::chrono::month_weekday& mwd, int y) noexcept
-> std::chrono::year_month_weekday;
 (35) (C++20 起)
year_month_weekday_last
constexpr auto operator/(const std::chrono::year_month& ym,

const std::chrono::weekday_last& wdl) noexcept

-> std::chrono::year_month_weekday_last;
 (36) (C++20 起)
constexpr auto operator/(const std::chrono::year& y,

const std::chrono::month_weekday_last& mwdl) noexcept

-> std::chrono::year_month_weekday_last;
 (37) (C++20 起)
constexpr auto operator/(int y, const std::chrono::month_weekday_last& mwdl) noexcept
-> std::chrono::year_month_weekday_last;
 (38) (C++20 起)
constexpr auto operator/(const std::chrono::month_weekday_last& mwdl,

const std::chrono::year& y) noexcept

-> std::chrono::year_month_weekday_last;
 (39) (C++20 起)
constexpr auto operator/(const std::chrono::month_weekday_last& mwdl, int y) noexcept
-> std::chrono::year_month_weekday_last;
 (40) (C++20 起)

这些 operator/ 为创建格里高利历日期提供约定语法。

对于创建完整日期，任何下列三种顺序都可接受：

  • year/month/day
  • month/day/year
  • day/month/year

每种情况中，能以下列之一替换 day ：

  • std::chrono::last ，对于月的最后一日；
  • weekday[i] ，对于月的第 i 个 weekday ；
  • weekday[std::chrono::last] ，对于该月的最后一个 weekday 。

若单纯的整数的含义相对于其他运算数的类型无歧义，则可接受它：允许 2005y/4/5 ，但不允许 5/April/2005 。

能够不以三种顺序之一应用第二个 operator/ 创建部分日期类型（ year_month 、 month_day 等）。

返回值

1) std::chrono::year_month(y, m)
2) std::chrono::year_month(y, std::chrono::month(m))
3,6) std::chrono::month_day(m, d)
4) std::chrono::month_day(m, std::chrono::day(d))
5,7) std::chrono::month_day(std::chrono::month(m), d)
8,10) std::chrono::month_day_last(m)
9,11) std::chrono::month_day_last(std::chrono::month(m))
12,14) std::chrono::month_weekday(m, wdi)
13,15) std::chrono::month_weekday(std::chrono::month(m), wdi)
16,18) std::chrono::month_weekday_last(m, wdl)
17,19) std::chrono::month_weekday_last(std::chrono::month(m), wdl)
20) std::chrono::year_month_day(ym.year(), ym.month(), d)
21) std::chrono::year_month_day(ym.year(), ym.month(), std::chrono::day(d))
22,24) std::chrono::year_month_day(y, md.month(), md.day())
23,25) std::chrono::year_month_day(std::chrono::year(y), md.month(), md.day())
26) std::chrono::year_month_day_last(ym.year(), std::chrono::month_day_last(ym.month()))
27,29) std::chrono::year_month_day_last(y, mdl)
28,30) std::chrono::year_month_day_last(std::chrono::year(y), mdl)
31) std::chrono::year_month_weekday(ym.year(), ym.month(), wdi)
32,34) std::chrono::year_month_weekday(y, mwd.month(), mwd.weekday_indexed())
33,35) std::chrono::year_month_weekday(std::chrono::year(y), mwd.month(), mwd.weekday_indexed())
36) std::chrono::year_month_weekday_last(ym.year(), ym.month(), wdl)
37,39) std::chrono::year_month_weekday_last(y, mwdl.month(), mwdl.weekday_last())
38,40) std::chrono::year_month_weekday_last(std::chrono::year(y), mwdl.month(), mwdl.weekday_last())

示例

#include <iostream>
#include <chrono>
using namespace std::chrono;

int main()
{
    std::cout << std::boolalpha;

    // 标准提供 2021y 作为 std::chrono::year(2021) 的备选
    // 标准提供 15d 作为 std::chrono::day(15) 的备选

    constexpr auto ym {year(2021)/8};
    std::cout << (ym == year_month(year(2021), August)) << ' ';

    constexpr auto md {9/day(15)};
    std::cout << (md == month_day(September, day(15))) << ' ';

    constexpr auto mdl {October/last};
    std::cout << (mdl == month_day_last(month(10))) << ' ';

    constexpr auto mw {11/Monday[3]};
    std::cout << (mw == month_weekday(November, Monday[3])) << ' ';

    constexpr auto mwdl {December/Sunday[last]};
    std::cout << (mwdl == month_weekday_last(month(12), weekday_last(Sunday))) << ' ';

    constexpr auto ymd {year(2021)/January/day(23)};
    std::cout << (ymd == year_month_day(2021y, month(January), 23d)) << '\n';
}

输出：

true true true true true true


std::chrono::parse

< cpp‎ | chrono
定义于头文件 <chrono>
template< class CharT, class Parsable >
/* unspecified */ parse( const CharT* fmt, Parsable& tp );
 (1) (C++20 起)
template< class CharT, class Traits, class Alloc, class Parsable >

/* unspecified */ parse( const std::basic_string <CharT, Traits, Alloc>& fmt,

Parsable& tp );
 (2) (C++20 起)
template< class CharT, class Traits, class Alloc, class Parsable >

/* unspecified */ parse( const CharT* fmt, Parsable& tp,

std::basic_string <CharT, Traits, Alloc>& abbrev );
 (3) (C++20 起)
template< class CharT, class Traits, class Alloc, class Parsable >

/* unspecified */ parse( const std::basic_string <CharT, Traits, Alloc>& fmt,
Parsable& tp,

std::basic_string <CharT, Traits, Alloc>& abbrev );
 (4) (C++20 起)
template< class CharT, class Parsable >

/* unspecified */ parse( const CharT* fmt, Parsable& tp,

std::chrono::minutes & offset );
 (5) (C++20 起)
template< class CharT, class Traits, class Alloc, class Parsable >

/* unspecified */ parse( const std::basic_string <CharT, Traits, Alloc>& fmt,

Parsable& tp, std::chrono::minutes & offset );
 (6) (C++20 起)
template< class CharT, class Traits, class Alloc, class Parsable >

/* unspecified */ parse( const CharT* fmt, Parsable& tp,
std::basic_string <CharT, Traits, Alloc>& abbrev,

std::chrono::minutes & offset );
 (7) (C++20 起)
template< class CharT, class Traits, class Alloc, class Parsable >

/* unspecified */ parse( const std::basic_string <CharT, Traits, Alloc>& fmt,
Parsable& tp,
std::basic_string <CharT, Traits, Alloc>& abbrev,

std::chrono::minutes & offset );
 (8) (C++20 起)

返回未指定类型的对象 manip ，使得给定 std::basic_istream <CharT, Traits> 对象 is ，表达式 is >> manip 以下列方式调用 from_stream （无限定，以启用实参依赖查找）：

1) from_stream(is, fmt, tp)
2) from_stream(is, fmt.c_str(), tp)
3) from_stream(is, fmt, tp, std::addressof (abbrev))
4) from_stream(is, fmt.c_str(), tp, std::addressof (abbrev))
5) from_stream(is, fmt, tp,
static_cast< std::basic_string <CharT, Traits, Alloc>*>(nullptr), &offset)
6) from_stream(is, fmt.c_str(), tp,
static_cast< std::basic_string <CharT, Traits, Alloc>*>(nullptr), &offset)
7) from_stream(is, fmt, tp, std::addressof (abbrev), &offset)
8) from_stream(is, fmt.c_str(), tp, std::addressof (abbrev), &offset) 。

表达式 is >> manip 是 std::basic_istream <CharT, Traits> 类型左值，其值为 is 。

这些重载仅若对应的 from_stream 表达式为良构才参与重载决议。

推荐实现令使用到格式字符串的悬垂引用困难，例如通过令返回类型不可移动并阻止 operator>> 接受返回类型的左值。

参数

fmt | - | 格式字符串（见后述）
tp | - | 保有分析结果的对象
abbrev | - | 保有对应 %Z 说明符的时区缩写或名称的字符串
offset | - | 表示对应 %z 说明符的距 UTC 偏移的时长

格式字符串

格式字符串由零或更多个转换说明符和通常字符组成。每个通常字符，除了空白字符和空终止字符，都匹配一个来自输入流的等同字符，或若流上的下个字符不比较相等则导致函数失败。

每个空白字符匹配输入流中的零或更多个空白字符。

每个不修饰的转换说明符以 % 字符后随一个确定说明符行为的字符开始。某些转换说明符拥有在 % 字符后插入修饰字符 E 或 O 的修饰形式。某些转换说明符拥有在 % 字符后插入作为十进制整数（下面显示为 N ）的宽度参数的修饰形式。每个转换说明符导致匹配的字符被按照下表转译成时间和日期类型的部分。

格式字符串中，以 % 开始但不匹配下列转换说明符之一的字符序列被转译成通常字符。

若 from_stream 无法分析格式字符串所指定的每项内容，或若分析出的信息不足以指定完整结果，或若分析透露矛盾的信息，则调用 is.setstate( std::ios_base::failbit ) 。

下列转换说明符可用：

转换
说明符 		解释
%% 匹配字面的 % 字符。
%n | 匹配一个空白字符。
%t | 匹配零或一个空白字符。
年
%C
%NC
%EC
%OC 		将世纪分析成十进制数。宽度 N 指定要读取的最大字符数。默认宽度为 2 。容许但不要求前导零。

修饰的命令 %EC 和 %OC 转译本地环境的替用世纪表示。
%y
%Ny
%Ey
%Oy 		分析年的低二位十进制位。若不另外指定世纪（例如用 %C ），则预设范围 [69, 99] 中的值指代 1969 至 1999 年，
而预设范围 [00, 68] 中的值指代 2000 至 2068 年。宽度 N 指定要读取的最大字符数。默认宽度为 2 。容许但不要求前导零。

修饰的命令 %Ey 和 %Oy 转译本地环境的替用表示。
%Y
%NY
%EY 		将年分析成十进制数。宽度 N 指定要读取的最大字符数。默认宽度为 4 。容许但不要求前导零。

修饰的命令 %EY 转译本地环境的替用表示。
月
%b
%B
%h 		分析本地环境的完整或缩写的无关大小写的月名。
%m
%Nm
%Om 		将月份分析成十进制数（一月为 1 ）。宽度 N 指定要读取的最大字符数。默认宽度为 2 。容许但不要求前导零。

修饰的命令 %Om 转译本地环境的替用表示。
日
%d
%Nd
%Od
%e
%Ne
%Oe 		将月之日分析成十进制数。宽度 N 指定要读取的最大字符数。默认宽度为 2 。容许但不要求前导零。

修改的命令 %Od 和 %Oe 转译本地环境的替用表示。
星期之日
%a
%A 		分析本地环境的完整或缩写的无关大小写的星期之日名。
%u
%Nu
%Ou 		分析 ISO 星期之日为十进制数 (1-7) ，其中星期一为 1 。宽度 N 指定要读取的最大字符数。默认宽度为 1 。容许但不要求前导零。

修饰的命令 %Ou 转译本地环境的替用表示。
%w
%Nw
%Ow 		分析星期之日为十进制数 (0-6) ，其中星期日为 0 。宽度 N 指定要读取的最大字符数。默认宽度为 1 。容许但不要求前导零。

修饰的命令 %Ow 转译本地环境的替用表示。
基于 ISO 8601 星期的年

ISO 8601 中，星期始于星期一，而每年的首周必须满足下列要求：

  • 包含 1 月 4 日
  • 包含该年的首个星期四
%g
%Ng 		分析基于 ISO 8601 的年的低二位十进制数。宽度 N 指定要读取的最大字符数。默认宽度为 2 。容许但不要求前导零。
%G
%NG 		将基于 ISO 8601 的年分析成十进制数。宽度 N 指定要读取的最大字符数。默认宽度为 4 。容许但不要求前导零。
%V
%NV 		将基于 ISO 8601 的年之星期分析成十进制数。宽度 N 指定要读取的最大字符数。默认宽度为 2 。容许但不要求前导零。
年之星期/日
%j
%Nj 		分析年之日为十进制数（ 1 月 1 日为 1 ）。宽度 N 指定要读取的最大字符数。默认宽度为 3 。容许但不要求前导零。
%U
%NU 		分析年之星期为十进制数。该年的首个星期日是星期 01 的首日。同年中先于该天的日期属于星期 00 。
宽度 N 指定要读取的最大字符数。默认宽度为 2 。容许但不要求前导零。
%W
%NW 		分析年之星期为十进制数。该年的首个星期一是星期 01 的首日。同年中先于该天的日期属于星期 00 。
宽度 N 指定要读取的最大字符数。默认宽度为 2 。容许但不要求前导零。
日期
%D | 等价于 "%m/%d/%y" 。
%F
%NF 		等价于 "%Y-%m-%d" 。若指定宽度，则它只应用于 %Y 。
%x
%Ex 		分析本地环境的日期表示。

修饰的命令 %Ex 转译本地环境的替用日期表示。
当天时刻
%H
%NH
%OH 		将时（ 24 小时时钟）分析成十进制数。宽度 N 指定要读取的最大字符数。默认宽度为 2 。容许但不要求前导零。

修饰的命令 %OH 转译本地环境的替用表示。
%I
%NI 		将时（ 12 小时时钟）分析成十进制数。宽度 N 指定要读取的最大字符数。默认宽度为 2 。容许但不要求前导零。
%M
%NM
%OM 		将分分析成十进制数。宽度 N 指定要读取的最大字符数。默认宽度为 2 。容许但不要求前导零。

修饰的命令 %OM 转译本地环境的替用表示。
%S
%NS
%OS 		将秒分析成十进制数。宽度 N 指定要读取的最大字符数。默认宽度为 2 。容许但不要求前导零。

修饰的命令 %OS 转译本地环境的替用表示。
%p | 分析与 12 小时时钟关联的 AM/PM 记法的本地环境等价版本。
%R | 等价于 "%H:%M" 。
%T | 等价于 "%H:%M:%S" 。
%r | 分析本地环境的 12 小时时钟时刻。
%X
%EX 		分析本地环境的时刻表示。

修饰的命令 %EX 转译本地环境的替用时间表示。
杂项
%c
%Ec 		分析本地环境的日期和时间表示。

修饰的命令 %Ec 转译本地环境的替用日期和时间表示。
%z
%Ez
%Oz 		以格式 [+|-]hh[mm] 分析距 UTC 的偏移。例如 -0430 指代落后 UTC 4 小时 30 分，而 04 指代领先 UTC 4 小时。

修饰的命令 %Ez 和 %Oz 分析格式 [+|-]h[h][:mm] （即要求时和分之间有 : ，并令时的前导零可选）。
%Z | 分析时区缩写或名称，取仅含字符 A 到 Z 、 a 到 z 、 0 到 9 、 - 、 + 、 _ 和 / 的最长字符序列。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3554 | C++20 | 缺少接受简单的空终止字符类型序列的重载 | 已添加

参阅

from_stream(std::chrono::sys_time) (C++20) | 按照给定的格式从流分析 sys_time (函数模板)
from_stream(std::chrono::utc_time) (C++20) | 按照给定的格式从流分析 utc_time (函数模板)
from_stream(std::chrono::tai_time) (C++20) | 按照给定的格式从流分析 tai_time (函数模板)
from_stream(std::chrono::gps_time) (C++20) | 按照给定的格式从流分析 gps_time (函数模板)
from_stream(std::chrono::file_time) (C++20) | 按照给定的格式从流分析 file_time (函数模板)
from_stream(std::chrono::local_time) (C++20) | 按照给定的格式从流分析 local_time (函数模板)
from_stream (C++20) | 按照提供的格式从流分析 year (函数模板)
from_stream (C++20) | 按照提供的格式从流分析 month (函数模板)
from_stream (C++20) | 按照提供的格式从流分析 day (函数模板)
from_stream (C++20) | 按照提供的格式从流分析 weekday (函数模板)
from_stream (C++20) | 按照提供的格式从流分析 month_day (函数模板)
from_stream (C++20) | 按照提供的格式从流分析 year_month (函数模板)
from_stream (C++20) | 按照给定的格式从流分析 year_month_day (函数模板)


std::chrono::steady_clock

< cpp‎ | chrono
定义于头文件 <chrono> |
class steady_clock; | (C++11 起)

类 std::chrono::steady_clock 表示单调时钟。此时钟的时间点无法减少，因为物理时间向前移动。此时钟与壁钟时间无关（例如，它能是上次重启开始的时间），且最适于度量间隔。

std::chrono::steady_clock 满足平凡时钟 (TrivialClock) 的要求。

成员类型

成员类型 | 定义
rep | 表示时钟时长中计次数的算术类型
period | 表示时钟计次周期的 std::ratio 类型，单位为秒
duration | std::chrono::duration <rep, period>
time_point | std::chrono::time_point <std::chrono::steady_clock>

成员常量

constexpr bool is_steady
[静态]
 稳定时钟标志，始终为 true
(公开静态成员常量)

成员函数

now
[静态]
 返回表示当前时钟值的 time_point
(公开静态成员函数)

参阅

system_clock (C++11) | 来自系统范围实时时钟的壁钟时间 (类)
high_resolution_clock (C++11) | 拥有最短可用计次周期的时钟 (类)


std::chrono::steady_clock::now

< cpp‎ | chrono‎ | steady clock

static std::chrono::time_point < std::chrono::steady_clock > now() noexcept; | (C++11 起)

返回表示当前时间的时间点。

参数

（无）

返回值

表示当前时间的时间点。

示例

#include <iostream>
#include <vector>
#include <numeric>
#include <chrono>

volatile int sink;
int main()
{
    for (auto size = 1ull; size < 1000000000ull; size *= 100) {
        // 记录开始时间
        auto start = std::chrono::steady_clock::now();
        // 做一些工作
        std::vector<int> v(size, 42);
        sink = std::accumulate(v.begin(), v.end(), 0u); // 确保其副效应
        // 记录结束时间
        auto end = std::chrono::steady_clock::now();
        std::chrono::duration<double> diff = end-start;
        std::cout << "Time to fill and iterate a vector of "
                  << size << " ints : " << diff.count() << " s\n";
    }
}

可能的输出：

Time to fill and iterate a vector of 1 ints : 2.43e-07 s
Time to fill and iterate a vector of 100 ints : 4.1e-07 s
Time to fill and iterate a vector of 10000 ints : 2.519e-05 s
Time to fill and iterate a vector of 1000000 ints : 0.00207669 s
Time to fill and iterate a vector of 100000000 ints : 0.423087 s


std::chrono::sys_info

< cpp‎ | chrono
定义于头文件 <chrono> |
struct sys_info; | (C++20 起)

类 sys_info 描述与在特定时间点（表示为 std::chrono::sys_time 或 std::chrono::local_time ）关联的时区信息。这是低层数据结构，通常不为用户代码所用。

成员对象

成员对象 | 类型
begin, end | std::chrono::sys_seconds
offset | std::chrono::seconds
save | std::chrono::minutes
abbrev | std::string

begin 和 end 数据成员指示范围 [begin, end) ——其中 offset 和 abbrev 对与此 sys_info 关联的时区有效。

offset 和 abbrev 数据成员分别指示 UTC 偏移和时区缩写，对于关联的时区和 std::chrono::time_point 有效。注意时区缩写不是独有的。

save 数据成员，若非零则指示在指定时间点时区处于夏时令。该情况下， offset - save 是假设无夏时令则，此时区会使用的偏移的建议。然而此信息不可靠：确认实际偏移的仅有方式是确实无夏时令（即返回 sys_info 使得 save == 0min ）。

非成员函数

operator<<
(C++20)
 输出 sys_info 到流中
(函数模板)

辅助类

std::formatter<std::chrono::sys_info>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 sys_info
(类模板特化)


std::chrono::operator<< (std::chrono::sys_info)

< cpp‎ | chrono‎ | sys info
定义于头文件 <chrono>
template<class CharT, class Traits>

std::basic_ostream <CharT, Traits>& operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::sys_info& r);
 (C++20 起)

插入 r 的文本表示到 os 中。准确格式未指定。

返回值

os 。


std::chrono::system_clock

< cpp‎ | chrono
定义于头文件 <chrono> |
class system_clock; | (C++11 起)

类 std::chrono::system_clock 表示系统范围的实时壁钟。

它可以不单调：大多数系统上，系统时间可以在任何时候被调节。它是唯一有能力映射其时间点到 C 风格时间的 C++ 时钟。

std::chrono::system_clock 满足平凡时钟 (TrivialClock) 的要求。

不指定 system_clock 的纪元，但多数实现使用 Unix 时间（即从协调世界时 (UTC) 1970 年 1 月 1 日星期四 00:00:00 开始的时间，不计闰秒）。 | (C++20 前)
system_clock 度量 Unix 时间（即从协调世界时 (UTC) 1970 年 1 月 1 日星期四 00:00:00 开始的时间，不计闰秒）。 | (C++20 起)

时间点族

定义于命名空间 std::chrono |
template<class Duration> using sys_time = std::chrono::time_point <std::chrono::system_clock, Duration>; | (C++20 起)
using sys_seconds = sys_time< std::chrono::seconds >; | (C++20 起)
using sys_days = sys_time<std::chrono::days>; | (C++20 起)
operator<<(std::chrono::sys_time) (C++20) | 进行 sys_time 上的流输出 (函数模板)
from_stream(std::chrono::sys_time) (C++20) | 按照给定的格式从流分析 sys_time (函数模板)
std::formatter<std::chrono::sys_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 sys_time (类模板特化)

成员类型

成员类型 | 定义
rep | 表示时钟时长中计次数的有符号算术类型
period | 表示时钟计次周期的 std::ratio 类型，单位为秒
duration | std::chrono::duration <rep, period> ，足以表示负时长
time_point | std::chrono::time_point <std::chrono::system_clock>

成员常量

constexpr bool is_steady
[静态]
 若时间间隔计次始终为常数，即纵使在调整了外部时钟的情况下，调用 now() 的返回值亦单调递增，则为 true ；否则为 false
(公开静态成员常量)

成员函数

now [静态] | 返回表示时间中当前点的 std::chrono::time_point (公开静态成员函数)
to_time_t [静态] | 转换系统时钟时间点为 std::time_t (公开静态成员函数)
from_time_t [静态] | 转换 std::time_t 到系统时钟时间点 (公开静态成员函数)

注解

system_clock 的时间值能由操作系统在内部调整到任何时间，例如由于 NTP 同步或用户更改系统的时钟。然而夏令时和时区更改不影响它，因为它基于 UTC 时区。

参阅

steady_clock (C++11) | 决不会调整的单调时钟 (类)
high_resolution_clock (C++11) | 拥有可用的最短嘀嗒周期的时钟 (类)


std::chrono::system_clock::from_time_t

< cpp‎ | chrono‎ | system clock
static std::chrono::system_clock::time_point from_time_t( std::time_t t ) noexcept; | (C++11 起)

用二个类型间的较低精度，转换 t 为时间点类型。

若 time_point 拥有较低精度，则舍入还是截断值是实现定义的。

参数

t - 要转换的 std::time_t 值

返回值

表示 t 的 std::chrono::system_clock::time_point 类型值。

参阅

to_time_t
[静态]
 转换系统时钟时间点为 std::time_t
(公开静态成员函数)


std::chrono::system_clock::now

< cpp‎ | chrono‎ | system clock

static std::chrono::time_point < std::chrono::system_clock > now() noexcept; | (C++11 起)

返回表示当前时间的时间点。

参数

（无）

返回值

表示当前时间的时间点。

示例

#include <iostream>
#include <vector>
#include <numeric>
#include <chrono>

volatile int sink;
int main()
{
    for (auto size = 1ull; size < 1000000000ull; size *= 100) {
        // 记录开始时间
        auto start = std::chrono::system_clock::now();
        // 做一些工作
        std::vector<int> v(size, 42);
        sink = std::accumulate(v.begin(), v.end(), 0u); // 确保其副效应
        // 记录结束时间
        auto end = std::chrono::system_clock::now();
        std::chrono::duration<double> diff = end-start;
        std::cout << "Time to fill and iterate a vector of "
                  << size << " ints : " << diff.count() << " s\n";
    }
}

可能的输出：

Time to fill and iterate a vector of 1 ints : 2.43e-07 s
Time to fill and iterate a vector of 100 ints : 4.1e-07 s
Time to fill and iterate a vector of 10000 ints : 2.519e-05 s
Time to fill and iterate a vector of 1000000 ints : 0.00207669 s
Time to fill and iterate a vector of 100000000 ints : 0.423087 s


std::chrono::operator<<(std::chrono::sys_time)

< cpp‎ | chrono‎ | system clock
定义于头文件 <chrono>
template <class CharT, class Traits, class Duration>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::sys_time<Duration>& tp);
 (1) (C++20 起)
template <class CharT, class Traits, class Duration>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::sys_days& tp);
 (2) (C++20 起)

输出 tp 到流 os 中。

1) 等价于：
return os << std::format(os.getloc(), STATICALLY-WIDEN<CharT>("{:L%F %T}"), tp);

其中 STATICALLY_WIDEN<CharT>("{:L%F %T}") 若 CharT 为 char 则为 "{:L%F %T}" ，而若 CharT 为 wchar_t 则为 L"{:L%F %T}" 。

此重载仅若 std::chrono::treat_as_floating_point_v<typename Duration::rep> 为 false 且 Duration(1) < std::chrono::days(1) 才参与重载决议。
2) 等价于 os << std::chrono::year_month_day(tp);

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

std::formatter<std::chrono::sys_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 sys_time (类模板特化)
format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
operator<< (C++20) | 输出 year_month_day 到流中 (函数模板)


std::chrono::system_clock::to_time_t

< cpp‎ | chrono‎ | system clock
static std::time_t to_time_t( const time_point& t ) noexcept; | (C++11 起)

转换 t 为 std::time_t 类型。

若 std::time_t 拥有较低精度，则是舍入还是截断值是实现定义的。

参数

t - 要转换的系统时钟时间点

返回值

表示 t 的 std::time_t 值。

参阅

from_time_t
[静态]
 转换 std::time_t 到系统时钟时间点
(公开静态成员函数)


std::chrono::tai_clock

< cpp‎ | chrono
定义于头文件 <chrono> |
class tai_clock; | (C++20 起)

时钟 std::chrono::tai_clock 是表示国际原子时 (International Atomic Time, TAI) 概念的时钟 (Clock) 。它度量从 1958 年 1 月 1 日 00:00:00 开始的时间，并且在当天提前 UTC 10 秒（即其纪元 1958-01-01 00:00:00 TAI 是 1957-12-31 23:59:50 UTC ）。

不插入闰秒到 TAI 中。从而每次插入一闰秒到 UTC 中， UTC 就多落后 TAI 一秒。迄至 2017 年 12 月， UTC 比 TAI 落后 37 秒，反映了 10 秒的初始差距和 1958 到 2017 年间插入的 27 闰秒。从而 2018-01-01 00:00:00 UTC 等价于 2018-01-01 00:00:37 TAI 。

tai_clock 满足时钟 (Clock) 要求。它不满足平凡时钟 (TrivialClock) 要求，除非实现能保证 now() 不抛异常。

时间点族

定义于命名空间 std::chrono |
template<class Duration> using tai_time = std::chrono::time_point <std::chrono::tai_clock, Duration>; | (C++20 起)
using tai_seconds = tai_time< std::chrono::seconds >; | (C++20 起)
operator<<(std::chrono::tai_time) (C++20) | 进行 tai_time 上的流输出 (函数模板)
from_stream(std::chrono::tai_time) (C++20) | 按照给定的格式从流分析 tai_time (函数模板)
std::formatter<std::chrono::tai_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 tai_time (类模板特化)

成员类型

成员类型 | 定义
rep | 表示时钟时长中计次数的有符号算术类型
period | 表示时钟计次周期的 std::ratio 类型，单位为秒
duration | std::chrono::duration <rep, period> ，足以表示负时长
time_point | std::chrono::time_point <std::chrono::tai_clock>

成员常量

constexpr bool is_steady
[静态]
 若时间间隔计次始终为常数，即纵使在调整了外部时钟的情况下，调用 now() 的返回值亦单调递增，则为 true ；否则为 false
(公开静态成员常量)

成员函数

now [静态] | 返回表示当前时间点的 std::chrono::time_point (公开静态成员函数)
to_utc [静态] | 转换 tai_time 为 utc_time (公开静态成员函数)
from_utc [静态] | 从 utc_time 转换到 tai_time (公开静态成员函数)


std::chrono::tai_clock::from_utc

< cpp‎ | chrono‎ | tai clock
template <class Duration>

static std::chrono::tai_time< std::common_type_t <Duration, std::chrono::seconds >>

from_utc(const std::chrono::utc_time<Duration>&) noexcept;
 (C++20 起)

转换 utc_time t 为表示相同时间点的 tai_time 。

返回值

与 t 表示相同时间点的 std::chrono::tai_time ，如同通过从 t.time_since_epoch() 构造返回类型的值，并加上 378691210s 一般计算结果。（ 378691210 是二个时钟纪元 1958-01-01 00:00:00 TAI 和 1970-01-01 00:00:00 UTC 之间的秒数。）

参阅

to_utc [静态] | 转换 tai_time 为 utc_time (公开静态成员函数)
clock_cast (C++20) | 转换一个时钟的时间点为另一个 (函数模板)


std::chrono::tai_clock::now

< cpp‎ | chrono‎ | tai clock

static std::chrono::time_point <std::chrono::tai_clock> now(); | (C++20 起)

返回表示当前时间的时间点。 如同以 std::chrono::tai_clock::from_utc(std::chrono::utc_clock::now()) 计算结果。实现可以用更精确的 TAI 时间值。

参数

（无）

返回值

表示当前时间的时间点。

示例

#include <iostream>
#include <vector>
#include <numeric>
#include <chrono>

volatile int sink;
int main()
{
    for (auto size = 1ull; size < 1000000000ull; size *= 100) {
        // 记录开始时间
        auto start = std::chrono::tai_clock::now();
        // 做一些工作
        std::vector<int> v(size, 42);
        sink = std::accumulate(v.begin(), v.end(), 0u); // 确保其副效应
        // 记录结束时间
        auto end = std::chrono::tai_clock::now();
        std::chrono::duration<double> diff = end-start;
        std::cout << "Time to fill and iterate a vector of "
                  << size << " ints : " << diff.count() << " s\n";
    }
}

可能的输出：

Time to fill and iterate a vector of 1 ints : 2.43e-07 s
Time to fill and iterate a vector of 100 ints : 4.1e-07 s
Time to fill and iterate a vector of 10000 ints : 2.519e-05 s
Time to fill and iterate a vector of 1000000 ints : 0.00207669 s
Time to fill and iterate a vector of 100000000 ints : 0.423087 s


std::chrono::operator<<(std::chrono::tai_time)

< cpp‎ | chrono‎ | tai clock

定义于头文件 <chrono>
template <class CharT, class Traits, class Duration>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::tai_time<Duration>& tp);
 (C++20 起)

输出 tp 到流 os 中，如同用 os << std::format(STATICALLY_WIDEN<CharT>("{:L%F %T}"), tp) ，其中 STATICALLY_WIDEN<CharT>("{:L%F %T}") 若 CharT 为 char 则为 "{:L%F %T}" ，而若 CharT 为 wchar_t 则为 L"{:L%F %T}" 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

std::formatter<std::chrono::tai_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 tai_time (类模板特化)
format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)


std::chrono::tai_clock::to_utc

< cpp‎ | chrono‎ | tai clock
template <class Duration>

static std::chrono::utc_time< std::common_type_t <Duration, std::chrono::seconds >>

to_utc(const std::chrono::tai_time<Duration>& t) noexcept;
 (C++20 起)

转换 tai_time t 为表示相同时间点的 utc_time 。

返回值

与 t 表示相同时间点的 std::chrono::utc_time ，如同通过从 t.time_since_epoch() 构造返回类型的值并减去 378691210s 一般计算。（ 378691210 是二个时钟纪元 1958-01-01 00:00:00 TAI 和 1970-01-01 00:00:00 UTC 之间的秒数。）

参阅

from_utc [静态] | 从 utc_time 转换到 tai_time (公开静态成员函数)
clock_cast (C++20) | 转换一个时钟的时间点为另一个 (函数模板)


std::chrono::time_point

< cpp‎ | chrono
定义于头文件 <chrono> |
template< class Clock, class Duration = typename Clock::duration > class time_point; | (C++11 起)

类模板 std::chrono::time_point 表示时间中的一个点。它被实现成如同存储一个 Duration 类型的自 Clock 的纪元起始开始的时间间隔的值。

Clock 必须满足时钟 (Clock) 的要求或为 std::chrono::local_t (C++20 起)。

 (C++23 前)

成员类型

成员类型 | 定义
clock | Clock ，此时间点在此时钟上计量
duration | Duration ，用于计量从纪元起时间的 std::chrono::duration 类型
rep | Rep ，表示时期的计次数的算术类型
period | Period ，表示时期周期的 std::ratio 类型

成员函数

(构造函数) | 构造新的 time_point (公开成员函数)
time_since_epoch | 返回表示为从其时钟起点开始的时间点 (公开成员函数)
operator+=operator-= | 以给定的 duration 修改 time_point (公开成员函数)
operator++operator++(int)operator--operator--(int) (C++20) | 自增或自减 duration (公开成员函数)
min [静态] | 返回对应最小时长的时间点 (公开静态成员函数)
max [静态] | 返回对应最大时长的时间点 (公开静态成员函数)

非成员函数

operator+operator- (C++11) | 实施涉及时间点的加法和减法运算 (函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=> (C++11)(C++11)(C++20 中移除)(C++11)(C++11)(C++11)(C++11)(C++20) | 比较两个时间点 (函数模板)
time_point_cast (C++11) | 转换时间点为同一时钟上拥有不同时长的另一时间点 (函数模板)
floor(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，向下取整 (函数模板)
ceil(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，向上取整 (函数模板)
round(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，就近取整，偶数优先 (函数模板)

辅助类

std::common_type<std::chrono::time_point>
(C++11)
 特化 std::common_type 特征
(类模板特化)

示例

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <ctime>
#include <chrono>

void slow_motion()
{
    static int a[] {1,2,3,4,5,6,7,8,9,10,11,12};
    while (std::ranges::next_permutation(a).found)
    { } // 生成 12! 个排列
}

int main()
{
    using namespace std::literals; // 允许用 24h 、 1ms 、 1s 代替对应的
                                   // std::chrono::hours(24) 等待

    const std::chrono::time_point<std::chrono::system_clock> now =
        std::chrono::system_clock::now();
        // “生产代码”可以简化为：
        // const auto now = std::chrono::system_clock::now();

    const std::time_t t_c = std::chrono::system_clock::to_time_t(now - 24h);
    std::cout << "24 hours ago, the time was "
              << std::put_time(std::localtime(&t_c), "%F %T.\n") << std::flush;

    const std::chrono::time_point<std::chrono::steady_clock> start =
        std::chrono::steady_clock::now();
        // “现实生活”的替用写法会是：
        // const auto start = std::chrono::steady_clock::now();

    slow_motion();

    const auto end = std::chrono::steady_clock::now();

    std::cout
      << "Slow calculations took "
      << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "µs ≈ "
      << (end - start) / 1ms << "ms ≈ " // 几乎等价于以上形式，
      << (end - start) / 1s << "s.\n";  // 但分别使用毫秒和秒
}

可能的输出：

24 hours ago, the time was 2021-02-15 18:28:52.
Slow calculations took 2090448µs ≈ 2090ms ≈ 2s.

参阅

duration
(C++11)
 时间区间
(类模板)


std::chrono::ceil(std::chrono::time_point)

< cpp‎ | chrono‎ | time point
定义于头文件 <chrono>
template <class ToDuration, class Clock, class Duration>

constexpr std::chrono::time_point <Clock, ToDuration>

ceil(const std::chrono::time_point <Clock, Duration>& tp);
 (C++17 起)

返回能以 ToDuration 表示的大于或等于 tp 的最小时间点 t 。

函数不参与重载决议，除非 ToDuration 是 std::chrono::duration 的特化。

参数

tp - 要向上取整的时间点

返回值

向上取整到使用 ToDuration 类型时长的下个时间点的 tp 。

可能的实现

namespace detail {
template<class> inline constexpr bool is_duration_v = false;
template<class Rep, class Period> inline constexpr bool is_duration_v<
    std::chrono::duration<Rep, Period>> = true;
}

template <class To, class Clock, class FromDuration,
          class = std::enable_if_t<detail::is_duration_v<To>>>
constexpr std::chrono::time_point<Clock, To>
    ceil(const std::chrono::time_point<Clock, FromDuration>& tp)
{
    return std::chrono::time_point<Clock, To>{
               std::chrono::ceil<To>(tp.time_since_epoch())};
}

示例

#include <iostream>
#include <chrono>
#include <string>

template <typename TimePoint>
std::string to_string(const TimePoint& time_point)
{
    return std::to_string(time_point.time_since_epoch().count());
}

int main()
{
    using namespace std::literals::chrono_literals;
    using Sec = std::chrono::seconds;

    std::cout << "Time point\t" "Cast\t" "Floor\t" "Round\t" "Ceil\n";
    std::cout << "(ms)\t\t"     "(s)\t"  "(s)\t"   "(s)\t"   "(s)\n";
    for (const auto value_ms: {5432ms, 5678ms}) {
        std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>
            time_point_ms(value_ms);

        std::cout
            << to_string(time_point_ms) << "\t\t"
            << to_string(std::chrono::time_point_cast<Sec>(time_point_ms)) << "\t"
            << to_string(std::chrono::floor          <Sec>(time_point_ms)) << "\t"
            << to_string(std::chrono::round          <Sec>(time_point_ms)) << "\t"
            << to_string(std::chrono::ceil           <Sec>(time_point_ms)) << "\n";
    }
}

输出：

Time point     Cast    Floor   Round   Ceil
(ms)            (s)     (s)     (s)     (s)
5432            5       5       5       6
5678            5       5       6       6

参阅

time_point_cast (C++11) | 转换时间点为同一时钟上拥有不同时长的另一时间点 (函数模板)
floor(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，向下取整 (函数模板)
round(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，就近取整，偶数优先 (函数模板)
ceil(std::chrono::duration) (C++17) | 以向上取整的方式，将一个时长转换为另一个时长 (函数模板)
ceilceilfceill (C++11)(C++11) | 不小于给定值的最接近整数值 (函数)


std::common_type(std::chrono::time_point)

< cpp‎ | chrono‎ | time point
template <class Clock, class Duration1, class Duration2>

struct common_type< std::chrono::time_point <Clock, Duration1>,
std::chrono::time_point <Clock, Duration2>> {
typedef std::chrono::time_point <
Clock, typename std::common_type <Duration1, Duration2>::type> type;

};
 (C++11 起)

暴露名为 type 的类型，它是二个 std::chrono::time_point 的公共类型。

注意

二个 std::chrono::time_point 类型的公共类型是 std::chrono::time_point ，拥有与二个类型相同的时钟，及其时长的 std::common_type 。

示例

本节未完成
原因：暂无示例

参阅

common_type
(C++11)
 确定一组类型的公共类型
(类模板)


std::chrono::floor(std::chrono::time_point)

< cpp‎ | chrono‎ | time point
定义于头文件 <chrono>
template <class ToDuration, class Clock, class Duration>

constexpr std::chrono::time_point <Clock, ToDuration>

floor(const std::chrono::time_point <Clock, Duration>& tp);
 (C++17 起)

返回能以 ToDuration 表示的小于或等于 tp 的最大时间点 t 。

函数不参与重载决议，除非 ToDuration 是 std::chrono::duration 的特化。

参数

tp - 要向下取整的时间点

返回值

向下取整到使用 ToDuration 类型时长的下一个时间点的 tp 。

可能的实现

namespace detail {
template<class> inline constexpr bool is_duration_v = false;
template<class Rep, class Period> inline constexpr bool is_duration_v<
    std::chrono::duration<Rep, Period>> = true;
}

template <class To, class Clock, class FromDuration,
          class = std::enable_if_t<detail::is_duration_v<To>>>
constexpr std::chrono::time_point<Clock, To>
    floor(const std::chrono::time_point<Clock, FromDuration>& tp)
{
    return std::chrono::time_point<Clock, To>{
        std::chrono::floor<To>(tp.time_since_epoch())};
}

示例

#include <iostream>
#include <chrono>
#include <string>

template <typename TimePoint>
std::string to_string(const TimePoint& time_point)
{
    return std::to_string(time_point.time_since_epoch().count());
}

int main()
{
    using namespace std::literals::chrono_literals;
    using Sec = std::chrono::seconds;

    std::cout << "Time point\t" "Cast\t" "Floor\t" "Round\t" "Ceil\n";
    std::cout << "(ms)\t\t"     "(s)\t"  "(s)\t"   "(s)\t"   "(s)\n";
    for (const auto value_ms: {5432ms, 5678ms}) {
        std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>
            time_point_ms(value_ms);

        std::cout
            << to_string(time_point_ms) << "\t\t"
            << to_string(std::chrono::time_point_cast<Sec>(time_point_ms)) << "\t"
            << to_string(std::chrono::floor          <Sec>(time_point_ms)) << "\t"
            << to_string(std::chrono::round          <Sec>(time_point_ms)) << "\t"
            << to_string(std::chrono::ceil           <Sec>(time_point_ms)) << "\n";
    }
}

输出：

Time point     Cast    Floor   Round   Ceil
(ms)            (s)     (s)     (s)     (s)
5432            5       5       5       6
5678            5       5       6       6

参阅

time_point_cast (C++11) | 转换时间点为同一时钟上拥有不同时长的另一时间点 (函数模板)
ceil(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，向上取整 (函数模板)
round(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，就近取整，偶数优先 (函数模板)
floor(std::chrono::duration) (C++17) | 以向下取整的方式，将一个时长转换为另一个时长 (函数模板)
floorfloorffloorl (C++11)(C++11) | 不大于给定值的最接近整数 (函数)


std::chrono::time_point<Clock,Duration>::max

< cpp‎ | chrono‎ | time point
static constexpr time_point max(); | (C++20 前)
static constexpr time_point max() noexcept; | (C++20 起)

返回拥有最大可能时长的 time_point ，即 time_point(std::chrono::duration::max()) 。

参数

（无）

返回值

最大的可能的 time_point

示例

#include <chrono>
#include <vector>
#include <iostream>

int main()
{
    std::chrono::time_point<std::chrono::system_clock> now =
        std::chrono::system_clock::now();
    std::vector<std::chrono::time_point<std::chrono::system_clock>> times {
        now - std::chrono::hours(24),
        now - std::chrono::hours(48),
        now + std::chrono::hours(24),
    };

    std::chrono::time_point<std::chrono::system_clock> earliest =
        std::chrono::time_point<std::chrono::system_clock>::max();

    std::cout << "all times:\n";
    for (const auto &time : times) {
        std::time_t t = std::chrono::system_clock::to_time_t(time);
        std::cout << std::ctime(&t);

        if (time < earliest) earliest = time;
    }

    std::time_t t = std::chrono::system_clock::to_time_t(earliest);
    std::cout << "earliest:\n" << std::ctime(&t);
}

可能的输出：

all times:
Sun Oct  7 19:06:48 2012
Sat Oct  6 19:06:48 2012
Tue Oct  9 19:06:48 2012
earliest:
Sat Oct  6 19:06:48 2012


std::chrono::time_point<Clock,Duration>::min

< cpp‎ | chrono‎ | time point
static constexpr time_point min(); | (C++20 前)
static constexpr time_point min() noexcept; | (C++20 起)

返回拥有最小可能时长的 time_point ，即 time_point(std::chrono::duration::min()) 。

参数

（无）

返回值

最小的可能的 time_point

示例

#include <iostream>
#include <ratio>
#include <chrono>

constexpr auto steady_min = std::chrono::steady_clock::time_point::min();

int main()
{
    auto last_frame = steady_min;
    std::chrono::duration<float, std::milli> game_time {0.0F};

    for (std::size_t count = 0; count < 5; ++count) {
        auto current_frame = std::chrono::steady_clock::now();
        // 若是首帧则初始化计时器：
        if (last_frame == steady_min)
            last_frame = current_frame;
        game_time += current_frame - last_frame;
        std::cout << "Drawing frame at " << game_time.count() << " ms\n";
        // 在时间偏移 game_time 绘制帧……
    }
}

可能的输出：

Drawing frame at 0 ms
Drawing frame at 0.17551 ms
Drawing frame at 0.358325 ms
Drawing frame at 0.545384 ms
Drawing frame at 0.736717 ms


std::chrono::time_point<Clock,Duration>::operator+, operator-

< cpp‎ | chrono‎ | time point
 | (1)
time_point& operator+=( const duration& d ); |  | (C++17 前)
constexpr time_point& operator+=( const duration& d ); |  | (C++17 起)
 | (2)
time_point& operator-=( const duration& d ); |  | (C++17 前)
constexpr time_point& operator-=( const duration& d ); |  | (C++17 起)

以指定的时长修改时间点。

1) 应用偏移 d 到 pt 。等效地以 d_ += d 将 d 加到内部存储的 duration 。
2) 以负方向应用偏移 d 到 pt 。等效地以 d_ -= d 从内部存储的 duration d_ 减去 d 。

参数

d - 要应用的时间偏移

返回值

*this 。

异常

可能抛出实现定义的异常。

参阅

operator+operator-
(C++11)
 实施涉及时间点的加法和减法运算
(函数模板)


operator+, operator-(std::chrono::time_point)

< cpp‎ | chrono‎ | time point
定义于头文件 <chrono> |
 | (1)
template< class C, class D1, class R2, class P2 > time_point<C, typename std::common_type <D1, duration<R2,P2>>::type> operator+( const time_point<C,D1>& pt, const duration<R2,P2>& d ); |  | (C++11 起) (C++14 前)
template< class C, class D1, class R2, class P2 > constexpr time_point<C, typename std::common_type <D1, duration<R2,P2>>::type> operator+( const time_point<C,D1>& pt, const duration<R2,P2>& d ); |  | (C++14 起)
 | (2)
template< class R1, class P1, class C, class D2 > time_point<C, typename std::common_type <duration<R1,P1>,D2>::type> operator+( const duration<R1,P1>& d, const time_point<C,D2>& pt ); |  | (C++11 起) (C++14 前)
template< class R1, class P1, class C, class D2 > constexpr time_point<C, typename std::common_type <duration<R1,P1>,D2>::type> operator+( const duration<R1,P1>& d, const time_point<C,D2>& pt ); |  | (C++14 起)
 | (3)
template< class C, class D1, class R2, class P2 > time_point<C, typename std::common_type <D1, duration<R2,P2>>::type> operator-( const time_point<C,D1>& pt, const duration<R2,P2>& d ); |  | (C++11 起) (C++14 前)
template< class C, class D1, class R2, class P2 > constexpr time_point<C, typename std::common_type <D1, duration<R2,P2>>::type> operator-( const time_point<C,D1>& pt, const duration<R2,P2>& d ); |  | (C++14 起)
 | (4)
template< class C, class D1, class D2 > typename std::common_type <D1,D2>::type operator-( const time_point<C,D1>& pt_lhs, const time_point<C,D2>& pt_rhs ); |  | (C++11 起) (C++14 前)
template< class C, class D1, class D2 > constexpr typename std::common_type <D1,D2>::type operator-( const time_point<C,D1>& pt_lhs, const time_point<C,D2>& pt_rhs ); |  | (C++14 起)

进行涉及 time_point 的加减运算。

1-2) 应用偏移 d 到 pt 。等效于返回 CT(pt.time_since_epoch() + d) ，其中 CT 为返回类型。
3) 以负方向应用偏移 d 到 pt 。等效于返回 CT(pt.time_since_epoch() - d) ，其中 CT 为返回类型。
4) 计算 pt_lhs 与 pt_rhs 之间的差。

参数

pt | - | 要应用偏移到的时间点
d | - | 时间偏移
pt_lhs, pt_rhs | - | 用于提取差的时间点

返回值

1-3) 由应用偏移 d 产生的时间点。
4) 时间点之间的时长。

异常

可能抛出实现定义的异常。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2739 | C++11 | pt - d 对无符号 duration 行为不规律 | 更正行为

参阅

operator+=operator-=
 以给定的 duration 修改 time_point
(公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::chrono::time_point)

< cpp‎ | chrono‎ | time point
定义于头文件 <chrono>
(1)
template< class Clock, class Dur1, class Dur2 >

bool operator==( const std::chrono::time_point <Clock,Dur1>& lhs,

const std::chrono::time_point <Clock,Dur2>& rhs );
 (C++11 起)
(C++14 前)
template< class Clock, class Dur1, class Dur2 >

constexpr bool operator==( const std::chrono::time_point <Clock,Dur1>& lhs,

const std::chrono::time_point <Clock,Dur2>& rhs );
 (C++14 起)
(2)
template< class Clock, class Dur1, class Dur2 >

bool operator!=( const std::chrono::time_point <Clock,Dur1>& lhs,

const std::chrono::time_point <Clock,Dur2>& rhs );
 (C++11 起)
(C++14 前)
template< class Clock, class Dur1, class Dur2 >

constexpr bool operator!=( const std::chrono::time_point <Clock,Dur1>& lhs,

const std::chrono::time_point <Clock,Dur2>& rhs );
 (C++14 起)
(C++20 前)
(3)
template< class Clock, class Dur1, class Dur2 >

bool operator<( const std::chrono::time_point <Clock,Dur1>& lhs,

const std::chrono::time_point <Clock,Dur2>& rhs );
 (C++11 起)
(C++14 前)
template< class Clock, class Dur1, class Dur2 >

constexpr bool operator<( const std::chrono::time_point <Clock,Dur1>& lhs,

const std::chrono::time_point <Clock,Dur2>& rhs );
 (C++14 起)
(4)
template< class Clock, class Dur1, class Dur2 >

bool operator<=( const std::chrono::time_point <Clock,Dur1>& lhs,

const std::chrono::time_point <Clock,Dur2>& rhs );
 (C++11 起)
(C++14 前)
template< class Clock, class Dur1, class Dur2 >

constexpr bool operator<=( const std::chrono::time_point <Clock,Dur1>& lhs,

const std::chrono::time_point <Clock,Dur2>& rhs );
 (C++14 起)
(5)
template< class Clock, class Dur1, class Dur2 >

bool operator>( const std::chrono::time_point <Clock,Dur1>& lhs,

const std::chrono::time_point <Clock,Dur2>& rhs );
 (C++11 起)
(C++14 前)
template< class Clock, class Dur1, class Dur2 >

constexpr bool operator>( const std::chrono::time_point <Clock,Dur1>& lhs,

const std::chrono::time_point <Clock,Dur2>& rhs );
 (C++14 起)
(6)
template< class Clock, class Dur1, class Dur2 >

bool operator>=( const std::chrono::time_point <Clock,Dur1>& lhs,

const std::chrono::time_point <Clock,Dur2>& rhs );
 (C++11 起)
(C++14 前)
template< class Clock, class Dur1, class Dur2 >

constexpr bool operator>=( const std::chrono::time_point <Clock,Dur1>& lhs,

const std::chrono::time_point <Clock,Dur2>& rhs );
 (C++14 起)
template<class Clock, class Dur1, std::three_way_comparable_with<Dur1> Dur2>

constexpr auto operator<=>( const std::chrono::time_point <Clock,Dur1>& lhs,

const std::chrono::time_point <Clock,Dur2>& rhs );
 (7) (C++20 起)

比较二个时间点。以比较 time_since_epoch() 对这些时间点的结果进行比较。

1-2) 检查 time_point lhs 与 rhs 是否给定时钟的同一时间点。
3-6) 比较 time_point lhs 与 rhs 。
7) 比较 time_point lhs 与 rhs 。返回类型从 lhs.time_since_epoch() <=> rhs.time_since_epoch() 推导，从而为 Dur1 与 Dur2 的三路比较结果类型。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的 time_point

返回值

1) 若 lhs 与 rhs 指代同一时间点则为 true ，否则为 false 。
2) 若 lhs 与 rhs 指代不同时间点则为 true ，否则为 false 。
3) 若 lhs 指代的时间点先于 rhs 则为 true ，否则为 false 。
4) 若 lhs 指代的时间点先于 rhs ，或指代的时间点与 rhs 相同则为 true ，否则为 false 。
5) 若 lhs 指代的时间点后于 rhs 则为 ，否则为 false 。
6) 若 lhs 指代的时间点后于 rhs ，或指代的时间点与 rhs 相同则为 true ，否则为 false 。
7) lhs.time_since_epoch() <=> rhs.time_since_epoch() 。

异常

可能抛出实现定义的异常。

注解

time_point 的双路比较运算符曾在 C++11 中不是 constexpr ，这在 C++14 中更正。


std::chrono::time_point<Clock,Duration>::operator++, std::chrono::time_point<Clock,Duration>::operator--

< cpp‎ | chrono‎ | time point
constexpr time_point& operator++(); | (1) | (C++20 起)
constexpr time_point operator++(int); | (2) | (C++20 起)
constexpr time_point& operator--(); | (3) | (C++20 起)
constexpr time_point operator--(int); | (4) | (C++20 起)

以 duration 的一个计次修改时间点 *this 。

若 d_ 为此 time_point 对象保有时长（即自纪元起的时间）的成员变量，则

1) 等价于 ++d_; return *this;
2) 等价于 return time_point(d_++)
3) 等价于 --d_; return *this;
4) 等价于 return time_point(d_--);

参数

（无）

返回值

1,3) 到修改后的此 time_point 的引用
2,4) 进行修改前的 time_point 的副本

示例

本节未完成
原因：暂无示例

参阅

operator++operator++(int)operator--operator--(int) | 递增或递减滴答计数 (std::chrono::duration<Rep,Period> 的公开成员函数)
operator+=operator-= | 以给定的 duration 修改 time_point (公开成员函数)
operator+operator- (C++11) | 实施涉及时间点的加法和减法运算 (函数模板)


std::chrono::round(std::chrono::time_point)

< cpp‎ | chrono‎ | time point
定义于头文件 <chrono>
template <class ToDuration, class Clock, class Duration>

constexpr std::chrono::time_point <Clock, ToDuration>

round(const std::chrono::time_point <Clock, Duration>& tp);
 (C++17 起)

返回能以 ToDuration 表示的最接近 tp 的时间点，中点情况下向偶数舍入。

函数不参与重载决议，除非 ToDuration 是 std::chrono::duration 的特化且 std::chrono::treat_as_floating_point_v<typename ToDuration::rep> 为 false 。

参数

tp - 要舍入到最近值的时间点

返回值

舍入到使用 ToDuration 类型时长的最近时间点的 tp ，中点情况下向偶数舍入。

可能的实现

namespace detail {
template<class> inline constexpr bool is_duration_v = false;
template<class Rep, class Period> inline constexpr bool is_duration_v<
    std::chrono::duration<Rep, Period>> = true;
}

template <class To, class Clock, class FromDuration,
          class = std::enable_if_t<detail::is_duration_v<To>
             && !std::chrono::treat_as_floating_point_v<typename To::rep>>>
constexpr std::chrono::time_point<Clock, To> round(
    const std::chrono::time_point<Clock, FromDuration>& tp)
{
    return std::chrono::time_point<Clock, To>{
        std::chrono::round<To>(tp.time_since_epoch())};
}

示例

#include <iostream>
#include <chrono>
#include <string>

template <typename TimePoint>
std::string to_string(const TimePoint& time_point)
{
    return std::to_string(time_point.time_since_epoch().count());
}

int main()
{
    using namespace std::literals::chrono_literals;
    using Sec = std::chrono::seconds;

    std::cout << "Time point\t" "Cast\t" "Floor\t" "Round\t" "Ceil\n";
    std::cout << "(ms)\t\t"     "(s)\t"  "(s)\t"   "(s)\t"   "(s)\n";
    for (const auto value_ms: {5432ms, 5678ms}) {
        std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>
            time_point_ms(value_ms);

        std::cout
            << to_string(time_point_ms) << "\t\t"
            << to_string(std::chrono::time_point_cast<Sec>(time_point_ms)) << "\t"
            << to_string(std::chrono::floor          <Sec>(time_point_ms)) << "\t"
            << to_string(std::chrono::round          <Sec>(time_point_ms)) << "\t"
            << to_string(std::chrono::ceil           <Sec>(time_point_ms)) << "\n";
    }
}

输出：

Time point     Cast    Floor   Round   Ceil
(ms)            (s)     (s)     (s)     (s)
5432            5       5       5       6
5678            5       5       6       6

参阅

time_point_cast (C++11) | 转换时间点为同一时钟上拥有不同时长的另一时间点 (函数模板)
ceil(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，向上取整 (函数模板)
floor(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，向下取整 (函数模板)
round(std::chrono::duration) (C++17) | 转换时长到另一个时长，就近取整，偶数优先 (函数模板)
roundroundfroundllroundlroundflroundlllroundllroundfllroundl (C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11) | 最接近整数，中间情况下向远离零舍入 (函数)


std::chrono::time_point<Clock,Duration>::time_point

< cpp‎ | chrono‎ | time point
 | (1)
time_point(); |  | (C++11 起) (C++14 前)
constexpr time_point(); |  | (C++14 起)
 | (2)
explicit time_point( const duration& d ); |  | (C++11 起) (C++14 前)
constexpr explicit time_point( const duration& d ); |  | (C++14 起)
 | (3)
template< class Duration2 > time_point( const time_point<Clock,Duration2>& t ); |  | (C++11 起) (C++14 前)
template< class Duration2 > constexpr time_point( const time_point<Clock,Duration2>& t ); |  | (C++14 起)

从数个可选数据源之一构造新的 time_point 。

1) 默认构造函数，创建表示 Clock 的纪元（即 time_since_epoch() 为零）的 time_point 。
2) 构造位于 Clock 的纪元加上 d 的 time_point 。
3) 通过转换 t 为 duration 构造 time_point 。此构造函数仅若 Duration2 可隐式转换为 duration 才参与重载决议。

参数

d | - | 复制来源的 duration
t | - | 转换来源的 time_point

示例

#include <chrono>
#include <iostream>

using Clock = std::chrono::high_resolution_clock;
using TimePoint = std::chrono::time_point<Clock>;

void print_ms(const TimePoint& point)
{
    using Ms = std::chrono::milliseconds;
    const Clock::duration since_epoch = point.time_since_epoch();
    std::cout << std::chrono::duration_cast<Ms>(since_epoch).count() << " ms\n";
}

int main()
{
    const TimePoint default_value = TimePoint(); // (1)
    print_ms(default_value); // 0 ms

    const Clock::duration duration_4_seconds = std::chrono::seconds(4);
    const TimePoint time_point_4_seconds(duration_4_seconds); // (2)
      // 从纪元开始 4 秒
    print_ms(time_point_4_seconds); // 4000 ms

    const TimePoint time_point_now = Clock::now(); // (3)
    print_ms(time_point_now); // 43098276 ms
}

可能的输出：

0 ms
4000 ms
43098276 ms

参阅

(构造函数) | 构造新 duration (std::chrono::duration<Rep,Period> 的公开成员函数)
duration_cast (C++11) | 转换时长到另一个拥有不同嘀嗒间隔的时长 (函数模板)


std::chrono::time_point_cast

< cpp‎ | chrono‎ | time point
定义于头文件 <chrono>
template <class ToDuration, class Clock, class Duration>

std::chrono::time_point <Clock, ToDuration>

time_point_cast(const std::chrono::time_point <Clock, Duration> &t);
 (C++11 起)
(C++14 前)
template <class ToDuration, class Clock, class Duration>

constexpr std::chrono::time_point <Clock, ToDuration>

time_point_cast(const std::chrono::time_point <Clock, Duration> &t);
 (C++14 起)

将 std::chrono::time_point 从一个时长转换到另一个。

time_point_cast 仅若 ToDuration 为 std::chrono::duration 的特化才参与重载决议。

示例

t - 转换来源的 time_point

返回值

std::chrono::time_point <Clock, ToDuration>(
std::chrono::duration_cast <ToDuration>(t.time_since_epoch())) 。

示例

#include <iostream>
#include <chrono>

using Clock = std::chrono::high_resolution_clock;
using Ms = std::chrono::milliseconds;
using Sec = std::chrono::seconds;

template<class Duration>
using TimePoint = std::chrono::time_point<Clock, Duration>;

inline void print_ms(const TimePoint<Ms>& time_point)
{
    std::cout << time_point.time_since_epoch().count() << " ms\n";
}

int main()
{
    TimePoint<Sec> time_point_sec(Sec(4));

    // 隐式转换，无精度损失
    TimePoint<Ms> time_point_ms(time_point_sec);
    print_ms(time_point_ms); // 4000 ms

    time_point_ms = TimePoint<Ms>(Ms(5756));

    // 显式转型，在精度损失可能发生时需要
    // 5756 truncated to 5000
    time_point_sec = std::chrono::time_point_cast<Sec>(time_point_ms);
    print_ms(time_point_sec); // 5000 ms
}

输出：

4000 ms
5000 ms

参阅

time_point (C++11) | 时间中的点 (类模板)
floor(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，向下取整 (函数模板)
ceil(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，向上取整 (函数模板)
round(std::chrono::time_point) (C++17) | 转换 time_point 到另一个，就近取整，偶数优先 (函数模板)
duration_cast (C++11) | 转换时长到另一个拥有不同嘀嗒间隔的时长 (函数模板)


std::chrono::time_point<Clock,Duration>::time_since_epoch

< cpp‎ | chrono‎ | time point
duration time_since_epoch() const; | (C++11 起) (C++14 前)
constexpr duration time_since_epoch() const; | (C++14 起)

返回表示 *this 与 clock 的纪元间的时间量的 duration 。

参数

（无）

返回值

此 time_point 与 clock 的纪元间的时间量

示例

#include <iostream>
#include <chrono>
#include <ctime>

int main()
{
    auto p0 = std::chrono::time_point<std::chrono::system_clock>{};
    auto p1 = std::chrono::system_clock::now();
    auto p2 = p1 - std::chrono::hours(24);

    auto epoch_time = std::chrono::system_clock::to_time_t(p0);
    std::cout << "epoch: " << std::ctime(&epoch_time);
    auto today_time = std::chrono::system_clock::to_time_t(p1);
    std::cout << "today: " << std::ctime(&today_time);

    std::cout << "hours since epoch: "
              << std::chrono::duration_cast<std::chrono::hours>(
                   p1.time_since_epoch()).count()
              << '\n';
    std::cout << "yesterday, hours since epoch: "
              << std::chrono::duration_cast<std::chrono::hours>(
                   p2.time_since_epoch()).count()
              << '\n';
}

可能的输出：

epoch: Thu Jan  1 00:00:00 1970
today: Fri Jun 30 10:44:11 2017
hours since epoch: 416338
yesterday, hours since epoch: 416314


std::chrono::time_zone

< cpp‎ | chrono
定义于头文件 <chrono> |
class time_zone; | (C++20 起)

类 time_zone 表示特定地理区域的所有时区转变。

用户不能构造 time_zone 对象。库实现在初始化时区数据库时创建 time_zone 对象，并提供对这些对象的 const 访问。

time_zone 不可复制，但有默认化的移动构造函数和移动赋值运算符。然而，因为用户只拥有对 time_zone 对象的 const 访问，无法在用户代码中调用这些函数而不引发未定义行为。

成员函数

name | 获得此 time_zone 的名称 (公开成员函数)
get_info | 获得与 sys_time 或 local_time 关联的信息 (公开成员函数)
to_sys | 将此时区中的 local_time 转换成 sys_time (公开成员函数)
to_local | 将 sys_time 转换成此时区中的 local_time (公开成员函数)

非成员函数

operator==operator<=>
(C++20)
 比较二个 time_zone 对象
(函数)


std::chrono::time_zone::get_info

< cpp‎ | chrono‎ | time zone
template<class Duration > std::chrono::sys_info get_info(const std::chrono::sys_time<Duration>& tp) const; | (C++20 起)
template< class Duration > std::chrono::local_info get_info(const std::chrono::local_time<Duration>& tp) const; | (C++20 起)

获得关于此时区在时间点 tp 的信息。

返回值

1) 含有此时区在时间点 tp 有效的时区信息的 std::chrono::sys_info 结构体 i 。 tp 将在范围 [i.begin, i.end) 中。
2) 含有关于本地时间 tp 在此时区中的信息的 std::chrono::local_info 结构体。


std::chrono::time_zone::name

< cpp‎ | chrono‎ | time zone
std::string_view name() const noexcept; | (C++20 起)

获得此时区的名称。

返回值

此时区的名称（例如 "America/New_York" ）。


std::chrono::operator==,<=>(std::chrono::time_zone)

< cpp‎ | chrono‎ | time zone
定义于头文件 <chrono>
bool operator==( const std::chrono::time_zone& x,
const std::chrono::time_zone& y ) noexcept;
 (1) (C++20 起)
std::strong_ordering operator!=( const std::chrono::time_zone& x,
const std::chrono::time_zone& y ) noexcept;
 (2) (C++20 起)

以名称比较二个 time_zone 值 x 与 y 。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

返回值

1) x.name() == y.name() 。
2) x.name() <=> y.name() 。


std::chrono::time_zone::to_local

< cpp‎ | chrono‎ | time zone
template< class Duration >

auto to_local(const std::chrono::sys_time<Duration>& tp) const

-> std::chrono::local_time< std::common_type_t <Duration, std::chrono::seconds >>;
 (C++20 起)

转换 sys_time tp 为此时区中对应的 local_time 。

返回值

与 tp 和此时区关联的 local_time 。

注意

结果的精度至少为 std::chrono::seconds ，而若参数拥有更精细的精度则将更精细。


std::chrono::time_zone::to_sys

< cpp‎ | chrono‎ | time zone
template< class Duration >

auto to_sys(const std::chrono::local_time<Duration>& tp) const

-> std::chrono::sys_time< std::common_type_t <Duration, std::chrono::seconds >>;
 (C++20 起)
template< class Duration >

auto to_sys(const std::chrono::local_time<Duration>& tp, std::chrono::choose z) const

-> std::chrono::sys_time< std::common_type_t <Duration, std::chrono::seconds >>;
 (C++20 起)

转换此时区中的 local_time tp 为对应的 sys_time 。

1) 若转换有歧义或 tp 表示不存在的时间则抛出异常。
2) 按照 z 的值解决歧义：
  • 若 z == std::chrono::choose::earliest ，则返回较早的 sys_time 。
  • 若 z == std::chrono::choose::latest ，则返回较晚的 sys_time 。
若 tp 表示二个 UTC time_point 间不存在的时间，则二个 time_point 将相同，并将返回该 time_point 。

返回值

按照此时区规则的 tp 的 UTC 等价版本。

异常

1) 若转换有歧义则抛出 std::chrono::ambiguous_local_time 。若 tp 表示不存在的时间则抛出 std::chrono::nonexistent_local_time 。

注意

结果的精度至少为 std::chrono::seconds ，而且若参数有更精细的精度则将更精细。

歧义和不存在的本地时间能作为时区转变（例如夏时令）的结果出现。例如， "2016-03-13 02:30:00" 不存在于 "America/New_York" 时区，而该时区中的 "2016-11-06 01:30:00" 能对应二个 UTC 时间点： 2016-11-06 05:30:00 UTC 和 2016-11-06 06:30:00 UTC 。


std::chrono::time_zone_link

< cpp‎ | chrono
定义于头文件 <chrono> |
class time_zone_link; | (C++20 起)

类 time_zone_link 表示时区的替用名。

用户不能构造 v 对象。库实现在初始化时区数据库时创建 time_zone_link 对象，并提供对这些对象的 const 访问。

time_zone_link 不可复制，但有默认化的移动构造函数和移动赋值运算符。然而，因为用户只拥有对 time_zone_link 对象的 const 访问，无法在用户代码中调用这些函数而不引发未定义行为。

成员函数

nametarget
 访问此 time_zone_link 的名称与目标
(公开成员函数)

非成员函数

operator==operator<=>
(C++20)
 比较二个 time_zone_link 对象
(函数)


std::chrono::time_zone_link::name, std::chrono::time_zone_link::target

< cpp‎ | chrono‎ | time zone link
std::string_view name() const noexcept; | (1)
std::string_view target() const noexcept; | (2)

访问此 time_zone_link 对象的名称和目标。

返回值

1) 此 time_zone_link 对象所表示的替用名。
2) 此 time_zone_link 对象为之提供替用名的 std::chrono::time_zone 的名称。


std::chrono::operator==,<=>(std::chrono::time_zone_link)

< cpp‎ | chrono‎ | time zone link
定义于头文件 <chrono>
bool operator==( const std::chrono::time_zone_link& x,
const std::chrono::time_zone_link& y ) noexcept;
 (1) (C++20 起)
std::strong_ordering operator<=>( const std::chrono::time_zone_link& x,
const std::chrono::time_zone_link& y ) noexcept;
 (2) (C++20 起)

按名称比较二个 time_zone_link 值 x 与 y 。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

返回值

1) x.name() == y.name() 。
2) x.name() <=> y.name() 。


std::chrono::treat_as_floating_point

< cpp‎ | chrono
定义于头文件 <chrono> |
template <class Rep> struct treat_as_floating_point : std::is_floating_point <Rep> {}; | (C++11 起)

std::chrono::treat_as_floating_point 特性帮助确定时期是否能转换成拥有另一种不同计次周期的时期。

二个时期间的隐式转换通常依赖于时期的计次周期。然而若 std::chrono::treat_as_floating_point<Rep>::value == true 则可发生隐式转换，不管计次周期如何。

辅助变量模板

template< class Rep > inline constexpr bool treat_as_floating_point_v = treat_as_floating_point<Rep>::value; | (C++17 起)

特化

可对程序定义类型特化 std::chrono::treat_as_floating_point 。

示例

#include <iostream>
#include <chrono>
#include <thread>

void timed_piece_of_code()
{
    std::chrono::milliseconds simulated_work(2);
    std::this_thread::sleep_for(simulated_work);
}

int main()
{
    auto start = std::chrono::high_resolution_clock::now();

    std::cout << "Running some timed piece of code..." << '\n';
    timed_piece_of_code();

    auto stop = std::chrono::high_resolution_clock::now();

    // 浮点毫秒类型
    using FpMilliseconds =
        std::chrono::duration<float, std::chrono::milliseconds::period>;

    static_assert(std::chrono::treat_as_floating_point<FpMilliseconds::rep>::value,
                  "Rep required to be floating point");

    // 注意此处不允许隐式转换
    auto i_ms = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);

    // 注意此处允许隐式转换
    auto f_ms = FpMilliseconds(stop - start);

    std::cout << "Time in milliseconds, using default rep: "
              << i_ms.count() << '\n';

    std::cout << "Time in milliseconds, using floating point rep: "
              << f_ms.count() << '\n';

}

可能的输出：

Running some timed piece of code...
Timing stats:
  Time in milliseconds, using default rep: 2
  Time in milliseconds, using floating point rep: 2.57307

参阅


std::chrono::tzdb

< cpp‎ | chrono
定义于头文件 <chrono> |
struct tzdb; | (C++20 起)

类 tzdb 表示 IANA 时区数据库的副本。用户不能构造 tzdb ，而只能通过自由函数 std::chrono::get_tzdb_list 和 std::chrono::get_tzdb 访问其一个实例。

成员对象

成员对象 | 描述
version | 含数据库版本的 std::string
zones | 含时区描述的已排序 std::vector <std::chrono::time_zone>
links | 含时区替用名描述（链接）的已排序 std::vector <std::chrono::link>
leaps | 含闰秒描述的已排序 std::vector <std::chrono::leaps>

成员函数

locate_zone | 以给定的名称定位时区 (公开成员函数)
current_zone | 返回本地时区 (公开成员函数)


std::chrono::tzdb::current_zone

< cpp‎ | chrono‎ | tzdb
const std::chrono::time_zone* current_zone() const; | (C++20 起)

获得指向此数据库中表示计算机本地时区的 std::chrono::time_zone 的指针。

返回值

指向此数据库中表示计算机本地时区的 std::chrono::time_zone 的指针。


std::chrono::tzdb::locate_zone

< cpp‎ | chrono‎ | tzdb
const std::chrono::time_zone* locate_zone( std::string_view tz_name) const; | (C++20 起)

获得指向此数据库中表示 tz_name 所指代的时区的 std::chrono::time_zone 的指针。若 p 是返回的指针，则 p->name() == tz_name 或在此数据库中有一个 std::chrono::time_zone_link l 使得 p->name() == l.target() && l.name() == tz_name 。

返回值

指向此数据库中表示 tz_name 所指代的时区的 std::chrono::time_zone 的指针。

异常

若找不到这种 time_zone 则为 std::runtime_error 。


std::chrono::get_tzdb_list, std::chrono::get_tzdb, std::chrono::remote_version, std::chrono::reload_tzdb

< cpp‎ | chrono
std::chrono::tzdb_list& get_tzdb_list(); | (1) | (C++20 起)
const std::chrono::tzdb& get_tzdb(); | (2) | (C++20 起)
std::string remote_version(); | (3) | (C++20 起)
const std::chrono::tzdb& reload_tzdb(); | (4) | (C++20 起)

这些函数提供到程序范围的时区数据库访问。

1) 返回到全局 std::chrono::tzdb_list 单例的引用。若这是到数据库的首次访问，则初始化数据库。初始化后，数据库将保有单个初始化的 std::chrono::tzdb 对象 。此函数是线程安全的：同时调用此函数不引入数据竞争。
2) 返回到 tzdb_list 单例所保有的首个 std::chrono::tzdb 对象的引用。等价于 std::chrono::get_tzdb_list().front() 。
3) 返回含有最新远程数据库版本的 string 。
4) 若 remote_version() != get_tzdb().version ，则推入表示远程数据库的新 tzdb 对象到 get_tzdb_list() 所引用的 tzdb_list 单例的前部。否则无效果。不非法化任何引用、指针或迭代器。同时与 get_tzdb_list().front() 或 get_tzdb_list().erase_after() 调用此函数不引入数据竞争。

异常

1) 若因任何原因，到 tzdb_list 的引用含有一或多个不能返回的 tzdb 则为 std::runtime_error 。

返回值

1) 到全局 std::chrono::tzdb_list 单例的引用。
2) std::chrono::get_tzdb_list().front() 。
3) 含有最新远程数据库版本的 string 。
4) （此函数所作的任何更新后的） std::chrono::get_tzdb_list().front() 。


std::chrono::tzdb_list

< cpp‎ | chrono
定义于头文件 <chrono> |
class tzdb_list; | (C++20 起)

tzdb_list 是 std::chrono::tzdb 的单例链表，每个都保有 IANA 时区数据库的副本。用户不能构造 tzdb_list ，只能由 std::chrono::get_tzdb_list 自由函数访问一个对象。

成员类型

成员类型 | 定义
const_iterator | 值类型为 std::chrono::tzdb 的常老式向前迭代器 (LegacyForwardIterator)

成员函数

(构造函数) [被删除] | 定义复制构造函数为被删除 (公开成员函数)
operator= [被删除] | 定义复制赋值运算符为被删除 (公开成员函数)
front | 访问首元素 (公开成员函数)
erase_after | 擦除元素后的元素 (公开成员函数)
begincbegin | 返回指向表起始的迭代器 (公开成员函数)
endcend | 返回表的尾后迭代器 (公开成员函数)


std::chrono::tzdb_list::begin

< cpp‎ | chrono‎ | tzdb list
const_iterator begin() const noexcept; | (C++20 起)
const_iterator cbegin() const noexcept; | (C++20 起)

返回指向容器中首个 std::chrono::tzdb 的迭代器。

返回值

指向容器中首个 std::chrono::tzdb 的迭代器。


std::chrono::tzdb_list::end, std::chrono::tzdb_list::cend

< cpp‎ | chrono‎ | tzdb list
const_iterator end() const noexcept; | (C++20 起)
const_iterator cend() const noexcept; | (C++20 起)

返回 tzdb_list 的尾后迭代器。试图访问此迭代器导致未定义行为。

返回值

尾后迭代器。


std::chrono::tzdb_list::erase_after

< cpp‎ | chrono‎ | tzdb list
const_iterator erase_after(const_iterator p); | (C++20 起)

擦除后随 p 的迭代器所指向的 std::chrono::tzdb 若该迭代器不可解引用则行为未定义。不非法化指针、引用或迭代器，除了指代被擦除元素者。

返回值

指向后随被擦除元素的迭代器，或若这种元素不存在则为 end() 。

注意

有意令 tzdb_list 实现为链表，而其接口类似 std::forward_list 的接口。然而它无 before_begin() ，故不可能擦除首元素。


std::chrono::tzdb_list::front

< cpp‎ | chrono‎ | tzdb list
const std::chrono::tzdb& front() const noexcept; | (C++20 起)

获得到表中首个 std::chrono::tzdb 的引用。同时调用此函数和 std::chrono::reload_tzdb() 不引入数据竞争。


std::chrono::utc_clock

< cpp‎ | chrono
定义于头文件 <chrono> |
class utc_clock; | (C++20 起)

时钟 std::chrono::utc_clock 是表示协调世界时 (Coordinated Universal Time, UTC) 的时钟 (Clock) 。它度量从 1970 年 1 月 1 日星期四 00:00:00 开始的时间，包括闰秒。

utc_clock 满足时钟 (Clock) 要求。它不满足平凡时钟 (TrivialClock) 要求，除非实现能保证 now() 不抛异常。

时间点族

定义于命名空间 std::chrono |
template<class Duration> using utc_time = std::chrono::time_point <std::chrono::utc_clock, Duration>; | (C++20 起)
using utc_seconds = utc_time< std::chrono::seconds >; | (C++20 起)
operator<<(std::chrono::utc_time) (C++20) | 进行 utc_time 上的流输出 (函数模板)
from_stream(std::chrono::utc_time) (C++20) | 按照给定的格式从流分析 utc_time (函数模板)
std::formatter<std::chrono::utc_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 utc_time (类模板特化)

成员类型

成员类型 | 定义
rep | 表示时钟时长中计次数的有符号算术类型
period | 表示时钟计次周期的 std::ratio 类型，单位为秒
duration | std::chrono::duration <rep, period> ，足以表示负时长
time_point | std::chrono::time_point <std::chrono::utc_clock>

成员常量

constexpr bool is_steady
[静态]
 若时间间隔计次始终为常数，即纵使在调整了外部时钟的情况下，调用 now() 的返回值亦单调递增，则为 true ；否则为 false
(公开静态成员常量)

成员函数

now [静态] | 返回表示当前时间点的 std::chrono::time_point (公开静态成员函数)
to_sys [静态] | 转换 utc_time 为 sys_time (公开静态成员函数)
from_sys [静态] | 转换 sys_time 为 utc_time (公开静态成员函数)

非成员函数

get_leap_second_info
(C++20)
 从 utc_time 对象获得闰秒插入信息
(函数模板)

辅助类

leap_second_info
(C++20)
 闰秒插入信息
(类)

注解

官方的 UTC 纪元为 1972 年 1 月 1 日。 utc_clock 改用 1970 年 1 月 1 日以与 std::chrono::system_clock 一致。


std::chrono::utc_clock::from_sys

< cpp‎ | chrono‎ | utc clock
template <class Duration>

static std::chrono::utc_time< std::common_type_t <Duration, std::chrono::seconds >>

from_sys(const std::chrono::sys_time<Duration>& t);
 (C++20 起)

转换 sys_time t 到表示同一时间点的 utc_time u 。 u.time_since_epoch() - t.time_since_epoch() 等于在 t 与 1970 年 1 月 1 日间插入的闰秒数。若 t 是准确的插入闰秒日期，则将闰秒算作已插入。

返回值

与 t 表示同一时间点的 utc_time 。

参阅

to_sys
[静态]
 转换 utc_time 为 sys_time
(公开静态成员函数)


std::chrono::get_leap_second_info

< cpp‎ | chrono‎ | utc clock
定义于头文件 <chrono>
template< class Duration >

std::chrono::leap_second_info

get_leap_second_info( const std::chrono::utc_time<Duration>& ut );
 (C++20 起)

获得一个 std::chrono::leap_second_info ，其 is_leap_second 与 elapsed 分别指示 ut 是否在正闰秒插入中，及 1970 年 1 月 1 日与 ut 之间的闰秒和。

参数

ut - 要检验的 UTC 时间

返回值

如上指定的 leap_second_info 值。

异常

可能抛出实现定义的异常。

参阅

leap_second_info (C++20) | 闰秒插入信息 (类)
leap_second (C++20) | 含有关于插入闰秒的信息 (类)


std::chrono::leap_second_info

< cpp‎ | chrono‎ | utc clock
定义于头文件 <chrono>
struct leap_second_info {

bool is_leap_second;
std::chrono::seconds elapsed;

};
 (C++20 起)

leap_second_info 指示 UTC 时间是否在正闰秒插入期间，以及 1970 年 1 月 1 日与该 UTC 时间之间的闰秒和。

leap_second_info 无基类或 is_leap_second、 elapsed 和隐式声明的特殊成员函数以外的成员。

成员对象

is_leap_second | UTC 时间是否在正闰秒插入期间 (公开成员对象)
elapsed | 1970 年 1 月 1 日与该 UTC 时间之间的闰秒和 (公开成员对象)

注解

leap_second_info 常从 std::chrono::get_leap_second_info 获得。

参阅

leap_second
(C++20)
 含有关于插入闰秒的信息
(类)


std::chrono::utc_clock::now

< cpp‎ | chrono‎ | utc clock

static std::chrono::time_point <std::chrono::utc_clock> now(); | (C++20 起)

返回表示当前时间的时间点。 如同以 std::chrono::utc_clock::from_sys(std::chrono::system_clock::now()) 计算结果。实现可以用更精确的 UTC 时间值。

参数

（无）

返回值

表示当前时间的时间点。

示例

#include <iostream>
#include <vector>
#include <numeric>
#include <chrono>

volatile int sink;
int main()
{
    for (auto size = 1ull; size < 1000000000ull; size *= 100) {
        // 记录开始时间
        auto start = std::chrono::utc_clock::now();
        // 做一些工作
        std::vector<int> v(size, 42);
        sink = std::accumulate(v.begin(), v.end(), 0u); // 确保其副效应
        // 记录结束时间
        auto end = std::chrono::utc_clock::now();
        std::chrono::duration<double> diff = end-start;
        std::cout << "Time to fill and iterate a vector of "
                  << size << " ints : " << diff.count() << " s\n";
    }
}

可能的输出：

Time to fill and iterate a vector of 1 ints : 2.43e-07 s
Time to fill and iterate a vector of 100 ints : 4.1e-07 s
Time to fill and iterate a vector of 10000 ints : 2.519e-05 s
Time to fill and iterate a vector of 1000000 ints : 0.00207669 s
Time to fill and iterate a vector of 100000000 ints : 0.423087 s


std::chrono::operator<<(std::chrono::utc_time)

< cpp‎ | chrono‎ | utc clock

定义于头文件 <chrono>
template <class CharT, class Traits, class Duration>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::utc_time<Duration>& tp);
 (C++20 起)

输出 tp 到流 os 中，如同用 os << std::format(STATICALLY_WIDEN<CharT>("{:L%F %T}"), tp) ，其中 STATICALLY_WIDEN<CharT>("{:L%F %T}") 若 CharT 为 char 则为 "{:L%F %T}" ，而若 CharT 为 wchar_t 则为 L"{:L%F %T}" 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

std::formatter<std::chrono::utc_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 utc_time (类模板特化)
format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)


std::chrono::utc_clock::to_sys

< cpp‎ | chrono‎ | utc clock
template <class Duration>

static std::chrono::sys_time< std::common_type_t <Duration, std::chrono::seconds >>

to_sys(const std::chrono::utc_time<Duration>& t);
 (C++20 起)

转换 utc_time t 为表示同一时间点的 sys_time （若可能）。

若 t 表示在闰秒插入期间的时间点，则返回先于插入闰秒的最后可表示 sys_time 值。所有其他情况下， utc_clock::from_sys(utc_clock::to_sys(t)) == t 。

返回值

与 t 表示同一时间点的 sys_time ，或若 t 表示在闰秒插入期间的时间点，则为先于插入闰秒的最后可表示值。

参阅

from_sys
[静态]
 转换 sys_time 为 utc_time
(公开静态成员函数)


std::chrono::weekday

< cpp‎ | chrono
定义于头文件 <chrono> |
class weekday; | (C++20 起)
inline constexpr std::chrono::weekday Sunday{0}; | (C++20 起)
inline constexpr std::chrono::weekday Monday{1}; | (C++20 起)
inline constexpr std::chrono::weekday Tuesday{2}; | (C++20 起)
inline constexpr std::chrono::weekday Wednesday{3}; | (C++20 起)
inline constexpr std::chrono::weekday Thursday{4}; | (C++20 起)
inline constexpr std::chrono::weekday Friday{5}; | (C++20 起)
inline constexpr std::chrono::weekday Saturday{6}; | (C++20 起)

类 weekday 表示格里高利历中的星期之日。其正常范围为 [0, 6] ，从星期日到星期六，但它能保有范围 [0, 255] 中的任何值。对星期的七日，于 std::chrono 命名空间中预定义七个具名常量。

weekday 是可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 weekday (公开成员函数)
operator++operator++(int)operator--operator--(int) | 自增或自减 weekday (公开成员函数)
operator+=operator-= | 加或减日数 (公开成员函数)
c_encodingiso_encoding | 取得存储的星期值日值 取得 ISO 8601 星期之日值 (公开成员函数)
ok | 检查存储的星期之日值是否合法 (公开成员函数)
operator[] | 从此 weekday 构造 weekday_indexed 或 weekday_last 的便利语法 (公开成员函数)

非成员函数

operator== (C++20) | 比较二个 weekday 值 (函数)
operator+operator- (C++20) | 在 weekday 上进行算术 (函数)
operator<< (C++20) | 输出 weekday 到流中 (函数模板)
from_stream (C++20) | 按照提供的格式从流分析 weekday (函数模板)

辅助类

std::formatter<std::chrono::weekday>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 weekday
(类模板特化)


std::chrono::weekday::c_encoding, std::chrono::weekday::iso_encoding

< cpp‎ | chrono‎ | weekday
constexpr unsigned c_encoding() const noexcept; | (1) | (C++20 起)
constexpr unsigned iso_encoding() const noexcept; | (2) | (C++20 起)
1) 返回存储于 *this 的星期之日值。
1) 返回存储于 *this 的星期之日值，除了按照 ISO 8601 转译星期日（存储为 ​0​ ）为 7 。

返回值

1) 存储于 *this 的星期之日值。
2) c_encoding() == 0u ? 7u : c_encoding() 。


std::chrono::weekday::ok

< cpp‎ | chrono‎ | weekday
constexpr bool ok() const noexcept; | (C++20 起)

检查存储于 *this 的星期之日值是否在合法范围，即 [0, 6] 中。

返回值

若存储于 *this 的星期之日值在范围 [0, 6] 中则为 true 。否则为 false 。


std::chrono::weekday::operator+=, std::chrono::weekday::operator-=

< cpp‎ | chrono‎ | weekday
constexpr std::chrono::weekday& operator+=(const std::chrono::days& d) noexcept; | (1) | (C++20 起)
constexpr std::chrono::weekday& operator-=(const std::chrono::days& d) noexcept; | (2) | (C++20 起)

对星期之日值加或减 d.count() ，将结果对 7 取余，规约成范围 [0, 6] 中的整数。

1) 进行 *this = *this + d;
2) 进行 *this = *this - d;

返回值

到修改后的此 weekday 的引用。

注意

调用这些函数之一后，若运算中不出现溢出，则 ok() 始终为 true 。

示例

#include <iostream>
#include <chrono>

int main()
{
    std::cout << std::boolalpha;

    std::chrono::weekday wd {5}; // Friday is 5
    wd += std::chrono::days(2);
    std::cout << (wd == std::chrono::weekday(0)) << ' '
              << (wd == std::chrono::Sunday) << ' ';

    wd -= std::chrono::days(3);
    std::cout << (wd == std::chrono::weekday(4)) << ' '
              << (wd == std::chrono::Thursday) << ' ';

    wd = std::chrono::Wednesday;
    wd += std::chrono::days{8}; // ((3 += 8 == 11) % 7) == 4;
    std::cout << (wd == std::chrono::Thursday) << ' ';

    wd -= (std::chrono::Sunday - std::chrono::Tuesday); // -= -2
    // (4 -= -2) == 6
    std::cout << (wd == std::chrono::Saturday) << '\n';
}

输出：

true true true true true true

参阅

operator++operator++(int)operator--operator--(int) | 自增或自减 weekday (公开成员函数)
operator+operator- (C++20) | 在 weekday 上进行算术 (函数)


std::chrono::operator+, std::chrono::operator- (std::chrono::weekday)

< cpp‎ | chrono‎ | weekday
constexpr std::chrono::weekday operator+(const std::chrono::weekday& wd,
const std::chrono::days& d) noexcept;
 (1) (C++20 起)
constexpr std::chrono::weekday operator+(const std::chrono::days& d,
const std::chrono::weekday& wd) noexcept;
 (2) (C++20 起)
constexpr std::chrono::weekday operator-(const std::chrono::weekday& wd,
const std::chrono::days& d) noexcept;
 (3) (C++20 起)
constexpr std::chrono::days operator-(const std::chrono::weekday& wd1,
const std::chrono::weekday& wd2) noexcept;
 (4) (C++20 起)
1-2) 向 wd 加上 d.count() 日。通过首先求值 static_cast<long long>(wd.c_encoding()) + d.count() 再将它对 7 取余，得到范围 [0, 6] 中的整数，计算结果中保有的星期之日值。
3) 从 wd 减去 d.count() 日。等价于 return wd + -d; 。
4) 若 wd1.ok() 与 wd2.ok() 均为 true ，则返回 std::chrono::days 值 d ，满足 d.count() 在范围 [0, 6] 中且 wd2 + d == wd1 。否则返回值未指定。

返回值

1-3) 保有按上述方式计算的星期之日值的 std::chrono::weekday 。
4) 表示 wd1 与 wd2 间距离的 std::chrono::days 。

注意

只要计算不溢出， (1-3) 就始终返回合法的 weekday ，即使 wd.ok() 为 false 。

示例

#include <iostream>
#include <chrono>

int main()
{
    std::cout << std::boolalpha;

    std::chrono::weekday wd {4};
    wd = wd + std::chrono::days(2);
    std::cout << (wd == std::chrono::weekday(6)) << ' '
              << (wd == std::chrono::Saturday) << ' ';

    wd = wd - std::chrono::days(3);
    std::cout << (wd == std::chrono::weekday(3)) << ' '
              << (wd == std::chrono::Wednesday) << ' ';

    wd = std::chrono::Tuesday;
    wd = wd + std::chrono::days{8}; // (((2 + 8) == 10) % 7) == 3;
    std::cout << (wd == std::chrono::Wednesday) << ' ';

    wd = wd + (std::chrono::Sunday - std::chrono::Thursday); // (3 + 3) == 6
    std::cout << (wd == std::chrono::Saturday) << '\n';
}

输出：

true true true true true true

参阅

operator++operator++(int)operator--operator--(int) | 自增或自减 weekday (公开成员函数)
operator+=operator-= | 加或减日数 (公开成员函数)


std::chrono::weekday::operator[]

< cpp‎ | chrono‎ | weekday
constexpr std::chrono::weekday_indexed operator[](unsigned index) const noexcept; | (1) | (C++20 起)
constexpr std::chrono::weekday_last operator[](std::chrono::last_spec) const noexcept; | (2) | (C++20 起)
1) 从 *this 和 index 构造 weekday_indexed 。结果表示在某个待指定月份中的第 index 个星期之日。若 index 不在范围 [1, 5] 中或若 !ok() ，则结果中保有的值未指定。
2) 从 *this 构造 weekday_last 。结果表示某个待指定月份中的最后一个星期之日。

返回值

1) std::chrono::weekday_indexed(*this, index)
2) std::chrono::weekday_last(*this)

示例

#include <chrono>
#include <iostream>

int main()
{
  using namespace std::chrono;
  // 2019 年十月中的第二个星期二
  std::cout << year_month_day{ Tuesday[2] / October / 2019y } << '\n'
  // 2019 年十月中的最后一个星期二
            << year_month_day{ Tuesday[last] / October / 2019y } << '\n';
}

输出：

2019-10-08
2019-10-29


std::chrono::operator==(std::chrono::weekday)

< cpp‎ | chrono‎ | weekday
定义于头文件 <chrono>
constexpr bool operator==( const std::chrono::weekday& x,
const std::chrono::weekday& y ) noexcept;
 (C++20 起)

比较二个 std::chrono::weekday x 和 y 。

!= 运算符从 operator== 合成。

返回值

x.c_encoding() == y.c_encoding()

注解

weekday 不支持 < 、 <= 、 > 和 >= 运算符，因为在哪天是星期的首日上没有普遍的共识。

示例

#include <iostream>
#include <chrono>

int main()
{
    using namespace std::literals;

    constexpr std::chrono::weekday wd1{2};
    constexpr std::chrono::weekday wd2{std::chrono::Friday};
    // 2021 年 1 月 1 日是星期五
    constexpr std::chrono::weekday wd3{2021y/1/1};

    std::cout << std::boolalpha;
    std::cout << (wd1 == wd2) << "\n";
    std::cout << (wd2 == wd3) << "\n";
}

输出：

false
true


std::chrono::weekday::operator++, std::chrono::weekday::operator--

< cpp‎ | chrono‎ | weekday
constexpr std::chrono::weekday& operator++() noexcept; | (1) | (C++20 起)
constexpr std::chrono::weekday operator++(int) noexcept; | (2) | (C++20 起)
constexpr std::chrono::weekday& operator--() noexcept; | (3) | (C++20 起)
constexpr std::chrono::weekday operator--(int) noexcept; | (4) | (C++20 起)

对星期之日值加或减 1 ，将结果对 7 取余，规约成范围 [0, 6] 中的整数。

1-2) 进行 *this += std::chrono::days{1};
3-4) 进行 *this -= std::chrono::days{1};

参数

（无）

返回值

1,3) 到修改后的此 weekday 的引用。
2,4) 修改前所作的 weekday 的副本。

注意

调用这些函数之一后， ok() 始终为 true 。

示例

#include <iostream>
#include <chrono>

int main()
{
    std::cout << std::boolalpha;

    std::chrono::weekday wd {0}; // Sunday is 0 or 7

    --wd;
    std::cout << (wd == std::chrono::Saturday) << ' ';

    ++wd;
    std::cout << (wd == std::chrono::Sunday) << '\n';
}

输出：

true true

参阅

operator+=operator-= | 加或减日数 (公开成员函数)
operator+operator- (C++20) | 在 weekday 上进行算术 (函数)


std::chrono::operator<<(std::chrono::weekday)

< cpp‎ | chrono‎ | weekday
定义于头文件 <chrono>
template< class CharT, class Traits >

std::basic_ostream <CharT, Traits>&

operator<<( std::basic_ostream <CharT, Traits>& os, const std::chrono::weekday& wd );
 (C++20 起)

若 !wd.ok() 则插入 wd.c_encoding() 后随 " is not a valid weekday" 到 os 中。否则构成用与 os 关联的本地环境确定，由 wd 所表示的星期之日的缩写星期之日名组成的 std::basic_string<CharT> s ，并插入 s 到 os 中。

等价于

return os << (wd.ok() ?
std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{:L%a}"), wd) :
std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{} is not a valid weekday"),
wd.c_encoding()));

其中 STATICALLY_WIDEN<CharT>("...") 若 CharT 为 char 则为 "..." ，而若 CharT 为 wchar_t 则为 L"..." 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::weekday> (C++20) | std::formatter 的特化，按照提供的格式格式化 weekday (类模板特化)


std::chrono::weekday::weekday

< cpp‎ | chrono‎ | weekday
weekday() = default; | (1) | (C++20 起)
explicit constexpr weekday(unsigned wd) noexcept; | (2) | (C++20 起)
constexpr weekday(const std::chrono::sys_days& dp) noexcept; | (3) | (C++20 起)
explicit constexpr weekday(const std::chrono::local_days& dp) noexcept; | (4) | (C++20 起)

构造 weekday 对象。

1) 默认构造函数保留星期之日值未初始化。
2) 构造保有星期之日值 wd 的 weekday 对象。若 wd == 7 ，则保有的值为 ​0​ 。若 wd > 255 ，则保有的值未指定。
3) 构造表示 dp 所对应星期之日的 weekday 。此构造函数定义从 std::chrono::sys_days 到 weekday 的隐式转换。
4) 构造表示 dp 所对应星期之日的 weekday ，如同用 weekday(std::chrono::sys_days(dp.time_since_epoch())) 。


std::chrono::weekday_indexed

< cpp‎ | chrono
定义于头文件 <chrono> |
class weekday_indexed; | (C++20 起)

类 weekday_indexed 把表示格里高利历中星期之日的 weekday ，与范围 [1, 5] 中的小下标 n 结合。它表示某个月中的第一、第二、第三、第四或第五个星期之日。

weekday_indexed 是可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 weekday_indexed (公开成员函数)
weekday | 访问存储的 weekday (公开成员函数)
index | 访问存储的下标 (公开成员函数)
ok | 检查星期之日和下标是否均合法 (公开成员函数)

非成员函数

operator== (C++20) | 比较二个 weekday_indexed 值 (函数)
operator<< (C++20) | 输出 weekday_indexed 到流中 (函数模板)

辅助类

std::formatter<std::chrono::weekday_indexed>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 weekday_indexed
(类模板特化)


std::chrono::weekday_indexed::index

< cpp‎ | chrono‎ | weekday indexed
constexpr unsigned index() const noexcept; | (C++20 起)

访问存储于 *this 的下标。

返回值

存储于 *this 的下标。


std::chrono::weekday_indexed::ok

< cpp‎ | chrono‎ | weekday indexed
constexpr bool ok() const noexcept; | (C++20 起)

检查存储于 *this 的 weekday 对象和下标是否均合法。

返回值

若 weekday().ok() == true 且 index() 在范围 [1, 5] 中则为 true 。否则为 false 。


std::chrono::operator==(std::chrono::weekday_indexed)

< cpp‎ | chrono‎ | weekday indexed
定义于头文件 <chrono>
constexpr bool operator==(const std::chrono::weekday_indexed& x,
const std::chrono::weekday_indexed& y) noexcept;
 (C++20 起)

比较二个 weekday_indexed x 与 y 。

!= 运算符从 operator== 合成。

返回值

x.weekday() == y.weekday() && x.index() == y.index()

示例

#include <iostream>
#include <chrono>

int main()
{
    constexpr auto wdi1 {std::chrono::Tuesday[2]};
    constexpr std::chrono::weekday_indexed wdi2 {std::chrono::weekday(2), 2};
    std::cout << std::boolalpha << (wdi1 == wdi2) << '\n';
}

输出：

true


std::chrono::operator<<(std::chrono::weekday_indexed)

< cpp‎ | chrono‎ | weekday indexed
定义于头文件 <chrono>
template <class CharT, class Traits>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::weekday_indexed& wdi );
 (C++20 起)

输出 wdi 的文本表示到流 os 中，如同用：

if (wdi.index() >=1 && wdi.index() <= 5) {
os << std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{:L}[{}]"),
wdi.weekday(), wdi.index());
} else {
os << std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{:L}[{} is not a valid index]"),
wdi.weekday(), wdi.index());
}

其中 STATICALLY_WIDEN<CharT>("...") 若 CharT 为 char 则为 "..." ，而若 CharT 为 wchar_t 则为 L"..." 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::weekday> (C++20) | std::formatter 的特化，按照提供的格式格式化 weekday (类模板特化)


std::chrono::weekday_indexed::weekday

< cpp‎ | chrono‎ | weekday indexed
constexpr std::chrono::weekday weekday() const noexcept; | (C++20 起)

取得存储于 *this 的 std::chrono::weekday 对象副本。

返回值

存储于 *this 的 std::chrono::weekday 对象副本。


std::chrono::weekday_indexed::weekday_indexed

< cpp‎ | chrono‎ | weekday indexed
weekday_indexed() = default; | (C++20 起)
constexpr weekday_indexed(const std::chrono::weekday& wd, unsigned index) noexcept; | (C++20 起)

构造 weekday_indexed 。

1) 默认构造函数保留 std::chrono::weekday 和下标值未初始化。
2) 构造存储星期之日 wd 和下标 index 的 weekday_indexed 。若 !wd.ok() || index > 7 则保有的值未指定。

注解

更方便的构造 weekday_indexed 的方式是用 weekday 的 operator[] ，即 wd[index] 。

示例

#include <chrono>
#include <iostream>

int main()
{
  using namespace std::chrono;
  auto wdi = Tuesday[2]; // wdi 是表示第 2 个星期二的 weekday_indexed
  std::cout << year_month_day{ wdi / October / 2019y } ;
}

输出：

2019-10-08

参阅

operator[]
 从此 weekday 构造 weekday_indexed 或 weekday_last 的便利语法
(std::chrono::weekday 的公开成员函数)


std::chrono::weekday_last

< cpp‎ | chrono
定义于头文件 <chrono> |
class weekday_last; | (C++20 起)

类 weekday_last 表示某月的最后一个星期之日。

weekday_last 是可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 weekday_last 对象 (公开成员函数)
weekday | 访问存储的 weekday (公开成员函数)
ok | 检查存储的 weekday 是否合法 (公开成员函数)

非成员函数

operator== (C++20) | 比较二个 weekday_last 值 (函数)
operator<< (C++20) | 输出 weekday_last 到流中 (函数模板)

辅助类

std::formatter<std::chrono::weekday_last>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 weekday_last
(类模板特化)


std::chrono::weekday_last::ok

< cpp‎ | chrono‎ | weekday last
constexpr bool ok() const noexcept; | (C++20 起)

检查存储于 *this 的 weekday 对象是否合法。

返回值

weekday().ok()


std::chrono::operator==(std::chrono::weekday_last)

< cpp‎ | chrono‎ | weekday last
定义于头文件 <chrono>
constexpr bool operator==(const std::chrono::weekday_last& x,
const std::chrono::weekday_last& y) noexcept;
 (C++20 起)

比较二个 weekday_last 值 x 与 y 。

!= 运算符从 operator== 合成。

返回值

x.weekday() == y.weekday()

示例

#include <iostream>
#include <chrono>

int main()
{
    constexpr auto wdl1 {std::chrono::Tuesday[std::chrono::last]};
    constexpr std::chrono::weekday_last wdl2 {std::chrono::weekday(2)};
    std::cout << std::boolalpha
              << (wdl1 == wdl2) << ' '
              << (wdl1 == std::chrono::Wednesday[std::chrono::last]) << '\n';
}

输出：

true false


std::chrono::operator<<(std::chrono::weekday_last)

< cpp‎ | chrono‎ | weekday last
定义于头文件 <chrono>
template< class CharT, class Traits >

std::basic_ostream <CharT, Traits>&

operator<<( std::basic_ostream <CharT, Traits>& os, const std::chrono::weekday_last& wdl );
 (C++20 起)

输出 wdl 的文本表示到流 os 中，如同用

os << std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{:L}[last]"), wdl.weekday());

其中 STATICALLY_WIDEN<CharT>("{:L}[last]") 若 CharT 为 char 则为 "{:L}[last]" ，而若 CharT 为 wchar_t 则为 L"{:L}[last]" 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::weekday> (C++20) | std::formatter 的特化，按照提供的格式格式化 weekday (类模板特化)


std::chrono::weekday_last::weekday

< cpp‎ | chrono‎ | weekday last
constexpr std::chrono::weekday weekday() const noexcept; | (C++20 起)

取得存储于 *this 的 std::chrono::weekday 对象副本。

返回值

存储于 *this 的 std::chrono::weekday 对象副本。


std::chrono::weekday_last::weekday_last

< cpp‎ | chrono‎ | weekday last
explicit constexpr weekday_last(const chrono::weekday& wd) noexcept; | (C++20 起)

构造存储 weekday wd 的 weekday_last 对象。

注意

更方便的构造 weekday_last 的方法是用 weekday 的 operator[] ，即 wd[std::chrono::last] 。


std::chrono::year

< cpp‎ | chrono
定义于头文件 <chrono> |
class year; | (C++20 起)

类 year 表示外推格里高利历中的年份。其范围是 [-32767, 32767] 。

year 是可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 year (公开成员函数)
operator++operator++(int)operator--operator--(int) | 自增或自减 year (公开成员函数)
operator+=operator-= | 从 year 加上或减去年数 (公开成员函数)
operator+operator- | 应用一元运算符到 year (公开成员函数)
is_leap | 确定该年是否为闰年 (公开成员函数)
operator int | 取得年份值 (公开成员函数)
ok | 检查存储的年份值是否合法 (公开成员函数)
min [静态] | 返回最小的可能的 year 值 (公开静态成员函数)
max [静态] | 返回最大的可能的 year (公开静态成员函数)

非成员函数

operator==operator<=> (C++20) | 比较二个 year 值 (函数)
operator+operator- (C++20) | 进行 year 上的算术 (函数)
operator<< (C++20) | 输出 year 到流 (函数模板)
from_stream (C++20) | 按照提供的格式从流分析 year (函数模板)

辅助类

std::formatter<std::chrono::year>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 year
(类模板特化)

字面量

定义于内联命名空间 std::literals::chrono_literals
operator""y
(C++20)
 表示特定年的 std::chrono::year 字面量
(函数)


std::chrono::year::is_leap

< cpp‎ | chrono‎ | year
constexpr bool is_leap() const noexcept; | (C++20 起)

确定 *this 是否表示外推格里高利历中的闰年。

若存储的年份值满足下列条件则 *this 表示闰年

  • 被 4 整除且不被 100 整除；或
  • 被 400 整除。

返回值

若 *this 表示闰年则为 true ，否则为 false 。

示例

#include <iostream>
#include <chrono>

int main()
{
    using namespace std::chrono_literals;
    for (const std::chrono::year y : {2020y, 2021y, 2000y, 3000y}) {
        if (const int iy{ static_cast<int>(y) }; y.is_leap()) {
            std::cout << iy << " is a leap year because it is divisible by "
                      << (iy % 400 == 0 ? "400\n" : "4 and not divisible by 100\n");
        } else {
            std::cout << iy << " is not a leap year\n";
        }
    }
}

输出：

2020 is a leap year because it is divisible by 4 and not divisible by 100
2021 is not a leap year
2000 is a leap year because it is divisible by 400
3000 is not a leap year


std::chrono::year::max

< cpp‎ | chrono‎ | year
static constexpr year max() noexcept; | (C++20 起)

返回最大的可能的 year ，即 std::chrono::year(32767) 。

返回值

std::chrono::year(32767)


std::chrono::year::min

< cpp‎ | chrono‎ | year
static constexpr std::chrono::year min() noexcept; | (C++20 起)

返回最小的可能的 year ，即 std::chrono::year(-32767) 。

返回值

std::chrono::year(-32767)


std::chrono::year::ok

< cpp‎ | chrono‎ | year
constexpr bool ok() const noexcept; | (C++20 起)

检查存储于 *this 的年份值是否在合法范围，即 [-32767, 32767] 中。

返回值

若存储于 *this 的年份值在范围 [-32767, 32767] 中则为 true 。否则为 false 。


std::chrono::year::operator+=, std::chrono::year::operator-=

< cpp‎ | chrono‎ | year
constexpr std::chrono::year& operator+=(const std::chrono::years& y) noexcept; | (1) | (C++20 起)
constexpr std::chrono::year& operator-=(const std::chrono::years& y) noexcept; | (2) | (C++20 起)

从年份值加或减 y.count() 年。

1) 等价于 *this = *this + y;
2) 等价于 *this = *this - y;

返回值

到修改后的此 year 的引用。

注意

若结果会在范围 [-32767, 32767] 外，则实际存储值未指定。

示例

本节未完成
原因：暂无示例

参阅

operator++operator++(int)operator--operator--(int) | 自增或自减 year (公开成员函数)
operator+operator- (C++20) | 进行 year 上的算术 (函数)


std::chrono::operator+, std::chrono::operator- (std::chrono::year)

< cpp‎ | chrono‎ | year
定义于头文件 <chrono>
constexpr std::chrono::year operator+(const std::chrono::year& y,
const std::chrono::years& ys) noexcept;
 (1) (C++20 起)
constexpr std::chrono::year operator+(const std::chrono::years& ys,
const std::chrono::year& y) noexcept;
 (2) (C++20 起)
constexpr std::chrono::year operator-(const std::chrono::year& y,
const std::chrono::years& ys) noexcept;
 (3) (C++20 起)
constexpr std::chrono::years operator-(const std::chrono::year& y1,
const std::chrono::year& y2) noexcept;
 (4) (C++20 起)
1-2) 对 y 加 ys.count() 年。
3) 从 y 减去 ys.count() 年。
4) 返回 y1 与 y2 间按年计算的差。

返回值

1-2) std::chrono::year(int(y) + ys.count())
3) std::chrono::year(int(y) - ys.count())
4) std::chrono::years(int(y1) - int(y2))

注解

若 (1-3) 产生的年份值在范围 [-32767,32767] 外，则实际存储值未指定。

二个 year 值相减的结果是 std::chrono::years 类型时长。此时长单位表示格里高利年的平均长度，而结果与运算数所表示的具体年中的日数无关。例如 2018y - 2017y 的结果是 std::chrono::years(1) ，它表示 365.2425 日，而非 365 日。

示例

#include <iostream>
#include <chrono>

int main()
{

    std::chrono::year y {2020};

    y = y + std::chrono::years(12);
    if (y == std::chrono::year(2032)) {
        std::cout << "Years added correctly" << "\n";
    } else {
        std::cout << "Years not added correctly" << "\n";
    }

    y = y - std::chrono::years(33);
    if (y == std::chrono::year(1999)) {
        std::cout << "Years subtracted correctly" << "\n";
    } else {
        std::cout << "Years not subtracted correctly" << "\n";
    }

    std::chrono::years ys = std::chrono::year(2025) - std::chrono::year(2020);
    if (ys == std::chrono::years(5)) {
        std::cout << "Years subtracted correctly" << "\n";
    } else {
        std::cout << "Years not subtracted correctly" << "\n";
    }

}

输出：

Years added correctly
Years subtracted correctly
Years subtracted correctly

返回值

operator++operator++(int)operator--operator--(int) | 自增或自减 month (std::chrono::month 的公开成员函数)
operator+=operator-= | 加或减月数 (std::chrono::month 的公开成员函数)


std::chrono::operator==,<=>(std::chrono::year)

< cpp‎ | chrono‎ | year
定义于头文件 <chrono>
constexpr bool operator==( const std::chrono::year& x,
const std::chrono::year& y ) noexcept;
 (1) (C++20 起)
constexpr std::strong_ordering operator<=>( const std::chrono::year& x,
const std::chrono::year& y ) noexcept;
 (2) (C++20 起)

比较二个 std::chrono::year x 与 y 。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

返回值

1) int(x) == int(y)
2) int(x) <=> int(y)

示例

#include <iostream>
#include <chrono>

int main()
{
    using namespace std::chrono;

    constexpr year y1{2020};
    constexpr year y2{2021};

    if (y1 == y2) {
        std::cout << "y1 and y2 are equal\n";
    } else {
        std::cout << "y1 and y2 are not equal\n";
    }

    static_assert(
        (2020y < 2023y) && (2020y == 2020y) && (2020y <= 2023y) &&
        (2023y > 2020y) && (2023y != 2020y) && (2023y >= 2020y)
    );
}

输出：

y1 and y2 are not equal


std::chrono::year::operator++, std::chrono::year::operator--

< cpp‎ | chrono‎ | year
constexpr std::chrono::year& operator++() noexcept; | (1) | (C++20 起)
constexpr std::chrono::year operator++(int) noexcept; | (2) | (C++20 起)
constexpr std::chrono::year& operator--() noexcept; | (3) | (C++20 起)
constexpr std::chrono::year operator--(int) noexcept; | (4) | (C++20 起)

从年份值加或减 1 。

1-2) 进行 *this += std::chrono::years{1};
3-4) 进行 *this -= std::chrono::years{1};

参数

（无）

返回值

1,3) 到修改后的此 year 的引用。
2,4) 修改前所作的 year 的副本。

注意

若结果会在范围 [-32767, 32767] 外，则实际存储值未指定。

示例

本节未完成
原因：暂无示例

参阅

operator+=operator-= | 从 year 加上或减去年数 (公开成员函数)
operator+operator- (C++20) | 进行 year 上的算术 (函数)


std::chrono::year::operator int

< cpp‎ | chrono‎ | year
explicit constexpr operator int() const noexcept; | (C++20 起)

返回 *this 中存储的年份值。

返回值

*this 中存储的年份值。


std::chrono::operator<<(std::chrono::year)

< cpp‎ | chrono‎ | year
template <class CharT, class Traits>

std::basic_ostream <CharT, Traits>&

operator<<( std::basic_ostream <CharT, Traits>& os, const std::chrono::year& y);
 (C++20 起)

构成由格式化为十进制数的存储于 y 的年值，若结果会少于四位则左填充 0 到四位组成的 std::basic_string<CharT> s 。然后若 !y.ok() 则后附 " is not a valid year" 到格式化的字符串。插入该字符串到 os 中。

等价于

return os << (y.ok() ?
std::format(STATICALLY_WIDEN<CharT>("{:%Y}"), y) :
std::format(STATICALLY_WIDEN<CharT>("{:%Y} is not a valid year"), y));

其中 STATICALLY_WIDEN<CharT>("...") 若 CharT 为 char 则为 "..." ，而若 CharT 为 wchar_t 则为 L"..." 。

返回值

os 。

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::year> (C++20) | std::formatter 的特化，按照提供的格式格式化 year (类模板特化)


std::chrono::year::operator+, std::chrono::year::operator-

< cpp‎ | chrono‎ | year
constexpr std::chrono::year operator+() noexcept; | (1) | (C++20 起)
constexpr std::chrono::year operator-() noexcept; | (2) | (C++20 起)

应用一元运算符到年份值。

1) 返回 *this 的副本。
2) 返回年份值为 *this 的年份值相反数的 year 。

返回值

1) *this
2) std::chrono::year(-int(*this))

示例

本节未完成
原因：暂无示例


std::chrono::year::year

< cpp‎ | chrono‎ | year
year() = default; | (C++20 起)
explicit constexpr year(int y) noexcept; | (C++20 起)

构造 year 对象。

1) 默认构造函数保留年份值未初始化。
2) 若 y 在范围 [-32767, 32767] 中，则构造保有年份值 y 的 year 对象。否则保有值未指定。


std::chrono::year_month

< cpp‎ | chrono
定义于头文件 <chrono> |
class year_month; | (C++20 起)

类 year_month 表示特定年的特定月，但不指定日。它是基于域的时间点，解析为 std::chrono::months 。

year_month 是可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 year_month (公开成员函数)
yearmonth | 访问存储的 year 和 month (公开成员函数)
operator+=operator-= | 以一定量的月和年为程度修改 year_month (公开成员函数)
ok | 检查此 year_month 是否合法 (公开成员函数)

非成员函数

operator==operator<=> (C++20) | 比较二个 year_month 值 (函数)
operator+operator- (C++20) | 进行 year_month 上的算术 (函数)
operator<< (C++20) | 输出 year_month 到流中 (函数模板)
from_stream (C++20) | 按照提供的格式从流分析 year_month (函数模板)

辅助类

std::formatter<std::chrono::year_month>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 year_month
(类模板特化)


std::chrono::year_month::year, std::chrono::year_month::month

< cpp‎ | chrono‎ | year month
constexpr std::chrono::year year() const noexcept; | (1) | (C++20 起)
constexpr std::chrono::month month() const noexcept; | (2) | (C++20 起)

取得存储于此 year_month 对象的 year 和 month 值。

返回值

1) 返回存储的 std::chrono::year 值。
2) 返回存储的 std::chrono::month 值。

示例

#include <iostream>
#include <chrono>

int main()
{
    std::cout << std::boolalpha;

    constexpr auto ym {std::chrono::year(2021)/std::chrono::July};
    std::cout << (ym.year() == std::chrono::year(2021)) << ' ';
    std::cout << (ym.month() == std::chrono::month(7)) << '\n';

}

输出：

true true


std::chrono::year_month::ok

< cpp‎ | chrono‎ | year month
constexpr bool ok() const noexcept; | (C++20 起)

检查存储于此对象的 year 和 month 值是否均合法。

返回值

year().ok() && month().ok()


std::chrono::year_month::operator+=, std::chrono::year_month::operator-=

< cpp‎ | chrono‎ | year month

constexpr std::chrono::year_month& operator+=(const std::chrono::years& dy) const noexcept; | (1) | (C++20 起)
constexpr std::chrono::year_month& operator+=(const std::chrono::months& dm) const noexcept; | (2) | (C++20 起)
constexpr std::chrono::year_month& operator-=(const std::chrono::years& dy) const noexcept; | (3) | (C++20 起)
constexpr std::chrono::year_month& operator-=(const std::chrono::months& dm) const noexcept; | (4) | (C++20 起)

以时长 dy 或 dm 为程度修改时间点 *this 。

1) 等价于 *this = *this + dy;
2) 等价于 *this = *this + dm;
3) 等价于 *this = *this - dy;
4) 等价于 *this = *this - dm;

对于能转换到 std::chrono::years 与 std::chrono::months 两者的时长，若调用有歧义，则偏好 years 重载 (1,3) 。

参阅

operator+operator-
(C++20)
 进行 year_month 上的算术
(函数)


std::chrono::operator+, std::chrono::operator- (std::chrono::year_month)

< cpp‎ | chrono‎ | year month
constexpr std::chrono::year_month operator+(const std::chrono::year_month& ym,
const std::chrono::years& dy) noexcept;
 (1) (C++20 起)
constexpr std::chrono::year_month operator+(const std::chrono::years& dy,
const std::chrono::year_month& ym) noexcept;
 (2) (C++20 起)
constexpr std::chrono::year_month operator+(const std::chrono::year_month& ym,
const std::chrono::months& dm) noexcept;
 (3) (C++20 起)
constexpr std::chrono::year_month operator+(const std::chrono::months& dm,
const std::chrono::year_month& ym) noexcept;
 (4) (C++20 起)
constexpr std::chrono::year_month operator-(const std::chrono::year_month& ym,
const std::chrono::years& dy) noexcept;
 (5) (C++20 起)
constexpr std::chrono::year_month operator-(const std::chrono::year_month& ym,
const std::chrono::months& dm) noexcept;
 (6) (C++20 起)
constexpr std::chrono::months operator-(const std::chrono::year_month& ym1,
const std::chrono::year_month& ym2) noexcept;
 (7) (C++20 起)
1-2) 加上 dy.count() 年到 ym 。
3-4) 加上 dm.count() 月到 ym 。
5) 从 ym 减去 dy.count() 年。
6) 从 ym 减去 dm.count() 月。
7) 返回 ym1 与 ym2 所表示的二个时间点间以 months 计量的差。

对于能转换到 std::chrono::years 与 std::chrono::months 两者的时长，若调用有歧义，则偏好 years 重载 (1,2,5) 。

返回值

1-2) std::chrono::year_month(ym.year() + dy, ym.month())
3-4) A year_month value z such that z - ym == dm
5) ym + -dy
6) ym + -dm
7) ym1.year() - ym2.year() + std::chrono::months(int(unsigned(ym1.month())) - int(unsigned(ym2.month())))

注解

二个 year_month 值相减的结果是 std::chrono::months 类型时长。此时长单位表示格里高利月的平均长度（ 30.436875 日），而产生的时长与问题中的实际日数无关。例如 2017y/3 - 2017y/2 的结果是 std::chrono::months(1) ，即使 2017 年二月只含 28 日。

示例

本节未完成
原因：暂无示例

参阅

operator+=operator-=
 以一定量的月和年为程度修改 year_month
(公开成员函数)


std::chrono::operator==,<=>(std::chrono::year_month)

< cpp‎ | chrono‎ | year month
定义于头文件 <chrono>
constexpr bool operator==( const std::chrono::year_month& x,
const std::chrono::year_month& y ) noexcept;
 (1) (C++20 起)
constexpr std::strong_ordering operator<=>( const std::chrono::year_month& x,
const std::chrono::year_month& y ) noexcept;
 (2) (C++20 起)

比较二个 year_month 值 x 与 y 。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

返回值

1) x.year() == y.year() && x.month() == y.month()
2) x.year() <=> y.year() != 0 ? x.year() <=> y.year() : x.month() <=> y.month()

示例

#include <iostream>
#include <chrono>

int main()
{
    using namespace std::chrono;

    constexpr year_month ym1 {year(2021), month(7)};
    constexpr year_month ym2 {year(2021)/7};

    std::cout << std::boolalpha << (ym1 == ym2) << '\n';

    static_assert(
        (2020y/1 < 2020y/2) && (2020y/2 == 2020y/2) && (2020y/3 <= 2021y/3)
     && (2023y/1 > 2020y/2) && (3020y/2 != 2020y/2) && (2020y/3 >= 2020y/3)
    );
}

输出：

true


std::chrono::operator<<(std::chrono::year_month)

< cpp‎ | chrono‎ | year month
定义于头文件 <chrono>
template< class CharT, class Traits >

std::basic_ostream <CharT, Traits>&

operator<<( std::basic_ostream <CharT, Traits>& os, const std::chrono::year_month& ym );
 (C++20 起)

输出 ym 的文本表示到流 os 中，如同用

os << std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{}/{:L}"), ym.year(), ym.month())

其中 STATICALLY_WIDEN<CharT>("{}/{:L}") 若 CharT 为 char 则为 "{}/{:L}" ，而若 CharT 为 wchar_t 则为 L"{}/{:L}" 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::year_month> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month (类模板特化)


std::chrono::year_month::year_month

< cpp‎ | chrono‎ | year month
year_month() = default; | (1) | (C++20 起)
constexpr year_month(const std::chrono::year& y, const std::chrono::month& m) noexcept; | (2) | (C++20 起)

构造 year_month 对象。

1) 默认构造函数保留年与月未初始化。
2) 构造存储 year y 和 month m 的 year_month 对象。

注意

构造 year_month 的更方便的方式是用 operator/ ，例如 2007y/std::chrono::April 。

参阅

operator/
(C++20)
 创建格里高利历日期的约定语法
(函数)


std::chrono::year_month_day

< cpp‎ | chrono
定义于头文件 <chrono> |
class year_month_day; | (C++20 起)

类 year_month_day 表示为特定的年月日。它是基于域的时间点，其解析为 std::chrono::days 。它直接支持面向 std::chrono::years 与 std::chrono::months 的算术。与 std::chrono::sys_days 间的双向隐式转换等效地允许进行面向 std::chrono::days 的算术。

year_month_day 是可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 year_month_day (公开成员函数)
operator+=operator-= | 以一定量的 months 或 years 为程度修改时间点 (公开成员函数)
yearmonthday | 访问此对象中存储的 year 、 month 和 day (公开成员函数)
operator sys_daysoperator local_days | 转换到 std::chrono::time_point (公开成员函数)
ok | 检查 year_month_day 是否表示合法的日期 (公开成员函数)

非成员函数

operator==operator<=> (C++20) | 比较二个 year_month_day 值 (函数)
operator+operator- (C++20) | 将 year_month_day 与一定量的年数或月数相加或相减 (函数)
operator<< (C++20) | 输出 year_month_day 到流中 (函数模板)
from_stream (C++20) | 按照给定的格式从流分析 year_month_day (函数模板)

辅助类

std::formatter<std::chrono::year_month_day>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 year_month_day
(类模板特化)


std::chrono::year_month_day::year, std::chrono::year_month_day::month, std::chrono::year_month_day::day

< cpp‎ | chrono‎ | year month day
constexpr std::chrono::year year() const noexcept; | (1) | (C++20 起)
constexpr std::chrono::month month() const noexcept; | (2) | (C++20 起)
constexpr std::chrono::day day() const noexcept; | (3) | (C++20 起)

取得存储于此 year_month_day 对象的 year 、 month 和 day 值。

返回值

1) 返回存储的 std::chrono::year 值。
2) 返回存储的 std::chrono::month 值。
3) 返回存储的 std::chrono::day 值。


std::chrono::year_month_day::ok

< cpp‎ | chrono‎ | year month day
constexpr bool ok() const noexcept; | (C++20 起)

检查此 year_month_day 对象是否表示合法的日历日期。

返回值

若此 year_month_day 对象表示合法的日历日期，即存储的 year 、 month 和 day 值均合法，且存储的 day 值在给定年和月的日数内，则为 true 。否则为 false 。

可能的实现

constexpr bool std::chrono::year_month_day::ok() const noexcept {
    return year().ok() && month().ok() && day().ok() &&
           day() <= (year()/month()/std::chrono::last).day();
}


std::chrono::year_month_day::operator+=, std::chrono::year_month_day::operator-=

< cpp‎ | chrono‎ | year month day

constexpr std::chrono::year_month_day& operator+=(const std::chrono::years& dy) const noexcept; | (1) | (C++20 起)
constexpr std::chrono::year_month_day& operator+=(const std::chrono::months& dm) const noexcept; | (2) | (C++20 起)
constexpr std::chrono::year_month_day& operator-=(const std::chrono::years& dy) const noexcept; | (3) | (C++20 起)
constexpr std::chrono::year_month_day& operator-=(const std::chrono::months& dm) const noexcept; | (4) | (C++20 起)

以时长 dy 或 dm 为程度修改时间点 *this 。

1) 等价于 *this = *this + dy;
2) 等价于 *this = *this + dm;
3) 等价于 *this = *this - dy;
4) 等价于 *this = *this - dm;

对于能转换到 std::chrono::years 与 std::chrono::months 两者的时长，若调用有歧义，则偏好 years 重载 (1,3) 。

参阅

operator+operator-
(C++20)
 将 year_month_day 与一定量的年数或月数相加或相减
(函数)


std::chrono::operator+, std::chrono::operator- (std::chrono::year_month_day)

< cpp‎ | chrono‎ | year month day
定义于头文件 <chrono>
constexpr std::chrono::year_month_day operator+(const std::chrono::year_month_day& ymd,
const std::chrono::months& dm) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_day operator+(const std::chrono::months& dm,
const std::chrono::year_month_day& ymd) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_day operator+(const std::chrono::year_month_day& ymd,
const std::chrono::years& dy) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_day operator+(const std::chrono::years& dy,
const std::chrono::year_month_day& ymd) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_day operator-(const std::chrono::year_month_day& ymd,
const std::chrono::months& dm) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_day operator-(const std::chrono::year_month_day& ymd,
const std::chrono::years& dy) noexcept;
 (C++20 起)
1-2) 将 dm.count() 月加到 ymd 所表示的日期。结果与 ymd 拥有相同的 day() ，且与 std::chrono::year_month(ymd.year(), ymd.month()) + dm 拥有相同的 year() 和 month() 。
3-4) 将 dy.count() 年加到 ymd 所表示的日期。结果等价于 std::chrono::year_month_day(ymd.year() + dy, ymd.month(), ymd.day() 。
5) 从 ymd 所表示的日期减去 dm.count() 月。等价于 ymd + -dm 。
5) 从 ymd 所表示的日期减去 dy.count() 年。等价于 ymd + -dy 。

对于能转换到 std::chrono::years 与 std::chrono::months 两者的时长，若调用本会有歧义则偏好 years 重载 (3,4,6) 。

注解

即使 ymd.ok() 为 true ，若 ymd.day() 为 29 、 30 或 31 ，则产生的 year_month_day 可能不表示合法日期。


std::chrono::operator==,<=>(std::chrono::year_month_day)

< cpp‎ | chrono‎ | year month day
定义于头文件 <chrono>
constexpr bool operator==( const std::chrono::year_month_day& x,
const std::chrono::year_month_day& y ) noexcept;
 (1) (C++20 起)
constexpr std::strong_ordering

operator<=>( const std::chrono::year_month_day& x,

const std::chrono::year_month_day& y ) noexcept;
 (2) (C++20 起)

比较二个 year_month_day 值 x 与 y 。这是字典序比较：首先比较 year() ，然后是 month() ，最后比较 day() 。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

返回值

1) x.year() == y.year() && x.month() == y.month() && x.day() == y.day()
2) 若 x.year() <=> y.year != 0 则为 x.year() <=> y.year ；否则若 x.month() <=> y.month() != 0 则为 x.month() <=> y.month() ；否则为 x.day() <=> y.day()

注解

若 x 和 y 都表示合法日期（ x.ok() && y.ok() == true ），则字典序比较的结果与日历顺序一致。

示例

#include <iostream>
#include <chrono>

int main()
{
    constexpr auto ymd1 {std::chrono::day(1)/7/2021};
    constexpr auto ymd2 {std::chrono::year(2021)/7/1};
    std::cout << std::boolalpha << (ymd1 == ymd2) << '\n';

    static_assert(ymd1 <= ymd2);
}

输出：

true


std::chrono::year_month_day::operator sys_days, std::chrono::year_month_day::operator local_days

< cpp‎ | chrono‎ | year month day
constexpr operator std::chrono::sys_days() const noexcept; | (1) | (C++20 起)
explicit constexpr operator std::chrono::local_days() const noexcept; | (2) | (C++20 起)

将 *this 转换成与此 year_month_day 表示同一日期的 std::chrono::time_point 。

1) 若 ok() 为 true ，则返回值保有从 std::chrono::system_clock 纪元 (1970-01-01) 到 *this 的日数总计。若 *this 表示的日期先于纪元，则结果为负。
否则，若存储的 year 和 month 合法（ year().ok() && month().ok() 为 true ），则返回值为 sys_days(year()/month()/1d) + (day() - 1d) 。
否则（若 year().ok() && month().ok() 为 false ），返回值未指定。
范围 [std::chrono::days{-12687428}, std::chrono::days{11248737}] 中的 sys_days ，转换到 year_month_day 再转换回来后，生成相同值。
2) 同 (1) ，但替而返回 local_days 。等价于 return local_days(sys_days(*this).time_since_epoch()); 。

注意

转换到 sys_days 再转换回来，能用于正规化含有非法 day 但有合法 year 和 month 的 year_month_day ：

using namespace std::chrono;
auto ymd = 2017y/January/0;
ymd = sys_days{ymd};
// ymd 现在是 2016y/December/31

能通过加（或减）零个 std::chrono::months 正规化年和月：

using namespace std::chrono;
constexpr year_month_day normalize(year_month_day ymd){
    ymd += months{0}; // 正规化年和月
    return sys_days{ymd}; // 正规化日
}
static_assert(normalize(2017y/33/59) == 2019y/10/29);

示例

本节未完成
原因：暂无示例


std::chrono::operator<<(std::chrono::year_month_day)

< cpp‎ | chrono‎ | year month day
定义于头文件 <chrono>
template< class CharT, class Traits >

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::year_month_day& ymd );
 (C++20 起)

输出 ymd 的文本表示到流 os 中。这首先构成由格式为 yyyy-mm-dd （同 formatter 用 %F 说明符的输出）的日期文本表示组成的 std::basic_string <CharT> s 。然后，若 !ymd.ok() 则后附 " is not a valid date" 到 s 。插入 s 到 os 中。

等价于

return os << (ymd.ok() ?
std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{:%F}"), ymd) :
std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{:%F} is not a valid date"), ymd));

其中 STATICALLY_WIDEN<CharT>("...") 若 CharT 为 char 则为 "..." ，而若 CharT 为 wchar_t 则为 L"..." 。

返回值

os 。

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::year_month_day> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month_day (类模板特化)


std::chrono::year_month_day::year_month_day

< cpp‎ | chrono‎ | year month day
year_month_day() = default;
 (1) (C++20 起)
constexpr year_month_day(const std::chrono::year& y,

const std::chrono::month& m,

const std::chrono::day& d) noexcept;
 (2) (C++20 起)
constexpr year_month_day(const std::chrono::year_month_day_last& ymdl) noexcept;
 (C++20 起)
constexpr year_month_day(const std::chrono::sys_days& dp) noexcept;
 (C++20 起)
explicit constexpr year_month_day(const std::chrono::local_days& dp) noexcept;
 (C++20 起)

构造 year_month_day 对象。

1) 默认构造函数保留日期未初始化。
2) 构造存储年 y 、月 m 和日 d 的 year_month_day 对象。
3) 构造存储年 ymdl.year() 、月 ymdl.month() 和日 ymdl.day() 的 year_month_day 对象。
4) 构造与 dp 表示相同日期的 year_month_day 对象。
5) 如同用 year_month_day(sys_days(dp.time_since_epoch())) 构造与 dp 表示相同日期的 year_month_day 对象。

构造函数 (3-4) 分别定义来自 std::chrono::year_month_day_last 和 std::chrono::sys_days 的隐式转换。

对于任何表示合法日期的 year_month_day 对象 ymd （ ymd.ok() == true ），转换 ymd 为 sys_days 再转换回来生成相同值。

注意

亦能由将部分日期类型 std::chrono::year_month 及 std::chrono::month_day 与缺失组分（分别为 day 和 year ）结合，用 operator/ 创建 year_month_day 。

参阅

operator/
(C++20)
 创建格里高利历日期的约定语法
(函数)


std::chrono::year_month_day_last

< cpp‎ | chrono
定义于头文件 <chrono> |
class year_month_day_last; | (C++20 起)

类 year_month_day_last 表示特定年和月的最后一日。它是基于域的时间点，解析为 std::chrono::days ，所受的限制是它只能表示月的最后一日。

它直接支持面向 std::chrono::years 和 std::chrono::months 的算术。到 std::chrono::sys_days 的隐式转换等效地允许面向 std::chrono::days 的算术。

year_month_day_last 是可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 year_month_day_last 对象 (公开成员函数)
operator+=operator-= | 以 months 和 years 为数量修改时间点 (公开成员函数)
yearmonthdaymonth_day_last | 访问此对象的域 (公开成员函数)
operator sys_daysoperator local_days | 转换到 std::chrono::time_point (公开成员函数)
ok | 检查此对象是否表示合法日期 (公开成员函数)

非成员函数

operator==operator<=> (C++20) | 比较二个 year_month_day_last 值 (函数)
operator+operator- (C++20) | 将 year_month_day_last 和一定数量的 years 或 months 相加或相减 (函数)
operator<< (C++20) | 输出 year_month_day_last 到流中 (函数模板)

辅助类

std::formatter<std::chrono::year_month_day_last>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 year_month_day_last
(类模板特化)


std::chrono::year_month_day_last::year, std::chrono::year_month_day_last::month, std::chrono::year_month_day_last::day, std::chrono::year_month_day_last::month_day_last

< cpp‎ | chrono‎ | year month day last
constexpr std::chrono::year year() const noexcept; | (1) | (C++20 起)
constexpr std::chrono::month month() const noexcept; | (2) | (C++20 起)
constexpr std::chrono::day day() const noexcept; | (3) | (C++20 起)
constexpr std::chrono::month_day_last month_day_last() const noexcept; | (4) | (C++20 起)

取得存储于此 year_month_day_last 对象的域的值。

返回值

1) 返回存储的 std::chrono::year 值。
2) 返回存储的 std::chrono::month 值。
3) 对应存储的 year 和 month 的最后一日的 std::chrono::day 值。若 this->ok() 为 false ，则返回值未指定。
4) 从 month() 构造的 std::chrono::month_day_last 。


std::chrono::year_month_day_last::ok

< cpp‎ | chrono‎ | year month day last
constexpr bool ok() const noexcept; | (C++20 起)

检查 *this 是否表示合法日期。因为 year_month_day_last 表示特定月的最后一日，故只要年和月合法它就表示合法日期。

返回值

year().ok() && month().ok()


std::chrono::year_month_day_last::operator+=, std::chrono::year_month_day_last::operator-=

< cpp‎ | chrono‎ | year month day last

constexpr std::chrono::year_month_day_last& operator+=(const std::chrono::years& dy) const noexcept; | (1) | (C++20 起)
constexpr std::chrono::year_month_day_last& operator+=(const std::chrono::months& dm) const noexcept; | (2) | (C++20 起)
constexpr std::chrono::year_month_day_last& operator-=(const std::chrono::years& dy) const noexcept; | (3) | (C++20 起)
constexpr std::chrono::year_month_day_last& operator-=(const std::chrono::months& dm) const noexcept; | (4) | (C++20 起)

以时长 dy 或 dm 为程度修改时间点 *this 。

1) 等价于 *this = *this + dy;
2) 等价于 *this = *this + dm;
3) 等价于 *this = *this - dy;
4) 等价于 *this = *this - dm;

对于能转换到 std::chrono::years 与 std::chrono::months 两者的时长，若调用有歧义，则偏好 years 重载 (1,3) 。

参阅

operator+operator-
(C++20)
 将 year_month_day_last 和一定数量的 years 或 months 相加或相减
(函数)


std::chrono::operator+, std::chrono::operator- (std::chrono::year_month_day_last)

< cpp‎ | chrono‎ | year month day last
定义于头文件 <chrono>
constexpr std::chrono::year_month_day_last
operator+(const std::chrono::year_month_day_last& ymdl, const std::chrono::months& dm) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_day_last
operator+(const std::chrono::months& dm, const std::chrono::year_month_day_last& ymdl) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_day_last
operator+(const std::chrono::year_month_day_last& ymdl, const std::chrono::years& dy) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_day_last
operator+(const std::chrono::years& dy, const std::chrono::year_month_day_last& ymdl) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_day_last
operator-(const std::chrono::year_month_day_last& ymdl, const std::chrono::months& dm) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_day_last
operator-(const std::chrono::year_month_day_last& ymdl, const std::chrono::years& dy) noexcept;
 (C++20 起)
1-2) 将 dm.count() 月加到 ymdl 所表示的日期。结果与 std::chrono::year_month(ymdl.year(), ymdl.month()) + dm 拥有相同的 year() 和 month() 。
3-4) 将 dy.count() 年加到 ymdl 所表示的日期。结果等价于 std::chrono::year_month_day_last(ymdl.year() + dy, ymdl.month_day_last()) 。
5) 从 ymdl 所表示的日期减去 dm.count() 月。等价于 ymdl + -dm 。
5) 从 ymdl 所表示的日期减去 dy.count() 年。等价于 ymdl + -dy 。

对于能转换到 std::chrono::years 与 std::chrono::months 两者的时长，若调用本会有歧义则偏好 years 重载 (3,4,6) 。


std::chrono::operator==,<=>(std::chrono::year_month_day_last)

< cpp‎ | chrono‎ | year month day last
定义于头文件 <chrono>
constexpr bool operator==(const std::chrono::year_month_day_last& x,
const std::chrono::year_month_day_last& y) noexcept;
 (1) (C++20 起)
constexpr std::strong_ordering

operator<=>( const std::chrono::year_month_day_last& x,

const std::chrono::year_month_day_last& y ) noexcept;
 (2) (C++20 起)

比较二个 year_month_day_last 值 x 与 y 。这是字典序比较：首先比较 year() ，再比较 month() 。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

返回值

1) x.year() == y.year() && x.month() == y.month()
2) x.year() <=> y.year() != 0 ? x.year() <=> y.year() : x.month() <=> y.month()

注解

若 x 和 y 均表示合法日期（ x.ok() && y.ok() == true ），则字典序比较的结果与日历顺序一致。

示例

#include <iostream>
#include <chrono>

int main()
{
    std::cout << std::boolalpha;

    auto ymdl1 {11/std::chrono::last/2020};
    auto mdl {std::chrono::last/std::chrono::November};
    auto ymdl2 {mdl/2020};
    std::cout << (ymdl1 == ymdl2) << ' ';
    ymdl1 -= std::chrono::months{2};
    ymdl2 -= std::chrono::months{1};
    std::cout << (ymdl1 < ymdl2) << '\n';
}

输出：

true true


std::chrono::year_month_day_last::operator sys_days, std::chrono::year_month_day_last::operator local_days

< cpp‎ | chrono‎ | year month day last
constexpr operator std::chrono::sys_days() const noexcept; | (1) | (C++20 起)
explicit constexpr operator std::chrono::local_days() const noexcept; | (2) | (C++20 起)

转换 *this 为与此 year_month_day_last 表示相同日期的 std::chrono::time_point 。这等价于从 year() 、 month() 和 day() 合成 year_month_day ，再将该 year_month_day 转换成目标类型。

1) 等价于 std::chrono::sys_days(year()/month()/day())
2) 等价于 std::chrono::local_days(year()/month()/day())

示例

本节未完成
原因：暂无示例

参阅

operator sys_daysoperator local_days
 转换到 std::chrono::time_point
(std::chrono::year_month_day 的公开成员函数)


std::chrono::operator<<(std::chrono::year_month_day_last)

< cpp‎ | chrono‎ | year month day last
定义于头文件 <chrono>
template< class CharT, class Traits >

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::year_month_day_last& ymdl );
 (C++20 起)

输出 ymdl 的文本表示到 os 中，如同用

os << std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{}/{:L}"),
ymdl.year(), ymdl.month_day_last());

其中 STATICALLY_WIDEN<CharT>("{}/{:L}") 若 CharT 为 char 则为 "{}/{:L}" ，而若 CharT 为 wchar_t 则为 L"{}/{:L}" 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::year_month_day> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month_day (类模板特化)


std::chrono::year_month_day_last::year_month_day_last

< cpp‎ | chrono‎ | year month day last
constexpr year_month_day_last(const std::chrono::year& y,
const std::chrono::month_day_last& mdl) noexcept;
 (C++20 起)

构造存储年 y 和月 mdl.month() 的 year_month_day_last 对象。构造的对象表示该年和月的最后一日。

注意

亦能通过用 operator/ 将 std::chrono::year_month 与 std::chrono::last 结合，创建 year_month_day_last 。

参阅

operator/
(C++20)
 创建格里高利历日期的约定语法
(函数)


std::chrono::year_month_weekday

< cpp‎ | chrono
定义于头文件 <chrono> |
class year_month_weekday; | (C++20 起)

类 year_month_weekday 表示特定年月的第 n 个星期之日。它是基于域的时间点，解析为 std::chrono::days 。它直接支持面向 std::chrono::years 和 std::chrono::months 的算术。来自和到 std::chrono::sys_days 的隐式转换允许等效地进行面向 std::chrono::days 的算术。

year_month_weekday 是可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 year_month_weekday (公开成员函数)
operator+=operator-= | 以一定的 months 或 years 为数量修改时间点 (公开成员函数)
yearmonthweekdayindexweekday_indexed | 访问此对象的域 (公开成员函数)
operator sys_daysoperator local_days | 转换到 std::chrono::time_point (公开成员函数)
ok | 检查此对象是否表示合法日期 (公开成员函数)

非成员函数

operator== (C++20) | 比较二个 year_month_weekday 值 (函数)
operator+operator- (C++20) | 将 year_month_weekday 与一定数量的 years 或 months 相加或相减 (函数)
operator<< (C++20) | 输出 year_month_weekday 到流中 (函数模板)

辅助类

std::formatter<std::chrono::year_month_weekday>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 year_month_weekday
(类模板特化)


std::chrono::year_month_weekday::year, std::chrono::year_month_weekday::month, std::chrono::year_month_weekday::weekday, std::chrono::year_month_weekday::index, std::chrono::year_month_weekday::weekday_indexed

< cpp‎ | chrono‎ | year month weekday
constexpr std::chrono::year year() const noexcept; | (1) | (C++20 起)
constexpr std::chrono::month month() const noexcept; | (2) | (C++20 起)
constexpr std::chrono::weekday weekday() const noexcept; | (3) | (C++20 起)
constexpr unsigned index() const noexcept; | (4) | (C++20 起)
constexpr std::chrono::weekday_indexed weekday_indexed() const noexcept; | (5) | (C++20 起)

返回存储于此 year_month_weekday 对象中的域的值。

返回值

1) 返回存储的 std::chrono::year 值。
2) 返回存储的 std::chrono::month 值。
3) 返回存储的 std::chrono::weekday 值。
4) 返回存储的星期之日下标。
5) weekday()[index()] 。


std::chrono::year_month_weekday::ok

< cpp‎ | chrono‎ | year month weekday
constexpr bool ok() const noexcept; | (C++20 起)

检查此 year_month_weekday 对象是否表示合法日期。

返回值

若此 year_month_weekday 对象表示合法日期，即 year().ok() && month().ok() && weekday_indexed().ok() 为 true 且指定年月中至少有 index() 个 weekday() ，则为 true 。否则为 false 。


std::chrono::year_month_weekday::operator+=, std::chrono::year_month_weekday::operator-=

< cpp‎ | chrono‎ | year month weekday

constexpr std::chrono::year_month_weekday& operator+=(const std::chrono::years& dy) const noexcept; | (1) | (C++20 起)
constexpr std::chrono::year_month_weekday& operator+=(const std::chrono::months& dm) const noexcept; | (2) | (C++20 起)
constexpr std::chrono::year_month_weekday& operator-=(const std::chrono::years& dy) const noexcept; | (3) | (C++20 起)
constexpr std::chrono::year_month_weekday& operator-=(const std::chrono::months& dm) const noexcept; | (4) | (C++20 起)

以时长 dy 或 dm 为程度修改时间点 *this 。

1) 等价于 *this = *this + dy;
2) 等价于 *this = *this + dm;
3) 等价于 *this = *this - dy;
4) 等价于 *this = *this - dm;

对于能转换到 std::chrono::years 与 std::chrono::months 两者的时长，若调用有歧义，则偏好 years 重载 (1,3) 。

参阅

operator+operator-
(C++20)
 将 year_month_weekday 与一定数量的 years 或 months 相加或相减
(函数)


std::chrono::operator+, std::chrono::operator- (std::chrono::year_month_weekday)

< cpp‎ | chrono‎ | year month weekday
constexpr std::chrono::year_month_weekday
operator+(const std::chrono::year_month_weekday& ymwd, const std::chrono::months& dm) noexcept;
 (1) (C++20 起)
constexpr std::chrono::year_month_weekday
operator+(const std::chrono::months& dm, const std::chrono::year_month_weekday& ymwd) noexcept;
 (2) (C++20 起)
constexpr std::chrono::year_month_weekday
operator+(const std::chrono::year_month_weekday& ymwd, const std::chrono::years& dy) noexcept;
 (3) (C++20 起)
constexpr std::chrono::year_month_weekday
operator+(const std::chrono::years& dy, const std::chrono::year_month_weekday& ymwd) noexcept;
 (4) (C++20 起)
constexpr std::chrono::year_month_weekday
operator-(const std::chrono::year_month_weekday& ymwd, const std::chrono::months& dm) noexcept;
 (5) (C++20 起)
constexpr std::chrono::year_month_weekday
operator-(const std::chrono::year_month_weekday& ymwd, const std::chrono::years& dy) noexcept;
 (6) (C++20 起)
1-2) 将 dm.count() 月加到 ymwd 所表示的日期。结果与 std::chrono::year_month(ymwd.year(), ymwd.month()) + dm 拥有相同的 year() 和 month() ，并与 ymwd 拥有相同的 weekday() 和 index() 。
3-4) 将 dy.count() 年加到 ymwd 所表示的日期。结果等价于 std::chrono::year_month_weekday(ymwd.year() + dy, ymwd.month(), ymwd.weekday_indexed()) 。
5) 从 ymwd 所表示的日期减去 dm.count() 月。等价于 ymwd + -dm 。
6) 从 ymwd 所表示的日期减去 dy.count() 年。等价于 ymwd + -dy 。

对于能转换到 std::chrono::years 与 std::chrono::months 两者的时长，若调用本会有歧义则偏好 years 重载 (3,4,6) 。

注解

即使 ymwd.ok() 为 true ，若 ymwd.index() 为 5 则生成的 year_month_weekday 可能不表示合法日期。


std::chrono::operator==(std::chrono::year_month_weekday)

< cpp‎ | chrono‎ | year month weekday
定义于头文件 <chrono>
constexpr bool operator==(const std::chrono::year_month_weekday& x,
const std::chrono::year_month_weekday& y) noexcept;
 (C++20 起)

比较二个 year_month_weekday 值 x 与 y 。

!= 运算符从 operator== 合成。

返回值

x.year() == y.year() && x.month() == y.month() && x.weekday_indexed() == y.weekday_indexed()

示例

#include <iostream>
#include <chrono>
using namespace std::chrono;

int main()
{
    constexpr auto ymwdi1 {Wednesday[1]/January/2021};
    constexpr year_month_weekday ymwdi2 {year(2021), month(1), weekday(3)[1]};
    std::cout << std::boolalpha << (ymwdi1 == ymwdi2) << '\n';
}

输出：

true


std::chrono::year_month_weekday::operator sys_days, std::chrono::year_month_weekday::operator local_days

< cpp‎ | chrono‎ | year month weekday
constexpr operator std::chrono::sys_days() const noexcept; | (1) | (C++20 起)
explicit constexpr operator std::chrono::local_days() const noexcept; | (2) | (C++20 起)

转换 *this 为与此 year_month_weekday 表示同一日期的 std::chrono::time_point 。

1) 若 year().ok() && month().ok() && weekday().ok() ：
  • 若 index() == 0 ，则返回表示该年月的首个 weekday() 前 7 日的日期的 sys_days 。
  • 其他情况下，返回表示该年月的首个 weekday() 后 (index() - 1) * 7 日的日期的 sys_days 。
否则，返回值未指定。
2) 同 (1) ，但返回 local_days ，而非 sys_days 。等价于 local_days(sys_days(*this).time_since_epoch()) 。


std::chrono::operator<<(std::chrono::year_month_weekday)

< cpp‎ | chrono‎ | year month weekday
定义于头文件 <chrono>
template< class CharT, class Traits >

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::year_month_weekday& ymwd );
 (C++20 起)

输出 ymwd 的文本表示到 os 中，如同用

os << std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{}/{:L}/{:L}"),
ymwd.year(), ymwd.month(), ymwd.weekday_indexed());

其中 STATICALLY_WIDEN<CharT>("{}/{:L}/{:L}") 若 CharT 为 char 则为 "{}/{:L}/{:L}" ，而若 CharT 为 wchar_t 则为 L"{}/{:L}/{:L}" 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::year_month_day> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month_day (类模板特化)


std::chrono::year_month_weekday::year_month_weekday

< cpp‎ | chrono‎ | year month weekday
year_month_weekday() = default;
 (1) (C++20 起)
constexpr year_month_weekday(const std::chrono::year& y, const std::chrono::month& m,
const std::chrono::weekday_indexed& wdi) noexcept;
 (2) (C++20 起)
constexpr year_month_weekday(const std::chrono::sys_days& dp) noexcept;
 (3) (C++20 起)
explicit constexpr year_month_weekday(const std::chrono::local_days& dp) noexcept;
 (4) (C++20 起)

构造 year_month_weekday 对象。

1) 默认构造函数保留域未初始化。
2) 构造存储 year y 、 month m 、 weekday wdi.weekday() 和星期之日下标 wdi.index() 的 year_month_weekday 。
3) 构造对应 dp 所表示日期的 year_month_weekday 对象。对于任何存储合法日期的 year_month_weekday 对象，将它转换成 sys_days 再转换回来生成相同值。此构造函数定义从 sys_days 到 year_month_weekday 的隐式转换。
4) 构造对应 dp 所表示日期的 year_month_weekday 对象。等价于 year_month_weekday(sys_days(dp.time_since_epoch())) 。

注意

亦能通过用 operator/ 将部分日期 std::chrono::year_month 及 std::chrono::month_weekday 与缺失成分（分别为有下标的星期之日和年）结合创建 year_month_weekday 。

参阅

operator/
(C++20)
 创建格里高利历日期的约定语法
(函数)


std::chrono::year_month_weekday_last

< cpp‎ | chrono
定义于头文件 <chrono> |
class year_month_weekday_last; | (C++20 起)

类 year_month_weekday_last 表示特定年月的最后一个星期之日。它是基于域的时间点，解析为 std::chrono::days ，除了它被限制为指向年和月的最后一个星期之日。它直接支持面向 std::chrono::years 和 std::chrono::months 的算术。到 std::chrono::sys_days 的隐式转换允许等效地进行面向 std::chrono::days 的算术。

year_month_weekday_last 是可平凡复制 (TriviallyCopyable) 的标准布局类型 (StandardLayoutType) 。

成员函数

(构造函数) | 构造 year_month_weekday_last (公开成员函数)
operator+=operator-= | 以一定的 months 或 years 为数量修改时间点 (公开成员函数)
yearmonthweekdayweekday_last | 访问此对象的域 (公开成员函数)
operator sys_daysoperator local_days | 转换到 std::chrono::time_point (公开成员函数)
ok | 检查此对象是否表示合法日期 (公开成员函数)

非成员函数

operator== (C++20) | 比较二个 year_month_weekday_last 值 (函数)
operator+operator- (C++20) | 将 year_month_weekday_last 与一定数量的 years 或 months 相加或相减 (函数)
operator<< (C++20) | 输出 year_month_weekday_last 到流中 (函数模板)

辅助类

std::formatter<std::chrono::year_month_weekday_last>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 year_month_weekday_last
(类模板特化)


std::chrono::year_month_weekday_last::year, std::chrono::year_month_weekday_last::month, std::chrono::year_month_weekday_last::weekday, std::chrono::year_month_weekday_last::weekday_last

< cpp‎ | chrono‎ | year month weekday last
constexpr std::chrono::year year() const noexcept; | (C++20 起)
constexpr std::chrono::month month() const noexcept; | (C++20 起)
constexpr std::chrono::weekday weekday() const noexcept; | (C++20 起)
constexpr std::chrono::weekday_last weekday_last() const noexcept; | (C++20 起)

取得存储于此 year_month_weekday_last 对象的域的值。

返回值

1) 返回存储的 std::chrono::year 值。
2) 返回存储的 std::chrono::month 值。
3) 返回存储的 std::chrono::weekday 值。
4) std::chrono::weekday_last(weekday()) 。


std::chrono::year_month_weekday_last::ok

< cpp‎ | chrono‎ | year month weekday last
constexpr bool ok() const noexcept; | (C++20 起)

检查此对象是否表示合法日期。因为 year_month_weekday_last 表示特定月的最后一个星期之日，故只要 year 、 month 和 weekday 合法，它就合法。

返回值

year().ok() && month().ok() && weekday().ok()


std::chrono::year_month_weekday_last::operator+=, std::chrono::year_month_weekday_last::operator-=

< cpp‎ | chrono‎ | year month weekday last

constexpr std::chrono::year_month_weekday_last& operator+=(const std::chrono::years& dy) const noexcept; | (1) | (C++20 起)
constexpr std::chrono::year_month_weekday_last& operator+=(const std::chrono::months& dm) const noexcept; | (2) | (C++20 起)
constexpr std::chrono::year_month_weekday_last& operator-=(const std::chrono::years& dy) const noexcept; | (3) | (C++20 起)
constexpr std::chrono::year_month_weekday_last& operator-=(const std::chrono::months& dm) const noexcept; | (4) | (C++20 起)

以时长 dy 或 dm 为程度修改时间点 *this 。

1) 等价于 *this = *this + dy;
2) 等价于 *this = *this + dm;
3) 等价于 *this = *this - dy;
4) 等价于 *this = *this - dm;

对于能转换到 std::chrono::years 与 std::chrono::months 两者的时长，若调用有歧义，则偏好 years 重载 (1,3) 。

参阅

operator+operator-
(C++20)
 将 year_month_weekday_last 与一定数量的 years 或 months 相加或相减
(函数)


std::chrono::operator+, std::chrono::operator- (std::chrono::year_month_weekday_last)

< cpp‎ | chrono‎ | year month weekday last
constexpr std::chrono::year_month_weekday_last

operator+(const std::chrono::year_month_weekday_last& ymwdl,

const std::chrono::months& dm) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_weekday_last

operator+(const std::chrono::months& dm,

const std::chrono::year_month_weekday_last& ymwdl) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_weekday_last

operator+(const std::chrono::year_month_weekday_last& ymwdl,

const std::chrono::years& dy) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_weekday_last

operator+(const std::chrono::years& dy,

const std::chrono::year_month_weekday_last& ymwdl) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_weekday_last

operator-(const std::chrono::year_month_weekday_last& ymwdl,

const std::chrono::months& dm) noexcept;
 (C++20 起)
constexpr std::chrono::year_month_weekday_last

operator-(const std::chrono::year_month_weekday_last& ymwdl,

const std::chrono::years& dy) noexcept;
 (C++20 起)
1-2) 将 dm.count() 月加到 ymwdl 所表示的日期。结果与 std::chrono::year_month(ymwdl.year(), ymwdl.month()) + dm 拥有相同的 year() 和 month() ，并与 ymwdl 拥有相同的 weekday() 。
3-4) 将 dy.count() 年加到 ymwdl 所表示的日期。结果等价于 std::chrono::year_month_weekday_last(ymwdl.year() + dy, ymwdl.month(), ymwd.weekday_last()) 。
5) 从 ymwdl 所表示的日期减去 dm.count() 月。等价于 ymwdl+ -dm 。
6) 从 ymwdl 所表示的日期减去 dy.count() 年。等价于 ymwdl + -dy 。

对于能转换到 std::chrono::years 与 std::chrono::months 两者的时长，若调用本会有歧义则偏好 years 重载 (3,4,6) 。


std::chrono::operator==(std::chrono::year_month_weekday_last)

< cpp‎ | chrono‎ | year month weekday last
定义于头文件 <chrono>
constexpr bool operator==(const std::chrono::year_month_weekday_last& x,
const std::chrono::year_month_weekday_last& y) noexcept;
 (C++20 起)

比较二个 year_month_weekday_last 值 x 与 y 。

!= 运算符从 operator== 合成。

返回值

x.year() == y.year() && x.month() == y.month() && x.weekday() == y.weekday()

示例

#include <iostream>
#include <chrono>
using namespace std::chrono;

int main()
{
    constexpr auto ymwdl1 {Tuesday[last]/11/2021};
    auto ymwdl2 = Tuesday[last]/11/2020;
    ymwdl2 += months(12);
    std::cout << std::boolalpha << (ymwdl1 == ymwdl2) << '\n';
}

输出：

true


std::chrono::year_month_weekday_last::operator sys_days, std::chrono::year_month_weekday_last::operator local_days

< cpp‎ | chrono‎ | year month weekday last
constexpr operator std::chrono::sys_days() const noexcept; | (1) | (C++20 起)
explicit constexpr operator std::chrono::local_days() const noexcept; | (2) | (C++20 起)

将 *this 转换成与此 year_month_weekday_last 表示相同时间点的 std::chrono::time_point 。

1) 若 ok() 为 true ，则返回表示该 year() 和 month() 的最后一个 weekday() 的 sys_days 。否则返回值未指定。
2) 同 (1) ，但返回 local_days 而非 sys_days 。等价于 local_days(sys_days(*this).time_since_epoch()) 。


std::chrono::operator<<(std::chrono::year_month_weekday_last)

< cpp‎ | chrono‎ | year month weekday last
定义于头文件 <chrono>
template< class CharT, class Traits >

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::year_month_weekday_last& ymwdl );
 (C++20 起)

输出 ymwdl 的文本表示到 os 中，如同用

os << std::format(os.getloc(), STATICALLY_WIDEN<CharT>("{}/{:L}/{:L}"),
ymwdl.year(), ymwdl.month(), ymwdl.weekday_last());

其中 STATICALLY_WIDEN<CharT>("{}/{:L}/{:L}") 若 CharT 为 char 则为 "{}/{:L}/{:L}" ，而若 CharT 为 wchar_t 则为 L"{}/{:L}/{:L}" 。

返回值

os 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
std::formatter<std::chrono::year_month_day> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month_day (类模板特化)


std::chrono::year_month_weekday_last::year_month_weekday_last

< cpp‎ | chrono‎ | year month weekday last
constexpr year_month_weekday_last(const std::chrono::year& y, const std::chrono::month& m,
const chrono::weekday_last& wdl) noexcept;
 (C++20 起)

构造存储 year y 、 month m 、 weekday wdl.weekday() 的 year_month_weekday_last 对象。构造的对象表示该年和月的最后一个星期之日。

注意

亦能通过用 operator/ 将部分日期类型 std::chrono::year_month 及 std::chrono::month_weekday_last 与缺失成分（分别为 weekday_last 和年）结合创建 year_month_weekday_last 。

参阅

operator/
(C++20)
 创建格里高利历日期的约定语法
(函数)


std::chrono::zoned_time

< cpp‎ | chrono
定义于头文件 <chrono> |
template < class Duration, class TimeZonePtr = const std::chrono::time_zone* > class zoned_time; | (C++20 起)
using zoned_seconds = std::chrono::zoned_time< std::chrono::seconds >; | (C++20 起)

类 zoned_time 表示时区与解析为 Duration 的 std::chrono::time_point 的逻辑配对。

zoned_time 的不变量是它始终指代合法的时区并表示该时区中存在且无歧义的时间点。为与此不变量一致， zoned_time 无移动构造函数或移动赋值运算符；试图移动 zoned_time 将进行复制。

若 Duration 不是 std::chrono::duration 的特化则程序为谬构。

模板形参 TimeZonePtr 允许用户提供其自身的时区指针类型并进一步经由 std::chrono::zoned_traits 定制 zoned_time 的行为。定制的时区类型不需要支持 std::chrono::time_zone 所支持的所有操作，只需支持实际在 zoned_time 上调用的函数所用的操作。

TimeZonePtr 必须为可移动构造 (MoveConstructible) 。允许仅移动的 TimeZonePtr ，但难以使用，因为 zoned_time 将为不可移动且不可能访问存储的 TimeZonePtr 。

成员类型

成员类型 | 定义
duration | std::common_type_t <Duration, std::chrono::seconds >

成员函数

(构造函数) | 构造 zoned_time (公开成员函数)
operator= | 赋值给 zoned_time (公开成员函数)
get_time_zone | 获得时区指针的副本 (公开成员函数)
operator local_timeget_local_time | 获得作为 local_time 的存储的时间点 (公开成员函数)
operator sys_timeget_sys_time | 获得作为 sys_time 的存储的时间点 (公开成员函数)
get_info | 获得关于在存储的时间点的时区的信息 (公开成员函数)

非成员函数

operator== (C++20) | 比较二个 zoned_time 值 (函数模板)
operator<< (C++20) | 输出 zoned_time 到流中 (函数模板)

辅助类

std::formatter<std::chrono::zoned_time>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 zoned_time
(类模板特化)

推导指引


std::chrono::zoned_time 的推导指引

< cpp‎ | chrono‎ | zoned time
zoned_time() -> zoned_time< std::chrono::seconds >;
 (1) (C++20 起)
template< class Duration >

zoned_time(std::chrono::sys_time<Duration>)

-> zoned_time< std::common_type_t <Duration, std::chrono::seconds >>;
 (2) (C++20 起)
template< class TimeZonePtrOrName >
zoned_time(TimeZonePtrOrName&&) -> zoned_time< std::chrono::seconds, /* see below */>;
 (3) (C++20 起)
template< class TimeZonePtrOrName, class Duration >

zoned_time(TimeZonePtrOrName&&, std::chrono::sys_time<Duration>)

-> zoned_time< std::common_type_t <Duration, std::chrono::seconds >, /* see below */>;
 (4) (C++20 起)
template< class TimeZonePtrOrName, class Duration >

zoned_time(TimeZonePtrOrName&&, std::chrono::local_time<Duration>,
std::chrono::choose = std::chrono::choose::earliest)

-> zoned_time< std::common_type_t <Duration, std::chrono::seconds >, /* see below */>;
 (5) (C++20 起)
template< class TimeZonePtrOrName&&, class Duration, class TimeZonePtr2 >

zoned_time(TimeZonePtrOrName, std::chrono::zoned_time<Duration, TimeZonePtr2>,
std::chrono::choose = std::chrono::choose::earliest)

-> zoned_time< std::common_type_t <Duration, std::chrono::seconds >, /* see below */>;
 (6) (C++20 起)

为 zoned_time 提供六个推导指引。它们把 Duration 正规化为最小解析为 std::chrono::seconds ，并提供用可转换成 std::string_view 的类型指定时区名的正确处理。

3-6) 若 std::is_convertible_v <TimeZonePtrOrName, std::string_view > 为 true ，则推导的第二模板实参为 const std::chrono::time_zone* 。否则为 std::remove_cvref_t<TimeZonePtrOrName> 。


std::chrono::zoned_time<Duration,TimeZonePtr>::get_info

< cpp‎ | chrono‎ | zoned time
std::chrono::sys_info get_info() const; | (C++20 起)

获得含有关于在存储于 *this 的时间点的时区的信息的 std::chrono::sys_info 。

返回值

zone->get_info(tp) ，其中 zone 是保有时区指针的非静态数据成员，而 tp 是保有存储的时间点（作为 std::chrono::sys_time<duration> 的）非静态数据成员。


std::chrono::zoned_time<Duration,TimeZonePtr>::operator local_time<duration>, std::chrono::zoned_time<Duration,TimeZonePtr>::get_local_time

< cpp‎ | chrono‎ | zoned time
std::chrono::local_time<duration> get_local_time() const; | (C++20 起)
explicit operator std::chrono::local_time<duration>() const; | (C++20 起)

获得表示对应 *this 所表示的时间点的时区中本地时间的 std::chrono::local_time<duration> 。

返回值

如同用 zone->to_local(get_sys_time()) 计算的 std::chrono::local_time<duration> ，其中 zone 是保有存储的时区指针的非静态数据成员。


std::chrono::zoned_time<Duration,TimeZonePtr>::operator sys_time<duration>, std::chrono::zoned_time<Duration,TimeZonePtr>::get_sys_time

< cpp‎ | chrono‎ | zoned time
operator std::chrono::sys_time<duration>() const; | (C++20 起)
std::chrono::sys_time<duration> get_sys_time() const; | (C++20 起)

获得与此 zoned_time 对象表示时间中同一点的 std::chrono::sys_time<duration> 。

返回值

与 *this 表示时间中同一点的 std::chrono::sys_time<duration> 。


std::chrono::zoned_time<Duration,TimeZonePtr>::get_time_zone

< cpp‎ | chrono‎ | zoned time
TimeZonePtr get_time_zone() const; | (C++20 起)

取得存储的时区指针。

返回值

存储的时区指针的副本。

注意

TimeZonePtr 为仅移动的类型时，没有办法访问时区指针。


std::chrono::zoned_time<Duration,TimeZonePtr>::operator=

< cpp‎ | chrono‎ | zoned time
zoned_time& operator=(const zoned_time& other) = default; | (1) | (C++20 起)
zoned_time& operator=(const std::chrono::sys_time<Duration>& other); | (2) | (C++20 起)
zoned_time& operator=(const std::chrono::local_time<Duration>& other); | (3) | (C++20 起)

赋 other 的值给 *this 。

1) 默认化的复制赋值运算符。复制赋值存储的时间点及存储的时区指针。 zoned_time 无移动赋值运算符；移动即是复制。
2) 赋值 other 给存储的时间点。不更改时区指针。调用后 get_sys_time() == other 。
3) 如同用 zone->to_sys(other) 转换 other 为 std::chrono::sys_time （其中 zone 是保有存储的时区指针的非静态数据成员）再赋值结果给存储的时间点。不更改时区指针。调用后 get_local_time() == other 。

返回值

*this 。


std::chrono::operator==(std::chrono::zoned_time)

< cpp‎ | chrono‎ | zoned time
定义于头文件 <chrono>
template <class Duration1, class Duration2, class TimeZonePtr>

bool operator==(const std::chrono::zoned_time<Duration1, TimeZonePtr>& x,

const std::chrono::zoned_time<Duration2, TimeZonePtr>& y);
 (C++20 起)

比较二个 zoned_time 值 x 和 y 。若二个 zoned_time 对象的时间点和时区指针按照 operator== 比较相等，则它们比较相等。

!= 运算符从 operator== 合成。

返回值

x.get_time_zone() == y.get_time_zone() && x.get_sys_time() == y.get_sys_time() ，除了比较在 x 和 y 的非静态数据成员上直接进行，而不进行复制。


std::chrono::operator<<(std::chrono::zoned_time)

< cpp‎ | chrono‎ | zoned time
定义于头文件 <chrono>
template <class CharT, class Traits, class Duration, class TimeZonePtr>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::chrono::zoned_time<Duration, TimeZonePtr>& tp );
 (C++20 起)

如同用 std::format(os, fmt, tp) 输出 tp 到流 os ，其中 fmt 若 CharT 为 char 则为 "{:L%F %T %Z}" ，或若 CharT 为 wchar_t 则为 L"{:L%F %T %Z}" 。

参数

os | - | 输出流
tp | - | 要输出的 zoned_time

返回值

os 。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2372R3 | C++20 | 默认使用给定的本地环境 | 需要 L 以使用本地环境

参阅

std::formatter<std::chrono::zoned_time>
(C++20)
 std::formatter 的特化，按照提供的格式格式化 zoned_time
(类模板特化)


std::chrono::zoned_time<Duration,TimeZonePtr>::zoned_time

< cpp‎ | chrono‎ | zoned time
zoned_time();
 (1) (C++20 起)
zoned_time(const std::chrono::sys_time<Duration>& st);
 (2) (C++20 起)
zoned_time(const zoned_time& other) = default;
 (3) (C++20 起)
template< class Duration2 >
zoned_time(const std::chrono::zoned_time<Duration2, TimeZonePtr>& other);
 (4) (C++20 起)
explicit zoned_time(TimeZonePtr z);
 (5) (C++20 起)
explicit zoned_time( std::string_view name);
 (6) (C++20 起)
zoned_time(TimeZonePtr z, const std::chrono::sys_time<Duration>& st);
 (7) (C++20 起)
zoned_time( std::string_view name, const std::chrono::sys_time<Duration>& st);
 (8) (C++20 起)
zoned_time(TimeZonePtr z, const std::chrono::local_time<Duration>& tp);
 (9) (C++20 起)
zoned_time( std::string_view name, const std::chrono::local_time<Duration>& tp);
 (10) (C++20 起)
zoned_time(TimeZonePtr z, const std::chrono::local_time<Duration>& tp,
std::chrono::choose c);
 (11) (C++20 起)
zoned_time( std::string_view name,
const std::chrono::local_time<Duration>& tp, std::chrono::choose c);
 (12) (C++20 起)
template< class Duration2, class TimeZonePtr2 >

zoned_time(TimeZonePtr z,

const std::chrono::zoned_time<Duration2, TimeZonePtr2>& zt);
 (13) (C++20 起)
template< class Duration2, class TimeZonePtr2 >

zoned_time(TimeZonePtr z,
const std::chrono::zoned_time<Duration2, TimeZonePtr2>& zt,

std::chrono::choose);
 (14) (C++20 起)
template< class Duration2, class TimeZonePtr2 >

zoned_time( std::string_view name,

const std::chrono::zoned_time<Duration2, TimeZonePtr2>& zt);
 (15) (C++20 起)
template< class Duration2, class TimeZonePtr2 >

zoned_time( std::string_view name,
const std::chrono::zoned_time<Duration2, TimeZonePtr2>& zt,

std::chrono::choose);
 (16) (C++20 起)

构造 zoned_time 对象，按照下表初始化存储的时区指针和时间点，其中 traits 为 std::chrono::zoned_traits<TimeZonePtr> ：

重载 | 时区指针（记为 zone ） | 时间点（ std::chrono::sys_time<duration> ） | 注意
(1) | traits::default_zone() | 默认构造 | (a)
(2) |  | st
(3) | other.get_time_zone() | other.get_sys_time() | (b)
(4) | other.get_time_zone() | other.get_sys_time() | (e)
(5) | std::move(z) | 默认构造 |
(6) | traits::locate_zone(name) |  | (c)
(7) | std::move(z) | st |
(8) | traits::locate_zone(name) |  | (c)
(9) | std::move(z) | zone->to_sys(tp) | (d)
(10) | traits::locate_zone(name) |  | (c,d)
(11) | std::move(z) | zone->to_sys(tp, c) | (d)
(12) | traits::locate_zone(name) |  | (c,d)
(13-14) | std::move(z) | zt.get_sys_time() | (e)
(15-16) | traits::locate_zone(name) |  | (c,e)
a) 若 traits::default_zone() 非良式，则指定来调用该表达式的构造函数 (1-2) 不参与重载决议。
b) 若 std::is_copy_constructible_v <TimeZonePtr> 为 false 则定义默认化的复制构造函数 (3) 为被删除。
c) 若 traits::locate_zone(name) 非良式或若该表达式不可转换成 TimeZonePtr ，则带 std::string_view 参数 name 的构造函数 (6,8,10,12,15-16) 不参与重载决议。
d) 若 zone->to_sys 非良式或其结果不可转换成 std::chrono::sys_time<duration> ，则指定来调用该调用表达式的构造函数 (9-12) 不参与重载决议。
e) 若 Duration2 不可转换成 Duration ，则带模板形参 Duration2 的构造函数 (4,13-16) 不参与重载决议。

若（按上述方式初始化的）时区指针不指代合法时区，则行为未定义。

注解

zoned_time 无移动构造函数，而移动它的尝试将替而用默认化的复制构造函数 (3) 进行复制。从而当 TimeZonePtr 是仅移动的类型时， zoned_time 不可移动：既不能复制亦不能移动它。

构造函数 (14,16) 接受 std::chrono::choose 参数，但该参数无效果。


std::chrono::zoned_traits

< cpp‎ | chrono
定义于头文件 <chrono> |  |
template < class TimeZonePtr > struct zoned_traits { }; | (1) | (C++20 起)
template <> struct zoned_traits<const std::chrono::time_zone*>; | (2) | (C++20 起)

类 zoned_traits 提供方式定制带定制时区指针类型的 std::chrono::zoned_time 构造函数的行为。具体而言，它允许这种类型指定要用的默认时区，和时区名到对应时区指针的映射。它可接受不支持任一操作的定制时区指针类型，该情况下对应的 zoned_time 构造函数将不参与重载决议。

初等模板为空。为默认时区指针类型 const std::chrono::time_zone* 提供特化。

成员函数

std::chrono::zoned_traits<const std::chrono::time_zone*>::default_zone

static const std::chrono::time_zone* default_zone();

返回默认时区 (UTC) 的时区指针。

返回值

std::chrono::locate_zone("UTC") 。

std::chrono::zoned_traits<const std::chrono::time_zone*>::locate_zone

static const std::chrono::time_zone* locate_zone( std::string_view name);

返回 name 所代表的时区的时区指针。

返回值

std::chrono::locate_zone(name) 。


注释

< cpp

注释是一种代码内文档。当被插入到程序中时，它们实际上会被编译器忽略；它们只需要被阅读源代码的人当作注记。虽然具体的文档并不是 C++ 标准的一部分，但一些工具可以解析各式注释。

语法

/* 注释 */ | (1)
// 注释 | (2)
1) 通称为“ C 风格”或“多行”注释。
2) 通称为“ C++ 风格”或“单行”注释。

在翻译阶段 3 中，每段注释通过被替换为单个空白字符从程序中移除。

C 风格

C 风格注释通常用于注释大块的文本，也可以用于注释单行文本。要插入一个 C 风格注释，可以简单地以 /* 和 */ 环绕文本；这样会使注释的内容被编译器忽略。尽管不是 C++ 标准的一部分， /** 和 */ 常用于指示文档块；这是合法的，因为第二个星号简单地被当做注释的一部分。C风格注释不能被嵌套。

C++ 风格

C++ 风格注释通常用于注释单行文本；不过也可以把多个 C++ 风格注释放在一起来组成多行注释。 C++ 风格注释告诉编译器忽略 // 和换行符之间的所有内容。

注意

因为注释在预处理器阶段前已经被移除，所以宏不能用于组成注释，而且未终止的 C 风格注释不会从被 #include 的文件中漏出。

除了把代码注释掉之外，用于排除源代码的其他机制还有：

#if 0
    std::cout << "这一句不会被执行，甚至不会被编译\n";
#endif

以及

if(false) {
    std::cout << "这一句不会被执行\n";
}

示例

#include <iostream>
/* C 风格注释
能含有多行 */
/* 或只有一行 */

/**************
 *  你能插入任意数量的 * ，
 *  但你不能嵌套注释
 */

// C++ 风格注释能注释一行

// 或者，能将
// 它们串在一起

int main()
{
  // 注释在预处理前被移除，
  // 故 ABC 为 1 ，而非 1//2134 ，
  // 而 "1 hello world"将得以打印
#define ABC 1//2134
  std::cout << ABC << " hello world\n";

  // 下方代码不会运行
  // return 1;

  // 下方代码会运行
  return 0;
}

输出：

1 hello world

参阅


C++ 编译器支持情况表

< cpp
我们尽可能努力维护这个页面，但仍可能缺少最新发布的编译器的版本信息。如果你发现有过时的内容的话，请帮助我们来更新它吧！

下表为各个编译器对新的 C++ 功能特性的支持情况。这些功能特性包括 C++11 、 C++14 、 C++17、 C++20 和以后接受的修订版标准 (C++23/C++2b) ，还有大量技术规范的内容。

C++2b 功能特性

请注意，随 C++2b 标准草案的逐步推进，此列表可能会发生变化。

C++23 核心语言功能特性

C++23 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc
（有符号） size_t 的字面量后缀 | P0330R8 | 11 | 13 |  |  |  |  |  |  |  |  |  |
使 () 对 lambda 更可选 | P1102R2 | 11 | 13 |  |  |  |  |  |  |  |  |  |
if consteval | P1938R3 | 12 | 14 |  |  |  |  |  |  |  |  |  |
移除垃圾收集支持 | P2186R2 | 12 |  |  |  |  |  |  |  |  |  |  |
DR：C++ 标识符语法使用 Unicode 标准附录 31 | P1949R7 | 12 | 14 |  |  |  |  |  |  |  |  |  |
DR：允许重复属性 | P2156R1 | 11 | 13 |  |  |  |  |  |  |  |  |  |
static_assert 与 constexpr if 中的窄化按语境转换 | P1401R5 | 9 | 13 (部分)* 14 |  |  |  |  |  |  |  |  |  |
在拼接行前剔除空白符 | P2223R2 | 是 | 是 |  | 是 |  |  |  |  |  |  |  |
使声明顺序布局强制 | P1847R4 | 是 | 是 | 是 | 是 |  |  |  |  |  |  |  |
移除混合宽字符串字面量连接 | P2201R1 | 是 | 是 | 是 | 是 |  | 是 |  |  |  |  |  |
C++23 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc

C++23 库功能特性

C++23 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
栈踪库 | P0881R7 |  |  |  |  |  |  |
<stdatomic.h> | P0943R6 |  |  |  |  |  |  |
std::is_scoped_enum | P1048R1 | 11 | 12 | 19.30* |  |  |  |
basic_string/basic_string_view 的 contains() | P1679R3 | 11 | 12 |  |  |  |  |
std::to_underlying | P1682R3 | 11 | 13 |  |  |  |  |
std::variant 的派生类的 std::visit | P2162R2 |  | 13 | 19.20** |  |  |  |
放松 time_point<>::clock 的要求 | P2212R2 | N/A |  | N/A |  |  |  |
DR：条件性借用范围 | P2017R1 |  |  | 19.30* |  |  |  |
DR：修复输入范围适配器与 std::counted_iterator | P2259R1 |  |  |  |  |  |  |
在分配器接口中提供大小反馈 | P0401R6 |  |  |  |  |  |  |
<spanstream> ：以 std::span 为基础的字符串流 | P0448R4 |  |  |  |  |  |  |
std::out_ptr()、 std::inout_ptr() | P1132R8 |  |  |  |  |  |  |
constexpr type_info::operator==() | P1328R1 |  |  |  |  |  |  |
std::stack 与 std::queue 的迭代器对构造函数 | P1425R4 |  |  |  |  |  |  |
容器推导指引中分配器的非推导语境 | P1518R2 |  |  |  |  |  |  |
ranges::starts_with() 与 ranges::ends_with() | P1659R3 | 11 |  |  |  |  |  |
禁止 basic_string 与 basic_string_view 从 nullptr 构造 | P2166R1 |  |  |  |  |  |  |
std::invoke_r() | P2136R3 |  |  |  |  |  |  |
basic_string_view 的范围构造函数 | P1989R2 |  |  |  |  |  |  |
pair 的转发构造函数的默认模板实参 | P1951R1 |  |  |  |  |  |  |
移除垃圾收集与基于可达性的泄漏检测（库支持） | P2186R2 |  |  |  |  |  |  |
DR：join_view 应结合所有范围 | P2328R1 |  |  |  |  |  |  |
DR：view 不要求 default_initializable | P2325R3 |  |  |  |  |  |  |
DR：范围适配器对象按值绑定实参 | P2281R1 |  |  | 19.29 (16.10)* |  |  |  |
DR：std::optional 与 std::variant 的 constexpr | P2231R1 |  |  |  |  |  |  |
DR：std::format() 改进 | P2216R3 |  |  |  |  |  |  |
DR：lazy_split_view 与重新设计的 split_view | P2210R2 |  |  |  |  |  |  |
C++23 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库

C++20 功能特性

C++20 核心语言功能特性

C++20 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc
允许 lambda 捕获 [=, this] | P0409R2 | 8 | 6 | 19.22* | 10.0.0* | 5.1 |  |  |  |  |  | 20.7 |
__VA_OPT__ | P0306R4 P1042R1 | 8 (部分)* 10 | 9 | 19.25* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
指派初始化器 | P0329R4 | 4.7 (部分)* 8 | 3.0 (部分)* 10 | 19.21* | (部分)* | 5.1 |  |  |  |  |  | 20.7 |
泛型 lambda 的模板形参列表 | P0428R2 | 8 | 9 | 19.22* | 11.0.0* | 5.1 |  |  |  |  |  | 20.7 |
位域的默认成员初始化器 | P0683R1 | 8 | 6 | 19.25* | 10.0.0* | 5.1 |  |  |  |  |  | 20.7 |
类模板实参推导中的 intializer_list 构造函数 | P0702R1 | 8 | 6 | 19.14* | 是 | 5.0 |  |  |  |  |  | 20.7 |
const& 限定的成员指针 | P0704R1 | 8 | 6 | 19.14* | 是 | 5.0 |  |  |  |  |  | 20.7 |
概念 | P0734R0 | 6 (仅 TS) 10 | 10 | 19.23* (部分)* |  |  |  |  |  |  |  | 20.11 |
不求值语境中的 lambda | P0315R4 | 9 |  | 19.28 (16.8)* |  |  |  |  |  |  |  |  |
三路比较运算符 | P0515R3 | 10 | 8 (部分) 10 | 19.20* |  | 5.1 |  |  |  |  |  | 20.7 |
DR ：简化隐式 lambda 捕获 | P0588R1 | 8 |  | 19.24* |  | 5.1 |  |  |  |  |  | 20.7 |
基于范围的 for 的初始化语句 | P0614R1 | 9 | 8 | 19.25* | 11.0.0* | 6.0 |  |  |  |  |  | 20.11 |
可默认构造与可赋值的无状态 lambda | P0624R2 | 9 | 8 | 19.22* | 10.0.1* | 5.1 |  |  |  |  |  |  |
预置复制构造函数与 const 的不匹配 | P0641R2 | 9 | 8 | 19.0 (2015)* | 10.0.1* | 5.1 |  |  |  |  |  | 20.7 |
特化上的访问检查 | P0692R1 | 是 | 8 (部分) | 19.26* | 10.0.1* (部分) | 5.1 |  |  |  |  |  | 20.7 |
ADL 与不可见的函数模板 | P0846R0 | 9 | 9 | 19.21* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
DR：指定 constexpr 函数定义何时为常量求值所需要 | P0859R0 | 5.2 (部分)* 9 | 8 | 19.27* (部分)* |  |  |  |  |  |  |  |  |
属性 [[likely]] 与 [[unlikely]] | P0479R5 | 9 | 12 | 19.26* |  | 5.1 |  |  |  |  |  | 20.7 |
使 typename 更可选 | P0634R3 | 9 |  | 19.29 (16.10)* |  | 5.1 |  |  |  |  |  | 20.7 |
Lambda 初始化捕获中的包展开 | P0780R2 | 9 | 9 | 19.22* | 11.0.3* | 6.1 |  |  |  |  |  | 20.11 |
属性 [[no_unique_address]] | P0840R2 | 9 | 9 | 19.28 (16.9)** | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
条件性平凡的特殊成员函数 | P0848R3 | 10 |  | 19.28 (16.8)* |  | 6.1 |  |  |  |  |  | 20.11 |
DR：放松结构化绑定定制点查找规则 | P0961R1 | 8 | 8 | 19.21* | 10.0.1* | 5.1 |  |  |  |  |  |  |
DR：放松范围 for 循环定制点查找规则 | P0962R1 | 8 |  |  |  | 5.1 |  |  |  |  |  |  |
DR ：允许到可访问成员的结构化绑定 | P0969R0 | 8 | 8 | 19.21* | 10.0.1* | 5.1 |  |  |  |  |  |  |
销毁的 operator delete | P0722R3 | 9 | 6 | 19.27* | 10.0.0* | 6.1 |  |  |  |  |  |  |
非类型模板形参非类型模板形参中的类类型 | P0732R2 | 9 | 12 (部分) | 19.26*(部分)* 19.28 (16.9)* |  | 6.2 |  |  |  |  |  |  |
弃用经由 [=] 隐式捕获 this | P0806R2 | 9 | 7 | 19.22* |  | 5.1 |  |  |  |  |  | 20.7 |
explicit(bool) | P0892R2 | 9 | 9 | 19.24* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
集成功能特性测试宏 | P0941R2 | 5 | 3.4 | 19.15* (部分) 19.20* | 是 | 5.0 |  |  |  |  |  | 20.7 |
禁止有用户声明构造函数的聚合体 | P1008R1 | 9 | 8 | 19.20* | 10.0.1* | 5.1 |  |  |  |  |  | 20.7 |
constexpr 虚函数 | P1064R0 | 9 | 9 | 19.28 (16.9)* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
比较的一致性改进 | P1120R0 | 10 | 8 (部分) 10 | 19.22* | 10.0.1* (部分) | 5.1 |  |  |  |  |  | 20.7 |
char8_t | P0482R6 | 9 | 7 | 19.22* | 10.0.0* | 5.1 |  |  |  |  |  | 20.7 |
std::is_constant_evaluated() | P0595R2 | 9 | 9 | 19.25* | 11.0.3* | 5.1 | 19.1 |  |  |  |  |  |
constexpr 函数中的 try-catch 块 | P1002R1 | 9 | 8 | 19.25* | 10.0.1* | 5.1 |  |  |  |  |  | 20.7 |
立即函数（consteval） | P1073R3 | 10 (部分)* 11 | 11 (部分) | 19.28 (16.8)** (部分) 19.29 (16.10)* |  | 5.1 |  |  |  |  |  | 20.7 |
嵌套内联命名空间 | P1094R2 | 9 | 8 | 19.27* | 10.0.1* | 5.1 |  |  |  |  |  | 20.7 |
有约束 声明的另一种手段 | P1141R2 | 10 | 10 | 19.26* (部分) 19.28 (16.9)* |  | 6.1 |  |  |  |  |  | 20.11 |
有符号整数为补码 | P1236R1 | 9 |  | 是 | 11.0.3* | N/A |  |  |  |  |  | 是 |
constexpr dynamic_cast 及多态 typeid | P1327R1 | 10 | 9 | 19.29 (16.10)* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
在 constexpr 内更改联合体的活跃成员 | P1330R0 | 9 | 9 | 19.10* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
协程 | P0912R5 | 10 | 8 (部分) | 19.0 (2015)* (部分) 19.10* (仅 TS) 19.28 (16.8)* | 10.0.1* (部分) | 5.1 |  |  |  |  |  |  |
括号形式的聚合体初始化 | P0960R3 | 10 |  | 19.28 (16.8)* |  | 5.1 |  |  |  |  |  | 20.7 |
DR： new 表达式中的数组大小推导 | P1009R2 | 11 | 9 | 19.27* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
模块 | P1103R3 | 11 (部分) | 8 (部分) | 19.0 (2015)* (部分) 19.10* (仅 TS) 19.28 (16.8)* | 10.0.1* (部分) |  |  |  |  |  |  |  |
更强的 Unicode 要求 | P1041R4 P1139R2 | 10 | 是 | 19.0 (2015)* (P1041R4) 19.26* (P1139R2) | 是 | N/A |  |  |  |  |  |  |
<=> != == | P1185R2 | 10 | 10 | 19.22* |  | 5.1 |  |  |  |  |  | 20.7 |
DR ：拥有不同异常说明的显式默认化函数 | P1286R2 | 10 | 9 | 19.28 (16.8)* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
结构化绑定的 lambda 捕获与存储类说明符 | P1091R3 P1381R1 | 10 | 8 (部分) | 19.11*(P1381R1) 19.24*(P1091R3) | 10.0.1* (部分) | 5.1 |  |  |  |  |  | 20.7 |
容许转换到未知边界数组 | P0388R4 | 10 |  | 19.27* |  | 6.0 |  |  |  |  |  | 20.11 |
constexpr 容器操作 | P0784R7 | 10 | 10 | 19.28 (16.9)* |  | 6.0 |  |  |  |  |  | 20.11 |
弃用 volatile 的某些用法 | P1152R4 | 10 | 10 | 19.27* |  | 6.0 |  |  |  |  |  | 20.11 |
constinit | P1143R2 | 10 | 10 | 19.29 (16.10)* |  | 6.1 |  |  |  |  |  | 20.11 |
弃用下标中的逗号运算符 | P1161R3 | 10 | 9 | 19.25* | 11.0.3* | 6.0 |  |  |  |  |  | 20.11 |
带消息的 [[nodiscard]] | P1301R4 | 10 | 9 | 19.25* | 11.0.3* | 6.0 |  |  |  |  |  | 20.11 |
constexpr 函数中的平凡默认初始化 | P1331R2 | 10 | 10 | 19.27* |  | 6.1 |  |  |  |  |  | 20.11 |
constexpr 函数中的不求值 asm 声明 | P1668R1 | 10 | 10 | 19.28 (16.9)* |  | 6.1 |  |  |  |  |  | 20.11 |
using enum | P1099R5 | 11 | 13 | 19.24* |  | 6.3 |  |  |  |  |  |  |
对指定的比较类别合成三路比较 | P1186R3 | 11 | 10 | 19.24* |  | 6.0 |  |  |  |  |  | 20.11 |
DR：构造函数的 [[nodiscard]] | P1771R1 | 10 | 9 | 19.24* | 11.0.3* | 6.0 |  |  |  |  |  | 20.11 |
别名模板的类模板实参推导 | P1814R0 | 10 |  | 19.27* |  |  |  |  |  |  |  |  |
聚合类的类模板实参推导 | P1816R0 P2082R1 | 10(P1816R0) 11(P2082R1) |  | 19.27* |  |  |  |  |  |  |  |  |
DR ：更多局部对象与右值引用的隐式移动 | P1825R0 | 11* | 13 | 19.24* |  | 6.0 |  |  |  |  |  | 20.11 |
允许默认化按值比较 | P1946R0 | 10 | 10 | 19.25* |  | 6.1 |  |  |  |  |  | 20.11 |
移除 std::weak_equality 与 std::strong_equality | P1959R0 | 10 | 10 | 19.25* |  | 6.1 |  |  |  |  |  | 20.11 |
非类型模板形参的不一致 | P1907R1 | 10 (部分) 11 | 12 (部分) | 19.26* |  | 6.2 |  |  |  |  |  |  |
DR：伪析构函数终结对象生存期 | P0593R6 | 11 | 11 | 是 |  | N/A |  |  |  |  |  |  |
DR ：应认为从 T* 到 bool 的转换为窄化 | P1957R2 | 10* 11* | 11 | 19.27* |  | 6.1 |  |  |  |  |  |  |
C++20 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc

C++20 库功能特性

C++20 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
std::endian | P0463R1 | 8 | 7 | 19.22* | 10.0.0* |  |  |
扩展 std::make_shared() 以支持数组 | P0674R1 |  |  | 19.27* |  |  |  |
浮点原子类型 | P0020R6 | 10 |  | 19.22* |  |  |  |
同步缓冲（std::basic_osyncstream） | P0053R7 | 11 |  | 19.29 (16.10)* |  |  |  |
<algorithm> 与 <utility> 的 constexpr | P0202R3 | 10 | 8 (部分) 12 | 19.26* | 10.0.1* (部分) |  |  |
<complex> 的更多 constexpr | P0415R1 | 9 | 7 (部分) | 19.27* | 10.0.0* (部分) |  |  |
使 std::memory_order 为有作用域枚举 | P0439R0 | 9 | 9 | 19.25* | 11.0.3* |  |  |
字符串 前缀与后缀检查： string (_view) ::starts_with/ends_with | P0457R2 | 9 | 6 | 19.21* | 10.0.0* |  |  |
=operator<=> 的库支持 <compare> | P0768R1 | 10 | 7 (部分) 12 | 19.20* (部分) 19.28 (16.9)* | 10.0.0* (部分) |  |  |
std::remove_cvref | P0550R2 | 9 | 6 | 19.20* | 10.0.0* |  |  |
标准库中的 [[nodiscard]] | P0600R1 | 9 | 7 (部分) | 19.13* (部分) 19.22* | 10.0.0* (部分) |  |  |
于数值算法使用 std::move | P0616R0 | 9 | 12 | 19.23* |  |  |  |
转换指针为裸指针的工具 | P0653R2 | 8 | 6 | 19.22* | 是 |  |  |
原子 std::shared_ptr 与 std::weak_ptr | P0718R2 |  |  | 19.27* |  |  |  |
std::span | P0122R7 | 10 | 7 | 19.26* | 10.0.0* |  |  |
日历与时区 | P0355R7 | 11 (部分) | 7 (部分) | 19.29 (16.10)* | 10.0.0* (部分) |  |  |
<version> | P0754R2 | 9 | 7 | 19.22* | 10.0.0* |  |  |
比较无序容器 | P0809R0 |  | 是 | 16.0* | 是 |  |  |
常量表达式迭代器 (ConstexprIterator) 要求 | P0858R0 | 9 |  | 19.11* |  |  |  |
std::basic_string::reserve() 不应收缩 | P0966R1 | 11 | 8 | 19.25* | 10.0.1* |  |  |
带填充位的原子比较交换 | P0528R3 |  |  | 19.28 (16.8)* |  |  |  |
std::atomic_ref | P0019R8 | 10 |  | 19.28 (16.8)* |  |  |  |
关联容器的 contains() 成员函数，如 std::map::contains() | P0458R2 | 9 | 9 (部分)* 13 | 19.21* | 11.0.3* |  |  |
DR ：逐片构造的受保证复制消除 | P0475R1 | 9 | 是 | 19.29 (16.10)* | 是 |  |  |
std::bit_cast() | P0476R2 | 11 |  | 19.27* |  |  |  |
整数的 2 的幂的运算： std::bit_ceil()、 std::bit_floor()、 std::bit_width()、 std::has_single_bit() | P0556R3 P1956R1 | 9 (P0556R3) 10 (P1956R1) | 9 (P0556R3) 12 (P1956R1) | 19.25* (P0556R3)* 19.27* (P1956R1)* 19.28 (16.8)* |  |  |  |
改进擦除式算法的返回值 | P0646R1 | 9 | 10 | 19.21* |  |  |  |
std::destroying_delete | P0722R3 | 9 | 9 | 19.27* | 11.0.3* |  |  |
std::is_nothrow_convertible | P0758R1 | 9 | 9 | 19.23* | 11.0.3* |  |  |
添加 std::shift_left/right 到 <algorithm> | P0769R2 | 10 | 12 | 19.21* |  |  |  |
std::swap() 与 swap 相关函数的 constexpr | P0879R0 | 10 | 12 (部分) 13 | 19.26* |  |  |  |
std::type_identity | P0887R1 | 9 | 8 | 19.21* | 10.0.1* |  |  |
概念库 | P0898R3 | 10 | 13 | 19.23* |  |  |  |
std::array 的 constexpr 比较运算符 | P1023R0 | 10 | 8 | 19.27* | 10.0.1* |  |  |
std::unwrap_ref_decay 与 std::unwrap_reference | P0318R1 | 9 | 8 | 19.21* | 10.0.1* |  |  |
std::bind_front() | P0356R5 | 9 | 13 | 19.25* |  |  |  |
不完整类型的 std::reference_wrapper | P0357R3 | 9 | 8 | 19.26* | 10.0.1* |  |  |
修正 operator>>(basic_istream&, CharT*) | P0487R1 | 11 | 8 | 19.23* | 10.0.1* |  |  |
char8_t 的库支持 | P0482R6 | 9 | 8 (部分)* | 19.22* |  |  |  |
实现使用分配器 构造的工具函数 | P0591R4 | 9 |  | 19.29 (16.10)* |  |  |  |
DR： std::variant 与 std::optional 应传播复制/移动平凡性 | P0602R4 | 8.3 | 8 | 19.11* | 10.0.1* |  |  |
理智的 std::variant 转换构造函数 | P0608R3 | 10 | 9 | 19.29 (16.10)* | 11.0.3* |  |  |
std::function 的移动构造函数应为 noexcept | P0771R1 | 7.2 | 6 | 19.22* | 是 |  |  |
一个 范围 提案 | P0896R4 | 10 | 13 (部分) | 19.29 (16.10)* |  |  |  |
无序容器的异质查找 | P0919R3 P1690R1 | 11 | 12 | 19.23* (P0919R3) 19.25* (P1690R1) |  |  |  |
<chrono> zero()、 min() 及 max() 应为 noexcept | P0972R0 | 9 | 8 | 19.14* | 10.0.1* |  |  |
std::pointer_traits 中的 constexpr | P1006R1 | 9 | 8 | 19.26* | 10.0.1* |  |  |
std::assume_aligned() | P1007R3 | 9* 11 |  | 19.28 (16.9)* |  |  |  |
使用默认初始化的智能指针创建（如 make_unique_for_overwrite） | P1020R1 P1973R1 |  |  | 19.28 (16.9)* |  |  |  |
杂项 constexpr 小部分 | P1032R1 | 10 | 13 | 19.28 (16.8)* |  |  |  |
移除 std::span 的比较运算符 | P1085R2 | 10 | 8 | 19.26* | 10.0.1* |  |  |
使 operator+(basic_string) 的有状态分配器传播更加一致 | P1165R1 | 10 |  | 19.26* |  |  |  |
一致容器擦除，如 std::erase(std::vector) 或 std::erase_if(std::map) | P1209R0 P1115R3 | 9 (P1209R0) 10 (P1115R3) | 8 (P1209R0) 11 (P1115R3) | 19.25* (P1209R0) 19.27* (P1115R3) | 10.0.1* (P1209R0) |  |  |
标准库头文件单元 | P1502R1 | 11 |  | 19.29 (16.10)* |  |  |  |
polymorphic_allocator<> 作为词汇类型 | P0339R6 | 9 |  | 19.28 (16.9)* |  |  |  |
std::execution::unseq | P1001R2 | 9 |  | 19.28 (16.8)* |  |  |  |
std::lerp() 与 std::midpoint() | P0811R3 | 9 | 9 | 19.23* (部分) 19.28 (16.8)* | 11.0.3* |  |  |
std::span 的实用性增强 | P1024R3 | 10 | 9 | 19.26* | 11.0.3* |  |  |
DR：使 create_directory() 自发 | P1164R1 | 8.3 | 12 | 19.20* |  |  |  |
std::ssize() 与 std::span 的无符号长度 | P1227R2 | 10 | 9 | 19.25* | 11.0.3* |  |  |
有界及无界数组特征 | P1357R1 | 9 | 9 | 19.25* | 11.0.3* |  |  |
std::to_array() | P0325R4 | 10 | 10 | 19.25* |  |  |  |
std::basic_stringbuf 缓冲的有效访问 | P0408R7 | 11 |  | 19.29 (16.10)* |  |  |  |
布局 兼容性与指针 可互转换性特征 | P0466R5 |  |  | 19.29 (16.10)** |  |  |  |
位操作： std:: rotl()、 rotr()、 countl_zero()、 countl_one()、 countr_zero()、 countr_one()、 popcount() | P0553R4 | 9 | 9 | 19.25** 19.28 (16.8)* | 11.0.3* |  |  |
数学常数 | P0631R8 | 10 | 11 | 19.25* |  |  |  |
文本格式化 | P0645R10 |  |  | 19.29 (16.10)* |  |  |  |
std::stop_token 与 std::jthread | P0660R10 | 10 |  | 19.28 (16.9)* |  |  |  |
constexpr std::allocator 及相关工具 | P0784R7 | 10 | 12 | 19.29 (16.10)* |  |  |  |
constexpr std::string | P0980R1 |  |  | 19.29 (16.10)* |  |  |  |
constexpr std::vector | P1004R2 |  |  | 19.29 (16.10)* |  |  |  |
输入范围适配器 | P1035R7 | 10 |  | 19.29 (16.10)* |  |  |  |
constexpr std::invoke() 及相关工具 | P1065R2 | 10 | 12 | 19.28 (16.8)* |  |  |  |
原子等待与提醒、 std::counting_semaphore 、 std::latch 及 std::barrier | P1135R6 | 11 | 11 | 19.28 (16.8)* |  |  |  |
std::source_location | P1208R6 | 11 |  | 19.29 (16.10)* |  |  |  |
添加 <=> 到标准库 | P1614R2 | 10 |  | 19.29 (16.10)* |  |  |  |
std::atomic 与 std::atomic_flag 的 constexpr 默认构造函数 | P0883R2 | 10 | 13 | 19.26* |  |  |  |
数值算法的 constexpr | P1645R1 | 10 | 12 | 19.26* |  |  |  |
安全整数比较 | P0586R2 | 10 | 13 | 19.27* |  |  |  |
C++20 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库

C++17 功能特性

C++17 核心语言功能特性

C++17 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc
直接列表初始化的新 auto 规则 | N3922 | 5 | 3.8 | 19.0 (2015)* | 是 | 4.10.1 | 17.0 |  |  | 10.3 |  | 17.7 |
无消息的 static_assert | N3928 | 6 | 2.5 | 19.10* | 是 | 4.12 | 18.0 |  |  | 10.3 |  | 17.7 |
模板模板形参中的 typename | N4051 | 5 | 3.5 | 19.0 (2015)* | 是 | 4.10.1 | 17.0 |  |  | 10.3 |  | 17.7 |
移除三标符 | N4086 | 5 | 3.5 | 16.0* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
嵌套命名空间定义 | N4230 | 6 | 3.6 | 19.0 (Update 3)* | 是 | 4.12 | 17.0 |  |  | 10.3 |  | 17.7 |
命名空间和枚举项的属性 | N4266 | 4.9 (部分)* 6 | 3.6 | 19.0 (2015)* | 是 | 4.11 | 17.0 |  |  | 10.3 |  | 17.7 |
u8 字符字面量 | N4267 | 6 | 3.6 | 19.0 (2015)* | 是 | 4.11 | 17.0 |  |  | 10.3 |  | 17.7 |
允许所有非类型模板实参的常量求值 | N4268 | 6 | 3.6 | 19.12* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
折叠表达式 | N4295 | 6 | 3.6 | 19.12* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
一元折叠表达式和空形参包 | P0036R0 | 6 | 3.9 | 19.12* | 是 | 4.14 |  |  |  | 10.3 |  |  |
移除 register 关键字的已弃用用法 | P0001R1 | 7 | 3.8 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
移除已弃用的 operator++(bool) | P0002R1 | 7 | 3.8 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
令异常规定为类型系统的一部分 | P0012R1 | 7 | 4 | 19.12* | 是 | 4.14 | 19.0 |  |  | 10.3 |  |  |
有基类的类的聚合初始化 | P0017R1 | 7 | 3.9 | 19.14* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
预处理器条件中的 __has_include | P0061R1 | 5 | 是 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
DR ：继承构造函数的新规定 (DR1941 等) | P0136R1 | 7 | 3.9 | 19.14* | 是 | 6.1 |  |  |  | 10.3 |  | 19.1 |
*this 的 lambda 捕获 | P0018R3 | 7 | 3.9 | 19.11* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
枚举的直接列表初始化 | P0138R2 | 7 | 3.9 | 19.11* | 是 | 4.14 | 18.0 |  |  | 10.3 |  |  |
constexpr lambda 表达式 | P0170R1 | 7 | 5 | 19.11* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
基于范围 for 的相异 begin 和 end 类型 | P0184R0 | 6 | 3.9 | 19.10* | 是 | 4.12 | 18.0 |  |  | 10.3 |  | 17.7 |
[[fallthrough]] 属性 | P0188R1 | 7 | 3.9 | 19.10* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
[[nodiscard]] 属性 | P0189R1 | 7 | 3.9 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
[[maybe_unused]] 属性 | P0212R1 | 7 | 3.9 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
十六进制浮点字面量 | P0245R1 | 3.0 | 是 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
使用属性命名空间而不重复 | P0028R4 | 7 | 3.9 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
过对齐数据的动态内存分配 | P0035R4 | 7 | 4 | 19.12* | 10.0.0* | 4.14 |  |  |  | 10.3 |  |  |
类模板实参推导 | P0091R3 | 7 | 5 | 19.14* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  | 19.1 |
具有 auto 类型的非类型模板形参 | P0127R2 | 7 | 4 | 19.14* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  | 19.1 |
受保证的复制消除 | P0135R1 | 7 | 4 | 19.13* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  | 19.1 |
替换含引用成员的类对象 | P0137R1 | 7 | 6 | 19.14* | 是 | 5.0 |  |  |  | 10.3 |  |  |
更严格的表达式求值顺序 | P0145R3 | 7 | 4 | 19.14* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
结构化绑定 | P0217R3 | 7 | 4 | 19.11* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
忽略未知属性 | P0283R2 | 是 | 3.9 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
constexpr if 语句 | P0292R2 | 7 | 3.9 | 19.11* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
if 和 switch 的初始化语句 | P0305R1 | 7 | 3.9 | 19.11* | 是 | 4.14 | 18.0 |  |  | 10.3 |  | 18.1 |
inline 变量 | P0386R2 | 7 | 3.9 | 19.12* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
移除动态异常说明 | P0003R5 | 7 | 4 | 19.10* | 是 | 4.14 | 19.0 |  |  | 10.3 |  |  |
using 声明中的包展开 | P0195R2 | 7 | 4 | 19.14* | 是 | 5.0 |  |  |  | 10.3 |  |  |
DR ：模板模板实参的匹配排除了兼容的模板 | P0522R0 | 7 | 4 | 19.12* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
C++17 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc

C++17 库功能特性

C++17 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Intel 并行 STL | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
std::void_t | N3911 | 6 | 3.6 | 19.0 (2015)* | 是 | N/A |  | 10.3 |
std::uncaught_exceptions() | N4259 | 6 | 3.7 | 19.0 (2015)* | 是 | N/A |  | 10.3 |
std::size() 、 std::empty() 与 std::data() | N4280 | 6 | 3.6 | 19.0 (2015)* | 是 | N/A |  | 10.3 |
改进 std::pair 与 std::tuple | N4387 | 6 | 4 | 19.0 (Update 2)* | 是 | N/A |  | 10.3 |
std::bool_constant | N4389 | 6 | 3.7 | 19.0 (2015)* | 是 | N/A |  | 10.3 |
std::shared_mutex （无时限） | N4508 | 6 | 3.7 | 19.0 (Update 2)* | 是 | N/A |  | 10.3 |
类型特性变量模板 | P0006R0 | 7 | 3.8 | 19.0 (Update 2)* | 是 | N/A |  | 10.3 |
逻辑运算符类型特性 | P0013R1 | 6 | 3.8 | 19.0 (Update 2)* | 是 | N/A |  | 10.3 |
标准化并行 TS | P0024R2 | 9* |  | 19.14* |  | 18.0* |  |  |
std::clamp() | P0025R0 | 7 | 3.9 | 19.0 (Update 3)* | 10.0.0* | N/A |  | 10.3 |
硬件干涉大小 | P0154R1 |  |  | 19.11* |  | N/A |  |  |
(nothrow-)swappable 特性 | P0185R1 | 7 | 3.9 | 19.0 (Update 3)* | 10.0.0* | N/A |  | 10.3 |
文件系统库 | P0218R1 | 8 | 7 | 19.14* | 11.0.0* | N/A |  | 10.3 |
std::string_view | N3921 P0220R1 | 7 | 4 | 19.10* | 10.0.0* | N/A |  | 10.3 |
std::any | P0220R1 | 7 | 4 | 19.10* | 10.0.0* | N/A |  | 10.3 |
std::optional | P0220R1 | 7 | 4 | 19.10* | 10.0.0* | N/A |  | 10.3 |
多态内存资源 | P0220R1 | 9 |  | 19.13* |  | N/A |  | 10.3 |
数学特殊函数 | P0226R1 | 7 |  | 19.14* |  | N/A |  | 10.3 |
C++17 应指代 C11 而非 C99 | P0063R3 | 9 | 7 | 19.0 (2015)* (部分)* |  | N/A |  | 10.3 |
接合 map 与 set | P0083R3 | 7 | 8 | 19.12* | 10.0.0* | N/A |  |  |
std::variant | P0088R3 | 7 | 4 | 19.10* | 10.0.0* | N/A |  | 10.3 |
std::make_from_tuple() | P0209R2 | 7 | 3.9 | 19.10* | 是 | N/A |  | 10.3 |
std::has_unique_object_representations | P0258R2 | 7 | 6 | 19.11* | 是 | N/A |  | 10.3 |
std::gcd() 与 std::lcm() | P0295R0 | 7 | 4 | 19.11* | 是 | N/A |  | 10.3 |
std::not_fn | P0005R4 P0358R1 | 7 | 3.9 | 19.12* |  | N/A |  | 10.3 |
初等字符串转换 | P0067R5 | 8 (无浮点) | 7 (无浮点) | 19.14* (无浮点)* 19.24* |  | N/A |  |  |
有数组支持的 std::shared_ptr 与 std::weak_ptr | P0414R2 | 7 | 11 | 19.12* |  | N/A |  | 10.3 |
std::scoped_lock | P0156R2 | 7 | 5 | 19.11* | 是 | N/A |  | 10.3 |
std::byte | P0298R3 | 7 | 5 | 19.11* | 是 | N/A |  | 10.3 |
std::is_aggregate | LWG2911 | 7 | 5 | 19.15* | 是 | N/A |  | 10.3 |
C++17 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Intel 并行 STL | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库

C++14 功能特性

C++14 核心语言功能特性

C++14 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc
按语境转换的遣词调整 | N3323 | 4.9 | 3.4 | 18.0* | 是 | 4.9 | 16.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 16.1 | 9.0
二进制字面量 | N3472 | 4.3 (GNU) 4.9 | 2.9 | 19.0 (2015)* | 是 | 4.10 | 11.0 | 13.1.2* | 5.14 | 10.3 | 8.6 | 2015 | 9.0
decltype(auto)，普通函数的返回类型推导 | N3638 | 4.8 (部分)* 4.9 | 是 | 19.0 (2015)* | 是 | 4.9 | 15.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 16.1 | 9.0
带初始化/泛化的 lambda 捕获 (init-capture) | N3648 | 4.5 (部分) 4.9 | 3.4 | 19.0 (2015)* | 是 | 4.10 | 15.0 | 16.1.1* | 5.15 | 10.3 | 8.6 | 16.1 | 9.0
泛型 lambda 表达式 | N3649 | 4.9 | 3.4 | 19.0 (2015)* | 是 | 4.10 | 16.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 16.1 | 9.0
变量模板 | N3651 | 5 | 3.4 | 19.0 (Update 2)* | 是 | 4.11 | 17.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 17.4 | 9.0
扩展的 constexpr | N3652 | 5 | 3.4 | 19.10* | 是 | 4.11 | 17.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 17.4 | 9.0
带成员初始化器的聚合体 (NSDMI) | N3653 | 5 | 3.3 | 19.10* | 是 | 4.9 | 16.0 | 16.1.1* | 5.14 | 10.3 | 8.6 | 16.1 | 9.0
忽略/扩展内存分配 | N3664 | N/A | 3.4 | N/A | 是 | N/A | N/A | N/A | N/A | 10.3 | 8.6 | 17.4 | N/A
[[deprecated]] 属性 | N3760 | 4.9 | 3.4 | 19.0 (2015)* | 是 | 4.9 | 15.0* 16.0 | 13.1.2* | 5.14 | 10.3 | 8.6 | 16.1 | 9.0
具大小解分配 | N3778 | 5 | 3.4 | 19.0 (2015)* | 是 | 4.10.1 | 17.0 | 16.1.1* | 5.14 | 10.3 | 8.6 | 16.1 |
单引号作为数位分隔符 | N3781 | 4.9 | 3.4 | 19.0 (2015)* | 是 | 4.10 | 16.0 | 13.1.2* | 5.14 | 10.3 | 8.6 | 2015 | 9.0
C++14 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc

C++14 库功能特性

C++14 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
<complex> 的 constexpr | N3302 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
通透的运算符函数对象 | N3421 | 4.9 | 3.4 | 18.0* | 是 | 5.15 | 10.3 | 8.6
std::result_of 与 SFINAE | N3462 | 5 | 是 | 19.0 (Update 2)* | 是 | 5.15 | 10.3 | 8.6
<chrono> 的 constexpr | N3469 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
<array> 的 constexpr | N3470 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
<initializer_list> 、 <utility> 和 <tuple> 的 constexpr | N3471 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
改进的 std::integral_constant | N3545 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
<chrono> 和 <string> 的用户定义字面量 | N3642 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
空向前迭代器 | N3644 | 5 (部分) | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::quoted | N3654 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::make_unique | N3656 | 4.9 | 3.4 | 18.0* | 是 | 5.15 | 10.3 | 8.6
异质关联查找 | N3657 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::integer_sequence | N3658 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::shared_timed_mutex | N3659 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::exchange | N3668 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
修正无 const 的 constexpr 成员函数 | N3669 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::get<T>() | N3670 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
双范围的 std::equal 、 std::is_permutation 、 std::mismatch | N3671 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
C++14 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库

C++11 功能特性

C++11 核心语言功能特性

C++11 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc | HP aCC | Digital Mars C++
C99 预处理器 | N1653 | 4.3 | 是 | 19.0 (2015)* (部分)* 19.26* | 是 | 4.1 | 11.1 | 10.1 | 5.9 | 是 | 8.4 | 2015 | 7.0 | A.06.25 | 是
static_assert | N1720 | 4.3 | 2.9 | 16.0* | 是 | 4.1 | 11.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 | 8.52
右角括号 | N1757 | 4.3 | 是 | 14.0* | 是 | 4.1 | 11.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
扩展的 friend 声明 | N1791 | 4.7 | 2.9 | 16.0* (部分) 18.0* | 是 | 4.1 | 11.1 (部分) 12.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
long long | N1811 | 是 | 是 | 14.0* | 是 | 是 | 是 | 是 | 是 | 是 | 8.4 | 2015 | 7.0 | 是 | 是
类型特征的编译器支持 | N1836 | 4.3 | 3.0 | 14.0* | 是 | 4.0 | 10.0 | 13.1.3 | 5.13 | 是 | 8.4 | 2015 |  | 6.16 |
auto | N1984 | 4.4 | 是 | 16.0* | 是 | 3.9 | 11.0 (v0.9) 12.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
委托构造函数 | N1986 | 4.7 | 3.0 | 18.0* | 是 | 4.7 | 14.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
extern template | N1987 | 3.3 | 是 | 12.0* | 是 | 3.9 | 9.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
constexpr | N2235 | 4.6 | 3.1 | 19.0 (2015)* | 是 | 4.6 | 13.0 (部分) 14.0 | 12.1 (部分) 13.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
模板别名 | N2258 | 4.7 | 3.0 | 18.0* | 是 | 4.2 | 12.1 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
char16_t 与 char32_t | N2249 | 4.4 | 2.9 | 19.0 (2015)* | 是 | 4.4 | 12.1* 14.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 | 8.52
alignas | N2341 | 4.8 | 3.0 | 19.0 (2015)* | 是 | 4.8 | 15.0 | 13.1.2* | 5.13 | 是 | 8.6 | 2015 | 7.0 |  |
alignof | N2341 | 4.5 | 2.9 | 19.0 (2015)* | 是 | 4.8 | 15.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
默认化与被删除的函数 | N2346 | 4.4 | 3.0 | 18.0* | 是 | 4.1 | 12.0 | 13.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
强类型 enum | N2347 | 4.4 | 2.9 | 17.0* | 是 | 4.0 | 13.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
原子操作 | N2427 | 4.4 | 3.1 | 17.0* | 是 | Yes | 13.0 | 13.1.2* | 5.14 | 是 | 8.4 | 2015 |  |  |
nullptr | N2431 | 4.6 | 2.9 | 16.0* | 是 | 4.2 | 12.1 | 13.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 | 8.52
显式转换运算符 | N2437 | 4.5 | 3.0 | 18.0* | 是 | 4.4 | 13.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
引用限定符 | N2439 | 4.8.1 | 2.9 | 19.0 (2015)* | 是 | 4.7 | 14.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
Unicode 字符串字面量 | N2442 | 4.4 | 3.0 | 19.0 (2015)* | 是 | 4.7 | 11.0* | 10.1* 13.1.1* | 5.7 | 是 | 8.4 | 2015 | 7.0 | A.06.28 | 8.52
未处理的字符串字面量 | N2442 | 4.5 | 是 | 18.0* | 是 | 4.7 | 14.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 | 8.52
内联命名空间 | N2535 | 4.4 | 2.9 | 19.0 (2015)* | 是 | 4.5 | 14.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
继承构造函数 | N2540 | 4.8 | 3.3 | 19.0 (2015)* | 是 | 4.8 | 15.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
尾随的函数返回类型 | N2541 | 4.4 | 2.9 | 16.0* | 是 | 4.1 | 12.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
无限制的联合体 | N2544 | 4.6 | 3.0 | 19.0 (2015)* | 是 | 4.6 | 14.0* | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
变参数模板 | N2242 N2555 | 4.3 (N2242) 4.4 | 2.9 | 18.0* | 是 | 4.3 (N2242) 4.3 | 12.1 | 11.1 (N2242) | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
表达式 SFINAE | N2634 | 4.4 | 2.9 | 19.14* | 是 | 4.2 | 12.1 |  |  | 是 | 8.4 | 2015 | 7.0 |  |
局部与无名类型作为模板形参 | N2657 | 4.5 | 2.9 | 16.0* | 是 | 4.2 | 12.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
线程局部存储 | N2659 | 4.4 (部分) 4.8 | 3.3* | 16.0* (部分) 19.0 (2015)* | 是 | 4.8 | 11.1 (部分) 15.0* | 10.1 (部分)* 13.1.2 (部分)* | 5.9 (部分) | 是 | 8.4 | 2015 |  |  | 8.52 (部分)
带并发的动态初始化与析构（魔法静态变量） | N2660 | 4.3 | 2.9 | 19.0 (2015)* | 是 | Yes | 11.1* | 13.1.2* | 5.13 | 是 | 8.4 | 2015 |  | A.06.25 |
垃圾收集与基于可达性的泄漏检测 | N2670 |  |  |  |  |  |  |  |  |  |  |  |  |  |
初始化器列表 | N2672 | 4.4 | 3.1 | 18.0* | 是 | 4.5 | 13.0 (部分) 14.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
非静态数据成员初始化器 | N2756 | 4.7 | 3.0 | 18.0* | 是 | 4.6 | 14.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
属性 | N2761 | 4.8 | 3.3 | 19.0 (2015)* | 是 | 4.2 | 12.1 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
前置 enum 声明 | N2764 | 4.6 | 3.1 | 17.0* | 是 | 4.5 | 11.1 (部分) 14.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
用户定义的字面量 | N2765 | 4.7 | 3.1 | 19.0 (2015)* | 是 | 4.8 | 15.0 | 13.1.2* | 5.14 | 是 | 8.4 | 2015 | 7.0 |  |
右值引用 | N2118 N2844 CWG1138 | 4.3 (N2118) 4.5 | 2.9 | 16.0* (N2844) 17.0* | 是 | 4.5 | 11.1 (N2118) 12.0 (N2844) 14.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0* | A.06.25 |
Lambda 表达式 | N2550 N2658 N2927 | 4.5 | 3.1 | 16.0* (N2658) 17.0* | 是 | 4.1 | 12.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
范围 for 循环 | N2930 | 4.6 | 3.0 | 17.0* | 是 | 4.5 | 13.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
noexcept | N3050 | 4.6 | 3.0 | 19.0 (2015)* | 是 | 4.5 | 14.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
默认化的移动特殊成员 函数 | N3053 | 4.6 | 3.0 | 19.0 (2015)* | 是 | 4.5 | 14.0 |  | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
override 与 final | N2928 N3206 N3272 | 4.7 | 2.9 | 14.0* (部分) 17.0* | 是 | 4.8 | 12.0 (N2928) 14.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
decltype | N2343 N3276 | 4.3 (N2343) 4.8.1 | 2.9 | 16.0* | 是 | 4.2 (N2343) 4.8 | 11.0 (N2343) 12.0 | 11.1 (N2343) | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 | 8.52 (N2343)
C++11 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc | HP aCC | Digital Mars C++

C++11 库功能特性

C++11 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
类型特征 | N1836 | 4.3 | 3.0 | 14.0* | 是 | 5.13 | 是 | 8.4
垃圾收集与基于可达性的泄漏检测（库支持） | N2670 | 6 (无操作) | 3.4 (无操作) | 19.0 (2015)* (无操作) | 是 (无操作) |  |  |
金额、时间及十六进制浮点 I/O 操纵符 | N2071 N2072 | 5 | 3.8 | 19.0 (2015)* | 是 | 5.15 |  |
C++11 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库

* - 在版本号上停留可以查看注记

引用

各编译器厂商的兼容性检查单文档（这些通常比以上表格更能反映最新的情况）

  • GCC （更新于 2021-02 ）
    • C++11 核心语言支持状况（ 4.8.1 起完成，除了无编译器实现并于 C++23 移除的 N2670 ）
    • C++14 核心语言支持状况（ 5.1 起完成）
    • C++17 核心语言支持状况（ 7.1 起完成）
    • C++20 核心语言支持状况（ 11.0 起除模块部分完成）
    • C++23 核心语言支持状况
    • C++11 库支持状况（ 5.1 起完成）
    • C++14 库支持状况（ 5.1 起完成）
    • C++17 库支持状况
    • C++20 库支持状况
    • 技术规范支持状况
    • 核心语言缺陷报告状况
  • Clang++ （更新于 2021-07 ）
    • C++11 核心语言支持状况（ 3.3 起完成）
    • C++11 库支持状况（ 2012-07-29 起完成）
    • C++14 核心语言支持状况（ 3.4 起完成）
    • C++14 库支持状况（ 3.5 起完成）
    • C++17 核心语言支持状况（ 5.0 起完成）
    • C++17 库支持状况
    • C++20 核心语言支持状况
    • C++20 库支持状况
    • C++23 核心语言支持状况
    • C++23 库支持状况
    • 技术规范支持状况
    • 核心语言缺陷报告状况
  • Apple Clang （更新于 2019-06 ）
    • 维基百科上的 Xcode 工具链版本
    • Xcode 发行注记
  • Microsoft Visual Studio （更新于 2020-03 ）
    • 即将发布的 Visual Studio 2019 更改记录
    • C++17/20 Visual Studio 2019 中的 C++17/20 功能特性和修正
    • VS 2017 15.8 中的 STL 功能特性和修正
    • C++17 宣告： MSVC 遵从 C++ 标准（ 15.7 起完成）
    • C++17 VS 2017 15.5 中的功能特性及 STL 修正
    • C++17 VS 2017 15.3 中的功能特性和 STL 修正
    • C++11/C++14/C++17 VS2017.3 中的核心语言和库状况
    • C++11/C++14/C++17 核心语言支持状况
      • VS2010 、 VS2012 、 VS2013 和 VS2015 中的 C++11/14/17 核心语言支持状况
      • VS2013 vs. VS2015 CTP0
      • VS2013 vs. VS2015 CTP1
      • VS2013 vs. VS2015 CTP3 （包含路线图表格）
      • VS2015 ("VS14") 预览
      • VS2015 ("VS14") 发行候选（ C++11 仍不完整，但出现 C++17 支持）
      • VS2019
    • C++11 和 C++14 库支持状况
    • C++11/14/17 VS 2015 RTM 中的功能特性，包括核心语言与标准库（包括技术规范）
    • VS 2015 Update 2 标准库中的 C++14/17 功能特性 库对于当前 C++17 特性完整，有少量问题（一些缺陷报告、一些 constexpr 等）
    • VS “15” 预览 5 中的 C++14/17 功能特性和 STL 修正，包括详细的 C++17 状况表格
  • Intel C++ （更新于 2018-11 ）
    • C++11 核心语言支持状况（ 15.0 起完全支持）
    • C++14 核心语言支持状况（ 17.0 起功能完整， N3664 是一项优化）
    • C++17 核心语言支持状况（不完全支持）
    • Intel 19.0 beta 的 C++17 特性
    • Intel 不提供 C++ 标准库的实现，除了
      • 并行 STL （ C++17 带执行策略支持的标准库算法的实现）
    • Intel 与 GCC 的 libstdc++ 各版本间的兼容性
  • EDG （更新于 2019-10 ）
    • C++11 核心语言支持状况
    • C++14 核心语言支持状况
    • C++17 核心语言支持状况
    • C++20 核心语言支持状况
    • EDG 不提供 C++ 标准库的实现
  • Oracle C++ （更新于 2017-07 ）
    • 版本号为编译器版本而非 Oracle Studio 版本
    • C++11 核心语言支持状况
      • 5.14 中已经加入所缺少的 C++11 支持（页面中有错误，仍然声称是 5.13）
    • 5.14 中加入的 C++14 功能特性
      • 5.15 中添加了完整 C++14 支持。
    • Oracle 提供对标准库的四种不同实现：
      • libCstd （ RogueWave 标准库版本 2 ），早于 C++98
      • stlport4 （ STLport 标准库版本 4.5.3 ），早于 C++03
      • stdcxx4 （ Apache 标准库版本 4 ），早于 C++11
      • libstdc++ （ GCC 运行时库，根据不同发布版本对 C++11 和 C++14 有所支持）
  • IBM XL C++ （更新于 2018-05 ）
    • IBM XL C++ for Linux
      • 核心语言支持状况： 13.1.6 起 C++11 完整， 16.1.0 中部分 C++14
      • IBM 在 Linux 上不提供 C++ 标准库实现（使用 GNU libstdc++ ）
    • IBM XL C++ for AIX
      • 核心语言支持状况： 13.1.3 中部分支持 C++11 。
      • IBM 为 AIX 提供一个 Dinkumware 库的版本，带 C++ TR1 的完整支持，包括 <regex> ，但不支持 C++11
  • HP aCC
    • HP aC++ A.06.28 发行注记 (包括 C++11 核心语言功能特性)
    • HP 提供了 RogueWave STL 2.0 对 C++98 标准库的实现的一个版本
  • Digital Mars C++
    • C++11 核心语言支持状况
  • Embarcadero C++
    • 语言功能特性遵从状况 (RAD Studio 10.1 Berlin) ，包括老式编译器与 Clang 增强编译器（基于 Clang 3.3 ）所支持的 C++11 功能特性
    • 语言功能特性遵从状况 (RAD Studio 10.3 Rio) ，包括老式编译器所支持的 C++11 功能特性，和 Clang 增强编译器（基于 Clang 5.0 ）所支持的 C++11、 C++14 及 C++17 功能特性
  • Cray （更新于 2018-01 ）
    • Cray C 与 C++ 参考手册 (8.4) 声称 8.4 版支持除 alignas 外的全部 C++14
    • Cray C 与 C++ 参考手册 (8.6) 对于版本 8.6 ，声称支持全部 C++14
    • Cray C 与 C++ 参考手册 (9.1) 对于版本 9.1 未声称 C++14 后的支持
  • Portland Group (PGI) （更新于 2019-01）
    • 2016 版发行注记 声称支持 C++14，但不支持“推广的 constexpr 以及 constexpr 成员函数和隐含的 const 、变量模板、澄清内存分配（分配的合并）”
    • 2018 版发行注记
    • PGI 19.1 参考手册
    • PGI 不提供 C++ 标准库的实现
  • Nvidia Cuda nvcc （更新于 2021-03-04 ）
    • CUDA CUDA C 编程手册 (v11.2.1)
    • “ nvcc 版本 11.0 及之后的版本支持所有 C++17 语言功能特性，一些受到此处描述的限制。”
    • NVCC 不提供 C++ 标准库的实现
  • Texas Instruments （更新于 2018-05 ）
    • cl430 版本 v18.1.0 声称 C++14 支持
  • Analog Devices （更新于 2018-05 ）
    • CrossCore Embedded Studio 2.8.0 for SHARC 声称 C++11 支持。


C++11 的编译器支持

< cpp‎ | compiler support

C++11 核心语言功能特性

C++11 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc | HP aCC | Digital Mars C++
C99 预处理器 | N1653 | 4.3 | 是 | 19.0 (2015)* (部分)* 19.26* | 是 | 4.1 | 11.1 | 10.1 | 5.9 | 是 | 8.4 | 2015 | 7.0 | A.06.25 | 是
static_assert | N1720 | 4.3 | 2.9 | 16.0* | 是 | 4.1 | 11.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 | 8.52
右角括号 | N1757 | 4.3 | 是 | 14.0* | 是 | 4.1 | 11.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
扩展的 friend 声明 | N1791 | 4.7 | 2.9 | 16.0* (部分) 18.0* | 是 | 4.1 | 11.1 (部分) 12.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
long long | N1811 | 是 | 是 | 14.0* | 是 | 是 | 是 | 是 | 是 | 是 | 8.4 | 2015 | 7.0 | 是 | 是
类型特征的编译器支持 | N1836 | 4.3 | 3.0 | 14.0* | 是 | 4.0 | 10.0 | 13.1.3 | 5.13 | 是 | 8.4 | 2015 |  | 6.16 |
auto | N1984 | 4.4 | 是 | 16.0* | 是 | 3.9 | 11.0 (v0.9) 12.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
委托构造函数 | N1986 | 4.7 | 3.0 | 18.0* | 是 | 4.7 | 14.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
extern template | N1987 | 3.3 | 是 | 12.0* | 是 | 3.9 | 9.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
constexpr | N2235 | 4.6 | 3.1 | 19.0 (2015)* | 是 | 4.6 | 13.0 (部分) 14.0 | 12.1 (部分) 13.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
模板别名 | N2258 | 4.7 | 3.0 | 18.0* | 是 | 4.2 | 12.1 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
char16_t 与 char32_t | N2249 | 4.4 | 2.9 | 19.0 (2015)* | 是 | 4.4 | 12.1* 14.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 | 8.52
alignas | N2341 | 4.8 | 3.0 | 19.0 (2015)* | 是 | 4.8 | 15.0 | 13.1.2* | 5.13 | 是 | 8.6 | 2015 | 7.0 |  |
alignof | N2341 | 4.5 | 2.9 | 19.0 (2015)* | 是 | 4.8 | 15.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
默认化与被删除的函数 | N2346 | 4.4 | 3.0 | 18.0* | 是 | 4.1 | 12.0 | 13.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
强类型 enum | N2347 | 4.4 | 2.9 | 17.0* | 是 | 4.0 | 13.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
原子操作 | N2427 | 4.4 | 3.1 | 17.0* | 是 | Yes | 13.0 | 13.1.2* | 5.14 | 是 | 8.4 | 2015 |  |  |
nullptr | N2431 | 4.6 | 2.9 | 16.0* | 是 | 4.2 | 12.1 | 13.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 | 8.52
显式转换运算符 | N2437 | 4.5 | 3.0 | 18.0* | 是 | 4.4 | 13.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
引用限定符 | N2439 | 4.8.1 | 2.9 | 19.0 (2015)* | 是 | 4.7 | 14.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
Unicode 字符串字面量 | N2442 | 4.4 | 3.0 | 19.0 (2015)* | 是 | 4.7 | 11.0* | 10.1* 13.1.1* | 5.7 | 是 | 8.4 | 2015 | 7.0 | A.06.28 | 8.52
未处理的字符串字面量 | N2442 | 4.5 | 是 | 18.0* | 是 | 4.7 | 14.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 | 8.52
内联命名空间 | N2535 | 4.4 | 2.9 | 19.0 (2015)* | 是 | 4.5 | 14.0 | 11.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
继承构造函数 | N2540 | 4.8 | 3.3 | 19.0 (2015)* | 是 | 4.8 | 15.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
尾随的函数返回类型 | N2541 | 4.4 | 2.9 | 16.0* | 是 | 4.1 | 12.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
无限制的联合体 | N2544 | 4.6 | 3.0 | 19.0 (2015)* | 是 | 4.6 | 14.0* | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
变参数模板 | N2242 N2555 | 4.3 (N2242) 4.4 | 2.9 | 18.0* | 是 | 4.3 (N2242) 4.3 | 12.1 | 11.1 (N2242) | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
表达式 SFINAE | N2634 | 4.4 | 2.9 | 19.14* | 是 | 4.2 | 12.1 |  |  | 是 | 8.4 | 2015 | 7.0 |  |
局部与无名类型作为模板形参 | N2657 | 4.5 | 2.9 | 16.0* | 是 | 4.2 | 12.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
线程局部存储 | N2659 | 4.4 (部分) 4.8 | 3.3* | 16.0* (部分) 19.0 (2015)* | 是 | 4.8 | 11.1 (部分) 15.0* | 10.1 (部分)* 13.1.2 (部分)* | 5.9 (部分) | 是 | 8.4 | 2015 |  |  | 8.52 (部分)
带并发的动态初始化与析构（魔法静态变量） | N2660 | 4.3 | 2.9 | 19.0 (2015)* | 是 | Yes | 11.1* | 13.1.2* | 5.13 | 是 | 8.4 | 2015 |  | A.06.25 |
垃圾收集与基于可达性的泄漏检测 | N2670 |  |  |  |  |  |  |  |  |  |  |  |  |  |
初始化器列表 | N2672 | 4.4 | 3.1 | 18.0* | 是 | 4.5 | 13.0 (部分) 14.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
非静态数据成员初始化器 | N2756 | 4.7 | 3.0 | 18.0* | 是 | 4.6 | 14.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
属性 | N2761 | 4.8 | 3.3 | 19.0 (2015)* | 是 | 4.2 | 12.1 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.27 |
前置 enum 声明 | N2764 | 4.6 | 3.1 | 17.0* | 是 | 4.5 | 11.1 (部分) 14.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
用户定义的字面量 | N2765 | 4.7 | 3.1 | 19.0 (2015)* | 是 | 4.8 | 15.0 | 13.1.2* | 5.14 | 是 | 8.4 | 2015 | 7.0 |  |
右值引用 | N2118 N2844 CWG1138 | 4.3 (N2118) 4.5 | 2.9 | 16.0* (N2844) 17.0* | 是 | 4.5 | 11.1 (N2118) 12.0 (N2844) 14.0 | 12.1 | 5.13 | 是 | 8.4 | 2015 | 7.0* | A.06.25 |
Lambda 表达式 | N2550 N2658 N2927 | 4.5 | 3.1 | 16.0* (N2658) 17.0* | 是 | 4.1 | 12.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
范围 for 循环 | N2930 | 4.6 | 3.0 | 17.0* | 是 | 4.5 | 13.0 | 13.1.2* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
noexcept | N3050 | 4.6 | 3.0 | 19.0 (2015)* | 是 | 4.5 | 14.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.28 |
默认化的移动特殊成员 函数 | N3053 | 4.6 | 3.0 | 19.0 (2015)* | 是 | 4.5 | 14.0 |  | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 |
override 与 final | N2928 N3206 N3272 | 4.7 | 2.9 | 14.0* (部分) 17.0* | 是 | 4.8 | 12.0 (N2928) 14.0 | 13.1.1* | 5.13 | 是 | 8.4 | 2015 | 7.0 |  |
decltype | N2343 N3276 | 4.3 (N2343) 4.8.1 | 2.9 | 16.0* | 是 | 4.2 (N2343) 4.8 | 11.0 (N2343) 12.0 | 11.1 (N2343) | 5.13 | 是 | 8.4 | 2015 | 7.0 | A.06.25 | 8.52 (N2343)
C++11 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc | HP aCC | Digital Mars C++

C++11 库功能特性

C++11 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
类型特征 | N1836 | 4.3 | 3.0 | 14.0* | 是 | 5.13 | 是 | 8.4
垃圾收集与基于可达性的泄漏检测（库支持） | N2670 | 6 (无操作) | 3.4 (无操作) | 19.0 (2015)* (无操作) | 是 (无操作) |  |  |
金额、时间及十六进制浮点 I/O 操纵符 | N2071 N2072 | 5 | 3.8 | 19.0 (2015)* | 是 | 5.15 |  |
C++11 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库


C++14 的编译器支持

< cpp‎ | compiler support

C++14 核心语言功能特性

C++14 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc
按语境转换的遣词调整 | N3323 | 4.9 | 3.4 | 18.0* | 是 | 4.9 | 16.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 16.1 | 9.0
二进制字面量 | N3472 | 4.3 (GNU) 4.9 | 2.9 | 19.0 (2015)* | 是 | 4.10 | 11.0 | 13.1.2* | 5.14 | 10.3 | 8.6 | 2015 | 9.0
decltype(auto)，普通函数的返回类型推导 | N3638 | 4.8 (部分)* 4.9 | 是 | 19.0 (2015)* | 是 | 4.9 | 15.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 16.1 | 9.0
带初始化/泛化的 lambda 捕获 (init-capture) | N3648 | 4.5 (部分) 4.9 | 3.4 | 19.0 (2015)* | 是 | 4.10 | 15.0 | 16.1.1* | 5.15 | 10.3 | 8.6 | 16.1 | 9.0
泛型 lambda 表达式 | N3649 | 4.9 | 3.4 | 19.0 (2015)* | 是 | 4.10 | 16.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 16.1 | 9.0
变量模板 | N3651 | 5 | 3.4 | 19.0 (Update 2)* | 是 | 4.11 | 17.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 17.4 | 9.0
扩展的 constexpr | N3652 | 5 | 3.4 | 19.10* | 是 | 4.11 | 17.0 | 13.1.2* | 5.15 | 10.3 | 8.6 | 17.4 | 9.0
带成员初始化器的聚合体 (NSDMI) | N3653 | 5 | 3.3 | 19.10* | 是 | 4.9 | 16.0 | 16.1.1* | 5.14 | 10.3 | 8.6 | 16.1 | 9.0
忽略/扩展内存分配 | N3664 | N/A | 3.4 | N/A | 是 | N/A | N/A | N/A | N/A | 10.3 | 8.6 | 17.4 | N/A
[[deprecated]] 属性 | N3760 | 4.9 | 3.4 | 19.0 (2015)* | 是 | 4.9 | 15.0* 16.0 | 13.1.2* | 5.14 | 10.3 | 8.6 | 16.1 | 9.0
具大小解分配 | N3778 | 5 | 3.4 | 19.0 (2015)* | 是 | 4.10.1 | 17.0 | 16.1.1* | 5.14 | 10.3 | 8.6 | 16.1 |
单引号作为数位分隔符 | N3781 | 4.9 | 3.4 | 19.0 (2015)* | 是 | 4.10 | 16.0 | 13.1.2* | 5.14 | 10.3 | 8.6 | 2015 | 9.0
C++14 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc

C++14 库功能特性

C++14 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
<complex> 的 constexpr | N3302 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
通透的运算符函数对象 | N3421 | 4.9 | 3.4 | 18.0* | 是 | 5.15 | 10.3 | 8.6
std::result_of 与 SFINAE | N3462 | 5 | 是 | 19.0 (Update 2)* | 是 | 5.15 | 10.3 | 8.6
<chrono> 的 constexpr | N3469 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
<array> 的 constexpr | N3470 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
<initializer_list> 、 <utility> 和 <tuple> 的 constexpr | N3471 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
改进的 std::integral_constant | N3545 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
<chrono> 和 <string> 的用户定义字面量 | N3642 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
空向前迭代器 | N3644 | 5 (部分) | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::quoted | N3654 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::make_unique | N3656 | 4.9 | 3.4 | 18.0* | 是 | 5.15 | 10.3 | 8.6
异质关联查找 | N3657 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::integer_sequence | N3658 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::shared_timed_mutex | N3659 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::exchange | N3668 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
修正无 const 的 constexpr 成员函数 | N3669 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
std::get<T>() | N3670 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
双范围的 std::equal 、 std::is_permutation 、 std::mismatch | N3671 | 5 | 3.4 | 19.0 (2015)* | 是 | 5.15 | 10.3 | 8.6
C++14 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库


C++17 的编译器支持

< cpp‎ | compiler support

C++17 核心语言功能特性

C++17 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc
直接列表初始化的新 auto 规则 | N3922 | 5 | 3.8 | 19.0 (2015)* | 是 | 4.10.1 | 17.0 |  |  | 10.3 |  | 17.7 |
无消息的 static_assert | N3928 | 6 | 2.5 | 19.10* | 是 | 4.12 | 18.0 |  |  | 10.3 |  | 17.7 |
模板模板形参中的 typename | N4051 | 5 | 3.5 | 19.0 (2015)* | 是 | 4.10.1 | 17.0 |  |  | 10.3 |  | 17.7 |
移除三标符 | N4086 | 5 | 3.5 | 16.0* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
嵌套命名空间定义 | N4230 | 6 | 3.6 | 19.0 (Update 3)* | 是 | 4.12 | 17.0 |  |  | 10.3 |  | 17.7 |
命名空间和枚举项的属性 | N4266 | 4.9 (部分)* 6 | 3.6 | 19.0 (2015)* | 是 | 4.11 | 17.0 |  |  | 10.3 |  | 17.7 |
u8 字符字面量 | N4267 | 6 | 3.6 | 19.0 (2015)* | 是 | 4.11 | 17.0 |  |  | 10.3 |  | 17.7 |
允许所有非类型模板实参的常量求值 | N4268 | 6 | 3.6 | 19.12* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
折叠表达式 | N4295 | 6 | 3.6 | 19.12* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
一元折叠表达式和空形参包 | P0036R0 | 6 | 3.9 | 19.12* | 是 | 4.14 |  |  |  | 10.3 |  |  |
移除 register 关键字的已弃用用法 | P0001R1 | 7 | 3.8 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
移除已弃用的 operator++(bool) | P0002R1 | 7 | 3.8 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
令异常规定为类型系统的一部分 | P0012R1 | 7 | 4 | 19.12* | 是 | 4.14 | 19.0 |  |  | 10.3 |  |  |
有基类的类的聚合初始化 | P0017R1 | 7 | 3.9 | 19.14* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
预处理器条件中的 __has_include | P0061R1 | 5 | 是 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
DR ：继承构造函数的新规定 (DR1941 等) | P0136R1 | 7 | 3.9 | 19.14* | 是 | 6.1 |  |  |  | 10.3 |  | 19.1 |
*this 的 lambda 捕获 | P0018R3 | 7 | 3.9 | 19.11* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
枚举的直接列表初始化 | P0138R2 | 7 | 3.9 | 19.11* | 是 | 4.14 | 18.0 |  |  | 10.3 |  |  |
constexpr lambda 表达式 | P0170R1 | 7 | 5 | 19.11* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
基于范围 for 的相异 begin 和 end 类型 | P0184R0 | 6 | 3.9 | 19.10* | 是 | 4.12 | 18.0 |  |  | 10.3 |  | 17.7 |
[[fallthrough]] 属性 | P0188R1 | 7 | 3.9 | 19.10* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
[[nodiscard]] 属性 | P0189R1 | 7 | 3.9 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
[[maybe_unused]] 属性 | P0212R1 | 7 | 3.9 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
十六进制浮点字面量 | P0245R1 | 3.0 | 是 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
使用属性命名空间而不重复 | P0028R4 | 7 | 3.9 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
过对齐数据的动态内存分配 | P0035R4 | 7 | 4 | 19.12* | 10.0.0* | 4.14 |  |  |  | 10.3 |  |  |
类模板实参推导 | P0091R3 | 7 | 5 | 19.14* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  | 19.1 |
具有 auto 类型的非类型模板形参 | P0127R2 | 7 | 4 | 19.14* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  | 19.1 |
受保证的复制消除 | P0135R1 | 7 | 4 | 19.13* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  | 19.1 |
替换含引用成员的类对象 | P0137R1 | 7 | 6 | 19.14* | 是 | 5.0 |  |  |  | 10.3 |  |  |
更严格的表达式求值顺序 | P0145R3 | 7 | 4 | 19.14* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
结构化绑定 | P0217R3 | 7 | 4 | 19.11* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
忽略未知属性 | P0283R2 | 是 | 3.9 | 19.11* | 是 | 4.13 | 18.0 |  |  | 10.3 |  | 17.7 |
constexpr if 语句 | P0292R2 | 7 | 3.9 | 19.11* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
if 和 switch 的初始化语句 | P0305R1 | 7 | 3.9 | 19.11* | 是 | 4.14 | 18.0 |  |  | 10.3 |  | 18.1 |
inline 变量 | P0386R2 | 7 | 3.9 | 19.12* | 是 | 4.14 | 19.0 |  |  | 10.3 |  | 18.1 |
移除动态异常说明 | P0003R5 | 7 | 4 | 19.10* | 是 | 4.14 | 19.0 |  |  | 10.3 |  |  |
using 声明中的包展开 | P0195R2 | 7 | 4 | 19.14* | 是 | 5.0 |  |  |  | 10.3 |  |  |
DR ：模板模板实参的匹配排除了兼容的模板 | P0522R0 | 7 | 4 | 19.12* | 是 | 5.0 | 19.0.1 |  |  | 10.3 |  |  |
C++17 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc

C++17 库功能特性

C++17 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Intel 并行 STL | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
std::void_t | N3911 | 6 | 3.6 | 19.0 (2015)* | 是 | N/A |  | 10.3 |
std::uncaught_exceptions() | N4259 | 6 | 3.7 | 19.0 (2015)* | 是 | N/A |  | 10.3 |
std::size() 、 std::empty() 与 std::data() | N4280 | 6 | 3.6 | 19.0 (2015)* | 是 | N/A |  | 10.3 |
改进 std::pair 与 std::tuple | N4387 | 6 | 4 | 19.0 (Update 2)* | 是 | N/A |  | 10.3 |
std::bool_constant | N4389 | 6 | 3.7 | 19.0 (2015)* | 是 | N/A |  | 10.3 |
std::shared_mutex （无时限） | N4508 | 6 | 3.7 | 19.0 (Update 2)* | 是 | N/A |  | 10.3 |
类型特性变量模板 | P0006R0 | 7 | 3.8 | 19.0 (Update 2)* | 是 | N/A |  | 10.3 |
逻辑运算符类型特性 | P0013R1 | 6 | 3.8 | 19.0 (Update 2)* | 是 | N/A |  | 10.3 |
标准化并行 TS | P0024R2 | 9* |  | 19.14* |  | 18.0* |  |  |
std::clamp() | P0025R0 | 7 | 3.9 | 19.0 (Update 3)* | 10.0.0* | N/A |  | 10.3 |
硬件干涉大小 | P0154R1 |  |  | 19.11* |  | N/A |  |  |
(nothrow-)swappable 特性 | P0185R1 | 7 | 3.9 | 19.0 (Update 3)* | 10.0.0* | N/A |  | 10.3 |
文件系统库 | P0218R1 | 8 | 7 | 19.14* | 11.0.0* | N/A |  | 10.3 |
std::string_view | N3921 P0220R1 | 7 | 4 | 19.10* | 10.0.0* | N/A |  | 10.3 |
std::any | P0220R1 | 7 | 4 | 19.10* | 10.0.0* | N/A |  | 10.3 |
std::optional | P0220R1 | 7 | 4 | 19.10* | 10.0.0* | N/A |  | 10.3 |
多态内存资源 | P0220R1 | 9 |  | 19.13* |  | N/A |  | 10.3 |
数学特殊函数 | P0226R1 | 7 |  | 19.14* |  | N/A |  | 10.3 |
C++17 应指代 C11 而非 C99 | P0063R3 | 9 | 7 | 19.0 (2015)* (部分)* |  | N/A |  | 10.3 |
接合 map 与 set | P0083R3 | 7 | 8 | 19.12* | 10.0.0* | N/A |  |  |
std::variant | P0088R3 | 7 | 4 | 19.10* | 10.0.0* | N/A |  | 10.3 |
std::make_from_tuple() | P0209R2 | 7 | 3.9 | 19.10* | 是 | N/A |  | 10.3 |
std::has_unique_object_representations | P0258R2 | 7 | 6 | 19.11* | 是 | N/A |  | 10.3 |
std::gcd() 与 std::lcm() | P0295R0 | 7 | 4 | 19.11* | 是 | N/A |  | 10.3 |
std::not_fn | P0005R4 P0358R1 | 7 | 3.9 | 19.12* |  | N/A |  | 10.3 |
初等字符串转换 | P0067R5 | 8 (无浮点) | 7 (无浮点) | 19.14* (无浮点)* 19.24* |  | N/A |  |  |
有数组支持的 std::shared_ptr 与 std::weak_ptr | P0414R2 | 7 | 11 | 19.12* |  | N/A |  | 10.3 |
std::scoped_lock | P0156R2 | 7 | 5 | 19.11* | 是 | N/A |  | 10.3 |
std::byte | P0298R3 | 7 | 5 | 19.11* | 是 | N/A |  | 10.3 |
std::is_aggregate | LWG2911 | 7 | 5 | 19.15* | 是 | N/A |  | 10.3 |
C++17 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Intel 并行 STL | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库


C++20 的编译器支持

< cpp‎ | compiler support

C++20 核心语言功能特性

C++20 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc
允许 lambda 捕获 [=, this] | P0409R2 | 8 | 6 | 19.22* | 10.0.0* | 5.1 |  |  |  |  |  | 20.7 |
__VA_OPT__ | P0306R4 P1042R1 | 8 (部分)* 10 | 9 | 19.25* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
指派初始化器 | P0329R4 | 4.7 (部分)* 8 | 3.0 (部分)* 10 | 19.21* | (部分)* | 5.1 |  |  |  |  |  | 20.7 |
泛型 lambda 的模板形参列表 | P0428R2 | 8 | 9 | 19.22* | 11.0.0* | 5.1 |  |  |  |  |  | 20.7 |
位域的默认成员初始化器 | P0683R1 | 8 | 6 | 19.25* | 10.0.0* | 5.1 |  |  |  |  |  | 20.7 |
类模板实参推导中的 intializer_list 构造函数 | P0702R1 | 8 | 6 | 19.14* | 是 | 5.0 |  |  |  |  |  | 20.7 |
const& 限定的成员指针 | P0704R1 | 8 | 6 | 19.14* | 是 | 5.0 |  |  |  |  |  | 20.7 |
概念 | P0734R0 | 6 (仅 TS) 10 | 10 | 19.23* (部分)* |  |  |  |  |  |  |  | 20.11 |
不求值语境中的 lambda | P0315R4 | 9 |  | 19.28 (16.8)* |  |  |  |  |  |  |  |  |
三路比较运算符 | P0515R3 | 10 | 8 (部分) 10 | 19.20* |  | 5.1 |  |  |  |  |  | 20.7 |
DR ：简化隐式 lambda 捕获 | P0588R1 | 8 |  | 19.24* |  | 5.1 |  |  |  |  |  | 20.7 |
基于范围的 for 的初始化语句 | P0614R1 | 9 | 8 | 19.25* | 11.0.0* | 6.0 |  |  |  |  |  | 20.11 |
可默认构造与可赋值的无状态 lambda | P0624R2 | 9 | 8 | 19.22* | 10.0.1* | 5.1 |  |  |  |  |  |  |
预置复制构造函数与 const 的不匹配 | P0641R2 | 9 | 8 | 19.0 (2015)* | 10.0.1* | 5.1 |  |  |  |  |  | 20.7 |
特化上的访问检查 | P0692R1 | 是 | 8 (部分) | 19.26* | 10.0.1* (部分) | 5.1 |  |  |  |  |  | 20.7 |
ADL 与不可见的函数模板 | P0846R0 | 9 | 9 | 19.21* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
DR：指定 constexpr 函数定义何时为常量求值所需要 | P0859R0 | 5.2 (部分)* 9 | 8 | 19.27* (部分)* |  |  |  |  |  |  |  |  |
属性 [[likely]] 与 [[unlikely]] | P0479R5 | 9 | 12 | 19.26* |  | 5.1 |  |  |  |  |  | 20.7 |
使 typename 更可选 | P0634R3 | 9 |  | 19.29 (16.10)* |  | 5.1 |  |  |  |  |  | 20.7 |
Lambda 初始化捕获中的包展开 | P0780R2 | 9 | 9 | 19.22* | 11.0.3* | 6.1 |  |  |  |  |  | 20.11 |
属性 [[no_unique_address]] | P0840R2 | 9 | 9 | 19.28 (16.9)** | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
条件性平凡的特殊成员函数 | P0848R3 | 10 |  | 19.28 (16.8)* |  | 6.1 |  |  |  |  |  | 20.11 |
DR：放松结构化绑定定制点查找规则 | P0961R1 | 8 | 8 | 19.21* | 10.0.1* | 5.1 |  |  |  |  |  |  |
DR：放松范围 for 循环定制点查找规则 | P0962R1 | 8 |  |  |  | 5.1 |  |  |  |  |  |  |
DR ：允许到可访问成员的结构化绑定 | P0969R0 | 8 | 8 | 19.21* | 10.0.1* | 5.1 |  |  |  |  |  |  |
销毁的 operator delete | P0722R3 | 9 | 6 | 19.27* | 10.0.0* | 6.1 |  |  |  |  |  |  |
非类型模板形参非类型模板形参中的类类型 | P0732R2 | 9 | 12 (部分) | 19.26*(部分)* 19.28 (16.9)* |  | 6.2 |  |  |  |  |  |  |
弃用经由 [=] 隐式捕获 this | P0806R2 | 9 | 7 | 19.22* |  | 5.1 |  |  |  |  |  | 20.7 |
explicit(bool) | P0892R2 | 9 | 9 | 19.24* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
集成功能特性测试宏 | P0941R2 | 5 | 3.4 | 19.15* (部分) 19.20* | 是 | 5.0 |  |  |  |  |  | 20.7 |
禁止有用户声明构造函数的聚合体 | P1008R1 | 9 | 8 | 19.20* | 10.0.1* | 5.1 |  |  |  |  |  | 20.7 |
constexpr 虚函数 | P1064R0 | 9 | 9 | 19.28 (16.9)* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
比较的一致性改进 | P1120R0 | 10 | 8 (部分) 10 | 19.22* | 10.0.1* (部分) | 5.1 |  |  |  |  |  | 20.7 |
char8_t | P0482R6 | 9 | 7 | 19.22* | 10.0.0* | 5.1 |  |  |  |  |  | 20.7 |
std::is_constant_evaluated() | P0595R2 | 9 | 9 | 19.25* | 11.0.3* | 5.1 | 19.1 |  |  |  |  |  |
constexpr 函数中的 try-catch 块 | P1002R1 | 9 | 8 | 19.25* | 10.0.1* | 5.1 |  |  |  |  |  | 20.7 |
立即函数（consteval） | P1073R3 | 10 (部分)* 11 | 11 (部分) | 19.28 (16.8)** (部分) 19.29 (16.10)* |  | 5.1 |  |  |  |  |  | 20.7 |
嵌套内联命名空间 | P1094R2 | 9 | 8 | 19.27* | 10.0.1* | 5.1 |  |  |  |  |  | 20.7 |
有约束 声明的另一种手段 | P1141R2 | 10 | 10 | 19.26* (部分) 19.28 (16.9)* |  | 6.1 |  |  |  |  |  | 20.11 |
有符号整数为补码 | P1236R1 | 9 |  | 是 | 11.0.3* | N/A |  |  |  |  |  | 是 |
constexpr dynamic_cast 及多态 typeid | P1327R1 | 10 | 9 | 19.29 (16.10)* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
在 constexpr 内更改联合体的活跃成员 | P1330R0 | 9 | 9 | 19.10* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
协程 | P0912R5 | 10 | 8 (部分) | 19.0 (2015)* (部分) 19.10* (仅 TS) 19.28 (16.8)* | 10.0.1* (部分) | 5.1 |  |  |  |  |  |  |
括号形式的聚合体初始化 | P0960R3 | 10 |  | 19.28 (16.8)* |  | 5.1 |  |  |  |  |  | 20.7 |
DR： new 表达式中的数组大小推导 | P1009R2 | 11 | 9 | 19.27* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
模块 | P1103R3 | 11 (部分) | 8 (部分) | 19.0 (2015)* (部分) 19.10* (仅 TS) 19.28 (16.8)* | 10.0.1* (部分) |  |  |  |  |  |  |  |
更强的 Unicode 要求 | P1041R4 P1139R2 | 10 | 是 | 19.0 (2015)* (P1041R4) 19.26* (P1139R2) | 是 | N/A |  |  |  |  |  |  |
<=> != == | P1185R2 | 10 | 10 | 19.22* |  | 5.1 |  |  |  |  |  | 20.7 |
DR ：拥有不同异常说明的显式默认化函数 | P1286R2 | 10 | 9 | 19.28 (16.8)* | 11.0.3* | 5.1 |  |  |  |  |  | 20.7 |
结构化绑定的 lambda 捕获与存储类说明符 | P1091R3 P1381R1 | 10 | 8 (部分) | 19.11*(P1381R1) 19.24*(P1091R3) | 10.0.1* (部分) | 5.1 |  |  |  |  |  | 20.7 |
容许转换到未知边界数组 | P0388R4 | 10 |  | 19.27* |  | 6.0 |  |  |  |  |  | 20.11 |
constexpr 容器操作 | P0784R7 | 10 | 10 | 19.28 (16.9)* |  | 6.0 |  |  |  |  |  | 20.11 |
弃用 volatile 的某些用法 | P1152R4 | 10 | 10 | 19.27* |  | 6.0 |  |  |  |  |  | 20.11 |
constinit | P1143R2 | 10 | 10 | 19.29 (16.10)* |  | 6.1 |  |  |  |  |  | 20.11 |
弃用下标中的逗号运算符 | P1161R3 | 10 | 9 | 19.25* | 11.0.3* | 6.0 |  |  |  |  |  | 20.11 |
带消息的 [[nodiscard]] | P1301R4 | 10 | 9 | 19.25* | 11.0.3* | 6.0 |  |  |  |  |  | 20.11 |
constexpr 函数中的平凡默认初始化 | P1331R2 | 10 | 10 | 19.27* |  | 6.1 |  |  |  |  |  | 20.11 |
constexpr 函数中的不求值 asm 声明 | P1668R1 | 10 | 10 | 19.28 (16.9)* |  | 6.1 |  |  |  |  |  | 20.11 |
using enum | P1099R5 | 11 | 13 | 19.24* |  | 6.3 |  |  |  |  |  |  |
对指定的比较类别合成三路比较 | P1186R3 | 11 | 10 | 19.24* |  | 6.0 |  |  |  |  |  | 20.11 |
DR：构造函数的 [[nodiscard]] | P1771R1 | 10 | 9 | 19.24* | 11.0.3* | 6.0 |  |  |  |  |  | 20.11 |
别名模板的类模板实参推导 | P1814R0 | 10 |  | 19.27* |  |  |  |  |  |  |  |  |
聚合类的类模板实参推导 | P1816R0 P2082R1 | 10(P1816R0) 11(P2082R1) |  | 19.27* |  |  |  |  |  |  |  |  |
DR ：更多局部对象与右值引用的隐式移动 | P1825R0 | 11* | 13 | 19.24* |  | 6.0 |  |  |  |  |  | 20.11 |
允许默认化按值比较 | P1946R0 | 10 | 10 | 19.25* |  | 6.1 |  |  |  |  |  | 20.11 |
移除 std::weak_equality 与 std::strong_equality | P1959R0 | 10 | 10 | 19.25* |  | 6.1 |  |  |  |  |  | 20.11 |
非类型模板形参的不一致 | P1907R1 | 10 (部分) 11 | 12 (部分) | 19.26* |  | 6.2 |  |  |  |  |  |  |
DR：伪析构函数终结对象生存期 | P0593R6 | 11 | 11 | 是 |  | N/A |  |  |  |  |  |  |
DR ：应认为从 T* 到 bool 的转换为窄化 | P1957R2 | 10* 11* | 11 | 19.27* |  | 6.1 |  |  |  |  |  |  |
C++20 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc

C++20 库功能特性

C++20 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
std::endian | P0463R1 | 8 | 7 | 19.22* | 10.0.0* |  |  |
扩展 std::make_shared() 以支持数组 | P0674R1 |  |  | 19.27* |  |  |  |
浮点原子类型 | P0020R6 | 10 |  | 19.22* |  |  |  |
同步缓冲（std::basic_osyncstream） | P0053R7 | 11 |  | 19.29 (16.10)* |  |  |  |
<algorithm> 与 <utility> 的 constexpr | P0202R3 | 10 | 8 (部分) 12 | 19.26* | 10.0.1* (部分) |  |  |
<complex> 的更多 constexpr | P0415R1 | 9 | 7 (部分) | 19.27* | 10.0.0* (部分) |  |  |
使 std::memory_order 为有作用域枚举 | P0439R0 | 9 | 9 | 19.25* | 11.0.3* |  |  |
字符串 前缀与后缀检查： string (_view) ::starts_with/ends_with | P0457R2 | 9 | 6 | 19.21* | 10.0.0* |  |  |
=operator<=> 的库支持 <compare> | P0768R1 | 10 | 7 (部分) 12 | 19.20* (部分) 19.28 (16.9)* | 10.0.0* (部分) |  |  |
std::remove_cvref | P0550R2 | 9 | 6 | 19.20* | 10.0.0* |  |  |
标准库中的 [[nodiscard]] | P0600R1 | 9 | 7 (部分) | 19.13* (部分) 19.22* | 10.0.0* (部分) |  |  |
于数值算法使用 std::move | P0616R0 | 9 | 12 | 19.23* |  |  |  |
转换指针为裸指针的工具 | P0653R2 | 8 | 6 | 19.22* | 是 |  |  |
原子 std::shared_ptr 与 std::weak_ptr | P0718R2 |  |  | 19.27* |  |  |  |
std::span | P0122R7 | 10 | 7 | 19.26* | 10.0.0* |  |  |
日历与时区 | P0355R7 | 11 (部分) | 7 (部分) | 19.29 (16.10)* | 10.0.0* (部分) |  |  |
<version> | P0754R2 | 9 | 7 | 19.22* | 10.0.0* |  |  |
比较无序容器 | P0809R0 |  | 是 | 16.0* | 是 |  |  |
常量表达式迭代器 (ConstexprIterator) 要求 | P0858R0 | 9 |  | 19.11* |  |  |  |
std::basic_string::reserve() 不应收缩 | P0966R1 | 11 | 8 | 19.25* | 10.0.1* |  |  |
带填充位的原子比较交换 | P0528R3 |  |  | 19.28 (16.8)* |  |  |  |
std::atomic_ref | P0019R8 | 10 |  | 19.28 (16.8)* |  |  |  |
关联容器的 contains() 成员函数，如 std::map::contains() | P0458R2 | 9 | 9 (部分)* 13 | 19.21* | 11.0.3* |  |  |
DR ：逐片构造的受保证复制消除 | P0475R1 | 9 | 是 | 19.29 (16.10)* | 是 |  |  |
std::bit_cast() | P0476R2 | 11 |  | 19.27* |  |  |  |
整数的 2 的幂的运算： std::bit_ceil()、 std::bit_floor()、 std::bit_width()、 std::has_single_bit() | P0556R3 P1956R1 | 9 (P0556R3) 10 (P1956R1) | 9 (P0556R3) 12 (P1956R1) | 19.25* (P0556R3)* 19.27* (P1956R1)* 19.28 (16.8)* |  |  |  |
改进擦除式算法的返回值 | P0646R1 | 9 | 10 | 19.21* |  |  |  |
std::destroying_delete | P0722R3 | 9 | 9 | 19.27* | 11.0.3* |  |  |
std::is_nothrow_convertible | P0758R1 | 9 | 9 | 19.23* | 11.0.3* |  |  |
添加 std::shift_left/right 到 <algorithm> | P0769R2 | 10 | 12 | 19.21* |  |  |  |
std::swap() 与 swap 相关函数的 constexpr | P0879R0 | 10 | 12 (部分) 13 | 19.26* |  |  |  |
std::type_identity | P0887R1 | 9 | 8 | 19.21* | 10.0.1* |  |  |
概念库 | P0898R3 | 10 | 13 | 19.23* |  |  |  |
std::array 的 constexpr 比较运算符 | P1023R0 | 10 | 8 | 19.27* | 10.0.1* |  |  |
std::unwrap_ref_decay 与 std::unwrap_reference | P0318R1 | 9 | 8 | 19.21* | 10.0.1* |  |  |
std::bind_front() | P0356R5 | 9 | 13 | 19.25* |  |  |  |
不完整类型的 std::reference_wrapper | P0357R3 | 9 | 8 | 19.26* | 10.0.1* |  |  |
修正 operator>>(basic_istream&, CharT*) | P0487R1 | 11 | 8 | 19.23* | 10.0.1* |  |  |
char8_t 的库支持 | P0482R6 | 9 | 8 (部分)* | 19.22* |  |  |  |
实现使用分配器 构造的工具函数 | P0591R4 | 9 |  | 19.29 (16.10)* |  |  |  |
DR： std::variant 与 std::optional 应传播复制/移动平凡性 | P0602R4 | 8.3 | 8 | 19.11* | 10.0.1* |  |  |
理智的 std::variant 转换构造函数 | P0608R3 | 10 | 9 | 19.29 (16.10)* | 11.0.3* |  |  |
std::function 的移动构造函数应为 noexcept | P0771R1 | 7.2 | 6 | 19.22* | 是 |  |  |
一个 范围 提案 | P0896R4 | 10 | 13 (部分) | 19.29 (16.10)* |  |  |  |
无序容器的异质查找 | P0919R3 P1690R1 | 11 | 12 | 19.23* (P0919R3) 19.25* (P1690R1) |  |  |  |
<chrono> zero()、 min() 及 max() 应为 noexcept | P0972R0 | 9 | 8 | 19.14* | 10.0.1* |  |  |
std::pointer_traits 中的 constexpr | P1006R1 | 9 | 8 | 19.26* | 10.0.1* |  |  |
std::assume_aligned() | P1007R3 | 9* 11 |  | 19.28 (16.9)* |  |  |  |
使用默认初始化的智能指针创建（如 make_unique_for_overwrite） | P1020R1 P1973R1 |  |  | 19.28 (16.9)* |  |  |  |
杂项 constexpr 小部分 | P1032R1 | 10 | 13 | 19.28 (16.8)* |  |  |  |
移除 std::span 的比较运算符 | P1085R2 | 10 | 8 | 19.26* | 10.0.1* |  |  |
使 operator+(basic_string) 的有状态分配器传播更加一致 | P1165R1 | 10 |  | 19.26* |  |  |  |
一致容器擦除，如 std::erase(std::vector) 或 std::erase_if(std::map) | P1209R0 P1115R3 | 9 (P1209R0) 10 (P1115R3) | 8 (P1209R0) 11 (P1115R3) | 19.25* (P1209R0) 19.27* (P1115R3) | 10.0.1* (P1209R0) |  |  |
标准库头文件单元 | P1502R1 | 11 |  | 19.29 (16.10)* |  |  |  |
polymorphic_allocator<> 作为词汇类型 | P0339R6 | 9 |  | 19.28 (16.9)* |  |  |  |
std::execution::unseq | P1001R2 | 9 |  | 19.28 (16.8)* |  |  |  |
std::lerp() 与 std::midpoint() | P0811R3 | 9 | 9 | 19.23* (部分) 19.28 (16.8)* | 11.0.3* |  |  |
std::span 的实用性增强 | P1024R3 | 10 | 9 | 19.26* | 11.0.3* |  |  |
DR：使 create_directory() 自发 | P1164R1 | 8.3 | 12 | 19.20* |  |  |  |
std::ssize() 与 std::span 的无符号长度 | P1227R2 | 10 | 9 | 19.25* | 11.0.3* |  |  |
有界及无界数组特征 | P1357R1 | 9 | 9 | 19.25* | 11.0.3* |  |  |
std::to_array() | P0325R4 | 10 | 10 | 19.25* |  |  |  |
std::basic_stringbuf 缓冲的有效访问 | P0408R7 | 11 |  | 19.29 (16.10)* |  |  |  |
布局 兼容性与指针 可互转换性特征 | P0466R5 |  |  | 19.29 (16.10)** |  |  |  |
位操作： std:: rotl()、 rotr()、 countl_zero()、 countl_one()、 countr_zero()、 countr_one()、 popcount() | P0553R4 | 9 | 9 | 19.25** 19.28 (16.8)* | 11.0.3* |  |  |
数学常数 | P0631R8 | 10 | 11 | 19.25* |  |  |  |
文本格式化 | P0645R10 |  |  | 19.29 (16.10)* |  |  |  |
std::stop_token 与 std::jthread | P0660R10 | 10 |  | 19.28 (16.9)* |  |  |  |
constexpr std::allocator 及相关工具 | P0784R7 | 10 | 12 | 19.29 (16.10)* |  |  |  |
constexpr std::string | P0980R1 |  |  | 19.29 (16.10)* |  |  |  |
constexpr std::vector | P1004R2 |  |  | 19.29 (16.10)* |  |  |  |
输入范围适配器 | P1035R7 | 10 |  | 19.29 (16.10)* |  |  |  |
constexpr std::invoke() 及相关工具 | P1065R2 | 10 | 12 | 19.28 (16.8)* |  |  |  |
原子等待与提醒、 std::counting_semaphore 、 std::latch 及 std::barrier | P1135R6 | 11 | 11 | 19.28 (16.8)* |  |  |  |
std::source_location | P1208R6 | 11 |  | 19.29 (16.10)* |  |  |  |
添加 <=> 到标准库 | P1614R2 | 10 |  | 19.29 (16.10)* |  |  |  |
std::atomic 与 std::atomic_flag 的 constexpr 默认构造函数 | P0883R2 | 10 | 13 | 19.26* |  |  |  |
数值算法的 constexpr | P1645R1 | 10 | 12 | 19.26* |  |  |  |
安全整数比较 | P0586R2 | 10 | 13 | 19.27* |  |  |  |
C++20 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库


C++23 的编译器支持

< cpp‎ | compiler support

C++23 核心语言功能特性

C++23 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ （前 Portland Group/PGI） | Nvidia nvcc
（有符号） size_t 的字面量后缀 | P0330R8 | 11 | 13 |  |  |  |  |  |  |  |  |  |
使 () 对 lambda 更可选 | P1102R2 | 11 | 13 |  |  |  |  |  |  |  |  |  |
if consteval | P1938R3 | 12 | 14 |  |  |  |  |  |  |  |  |  |
移除垃圾收集支持 | P2186R2 | 12 |  |  |  |  |  |  |  |  |  |  |
DR：C++ 标识符语法使用 Unicode 标准附录 31 | P1949R7 | 12 | 14 |  |  |  |  |  |  |  |  |  |
DR：允许重复属性 | P2156R1 | 11 | 13 |  |  |  |  |  |  |  |  |  |
static_assert 与 constexpr if 中的窄化按语境转换 | P1401R5 | 9 | 13 (部分)* 14 |  |  |  |  |  |  |  |  |  |
在拼接行前剔除空白符 | P2223R2 | 是 | 是 |  | 是 |  |  |  |  |  |  |  |
使声明顺序布局强制 | P1847R4 | 是 | 是 | 是 | 是 |  |  |  |  |  |  |  |
移除混合宽字符串字面量连接 | P2201R1 | 是 | 是 | 是 | 是 |  | 是 |  |  |  |  |  |
C++23 功能特性 | 提案 | GCC | Clang | MSVC | Apple Clang | EDG eccp | Intel C++ | IBM XLC++ | Sun/Oracle C++ | Embarcadero C++ Builder | Cray | Nvidia HPC C++ | Nvidia nvcc

C++23 库功能特性

C++23 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库
栈踪库 | P0881R7 |  |  |  |  |  |  |
<stdatomic.h> | P0943R6 |  |  |  |  |  |  |
std::is_scoped_enum | P1048R1 | 11 | 12 | 19.30* |  |  |  |
basic_string/basic_string_view 的 contains() | P1679R3 | 11 | 12 |  |  |  |  |
std::to_underlying | P1682R3 | 11 | 13 |  |  |  |  |
std::variant 的派生类的 std::visit | P2162R2 |  | 13 | 19.20** |  |  |  |
放松 time_point<>::clock 的要求 | P2212R2 | N/A |  | N/A |  |  |  |
DR：条件性借用范围 | P2017R1 |  |  | 19.30* |  |  |  |
DR：修复输入范围适配器与 std::counted_iterator | P2259R1 |  |  |  |  |  |  |
在分配器接口中提供大小反馈 | P0401R6 |  |  |  |  |  |  |
<spanstream> ：以 std::span 为基础的字符串流 | P0448R4 |  |  |  |  |  |  |
std::out_ptr()、 std::inout_ptr() | P1132R8 |  |  |  |  |  |  |
constexpr type_info::operator==() | P1328R1 |  |  |  |  |  |  |
std::stack 与 std::queue 的迭代器对构造函数 | P1425R4 |  |  |  |  |  |  |
容器推导指引中分配器的非推导语境 | P1518R2 |  |  |  |  |  |  |
ranges::starts_with() 与 ranges::ends_with() | P1659R3 | 11 |  |  |  |  |  |
禁止 basic_string 与 basic_string_view 从 nullptr 构造 | P2166R1 |  |  |  |  |  |  |
std::invoke_r() | P2136R3 |  |  |  |  |  |  |
basic_string_view 的范围构造函数 | P1989R2 |  |  |  |  |  |  |
pair 的转发构造函数的默认模板实参 | P1951R1 |  |  |  |  |  |  |
移除垃圾收集与基于可达性的泄漏检测（库支持） | P2186R2 |  |  |  |  |  |  |
DR：join_view 应结合所有范围 | P2328R1 |  |  |  |  |  |  |
DR：view 不要求 default_initializable | P2325R3 |  |  |  |  |  |  |
DR：范围适配器对象按值绑定实参 | P2281R1 |  |  | 19.29 (16.10)* |  |  |  |
DR：std::optional 与 std::variant 的 constexpr | P2231R1 |  |  |  |  |  |  |
DR：std::format() 改进 | P2216R3 |  |  |  |  |  |  |
DR：lazy_split_view 与重新设计的 split_view | P2210R2 |  |  |  |  |  |  |
C++23 功能特性 | 提案 | GCC libstdc++ | Clang libc++ | MSVC STL | Apple Clang | Sun/Oracle C++ 标准库 | Embarcadero C++ Builder 标准库 | Cray C++ 标准库


概念库 (C++20)

< cpp

概念库提供基础库概念们的定义，它们能用于进行模板实参的编译时校验，以及基于类型属性的函数派发。这些概念在程序中提供等式推理的基础。

标准库中的大多数概念一同加上了语法及语义要求。若符合标准概念的语法要求，则称它被满足，而若满足标准概念并且还符合其语义要求（若存在），则称它被实现。

通常，编译器只能检查语法要求。若程序的合法性或含义取决于模板实参序列是否实现一个概念，而该概念被满足但未被实现，或若在使用点语义要求未得到满足，则程序非良构，不要求诊断。

定义于命名空间 std
核心语言概念
定义于头文件 <concepts>
same_as
(C++20)
 指定一个类型与另一类型相同
(概念)
derived_from
(C++20)
 指定一个类型派生自另一类型
(概念)
convertible_to
(C++20)
 指定一个类型能隐式转换成另一类型
(概念)
common_reference_with
(C++20)
 指定两个类型共有一个公共引用类型
(概念)
common_with
(C++20)
 指定两个类型共有一个公共类型
(概念)
integral
(C++20)
 指定类型为整型类型
(概念)
signed_integral
(C++20)
 指定类型为有符号的整型类型
(概念)
unsigned_integral
(C++20)
 指定类型为无符号的整型类型
(概念)
floating_point
(C++20)
 指定类型为浮点类型
(概念)
assignable_from
(C++20)
 指定一个类型能从另一类型赋值
(概念)
swappableswappable_with
(C++20)
 指定一个类型能进行交换，或两个类型能彼此交换
(概念)
destructible
(C++20)
 指定能销毁该类型的对象
(概念)
constructible_from
(C++20)
 指定该类型的变量能从一组实参类型进行构造，或绑定到一组实参类型
(概念)
default_initializable
(C++20)
 指定能默认构造一个类型的对象
(概念)
move_constructible
(C++20)
 指定能移动构造一个类型的对象
(概念)
copy_constructible
(C++20)
 指定能复制构造和移动构造一个类型的对象
(概念)
比较概念
定义于头文件 <concepts>
boolean-testable
(C++20)
 指定能用于布尔语境的类型
(仅用于阐释的概念)
equality_comparableequality_comparable_with
(C++20)
 指定运算符 == 为等价关系
(概念)
totally_orderedtotally_ordered_with
(C++20)
 指定比较运算符在该类型上产生全序
(概念)
定义于头文件 <compare>
three_way_comparablethree_way_comparable_with
(C++20)
 指定运算符 <=> 在给定类型上产生一致的结果
(概念)
对象概念
定义于头文件 <concepts>
movable
(C++20)
 指定能移动及交换一个类型的对象
(概念)
copyable
(C++20)
 指定能复制、移动及交换一个类型的对象
(概念)
semiregular
(C++20)
 指定能赋值、移动、交换及默认构造一个类型的对象
(概念)
regular
(C++20)
 指定类型为正则，即它既为 semiregular 亦为 equality_comparable
(概念)
可调用概念
定义于头文件 <concepts>
invocableregular_invocable
(C++20)
 指定能以给定的一组实参类型调用的可调用类型
(概念)
predicate
(C++20)
 指定可调用类型为布尔谓词
(概念)
relation
(C++20)
 指定可调用类型为二元关系
(概念)
equivalence_relation
(C++20)
 指定 relation 施加等价关系
(概念)
strict_weak_order
(C++20)
 指定一个 relation 所强加的是严格弱序
(概念)

更多概念可在迭代器库、算法库与范围库中找到。


std::assignable_from

< cpp‎ | concepts
定义于头文件 <concepts>
template< class LHS, class RHS >

concept assignable_from =
std::is_lvalue_reference_v <LHS> &&
std::common_reference_with<
const std::remove_reference_t <LHS>&,
const std::remove_reference_t <RHS>&> &&
requires(LHS lhs, RHS&& rhs) {
{ lhs = std::forward <RHS>(rhs) } -> std::same_as<LHS>;

};
 (C++20 起)

概念 assignable_from<LHS, RHS> 指定能赋值类型和值类别由 RHS 编码的表达式给类型为 LHS 所指定的左值表达式。

语义要求

给定

  • lhs ，指代对象 lcopy 的左值，使得 decltype((lhs)) 为 LHS ，
  • rhs ，使得 decltype((rhs)) 为 RHS 的表达式，
  • rcopy ，等于 rhs 的单独对象，

assignable_from<LHS, RHS> 仅若符合下列条件才得到实现

  • std::addressof (lhs = rhs) == std::addressof (lcopy) （即赋值表达式生成指代左操作数的左值）；
  • 求值 lhs = rhs 后：
    • lhs 等于 rcopy ，除非 rhs 是指代 lcopy 的非 const 亡值（即赋值为自移动赋值），
    • 若 rhs 是泛左值；
      • 若它是非 const 亡值，则其所指代的对象在合法但未指定的状态；
      • 否则，不修改其所指代的对象；

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

注解

赋值不必为全函数。具体来说，若赋值给某对象 x 可能导致修改某其他对象 y ，则 x = y 可能不在 = 的定义域中。若左操作数直接或间接占有右操作数（例如用指向基于结点的数据结构中的结点的智能指针，或用类似 std::vector < std::any > 的构造），则这常发生。

参阅

is_assignableis_trivially_assignableis_nothrow_assignable
(C++11)(C++11)(C++11)
 检查类型是否拥有针对特定实参的赋值运算符
(类模板)


boolean-testable

< cpp‎ | concepts
template<class B>

concept __boolean_testable_impl = // 仅用于阐释

std::convertible_to<B, bool>;
 (C++20 起)
template<class B>

concept boolean-testable = // 仅用于阐释
__boolean_testable_impl<B> &&
requires (B&& b) {
{ ! std::forward <B>(b) } -> __boolean_testable_impl;

};
 (C++20 起)

仅用于阐释的概念 boolean-testable 指定可转换成 bool 的表达式，和逻辑运算符拥有通常行为（包括短路），即使是对于二个不同的 boolean-testable 类型的要求。

正式而言，为满足仅用于阐释的概念 __boolean_testable_impl ，类型必须不定义任何成员 operator&& 与 operator|| ，而且无可生成的非成员 operator&& 及 operator|| 可对实参依赖查找可见。另外给定使 decltype((e)) 为 B 的表达式 e ， boolean-testable 仅若 bool(e) == !bool(!e) 才得到实现。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

注解

boolean-testable 类型的例子包括 bool、 std::true_type、 std::bitset <N>::reference 和 int* 。


std::common_reference_with

< cpp‎ | concepts
定义于头文件 <concepts>
template < class T, class U >

concept common_reference_with =
std::same_as<std::common_reference_t<T, U>, std::common_reference_t<U, T>> &&
std::convertible_to<T, std::common_reference_t<T, U>> &&

std::convertible_to<U, std::common_reference_t<T, U>>;
 (C++20 起)

概念 common_reference_with<T, U> 指定二个类型 T 与 U 共享均能转换到的共用引用类型（以 std::common_reference_t 计算）。

语义要求

T 与 U 实现 common_reference_with<T, U> ，仅若给定保持相等性的表达式 t1 、 t2 、 u1 及 u2 ，且它们满足 decltype((t1)) 与 decltype((t2)) 均为 T 而 decltype((u1)) 与 decltype((u2)) 均为 U ，且

  • std::common_reference_t<T, U>(t1) 等于 std::common_reference_t<T, U>(t2) 当且仅当 t1 等于 t2 ；而
  • std::common_reference_t<T, U>(u1) 等于 std::common_reference_t<T, U>(u2) 当且仅当 u1 等于 u2 。

换言之，转换到共用引用类型必须保持相等性。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

参阅

common_referencebasic_common_reference (C++20) | 确定类型组的共用引用类型 (类模板)
common_with (C++20) | 指定两个类型共有一个公共类型 (概念)
common_type (C++11) | 确定一组类型的公共类型 (类模板)


std::common_with

< cpp‎ | concepts
定义于头文件 <concepts>
template <class T, class U>

concept common_with =
std::same_as< std::common_type_t <T, U>, std::common_type_t <U, T>> &&
requires {
static_cast< std::common_type_t <T, U>>( std::declval <T>());
static_cast< std::common_type_t <T, U>>( std::declval <U>());
} &&
std::common_reference_with<
std::add_lvalue_reference_t <const T>,
std::add_lvalue_reference_t <const U>> &&
std::common_reference_with<
std::add_lvalue_reference_t < std::common_type_t <T, U>>,
std::common_reference_t<
std::add_lvalue_reference_t <const T>,

std::add_lvalue_reference_t <const U>>>;
 (C++20 起)

概念 common_with<T, U> 指定二个类型 T 与 U 共享均能转换到的共用类型（以 std::common_type_t 计算）。

语义要求

T 与 U 实现 common_with<T, U> ，仅若给定保持相等性的表达式 t1 、 t2 、 u1 和 u2 ，且它们满足 decltype((t1)) 与 decltype((t2)) 均为 T 而 decltype((u1)) 与 decltype((u2)) 均为 U ，且

  • std::common_type_t <T, U>(t1) 等于 std::common_type_t <T, U>(t2) 当且仅当 t1 等于 t2 ；而
  • std::common_type_t <T, U>(u1) 等于 std::common_type_t <T, U>(u2) 当且仅当 u1 等于 u2 。

换言之，转换到共用类型必须保持相等性。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

参阅

common_type (C++11) | 确定一组类型的公共类型 (类模板)
common_referencebasic_common_reference (C++20) | 确定类型组的共用引用类型 (类模板)
common_reference_with (C++20) | 指定两个类型共有一个公共引用类型 (概念)


std::constructible_from

< cpp‎ | concepts
定义于头文件 <concepts> |
template < class T, class... Args > concept constructible_from = std::destructible<T> && std::is_constructible_v <T, Args...>; | (C++20 起)

constructible_from 概念指定 T 类型变量能以给定的参数类型集 Args... 初始化。

参阅

is_constructibleis_trivially_constructibleis_nothrow_constructible
(C++11)(C++11)(C++11)
 检查类型是否带有针对特定实参的构造函数
(类模板)


std::convertible_to

< cpp‎ | concepts
定义于头文件 <concepts>
template <class From, class To>

concept convertible_to =
std::is_convertible_v <From, To> &&
requires {
static_cast<To>( std::declval <From>());

};
 (C++20 起)

概念 convertible_to<From, To> 指定类型和值类别均与 std::declval <From>() 相同的表达式能隐式和显式转换成 To 类型，而二种转换形式等价。

语义要求

convertible_to<From, To> 仅若符合下列条件才得以实现。给定 std::add_rvalue_reference_t <From>() 类型函数 fun ，满足表达式 fun() 保持相等性（见下方），

  • 以下任一成立
    • To 既非对象亦非到对象引用类型，或
    • static_cast<To>(fun()) 等于 []() -> To { return fun(); }() ，且
  • 下列之一为真：
    • std::add_rvalue_reference_t <From> 不是到对象引用类型，或
    • std::add_rvalue_reference_t <From> 是到非 const 限定类型的右值引用，而 fun() 所引用的结果状态在上述任一表达式后合法但未指定；或
    • 上述任一表达式不修改 fun() 所引用的对象。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

参阅

is_convertibleis_nothrow_convertible
(C++11)(C++20)
 检查是否能转换一个类型为另一类型
(类模板)


std::copy_constructible

< cpp‎ | concepts
定义于头文件 <concepts>
template <class T>

concept copy_constructible =
std::move_constructible<T> &&
std::constructible_from<T, T&> && std::convertible_to<T&, T> &&
std::constructible_from<T, const T&> && std::convertible_to<const T&, T> &&

std::constructible_from<T, const T> && std::convertible_to<const T, T>;
 (C++20 起)

概念 copy_constructible 若符合这些条件则得到满足： T 为左值引用类型，或若它是 move_constructible 对象类型，而能从（可为 const 的）该类型左值或 const 右值，在直接和复制初始化语境中以通常语义构造该类型对象（构造副本而不更改源）。

语义要求

若 T 为对象类型，则 copy_constructible<T> 仅若符合下列条件才得到实现。给定

  • v ， T 类型左值（可为 const ）或为 const T 类型右值，

下列为真：

  • 定义 T u = v; 后， u 等于 v 且 v 不被修改；
  • T(v) 等于 v 且不修改 v 。

参阅

is_copy_constructibleis_trivially_copy_constructibleis_nothrow_copy_constructible
(C++11)(C++11)(C++11)
 检查类型是否拥有复制构造函数
(类模板)


std::copyable

< cpp‎ | concepts
定义于头文件 <concepts>
template <class T>

concept copyable =
std::copy_constructible<T> &&
std::movable<T> &&
std::assignable_from<T&, T&> &&
std::assignable_from<T&, const T&> &&

std::assignable_from<T&, const T>;
 (C++20 起)

概念 copyable<T> 指定 T 是亦能复制的 movable 对象类型（即它支持移动构造和移动赋值）。

参阅

movable
(C++20)
 指定能移动及交换一个类型的对象
(概念)


std::default_initializable

< cpp‎ | concepts
定义于头文件 <concepts>
template < class T >

concept default_initializable = std::constructible_from<T> && requires { T{}; } &&

/* T t; 为良构，见后述 */;
 (C++20 起)

default_initializable 概念检查 T 类型变量能否

  • 值初始化（ T() 为良构）
  • 从空初始化器列表直接列表初始化（ T{} 为良构）；以及
  • 默认初始化（ T t; 为良构）。

如同在与 T 无关的语境中进行访问检查。仅考虑变量初始化的立即语境的合法性。

可能的实现

template<class T>
concept default_initializable =
    std::constructible_from<T> &&
    requires { T{}; } &&
    requires { ::new (static_cast<void*>(nullptr)) T; };

参阅

constructible_from (C++20) | 指定该类型的变量能从一组实参类型进行构造，或绑定到一组实参类型 (概念)
is_default_constructibleis_trivially_default_constructibleis_nothrow_default_constructible (C++11)(C++11)(C++11) | 检查类型是否有默认构造函数 (类模板)


std::derived_from

< cpp‎ | concepts
定义于头文件 <concepts> |
template< class Derived, class Base > concept derived_from = std::is_base_of_v <Base, Derived> && std::is_convertible_v <const volatile Derived*, const volatile Base*>; | (C++20 起)

概念 derived_from<Derived, Base> 若且唯若忽略 cv 限定符后 Base 是类类型，且它为 Derived 或是 Derived 的公开无歧义基类才得到满足。

注意当 Base 是 Derived 的私有或受保护基类时，此行为异于 std::is_base_of 。

参阅

is_base_of (C++11) | 检查一个类型是否派生自另一个类型 (类模板)
is_convertibleis_nothrow_convertible (C++11)(C++20) | 检查是否能转换一个类型为另一类型 (类模板)


std::destructible

< cpp‎ | concepts
定义于头文件 <concepts> |
template < class T > concept destructible = std::is_nothrow_destructible_v <T>; | (C++20 起)

概念 destructible 指定能在实例生存期结尾安全销毁的所有类型（包含引用类型）的概念。

注解

不同于 可析构 (Destructible) 具名要求， std::destructible 要求析构函数为 noexcept(true) ，而不仅是调用时不抛出，并且允许引用类型和数组类型。

参阅

is_destructibleis_trivially_destructibleis_nothrow_destructible
(C++11)(C++11)(C++11)
 检查类型是否拥有未被弃置的析构函数
(类模板)


std::equality_comparable, std::equality_comparable_with

< cpp‎ | concepts
定义于头文件 <concepts>
template < class T >
concept equality_comparable = __WeaklyEqualityComparableWith<T, T>;
 (1) (C++20 起)
template <class T, class U>

concept equality_comparable_with =
std::equality_comparable<T> &&
std::equality_comparable<U> &&
std::common_reference_with<
const std::remove_reference_t <T>&,
const std::remove_reference_t <U>&> &&
std::equality_comparable<
std::common_reference_t<
const std::remove_reference_t <T>&,
const std::remove_reference_t <U>&>> &&

__WeaklyEqualityComparableWith<T, U>;
 (2) (C++20 起)
template<class T, class U>

concept __WeaklyEqualityComparableWith = // 仅用于解释
requires(const std::remove_reference_t <T>& t,
const std::remove_reference_t <U>& u) {
{ t == u } -> boolean-testable;
{ t != u } -> boolean-testable;
{ u == t } -> boolean-testable;
{ u != t } -> boolean-testable;

};
 (3) (C++20 起)
1) 概念 std::equality_comparable 指定比较运算符 == 和 != 在 T 上反映相等性： == 若且唯若运算数相等才生成 true 。
2) 概念 std::equality_comparable_with 指定比较运算符 == 和 != 在（可能混合的） T 和 U 运算数上生成与相等一致的结果。比较混合的运算数产生的结果等价于比较转换到其共用类型的运算数。
3) 仅用于阐释的概念 __WeaklyEqualityComparableWith 指定 T 类型对象和 U 类型对象能用 == 和 != 彼此比较相等（以任一顺序），而比较结果一致。

语义要求

这些概念仅若其所蕴含的概念均被实现才得到实现。

1) std::equality_comparable<T> 仅若符合下列条件才得到实现。给定 T 类型对象 a 和 b ， bool(a == b) 若且唯若 a 和 b 相等才为 true 。同 a == b 保持相等性的要求，这隐含 == 为对称且传递，而且 == 进而对所有至少等于一个其他对象的 a 自反。
2) std::equality_comparable_with<T, U> 仅若符合下列条件才得到实现，给定任何 const std::remove_reference_t <T> 类型左值 t 和任何 const std::remove_reference_t <U> 类型左值 u ，并令 C 为 std::common_reference_t<const std::remove_reference_t <T>&, const std::remove_reference_t <U>&> ，则 bool(t == u) == bool(C(t) == C(u)) 。
3) __WeaklyEqualityComparableWith<T, U> 仅若符合下列条件才得到实现。给定
  • t ， const std::remove_reference_t <T> 类型左值，和
  • u ， const std::remove_reference_t <U> 类型左值，

下列为真：

  • t == u 、 u == t 、 t != u 、 u != t 拥有相同定义域；
  • bool(u == t) == bool(t == u) ；
  • bool(t != u) == !bool(t == u) ；且
  • bool(u != t) == bool(t != u) 。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

隐式表达式变种

使用不修改某 const 左值运算数的表达式的 requires 表达式亦隐式要求该表达式的额外变种对给定运算数接受非 const 左值或（可为 const 的）右值，除非以有区别的语义显式要求这种表达式变种。这些隐式表达式变种必须符合与声明的表达式的相同的语义。不指定实现以何种程度校验变种的语法。


std::equivalence_relation

< cpp‎ | concepts
定义于头文件 <concepts> |
template < class R, class T, class U > concept equivalence_relation = std::relation<R, T, U>; | (C++20 起)

概念 equivalence_relation<R, T, U> 指定 relation R 在其参数上施加等价关系。

语义要求

关系 r 为等价关系若

  • 它为自反：对于所有 x ， r(x, x) 为 true ；
  • 它为对称：对于所有 a 与 b ， r(a, b) 为 true 当且仅当 r(b, a) 为 true ；
  • 它为传递： r(a, b) && r(b, c) 蕴含 r(a, c) 。

注解

relation 与 equivalence_relation 间的区别是纯语义的。


std::floating_point

< cpp‎ | concepts
定义于头文件 <concepts> |
template < class T > concept floating_point = std::is_floating_point_v <T>; | (C++20 起)

概念 floating_point<T> 当且仅当 T 为浮点类型才得到满足。

参阅

is_floating_point
(C++11)
 检查类型是否是浮点类型
(类模板)


std::integral

< cpp‎ | concepts
定义于头文件 <concepts> |
template < class T > concept integral = std::is_integral_v <T>; | (C++20 起)

概念 integral<T> 若且唯若 T 为整数类型才得到满足。

参阅

is_integral
(C++11)
 检查类型是否为整型
(类模板)


std::invocable, std::regular_invocable

< cpp‎ | concepts
定义于头文件 <concepts>
template< class F, class... Args >

concept invocable =
requires(F&& f, Args&&... args) {
std::invoke ( std::forward <F>(f), std::forward <Args>(args)...);
/* 不要求保持相等性 */

};
 (C++20 起)
template< class F, class... Args >
concept regular_invocable = std::invocable<F, Args...>;
 (C++20 起)

invocable 概念指定能用函数模板 std::invoke 以参数集 Args... 调用可调用类型 F 。

regular_invocable 概念对 invocable 概念增加 invoke 必须保持相等性且不修改可调用对象或参数。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

注意

invocable 与 regular_invocable 间的区别是纯语义上的。

随机数生成器可满足 invocable 但不能满足 regular_invocable （除了搞笑 的）。


std::movable

< cpp‎ | concepts
定义于头文件 <concepts>
template < class T >

concept movable =
std::is_object_v <T> &&
std::move_constructible<T> &&
std::assignable_from<T&, T> &&

std::swappable<T>;
 (C++20 起)

概念 movable<T> 指定 T 是能移动的对象类型（即它能移动构造、移动赋值，而 T 类型左值能交换）。

参阅

copyable
(C++20)
 指定能复制、移动及交换一个类型的对象
(概念)


std::move_constructible

< cpp‎ | concepts
定义于头文件 <concepts> |
template< class T > concept move_constructible = std::constructible_from<T, T> && std::convertible_to<T, T>; | (C++20 起)

概念 move_constructible 若符合这些条件则得到满足， T 为引用类型，或它是对象类型，并且能在直接和复制初始化语境中，以通常语义从该类型右值构造该类型对象。

语义要求

若 T 是对象类型，则 move_constructible<T> 仅若符合下列条件才得到实现。给定

  • rv ， T 类型右值，和
  • u2 ，等于 rv 的 T 类型不同对象，

下列为真：

  • 在定义 T u = rv; 后， u 等于 u2 ；
  • T(rv) 等于 u2 ；且
  • 若 T 无 const 限定，则 rv 的结果状态（在上述任一条中求值的定义/表达式后）合法但未指定；否则不更改它。

参阅

is_move_constructibleis_trivially_move_constructibleis_nothrow_move_constructible
(C++11)(C++11)(C++11)
 检查类型是否能从右值引用构造
(类模板)


std::predicate

< cpp‎ | concepts
定义于头文件 <concepts> |
template < class F, class... Args > concept predicate = std::regular_invocable<F, Args...> && boolean-testable<std::invoke_result_t<F, Args...>>; | (C++20 起)

概念 predicate<F, Args...> 指定 F 是谓词，接受类型和值类别由 Args... 编码的参数，即能以这些参数调用它并产生 boolean-testable 结果。

注意 regular_invocable 要求调用既不修改可调用对象亦不修改参数，并保持相等性。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。


std::regular

< cpp‎ | concepts
定义于头文件 <concepts> |
template <class T> concept regular = std::semiregular<T> && std::equality_comparable<T>; | (C++20 起)

regular 概念指定类型为正则，即它可复制、可默认构造且可比较相等。表现类似如 int 的内建类型，且能以 == 比较的类型满足它。

示例

#include <concepts>
#include <iostream>

template<std::regular T>
struct Single {
    T value;
    friend bool operator==(const Single&, const Single&) = default;
};

int main()
{
    Single<int> myInt1{4};
    Single<int> myInt2;
    myInt2 = myInt1;

    if (myInt1 == myInt2)
        std::cout << "Equal\n";

    std::cout << myInt1.value << ' ' << myInt2.value << '\n';
}

输出：

Equal
4 4

参阅

semiregular
(C++20)
 指定能赋值、移动、交换及默认构造一个类型的对象
(概念)


std::relation

< cpp‎ | concepts
定义于头文件 <concepts> |
template <class R, class T, class U> concept relation = std::predicate<R, T, T> && std::predicate<R, U, U> && std::predicate<R, T, U> && std::predicate<R, U, T>; | (C++20 起)

概念 relation<R, T, U> 指定 R 定义在类型和值类别为 T 或 U 所编码的表达式上的二元关系。


std::same_as

< cpp‎ | concepts
定义于头文件 <concepts> |
template < class T, class U > concept same_as = /* see below */; | (C++20 起)

概念 same_as<T, U> 若且唯若 T 与 U 代表同一类型才得到满足。

std::same_as<T, U> 包含 std::same_as<U, T> ，反之亦然。

可能的实现

namespace detail {
    template< class T, class U >
    concept SameHelper = std::is_same_v<T, U>;
}

template< class T, class U >
concept same_as = detail::SameHelper<T, U> && detail::SameHelper<U, T>;

参阅

is_same
(C++11)
 检查两个类型是否相同
(类模板)


std::semiregular

< cpp‎ | concepts
定义于头文件 <concepts> |
template <class T> concept semiregular = std::copyable<T> && std::default_initializable<T>; | (C++20 起)

semiregular 概念指定类型既为可复制亦为可默认构造。表现类似如 int 的内建类型的类型满足它，除了它们不需要支持以 == 比较。

示例

#include <concepts>
#include <iostream>

template<std::semiregular T>
// 版权所有 Alexander Stepanov
// 概念是 T 上的要求
// T 上的要求： T 为半正则
// T a(b) 或 T a = b => 复制构造函数； T a => 默认构造函数； a = b => 赋值；
struct Single {
    T value;
    // 隐式声明的特殊成员函数表现类似以下定义，除了它们可以拥有额外属性。
    // Single(const Single& x) : value(x.value){}
    // Single(){}
    // ~Single(){}
    // Single& operator=(const Single& x) { value = x.value; return *this; }
};

int main()
{
    Single<int> myInt1;
    myInt1.value = 4;
    Single<int> myInt2(myInt1);
    Single<int> myInt3;
    myInt3 = myInt2;

    std::cout << myInt1.value << ' ' << myInt2.value << ' ' << myInt3.value << '\n';
}

输出：

4 4 4

参阅

regular
(C++20)
 指定类型为正则，即它既为 semiregular 亦为 equality_comparable
(概念)


std::signed_integral

< cpp‎ | concepts
定义于头文件 <concepts> |
template < class T > concept signed_integral = std::integral<T> && std::is_signed_v <T>; | (C++20 起)

概念 signed_integral<T> 若且唯若 T 为整数类型且 std::is_signed_v <T> 为 true 才得到满足。.

注意

signed_integral<T> 可以为不是有符号整数类型，如 char 的类型所满足（在 char 为有符号的系统上）。

参阅

is_integral (C++11) | 检查类型是否为整型 (类模板)
is_signed (C++11) | 检查类型是否为有符号算术类型 (类模板)


std::strict_weak_order

< cpp‎ | concepts
定义于头文件 <concepts> |
template < class R, class T, class U > concept strict_weak_order = std::relation<R, T, U>; | (C++20 起)

概念 strict_weak_order<R, T, U> 指定 relation R 在其参数上施加严格弱序。

语义要求

若符合下列条件，则关系 r 是严格弱序：

  • 它非自反：对所有 x ， r(x, x) 为 false ；
  • 它为传递：对所有 a 、 b 和 c ，若 r(a, b) 与 r(b, c) 均为 true ，则 r(a, c) 为 true ；
  • 令 e(a, b) 为 !r(a, b) && !r(b, a) ，则 e 为传递： e(a, b) && e(b, c) 蕴含 e(a, c) 。

在这些条件下，能证明 e 是等价关系，而 r 在 e 所确定的等价类上引入严格全序。

注解

relation 与 strict_weak_order 间的区别是纯语义的。


std::swappable, std::swappable_with

< cpp‎ | concepts
定义于头文件 <concepts>
template< class T >

concept swappable =
requires(T& a, T& b) {
ranges::swap(a, b);

};
 (1) (C++20 起)
template< class T, class U >

concept swappable_with =
common_reference_with<T, U> &&
requires(T&& t, U&& u) {
ranges::swap( std::forward <T>(t), std::forward <T>(t));
ranges::swap( std::forward <U>(u), std::forward <U>(u));
ranges::swap( std::forward <T>(t), std::forward <U>(u));
ranges::swap( std::forward <U>(u), std::forward <T>(t));

};
 (2) (C++20 起)

概念 swappable<T> 指定 T 类型左值可交换。

概念 swappable_with<T, U> 指定属于 T 和 U 所编码的类型和值类别的表达式彼此可交换。 swappable_with<T, U> 仅若调用 ranges::swap(t, u) 交换 t 与 u 的值，即给定等于 t 的独立对象 t2 和等于 u 的独立对象 u2 ，求值 ranges::swap(t, u) 或 ranges::swap(u, t) 后 t2 等于 u 且 u2 等于 t ，才得到满足。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。


std::totally_ordered, std::totally_ordered_with

< cpp‎ | concepts
定义于头文件 <concepts>
template <class T>

concept totally_ordered =

std::equality_comparable<T> && __PartiallyOrderedWith<T, T>;
 (1) (C++20 起)
template <class T, class U>

concept totally_ordered_with =
std::totally_ordered<T> &&
std::totally_ordered<U> &&
std::equality_comparable_with<T, U> &&
std::totally_ordered<
std::common_reference_t<
const std::remove_reference_t <T>&,
const std::remove_reference_t <U>&>> &&

__PartiallyOrderedWith<T, U>;
 (2) (C++20 起)
template<class T, class U>

concept __PartiallyOrderedWith = // 仅用于阐释
requires(const std::remove_reference_t <T>& t,
const std::remove_reference_t <U>& u) {
{ t < u } -> boolean-testable;
{ t > u } -> boolean-testable;
{ t <= u } -> boolean-testable;
{ t >= u } -> boolean-testable;
{ u < t } -> boolean-testable;
{ u > t } -> boolean-testable;
{ u <= t } -> boolean-testable;
{ u >= t } -> boolean-testable;

};
 (3) (C++20 起)
1) 概念 std::totally_ordered 指定比较运算符 ==,!=,<,>,<=,>= 在一个类型上产生的结果与该类型上的严格全序一致。
2) 概念 std::totally_ordered_with 指定比较运算符 ==,!=,<,>,<=,>= 在（可能混合的） T 和 U 运算数上产生的结果等价于比较转换到其共用类型的运算数的结果。
3) 仅用于阐释的概念 __PartiallyOrderedWith 指定 T 类型对象与 U 类型对象能（以任何顺序）用 < 、 > 、 <= 及 >= 在一个偏序中彼此比较，且比较结果一致。

语义要求

这些概念仅若其所蕴含的概念均被实现才得到实现。

1) std::totally_ordered<T> 仅若符合下列条件才得到实现。给定 const std::remove_reference_t <T> 类型左值 a 、 b 和 c ：
  • bool(a < b) 、 bool(a > b) 和 bool(a == b) 恰有一者为 true ；
  • 若 bool(a < b) 与 bool(b < c) 均为 true ，则 bool(a < c) 为 true ；
  • bool(a > b) == bool(b < a)
  • bool(a >= b) == !bool(a < b)
  • bool(a <= b) == !bool(b < a)
2) 正式而言， std::totally_ordered_with<T, U> 仅若符合下列条件才得到实现。仅若给定
  • t ， const std::remove_reference_t <T> 类型左值，与
  • u ， const std::remove_reference_t <U> 类型左值，

并令 C 为 std::common_reference_t<const std::remove_reference_t <T>&, const std::remove_reference_t <U>&> ：

  • bool(t < u) == bool(C(t) < C(u))
  • bool(t > u) == bool(C(t) > C(u))
  • bool(t <= u) == bool(C(t) <= C(u))
  • bool(t >= u) == bool(C(t) >= C(u))
  • bool(u < t) == bool(C(u) < C(t))
  • bool(u > t) == bool(C(u) > C(t))
  • bool(u <= t) == bool(C(u) <= C(t))
  • bool(u >= t) == bool(C(u) >= C(t))
3) 正式而言， T 与 U 实现 __PartiallyOrderedWith<T, U> ，仅若给定
  • t ， const std::remove_reference_t <T> 类型左值，与
  • u ， const std::remove_reference_t <U> 类型左值

下列为真：

  • t < u 、 t <= u 、 t > u 、 t >= u 、 u < t 、 u <= t 、 u > t 及 u >= t 拥有相同定义域；
  • bool(t < u) == bool(u > t) ；
  • bool(u < t) == bool(t > u) ；
  • bool(t <= u) == bool(u >= t) ；且
  • bool(u <= t) == bool(t >= u) 。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

隐式表达式变种

使用不修改某 const 左值运算数的表达式的 requires 表达式亦隐式要求该表达式的额外变种对给定运算数接受非 const 左值或（可为 const 的）右值，除非以有区别的语义显式要求这种表达式变种。这些隐式表达式变种必须符合与声明的表达式的相同的语义。不指定实现以何种程度校验变种的语法。


std::unsigned_integral

< cpp‎ | concepts
定义于头文件 <concepts> |
template < class T > concept unsigned_integral = std::integral<T> && !std::signed_integral<T>; | (C++20 起)

概念 unsigned_integral<T> 若且唯若 T 是整数类型且 std::is_signed_v <T> 为 false 才得到满足。

注解

unsigned_integral<T> 可以为不是有符号整数类型的类型，例如 bool 所满足。

参阅

is_integral (C++11) | 检查类型是否为整型 (类模板)
is_signed (C++11) | 检查类型是否为有符号算术类型 (类模板)


容器库

< cpp

容器库是类模板与算法的汇集，允许程序员简单地访问常见数据结构，例如队列、链表和栈。有三类容器——顺序容器、关联容器和无序关联容器——每种都被设计为支持不同组的操作。

容器管理为其元素分配的存储空间，并提供直接或间接地通过迭代器（拥有类似指针属性的对象）访问它们的函数。

大多数容器拥有至少几个常见的成员函数，并共享功能。特定应用的最佳容器不仅依赖于提供的功能，还依赖于对于不同工作量的效率。

顺序容器

顺序容器实现能按顺序访问的数据结构。

array (C++11) | 静态的连续数组 (类模板)
vector | 动态的连续数组 (类模板)
deque | 双端队列 (类模板)
forward_list (C++11 起) | 单链表 (类模板)
list | 双链表 (类模板)

关联容器

关联容器实现能快速查找（ O(log n) 复杂度）的数据结构。

set | 唯一键的集合，按照键排序 (类模板)
map | 键值对的集合，按照键排序，键是唯一的 (类模板)
multiset | 键的集合，按照键排序 (类模板)
multimap | 键值对的集合，按照键排序 (类模板)

无序关联容器

无序关联容器提供能快速查找（均摊 O(1) ，最坏情况 O(n) 的复杂度）的无序（哈希）数据结构。

unordered_set (C++11 起) | 唯一键的集合，按照键生成散列 (类模板)
unordered_map (C++11 起) | 键值对的集合，按照键生成散列，键是唯一的 (类模板)
unordered_multiset (C++11 起) | 键的集合，按照键生成散列 (类模板)
unordered_multimap (C++11 起) | 键值对的集合，按照键生成散列 (类模板)

容器适配器

容器适配器提供顺序容器的不同接口。

stack | 适配一个容器以提供栈（LIFO 数据结构） (类模板)
queue | 适配一个容器以提供队列（FIFO 数据结构） (类模板)
priority_queue | 适配一个容器以提供优先级队列 (类模板)

span

span 是相接的对象序列上的非占有视图，某个其他对象占有序列的存储。

span
(C++20)
 对象的连续序列上的无所有权视图
(类模板)

迭代器非法化

只读方法决不非法化迭代器或引用。修改容器内容的方法可能非法化迭代器和/或引用，总结于此表格。

类别 | 容器 | 插入后…… |  | 擦除后…… |  | 条件
 |  | 迭代器合法？ | 引用合法？ | 迭代器合法？ | 引用合法？
顺序容器 | array | N/A |  | N/A |  |
 | vector | 否 |  | N/A |  | 插入更改容量
 |  | 是 |  | 是 |  | 被修改元素前
 |  | 否 |  | 否 |  | 于被修改元素或其后
 | deque | 否 | 是 | 是，除了被擦除元素 |  | 修改首或尾元素
 |  |  | 否 | 否 |  | 仅修改中部
 | list | 是 |  | 是，除了被擦除元素 |  |
 | forward_list | 是 |  | 是，除了被擦除元素 |  |
关联容器 | set multiset map multimap | 是 |  | 是，除了被擦除元素 |  |
无序关联容器 | unordered_set unordered_multiset unordered_map unordered_multimap | 否 | 是 | N/A |  | 插入导致重哈希
 |  | 是 |  | 是，除了被擦除元素 |  | 无重哈希

此处插入指代任何添加一或多个元素到容器的方法，而擦除指代任何从容器移除一或多个元素的方法。

  • 插入方法的例子是 std::set::insert 、 std::map::emplace 、 std::vector::push_back 和 std::deque::push_front 。
    • 注意 std::unordered_map::operator[] 也算，因为它可能插入元素到 map 中。
  • 擦除方法的例子是 std::set::erase 、 std::vector::pop_back 、 std::deque::pop_front 和 std::map::clear 。
    • clear 非法化所有迭代器和引用。因为它擦除所有元素，这在技术上遵照上述规则。

尾后迭代器需要特别留意。通常像指向未被擦除元素的正常迭代器一般非法化此迭代器。故 std::set::end 决不被非法化， std::unordered_set::end 仅在重哈希时被非法化， std::vector::end 始终被非法化（因为它始终出现在被修改元素后），以此类推。

有一个例外：删除 std::deque 末元素的擦除操作会非法化尾后迭代器，尽管它不是容器的被擦除元素（或者说根本不是元素）。与 std::deque 迭代器的通用规则结合后，最终结果是不非法化 std::deque::end 的唯一修改操作是删除首元素，而非末元素的擦除。

线程安全

  1. 能同时在不同容器上由不同线程调用所有容器函数。更广泛而言， C++ 标准库函数不读取能通过其他线程访问的对象，除非这些对象能直接或间接地经由函数参数，包含 this 指针访问。
  2. 能同时在同一容器上由不同线程调用 const 成员函数。而且，成员函数 begin() 、 end(), rbegin() 、 rend() 、 front() 、 back() 、 data() 、 find() 、 lower_bound() 、 upper_bound() 、 equal_range() 、 at() 和除了关联容器中的 operator[] 对于线程安全的目标表现如同 const （即它们亦能同时在同一容器上由不同线程调用）。更广泛而言， C++ 标准库函数不修改对象，除非这些对象能直接或间接地经由函数参数，包含 this 指针访问。
  3. 同一容器中不同元素能由不同线程同时修改，除了 std::vector<bool> 的元素（例如， std::future 对象的 vector 能从多个线程接收值）。
  4. 迭代器操作（例如自增迭代器）读但不修改底层容器，而且能与同一容器上的其他迭代器操作同时由 const 成员函数执行。非法化任何迭代器的容器操作修改容器，且不能与任何在既存迭代器上的操作同时执行，即使这些迭代器未被非法化。
  5. 同一容器上的元素可以同时由不指定为访问这些元素的函数修改。更广泛而言， C++ 标准库函数不间接读取能从其参数访问的对象（包含容器的其他对象），除非其规定要求如此。
  6. 任何情况下，容器操作（还有算法，或其他 C++ 标准库函数）可于内部并行化，只要不更改用户可见的结果（例如 std::transform 可并行化，但指定了按顺序观览序列的每个元素的 std::for_each 不行）
 (C++11 起)

成员函数表格

- C++03 起存在的函数
- C++11 起存在的函数
- C++17 起存在的函数
- C++20 起存在的函数
顺序容器 | 关联容器 | 无序关联容器 | 容器适配器
头文件 | <array> | <vector> | <deque> | <forward_list> | <list> | <set> | <map> | <unordered_set> | <unordered_map> | <stack> | <queue>
容器
array
vector
deque
forward_list
list
set
multiset
map
multimap
unordered_set
unordered_multiset
unordered_map
unordered_multimap
stack
queue
priority_queue
(构造函数)
(隐式)
vector
deque
forward_list
list
set
multiset
map
multimap
unordered_set
unordered_multiset
unordered_map
unordered_multimap
stack
queue
priority_queue
(析构函数)
(隐式)
~vector
~deque
~forward_list
~list
~set
~multiset
~map
~multimap
~unordered_set
~unordered_multiset
~unordered_map
~unordered_multimap
~stack
~queue
~priority_queue
operator=
(隐式)
operator=
operator=
operator=
operator=
operator=
operator=
operator=
operator=
operator=
operator=
operator=
operator=
operator=
operator=
operator=
assign
assign
assign
assign
assign
迭代器
begin
cbegin
begin
cbegin
begin
cbegin
begin
cbegin
begin
cbegin
begin
cbegin
begin
cbegin
begin
cbegin
begin
cbegin
begin
cbegin
begin
cbegin
begin
cbegin
begin
cbegin
begin
cbegin
end
cend
end
cend
end
cend
end
cend
end
cend
end
cend
end
cend
end
cend
end
cend
end
cend
end
cend
end
cend
end
cend
end
cend
rbegin
crbegin
rbegin
crbegin
rbegin
crbegin
rbegin
crbegin
rbegin
crbegin
rbegin
crbegin
rbegin
crbegin
rbegin
crbegin
rbegin
crbegin
rend
crend
rend
crend
rend
crend
rend
crend
rend
crend
rend
crend
rend
crend
rend
crend
rend
crend
元素访问
at
at
at
at
at
at
operator[]
operator[]
operator[]
operator[]
operator[]
operator[]
data
data
data
front
front
front
front
front
front
front
top
back
back
back
back
back
top
back
容量
empty
empty
empty
empty
empty
empty
empty
empty
empty
empty
empty
empty
empty
empty
empty
empty
empty
size
size
size
size
size
size
size
size
size
size
size
size
size
size
size
size
max_size
max_size
max_size
max_size
max_size
max_size
max_size
max_size
max_size
max_size
max_size
max_size
max_size
max_size
resize
resize
resize
resize
resize
capacity
capacity
bucket_count
bucket_count
bucket_count
bucket_count
reserve
reserve
reserve
reserve
reserve
reserve
shrink_to_fit
shrink_to_fit
shrink_to_fit
修改器
clear
clear
clear
clear
clear
clear
clear
clear
clear
clear
clear
clear
clear
insert
insert
insert
insert_after
insert
insert
insert
insert
insert
insert
insert
insert
insert
insert_or_assign
insert_or_assign
insert_or_assign
emplace
emplace
emplace
emplace_after
emplace
emplace
emplace
emplace
emplace
emplace
emplace
emplace
emplace
emplace_hint
emplace_hint
emplace_hint
emplace_hint
emplace_hint
emplace_hint
emplace_hint
emplace_hint
emplace_hint
try_emplace
try_emplace
try_emplace
erase
erase
erase
erase_after
erase
erase
erase
erase
erase
erase
erase
erase
erase
push_front
push_front
push_front
push_front
emplace_front
emplace_front
emplace_front
emplace_front
pop_front
pop_front
pop_front
pop_front
pop
pop
push_back
push_back
push_back
push_back
push
push
push
emplace_back
emplace_back
emplace_back
emplace_back
emplace
emplace
emplace
pop_back
pop_back
pop_back
pop_back
pop
swap
swap
swap
swap
swap
swap
swap
swap
swap
swap
swap
swap
swap
swap
swap
swap
swap
merge
merge
merge
merge
merge
merge
merge
merge
merge
merge
merge
extract
extract
extract
extract
extract
extract
extract
extract
extract
链表操作
splice
splice_after
splice
remove
remove
remove
remove_if
remove_if
remove_if
reverse
reverse
reverse
unique
unique
unique
sort
sort
sort
查找
count
count
count
count
count
count
count
count
count
find
find
find
find
find
find
find
find
find
contains
contains
contains
contains
contains
contains
contains
contains
contains
lower_bound
lower_bound
lower_bound
lower_bound
lower_bound
upper_bound
upper_bound
upper_bound
upper_bound
upper_bound
equal_range
equal_range
equal_range
equal_range
equal_range
equal_range
equal_range
equal_range
equal_range
观察器
key_comp
key_comp
key_comp
key_comp
key_comp
value_comp
value_comp
value_comp
value_comp
value_comp
hash_function
hash_function
hash_function
hash_function
hash_function
key_eq
key_eq
key_eq
key_eq
key_eq
分配器
get_allocator
get_allocator
get_allocator
get_allocator
get_allocator
get_allocator
get_allocator
get_allocator
get_allocator
get_allocator
get_allocator
get_allocator
get_allocator
容器
array
vector
deque
forward_list
list
set
multiset
map
multimap
unordered_set
unordered_multiset
unordered_map
unordered_multimap
stack
queue
priority_queue
顺序容器 | 关联容器 | 无序关联容器 | 容器适配器


std::array

< cpp‎ | container
定义于头文件 <array> |
template< class T, std::size_t N > struct array; | (C++11 起)

std::array 是封装固定大小数组的容器。

此容器是一个聚合类型，其语义等同于保有一个 C 风格数组 T[N] 作为其唯一非静态数据成员的结构体。不同于 C 风格数组，它不会自动退化成 T* 。它能作为聚合类型聚合初始化，只要有至多 N 个能转换成 T 的初始化器： std::array<int, 3> a = {1,2,3}; 。

该结构体结合了 C 风格数组的性能、可访问性与容器的优点，比如可获取大小、支持赋值、随机访问迭代器等。

std::array 满足容器 (Container) 和可逆容器 (ReversibleContainer) 的要求，除了默认构造的 array 是非空的，以及进行交换的复杂度是线性，它满足连续容器 (ContiguousContainer) (C++17 起)的要求并部分满足序列容器 (SequenceContainer) 的要求。

当其长度为零时 array （ N == 0 ）有特殊情况。此时， array.begin() == array.end() ，并拥有某个唯一值。在零长 array 上调用 front() 或 back() 是未定义的。

亦可将 array 当做拥有 N 个同类型元素的元组。

迭代器非法化

按照规则，指向 array 的迭代器在 array 的生存期间决不非法化。然而要注意，在 swap 时，迭代器将继续指向同一 array 的元素，并将改变元素的值。

成员类型

成员类型 | 定义
value_type | T
size_type | std::size_t
difference_type | std::ptrdiff_t
reference | value_type&
const_reference | const value_type&
pointer | value_type*
const_pointer | const value_type*
iterator
指向 value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 及老式连续迭代器 (LegacyContiguousIterator) |
指向 value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 及老式连续迭代器 (LegacyContiguousIterator) 且为字面类型 (LiteralType) | (C++20 前)
指向 value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 、contiguous_iterator 及常量表达式迭代器 (ConstexprIterator) | (C++20 起)
const_iterator
指向 const value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 及老式连续迭代器 (LegacyContiguousIterator) |
指向 const value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 及老式连续迭代器 (LegacyContiguousIterator) 且为字面类型 (LiteralType) | (C++20 前)
指向 const value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 、contiguous_iterator 及常量表达式迭代器 (ConstexprIterator) | (C++20 起)
reverse_iterator | std::reverse_iterator <iterator>
const_reverse_iterator | std::reverse_iterator <const_iterator>

成员函数

隐式定义的成员函数
(构造函数)
(隐式声明)
 遵循聚合初始化的规则初始化 array （注意默认初始化可以导致非类的 T 的不确定值）
(公开成员函数)
(析构函数)
(隐式声明)
 销毁 array 的每个元素
(公开成员函数)
operator=
(隐式声明)
 以来自另一 array 的每个元素重写 array 的对应元素
(公开成员函数)
元素访问
at
(C++11)
 访问指定的元素，同时进行越界检查
(公开成员函数)
operator[]
(C++11)
 访问指定的元素
(公开成员函数)
front
(C++11)
 访问第一个元素
(公开成员函数)
back
(C++11)
 访问最后一个元素
(公开成员函数)
data
(C++11)
 直接访问底层数组
(公开成员函数)
迭代器
begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)
rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)
rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)
容量
empty
(C++11)
 检查容器是否为空
(公开成员函数)
size
(C++11)
 返回容纳的元素数
(公开成员函数)
max_size
(C++11)
 返回可容纳的最大元素数
(公开成员函数)
操作
fill
(C++11)
 以指定值填充容器
(公开成员函数)
swap
(C++11)
 交换内容
(公开成员函数)

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 按照字典顺序比较 array 中的值 (函数模板)
std::get(std::array) | 访问 array 的一个元素 (函数模板)
std::swap(std::array) (C++11) | 特化 std::swap 算法 (函数模板)
to_array (C++20) | 从内建数组创建 std::array 对象 (函数模板)

辅助类

std::tuple_size<std::array> (C++11) | 获得 array 的大小 (类模板特化)
std::tuple_element<std::array> (C++11) | 获得 array 元素的类型 (类模板特化)

推导指引 (C++17 起)

示例

#include <string>
#include <iterator>
#include <iostream>
#include <algorithm>
#include <array>

int main()
{
    // 用聚合初始化构造
    std::array<int, 3> a1{ {1, 2, 3} }; // CWG 1270 重申前的 C++11 中要求双花括号
                                        // （ C++11 之后的版本和 C++14 起不要求）
    std::array<int, 3> a2 = {1, 2, 3};  // = 后决不要求双花括号
    std::array<std::string, 2> a3 = { std::string("a"), "b" };

    // 支持容器操作
    std::sort(a1.begin(), a1.end());
    std::reverse_copy(a2.begin(), a2.end(),
                      std::ostream_iterator<int>(std::cout, " "));

    std::cout << '\n';

    // 支持带范围 for 循环
    for(const auto& s: a3)
        std::cout << s << ' ';
}

输出：

3 2 1
a b

参阅

make_array
 创建 std::array 对象，从参数推导出其大小和可选的元素类型
(函数模板)


std::array<T,N>::at

< cpp‎ | container‎ | array

reference at( size_type pos ); | (C++17 前)
constexpr reference at( size_type pos ); | (C++17 起)
const_reference at( size_type pos ) const; | (C++14 前)
constexpr const_reference at( size_type pos ) const; | (C++14 起)

返回位于指定位置 pos 的元素的引用，有边界检查。

若 pos 不在容器范围内，则抛出 std::out_of_range 类型的异常。

参数

pos - 要返回的元素的位置

返回值

到所需元素的引用。

异常

若 !(pos < size()) 则抛出 std::out_of_range

复杂度

常数。

示例

#include <iostream>
#include <array>

int main()
{
    std::array<int,6> data = { 1, 2, 4, 5, 5, 6 };

    // Set element 1
    data.at(1) = 88;

    // Read element 2
    std::cout << "Element at index 2 has value " << data.at(2) << '\n';

    std::cout << "data size = " << data.size() << '\n';

    try {
        // Set element 6
        data.at(6) = 666;
    } catch (std::out_of_range const& exc) {
        std::cout << exc.what() << '\n';
    }

    // Print final values
    std::cout << "data:";
    for (int elem : data)
        std::cout << " " << elem;
    std::cout << '\n';
}

可能的输出：

Element at index 2 has value 4
data size = 6
array::at: __n (which is 6) >= _Nm (which is 6)
data: 1 88 4 5 5 6

参阅

operator[]
(C++11)
 访问指定的元素
(公开成员函数)


std::array<T,N>::back

< cpp‎ | container‎ | array

reference back(); | (C++17 前)
constexpr reference back(); | (C++17 起)
const_reference back() const; | (C++14 前)
constexpr const_reference back() const; | (C++14 起)

返回到容器中最后一个元素的引用。

在空容器上调用 back 导致未定义行为。

参数

（无）

返回值

到最后元素的引用。

复杂度

常数。

注解

对于非空容器 c ，表达式 c.back() 等价于 * std::prev (c.end()) 。

示例

下列代码用 back 显示 std::array <char> 的最后一个元素：

#include <array>
#include <iostream>

int main()
{
    std::array<char, 6> letters {'o', 'm', 'g', 'w', 't', 'f'};
    if (!letters.empty()) {
        std::cout << "The last character is: " << letters.back() << '\n';
    }
}

输出：

The last character is f

参阅

front
(C++11)
 访问第一个元素
(公开成员函数)


std::array<T,N>::begin, std::array<T,N>::cbegin

< cpp‎ | container‎ | array

iterator begin() noexcept; | (C++17 前)
constexpr iterator begin() noexcept; | (C++17 起)
const_iterator begin() const noexcept; | (C++17 前)
constexpr const_iterator begin() const noexcept; | (C++17 起)
const_iterator cbegin() const noexcept; | (C++17 前)
constexpr const_iterator cbegin() const noexcept; | (C++17 起)

返回指向 array 首元素的迭代器。

若 array 为空，则返回的迭代器将等于 end() 。

参数

（无）

返回值

指向首元素的迭代器。

复杂度

常数。

示例

#include <array>
#include <iostream>
#include <algorithm>
#include <iomanip>

int main()
{
    std::cout << std::boolalpha;

    std::array<int, 0> empty;
    std::cout << "1) "
              << (empty.begin() == empty.end()) << ' '     // true
              << (empty.cbegin() == empty.cend()) << '\n'; // true
    // *(empty.begin()) = 42; // => 运行时的未定义行为

    std::array<int, 4> numbers{5, 2, 3, 4};
    std::cout << "2) "
              << (numbers.begin() == numbers.end()) << ' '    // false
              << (numbers.cbegin() == numbers.cend()) << '\n' // false
              << "3) "
              << *(numbers.begin()) << ' '    // 5
              << *(numbers.cbegin()) << '\n'; // 5

    *numbers.begin() = 1;
    std::cout << "4) " << *(numbers.begin()) << '\n'; // 1
    // *(numbers.cbegin()) = 42; // 编译时错误：
                                 // 只读变量不可赋值

    // 打印所有元素
    std::cout << "5) ";
    std::for_each(numbers.cbegin(), numbers.cend(), [](int x) {
       std::cout << x << ' ';
    });
    std::cout << '\n';

    constexpr std::array constants{'A', 'B', 'C'};
    static_assert(constants.begin() != constants.end());   // OK
    static_assert(constants.cbegin() != constants.cend()); // OK
    static_assert(*constants.begin() == 'A');              // OK
    static_assert(*constants.cbegin() == 'A');             // OK
    // *constants.begin() = 'Z'; // 编译时错误：
                                 // 只读变量不可赋值
}

输出：

1) true true
2) false false
3) 5 5
4) 1
5) 1 2 3 4

参阅

end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)


std::array<T,N>::data

< cpp‎ | container‎ | array

T* data() noexcept; | (C++11 起) (C++17 前)
constexpr T* data() noexcept; | (C++17 起)
const T* data() const noexcept; | (C++11 起) (C++17 前)
constexpr const T* data() noexcept; | (C++17 起)

返回指向作为元素存储工作的底层数组的指针。指针满足范围 [data(); data() + size()) 始终是合法范围，即使容器为空（该情况下 data() 不可解引用）。

参数

（无）

返回值

指向底层元素存储的指针。对于非空容器，返回的指针与首元素地址比较相等。

复杂度

常数。

注解

若 size() 为 0 ，则 data() 可能或可能不返回空指针。

参阅

front (C++11) | 访问第一个元素 (公开成员函数)
back (C++11) | 访问最后一个元素 (公开成员函数)
size (C++11) | 返回容纳的元素数 (公开成员函数)


std::array 的推导指引

< cpp‎ | container‎ | array
定义于头文件 <array> |
template <class T, class... U> array(T, U...) -> array<T, 1 + sizeof...(U)>; | (C++17 起)

为 std::array 提供一个推导指引，以提供 std::experimental::make_array 对于从变长参数包构造 std::array 的等价物。

若 ( std::is_same_v <T, U> && ...) 非 true 则程序为谬构。注意它在 sizeof...(U) 为零时为 true 。

示例

#include <array>
int main()
{
    int const x = 10;
    std::array a{1, 2, 3, 5, x}; // OK 创建 std::array<int, 5>

//  std::array b{1, 2u}; // 错误，所有参数必须拥有相同类型
}


std::array<T,N>::empty

< cpp‎ | container‎ | array

constexpr bool empty() const noexcept; | (C++11 起) (C++20 前)
[[nodiscard]] constexpr bool empty() const noexcept; | (C++20 起)

检查容器是否无元素，即是否 begin() == end() 。

参数

（无）

返回值

若容器为空则为 true ，否则为 false

复杂度

常数。

示例

下列代码用 empty 检查 std::array 是否含有任何元素：

#include <array>
#include <iostream>

int main()
{
    std::array<int, 4> numbers {3, 1, 4, 1};
    std::array<int, 0> no_numbers;

    std::cout << std::boolalpha;
    std::cout << "numbers.empty(): " << numbers.empty() << '\n';
    std::cout << "no_numbers.empty(): " << no_numbers.empty() << '\n';
}

输出：

numbers.empty(): false
no_numbers.empty(): true

参阅

size
(C++11)
 返回容纳的元素数
(公开成员函数)


std::array<T,N>::end, std::array<T,N>::cend

< cpp‎ | container‎ | array

iterator end() noexcept; | (C++17 前)
constexpr iterator end() noexcept; | (C++17 起)
const_iterator end() const noexcept; | (C++17 前)
constexpr const_iterator end() const noexcept; | (C++17 起)
const_iterator cend() const noexcept; | (C++17 前)
constexpr const_iterator cend() const noexcept; | (C++17 起)

返回指向 array 末元素后一元素的迭代器。

此元素表现为占位符；试图访问它导致未定义行为。

参数

（无）

返回值

指向后随最后元素的迭代器。

复杂度

常数。

示例

#include <array>
#include <iostream>
#include <algorithm>
#include <iomanip>

int main()
{
    std::cout << std::boolalpha;

    std::array<int, 0> empty;
    std::cout << "1) "
              << (empty.begin() == empty.end()) << ' '     // true
              << (empty.cbegin() == empty.cend()) << '\n'; // true
    // *(empty.begin()) = 42; // => 运行时的未定义行为

    std::array<int, 4> numbers{5, 2, 3, 4};
    std::cout << "2) "
              << (numbers.begin() == numbers.end()) << ' '    // false
              << (numbers.cbegin() == numbers.cend()) << '\n' // false
              << "3) "
              << *(numbers.begin()) << ' '    // 5
              << *(numbers.cbegin()) << '\n'; // 5

    *numbers.begin() = 1;
    std::cout << "4) " << *(numbers.begin()) << '\n'; // 1
    // *(numbers.cbegin()) = 42; // 编译时错误：
                                 // 只读变量不可赋值

    // 打印所有元素
    std::cout << "5) ";
    std::for_each(numbers.cbegin(), numbers.cend(), [](int x) {
       std::cout << x << ' ';
    });
    std::cout << '\n';

    constexpr std::array constants{'A', 'B', 'C'};
    static_assert(constants.begin() != constants.end());   // OK
    static_assert(constants.cbegin() != constants.cend()); // OK
    static_assert(*constants.begin() == 'A');              // OK
    static_assert(*constants.cbegin() == 'A');             // OK
    // *constants.begin() = 'Z'; // 编译时错误：
                                 // 只读变量不可赋值
}

输出：

1) true true
2) false false
3) 5 5
4) 1
5) 1 2 3 4

参阅

begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)


std::array<T,N>::fill

< cpp‎ | container‎ | array
void fill( const T& value ); | (C++11 起) (C++20 前)
constexpr void fill( const T& value ); | (C++20 起)

将定值 value 赋给容器中的所有元素。

参数

value - 要赋给元素的值

返回值

（无）

复杂度

与容器大小成线性。

示例

#include <array>
#include <iostream>
#include <algorithm>

int main()
{
    constexpr int xy = 4;

    using Cell = std::array<unsigned char, 8>;

    std::array<Cell, xy * xy> board;

    board.fill({ {0xE2, 0x96, 0x84, 0xE2, 0x96, 0x80, 0, 0} }); // "▄▀";

    std::for_each(board.cbegin(), board.cend(), [xy, O=1](const auto& c) mutable
    {
        std::cout << c.data() << ((O++ % xy) ? "" : "\n");
    });
}

输出：

▄▀▄▀▄▀▄▀
▄▀▄▀▄▀▄▀
▄▀▄▀▄▀▄▀
▄▀▄▀▄▀▄▀

参阅

fill | 将一个给定值复制赋值给一个范围内的每个元素 (函数模板)
fill_n | 将一个给定值复制赋值给一个范围内的 N 个元素 (函数模板)


std::array<T,N>::front

< cpp‎ | container‎ | array

reference front(); | (C++17 前)
constexpr reference front(); | (C++17 起)
const_reference front() const; | (C++14 前)
constexpr const_reference front() const; | (C++14 起)

返回到容器首元素的引用。

在空容器上对 front 的调用是未定义的。

参数

（无）

返回值

到首元素的引用

复杂度

常数

注解

对于容器 c ，表达式 c.front() 等价于 *c.begin() 。

示例

下列代码用 front 显示 std::array <char, 6> 的首元素：

#include <array>
#include <iostream>

int main()
{
    std::array<char, 6> letters {'o', 'm', 'g', 'w', 't', 'f'};

    if (!letters.empty()) {
        std::cout << "The first character is: " << letters.front() << '\n';
    }
}

输出：

The first character is o

参阅

back
(C++11)
 访问最后一个元素
(公开成员函数)


std::get(std::array)

< cpp‎ | container‎ | array
定义于头文件 <array>
(1)
template< std::size_t I, class T, std::size_t N >
T& get( std::array <T,N>& a ) noexcept;
 (C++11 起)
(C++14 前)
template< std::size_t I, class T, std::size_t N >
constexpr T& get( std::array <T,N>& a ) noexcept;
 (C++14 起)
(2)
template< std::size_t I, class T, std::size_t N >
T&& get( std::array <T,N>&& a ) noexcept;
 (C++11 起)
(C++14 前)
template< std::size_t I, class T, std::size_t N >
constexpr T&& get( std::array <T,N>&& a ) noexcept;
 (C++14 起)
(3)
template< std::size_t I, class T, std::size_t N >
const T& get( const std::array <T,N>& a ) noexcept;
 (C++11 起)
(C++14 前)
template< std::size_t I, class T, std::size_t N >
constexpr const T& get( const std::array <T,N>& a ) noexcept;
 (C++14 起)
(4)
template< std::size_t I, class T, std::size_t N >
const T&& get( const std::array <T,N>&& a ) noexcept;
 (C++11 起)
(C++14 前)
template< std::size_t I, class T, std::size_t N >
constexpr const T&& get( const std::array <T,N>&& a ) noexcept;
 (C++14 起)

从 array 提取第 I 个元素。

I 必须是范围 [0, N) 中的整数值。与 at() 或 operator[] 相反，这在编译时强制。

参数

a - 要提取其内容的数组

返回值

到 a 的第 I 元素的引用。

时间复杂度

常数。

示例

#include <iostream>
#include <array>

int main()
{
    std::array<int, 3> arr;

    // 设置值：
    std::get<0>(arr) = 1;
    std::get<1>(arr) = 2;
    std::get<2>(arr) = 3;

    // 获取值：
    std::cout << "(" << std::get<0>(arr) << ", " << std::get<1>(arr)
              << ", " << std::get<2>(arr) << ")\n";
}

输出：

(1, 2, 3)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2485 | C++11 | 无对于 const array&& 的重载 | 添加重载

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
operator[] (C++11) | 访问指定的元素 (公开成员函数)
at (C++11) | 访问指定的元素，同时进行越界检查 (公开成员函数)
std::get(std::tuple) | 元组式访问指定的元素 (函数模板)
std::get(std::pair) (C++11) | 访问 pair 的一个元素 (函数模板)
std::get(std::variant) (C++17) | 以给定索引或类型（若类型唯一）读取 variant 的值，错误时抛出异常 (函数模板)


std::array<T,N>::max_size

< cpp‎ | container‎ | array

constexpr size_type max_size() const noexcept; | (C++11 起)

返回根据系统或库实现限制的容器可保有的元素最大数量，即对于最大容器的 std::distance (begin(), end()) 。

参数

（无）

返回值

元素数量的最大值。

复杂度

常数。

注解

因为每个 std::array<T, N> 都是固定大小容器，故 max_size 返回的值等于 N （亦为 size 所返回的值）

示例

#include <iostream>
#include <array>

int main()
{
    std::array<char, 10> s;
    std::cout << "Maximum size of a 'array' is " << s.max_size() << "\n";
}

可能的输出：

Maximum size of a 'array' is 10

参阅

size
(C++11)
 返回容纳的元素数
(公开成员函数)


std::array<T,N>::operator[]

< cpp‎ | container‎ | array

reference operator[]( size_type pos ); | (C++17 前)
constexpr reference operator[]( size_type pos ); | (C++17 起)
const_reference operator[]( size_type pos ) const; | (C++14 前)
constexpr const_reference operator[]( size_type pos ) const; | (C++14 起)

返回位于指定位置 pos 的元素的引用。不进行边界检查。

参数

pos - 要返回的元素的位置

返回值

到所需元素的引用。

复杂度

常数。

注解

不同于 std::map::operator[] ，此运算符决不插入新元素到容器。通过此运算符访问不存在的元素是未定义行为。

示例

下列代码使用 operator[] 读取并写入 std::array <int> ：

#include <array>
#include <iostream>

int main()
{
    std::array<int,4> numbers {2, 4, 6, 8};

    std::cout << "Second element: " << numbers[1] << '\n';

    numbers[0] = 5;

    std::cout << "All numbers:";
    for (auto i : numbers) {
        std::cout << ' ' << i;
    }
    std::cout << '\n';
}

输出：

Second element: 4
All numbers: 5 4 6 8

参阅

at
(C++11)
 访问指定的元素，同时进行越界检查
(公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::array)

< cpp‎ | container‎ | array

定义于头文件 <array>
(1)
template< class T, std::size_t N >

bool operator==( const std::array <T,N>& lhs,

const std::array <T,N>& rhs );
 (C++20 前)
template< class T, std::size_t N >

constexpr bool operator==( const std::array <T,N>& lhs,

const std::array <T,N>& rhs );
 (C++20 起)
template< class T, std::size_t N >

bool operator!=( const std::array <T,N>& lhs,

const std::array <T,N>& rhs );
 (2) (C++20 前)
template< class T, std::size_t N >

bool operator<( const std::array <T,N>& lhs,

const std::array <T,N>& rhs );
 (3) (C++20 前)
template< class T, std::size_t N >

bool operator<=( const std::array <T,N>& lhs,

const std::array <T,N>& rhs );
 (4) (C++20 前)
template< class T, std::size_t N >

bool operator>( const std::array <T,N>& lhs,

const std::array <T,N>& rhs );
 (5) (C++20 前)
template< class T, std::size_t N >

bool operator>=( const std::array <T,N>& lhs,

const std::array <T,N>& rhs );
 (6) (C++20 前)
template< class T, std::size_t N >

constexpr /* see below */ operator<=>( const std::array <T,N>& lhs,

const std::array <T,N>& rhs );
 (7) (C++20 起)

比较二个 array 的内容。

1-2) 检查 lhs 与 rhs 的内容是否相等，即它们是否拥有相同数量的元素且 lhs 中每个元素与 rhs 的同位置元素比较相等。
3-6) 按字典序比较 lhs 与 rhs 的内容。由等价于 std::lexicographical_compare 的函数进行比较。
7) 按字典序比较 lhs 与 rhs 的内容。如同通过在二个 array 上以进行合成三路比较（见后述）的函数对象调用 std::lexicographical_compare_three_way 进行比较。返回类型同合成三路比较的结果类型。

给定分别作为左操作数与右操作数的两个 const E 左值 lhs 与 rhs （其中 E 为 T ），合成三路比较定义如下：

  • 若 std::three_way_comparable_with<E, E> 得到满足则等价于 lhs <=> rhs ；
  • 否则，若以 operator< 比较二个 const E 左值为良构且结果类型满足 boolean-testable ，则等价于
lhs < rhs ? std::weak_ordering::less :
rhs < lhs ? std::weak_ordering::greater :
            std::weak_ordering::equivalent
  • 否则，不定义合成三路比较，而 operator<=> 不参与重载决议。
若 three_way_comparable_with 或 boolean-testable 被满足但未被实现，或使用 operator< 但 E 与 < 不建立全序，则 operator<=> 的行为未定义。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较内容的 array
-
为使用重载 (1-2) ， T 必须满足可相等比较 (EqualityComparable) 的要求。
-
为使用重载 (3-6) ， T 必须满足可小于比较 (LessThanComparable) 的要求。顺序关系必须建立全序。

返回值

1) 若 array 内容相等则为 true ，否则为 false
2) 若 array 内容不相等则为 true ，否则为 false
3) 若 lhs 的内容按字典序小于 rhs 的内容则为 true ，否则为 false
4) 若 lhs 的内容按字典序小于或等于 rhs 的内容则为 true ，否则为 false
5) 若 lhs 的内容按字典序大于 rhs 的内容则为 true ，否则为 false
6) 若 lhs 的内容按字典序大于或等于 rhs 的内容则为 true ，否则为 false
7) lhs 与 rhs 中的首对不等价元素的相对顺序，若有这种元素；否则为 lhs.size() <=> rhs.size() 。

复杂度

与 array 大小成线性

示例

#include <iostream>
#include <array>

int main()
{
    std::array<int, 3> alice{1, 2, 3};
    std::array<int, 3> bob{7, 8, 9};
    std::array<int, 3> eve{1, 2, 3};

    std::cout << std::boolalpha;

    // 比较不相等的容器
    std::cout << "alice == bob returns " << (alice == bob) << '\n';
    std::cout << "alice != bob returns " << (alice != bob) << '\n';
    std::cout << "alice <  bob returns " << (alice < bob) << '\n';
    std::cout << "alice <= bob returns " << (alice <= bob) << '\n';
    std::cout << "alice >  bob returns " << (alice > bob) << '\n';
    std::cout << "alice >= bob returns " << (alice >= bob) << '\n';

    std::cout << '\n';

    // 比较相等的容器
    std::cout << "alice == eve returns " << (alice == eve) << '\n';
    std::cout << "alice != eve returns " << (alice != eve) << '\n';
    std::cout << "alice <  eve returns " << (alice < eve) << '\n';
    std::cout << "alice <= eve returns " << (alice <= eve) << '\n';
    std::cout << "alice >  eve returns " << (alice > eve) << '\n';
    std::cout << "alice >= eve returns " << (alice >= eve) << '\n';
}

输出：

alice == bob returns false
alice != bob returns true
alice <  bob returns true
alice <= bob returns true
alice >  bob returns false
alice >= bob returns false

alice == eve returns true
alice != eve returns false
alice <  eve returns false
alice <= eve returns true
alice >  eve returns false
alice >= eve returns true


std::array<T,N>::rbegin, std::array<T,N>::crbegin

< cpp‎ | container‎ | array

reverse_iterator rbegin() noexcept; | (C++17 前)
constexpr reverse_iterator rbegin() noexcept; | (C++17 起)
const_reverse_iterator rbegin() const noexcept; | (C++17 前)
constexpr const_reverse_iterator rbegin() const noexcept; | (C++17 起)
const_reverse_iterator crbegin() const noexcept; | (C++17 前)
constexpr const_reverse_iterator crbegin() const noexcept; | (C++17 起)

返回指向逆向 array 首元素的逆向迭代器。它对应非逆向 array 的末元素。若 array 为空，则返回的迭代器等于 rend() 。

参数

（无）

返回值

指向首元素的逆向迭代器。

复杂度

常数。

示例

#include <algorithm>
#include <iostream>
#include <string>
#include <string_view>
#include <array>

int main()
{
    constexpr std::array<std::string_view, 8> data = {"▁","▂","▃","▄","▅","▆","▇","█"};

    std::array<std::string, std::size(data)> arr;

    // 'data' 是只读 array 故我们只能用 const 版本的迭代器读取它
    // （注意 'cbegin' 前面的 'c' 代表 'const' ）；
    // 'arr' 是目标，故使用非 const 版本的迭代器 'begin' 。
    std::copy(data.cbegin(), data.cend(), arr.begin());
    //             ^              ^           ^

    auto print = [](const std::string_view s) { std::cout << s << ' '; };

    print("Print 'arr' in direct order using [cbegin, cend):\t");
    std::for_each(arr.cbegin(), arr.cend(), print);
    //                ^             ^
    print("\n\nPrint 'arr' in reverse order using [crbegin, crend):\t");
    std::for_each(arr.crbegin(), arr.crend(), print);
    //                ^^             ^^
    print("\n");
}

输出：

Print 'arr' in direct order using [cbegin, cend):        ▁ ▂ ▃ ▄ ▅ ▆ ▇ █

Print 'arr' in reverse order using [crbegin, crend):     █ ▇ ▆ ▅ ▄ ▃ ▂ ▁

参阅

rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)


std::array<T,N>::rend, std::array<T,N>::crend

< cpp‎ | container‎ | array

reverse_iterator rend() noexcept; | (C++17 前)
constexpr reverse_iterator rend() noexcept; | (C++17 起)
const_reverse_iterator rend() const noexcept; | (C++17 前)
constexpr const_reverse_iterator rend() const noexcept; | (C++17 起)
const_reverse_iterator crend() const noexcept; | (C++17 前)
constexpr const_reverse_iterator crend() const noexcept; | (C++17 起)

返回指向逆向 array 末元素后一元素的逆向迭代器。它对应非逆向 array 首元素的前一元素。此元素表现为占位符，试图访问它导致未定义行为。

参数

（无）

返回值

指向末元素后一元素的逆向迭代器。

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)


std::array<T,N>::size

< cpp‎ | container‎ | array

constexpr size_type size() const noexcept; | (C++11 起)

返回容器中的元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

容器中的元素数量。

复杂度

常数。

示例

下列代码用 size 显示 std::array 中的元素数：

#include <array>
#include <iostream>

int main()
{
    std::array<int, 4> nums {1, 3, 5, 7};

    std::cout << "nums contains " << nums.size() << " elements.\n";
}

输出：

nums contains 4 elements.

参阅

empty (C++11) | 检查容器是否为空 (公开成员函数)
max_size (C++11) | 返回可容纳的最大元素数 (公开成员函数)


std::array<T,N>::swap

< cpp‎ | container‎ | array
void swap( array& other ) noexcept(/* see below */); | (C++11 起) (C++20 前)
constexpr void swap( array& other ) noexcept(/* see below */); | (C++20 起)

将容器内容与 other 的内容交换。不导致迭代器和引用关联到别的容器。

参数

other - 要与之交换内容的 array

返回值

（无）

异常

noexcept 说明： noexcept(noexcept(swap( std::declval <T&>(), std::declval <T&>()))) 在以上表达式中，按照同 C++17 std::is_nothrow_swappable 特性所用的行为查找标识符 swap 。 | (C++17 前)
noexcept 说明： noexcept( std::is_nothrow_swappable_v <T>) | (C++17 起)
对于零长 array ，
noexcept 说明：
noexcept

复杂度

与容器大小成线性。

示例

#include <array>
#include <iostream>

template<class Os, class V> Os& operator<<(Os& os, const V& v) {
    os << "{";
    for (auto i : v) os << ' ' << i;
    return os << " } ";
}

int main()
{
    std::array<int, 3> a1{1, 2, 3}, a2{4, 5, 6};

    auto it1 = a1.begin();
    auto it2 = a2.begin();
    int& ref1 = a1[1];
    int& ref2 = a2[1];

    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';
    a1.swap(a2);
    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';

    // 注意交换后迭代器与引用保持与原 array 关联，
    // 例如 `it1` 仍指向元素 a1[0] ， `ref1` 仍指代 a1[1] 。
}

输出：

{ 1 2 3 } { 4 5 6 } 1 4 2 5
{ 4 5 6 } { 1 2 3 } 4 1 5 2

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2456 | C++11 | noexcept 规定曾为谬构 | 使之有效

参阅

std::swap(std::array)
(C++11)
 特化 std::swap 算法
(函数模板)


std::swap(std::array)

< cpp‎ | container‎ | array

定义于头文件 <array>
template< class T, std::size_t N >

void swap( std::array <T,N>& lhs,

std::array <T,N>& rhs );
 (C++11 起)
(C++17 前)
template< class T, std::size_t N >

void swap( std::array <T,N>& lhs,

std::array <T,N>& rhs ) noexcept(/* see below */);
 (C++17 起)
(C++20 前)
template< class T, std::size_t N >

constexpr void swap( std::array <T,N>& lhs,

std::array <T,N>& rhs ) noexcept(/* see below */);
 (C++20 起)

为 std::array 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

此重载仅若 N == 0 或 std::is_swappable_v <T> 为 true 才参与重载决议。

 (C++17 起)

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

与容器大小成线性。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

#include <algorithm>
#include <iostream>
#include <array>

int main()
{
    std::array<int, 3> alice{1, 2, 3};
    std::array<int, 3> bob{7, 8, 9};

    auto print = [](const int& n) { std::cout << " " << n; };

    // 打印交换前的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';

    std::cout << "-- SWAP\n";
    std::swap(alice,bob);

    // 打印交换后的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
}

输出：

alice: 1 2 3
bob  : 7 8 9
-- SWAP
alice: 7 8 9
bob  : 1 2 3

参阅

swap
(C++11)
 交换内容
(公开成员函数)


std::to_array

< cpp‎ | container‎ | array
定义于头文件 <array>
template<class T, std::size_t N>
constexpr std::array < std::remove_cv_t <T>, N> to_array(T (&a)[N]);
 (1) (C++20 起)
template<class T, std::size_t N>
constexpr std::array < std::remove_cv_t <T>, N> to_array(T (&&a)[N]);
 (2) (C++20 起)

从一维内建数组 a 创建 std::array 。从 a 的对应元素复制初始化 std::array 的元素。不支持复制或移动多维内建数组。

1) 对 0, ..., N - 1 中的每个 i ，以 a[i] 复制初始化结果的对应元素。若 std::is_constructible_v <T, T&> 为 false 则此重载为谬构。
2) 对 0, ..., N - 1 中的每个 i ，以 std::move(a[i]) 复制初始化结果的对应元素。若 std::is_move_constructible_v <T> 为 false 则此重载为谬构。

std::is_array_v <T> 为 true 时两个重载均为谬构。

参数

a - 要转换成 std::array 的内建数组
类型要求
-
为使用重载 (1) ， T 必须满足可复制构造 (CopyConstructible) 的要求。
-
为使用重载 (2) ， T 必须满足可移动构造 (MoveConstructible) 的要求。

返回值

1) std::array < std::remove_cv_t <T>, N>{ a[0], ..., a[N - 1] }
2) std::array < std::remove_cv_t <T>, N>{ std::move(a[0]), ..., std::move(a[N - 1]) }

注解

有一些不能使用 std::array 的类模板实参推导而 to_array 可用的情况：

  • to_array 能在手工指定 std::array 的元素类型并推导长度时指定，这在想要隐式转换时会更好。
  • to_array 能复制字符串字面量，而类模板实参推导构造单个指向其首字符的 std::array 。
std::to_array<long>({3, 4}); // OK ：隐式转换
// std::array<long>{3, 4};   // 错误：模板参数太少
std::to_array("foo");        // 创建 std::array<char, 4>{ 'f', 'o', 'o', '\0' }
std::array{"foo"};           // 创建 std::array<const char*, 1>{ +"foo" }

可能的实现

版本一
namespace detail {

template <class T, std::size_t N, std::size_t... I>
constexpr std::array<std::remove_cv_t<T>, N>
    to_array_impl(T (&a)[N], std::index_sequence<I...>)
{
    return { {a[I]...} };
}

}

template <class T, std::size_t N>
constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N])
{
    return detail::to_array_impl(a, std::make_index_sequence<N>{});
}
版本二
namespace detail {

template <class T, std::size_t N, std::size_t... I>
constexpr std::array<std::remove_cv_t<T>, N>
    to_array_impl(T (&&a)[N], std::index_sequence<I...>)
{
    return { {std::move(a[I])...} };
}

}

template <class T, std::size_t N>
constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&&a)[N])
{
    return detail::to_array_impl(std::move(a), std::make_index_sequence<N>{});
}

示例

#include <type_traits>
#include <utility>
#include <array>
#include <memory>

int main()
{
    // 复制字符串字面量
    auto a1 = std::to_array("foo");
    static_assert(a1.size() == 4);

    // 推导元素类型和长度
    auto a2 = std::to_array({ 0, 2, 1, 3 });
    static_assert(std::is_same_v<decltype(a2), std::array<int, 4>>);

    // 推导长度而元素类型指定
    // 发生隐式转换
    auto a3 = std::to_array<long>({ 0, 1, 3 });
    static_assert(std::is_same_v<decltype(a3), std::array<long, 3>>);

    auto a4 = std::to_array<std::pair<int, float>>(
        { { 3, .0f }, { 4, .1f }, { 4, .1e23f } });
    static_assert(a4.size() == 3);

    // 创建不可复制的 std::array
    auto a5 = std::to_array({ std::make_unique<int>(3) });
    static_assert(a5.size() == 1);

    // 错误：不支持复制多维数组
    // char s[2][6] = { "nice", "thing" };
    // auto a6 = std::to_array(s);
}

参阅

make_array
 创建 std::array 对象，从参数推导出其大小和可选的元素类型
(函数模板)


std::tuple_element<std::array>

< cpp‎ | container‎ | array
定义于头文件 <array>
template< std::size_t I, class T, std::size_t N >
struct tuple_element<I, std::array <T, N> >;
 (C++11 起)

使用类 tuple 接口，提供 array 元素类型的编译时带下标访问

成员类型

成员类型 | 定义
type | array 的元素类型

可能的实现

template<std::size_t I, class T>
  struct tuple_element;

template<std::size_t I, class T, std::size_t N>
  struct tuple_element<I, std::array<T,N> >
  {
     using type = T;
  };

示例

#include <array>
#include <iostream>
#include <tuple>
#include <type_traits>

int main()
{
   // 定义 array 并获取位于位置 0 的元素类型
   std::array<int, 10> data {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
   using T = std::tuple_element<0, decltype(data)>::type; // int

   std::cout << std::boolalpha;
   std::cout << std::is_same<T, int>::value << '\n';

   const auto const_data = data;
   using CT = std::tuple_element<0, decltype(const_data)>::type; // const int

   // tuple_element 的结果取决于仿 tuple 类型的 cv 限定
   std::cout << std::is_same<T, CT>::value << '\n';
   std::cout << std::is_same<CT, const int>::value << '\n';
}

输出：

true
false
true

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
std::tuple_element<std::tuple> (C++11) | 获得指定元素的类型 (类模板特化)
std::tuple_element<std::pair> (C++11) | 获得 pair 中元素的类型 (类模板特化)


std::tuple_size(std::array)

< cpp‎ | container‎ | array
定义于头文件 <array>
template< class T, std::size_t N >

struct tuple_size< std::array <T, N> > :
std::integral_constant < std::size_t, N>

{ };
 (C++11 起)

提供作为编译时常量表达式访问 std::array 中元素数量的方法。

继承自 std::integral_constant

成员常量

value
[静态]
 N ， array 中的元素数
(公开静态成员常量)

成员函数

operator std::size_t | 转换对象为 std::size_t ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | std::size_t
type | std::integral_constant < std::size_t, value>

示例

#include <iostream>
#include <array>

template<class T>
void test(T t)
{
    int a[std::tuple_size<T>::value]; // 能用于编译时
    std::cout << std::tuple_size<T>::value << '\n';
}

int main()
{
    std::array<float, 3> arr;
    test(arr);
}

输出：

3

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
std::tuple_size<std::tuple> (C++11) | 在编译时获得 tuple 的大小 (类模板特化)


std::deque

< cpp‎ | container
定义于头文件 <deque>
template<

class T,
class Allocator = std::allocator <T>

> class deque;
 (1)
namespace pmr {

template <class T>
using deque = std::deque<T, std::pmr::polymorphic_allocator <T>>;

}
 (2) (C++17 起)

std::deque （ double-ended queue ，双端队列）是有下标顺序容器，它允许在其首尾两端快速插入及删除。另外，在 deque 任一端插入或删除不会非法化指向其余元素的指针或引用。

与 std::vector 相反， deque 的元素不是相接存储的：典型实现用单独分配的固定大小数组的序列，外加额外的登记，这表示下标访问必须进行二次指针解引用，与之相比 vector 的下标访问只进行一次。

deque 的存储按需自动扩展及收缩。扩张 deque 比扩张 std::vector 更优，因为它不涉及到复制既存元素到新内存位置。另一方面， deque 典型地拥有较大的最小内存开销；只保有一个元素的 deque 必须分配其整个内部数组（例如 64 位 libstdc++ 上为对象大小 8 倍； 64 位 libc++ 上为对象大小 16 倍或 4096 字节的较大者）。

deque 上常见操作的复杂度（效率）如下：

  • 随机访问——常数 O(1)
  • 在结尾或起始插入或移除元素——常数 O(1)
  • 插入或移除元素——线性 O(n)

std::deque 满足容器 (Container) 、知分配器容器 (AllocatorAwareContainer) 、序列容器 (SequenceContainer) 和可逆容器 (ReversibleContainer) 的要求。

模板形参

T - 元素的类型。
T 必须满足可复制赋值 (CopyAssignable) 和可复制构造 (CopyConstructible) 的要求。 | (C++11 前)
加诸元素的要求依赖于容器上进行的实际操作。泛言之，要求元素类型是完整类型并满足可擦除 (Erasable) 的要求，但许多成员函数附带了更严格的要求。 | (C++11 起)
Allocator - 用于获取/释放内存及构造/析构内存中元素的分配器。类型必须满足分配器 (Allocator) 的要求。若 Allocator::value_type 与 T 不同则行为未定义 (C++20 前)程序非良构 (C++20 起)。

迭代器非法化

本节未完成

此节有仍少量不准确处，更多细节请查看涉及单独成员函数的页面

操作 | 被非法化
所有只读操作 | 决不
swap 、 std::swap | 尾后迭代器可能被非法化（实现定义）
shrink_to_fit 、 clear 、 insert 、 emplace 、 push_front 、 push_back 、 emplace_front 、 emplace_back | 始终
erase | 若在起始擦除——仅被擦除元素 若在末尾擦除——仅被擦除元素和尾后迭代器 否则——非法化所有迭代器（包含尾后迭代器）。
resize | 若新大小小于旧者：仅被擦除元素和尾后迭代器 若新大小大于旧者：非法化所有迭代器 否则——不非法化任何迭代器。
pop_front | 仅有指向被擦除元素者
pop_back | 仅有指向被擦除元素者和尾后迭代器

非法化注意

  • 从 deque 任一端插入时， insert 和 emplace 不会非法化引用。
  • push_front 、 push_back 、 emplace_front 和 emplace_back 不会非法化任何到 deque 元素的引用。
  • 从 deque 任一端擦除时， erase 、 pop_front 和 pop_back 不会非法化到未擦除元素的引用。
  • 以较小的大小调用 resize 不会非法化任何到未擦除元素的引用。
  • 以较大的大小调用 resize 不会非法化任何到 deque 元素的引用。

成员类型

成员类型 | 定义
value_type | T
allocator_type | Allocator
size_type | 无符号整数类型（通常是 std::size_t ）
difference_type | 有符号整数类型（通常是 std::ptrdiff_t ）
reference | value_type&
const_reference | const value_type&
pointer
Allocator::pointer | (C++11 前)
std::allocator_traits <Allocator>::pointer | (C++11 起)
const_pointer
Allocator::const_pointer | (C++11 前)
std::allocator_traits <Allocator>::const_pointer | (C++11 起)
iterator | 指向 value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator)
iterator | 指向 value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator)
reverse_iterator | std::reverse_iterator <iterator>
const_reverse_iterator | std::reverse_iterator <const_iterator>

成员函数

(构造函数)
 构造 deque
(公开成员函数)
(析构函数)
 析构 deque
(公开成员函数)
operator=
 赋值给容器
(公开成员函数)
assign
 将值赋给容器
(公开成员函数)
get_allocator
 返回相关的分配器
(公开成员函数)
元素访问
at
 访问指定的元素，同时进行越界检查
(公开成员函数)
operator[]
 访问指定的元素
(公开成员函数)
front
 访问第一个元素
(公开成员函数)
back
 访问最后一个元素
(公开成员函数)
迭代器
begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)
rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)
rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)
容量
empty
 检查容器是否为空
(公开成员函数)
size
 返回容纳的元素数
(公开成员函数)
max_size
 返回可容纳的最大元素数
(公开成员函数)
shrink_to_fit
(C++11)
 通过释放未使用的内存减少内存的使用
(公开成员函数)
修改器
clear
 清除内容
(公开成员函数)
insert
 插入元素
(公开成员函数)
emplace
(C++11)
 原位构造元素
(公开成员函数)
erase
 擦除元素
(公开成员函数)
push_back
 将元素添加到容器末尾
(公开成员函数)
emplace_back
(C++11)
 在容器末尾就地构造元素
(公开成员函数)
pop_back
 移除末元素
(公开成员函数)
push_front
 插入元素到容器起始
(公开成员函数)
emplace_front
(C++11)
 在容器头部原位构造元素
(公开成员函数)
pop_front
 移除首元素
(公开成员函数)
resize
 改变容器中可存储元素的个数
(公开成员函数)
swap
 交换内容
(公开成员函数)

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 按照字典顺序比较 deque 中的值 (函数模板)
std::swap(std::deque) | 特化 std::swap 算法 (函数模板)
erase(std::deque)erase_if(std::deque) (C++20) | 擦除所有满足特定判别标准的元素 (函数模板)

推导指引 (C++17 起)

示例

#include <iostream>
#include <deque>

int main()
{
    // 创建容纳整数的 deque
    std::deque<int> d = {7, 5, 16, 8};

    // 从 deque 的首尾添加整数
    d.push_front(13);
    d.push_back(25);

    // 迭代并打印 deque 的值
    for(int n : d) {
        std::cout << n << '\n';
    }
}

输出：

13
7
5
16
8
25


std::deque<T,Allocator>::assign

< cpp‎ | container‎ | deque

void assign( size_type count, const T& value ); | (1) |
template< class InputIt > void assign( InputIt first, InputIt last ); | (2) |
void assign( std::initializer_list <T> ilist ); | (3) | (C++11 起)

替换容器的内容。

1) 以 count 份 value 的副本替换内容。
2) 以范围 [first, last) 中元素的副本替换内容。若任一参数是指向 *this 中的迭代器则行为未定义。
若 InputIt 为整数类型，则此重载与 (1) 拥有相同效果。 | (C++11 前)
此重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 才参与重载决议。 | (C++11 起)
3) 以来自 initializer_list ilist 的元素替换内容。

所有指向容器元素的迭代器、指针及引用均被非法化。尾后迭代器亦被非法化。

参数

count | - | 容器的新大小
value | - | 用以初始化容器元素的值
first, last | - | 复制来源元素的范围
ilist | - | 复制值来源的 initializer_list

复杂度

1) 与 count 成线性
2) 与 first 和 last 间的距离成线性
3) 与 ilist.size() 成线性

示例

下列代码用 assign 添加数个字符到 std::deque <char> ：

#include <deque>
#include <iostream>

int main()
{
    std::deque<char> characters;

    characters.assign(5, 'a');

    for (char c : characters) {
        std::cout << c << ' ';
    }

    characters.assign({'\n', 'C', '+', '+', '1', '1', '\n'});

    for (char c : characters) {
        std::cout << c;
    }
}

输出：

a a a a a
C++11

参阅

(构造函数)
 构造 deque
(公开成员函数)


std::deque<T,Allocator>::at

< cpp‎ | container‎ | deque

reference at( size_type pos );
const_reference at( size_type pos ) const;

返回位于指定位置 pos 的元素的引用，有边界检查。

若 pos 不在容器范围内，则抛出 std::out_of_range 类型的异常。

参数

pos - 要返回的元素的位置

返回值

到所需元素的引用。

异常

若 !(pos < size()) 则抛出 std::out_of_range

复杂度

常数。

示例

#include <iostream>
#include <deque>

int main()
{
    std::deque<int> data = { 1, 2, 4, 5, 5, 6 };

    // Set element 1
    data.at(1) = 88;

    // Read element 2
    std::cout << "Element at index 2 has value " << data.at(2) << '\n';

    std::cout << "data size = " << data.size() << '\n';

    try {
        // Set element 6
        data.at(6) = 666;
    } catch (std::out_of_range const& exc) {
        std::cout << exc.what() << '\n';
    }

    // Print final values
    std::cout << "data:";
    for (int elem : data)
        std::cout << " " << elem;
    std::cout << '\n';
}

可能的输出：

Element at index 2 has value 4
data size = 6
deque::_M_range_check: __n (which is 6)>= this->size() (which is 6)
data: 1 88 4 5 5 6

参阅

operator[]
 访问指定的元素
(公开成员函数)


std::deque<T,Allocator>::back

< cpp‎ | container‎ | deque

reference back();
const_reference back() const;

返回到容器中最后一个元素的引用。

在空容器上调用 back 导致未定义行为。

参数

（无）

返回值

到最后元素的引用。

复杂度

常数。

注解

对于非空容器 c ，表达式 c.back() 等价于 * std::prev (c.end()) 。

示例

下列代码用 back 显示 std::deque <char> 的最后一个元素：

#include <deque>
#include <iostream>

int main()
{
    std::deque<char> letters {'o', 'm', 'g', 'w', 't', 'f'};
    if (!letters.empty()) {
        std::cout << "The last character is: " << letters.back() << '\n';
    }
}

输出：

The last character is f

参阅

front
 访问第一个元素
(公开成员函数)


std::deque<T,Allocator>::begin, std::deque<T,Allocator>::cbegin

< cpp‎ | container‎ | deque

iterator begin(); | (C++11 前)
iterator begin() noexcept; | (C++11 起)
const_iterator begin() const; | (C++11 前)
const_iterator begin() const noexcept; | (C++11 起)
const_iterator cbegin() const noexcept; | (C++11 起)

返回指向 deque 首元素的迭代器。

若 deque 为空，则返回的迭代器将等于 end() 。

参数

（无）

返回值

指向首元素的迭代器。

复杂度

常数。

示例

#include <iostream>
#include <numeric>
#include <deque>
#include <string>

int main()
{
        std::deque<int> nums {1, 2, 4, 8, 16};
        std::deque<std::string> fruits {"orange", "apple", "raspberry"};
        std::deque<char> empty;

        // 求和 deque nums 中的所有整数（若存在），仅打印结果。
        std::cout << "Sum of nums: " <<
                std::accumulate(nums.begin(), nums.end(), 0) << "\n";

        // 打印 deque fruits 中的首个 fruis ，不检查是否有一个。
        std::cout << "First fruit: " << *fruits.begin() << "\n";

        if (empty.begin() == empty.end())
                std::cout << "deque 'empty' is indeed empty.\n";
}

输出：

Sum of nums: 31
First fruit: orange
deque 'empty' is indeed empty.

参阅

end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)


std::deque<T,Allocator>::clear

< cpp‎ | container‎ | deque

void clear(); | (C++11 前)
void clear() noexcept; | (C++11 起)

从容器擦除所有元素。此调用后 size() 返回零。

非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器亦被非法化。

参数

（无）

返回值

（无）

复杂度

与容器大小，即元素数成线性。

示例

#include <algorithm>
#include <iostream>
#include <deque>

int main()
{
    std::deque<int> container{1, 2, 3};

    auto print = [](const int& n) { std::cout << " " << n; };

    std::cout << "Before clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';

    std::cout << "Clear\n";
    container.clear();

    std::cout << "After clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';
}

输出：

Before clear: 1 2 3
Size=3
Clear
After clear:
Size=0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2231 | C++11 | C++11 中错误地省略了复杂度保证 | 重申复杂度为线性

参阅

erase
 擦除元素
(公开成员函数)


std::deque 的推导指引

< cpp‎ | container‎ | deque

定义于头文件 <deque>
template< class InputIt,

class Alloc = std::allocator <typename std::iterator_traits <InputIt>::value_type>>
deque(InputIt, InputIt, Alloc = Alloc())

-> deque<typename std::iterator_traits <InputIt>::value_type, Alloc>;
 (C++17 起)

为 deque 提供此推导指引，以允许从迭代器范围推导。此重载仅若InputIt 满足老式输入迭代器 (LegacyInputIterator) 且 Alloc 满足分配器 (Allocator) 才参与重载决议

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

示例

#include <deque>
#include <vector>
int main() {
   std::vector<int> v = {1, 2, 3, 4};

   // 使用显式推导指引推导 std::deque<int>
   std::deque x(v.begin(), v.end());

   // 推导 std::deque<std::vector<int>::iterator>
   // 列表初始化的重载决议第一阶段选择从 initializer_list 构造函数合成的候选
   // 不进行第二阶段且推导指引无效果
   std::deque y{v.begin(), v.end()};
}


std::deque<T,Allocator>::deque

< cpp‎ | container‎ | deque

deque();
 (1)
explicit deque( const Allocator& alloc );
 (2)
(3)
explicit deque( size_type count,

const T& value = T(),

const Allocator& alloc = Allocator());
 (C++11 前)
deque( size_type count,

const T& value,

const Allocator& alloc = Allocator());
 (C++11 起)
(4)
explicit deque( size_type count );
 (C++11 起)
(C++14 前)
explicit deque( size_type count, const Allocator& alloc = Allocator() );
 (C++14 起)
template< class InputIt >

deque( InputIt first, InputIt last,

const Allocator& alloc = Allocator() );
 (5)
deque( const deque& other );
 (6)
deque( const deque& other, const Allocator& alloc );
 (7) (C++11 起)
deque( deque&& other );
 (8) (C++11 起)
deque( deque&& other, const Allocator& alloc );
 (9) (C++11 起)
deque( std::initializer_list <T> init,
const Allocator& alloc = Allocator() );
 (10) (C++11 起)

从各种数据源构造新容器，可选地使用用户提供的分配器 alloc 。

1) 默认构造函数。构造拥有默认构造的分配器的空容器。
2) 构造拥有给定分配器 alloc 的空容器。
3) 构造拥有 count 个有值 value 的元素的容器。
4) 构造拥有个 count 默认插入的 T 实例的容器。不进行复制。
5) 构造拥有范围 [first, last) 内容的容器。
若 InputIt 是整数类型，则此构造函数拥有的效果同 deque(static_cast<size_type>(first), static_cast<value_type>(last), a) 。 | (C++11 前)
此重载仅若InputIt 满足老式输入迭代器 (LegacyInputIterator) 才参与重载决议，以避免和重载 (2) 的歧义。 | (C++11 起)
6) 复制构造函数。构造拥有 other 内容的容器。

如同通过调用
std::allocator_traits <allocator_type>::select_on_container_copy_construction(
other.get_allocator())
获得分配器。

 (C++11 起)
7) 构造拥有 other 内容的容器，以 alloc 为分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
8) 移动构造函数。用移动语义构造拥有 other 内容的容器。分配器通过属于 other 的分配器移动构造获得。
9) 有分配器扩展的移动构造函数。以 alloc 为新容器的分配器，从 other 移动内容；若 alloc != other.get_allocator() ，则它导致逐元素移动。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
10) 构造拥有 initializer_list init 内容的容器。

参数

alloc | - | 用于此容器所有内存分配的分配器
count | - | 容器的大小
value | - | 以之初始化容器元素的值
first, last | - | 复制元素的来源范围
other | - | 用作初始化容器元素来源的另一容器
init | - | 用作初始化元素来源的 initializer_list

复杂度

1-2) 常数
3-4) 与 count 成线性
5) 与 first 和 last 的距离成线性
6-7) 与 other 的大小成线性
8) 常数。
9) 若 alloc != other.get_allocator() 则为线性，否则为常数。
10) 与 init 的大小成线性。

异常

调用 Allocator::allocate 可能抛出。

注解

在容器移动构造（重载 (8) ）后，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

#include <deque>
#include <string>
#include <iostream>

template<typename T>
std::ostream& operator<<(std::ostream& s, const std::deque<T>& v)
{
    s.put('[');
    char comma[3] = {'\0', ' ', '\0'};
    for (const auto& e : v) {
        s << comma << e;
        comma[0] = ',';
    }
    return s << ']';
}

int main()
{
    // C++11 初始化器列表语法：
    std::deque<std::string> words1 {"the", "frogurt", "is", "also", "cursed"};
    std::cout << "words1: " << words1 << '\n';

    // words2 == words1
    std::deque<std::string> words2(words1.begin(), words1.end());
    std::cout << "words2: " << words2 << '\n';

    // words3 == words1
    std::deque<std::string> words3(words1);
    std::cout << "words3: " << words3 << '\n';

    // words4 为 {"Mo", "Mo", "Mo", "Mo", "Mo"}
    std::deque<std::string> words4(5, "Mo");
    std::cout << "words4: " << words4 << '\n';
}

输出：

words1: [the, frogurt, is, also, cursed]
words2: [the, frogurt, is, also, cursed]
words3: [the, frogurt, is, also, cursed]
words4: [Mo, Mo, Mo, Mo, Mo]

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2193 | C++11 | 默认构造函数为 explicit | 使之为非 explicit

参阅

assign | 将值赋给容器 (公开成员函数)
operator= | 赋值给容器 (公开成员函数)


std::deque<T,Allocator>::emplace

< cpp‎ | container‎ | deque

template< class... Args > iterator emplace( const_iterator pos, Args&&... args ); | (C++11 起)

直接于 pos 前插入元素到容器中。

通过 std::allocator_traits::construct 构造元素，常用布置 new 在容器提供的位置原位构造元素。然而若要求的位置已被既存的元素占据，则首先在另一位置构造被插入的元素，然后再将他移动赋值到要求的位置中。

将参数 args... 作为 std::forward <Args>(args)... 转发给构造函数。 args... 可以直接或间接地指代容器中的值。

所有迭代器，含尾后迭代器，都被非法化。引用亦被非法化，除非 pos == begin() 或 pos == end() ，该情况下它们不被非法化。

参数

pos | - | 将构造新元素到其前的迭代器
args | - | 转发给元素构造函数的参数
类型要求
- T （容器元素类型） 必须满足可移动赋值 (MoveAssignable) 、 可移动插入 (MoveInsertable) 和 可就位构造 (EmplaceConstructible) 的要求。

返回值

指向被安置的元素的迭代器。

复杂度

与 pos 和容器两端距离的较小者成线性。

异常

若 value_type 的复制构造函数、移动构造函数、赋值运算符或移动赋值运算符以外的操作抛异常，或若在用 emplace 在任一端插入单个元素时抛异常，则无效果（强异常保证）。

否则，效果未指定。

示例

#include <iostream>
#include <string>
#include <deque>

struct A {
    std::string s;
    A(std::string str) : s(std::move(str))  { std::cout << " constructed\n"; }
    A(const A& o) : s(o.s) { std::cout << " copy constructed\n"; }
    A(A&& o) : s(std::move(o.s)) { std::cout << " move constructed\n"; }
    A& operator=(const A& other) {
        s = other.s;
        std::cout << " copy assigned\n";
        return *this;
    }
    A& operator=(A&& other) {
        s = std::move(other.s);
        std::cout << " move assigned\n";
        return *this;
    }
};

int main()
{
    std::deque<A> container;

    std::cout << "construct 2 times A:\n";
    A two { "two" };
    A three { "three" };

    std::cout << "emplace:\n";
    container.emplace(container.end(), "one");

    std::cout << "emplace with A&:\n";
    container.emplace(container.end(), two);

    std::cout << "emplace with A&&:\n";
    container.emplace(container.end(), std::move(three));

    std::cout << "content:\n";
    for (const auto& obj : container)
        std::cout << ' ' << obj.s;
    std::cout << '\n';
}

输出：

construct 2 times A:
 constructed
 constructed
emplace:
 constructed
emplace with A&:
 copy constructed
emplace with A&&:
 move constructed
content vec:
 one two three

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2164 | C++11 | 不清楚参数是否能指代容器 | 已澄清

参阅

insert
 插入元素
(公开成员函数)


std::deque<T,Allocator>::emplace_back

< cpp‎ | container‎ | deque

template< class... Args > void emplace_back( Args&&... args ); | (C++11 起) (C++17 前)
template< class... Args > reference emplace_back( Args&&... args ); | (C++17 起)

添加新元素到容器尾。元素通过 std::allocator_traits::construct 构造，它典型地用布置 new 于容器所提供的位置原位构造元素。参数 args... 以 std::forward <Args>(args)... 转发到构造函数。

所有迭代器，包含尾后迭代器，都被非法化。没有引用被非法化。

参数

args - 转发到元素构造函数的参数
类型要求
-
value_type 必须满足可就位构造 (EmplaceConstructible) 的要求。

返回值

（无） | (C++17 前)
到被插入元素的引用。 | (C++17 起)

复杂度

常数。

异常

若抛出异常，则此函数无效果（强异常保证）。

示例

下列代码用 emplace_back 后附 President 类型对象到 std::deque 。它演示 emplace_back 如何转发参数到 President 的构造函数，并展示如何用 emplace_back 避免用 push_back 时的额外复制或移动操作。

#include <deque>
#include <string>
#include <iostream>

struct President
{
    std::string name;
    std::string country;
    int year;

    President(std::string p_name, std::string p_country, int p_year)
        : name(std::move(p_name)), country(std::move(p_country)), year(p_year)
    {
        std::cout << "I am being constructed.\n";
    }
    President(President&& other)
        : name(std::move(other.name)), country(std::move(other.country)), year(other.year)
    {
        std::cout << "I am being moved.\n";
    }
    President& operator=(const President& other) = default;
};

int main()
{
    std::deque<President> elections;
    std::cout << "emplace_back:\n";
    elections.emplace_back("Nelson Mandela", "South Africa", 1994);

    std::deque<President> reElections;
    std::cout << "\npush_back:\n";
    reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));

    std::cout << "\nContents:\n";
    for (President const& president: elections) {
        std::cout << president.name << " was elected president of "
                  << president.country << " in " << president.year << ".\n";
    }
    for (President const& president: reElections) {
        std::cout << president.name << " was re-elected president of "
                  << president.country << " in " << president.year << ".\n";
    }
}

输出：

emplace_back:
I am being constructed.

push_back:
I am being constructed.
I am being moved.

Contents:
Nelson Mandela was elected president of South Africa in 1994.
Franklin Delano Roosevelt was re-elected president of the USA in 1936.

参阅

push_back
 将元素添加到容器末尾
(公开成员函数)


std::deque<T,Allocator>::emplace_front

< cpp‎ | container‎ | deque

template< class... Args > void emplace_front( Args&&... args ); | (C++11 起) (C++17 前)
template< class... Args > reference emplace_front( Args&&... args ); | (C++17 起)

插入新元素到容器起始。通过 std::allocator_traits::construct 构造元素，它典型地用布置 new 在容器所提供的位置原位构造元素。将参数 args... 作为 std::forward <Args>(args)... 转发给构造函数。

所有迭代器，包含尾后迭代器，都被非法化。没有引用被非法化。

参数

args - 转发给元素构造函数的参数
类型要求
-
T （容器元素类型） 必须满足可就位构造 (EmplaceConstructible) 的要求。

返回值

（无） | (C++17 前)
到被插入元素的引用。 | (C++17 起)

复杂度

常数。

异常

若抛异常，则此函数无效果（强异常保证）。

参阅

push_front
 插入元素到容器起始
(公开成员函数)


std::deque<T,Allocator>::empty

< cpp‎ | container‎ | deque

bool empty() const; | (C++11 前)
bool empty() const noexcept; | (C++11 起) (C++20 前)
[[nodiscard]] bool empty() const noexcept; | (C++20 起)

检查容器是否无元素，即是否 begin() == end() 。

参数

（无）

返回值

若容器为空则为 true ，否则为 false

复杂度

常数。

示例

下列代码用 empty 检查 std::deque <int> 是否含有任何元素：

#include <deque>
#include <iostream>

int main()
{
    std::deque<int> numbers;
    std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';

    numbers.push_back(42);
    numbers.push_back(13317);
    std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
}

输出：

Initially, numbers.empty(): 1
After adding elements, numbers.empty(): 0

参阅

size
 返回容纳的元素数
(公开成员函数)


std::deque<T,Allocator>::end, std::deque<T,Allocator>::cend

< cpp‎ | container‎ | deque

iterator end(); | (C++11 前)
iterator end() noexcept; | (C++11 起)
const_iterator end() const; | (C++11 前)
const_iterator end() const noexcept; | (C++11 起)
const_iterator cend() const noexcept; | (C++11 起)

返回指向 deque 末元素后一元素的迭代器。

此元素表现为占位符；试图访问它导致未定义行为。

参数

（无）

返回值

指向后随最后元素的迭代器。

复杂度

常数。

示例

#include <iostream>
#include <numeric>
#include <deque>
#include <string>

int main()
{
        std::deque<int> nums {1, 2, 4, 8, 16};
        std::deque<std::string> fruits {"orange", "apple", "raspberry"};
        std::deque<char> empty;

        // 求和 deque nums 中的所有整数（若存在），仅打印结果。
        std::cout << "Sum of nums: " <<
                std::accumulate(nums.begin(), nums.end(), 0) << "\n";

        // 打印 deque fruits 中的首个 fruis ，不检查是否有一个。
        std::cout << "First fruit: " << *fruits.begin() << "\n";

        if (empty.begin() == empty.end())
                std::cout << "deque 'empty' is indeed empty.\n";
}

输出：

Sum of nums: 31
First fruit: orange
deque 'empty' is indeed empty.

参阅

begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)


std::deque<T,Allocator>::erase

< cpp‎ | container‎ | deque

 | (1)
iterator erase( iterator pos ); |  | (C++11 前)
iterator erase( const_iterator pos ); |  | (C++11 起)
 | (2)
iterator erase( iterator first, iterator last ); |  | (C++11 前)
iterator erase( const_iterator first, const_iterator last ); |  | (C++11 起)

从容器擦除指定的元素。

1) 移除位于 pos 的元素。
2) 移除范围 [first; last) 中的元素。

所有迭代器和引用都被非法化，除非被擦除的元素在容器的首或尾，该情况下仅指向被擦除元素的迭代器或引用被非法化。

尾后迭代器是否被非法化是未指定的。 | (C++11 前)
尾后迭代器亦被非法化，除非被擦除元素在容器首，而尾元素未被擦除。 | (C++11 起)

迭代器 pos 必须合法且可解引用。从而不能以 end() 迭代器（合法，但不可解引用）为 pos 的值。

若 first==last 则迭代器 first 不必可解引用：擦除空范围是无操作。

参数

pos | - | 指向要移除的元素的迭代器
first, last | - | 要移除的元素范围
类型要求
- T 必须满足可移动赋值 (MoveAssignable) 的要求。

返回值

后随最后移除元素的迭代器。

若 pos 指代末元素，则返回 end() 迭代器。

若在移除前 last == end() ，则返回更新的 end() 迭代器。

若 [first, last) 为空范围，则返回 last 。

异常

不抛出，除非 T 的赋值运算符抛异常。

复杂度

线性：调用 T 析构函数的次数与被擦除的元素数相同，调用 T 赋值运算符的次数不多于被擦除元素前的元素数和被擦除元素后的元素数。

示例

#include <deque>
#include <iostream>

int main( )
{
    std::deque<int> c{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    for (auto &i : c) {
        std::cout << i << " ";
    }
    std::cout << '\n';

    c.erase(c.begin());

    for (auto &i : c) {
        std::cout << i << " ";
    }
    std::cout << '\n';

    c.erase(c.begin()+2, c.begin()+5);

    for (auto &i : c) {
        std::cout << i << " ";
    }
    std::cout << '\n';
}

输出：

0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 6 7 8 9

参阅

clear
 清除内容
(公开成员函数)


std::erase, std::erase_if (std::deque)

< cpp‎ | container‎ | deque

定义于头文件 <deque>
template< class T, class Alloc, class U >

typename std::deque <T,Alloc>::size_type

erase( std::deque <T,Alloc>& c, const U& value);
 (1) (C++20 起)
template< class T, class Alloc, class Pred >

typename std::deque <T,Alloc>::size_type

erase_if( std::deque <T,Alloc>& c, Pred pred);
 (2) (C++20 起)
1) 从容器中擦除所有比较等于 value 的元素。等价于
auto it = std::remove(c.begin(), c.end(), value);
auto r = std::distance(it, c.end());
c.erase(it, c.end());
return r;
2) 从容器中擦除所有满足 pred 的元素。等价于
auto it = std::remove_if(c.begin(), c.end(), pred);
auto r = std::distance(it, c.end());
c.erase(it, c.end());
return r;

参数

c | - | 要从中擦除的容器
value | - | 要擦除的值
pred | - | 若应该擦除元素则返回 ​true 的一元谓词。 对每个（可为 const 的） T 类型参数 v ，表达式 pred(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 T& 类型参数，亦不允许 T ，除非对 T 而言移动等价于复制 (C++11 起)。 ​

返回值

被擦除的元素数。

复杂度

线性。

示例

#include <iostream>
#include <numeric>
#include <deque>

void print_container(const std::deque<char>& c)
{
    for (auto x : c) {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    std::deque<char> cnt(10);
    std::iota(cnt.begin(), cnt.end(), '0');

    std::cout << "Init:\n";
    print_container(cnt);

    auto erased = std::erase(cnt, '3');
    std::cout << "Erase \'3\':\n";
    print_container(cnt);

    std::erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; });
    std::cout << "Erase all even numbers:\n";
    print_container(cnt);
    std::cout << "In all " << erased << " even numbers were erased.\n";
}

输出：

Init:
0 1 2 3 4 5 6 7 8 9
Erase '3':
0 1 2 4 5 6 7 8 9
Erase all even numbers:
1 5 7 9
In all 5 even numbers were erased.

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::deque<T,Allocator>::front

< cpp‎ | container‎ | deque

reference front();
const_reference front() const;

返回到容器首元素的引用。

在空容器上对 front 的调用是未定义的。

参数

（无）

返回值

到首元素的引用

复杂度

常数

注解

对于容器 c ，表达式 c.front() 等价于 *c.begin() 。

示例

下列代码用 front 显示 std::deque <char> 的首元素：

#include <deque>
#include <iostream>

int main()
{
    std::deque<char> letters {'o', 'm', 'g', 'w', 't', 'f'};

    if (!letters.empty()) {
        std::cout << "The first character is: " << letters.front() << '\n';
    }
}

输出：

The first character is o

参阅

back
 访问最后一个元素
(公开成员函数)


std::deque<T,Allocator>::get_allocator

< cpp‎ | container‎ | deque

allocator_type get_allocator() const; | (C++11 前)
allocator_type get_allocator() const noexcept; | (C++11 起)

返回与容器关联的分配器。

参数

（无）

返回值

关联的分配器。

复杂度

常数。


std::deque<T,Allocator>::insert

< cpp‎ | container‎ | deque

 | (1) |
iterator insert( iterator pos, const T& value ); |  |  | (C++11 前)
iterator insert( const_iterator pos, const T& value ); |  |  | (C++11 起)
iterator insert( const_iterator pos, T&& value ); | (2) | (C++11 起)
 | (3) |
void insert( iterator pos, size_type count, const T& value ); |  |  | (C++11 前)
iterator insert( const_iterator pos, size_type count, const T& value ); |  |  | (C++11 起)
 | (4) |
template< class InputIt > void insert( iterator pos, InputIt first, InputIt last); |  |  | (C++11 前)
template< class InputIt > iterator insert( const_iterator pos, InputIt first, InputIt last ); |  |  | (C++11 起)
iterator insert( const_iterator pos, std::initializer_list <T> ilist ); | (5) | (C++11 起)

插入元素到容器中的指定位置。

1-2) 在 pos 前插入 value 。
3) 在 pos 前插入 value 的 count 个副本。
4) 在 pos 前插入来自范围 [first, last) 的元素。
若 InputIt 为整数类型，则此重载与重载 (3) 拥有相同效果。 | (C++11 前)
此重载仅若 InputIt 足以为老式输入迭代器 (LegacyInputIterator) 才参与重载决议，以避免与重载 (3) 有歧义。 | (C++11 起)
若 first 和 last 是指向 *this 中的迭代器，则行为未定义。
5) 在 pos 前插入来自 initializer_list ilist 的元素。

所有迭代器，含尾后迭代器，都被非法化。引用亦被非法化，除非 pos == begin() 或 pos == end() ，该情况下它们不被非法化。

参数

pos | - | 将内容插入到其前的迭代器。 pos 可为 end() 迭代器
value | - | 要插入的元素值
first, last | - | 要插入的元素范围，不能是指向调用 insert 所用的容器中的迭代器
ilist | - | 要插入的值来源的 initializer_list
类型要求
- 为使用重载 (1) ， T 必须满足可复制赋值 (CopyAssignable) 和 可复制插入 (CopyInsertable) 的要求。
- 为使用重载 (2) ， T 必须满足可移动赋值 (MoveAssignable) 和 可移动插入 (MoveInsertable) 的要求。
- 为使用重载 (3) ， T 必须满足可复制赋值 (CopyAssignable) 和 可复制插入 (CopyInsertable) 的要求。
- 为使用重载 (4,5) ， T 必须满足可就位构造 (EmplaceConstructible) 的要求。
- 为使用重载 (4,5) ， T 必须满足可交换 (Swappable) 、 可移动赋值 (MoveAssignable) 、 可移动构造 (MoveConstructible) 和 可移动插入 (MoveInsertable) 的要求。(C++17 起)

返回值

1-2) 指向被插入 value 的迭代器。
3) 指向首个被插入元素的迭代器，或若 count==0 则为 pos 。
4) 指向首个被插入元素的迭代器，或若 first==last 则为 pos 。
5) 指向首个被插入元素的迭代器，或若 ilist 为空则为 pos 。

复杂度

1-2) 常数，加上与 pos 和容器两端距离的较小者成线性。
3) 与 count 成线性，加上与 pos 和容器两端距离的较小者成线性。
4) 与 std::distance (first, last) 成线性，加上与 pos 和容器两端距离的较小者成线性。
5) 与 ilist.size() 成线性，加上与 pos 和容器两端距离的较小者成线性。

异常

若在任一端插入单个元素时抛出异常，则此函数无效果（强异常保证）。

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
push_front | 插入元素到容器起始 (公开成员函数)
push_back | 将元素添加到容器末尾 (公开成员函数)


std::deque<T,Allocator>::max_size

< cpp‎ | container‎ | deque

size_type max_size() const; | (C++11 前)
size_type max_size() const noexcept; | (C++11 起)

返回根据系统或库实现限制的容器可保有的元素最大数量，即对于最大容器的 std::distance (begin(), end()) 。

参数

（无）

返回值

元素数量的最大值。

复杂度

常数。

注解

此值通常反映容器大小上的理论极限，至多为 std::numeric_limits <difference_type>::max() 。运行时，可用 RAM 总量可能会限制容器大小到小于 max_size() 的值。

示例

#include <iostream>
#include <deque>

int main()
{
    std::deque<char> s;
    std::cout << "Maximum size of a 'deque' is " << s.max_size() << "\n";
}

可能的输出：

Maximum size of a 'deque' is 9223372036854775807

参阅

size
 返回容纳的元素数
(公开成员函数)


std::deque<T,Allocator>::operator=

< cpp‎ | container‎ | deque

deque& operator=( const deque& other ); | (1) |
 | (2) |
deque& operator=( deque&& other ); |  |  | (C++11 起) (C++17 前)
deque& operator=( deque&& other ) noexcept(/* see below */); |  |  | (C++17 起)
deque& operator=( std::initializer_list <T> ilist ); | (3) | (C++11 起)

替换容器内容。

1) 复制赋值运算符。以 other 的副本替换内容。

若 std::allocator_traits <allocator_type>::propagate_on_container_copy_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若 *this 的分配器在赋值后将与其旧值比较不相等，则用旧分配器解分配内存，然后在复制元素前用新分配器分配内存。否则，在可行时可能复用 *this 所拥有的内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素复制赋值替换。

 (C++11 起)
2) 移动赋值运算符。用移动语义以 other 的内容替换内容（即从 other 移动 other 中的数据到此容器中）。之后 other 在合法但未指定的状态。
若 std::allocator_traits <allocator_type>::propagate_on_container_move_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若它为 false 且 *this 与 other 的分配器不比较相等，则 *this 不能接管 other 所拥有的内存的所有权且必须单独地移动赋值每个元素，并用其自身的分配器按需分配额外内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素移动赋值替换。
3) 以 initializer_list ilist 所标识者替换内容。

参数

other | - | 用作数据源的另一容器
ilist | - | 用作数据源的 initializer_list

返回值

*this

复杂度

1) 与 *this 和 other 的大小成线性。
2) 与 *this 的大小成线性，除非分配器不比较相等且不传播，该情况下与 *this 和 other 的大小成线性。
3) 与 *this 和 ilist 的大小成线性。

异常

可能抛出实现定义的异常。 | (C++17 前)
1,3) 可能抛出实现定义的异常。 2) noexcept 说明： noexcept( std::allocator_traits <Allocator>::is_always_equal::value) | (C++17 起)

注解

在容器移动赋值（重载 (2) ）后，除非不兼容的分配器强制逐元素移动赋值，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

下列代码用 operator= 赋值一个 std::deque 给另一个：

#include <deque>
#include <iostream>

void display_sizes(const std::deque<int>& nums1,
                   const std::deque<int>& nums2,
                   const std::deque<int>& nums3)
{
    std::cout << "nums1: " << nums1.size()
              << " nums2: " << nums2.size()
              << " nums3: " << nums3.size() << '\n';
}

int main()
{
    std::deque<int> nums1 {3, 1, 4, 6, 5, 9};
    std::deque<int> nums2;
    std::deque<int> nums3;

    std::cout << "Initially:\n";
    display_sizes(nums1, nums2, nums3);

    // 复制赋值会从 nums1 复制数据到 nums2
    nums2 = nums1;

    std::cout << "After assigment:\n";
    display_sizes(nums1, nums2, nums3);

    // 移动赋值会从 nums1 移动数据到 nums3 ，
    // 一并修改 nums1 和 nums3
    nums3 = std::move(nums1);

    std::cout << "After move assigment:\n";
    display_sizes(nums1, nums2, nums3);
}

输出：

Initially:
nums1: 6 nums2: 0 nums3: 0
After assigment:
nums1: 6 nums2: 6 nums3: 0
After move assigment:
nums1: 0 nums2: 6 nums3: 6

参阅

(构造函数) | 构造 deque (公开成员函数)
assign | 将值赋给容器 (公开成员函数)


std::deque<T,Allocator>::operator[]

< cpp‎ | container‎ | deque

reference operator[]( size_type pos );
const_reference operator[]( size_type pos ) const;

返回位于指定位置 pos 的元素的引用。不进行边界检查。

参数

pos - 要返回的元素的位置

返回值

到所需元素的引用。

复杂度

常数。

注解

不同于 std::map::operator[] ，此运算符决不插入新元素到容器。通过此运算符访问不存在的元素是未定义行为。

示例

下列代码使用 operator[] 读取并写入 std::deque <int> ：

#include <deque>
#include <iostream>

int main()
{
    std::deque<int> numbers {2, 4, 6, 8};

    std::cout << "Second element: " << numbers[1] << '\n';

    numbers[0] = 5;

    std::cout << "All numbers:";
    for (auto i : numbers) {
        std::cout << ' ' << i;
    }
    std::cout << '\n';
}

输出：

Second element: 4
All numbers: 5 4 6 8

参阅

at
 访问指定的元素，同时进行越界检查
(公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::deque)

< cpp‎ | container‎ | deque

定义于头文件 <deque>
template< class T, class Alloc >

bool operator==( const std::deque <T,Alloc>& lhs,

const std::deque <T,Alloc>& rhs );
 (1)
template< class T, class Alloc >

bool operator!=( const std::deque <T,Alloc>& lhs,

const std::deque <T,Alloc>& rhs );
 (2) (C++20 前)
template< class T, class Alloc >

bool operator<( const std::deque <T,Alloc>& lhs,

const std::deque <T,Alloc>& rhs );
 (3) (C++20 前)
template< class T, class Alloc >

bool operator<=( const std::deque <T,Alloc>& lhs,

const std::deque <T,Alloc>& rhs );
 (4) (C++20 前)
template< class T, class Alloc >

bool operator>( const std::deque <T,Alloc>& lhs,

const std::deque <T,Alloc>& rhs );
 (5) (C++20 前)
template< class T, class Alloc >

bool operator>=( const std::deque <T,Alloc>& lhs,

const std::deque <T,Alloc>& rhs );
 (6) (C++20 前)
template< class T, class Alloc >

/* see below */ operator<=>( const std::deque <T,Alloc>& lhs,

const std::deque <T,Alloc>& rhs );
 (7) (C++20 起)

比较二个 deque 的内容。

1-2) 检查 lhs 与 rhs 的内容是否相等，即它们是否拥有相同数量的元素且 lhs 中每个元素与 rhs 的同位置元素比较相等。
3-6) 按字典序比较 lhs 与 rhs 的内容。由等价于 std::lexicographical_compare 的函数进行比较。
7) 按字典序比较 lhs 与 rhs 的内容。如同通过在二个 deque 上以进行合成三路比较（见后述）的函数对象调用 std::lexicographical_compare_three_way 进行比较。返回类型同合成三路比较的结果类型。

给定分别作为左操作数与右操作数的两个 const E 左值 lhs 与 rhs （其中 E 为 T ），合成三路比较定义如下：

  • 若 std::three_way_comparable_with<E, E> 得到满足则等价于 lhs <=> rhs ；
  • 否则，若以 operator< 比较二个 const E 左值为良构且结果类型满足 boolean-testable ，则等价于
lhs < rhs ? std::weak_ordering::less :
rhs < lhs ? std::weak_ordering::greater :
            std::weak_ordering::equivalent
  • 否则，不定义合成三路比较，而 operator<=> 不参与重载决议。
若 three_way_comparable_with 或 boolean-testable 被满足但未被实现，或使用 operator< 但 E 与 < 不建立全序，则 operator<=> 的行为未定义。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较内容的 deque
-
为使用重载 (1-2) ， T 必须满足可相等比较 (EqualityComparable) 的要求。
-
为使用重载 (3-6) ， T 必须满足可小于比较 (LessThanComparable) 的要求。顺序关系必须建立全序。

返回值

1) 若 deque 内容相等则为 true ，否则为 false
2) 若 deque 内容不相等则为 true ，否则为 false
3) 若 lhs 的内容按字典序小于 rhs 的内容则为 true ，否则为 false
4) 若 lhs 的内容按字典序小于或等于 rhs 的内容则为 true ，否则为 false
5) 若 lhs 的内容按字典序大于 rhs 的内容则为 true ，否则为 false
6) 若 lhs 的内容按字典序大于或等于 rhs 的内容则为 true ，否则为 false
7) lhs 与 rhs 中的首对不等价元素的相对顺序，若有这种元素；否则为 lhs.size() <=> rhs.size() 。

复杂度

1-2) 若 lhs 与 rhs 的大小不同则为常数，否则与 deque 大小成线性
3-7) 与 deque 大小成线性

示例

#include <iostream>
#include <deque>

int main()
{
    std::deque<int> alice{1, 2, 3};
    std::deque<int> bob{7, 8, 9, 10};
    std::deque<int> eve{1, 2, 3};

    std::cout << std::boolalpha;

    // 比较不相等的容器
    std::cout << "alice == bob returns " << (alice == bob) << '\n';
    std::cout << "alice != bob returns " << (alice != bob) << '\n';
    std::cout << "alice <  bob returns " << (alice < bob) << '\n';
    std::cout << "alice <= bob returns " << (alice <= bob) << '\n';
    std::cout << "alice >  bob returns " << (alice > bob) << '\n';
    std::cout << "alice >= bob returns " << (alice >= bob) << '\n';

    std::cout << '\n';

    // 比较相等的容器
    std::cout << "alice == eve returns " << (alice == eve) << '\n';
    std::cout << "alice != eve returns " << (alice != eve) << '\n';
    std::cout << "alice <  eve returns " << (alice < eve) << '\n';
    std::cout << "alice <= eve returns " << (alice <= eve) << '\n';
    std::cout << "alice >  eve returns " << (alice > eve) << '\n';
    std::cout << "alice >= eve returns " << (alice >= eve) << '\n';
}

输出：

alice == bob returns false
alice != bob returns true
alice <  bob returns true
alice <= bob returns true
alice >  bob returns false
alice >= bob returns false

alice == eve returns true
alice != eve returns false
alice <  eve returns false
alice <= eve returns true
alice >  eve returns false
alice >= eve returns true


std::deque<T,Allocator>::pop_back

< cpp‎ | container‎ | deque

void pop_back();

移除容器的末元素。

在空容器上调用 pop_back 导致未定义行为。

指向被擦除元素的迭代器和引用被非法化。尾后迭代器是否被非法化是未指定的。其他迭代器和引用不受影响。 | (C++11 前)
指向被擦除元素的迭代器和引用被非法化。尾后迭代器亦被非法化。其他引用和迭代器不受影响。 | (C++11 起)

参数

（无）

返回值

（无）

复杂度

常数。

异常

不抛出。

示例

#include <deque>
#include <iostream>

template<class T>
void print(T const & xs)
{
    std::cout << "[ ";
    for(auto && x : xs) {
        std::cout << x << ' ';
    }
    std::cout << "]\n";
}

int main()
{
    std::deque<int> numbers;

    print(numbers);

    numbers.push_back(5);
    numbers.push_back(3);
    numbers.push_back(4);

    print(numbers);

    numbers.pop_back();

    print(numbers);
}

输出：

[ ]
[ 5 3 4 ]
[ 5 3 ]

参阅

pop_front | 移除首元素 (公开成员函数)
push_back | 将元素添加到容器末尾 (公开成员函数)


std::deque<T,Allocator>::pop_front

< cpp‎ | container‎ | deque

void pop_front();

移除容器首元素。若容器中无元素，则行为未定义。

指向被擦除元素的迭代器和引用被非法化。若元素是容器中的最后元素，则尾后迭代器是否被非法化是未指定的。其他迭代器和引用不受影响。 | (C++11 前)
指向被擦除元素的迭代器和引用被非法化。若元素是容器的最后元素，则尾后迭代器亦被非法化。其他迭代器和引用不受影响。 | (C++11 起)

参数

（无）

返回值

（无）

复杂度

常数。

异常

不抛出。

参阅

pop_back | 移除末元素 (公开成员函数)
push_front | 插入元素到容器起始 (公开成员函数)


std::deque<T,Allocator>::push_back

< cpp‎ | container‎ | deque

void push_back( const T& value ); | (1) |
void push_back( T&& value ); | (2) | (C++11 起)

后附给定元素 value 到容器尾。

1) 初始化新元素为 value 的副本。
2) 移动 value 进新元素。

所有迭代器，包含尾后迭代器，都被非法化。没有引用被非法化。

参数

value - 要后附的元素值
类型要求
-
为使用重载 (1) ， T 必须满足可复制插入 (CopyInsertable) 的要求。
-
为使用重载 (2) ， T 必须满足可移动插入 (MoveInsertable) 的要求。

返回值

（无）

复杂度

常数。

异常

若抛出异常（可能因为 Allocator::allocate() 或元素复制/移动构造函数/赋值），则此函数无效果（强异常保证）。

示例

#include <deque>
#include <iostream>
#include <iomanip>

int main()
{
    std::deque<std::string> letters;

    letters.push_back("abc");
    std::string s = "def";
    letters.push_back(std::move(s));

    std::cout << "deque holds: ";
    for (auto&& i : letters) std::cout << std::quoted(i) << ' ';
    std::cout << "\nMoved-from string holds " << std::quoted(s) << '\n';
}

输出：

deque holds: "abc" "def"
Moved-from string holds ""

参阅

emplace_back (C++11) | 在容器末尾就地构造元素 (公开成员函数)
push_front | 插入元素到容器起始 (公开成员函数)
pop_back | 移除末元素 (公开成员函数)


std::deque<T,Allocator>::push_front

< cpp‎ | container‎ | deque

void push_front( const T& value ); |
void push_front( T&& value ); | (C++11 起)

前附给定元素 value 到容器起始。

所有迭代器，包含尾后迭代器，都被非法化。没有引用被非法化。

参数

value - 要前附的元素值

返回值

（无）

复杂度

常数。

异常

若抛出异常，则此函数无效果（强异常保证）。

参阅

emplace_front (C++11) | 在容器头部原位构造元素 (公开成员函数)
push_back | 将元素添加到容器末尾 (公开成员函数)
pop_front | 移除首元素 (公开成员函数)


std::deque<T,Allocator>::rbegin, std::deque<T,Allocator>::crbegin

< cpp‎ | container‎ | deque

reverse_iterator rbegin(); | (C++11 前)
reverse_iterator rbegin() noexcept; | (C++11 起)
const_reverse_iterator rbegin() const; | (C++11 前)
const_reverse_iterator rbegin() const noexcept; | (C++11 起)
const_reverse_iterator crbegin() const noexcept; | (C++11 起)

返回指向逆向 deque 首元素的逆向迭代器。它对应非逆向 deque 的末元素。若 deque 为空，则返回的迭代器等于 rend() 。

参数

（无）

返回值

指向首元素的逆向迭代器。

复杂度

常数。

示例

#include <iostream>
#include <numeric>
#include <deque>
#include <string>

int main()
{
        std::deque<int> nums {1, 2, 4, 8, 16};
        std::deque<std::string> fruits {"orange", "apple", "raspberry"};
        std::deque<char> empty;

        // 求和 deque nums 中的所有整数（若存在），仅打印结果。
        std::cout << "Sum of nums: " <<
                std::accumulate(nums.begin(), nums.end(), 0) << "\n";

        // 打印 deque fruits 中的首个 fruis ，不检查是否有一个。
        std::cout << "First fruit: " << *fruits.begin() << "\n";

        if (empty.begin() == empty.end())
                std::cout << "deque 'empty' is indeed empty.\n";
}

输出：

Sum of nums: 31
First fruit: orange
deque 'empty' is indeed empty.

参阅

rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)


std::deque<T,Allocator>::rend, std::deque<T,Allocator>::crend

< cpp‎ | container‎ | deque

reverse_iterator rend(); | (C++11 前)
reverse_iterator rend() noexcept; | (C++11 起)
const_reverse_iterator rend() const; | (C++11 前)
const_reverse_iterator rend() const noexcept; | (C++11 起)
const_reverse_iterator crend() const noexcept; | (C++11 起)

返回指向逆向 deque 末元素后一元素的逆向迭代器。它对应非逆向 deque 首元素的前一元素。此元素表现为占位符，试图访问它导致未定义行为。

参数

（无）

返回值

指向末元素后一元素的逆向迭代器。

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)


std::deque<T,Allocator>::resize

< cpp‎ | container‎ | deque

void resize( size_type count ); | (1) | (C++11 起)
 | (2) |
void resize( size_type count, T value = T() ); |  |  | (C++11 前)
void resize( size_type count, const value_type& value ); |  |  | (C++11 起)

重设容器大小以容纳 count 个元素。

若当前大小大于 count ，则减小容器为其首 count 个元素。

若当前大小小于 count ，

1) 则后附额外的默认插入的元素
2) 则后附额外的 value 的副本

参数

count | - | 容器的大小
value | - | 用以初始化新元素的值
类型要求
- 为使用重载 (1) ， T 必须满足可移动插入 (MoveInsertable) 和 可默认插入 (DefaultInsertable) 的要求。
- 为使用重载 (2) ， T 必须满足可复制插入 (CopyInsertable) 的要求。

返回值

（无）

复杂度

与当前大小和 count 间的差成线性。

注解

若不想要重载 (1) 中的值初始化，例如元素是非类类型且不需要清零，则可以提供定制的 Allocator::construct 避免。

示例

#include <iostream>
#include <deque>
int main()
{
    std::deque<int> c = {1, 2, 3};
    std::cout << "The deque holds: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
    c.resize(5);
    std::cout << "After resize up to 5: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
    c.resize(2);
    std::cout << "After resize down to 2: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
}

输出：

The deque holds: 1 2 3
After resize up to 5: 1 2 3 0 0
After resize down to 2: 1 2

参阅

size | 返回容纳的元素数 (公开成员函数)
insert | 插入元素 (公开成员函数)
erase | 擦除元素 (公开成员函数)


std::deque<T,Allocator>::shrink_to_fit

< cpp‎ | container‎ | deque

void shrink_to_fit(); | (C++11 起)

请求移除未使用的容量。

它是减少使用内存而不更改序列的大小非强制性请求。请求是否达成依赖于实现。

所有迭代器和引用都被非法化。尾后迭代器亦被非法化。

参数

（无）

类型要求
-
T 必须满足可移动插入 (MoveInsertable) 的要求。

返回值

（无）

复杂度

至多与容器大小成线性。

注解

若 T 的移动构造函数以外的操作抛出异常，则无效果。

示例

#include <deque>

int main() {
    std::deque<int> nums(1000, 42);
    nums.push_front(1);
    nums.pop_front();

    nums.clear();

    // nums 现在不含项目，但它仍保有分配的内存。
    // 调用 shrink_to_fit 可能会释放任何不使用的内存。
    nums.shrink_to_fit();
}

参阅

size
 返回容纳的元素数
(公开成员函数)


std::deque<T,Allocator>::size

< cpp‎ | container‎ | deque

size_type size() const; | (C++11 前)
size_type size() const noexcept; | (C++11 起)

返回容器中的元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

容器中的元素数量。

复杂度

常数。

示例

下列代码用 size 显示 std::deque 中的元素数：

#include <deque>
#include <iostream>

int main()
{
    std::deque<int> nums {1, 3, 5, 7};

    std::cout << "nums contains " << nums.size() << " elements.\n";
}

输出：

nums contains 4 elements.

参阅

empty | 检查容器是否为空 (公开成员函数)
max_size | 返回可容纳的最大元素数 (公开成员函数)
resize | 改变容器中可存储元素的个数 (公开成员函数)


std::deque<T,Allocator>::swap

< cpp‎ | container‎ | deque

void swap( deque& other ); | (C++17 前)
void swap( deque& other ) noexcept(/* see below */); | (C++17 起)

将内容与 other 的交换。不在单独的元素上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。尾后迭代器被非法化。

若 std::allocator_traits <allocator_type>::propagate_on_container_swap::value 为 true ，则用对非成员 swap 的无限定调用交换分配器。否则，不交换它们（且若 get_allocator() != other.get_allocator() ，则行为未定义）。

 (C++11 起)

参数

other - 要与之交换内容的容器

返回值

（无）

异常

（无） | (C++17 前)
noexcept 说明： noexcept( std::allocator_traits <Allocator>::is_always_equal::value) | (C++17 起)

复杂度

常数。

示例

#include <iostream>
#include <deque>

template<class Os, class Co> Os& operator<<(Os& os, const Co& co) {
    os << "{";
    for (auto const& i : co) { os << ' ' << i; }
    return os << " } ";
}

int main()
{
    std::deque<int> a1{1, 2, 3}, a2{4, 5};

    auto it1 = std::next(a1.begin());
    auto it2 = std::next(a2.begin());

    int& ref1 = a1.front();
    int& ref2 = a2.front();

    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';
    a1.swap(a2);
    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';

    // 注意交换后迭代器与引用保持与其原来的元素关联，例如指向 'a1' 中值为 2 的元素的 it1 仍指向同一元素，
    // 尽管此元素被移动到 'a2' 中。
}

输出：

{ 1 2 3 } { 4 5 } 2 5 1 4
{ 4 5 } { 1 2 3 } 2 5 1 4

参阅

std::swap(std::deque)
 特化 std::swap 算法
(函数模板)


std::swap(std::deque)

< cpp‎ | container‎ | deque

定义于头文件 <deque>
template< class T, class Alloc >

void swap( std::deque <T,Alloc>& lhs,

std::deque <T,Alloc>& rhs );
 (C++17 前)
template< class T, class Alloc >

void swap( std::deque <T,Alloc>& lhs,

std::deque <T,Alloc>& rhs ) noexcept(/* see below */);
 (C++17 起)

为 std::deque 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

#include <algorithm>
#include <iostream>
#include <deque>

int main()
{
    std::deque<int> alice{1, 2, 3};
    std::deque<int> bob{7, 8, 9, 10};

    auto print = [](const int& n) { std::cout << " " << n; };

    // 打印交换前的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';

    std::cout << "-- SWAP\n";
    std::swap(alice,bob);

    // 打印交换后的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
}

输出：

alice: 1 2 3
bob  : 7 8 9 10
-- SWAP
alice: 7 8 9 10
bob  : 1 2 3

参阅

swap
 交换内容
(公开成员函数)


std::deque<T,Allocator>::~deque

< cpp‎ | container‎ | deque

~deque();

销毁 deque 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 deque 大小成线性。


std::forward_list

< cpp‎ | container
定义于头文件 <forward_list>
template<

class T,
class Allocator = std::allocator <T>

> class forward_list;
 (1) (C++11 起)
namespace pmr {

template <class T>
using forward_list = std::forward_list<T, std::pmr::polymorphic_allocator <T>>;

}
 (2) (C++17 起)

std::forward_list 是支持从容器中的任何位置快速插入和移除元素的容器。不支持快速随机访问。它实现为单链表，且实质上与其在 C 中实现相比无任何开销。与 std::list 相比，此容器在不需要双向迭代时提供更有效地利用空间的存储。

在链表内或跨数个链表添加、移除和移动元素，不会非法化当前指代链表中其他元素的迭代器。然而，在从链表移除元素（通过 erase_after ）时，指代对应元素的迭代器或引用会被非法化。

std::forward_list 满足容器 (Container) （除了 operator== 的复杂度始终为线性和 size 函数）、知分配器容器 (AllocatorAwareContainer) 和序列容器 (SequenceContainer) 的要求。

模板形参

T - 元素的类型。
加诸元素的要求依赖于容器上进行的实际操作。泛言之，要求元素类型是完整类型并满足可擦除 (Erasable) 的要求，但许多成员函数附带了更严格的要求。 | (C++17 前)
加诸元素的要求依赖于容器上进行的实际操作。泛言之，要求元素类型满足可擦除 (Erasable) 的要求，但许多成员函数附带了更严格的要求。若分配器满足分配器完整性要求，则容器（但非其成员）能以不完整元素类型实例化。 | (C++17 起)
Allocator - 用于获取/释放内存及构造/析构内存中元素的分配器。类型必须满足分配器 (Allocator) 的要求。若 Allocator::value_type 与 T 不同则行为未定义 (C++20 前)程序非良构 (C++20 起)。

成员类型

成员类型 | 定义
value_type | T
allocator_type | Allocator
size_type | 无符号整数类型（通常是 std::size_t ）
difference_type | 有符号整数类型（通常是 std::ptrdiff_t ）
reference | value_type&
const_reference | const value_type&
pointer | std::allocator_traits <Allocator>::pointer
const_pointer | std::allocator_traits <Allocator>::const_pointer
iterator | 指向 value_type 的常老式向前迭代器 (LegacyForwardIterator)
const_iterator | 指向 const value_type 的老式向前迭代器 (LegacyForwardIterator)

成员函数

(构造函数)
(C++11)
 构造 forward_list
(公开成员函数)
(析构函数)
(C++11)
 析构 forward_list
(公开成员函数)
operator=
(C++11)
 赋值给容器
(公开成员函数)
assign
(C++11)
 将值赋给容器
(公开成员函数)
get_allocator
(C++11)
 返回相关的分配器
(公开成员函数)
元素访问
front
(C++11)
 访问第一个元素
(公开成员函数)
迭代器
before_begincbefore_begin
(C++11)
 返回指向第一个元素之前迭代器
(公开成员函数)
begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)
容量
empty
(C++11)
 检查容器是否为空
(公开成员函数)
max_size
(C++11)
 返回可容纳的最大元素数
(公开成员函数)
修改器
clear
(C++11)
 清除内容
(公开成员函数)
insert_after
(C++11)
 在某个元素后插入新元素
(公开成员函数)
emplace_after
(C++11)
 在元素后原位构造元素
(公开成员函数)
erase_after
(C++11)
 擦除元素后的元素
(公开成员函数)
push_front
(C++11)
 插入元素到容器起始
(公开成员函数)
emplace_front
(C++11)
 在容器头部原位构造元素
(公开成员函数)
pop_front
(C++11)
 移除首元素
(公开成员函数)
resize
(C++11)
 改变容器中可存储元素的个数
(公开成员函数)
swap
(C++11)
 交换内容
(公开成员函数)
操作
merge
(C++11)
 合并二个已排序列表
(公开成员函数)
splice_after
(C++11)
 从另一 forward_list 移动元素
(公开成员函数)
removeremove_if
(C++11)
 移除满足特定标准的元素
(公开成员函数)
reverse
(C++11)
 将该链表的所有元素的顺序反转
(公开成员函数)
unique
(C++11)
 删除连续的重复元素
(公开成员函数)
sort
(C++11)
 对元素进行排序
(公开成员函数)

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 按照字典顺序比较 forward_list 中的值 (函数模板)
std::swap(std::forward_list) (C++11) | 特化 std::swap 算法 (函数模板)
erase(std::forward_list)erase_if(std::forward_list) (C++20) | 擦除所有满足特定判别标准的元素 (函数模板)

推导指引 (C++17 起)


std::forward_list<T,Allocator>::assign

< cpp‎ | container‎ | forward list

void assign( size_type count, const T& value ); | (1) | (C++11 起)
template< class InputIt > void assign( InputIt first, InputIt last ); | (2) | (C++11 起)
void assign( std::initializer_list <T> ilist ); | (3) | (C++11 起)

替换容器的内容。

1) 以 count 份 value 的副本替换内容。
2) 以范围 [first, last) 中元素的副本替换内容。若任一参数是指向 *this 中的迭代器则行为未定义。
若 InputIt 为整数类型，则此重载与 (1) 拥有相同效果。 | (C++11 前)
此重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 才参与重载决议。 | (C++11 起)
3) 以来自 initializer_list ilist 的元素替换内容。

所有指向容器元素的迭代器、指针及引用均被非法化。

参数

count | - | 容器的新大小
value | - | 用以初始化容器元素的值
first, last | - | 复制来源元素的范围
ilist | - | 复制值来源的 initializer_list

复杂度

1) 与 count 成线性
2) 与 first 和 last 间的距离成线性
3) 与 ilist.size() 成线性

示例

下列代码用 assign 添加数个字符到 std::forward_list <char> ：

#include <forward_list>
#include <iostream>

int main()
{
    std::forward_list<char> characters;

    characters.assign(5, 'a');

    for (char c : characters) {
        std::cout << c << ' ';
    }

    characters.assign({'\n', 'C', '+', '+', '1', '1', '\n'});

    for (char c : characters) {
        std::cout << c;
    }
}

输出：

a a a a a
C++11

参阅

(构造函数)
(C++11)
 构造 forward_list
(公开成员函数)


std::forward_list<T,Allocator>::before_begin, cbefore_begin

< cpp‎ | container‎ | forward list
iterator before_begin() noexcept; | (C++11 起)
const_iterator before_begin() const noexcept; | (C++11 起)
const_iterator cbefore_begin() const noexcept; | (C++11 起)

返回指向首元素前一元素的迭代器。此元素表现为占位符，试图访问它会导致未定义行为。仅有的使用情况是在函数 insert_after() 、 emplace_after() 、 erase_after() 、 splice_after() 和迭代器自增中：自增始前迭代器准确地给出与从 begin()/cbegin() 获得者相同的迭代器。

参数

（无）

返回值

指向首元素前一元素的迭代器。

复杂度

常数。

参阅

begin cbegin (C++11) | 返回指向起始的迭代器 (公开成员函数)
end cend (C++11) | 返回指向末尾的迭代器 (公开成员函数)


std::forward_list<T,Allocator>::begin, std::forward_list<T,Allocator>::cbegin

< cpp‎ | container‎ | forward list

iterator begin() noexcept; | (C++11 起)
const_iterator begin() const noexcept; | (C++11 起)
const_iterator cbegin() const noexcept; | (C++11 起)

返回指向 forward_list 首元素的迭代器。

若 forward_list 为空，则返回的迭代器将等于 end() 。

参数

（无）

返回值

指向首元素的迭代器。

复杂度

常数。

示例

#include <iostream>
#include <numeric>
#include <forward_list>
#include <string>

int main()
{
        std::forward_list<int> nums {1, 2, 4, 8, 16};
        std::forward_list<std::string> fruits {"orange", "apple", "raspberry"};
        std::forward_list<char> empty;

        // 求和 forward_list nums 中的所有整数（若存在），仅打印结果。
        std::cout << "Sum of nums: " <<
                std::accumulate(nums.begin(), nums.end(), 0) << "\n";

        // 打印 forward_list fruits 中的首个 fruis ，不检查是否有一个。
        std::cout << "First fruit: " << *fruits.begin() << "\n";

        if (empty.begin() == empty.end())
                std::cout << "forward_list 'empty' is indeed empty.\n";
}

输出：

Sum of nums: 31
First fruit: orange
forward_list 'empty' is indeed empty.

参阅

end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)


std::forward_list<T,Allocator>::clear

< cpp‎ | container‎ | forward list

void clear() noexcept; | (C++11 起)

从容器擦除所有元素。此调用后 size() 返回零。

非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器保持合法。

参数

（无）

返回值

（无）

复杂度

与容器大小，即元素数成线性。

示例

#include <algorithm>
#include <iostream>
#include <forward_list>

int main()
{
    std::forward_list<int> container{1, 2, 3};

    auto print = [](const int& n) { std::cout << " " << n; };

    std::cout << "Before clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << '\n';

    std::cout << "Clear\n";
    container.clear();

    std::cout << "After clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << '\n';
}

输出：

Before clear: 1 2 3
Clear
After clear:

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2231 | C++11 | C++11 中错误地省略了复杂度保证 | 重申复杂度为线性

参阅

erase_after
(C++11)
 擦除元素后的元素
(公开成员函数)


std::forward_list 的推导指引

< cpp‎ | container‎ | forward list

定义于头文件 <forward_list>
template< class InputIt,

class Alloc = std::allocator <typename std::iterator_traits <InputIt>::value_type>>
forward_list(InputIt, InputIt, Alloc = Alloc())

-> forward_list<typename std::iterator_traits <InputIt>::value_type, Alloc>;
 (C++17 起)

为 forward_list 提供此推导指引，以允许从迭代器范围推导。此重载仅若InputIt 满足老式输入迭代器 (LegacyInputIterator) 且 Alloc 满足分配器 (Allocator) 才参与重载决议

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

示例

#include <forward_list>
#include <vector>
int main() {
   std::vector<int> v = {1, 2, 3, 4};

   // 使用显式推导指引推导 std::forward_list<int>
   std::forward_list x(v.begin(), v.end());

   // 推导 std::forward_list<std::vector<int>::iterator>
   // 列表初始化的重载决议第一阶段选择从 initializer_list 构造函数合成的候选
   // 不进行第二阶段且推导指引无效果
   std::forward_list y{v.begin(), v.end()};
}


std::forward_list<T,Allocator>::emplace_after

< cpp‎ | container‎ | forward list
template< class... Args > iterator emplace_after( const_iterator pos, Args&&... args ); | (C++11 起)

在容器中的指定位置后插入新元素。原位构造元素，即不进行复制或移动操作。准确地以与提供给函数者相同的参数调用元素的构造函数。

没有引用和迭代器被非法化。

参数

pos | - | 新元素将构造于其后的迭代器
args | - | 转发给元素构造函数的参数

返回值

指向新元素的迭代器。

复杂度

常数。

异常

若抛出任何异常（例如由构造函数），则容器留在未修改状态，如同从未调用过此函数（强异常保证）。

示例

示例演示按自然顺序（与逆序相反）的单链表规范填充。

#include <forward_list>
#include <iostream>
#include <string>

struct Sum {
    std::string remark;
    int sum;

    Sum(std::string remark, int sum)
        : remark{std::move(remark)}, sum{sum} {}

    void print() const {
        std::cout << remark << " = " << sum << '\n';
    }
};

int main()
{
    std::forward_list<Sum> list;

    auto iter = list.before_begin();
    std::string str{"1"};
    for (int i{1}, sum{1}; i != 10; sum += i) {
        iter = list.emplace_after(iter, str, sum);
        ++i;
        str += " + " + std::to_string(i);
    }

    for (const Sum& s : list) s.print();
}

输出：

1 = 1
1 + 2 = 3
1 + 2 + 3 = 6
1 + 2 + 3 + 4 = 10
1 + 2 + 3 + 4 + 5 = 15
1 + 2 + 3 + 4 + 5 + 6 = 21
1 + 2 + 3 + 4 + 5 + 6 + 7 = 28
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 = 36
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 = 45

参阅

insert_after
(C++11)
 在某个元素后插入新元素
(公开成员函数)


std::forward_list<T,Allocator>::emplace_front

< cpp‎ | container‎ | forward list

template< class... Args > void emplace_front( Args&&... args ); | (C++11 起) (C++17 前)
template< class... Args > reference emplace_front( Args&&... args ); | (C++17 起)

插入新元素到容器起始。通过 std::allocator_traits::construct 构造元素，它典型地用布置 new 在容器所提供的位置原位构造元素。将参数 args... 作为 std::forward <Args>(args)... 转发给构造函数。

没有引用和迭代器被非法化。

参数

args - 转发给元素构造函数的参数
类型要求
-
T （容器元素类型） 必须满足可就位构造 (EmplaceConstructible) 的要求。

返回值

（无） | (C++17 前)
到被插入元素的引用。 | (C++17 起)

复杂度

常数。

异常

若抛异常，则此函数无效果（强异常保证）。

参阅

push_front
(C++11)
 插入元素到容器起始
(公开成员函数)


std::forward_list<T,Allocator>::empty

< cpp‎ | container‎ | forward list

bool empty() const noexcept; | (C++11 起) (C++20 前)
[[nodiscard]] bool empty() const noexcept; | (C++20 起)

检查容器是否无元素，即是否 begin() == end() 。

参数

（无）

返回值

若容器为空则为 true ，否则为 false

复杂度

常数。

示例

下列代码用 empty 检查 std::forward_list <int> 是否含任何元素：

#include <forward_list>
#include <iostream>

int main()
{
    std::forward_list<int> numbers;
    std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';

    numbers.push_front(42);
    numbers.push_front(13317);
    std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
}

输出：

Initially, numbers.empty(): 1
After adding elements, numbers.empty(): 0


std::forward_list<T,Allocator>::end, std::forward_list<T,Allocator>::cend

< cpp‎ | container‎ | forward list

iterator end() noexcept; | (C++11 起)
const_iterator end() const noexcept; | (C++11 起)
const_iterator cend() const noexcept; | (C++11 起)

返回指向 forward_list 末元素后一元素的迭代器。

此元素表现为占位符；试图访问它导致未定义行为。

参数

（无）

返回值

指向后随最后元素的迭代器。

复杂度

常数。

示例

#include <iostream>
#include <numeric>
#include <forward_list>
#include <string>

int main()
{
        std::forward_list<int> nums {1, 2, 4, 8, 16};
        std::forward_list<std::string> fruits {"orange", "apple", "raspberry"};
        std::forward_list<char> empty;

        // 求和 forward_list nums 中的所有整数（若存在），仅打印结果。
        std::cout << "Sum of nums: " <<
                std::accumulate(nums.begin(), nums.end(), 0) << "\n";

        // 打印 forward_list fruits 中的首个 fruis ，不检查是否有一个。
        std::cout << "First fruit: " << *fruits.begin() << "\n";

        if (empty.begin() == empty.end())
                std::cout << "forward_list 'empty' is indeed empty.\n";
}

输出：

Sum of nums: 31
First fruit: orange
forward_list 'empty' is indeed empty.

参阅

begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)


std::erase, std::erase_if (std::forward_list)

< cpp‎ | container‎ | forward list

定义于头文件 <forward_list>
template< class T, class Alloc, class U >

typename std::forward_list <T,Alloc>::size_type

erase( std::forward_list <T,Alloc>& c, const U& value);
 (1) (C++20 起)
template< class T, class Alloc, class Pred >

typename std::forward_list <T,Alloc>::size_type

erase_if( std::forward_list <T,Alloc>& c, Pred pred);
 (2) (C++20 起)
1) 从容器中擦除所有比较等于 value 的元素。等价于 return c.remove_if([&](auto& elem) { return elem == value; }); 。
2) 从容器中擦除所有满足 pred 的元素。等价于 return c.remove_if(pred); 。

参数

c | - | 要从中擦除的容器
value | - | 要擦除的值
pred | - | 若应该擦除元素则返回 ​true 的一元谓词。 对每个（可为 const 的） T 类型参数 v ，表达式 pred(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 T& 类型参数，亦不允许 T ，除非对 T 而言移动等价于复制 (C++11 起)。 ​

返回值

被擦除的元素数。

复杂度

线性。

示例

#include <iostream>
#include <numeric>
#include <forward_list>

void print_container(const std::forward_list<char>& c)
{
    for (auto x : c) {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    std::forward_list<char> cnt(10);
    std::iota(cnt.begin(), cnt.end(), '0');

    std::cout << "Init:\n";
    print_container(cnt);

    auto erased = std::erase(cnt, '3');
    std::cout << "Erase \'3\':\n";
    print_container(cnt);

    std::erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; });
    std::cout << "Erase all even numbers:\n";
    print_container(cnt);
    std::cout << "In all " << erased << " even numbers were erased.\n";
}

输出：

Init:
0 1 2 3 4 5 6 7 8 9
Erase '3':
0 1 2 4 5 6 7 8 9
Erase all even numbers:
1 5 7 9
In all 5 even numbers were erased.

注解

不同于 std::forward_list::remove ， erase 接受异种类型并且不强制在调用 == 运算符前转换到容器的值类型。

参阅

removeremove_if | 移除满足特定判别标准的元素 (函数模板)
removeremove_if (C++11) | 移除满足特定标准的元素 (公开成员函数)


std::forward_list<T,Allocator>::erase_after

< cpp‎ | container‎ | forward list
iterator erase_after( const_iterator pos ); | (1) | (C++11 起)
iterator erase_after( const_iterator first, const_iterator last ); | (2) | (C++11 起)

从容器移除指定元素。

1) 移除 pos 后的元素。
2) 移除 first 后 last 前的元素。

参数

pos | - | 指向前趋要被移除元素的迭代器
first, last | - | 要移除的元素范围

返回值

1) 指向后随被擦除元素的迭代器，或若不存在这种元素则为 end() 。
2) last

复杂度

1) 常数。
2) 与 first 和 last 之间的距离成线性。

示例

#include <forward_list>
#include <iterator>
#include <iostream>
int main()
{
    std::forward_list<int> l = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    //    l.erase( l.begin() ); // 错误：无要擦除的元素

    l.erase_after( l.before_begin() ); // 移除首元素

    for( auto n : l ) std::cout << n << " ";
    std::cout << '\n';

    auto fi= std::next( l.begin() );
    auto la= std::next( fi, 3 );

    l.erase_after( fi, la );

    for( auto n : l ) std::cout << n << " ";
    std::cout << '\n';
}

输出：

2 3 4 5 6 7 8 9
2 3 6 7 8 9

参阅

clear
(C++11)
 清除内容
(公开成员函数)


std::forward_list<T,Allocator>::forward_list

< cpp‎ | container‎ | forward list

forward_list();
 (1)
explicit forward_list( const Allocator& alloc );
 (2)
forward_list( size_type count,

const T& value,

const Allocator& alloc = Allocator());
 (3) (C++11 起)
(4)
explicit forward_list( size_type count );
 (C++11 起)
(C++14 前)
explicit forward_list( size_type count, const Allocator& alloc = Allocator() );
 (C++14 起)
template< class InputIt >

forward_list( InputIt first, InputIt last,

const Allocator& alloc = Allocator() );
 (5) (C++11 起)
forward_list( const forward_list& other );
 (6) (C++11 起)
forward_list( const forward_list& other, const Allocator& alloc );
 (7) (C++11 起)
forward_list( forward_list&& other );
 (8) (C++11 起)
forward_list( forward_list&& other, const Allocator& alloc );
 (9) (C++11 起)
forward_list( std::initializer_list <T> init,
const Allocator& alloc = Allocator() );
 (10) (C++11 起)

从各种数据源构造新容器，可选地使用用户提供的分配器 alloc 。

1) 默认构造函数。构造拥有默认构造的分配器的空容器。
2) 构造拥有给定分配器 alloc 的空容器。
3) 构造拥有 count 个有值 value 的元素的容器。
4) 构造拥有个 count 默认插入的 T 实例的容器。不进行复制。
5) 构造拥有范围 [first, last) 内容的容器。
若 InputIt 是整数类型，则此构造函数拥有的效果同 forward_list(static_cast<size_type>(first), static_cast<value_type>(last), a) 。 | (C++11 前)
此重载仅若InputIt 满足老式输入迭代器 (LegacyInputIterator) 才参与重载决议，以避免和重载 (2) 的歧义。 | (C++11 起)
6) 复制构造函数。构造拥有 other 内容的容器。

如同通过调用
std::allocator_traits <allocator_type>::select_on_container_copy_construction(
other.get_allocator())
获得分配器。

 (C++11 起)
7) 构造拥有 other 内容的容器，以 alloc 为分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
8) 移动构造函数。用移动语义构造拥有 other 内容的容器。分配器通过属于 other 的分配器移动构造获得。
9) 有分配器扩展的移动构造函数。以 alloc 为新容器的分配器，从 other 移动内容；若 alloc != other.get_allocator() ，则它导致逐元素移动。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
10) 构造拥有 initializer_list init 内容的容器。

参数

alloc | - | 用于此容器所有内存分配的分配器
count | - | 容器的大小
value | - | 以之初始化容器元素的值
first, last | - | 复制元素的来源范围
other | - | 用作初始化容器元素来源的另一容器
init | - | 用作初始化元素来源的 initializer_list

复杂度

1-2) 常数
3-4) 与 count 成线性
5) 与 first 和 last 的距离成线性
6-7) 与 other 的大小成线性
8) 常数。
9) 若 alloc != other.get_allocator() 则为线性，否则为常数。
10) 与 init 的大小成线性。

异常

调用 Allocator::allocate 可能抛出。

注解

在容器移动构造（重载 (8) ）后，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

#include <forward_list>
#include <string>
#include <iostream>

template<typename T>
std::ostream& operator<<(std::ostream& s, const std::forward_list<T>& v)
{
    s.put('[');
    char comma[3] = {'\0', ' ', '\0'};
    for (const auto& e : v) {
        s << comma << e;
        comma[0] = ',';
    }
    return s << ']';
}

int main()
{
    // C++11 初始化器列表语法：
    std::forward_list<std::string> words1 {"the", "frogurt", "is", "also", "cursed"};
    std::cout << "words1: " << words1 << '\n';

    // words2 == words1
    std::forward_list<std::string> words2(words1.begin(), words1.end());
    std::cout << "words2: " << words2 << '\n';

    // words3 == words1
    std::forward_list<std::string> words3(words1);
    std::cout << "words3: " << words3 << '\n';

    // words4 为 {"Mo", "Mo", "Mo", "Mo", "Mo"}
    std::forward_list<std::string> words4(5, "Mo");
    std::cout << "words4: " << words4 << '\n';
}

输出：

words1: [the, frogurt, is, also, cursed]
words2: [the, frogurt, is, also, cursed]
words3: [the, frogurt, is, also, cursed]
words4: [Mo, Mo, Mo, Mo, Mo]

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2193 | C++11 | 默认构造函数为 explicit | 使之为非 explicit

参阅

assign (C++11) | 将值赋给容器 (公开成员函数)
operator= (C++11) | 赋值给容器 (公开成员函数)


std::forward_list<T,Allocator>::front

< cpp‎ | container‎ | forward list

reference front(); | (C++11 起)
const_reference front() const; | (C++11 起)

返回到容器首元素的引用。

在空容器上对 front 的调用是未定义的。

参数

（无）

返回值

到首元素的引用

复杂度

常数

注解

对于容器 c ，表达式 c.front() 等价于 *c.begin() 。

示例

下列代码用 front 显示 std::forward_list <char> 的首元素：

#include <forward_list>
#include <iostream>

int main()
{
    std::forward_list<char> letters {'o', 'm', 'g', 'w', 't', 'f'};

    if (!letters.empty()) {
        std::cout << "The first character is: " << letters.front() << '\n';
    }
}

输出：

The first character is o


std::forward_list<T,Allocator>::get_allocator

< cpp‎ | container‎ | forward list

allocator_type get_allocator() const noexcept; | (C++11 起)

返回与容器关联的分配器。

参数

（无）

返回值

关联的分配器。

复杂度

常数。


std::forward_list<T,Allocator>::insert_after

< cpp‎ | container‎ | forward list
iterator insert_after( const_iterator pos, const T& value ); | (1) | (C++11 起)
iterator insert_after( const_iterator pos, T&& value ); | (2) | (C++11 起)
iterator insert_after( const_iterator pos, size_type count, const T& value ); | (3) | (C++11 起)
template< class InputIt > iterator insert_after( const_iterator pos, InputIt first, InputIt last ); | (4) | (C++11 起)
iterator insert_after( const_iterator pos, std::initializer_list <T> ilist ); | (5) | (C++11 起)

在容器中的指定位置后插入元素。

1-2) 在 pos 所指向的元素后插入 value
3) 在 pos 所指向的元素后插入 value 的 count 个副本
4) 在 pos 所指向的元素后插入来自范围 [first, last) 的元素。 若 first 与 last 是指向 *this 中的迭代器则行为未定义。
5) 插入来自 initializer_list ilist 的元素。

没有引用和迭代器被非法化。

参数

pos | - | 内容将插入到其后的迭代器
value | - | 要插入的元素值
count | - | 要插入的副本数
first, last | - | 要插入的元素范围
ilist | - | 插入值来源的 initializer_list
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

1-2) 指向被插入元素的迭代器。、
3) 指向最后被插入元素的迭代器，或若 count==0 则为 pos 。
4) 指向最后被插入元素的迭代器，或若 first==last 则为 pos 。
5) 指向最后被插入元素的迭代器，或若 ilist 为空则为 pos 。

异常

若在 insert_after 期间抛出异常，则无效果（强异常保证）。

复杂度

1-2) 常数。
3) 与 count 成线性
4) 与 std::distance (first, last) 成线性
5) 与 ilist.size() 成线性

示例

#include <forward_list>
#include <string>
#include <iostream>
#include <vector>

template<typename T>
std::ostream& operator<<(std::ostream& s, const std::forward_list<T>& v) {
    s.put('[');
    char comma[3] = {'\0', ' ', '\0'};
    for (const auto& e : v) {
        s << comma << e;
        comma[0] = ',';
    }
    return s << ']';
}

int main()
{
    std::forward_list<std::string> words {"the", "frogurt", "is", "also", "cursed"};
    std::cout << "words: " << words << '\n';

    // insert_after (2)
    auto beginIt = words.begin();
    words.insert_after(beginIt, "strawberry");
    std::cout << "words: " << words << '\n';

    // insert_after (3)
    auto anotherIt = beginIt;
    ++anotherIt;
    anotherIt = words.insert_after(anotherIt, 2, "strawberry");
    std::cout << "words: " << words << '\n';

    // insert_after (4)
    std::vector<std::string> V = { "apple", "banana", "cherry"};
    anotherIt = words.insert_after(anotherIt, V.begin(), V.end());
    std::cout << "words: " << words << '\n';

    // insert_after (5)
    words.insert_after(anotherIt, {"jackfruit", "kiwifruit", "lime", "mango"});
    std::cout << "words: " << words << '\n';
}

输出：

words: [the, frogurt, is, also, cursed]
words: [the, strawberry, frogurt, is, also, cursed]
words: [the, strawberry, strawberry, strawberry, frogurt, is, also, cursed]
words: [the, strawberry, strawberry, strawberry, apple, banana, cherry, frogurt, is, also, cursed]
words: [the, strawberry, strawberry, strawberry, apple, banana, cherry, jackfruit, kiwifruit, lime, mango, frogurt, is, also, cursed]

参阅

emplace_after (C++11) | 在元素后原位构造元素 (公开成员函数)
push_front (C++11) | 插入元素到容器起始 (公开成员函数)


std::forward_list<T,Allocator>::max_size

< cpp‎ | container‎ | forward list

size_type max_size() const noexcept; | (C++11 起)

返回根据系统或库实现限制的容器可保有的元素最大数量，即对于最大容器的 std::distance (begin(), end()) 。

参数

（无）

返回值

元素数量的最大值。

复杂度

常数。

注解

此值通常反映容器大小上的理论极限，至多为 std::numeric_limits <difference_type>::max() 。运行时，可用 RAM 总量可能会限制容器大小到小于 max_size() 的值。

示例

#include <iostream>
#include <forward_list>

int main()
{
    std::forward_list<char> s;
    std::cout << "Maximum size of a 'forward_list' is " << s.max_size() << "\n";
}

可能的输出：

Maximum size of a 'forward_list' is 1152921504606846975


std::forward_list<T,Allocator>::merge

< cpp‎ | container‎ | forward list

void merge( forward_list& other ); | (1) | (C++11 起)
void merge( forward_list&& other ); | (1) | (C++11 起)
template <class Compare> void merge( forward_list& other, Compare comp ); | (2) | (C++11 起)
template <class Compare> void merge( forward_list&& other, Compare comp ); | (2) | (C++11 起)

归并二个已排序链表为一个。链表应以升序排序。

不复制元素。操作后容器 other 变为空。若 other 与 *this 指代同一对象则函数不做任何事。若 get_allocator() != other.get_allocator() ，则行为未定义。没有引用和迭代器变得非法，除了被移动元素的迭代器现在指代到 *this 中，而非到 other 中，第一版本用 operator< 比较元素，第二版本用给定的比较函数 comp 。

此操作是稳定的：对于二个链表中的等价元素，来自 *this 的元素始终前驱来自 other 的元素，而且 *this 和 other 的等价元素顺序不更改。

参数

other - 要交换的另一容器
comp - 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。

比较函数的签名应等价于如下：

bool cmp(const Type1 &a, const Type2 &b);

虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。
类型 Type1 与 Type2 必须使得 forward_list<T,Allocator>::const_iterator 类型的对象能在解引用后隐式转换到这两个类型。 ​

返回值

（无）

异常

若抛出异常，则此函数无效果（强异常保证），除非异常来自比较函数。

复杂度

至多 std::distance (begin(), end()) + std::distance (other.begin(), other.end()) - 1 次比较。

示例

#include <iostream>
#include <forward_list>

std::ostream& operator<<(std::ostream& ostr, const std::forward_list<int>& list)
{
    for (auto &i : list) {
        ostr << " " << i;
    }
    return ostr;
}

int main()
{
    std::forward_list<int> list1 = { 5,9,0,1,3 };
    std::forward_list<int> list2 = { 8,7,2,6,4 };

    list1.sort();
    list2.sort();
    std::cout << "list1:  " << list1 << "\n";
    std::cout << "list2:  " << list2 << "\n";
    list1.merge(list2);
    std::cout << "merged: " << list1 << "\n";
}

输出：

list1:   0 1 3 5 9
list2:   2 4 6 7 8
merged:  0 1 2 3 4 5 6 7 8 9

参阅

splice_after
(C++11)
 从另一 forward_list 移动元素
(公开成员函数)


std::forward_list<T,Allocator>::operator=

< cpp‎ | container‎ | forward list

forward_list& operator=( const forward_list& other ); | (1) | (C++11 起)
 | (2) |
forward_list& operator=( forward_list&& other ); |  |  | (C++11 起) (C++17 前)
forward_list& operator=( forward_list&& other ) noexcept(/* see below */); |  |  | (C++17 起)
forward_list& operator=( std::initializer_list <T> ilist ); | (3) | (C++11 起)

替换容器内容。

1) 复制赋值运算符。以 other 的副本替换内容。
若 std::allocator_traits <allocator_type>::propagate_on_container_copy_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若 *this 的分配器在赋值后将与其旧值比较不相等，则用旧分配器解分配内存，然后在复制元素前用新分配器分配内存。否则，在可行时可能复用 *this 所拥有的内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素复制赋值替换。
2) 移动赋值运算符。用移动语义以 other 的内容替换内容（即从 other 移动 other 中的数据到此容器中）。之后 other 在合法但未指定的状态。
若 std::allocator_traits <allocator_type>::propagate_on_container_move_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若它为 false 且 *this 与 other 的分配器不比较相等，则 *this 不能接管 other 所拥有的内存的所有权且必须单独地移动赋值每个元素，并用其自身的分配器按需分配额外内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素移动赋值替换。
3) 以 initializer_list ilist 所标识者替换内容。

参数

other | - | 用作数据源的另一容器
ilist | - | 用作数据源的 initializer_list

返回值

*this

复杂度

1) 与 *this 和 other 的大小成线性。
2) 与 *this 的大小成线性，除非分配器不比较相等且不传播，该情况下与 *this 和 other 的大小成线性。
3) 与 *this 和 ilist 的大小成线性。

异常

可能抛出实现定义的异常。 | (C++17 前)
1,3) 可能抛出实现定义的异常。 2) noexcept 说明： noexcept( std::allocator_traits <Allocator>::is_always_equal::value) | (C++17 起)

注解

在容器移动赋值（重载 (2) ）后，除非不兼容的分配器强制逐元素移动赋值，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

下列代码用 operator= 赋值一个 std::forward_list 给另一个：

#include <forward_list>
#include <iostream>

void display_sizes(const std::forward_list<int> &nums1,
                   const std::forward_list<int> &nums2,
                   const std::forward_list<int> &nums3)
{
    std::cout << "nums1: " << std::distance(nums1.begin(), nums1.end())
              << " nums2: " << std::distance(nums2.begin(), nums2.end())
              << " nums3: " << std::distance(nums3.begin(), nums3.end()) << '\n';
}

int main()
{
    std::forward_list<int> nums1 {3, 1, 4, 6, 5, 9};
    std::forward_list<int> nums2;
    std::forward_list<int> nums3;

    std::cout << "Initially:\n";
    display_sizes(nums1, nums2, nums3);

    // 复制赋值从 nums1 复制数据到 nums2
    nums2 = nums1;

    std::cout << "After assigment:\n";
    display_sizes(nums1, nums2, nums3);

    // 移动赋值从 nums1 移动数据到 nums3,
    // 修改 nums1 和 nums3
    nums3 = std::move(nums1);

    std::cout << "After move assigment:\n";
    display_sizes(nums1, nums2, nums3);
}

输出：

Initially:
nums1: 6 nums2: 0 nums3: 0
After assigment:
nums1: 6 nums2: 6 nums3: 0
After move assigment:
nums1: 0 nums2: 6 nums3: 6

参阅

(构造函数) (C++11) | 构造 forward_list (公开成员函数)
assign (C++11) | 将值赋给容器 (公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::forward_list)

< cpp‎ | container‎ | forward list

定义于头文件 <forward_list>
template< class T, class Alloc >

bool operator==( const std::forward_list <T,Alloc>& lhs,

const std::forward_list <T,Alloc>& rhs );
 (1)
template< class T, class Alloc >

bool operator!=( const std::forward_list <T,Alloc>& lhs,

const std::forward_list <T,Alloc>& rhs );
 (2) (C++20 前)
template< class T, class Alloc >

bool operator<( const std::forward_list <T,Alloc>& lhs,

const std::forward_list <T,Alloc>& rhs );
 (3) (C++20 前)
template< class T, class Alloc >

bool operator<=( const std::forward_list <T,Alloc>& lhs,

const std::forward_list <T,Alloc>& rhs );
 (4) (C++20 前)
template< class T, class Alloc >

bool operator>( const std::forward_list <T,Alloc>& lhs,

const std::forward_list <T,Alloc>& rhs );
 (5) (C++20 前)
template< class T, class Alloc >

bool operator>=( const std::forward_list <T,Alloc>& lhs,

const std::forward_list <T,Alloc>& rhs );
 (6) (C++20 前)
template< class T, class Alloc >

/* see below */ operator<=>( const std::forward_list <T,Alloc>& lhs,

const std::forward_list <T,Alloc>& rhs );
 (7) (C++20 起)

比较二个 forward_list 的内容。

1-2) 检查 lhs 与 rhs 的内容是否相等，即它们是否拥有相同数量的元素且 lhs 中每个元素与 rhs 的同位置元素比较相等。
3-6) 按字典序比较 lhs 与 rhs 的内容。由等价于 std::lexicographical_compare 的函数进行比较。
7) 按字典序比较 lhs 与 rhs 的内容。如同通过在二个 forward_list 上以进行合成三路比较（见后述）的函数对象调用 std::lexicographical_compare_three_way 进行比较。返回类型同合成三路比较的结果类型。

给定分别作为左操作数与右操作数的两个 const E 左值 lhs 与 rhs （其中 E 为 T ），合成三路比较定义如下：

  • 若 std::three_way_comparable_with<E, E> 得到满足则等价于 lhs <=> rhs ；
  • 否则，若以 operator< 比较二个 const E 左值为良构且结果类型满足 boolean-testable ，则等价于
lhs < rhs ? std::weak_ordering::less :
rhs < lhs ? std::weak_ordering::greater :
            std::weak_ordering::equivalent
  • 否则，不定义合成三路比较，而 operator<=> 不参与重载决议。
若 three_way_comparable_with 或 boolean-testable 被满足但未被实现，或使用 operator< 但 E 与 < 不建立全序，则 operator<=> 的行为未定义。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较内容的 forward_list
-
为使用重载 (1-2) ， T 必须满足可相等比较 (EqualityComparable) 的要求。
-
为使用重载 (3-6) ， T 必须满足可小于比较 (LessThanComparable) 的要求。顺序关系必须建立全序。

返回值

1) 若 forward_list 内容相等则为 true ，否则为 false
2) 若 forward_list 内容不相等则为 true ，否则为 false
3) 若 lhs 的内容按字典序小于 rhs 的内容则为 true ，否则为 false
4) 若 lhs 的内容按字典序小于或等于 rhs 的内容则为 true ，否则为 false
5) 若 lhs 的内容按字典序大于 rhs 的内容则为 true ，否则为 false
6) 若 lhs 的内容按字典序大于或等于 rhs 的内容则为 true ，否则为 false
7) lhs 与 rhs 中的首对不等价元素的相对顺序，若有这种元素；否则为 lhs.size() <=> rhs.size() 。

复杂度

与 forward_list 大小成线性

示例

#include <iostream>
#include <forward_list>

int main()
{
    std::forward_list<int> alice{1, 2, 3};
    std::forward_list<int> bob{7, 8, 9, 10};
    std::forward_list<int> eve{1, 2, 3};

    std::cout << std::boolalpha;

    // 比较不相等的容器
    std::cout << "alice == bob returns " << (alice == bob) << '\n';
    std::cout << "alice != bob returns " << (alice != bob) << '\n';
    std::cout << "alice <  bob returns " << (alice < bob) << '\n';
    std::cout << "alice <= bob returns " << (alice <= bob) << '\n';
    std::cout << "alice >  bob returns " << (alice > bob) << '\n';
    std::cout << "alice >= bob returns " << (alice >= bob) << '\n';

    std::cout << '\n';

    // 比较相等的容器
    std::cout << "alice == eve returns " << (alice == eve) << '\n';
    std::cout << "alice != eve returns " << (alice != eve) << '\n';
    std::cout << "alice <  eve returns " << (alice < eve) << '\n';
    std::cout << "alice <= eve returns " << (alice <= eve) << '\n';
    std::cout << "alice >  eve returns " << (alice > eve) << '\n';
    std::cout << "alice >= eve returns " << (alice >= eve) << '\n';
}

输出：

alice == bob returns false
alice != bob returns true
alice <  bob returns true
alice <= bob returns true
alice >  bob returns false
alice >= bob returns false

alice == eve returns true
alice != eve returns false
alice <  eve returns false
alice <= eve returns true
alice >  eve returns false
alice >= eve returns true


std::forward_list<T,Allocator>::pop_front

< cpp‎ | container‎ | forward list

void pop_front(); | (C++11 起)

移除容器首元素。若容器中无元素，则行为未定义。

指向被擦除元素的迭代器和引用被非法化。

参数

（无）

返回值

（无）

复杂度

常数。

异常

不抛出。

参阅

push_front
(C++11)
 插入元素到容器起始
(公开成员函数)


std::forward_list<T,Allocator>::push_front

< cpp‎ | container‎ | forward list

void push_front( const T& value ); | (C++11 起)
void push_front( T&& value ); | (C++11 起)

前附给定元素 value 到容器起始。

没有引用和迭代器被非法化。

参数

value - 要前附的元素值

返回值

（无）

复杂度

常数。

异常

若抛出异常，则此函数无效果（强异常保证）。

参阅

emplace_front (C++11) | 在容器头部原位构造元素 (公开成员函数)
pop_front (C++11) | 移除首元素 (公开成员函数)


std::forward_list<T,Allocator>::remove, remove_if

< cpp‎ | container‎ | forward list

void remove( const T& value ); | (C++11 起) (C++20 前)
size_type remove( const T& value ); | (C++20 起)
template< class UnaryPredicate > void remove_if( UnaryPredicate p ); | (C++11 起) (C++20 前)
template< class UnaryPredicate > size_type remove_if( UnaryPredicate p ); | (C++20 起)

移除所有满足特定标准的元素。第一版本移除所有等于 value 的元素，第二版本移除所有谓词 p 对它返回 true 的元素。

参数

value | - | 要移除的元素的值
p | - | 若应该移除该元素则返回 ​true 的一元谓词。 对每个（可为 const 的） T 类型参数 v ，表达式 p(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 T& 类型参数，亦不允许 T ，除非对 T 而言移动等价于复制 (C++11 起)。 ​

返回值

（无） | (C++20 前)
移除的元素数。 | (C++20 起)

复杂度

与容器大小成线性

示例

#include <forward_list>
#include <iostream>

int main()
{
    std::forward_list<int> l = { 1,100,2,3,10,1,11,-1,12 };

    l.remove(1); // 移除两个等于 1 的元素
    l.remove_if([](int n){ return n > 10; }); // 移除全部大于 10 的元素

    for (int n : l) {
        std::cout << n << ' ';
    }
    std::cout << '\n';
}

输出：

2 3 10 -1

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::forward_list<T,Allocator>::resize

< cpp‎ | container‎ | forward list

void resize( size_type count ); | (1) | (C++11 起)
void resize( size_type count, const value_type& value ); | (2) | (C++11 起)

重设容器大小以容纳 count 个元素。

若当前大小大于 count ，则减小容器为其首 count 个元素。

若当前大小小于 count ，

1) 则后附额外的默认插入的元素
2) 则后附额外的 value 的副本

参数

count | - | 容器的大小
value | - | 用以初始化新元素的值
类型要求
- 为使用重载 (1) ， T 必须满足可默认插入 (DefaultInsertable) 的要求。
- 为使用重载 (2) ， T 必须满足可复制插入 (CopyInsertable) 的要求。

返回值

（无）

复杂度

与当前大小和 count 间的差成线性。可能有遍历链表以抵达首个要擦除元素/插入位置结尾所致的额外复杂度。

注解

若不想要重载 (1) 中的值初始化，例如元素是非类类型且不需要清零，则可以提供定制的 Allocator::construct 避免。

示例

#include <iostream>
#include <forward_list>
int main()
{
    std::forward_list<int> c = {1, 2, 3};
    std::cout << "The forward_list holds: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
    c.resize(5);
    std::cout << "After resize up to 5: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
    c.resize(2);
    std::cout << "After resize down to 2: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
}

输出：

The forward_list holds: 1 2 3
After resize up to 5: 1 2 3 0 0
After resize down to 2: 1 2

参阅

insert_after (C++11) | 在某个元素后插入新元素 (公开成员函数)
erase_after (C++11) | 擦除元素后的元素 (公开成员函数)


std::forward_list<T,Allocator>::reverse

< cpp‎ | container‎ | forward list

void reverse() noexcept; | (C++11 起)

逆转容器中的元素顺序。不非法化任何引用或迭代器。

参数

（无）

返回值

（无）

复杂度

与容器大小成线性

示例

#include <iostream>
#include <forward_list>

std::ostream& operator<<(std::ostream& ostr, const std::forward_list<int>& list)
{
    for (auto &i : list) {
        ostr << " " << i;
    }
    return ostr;
}

int main()
{
    std::forward_list<int> list = { 8,7,5,9,0,1,3,2,6,4 };

    std::cout << "before:     " << list << "\n";
    list.sort();
    std::cout << "ascending:  " << list << "\n";
    list.reverse();
    std::cout << "descending: " << list << "\n";
}

输出：

before:      8 7 5 9 0 1 3 2 6 4
ascending:   0 1 2 3 4 5 6 7 8 9
descending:  9 8 7 6 5 4 3 2 1 0

参阅

sort
(C++11)
 对元素进行排序
(公开成员函数)


std::forward_list<T,Allocator>::sort

< cpp‎ | container‎ | forward list

void sort(); | (1) | (C++11 起)
template< class Compare > void sort( Compare comp ); | (2) | (C++11 起)

以升序排序元素。保持相等元素的顺序。第一版本用 operator< 比较元素，第二版本用给定的比较函数 comp 。

若抛出异常，则 *this 中元素顺序未指定。

参数

comp - 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。

比较函数的签名应等价于如下：

bool cmp(const Type1 &a, const Type2 &b);

虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。
类型 Type1 与 Type2 必须使得 forward_list<T,Allocator>::const_iterator 类型的对象能在解引用后隐式转换到这两个类型。 ​

返回值

（无）

复杂度

大约 N log N 次比较，其中 N 是表中的元素数。

注意

std::sort 要求随机访问迭代器且不能用于 forward_list 。此函数与 std::sort 的区别在于，它不要求 forward_list 的元素类型可交换，保留所有迭代器的值，并进行稳定排序。

示例

#include <iostream>
#include <functional>
#include <forward_list>

std::ostream& operator<<(std::ostream& ostr, const std::forward_list<int>& list)
{
    for (auto &i : list) {
        ostr << " " << i;
    }
    return ostr;
}

int main()
{
    std::forward_list<int> list = { 8,7,5,9,0,1,3,2,6,4 };

    std::cout << "before:     " << list << "\n";
    list.sort();
    std::cout << "ascending:  " << list << "\n";
    list.sort(std::greater<int>());
    std::cout << "descending: " << list << "\n";
}

输出：

before:      8 7 5 9 0 1 3 2 6 4
ascending:   0 1 2 3 4 5 6 7 8 9
descending:  9 8 7 6 5 4 3 2 1 0


std::forward_list<T,Allocator>::splice_after

< cpp‎ | container‎ | forward list
void splice_after( const_iterator pos, forward_list& other );
 (1) (C++11 起)
void splice_after( const_iterator pos, forward_list&& other );
 (1) (C++11 起)
void splice_after( const_iterator pos, forward_list& other,
const_iterator it );
 (2) (C++11 起)
void splice_after( const_iterator pos, forward_list&& other,
const_iterator it );
 (2) (C++11 起)
void splice_after( const_iterator pos, forward_list& other,
const_iterator first, const_iterator last );
 (3) (C++11 起)
void splice_after( const_iterator pos, forward_list&& other,
const_iterator first, const_iterator last );
 (3) (C++11 起)

从另一 forward_list 移动元素到 *this 。

不复制元素。 pos 必须是指向 *this 中的可解引用迭代器或 before_begin() 迭代器（特别是 end() 不是 pos 的合法参数值）。若 get_allocator() != other.get_allocator() 则行为未定义。没有迭代器或引用被非法化，指向被移动的元素的迭代器现在指代到 *this 中，而非 other 中。

1) 从 other 移动所有元素到 *this 。元素被插入到 pos 所指向的元素后。操作后 other 变为空。若 other 与 *this 指代同一对象则行为未定义。
2) 从 other 移动后随 it 的迭代器所指向的元素到 *this 。元素被插入到 pos 所指向的元素后，若 pos == it 或若 pos == ++it 则无效果。
3) 从 other 移动范围 (first, last) 中的元素到 *this 。元素被插入到 pos 所指向的元素后。不移动 first 所指向的元素。若 pos 是范围 (first,last) 中的元素则行为未定义。

参数

pos | - | 指向将插入内容到其后的元素的迭代器
other | - | 移动内容来源的另一容器
it | - | 指向从 other 移动到 *this 的元素的迭代器的前趋迭代器
first, last | - | 从 other 移动到 *this 的元素范围

返回值

（无）

异常

不抛出。

复杂度

1) 与 other 的大小成线性
2) 常数
3) 与 std::distance (first, last) 成线性

示例

演示 splice_after() 第三种形式中开区间 (first, last) 的含义：不移动 l1 的首元素。

#include <iostream>
#include <forward_list>

int main()
{
    std::forward_list<int> l1 = {1, 2, 3, 4, 5};
    std::forward_list<int> l2 = {10, 11, 12};

    l2.splice_after(l2.cbegin(), l1, l1.cbegin(), l1.cend());
    // 不等价于 l2.splice_after(l2.cbegin(), l1);

    for (int n : l1)
        std::cout << n << ' ';
    std::cout << '\n';

    for (int n : l2)
        std::cout << n << ' ';
    std::cout << '\n';
}

输出：

1
10 2 3 4 5 11 12

参阅

merge (C++11) | 合并二个已排序列表 (公开成员函数)
removeremove_if (C++11) | 移除满足特定标准的元素 (公开成员函数)


std::forward_list<T,Allocator>::swap

< cpp‎ | container‎ | forward list

void swap( forward_list& other ); | (C++11 起) (C++17 前)
void swap( forward_list& other ) noexcept(/* see below */); | (C++17 起)

将内容与 other 的交换。不在单独的元素上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。在操作后，保有此容器中尾后值的迭代器指代此容器或另一容器是未指定的。

若 std::allocator_traits <allocator_type>::propagate_on_container_swap::value 为 true ，则用对非成员 swap 的无限定调用交换分配器。否则，不交换它们（且若 get_allocator() != other.get_allocator() ，则行为未定义）。

 (C++11 起)

参数

other - 要与之交换内容的容器

返回值

（无）

异常

（无） | (C++17 前)
noexcept 说明： noexcept( std::allocator_traits <Allocator>::is_always_equal::value) | (C++17 起)

复杂度

常数。

示例

#include <iostream>
#include <forward_list>

template<class Os, class Co> Os& operator<<(Os& os, const Co& co) {
    os << "{";
    for (auto const& i : co) { os << ' ' << i; }
    return os << " } ";
}

int main()
{
    std::forward_list<int> a1{1, 2, 3}, a2{4, 5};

    auto it1 = std::next(a1.begin());
    auto it2 = std::next(a2.begin());

    int& ref1 = a1.front();
    int& ref2 = a2.front();

    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';
    a1.swap(a2);
    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';

    // 注意交换后迭代器与引用保持与其原来的元素关联，例如指向 'a1' 中值为 2 的元素的 it1 仍指向同一元素，
    // 尽管此元素被移动到 'a2' 中。
}

输出：

{ 1 2 3 } { 4 5 } 2 5 1 4
{ 4 5 } { 1 2 3 } 2 5 1 4

参阅

std::swap(std::forward_list)
(C++11)
 特化 std::swap 算法
(函数模板)


std::swap(std::forward_list)

< cpp‎ | container‎ | forward list

定义于头文件 <forward_list>
template< class T, class Alloc >

void swap( std::forward_list <T,Alloc>& lhs,

std::forward_list <T,Alloc>& rhs );
 (C++11 起)
(C++17 前)
template< class T, class Alloc >

void swap( std::forward_list <T,Alloc>& lhs,

std::forward_list <T,Alloc>& rhs ) noexcept(/* see below */);
 (C++17 起)

为 std::forward_list 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

#include <algorithm>
#include <iostream>
#include <forward_list>

int main()
{
    std::forward_list<int> alice{1, 2, 3};
    std::forward_list<int> bob{7, 8, 9, 10};

    auto print = [](const int& n) { std::cout << " " << n; };

    // 打印交换前的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';

    std::cout << "-- SWAP\n";
    std::swap(alice,bob);

    // 打印交换后的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
}

输出：

alice: 1 2 3
bob  : 7 8 9 10
-- SWAP
alice: 7 8 9 10
bob  : 1 2 3

参阅

swap
(C++11)
 交换内容
(公开成员函数)


std::forward_list<T,Allocator>::unique

< cpp‎ | container‎ | forward list

 | (1)
void unique(); |  | (C++11 起) (C++20 前)
size_type unique(); |  | (C++20 起)
 | (2)
template< class BinaryPredicate > void unique( BinaryPredicate p ); |  | (C++11 起) (C++20 前)
template< class BinaryPredicate > size_type unique( BinaryPredicate p ); |  | (C++20 起)

从容器移除所有相继的重复元素。只留下相等元素组中的第一个元素。若选择的比较器不建立等价关系则行为未定义。

1) 用 operator== 比较元素。
2) 用二元谓词 p 比较元素。

参数

p - 若元素应被当做相等则返回 ​true 的二元谓词。

谓词函数的签名应等价于如下：

bool pred(const Type1 &a, const Type2 &b);

虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。
类型 Type1 与 Type2 必须使得 forward_list<T,Allocator>::const_iterator 类型的对象能在解引用后隐式转换到这两个类型。 ​

返回值

（无） | (C++20 前)
移除的元素数。 | (C++20 起)

复杂度

若容器非空则准确比较元素 std::distance (begin(), end()) - 1 次。否则不进行比较。

示例

#include <iostream>
#include <forward_list>

auto print = [](auto remark, auto const& container) {
  std::cout << remark;
  for (auto const& val : container)
    std::cout << ' ' << val;
  std::cout << '\n';
};

int main()
{
  std::forward_list<int> c = {1, 2, 2, 3, 3, 2, 1, 1, 2};
  print("Before unique():", c);
  c.unique();
  print("After  unique():", c);

  c = {1, 2, 12, 23, 3, 2, 51, 1, 2};
  print("Before unique(pred):", c);
  c.unique([mod=10](int x, int y) { return (x % mod) == (y % mod); });
  print("After  unique(pred):", c);
}

输出：

Before unique(): 1 2 2 3 3 2 1 1 2
After  unique(): 1 2 3 2 1 2
Before unique(pred): 1 2 12 23 3 2 51 1 2
After  unique(pred): 1 2 23 2 51 2

参阅

unique
 移除范围内的连续重复元素
(函数模板)


std::forward_list<T,Allocator>::~forward_list

< cpp‎ | container‎ | forward list

~forward_list(); | (C++11 起)

销毁 forward_list 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 forward_list 大小成线性。


std::list

< cpp‎ | container
定义于头文件 <list>
template<

class T,
class Allocator = std::allocator <T>

> class list;
 (1)
namespace pmr {

template <class T>
using list = std::list<T, std::pmr::polymorphic_allocator <T>>;

}
 (2) (C++17 起)

std::list 是支持常数时间从容器任何位置插入和移除元素的容器。不支持快速随机访问。它通常实现为双向链表。与 std::forward_list 相比，此容器提供双向迭代但在空间上效率稍低。

在 list 内或在数个 list 间添加、移除和移动元素不会非法化迭代器或引用。迭代器仅在对应元素被删除时非法化。

std::list 满足容器 (Container) 、知分配器容器 (AllocatorAwareContainer) 、序列容器 (SequenceContainer) 及可逆容器 (ReversibleContainer) 的要求。

模板参数

T - 元素的类型。
T 必须满足可复制赋值 (CopyAssignable) 和可复制构造 (CopyConstructible) 的要求。 | (C++11 前)
加诸元素的要求依赖于容器上进行的实际操作。泛言之，要求元素类型是完整类型并满足可擦除 (Erasable) 的要求，但许多成员函数附带了更严格的要求。 | (C++11 起) (C++17 前)
加诸元素的要求依赖于容器上进行的实际操作。泛言之，要求元素类型满足可擦除 (Erasable) 的要求，但许多成员函数附带了更严格的要求。若分配器满足分配器完整性要求，则容器（但非其成员）能以不完整元素类型实例化。 | (C++17 起)
Allocator - 用于获取/释放内存及构造/析构内存中元素的分配器。类型必须满足分配器 (Allocator) 的要求。若 Allocator::value_type 与 T 不同则行为未定义 (C++20 前)程序非良构 (C++20 起)。

成员类型

成员类型 | 定义
value_type | T
allocator_type | Allocator
size_type | 无符号整数类型（通常是 std::size_t ）
difference_type | 有符号整数类型（通常是 std::ptrdiff_t ）
reference | value_type&
const_reference | const value_type&
pointer
Allocator::pointer | (C++11 前)
std::allocator_traits <Allocator>::pointer | (C++11 起)
const_pointer
Allocator::const_pointer | (C++11 前)
std::allocator_traits <Allocator>::const_pointer | (C++11 起)
iterator | 指向 value_type 的老式双向迭代器 (LegacyBidirectionalIterator)
const_iterator | 指向 const value_type 的老式双向迭代器 (LegacyBidirectionalIterator)
reverse_iterator | std::reverse_iterator <iterator>
const_reverse_iterator | std::reverse_iterator <const_iterator>

成员函数

(构造函数)
 构造 list
(公开成员函数)
(析构函数)
 析构 list
(公开成员函数)
operator=
 赋值给容器
(公开成员函数)
assign
 将值赋给容器
(公开成员函数)
get_allocator
 返回相关的分配器
(公开成员函数)
元素访问
front
 访问第一个元素
(公开成员函数)
back
 访问最后一个元素
(公开成员函数)
迭代器
begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)
rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)
rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)
容量
empty
 检查容器是否为空
(公开成员函数)
size
 返回容纳的元素数
(公开成员函数)
max_size
 返回可容纳的最大元素数
(公开成员函数)
修改器
clear
 清除内容
(公开成员函数)
insert
 插入元素
(公开成员函数)
emplace
(C++11)
 原位构造元素
(公开成员函数)
erase
 擦除元素
(公开成员函数)
push_back
 将元素添加到容器末尾
(公开成员函数)
emplace_back
(C++11)
 在容器末尾就地构造元素
(公开成员函数)
pop_back
 移除末元素
(公开成员函数)
push_front
 插入元素到容器起始
(公开成员函数)
emplace_front
(C++11)
 在容器头部原位构造元素
(公开成员函数)
pop_front
 移除首元素
(公开成员函数)
resize
 改变容器中可存储元素的个数
(公开成员函数)
swap
 交换内容
(公开成员函数)
操作
merge
 合并二个已排序列表
(公开成员函数)
splice
 从另一个list中移动元素
(公开成员函数)
removeremove_if
 移除满足特定标准的元素
(公开成员函数)
reverse
 将该链表的所有元素的顺序反转
(公开成员函数)
unique
 删除连续的重复元素
(公开成员函数)
sort
 对元素进行排序
(公开成员函数)

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 按照字典顺序比较 list 中的值 (函数模板)
std::swap(std::list) | 特化 std::swap 算法 (函数模板)
erase(std::list)erase_if(std::list) (C++20) | 擦除所有满足特定判别标准的元素 (函数模板)

推导指引 (C++17 起)

示例

#include <algorithm>
#include <iostream>
#include <list>

int main()
{
    // 创建含整数的 list
    std::list<int> l = { 7, 5, 16, 8 };

    // 添加整数到 list 开头
    l.push_front(25);
    // 添加整数到 list 结尾
    l.push_back(13);

    // 以搜索插入 16 前的值
    auto it = std::find(l.begin(), l.end(), 16);
    if (it != l.end()) {
        l.insert(it, 42);
    }

    // 迭代并打印 list 的值
    for (int n : l) {
        std::cout << n << '\n';
    }
}

输出：

25
7
5
42
16
8
13


std::list<T,Allocator>::assign

< cpp‎ | container‎ | list

void assign( size_type count, const T& value ); | (1) |
template< class InputIt > void assign( InputIt first, InputIt last ); | (2) |
void assign( std::initializer_list <T> ilist ); | (3) | (C++11 起)

替换容器的内容。

1) 以 count 份 value 的副本替换内容。
2) 以范围 [first, last) 中元素的副本替换内容。若任一参数是指向 *this 中的迭代器则行为未定义。
若 InputIt 为整数类型，则此重载与 (1) 拥有相同效果。 | (C++11 前)
此重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 才参与重载决议。 | (C++11 起)
3) 以来自 initializer_list ilist 的元素替换内容。

所有指向容器元素的迭代器、指针及引用均被非法化。

参数

count | - | 容器的新大小
value | - | 用以初始化容器元素的值
first, last | - | 复制来源元素的范围
ilist | - | 复制值来源的 initializer_list

复杂度

1) 与 count 成线性
2) 与 first 和 last 间的距离成线性
3) 与 ilist.size() 成线性

示例

下列代码用 assign 添加数个字符到 std::list <char> ：

#include <list>
#include <iostream>

int main()
{
    std::list<char> characters;

    characters.assign(5, 'a');

    for (char c : characters) {
        std::cout << c << ' ';
    }

    characters.assign({'\n', 'C', '+', '+', '1', '1', '\n'});

    for (char c : characters) {
        std::cout << c;
    }
}

输出：

a a a a a
C++11

参阅

(构造函数)
 构造 list
(公开成员函数)


std::list<T,Allocator>::back

< cpp‎ | container‎ | list

reference back();
const_reference back() const;

返回到容器中最后一个元素的引用。

在空容器上调用 back 导致未定义行为。

参数

（无）

返回值

到最后元素的引用。

复杂度

常数。

注解

对于非空容器 c ，表达式 c.back() 等价于 * std::prev (c.end()) 。

示例

下列代码用 back 显示 std::list <char> 的最后一个元素：

#include <list>
#include <iostream>

int main()
{
    std::list<char> letters {'o', 'm', 'g', 'w', 't', 'f'};
    if (!letters.empty()) {
        std::cout << "The last character is: " << letters.back() << '\n';
    }
}

输出：

The last character is f

参阅

front
 访问第一个元素
(公开成员函数)


std::list<T,Allocator>::begin, std::list<T,Allocator>::cbegin

< cpp‎ | container‎ | list

iterator begin(); | (C++11 前)
iterator begin() noexcept; | (C++11 起)
const_iterator begin() const; | (C++11 前)
const_iterator begin() const noexcept; | (C++11 起)
const_iterator cbegin() const noexcept; | (C++11 起)

返回指向 list 首元素的迭代器。

若 list 为空，则返回的迭代器将等于 end() 。

参数

（无）

返回值

指向首元素的迭代器。

复杂度

常数。

示例

#include <iostream>
#include <numeric>
#include <list>
#include <string>

int main()
{
        std::list<int> nums {1, 2, 4, 8, 16};
        std::list<std::string> fruits {"orange", "apple", "raspberry"};
        std::list<char> empty;

        // 求和 list nums 中的所有整数（若存在），仅打印结果。
        std::cout << "Sum of nums: " <<
                std::accumulate(nums.begin(), nums.end(), 0) << "\n";

        // 打印 list fruits 中的首个 fruis ，不检查是否有一个。
        std::cout << "First fruit: " << *fruits.begin() << "\n";

        if (empty.begin() == empty.end())
                std::cout << "list 'empty' is indeed empty.\n";
}

输出：

Sum of nums: 31
First fruit: orange
list 'empty' is indeed empty.

参阅

end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)


std::list<T,Allocator>::clear

< cpp‎ | container‎ | list

void clear(); | (C++11 前)
void clear() noexcept; | (C++11 起)

从容器擦除所有元素。此调用后 size() 返回零。

非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器保持合法。

参数

（无）

返回值

（无）

复杂度

与容器大小，即元素数成线性。

示例

#include <algorithm>
#include <iostream>
#include <list>

int main()
{
    std::list<int> container{1, 2, 3};

    auto print = [](const int& n) { std::cout << " " << n; };

    std::cout << "Before clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';

    std::cout << "Clear\n";
    container.clear();

    std::cout << "After clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';
}

输出：

Before clear: 1 2 3
Size=3
Clear
After clear:
Size=0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2231 | C++11 | C++11 中错误地省略了复杂度保证 | 重申复杂度为线性

参阅

erase
 擦除元素
(公开成员函数)


std::list 的推导指引

< cpp‎ | container‎ | list

定义于头文件 <list>
template< class InputIt,

class Alloc = std::allocator <typename std::iterator_traits <InputIt>::value_type>>
list(InputIt, InputIt, Alloc = Alloc())

-> list<typename std::iterator_traits <InputIt>::value_type, Alloc>;
 (C++17 起)

为 list 提供此推导指引，以允许从迭代器范围推导。此重载仅若InputIt 满足老式输入迭代器 (LegacyInputIterator) 且 Alloc 满足分配器 (Allocator) 才参与重载决议

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

示例

#include <list>
#include <vector>
int main() {
   std::vector<int> v = {1, 2, 3, 4};

   // 使用显式推导指引推导 std::list<int>
   std::list x(v.begin(), v.end());

   // 推导 std::list<std::vector<int>::iterator>
   // 列表初始化的重载决议第一阶段选择从 initializer_list 构造函数合成的候选
   // 不进行第二阶段且推导指引无效果
   std::list y{v.begin(), v.end()};
}


std::list<T,Allocator>::emplace

< cpp‎ | container‎ | list

template< class... Args > iterator emplace( const_iterator pos, Args&&... args ); | (C++11 起)

直接于 pos 前插入元素到容器中。

通过 std::allocator_traits::construct 构造元素，用布置 new 在容器提供的位置原位构造元素。

将参数 args... 作为 std::forward <Args>(args)... 转发给构造函数。 args... 可以直接或间接地指代容器中的值。

没有引用和迭代器被非法化。

参数

pos | - | 将构造新元素到其前的迭代器
args | - | 转发给元素构造函数的参数
类型要求
- T （容器元素类型） 必须满足可就位构造 (EmplaceConstructible) 的要求。

返回值

指向被安置的元素的迭代器。

复杂度

常数。

异常

若抛异常（例如由构造函数），则保留容器不修改，如同未曾调用过此函数（强异常保证）。

示例

#include <iostream>
#include <string>
#include <list>

struct A {
    std::string s;
    A(std::string str) : s(std::move(str))  { std::cout << " constructed\n"; }
    A(const A& o) : s(o.s) { std::cout << " copy constructed\n"; }
    A(A&& o) : s(std::move(o.s)) { std::cout << " move constructed\n"; }
    A& operator=(const A& other) {
        s = other.s;
        std::cout << " copy assigned\n";
        return *this;
    }
    A& operator=(A&& other) {
        s = std::move(other.s);
        std::cout << " move assigned\n";
        return *this;
    }
};

int main()
{
    std::list<A> container;

    std::cout << "construct 2 times A:\n";
    A two { "two" };
    A three { "three" };

    std::cout << "emplace:\n";
    container.emplace(container.end(), "one");

    std::cout << "emplace with A&:\n";
    container.emplace(container.end(), two);

    std::cout << "emplace with A&&:\n";
    container.emplace(container.end(), std::move(three));

    std::cout << "content:\n";
    for (const auto& obj : container)
        std::cout << ' ' << obj.s;
    std::cout << '\n';
}

输出：

construct 2 times A:
 constructed
 constructed
emplace:
 constructed
emplace with A&:
 copy constructed
emplace with A&&:
 move constructed
content vec:
 one two three

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2164 | C++11 | 不清楚参数是否能指代容器 | 已澄清

参阅

insert
 插入元素
(公开成员函数)


std::list<T,Allocator>::emplace_back

< cpp‎ | container‎ | list

template< class... Args > void emplace_back( Args&&... args ); | (C++11 起) (C++17 前)
template< class... Args > reference emplace_back( Args&&... args ); | (C++17 起)

添加新元素到容器尾。元素通过 std::allocator_traits::construct 构造，它典型地用布置 new 于容器所提供的位置原位构造元素。参数 args... 以 std::forward <Args>(args)... 转发到构造函数。

没有引用和迭代器被非法化。

参数

args - 转发到元素构造函数的参数
类型要求
-
value_type 必须满足可就位构造 (EmplaceConstructible) 的要求。

返回值

（无） | (C++17 前)
到被插入元素的引用。 | (C++17 起)

复杂度

常数。

异常

若抛出异常，则此函数无效果（强异常保证）。

示例

下列代码用 emplace_back 后附 President 类型对象到 std::list 。它演示 emplace_back 如何转发参数到 President 的构造函数，并展示如何用 emplace_back 避免用 push_back 时的额外复制或移动操作。

#include <list>
#include <string>
#include <iostream>

struct President
{
    std::string name;
    std::string country;
    int year;

    President(std::string p_name, std::string p_country, int p_year)
        : name(std::move(p_name)), country(std::move(p_country)), year(p_year)
    {
        std::cout << "I am being constructed.\n";
    }
    President(President&& other)
        : name(std::move(other.name)), country(std::move(other.country)), year(other.year)
    {
        std::cout << "I am being moved.\n";
    }
    President& operator=(const President& other) = default;
};

int main()
{
    std::list<President> elections;
    std::cout << "emplace_back:\n";
    elections.emplace_back("Nelson Mandela", "South Africa", 1994);

    std::list<President> reElections;
    std::cout << "\npush_back:\n";
    reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));

    std::cout << "\nContents:\n";
    for (President const& president: elections) {
        std::cout << president.name << " was elected president of "
                  << president.country << " in " << president.year << ".\n";
    }
    for (President const& president: reElections) {
        std::cout << president.name << " was re-elected president of "
                  << president.country << " in " << president.year << ".\n";
    }
}

输出：

emplace_back:
I am being constructed.

push_back:
I am being constructed.
I am being moved.

Contents:
Nelson Mandela was elected president of South Africa in 1994.
Franklin Delano Roosevelt was re-elected president of the USA in 1936.

参阅

push_back
 将元素添加到容器末尾
(公开成员函数)


std::list<T,Allocator>::emplace_front

< cpp‎ | container‎ | list

template< class... Args > void emplace_front( Args&&... args ); | (C++11 起) (C++17 前)
template< class... Args > reference emplace_front( Args&&... args ); | (C++17 起)

插入新元素到容器起始。通过 std::allocator_traits::construct 构造元素，它典型地用布置 new 在容器所提供的位置原位构造元素。将参数 args... 作为 std::forward <Args>(args)... 转发给构造函数。

没有引用和迭代器被非法化。

参数

args - 转发给元素构造函数的参数
类型要求
-
T （容器元素类型） 必须满足可就位构造 (EmplaceConstructible) 的要求。

返回值

（无） | (C++17 前)
到被插入元素的引用。 | (C++17 起)

复杂度

常数。

异常

若抛异常，则此函数无效果（强异常保证）。

参阅

push_front
 插入元素到容器起始
(公开成员函数)


std::list<T,Allocator>::empty

< cpp‎ | container‎ | list

bool empty() const; | (C++11 前)
bool empty() const noexcept; | (C++11 起) (C++20 前)
[[nodiscard]] bool empty() const noexcept; | (C++20 起)

检查容器是否无元素，即是否 begin() == end() 。

参数

（无）

返回值

若容器为空则为 true ，否则为 false

复杂度

常数。

示例

下列代码用 empty 检查 std::list <int> 是否含有任何元素：

#include <list>
#include <iostream>

int main()
{
    std::list<int> numbers;
    std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';

    numbers.push_back(42);
    numbers.push_back(13317);
    std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
}

输出：

Initially, numbers.empty(): 1
After adding elements, numbers.empty(): 0

参阅

size
 返回容纳的元素数
(公开成员函数)


std::list<T,Allocator>::end, std::list<T,Allocator>::cend

< cpp‎ | container‎ | list

iterator end(); | (C++11 前)
iterator end() noexcept; | (C++11 起)
const_iterator end() const; | (C++11 前)
const_iterator end() const noexcept; | (C++11 起)
const_iterator cend() const noexcept; | (C++11 起)

返回指向 list 末元素后一元素的迭代器。

此元素表现为占位符；试图访问它导致未定义行为。

参数

（无）

返回值

指向后随最后元素的迭代器。

复杂度

常数。

示例

#include <iostream>
#include <numeric>
#include <list>
#include <string>

int main()
{
        std::list<int> nums {1, 2, 4, 8, 16};
        std::list<std::string> fruits {"orange", "apple", "raspberry"};
        std::list<char> empty;

        // 求和 list nums 中的所有整数（若存在），仅打印结果。
        std::cout << "Sum of nums: " <<
                std::accumulate(nums.begin(), nums.end(), 0) << "\n";

        // 打印 list fruits 中的首个 fruis ，不检查是否有一个。
        std::cout << "First fruit: " << *fruits.begin() << "\n";

        if (empty.begin() == empty.end())
                std::cout << "list 'empty' is indeed empty.\n";
}

输出：

Sum of nums: 31
First fruit: orange
list 'empty' is indeed empty.

参阅

begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)


std::list<T,Allocator>::erase

< cpp‎ | container‎ | list

 | (1)
iterator erase( iterator pos ); |  | (C++11 前)
iterator erase( const_iterator pos ); |  | (C++11 起)
 | (2)
iterator erase( iterator first, iterator last ); |  | (C++11 前)
iterator erase( const_iterator first, const_iterator last ); |  | (C++11 起)

从容器擦除指定的元素。

1) 移除位于 pos 的元素。
2) 移除范围 [first; last) 中的元素。

指向被擦除元素的迭代器和引用被非法化。其他引用和迭代器不受影响。

迭代器 pos 必须合法且可解引用。从而不能以 end() 迭代器（合法，但不可解引用）为 pos 的值。

若 first==last 则迭代器 first 不必可解引用：擦除空范围是无操作。

参数

pos | - | 指向要移除的元素的迭代器
first, last | - | 要移除的元素范围

返回值

后随最后移除元素的迭代器。

若 pos 指代末元素，则返回 end() 迭代器。

若在移除前 last == end() ，则返回更新的 end() 迭代器。

若 [first, last) 为空范围，则返回 last 。

异常

（无）

复杂度

1) 常数。
2) 与 first 和 last 间的距离成线性。

示例

#include <list>
#include <iostream>
#include <iterator>

int main( )
{
    std::list<int> c{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    for (auto &i : c) {
        std::cout << i << " ";
    }
    std::cout << '\n';

    c.erase(c.begin());

    for (auto &i : c) {
        std::cout << i << " ";
    }
    std::cout << '\n';

    std::list<int>::iterator range_begin = c.begin();
    std::list<int>::iterator range_end = c.begin();
    std::advance(range_begin,2);
    std::advance(range_end,5);

    c.erase(range_begin, range_end);

    for (auto &i : c) {
        std::cout << i << " ";
    }
    std::cout << '\n';
}

输出：

0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 6 7 8 9

参阅

clear
 清除内容
(公开成员函数)


std::erase, std::erase_if (std::list)

< cpp‎ | container‎ | list

定义于头文件 <list>
template< class T, class Alloc, class U >

typename std::list <T,Alloc>::size_type

erase( std::list <T,Alloc>& c, const U& value);
 (1) (C++20 起)
template< class T, class Alloc, class Pred >

typename std::list <T,Alloc>::size_type

erase_if( std::list <T,Alloc>& c, Pred pred);
 (2) (C++20 起)
1) 从容器中擦除所有比较等于 value 的元素。等价于 return c.remove_if([&](auto& elem) { return elem == value; }); 。
2) 从容器中擦除所有满足 pred 的元素。等价于 return c.remove_if(pred); 。

参数

c | - | 要从中擦除的容器
value | - | 要擦除的值
pred | - | 若应该擦除元素则返回 ​true 的一元谓词。 对每个（可为 const 的） T 类型参数 v ，表达式 pred(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 T& 类型参数，亦不允许 T ，除非对 T 而言移动等价于复制 (C++11 起)。 ​

返回值

被擦除的元素数。

复杂度

线性。

示例

#include <iostream>
#include <numeric>
#include <list>

void print_container(const std::list<char>& c)
{
    for (auto x : c) {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    std::list<char> cnt(10);
    std::iota(cnt.begin(), cnt.end(), '0');

    std::cout << "Init:\n";
    print_container(cnt);

    auto erased = std::erase(cnt, '3');
    std::cout << "Erase \'3\':\n";
    print_container(cnt);

    std::erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; });
    std::cout << "Erase all even numbers:\n";
    print_container(cnt);
    std::cout << "In all " << erased << " even numbers were erased.\n";
}

输出：

Init:
0 1 2 3 4 5 6 7 8 9
Erase '3':
0 1 2 4 5 6 7 8 9
Erase all even numbers:
1 5 7 9
In all 5 even numbers were erased.

注解

不同于 std::list::remove ， erase 接受异种类型并且不强制在调用 == 运算符前转换到容器的值类型。

参阅

removeremove_if | 移除满足特定判别标准的元素 (函数模板)
removeremove_if | 移除满足特定标准的元素 (公开成员函数)


std::list<T,Allocator>::front

< cpp‎ | container‎ | list

reference front();
const_reference front() const;

返回到容器首元素的引用。

在空容器上对 front 的调用是未定义的。

参数

（无）

返回值

到首元素的引用

复杂度

常数

注解

对于容器 c ，表达式 c.front() 等价于 *c.begin() 。

示例

下列代码用 front 显示 std::list <char> 的首元素：

#include <list>
#include <iostream>

int main()
{
    std::list<char> letters {'o', 'm', 'g', 'w', 't', 'f'};

    if (!letters.empty()) {
        std::cout << "The first character is: " << letters.front() << '\n';
    }
}

输出：

The first character is o

参阅

back
 访问最后一个元素
(公开成员函数)


std::list<T,Allocator>::get_allocator

< cpp‎ | container‎ | list

allocator_type get_allocator() const; | (C++11 前)
allocator_type get_allocator() const noexcept; | (C++11 起)

返回与容器关联的分配器。

参数

（无）

返回值

关联的分配器。

复杂度

常数。


std::list<T,Allocator>::insert

< cpp‎ | container‎ | list

 | (1) |
iterator insert( iterator pos, const T& value ); |  |  | (C++11 前)
iterator insert( const_iterator pos, const T& value ); |  |  | (C++11 起)
iterator insert( const_iterator pos, T&& value ); | (2) | (C++11 起)
 | (3) |
void insert( iterator pos, size_type count, const T& value ); |  |  | (C++11 前)
iterator insert( const_iterator pos, size_type count, const T& value ); |  |  | (C++11 起)
 | (4) |
template< class InputIt > void insert( iterator pos, InputIt first, InputIt last); |  |  | (C++11 前)
template< class InputIt > iterator insert( const_iterator pos, InputIt first, InputIt last ); |  |  | (C++11 起)
iterator insert( const_iterator pos, std::initializer_list <T> ilist ); | (5) | (C++11 起)

插入元素到容器中的指定位置。

1-2) 在 pos 前插入 value 。
3) 在 pos 前插入 value 的 count 个副本。
4) 在 pos 前插入来自范围 [first, last) 的元素。
若 InputIt 为整数类型，则此重载与重载 (3) 拥有相同效果。 | (C++11 前)
此重载仅若 InputIt 足以为老式输入迭代器 (LegacyInputIterator) 才参与重载决议，以避免与重载 (3) 有歧义。 | (C++11 起)
若 first 和 last 是指向 *this 中的迭代器，则行为未定义。
5) 在 pos 前插入来自 initializer_list ilist 的元素。

没有引用和迭代器被非法化。

参数

pos | - | 将内容插入到其前的迭代器。 pos 可为 end() 迭代器
value | - | 要插入的元素值
first, last | - | 要插入的元素范围，不能是指向调用 insert 所用的容器中的迭代器
ilist | - | 要插入的值来源的 initializer_list
类型要求
- 为使用重载 (1) ， T 必须满足可复制插入 (CopyInsertable) 的要求。
- 为使用重载 (2) ， T 必须满足可移动插入 (MoveInsertable) 的要求。
- 为使用重载 (3) ， T 必须满足可复制赋值 (CopyAssignable) 和 可复制插入 (CopyInsertable) 的要求。
- 为使用重载 (4,5) ， T 必须满足可就位构造 (EmplaceConstructible) 的要求。

返回值

1-2) 指向被插入 value 的迭代器。
3) 指向首个被插入元素的迭代器，或若 count==0 则为 pos 。
4) 指向首个被插入元素的迭代器，或若 first==last 则为 pos 。
5) 指向首个被插入元素的迭代器，或若 ilist 为空则为 pos 。

复杂度

1-2) 常数。
3) 与 count 成线性。
4) 与 std::distance (first, last) 成线性。
5) 与 ilist.size() 成线性。

异常

若抛出异常，则无效果（强异常保证）。

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
push_front | 插入元素到容器起始 (公开成员函数)
push_back | 将元素添加到容器末尾 (公开成员函数)


std::list<T,Allocator>::list

< cpp‎ | container‎ | list

list();
 (1)
explicit list( const Allocator& alloc );
 (2)
(3)
explicit list( size_type count,

const T& value = T(),

const Allocator& alloc = Allocator());
 (C++11 前)
list( size_type count,

const T& value,

const Allocator& alloc = Allocator());
 (C++11 起)
(4)
explicit list( size_type count );
 (C++11 起)
(C++14 前)
explicit list( size_type count, const Allocator& alloc = Allocator() );
 (C++14 起)
template< class InputIt >

list( InputIt first, InputIt last,

const Allocator& alloc = Allocator() );
 (5)
list( const list& other );
 (6)
list( const list& other, const Allocator& alloc );
 (7) (C++11 起)
list( list&& other );
 (8) (C++11 起)
list( list&& other, const Allocator& alloc );
 (9) (C++11 起)
list( std::initializer_list <T> init,
const Allocator& alloc = Allocator() );
 (10) (C++11 起)

从各种数据源构造新容器，可选地使用用户提供的分配器 alloc 。

1) 默认构造函数。构造拥有默认构造的分配器的空容器。
2) 构造拥有给定分配器 alloc 的空容器。
3) 构造拥有 count 个有值 value 的元素的容器。
4) 构造拥有个 count 默认插入的 T 实例的容器。不进行复制。
5) 构造拥有范围 [first, last) 内容的容器。
若 InputIt 是整数类型，则此构造函数拥有的效果同 list(static_cast<size_type>(first), static_cast<value_type>(last), a) 。 | (C++11 前)
此重载仅若InputIt 满足老式输入迭代器 (LegacyInputIterator) 才参与重载决议，以避免和重载 (2) 的歧义。 | (C++11 起)
6) 复制构造函数。构造拥有 other 内容的容器。

如同通过调用
std::allocator_traits <allocator_type>::select_on_container_copy_construction(
other.get_allocator())
获得分配器。

 (C++11 起)
7) 构造拥有 other 内容的容器，以 alloc 为分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
8) 移动构造函数。用移动语义构造拥有 other 内容的容器。分配器通过属于 other 的分配器移动构造获得。
9) 有分配器扩展的移动构造函数。以 alloc 为新容器的分配器，从 other 移动内容；若 alloc != other.get_allocator() ，则它导致逐元素移动。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
10) 构造拥有 initializer_list init 内容的容器。

参数

alloc | - | 用于此容器所有内存分配的分配器
count | - | 容器的大小
value | - | 以之初始化容器元素的值
first, last | - | 复制元素的来源范围
other | - | 用作初始化容器元素来源的另一容器
init | - | 用作初始化元素来源的 initializer_list

复杂度

1-2) 常数
3-4) 与 count 成线性
5) 与 first 和 last 的距离成线性
6-7) 与 other 的大小成线性
8) 常数。
9) 若 alloc != other.get_allocator() 则为线性，否则为常数。
10) 与 init 的大小成线性。

异常

调用 Allocator::allocate 可能抛出。

注解

在容器移动构造（重载 (8) ）后，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

#include <list>
#include <string>
#include <iostream>

template<typename T>
std::ostream& operator<<(std::ostream& s, const std::list<T>& v)
{
    s.put('[');
    char comma[3] = {'\0', ' ', '\0'};
    for (const auto& e : v) {
        s << comma << e;
        comma[0] = ',';
    }
    return s << ']';
}

int main()
{
    // C++11 初始化器列表语法：
    std::list<std::string> words1 {"the", "frogurt", "is", "also", "cursed"};
    std::cout << "words1: " << words1 << '\n';

    // words2 == words1
    std::list<std::string> words2(words1.begin(), words1.end());
    std::cout << "words2: " << words2 << '\n';

    // words3 == words1
    std::list<std::string> words3(words1);
    std::cout << "words3: " << words3 << '\n';

    // words4 为 {"Mo", "Mo", "Mo", "Mo", "Mo"}
    std::list<std::string> words4(5, "Mo");
    std::cout << "words4: " << words4 << '\n';
}

输出：

words1: [the, frogurt, is, also, cursed]
words2: [the, frogurt, is, also, cursed]
words3: [the, frogurt, is, also, cursed]
words4: [Mo, Mo, Mo, Mo, Mo]

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2193 | C++11 | 默认构造函数为 explicit | 使之为非 explicit

参阅

assign | 将值赋给容器 (公开成员函数)
operator= | 赋值给容器 (公开成员函数)


std::list<T,Allocator>::max_size

< cpp‎ | container‎ | list

size_type max_size() const; | (C++11 前)
size_type max_size() const noexcept; | (C++11 起)

返回根据系统或库实现限制的容器可保有的元素最大数量，即对于最大容器的 std::distance (begin(), end()) 。

参数

（无）

返回值

元素数量的最大值。

复杂度

常数。

注解

此值通常反映容器大小上的理论极限，至多为 std::numeric_limits <difference_type>::max() 。运行时，可用 RAM 总量可能会限制容器大小到小于 max_size() 的值。

示例

#include <iostream>
#include <list>

int main()
{
    std::list<char> s;
    std::cout << "Maximum size of a 'list' is " << s.max_size() << "\n";
}

可能的输出：

Maximum size of a 'list' is 768614336404564650

参阅

size
 返回容纳的元素数
(公开成员函数)


std::list<T,Allocator>::merge

< cpp‎ | container‎ | list

void merge( list& other ); | (1) |
void merge( list&& other ); | (1) | (C++11 起)
template <class Compare> void merge( list& other, Compare comp ); | (2) |
template <class Compare> void merge( list&& other, Compare comp ); | (2) | (C++11 起)

归并二个已排序链表为一个。链表应以升序排序。

不复制元素。操作后容器 other 变为空。若 other 与 *this 指代同一对象则函数不做任何事。若 get_allocator() != other.get_allocator() ，则行为未定义。没有引用和迭代器变得非法，除了被移动元素的迭代器现在指代到 *this 中，而非到 other 中，第一版本用 operator< 比较元素，第二版本用给定的比较函数 comp 。

此操作是稳定的：对于二个链表中的等价元素，来自 *this 的元素始终前驱来自 other 的元素，而且 *this 和 other 的等价元素顺序不更改。

参数

other - 要交换的另一容器
comp - 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。

比较函数的签名应等价于如下：

bool cmp(const Type1 &a, const Type2 &b);

虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。
类型 Type1 与 Type2 必须使得 list<T,Allocator>::const_iterator 类型的对象能在解引用后隐式转换到这两个类型。 ​

返回值

（无）

异常

若抛出异常，则此函数无效果（强异常保证），除非异常来自比较函数。

复杂度

至多 std::distance (begin(), end()) + std::distance (other.begin(), other.end()) - 1 次比较。

示例

#include <iostream>
#include <list>

std::ostream& operator<<(std::ostream& ostr, const std::list<int>& list)
{
    for (auto &i : list) {
        ostr << " " << i;
    }
    return ostr;
}

int main()
{
    std::list<int> list1 = { 5,9,0,1,3 };
    std::list<int> list2 = { 8,7,2,6,4 };

    list1.sort();
    list2.sort();
    std::cout << "list1:  " << list1 << "\n";
    std::cout << "list2:  " << list2 << "\n";
    list1.merge(list2);
    std::cout << "merged: " << list1 << "\n";
}

输出：

list1:   0 1 3 5 9
list2:   2 4 6 7 8
merged:  0 1 2 3 4 5 6 7 8 9

参阅

splice
 从另一个list中移动元素
(公开成员函数)


std::list<T,Allocator>::operator=

< cpp‎ | container‎ | list

list& operator=( const list& other ); | (1) |
 | (2) |
list& operator=( list&& other ); |  |  | (C++11 起) (C++17 前)
list& operator=( list&& other ) noexcept(/* see below */); |  |  | (C++17 起)
list& operator=( std::initializer_list <T> ilist ); | (3) | (C++11 起)

替换容器内容。

1) 复制赋值运算符。以 other 的副本替换内容。

若 std::allocator_traits <allocator_type>::propagate_on_container_copy_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若 *this 的分配器在赋值后将与其旧值比较不相等，则用旧分配器解分配内存，然后在复制元素前用新分配器分配内存。否则，在可行时可能复用 *this 所拥有的内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素复制赋值替换。

 (C++11 起)
2) 移动赋值运算符。用移动语义以 other 的内容替换内容（即从 other 移动 other 中的数据到此容器中）。之后 other 在合法但未指定的状态。
若 std::allocator_traits <allocator_type>::propagate_on_container_move_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若它为 false 且 *this 与 other 的分配器不比较相等，则 *this 不能接管 other 所拥有的内存的所有权且必须单独地移动赋值每个元素，并用其自身的分配器按需分配额外内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素移动赋值替换。
3) 以 initializer_list ilist 所标识者替换内容。

参数

other | - | 用作数据源的另一容器
ilist | - | 用作数据源的 initializer_list

返回值

*this

复杂度

1) 与 *this 和 other 的大小成线性。
2) 与 *this 的大小成线性，除非分配器不比较相等且不传播，该情况下与 *this 和 other 的大小成线性。
3) 与 *this 和 ilist 的大小成线性。

异常

可能抛出实现定义的异常。 | (C++17 前)
1,3) 可能抛出实现定义的异常。 2) noexcept 说明： noexcept( std::allocator_traits <Allocator>::is_always_equal::value) | (C++17 起)

注解

在容器移动赋值（重载 (2) ）后，除非不兼容的分配器强制逐元素移动赋值，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

下列代码用 operator= 赋值一个 std::list 给另一个：

#include <list>
#include <iostream>

void display_sizes(const std::list<int>& nums1,
                   const std::list<int>& nums2,
                   const std::list<int>& nums3)
{
    std::cout << "nums1: " << nums1.size()
              << " nums2: " << nums2.size()
              << " nums3: " << nums3.size() << '\n';
}

int main()
{
    std::list<int> nums1 {3, 1, 4, 6, 5, 9};
    std::list<int> nums2;
    std::list<int> nums3;

    std::cout << "Initially:\n";
    display_sizes(nums1, nums2, nums3);

    // 复制赋值从 nums1 复制数据到 nums2
    nums2 = nums1;

    std::cout << "After assigment:\n";
    display_sizes(nums1, nums2, nums3);

    // 移动赋值从 nums1 移动数据到 nums3,
    // 一同修改 nums1 和 nums3
    nums3 = std::move(nums1);

    std::cout << "After move assigment:\n";
    display_sizes(nums1, nums2, nums3);
}

输出：

Initially:
nums1: 6 nums2: 0 nums3: 0
After assigment:
nums1: 6 nums2: 6 nums3: 0
After move assigment:
nums1: 0 nums2: 6 nums3: 6

参阅

(构造函数) | 构造 list (公开成员函数)
assign | 将值赋给容器 (公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::list)

< cpp‎ | container‎ | list

定义于头文件 <list>
template< class T, class Alloc >

bool operator==( const std::list <T,Alloc>& lhs,

const std::list <T,Alloc>& rhs );
 (1)
template< class T, class Alloc >

bool operator!=( const std::list <T,Alloc>& lhs,

const std::list <T,Alloc>& rhs );
 (2) (C++20 前)
template< class T, class Alloc >

bool operator<( const std::list <T,Alloc>& lhs,

const std::list <T,Alloc>& rhs );
 (3) (C++20 前)
template< class T, class Alloc >

bool operator<=( const std::list <T,Alloc>& lhs,

const std::list <T,Alloc>& rhs );
 (4) (C++20 前)
template< class T, class Alloc >

bool operator>( const std::list <T,Alloc>& lhs,

const std::list <T,Alloc>& rhs );
 (5) (C++20 前)
template< class T, class Alloc >

bool operator>=( const std::list <T,Alloc>& lhs,

const std::list <T,Alloc>& rhs );
 (6) (C++20 前)
template< class T, class Alloc >

/* see below */ operator<=>( const std::list <T,Alloc>& lhs,

const std::list <T,Alloc>& rhs );
 (7) (C++20 起)

比较二个 list 的内容。

1-2) 检查 lhs 与 rhs 的内容是否相等，即它们是否拥有相同数量的元素且 lhs 中每个元素与 rhs 的同位置元素比较相等。
3-6) 按字典序比较 lhs 与 rhs 的内容。由等价于 std::lexicographical_compare 的函数进行比较。
7) 按字典序比较 lhs 与 rhs 的内容。如同通过在二个 list 上以进行合成三路比较（见后述）的函数对象调用 std::lexicographical_compare_three_way 进行比较。返回类型同合成三路比较的结果类型。

给定分别作为左操作数与右操作数的两个 const E 左值 lhs 与 rhs （其中 E 为 T ），合成三路比较定义如下：

  • 若 std::three_way_comparable_with<E, E> 得到满足则等价于 lhs <=> rhs ；
  • 否则，若以 operator< 比较二个 const E 左值为良构且结果类型满足 boolean-testable ，则等价于
lhs < rhs ? std::weak_ordering::less :
rhs < lhs ? std::weak_ordering::greater :
            std::weak_ordering::equivalent
  • 否则，不定义合成三路比较，而 operator<=> 不参与重载决议。
若 three_way_comparable_with 或 boolean-testable 被满足但未被实现，或使用 operator< 但 E 与 < 不建立全序，则 operator<=> 的行为未定义。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较内容的 list
-
为使用重载 (1-2) ， T 必须满足可相等比较 (EqualityComparable) 的要求。
-
为使用重载 (3-6) ， T 必须满足可小于比较 (LessThanComparable) 的要求。顺序关系必须建立全序。

返回值

1) 若 list 内容相等则为 true ，否则为 false
2) 若 list 内容不相等则为 true ，否则为 false
3) 若 lhs 的内容按字典序小于 rhs 的内容则为 true ，否则为 false
4) 若 lhs 的内容按字典序小于或等于 rhs 的内容则为 true ，否则为 false
5) 若 lhs 的内容按字典序大于 rhs 的内容则为 true ，否则为 false
6) 若 lhs 的内容按字典序大于或等于 rhs 的内容则为 true ，否则为 false
7) lhs 与 rhs 中的首对不等价元素的相对顺序，若有这种元素；否则为 lhs.size() <=> rhs.size() 。

复杂度

1-2) 若 lhs 与 rhs 的大小不同则为常数，否则与 list 大小成线性
3-7) 与 list 大小成线性

示例

#include <iostream>
#include <list>

int main()
{
    std::list<int> alice{1, 2, 3};
    std::list<int> bob{7, 8, 9, 10};
    std::list<int> eve{1, 2, 3};

    std::cout << std::boolalpha;

    // 比较不相等的容器
    std::cout << "alice == bob returns " << (alice == bob) << '\n';
    std::cout << "alice != bob returns " << (alice != bob) << '\n';
    std::cout << "alice <  bob returns " << (alice < bob) << '\n';
    std::cout << "alice <= bob returns " << (alice <= bob) << '\n';
    std::cout << "alice >  bob returns " << (alice > bob) << '\n';
    std::cout << "alice >= bob returns " << (alice >= bob) << '\n';

    std::cout << '\n';

    // 比较相等的容器
    std::cout << "alice == eve returns " << (alice == eve) << '\n';
    std::cout << "alice != eve returns " << (alice != eve) << '\n';
    std::cout << "alice <  eve returns " << (alice < eve) << '\n';
    std::cout << "alice <= eve returns " << (alice <= eve) << '\n';
    std::cout << "alice >  eve returns " << (alice > eve) << '\n';
    std::cout << "alice >= eve returns " << (alice >= eve) << '\n';
}

输出：

alice == bob returns false
alice != bob returns true
alice <  bob returns true
alice <= bob returns true
alice >  bob returns false
alice >= bob returns false

alice == eve returns true
alice != eve returns false
alice <  eve returns false
alice <= eve returns true
alice >  eve returns false
alice >= eve returns true


std::list<T,Allocator>::pop_back

< cpp‎ | container‎ | list

void pop_back();

移除容器的末元素。

在空容器上调用 pop_back 导致未定义行为。

指向被擦除元素的迭代器和引用被非法化。

参数

（无）

返回值

（无）

复杂度

常数。

异常

不抛出。

示例

#include <list>
#include <iostream>

template<class T>
void print(T const & xs)
{
    std::cout << "[ ";
    for(auto && x : xs) {
        std::cout << x << ' ';
    }
    std::cout << "]\n";
}

int main()
{
    std::list<int> numbers;

    print(numbers);

    numbers.push_back(5);
    numbers.push_back(3);
    numbers.push_back(4);

    print(numbers);

    numbers.pop_back();

    print(numbers);
}

输出：

[ ]
[ 5 3 4 ]
[ 5 3 ]

参阅

pop_front | 移除首元素 (公开成员函数)
push_back | 将元素添加到容器末尾 (公开成员函数)


std::list<T,Allocator>::pop_front

< cpp‎ | container‎ | list

void pop_front();

移除容器首元素。若容器中无元素，则行为未定义。

指向被擦除元素的迭代器和引用被非法化。

参数

（无）

返回值

（无）

复杂度

常数。

异常

不抛出。

参阅

pop_back | 移除末元素 (公开成员函数)
push_front | 插入元素到容器起始 (公开成员函数)


std::list<T,Allocator>::push_back

< cpp‎ | container‎ | list

void push_back( const T& value ); | (1) |
void push_back( T&& value ); | (2) | (C++11 起)

后附给定元素 value 到容器尾。

1) 初始化新元素为 value 的副本。
2) 移动 value 进新元素。

没有引用和迭代器被非法化。

参数

value - 要后附的元素值
类型要求
-
为使用重载 (1) ， T 必须满足可复制插入 (CopyInsertable) 的要求。
-
为使用重载 (2) ， T 必须满足可移动插入 (MoveInsertable) 的要求。

返回值

（无）

复杂度

常数。

异常

若抛出异常（可能因为 Allocator::allocate() 或元素复制/移动构造函数/赋值），则此函数无效果（强异常保证）。

示例

#include <list>
#include <iostream>
#include <iomanip>

int main()
{
    std::list<std::string> letters;

    letters.push_back("abc");
    std::string s = "def";
    letters.push_back(std::move(s));

    std::cout << "list holds: ";
    for (auto&& i : letters) std::cout << std::quoted(i) << ' ';
    std::cout << "\nMoved-from string holds " << std::quoted(s) << '\n';
}

输出：

list holds: "abc" "def"
Moved-from string holds ""

参阅

emplace_back (C++11) | 在容器末尾就地构造元素 (公开成员函数)
push_front | 插入元素到容器起始 (公开成员函数)
pop_back | 移除末元素 (公开成员函数)


std::list<T,Allocator>::push_front

< cpp‎ | container‎ | list

void push_front( const T& value ); |
void push_front( T&& value ); | (C++11 起)

前附给定元素 value 到容器起始。

没有引用和迭代器被非法化。

参数

value - 要前附的元素值

返回值

（无）

复杂度

常数。

异常

若抛出异常，则此函数无效果（强异常保证）。

参阅

emplace_front (C++11) | 在容器头部原位构造元素 (公开成员函数)
push_back | 将元素添加到容器末尾 (公开成员函数)
pop_front | 移除首元素 (公开成员函数)


std::list<T,Allocator>::rbegin, std::list<T,Allocator>::crbegin

< cpp‎ | container‎ | list

reverse_iterator rbegin(); | (C++11 前)
reverse_iterator rbegin() noexcept; | (C++11 起)
const_reverse_iterator rbegin() const; | (C++11 前)
const_reverse_iterator rbegin() const noexcept; | (C++11 起)
const_reverse_iterator crbegin() const noexcept; | (C++11 起)

返回指向逆向 list 首元素的逆向迭代器。它对应非逆向 list 的末元素。若 list 为空，则返回的迭代器等于 rend() 。

参数

（无）

返回值

指向首元素的逆向迭代器。

复杂度

常数。

示例

#include <iostream>
#include <numeric>
#include <list>
#include <string>

int main()
{
        std::list<int> nums {1, 2, 4, 8, 16};
        std::list<std::string> fruits {"orange", "apple", "raspberry"};
        std::list<char> empty;

        // 求和 list nums 中的所有整数（若存在），仅打印结果。
        std::cout << "Sum of nums: " <<
                std::accumulate(nums.begin(), nums.end(), 0) << "\n";

        // 打印 list fruits 中的首个 fruis ，不检查是否有一个。
        std::cout << "First fruit: " << *fruits.begin() << "\n";

        if (empty.begin() == empty.end())
                std::cout << "list 'empty' is indeed empty.\n";
}

输出：

Sum of nums: 31
First fruit: orange
list 'empty' is indeed empty.

参阅

rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)


std::list<T,Allocator>::remove, remove_if

< cpp‎ | container‎ | list

void remove( const T& value ); | (C++20 前)
size_type remove( const T& value ); | (C++20 起)
template< class UnaryPredicate > void remove_if( UnaryPredicate p ); | (C++20 前)
template< class UnaryPredicate > size_type remove_if( UnaryPredicate p ); | (C++20 起)

移除所有满足特定标准的元素。第一版本移除所有等于 value 的元素，第二版本移除所有谓词 p 对它返回 true 的元素。

参数

value | - | 要移除的元素的值
p | - | 若应该移除该元素则返回 ​true 的一元谓词。 对每个（可为 const 的） T 类型参数 v ，表达式 p(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 T& 类型参数，亦不允许 T ，除非对 T 而言移动等价于复制 (C++11 起)。 ​

返回值

（无） | (C++20 前)
移除的元素数。 | (C++20 起)

复杂度

与容器大小成线性

示例

#include <list>
#include <iostream>

int main()
{
    std::list<int> l = { 1,100,2,3,10,1,11,-1,12 };

    l.remove(1); // 移除两个等于 1 的元素
    l.remove_if([](int n){ return n > 10; }); // 移除全部大于 10 的元素

    for (int n : l) {
        std::cout << n << ' ';
    }
    std::cout << '\n';
}

输出：

2 3 10 -1

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::list<T,Allocator>::rend, std::list<T,Allocator>::crend

< cpp‎ | container‎ | list

reverse_iterator rend(); | (C++11 前)
reverse_iterator rend() noexcept; | (C++11 起)
const_reverse_iterator rend() const; | (C++11 前)
const_reverse_iterator rend() const noexcept; | (C++11 起)
const_reverse_iterator crend() const noexcept; | (C++11 起)

返回指向逆向 list 末元素后一元素的逆向迭代器。它对应非逆向 list 首元素的前一元素。此元素表现为占位符，试图访问它导致未定义行为。

参数

（无）

返回值

指向末元素后一元素的逆向迭代器。

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)


std::list<T,Allocator>::resize

< cpp‎ | container‎ | list

void resize( size_type count ); | (1) | (C++11 起)
 | (2) |
void resize( size_type count, T value = T() ); |  |  | (C++11 前)
void resize( size_type count, const value_type& value ); |  |  | (C++11 起)

重设容器大小以容纳 count 个元素。

若当前大小大于 count ，则减小容器为其首 count 个元素。

若当前大小小于 count ，

1) 则后附额外的默认插入的元素
2) 则后附额外的 value 的副本

参数

count | - | 容器的大小
value | - | 用以初始化新元素的值
类型要求
- 为使用重载 (1) ， T 必须满足可默认插入 (DefaultInsertable) 的要求。
- 为使用重载 (2) ， T 必须满足可复制插入 (CopyInsertable) 的要求。

返回值

（无）

复杂度

与当前大小和 count 间的差成线性。

注解

若不想要重载 (1) 中的值初始化，例如元素是非类类型且不需要清零，则可以提供定制的 Allocator::construct 避免。

示例

#include <iostream>
#include <list>
int main()
{
    std::list<int> c = {1, 2, 3};
    std::cout << "The list holds: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
    c.resize(5);
    std::cout << "After resize up to 5: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
    c.resize(2);
    std::cout << "After resize down to 2: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
}

输出：

The list holds: 1 2 3
After resize up to 5: 1 2 3 0 0
After resize down to 2: 1 2

参阅

size | 返回容纳的元素数 (公开成员函数)
insert | 插入元素 (公开成员函数)
erase | 擦除元素 (公开成员函数)


std::list<T,Allocator>::reverse

< cpp‎ | container‎ | list

void reverse(); | (C++11 前)
void reverse() noexcept; | (C++11 起)

逆转容器中的元素顺序。不非法化任何引用或迭代器。

参数

（无）

返回值

（无）

复杂度

与容器大小成线性

示例

#include <iostream>
#include <list>

std::ostream& operator<<(std::ostream& ostr, const std::list<int>& list)
{
    for (auto &i : list) {
        ostr << " " << i;
    }
    return ostr;
}

int main()
{
    std::list<int> list = { 8,7,5,9,0,1,3,2,6,4 };

    std::cout << "before:     " << list << "\n";
    list.sort();
    std::cout << "ascending:  " << list << "\n";
    list.reverse();
    std::cout << "descending: " << list << "\n";
}

输出：

before:      8 7 5 9 0 1 3 2 6 4
ascending:   0 1 2 3 4 5 6 7 8 9
descending:  9 8 7 6 5 4 3 2 1 0

参阅

sort
 对元素进行排序
(公开成员函数)


std::list<T,Allocator>::size

< cpp‎ | container‎ | list
size_type size() const; | (C++11 前)
size_type size() const noexcept; | (C++11 起)

返回容器中的元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

容器中的元素数量。

复杂度

常数或线性。 | (C++11 前)
常数。 | (C++11 起)

示例

下列代码用 size 显示 std::list 中的元素数：

#include <list>
#include <iostream>

int main()
{
    std::list<int> nums {1, 3, 5, 7};

    std::cout << "nums contains " << nums.size() << " elements.\n";
}

输出：

nums contains 4 elements.

参阅

empty | 检查容器是否为空 (公开成员函数)
max_size | 返回可容纳的最大元素数 (公开成员函数)
resize | 改变容器中可存储元素的个数 (公开成员函数)


std::list<T,Allocator>::sort

< cpp‎ | container‎ | list

void sort(); | (1)
template< class Compare > void sort( Compare comp ); | (2)

以升序排序元素。保持相等元素的顺序。第一版本用 operator< 比较元素，第二版本用给定的比较函数 comp 。

若抛出异常，则 *this 中元素顺序未指定。

参数

comp - 比较函数对象（即满足比较 (Compare) 概念的对象），若第一参数小于（即先序于）第二参数则返回 ​true 。

比较函数的签名应等价于如下：

bool cmp(const Type1 &a, const Type2 &b);

虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。
类型 Type1 与 Type2 必须使得 list<T,Allocator>::const_iterator 类型的对象能在解引用后隐式转换到这两个类型。 ​

返回值

（无）

复杂度

大约 N log N 次比较，其中 N 是表中的元素数。

注意

std::sort 要求随机访问迭代器且不能用于 list 。此函数与 std::sort 的区别在于，它不要求 list 的元素类型可交换，保留所有迭代器的值，并进行稳定排序。

示例

#include <iostream>
#include <functional>
#include <list>

std::ostream& operator<<(std::ostream& ostr, const std::list<int>& list)
{
    for (auto &i : list) {
        ostr << " " << i;
    }
    return ostr;
}

int main()
{
    std::list<int> list = { 8,7,5,9,0,1,3,2,6,4 };

    std::cout << "before:     " << list << "\n";
    list.sort();
    std::cout << "ascending:  " << list << "\n";
    list.sort(std::greater<int>());
    std::cout << "descending: " << list << "\n";
}

输出：

before:      8 7 5 9 0 1 3 2 6 4
ascending:   0 1 2 3 4 5 6 7 8 9
descending:  9 8 7 6 5 4 3 2 1 0


std::list<T,Allocator>::splice

< cpp‎ | container‎ | list

void splice( const_iterator pos, list& other );
 (1)
void splice( const_iterator pos, list&& other );
 (1) (C++11 起)
void splice( const_iterator pos, list& other, const_iterator it );
 (2)
void splice( const_iterator pos, list&& other, const_iterator it );
 (2) (C++11 起)
void splice( const_iterator pos, list& other,
const_iterator first, const_iterator last);
 (3)
void splice( const_iterator pos, list&& other,
const_iterator first, const_iterator last );
 (3) (C++11 起)

从一个 list 转移元素给另一个。

不复制或移动元素，仅重指向链表结点的内部指针。若 get_allocator() != other.get_allocator() 则行为未定义。没有迭代器或引用被非法化，指向被移动元素的迭代器保持合法，但现在指代到 *this 中，而非到 other 中。

1) 从 other 转移所有元素到 *this 中。元素被插入到 pos 所指向的元素之前。操作后容器 other 变为空。若 other 与 *this 指代同一对象则行为未定义。
2) 从 other 转移 it 所指向的元素到 *this 。元素被插入到 pos 所指向的元素之前。
3) 从 other 转移范围 [first, last) 中的元素到 *this 。元素被插入到 pos 所指向的元素之前。若 pos 是范围 [first,last) 中的迭代器则行为未定义。

参数

pos | - | 将插入内容到其前的元素
other | - | 要自之转移内容的另一容器
it | - | 要从 other 转移到 *this 的元素
first, last | - | 要从 other 转移到 *this 的元素范围

返回值

（无）

异常

不抛出。

复杂度

1-2) 常数。

3) 若 other 与 *this 指代同一对象则为常数，否则与 std::distance (first, last) 成线性。

示例

#include <iostream>
#include <list>

std::ostream& operator<<(std::ostream& ostr, const std::list<int>& list)
{
    for (auto &i : list) {
        ostr << " " << i;
    }
    return ostr;
}

int main ()
{
    std::list<int> list1 = { 1, 2, 3, 4, 5 };
    std::list<int> list2 = { 10, 20, 30, 40, 50 };

    auto it = list1.begin();
    std::advance(it, 2);

    list1.splice(it, list2);

    std::cout << "list1: " << list1 << "\n";
    std::cout << "list2: " << list2 << "\n";

    list2.splice(list2.begin(), list1, it, list1.end());

    std::cout << "list1: " << list1 << "\n";
    std::cout << "list2: " << list2 << "\n";
}

输出：

list1:  1 2 10 20 30 40 50 3 4 5
list2:
list1:  1 2 10 20 30 40 50
list2:  3 4 5

参阅

merge | 合并二个已排序列表 (公开成员函数)
removeremove_if | 移除满足特定标准的元素 (公开成员函数)


std::list<T,Allocator>::swap

< cpp‎ | container‎ | list

void swap( list& other ); | (C++17 前)
void swap( list& other ) noexcept(/* see below */); | (C++17 起)

将内容与 other 的交换。不在单独的元素上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。在操作后，保有此容器中尾后值的迭代器指代此容器或另一容器是未指定的。

若 std::allocator_traits <allocator_type>::propagate_on_container_swap::value 为 true ，则用对非成员 swap 的无限定调用交换分配器。否则，不交换它们（且若 get_allocator() != other.get_allocator() ，则行为未定义）。

 (C++11 起)

参数

other - 要与之交换内容的容器

返回值

（无）

异常

（无） | (C++17 前)
noexcept 说明： noexcept( std::allocator_traits <Allocator>::is_always_equal::value) | (C++17 起)

复杂度

常数。

示例

#include <iostream>
#include <list>

template<class Os, class Co> Os& operator<<(Os& os, const Co& co) {
    os << "{";
    for (auto const& i : co) { os << ' ' << i; }
    return os << " } ";
}

int main()
{
    std::list<int> a1{1, 2, 3}, a2{4, 5};

    auto it1 = std::next(a1.begin());
    auto it2 = std::next(a2.begin());

    int& ref1 = a1.front();
    int& ref2 = a2.front();

    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';
    a1.swap(a2);
    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';

    // 注意交换后迭代器与引用保持与其原来的元素关联，例如指向 'a1' 中值为 2 的元素的 it1 仍指向同一元素，
    // 尽管此元素被移动到 'a2' 中。
}

输出：

{ 1 2 3 } { 4 5 } 2 5 1 4
{ 4 5 } { 1 2 3 } 2 5 1 4

参阅

std::swap(std::list)
 特化 std::swap 算法
(函数模板)


std::swap(std::list)

< cpp‎ | container‎ | list

定义于头文件 <list>
template< class T, class Alloc >

void swap( std::list <T,Alloc>& lhs,

std::list <T,Alloc>& rhs );
 (C++17 前)
template< class T, class Alloc >

void swap( std::list <T,Alloc>& lhs,

std::list <T,Alloc>& rhs ) noexcept(/* see below */);
 (C++17 起)

为 std::list 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

#include <algorithm>
#include <iostream>
#include <list>

int main()
{
    std::list<int> alice{1, 2, 3};
    std::list<int> bob{7, 8, 9, 10};

    auto print = [](const int& n) { std::cout << " " << n; };

    // 打印交换前的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';

    std::cout << "-- SWAP\n";
    std::swap(alice,bob);

    // 打印交换后的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
}

输出：

alice: 1 2 3
bob  : 7 8 9 10
-- SWAP
alice: 7 8 9 10
bob  : 1 2 3

参阅

swap
 交换内容
(公开成员函数)


std::list<T,Allocator>::unique

< cpp‎ | container‎ | list

 | (1)
void unique(); |  | (C++20 前)
size_type unique(); |  | (C++20 起)
 | (2)
template< class BinaryPredicate > void unique( BinaryPredicate p ); |  | (C++20 前)
template< class BinaryPredicate > size_type unique( BinaryPredicate p ); |  | (C++20 起)

从容器移除所有相继的重复元素。只留下相等元素组中的第一个元素。若选择的比较器不建立等价关系则行为未定义。

1) 用 operator== 比较元素。
2) 用二元谓词 p 比较元素。

参数

p - 若元素应被当做相等则返回 ​true 的二元谓词。

谓词函数的签名应等价于如下：

bool pred(const Type1 &a, const Type2 &b);

虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 Type1 与 Type2 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 Type1 的移动等价于复制 (C++11 起)）。
类型 Type1 与 Type2 必须使得 list<T,Allocator>::const_iterator 类型的对象能在解引用后隐式转换到这两个类型。 ​

返回值

（无） | (C++20 前)
移除的元素数。 | (C++20 起)

复杂度

若容器非空则准确比较元素 size() - 1 次。否则不进行比较。

示例

#include <iostream>
#include <list>

auto print = [](auto remark, auto const& container) {
  std::cout << remark;
  for (auto const& val : container)
    std::cout << ' ' << val;
  std::cout << '\n';
};

int main()
{
  std::list<int> c = {1, 2, 2, 3, 3, 2, 1, 1, 2};
  print("Before unique():", c);
  c.unique();
  print("After  unique():", c);

  c = {1, 2, 12, 23, 3, 2, 51, 1, 2};
  print("Before unique(pred):", c);
  c.unique([mod=10](int x, int y) { return (x % mod) == (y % mod); });
  print("After  unique(pred):", c);
}

输出：

Before unique(): 1 2 2 3 3 2 1 1 2
After  unique(): 1 2 3 2 1 2
Before unique(pred): 1 2 12 23 3 2 51 1 2
After  unique(pred): 1 2 23 2 51 2

参阅

unique
 移除范围内的连续重复元素
(函数模板)


std::list<T,Allocator>::~list

< cpp‎ | container‎ | list

~list();

销毁 list 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 list 大小成线性。


std::map

< cpp‎ | container
定义于头文件 <map>
template<

class Key,
class T,
class Compare = std::less <Key>,
class Allocator = std::allocator < std::pair <const Key, T> >

> class map;
 (1)
namespace pmr {

template <class Key, class T, class Compare = std::less <Key>>
using map = std::map<Key, T, Compare,
std::pmr::polymorphic_allocator < std::pair <const Key,T>>>

}
 (2) (C++17 起)

std::map 是有序键值对容器，它的元素的键是唯一的。用比较函数 Compare 排序键。搜索、移除和插入操作拥有对数复杂度。 map 通常实现为红黑树。

在每个标准库使用比较 (Compare) 概念的位置，以等价关系检验唯一性。不精确而言，若二个对象 a 与 b 互相比较不小于对方 ： !comp(a, b) && !comp(b, a) ，则认为它们等价（非唯一）。

std::map 满足容器 (Container) 、知分配器容器 (AllocatorAwareContainer) 、关联容器 (AssociativeContainer) 和可逆容器 (ReversibleContainer) 的要求。

成员类型

成员类型 | 定义
key_type | Key
mapped_type | T
value_type | std::pair <const Key, T>
size_type | 无符号整数类型（通常是 std::size_t ）
difference_type | 有符号整数类型（通常是 std::ptrdiff_t ）
key_compare | Compare
allocator_type | Allocator
reference | value_type&
const_reference | const value_type&
pointer
Allocator::pointer | (C++11 前)
std::allocator_traits <Allocator>::pointer | (C++11 起)
const_pointer
Allocator::const_pointer | (C++11 前)
std::allocator_traits <Allocator>::const_pointer | (C++11 起)
iterator | 指向 value_type 的老式双向迭代器 (LegacyBidirectionalIterator)
const_iterator | 指向 const value_type 的老式双向迭代器 (LegacyBidirectionalIterator)
reverse_iterator | std::reverse_iterator <iterator>
const_reverse_iterator | std::reverse_iterator <const_iterator>
node_type(C++17 起) | 表示容器结点的结点把柄特化
insert_return_type(C++17 起) 描述插入 node_type 结果的类型，下列类型的特化
template <class Iter, class NodeType> struct /*unspecified*/ {
    Iter     position;
    bool     inserted;
    NodeType node;
};
，以模板实参 iterator 和 node_type 实例化。

成员类

value_compare
 比较类型为value_type的对象
(类)

成员函数

(构造函数)
 构造 map
(公开成员函数)
(析构函数)
 析构 map
(公开成员函数)
operator=
 赋值给容器
(公开成员函数)
get_allocator
 返回相关的分配器
(公开成员函数)
元素访问
at
 访问指定的元素，同时进行越界检查
(公开成员函数)
operator[]
 访问或插入指定的元素
(公开成员函数)
迭代器
begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)
rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)
rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)
容量
empty
 检查容器是否为空
(公开成员函数)
size
 返回容纳的元素数
(公开成员函数)
max_size
 返回可容纳的最大元素数
(公开成员函数)
修改器
clear
 清除内容
(公开成员函数)
insert
 插入元素或结点 (C++17 起)
(公开成员函数)
insert_or_assign
(C++17)
 插入元素，或若键已存在则赋值给当前元素
(公开成员函数)
emplace
(C++11)
 原位构造元素
(公开成员函数)
emplace_hint
(C++11)
 使用提示原位构造元素
(公开成员函数)
try_emplace
(C++17)
 若键不存在则原位插入，若键存在则不做任何事
(公开成员函数)
erase
 擦除元素
(公开成员函数)
swap
 交换内容
(公开成员函数)
extract
(C++17)
 从另一容器释出结点
(公开成员函数)
merge
(C++17)
 从另一容器接合结点
(公开成员函数)
查找
count
 返回匹配特定键的元素数量
(公开成员函数)
find
 寻找带有特定键的元素
(公开成员函数)
contains
(C++20)
 检查容器是否含有带特定键的元素
(公开成员函数)
equal_range
 返回匹配特定键的元素范围
(公开成员函数)
lower_bound
 返回指向首个不小于给定键的元素的迭代器
(公开成员函数)
upper_bound
 返回指向首个大于给定键的元素的迭代器
(公开成员函数)
观察器
key_comp
 返回用于比较键的函数
(公开成员函数)
value_comp
 返回用于在value_type类型的对象中比较键的函数。
(公开成员函数)

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 按照字典顺序比较 map 中的值 (函数模板)
std::swap(std::map) | 特化 std::swap 算法 (函数模板)
erase_if(std::map) (C++20) | 擦除所有满足特定判别标准的元素 (函数模板)

推导指引 (C++17 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 464 | C++98 | 以键访问 const map 不方便 | 提供 at 函数


std::map<Key,T,Compare,Allocator>::at

< cpp‎ | container‎ | map

T& at( const Key& key ); | (1)
const T& at( const Key& key ) const; | (2)

返回到拥有等于 key 的关键的元素被映射值的引用。若无这种元素，则抛出 std::out_of_range 类型异常。

参数

key - 要找到的元素的关键

返回值

到请求元素的被映射值的引用

异常

若容器无拥有指定 key 的元素则为 std::out_of_range

复杂度

与容器大小成对数。

复杂度

operator[]
 访问或插入指定的元素
(公开成员函数)


std::map<Key,T,Compare,Allocator>::begin, std::map<Key,T,Compare,Allocator>::cbegin

< cpp‎ | container‎ | map

iterator begin(); | (C++11 前)
iterator begin() noexcept; | (C++11 起)
const_iterator begin() const; | (C++11 前)
const_iterator begin() const noexcept; | (C++11 起)
const_iterator cbegin() const noexcept; | (C++11 起)

返回指向 map 首元素的迭代器。

若 map 为空，则返回的迭代器将等于 end() 。

参数

（无）

返回值

指向首元素的迭代器。

复杂度

常数。

示例

#include <iostream>
#include <map>

int main() {
  std::map<int, float> num_map;
  num_map[4] = 4.13;
  num_map[9] = 9.24;
  num_map[1] = 1.09;
  // 调用 a_map.begin() 与 a_map.end()
  for (auto it = num_map.begin(); it != num_map.end(); ++it) {
    std::cout << it->first << ", " << it->second << '\n';
  }
}

输出：

1, 1.09
4, 4.13
9, 9.24

使用定制比较函数的示例

#include <cmath>
#include <iostream>
#include <map>

struct Point { double x, y; };

// 比较二个 Pointer 指针的 x 坐标
struct PointCmp {
    bool operator()(const Point *lhs, const Point *rhs) const {
        return lhs->x < rhs->x;
    }
};

int main() {
    // 注意尽管 x 坐标乱序，亦将按照递增的 x 坐标迭代 map
    Point points[3] = { {2, 0}, {1, 0}, {3, 0} };

    // mag 是发送结点地址到其在 x-y 平面中长度的 map
    // 尽管键为指向 Point 的指针，我们希望按照点的 x 坐标而非点的地址为 map 赋序。
    // 通过用 PointCmp 类的比较方法进行。
    std::map<Point *, double, PointCmp> mag({
        { points,     2 },
        { points + 1, 1 },
        { points + 2, 3 }
    });

    // 从 0 到长度更改每个 y 坐标
    for(auto iter = mag.begin(); iter != mag.end(); ++iter){
        auto cur = iter->first; // 指向 Point 的指针
        cur->y = mag[cur]; // 亦能用 cur->y = iter->second;
    }

    // 更新并打印每个点的长度
    for(auto iter = mag.begin(); iter != mag.end(); ++iter){
        auto cur = iter->first;
        mag[cur] = std::hypot(cur->x, cur->y);
        std::cout << "The magnitude of (" << cur->x << ", " << cur->y << ") is ";
        std::cout << iter->second << '\n';
    }

    // 以基于范围的 for 循环重复上述内容
    for(auto i : mag) {
        auto cur = i.first;
        cur->y = i.second;
        mag[cur] = std::hypot(cur->x, cur->y);
        std::cout << "The magnitude of (" << cur->x << ", " << cur->y << ") is ";
        std::cout << mag[cur] << '\n';
        // 注意与上述 std::cout << iter->second << '\n'; 相反，
        // std::cout << i.second << '\n'; 将不打印更新的长度
    }
}

输出：

The magnitude of (1, 1) is 1.41421
The magnitude of (2, 2) is 2.82843
The magnitude of (3, 3) is 4.24264
The magnitude of (1, 1.41421) is 1.73205
The magnitude of (2, 2.82843) is 3.4641
The magnitude of (3, 4.24264) is 5.19615

参阅

end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)


std::map<Key,T,Compare,Allocator>::clear

< cpp‎ | container‎ | map

void clear(); | (C++11 前)
void clear() noexcept; | (C++11 起)

从容器擦除所有元素。此调用后 size() 返回零。

非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器保持合法。

参数

（无）

返回值

（无）

复杂度

与容器大小，即元素数成线性。

示例

#include <algorithm>
#include <iostream>
#include <map>

int main()
{
    std::map<int, char> container{{1, 'x'}, {2, 'y'}, {3, 'z'}};

    auto print = [](std::pair<const int, char>& n) {
        std::cout << " " << n.first << '(' << n.second << ')';
    };

    std::cout << "Before clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';

    std::cout << "Clear\n";
    container.clear();

    std::cout << "After clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';
}

输出：

Before clear: 1(x) 2(y) 3(z)
Size=3
Clear
After clear:
Size=0

参阅

erase
 擦除元素
(公开成员函数)


std::map<Key,T,Compare,Allocator>::contains

< cpp‎ | container‎ | map

bool contains( const Key& key ) const; | (1) | (C++20 起)
template< class K > bool contains( const K& x ) const; | (2) | (C++20 起)
1) 检查容器中是否有键等价于 key 的元素。
2) 检查是否有键比较等价于值 x 的元素。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 任何能通透地与键比较的类型的值

返回值

若有这种元素则为 true ，否则为 false 。

复杂度

与容器大小成对数。

示例

#include <iostream>
#include <map>

int main()
{
    std::map<int,char> example = {{1,'a'},{2,'b'}};

    for(int x: {2, 5}) {
        if(example.contains(x)) {
            std::cout << x << ": Found\n";
        } else {
            std::cout << x << ": Not found\n";
        }
    }
}

输出：

2: Found
5: Not found

参阅

find | 寻找带有特定键的元素 (公开成员函数)
count | 返回匹配特定键的元素数量 (公开成员函数)
equal_range | 返回匹配特定键的元素范围 (公开成员函数)


std::map<Key,T,Compare,Allocator>::count

< cpp‎ | container‎ | map

size_type count( const Key& key ) const; | (1) |
template< class K > size_type count( const K& x ) const; | (2) | (C++14 起)

返回拥有关键比较等价于指定参数的元素数，因为此容器不允许重复故为 1 或 0。

1) 返回拥有关键 key 的元素数。
2) 返回拥有关键比较等价于值 x 的元素数。此重载仅若有限定 id Compare::is_transparent 合法且指代一个类型才参与重载决议。这允许调用此函数而不构造 Key 的实例。

参数

key | - | 要计量元素数的关键值
x | - | 要与关键比较的替用值

返回值

拥有比较等价于 key 或 x 的关键的元素数，对于 (1) 为 1 或 0。

复杂度

与容器大小成对数。

参阅

find | 寻找带有特定键的元素 (公开成员函数)
equal_range | 返回匹配特定键的元素范围 (公开成员函数)


std::map 的推导指引

< cpp‎ | container‎ | map

定义于头文件 <map>
template <class InputIt,

class Comp = std::less <iter_key_t<InputIt>>,
class Alloc = std::allocator <iter_to_alloc_t<InputIt>>>
map(InputIt, InputIt, Comp = Comp(), Alloc = Alloc())

-> map<iter_key_t<InputIt>, iter_val_t<InputIt>, Comp, Alloc>;
 (1) (C++17 起)
template<class Key,

class T,
class Comp = std::less <Key>,
class Alloc = std::allocator < std::pair <const Key, T>>>
map( std::initializer_list < std::pair <const Key, T>>, Comp = Comp(), Alloc = Alloc())

-> map<Key, T, Comp, Alloc>;
 (2) (C++17 起)
template<class InputIt, class Alloc>

map(InputIt, InputIt, Alloc)
-> map<iter_key_t<InputIt>, iter_val_t<InputIt>,

std::less <iter_key_t<InputIt>>, Alloc>;
 (3) (C++17 起)
template<class Key, class T, class Allocator>

map( std::initializer_list < std::pair <const Key, T>>, Allocator)

-> map<Key, T, std::less <Key>, Allocator>;
 (4) (C++17 起)

其中类型别名 iter_key_t 、 iter_val_t 、 iter_to_alloc_t 如同定义如下

template<class InputIt>

using iter_key_t = std::remove_const_t <

typename std::iterator_traits <InputIt>::value_type::first_type>;
 (仅为说明)
template<class InputIt>
using iter_val_t = typename std::iterator_traits <InputIt>::value_type::second_type;
 (仅为说明)
template<class InputIt>

using iter_to_alloc_t = std::pair <
std::add_const_t <typename std::iterator_traits <InputIt>::value_type::first_type>,
typename std::iterator_traits <InputIt>::value_type::second_type

>
 (仅为说明)

为 map 提供此推导指引，以允许从迭代器范围（重载 (1,3) ）和 std::initializer_list （重载 (2,4) ）推导。这些重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 、 Alloc 满足分配器 (Allocator) 且 Comp 不满足分配器 (Allocator) 才参与重载决议。

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

示例

#include <map>
int main() {
// std::map m1 = {{"foo", 1}, {"bar", 2}}; // 错误：花括号初始化器列表无类型；
                                           // 不能推导 pair<const Key, T>
                                           // 自 {"foo", 1} 或 {"bar", 2}

   std::map m1 = std::initializer_list<
                        std::pair<char const* const, int>>({{"foo", 2}, {"bar", 3}}); // 指引 #2
   std::map m2(m1.begin(), m1.end()); // 指引 #1
}


std::map<Key,T,Compare,Allocator>::emplace

< cpp‎ | container‎ | map

template< class... Args > std::pair <iterator,bool> emplace( Args&&... args ); | (C++11 起)

若容器中无拥有该关键的元素，则插入以给定的 args 原位构造的新元素到容器。

细心地使用 emplace 允许在构造新元素的同时避免不必要的复制或移动操作。 准确地以与提供给 emplace 者相同的参数，通过 std::forward <Args>(args)... 转发调用新元素（即 std::pair <const Key, T> ）的构造函数。 即使容器中已有拥有该关键的元素，也可能构造元素，该情况下新构造的元素将被立即销毁。

没有迭代器或引用被非法化。

参数

args - 要转发给元素构造函数的参数

返回值

返回由指向被插入元素，或若不发生插入则为既存元素的迭代器，和指代插入是否发生的 bool （若发生插入则为 true ，否则为 false ）。

异常

若任何操作抛出异常，则此函数无效果。

复杂度

与容器大小成对数。

示例

#include <iostream>
#include <utility>
#include <string>
#include <map>

int main()
{
    std::map<std::string, std::string> m;

    // 使用 pair 的移动构造函数
    m.emplace(std::make_pair(std::string("a"), std::string("a")));

    // 使用 pair 的转换移动构造函数
    m.emplace(std::make_pair("b", "abcd"));

    // 使用 pair 的模板构造函数
    m.emplace("d", "ddd");

    // 使用 pair 的逐片构造函数
    m.emplace(std::piecewise_construct,
              std::forward_as_tuple("c"),
              std::forward_as_tuple(10, 'c'));
    // C++17 起，能使用 m.try_emplace("c", 10, 'c');

    for (const auto &p : m) {
        std::cout << p.first << " => " << p.second << '\n';
    }
}

输出：

a => a
b => abcd
c => cccccccccc
d => ddd

参阅

emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)
try_emplace (C++17) | 若键不存在则原位插入，若键存在则不做任何事 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)


std::map<Key,T,Compare,Allocator>::emplace_hint

< cpp‎ | container‎ | map
template <class... Args> iterator emplace_hint( const_iterator hint, Args&&... args ); | (C++11 起)

插入元素到尽可能靠近正好在 hint 之前的位置。原位构造元素，即不进行复制或移动操作。

准确地与提供给函数的参数相同者，再以 std::forward <Args>(args)... 转发调用元素类型（ value_type ，即 std::pair <const Key, T> ）的构造函数。

没有迭代器或引用被非法化。

参数

hint | - | 指向将插入新元素到其前的位置的迭代器
args | - | 转发给元素构造函数的参数

返回值

返回指向新插入元素的迭代器。

若因为元素已存在而失败，则返回指向拥有等价关键的既存元素的迭代器。

异常

若任何操作抛出异常，则此函数无效果（强异常保证）。

复杂度

通常与容器大小成对数，但若新元素被插入到恰于 hint 前则为均摊常数。

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)


std::map<Key,T,Compare,Allocator>::empty

< cpp‎ | container‎ | map

bool empty() const; | (C++11 前)
bool empty() const noexcept; | (C++11 起) (C++20 前)
[[nodiscard]] bool empty() const noexcept; | (C++20 起)

检查容器是否无元素，即是否 begin() == end() 。

参数

（无）

返回值

若容器为空则为 true ，否则为 false

复杂度

常数。

示例

下列代码用 empty 检查 std::map <int, int> 是否含有任何元素：

#include <map>
#include <iostream>
#include <utility>

int main()
{
    std::map<int,int> numbers;
    std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';

    numbers.emplace(42, 13);
    numbers.insert(std::make_pair(13317, 123));
    std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
}

输出：

Initially, numbers.empty(): 1
After adding elements, numbers.empty(): 0

参阅

size
 返回容纳的元素数
(公开成员函数)


std::map<Key,T,Compare,Allocator>::end, std::map<Key,T,Compare,Allocator>::cend

< cpp‎ | container‎ | map

iterator end(); | (C++11 前)
iterator end() noexcept; | (C++11 起)
const_iterator end() const; | (C++11 前)
const_iterator end() const noexcept; | (C++11 起)
const_iterator cend() const noexcept; | (C++11 起)

返回指向 map 末元素后一元素的迭代器。

此元素表现为占位符；试图访问它导致未定义行为。

参数

（无）

返回值

指向后随最后元素的迭代器。

复杂度

常数。

示例

#include <iostream>
#include <map>

int main() {
  std::map<int, float> num_map;
  num_map[4] = 4.13;
  num_map[9] = 9.24;
  num_map[1] = 1.09;
  // 调用 a_map.begin() 与 a_map.end()
  for (auto it = num_map.begin(); it != num_map.end(); ++it) {
    std::cout << it->first << ", " << it->second << '\n';
  }
}

输出：

1, 1.09
4, 4.13
9, 9.24

使用定制比较函数的示例

#include <cmath>
#include <iostream>
#include <map>

struct Point { double x, y; };

// 比较二个 Pointer 指针的 x 坐标
struct PointCmp {
    bool operator()(const Point *lhs, const Point *rhs) const {
        return lhs->x < rhs->x;
    }
};

int main() {
    // 注意尽管 x 坐标乱序，亦将按照递增的 x 坐标迭代 map
    Point points[3] = { {2, 0}, {1, 0}, {3, 0} };

    // mag 是发送结点地址到其在 x-y 平面中长度的 map
    // 尽管键为指向 Point 的指针，我们希望按照点的 x 坐标而非点的地址为 map 赋序。
    // 通过用 PointCmp 类的比较方法进行。
    std::map<Point *, double, PointCmp> mag({
        { points,     2 },
        { points + 1, 1 },
        { points + 2, 3 }
    });

    // 从 0 到长度更改每个 y 坐标
    for(auto iter = mag.begin(); iter != mag.end(); ++iter){
        auto cur = iter->first; // 指向 Point 的指针
        cur->y = mag[cur]; // 亦能用 cur->y = iter->second;
    }

    // 更新并打印每个点的长度
    for(auto iter = mag.begin(); iter != mag.end(); ++iter){
        auto cur = iter->first;
        mag[cur] = std::hypot(cur->x, cur->y);
        std::cout << "The magnitude of (" << cur->x << ", " << cur->y << ") is ";
        std::cout << iter->second << '\n';
    }

    // 以基于范围的 for 循环重复上述内容
    for(auto i : mag) {
        auto cur = i.first;
        cur->y = i.second;
        mag[cur] = std::hypot(cur->x, cur->y);
        std::cout << "The magnitude of (" << cur->x << ", " << cur->y << ") is ";
        std::cout << mag[cur] << '\n';
        // 注意与上述 std::cout << iter->second << '\n'; 相反，
        // std::cout << i.second << '\n'; 将不打印更新的长度
    }
}

输出：

The magnitude of (1, 1) is 1.41421
The magnitude of (2, 2) is 2.82843
The magnitude of (3, 3) is 4.24264
The magnitude of (1, 1.41421) is 1.73205
The magnitude of (2, 2.82843) is 3.4641
The magnitude of (3, 4.24264) is 5.19615

参阅

begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)


std::map<Key,T,Compare,Allocator>::equal_range

< cpp‎ | container‎ | map

std::pair <iterator,iterator> equal_range( const Key& key ); | (1) |
std::pair <const_iterator,const_iterator> equal_range( const Key& key ) const; | (2) |
template< class K > std::pair <iterator,iterator> equal_range( const K& x ); | (3) | (C++14 起)
template< class K > std::pair <const_iterator,const_iterator> equal_range( const K& x ) const; | (4) | (C++14 起)

返回容器中所有拥有给定关键的元素范围。范围以二个迭代器定义，一个指向首个不小于 key 的元素，另一个指向首个大于 key 的元素。首个迭代器可以换用 lower_bound() 获得，而第二迭代器可换用 upper_bound() 获得。

1,2) 比较关键与 key 。
3,4) 比较关键与值 x 。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。
本节未完成
原因：更好地解释

参数

key | - | 要比较元素的关键值
x | - | 能与 Key 比较的替用值

返回值

含一对定义所需范围的迭代器的 std::pair ：第一个指向首个不小于 key 的元素，第二个指向首个大于 key 的元素。

若无元素不小于 key ，则将尾后（见 end() ）迭代器作为第一元素返回。类似地，若无元素大于 key ，则将尾后迭代器作为第二元素返回。

复杂度

与容器大小成对数。

示例

#include <map>
#include <iostream>

int main()
{
    const std::map<int, const char*> m{
        { 0, "zero" },
        { 1, "one" },
        { 2, "two" },
    };

    {
        auto p = m.equal_range(1);
        for (auto& q = p.first; q != p.second; ++q) {
            std::cout << "m[" << q->first << "] = " << q->second << '\n';
        }

        if (p.second == m.find(2)) {
            std::cout << "end of equal_range (p.second) is one-past p.first\n";
        } else {
            std::cout << "unexpected; p.second expected to be one-past p.first\n";
        }
    }

    {
        auto pp = m.equal_range(-1);
        if (pp.first == m.begin()) {
            std::cout << "pp.first is iterator to first not-less than -1\n";
        } else {
            std::cout << "unexpected pp.first\n";
        }

        if (pp.second == m.begin()) {
            std::cout << "pp.second is iterator to first element greater-than -1\n";
        } else {
            std::cout << "unexpected pp.second\n";
        }
    }

    {
        auto ppp = m.equal_range(3);
        if (ppp.first == m.end()) {
            std::cout << "ppp.first is iterator to first not-less than 3\n";
        } else {
            std::cout << "unexpected ppp.first\n";
        }

        if (ppp.second == m.end()) {
            std::cout << "ppp.second is iterator to first element greater-than 3\n";
        } else {
            std::cout << "unexpected ppp.second\n";
        }
    }
}

输出：

m[1] = one
end of equal_range (p.second) is one-past p.first
pp.first is iterator to first not-less than -1
pp.second is iterator to first element greater-than -1
ppp.first is iterator to first not-less than 3
ppp.second is iterator to first element greater-than 3

参阅

find | 寻找带有特定键的元素 (公开成员函数)
contains (C++20) | 检查容器是否含有带特定键的元素 (公开成员函数)
count | 返回匹配特定键的元素数量 (公开成员函数)
upper_bound | 返回指向首个大于给定键的元素的迭代器 (公开成员函数)
lower_bound | 返回指向首个不小于给定键的元素的迭代器 (公开成员函数)
equal_range | 返回匹配特定键值的元素范围 (函数模板)


std::map<Key,T,Compare,Allocator>::erase

< cpp‎ | container‎ | map

 | (1) |
void erase( iterator pos ); |  |  | (C++11 前)
iterator erase( iterator pos ); |  |  | (C++11 起)
iterator erase( const_iterator pos ); |  |  | (C++11 起)
 | (2) |
void erase( iterator first, iterator last ); |  |  | (C++11 前)
iterator erase( const_iterator first, const_iterator last ); |  |  | (C++11 起)
size_type erase( const key_type& key ); | (3) |
template< class K > size_type erase( K&& x ); | (4) | (C++23 起)

从容器移除指定的元素。

1) 移除位于 pos 的元素。
2) 移除范围 [first; last) 中的元素，它必须是 *this 中的合法范围。
3) 移除键等价于 key 的元素（若存在一个）。
4) 移除键比较等价于值 x 的元素（若存在一个）。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

指向被擦除元素的引用和迭代器被非法化。其他引用和迭代器不受影响。

迭代器 pos 必须合法且可解引用。从而 end() 迭代器（合法，但不可解引用）不能用作 pos 所用的值。

参数

pos | - | 指向要移除的元素的迭代器
first, last | - | 要移除的元素范围
key | - | 要移除的元素键值
x | - | 任何能与键通透比较的类型的值，指代要移除的元素

返回值

1-2) （无） (C++11 前)后随最后被移除的元素的迭代器。 (C++11 起)
3,4) 被移除的元素数。

异常

1,2) 不抛出
3,4) 任何 Compare 对象所抛的异常

复杂度

给定 map 的实例 c ：

1) 均摊常数
2) log(c.size()) + std::distance (first, last)
3) log(c.size()) + c.count(key)
4) log(c.size()) + c.count(x)

示例

#include <map>
#include <iostream>
int main()
{
    std::map<int, std::string> c = {
        {1, "one" }, {2, "two" }, {3, "three"},
        {4, "four"}, {5, "five"}, {6, "six"  }
    };

    // 从 c 擦除所有奇数
    for(auto it = c.begin(); it != c.end(); ) {
        if(it->first % 2 != 0)
            it = c.erase(it);
        else
            ++it;
    }

    for(auto& p : c) {
        std::cout << p.second << ' ';
    }
}

输出：

two four six

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2059 | C++11 | 对一个 const_iterator 的重载引入了新的歧义 | 添加了对 iterator 的重载

参阅

clear
 清除内容
(公开成员函数)


std::erase_if (std::map)

< cpp‎ | container‎ | map

定义于头文件 <map>
template< class Key, class T, class Compare, class Alloc, class Pred >

typename std::map <Key,T,Compare,Alloc>::size_type

erase_if( std::map <Key,T,Compare,Alloc>& c, Pred pred);
 (C++20 起)

从容器中擦除所有满足谓词 pred 的元素。等价于

auto old_size = c.size();
for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}
return old_size - c.size();

参数

c | - | 要从中擦除的元素
pred | - | 若应该擦除元素则对它返回 true 的谓词

返回值

擦除的元素数。

复杂度

线性。

示例

#include <map>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& cont)
{
    os << "{";
    for (const auto& item : cont) {
        os << "{" << item.first << ", " << item.second << "}";
    }
    return os << "}";
}

int main()
{
    std::map<int, char> data {{1, 'a'},{2, 'b'},{3, 'c'},{4, 'd'},
                              {5, 'e'},{4, 'f'},{5, 'g'},{5, 'g'}};
    std::cout << "Original:\n" << data << '\n';

    const auto count = std::erase_if(data, [](const auto& item) {
        auto const& [key, value] = item;
        return (key & 1) == 1;
    });

    std::cout << "Erase items with odd keys:\n" << data << '\n'
              << count << " items removed.\n";
}

输出：

Original:
{{1, a}{2, b}{3, c}{4, d}{5, e}}
Erase items with odd keys:
{{2, b}{4, d}}
3 items removed.

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::map<Key,T,Compare,Allocator>::extract

< cpp‎ | container‎ | map

node_type extract( const_iterator position ); | (1) | (C++17 起)
node_type extract( const key_type& k ); | (2) | (C++17 起)
template< class K > node_type extract( K&& x ); | (3) | (C++23 起)
1) 解链含 position 所指向元素的结点并返回占有它的结点柄。
2) 若容器拥有元素而其关键等于 x ，则从容器解链该元素并返回占有它的结点柄。否则，返回空结点柄。
3) 同 (2) 。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

任何情况下，均不复制或移动元素，只重指向容器结点的内部指针（可能出现再平衡，和 erase() 一样）。

释出结点只会非法化指向被释出元素的迭代器。指向被释出元素的指针和引用保持合法，但在结点柄占有该元素时不能使用：若元素被插入容器，就能使用它们。

参数

position | - | 指向此容器中的合法迭代器
k | - | 鉴别要被释出的结点的键
x | - | 任何能与键通透比较的类型的值，鉴别要释出的结点

返回值

占有被释出元素的结点柄，或 (2,3) 中找不到元素的情况下为空结点柄。

复杂度

1) 均摊常数
2,3) log(a.size())

注解

extract 是更换 map 的键而不重分配的唯一方式：

map<int, string> m{{1, "mango"}, {2, "papaya"}, {3, "guava"}};
auto nh = m.extract(2);
nh.key() = 4;
m.insert(move(nh));
// m == {{1, "mango"}, {3, "guava"}, {4, "papaya"}}

示例

#include <algorithm>
#include <iostream>
#include <map>

int main()
{
    std::map<int, char> cont{{1, 'a'}, {2, 'b'}, {3, 'c'}};

    auto print = [](std::pair<const int, char>& n) {
        std::cout << " " << n.first << '(' << n.second << ')';
    };

    std::cout << "Start:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 释出结点柄并更改键
    auto nh = cont.extract(1);
    nh.key() = 4;

    std::cout << "After extract and before insert:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 往回插入结点柄
    cont.insert(move(nh));

    std::cout << "End:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';
}

输出：

Start: 1(a) 2(b) 3(c)
After extract and before insert: 2(b) 3(c)
End: 2(b) 3(c) 4(a)

参阅

merge (C++17) | 从另一容器接合结点 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)
erase | 擦除元素 (公开成员函数)


std::map<Key,T,Compare,Allocator>::find

< cpp‎ | container‎ | map

iterator find( const Key& key ); | (1) |
const_iterator find( const Key& key ) const; | (2) |
template< class K > iterator find( const K& x ); | (3) | (C++14 起)
template< class K > const_iterator find( const K& x ) const; | (4) | (C++14 起)
1,2) 寻找键等于 key 的的元素。
3,4) 寻找键比较等价于值 x 的元素。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 能通透地与键比较的任何类型值

返回值

指向键等于 key 的元素的迭代器。若找不到这种元素，则返回尾后（见 end() ）迭代器。

复杂度

与容器大小成对数。

示例

#include <iostream>
#include <map>

struct FatKey   { int x; int data[1000]; };
struct LightKey { int x; };
// 注：如上详述，容器必须使用 std::less<> （或其他通透比较器）以访问这些重载。
// 这包括标准重载，例如在 std::string 与 std::string_view 之间。
bool operator<(const FatKey& fk, const LightKey& lk) { return fk.x < lk.x; }
bool operator<(const LightKey& lk, const FatKey& fk) { return lk.x < fk.x; }
bool operator<(const FatKey& fk1, const FatKey& fk2) { return fk1.x < fk2.x; }

int main()
{
// 简单比较演示
    std::map<int,char> example = {{1,'a'},{2,'b'}};

    auto search = example.find(2);
    if (search != example.end()) {
        std::cout << "Found " << search->first << " " << search->second << '\n';
    } else {
        std::cout << "Not found\n";
    }

// 通透比较演示
    std::map<FatKey, char, std::less<>> example2 = { { {1, {} },'a'}, { {2, {} },'b'} };

    LightKey lk = {2};
    auto search2 = example2.find(lk);
    if (search2 != example2.end()) {
        std::cout << "Found " << search2->first.x << " " << search2->second << '\n';
    } else {
        std::cout << "Not found\n";
    }
// 获得 const 迭代器。
// 编译器通过访问 map 的路径决定是否返回（非） const 类型的迭代器；
// 为避免此目的所致的修改，最简单的选择之一是以 const 引用访问 map 。
    const auto& example2ref = example2;
    auto search3 = example2ref.find(lk);
    if (search3 != example2.end()) {
        std::cout << "Found " << search3->first.x << ' ' << search3->second << '\n';
    //  search3->second = 'c'; // 错误：在只读对象中赋值成员
                               // 'std::pair<const FatKey, char>::second'
    }
}

输出：

Found 2 b
Found 2 b
Found 2 b

参阅

count | 返回匹配特定键的元素数量 (公开成员函数)
equal_range | 返回匹配特定键的元素范围 (公开成员函数)


std::map<Key,T,Compare,Allocator>::get_allocator

< cpp‎ | container‎ | map

allocator_type get_allocator() const; | (C++11 前)
allocator_type get_allocator() const noexcept; | (C++11 起)

返回与容器关联的分配器。

参数

（无）

返回值

关联的分配器。

复杂度

常数。


std::map<Key,T,Compare,Allocator>::insert

< cpp‎ | container‎ | map
std::pair <iterator,bool> insert( const value_type& value ); | (1) |
template< class P > std::pair <iterator,bool> insert( P&& value ); | (2) | (C++11 起)
std::pair <iterator,bool> insert( value_type&& value ); | (3) | (C++17 起)
 | (4) |
iterator insert( iterator hint, const value_type& value ); |  |  | (C++11 前)
iterator insert( const_iterator hint, const value_type& value ); |  |  | (C++11 起)
template< class P > iterator insert( const_iterator hint, P&& value ); | (5) | (C++11 起)
iterator insert( const_iterator hint, value_type&& value ); | (6) | (C++17 起)
template< class InputIt > void insert( InputIt first, InputIt last ); | (7) |
void insert( std::initializer_list <value_type> ilist ); | (8) | (C++11 起)
insert_return_type insert(node_type&& nh); | (9) | (C++17 起)
iterator insert(const_iterator hint, node_type&& nh); | (10) | (C++17 起)

若容器尚未含有带等价关键的元素，则插入元素到容器中。

1-3) 插入 value 。重载 (2) 等价于 emplace( std::forward <P>(value)) ，且仅若 std::is_constructible <value_type, P&&>::value == true 才参与重载决议。
4-6) 插入 value 到尽可能接近，恰好前于(C++11 起) hint 的位置。重载 (4) 等价于 emplace_hint(hint, std::forward <P>(value)) ，且仅若 std::is_constructible <value_type, P&&>::value == true 才参与重载决议。
7) 插入来自范围 [first, last) 的元素。若范围中的多个元素拥有比较等价的关键，则插入哪个元素是未指定的（待决的 LWG2844 ）。
8) 插入来自 initializer_list ilist 的元素。若范围中的多个元素拥有比较等价的关键，则插入哪个元素是未指定的（待决的 LWG2844 ）。
9) 若 nh 是空的结点把柄，则不做任何事。否则插入 nh 所占有的元素到容器，若容器尚未含有拥有等价于 nh.key() 的关键的元素。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。
10) 若 nh 是空的结点把柄，则不做任何事并返回尾迭代器。否则，插入 nh 所占有的元素到容器，若容器尚未含有拥有等价于 nh.key() 的关键的元素，并返回指向拥有等于 nh.key() 的关键的元素的迭代器（无关乎插入成功还是失败）。若插入成功，则从 nh 移动，否则它保持该元素的所有权。元素被插入到尽可能接近正好先于 hint 的位置。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。

没有迭代器或引用被非法化。若插入成功，则在结点把柄保有元素时获得的指向该元素的指针和引用被非法化，而在提取前获得的指向元素的指针和引用变得合法。 (C++17 起)

参数

hint -
用作搜索开始位置的建议的迭代器 | (C++11 前)
指向将插入新元素到其前的位置的迭代器 | (C++11 起)
value - 要插入的值
first, last - 要插入的元素范围
ilist - 插入值来源的 initializer_list
nh - 兼容的结点把柄
类型要求
-
InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

1-3) 返回由指向被插入元素的迭代器（或阻止插入的元素的迭代器）和指代插入是否发生的 bool 组成的 pair 。
4-6) 返回指向被插入元素的迭代器，或指向阻止插入的元素的迭代器。
7-8) （无）
9) 返回 insert_return_type ，其成员初始化如下：若 nh 为空，则 inserted 为 false ， position 为 end() ，而 node 为空。否则发生插入， inserted 为 true ， position 指向被插入元素，而 node 为空。若插入失败，则 inserted 为 false ， node 拥有 nh 的先前值，而 position 指向拥有等价于 nh.key() 的关键的元素。
10) 若 nh 为空则为尾迭代器，若插入发生则为指向被插入元素的迭代器，而若插入失败则为指向拥有等价于 nh.key() 的关键的元素的迭代器。

异常

1-6) 若任何操作抛出异常，则插入无效果（强异常保证）。
7-8) 若任何操作抛出异常，则程序在合法状态（基础异常保证）。
9-10) 若任何操作抛出异常，则插入无效果， nh 保持不变（强异常保证）。

复杂度

1-3) 与容器大小成对数， O(log(size())) 。
4-6) 若插入恰好发生在 hint 后的位置则为均摊常数，否则与容器大小成对数。 | (C++11 前)
4-6) 若插入恰好发生在 hint 前的位置则为均摊常数，否则与容器大小成对数。 | (C++11 起)
7-8) O(N*log(size() + N)) ，其中 N 是要插入的元素数。
9) 与容器大小成对数， O(log(size())) 。
10) 若插入恰好发生在 hint 前的位置则为均摊常数，否则与容器大小成对数。

注解

有提示插入 (4-6) 不返回 bool ，这是为了与顺序容器上的定位插入，如 std::vector::insert 签名兼容。这使得可以创建泛型插入器，例如 std::inserter 。检查有提示插入是否成功的一种方式是比较插入前后的 size() 。

示例

#include <iomanip>
#include <iostream>
#include <map>
#include <string>

using namespace std::literals;

template<typename It>
void printInsertionStatus(It it, bool success)
{
    std::cout << "Insertion of " << it->first << (success ? " succeeded\n" : " failed\n");
}

int main()
{
    std::map<std::string, float> karasunoPlayerHeights;

    // 重载 3 ：从右值引用插入
    const auto [it_hinata, success] = karasunoPlayerHeights.insert({"Hinata"s, 162.8});
    printInsertionStatus(it_hinata, success);

    {
        // 重载 1 ：从左值引用插入
        const auto [it, success2] = karasunoPlayerHeights.insert(*it_hinata);
        printInsertionStatus(it, success2);
    }
    {
        // 重载 2 ：经由转发到 emplace 插入
        const auto [it, success] = karasunoPlayerHeights.insert({"Kageyama", 180.6});
        printInsertionStatus(it, success);
    }

    {
        // 重载 6 ：带位置提示从右值引用插入
        const std::size_t n = std::size(karasunoPlayerHeights);
        const auto it = karasunoPlayerHeights.insert(it_hinata, {"Azumane"s, 184.7});
        printInsertionStatus(it, std::size(karasunoPlayerHeights) != n);
    }
    {
        // 重载 4 ：带位置提示从左值引用插入
        const std::size_t n = std::size(karasunoPlayerHeights);
        const auto it = karasunoPlayerHeights.insert(it_hinata, *it_hinata);
        printInsertionStatus(it, std::size(karasunoPlayerHeights) != n);
    }
    {
        // 重载 5 ：带位置提示经由转发到 emplace 插入
        const std::size_t n = std::size(karasunoPlayerHeights);
        const auto it = karasunoPlayerHeights.insert(it_hinata, {"Tsukishima", 188.3});
        printInsertionStatus(it, std::size(karasunoPlayerHeights) != n);
    }

    auto node_hinata = karasunoPlayerHeights.extract(it_hinata);
    std::map<std::string, float> playerHeights;

    // 重载 7 ：从范围插入
    playerHeights.insert(std::begin(karasunoPlayerHeights), std::end(karasunoPlayerHeights));

    // 重载 8 ：从 initializer_list 插入
    playerHeights.insert({{"Kozume"s, 169.2}, {"Kuroo", 187.7}});

    // 重载 9 ：插入结点
    const auto status = playerHeights.insert(std::move(node_hinata));
    printInsertionStatus(status.position, status.inserted);

    node_hinata = playerHeights.extract(status.position);
    {
        // 重载 10 ：插入结点带位置提示
        const std::size_t n = std::size(playerHeights);
        const auto it = playerHeights.insert(std::begin(playerHeights), std::move(node_hinata));
        printInsertionStatus(it, std::size(playerHeights) != n);
    }

    // 打印结果 map
    std::cout << std::left << '\n';
    for (const auto& [name, height] : playerHeights)
        std::cout << std::setw(10) << name << " | " << height << "cm\n";
}

输出：

Insertion of Hinata succeeded
Insertion of Hinata failed
Insertion of Kageyama succeeded
Insertion of Azumane succeeded
Insertion of Hinata failed
Insertion of Tsukishima succeeded
Insertion of Hinata succeeded
Insertion of Hinata succeeded

Azumane    | 184.7cm
Hinata     | 162.8cm
Kageyama   | 180.6cm
Kozume     | 169.2cm
Kuroo      | 187.7cm
Tsukishima | 188.3cm

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)
insert_or_assign (C++17) | 插入元素，或若键已存在则赋值给当前元素 (公开成员函数)


std::map<Key,T,Compare,Allocator>::insert_or_assign

< cpp‎ | container‎ | map

template <class M> std::pair <iterator, bool> insert_or_assign(const key_type& k, M&& obj); | (1) | (C++17 起)
template <class M> std::pair <iterator, bool> insert_or_assign(key_type&& k, M&& obj); | (2) | (C++17 起)
template <class M> iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); | (3) | (C++17 起)
template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); | (4) | (C++17 起)
1,3) 若等价于 k 的键已存在于容器中，则赋值 std::forward <M>(obj) 给对应于键 k 的 mapped_type 。若键不存在，则如同用 insert 插入从 value_type(k, std::forward <M>(obj)) 构造的新值。
2,4) 同 (1,3) ，除了从 value_type(std::move(k), std::forward <M>(obj)) 构造被映射值。

若 std::is_assignable_v <mapped_type&, M&&> 为 false 则行为未定义 (C++20 前)程序非良构 (C++20 起)。

没有迭代器或引用被非法化。

参数

k | - | 用于查找和若找不到则插入的键
hint | - | 指向新元素将要插入位置之前位置的迭代器
obj | - | 要插入或赋值的值

返回值

1,2) 若插入发生则 bool 组分为 true ，若赋值发生则 bool 组分为 false 。迭代器组分指向插入或更新的元素。
3,4) 指向被插入或更新的元素的迭代器。

复杂度

1,2) 与 emplace 的相同
3,4) 与 emplace_hint 的相同

注解

insert_or_assign 返回多于 operator[] 的信息，而且不要求被映射类型的可默认构造性。

示例

#include <iostream>
#include <map>
#include <string>

auto print_node = [](const auto &node) {
    std::cout << "[" << node.first << "] = " << node.second << '\n';
};

auto print_result = [](auto const &pair) {
    std::cout << (pair.second ? "inserted: " : "assigned: ");
    print_node(*pair.first);
};

int main()
{
    std::map<std::string, std::string> myMap;

    print_result( myMap.insert_or_assign("a", "apple"     ) );
    print_result( myMap.insert_or_assign("b", "banana"    ) );
    print_result( myMap.insert_or_assign("c", "cherry"    ) );
    print_result( myMap.insert_or_assign("c", "clementine") );

    for (const auto &node : myMap) { print_node(node); }
}

输出：

inserted: [a] = apple
inserted: [b] = banana
inserted: [c] = cherry
assigned: [c] = clementine
[a] = apple
[b] = banana
[c] = clementine

参阅

operator[] | 访问或插入指定的元素 (公开成员函数)
at | 访问指定的元素，同时进行越界检查 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)
emplace (C++11) | 原位构造元素 (公开成员函数)


std::map<Key,T,Compare,Allocator>::key_comp

< cpp‎ | container‎ | map

key_compare key_comp() const;

返回用于比较关键的函数对象，它是此容器构造函数参数 comp 的副本。

参数

（无）

返回值

比较关键的函数对象。

复杂度

常数

参阅

value_comp
 返回用于在value_type类型的对象中比较键的函数。
(公开成员函数)


std::map<Key,T,Compare,Allocator>::lower_bound

< cpp‎ | container‎ | map

iterator lower_bound( const Key& key ); | (1) |
const_iterator lower_bound( const Key& key ) const; | (1) |
template< class K > iterator lower_bound(const K& x); | (2) | (C++14 起)
template< class K > const_iterator lower_bound(const K& x) const; | (2) | (C++14 起)
1) 返回指向首个不小于 key 的元素的迭代器。
2) 返回指向首个比较不小于值 x 的元素的迭代器。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 要与元素比较的键值
x | - | 能与 Key 比较的替用值

返回值

指向首个不小于 key 的元素的迭代器。若找不到这种元素，则返回尾后迭代器（见 end() ）。

复杂度

与容器大小成对数。

参阅

equal_range | 返回匹配特定键的元素范围 (公开成员函数)
upper_bound | 返回指向首个大于给定键的元素的迭代器 (公开成员函数)


std::map<Key,T,Compare,Allocator>::map

< cpp‎ | container‎ | map

map();

explicit map( const Compare& comp,

const Allocator& alloc = Allocator() );
 (1)
explicit map( const Allocator& alloc );
 (1) (C++11 起)
(2)
template< class InputIt >

map( InputIt first, InputIt last,
const Compare& comp = Compare(),

const Allocator& alloc = Allocator() );
template< class InputIt >

map( InputIt first, InputIt last,

const Allocator& alloc );
 (C++14 起)
map( const map& other );
 (3)
map( const map& other, const Allocator& alloc );
 (3) (C++11 起)
map( map&& other );
 (4) (C++11 起)
map( map&& other, const Allocator& alloc );
 (4) (C++11 起)
(5)
map( std::initializer_list <value_type> init,

const Compare& comp = Compare(),

const Allocator& alloc = Allocator() );
 (C++11 起)
map( std::initializer_list <value_type> init,
const Allocator& );
 (C++14 起)

从各种数据源构造新容器，可选地使用用户提供的分配器 alloc 或比较函数对象 comp 。

1) 构造空容器。
2) 构造容器，使之拥有范围 [first, last) 的内容。若范围中的多个元素拥有比较等价的关键，则插入哪个元素是未指定的（待决的 LWG2844 ）。
3) 复制构造函数。构造容器，使之拥有 other 的内容副本。
若不提供 alloc ，则通过调用 std::allocator_traits <allocator_type>::select_on_container_copy_construction( other.get_allocator()) 获得分配器。 | (C++11 起)
在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。 | (C++23 起)
4) 移动构造函数。用移动语义构造容器，使之拥有 other 的内容。若不提供 alloc ，则从属于 other 的分配器移动构造分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
5) 构造容器，使之拥有 initializer_list init 的内容。若范围中的多个元素拥有比较等价的关键，则插入哪个元素是未指定的（待决的 LWG2844 ）。

参数

alloc | - | 用于此容器所有内存分配的分配器
comp | - | 用于所有关键比较的比较函数对象
first, last | - | 复制元素来源的范围
other | - | 要用作源以初始化容器元素的另一容器
init | - | 用以初始化容器元素的 initializer_list
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- Compare 必须满足比较 (Compare) 的要求。
- Allocator 必须满足分配器 (Allocator) 的要求。

复杂度

1) 常数。
2) N log(N) ，其中通常有 N = std::distance (first, last) ，若范围已按照 value_comp() 排序则与 N 成线性。
3) 与 other 的大小成线性。
4) 常数。若给定 alloc 且 alloc != other.get_allocator() 则为线性。
5) N log(N) ，其中通常有 N = init.size() ，若 init 已按照 value_comp() 排序则与 N 成线性 。

异常

对 Allocator::allocate 的调用可能抛出。

注解

在容器移动构造（重载 (4) ）后，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

尽管在 C++23 前未正式要求，一些实现已经在较早的模式中将 Allocator 放入非推导语境。

示例

#include <iostream>
#include <string>
#include <iomanip>
#include <map>

template<typename Map>
void print_map(Map& m)
{
   std::cout << '{';
   for(auto& p: m)
        std::cout << p.first << ':' << p.second << ' ';
   std::cout << "}\n";
}

struct Point { double x, y; };
struct PointCmp {
    bool operator()(const Point& lhs, const Point& rhs) const {
        return lhs.x < rhs.x; // NB 。有意忽略 y
    }
};

int main()
{
  // (1) 默认构造函数
  std::map<std::string, int> map1;
  map1["something"] = 69;
  map1["anything"] = 199;
  map1["that thing"] = 50;
  std::cout << "map1 = "; print_map(map1);

  // (2) 范围构造函数
  std::map<std::string, int> iter(map1.find("anything"), map1.end());
  std::cout << "\niter = "; print_map(iter);
  std::cout << "map1 = "; print_map(map1);

  // (3) 复制构造函数
  std::map<std::string, int> copied(map1);
  std::cout << "\ncopied = "; print_map(copied);
  std::cout << "map1 = "; print_map(map1);

  // (4) 移动构造函数
  std::map<std::string, int> moved(std::move(map1));
  std::cout << "\nmoved = "; print_map(moved);
  std::cout << "map1 = "; print_map(map1);

  // (5) initializer_list 构造函数
  const std::map<std::string, int> init {
    {"this", 100},
    {"can", 100},
    {"be", 100},
    {"const", 100},
  };
  std::cout << "\ninit = "; print_map(init);

  // 定制关键类选项 1 ：
  // 使用比较 struct
  std::map<Point, double, PointCmp> mag = {
      { {5, -12}, 13 },
      { {3, 4},   5 },
      { {-8, -15}, 17 }
  };

  for(auto p : mag)
      std::cout << "The magnitude of (" << p.first.x
                << ", " << p.first.y << ") is "
                << p.second << '\n';

  // 定制关键类选项 2 ：
  // 使用比较 lambda
  // 此 lambda 按照其模比较点，注意其中模取自局部变量 mag
  auto cmpLambda = [&mag](const Point &lhs, const Point &rhs) { return mag[lhs] < mag[rhs]; };
  // 你亦可使用不依赖局部变量的 lambda ，像这样：
  // auto cmpLambda = [](const Point &lhs, const Point &rhs) { return lhs.y < rhs.y; };
  std::map<Point, double, decltype(cmpLambda)> magy(cmpLambda);

  // 各种插入元素的方式：
  magy.insert(std::pair<Point, double>({5, -12}, 13));
  magy.insert({ {3, 4}, 5});
  magy.insert({Point{-8.0, -15.0}, 17});

  std::cout << '\n';
  for(auto p : magy)
      std::cout << "The magnitude of (" << p.first.x
                << ", " << p.first.y << ") is "
                << p.second << '\n';
}

输出：

map1 = {anything:199 something:69 that thing:50 }

iter = {anything:199 something:69 that thing:50 }
map1 = {anything:199 something:69 that thing:50 }

copied = {anything:199 something:69 that thing:50 }
map1 = {anything:199 something:69 that thing:50 }

moved = {anything:199 something:69 that thing:50 }
map1 = {}

init = {be:100 can:100 const:100 this:100 }
The magnitude of (-8, -15) is 17
The magnitude of (3, 4) is 5
The magnitude of (5, -12) is 13

The magnitude of (3, 4) is 5
The magnitude of (5, -12) is 13
The magnitude of (-8, -15) is 17

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2193 | C++11 | 默认构造函数为 explicit | 使之为非 explicit

参阅

operator=
 赋值给容器
(公开成员函数)


std::map<Key,T,Compare,Allocator>::max_size

< cpp‎ | container‎ | map

size_type max_size() const; | (C++11 前)
size_type max_size() const noexcept; | (C++11 起)

返回根据系统或库实现限制的容器可保有的元素最大数量，即对于最大容器的 std::distance (begin(), end()) 。

参数

（无）

返回值

元素数量的最大值。

复杂度

常数。

注解

此值通常反映容器大小上的理论极限，至多为 std::numeric_limits <difference_type>::max() 。运行时，可用 RAM 总量可能会限制容器大小到小于 max_size() 的值。

示例

#include <iostream>
#include <map>

int main()
{
    std::map<char,char> s;
    std::cout << "Maximum size of a 'map' is " << s.max_size() << "\n";
}

可能的输出：

Maximum size of a 'map' is 576460752303423487

参阅

size
 返回容纳的元素数
(公开成员函数)


std::map<Key,T,Compare,Allocator>::merge

< cpp‎ | container‎ | map

template<class C2> void merge( std::map <Key, T, C2, Allocator>& source ); | (1) | (C++17 起)
template<class C2> void merge( std::map <Key, T, C2, Allocator>&& source ); | (2) | (C++17 起)
template<class C2> void merge( std::multimap <Key, T, C2, Allocator>& source ); | (3) | (C++17 起)
template<class C2> void merge( std::multimap <Key, T, C2, Allocator>&& source ); | (4) | (C++17 起)

试图提取（“接合”） source 中每个元素，并用 *this 的比较对象插入到 *this 。 若 *this 中有元素，其键等价于来自 source 中元素的键，则不从 source 提取该元素。 不复制或移动元素，只会重指向容器结点的内部指针。指向被转移元素的所有指针和引用保持合法，但现在指代到 *this 中而非到 source 中。

若 get_allocator() != source.get_allocator() 则行为未定义。

参数

source - 传递结点来源的兼容容器

返回值

（无）

异常

不抛异常，除非比较抛出。

复杂度

N*log(size()+N)) ，其中 N 为 source.size() 。

示例

#include <map>
#include <iostream>
#include <string>

int main()
{
  std::map<int, std::string> ma {{1, "apple"}, {5, "pear"}, {10, "banana"}};
  std::map<int, std::string> mb {{2, "zorro"}, {4, "batman"}, {5, "X"}, {8, "alpaca"}};
  std::map<int, std::string> u;
  u.merge(ma);
  std::cout << "ma.size(): " << ma.size() << '\n';
  u.merge(mb);
  std::cout << "mb.size(): " << mb.size() << '\n';
  std::cout << "mb.at(5): " << mb.at(5) << '\n';
  for(auto const &kv: u)
    std::cout << kv.first << ", " << kv.second << '\n';
}

输出：

ma.size(): 0
mb.size(): 1
mb.at(5): X
1, apple
2, zorro
4, batman
5, pear
8, alpaca
10, banana

参阅

extract (C++17) | 从另一容器释出结点 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)


std::map<Key,T,Compare,Allocator>::operator=

< cpp‎ | container‎ | map

map& operator=( const map& other ); | (1) |
 | (2) |
map& operator=( map&& other ); |  |  | (C++11 起) (C++17 前)
map& operator=( map&& other ) noexcept(/* see below */); |  |  | (C++17 起)
map& operator=( std::initializer_list <value_type> ilist ); | (3) | (C++11 起)

替换容器内容。

1) 复制赋值运算符。以 other 的副本替换内容。

若 std::allocator_traits <allocator_type>::propagate_on_container_copy_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若 *this 的分配器在赋值后将与其旧值比较不相等，则用旧分配器解分配内存，然后在复制元素前用新分配器分配内存。否则，在可行时可能复用 *this 所拥有的内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素复制赋值替换。

 (C++11 起)
2) 移动赋值运算符。用移动语义以 other 的内容替换内容（即从 other 移动 other 中的数据到此容器中）。之后 other 在合法但未指定的状态。
若 std::allocator_traits <allocator_type>::propagate_on_container_move_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若它为 false 且 *this 与 other 的分配器不比较相等，则 *this 不能接管 other 所拥有的内存的所有权且必须单独地移动赋值每个元素，并用其自身的分配器按需分配额外内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素移动赋值替换。
3) 以 initializer_list ilist 所标识者替换内容。

参数

other | - | 用作数据源的另一容器
ilist | - | 用作数据源的 initializer_list

返回值

*this

复杂度

1) 与 *this 和 other 的大小成线性。
2) 与 *this 的大小成线性，除非分配器不比较相等且不传播，该情况下与 *this 和 other 的大小成线性。
3) 通常为 O(NlogN) ，其中 N 为 size() + ilist.size() 。若 ilist 相对于 value_comp() 已排序则为线性。

异常

可能抛出实现定义的异常。

 (C++17 前)
1,3) 可能抛出实现定义的异常。
2)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value
&& std::is_nothrow_move_assignable <Compare>::value)
 (C++17 起)

注解

在容器移动赋值（重载 (2) ）后，除非不兼容的分配器强制逐元素移动赋值，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

下列代码用 operator= 赋值一个 std::map 给另一个：

#include <map>
#include <iostream>

void display_sizes(const std::map<int, int> &nums1,
                   const std::map<int, int> &nums2,
                   const std::map<int, int> &nums3)
{
    std::cout << "nums1: " << nums1.size()
              << " nums2: " << nums2.size()
              << " nums3: " << nums3.size() << '\n';
}

int main()
{
    std::map<int, int> nums1 {{3, 1}, {4, 1}, {5, 9},
                              {6, 1}, {7, 1}, {8, 9}};
    std::map<int, int> nums2;
    std::map<int, int> nums3;

    std::cout << "Initially:\n";
    display_sizes(nums1, nums2, nums3);

    // 复制赋值从 nums1 复制数据到 nums2
    nums2 = nums1;

    std::cout << "After assigment:\n";
    display_sizes(nums1, nums2, nums3);

    // 移动赋值从 nums1 移动数据到 nums3,
    // 一同修改 nums1 和 nums3
    nums3 = std::move(nums1);

    std::cout << "After move assigment:\n";
    display_sizes(nums1, nums2, nums3);
}

输出：

Initially:
nums1: 6 nums2: 0 nums3: 0
After assigment:
nums1: 6 nums2: 6 nums3: 0
After move assigment:
nums1: 0 nums2: 6 nums3: 6

参阅

(构造函数)
 构造 map
(公开成员函数)


std::map<Key,T,Compare,Allocator>::operator[]

< cpp‎ | container‎ | map

T& operator[]( const Key& key ); | (1) |
T& operator[]( Key&& key ); | (2) | (C++11 起)

返回到映射到等于 key 的键的值的引用，若这种键不存在则进行插入。

1) 若键不存在则插入 value_type(key, T()) 。此函数等价于 return insert( std::make_pair (key, T())).first->second;
-
key_type 必须满足可复制构造 (CopyConstructible) 的要求。
-
mapped_type 必须满足可复制构造 (CopyConstructible) 和 可默认构造 (DefaultConstructible) 的要求。
若进行插入，则值初始化被映射值（对类类型为默认构造，否则为零初始化）并返回到它的引用。
 (C++11 前)
1) 若键不存在，则插入从 std::piecewise_construct, std::forward_as_tuple (key), std::tuple <>() 原位构造的 value_type 对象。此函数等价于 return this->try_emplace(key).first->second; 。 (C++17 起)
使用默认分配器时，这导致从 key 复制构造关键，并值初始化被映射值。
-
value_type 必须从 std::piecewise_construct, std::forward_as_tuple (key), std::tuple <>() 可就位构造 (EmplaceConstructible) 。使用默认分配器时，这表明 key_type 必须可复制构造 (CopyConstructible) 而 mapped_type 必须可默认构造 (DefaultConstructible) 。
2) 若键不存在，则插入从 std::piecewise_construct, std::forward_as_tuple (std::move(key)), std::tuple <>() 原位构造的 value_type 对象。此函数等价于 return this->try_emplace(std::move(key)).first->second; 。 (C++17 起)
使用默认分配器时，这导致从 key 移动构造关键，并值初始化被映射值。
-
value_type 必须从 std::piecewise_construct, std::forward_as_tuple (std::move(key)), std::tuple <>() 可就位构造 (EmplaceConstructible) 。使用默认分配器时，这表明 key_type 必须为可移动构造 (MoveConstructible) 而 mapped_type 必须为可默认构造 (DefaultConstructible) 。
(C++11 起)

没有迭代器或引用被非法化。

参数

key - 要寻找的元素键

返回值

若不存在拥有关键 key 的元素，则为到新元素被映射值的引用。否则为到既存的关键等价于 key 的元素的被映射值的引用。

异常

若任何操作抛出异常，则插入无效果。

复杂度

与容器大小成对数。

注解

出版的 C++11 和 C++14 标准中，指定此函数要求 mapped_type 为可默认插入 (DefaultInsertable) 且 key_type 为可复制插入 (CopyInsertable) 或可移动插入 (MoveInsertable) 到 *this 。此规定有缺陷并为 LWG 问题 2469 所修复，而上面的描述合并了该问题的解决方案。

然而，已知一个实现（ libc++ ）通过二个分离的分配器 construct() 调用构造 key_type 和 mapped_type 对象，可认为如发布时的标准所要求，而非原位构造 value_type 对象。

operator[] 非 const ，因为若不关键不存在则它插入关键。若此行为非所欲或容器为 const ，则可用 at() 。

insert_or_assign() 返回的信息多于 operator[] ，而且不要求 mapped_type 可默认构造。

 (C++17 起)

示例

#include <iostream>
#include <string>
#include <vector>
#include <map>

int main()
{
    std::map<char, int> letter_counts {{'a', 27}, {'b', 3}, {'c', 1}};

    std::cout << "initially:\n";
    for (const auto &pair : letter_counts) {
        std::cout << pair.first << ": " << pair.second << '\n';
    }

    letter_counts['b'] = 42;  // 更新既存值
    letter_counts['x'] = 9;  // 插入新值

    std::cout << "after modifications:\n";
    for (const auto &pair : letter_counts) {
        std::cout << pair.first << ": " << pair.second << '\n';
    }

    // 统计每个词的出现数
    // （首次调用 operator[] 以零初始化计数器）
    std::map<std::string, size_t>  word_map;
    for (const auto &w : { "this", "sentence", "is", "not", "a", "sentence",
                           "this", "sentence", "is", "a", "hoax"}) {
        ++word_map[w];
    }

    for (const auto &pair : word_map) {
        std::cout << pair.second << " occurrences of word '" << pair.first << "'\n";
    }
}

输出：

initially:
a: 27
b: 3
c: 1
after modifications:
a: 27
b: 42
c: 1
x: 9
2 occurrences of word 'a'
1 occurrences of word 'hoax'
2 occurrences of word 'is'
1 occurrences of word 'not'
3 occurrences of word 'sentence'
2 occurrences of word 'this'

参阅

at | 访问指定的元素，同时进行越界检查 (公开成员函数)
insert_or_assign (C++17) | 插入元素，或若键已存在则赋值给当前元素 (公开成员函数)
try_emplace (C++17) | 若键不存在则原位插入，若键存在则不做任何事 (公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::map)

< cpp‎ | container‎ | map

定义于头文件 <map>
template< class Key, class T, class Compare, class Alloc >

bool operator==( const std::map <Key,T,Compare,Alloc>& lhs,

const std::map <Key,T,Compare,Alloc>& rhs );
 (1)
template< class Key, class T, class Compare, class Alloc >

bool operator!=( const std::map <Key,T,Compare,Alloc>& lhs,

const std::map <Key,T,Compare,Alloc>& rhs );
 (2) (C++20 前)
template< class Key, class T, class Compare, class Alloc >

bool operator<( const std::map <Key,T,Compare,Alloc>& lhs,

const std::map <Key,T,Compare,Alloc>& rhs );
 (3) (C++20 前)
template< class Key, class T, class Compare, class Alloc >

bool operator<=( const std::map <Key,T,Compare,Alloc>& lhs,

const std::map <Key,T,Compare,Alloc>& rhs );
 (4) (C++20 前)
template< class Key, class T, class Compare, class Alloc >

bool operator>( const std::map <Key,T,Compare,Alloc>& lhs,

const std::map <Key,T,Compare,Alloc>& rhs );
 (5) (C++20 前)
template< class Key, class T, class Compare, class Alloc >

bool operator>=( const std::map <Key,T,Compare,Alloc>& lhs,

const std::map <Key,T,Compare,Alloc>& rhs );
 (6) (C++20 前)
template< class Key, class T, class Compare, class Alloc >

/* see below */ operator<=>( const std::map <Key,T,Compare,Alloc>& lhs,

const std::map <Key,T,Compare,Alloc>& rhs );
 (7) (C++20 起)

比较二个 map 的内容。

1-2) 检查 lhs 与 rhs 的内容是否相等，即它们是否拥有相同数量的元素且 lhs 中每个元素与 rhs 的同位置元素比较相等。
3-6) 按字典序比较 lhs 与 rhs 的内容。由等价于 std::lexicographical_compare 的函数进行比较。此比较忽略 map 的定序 Compare 。
7) 按字典序比较 lhs 与 rhs 的内容。如同通过在二个 map 上以进行合成三路比较（见后述）的函数对象调用 std::lexicographical_compare_three_way 进行比较。返回类型同合成三路比较的结果类型。此比较忽略 map 的定序 Compare 。

给定分别作为左操作数与右操作数的两个 const E 左值 lhs 与 rhs （其中 E 为 std::pair <const Key, T> ），合成三路比较定义如下：

  • 若 std::three_way_comparable_with<E, E> 得到满足则等价于 lhs <=> rhs ；
  • 否则，若以 operator< 比较二个 const E 左值为良构且结果类型满足 boolean-testable ，则等价于
lhs < rhs ? std::weak_ordering::less :
rhs < lhs ? std::weak_ordering::greater :
            std::weak_ordering::equivalent
  • 否则，不定义合成三路比较，而 operator<=> 不参与重载决议。
若 three_way_comparable_with 或 boolean-testable 被满足但未被实现，或使用 operator< 但 E 与 < 不建立全序，则 operator<=> 的行为未定义。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较内容的 map
-
为使用重载 (1-2) ， T, Key 必须满足可相等比较 (EqualityComparable) 的要求。
-
为使用重载 (3-6) ， Key 必须满足可小于比较 (LessThanComparable) 的要求。顺序关系必须建立全序。

返回值

1) 若 map 内容相等则为 true ，否则为 false
2) 若 map 内容不相等则为 true ，否则为 false
3) 若 lhs 的内容按字典序小于 rhs 的内容则为 true ，否则为 false
4) 若 lhs 的内容按字典序小于或等于 rhs 的内容则为 true ，否则为 false
5) 若 lhs 的内容按字典序大于 rhs 的内容则为 true ，否则为 false
6) 若 lhs 的内容按字典序大于或等于 rhs 的内容则为 true ，否则为 false
7) lhs 与 rhs 中的首对不等价元素的相对顺序，若有这种元素；否则为 lhs.size() <=> rhs.size() 。

复杂度

1-2) 若 lhs 与 rhs 的大小不同则为常数，否则与 map 大小成线性
3-7) 与 map 大小成线性

示例

#include <iostream>
#include <map>

int main()
{
    std::map<int, char> alice{{1, 'a'}, {2, 'b'}, {3, 'c'}};
    std::map<int, char> bob{{7, 'Z'}, {8, 'Y'}, {9, 'X'}, {10, 'W'}};
    std::map<int, char> eve{{1, 'a'}, {2, 'b'}, {3, 'c'}};

    std::cout << std::boolalpha;

    // 比较不相等的容器
    std::cout << "alice == bob returns " << (alice == bob) << '\n';
    std::cout << "alice != bob returns " << (alice != bob) << '\n';
    std::cout << "alice <  bob returns " << (alice < bob) << '\n';
    std::cout << "alice <= bob returns " << (alice <= bob) << '\n';
    std::cout << "alice >  bob returns " << (alice > bob) << '\n';
    std::cout << "alice >= bob returns " << (alice >= bob) << '\n';

    std::cout << '\n';

    // 比较相等的容器
    std::cout << "alice == eve returns " << (alice == eve) << '\n';
    std::cout << "alice != eve returns " << (alice != eve) << '\n';
    std::cout << "alice <  eve returns " << (alice < eve) << '\n';
    std::cout << "alice <= eve returns " << (alice <= eve) << '\n';
    std::cout << "alice >  eve returns " << (alice > eve) << '\n';
    std::cout << "alice >= eve returns " << (alice >= eve) << '\n';
}

输出：

alice == bob returns false
alice != bob returns true
alice <  bob returns true
alice <= bob returns true
alice >  bob returns false
alice >= bob returns false

alice == eve returns true
alice != eve returns false
alice <  eve returns false
alice <= eve returns true
alice >  eve returns false
alice >= eve returns true


std::map<Key,T,Compare,Allocator>::rbegin, std::map<Key,T,Compare,Allocator>::crbegin

< cpp‎ | container‎ | map

reverse_iterator rbegin(); | (C++11 前)
reverse_iterator rbegin() noexcept; | (C++11 起)
const_reverse_iterator rbegin() const; | (C++11 前)
const_reverse_iterator rbegin() const noexcept; | (C++11 起)
const_reverse_iterator crbegin() const noexcept; | (C++11 起)

返回指向逆向 map 首元素的逆向迭代器。它对应非逆向 map 的末元素。若 map 为空，则返回的迭代器等于 rend() 。

参数

（无）

返回值

指向首元素的逆向迭代器。

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)


std::map<Key,T,Compare,Allocator>::rend, std::map<Key,T,Compare,Allocator>::crend

< cpp‎ | container‎ | map

reverse_iterator rend(); | (C++11 前)
reverse_iterator rend() noexcept; | (C++11 起)
const_reverse_iterator rend() const; | (C++11 前)
const_reverse_iterator rend() const noexcept; | (C++11 起)
const_reverse_iterator crend() const noexcept; | (C++11 起)

返回指向逆向 map 末元素后一元素的逆向迭代器。它对应非逆向 map 首元素的前一元素。此元素表现为占位符，试图访问它导致未定义行为。

参数

（无）

返回值

指向末元素后一元素的逆向迭代器。

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)


std::map<Key,T,Compare,Allocator>::size

< cpp‎ | container‎ | map

size_type size() const; | (C++11 前)
size_type size() const noexcept; | (C++11 起)

返回容器中的元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

容器中的元素数量。

复杂度

常数。

示例

下列代码用 size 显示 std::map 中的元素数：

#include <map>
#include <iostream>

int main()
{
    std::map<int,char> nums {{1, 'a'}, {3, 'b'}, {5, 'c'}, {7, 'd'}};

    std::cout << "nums contains " << nums.size() << " elements.\n";
}

输出：

nums contains 4 elements.

参阅

empty | 检查容器是否为空 (公开成员函数)
max_size | 返回可容纳的最大元素数 (公开成员函数)


std::map<Key,T,Compare,Allocator>::swap

< cpp‎ | container‎ | map

void swap( map& other ); | (C++17 前)
void swap( map& other ) noexcept(/* see below */); | (C++17 起)

将内容与 other 的交换。不在单独的元素上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。尾后迭代器被非法化。

Pred 对象必须可交换 (Swappable) ，并用非成员 swap 的非限定调用交换它们。

若 std::allocator_traits <allocator_type>::propagate_on_container_swap::value 为 true ，则用对非成员 swap 的无限定调用交换分配器。否则，不交换它们（且若 get_allocator() != other.get_allocator() ，则行为未定义）。

 (C++11 起)

参数

other - 要与之交换内容的容器

返回值

（无）

异常

任何 Compare 对象交换所抛的异常。

 (C++17 前)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value
&& std::is_nothrow_swappable <Compare>::value)
 (C++17 起)

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

std::swap(std::map)
 特化 std::swap 算法
(函数模板)


std::swap(std::map)

< cpp‎ | container‎ | map

定义于头文件 <map>
template< class Key, class T, class Compare, class Alloc >

void swap( std::map <Key,T,Compare,Alloc>& lhs,

std::map <Key,T,Compare,Alloc>& rhs );
 (C++17 前)
template< class Key, class T, class Compare, class Alloc >

void swap( std::map <Key,T,Compare,Alloc>& lhs,

std::map <Key,T,Compare,Alloc>& rhs ) noexcept(/* see below */);
 (C++17 起)

为 std::map 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

#include <algorithm>
#include <iostream>
#include <map>

int main()
{
    std::map<int, char> alice{{1, 'a'}, {2, 'b'}, {3, 'c'}};
    std::map<int, char> bob{{7, 'Z'}, {8, 'Y'}, {9, 'X'}, {10, 'W'}};

    auto print = [](std::pair<const int, char>& n) {
        std::cout << " " << n.first << '(' << n.second << ')';
    };

    // 打印交换前的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';

    std::cout << "-- SWAP\n";
    std::swap(alice,bob);

    // 打印交换后的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
}

输出：

alice: 1(a) 2(b) 3(c)
bob  : 7(Z) 8(Y) 9(X) 10(W)
-- SWAP
alice: 7(Z) 8(Y) 9(X) 10(W)
bob  : 1(a) 2(b) 3(c)

参阅

swap
 交换内容
(公开成员函数)


std::map<Key,T,Compare,Allocator>::try_emplace

< cpp‎ | container‎ | map

template <class... Args> pair<iterator, bool> try_emplace(const key_type& k, Args&&... args); | (1) | (C++17 起)
template <class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); | (2) | (C++17 起)
template <class... Args> iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); | (3) | (C++17 起)
template <class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); | (4) | (C++17 起)
1) 若容器中已存在等价于 k 的关键，则不做任何事。否则行为类似 emplace ，除了以 value_type(std::piecewise_construct, std::forward_as_tuple(k), std::forward_as_tuple(std::forward<Args>(args)...)) 构造元素
2) 若容器中已存在等价于 k 的关键，则不做任何事。否则行为类似 emplace ，除了以 value_type(std::piecewise_construct, std::forward_as_tuple(std::move(k)), std::forward_as_tuple(std::forward<Args>(args)...)) 构造元素
3) 若容器中已存在等价于 k 的关键，则不做任何事。否则行为类似 emplace_hint ，除了以 value_type(std::piecewise_construct, std::forward_as_tuple(k), std::forward_as_tuple(std::forward<Args>(args)...)) 构造元素
4) 若容器中已存在等价于 k 的关键，则不做任何事。否则行为类似 emplace_hint ，除了以 value_type(std::piecewise_construct, std::forward_as_tuple(std::move(k)), std::forward_as_tuple(std::forward<Args>(args)...)) 构造元素

没有迭代器或引用被非法化。

参数

k | - | 用于查找和若找不到则插入的关键
hint | - | 指向位置的迭代器，新元素将插入到其前
args | - | 转发给元素构造函数的参数

返回值

1,2) 同 emplace
3,4) 同 emplace_hint

复杂度

1,2) 同 emplace
3,4) 同 emplace_hint

注意

不同于 insert 或 emplace ，若不发生插入，则这些函数不从右值参数移动，这令操纵 value 为仅移动类型的 map ，如 std::map<std::string, std::unique_ptr<foo>> 更为容易。另外， try_emplace 分离地处理关键和到 mapped_type 的参数，不同于要求参数构造 value_type （即一个 std::pair ）的 emplace 。

示例

#include <iostream>
#include <utility>
#include <string>

#include <map>
int main()
{
    using namespace std::literals;
    std::map<std::string, std::string> m;

    m.try_emplace("a", "a"s);
    m.try_emplace("b", "abcd");
    m.try_emplace("c", 10, 'c');
    m.try_emplace("c", "Won't be inserted");

    for (const auto &p : m) {
        std::cout << p.first << " => " << p.second << '\n';
    }
}

输出：

a => a
b => abcd
c => cccccccccc

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)


std::map<Key,T,Compare,Allocator>::upper_bound

< cpp‎ | container‎ | map

iterator upper_bound( const Key& key ); | (1) |
const_iterator upper_bound( const Key& key ) const; | (1) |
template< class K > iterator upper_bound( const K& x ); | (2) | (C++14 起)
template< class K > const_iterator upper_bound( const K& x ) const; | (2) | (C++14 起)
1) 返回指向首个大于 key 的元素的迭代器。
2) 返回指向首个比较大于值 x 的元素的迭代器。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 与元素比较的键值
x | - | 能与 Key 比较的替用值

返回值

指向首个大于 key 的元素的迭代器。若找不到这种元素，则返回尾后（见 end() ）迭代器。

复杂度

与容器大小成对数。

参阅

equal_range | 返回匹配特定键的元素范围 (公开成员函数)
lower_bound | 返回指向首个不小于给定键的元素的迭代器 (公开成员函数)


std::map<Key,T,Compare,Allocator>::value_comp

< cpp‎ | container‎ | map

std::map::value_compare value_comp() const;

返回比较 std::map::value_type （关键-值 pair ）对象的函数对象，它用 key_comp 比较 pair 的第一组分。

参数

（无）

返回值

比较值的函数对象。

复杂度

常数。

参阅

key_comp
 返回用于比较键的函数
(公开成员函数)


std::map<Key,T,Compare,Allocator>::value_compare

< cpp‎ | container‎ | map

class value_compare;

std::map::value_compare 是函数对象，通过比较 pair 的首组分比较 std::map::value_type （关键-值 pair ）类型对象。

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | bool
first_argument_type (C++17 中弃用)(C++20 中移除) | value_type
second_argument_type (C++17 中弃用)(C++20 中移除) | value_type

这些成员类型由公开继承 std::binary_function <value_type, value_type, bool> 获得。

 (C++11 前)

受保护成员对象

Compare comp
 存储的比较器
(受保护成员对象)

成员函数

(构造函数) | 构造新的 value_compare 对象 (受保护成员函数)
operator() | 比较两个 value_type 类型的值 (公开成员函数)

std::map<Key,T,Compare,Alloc>::value_compare::value_compare

protected:
value_compare( Compare c );

初始化内部比较器的实例为 c 。

参数

c - 要赋值的比较器

std::map<Key,T,Compare,Alloc>::value_compare::operator()

bool operator()( const value_type& lhs, const value_type& rhs ) const;

通过调用存储的比较器比较 lhs.first 与 rhs.first 。

参数

lhs, rhs - 要比较的值

返回值

comp(lhs.first, rhs.first) 。

异常

可能抛出实现定义的异常。


std::map<Key,T,Compare,Allocator>::~map

< cpp‎ | container‎ | map

~map();

销毁 map 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 map 大小成线性。


std::multimap

< cpp‎ | container
定义于头文件 <map>
template<

class Key,
class T,
class Compare = std::less <Key>,
class Allocator = std::allocator < std::pair <const Key, T> >

> class multimap;
 (1)
namespace pmr {

template <class Key, class T, class Compare = std::less <Key>>
using multimap = std::multimap<Key, T, Compare,
std::pmr::polymorphic_allocator < std::pair <const Key,T>>>;

}
 (2) (C++17 起)

multimap 是关联容器，含有键值对的已排序列表，同时容许多个元素拥有同一键。按照应用到键的比较函数 Compare 排序。搜索、插入和移除操作拥有对数复杂度。

拥有等价键的键值对的顺序就是插入顺序，且不会更改。(C++11 起)

凡在标准库使用比较 (Compare) 概念出，都用描述于比较 (Compare) 上的等价关系确定等价性。不精确地说，若二个对象 a 和 b 互不小于对方： !comp(a, b) && !comp(b, a) ，则认为它们等价。

std::multimap 满足容器 (Container) 、知分配器容器 (AllocatorAwareContainer) 、关联容器 (AssociativeContainer) 和可逆容器 (ReversibleContainer) 的要求。

成员类型

成员类型 | 定义
key_type | Key
mapped_type | T
value_type | std::pair <const Key, T>
size_type | 无符号整数类型（通常是 std::size_t ）
difference_type | 有符号整数类型（通常是 std::ptrdiff_t ）
key_compare | Compare
allocator_type | Allocator
reference | value_type&
const_reference | const value_type&
pointer
Allocator::pointer | (C++11 前)
std::allocator_traits <Allocator>::pointer | (C++11 起)
const_pointer
Allocator::const_pointer | (C++11 前)
std::allocator_traits <Allocator>::const_pointer | (C++11 起)
iterator | 指向 value_type 的老式双向迭代器 (LegacyBidirectionalIterator)
const_iterator | 指向 const value_type 的老式双向迭代器 (LegacyBidirectionalIterator)
reverse_iterator | std::reverse_iterator <iterator>
const_reverse_iterator | std::reverse_iterator <const_iterator>
node_type(C++17 起) | 表示容器结点的结点把柄特化

成员类

value_compare
 比较类型为value_type的对象
(类)

成员函数

(构造函数)
 构造 multimap
(公开成员函数)
(析构函数)
 析构 multimap
(公开成员函数)
operator=
 赋值给容器
(公开成员函数)
get_allocator
 返回相关的分配器
(公开成员函数)
迭代器
begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)
rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)
rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)
容量
empty
 检查容器是否为空
(公开成员函数)
size
 返回容纳的元素数
(公开成员函数)
max_size
 返回可容纳的最大元素数
(公开成员函数)
修改器
clear
 清除内容
(公开成员函数)
insert
 插入元素或结点 (C++17 起)
(公开成员函数)
emplace
(C++11)
 原位构造元素
(公开成员函数)
emplace_hint
(C++11)
 使用提示原位构造元素
(公开成员函数)
erase
 擦除元素
(公开成员函数)
swap
 交换内容
(公开成员函数)
extract
(C++17)
 从另一容器释出结点
(公开成员函数)
merge
(C++17)
 从另一容器接合结点
(公开成员函数)
查找
count
 返回匹配特定键的元素数量
(公开成员函数)
find
 寻找带有特定键的元素
(公开成员函数)
contains
(C++20)
 检查容器是否含有带特定键的元素
(公开成员函数)
equal_range
 返回匹配特定键的元素范围
(公开成员函数)
lower_bound
 返回指向首个不小于给定键的元素的迭代器
(公开成员函数)
upper_bound
 返回指向首个大于给定键的元素的迭代器
(公开成员函数)
观察器
key_comp
 返回用于比较键的函数
(公开成员函数)
value_comp
 返回用于在value_type类型的对象中比较键的函数。
(公开成员函数)

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 按照字典顺序比较 multimap 中的值 (函数模板)
std::swap(std::multimap) | 特化 std::swap 算法 (函数模板)
erase_if(std::multimap) (C++20) | 擦除所有满足特定判别标准的元素 (函数模板)

推导指引 (C++17 起)


std::multimap<Key,T,Compare,Allocator>::begin, std::multimap<Key,T,Compare,Allocator>::cbegin

< cpp‎ | container‎ | multimap

iterator begin(); | (C++11 前)
iterator begin() noexcept; | (C++11 起)
const_iterator begin() const; | (C++11 前)
const_iterator begin() const noexcept; | (C++11 起)
const_iterator cbegin() const noexcept; | (C++11 起)

返回指向 multimap 首元素的迭代器。

若 multimap 为空，则返回的迭代器将等于 end() 。

参数

（无）

返回值

指向首元素的迭代器。

复杂度

常数。

示例

#include <algorithm>
#include <cassert>
#include <iostream>
#include <map>
#include <string>
#include <cstddef>

int main()
{
    auto show_node = [](const auto& node, char ending = '\n') {
        std::cout << "{ " << node.first << ", " << node.second << " }" << ending;
    };

    std::multimap<std::size_t, std::string> mmap;
    assert(mmap.begin() == mmap.end());   // OK
    assert(mmap.cbegin() == mmap.cend()); // OK

    mmap.insert({ sizeof(long), "LONG" });
    show_node(*(mmap.cbegin()));
    assert(mmap.begin() != mmap.end());   // OK
    assert(mmap.cbegin() != mmap.cend()); // OK
    mmap.begin()->second = "long";
    show_node(*(mmap.cbegin()));

    mmap.insert({ sizeof(int), "int" });
    show_node(*mmap.cbegin());

    mmap.insert({ sizeof(short), "short" });
    show_node(*mmap.cbegin());

    mmap.insert({ sizeof(char), "char" });
    show_node(*mmap.cbegin());

    mmap.insert({{ sizeof(float), "float" }, { sizeof(double), "double" }});

    std::cout << "mmap = { ";
    std::for_each(mmap.cbegin(), mmap.cend(), [&](const auto& n) { show_node(n, ' '); });
    std::cout << "};\n";
}

可能的输出：

{ 8, LONG }
{ 8, long }
{ 4, int }
{ 2, short }
{ 1, char }
mmap = { { 1, char } { 2, short } { 4, int } { 4, float } { 8, long } { 8, double } };

参阅

end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)


std::multimap<Key,T,Compare,Allocator>::clear

< cpp‎ | container‎ | multimap

void clear(); | (C++11 前)
void clear() noexcept; | (C++11 起)

从容器擦除所有元素。此调用后 size() 返回零。

非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器保持合法。

参数

（无）

返回值

（无）

复杂度

与容器大小，即元素数成线性。

示例

#include <algorithm>
#include <iostream>
#include <map>

int main()
{
    std::multimap<int, char> container{{1, 'x'}, {2, 'y'}, {3, 'z'}};

    auto print = [](std::pair<const int, char>& n) {
        std::cout << " " << n.first << '(' << n.second << ')';
    };

    std::cout << "Before clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';

    std::cout << "Clear\n";
    container.clear();

    std::cout << "After clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';
}

输出：

Before clear: 1(x) 2(y) 3(z)
Size=3
Clear
After clear:
Size=0

参阅

erase
 擦除元素
(公开成员函数)


std::multimap<Key,T,Compare,Allocator>::contains

< cpp‎ | container‎ | multimap

bool contains( const Key& key ) const; | (1) | (C++20 起)
template< class K > bool contains( const K& x ) const; | (2) | (C++20 起)
1) 检查容器中是否有键等价于 key 的元素。
2) 检查是否有键比较等价于值 x 的元素。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 任何能通透地与键比较的类型的值

返回值

若有这种元素则为 true ，否则为 false 。

复杂度

与容器大小成对数。

示例

#include <iostream>
#include <map>

int main()
{
    std::multimap<int,char> example = {{1,'a'},{2,'b'}};

    for(int x: {2, 5}) {
        if(example.contains(x)) {
            std::cout << x << ": Found\n";
        } else {
            std::cout << x << ": Not found\n";
        }
    }
}

输出：

2: Found
5: Not found

参阅

find | 寻找带有特定键的元素 (公开成员函数)
count | 返回匹配特定键的元素数量 (公开成员函数)
equal_range | 返回匹配特定键的元素范围 (公开成员函数)


std::multimap<Key,T,Compare,Allocator>::count

< cpp‎ | container‎ | multimap

size_type count( const Key& key ) const; | (1) |
template< class K > size_type count( const K& x ) const; | (2) | (C++14 起)

返回拥有关键比较等价于指定参数的元素数。

1) 返回拥有关键 key 的元素数。
2) 返回拥有关键比较等价于值 x 的元素数。此重载仅若有限定 id Compare::is_transparent 合法且指代一个类型才参与重载决议。这允许调用此函数而不构造 Key 的实例。

参数

key | - | 要计量元素数的关键值
x | - | 要与关键比较的替用值

返回值

拥有比较等价于 key 或 x 的关键的元素数。

复杂度

与容器大小成对数，加上与找到的元素数成线性。

参阅

find | 寻找带有特定键的元素 (公开成员函数)
equal_range | 返回匹配特定键的元素范围 (公开成员函数)


std::multimap 的推导指引

< cpp‎ | container‎ | multimap

定义于头文件 <map>
template <class InputIt,

class Comp = std::less <iter_key_t<InputIt>>,
class Alloc = std::allocator <iter_to_alloc_t<InputIt>>>
multimap(InputIt, InputIt, Comp = Comp(), Alloc = Alloc())

-> multimap<iter_key_t<InputIt>, iter_val_t<InputIt>, Comp, Alloc>;
 (1) (C++17 起)
template<class Key,

class T,
class Comp = std::less <Key>,
class Alloc = std::allocator < std::pair <const Key, T>>>
multimap( std::initializer_list < std::pair <const Key, T>>, Comp = Comp(), Alloc = Alloc())

-> multimap<Key, T, Comp, Alloc>;
 (2) (C++17 起)
template<class InputIt, class Alloc>

multimap(InputIt, InputIt, Alloc)
-> multimap<iter_key_t<InputIt>, iter_val_t<InputIt>,

std::less <iter_key_t<InputIt>>, Alloc>;
 (3) (C++17 起)
template<class Key, class T, class Allocator>

multimap( std::initializer_list < std::pair <const Key, T>>, Allocator)

-> multimap<Key, T, std::less <Key>, Allocator>;
 (4) (C++17 起)

其中类型别名 iter_key_t 、 iter_val_t 、 iter_to_alloc_t 如同定义如下

template<class InputIt>

using iter_key_t = std::remove_const_t <

typename std::iterator_traits <InputIt>::value_type::first_type>;
 (仅为说明)
template<class InputIt>
using iter_val_t = typename std::iterator_traits <InputIt>::value_type::second_type;
 (仅为说明)
template<class InputIt>

using iter_to_alloc_t = std::pair <
std::add_const_t <typename std::iterator_traits <InputIt>::value_type::first_type>,
typename std::iterator_traits <InputIt>::value_type::second_type

>
 (仅为说明)

为 multimap 提供此推导指引，以允许从迭代器范围（重载 (1,3) ）和 std::initializer_list （重载 (2,4) ）推导。这些重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 、 Alloc 满足分配器 (Allocator) 且 Comp 不满足分配器 (Allocator) 才参与重载决议。

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

示例

#include <map>
int main() {
// std::multimap m1 = {{"foo", 1}, {"bar", 2}}; // 错误：花括号初始化器列表无类型；
                                                // 不能推导 pair<const Key, T>
                                                // 自 {"foo", 1} 或 {"bar", 2}

   std::multimap m1 = std::initializer_list<
                        std::pair<char const* const, int>>({{"foo", 2}, {"bar", 3}}); // 指引 #2
   std::multimap m2(m1.begin(), m1.end()); // 指引 #1
}


std::multimap<Key,T,Compare,Allocator>::emplace

< cpp‎ | container‎ | multimap

template< class... Args > iterator emplace( Args&&... args ); | (C++11 起)

插入以给定的 args 原位构造的新元素到容器。

细心地使用 emplace 允许在构造新元素的同时避免不必要的复制或移动操作。 准确地以与提供给 emplace 者相同的参数，通过 std::forward <Args>(args)... 转发调用新元素（即 std::pair <const Key, T> ）的构造函数。

没有迭代器或引用被非法化。

参数

args - 要转发给元素构造函数的参数

返回值

指向被插入元素的迭代器。

异常

若任何操作抛出异常，则此函数无效果。

复杂度

与容器大小成对数。

示例

#include <iostream>
#include <utility>
#include <string>
#include <map>

int main()
{
    std::multimap<std::string, std::string> m;

    // 使用 pair 的移动构造函数
    m.emplace(std::make_pair(std::string("a"), std::string("a")));

    // 使用 pair 的转换移动构造函数
    m.emplace(std::make_pair("b", "abcd"));

    // 使用 pair 的模板构造函数
    m.emplace("d", "ddd");

    // 使用 pair 的逐片构造函数
    m.emplace(std::piecewise_construct,
              std::forward_as_tuple("c"),
              std::forward_as_tuple(10, 'c'));

    for (const auto &p : m) {
        std::cout << p.first << " => " << p.second << '\n';
    }
}

输出：

a => a
b => abcd
c => cccccccccc
d => ddd

参阅

emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)


std::multimap<Key,T,Compare,Allocator>::emplace_hint

< cpp‎ | container‎ | multimap
template <class... Args> iterator emplace_hint( const_iterator hint, Args&&... args ); | (C++11 起)

插入新元素到尽可能接近恰在 hint 前的呆滞。原位构造元素，即不进行复制或移动操作。

准确地以与提供给函数的参数相同者，以 std::forward <Args>(args)... 转发调用元素类型（ value_type 即 std::pair <const Key, T> ）的构造函数。

没有迭代器或引用被非法化。

参数

hint | - | 指向将插入新元素到其前的位置的迭代器
args | - | 转发给元素构造函数的参数

返回值

返回指向新插入元素的迭代器。

复杂度

若任何操作抛出异常，则此函数无效果（强异常保证）。

复杂度

通常与容器大小成对数，但若正好在 hint 前插入新元素则为均摊常数。

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)


std::multimap<Key,T,Compare,Allocator>::empty

< cpp‎ | container‎ | multimap

bool empty() const; | (C++11 前)
bool empty() const noexcept; | (C++11 起) (C++20 前)
[[nodiscard]] bool empty() const noexcept; | (C++20 起)

检查容器是否无元素，即是否 begin() == end() 。

参数

（无）

返回值

若容器为空则为 true ，否则为 false

复杂度

常数。

示例

下列代码用 empty 检查 std::multimap <int, int> 是否含有任何元素：

#include <map>
#include <iostream>
#include <utility>

int main()
{
    std::multimap<int, int> numbers;
    std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';

    numbers.emplace(42, 13);
    numbers.insert(std::make_pair(13317, 123));
    std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
}

输出：

Initially, numbers.empty(): 1
After adding elements, numbers.empty(): 0

参阅

size
 返回容纳的元素数
(公开成员函数)


std::multimap<Key,T,Compare,Allocator>::end, std::multimap<Key,T,Compare,Allocator>::cend

< cpp‎ | container‎ | multimap

iterator end(); | (C++11 前)
iterator end() noexcept; | (C++11 起)
const_iterator end() const; | (C++11 前)
const_iterator end() const noexcept; | (C++11 起)
const_iterator cend() const noexcept; | (C++11 起)

返回指向 multimap 末元素后一元素的迭代器。

此元素表现为占位符；试图访问它导致未定义行为。

参数

（无）

返回值

指向后随最后元素的迭代器。

复杂度

常数。

示例

#include <algorithm>
#include <cassert>
#include <iostream>
#include <map>
#include <string>
#include <cstddef>

int main()
{
    auto show_node = [](const auto& node, char ending = '\n') {
        std::cout << "{ " << node.first << ", " << node.second << " }" << ending;
    };

    std::multimap<std::size_t, std::string> mmap;
    assert(mmap.begin() == mmap.end());   // OK
    assert(mmap.cbegin() == mmap.cend()); // OK

    mmap.insert({ sizeof(long), "LONG" });
    show_node(*(mmap.cbegin()));
    assert(mmap.begin() != mmap.end());   // OK
    assert(mmap.cbegin() != mmap.cend()); // OK
    mmap.begin()->second = "long";
    show_node(*(mmap.cbegin()));

    mmap.insert({ sizeof(int), "int" });
    show_node(*mmap.cbegin());

    mmap.insert({ sizeof(short), "short" });
    show_node(*mmap.cbegin());

    mmap.insert({ sizeof(char), "char" });
    show_node(*mmap.cbegin());

    mmap.insert({{ sizeof(float), "float" }, { sizeof(double), "double" }});

    std::cout << "mmap = { ";
    std::for_each(mmap.cbegin(), mmap.cend(), [&](const auto& n) { show_node(n, ' '); });
    std::cout << "};\n";
}

可能的输出：

{ 8, LONG }
{ 8, long }
{ 4, int }
{ 2, short }
{ 1, char }
mmap = { { 1, char } { 2, short } { 4, int } { 4, float } { 8, long } { 8, double } };

参阅

begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)


std::multimap<Key,T,Compare,Allocator>::equal_range

< cpp‎ | container‎ | multimap

std::pair <iterator,iterator> equal_range( const Key& key ); | (1) |
std::pair <const_iterator,const_iterator> equal_range( const Key& key ) const; | (2) |
template< class K > std::pair <iterator,iterator> equal_range( const K& x ); | (3) | (C++14 起)
template< class K > std::pair <const_iterator,const_iterator> equal_range( const K& x ) const; | (4) | (C++14 起)

返回容器中所有拥有给定关键的元素范围。范围以二个迭代器定义，一个指向首个不小于 key 的元素，另一个指向首个大于 key 的元素。首个迭代器可以换用 lower_bound() 获得，而第二迭代器可换用 upper_bound() 获得。

1,2) 比较关键与 key 。
3,4) 比较关键与值 x 。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。
本节未完成
原因：更好地解释

参数

key | - | 要比较元素的关键值
x | - | 能与 Key 比较的替用值

返回值

含一对定义所需范围的迭代器的 std::pair ：第一个指向首个不小于 key 的元素，第二个指向首个大于 key 的元素。

若无元素不小于 key ，则将尾后（见 end() ）迭代器作为第一元素返回。类似地，若无元素大于 key ，则将尾后迭代器作为第二元素返回。

因为 emplace 和无提示的 insert 始终在上界插入，相等范围中等价元素的顺序就是插入顺序，除非用有提示的 insert 或 emplace_hint 在不同的位置插入元素。

 (C++11 起)

复杂度

与容器大小成对数。

示例

#include <iostream>
#include <map>

int main()
{
    std::multimap<int, char> dict {
        {1, 'A'},
        {2, 'B'},
        {2, 'C'},
        {2, 'D'},
        {4, 'E'},
        {3, 'F'}
    };

    auto range = dict.equal_range(2);

    for (auto i = range.first; i != range.second; ++i)
    {
        std::cout << i->first << ": " << i->second << '\n';
    }
}

输出：

2: B
2: C
2: D

参阅

find | 寻找带有特定键的元素 (公开成员函数)
contains (C++20) | 检查容器是否含有带特定键的元素 (公开成员函数)
count | 返回匹配特定键的元素数量 (公开成员函数)
upper_bound | 返回指向首个大于给定键的元素的迭代器 (公开成员函数)
lower_bound | 返回指向首个不小于给定键的元素的迭代器 (公开成员函数)
equal_range | 返回匹配特定键值的元素范围 (函数模板)


std::multimap<Key,T,Compare,Allocator>::erase

< cpp‎ | container‎ | multimap

 | (1) |
void erase( iterator pos ); |  |  | (C++11 前)
iterator erase( iterator pos ); |  |  | (C++11 起)
iterator erase( const_iterator pos ); |  |  | (C++11 起)
 | (2) |
void erase( iterator first, iterator last ); |  |  | (C++11 前)
iterator erase( const_iterator first, const_iterator last ); |  |  | (C++11 起)
size_type erase( const key_type& key ); | (3) |
template< class K > size_type erase( K&& x ); | (4) | (C++23 起)

从容器移除指定的元素。

1) 移除位于 pos 的元素。
2) 移除范围 [first; last) 中的元素，它必须是 *this 中的合法范围。
3) 移除键等价于 key 的所有元素。
4) 移除键比较等价于值 x 的所有元素。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

指向被擦除元素的引用和迭代器被非法化。其他引用和迭代器不受影响。

迭代器 pos 必须合法且可解引用。从而 end() 迭代器（合法，但不可解引用）不能用作 pos 所用的值。

参数

pos | - | 指向要移除的元素的迭代器
first, last | - | 要移除的元素范围
key | - | 要移除的元素键值
x | - | 任何能与键通透比较的类型的值，指代要移除的元素

返回值

1-2) （无） (C++11 前)后随最后被移除的元素的迭代器。 (C++11 起)
3,4) 被移除的元素数。

异常

1,2) 不抛出
3,4) 任何 Compare 对象所抛的异常

复杂度

给定 multimap 的实例 c ：

1) 均摊常数
2) log(c.size()) + std::distance (first, last)
3) log(c.size()) + c.count(key)
4) log(c.size()) + c.count(x)

示例

#include <map>
#include <iostream>
int main()
{
    std::multimap<int, std::string> c = {
        {1, "one" }, {2, "two" }, {3, "three"},
        {4, "four"}, {5, "five"}, {6, "six"  }
    };

    // 从 c 擦除所有奇数
    for(auto it = c.begin(); it != c.end(); ) {
        if(it->first % 2 != 0)
            it = c.erase(it);
        else
            ++it;
    }

    for(auto& p : c) {
        std::cout << p.second << ' ';
    }
}

输出：

two four six

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2059 | C++11 | 对一个 const_iterator 的重载引入了新的歧义 | 添加了对 iterator 的重载

参阅

clear
 清除内容
(公开成员函数)


std::erase_if (std::multimap)

< cpp‎ | container‎ | multimap

定义于头文件 <map>
template< class Key, class T, class Compare, class Alloc, class Pred >

typename std::multimap <Key,T,Compare,Alloc>::size_type

erase_if( std::multimap <Key,T,Compare,Alloc>& c, Pred pred);
 (C++20 起)

从容器中擦除所有满足谓词 pred 的元素。等价于

auto old_size = c.size();
for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}
return old_size - c.size();

参数

c | - | 要从中擦除的元素
pred | - | 若应该擦除元素则对它返回 true 的谓词

返回值

擦除的元素数。

复杂度

线性。

示例

#include <map>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& cont)
{
    os << "{";
    for (const auto& item : cont) {
        os << "{" << item.first << ", " << item.second << "}";
    }
    return os << "}";
}

int main()
{
    std::multimap<int, char> data {{1, 'a'},{2, 'b'},{3, 'c'},{4, 'd'},
                                   {5, 'e'},{4, 'f'},{5, 'g'},{5, 'g'}};
    std::cout << "Original:\n" << data << '\n';

    const auto count = std::erase_if(data, [](const auto& item) {
        auto const& [key, value] = item;
        return (key & 1) == 1;
    });

    std::cout << "Erase items with odd keys:\n" << data << '\n'
              << count << " items removed.\n";
}

输出：

Original:
{{1, a}{2, b}{3, c}{4, d}{4, f}{5, e}{5, g}{5, g}}
Erase items with odd keys:
{{2, b}{4, d}{4, f}}
5 items removed.

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::multimap<Key,T,Compare,Allocator>::extract

< cpp‎ | container‎ | multimap

node_type extract( const_iterator position ); | (1) | (C++17 起)
node_type extract( const key_type& k ); | (2) | (C++17 起)
template< class K > node_type extract( K&& x ); | (3) | (C++23 起)
1) 解链含 position 所指向元素的结点并返回占有它的结点柄。
2) 若容器拥有元素而其关键等于 x ，则从容器解链首个这种元素并返回占有它的结点柄。否则，返回空结点柄。
3) 同 (2) 。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

任何情况下，均不复制或移动元素，只重指向容器结点的内部指针（可能出现再平衡，和 erase() 一样）。

释出结点只会非法化指向被释出元素的迭代器。指向被释出元素的指针和引用保持合法，但在结点柄占有该元素时不能使用：若元素被插入容器，就能使用它们。

参数

position | - | 指向此容器中的合法迭代器
k | - | 鉴别要被释出的结点的键
x | - | 任何能与键通透比较的类型的值，鉴别要释出的结点

返回值

占有被释出元素的结点柄，或 (2,3) 中找不到元素的情况下为空结点柄。

复杂度

1) 均摊常数
2,3) log(a.size())

注解

extract 是更换 map 的键而不重分配的唯一方式：

map<int, string> m{{1, "mango"}, {2, "papaya"}, {3, "guava"}};
auto nh = m.extract(2);
nh.key() = 4;
m.insert(move(nh));
// m == {{1, "mango"}, {3, "guava"}, {4, "papaya"}}

示例

#include <algorithm>
#include <iostream>
#include <map>

int main()
{
    std::multimap<int, char> cont{{1, 'a'}, {2, 'b'}, {3, 'c'}};

    auto print = [](std::pair<const int, char>& n) {
        std::cout << " " << n.first << '(' << n.second << ')';
    };

    std::cout << "Start:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 释出结点柄并更改键
    auto nh = cont.extract(1);
    nh.key() = 4;

    std::cout << "After extract and before insert:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 往回插入结点柄
    cont.insert(move(nh));

    std::cout << "End:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';
}

输出：

Start: 1(a) 2(b) 3(c)
After extract and before insert: 2(b) 3(c)
End: 2(b) 3(c) 4(a)

参阅

merge (C++17) | 从另一容器接合结点 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)
erase | 擦除元素 (公开成员函数)


std::multimap<Key,T,Compare,Allocator>::find

< cpp‎ | container‎ | multimap

iterator find( const Key& key ); | (1) |
const_iterator find( const Key& key ) const; | (2) |
template< class K > iterator find( const K& x ); | (3) | (C++14 起)
template< class K > const_iterator find( const K& x ) const; | (4) | (C++14 起)
1,2) 寻找键等于 key 的的元素。若容器中有数个拥有键 key 的元素，则可能返回任意一者。
3,4) 寻找键比较等价于值 x 的元素。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 能通透地与键比较的任何类型值

返回值

指向键等于 key 的元素的迭代器。若找不到这种元素，则返回尾后（见 end() ）迭代器。

复杂度

与容器大小成对数。

示例

#include <iostream>
#include <map>

struct FatKey   { int x; int data[1000]; };
struct LightKey { int x; };
// 注：如上详述，容器必须使用 std::less<> （或其他通透比较器）以访问这些重载。
// 这包括标准重载，例如在 std::string 与 std::string_view 之间。
bool operator<(const FatKey& fk, const LightKey& lk) { return fk.x < lk.x; }
bool operator<(const LightKey& lk, const FatKey& fk) { return lk.x < fk.x; }
bool operator<(const FatKey& fk1, const FatKey& fk2) { return fk1.x < fk2.x; }

int main()
{
// 简单比较演示
    std::multimap<int,char> example = {{1,'a'},{2,'b'}};

    auto search = example.find(2);
    if (search != example.end()) {
        std::cout << "Found " << search->first << " " << search->second << '\n';
    } else {
        std::cout << "Not found\n";
    }

// 通透比较演示
    std::multimap<FatKey, char, std::less<>> example2 = { { {1, {} },'a'}, { {2, {} },'b'} };

    LightKey lk = {2};
    auto search2 = example2.find(lk);
    if (search2 != example2.end()) {
        std::cout << "Found " << search2->first.x << " " << search2->second << '\n';
    } else {
        std::cout << "Not found\n";
    }
// 获得 const 迭代器。
// 编译器通过访问 map 的路径决定是否返回（非） const 类型的迭代器；
// 为避免此目的所致的修改，最简单的选择之一是以 const 引用访问 map 。
    const auto& example2ref = example2;
    auto search3 = example2ref.find(lk);
    if (search3 != example2.end()) {
        std::cout << "Found " << search3->first.x << ' ' << search3->second << '\n';
    //  search3->second = 'c'; // 错误：在只读对象中赋值成员
                               // 'std::pair<const FatKey, char>::second'
    }
}

输出：

Found 2 b
Found 2 b
Found 2 b

参阅

count | 返回匹配特定键的元素数量 (公开成员函数)
equal_range | 返回匹配特定键的元素范围 (公开成员函数)


std::multimap<Key,T,Compare,Allocator>::get_allocator

< cpp‎ | container‎ | multimap

allocator_type get_allocator() const; | (C++11 前)
allocator_type get_allocator() const noexcept; | (C++11 起)

返回与容器关联的分配器。

参数

（无）

返回值

关联的分配器。

复杂度

常数。


std::multimap<Key,T,Compare,Allocator>::insert

< cpp‎ | container‎ | multimap
iterator insert( const value_type& value ); | (1) |
iterator insert( value_type&& value ); | (1) | (C++17 起)
template< class P > iterator insert( P&& value ); | (2) | (C++11 起)
 | (3) |
iterator insert( iterator hint, const value_type& value ); |  |  | (C++11 前)
iterator insert( const_iterator hint, const value_type& value ); |  |  | (C++11 起)
iterator insert( const_iterator hint, value_type&& value ); | (3) | (C++17 起)
template< class P > iterator insert( const_iterator hint, P&& value ); | (4) | (C++11 起)
template< class InputIt > void insert( InputIt first, InputIt last ); | (5) |
void insert( std::initializer_list <value_type> ilist ); | (6) | (C++11 起)
iterator insert(node_type&& nh); | (7) | (C++17 起)
iterator insert(const_iterator hint, node_type&& nh); | (8) | (C++17 起)

插入元素到容器中。

1-2) 插入 value 。若容器拥有带等价关键的元素，则插入到范围的上界。(C++11 起)重载 (2) 等价于 emplace( std::forward <P>(value)) ，且仅若 std::is_constructible <value_type, P&&>::value == true 才参与重载决议。
3-4) 插入 value 到尽可能接近，恰好前于(C++11 起) hint 的位置。重载 (4) 等价于 emplace_hint(hint, std::forward <P>(value)) ，且仅若 std::is_constructible <value_type, P&&>::value == true 才参与重载决议。
5) 插入来自范围 [first, last) 的元素。
6) 插入来自 initializer_list ilist 的元素。
7) 若 nh 是空的结点把柄，则不做任何事。否则插入 nh 所占有的元素到容器并返回指向被插入元素的迭代器。若范围含有关键等价于存在于容器中的 nh.key() 的关键，则在范围结尾插入元素。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。
8) 若 nh 是空的结点把柄，则不做任何事并返回尾迭代器。否则，插入 nh 所占有的元素到容器，并返回指向拥有等于 nh.key() 的关键的元素的迭代器元素被插入到尽可能接近正好先于 hint 的位置。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。

没有迭代器或引用被非法化。若插入成功，则在结点把柄保有元素时获得的指向该元素的指针和引用被非法化，而在提取前获得的指向元素的指针和引用变得合法。 (C++17 起)

参数

hint -
用作搜索开始位置的建议的迭代器 | (C++11 前)
指向将插入新元素到其前的位置的迭代器 | (C++11 起)
value - 要插入的值
first, last - 要插入的元素范围
ilist - 插入值来源的 initializer_list
nh - 兼容的结点把柄
类型要求
-
InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

1-4) 指向被插入元素的迭代器。
5-6) （无）
7,8) 若 nh 为空则为尾迭代器，否则为指向被插入元素的迭代器。

异常

1-4) 若任何操作抛出异常，则插入无效果。
本节未完成
原因：情况 5-6

复杂度

1-2) 与容器大小成对数， O(log(size())) 。
3-4) 若插入恰好发生在 hint 后的位置则为均摊常数，否则与容器大小成对数。 | (C++11 前)
3-4) 若插入恰好发生在 hint 前的位置则为均摊常数，否则与容器大小成对数。 | (C++11 起)
5-6) O(N*log(size() + N)) ，其中 N 是要插入的元素数。
7) 与容器大小成对数， O(log(size())) 。
8) 若插入恰好发生在 hint 前的位置则为均摊常数，否则与容器大小成对数。

示例

#include <iostream>
#include <string>
#include <map>
#include <functional>

template<class M>
void print(const M& mmap)
{
    for (auto & e : mmap)
        std::cout << "{" << e.first << "," << e.second << "} ";
    std::cout << '\n';
}

int main()
{
  // 列表初始化
  std::multimap<int, std::string, std::greater<int>> mmap
    {{2, "foo"}, {2, "bar"}, {3, "baz"}, {1, "abc"}, {5, "def"}};

  // 用 value_type 插入
  mmap.insert(decltype(mmap)::value_type(5, "pqr"));
  print(mmap);

  // 用 make_pair 插入
  mmap.insert(std::make_pair(6, "uvw"));
  print(mmap);

  mmap.insert({7, "xyz"});
  print(mmap);

  // 用 initialization_list 插入
  mmap.insert({{5, "one"}, {5, "two"}});
  print(mmap);

  // 擦除所有关键为 5 的条目
  mmap.erase(5);
  print(mmap);

  // 寻找并擦除特定条目
  auto pos = mmap.begin();
  while (pos->second != "bar" && pos != mmap.end()) ++pos;
  mmap.erase(pos);
  print(mmap);
}

输出：

{5,def} {5,pqr} {3,baz} {2,foo} {2,bar} {1,abc}
{6,uvw} {5,def} {5,pqr} {3,baz} {2,foo} {2,bar} {1,abc}
{7,xyz} {6,uvw} {5,def} {5,pqr} {3,baz} {2,foo} {2,bar} {1,abc}
{7,xyz} {6,uvw} {5,def} {5,pqr} {5,one} {5,two} {3,baz} {2,foo} {2,bar} {1,abc}
{7,xyz} {6,uvw} {3,baz} {2,foo} {2,bar} {1,abc}
{7,xyz} {6,uvw} {3,baz} {2,foo} {1,abc}

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)


std::multimap<Key,T,Compare,Allocator>::key_comp

< cpp‎ | container‎ | multimap

key_compare key_comp() const;

返回用于比较关键的函数对象，它是此容器构造函数参数 comp 的副本。

参数

（无）

返回值

比较关键的函数对象。

复杂度

常数

参阅

value_comp
 返回用于在value_type类型的对象中比较键的函数。
(公开成员函数)


std::multimap<Key,T,Compare,Allocator>::lower_bound

< cpp‎ | container‎ | multimap

iterator lower_bound( const Key& key ); | (1) |
const_iterator lower_bound( const Key& key ) const; | (1) |
template< class K > iterator lower_bound(const K& x); | (2) | (C++14 起)
template< class K > const_iterator lower_bound(const K& x) const; | (2) | (C++14 起)
1) 返回指向首个不小于 key 的元素的迭代器。
2) 返回指向首个比较不小于值 x 的元素的迭代器。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 要与元素比较的键值
x | - | 能与 Key 比较的替用值

返回值

指向首个不小于 key 的元素的迭代器。若找不到这种元素，则返回尾后迭代器（见 end() ）。

复杂度

与容器大小成对数。

参阅

equal_range | 返回匹配特定键的元素范围 (公开成员函数)
upper_bound | 返回指向首个大于给定键的元素的迭代器 (公开成员函数)


std::multimap<Key,T,Compare,Allocator>::max_size

< cpp‎ | container‎ | multimap

size_type max_size() const; | (C++11 前)
size_type max_size() const noexcept; | (C++11 起)

返回根据系统或库实现限制的容器可保有的元素最大数量，即对于最大容器的 std::distance (begin(), end()) 。

参数

（无）

返回值

元素数量的最大值。

复杂度

常数。

注解

此值通常反映容器大小上的理论极限，至多为 std::numeric_limits <difference_type>::max() 。运行时，可用 RAM 总量可能会限制容器大小到小于 max_size() 的值。

示例

#include <iostream>
#include <map>

int main()
{
    std::multimap<char,char> s;
    std::cout << "Maximum size of a 'multimap' is " << s.max_size() << "\n";
}

可能的输出：

Maximum size of a 'multimap' is 576460752303423487

参阅

size
 返回容纳的元素数
(公开成员函数)


std::multimap<Key,T,Compare,Allocator>::merge

< cpp‎ | container‎ | multimap

template<class C2> void merge( std::map <Key, T, C2, Allocator>& source ); | (1) | (C++17 起)
template<class C2> void merge( std::map <Key, T, C2, Allocator>&& source ); | (2) | (C++17 起)
template<class C2> void merge( std::multimap <Key, T, C2, Allocator>& source ); | (3) | (C++17 起)
template<class C2> void merge( std::multimap <Key, T, C2, Allocator>&& source ); | (4) | (C++17 起)

试图提取（“接合”） source 中每个元素，并用 *this 的比较对象插入到 *this 。

不复制或移动元素，只会重指向容器结点的内部指针。指向被转移元素的所有指针和引用保持合法，但现在指代到 *this 中而非到 source 中。

若 get_allocator() != source.get_allocator() 则行为未定义。

参数

source - 传递结点来源的兼容容器

返回值

（无）

异常

不抛异常，除非比较抛出。

复杂度

N*log(size()+N)) ，其中 N 为 source.size() 。

示例

#include <map>
#include <iostream>
#include <string>

int main()
{
  std::multimap<int, std::string> ma {{1, "apple"}, {5, "pear"}, {10, "banana"}};
  std::multimap<int, std::string> mb {{2, "zorro"}, {4, "batman"}, {5, "X"}, {8, "alpaca"}};
  std::multimap<int, std::string> u;
  u.merge(ma);
  std::cout << "ma.size(): " << ma.size() << '\n';
  u.merge(mb);
  std::cout << "mb.size(): " << mb.size() << '\n';

  for(auto const &kv: u)
    std::cout << kv.first << ", " << kv.second << '\n';
}

输出：

ma.size(): 0
mb.size(): 0
1, apple
2, zorro
4, batman
5, pear
5, X
8, alpaca
10, banana

参阅

extract (C++17) | 从另一容器释出结点 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)


std::multimap<Key,T,Compare,Allocator>::multimap

< cpp‎ | container‎ | multimap

multimap();

explicit multimap( const Compare& comp,

const Allocator& alloc = Allocator() );
 (1)
explicit multimap( const Allocator& alloc );
 (1) (C++11 起)
(2)
template< class InputIt >

multimap( InputIt first, InputIt last,
const Compare& comp = Compare(),

const Allocator& alloc = Allocator() );
template< class InputIt >

multimap( InputIt first, InputIt last,

const Allocator& alloc );
 (C++14 起)
multimap( const multimap& other );
 (3)
multimap( const multimap& other, const Allocator& alloc );
 (3) (C++11 起)
multimap( multimap&& other );
 (4) (C++11 起)
multimap( multimap&& other, const Allocator& alloc );
 (4) (C++11 起)
(5)
multimap( std::initializer_list <value_type> init,

const Compare& comp = Compare(),

const Allocator& alloc = Allocator() );
 (C++11 起)
multimap( std::initializer_list <value_type> init,
const Allocator& );
 (C++14 起)

从各种数据源构造新容器，可选地使用用户提供的分配器 alloc 或比较函数对象 comp 。

1) 构造空容器。
2) 构造容器，使之拥有范围 [first, last) 的内容。
3) 复制构造函数。构造容器，使之拥有 other 的内容副本。
若不提供 alloc ，则通过调用 std::allocator_traits <allocator_type>::select_on_container_copy_construction( other.get_allocator()) 获得分配器。 | (C++11 起)
在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。 | (C++23 起)
4) 移动构造函数。用移动语义构造容器，使之拥有 other 的内容。若不提供 alloc ，则从属于 other 的分配器移动构造分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
5) 构造容器，使之拥有 initializer_list init 的内容。

参数

alloc | - | 用于此容器所有内存分配的分配器
comp | - | 用于所有关键比较的比较函数对象
first, last | - | 复制元素来源的范围
other | - | 要用作源以初始化容器元素的另一容器
init | - | 用以初始化容器元素的 initializer_list
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- Compare 必须满足比较 (Compare) 的要求。
- Allocator 必须满足分配器 (Allocator) 的要求。

复杂度

1) 常数。
2) N log(N) ，其中通常有 N = std::distance (first, last) ，若范围已按照 value_comp() 排序则与 N 成线性。
3) 与 other 的大小成线性。
4) 常数。若给定 alloc 且 alloc != other.get_allocator() 则为线性。
5) N log(N) ，其中通常有 N = init.size() ，若 init 已按照 value_comp() 排序则与 N 成线性 。

异常

对 Allocator::allocate 的调用可能抛出。

注解

在容器移动构造（重载 (4) ）后，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

尽管在 C++23 前未正式要求，一些实现已经在较早的模式中将 Allocator 放入非推导语境。

示例

#include <iostream>
#include <map>

struct Point { double x, y; };
struct PointCmp {
    bool operator()(const Point& lhs, const Point& rhs) const {
        return lhs.x < rhs.x; // NB 。有意忽略 y
    }
};

int main() {
    std::multimap<int, int> m = {{1,1},{2,2},{3,3},{4,4},{5,5},{4,4},{3,3},{2,2},{1,1}};
    for(auto& p: m) std::cout << p.first << ' ' << p.second << '\n';

    // 定制比较
    std::multimap<Point, double, PointCmp> mag{
        { {5, 12}, 13 },
        { {3, 4}, 5 },
        { {8, 15}, 17 },
        { {3, -3}, -1 },
    };

  for(auto p : mag)
      std::cout << "The magnitude of (" << p.first.x
                << ", " << p.first.y << ") is "
                << p.second << '\n';
}

输出：

1 1
1 1
2 2
2 2
3 3
3 3
4 4
4 4
5 5
The magnitude of (3, 4) is 5
The magnitude of (3, -3) is -1
The magnitude of (5, 12) is 13
The magnitude of (8, 15) is 17

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2193 | C++11 | 默认构造函数为 explicit | 使之为非 explicit

参阅

operator=
 赋值给容器
(公开成员函数)


std::multimap<Key,T,Compare,Allocator>::operator=

< cpp‎ | container‎ | multimap

multimap& operator=( const multimap& other ); | (1) |
 | (2) |
multimap& operator=( multimap&& other ); |  |  | (C++11 起) (C++17 前)
multimap& operator=( multimap&& other ) noexcept(/* see below */); |  |  | (C++17 起)
multimap& operator=( std::initializer_list <value_type> ilist ); | (3) | (C++11 起)

替换容器内容。

1) 复制赋值运算符。以 other 的副本替换内容。

若 std::allocator_traits <allocator_type>::propagate_on_container_copy_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若 *this 的分配器在赋值后将与其旧值比较不相等，则用旧分配器解分配内存，然后在复制元素前用新分配器分配内存。否则，在可行时可能复用 *this 所拥有的内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素复制赋值替换。

 (C++11 起)
2) 移动赋值运算符。用移动语义以 other 的内容替换内容（即从 other 移动 other 中的数据到此容器中）。之后 other 在合法但未指定的状态。
若 std::allocator_traits <allocator_type>::propagate_on_container_move_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若它为 false 且 *this 与 other 的分配器不比较相等，则 *this 不能接管 other 所拥有的内存的所有权且必须单独地移动赋值每个元素，并用其自身的分配器按需分配额外内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素移动赋值替换。
3) 以 initializer_list ilist 所标识者替换内容。

参数

other | - | 用作数据源的另一容器
ilist | - | 用作数据源的 initializer_list

返回值

*this

复杂度

1) 与 *this 和 other 的大小成线性。
2) 与 *this 的大小成线性，除非分配器不比较相等且不传播，该情况下与 *this 和 other 的大小成线性。
3) 通常为 O(NlogN) ，其中 N 为 size() + ilist.size() 。若 ilist 相对于 value_comp() 已排序则为线性。

异常

可能抛出实现定义的异常。

 (C++17 前)
1,3) 可能抛出实现定义的异常。
2)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value
&& std::is_nothrow_move_assignable <Compare>::value)
 (C++17 起)

注解

在容器移动赋值（重载 (2) ）后，除非不兼容的分配器强制逐元素移动赋值，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

下列代码用 operator= 赋值一个 std::multimap 给另一个：

#include <map>
#include <iostream>

void display_sizes(const std::multimap<int, int> &nums1,
                   const std::multimap<int, int> &nums2,
                   const std::multimap<int, int> &nums3)
{
    std::cout << "nums1: " << nums1.size()
              << " nums2: " << nums2.size()
              << " nums3: " << nums3.size() << '\n';
}

int main()
{
    std::multimap<int, int> nums1 {{3, 1}, {4, 1}, {5, 9},
                                   {6, 1}, {7, 1}, {8, 9}};
    std::multimap<int, int> nums2;
    std::multimap<int, int> nums3;

    std::cout << "Initially:\n";
    display_sizes(nums1, nums2, nums3);

    // 复制赋值从 nums1 复制数据到 nums2
    nums2 = nums1;

    std::cout << "After assigment:\n";
    display_sizes(nums1, nums2, nums3);

    // 移动赋值从 nums1 移动数据到 nums3,
    // 一同修改 nums1 和 nums3
    nums3 = std::move(nums1);

    std::cout << "After move assigment:\n";
    display_sizes(nums1, nums2, nums3);
}

输出：

Initially:
nums1: 6 nums2: 0 nums3: 0
After assigment:
nums1: 6 nums2: 6 nums3: 0
After move assigment:
nums1: 0 nums2: 6 nums3: 6

参阅

(构造函数)
 构造 multimap
(公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::multimap)

< cpp‎ | container‎ | multimap

定义于头文件 <map>
template< class Key, class T, class Compare, class Alloc >

bool operator==( const std::multimap <Key,T,Compare,Alloc>& lhs,

const std::multimap <Key,T,Compare,Alloc>& rhs );
 (1)
template< class Key, class T, class Compare, class Alloc >

bool operator!=( const std::multimap <Key,T,Compare,Alloc>& lhs,

const std::multimap <Key,T,Compare,Alloc>& rhs );
 (2) (C++20 前)
template< class Key, class T, class Compare, class Alloc >

bool operator<( const std::multimap <Key,T,Compare,Alloc>& lhs,

const std::multimap <Key,T,Compare,Alloc>& rhs );
 (3) (C++20 前)
template< class Key, class T, class Compare, class Alloc >

bool operator<=( const std::multimap <Key,T,Compare,Alloc>& lhs,

const std::multimap <Key,T,Compare,Alloc>& rhs );
 (4) (C++20 前)
template< class Key, class T, class Compare, class Alloc >

bool operator>( const std::multimap <Key,T,Compare,Alloc>& lhs,

const std::multimap <Key,T,Compare,Alloc>& rhs );
 (5) (C++20 前)
template< class Key, class T, class Compare, class Alloc >

bool operator>=( const std::multimap <Key,T,Compare,Alloc>& lhs,

const std::multimap <Key,T,Compare,Alloc>& rhs );
 (6) (C++20 前)
template< class Key, class T, class Compare, class Alloc >

/* see below */ operator<=>( const std::multimap <Key,T,Compare,Alloc>& lhs,

const std::multimap <Key,T,Compare,Alloc>& rhs );
 (7) (C++20 起)

比较二个 multimap 的内容。

1-2) 检查 lhs 与 rhs 的内容是否相等，即它们是否拥有相同数量的元素且 lhs 中每个元素与 rhs 的同位置元素比较相等。
3-6) 按字典序比较 lhs 与 rhs 的内容。由等价于 std::lexicographical_compare 的函数进行比较。此比较忽略 multimap 的定序 Compare 。
7) 按字典序比较 lhs 与 rhs 的内容。如同通过在二个 multimap 上以进行合成三路比较（见后述）的函数对象调用 std::lexicographical_compare_three_way 进行比较。返回类型同合成三路比较的结果类型。此比较忽略 multimap 的定序 Compare 。

给定分别作为左操作数与右操作数的两个 const E 左值 lhs 与 rhs （其中 E 为 std::pair <const Key, T> ），合成三路比较定义如下：

  • 若 std::three_way_comparable_with<E, E> 得到满足则等价于 lhs <=> rhs ；
  • 否则，若以 operator< 比较二个 const E 左值为良构且结果类型满足 boolean-testable ，则等价于
lhs < rhs ? std::weak_ordering::less :
rhs < lhs ? std::weak_ordering::greater :
            std::weak_ordering::equivalent
  • 否则，不定义合成三路比较，而 operator<=> 不参与重载决议。
若 three_way_comparable_with 或 boolean-testable 被满足但未被实现，或使用 operator< 但 E 与 < 不建立全序，则 operator<=> 的行为未定义。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较内容的 multimap
-
为使用重载 (1-2) ， T, Key 必须满足可相等比较 (EqualityComparable) 的要求。
-
为使用重载 (3-6) ， Key 必须满足可小于比较 (LessThanComparable) 的要求。顺序关系必须建立全序。

返回值

1) 若 multimap 内容相等则为 true ，否则为 false
2) 若 multimap 内容不相等则为 true ，否则为 false
3) 若 lhs 的内容按字典序小于 rhs 的内容则为 true ，否则为 false
4) 若 lhs 的内容按字典序小于或等于 rhs 的内容则为 true ，否则为 false
5) 若 lhs 的内容按字典序大于 rhs 的内容则为 true ，否则为 false
6) 若 lhs 的内容按字典序大于或等于 rhs 的内容则为 true ，否则为 false
7) lhs 与 rhs 中的首对不等价元素的相对顺序，若有这种元素；否则为 lhs.size() <=> rhs.size() 。

复杂度

1-2) 若 lhs 与 rhs 的大小不同则为常数，否则与 multimap 大小成线性
3-7) 与 multimap 大小成线性

示例

#include <iostream>
#include <map>

int main()
{
    std::multimap<int, char> alice{{1, 'a'}, {2, 'b'}, {3, 'c'}};
    std::multimap<int, char> bob{{7, 'Z'}, {8, 'Y'}, {9, 'X'}, {10, 'W'}};
    std::multimap<int, char> eve{{1, 'a'}, {2, 'b'}, {3, 'c'}};

    std::cout << std::boolalpha;

    // 比较不相等的容器
    std::cout << "alice == bob returns " << (alice == bob) << '\n';
    std::cout << "alice != bob returns " << (alice != bob) << '\n';
    std::cout << "alice <  bob returns " << (alice < bob) << '\n';
    std::cout << "alice <= bob returns " << (alice <= bob) << '\n';
    std::cout << "alice >  bob returns " << (alice > bob) << '\n';
    std::cout << "alice >= bob returns " << (alice >= bob) << '\n';

    std::cout << '\n';

    // 比较相等的容器
    std::cout << "alice == eve returns " << (alice == eve) << '\n';
    std::cout << "alice != eve returns " << (alice != eve) << '\n';
    std::cout << "alice <  eve returns " << (alice < eve) << '\n';
    std::cout << "alice <= eve returns " << (alice <= eve) << '\n';
    std::cout << "alice >  eve returns " << (alice > eve) << '\n';
    std::cout << "alice >= eve returns " << (alice >= eve) << '\n';
}

输出：

alice == bob returns false
alice != bob returns true
alice <  bob returns true
alice <= bob returns true
alice >  bob returns false
alice >= bob returns false

alice == eve returns true
alice != eve returns false
alice <  eve returns false
alice <= eve returns true
alice >  eve returns false
alice >= eve returns true


std::multimap<Key,T,Compare,Allocator>::rbegin, std::multimap<Key,T,Compare,Allocator>::crbegin

< cpp‎ | container‎ | multimap

reverse_iterator rbegin(); | (C++11 前)
reverse_iterator rbegin() noexcept; | (C++11 起)
const_reverse_iterator rbegin() const; | (C++11 前)
const_reverse_iterator rbegin() const noexcept; | (C++11 起)
const_reverse_iterator crbegin() const noexcept; | (C++11 起)

返回指向逆向 multimap 首元素的逆向迭代器。它对应非逆向 multimap 的末元素。若 multimap 为空，则返回的迭代器等于 rend() 。

参数

（无）

返回值

指向首元素的逆向迭代器。

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)


std::multimap<Key,T,Compare,Allocator>::rend, std::multimap<Key,T,Compare,Allocator>::crend

< cpp‎ | container‎ | multimap

reverse_iterator rend(); | (C++11 前)
reverse_iterator rend() noexcept; | (C++11 起)
const_reverse_iterator rend() const; | (C++11 前)
const_reverse_iterator rend() const noexcept; | (C++11 起)
const_reverse_iterator crend() const noexcept; | (C++11 起)

返回指向逆向 multimap 末元素后一元素的逆向迭代器。它对应非逆向 multimap 首元素的前一元素。此元素表现为占位符，试图访问它导致未定义行为。

参数

（无）

返回值

指向末元素后一元素的逆向迭代器。

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)


std::multimap<Key,T,Compare,Allocator>::size

< cpp‎ | container‎ | multimap

size_type size() const; | (C++11 前)
size_type size() const noexcept; | (C++11 起)

返回容器中的元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

容器中的元素数量。

复杂度

常数。

示例

下列代码用 size 显示 std::multimap 中的元素数：

#include <map>
#include <iostream>

int main()
{
    std::multimap<int,char> nums {{1, 'a'}, {3, 'b'}, {5, 'c'}, {7, 'd'}};

    std::cout << "nums contains " << nums.size() << " elements.\n";
}

输出：

nums contains 4 elements.

参阅

empty | 检查容器是否为空 (公开成员函数)
max_size | 返回可容纳的最大元素数 (公开成员函数)


std::multimap<Key,T,Compare,Allocator>::swap

< cpp‎ | container‎ | multimap

void swap( multimap& other ); | (C++17 前)
void swap( multimap& other ) noexcept(/* see below */); | (C++17 起)

将内容与 other 的交换。不在单独的元素上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。尾后迭代器被非法化。

Pred 对象必须可交换 (Swappable) ，并用非成员 swap 的非限定调用交换它们。

若 std::allocator_traits <allocator_type>::propagate_on_container_swap::value 为 true ，则用对非成员 swap 的无限定调用交换分配器。否则，不交换它们（且若 get_allocator() != other.get_allocator() ，则行为未定义）。

 (C++11 起)

参数

other - 要与之交换内容的容器

返回值

（无）

异常

任何 Compare 对象交换所抛的异常。

 (C++17 前)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value
&& std::is_nothrow_swappable <Compare>::value)
 (C++17 起)

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

std::swap(std::multimap)
 特化 std::swap 算法
(函数模板)


std::swap(std::multimap)

< cpp‎ | container‎ | multimap

定义于头文件 <map>
template< class Key, class T, class Compare, class Alloc >

void swap( std::multimap <Key,T,Compare,Alloc>& lhs,

std::multimap <Key,T,Compare,Alloc>& rhs );
 (C++17 前)
template< class Key, class T, class Compare, class Alloc >

void swap( std::multimap <Key,T,Compare,Alloc>& lhs,

std::multimap <Key,T,Compare,Alloc>& rhs ) noexcept(/* see below */);
 (C++17 起)

为 std::multimap 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

#include <algorithm>
#include <iostream>
#include <map>

int main()
{
    std::multimap<int, char> alice{{1, 'a'}, {2, 'b'}, {3, 'c'}};
    std::multimap<int, char> bob{{7, 'Z'}, {8, 'Y'}, {9, 'X'}, {10, 'W'}};

    auto print = [](std::pair<const int, char>& n) {
        std::cout << " " << n.first << '(' << n.second << ')';
    };

    // 打印交换前的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';

    std::cout << "-- SWAP\n";
    std::swap(alice,bob);

    // 打印交换后的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
}

输出：

alice: 1(a) 2(b) 3(c)
bob  : 7(Z) 8(Y) 9(X) 10(W)
-- SWAP
alice: 7(Z) 8(Y) 9(X) 10(W)
bob  : 1(a) 2(b) 3(c)

参阅

swap
 交换内容
(公开成员函数)


std::multimap<Key,T,Compare,Allocator>::upper_bound

< cpp‎ | container‎ | multimap

iterator upper_bound( const Key& key ); | (1) |
const_iterator upper_bound( const Key& key ) const; | (1) |
template< class K > iterator upper_bound( const K& x ); | (2) | (C++14 起)
template< class K > const_iterator upper_bound( const K& x ) const; | (2) | (C++14 起)
1) 返回指向首个大于 key 的元素的迭代器。
2) 返回指向首个比较大于值 x 的元素的迭代器。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 与元素比较的键值
x | - | 能与 Key 比较的替用值

返回值

指向首个大于 key 的元素的迭代器。若找不到这种元素，则返回尾后（见 end() ）迭代器。

复杂度

与容器大小成对数。

参阅

equal_range | 返回匹配特定键的元素范围 (公开成员函数)
lower_bound | 返回指向首个不小于给定键的元素的迭代器 (公开成员函数)


std::multimap<Key,T,Compare,Allocator>::value_comp

< cpp‎ | container‎ | multimap

std::multimap::value_compare value_comp() const;

返回比较 std::multimap::value_type （关键-值 pair ）对象的函数对象，它用 key_comp 比较 pair 的第一组分。

参数

（无）

返回值

比较值的函数对象。

复杂度

常数。

参阅

key_comp
 返回用于比较键的函数
(公开成员函数)


std::multimap<Key,T,Compare,Allocator>::value_compare

< cpp‎ | container‎ | multimap

class value_compare;

std::multimap::value_compare 是函数对象，通过比较 pair 的首组分比较 std::multimap::value_type （关键-值 pair ）类型对象。

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | bool
first_argument_type (C++17 中弃用)(C++20 中移除) | value_type
second_argument_type (C++17 中弃用)(C++20 中移除) | value_type

这些成员类型由公开继承 std::binary_function <value_type, value_type, bool> 获得。

 (C++11 前)

受保护成员对象

Compare comp
 存储的比较器
(受保护成员对象)

成员函数

(构造函数) | 构造新的 value_compare 对象 (受保护成员函数)
operator() | 比较两个 value_type 类型的值 (公开成员函数)

std::multimap<Key,T,Compare,Alloc>::value_compare::value_compare

protected:
value_compare( Compare c );

初始化内部比较器的实例为 c 。

参数

c - 要赋值的比较器

std::multimap<Key,T,Compare,Alloc>::value_compare::operator()

bool operator()( const value_type& lhs, const value_type& rhs ) const;

通过调用存储的比较器比较 lhs.first 与 rhs.first 。

参数

lhs, rhs - 要比较的值

返回值

comp(lhs.first, rhs.first) 。

异常

可能抛出实现定义的异常。


std::multimap<Key,T,Compare,Allocator>::~multimap

< cpp‎ | container‎ | multimap

~multimap();

销毁 multimap 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 multimap 大小成线性。


std::multiset

< cpp‎ | container
定义于头文件 <set>
template<

class Key,
class Compare = std::less <Key>,
class Allocator = std::allocator <Key>

> class multiset;
 (1)
namespace pmr {

template <class Key, class Compare = std::less <Key>>
using multiset = std::multiset<Key, Compare,
std::pmr::polymorphic_allocator <Key>>;

}
 (2) (C++17 起)

std::multiset 是含有 Key 类型对象有序集的容器。不同于 set ，它允许多个 Key 拥有等价的值。用关键比较函数 Compare 进行排序。搜索、插入和移除操作拥有对数复杂度。

在标准库使用比较 (Compare) 概念的每处，都用描述于比较 (Compare) 的等价关系确定等价性。不精确地说，若二个对象 a 和 b 互不比较小于对方： !comp(a, b) && !comp(b, a) ，则认为它们等价。

比较等价的元素顺序是插入顺序，而且不会更改。(C++11 起)

std::multiset 满足容器 (Container) 、知分配器容器 (AllocatorAwareContainer) 、关联容器 (AssociativeContainer) 和可逆容器 (ReversibleContainer) 的要求。

成员类型

成员类型 | 定义
key_type | Key
value_type | Key
size_type | 无符号整数类型（通常是 std::size_t ）
difference_type | 有符号整数类型（通常是 std::ptrdiff_t ）
key_compare | Compare
value_compare | Compare
allocator_type | Allocator
reference | value_type&
const_reference | const value_type&
pointer
Allocator::pointer | (C++11 前)
std::allocator_traits <Allocator>::pointer | (C++11 起)
const_pointer
Allocator::const_pointer | (C++11 前)
std::allocator_traits <Allocator>::const_pointer | (C++11 起)
iterator | 指向 value_type 的常老式双向迭代器 (LegacyBidirectionalIterator)
const_iterator | 指向 const value_type 的老式双向迭代器 (LegacyBidirectionalIterator)
reverse_iterator | std::reverse_iterator <iterator>
const_reverse_iterator | std::reverse_iterator <const_iterator>
node_type(C++17 起) | 表示容器结点的结点把柄特化

成员函数

(构造函数)
 构造 multiset
(公开成员函数)
(析构函数)
 析构 multiset
(公开成员函数)
operator=
 赋值给容器
(公开成员函数)
get_allocator
 返回相关的分配器
(公开成员函数)
迭代器
begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)
rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)
rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)
容量
empty
 检查容器是否为空
(公开成员函数)
size
 返回容纳的元素数
(公开成员函数)
max_size
 返回可容纳的最大元素数
(公开成员函数)
修改器
clear
 清除内容
(公开成员函数)
insert
 插入元素或结点 (C++17 起)
(公开成员函数)
emplace
(C++11)
 原位构造元素
(公开成员函数)
emplace_hint
(C++11)
 使用提示原位构造元素
(公开成员函数)
erase
 擦除元素
(公开成员函数)
swap
 交换内容
(公开成员函数)
extract
(C++17)
 从另一容器释出结点
(公开成员函数)
merge
(C++17)
 从另一容器接合结点
(公开成员函数)
查找
count
 返回匹配特定键的元素数量
(公开成员函数)
find
 寻找带有特定键的元素
(公开成员函数)
contains
(C++20)
 检查容器是否含有带特定键的元素
(公开成员函数)
equal_range
 返回匹配特定键的元素范围
(公开成员函数)
lower_bound
 返回指向首个不小于给定键的元素的迭代器
(公开成员函数)
upper_bound
 返回指向首个大于给定键的元素的迭代器
(公开成员函数)
观察器
key_comp
 返回用于比较键的函数
(公开成员函数)
value_comp
 返回用于在value_type类型的对象中比较键的函数。
(公开成员函数)

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 按照字典顺序比较 multiset 中的值 (函数模板)
std::swap(std::multiset) | 特化 std::swap 算法 (函数模板)
erase_if(std::multiset) (C++20) | 擦除所有满足特定判别标准的元素 (函数模板)

推导指引 (C++17 起)

注意

成员类型 iterator 与 const_iterator 可能是同一类型的别名。这表明以二个类型为参数类型的一对函数重载可能违背单一定义规则。因为 iterator 可转换为 const_iterator ，单个以 const_iterator 为参数类型的函数会是有效的。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 103 | C++98 | 迭代器允许修改关键 | 使迭代器为常


std::multiset<Key,Compare,Allocator>::begin, std::multiset<Key,Compare,Allocator>::cbegin

< cpp‎ | container‎ | multiset

iterator begin(); | (C++11 前)
iterator begin() noexcept; | (C++11 起)
const_iterator begin() const; | (C++11 前)
const_iterator begin() const noexcept; | (C++11 起)
const_iterator cbegin() const noexcept; | (C++11 起)

返回指向 multiset 首元素的迭代器。

若 multiset 为空，则返回的迭代器将等于 end() 。

参数

（无）

返回值

指向首元素的迭代器。

复杂度

常数。

注意

因为 iterator 和 const_iterator 都是常迭代器（而且实际上可以是同一类型），故不可能通过任何这些成员函数返回的迭代器修改容器元素。

示例

#include <iostream>
#include <iterator>
#include <set>
#include <string>

int main()
{
    const std::multiset<std::string> words = {
        "some", "not", "sorted", "words",
        "will", "come", "out", "sorted",
    };

    for (auto it = words.begin(); it != words.end(); ) {
        auto cnt = words.count(*it);
        std::cout << *it << ":\t" << cnt << '\n';
        std::advance(it, cnt); // 所有元素均拥有等价的键
    }
}

输出：

come:  1
not:    1
out:    1
some:   1
sorted: 2
will:   1
words:  1

参阅

end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)


std::multiset<Key,Compare,Allocator>::clear

< cpp‎ | container‎ | multiset

void clear(); | (C++11 前)
void clear() noexcept; | (C++11 起)

从容器擦除所有元素。此调用后 size() 返回零。

非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器保持合法。

参数

（无）

返回值

（无）

复杂度

与容器大小，即元素数成线性。

示例

#include <algorithm>
#include <iostream>
#include <set>

int main()
{
    std::multiset<int> container{1, 2, 3};

    auto print = [](const int& n) { std::cout << " " << n; };

    std::cout << "Before clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';

    std::cout << "Clear\n";
    container.clear();

    std::cout << "After clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';
}

输出：

Before clear: 1 2 3
Size=3
Clear
After clear:
Size=0

参阅

erase
 擦除元素
(公开成员函数)


std::multiset<Key,Compare,Allocator>::contains

< cpp‎ | container‎ | multiset

bool contains( const Key& key ) const; | (1) | (C++20 起)
template< class K > bool contains( const K& x ) const; | (2) | (C++20 起)
1) 检查容器中是否有键等价于 key 的元素。
2) 检查是否有键比较等价于值 x 的元素。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 任何能通透地与键比较的类型的值

返回值

若有这种元素则为 true ，否则为 false 。

复杂度

与容器大小成对数。

示例

#include <iostream>
#include <set>

int main()
{
    std::multiset<int> example = {1, 2, 3, 4};

    for(int x: {2, 5}) {
        if(example.contains(x)) {
            std::cout << x << ": Found\n";
        } else {
            std::cout << x << ": Not found\n";
        }
    }
}

输出：

2: Found
5: Not found

参阅

find | 寻找带有特定键的元素 (公开成员函数)
count | 返回匹配特定键的元素数量 (公开成员函数)
equal_range | 返回匹配特定键的元素范围 (公开成员函数)


std::multiset<Key,Compare,Allocator>::count

< cpp‎ | container‎ | multiset

size_type count( const Key& key ) const; | (1) |
template< class K > size_type count( const K& x ) const; | (2) | (C++14 起)

返回拥有关键比较等价于指定参数的元素数。

1) 返回拥有关键 key 的元素数。
2) 返回拥有关键比较等价于值 x 的元素数。此重载仅若有限定 id Compare::is_transparent 合法且指代一个类型才参与重载决议。这允许调用此函数而不构造 Key 的实例。

参数

key | - | 要计量元素数的关键值
x | - | 要与关键比较的替用值

返回值

拥有比较等价于 key 或 x 的关键的元素数。

复杂度

与容器大小成对数，加上与找到的元素数成线性。

参阅

find | 寻找带有特定键的元素 (公开成员函数)
equal_range | 返回匹配特定键的元素范围 (公开成员函数)


std::multiset 的推导指引

< cpp‎ | container‎ | multiset

定义于头文件 <set>
template<class InputIt,

class Comp = std::less <typename std::iterator_traits <InputIt>::value_type>,
class Alloc = std::allocator <typename std::iterator_traits <InputIt>::value_type>>
multiset(InputIt, InputIt, Comp = Comp(), Alloc = Alloc())

-> multiset<typename std::iterator_traits <InputIt>::value_type, Comp, Alloc>;
 (1) (C++17 起)
template<class Key, class Comp = std::less <Key>, class Alloc = std::allocator <Key>>

multiset( std::initializer_list <Key>, Comp = Comp(), Alloc = Alloc())

-> multiset<Key, Comp, Alloc>;
 (2) (C++17 起)
template<class InputIt, class Alloc>

multiset(InputIt, InputIt, Alloc)
-> multiset<typename std::iterator_traits <InputIt>::value_type,

std::less <typename std::iterator_traits <InputIt>::value_type>, Alloc>;
 (3) (C++17 起)
template<class Key, class Alloc>

multiset( std::initializer_list <Key>, Alloc)

-> multiset<Key, std::less <Key>, Alloc>;
 (4) (C++17 起)

为 multiset 提供这些推导指引以允许从范围（重载 (1,3) ）和 std::initializer_list （重载 (2,4) ）推导。此重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 、 Alloc 满足分配器 (Allocator) 且 Comp 不满足分配器 (Allocator) 才参与重载决议。

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

示例

#include <set>
int main() {
   std::multiset s = {1,2,3,4}; // 指引 #2 推导 std::multiset<int>
   std::multiset s2(s.begin(), s.end()); // 指引 #1 推导 std::multiset<int>
}


std::multiset<Key,Compare,Allocator>::emplace

< cpp‎ | container‎ | multiset

template< class... Args > iterator emplace( Args&&... args ); | (C++11 起)

插入以给定的 args 原位构造的新元素到容器。

细心地使用 emplace 允许在构造新元素的同时避免不必要的复制或移动操作。 准确地以与提供给 emplace 者相同的参数，通过 std::forward <Args>(args)... 转发调用新元素的构造函数。

没有迭代器或引用被非法化。

参数

args - 要转发给元素构造函数的参数

返回值

指向被插入元素的迭代器。

异常

若任何操作抛出异常，则此函数无效果。

复杂度

与容器大小成对数。

示例

本节未完成
原因：暂无示例

参阅

emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)


std::multiset<Key,Compare,Allocator>::emplace_hint

< cpp‎ | container‎ | multiset
template <class... Args> iterator emplace_hint( const_iterator hint, Args&&... args ); | (C++11 起)

插入新元素到尽可能靠近恰在 hint 前的位置。原位构造元素，即不进行复制或移动操作。

准确地以同提供给函数的参数者，以 std::forward <Args>(args)... 转发调用元素的构造函数。

没有迭代器或引用被非法化。

参数

hint | - | 指向将新元素插入其前的位置的迭代器
args | - | 转发给元素构造函数的参数

返回值

返回指向新插入元素的迭代器。

异常

若任何操作抛出异常，则此函数无效果（强异常保证）。

复杂度

通常与容器大小成对数，但若新元素正好插入到 hint 之前则为均摊常数。

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)


std::multiset<Key,Compare,Allocator>::empty

< cpp‎ | container‎ | multiset

bool empty() const; | (C++11 前)
bool empty() const noexcept; | (C++11 起) (C++20 前)
[[nodiscard]] bool empty() const noexcept; | (C++20 起)

检查容器是否无元素，即是否 begin() == end() 。

参数

（无）

返回值

若容器为空则为 true ，否则为 false

复杂度

常数。

示例

下列代码用 empty 检查 std::multiset <int> 是否含任何元素：

#include <set>
#include <iostream>

int main()
{
    std::multiset<int> numbers;
    std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';

    numbers.insert(42);
    numbers.insert(13317);
    std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
}

输出：

Initially, numbers.empty(): 1
After adding elements, numbers.empty(): 0

参阅

size
 返回容纳的元素数
(公开成员函数)


std::multiset<Key,Compare,Allocator>::end, std::multiset<Key,Compare,Allocator>::cend

< cpp‎ | container‎ | multiset

iterator end(); | (C++11 前)
iterator end() noexcept; | (C++11 起)
const_iterator end() const; | (C++11 前)
const_iterator end() const noexcept; | (C++11 起)
const_iterator cend() const noexcept; | (C++11 起)

返回指向 multiset 末元素后一元素的迭代器。

此元素表现为占位符；试图访问它导致未定义行为。

参数

（无）

返回值

指向后随最后元素的迭代器。

复杂度

常数。

注意

因为 iterator 和 const_iterator 都是常迭代器（而且实际上可以是同一类型），故不可能通过任何这些成员函数返回的迭代器修改容器元素。

示例

#include <iostream>
#include <iterator>
#include <set>
#include <string>

int main()
{
    const std::multiset<std::string> words = {
        "some", "not", "sorted", "words",
        "will", "come", "out", "sorted",
    };

    for (auto it = words.begin(); it != words.end(); ) {
        auto cnt = words.count(*it);
        std::cout << *it << ":\t" << cnt << '\n';
        std::advance(it, cnt); // 所有元素均拥有等价的键
    }
}

输出：

come:  1
not:    1
out:    1
some:   1
sorted: 2
will:   1
words:  1

参阅

begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)


std::multiset<Key,Compare,Allocator>::equal_range

< cpp‎ | container‎ | multiset

std::pair <iterator,iterator> equal_range( const Key& key ); | (1) |
std::pair <const_iterator,const_iterator> equal_range( const Key& key ) const; | (2) |
template< class K > std::pair <iterator,iterator> equal_range( const K& x ); | (3) | (C++14 起)
template< class K > std::pair <const_iterator,const_iterator> equal_range( const K& x ) const; | (4) | (C++14 起)

返回容器中所有拥有给定关键的元素范围。范围以二个迭代器定义，一个指向首个不小于 key 的元素，另一个指向首个大于 key 的元素。首个迭代器可以换用 lower_bound() 获得，而第二迭代器可换用 upper_bound() 获得。

1,2) 比较关键与 key 。
3,4) 比较关键与值 x 。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。
本节未完成
原因：更好地解释

参数

key | - | 要比较元素的关键值
x | - | 能与 Key 比较的替用值

返回值

含一对定义所需范围的迭代器的 std::pair ：第一个指向首个不小于 key 的元素，第二个指向首个大于 key 的元素。

若无元素不小于 key ，则将尾后（见 end() ）迭代器作为第一元素返回。类似地，若无元素大于 key ，则将尾后迭代器作为第二元素返回。

因为 emplace 和无提示的 insert 始终在上界插入，相等范围中等价元素的顺序就是插入顺序，除非用有提示的 insert 或 emplace_hint 在不同的位置插入元素。

 (C++11 起)

复杂度

与容器大小成对数。

示例

#include <set>
#include <iostream>

template <typename I>
void print_equal_range(I first, I lb, I ub, I last) {
    for (I i{first}; i != lb; ++i)
        std::cout << *i << " ";
    std::cout << "[ ";
    for (I i{lb}; i != ub; ++i)
        std::cout << *i << " ";
    std::cout << ") ";
    for (I i{ub}; i != last; ++i)
        std::cout << *i << " ";
    std::cout << '\n';
}

int main()
{
    std::multiset<int> c{4, 3, 2, 1, 3, 3};
    std::cout << "c = ";
    print_equal_range(begin(c), begin(c), end(c), end(c));
    for (int key{}; key != 6; ++key) {
        std::cout << "key = " << key << "; equal range = ";
        const auto [lb, ub] = c.equal_range(key);
        print_equal_range(begin(c), lb, ub, end(c));
    }
}

输出：

c = [ 1 2 3 3 3 4 )
key = 0; equal range = [ ) 1 2 3 3 3 4
key = 1; equal range = [ 1 ) 2 3 3 3 4
key = 2; equal range = 1 [ 2 ) 3 3 3 4
key = 3; equal range = 1 2 [ 3 3 3 ) 4
key = 4; equal range = 1 2 3 3 3 [ 4 )
key = 5; equal range = 1 2 3 3 3 4 [ )

参阅

find | 寻找带有特定键的元素 (公开成员函数)
contains (C++20) | 检查容器是否含有带特定键的元素 (公开成员函数)
count | 返回匹配特定键的元素数量 (公开成员函数)
upper_bound | 返回指向首个大于给定键的元素的迭代器 (公开成员函数)
lower_bound | 返回指向首个不小于给定键的元素的迭代器 (公开成员函数)
equal_range | 返回匹配特定键值的元素范围 (函数模板)


std::multiset<Key,Compare,Allocator>::erase

< cpp‎ | container‎ | multiset

 | (1) |
void erase( iterator pos ); |  |  | (C++11 前)
iterator erase( iterator pos ); |  |  | (C++11 起)
iterator erase( const_iterator pos ); |  |  | (C++11 起)
 | (2) |
void erase( iterator first, iterator last ); |  |  | (C++11 前)
iterator erase( const_iterator first, const_iterator last ); |  |  | (C++11 起)
size_type erase( const key_type& key ); | (3) |
template< class K > size_type erase( K&& x ); | (4) | (C++23 起)

从容器移除指定的元素。

1) 移除位于 pos 的元素。若 iterator 与 const_iterator 为同一类型则仅提供一个重载。 (C++11 起)
2) 移除范围 [first; last) 中的元素，它必须是 *this 中的合法范围。
3) 移除键等价于 key 的所有元素。
4) 移除键比较等价于值 x 的所有元素。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

指向被擦除元素的引用和迭代器被非法化。其他引用和迭代器不受影响。

迭代器 pos 必须合法且可解引用。从而 end() 迭代器（合法，但不可解引用）不能用作 pos 所用的值。

参数

pos | - | 指向要移除的元素的迭代器
first, last | - | 要移除的元素范围
key | - | 要移除的元素键值
x | - | 任何能与键通透比较的类型的值，指代要移除的元素

返回值

1-2) （无） (C++11 前)后随最后被移除的元素的迭代器。 (C++11 起)
3,4) 被移除的元素数。

异常

1,2) 不抛出
3,4) 任何 Compare 对象所抛的异常

复杂度

给定 multiset 的实例 c ：

1) 均摊常数
2) log(c.size()) + std::distance (first, last)
3) log(c.size()) + c.count(key)
4) log(c.size()) + c.count(x)

示例

#include <set>
#include <iostream>
int main()
{
    std::multiset<int> c = { 1, 2, 3, 4,    1, 2, 3, 4 };

    auto print = [&c] {
        std::cout << "c = { ";
        for(int n : c)
            std::cout << n << ' ';
        std::cout << "}\n";
    };
    print();

    std::cout << "Erase all odd numbers:\n";
    for(auto it = c.begin(); it != c.end(); ) {
        if(*it % 2 != 0)
            it = c.erase(it);
        else
            ++it;
    }
    print();

    std::cout << "Erase 1, erased count: " << c.erase(1) << '\n';
    std::cout << "Erase 2, erased count: " << c.erase(2) << '\n';
    std::cout << "Erase 2, erased count: " << c.erase(2) << '\n';
    print();
}

输出：

c = { 1 1 2 2 3 3 4 4 }
Erase all odd numbers:
c = { 2 2 4 4 }
Erase 1, erased count: 0
Erase 2, erased count: 2
Erase 2, erased count: 0
c = { 4 4 }

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2059 | C++11 | 对一个 const_iterator 的重载引入了新的歧义 | 添加了对 iterator 的重载

参阅

clear
 清除内容
(公开成员函数)


std::erase_if (std::multiset)

< cpp‎ | container‎ | multiset

定义于头文件 <set>
template< class Key, class Compare, class Alloc, class Pred >

typename std::multiset <Key,Compare,Alloc>::size_type

erase_if( std::multiset <Key,Compare,Alloc>& c, Pred pred);
 (C++20 起)

从容器中擦除所有满足谓词 pred 的元素。等价于

auto old_size = c.size();
for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}
return old_size - c.size();

参数

c | - | 要从中擦除的元素
pred | - | 若应该擦除元素则对它返回 true 的谓词

返回值

擦除的元素数。

复杂度

线性。

示例

#include <set>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& container)
{
    os << "{ ";
    for (const auto& item : container) {
        os << item << ' ';
    }
    return os << "}";
}

int main()
{
    std::multiset data { 0, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7 };
    std::cout << "Original:\n" << data << '\n';

    auto divisible_by_3 = [](auto const& x) { return (x % 3) == 0; };

    const auto count = std::erase_if(data, divisible_by_3);

    std::cout << "Erase all items divisible by 3:\n" << data << '\n'
              << count << " items erased.\n";
}

输出：

Original:
{ 0 1 2 3 3 4 5 5 6 6 7 }
Erase all items divisible by 3:
{ 1 2 4 5 5 7 }
5 items erased.

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::multiset<Key,Compare,Allocator>::extract

< cpp‎ | container‎ | multiset

node_type extract( const_iterator position ); | (1) | (C++17 起)
node_type extract( const key_type& k ); | (2) | (C++17 起)
template< class K > node_type extract( K&& x ); | (3) | (C++23 起)
1) 解链含 position 所指向元素的结点并返回占有它的结点柄。
2) 若容器拥有元素而其关键等于 x ，则从容器解链首个这种元素并返回占有它的结点柄。否则，返回空结点柄。
3) 同 (2) 。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

任何情况下，均不复制或移动元素，只重指向容器结点的内部指针（可能出现再平衡，和 erase() 一样）。

释出结点只会非法化指向被释出元素的迭代器。指向被释出元素的指针和引用保持合法，但在结点柄占有该元素时不能使用：若元素被插入容器，就能使用它们。

参数

position | - | 指向此容器中的合法迭代器
k | - | 鉴别要被释出的结点的键
x | - | 任何能与键通透比较的类型的值，鉴别要释出的结点

返回值

占有被释出元素的结点柄，或 (2,3) 中找不到元素的情况下为空结点柄。

复杂度

1) 均摊常数
2,3) log(a.size())

注解

extract 是从 set 带走仅移动对象的唯一方式：

set<move_only_type> s;
s.emplace(...);
move_only_type mot = move(s.extract(s.begin()).value());

示例

#include <algorithm>
#include <iostream>
#include <set>

int main()
{
    std::multiset<int> cont{1, 2, 3};

    auto print = [](const int& n) { std::cout << " " << n; };

    std::cout << "Start:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 释出结点柄并更改键
    auto nh = cont.extract(1);
    nh.value() = 4;

    std::cout << "After extract and before insert:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 往回插入结点柄
    cont.insert(move(nh));

    std::cout << "End:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';
}

输出：

Start: 1 2 3
After extract and before insert: 2 3
End: 2 3 4

参阅

merge (C++17) | 从另一容器接合结点 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)
erase | 擦除元素 (公开成员函数)


std::multiset<Key,Compare,Allocator>::find

< cpp‎ | container‎ | multiset

iterator find( const Key& key ); | (1) |
const_iterator find( const Key& key ) const; | (2) |
template< class K > iterator find( const K& x ); | (3) | (C++14 起)
template< class K > const_iterator find( const K& x ) const; | (4) | (C++14 起)
1,2) 寻找键等于 key 的的元素。
3,4) 寻找键比较等价于值 x 的元素。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 能通透地与键比较的任何类型值

返回值

指向键等于 key 的元素的迭代器。若找不到这种元素，则返回尾后（见 end() ）迭代器。

复杂度

与容器大小成对数。

示例

#include <iostream>
#include <set>

struct FatKey   { int x; int data[1000]; };
struct LightKey { int x; };
// 注：如上详述，容器必须使用 std::less<> （或其他通透比较器）以访问这些重载。
// 这包括标准重载，例如在 std::string 与 std::string_view 之间。
bool operator<(const FatKey& fk, const LightKey& lk) { return fk.x < lk.x; }
bool operator<(const LightKey& lk, const FatKey& fk) { return lk.x < fk.x; }
bool operator<(const FatKey& fk1, const FatKey& fk2) { return fk1.x < fk2.x; }

int main()
{
// 简单比较演示
    std::multiset<int> example = {1, 2, 3, 4};

    auto search = example.find(2);
    if (search != example.end()) {
        std::cout << "Found " << (*search) << '\n';
    } else {
        std::cout << "Not found\n";
    }

// 通透比较演示
    std::multiset<FatKey, std::less<>> example2 = { {1, {} }, {2, {} }, {3, {} }, {4, {} } };

    LightKey lk = {2};
    auto search2 = example2.find(lk);
    if (search2 != example2.end()) {
        std::cout << "Found " << search2->x << '\n';
    } else {
        std::cout << "Not found\n";
    }

}

输出：

Found 2
Found 2

参阅

count | 返回匹配特定键的元素数量 (公开成员函数)
equal_range | 返回匹配特定键的元素范围 (公开成员函数)


std::multiset<Key,Compare,Allocator>::get_allocator

< cpp‎ | container‎ | multiset

allocator_type get_allocator() const; | (C++11 前)
allocator_type get_allocator() const noexcept; | (C++11 起)

返回与容器关联的分配器。

参数

（无）

返回值

关联的分配器。

复杂度

常数。


std::multiset<Key,Compare,Allocator>::insert

< cpp‎ | container‎ | multiset
iterator insert( const value_type& value ); | (1) |
iterator insert( value_type&& value ); | (2) | (C++11 起)
 | (3) |
iterator insert( iterator hint, const value_type& value ); |  |  | (C++11 前)
iterator insert( const_iterator hint, const value_type& value ); |  |  | (C++11 起)
iterator insert( const_iterator hint, value_type&& value ); | (4) | (C++11 起)
template< class InputIt > void insert( InputIt first, InputIt last ); | (5) |
void insert( std::initializer_list <value_type> ilist ); | (6) | (C++11 起)
iterator insert(node_type&& nh); | (7) | (C++17 起)
iterator insert(const_iterator hint, node_type&& nh); | (8) | (C++17 起)

插入元素到容器。

1-2) 插入 value 。若容器拥有带等价关键的元素，则插入到范围上界。(C++11 起).
3-4) 插入 value 到尽可能接近，正好前于(C++11 起) hint 的位置。
5) 插入来自范围 [first, last) 的元素。
6) 插入来自 initializer_list ilist 的元素。
7) 若 nh 是空的结点把柄，则不做任何事。否则插入 nh 所占有的元素到容器并返回指向被插入元素的迭代器。若范围含有关键等价于存在于容器中的 nh.key() 的关键，则在范围结尾插入元素。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。
8) 若 nh 是空的结点把柄，则不做任何事并返回尾迭代器。否则，插入 nh 所占有的元素到容器，并返回指向拥有等于 nh.key() 的关键的元素的迭代器元素被插入到尽可能接近正好先于 hint 的位置。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。

没有迭代器或引用被非法化。若插入成功，则在结点把柄保有元素时获得的指向该元素的指针和引用被非法化，而在提取前获得的指向元素的指针和引用变得合法。 (C++17 起)

参数

hint -
迭代器，用作搜索开始位置的建议 | (C++11 前)
指向将插入新元素到其前的位置的迭代器 | (C++11 起)
value - 要插入的元素值
first, last - 要插入的元素范围
ilist - 插入值来源的 initializer_list
nh - 兼容的结点把柄
类型要求
-
InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

1-4) 返回指向被插入元素的迭代器。
5-6) （无）
7,8) 若 nh 为空则为尾迭代器，否则为指向被插入元素的迭代器。

异常

1-4) 若任何操作抛出异常，则插入无效果。
本节未完成
原因：情况 5-6

复杂度

1-2) 与容器大小成对数， O(log(size())) 。
3-4) 若插入恰好发生在 hint 后的位置则为均摊常数，否则与容器大小成对数。 | (C++11 前)
3-4) 若插入恰好发生在 hint 前的位置则为均摊常数，否则与容器大小成对数。 | (C++11 起)
5-6) O(N*log(size() + N)) ，其中 N 是要插入的元素数。
7) 与容器大小成对数， O(log(size())) 。
8) 若插入恰好发生在 hint 前的位置则为均摊常数，否则与容器大小成对数。

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)


std::multiset<Key,Compare,Allocator>::key_comp

< cpp‎ | container‎ | multiset

key_compare key_comp() const;

返回用于比较关键的函数对象，它是此容器构造函数参数 comp 的副本，它与 value_comp 相同。

参数

（无）

返回值

比较关键的函数对象。

复杂度

常数

参阅

value_comp
 返回用于在value_type类型的对象中比较键的函数。
(公开成员函数)


std::multiset<Key,Compare,Allocator>::lower_bound

< cpp‎ | container‎ | multiset

iterator lower_bound( const Key& key ); | (1) |
const_iterator lower_bound( const Key& key ) const; | (1) |
template< class K > iterator lower_bound(const K& x); | (2) | (C++14 起)
template< class K > const_iterator lower_bound(const K& x) const; | (2) | (C++14 起)
1) 返回指向首个不小于 key 的元素的迭代器。
2) 返回指向首个比较不小于值 x 的元素的迭代器。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 要与元素比较的键值
x | - | 能与 Key 比较的替用值

返回值

指向首个不小于 key 的元素的迭代器。若找不到这种元素，则返回尾后迭代器（见 end() ）。

复杂度

与容器大小成对数。

参阅

equal_range | 返回匹配特定键的元素范围 (公开成员函数)
upper_bound | 返回指向首个大于给定键的元素的迭代器 (公开成员函数)


std::multiset<Key,Compare,Allocator>::max_size

< cpp‎ | container‎ | multiset

size_type max_size() const; | (C++11 前)
size_type max_size() const noexcept; | (C++11 起)

返回根据系统或库实现限制的容器可保有的元素最大数量，即对于最大容器的 std::distance (begin(), end()) 。

参数

（无）

返回值

元素数量的最大值。

复杂度

常数。

注解

此值通常反映容器大小上的理论极限，至多为 std::numeric_limits <difference_type>::max() 。运行时，可用 RAM 总量可能会限制容器大小到小于 max_size() 的值。

示例

#include <iostream>
#include <set>

int main()
{
    std::multiset<char> s;
    std::cout << "Maximum size of a 'multiset' is " << s.max_size() << "\n";
}

可能的输出：

Maximum size of a 'multiset' is 576460752303423487

参阅

size
 返回容纳的元素数
(公开成员函数)


std::multiset<Key,Compare,Allocator>::merge

< cpp‎ | container‎ | multiset

template<class C2> void merge( std::set <Key, C2, Allocator>& source ); | (1) | (C++17 起)
template<class C2> void merge( std::set <Key, C2, Allocator>&& source ); | (2) | (C++17 起)
template<class C2> void merge( std::multiset <Key, C2, Allocator>& source ); | (3) | (C++17 起)
template<class C2> void merge( std::multiset <Key, C2, Allocator>&& source ); | (4) | (C++17 起)

试图提取（“接合”） source 中每个元素，并用 *this 的比较对象插入到 *this 。

不复制或移动元素，只会重指向容器结点的内部指针。指向被转移元素的所有指针和引用保持合法，但现在指代到 *this 中而非到 source 中。

若 get_allocator() != source.get_allocator() 则行为未定义。

参数

source - 传递结点来源的兼容容器

返回值

（无）

异常

不抛异常，除非比较抛出。

复杂度

N*log(size()+N)) ，其中 N 为 source.size() 。

示例

#include <iostream>
#include <set>

// 打印出容器
template <class Os, class K>
Os& operator<<(Os& os, const std::multiset<K>& v) {
    os << '[' << v.size() << "] {";
    bool o{};
    for (const auto& e : v)
        os << (o ? ", " : (o = 1, " ")) << e;
    return os << " }\n";
}

int main()
{
    std::multiset<char>
        p{ 'C', 'B', 'B', 'A' },
        q{ 'E', 'D', 'E', 'C' };

    std::cout << "p: " << p << "q: " << q;

    p.merge(q);

    std::cout << "p.merge(q);\n" << "p: " << p << "q: " << q;
}

输出：

p: [4] { A, B, B, C }
q: [4] { C, D, E, E }
p.merge(q);
p: [8] { A, B, B, C, C, D, E, E }
q: [0] { }

参阅

extract (C++17) | 从另一容器释出结点 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)


std::multiset<Key,Compare,Allocator>::multiset

< cpp‎ | container‎ | multiset

multiset();

explicit multiset( const Compare& comp,

const Allocator& alloc = Allocator() );
 (1)
explicit multiset( const Allocator& alloc );
 (1) (C++11 起)
(2)
template< class InputIt >

multiset( InputIt first, InputIt last,
const Compare& comp = Compare(),

const Allocator& alloc = Allocator() );
template< class InputIt >

multiset( InputIt first, InputIt last,

const Allocator& alloc );
 (C++14 起)
multiset( const multiset& other );
 (3)
multiset( const multiset& other, const Allocator& alloc );
 (3) (C++11 起)
multiset( multiset&& other );
 (4) (C++11 起)
multiset( multiset&& other, const Allocator& alloc );
 (4) (C++11 起)
(5)
multiset( std::initializer_list <value_type> init,

const Compare& comp = Compare(),

const Allocator& alloc = Allocator() );
 (C++11 起)
multiset( std::initializer_list <value_type> init,
const Allocator& );
 (C++14 起)

从各种数据源构造新容器，可选地使用用户提供的分配器 alloc 或比较函数对象 comp 。

1) 构造空容器。
2) 构造容器，使之拥有范围 [first, last) 的内容。
3) 复制构造函数。构造容器，使之拥有 other 的内容副本。
若不提供 alloc ，则通过调用 std::allocator_traits <allocator_type>::select_on_container_copy_construction( other.get_allocator()) 获得分配器。 | (C++11 起)
在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。 | (C++23 起)
4) 移动构造函数。用移动语义构造容器，使之拥有 other 的内容。若不提供 alloc ，则从属于 other 的分配器移动构造分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
5) 构造容器，使之拥有 initializer_list init 的内容。

参数

alloc | - | 用于此容器所有内存分配的分配器
comp | - | 用于所有关键比较的比较函数对象
first, last | - | 复制元素来源的范围
other | - | 要用作源以初始化容器元素的另一容器
init | - | 用以初始化容器元素的 initializer_list
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- Compare 必须满足比较 (Compare) 的要求。
- Allocator 必须满足分配器 (Allocator) 的要求。

复杂度

1) 常数。
2) N log(N) ，其中通常有 N = std::distance (first, last) ，若范围已按照 value_comp() 排序则与 N 成线性。
3) 与 other 的大小成线性。
4) 常数。若给定 alloc 且 alloc != other.get_allocator() 则为线性。
5) N log(N) ，其中通常有 N = init.size() ，若 init 已按照 value_comp() 排序则与 N 成线性 。

异常

对 Allocator::allocate 的调用可能抛出。

注解

在容器移动构造（重载 (4) ）后，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

尽管在 C++23 前未正式要求，一些实现已经在较早的模式中将 Allocator 放入非推导语境。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2193 | C++11 | 默认构造函数为 explicit | 使之为非 explicit

参阅

operator=
 赋值给容器
(公开成员函数)


std::multiset<Key,Compare,Allocator>::operator=

< cpp‎ | container‎ | multiset

multiset& operator=( const multiset& other ); | (1) |
 | (2) |
multiset& operator=( multiset&& other ); |  |  | (C++11 起) (C++17 前)
multiset& operator=( multiset&& other ) noexcept(/* see below */); |  |  | (C++17 起)
multiset& operator=( std::initializer_list <value_type> ilist ); | (3) | (C++11 起)

替换容器内容。

1) 复制赋值运算符。以 other 的副本替换内容。

若 std::allocator_traits <allocator_type>::propagate_on_container_copy_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若 *this 的分配器在赋值后将与其旧值比较不相等，则用旧分配器解分配内存，然后在复制元素前用新分配器分配内存。否则，在可行时可能复用 *this 所拥有的内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素复制赋值替换。

 (C++11 起)
2) 移动赋值运算符。用移动语义以 other 的内容替换内容（即从 other 移动 other 中的数据到此容器中）。之后 other 在合法但未指定的状态。
若 std::allocator_traits <allocator_type>::propagate_on_container_move_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若它为 false 且 *this 与 other 的分配器不比较相等，则 *this 不能接管 other 所拥有的内存的所有权且必须单独地移动赋值每个元素，并用其自身的分配器按需分配额外内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素移动赋值替换。
3) 以 initializer_list ilist 所标识者替换内容。

参数

other | - | 用作数据源的另一容器
ilist | - | 用作数据源的 initializer_list

返回值

*this

复杂度

1) 与 *this 和 other 的大小成线性。
2) 与 *this 的大小成线性，除非分配器不比较相等且不传播，该情况下与 *this 和 other 的大小成线性。
3) 通常为 O(NlogN) ，其中 N 为 size() + ilist.size() 。若 ilist 相对于 value_comp() 已排序则为线性。

异常

可能抛出实现定义的异常。

 (C++17 前)
1,3) 可能抛出实现定义的异常。
2)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value
&& std::is_nothrow_move_assignable <Compare>::value)
 (C++17 起)

注解

在容器移动赋值（重载 (2) ）后，除非不兼容的分配器强制逐元素移动赋值，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

下列代码用 operator= 赋值一个 std::multiset 给另一个：

#include <set>
#include <iostream>

void display_sizes(const std::multiset<int> &nums1,
                   const std::multiset<int> &nums2,
                   const std::multiset<int> &nums3)
{
    std::cout << "nums1: " << nums1.size()
              << " nums2: " << nums2.size()
              << " nums3: " << nums3.size() << '\n';
}

int main()
{
    std::multiset<int> nums1 {3, 1, 4, 6, 5, 9};
    std::multiset<int> nums2;
    std::multiset<int> nums3;

    std::cout << "Initially:\n";
    display_sizes(nums1, nums2, nums3);

    // 复制赋值从 nums1 复制数据到 nums2
    nums2 = nums1;

    std::cout << "After assigment:\n";
    display_sizes(nums1, nums2, nums3);

    // 移动赋值从 nums1 移动数据到 nums3,
    // 一同修改 nums1 和 nums3
    nums3 = std::move(nums1);

    std::cout << "After move assigment:\n";
    display_sizes(nums1, nums2, nums3);
}

输出：

Initially:
nums1: 6 nums2: 0 nums3: 0
After assigment:
nums1: 6 nums2: 6 nums3: 0
After move assigment:
nums1: 0 nums2: 6 nums3: 6

参阅

(构造函数)
 构造 multiset
(公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::multiset)

< cpp‎ | container‎ | multiset

定义于头文件 <set>
template< class Key, class Compare, class Alloc >

bool operator==( const std::multiset <Key,Compare,Alloc>& lhs,

const std::multiset <Key,Compare,Alloc>& rhs );
 (1)
template< class Key, class Compare, class Alloc >

bool operator!=( const std::multiset <Key,Compare,Alloc>& lhs,

const std::multiset <Key,Compare,Alloc>& rhs );
 (2) (C++20 前)
template< class Key, class Compare, class Alloc >

bool operator<( const std::multiset <Key,Compare,Alloc>& lhs,

const std::multiset <Key,Compare,Alloc>& rhs );
 (3) (C++20 前)
template< class Key, class Compare, class Alloc >

bool operator<=( const std::multiset <Key,Compare,Alloc>& lhs,

const std::multiset <Key,Compare,Alloc>& rhs );
 (4) (C++20 前)
template< class Key, class Compare, class Alloc >

bool operator>( const std::multiset <Key,Compare,Alloc>& lhs,

const std::multiset <Key,Compare,Alloc>& rhs );
 (5) (C++20 前)
template< class Key, class Compare, class Alloc >

bool operator>=( const std::multiset <Key,Compare,Alloc>& lhs,

const std::multiset <Key,Compare,Alloc>& rhs );
 (6) (C++20 前)
template< class Key, class Compare, class Alloc >

/* see below */ operator<=>( const std::multiset <Key,Compare,Alloc>& lhs,

const std::multiset <Key,Compare,Alloc>& rhs );
 (7) (C++20 起)

比较二个 multiset 的内容。

1-2) 检查 lhs 与 rhs 的内容是否相等，即它们是否拥有相同数量的元素且 lhs 中每个元素与 rhs 的同位置元素比较相等。
3-6) 按字典序比较 lhs 与 rhs 的内容。由等价于 std::lexicographical_compare 的函数进行比较。此比较忽略 multiset 的定序 Compare 。
7) 按字典序比较 lhs 与 rhs 的内容。如同通过在二个 multiset 上以进行合成三路比较（见后述）的函数对象调用 std::lexicographical_compare_three_way 进行比较。返回类型同合成三路比较的结果类型。此比较忽略 multiset 的定序 Compare 。

给定分别作为左操作数与右操作数的两个 const E 左值 lhs 与 rhs （其中 E 为 Key ），合成三路比较定义如下：

  • 若 std::three_way_comparable_with<E, E> 得到满足则等价于 lhs <=> rhs ；
  • 否则，若以 operator< 比较二个 const E 左值为良构且结果类型满足 boolean-testable ，则等价于
lhs < rhs ? std::weak_ordering::less :
rhs < lhs ? std::weak_ordering::greater :
            std::weak_ordering::equivalent
  • 否则，不定义合成三路比较，而 operator<=> 不参与重载决议。
若 three_way_comparable_with 或 boolean-testable 被满足但未被实现，或使用 operator< 但 E 与 < 不建立全序，则 operator<=> 的行为未定义。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较内容的 multiset
-
为使用重载 (1-2) ， Key 必须满足可相等比较 (EqualityComparable) 的要求。

返回值

1) 若 multiset 内容相等则为 true ，否则为 false
2) 若 multiset 内容不相等则为 true ，否则为 false
3) 若 lhs 的内容按字典序小于 rhs 的内容则为 true ，否则为 false
4) 若 lhs 的内容按字典序小于或等于 rhs 的内容则为 true ，否则为 false
5) 若 lhs 的内容按字典序大于 rhs 的内容则为 true ，否则为 false
6) 若 lhs 的内容按字典序大于或等于 rhs 的内容则为 true ，否则为 false
7) lhs 与 rhs 中的首对不等价元素的相对顺序，若有这种元素；否则为 lhs.size() <=> rhs.size() 。

复杂度

1-2) 若 lhs 与 rhs 的大小不同则为常数，否则与 multiset 大小成线性
3-7) 与 multiset 大小成线性

示例

#include <iostream>
#include <set>

int main()
{
    std::multiset<int> alice{1, 2, 3};
    std::multiset<int> bob{7, 8, 9, 10};
    std::multiset<int> eve{1, 2, 3};

    std::cout << std::boolalpha;

    // 比较不相等的容器
    std::cout << "alice == bob returns " << (alice == bob) << '\n';
    std::cout << "alice != bob returns " << (alice != bob) << '\n';
    std::cout << "alice <  bob returns " << (alice < bob) << '\n';
    std::cout << "alice <= bob returns " << (alice <= bob) << '\n';
    std::cout << "alice >  bob returns " << (alice > bob) << '\n';
    std::cout << "alice >= bob returns " << (alice >= bob) << '\n';

    std::cout << '\n';

    // 比较相等的容器
    std::cout << "alice == eve returns " << (alice == eve) << '\n';
    std::cout << "alice != eve returns " << (alice != eve) << '\n';
    std::cout << "alice <  eve returns " << (alice < eve) << '\n';
    std::cout << "alice <= eve returns " << (alice <= eve) << '\n';
    std::cout << "alice >  eve returns " << (alice > eve) << '\n';
    std::cout << "alice >= eve returns " << (alice >= eve) << '\n';
}

输出：

alice == bob returns false
alice != bob returns true
alice <  bob returns true
alice <= bob returns true
alice >  bob returns false
alice >= bob returns false

alice == eve returns true
alice != eve returns false
alice <  eve returns false
alice <= eve returns true
alice >  eve returns false
alice >= eve returns true


std::multiset<Key,Compare,Allocator>::rbegin, std::multiset<Key,Compare,Allocator>::crbegin

< cpp‎ | container‎ | multiset

reverse_iterator rbegin(); | (C++11 前)
reverse_iterator rbegin() noexcept; | (C++11 起)
const_reverse_iterator rbegin() const; | (C++11 前)
const_reverse_iterator rbegin() const noexcept; | (C++11 起)
const_reverse_iterator crbegin() const noexcept; | (C++11 起)

返回指向逆向 multiset 首元素的逆向迭代器。它对应非逆向 multiset 的末元素。若 multiset 为空，则返回的迭代器等于 rend() 。

参数

（无）

返回值

指向首元素的逆向迭代器。

复杂度

常数。

注意

因为 iterator 和 const_iterator 都是常迭代器（而且实际上可以是同一类型），故不可能通过任何这些成员函数返回的迭代器修改容器元素。

示例

本节未完成
原因：暂无示例

参阅

rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)


std::multiset<Key,Compare,Allocator>::rend, std::multiset<Key,Compare,Allocator>::crend

< cpp‎ | container‎ | multiset

reverse_iterator rend(); | (C++11 前)
reverse_iterator rend() noexcept; | (C++11 起)
const_reverse_iterator rend() const; | (C++11 前)
const_reverse_iterator rend() const noexcept; | (C++11 起)
const_reverse_iterator crend() const noexcept; | (C++11 起)

返回指向逆向 multiset 末元素后一元素的逆向迭代器。它对应非逆向 multiset 首元素的前一元素。此元素表现为占位符，试图访问它导致未定义行为。

参数

（无）

返回值

指向末元素后一元素的逆向迭代器。

复杂度

常数。

注意

因为 iterator 和 const_iterator 都是常迭代器（而且实际上可以是同一类型），故不可能通过任何这些成员函数返回的迭代器修改容器元素。

示例

本节未完成
原因：暂无示例

参阅

rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)


std::multiset<Key,Compare,Allocator>::size

< cpp‎ | container‎ | multiset

size_type size() const; | (C++11 前)
size_type size() const noexcept; | (C++11 起)

返回容器中的元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

容器中的元素数量。

复杂度

常数。

示例

下列代码用 size 显示 std::multiset 中的元素数：

#include <set>
#include <iostream>

int main()
{
    std::multiset<int> nums {1, 3, 5, 7};

    std::cout << "nums contains " << nums.size() << " elements.\n";
}

输出：

nums contains 4 elements.

参阅

empty | 检查容器是否为空 (公开成员函数)
max_size | 返回可容纳的最大元素数 (公开成员函数)


std::multiset<Key,Compare,Allocator>::swap

< cpp‎ | container‎ | multiset

void swap( multiset& other ); | (C++17 前)
void swap( multiset& other ) noexcept(/* see below */); | (C++17 起)

将内容与 other 的交换。不在单独的元素上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。尾后迭代器被非法化。

Pred 对象必须可交换 (Swappable) ，并用非成员 swap 的非限定调用交换它们。

若 std::allocator_traits <allocator_type>::propagate_on_container_swap::value 为 true ，则用对非成员 swap 的无限定调用交换分配器。否则，不交换它们（且若 get_allocator() != other.get_allocator() ，则行为未定义）。

 (C++11 起)

参数

other - 要与之交换内容的容器

返回值

（无）

异常

任何 Compare 对象交换所抛的异常。

 (C++17 前)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value
&& std::is_nothrow_swappable <Compare>::value)
 (C++17 起)

复杂度

常数。

示例

#include <iostream>
#include <set>

template<class Os, class Co> Os& operator<<(Os& os, const Co& co) {
    os << "{";
    for (auto const& i : co) { os << ' ' << i; }
    return os << " } ";
}

int main()
{
    std::multiset<int> a1{3, 1, 3, 2}, a2{5, 4, 5};

    auto it1 = std::next(a1.begin());
    auto it2 = std::next(a2.begin());

    const int& ref1 = *(a1.begin());
    const int& ref2 = *(a2.begin());

    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';
    a1.swap(a2);
    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';

    // 注意交换前指代一个容器中的元素的每个迭代器在交换后都指代同一元素。对于引用同为真。
}

输出：

{ 1 2 3 3 } { 4 5 5 } 2 5 1 4
{ 4 5 5 } { 1 2 3 3 } 2 5 1 4

参阅

std::swap(std::multiset)
 特化 std::swap 算法
(函数模板)


std::swap(std::multiset)

< cpp‎ | container‎ | multiset

定义于头文件 <set>
template< class Key, class Compare, class Alloc >

void swap( std::multiset <Key,Compare,Alloc>& lhs,

std::multiset <Key,Compare,Alloc>& rhs );
 (C++17 前)
template< class Key, class Compare, class Alloc >

void swap( std::multiset <Key,Compare,Alloc>& lhs,

std::multiset <Key,Compare,Alloc>& rhs ) noexcept(/* see below */);
 (C++17 起)

为 std::multiset 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

#include <algorithm>
#include <iostream>
#include <set>

int main()
{
    std::multiset<int> alice{1, 2, 3};
    std::multiset<int> bob{7, 8, 9, 10};

    auto print = [](const int& n) { std::cout << " " << n; };

    // 打印交换前的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';

    std::cout << "-- SWAP\n";
    std::swap(alice,bob);

    // 打印交换后的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
}

输出：

alice: 1 2 3
bob  : 7 8 9 10
-- SWAP
alice: 7 8 9 10
bob  : 1 2 3

参阅

swap
 交换内容
(公开成员函数)


std::multiset<Key,Compare,Allocator>::upper_bound

< cpp‎ | container‎ | multiset

iterator upper_bound( const Key& key ); | (1) |
const_iterator upper_bound( const Key& key ) const; | (1) |
template< class K > iterator upper_bound( const K& x ); | (2) | (C++14 起)
template< class K > const_iterator upper_bound( const K& x ) const; | (2) | (C++14 起)
1) 返回指向首个大于 key 的元素的迭代器。
2) 返回指向首个比较大于值 x 的元素的迭代器。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 与元素比较的键值
x | - | 能与 Key 比较的替用值

返回值

指向首个大于 key 的元素的迭代器。若找不到这种元素，则返回尾后（见 end() ）迭代器。

复杂度

与容器大小成对数。

参阅

equal_range | 返回匹配特定键的元素范围 (公开成员函数)
lower_bound | 返回指向首个不小于给定键的元素的迭代器 (公开成员函数)


std::multiset<Key,Compare,Allocator>::value_comp

< cpp‎ | container‎ | multiset

std::multiset::value_compare value_comp() const;

返回比较值的函数对象。它与 key_comp 相同。

参数

（无）

返回值

比较值的函数对象。

复杂度

常数。

参阅

key_comp
 返回用于比较键的函数
(公开成员函数)


std::multiset<Key,Compare,Allocator>::~multiset

< cpp‎ | container‎ | multiset

~multiset();

销毁 multiset 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 multiset 大小成线性。


结点柄 (C++17)

< cpp‎ | container
template</*unspecified*/> class /*node-handle*/; | (C++17 起)

关联容器 std::set 、 std::map 、 std::multiset 、 std::multimap 、 std::unordered_set 、 std::unordered_map 、 std::unordered_multiset 、 std::unordered_multimap 是基于结点的数据结构，而且可用称作结点柄的未指定类型的对象释出其结点。

结点柄是仅移动类型，它占有元素（ value_type ）并提供对元素的访问，并提供对元素键部分（ key_type ）和被映射部分（ mapped_type ）的非 const 访问。若结点柄在持有结点时析构它，则用容器的分配器正确地析构结点。结点柄含有容器分配器的副本，这是结点柄能在容器生存期外存在所必须的。

结点柄的准确类型（此处显示为 /*node-handle*/ ）是未指定的，但每个容器都暴露其结点柄类型为成员 node_type 。

结点柄能用于在二个有相同键、值和分配器类型（忽略比较或哈希/相等性）的关联容器间传递结点的所有权，而无需调用任何容器元素上的复制/移动操作（这种操作被称为“接合”）。在唯一和非唯一容器间传递也是容许的：来自 std::map 的结点柄能插入 std::multimap ，但不能插入 std::unordered_map 或 std::set 。

结点柄可以为空，该情况下它不保有元素和分配器。默认构造和被移动的结点柄是空的。另外，空的结点柄可由对容器成员函数 extract 的失败调用产生。

若成功将元素插入容器，则为结点柄所占有时获得的到该元素的引用或指针会被非法化。

对于所有 key_type 为 K 而 mapped_type 为 T 的映射容器（ std::map 、 std::multimap 、 std::unordered_map 及 std::unordered_multimap ），若对 std::pair <K, T> 或 std::pair <const K, T> 存在 std::pair 的用户定义特化，则涉及结点柄的操作行为未定义。

成员类型

成员类型 | 定义
key_type(仅 map 容器) | 存储于结点的关键
mapped_type(仅 map 容器) | 存储于结点的元素的被映射部分
value_type(仅 set 容器) | 存储于结点的元素
allocator_type | 销毁元素时使用的分配器

成员函数

构造函数

constexpr /*node-handle*/() noexcept; | (1)
/*node-handle*/(/*node-handle*/&& nh) noexcept; | (2)
1) 默认构造函数初始化结点柄为空状态。
2) 移动构造函数从 nh 取走容器元素所有权，移动构造成员分配器，并令 nh 留在空状态。

参数

nh - 同类型的结点柄（不必属于相同容器）

注解

结点柄是仅移动的，不定义复制构造函数。

operator=

/*node-handle*/& operator=(/*node-handle*/&& nh);
  • 若结点柄非空，
  • 则通过调用 std::allocator_traits<allocator_type>::destroy ，销毁此结点柄所管理的容器元素对象中的 value_type 子对象；
  • 通过调用 allocator_traits<allocator_type>::rebind_traits<container-node-type>::deallocate 解分配容器元素；
  • 从 nh 获得容器元素的所有权；
  • 若结点柄为空（从而不含分配器）或若 allocator_traits<allocator_type>::propagate_on_container_move_assignment 为 true ，则从 nh 移动赋值分配器；
  • 设置 nh 为空状态。

若结点非空且 allocator_traits<allocator_type>::propagate_on_container_move_assignment 为 false 且分配器比较不相等，则行为未定义。

参数

nh - 同类型的结点柄（不必属于相同容器）

返回

*this

异常

不抛出。

注解

结点柄是仅移动的，不定义复制赋值。

析构函数

~/*node-handle*/();
  • 若结点柄非空,
  • 则通过调用 std::allocator_traits<allocator_type>::destroy ，销毁此结点柄所管理的容器元素对象中的 value_type 子对象；
  • 通过调用 allocator_traits<allocator_type>::rebind_traits<container-node-type>::deallocate 解分配容器元素。

empty

bool empty() const noexcept; | (C++20 前)
[[nodiscard]] bool empty() const noexcept; | (C++20 起)

若结点柄为空则返回 true ，否则返回 false 。

operator bool

explicit operator bool() const noexcept;

若结点柄为空则转换为 false ，否则返回 true 。

get_allocator

allocator_type get_allocator() const;

返回存储的分配器（它是源容器的分配器副本）的副本。若结点柄为空则行为未定义。

异常

不抛出。

value

value_type& value() const; | (仅 set 容器)

返回到此结点柄所管理的容器元素对象中的 value_type 子对象的引用。若结点柄为空则行为未定义。

异常

不抛出。

key

key_type& key() const; | (仅 map 容器)

返回到此结点柄所管理的容器元素对象中的 value_type 子对象的 key_type 成员的非 const 引用。若结点柄为空则行为未定义。

异常

不抛出。

注解

此函数使得能够修改从映射释出的结点的键，再重插入到映射，而无需复制或移动元素。

mapped

mapped_type& mapped() const; | (仅 map 容器)

返回到此结点柄所管理的容器元素对象中的 value_type 子对象的 mapped_type 成员的引用。若结点柄为空则行为未定义。

异常

不抛出。

swap

void swap(/*node-handle*/& nh) noexcept(/* see below */);
  • 交换容器结点的所有权；
  • 若一个结点为空或两个结点均为非空且 std::allocator_traits<allocator_type>::propagate_on_container_swap 为 true ，则一同交换分配器。

若两个结点均为非空且 allocator_traits<allocator_type>::propagate_on_container_swap 为 false 而分配器比较不相等，则行为未定义。

异常

noexcept 说明：
noexcept( std::allocator_traits <allocator_type>::propagate_on_container_swap::value ||
std::allocator_traits <allocator_type>::is_always_equal::value)

非成员函数

swap

friend void swap(/*node-handle*/& x, /*node-handle*/& y) noexcept(noexcept(x.swap(y)));

等效地执行 x.swap(y) 。

此函数对通常无限定或有限定查找不可见，而只能在 node-handle 为参数的关联类时由实参依赖查找找到。


std::priority_queue

< cpp‎ | container
定义于头文件 <queue>
template<

class T,
class Container = std::vector <T>,
class Compare = std::less <typename Container::value_type>

> class priority_queue;

priority_queue 是容器适配器，它提供常数时间的（默认）最大元素查找，对数代价的插入与释出。

可用用户提供的 Compare 更改顺序，例如，用 std::greater<T> 将导致最小元素作为 top() 出现。

用 priority_queue 工作类似管理某些随机访问容器中的堆，优势是不可能突然把堆非法化。

模板形参

T - 存储的元素类型。若 T 与 Container::value_type 不是同一类型则行为未定义。 (C++17 起)
Container - 用于存储元素的底层容器类型。容器必须满足序列容器 (SequenceContainer) 的要求，而其迭代器必须满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。另外，它必须提供拥有通常语义的下列函数：
  • front()
  • push_back()
  • pop_back()

标准容器 std::vector 和 std::deque 满足这些要求。
Compare - 提供严格弱序的比较 (Compare) 类型。

注意比较 (Compare) 形参的定义，使得若其第一参数在弱序中先于其第二参数则返回 true 。但因为 priority_queue 首先输出最大元素，故“先来”的元素实际上最后输出。即队列头含有按照比较 (Compare) 所施加弱序的“最后”元素。

成员类型

成员类型 | 定义
container_type | Container
value_compare | Compare
value_type | Container::value_type
size_type | Container::size_type
reference | Container::reference
const_reference | Container::const_reference

成员函数

(构造函数)
 构造 priority_queue
(公开成员函数)
(析构函数)
 析构 priority_queue
(公开成员函数)
operator=
 赋值给容器适配器
(公开成员函数)
元素访问
top
 访问栈顶元素
(公开成员函数)
容量
empty
 检查底层容器是否为空
(公开成员函数)
size
 返回容纳的元素数
(公开成员函数)
修改器
push
 插入元素，并对底层容器排序
(公开成员函数)
emplace
(C++11)
 原位构造元素并排序底层容器
(公开成员函数)
pop
 删除队首元素
(公开成员函数)
swap
(C++11)
 交换内容
(公开成员函数)

成员对象
Container c
 底层容器
(受保护成员对象)
Compare comp
 比较函数对象
(受保护成员对象)

非成员函数

std::swap(std::priority_queue)
(C++11)
 特化 std::swap 算法
(函数模板)

辅助类

std::uses_allocator<std::priority_queue>
(C++11)
 特化 std::uses_allocator 类型特征
(类模板特化)

推导指引 (C++17 起)

示例

#include <functional>
#include <queue>
#include <vector>
#include <iostream>

template<typename T> void print_queue(T& q) {
    while(!q.empty()) {
        std::cout << q.top() << " ";
        q.pop();
    }
    std::cout << '\n';
}

int main() {
    std::priority_queue<int> q;

    for(int n : {1,8,5,6,3,4,0,9,7,2})
        q.push(n);

    print_queue(q);

    std::priority_queue<int, std::vector<int>, std::greater<int> > q2;

    for(int n : {1,8,5,6,3,4,0,9,7,2})
        q2.push(n);

    print_queue(q2);

    // 用 lambda 比较元素。
    auto cmp = [](int left, int right) { return (left ^ 1) < (right ^ 1); };
    std::priority_queue<int, std::vector<int>, decltype(cmp)> q3(cmp);

    for(int n : {1,8,5,6,3,4,0,9,7,2})
        q3.push(n);

    print_queue(q3);

}

输出：

9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9
8 9 6 7 4 5 2 3 0 1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2684 | C++98 | priority_queue 接收比较器但缺少对它的成员 typedef | 已添加


std::priority_queue 的推导指引

< cpp‎ | container‎ | priority queue
定义于头文件 <queue>
template <class Comp, class Container>

priority_queue(Comp, Container)

-> priority_queue<typename Container::value_type, Container, Comp>;
 (1) (C++17 起)
template<class InputIt,

class Comp = std::less </*iter-value-type*/<InputIt>>,
class Container = std::vector </*iter-value-type*/<InputIt>>
priority_queue(InputIt, InputIt, Comp = Comp(), Container = Container())

-> priority_queue</*iter-value-type*/<InputIt>, Container, Comp>;
 (2) (C++17 起)
template<class Comp, class Container, class Alloc>

priority_queue(Comp, Container, Alloc)

-> priority_queue<typename Container::value_type, Container, Comp>;
 (3) (C++17 起)
template<class InputIt, class Alloc>

priority_queue(InputIt, InputIt, Alloc)
-> priority_queue</*iter-value-type*/<InputIt>,
std::vector </*iter-value-type*/<InputIt>, Alloc>,

std::less </*iter-value-type*/<InputIt>>>;
 (4) (C++17 起)
template<class InputIt, class Comp, class Alloc>

priority_queue(InputIt, InputIt, Comp, Alloc)
-> priority_queue</*iter-value-type*/<InputIt>,

std::vector </*iter-value-type*/<InputIt>, Alloc>, Comp>;
 (5) (C++17 起)
template<class InputIt, class Comp, class Container, class Alloc>

priority_queue(InputIt, InputIt, Comp, Container, Alloc)

-> priority_queue<typename Container::value_type, Container, Comp>;
 (6) (C++17 起)

为 std::priority_queue 提供这些推导指引以允许从底层容器类型以及从迭代器范围推导。对任何类型 It ， /*iter-value-type*/<It> 指代 typename std::iterator_traits <It>::value_type 。

这些重载仅若

  • InputIt 满足老式输入迭代器 (LegacyInputIterator) 、
  • Comp 不满足分配器 (Allocator) 、
  • Container 不满足分配器 (Allocator) ，
  • 对于重载 (4) 与 (5) ， (C++23 起) Alloc 满足分配器 (Allocator) ，并且
  • 对于重载 (3) 与 (6) ， std::uses_allocator_v <Container, Alloc> 为 true 才参与重载决议。

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

示例

#include <vector>
#include <queue>
int main() {
   std::vector<int> v = {1,2,3,4};
   std::priority_queue pq1{std::greater<int>{}, v}; // 推导 std::priority_queue<
                                                    //   int, std::vector<int>,
                                                    //   std::greater<int>>
   std::priority_queue pq2{v.begin(), v.end()}; // 推导 std::priority_queue<int>
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3506 | C++17 | 缺少源自迭代器和分配器的推导指引 | 已添加


std::priority_queue<T,Container,Compare>::emplace

< cpp‎ | container‎ | priority queue

template< class... Args > void emplace( Args&&... args ); | (C++11 起)

推入新元素到 priority_queue 。原位构造元素，即不进行移动或复制操作。以与提供给函数者准确相同的参数调用元素的构造函数。

等效地调用 c.emplace_back( std::forward <Args>(args)...); std::push_heap (c.begin(), c.end(), comp); 。

参数

args - 转发给元素构造函数的参数

返回值

（无）

复杂度

对数次比较加上 Container::emplace_back 的复杂度。

参阅

push | 插入元素，并对底层容器排序 (公开成员函数)
pop | 删除队首元素 (公开成员函数)


std::priority_queue<T,Container,Compare>::empty

< cpp‎ | container‎ | priority queue

bool empty() const; | (C++20 前)
[[nodiscard]] bool empty() const; | (C++20 起)

检查底层容器是否为空，即是否 c.empty() 。

参数

（无）

返回值

若底层容器为空则为 true ，否则为 false 。

复杂度

常数

参阅

size
 返回容纳的元素数
(公开成员函数)


std::priority_queue<T,Container,Compare>::operator=

< cpp‎ | container‎ | priority queue
priority_queue& operator=( const priority_queue& other ); | (1) |
priority_queue& operator=( priority_queue&& other ); | (2) | (C++11 起)

以 other 的内容替换容器适配器的内容。

1) 复制赋值运算符。以 other 的内容副本替换内容。等效地调用 c = other.c; comp = other.comp; 。(隐式声明)
2) 移动赋值运算符。用移动语义以 other 的内容替换内容。等效地调用 c = std::move(other.c); comp = std::move(other.comp); 。(隐式声明)

参数

other - 用作源的另一容器适配器

返回值

*this

复杂度

等价于底层容器 operator= 的复杂度。

参阅

(构造函数)
 构造 priority_queue
(公开成员函数)


std::priority_queue<T,Container,Compare>::pop

< cpp‎ | container‎ | priority queue

void pop();

从 priority_queue 移除顶元素。等效地调用 std::pop_heap (c.begin(), c.end(), comp); c.pop_back(); 。

参数

（无）

返回值

（无）

复杂度

对数次比较加 Container::pop_back 的复杂度。

参阅

emplace (C++11) | 原位构造元素并排序底层容器 (公开成员函数)
push | 插入元素，并对底层容器排序 (公开成员函数)
top | 访问栈顶元素 (公开成员函数)


std::priority_queue<T,Container,Compare>::priority_queue

< cpp‎ | container‎ | priority queue
priority_queue() : priority_queue(Compare(), Container()) { }
 (1) (C++11 起)
explicit priority_queue( const Compare& compare )
: priority_queue(compare, Container()) { }
 (2) (C++11 起)
(3)
explicit priority_queue( const Compare& compare = Compare(),
const Container& cont = Container() );
 (C++11 前)
priority_queue( const Compare& compare, const Container& cont );
 (C++11 起)
priority_queue( const Compare& compare, Container&& cont );
 (4) (C++11 起)
priority_queue( const priority_queue& other );
 (5)
priority_queue( priority_queue&& other );
 (6) (C++11 起)
template< class InputIt >

priority_queue( InputIt first, InputIt last,

const Compare& compare = Compare() );
 (7) (C++11 起)
(8)
template< class InputIt >

priority_queue( InputIt first, InputIt last,
const Compare& compare = Compare(),

const Container& cont = Container() );
 (C++11 前)
template< class InputIt >

priority_queue( InputIt first, InputIt last,

const Compare& compare, const Container& cont );
 (C++11 起)
template< class InputIt >

priority_queue( InputIt first, InputIt last,

const Compare& compare, Container&& cont );
 (9) (C++11 起)
template< class Alloc >
explicit priority_queue( const Alloc& alloc );
 (10) (C++11 起)
template< class Alloc >
priority_queue( const Compare& compare, const Alloc& alloc );
 (11) (C++11 起)
template< class Alloc >

priority_queue( const Compare& compare, const Container& cont,

const Alloc& alloc );
 (12) (C++11 起)
template< class Alloc >

priority_queue( const Compare& compare, Container&& cont,

const Alloc& alloc );
 (13) (C++11 起)
template< class Alloc >
priority_queue( const priority_queue& other, const Alloc& alloc );
 (14) (C++11 起)
template< class Alloc >
priority_queue( priority_queue&& other, const Alloc& alloc );
 (15) (C++11 起)
template< class InputIt, class Alloc >
priority_queue( InputIt first, InputIt last, const Alloc& alloc );
 (16) (C++11 起)
template< class InputIt, class Alloc >

priority_queue( InputIt first, InputIt last, const Compare& compare,

const Alloc& alloc );
 (17) (C++11 起)
template< class InputIt, class Alloc >

priority_queue( InputIt first, InputIt last, const Compare& compare,

const Container& cont, const Alloc& alloc );
 (18) (C++11 起)
template< class InputIt, class Alloc >

priority_queue( InputIt first, InputIt last, const Compare& compare,

Container&& cont, const Alloc& alloc );
 (19) (C++11 起)

从多种数据源构造容器适配器的底层容器。

1) 默认构造函数。值初始化底层容器。
2) 用 compare 的内容复制构造比较函数对象 comp 。值初始化底层容器 c 。
3) 用 cont 的内容复制构造底层容器 c 。用 compare 的内容复制构造比较函数对象 comp 。调用 std::make_heap (c.begin(), c.end(), comp) 。此亦为默认构造函数。 (C++11 前)
4) 用 std::move(cont) 移动构造底层容器 c 。以 compare 的内容复制构造比较函数对象 comp 。调用 std::make_heap (c.begin(), c.end(), comp) 。
5) 复制构造函数。以 other.c 的内容复制构造底层容器。以 other.comp 复制构造比较函数对象。 (隐式声明)
6) 移动构造函数。以 std::move(other.c) 构造底层容器。以 std::move(other.comp) 构造比较函数对象。 (隐式声明)
7-9) 迭代器对构造函数。这些重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 才参与重载决议。
7) 如同用 c(first, last) 构造 c 并从 compare 构造 comp ，然后调用 std::make_heap (c.begin(), c.end(), comp); 。
8) 从 cont 复制构造 c 并从 compare 复制构造 comp 。然后调用 c.insert(c.end(), first, last); ，再调用 std::make_heap (c.begin(), c.end(), comp); 。
9) 从 std::move(cont) 移动构造 c 并从 compare 复制构造 comp 。然后调用 c.insert(c.end(), first, last); ，再调用 std::make_heap (c.begin(), c.end(), comp); 。
10-15) 分配器扩展构造函数。这些重载仅若 std::uses_allocator <container_type, Alloc>::value 为 true ，即底层容器为知分配器容器（对所有标准库容器为真）才参与重载决议。
10) 以 alloc 为分配器构造底层容器。等效地调用 c(alloc) 。值初始化 comp 。
11) 以 alloc 为分配器构造底层容器。等效地调用 c(alloc) 。从 compare 复制构造 comp 。
12) 用 cont 的内容，以 alloc 为分配器构造底层容器，如同用 c(cont, alloc) 。从 compare 复制构造 comp 。然后调用 std::make_heap (c.begin(), c.end(), comp) 。
13) 用 cont 的内容，以 alloc 为分配器并以移动语义构造底层容器，如同用 c(std::move(cont), alloc) 。从 compare 复制构造 comp 。然后调用 std::make_heap (c.begin(), c.end(), comp) 。
14) 用 other.c 的内容，以 alloc 为分配器构造底层容器。等效地调用 c(other.c, alloc) 。从 other.comp 复制构造 comp 。
15) 用 other 的内容，同时以 alloc 为分配器构造适配器。等效地调用 c(std::move(other.c), alloc) 。从 other.comp 移动构造 comp 。
16-19) 分配器扩展迭代器对构造函数，同 (7-9) ，除了用 alloc 构造底层容器。这些重载仅若 std::uses_allocator <container_type, Alloc>::value 为 true 且 InputIt 满足老式输入迭代器 (LegacyInputIterator) 才参与重载决议。

参数

alloc | - | 用于底层容器所有内存分配的分配器
other | - | 用作源初始化底层容器的另一容器适配器
cont | - | 用作源初始化底层容器的容器
compare | - | 用于初始化底层比较函数对象的比较函数对象
first, last | - | 要初始化的元素范围
类型要求
- Alloc 必须满足分配器 (Allocator) 的要求。
- Container 必须满足容器 (Container) 的要求。仅若 Container 满足知分配器容器 (AllocatorAwareContainer) 的要求才定义分配器扩展构造函数
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

复杂度

1-2) 常数。
3,12) \(\scriptsize \mathcal{O}{(N)}\)O(N) 次比较和 \(\scriptsize \mathcal{O}{(N)}\)O(N) 次 value_type 构造函数调用，其中 \(\scriptsize N\)N 为 cont.size() 。
4) \(\scriptsize \mathcal{O}{(N)}\)O(N) 次比较，其中 \(\scriptsize N\)N 为 cont.size() 。
6) 常数。
7,16-17) \(\scriptsize \mathcal{O}{(M)}\)O(M) 次比较，其中 \(\scriptsize M\)M 为 std::distance (first, last) 。
8,18) \(\scriptsize \mathcal{O}{(N+M)}\)O(N+M) 次比较和 \(\scriptsize \mathcal{O}{(N)}\)O(N) 次 value_type 构造函数调用，其中 \(\scriptsize N\)N 与 \(\scriptsize M\)M 分别为 cont.size() 与 std::distance (first, last) 。
9) \(\scriptsize \mathcal{O}{(N)}\)O(N) 次比较，其中 \(\scriptsize N\)N 为 cont.size() + std::distance (first, last) 。
10-11) 常数。
12) \(\scriptsize \mathcal{O}{(N)}\)O(N) 次比较和 \(\scriptsize \mathcal{O}{(N)}\)O(N) 次 value_type 构造函数调用，其中 \(\scriptsize N\)N 为 cont.size() 。
13) \(\scriptsize \mathcal{O}{(N)}\)O(N) 次比较，其中 \(\scriptsize N\)N 为 cont.size() 。
14) 与 other 的大小成线性。
15) 若 Alloc 与 other 的分配器比较相等则为常数。否则与 other 的大小成线性。
19) \(\scriptsize \mathcal{O}{(N+M)}\)O(N+M) 次比较与可能存在的 \(\scriptsize \mathcal{O}{(N)}\)O(N) 次 value_type 构造函数调用（若 Alloc 与 other 的分配器比较不相等则存在），其中 \(\scriptsize N\)N 与 \(\scriptsize M\)M 分别为 cont.size() 与 std::distance (first, last) 。

示例

#include <complex>
#include <functional>
#include <iostream>
#include <queue>
#include <vector>

int main()
{
    std::priority_queue<int> pq1;
    pq1.push(5);
    std::cout << "pq1.size() = " << pq1.size() << '\n';

    std::priority_queue<int> pq2 {pq1};
    std::cout << "pq2.size() = " << pq2.size() << '\n';

    std::vector<int> vec {3, 1, 4, 1, 5};
    std::priority_queue<int> pq3 {std::less<int>(), vec};
    std::cout << "pq3.size() = " << pq3.size() << '\n';

    for (std::cout << "pq3 : "; !pq3.empty(); pq3.pop())
    {
        std::cout << pq3.top() << ' ';
    }
    std::cout << '\n';

    // 带定制比较器的演示：

    using my_value_t = std::complex<double>;
    using my_container_t = std::vector<my_value_t>;

    auto my_comp = [](const my_value_t& z1, const my_value_t& z2) {
        return z2.real() < z1.real();
    };

    std::priority_queue<my_value_t,
                        my_container_t,
                        decltype(my_comp)> pq4 {my_comp};

    using namespace std::complex_literals;
    pq4.push(5.0 + 1i);
    pq4.push(3.0 + 2i);
    pq4.push(7.0 + 3i);

    for (; !pq4.empty(); pq4.pop())
    {
        const auto& z = pq4.top();
        std::cout << "pq4.top() = " << z << '\n';
    }
}

输出：

pq1.size() = 1
pq2.size() = 1
pq3.size() = 5
pq3 : 5 4 3 1 1
pq4.top() = (3,2)
pq4.top() = (5,1)
pq4.top() = (7,3)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数和构造函数 (4) 曾为 explicit | 使之为隐式
LWG 3506 | C++11 | 分配器扩展迭代器对构造函数缺失 | 已添加
LWG 3522 | C++11 | 迭代器对构造函数上的约束缺失 | 已添加
LWG 3529 | C++11 | 从一对迭代器构造调用 insert | 从它们构造容器

参阅

operator=
 赋值给容器适配器
(公开成员函数)


std::priority_queue<T,Container,Compare>::push

< cpp‎ | container‎ | priority queue

void push( const value_type& value ); |
void push( value_type&& value ); | (C++11 起)

推给定的元素 value 到 priority_queue 中。

1) 等效地调用 c.push_back(value); std::push_heap (c.begin(), c.end(), comp);
2) 等效地调用 c.push_back(std::move(value)); std::push_heap (c.begin(), c.end(), comp);

参数

value - 要推入的元素值

返回值

（无）

复杂度

对数次比较加 Container::push_back 的复杂度。

参阅

emplace (C++11) | 原位构造元素并排序底层容器 (公开成员函数)
pop | 删除队首元素 (公开成员函数)


std::priority_queue<T,Container,Compare>::size

< cpp‎ | container‎ | priority queue

size_type size() const;

返回底层容器中的元素数，即 c.size() 。

参数

（无）

返回值

容器中的元素数。

复杂度

常数。

参阅

empty
 检查底层容器是否为空
(公开成员函数)


std::priority_queue<T,Container,Compare>::swap

< cpp‎ | container‎ | priority queue

void swap( priority_queue& other ) noexcept(/* see below */); | (C++11 起)

交换容器适配器与 other 的内容。等效地调用 using std::swap ; swap(c, other.c); swap(comp, other.comp); 。

参数

other - 要交换内容的容器适配器

返回值

（无）

异常

noexcept 说明：
noexcept(noexcept(swap(c, other.c)) && noexcept(swap(comp, other.comp)))

上述表达式中，用与 C++17 std::is_nothrow_swappable 特性所用的相同方式查找标识符 swap 。

 (C++11 起)
(C++17 前)
noexcept 说明：
noexcept( std::is_nothrow_swappable_v <Container> &&
std::is_nothrow_swappable_v <Compare>)
 (C++17 起)

复杂度

与底层容器相同（常为常数）。

注解

一些实现（例如 libc++ ）对 C++11 前模式提供 swap 成员函数作为扩展。

示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2456 | C++11 | noexcept 规定非良构 | 使之能用

参阅

std::swap(std::priority_queue)
(C++11)
 特化 std::swap 算法
(函数模板)


std::swap(std::priority_queue)

< cpp‎ | container‎ | priority queue

定义于头文件 <queue>
template< class T, class Container, class Compare >

void swap( std::priority_queue <T,Container,Compare>& lhs,

std::priority_queue <T,Container,Compare>& rhs );
 (C++11 起)
(C++17 前)
template< class T, class Container, class Compare >

void swap( std::priority_queue <T,Container,Compare>& lhs,

std::priority_queue <T,Container,Compare>& rhs ) noexcept(/* see below */);
 (C++17 起)

为 std::priority_queue 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

此重载仅若 std::is_swappable_v <Container> 与 std::is_swappable_v <Compare> 均为 true 才参与重载决议。

 (C++17 起)

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

与交换底层容器相同。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++11)
 交换内容
(公开成员函数)


std::priority_queue<T,Container,Compare>::top

< cpp‎ | container‎ | priority queue
const_reference top() const;

返回到 priority_queue 顶元素的引用。此元素将在调用 pop() 时被移除。若使用默认比较函数，则返回的元素亦为优先队列中最大的元素。

参数

（无）

返回值

到顶元素的引用，如同以调用 c.front() 获得。

复杂度

常数。

参阅

pop
 删除队首元素
(公开成员函数)


std::uses_allocator<std::priority_queue>

< cpp‎ | container‎ | priority queue

template< class T, class Container, class Compare,class Alloc > struct uses_allocator<priority_queue<T,Compare,Container>,Alloc> : std::uses_allocator <Container, Alloc>::type { }; | (C++11 起)

为 std::priority_queue 提供 std::uses_allocator 类型特性的通透特化：容器适配器使用分配器，若且唯若底层容器使用。

继承自 std::integral_constant

成员常量

value
[静态]
 true
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

参阅

uses_allocator
(C++11)
 检查指定的类型是否支持使用分配器的构造
(类模板)


std::priority_queue<T,Container,Compare>::~priority_queue

< cpp‎ | container‎ | priority queue

~priority_queue();

销毁 priority_queue 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 priority_queue 大小成线性。


std::queue

< cpp‎ | container
定义于头文件 <queue>
template<

class T,
class Container = std::deque <T>

> class queue;

std::queue 类是容器适配器，它给予程序员队列的功能——尤其是 FIFO （先进先出）数据结构。

类模板表现为底层容器的包装器——只提供特定的函数集合。 queue 在底层容器尾端推入元素，从首端弹出元素。

模板形参

T - 存储的元素类型。若 T 与 Container::value_type 不是同一类型则行为未定义。 (C++17 起)
Container - 用于存储元素的底层容器。容器必须满足序列容器 (SequenceContainer) 的要求。另外，它必须提供带通常语义的下列函数：
  • back()
  • front()
  • push_back()
  • pop_front()

标准容器 std::deque 和 std::list 满足这些要求。

成员类型

成员类型 | 定义
container_type | Container
value_type | Container::value_type
size_type | Container::size_type
reference | Container::reference
const_reference | Container::const_reference

成员函数

(构造函数)
 构造 queue
(公开成员函数)
(析构函数)
 析构 queue
(公开成员函数)
operator=
 赋值给容器适配器
(公开成员函数)
元素访问
front
 访问第一个元素
(公开成员函数)
back
 访问最后一个元素
(公开成员函数)
容量
empty
 检查底层容器是否为空
(公开成员函数)
size
 返回容纳的元素数
(公开成员函数)
修改器
push
 向队列尾部插入元素
(公开成员函数)
emplace
(C++11)
 在尾部原位构造元素
(公开成员函数)
pop
 删除首个元素
(公开成员函数)
swap
(C++11)
 交换内容
(公开成员函数)

成员对象
Container c
 底层容器
(受保护成员对象)

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20) | 按照字典顺序比较 queue 中的值 (函数模板)
std::swap(std::queue) (C++11) | 特化 std::swap 算法 (函数模板)

辅助类

std::uses_allocator<std::queue>
(C++11)
 特化 std::uses_allocator 类型特征
(类模板特化)

推导指引 (C++17 起)


std::queue<T,Container>::back

< cpp‎ | container‎ | queue
reference back();
const_reference back() const;

返回到 queue 中末元素的引用。这是最近推入的元素。等效地调用 c.back() 。

参数

（无）

返回值

到末元素的引用

复杂度

常数

参阅

front | 访问第一个元素 (公开成员函数)
push | 向队列尾部插入元素 (公开成员函数)


std::queue 的推导指引

< cpp‎ | container‎ | queue

定义于头文件 <queue>
template<class Container>

queue(Container)

-> queue<typename Container::value_type, Container>;
 (1) (C++17 起)
template<class InputIt>

queue(InputIt, InputIt)

-> queue</*iter-value-t*/<InputIt>>;
 (2) (C++23 起)
template<class Container, class Alloc>

queue(Container, Alloc)

-> queue<typename Container::value_type, Container>;
 (3) (C++17 起)
template<class InputIt, class Alloc>

queue(InputIt, InputIt, Alloc)
-> queue</*iter-value-t*/<InputIt>,

std::deque </*iter-value-t*/<InputIt>, Alloc>>;
 (4) (C++23 起)

为 queue 提供推导指引以允许从底层容器类型推导。

1) 从参数推导底层容器类型。
2) 从迭代器推导元素类型，以 std::deque </*iter-value-t*/<InputIt>> 为底层容器类型，其中 /*iter-value-t*/<InputIt> 代表 typename std::iterator_traits <InputIt>::value_type 。
3-4) 同 (1-2) ，除了提供分配器。

这些重载仅若

  • InputIt （若存在）满足老式输入迭代器 (LegacyInputIterator) ，
  • Container （若存在）不满足分配器 (Allocator) ，
  • 对于 (3) (C++23 前)(4) (C++23 起) ，Alloc 满足分配器 (Allocator) ，以及
  • 若 Container 与 Alloc 均存在则 std::uses_allocator_v <Container, Alloc> 为 true

才参与重载决议。

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

示例

#include <vector>
#include <queue>
int main() {
   std::vector<int> v = {1,2,3,4};
   std::queue s{v};    // 指引 #1 推导 std::queue<int, vector<int>>
}


std::queue<T,Container>::emplace

< cpp‎ | container‎ | queue

template< class... Args > void emplace( Args&&... args ); | (C++11 起) (C++17 前)
template< class... Args > decltype(auto) emplace( Args&&... args ); | (C++17 起)

推入新元素到 queue 结尾。原位构造元素，即不进行移动或复制操作。以与提供给函数者准确相同的参数调用元素的构造函数。

等效地调用 c.emplace_back( std::forward <Args>(args)...); 。

参数

args - 转发给元素构造函数的参数

返回值

（无） | (C++17 前)
上述对 Container::emplace_back 的调用返回的值或引用，若它存在。 | (C++17 起)

复杂度

等同于 Container::emplace_back 的复杂度。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2783 | C++17 | emplace 返回 reference ，破坏与 C++17 前容器的兼容性 | 返回 decltype(auto)

参阅

push | 向队列尾部插入元素 (公开成员函数)
pop | 删除首个元素 (公开成员函数)


std::queue<T,Container>::empty

< cpp‎ | container‎ | queue

bool empty() const; | (C++20 前)
[[nodiscard]] bool empty() const; | (C++20 起)

检查底层容器是否为空，即是否 c.empty() 。

参数

（无）

返回值

若底层容器为空则为 true ，否则为 false 。

复杂度

常数

参阅

size
 返回容纳的元素数
(公开成员函数)


std::queue<T,Container>::front

< cpp‎ | container‎ | queue
reference front();
const_reference front() const;

返回到 queue 中首元素的引用。此元素将是调用 pop() 时第一个移除的元素。等效地调用 c.front() 。

参数

（无）

返回值

到首元素的引用。

复杂度

常数

参阅

back | 访问最后一个元素 (公开成员函数)
pop | 删除首个元素 (公开成员函数)


std::queue<T,Container>::operator=

< cpp‎ | container‎ | queue
queue& operator=( const queue& other ); | (1) |
queue& operator=( queue&& other ); | (2) | (C++11 起)

以 other 的内容替换容器适配器的内容。

1) 复制赋值运算符。以 other 的内容副本替换内容。等效地调用 c = other.c; 。(隐式声明)
2) 移动赋值运算符。用移动语义以 other 的内容替换内容。等效地调用 c = std::move(other.c); 。(隐式声明)

参数

other - 用作源的另一容器适配器

返回值

*this

复杂度

等价于底层容器 operator= 的复杂度。

参阅

(构造函数)
 构造 queue
(公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::queue)

< cpp‎ | container‎ | queue

template< class T, class Container >
bool operator==( const std::queue <T,Container>& lhs, const std::queue <T,Container>& rhs );
 (1)
template< class T, class Container >
bool operator!=( const std::queue <T,Container>& lhs, const std::queue <T,Container>& rhs );
 (2)
template< class T, class Container >
bool operator<( const std::queue <T,Container>& lhs, const std::queue <T,Container>& rhs );
 (3)
template< class T, class Container >
bool operator<=( const std::queue <T,Container>& lhs, const std::queue <T,Container>& rhs );
 (4)
template< class T, class Container >
bool operator>( const std::queue <T,Container>& lhs, const std::queue <T,Container>& rhs );
 (5)
template< class T, class Container >
bool operator>=( const std::queue <T,Container>& lhs, const std::queue <T,Container>& rhs );
 (6)
template< class T, std::three_way_comparable Container >

std::compare_three_way_result_t<Container>

operator<=>( const std::queue <T,Container>& lhs, const std::queue <T,Container>& rhs );
 (7) (C++20 起)

比较二个容器适配器的底层容器。通过应用对应的运算符到底层容器进行比较。

参数

lhs, rhs - 要比较内容的迭代器适配器
-
T 必须满足可相等比较 (EqualityComparable) 的要求。

返回值

@1-6若对应比较产出 true 则为 true ，否则为 false 。

7) 底层容器上三路比较的结果。

复杂度

与容器大小成线性


std::queue<T,Container>::pop

< cpp‎ | container‎ | queue

void pop();

从 queue 移除前端元素。等效地调用 c.pop_front() 。

参数

（无）

返回值

（无）

复杂度

等于 Container::pop_front 的复杂度。

参阅

emplace (C++11) | 在尾部原位构造元素 (公开成员函数)
push | 向队列尾部插入元素 (公开成员函数)
front | 访问第一个元素 (公开成员函数)


std::queue<T,Container>::push

< cpp‎ | container‎ | queue

void push( const value_type& value ); |
void push( value_type&& value ); | (C++11 起)

推给定的元素 value 到 queue 尾。

1) 等效地调用 c.push_back(value)
2) 等效地调用 c.push_back(std::move(value))

参数

value - 要推入的元素值

返回值

（无）

复杂度

等于 Container::push_back 的复杂度。

参阅

emplace (C++11) | 在尾部原位构造元素 (公开成员函数)
pop | 删除首个元素 (公开成员函数)


std::queue<T,Container>::queue

< cpp‎ | container‎ | queue

queue() : queue(Container()) { } | (1) | (C++11 起)
 | (2) |
explicit queue( const Container& cont = Container() ); |  |  | (C++11 前)
explicit queue( const Container& cont ); |  |  | (C++11 起)
explicit queue( Container&& cont ); | (3) | (C++11 起)
queue( const queue& other ); | (4) |
queue( queue&& other ); | (5) | (C++11 起)
template< class InputIt > queue( InputIt first, InputIt last ); | (6) | (C++23 起)
template< class Alloc > explicit queue( const Alloc& alloc ); | (7) | (C++11 起)
template< class Alloc > queue( const Container& cont, const Alloc& alloc ); | (8) | (C++11 起)
template< class Alloc > queue( Container&& cont, const Alloc& alloc ); | (9) | (C++11 起)
template< class Alloc > queue( const queue& other, const Alloc& alloc ); | (10) | (C++11 起)
template< class Alloc > queue( queue&& other, const Alloc& alloc ); | (11) | (C++11 起)
template< class InputIt, class Alloc > queue( InputIt first, InputIt last, const Alloc& alloc ); | (12) | (C++23 起)

从各种数据源构造容器适配器的新底层容器。

1) 默认构造函数。值初始化容器。
2) 以 cont 的内容复制构造底层容器 c 。此亦为默认构造函数。 (C++11 前)
3) 以 std::move(cont) 移动构造底层容器 c 。
4) 复制构造函数。以 other.c 的内容复制构造适配器。
5) 移动构造函数。以 std::move(other.c) 构造适配器。
6) 以范围 [first, last) 的内容构造底层容器 c 。此重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 才参与重载决议。
7-12) 这些构造函数仅若 std::uses_allocator <Container, Alloc> 为 true ，即底层容器是知分配器容器（对所有标准库容器为 true ）才参与重载决议。
7) 以 alloc 为分配器构造底层容器，如同以 c(alloc) 。
8) 用 cont 的内容，并以 alloc 为分配器构造底层容器，如同以 c(cont, alloc) 。
9) 以 cont 的内容用移动语义，同时以 alloc 为分配器构造底层容器，如同以 c(std::move(cont), alloc) 。
10) 以 other.c 的内容，并以 alloc 为分配器构造适配器，如同以 c(other.c, alloc) 。
11) 以 other 的内容使用移动语义，并以 alloc 为分配器构造适配器，如同以 c(std::move(other.c), alloc) 。
12) 以范围 [first, last) 的内容并以 alloc 为分配器构造底层容器，如同用 c(first, last, alloc) 。此重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 才参与重载决议。

参数

alloc | - | 用于底层容器所有内存分配的分配器
other | - | 用作源初始化底层容器的另一容器适配器
cont | - | 用作源初始化底层容器的容器
first, last | - | 用以初始化的元素范围
类型要求
- Alloc 必须满足分配器 (Allocator) 的要求。
- Container 必须满足容器 (Container) 的要求。接受一个分配器参数的构造函数仅若 Container 满足知分配器容器 (AllocatorAwareContainer) 的要求参与重载决议。
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

复杂度

同被包装容器上的对应操作。

示例

#include <queue>
#include <deque>
#include <iostream>

int main()
{
    std::queue<int> c1;
    c1.push(5);
    std::cout << c1.size() << '\n';

    std::queue<int> c2(c1);
    std::cout << c2.size() << '\n';

    std::deque<int> deq {3, 1, 4, 1, 5};
    std::queue<int> c3(deq);
    std::cout << c3.size() << '\n';
}

输出：

1
1
5

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式

参阅

operator=
 赋值给容器适配器
(公开成员函数)


std::queue<T,Container>::size

< cpp‎ | container‎ | queue

size_type size() const;

返回底层容器中的元素数，即 c.size() 。

参数

（无）

返回值

容器中的元素数。

复杂度

常数。

参阅

empty
 检查底层容器是否为空
(公开成员函数)


std::queue<T,Container>::swap

< cpp‎ | container‎ | queue

void swap( queue& other ) noexcept(/* see below */); | (C++11 起)

交换容器适配器与 other 的内容。等效地调用 using std::swap ; swap(c, other.c); 。

参数

other - 要交换内容的容器适配器

返回值

（无）

异常

noexcept 说明： noexcept(noexcept(swap(c, other.c))) 上述表达式中，用与 C++17 std::is_nothrow_swappable 特性所用的相同方式查找标识符 swap 。 | (C++11 起) (C++17 前)
noexcept 说明： noexcept( std::is_nothrow_swappable_v <Container>) | (C++17 起)

复杂度

与底层容器相同（常为常数）。

注解

一些实现（例如 libc++ ）对 C++11 前模式提供 swap 成员函数作为扩展。

示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2456 | C++11 | noexcept 规定非良构 | 使之能用

参阅

std::swap(std::queue)
(C++11)
 特化 std::swap 算法
(函数模板)


std::swap(std::queue)

< cpp‎ | container‎ | queue

定义于头文件 <queue>
template< class T, class Container >

void swap( std::queue <T,Container>& lhs,

std::queue <T,Container>& rhs );
 (C++11 起)
(C++17 前)
template< class T, class Container >

void swap( std::queue <T,Container>& lhs,

std::queue <T,Container>& rhs ) noexcept(/* see below */);
 (C++17 起)

为 std::queue 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

此重载仅若 std::is_swappable_v <Container> 为 true 才参与重载决议。

 (C++17 起)

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

与交换底层容器相同。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++11)
 交换内容
(公开成员函数)


std::uses_allocator<std::queue>

< cpp‎ | container‎ | queue

template< class T, class Container, class Alloc > struct uses_allocator<queue<T,Container>,Alloc> : std::uses_allocator <Container, Alloc>::type { }; | (C++11 起)

为 std::queue 提供 std::uses_allocator 类型特性的通透特化：容器适配器使用分配器，若且唯若底层容器使用。

继承自 std::integral_constant

成员常量

value
[静态]
 true
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

参阅

uses_allocator
(C++11)
 检查指定的类型是否支持使用分配器的构造
(类模板)


std::queue<T,Container>::~queue

< cpp‎ | container‎ | queue

~queue();

销毁 queue 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 queue 大小成线性。


std::set

< cpp‎ | container
定义于头文件 <set>
template<

class Key,
class Compare = std::less <Key>,
class Allocator = std::allocator <Key>

> class set;
 (1)
namespace pmr {

template <class Key, class Compare = std::less <Key>>
using set = std::set<Key, Compare, std::pmr::polymorphic_allocator <Key>>;

}
 (2) (C++17 起)

std::set 是关联容器，含有 Key 类型对象的已排序集。用比较函数 比较 (Compare) 进行排序。搜索、移除和插入拥有对数复杂度。 set 通常以红黑树实现。

在每个标准库使用比较 (Compare) 概念的场所，用等价关系确定唯一性。不精确地说，若二个对象 a 与 b 相互间既不比较大于亦不比较小于： !comp(a, b) && !comp(b, a) ，则认为它们等价。

std::set 满足容器 (Container) 、知分配器容器 (AllocatorAwareContainer) 、关联容器 (AssociativeContainer) 和可逆容器 (ReversibleContainer) 的要求。

成员类型

成员类型 | 定义
key_type | Key
value_type | Key
size_type | 无符号整数类型（通常是 std::size_t ）
difference_type | 有符号整数类型（通常是 std::ptrdiff_t ）
key_compare | Compare
value_compare | Compare
allocator_type | Allocator
reference | value_type&
const_reference | const value_type&
pointer
Allocator::pointer | (C++11 前)
std::allocator_traits <Allocator>::pointer | (C++11 起)
const_pointer
Allocator::const_pointer | (C++11 前)
std::allocator_traits <Allocator>::const_pointer | (C++11 起)
iterator | 指向 value_type 的常老式双向迭代器 (LegacyBidirectionalIterator)
const_iterator | 指向 const value_type 的老式双向迭代器 (LegacyBidirectionalIterator)
reverse_iterator | std::reverse_iterator <iterator>
const_reverse_iterator | std::reverse_iterator <const_iterator>
node_type(C++17 起) | 表示容器结点的结点把柄特化
insert_return_type(C++17 起) 描述插入 node_type 结果的类型，下列类型的特化
template <class Iter, class NodeType> struct /*unspecified*/ {
    Iter     position;
    bool     inserted;
    NodeType node;
};
，以模板实参 iterator 和 node_type 实例化。

成员函数

(构造函数)
 构造 set
(公开成员函数)
(析构函数)
 析构 set
(公开成员函数)
operator=
 赋值给容器
(公开成员函数)
get_allocator
 返回相关的分配器
(公开成员函数)
迭代器
begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)
rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)
rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)
容量
empty
 检查容器是否为空
(公开成员函数)
size
 返回容纳的元素数
(公开成员函数)
max_size
 返回可容纳的最大元素数
(公开成员函数)
修改器
clear
 清除内容
(公开成员函数)
insert
 插入元素或结点 (C++17 起)
(公开成员函数)
emplace
(C++11)
 原位构造元素
(公开成员函数)
emplace_hint
(C++11)
 使用提示原位构造元素
(公开成员函数)
erase
 擦除元素
(公开成员函数)
swap
 交换内容
(公开成员函数)
extract
(C++17)
 从另一容器释出结点
(公开成员函数)
merge
(C++17)
 从另一容器接合结点
(公开成员函数)
查找
count
 返回匹配特定键的元素数量
(公开成员函数)
find
 寻找带有特定键的元素
(公开成员函数)
contains
(C++20)
 检查容器是否含有带特定键的元素
(公开成员函数)
equal_range
 返回匹配特定键的元素范围
(公开成员函数)
lower_bound
 返回指向首个不小于给定键的元素的迭代器
(公开成员函数)
upper_bound
 返回指向首个大于给定键的元素的迭代器
(公开成员函数)
观察器
key_comp
 返回用于比较键的函数
(公开成员函数)
value_comp
 返回用于在value_type类型的对象中比较键的函数。
(公开成员函数)

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 按照字典顺序比较 set 中的值 (函数模板)
std::swap(std::set) | 特化 std::swap 算法 (函数模板)
erase_if(std::set) (C++20) | 擦除所有满足特定判别标准的元素 (函数模板)

推导指引 (C++17 起)

注解

成员类型 iterator 与 const_iterator 可能是同一类型的别名。这表明以二个类型为参数类型的一对函数重载可能违背单一定义规则。因为 iterator 可转换为 const_iterator ，单个以 const_iterator 为参数类型的函数会是有效的。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 103 | C++98 | 迭代器允许修改键 | 使迭代器为常


std::set<Key,Compare,Allocator>::begin, std::set<Key,Compare,Allocator>::cbegin

< cpp‎ | container‎ | set

iterator begin(); | (C++11 前)
iterator begin() noexcept; | (C++11 起)
const_iterator begin() const; | (C++11 前)
const_iterator begin() const noexcept; | (C++11 起)
const_iterator cbegin() const noexcept; | (C++11 起)

返回指向 set 首元素的迭代器。

若 set 为空，则返回的迭代器将等于 end() 。

参数

（无）

返回值

指向首元素的迭代器。

复杂度

常数。

注意

因为 iterator 和 const_iterator 都是常迭代器（而且实际上可以是同一类型），故不可能通过任何这些成员函数返回的迭代器修改容器元素。

示例

#include <algorithm>
#include <iostream>
#include <set>

int main() {
  std::set<int> set = { 3, 1, 4, 1, 5, 9, 2, 6, 5 };
  std::for_each(set.cbegin(), set.cend(), [](int x) {
    std::cout << x << ' ';
  });
  std::cout << '\n';
}

输出：

1 2 3 4 5 6 9

参阅

end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)


std::set<Key,Compare,Allocator>::clear

< cpp‎ | container‎ | set

void clear(); | (C++11 前)
void clear() noexcept; | (C++11 起)

从容器擦除所有元素。此调用后 size() 返回零。

非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器保持合法。

参数

（无）

返回值

（无）

复杂度

与容器大小，即元素数成线性。

示例

#include <algorithm>
#include <iostream>
#include <set>

int main()
{
    std::set<int> container{1, 2, 3};

    auto print = [](const int& n) { std::cout << " " << n; };

    std::cout << "Before clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';

    std::cout << "Clear\n";
    container.clear();

    std::cout << "After clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';
}

输出：

Before clear: 1 2 3
Size=3
Clear
After clear:
Size=0

参阅

erase
 擦除元素
(公开成员函数)


std::set<Key,Compare,Allocator>::contains

< cpp‎ | container‎ | set

bool contains( const Key& key ) const; | (1) | (C++20 起)
template< class K > bool contains( const K& x ) const; | (2) | (C++20 起)
1) 检查容器中是否有键等价于 key 的元素。
2) 检查是否有键比较等价于值 x 的元素。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 任何能通透地与键比较的类型的值

返回值

若有这种元素则为 true ，否则为 false 。

复杂度

与容器大小成对数。

示例

#include <iostream>
#include <set>

int main()
{
    std::set<int> example = {1, 2, 3, 4};

    for(int x: {2, 5}) {
        if(example.contains(x)) {
            std::cout << x << ": Found\n";
        } else {
            std::cout << x << ": Not found\n";
        }
    }
}

输出：

2: Found
5: Not found

参阅

find | 寻找带有特定键的元素 (公开成员函数)
count | 返回匹配特定键的元素数量 (公开成员函数)
equal_range | 返回匹配特定键的元素范围 (公开成员函数)


std::set<Key,Compare,Allocator>::count

< cpp‎ | container‎ | set

size_type count( const Key& key ) const; | (1) |
template< class K > size_type count( const K& x ) const; | (2) | (C++14 起)

返回拥有关键比较等价于指定参数的元素数，因为此容器不允许重复故为 1 或 0。

1) 返回拥有关键 key 的元素数。
2) 返回拥有关键比较等价于值 x 的元素数。此重载仅若有限定 id Compare::is_transparent 合法且指代一个类型才参与重载决议。这允许调用此函数而不构造 Key 的实例。

参数

key | - | 要计量元素数的关键值
x | - | 要与关键比较的替用值

返回值

拥有比较等价于 key 或 x 的关键的元素数，对于 (1) 为 1 或 0。

复杂度

与容器大小成对数。

参阅

find | 寻找带有特定键的元素 (公开成员函数)
equal_range | 返回匹配特定键的元素范围 (公开成员函数)


std::set 的推导指引

< cpp‎ | container‎ | set

定义于头文件 <set>
template<class InputIt,

class Comp = std::less <typename std::iterator_traits <InputIt>::value_type>,
class Alloc = std::allocator <typename std::iterator_traits <InputIt>::value_type>>
set(InputIt, InputIt, Comp = Comp(), Alloc = Alloc())

-> set<typename std::iterator_traits <InputIt>::value_type, Comp, Alloc>;
 (1) (C++17 起)
template<class Key, class Comp = std::less <Key>, class Alloc = std::allocator <Key>>

set( std::initializer_list <Key>, Comp = Comp(), Alloc = Alloc())

-> set<Key, Comp, Alloc>;
 (2) (C++17 起)
template<class InputIt, class Alloc>

set(InputIt, InputIt, Alloc)
-> set<typename std::iterator_traits <InputIt>::value_type,

std::less <typename std::iterator_traits <InputIt>::value_type>, Alloc>;
 (3) (C++17 起)
template<class Key, class Alloc>

set( std::initializer_list <Key>, Alloc)

-> set<Key, std::less <Key>, Alloc>;
 (4) (C++17 起)

为 set 提供这些推导指引以允许从范围（重载 (1,3) ）和 std::initializer_list （重载 (2,4) ）推导。此重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 、 Alloc 满足分配器 (Allocator) 且 Comp 不满足分配器 (Allocator) 才参与重载决议。

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

示例

#include <set>
int main() {
   std::set s = {1,2,3,4}; // 指引 #2 推导 std::set<int>
   std::set s2(s.begin(), s.end()); // 指引 #1 推导 std::set<int>
}


std::set<Key,Compare,Allocator>::emplace

< cpp‎ | container‎ | set

template< class... Args > std::pair <iterator,bool> emplace( Args&&... args ); | (C++11 起)

若容器中无拥有该关键的元素，则插入以给定的 args 原位构造的新元素到容器。

细心地使用 emplace 允许在构造新元素的同时避免不必要的复制或移动操作。 准确地以与提供给 emplace 者相同的参数，通过 std::forward <Args>(args)... 转发调用新元素的构造函数。 即使容器中已有拥有该关键的元素，也可能构造元素，该情况下新构造的元素将被立即销毁。

没有迭代器或引用被非法化。

参数

args - 要转发给元素构造函数的参数

返回值

返回由指向被插入元素，或若不发生插入则为既存元素的迭代器，和指代插入是否发生的 bool （若发生插入则为 true ，否则为 false ）。

异常

若任何操作抛出异常，则此函数无效果。

复杂度

与容器大小成对数。

示例

#include <chrono>
#include <functional>
#include <iomanip>
#include <iostream>
#include <set>
#include <string>

class Dew
{
  private:
    int a;
    int b;
    int c;

  public:
    Dew(int _a, int _b, int _c)
      : a(_a), b(_b), c(_c)
    {}

    bool operator<(const Dew &other) const
    {
      if (a < other.a)
        return true;
      if (a == other.a && b < other.b)
        return true;
      return (a == other.a && b == other.b && c < other.c);
    }
};

const int nof_operations = 120;

int set_emplace() {
    std::set<Dew> set;
    for(int i = 0; i < nof_operations; ++i)
        for(int j = 0; j < nof_operations; ++j)
            for(int k = 0; k < nof_operations; ++k)
              set.emplace(i, j, k);

    return set.size();
}

int set_insert() {
    std::set<Dew> set;
    for(int i = 0; i < nof_operations; ++i)
        for(int j = 0; j < nof_operations; ++j)
            for(int k = 0; k < nof_operations; ++k)
              set.insert(Dew(i, j, k));

    return set.size();
}

void timeit(std::function<int()> set_test, std::string what = "") {
  auto start = std::chrono::system_clock::now();
  int setsize = set_test();
  auto stop = std::chrono::system_clock::now();
  std::chrono::duration<double, std::milli> time = stop - start;
  if (what.size() > 0 && setsize > 0) {
    std::cout << std::fixed << std::setprecision(2)
        << time.count() << "  ms for " << what << '\n';
  }
}

int main()
{
  set_insert();
  timeit(set_insert, "insert");
  timeit(set_emplace, "emplace");
  timeit(set_insert, "insert");
  timeit(set_emplace, "emplace");
}

可能的输出：

638.45  ms for insert
619.44  ms for emplace
609.43  ms for insert
652.55  ms for emplace

参阅

emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)


std::set<Key,Compare,Allocator>::emplace_hint

< cpp‎ | container‎ | set
template <class... Args> iterator emplace_hint( const_iterator hint, Args&&... args ); | (C++11 起)

插入新元素到容器中尽可能接近于恰在 hint 前的位置。原位构造元素，即不进行复制或移动操作。

以提供给函数的参数准确相同者，以 std::forward <Args>(args)... 转发调用元素的构造函数。

没有迭代器或引用被非法化。

参数

hint | - | 指向新元素将插入到其前的位置的迭代器
args | - | 转发给元素构造函数的参数

返回值

返回指向新插入元素的迭代器。

若因元素已存在而插入失败，则返回指向拥有等价关键的既存元素的迭代器。

异常

若任何操作抛出异常，则此函数无效果（强异常保证）。

复杂度

通常与容器大小成对数，但若新元素正好被插入到 hint 之前则为均摊常数。

示例

#include <set>
#include <chrono>
#include <iostream>
#include <iomanip>
#include <functional>

const int nof_operations = 100500;

int set_emplace() {
  std::set<int> set;
  for(int i = 0; i < nof_operations; ++i) {
    set.emplace(i);
  }
  return set.size();
}

int set_emplace_hint() {
  std::set<int> set;
  auto it = set.begin();
  for(int i = 0; i < nof_operations; ++i) {
    set.emplace_hint(it, i);
    it = set.end();
  }
  return set.size();
}

int set_emplace_hint_wrong() {
  std::set<int> set;
  auto it = set.begin();
  for(int i = nof_operations; i > 0; --i) {
    set.emplace_hint(it, i);
    it = set.end();
  }
  return set.size();
}

int set_emplace_hint_corrected() {
  std::set<int> set;
  auto it = set.begin();
  for(int i = nof_operations; i > 0; --i) {
    set.emplace_hint(it, i);
    it = set.begin();
  }
  return set.size();
}

int set_emplace_hint_closest() {
  std::set<int> set;
  auto it = set.begin();
  for(int i = 0; i < nof_operations; ++i) {
    it = set.emplace_hint(it, i);
  }
  return set.size();
}

void timeit(std::function<int()> set_test, std::string what = "") {
  auto start = std::chrono::system_clock::now();
  int setsize = set_test();
  auto stop = std::chrono::system_clock::now();
  std::chrono::duration<double, std::milli> time = stop - start;
  if (what.size() > 0 && setsize > 0) {
    std::cout << std::fixed << std::setprecision(2)
              << time.count() << "  ms for " << what << '\n';
  }
}

int main() {
   timeit(set_emplace); // 栈加热
   timeit(set_emplace, "plain emplace");
   timeit(set_emplace_hint, "emplace with correct hint");
   timeit(set_emplace_hint_wrong, "emplace with wrong hint");
   timeit(set_emplace_hint_corrected, "corrected emplace");
   timeit(set_emplace_hint_closest, "emplace using returned iterator");
}

可能的输出：

18.96  ms for plain emplace
7.95  ms for emplace with correct hint
19.39  ms for emplace with wrong hint
8.39  ms for corrected emplace
7.90  ms for emplace using returned iterator

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)


std::set<Key,Compare,Allocator>::empty

< cpp‎ | container‎ | set

bool empty() const; | (C++11 前)
bool empty() const noexcept; | (C++11 起) (C++20 前)
[[nodiscard]] bool empty() const noexcept; | (C++20 起)

检查容器是否无元素，即是否 begin() == end() 。

参数

（无）

返回值

若容器为空则为 true ，否则为 false

复杂度

常数。

示例

下列代码用 empty 检查 std::set <int> 是否含有任何元素：

#include <set>
#include <iostream>

int main()
{
    std::set<int> numbers;
    std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';

    numbers.insert(42);
    numbers.insert(13317);
    std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
}

输出：

Initially, numbers.empty(): 1
After adding elements, numbers.empty(): 0

参阅

size
 返回容纳的元素数
(公开成员函数)


std::set<Key,Compare,Allocator>::end, std::set<Key,Compare,Allocator>::cend

< cpp‎ | container‎ | set

iterator end(); | (C++11 前)
iterator end() noexcept; | (C++11 起)
const_iterator end() const; | (C++11 前)
const_iterator end() const noexcept; | (C++11 起)
const_iterator cend() const noexcept; | (C++11 起)

返回指向 set 末元素后一元素的迭代器。

此元素表现为占位符；试图访问它导致未定义行为。

参数

（无）

返回值

指向后随最后元素的迭代器。

复杂度

常数。

注意

因为 iterator 和 const_iterator 都是常迭代器（而且实际上可以是同一类型），故不可能通过任何这些成员函数返回的迭代器修改容器元素。

示例

#include <algorithm>
#include <iostream>
#include <set>

int main() {
  std::set<int> set = { 3, 1, 4, 1, 5, 9, 2, 6, 5 };
  std::for_each(set.cbegin(), set.cend(), [](int x) {
    std::cout << x << ' ';
  });
  std::cout << '\n';
}

输出：

1 2 3 4 5 6 9

参阅

begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)


std::set<Key,Compare,Allocator>::equal_range

< cpp‎ | container‎ | set

std::pair <iterator,iterator> equal_range( const Key& key ); | (1) |
std::pair <const_iterator,const_iterator> equal_range( const Key& key ) const; | (2) |
template< class K > std::pair <iterator,iterator> equal_range( const K& x ); | (3) | (C++14 起)
template< class K > std::pair <const_iterator,const_iterator> equal_range( const K& x ) const; | (4) | (C++14 起)

返回容器中所有拥有给定关键的元素范围。范围以二个迭代器定义，一个指向首个不小于 key 的元素，另一个指向首个大于 key 的元素。首个迭代器可以换用 lower_bound() 获得，而第二迭代器可换用 upper_bound() 获得。

1,2) 比较关键与 key 。
3,4) 比较关键与值 x 。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。
本节未完成
原因：更好地解释

参数

key | - | 要比较元素的关键值
x | - | 能与 Key 比较的替用值

返回值

含一对定义所需范围的迭代器的 std::pair ：第一个指向首个不小于 key 的元素，第二个指向首个大于 key 的元素。

若无元素不小于 key ，则将尾后（见 end() ）迭代器作为第一元素返回。类似地，若无元素大于 key ，则将尾后迭代器作为第二元素返回。

复杂度

与容器大小成对数。

示例

#include <set>
#include <iostream>

template <typename I>
void print_equal_range(I first, I lb, I ub, I last) {
    for (I i{first}; i != lb; ++i)
        std::cout << *i << " ";
    std::cout << "[ ";
    for (I i{lb}; i != ub; ++i)
        std::cout << *i << " ";
    std::cout << ") ";
    for (I i{ub}; i != last; ++i)
        std::cout << *i << " ";
    std::cout << '\n';
}

int main()
{
    std::set<int> c{4, 3, 2, 1, 3, 3};
    std::cout << "c = ";
    print_equal_range(begin(c), begin(c), end(c), end(c));
    for (int key{}; key != 6; ++key) {
        std::cout << "key = " << key << "; equal range = ";
        const auto [lb, ub] = c.equal_range(key);
        print_equal_range(begin(c), lb, ub, end(c));
    }
}

输出：

c = [ 1 2 3 4 )
key = 0; equal range = [ ) 1 2 3 4
key = 1; equal range = [ 1 ) 2 3 4
key = 2; equal range = 1 [ 2 ) 3 4
key = 3; equal range = 1 2 [ 3 ) 4
key = 4; equal range = 1 2 3 [ 4 )
key = 5; equal range = 1 2 3 4 [ )

参阅

find | 寻找带有特定键的元素 (公开成员函数)
contains (C++20) | 检查容器是否含有带特定键的元素 (公开成员函数)
count | 返回匹配特定键的元素数量 (公开成员函数)
upper_bound | 返回指向首个大于给定键的元素的迭代器 (公开成员函数)
lower_bound | 返回指向首个不小于给定键的元素的迭代器 (公开成员函数)
equal_range | 返回匹配特定键值的元素范围 (函数模板)


std::set<Key,Compare,Allocator>::erase

< cpp‎ | container‎ | set

 | (1) |
void erase( iterator pos ); |  |  | (C++11 前)
iterator erase( iterator pos ); |  |  | (C++11 起)
iterator erase( const_iterator pos ); |  |  | (C++11 起)
 | (2) |
void erase( iterator first, iterator last ); |  |  | (C++11 前)
iterator erase( const_iterator first, const_iterator last ); |  |  | (C++11 起)
size_type erase( const key_type& key ); | (3) |
template< class K > size_type erase( K&& x ); | (4) | (C++23 起)

从容器移除指定的元素。

1) 移除位于 pos 的元素。若 iterator 与 const_iterator 为同一类型则仅提供一个重载。 (C++11 起)
2) 移除范围 [first; last) 中的元素，它必须是 *this 中的合法范围。
3) 移除键等价于 key 的元素（若存在一个）。
4) 移除键比较等价于值 x 的元素（若存在一个）。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

指向被擦除元素的引用和迭代器被非法化。其他引用和迭代器不受影响。

迭代器 pos 必须合法且可解引用。从而 end() 迭代器（合法，但不可解引用）不能用作 pos 所用的值。

参数

pos | - | 指向要移除的元素的迭代器
first, last | - | 要移除的元素范围
key | - | 要移除的元素键值
x | - | 任何能与键通透比较的类型的值，指代要移除的元素

返回值

1-2) （无） (C++11 前)后随最后被移除的元素的迭代器。 (C++11 起)
3,4) 被移除的元素数。

异常

1,2) 不抛出
3,4) 任何 Compare 对象所抛的异常

复杂度

给定 set 的实例 c ：

1) 均摊常数
2) log(c.size()) + std::distance (first, last)
3) log(c.size()) + c.count(key)
4) log(c.size()) + c.count(x)

示例

#include <set>
#include <iostream>
int main()
{
    std::set<int> c = { 1, 2, 3, 4,    1, 2, 3, 4 };

    auto print = [&c] {
        std::cout << "c = { ";
        for(int n : c)
            std::cout << n << ' ';
        std::cout << "}\n";
    };
    print();

    std::cout << "Erase all odd numbers:\n";
    for(auto it = c.begin(); it != c.end(); ) {
        if(*it % 2 != 0)
            it = c.erase(it);
        else
            ++it;
    }
    print();

    std::cout << "Erase 1, erased count: " << c.erase(1) << '\n';
    std::cout << "Erase 2, erased count: " << c.erase(2) << '\n';
    std::cout << "Erase 2, erased count: " << c.erase(2) << '\n';
    print();
}

输出：

c = { 1 2 3 4 }
Erase all odd numbers:
c = { 2 4 }
Erase 1, erased count: 0
Erase 2, erased count: 1
Erase 2, erased count: 0
c = { 4 }

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2059 | C++11 | 对一个 const_iterator 的重载引入了新的歧义 | 添加了对 iterator 的重载

参阅

clear
 清除内容
(公开成员函数)


std::erase_if (std::set)

< cpp‎ | container‎ | set

定义于头文件 <set>
template< class Key, class Compare, class Alloc, class Pred >

typename std::set <Key,Compare,Alloc>::size_type

erase_if( std::set <Key,Compare,Alloc>& c, Pred pred);
 (C++20 起)

从容器中擦除所有满足谓词 pred 的元素。等价于

auto old_size = c.size();
for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}
return old_size - c.size();

参数

c | - | 要从中擦除的元素
pred | - | 若应该擦除元素则对它返回 true 的谓词

返回值

擦除的元素数。

复杂度

线性。

示例

#include <set>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& container)
{
    os << "{ ";
    for (const auto& item : container) {
        os << item << ' ';
    }
    return os << "}";
}

int main()
{
    std::set data { 0, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7 };
    std::cout << "Original:\n" << data << '\n';

    auto divisible_by_3 = [](auto const& x) { return (x % 3) == 0; };

    const auto count = std::erase_if(data, divisible_by_3);

    std::cout << "Erase all items divisible by 3:\n" << data << '\n'
              << count << " items erased.\n";
}

输出：

Original:
{ 0 1 2 3 4 5 6 7 }
Erase all items divisible by 3:
{ 1 2 4 5 7 }
3 items erased.

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::set<Key,Compare,Allocator>::extract

< cpp‎ | container‎ | set

node_type extract( const_iterator position ); | (1) | (C++17 起)
node_type extract( const key_type& k ); | (2) | (C++17 起)
template< class K > node_type extract( K&& x ); | (3) | (C++23 起)
1) 解链含 position 所指向元素的结点并返回占有它的结点柄。
2) 若容器拥有元素而其关键等于 x ，则从容器解链该元素并返回占有它的结点柄。否则，返回空结点柄。
3) 同 (2) 。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

任何情况下，均不复制或移动元素，只重指向容器结点的内部指针（可能出现再平衡，和 erase() 一样）。

释出结点只会非法化指向被释出元素的迭代器。指向被释出元素的指针和引用保持合法，但在结点柄占有该元素时不能使用：若元素被插入容器，就能使用它们。

参数

position | - | 指向此容器中的合法迭代器
k | - | 鉴别要被释出的结点的键
x | - | 任何能与键通透比较的类型的值，鉴别要释出的结点

返回值

占有被释出元素的结点柄，或 (2,3) 中找不到元素的情况下为空结点柄。

复杂度

1) 均摊常数
2,3) log(a.size())

注解

extract 是从 set 带走仅移动对象的唯一方式：

set<move_only_type> s;
s.emplace(...);
move_only_type mot = move(s.extract(s.begin()).value());

示例

#include <algorithm>
#include <iostream>
#include <set>

int main()
{
    std::set<int> cont{1, 2, 3};

    auto print = [](const int& n) { std::cout << " " << n; };

    std::cout << "Start:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 释出结点柄并更改键
    auto nh = cont.extract(1);
    nh.value() = 4;

    std::cout << "After extract and before insert:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 往回插入结点柄
    cont.insert(move(nh));

    std::cout << "End:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';
}

输出：

Start: 1 2 3
After extract and before insert: 2 3
End: 2 3 4

参阅

merge (C++17) | 从另一容器接合结点 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)
erase | 擦除元素 (公开成员函数)


std::set<Key,Compare,Allocator>::find

< cpp‎ | container‎ | set

iterator find( const Key& key ); | (1) |
const_iterator find( const Key& key ) const; | (2) |
template< class K > iterator find( const K& x ); | (3) | (C++14 起)
template< class K > const_iterator find( const K& x ) const; | (4) | (C++14 起)
1,2) 寻找键等于 key 的的元素。
3,4) 寻找键比较等价于值 x 的元素。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 能通透地与键比较的任何类型值

返回值

指向键等于 key 的元素的迭代器。若找不到这种元素，则返回尾后（见 end() ）迭代器。

复杂度

与容器大小成对数。

示例

#include <iostream>
#include <set>

struct FatKey   { int x; int data[1000]; };
struct LightKey { int x; };
// 注：如上详述，容器必须使用 std::less<> （或其他通透比较器）以访问这些重载。
// 这包括标准重载，例如在 std::string 与 std::string_view 之间。
bool operator<(const FatKey& fk, const LightKey& lk) { return fk.x < lk.x; }
bool operator<(const LightKey& lk, const FatKey& fk) { return lk.x < fk.x; }
bool operator<(const FatKey& fk1, const FatKey& fk2) { return fk1.x < fk2.x; }

int main()
{
// 简单比较演示
    std::set<int> example = {1, 2, 3, 4};

    auto search = example.find(2);
    if (search != example.end()) {
        std::cout << "Found " << (*search) << '\n';
    } else {
        std::cout << "Not found\n";
    }

// 通透比较演示
    std::set<FatKey, std::less<>> example2 = { {1, {} }, {2, {} }, {3, {} }, {4, {} } };

    LightKey lk = {2};
    auto search2 = example2.find(lk);
    if (search2 != example2.end()) {
        std::cout << "Found " << search2->x << '\n';
    } else {
        std::cout << "Not found\n";
    }

}

输出：

Found 2
Found 2

参阅

count | 返回匹配特定键的元素数量 (公开成员函数)
equal_range | 返回匹配特定键的元素范围 (公开成员函数)


std::set<Key,Compare,Allocator>::get_allocator

< cpp‎ | container‎ | set

allocator_type get_allocator() const; | (C++11 前)
allocator_type get_allocator() const noexcept; | (C++11 起)

返回与容器关联的分配器。

参数

（无）

返回值

关联的分配器。

复杂度

常数。


std::set<Key,Compare,Allocator>::insert

< cpp‎ | container‎ | set
std::pair <iterator,bool> insert( const value_type& value ); | (1) |
std::pair <iterator,bool> insert( value_type&& value ); | (2) | (C++11 起)
 | (3) |
iterator insert( iterator hint, const value_type& value ); |  |  | (C++11 前)
iterator insert( const_iterator hint, const value_type& value ); |  |  | (C++11 起)
iterator insert( const_iterator hint, value_type&& value ); | (4) | (C++11 起)
template< class InputIt > void insert( InputIt first, InputIt last ); | (5) |
void insert( std::initializer_list <value_type> ilist ); | (6) | (C++11 起)
insert_return_type insert(node_type&& nh); | (7) | (C++17 起)
iterator insert(const_iterator hint, node_type&& nh); | (8) | (C++17 起)

插入元素到容器，若容器未含拥有等价关键的元素。

1-2) 插入 value 。
3-4) 插入 value 到尽可能接近 (C++11 前)正好前于 (C++11 起) hint 的位置。
5) 插入来自范围 [first, last) 的元素。 若范围中的多个元素拥有比较等价的关键，则插入哪个元素是未指定的（待决的 LWG2844 ）。
6) 插入来自 initializer_list ilist 的元素。 若范围中的多个元素拥有比较等价的关键，则插入哪个元素是未指定的（待决的 LWG2844 ）。
7) 若 nh 是空的结点把柄，则不做任何事。否则插入 nh 所占有的元素到容器，若容器尚未含有拥有等价于 nh.key() 的关键的元素。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。
8) 若 nh 是空的结点把柄，则不做任何事并返回尾迭代器。否则，插入 nh 所占有的元素到容器，若容器尚未含有拥有等价于 nh.key() 的关键的元素，并返回指向拥有等于 nh.key() 的关键的元素的迭代器（无关乎插入成功还是失败）。若插入成功，则从 nh 移动，否则它保持该元素的所有权。元素被插入到尽可能接近正好先于 hint 的位置。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。

没有迭代器或引用被非法化。若插入成功，则在结点把柄保有元素时获得的指向该元素的指针和引用被非法化，而在提取前获得的指向元素的指针和引用变得合法。 (C++17 起)

参数

hint -
用作提示从何处开始搜索的迭代器 | (C++11 前)
指向新元素将被插入位置之前的迭代器 | (C++11 起)
value - 要插入的元素值
first, last - 要插入的元素范围
ilist - 插入值来源的 initializer_list
nh - 兼容的结点把柄
类型要求
-
InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

1-2) 返回由指向被插入元素（或阻止插入的元素）的迭代器和若插入发生则设为 true 的 bool 值。
3-4) 返回指向被插入元素，或阻止插入的元素的迭代器。
5-6) （无）
7) 返回 insert_return_type ，其成员初始化如下：若 nh 为空，则 inserted 为 false ， position 为 end() ，而 node 为空。否则发生插入， inserted 为 true ， position 指向被插入元素，而 node 为空。若插入失败，则 inserted 为 false ， node 拥有 nh 的先前值，而 position 指向拥有等价于 nh.key() 的关键的元素。
8) 若 nh 为空则为尾迭代器，若插入发生则为指向被插入元素的迭代器，而若插入失败则为指向拥有等价于 nh.key() 的关键的元素的迭代器。

异常

1-4) 若任何操作抛异常，则插入无效果。
本节未完成
原因：情况 5-8

复杂度

1-2) 与容器大小成对数， O(log(size())) 。
3-4) 若插入恰好发生在正好后于 hint 的位置，则为均摊常数，否则与容器大小成对数。 | (C++11 前)
3-4) 若插入恰好发生在正好先于 hint 的位置，则为均摊常数，否则与容器大小成对数。 | (C++11 起)
5-6) O(N*log(size() + N)) ，其中 N 是要插入的元素数。
7) 与容器大小成对数， O(log(size())) 。
8) 若插入恰好发生在正好先于 hint 的位置，则为均摊常数，否则与容器大小成对数。

注意

有提示插入 (3,4) 不返回 bool ，这是为了与顺序容器上的定位插入，如 std::vector::insert 签名兼容。这使得可以创建泛型插入器，例如 std::inserter 。检查有提示插入是否成功的一种方式是比较插入前后的 size() 。

重载 (5,6) 通常实现为循环，其中以 end() 为 hint 调用重载 (3) ；它们对后附最小元素大于 *this 中最大元素的有序序列（例如另一 set ）优化。

示例

#include <set>
#include <cassert>
#include <iostream>

int main()
{
  std::set<int> set;

  auto result_1 = set.insert(3);
  assert(result_1.first != set.end()); // 它是合法迭代器
  assert(*result_1.first == 3);
  if (result_1.second)
    std::cout << "insert done\n";

  auto result_2 = set.insert(3);
  assert(result_2.first == result_1.first); // 相同迭代器
  assert(*result_2.first == 3);
  if (!result_2.second)
    std::cout << "no insertion\n";
}

输出：

insert done
no insertion

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)


std::set<Key,Compare,Allocator>::key_comp

< cpp‎ | container‎ | set

key_compare key_comp() const;

返回用于比较关键的函数对象，它是此容器构造函数参数 comp 的副本，它与 value_comp 相同。

参数

（无）

返回值

比较关键的函数对象。

复杂度

常数

参阅

value_comp
 返回用于在value_type类型的对象中比较键的函数。
(公开成员函数)


std::set<Key,Compare,Allocator>::lower_bound

< cpp‎ | container‎ | set

iterator lower_bound( const Key& key ); | (1) |
const_iterator lower_bound( const Key& key ) const; | (1) |
template< class K > iterator lower_bound(const K& x); | (2) | (C++14 起)
template< class K > const_iterator lower_bound(const K& x) const; | (2) | (C++14 起)
1) 返回指向首个不小于 key 的元素的迭代器。
2) 返回指向首个比较不小于值 x 的元素的迭代器。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 要与元素比较的键值
x | - | 能与 Key 比较的替用值

返回值

指向首个不小于 key 的元素的迭代器。若找不到这种元素，则返回尾后迭代器（见 end() ）。

复杂度

与容器大小成对数。

参阅

equal_range | 返回匹配特定键的元素范围 (公开成员函数)
upper_bound | 返回指向首个大于给定键的元素的迭代器 (公开成员函数)


std::set<Key,Compare,Allocator>::max_size

< cpp‎ | container‎ | set

size_type max_size() const; | (C++11 前)
size_type max_size() const noexcept; | (C++11 起)

返回根据系统或库实现限制的容器可保有的元素最大数量，即对于最大容器的 std::distance (begin(), end()) 。

参数

（无）

返回值

元素数量的最大值。

复杂度

常数。

注解

此值通常反映容器大小上的理论极限，至多为 std::numeric_limits <difference_type>::max() 。运行时，可用 RAM 总量可能会限制容器大小到小于 max_size() 的值。

示例

#include <iostream>
#include <set>

int main()
{
    std::set<char> s;
    std::cout << "Maximum size of a 'set' is " << s.max_size() << "\n";
}

可能的输出：

Maximum size of a 'set' is 576460752303423487

参阅

size
 返回容纳的元素数
(公开成员函数)


std::set<Key,Compare,Allocator>::merge

< cpp‎ | container‎ | set

template<class C2> void merge( std::set <Key, C2, Allocator>& source ); | (1) | (C++17 起)
template<class C2> void merge( std::set <Key, C2, Allocator>&& source ); | (2) | (C++17 起)
template<class C2> void merge( std::multiset <Key, C2, Allocator>& source ); | (3) | (C++17 起)
template<class C2> void merge( std::multiset <Key, C2, Allocator>&& source ); | (4) | (C++17 起)

试图提取（“接合”） source 中每个元素，并用 *this 的比较对象插入到 *this 。 若 *this 中有元素，其键等价于来自 source 中元素的键，则不从 source 提取该元素。 不复制或移动元素，只会重指向容器结点的内部指针。指向被转移元素的所有指针和引用保持合法，但现在指代到 *this 中而非到 source 中。

若 get_allocator() != source.get_allocator() 则行为未定义。

参数

source - 传递结点来源的兼容容器

返回值

（无）

异常

不抛异常，除非比较抛出。

复杂度

N*log(size()+N)) ，其中 N 为 source.size() 。

示例

#include <iostream>
#include <set>

// 打印出容器
template <class Os, class K>
Os& operator<<(Os& os, const std::set<K>& v) {
    os << '[' << v.size() << "] {";
    bool o{};
    for (const auto& e : v)
        os << (o ? ", " : (o = 1, " ")) << e;
    return os << " }\n";
}

int main()
{
    std::set<char>
        p{ 'C', 'B', 'B', 'A' },
        q{ 'E', 'D', 'E', 'C' };

    std::cout << "p: " << p << "q: " << q;

    p.merge(q);

    std::cout << "p.merge(q);\n" << "p: " << p << "q: " << q;
}

输出：

p: [3] { A, B, C }
q: [3] { C, D, E }
p.merge(q);
p: [5] { A, B, C, D, E }
q: [1] { C }

参阅

extract (C++17) | 从另一容器释出结点 (公开成员函数)
insert | 插入元素或结点 (C++17 起) (公开成员函数)


std::set<Key,Compare,Allocator>::operator=

< cpp‎ | container‎ | set

set& operator=( const set& other ); | (1) |
 | (2) |
set& operator=( set&& other ); |  |  | (C++11 起) (C++17 前)
set& operator=( set&& other ) noexcept(/* see below */); |  |  | (C++17 起)
set& operator=( std::initializer_list <value_type> ilist ); | (3) | (C++11 起)

替换容器内容。

1) 复制赋值运算符。以 other 的副本替换内容。

若 std::allocator_traits <allocator_type>::propagate_on_container_copy_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若 *this 的分配器在赋值后将与其旧值比较不相等，则用旧分配器解分配内存，然后在复制元素前用新分配器分配内存。否则，在可行时可能复用 *this 所拥有的内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素复制赋值替换。

 (C++11 起)
2) 移动赋值运算符。用移动语义以 other 的内容替换内容（即从 other 移动 other 中的数据到此容器中）。之后 other 在合法但未指定的状态。
若 std::allocator_traits <allocator_type>::propagate_on_container_move_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若它为 false 且 *this 与 other 的分配器不比较相等，则 *this 不能接管 other 所拥有的内存的所有权且必须单独地移动赋值每个元素，并用其自身的分配器按需分配额外内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素移动赋值替换。
3) 以 initializer_list ilist 所标识者替换内容。

参数

other | - | 用作数据源的另一容器
ilist | - | 用作数据源的 initializer_list

返回值

*this

复杂度

1) 与 *this 和 other 的大小成线性。
2) 与 *this 的大小成线性，除非分配器不比较相等且不传播，该情况下与 *this 和 other 的大小成线性。
3) 通常为 O(NlogN) ，其中 N 为 size() + ilist.size() 。若 ilist 相对于 value_comp() 已排序则为线性。

异常

可能抛出实现定义的异常。

 (C++17 前)
1,3) 可能抛出实现定义的异常。
2)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value
&& std::is_nothrow_move_assignable <Compare>::value)
 (C++17 起)

注解

在容器移动赋值（重载 (2) ）后，除非不兼容的分配器强制逐元素移动赋值，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

下列代码用 operator= 赋值一个 std::set 给另一个：

#include <set>
#include <iostream>

void display_sizes(const std::set<int> &nums1,
                   const std::set<int> &nums2,
                   const std::set<int> &nums3)
{
    std::cout << "nums1: " << nums1.size()
              << " nums2: " << nums2.size()
              << " nums3: " << nums3.size() << '\n';
}

int main()
{
    std::set<int> nums1 {3, 1, 4, 6, 5, 9};
    std::set<int> nums2;
    std::set<int> nums3;

    std::cout << "Initially:\n";
    display_sizes(nums1, nums2, nums3);

    // 复制赋值从 nums1 复制数据到 nums2
    nums2 = nums1;

    std::cout << "After assigment:\n";
    display_sizes(nums1, nums2, nums3);

    // 移动赋值从 nums1 移动数据到 nums3,
    // 一同修改 nums1 和 nums3
    nums3 = std::move(nums1);

    std::cout << "After move assigment:\n";
    display_sizes(nums1, nums2, nums3);
}

输出：

Initially:
nums1: 6 nums2: 0 nums3: 0
After assigment:
nums1: 6 nums2: 6 nums3: 0
After move assigment:
nums1: 0 nums2: 6 nums3: 6

参阅

(构造函数)
 构造 set
(公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::set)

< cpp‎ | container‎ | set

定义于头文件 <set>
template< class Key, class Compare, class Alloc >

bool operator==( const std::set <Key,Compare,Alloc>& lhs,

const std::set <Key,Compare,Alloc>& rhs );
 (1)
template< class Key, class Compare, class Alloc >

bool operator!=( const std::set <Key,Compare,Alloc>& lhs,

const std::set <Key,Compare,Alloc>& rhs );
 (2) (C++20 前)
template< class Key, class Compare, class Alloc >

bool operator<( const std::set <Key,Compare,Alloc>& lhs,

const std::set <Key,Compare,Alloc>& rhs );
 (3) (C++20 前)
template< class Key, class Compare, class Alloc >

bool operator<=( const std::set <Key,Compare,Alloc>& lhs,

const std::set <Key,Compare,Alloc>& rhs );
 (4) (C++20 前)
template< class Key, class Compare, class Alloc >

bool operator>( const std::set <Key,Compare,Alloc>& lhs,

const std::set <Key,Compare,Alloc>& rhs );
 (5) (C++20 前)
template< class Key, class Compare, class Alloc >

bool operator>=( const std::set <Key,Compare,Alloc>& lhs,

const std::set <Key,Compare,Alloc>& rhs );
 (6) (C++20 前)
template< class Key, class Compare, class Alloc >

/* see below */ operator<=>( const std::set <Key,Compare,Alloc>& lhs,

const std::set <Key,Compare,Alloc>& rhs );
 (7) (C++20 起)

比较二个 set 的内容。

1-2) 检查 lhs 与 rhs 的内容是否相等，即它们是否拥有相同数量的元素且 lhs 中每个元素与 rhs 的同位置元素比较相等。
3-6) 按字典序比较 lhs 与 rhs 的内容。由等价于 std::lexicographical_compare 的函数进行比较。此比较忽略 set 的定序 Compare 。
7) 按字典序比较 lhs 与 rhs 的内容。如同通过在二个 set 上以进行合成三路比较（见后述）的函数对象调用 std::lexicographical_compare_three_way 进行比较。返回类型同合成三路比较的结果类型。此比较忽略 set 的定序 Compare 。

给定分别作为左操作数与右操作数的两个 const E 左值 lhs 与 rhs （其中 E 为 Key ），合成三路比较定义如下：

  • 若 std::three_way_comparable_with<E, E> 得到满足则等价于 lhs <=> rhs ；
  • 否则，若以 operator< 比较二个 const E 左值为良构且结果类型满足 boolean-testable ，则等价于
lhs < rhs ? std::weak_ordering::less :
rhs < lhs ? std::weak_ordering::greater :
            std::weak_ordering::equivalent
  • 否则，不定义合成三路比较，而 operator<=> 不参与重载决议。
若 three_way_comparable_with 或 boolean-testable 被满足但未被实现，或使用 operator< 但 E 与 < 不建立全序，则 operator<=> 的行为未定义。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较内容的 set
-
为使用重载 (1-2) ， Key 必须满足可相等比较 (EqualityComparable) 的要求。

返回值

1) 若 set 内容相等则为 true ，否则为 false
2) 若 set 内容不相等则为 true ，否则为 false
3) 若 lhs 的内容按字典序小于 rhs 的内容则为 true ，否则为 false
4) 若 lhs 的内容按字典序小于或等于 rhs 的内容则为 true ，否则为 false
5) 若 lhs 的内容按字典序大于 rhs 的内容则为 true ，否则为 false
6) 若 lhs 的内容按字典序大于或等于 rhs 的内容则为 true ，否则为 false
7) lhs 与 rhs 中的首对不等价元素的相对顺序，若有这种元素；否则为 lhs.size() <=> rhs.size() 。

复杂度

1-2) 若 lhs 与 rhs 的大小不同则为常数，否则与 set 大小成线性
3-7) 与 set 大小成线性

示例

#include <iostream>
#include <set>

int main()
{
    std::set<int> alice{1, 2, 3};
    std::set<int> bob{7, 8, 9, 10};
    std::set<int> eve{1, 2, 3};

    std::cout << std::boolalpha;

    // 比较不相等的容器
    std::cout << "alice == bob returns " << (alice == bob) << '\n';
    std::cout << "alice != bob returns " << (alice != bob) << '\n';
    std::cout << "alice <  bob returns " << (alice < bob) << '\n';
    std::cout << "alice <= bob returns " << (alice <= bob) << '\n';
    std::cout << "alice >  bob returns " << (alice > bob) << '\n';
    std::cout << "alice >= bob returns " << (alice >= bob) << '\n';

    std::cout << '\n';

    // 比较相等的容器
    std::cout << "alice == eve returns " << (alice == eve) << '\n';
    std::cout << "alice != eve returns " << (alice != eve) << '\n';
    std::cout << "alice <  eve returns " << (alice < eve) << '\n';
    std::cout << "alice <= eve returns " << (alice <= eve) << '\n';
    std::cout << "alice >  eve returns " << (alice > eve) << '\n';
    std::cout << "alice >= eve returns " << (alice >= eve) << '\n';
}

输出：

alice == bob returns false
alice != bob returns true
alice <  bob returns true
alice <= bob returns true
alice >  bob returns false
alice >= bob returns false

alice == eve returns true
alice != eve returns false
alice <  eve returns false
alice <= eve returns true
alice >  eve returns false
alice >= eve returns true


std::set<Key,Compare,Allocator>::rbegin, std::set<Key,Compare,Allocator>::crbegin

< cpp‎ | container‎ | set

reverse_iterator rbegin(); | (C++11 前)
reverse_iterator rbegin() noexcept; | (C++11 起)
const_reverse_iterator rbegin() const; | (C++11 前)
const_reverse_iterator rbegin() const noexcept; | (C++11 起)
const_reverse_iterator crbegin() const noexcept; | (C++11 起)

返回指向逆向 set 首元素的逆向迭代器。它对应非逆向 set 的末元素。若 set 为空，则返回的迭代器等于 rend() 。

参数

（无）

返回值

指向首元素的逆向迭代器。

复杂度

常数。

注意

因为 iterator 和 const_iterator 都是常迭代器（而且实际上可以是同一类型），故不可能通过任何这些成员函数返回的迭代器修改容器元素。

示例

本节未完成
原因：暂无示例

参阅

rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)


std::set<Key,Compare,Allocator>::rend, std::set<Key,Compare,Allocator>::crend

< cpp‎ | container‎ | set

reverse_iterator rend(); | (C++11 前)
reverse_iterator rend() noexcept; | (C++11 起)
const_reverse_iterator rend() const; | (C++11 前)
const_reverse_iterator rend() const noexcept; | (C++11 起)
const_reverse_iterator crend() const noexcept; | (C++11 起)

返回指向逆向 set 末元素后一元素的逆向迭代器。它对应非逆向 set 首元素的前一元素。此元素表现为占位符，试图访问它导致未定义行为。

参数

（无）

返回值

指向末元素后一元素的逆向迭代器。

复杂度

常数。

注意

因为 iterator 和 const_iterator 都是常迭代器（而且实际上可以是同一类型），故不可能通过任何这些成员函数返回的迭代器修改容器元素。

示例

本节未完成
原因：暂无示例

参阅

rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)


std::set<Key,Compare,Allocator>::set

< cpp‎ | container‎ | set

set();

explicit set( const Compare& comp,

const Allocator& alloc = Allocator() );
explicit set( const Allocator& alloc );
 (1) (C++11 起)
(2)
template< class InputIt >

set( InputIt first, InputIt last,
const Compare& comp = Compare(),

const Allocator& alloc = Allocator() );
template< class InputIt >

set( InputIt first, InputIt last, const Allocator& alloc)

: set(first, last, Compare(), alloc) {}
 (C++14 起)
set( const set& other );
 (3)
set( const set& other, const Allocator& alloc );
 (3) (C++11 起)
set( set&& other );
 (4) (C++11 起)
set( set&& other, const Allocator& alloc );
 (4) (C++11 起)
(5)
set( std::initializer_list <value_type> init,

const Compare& comp = Compare(),

const Allocator& alloc = Allocator() );
 (C++11 起)
set( std::initializer_list <value_type> init, const Allocator& alloc )
: set(init, Compare(), alloc) {}
 (C++14 起)

从各种数据源，可选地用用户提供的分配器 alloc 或比较函数对象 comp 构造新容器。

1) 默认构造函数。构造新容器。
2) 范围构造函数。构造拥有范围 [first, last) 内容的容器。若范围中的多个元素拥有比较等价的关键，则插入哪个元素是未指定的（待决的 LWG2844 ）。
3) 复制构造函数。以 other 内容的副本构造容器。
若不提供 alloc ，则通过调用 std::allocator_traits <allocator_type>::select_on_container_copy_construction( other.get_allocator()) 获得分配器。 | (C++11 起)
在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。 | (C++23 起)
4) 移动构造函数。用移动语义构造拥有 other 内容的容器。若不提供 alloc ，则以从属于 other 的分配器移动构造获得分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
5) initializer_list 构造函数。构造拥有 initializer_list init 内容的容器。若范围中的多个元素拥有比较等价的关键，则插入哪个元素是未指定的（待决的 LWG2844 ）。

参数

alloc | - | 用于此容器所有内存分配的分配器
comp | - | 用于所有关键比较的比较函数对象
first, last | - | 复制元素的来源范围
other | - | 将用作初始化容器元素所用源的另一容器
init | - | 初始化容器元素所用的 initializer_list
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- Compare 必须满足比较 (Compare) 的要求。
- Allocator 必须满足分配器 (Allocator) 的要求。

复杂度

1) 常数
2) 通常为 N log(N) ，若范围已按照 value_comp() 排序则与 N 成线性，其中 N = std::distance (first, last) 。
3) 与 other 的大小成线性。
4) 常数。若给定 alloc 而 alloc != other.get_allocator() ，则为线性。
5) N log(N) ，其中通常有 N = init.size() 。若 init 已按照 value_comp() 排序则与 N 成线性。

异常

调用 Allocator::allocate 可能抛出。

注解

在容器移动构造（重载 (4) ）后，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

尽管在 C++23 前未正式要求，一些实现已经在较早的模式中将 Allocator 放入非推导语境。

示例

#include <iostream>
#include <string>
#include <set>
#include <cmath>

struct Point { double x, y; };
struct PointCmp {
    bool operator()(const Point& lhs, const Point& rhs) const {
        return std::hypot(lhs.x, lhs.y) < std::hypot(rhs.x, rhs.y);
    }
};

int main()
{
  // (1) 默认初始化器
  std::set<std::string> a;
  a.insert("cat");
  a.insert("dog");
  a.insert("horse");
  for(auto& str: a) std::cout << str << ' ';
  std::cout << '\n';

  // (2) 迭代器初始化器
  std::set<std::string> b(a.find("dog"), a.end());
  for(auto& str: b) std::cout << str << ' ';
  std::cout << '\n';

  // (3) 复制构造函数
  std::set<std::string> c(a);
  c.insert("another horse");
  for(auto& str: c) std::cout << str << ' ';
  std::cout << '\n';

  // (4) 移动构造函数
  std::set<std::string> d(std::move(a));
  for(auto& str: d) std::cout << str << ' ';
  std::cout << '\n';
  std::cout << "moved-from set is ";
  for(auto& str: a) std::cout << str << ' ';
  std::cout << '\n';

  // (5) initializer_list 构造函数
  std::set<std::string> e {"one", "two", "three", "five", "eight"};
  for(auto& str: e) std::cout << str << ' ';
  std::cout << '\n';

  // 自定义比较
  std::set<Point, PointCmp> z = {{2, 5}, {3, 4}, {1, 1}};
  z.insert({1, -1}); // 这会失败，因为 1,-1 的长度等于 1,1
  for(auto& p: z) std::cout << '(' << p.x << ',' << p.y << ") ";
  std::cout << '\n';
}

输出：

cat dog horse
dog horse
another horse cat dog horse
cat dog horse
moved-from set is
eight five one three two
(1,1) (3,4) (2,5)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2193 | C++11 | 默认构造函数为 explicit | 使之为非 explicit

参阅

operator=
 赋值给容器
(公开成员函数)


std::set<Key,Compare,Allocator>::size

< cpp‎ | container‎ | set

size_type size() const; | (C++11 前)
size_type size() const noexcept; | (C++11 起)

返回容器中的元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

容器中的元素数量。

复杂度

常数。

示例

下列代码用 size 显示 std::set <int> 中的元素数：

#include <set>
#include <iostream>

int main()
{
    std::set<int> nums {1, 3, 5, 7};

    std::cout << "nums contains " << nums.size() << " elements.\n";
}

输出：

nums contains 4 elements.

参阅

empty | 检查容器是否为空 (公开成员函数)
max_size | 返回可容纳的最大元素数 (公开成员函数)


std::set<Key,Compare,Allocator>::swap

< cpp‎ | container‎ | set

void swap( set& other ); | (C++17 前)
void swap( set& other ) noexcept(/* see below */); | (C++17 起)

将内容与 other 的交换。不在单独的元素上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。尾后迭代器被非法化。

Pred 对象必须可交换 (Swappable) ，并用非成员 swap 的非限定调用交换它们。

若 std::allocator_traits <allocator_type>::propagate_on_container_swap::value 为 true ，则用对非成员 swap 的无限定调用交换分配器。否则，不交换它们（且若 get_allocator() != other.get_allocator() ，则行为未定义）。

 (C++11 起)

参数

other - 要与之交换内容的容器

返回值

（无）

异常

任何 Compare 对象交换所抛的异常。

 (C++17 前)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value
&& std::is_nothrow_swappable <Compare>::value)
 (C++17 起)

复杂度

常数。

示例

#include <iostream>
#include <set>

template<class Os, class Co> Os& operator<<(Os& os, const Co& co) {
    os << "{";
    for (auto const& i : co) { os << ' ' << i; }
    return os << " } ";
}

int main()
{
    std::set<int> a1{3, 1, 3, 2}, a2{5, 4, 5};

    auto it1 = std::next(a1.begin());
    auto it2 = std::next(a2.begin());

    const int& ref1 = *(a1.begin());
    const int& ref2 = *(a2.begin());

    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';
    a1.swap(a2);
    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';

    // 注意交换前指代一个容器中的元素的每个迭代器在交换后都指代同一元素。对于引用同为真。
}

输出：

{ 1 2 3 } { 4 5 } 2 5 1 4
{ 4 5 } { 1 2 3 } 2 5 1 4

参阅

std::swap(std::set)
 特化 std::swap 算法
(函数模板)


std::swap(std::set)

< cpp‎ | container‎ | set

定义于头文件 <set>
template< class Key, class Compare, class Alloc >

void swap( std::set <Key,Compare,Alloc>& lhs,

std::set <Key,Compare,Alloc>& rhs );
 (C++17 前)
template< class Key, class Compare, class Alloc >

void swap( std::set <Key,Compare,Alloc>& lhs,

std::set <Key,Compare,Alloc>& rhs ) noexcept(/* see below */);
 (C++17 起)

为 std::set 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

#include <algorithm>
#include <iostream>
#include <set>

int main()
{
    std::set<int> alice{1, 2, 3};
    std::set<int> bob{7, 8, 9, 10};

    auto print = [](const int& n) { std::cout << " " << n; };

    // 打印交换前的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';

    std::cout << "-- SWAP\n";
    std::swap(alice,bob);

    // 打印交换后的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
}

输出：

alice: 1 2 3
bob  : 7 8 9 10
-- SWAP
alice: 7 8 9 10
bob  : 1 2 3

参阅

swap
 交换内容
(公开成员函数)


std::set<Key,Compare,Allocator>::upper_bound

< cpp‎ | container‎ | set

iterator upper_bound( const Key& key ); | (1) |
const_iterator upper_bound( const Key& key ) const; | (1) |
template< class K > iterator upper_bound( const K& x ); | (2) | (C++14 起)
template< class K > const_iterator upper_bound( const K& x ) const; | (2) | (C++14 起)
1) 返回指向首个大于 key 的元素的迭代器。
2) 返回指向首个比较大于值 x 的元素的迭代器。此重载仅若有限定标识 Compare::is_transparent 合法并指代类型才参与重载决议。它允许无需构造 Key 的实例就调用此函数。

参数

key | - | 与元素比较的键值
x | - | 能与 Key 比较的替用值

返回值

指向首个大于 key 的元素的迭代器。若找不到这种元素，则返回尾后（见 end() ）迭代器。

复杂度

与容器大小成对数。

参阅

equal_range | 返回匹配特定键的元素范围 (公开成员函数)
lower_bound | 返回指向首个不小于给定键的元素的迭代器 (公开成员函数)


std::set<Key,Compare,Allocator>::value_comp

< cpp‎ | container‎ | set

std::set::value_compare value_comp() const;

返回比较值的函数对象。它与 key_comp 相同。

参数

（无）

返回值

比较值的函数对象。

复杂度

常数。

参阅

key_comp
 返回用于比较键的函数
(公开成员函数)


std::set<Key,Compare,Allocator>::~set

< cpp‎ | container‎ | set

~set();

销毁 set 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 set 大小成线性。


std::span

< cpp‎ | container
定义于头文件 <span> |
template< class T, std::size_t Extent = std::dynamic_extent > class span; | (C++20 起)

类模板 span 所描述的对象能指代对象的相接序列，序列的首元素在零位置。 span 能拥有静态长度，该情况下序列中的元素数已知并编码于类型中，或拥有动态长度。

典型实现只保有两个成员：指向 T 的指针和大小。

std::span 的每个特化均为可平凡复制 (TriviallyCopyable) 类型。

 (C++23 起)

模板形参

T | - | 元素类型；必须是完整对象类型且非抽象类
Extent | - | 序列中的元素数，或若它为动态则为 std::dynamic_extent

成员类型

成员类型 | 定义
element_type | T
value_type | std::remove_cv_t <T>
size_type | std::size_t
difference_type | std::ptrdiff_t
pointer | T*
const_pointer | const T*
reference | T&
const_reference | const T&
iterator | 实现定义的老式随机访问迭代器 (LegacyRandomAccessIterator) 、常量表达式迭代器 (ConstexprIterator) 兼老式连续迭代器 (LegacyContiguousIterator) ，其 value_type 为 value_type
reverse_iterator | std::reverse_iterator <iterator>
const_reverse_iterator | std::reverse_iterator <const_iterator>

注意：若 T 无 const 限定则 iterator 为可变迭代器。

容器 (Container) 的迭代器类型上的所有要求亦应用于 span 的 iterator 类型。

成员常量

static constexpr std::size_t extent = Extent;

成员函数

(构造函数)
 构造 span
(公开成员函数)
operator=
 赋值 span
(公开成员函数)
迭代器
begin
(C++20)
 返回指向起始的迭代器
(公开成员函数)
end
(C++20)
 返回指向末尾的迭代器
(公开成员函数)
rbegin
(C++20)
 返回指向起始的逆向迭代器
(公开成员函数)
rend
(C++20)
 返回指向末尾的逆向迭代器
(公开成员函数)
元素访问
front
(C++20)
 访问第一个元素
(公开成员函数)
back
(C++20)
 访问最后一个元素
(公开成员函数)
operator[]
 访问序列的元素
(公开成员函数)
data
 返回指向元素序列起始的指针
(公开成员函数)
观察器
size
 返回序列中的元素数
(公开成员函数)
size_bytes
 返回以字节表示的序列大小
(公开成员函数)
empty
 检查序列是否为空
(公开成员函数)
子视图
first
 获得由序列首 N 个元素组成的子段
(公开成员函数)
last
 获得由序列末 N 个元素组成的子段
(公开成员函数)
subspan
 获得子段
(公开成员函数)

非成员函数

as_bytesas_writable_bytes
 转换 span 为对其底层字节的视图
(函数模板)

非成员常量

dynamic_extent
(C++20)
 size_t 类型常量，指明 span 拥有动态长度
(常量)

辅助模板

template<class T, std::size_t Extent>
inline constexpr bool ranges::enable_borrowed_range<std::span<T, Extent>> = true;

std::ranges::enable_borrowed_range 的此特化使得 span 满足 borrowed_range 。

template<class T, std::size_t Extent>
inline constexpr bool ranges::enable_view<std::span<T, Extent>> = true;

std::ranges::enable_view 的此特化使零或动态长度的 span 满足 view 。

推导指引

注解

即使在 C++23 中引入的正式要求前，所有既存实现中 std::span 的特化已经为可平凡复制类型。

示例

示例用 std::span 实现连续范围上的算法。

#include <algorithm>
#include <cstddef>
#include <iostream>
#include <span>

template<class T, std::size_t N> [[nodiscard]]
constexpr auto slide(std::span<T,N> s, std::size_t offset, std::size_t width) {
    return s.subspan(offset, offset + width <= s.size() ? width : 0U);
}

template<class T, std::size_t N, std::size_t M> [[nodiscard]]
constexpr bool starts_with(std::span<T,N> data, std::span<T,M> prefix) {
    return data.size() >= prefix.size()
        && std::equal(prefix.begin(), prefix.end(), data.begin());
}

template<class T, std::size_t N, std::size_t M> [[nodiscard]]
constexpr bool ends_with(std::span<T,N> data, std::span<T,M> suffix) {
    return data.size() >= suffix.size()
        && std::equal(data.end() - suffix.size(), data.end(),
                      suffix.end() - suffix.size());
}

template<class T, std::size_t N, std::size_t M> [[nodiscard]]
constexpr bool contains(std::span<T,N> span, std::span<T,M> sub) {
    return std::search(span.begin(), span.end(), sub.begin(), sub.end()) != span.end();
//  return std::ranges::search(span, sub).begin() != span.end();
}

void print(const auto& seq) {
    for (const auto& elem : seq) std::cout << elem << ' ';
    std::cout << '\n';
}

int main()
{
    constexpr int a[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
    constexpr int b[] { 8, 7, 6 };

    for (std::size_t offset{}; ; ++offset) {
        constexpr std::size_t width{6};
        auto s = slide(std::span{a}, offset, width);
        if (s.empty())
            break;
        print(s);
    }

    static_assert(starts_with(std::span{a}, std::span{a,4})
        && starts_with(std::span{a+1, 4}, std::span{a+1,3})
        && !starts_with(std::span{a}, std::span{b})
        && !starts_with(std::span{a,8}, std::span{a+1,3})
        && ends_with(std::span{a}, std::span{a+6,3})
        && !ends_with(std::span{a}, std::span{a+6,2})
        && contains(std::span{a}, std::span{a+1,4})
        && !contains(std::span{a,8}, std::span{a,9}));
}

输出：

0 1 2 3 4 5
1 2 3 4 5 6
2 3 4 5 6 7
3 4 5 6 7 8

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | 非零静态长度的 span 不是 view | view 不要求 default_initializable 故它们是

参阅

initializer_list (C++11) | 在列表初始化中创建临时数组然后引用它 (类模板)
basic_string_view (C++17) | 只读的字符串视图 (类模板)
ranges::subrange (C++20) | 将迭代器/哨位对结合为一个 view (类模板)


std::as_bytes, std::as_writable_bytes

< cpp‎ | container‎ | span
template< class T, std::size_t N>
std::span<const std::byte, S/* see below */> as_bytes(std::span<T, N> s) noexcept;
 (1)
template< class T, std::size_t N>
std::span<std::byte, S/* see below */> as_writable_bytes(std::span<T, N> s) noexcept;
 (2)

获得对 span s 的元素的对象表示的视图。

若 N 为 std::dynamic_extent ，则返回的 span S 的长度亦为 std::dynamic_extent ；否则它是 sizeof(T) * N 。

as_writable_bytes 仅若 std::is_const_v <T> 为 false 才参与重载决议。

返回值

1) 以 {reinterpret_cast<const std::byte*>(s.data()), s.size_bytes()} 构造的 span 。
2) 以 {reinterpret_cast<std::byte*>(s.data()), s.size_bytes()} 构造的 span 。

示例

#include <cstddef>
#include <iomanip>
#include <iostream>
#include <span>

void print(float const x, std::span<const std::byte> const bytes)
{
    std::cout << std::setprecision(6) << std::setw(8) << x << " = { "
              << std::hex << std::uppercase << std::setfill('0');
    for (auto const b : bytes) {
        std::cout << std::setw(2) << std::to_integer<int>(b) << ' ';
    }
    std::cout << std::dec << "}\n";
}

int main()
{
    /* mutable */ float data[1] { 3.141592f };

    auto const const_bytes = std::as_bytes(std::span{ data });

    print(data[0], const_bytes);

    auto const writable_bytes = std::as_writable_bytes(std::span{ data });

    // 更改作为最高有效位的符号位（ IEEE 754 浮点标准）
    writable_bytes[3] |= std::byte{ 0b1000'0000 };

    print(data[0], const_bytes);
}

可能的输出：

 3.14159 = { D8 0F 49 40 }
-3.14159 = { D8 0F 49 C0 }

参阅

byte
(C++17)
 字节类型
(枚举)


std::span<T,Extent>::back

< cpp‎ | container‎ | span
constexpr reference back() const;

返回到 span 中末元素的引用。

在空 span 上调用 back 导致未定义行为。

参数

（无）

返回值

到尾元素的引用。

复杂度

常数

注解

对于 span c ，表达式 c.back() 等价于 *(c.end()-1) 。

示例

#include <span>
#include <iostream>

void print_forward(std::span<const int> const span) {
    for (auto n { span.size() }; n != 0; --n ) {
        std::cout << span.last(n).front() << ' ';
    }
    std::cout << '\n';
}

void print_backward(std::span<const int> const span) {
    for (auto n { span.size() }; n != 0; --n) {
        std::cout << span.first(n).back() << ' ';
    }
    std::cout << '\n';
}

int main()
{
    constexpr int numbers[] { 0, 1, 2, 3, 4 };
    print_forward(numbers);
    print_backward(numbers);
}

输出：

0 1 2 3 4
4 3 2 1 0

参阅

front
(C++20)
 访问第一个元素
(公开成员函数)


std::span<T,Extent>::begin

< cpp‎ | container‎ | span

constexpr iterator begin() const noexcept;

返回指向 span 首元素的迭代器。

若 span 为空，则返回的迭代器将等于 end() 。

参数

（无）

返回值

指向首元素的迭代器。

复杂度

常数。

示例

Template:cpp/container/begin/examples/span

参阅

end
(C++20)
 返回指向末尾的迭代器
(公开成员函数)


std::span<T,Extent>::data

< cpp‎ | container‎ | span
constexpr pointer data() const noexcept;

返回指向序列起始的指针。

返回值

指向序列起始的指针。

参阅

(构造函数)
 构造 span
(公开成员函数)


std::span 的推导指引

< cpp‎ | container‎ | span
定义于头文件 <span>
template <class It, class EndOrSize>
span(It, EndOrSize) -> span< std::remove_reference_t <std::iter_reference_t<It>>>;
 (1)
template<class T, std::size_t N>
span(T (&)[N]) -> span<T, N>;
 (2)
template<class T, std::size_t N>
span( std::array <T, N>&) -> span<T, N>;
 (3)
template<class T, std::size_t N>
span(const std::array <T, N>&) -> span<const T, N>;
 (4)
template<class R>
span(R&&) -> span< std::remove_reference_t <std::ranges::range_reference_t<R>>>;
 (5)

为 span 提供下列推导指引。

(1) 允许从迭代器-哨位对推导元素类型。此重载仅若 It 满足 contiguous_iterator 才参与重载决议。

(2-4) 允许从内建数组与 std::array 推导静态长度。

(5) 允许从范围推导元素类型。此重载仅若 R 满足 contiguous_range 才参与重载决议。

示例

#include <array>
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <span>
#include <string_view>
#include <vector>

void print(std::string_view rem = "", std::size_t size_of = 0, std::size_t extent = 0) {
    if (rem.empty()) {
        std::cout << "name │ sizeof │ extent\n─────┼────────┼────────\n";
        return;
    }
    std::cout << std::setw(4) << rem << " │ " << std::setw(6) << size_of << " │ ";
    if (extent == std::dynamic_extent)
        std::cout << "dynamic";
    else
        std::cout << extent;
    std::cout << '\n';
}

int main() {
    int a[] {1, 2, 3, 4, 5};

    print();
    std::span s1 {std::begin(a), std::end(a)}; // 指引 (1)
    print("s1", sizeof s1, s1.extent);

    std::span s2 {std::begin(a), 3}; // 指引 (1)
    print("s2", sizeof s2, s2.extent);

    std::span s3 {a}; // 指引 (2)
    print("s3", sizeof s3, s3.extent);

    std::span<int> s4 {a}; // 不使用指引，制作动态 span
    print("s4", sizeof s4, s4.extent);

    std::array arr {6, 7, 8};
    std::span s5 {arr}; // 指引 (3)
    print("s5", sizeof s5, s5.extent);
    s5[0] = 42; // OK, element_type is 'int'

    const std::array arr2 {9, 10, 11};
    std::span s6 {arr2}; // 指引 (4)
    print("s6", sizeof s6, s6.extent);
    // s6[0] = 42; // Error: element_type is 'const int'

    std::vector v {66, 69, 99};
    std::span s7 {v}; // 指引 (5)
    print("s7", sizeof s7, s7.extent);
}

输出：

name │ sizeof │ extent
─────┼────────┼────────
  s1 │     16 │ dynamic
  s2 │     16 │ dynamic
  s3 │      8 │ 5
  s4 │     16 │ dynamic
  s5 │      8 │ 3
  s6 │      8 │ 3
  s7 │     16 │ dynamic


std::dynamic_extent

< cpp‎ | container‎ | span
定义于头文件 <span> |
inline constexpr std::size_t dynamic_extent = std::numeric_limits < std::size_t >::max(); | (C++20 起)

std::dynamic_extent 是 std::size_t 类型常量，用于区别拥有静态和动态长度的 std::span 。

注解

由于 std::size_t 是无符号类型，等价的定义是：

inline constexpr std::size_t dynamic_extent = -1;

见整型转换。

示例

#include <array>
#include <cassert>
#include <cstddef>
#include <iostream>
#include <span>
#include <string_view>
#include <vector>

int main()
{
    auto print = [](std::string_view const name, std::size_t ex) {
        std::cout << name << ", ";
        if (ex == std::dynamic_extent) {
            std::cout << "dynamic extent\n";
        } else {
            std::cout << "static extent = " << ex << '\n';
        }
    };

    int a[]{1,2,3,4,5};

    std::span span1{a};
    print("span1", span1.extent);

    std::span<int, std::dynamic_extent> span2{a};
    print("span2", span2.extent);

    std::array ar{1,2,3,4,5};
    std::span span3{ar};
    print("span3", span3.extent);

    std::vector v{1,2,3,4,5};
    std::span span4{v};
    print("span4", span4.extent);
}

输出：

span1, static extent = 5
span2, dynamic extent
span3, static extent = 5
span4, dynamic extent

参阅

span
(C++20)
 对象的连续序列上的无所有权视图
(类模板)


std::span<T,Extent>::empty

< cpp‎ | container‎ | span
[[nodiscard]] constexpr bool empty() const noexcept;

检查 span 是否为空。

返回值

若 span 为空（即 size() == 0 ）则为 true ；否则为 false 。

示例

#include <span>
#include <iostream>
#include <iomanip>

int main()
{
    std::span<const char> span{ "ABCDEF" };

    while (!span.empty()) {
        std::cout << std::quoted(span.data()) << '\n';
        span = span.last(span.size() - 1);
    }
}

输出：

"ABCDEF"
"BCDEF"
"CDEF"
"DEF"
"EF"
"F"
""

参阅

size
 返回序列中的元素数
(公开成员函数)


std::span<T,Extent>::end

< cpp‎ | container‎ | span

constexpr iterator end() const noexcept;

返回指向 span 末元素后一元素的迭代器。

此元素表现为占位符；试图访问它导致未定义行为。

参数

（无）

返回值

指向后随最后元素的迭代器。

复杂度

常数。

示例

Template:cpp/container/begin/examples/span

参阅

begin
(C++20)
 返回指向起始的迭代器
(公开成员函数)


std::span<T,Extent>::first

< cpp‎ | container‎ | span
template< std::size_t Count >
constexpr std::span<element_type, Count> first() const;
constexpr std::span<element_type, std::dynamic_extent> first( std::size_t Count ) const;

获得 span ，其为此 span 的首 Count 个元素上的视图。若 Count > Extent 则程序非良构。若 Count > size() 则行为未定义。

返回值

作为 *this 的首 Count 个元素上的视图的 span r ，满足 r.data() == this->data() && r.size() == Count 。

参阅

last | 获得由序列末 N 个元素组成的子段 (公开成员函数)
subspan | 获得子段 (公开成员函数)


std::span<T,Extent>::front

< cpp‎ | container‎ | span
constexpr reference front() const;

返回到 span 中首元素的引用。

在空 sapn 上调用 front 导致未定义行为。

参数

（无）

返回值

到首元素的引用。

复杂度

常数。

注解

对于 span c ，表达式 c.front() 等价于 *c.begin() 。

示例

#include <span>
#include <iostream>

void print(std::span<const int> const data)
{
    for (auto offset{0U}; offset != data.size(); ++offset) {
        std::cout << data.subspan(offset).front() << ' ';
    }
    std::cout << '\n';
}

int main()
{
    constexpr int data[] { 0, 1, 2, 3, 4, 5, 6 };
    print({data, 4});
}

输出：

0 1 2 3

参阅

back
(C++20)
 访问最后一个元素
(公开成员函数)


std::get(std::span)

< cpp‎ | container‎ | span
template< std::size_t I, class T, std::size_t N >
constexpr T& get( std::span<T,N> s ) noexcept;
 (C++20 起)

获得到 span s 的第 I 个元素的引用。

该 span 必须拥有静态长度（即 N != std::dynamic_extent ）且 I 必须是范围 [0, N) 中的整数值。这在编译时强制，与 operator[] 相反。

参数

s - 要提取内容的 span

返回值

到 s 的第 I 元素的引用。

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

operator[] | 访问序列的元素 (公开成员函数)
std::get(std::tuple) | 元组式访问指定的元素 (函数模板)
std::get(std::pair) (C++11) | 访问 pair 的一个元素 (函数模板)
std::get(std::variant) (C++17) | 以给定索引或类型（若类型唯一）读取 variant 的值，错误时抛出异常 (函数模板)


std::span<T,Extent>::last

< cpp‎ | container‎ | span
template< std::size_t Count >
constexpr std::span<element_type, Count> last() const;
constexpr std::span<element_type, std::dynamic_extent> last( std::size_t Count ) const;

获得 span ，结果为此 span 的最后 Count 个元素上的视图。若 Count > Extent 则程序非良构。若 Count > size() 则行为未定义。

返回值

为此 *this 的最后 Count 个元素上的视图的 r ，使得 r.data() == this->data() + (this->size() - Count) && r.size() == Count 。

参阅

first | 获得由序列首 N 个元素组成的子段 (公开成员函数)
subspan | 获得子段 (公开成员函数)


std::span<T,Extent>::operator=

< cpp‎ | container‎ | span
constexpr span& operator=( const span& other ) noexcept = default;

赋值 other 给 *this 。此默认化的赋值运算符进行数据指针和大小的浅复制，即调用此函数后， data() == other.data() 且 size() == other.size() 。

参数

other - 要复制的另一 span

返回值

*this 。

示例

#include <algorithm>
#include <array>
#include <cassert>
#include <cstddef>
#include <iostream>
#include <span>
#include <string_view>

void print(std::string_view info = "", std::span<const int> span = {},
           std::size_t extent = 0, std::size_t size_of = 0) {
    if (span.size() == 0) {
        std::cout << info << '\n';
        return;
    }
    std::cout << info << '[' << span.size() << "] {";
    std::ranges::for_each(span, [](const int x) { std::cout << ' ' << x; });
    std::cout << " }";
    if (extent != 0) {
        std::cout << " extent = ";
        if (extent == std::dynamic_extent)
            std::cout << "dynamic";
        else
            std::cout << extent;
    }
    if (size_of != 0) {
        std::cout << ", sizeof = " << size_of;
    }
    std::cout << '\n';
}

int main()
{
    std::array<int,6> a1;
    std::array<int,6> a2;
    a1.fill(3);
    a2.fill(4);

    auto s1 = std::span(a1);
    auto s2 = std::span(a2);
    print("s1", s1, s1.extent, sizeof(s1));
    print("s2", s2, s2.extent, sizeof(s2));

    // 检查赋值是否进行浅复制
    s1 = s2;
    (s1.data() == s2.data() && s1.size() == s2.size())
        ? print("s1 = s2; is a shallow copy!")
        : print("s1 = s2; is a deep copy!");
    print("s1", s1);

    print("Fill s1 with 5:");
    std::ranges::fill(s1, 5);
    // s2 亦被“更新”因为 s1 与 s2 引用同一数据
    assert(std::ranges::equal(s1, s2));
    print("s1", s1);
    print("s2", s2);
    print();

    int a3[] {1, 2, 3, 4};
    int a4[] {2, 3, 4, 5};
    int a5[] {3, 4, 5};

    std::span<int, std::dynamic_extent> dynamic_1 {a3};
    std::span<int, std::dynamic_extent> dynamic_2 {a4, 3};
    std::span<int, 4> static_1 {a3};
    std::span<int, 4> static_2 {a4};
    std::span<int, 3> static_3 {a5};

    print("dynamic_1", dynamic_1, dynamic_1.extent, sizeof(dynamic_1));
    print("dynamic_2", dynamic_2, dynamic_2.extent, sizeof(dynamic_2));
    print("static_1", static_1, static_1.extent, sizeof(static_1));
    print("static_2", static_2, static_2.extent, sizeof(static_2));
    print("static_3", static_3, static_3.extent, sizeof(static_3));

    dynamic_1 = dynamic_2; // OK
    dynamic_1 = static_1;  // OK
 // static_1  = dynamic_1; // 错误：无匹配的 ‘operator=’
    static_1  = static_2;  // OK ：相同长度 = 4
 // static_1  = static_3;  // 错误：不同长度： 4 与 3
}

输出：

s1[6] { 3 3 3 3 3 3 } extent = 6, sizeof = 8
s2[6] { 4 4 4 4 4 4 } extent = 6, sizeof = 8
s1 = s2; is a shallow copy!
s1[6] { 4 4 4 4 4 4 }
Fill s1 with 5:
s1[6] { 5 5 5 5 5 5 }
s2[6] { 5 5 5 5 5 5 }

dynamic_1[4] { 1 2 3 4 } extent = dynamic, sizeof = 16
dynamic_2[3] { 2 3 4 } extent = dynamic, sizeof = 16
static_1[4] { 1 2 3 4 } extent = 4, sizeof = 8
static_2[4] { 2 3 4 5 } extent = 4, sizeof = 8
static_3[3] { 3 4 5 } extent = 3, sizeof = 8

参阅

(构造函数) | 构造 span (公开成员函数)
data | 返回指向元素序列起始的指针 (公开成员函数)
size | 返回序列中的元素数 (公开成员函数)


std::span<T,Extent>::operator[]

< cpp‎ | container‎ | span
constexpr reference operator[](size_type idx) const;

获得到序列的第 idx 个元素的引用。若 idx 在范围外（即若它大于或等于 size() ）则行为未定义。

参数

idx - 要访问的元素的下标

返回值

到序列第 idx 个元素的引用，即 data()[idx] 。

异常

不抛出。

示例

#include <cstddef>
#include <iostream>
#include <span>
#include <utility>

void reverse(std::span<int> span) {
    for (std::size_t i = 0, j = std::size(span); i < j; ++i) {
        --j;
        std::swap(span[i], span[j]);
    }
}

void print(std::span<const int> const span) {
    for (int element: span) {
        std::cout << element << ' ';
    }
    std::cout << '\n';
}

int main() {
    int data[]{ 1, 2, 3, 4, 5 };
    print(data);
    reverse(data);
    print(data);
}

输出：

1 2 3 4 5
5 4 3 2 1

参阅

data | 返回指向元素序列起始的指针 (公开成员函数)
size | 返回序列中的元素数 (公开成员函数)


std::span<T,Extent>::rbegin

< cpp‎ | container‎ | span

constexpr reverse_iterator rbegin() const noexcept;

返回指向逆向 span 首元素的逆向迭代器。它对应非逆向 span 的末元素。若 span 为空，则返回的迭代器等于 rend() 。

参数

（无）

返回值

指向首元素的逆向迭代器。

复杂度

常数。

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <span>

int main()
{
    constexpr std::span<const char> code{ "@droNE_T0P_w$s@s#_SECRET_a,p^42!" };

    auto hacker = [](const unsigned O) { return O-0141<120; };

    std::copy_if(code.rbegin(), code.rend(),
        std::ostream_iterator<const char>(std::cout), hacker);
}

输出：

password

参阅

rend
(C++20)
 返回指向末尾的逆向迭代器
(公开成员函数)


std::span<T,Extent>::rend

< cpp‎ | container‎ | span

constexpr reverse_iterator rend() const noexcept;

返回指向逆向 span 末元素后一元素的逆向迭代器。它对应非逆向 span 首元素的前一元素。此元素表现为占位符，试图访问它导致未定义行为。

参数

（无）

返回值

指向末元素后一元素的逆向迭代器。

复杂度

常数。

示例

#include <algorithm>
#include <iostream>
#include <span>
#include <string_view>

void ascending(const std::span<const std::string_view> data,
               const std::string_view term)
{
    std::for_each(data.begin(), data.end(),
        [](const std::string_view x) { std::cout << x << " "; });
    std::cout << term;
}

void descending(const std::span<const std::string_view> data,
               const std::string_view term)
{
    std::for_each(data.rbegin(), data.rend(),
        [](const std::string_view x) { std::cout << x << " "; });
    std::cout << term;
}

int main()
{
    constexpr std::string_view bars[]{ "▁","▂","▃","▄","▅","▆","▇","█" };
    ascending(bars, " ");
    descending(bars, "\n");
}

输出：

▁ ▂ ▃ ▄ ▅ ▆ ▇ █  █ ▇ ▆ ▅ ▄ ▃ ▂ ▁

参阅

rbegin
(C++20)
 返回指向起始的逆向迭代器
(公开成员函数)


std::span<T,Extent>::size

< cpp‎ | container‎ | span
constexpr size_type size() const noexcept;

返回 span 中的元素数。

返回值

span 中的元素数。

参阅

(构造函数) | 构造 span (公开成员函数)
size_bytes | 返回以字节表示的序列大小 (公开成员函数)


std::span<T,Extent>::size_bytes

< cpp‎ | container‎ | span
constexpr size_type size_bytes() const noexcept;

返回以字节计的序列大小。

返回值

以字节计的序列大小，即 size() * sizeof(element_type) 。

示例

#include <span>
#include <cstdint>

int main()
{
    static constexpr std::int32_t a[] { 1, 2, 3, 4, 5 };
    constexpr std::span s{a};

    static_assert( sizeof(int32_t) == 4  );
    static_assert( std::size(a)    == 5  );
    static_assert( sizeof(a)       == 20 );
    static_assert( s.size()        == 5  );
    static_assert( s.size_bytes()  == 20 );
}

参阅

size
 返回序列中的元素数
(公开成员函数)


std::span<T,Extent>::span

< cpp‎ | container‎ | span
constexpr span() noexcept;
 (1)
template< class It >

explicit(extent != std::dynamic_extent)

constexpr span( It first, size_type count );
 (2)
template< class It, class End >

explicit(extent != std::dynamic_extent)

constexpr span( It first, End last );
 (3)
template< std::size_t N >
constexpr span( element_type (&arr)[N] ) noexcept;
 (4)
template< class U, std::size_t N >
constexpr span( std::array <U, N>& arr ) noexcept;
 (5)
template< class U, std::size_t N >
constexpr span( const std::array <U, N>& arr ) noexcept;
 (6)
template< class R >

explicit(extent != std::dynamic_extent)

constexpr span( R&& range );
 (7)
template< class U, std::size_t N >

explicit(extent != std::dynamic_extent && N == std::dynamic_extent)

constexpr span( const std::span<U, N>& s ) noexcept;
 (8)
constexpr span( const span& other ) noexcept = default;
 (9)

构造 span 。

1) 构造空 span 使其 data() == nullptr 而 size() == 0 。
  • 此重载仅若extent == 0 || extent == std::dynamic_extent才参与重载决议。
2) 构造作为范围 [first, first + count) 上的视图的 span ；产生的 span 有 data() == std::to_address(first) 与 size() == count 。
  • 若 [first, first + count) 不是合法范围，若 It 不实际实现 contiguous_iterator 或若 extent != std::dynamic_extent && count != extent 则行为未定义。这些重载仅若
  • It 满足 contiguous_iterator
  • 从 std::iter_reference_t<It> 到 element_type 的转换至多为限定转换
才参与重载决议。
3) 构造作为范围 [first, last) 上的视图的 span ；产生的 span 有 data() == std::to_address(first) 与 size() == last-first 。若 [first, last) 不是合法范围，若 It 不实际实现 contiguous_iterator ，若 End 不实际实现 It 的 sized_sentinel_for ，或若 extent != std::dynamic_extent && last-first != extent 则行为未定义。
  • 此重载仅若
  • It 满足 contiguous_iterator ，
  • End 满足 It 的 sized_sentinel_for ，
  • 从 std::iter_reference_t<It> 到 element_type 的转换至多为限定转换，且
  • std::is_convertible_v <End, std::size_t > 为 false
才参与重载决议。
4-6) 构造作为数组 arr 上的视图的 span ；产生的 span 有 size() == N 与 data() == std::data (arr) 。
  • 这些重载仅若extent == std::dynamic_extent || N == extent 为 true 且从 std::remove_pointer_t <decltype( std::data (arr))> 到 element_type 的转换至多为限定转换才参与重载决议。这些构造函数模板决不用于类模板实参推导。
7) 构造作为范围 range 上的视图的 span ；产生的 span 有 size() == std::ranges::size(r) 与 data() == std::ranges::data(range) 。
  • 若 R 不实际实现 contiguous_range 与 sized_range 或当 element_type 为非 const 时 R 不实际实现 borrowed_range 或 extent != dynamic_extent 与 std::ranges::size(range) != extent 均为 true 则行为未定义。
  • 此重载仅若
  • extent == dynamic_extent ；
  • R 满足 contiguous_range 与 sized_range ，
  • R 满足 borrowed_range 或 std::is_const_v <element_type> 为 true
  • std::remove_cvref_t<R> 不是 std::span 的特化，
  • std::remove_cvref_t<R> 不是 std::array 的特化，
  • std::is_array_v <std::remove_cvref_t<R>> 为 false ，且
  • 从 std::ranges::range_reference_t<R> 到 element_type 的转换至多为限定转换
才参与重载决议。
8) 从另一 span source 的转换构造函数；产生的 span 有 size() == source.size() 与 data() == source.data() 。
  • 若 extent != dynamic_extent 与 source.size() != extent 均为 true 则行为未定义。
  • 此重载仅若extent == std::dynamic_extent 、 N == std::dynamic_extent 与 N == extent 至少一者为 true 且从 U 到 element_type 的转换至多为限定转换才参与重载决议。
9) 默认化的赋值构造函数复制大小与数据指针；产生的 span 有 size() == other.size() 与 data() == other.data() 。

参数

first | - | 指向序列首元素的迭代器
count | - | 序列的元素数
last | - | 指向序列末元素后一位置的迭代器或另一哨位
arr | - | 用于构造视图的数组
r | - | 用于构造视图的范围
source | - | 要转换的另一 span
other | - | 要复制的另一 span

异常

2) 不抛出。
3) 在抛出时 last - first 抛出其所抛出的异常。
7) 在 std::ranges::size(r) 与 std::ranges::data(r) 抛出时抛出其所抛出的异常。

参阅

data | 返回指向元素序列起始的指针 (公开成员函数)
size | 返回序列中的元素数 (公开成员函数)
operator= | 赋值 span (公开成员函数)
sizessize (C++17)(C++20) | 返回容器或数组的大小 (函数模板)
data (C++17) | 获得指向底层数组的指针 (函数模板)


std::span<T,Extent>::subspan

< cpp‎ | container‎ | span
template< std::size_t Offset,

std::size_t Count = std::dynamic_extent >

constexpr std::span<element_type, E /* see below */> subspan() const;
 (1)
constexpr std::span<element_type, std::dynamic_extent>

subspan( std::size_t Offset,

std::size_t Count = std::dynamic_extent ) const;
 (2)

获得 span ，它是此 span 的始于偏移 Offset 的 Count 个元素上的视图。若 Count 为 std::dynamic_extent ，则子段中的元素数为 size() - offset （即它结束于 *this 的结尾）。

若

  • Offset 大于 Extent ，或
  • Count 不是 std::dynamic_extent 且 Count 大于 Extent - Offset

则 (1) 为谬构。

若 Offset 或 Count 在范围外则行为未定义。若出现以下条件则这会发生：

  • Offset 大于 size() ；
  • Count 非 std::dynamic_extent 且 Count 大于 size() - Offset 。

按下列方式确定 (1) 所返回的 span 的长度模板实参 E ：

  • 若 Count 不是 std::dynamic_extent 则为 Count ；
  • 否则，若 Extent 不是 std::dynamic_extent ，则为 Extent - Offset ；
  • 否则为 std::dynamic_extent 。

返回值

请求的子段 r ，满足 r.data() == this->data() + Offset 。若 Count 为 std::dynamic_extent ，则 r.size() == this->size() - Offset ；否则 r.size() == Count 。

参阅

first | 获得由序列首 N 个元素组成的子段 (公开成员函数)
last | 获得由序列末 N 个元素组成的子段 (公开成员函数)


std::stack

< cpp‎ | container
定义于头文件 <stack>
template<

class T,
class Container = std::deque <T>

> class stack;

std::stack 类是容器适配器，它给予程序员栈的功能——特别是 FILO （先进后出）数据结构。

该类模板表现为底层容器的包装器——只提供特定函数集合。栈从被称作栈顶的容器尾部推弹元素。

模板形参

T - 存储的元素类型。若 T 与 Container::value_type 不是同一类型则行为未定义。 (C++17 起)
Container - 用于存储元素的底层容器类型。容器必须满足序列容器 (SequenceContainer) 的要求。另外，它必须提供拥有通常语义的下列函数：
  • back()
  • push_back()
  • pop_back()

标准容器 std::vector 、 std::deque 和 std::list 满足这些要求。若不为特定的 stack 类特化指定容器类，则使用标准容器 std::deque 。

成员类型

成员类型 | 定义
container_type | Container
value_type | Container::value_type
size_type | Container::size_type
reference | Container::reference
const_reference | Container::const_reference

成员函数

(构造函数)
 构造 stack
(公开成员函数)
(析构函数)
 析构 stack
(公开成员函数)
operator=
 赋值给容器适配器
(公开成员函数)
元素访问
top
 访问栈顶元素
(公开成员函数)
容量
empty
 检查底层容器是否为空
(公开成员函数)
size
 返回容纳的元素数
(公开成员函数)
修改器
push
 向栈顶插入元素
(公开成员函数)
emplace
(C++11)
 在顶部原位构造元素
(公开成员函数)
pop
 删除栈顶元素
(公开成员函数)
swap
(C++11)
 交换内容
(公开成员函数)

成员对象
Container c
 底层容器
(受保护成员对象)

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20) | 按照字典顺序比较 stack 中的值 (函数模板)
std::swap(std::stack) (C++11) | 特化 std::swap 算法 (函数模板)

辅助类

std::uses_allocator<std::stack>
(C++11)
 特化 std::uses_allocator 类型特征
(类模板特化)

推导指引 (C++17 起)


std::stack 的推导指引

< cpp‎ | container‎ | stack

定义于头文件 <stack>
template<class Container>

stack(Container)

-> stack<typename Container::value_type, Container>;
 (1) (C++17 起)
template<class InputIt>

stack(InputIt, InputIt)

-> stack</*iter-value-t*/<InputIt>>;
 (2) (C++23 起)
template<class Container, class Alloc>

stack(Container, Alloc)

-> stack<typename Container::value_type, Container>;
 (3) (C++17 起)
template<class InputIt, class Alloc>

stack(InputIt, InputIt, Alloc)
-> stack</*iter-value-t*/<InputIt>,

std::deque </*iter-value-t*/<InputIt>, Alloc>>;
 (4) (C++23 起)

为 stack 提供推导指引以允许从底层容器类型推导。

1) 从参数推导底层容器类型。
2) 从迭代器推导元素类型，以 std::deque </*iter-value-t*/<InputIt>> 为底层容器类型，其中 /*iter-value-t*/<InputIt> 代表 typename std::iterator_traits <InputIt>::value_type 。
3-4) 同 (1-2) ，除了提供分配器。

这些重载仅若

  • InputIt （若存在）满足老式输入迭代器 (LegacyInputIterator) ，
  • Container （若存在）不满足分配器 (Allocator) ，
  • 对于 (3) (C++23 前)(4) (C++23 起) ，Alloc 满足分配器 (Allocator) ，以及
  • 若 Container 与 Alloc 均存在则 std::uses_allocator_v <Container, Alloc> 为 true

才参与重载决议。

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

示例

#include <vector>
#include <stack>
int main() {
   std::vector<int> v = {1,2,3,4};
   std::stack s{v};    // 指引 #1 推导 std::stack<int, vector<int>>
}


std::stack<T,Container>::emplace

< cpp‎ | container‎ | stack

template< class... Args > void emplace( Args&&... args ); | (C++11 起) (C++17 前)
template< class... Args > decltype(auto) emplace( Args&&... args ); | (C++17 起)

推入新元素到 stack 顶。原位构造元素，即不进行移动或复制操作。以与提供给函数者准确相同的参数调用元素的构造函数。

等效地调用 c.emplace_back( std::forward <Args>(args)...); 。

参数

args - 转发给元素构造函数的参数

返回值

（无） | (C++17 前)
上述对 Container::emplace_back 的调用返回的值或引用，若它存在。 | (C++17 起)

复杂度

等同于 Container::emplace_back 的复杂度。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2783 | C++17 | emplace 返回 reference ，破坏与 C++17 前容器的兼容性 | 返回 decltype(auto)

参阅

push | 向栈顶插入元素 (公开成员函数)
pop | 删除栈顶元素 (公开成员函数)


std::stack<T,Container>::empty

< cpp‎ | container‎ | stack

bool empty() const; | (C++20 前)
[[nodiscard]] bool empty() const; | (C++20 起)

检查底层容器是否为空，即是否 c.empty() 。

参数

（无）

返回值

若底层容器为空则为 true ，否则为 false 。

复杂度

常数

参阅

size
 返回容纳的元素数
(公开成员函数)


std::stack<T,Container>::operator=

< cpp‎ | container‎ | stack
stack& operator=( const stack& other ); | (1) |
stack& operator=( stack&& other ); | (2) | (C++11 起)

以 other 的内容替换容器适配器的内容。

1) 复制赋值运算符。以 other 的内容副本替换内容。等效地调用 c = other.c; 。(隐式声明)
2) 移动赋值运算符。用移动语义以 other 的内容替换内容。等效地调用 c = std::move(other.c); 。(隐式声明)

参数

other - 用作源的另一容器适配器

返回值

*this

复杂度

等价于底层容器 operator= 的复杂度。

参阅

(构造函数)
 构造 stack
(公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::stack)

< cpp‎ | container‎ | stack

template< class T, class Container >
bool operator==( const std::stack <T,Container>& lhs, const std::stack <T,Container>& rhs );
 (1)
template< class T, class Container >
bool operator!=( const std::stack <T,Container>& lhs, const std::stack <T,Container>& rhs );
 (2)
template< class T, class Container >
bool operator<( const std::stack <T,Container>& lhs, const std::stack <T,Container>& rhs );
 (3)
template< class T, class Container >
bool operator<=( const std::stack <T,Container>& lhs, const std::stack <T,Container>& rhs );
 (4)
template< class T, class Container >
bool operator>( const std::stack <T,Container>& lhs, const std::stack <T,Container>& rhs );
 (5)
template< class T, class Container >
bool operator>=( const std::stack <T,Container>& lhs, const std::stack <T,Container>& rhs );
 (6)
template< class T, std::three_way_comparable Container >

std::compare_three_way_result_t<Container>

operator<=>( const std::stack <T,Container>& lhs, const std::stack <T,Container>& rhs );
 (7) (C++20 起)

比较二个容器适配器的底层容器。通过应用对应的运算符到底层容器进行比较。

参数

lhs, rhs - 要比较内容的迭代器适配器
-
T 必须满足可相等比较 (EqualityComparable) 的要求。

返回值

@1-6若对应比较产出 true 则为 true ，否则为 false 。

7) 底层容器上三路比较的结果。

复杂度

与容器大小成线性


std::stack<T,Container>::pop

< cpp‎ | container‎ | stack

void pop();

从 stack 移除顶元素。等效地调用 c.pop_back() 。

参数

（无）

返回值

（无）

复杂度

等于 Container::pop_back 的复杂度。

参阅

emplace (C++11) | 在顶部原位构造元素 (公开成员函数)
push | 向栈顶插入元素 (公开成员函数)
top | 访问栈顶元素 (公开成员函数)


std::stack<T,Container>::push

< cpp‎ | container‎ | stack

void push( const value_type& value ); |
void push( value_type&& value ); | (C++11 起)

推给定的元素 value 到 stack 顶。

1) 等效地调用 c.push_back(value)
2) 等效地调用 c.push_back(std::move(value))

参数

value - 要推入的元素值

返回值

（无）

复杂度

等于 Container::push_back 的复杂度。

参阅

emplace (C++11) | 在顶部原位构造元素 (公开成员函数)
pop | 删除栈顶元素 (公开成员函数)


std::stack<T,Container>::size

< cpp‎ | container‎ | stack

size_type size() const;

返回底层容器中的元素数，即 c.size() 。

参数

（无）

返回值

容器中的元素数。

复杂度

常数。

参阅

empty
 检查底层容器是否为空
(公开成员函数)


std::stack<T,Container>::stack

< cpp‎ | container‎ | stack

stack() : stack(Container()) { } | (1) | (C++11 起)
 | (2) |
explicit stack( const Container& cont = Container() ); |  |  | (C++11 前)
explicit stack( const Container& cont ); |  |  | (C++11 起)
explicit stack( Container&& cont ); | (3) | (C++11 起)
stack( const stack& other ); | (4) |
stack( stack&& other ); | (5) | (C++11 起)
template< class InputIt > stack( InputIt first, InputIt last ); | (6) | (C++23 起)
template< class Alloc > explicit stack( const Alloc& alloc ); | (7) | (C++11 起)
template< class Alloc > stack( const Container& cont, const Alloc& alloc ); | (8) | (C++11 起)
template< class Alloc > stack( Container&& cont, const Alloc& alloc ); | (9) | (C++11 起)
template< class Alloc > stack( const stack& other, const Alloc& alloc ); | (10) | (C++11 起)
template< class Alloc > stack( stack&& other, const Alloc& alloc ); | (11) | (C++11 起)
template< class InputIt, class Alloc > stack( InputIt first, InputIt last, const Alloc& alloc ); | (12) | (C++23 起)

从各种数据源构造容器适配器的新底层容器。

1) 默认构造函数。值初始化容器。
2) 以 cont 的内容复制构造底层容器 c 。此亦为默认构造函数。 (C++11 前)
3) 以 std::move(cont) 移动构造底层容器 c 。
4) 复制构造函数。以 other.c 的内容复制构造适配器。
5) 移动构造函数。以 std::move(other.c) 构造适配器。
6) 以范围 [first, last) 的内容构造底层容器 c 。此重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 才参与重载决议。
7-12) 这些构造函数仅若 std::uses_allocator <Container, Alloc> 为 true ，即底层容器是知分配器容器（对所有标准库容器为 true ）才参与重载决议。
7) 以 alloc 为分配器构造底层容器，如同以 c(alloc) 。
8) 用 cont 的内容，并以 alloc 为分配器构造底层容器，如同以 c(cont, alloc) 。
9) 以 cont 的内容用移动语义，同时以 alloc 为分配器构造底层容器，如同以 c(std::move(cont), alloc) 。
10) 以 other.c 的内容，并以 alloc 为分配器构造适配器，如同以 c(other.c, alloc) 。
11) 以 other 的内容使用移动语义，并以 alloc 为分配器构造适配器，如同以 c(std::move(other.c), alloc) 。
12) 以范围 [first, last) 的内容并以 alloc 为分配器构造底层容器，如同用 c(first, last, alloc) 。此重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 才参与重载决议。

参数

alloc | - | 用于底层容器所有内存分配的分配器
other | - | 用作源初始化底层容器的另一容器适配器
cont | - | 用作源初始化底层容器的容器
first, last | - | 用以初始化的元素范围
类型要求
- Alloc 必须满足分配器 (Allocator) 的要求。
- Container 必须满足容器 (Container) 的要求。接受一个分配器参数的构造函数仅若 Container 满足知分配器容器 (AllocatorAwareContainer) 的要求参与重载决议。
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

复杂度

同被包装容器上的对应操作。

示例

#include <stack>
#include <deque>
#include <iostream>

int main()
{
    std::stack<int> c1;
    c1.push(5);
    std::cout << c1.size() << '\n';

    std::stack<int> c2(c1);
    std::cout << c2.size() << '\n';

    std::deque<int> deq {3, 1, 4, 1, 5};
    std::stack<int> c3(deq);
    std::cout << c3.size() << '\n';
}

输出：

1
1
5

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式

参阅

operator=
 赋值给容器适配器
(公开成员函数)


std::stack<T,Container>::swap

< cpp‎ | container‎ | stack

void swap( stack& other ) noexcept(/* see below */); | (C++11 起)

交换容器适配器与 other 的内容。等效地调用 using std::swap ; swap(c, other.c); 。

参数

other - 要交换内容的容器适配器

返回值

（无）

异常

noexcept 说明： noexcept(noexcept(swap(c, other.c))) 上述表达式中，用与 C++17 std::is_nothrow_swappable 特性所用的相同方式查找标识符 swap 。 | (C++11 起) (C++17 前)
noexcept 说明： noexcept( std::is_nothrow_swappable_v <Container>) | (C++17 起)

复杂度

与底层容器相同（常为常数）。

注解

一些实现（例如 libc++ ）对 C++11 前模式提供 swap 成员函数作为扩展。

示例

#include <iostream>
#include <stack>
#include <string>
#include <vector>

template <typename Stack>
void print(Stack stack /* pass by value */, int id)
{
    std::cout << "s" << id << " [" << stack.size() << "]: ";
    for (; !stack.empty(); stack.pop())
        std::cout << stack.top() << ' ';
    std::cout << (id > 1 ? "\n\n" : "\n");
}

int main()
{
    std::vector<std::string>
        v1{"1","2","3","4"},
        v2{"Ɐ","B","Ɔ","D","Ǝ"};

    std::stack s1{std::move(v1)};
    std::stack s2{std::move(v2)};

    print(s1, 1);
    print(s2, 2);

    s1.swap(s2);

    print(s1, 1);
    print(s2, 2);
}

输出：

s1 [4]: 4 3 2 1
s2 [5]: Ǝ D Ɔ B Ɐ

s1 [5]: Ǝ D Ɔ B Ɐ
s2 [4]: 4 3 2 1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2456 | C++11 | noexcept 规定非良构 | 使之能用

参阅

std::swap(std::stack)
(C++11)
 特化 std::swap 算法
(函数模板)


std::swap(std::stack)

< cpp‎ | container‎ | stack

定义于头文件 <stack>
template< class T, class Container >

void swap( std::stack <T,Container>& lhs,

std::stack <T,Container>& rhs );
 (C++11 起)
(C++17 前)
template< class T, class Container >

void swap( std::stack <T,Container>& lhs,

std::stack <T,Container>& rhs ) noexcept(/* see below */);
 (C++17 起)

为 std::stack 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

此重载仅若 std::is_swappable_v <Container> 为 true 才参与重载决议。

 (C++17 起)

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

与交换底层容器相同。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++11)
 交换内容
(公开成员函数)


std::stack<T,Container>::top

< cpp‎ | container‎ | stack
reference top();
const_reference top() const;

返回 stack 中顶元素的引用。它是最近推入的元素。此元素将在调用 pop() 时被移除。等效于调用 c.back() 。

参数

（无）

返回值

到末尾元素的引用

复杂度

常数

示例

#include <stack>
#include <iostream>

int main()
{
    std::stack<int>   s;

    s.push( 2 );
    s.push( 6 );
    s.push( 51 );

    std::cout << s.size() << " elements on stack\n";
    std::cout << "Top element: "
              << s.top()         // 保留元素在 stack 上
              << "\n";
    std::cout << s.size() << " elements on stack\n";
    s.pop();
    std::cout << s.size() << " elements on stack\n";
    std::cout << "Top element: " << s.top() << "\n";

    return 0;
}

输出：

3 elements on stack
Top element: 51
3 elements on stack
2 elements on stack
Top element: 6

参阅

push | 向栈顶插入元素 (公开成员函数)
pop | 删除栈顶元素 (公开成员函数)


std::uses_allocator<std::stack>

< cpp‎ | container‎ | stack

template< class T, class Container, class Alloc > struct uses_allocator<stack<T,Container>,Alloc> : std::uses_allocator <Container, Alloc>::type { }; | (C++11 起)

为 std::stack 提供 std::uses_allocator 类型特性的通透特化：容器适配器使用分配器，若且唯若底层容器使用。

继承自 std::integral_constant

成员常量

value
[静态]
 true
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

参阅

uses_allocator
(C++11)
 检查指定的类型是否支持使用分配器的构造
(类模板)


std::stack<T,Container>::~stack

< cpp‎ | container‎ | stack

~stack();

销毁 stack 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 stack 大小成线性。


std::unordered_map

< cpp‎ | container
定义于头文件 <unordered_map>
template<

class Key,
class T,
class Hash = std::hash <Key>,
class KeyEqual = std::equal_to <Key>,
class Allocator = std::allocator < std::pair <const Key, T> >

> class unordered_map;
 (1) (C++11 起)
namespace pmr {

template <class Key,
class T,
class Hash = std::hash <Key>,
class KeyEqual = std::equal_to <Key>>
using unordered_map = std::unordered_map<Key, T, Hash, Pred,
std::pmr::polymorphic_allocator < std::pair <const Key,T>>>;

}
 (2) (C++17 起)

unordered_map 是关联容器，含有带唯一键的键-值 pair 。搜索、插入和元素移除拥有平均常数时间复杂度。

元素在内部不以任何特定顺序排序，而是组织进桶中。元素放进哪个桶完全依赖于其键的哈希。这允许对单独元素的快速访问，因为一旦计算哈希，则它准确指代元素所放进的桶。

std::unordered_map 满足容器 (Container) 、知分配器容器 (AllocatorAwareContainer) 、无序关联容器 (UnorderedAssociativeContainer) 的要求。

迭代器非法化

操作 | 非法化
所有只读操作、 swap 、 std::swap | 决不
clear 、 rehash 、 reserve 、 operator= | 始终
insert 、 emplace 、 emplace_hint 、 operator[] | 仅若重哈希导致
erase | 仅为指向被擦除元素者

注意

  • swap 函数不非法化容器内的任何迭代器，但它们非法化标记交换区域结尾的迭代器。
  • 指向存储于容器中的关键或元素的引用和指针仅因擦除该元素才被非法化，即使在非法化对应迭代器时。

成员类型

成员类型 | 定义
key_type | Key
mapped_type | T
value_type | std::pair <const Key, T>
size_type | 无符号整数类型（通常是 std::size_t ）
difference_type | 有符号整数类型（通常是 std::ptrdiff_t ）
hasher | Hash
key_equal | KeyEqual
allocator_type | Allocator
reference | value_type&
const_reference | const value_type&
pointer | std::allocator_traits <Allocator>::pointer
const_pointer | std::allocator_traits <Allocator>::const_pointer
iterator | 指向 value_type 的常老式向前迭代器 (LegacyForwardIterator)
const_iterator | 指向 const value_type 的老式向前迭代器 (LegacyForwardIterator)
local_iterator 类别、值、差、指针和引用类型都与 iterator 相同的迭代器类型。
能用此迭代器在单个桶迭代，但不能跨桶。
const_local_iterator 类别、值、差、指针和引用类型都与 const_iterator 相同的迭代器类型。
能用此迭代器在单个桶迭代，但不能跨桶。
node_type(C++17 起) | 表示容器结点的结点把柄特化
insert_return_type(C++17 起) 描述插入 node_type 结果的类型，下列类型的特化
template <class Iter, class NodeType> struct /*unspecified*/ {
    Iter     position;
    bool     inserted;
    NodeType node;
};
，以模板实参 iterator 和 node_type 实例化。

成员函数

(构造函数)
(C++11)
 构造 unordered_map
(公开成员函数)
(析构函数)
(C++11)
 析构 unordered_map
(公开成员函数)
operator=
(C++11)
 赋值给容器
(公开成员函数)
get_allocator
(C++11)
 返回相关的分配器
(公开成员函数)
迭代器
begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)
容量
empty
(C++11)
 检查容器是否为空
(公开成员函数)
size
(C++11)
 返回容纳的元素数
(公开成员函数)
max_size
(C++11)
 返回可容纳的最大元素数
(公开成员函数)
修改器
clear
(C++11)
 清除内容
(公开成员函数)
insert
(C++11)
 插入元素或结点 (C++17 起)
(公开成员函数)
insert_or_assign
(C++17)
 插入元素，或若键已存在则赋值给当前元素
(公开成员函数)
emplace
(C++11)
 原位构造元素
(公开成员函数)
emplace_hint
(C++11)
 使用提示原位构造元素
(公开成员函数)
try_emplace
(C++17)
 若键不存在则原位插入，若键存在则不做任何事
(公开成员函数)
erase
(C++11)
 擦除元素
(公开成员函数)
swap
(C++11)
 交换内容
(公开成员函数)
extract
(C++17)
 从另一容器释出结点
(公开成员函数)
merge
(C++17)
 从另一容器接合结点
(公开成员函数)
查找
at
(C++11)
 访问指定的元素，同时进行越界检查
(公开成员函数)
operator[]
(C++11)
 访问或插入指定的元素
(公开成员函数)
count
(C++11)
 返回匹配特定键的元素数量
(公开成员函数)
find
(C++11)
 寻找带有特定键的元素
(公开成员函数)
contains
(C++20)
 检查容器是否含有带特定键的元素
(公开成员函数)
equal_range
(C++11)
 返回匹配特定键的元素范围
(公开成员函数)
桶接口
begin(size_type) cbegin(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的开始
(公开成员函数)
end(size_type) cend(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的末尾
(公开成员函数)
bucket_count
(C++11)
 返回桶数
(公开成员函数)
max_bucket_count
(C++11)
 返回桶的最大数量
(公开成员函数)
bucket_size
(C++11)
 返回在特定的桶中的元素数量
(公开成员函数)
bucket
(C++11)
 返回带有特定键的桶
(公开成员函数)
哈希策略
load_factor
(C++11)
 返回每个桶的平均元素数量
(公开成员函数)
max_load_factor
(C++11)
 管理每个桶的平均元素数量的最大值
(公开成员函数)
rehash
(C++11)
 为至少为指定数量的桶预留存储空间并重新生成散列表
(公开成员函数)
reserve
(C++11)
 为至少为指定数量的元素预留存储空间并重新生成哈希表。
(公开成员函数)
观察器
hash_function
(C++11)
 返回用于对键散列的函数
(公开成员函数)
key_eq
(C++11)
 返回用于比较键的相等性的函数
(公开成员函数)

非成员函数

operator==operator!= (C++20 中移除) | 比较 unordered_map 中的值 (函数模板)
std::swap(std::unordered_map) (C++11) | 特化 std::swap 算法 (函数模板)
erase_if(std::unordered_map) (C++20) | 擦除所有满足特定判别标准的元素 (函数模板)

推导指引 (C++17 起)

示例

#include <iostream>
#include <string>
#include <unordered_map>

int main()
{
    // 创建三个 string 的 unordered_map （映射到 string ）
    std::unordered_map<std::string, std::string> u = {
        {"RED","#FF0000"},
        {"GREEN","#00FF00"},
        {"BLUE","#0000FF"}
    };

    // 迭代并打印 unordered_map 的关键和值
    for( const auto& n : u ) {
        std::cout << "Key:[" << n.first << "] Value:[" << n.second << "]\n";
    }

    // 添加新入口到 unordered_map
    u["BLACK"] = "#000000";
    u["WHITE"] = "#FFFFFF";

    // 用关键输出值
    std::cout << "The HEX of color RED is:[" << u["RED"] << "]\n";
    std::cout << "The HEX of color BLACK is:[" << u["BLACK"] << "]\n";

    return 0;
}

输出：

Key:[RED] Value:[#FF0000]
Key:[BLUE] Value:[#0000FF]
Key:[GREEN] Value:[#00FF00]
The HEX of color RED is:[#FF0000]
The HEX of color BLACK is:[#000000]


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::at

< cpp‎ | container‎ | unordered map

T& at( const Key& key ); | (1) | (C++11 起)
const T& at( const Key& key ) const; | (2) | (C++11 起)

返回到拥有等于 key 的关键的元素被映射值的引用。若无这种元素，则抛出 std::out_of_range 类型异常。

参数

key - 要找到的元素的关键

返回值

到请求元素的被映射值的引用

异常

若容器无拥有指定 key 的元素则为 std::out_of_range

复杂度

平均情况：常数，最坏情况：与大小成线性。

复杂度

operator[]
(C++11)
 访问或插入指定的元素
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::begin, std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::cbegin

< cpp‎ | container‎ | unordered map

iterator begin() noexcept; | (C++11 起)
const_iterator begin() const noexcept; | (C++11 起)
const_iterator cbegin() const noexcept; | (C++11 起)

返回指向 unordered_map 首元素的迭代器。

若 unordered_map 为空，则返回的迭代器将等于 end() 。

参数

（无）

返回值

指向首元素的迭代器。

复杂度

常数。

示例

#include <cmath>
#include <iostream>
#include <unordered_map>

struct Node { double x, y; };

int main() {
    Node nodes[3] = { {1, 0}, {2, 0}, {3, 0} };

    // mag 是映射 Node 地址到其平面中长度的 map
    std::unordered_map<Node *, double> mag = {
        { nodes,     1 },
        { nodes + 1, 2 },
        { nodes + 2, 3 }
    };

    // 从 0 到长度更改每个 y 坐标
    for(auto iter = mag.begin(); iter != mag.end(); ++iter){
        auto cur = iter->first; // 指向 Node 的指针
        cur->y = mag[cur]; // 亦能使用 cur->y = iter->second;
    }

    // 更新并打印每个结点的长度
    for(auto iter = mag.begin(); iter != mag.end(); ++iter){
        auto cur = iter->first;
        mag[cur] = std::hypot(cur->x, cur->y);
        std::cout << "The magnitude of (" << cur->x << ", " << cur->y << ") is ";
        std::cout << iter->second << '\n';
    }

    // 以基于范围的 for 循环重复上述内容
    for(auto i : mag) {
        auto cur = i.first;
        cur->y = i.second;
        mag[cur] = std::hypot(cur->x, cur->y);
        std::cout << "The magnitude of (" << cur->x << ", " << cur->y << ") is ";
        std::cout << mag[cur] << '\n';
        // 注意与上述 std::cout << iter->second << '\n'; 相反，
        // std::cout << i.second << '\n'; 将不会打印更新的长度
    }
}

可能的输出：

The magnitude of (3, 3) is 4.24264
The magnitude of (1, 1) is 1.41421
The magnitude of (2, 2) is 2.82843
The magnitude of (3, 4.24264) is 5.19615
The magnitude of (1, 1.41421) is 1.73205
The magnitude of (2, 2.82843) is 3.4641

参阅

end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::begin(size_type), std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::cbegin(size_type)

< cpp‎ | container‎ | unordered map

local_iterator begin( size_type n ); | (C++11 起)
const_local_iterator begin( size_type n ) const; | (C++11 起)
const_local_iterator cbegin( size_type n ) const; | (C++11 起)

返回指向下标为 n 的桶首元素的迭代器。

参数

n - 要访问的桶的下标

返回值

指向首元素的迭代器。

复杂度

常数。

参阅

end(size_type) cend(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的末尾
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::bucket

< cpp‎ | container‎ | unordered map

size_type bucket( const Key& key ) const; | (C++11 起)

返回关键 key 的桶的下标。始终会在此桶中找到关键等于 key 的元素（若存在）。返回值仅对 bucket_count() 返回相同值的容器实例合法。

若 bucket_count() 为零则行为未定义。

参数

key - 要检验的关键值

返回值

关键 key 的桶编号。

复杂度

常数。

参阅

bucket_size
(C++11)
 返回在特定的桶中的元素数量
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::bucket_count

< cpp‎ | container‎ | unordered map

size_type bucket_count() const; | (C++11 起)

返回容器中的桶数。

参数

（无）

返回值

容器中的桶数。

复杂度

常数。

参阅

bucket_size (C++11) | 返回在特定的桶中的元素数量 (公开成员函数)
max_bucket_count (C++11) | 返回桶的最大数量 (公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::bucket_size

< cpp‎ | container‎ | unordered map

size_type bucket_size( size_type n ) const; | (C++11 起)

返回下标为 n 的桶中的元素数。

参数

n - 要检验的桶的下标

返回值

桶 n 中的元素数。

复杂度

与桶 n 的大小成线性。

参阅

bucket_count
(C++11)
 返回桶数
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::clear

< cpp‎ | container‎ | unordered map

void clear() noexcept; | (C++11 起)

从容器擦除所有元素。此调用后 size() 返回零。

非法化任何指代所含元素的引用、指针或迭代器。可能亦非法化尾后迭代器。

参数

（无）

返回值

（无）

复杂度

与容器大小，即元素数成线性。

示例

#include <algorithm>
#include <iostream>
#include <unordered_map>

int main()
{
    std::unordered_map<int, char> container{{1, 'x'}, {2, 'y'}, {3, 'z'}};

    auto print = [](std::pair<const int, char>& n) {
        std::cout << " " << n.first << '(' << n.second << ')';
    };

    std::cout << "Before clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';

    std::cout << "Clear\n";
    container.clear();

    std::cout << "After clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';
}

可能的输出：

Before clear: 1(x) 2(y) 3(z)
Size=3
Clear
After clear:
Size=0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2550 | C++11 | 对于无序关联容器，不清楚复杂度是与元素数还是桶数成线性 | 辨明它与元素数成线性

参阅

erase
(C++11)
 擦除元素
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::contains

< cpp‎ | container‎ | unordered map

bool contains( const Key& key ) const; | (1) | (C++20 起)
template< class K > bool contains( const K& x ) const; | (2) | (C++20 起)
1) 检查容器中是否有键等价于 key 的元素。
2) 检查是否有键比较等价于值 x 的元素。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 任何能通透地与键比较的类型的值

返回值

若有这种元素则为 true ，否则为 false 。

复杂度

平均为常数，最坏情况与容器大小成线性。

示例

#include <iostream>
#include <unordered_map>

int main()
{
    std::unordered_map<int,char> example = {{1,'a'},{2,'b'}};

    for(int x: {2, 5}) {
        if(example.contains(x)) {
            std::cout << x << ": Found\n";
        } else {
            std::cout << x << ": Not found\n";
        }
    }
}

输出：

2: Found
5: Not found

参阅

find (C++11) | 寻找带有特定键的元素 (公开成员函数)
count (C++11) | 返回匹配特定键的元素数量 (公开成员函数)
equal_range (C++11) | 返回匹配特定键的元素范围 (公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::count

< cpp‎ | container‎ | unordered map

size_type count( const Key& key ) const; | (1) | (C++11 起)
template< class K > size_type count( const K& x ) const; | (2) | (C++20 起)
1) 返回拥有比较等于指定参数 key 的关键的元素数，因为此容器不允许重复故为 1 或 0 。
2) 返回键比较等价于指定参数 x 的元素数。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要计量等价元素数的键值
x | - | 能通透地与键比较的任何类型值

返回值

1) 拥有关键 key 的元素数，即 1 或 0 。
2) 键比较等价于 x 的元素数。

复杂度

平均为常数，最坏情况与容器大小成线性。

参阅

find (C++11) | 寻找带有特定键的元素 (公开成员函数)
equal_range (C++11) | 返回匹配特定键的元素范围 (公开成员函数)


std::unordered_map 的推导指引

< cpp‎ | container‎ | unordered map

定义于头文件 <unordered_map>
template<class InputIt,

class Hash = std::hash <iter_key_t<InputIt>>,
class Pred = std::equal_to <iter_key_t<InputIt>>,
class Alloc = std::allocator <iter_to_alloc_t<InputIt>>>
unordered_map(InputIt, InputIt,
typename /*see below*/::size_type = /*see below*/,
Hash = Hash(), Pred = Pred(), Alloc = Alloc())

-> unordered_map<iter_key_t<InputIt>, iter_value_t<InputIt>, Hash, Pred, Alloc>;
 (1) (C++17 起)
template<class Key, class T, class Hash = std::hash <Key>,

class Pred = std::equal_to <Key>,
class Alloc = std::allocator < std::pair <const Key, T>>>
unordered_map( std::initializer_list < std::pair <const Key, T>>,
typename /*see below*/::size_type = /*see below*/,
Hash = Hash(), Pred = Pred(), Alloc = Alloc())

-> unordered_map<Key, T, Hash, Pred, Alloc>;
 (2) (C++17 起)
template<class InputIt, class Alloc>

unordered_map(InputIt, InputIt, typename /*see below*/::size_type, Alloc)
-> unordered_map<iter_key_t<InputIt>, iter_val_t<InputIt>,
std::hash <iter_key_t<InputIt>>,

std::equal_to <iter_key_t<InputIt>>, Alloc>;
 (3) (C++17 起)
template<class InputIt, class Alloc>

unordered_map(InputIt, InputIt, Alloc)
-> unordered_map<iter_key_t<InputIt>, iter_val_t<InputIt>,
std::hash <iter_key_t<InputIt>>,

std::equal_to <iter_key_t<InputIt>>, Alloc>;
 (4) (C++17 起)
template<class InputIt, class Hash, class Alloc>

unordered_map(InputIt, InputIt, typename /*see below*/::size_type, Hash, Alloc)
-> unordered_map<iter_key_t<InputIt>, iter_val_t<InputIt>, Hash,

std::equal_to <iter_key_t<InputIt>>, Alloc>;
 (5) (C++17 起)
template<class Key, class T, typename Alloc>

unordered_map( std::initializer_list < std::pair <const Key, T>>,
typename /*see below*/::size_type, Alloc)

-> unordered_map<Key, T, std::hash <Key>, std::equal_to <Key>, Alloc>;
 (6) (C++17 起)
template<class Key, class T, typename Alloc>

unordered_map( std::initializer_list < std::pair <const Key, T>>, Alloc)

-> unordered_map<Key, T, std::hash <Key>, std::equal_to <Key>, Alloc>;
 (7) (C++17 起)
template<class Key, class T, class Hash, class Alloc>

unordered_map( std::initializer_list < std::pair <const Key, T>>,
typename /*see below*/::size_type, Hash, Alloc)

-> unordered_map<Key, T, Hash, equal_to<Key>, Allocator>;
 (8) (C++17 起)

其中类型别名 iter_key_t 、 iter_val_t 、 iter_to_alloc_t 如同定义如下

template<class InputIt>

using iter_key_t = std::remove_const_t <

typename std::iterator_traits <InputIt>::value_type::first_type>;
 (仅为说明)
template<class InputIt>
using iter_val_t = typename std::iterator_traits <InputIt>::value_type::second_type;
 (仅为说明)
template<class InputIt>

using iter_to_alloc_t = std::pair <
std::add_const_t <typename std::iterator_traits <InputIt>::value_type::first_type>,
typename std::iterator_traits <InputIt>::value_type::second_type

>
 (仅为说明)

为 unordered_map 提供这些推导指引以允许从迭代器范围（重载 (1,3-5) ）和 std::initializer_list （重载 (2,6-8) ）推导。这些重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 、 Alloc 满足分配器 (Allocator) 、 Hash 或 Pred 均不满足分配器 (Allocator) 且 Hash 不是整数类型才参与重载决议。

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

这些指引中的 size_type 形参类型指代推导指引推导出的类型的 size_type 成员类型。

示例

#include <unordered_map>
int main() {
// std::unordered_map m1 = {{"foo", 1}, {"bar", 2}}; // 错误：花括号初始化器列表无类型
                                                     // 不能从 {"foo", 1} 或 {"bar", 2}
                                                     // 推导 pair<const Key, T>
   std::unordered_map m1 = std::initializer_list<
                        std::pair<char const* const, int>>({{"foo", 2}, {"bar", 3}}); // 指引 #2
   std::unordered_map m2(m1.begin(), m1.end()); // 指引 #1
}


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::emplace

< cpp‎ | container‎ | unordered map

template< class... Args > std::pair <iterator,bool> emplace( Args&&... args ); | (C++11 起)

若容器中无拥有该关键的元素，则插入以给定的 args 原位构造的新元素到容器。

细心地使用 emplace 允许在构造新元素的同时避免不必要的复制或移动操作。 准确地以与提供给 emplace 者相同的参数，通过 std::forward <Args>(args)... 转发调用新元素（即 std::pair <const Key, T> ）的构造函数。 即使容器中已有拥有该关键的元素，也可能构造元素，该情况下新构造的元素将被立即销毁。

若因插入发生重哈希，则所有迭代器都被非法化。否则迭代器不受影响。引用不被非法化。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。

参数

args - 要转发给元素构造函数的参数

返回值

返回由指向被插入元素，或若不发生插入则为既存元素的迭代器，和指代插入是否发生的 bool （若发生插入则为 true ，否则为 false ）。

异常

若任何操作抛出异常，则此函数无效果。

复杂度

平均为均摊常数，最坏情况与容器大小成线性。

示例

#include <iostream>
#include <utility>
#include <string>
#include <unordered_map>

int main()
{
    std::unordered_map<std::string, std::string> m;

    // 使用 pair 的移动构造函数
    m.emplace(std::make_pair(std::string("a"), std::string("a")));

    // 使用 pair 的转换移动构造函数
    m.emplace(std::make_pair("b", "abcd"));

    // 使用 pair 的模板构造函数
    m.emplace("d", "ddd");

    // 使用 pair 的逐片构造函数
    m.emplace(std::piecewise_construct,
              std::forward_as_tuple("c"),
              std::forward_as_tuple(10, 'c'));
    // C++17 起，能使用 m.try_emplace("c", 10, 'c');

    for (const auto &p : m) {
        std::cout << p.first << " => " << p.second << '\n';
    }
}

可能的输出：

a => a
b => abcd
c => cccccccccc
d => ddd

参阅

emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)
try_emplace (C++17) | 若键不存在则原位插入，若键存在则不做任何事 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::emplace_hint

< cpp‎ | container‎ | unordered map
template <class... Args> iterator emplace_hint( const_iterator hint, Args&&... args ); | (C++11 起)

插入新元素到容器，以 hint 为应当放置新元素位置的建议。原位构造元素，即不进行复制或移动操作。

准确地以与提供给函数者相同的参数，以 std::forward <Args>(args)... 转发调用元素类型（ value_type 即 std::pair <const Key, T> ）的构造函数。

若因插入发生重哈希，则所有迭代器都被非法化。否则迭代器不受影响。引用不被非法化。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。

参数

hint | - | 迭代器，用作插入新元素位置的建议
args | - | 转发给元素构造函数的参数

返回值

返回指向新插入元素的迭代器。

若因元素已存在而插入失败，则返回指向带等价关键的既存元素。

异常

若任何操作抛出异常，则此函数无效果（强异常保证）。

复杂度

平均为均摊常数，最坏情况与容器大小成线性。

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::empty

< cpp‎ | container‎ | unordered map

bool empty() const noexcept; | (C++11 起) (C++20 前)
[[nodiscard]] bool empty() const noexcept; | (C++20 起)

检查容器是否无元素，即是否 begin() == end() 。

参数

（无）

返回值

若容器为空则为 true ，否则为 false

复杂度

常数。

示例

下列代码用 empty 检查 std::unordered_map <int,int> 是否含有任何元素：

#include <unordered_map>
#include <iostream>
#include <utility>

int main()
{
    std::unordered_map<int, int> numbers;
    std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';

    numbers.emplace(42, 13);
    numbers.insert(std::make_pair(13317, 123));
    std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
}

输出：

Initially, numbers.empty(): 1
After adding elements, numbers.empty(): 0

参阅

size
(C++11)
 返回容纳的元素数
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::end, std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::cend

< cpp‎ | container‎ | unordered map

iterator end() noexcept; | (C++11 起)
const_iterator end() const noexcept; | (C++11 起)
const_iterator cend() const noexcept; | (C++11 起)

返回指向 unordered_map 末元素后一元素的迭代器。

此元素表现为占位符；试图访问它导致未定义行为。

参数

（无）

返回值

指向后随最后元素的迭代器。

复杂度

常数。

示例

#include <cmath>
#include <iostream>
#include <unordered_map>

struct Node { double x, y; };

int main() {
    Node nodes[3] = { {1, 0}, {2, 0}, {3, 0} };

    // mag 是映射 Node 地址到其平面中长度的 map
    std::unordered_map<Node *, double> mag = {
        { nodes,     1 },
        { nodes + 1, 2 },
        { nodes + 2, 3 }
    };

    // 从 0 到长度更改每个 y 坐标
    for(auto iter = mag.begin(); iter != mag.end(); ++iter){
        auto cur = iter->first; // 指向 Node 的指针
        cur->y = mag[cur]; // 亦能使用 cur->y = iter->second;
    }

    // 更新并打印每个结点的长度
    for(auto iter = mag.begin(); iter != mag.end(); ++iter){
        auto cur = iter->first;
        mag[cur] = std::hypot(cur->x, cur->y);
        std::cout << "The magnitude of (" << cur->x << ", " << cur->y << ") is ";
        std::cout << iter->second << '\n';
    }

    // 以基于范围的 for 循环重复上述内容
    for(auto i : mag) {
        auto cur = i.first;
        cur->y = i.second;
        mag[cur] = std::hypot(cur->x, cur->y);
        std::cout << "The magnitude of (" << cur->x << ", " << cur->y << ") is ";
        std::cout << mag[cur] << '\n';
        // 注意与上述 std::cout << iter->second << '\n'; 相反，
        // std::cout << i.second << '\n'; 将不会打印更新的长度
    }
}

可能的输出：

The magnitude of (3, 3) is 4.24264
The magnitude of (1, 1) is 1.41421
The magnitude of (2, 2) is 2.82843
The magnitude of (3, 4.24264) is 5.19615
The magnitude of (1, 1.41421) is 1.73205
The magnitude of (2, 2.82843) is 3.4641

参阅

begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::end(size_type), std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::cend(size_type)

< cpp‎ | container‎ | unordered map

local_iterator end( size_type n ); | (C++11 起)
const_local_iterator end( size_type n ) const; | (C++11 起)
const_local_iterator cend( size_type n ) const; | (C++11 起)

返回后随下标为 n 的桶的最后元素的元素的迭代器。此元素表现为占位符，试图访问它会导致未定义行为。

参数

n - 要访问的桶的下标

返回值

指向后随最后元素的元素的迭代器。

复杂度

常数

参阅

begin(size_type) cbegin(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的开始
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::equal_range

< cpp‎ | container‎ | unordered map

std::pair <iterator,iterator> equal_range( const Key& key ); | (1) | (C++11 起)
std::pair <const_iterator,const_iterator> equal_range( const Key& key ) const; | (2) | (C++11 起)
template< class K > std::pair <iterator,iterator> equal_range( const K& x ); | (3) | (C++20 起)
template< class K > std::pair <const_iterator,const_iterator> equal_range( const K& x ) const; | (4) | (C++20 起)
1,2) 返回容器中所有键等于 key 的元素范围。范围以二个迭代器定义，第一个指向所需范围的首元素，而第二个指向范围的尾后一位元素。
3,4) 返回含有容器中所有键等价于 x 的元素的范围。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要与元素比较的键值
x | - | 任何能与键通透比较的类型的值

返回值

含一对定义所需范围的迭代器的 std::pair 。若无这种元素，则将尾后（见 end() ）迭代器作为 pair 的两个元素返回。

复杂度

平均情况与带关键 key 的元素数成线性，最坏情况与容器大小成线性。

示例

#include <iostream>
#include <unordered_map>

int main()
{
    std::unordered_map<int,char> map = {{1,'a'},{1,'b'},{1,'d'},{2,'b'}};
    auto range = map.equal_range(1);
    for (auto it = range.first; it != range.second; ++it) {
        std::cout << it->first << ' ' << it->second << '\n';
    }
}

输出：

1 a

参阅

find (C++11) | 寻找带有特定键的元素 (公开成员函数)
contains (C++20) | 检查容器是否含有带特定键的元素 (公开成员函数)
count (C++11) | 返回匹配特定键的元素数量 (公开成员函数)
equal_range | 返回匹配特定键值的元素范围 (函数模板)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::erase

< cpp‎ | container‎ | unordered map

 | (1) |
iterator erase( iterator pos ); |  |  | (C++11 起)
iterator erase( const_iterator pos ); |  |  | (C++11 起)
 | (2) |
iterator erase( const_iterator first, const_iterator last ); |  |  | (C++11 起)
size_type erase( const key_type& key ); | (3) | (C++11 起)
template< class K > size_type erase( K&& x ); | (4) | (C++23 起)

从容器移除指定的元素。

1) 移除位于 pos 的元素。
2) 移除范围 [first; last) 中的元素，它必须是 *this 中的合法范围。
3) 移除键等价于 key 的元素（若存在一个）。
4) 移除键比较等价于值 x 的元素（若存在一个）。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

到被擦除元素的引用和迭代器被非法化。其他迭代器和引用不被非法化。

迭代器 pos 必须合法且可解引用。从而 end() 迭代器（合法，但不可解引用）不能用作 pos 所用的值。 保留未被擦除的元素顺序（这使得可能在迭代通过容器时擦除单独的元素）。

参数

pos | - | 指向要移除的元素的迭代器
first, last | - | 要移除的元素范围
key | - | 要移除的元素键值
x | - | 任何能与键通透比较的类型的值，指代要移除的元素

返回值

1-2) 后随最后被移除的元素的迭代器。
3,4) 被移除的元素数。

异常

1,2) 不抛出
3,4) 任何 Hash 与 KeyEqual 对象所抛的异常

复杂度

给定 unordered_map 的实例 c ：

1) 平均情况：常数，最坏情况： c.size()
2) 平均情况： std::distance (first, last) ，最坏情况： c.size()
3) 平均情况： c.count(key) ，最坏情况： c.size()
4) 平均情况： c.count(x) ，最坏情况： c.size()

示例

#include <unordered_map>
#include <iostream>
int main()
{
    std::unordered_map<int, std::string> c = {
        {1, "one" }, {2, "two" }, {3, "three"},
        {4, "four"}, {5, "five"}, {6, "six"  }
    };

    // 从 c 擦除所有奇数
    for(auto it = c.begin(); it != c.end(); ) {
        if(it->first % 2 != 0)
            it = c.erase(it);
        else
            ++it;
    }

    for(auto& p : c) {
        std::cout << p.second << ' ';
    }
}

可能的输出：

two four six

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2059 | C++11 | 对一个 const_iterator 的重载引入了新的歧义 | 添加了对 iterator 的重载
LWG 2356 | C++11 | 未被擦除的元素顺序未指定 | 要求保留

参阅

clear
(C++11)
 清除内容
(公开成员函数)


std::erase_if (std::unordered_map)

< cpp‎ | container‎ | unordered map

定义于头文件 <unordered_map>
template< class Key, class T, class Hash, class KeyEqual, class Alloc, class Pred >

typename std::unordered_map <Key,T,Hash,KeyEqual,Alloc>::size_type

erase_if( std::unordered_map <Key,T,Hash,KeyEqual,Alloc>& c, Pred pred);
 (C++20 起)

从容器中擦除所有满足谓词 pred 的元素。等价于

auto old_size = c.size();
for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}
return old_size - c.size();

参数

c | - | 要从中擦除的元素
pred | - | 若应该擦除元素则对它返回 true 的谓词

返回值

擦除的元素数。

复杂度

线性。

示例

#include <unordered_map>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& cont)
{
    os << "{";
    for (const auto& item : cont) {
        os << "{" << item.first << ", " << item.second << "}";
    }
    return os << "}";
}

int main()
{
    std::unordered_map<int, char> data {{1, 'a'},{2, 'b'},{3, 'c'},{4, 'd'},
                                        {5, 'e'},{4, 'f'},{5, 'g'},{5, 'g'}};
    std::cout << "Original:\n" << data << '\n';

    const auto count = std::erase_if(data, [](const auto& item) {
        auto const& [key, value] = item;
        return (key & 1) == 1;
    });

    std::cout << "Erase items with odd keys:\n" << data << '\n'
              << count << " items removed.\n";
}

输出：

Original:
{{5, e}{4, d}{3, c}{2, b}{1, a}}
Erase items with odd keys:
{{4, d}{2, b}}
3 items removed.

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::extract

< cpp‎ | container‎ | unordered map

node_type extract( const_iterator position ); | (1) | (C++17 起)
node_type extract( const key_type& k ); | (2) | (C++17 起)
template< class K > node_type extract( K&& x ); | (3) | (C++23 起)
1) 解链含 position 所指向元素的结点并返回占有它的结点柄。
2) 若容器拥有元素而其关键等于 x ，则从容器解链该元素并返回占有它的结点柄。否则，返回空结点柄。
3) 同 (2) 。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

任何情况下，均不复制或移动元素，只重指向容器结点的内部指针。

释出结点只会非法化指向被释出元素的迭代器，并保持未被擦除元素的相对顺序。指向被释出元素的指针和引用保持合法，但在结点柄占有该元素时不能使用：若元素被插入容器，就能使用它们。

参数

position | - | 指向此容器中的合法迭代器
k | - | 鉴别要被释出的结点的键
x | - | 任何能与键通透比较的类型的值，鉴别要释出的结点

返回值

占有被释出元素的结点柄，或 (2,3) 中找不到元素的情况下为空结点柄。

复杂度

1,2,3) 平均情况 O(1) ，最坏情况 O(a.size()) 。

注解

extract 是更换 map 的键而不重分配的唯一方式：

map<int, string> m{{1, "mango"}, {2, "papaya"}, {3, "guava"}};
auto nh = m.extract(2);
nh.key() = 4;
m.insert(move(nh));
// m == {{1, "mango"}, {3, "guava"}, {4, "papaya"}}

示例

#include <algorithm>
#include <iostream>
#include <unordered_map>

int main()
{
    std::unordered_map<int, char> cont{{1, 'a'}, {2, 'b'}, {3, 'c'}};

    auto print = [](std::pair<const int, char>& n) {
        std::cout << " " << n.first << '(' << n.second << ')';
    };

    std::cout << "Start:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 释出结点柄并更改键
    auto nh = cont.extract(1);
    nh.key() = 4;

    std::cout << "After extract and before insert:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 往回插入结点柄
    cont.insert(move(nh));

    std::cout << "End:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';
}

可能的输出：

Start: 1(a) 2(b) 3(c)
After extract and before insert: 2(b) 3(c)
End: 2(b) 3(c) 4(a)

参阅

merge (C++17) | 从另一容器接合结点 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)
erase (C++11) | 擦除元素 (公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::find

< cpp‎ | container‎ | unordered map

iterator find( const Key& key ); | (1) |
const_iterator find( const Key& key ) const; | (2) |
template< class K > iterator find( const K& x ); | (3) | (C++20 起)
template< class K > const_iterator find( const K& x ) const; | (4) | (C++20 起)
1,2) 寻找键等于 key 的的元素。
3,4) 寻找键比较等价于值 x 的元素。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 能通透地与键比较的任何类型值

返回值

指向键等于 key 的元素的迭代器。若找不到这种元素，则返回尾后（见 end() ）迭代器。

复杂度

平均为常数，最坏情况与容器大小成线性。

示例

#include <cstddef>
#include <iostream>
#include <functional>
#include <string>
#include <string_view>
#include <unordered_map>

using namespace std::literals;
using std::size_t;

struct string_hash
{
    using hash_type = std::hash<std::string_view>;
    using is_transparent = void;

    size_t operator()(const char* str) const        { return hash_type{}(str); }
    size_t operator()(std::string_view str) const   { return hash_type{}(str); }
    size_t operator()(std::string const& str) const { return hash_type{}(str); }
};

int main()
{
    // 简单比较演示
    std::unordered_map<int,char> example = {{1,'a'},{2,'b'}};

    auto search = example.find(2);
    if (search != example.end()) {
        std::cout << "Found " << search->first << " " << search->second << '\n';
    } else {
        std::cout << "Not found\n";
    }

    // C++20 演示：无序容器的异质查找（通透哈希）
    std::unordered_map<std::string, size_t, string_hash, std::equal_to<>> map{ {"one"s, 1} };
    std::cout << std::boolalpha
        << (map.find("one")   != map.end()) << '\n'
        << (map.find("one"s)  != map.end()) << '\n'
        << (map.find("one"sv) != map.end()) << '\n';
}

输出：

Found 2 b
true
true
true

参阅

count (C++11) | 返回匹配特定键的元素数量 (公开成员函数)
equal_range (C++11) | 返回匹配特定键的元素范围 (公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::get_allocator

< cpp‎ | container‎ | unordered map

allocator_type get_allocator() const noexcept; | (C++11 起)

返回与容器关联的分配器。

参数

（无）

返回值

关联的分配器。

复杂度

常数。


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::hash_function

< cpp‎ | container‎ | unordered map

hasher hash_function() const; | (C++11 起)

返回对关键哈希的函数。

参数

（无）

返回值

哈希函数。

复杂度

常数。

参阅

key_eq
(C++11)
 返回用于比较键的相等性的函数
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::insert

< cpp‎ | container‎ | unordered map
std::pair <iterator,bool> insert( const value_type& value ); | (1) | (C++11 起)
std::pair <iterator,bool> insert( value_type&& value ); | (1) | (C++17 起)
template< class P > std::pair <iterator,bool> insert( P&& value ); | (2) | (C++11 起)
iterator insert( const_iterator hint, const value_type& value ); | (3) | (C++11 起)
iterator insert( const_iterator hint, value_type&& value ); | (3) | (C++17 起)
template< class P > iterator insert( const_iterator hint, P&& value ); | (4) | (C++11 起)
template< class InputIt > void insert( InputIt first, InputIt last ); | (5) | (C++11 起)
void insert( std::initializer_list <value_type> ilist ); | (6) | (C++11 起)
insert_return_type insert(node_type&& nh); | (7) | (C++17 起)
iterator insert(const_iterator hint, node_type&& nh); | (8) | (C++17 起)

若容器尚未含有带等价关键的元素，则插入元素到容器中。

1-2) 插入 value 。重载 (2) 等价于 emplace( std::forward <P>(value)) ，且仅若 std::is_constructible <value_type, P&&>::value == true 才参与重载决议。
3-4) 插入 value ，以 hint 为应当开始搜索的位置的非强制建议。重载 (4) 等价于 emplace_hint(hint, std::forward <P>(value)) ，且仅若 std::is_constructible <value_type, P&&>::value == true 才参与重载决议。
5) 插入来自范围 [first, last) 的元素。若范围中的多个元素拥有比较等价的关键，则插入哪个元素是未指定的（待决的 LWG2844 ）。
6) 插入来自 initializer_list ilist 的元素。若范围中的多个元素拥有比较等价的关键，则插入哪个元素是未指定的（待决的 LWG2844 ）。
7) 若 nh 是空的结点把柄，则不做任何事。否则插入 nh 所占有的元素到容器，若容器尚未含有拥有等价于 nh.key() 的关键的元素。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。
8) 若 nh 是空的结点把柄，则不做任何事并返回尾迭代器。否则，插入 nh 所占有的元素到容器，若容器尚未含有拥有等价于 nh.key() 的关键的元素，并返回指向拥有等于 nh.key() 的关键的元素的迭代器（无关乎插入成功还是失败）。若插入成功，则从 nh 移动，否则它保持该元素的所有权。元素被插入到尽可能接近 hint 的位置。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。

若因插入发生重哈希，则所有迭代器都被非法化。否则迭代器不受影响。引用不受影响。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。若插入成功，则在结点把柄保有元素时获得的指向该元素的指针和引用被非法化，而在提取前获得的指向元素的指针和引用变得合法。 (C++17 起)

参数

hint | - | 迭代器，用作插入内容位置的建议
value | - | 要插入的元素值
first, last | - | 要插入的元素范围
ilist | - | 插入值来源的 initializer_list
nh | - | 兼容的结点把柄
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

1-2) 返回由指向被插入元素（或阻止插入的元素）的迭代器和指代插入是否发生的 bool 组成的 pair 。
3-4) 返回指向被插入元素，或阻止插入的元素的迭代器。
5-6) （无）
7) 返回 insert_return_type ，其成员初始化如下：若 nh 为空，则 inserted 为 false ， position 为 end() ，而 node 为空。否则发生插入， inserted 为 true ， position 指向被插入元素，而 node 为空。若插入失败，则 inserted 为 false ， node 拥有 nh 的先前值，而 position 指向拥有等价于 nh.key() 的关键的元素。
8) 若 nh 为空则为尾迭代器，若插入发生则为指向被插入元素的迭代器，而若插入失败则为指向拥有等价于 nh.key() 的关键的元素的迭代器。

异常

1-4) 若任何操作抛出异常，则插入无效果。
本节未完成
原因：情况 5-6

复杂度

1-4) 平均情况： O(1) ，最坏情况 O(size())
5-6) 平均情况： O(N) ，其中 N 是要插入的元素数。最坏情况： O(N*size()+N)
7-8) 平均情况： O(1) ，最坏情况 O(size())

注意

有提示插入 (3,4) 不返回 bool ，这是为了与顺序容器上的定位插入，如 std::vector::insert 签名兼容。这使得可以创建泛型插入器，例如 std::inserter 。检查有提示插入是否成功的一种方式是比较插入前后的 size() 。

示例

#include <string>
#include <iostream>
#include <unordered_map>

int main ()
{
    std::unordered_map<int, std::string> dict = {{1, "one"}, {2, "two"}};
    dict.insert({3, "three"});
    dict.insert(std::make_pair(4, "four"));
    dict.insert({{4, "another four"}, {5, "five"}});

    bool ok = dict.insert({1, "another one"}).second;
    std::cout << "inserting 1 -> \"another one\" "
              << (ok ? "succeeded" : "failed") << '\n';

    std::cout << "contents:\n";
    for(auto& p: dict)
        std::cout << " " << p.first << " => " << p.second << '\n';
}

可能的输出：

inserting 1 -> "another one" failed
contents:
 5 => five
 1 => one
 2 => two
 3 => three
 4 => four

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)
insert_or_assign (C++17) | 插入元素，或若键已存在则赋值给当前元素 (公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::insert_or_assign

< cpp‎ | container‎ | unordered map

template <class M> std::pair <iterator, bool> insert_or_assign(const key_type& k, M&& obj); | (1) | (C++17 起)
template <class M> std::pair <iterator, bool> insert_or_assign(key_type&& k, M&& obj); | (2) | (C++17 起)
template <class M> iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); | (3) | (C++17 起)
template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); | (4) | (C++17 起)
1,3) 若等价于 k 的键已存在于容器中，则赋值 std::forward <M>(obj) 给对应于键 k 的 mapped_type 。若键不存在，则如同用 insert 插入从 value_type(k, std::forward <M>(obj)) 构造的新值。
2,4) 同 (1,3) ，除了从 value_type(std::move(k), std::forward <M>(obj)) 构造被映射值。

若 std::is_assignable_v <mapped_type&, M&&> 为 false 则行为未定义 (C++20 前)程序非良构 (C++20 起)。

若插入发生且导致容器的重哈希，则所有迭代器被非法化。否则迭代器不受影响。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。

参数

k | - | 用于查找和若找不到则插入的键
hint | - | 指向新元素将要插入位置之前位置的迭代器
obj | - | 要插入或赋值的值

返回值

1,2) 若插入发生则 bool 组分为 true ，若赋值发生则 bool 组分为 false 。迭代器组分指向插入或更新的元素。
3,4) 指向被插入或更新的元素的迭代器。

复杂度

1,2) 与 emplace 的相同
3,4) 与 emplace_hint 的相同

注解

insert_or_assign 返回多于 operator[] 的信息，而且不要求被映射类型的可默认构造性。

示例

#include <iostream>
#include <unordered_map>
#include <string>

auto print_node = [](const auto &node) {
    std::cout << "[" << node.first << "] = " << node.second << '\n';
};

auto print_result = [](auto const &pair) {
    std::cout << (pair.second ? "inserted: " : "assigned: ");
    print_node(*pair.first);
};

int main()
{
    std::unordered_map<std::string, std::string> myMap;

    print_result( myMap.insert_or_assign("a", "apple"     ) );
    print_result( myMap.insert_or_assign("b", "banana"    ) );
    print_result( myMap.insert_or_assign("c", "cherry"    ) );
    print_result( myMap.insert_or_assign("c", "clementine") );

    for (const auto &node : myMap) { print_node(node); }
}

可能的输出：

inserted: [a] = apple
inserted: [b] = banana
inserted: [c] = cherry
assigned: [c] = clementine
[c] = clementine
[a] = apple
[b] = banana

参阅

operator[] (C++11) | 访问或插入指定的元素 (公开成员函数)
at (C++11) | 访问指定的元素，同时进行越界检查 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)
emplace (C++11) | 原位构造元素 (公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::key_eq

< cpp‎ | container‎ | unordered map

key_equal key_eq() const; | (C++11 起)

返回比较关键相等性的函数。

参数

（无）

返回值

关键比较函数。

复杂度

常数。

参阅

hash_function
(C++11)
 返回用于对键散列的函数
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::load_factor

< cpp‎ | container‎ | unordered map

float load_factor() const; | (C++11 起)

返回每个桶元素的平均数，即 size() 除以 bucket_count() 。

参数

（无）

返回值

每个桶元素的平均数。

复杂度

常数。

参阅

max_load_factor
(C++11)
 管理每个桶的平均元素数量的最大值
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::max_bucket_count

< cpp‎ | container‎ | unordered map

size_type max_bucket_count() const; | (C++11 起)

返回容器由于系统或库实现限制的能保有的最大桶数。

参数

（无）

返回值

最大桶数。

复杂度

常数。

参阅

bucket_count
(C++11)
 返回桶数
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::max_load_factor

< cpp‎ | container‎ | unordered map

float max_load_factor() const; | (1) | (C++11 起)
void max_load_factor( float ml ); | (2) | (C++11 起)

管理最大加载因子（每个桶的平均元素数）。若加载因子超出此阈值，则容器自动增加桶数。

1) 返回最大加载因子。

2) 设置最大加载因子为 ml 。

参数

ml - 新设置的最大加载因子

返回值

1) 当前最大加载因子。

2) 无。

复杂度

常数

参阅

load_factor
(C++11)
 返回每个桶的平均元素数量
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::max_size

< cpp‎ | container‎ | unordered map

size_type max_size() const noexcept; | (C++11 起)

返回根据系统或库实现限制的容器可保有的元素最大数量，即对于最大容器的 std::distance (begin(), end()) 。

参数

（无）

返回值

元素数量的最大值。

复杂度

常数。

注解

此值通常反映容器大小上的理论极限，至多为 std::numeric_limits <difference_type>::max() 。运行时，可用 RAM 总量可能会限制容器大小到小于 max_size() 的值。

示例

#include <iostream>
#include <unordered_map>

int main()
{
    std::unordered_map<char,char> s;
    std::cout << "Maximum size of a 'unordered_map' is " << s.max_size() << "\n";
}

可能的输出：

Maximum size of a 'unordered_map' is 768614336404564650

参阅

size
(C++11)
 返回容纳的元素数
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::merge

< cpp‎ | container‎ | unordered map

template<class H2, class P2> void merge( std::unordered_map <Key, T, H2, P2, Allocator>& source ); | (1) | (C++17 起)
template<class H2, class P2> void merge( std::unordered_map <Key, T, H2, P2, Allocator>&& source ); | (2) | (C++17 起)
template<class H2, class P2> void merge( std::unordered_multimap <Key, T, H2, P2, Allocator>& source ); | (3) | (C++17 起)
template<class H2, class P2> void merge( std::unordered_multimap <Key, T, H2, P2, Allocator>&& source ); | (4) | (C++17 起)

试图提取（“接合”） source 中每个元素，并用 *this 的散列函数与键相等谓词插入到 *this 。 若 *this 中有元素，其键等价于来自 source 中元素的键，则不从 source 提取该元素。 不复制或移动元素，只会重指向容器结点的内部指针。指向被转移元素的所有指针和引用保持合法，但现在指代到 *this 中而非到 source 中。指代被转移元素的迭代器和所有指代到 *this 的迭代器被非法化。指向留在 source 中元素的迭代器保持合法。

若 get_allocator() != source.get_allocator() 则行为未定义。

参数

source - 传递结点来源的兼容容器

返回值

（无）

复杂度

平均情况 O(N) ，最坏情况 O(N*size()+N) ，其中 N 为 source.size() 。

示例

#include <iostream>
#include <string>
#include <utility>
#include <unordered_map>

// 打印出 std::pair
template <class Os, class U, class V>
Os& operator<<(Os& os, const std::pair<U,V>& p) {
    return os << '{' << p.first << ", " << p.second << '}';
}

// 打印出关联容器
template <class Os, class K, class V>
Os& operator<<(Os& os, const std::unordered_map<K, V>& v) {
    os << '[' << v.size() << "] { ";
    bool o{};
    for (const auto& e : v)
        os << (o ? ", " : (o = 1, "")) << e;
    return os << " }\n";
}

int main()
{
    std::unordered_map<std::string, int>
        p{ {"C", 3}, {"B", 2}, {"A", 1}, {"A", 0} },
        q{ {"E", 6}, {"E", 7}, {"D", 5}, {"A", 4} };

    std::cout << "p: " << p << "q: " << q;

    p.merge(q);

    std::cout << "p.merge(q);\n" << "p: " << p << "q: " << q;
}

可能的输出：

p: [3] { {A, 1}, {B, 2}, {C, 3} }
q: [3] { {A, 4}, {D, 5}, {E, 6} }
p.merge(q);
p: [5] { {E, 6}, {D, 5}, {A, 1}, {B, 2}, {C, 3} }
q: [1] { {A, 4} }

参阅

extract (C++17) | 从另一容器释出结点 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::operator=

< cpp‎ | container‎ | unordered map

unordered_map& operator=( const unordered_map& other ); | (1) | (C++11 起)
 | (2) |
unordered_map& operator=( unordered_map&& other ); |  |  | (C++11 起) (C++17 前)
unordered_map& operator=( unordered_map&& other ) noexcept(/* see below */); |  |  | (C++17 起)
unordered_map& operator=( std::initializer_list <value_type> ilist ); | (3) | (C++11 起)

替换容器内容。

1) 复制赋值运算符。以 other 的副本替换内容。
若 std::allocator_traits <allocator_type>::propagate_on_container_copy_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若 *this 的分配器在赋值后将与其旧值比较不相等，则用旧分配器解分配内存，然后在复制元素前用新分配器分配内存。否则，在可行时可能复用 *this 所拥有的内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素复制赋值替换。
2) 移动赋值运算符。用移动语义以 other 的内容替换内容（即从 other 移动 other 中的数据到此容器中）。之后 other 在合法但未指定的状态。
若 std::allocator_traits <allocator_type>::propagate_on_container_move_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若它为 false 且 *this 与 other 的分配器不比较相等，则 *this 不能接管 other 所拥有的内存的所有权且必须单独地移动赋值每个元素，并用其自身的分配器按需分配额外内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素移动赋值替换。
3) 以 initializer_list ilist 所标识者替换内容。

参数

other | - | 用作数据源的另一容器
ilist | - | 用作数据源的 initializer_list

返回值

*this

复杂度

1) 与 *this 和 other 的大小成线性。
2) 与 *this 的大小成线性，除非分配器不比较相等且不传播，该情况下与 *this 和 other 的大小成线性。
3) 与 *this 和 ilist 的大小成线性。

异常

可能抛出实现定义的异常。

 (C++17 前)
1,3) 可能抛出实现定义的异常。
2)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value

&& std::is_nothrow_move_assignable <Hash>::value

&& std::is_nothrow_move_assignable <Pred>::value)
 (C++17 起)

注解

在容器移动赋值（重载 (2) ）后，除非不兼容的分配器强制逐元素移动赋值，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

下列代码用 operator= 赋值一个 std::unordered_map 给另一个：

#include <unordered_map>
#include <iostream>

void display_sizes(const std::unordered_map<int, int> &nums1,
                   const std::unordered_map<int, int> &nums2,
                   const std::unordered_map<int, int> &nums3)
{
    std::cout << "nums1: " << nums1.size()
              << " nums2: " << nums2.size()
              << " nums3: " << nums3.size() << '\n';
}

int main()
{
    std::unordered_map<int, int> nums1 {{3, 1}, {4, 1}, {5, 9},
                                        {6, 1}, {7, 1}, {8, 9}};
    std::unordered_map<int, int> nums2;
    std::unordered_map<int, int> nums3;

    std::cout << "Initially:\n";
    display_sizes(nums1, nums2, nums3);

    // 复制赋值从 nums1 复制数据到 nums2
    nums2 = nums1;

    std::cout << "After assigment:\n";
    display_sizes(nums1, nums2, nums3);

    // 移动赋值从 nums1 移动数据到 nums3,
    // 一同修改 nums1 和 nums3
    nums3 = std::move(nums1);

    std::cout << "After move assigment:\n";
    display_sizes(nums1, nums2, nums3);
}

输出：

Initially:
nums1: 6 nums2: 0 nums3: 0
After assigment:
nums1: 6 nums2: 6 nums3: 0
After move assigment:
nums1: 0 nums2: 6 nums3: 6

参阅

(构造函数)
(C++11)
 构造 unordered_map
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::operator[]

< cpp‎ | container‎ | unordered map

T& operator[]( const Key& key ); | (1) | (C++11 起)
T& operator[]( Key&& key ); | (2) | (C++11 起)

返回到映射到等于 key 的键的值的引用，若这种键不存在则进行插入。

1) 若键不存在，则插入从 std::piecewise_construct, std::forward_as_tuple (key), std::tuple <>() 原位构造的 value_type 对象。此函数等价于 return this->try_emplace(key).first->second; 。 (C++17 起)
使用默认分配器时，这导致从 key 复制构造关键，并值初始化被映射值。
-
value_type 必须从 std::piecewise_construct, std::forward_as_tuple (key), std::tuple <>() 可就位构造 (EmplaceConstructible) 。使用默认分配器时，这表明 key_type 必须可复制构造 (CopyConstructible) 而 mapped_type 必须可默认构造 (DefaultConstructible) 。
2) 若键不存在，则插入从 std::piecewise_construct, std::forward_as_tuple (std::move(key)), std::tuple <>() 原位构造的 value_type 对象。此函数等价于 return this->try_emplace(std::move(key)).first->second; 。 (C++17 起)
使用默认分配器时，这导致从 key 移动构造关键，并值初始化被映射值。
-
value_type 必须从 std::piecewise_construct, std::forward_as_tuple (std::move(key)), std::tuple <>() 可就位构造 (EmplaceConstructible) 。使用默认分配器时，这表明 key_type 必须为可移动构造 (MoveConstructible) 而 mapped_type 必须为可默认构造 (DefaultConstructible) 。

若插入发生且导致容器的重哈希，则所有迭代器被非法化。否则迭代器不受影响。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。

参数

key - 要寻找的元素键

返回值

若不存在拥有关键 key 的元素，则为到新元素被映射值的引用。否则为到既存的关键等价于 key 的元素的被映射值的引用。

异常

若任何操作抛出异常，则插入无效果。

复杂度

平均情况：常数，最坏情况：与大小成线性。

注解

出版的 C++11 和 C++14 标准中，指定此函数要求 mapped_type 为可默认插入 (DefaultInsertable) 且 key_type 为可复制插入 (CopyInsertable) 或可移动插入 (MoveInsertable) 到 *this 。此规定有缺陷并为 LWG 问题 2469 所修复，而上面的描述合并了该问题的解决方案。

然而，已知一个实现（ libc++ ）通过二个分离的分配器 construct() 调用构造 key_type 和 mapped_type 对象，可认为如发布时的标准所要求，而非原位构造 value_type 对象。

operator[] 非 const ，因为若不关键不存在则它插入关键。若此行为非所欲或容器为 const ，则可用 at() 。

insert_or_assign() 返回的信息多于 operator[] ，而且不要求 mapped_type 可默认构造。

 (C++17 起)

示例

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>

int main()
{
    std::unordered_map<char, int> letter_counts {{'a', 27}, {'b', 3}, {'c', 1}};

    std::cout << "initially:\n";
    for (const auto &pair : letter_counts) {
        std::cout << pair.first << ": " << pair.second << '\n';
    }

    letter_counts['b'] = 42;  // 更新既存值
    letter_counts['x'] = 9;  // 插入新值

    std::cout << "after modifications:\n";
    for (const auto &pair : letter_counts) {
        std::cout << pair.first << ": " << pair.second << '\n';
    }

    // 统计每个词的出现数
    // （首次调用 operator[] 以零初始化计数器）
    std::unordered_map<std::string, size_t>  word_map;
    for (const auto &w : { "this", "sentence", "is", "not", "a", "sentence",
                           "this", "sentence", "is", "a", "hoax"}) {
        ++word_map[w];
    }

    for (const auto &pair : word_map) {
        std::cout << pair.second << " occurrences of word '" << pair.first << "'\n";
    }
}

可能的输出：

initially:
a: 27
b: 3
c: 1
after modifications:
a: 27
b: 42
c: 1
x: 9
2 occurrences of word 'a'
1 occurrences of word 'hoax'
2 occurrences of word 'is'
1 occurrences of word 'not'
3 occurrences of word 'sentence'
2 occurrences of word 'this'

参阅

at (C++11) | 访问指定的元素，同时进行越界检查 (公开成员函数)
insert_or_assign (C++17) | 插入元素，或若键已存在则赋值给当前元素 (公开成员函数)
try_emplace (C++17) | 若键不存在则原位插入，若键存在则不做任何事 (公开成员函数)


operator==,!=(std::unordered_map)

< cpp‎ | container‎ | unordered map

template< class Key, class T, class Hash, class KeyEqual, class Allocator >

bool operator==( const std::unordered_map <Key,T,Hash,KeyEqual,Allocator>& lhs,

const std::unordered_map <Key,T,Hash,KeyEqual,Allocator>& rhs );
 (1)
template< class Key, class T, class Hash, class KeyEqual, class Allocator >

bool operator!=( const std::unordered_map <Key,T,Hash,KeyEqual,Allocator>& lhs,

const std::unordered_map <Key,T,Hash,KeyEqual,Allocator>& rhs );
 (2) (C++20 前)

比较二个无序容器的内容。

若下列条件成立则二个无序容器 lhs 与 rhs 相等：

  • lhs.size() == rhs.size()
  • 从 lhs.equal_range(lhs_eq1) 获得的每组等价元素 [lhs_eq1, lhs_eq2) 拥有在另一容器中从 rhs.equal_range(rhs_eq1) 获得的对应等价元素组 [rhs_eq1, rhs_eq2) ，且它们拥有下列属性：
  • std::distance (lhs_eq1, lhs_eq2) == std::distance (rhs_eq1, rhs_eq2) 。
  • std::is_permutation (lhs_eq1, lhs_eq2, rhs_eq1) == true 。

若 Key 或 T 非可相等比较 (EqualityComparable) 则行为未定义。

若 hash_function() 和 key_eq() (C++20 前)key_eq() (C++20 起) 在 lhs 和 rhs 上拥有不相同的行为，或若 Key 的 operator== 不是对于 key_eq() 所引入的等价关键组的细分（即若用 operator== 比较相等的二个元素落入不同划分），则行为未定义。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的无序容器

返回值

1) 若容器内容相等则为 true ，否则为 false 。
2) 若容器内容不相等则为 true ，否则为 false 。

复杂度

调用 value_type 上的 operator== 、调用 key_eq 所返回的谓词，及调用 hash_function 所返回的哈希器的次数，平均情况下与 N 成正比，最坏情况下与 N2 成正比，其中 N 是容器大小。


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::rehash

< cpp‎ | container‎ | unordered map

void rehash( size_type count ); | (C++11 起)

设置桶数为 count 并重哈希容器，即考虑桶总数已改变，再把元素放到适当的桶中。若新的桶数使加载因子大于最大加载因子（ count < size() / max_load_factor() ），则新桶数至少为 size() / max_load_factor() 。

参数

count - 新的桶数

返回值

（无）

复杂度

平均与容器大小成线性，最坏情况成平方。

注意

rehash(0) 可用于强制无条件的重哈希，例如在通过临时增加 max_load_factor() 暂停自动重哈希之后。

参阅

reserve
(C++11)
 为至少为指定数量的元素预留存储空间并重新生成哈希表。
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::reserve

< cpp‎ | container‎ | unordered map

void reserve( size_type count ); | (C++11 起)

设置桶数为适应至少 count 个元素，而不超出最大加载因子所需的数，并重哈希容器，即考虑桶数已更改后将元素放进适合的桶。等效地调用 rehash( std::ceil (count / max_load_factor())) 。

参数

count - 容器的新容量

返回值

（无）

复杂度

平均情况与容器大小成线性，最坏情况成平方。

参阅

rehash
(C++11)
 为至少为指定数量的桶预留存储空间并重新生成散列表
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::size

< cpp‎ | container‎ | unordered map

size_type size() const noexcept; | (C++11 起)

返回容器中的元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

容器中的元素数量。

复杂度

常数。

示例

下列代码用 size 显示 std::unordered_map 中的元素数：

#include <unordered_map>
#include <iostream>

int main()
{
    std::unordered_map<int,char> nums {{1, 'a'}, {3, 'b'}, {5, 'c'}, {7, 'd'}};

    std::cout << "nums contains " << nums.size() << " elements.\n";
}

输出：

nums contains 4 elements.

参阅

empty (C++11) | 检查容器是否为空 (公开成员函数)
max_size (C++11) | 返回可容纳的最大元素数 (公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::swap

< cpp‎ | container‎ | unordered map

void swap( unordered_map& other ); | (C++11 起) (C++17 前)
void swap( unordered_map& other ) noexcept(/* see below */); | (C++17 起)

将内容与 other 的交换。不在单独的元素上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。尾后迭代器被非法化。

Hash 和 KeyEqual 对象必须可交换 (Swappable) ，并用非成员 swap 的非限定调用交换它们。

若 std::allocator_traits <allocator_type>::propagate_on_container_swap::value 为 true ，则用对非成员 swap 的无限定调用交换分配器。否则，不交换它们（且若 get_allocator() != other.get_allocator() ，则行为未定义）。

 (C++11 起)

参数

other - 要与之交换内容的容器

返回值

（无）

异常

任何 Hash 或 KeyEqual 对象交换所抛的异常。

 (C++17 前)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value

&& std::is_nothrow_swappable <Hash>::value

&& std::is_nothrow_swappable <key_equal>::value)
 (C++17 起)

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

std::swap(std::unordered_map)
(C++11)
 特化 std::swap 算法
(函数模板)


std::swap(std::unordered_map)

< cpp‎ | container‎ | unordered map

定义于头文件 <unordered_map>
template< class Key, class T, class Hash, class KeyEqual, class Alloc >

void swap( std::unordered_map <Key,T,Hash,KeyEqual,Alloc>& lhs,

std::unordered_map <Key,T,Hash,KeyEqual,Alloc>& rhs );
 (C++11 起)
(C++17 前)
template< class Key, class T, class Hash, class KeyEqual, class Alloc >

void swap( std::unordered_map <Key,T,Hash,KeyEqual,Alloc>& lhs,

std::unordered_map <Key,T,Hash,KeyEqual,Alloc>& rhs ) noexcept(/* see below */);
 (C++17 起)

为 std::unordered_map 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

#include <algorithm>
#include <iostream>
#include <unordered_map>

int main()
{
    std::unordered_map<int, char> alice{{1, 'a'}, {2, 'b'}, {3, 'c'}};
    std::unordered_map<int, char> bob{{7, 'Z'}, {8, 'Y'}, {9, 'X'}, {10, 'W'}};

    auto print = [](std::pair<const int, char>& n) {
        std::cout << " " << n.first << '(' << n.second << ')';
    };

    // 打印交换前的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';

    std::cout << "-- SWAP\n";
    std::swap(alice,bob);

    // 打印交换后的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
}

可能的输出：

alice: 1(a) 2(b) 3(c)
bob  : 7(Z) 8(Y) 9(X) 10(W)
-- SWAP
alice: 7(Z) 8(Y) 9(X) 10(W)
bob  : 1(a) 2(b) 3(c)

参阅

swap
(C++11)
 交换内容
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::try_emplace

< cpp‎ | container‎ | unordered map

template <class... Args> pair<iterator, bool> try_emplace(const key_type& k, Args&&... args); | (1) | (C++17 起)
template <class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); | (2) | (C++17 起)
template <class... Args> iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); | (3) | (C++17 起)
template <class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); | (4) | (C++17 起)
1) 若容器中已存在等价于 k 的关键，则不做任何事。否则行为类似 emplace ，除了以 value_type(std::piecewise_construct, std::forward_as_tuple(k), std::forward_as_tuple(std::forward<Args>(args)...)) 构造元素
2) 若容器中已存在等价于 k 的关键，则不做任何事。否则行为类似 emplace ，除了以 value_type(std::piecewise_construct, std::forward_as_tuple(std::move(k)), std::forward_as_tuple(std::forward<Args>(args)...)) 构造元素
3) 若容器中已存在等价于 k 的关键，则不做任何事。否则行为类似 emplace_hint ，除了以 value_type(std::piecewise_construct, std::forward_as_tuple(k), std::forward_as_tuple(std::forward<Args>(args)...)) 构造元素
4) 若容器中已存在等价于 k 的关键，则不做任何事。否则行为类似 emplace_hint ，除了以 value_type(std::piecewise_construct, std::forward_as_tuple(std::move(k)), std::forward_as_tuple(std::forward<Args>(args)...)) 构造元素

若因插入发生重哈希，则所有迭代器都被非法化。否则迭代器不受影响。引用不被非法化。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。

参数

k | - | 用于查找和若找不到则插入的关键
hint | - | 指向位置的迭代器，新元素将插入到其前
args | - | 转发给元素构造函数的参数

返回值

1,2) 同 emplace
3,4) 同 emplace_hint

复杂度

1,2) 同 emplace
3,4) 同 emplace_hint

注意

不同于 insert 或 emplace ，若不发生插入，则这些函数不从右值参数移动，这令操纵 value 为仅移动类型的 map ，如 std::unordered_map<std::string, std::unique_ptr<foo>> 更为容易。另外， try_emplace 分离地处理关键和到 mapped_type 的参数，不同于要求参数构造 value_type （即一个 std::pair ）的 emplace 。

示例

#include <iostream>
#include <utility>
#include <string>

#include <unordered_map>
int main()
{
    using namespace std::literals;
    std::unordered_map<std::string, std::string> m;

    m.try_emplace("a", "a"s);
    m.try_emplace("b", "abcd");
    m.try_emplace("c", 10, 'c');
    m.try_emplace("c", "Won't be inserted");

    for (const auto &p : m) {
        std::cout << p.first << " => " << p.second << '\n';
    }
}

可能的输出：

a => a
b => abcd
c => cccccccccc

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::unordered_map

< cpp‎ | container‎ | unordered map

unordered_map() : unordered_map( size_type(/*implementation-defined*/) ) {}

explicit unordered_map( size_type bucket_count,
const Hash& hash = Hash(),
const key_equal& equal = key_equal(),

const Allocator& alloc = Allocator() );
 (1) (C++11 起)
unordered_map( size_type bucket_count,

const Allocator& alloc )
: unordered_map(bucket_count, Hash(), key_equal(), alloc) {}
unordered_map( size_type bucket_count,
const Hash& hash,
const Allocator& alloc )

: unordered_map(bucket_count, hash, key_equal(), alloc) {}
 (1) (C++14 起)
explicit unordered_map( const Allocator& alloc );
 (1) (C++11 起)
template< class InputIt >

unordered_map( InputIt first, InputIt last,
size_type bucket_count = /*implementation-defined*/,
const Hash& hash = Hash(),
const key_equal& equal = key_equal(),

const Allocator& alloc = Allocator() );
 (2) (C++11 起)
template< class InputIt >

unordered_map( InputIt first, InputIt last,
size_type bucket_count,
const Allocator& alloc )
: unordered_map(first, last,

bucket_count, Hash(), key_equal(), alloc) {}
 (2) (C++14 起)
template< class InputIt >

unordered_map( InputIt first, InputIt last,
size_type bucket_count,
const Hash& hash,
const Allocator& alloc )
: unordered_map(first, last,

bucket_count, hash, key_equal(), alloc) {}
 (2) (C++14 起)
unordered_map( const unordered_map& other );
 (3) (C++11 起)
unordered_map( const unordered_map& other, const Allocator& alloc );
 (3) (C++11 起)
unordered_map( unordered_map&& other );
 (4) (C++11 起)
unordered_map( unordered_map&& other, const Allocator& alloc );
 (4) (C++11 起)
unordered_map( std::initializer_list <value_type> init,

size_type bucket_count = /*implementation-defined*/,
const Hash& hash = Hash(),
const key_equal& equal = key_equal(),

const Allocator& alloc = Allocator() );
 (5) (C++11 起)
unordered_map( std::initializer_list <value_type> init,

size_type bucket_count,
const Allocator& alloc )
: unordered_map(init, bucket_count,

Hash(), key_equal(), alloc) {}
 (5) (C++14 起)
unordered_map( std::initializer_list <value_type> init,

size_type bucket_count,
const Hash& hash,
const Allocator& alloc )
: unordered_map(init, bucket_count,

hash, key_equal(), alloc) {}
 (5) (C++14 起)

从各种数据源构造新容器。可选的以用户提供的 bucket_count 为用于创建的最小桶数，以 hash 为哈希函数，以 equal 为比较关键的函数，和以 alloc 为分配器。

1) 构造空容器。设置 max_load_factor() 为 1.0 。对于默认构造函数，桶数是实现定义的。
2) 构造拥有范围 [first, last) 的内容的容器。设置 max_load_factor() 为 1.0 。若范围中的多个元素拥有比较等价的关键，则插入哪个元素是未指定的（待决的 LWG2844 ）。
3) 复制构造函数。构造拥有 other 内容副本的容器，一同复制加载因子、谓词和哈希函数。若不提供 alloc ，则通过调用 std::allocator_traits <allocator_type>::select_on_container_copy_construction(other.get_allocator()) 获得分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
4) 移动构造函数。用移动语义构造拥有 other 内容的容器。若不提供 alloc ，则通过从属于 other 的分配器移动构造获得分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
5) 构造拥有 initializer_list init 内容的容器，同 unordered_map(init.begin(), init.end()) 。

参数

alloc | - | 用于此容器所有内存分配器的分配器
bucket_count | - | 初始化时用的最小桶数。若不指定，则使用实现定义的默认值
hash | - | 要用的哈希函数
equal | - | 用于此容器所有关键比较的比较函数
first, last | - | 复制元素来源的范围
other | - | 用作源以初始化容器元素的另一容器
init | - | 用以初始化容器元素的 initializer_list
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

复杂度

1) 常数
2) 平均情况与 first 和 last 间的距离成线性，最坏情况成平方。
3) 与 other 的大小成线性。
4) 常数。若给定 alloc 且 alloc != other.get_allocator() 则为线性。
5) 平均情况与 init 的大小成线性，最坏情况成平方。

异常

对 Allocator::allocate 的调用可能抛出。

注解

在容器移动构造（重载 (4) ）后，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

尽管在 C++23 前未正式要求，一些实现已经在较早的模式中将 Allocator 放入非推导语境。

示例

#include <unordered_map>
#include <vector>
#include <bitset>
#include <string>
#include <utility>

struct Key {
    std::string first;
    std::string second;
};

struct KeyHash {
 std::size_t operator()(const Key& k) const
 {
     return std::hash<std::string>()(k.first) ^
            (std::hash<std::string>()(k.second) << 1);
 }
};

struct KeyEqual {
 bool operator()(const Key& lhs, const Key& rhs) const
 {
    return lhs.first == rhs.first && lhs.second == rhs.second;
 }
};

struct Foo {
    Foo(int val_) : val(val_) {}
    int val;
    bool operator==(const Foo &rhs) const { return val == rhs.val; }
};

namespace std {
    template<> struct hash<Foo> {
        std::size_t operator()(const Foo &f) const {
            return std::hash<int>{}(f.val);
        }
    };
}

int main()
{
    // 默认构造函数：空 unordered_map
    std::unordered_map<std::string, std::string> m1;

    // 列表构造函数
    std::unordered_map<int, std::string> m2 =
    {
        {1, "foo"},
        {3, "bar"},
        {2, "baz"},
    };

    // 复制构造函数
    std::unordered_map<int, std::string> m3 = m2;

    // 移动构造函数
    std::unordered_map<int, std::string> m4 = std::move(m2);

    // 范围构造函数
    std::vector<std::pair<std::bitset<8>, int>> v = { {0x12, 1}, {0x01,-1} };
    std::unordered_map<std::bitset<8>, double> m5(v.begin(), v.end());

    // 带定制 Key 类型的构造函数的选项 1
    // 定义 KeyHash 与 KeyEqual 结构体并在模板中使用它们
    std::unordered_map<Key, std::string, KeyHash, KeyEqual> m6 = {
            { {"John", "Doe"}, "example"},
            { {"Mary", "Sue"}, "another"}
    };

    // 带定制 Key 类型的构造函数的选项 2
    // 为 class/struct 定义 const == 运算符并于 std 命名空间特化 std::hash 结构体
    std::unordered_map<Foo, std::string> m7 = {
        { Foo(1), "One"}, { 2, "Two"}, { 3, "Three"}
    };

    // 选项 3 ：用 lambdas
    // 注意必须将初始桶数传递给构造函数
    struct Goo {int val; };
    auto hash = [](const Goo &g){ return std::hash<int>{}(g.val); };
    auto comp = [](const Goo &l, const Goo &r){ return l.val == r.val; };
    std::unordered_map<Goo, double, decltype(hash), decltype(comp)> m8(10, hash, comp);
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2193 | C++11 | 默认构造函数为 explicit | 使之为非 explicit

参阅

operator=
(C++11)
 赋值给容器
(公开成员函数)


std::unordered_map<Key,T,Hash,KeyEqual,Allocator>::~unordered_map

< cpp‎ | container‎ | unordered map

~unordered_map(); | (C++11 起)

销毁 unordered_map 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 unordered_map 大小成线性。


std::unordered_multimap

< cpp‎ | container
定义于头文件 <unordered_map>
template<

class Key,
class T,
class Hash = std::hash <Key>,
class KeyEqual = std::equal_to <Key>,
class Allocator = std::allocator < std::pair <const Key, T> >

> class unordered_multimap;
 (1) (C++11 起)
namespace pmr {

template <class Key, class T,
class Hash = std::hash <Key>,
class Pred = std::equal_to <Key>>
using unordered_multimap = std::unordered_multimap<Key, T, Hash, Pred,
std::pmr::polymorphic_allocator < std::pair <const Key,T>>>;

}
 (2) (C++17 起)

unordered_multimap 是无序关联容器，支持等价的关键（一个 unordered_multimap 可含有每个关键值的多个副本）和将关键与另一类型的值关联。 unordered_multimap 类支持向前迭代器。搜索、插入和移除拥有平均常数时间复杂度。

元素在内部不以任何特定顺序排序，而是组织到桶中。元素被放进哪个桶完全依赖于其关键的哈希。这允许到单独元素的快速访问，因为哈希一旦计算，则它指代元素被放进的准确的桶。

不要求此容器的迭代顺序稳定（故例如 std::equal 不能用于比较二个 std::unordered_multimap ），除了关键比较等价（以 key_eq() 为比较器比较相等）的每组元素在迭代顺序中组成相接的子范围，它亦可用 equal_range() 访问。

std::unordered_multimap 满足容器 (Container) 、知分配器容器 (AllocatorAwareContainer) 、无序关联容器 (UnorderedAssociativeContainer) 的要求。

成员类型

成员类型 | 定义
key_type | Key
mapped_type | T
value_type | std::pair <const Key, T>
size_type | 无符号整数类型（通常是 std::size_t ）
difference_type | 有符号整数类型（通常是 std::ptrdiff_t ）
hasher | Hash
key_equal | KeyEqual
allocator_type | Allocator
reference | value_type&
const_reference | const value_type&
pointer | std::allocator_traits <Allocator>::pointer
const_pointer | std::allocator_traits <Allocator>::const_pointer
iterator | 指向 value_type 的常老式向前迭代器 (LegacyForwardIterator)
const_iterator | 指向 const value_type 的老式向前迭代器 (LegacyForwardIterator)
local_iterator | 类别、值、差、指针和引用类型都与 iterator 相同的迭代器类型。 能用此迭代器在单个桶迭代，但不能跨桶。
const_local_iterator | 类别、值、差、指针和引用类型都与 const_iterator 相同的迭代器类型。 能用此迭代器在单个桶迭代，但不能跨桶。
node_type(C++17 起) | 表示容器结点的结点把柄特化

成员函数

(构造函数)
(C++11)
 构造 unordered_multimap
(公开成员函数)
(析构函数)
(C++11)
 析构 unordered_multimap
(公开成员函数)
operator=
(C++11)
 赋值给容器
(公开成员函数)
get_allocator
(C++11)
 返回相关的分配器
(公开成员函数)
迭代器
begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)
容器
empty
(C++11)
 检查容器是否为空
(公开成员函数)
size
(C++11)
 返回容纳的元素数
(公开成员函数)
max_size
(C++11)
 返回可容纳的最大元素数
(公开成员函数)
修改器
clear
(C++11)
 清除内容
(公开成员函数)
insert
(C++11)
 插入元素或结点 (C++17 起)
(公开成员函数)
emplace
(C++11)
 原位构造元素
(公开成员函数)
emplace_hint
(C++11)
 使用提示原位构造元素
(公开成员函数)
erase
(C++11)
 擦除元素
(公开成员函数)
swap
(C++11)
 交换内容
(公开成员函数)
extract
(C++17)
 从另一容器释出结点
(公开成员函数)
merge
(C++17)
 从另一容器接合结点
(公开成员函数)
查找
count
(C++11)
 返回匹配特定键的元素数量
(公开成员函数)
find
(C++11)
 寻找带有特定键的元素
(公开成员函数)
contains
(C++20)
 检查容器是否含有带特定键的元素
(公开成员函数)
equal_range
(C++11)
 返回匹配特定键的元素范围
(公开成员函数)
桶接口
begin(size_type) cbegin(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的开始
(公开成员函数)
end(size_type) cend(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的末尾
(公开成员函数)
bucket_count
(C++11)
 返回桶数
(公开成员函数)
max_bucket_count
(C++11)
 返回桶的最大数量
(公开成员函数)
bucket_size
(C++11)
 返回在特定的桶中的元素数量
(公开成员函数)
bucket
(C++11)
 返回带有特定键的桶
(公开成员函数)
哈希策略
load_factor
(C++11)
 返回每个桶的平均元素数量
(公开成员函数)
max_load_factor
(C++11)
 管理每个桶的平均元素数量的最大值
(公开成员函数)
rehash
(C++11)
 为至少为指定数量的桶预留存储空间并重新生成散列表
(公开成员函数)
reserve
(C++11)
 为至少为指定数量的元素预留存储空间并重新生成哈希表。
(公开成员函数)
观察器
hash_function
(C++11)
 返回用于对键散列的函数
(公开成员函数)
key_eq
(C++11)
 返回用于比较键的相等性的函数
(公开成员函数)

非成员函数

operator==operator!= (C++20 中移除) | 比较 unordered_multimap 中的值 (函数模板)
std::swap(std::unordered_multimap) (C++11) | 特化 std::swap 算法 (函数模板)
erase_if(std::unordered_multimap) (C++20) | 擦除所有满足特定判别标准的元素 (函数模板)

推导指引 (C++17 起)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::begin, std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::cbegin

< cpp‎ | container‎ | unordered multimap

iterator begin() noexcept; | (C++11 起)
const_iterator begin() const noexcept; | (C++11 起)
const_iterator cbegin() const noexcept; | (C++11 起)

返回指向 unordered_multimap 首元素的迭代器。

若 unordered_multimap 为空，则返回的迭代器将等于 end() 。

参数

（无）

返回值

指向首元素的迭代器。

复杂度

常数。

示例

#include <unordered_map>
#include <algorithm>
#include <cassert>
#include <iostream>
#include <string>
#include <utility>

int main()
{
    auto show_node = [](const std::pair<std::string, std::string>& node) {
        std::cout << node.first << "  :  " << node.second << '\n';
    };

    std::unordered_multimap<std::string, std::string> lemmas;
    assert(lemmas.begin() == lemmas.end());   // OK
    assert(lemmas.cbegin() == lemmas.cend()); // OK

    lemmas.insert({ "1. ∀x ∈ N ∃y ∈ N", "x ≤ y" });
    show_node(*lemmas.cbegin());
    assert(lemmas.begin() != lemmas.end());   // OK
    assert(lemmas.cbegin() != lemmas.cend()); // OK
    lemmas.begin()->second = "x < y";
    show_node(*lemmas.cbegin());

    lemmas.insert({ "2. ∀x,y ∈ N", "x = y V x ≠ y" });
    show_node(*lemmas.cbegin());

    lemmas.insert({ "3. ∀x ∈ N ∃y ∈ N", "y = x + 1" });
    show_node(*lemmas.cbegin());

    std::cout << "lemmas: \n";
    std::for_each(lemmas.cbegin(), lemmas.cend(),
        [&](const auto& n) { show_node(n); });
    std::cout << "\n";
}

可能的输出：

1. ∀x ∈ N ∃y ∈ N  :  x ≤ y
1. ∀x ∈ N ∃y ∈ N  :  x < y
2. ∀x,y ∈ N  :  x = y V x ≠ y
3. ∀x ∈ N ∃y ∈ N  :  y = x + 1
lemmas:
3. ∀x ∈ N ∃y ∈ N  :  y = x + 1
1. ∀x ∈ N ∃y ∈ N  :  x < y
2. ∀x,y ∈ N  :  x = y V x ≠ y

参阅

end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::begin(size_type), std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::cbegin(size_type)

< cpp‎ | container‎ | unordered multimap

local_iterator begin( size_type n ); | (C++11 起)
const_local_iterator begin( size_type n ) const; | (C++11 起)
const_local_iterator cbegin( size_type n ) const; | (C++11 起)

返回指向下标为 n 的桶首元素的迭代器。

参数

n - 要访问的桶的下标

返回值

指向首元素的迭代器。

复杂度

常数。

参阅

end(size_type) cend(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的末尾
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::bucket

< cpp‎ | container‎ | unordered multimap

size_type bucket( const Key& key ) const; | (C++11 起)

返回关键 key 的桶的下标。始终会在此桶中找到关键等于 key 的元素（若存在）。返回值仅对 bucket_count() 返回相同值的容器实例合法。

若 bucket_count() 为零则行为未定义。

参数

key - 要检验的关键值

返回值

关键 key 的桶编号。

复杂度

常数。

参阅

bucket_size
(C++11)
 返回在特定的桶中的元素数量
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::bucket_count

< cpp‎ | container‎ | unordered multimap

size_type bucket_count() const; | (C++11 起)

返回容器中的桶数。

参数

（无）

返回值

容器中的桶数。

复杂度

常数。

参阅

bucket_size (C++11) | 返回在特定的桶中的元素数量 (公开成员函数)
max_bucket_count (C++11) | 返回桶的最大数量 (公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::bucket_size

< cpp‎ | container‎ | unordered multimap

size_type bucket_size( size_type n ) const; | (C++11 起)

返回下标为 n 的桶中的元素数。

参数

n - 要检验的桶的下标

返回值

桶 n 中的元素数。

复杂度

与桶 n 的大小成线性。

参阅

bucket_count
(C++11)
 返回桶数
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::clear

< cpp‎ | container‎ | unordered multimap

void clear() noexcept; | (C++11 起)

从容器擦除所有元素。此调用后 size() 返回零。

非法化任何指代所含元素的引用、指针或迭代器。可能亦非法化尾后迭代器。

参数

（无）

返回值

（无）

复杂度

与容器大小，即元素数成线性。

示例

#include <algorithm>
#include <iostream>
#include <unordered_map>

int main()
{
    std::unordered_multimap<int, char> container{{1, 'x'}, {2, 'y'}, {3, 'z'}};

    auto print = [](std::pair<const int, char>& n) {
        std::cout << " " << n.first << '(' << n.second << ')';
    };

    std::cout << "Before clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';

    std::cout << "Clear\n";
    container.clear();

    std::cout << "After clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';
}

可能的输出：

Before clear: 1(x) 2(y) 3(z)
Size=3
Clear
After clear:
Size=0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2550 | C++11 | 对于无序关联容器，不清楚复杂度是与元素数还是桶数成线性 | 辨明它与元素数成线性

参阅

erase
(C++11)
 擦除元素
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::contains

< cpp‎ | container‎ | unordered multimap

bool contains( const Key& key ) const; | (1) | (C++20 起)
template< class K > bool contains( const K& x ) const; | (2) | (C++20 起)
1) 检查容器中是否有键等价于 key 的元素。
2) 检查是否有键比较等价于值 x 的元素。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 任何能通透地与键比较的类型的值

返回值

若有这种元素则为 true ，否则为 false 。

复杂度

平均为常数，最坏情况与容器大小成线性。

示例

#include <iostream>
#include <unordered_map>

int main()
{
    std::unordered_multimap<int,char> example = {{1,'a'},{2,'b'}};

    for(int x: {2, 5}) {
        if(example.contains(x)) {
            std::cout << x << ": Found\n";
        } else {
            std::cout << x << ": Not found\n";
        }
    }
}

输出：

2: Found
5: Not found

参阅

find (C++11) | 寻找带有特定键的元素 (公开成员函数)
count (C++11) | 返回匹配特定键的元素数量 (公开成员函数)
equal_range (C++11) | 返回匹配特定键的元素范围 (公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::count

< cpp‎ | container‎ | unordered multimap

size_type count( const Key& key ) const; | (1) | (C++11 起)
template< class K > size_type count( const K& x ) const; | (2) | (C++20 起)
1) 返回拥有比较等于指定参数 key 的关键的元素数。
2) 返回键比较等价于指定参数 x 的元素数。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要计量等价元素数的键值
x | - | 能通透地与键比较的任何类型值

返回值

1) 拥有关键 key 的元素数。
2) 键比较等价于 x 的元素数。

复杂度

平均与拥有关键 key 的元素数成线性，最坏情况与容器大小成线性。

参阅

find (C++11) | 寻找带有特定键的元素 (公开成员函数)
equal_range (C++11) | 返回匹配特定键的元素范围 (公开成员函数)


std::unordered_multimap 的推导指引

< cpp‎ | container‎ | unordered multimap

定义于头文件 <unordered_map>
template<class InputIt,

class Hash = std::hash <iter_key_t<InputIt>>,
class Pred = std::equal_to <iter_key_t<InputIt>>,
class Alloc = std::allocator <iter_to_alloc_t<InputIt>>>
unordered_multimap(InputIt, InputIt,
typename /*see below*/::size_type = /*see below*/,
Hash = Hash(), Pred = Pred(), Alloc = Alloc())

-> unordered_multimap<iter_key_t<InputIt>, iter_value_t<InputIt>, Hash, Pred, Alloc>;
 (1) (C++17 起)
template<class Key, class T, class Hash = std::hash <Key>,

class Pred = std::equal_to <Key>,
class Alloc = std::allocator < std::pair <const Key, T>>>
unordered_multimap( std::initializer_list < std::pair <const Key, T>>,
typename /*see below*/::size_type = /*see below*/,
Hash = Hash(), Pred = Pred(), Alloc = Alloc())

-> unordered_multimap<Key, T, Hash, Pred, Alloc>;
 (2) (C++17 起)
template<class InputIt, class Alloc>

unordered_multimap(InputIt, InputIt, typename /*see below*/::size_type, Alloc)
-> unordered_multimap<iter_key_t<InputIt>, iter_val_t<InputIt>,
std::hash <iter_key_t<InputIt>>,

std::equal_to <iter_key_t<InputIt>>, Alloc>;
 (3) (C++17 起)
template<class InputIt, class Alloc>

unordered_multimap(InputIt, InputIt, Alloc)
-> unordered_multimap<iter_key_t<InputIt>, iter_val_t<InputIt>,
std::hash <iter_key_t<InputIt>>,

std::equal_to <iter_key_t<InputIt>>, Alloc>;
 (4) (C++17 起)
template<class InputIt, class Hash, class Alloc>

unordered_multimap(InputIt, InputIt, typename /*see below*/::size_type, Hash, Alloc)
-> unordered_multimap<iter_key_t<InputIt>, iter_val_t<InputIt>, Hash,

std::equal_to <iter_key_t<InputIt>>, Alloc>;
 (5) (C++17 起)
template<class Key, class T, typename Alloc>

unordered_multimap( std::initializer_list < std::pair <const Key, T>>,
typename /*see below*/::size_type, Alloc)

-> unordered_multimap<Key, T, std::hash <Key>, std::equal_to <Key>, Alloc>;
 (6) (C++17 起)
template<class Key, class T, typename Alloc>

unordered_multimap( std::initializer_list < std::pair <const Key, T>>, Alloc)

-> unordered_multimap<Key, T, std::hash <Key>, std::equal_to <Key>, Alloc>;
 (7) (C++17 起)
template<class Key, class T, class Hash, class Alloc>

unordered_multimap( std::initializer_list < std::pair <const Key, T>>,
typename /*see below*/::size_type, Hash, Alloc)

-> unordered_multimap<Key, T, Hash, equal_to<Key>, Allocator>;
 (8) (C++17 起)

其中类型别名 iter_key_t 、 iter_val_t 、 iter_to_alloc_t 如同定义如下

template<class InputIt>

using iter_key_t = std::remove_const_t <

typename std::iterator_traits <InputIt>::value_type::first_type>;
 (仅为说明)
template<class InputIt>
using iter_val_t = typename std::iterator_traits <InputIt>::value_type::second_type;
 (仅为说明)
template<class InputIt>

using iter_to_alloc_t = std::pair <
std::add_const_t <typename std::iterator_traits <InputIt>::value_type::first_type>,
typename std::iterator_traits <InputIt>::value_type::second_type

>
 (仅为说明)

为 unordered_multimap 提供这些推导指引以允许从迭代器范围（重载 (1,3-5) ）和 std::initializer_list （重载 (2,6-8) ）推导。这些重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 、 Alloc 满足分配器 (Allocator) 、 Hash 或 Pred 均不满足分配器 (Allocator) 且 Hash 不是整数类型才参与重载决议。

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

这些指引中的 size_type 形参类型指代推导指引推导出的类型的 size_type 成员类型。

示例

#include <unordered_map>
int main() {
// std::unordered_multimap m1 = {{"foo", 1}, {"bar", 2}}; // 错误：花括号初始化器列表无类型
                                                          // 不能从 {"foo", 1} 或 {"bar", 2}
                                                          // 推导 pair<const Key, T>
   std::unordered_multimap m1 = std::initializer_list<
                        std::pair<char const* const, int>>({{"foo", 2}, {"bar", 3}}); // 指引 #2
   std::unordered_multimap m2(m1.begin(), m1.end()); // 指引 #1
}


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::emplace

< cpp‎ | container‎ | unordered multimap

template< class... Args > iterator emplace( Args&&... args ); | (C++11 起)

插入以给定的 args 原位构造的新元素到容器。

细心地使用 emplace 允许在构造新元素的同时避免不必要的复制或移动操作。 准确地以与提供给 emplace 者相同的参数，通过 std::forward <Args>(args)... 转发调用新元素（即 std::pair <const Key, T> ）的构造函数。

若因插入发生重哈希，则所有迭代器都被非法化。否则迭代器不受影响。引用不被非法化。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。

参数

args - 要转发给元素构造函数的参数

返回值

指向被插入元素的迭代器。

异常

若任何操作抛出异常，则此函数无效果。

复杂度

平均为均摊常数，最坏情况与容器大小成线性。

示例

#include <iostream>
#include <utility>
#include <string>
#include <unordered_map>

int main()
{
    std::unordered_multimap<std::string, std::string> m;

    // 使用 pair 的移动构造函数
    m.emplace(std::make_pair(std::string("a"), std::string("a")));

    // 使用 pair 的转换移动构造函数
    m.emplace(std::make_pair("b", "abcd"));

    // 使用 pair 的模板构造函数
    m.emplace("d", "ddd");

    // 使用 pair 的逐片构造函数
    m.emplace(std::piecewise_construct,
              std::forward_as_tuple("c"),
              std::forward_as_tuple(10, 'c'));

    for (const auto &p : m) {
        std::cout << p.first << " => " << p.second << '\n';
    }
}

可能的输出：

a => a
b => abcd
c => cccccccccc
d => ddd

参阅

emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::emplace_hint

< cpp‎ | container‎ | unordered multimap
template <class... Args> iterator emplace_hint( const_iterator hint, Args&&... args ); | (C++11 起)

插入新元素到容器，以 hint 为应当放置元素位置的建议。原位构造元素，即不进行复制或移动操作。

准确地与以提供给元素者相同的参数，以 std::forward <Args>(args)... 转发调用元素类型（ value_type 即 std::pair <const Key, T> ）的构造函数。

若因插入发生重哈希，则所有迭代器都被非法化。否则迭代器不受影响。引用不被非法化。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。

参数

hint | - | 迭代器，用作插入新元素位置的建议
args | - | 转发给元素构造函数的参数

返回值

返回指向新插入元素的迭代器。

异常

若任何操作抛出异常，则此函数无效果（强异常保证）。

复杂度

平均为均摊常数，最坏情况下与容器大小成线性。

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::empty

< cpp‎ | container‎ | unordered multimap

bool empty() const noexcept; | (C++11 起) (C++20 前)
[[nodiscard]] bool empty() const noexcept; | (C++20 起)

检查容器是否无元素，即是否 begin() == end() 。

参数

（无）

返回值

若容器为空则为 true ，否则为 false

复杂度

常数。

示例

下列代码用 empty 检查 std::unordered_multimap <int,int> 是否含有任何元素：

#include <unordered_map>
#include <iostream>
#include <utility>

int main()
{
    std::unordered_multimap<int, int> numbers;
    std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';

    numbers.emplace(42, 13);
    numbers.insert(std::make_pair(13317, 123));
    std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
}

输出：

Initially, numbers.empty(): 1
After adding elements, numbers.empty(): 0

参阅

size
(C++11)
 返回容纳的元素数
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::end, std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::cend

< cpp‎ | container‎ | unordered multimap

iterator end() noexcept; | (C++11 起)
const_iterator end() const noexcept; | (C++11 起)
const_iterator cend() const noexcept; | (C++11 起)

返回指向 unordered_multimap 末元素后一元素的迭代器。

此元素表现为占位符；试图访问它导致未定义行为。

参数

（无）

返回值

指向后随最后元素的迭代器。

复杂度

常数。

示例

#include <unordered_map>
#include <algorithm>
#include <cassert>
#include <iostream>
#include <string>
#include <utility>

int main()
{
    auto show_node = [](const std::pair<std::string, std::string>& node) {
        std::cout << node.first << "  :  " << node.second << '\n';
    };

    std::unordered_multimap<std::string, std::string> lemmas;
    assert(lemmas.begin() == lemmas.end());   // OK
    assert(lemmas.cbegin() == lemmas.cend()); // OK

    lemmas.insert({ "1. ∀x ∈ N ∃y ∈ N", "x ≤ y" });
    show_node(*lemmas.cbegin());
    assert(lemmas.begin() != lemmas.end());   // OK
    assert(lemmas.cbegin() != lemmas.cend()); // OK
    lemmas.begin()->second = "x < y";
    show_node(*lemmas.cbegin());

    lemmas.insert({ "2. ∀x,y ∈ N", "x = y V x ≠ y" });
    show_node(*lemmas.cbegin());

    lemmas.insert({ "3. ∀x ∈ N ∃y ∈ N", "y = x + 1" });
    show_node(*lemmas.cbegin());

    std::cout << "lemmas: \n";
    std::for_each(lemmas.cbegin(), lemmas.cend(),
        [&](const auto& n) { show_node(n); });
    std::cout << "\n";
}

可能的输出：

1. ∀x ∈ N ∃y ∈ N  :  x ≤ y
1. ∀x ∈ N ∃y ∈ N  :  x < y
2. ∀x,y ∈ N  :  x = y V x ≠ y
3. ∀x ∈ N ∃y ∈ N  :  y = x + 1
lemmas:
3. ∀x ∈ N ∃y ∈ N  :  y = x + 1
1. ∀x ∈ N ∃y ∈ N  :  x < y
2. ∀x,y ∈ N  :  x = y V x ≠ y

参阅

begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::end(size_type), std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::cend(size_type)

< cpp‎ | container‎ | unordered multimap

local_iterator end( size_type n ); | (C++11 起)
const_local_iterator end( size_type n ) const; | (C++11 起)
const_local_iterator cend( size_type n ) const; | (C++11 起)

返回后随下标为 n 的桶的最后元素的元素的迭代器。此元素表现为占位符，试图访问它会导致未定义行为。

参数

n - 要访问的桶的下标

返回值

指向后随最后元素的元素的迭代器。

复杂度

常数

参阅

begin(size_type) cbegin(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的开始
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::equal_range

< cpp‎ | container‎ | unordered multimap

std::pair <iterator,iterator> equal_range( const Key& key ); | (1) | (C++11 起)
std::pair <const_iterator,const_iterator> equal_range( const Key& key ) const; | (2) | (C++11 起)
template< class K > std::pair <iterator,iterator> equal_range( const K& x ); | (3) | (C++20 起)
template< class K > std::pair <const_iterator,const_iterator> equal_range( const K& x ) const; | (4) | (C++20 起)
1,2) 返回容器中所有键等于 key 的元素范围。范围以二个迭代器定义，第一个指向所需范围的首元素，而第二个指向范围的尾后一位元素。
3,4) 返回含有容器中所有键等价于 x 的元素的范围。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要与元素比较的键值
x | - | 任何能与键通透比较的类型的值

返回值

含一对定义所需范围的迭代器的 std::pair 。若无这种元素，则将尾后（见 end() ）迭代器作为 pair 的两个元素返回。

复杂度

平均情况与带关键 key 的元素数成线性，最坏情况与容器大小成线性。

示例

#include <iostream>
#include <unordered_map>

int main()
{
    std::unordered_multimap<int,char> map = {{1,'a'},{1,'b'},{1,'d'},{2,'b'}};
    auto range = map.equal_range(1);
    for (auto it = range.first; it != range.second; ++it) {
        std::cout << it->first << ' ' << it->second << '\n';
    }
}

输出：

1 a
1 b
1 d

参阅

find (C++11) | 寻找带有特定键的元素 (公开成员函数)
contains (C++20) | 检查容器是否含有带特定键的元素 (公开成员函数)
count (C++11) | 返回匹配特定键的元素数量 (公开成员函数)
equal_range | 返回匹配特定键值的元素范围 (函数模板)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::erase

< cpp‎ | container‎ | unordered multimap

 | (1) |
iterator erase( iterator pos ); |  |  | (C++11 起)
iterator erase( const_iterator pos ); |  |  | (C++11 起)
 | (2) |
iterator erase( const_iterator first, const_iterator last ); |  |  | (C++11 起)
size_type erase( const key_type& key ); | (3) | (C++11 起)
template< class K > size_type erase( K&& x ); | (4) | (C++23 起)

从容器移除指定的元素。

1) 移除位于 pos 的元素。
2) 移除范围 [first; last) 中的元素，它必须是 *this 中的合法范围。
3) 移除键等价于 key 的所有元素。
4) 移除键比较等价于值 x 的所有元素。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

到被擦除元素的引用和迭代器被非法化。其他迭代器和引用不被非法化。

迭代器 pos 必须合法且可解引用。从而 end() 迭代器（合法，但不可解引用）不能用作 pos 所用的值。 保留未被擦除的元素顺序（这使得可能在迭代通过容器时擦除单独的元素）。

参数

pos | - | 指向要移除的元素的迭代器
first, last | - | 要移除的元素范围
key | - | 要移除的元素键值
x | - | 任何能与键通透比较的类型的值，指代要移除的元素

返回值

1-2) 后随最后被移除的元素的迭代器。
3,4) 被移除的元素数。

异常

1,2) 不抛出
3,4) 任何 Hash 与 KeyEqual 对象所抛的异常

复杂度

给定 unordered_multimap 的实例 c ：

1) 平均情况：常数，最坏情况： c.size()
2) 平均情况： std::distance (first, last) ，最坏情况： c.size()
3) 平均情况： c.count(key) ，最坏情况： c.size()
4) 平均情况： c.count(x) ，最坏情况： c.size()

示例

#include <unordered_map>
#include <iostream>
int main()
{
    std::unordered_multimap<int, std::string> c = {
        {1, "one" }, {2, "two" }, {3, "three"},
        {4, "four"}, {5, "five"}, {6, "six"  }
    };

    // 从 c 擦除所有奇数
    for(auto it = c.begin(); it != c.end(); ) {
        if(it->first % 2 != 0)
            it = c.erase(it);
        else
            ++it;
    }

    for(auto& p : c) {
        std::cout << p.second << ' ';
    }
}

可能的输出：

two four six

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2059 | C++11 | 对一个 const_iterator 的重载引入了新的歧义 | 添加了对 iterator 的重载
LWG 2356 | C++11 | 未被擦除的元素顺序未指定 | 要求保留

参阅

clear
(C++11)
 清除内容
(公开成员函数)


std::erase_if (std::unordered_multimap)

< cpp‎ | container‎ | unordered multimap

定义于头文件 <unordered_map>
template< class Key, class T, class Hash, class KeyEqual, class Alloc, class Pred >

typename std::unordered_multimap <Key,T,Hash,KeyEqual,Alloc>::size_type

erase_if( std::unordered_multimap <Key,T,Hash,KeyEqual,Alloc>& c, Pred pred);
 (C++20 起)

从容器中擦除所有满足谓词 pred 的元素。等价于

auto old_size = c.size();
for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}
return old_size - c.size();

参数

c | - | 要从中擦除的元素
pred | - | 若应该擦除元素则对它返回 true 的谓词

返回值

擦除的元素数。

复杂度

线性。

示例

#include <unordered_map>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& cont)
{
    os << "{";
    for (const auto& item : cont) {
        os << "{" << item.first << ", " << item.second << "}";
    }
    return os << "}";
}

int main()
{
    std::unordered_multimap<int, char> data {{1, 'a'},{2, 'b'},{3, 'c'},{4, 'd'},
                                             {5, 'e'},{4, 'f'},{5, 'g'},{5, 'g'}};
    std::cout << "Original:\n" << data << '\n';

    const auto count = std::erase_if(data, [](const auto& item) {
        auto const& [key, value] = item;
        return (key & 1) == 1;
    });

    std::cout << "Erase items with odd keys:\n" << data << '\n'
              << count << " items removed.\n";
}

输出：

Original:
{{5, g}{5, g}{5, e}{4, f}{4, d}{3, c}{2, b}{1, a}}
Erase items with odd keys:
{{4, f}{4, d}{2, b}}
5 items removed.

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::extract

< cpp‎ | container‎ | unordered multimap

node_type extract( const_iterator position ); | (1) | (C++17 起)
node_type extract( const key_type& k ); | (2) | (C++17 起)
template< class K > node_type extract( K&& x ); | (3) | (C++23 起)
1) 解链含 position 所指向元素的结点并返回占有它的结点柄。
2) 若容器拥有元素而其关键等于 x ，则从容器解链首个这种元素并返回占有它的结点柄。否则，返回空结点柄。
3) 同 (2) 。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

任何情况下，均不复制或移动元素，只重指向容器结点的内部指针。

释出结点只会非法化指向被释出元素的迭代器，并保持未被擦除元素的相对顺序。指向被释出元素的指针和引用保持合法，但在结点柄占有该元素时不能使用：若元素被插入容器，就能使用它们。

参数

position | - | 指向此容器中的合法迭代器
k | - | 鉴别要被释出的结点的键
x | - | 任何能与键通透比较的类型的值，鉴别要释出的结点

返回值

占有被释出元素的结点柄，或 (2,3) 中找不到元素的情况下为空结点柄。

复杂度

1,2,3) 平均情况 O(1) ，最坏情况 O(a.size()) 。

注解

extract 是更换 map 的键而不重分配的唯一方式：

map<int, string> m{{1, "mango"}, {2, "papaya"}, {3, "guava"}};
auto nh = m.extract(2);
nh.key() = 4;
m.insert(move(nh));
// m == {{1, "mango"}, {3, "guava"}, {4, "papaya"}}

示例

#include <algorithm>
#include <iostream>
#include <unordered_map>

int main()
{
    std::unordered_multimap<int, char> cont{{1, 'a'}, {2, 'b'}, {3, 'c'}};

    auto print = [](std::pair<const int, char>& n) {
        std::cout << " " << n.first << '(' << n.second << ')';
    };

    std::cout << "Start:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 释出结点柄并更改键
    auto nh = cont.extract(1);
    nh.key() = 4;

    std::cout << "After extract and before insert:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 往回插入结点柄
    cont.insert(move(nh));

    std::cout << "End:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';
}

可能的输出：

Start: 1(a) 2(b) 3(c)
After extract and before insert: 2(b) 3(c)
End: 2(b) 3(c) 4(a)

参阅

merge (C++17) | 从另一容器接合结点 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)
erase (C++11) | 擦除元素 (公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::find

< cpp‎ | container‎ | unordered multimap

iterator find( const Key& key ); | (1) |
const_iterator find( const Key& key ) const; | (2) |
template< class K > iterator find( const K& x ); | (3) | (C++20 起)
template< class K > const_iterator find( const K& x ) const; | (4) | (C++20 起)
1,2) 寻找键等于 key 的的元素。
3,4) 寻找键比较等价于值 x 的元素。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 能通透地与键比较的任何类型值

返回值

指向键等于 key 的元素的迭代器。若找不到这种元素，则返回尾后（见 end() ）迭代器。

复杂度

平均为常数，最坏情况与容器大小成线性。

示例

#include <iostream>
#include <unordered_map>

int main()
{
// 简单比较演示
    std::unordered_multimap<int,char> example = {{1,'a'},{2,'b'}};

    auto search = example.find(2);
    if (search != example.end()) {
        std::cout << "Found " << search->first << " " << search->second << '\n';
    } else {
        std::cout << "Not found\n";
    }

}

输出：

Found 2 b

参阅

count (C++11) | 返回匹配特定键的元素数量 (公开成员函数)
equal_range (C++11) | 返回匹配特定键的元素范围 (公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::get_allocator

< cpp‎ | container‎ | unordered multimap

allocator_type get_allocator() const noexcept; | (C++11 起)

返回与容器关联的分配器。

参数

（无）

返回值

关联的分配器。

复杂度

常数。


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::hash_function

< cpp‎ | container‎ | unordered multimap

hasher hash_function() const; | (C++11 起)

返回对关键哈希的函数。

参数

（无）

返回值

哈希函数。

复杂度

常数。

参阅

key_eq
(C++11)
 返回用于比较键的相等性的函数
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::insert

< cpp‎ | container‎ | unordered multimap
iterator insert( const value_type& value ); | (1) | (C++11 起)
iterator insert( value_type&& value ); | (1) | (C++17 起)
template< class P > iterator insert( P&& value ); | (2) | (C++11 起)
iterator insert( const_iterator hint, const value_type& value ); | (3) | (C++11 起)
iterator insert( const_iterator hint, value_type&& value ); | (3) | (C++17 起)
template< class P > iterator insert( const_iterator hint, P&& value ); | (4) | (C++11 起)
template< class InputIt > void insert( InputIt first, InputIt last ); | (5) | (C++11 起)
void insert( std::initializer_list <value_type> ilist ); | (6) | (C++11 起)
iterator insert(node_type&& nh); | (7) | (C++17 起)
iterator insert(const_iterator hint, node_type&& nh); | (8) | (C++17 起)

插入元素到容器中。

1-2) 插入 value 。重载 (2) 等价于 emplace( std::forward <P>(value)) ，且仅若 std::is_constructible <value_type, P&&>::value == true 才参与重载决议。
3-4) 插入 value ，以 hint 为应当开始搜索的位置的非强制建议。重载 (4) 等价于 emplace_hint(hint, std::forward <P>(value)) ，且仅若 std::is_constructible <value_type, P&&>::value == true 才参与重载决议。
5) 插入来自范围 [first, last) 的元素。
6) 插入来自 initializer_list ilist 的元素。
7) 若 nh 是空的结点把柄，则不做任何事。否则插入 nh 所占有的元素到容器并返回指向被插入元素的迭代器。。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。
8) 若 nh 是空的结点把柄，则不做任何事并返回尾迭代器。否则，插入 nh 所占有的元素到容器，并返回指向拥有等于 nh.key() 的关键的元素的迭代器元素被插入到尽可能接近 hint 的位置。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。

若因插入发生重哈希，则所有迭代器都被非法化。否则迭代器不受影响。引用不受影响。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。若插入成功，则在结点把柄保有元素时获得的指向该元素的指针和引用被非法化，而在提取前获得的指向元素的指针和引用变得合法。 (C++17 起)

参数

hint | - | 迭代器，用作插入内容位置的建议
value | - | 要插入的元素值
first, last | - | 要插入的元素范围
ilist | - | 插入值来源的 initializer_list
nh | - | 兼容的结点把柄
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

1-4) 返回指向被插入元素的迭代器。
5-6) （无）
7,8) 若 nh 为空则为尾迭代器，否则为指向被插入元素的迭代器。

异常

1-4) 若任何操作抛出异常，则插入无效果。
本节未完成
原因：情况 5-6

复杂度

1-4) 平均情况： O(1) ，最坏情况 O(size())
5-6) 平均情况： O(N) ，其中 N 是要插入的元素数。最坏情况： O(N*size()+N)
7-8) 平均情况： O(1) ，最坏情况 O(size())

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::key_eq

< cpp‎ | container‎ | unordered multimap

key_equal key_eq() const; | (C++11 起)

返回比较关键相等性的函数。

参数

（无）

返回值

关键比较函数。

复杂度

常数。

参阅

hash_function
(C++11)
 返回用于对键散列的函数
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::load_factor

< cpp‎ | container‎ | unordered multimap

float load_factor() const; | (C++11 起)

返回每个桶元素的平均数，即 size() 除以 bucket_count() 。

参数

（无）

返回值

每个桶元素的平均数。

复杂度

常数。

参阅

max_load_factor
(C++11)
 管理每个桶的平均元素数量的最大值
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::max_bucket_count

< cpp‎ | container‎ | unordered multimap

size_type max_bucket_count() const; | (C++11 起)

返回容器由于系统或库实现限制的能保有的最大桶数。

参数

（无）

返回值

最大桶数。

复杂度

常数。

参阅

bucket_count
(C++11)
 返回桶数
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::max_load_factor

< cpp‎ | container‎ | unordered multimap

float max_load_factor() const; | (1) | (C++11 起)
void max_load_factor( float ml ); | (2) | (C++11 起)

管理最大加载因子（每个桶的平均元素数）。若加载因子超出此阈值，则容器自动增加桶数。

1) 返回最大加载因子。

2) 设置最大加载因子为 ml 。

参数

ml - 新设置的最大加载因子

返回值

1) 当前最大加载因子。

2) 无。

复杂度

常数

参阅

load_factor
(C++11)
 返回每个桶的平均元素数量
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::max_size

< cpp‎ | container‎ | unordered multimap

size_type max_size() const noexcept; | (C++11 起)

返回根据系统或库实现限制的容器可保有的元素最大数量，即对于最大容器的 std::distance (begin(), end()) 。

参数

（无）

返回值

元素数量的最大值。

复杂度

常数。

注解

此值通常反映容器大小上的理论极限，至多为 std::numeric_limits <difference_type>::max() 。运行时，可用 RAM 总量可能会限制容器大小到小于 max_size() 的值。

示例

#include <iostream>
#include <unordered_map>

int main()
{
    std::unordered_multimap<char,char> s;
    std::cout << "Maximum size of a 'unordered_multimap' is " << s.max_size() << "\n";
}

可能的输出：

Maximum size of a 'unordered_multimap' is 768614336404564650

参阅

size
(C++11)
 返回容纳的元素数
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::merge

< cpp‎ | container‎ | unordered multimap

template<class H2, class P2> void merge( std::unordered_map <Key, T, H2, P2, Allocator>& source ); | (1) | (C++17 起)
template<class H2, class P2> void merge( std::unordered_map <Key, T, H2, P2, Allocator>&& source ); | (2) | (C++17 起)
template<class H2, class P2> void merge( std::unordered_multimap <Key, T, H2, P2, Allocator>& source ); | (3) | (C++17 起)
template<class H2, class P2> void merge( std::unordered_multimap <Key, T, H2, P2, Allocator>&& source ); | (4) | (C++17 起)

试图提取（“接合”） source 中每个元素，并用 *this 的散列函数与键相等谓词插入到 *this 。

不复制或移动元素，只会重指向容器结点的内部指针。指向被转移元素的所有指针和引用保持合法，但现在指代到 *this 中而非到 source 中。指代被转移元素的迭代器和所有指代到 *this 的迭代器被非法化。

若 get_allocator() != source.get_allocator() 则行为未定义。

参数

source - 传递结点来源的兼容容器

返回值

（无）

复杂度

平均情况 O(N) ，最坏情况 O(N*size()+N) ，其中 N 为 source.size() 。

示例

#include <iostream>
#include <string>
#include <utility>
#include <unordered_map>

// 打印出 std::pair
template <class Os, class U, class V>
Os& operator<<(Os& os, const std::pair<U,V>& p) {
    return os << '{' << p.first << ", " << p.second << '}';
}

// 打印出关联容器
template <class Os, class K, class V>
Os& operator<<(Os& os, const std::unordered_multimap<K, V>& v) {
    os << '[' << v.size() << "] { ";
    bool o{};
    for (const auto& e : v)
        os << (o ? ", " : (o = 1, "")) << e;
    return os << " }\n";
}

int main()
{
    std::unordered_multimap<std::string, int>
        p{ {"C", 3}, {"B", 2}, {"A", 1}, {"A", 0} },
        q{ {"E", 6}, {"E", 7}, {"D", 5}, {"A", 4} };

    std::cout << "p: " << p << "q: " << q;

    p.merge(q);

    std::cout << "p.merge(q);\n" << "p: " << p << "q: " << q;
}

可能的输出：

p: [4] { {A, 1}, {A, 0}, {B, 2}, {C, 3} }
q: [4] { {A, 4}, {D, 5}, {E, 6}, {E, 7} }
p.merge(q);
p: [8] { {E, 6}, {E, 7}, {C, 3}, {A, 1}, {A, 0}, {A, 4}, {D, 5}, {B, 2} }
q: [0] { }

参阅

extract (C++17) | 从另一容器释出结点 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::operator=

< cpp‎ | container‎ | unordered multimap

unordered_multimap& operator=( const unordered_multimap& other ); | (1) | (C++11 起)
 | (2) |
unordered_multimap& operator=( unordered_multimap&& other ); |  |  | (C++11 起) (C++17 前)
unordered_multimap& operator=( unordered_multimap&& other ) noexcept(/* see below */); |  |  | (C++17 起)
unordered_multimap& operator=( std::initializer_list <value_type> ilist ); | (3) | (C++11 起)

替换容器内容。

1) 复制赋值运算符。以 other 的副本替换内容。
若 std::allocator_traits <allocator_type>::propagate_on_container_copy_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若 *this 的分配器在赋值后将与其旧值比较不相等，则用旧分配器解分配内存，然后在复制元素前用新分配器分配内存。否则，在可行时可能复用 *this 所拥有的内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素复制赋值替换。
2) 移动赋值运算符。用移动语义以 other 的内容替换内容（即从 other 移动 other 中的数据到此容器中）。之后 other 在合法但未指定的状态。
若 std::allocator_traits <allocator_type>::propagate_on_container_move_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若它为 false 且 *this 与 other 的分配器不比较相等，则 *this 不能接管 other 所拥有的内存的所有权且必须单独地移动赋值每个元素，并用其自身的分配器按需分配额外内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素移动赋值替换。
3) 以 initializer_list ilist 所标识者替换内容。

参数

other | - | 用作数据源的另一容器
ilist | - | 用作数据源的 initializer_list

返回值

*this

复杂度

1) 与 *this 和 other 的大小成线性。
2) 与 *this 的大小成线性，除非分配器不比较相等且不传播，该情况下与 *this 和 other 的大小成线性。
3) 与 *this 和 ilist 的大小成线性。

异常

可能抛出实现定义的异常。

 (C++17 前)
1,3) 可能抛出实现定义的异常。
2)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value

&& std::is_nothrow_move_assignable <Hash>::value

&& std::is_nothrow_move_assignable <Pred>::value)
 (C++17 起)

注解

在容器移动赋值（重载 (2) ）后，除非不兼容的分配器强制逐元素移动赋值，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

下列代码用 operator= 赋值一个 std::unordered_multimap 给另一个：

#include <unordered_map>
#include <iostream>

void display_sizes(const std::unordered_multimap<int, int> &nums1,
                   const std::unordered_multimap<int, int> &nums2,
                   const std::unordered_multimap<int, int> &nums3)
{
    std::cout << "nums1: " << nums1.size()
              << " nums2: " << nums2.size()
              << " nums3: " << nums3.size() << '\n';
}

int main()
{
    std::unordered_multimap<int, int> nums1 {{3, 1}, {4, 1}, {5, 9},
                                   {6, 1}, {7, 1}, {8, 9}};
    std::unordered_multimap<int, int> nums2;
    std::unordered_multimap<int, int> nums3;

    std::cout << "Initially:\n";
    display_sizes(nums1, nums2, nums3);

    // 复制赋值从 nums1 复制数据到 nums2
    nums2 = nums1;

    std::cout << "After assigment:\n";
    display_sizes(nums1, nums2, nums3);

    // 移动赋值从 nums1 移动数据到 nums3,
    // 一同修改 nums1 和 nums3
    nums3 = std::move(nums1);

    std::cout << "After move assigment:\n";
    display_sizes(nums1, nums2, nums3);
}

输出：

Initially:
nums1: 6 nums2: 0 nums3: 0
After assigment:
nums1: 6 nums2: 6 nums3: 0
After move assigment:
nums1: 0 nums2: 6 nums3: 6

参阅

(构造函数)
(C++11)
 构造 unordered_multimap
(公开成员函数)


operator==,!=(std::unordered_multimap)

< cpp‎ | container‎ | unordered multimap

template< class Key, class T, class Hash, class KeyEqual, class Allocator >

bool operator==( const std::unordered_multimap <Key,T,Hash,KeyEqual,Allocator>& lhs,

const std::unordered_multimap <Key,T,Hash,KeyEqual,Allocator>& rhs );
 (1)
template< class Key, class T, class Hash, class KeyEqual, class Allocator >

bool operator!=( const std::unordered_multimap <Key,T,Hash,KeyEqual,Allocator>& lhs,

const std::unordered_multimap <Key,T,Hash,KeyEqual,Allocator>& rhs );
 (2) (C++20 前)

比较二个无序容器的内容。

若下列条件成立则二个无序容器 lhs 与 rhs 相等：

  • lhs.size() == rhs.size()
  • 从 lhs.equal_range(lhs_eq1) 获得的每组等价元素 [lhs_eq1, lhs_eq2) 拥有在另一容器中从 rhs.equal_range(rhs_eq1) 获得的对应等价元素组 [rhs_eq1, rhs_eq2) ，且它们拥有下列属性：
  • std::distance (lhs_eq1, lhs_eq2) == std::distance (rhs_eq1, rhs_eq2) 。
  • std::is_permutation (lhs_eq1, lhs_eq2, rhs_eq1) == true 。

若 Key 或 T 非可相等比较 (EqualityComparable) 则行为未定义。

若 hash_function() 和 key_eq() (C++20 前)key_eq() (C++20 起) 在 lhs 和 rhs 上拥有不相同的行为，或若 Key 的 operator== 不是对于 key_eq() 所引入的等价关键组的细分（即若用 operator== 比较相等的二个元素落入不同划分），则行为未定义。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的无序容器

返回值

1) 若容器内容相等则为 true ，否则为 false 。
2) 若容器内容不相等则为 true ，否则为 false 。

复杂度

调用 value_type 上的 operator== 、调用 key_eq 所返回的谓词，及调用 hash_function 所返回的哈希器的次数，平均情况下与 ΣSi2 成正比，其中 S 是第 i 个等价关键组的大小。最坏情况下与 N2 成正比，其中 N 是容器大小。若每个等价关键组中元素以相同顺序排列（在容器互为副本时发生），则平均情况变为与 N 成正比。


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::rehash

< cpp‎ | container‎ | unordered multimap

void rehash( size_type count ); | (C++11 起)

设置桶数为 count 并重哈希容器，即考虑桶总数已改变，再把元素放到适当的桶中。若新的桶数使加载因子大于最大加载因子（ count < size() / max_load_factor() ），则新桶数至少为 size() / max_load_factor() 。

参数

count - 新的桶数

返回值

（无）

复杂度

平均与容器大小成线性，最坏情况成平方。

注意

rehash(0) 可用于强制无条件的重哈希，例如在通过临时增加 max_load_factor() 暂停自动重哈希之后。

参阅

reserve
(C++11)
 为至少为指定数量的元素预留存储空间并重新生成哈希表。
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::reserve

< cpp‎ | container‎ | unordered multimap

void reserve( size_type count ); | (C++11 起)

设置桶数为适应至少 count 个元素，而不超出最大加载因子所需的数，并重哈希容器，即考虑桶数已更改后将元素放进适合的桶。等效地调用 rehash( std::ceil (count / max_load_factor())) 。

参数

count - 容器的新容量

返回值

（无）

复杂度

平均情况与容器大小成线性，最坏情况成平方。

参阅

rehash
(C++11)
 为至少为指定数量的桶预留存储空间并重新生成散列表
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::size

< cpp‎ | container‎ | unordered multimap

size_type size() const noexcept; | (C++11 起)

返回容器中的元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

容器中的元素数量。

复杂度

常数。

示例

下列代码用 size 显示 std::unordered_multimap 中的元素数：

#include <unordered_map>
#include <iostream>

int main()
{
    std::unordered_multimap<int,char> nums {{1, 'a'}, {3, 'b'}, {5, 'c'}, {7, 'd'}};

    std::cout << "nums contains " << nums.size() << " elements.\n";
}

输出：

nums contains 4 elements.

参阅

empty (C++11) | 检查容器是否为空 (公开成员函数)
max_size (C++11) | 返回可容纳的最大元素数 (公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::swap

< cpp‎ | container‎ | unordered multimap

void swap( unordered_multimap& other ); | (C++11 起) (C++17 前)
void swap( unordered_multimap& other ) noexcept(/* see below */); | (C++17 起)

将内容与 other 的交换。不在单独的元素上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。尾后迭代器被非法化。

Hash 和 KeyEqual 对象必须可交换 (Swappable) ，并用非成员 swap 的非限定调用交换它们。

若 std::allocator_traits <allocator_type>::propagate_on_container_swap::value 为 true ，则用对非成员 swap 的无限定调用交换分配器。否则，不交换它们（且若 get_allocator() != other.get_allocator() ，则行为未定义）。

 (C++11 起)

参数

other - 要与之交换内容的容器

返回值

（无）

异常

任何 Hash 或 KeyEqual 对象交换所抛的异常。

 (C++17 前)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value

&& std::is_nothrow_swappable <Hash>::value

&& std::is_nothrow_swappable <key_equal>::value)
 (C++17 起)

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

std::swap(std::unordered_multimap)
(C++11)
 特化 std::swap 算法
(函数模板)


std::swap(std::unordered_multimap)

< cpp‎ | container‎ | unordered multimap

定义于头文件 <unordered_map>
template< class Key, class T, class Hash, class KeyEqual, class Alloc >

void swap( std::unordered_multimap <Key,T,Hash,KeyEqual,Alloc>& lhs,

std::unordered_multimap <Key,T,Hash,KeyEqual,Alloc>& rhs );
 (C++11 起)
(C++17 前)
template< class Key, class T, class Hash, class KeyEqual, class Alloc >

void swap( std::unordered_multimap <Key,T,Hash,KeyEqual,Alloc>& lhs,

std::unordered_multimap <Key,T,Hash,KeyEqual,Alloc>& rhs ) noexcept(/* see below */);
 (C++17 起)

为 std::unordered_multimap 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

#include <algorithm>
#include <iostream>
#include <unordered_map>

int main()
{
    std::unordered_multimap<int, char> alice{{1, 'a'}, {2, 'b'}, {3, 'c'}};
    std::unordered_multimap<int, char> bob{{7, 'Z'}, {8, 'Y'}, {9, 'X'}, {10, 'W'}};

    auto print = [](std::pair<const int, char>& n) {
        std::cout << " " << n.first << '(' << n.second << ')';
    };

    // 打印交换前的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';

    std::cout << "-- SWAP\n";
    std::swap(alice,bob);

    // 打印交换后的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
}

可能的输出：

alice: 1(a) 2(b) 3(c)
bob  : 7(Z) 8(Y) 9(X) 10(W)
-- SWAP
alice: 7(Z) 8(Y) 9(X) 10(W)
bob  : 1(a) 2(b) 3(c)

参阅

swap
(C++11)
 交换内容
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::unordered_multimap

< cpp‎ | container‎ | unordered multimap

unordered_multimap() : unordered_multimap( size_type(/*implementation-defined*/) ) {}

explicit unordered_multimap( size_type bucket_count,
const Hash& hash = Hash(),
const key_equal& equal = key_equal(),

const Allocator& alloc = Allocator() );
 (1) (C++11 起)
unordered_multimap( size_type bucket_count,

const Allocator& alloc )
: unordered_multimap(bucket_count, Hash(), key_equal(), alloc) {}
unordered_multimap( size_type bucket_count,
const Hash& hash,
const Allocator& alloc )

: unordered_multimap(bucket_count, hash, key_equal(), alloc) {}
 (1) (C++14 起)
explicit unordered_multimap( const Allocator& alloc );
 (1) (C++11 起)
template< class InputIt >

unordered_multimap( InputIt first, InputIt last,
size_type bucket_count = /*implementation-defined*/,
const Hash& hash = Hash(),
const key_equal& equal = key_equal(),

const Allocator& alloc = Allocator() );
 (2) (C++11 起)
template< class InputIt >

unordered_multimap( InputIt first, InputIt last,
size_type bucket_count,
const Allocator& alloc )
: unordered_multimap(first, last,

bucket_count, Hash(), key_equal(), alloc) {}
 (2) (C++14 起)
template< class InputIt >

unordered_multimap( InputIt first, InputIt last,
size_type bucket_count,
const Hash& hash,
const Allocator& alloc )
: unordered_multimap(first, last,

bucket_count, hash, key_equal(), alloc) {}
 (2) (C++14 起)
unordered_multimap( const unordered_multimap& other );
 (3) (C++11 起)
unordered_multimap( const unordered_multimap& other, const Allocator& alloc );
 (3) (C++11 起)
unordered_multimap( unordered_multimap&& other );
 (4) (C++11 起)
unordered_multimap( unordered_multimap&& other, const Allocator& alloc );
 (4) (C++11 起)
unordered_multimap( std::initializer_list <value_type> init,

size_type bucket_count = /*implementation-defined*/,
const Hash& hash = Hash(),
const key_equal& equal = key_equal(),

const Allocator& alloc = Allocator() );
 (5) (C++11 起)
unordered_multimap( std::initializer_list <value_type> init,

size_type bucket_count,
const Allocator& alloc )
: unordered_multimap(init, bucket_count,

Hash(), key_equal(), alloc) {}
 (5) (C++14 起)
unordered_multimap( std::initializer_list <value_type> init,

size_type bucket_count,
const Hash& hash,
const Allocator& alloc )
: unordered_multimap(init, bucket_count,

hash, key_equal(), alloc) {}
 (5) (C++14 起)

从各种数据源构造新容器。可选的以用户提供的 bucket_count 为用于创建的最小桶数，以 hash 为哈希函数，以 equal 为比较关键的函数，和以 alloc 为分配器。

1) 构造空容器。设置 max_load_factor() 为 1.0 。对于默认构造函数，桶数是实现定义的。
2) 构造拥有范围 [first, last) 的内容的容器。设置 max_load_factor() 为 1.0 。
3) 复制构造函数。构造拥有 other 内容副本的容器，一同复制加载因子、谓词和哈希函数。若不提供 alloc ，则通过调用 std::allocator_traits <allocator_type>::select_on_container_copy_construction(other.get_allocator()) 获得分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
4) 移动构造函数。用移动语义构造拥有 other 内容的容器。若不提供 alloc ，则通过从属于 other 的分配器移动构造获得分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
5) 构造拥有 initializer_list init 内容的容器，同 unordered_multimap(init.begin(), init.end()) 。

参数

alloc | - | 用于此容器所有内存分配器的分配器
bucket_count | - | 初始化时用的最小桶数。若不指定，则使用实现定义的默认值
hash | - | 要用的哈希函数
equal | - | 用于此容器所有关键比较的比较函数
first, last | - | 复制元素来源的范围
other | - | 用作源以初始化容器元素的另一容器
init | - | 用以初始化容器元素的 initializer_list
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

复杂度

1) 常数
2) 平均情况与 first 和 last 间的距离成线性，最坏情况成平方。
3) 与 other 的大小成线性。
4) 常数。若给定 alloc 且 alloc != other.get_allocator() 则为线性。
5) 平均情况与 init 的大小成线性，最坏情况成平方。

异常

对 Allocator::allocate 的调用可能抛出。

注解

在容器移动构造（重载 (4) ）后，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

尽管在 C++23 前未正式要求，一些实现已经在较早的模式中将 Allocator 放入非推导语境。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2193 | C++11 | 默认构造函数为 explicit | 使之为非 explicit

参阅

operator=
(C++11)
 赋值给容器
(公开成员函数)


std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator>::~unordered_multimap

< cpp‎ | container‎ | unordered multimap

~unordered_multimap(); | (C++11 起)

销毁 unordered_multimap 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 unordered_multimap 大小成线性。


std::unordered_multiset

< cpp‎ | container
定义于头文件 <unordered_set>
template<

class Key,
class Hash = std::hash <Key>,
class KeyEqual = std::equal_to <Key>,
class Allocator = std::allocator <Key>

> class unordered_multiset;
 (1) (C++11 起)
namespace pmr {

template <class Key,
class Hash = std::hash <Key>,
class Pred = std::equal_to <Key>>
using unordered_multiset = std::unordered_multiset<Key, Hash, Pred,
std::pmr::polymorphic_allocator <Key>>

}
 (2) (C++17 起)

unordered_multiset 是关联容器，含有可能非唯一 Key 类型对象的集合。搜索、插入和移除拥有平均常数时间复杂度。

元素在内部并不以任何顺序排序，只是被组织到桶中。元素被放入哪个桶完全依赖其值的哈希。这允许快速访问单独的元素，因为一旦计算哈希，它就指代放置该元素的准确的桶。

不要求此容器的迭代顺序稳定（故例如 std::equal 不能用于比较二个 std::unordered_multiset ），除了关键比较等价（以 key_eq() 为比较器比较相等）的每组元素组成迭代顺序中的相接子范围，它可用 equal_range() 访问。

std::unordered_multiset 满足容器 (Container) 、知分配器容器 (AllocatorAwareContainer) 、无序关联容器 (UnorderedAssociativeContainer) 的要求

成员类型

成员类型 | 定义
key_type | Key
value_type | Key
size_type | 无符号整数类型（通常是 std::size_t ）
difference_type | 有符号整数类型（通常是 std::ptrdiff_t ）
hasher | Hash
key_equal | KeyEqual
allocator_type | Allocator
reference | value_type&
const_reference | const value_type&
pointer | std::allocator_traits <Allocator>::pointer
const_pointer | std::allocator_traits <Allocator>::const_pointer
iterator | 指向 value_type 的常老式向前迭代器 (LegacyForwardIterator)
const_iterator | 指向 const value_type 的老式向前迭代器 (LegacyForwardIterator)
local_iterator | 类别、值、差、指针和引用类型都与 iterator 相同的迭代器类型。 能用此迭代器在单个桶迭代，但不能跨桶。
const_local_iterator | 类别、值、差、指针和引用类型都与 const_iterator 相同的迭代器类型。 能用此迭代器在单个桶迭代，但不能跨桶。
node_type(C++17 起) | 表示容器结点的结点把柄特化

成员函数

(构造函数)
(C++11)
 构造 unordered_multiset
(公开成员函数)
(析构函数)
(C++11)
 析构 unordered_multiset
(公开成员函数)
operator=
(C++11)
 赋值给容器
(公开成员函数)
get_allocator
(C++11)
 返回相关的分配器
(公开成员函数)
迭代器
begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)
容量
empty
(C++11)
 检查容器是否为空
(公开成员函数)
size
(C++11)
 返回容纳的元素数
(公开成员函数)
max_size
(C++11)
 返回可容纳的最大元素数
(公开成员函数)
修改器
clear
(C++11)
 清除内容
(公开成员函数)
insert
(C++11)
 插入元素或结点 (C++17 起)
(公开成员函数)
emplace
(C++11)
 原位构造元素
(公开成员函数)
emplace_hint
(C++11)
 使用提示原位构造元素
(公开成员函数)
erase
(C++11)
 擦除元素
(公开成员函数)
swap
(C++11)
 交换内容
(公开成员函数)
extract
(C++17)
 从另一容器释出结点
(公开成员函数)
merge
(C++17)
 从另一容器接合结点
(公开成员函数)
查找
count
(C++11)
 返回匹配特定键的元素数量
(公开成员函数)
find
(C++11)
 寻找带有特定键的元素
(公开成员函数)
contains
(C++20)
 检查容器是否含有带特定键的元素
(公开成员函数)
equal_range
(C++11)
 返回匹配特定键的元素范围
(公开成员函数)
桶接口
begin(size_type) cbegin(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的开始
(公开成员函数)
end(size_type) cend(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的末尾
(公开成员函数)
bucket_count
(C++11)
 返回桶数
(公开成员函数)
max_bucket_count
(C++11)
 返回桶的最大数量
(公开成员函数)
bucket_size
(C++11)
 返回在特定的桶中的元素数量
(公开成员函数)
bucket
(C++11)
 返回带有特定键的桶
(公开成员函数)
哈希策略
load_factor
(C++11)
 返回每个桶的平均元素数量
(公开成员函数)
max_load_factor
(C++11)
 管理每个桶的平均元素数量的最大值
(公开成员函数)
rehash
(C++11)
 为至少为指定数量的桶预留存储空间并重新生成散列表
(公开成员函数)
reserve
(C++11)
 为至少为指定数量的元素预留存储空间并重新生成哈希表。
(公开成员函数)
观察器
hash_function
(C++11)
 返回用于对键散列的函数
(公开成员函数)
key_eq
(C++11)
 返回用于比较键的相等性的函数
(公开成员函数)

非成员函数

operator==operator!= (C++20 中移除) | 比较 unordered_multiset 中的值 (函数模板)
std::swap(std::unordered_multiset) (C++11) | 特化 std::swap 算法 (函数模板)
erase_if(std::unordered_multiset) (C++20) | 擦除所有满足特定判别标准的元素 (函数模板)

推导指引 (C++17 起)

注意

成员类型 iterator 与 const_iterator 可能是同一类型的别名。这表明以二个类型为参数类型的一对函数重载可能违背单一定义规则。因为 iterator 可转换为 const_iterator ，单个以 const_iterator 为参数类型的函数会是有效的。


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::begin, std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::cbegin

< cpp‎ | container‎ | unordered multiset

iterator begin() noexcept; | (C++11 起)
const_iterator begin() const noexcept; | (C++11 起)
const_iterator cbegin() const noexcept; | (C++11 起)

返回指向 unordered_multiset 首元素的迭代器。

若 unordered_multiset 为空，则返回的迭代器将等于 end() 。

参数

（无）

返回值

指向首元素的迭代器。

复杂度

常数。

注意

因为 iterator 和 const_iterator 都是常迭代器（而且实际上可以是同一类型），故不可能通过任何这些成员函数返回的迭代器修改容器元素。

示例

#include <iostream>
#include <iterator>
#include <string>
#include <unordered_set>

int main() {
    const std::unordered_multiset<std::string> words = {
        "some", "words", "to", "count",
        "count", "these", "words"
    };

    for (auto it = words.begin(); it != words.end(); ) {
        auto cnt = words.count(*it);
        std::cout << *it << ":\t" << cnt << '\n';
        std::advance(it, cnt); // 所有元素均拥有等价的键
    }
}

可能的输出：

some:   1
words:  2
to:     1
count:  2
these:  1

参阅

end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::begin(size_type), std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::cbegin(size_type)

< cpp‎ | container‎ | unordered multiset

local_iterator begin( size_type n ); | (C++11 起)
const_local_iterator begin( size_type n ) const; | (C++11 起)
const_local_iterator cbegin( size_type n ) const; | (C++11 起)

返回指向下标为 n 的桶首元素的迭代器。

参数

n - 要访问的桶的下标

返回值

指向首元素的迭代器。

复杂度

常数。

参阅

end(size_type) cend(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的末尾
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::bucket

< cpp‎ | container‎ | unordered multiset

size_type bucket( const Key& key ) const; | (C++11 起)

返回关键 key 的桶的下标。始终会在此桶中找到关键等于 key 的元素（若存在）。返回值仅对 bucket_count() 返回相同值的容器实例合法。

若 bucket_count() 为零则行为未定义。

参数

key - 要检验的关键值

返回值

关键 key 的桶编号。

复杂度

常数。

参阅

bucket_size
(C++11)
 返回在特定的桶中的元素数量
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::bucket_count

< cpp‎ | container‎ | unordered multiset

size_type bucket_count() const; | (C++11 起)

返回容器中的桶数。

参数

（无）

返回值

容器中的桶数。

复杂度

常数。

参阅

bucket_size (C++11) | 返回在特定的桶中的元素数量 (公开成员函数)
max_bucket_count (C++11) | 返回桶的最大数量 (公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::bucket_size

< cpp‎ | container‎ | unordered multiset

size_type bucket_size( size_type n ) const; | (C++11 起)

返回下标为 n 的桶中的元素数。

参数

n - 要检验的桶的下标

返回值

桶 n 中的元素数。

复杂度

与桶 n 的大小成线性。

参阅

bucket_count
(C++11)
 返回桶数
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::clear

< cpp‎ | container‎ | unordered multiset

void clear() noexcept; | (C++11 起)

从容器擦除所有元素。此调用后 size() 返回零。

非法化任何指代所含元素的引用、指针或迭代器。可能亦非法化尾后迭代器。

参数

（无）

返回值

（无）

复杂度

与容器大小，即元素数成线性。

示例

#include <algorithm>
#include <iostream>
#include <unordered_set>

int main()
{
    std::unordered_multiset<int> container{1, 2, 3};

    auto print = [](const int& n) { std::cout << " " << n; };

    std::cout << "Before clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';

    std::cout << "Clear\n";
    container.clear();

    std::cout << "After clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';
}

可能的输出：

Before clear: 1 2 3
Size=3
Clear
After clear:
Size=0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2550 | C++11 | 对于无序关联容器，不清楚复杂度是与元素数还是桶数成线性 | 辨明它与元素数成线性

参阅

erase
(C++11)
 擦除元素
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::contains

< cpp‎ | container‎ | unordered multiset

bool contains( const Key& key ) const; | (1) | (C++20 起)
template< class K > bool contains( const K& x ) const; | (2) | (C++20 起)
1) 检查容器中是否有键等价于 key 的元素。
2) 检查是否有键比较等价于值 x 的元素。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 任何能通透地与键比较的类型的值

返回值

若有这种元素则为 true ，否则为 false 。

复杂度

平均为常数，最坏情况与容器大小成线性。

示例

#include <iostream>
#include <unordered_set>

int main()
{
    std::unordered_multiset<int> example = {1, 2, 3, 4};

    for(int x: {2, 5}) {
        if(example.contains(x)) {
            std::cout << x << ": Found\n";
        } else {
            std::cout << x << ": Not found\n";
        }
    }
}

输出：

2: Found
5: Not found

参阅

find (C++11) | 寻找带有特定键的元素 (公开成员函数)
count (C++11) | 返回匹配特定键的元素数量 (公开成员函数)
equal_range (C++11) | 返回匹配特定键的元素范围 (公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::count

< cpp‎ | container‎ | unordered multiset

size_type count( const Key& key ) const; | (1) | (C++11 起)
template< class K > size_type count( const K& x ) const; | (2) | (C++20 起)
1) 返回拥有比较等于指定参数 key 的关键的元素数。
2) 返回键比较等价于指定参数 x 的元素数。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要计量等价元素数的键值
x | - | 能通透地与键比较的任何类型值

返回值

1) 拥有关键 key 的元素数。
2) 键比较等价于 x 的元素数。

复杂度

平均与拥有关键 key 的元素数成线性，最坏情况与容器大小成线性。

参阅

find (C++11) | 寻找带有特定键的元素 (公开成员函数)
equal_range (C++11) | 返回匹配特定键的元素范围 (公开成员函数)


std::unordered_multiset 的推导指引

< cpp‎ | container‎ | unordered multiset

定义于头文件 <unordered_set>
template<class InputIt,

class Hash = std::hash <typename std::iterator_traits <InputIt>::value_type>,
class Pred = std::equal_to <typename std::iterator_traits <InputIt>::value_type>,
class Alloc = std::allocator <typename std::iterator_traits <InputIt>::value_type>>
unordered_multiset(InputIt, InputIt,
typename /*see below*/::size_type = /*see below*/,
Hash = Hash(), Pred = Pred(), Alloc = Alloc())

-> unordered_multiset<typename std::iterator_traits <InputIt>::value_type, Hash, Pred, Alloc>;
 (1) (C++17 起)
template<class T,

class Hash = std::hash <T>,
class Pred = std::equal_to <T>,
class Alloc = std::allocator <T>>
unordered_multiset( std::initializer_list <T>,
typename /*see below*/::size_type = /*see below*/,
Hash = Hash(), Pred = Pred(), Alloc = Alloc())

-> unordered_multiset<T, Hash, Pred, Alloc>;
 (2) (C++17 起)
template<class InputIt, class Alloc>

unordered_multiset(InputIt, InputIt, typename /*see below*/::size_type, Alloc)
-> unordered_multiset<typename std::iterator_traits <InputIt>::value_type,
std::hash <typename std::iterator_traits <InputIt>::value_type>,
std::equal_to <typename std::iterator_traits <InputIt>::value_type>,

Alloc>;
 (3) (C++17 起)
template<class InputIt, class Hash, class Alloc>

unordered_multiset(InputIt, InputIt, typename /*see below*/::size_type, Hash, Alloc)
-> unordered_multiset<typename std::iterator_traits <InputIt>::value_type, Hash,

std::equal_to <typename std::iterator_traits <InputIt>::value_type>, Allocator>;
 (4) (C++17 起)
template<class T, class Allocator>

unordered_multiset( std::initializer_list <T>, typename /*see below*/::size_type, Allocator)

-> unordered_multiset<T, std::hash <T>, std::equal_to <T>, Alloc>;
 (5) (C++17 起)
template<class T, class Hash, class Alloc>

unordered_multiset( std::initializer_list <T>, typename /*see below*/::size_type, Hash, Alloc)

-> unordered_multiset<T, Hash, std::equal_to <T>, Alloc>;
 (6) (C++17 起)

为 unordered_multiset 提供这些推导指引以允许从迭代器范围（重载 (1,3,4) ）和 std::initializer_list （重载 (2,5.6) ）推导。此重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 、 Alloc 满足分配器 (Allocator) 、 Hash 或 Pred 均不满足分配器 (Allocator) 、 Hash 不是整数类型才参与重载决议

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

这些指引中的 size_type 参数类型指代推导指引所推导出的类型的 size_type 成员类型。

示例

#include <unordered_set>
int main() {
   std::unordered_multiset s = {1,2,3,4};            // 指引 #2 推导 std::unordered_multiset<int>
   std::unordered_multiset s2(s.begin(), s.end());   // 指引 #1 推导 std::unordered_multiset<int>
}


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::emplace

< cpp‎ | container‎ | unordered multiset

template< class... Args > iterator emplace( Args&&... args ); | (C++11 起)

插入以给定的 args 原位构造的新元素到容器。

细心地使用 emplace 允许在构造新元素的同时避免不必要的复制或移动操作。 准确地以与提供给 emplace 者相同的参数，通过 std::forward <Args>(args)... 转发调用新元素的构造函数。

若因插入发生重哈希，则所有迭代器都被非法化。否则迭代器不受影响。引用不被非法化。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。

参数

args - 要转发给元素构造函数的参数

返回值

指向被插入元素的迭代器。

异常

若任何操作抛出异常，则此函数无效果。

复杂度

平均为均摊常数，最坏情况与容器大小成线性。

示例

本节未完成
原因：暂无示例

参阅

emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::emplace_hint

< cpp‎ | container‎ | unordered multiset
template <class... Args> iterator emplace_hint( const_iterator hint, Args&&... args ); | (C++11 起)

插入新元素到容器中，以 hint 为放置元素位置的建议。原位构造元素，即不进行复制或移动操作。

准确地以与提供给函数的参数相同者，以 std::forward <Args>(args)... 转发调用元素的构造函数。

若因插入发生重哈希，则所有迭代器都被非法化。否则迭代器不受影响。引用不被非法化。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。

参数

hint | - | 迭代器，用作插入新元素位置的建议
args | - | 转发给元素构造函数的参数

返回值

返回指向新插入元素的迭代器。

异常

若任何操作抛出异常，则此函数无效果（强异常保证）。

复杂度

平均为均摊常数，最坏情况下与容器大小成线性。

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::empty

< cpp‎ | container‎ | unordered multiset

bool empty() const noexcept; | (C++11 起) (C++20 前)
[[nodiscard]] bool empty() const noexcept; | (C++20 起)

检查容器是否无元素，即是否 begin() == end() 。

参数

（无）

返回值

若容器为空则为 true ，否则为 false

复杂度

常数。

示例

下列代码用 empty 检查 std::unordered_multiset <int> 是否含有任何元素：

#include <unordered_set>
#include <iostream>

int main()
{
    std::unordered_multiset<int> numbers;
    std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';

    numbers.insert(42);
    numbers.insert(13317);
    std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
}

输出：

Initially, numbers.empty(): 1
After adding elements, numbers.empty(): 0

参阅

size
(C++11)
 返回容纳的元素数
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::end, std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::cend

< cpp‎ | container‎ | unordered multiset

iterator end() noexcept; | (C++11 起)
const_iterator end() const noexcept; | (C++11 起)
const_iterator cend() const noexcept; | (C++11 起)

返回指向 unordered_multiset 末元素后一元素的迭代器。

此元素表现为占位符；试图访问它导致未定义行为。

参数

（无）

返回值

指向后随最后元素的迭代器。

复杂度

常数。

注意

因为 iterator 和 const_iterator 都是常迭代器（而且实际上可以是同一类型），故不可能通过任何这些成员函数返回的迭代器修改容器元素。

示例

#include <iostream>
#include <iterator>
#include <string>
#include <unordered_set>

int main() {
    const std::unordered_multiset<std::string> words = {
        "some", "words", "to", "count",
        "count", "these", "words"
    };

    for (auto it = words.begin(); it != words.end(); ) {
        auto cnt = words.count(*it);
        std::cout << *it << ":\t" << cnt << '\n';
        std::advance(it, cnt); // 所有元素均拥有等价的键
    }
}

可能的输出：

some:   1
words:  2
to:     1
count:  2
these:  1

参阅

begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::end(size_type), std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::cend(size_type)

< cpp‎ | container‎ | unordered multiset

local_iterator end( size_type n ); | (C++11 起)
const_local_iterator end( size_type n ) const; | (C++11 起)
const_local_iterator cend( size_type n ) const; | (C++11 起)

返回后随下标为 n 的桶的最后元素的元素的迭代器。此元素表现为占位符，试图访问它会导致未定义行为。

参数

n - 要访问的桶的下标

返回值

指向后随最后元素的元素的迭代器。

复杂度

常数

参阅

begin(size_type) cbegin(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的开始
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::equal_range

< cpp‎ | container‎ | unordered multiset

std::pair <iterator,iterator> equal_range( const Key& key ); | (1) | (C++11 起)
std::pair <const_iterator,const_iterator> equal_range( const Key& key ) const; | (2) | (C++11 起)
template< class K > std::pair <iterator,iterator> equal_range( const K& x ); | (3) | (C++20 起)
template< class K > std::pair <const_iterator,const_iterator> equal_range( const K& x ) const; | (4) | (C++20 起)
1,2) 返回容器中所有键等于 key 的元素范围。范围以二个迭代器定义，第一个指向所需范围的首元素，而第二个指向范围的尾后一位元素。
3,4) 返回含有容器中所有键等价于 x 的元素的范围。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要与元素比较的键值
x | - | 任何能与键通透比较的类型的值

返回值

含一对定义所需范围的迭代器的 std::pair 。若无这种元素，则将尾后（见 end() ）迭代器作为 pair 的两个元素返回。

复杂度

平均情况与带关键 key 的元素数成线性，最坏情况与容器大小成线性。

示例

对给定字符串估计字符频率。

#include <iostream>
#include <iterator>
#include <string>
#include <unordered_set>

int main()
{
    std::string sentence{"cppreference.com"};
    std::cout << "The sentence: " << sentence << '\n';

    std::unordered_multiset<char> sequence;
    for (char x : sentence) { sequence.insert(x); }

    std::cout << "The sequence: { ";
    for (char x : sequence) { std::cout << x << ' '; }

    std::cout << "}\n" "Symbol:Frequency: ";
    for (auto it = sequence.begin(); it != sequence.end(); ) {
        if (auto [first, last] = sequence.equal_range(*it); first != last) {
            std::cout << *first << ":" << std::distance(first, last) << "  ";
            it = last;
        } else {
            ++it;
        }
    }
}

可能的输出：

The sentence: cppreference.com
The sequence: { m o c c c p p r r e e e e f n . }
Symbol:Frequency: m:1  o:1  c:3  p:2  r:2  e:4  f:1  n:1  .:1

参阅

find (C++11) | 寻找带有特定键的元素 (公开成员函数)
contains (C++20) | 检查容器是否含有带特定键的元素 (公开成员函数)
count (C++11) | 返回匹配特定键的元素数量 (公开成员函数)
equal_range | 返回匹配特定键值的元素范围 (函数模板)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::erase

< cpp‎ | container‎ | unordered multiset

 | (1) |
iterator erase( iterator pos ); |  |  | (C++11 起)
iterator erase( const_iterator pos ); |  |  | (C++11 起)
 | (2) |
iterator erase( const_iterator first, const_iterator last ); |  |  | (C++11 起)
size_type erase( const key_type& key ); | (3) | (C++11 起)
template< class K > size_type erase( K&& x ); | (4) | (C++23 起)

从容器移除指定的元素。

1) 移除位于 pos 的元素。若 iterator 与 const_iterator 为同一类型则仅提供一个重载。
2) 移除范围 [first; last) 中的元素，它必须是 *this 中的合法范围。
3) 移除键等价于 key 的所有元素。
4) 移除键比较等价于值 x 的所有元素。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

到被擦除元素的引用和迭代器被非法化。其他迭代器和引用不被非法化。

迭代器 pos 必须合法且可解引用。从而 end() 迭代器（合法，但不可解引用）不能用作 pos 所用的值。 保留未被擦除的元素顺序（这使得可能在迭代通过容器时擦除单独的元素）。

参数

pos | - | 指向要移除的元素的迭代器
first, last | - | 要移除的元素范围
key | - | 要移除的元素键值
x | - | 任何能与键通透比较的类型的值，指代要移除的元素

返回值

1-2) 后随最后被移除的元素的迭代器。
3,4) 被移除的元素数。

异常

1,2) 不抛出
3,4) 任何 Hash 与 KeyEqual 对象所抛的异常

复杂度

给定 unordered_multiset 的实例 c ：

1) 平均情况：常数，最坏情况： c.size()
2) 平均情况： std::distance (first, last) ，最坏情况： c.size()
3) 平均情况： c.count(key) ，最坏情况： c.size()
4) 平均情况： c.count(x) ，最坏情况： c.size()

示例

#include <unordered_set>
#include <iostream>
int main()
{
    std::unordered_multiset<int> c = { 1, 2, 3, 4,    1, 2, 3, 4 };

    auto print = [&c] {
        std::cout << "c = { ";
        for(int n : c)
            std::cout << n << ' ';
        std::cout << "}\n";
    };
    print();

    std::cout << "Erase all odd numbers:\n";
    for(auto it = c.begin(); it != c.end(); ) {
        if(*it % 2 != 0)
            it = c.erase(it);
        else
            ++it;
    }
    print();

    std::cout << "Erase 1, erased count: " << c.erase(1) << '\n';
    std::cout << "Erase 2, erased count: " << c.erase(2) << '\n';
    std::cout << "Erase 2, erased count: " << c.erase(2) << '\n';
    print();
}

可能的输出：

c = { 1 1 2 2 3 3 4 4 }
Erase all odd numbers:
c = { 2 2 4 4 }
Erase 1, erased count: 0
Erase 2, erased count: 2
Erase 2, erased count: 0
c = { 4 4 }

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2059 | C++11 | 对一个 const_iterator 的重载引入了新的歧义 | 添加了对 iterator 的重载
LWG 2356 | C++11 | 未被擦除的元素顺序未指定 | 要求保留

参阅

clear
(C++11)
 清除内容
(公开成员函数)


std::erase_if (std::unordered_multiset)

< cpp‎ | container‎ | unordered multiset

定义于头文件 <unordered_set>
template< class Key, class Hash, class KeyEqual, class Alloc, class Pred >

typename std::unordered_multiset <Key,Hash,KeyEqual,Alloc>::size_type

erase_if( std::unordered_multiset <Key,Hash,KeyEqual,Alloc>& c, Pred pred);
 (C++20 起)

从容器中擦除所有满足谓词 pred 的元素。等价于

auto old_size = c.size();
for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}
return old_size - c.size();

参数

c | - | 要从中擦除的元素
pred | - | 若应该擦除元素则对它返回 true 的谓词

返回值

擦除的元素数。

复杂度

线性。

示例

#include <unordered_set>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& container)
{
    os << "{ ";
    for (const auto& item : container) {
        os << item << ' ';
    }
    return os << "}";
}

int main()
{
    std::unordered_multiset data { 0, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7 };
    std::cout << "Original:\n" << data << '\n';

    auto divisible_by_3 = [](auto const& x) { return (x % 3) == 0; };

    const auto count = std::erase_if(data, divisible_by_3);

    std::cout << "Erase all items divisible by 3:\n" << data << '\n'
              << count << " items erased.\n";
}

输出：

Original:
{ 7 6 6 5 5 4 3 3 2 1 0 }
Erase all items divisible by 3:
{ 7 5 5 4 2 1 }
5 items erased.

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::extract

< cpp‎ | container‎ | unordered multiset

node_type extract( const_iterator position ); | (1) | (C++17 起)
node_type extract( const key_type& k ); | (2) | (C++17 起)
template< class K > node_type extract( K&& x ); | (3) | (C++23 起)
1) 解链含 position 所指向元素的结点并返回占有它的结点柄。
2) 若容器拥有元素而其关键等于 x ，则从容器解链首个这种元素并返回占有它的结点柄。否则，返回空结点柄。
3) 同 (2) 。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

任何情况下，均不复制或移动元素，只重指向容器结点的内部指针。

释出结点只会非法化指向被释出元素的迭代器，并保持未被擦除元素的相对顺序。指向被释出元素的指针和引用保持合法，但在结点柄占有该元素时不能使用：若元素被插入容器，就能使用它们。

参数

position | - | 指向此容器中的合法迭代器
k | - | 鉴别要被释出的结点的键
x | - | 任何能与键通透比较的类型的值，鉴别要释出的结点

返回值

占有被释出元素的结点柄，或 (2,3) 中找不到元素的情况下为空结点柄。

复杂度

1,2,3) 平均情况 O(1) ，最坏情况 O(a.size()) 。

注解

extract 是从 set 带走仅移动对象的唯一方式：

set<move_only_type> s;
s.emplace(...);
move_only_type mot = move(s.extract(s.begin()).value());

示例

#include <algorithm>
#include <iostream>
#include <unordered_set>

int main()
{
    std::unordered_multiset<int> cont{1, 2, 3};

    auto print = [](const int& n) { std::cout << " " << n; };

    std::cout << "Start:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 释出结点柄并更改键
    auto nh = cont.extract(1);
    nh.value() = 4;

    std::cout << "After extract and before insert:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 往回插入结点柄
    cont.insert(move(nh));

    std::cout << "End:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';
}

可能的输出：

Start: 1 2 3
After extract and before insert: 2 3
End: 2 3 4

参阅

merge (C++17) | 从另一容器接合结点 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)
erase (C++11) | 擦除元素 (公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::find

< cpp‎ | container‎ | unordered multiset

iterator find( const Key& key ); | (1) |
const_iterator find( const Key& key ) const; | (2) |
template< class K > iterator find( const K& x ); | (3) | (C++20 起)
template< class K > const_iterator find( const K& x ) const; | (4) | (C++20 起)
1,2) 寻找键等于 key 的的元素。
3,4) 寻找键比较等价于值 x 的元素。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 能通透地与键比较的任何类型值

返回值

指向键等于 key 的元素的迭代器。若找不到这种元素，则返回尾后（见 end() ）迭代器。

复杂度

平均为常数，最坏情况与容器大小成线性。

示例

#include <iostream>
#include <unordered_set>

int main()
{
// 简单比较演示
    std::unordered_multiset<int> example = {1, 2, 3, 4};

    auto search = example.find(2);
    if (search != example.end()) {
        std::cout << "Found " << (*search) << '\n';
    } else {
        std::cout << "Not found\n";
    }

}

输出：

Found 2

参阅

count (C++11) | 返回匹配特定键的元素数量 (公开成员函数)
equal_range (C++11) | 返回匹配特定键的元素范围 (公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::get_allocator

< cpp‎ | container‎ | unordered multiset

allocator_type get_allocator() const noexcept; | (C++11 起)

返回与容器关联的分配器。

参数

（无）

返回值

关联的分配器。

复杂度

常数。


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::hash_function

< cpp‎ | container‎ | unordered multiset

hasher hash_function() const; | (C++11 起)

返回对关键哈希的函数。

参数

（无）

返回值

哈希函数。

复杂度

常数。

参阅

key_eq
(C++11)
 返回用于比较键的相等性的函数
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::insert

< cpp‎ | container‎ | unordered multiset
iterator insert( const value_type& value ); | (1) | (C++11 起)
iterator insert( value_type&& value ); | (2) | (C++11 起)
iterator insert( const_iterator hint, const value_type& value ); | (3) | (C++11 起)
iterator insert( const_iterator hint, value_type&& value ); | (4) | (C++11 起)
template< class InputIt > void insert( InputIt first, InputIt last ); | (5) | (C++11 起)
void insert( std::initializer_list <value_type> ilist ); | (6) | (C++11 起)
iterator insert(node_type&& nh); | (7) | (C++17 起)
iterator insert(const_iterator hint, node_type&& nh); | (8) | (C++17 起)

插入元素到容器中。

1-2) 插入 value 。
3-4) 插入 value ，以 hint 为应当开始搜索的位置的非强制建议。
5) 插入来自范围 [first, last) 的元素。
6) 插入来自 initializer_list ilist 的元素。
7) 若 nh 是空的结点把柄，则不做任何事。否则插入 nh 所占有的元素到容器并返回指向被插入元素的迭代器。。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。
8) 若 nh 是空的结点把柄，则不做任何事并返回尾迭代器。否则，插入 nh 所占有的元素到容器，并返回指向拥有等于 nh.key() 的关键的元素的迭代器元素被插入到尽可能接近 hint 的位置。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。

若因插入发生重哈希，则所有迭代器都被非法化。否则迭代器不受影响。引用不受影响。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。若插入成功，则在结点把柄保有元素时获得的指向该元素的指针和引用被非法化，而在提取前获得的指向元素的指针和引用变得合法。 (C++17 起)

参数

hint | - | 迭代器，用作插入内容位置的建议
value | - | 要插入的元素值
first, last | - | 要插入的元素范围
ilist | - | 插入值来源的 initializer_list
nh | - | 兼容的结点把柄
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

1-4) 返回指向被插入元素的迭代器。
5-6) （无）
7,8) 若 nh 为空则为尾迭代器，否则为指向被插入元素的迭代器。

异常

1-4) 若任何操作抛出异常，则插入无效果。
本节未完成
原因：情况 5-6

复杂度

1-4) 平均情况： O(1) ，最坏情况 O(size())
5-6) 平均情况： O(N) ，其中 N 是要插入的元素数。最坏情况： O(N*size()+N)
7-8) 平均情况： O(1) ，最坏情况 O(size())

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::key_eq

< cpp‎ | container‎ | unordered multiset

key_equal key_eq() const; | (C++11 起)

返回比较关键相等性的函数。

参数

（无）

返回值

关键比较函数。

复杂度

常数。

参阅

hash_function
(C++11)
 返回用于对键散列的函数
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::load_factor

< cpp‎ | container‎ | unordered multiset

float load_factor() const; | (C++11 起)

返回每个桶元素的平均数，即 size() 除以 bucket_count() 。

参数

（无）

返回值

每个桶元素的平均数。

复杂度

常数。

参阅

max_load_factor
(C++11)
 管理每个桶的平均元素数量的最大值
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::max_bucket_count

< cpp‎ | container‎ | unordered multiset

size_type max_bucket_count() const; | (C++11 起)

返回容器由于系统或库实现限制的能保有的最大桶数。

参数

（无）

返回值

最大桶数。

复杂度

常数。

参阅

bucket_count
(C++11)
 返回桶数
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::max_load_factor

< cpp‎ | container‎ | unordered multiset

float max_load_factor() const; | (1) | (C++11 起)
void max_load_factor( float ml ); | (2) | (C++11 起)

管理最大加载因子（每个桶的平均元素数）。若加载因子超出此阈值，则容器自动增加桶数。

1) 返回最大加载因子。

2) 设置最大加载因子为 ml 。

参数

ml - 新设置的最大加载因子

返回值

1) 当前最大加载因子。

2) 无。

复杂度

常数

参阅

load_factor
(C++11)
 返回每个桶的平均元素数量
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::max_size

< cpp‎ | container‎ | unordered multiset

size_type max_size() const noexcept; | (C++11 起)

返回根据系统或库实现限制的容器可保有的元素最大数量，即对于最大容器的 std::distance (begin(), end()) 。

参数

（无）

返回值

元素数量的最大值。

复杂度

常数。

注解

此值通常反映容器大小上的理论极限，至多为 std::numeric_limits <difference_type>::max() 。运行时，可用 RAM 总量可能会限制容器大小到小于 max_size() 的值。

示例

#include <iostream>
#include <unordered_set>

int main()
{
    std::unordered_multiset<char> s;
    std::cout << "Maximum size of a 'unordered_multiset' is " << s.max_size() << "\n";
}

可能的输出：

Maximum size of a 'unordered_multiset' is 768614336404564650

参阅

size
(C++11)
 返回容纳的元素数
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::merge

< cpp‎ | container‎ | unordered multiset

template<class H2, class P2> void merge( std::unordered_set <Key, H2, P2, Allocator>& source ); | (1) | (C++17 起)
template<class H2, class P2> void merge( std::unordered_set <Key, H2, P2, Allocator>&& source ); | (2) | (C++17 起)
template<class H2, class P2> void merge( std::unordered_multiset <Key, H2, P2, Allocator>& source ); | (3) | (C++17 起)
template<class H2, class P2> void merge( std::unordered_multiset <Key, H2, P2, Allocator>&& source ); | (4) | (C++17 起)

试图提取（“接合”） source 中每个元素，并用 *this 的散列函数与键相等谓词插入到 *this 。

不复制或移动元素，只会重指向容器结点的内部指针。指向被转移元素的所有指针和引用保持合法，但现在指代到 *this 中而非到 source 中。指代被转移元素的迭代器和所有指代到 *this 的迭代器被非法化。

若 get_allocator() != source.get_allocator() 则行为未定义。

参数

source - 传递结点来源的兼容容器

返回值

（无）

复杂度

平均情况 O(N) ，最坏情况 O(N*size()+N) ，其中 N 为 source.size() 。

示例

#include <iostream>
#include <unordered_set>

// 打印出容器
template <class Os, class K>
Os& operator<<(Os& os, const std::unordered_multiset<K>& v) {
    os << '[' << v.size() << "] {";
    bool o{};
    for (const auto& e : v)
        os << (o ? ", " : (o = 1, " ")) << e;
    return os << " }\n";
}

int main()
{
    std::unordered_multiset<char>
        p{ 'C', 'B', 'B', 'A' },
        q{ 'E', 'D', 'E', 'C' };

    std::cout << "p: " << p << "q: " << q;

    p.merge(q);

    std::cout << "p.merge(q);\n" << "p: " << p << "q: " << q;
}

可能的输出：

p: [4] { A, B, B, C }
q: [4] { C, D, E, E }
p.merge(q);
p: [8] { E, E, D, A, B, B, C, C }
q: [0] { }

参阅

extract (C++17) | 从另一容器释出结点 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::operator=

< cpp‎ | container‎ | unordered multiset

unordered_multiset& operator=( const unordered_multiset& other ); | (1) | (C++11 起)
 | (2) |
unordered_multiset& operator=( unordered_multiset&& other ); |  |  | (C++11 起) (C++17 前)
unordered_multiset& operator=( unordered_multiset&& other ) noexcept(/* see below */); |  |  | (C++17 起)
unordered_multiset& operator=( std::initializer_list <value_type> ilist ); | (3) | (C++11 起)

替换容器内容。

1) 复制赋值运算符。以 other 的副本替换内容。
若 std::allocator_traits <allocator_type>::propagate_on_container_copy_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若 *this 的分配器在赋值后将与其旧值比较不相等，则用旧分配器解分配内存，然后在复制元素前用新分配器分配内存。否则，在可行时可能复用 *this 所拥有的内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素复制赋值替换。
2) 移动赋值运算符。用移动语义以 other 的内容替换内容（即从 other 移动 other 中的数据到此容器中）。之后 other 在合法但未指定的状态。
若 std::allocator_traits <allocator_type>::propagate_on_container_move_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若它为 false 且 *this 与 other 的分配器不比较相等，则 *this 不能接管 other 所拥有的内存的所有权且必须单独地移动赋值每个元素，并用其自身的分配器按需分配额外内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素移动赋值替换。
3) 以 initializer_list ilist 所标识者替换内容。

参数

other | - | 用作数据源的另一容器
ilist | - | 用作数据源的 initializer_list

返回值

*this

复杂度

1) 与 *this 和 other 的大小成线性。
2) 与 *this 的大小成线性，除非分配器不比较相等且不传播，该情况下与 *this 和 other 的大小成线性。
3) 与 *this 和 ilist 的大小成线性。

异常

可能抛出实现定义的异常。

 (C++17 前)
1,3) 可能抛出实现定义的异常。
2)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value

&& std::is_nothrow_move_assignable <Hash>::value

&& std::is_nothrow_move_assignable <Pred>::value)
 (C++17 起)

注解

在容器移动赋值（重载 (2) ）后，除非不兼容的分配器强制逐元素移动赋值，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

下列代码用 operator= 赋值一个 std::unordered_multiset 给另一个：

#include <unordered_set>
#include <iostream>

void display_sizes(const std::unordered_multiset<int> &nums1,
                   const std::unordered_multiset<int> &nums2,
                   const std::unordered_multiset<int> &nums3)
{
    std::cout << "nums1: " << nums1.size()
              << " nums2: " << nums2.size()
              << " nums3: " << nums3.size() << '\n';
}

int main()
{
    std::unordered_multiset<int> nums1 {3, 1, 4, 6, 5, 9};
    std::unordered_multiset<int> nums2;
    std::unordered_multiset<int> nums3;

    std::cout << "Initially:\n";
    display_sizes(nums1, nums2, nums3);

    // 复制赋值从 nums1 复制数据到 nums2
    nums2 = nums1;

    std::cout << "After assigment:\n";
    display_sizes(nums1, nums2, nums3);

    // 移动赋值从 nums1 移动数据到 nums3,
    // 一同修改 nums1 和 nums3
    nums3 = std::move(nums1);

    std::cout << "After move assigment:\n";
    display_sizes(nums1, nums2, nums3);
}

输出：

Initially:
nums1: 6 nums2: 0 nums3: 0
After assigment:
nums1: 6 nums2: 6 nums3: 0
After move assigment:
nums1: 0 nums2: 6 nums3: 6

参阅

(构造函数)
(C++11)
 构造 unordered_multiset
(公开成员函数)


operator==,!=(std::unordered_multiset)

< cpp‎ | container‎ | unordered multiset

template< class Key, class Hash, class KeyEqual, class Allocator >

bool operator==( const std::unordered_multiset <Key,Hash,KeyEqual,Allocator>& lhs,

const std::unordered_multiset <Key,Hash,KeyEqual,Allocator>& rhs );
 (1)
template< class Key, class Hash, class KeyEqual, class Allocator >

bool operator!=( const std::unordered_multiset <Key,Hash,KeyEqual,Allocator>& lhs,

const std::unordered_multiset <Key,Hash,KeyEqual,Allocator>& rhs );
 (2) (C++20 前)

比较二个无序容器的内容。

若下列条件成立则二个无序容器 lhs 与 rhs 相等：

  • lhs.size() == rhs.size()
  • 从 lhs.equal_range(lhs_eq1) 获得的每组等价元素 [lhs_eq1, lhs_eq2) 拥有在另一容器中从 rhs.equal_range(rhs_eq1) 获得的对应等价元素组 [rhs_eq1, rhs_eq2) ，且它们拥有下列属性：
  • std::distance (lhs_eq1, lhs_eq2) == std::distance (rhs_eq1, rhs_eq2) 。
  • std::is_permutation (lhs_eq1, lhs_eq2, rhs_eq1) == true 。

若 Key 非可相等比较 (EqualityComparable) 则行为未定义。

若 hash_function() 和 key_eq() (C++20 前)key_eq() (C++20 起) 在 lhs 和 rhs 上拥有不相同的行为，或若 Key 的 operator== 不是对于 key_eq() 所引入的等价关键组的细分（即若用 operator== 比较相等的二个元素落入不同划分），则行为未定义。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的无序容器

返回值

1) 若容器内容相等则为 true ，否则为 false 。
2) 若容器内容不相等则为 true ，否则为 false 。

复杂度

调用 value_type 上的 operator== 、调用 key_eq 所返回的谓词，及调用 hash_function 所返回的哈希器的次数，平均情况下与 ΣSi2 成正比，其中 S 是第 i 个等价关键组的大小。最坏情况下与 N2 成正比，其中 N 是容器大小。若每个等价关键组中元素以相同顺序排列（在容器互为副本时发生），则平均情况变为与 N 成正比。


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::rehash

< cpp‎ | container‎ | unordered multiset

void rehash( size_type count ); | (C++11 起)

设置桶数为 count 并重哈希容器，即考虑桶总数已改变，再把元素放到适当的桶中。若新的桶数使加载因子大于最大加载因子（ count < size() / max_load_factor() ），则新桶数至少为 size() / max_load_factor() 。

参数

count - 新的桶数

返回值

（无）

复杂度

平均与容器大小成线性，最坏情况成平方。

注意

rehash(0) 可用于强制无条件的重哈希，例如在通过临时增加 max_load_factor() 暂停自动重哈希之后。

参阅

reserve
(C++11)
 为至少为指定数量的元素预留存储空间并重新生成哈希表。
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::reserve

< cpp‎ | container‎ | unordered multiset

void reserve( size_type count ); | (C++11 起)

设置桶数为适应至少 count 个元素，而不超出最大加载因子所需的数，并重哈希容器，即考虑桶数已更改后将元素放进适合的桶。等效地调用 rehash( std::ceil (count / max_load_factor())) 。

参数

count - 容器的新容量

返回值

（无）

复杂度

平均情况与容器大小成线性，最坏情况成平方。

参阅

rehash
(C++11)
 为至少为指定数量的桶预留存储空间并重新生成散列表
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::size

< cpp‎ | container‎ | unordered multiset

size_type size() const noexcept; | (C++11 起)

返回容器中的元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

容器中的元素数量。

复杂度

常数。

示例

下列代码用 size 显示 std::unordered_multiset <int> 中的元素数：

#include <unordered_set>
#include <iostream>

int main()
{
    std::unordered_multiset<int> nums {1, 3, 5, 7};

    std::cout << "nums contains " << nums.size() << " elements.\n";
}

输出：

nums contains 4 elements.

参阅

empty (C++11) | 检查容器是否为空 (公开成员函数)
max_size (C++11) | 返回可容纳的最大元素数 (公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::swap

< cpp‎ | container‎ | unordered multiset

void swap( unordered_multiset& other ); | (C++11 起) (C++17 前)
void swap( unordered_multiset& other ) noexcept(/* see below */); | (C++17 起)

将内容与 other 的交换。不在单独的元素上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。尾后迭代器被非法化。

Hash 和 KeyEqual 对象必须可交换 (Swappable) ，并用非成员 swap 的非限定调用交换它们。

若 std::allocator_traits <allocator_type>::propagate_on_container_swap::value 为 true ，则用对非成员 swap 的无限定调用交换分配器。否则，不交换它们（且若 get_allocator() != other.get_allocator() ，则行为未定义）。

 (C++11 起)

参数

other - 要与之交换内容的容器

返回值

（无）

异常

任何 Hash 或 KeyEqual 对象交换所抛的异常。

 (C++17 前)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value

&& std::is_nothrow_swappable <Hash>::value

&& std::is_nothrow_swappable <key_equal>::value)
 (C++17 起)

复杂度

常数。

示例

#include <iostream>
#include <unordered_set>

template<class Os, class Co> Os& operator<<(Os& os, const Co& co) {
    os << "{";
    for (auto const& i : co) { os << ' ' << i; }
    return os << " } ";
}

int main()
{
    std::unordered_multiset<int> a1{3, 1, 3, 2}, a2{5, 4, 5};

    auto it1 = std::next(a1.begin());
    auto it2 = std::next(a2.begin());

    const int& ref1 = *(a1.begin());
    const int& ref2 = *(a2.begin());

    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';
    a1.swap(a2);
    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';

    // 注意交换前指代一个容器中的元素的每个迭代器在交换后都指代同一元素。对于引用同为真。
}

可能的输出：

{ 2 3 3 1 } { 4 5 5 } 3 5 2 4
{ 4 5 5 } { 2 3 3 1 } 3 5 2 4

参阅

std::swap(std::unordered_multiset)
(C++11)
 特化 std::swap 算法
(函数模板)


std::swap(std::unordered_multiset)

< cpp‎ | container‎ | unordered multiset

定义于头文件 <unordered_set>
template< class Key, class Hash, class KeyEqual, class Alloc >

void swap( std::unordered_multiset <Key,Hash,KeyEqual,Alloc>& lhs,

std::unordered_multiset <Key,Hash,KeyEqual,Alloc>& rhs );
 (C++11 起)
(C++17 前)
template< class Key, class Hash, class KeyEqual, class Alloc >

void swap( std::unordered_multiset <Key,Hash,KeyEqual,Alloc>& lhs,

std::unordered_multiset <Key,Hash,KeyEqual,Alloc>& rhs ) noexcept(/* see below */);
 (C++17 起)

为 std::unordered_multiset 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

#include <algorithm>
#include <iostream>
#include <unordered_set>

int main()
{
    std::unordered_multiset<int> alice{1, 2, 3};
    std::unordered_multiset<int> bob{7, 8, 9, 10};

    auto print = [](const int& n) { std::cout << " " << n; };

    // 打印交换前的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';

    std::cout << "-- SWAP\n";
    std::swap(alice,bob);

    // 打印交换后的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
}

可能的输出：

alice: 1 2 3
bob  : 7 8 9 10
-- SWAP
alice: 7 8 9 10
bob  : 1 2 3

参阅

swap
(C++11)
 交换内容
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::unordered_multiset

< cpp‎ | container‎ | unordered multiset

unordered_multiset() : unordered_multiset( size_type(/*implementation-defined*/) ) {}

explicit unordered_multiset( size_type bucket_count,
const Hash& hash = Hash(),
const key_equal& equal = key_equal(),

const Allocator& alloc = Allocator() );
 (1) (C++11 起)
unordered_multiset( size_type bucket_count,

const Allocator& alloc )
: unordered_multiset(bucket_count, Hash(), key_equal(), alloc) {}
unordered_multiset( size_type bucket_count,
const Hash& hash,
const Allocator& alloc )

: unordered_multiset(bucket_count, hash, key_equal(), alloc) {}
 (1) (C++14 起)
explicit unordered_multiset( const Allocator& alloc );
 (1) (C++11 起)
template< class InputIt >

unordered_multiset( InputIt first, InputIt last,
size_type bucket_count = /*implementation-defined*/,
const Hash& hash = Hash(),
const key_equal& equal = key_equal(),

const Allocator& alloc = Allocator() );
 (2) (C++11 起)
template< class InputIt >

unordered_multiset( InputIt first, InputIt last,
size_type bucket_count,
const Allocator& alloc )
: unordered_multiset(first, last,

bucket_count, Hash(), key_equal(), alloc) {}
 (2) (C++14 起)
template< class InputIt >

unordered_multiset( InputIt first, InputIt last,
size_type bucket_count,
const Hash& hash,
const Allocator& alloc )
: unordered_multiset(first, last,

bucket_count, hash, key_equal(), alloc) {}
 (2) (C++14 起)
unordered_multiset( const unordered_multiset& other );
 (3) (C++11 起)
unordered_multiset( const unordered_multiset& other, const Allocator& alloc );
 (3) (C++11 起)
unordered_multiset( unordered_multiset&& other );
 (4) (C++11 起)
unordered_multiset( unordered_multiset&& other, const Allocator& alloc );
 (4) (C++11 起)
unordered_multiset( std::initializer_list <value_type> init,

size_type bucket_count = /*implementation-defined*/,
const Hash& hash = Hash(),
const key_equal& equal = key_equal(),

const Allocator& alloc = Allocator() );
 (5) (C++11 起)
unordered_multiset( std::initializer_list <value_type> init,

size_type bucket_count,
const Allocator& alloc )
: unordered_multiset(init, bucket_count,

Hash(), key_equal(), alloc) {}
 (5) (C++14 起)
unordered_multiset( std::initializer_list <value_type> init,

size_type bucket_count,
const Hash& hash,
const Allocator& alloc )
: unordered_multiset(init, bucket_count,

hash, key_equal(), alloc) {}
 (5) (C++14 起)

从各种数据源构造新容器。可选的以用户提供的 bucket_count 为用于创建的最小桶数，以 hash 为哈希函数，以 equal 为比较关键的函数，和以 alloc 为分配器。

1) 构造空容器。设置 max_load_factor() 为 1.0 。对于默认构造函数，桶数是实现定义的。
2) 构造拥有范围 [first, last) 的内容的容器。设置 max_load_factor() 为 1.0 。
3) 复制构造函数。构造拥有 other 内容副本的容器，一同复制加载因子、谓词和哈希函数。若不提供 alloc ，则通过调用 std::allocator_traits <allocator_type>::select_on_container_copy_construction(other.get_allocator()) 获得分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
4) 移动构造函数。用移动语义构造拥有 other 内容的容器。若不提供 alloc ，则通过从属于 other 的分配器移动构造获得分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
5) 构造拥有 initializer_list init 内容的容器，同 unordered_multiset(init.begin(), init.end()) 。

参数

alloc | - | 用于此容器所有内存分配器的分配器
bucket_count | - | 初始化时用的最小桶数。若不指定，则使用实现定义的默认值
hash | - | 要用的哈希函数
equal | - | 用于此容器所有关键比较的比较函数
first, last | - | 复制元素来源的范围
other | - | 用作源以初始化容器元素的另一容器
init | - | 用以初始化容器元素的 initializer_list
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

复杂度

1) 常数
2) 平均情况与 first 和 last 间的距离成线性，最坏情况成平方。
3) 与 other 的大小成线性。
4) 常数。若给定 alloc 且 alloc != other.get_allocator() 则为线性。
5) 平均情况与 init 的大小成线性，最坏情况成平方。

异常

对 Allocator::allocate 的调用可能抛出。

注解

在容器移动构造（重载 (4) ）后，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

尽管在 C++23 前未正式要求，一些实现已经在较早的模式中将 Allocator 放入非推导语境。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2193 | C++11 | 默认构造函数为 explicit | 使之为非 explicit

参阅

operator=
(C++11)
 赋值给容器
(公开成员函数)


std::unordered_multiset<Key,Hash,KeyEqual,Allocator>::~unordered_multiset

< cpp‎ | container‎ | unordered multiset

~unordered_multiset(); | (C++11 起)

销毁 unordered_multiset 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 unordered_multiset 大小成线性。


std::unordered_set

< cpp‎ | container
定义于头文件 <unordered_set>
template<

class Key,
class Hash = std::hash <Key>,
class KeyEqual = std::equal_to <Key>,
class Allocator = std::allocator <Key>

> class unordered_set;
 (1) (C++11 起)
namespace pmr {

template <class Key,
class Hash = std::hash <Key>,
class Pred = std::equal_to <Key>>
using unordered_set = std::unordered_set<Key, Hash, Pred,
std::pmr::polymorphic_allocator <Key>>;

}
 (2) (C++17 起)

unordered_set 是含有 Key 类型唯一对象集合的关联容器。搜索、插入和移除拥有平均常数时间复杂度。

在内部，元素并不以任何特别顺序排序，而是组织进桶中。元素被放进哪个桶完全依赖其值的哈希。这允许对单独元素的快速访问，因为哈希一旦确定，就准确指代元素被放入的桶。

不可修改容器元素（即使通过非 const 迭代器），因为修改可能更改元素的哈希，并破坏容器。

std::unordered_set 满足容器 (Container) 、知分配器容器 (AllocatorAwareContainer) 、无序关联容器 (UnorderedAssociativeContainer) 的要求。

成员类型

成员类型 | 定义
key_type | Key
value_type | Key
size_type | 无符号整数类型（通常是 std::size_t ）
difference_type | 有符号整数类型（通常是 std::ptrdiff_t ）
hasher | Hash
key_equal | KeyEqual
allocator_type | Allocator
reference | value_type&
const_reference | const value_type&
pointer | std::allocator_traits <Allocator>::pointer
const_pointer | std::allocator_traits <Allocator>::const_pointer
iterator | 指向 value_type 的常老式向前迭代器 (LegacyForwardIterator)
const_iterator | 指向 const value_type 的老式向前迭代器 (LegacyForwardIterator)
local_iterator 类别、值、差、指针和引用类型都与 iterator 相同的迭代器类型。
能用此迭代器在单个桶迭代，但不能跨桶。
const_local_iterator 类别、值、差、指针和引用类型都与 const_iterator 相同的迭代器类型。
能用此迭代器在单个桶迭代，但不能跨桶。
node_type(C++17 起) | 表示容器结点的结点把柄特化
insert_return_type(C++17 起) 描述插入 node_type 结果的类型，下列类型的特化
template <class Iter, class NodeType> struct /*unspecified*/ {
    Iter     position;
    bool     inserted;
    NodeType node;
};
，以模板实参 iterator 和 node_type 实例化。

成员函数

(构造函数)
(C++11)
 构造 unordered_set
(公开成员函数)
(析构函数)
(C++11)
 析构 unordered_set
(公开成员函数)
operator=
(C++11)
 赋值给容器
(公开成员函数)
get_allocator
(C++11)
 返回相关的分配器
(公开成员函数)
迭代器
begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)
容量
empty
(C++11)
 检查容器是否为空
(公开成员函数)
size
(C++11)
 返回容纳的元素数
(公开成员函数)
max_size
(C++11)
 返回可容纳的最大元素数
(公开成员函数)
修改器
clear
(C++11)
 清除内容
(公开成员函数)
insert
(C++11)
 插入元素或结点 (C++17 起)
(公开成员函数)
emplace
(C++11)
 原位构造元素
(公开成员函数)
emplace_hint
(C++11)
 使用提示原位构造元素
(公开成员函数)
erase
(C++11)
 擦除元素
(公开成员函数)
swap
(C++11)
 交换内容
(公开成员函数)
extract
(C++17)
 从另一容器释出结点
(公开成员函数)
merge
(C++17)
 从另一容器接合结点
(公开成员函数)
查找
count
(C++11)
 返回匹配特定键的元素数量
(公开成员函数)
find
(C++11)
 寻找带有特定键的元素
(公开成员函数)
contains
(C++20)
 检查容器是否含有带特定键的元素
(公开成员函数)
equal_range
(C++11)
 返回匹配特定键的元素范围
(公开成员函数)
桶接口
begin(size_type) cbegin(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的开始
(公开成员函数)
end(size_type) cend(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的末尾
(公开成员函数)
bucket_count
(C++11)
 返回桶数
(公开成员函数)
max_bucket_count
(C++11)
 返回桶的最大数量
(公开成员函数)
bucket_size
(C++11)
 返回在特定的桶中的元素数量
(公开成员函数)
bucket
(C++11)
 返回带有特定键的桶
(公开成员函数)
哈希策略
load_factor
(C++11)
 返回每个桶的平均元素数量
(公开成员函数)
max_load_factor
(C++11)
 管理每个桶的平均元素数量的最大值
(公开成员函数)
rehash
(C++11)
 为至少为指定数量的桶预留存储空间并重新生成散列表
(公开成员函数)
reserve
(C++11)
 为至少为指定数量的元素预留存储空间并重新生成哈希表。
(公开成员函数)
观察器
hash_function
(C++11)
 返回用于对键散列的函数
(公开成员函数)
key_eq
(C++11)
 返回用于比较键的相等性的函数
(公开成员函数)

非成员函数

operator==operator!= (C++20 中移除) | 比较 unordered_set 中的值 (函数模板)
std::swap(std::unordered_set) (C++11) | 特化 std::swap 算法 (函数模板)
erase_if(std::unordered_set) (C++20) | 擦除所有满足特定判别标准的元素 (函数模板)

推导指引 (C++17 起)

注意

成员类型 iterator 与 const_iterator 可能是同一类型的别名。这表明以二个类型为参数类型的一对函数重载可能违背单一定义规则。因为 iterator 可转换为 const_iterator ，单个以 const_iterator 为参数类型的函数会是有效的。


std::unordered_set<Key,Hash,KeyEqual,Allocator>::begin, std::unordered_set<Key,Hash,KeyEqual,Allocator>::cbegin

< cpp‎ | container‎ | unordered set

iterator begin() noexcept; | (C++11 起)
const_iterator begin() const noexcept; | (C++11 起)
const_iterator cbegin() const noexcept; | (C++11 起)

返回指向 unordered_set 首元素的迭代器。

若 unordered_set 为空，则返回的迭代器将等于 end() 。

参数

（无）

返回值

指向首元素的迭代器。

复杂度

常数。

注意

因为 iterator 和 const_iterator 都是常迭代器（而且实际上可以是同一类型），故不可能通过任何这些成员函数返回的迭代器修改容器元素。

示例

#include <iostream>
#include <unordered_set>

struct Point { double x, y; };

int main() {
    Point pts[3] = { {1, 0}, {2, 0}, {3, 0} };

    // points 是含有点的地址的 set
    std::unordered_set<Point *> points = { pts, pts + 1, pts + 2 };

    // 更改每个 (i, 0) 的 y 坐标从 0 到 i^2 并打印点
    for(auto iter = points.begin(); iter != points.end(); ++iter){
        (*iter)->y = ((*iter)->x) * ((*iter)->x); // iter 为指向 Point* 的指针
        std::cout << "(" << (*iter)->x << ", " << (*iter)->y << ") ";
    }
    std::cout << '\n';

    // 现在用基于范围的 for 循环，我们把每个 y 坐标增加 10
    for(Point * i : points) {
        i->y += 10;
        std::cout << "(" << i->x << ", " << i->y << ") ";
    }
}

可能的输出：

(3, 9) (1, 1) (2, 4)
(3, 19) (1, 11) (2, 14)

参阅

end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::begin(size_type), std::unordered_set<Key,Hash,KeyEqual,Allocator>::cbegin(size_type)

< cpp‎ | container‎ | unordered set

local_iterator begin( size_type n ); | (C++11 起)
const_local_iterator begin( size_type n ) const; | (C++11 起)
const_local_iterator cbegin( size_type n ) const; | (C++11 起)

返回指向下标为 n 的桶首元素的迭代器。

参数

n - 要访问的桶的下标

返回值

指向首元素的迭代器。

复杂度

常数。

参阅

end(size_type) cend(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的末尾
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::bucket

< cpp‎ | container‎ | unordered set

size_type bucket( const Key& key ) const; | (C++11 起)

返回关键 key 的桶的下标。始终会在此桶中找到关键等于 key 的元素（若存在）。返回值仅对 bucket_count() 返回相同值的容器实例合法。

若 bucket_count() 为零则行为未定义。

参数

key - 要检验的关键值

返回值

关键 key 的桶编号。

复杂度

常数。

参阅

bucket_size
(C++11)
 返回在特定的桶中的元素数量
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::bucket_count

< cpp‎ | container‎ | unordered set

size_type bucket_count() const; | (C++11 起)

返回容器中的桶数。

参数

（无）

返回值

容器中的桶数。

复杂度

常数。

参阅

bucket_size (C++11) | 返回在特定的桶中的元素数量 (公开成员函数)
max_bucket_count (C++11) | 返回桶的最大数量 (公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::bucket_size

< cpp‎ | container‎ | unordered set

size_type bucket_size( size_type n ) const; | (C++11 起)

返回下标为 n 的桶中的元素数。

参数

n - 要检验的桶的下标

返回值

桶 n 中的元素数。

复杂度

与桶 n 的大小成线性。

参阅

bucket_count
(C++11)
 返回桶数
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::clear

< cpp‎ | container‎ | unordered set

void clear() noexcept; | (C++11 起)

从容器擦除所有元素。此调用后 size() 返回零。

非法化任何指代所含元素的引用、指针或迭代器。可能亦非法化尾后迭代器。

参数

（无）

返回值

（无）

复杂度

与容器大小，即元素数成线性。

示例

#include <algorithm>
#include <iostream>
#include <unordered_set>

int main()
{
    std::unordered_set<int> container{1, 2, 3};

    auto print = [](const int& n) { std::cout << " " << n; };

    std::cout << "Before clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';

    std::cout << "Clear\n";
    container.clear();

    std::cout << "After clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';
}

可能的输出：

Before clear: 1 2 3
Size=3
Clear
After clear:
Size=0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2550 | C++11 | 对于无序关联容器，不清楚复杂度是与元素数还是桶数成线性 | 辨明它与元素数成线性

参阅

erase
(C++11)
 擦除元素
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::contains

< cpp‎ | container‎ | unordered set

bool contains( const Key& key ) const; | (1) | (C++20 起)
template< class K > bool contains( const K& x ) const; | (2) | (C++20 起)
1) 检查容器中是否有键等价于 key 的元素。
2) 检查是否有键比较等价于值 x 的元素。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 任何能通透地与键比较的类型的值

返回值

若有这种元素则为 true ，否则为 false 。

复杂度

平均为常数，最坏情况与容器大小成线性。

示例

#include <iostream>
#include <unordered_set>

int main()
{
    std::unordered_set<int> example = {1, 2, 3, 4};

    for(int x: {2, 5}) {
        if(example.contains(x)) {
            std::cout << x << ": Found\n";
        } else {
            std::cout << x << ": Not found\n";
        }
    }
}

输出：

2: Found
5: Not found

参阅

find (C++11) | 寻找带有特定键的元素 (公开成员函数)
count (C++11) | 返回匹配特定键的元素数量 (公开成员函数)
equal_range (C++11) | 返回匹配特定键的元素范围 (公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::count

< cpp‎ | container‎ | unordered set

size_type count( const Key& key ) const; | (1) | (C++11 起)
template< class K > size_type count( const K& x ) const; | (2) | (C++20 起)
1) 返回拥有比较等于指定参数 key 的关键的元素数，因为此容器不允许重复故为 1 或 0 。
2) 返回键比较等价于指定参数 x 的元素数。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要计量等价元素数的键值
x | - | 能通透地与键比较的任何类型值

返回值

1) 拥有关键 key 的元素数，即 1 或 0 。
2) 键比较等价于 x 的元素数。

复杂度

平均为常数，最坏情况与容器大小成线性。

参阅

find (C++11) | 寻找带有特定键的元素 (公开成员函数)
equal_range (C++11) | 返回匹配特定键的元素范围 (公开成员函数)


std::unordered_set 的推导指引

< cpp‎ | container‎ | unordered set

定义于头文件 <unordered_set>
template<class InputIt,

class Hash = std::hash <typename std::iterator_traits <InputIt>::value_type>,
class Pred = std::equal_to <typename std::iterator_traits <InputIt>::value_type>,
class Alloc = std::allocator <typename std::iterator_traits <InputIt>::value_type>>
unordered_set(InputIt, InputIt,
typename /*see below*/::size_type = /*see below*/,
Hash = Hash(), Pred = Pred(), Alloc = Alloc())

-> unordered_set<typename std::iterator_traits <InputIt>::value_type, Hash, Pred, Alloc>;
 (1) (C++17 起)
template<class T,

class Hash = std::hash <T>,
class Pred = std::equal_to <T>,
class Alloc = std::allocator <T>>
unordered_set( std::initializer_list <T>,
typename /*see below*/::size_type = /*see below*/,
Hash = Hash(), Pred = Pred(), Alloc = Alloc())

-> unordered_set<T, Hash, Pred, Alloc>;
 (2) (C++17 起)
template<class InputIt, class Alloc>

unordered_set(InputIt, InputIt, typename /*see below*/::size_type, Alloc)
-> unordered_set<typename std::iterator_traits <InputIt>::value_type,
std::hash <typename std::iterator_traits <InputIt>::value_type>,
std::equal_to <typename std::iterator_traits <InputIt>::value_type>,

Alloc>;
 (3) (C++17 起)
template<class InputIt, class Hash, class Alloc>

unordered_set(InputIt, InputIt, typename /*see below*/::size_type, Hash, Alloc)
-> unordered_set<typename std::iterator_traits <InputIt>::value_type, Hash,

std::equal_to <typename std::iterator_traits <InputIt>::value_type>, Allocator>;
 (4) (C++17 起)
template<class T, class Allocator>

unordered_set( std::initializer_list <T>, typename /*see below*/::size_type, Allocator)

-> unordered_set<T, std::hash <T>, std::equal_to <T>, Alloc>;
 (5) (C++17 起)
template<class T, class Hash, class Alloc>

unordered_set( std::initializer_list <T>, typename /*see below*/::size_type, Hash, Alloc)

-> unordered_set<T, Hash, std::equal_to <T>, Alloc>;
 (6) (C++17 起)

为 unordered_set 提供这些推导指引以允许从迭代器范围（重载 (1,3,4) ）和 std::initializer_list （重载 (2,5.6) ）推导。此重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 、 Alloc 满足分配器 (Allocator) 、 Hash 或 Pred 均不满足分配器 (Allocator) 、 Hash 不是整数类型才参与重载决议

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

这些指引中的 size_type 参数类型指代推导指引所推导出的类型的 size_type 成员类型。

示例

#include <unordered_set>
int main() {
   std::unordered_set s = {1,2,3,4};            // 指引 #2 推导 std::unordered_set<int>
   std::unordered_set s2(s.begin(), s.end());   // 指引 #1 推导 std::unordered_set<int>
}


std::unordered_set<Key,Hash,KeyEqual,Allocator>::emplace

< cpp‎ | container‎ | unordered set

template< class... Args > std::pair <iterator,bool> emplace( Args&&... args ); | (C++11 起)

若容器中无拥有该关键的元素，则插入以给定的 args 原位构造的新元素到容器。

细心地使用 emplace 允许在构造新元素的同时避免不必要的复制或移动操作。 准确地以与提供给 emplace 者相同的参数，通过 std::forward <Args>(args)... 转发调用新元素的构造函数。 即使容器中已有拥有该关键的元素，也可能构造元素，该情况下新构造的元素将被立即销毁。

若因插入发生重哈希，则所有迭代器都被非法化。否则迭代器不受影响。引用不被非法化。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。

参数

args - 要转发给元素构造函数的参数

返回值

返回由指向被插入元素，或若不发生插入则为既存元素的迭代器，和指代插入是否发生的 bool （若发生插入则为 true ，否则为 false ）。

异常

若任何操作抛出异常，则此函数无效果。

复杂度

平均为均摊常数，最坏情况与容器大小成线性。

示例

本节未完成
原因：暂无示例

参阅

emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::emplace_hint

< cpp‎ | container‎ | unordered set
template <class... Args> iterator emplace_hint( const_iterator hint, Args&&... args ); | (C++11 起)

插入新元素到容器，以 hint 为放置元素位置的建议。原位构造元素，即不进行复制或移动操作。

准确地以提供给函数的参数相同者，以 std::forward <Args>(args)... 转发调用元素的构造函数。

若因插入发生重哈希，则所有迭代器都被非法化。否则迭代器不受影响。引用不被非法化。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。

参数

hint | - | 迭代器，用作插入新元素位置的建议
args | - | 转发给元素构造函数的参数

返回值

指向新插入元素的迭代器。

若因元素已存在而失败，则返回指向拥有等价关键的既存元素。

异常

若任何操作抛出异常，则此函数无效果（强异常保证）。

复杂度

平均为均摊常数，最坏情况下与容器大小成线性。

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::empty

< cpp‎ | container‎ | unordered set

bool empty() const noexcept; | (C++11 起) (C++20 前)
[[nodiscard]] bool empty() const noexcept; | (C++20 起)

检查容器是否无元素，即是否 begin() == end() 。

参数

（无）

返回值

若容器为空则为 true ，否则为 false

复杂度

常数。

示例

下列代码用 empty 检查 std::unordered_set <int> 是否含有任何元素：

#include <unordered_set>
#include <iostream>

int main()
{
    std::unordered_set<int> numbers;
    std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';

    numbers.insert(42);
    numbers.insert(13317);
    std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
}

输出：

Initially, numbers.empty(): 1
After adding elements, numbers.empty(): 0

参阅

size
(C++11)
 返回容纳的元素数
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::end, std::unordered_set<Key,Hash,KeyEqual,Allocator>::cend

< cpp‎ | container‎ | unordered set

iterator end() noexcept; | (C++11 起)
const_iterator end() const noexcept; | (C++11 起)
const_iterator cend() const noexcept; | (C++11 起)

返回指向 unordered_set 末元素后一元素的迭代器。

此元素表现为占位符；试图访问它导致未定义行为。

参数

（无）

返回值

指向后随最后元素的迭代器。

复杂度

常数。

注意

因为 iterator 和 const_iterator 都是常迭代器（而且实际上可以是同一类型），故不可能通过任何这些成员函数返回的迭代器修改容器元素。

示例

#include <iostream>
#include <unordered_set>

struct Point { double x, y; };

int main() {
    Point pts[3] = { {1, 0}, {2, 0}, {3, 0} };

    // points 是含有点的地址的 set
    std::unordered_set<Point *> points = { pts, pts + 1, pts + 2 };

    // 更改每个 (i, 0) 的 y 坐标从 0 到 i^2 并打印点
    for(auto iter = points.begin(); iter != points.end(); ++iter){
        (*iter)->y = ((*iter)->x) * ((*iter)->x); // iter 为指向 Point* 的指针
        std::cout << "(" << (*iter)->x << ", " << (*iter)->y << ") ";
    }
    std::cout << '\n';

    // 现在用基于范围的 for 循环，我们把每个 y 坐标增加 10
    for(Point * i : points) {
        i->y += 10;
        std::cout << "(" << i->x << ", " << i->y << ") ";
    }
}

可能的输出：

(3, 9) (1, 1) (2, 4)
(3, 19) (1, 11) (2, 14)

参阅

begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::end(size_type), std::unordered_set<Key,Hash,KeyEqual,Allocator>::cend(size_type)

< cpp‎ | container‎ | unordered set

local_iterator end( size_type n ); | (C++11 起)
const_local_iterator end( size_type n ) const; | (C++11 起)
const_local_iterator cend( size_type n ) const; | (C++11 起)

返回后随下标为 n 的桶的最后元素的元素的迭代器。此元素表现为占位符，试图访问它会导致未定义行为。

参数

n - 要访问的桶的下标

返回值

指向后随最后元素的元素的迭代器。

复杂度

常数

参阅

begin(size_type) cbegin(size_type)
(C++11)
 返回一个迭代器，指向指定的桶的开始
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::equal_range

< cpp‎ | container‎ | unordered set

std::pair <iterator,iterator> equal_range( const Key& key ); | (1) | (C++11 起)
std::pair <const_iterator,const_iterator> equal_range( const Key& key ) const; | (2) | (C++11 起)
template< class K > std::pair <iterator,iterator> equal_range( const K& x ); | (3) | (C++20 起)
template< class K > std::pair <const_iterator,const_iterator> equal_range( const K& x ) const; | (4) | (C++20 起)
1,2) 返回容器中所有键等于 key 的元素范围。范围以二个迭代器定义，第一个指向所需范围的首元素，而第二个指向范围的尾后一位元素。
3,4) 返回含有容器中所有键等价于 x 的元素的范围。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要与元素比较的键值
x | - | 任何能与键通透比较的类型的值

返回值

含一对定义所需范围的迭代器的 std::pair 。若无这种元素，则将尾后（见 end() ）迭代器作为 pair 的两个元素返回。

复杂度

平均情况与带关键 key 的元素数成线性，最坏情况与容器大小成线性。

示例

本节未完成
原因：暂无示例

参阅

find (C++11) | 寻找带有特定键的元素 (公开成员函数)
contains (C++20) | 检查容器是否含有带特定键的元素 (公开成员函数)
count (C++11) | 返回匹配特定键的元素数量 (公开成员函数)
equal_range | 返回匹配特定键值的元素范围 (函数模板)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::erase

< cpp‎ | container‎ | unordered set

 | (1) |
iterator erase( iterator pos ); |  |  | (C++11 起)
iterator erase( const_iterator pos ); |  |  | (C++11 起)
 | (2) |
iterator erase( const_iterator first, const_iterator last ); |  |  | (C++11 起)
size_type erase( const key_type& key ); | (3) | (C++11 起)
template< class K > size_type erase( K&& x ); | (4) | (C++23 起)

从容器移除指定的元素。

1) 移除位于 pos 的元素。若 iterator 与 const_iterator 为同一类型则仅提供一个重载。
2) 移除范围 [first; last) 中的元素，它必须是 *this 中的合法范围。
3) 移除键等价于 key 的元素（若存在一个）。
4) 移除键比较等价于值 x 的元素（若存在一个）。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

到被擦除元素的引用和迭代器被非法化。其他迭代器和引用不被非法化。

迭代器 pos 必须合法且可解引用。从而 end() 迭代器（合法，但不可解引用）不能用作 pos 所用的值。 保留未被擦除的元素顺序（这使得可能在迭代通过容器时擦除单独的元素）。

参数

pos | - | 指向要移除的元素的迭代器
first, last | - | 要移除的元素范围
key | - | 要移除的元素键值
x | - | 任何能与键通透比较的类型的值，指代要移除的元素

返回值

1-2) 后随最后被移除的元素的迭代器。
3,4) 被移除的元素数。

异常

1,2) 不抛出
3,4) 任何 Hash 与 KeyEqual 对象所抛的异常

复杂度

给定 unordered_set 的实例 c ：

1) 平均情况：常数，最坏情况： c.size()
2) 平均情况： std::distance (first, last) ，最坏情况： c.size()
3) 平均情况： c.count(key) ，最坏情况： c.size()
4) 平均情况： c.count(x) ，最坏情况： c.size()

示例

#include <unordered_set>
#include <iostream>
int main()
{
    std::unordered_set<int> c = { 1, 2, 3, 4,    1, 2, 3, 4 };

    auto print = [&c] {
        std::cout << "c = { ";
        for(int n : c)
            std::cout << n << ' ';
        std::cout << "}\n";
    };
    print();

    std::cout << "Erase all odd numbers:\n";
    for(auto it = c.begin(); it != c.end(); ) {
        if(*it % 2 != 0)
            it = c.erase(it);
        else
            ++it;
    }
    print();

    std::cout << "Erase 1, erased count: " << c.erase(1) << '\n';
    std::cout << "Erase 2, erased count: " << c.erase(2) << '\n';
    std::cout << "Erase 2, erased count: " << c.erase(2) << '\n';
    print();
}

可能的输出：

c = { 1 2 3 4 }
Erase all odd numbers:
c = { 2 4 }
Erase 1, erased count: 0
Erase 2, erased count: 1
Erase 2, erased count: 0
c = { 4 }

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2059 | C++11 | 对一个 const_iterator 的重载引入了新的歧义 | 添加了对 iterator 的重载
LWG 2356 | C++11 | 未被擦除的元素顺序未指定 | 要求保留

参阅

clear
(C++11)
 清除内容
(公开成员函数)


std::erase_if (std::unordered_set)

< cpp‎ | container‎ | unordered set

定义于头文件 <unordered_set>
template< class Key, class Hash, class KeyEqual, class Alloc, class Pred >

typename std::unordered_set <Key,Hash,KeyEqual,Alloc>::size_type

erase_if( std::unordered_set <Key,Hash,KeyEqual,Alloc>& c, Pred pred);
 (C++20 起)

从容器中擦除所有满足谓词 pred 的元素。等价于

auto old_size = c.size();
for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}
return old_size - c.size();

参数

c | - | 要从中擦除的元素
pred | - | 若应该擦除元素则对它返回 true 的谓词

返回值

擦除的元素数。

复杂度

线性。

示例

#include <unordered_set>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& container)
{
    os << "{ ";
    for (const auto& item : container) {
        os << item << ' ';
    }
    return os << "}";
}

int main()
{
    std::unordered_set data { 0, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7 };
    std::cout << "Original:\n" << data << '\n';

    auto divisible_by_3 = [](auto const& x) { return (x % 3) == 0; };

    const auto count = std::erase_if(data, divisible_by_3);

    std::cout << "Erase all items divisible by 3:\n" << data << '\n'
              << count << " items erased.\n";
}

输出：

Original:
{ 7 6 5 4 3 2 1 0 }
Erase all items divisible by 3:
{ 7 5 4 2 1 }
3 items erased.

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::extract

< cpp‎ | container‎ | unordered set

node_type extract( const_iterator position ); | (1) | (C++17 起)
node_type extract( const key_type& k ); | (2) | (C++17 起)
template< class K > node_type extract( K&& x ); | (3) | (C++23 起)
1) 解链含 position 所指向元素的结点并返回占有它的结点柄。
2) 若容器拥有元素而其关键等于 x ，则从容器解链该元素并返回占有它的结点柄。否则，返回空结点柄。
3) 同 (2) 。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型，且 iterator 与 const_iterator 均不可从 K 隐式转换才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

任何情况下，均不复制或移动元素，只重指向容器结点的内部指针。

释出结点只会非法化指向被释出元素的迭代器，并保持未被擦除元素的相对顺序。指向被释出元素的指针和引用保持合法，但在结点柄占有该元素时不能使用：若元素被插入容器，就能使用它们。

参数

position | - | 指向此容器中的合法迭代器
k | - | 鉴别要被释出的结点的键
x | - | 任何能与键通透比较的类型的值，鉴别要释出的结点

返回值

占有被释出元素的结点柄，或 (2,3) 中找不到元素的情况下为空结点柄。

复杂度

1,2,3) 平均情况 O(1) ，最坏情况 O(a.size()) 。

注解

extract 是从 set 带走仅移动对象的唯一方式：

set<move_only_type> s;
s.emplace(...);
move_only_type mot = move(s.extract(s.begin()).value());

示例

#include <algorithm>
#include <iostream>
#include <unordered_set>

int main()
{
    std::unordered_set<int> cont{1, 2, 3};

    auto print = [](const int& n) { std::cout << " " << n; };

    std::cout << "Start:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 释出结点柄并更改键
    auto nh = cont.extract(1);
    nh.value() = 4;

    std::cout << "After extract and before insert:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';

    // 往回插入结点柄
    cont.insert(move(nh));

    std::cout << "End:";
    std::for_each(cont.begin(), cont.end(), print);
    std::cout << '\n';
}

可能的输出：

Start: 1 2 3
After extract and before insert: 2 3
End: 2 3 4

参阅

merge (C++17) | 从另一容器接合结点 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)
erase (C++11) | 擦除元素 (公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::find

< cpp‎ | container‎ | unordered set

iterator find( const Key& key ); | (1) |
const_iterator find( const Key& key ) const; | (2) |
template< class K > iterator find( const K& x ); | (3) | (C++20 起)
template< class K > const_iterator find( const K& x ) const; | (4) | (C++20 起)
1,2) 寻找键等于 key 的的元素。
3,4) 寻找键比较等价于值 x 的元素。此重载仅若有限定标识 Hash::is_transparent 与 KeyEqual::is_transparent 均合法并指代类型才参与重载决议。这假设能用 K 和 Key 类型一起调用这种 Hash ，还有 KeyEqual 是通透的，进而允许不用构造 Key 的实例就调用此函数。

参数

key | - | 要搜索的元素键值
x | - | 能通透地与键比较的任何类型值

返回值

指向键等于 key 的元素的迭代器。若找不到这种元素，则返回尾后（见 end() ）迭代器。

复杂度

平均为常数，最坏情况与容器大小成线性。

示例

#include <iostream>
#include <unordered_set>

int main()
{
// 简单比较演示
    std::unordered_set<int> example = {1, 2, 3, 4};

    auto search = example.find(2);
    if (search != example.end()) {
        std::cout << "Found " << (*search) << '\n';
    } else {
        std::cout << "Not found\n";
    }

}

输出：

Found 2

参阅

count (C++11) | 返回匹配特定键的元素数量 (公开成员函数)
equal_range (C++11) | 返回匹配特定键的元素范围 (公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::get_allocator

< cpp‎ | container‎ | unordered set

allocator_type get_allocator() const noexcept; | (C++11 起)

返回与容器关联的分配器。

参数

（无）

返回值

关联的分配器。

复杂度

常数。


std::unordered_set<Key,Hash,KeyEqual,Allocator>::hash_function

< cpp‎ | container‎ | unordered set

hasher hash_function() const; | (C++11 起)

返回对关键哈希的函数。

参数

（无）

返回值

哈希函数。

复杂度

常数。

参阅

key_eq
(C++11)
 返回用于比较键的相等性的函数
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::insert

< cpp‎ | container‎ | unordered set
std::pair <iterator,bool> insert( const value_type& value ); | (1) | (C++11 起)
std::pair <iterator,bool> insert( value_type&& value ); | (2) | (C++11 起)
iterator insert( const_iterator hint, const value_type& value ); | (3) | (C++11 起)
iterator insert( const_iterator hint, value_type&& value ); | (4) | (C++11 起)
template< class InputIt > void insert( InputIt first, InputIt last ); | (5) | (C++11 起)
void insert( std::initializer_list <value_type> ilist ); | (6) | (C++11 起)
insert_return_type insert(node_type&& nh); | (7) | (C++17 起)
iterator insert(const_iterator hint, node_type&& nh); | (8) | (C++17 起)

若容器尚未含有带等价关键的元素，则插入元素到容器中。

1-2) 插入 value 。
3-4) 插入 value ，以 hint 为应当开始搜索的位置的非强制建议。
5) 插入来自范围 [first, last) 的元素。若范围中的多个元素拥有比较等价的关键，则插入哪个元素是未指定的（待决的 LWG2844 ）。
6) 插入来自 initializer_list ilist 的元素。若范围中的多个元素拥有比较等价的关键，则插入哪个元素是未指定的（待决的 LWG2844 ）。
7) 若 nh 是空的结点把柄，则不做任何事。否则插入 nh 所占有的元素到容器，若容器尚未含有拥有等价于 nh.key() 的关键的元素。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。
8) 若 nh 是空的结点把柄，则不做任何事并返回尾迭代器。否则，插入 nh 所占有的元素到容器，若容器尚未含有拥有等价于 nh.key() 的关键的元素，并返回指向拥有等于 nh.key() 的关键的元素的迭代器（无关乎插入成功还是失败）。若插入成功，则从 nh 移动，否则它保持该元素的所有权。元素被插入到尽可能接近 hint 的位置。若 nh 非空且 get_allocator() != nh.get_allocator() 则行为未定义。

若因插入发生重哈希，则所有迭代器都被非法化。否则迭代器不受影响。引用不受影响。重哈希仅若新元素数量大于 max_load_factor()*bucket_count() 才发生。若插入成功，则在结点把柄保有元素时获得的指向该元素的指针和引用被非法化，而在提取前获得的指向元素的指针和引用变得合法。 (C++17 起)

参数

hint | - | 迭代器，用作插入内容位置的建议
value | - | 要插入的元素值
first, last | - | 要插入的元素范围
ilist | - | 插入值来源的 initializer_list
nh | - | 兼容的结点把柄
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

1-2) 返回由指向被插入元素（或阻止插入的元素）的迭代器和指代插入是否发生的 bool 组成的 pair 。
3-4) 返回指向被插入元素，或阻止插入的元素的迭代器。
5-6) （无）
7) 返回 insert_return_type ，其成员初始化如下：若 nh 为空，则 inserted 为 false ， position 为 end() ，而 node 为空。否则发生插入， inserted 为 true ， position 指向被插入元素，而 node 为空。若插入失败，则 inserted 为 false ， node 拥有 nh 的先前值，而 position 指向拥有等价于 nh.key() 的关键的元素。
8) 若 nh 为空则为尾迭代器，若插入发生则为指向被插入元素的迭代器，而若插入失败则为指向拥有等价于 nh.key() 的关键的元素的迭代器。

异常

1-4) 若任何操作抛出异常，则插入无效果。
本节未完成
原因：情况 5-8

复杂度

1-4) 平均情况： O(1) ，最坏情况 O(size())
5-6) 平均情况： O(N) ，其中 N 是要插入的元素数。最坏情况： O(N*size()+N)
7-8) 平均情况： O(1) ，最坏情况 O(size())

注意

有提示插入 (3,4) 不返回 bool ，这是为了与顺序容器上的定位插入，如 std::vector::insert 签名兼容。这使得可以创建泛型插入器，例如 std::inserter 。检查有提示插入是否成功的一种方式是比较插入前后的 size() 。

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
emplace_hint (C++11) | 使用提示原位构造元素 (公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::key_eq

< cpp‎ | container‎ | unordered set

key_equal key_eq() const; | (C++11 起)

返回比较关键相等性的函数。

参数

（无）

返回值

关键比较函数。

复杂度

常数。

参阅

hash_function
(C++11)
 返回用于对键散列的函数
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::load_factor

< cpp‎ | container‎ | unordered set

float load_factor() const; | (C++11 起)

返回每个桶元素的平均数，即 size() 除以 bucket_count() 。

参数

（无）

返回值

每个桶元素的平均数。

复杂度

常数。

参阅

max_load_factor
(C++11)
 管理每个桶的平均元素数量的最大值
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::max_bucket_count

< cpp‎ | container‎ | unordered set

size_type max_bucket_count() const; | (C++11 起)

返回容器由于系统或库实现限制的能保有的最大桶数。

参数

（无）

返回值

最大桶数。

复杂度

常数。

参阅

bucket_count
(C++11)
 返回桶数
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::max_load_factor

< cpp‎ | container‎ | unordered set

float max_load_factor() const; | (1) | (C++11 起)
void max_load_factor( float ml ); | (2) | (C++11 起)

管理最大加载因子（每个桶的平均元素数）。若加载因子超出此阈值，则容器自动增加桶数。

1) 返回最大加载因子。

2) 设置最大加载因子为 ml 。

参数

ml - 新设置的最大加载因子

返回值

1) 当前最大加载因子。

2) 无。

复杂度

常数

参阅

load_factor
(C++11)
 返回每个桶的平均元素数量
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::max_size

< cpp‎ | container‎ | unordered set

size_type max_size() const noexcept; | (C++11 起)

返回根据系统或库实现限制的容器可保有的元素最大数量，即对于最大容器的 std::distance (begin(), end()) 。

参数

（无）

返回值

元素数量的最大值。

复杂度

常数。

注解

此值通常反映容器大小上的理论极限，至多为 std::numeric_limits <difference_type>::max() 。运行时，可用 RAM 总量可能会限制容器大小到小于 max_size() 的值。

示例

#include <iostream>
#include <unordered_set>

int main()
{
    std::unordered_set<char> s;
    std::cout << "Maximum size of a 'unordered_set' is " << s.max_size() << "\n";
}

可能的输出：

Maximum size of a 'unordered_set' is 768614336404564650

参阅

size
(C++11)
 返回容纳的元素数
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::merge

< cpp‎ | container‎ | unordered set

template<class H2, class P2> void merge( std::unordered_set <Key, H2, P2, Allocator>& source ); | (1) | (C++17 起)
template<class H2, class P2> void merge( std::unordered_set <Key, H2, P2, Allocator>&& source ); | (2) | (C++17 起)
template<class H2, class P2> void merge( std::unordered_multiset <Key, H2, P2, Allocator>& source ); | (3) | (C++17 起)
template<class H2, class P2> void merge( std::unordered_multiset <Key, H2, P2, Allocator>&& source ); | (4) | (C++17 起)

试图提取（“接合”） source 中每个元素，并用 *this 的散列函数与键相等谓词插入到 *this 。 若 *this 中有元素，其键等价于来自 source 中元素的键，则不从 source 提取该元素。 不复制或移动元素，只会重指向容器结点的内部指针。指向被转移元素的所有指针和引用保持合法，但现在指代到 *this 中而非到 source 中。指代被转移元素的迭代器和所有指代到 *this 的迭代器被非法化。指向留在 source 中元素的迭代器保持合法。

若 get_allocator() != source.get_allocator() 则行为未定义。

参数

source - 传递结点来源的兼容容器

返回值

（无）

复杂度

平均情况 O(N) ，最坏情况 O(N*size()+N) ，其中 N 为 source.size() 。

示例

#include <iostream>
#include <unordered_set>

// 打印出容器
template <class Os, class K>
Os& operator<<(Os& os, const std::unordered_set<K>& v) {
    os << '[' << v.size() << "] {";
    bool o{};
    for (const auto& e : v)
        os << (o ? ", " : (o = 1, " ")) << e;
    return os << " }\n";
}

int main()
{
    std::unordered_set<char>
        p{ 'C', 'B', 'B', 'A' },
        q{ 'E', 'D', 'E', 'C' };

    std::cout << "p: " << p << "q: " << q;

    p.merge(q);

    std::cout << "p.merge(q);\n" << "p: " << p << "q: " << q;
}

可能的输出：

p: [3] { A, B, C }
q: [3] { C, D, E }
p.merge(q);
p: [5] { E, D, A, B, C }
q: [1] { C }

参阅

extract (C++17) | 从另一容器释出结点 (公开成员函数)
insert (C++11) | 插入元素或结点 (C++17 起) (公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::operator=

< cpp‎ | container‎ | unordered set

unordered_set& operator=( const unordered_set& other ); | (1) | (C++11 起)
 | (2) |
unordered_set& operator=( unordered_set&& other ); |  |  | (C++11 起) (C++17 前)
unordered_set& operator=( unordered_set&& other ) noexcept(/* see below */); |  |  | (C++17 起)
unordered_set& operator=( std::initializer_list <value_type> ilist ); | (3) | (C++11 起)

替换容器内容。

1) 复制赋值运算符。以 other 的副本替换内容。
若 std::allocator_traits <allocator_type>::propagate_on_container_copy_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若 *this 的分配器在赋值后将与其旧值比较不相等，则用旧分配器解分配内存，然后在复制元素前用新分配器分配内存。否则，在可行时可能复用 *this 所拥有的内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素复制赋值替换。
2) 移动赋值运算符。用移动语义以 other 的内容替换内容（即从 other 移动 other 中的数据到此容器中）。之后 other 在合法但未指定的状态。
若 std::allocator_traits <allocator_type>::propagate_on_container_move_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若它为 false 且 *this 与 other 的分配器不比较相等，则 *this 不能接管 other 所拥有的内存的所有权且必须单独地移动赋值每个元素，并用其自身的分配器按需分配额外内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素移动赋值替换。
3) 以 initializer_list ilist 所标识者替换内容。

参数

other | - | 用作数据源的另一容器
ilist | - | 用作数据源的 initializer_list

返回值

*this

复杂度

1) 与 *this 和 other 的大小成线性。
2) 与 *this 的大小成线性，除非分配器不比较相等且不传播，该情况下与 *this 和 other 的大小成线性。
3) 与 *this 和 ilist 的大小成线性。

异常

可能抛出实现定义的异常。

 (C++17 前)
1,3) 可能抛出实现定义的异常。
2)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value

&& std::is_nothrow_move_assignable <Hash>::value

&& std::is_nothrow_move_assignable <Pred>::value)
 (C++17 起)

注解

在容器移动赋值（重载 (2) ）后，除非不兼容的分配器强制逐元素移动赋值，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

下列代码用 operator= 赋值一个 std::unordered_set 给另一个：

#include <unordered_set>
#include <iostream>

void display_sizes(const std::unordered_set<int> &nums1,
                   const std::unordered_set<int> &nums2,
                   const std::unordered_set<int> &nums3)
{
    std::cout << "nums1: " << nums1.size()
              << " nums2: " << nums2.size()
              << " nums3: " << nums3.size() << '\n';
}

int main()
{
    std::unordered_set<int> nums1 {3, 1, 4, 6, 5, 9};
    std::unordered_set<int> nums2;
    std::unordered_set<int> nums3;

    std::cout << "Initially:\n";
    display_sizes(nums1, nums2, nums3);

    // 复制赋值从 nums1 复制数据到 nums2
    nums2 = nums1;

    std::cout << "After assigment:\n";
    display_sizes(nums1, nums2, nums3);

    // 移动赋值从 nums1 移动数据到 nums3,
    // 一同修改 nums1 和 nums3
    nums3 = std::move(nums1);

    std::cout << "After move assigment:\n";
    display_sizes(nums1, nums2, nums3);
}

输出：

Initially:
nums1: 6 nums2: 0 nums3: 0
After assigment:
nums1: 6 nums2: 6 nums3: 0
After move assigment:
nums1: 0 nums2: 6 nums3: 6

参阅

(构造函数)
(C++11)
 构造 unordered_set
(公开成员函数)


operator==,!=(std::unordered_set)

< cpp‎ | container‎ | unordered set

template< class Key, class Hash, class KeyEqual, class Allocator >

bool operator==( const std::unordered_set <Key,Hash,KeyEqual,Allocator>& lhs,

const std::unordered_set <Key,Hash,KeyEqual,Allocator>& rhs );
 (1)
template< class Key, class Hash, class KeyEqual, class Allocator >

bool operator!=( const std::unordered_set <Key,Hash,KeyEqual,Allocator>& lhs,

const std::unordered_set <Key,Hash,KeyEqual,Allocator>& rhs );
 (2) (C++20 前)

比较二个无序容器的内容。

若下列条件成立则二个无序容器 lhs 与 rhs 相等：

  • lhs.size() == rhs.size()
  • 从 lhs.equal_range(lhs_eq1) 获得的每组等价元素 [lhs_eq1, lhs_eq2) 拥有在另一容器中从 rhs.equal_range(rhs_eq1) 获得的对应等价元素组 [rhs_eq1, rhs_eq2) ，且它们拥有下列属性：
  • std::distance (lhs_eq1, lhs_eq2) == std::distance (rhs_eq1, rhs_eq2) 。
  • std::is_permutation (lhs_eq1, lhs_eq2, rhs_eq1) == true 。

若 Key 非可相等比较 (EqualityComparable) 则行为未定义。

若 hash_function() 和 key_eq() (C++20 前)key_eq() (C++20 起) 在 lhs 和 rhs 上拥有不相同的行为，或若 Key 的 operator== 不是对于 key_eq() 所引入的等价关键组的细分（即若用 operator== 比较相等的二个元素落入不同划分），则行为未定义。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的无序容器

返回值

1) 若容器内容相等则为 true ，否则为 false 。
2) 若容器内容不相等则为 true ，否则为 false 。

复杂度

调用 value_type 上的 operator== 、调用 key_eq 所返回的谓词，及调用 hash_function 所返回的哈希器的次数，平均情况下与 N 成正比，最坏情况下与 N2 成正比，其中 N 是容器大小。


std::unordered_set<Key,Hash,KeyEqual,Allocator>::rehash

< cpp‎ | container‎ | unordered set

void rehash( size_type count ); | (C++11 起)

设置桶数为 count 并重哈希容器，即考虑桶总数已改变，再把元素放到适当的桶中。若新的桶数使加载因子大于最大加载因子（ count < size() / max_load_factor() ），则新桶数至少为 size() / max_load_factor() 。

参数

count - 新的桶数

返回值

（无）

复杂度

平均与容器大小成线性，最坏情况成平方。

注意

rehash(0) 可用于强制无条件的重哈希，例如在通过临时增加 max_load_factor() 暂停自动重哈希之后。

参阅

reserve
(C++11)
 为至少为指定数量的元素预留存储空间并重新生成哈希表。
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::reserve

< cpp‎ | container‎ | unordered set

void reserve( size_type count ); | (C++11 起)

设置桶数为适应至少 count 个元素，而不超出最大加载因子所需的数，并重哈希容器，即考虑桶数已更改后将元素放进适合的桶。等效地调用 rehash( std::ceil (count / max_load_factor())) 。

参数

count - 容器的新容量

返回值

（无）

复杂度

平均情况与容器大小成线性，最坏情况成平方。

参阅

rehash
(C++11)
 为至少为指定数量的桶预留存储空间并重新生成散列表
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::size

< cpp‎ | container‎ | unordered set

size_type size() const noexcept; | (C++11 起)

返回容器中的元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

容器中的元素数量。

复杂度

常数。

示例

下列代码用 size 显示 std::unordered_set <int> 中的元素数：

#include <unordered_set>
#include <iostream>

int main()
{
    std::unordered_set<int> nums {1, 3, 5, 7};

    std::cout << "nums contains " << nums.size() << " elements.\n";
}

输出：

nums contains 4 elements.

参阅

empty (C++11) | 检查容器是否为空 (公开成员函数)
max_size (C++11) | 返回可容纳的最大元素数 (公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::swap

< cpp‎ | container‎ | unordered set

void swap( unordered_set& other ); | (C++11 起) (C++17 前)
void swap( unordered_set& other ) noexcept(/* see below */); | (C++17 起)

将内容与 other 的交换。不在单独的元素上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。尾后迭代器被非法化。

Hash 和 KeyEqual 对象必须可交换 (Swappable) ，并用非成员 swap 的非限定调用交换它们。

若 std::allocator_traits <allocator_type>::propagate_on_container_swap::value 为 true ，则用对非成员 swap 的无限定调用交换分配器。否则，不交换它们（且若 get_allocator() != other.get_allocator() ，则行为未定义）。

 (C++11 起)

参数

other - 要与之交换内容的容器

返回值

（无）

异常

任何 Hash 或 KeyEqual 对象交换所抛的异常。

 (C++17 前)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::is_always_equal::value

&& std::is_nothrow_swappable <Hash>::value

&& std::is_nothrow_swappable <key_equal>::value)
 (C++17 起)

复杂度

常数。

示例

#include <iostream>
#include <unordered_set>

template<class Os, class Co> Os& operator<<(Os& os, const Co& co) {
    os << "{";
    for (auto const& i : co) { os << ' ' << i; }
    return os << " } ";
}

int main()
{
    std::unordered_set<int> a1{3, 1, 3, 2}, a2{5, 4, 5};

    auto it1 = std::next(a1.begin());
    auto it2 = std::next(a2.begin());

    const int& ref1 = *(a1.begin());
    const int& ref2 = *(a2.begin());

    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';
    a1.swap(a2);
    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';

    // 注意交换前指代一个容器中的元素的每个迭代器在交换后都指代同一元素。对于引用同为真。
}

可能的输出：

{ 2 1 3 } { 4 5 } 1 5 2 4
{ 4 5 } { 2 1 3 } 1 5 2 4

参阅

std::swap(std::unordered_set)
(C++11)
 特化 std::swap 算法
(函数模板)


std::swap(std::unordered_set)

< cpp‎ | container‎ | unordered set

定义于头文件 <unordered_set>
template< class Key, class Hash, class KeyEqual, class Alloc >

void swap( std::unordered_set <Key,Hash,KeyEqual,Alloc>& lhs,

std::unordered_set <Key,Hash,KeyEqual,Alloc>& rhs );
 (C++11 起)
(C++17 前)
template< class Key, class Hash, class KeyEqual, class Alloc >

void swap( std::unordered_set <Key,Hash,KeyEqual,Alloc>& lhs,

std::unordered_set <Key,Hash,KeyEqual,Alloc>& rhs ) noexcept(/* see below */);
 (C++17 起)

为 std::unordered_set 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

#include <algorithm>
#include <iostream>
#include <unordered_set>

int main()
{
    std::unordered_set<int> alice{1, 2, 3};
    std::unordered_set<int> bob{7, 8, 9, 10};

    auto print = [](const int& n) { std::cout << " " << n; };

    // 打印交换前的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';

    std::cout << "-- SWAP\n";
    std::swap(alice,bob);

    // 打印交换后的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
}

可能的输出：

alice: 1 2 3
bob  : 7 8 9 10
-- SWAP
alice: 7 8 9 10
bob  : 1 2 3

参阅

swap
(C++11)
 交换内容
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::unordered_set

< cpp‎ | container‎ | unordered set

unordered_set() : unordered_set( size_type(/*implementation-defined*/) ) {}

explicit unordered_set( size_type bucket_count,
const Hash& hash = Hash(),
const key_equal& equal = key_equal(),

const Allocator& alloc = Allocator() );
 (1) (C++11 起)
unordered_set( size_type bucket_count,

const Allocator& alloc )
: unordered_set(bucket_count, Hash(), key_equal(), alloc) {}
unordered_set( size_type bucket_count,
const Hash& hash,
const Allocator& alloc )

: unordered_set(bucket_count, hash, key_equal(), alloc) {}
 (1) (C++14 起)
explicit unordered_set( const Allocator& alloc );
 (1) (C++11 起)
template< class InputIt >

unordered_set( InputIt first, InputIt last,
size_type bucket_count = /*implementation-defined*/,
const Hash& hash = Hash(),
const key_equal& equal = key_equal(),

const Allocator& alloc = Allocator() );
 (2) (C++11 起)
template< class InputIt >

unordered_set( InputIt first, InputIt last,
size_type bucket_count,
const Allocator& alloc )
: unordered_set(first, last,

bucket_count, Hash(), key_equal(), alloc) {}
 (2) (C++14 起)
template< class InputIt >

unordered_set( InputIt first, InputIt last,
size_type bucket_count,
const Hash& hash,
const Allocator& alloc )
: unordered_set(first, last,

bucket_count, hash, key_equal(), alloc) {}
 (2) (C++14 起)
unordered_set( const unordered_set& other );
 (3) (C++11 起)
unordered_set( const unordered_set& other, const Allocator& alloc );
 (3) (C++11 起)
unordered_set( unordered_set&& other );
 (4) (C++11 起)
unordered_set( unordered_set&& other, const Allocator& alloc );
 (4) (C++11 起)
unordered_set( std::initializer_list <value_type> init,

size_type bucket_count = /*implementation-defined*/,
const Hash& hash = Hash(),
const key_equal& equal = key_equal(),

const Allocator& alloc = Allocator() );
 (5) (C++11 起)
unordered_set( std::initializer_list <value_type> init,

size_type bucket_count,
const Allocator& alloc )
: unordered_set(init, bucket_count,

Hash(), key_equal(), alloc) {}
 (5) (C++14 起)
unordered_set( std::initializer_list <value_type> init,

size_type bucket_count,
const Hash& hash,
const Allocator& alloc )
: unordered_set(init, bucket_count,

hash, key_equal(), alloc) {}
 (5) (C++14 起)

从各种数据源构造新容器。可选的以用户提供的 bucket_count 为用于创建的最小桶数，以 hash 为哈希函数，以 equal 为比较关键的函数，和以 alloc 为分配器。

1) 构造空容器。设置 max_load_factor() 为 1.0 。对于默认构造函数，桶数是实现定义的。
2) 构造拥有范围 [first, last) 的内容的容器。设置 max_load_factor() 为 1.0 。若范围中的多个元素拥有比较等价的关键，则插入哪个元素是未指定的（待决的 LWG2844 ）。
3) 复制构造函数。构造拥有 other 内容副本的容器，一同复制加载因子、谓词和哈希函数。若不提供 alloc ，则通过调用 std::allocator_traits <allocator_type>::select_on_container_copy_construction(other.get_allocator()) 获得分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
4) 移动构造函数。用移动语义构造拥有 other 内容的容器。若不提供 alloc ，则通过从属于 other 的分配器移动构造获得分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
5) 构造拥有 initializer_list init 内容的容器，同 unordered_set(init.begin(), init.end()) 。

参数

alloc | - | 用于此容器所有内存分配器的分配器
bucket_count | - | 初始化时用的最小桶数。若不指定，则使用实现定义的默认值
hash | - | 要用的哈希函数
equal | - | 用于此容器所有关键比较的比较函数
first, last | - | 复制元素来源的范围
other | - | 用作源以初始化容器元素的另一容器
init | - | 用以初始化容器元素的 initializer_list
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

复杂度

1) 常数
2) 平均情况与 first 和 last 间的距离成线性，最坏情况成平方。
3) 与 other 的大小成线性。
4) 常数。若给定 alloc 且 alloc != other.get_allocator() 则为线性。
5) 平均情况与 init 的大小成线性，最坏情况成平方。

异常

对 Allocator::allocate 的调用可能抛出。

注解

在容器移动构造（重载 (4) ）后，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

尽管在 C++23 前未正式要求，一些实现已经在较早的模式中将 Allocator 放入非推导语境。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2193 | C++11 | 默认构造函数为 explicit | 使之为非 explicit

参阅

operator=
(C++11)
 赋值给容器
(公开成员函数)


std::unordered_set<Key,Hash,KeyEqual,Allocator>::~unordered_set

< cpp‎ | container‎ | unordered set

~unordered_set(); | (C++11 起)

销毁 unordered_set 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 unordered_set 大小成线性。


std::vector

< cpp‎ | container
定义于头文件 <vector>
template<

class T,
class Allocator = std::allocator <T>

> class vector;
 (1)
namespace pmr {

template <class T>
using vector = std::vector<T, std::pmr::polymorphic_allocator <T>>;

}
 (2) (C++17 起)
1) std::vector 是封装动态数组的顺序容器。
2) std::pmr::vector 是使用多态分配器的模板别名。

连续存储元素，这意味着不仅可通过迭代器，还能用指向元素的常规指针访问元素。这意味着指向 vector 元素的指针能传递给任何期待指向数组元素的指针的函数。

vector 的存储是自动管理的，按需扩张收缩。 vector 通常占用多于静态数组的空间，因为要分配更多内存以管理将来的增长。 vector 所用的方式不在每次插入元素时，而只在额外内存耗尽时重分配。分配的内存总量可用 capacity() 函数查询。可通过调用 shrink_to_fit() 返回多出的内存给系统。 (C++11 起)

重分配通常是性能上有开销的操作。若元素数量已知，则 reserve() 函数可用于消除重分配。

vector 上的常见操作复杂度（效率）如下：

  • 随机访问——常数 𝓞(1)
  • 在末尾插入或移除元素——均摊常数 𝓞(1)
  • 插入或移除元素——与到 vector 结尾的距离成线性 𝓞(n)

std::vector （对于 bool 以外的 T ）满足容器 (Container) 、知分配器容器 (AllocatorAwareContainer) 、序列容器 (SequenceContainer) 、连续容器 (ContiguousContainer) (C++17 起)及可逆容器 (ReversibleContainer) 的要求。

std::vector 的特化是字面类型 (LiteralType) ，从而能在常量表达式的求值中创建它们。

然而 std::vector 对象通常不能为 constexpr ，因为任何动态分配的存储都必须在同一常量表达式求值中释放。

 (C++20 起)

模板形参

T - 元素的类型。
T 必须满足可复制赋值 (CopyAssignable) 和可复制构造 (CopyConstructible) 的要求。 | (C++11 前)
加诸元素的要求依赖于容器上进行的实际操作。泛言之，要求元素类型是完整类型并满足可擦除 (Erasable) 的要求，但许多成员函数附带了更严格的要求。 | (C++11 起) (C++17 前)
加诸元素的要求依赖于容器上进行的实际操作。泛言之，要求元素类型满足可擦除 (Erasable) 的要求，但许多成员函数附带了更严格的要求。若分配器满足分配器完整性要求，则容器（但非其成员）能以不完整元素类型实例化。 | (C++17 起)
Allocator - 用于获取/释放内存及构造/析构内存中元素的分配器。类型必须满足分配器 (Allocator) 的要求。若 Allocator::value_type 与 T 不同则行为未定义 (C++20 前)程序非良构 (C++20 起)。

特化

标准库提供 std::vector 对类型 bool 的特化，它可能为空间效率优化。

vector<bool>
 节省空间的动态 bitset
(类模板特化)

迭代器非法化

操作 | 非法化
所有只读操作 | 决不
swap 、 std::swap | end()
clear 、 operator= 、 assign | 始终
reserve 、 shrink_to_fit | 若 vector 更改容量，则为其全部。否则为无。
erase | 被擦除元素及之后的所有元素（包括 end() ）。
push_back 、 emplace_back | 若 vector 更改容量，则为其全部。否则仅 end() 。
insert, emplace | 若 vector 更改容量，则为其全部。否则仅为在或于插入点后者（包括 end() ）。
resize | 若 vector 更改容量，则为其全部。否则仅 end() 与被擦除元素。
pop_back | 被擦除元素及 end() 。

成员类型

成员类型 | 定义
value_type | T
allocator_type | Allocator
size_type | 无符号整数类型（通常是 std::size_t ）
difference_type | 有符号整数类型（通常是 std::ptrdiff_t ）
reference | value_type&
const_reference | const value_type&
pointer
Allocator::pointer | (C++11 前)
std::allocator_traits <Allocator>::pointer | (C++11 起)
const_pointer
Allocator::const_pointer | (C++11 前)
std::allocator_traits <Allocator>::const_pointer | (C++11 起)
iterator
指向 value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 及老式连续迭代器 (LegacyContiguousIterator) | (C++20 前)
指向 value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 、contiguous_iterator 及常量表达式迭代器 (ConstexprIterator) | (C++20 起)
const_iterator
指向 const value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 及老式连续迭代器 (LegacyContiguousIterator) | (C++20 前)
指向 const value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 、contiguous_iterator 及常量表达式迭代器 (ConstexprIterator) | (C++20 起)
reverse_iterator | std::reverse_iterator <iterator>
const_reverse_iterator | std::reverse_iterator <const_iterator>

成员函数

(构造函数)
 构造 vector
(公开成员函数)
(析构函数)
 析构 vector
(公开成员函数)
operator=
 赋值给容器
(公开成员函数)
assign
 将值赋给容器
(公开成员函数)
get_allocator
 返回相关的分配器
(公开成员函数)
元素访问
at
 访问指定的元素，同时进行越界检查
(公开成员函数)
operator[]
 访问指定的元素
(公开成员函数)
front
 访问第一个元素
(公开成员函数)
back
 访问最后一个元素
(公开成员函数)
data
 直接访问底层数组
(公开成员函数)
迭代器
begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)
rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)
rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)
容量
empty
 检查容器是否为空
(公开成员函数)
size
 返回容纳的元素数
(公开成员函数)
max_size
 返回可容纳的最大元素数
(公开成员函数)
reserve
 预留存储空间
(公开成员函数)
capacity
 返回当前存储空间能够容纳的元素数
(公开成员函数)
shrink_to_fit
(C++11)
 通过释放未使用的内存减少内存的使用
(公开成员函数)
修改器
clear
 清除内容
(公开成员函数)
insert
 插入元素
(公开成员函数)
emplace
(C++11)
 原位构造元素
(公开成员函数)
erase
 擦除元素
(公开成员函数)
push_back
 将元素添加到容器末尾
(公开成员函数)
emplace_back
(C++11)
 在容器末尾就地构造元素
(公开成员函数)
pop_back
 移除末元素
(公开成员函数)
resize
 改变容器中可存储元素的个数
(公开成员函数)
swap
 交换内容
(公开成员函数)

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 按照字典顺序比较 vector 中的值 (函数模板)
std::swap(std::vector) | 特化 std::swap 算法 (函数模板)
erase(std::vector)erase_if(std::vector) (C++20) | 擦除所有满足特定判别标准的元素 (函数模板)

推导指引 (C++17 起)

示例

#include <iostream>
#include <vector>

int main()
{
    // 创建含有整数的 vector
    std::vector<int> v = {7, 5, 16, 8};

    // 添加二个整数到 vector
    v.push_back(25);
    v.push_back(13);

    // 迭代并打印 vector 的值
    for(int n : v) {
        std::cout << n << '\n';
    }
}

输出：

7
5
16
8
25
13

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 69 | C++98 | 未要求 vector 的元素存储的连续性 | 已要求
LWG 464 | C++98 | 访问空的 vector 的底层存储导致未定义行为 | 提供 data 函数


std::vector<T,Allocator>::assign

< cpp‎ | container‎ | vector

 | (1)
void assign( size_type count, const T& value ); |  | (C++20 前)
constexpr void assign( size_type count, const T& value ); |  | (C++20 起)
 | (2)
template< class InputIt > void assign( InputIt first, InputIt last ); |  | (C++20 前)
template< class InputIt > constexpr void assign( InputIt first, InputIt last ); |  | (C++20 起)
 | (3)
void assign( std::initializer_list <T> ilist ); |  | (C++11 起) (C++20 前)
constexpr void assign( std::initializer_list <T> ilist ); |  | (C++20 起)

替换容器的内容。

1) 以 count 份 value 的副本替换内容。
2) 以范围 [first, last) 中元素的副本替换内容。若任一参数是指向 *this 中的迭代器则行为未定义。
若 InputIt 为整数类型，则此重载与 (1) 拥有相同效果。 | (C++11 前)
此重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 才参与重载决议。 | (C++11 起)
3) 以来自 initializer_list ilist 的元素替换内容。

所有指向容器元素的迭代器、指针及引用均被非法化。尾后迭代器亦被非法化。

参数

count | - | 容器的新大小
value | - | 用以初始化容器元素的值
first, last | - | 复制来源元素的范围
ilist | - | 复制值来源的 initializer_list

复杂度

1) 与 count 成线性
2) 与 first 和 last 间的距离成线性
3) 与 ilist.size() 成线性

示例

下列代码用 assign 添加数个字符到 std::vector <char> ：

#include <vector>
#include <iostream>

int main()
{
    std::vector<char> characters;

    characters.assign(5, 'a');

    for (char c : characters) {
        std::cout << c << ' ';
    }

    characters.assign({'\n', 'C', '+', '+', '1', '1', '\n'});

    for (char c : characters) {
        std::cout << c;
    }
}

输出：

a a a a a
C++11

参阅

(构造函数)
 构造 vector
(公开成员函数)


std::vector<T,Allocator>::at

< cpp‎ | container‎ | vector

reference at( size_type pos ); | (C++20 前)
constexpr reference at( size_type pos ); | (C++20 起)
const_reference at( size_type pos ) const; | (C++20 前)
constexpr const_reference at( size_type pos ) const; | (C++20 起)

返回位于指定位置 pos 的元素的引用，有边界检查。

若 pos 不在容器范围内，则抛出 std::out_of_range 类型的异常。

参数

pos - 要返回的元素的位置

返回值

到所需元素的引用。

异常

若 !(pos < size()) 则抛出 std::out_of_range

复杂度

常数。

示例

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> data = { 1, 2, 4, 5, 5, 6 };

    // Set element 1
    data.at(1) = 88;

    // Read element 2
    std::cout << "Element at index 2 has value " << data.at(2) << '\n';

    std::cout << "data size = " << data.size() << '\n';

    try {
        // Set element 6
        data.at(6) = 666;
    } catch (std::out_of_range const& exc) {
        std::cout << exc.what() << '\n';
    }

    // Print final values
    std::cout << "data:";
    for (int elem : data)
        std::cout << " " << elem;
    std::cout << '\n';
}

可能的输出：

Element at index 2 has value 4
data size = 6
vector::_M_range_check: __n (which is 6) >= this->size() (which is 6)
data: 1 88 4 5 5 6

参阅

operator[]
 访问指定的元素
(公开成员函数)


std::vector<T,Allocator>::back

< cpp‎ | container‎ | vector

reference back(); | (C++20 前)
constexpr reference back(); | (C++20 起)
const_reference back() const; | (C++20 前)
constexpr const_reference back() const; | (C++20 起)

返回到容器中最后一个元素的引用。

在空容器上调用 back 导致未定义行为。

参数

（无）

返回值

到最后元素的引用。

复杂度

常数。

注解

对于非空容器 c ，表达式 c.back() 等价于 * std::prev (c.end()) 。

示例

下列代码用 back 显示 std::vector <char> 的最后一个元素：

#include <vector>
#include <iostream>

int main()
{
    std::vector<char> letters {'o', 'm', 'g', 'w', 't', 'f'};
    if (!letters.empty()) {
        std::cout << "The last character is: " << letters.back() << '\n';
    }
}

输出：

The last character is f

参阅

front
 访问第一个元素
(公开成员函数)


std::vector<T,Allocator>::begin, std::vector<T,Allocator>::cbegin

< cpp‎ | container‎ | vector

iterator begin(); | (C++11 前)
iterator begin() noexcept; | (C++11 起) (C++20 前)
constexpr iterator begin() noexcept; | (C++20 起)
const_iterator begin() const; | (C++11 前)
const_iterator begin() const noexcept; | (C++11 起) (C++20 前)
constexpr const_iterator begin() const noexcept; | (C++20 起)
const_iterator cbegin() const noexcept; | (C++11 起) (C++20 前)
constexpr const_iterator cbegin() const noexcept; | (C++20 起)

返回指向 vector 首元素的迭代器。

若 vector 为空，则返回的迭代器将等于 end() 。

参数

（无）

返回值

指向首元素的迭代器。

复杂度

常数。

示例

#include <iostream>
#include <numeric>
#include <vector>
#include <string>

int main()
{
        std::vector<int> nums {1, 2, 4, 8, 16};
        std::vector<std::string> fruits {"orange", "apple", "raspberry"};
        std::vector<char> empty;

        // 求和 vector nums 中的所有整数（若存在），仅打印结果。
        std::cout << "Sum of nums: " <<
                std::accumulate(nums.begin(), nums.end(), 0) << "\n";

        // 打印 vector fruits 中的首个 fruis ，不检查是否有一个。
        std::cout << "First fruit: " << *fruits.begin() << "\n";

        if (empty.begin() == empty.end())
                std::cout << "vector 'empty' is indeed empty.\n";
}

输出：

Sum of nums: 31
First fruit: orange
vector 'empty' is indeed empty.

参阅

end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)


std::vector<T,Allocator>::capacity

< cpp‎ | container‎ | vector

size_type capacity() const; | (C++11 前)
size_type capacity() const noexcept; | (C++11 起) (C++20 前)
constexpr size_type capacity() const noexcept; | (C++20 起)

返回容器当前已为之分配空间的元素数。

参数

（无）

返回值

当前分配存储的容量。

复杂度

常数。

示例

#include <iostream>
#include <vector>

int main()
{
    int sz = 200;
    std::vector<int> v1;

    auto cap = v1.capacity();
    std::cout << "initial capacity=" << cap << '\n';

    for (int n = 0; n < sz; ++n) {
        v1.push_back(n);
        if (cap != v1.capacity()) {
            cap = v1.capacity();
            std::cout << "new capacity=" << cap << '\n';
        }
    }

    std::cout << "final size=" << v1.size() << '\n';
    std::cout << "final capacity=" << v1.capacity() << '\n';
}

可能的输出：

initial capacity=0
new capacity=1
new capacity=2
new capacity=4
new capacity=8
new capacity=16
new capacity=32
new capacity=64
new capacity=128
new capacity=256
final size=200
final capacity=256

参阅

size | 返回容纳的元素数 (公开成员函数)
reserve | 预留存储空间 (公开成员函数)


std::vector<T,Allocator>::clear

< cpp‎ | container‎ | vector

void clear(); | (C++11 前)
void clear() noexcept; | (C++11 起) (C++20 前)
constexpr void clear() noexcept; | (C++20 起)

从容器擦除所有元素。此调用后 size() 返回零。

非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器亦被非法化。

保持 vector 的 capacity() 不变（注意：更改容量上的标准限制在 vector::reserve 的规定中，见 [1] ）。

参数

（无）

返回值

（无）

复杂度

与容器大小，即元素数成线性。

示例

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> container{1, 2, 3};

    auto print = [](const int& n) { std::cout << " " << n; };

    std::cout << "Before clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';

    std::cout << "Clear\n";
    container.clear();

    std::cout << "After clear:";
    std::for_each(container.begin(), container.end(), print);
    std::cout << "\nSize=" << container.size() << '\n';
}

输出：

Before clear: 1 2 3
Size=3
Clear
After clear:
Size=0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2231 | C++11 | C++11 中错误地省略了复杂度保证 | 重申复杂度为线性

参阅

erase
 擦除元素
(公开成员函数)


std::vector<T,Allocator>::data

< cpp‎ | container‎ | vector

T* data(); | (C++11 前)
T* data() noexcept; | (C++11 起) (C++20 前)
constexpr T* data() noexcept; | (C++20 起)
const T* data() const; | (C++11 前)
const T* data() const noexcept; | (C++11 起) (C++20 前)
constexpr const T* data() noexcept; | (C++20 起)

返回指向作为元素存储工作的底层数组的指针。指针满足范围 [data(); data() + size()) 始终是合法范围，即使容器为空（该情况下 data() 不可解引用）。

参数

（无）

返回值

指向底层元素存储的指针。对于非空容器，返回的指针与首元素地址比较相等。

复杂度

常数。

注解

若 size() 为 0 ，则 data() 可能或可能不返回空指针。

参阅

front | 访问第一个元素 (公开成员函数)
back | 访问最后一个元素 (公开成员函数)
size | 返回容纳的元素数 (公开成员函数)


std::vector 的推导指引

< cpp‎ | container‎ | vector

定义于头文件 <vector>
template< class InputIt,

class Alloc = std::allocator <typename std::iterator_traits <InputIt>::value_type>>
vector(InputIt, InputIt, Alloc = Alloc())

-> vector<typename std::iterator_traits <InputIt>::value_type, Alloc>;
 (C++17 起)

为 vector 提供此推导指引，以允许从迭代器范围推导。此重载仅若InputIt 满足老式输入迭代器 (LegacyInputIterator) 且 Alloc 满足分配器 (Allocator) 才参与重载决议

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

示例

#include <vector>

int main() {
   std::vector<int> v = {1, 2, 3, 4};

   // 使用显式推导指引推导 std::vector<int>
   std::vector x(v.begin(), v.end());

   // 推导 std::vector<std::vector<int>::iterator>
   // 列表初始化的重载决议第一阶段选择从 initializer_list 构造函数合成的候选
   // 不进行第二阶段且推导指引无效果
   std::vector y{v.begin(), v.end()};
}


std::vector<T,Allocator>::emplace

< cpp‎ | container‎ | vector

template< class... Args > iterator emplace( const_iterator pos, Args&&... args ); | (C++11 起) (C++20 前)
template< class... Args > constexpr iterator emplace( const_iterator pos, Args&&... args ); | (C++20 起)

直接于 pos 前插入元素到容器中。

通过 std::allocator_traits::construct 构造元素，常用布置 new 在容器提供的位置原位构造元素。然而若要求的位置已被既存的元素占据，则首先在另一位置构造被插入的元素，然后再将他移动赋值到要求的位置中。

将参数 args... 作为 std::forward <Args>(args)... 转发给构造函数。 args... 可以直接或间接地指代容器中的值。

若新的 size() 大于 capacity() ，则所有迭代器和引用都被非法化。否则，仅在插入点前的迭代器和引用保持合法。尾后迭代器亦被非法化。

参数

pos | - | 将构造新元素到其前的迭代器
args | - | 转发给元素构造函数的参数
类型要求
- T （容器元素类型） 必须满足可移动赋值 (MoveAssignable) 、 可移动插入 (MoveInsertable) 和 可就位构造 (EmplaceConstructible) 的要求。

返回值

指向被安置的元素的迭代器。

复杂度

与 pos 和容器尾的距离成线性。

异常

若 value_type 的复制构造函数、移动构造函数、赋值运算符或移动赋值运算符以外的操作抛异常，或若在用 emplace 在尾部插入单个元素时抛异常，且 value_type 为可复制插入 (CopyInsertable) 或可不抛出移动构造，则无效果（强异常保证）。

否则，效果未指定。

注解

特化 std::vector<bool> 在 C++14 前无 emplace() 成员。

示例

#include <iostream>
#include <string>
#include <vector>

struct A {
    std::string s;
    A(std::string str) : s(std::move(str))  { std::cout << " constructed\n"; }
    A(const A& o) : s(o.s) { std::cout << " copy constructed\n"; }
    A(A&& o) : s(std::move(o.s)) { std::cout << " move constructed\n"; }
    A& operator=(const A& other) {
        s = other.s;
        std::cout << " copy assigned\n";
        return *this;
    }
    A& operator=(A&& other) {
        s = std::move(other.s);
        std::cout << " move assigned\n";
        return *this;
    }
};

int main()
{
    std::vector<A> container;
    // 预留足够的空间以使 vector 不必重设大小
    container.reserve(10);
    std::cout << "construct 2 times A:\n";
    A two { "two" };
    A three { "three" };

    std::cout << "emplace:\n";
    container.emplace(container.end(), "one");

    std::cout << "emplace with A&:\n";
    container.emplace(container.end(), two);

    std::cout << "emplace with A&&:\n";
    container.emplace(container.end(), std::move(three));

    std::cout << "content:\n";
    for (const auto& obj : container)
        std::cout << ' ' << obj.s;
    std::cout << '\n';
}

输出：

construct 2 times A:
 constructed
 constructed
emplace:
 constructed
emplace with A&:
 copy constructed
emplace with A&&:
 move constructed
content vec:
 one two three

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2164 | C++11 | 不清楚参数是否能指代容器 | 已澄清

参阅

insert
 插入元素
(公开成员函数)


std::vector<T,Allocator>::emplace_back

< cpp‎ | container‎ | vector

template< class... Args > void emplace_back( Args&&... args ); | (C++11 起) (C++17 前)
template< class... Args > reference emplace_back( Args&&... args ); | (C++17 起) (C++20 前)
template< class... Args > constexpr reference emplace_back( Args&&... args ); | (C++20 起)

添加新元素到容器尾。元素通过 std::allocator_traits::construct 构造，它典型地用布置 new 于容器所提供的位置原位构造元素。参数 args... 以 std::forward <Args>(args)... 转发到构造函数。

若新的 size() 大于 capacity() ，则所有迭代器和引用（包含尾后迭代器）都被非法化。否则仅尾后迭代器被非法化。

参数

args - 转发到元素构造函数的参数
类型要求
-
value_type 必须满足可移动插入 (MoveInsertable) 和 可就位构造 (EmplaceConstructible) 的要求。

返回值

（无） | (C++17 前)
到被插入元素的引用。 | (C++17 起)

复杂度

均摊常数。

异常

若抛出异常，则此函数无效果（强异常保证）。 若 T 的移动构造函数非 noexcept 且非可复制插入 (CopyInsertable) 到 *this ，则 vector 将使用抛出的移动构造函数。若它抛出，则保证被舍弃，且效果未指定。

注解

因为可能发生再分配， emplace_back 对 vector 要求元素类型为可移动插入 (MoveInsertable) 。

特化 std::vector<bool> 在 C++14 前无 emplace_back() 成员。

示例

下列代码用 emplace_back 后附 President 类型对象到 std::vector 。它演示 emplace_back 如何转发参数到 President 的构造函数，并展示如何用 emplace_back 避免用 push_back 时的额外复制或移动操作。

#include <vector>
#include <string>
#include <iostream>

struct President
{
    std::string name;
    std::string country;
    int year;

    President(std::string p_name, std::string p_country, int p_year)
        : name(std::move(p_name)), country(std::move(p_country)), year(p_year)
    {
        std::cout << "I am being constructed.\n";
    }
    President(President&& other)
        : name(std::move(other.name)), country(std::move(other.country)), year(other.year)
    {
        std::cout << "I am being moved.\n";
    }
    President& operator=(const President& other) = default;
};

int main()
{
    std::vector<President> elections;
    std::cout << "emplace_back:\n";
    elections.emplace_back("Nelson Mandela", "South Africa", 1994);

    std::vector<President> reElections;
    std::cout << "\npush_back:\n";
    reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));

    std::cout << "\nContents:\n";
    for (President const& president: elections) {
        std::cout << president.name << " was elected president of "
                  << president.country << " in " << president.year << ".\n";
    }
    for (President const& president: reElections) {
        std::cout << president.name << " was re-elected president of "
                  << president.country << " in " << president.year << ".\n";
    }
}

输出：

emplace_back:
I am being constructed.

push_back:
I am being constructed.
I am being moved.

Contents:
Nelson Mandela was elected president of South Africa in 1994.
Franklin Delano Roosevelt was re-elected president of the USA in 1936.

参阅

push_back
 将元素添加到容器末尾
(公开成员函数)


std::vector<T,Allocator>::empty

< cpp‎ | container‎ | vector

bool empty() const; | (C++11 前)
bool empty() const noexcept; | (C++11 起) (C++20 前)
[[nodiscard]] constexpr bool empty() const noexcept; | (C++20 起)

检查容器是否无元素，即是否 begin() == end() 。

参数

（无）

返回值

若容器为空则为 true ，否则为 false

复杂度

常数。

示例

下列代码用 empty 检查 std::vector <int> 是否含有任何元素:

#include <vector>
#include <iostream>

int main()
{
    std::cout << std::boolalpha;
    std::vector<int> numbers;
    std::cout << "Initially, numbers.empty(): " << numbers.empty() << '\n';

    numbers.push_back(42);
    std::cout << "After adding elements, numbers.empty(): " << numbers.empty() << '\n';
}

输出：

Initially, numbers.empty(): true
After adding elements, numbers.empty(): false

参阅

size
 返回容纳的元素数
(公开成员函数)


std::vector<T,Allocator>::end, std::vector<T,Allocator>::cend

< cpp‎ | container‎ | vector

iterator end(); | (C++11 前)
iterator end() noexcept; | (C++11 起) (C++20 前)
constexpr iterator end() noexcept; | (C++20 起)
const_iterator end() const; | (C++11 前)
const_iterator end() const noexcept; | (C++11 起) (C++20 前)
constexpr const_iterator end() const noexcept; | (C++20 起)
const_iterator cend() const noexcept; | (C++11 起) (C++20 前)
constexpr const_iterator cend() const noexcept; | (C++20 起)

返回指向 vector 末元素后一元素的迭代器。

此元素表现为占位符；试图访问它导致未定义行为。

参数

（无）

返回值

指向后随最后元素的迭代器。

复杂度

常数。

示例

#include <iostream>
#include <numeric>
#include <vector>
#include <string>

int main()
{
        std::vector<int> nums {1, 2, 4, 8, 16};
        std::vector<std::string> fruits {"orange", "apple", "raspberry"};
        std::vector<char> empty;

        // 求和 vector nums 中的所有整数（若存在），仅打印结果。
        std::cout << "Sum of nums: " <<
                std::accumulate(nums.begin(), nums.end(), 0) << "\n";

        // 打印 vector fruits 中的首个 fruis ，不检查是否有一个。
        std::cout << "First fruit: " << *fruits.begin() << "\n";

        if (empty.begin() == empty.end())
                std::cout << "vector 'empty' is indeed empty.\n";
}

输出：

Sum of nums: 31
First fruit: orange
vector 'empty' is indeed empty.

参阅

begin cbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)


std::vector<T,Allocator>::erase

< cpp‎ | container‎ | vector

 | (1)
iterator erase( iterator pos ); |  | (C++11 前)
iterator erase( const_iterator pos ); |  | (C++11 起) (C++20 前)
constexpr iterator erase( const_iterator pos ); |  | (C++20 起)
 | (2)
iterator erase( iterator first, iterator last ); |  | (C++11 前)
iterator erase( const_iterator first, const_iterator last ); |  | (C++11 起) (C++20 前)
constexpr iterator erase( const_iterator first, const_iterator last ); |  | (C++20 起)

从容器擦除指定的元素。

1) 移除位于 pos 的元素。
2) 移除范围 [first; last) 中的元素。

非法化位于擦除点或之后的迭代器，包含 end() 迭代器。

迭代器 pos 必须合法且可解引用。从而不能以 end() 迭代器（合法，但不可解引用）为 pos 的值。

若 first==last 则迭代器 first 不必可解引用：擦除空范围是无操作。

参数

pos | - | 指向要移除的元素的迭代器
first, last | - | 要移除的元素范围
类型要求
- T 必须满足可移动赋值 (MoveAssignable) 的要求。

返回值

后随最后移除元素的迭代器。

若 pos 指代末元素，则返回 end() 迭代器。

若在移除前 last == end() ，则返回更新的 end() 迭代器。

若 [first, last) 为空范围，则返回 last 。

异常

不抛出，除非 T 的赋值运算符抛异常。

复杂度

线性：调用 T 析构函数的次数与被擦除的元素数相同，调用 T 赋值运算符的次数与 vector 中被擦除元素后的元素数相等。

示例

#include <vector>
#include <iostream>

int main( )
{
    std::vector<int> c{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    for (auto &i : c) {
        std::cout << i << " ";
    }
    std::cout << '\n';

    c.erase(c.begin());

    for (auto &i : c) {
        std::cout << i << " ";
    }
    std::cout << '\n';

    c.erase(c.begin()+2, c.begin()+5);

    for (auto &i : c) {
        std::cout << i << " ";
    }
    std::cout << '\n';
}

输出：

0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 6 7 8 9

参阅

clear
 清除内容
(公开成员函数)


std::erase, std::erase_if (std::vector)

< cpp‎ | container‎ | vector

定义于头文件 <vector>
template< class T, class Alloc, class U >

constexpr typename std::vector <T,Alloc>::size_type

erase( std::vector <T,Alloc>& c, const U& value);
 (1) (C++20 起)
template< class T, class Alloc, class Pred >

constexpr typename std::vector <T,Alloc>::size_type

erase_if( std::vector <T,Alloc>& c, Pred pred);
 (2) (C++20 起)
1) 从容器中擦除所有比较等于 value 的元素。等价于
auto it = std::remove(c.begin(), c.end(), value);
auto r = std::distance(it, c.end());
c.erase(it, c.end());
return r;
2) 从容器中擦除所有满足 pred 的元素。等价于
auto it = std::remove_if(c.begin(), c.end(), pred);
auto r = std::distance(it, c.end());
c.erase(it, c.end());
return r;

参数

c | - | 要从中擦除的容器
value | - | 要擦除的值
pred | - | 若应该擦除元素则返回 ​true 的一元谓词。 对每个（可为 const 的） T 类型参数 v ，表达式 pred(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 T& 类型参数，亦不允许 T ，除非对 T 而言移动等价于复制 (C++11 起)。 ​

返回值

被擦除的元素数。

复杂度

线性。

示例

#include <iostream>
#include <numeric>
#include <vector>

void print_container(const std::vector<char>& c)
{
    for (auto x : c) {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    std::vector<char> cnt(10);
    std::iota(cnt.begin(), cnt.end(), '0');

    std::cout << "Init:\n";
    print_container(cnt);

    auto erased = std::erase(cnt, '3');
    std::cout << "Erase \'3\':\n";
    print_container(cnt);

    std::erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; });
    std::cout << "Erase all even numbers:\n";
    print_container(cnt);
    std::cout << "In all " << erased << " even numbers were erased.\n";
}

输出：

Init:
0 1 2 3 4 5 6 7 8 9
Erase '3':
0 1 2 4 5 6 7 8 9
Erase all even numbers:
1 5 7 9
In all 5 even numbers were erased.

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::vector<T,Allocator>::front

< cpp‎ | container‎ | vector

reference front(); | (C++20 前)
constexpr reference front(); | (C++20 起)
const_reference front() const; | (C++20 前)
constexpr const_reference front() const; | (C++20 起)

返回到容器首元素的引用。

在空容器上对 front 的调用是未定义的。

参数

（无）

返回值

到首元素的引用

复杂度

常数

注解

对于容器 c ，表达式 c.front() 等价于 *c.begin() 。

示例

下列代码用 front 显示 std::vector <char> 的首元素：

#include <vector>
#include <iostream>

int main()
{
    std::vector<char> letters {'o', 'm', 'g', 'w', 't', 'f'};

    if (!letters.empty()) {
        std::cout << "The first character is: " << letters.front() << '\n';
    }
}

输出：

The first character is o

参阅

back
 访问最后一个元素
(公开成员函数)


std::vector<T,Allocator>::get_allocator

< cpp‎ | container‎ | vector

allocator_type get_allocator() const; | (C++11 前)
allocator_type get_allocator() const noexcept; | (C++11 起) (C++20 前)
constexpr allocator_type get_allocator() const noexcept; | (C++20 起)

返回与容器关联的分配器。

参数

（无）

返回值

关联的分配器。

复杂度

常数。


std::vector<T,Allocator>::insert

< cpp‎ | container‎ | vector

 | (1)
iterator insert( iterator pos, const T& value ); |  | (C++11 前)
iterator insert( const_iterator pos, const T& value ); |  | (C++11 起) (C++20 前)
constexpr iterator insert( const_iterator pos, const T& value ); |  | (C++20 起)
 | (2)
iterator insert( const_iterator pos, T&& value ); |  | (C++11 起) (C++20 前)
constexpr iterator insert( const_iterator pos, T&& value ); |  | (C++20 起)
 | (3)
void insert( iterator pos, size_type count, const T& value ); |  | (C++11 前)
iterator insert( const_iterator pos, size_type count, const T& value ); |  | (C++11 起) (C++20 前)
constexpr iterator insert( const_iterator pos, size_type count, const T& value ); |  | (C++20 起)
 | (4)
template< class InputIt > void insert( iterator pos, InputIt first, InputIt last); |  | (C++11 前)
template< class InputIt > iterator insert( const_iterator pos, InputIt first, InputIt last ); |  | (C++11 起) (C++20 前)
template< class InputIt > constexpr iterator insert( const_iterator pos, InputIt first, InputIt last ); |  | (C++20 起)
 | (5)
iterator insert( const_iterator pos, std::initializer_list <T> ilist ); |  | (C++11 起) (C++20 前)
constexpr iterator insert( const_iterator pos, std::initializer_list <T> ilist ); |  | (C++20 起)

插入元素到容器中的指定位置。

1-2) 在 pos 前插入 value 。
3) 在 pos 前插入 value 的 count 个副本。
4) 在 pos 前插入来自范围 [first, last) 的元素。
若 InputIt 为整数类型，则此重载与重载 (3) 拥有相同效果。 | (C++11 前)
此重载仅若 InputIt 足以为老式输入迭代器 (LegacyInputIterator) 才参与重载决议，以避免与重载 (3) 有歧义。 | (C++11 起)
若 first 和 last 是指向 *this 中的迭代器，则行为未定义。
5) 在 pos 前插入来自 initializer_list ilist 的元素。

若新 size() 大于旧 capacity() 则导致重分配。 若新的 size() 大于 capacity() ，则所有迭代器和引用都被非法化。否则，仅在插入点前的迭代器和引用保持合法。尾后迭代器亦被非法化。

参数

pos | - | 将内容插入到其前的迭代器。 pos 可为 end() 迭代器
value | - | 要插入的元素值
first, last | - | 要插入的元素范围，不能是指向调用 insert 所用的容器中的迭代器
ilist | - | 要插入的值来源的 initializer_list
类型要求
- 为使用重载 (1) ， T 必须满足可复制赋值 (CopyAssignable) 和 可复制插入 (CopyInsertable) 的要求。
- 为使用重载 (2) ， T 必须满足可移动赋值 (MoveAssignable) 和 可移动插入 (MoveInsertable) 的要求。
- 为使用重载 (3) ， T 必须满足可复制赋值 (CopyAssignable) 和 可复制插入 (CopyInsertable) 的要求。
- 为使用重载 (4,5) ， T 必须满足可就位构造 (EmplaceConstructible) 的要求。
- 为使用重载 (4) ， T 必须满足可移动赋值 (MoveAssignable) 和 可移动插入 (MoveInsertable) 的要求。仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 但不满足老式向前迭代器 (LegacyForwardIterator) 才要求。(C++17 前)
- 为使用重载 (4,5) ， T 必须满足可交换 (Swappable) 、 可移动赋值 (MoveAssignable) 、 可移动构造 (MoveConstructible) 和 可移动插入 (MoveInsertable) 的要求。(C++17 起)

返回值

1-2) 指向被插入 value 的迭代器。
3) 指向首个被插入元素的迭代器，或若 count==0 则为 pos 。
4) 指向首个被插入元素的迭代器，或若 first==last 则为 pos 。
5) 指向首个被插入元素的迭代器，或若 ilist 为空则为 pos 。

复杂度

1-2) 常数，加上 pos 与容器结尾的距离成线性。
3) 与 count 成线性，加上 pos 与容器结尾的距离成线性。
4) 与 std::distance (first, last) 成线性，加上 pos 与容器结尾的距离成线性。
5) 与 ilist.size() 成线性，加上 pos 与容器结尾的距离成线性。

异常

若在尾端插入单个元素时抛出异常，且 T 为可复制插入 (CopyInsertable) 或 std::is_nothrow_move_constructible<T>::value 为 true ，则无效果（强异常保证）。

示例

#include <iostream>
#include <vector>

void print_vec(const std::vector<int>& vec)
{
    for (auto x: vec) {
         std::cout << ' ' << x;
    }
    std::cout << '\n';
}

int main ()
{
    std::vector<int> vec(3,100);
    print_vec(vec);

    auto it = vec.begin();
    it = vec.insert(it, 200);
    print_vec(vec);

    vec.insert(it,2,300);
    print_vec(vec);

    // "it" 不再合法，获取新值：
    it = vec.begin();

    std::vector<int> vec2(2,400);
    vec.insert(it+2, vec2.begin(), vec2.end());
    print_vec(vec);

    int arr[] = { 501,502,503 };
    vec.insert(vec.begin(), arr, arr+3);
    print_vec(vec);
}

输出：

100 100 100
200 100 100 100
300 300 200 100 100 100
300 300 400 400 200 100 100 100
501 502 503 300 300 400 400 200 100 100 100

参阅

emplace (C++11) | 原位构造元素 (公开成员函数)
push_back | 将元素添加到容器末尾 (公开成员函数)


std::vector<T,Allocator>::max_size

< cpp‎ | container‎ | vector

size_type max_size() const; | (C++11 前)
size_type max_size() const noexcept; | (C++11 起) (C++20 前)
constexpr size_type max_size() const noexcept; | (C++20 起)

返回根据系统或库实现限制的容器可保有的元素最大数量，即对于最大容器的 std::distance (begin(), end()) 。

参数

（无）

返回值

元素数量的最大值。

复杂度

常数。

注解

此值通常反映容器大小上的理论极限，至多为 std::numeric_limits <difference_type>::max() 。运行时，可用 RAM 总量可能会限制容器大小到小于 max_size() 的值。

示例

#include <iostream>
#include <vector>

int main()
{
    std::vector<char> s;
    std::cout << "Maximum size of a 'vector' is " << s.max_size() << "\n";
}

可能的输出：

Maximum size of a 'vector' is 9223372036854775807

参阅

size | 返回容纳的元素数 (公开成员函数)
capacity | 返回当前存储空间能够容纳的元素数 (公开成员函数)


std::vector<T,Allocator>::operator=

< cpp‎ | container‎ | vector

 | (1)
vector& operator=( const vector& other ); |  | (C++20 前)
constexpr vector& operator=( const vector& other ); |  | (C++20 起)
 | (2)
vector& operator=( vector&& other ); |  | (C++11 起) (C++17 前)
vector& operator=( vector&& other ) noexcept(/* see below */); |  | (C++17 起) (C++20 前)
constexpr vector& operator=( vector&& other ) noexcept(/* see below */); |  | (C++20 起)
 | (3)
vector& operator=( std::initializer_list <T> ilist ); |  | (C++11 起) (C++20 前)
constexpr vector& operator=( std::initializer_list <T> ilist ); |  | (C++20 起)

替换容器内容。

1) 复制赋值运算符。以 other 的副本替换内容。

若 std::allocator_traits <allocator_type>::propagate_on_container_copy_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若 *this 的分配器在赋值后将与其旧值比较不相等，则用旧分配器解分配内存，然后在复制元素前用新分配器分配内存。否则，在可行时可能复用 *this 所拥有的内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素复制赋值替换。

 (C++11 起)
2) 移动赋值运算符。用移动语义以 other 的内容替换内容（即从 other 移动 other 中的数据到此容器中）。之后 other 在合法但未指定的状态。
若 std::allocator_traits <allocator_type>::propagate_on_container_move_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若它为 false 且 *this 与 other 的分配器不比较相等，则 *this 不能接管 other 所拥有的内存的所有权且必须单独地移动赋值每个元素，并用其自身的分配器按需分配额外内存。任何情况下，原属于 *this 的元素要么被销毁，要么被逐元素移动赋值替换。
3) 以 initializer_list ilist 所标识者替换内容。

参数

other | - | 用作数据源的另一容器
ilist | - | 用作数据源的 initializer_list

返回值

*this

复杂度

1) 与 *this 和 other 的大小成线性。
2) 与 *this 的大小成线性，除非分配器不比较相等且不传播，该情况下与 *this 和 other 的大小成线性。
3) 与 *this 和 ilist 的大小成线性。

异常

可能抛出实现定义的异常。

 (C++17 前)
1,3) 可能抛出实现定义的异常。
2)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::propagate_on_container_move_assignment::value
|| std::allocator_traits <Allocator>::is_always_equal::value)
 (C++17 起)

注解

在容器移动赋值（重载 (2) ）后，除非不兼容的分配器强制逐元素移动赋值，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

下列代码用 operator= 赋值一个 std::vector 给另一个：

#include <vector>
#include <iostream>

void display_sizes(char const* comment,
                   const std::vector<int>& nums1,
                   const std::vector<int>& nums2,
                   const std::vector<int>& nums3)
{
    std::cout << comment
              << " nums1: " << nums1.size() << ','
              << " nums2: " << nums2.size() << ','
              << " nums3: " << nums3.size() << '\n';
}

void display(char const* comment, const std::vector<int>& v)
{
    std::cout << comment << "{ ";
    for (int e : v) {
        std::cout << e << ' ';
    }
    std::cout << "}\n";
}

int main()
{
    std::vector<int> nums1 {3, 1, 4, 6, 5, 9};
    std::vector<int> nums2;
    std::vector<int> nums3;

    display_sizes("Initially:\n", nums1, nums2, nums3);

    // 从 nums1 复制赋值数据到 nums2
    nums2 = nums1;

    display_sizes("After assigment:\n", nums1, nums2, nums3);

    // 从 nums1 移动赋值数据到 nums3,
    // 修改 nums1 和 nums3
    nums3 = std::move(nums1);

    display_sizes("After move assigment:\n", nums1, nums2, nums3);

    display("Now nums3 = ", nums3);

    // initializer_list 的复制赋值复制数据给 nums3
    nums3 = {1, 2, 3};

    display("After assignment of initializer_list \n nums3 = ", nums3);
}

输出：

Initially:
 nums1: 6, nums2: 0, nums3: 0
After assigment:
 nums1: 6, nums2: 6, nums3: 0
After move assigment:
 nums1: 0, nums2: 6, nums3: 6
Now nums3 = { 3 1 4 6 5 9 }
After assignment of initializer_list
 nums3 = { 1 2 3 }

参阅

(构造函数) | 构造 vector (公开成员函数)
assign | 将值赋给容器 (公开成员函数)


std::vector<T,Allocator>::operator[]

< cpp‎ | container‎ | vector

reference operator[]( size_type pos ); | (C++20 前)
constexpr reference operator[]( size_type pos ); | (C++20 起)
const_reference operator[]( size_type pos ) const; | (C++20 前)
constexpr const_reference operator[]( size_type pos ) const; | (C++20 起)

返回位于指定位置 pos 的元素的引用。不进行边界检查。

参数

pos - 要返回的元素的位置

返回值

到所需元素的引用。

复杂度

常数。

注解

不同于 std::map::operator[] ，此运算符决不插入新元素到容器。通过此运算符访问不存在的元素是未定义行为。

示例

下列代码使用 operator[] 读取并写入 std::vector <int> ：

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> numbers {2, 4, 6, 8};

    std::cout << "Second element: " << numbers[1] << '\n';

    numbers[0] = 5;

    std::cout << "All numbers:";
    for (auto i : numbers) {
        std::cout << ' ' << i;
    }
    std::cout << '\n';
}

输出：

Second element: 4
All numbers: 5 4 6 8

参阅

at
 访问指定的元素，同时进行越界检查
(公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::vector)

< cpp‎ | container‎ | vector

定义于头文件 <vector>
(1)
template< class T, class Alloc >

bool operator==( const std::vector <T,Alloc>& lhs,

const std::vector <T,Alloc>& rhs );
 (C++20 前)
template< class T, class Alloc >

constexpr bool operator==( const std::vector <T,Alloc>& lhs,

const std::vector <T,Alloc>& rhs );
 (C++20 起)
template< class T, class Alloc >

bool operator!=( const std::vector <T,Alloc>& lhs,

const std::vector <T,Alloc>& rhs );
 (2) (C++20 前)
template< class T, class Alloc >

bool operator<( const std::vector <T,Alloc>& lhs,

const std::vector <T,Alloc>& rhs );
 (3) (C++20 前)
template< class T, class Alloc >

bool operator<=( const std::vector <T,Alloc>& lhs,

const std::vector <T,Alloc>& rhs );
 (4) (C++20 前)
template< class T, class Alloc >

bool operator>( const std::vector <T,Alloc>& lhs,

const std::vector <T,Alloc>& rhs );
 (5) (C++20 前)
template< class T, class Alloc >

bool operator>=( const std::vector <T,Alloc>& lhs,

const std::vector <T,Alloc>& rhs );
 (6) (C++20 前)
template< class T, class Alloc >

constexpr /* see below */ operator<=>( const std::vector <T,Alloc>& lhs,

const std::vector <T,Alloc>& rhs );
 (7) (C++20 起)

比较二个 vector 的内容。

1-2) 检查 lhs 与 rhs 的内容是否相等，即它们是否拥有相同数量的元素且 lhs 中每个元素与 rhs 的同位置元素比较相等。
3-6) 按字典序比较 lhs 与 rhs 的内容。由等价于 std::lexicographical_compare 的函数进行比较。
7) 按字典序比较 lhs 与 rhs 的内容。如同通过在二个 vector 上以进行合成三路比较（见后述）的函数对象调用 std::lexicographical_compare_three_way 进行比较。返回类型同合成三路比较的结果类型。

给定分别作为左操作数与右操作数的两个 const E 左值 lhs 与 rhs （其中 E 为 T ），合成三路比较定义如下：

  • 若 std::three_way_comparable_with<E, E> 得到满足则等价于 lhs <=> rhs ；
  • 否则，若以 operator< 比较二个 const E 左值为良构且结果类型满足 boolean-testable ，则等价于
lhs < rhs ? std::weak_ordering::less :
rhs < lhs ? std::weak_ordering::greater :
            std::weak_ordering::equivalent
  • 否则，不定义合成三路比较，而 operator<=> 不参与重载决议。
若 three_way_comparable_with 或 boolean-testable 被满足但未被实现，或使用 operator< 但 E 与 < 不建立全序，则 operator<=> 的行为未定义。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较内容的 vector
-
为使用重载 (1-2) ， T 必须满足可相等比较 (EqualityComparable) 的要求。
-
为使用重载 (3-6) ， T 必须满足可小于比较 (LessThanComparable) 的要求。顺序关系必须建立全序。

返回值

1) 若 vector 内容相等则为 true ，否则为 false
2) 若 vector 内容不相等则为 true ，否则为 false
3) 若 lhs 的内容按字典序小于 rhs 的内容则为 true ，否则为 false
4) 若 lhs 的内容按字典序小于或等于 rhs 的内容则为 true ，否则为 false
5) 若 lhs 的内容按字典序大于 rhs 的内容则为 true ，否则为 false
6) 若 lhs 的内容按字典序大于或等于 rhs 的内容则为 true ，否则为 false
7) lhs 与 rhs 中的首对不等价元素的相对顺序，若有这种元素；否则为 lhs.size() <=> rhs.size() 。

复杂度

1-2) 若 lhs 与 rhs 的大小不同则为常数，否则与 vector 大小成线性
3-7) 与 vector 大小成线性

示例

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> alice{1, 2, 3};
    std::vector<int> bob{7, 8, 9, 10};
    std::vector<int> eve{1, 2, 3};

    std::cout << std::boolalpha;

    // 比较不相等的容器
    std::cout << "alice == bob returns " << (alice == bob) << '\n';
    std::cout << "alice != bob returns " << (alice != bob) << '\n';
    std::cout << "alice <  bob returns " << (alice < bob) << '\n';
    std::cout << "alice <= bob returns " << (alice <= bob) << '\n';
    std::cout << "alice >  bob returns " << (alice > bob) << '\n';
    std::cout << "alice >= bob returns " << (alice >= bob) << '\n';

    std::cout << '\n';

    // 比较相等的容器
    std::cout << "alice == eve returns " << (alice == eve) << '\n';
    std::cout << "alice != eve returns " << (alice != eve) << '\n';
    std::cout << "alice <  eve returns " << (alice < eve) << '\n';
    std::cout << "alice <= eve returns " << (alice <= eve) << '\n';
    std::cout << "alice >  eve returns " << (alice > eve) << '\n';
    std::cout << "alice >= eve returns " << (alice >= eve) << '\n';
}

输出：

alice == bob returns false
alice != bob returns true
alice <  bob returns true
alice <= bob returns true
alice >  bob returns false
alice >= bob returns false

alice == eve returns true
alice != eve returns false
alice <  eve returns false
alice <= eve returns true
alice >  eve returns false
alice >= eve returns true


std::vector<T,Allocator>::pop_back

< cpp‎ | container‎ | vector

void pop_back(); | (C++20 前)
constexpr void pop_back(); | (C++20 起)

移除容器的末元素。

在空容器上调用 pop_back 导致未定义行为。

非法化指向末元素的迭代器和引用，以及 end() 迭代器。

参数

（无）

返回值

（无）

复杂度

常数。

异常

不抛出。

示例

#include <vector>
#include <iostream>

template<class T>
void print(T const & xs)
{
    std::cout << "[ ";
    for(auto && x : xs) {
        std::cout << x << ' ';
    }
    std::cout << "]\n";
}

int main()
{
    std::vector<int> numbers;

    print(numbers);

    numbers.push_back(5);
    numbers.push_back(3);
    numbers.push_back(4);

    print(numbers);

    numbers.pop_back();

    print(numbers);
}

输出：

[ ]
[ 5 3 4 ]
[ 5 3 ]

参阅

push_back
 将元素添加到容器末尾
(公开成员函数)


std::vector<T,Allocator>::push_back

< cpp‎ | container‎ | vector

 | (1)
void push_back( const T& value ); |  | (C++20 前)
constexpr void push_back( const T& value ); |  | (C++20 起)
 | (2)
void push_back( T&& value ); |  | (C++11 起) (C++20 前)
constexpr void push_back( T&& value ); |  | (C++20 起)

后附给定元素 value 到容器尾。

1) 初始化新元素为 value 的副本。
2) 移动 value 进新元素。

若新的 size() 大于 capacity() ，则所有迭代器和引用（包含尾后迭代器）都被非法化。否则仅尾后迭代器被非法化。

参数

value - 要后附的元素值
类型要求
-
为使用重载 (1) ， T 必须满足可复制插入 (CopyInsertable) 的要求。
-
为使用重载 (2) ， T 必须满足可移动插入 (MoveInsertable) 的要求。

返回值

（无）

复杂度

均摊常数。

异常

若抛出异常（可能因为 Allocator::allocate() 或元素复制/移动构造函数/赋值），则此函数无效果（强异常保证）。

若 T 的移动构造函数不是 noexcept 且 T 不可复制插入 (CopyInsertable) 到 *this ，则 vector 将使用会抛出的移动构造函数。若它抛出，则抛弃保证且效果未指定。

 (C++11 起)

注解

一些实现在 push_back 导致会超出 max_size 的重分配时亦抛出 std::length_error ，由于这会隐式调用 reserve(size()+1) 的等价者。

示例

#include <vector>
#include <iostream>
#include <iomanip>

int main()
{
    std::vector<std::string> letters;

    letters.push_back("abc");
    std::string s = "def";
    letters.push_back(std::move(s));

    std::cout << "vector holds: ";
    for (auto&& i : letters) std::cout << std::quoted(i) << ' ';
    std::cout << "\nMoved-from string holds " << std::quoted(s) << '\n';
}

输出：

vector holds: "abc" "def"
Moved-from string holds ""

参阅

emplace_back (C++11) | 在容器末尾就地构造元素 (公开成员函数)
pop_back | 移除末元素 (公开成员函数)


std::vector<T,Allocator>::rbegin, std::vector<T,Allocator>::crbegin

< cpp‎ | container‎ | vector

reverse_iterator rbegin(); | (C++11 前)
reverse_iterator rbegin() noexcept; | (C++11 起) (C++20 前)
constexpr reverse_iterator rbegin() noexcept; | (C++20 起)
const_reverse_iterator rbegin() const; | (C++11 前)
const_reverse_iterator rbegin() const noexcept; | (C++11 起) (C++20 前)
constexpr const_reverse_iterator rbegin() const noexcept; | (C++20 起)
const_reverse_iterator crbegin() const noexcept; | (C++11 起) (C++20 前)
constexpr const_reverse_iterator crbegin() const noexcept; | (C++20 起)

返回指向逆向 vector 首元素的逆向迭代器。它对应非逆向 vector 的末元素。若 vector 为空，则返回的迭代器等于 rend() 。

参数

（无）

返回值

指向首元素的逆向迭代器。

复杂度

常数。

示例

#include <iostream>
#include <numeric>
#include <vector>
#include <string>

int main()
{
        std::vector<int> nums {1, 2, 4, 8, 16};
        std::vector<std::string> fruits {"orange", "apple", "raspberry"};
        std::vector<char> empty;

        // 求和 vector nums 中的所有整数（若存在），仅打印结果。
        std::cout << "Sum of nums: " <<
                std::accumulate(nums.begin(), nums.end(), 0) << "\n";

        // 打印 vector fruits 中的首个 fruis ，不检查是否有一个。
        std::cout << "First fruit: " << *fruits.begin() << "\n";

        if (empty.begin() == empty.end())
                std::cout << "vector 'empty' is indeed empty.\n";
}

输出：

Sum of nums: 31
First fruit: orange
vector 'empty' is indeed empty.

参阅

rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)


std::vector<T,Allocator>::rend, std::vector<T,Allocator>::crend

< cpp‎ | container‎ | vector

reverse_iterator rend(); | (C++11 前)
reverse_iterator rend() noexcept; | (C++11 起) (C++20 前)
constexpr reverse_iterator rend() noexcept; | (C++20 起)
const_reverse_iterator rend() const; | (C++11 前)
const_reverse_iterator rend() const noexcept; | (C++11 起) (C++20 前)
constexpr const_reverse_iterator rend() const noexcept; | (C++20 起)
const_reverse_iterator crend() const noexcept; | (C++11 起) (C++20 前)
constexpr const_reverse_iterator crend() const noexcept; | (C++20 起)

返回指向逆向 vector 末元素后一元素的逆向迭代器。它对应非逆向 vector 首元素的前一元素。此元素表现为占位符，试图访问它导致未定义行为。

参数

（无）

返回值

指向末元素后一元素的逆向迭代器。

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)


std::vector<T,Allocator>::reserve

< cpp‎ | container‎ | vector
void reserve( size_type new_cap ); | (C++20 前)
constexpr void reserve( size_type new_cap ); | (C++20 起)

增加 vector 的容量到大于或等于 new_cap 的值。若 new_cap 大于当前的 capacity() ，则分配新存储，否则该方法不做任何事。

reserve() 不更改 vector 的 size 。

若 new_cap 大于 capacity() ，则所有迭代器，包含尾后迭代器和所有到元素的引用都被非法化。否则，没有迭代器或引用被非法化。

参数

new_cap - vector 的新容量
类型要求
-
T 必须满足可移动插入 (MoveInsertable) 的要求。

返回值

（无）

异常

  • 若 new_cap > max_size() 则为 std::length_error 。
  • 任何 Allocator::allocate() 所抛的异常（典型为 std::bad_alloc ）

若抛出异常，则此函数无效果（强异常保证）。

若 T 的移动构造函数不是 noexcept 且 T 非可复制插入 (CopyInsertable) 到 *this ，则 vector 将使用移动构造函数。若它抛出，则摒弃保证，且效果未指定。

 (C++11 起)

复杂度

至多与容器的 size() 成线性。

注解

正确使用 reserve() 能避免不必要的分配，但不适当地使用 reserve() （例如在每次 push_back() 调用前调用它）可能会实际增加重分配的数量（通过导致容量线性而非指数增长）并导致计算复杂度增加，性能下降。例如，按引用接受任意 vector 并后附元素的函数通常不应在 vector 上调用 reserve() ，因为它不知道该 vector 的使用特征。

插入范围时， insert() 的范围版本通常更合适，因为它保持正确的容量增长行为，而不同于 reserve() 后随一系列 push_back() 。

不能用 reserve() 减少容器容量。为该目的提供的是 shrink_to_fit() 。

示例

#include <cstddef>
#include <new>
#include <vector>
#include <iostream>

// 带调试输出的最小 C++11 分配器
template <class Tp>
struct NAlloc {
    typedef Tp value_type;
    NAlloc() = default;
    template <class T> NAlloc(const NAlloc<T>&) {}
    Tp* allocate(std::size_t n)
    {
        n *= sizeof(Tp);
        std::cout << "allocating " << n << " bytes\n";
        return static_cast<Tp*>(::operator new(n));
    }
    void deallocate(Tp* p, std::size_t n)
    {
        std::cout << "deallocating " << n*sizeof(Tp) << " bytes\n";
        ::operator delete(p);
    }
};
template <class T, class U>
bool operator==(const NAlloc<T>&, const NAlloc<U>&) { return true; }
template <class T, class U>
bool operator!=(const NAlloc<T>&, const NAlloc<U>&) { return false; }

int main()
{
    int sz = 100;
    std::cout << "using reserve: \n";
    {
        std::vector<int, NAlloc<int>> v1;
        v1.reserve(sz);
        for(int n = 0; n < sz; ++n)
            v1.push_back(n);
    }
    std::cout << "not using reserve: \n";
    {
        std::vector<int, NAlloc<int>> v1;
        for(int n = 0; n < sz; ++n)
            v1.push_back(n);
    }
}

可能的输出：

using reserve:
allocating 400 bytes
deallocating 400 bytes
not using reserve:
allocating 4 bytes
allocating 8 bytes
deallocating 4 bytes
allocating 16 bytes
deallocating 8 bytes
allocating 32 bytes
deallocating 16 bytes
allocating 64 bytes
deallocating 32 bytes
allocating 128 bytes
deallocating 64 bytes
allocating 256 bytes
deallocating 128 bytes
allocating 512 bytes
deallocating 256 bytes
deallocating 512 bytes

参阅

capacity | 返回当前存储空间能够容纳的元素数 (公开成员函数)
max_size | 返回可容纳的最大元素数 (公开成员函数)
resize | 改变容器中可存储元素的个数 (公开成员函数)
shrink_to_fit (C++11) | 通过释放未使用的内存减少内存的使用 (公开成员函数)


std::vector<T,Allocator>::resize

< cpp‎ | container‎ | vector

 | (1)
void resize( size_type count ); |  | (C++11 起) (C++20 前)
constexpr void resize( size_type count ); |  | (C++20 起)
 | (2)
void resize( size_type count, T value = T() ); |  | (C++11 前)
void resize( size_type count, const value_type& value ); |  | (C++11 起) (C++20 前)
constexpr void resize( size_type count, const value_type& value ); |  | (C++20 起)

重设容器大小以容纳 count 个元素。

若当前大小大于 count ，则减小容器为其首 count 个元素。

若当前大小小于 count ，

1) 则后附额外的默认插入的元素
2) 则后附额外的 value 的副本

参数

count | - | 容器的大小
value | - | 用以初始化新元素的值
类型要求
- 为使用重载 (1) ， T 必须满足可移动插入 (MoveInsertable) 和 可默认插入 (DefaultInsertable) 的要求。
- 为使用重载 (2) ， T 必须满足可复制插入 (CopyInsertable) 的要求。

返回值

（无）

复杂度

与当前大小和 count 间的差成线性。若容量小于 count 则可能有重分配所致的额外复杂度。

异常

若抛出异常，则此函数无效果（强异常保证）。

重载 (1) 中，若 T 的移动构造函数不是 noexcept 且 T 不可复制插入 (CopyInsertable) 到 *this ，则 vector 将使用会抛出的移动构造函数。若它抛出，则抛弃保证且效果未指定。

 (C++11 起)

注解

若不想要重载 (1) 中的值初始化，例如元素是非类类型且不需要清零，则可以提供定制的 Allocator::construct 避免。 在重设大小到较小值时， vector 的容量决不减少，因为这会非法化所有的，而非只非法化等价的 pop_back() 调用序列所非法化的迭代器。

示例

#include <iostream>
#include <vector>
int main()
{
    std::vector<int> c = {1, 2, 3};
    std::cout << "The vector holds: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
    c.resize(5);
    std::cout << "After resize up to 5: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
    c.resize(2);
    std::cout << "After resize down to 2: ";
    for(auto& el: c) std::cout << el << ' ';
    std::cout << '\n';
}

输出：

The vector holds: 1 2 3
After resize up to 5: 1 2 3 0 0
After resize down to 2: 1 2

参阅

size | 返回容纳的元素数 (公开成员函数)
insert | 插入元素 (公开成员函数)
erase | 擦除元素 (公开成员函数)


std::vector<T,Allocator>::shrink_to_fit

< cpp‎ | container‎ | vector

void shrink_to_fit(); | (C++11 起) (C++20 前)
constexpr void shrink_to_fit(); | (C++20 起)

请求移除未使用的容量。

它是减少 capacity() 到 size()非强制性请求。请求是否达成依赖于实现。

若发生重分配，则所有迭代器，包含尾后迭代器，和所有到元素的引用都被非法化。若不发生重分配，则没有迭代器或引用被非法化。

参数

（无）

类型要求
-
T 必须满足可移动插入 (MoveInsertable) 的要求。

返回值

（无）

复杂度

至多与容器大小成线性。

注解

若 T 的移动构造函数以外的操作抛出异常，则无效果。

示例

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v;
    std::cout << "Default-constructed capacity is " << v.capacity() << '\n';
    v.resize(100);
    std::cout << "Capacity of a 100-element vector is " << v.capacity() << '\n';
    v.resize(50);
    std::cout << "Capacity after resize(50) is " << v.capacity() << '\n';
    v.shrink_to_fit();
    std::cout << "Capacity after shrink_to_fit() is " << v.capacity() << '\n';
    v.clear();
    std::cout << "Capacity after clear() is " << v.capacity() << '\n';
    v.shrink_to_fit();
    std::cout << "Capacity after shrink_to_fit() is " << v.capacity() << '\n';
    for (int i = 1000; i < 1300; ++i)
        v.push_back(i);
    std::cout << "Capacity after adding 300 elements is " << v.capacity() << '\n';
    v.shrink_to_fit();
    std::cout << "Capacity after shrink_to_fit() is " << v.capacity() << '\n';
}

可能的输出：

Default-constructed capacity is 0
Capacity of a 100-element vector is 100
Capacity after resize(50) is 100
Capacity after shrink_to_fit() is 50
Capacity after clear() is 50
Capacity after shrink_to_fit() is 0
Capacity after adding 300 elements is 512
Capacity after shrink_to_fit() is 300

参阅

size | 返回容纳的元素数 (公开成员函数)
capacity | 返回当前存储空间能够容纳的元素数 (公开成员函数)


std::vector<T,Allocator>::size

< cpp‎ | container‎ | vector

size_type size() const; | (C++11 前)
size_type size() const noexcept; | (C++11 起) (C++20 前)
constexpr size_type size() const noexcept; | (C++20 起)

返回容器中的元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

容器中的元素数量。

复杂度

常数。

示例

下列代码用 size 显示 std::vector <int> 中的元素数：

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> nums {1, 3, 5, 7};

    std::cout << "nums contains " << nums.size() << " elements.\n";
}

输出：

nums contains 4 elements.

参阅

capacity | 返回当前存储空间能够容纳的元素数 (公开成员函数)
empty | 检查容器是否为空 (公开成员函数)
max_size | 返回可容纳的最大元素数 (公开成员函数)
resize | 改变容器中可存储元素的个数 (公开成员函数)


std::vector<T,Allocator>::swap

< cpp‎ | container‎ | vector

void swap( vector& other ); | (C++17 前)
void swap( vector& other ) noexcept(/* see below */); | (C++17 起) (C++20 前)
constexpr void swap( vector& other ) noexcept(/* see below */); | (C++20 起)

将内容与 other 的交换。不在单独的元素上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。尾后迭代器被非法化。

若 std::allocator_traits <allocator_type>::propagate_on_container_swap::value 为 true ，则用对非成员 swap 的无限定调用交换分配器。否则，不交换它们（且若 get_allocator() != other.get_allocator() ，则行为未定义）。

 (C++11 起)

参数

other - 要与之交换内容的容器

返回值

（无）

异常

（无）

 (C++17 前)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::propagate_on_container_swap::value
|| std::allocator_traits <Allocator>::is_always_equal::value)
 (C++17 起)

复杂度

常数。

示例

#include <iostream>
#include <vector>

template<class Os, class Co> Os& operator<<(Os& os, const Co& co) {
    os << "{";
    for (auto const& i : co) { os << ' ' << i; }
    return os << " } ";
}

int main()
{
    std::vector<int> a1{1, 2, 3}, a2{4, 5};

    auto it1 = std::next(a1.begin());
    auto it2 = std::next(a2.begin());

    int& ref1 = a1.front();
    int& ref2 = a2.front();

    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';
    a1.swap(a2);
    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';

    // 注意交换后迭代器与引用保持与其原来的元素关联，例如指向 'a1' 中值为 2 的元素的 it1 仍指向同一元素，
    // 尽管此元素被移动到 'a2' 中。
}

输出：

{ 1 2 3 } { 4 5 } 2 5 1 4
{ 4 5 } { 1 2 3 } 2 5 1 4

参阅

std::swap(std::vector)
 特化 std::swap 算法
(函数模板)


std::swap(std::vector)

< cpp‎ | container‎ | vector

定义于头文件 <vector>
template< class T, class Alloc >

void swap( std::vector <T,Alloc>& lhs,

std::vector <T,Alloc>& rhs );
 (C++17 前)
template< class T, class Alloc >

void swap( std::vector <T,Alloc>& lhs,

std::vector <T,Alloc>& rhs ) noexcept(/* see below */);
 (C++17 起)
(C++20 前)
template< class T, class Alloc >

constexpr void swap( std::vector <T,Alloc>& lhs,

std::vector <T,Alloc>& rhs ) noexcept(/* see below */);
 (C++20 起)

为 std::vector 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的容器

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

注解

尽管 std::swap 对容器适配器的重载是在 C++11 引入的， C++98 中已能用 std::swap 交换容器适配器。这种 std::swap 调用通常拥有线性时间复杂度，但可以提供更好的复杂度。

示例

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> alice{1, 2, 3};
    std::vector<int> bob{7, 8, 9, 10};

    auto print = [](const int& n) { std::cout << " " << n; };

    // 打印交换前的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';

    std::cout << "-- SWAP\n";
    std::swap(alice,bob);

    // 打印交换后的状态
    std::cout << "alice:";
    std::for_each(alice.begin(), alice.end(), print);
    std::cout << '\n';
    std::cout << "bob  :";
    std::for_each(bob.begin(), bob.end(), print);
    std::cout << '\n';
}

输出：

alice: 1 2 3
bob  : 7 8 9 10
-- SWAP
alice: 7 8 9 10
bob  : 1 2 3

参阅

swap
 交换内容
(公开成员函数)


std::vector<T,Allocator>::vector

< cpp‎ | container‎ | vector

(1)
vector();
 (C++17 前)
vector() noexcept(noexcept(Allocator()));
 (C++17 起)
(C++20 前)
constexpr vector() noexcept(noexcept(Allocator()));
 (C++20 起)
(2)
explicit vector( const Allocator& alloc );
 (C++17 前)
explicit vector( const Allocator& alloc ) noexcept;
 (C++17 起)
(C++20 前)
constexpr explicit vector( const Allocator& alloc ) noexcept;
 (C++20 起)
(3)
explicit vector( size_type count,

const T& value = T(),

const Allocator& alloc = Allocator());
 (C++11 前)
vector( size_type count,

const T& value,

const Allocator& alloc = Allocator());
 (C++11 起)
(C++20 前)
constexpr vector( size_type count,

const T& value,

const Allocator& alloc = Allocator());
 (C++20 起)
(4)
explicit vector( size_type count );
 (C++11 起)
(C++14 前)
explicit vector( size_type count, const Allocator& alloc = Allocator() );
 (C++14 起)
(C++20 前)
constexpr explicit vector( size_type count,
const Allocator& alloc = Allocator() );
 (C++20 起)
(5)
template< class InputIt >

vector( InputIt first, InputIt last,

const Allocator& alloc = Allocator() );
 (C++20 前)
template< class InputIt >

constexpr vector( InputIt first, InputIt last,

const Allocator& alloc = Allocator() );
 (C++20 起)
(6)
vector( const vector& other );
 (C++20 前)
constexpr vector( const vector& other );
 (C++20 起)
(7)
vector( const vector& other, const Allocator& alloc );
 (C++11 起)
(C++20 前)
constexpr vector( const vector& other, const Allocator& alloc );
 (C++20 起)
(8)
vector( vector&& other );
 (C++11 起)
(C++17 前)
vector( vector&& other ) noexcept;
 (C++17 起)
(C++20 前)
constexpr vector( vector&& other ) noexcept;
 (C++20 起)
(9)
vector( vector&& other, const Allocator& alloc );
 (C++11 起)
(C++20 前)
constexpr vector( vector&& other, const Allocator& alloc );
 (C++20 起)
(10)
vector( std::initializer_list <T> init,
const Allocator& alloc = Allocator() );
 (C++11 起)
(C++20 前)
constexpr vector( std::initializer_list <T> init,
const Allocator& alloc = Allocator() );
 (C++20 起)

从各种数据源构造新容器，可选地使用用户提供的分配器 alloc 。

1) 默认构造函数。构造拥有默认构造的分配器的空容器。
2) 构造拥有给定分配器 alloc 的空容器。
3) 构造拥有 count 个有值 value 的元素的容器。
4) 构造拥有个 count 默认插入的 T 实例的容器。不进行复制。
5) 构造拥有范围 [first, last) 内容的容器。
若 InputIt 是整数类型，则此构造函数拥有的效果同 vector(static_cast<size_type>(first), static_cast<value_type>(last), a) 。 | (C++11 前)
此重载仅若InputIt 满足老式输入迭代器 (LegacyInputIterator) 才参与重载决议，以避免和重载 (2) 的歧义。 | (C++11 起)
6) 复制构造函数。构造拥有 other 内容的容器。

如同通过调用
std::allocator_traits <allocator_type>::select_on_container_copy_construction(
other.get_allocator())
获得分配器。

 (C++11 起)
7) 构造拥有 other 内容的容器，以 alloc 为分配器。

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
8) 移动构造函数。用移动语义构造拥有 other 内容的容器。分配器通过属于 other 的分配器移动构造获得。移动后，保证 other 为 empty() 。
9) 有分配器扩展的移动构造函数。以 alloc 为新容器的分配器，从 other 移动内容；若 alloc != other.get_allocator() ，则它导致逐元素移动。（该情况下，移动后不保证 other 为空）

在用于类模板实参推导时，仅从首个实参推导模板形参 Allocator 。

 (C++23 起)
10) 构造拥有 initializer_list init 内容的容器。

参数

alloc | - | 用于此容器所有内存分配的分配器
count | - | 容器的大小
value | - | 以之初始化容器元素的值
first, last | - | 复制元素的来源范围
other | - | 用作初始化容器元素来源的另一容器
init | - | 用作初始化元素来源的 initializer_list

复杂度

1-2) 常数
3-4) 与 count 成线性
5) 与 first 和 last 的距离成线性
6-7) 与 other 的大小成线性
8) 常数。
9) 若 alloc != other.get_allocator() 则为线性，否则为常数。
10) 与 init 的大小成线性。

异常

调用 Allocator::allocate 可能抛出。

注解

在容器移动构造（重载 (8) ）后，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

重载 (4) 对如 int 的非类类型元素清零，这与 new[] 将元素保持未初始化的行为不同。为匹配 new[] 的行为，可提供保留元素未初始化的自定义 Allocator::construct 。

示例

#include <vector>
#include <string>
#include <iostream>

template<typename T>
std::ostream& operator<<(std::ostream& s, const std::vector<T>& v)
{
    s.put('[');
    char comma[3] = {'\0', ' ', '\0'};
    for (const auto& e : v) {
        s << comma << e;
        comma[0] = ',';
    }
    return s << ']';
}

int main()
{
    // C++11 初始化器列表语法：
    std::vector<std::string> words1 {"the", "frogurt", "is", "also", "cursed"};
    std::cout << "words1: " << words1 << '\n';

    // words2 == words1
    std::vector<std::string> words2(words1.begin(), words1.end());
    std::cout << "words2: " << words2 << '\n';

    // words3 == words1
    std::vector<std::string> words3(words1);
    std::cout << "words3: " << words3 << '\n';

    // words4 为 {"Mo", "Mo", "Mo", "Mo", "Mo"}
    std::vector<std::string> words4(5, "Mo");
    std::cout << "words4: " << words4 << '\n';
}

输出：

words1: [the, frogurt, is, also, cursed]
words2: [the, frogurt, is, also, cursed]
words3: [the, frogurt, is, also, cursed]
words4: [Mo, Mo, Mo, Mo, Mo]

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2193 | C++11 | 默认构造函数为 explicit | 使之为非 explicit

参阅

assign | 将值赋给容器 (公开成员函数)
operator= | 赋值给容器 (公开成员函数)


std::vector<T,Allocator>::~vector

< cpp‎ | container‎ | vector

~vector(); | (C++20 前)
constexpr ~vector(); | (C++20 起)

销毁 vector 。调用元素的析构函数，然后解分配所用的存储。注意，若元素是指针，则不销毁所指向的对象。

复杂度

与 vector 大小成线性。


std::vector<bool>

< cpp‎ | container
定义于头文件 <vector>
template<class Allocator>
class vector<bool, Allocator>;

std::vector <bool> 是 std::vector 对类型 bool 为空间提效的特化。

std::vector <bool> 中对空间提效的行为（以及它是否有优化）是实现定义的。一种潜在优化涉及到 vector 的元素联合，使得每个元素占用一个单独的位，而非 sizeof(bool) 字节。

std::vector <bool> 表现类似 std::vector ，但为节省空间，它：

  • 不必作为连续数组存储元素
  • 暴露类 std::vector <bool>::reference 为访问单个位的方法。尤其是，此类型的类为 operator[] 以值返回。
  • 不使用 std::allocator_traits::construct 构造位值。
  • 不保证同一容器中的不同元素能由不同线程同时修改。

成员类型

成员类型 | 定义
value_type | bool
allocator_type | Allocator
size_type | 实现定义
difference_type | 实现定义
reference
 表示到单个 bool 的引用的代理类
(类)
const_reference | bool
pointer | 实现定义
const_pointer | 实现定义
iterator
实现定义 | (C++20 前)
实现定义的常量表达式迭代器 (ConstexprIterator) | (C++20 起)
const_iterator
实现定义 | (C++20 前)
实现定义的常量表达式迭代器 (ConstexprIterator) | (C++20 起)
reverse_iterator | std::reverse_iterator <iterator>
const_reverse_iterator | std::reverse_iterator <const_iterator>

成员函数

(构造函数)
 构造 vector
(std::vector<T,Allocator> 的公开成员函数)
(析构函数)
 析构 vector
(std::vector<T,Allocator> 的公开成员函数)
operator=
 赋值给容器
(std::vector<T,Allocator> 的公开成员函数)
assign
 将值赋给容器
(std::vector<T,Allocator> 的公开成员函数)
get_allocator
 返回相关的分配器
(std::vector<T,Allocator> 的公开成员函数)
元素访问
at
 访问指定的元素，同时进行越界检查
(std::vector<T,Allocator> 的公开成员函数)
operator[]
 访问指定的元素
(std::vector<T,Allocator> 的公开成员函数)
front
 访问第一个元素
(std::vector<T,Allocator> 的公开成员函数)
back
 访问最后一个元素
(std::vector<T,Allocator> 的公开成员函数)
迭代器
begin cbegin
(C++11)
 返回指向起始的迭代器
(std::vector<T,Allocator> 的公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(std::vector<T,Allocator> 的公开成员函数)
rbegincrbegin
(C++11)
 返回指向起始的逆向迭代器
(std::vector<T,Allocator> 的公开成员函数)
rendcrend
(C++11)
 返回指向末尾的逆向迭代器
(std::vector<T,Allocator> 的公开成员函数)
容器
empty
 检查容器是否为空
(std::vector<T,Allocator> 的公开成员函数)
size
 返回容纳的元素数
(std::vector<T,Allocator> 的公开成员函数)
max_size
 返回可容纳的最大元素数
(std::vector<T,Allocator> 的公开成员函数)
reserve
 预留存储空间
(std::vector<T,Allocator> 的公开成员函数)
capacity
 返回当前存储空间能够容纳的元素数
(std::vector<T,Allocator> 的公开成员函数)
修改器
clear
 清除内容
(std::vector<T,Allocator> 的公开成员函数)
insert
 插入元素
(std::vector<T,Allocator> 的公开成员函数)
emplace
(C++14 起)
 原位构造元素
(std::vector<T,Allocator> 的公开成员函数)
erase
 擦除元素
(std::vector<T,Allocator> 的公开成员函数)
push_back
 将元素添加到容器末尾
(std::vector<T,Allocator> 的公开成员函数)
emplace_back
(C++14)
 在末尾原位构造元素
(std::vector<T,Allocator> 的公开成员函数)
pop_back
 移除末元素
(std::vector<T,Allocator> 的公开成员函数)
resize
 改变容器中可存储元素的个数
(std::vector<T,Allocator> 的公开成员函数)
swap
 交换内容
(std::vector<T,Allocator> 的公开成员函数)
vector<bool> 特定修改器
flip
 翻转所有位
(公开成员函数)
swap
[静态]
 交换二个 std::vector<bool>::reference
(公开静态成员函数)

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 按照字典顺序比较 vector 中的值 (函数模板)
std::swap(std::vector) | 特化 std::swap 算法 (函数模板)
erase(std::vector)erase_if(std::vector) (C++20) | 擦除所有满足特定判别标准的元素 (函数模板)

辅助类

std::hash<std::vector<bool>>
(C++11)
 std::vector <bool> 的哈希支持
(类模板特化)

推导指引 (C++17)

注解

若位集的大小在编译时已知，可使用 std::bitset ，它提供一组更丰富的成员函数。另外， boost::dynamic_bitset 作为 std::vector<bool> 的替用者存在。

因为 std::vector <bool> 的表示可以优化，故它不需要满足所有容器 (Container) 或序列容器 (SequenceContainer) 要求。例如，因为 std::vector <bool>::iterator 是实现定义的，故它可以不满足老式向前迭代器 (LegacyForwardIterator) 要求。使用要求老式向前迭代器 (LegacyForwardIterator) 的算法，例如 std::search 可能导致编译时或运行时错误。

vector 的 Boost.Container 版本不对 bool 特化。


std::vector<bool,Allocator>::flip

< cpp‎ | container‎ | vector bool
定义于头文件 <vector> |
void flip(); | (C++20 前)
constexpr void flip(); | (C++20 起)

翻转 vector 中的每个 bool （以其相反值替换）。

参数

（无）

返回值

（无）

示例

#include <iostream>
#include <vector>

void print(const std::vector<bool>& vb) {
    for (const bool b : vb)
        std::cout << b;
    std::cout << '\n';
}

int main() {
    std::vector<bool> v{0, 1, 0, 1};
    print(v);
    v.flip();
    print(v);
}

输出：

0101
1010

参阅

operator[] | 访问指定的元素 (std::vector<T,Allocator> 的公开成员函数)
flip | 翻转位的值 (std::bitset<N> 的公开成员函数)


std::hash (std::vector<bool>)

< cpp‎ | container‎ | vector bool
template <class Allocator> struct hash<vector<bool, Allocator>>; | (C++11 起)

std::hash 对 std::vector <bool> 的模板特化允许用户获得 std::vector <bool> 类型对象的哈希。

示例

本节未完成
原因：暂无示例

参阅

hash
(C++11)
 散列函数对象
(类模板)


std::vector<bool>::reference

< cpp‎ | container‎ | vector bool
class reference;

std::vector <bool> 特化定义 std::vector <bool>::reference 为可公开访问的嵌套类。 std::vector <bool>::reference 代理访问 std::vector <bool> 中单个位的行为。

std::vector <bool>::reference 的基础使用是提供能从 operator[] 返回的左值。

任何通过 std::vector <bool>::reference 发生的对 vector 的读或写，会潜在地读或写整个底层的 vector 。

成员函数

(构造函数) | 构造引用，仅为 std::vector <bool> 自身所能访问 (公开成员函数)
(析构函数) | 销毁引用 (公开成员函数)
operator= | 赋 bool 给被引用位 (公开成员函数)
operator bool | 返回被引用位 (公开成员函数)
flip | 翻转被引用位 (公开成员函数)

std::vector<bool>::reference::~reference

~reference(); | (C++20 前)
constexpr ~reference(); | (C++20 起)

销毁 reference 。

std::vector<bool>::reference::operator=

reference& operator=( bool x );
reference& operator=( const reference& x );
 (C++11 前)
reference& operator=( bool x ) noexcept;
reference& operator=( const reference& x ) noexcept;
 (C++11 起)
(C++20 前)
constexpr reference& operator=( bool x ) noexcept;
constexpr reference& operator=( const reference& x ) noexcept;
 (C++20 起)

赋值给被引用位。

参数

x - 要赋值的值

返回值

*this

std::vector<bool>::reference::operator bool

operator bool() const; | (C++11 前)
operator bool() const noexcept; | (C++11 起) (C++20 前)
constexpr operator bool() const noexcept; | (C++20 起)

返回被引用位。

参数

（无）

返回值

被引用位。

std::vector<bool>::reference::flip

void flip(); | (C++11 前)
void flip() noexcept; | (C++11 起) (C++20 前)
constexpr void flip() noexcept; | (C++20 起)

反转被引用位。

参数

（无）

返回值

（无）

参阅

operator[] | 访问指定的元素 (std::vector<T,Allocator> 的公开成员函数)
swap [静态] | 交换二个 std::vector<bool>::reference (公开静态成员函数)


std::vector<bool,Allocator>::swap

< cpp‎ | container‎ | vector bool
定义于头文件 <vector> |
static void swap(reference x, reference y); | (C++20 前)
constexpr static void swap(reference x, reference y); | (C++20 起)

交换 x 与 y 的内容。

参数

x | - | 要与 y 交换的 std::vector <bool>::reference 值
y | - | 要与 x 交换的 std::vector <bool>::reference 值

返回值

（无）

复杂度

常数。

示例

#include <vector>
#include <iostream>

int main()
{
    std::vector<bool> vb1{ 1,0 };

    for (auto e : vb1) { std::cout << e << " "; }
    std::cout << '\n';

    vb1.swap(vb1[0], vb1[1]);

    for (auto e : vb1) { std::cout << e << " "; }
}

输出：

1 0
0 1

参阅

reference | 引用单个 bool 的代理类 (类)
swap | 交换内容 (std::vector<T,Allocator> 的公开成员函数)
std::swap(std::vector) | 特化 std::swap 算法 (函数模板)


协程支持 (C++20)

< cpp

协程支持库定义数个类型，它们提供协程的编译时与运行时支持。

协程特征

定义于头文件 <coroutine>
coroutine_traits
(C++20)
 用于发现协程承诺类型的特征类型
(类模板)

协程柄

定义于头文件 <coroutine>
coroutine_handle
(C++20)
 用于指代暂停或执行的协程
(类模板)

无操作协程

定义于头文件 <coroutine>
noop_coroutine (C++20) | 创建在等待或销毁时无可观察作用的协程柄 (函数)
noop_coroutine_promise (C++20) | 用于无可观察作用的协程 (类)
noop_coroutine_handle (C++20) | std::coroutine_handle<std::noop_coroutine_promise> ，有意用于指代无操作协程 (typedef)

平凡可等待体

定义于头文件 <coroutine>
suspend_never (C++20) | 指示 await 表达式应该决不暂停 (类)
suspend_always (C++20) | 指示 await 表达式应该始终暂停 (类)


std::coroutine_handle

< cpp‎ | coroutine
定义于头文件 <coroutine> |  |
template< class Promise = void > struct coroutine_handle; | (1) | (C++20 起)
template<> struct coroutine_handle<void>; | (2) | (C++20 起)
template<> struct coroutine_handle<std::noop_coroutine_promise>; | (3) | (C++20 起)
using noop_coroutine_handle = std::coroutine_handle<std::noop_coroutine_promise>; | (4) | (C++20 起)

类模板 coroutine_handle 能用于指代暂停或执行的协程。 coroutine_handle 的每个特化均为字面类型 (LiteralType) 。

1) 主模板，可从 Promise 类型的承诺对象创建。
2) 特化 std::coroutine_handle<void> 擦除承诺类型。它可从其他特化转换。
3) 特化 std::coroutine_handle<std::noop_coroutine_promise> 指代无操作协程。不能从承诺对象创建它。

典型实现上， std::coroutine_handle 的每个特化均为可平凡复制 (TriviallyCopyable) ，并保有一个指向协程状态的指针作为其仅有的非静态成员。

添加 coroutine_handle 的特化的程序行为未定义。

成员函数

(构造函数)
(C++20)
 构造 coroutine_handle 对象
(公开成员函数)
operator=
(C++20)
 赋值 coroutine_handle 对象
(公开成员函数)
from_promise
[静态] (C++20)
 从协程的承诺对象创建 coroutine_handle
(公开静态成员函数)
转换
operator coroutine_handle<>
(C++20)
 获得擦除类型的 coroutine_handle
(公开成员函数)
观察器
done
(C++20)
 检查协程是否已完成
(公开成员函数)
operator bool
(C++20)
 检查柄是否表示协程
(公开成员函数)
控制
operator()resume
(C++20)
 恢复协程执行
(公开成员函数)
destroy
(C++20)
 销毁协程
(公开成员函数)
承诺访问
promise
(C++20)
 访问协程的承诺对象
(公开成员函数)
导出/导入
address
(C++20)
 导出底层地址，即支撑协程的指针
(公开成员函数)
from_address
[静态] (C++20)
 从指针导入协程
(公开静态成员函数)

非成员函数

operator==operator<=>
(C++20)
 比较二个 coroutine_handle 对象
(函数)

辅助类

std::hash<std::coroutine_handle>
(C++20)
 std::coroutine_handle 的散列支持
(类模板特化)

注解

coroutine_handle 可能悬垂，该情况下必须谨慎使用该 coroutine_handle 以避免未定义行为。

示例

#include <coroutine>
#include <iostream>
#include <optional>
#include <ranges>

template<typename T> requires std::movable<T>
class Generator {
public:
    struct promise_type {
        Generator<T> get_return_object() {
            return Generator{Handle::from_promise(*this)};
        }
        static std::suspend_always initial_suspend() noexcept {
            return {};
        }
        static std::suspend_always final_suspend() noexcept {
            return {};
        }
        std::suspend_always yield_value(T value) noexcept {
            current_value = std::move(value);
            return {};
        }
        // 生成器协程中不允许 co_await 。
        void await_transform() = delete;
        static void unhandled_exception() {
            throw;
        }

        std::optional<T> current_value;
    };

    using Handle = std::coroutine_handle<promise_type>;

    explicit Generator(Handle coroutine) :
        m_coroutine{coroutine}
    {}

    Generator() = default;
    ~Generator() {
        if (m_coroutine) {
            m_coroutine.destroy();
        }
    }

    Generator(const Generator&) = delete;
    Generator& operator=(const Generator&) = delete;

    Generator(Generator&& other) noexcept :
        m_coroutine{other.m_coroutine}
    {
        other.m_coroutine = {};
    }

    Generator& operator=(Generator&& other) noexcept {
        if (this != &other) {
            m_coroutine = other.m_coroutine;
            other.m_coroutine = {};
        }
        return *this;
    }

    // 基于范围的 for 循环支持。
    class Iter {
    public:
        void operator++() {
            m_coroutine.resume();
        }
        const T& operator*() const {
            return *m_coroutine.promise().current_value;
        }
        bool operator==(std::default_sentinel_t) const {
            return !m_coroutine || m_coroutine.done();
        }

        explicit Iter(Handle coroutine) :
            m_coroutine{coroutine}
        {}

    private:
        Handle m_coroutine;
    };

    Iter begin() {
        if (m_coroutine) {
            m_coroutine.resume();
        }
        return Iter{m_coroutine};
    }
    std::default_sentinel_t end() {
        return {};
    }

private:
    Handle m_coroutine;
};

template<std::integral T>
Generator<T> range(T first, T last) {
    while (first < last) {
        co_yield first++;
    }
}

int main() {
    for (int i : range(-4, 8)) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
}

输出：

-4 -3 -2 -1 0 1 2 3 4 5 6 7

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3460 | C++20 | coroutine_handle 的公开基类能将它置于不想要的状态 | 移除继承


std::coroutine_handle<Promise>::address

< cpp‎ | coroutine‎ | coroutine handle
constexpr void* address() const noexcept; | (C++20 起)

返回 coroutine_handle 的底层地址。返回值为非空当且仅当 coroutine_handle 的当前值从协程的承诺对象获得。

参数

（无）

返回值

底层地址。

注解

返回值对特化 std::noop_coroutine_handle 始终为非空，因为不能创建 std::noop_coroutine_handle 而不使它指代无操作协程。

参阅

from_address
[静态] (C++20)
 从指针导入协程
(公开静态成员函数)


std::coroutine_handle<Promise>::coroutine_handle

< cpp‎ | coroutine‎ | coroutine handle
constexpr coroutine_handle() noexcept; | (1) | (C++20 起)
constexpr coroutine_handle( std::nullptr_t ) noexcept; | (2) | (C++20 起)
coroutine_handle( const coroutine_handle& other ) = default; | (3) | (C++20 起)
coroutine_handle( coroutine_handle&& other ) = default; | (4) | (C++20 起)

创建不指代协程的 coroutine_handle ，或复制 coroutine_handle 。

1-2) 初始化底层地址为 nullptr 。构造后， address() 返回 nullptr ，而该 coroutine_handle 不指代协程。这些构造函数不对特化 std::coroutine_handle<std::noop_coroutine_promise> 声明。
3-4) 复制底层地址。复制构造函数与移动构造函数等价于被隐式声明。

参数

other - 要复制的另一 coroutine_handle

注解

std::coroutine_handle<std::noop_coroutine_promise> 不可默认构造，亦不可从 std::nullptr_t 构造。 std::noop_coroutine 能用于创建新的 std::coroutine_handle<std::noop_coroutine_promise> 。

静态成员函数 from_promise 与 from_address 亦能创建 coroutine_handle 。

参阅

from_promise [静态] (C++20) | 从协程的承诺对象创建 coroutine_handle (公开静态成员函数)
from_address [静态] (C++20) | 从指针导入协程 (公开静态成员函数)
noop_coroutine (C++20) | 创建在等待或销毁时无可观察作用的协程柄 (函数)


std::coroutine_handle<Promise>::destroy

< cpp‎ | coroutine‎ | coroutine handle
其他特化的成员 |  |
void destroy() const; | (1) | (C++20 起)
特化 std::coroutine_handle<std::noop_coroutine_promise> 的成员 |  |
constexpr void destroy() const noexcept; | (2) | (C++20 起)
1) 销毁 *this 所指代的协程的协程状态，或若该协程为无操作协程则不做任何事。
2) 不做任何事。

若需要销毁且 *this 不指代暂停的协程，则行为未定义。

参数

（无）

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

operator()resume
(C++20)
 恢复协程执行
(公开成员函数)


std::coroutine_handle<Promise>::done

< cpp‎ | coroutine‎ | coroutine handle
其他特化的成员 |  |
bool done() const; | (1) | (C++20 起)
特化 std::coroutine_handle<std::noop_coroutine_promise> 的成员 |  |
constexpr bool done() const noexcept; | (2) | (C++20 起)

检查暂停的协程是否在其最终暂停点暂停。

1) 若 *this 所指代的协程在其最终暂停点暂停则返回 true ，若该协程在其他暂停点暂停则返回 false 。若 *this 不指代暂停的协程则行为未定义。
2) 始终返回 false 。

参数

（无）

返回值

1) 若该协程在其最终暂停点暂停则为 true ，若该协程在其他暂停点暂停则为 false 。
2) false 。

注解

无操作协程被认为始终不在其最终暂停点暂停。

示例

本节未完成
原因：暂无示例


std::coroutine_handle<Promise>::from_address

< cpp‎ | coroutine‎ | coroutine handle
static constexpr coroutine_handle from_address( void *addr ); | (C++20 起)

从空指针值或另一 coroutine_handle 的底层地址创建 coroutine_handle 。返回值的底层地址为 addr 。

若 addr 既非空指针值亦非 coroutine_handle 的底层地址，则行为未定义。若 addr 为 std::coroutine_handle<P1> 的底层地址，其中 Promise 与 P1 均非 void 且 P1 不同于 Promise ，则行为亦为未定义。

此函数不对特化 std::coroutine_handle<std::noop_coroutine_promise> 声明。

参数

addr - 要导入的底层地址

返回值

底层地址为 addr 的 std::coroutine_handle<Promise> 。

注解

若 addr 不是空指针值，则它必须从先前在指代某个协程的 coroutine_handle 上调用 address() 获得。

示例

本节未完成
原因：暂无示例

参阅

(构造函数) (C++20) | 构造 coroutine_handle 对象 (公开成员函数)
from_promise [静态] (C++20) | 从协程的承诺对象创建 coroutine_handle (公开静态成员函数)
noop_coroutine (C++20) | 创建在等待或销毁时无可观察作用的协程柄 (函数)


std::coroutine_handle<Promise>::from_promise

< cpp‎ | coroutine‎ | coroutine handle
static coroutine_handle from_promise( Promise& p ); | (C++20 起)

从协程的承诺对象创建 coroutine_handle 。创建的 coroutine_handle 指代该协程，而 promise() 返回到 p 的引用。

若 p 不是到承诺对象的引用则行为未定义。此函数仅对初等模板提供，即特化 std::coroutine_handle<> 与 std::coroutine_handle<std::noop_coroutine_promise> 无此函数。

参数

p - 要指代的协程的承诺对象

返回值

指代给定协程的 coroutine_handle 。

示例

本节未完成
原因：暂无示例

参阅

(构造函数) (C++20) | 构造 coroutine_handle 对象 (公开成员函数)
from_address [静态] (C++20) | 从指针导入协程 (公开静态成员函数)
noop_coroutine (C++20) | 创建在等待或销毁时无可观察作用的协程柄 (函数)


std::hash(std::coroutine_handle)

< cpp‎ | coroutine‎ | coroutine handle
定义于头文件 <coroutine> |
template< class Promise > struct hash<std::coroutine_handle<Promise>>; | (C++20 起)

std::hash 对 std::coroutine_handle 的模板特化允许用户获得 std::coroutine_handle<P> 对象的散列值。

特化的 operator() 为 noexcept 。

示例

本节未完成
原因：暂无示例

参阅

hash
(C++11)
 散列函数对象
(类模板)


std::coroutine_handle<Promise>::operator=

< cpp‎ | coroutine‎ | coroutine handle
coroutine_handle& operator=( std::nullptr_t ) noexcept; | (1) | (C++20 起)
coroutine_handle& operator=( const coroutine_handle& other ) = default; | (2) | (C++20 起)
coroutine_handle& operator=( coroutine_handle&& other ) = default; | (3) | (C++20 起)

替换底层地址。

1) 替换底层地址为空指针值。赋值后， *this 不指代协程。此赋值运算符不对特化 std::coroutine_handle<std::noop_coroutine_promise> 声明。
2-3) 替换底层地址为 other 的底层地址。复制与移动赋值运算符等价于隐式声明者。

参数

other - 作为赋值来源的另一 coroutine_handle

返回值

*this 。


std::coroutine_handle<Promise>::operator bool

< cpp‎ | coroutine‎ | coroutine handle
explicit constexpr operator bool() const noexcept; | (C++20 起)

检查 *this 是否为非空，即 *this 的值从某协程的承诺对象获得。等价于 return bool(address()); 。

若 Promise 为 std::noop_coroutine_promise ，则此转换函数始终返回 true 。

参数

（无）

返回值

bool(address()) ，或若 Promise 为 std::noop_coroutine_promise 则为 true 。

参阅

address
(C++20)
 导出底层地址，即支撑协程的指针
(公开成员函数)


std::operator==, operator<=>(std::coroutine_handle)

< cpp‎ | coroutine‎ | coroutine handle
定义于头文件 <coroutine>
constexpr bool
operator==(std::coroutine_handle<> x, std::coroutine_handle<> y) noexcept;
 (1) (C++20 起)
constexpr std::strong_ordering
operator<=>(std::coroutine_handle<> x, std::coroutine_handle<> y) noexcept;
 (2) (C++20 起)

按照底层地址比较二个 std::coroutine_handle<> 值 x 与 y 。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

参数

x, y - 要比较的 std::coroutine_handle<> 值

返回值

1) x.address() == y.address() 。
2) std::compare_three_way{}(x.address(), y.address()) 。

注解

尽管这些运算符仅对 std::coroutine_handle<> 重载， std::coroutine_handle 的其他特化亦可进行相等比较及三路比较，因为它们可隐式转换成 std::coroutine_handle<> 。

示例

本节未完成
原因：暂无示例


std::coroutine_handle<Promise>::operator coroutine_handle<>

< cpp‎ | coroutine‎ | coroutine handle
constexpr operator coroutine_handle<>() const noexcept; | (C++20 起)

此转换函数将 std::coroutine_handle<Promise> 值转换成保有相同底层地址的 std::coroutine_handle<> 。它等效地擦除承诺类型。

参数

（无）

返回值

std::coroutine_handle<>::from_address(address()) 。

参阅

operator==operator<=>
(C++20)
 比较二个 coroutine_handle 对象
(函数)


std::coroutine_handle<Promise>::promise

< cpp‎ | coroutine‎ | coroutine handle
主模板的成员 |
Promise& promise() const; | (C++20 起)
特化 std::coroutine_handle<std::noop_coroutine_promise> 的成员 |
std::noop_coroutine_promise& promise() const noexcept; | (C++20 起)

获得到承诺对象的引用。

若 *this 不指代承诺对象尚未被销毁的协程，则行为未定义。

此函数不对特化 std::coroutine_handle<> 提供。

参数

（无）

返回值

到承诺对象的引用。

注解

只要有某个 std::noop_coroutine_handle 指代无操作协程，该协程的承诺对象就不会被销毁。

参阅

from_promise
[静态] (C++20)
 从协程的承诺对象创建 coroutine_handle
(公开静态成员函数)


std::coroutine_handle<Promise>::operator(), std::coroutine_handle<Promise>::resume

< cpp‎ | coroutine‎ | coroutine handle
其他特化的成员
void operator()() const;
void resume() const;
 (1) (C++20 起)
特化 std::coroutine_handle<std::noop_coroutine_promise> 的成员
constexpr void operator()() const noexcept;
constexpr void resume() const noexcept;
 (2) (C++20 起)
1) 恢复 *this 所指代的协程的执行，或若该协程为无操作协程则不做任何事。
2) 不做任何事。

若 *this 不指代暂停的协程，或该协程不是无操作协程且在最终暂停点暂停，则行为未定义。同时恢复协程可能导致数据竞争。

在不同于协程暂停所在的执行代理上恢复协程拥有实现定义行为，除非每个执行代理都是由 std::thread 或 std::jthread 表示的线程，或执行 main 的线程。

参数

（无）

返回值

（无）

注解

在不同执行代理上恢复的协程应该处处避免依赖一致的线程同一性，例如跨过暂停点保有互斥体对象。

示例

本节未完成
原因：暂无示例

参阅

destroy
(C++20)
 销毁协程
(公开成员函数)


std::coroutine_traits

< cpp‎ | coroutine
定义于头文件 <coroutine> |
template< class R, class... Args > struct coroutine_traits; | (C++20 起)

从协程的返回类型与形参类型确定承诺类型。标准库实现提供与 R::promise_type 相同的公开可访问成员类型 promise_type ，若该有限定标识合法并代表类型。否则它无成员。

coroutine_traits 的程序定义特化应当定义公开可访问的成员类型 promise_type ，否则行为未定义。

模板形参

R | - | 协程的返回类型
Args | - | 协程的形参类型，若协程为非静态成员函数则包括隐式对象形参

成员类型

类型 | 定义
promise_type | R::promise_type ，若它合法，或由程序定义特化提供

可能的实现

template<class, class...>
struct coroutine_traits {};

template<class R, class... Args>
    requires requires { typename R::promise_type }
struct coroutine_traits<R, Args...> {
    using promise_type = R::promise_type;
};

注解

若协程为非静态成员函数，则 Args... 中的首个类型为隐式对象形参的类型，而剩下的是函数的形参类型（若存在）。

若 std::coroutind_traits<R, Args...>::promise_type 不存在或不是类类型，则对应的协程定义为谬构。

用户可定义取决于程序定义类型的 coroutine_traits 显式或偏特化，以避免修改返回类型。

示例

本节未完成
原因：暂无示例


std::noop_coroutine

< cpp‎ | coroutine
定义于头文件 <coroutine> |
std::noop_coroutine_handle noop_coroutine() noexcept; | (C++20 起)

返回指代无操作协程的协程柄。

若已有无操作协程的协程状态，则不指定 noop_coroutine 的后续调用是返回先前获得的协程柄，还是指代新的无操作协程的协程状态的协程柄。

参数

（无）

返回值

指代无操作协程的 std::noop_coroutine_handle 。

注解

不同的 noop_coroutine 调用的返回值可能也可能不比较相等。

noop_coroutine 可以仅返回指代协程状态对象的 noop_coroutine_handle 而无需开始协程。

示例

#include <coroutine>
#include <utility>
#include <iostream>

template<class T>
struct task {
    struct promise_type {
        auto get_return_object() {
            return task(std::coroutine_handle<promise_type>::from_promise(*this));
        }
        std::suspend_always initial_suspend() { return {}; }
        struct final_awaiter {
            bool await_ready() { return false; }
            void await_resume() {}
            std::coroutine_handle<> await_suspend(std::coroutine_handle<promise_type> h) {
                // 在当前协程（以 'h' 指代）执行即将结束时调用 final_awaiter::await_suspend 。
                // 若当前协程被另一协程经由 co_await get_task() 恢复，则存储到该协程的柄
                // 为 h.promise().previous 。该情况下，返回柄以恢复先前的协程。
                // 否则返回 noop_coroutine() ，其恢复不做任何事。

                auto previous = h.promise().previous;
                if (previous) {
                    return previous;
                } else {
                    return std::noop_coroutine();
                }
            }
        };
        final_awaiter final_suspend() noexcept { return {}; }
        void unhandled_exception() { throw; }
        void return_value(T value) { result = std::move(value); }
        T result;
        std::coroutine_handle<> previous;
    };

    task(std::coroutine_handle<promise_type> h) : coro(h) {}
    task(task&& t) = delete;
    ~task() { coro.destroy(); }

    struct awaiter {
        bool await_ready() { return false; }
        T await_resume() { return std::move(coro.promise().result); }
        auto await_suspend(std::coroutine_handle<> h) {
            coro.promise().previous = h;
            return coro;
        }
        std::coroutine_handle<promise_type> coro;
    };
    awaiter operator co_await() { return awaiter{coro}; }
    T operator()() {
        coro.resume();
        return std::move(coro.promise().result);
    }
private:
    std::coroutine_handle<promise_type> coro;
};

task<int> get_random() {
    std::cout << "in get_random()\n";
    co_return 4;
}
task<int> test() {
    task<int> v = get_random();
    task<int> u = get_random();
    std::cout << "in test()\n";
    int x = (co_await v + co_await u);
    co_return x;
}

int main() {
    task<int> t = test();
    int result = t();
    std::cout << result << '\n';
}

输出：

in test()
in get_random()
in get_random()
8

参阅

noop_coroutine_promise (C++20) | 用于无可观察作用的协程 (类)
noop_coroutine_handle (C++20) | std::coroutine_handle<std::noop_coroutine_promise> ，有意用于指代无操作协程 (typedef)


std::noop_coroutine_promise

< cpp‎ | coroutine
定义于头文件 <coroutine> |
struct noop_coroutine_promise {}; | (C++20 起)

noop_coroutine_promise 是无操作协程的承诺类型。

无操作协程表现如同它

  • 在协程控制流外不做任何事，且
  • 在开始和恢复后立即暂停，且
  • 拥有一种协程状态，而销毁该状态为无操作，且
  • 若有任何指代它的 std::coroutine_handle 则绝不抵达其最终暂停点。
本节未完成
原因：更精确的用语

无操作协程能由 std::noop_coroutine 开始，并由其所返回的协程柄控制。返回的协程柄类型为 std::noop_coroutine_handle ，这是 std::coroutine_handle<std::noop_coroutine_promise> 的同义词。

无操作协程的某些操作通过 std::noop_coroutine_handle 类型在编译期确定为无操作。

本节未完成
原因：无操作协程的用法

注解

不要求定义无操作协程。例如 gcc 实现仅提供一个无操作协程的协程状态对象，而其 noop_coroutine 函数返回含有指向它的指针的 noop_coroutine_handle 而无需开始协程。

示例

本节未完成
原因：暂无示例

参阅

noop_coroutine (C++20) | 创建在等待或销毁时无可观察作用的协程柄 (函数)
noop_coroutine_handle (C++20) | std::coroutine_handle<std::noop_coroutine_promise> ，有意用于指代无操作协程 (typedef)


std::suspend_always

< cpp‎ | coroutine
定义于头文件 <coroutine> |
struct suspend_always; | (C++20 起)

suspend_always 是空类，能用于指示 await 表达式始终暂停并且不产生值。

成员函数

await_ready (C++20) | 指示 await 表达式始终暂停 (公开成员函数)
await_suspend (C++20) | 无操作 (公开成员函数)
await_resume (C++20) | 无操作 (公开成员函数)

std::suspend_always::await_ready

constexpr bool await_ready() const noexcept { return false; } | (C++20 起)

始终返回 false ，指示 await 表达式始终暂停。

std::suspend_always::await_suspend

constexpr void await_suspend() const noexcept {} | (C++20 起)

不做任何事。

std::suspend_always::await_resume

constexpr void await_resume() const noexcept {} | (C++20 起)

不做任何事。若使用 suspend_always 则 await 表达式不产生值。

示例

本节未完成
原因：暂无示例

参阅

suspend_never
(C++20)
 指示 await 表达式应该决不暂停
(类)


std::suspend_never

< cpp‎ | coroutine
定义于头文件 <coroutine> |
struct suspend_never; | (C++20 起)

suspend_never 是空类，能用于指示 await 表达式绝不暂停并且不产生值。

成员函数

await_ready (C++20) | 指示 await 表达式绝不暂停 (公开成员函数)
await_suspend (C++20) | 无操作 (公开成员函数)
await_resume (C++20) | 无操作 (公开成员函数)

std::suspend_never::await_ready

constexpr bool await_ready() const noexcept { return true; } | (C++20 起)

始终返回 true ，指示 await 表达式绝不暂停。

std::suspend_never::await_suspend

constexpr void await_suspend() const noexcept {} | (C++20 起)

不做任何事。

std::suspend_never::await_resume

constexpr void await_resume() const noexcept {} | (C++20 起)

不做任何事。若使用 suspend_never 则 await 表达式不产生值。

示例

本节未完成
原因：暂无示例

参阅

suspend_always
(C++20)
 指示 await 表达式应该始终暂停
(类)


错误处理

< cpp

异常处理

头文件 <exception> 提供数个关联于 C++ 程序中异常处理的类与函数。

定义于头文件 <exception>
exception
 标准库组件抛出的各种异常的基类
(类)
异常对象的捕获与存储
uncaught_exceptionuncaught_exceptions
(C++20 中移除)(C++17)
 检查当前是否正在进行异常处理
(函数)
exception_ptr
(C++11)
 用于处理异常对象的共享指针类型
(typedef)
make_exception_ptr
(C++11)
 从异常对象创建一个std::exception_ptr
(函数模板)
current_exception
(C++11)
 捕获当前异常到 std::exception_ptr 之中
(函数)
rethrow_exception
(C++11)
 从一个 std::exception_ptr 抛出异常
(函数)
nested_exception
(C++11)
 用于捕获并存储当前异常的混入类型
(类)
throw_with_nested
(C++11)
 抛出实参，带上混入的 std::nested_exception
(函数模板)
rethrow_if_nested
(C++11)
 抛出 std::nested_exception 中的异常
(函数模板)
异常处理中的失败处理
定义于头文件 <exception>
terminate
 异常处理失败时调用的函数
(函数)
terminate_handler
 std::terminate 所调用的函数类型
(typedef)
get_terminate
(C++11)
 获得当前的 terminate_handler
(函数)
set_terminate
 更改将被 std::terminate 调用的函数
(函数)
bad_exception
 当 std::current_exception 无法复制异常对象时抛出的异常
(类)
异常规定违规处理（ C++17 中移除）
unexpected
(C++17 中移除)
 违背动态异常说明时调用的函数
(函数)
unexpected_handler
(C++17 中移除)
 std::unexpected 所调用的函数类型
(typedef)
get_unexpected
(C++11)(C++17 中移除)
 获得当前的 unexpected_handler
(函数)
set_unexpected
(C++17 中移除)
 更改要被 std::unexpected 调用的函数
(函数)

异常类别

数个便利异常类预定义于头文件 <stdexcept> 以报告特定的错误条件。这些类可分为二个类别：逻辑错误与运行时错误。逻辑错误是程序中错误逻辑的后果，而且可以避免。运行时错误来源于程序作用域以外的事件，且无法简单预测。

定义于头文件 <stdexcept>
logic_error | 指示违背逻辑前提条件或类不变量的异常类 (类)
invalid_argument | 报告非法参数的异常类 (类)
domain_error | 报告定义域错误的异常类 (类)
length_error | 报告试图超出最大允许大小的异常类 (类)
out_of_range | 报告参数落在期待范围外的异常类 (类)
runtime_error | 指示条件只可于运行时检测的异常类 (类)
range_error | 报告内部计算中值域错误的异常类 (类)
overflow_error | 报告算术上溢的异常类 (类)
underflow_error | 报告算术下溢的异常类 (类)
tx_exception (TM TS) | 取消原子事务的异常类 (类模板)

错误号

定义于头文件 <cerrno>
errno | 展开成 POSIX 兼容的线程局域错误号变量的宏 (宏变量)
E2BIG, EACCES, ..., EXDEV | 兼容标准 POSIX 的错误条件的宏 (宏常量)

断言

帮助实现程序中前置条件检查的断言。

定义于头文件 <cassert>
assert
 若用户指定的条件非 true 则中断程序。可以在发行构建中禁用
(宏函数)

系统错误

头文件 <system_error> 定义用于报告源于操作系统、流 I/O 、 std::future 或其他低层 API 的错误条件的类型和函数。

定义于头文件 <system_error>
error_category (C++11) | 错误类别的基类 (类)
generic_category (C++11) | 鉴别通用错误类别 (函数)
system_category (C++11) | 鉴别操作系统错误类别 (函数)
error_condition (C++11) | 保有可移植的错误码 (类)
errc (C++11) | 列出所有标准 <cerrno> 宏常量的 std::error_condition 枚举 (类)
error_code (C++11) | 保有依赖于平台的错误码 (类)
system_error (C++11) | 用于报告拥有 error_code 的错误条件的异常类 (类)

参阅

static_assert 声明 (C++11) 进行编译时断言检查


assert

< cpp‎ | error
定义于头文件 <cassert>
#ifdef NDEBUG

#define assert(condition) ((void)0)
#else
#define assert(condition) /*implementation defined*/

#endif

宏 assert 的定义依赖于标准库中没有定义的另一个名为 NDEBUG 宏。

若在包含了 <cassert> 或 <assert.h> 的源代码中定义名为 NDEBUG 的宏，则 assert 不做任何事。

若没有定义名为 NDEBUG 的宏，则 assert 将其参数（必须拥有标量类型）与零比较相等。若相等，则 assert 在标准错误输出上输出实现指定的诊断信息，并调用 std::abort 。诊断信息要求包含 expression 的文本，还有预定义变量 __func__ 与 (C++11 起) 预定义宏 __FILE__、 __LINE__ 的值。

表达式 assert(E) 保证为常量子表达式，若下列之一成立

  • 在最后定义或重定义（即包含了头文件 <cassert> 或 <assert.h> ） assert 位置定义了 NDEBUG；或
  • E 按语境转换成 bool 后，是求值为 true 的常量子表达式。
 (C++17 起)

参数

condition - 标量类型的表达式

返回值

（无）

注解

因为 assert 是仿函数宏，在 condition 中未被括号保护的逗号都被转译成宏参数的分隔符。这种逗号常能在模板参数列表和列表初始化中找到：

assert(std::is_same_v<int, int>); // 错误： assert 不接收二个参数
assert((std::is_same_v<int, int>)); // OK ：一个参数
static_assert(std::is_same_v<int, int>); // OK ：非宏
std::complex<double> c;
assert(c == std::complex<double>{0, 0}); // 错误
assert((c == std::complex<double>{0, 0})); // OK

没有标准化的添加消息到 assert 错误的接口。一个包含它的方式是使用逗号运算符，只要它未被重载：

assert(("There are five lights", 2 + 2 == 5));

assert 在 Microsoft CRT 中的实现不遵从 C++11 以及后续标准版本，因为其底层函数 ( _wassert ）不接收 __func__ 或等价的替代品。

示例

#include <iostream>
// 去注释化则禁用 assert()
// #define NDEBUG
#include <cassert>

int main()
{
    assert(2+2==4);
    std::cout << "Execution continues past the first assert\n";
    assert(2+2==5);
    std::cout << "Execution continues past the second assert\n";
}

可能的输出：

Execution continues past the first assert
test: test.cc:10: int main(): Assertion `2+2==5' failed.
Aborted

参阅

static_assert 声明 (C++11) | 进行编译时断言检查
abort | 导致非正常的程序终止（不进行清理） (函数)


std::bad_exception

< cpp‎ | error
定义于头文件 <exception>
class bad_exception;

std::bad_exception 是 C++ 运行时在下列情况抛出的异常类型：

  • 若 std::exception_ptr 存储被捕捉异常的副本，且被 std::current_exception 捕捉的异常对象的复制构造函数抛出异常，则被捕捉的异常是 std::bad_exception 的一个实例。
 (C++11 起)
  • 若动态异常规定被违背且 std::unexpected 抛出或重抛仍然违背异常规定的异常，但异常规定允许 std::bad_exception ，则抛出 std::bad_exception 。
 (C++17 前)
cpp/error/exception

继承图

成员函数

(构造函数) | 构造 bad_exception 对象 (公开成员函数)
operator= | 复制该对象 (公开成员函数)
what [虚] | 返回解释性字符串 (虚公开成员函数)

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

示例

#include <iostream>
#include <exception>
#include <stdexcept>

void my_unexp() { throw; }

void test() throw(std::bad_exception)
{
    throw std::runtime_error("test");
}

int main()
{
    std::set_unexpected(my_unexp);
    try {
         test();
    } catch(const std::bad_exception& e)
    {
        std::cerr << "Caught " << e.what() << '\n';
    }
}

可能的输出：

Caught std::bad_exception


std::bad_exception::bad_exception

< cpp‎ | error‎ | bad exception
 | (1)
bad_exception() throw(); |  | (C++11 前)
bad_exception() noexcept; |  | (C++11 起)
 | (2)
bad_exception( const bad_exception& other ) throw(); |  | (C++11 前)
bad_exception( const bad_exception& other ) noexcept; |  | (C++11 起)

构造新的 bad_exception 对象。

1) 默认构造函数。 what() 返回实现定义的字符串。
2) 复制构造函数。以 other 的内容初始化对象。若 *this 与 other 均拥有动态类型 std::bad_exception ，则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 要以之初始化的 bad_exception 对象


std::bad_exception::operator=

< cpp‎ | error‎ | bad exception
bad_exception& operator=( const bad_exception& other ) throw(); | (C++11 前)
bad_exception& operator=( const bad_exception& other ) noexcept; | (C++11 起)

用 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::bad_exception ，则赋值后 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 要赋值的另一 bad_exception 对象

返回值

*this.


std::bad_exception::what

< cpp‎ | error‎ | bad exception
virtual const char* what() const noexcept;

返回解释性字符串。

参数

（无）

返回值

指向拥有解释信息的空终止字符串的指针。


std::current_exception

< cpp‎ | error
定义于头文件 <exception> |
std::exception_ptr current_exception() noexcept; | (C++11 起)

若在当前异常处理（典型地在 catch 子句中）中调用，则捕获当前异常对象，并创建一个保有该异常对象复制或到该异常对象引用的 std::exception_ptr （依赖于实现）。被引用对象保持合法，只要至少要有一个 exception_ptr 对象引用它。

若此函数的实现要求对 new 的调用且调用失败，则返回地指针将保有到一个 std::bad_alloc 实例的引用。

若此函数的实现要求复制被捕获异常对象，且其复制构造函数抛出异常，则返回的指针将保有到被抛出异常的引用。若该被抛出遗产对象的复制构造函数亦抛出，则返回的指针可能保有到 std::bad_exception 实例的引用，以打断无尽循环。

若函数在无被处理异常时调用，则返回空的 std::exception_ptr 。

参数

（无）

返回值

保有到异常对象引用，或异常对象副本，或指向 std::bad_alloc 实例，或指向 std::bad_exception 实例的 std::exception_ptr 的实例。

示例

#include <iostream>
#include <string>
#include <exception>
#include <stdexcept>

void handle_eptr(std::exception_ptr eptr) // 按值传递 ok
{
    try {
        if (eptr) {
            std::rethrow_exception(eptr);
        }
    } catch(const std::exception& e) {
        std::cout << "Caught exception \"" << e.what() << "\"\n";
    }
}

int main()
{
    std::exception_ptr eptr;
    try {
        std::string().at(1); // 这生成一个 std::out_of_range
    } catch(...) {
        eptr = std::current_exception(); // 捕获
    }
    handle_eptr(eptr);
} // std::out_of_range 的析构函数调用于此，在 ept 析构时

输出：

Caught exception "basic_string::at"

参阅

exception_ptr (C++11) | 用于处理异常对象的共享指针类型 (typedef)
rethrow_exception (C++11) | 从一个 std::exception_ptr 抛出异常 (函数)
make_exception_ptr (C++11) | 从异常对象创建一个std::exception_ptr (函数模板)
uncaught_exceptionuncaught_exceptions (C++20 中移除)(C++17) | 检查当前是否正在进行异常处理 (函数)


std::domain_error

< cpp‎ | error
定义于头文件 <stdexcept>
class domain_error;

定义作为异常抛出的对象类型。实现可用它报告定义域错误，即输入在操作有定义的定义域外的情形。

标准库组件不抛此异常（数学函数报告以指定于 math_errhandling 的方式定义域错误）。然而，第三方库使用它。例如，若启用 boost::math::policies::throw_on_error （默认设置）则 boost.math 抛出 std::domain_error 。

cpp/error/exception cpp/error/logic error

继承图

成员函数

(构造函数) | 构造拥有给定消息的新 domain_error 对象 (公开成员函数)
operator= | 替换 domain_error 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::domain_error::domain_error

domain_error( const std::string & what_arg ); | (1) |
domain_error( const char* what_arg ); | (2) | (C++11 起)
 | (3) |
domain_error( const domain_error& other ); |  |  | (C++11 前)
domain_error( const domain_error& other ) noexcept; |  |  | (C++11 起)
1-2) 构造以 what_arg 为解释字符串的异常对象，解释字符串能通过 what() 访问。
3) 复制构造函数。若 *this 与 other 均拥有动态类型 std::domain_error 则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

what_arg | - | 解释字符串
other | - | 要复制的另一异常对象

异常

1-2) 可能抛出 std::bad_alloc

注解

因为不容许复制 std::domain_error 抛出异常，通常将此消息在内部存储为分离分配的引用计数字符串。这也是构造函数不接收 std::string&& 参数的理由：无论如何它必须复制内容。

std::domain_error::operator=

domain_error& operator=( const domain_error& other ); | (C++11 前)
domain_error& operator=( const domain_error& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::domain_error 则赋值后 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 用以赋值的另一异常对象

返回值

*this

std::domain_error::what

virtual const char* what() const throw(); | (C++11 前)
virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::logic_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)


std::errc

< cpp‎ | error
定义于头文件 <system_error> |
enum class errc; | (C++11 起)

有作用域枚举 std::errc 定义对应 POSIX 错误码的可移植错误条件。

成员常量

常量 | 等价的 POSIX 错误
address_family_not_supported | EAFNOSUPPORT
address_in_use | EADDRINUSE
address_not_available | EADDRNOTAVAIL
already_connected | EISCONN
argument_list_too_long | E2BIG
argument_out_of_domain | EDOM
bad_address | EFAULT
bad_file_descriptor | EBADF
bad_message | EBADMSG
broken_pipe | EPIPE
connection_aborted | ECONNABORTED
connection_already_in_progress | EALREADY
connection_refused | ECONNREFUSED
connection_reset | ECONNRESET
cross_device_link | EXDEV
destination_address_required | EDESTADDRREQ
device_or_resource_busy | EBUSY
directory_not_empty | ENOTEMPTY
executable_format_error | ENOEXEC
file_exists | EEXIST
file_too_large | EFBIG
filename_too_long | ENAMETOOLONG
function_not_supported | ENOSYS
host_unreachable | EHOSTUNREACH
identifier_removed | EIDRM
illegal_byte_sequence | EILSEQ
inappropriate_io_control_operation | ENOTTY
interrupted | EINTR
invalid_argument | EINVAL
invalid_seek | ESPIPE
io_error | EIO
is_a_directory | EISDIR
message_size | EMSGSIZE
network_down | ENETDOWN
network_reset | ENETRESET
network_unreachable | ENETUNREACH
no_buffer_space | ENOBUFS
no_child_process | ECHILD
no_link | ENOLINK
no_lock_available | ENOLCK
no_message_available | ENODATA
no_message | ENOMSG
no_protocol_option | ENOPROTOOPT
no_space_on_device | ENOSPC
no_stream_resources | ENOSR
no_such_device_or_address | ENXIO
no_such_device | ENODEV
no_such_file_or_directory | ENOENT
no_such_process | ESRCH
not_a_directory | ENOTDIR
not_a_socket | ENOTSOCK
not_a_stream | ENOSTR
not_connected | ENOTCONN
not_enough_memory | ENOMEM
not_supported | ENOTSUP
operation_canceled | ECANCELED
operation_in_progress | EINPROGRESS
operation_not_permitted | EPERM
operation_not_supported | EOPNOTSUPP
operation_would_block | EWOULDBLOCK
owner_dead | EOWNERDEAD
permission_denied | EACCES
protocol_error | EPROTO
protocol_not_supported | EPROTONOSUPPORT
read_only_file_system | EROFS
resource_deadlock_would_occur | EDEADLK
resource_unavailable_try_again | EAGAIN
result_out_of_range | ERANGE
state_not_recoverable | ENOTRECOVERABLE
stream_timeout | ETIME
text_file_busy | ETXTBSY
timed_out | ETIMEDOUT
too_many_files_open_in_system | ENFILE
too_many_files_open | EMFILE
too_many_links | EMLINK
too_many_symbolic_link_levels | ELOOP
value_too_large | EOVERFLOW
wrong_protocol_type | EPROTOTYPE

非成员函数

make_error_code(std::errc) (C++11) | 构造 std::errc 错误码 (函数)
make_error_condition(std::errc) (C++11) | 构造 std::errc 错误条件 (函数)

帮助类

is_error_condition_enum<std::errc>
(C++11)
 扩充 std::is_error_condition_enum 类型特性以鉴别 std::errc 值为 error_condition
(函数模板)

示例

#include <iostream>
#include <system_error>
#include <thread>
int main()
{
    try {
        std::thread().detach(); // 脱附一个非线程
    } catch (const std::system_error& e) {
        std::cout << "Caught a system_error\n";
        if(e.code() == std::errc::invalid_argument)
            std::cout << "The error condition is std::errc::invalid_argument\n";
        std::cout << "the error description is " << e.what() << '\n';
    }
}

输出：

Caught a system_error
The error condition is std::errc::invalid_argument
the error description is Invalid argument

参阅

error_code (C++11) | 保有依赖于平台的错误码 (类)
error_condition (C++11) | 保有可移植的错误码 (类)


std::is_error_condition_enum<std::errc>

< cpp‎ | error‎ | errc
定义于头文件 <system_error> |
template<> struct is_error_condition_enum< std::errc > : std::true_type ; | (C++11 起)

指定 std::errc 为一个错误条件枚举。这允许到 std::error_condition 的隐式转换。

继承自 std::integral_constant

成员常量

value
[静态]
 true
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

参阅

is_error_condition_enum
(C++11)
 鉴别枚举是否可作为 std::error_condition
(类模板)


std::make_error_code(std::errc)

< cpp‎ | error‎ | errc
定义于头文件 <system_error> |
std::error_code make_error_code( std::errc e ) noexcept; | (C++11 起)

为 errc 枚举 e 创建 error_code 值。

等价于 std::error_code (static_cast<int>(e), std::generic_category ())

参数

e - 要为之创建 error_code 的错误码枚举

返回值

对应 e 的错误码。


std::make_error_condition(std::errc)

< cpp‎ | error‎ | errc
定义于头文件 <system_error> |
std::error_condition make_error_condition( std::errc e ) noexcept; | (C++11 起)

为 errc 值 e 创建一个 error_condition 。设置错误码为 int(e) ，错误类别为 std::generic_category 。

参数

e - 标准错误码

返回值

e 的错误条件。

示例

#include <system_error>
#include <string>
#include <iostream>

int main()
{
    auto err = std::make_error_condition(std::errc::invalid_argument);
    std::cout << err.message() << '\n';
}

可能的输出：

Invalid argument


errno

< cpp‎ | error
定义于头文件 <cerrno>
#define errno /*implementation-defined*/

errno 是用于错误指示的预处理器宏。它展开成一个静态 (C++11 前)线程局域 (C++11 起)的 int 类型可修改左值。

数个标准库函数通过写入正整数到 errno 指示错误。 errno 的值被典型地设置为作为列于 <cerrno> 的，以字母 E 起始，后随大写字母或数字的宏常量。

程序启动时 errno 的值为 ​0​ ，而且尽管不管在错误发生与否时，允许写入正整数到 errno ，库函数决不会存储 ​0​ 于 errno 。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <clocale>

int main()
{
    double not_a_number = std::log(-1.0);
    if (errno == EDOM) {
        std::cout << "log(-1) failed: " << std::strerror(errno) << '\n';
        std::setlocale(LC_MESSAGES, "de_DE.utf8");
        std::cout << "Or, in German, " << std::strerror(errno) << '\n';
    }
}

可能的输出：

log(-1) failed: Numerical argument out of domain
Or, in German, Das numerische Argument ist ausserhalb des Definitionsbereiches

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 310 | C++98 | 未指明 errno 是宏还是有外部链接的标识符 | errno 必须是宏

参阅

E2BIG, EACCES, ..., EXDEV | 兼容标准 POSIX 的错误条件的宏 (宏常量)
perror | 显示对应当前错误的字符串于 stderr (函数)
strerror | 返回给定错误码的文本版本 (函数)


错误号

< cpp‎ | error

每个定义于 <cerrno> 的宏展开成 int 类型的整数常量表达式，每个都拥有正值，匹配 POSIX 错误码中的大多数。下列常量得到定义（实现可以定义更多，只要它们以 'E' 开始，后随数字或大写字母）

定义于头文件 <cerrno>
E2BIG (C++11) | 参数列表过长 (宏常量)
EACCES (C++11) | 权限被禁止 (宏常量)
EADDRINUSE (C++11) | 地址在使用中 (宏常量)
EADDRNOTAVAIL (C++11) | 地址不可用 (宏常量)
EAFNOSUPPORT (C++11) | 不支持地址系列 (宏常量)
EAGAIN (C++11) | 资源不可用，须重试 (宏常量)
EALREADY (C++11) | 连接已在进行 (宏常量)
EBADF (C++11) | 坏的的文件描述符 (宏常量)
EBADMSG (C++11) | 坏的消息 (宏常量)
EBUSY (C++11) | 设备或资源忙 (宏常量)
ECANCELED (C++11) | 操作取消 (宏常量)
ECHILD (C++11) | 无子进程 (宏常量)
ECONNABORTED (C++11) | 连接被打断 (宏常量)
ECONNREFUSED (C++11) | 连接被拒绝 (宏常量)
ECONNRESET (C++11) | 连接被重置 (宏常量)
EDEADLK (C++11) | 资源死锁会发生 (宏常量)
EDESTADDRREQ (C++11) | 要求目标地址 (宏常量)
EDOM | 数学参数在函数定义域外 (宏常量)
EEXIST (C++11) | 文件已存在 (宏常量)
EFAULT (C++11) | 坏的地址 (宏常量)
EFBIG (C++11) | 文件过大 (宏常量)
EHOSTUNREACH (C++11) | 主机不可抵达 (宏常量)
EIDRM (C++11) | 标识符被移除 (宏常量)
EILSEQ (C++11) | 非法字节序列 (宏常量)
EINPROGRESS (C++11) | 操作已在进行 (宏常量)
EINTR (C++11) | 函数被中断 (宏常量)
EINVAL (C++11) | 非法参数 (宏常量)
EIO (C++11) | I/O 错误 (宏常量)
EISCONN (C++11) | 接头已连接 (宏常量)
EISDIR (C++11) | 是目录 (宏常量)
ELOOP (C++11) | 符号链接级别过多 (宏常量)
EMFILE (C++11) | 文件描述符值过大 (宏常量)
EMLINK (C++11) | 链接过多 (宏常量)
EMSGSIZE (C++11) | 消息过大 (宏常量)
ENAMETOOLONG (C++11) | 文件名过长 (宏常量)
ENETDOWN (C++11) | 网络不工作 (宏常量)
ENETRESET (C++11) | 连接被网络打断 (宏常量)
ENETUNREACH (C++11) | 网络不可抵达 (宏常量)
ENFILE (C++11) | 系统中打开文件过多 (宏常量)
ENOBUFS (C++11) | 无缓冲空间可用 (宏常量)
ENODATA (C++11) | 流头已读取队列中无消息 (宏常量)
ENODEV (C++11) | 无此设备 (宏常量)
ENOENT (C++11) | 无此文件或目录 (宏常量)
ENOEXEC (C++11) | 可执行文件格式错误 (宏常量)
ENOLCK (C++11) | 无可用锁 (宏常量)
ENOLINK (C++11) | 链接已切断 (宏常量)
ENOMEM (C++11) | 空间不足 (宏常量)
ENOMSG (C++11) | 无所需类型消息 (宏常量)
ENOPROTOOPT (C++11) | 协议不可用 (宏常量)
ENOSPC (C++11) | 设备无剩余空间 (宏常量)
ENOSR (C++11) | 无流资源 (宏常量)
ENOSTR (C++11) | 非流 (宏常量)
ENOSYS (C++11) | 不支持的函数 (宏常量)
ENOTCONN (C++11) | 未连接的接头 (宏常量)
ENOTDIR (C++11) | 非目录 (宏常量)
ENOTEMPTY (C++11) | 目录非空 (宏常量)
ENOTRECOVERABLE (C++11) | 状态不可恢复 (宏常量)
ENOTSOCK (C++11) | 非接头 (宏常量)
ENOTSUP (C++11) | 不支持 (宏常量)
ENOTTY (C++11) | 不适合的 I/O 控制操作 (宏常量)
ENXIO (C++11) | 无此设备或地址 (宏常量)
EOPNOTSUPP (C++11) | 接头上不支持的操作 (宏常量)
EOVERFLOW (C++11) | 值过大而无法存入数据类型 (宏常量)
EOWNERDEAD (C++11) | 先前拥有者已死 (宏常量)
EPERM (C++11) | 操作不允许 (宏常量)
EPIPE (C++11) | 管道损坏 (宏常量)
EPROTO (C++11) | 协议错误 (宏常量)
EPROTONOSUPPORT (C++11) | 不支持的协议 (宏常量)
EPROTOTYPE (C++11) | 接头类型错误的协议 (宏常量)
ERANGE | 结果过大 (宏常量)
EROFS (C++11) | 只读文件系统 (宏常量)
ESPIPE (C++11) | 非法寻位 (宏常量)
ESRCH (C++11) | 无此进程 (宏常量)
ETIME (C++11) | 流 ioctl() 超时 (宏常量)
ETIMEDOUT (C++11) | 连接超时 (宏常量)
ETXTBSY (C++11) | 文本文件忙 (宏常量)
EWOULDBLOCK (C++11) | 操作会阻塞 (宏常量)
EXDEV (C++11) | 跨设备链接 (宏常量)

要求所有值为唯一，除了 EOPNOTSUPP 与 ENOTSUP 的值可以相同，及 EAGAIN 与 EWOULDBLOCK 的值可以相同

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <clocale>

int main()
{
    double not_a_number = std::log(-1.0);
    if (errno == EDOM) {
        std::cout << "log(-1) failed: " << std::strerror(errno) << '\n';
        std::setlocale(LC_MESSAGES, "de_DE.utf8");
        std::cout << "Or, in German, " << std::strerror(errno) << '\n';
    }
}

可能的输出：

log(-1) failed: Numerical argument out of domain
Or, in German, Das numerische Argument ist ausserhalb des Definitionsbereiches

参阅

errc (C++11) | 列出所有标准 <cerrno> 宏常量的 std::error_condition 枚举 (类)
errno | 展开成 POSIX 兼容的线程局域错误号变量的宏 (宏变量)
perror | 显示对应当前错误的字符串于 stderr (函数)
strerror | 返回给定错误码的文本版本 (函数)


std::error_category

< cpp‎ | error
定义于头文件 <system_error> |
class error_category; | (C++11 起)

std::error_category 作为特定错误类别，如 std::system_category 、 std::iostream_category 等的基类工作。每个特定类别类定义 error_code - error_condition 映射，并保有所有 error_condition 的解释字符串。错误类别类的对象被当做单例，按引用传递。

成员函数

(构造函数) | 构造 error_category (公开成员函数)
(析构函数) [虚] | 析构 error_category (虚公开成员函数)
operator= [被删除] | 不可复制赋值 (公开成员函数)
name [虚] | 获得类别名称 (虚公开成员函数)
default_error_condition [虚] | 映射 error_code 到 error_condition (虚公开成员函数)
equivalent [虚] | 比较 error_code 与 error_condition 的等价性 (虚公开成员函数)
message [虚] | 获得解释性字符串 (虚公开成员函数)
operator==operator!=operator<operator<=> (C++20 中移除)(C++20 中移除)(C++20) | 比较二个错误类别 (函数)

特定错误类别

generic_category (C++11) | 鉴别通用错误类别 (函数)
system_category (C++11) | 鉴别操作系统错误类别 (函数)
iostream_category (C++11) | 鉴别 iostream 错误类别 (函数)
future_category (C++11) | 鉴别 future 错误类别 (函数)

参阅

error_condition (C++11) | 保有可移植的错误码 (类)
error_code (C++11) | 保有依赖于平台的错误码 (类)


std::error_category::default_error_condition

< cpp‎ | error‎ | error category
virtual std::error_condition default_error_condition( int code ) const noexcept; | (C++11 起)

返回给定 error_code 的 error_condition 。

等价于 std::error_condition (code, *this) 。

参数

code - 要为之返回 error_condition error code

返回值

给定 error_code 的 error_condition 。


std::error_category::equivalent

< cpp‎ | error‎ | error category
virtual bool equivalent( int code,
const std::error_condition & condition ) const noexcept;
 (1) (C++11 起)
virtual bool equivalent( const std::error_code & code,
int condition ) const noexcept;
 (2) (C++11 起)

检查对于 *this 所表示的 error_category ， error_code 是否等价于 error_condition 。

1) 等价于 default_error_condition(code) == condition 。
2) 等价于 *this == code.category() && code.value() == condition 。

参数

code | - | 指定要比较的 error_code
condition | - | 指定要比较的 error_condition

返回值

若对于 *this 所表示的 error_category ， error_code 等价于给定的 error_condition ，则为 true ，否则为 false 。


std::error_category::error_category

< cpp‎ | error‎ | error category
constexpr error_category() noexcept; | (1) | (C++11 起)
error_category( const error_category& ) = delete; | (2) | (C++11 起)
1) 构造 error_category 对象。
2) 复制构造函数被删除。 error_category 既非可移动构造 (MoveConstructible) 亦非可复制构造 (CopyConstructible) 。

参数

（无）

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2145 | C++11 | error_category 不可构造 | 添加了默认构造函数


std::error_category::message

< cpp‎ | error‎ | error category
virtual std::string message( int condition ) const = 0; | (C++11 起)

返回对于 *this 所表示的错误类别描述给定错误条件按的字符串。

参数

condition - 指定要描述的错误条件

返回值

描述给定错误类别的字符串。

异常

可能抛出实现定义的异常。


std::error_category::name

< cpp‎ | error‎ | error category
virtual const char* name() const noexcept = 0; | (C++11 起)

返回指向指定错误类别名称的空终止字节字符串的指针。

参数

（无）

返回值

指定 error_category 名称的空终止字节字符串。


std::error_category::operator==,!=,<,<=>

< cpp‎ | error‎ | error category
bool operator==( const error_category& rhs ) const noexcept; | (1) | (C++11 起)
bool operator!=( const error_category& rhs ) const noexcept; | (2) | (C++11 起) (C++20 前)
bool operator<( const error_category& rhs ) const noexcept; | (3) | (C++11 起) (C++20 前)
std::strong_ordering operator<=>( const error_category& rhs ) const noexcept; | (4) | (C++20 起)

与另一错误类别比较。

1) 检查 *this 与 rhs 是否指代同一对象。
2) 检查 *this 与 rhs 是否不指代同一对象。
3) 按 this 与 &rhs 的顺序排序 *this 与 rhs 。等价于 std::less <const error_category*>()(this, &rhs) 。
4) 按 this 与 &rhs 的顺序排序 *this 与 rhs 。等价于 std::std::compare_three_way()(this, &rhs) 。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

rhs - 指定要比较的 error_category

返回值

1) 若 *this 与 rhs 指代同一对象，则为 true ，否则为 false 。
2) 若 *this 与 rhs 不指代同一对象，则为 true ，否则为 false 。
3) 若按 this 与 &rhs 的顺序， *this 小于 rhs 则为 true 。
4) 若按 this 与 &rhs 的顺序， *this 小于 rhs 则为 std::strong_ordering::less ，否则若按该顺序 rhs 小于 *this 则为 std::strong_ordering::greater ，否则为 std::strong_ordering::equal 。


std::error_category::~error_category

< cpp‎ | error‎ | error category
virtual ~error_category(); | (C++11 起)

析构对象。

参数

（无）


std::error_code

< cpp‎ | error
定义于头文件 <system_error> |
class error_code; | (C++11 起)

std::error_code 是依赖平台的错误码。每个 std::error_code 对象，保有一个源于操作系统或某些低层接口的错误码，和一个指向 std::error_category 类型对象的指针，它对应前述接口。错误码的值在错误类别之间可以不唯一。

成员函数

(构造函数)
 构造一个 error_code
(公开成员函数)
operator=
 赋值为另一 error_code
(公开成员函数)
assign
 赋值为另一 error_code
(公开成员函数)
修改器
clear
 设 error_code 为 system_category 中的值 0
(公开成员函数)
观察器
value
 获得 error_code 的值
(公开成员函数)
category
 获得此 error_code 的 error_category
(公开成员函数)
default_error_condition
 获得此 error_code 的 error_condition
(公开成员函数)
message
 获得此 error_code 的解释性字符串
(公开成员函数)
operator bool
 检查值是否非零
(公开成员函数)

非成员函数

operator==operator!=operator<operator<=> (C++20 中移除)(C++20 中移除)(C++20) | 比较两个 error_code (函数)
operator<< | 输出值和类别名到输出流 (函数)

辅助类

is_error_code_enum (C++11) | 鉴别类是否可作为 error_code 枚举 (类模板)
std::hash<std::error_code> (C++11) | std::error_code 的散列支持 (类模板特化)

参阅

error_condition (C++11) | 保有可移植的错误码 (类)
error_category (C++11) | 错误类别的基类 (类)


std::error_code::assign

< cpp‎ | error‎ | error code
void assign( int ec, const error_category& ecat ) noexcept; | (C++11 起)

以错误码 ec 和对应的类别 ecat 替换内容。

参数

ec | - | 要赋值的平台依赖错误码
ecat | - | ec 所对应的 error_category

返回值

（无）

参阅

operator=
 赋值为另一 error_code
(公开成员函数)


std::error_code::category

< cpp‎ | error‎ | error code
const std::error_category & category() const noexcept; | (C++11 起)

返回错误值的 error_category 。

参数

（无）

返回值

错误值的 error_category 。

参阅

value
 获得 error_code 的值
(公开成员函数)


std::error_code::clear

< cpp‎ | error‎ | error code
void clear() noexcept; | (C++11 起)

以默认值替换错误码和错误类别。

等价于 *this = error_code(0, std::system_category ()) 。

参数

（无）

返回值

（无）


std::error_code::default_error_condition

< cpp‎ | error‎ | error code
std::error_condition default_error_condition() const noexcept; | (C++11 起)

返回当前错误值的默认错误条件。

等价于 category().default_error_condition(value()).

参数

（无）

返回值

当前错误值的默认错误条件。


std::error_code::error_code

< cpp‎ | error‎ | error code
error_code() noexcept; | (1) | (C++11 起)
error_code( int ec, const error_category& ecat ) noexcept; | (2) | (C++11 起)
template< class ErrorCodeEnum > error_code( ErrorCodeEnum e ) noexcept; | (3) | (C++11 起)

构造新的 error_code 。

1) 构造带默认值的 error_code 。等价于 error_code(0, std::system_category ()) 。
2) 以 ec 为平台依赖的错误码并以 ecat 为对应的错误类别构造 error_code 。
3) 从错误码枚举 e 构造 error_code 。等价于 make_error_code(e) ，其中 make_error_code 由实参依赖查找找到。此重载仅若std::is_error_code_enum <ErrorCodeEnum>::value 为 true 才参与重载决议。

参数

ec | - | 用以构造的平台依赖的错误码
ecat | - | 对应 ec 的 error_category
e | - | 用以构造的错误码枚举

注解

最初的提案 N2422 中有意使用 ADL 所找到的 make_error_code ，并且已知实现均使用它。然而，标准要求只考虑 std::make_error_code 重载。此为 LWG 问题 3629 。

参阅

make_error_code(std::errc) (C++11) | 构造 std::errc 错误码 (函数)
make_error_code(std::io_errc) (C++11) | 构造一个 iostream 错误码 (函数)
make_error_code(std::future_errc) (C++11) | 构造一个 future error_code (函数)


std::hash<std::error_code>

< cpp‎ | error‎ | error code
定义于头文件 <system_error> |
template<> struct hash<error_code>; | (C++11 起)

std::hash 对 std::error_code 的模板特化允许用户获得 std::error_code 类型对象的哈希。


std::is_error_code_enum

< cpp‎ | error‎ | error code
定义于头文件 <system_error> |
template< class T > struct is_error_code_enum; | (C++11 起)

若 T 是错误码枚举，则此模板提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

此模板可以为用户定义类型特化，以指示该类型适合于 std::error_code 及 std::error_condition 自动转换。

标准库的下列类是错误码枚举：

  • std::io_errc
  • std::future_errc

帮助变量模板

template< class T > inline constexpr bool is_error_code_enum_v = is_error_code_enum<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 是错误码枚举则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

参阅

is_error_condition_enum
(C++11)
 鉴别枚举是否可作为 std::error_condition
(类模板)


std::error_code::message

< cpp‎ | error‎ | error code
std::string message() const; | (C++11 起)

返回对应当前错误值和类别的消息。

等价于 category().message(value()) 。

参数

（无）

返回值

对应当前错误值和类别的错误消息。

异常

可能抛出实现定义的异常。


std::error_code::operator=

< cpp‎ | error‎ | error code
template< class ErrorCodeEnum > error_code& operator=( ErrorCodeEnum e ) noexcept; | (C++11 起)

以表示错误码枚举 e 者替换错误码和对应类别。

等价于 *this = make_error_code(e) ，其中以无限定调用 make_error_code 以启用实参依赖查找。此重载仅若 std::is_error_code_enum <ErrorCodeEnum>::value 为 true 才参与重载决议。

参数

e - 要构造的错误码枚举

返回值

*this

注解

复制赋值运算符为隐式定义。

最初的提案 N2422 中有意使用 ADL 所找到的 make_error_code ，并且已知实现均使用它。然而，标准要求只考虑 std::make_error_code 重载。此为 LWG 问题 3629 。

参阅

assign
 赋值为另一 error_code
(公开成员函数)


std::error_code::operator bool

< cpp‎ | error‎ | error code
explicit operator bool() const noexcept; | (C++11 起)

检查错误值是否合法，即非零。

参数

（无）

返回值

若 value() == 0 则为 false ，否则为 true 。


std::operator==,!=,<,<=>(std::error_code)

< cpp‎ | error‎ | error code
定义于头文件 <system_error>
bool operator==( const std::error_code & lhs,
const std::error_code & rhs ) noexcept;
 (1) (C++11 起)
bool operator!=( const std::error_code & lhs,
const std::error_code & rhs ) noexcept;
 (2) (C++11 起)
(C++20 前)
bool operator<( const std::error_code & lhs,
const std::error_code & rhs ) noexcept;
 (3) (C++11 起)
(C++20 前)
std::strong_ordering operator<=>( const std::error_code & lhs,
const std::error_code & rhs ) noexcept;
 (4) (C++20 起)

比较二个 error_code 对象。

1) 比较 lhs 与 rhs 的相等性。
2) 比较 lhs 与 rhs 的相等性。
3) 检查 lhs 是否小于 rhs 。
4) 获得 lhs 与 rhs 的三路比较结果。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的 error_code

返回值

1) 若错误类别和错误值比较相等则为 true 。
2) 若错误类别或错误值比较不相等则为 true 。
3) 若 lhs.category() < rhs.category() 则为 true 。否则，若 lhs.category() == rhs.category() && lhs.value() < rhs.value() 则为 true 。否则为 false
4) 若 lhs.category() <=> rhs.category() 不为 std::strong_ordering::equal 则为该值。否则为 lhs.value() <=> rhs.value() 。

参阅

category
 获得此 error_code 的 error_category
(公开成员函数)


std::operator<<(std::error_code)

< cpp‎ | error‎ | error code
定义于头文件 <system_error>
template< class CharT, class Traits >

std::basic_ostream <CharT,Traits>&

operator<<( basic_ostream<CharT,Traits>& os, const error_code& ec );
 (C++11 起)

进行 error_code ec 上的流输出操作。

等价于 os << ec.category().name() << ':' << ec.value 。

参数

os | - | 要插入数据的输出流
ec | - | error_code

返回值

os


std::error_code::value

< cpp‎ | error‎ | error code
int value() const noexcept; | (C++11 起)

返回平台依赖的错误值。

参数

（无）

返回值

平台依赖的错误值。

参阅

category
 获得此 error_code 的 error_category
(公开成员函数)


std::error_condition

< cpp‎ | error
定义于头文件 <system_error> |
class error_condition; | (C++11 起)

std::error_condition 是独立于平台的错误码。类似于 std::error_code ，它为整数值和 std::error_category 所唯一标识，但不同于 std::error_code ，该值不依赖平台。

典型的实现保有整数数据成员（该值）和指向一个 std::error_category 的指针。

成员函数

(构造函数) | 构造 error_condition (公开成员函数)
operator= | 替换内容 (公开成员函数)
assign | 替换内容 (公开成员函数)
clear | 设置 error_condition 为值 0 ，于 generic_category 中 (公开成员函数)
value | 获得 error_condition 的值 (公开成员函数)
category | 获得此 error_condition 的 error_category (公开成员函数)
message | 获得解释性字符串 (公开成员函数)
operator bool | 检查值是否非零 (公开成员函数)

非成员函数

operator==operator!=operator<operator<=>
(C++20 中移除)(C++20 中移除)(C++20)
 比较 error_condition 和 error_code
(函数)

辅助类

is_error_condition_enum (C++11) | 鉴别枚举是否可作为 std::error_condition (类模板)
std::hash<std::error_condition> (C++17) | std::error_condition 的哈希支持 (类模板特化)

参阅

error_code (C++11) | 保有依赖于平台的错误码 (类)
error_category (C++11) | 错误类别的基类 (类)


std::error_condition::assign

< cpp‎ | error‎ | error condition
void assign( int val, const error_category& cat ) noexcept; | (C++11 起)

赋值内容给 error_condition 。设置 error_code 为 val ， error_category 为 cat 。

参数

val | - | 错误码
cat | - | error_category

返回值

（无）


std::error_condition::category

< cpp‎ | error‎ | error condition
const error_category& category() const noexcept; | (C++11 起)

返回存储的 error_category 。

参数

（无）

返回值

存储的 error_category 。


std::error_condition::clear

< cpp‎ | error‎ | error condition
void clear() noexcept; | (C++11 起)

清除 error_condition 的状态。设置 error_code 为 ​0​ ， error_category 为 std::generic_category 。

参数

（无）

返回值

（无）


std::error_condition::error_condition

< cpp‎ | error‎ | error condition
error_condition() noexcept; | (1) | (C++11 起)
error_condition( const error_condition& other ) noexcept; | (2) | (C++11 起) (隐式声明)
error_condition( int val, const error_category& cat ) noexcept; | (3) | (C++11 起)
template< class ErrorConditionEnum > error_condition( ErrorConditionEnum e ) noexcept; | (4) | (C++11 起)

构造新的 error_condition 。

1) 默认构造函数。初始化 error_condition 为 generic_category 和错误码 ​0​ 。
2) 复制构造函数。以 other 的内容初始化 error_condition 。
3) 以错误码 val 和错误类别 cat 初始化 error_condition 。
4) 以枚举 e 初始化 error_condition 。等效于对 e 调用实参依赖查找所找到的 make_error_condition 。此重载仅若 std::is_error_condition_enum <ErrorConditionEnum>::value 为 true 才参与重载决议。

参数

other | - | 以之初始化的另一 error_condition
val | - | 错误码
cat | - | 错误类别
e | - | 错误条件枚举

注解

最初的提案 N2422 中有意使用 ADL 所找到的 make_error_condition ，并且已知实现均使用它。然而，标准要求只考虑 std::make_error_condition 重载。此为 LWG 问题 3629 。

参阅

make_error_condition(std::errc) (C++11) | 构造 std::errc 错误条件 (函数)
make_error_condition(std::io_errc) (C++11) | 构造一个 iostream error_condition (函数)
make_error_condition(std::future_errc) (C++11) | 构造一个 future error_condition (函数)


std::hash<std::error_condition>

< cpp‎ | error‎ | error condition
定义于头文件 <system_error> |
template<> struct hash< std::error_condition >; | (C++17 起)

std::hash 对 std::error_condition 的模板特化允许用户获得 std::error_condition 类型对象的哈希。


std::is_error_condition_enum

< cpp‎ | error‎ | error condition
定义于头文件 <system_error> |
template< class T > struct is_error_condition_enum; | (C++11 起)

若 T 是错误条件枚举，则此模板提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

此模板可以为用户定义类型特化，以指示该类型适合于 std::error_condition 自动转换。

标准库的下列类是错误条件枚举： std::errc 。

帮助变量模板

template< class T > inline constexpr bool is_error_condition_enum_v = is_error_condition_enum<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 是错误条件枚举则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

参阅

is_error_code_enum
(C++11)
 鉴别类是否可作为 error_code 枚举
(类模板)


std::error_condition::message

< cpp‎ | error‎ | error condition
std::string message() const; | (C++11 起)

为存储的错误码和错误类别返回解释字符串。等效于调用 category().message(value()) 。

参数

（无）

返回值

存储的错误码和错误类别的解释消息。

异常

可能抛出实现定义的异常。


std::error_condition::operator=

< cpp‎ | error‎ | error condition
error_condition& operator=( const error_condition& other ) noexcept; | (1) | (C++11 起) (隐式声明)
template< class ErrorConditionEnum > error_condition& operator=( ErrorConditionEnum e ) noexcept; | (2) | (C++11 起)

赋值内容给 error_condition 。

1) 复制赋值运算符。赋值 other 的内容。
2) 为枚举 e 赋值 error_condition for enum 。等效于对 e 调用实参依赖查找所找到的 make_error_condition 。此重载仅若 std::is_error_condition_enum <ErrorConditionEnum>::value 为 true 才参与重载决议。

参数

other | - | 用以赋值的另一 error_condition
e | - | 错误条件枚举

注解

最初的提案 N2422 中有意使用 ADL 所找到的 make_error_condition ，并且已知实现均使用它。然而，标准要求只考虑 std::make_error_condition 重载。此为 LWG 问题 3629 。

返回值

*this 。


std::error_condition::operator bool

< cpp‎ | error‎ | error condition
explicit operator bool() const noexcept; | (C++11 起)

检查存储的错误码是否非零。

参数

（无）

返回值

若 value != 0 则为 true ，否则为 false 。


operator==,!=,<,<=>(std::error_condition)

< cpp‎ | error‎ | error condition
定义于头文件 <system_error>
bool operator==( const std::error_condition & lhs,
const std::error_condition & rhs ) noexcept;
 (1) (C++11 起)
bool operator!=( const std::error_condition & lhs,
const std::error_condition & rhs ) noexcept;
 (2) (C++11 起)
(C++20 前)
bool operator<( const std::error_condition & lhs,
const std::error_condition & rhs ) noexcept;
 (3) (C++11 起)
(C++20 前)
std::strong_ordering operator<=>( const std::error_condition & lhs,
const std::error_condition & rhs ) noexcept;
 (4) (C++20 起)
bool operator==( const std::error_code & code,
const std::error_condition & cond ) noexcept;
 (5) (C++11 起)
bool operator==( const std::error_condition & cond,
const std::error_code & code ) noexcept;
 (5) (C++11 起)
(C++20 前)
bool operator!=( const std::error_code & code,
const std::error_condition & cond ) noexcept;
 (6) (C++11 起)
(C++20 前)
bool operator!=( const std::error_condition & cond,
const std::error_code & code ) noexcept;
 (6) (C++11 起)
(C++20 前)

比较二个错误条件。

1) 检查 lhs 与 rhs 是否相等。
2) 检查 lhs 与 rhs 是否不相等。
3) 检查 lhs 是否小于 rhs 。
4) 获得 lhs 与 rhs 的三路比较结果。
5) 检查 code 是否为 cond 的语义匹配。
6) 检查 code 是否不是 cond 的语义匹配。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs, cond | - | 要比较的错误条件
code | - | 要比较的错误码

返回值

1) 若错误类别与错误值比较相等则为 true 。
2) 若错误类别或错误值比较不相等则为 true 。
3) 若则为 lhs.category() < rhs.category() ， true 。否则若 lhs.category() == rhs.category() && lhs.value() < rhs.value() 则为 true 。否则为 false 。
4) 若 lhs.category() <=> rhs.category() 不为 std::strong_ordering::equal 则为该值。否则为 lhs.value() <=> rhs.value() 。
5) 若 code.category().equivalent(code.value(), cond) 或 cond.category().equivalent(code, cond.value()) 则为 true 。
6) 若既非 code.category().equivalent(code.value(), cond) 亦非 cond.category().equivalent(code, cond.value()) 则为 true 。


std::error_condition::value

< cpp‎ | error‎ | error condition
int value() const noexcept; | (C++11 起)

返回存储的错误号。

参数

（无）

返回值

存储的错误号。


std::exception

< cpp‎ | error
定义于头文件 <exception>
class exception;

提供一致的接口，以通过 throw 表达式处理错误。

标准库所生成的所有异常继承自 std::exception

  • logic_error
  • invalid_argument
  • domain_error
  • length_error
  • out_of_range
  • future_error (C++11)
  • bad_optional_access (C++17)
  • runtime_error
  • range_error
  • overflow_error
  • underflow_error
  • regex_error (C++11)
  • system_error (C++11)
  • ios_base::failure (C++11)
  • filesystem::filesystem_error (C++17)
  • nonexistent_local_time (C++20)
  • ambiguous_local_time (C++20)
  • tx_exception (TM TS)
  • format_error (C++20)
  • bad_typeid
  • bad_cast
  • bad_any_cast (C++17)
  • bad_weak_ptr (C++11)
  • bad_function_call (C++11)
  • bad_alloc
  • bad_array_new_length (C++11)
  • bad_exception
  • ios_base::failure (C++11 前)
  • bad_variant_access (C++17)

成员函数

(构造函数) | 构造异常对象 (公开成员函数)
(析构函数) [虚] | 析构该异常对象 (虚公开成员函数)
operator= | 复制异常对象 (公开成员函数)
what [虚] | 返回解释性字符串 (虚公开成员函数)


std::exception::exception

< cpp‎ | error‎ | exception
 | (1)
exception() throw(); |  | (C++11 前)
exception() noexcept; |  | (C++11 起)
 | (2)
exception( const exception& other ) throw(); |  | (C++11 前)
exception( const exception& other ) noexcept; |  | (C++11 起)

构造新的异常对象。

1) 默认构造函数。 what() 返回实现定义的字符串。
2) 复制构造函数。以 other 的内容初始化其内容。若 *this 与 other 均拥有动态类型 std::exception ，则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 要赋值内容的另一 exception

注意

因为不允许复制 std::exception 抛出异常，故当派生类（例如 std::runtime_error ）必须管理用户定义的诊断信息时，常将它实现为写时复制的字符串。


std::get_unexpected

< cpp‎ | error
定义于头文件 <exception> |
std::unexpected_handler get_unexpected() noexcept; | (C++11 起) (弃用) (C++17 中移除)

返回当前安装的 std::unexpected_handler ，可以是空指针。

此函数线程安全。先前到 std::set_unexpected 的调用同步于（见 std::memory_order ）此函数的后继调用。

参数

（无）

返回值

当前安装的 std::unexpected_handler 。

参阅

unexpected_handler (C++17 中移除) | std::unexpected 所调用的函数类型 (typedef)
set_unexpected (C++17 中移除) | 更改要被 std::unexpected 调用的函数 (函数)


std::exception::operator=

< cpp‎ | error‎ | exception
exception& operator=( const exception& other ) throw(); | (C++11 前)
exception& operator=( const exception& other ) noexcept; | (C++11 起)

复制赋值运算符。赋值 other 的内容

赋值后调用 what() 的效果是实现定义的。 | (C++11 前)
若 *this 与 other 均拥有动态类型 std::exception ，则赋值后 std::strcmp (what(), other.what()) == 0 。 | (C++11 起)

参数

other - 要赋值内容的另一 exception


std::set_unexpected

< cpp‎ | error
定义于头文件 <exception> |
std::unexpected_handler set_unexpected( std::unexpected_handler f ) throw(); | (C++11 前)
std::unexpected_handler set_unexpected( std::unexpected_handler f ) noexcept; | (C++11 起) (弃用) (C++17 中移除)

令 f 为全局 std::unexpected_handler 并返回先前安装的 std::unexpected_handler 。

此函数线程安全。每个到 std::set_unexpected 的调用同步于（见 std::memory_order ）对 std::set_unexpected 和 std::get_unexpected 的后继调用。

 (C++11 起)

参数

f - std::unexpected_handler 类型的指向函数指针，或空指针

返回值

先前安装的 unexpected_handler ，或若未安装安装则为空指针值。

参阅

unexpected (C++17 中移除) | 违背动态异常说明时调用的函数 (函数)
get_unexpected (C++11)(C++17 中移除) | 获得当前的 unexpected_handler (函数)
unexpected_handler (C++17 中移除) | std::unexpected 所调用的函数类型 (typedef)


std::uncaught_exception, std::uncaught_exceptions

< cpp‎ | error
定义于头文件 <exception> |  |
 | (1) |
bool uncaught_exception() throw(); |  |  | (C++11 前)
bool uncaught_exception() noexcept; |  |  | (C++11 起) (C++17 中弃用) (C++20 中移除)
int uncaught_exceptions() noexcept; | (2) | (C++17 起)
1) 检测当前线程是否有生存的异常对象，即被抛出或重抛出且未进入匹配的 catch 子句、 std::terminate 或 std::unexpected 的异常。换言之，std::uncaught_exception 检测当前是否在进行栈回溯。
2) 检测当前线程已经抛出或重抛出且未进入其匹配 catch 子句的异常对象数。

有时抛出异常是安全的，即使当 std::uncaught_exception() == true 。例如，若栈回溯导致要析构对象，则该对象的析构函数可以运行抛出异常的代码，只要在离开析构函数前为某 catch 块捕捉该异常。

参数

（无）

返回值

1) 若此线程中当前正在进行栈回溯则为 true 。
2) 当前线程中的为捕捉异常对象数。

注意

返回 int 的 uncaught_exceptions 的一个使用例子是 boost.log 库：表达式 BOOST_LOG(logger) << foo(); 首先创建保障对象并记录其构造函数中的未捕捉异常数。由保障对象的析构函数进行输出，除非 foo() 抛出（该情况下析构函数中未捕捉异常的数量大于构造函数所观察到的）

示例

#include <iostream>
#include <exception>
#include <stdexcept>

struct Foo {
    int count = std::uncaught_exceptions();
    ~Foo() {
        std::cout << (count == std::uncaught_exceptions()
            ? "~Foo() called normally\n"
            : "~Foo() called during stack unwinding\n");
    }
};
int main()
{
    Foo f;
    try {
        Foo f;
        std::cout << "Exception thrown\n";
        throw std::runtime_error("test exception");
    } catch (const std::exception& e) {
        std::cout << "Exception caught: " << e.what() << '\n';
    }
}

输出：

Exception thrown
~Foo() called during stack unwinding
Exception caught: test exception
~Foo() called normally

参阅

terminate | 异常处理失败时调用的函数 (函数)
exception_ptr (C++11) | 用于处理异常对象的共享指针类型 (typedef)
current_exception (C++11) | 捕获当前异常到 std::exception_ptr 之中 (函数)

外部链接

  • GOTW 问题 47 ：未捕捉异常
  • std::uncaught_exceptions 的基本原理


std::unexpected

< cpp‎ | error
定义于头文件 <exception> |
void unexpected(); | (C++11 前)
[[noreturn]] void unexpected(); | (C++11 起) (弃用) (C++17 中移除)

std::unexpected() 为 C++ 运行时在违背动态异常规定时调用：从其异常规定禁止此类型异常的函数抛出该类型异常。

亦可从程序直接调用 std::unexpected() 。

任一情况下， std::unexpected 调用当前安装的 std::unexpected_handler 。默认的 std::unexpected_handler 调用 std::terminate 。

若析构函数在栈回溯期间重置 unexpected_handler 且之后的回溯导致调用 unexpected ，则将调用于 throw 表达式结尾安装的处理函数。（注意：重抛出是否应用新的处理函数是有歧义的） | (C++11 前)
若析构函数在栈回溯期间重置 unexpected_handler ，则若之后的回溯导致调用 unexpected ，则调用哪个处理函数是未指定的。 | (C++11 起)

参数

（无）

返回值

（无）

异常

抛出当前安装的 std::unexpected_handler 所抛的异常

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2111 | C++11 | 在栈回溯期间调用 set_unexpected 的效果异于 C++98 并破坏一些 ABI | 令它未指定

参阅

unexpected_handler
(C++17 中移除)
 std::unexpected 所调用的函数类型
(typedef)


std::unexpected_handler

< cpp‎ | error
定义于头文件 <exception> |
typedef void (*unexpected_handler)(); | (C++11 中弃用) (C++17 中移除)

std::unexpected_handler 是函数指针类型（指向不接收参数并返回 void 的函数），它为函数 std::set_unexpected 所安装，为 std::get_unexpected 所查询，并为 std::unexpected 所调用。

C++ 实现提供默认的 std::unexpected_handler 函数，它调用 std::terminate () 。若安装空指针值（用 std::set_unexpected ），则实现可以替代地恢复默认处理函数。

期待用户定义的 std::unexpected_handler 终止程序或抛出异常。若它抛出异常，则可能遇到下列三种情况之一：

1) std::unexpected_handler 所抛的异常满足之前被违背的动态异常规定。则允许新异常逃出函数并继续栈回溯。

2) std::unexpected_handler 所抛的异常仍然违背动态异常规定：

2a) 然而，异常规定允许 std::bad_exception ： C++ 运行时销毁抛出的异常对象，并构造 std::bad_exception 替代地抛出。

2b) 异常规定不允许 std::bad_exception ：调用 std::terminate () 。

参阅

unexpected (C++17 中移除) | 违背动态异常说明时调用的函数 (函数)
set_unexpected (C++17 中移除) | 更改要被 std::unexpected 调用的函数 (函数)
get_unexpected (C++11)(C++17 中移除) | 获得当前的 unexpected_handler (函数)


std::exception::what

< cpp‎ | error‎ | exception
virtual const char* what() const throw(); | (C++11 前)
virtual const char* what() const noexcept; | (C++11 起)

返回解释性字符串。

参数

（无）

返回值

指向拥有解释信息的空终止字符串的指针。该指针保证在获取它的异常对象被销毁前，或在调用该异常对象的非静态成员函数前合法。


std::exception::~exception

< cpp‎ | error‎ | exception
virtual ~exception();

销毁异常对象。


std::exception_ptr

< cpp‎ | error
定义于头文件 <exception> |
typedef /*unspecified*/ exception_ptr; | (C++11 起)

std::exception_ptr 是一个类可空指针的类型，管理已抛出并为 std::current_exception 所捕捉的异常对象。 std::exception_ptr 的实例可传递给另一函数，可以在另一线程，在那里异常可能重抛并为 catch 子句所处理。

默认构造的 std::exception_ptr 是空指针；它不指向异常对象。

二个 std::exception_ptr 实例比较相等，仅若它们均为空或都指向同一异常对象。

std::exception_ptr 不可隐式转换为任何算术、枚举或指针类型。它可以按语境转换成 bool ，且若它为空则求值为 false ，否则为 true 。

一个 std::exception_ptr 所引用的异常对象只要为至少一个 std::exception_ptr 所引用就保持合法： std::exception_ptr 是共享所有权的智能指针（注意：这附加于异常对象生存期规则）

std::exception_ptr 满足可空指针 (NullablePointer) 的要求。

示例

#include <iostream>
#include <string>
#include <exception>
#include <stdexcept>

void handle_eptr(std::exception_ptr eptr) // 按值传递 ok
{
    try {
        if (eptr) {
            std::rethrow_exception(eptr);
        }
    } catch(const std::exception& e) {
        std::cout << "Caught exception \"" << e.what() << "\"\n";
    }
}

int main()
{
    std::exception_ptr eptr;
    try {
        std::string().at(1); // 这生成一个 std::out_of_range
    } catch(...) {
        eptr = std::current_exception(); // 捕获
    }
    handle_eptr(eptr);
} // std::out_of_range 的析构函数调用于此，在 ept 析构时

输出：

Caught exception "basic_string::at"

参阅

make_exception_ptr (C++11) | 从异常对象创建一个std::exception_ptr (函数模板)
current_exception (C++11) | 捕获当前异常到 std::exception_ptr 之中 (函数)
rethrow_exception (C++11) | 从一个 std::exception_ptr 抛出异常 (函数)


std::generic_category

< cpp‎ | error
定义于头文件 <system_error> |
const std::error_category & generic_category() noexcept; | (C++11 起)

获取到用于通用错误的静态 error_category 对象的引用。对象要求覆写虚函数 error_category::name() 已返回指向字符串 "generic" 的指针。它用于鉴别对应 POSIX errno 码的错误条件。

参数

（无）

返回值

到导出自 std::error_category 的未指定运行时类型的静态对象的引用。

示例

#include <iostream>
#include <system_error>
#include <cerrno>
#include <string>
int main()
{
    std::error_condition econd = std::generic_category().default_error_condition(EDOM);
    std::cout << "Category: " << econd.category().name() << '\n'
              << "Value: " << econd.value() << '\n'
              << "Message: " << econd.message() << '\n';
}

输出：

Category: generic
Value: 33
Message: Numerical argument out of domain

参阅

system_category (C++11) | 鉴别操作系统错误类别 (函数)
errc (C++11) | 列出所有标准 <cerrno> 宏常量的 std::error_condition 枚举 (类)


std::get_terminate

< cpp‎ | error
定义于头文件 <exception> |
std::terminate_handler get_terminate() noexcept; | (C++11 起)

返回当前安装的 std::terminate_handler ，它可以是空指针。

此函数是线程安全的。先前对 std::set_terminate 的调用同步于（见 std::memory_order ）此函数。

 (C++11 起)

参数

（无）

返回值

当前安装的 std::terminate_handler.

参阅

terminate_handler | std::terminate 所调用的函数类型 (typedef)
set_terminate | 更改将被 std::terminate 调用的函数 (函数)


std::invalid_argument

< cpp‎ | error
定义于头文件 <stdexcept>
class invalid_argument;

定义作为异常抛出的对象类型。它报告因参数值未被接受而引发的错误。

std::bitset::bitset 和 std::stoi 与 std::stof 函数族抛出此异常。

cpp/error/exception cpp/error/logic error

继承图

成员函数

(构造函数) | 构造拥有给定消息的新 invalid_argument 对象 (公开成员函数)
operator= | 替换 invalid_argument 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::invalid_argument::invalid_argument

invalid_argument( const std::string & what_arg ); | (1) |
invalid_argument( const char* what_arg ); | (2) | (C++11 起)
 | (3) |
invalid_argument( const invalid_argument& other ); |  |  | (C++11 前)
invalid_argument( const invalid_argument& other ) noexcept; |  |  | (C++11 起)
1-2) 构造以 what_arg 为解释字符串的异常对象，解释字符串能通过 what() 访问。
3) 复制构造函数。若 *this 与 other 均拥有动态类型 std::invalid_argument 则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

what_arg | - | 解释字符串
other | - | 要复制的另一异常对象

异常

1-2) 可能抛出 std::bad_alloc

注解

因为不容许复制 std::invalid_argument 抛出异常，通常将此消息在内部存储为分离分配的引用计数字符串。这也是构造函数不接收 std::string&& 参数的理由：无论如何它必须复制内容。

std::invalid_argument::operator=

invalid_argument& operator=( const invalid_argument& other ); | (C++11 前)
invalid_argument& operator=( const invalid_argument& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::invalid_argument 则赋值后 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 用以赋值的另一异常对象

返回值

*this

std::invalid_argument::what

virtual const char* what() const throw(); | (C++11 前)
virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::logic_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

注解

此异常类型的目的同错误条件 std::errc::invalid_argument （在 std::system_error 中从 std::thread 的成员函数抛出）和关联的 errno 常量 EINVAL 。


std::length_error

< cpp‎ | error
定义于头文件 <stdexcept>
class length_error;

定义作为异常抛出的对象类型。它报告试图超出一些对象的实现定义长度极限所导致的错误。

此异常为 std::basic_string 的成员函数和 std::vector::reserve 所抛出。

cpp/error/exception cpp/error/logic error

继承图

成员函数

(构造函数) | 构造拥有给定消息的新 length_error 对象 (公开成员函数)
operator= | 替换 length_error 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::length_error::length_error

length_error( const std::string & what_arg ); | (1) |
length_error( const char* what_arg ); | (2) | (C++11 起)
 | (3) |
length_error( const length_error& other ); |  |  | (C++11 前)
length_error( const length_error& other ) noexcept; |  |  | (C++11 起)
1-2) 构造以 what_arg 为解释字符串的异常对象，解释字符串能通过 what() 访问。
3) 复制构造函数。若 *this 与 other 均拥有动态类型 std::length_error 则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

what_arg | - | 解释字符串
other | - | 要复制的另一异常对象

异常

1-2) 可能抛出 std::bad_alloc

注解

因为不容许复制 std::length_error 抛出异常，通常将此消息在内部存储为分离分配的引用计数字符串。这也是构造函数不接收 std::string&& 参数的理由：无论如何它必须复制内容。

std::length_error::operator=

length_error& operator=( const length_error& other ); | (C++11 前)
length_error& operator=( const length_error& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::length_error 则赋值后 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 用以赋值的另一异常对象

返回值

*this

std::length_error::what

virtual const char* what() const throw(); | (C++11 前)
virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::logic_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

参阅

resize
 更改存储的字符数
(std::basic_string<CharT,Traits,Allocator> 的公开成员函数)


std::logic_error

< cpp‎ | error
定义于头文件 <stdexcept>
class logic_error;

定义作为异常抛出的对象的类型。它报告程序内部错误逻辑所导致的可避免错误，如违背逻辑前提条件或类不变量。

没有标准库组件直接抛出此异常，但异常类型 std::invalid_argument 、 std::domain_error 、 std::length_error 、 std::out_of_range 、 std::future_error 及 std::experimental::bad_optional_access 派生自 std::logic_error 。

cpp/error/exception

继承图

成员函数

(构造函数) | 构造拥有给定消息的新 logic_error 对象 (公开成员函数)
operator= | 替换 logic_error 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::logic_error::logic_error

logic_error( const std::string & what_arg ); | (1) |
logic_error( const char* what_arg ); | (2) | (C++11 起)
 | (3) |
logic_error( const logic_error& other ); |  |  | (C++11 前)
logic_error( const logic_error& other ) noexcept; |  |  | (C++11 起)
1-2) 构造以 what_arg 为解释字符串的异常对象，解释字符串能通过 what() 访问。
3) 复制构造函数。若 *this 与 other 均拥有动态类型 std::logic_error 则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

what_arg | - | 解释字符串
other | - | 要复制的另一异常对象

异常

1-2) 可能抛出 std::bad_alloc

注解

因为不容许复制 std::logic_error 抛出异常，通常将此消息在内部存储为分离分配的引用计数字符串。这也是构造函数不接收 std::string&& 参数的理由：无论如何它必须复制内容。

std::logic_error::operator=

logic_error& operator=( const logic_error& other ); | (C++11 前)
logic_error& operator=( const logic_error& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::logic_error 则赋值后 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 用以赋值的另一异常对象

返回值

*this

std::logic_error::what

virtual const char* what() const throw(); | (C++11 前)
virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)


std::make_exception_ptr

< cpp‎ | error
定义于头文件 <exception> |
template< class E > std::exception_ptr make_exception_ptr( E e ) noexcept; | (C++11 起)

创建一个保有到 e 副本的引用的 std::exception_ptr 。这如同以下列代码执行：

try {
    throw e;
} catch(...) {
    return std::current_exception();
}

参数

（无）

返回值

保有到 e 副本，或到 std::bad_alloc 实例，或到 std::bad_exception 实例的引用的 std::exception_ptr 实例（参阅 std::current_exception ）。

注意

参数按值传递，并受切片影响。

参阅

current_exception
(C++11)
 捕获当前异常到 std::exception_ptr 之中
(函数)


std::nested_exception

< cpp‎ | error
定义于头文件 <exception> |
class nested_exception; | (C++11 起)

std::nested_exception 是一个多态混入类，可以捕获并存储当前异常，令任意类型的异常彼此间内嵌可行。

成员函数

(构造函数) | 构造 nested_exception (公开成员函数)
(析构函数) [虚] | 析构 nested exception (虚公开成员函数)
operator= | 替换 nested_exception 的内容 (公开成员函数)
rethrow_nested | 抛出存储的异常 (公开成员函数)
nested_ptr | 获得指向存储的异常的指针 (公开成员函数)

非成员函数

throw_with_nested (C++11) | 抛出实参，带上混入的 std::nested_exception (函数模板)
rethrow_if_nested (C++11) | 抛出 std::nested_exception 中的异常 (函数模板)

示例

演示构造并通过 nested_exception 对象递归

#include <iostream>
#include <stdexcept>
#include <exception>
#include <string>
#include <fstream>

// 打印异常的解释性字符串。若异常内嵌，则递归打印其保有的异常的解释
void print_exception(const std::exception& e, int level =  0)
{
    std::cerr << std::string(level, ' ') << "exception: " << e.what() << '\n';
    try {
        std::rethrow_if_nested(e);
    } catch(const std::exception& e) {
        print_exception(e, level+1);
    } catch(...) {}
}

// 示例函数，捕捉异常并将其包装于 nested_exception
void open_file(const std::string& s)
{
    try {
        std::ifstream file(s);
        file.exceptions(std::ios_base::failbit);
    } catch(...) {
        std::throw_with_nested( std::runtime_error("Couldn't open " + s) );
    }
}

// 示例函数，捕捉异常并将其包装于 nested_exception
void run()
{
    try {
        open_file("nonexistent.file");
    } catch(...) {
        std::throw_with_nested( std::runtime_error("run() failed") );
    }
}

// 运行上述实例函数并打印捕捉的异常
int main()
{
    try {
        run();
    } catch(const std::exception& e) {
        print_exception(e);
    }
}

输出：

exception: run() failed
 exception: Couldn't open nonexistent.file
  exception: basic_ios::clear

参阅

exception_ptr (C++11) | 用于处理异常对象的共享指针类型 (typedef)
throw_with_nested (C++11) | 抛出实参，带上混入的 std::nested_exception (函数模板)
rethrow_if_nested (C++11) | 抛出 std::nested_exception 中的异常 (函数模板)


std::nested_exception::nested_exception

< cpp‎ | error‎ | nested exception
nested_exception() noexcept; | (1) | (C++11 起)
nested_exception( const nested_exception& other ) noexcept = default; | (2) | (C++11 起)

构造新的 nested_exception 对象。

1) 默认构造函数。存储由调用 std::current_exception () 获得的异常对象于新的 nested_exception 对象。
2) 复制构造函数。以存储于 other 的异常初始化对象。

参数

other - 以之初始化内容的 nested_exception


std::nested_exception::nested_ptr

< cpp‎ | error‎ | nested exception
std::exception_ptr nested_ptr() const noexcept; | (C++11 起)

返回指向存储的异常的指针，若存在。

参数

（无）

返回值

若存储异常则为指向它的 std::exception_ptr ，否则为默认构造的 std::exception_ptr() 。


std::nested_exception::operator=

< cpp‎ | error‎ | nested exception
nested_exception& operator=( const nested_exception& other ) noexcept = default; | (C++11 起)

以保有于 other 中者替换存储的异常。

参数

other - 以之替换内容的 nested_exception

返回值

*this


std::nested_exception::rethrow_nested

< cpp‎ | error‎ | nested exception
[[noreturn]] void rethrow_nested() const; | (C++11 起)

重抛出存储的异常。若无存储的异常（即 nested_ptr() 返回空指针），则调用 std::terminate 。

参数

（无）

返回值

（无）


std::nested_exception::~nested_exception

< cpp‎ | error‎ | nested exception
virtual ~nested_exception() = default; | (C++11 起)

销毁 nested_exception 对象。


std::out_of_range

< cpp‎ | error
定义于头文件 <stdexcept>
class out_of_range;

定义作为异常抛出的对象类型。它报告访问试图受定义范围外的元素所带来的错误。

它可能为 std::bitset 与 std::basic_string 的成员函数、 std::stoi 与 std::stod 函数族及有边界检查的成员访问函数（例如 std::vector::at 与 std::map::at ）所抛出。

cpp/error/exception cpp/error/logic error std-out of range-inheritance.svg

继承图

成员函数

(构造函数) | 构造拥有给定消息的新 out_of_range 对象 (公开成员函数)
operator= | 替换 out_of_range 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::out_of_range::out_of_range

out_of_range( const std::string & what_arg ); | (1) |
out_of_range( const char* what_arg ); | (2) | (C++11 起)
 | (3) |
out_of_range( const out_of_range& other ); |  |  | (C++11 前)
out_of_range( const out_of_range& other ) noexcept; |  |  | (C++11 起)
1-2) 构造以 what_arg 为解释字符串的异常对象，解释字符串能通过 what() 访问。
3) 复制构造函数。若 *this 与 other 均拥有动态类型 std::out_of_range 则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

what_arg | - | 解释字符串
other | - | 要复制的另一异常对象

异常

1-2) 可能抛出 std::bad_alloc

注解

因为不容许复制 std::out_of_range 抛出异常，通常将此消息在内部存储为分离分配的引用计数字符串。这也是构造函数不接收 std::string&& 参数的理由：无论如何它必须复制内容。

std::out_of_range::operator=

out_of_range& operator=( const out_of_range& other ); | (C++11 前)
out_of_range& operator=( const out_of_range& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::out_of_range 则赋值后 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 用以赋值的另一异常对象

返回值

*this

std::out_of_range::what

virtual const char* what() const throw(); | (C++11 前)
virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::logic_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

注解

标准错误条件 std::errc::result_out_of_range 典型地指示结果而非输入在范围外的条件，而且与 std::range_error 及 ERANGE 关联更紧密。

参阅

at
 访问指定字符，有边界检查
(std::basic_string<CharT,Traits,Allocator> 的公开成员函数)


std::overflow_error

< cpp‎ | error
定义于头文件 <stdexcept>
class overflow_error;

定义作为异常抛出的对象类型。它能用于报告算术上溢错误（即计算结果对目标类型过大的情形）。

仅有的抛此异常的标准库组件是 std::bitset::to_ulong 和 std::bitset::to_ullong 。

标准库组件的数学函数不抛此异常（数学函数按指定于 math_errhandling 的方式报告上溢错误）。然而第三方库使用它。例如，若启用 boost::math::policies::throw_on_error （默认设置），则 boost.math 抛出 std::overflow_error 。

cpp/error/exception cpp/error/runtime error

继承图

成员函数

(构造函数) | 构造拥有给定消息的新 overflow_error 对象 (公开成员函数)
operator= | 替换 overflow_error 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::overflow_error::overflow_error

overflow_error( const std::string & what_arg ); | (1) |
overflow_error( const char* what_arg ); | (2) | (C++11 起)
 | (3) |
overflow_error( const overflow_error& other ); |  |  | (C++11 前)
overflow_error( const overflow_error& other ) noexcept; |  |  | (C++11 起)
1-2) 构造以 what_arg 为解释字符串的异常对象，解释字符串能通过 what() 访问。
3) 复制构造函数。若 *this 与 other 均拥有动态类型 std::overflow_error 则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

what_arg | - | 解释字符串
other | - | 要复制的另一异常对象

异常

1-2) 可能抛出 std::bad_alloc

注解

因为不容许复制 std::overflow_error 抛出异常，通常将此消息在内部存储为分离分配的引用计数字符串。这也是构造函数不接收 std::string&& 参数的理由：无论如何它必须复制内容。

std::overflow_error::operator=

overflow_error& operator=( const overflow_error& other ); | (C++11 前)
overflow_error& operator=( const overflow_error& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::overflow_error 则赋值后 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 用以赋值的另一异常对象

返回值

*this

std::overflow_error::what

virtual const char* what() const throw(); | (C++11 前)
virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::runtime_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)


std::range_error

< cpp‎ | error
定义于头文件 <stdexcept>
class range_error;

定义作为异常抛出的对象类型。它能用于报告值域错误（即计算结果不能以目标类型表示的情形）。

仅有的抛出此异常的标准库组件是 std::wstring_convert::from_bytes 和 std::wstring_convert::to_bytes 。

标准库组件中的数学函数不抛此异常（数学函数报告 math_errhandling 中指定的值域错误）。

cpp/error/exception cpp/error/runtime error

继承图

成员函数

(构造函数) | 构造拥有给定消息的新 range_error 对象 (公开成员函数)
operator= | 替换 range_error 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::range_error::range_error

range_error( const std::string & what_arg ); | (1) |
range_error( const char* what_arg ); | (2) | (C++11 起)
 | (3) |
range_error( const range_error& other ); |  |  | (C++11 前)
range_error( const range_error& other ) noexcept; |  |  | (C++11 起)
1-2) 构造以 what_arg 为解释字符串的异常对象，解释字符串能通过 what() 访问。
3) 复制构造函数。若 *this 与 other 均拥有动态类型 std::range_error 则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

what_arg | - | 解释字符串
other | - | 要复制的另一异常对象

异常

1-2) 可能抛出 std::bad_alloc

注解

因为不容许复制 std::range_error 抛出异常，通常将此消息在内部存储为分离分配的引用计数字符串。这也是构造函数不接收 std::string&& 参数的理由：无论如何它必须复制内容。

std::range_error::operator=

range_error& operator=( const range_error& other ); | (C++11 前)
range_error& operator=( const range_error& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::range_error 则赋值后 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 用以赋值的另一异常对象

返回值

*this

std::range_error::what

virtual const char* what() const throw(); | (C++11 前)
virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::runtime_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)


std::rethrow_exception

< cpp‎ | error
定义于头文件 <exception> |
[[noreturn]] void rethrow_exception( std::exception_ptr p ); | (C++11 起)

抛出异常指针 p 所引用的先前捕获的异常对象，或其副本。

是否创建副本是未指定的。若创建副本，则以未指定的方式分配其存储。

若 p 为空则行为未定义。

参数

p - 非空 std::exception_ptr

返回值

（无）

异常

若不创建副本，则为 p 所引用的异常对象。

否则，若实现成功复制异常对象，则为这种异常对象的副本。

否则，若分配或复制失败，则分别为 std::bad_alloc 或复制异常对象时抛出的异常。

注解

在 P1675R2 前， rethrow_exception 未被允许复制异常对象，这在一些异常对象分配在栈上的平台上无法实现。

示例

#include <iostream>
#include <string>
#include <exception>
#include <stdexcept>

void handle_eptr(std::exception_ptr eptr) // 按值传递 ok
{
    try {
        if (eptr) {
            std::rethrow_exception(eptr);
        }
    } catch(const std::exception& e) {
        std::cout << "Caught exception \"" << e.what() << "\"\n";
    }
}

int main()
{
    std::exception_ptr eptr;
    try {
        std::string().at(1); // 这生成一个 std::out_of_range
    } catch(...) {
        eptr = std::current_exception(); // 捕获
    }
    handle_eptr(eptr);
} // std::out_of_range 的析构函数调用于此，在 ept 析构时

输出：

Caught exception "basic_string::at"

参阅

exception_ptr (C++11) | 用于处理异常对象的共享指针类型 (typedef)
current_exception (C++11) | 捕获当前异常到 std::exception_ptr 之中 (函数)


std::rethrow_if_nested

< cpp‎ | error
定义于头文件 <exception> |
template< class E > void rethrow_if_nested( const E& e ); | (C++11 起)

若 E 不是多态类类型，或若 std::nested_exception 是 E 的不可访问或有歧义基类，则无效果。

否则，进行

if (auto p = dynamic_cast<const std::nested_exception*>(std::addressof(e)))
    p->rethrow_nested();

参数

e - 要重抛的异常对象

返回值

（无）

可能的实现

namespace details {
    template <class E>
    struct can_dynamic_cast
        : std::integral_constant<bool,
              std::is_polymorphic<E>::value &&
              (!std::is_base_of<std::nested_exception, E>::value ||
                std::is_convertible<E*, std::nested_exception*>::value)
          > { };

    template <class T>
    void rethrow_if_nested_impl(const T& e, std::true_type)
    {
        if(auto nep = dynamic_cast<const std::nested_exception*>(std::addressof(e)))
            nep->rethrow_nested();
    }

    template <class T>
    void rethrow_if_nested_impl(const T&, std::false_type) { }
}

template <class T>
void rethrow_if_nested(const T& t){
    details::rethrow_if_nested_impl(t, details::can_dynamic_cast<T>());
}

示例

演示构造并通过 nested_exception 对象递归

#include <iostream>
#include <stdexcept>
#include <exception>
#include <string>
#include <fstream>

// 打印异常的解释性字符串。若异常内嵌，则递归打印其保有的异常的解释
void print_exception(const std::exception& e, int level =  0)
{
    std::cerr << std::string(level, ' ') << "exception: " << e.what() << '\n';
    try {
        std::rethrow_if_nested(e);
    } catch(const std::exception& e) {
        print_exception(e, level+1);
    } catch(...) {}
}

// 示例函数，捕捉异常并将其包装于 nested_exception
void open_file(const std::string& s)
{
    try {
        std::ifstream file(s);
        file.exceptions(std::ios_base::failbit);
    } catch(...) {
        std::throw_with_nested( std::runtime_error("Couldn't open " + s) );
    }
}

// 示例函数，捕捉异常并将其包装于 nested_exception
void run()
{
    try {
        open_file("nonexistent.file");
    } catch(...) {
        std::throw_with_nested( std::runtime_error("run() failed") );
    }
}

// 运行上述实例函数并打印捕捉的异常
int main()
{
    try {
        run();
    } catch(const std::exception& e) {
        print_exception(e);
    }
}

输出：

exception: run() failed
 exception: Couldn't open nonexistent.file
  exception: basic_ios::clear

参阅

nested_exception (C++11) | 用于捕获并存储当前异常的混入类型 (类)
throw_with_nested (C++11) | 抛出实参，带上混入的 std::nested_exception (函数模板)


std::runtime_error

< cpp‎ | error
定义于头文件 <stdexcept>
class runtime_error;

定义作为异常抛出的对象类型。它报告源于程序作用域外，且不能轻易预测到的错误。

下列标准库组建抛出 std::runtime_error 类型异常： std::locale::locale 及 std::locale::combine 。

另外，标准异常类型 std::range_error 、 std::overflow_error 、 std::underflow_error 、 std::regex_error 及 std::system_error 派生自 std::runtime_error 。

cpp/error/exception

继承图

成员函数

(构造函数) | 构造拥有给定消息的新 runtime_error 对象 (公开成员函数)
operator= | 替换 runtime_error 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::runtime_error::runtime_error

runtime_error( const std::string & what_arg ); | (1) |
runtime_error( const char* what_arg ); | (2) | (C++11 起)
 | (3) |
runtime_error( const runtime_error& other ); |  |  | (C++11 前)
runtime_error( const runtime_error& other ) noexcept; |  |  | (C++11 起)
1-2) 构造以 what_arg 为解释字符串的异常对象，解释字符串能通过 what() 访问。
3) 复制构造函数。若 *this 与 other 均拥有动态类型 std::runtime_error 则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

what_arg | - | 解释字符串
other | - | 要复制的另一异常对象

异常

1-2) 可能抛出 std::bad_alloc

注解

因为不容许复制 std::runtime_error 抛出异常，通常将此消息在内部存储为分离分配的引用计数字符串。这也是构造函数不接收 std::string&& 参数的理由：无论如何它必须复制内容。

std::runtime_error::operator=

runtime_error& operator=( const runtime_error& other ); | (C++11 前)
runtime_error& operator=( const runtime_error& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::runtime_error 则赋值后 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 用以赋值的另一异常对象

返回值

*this

std::runtime_error::what

virtual const char* what() const throw(); | (C++11 前)
virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)


std::set_terminate

< cpp‎ | error
定义于头文件 <exception> |
std::terminate_handler set_terminate( std::terminate_handler f ) throw(); | (C++11 前)
std::terminate_handler set_terminate( std::terminate_handler f ) noexcept; | (C++11 起)

令 f 为新的全局 terminate_handler 函数并返回先前安装的 std::terminate_handler 。

此函数是线程安全的。每个对 std::set_terminate 的调用同步于（见 std::memory_order ）后继的 std::set_terminate 与 std::get_terminate

 (C++11 起)

参数

f - 指向 std::terminate_handler 类型函数的指针，或空指针

返回值

之前安装的 terminate_handler ，或若未安装则为空指针值。

示例

#include <iostream>
#include <cstdlib>
#include <exception>

int main()
{
    std::set_terminate([](){ std::cout << "Unhandled exception\n"; std::abort();});
    throw 1;
}

可能的输出：

Unhandled exception
bash: line 7:  7743 Aborted                 (core dumped) ./a.out

参阅

terminate | 异常处理失败时调用的函数 (函数)
get_terminate (C++11) | 获得当前的 terminate_handler (函数)
terminate_handler | std::terminate 所调用的函数类型 (typedef)


std::system_category

< cpp‎ | error
定义于头文件 <system_error> |
const std::error_category & system_category() noexcept; | (C++11 起)

获得到为操作系统报告错误而设的静态错误类别对象的引用。要求对象覆写虚函数 std::error_category::name() 以返回指向字符串 "system" 的指针。亦要求重写虚函数 std::error_category::default_error_condition() 以映射匹配 POSIX errno 值的 error_code 到 std::generic_category 。

参数

（无）

返回值

到从 std::error_category 派生的未指定运行时类型的静态对象的引用。

示例

#include <iostream>
#include <system_error>
#include <iomanip>
#include <string>

int main()
{
    std::error_condition econd = std::system_category().default_error_condition(EDOM);
    std::cout << "Category: " << econd.category().name() << '\n'
              << "Value: " << econd.value() << '\n'
              << "Message: " << econd.message() << '\n';

    econd = std::system_category().default_error_condition(10001);
    std::cout << "Category: " << econd.category().name() << '\n'
              << "Value: " << econd.value() << '\n'
              << "Message: " << econd.message() << '\n';
}

可能的输出：

Category: generic
Value: 33
Message: Numerical argument out of domain
Category: system
Value: 10001
Message: Unknown error 10001

参阅

generic_category (C++11) | 鉴别通用错误类别 (函数)
errc (C++11) | 列出所有标准 <cerrno> 宏常量的 std::error_condition 枚举 (类)


std::system_error

< cpp‎ | error
定义于头文件 <system_error> |
class system_error; | (C++11 起)

std::system_error 是多种库函数（通常是与 OS 设施交接的函数，例如 std::thread 的构造函数）在拥有关联于该异常的 std::error_code 时抛出的异常类型，同时可能报告该 std::error_code 。

cpp/error/exception cpp/error/runtime error

继承图

成员函数

(构造函数) | 构造 system_error 对象 (公开成员函数)
operator= | 替换 system_error 对象 (公开成员函数)
code | 返回错误码 (公开成员函数)
what [虚] | 返回解释性字符串 (虚公开成员函数)

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

示例

#include <thread>
#include <iostream>
#include <system_error>

int main()
{
    try {
        std::thread().detach(); // 试图脱附一个非线程
    } catch(const std::system_error& e) {
        std::cout << "Caught system_error with code " << e.code()
                  << " meaning " << e.what() << '\n';
    }
}

输出：

Caught system_error with code generic:22 meaning Invalid argument


std::system_error::code

< cpp‎ | error‎ | system error
const std::error_code & code() const noexcept; | (C++11 起)

返回存储的错误码。

参数

（无）

返回值

存储的错误码

参阅

what
[虚]
 返回解释性字符串
(虚公开成员函数)


std::system_error::operator=

< cpp‎ | error‎ | system error
system_error& operator=( const system_error& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 赋值后*this 与 other 均拥有动态类型 std::system_error 则 std::strcmp (what(), other.what()) == 0 。

参数

other - 用以赋值的另一 system_error 对象

返回值

*this

示例

本节未完成
原因：暂无示例


std::system_error::system_error

< cpp‎ | error‎ | system error
system_error( std::error_code ec );
 (1) (C++11 起)
system_error( std::error_code ec, const std::string & what_arg );
 (2) (C++11 起)
system_error( std::error_code ec, const char* what_arg );
 (2) (C++11 起)
system_error( int ev, const std::error_category & ecat );
 (3) (C++11 起)
system_error( int ev, const std::error_category & ecat,
const std::string & what_arg );
 (4) (C++11 起)
system_error( int ev, const std::error_category & ecat,
const char* what_arg );
 (4) (C++11 起)
system_error( const system_error& other ) noexcept;
 (5) (C++11 起)

构造新的 system_error 对象。

1) 以 error_code ec 构造
2) 以 error_code ec 和解释字符串 what_arg 构造。 what() 返回的字符串保证含有 what_arg 。
3) 以底层错误码 ev 和关联的 error_category ecat 构造。
4) 以底层错误码 ev 、关联的 error_category ecat 和解释字符串 what_arg 构造。 what() 返回的字符串保证含有 what_arg （假定它不含内嵌的空字符 ）。
5) 复制构造函数。以 other 的内容初始化内容。若 *this 与 other 均拥有动态类型 std::system_error 则 std::strcmp (what(), other.what()) == 0 。

参数

ec | - | 错误码
ev | - | 基础编码的错误码
ecat | - | 错误类别
what_arg | - | 解释性字符串

示例

演示如何从 errno 值创建 system_error 异常

#include <iostream>
#include <system_error>

int main()
{
    try
    {
        throw std::system_error(EDOM, std::generic_category());
    }
    catch (const std::system_error& error)
    {
        std::cout << "Error: " << error.code()
                  << " - " << error.code().message() << '\n';
    }
}

可能的输出：

Error: generic:33 - Numerical argument out of domain


std::system_error::what

< cpp‎ | error‎ | system error
virtual const char* what() const noexcept; | (C++11 起)

返回解释性字符串。

参数

（无）

返回值

指向拥有解释性信息的空终止字符串的指针。

参阅

code
 返回错误码
(公开成员函数)


std::terminate

< cpp‎ | error
定义于头文件 <exception> |
void terminate(); | (C++11 前)
[[noreturn]] void terminate() noexcept; | (C++11 起)

C++ 运行时在程序因任何下列原因不能继续时调用 std::terminate() ：

1) 未捕捉抛出的异常（此情况下是否进行任何栈回溯是实现定义的）
2) 在处理仍未经由异常捕捉的异常时（例如由某局部对象的析构函数，或构造 catch 子句参数的复制构造函数抛出），由异常处理机制所直接调用
3) 静态或线程局域 (C++11 起)对象的构造函数或析构函数抛出异常
4) 以 std::atexit 或 std::at_quick_exit (C++11 起)注册的函数抛出异常
5) 违反动态异常说明，并执行了 std::unexpected 的默认处理函数
6) std::unexpected 的非默认处理函数抛出了违背先前所违背动态异常规定的异常，若这种规定不包含 std::bad_exception
 (C++17 前)
7) 违反 noexcept 说明（此情况下是否进行任何栈回溯是实现定义的）
8) 为一个不保有被捕获异常的对象调用 std::nested_exception::rethrow_nested
9) 从 std::thread 的起始函数抛出异常
10) 可结合的 std::thread 被析构或赋值
11) std::condition_variable::wait、 std::condition_variable::wait_until 或 std::condition_variable::wait_for 无法达成其前条件（例如若重锁定互斥抛出）
 (C++11 起)
12) 并行算法所调用的函数经由未捕捉异常退出，且该执行策略指定了终止。
 (C++17 起)

亦可直接从程序调用 std::terminate() 。

任何情况下， std::terminate 调用当前安装的 std::terminate_handler 。默认的 std::terminate_handler 调用 std::abort 。

若析构函数在栈回溯时重设 terminate_handler ，且后面的回溯导致调用 terminate ，则在 throw 表达式的结尾安装的处理函数会得到调用。（注意：重抛出是否应用新处理函数是有歧义的） | (C++11 前)
若析构函数在栈回溯时重设 terminate_handler ，则若后面的栈回溯导致调用 terminate ，调用哪个处理函数是未指定的。 | (C++11 起)

参数

（无）

返回值

（无）

注解

若不想要处理函数机制，例如因为它要求可能增加二进制大小的原子操作，则在非正常终止程序时直接调用 std::abort 更适合。

某些编译器内建子程序，例如 __builtin_trap （ gcc、 clang 及 icc ）或 __debugbreak （ msvc ），能用于尽可能快地终止程序。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2111 | C++11 | 在栈回溯期间调用 set_terminate 的效果异于 C++98 并破坏一些 ABI | 令它未指定

参阅

terminate_handler | std::terminate 所调用的函数类型 (typedef)
abort | 导致非正常的程序终止（不进行清理） (函数)


std::terminate_handler

< cpp‎ | error
定义于头文件 <exception>
typedef void (*terminate_handler)();

std::terminate_handler 是函数指针类型（指向不接收参数且返回 void 的函数），这些函数为 std::set_terminate 安装，为 std::get_terminate 查询，并为 std::terminate 调用。

C++ 实现提供默认的 std::terminate_handler 函数，它调用 std::abort () 。若安装空指针值（以 std::set_terminate 的手段），则实现可以恢复默认安装的处理函数。

参阅

terminate | 异常处理失败时调用的函数 (函数)
set_terminate | 更改将被 std::terminate 调用的函数 (函数)
get_terminate (C++11) | 获得当前的 terminate_handler (函数)


std::throw_with_nested

< cpp‎ | error
定义于头文件 <exception> |
template< class T > [[noreturn]] void throw_with_nested( T&& t ); | (C++11 起)

若 std::decay <T>::type 是非 final 、非 union 、既非 std::nested_exception 亦非从 std::nested_exception 派生的类类型，则抛出一个从 std::nested_exception 和 std::decay <T>::type 两者公开派生的未指定类型的异常，从 std::forward <T>(t) 构造。 nested_exception 基类的默认构造函数调用 std::current_exception ，于一个 std::exception_ptr 捕获当前处理的异常对象，若它存在。

否则抛出 std::forward <T>(t) 。

要求 std::decay <T>::type 为可复制构造 (CopyConstructible) 。

参数

t - 要抛出的异常对象

返回值

（无）

示例

演示构造并通过 nested_exception 对象递归

#include <iostream>
#include <stdexcept>
#include <exception>
#include <string>
#include <fstream>

// 打印异常的解释性字符串。若异常内嵌，则递归打印其保有的异常的解释
void print_exception(const std::exception& e, int level =  0)
{
    std::cerr << std::string(level, ' ') << "exception: " << e.what() << '\n';
    try {
        std::rethrow_if_nested(e);
    } catch(const std::exception& e) {
        print_exception(e, level+1);
    } catch(...) {}
}

// 示例函数，捕捉异常并将其包装于 nested_exception
void open_file(const std::string& s)
{
    try {
        std::ifstream file(s);
        file.exceptions(std::ios_base::failbit);
    } catch(...) {
        std::throw_with_nested( std::runtime_error("Couldn't open " + s) );
    }
}

// 示例函数，捕捉异常并将其包装于 nested_exception
void run()
{
    try {
        open_file("nonexistent.file");
    } catch(...) {
        std::throw_with_nested( std::runtime_error("run() failed") );
    }
}

// 运行上述实例函数并打印捕捉的异常
int main()
{
    try {
        run();
    } catch(const std::exception& e) {
        print_exception(e);
    }
}

输出：

exception: run() failed
 exception: Couldn't open nonexistent.file
  exception: basic_ios::clear

参阅

nested_exception (C++11) | 用于捕获并存储当前异常的混入类型 (类)
rethrow_if_nested (C++11) | 抛出 std::nested_exception 中的异常 (函数模板)


std::tx_exception

< cpp‎ | error
定义于头文件 <stdexcept> |
template< class T > class tx_exception : public std::runtime_error ; | (TM TS)

定义能用于取消并回滚关键词 atomic_cancel 所初始化的原子事务的异常类型。

若 T 非可平凡复制 (TriviallyCopyable) ，则特化 std::tx_exception<T> 的程序为谬构。

成员函数

std::tx_exception::tx_exception

explicit tx_exception( T value ) transaction_safe; | (1) | (TM TS)
tx_exception( T value, const std::string & what_arg ) transaction_safe; | (2) | (TM TS)
tx_exception( T value, const char* what_arg ) transaction_safe; | (3) | (TM TS)
tx_exception( const tx_exception& other ) transaction_safe noexcept; | (4) | (TM TS)
1-3) 以 what_arg 为能通过 what() 访问的解释性字符串并以 value 为能通过 get() 访问的对象构造异常对象。
4) 复制构造函数。若 *this 与 other 均拥有动态类型 std::tx_exception<T> 则 std::strcmp (what(), other.what()) == 0 。

参数

value | - | 载荷对象
what_arg | - | 解释字符串
other | - | 要复制的另一字符串

异常

1-3) 可能抛出实现定义的异常。

std::tx_exception::operator=

tx_exception& operator=( const tx_exception& other ) transaction_safe noexcept; | (TM TS)

以 other 的内容赋值内容。若 *this 与 other 均拥有动态类型 std::tx_exception<T> 则赋值后 std::strcmp (what(), other.what()) == 0 。

参数

other - 用以赋值的另一异常对象

返回值

*this

std::tx_exception::get

T get() const transaction_safe; | (TM TS)

返回异常对象保有的载荷对象。

异常

可能抛出实现定义的异常。

std::tx_exception::what

virtual const char* what() const transaction_safe_dynamic noexcept; | (TM TS)

返回解释字符串。

参数

（无）

返回值

指向拥有解释信息的空中止字符串的指针。

继承自 std::runtime_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)


std::underflow_error

< cpp‎ | error
定义于头文件 <stdexcept>
class underflow_error;

定义作为异常抛出的类型。它可用于报告算术下溢错误（即计算结果是非正规浮点值的情形）。

标准库组建不抛此异常（数学函数按指定于 math_errhandling 的方式报告下溢错误）。然而第三方库使用它。例如，若启用了 boost::math::policies::throw_on_error （默认设置），则 boost.math 抛出 std::underflow_error 。

cpp/error/exception cpp/error/runtime error

继承图

成员函数

(构造函数) | 构造拥有给定消息的新 underflow_error 对象 (公开成员函数)
operator= | 替换 underflow_error 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::underflow_error::underflow_error

underflow_error( const std::string & what_arg ); | (1) |
underflow_error( const char* what_arg ); | (2) | (C++11 起)
 | (3) |
underflow_error( const underflow_error& other ); |  |  | (C++11 前)
underflow_error( const underflow_error& other ) noexcept; |  |  | (C++11 起)
1-2) 构造以 what_arg 为解释字符串的异常对象，解释字符串能通过 what() 访问。
3) 复制构造函数。若 *this 与 other 均拥有动态类型 std::underflow_error 则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

what_arg | - | 解释字符串
other | - | 要复制的另一异常对象

异常

1-2) 可能抛出 std::bad_alloc

注解

因为不容许复制 std::underflow_error 抛出异常，通常将此消息在内部存储为分离分配的引用计数字符串。这也是构造函数不接收 std::string&& 参数的理由：无论如何它必须复制内容。

std::underflow_error::operator=

underflow_error& operator=( const underflow_error& other ); | (C++11 前)
underflow_error& operator=( const underflow_error& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::underflow_error 则赋值后 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 用以赋值的另一异常对象

返回值

*this

std::underflow_error::what

virtual const char* what() const throw(); | (C++11 前)
virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::runtime_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)


实验性 C++ 特性

< cpp

C++ 标准委员会为未来的标准化出版实验性 C++ 语言与库扩展。

注意： 2012 之前，这些出版使用 TR （技术报告）格式。从 2012 起， ISO 手续改为使用 TS （技术规范）格式。

ISO 编号 | 名称 | 状态 | 链接
ISO/IEC TR 18015:2006 | C++ 性能上的技术报告 | 出版于 2006 （ ISO 商店） 草案： TR18015 (2006-02-15) 。 |
ISO/IEC TR 19768:2007 | C++ 库扩展上的技术报告 | 出版于 2007-11-15 （ ISO 商店） 草案： n1836 (2005-06-24) 。 分离到 ISO 29124 ，剩下的并入 C++11 。 |
ISO/IEC 29124:2010 | 对 C++ 库的支持数学特殊函数的扩展 | 出版于 2010-09-03 （ ISO 商店） 最终草案： n3060 (2010-03-06) 。 ✔ 并入 C++17 。 | 特殊函数
ISO/IEC TR 24733:2011 | 对编程语言 C++ 的支持十进制浮点算术的扩展 | 出版于 2011-10-25 （ ISO 商店）。草案： n2849 (2009-03-06) 。 可能会为将来的 TS 所取代或并入未来的 C++ 修订版（最近的合并提案为 n3871 ） |
ISO/IEC TS 18822:2015 | C++ 文件系统技术规范 | 出版于 2015-06-18 （ ISO 商店）。最终草案： n4100 (2014-07-04) 。 并入 C++17 。 | 文件系统
ISO/IEC TS 19570:2015 | 并行的 C++ 扩展 | 出版于 2015-06-24 （ ISO 商店）。最终草案： n4507 (2015-05-05) 。 ✔并入 C++17 。 | 并行
ISO/IEC TS 19841:2015 | 事务性内存 TS | 出版于 2015-09-16 （ ISO 商店）。最终草案： n4514 (2015-05-08) 。 | 事务性内存
ISO/IEC TS 19568:2015 | 库基础的 C++ 扩展 | 出版于 2015-09-30 （ ISO 商店）。最终草案： n4480 (2015-04-07) 。 ✔并入 C++17 ，除了调用特征。 | 库扩展
ISO/IEC TS 19217:2015 | 概念的 C++ 扩展 | 出版于 2015-11-13 （ 商店）。最终草案： n4553 (2015-10-02) 当前草案： p0734r0 (2017-07-14) 。 ✔ 并入 C++20 （有修改）。 | 约束与概念
ISO/IEC TS 19571:2016 | 并发的 C++ 扩展 | 出版于 2016-01-19 （ ISO 商店）。最终草案： p0159r0 (2015-10-22) 。 ✔部分并入 C++20 。 | 并发
ISO/IEC TS 19568:2017 | 库基础的 C++ 扩展，版本 2 | 出版于 2017-03-30 （ ISO 商店）。草案： n4617 (2016-11-28) 。 ✔部分并入 C++17 与 C++20 。 | 库扩展 2
ISO/IEC TS 21425:2017 | 范围 TS | 出版于 2017-12-05 （ ISO 商店）。草案： n4685 (2017-07-31) 。 ✔ 并入 C++20 。 | 范围
ISO/IEC TS 22277:2017 | 协程 TS | 出版于 2017-12-05 （ ISO 商店）。草案： n4736 (2018-03-31) ，最新草案： n4775 (2018-10-07) 。 ✔ 并入 C++20 。 |
ISO/IEC TS 19216:2018 | 网络 TS | 出版于 2018-04-24 （ ISO 商店）。草案： n4734 (2017-04-04) 。最终草案 n4771 (2018-10-08) 。 | 网络
ISO/IEC TS 21544:2018 | 模块 TS | 出版于 2018-05-16 （ ISO 商店）。最终草案： n4720 (2018-01-29) ✔ 并入 C++20 （有修改）。 |
ISO/IEC TS 19570:2018 | 并行 TS 版本 2 | 出版于 2018-11-15 （ ISO 商店）。最终草案： n4793 (2018-11-26) 。 | 并行 2
ISO/IEC TS 23619 | 反射 TS | 出版于 2021-10-11 （ ISO 商店）。草案 n4856 (2020-03-02) 。替代草案 p1240r1 (2019-10-03) 。 | 反射
 | 数值 | 早期开发。草案 p1889r1 (2019-12-27) 。 |
ISO/IEC NP 19571 | 并发 TS 版本 2 | 早期开发。草案 n4895 (2021-08-15) 。 | 并发 2
ISO/IEC AWI TS 19568 | 库基础的 C++ 扩展，版本 3 | 早期开发： n4873 (2020-11-09) 。 | 库扩展 3
ISO/IEC NP 19841 | 最小事务性内存 TS | 早期开发： p2066r8 (2021-07-15) 。 |
 | 模式匹配 | 早期开发。草案 p1371r3 (2020-09-15) 。 |
 | 线性代数 | 早期开发。草案 p1385r6 (2020-03-01) 与 p1673r4 (2021-08-15) 。 |
 | 2D 图形 | 早期开发。草案 p0267r10 (2019-10-07) 。 |
ISO/IEC NP 19569 | 数组扩展 TS | ×撤销。废弃草案： n3820 (2013-10-10) 。 |

参阅


std::experimental::barrier

< cpp‎ | experimental
定义于头文件 <experimental/barrier> |
class barrier; | (并发 TS)

类 std::experimental::barrier 提供线程协调机制，它允许参与线程阻塞直至操作完成。不同于 std::experimental::latch ，屏障可重用；一旦从屏障的同步点释放参与线程，则线程能重用同一屏障。

屏障拥有完成阶段，一旦参与线程集中度所有线程到达同步点，则参与线程之一执行完成阶段。 arrive_and_wait 和 arrive_and_drop 的调用同步于完成阶段的起始；完成阶段的结束同步于从其完成所阻塞的所有调用返回。

对于 std::experimental::barrier ，完成阶段为空。 std::experimental::flex_barrier 允许用户以函数对象控制完成阶段。

为 num_threads 个线程构造的 barrier 的参与线程集，是在构造后首先到达其同步点的 num_threads 个线程。同一线程集（除了调用了 arrive_and_drop() 的线程）必须在 barrier 的每轮到达。

成员函数

(构造函数) | 构造 barrier (公开成员函数)
(析构函数) | 销毁 barrier (公开成员函数)
operator= [被删除] | 非可复制赋值 (公开成员函数)
arrive_and_wait | 到达同步点并阻塞 (公开成员函数)
arrive_and_drop | 到达同步点，并从参与线程集中移除当前线程 (公开成员函数)


std::experimental::barrier::arrive_and_drop

< cpp‎ | experimental‎ | barrier
void arrive_and_drop(); | (并发 TS)

到达 barrier 的同步点并从参与线程集中移除当前线程。此函数是否阻塞直至完成阶段结束是未指定的。

若调用方线程不在此 barrier 的参与线程集中，则行为未定义。

对 arrive_and_drop 的调用同步于 barrier 的完成阶段的开始。完成阶段的完成同步于从调用返回。

对 arrive_and_drop 和 arrive_and_wait 的调用决不引入与其自身或与彼此间的数据竞争。

异常

不抛出异常。

注意

若每个参与线程都调用 arrive_and_drop() ，则屏障只能被销毁。

一个线程在 barrier 上调用 arrive_and_drop() 后，它就不再是参与线程集的成员，从而不能再于同一 barrier 上调用 arrive_and_drop() 或 arrive_and_wait() 。

参阅

arrive_and_wait
 到达同步点并阻塞
(公开成员函数)


std::experimental::barrier::arrive_and_wait

< cpp‎ | experimental‎ | barrier
void arrive_and_wait(); | (并发 TS)

阻塞并到达屏障的同步点。

若调用方线程不在此 barrier 的参与线程集中，则行为未定义。

对 arrive_and_wait 的调用同步于 barrier 的完成阶段的开始。完成阶段的完成同步于从调用返回。

对 arrive_and_drop 和 arrive_and_wait 的调用决不引入与其自身或与彼此间的数据竞争。

注意

线程立即在从此调用返回时，调用 arrive_and_wait() 或 arrive_and_drop() 是安全的。不需要确保在一个线程再次调用它时，所有线程都已退出 arrive_and_wait() 。

为 num_threads 个线程构造的 barrier 的参与线程集是首 num_threads 个到达其同步点的线程。此集合不在循环间更改，除非线程由于 arrive_and_drop() 调用被移除出集合。

异常

不抛出异常。

参阅

arrive_and_drop
 到达同步点，并从参与线程集中移除当前线程
(公开成员函数)


std::experimental::barrier::barrier

< cpp‎ | experimental‎ | barrier
explicit barrier( std::ptrdiff_t num_threads ); | (1) | (并发 TS)
barrier( const barrier & ) = delete; | (2) | (并发 TS)
1) 构造 num_threads 个参与线程的 barrier 。参与线程的集合是首先到达同步点的 num_threads 个线程。
2) 复制构造函数被删除； barrier 不可复制。

参数

num_threads - 屏障的参与线程数；必须为非负

注意

若 num_threads 为零，则参与线程为空，而 barrier 只能被销毁。


std::experimental::barrier::~barrier

< cpp‎ | experimental‎ | barrier
~barrier(); | (并发 TS)

销毁 barrier 。

若线程在同步点阻塞，则行为未定义。


std::experimental::erase (std::basic_string)

< cpp‎ | experimental

定义于头文件 <experimental/string> |
template <class charT, class traits, class A, class U> void erase( std::basic_string <charT, traits, A>& c, const U& value); | (库基础 TS v2)

从容器擦除所有比较等于 value 的元素。等价于 c.erase(std::remove(c.begin(), c.end(), value), c.end());

参数

c | - | 要从中擦除的容器
value | - | 要移除的值

复杂度

线性。

示例

#include <experimental/string>
#include <iostream>

int main()
{
    std::string data{"$$P$A$S$S$$W$O$R$$D$"};
    std::cout << data << '\n';
    auto crack{'$'};
    std::experimental::erase(data, crack);
    std::cout << data << '\n';
}

输出：

$$P$A$S$S$$W$O$R$$D$
PASSWORD

参阅

removeremove_if | 移除满足特定判别标准的元素 (函数模板)
erase_if(std::basic_string) (库基础 2 TS) | 从 std::basic_string 擦除所有满足谓词的元素 (函数模板)


std::experimental::erase_if (std::basic_string)

< cpp‎ | experimental

定义于头文件 <experimental/string> |
template <..., class Pred> void erase_if( std::basic_string <...>& c, Pred pred); | (库基础 TS v2)

从容器擦除所有满足谓词 pred 的元素。等价于 c.erase( std::remove_if (c.begin(), c.end(), pred), c.end());

参数

c | - | 要从中擦除的容器
pred | - | 确定该擦除哪些元素的谓词

复杂度

线性。

示例

#include <experimental/string>
#include <iostream>

int main()
{
    std::string data { "1337!p_C00L_<a-_HACKER_!@s_{!s#@_w^o%r*d#42" };

    std::cout << "Original: \n\"" << data << "\"\n";

    auto crack = [](auto O) { return O < 0141 or 0172 < O; };

    std::experimental::erase_if(data, crack);

    std::cout << "After erase_if: \n\"" << data << "\"\n";
}

输出：

Original:
"1337!p_C00L_<a-_HACKER_!@s_{!s#@_w^o%r*d#42"
After erase_if:
"password"

参阅

removeremove_if | 移除满足特定判别标准的元素 (函数模板)
erase(std::basic_string) (库基础 2 TS) | 从 std::basic_string 擦除所有等于特定值的元素 (函数模板)


并发扩展

< cpp‎ | experimental

C++ 并发扩展 (C++ Extensions for Concurrency) ， ISO/IEC TS 19571:2016 ，为 C++ 标准库定义下列新组件：

std::future 的持续及其他扩展

定义于头文件 <experimental/future>
future (并发 TS) | 以持续和其他特性增强的 std::future 版本 (类模板)
shared_future (并发 TS) | 以持续和其他特性增强的 std::shared_future 版本 (类模板)
promise (并发 TS) | 使用 std::experimental::future 的 std::promise 修改版本 (类模板)
packaged_task (并发 TS) | 使用 std::experimental::future 的 std::packaged_task 修改版本 (类模板)
when_all (并发 TS) | 产生在所有给定 furure 或 shared_future 均就绪时成为就绪的 future (函数模板)
when_any (并发 TS) | 产生在至少一个给定 future 或 shared_future 就绪时成为就绪的 future (函数模板)
make_ready_future (并发 TS) | 产生立即就绪并保有指定值的 future (函数模板)
make_exceptional_future (并发 TS) | 产生立即就绪并保有给定异常的 future (函数模板)

特性测试宏

定义于头文件 <experimental/future>
__cpp_lib_experimental_future_continuations | 至少为 201505 的值，指示支持 future::then 和其他扩展 (宏常量)
定义于头文件 <experimental/latch>
__cpp_lib_experimental_latch | 至少为 201505 的值，指示支持 latch 类型 (宏常量)
定义于头文件 <experimental/barrier>
__cpp_lib_experimental_barrier | 至少为 201505 的值，指示支持 barrier 类型 (宏常量)
定义于头文件 <experimental/atomic>
__cpp_lib_experimental_atomic_smart_pointers | 至少为 201505 的值，指示支持原子智能指针 (宏常量)

并入 C++20

并发 TS 的下列组件已并入 C++20 标准。

闩和屏障

定义于头文件 <experimental/latch>
latch (并发 TS) | 单次使用的线程屏障 (类)
定义于头文件 <experimental/barrier>
barrier (并发 TS) | 可复用线程屏障 (类)
flex_barrier (并发 TS) | 带有在完成时的可定制行为的可复用线程屏障 (类)

原子智能指针

这些类模板替换 shared_ptr 的原子函数重载

定义于头文件 <experimental/atomic>
atomic_shared_ptr (并发 TS) | std::shared_ptr 的原子版本 (类模板)
atomic_weak_ptr (并发 TS) | std::weak_ptr 的原子版本 (类模板)


std::experimental::packaged_task (并发 TS)

< cpp‎ | experimental‎ | concurrency

此页面提及并发 TS 所提供的支持该 TS 所改进的 std::future 的 std::packaged_task 修改版本。库基础 TS 所提供的支持类型擦除分配器的 packaged_task 版本，见 std::experimental::fundamentals_v2::packaged_task 。

定义于头文件 <experimental/future> |  |
template< class > class packaged_task; // 不定义 | (1) | (并发 TS)
template< class R, class ...Args > class packaged_task<R(Args...)>; | (2) | (并发 TS)

std::experimental::concurrency_v1::packaged_task 是并发 TS 所提供的 std::packaged_task 修改版本，运用 std::experimental::future 。

其相对于 std::packaged_task 的唯一更改是 get_future() 成员函数返回 std::experimental::future<R> 。


std::experimental::promise (并发 TS)

< cpp‎ | experimental‎ | concurrency

此页面提及并发 TS 所提供的支持该 TS 所改进的 std::future 的 std::promise 版本。库基础 TS 所提供的带类型擦除分配器支持的 promise 修改版本，见 std::experimental::fundamentals_v2::promise 。

定义于头文件 <experimental/future> |  |
template< class R > class promise; | (1) | (并发 TS)
template< class R > class promise<R&>; | (2) | (并发 TS)
template<> class promise<void>; | (3) | (并发 TS)

std::experimental::concurrency_v1::promise 是并发 TS 所提供的 std::promise 修改版本，它运用 std::experimental::future 。

其相对于 std::promise 的唯一更改是 get_future() 返回 std::experimental::future 。


制约与概念

< cpp‎ | experimental

此页面描述实验性的新语言特性。对于用于标准库规范的具名类型要求，见具名要求。

类模板、函数模板及非模板函数（常为类模板成员）可以与制约关联，制约指定模板实参上的要求，这能用于选择最准确的函数重载和模板特化。

制约亦可用于限制变量声明和函数返回类型中的自动类型推导，为只有满足指定要求的类型。

这种要求的具名集合被称为概念。每个概念都是谓词，于编译时求值，并成为模板接口的一部分，它在其中用作制约：

#include <string>
#include <locale>
using namespace std::literals;

// 概念 "EqualityComparable" 的声明，任何有该类型值 a 和 b ，
// 而表达式 a==b 可编译而其结果可转换为 bool 的 T 类型满足它
template<typename T>
concept bool EqualityComparable = requires(T a, T b) {
    { a == b } -> bool;
};

void f(EqualityComparable&&); // 有制约函数模板的声明
// template<typename T>
// void f(T&&) requires EqualityComparable<T>; // 相同的长形式

int main() {
  f("abc"s); // OK ： std::string 为 EqualityComparable
  f(std::use_facet<std::ctype<char>>(std::locale{})); // 错误：非 EqualityComparable
}

在编译时检测制约违规，早于模板实例化处理，这导致错误信息更易理解。

std::list<int> l = {3,-1,10};
std::sort(l.begin(), l.end());
//无概念的典型编译器诊断：
//  invalid operands to binary expression ('std::_List_iterator<int>' and
//  'std::_List_iterator<int>')
//                           std::__lg(__last - __first) * 2);
//                                     ~~~~~~ ^ ~~~~~~~
// …… 50 行输出……
//
//有概念的典型编译器诊断：
//  error: cannot call std::sort with std::_List_iterator<int>
//  note:  concept RandomAccessIterator<std::_List_iterator<int>> was not satisfied

概念的目的是模拟语义类别（ Number 、 Range 、 RegularFunction ）而非语法制约（ HasPlus 、 Array ）。按照 ISO C++ 核心方针 T.20 ，“与语法制约相反，指定有意义语义的能力是真概念的定义性特征。”

占位符

无制约占位符 auto 与拥有形式 concept-name < template-argument-list(optional)> 的有制约占位符，是要被推导的类型的占位符。

占位符可出现于变量声明（该情况下它们从初始化器推导）或于函数返回类型（该情况下它们从 return 语句推导）

std::pair<auto, auto> p2 = std::make_pair(0, 'a'); // 第一个 auto 是 int,
                                                   // 第二个 auto 是 char

Sortable x = f(y); // x 的类型从 f 的返回类型推导，仅若类型满足制约 Sortable 才能编译

auto f(Container) -> Sortable; // 返回类型从 return 语句推导，仅若类型满足 Sortable 才能编译

占位符亦可出现于形参中，该情况下它们将函数声明转化为模板声明（若占位符有制约，则模板声明有制约）

template<size_t N> concept bool Even = (N%2 == 0);
void f(std::array<auto, Even>); // 这是有二个形参的模板：
       // 无制约类型形参和有制约非类型形参

有制约占位符可用于 auto 能用的任何位置，例如在泛型 lambda 声明中

auto gl = [](Assignable& a, auto* b) { a = *b; };

缩写的模板

若函数参数列表中出现一或多个占位符，则函数声明实际上是函数模板声明，其模板形参列表以出现顺序，为每个单独的占位符包含一个虚设的形参

// 短形式
void g1(const EqualityComparable*, Incrementable&);
// 长形式：
// template<EqualityComparable T, Incrementable U> void g1(const T*, U&);
// 更长形式：
// template<typename T, typename U>
// void g1(const T*, U&) requires EqualityComparable<T> && Incrementable<U>;

void f2(std::vector<auto*>...);
// 长形式： template<typename... T> void f2(std::vector<T*>...);

void f4(auto (auto::*)(auto));
// 长形式： template<typename T, typename U, typename V> void f4(T (U::*)(V));

等价的有制约类型指定符所引入的所有占位符拥有同一虚设模板形参。然而，每个无制约指定符（ auto ）始终引入一个相异的模板形参

void f0(Comparable a, Comparable* b);
// 长形式： template<Comparable T> void f0(T a, T* b);

void f1(auto a, auto* b);
// 长形式： template<typename T, typename U> f1(T a, U* b);

函数模板与类模板都能用模板引入声明，它有语法 concept-name { parameter-list(可选)} ，此情况中不需要关键词 template ：来自模板引入的 parameter-list 的每个形参都成为模板形参，其种类（类型、非类型、模板）以具名概念中对应形参的种类确定。

除了声明模板，模板引入关联一个谓词制约（见后述），它指名（对于变量概念）或调用（对于函数概念）该引入所指名的概念。

EqualityComparable{T} class Foo;
// 长形式： template<EqualityComparable T> class Foo;
// 更长形式： template<typename T> requires EqualityComparable<T> class Foo;

template<typename T, int N, typename... Xs> concept bool Example = ...;
Example{A, B, ...C} struct S1;
// 长形式： template<class A, int B, class... C> requires Example<A,B,C...> struct S1;

对于函数模板，模板引入能与占位符组合：

Sortable{T} void f(T, auto);
// 长形式： template<Sortable T, typename U> void f(T, U);
// 另一种只用占位符的形式： void f(Sortable, auto);
本节未完成
原因：润色模板声明页面并链接至此

概念

概念是具名要求集合。概念的定义出现于命名空间作用域，并拥有函数模板定义（该情况下称为函数概念）或变量模板定义（该情况下称为变量概念）的形式。仅有的区别是关键词 concept 出现于 decl-specifier-seq 中：

// 来自标准（范围 TS ）的变量概念
template <class T, class U>
concept bool Derived = std::is_base_of<U, T>::value;

// 来自标准（范围 TS ）的函数概念
template <class T>
concept bool EqualityComparable() {
    return requires(T a, T b) { {a == b} -> Boolean; {a != b} -> Boolean; };
}

下列限制应用于函数概念：

  • 不允许 inline 与 constexpr ，函数自动为 inline 与 constexpr
  • 不允许 friend 与 virtual
  • 不允许异常规定，函数自动为 noexcept(true) 。
  • 不能声明并延迟定义，不能重声明
  • 返回类型必须是 bool
  • 不允许返回类型推导
  • 参数列表必须为空
  • 函数体必须仅由一条 return 语句组成，其参数必须是一条制约表达式（谓词制约、其他制约的合取/析取或 requires 表达式，见后述）

下列限制应用于变量概念：

  • 必须有类型 bool
  • 不能声明为无初始化器
  • 不允许 constexpr ，变量自动为 constexpr
  • 初始化器必须是制约表达式（谓词制约、其他制约的合取/析取或 requires 表达式，见后述）

概念不能在函数体内或变量初始化器内递归地指涉自身：

template<typename T>
concept bool F() { return F<typename T::type>(); } // 错误
template<typename T>
concept bool V = V<T*>; // 错误

概念定义不能有关联的制约。

template<class T> concept bool C1 = true;
template<C1 T>
concept bool Error1 = true; // 错误：C1 T 声明了一个关联的制约
template<class T> requires C1<T>
concept bool Error2 = true; // 错误：requires 子句声明了一个关联的制约

不允许概念的显式实例化、显式特化或部分特化（不能更改制约的原初定义的意义）。

制约

制约是一系列逻辑运算，它指定模板实参上的要求。它们可出现于 requires 表达式（见后述）中，及直接作为概念的体。

制约有 9 种类型：

1) 合取
2) 析取
3) 谓词制约
4) 表达式制约（仅在 requires 表达式中）
5) 类型制约（仅在 requires 表达式中）
6) 隐式转换制约（仅在 requires 表达式中）
7) 实参推导制约（仅在 requires 表达式中）
8) 异常制约（仅在 requires 表达式中）
9) 参数化制约（仅在 requires 表达式中）

前三个类型的制约可以直接作为概念的体，或作为随即的 requires 子句出现：

template<typename T>
requires // requires 子句（随即的制约）
sizeof(T) > 1 && get_value<T>() // 二个谓词制约的合取
void f(T);

附着多个制约到同一声明时，总制约是按下列顺序的合取：模板引入所引入的制约、按出现顺序的每个模板形参的制约、模板形参列表后的 requires 子句、按出现顺序的每个函数参数的制约、尾随的 requires 子句：

// 声明用制约 Incrementable<T> && Decrementable<T> 声明同一有制约函数模板
template<Incrementable T>
void f(T) requires Decrementable<T>;
template<typename T>
requires Incrementable<T> && Decrementable<T>
void f(T); // OK

// 下列二个声明拥有不同制约：
// 第一个声明有 Incrementable<T> && Decrementable<T>
// 第二个声明有 Decrementable<T> && Incrementable<T>
// 尽管它们逻辑等价。
// 第二个声明为病式，不要求诊断。

template<Incrementable T> requires Decrementable<T> void g();
template<Decrementable T> requires Incrementable<T> void g(); // 错误

合取

以 P && Q 指定制约 P 与 Q 的合取。

// 来自标准库（范围 TS）的示例概念
template <class T>
concept bool Integral = std::is_integral<T>::value;
template <class T>
concept bool SignedIntegral = Integral<T> && std::is_signed<T>::value;
template <class T>
concept bool UnsignedIntegral = Integral<T> && !SignedIntegral<T>;

二个制约的合取，仅若二个制约均得到满足才得到满足。合取从左到右且为短路求值（若不满足左侧制约，则不尝试对右侧制约的模板实参替换：这阻止立即语境之外替换导致的失败）。制约合取中不允许用户定义的 operator&& 重载。

析取

以 P || Q 指定制约 P 与 Q 的析取。

若任一制约得到满足，则二个制约的析取的到满足。析取从左到右且为短路求值（若满足左侧制约，则不尝试对右侧制约的模板实参替换）。制约析取中不允许用户定义的 operator|| 重载。

// 来自标准库（范围 TS ）的示例制约
template <class T = void>
requires EqualityComparable<T>() || Same<T, void>
struct equal_to;

谓词制约

谓词制约是 bool 类型的常量表达式。它仅若求值为 true 才得到满足。

template<typename T> concept bool Size32 = sizeof(T) == 4;

谓词制约能指定非类型模板形参上和模板模板实参上的要求。

谓词制约必须直接求值为 bool ，不允许转换：

template<typename T> struct S {
    constexpr explicit operator bool() const { return true; }
};
template<typename T>
requires S<T>{} // 坏的谓词制约： S<T>{} 不是 bool
void f(T);
f(0); // 错误：决不满足制约

要求

关键词 requires 有二种使用方式：

1) 引入 requires 子句，它指定模板实参或函数声明上的制约。
template<typename T>
void f(T&&) requires Eq<T>; // 能作为函数声明器的最末元素出现

template<typename T> requires Addable<T> // 或在模板形参列表之右
T add(T a, T b) { return a + b; }
此情况下，关键词 requires 必须为某个常量表达式所后随（故可以写 "requires true;" ），但其意图是使用具名概念（如上述示例中）或具名概念的合取/析取或 requires 表达式。
2) 开始 requires 表达式，它是 bool 类型纯右值，描述某些模板实参上的制约。若满足对应概念则这种表达式为 true ，否则为 false ：
template<typename T>
concept bool Addable = requires (T x) { x + x; }; // requires 表达式

template<typename T> requires Addable<T> // requires 子句，非 requires 表达式
T add(T a, T b) { return a + b; }

template<typename T>
requires requires (T x) { x + x; } // 随即制约，注意使用二次关键字
T add(T a, T b) { return a + b; }

requires 表达式的语法如下：

requires ( parameter-list(可选) ) { requirement-seq }
parameter-list | - | 逗号分隔列表，如在函数声明中，除了不允许默认参数，且最后的参数不能是省略号。这些参数无存储期、链接或生存期。这些参数在 requirement-seq 的闭 } 前处于作用域中。若不使用参数，则环绕的括号亦可省略
requirement-seq | - | 要求的空白符分隔序列，描述于下（每个要求以分号结尾）。每个要求添加另一制约到此 requires 表达式所定义的制约合取。

requirements-seq 中的每个要求是下列之一：

  • 简单要求
  • 类型要求
  • 复合要求
  • 嵌套要求

要求可以提及在作用域中的模板形参，和于 parameter-list 引入的局部参数。在参数化时，称 requires 表达式引入一个参数化制约。

替换模板实参到至 reqiures 表达式可能导致于其要求中形成非法类型或表达式。这些情况下，

  • 若替换失败出现于用于模板化实体声明之外的 requires 表达式，则程序为病式。
  • 若 requires 表达式用于模板化实体的声明中，则对应的制约被当做“不满足”而替换失败不是错误，然而
  • 若替换失败会在对每个可能模板实参的 requires 表达式中出现，则程序为病式，不要求诊断：
template<class T> concept bool C = requires {
    new int[-(int)sizeof(T)]; // 对每个 T 非法：病式，不要求诊断
};

简单要求

简单要求是任意表达式语句。要求是表达式合法（是为表达式制约）。不同于谓词制约，不发生求值，只检查语言正确性。

template<typename T>
concept bool Addable =
requires (T a, T b) {
    a + b; // “表达式 a + b 是可编译的合法表达式”
};

// 来自标准库（范围 TS ）的示例
template <class T, class U = T>
concept bool Swappable = requires(T&& t, U&& u) {
    swap(std::forward<T>(t), std::forward<U>(u));
    swap(std::forward<U>(u), std::forward<T>(t));
};

类型要求

类型要求是关键词 typename 后随类型名，可选地有限定。要求是该具名类型存在（类型制约）：这可用于校验具体的具名嵌套类型是否存在，或类模板特化是否指名一个类型，或别名模板是否指名一个类型。

template<typename T> using Ref = T&;
template<typename T> concept bool C =
requires {
    typename T::inner; // 要求的嵌套成员名
    typename S<T>;     // 要求的类模板特化
    typename Ref<T>;   // 要求的别名模版替换
};

// 来自标准库（范围 TS ）的示例概念
template <class T, class U> using CommonType = std::common_type_t<T, U>;
template <class T, class U> concept bool Common =
requires (T t, U u) {
    typename CommonType<T, U>; // CommonType<T, U> 合法且指名类型
    { CommonType<T, U>{std::forward<T>(t)} };
    { CommonType<T, U>{std::forward<U>(u)} };
};

复合要求

复合要求拥有形式

{ expression } noexcept(可选) trailing-return-type(可选) ;

并指定下列制约的合取：

1) expression 是合法表达式（表达式制约）
2) 若使用 noexcept ，则表达式必须亦为 noexcept （异常制约）
3) 若 trailing-return-type 指名用占位符的类型，则类型必须可从表达式的类型推导（实参推导制约）
4) 若 trailing-return-type 指名不用占位符的类型，则再添加二个制约：
4a) trailing-return-type 所指名的类型合法（类型制约）
4b) 表达式结果可隐式转换成该类型（隐式转换制约）
template<typename T> concept bool C2 =
requires(T x) {
    {*x} -> typename T::inner; // 表达式 *x 必须合法
                               // AND 类型 T::inner 必须合法
                               // AND *x 的结果必须可转换成 T::inner
};

// 来自标准库（范围 TS ）的示例概念
template <class T, class U> concept bool Same = std::is_same<T,U>::value;
template <class B> concept bool Boolean =
requires(B b1, B b2) {
    { bool(b1) }; // 直接初始化制约必须使用表达式
    { !b1 } -> bool; // 复合制约
    requires Same<decltype(b1 && b2), bool>; // 嵌套制约，见后述
    requires Same<decltype(b1 || b2), bool>;
};

嵌套要求

嵌套要求是另一以分号终止的 requires 子句。它被用于引入谓词制约（见前述），该制约以另一应用到局部参数的具名制约表达（在 requires 子句外，谓词制约不能使用参数，而直接放置表达式于 requires 子句中会令它成为表达式制约，这表示不求值它）。

// 来自范围 TS 的示例制约
template <class T>
concept bool Semiregular = DefaultConstructible<T> &&
    CopyConstructible<T> && Destructible<T> && CopyAssignable<T> &&
requires(T a, size_t n) {
    requires Same<T*, decltype(&a)>;  // 嵌套：“ Same<...> 求值为 true ”
    { a.~T() } noexcept;  // 复合： "a.~T()" 是不抛出的合法表达式
    requires Same<T*, decltype(new T)>; // 嵌套：“ Same<...> 求值为 true ”
    requires Same<T*, decltype(new T[n])>; // 嵌套
    { delete new T };  // 复合
    { delete new T[n] }; // 复合
};

概念决议

类似任何其他函数模板，函数概念（但不是变量概念）能重载：可以提供全部使用同一 concept-name 的多个概念定义。

概念决议在 concept-name （可以有限定）出现于下列语境时进行

1) 有制约类型指定符 void f(Concept); std::vector <Concept> x = ...;
2) 有制约形参 template<Concept T> void f();
3) 模板引入 Concept{T} struct X;
4) 制约表达式 template<typename T> void f() requires Concept<T>;
template<typename T> concept bool C() { return true; } // #1
template<typename T, typename U> concept bool C() { return true; } // #2
void f(C); // C 所指代的制约集包含 #1 和 #2 ；
           // 概念决议（见后述）选择 #1 。

为进行概念决议，每个匹配名称（与限定，若存在）的模板形参都与模板实参与通配符这些概念实参的序列配对。通配符可匹配任何种类（类型、非类型、模板）的模板实参。形参集构造方式各异，依赖于语境

1) 对于用作有制约类型指定符或形参一部分的概念名，若概念名以无形参列表使用，则实参列表是单个通配符。
template<typename T> concept bool C1() { return true; } // #1
template<typename T, typename U> concept bool C1() { return true; } // #2
void f1(const C1*); // <wildcard> 匹配 <T> ，选择 #1
2) 对于用作有制约类型指定符或形参一部分的概念名，若概念名以模板实参列表使用，则实参列表是一个通配符后随实参列表。
template<typename T> concept bool C1() { return true; } // #1
template<typename T, typename U> concept bool C1() { return true; } // #2
void f2(C1<char>); // <wildcard, char> 匹配 <T, U> ，选择 #2
3) 若概念出现于模板引入中，则实参列表是与模板引入中形参列表等长的占位符序列
template<typename... Ts>
concept bool C3 = true;
C3{T} void q2();     // OK: <T> 匹配 <...Ts>
C3{...Ts} void q1(); // OK: <...Ts> 匹配 <...Ts>
4) 若概念作为模板 id 出现，则概念实参列表准确地是该模板 id 的实参序列
template<typename T> concept bool C() { return true; } // #1
template<typename T, typename U> concept bool C() { return true; } // #2

template <typename T>
void f(T) requires C<T>(); // 匹配 #1

概念决议通过配对每个实参和对应每个可见概念的对应形参进行。默认模板实参（若使用）为每个不对应实参的形参实例化，然后后附到实参列表。模板实参匹配形参，仅若它拥有相同种类（类型、非类型、模板），除非实参是通配符。形参包可匹配零或更多实参，只要所有实参都匹配种类中的模式（除非它们是通配符）。

若任何实参不匹配其对应的形参，或若有多于形参的实参，且最后的形参不是包，则该概念不可达。若有零或多于一个可生成概念，则程序为病式。

template<typename T> concept bool C2() { return true; }
template<int T> concept bool C2() { return true; }

template<C2<0> T> struct S1; // 错误： <wildcard, 0> 不匹配 <typename T> 或 <int T>
template<C2 T> struct S2; // #1 与 #2 均匹配：错误
本节未完成
原因：需要一个带有意义概念的示例，而非这些 'return true' 占位符

制约的偏序

在任何进一步分析前，通过替换每个具名概念和每个 requires 表达式的体规范化制约，直到剩下原子制约上的合取与析取序列。原子制约是谓词制约、表达式制约、隐式转换制约、实参推导制约和异常制约。

若能不因等价性分析类型和表达式就能证明概念 P 蕴含 概念 Q ，则说 P 包含 Q （故 N >= 0 不包含 N > 0 ）

具体而言，转换首个 P 为析取范式并转换 Q 为合取范式，再以下列方式比较它们：

  • 每个原子制约 A 包含等价的原子制约 A
  • 每个原子制约 A 包含析取 A||B 而不包含合取 A&&B
  • 每个合取 A&&B 包含 A ，但析取 A||B 不包含 A

包含关系定义制约上的偏序，这被用于确定：

  • 重载决议中非模板函数的最佳可生成候选
  • 重载集中非模板函数的地址
  • 模板模板实参的最佳匹配
  • 类模板特化的偏序
  • 函数模板的偏序
本节未完成
原因：从上述内容添加到此的回链

若声明 D1 与 D2 有制约且 D1 的规范化制约包含 D2 的规范化制约（或若 D1 有制约而 D2 无制约），则说 D1 与 D2 相比至少一样有制约。若 D1 至少与 D2 一样有制约，而 D2 不至少与 D1 一样有制约，则 D1 比 D2 更受制约。

template<typename T>
concept Decrementable = requires(T t) { --t; };
template<typename T>
concept RevIterator = Decrementable<T> && requires(T t) { *t; };

// RevIterator 包含 Decrementable ，但非相反
// RevIterator 比 Decrementable 更受制约

void f(Decrementable); // #1
void f(RevIterator);   // #2

f(0);       // int 仅满足可自增，选择 #1
f((int*)0); // int* 满足二个制约，选择 #2 ，因为更受制约

void g(auto);          // #3（无制约）
void g(Decrementable); // #4

g(true);  // bool 不满足 Decrementable ，选择 #3
g(0);     // int 满足 Decrementable ，选择 #4 因为它更受制约

关键词

concept, requires

编译器支持

GCC >= 6.1 支持此技术规范（要求选项 -fconcepts ）。


std::experimental::erase (std::deque)

< cpp‎ | experimental

定义于头文件 <experimental/deque> |
template <class T, class A, class U> void erase( std::deque <T, A>& c, const U& value); | (库基础 TS v2)

从容器擦除所有比较等于 value 的元素。等价于 c.erase(std::remove(c.begin(), c.end(), value), c.end());

参数

c | - | 要从中擦除的容器
value | - | 要移除的值

复杂度

线性。

示例

#include <experimental/deque>
#include <iostream>

auto show = [](const auto& container) {
    for (auto e : container) {
        std::cout << e;
    }
    std::cout << '\n';
};

int main()
{
    std::deque<int> data{1,1,1,4,1,1,1,2,1,1,1};
    show(data);
    std::experimental::erase(data, 1);
    show(data);
}

输出：

11141112111
42

参阅

removeremove_if | 移除满足特定判别标准的元素 (函数模板)
erase_if(std::deque) (库基础 2 TS) | 从 std::deque 擦除所有满足谓词的元素 (函数模板)


std::experimental::erase_if (std::deque)

< cpp‎ | experimental

定义于头文件 <experimental/deque> |
template <class T, class Alloc, class Pred> void erase_if( std::deque <T,Alloc>& c, Pred pred); | (库基础 TS v2)

从容器擦除所有满足谓词 pred 的元素。等价于 c.erase( std::remove_if (c.begin(), c.end(), pred), c.end());

参数

c | - | 要从中擦除的容器
pred | - | 确定该擦除哪些元素的谓词

复杂度

线性。

示例

#include <experimental/deque>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& container)
{
    os << "{ ";
    for (const auto& item : container) {
        os << item << ' ';
    }
    return os << "}";
}

int main()
{
    std::deque<int> data { 3, 3, 4, 5, 5, 6, 6, 7, 2, 1, 0 };

    std::cout << "Original:\n" << data << '\n';

    auto divisible_by_3 = [](auto const& x) { return (x % 3) == 0; };

    std::experimental::erase_if(data, divisible_by_3);

    std::cout << "Erase all items divisible by 3:\n" << data << '\n';
}

输出：

Original:
{ 3 3 4 5 5 6 6 7 2 1 0 }
Erase all items divisible by 3:
{ 4 5 5 7 2 1 }

参阅

removeremove_if | 移除满足特定判别标准的元素 (函数模板)
erase(std::deque) (库基础 2 TS) | 从 std::deque 擦除所有等于特定值的元素 (函数模板)


std::experimental::erased_type

< cpp‎ | experimental
定义于头文件 <experimental/utility> |
struct erased_type { }; | (库基础 TS)

结构体 erased_type 是空结构体，作为类型占位符，在实际类型于运行时确定的情形中使用。例如，使用类型擦除分配器的类中，嵌套 typedef allocator_type 是 erased_type 的别名。


std::experimental::flex_barrier

< cpp‎ | experimental
定义于头文件 <experimental/barrier> |
class flex_barrier; | (并发 TS)

类 std::experimental::flex_barrier 提供线程协调机制，允许参与线程的集合阻塞直至操作完成。不同于 std::experimental::latch ，屏障可重用；一旦从屏障的同步点释放参与线程，则它们能重用同一屏障。

屏障拥有完成阶段，一旦参与线程集中的所有线程都到达同步点，则由参与线程之一执行完成阶段。 arrive_and_wait 和 arrive_and_drop 的调用同步于完成阶段的开始；完成阶段的结束同步于从其完成所阻塞的所有调用返回。

std::experimental::flex_barrier 允许用户以函数对象控制完成阶段。若函数对象返回 -1 ，则不更改参与线程集（而下个循环中同一参与线程集必须抵达同步点）；否则参与线程集变为拥有等于返回值 N 的新大小的集合，并由到达屏障同步点的下 N 个线程组成。

不需要此功能的用户能使用 std::experimental::barrier 。

成员函数

(构造函数) | 构造 flex_barrier (公开成员函数)
(析构函数) | 销毁 flex_barrier (公开成员函数)
operator= [被删除] | 非可复制赋值 (公开成员函数)
arrive_and_wait | 到达同步点并阻塞 (公开成员函数)
arrive_and_drop | 到达同步点并从参与线程集中移除当前线程 (公开成员函数)


std::experimental::flex_barrier::arrive_and_drop

< cpp‎ | experimental‎ | flex barrier
void arrive_and_drop(); | (并发 TS)

到达 flex_barrier 的同步点并从参与线程集中移除当前线程。此函数是否阻塞直至完成阶段结束是未指定的。若函数阻塞，则必须选择调用方线程执行完成阶段。

若调用方线程不在此 flex_barrier 的参与线程集中，则行为未定义。

对 arrive_and_drop 的调用同步于 flex_barrier 完成阶段的开始。若所有调用都阻塞，则完成阶段的完成同步于从该调用返回。

调用 arrive_and_drop 和 arrive_and_wait 决不引入与自身或彼此的数据竞争。

异常

不抛出。

注意

即使每个参与线程都调用 arrive_and_drop ，也将执行完成阶段。

线程在 flex_barrier 上调用 arrive_and_drop 后，它不能调用该屏障上的任何成员函数，除了析构函数，即使完成阶段所调用的函数对象返回正值。

参阅

arrive_and_wait
 到达同步点并阻塞
(公开成员函数)


std::experimental::flex_barrier::arrive_and_wait

< cpp‎ | experimental‎ | flex barrier
void arrive_and_wait(); | (并发 TS)

阻塞并到达 flex_barrier 的同步点。

若调用线程不在此 flex_barrier 的参与线程集中，则行为未定义。

对 arrive_and_wait 的调用同步于 flex_barrier 完成阶段的开始。完成阶段的完成同步于从调用返回。

调用 arrive_and_drop 和 arrive_and_wait 决不引入与自身或彼此的数据竞争。

注意

从此调用返回时，线程立即调用 arrive_and_wait() 或 arrive_and_drop() 是安全的（只要完成阶段的函数对象不返回零）。不需要确保所有阻塞线程都在一个线程再次调用它时已退出 arrive_and_wait() 。

完成阶段执行构造 flex_barrier 时指定的函数对象。若它返回 -1 ，则不更改参与线程集（而下个循环中同一参与线程集必须抵达同步点）；否则参与线程集变为拥有等于返回值 N 的新大小的集合，并由到达屏障同步点的下 N 个线程组成。若 N == 0 ，则 flex_barrier 只能被销毁。

为 num_threads 个线程构造的 flex_barrier 的的初始参与线程集是首 num_threads 个到达其同步点的线程。

异常

不抛出。

参阅

arrive_and_drop
 到达同步点并从参与线程集中移除当前线程
(公开成员函数)


std::experimental::flex_barrier::flex_barrier

< cpp‎ | experimental‎ | flex barrier
explicit flex_barrier( std::ptrdiff_t num_threads ); | (1) | (并发 TS)
template < class F > flex_barrier( std::ptrdiff_t num_threads, F completion ); | (2) | (并发 TS)
flex_barrier( const flex_barrier & ) = delete; | (3) | (并发 TS)
1) 拥有同 flex_barrier(num_threads, c) 的效果，其中 c 是可调用 (Callable) 对象，其调用返回 -1 且无副效应。
2) 为 num_threads 个参与线程构造 flex_barrier ，将 completion 用于完成阶段。参与线程集是首 num_threads 个到达同步点的线程。
3) 复制构造函数被删除； flex_barrier 不可复制。

参数

num_threads | - | flex_barrier 的参与线程数；必须非负
completion | - | 控制完成阶段的函数对象；必须以无参数可调用 (Callable) 并拥有 std::ptrdiff_t 返回类型，调用时必须返回不小于 -1 的值且不抛出异常。
类型要求
- F 必须满足可复制构造 (CopyConstructible) 的要求。

注意

若 num_threads 为零，则参与线程集为空，而 flex_barrier 只能被销毁。


std::experimental::flex_barrier::~flex_barrier

< cpp‎ | experimental‎ | flex barrier
~flex_barrier(); | (并发 TS)

销毁 flex_barrier 。

若线程在同步点阻塞，则行为未定义。


std::experimental::erase (std::forward_list)

< cpp‎ | experimental

定义于头文件 <experimental/forward_list> |
template <class T, class A, class U> void erase( std::forward_list <T, A>& c, const U& value); | (库基础 TS v2)

从容器擦除所有比较等于 value 的元素。等价于 c.remove_if([&](auto& elem) { return elem == value; });

参数

c | - | 要从中擦除的容器
value | - | 要移除的值

复杂度

线性。

示例

#include <experimental/forward_list>
#include <iostream>

auto show = [](const auto& container) {
    for (auto e : container) {
        std::cout << e;
    }
    std::cout << '\n';
};

int main()
{
    std::forward_list<int> data{1,1,1,4,1,1,1,2,1,1,1};
    show(data);
    std::experimental::erase(data, 1);
    show(data);
}

输出：

11141112111
42

注解

不同于 std::forward_list::remove ，此函数模板接受异相类型，并在调用 == 运算符前不强制转换到容器的 value_type 。

参阅

removeremove_if | 移除满足特定判别标准的元素 (函数模板)
removeremove_if (C++11) | 移除满足特定标准的元素 (std::forward_list<T,Allocator> 的公开成员函数)
erase_if(std::forward_list) (库基础 2 TS) | 从 std::forward_list 擦除所有满足谓词的元素 (函数模板)


std::experimental::erase_if (std::forward_list)

< cpp‎ | experimental

定义于头文件 <experimental/forward_list> |
template <class T, class Alloc, class Pred> void erase_if( std::forward_list <T,Alloc>& c, Pred pred); | (库基础 TS v2)

从容器擦除所有满足谓词 pred 的元素。等价于 c.remove_if(pred);

参数

c | - | 要从中擦除的容器
pred | - | 确定该擦除哪些元素的谓词

复杂度

线性。

示例

#include <experimental/forward_list>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& container)
{
    os << "{ ";
    for (const auto& item : container) {
        os << item << ' ';
    }
    return os << "}";
}

int main()
{
    std::forward_list<int> data { 3, 3, 4, 5, 5, 6, 6, 7, 2, 1, 0 };

    std::cout << "Original:\n" << data << '\n';

    auto divisible_by_3 = [](auto const& x) { return (x % 3) == 0; };

    std::experimental::erase_if(data, divisible_by_3);

    std::cout << "Erase all items divisible by 3:\n" << data << '\n';
}

输出：

Original:
{ 3 3 4 5 5 6 6 7 2 1 0 }
Erase all items divisible by 3:
{ 4 5 5 7 2 1 }

参阅

removeremove_if | 移除满足特定判别标准的元素 (函数模板)
removeremove_if (C++11) | 移除满足特定标准的元素 (std::forward_list<T,Allocator> 的公开成员函数)
erase(std::forward_list) (库基础 2 TS) | 从 std::forward_list 擦除所有等于特定值的元素 (函数模板)


文件系统库

< cpp‎ | experimental

文件系统库 (Filesystem library) ， ISO/IEC TS 18822:2015 ，提供在文件系统与其组件，例如路径、常规文件与目录上进行操作的设施。

此库是可选的技术规范，而且若层级文件系统不能为实现所访问，或若它不提供必要的兼容性，则此库可能不可用。若底层文件系统不支持（例如 FAT 文件系统无硬链接、软连接和其他特性），则某些特性可能不可用。

若对此库中的函数的调用引入文件系统竞争，即多个线程、进程或计算机交错地访问并修改文件系统中的同一对象，则行为未定义。

此库直接基于 boost.filesystem ，当前可用它的编译器和平台多于此实验性技术规范。

库范畴定义

  • 文件：持有数据的文件系统对象，能被写入或读取，或二者皆可。文件拥有名称和属性，属性之一是文件类型：
  • 目录：表现为目录条目的容器的文件，目录条目标识其他文件（其中一些可以是另外的嵌套的目录）。讨论到具体文件时，入口出现于其中的目录是其亲目录。亲目录能以相对路径名 ".." 表示。
  • 硬链接：关联一个名词到一个既存文件的目录条目。若支持多重硬链接，则文件在最后一个到它的硬链接被移除后才被移除。
  • 符号链接：关联一个名词到一个路径的目录条目，路径可以存在亦可不存在。
  • 常规文件：不是其他文件类型的文件。
  • 文件名：命名一个文件的字符串。容许字符、大小写区别、最大长度以及被禁止名称是实现定义的。名称 "." （点）与 ".." （双点）在库层次拥有特殊含义。
  • 路径：标识一个文件的元素序列。它以可选的 root-name （例如 Windows 上的 "C:" 或 "//server" ）开始，后随可选的 root-directory （例如 Unix 上的 "/" ），后随零或更多个文件名（除了最后一个都必须是目录或到目录的链接）的序列。表示路径的字符串（路径名）的原生格式（如哪些字符被用作分隔符）与字符编码是实现定义的，库提供路径的可移植表示。
  • 绝对路径：无歧义地标识一个文件位置的路径。
  • 规范路径：不包含符号链接、 "." 或 ".." 元素的绝对路径。
  • 相对路径：标识相对于文件系统中某位置的文件位置的路径。特殊路径名 "." （点，“当前目录”）和 ".." （双点、“亲目录”）是相对路径。

类

path | 表示一个路径 (类)
filesystem_error | 文件系统错误时抛出的异常 (类)
directory_entry | 目录条目 (类)
directory_iterator | 指向目录内容的迭代器 (类)
recursive_directory_iterator | 指向目录及其子目录的内容的迭代器 (类)
file_status | 表示文件类型及权限 (类)
space_info | 关于文件系统上自由及可用空间的信息 (类)
file_type | 文件的类型 (枚举)
perms | 标识文件系统权限 (枚举)
copy_options | 指定复制操作的语义 (枚举)
directory_options | 用于迭代目录内容的选项 (枚举)
file_time_type | 表示文件时间值 (typedef)

非成员函数

absolutesystem_complete
 组成一个绝对路径
转换路径为绝对路径，复现 OS 特定的行为
(函数)
canonical
 组成一个规范路径
(函数)
copy
 复制文件或目录
(函数)
copy_file
 复制文件内容
(函数)
copy_symlink
 复制一个符号链接
(函数)
create_directorycreate_directories
 创建新目录
(函数)
create_hard_link
 创建一个硬链接
(函数)
create_symlinkcreate_directory_symlink
 创建一个符号链接
(函数)
current_path
 返回当前工作目录
(函数)
exists
 检查路径是否指代既存的文件系统对象
(函数)
equivalent
 检查两个路径是否指代同一文件系统对象
(函数)
file_size
 返回文件的大小
(函数)
hard_link_count
 返回指代特定文件的硬链接数
(函数)
last_write_time
 获取或设置最近一次数据修改的时间
(函数)
permissions
 修改文件访问权限
(函数)
read_symlink
 获得符号链接的目标
(函数)
removeremove_all
 移除一个文件或空目录
移除一个文件或递归地移除一个目录与其全部内容
(函数)
rename
 移动或重命名一个文件或目录
(函数)
resize_file
 以截断或填充零更改一个常规文件的大小
(函数)
space
 确定文件系统上的可用空闲空间
(函数)
statussymlink_status
 确定文件属性
确定文件属性，检查符号链接目标
(函数)
temp_directory_path
 返回一个适用于临时文件的目录
(函数)
文件类型
is_block_file
 检查给定路径是否指代块设备
(函数)
is_character_file
 检查给定路径是否指代字符设备
(函数)
is_directory
 检查给定路径是否指代一个目录
(函数)
is_empty
 检查给定路径是否指代一个空的文件或目录
(函数)
is_fifo
 检查给定路径是否指代一个命名管道
(函数)
is_other
 检查参数是否指代一个其他文件
(函数)
is_regular_file
 检查参数是否指代一个常规文件
(函数)
is_socket
 检查参数是否指代一个具名 IPC 套接字
(函数)
is_symlink
 检查参数是否指代一个符号链接
(函数)
status_known
 检查文件状态是否已知
(函数)


std::experimental::function

< cpp‎ | experimental
定义于头文件 <experimental/functional> |
template< class > class function; /* undefined */ | (库基础 TS)
template< class R, class... Args > class function<R(Args...)> | (库基础 TS)

std::experimental::function 是 std::function 的修改版本，支持类型擦除分配器。

成员类型

类型 | 定义
allocator_type | std::experimental::erased_type

成员函数

(构造函数) | 构造新的 std::experimental::function 实例 (公开成员函数)
operator= | 赋值新目标 (公开成员函数)
swap | 交换内容 (公开成员函数)
get_memory_resource | 获得指向此对象用来分配内存的 memory_resource 的指针 (公开成员函数)

非成员函数

std::experimental::swap(std::experimental::function) | 特化 swap 算法 (函数模板)
operator==operator!= | 比较 std::experimental::function 和 nullptr (函数模板)

辅助类

std::uses_allocator<std::experimental::function>
 特化 std::uses_allocator 类型特性
(类模板特化)

等同于 std::function 的成员

成员类型

类型 | 定义
result_type | R
argument_type | 若 sizeof...(Args)==1 ，且 T 为 Args... 中第一个并为唯一的类型则为 T
first_argument_type | 若 sizeof...(Args)==2 且 T1 为 Args... 中二个类型的第一个则为 T1
second_argument_type | 若 sizeof...(Args)==2 且 T2 为 Args... 中二个类型的第二个则为 T2

成员函数

(析构函数)
 析构 std::function 实例
(std::function<R(Args...)> 的公开成员函数)
operator bool
 检查是否包含了有效的目标
(std::function<R(Args...)> 的公开成员函数)
operator()
 调用其目标
(std::function<R(Args...)> 的公开成员函数)
目标访问
target_type
 获得 std::function 所存储的目标的typeid
(std::function<R(Args...)> 的公开成员函数)
target
 获得指向 std::function 所存储的目标的指针
(std::function<R(Args...)> 的公开成员函数)


std::experimental::function<R(Args...)>::function

< cpp‎ | experimental‎ | function
function() noexcept;
 (1) (库基础 TS)
function( std::nullptr_t ) noexcept;
 (2) (库基础 TS)
function( const function& other );
 (3) (库基础 TS)
function( function&& other );
 (4) (库基础 TS)
template< class F >
function( F f );
 (5) (库基础 TS)
template< class Alloc >
function( std::allocator_arg_t, const Alloc& alloc ) noexcept;
 (6) (库基础 TS)
template< class Alloc >

function( std::allocator_arg_t, const Alloc& alloc,

std::nullptr_t ) noexcept;
 (7) (库基础 TS)
template< class Alloc >

function( std::allocator_arg_t, const Alloc& alloc,

const function& other );
 (8) (库基础 TS)
template< class Alloc >

function( std::allocator_arg_t, const Alloc& alloc,

function&& other );
 (9) (库基础 TS)
template< class F, class Alloc >
function( std::allocator_arg_t, const Alloc& alloc, F f );
 (10) (库基础 TS)

从各种源构造 std::experimental::function 。

1-2) 构造空 function 。
3-4) 复制 (3) 或移动 (4) other 的目标到 *this 的目标。若 other 为空，则调用后 *this 将亦为空。
5) 以 f 的副本初始化目标。若 f 是指向函数的空指针或指向成员的空指针，则调用后 *this 将为空。此构造函数仅若 f 对参数类型 Args... 和返回类型 R 可调用 (Callable) 才参与重载决议。
6-10) 同 (1-5) ，除了用 alloc 分配 function 可能使用的任何内部数据结构的内存。这些构造函数将 alloc 当做类型擦除的分配器。

目标为函数指针或 std::reference_wrapper 时，保证小对象优化，即始终直接存储这些目标于 std::experimental::function 对象内，不发生动态分配。其他大对象可能在动态分配的存储中构造，并由 std::experimental::function 对象通过指针访问。

若构造函数移动或复制函数对象，包含 std::experimental::function 的实例，则由使用分配器构造用分配器 this->get_memory_resource() 进行移动或复制。

类型擦除的分配器

function 的接收分配器参数 alloc 的构造函数将参数当做类型擦除的分配器。以分配器参数（若指定）确定 function 用来分配内存的 memory_resource 指针，如下：

alloc 的类型 | memory_resource 指针的值
不存在（构造时不指定分配器） | 构造时 std::experimental::pmr::get_default_resource () 的值。
std::nullptr_t | 构造时 std::experimental::pmr::get_default_resource () 的值。
可转换为 std::experimental::pmr::memory_resource * 的指针类型 | static_cast< std::experimental::pmr::memory_resource *>(alloc)
std::experimental::pmr::polymorphic_allocator 的特化 | alloc.resource()
任何其他符合分配器 (Allocator) 要求的类型 | 指向 std::experimental::pmr::resource_adaptor <A>(alloc) 类型对象的指针，其中 A 是 alloc 的类型。指针仅在 function 对象的生存期内保持合法。
非以上类型 | 程序为病式

参数

other | - | 用于初始化 *this 的函数对象
f | - | 用于初始化 *this 的可调用对象
alloc | - | 用于内部内存分配的分配器
类型要求
- F 必须满足可调用 (Callable) 和 可复制构造 (CopyConstructible) 的要求。

异常

3,8) 若 other 的目标是函数指针或 std::reference_wrapper 则不抛出，否则可能抛出 std::bad_alloc 或存储的可调用对象的复制构造函数所抛出的任何异常。
4) （无）
5,10) 若 f 是函数指针或 std::reference_wrapper 则不抛出，否则可能抛出 std::bad_alloc 或存储的可调用对象的复制构造函数所抛出的任何异常。
9) （无）

示例

本节未完成
原因：暂无示例


std::experimental::function<R(Args...)>::get_memory_resource

< cpp‎ | experimental‎ | function

std::experimental::pmr::memory_resource * get_memory_resource() const noexcept; | (库基础 TS)

返回指向此对象用来分配内存的 memory_resource 的指针。

参数

（无）

返回值

指向此对象用来分配内存的 memory_resource 的指针。

参阅

(构造函数)
 构造新的 std::experimental::function 实例
(公开成员函数)


std::experimental::function<R(Args...)>::operator=

< cpp‎ | experimental‎ | function
function& operator=( const function& other ); | (1) | (库基础 TS)
function& operator=( function&& other ); | (2) | (库基础 TS)
function& operator=( std::nullptr_t ) noexcept; | (3) | (库基础 TS)
template< class F > function& operator=( F&& f ); | (4) | (库基础 TS)
template< class F > function& operator=( std::reference_wrapper <F> f ); | (5) | (库基础 TS)

赋值新目标给 std::experimental::function 。在以下描述中，令 ALLOCATOR_OF(f) 为 f 的构造中指定的分配器，或若未指定则为构造时 std::experimental::pmr::get_default_resource () 的值。

1) 如同通过执行 function( std::allocator_arg, ALLOCATOR_OF(*this), other).swap(*this); 赋值 other 的目标的副本。
2) 如同以执行 function( std::allocator_arg, ALLOCATOR_OF(*this), std::move(other)).swap(*this); 移动 other 的目标到 *this 。 other 在合法状态并拥有未指定值。
3) 销毁 *this 的目标。调用后 *this 为空。赋值后 get_memory_resource()所返回的内存资源等价于赋值前的内存资源，但地址可以更改。
4) 如同通过执行 function( std::allocator_arg, ALLOCATOR_OF(*this),std::forward <F>(f)).swap(*this); 设置 *this 的目标为 f 。此运算符仅若 f 对参数类型 Args... 和返回类型 R 可调用 (Callable) 才参与重载决议。
5) 如同通过执行 function( std::allocator_arg, ALLOCATOR_OF(*this), f).swap(*this); 设置 *this 的目标为 f 的副本。

参数

other | - | 要复制或移动的另一 std::experimental::function 对象
f | - | 要用以初始化目标的可调用对象
类型要求
- F 必须满足可调用 (Callable) 的要求。

返回值

*this

异常

1-2,4-5) （无）


operator==,!=(std::experimental::function)

< cpp‎ | experimental‎ | function
template< class R, class... ArgTypes >

bool operator==( const std::experimental::function<R(ArgTypes...)>& f,

std::nullptr_t ) noexcept;
 (1) (库基础 TS)
template< class R, class... ArgTypes >

bool operator==( std::nullptr_t,

const std::experimental::function<R(ArgTypes...)>& f ) noexcept;
 (2) (库基础 TS)
template< class R, class... ArgTypes >

bool operator!=( const std::experimental::function<R(ArgTypes...)>& f,

std::nullptr_t ) noexcept;
 (3) (库基础 TS)
template< class R, class... ArgTypes >

bool operator!=( std::nullptr_t,

const std::experimental::function<R(ArgTypes...)>& f ) noexcept;
 (4) (库基础 TS)

比较 std::experimental::function 和空指针。空 function （即无可调用目标的 function ）与之比较相等，非空 function 比较不相等。

参数

f - 要比较的 std::experimental::function

返回值

1-2) !f
3-4) (bool) f

参阅

operator==operator!=
(C++20 中移除)
 比较 std::function 和 nullptr
(函数模板)


std::experimental::function<R(Args...)>::swap

< cpp‎ | experimental‎ | function
void swap( function& other ); | (库基础 TS)

交换 *this 和 other 的存储可调用对象。

不交换 *this 与 other 的分配器。

若 *this->get_memory_resource() != *other.get_memory_resource() 则行为未定义。

参数

other - 要与之交换存储可调用对象的函数包装器

返回值

（无）


std::experimental::swap(std::experimental::function)

< cpp‎ | experimental‎ | function
template< class R, class... Args >

void swap( std::experimental::function<R(Args...)> &lhs,

std::experimental::function<R(Args...)> &rhs );

为 std::experimental::function 重载 swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换其状态的多态 function

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

swap
 交换内容
(公开成员函数)


std::uses_allocator<std::experimental::function>

< cpp‎ | experimental‎ | function
定义于头文件 <experimental/functional>
template< class R, class... ArgTypes, class Alloc >

struct uses_allocator<std::experimental::function<R(ArgTypes...)>, Alloc>

: std::true_type { };
 (库基础 TS)

std::uses_allocator 的此特化告知其他库组件： std::experimental::function 类型的所有对象支持 uses-allocator 构造。

继承自 std::integral_constant

成员常量

value
[静态]
 true
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

参阅

uses_allocator
(C++11)
 检查指定的类型是否支持使用分配器的构造
(类模板)


std::experimental::future

< cpp‎ | experimental
定义于头文件 <experimental/future> |  |
template< class T > class future; | (1) | (并发 TS)
template< class T > class future<T&>; | (2) | (并发 TS)
template<> class future<void>; | (3) | (并发 TS)

类模板 std::experimental::future 以下列操作扩展 std::future ：

  • 使用 future<future<T>> 的解包装构造函数；
  • 查询关联共享状态是否就绪的 is_ready ；以及
  • 附着持续到期货的成员函数 then 。

然而， std::experimental::future 与 std::future 间无相互操作。

成员函数

(构造函数) | 构造 future 对象 (公开成员函数)
is_ready | 检查共享状态是否就绪 (公开成员函数)
then | 附着持续到 future (公开成员函数)
operator= | 移动 future 对象 (公开成员函数)

等同于 std::future 的成员

成员函数

注意 share() 返回 std::experimental::shared_future<T> 。其他行为等同。

(析构函数)
 析构 future 对象
(std::future<T> 的公开成员函数)
share
 从 *this 转移共享状态给 shared_future 并返回它
(std::future<T> 的公开成员函数)
设置结果
get
 返回结果
(std::future<T> 的公开成员函数)
状态
valid
 检查 future 是否拥有共享状态
(std::future<T> 的公开成员函数)
wait
 等待结果变得可用
(std::future<T> 的公开成员函数)
wait_for
 等待结果，如果在指定的超时间隔后仍然无法得到结果，则返回。
(std::future<T> 的公开成员函数)
wait_until
 等待结果，如果在已经到达指定的时间点时仍然无法得到结果，则返回。
(std::future<T> 的公开成员函数)

示例

本节未完成
原因：暂无示例

参阅

shared_future
(并发 TS)
 以持续和其他特性增强的 std::shared_future 版本
(类模板)


std::experimental::future<T>::future

< cpp‎ | experimental‎ | future

future() noexcept; | (1)
future(std::experimental::future<T>&& f) noexcept; | (2)
future(const std::experimental::future<T>&) = delete; | (3)
future(std::experimental::future<std::experimental::future<T>> && other) noexcept; | (4)
1) 默认构造函数。构造不指代共享状态的空 future 对象。
2) 构造 future ，转移 f 所保有的共享状态，若存在。构造后 f.valid() 为 false 。
3) 复制构造函数被删除。不能复制 future 。
4) 从 other 所指代的共享状态构造 future 对象。结果 future 的对象在下列之一发生时变为就绪：
  • other 与 other.get() 均就绪。存储来自 other.get() 的值或异常到与结果 future 状态关联的共享状态中。
  • other 就绪，但 other.get() 非法。存储以 std::future_errc::broken_promise 为错误条件的 std::future_error 类型异常到与结果 future 对象关联的共享状态中。
此构造函数返回后， valid() == true 而 other.valid() == false 。

参数

f | - | 用以初始化的另一 future 对象
other | - | 要解包装的 std::experimental::future 对象

示例

本节未完成
原因：暂无示例

参阅

(构造函数)
 构造 future 对象
(std::future<T> 的公开成员函数)


std::experimental::future<T>::is_ready

< cpp‎ | experimental‎ | future

bool is_ready() const;

检查关联的共享状态是否就绪。

若 valid() 为 false 则行为未定义。

参数

（无）

返回值

若关联的共享状态就绪则为 true ，否则为 false 。

示例

本节未完成
原因：暂无示例

参阅

valid
 检查 future 是否拥有共享状态
(std::future<T> 的公开成员函数)


std::experimental::future<T>::operator=

< cpp‎ | experimental‎ | future
std::experimental::future<T>& operator=( std::experimental::future<T>&& other ) noexcept; | (1)
std::experimental::future<T>& operator=( const std::experimental::future<T>& other ) = delete; | (2)

赋值另一 future 对象的内容。

1) 释放任何共享状态并移动赋值 other 给 *this 。赋值后 other.valid() == false 而 this->valid() 将生成与 other.valid() 在赋值前相同的值。

2) std::experimental::future 不可复制赋值 (CopyAssignable) 。

参数

other - 将传递状态给 *this 的 std::experimental::future

返回值

*this


std::experimental::future<T>::then

< cpp‎ | experimental‎ | future

template < class F >
future</* see below */> then(F&& func) ;

附着持续 func 到 *this 。若 *this 无关联共享状态（即 valid() == false ）则行为未定义。

创建与要返回的 future 对象关联的共享状态，和如同用 DECAY_COPY( std::forward <F>(func)) 构造，在调用 then 的线程中求值的 func 的副本 fd ，其中 DECAY_COPY 定义为

template <class T>
std::decay_t<T> DECAY_COPY(T&& v) {
    return std::forward<T>(v);
}

当前与 *this 关联的共享状态就绪时，在未指定的执行线程上调用持续 INVOKE(std::move(fd), std::move(*this)) ，其中 INVOKE 是 可调用 (Callable) 中定义的操作。若该表达式非法，则行为未定义。

将从持续返回的任何值存储为返回的 future 对象的共享状态中的结果。将任何从持续的执行传播的异常存储为返回的 future 对象的共享状态中的异常结果。

令 U 为持续的返回类型（即 std::result_of_t < std::decay_t <F>(std::experimental::future<T>)> ）。若 U 为对于某类型 T2 的 std::experimental::future<T2> ，则 then 的返回类型为 std::experimental::future<T2> ，否则它为 std::experimental::future<U> 。这被称为隐式解包装。

若发生隐式解包装且持续返回非法的 future ，则用以 std::future_errc::broken_promise 为错误条件的 std::future_error 类型异常令共享状态就绪。

此函数返回后， valid() 为 false 。

参数

func - 要附着的持续。

返回值

与此对象所创建的共享状态关联的 std::experimental::future 对象。对于返回的对象 valid() == true 。

示例

本节未完成
原因：暂无示例


std::experimental::invocation_type, std::experimental::raw_invocation_type

< cpp‎ | experimental
定义于头文件 <experimental/type_traits> |  |
template<class> struct raw_invocation_type; // 不定义 template<class Fn, class... ArgTypes> struct raw_invocation_type<Fn(ArgTypes...)>; | (1) | (库基础 TS)
template<class> struct invocation_type; // 不定义 template<class Fn, class... ArgTypes> struct invocation_type<Fn(ArgTypes...)>; | (2) | (库基础 TS)

在以参数 ArgTypes... 调用 Fn ，如在 INVOKE( std::declval <Fn>(), std::declval <ArgTypes>()...) 中时计算调用形参，其中 INVOKE 是 可调用 (Callable) 中定义的操作。

表达式 INVOKE(f, t1, t2, ..., tN) 的调用形参定义如下，其中 T1 是（可有 cv 限定的） t1 的类型，而若 t1 为左值则 U1 为 T1& ，否则为 T1&& ：

  • 若 f 是指向类 T 成员函数的指针，则调用参数是 U1 后随 t2, ..., tN 所匹配的 f 的形参。
  • 若 N == 1 且 f 为指向类 T 数据成员的指针，则调用形参为 U1 。
  • 若 f 为类类型对象，则调用形参为在 f 的代理调用函数和函数调用运算符间，实参 t1, ..., tN 的最佳可达函数的匹配 t1, ..., tN 的形参。
  • 所有其他情况下，调用形参是 f 的匹配 t1, ..., tN 的形参。

若实参 tI 匹配函数形参列表中的省略号，则对应的调用形参是应用默认参数提升到 tI 的结果。

Fn 和 ArgTypes 中的所有类型能为完整类型、未知边界数组或（可有 cv 限定的） void 。

成员类型

成员类型 定义
raw_invocation_type<Fn(ArgTypes...)>::type R(T1, T2, ...) ，其中：
  • R 为 std::result_of_t <Fn(ArgTypes...)>
  • T1, T2, ... 为定义于上的 INVOKE( std::declval <Fn>(), std::declval <ArgTypes>()...) 的调用形参。

仅若能在不求值语境中以 ArgTypes... 调用 Fn 才定义。
invocation_type<Fn(ArgTypes...)>::type R(U1, U2, ...) ，其中
  • R 为 std::result_of_t <Fn(ArgTypes...)>
  • T1, T2, ... 为定义如上的 INVOKE( std::declval <Fn>(), std::declval <ArgTypes>()...) 的调用形参
  • A1, A2, ... 代表 ArgTypes...
  • 若 std::declval <Ai>() 为右值则 Ui 为 std::decay_t <Ai> ，否则为 Ti 。

仅若能在不求值语境中以 ArgTypes... 调用 Fn 才定义。

辅助类型

template< class T > using raw_invocation_type_t = typename raw_invocation_type<T>::type; | (库基础 TS)
template< class T > using invocation_type_t = typename invocation_type<T>::type; | (库基础 TS)

示例

本节未完成
原因：暂无示例

参阅


std::experimental::is_detected, std::experimental::detected_t, std::experimental::detected_or

< cpp‎ | experimental
定义于头文件 <experimental/type_traits> |
template< template<class...> class Op, class... Args > using is_detected = /* see below */; | (库基础 TS v2)
template< template<class...> class Op, class... Args > using detected_t = /* see below */; | (库基础 TS v2)
template< class Default, template<class...> class Op, class... Args > using detected_or = /* see below */; | (库基础 TS v2)

别名模板 detected_or 是拥有二个公开成员 typedef value_t 和 type 的未指定类类型的别名，它们定义如下：

  • 若模板 id Op<Args...> 代表合法类型，则 value_t 是 std::true_type 的别名，而 type 是 Op<Args...> 的别名；
  • 否则， value_t 是 std::false_type 的别名而 type 是 Default 的别名。

别名模板 is_detected 等价于 typename detected_or< std::experimental::nonesuch, Op, Args...>::value_t 。若模板 id Op<Args...> 代表合法类型，则它是 std::true_type 的别名；否则它是 std::false_type 的别名。

别名模版 detected_t 等价于 typename detected_or< std::experimental::nonesuch, Op, Args...>::type 。若模板 id Op<Args...> 代表合法类型，则它是 Op<Args...> 的别名；否则它是类 std::experimental::nonesuch 的别名。

额外工具

template< template<class...> class Op, class... Args > constexpr bool is_detected_v = is_detected<Op, Args...>::value; | (库基础 TS v2)
template< template<class...> class Op, class... Args > constexpr inline bool is_detected_v = is_detected<Op, Args...>::value; | (库基础 TS v3)
template< class Default, template<class...> class Op, class... Args > using detected_or_t = typename detected_or<Default, Op, Args...>::type; | (库基础 TS v2)
template <class Expected, template<class...> class Op, class... Args> using is_detected_exact = std::is_same <Expected, detected_t<Op, Args...>>; | (库基础 TS v2)
template <class Expected, template<class...> class Op, class... Args> constexpr bool is_detected_exact_v = is_detected_exact<Expected, Op, Args...>::value; | (库基础 TS v2)
template <class Expected, template<class...> class Op, class... Args> constexpr inline bool is_detected_exact_v = is_detected_exact<Expected, Op, Args...>::value; | (库基础 TS v3)
template <class To, template<class...> class Op, class... Args> using is_detected_convertible = std::is_convertible <detected_t<Op, Args...>, To>; | (库基础 TS v2)
template <class To, template<class...> class Op, class... Args> constexpr bool is_detected_convertible_v = is_detected_convertible<To, Op, Args...>::value; | (库基础 TS v2)
template <class To, template<class...> class Op, class... Args> constexpr inline bool is_detected_convertible_v = is_detected_convertible<To, Op, Args...>::value; | (库基础 TS v3)

别名模版 is_detected_exact 检查 detected_t<Op, Args...> 是否为 Expected 。

别名模板 is_detected_convertible 检查 detected_t<Op, Args...> 是否可转换为 To 。

可能的实现

namespace detail {
template <class Default, class AlwaysVoid,
          template<class...> class Op, class... Args>
struct detector {
  using value_t = std::false_type;
  using type = Default;
};

template <class Default, template<class...> class Op, class... Args>
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> {
  // 注意 std::void_t 是 C++17 特性
  using value_t = std::true_type;
  using type = Op<Args...>;
};

} // namespace detail

template <template<class...> class Op, class... Args>
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;

template <template<class...> class Op, class... Args>
using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type;

template <class Default, template<class...> class Op, class... Args>
using detected_or = detail::detector<Default, void, Op, Args...>;

示例

#include <experimental/type_traits>
#include <cstddef>

template<class T>
using copy_assign_t = decltype(std::declval<T&>() = std::declval<const T&>());

struct Meow { };
struct Purr { void operator=(const Purr&) = delete; };

static_assert(std::experimental::is_detected<copy_assign_t, Meow>::value,
              "Meow should be copy assignable!");
static_assert(!std::experimental::is_detected_v<copy_assign_t, Purr>,
              "Purr should not be copy assignable!");
static_assert(std::experimental::is_detected_exact_v<Meow&, copy_assign_t, Meow>,
              "Copy assignment of Meow should return Meow&!");

template<class T>
using diff_t = typename T::difference_type;

template <class Ptr>
using difference_type = std::experimental::detected_or_t<std::ptrdiff_t, diff_t, Ptr>;

struct Woof { using difference_type = int; };
struct Bark {};

static_assert(std::is_same<difference_type<Woof>, int>::value,
              "Woof's difference_type should be int!");
static_assert(std::is_same<difference_type<Bark>, std::ptrdiff_t>::value,
              "Bark's difference_type should be ptrdiff_t!");

int main() {}

参阅


std::experimental::latch

< cpp‎ | experimental
定义于头文件 <experimental/latch> |
class latch; | (并发 TS)

latch 是 ptrdiff_t 类型的向下计数器，它能用于同步线程。在创建时初始化计数器的值。

线程可能在 latch 上阻塞直至计数器减少到零。没有可能增加或重置计数器，这使 latch 为单次使用的屏障。

不同于 std::experimental::barrier ，参与线程能减少 std::experimental::latch 多于一次。

成员函数

(构造函数) | 构造 latch (公开成员函数)
(析构函数) | 销毁 latch (公开成员函数)
operator= [被删除] | 非可复制赋值 (公开成员函数)
count_down_and_wait | 减少计数器 1 并阻塞直至它抵达零 (公开成员函数)
count_down | 以非阻塞方式自减计数器 (公开成员函数)
is_ready | 测试内部计数器是否等于零 (公开成员函数)
wait | 阻塞直至计数器抵达零 (公开成员函数)


std::experimental::latch::count_down

< cpp‎ | experimental‎ | latch
void count_down( ptrdiff_t n = 1); | (1) | (并发 TS)

原子地自减计数器的值 n ，而不阻塞调用方。

若 n 大于内部计数器的值或为负，则行为未定义。

此操作同步于所有在此 latch 上阻塞的调用，和所有返回 true 的在此 latch 上的 is_ready 调用。

参数

n - 内部计数器所自减的值

返回值

（无）

异常

不抛出。


std::experimental::latch::count_down_and_wait

< cpp‎ | experimental‎ | latch
void count_down_and_wait(); | (1) | (并发 TS)

原子地自减内部计数器 1 ，（若需要则）并阻塞调用方线程直至计数器抵达零。

若内部计数器已为零则行为未定义。

此操作同步于任何在此 latch 上阻塞的调用，和所有返回 true 的在此 latch 上的 is_ready 调用。

参数

（无）

返回值

（无）

异常

不抛出。


std::experimental::latch::is_ready

< cpp‎ | experimental‎ | latch
bool is_ready() const noexcept; | (1) | (并发 TS)

若内部计数器等于零则返回 true 。

参数

（无）

返回值

若 *this 闩的内部计数器等于零则为 true 。


std::experimental::latch::latch

< cpp‎ | experimental‎ | latch
explicit latch( ptrdiff_t value ); | (1) | (并发 TS)
latch( const latch & ) = delete; | (2) | (并发 TS)
1) 构造 latch 并初始化其内部计数器。
2) 复制构造函数被删除。 latch 不可复制。

参数

value - 内部计数器的初值；必须为非负


std::experimental::latch::wait

< cpp‎ | experimental‎ | latch
void wait() const; | (1) | (并发 TS)

阻塞调用方线程，直至内部计数器抵达 0 。若它已为零，则立即返回。

参数

（无）

返回值

（无）

异常

不抛出。


std::experimental::latch::~latch

< cpp‎ | experimental‎ | latch
~latch(); | (并发 TS)

销毁 latch 。

若线程在同步点阻塞，则行为未定义。

即使不是所有线程都已从 wait() 或 count_down_and_wait() 返回，亦可调用析构函数，只要内部计数器必须等于零。

析构函数可能阻塞直至所有线程都已从阻塞函数返回。

在一个线程调用析构函数后，不允许线程在此 latch 上阻塞。


C++ 标准库扩展

< cpp‎ | experimental

C++ 库基础扩展之版本 1 (The C++ Extensions for Library Fundamentals) ， ISO/IEC TS 19568:2015 为 C++ 标准库定义下列新组件：

C++17 未选择 ISO/IEC TS 19568:2015 的下列组件

支持类型擦除分配器的既存类修改版本

定义于头文件 <experimental/functional>
function | 带有类型擦除分配器支持的 std::function 修改版本 (类模板)
定义于头文件 <experimental/future>
promise | 带有类型擦除分配器支持的 std::promise 修改版本 (类模板)
packaged_task | 带有类型擦除分配器支持的 std::packaged_task 修改版本 (类模板)

内存资源适配器

resource_adaptor
 将分配器适配到 memory_resource
(别名模板)

通用工具

定义于头文件 <experimental/utility>
erased_type | 类型擦除的占位符类型，例如在分配器中 (类)
定义于头文件 <experimental/type_traits>
invocation_typeraw_invocation_type | 推导以给定参数调用可调用对象时的隐含函数类型 (类模板)

特性测试宏

定义于头文件 <experimental/optional>
__cpp_lib_experimental_optional | 至少为 201411 的值，指示支持 optional 类型 (宏常量)
定义于头文件 <experimental/any>
__cpp_lib_experimental_any | 至少为 201411 的值，指示支持 any 类型 (宏常量)
定义于头文件 <experimental/string_view>
__cpp_lib_experimental_string_view | 至少为 201411 的值，指示支持 basic_string_view 模板 (宏常量)
定义于头文件 <experimental/tuple>
__cpp_lib_experimental_apply | 至少为 201402 的值，指示支持 tuple 的 apply() 函数 (宏常量)
定义于头文件 <experimental/type_traits>
__cpp_lib_experimental_type_trait_variable_templates | 至少为 201402 的值，指示支持类型特性的变量模板 (宏常量)
__cpp_lib_experimental_invocation_type | 至少为 201406 的值，指示支持调用类型特性 (宏常量)
定义于头文件 <experimental/functional>
__cpp_lib_experimental_boyer_moore_searching | 至少为 201411 的值，指示支持附加搜索算法 (宏常量)
__cpp_lib_experimental_function_erased_allocator | 至少为 201406 的值，指示支持 std::function 的类型擦除分配器 (宏常量)
定义于头文件 <experimental/future>
__cpp_lib_experimental_promise_erased_allocator | 至少为 201406 的值，指示支持 std::promise 的类型擦除分配器 (宏常量)
__cpp_lib_experimental_packaged_task_erased_allocator | 至少为 201406 的值，指示支持 std::packaged_task 的类型擦除分配器 (宏常量)
定义于头文件 <experimental/memory>
__cpp_lib_experimental_shared_ptr_arrays | 至少为 201406 的值，指示 shared_ptr 支持数组 (宏常量)
定义于头文件 <experimental/memory_resource>
__cpp_lib_experimental_memory_resources | 至少为 201402 的值，指示支持多态内存资源 (宏常量)
定义于头文件 <experimental/algorithm>
__cpp_lib_experimental_sample | 至少为 201402 的值，指示支持采样算法 (宏常量)

并入 C++17

ISO/IEC TS 19568:2015 的下列组件已包含于 C++17

可选对象

定义于头文件 <experimental/optional>
optional
 表示可选对象的类模板
(类模板)

类 any

定义于头文件 <experimental/any>
any
 任何类型单个值的类型安全容器
(类)

string_view

定义于头文件 <experimental/string_view>
basic_string_view
 到字符串的非占有引用
(类模板)

类型擦除及多态分配器

多态分配器与内存资源

此节中的实体声明于 std::experimental::pmr 命名空间

定义于头文件 <experimental/memory_resource>
memory_resource | 封装内存资源的类的抽象接口 (类)
synchronized_pool_resource | 线程安全的，在不同块大小的池中管理分配的 memory_resource (类)
unsynchronized_pool_resource | 线程不安全的，在不同块大小的池中管理分配的 memory_resource (类)
monotonic_buffer_resource | 特殊用途的 memory_resource ，它仅在销毁资源时释放分配的内存 (类)
polymorphic_allocator | 支持运行时多态的分配器，多态基于构造所用的 memory_resource (类模板)
new_delete_resource | 返回一个静态的程序范围 memory_resource，它使用全局 operator new 与 operator delete 分配和解分配内存 (函数)
null_memory_resource | 返回一个不进行任何分配的静态 memory_resource (函数)
get_default_resource | 获取缺省 memory_resource (函数)
set_default_resource | 设置缺省 memory_resource (函数)

使用多态分配器的容器的便利别名

std::experimental::pmr 命名空间中为标准库中的下列类模板提供便利别名和别名模板：

提供了便利别名的容器模板列表
  • std::vector
  • std::deque
  • std::forward_list
  • std::list
  • std::basic_string
  • std::map
  • std::multimap
  • std::set
  • std::multiset
  • std::match_results
  • std::unordered_map
  • std::unordered_multimap
  • std::unordered_set
  • std::unordered_multiset

shared_ptr 的数组支持

定义于头文件 <experimental/memory>
类 | 描述
shared_ptr | 支持数组的 std::shared_ptr 修改版本 (类模板)
weak_ptr | 支持数组的 std::weak_ptr 修改版本 (类模板)

采样和搜索算法

定义于头文件 <experimental/algorithm>
sample | 从序列中选择 n 个随机元素 (函数模板)
search | 应用搜索器 (Searcher) 到序列 (函数模板)
定义于头文件 <experimental/functional>
default_searcher | 标准 C++ 库搜索算法实现 (类模板)
make_default_searcher | 创建 default_searcher 的帮助函数 (函数模板)
boyer_moore_searcher | Boyer-Moore 搜索算法实现 (类模板)
make_boyer_moore_searcher | 创建 boyer_moore_searcher 的帮助函数 (函数模板)
boyer_moore_horspool_searcher | Boyer-Moore-Horspool 搜索算法实现 (类模板)
make_boyer_moore_horspool_searcher | 创建 boyer_moore_horspool_searcher 的帮助函数 (函数模板)

通用工具

定义于头文件 <experimental/tuple>
apply
 以参数的 tuple 调用函数
(函数模板)

另外，该 TS 为标准库中的类型特性和其他类模板提供大量 constexpr 变量模板：

提供了变量模板的类型特性和其他类模板
  • std::is_void
  • std::is_null_pointer
  • std::is_integral
  • std::is_floating_point
  • std::is_array
  • std::is_pointer
  • std::is_lvalue_reference
  • std::is_rvalue_reference
  • std::is_member_object_pointer
  • std::is_member_function_pointer
  • std::is_enum
  • std::is_union
  • std::is_class
  • std::is_function
  • std::is_reference
  • std::is_arithmetic
  • std::is_fundamental
  • std::is_object
  • std::is_scalar
  • std::is_compound
  • std::is_member_pointer
  • std::is_const
  • std::is_volatile
  • std::is_trivial
  • std::is_trivially_copyable
  • std::is_standard_layout
  • std::is_pod
  • std::is_literal_type
  • std::is_empty
  • std::is_polymorphic
  • std::is_abstract
  • std::is_final
  • std::is_signed
  • std::is_unsigned
  • std::is_constructible
  • std::is_trivially_constructible
  • std::is_nothrow_constructible
  • std::is_default_constructible
  • std::is_trivially_default_constructible
  • std::is_nothrow_default_constructible
  • std::is_copy_constructible
  • std::is_trivially_copy_constructible
  • std::is_nothrow_copy_constructible
  • std::is_move_constructible
  • std::is_trivially_move_constructible
  • std::is_nothrow_move_constructible
  • std::is_assignable
  • std::is_trivially_assignable
  • std::is_nothrow_assignable
  • std::is_copy_assignable
  • std::is_trivially_copy_assignable
  • std::is_nothrow_copy_assignable
  • std::is_move_assignable
  • std::is_trivially_move_assignable
  • std::is_nothrow_move_assignable
  • std::is_destructible
  • std::is_trivially_destructible
  • std::is_nothrow_destructible
  • std::has_virtual_destructor
  • std::alignment_of
  • std::rank
  • std::extent
  • std::is_same
  • std::is_base_of
  • std::is_convertible
  • std::ratio_equal
  • std::ratio_not_equal
  • std::ratio_less
  • std::ratio_less_equal
  • std::ratio_greater
  • std::ratio_greater_equal
  • std::tuple_size
  • std::chrono::treat_as_floating_point
  • std::is_error_code_enum
  • std::is_error_condition_enum
  • std::is_bind_expression
  • std::is_placeholder
  • std::uses_allocator


std::experimental::packaged_task (库基础 TS)

< cpp‎ | experimental‎ | lib extensions

此页面提及库基础 TS 所提供的带类型擦除分配器支持的 std::packaged_task 修改版本。并发 TS 所提供的支持该 TS 所改进的 std::future 的 packaged_task 版本，见 std::experimental::concurrency_v1::packaged_task 。

定义于头文件 <experimental/future> |  |
template< class > class packaged_task; // 不定义 | (1) | (库基础 TS)
template< class R, class ...Args > class packaged_task<R(Args...)>; | (2) | (库基础 TS)

std::experimental::fundamentals_v1::packaged_task （和 std::experimental::fundamentals_v2::packaged_task ）是库基础 TS 提供的 std::packaged_task 的修改版本，带有类型擦除分配器支持。

成员类型

成员类型 | 定义
allocator_type | std::experimental::erased_type

成员函数

(构造函数) | 构造任务对象 (公开成员函数)
get_memory_resource | 取得指向此对象用来分配内存的 memory_resource 的指针 (公开成员函数)

非成员函数

std::experimental::swap(std::experimental::packaged_task)
 特化 swap 算法
(函数模板)

辅助类

std::uses_allocator<std::experimental::packaged_task>
 特化 std::uses_allocator 类型特性
(类模板特化)

等同于 std::packaged_task 的成员

成员函数

(析构函数)
 析构任务对象
(std::packaged_task<R(Args...)> 的公开成员函数)
operator=
 移动任务对象
(std::packaged_task<R(Args...)> 的公开成员函数)
valid
 检查任务对象是否拥有合法函数
(std::packaged_task<R(Args...)> 的公开成员函数)
swap
 交换二个任务对象
(std::packaged_task<R(Args...)> 的公开成员函数)
获取结果
get_future
 返回与承诺的结果关联的 std::future
(std::packaged_task<R(Args...)> 的公开成员函数)
执行
operator()
 执行函数
(std::packaged_task<R(Args...)> 的公开成员函数)
make_ready_at_thread_exit
 执行函数，并确保结果仅在一旦当前线程退出时就绪
(std::packaged_task<R(Args...)> 的公开成员函数)
reset
 重置状态，抛弃任何先前执行的存储结果
(std::packaged_task<R(Args...)> 的公开成员函数)


std::experimental::packaged_task<R(Args...)>::get_memory_resource

< cpp‎ | experimental‎ | lib extensions‎ | packaged task

std::experimental::pmr::memory_resource * get_memory_resource() const noexcept; | (库基础 TS)

返回指向此对象用来分配内存的 memory_resource 的指针。

参数

（无）

返回值

指向此对象用来分配内存的 memory_resource 的指针。

参阅

(构造函数)
 构造任务对象
(公开成员函数)


std::experimental::packaged_task<R(Args...)>::packaged_task (库基础 TS)

< cpp‎ | experimental‎ | lib extensions‎ | packaged task
packaged_task() noexcept; | (1) | (库基础 TS)
template <class F> explicit packaged_task( F&& f ); | (2) | (库基础 TS)
template <class F, class Allocator> explicit packaged_task( std::allocator_arg_t, const Allocator& alloc, F&& f ); | (3) | (库基础 TS)
packaged_task( const packaged_task& ) = delete; | (4) | (库基础 TS)
packaged_task( packaged_task&& rhs ) noexcept; | (5) | (库基础 TS)

构造新的 std::experimental::packaged_task 对象。

1) 构造无任务且无共享状态的 std::experimental::packaged_task 对象。
2) 构造拥有共享状态和任务副本的 std::experimental::packaged_task 对象，以 std::forward <F>(f) 初始化。此构造函数仅若 std::decay <F>::type 与 std::packaged_task <R(ArgTypes...)> 为同一类型才参与重载决议。
3) 构造拥有共享状态和任务副本的 std::experimental::packaged_task 对象，以 std::forward <F>(f) 初始化。用提供的分配器分配存储任务所需的内存，分配器被当做类型擦除的分配器（见后述）。此构造函数仅若 std::decay <F>::type 与 std::packaged_task <R(ArgTypes...)> 为相同类型才参与重载决议。
4) 复制构造函数被删除， std::experimental::packaged_task 为仅移动。
5) 构造拥有共享对象和 rhs 先前占有的任务的 std::experimental::packaged_task ，并使 rhs 有无共享状态和被移动的任务。

类型擦除的分配器

packaged_task 的接收分配器参数 alloc 的构造函数将参数当做类型擦除的分配器。以分配器参数（若指定）确定 packaged_task 用来分配内存的 memory_resource 指针，如下：

alloc 的类型 | memory_resource 指针的值
不存在（构造时不指定分配器） | 构造时 std::experimental::pmr::get_default_resource () 的值。
std::nullptr_t | 构造时 std::experimental::pmr::get_default_resource () 的值。
可转换为 std::experimental::pmr::memory_resource * 的指针类型 | static_cast< std::experimental::pmr::memory_resource *>(alloc)
std::experimental::pmr::polymorphic_allocator 的特化 | alloc.resource()
任何其他符合分配器 (Allocator) 要求的类型 | 指向 std::experimental::pmr::resource_adaptor <A>(alloc) 类型对象的指针，其中 A 是 alloc 的类型。指针仅在 packaged_task 对象的生存期内保持合法。
非以上类型 | 程序为病式

参数

f | - | 要执行的可调用目标（函数、成员函数、 lambda 表达式、仿函数）
alloc | - | 存储任务时使用的分配器
rhs | - | 要移动的 std::experimental::packaged_task

异常

2-3) 任何 f 的复制/移动构造函数可能抛出的异常，及可能的 std::bad_alloc ，若分配失败。
4) （无）


std::experimental::swap(std::experimental::packaged_task)

< cpp‎ | experimental‎ | lib extensions‎ | packaged task
template< class R, class... Args >

void swap( std::experimental::packaged_task<R(Args...)> &lhs,

std::experimental::packaged_task<R(Args...)> &rhs ) noexcept;

为 std::experimental::packaged_task 重载 swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的 packaged_task

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

swap
 交换二个任务对象
(std::packaged_task<R(Args...)> 的公开成员函数)


std::uses_allocator<std::experimental::packaged_task>

< cpp‎ | experimental‎ | lib extensions‎ | packaged task
定义于头文件 <experimental/future>
template< class R, class Alloc >

struct uses_allocator<std::experimental::packaged_task<R>, Alloc>

: std::true_type { };
 (库基础 TS)

std::uses_allocator 的此特化告知其他库组件，所有 std::experimental::packaged_task 类型对象支持 uses-allocator 构造。

继承自 std::integral_constant

成员常量

value
[静态]
 true
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

参阅

uses_allocator
(C++11)
 检查指定的类型是否支持使用分配器的构造
(类模板)


std::experimental::promise (库基础 TS)

< cpp‎ | experimental‎ | lib extensions

此页面提及库基础 TS 所提供的带类型擦除分配器支持的 std::promise 修改版本。并发 TS 所提供的支持该 TS 所改进的 std::future 的 promise 版本，见 std::experimental::concurrency_v1::promise 。

定义于头文件 <experimental/future> |  |
template< class R > class promise; | (1) | (库基础 TS)
template< class R > class promise<R&>; | (2) | (库基础 TS)
template<> class promise<void>; | (3) | (库基础 TS)

std::experimental::fundamentals_v1::promise （和 std::experimental::fundamentals_v2::promise ）是 std::promise 的修改版，由库基础 TS 提供，带类型擦除分配器的支持。

成员类型

成员类型 | 定义
allocator_type | std::experimental::erased_type

成员函数

(构造函数) | 构造 promise 对象 (公开成员函数)
get_memory_resource | 取得指向此对象用来分配内存的 memory_resource 的指针 (公开成员函数)

非成员函数

std::experimental::swap(std::experimental::promise)
 特化 swap 算法
(函数模板)

辅助类

std::uses_allocator<std::experimental::promise>
 特化 std::uses_allocator 类型特性
(类模板特化)

等同于 std::promise 的成员

成员函数

(析构函数)
 析构std::promise对象
(std::promise<R> 的公开成员函数)
operator=
 赋值共享状态
(std::promise<R> 的公开成员函数)
swap
 交换二个 promise 对象
(std::promise<R> 的公开成员函数)
获取结果
get_future
 返回与承诺的结果关联的 future
(std::promise<R> 的公开成员函数)
设置结果
set_value
 设置结果为指定值
(std::promise<R> 的公开成员函数)
set_value_at_thread_exit
 设置结果为指定值，同时仅在线程退出时分发提醒
(std::promise<R> 的公开成员函数)
set_exception
 设置结果为指示异常
(std::promise<R> 的公开成员函数)
set_exception_at_thread_exit
 设置结果为指示异常，同时仅在线程退出时分发提醒
(std::promise<R> 的公开成员函数)


std::experimental::promise<R>::get_memory_resource

< cpp‎ | experimental‎ | lib extensions‎ | promise

std::experimental::pmr::memory_resource * get_memory_resource() const noexcept; | (库基础 TS)

返回指向此对象用来分配内存的 memory_resource 的指针。

参数

（无）

返回值

指向此对象用来分配内存的 memory_resource 的指针。

参阅

(构造函数)
 构造 promise 对象
(公开成员函数)


std::experimental::promise<R>::promise (库基础 TS)

< cpp‎ | experimental‎ | lib extensions‎ | promise
promise(); | (1) | (库基础 TS)
template< class Alloc > promise( std::allocator_arg_t, const Alloc& alloc ); | (2) | (库基础 TS)
promise( promise&& other ) noexcept; | (3) | (库基础 TS)
promise( const promise& other ) = delete; | (4) | (库基础 TS)

构造 std::experimental::promise 对象。

1) 默认构造函数。构造拥有空共享状态的 promise 。
2) 构造拥有空共享状态的 promise 。用被当做类型擦除分配器（见后述）的 alloc 分配共享状态。
3) 移动构造函数。用移动语义构造拥有 other 的共享状态的 promise 。构造后， other 无共享状态。
4) std::experimental::promise 不可复制。

类型擦除的分配器

promise 的接收分配器参数 alloc 的构造函数将参数当做类型擦除的分配器。以分配器参数（若指定）确定 promise 用来分配内存的 memory_resource 指针，如下：

alloc 的类型 | memory_resource 指针的值
不存在（构造时不指定分配器） | 构造时 std::experimental::pmr::get_default_resource () 的值。
std::nullptr_t | 构造时 std::experimental::pmr::get_default_resource () 的值。
可转换为 std::experimental::pmr::memory_resource * 的指针类型 | static_cast< std::experimental::pmr::memory_resource *>(alloc)
std::experimental::pmr::polymorphic_allocator 的特化 | alloc.resource()
任何其他符合分配器 (Allocator) 要求的类型 | 指向 std::experimental::pmr::resource_adaptor <A>(alloc) 类型对象的指针，其中 A 是 alloc 的类型。指针仅在 promise 对象的生存期内保持合法。
非以上类型 | 程序为病式

参数

alloc | - | 用于分配共享状态的分配器
other | - | 取得其共享状态的另一 std::experimental::promise

异常

1-2) （无）


std::experimental::swap(std::experimental::promise)

< cpp‎ | experimental‎ | lib extensions‎ | promise
template< class R >

void swap( std::experimental::promise<R> &lhs,

std::experimental::promise<R> &rhs ) noexcept;

为 std::experimental::promise 重载 swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的 promise

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

swap
 交换二个 promise 对象
(std::promise<R> 的公开成员函数)


std::uses_allocator<std::experimental::promise>

< cpp‎ | experimental‎ | lib extensions‎ | promise
定义于头文件 <experimental/future>
template< class R, class Alloc >

struct uses_allocator<std::experimental::promise<R>, Alloc>

: std::true_type { };
 (库基础 TS)

std::uses_allocator 的此特化告知其他库组件， std::experimental::promise 类型的所有对象支持 uses-allocator 构造。

继承自 std::integral_constant

成员常量

value
[静态]
 true
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

参阅

uses_allocator
(C++11)
 检查指定的类型是否支持使用分配器的构造
(类模板)


C++ 标准库扩展，版本 2

< cpp‎ | experimental

C++ 库基础扩展的版本 2 (Version 2 of the C++ Extensions for Library Fundamentals) ， ISO/IEC TS 19568:2017 在定义于版本 1 中的组件外，还为 C++ 标准库定义下列组件：

C++ 检测手法

定义于头文件 <experimental/type_traits>
is_detected detected_t detected_or | 检测 template-id 是否良式的别名模板 (别名模板)
nonesuch | detected_t 在失败时返回的类类型 (类)

传播 const 的仿指针对象包装器

定义于头文件 <experimental/propagate_const>
propagate_const
 传播 const 的仿类指针对象包装器
(类模板)

非占有指针

定义于头文件 <experimental/memory>
observer_ptr
 表示非占有指针的类
(类模板)

std::array 创建

定义于头文件 <experimental/array>
make_array
 创建 std::array 对象，从参数推导出其大小和可选的元素类型
(函数模板)

ostream_joiner

定义于头文件 <experimental/iterator>
ostream_joiner
 写入相继元素到输出流，并以分隔符分隔相邻元素的输出迭代器
(类模板)

简单的随机数生成设施

为每个线程维护一个 std::default_random_engine 类型的逐线程引擎，初始化到不可预测状态，而它并为下列函数所用。

定义于头文件 <experimental/random>
randint | 生成指定范围中的随机整数 (函数模板)
reseed | 重播种单个线程的随机引擎 (函数)
定义于头文件 <experimental/algorithm>
sample | 从序列随机选择 n 个元素 (函数模板)
shuffle | 随机地重排范围中的元素 (函数模板)

特性测试宏

定义于头文件 <experimental/type_traits>
__cpp_lib_experimental_logical_traits | 至少为 201511 的值，指示支持逻辑运算符类型特性 (宏常量)
__cpp_lib_experimental_detect | 至少为 201505 的值，指示支持检测手法 (宏常量)
定义于头文件 <experimental/propagate_const>
__cpp_lib_experimental_propagate_const | 至少为 201505 的值，指示支持 propagate_const (宏常量)
定义于头文件 <experimental/functional>
__cpp_lib_experimental_not_fn | 至少为 201406 的值，指示支持 not_fn (宏常量)
定义于头文件 <experimental/memory>
__cpp_lib_experimental_observer_ptr | 至少为 201411 的值，指示支持 observer_ptr (宏常量)
定义于头文件 <experimental/array>
__cpp_lib_experimental_make_array | 至少为 201505 的值，指示支持 make_array (宏常量)
定义于头文件 <experimental/iterator>
__cpp_lib_experimental_ostream_joiner | 至少为 201411 的值，指示支持 ostream_joiner (宏常量)
定义于头文件 <experimental/vector>
__cpp_lib_experimental_erase_if | 至少为 201411 的值，指示支持统一容器擦除 (宏常量)
定义于头文件 <experimental/numeric>
__cpp_lib_experimental_gcd_lcm | 至少为 201411 的值，指示支持 gcd 和 lcm (宏常量)
定义于头文件 <experimental/random>
__cpp_lib_experimental_randint | 至少为 201511 的值，指示支持 randint (宏常量)
定义于头文件 <experimental/source_location>
__cpp_lib_experimental_source_location | 至少为 201505 的值，指示支持 source_location (宏常量)

并入 C++17

库基础 v2 的下列组件已被采纳到 C++17 标准。

定义于头文件 <experimental/type_traits>
void_t | void 的变长别名模板 (别名模板)
定义于头文件 <experimental/type_traits>
conjunction | 变长逻辑与元函数 (类模板)
disjunction | 变长逻辑或元函数 (类模板)
negation | 逻辑非元函数 (类模板)
定义于头文件 <experimental/functional>
not_fn | 创建函数对象，它返回其所保有的函数对象结果的逻辑补 (函数模板)
定义于头文件 <experimental/numeric>
gcd | 返回二个整数最大公约数的 constexpr 函数模板 (函数模板)
lcm | 返回二个整数最小公倍数的 constexpr 函数模板 (函数模板)

并入 C++20

库基础 v2 的下列组件已被采纳到 C++20 标准。

统一容器擦除

定义于头文件 <experimental/string>
erase(std::basic_string) | 从 std::basic_string 擦除所有等于特定值的元素 (函数模板)
erase_if(std::basic_string) | 从 std::basic_string 擦除所有满足谓词的元素 (函数模板)
定义于头文件 <experimental/deque>
erase(std::deque) | 从 std::deque 擦除所有等于特定值的元素 (函数模板)
erase_if(std::deque) | 从 std::deque 擦除所有满足谓词的元素 (函数模板)
定义于头文件 <experimental/vector>
erase(std::vector) | 从 std::vector 擦除所有等于特定值的元素 (函数模板)
erase_if(std::vector) | 从 std::vector 擦除所有满足谓词的元素 (函数模板)
定义于头文件 <experimental/forward_list>
erase(std::forward_list) | 从 std::forward_list 擦除所有等于特定值的元素 (函数模板)
erase_if(std::forward_list) | 从 std::forward_list 擦除所有满足谓词的元素 (函数模板)
定义于头文件 <experimental/list>
erase(std::list) | 从 std::list 擦除所有等于特定值的元素 (函数模板)
erase_if(std::list) | 从 std::list 擦除所有满足谓词的元素 (函数模板)
定义于头文件 <experimental/map>
erase_if(std::map) | 从 std::map 擦除所有满足谓词的元素 (函数模板)
erase_if(std::multimap) | 从 std::multimap 擦除所有满足谓词的元素 (函数模板)
定义于头文件 <experimental/set>
erase_if(std::set) | 从 std::set 擦除所有满足谓词的元素 (函数模板)
erase_if(std::multiset) | 从 std::multiset 擦除所有满足谓词的元素 (函数模板)
定义于头文件 <experimental/unordered_map>
erase_if(std::unordered_map) | 从 std::unordered_map 擦除所有满足谓词的元素 (函数模板)
erase_if(std::unordered_multimap) | 从 std::unordered_multimap 擦除所有满足谓词的元素 (函数模板)
定义于头文件 <experimental/unordered_set>
erase_if(std::unordered_set) | 从 std::unordered_set 擦除所有满足谓词的元素 (函数模板)
erase_if(std::unordered_multiset) | 从 std::unordered_multiset 擦除所有满足谓词的元素 (函数模板)

源码信息捕获

定义于头文件 <experimental/source_location>
source_location
 表示关于源码的，如文件名、行号和函数名的信息
(类)

std::array 转换

定义于头文件 <experimental/array>
to_array
 从内建数组创建 std::array 对象
(函数模板)


C++ 标准库扩展，版本 3

< cpp‎ | experimental

C++ 库基础扩展 (C++ Extensions for Library Fundamentals) 的版本 3 在版本 1 与版本 2 之外为 C++ 标准库定义下列新组件。

std::experimental::make_array 及并入 C++17/20 的组件被排除出库基础 TS v3 。

作用域防护

定义于头文件 <experimental/scope>
scope_exit | 包装函数对象并在退出作用域时调用 (类模板)
scope_fail | 包装函数对象并在通过异常退出作用域时调用 (类模板)
scope_success | 包装函数对象并在正常退出作用域时调用 (类模板)
unique_resource | 通用 RAII 资源柄包装 (类模板)

特性测试宏

定义于头文件 <experimental/scope>
__cpp_lib_experimental_scope
 至少为 201902 的值，指示支持作用域防护
(宏常量)


std::experimental::erase (std::list)

< cpp‎ | experimental

定义于头文件 <experimental/list> |
template <class T, class A, class U> void erase( std::list <T, A>& c, const U& value); | (库基础 TS v2)

从容器擦除所有比较等于 value 的元素。等价于 c.remove_if([&](auto& elem) { return elem == value; });

参数

c | - | 要从中擦除的容器
value | - | 要移除的值

复杂度

线性。

示例

#include <experimental/list>
#include <iostream>

auto show = [](const auto& container) {
    for (auto e : container) {
        std::cout << e;
    }
    std::cout << '\n';
};

int main()
{
    std::list<int> data{1,1,1,4,1,1,1,2,1,1,1};
    show(data);
    std::experimental::erase(data, 1);
    show(data);
}

输出：

11141112111
42

注解

不同于 std::list::remove ，此函数模板接受异相类型，并在调用 == 运算符前不强制转换到容器的 value_type 。

参阅

removeremove_if | 移除满足特定判别标准的元素 (函数模板)
removeremove_if | 移除满足特定标准的元素 (std::list<T,Allocator> 的公开成员函数)
erase_if(std::list) (库基础 2 TS) | 从 std::list 擦除所有满足谓词的元素 (函数模板)


std::experimental::erase_if (std::list)

< cpp‎ | experimental

定义于头文件 <experimental/list> |
template <class T, class Alloc, class Pred> void erase_if( std::list <T,Alloc>& c, Pred pred); | (库基础 TS v2)

从容器擦除所有满足谓词 pred 的元素。等价于 c.remove_if(pred);

参数

c | - | 要从中擦除的容器
pred | - | 确定该擦除哪些元素的谓词

复杂度

线性。

示例

#include <experimental/list>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& container)
{
    os << "{ ";
    for (const auto& item : container) {
        os << item << ' ';
    }
    return os << "}";
}

int main()
{
    std::list<int> data { 3, 3, 4, 5, 5, 6, 6, 7, 2, 1, 0 };

    std::cout << "Original:\n" << data << '\n';

    auto divisible_by_3 = [](auto const& x) { return (x % 3) == 0; };

    std::experimental::erase_if(data, divisible_by_3);

    std::cout << "Erase all items divisible by 3:\n" << data << '\n';
}

输出：

Original:
{ 3 3 4 5 5 6 6 7 2 1 0 }
Erase all items divisible by 3:
{ 4 5 5 7 2 1 }

参阅

removeremove_if | 移除满足特定判别标准的元素 (函数模板)
removeremove_if | 移除满足特定标准的元素 (std::list<T,Allocator> 的公开成员函数)
erase(std::list) (库基础 2 TS) | 从 std::list 擦除所有等于特定值的元素 (函数模板)


std::experimental::make_array

< cpp‎ | experimental
定义于头文件 <experimental/array> |
template <class D = void, class... Types> constexpr std::array <VT /* see below */, sizeof...(Types)> make_array(Types&&... t); | (库基础 TS v2)

创建一个 std::array ，其大小等于参数数量，且其元素从对应参数初始化。返回 std::array <VT, sizeof...(Types)>{ std::forward <Types>(t)...}

若 D 为 void ，则推出的类型 VT 为 std::common_type_t <Types...> 。否则，类型为 D 。

若 D 为 void ，且 std::decay_t <Types>... 中任意一者是 std::reference_wrapper 的特化，则程序为谬构。

注解

make_array 在库基础 TS v3 中被移除，因为 std::array 的推导指引与 std::to_array 已在 C++20 中。

可能的实现

namespace details {
  template<class> struct is_ref_wrapper : std::false_type {};
  template<class T> struct is_ref_wrapper<std::reference_wrapper<T>> : std::true_type {};

  template<class T>
  using not_ref_wrapper = std::experimental::negation<is_ref_wrapper<std::decay_t<T>>>;

  template <class D, class...> struct return_type_helper { using type = D; };
  template <class... Types>
  struct return_type_helper<void, Types...> : std::common_type<Types...> {
      static_assert(std::experimental::conjunction_v<not_ref_wrapper<Types>...>,
                    "Types cannot contain reference_wrappers when D is void");
  };

  template <class D, class... Types>
  using return_type = std::array<typename return_type_helper<D, Types...>::type,
                                 sizeof...(Types)>;
}

template < class D = void, class... Types>
constexpr details::return_type<D, Types...> make_array(Types&&... t) {
  return {std::forward<Types>(t)... };
}

示例

#include <experimental/array>
#include <iostream>
#include <type_traits>

int main()
{
    auto arr = std::experimental::make_array(1, 2, 3, 4, 5);
    bool is_array_of_5_ints = std::is_same<decltype(arr), std::array<int, 5>>::value;
    std::cout << "Returns an array of five ints? ";
    std::cout << std::boolalpha << is_array_of_5_ints << '\n';
}

输出：

Returns an array of five ints? true

参阅

to_array
 从内建数组创建 std::array 对象
(函数模板)


std::experimental::make_exceptional_future

< cpp‎ | experimental
定义于头文件 <experimental/future> |  |
template < class T > future<T> make_exceptional_future( std::exception_ptr ex); | (1) | (并发 TS)
template < class T, class E > future<T> make_exceptional_future(E ex); | (2) | (并发 TS)
1) 创建立即就绪的 T 类型共享装填，并存储异常指针 ex ，然后返回与该共享状态该关联的 future ，如同用 promise<T> p; p.set_exception(ex); return p.get_future(); 。若 ex 为空则行为未定义。
2) 创建立即就绪的 T 类型共享状态，并存储从 ex 构造的异常指针，然后返回与该共享状态关联的 future ，如同用 promise<T> p; p.set_exception( std::make_exception_ptr (ex)); return p.get_future(); 。

返回值

与创建的共享状态关联的 future 对象。

参阅

make_ready_future
(并发 TS)
 产生立即就绪并保有指定值的 future
(函数模板)


std::experimental::make_ready_future

< cpp‎ | experimental
定义于头文件 <experimental/future> |  |
template < class T > future<V /* see below */> make_ready_future(T&& value); | (1) | (并发 TS)
future<void> make_ready_future(); | (2) | (并发 TS)
1) 若 std::decay_t <T> 为 std::reference_wrapper <X> ，则 V 为 X& ，否则 V 为 std::decay_t <T> 。
创建立即就绪的 V 类型共享状态，从 std::forward <T>(value) 构造结果，然后返回与该共享状态关联的 std::experimental::future 。
2) 创建立即就绪的 void 类型共享状态，然后返回与该共享状态关联的 std::experimental::future 。

返回值

与创建的共享状态关联的 std::experimental::future 。

参阅

make_exceptional_future
(并发 TS)
 产生立即就绪并保有给定异常的 future
(函数模板)


std::experimental::erase_if (std::map)

< cpp‎ | experimental

定义于头文件 <experimental/map> |
template <class Key, class T, class Compare, class Alloc, class Pred> void erase_if( std::map <Key,T,Compare,Alloc>& c, Pred pred); | (库基础 TS v2)

从容器擦除所有满足谓词 pred 的元素。等价于

for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}

参数

c | - | 要从中擦除的容器
pred | - | 确定该擦除哪些元素的谓词

复杂度

线性。

示例

#include <experimental/map>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& cont)
{
    os << "{";
    for (const auto& item : cont) {
        os << "{" << item.first << ", " << item.second << "}";
    }
    return os << "}";
}

int main()
{
    std::map<int, char> data {{1, 'a'},{2, 'b'},{3, 'c'},{4, 'd'},
                              {5, 'e'},{4, 'f'},{5, 'g'},{5, 'g'}};
    std::cout << "Original:\n" << data << '\n';

    std::experimental::erase_if(data, [](const auto& item) {
        return (item.first & 1) == 1;
    });

    std::cout << "Erase items with odd keys:\n" << data << '\n';
}

输出：

Original:
{{1, a}{2, b}{3, c}{4, d}{5, e}}
Erase items with odd keys:
{{2, b}{4, d}}

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::experimental::erase_if (std::multimap)

< cpp‎ | experimental

定义于头文件 <experimental/map> |
template <class Key, class T, class Compare, class Alloc, class Pred> void erase_if( std::multimap <Key,T,Compare,Alloc>& c, Pred pred); | (库基础 TS v2)

从容器擦除所有满足谓词 pred 的元素。等价于

for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}

参数

c | - | 要从中擦除的容器
pred | - | 确定该擦除哪些元素的谓词

复杂度

线性。

示例

#include <experimental/map>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& cont)
{
    os << "{";
    for (const auto& item : cont) {
        os << "{" << item.first << ", " << item.second << "}";
    }
    return os << "}";
}

int main()
{
    std::multimap<int, char> data {{1, 'a'},{2, 'b'},{3, 'c'},{4, 'd'},
                                   {5, 'e'},{4, 'f'},{5, 'g'},{5, 'g'}};
    std::cout << "Original:\n" << data << '\n';

    std::experimental::erase_if(data, [](const auto& item) {
        return (item.first & 1) == 1;
    });

    std::cout << "Erase items with odd keys:\n" << data << '\n';
}

输出：

Original:
{{1, a}{2, b}{3, c}{4, d}{4, f}{5, e}{5, g}{5, g}}
Erase items with odd keys:
{{2, b}{4, d}{4, f}}

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::experimental::erase_if (std::multiset)

< cpp‎ | experimental

定义于头文件 <experimental/set> |
template <class Key, class Compare, class Alloc, class Pred> void erase_if( std::multiset <Key,Compare,Alloc>& c, Pred pred); | (库基础 TS v2)

从容器擦除所有满足谓词 pred 的元素。等价于

for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}

参数

c | - | 要从中擦除的容器
pred | - | 确定该擦除哪些元素的谓词

复杂度

线性。

示例

#include <experimental/set>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& container)
{
    os << "{ ";
    for (const auto& item : container) {
        os << item << ' ';
    }
    return os << "}";
}

int main()
{
    std::multiset<int> data { 3, 3, 4, 5, 5, 6, 6, 7, 2, 1, 0 };

    std::cout << "Original:\n" << data << '\n';

    auto divisible_by_3 = [](auto const& x) { return (x % 3) == 0; };

    std::experimental::erase_if(data, divisible_by_3);

    std::cout << "Erase all items divisible by 3:\n" << data << '\n';
}

输出：

Original:
{ 0 1 2 3 3 4 5 5 6 6 7 }
Erase all items divisible by 3:
{ 1 2 4 5 5 7 }

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::experimental::nonesuch

< cpp‎ | experimental
定义于头文件 <experimental/type_traits>
struct nonesuch {

~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;

};
 (库基础 TS v2)

std::experimental::nonesuch 是 std::experimental::detected_t 用以指示检测失败的类类型。

nonesuch 无默认构造函数或 intializer_list 构造函数，且非聚合体。

注意

不能构造、析构或销毁 nonesuch 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2960 | LFTSv2 | nonesuch 可为聚合体并拥有源自 {} 的隐式转换序列 | 使之为非聚合体并移除 ICS


std::experimental::not_fn

< cpp‎ | experimental
定义于头文件 <experimental/functional> |
template< class F> /*unspecified*/ not_fn( F&& f ); | (库基础 TS v2)

创建转发调用包装器，它返回其所保有的可调用对象的逻辑补。

参数

f - 对象，从该对象构造包装器所保有的可调用 (Callable) 对象

返回值

令 FD 为 std::decay_t <F> ， fd 为从 std::forward <F>(f) 构造的 FD 类型左值。

则 not_fn 返回未指定类型的转发调用包装器，使得 fn(a1, a2, ..., aN) 等价于 !INVOKE(fd, a1, ..., aN) ，其中 INVOKE 是 可调用 (Callable) 中描述的操作。

返回的调用包装器始终为可移动构造 (MoveConstructible) ，而若 FD 为可复制构造 (CopyConstructible) 则它亦为可复制构造 (CopyConstructible) 。

提醒

若 fd 非可调用 (Callable) ，或 std::is_constructible <FD, F>::value 非 true ，则行为未定义。

异常

不抛异常，除非 fd 的构造抛出。

可能的实现

namespace detail {
    template<class F>
    struct not_fn_t {
        F f;
        template<class... Args>
        auto operator()(Args&&... args)
            noexcept(noexcept(!std::invoke(f, std::forward<Args>(args)...)))
            -> decltype(!std::invoke(f, std::forward<Args>(args)...)) {
            return !std::invoke(f, std::forward<Args>(args)...);
        }

        // QoI 的 cv 限定重载
        template<class... Args>
        auto operator()(Args&&... args) const
            noexcept(noexcept(!std::invoke(f, std::forward<Args>(args)...)))
            -> decltype(!std::invoke(f, std::forward<Args>(args)...)) {
            return !std::invoke(f, std::forward<Args>(args)...);
        }

        template<class... Args>
        auto operator()(Args&&... args) volatile
            noexcept(noexcept(!std::invoke(f, std::forward<Args>(args)...)))
            -> decltype(!std::invoke(f, std::forward<Args>(args)...)) {
            return !std::invoke(f, std::forward<Args>(args)...);
        }
        template<class... Args>
        auto operator()(Args&&... args) const volatile
            noexcept(noexcept(!std::invoke(f, std::forward<Args>(args)...)))
            -> decltype(!std::invoke(f, std::forward<Args>(args)...)) {
            return !std::invoke(f, std::forward<Args>(args)...);
        }
    };
}

template<class F>
detail::not_fn_t<std::decay_t<F>> not_fn(F&& f) { return { std::forward<F>(f) }; }

注意

not_fn 的用意是替换 C++03 时代的取反器 std::not1 和 std::not2 。

参阅

not_fn
(C++17)
 创建返回其保有的函数对象的结果之补的函数对象
(函数模板)


std::experimental::observer_ptr

< cpp‎ | experimental
定义于头文件 <experimental/memory> |
template< class W > class observer_ptr; | (库基础 TS v2)

std::experimental::observer_ptr 是非占有指针，或观察器。观察器存储指向称为被查看对象的第二对象的指针。 observer_ptr 亦可无被查看对象。

观察器不以任何方式负责被查看对象；观察器与其所查看的对象间无固有关系。

它是有意被用作裸指针类型的接近偶然的替换，优点是作为词汇类型，它指示其有意使用，而无需读代码者的详细分析。

observer_ptr 的特化满足可复制构造 (CopyConstructible) 和可复制赋值 (CopyAssignable) 的要求。

类型要求
-
W 不应为引用类型，但可为不完整类型。

成员类型

成员类型 | 定义
element_type | W ，此 observer_ptr 所查看的对象类型

成员函数

(构造函数)
 构造新的 observer_ptr
(公开成员函数)
(析构函数)
(隐式声明)
 销毁 observer_ptr
(公开成员函数)
operator=
(隐式声明)
 隐式声明的复制和移动赋值运算符，赋值存储的指针
(公开成员函数)
修改器
release
 返回指向被查看对象的指针并停止查看对象
(公开成员函数)
reset
 替换被查看对象
(公开成员函数)
swap
 交换所查看的对象
(公开成员函数)
观察器
get
 返回指向被查看对象的指针
(公开成员函数)
operator bool
 检查是否有关联的被查看对象
(公开成员函数)
operator*operator->
 解引用指向被查看对象的指针
(公开成员函数)
转换
operator element_type*
 到被存储指针的显式转换函数
(公开成员函数)

非成员函数

make_observer | 创建查看对象的 observer_ptr (函数模板)
operator==operator!=operator<operator<=operator>operator>= | 与另一 observer_ptr 或 nullptr 比较 (函数模板)
std::experimental::swap(std::experimental::observer_ptr) | 特化 swap 算法 (函数模板)

辅助类

std::hash<std::experimental::observer_ptr>
 observer_ptr 的哈希支持
(类模板特化)

示例

本节未完成
原因：暂无示例


std::experimental::observer_ptr<W>::get

< cpp‎ | experimental‎ | observer ptr
constexpr element_type* get() const noexcept; | (库基础 TS v2)

返回指向被查看对象的指针，或若无被查看对象则返回 nullptr 。

参数

（无）

返回值

指向被查看对象的指针，或若无被查看对象则为 nullptr 。

示例

本节未完成
原因：暂无示例

参阅

release
 返回指向被查看对象的指针并停止查看对象
(公开成员函数)


std::hash(std::experimental::observer_ptr)

< cpp‎ | experimental‎ | observer ptr
定义于头文件 <experimental/memory> |
template<class T> struct hash< std::experimental::observer_ptr <T>>; | (库基础 TS v2)

std::hash 对 std::experimental::observer_ptr <T> 的模板特化允许用户获得 std::experimental::observer_ptr <T> 类型对象的哈希。

对于给定的 std::experimental::observer_ptr <T> p ，此特化确保 std::hash < std::experimental::observer_ptr <T>>()(p) == std::hash <T*>()(p.get()) 。

示例

本节未完成
原因：暂无示例

参阅

hash
(C++11)
 散列函数对象
(类模板)


std::experimental::make_observer

< cpp‎ | experimental‎ | observer ptr
定义于头文件 <experimental/memory> |
template <class W> std::experimental::observer_ptr <W> make_observer(W* p) noexcept; | (库基础 TS v2)

创建 observer_ptr 对象，从函数实参的类型推导模板实参。

参数

p - 指向要为 observer_ptr 对象所查看的对象

返回值

如同以 std::experimental::observer_ptr <W>(p) 创建的 observer_ptr 对象。

示例

本节未完成
原因：暂无示例


std::experimental::observer_ptr<W>::observer_ptr

< cpp‎ | experimental‎ | observer ptr
constexpr observer_ptr() noexcept;
constexpr observer_ptr( nullptr_t ) noexcept;
 (1) (库基础 TS v2)
constexpr explicit observer_ptr( element_type* p ) noexcept;
 (2) (库基础 TS v2)
template<class W2>
constexpr observer_ptr( observer_ptr<W2> other ) noexcept;
 (3) (库基础 TS v2)
observer_ptr( const observer_ptr& other ) = default;
 (4) (库基础 TS v2)
(隐式声明)
observer_ptr( observer_ptr&& other ) = default;
 (5) (库基础 TS v2)
(隐式声明)
1) 构造无对应被查看对象的 observer_ptr 。
2) 构造查看 p 的 observer_ptr 。
3) 构造查看 other.get() 的 observer_ptr 。此重载仅若 W2* 可转换为 element_type* 才参与重载决议。
4-5) 隐式声明的复制和移动构造函数。构造查看 other.get() 的 observer_ptr 。

参数

p | - | 指向要查看的对象的指针
other | - | 要复制的另一 observer_ptr


std::experimental::observer_ptr<W>::operator*, std::experimental::observer_ptr<W>::operator->

< cpp‎ | experimental‎ | observer ptr
constexpr std::add_lvalue_reference_t <element_type> operator*() const; | (1) | (库基础 TS v2)
constexpr element_type* operator->() const noexcept; | (2) | (库基础 TS v2)

operator* 和 operator-> 提供对 *this 所查看对象的访问。

若 get() == nullptr 则 operator* 的行为未定义。

参数

（无）

返回值

1) 返回 *this 所查看的对象，等价于 *get() 。

2) 返回指向 *this 所查看对象的指针，等价于 get() 。

异常

1) 不抛异常。

示例

本节未完成
原因：暂无示例

参阅

get
 返回指向被查看对象的指针
(公开成员函数)


std::experimental::observer_ptr<W>::operator bool

< cpp‎ | experimental‎ | observer ptr
constexpr explicit operator bool() const noexcept; | (库基础 TS v2)

检查 *this 是否有关联的被查看对象，即是否有 get() != nullptr 。

参数

（无）

返回值

若 *this 拥有关联的被查看对象则为 true ，否则为 false 。

示例

本节未完成
原因：暂无示例

参阅

get
 返回指向被查看对象的指针
(公开成员函数)


operator==,!=,<,<=,>,>=(std::experimental::observer_ptr)

< cpp‎ | experimental‎ | observer ptr
template<class W1, class W2> bool operator==(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2); | (1) | (库基础 TS v2)
template<class W1, class W2> bool operator!=(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2); | (2) | (库基础 TS v2)
template<class W> bool operator==(const observer_ptr<W>& p, std::nullptr_t ) noexcept; | (3) | (库基础 TS v2)
template<class W> bool operator==( std::nullptr_t, const observer_ptr<W>& p) noexcept; | (4) | (库基础 TS v2)
template<class W> bool operator!=(const observer_ptr<W>& p, std::nullptr_t ) noexcept; | (5) | (库基础 TS v2)
template<class W> bool operator!=( std::nullptr_t, const observer_ptr<W>& p) noexcept; | (6) | (库基础 TS v2)
template<class W1, class W2> bool operator<(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2); | (7) | (库基础 TS v2)
template<class W1, class W2> bool operator>(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2); | (8) | (库基础 TS v2)
template<class W1, class W2> bool operator<=(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2); | (9) | (库基础 TS v2)
template<class W1, class W2> bool operator>=(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2); | (10) | (库基础 TS v2)

比较二个 observer_ptr 的指针值，或一个 observer_ptr 和 nullptr 。

1-2) 二个 observer_ptr 的相等比较
3-6) 一个 observer_ptr 和 nullptr 的相等比较。
7-10) 二个 observer_ptr 的顺序比较。

参数

p, p1, p2 - 要比较的 observer_ptr

返回值

1) p1.get() == p2.get()

2) !(p1 == p2)

3-4) !p

5-6) (bool)p

7) std::less <W3>()(p1.get(), p2.get()) ，其中 W3 是 W1* 与 W2* 的合成指针类型

8) p2 < p1

9) !(p2 < p1)

10) !(p1 < p2)


std::experimental::observer_ptr<W>::operator element_type*

< cpp‎ | experimental‎ | observer ptr
constexpr explicit operator element_type*() const noexcept; | (库基础 TS v2)

提供到存储指针的类型的显式转换。

参数

（无）

返回值

指向被查看对象的指针，即 get() 。

示例

本节未完成
原因：暂无示例

参阅

get
 返回指向被查看对象的指针
(公开成员函数)


std::experimental::observer_ptr<W>::release

< cpp‎ | experimental‎ | observer ptr
constexpr element_type* release() noexcept; | (库基础 TS v2)

停止查看被查看对象，若它存在。调用后 get() 返回 nullptr 。

参数

（无）

返回值

指向先前的被查看对象的指针，或若无被查看对象则为 nullptr ，即调用前 get() 会返回的值。

示例

本节未完成
原因：暂无示例

参阅

get | 返回指向被查看对象的指针 (公开成员函数)
reset | 替换被查看对象 (公开成员函数)


std::experimental::observer_ptr<W>::reset

< cpp‎ | experimental‎ | observer ptr
constexpr void reset(element_type* p = nullptr) noexcept; | (库基础 TS v2)

设置 *this 查看 p 所指向的对象。调用后 get() 返回 p 。

参数

ptr - 指向要查看的新对象的指针

示例

本节未完成
原因：暂无示例

参阅

release
 返回指向被查看对象的指针并停止查看对象
(公开成员函数)


std::experimental::observer_ptr<W>::swap

< cpp‎ | experimental‎ | observer ptr
constexpr void swap(observer_ptr& other) noexcept; | (库基础 TS v2)

通过在 *this 和 other 的存储指针上调用 swap ，交换 *this 和另一 observer_ptr 对象 other 的被查看对象。

参数

other - 要与之交换所查看对象的另一 observer_ptr 对象

返回值

（无）

示例

本节未完成
原因：暂无示例


std::experimental::swap(std::experimental::observer_ptr)

< cpp‎ | experimental‎ | observer ptr
template< class W > void swap( observer_ptr<W>& lhs, observer_ptr<W>& rhs ) noexcept; | (库基础 TS v2)

为 std::experimental::observer_ptr 特化 swap 算法。交换 lhs 与 rhs 的指针。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的 observer_ptr

返回值

（无）

复杂度

常数

参阅

swap | 交换两个对象的值 (函数模板)
swap | 交换所查看的对象 (公开成员函数)


std::experimental::ostream_joiner

< cpp‎ | experimental
定义于头文件 <experimental/iterator> |
template< class DelimT, class CharT = char, class Traits = std::char_traits <CharT>> class ostream_joiner; | (库基础 TS v2)

std::experimental::ostream_joiner 是为 std::basic_ostream 构造的单趟老式输出迭代器 (LegacyOutputIterator) ，它用 operator<< 写入分隔符所分隔相继对象到该流中。在每两个写入的对象间，写入分隔符到输出流。在赋值给迭代器（无论是否解引用）时进行写入操作。自增 ostream_joiner 是无操作。

典型实现中， ostream_joiner 仅有的数据成员是指向关联 std::basic_ostream 的指针、分隔符和指示下次写入是否对于序列中首元素的 bool 成员。

与 std::ostream_iterator 相比， ostream_joiner 少打印一次分隔符，并且不在待打印的对象类型上模板化。

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
ostream_type | std::basic_ostream <CharT, Traits>
value_type | void
difference_type | void
pointer | void
reference | void
iterator_category | std::output_iterator_tag

成员函数

(构造函数) | 创建新的 ostream_joiner (公开成员函数)
(析构函数) (隐式声明) | 销毁 ostream_joiner (公开成员函数)
operator= | 写入对象到关联输出序列 (公开成员函数)
operator* | 无操作 (公开成员函数)
operator++operator++(int) | 无操作 (公开成员函数)

非成员函数

make_ostream_joiner
 创建 ostream_joiner 对象，从函数参数推导模板实参
(函数模板)

示例

#include <algorithm>
#include <experimental/iterator>
#include <iostream>
#include <iterator>

int main()
{
    int i[] = {1, 2, 3, 4, 5};
    std::copy(std::begin(i),
              std::end(i),
              std::experimental::make_ostream_joiner(std::cout, ", "));
}

输出：

1, 2, 3, 4, 5

参阅

ostreambuf_iterator | 写入 std::basic_streambuf 的输出迭代器 (类模板)
ostream_iterator | 写入 std::basic_ostream 的输出迭代器 (类模板)
istream_iterator | 从 std::basic_istream 读取的输入迭代器 (类模板)


std::experimental::make_ostream_joiner

< cpp‎ | experimental‎ | ostream joiner
定义于头文件 <experimental/iterator>
template <class charT, class traits, class DelimT>

std::experimental::ostream_joiner < std::decay_t <DelimT>, charT, traits>

make_ostream_joiner( std::basic_ostream <charT, traits>& os, DelimT&& delimiter);
 (库基础 TS v2)

创建 ostream_joiner 对象，从函数实参的类型推导模板实参。

参数

os | - | 要将迭代器关联到的 basic_ostream 对象
delimiter | - | 分隔符

返回值

如同用 std::experimental::ostream_joiner < std::decay_t <DelimT>, charT, traits>(os, std::forward <DelimT>(delimiter)) 创建的 ostream_joiner 对象。

示例

本节未完成
原因：暂无示例


std::experimental::ostream_joiner<DelimT,CharT,Traits>::operator*

< cpp‎ | experimental‎ | ostream joiner
ostream_joiner& operator*() noexcept; | (库基础 TS v2)

不做任何事，提供此成员函数以满足老式输出迭代器 (LegacyOutputIterator) 的要求。

它返回迭代器自身，这使得可以用如 *iter = value 的代码输入（插入）值到底层流中。

参数

（无）

返回值

*this


std::experimental::ostream_joiner<DelimT,CharT,Traits>::operator=

< cpp‎ | experimental‎ | ostream joiner
template<class T> ostream_joiner& operator=(const T& value); | (1) | (库基础 TS v2)
ostream_joiner& operator=(const ostream_joiner& other) = default; | (2) | (库基础 TS v2) (隐式声明)
ostream_joiner& operator=(ostream_joiner&& other) = default; | (3) | (库基础 TS v2) (隐式声明)

1) 首先，若私有“首元素”标志为 false ，则如同用 os << delim; 插入分隔符 delim 到与此迭代器关联的输出流 os 中。

然后，无条件地设置“首元素”标志为 false ，然后如同用 os << value; 插入 value 到输出流中。

令 out_stream 、 delim 和 first_element 分别代表私有流指针、分隔符和“首元素”标志成员，则此函数等价于

if (!first_element)
    *out_stream << delim;
first_element = false;
*out_stream << value;
return *this;

2-3) 隐式声明的复制/移动赋值运算符，复制移动/赋值私有流指针、分隔符和“首元素”标志成员。

参数

value | - | 要写入到流的对象
other | - | 要被赋值给此对象的 ostream_joiner 对象

返回值

*this 。

示例

本节未完成
原因：暂无示例


std::experimental::ostream_joiner<DelimT,CharT,Traits>::operator++

< cpp‎ | experimental‎ | ostream joiner
ostream_joiner& operator++() noexcept; | (库基础 TS v2)
ostream_joiner& operator++( int ) noexcept; | (库基础 TS v2)

不做任何事。提供此成员函数以满足老式输出迭代器 (LegacyOutputIterator) 的要求。它们使得能用表达式 *iter++=value 和 *++iter=value 输出（插入）值到底层流中。

参数

（无）

返回值

*this


std::experimental::ostream_joiner<DelimT,CharT,Traits>::ostream_joiner

< cpp‎ | experimental‎ | ostream joiner
ostream_joiner(ostream_type& stream, const DelimT& delimiter); | (1) | (库基础 TS v2)
ostream_joiner(ostream_type& stream, DelimT&& delimiter); | (2) | (库基础 TS v2)
ostream_joiner(const ostream_joiner& other) = default; | (3) | (库基础 TS v2) (隐式声明)
ostream_joiner(ostream_joiner&& other) = default; | (4) | (库基础 TS v2) (隐式声明)

1) 构造迭代器，以 std::addressof (stream) 初始化私有 ostream_type* 成员，以 delimiter 初始化私有分隔符成员，并设置私有“首元素”标志为 true 。

2) 构造迭代器，以 std::addressof (stream) 初始化私有 ostream_type* 成员，以 std::move(delimiter) 初始化私有分隔符成员，并设置私有“首元素”标志为 true 。

3-4) 隐式声明的复制/移动构造函数，复制/移动构造私有流指针、分隔符和“首元素”标志成员。

参数

stream | - | 此迭代器要访问的输出流
delimiter | - | 要在二个输出间插入到流中的分隔符
other | - | ostream_joiner 对象，从它复制或移动构造此对象

示例

本节未完成
原因：暂无示例


并行扩展

< cpp‎ | experimental

C++ 并行扩展 (C++ Extensions for Parallelism) ， ISO/IEC TS 19570:2015 为 C++ 标准库定义下列新组件：

执行策略

并行 TS 描述三种执行策略：顺序、并行和并行加向量，并提供对应的执行策略类型和对象。用户可以通过以对应类型的执行策略对象调用并行算法，静态地选择执行策略，或用类型擦除的 execution_policy 类动态地选择执行策略。

实现可以定义额外的执行策略为扩展。以实现定义类型执行策略对象调用并行算法的语义是实现定义的。

定义于头文件 <experimental/execution_policy>
sequential_execution_policyparallel_execution_policyparallel_vector_execution_policy | 执行策略类型 (类)
seqparpar_vec | 全局执行策略对象 (常量)
execution_policy | 动态执行策略 (类)
is_execution_policy | 测试类是否表示执行策略 (类模板)

异常列表

定义于头文件 <experimental/exception_list>
exception_list
 在并行执行期间引发的异常
(类)

既存算法的并行化版本

该 TS 为来自 <algorithm> 、 <numeric> 和 <memory> 的下列 69 个算法提供并行化版本：

提供了并行化版本的标准库算法
  • std::adjacent_difference
  • std::adjacent_find
  • std::all_of
  • std::any_of
  • std::copy
  • std::copy_if
  • std::copy_n
  • std::count
  • std::count_if
  • std::equal
  • std::fill
  • std::fill_n
  • std::find
  • std::find_end
  • std::find_first_of
  • std::find_if
  • std::find_if_not
  • std::generate
  • std::generate_n
  • std::includes
  • std::inner_product
  • std::inplace_merge
  • std::is_heap
  • std::is_heap_until
  • std::is_partitioned
  • std::is_sorted
  • std::is_sorted_until
  • std::lexicographical_compare
  • std::max_element
  • std::merge
  • std::min_element
  • std::minmax_element
  • std::mismatch
  • std::move
  • std::none_of
  • std::nth_element
  • std::partial_sort
  • std::partial_sort_copy
  • std::partition
  • std::partition_copy
  • std::remove
  • std::remove_copy
  • std::remove_copy_if
  • std::remove_if
  • std::replace
  • std::replace_copy
  • std::replace_copy_if
  • std::replace_if
  • std::reverse
  • std::reverse_copy
  • std::rotate
  • std::rotate_copy
  • std::search
  • std::search_n
  • std::set_difference
  • std::set_intersection
  • std::set_symmetric_difference
  • std::set_union
  • std::sort
  • std::stable_partition
  • std::stable_sort
  • std::swap_ranges
  • std::transform
  • std::uninitialized_copy
  • std::uninitialized_copy_n
  • std::uninitialized_fill
  • std::uninitialized_fill_n
  • std::unique
  • std::unique_copy

新算法

定义于头文件 <experimental/algorithm>
for_each | 类似 std::for_each ，除了返回 void (函数模板)
for_each_n | 应用函数对象到序列的首 n 个元素 (函数模板)
定义于头文件 <experimental/numeric>
reduce (并行 TS) | 类似 std::accumulate ，除了不按顺序 (函数模板)
exclusive_scan | 类似 std::partial_sum ，从第 i 个和排除第 i 个输入元素 (函数模板)
inclusive_scan | 类似 std::partial_sum ，包含第 i 个元素于第 i 个和 (函数模板)
transform_reduce (并行 TS) | 应用函数对象，然后不按顺序规约 (函数模板)
transform_exclusive_scan | 应用函数对象，再计算 exclusive_scan (函数模板)
transform_inclusive_scan | 应用函数对象，再计算 inclusive_scan (函数模板)


并行扩展，版本 2

< cpp‎ | experimental

并行的 C++ 扩展版本 2 （ The C++ Extensions for Parallelism Version 2 ）， ISO/IEC TS 19570:2018 为 C++ 标准库定义下列新组件：

并行异常

定义于头文件 <experimental/exception_list>
exception_list
 并行执行期间引发的异常
(类)

执行策略

定义于头文件 <experimental/execution_policy>
unsequenced_policyvector_policy | 执行策略类型 (类)
unseqvec | 全局执行策略对象 (常量)

并行算法

本节未完成

任务块

本节未完成

数据并行类型

simd (并行 TS v2) | 数据并行向量类型 (类模板)
simd_mask (并行 TS v2) | 元素类型为 bool 的数据并行类型 (类模板)

特性测试宏

定义于头文件 <experimental/task_block>
__cpp_lib_experimental_parallel_task_block | 至少为 201711 的值，指示支持任务块功能 (宏常量)
定义于头文件 <experimental/execution>
__cpp_lib_experimental_execution_vector_policy | 至少为 201711 的值，指示支持向量和波前策略 (宏常量)
定义于头文件 <experimental/algorithm>
__cpp_lib_experimental_parallel_for_loop | 至少为 201711 的值，指示支持 for_loop 类的算法 (宏常量)
定义于头文件 <experimental/simd>
__cpp_lib_experimental_parallel_simd | 至少为 201803 的值，指示支持数据并行类型库 (宏常量)


std::experimental::propagate_const

< cpp‎ | experimental
定义于头文件 <experimental/propagate_const> |
template<class T> class propagate_const; | (库基础 TS v2)

std::experimental::propagate_const 是为指针和仿指针对象传播 const 的包装器。如名所示，在通过 const 访问路径访问时，它把被包装指针当做指向 const 的指针。

若底层的仿指针类型类满足可移动构造 (MoveConstructible) 和可移动赋值 (MoveAssignable) 的要求，则该类满足对应概念，但 propagate_const 既非可复制构造 (CopyConstructible) 亦非可复制赋值 (CopyAssignable) 。

类型要求
-
T 必须是下面指定的对象指针类型或仿指针类型。若 T 为数组类型、引用类型、指向函数指针类型、指向（可为 cv 限定的） void 指针类型，或若 decltype(* std::declval <T&>()) 不是左值引用类型，则程序为病式。

仿指针类型上的要求

若 T 为类类型，则它必须满足此节中的要求。

给定

  • t ， T 类型的可修改左值表达式
  • ct ，绑定到 T 的 const T&
  • element_type ，对象类型

下列表达式必须合法并拥有其指定的效果：

表达式 | 返回类型 | 前提条件 | 操作语义
t.get() | element_type* |  |
ct.get() | element_type* 或 const element_type* |  | t.get() == ct.get()
*t | element_type& | t.get() != nullptr | *t 与 *(t.get()) 指代同一对象
*ct | element_type& 或 const element_type& | ct.get() != nullptr | *ct 与 *(ct.get()) 指代同一对象
t.operator->() | element_type* | t.get() != nullptr | t.operator->() == t.get()
ct.operator->() | element_type* 或 const element_type* | ct.get() != nullptr | ct.operator->() == ct.get()
(bool)t | bool |  | (bool)t 等价于 t.get() != nullptr
(bool)ct | bool |  | (bool)ct 等价于 ct.get() != nullptr

还有， T 和 const T 应当可按语境转换为 bool 。

另外，若 T 可隐式转换为 element_type* ，则 (element_type*)t 应当等于 t.get() 。类似地，若 const T 可隐式转换为 const element_type* ，则 (const element_type*)ct 应当等于 ct.get() 。

成员类型

成员类型 | 定义
element_type | std::remove_reference_t <decltype(* std::declval <T&>())> ， T 所指向对象的类型

成员函数

(构造函数)
 构造新的 propagate_const
(公开成员函数)
(析构函数)
(隐式声明)
 销毁 propagate_const 并销毁所含指针
(公开成员函数)
operator=
 赋值 propagate_const 对象
(公开成员函数)
swap
 交换被包装指针
(公开成员函数)
观察器
get
 返回指向被包装指针所指向对象的指针
(公开成员函数)
operator bool
 检查被包装指针是否为空
(公开成员函数)
operator*operator->
 解引用被包装指针
(公开成员函数)
operator element_type*operator const element_type*
 到指针的隐式转换函数
(公开成员函数)

非成员函数

operator==operator!=operator<operator<=operator>operator>= | 与另一 propagate_const 、另一指针，或与 nullptr 比较 (函数模板)
std::experimental::swap(std::experimental::propagate_const) | 特化 swap 算法 (函数模板)
get_underlying | 获取到被包装仿指针对象的引用 (函数模板)

辅助类

std::hash<std::experimental::propagate_const> | propagate_const 的哈希支持 (类模板特化)
std::equal_to<std::experimental::propagate_const>std::not_equal_to<std::experimental::propagate_const>std::less<std::experimental::propagate_const>std::greater<std::experimental::propagate_const>std::less_equal<std::experimental::propagate_const>std::greater_equal<std::experimental::propagate_const> | 标准比较函数对象对 propagate_const 的特化 (类模板特化)

示例

#include <iostream>
#include <memory>
#include <experimental/propagate_const>

struct X
{
    void g() const { std::cout << "g (const)\n"; }
    void g() { std::cout << "g (non-const)\n"; }
};

struct Y
{
    Y() : m_ptrX(std::make_unique<X>()) { }

    void f() const
    {
        std::cout << "f (const)\n";
        m_ptrX->g();
    }

    void f()
    {
        std::cout << "f (non-const)\n";
        m_ptrX->g();
    }

    std::experimental::propagate_const<std::unique_ptr<X>> m_ptrX;
};

int main()
{
    Y y;
    y.f();

    const Y cy;
    cy.f();
}

输出：

f (non-const)
g (non-const)
f (const)
g (const)


std::equal_to, not_equal_to, less, greater, less_equal, greater_equal(std::experimental::propagate_const)

< cpp‎ | experimental‎ | propagate const
定义于头文件 <experimental/propagate_const> |
template<class T> struct equal_to< std::experimental::propagate_const <T>>; | (库基础 TS v2)
template<class T> struct not_equal_to< std::experimental::propagate_const <T>>; | (库基础 TS v2)
template<class T> struct less< std::experimental::propagate_const <T>>; | (库基础 TS v2)
template<class T> struct greater< std::experimental::propagate_const <T>>; | (库基础 TS v2)
template<class T> struct less_equal< std::experimental::propagate_const <T>>; | (库基础 TS v2)
template<class T> struct greater_equal< std::experimental::propagate_const <T>>; | (库基础 TS v2)

为 std::experimental::propagate_const <T> 部分特化标准比较函数对象。

令 p.t_ 代表 std::experimental::propagate_const <T> p 所包装的仿指针对象，则给定 std::experimental::propagate_const <T> 类型的指针 p 和 q ，下列应当成立：

  • std::equal_to < std::experimental::propagate_const <T>>()(p, q) == std::equal_to <T>()(p.t_, q.t_)
  • std::not_equal_to < std::experimental::propagate_const <T>>()(p, q) == std::not_equal_to <T>()(p.t_, q.t_)
  • std::less < std::experimental::propagate_const <T>>()(p, q) == std::less <T>()(p.t_, q.t_)
  • std::greater < std::experimental::propagate_const <T>>()(p, q) == std::greater <T>()(p.t_, q.t_)
  • std::less_equal < std::experimental::propagate_const <T>>()(p, q) == std::less_equal <T>()(p.t_, q.t_)
  • std::greater_equal < std::experimental::propagate_const <T>>()(p, q) == std::greater_equal <T>()(p.t_, q.t_)

注意

这些特化确保 T 为指针类型时，这些类模板对 std::experimental::propagate_const <T> 的特化产出全序，即使对应的内建运算符不如此。

示例

本节未完成
原因：暂无示例

参阅

equal_to | 实现 x == y 的函数对象 (类模板)
not_equal_to | 实现 x != y 的函数对象 (类模板)
less | 实现 x < y 的函数对象 (类模板)
greater | 实现 x > y 的函数对象 (类模板)
less_equal | 实现 x <= y 的函数对象 (类模板)
greater_equal | 实现 x >= y 的函数对象 (类模板)


std::experimental::propagate_const<T>::get

< cpp‎ | experimental‎ | propagate const
constexpr element_type* get(); | (库基础 TS v2)
constexpr const element_type* get() const; | (库基础 TS v2)

返回指向被包装的仿指针对象 t_ 所指向对象的指针。

参数

（无）

返回值

若 T 为对象指针类型，则为 t_ 。否则为 t_.get() 。

示例

本节未完成
原因：暂无示例


std::experimental::get_underlying

< cpp‎ | experimental‎ | propagate const
template< class T > constexpr T& get_underlying(propagate_const<T>& pt) noexcept; | (库基础 TS v2)
template< class T > constexpr const T& get_underlying(const propagate_const<T>& pt) noexcept; | (库基础 TS v2)

获得到存储于 propagate_const 中的仿指针对象的引用。

参数

pt - propagate_const 对象

返回值

到存储于 pt 中的仿指针对象的引用。


std::hash(std::experimental::propagate_const)

< cpp‎ | experimental‎ | propagate const
定义于头文件 <experimental/propagate_const> |
template<class T> struct hash< std::experimental::propagate_const <T>>; | (库基础 TS v2)

std::hash 对 std::experimental::propagate_const <T> 的类模板特化允许用户获得 std::experimental::propagate_const <T> 类型对象的哈希。

对于给定的 std::experimental::propagate_const <T> p ，此特化确保 std::hash < std::experimental::propagate_const <T>>()(p) == std::hash <T>()(p.t_) ，其中 p.t_ 是 p 所包装的仿指针对象。

示例

本节未完成
原因：暂无示例

参阅

hash
(C++11)
 散列函数对象
(类模板)


std::experimental::propagate_const<T>::operator*, std::experimental::propagate_const<T>::operator->

< cpp‎ | experimental‎ | propagate const
constexpr element_type& operator*(); | (1) | (库基础 TS v2)
constexpr const element_type& operator*() const; | (2) | (库基础 TS v2)
constexpr element_type* operator->(); | (3) | (库基础 TS v2)
constexpr const element_type* operator->() const; | (4) | (库基础 TS v2)

提供到 *this 所包装的仿指针对象所指向对象的访问。

若 get() == nullptr 则这些函数的行为未定义。

参数

（无）

返回值

1-2) 被包装的仿指针对象所指向的对象，即 *get() 。

3-4) 指向被包装的仿指针对象所指向的对象的指针，即 get() 。

参数

本节未完成
原因：暂无示例

参阅

get
 返回指向被包装指针所指向对象的指针
(公开成员函数)


std::experimental::propagate_const<T>::operator=

< cpp‎ | experimental‎ | propagate const
constexpr propagate_const& operator=( propagate_const&& p ) = default; | (1) | (库基础 TS v2)
template<class U> constexpr propagate_const& operator=( propagate_const<U>&& pu ); | (2) | (库基础 TS v2)
template<class U> constexpr propagate_const& operator=( U&& u ); | (3) | (库基础 TS v2)
propagate_const& operator=( const propagate_const& ) = delete; | (4) | (库基础 TS v2)

令 t_ 指代私有数据成员，即被包装的仿指针对象。

1) 显式默认化的移动赋值运算符，它从 p.t_ 移动赋值 this->t_ 。
2) 赋值 std::move(pu.t_) 给 this->t_ 。
此重载仅若 U 可隐式转换为 T 才参与重载决议。
3) 赋值 std::forward <U>(u) 给 this->t_ 。
此重载仅若 U 可隐式转换为 T 且 std::decay_t <U> 不是 propagate_const 的特化才参与重载决议。
4) 复制赋值运算符被显式删除。 propagate_const 不可复制。

参数

p | - | 要移动的另一 propagate_const 对象
pu | - | 要移动的另一不同特化的 propagate_const 对象
u | - | 赋值给所含指针的另一对象

返回值

*this 。


std::experimental::propagate_const<T>::operator bool

< cpp‎ | experimental‎ | propagate const
constexpr explicit operator bool() const; | (库基础 TS v2)

检查被包装仿指针对象 t_ 是否为空。

参数

（无）

返回值

若被包装对象非空则为 true ，否则为 false 。等价于 (bool)t_ 。

示例

本节未完成
原因：暂无示例

参阅

get
 返回指向被包装指针所指向对象的指针
(公开成员函数)


operator==,!=,<,<=,>,>=(std::experimental::propagate_const)

< cpp‎ | experimental‎ | propagate const
template <class T> constexpr bool operator==(const propagate_const<T>& pt, nullptr_t); | (1) | (库基础 TS v2)
template <class T> constexpr bool operator==(nullptr_t, const propagate_const<T>& pt); | (2) | (库基础 TS v2)
template <class T> constexpr bool operator!=(const propagate_const<T>& pt, nullptr_t); | (3) | (库基础 TS v2)
template <class T> constexpr bool operator!=(nullptr_t, const propagate_const<T>& pt); | (4) | (库基础 TS v2)
template <class T, class U> constexpr bool operator==(const propagate_const<T>& pt, const propagate_const<U>& pu); | (5) | (库基础 TS v2)
template <class T, class U> constexpr bool operator!=(const propagate_const<T>& pt, const propagate_const<U>& pu); | (6) | (库基础 TS v2)
template <class T, class U> constexpr bool operator<(const propagate_const<T>& pt, const propagate_const<U>& pu); | (7) | (库基础 TS v2)
template <class T, class U> constexpr bool operator>(const propagate_const<T>& pt, const propagate_const<U>& pu); | (8) | (库基础 TS v2)
template <class T, class U> constexpr bool operator<=(const propagate_const<T>& pt, const propagate_const<U>& pu); | (9) | (库基础 TS v2)
template <class T, class U> constexpr bool operator>=(const propagate_const<T>& pt, const propagate_const<U>& pu); | (10) | (库基础 TS v2)
template <class T, class U> constexpr bool operator==(const propagate_const<T>& pt, const U& u); | (11) | (库基础 TS v2)
template <class T, class U> constexpr bool operator!=(const propagate_const<T>& pt, const U& u); | (12) | (库基础 TS v2)
template <class T, class U> constexpr bool operator==(const T& t, const propagate_const<U>& pu); | (13) | (库基础 TS v2)
template <class T, class U> constexpr bool operator!=(const T& t, const propagate_const<U>& pu); | (14) | (库基础 TS v2)
template <class T, class U> constexpr bool operator<(const propagate_const<T>& pt, const U& u); | (15) | (库基础 TS v2)
template <class T, class U> constexpr bool operator>(const propagate_const<T>& pt, const U& u); | (16) | (库基础 TS v2)
template <class T, class U> constexpr bool operator<=(const propagate_const<T>& pt, const U& u); | (17) | (库基础 TS v2)
template <class T, class U> constexpr bool operator>=(const propagate_const<T>& pt, const U& u); | (18) | (库基础 TS v2)
template <class T, class U> constexpr bool operator<(const T& t, const propagate_const<U>& pu); | (19) | (库基础 TS v2)
template <class T, class U> constexpr bool operator>(const T& t, const propagate_const<U>& pu); | (20) | (库基础 TS v2)
template <class T, class U> constexpr bool operator<=(const T& t, const propagate_const<U>& pu); | (21) | (库基础 TS v2)
template <class T, class U> constexpr bool operator>=(const T& t, const propagate_const<U>& pu); | (22) | (库基础 TS v2)

在二个 propagate_const 的被包装指针，或一个 propagate_const 和 nullptr ，或一个 propagate_const 和另一对象之间比较。

1-4) propagate_const 和 nullptr 的相等比较。
5-6) 二个 propagate_const 的相等比较。
7-10) 二个 propagate_const 的顺序比较。
11-14) 一个 propagate_const 和另一对象的相等比较。
15-22) 一个 propagate_const 和另一对象的顺序比较。

参数

pt, pu | - | 要比较的 propagate_const
t, u | - | 要比较的另一对象

返回值

令 t_ 代表 propagate_const 所包装的底层仿指针对象

1) pt.t_ == nullptr
2) nullptr == pt.t_
3) pt.t_ != nullptr
4) nullptr != pt.t_
5) pt.t_ == pu.t_
6) pt.t_ != pu.t_
7) pt.t_ < pu.t_
8) pt.t_ > pu.t_
9) pt.t_ <= pu.t_
10) pt.t_ >= pu.t_
11) pt.t_ == u
12) pt.t_ != u
13) t == pu.t_
14) t != pu.t_
15) pt.t_ < u
16) pt.t_ > u
17) pt.t_ <= u
18) pt.t_ >= u
19) t < pu.t_
20) t > pu.t_
21) t <= pu.t_
22) t >= pu.t_


std::experimental::propagate_const<T>::operator element_type*, std::experimental::propagate_const<T>::operator const element_type*

< cpp‎ | experimental‎ | propagate const
constexpr operator element_type*(); | (1) | (库基础 TS v2)
constexpr operator const element_type*() const; | (2) | (库基础 TS v2)

提供到 element_type* 和 const element_type* 的隐式转换。

1) 此函数仅若 T 为指向对象指针类型，或可隐式转换为 element_type* 才参与重载决议。

2) 此函数仅若 T 为指向对象指针类型，或可隐式转换为 const element_type* 才参与重载决议。

参数

（无）

返回值

指向被包装的仿指针对象所指向对象的指针，即 this->get() 。

示例

本节未完成
原因：暂无示例

参阅

get
 返回指向被包装指针所指向对象的指针
(公开成员函数)


std::experimental::propagate_const<T>::propagate_const

< cpp‎ | experimental‎ | propagate const
constexpr propagate_const() = default; | (1) | (库基础 TS v2)
constexpr propagate_const( propagate_const&& p ) = default; | (2) | (库基础 TS v2)
template<class U> /* see below */ constexpr propagate_const( propagate_const<U>&& pu ); | (3) | (库基础 TS v2)
template<class U> /* see below */ constexpr propagate_const( U&& u ); | (4) | (库基础 TS v2)
propagate_const( const propagate_const& ) = delete; | (5) | (库基础 TS v2)

令 t_ 指代私有数据成员，即被包装的仿指针对象。

1) 构造 propagate_const ，默认初始化 this->t_ 。
2) 显式默认化的移动构造函数，从 p.t_ 移动构造 this->t_ 。
3) 如同以直接非列表初始化，从表达式 std::move(pu.t_) 初始化 this->t_ 。
此构造函数仅若 std::is_constructible <T, U>::value 为 true 才参与重载决议，若且唯若 std::is_convertible <U, T>::value 为 false 才为 explicit 。
4) 如同以直接非列表初始化，用表达式 std::forward <U>(u) 初始化 this->t_ 。
此构造函数仅若 std::is_constructible <T, U>::value 为 true 而 std::decay_t <U> 不是 propagate_const 的特化才参与重载决议。此构造函数若且唯若 std::is_convertible <U, T>::value 为 false 才为 explicit 。
5) 复制构造函数被显式删除。 propagate_const 不可复制。

参数

p | - | 要移动的另一 propagate_const 对象
pu | - | 要移动的另一不同特化的 propagate_const 对象
u | - | 用来初始化所含指针的另一对象

注解

在库基础 TS v2 （基于 C++14 ）中， (4) 与 (5) 常以 explicit/非 explicit 重载对实现。从库基础 TS v3 （基于 C++20 ）起，它们能以条件性 explicit 说明符实现。


std::experimental::propagate_const<T>::swap

< cpp‎ | experimental‎ | propagate const
constexpr void swap(propagate_const & pt) noexcept(/* see below */); | (库基础 TS v2)

交换被包装指针和 pt 的被包装指针。令 t_ 指代私有数据成员，即被包装的仿指针对象，则此函数等价于 swap(t_, pt.t_) ，其中对 swap 的重载决议在 std::swap 与通常查找规则所找到的任何声明之间进行，如在可交换 (Swappable) 中描述。

若 T 的左值不满足可交换 (Swappable) 则行为未定义。

参数

pt - 要与之交换的另一 propagate_const 对象

异常

noexcept 说明： noexcept(noexcept(swap(t_, pt.t_))) 异常说明中标识符 swap 的查找找到上述的重载，并且不找到成员函数自身，使得异常说明等价于 C++17 std::is_nothrow_swappable 。 | (库基础 TS v2)
noexcept 说明： noexcept( std::is_nothrow_swappable_v <T>) | (库基础 TS v3)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3413 | LFTSv2 | 异常说明为谬构 | 使之为良构


std::experimental::swap(std::experimental::propagate_const)

< cpp‎ | experimental‎ | propagate const
template< class T > constexpr void swap( std::experimental::propagate_const <T>& lhs, std::experimental::propagate_const <T>& rhs ) noexcept(/* see below */); | (库基础 TS v2)

为 std::experimental::propagate_const 特化 swap 算法。交换 lhs 与 rhs 的指针。等价于 lhs.swap(rhs) 。

此重载仅若 std::is_swappable_v <T> 为 true 才参与重载决议。

 (库基础 TS v3)

参数

lhs, rhs - 要交换内容的 propagate_const

返回值

（无）

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))

复杂度

常数

参阅

swap | 交换两个对象的值 (函数模板)
swap | 交换被包装指针 (公开成员函数)


std::experimental::randint

< cpp‎ | experimental
定义于头文件 <experimental/random> |
template <class IntType> IntType randint(IntType a, IntType b); | (库基础 TS v2)

生成闭区间 [a, b] 中的随机整数。

参数

a, b - 指定范围的整数值

返回值

用逐线程随机数引擎调用 std::uniform_int_distribution <IntType> 的线程局域实例生成的闭区间 [a, b] 中的随机整数 i 。

提醒

若 IntType 不是 short 、 int 、 long 、 long long 、 unsigned short 、 unsigned int 、 unsigned long 或 unsigned long long 之一，则程序非良构。

若 a > b 则行为未定义。

示例

#include <iostream>
#include <experimental/random>

int main()
{
    int random_number = std::experimental::randint(100, 999);
    std::cout << "random 3-digit number: " << random_number << '\n';
}

可能的输出：

random 3-digit number: 273

参阅

reseed
 重播种单个线程的随机引擎
(函数)


范围扩展

< cpp‎ | experimental

C++ 范围扩展 (Extensions for Ranges) ， ISO/IEC TS 21425:2017 指定对核心语言的一个修改，并为 C++ 标准库定义列于此页面的新组件。

范围 TS 基于概念 TS 所修改的 C++14 标准。

核心语言更改

范围 TS 修改基于范围的 for 循环规定，以容许不同类型的 begin 和 end 迭代器。此更改容许使用哨位，并且已存在于 C++17 。

概念

核心语言概念
定义于头文件 <experimental/ranges/concepts>
定义于命名空间 std::experimental::ranges
Same
 指定类型与另一类型相同
(概念)
DerivedFrom
 指定该类型从另一类型派生
(概念)
ConvertibleTo
 指定类型能隐式转换成另一类型
(概念)
CommonReference
 指定两个类型共有一个公共引用类型
(概念)
Common
 指定两个类型共有一个公共类型
(概念)
Integral
 指定类型为整型类型
(概念)
SignedIntegral
 指定类型为有符号的整型类型
(概念)
UnsignedIntegral
 指定类型为无符号的整型类型
(概念)
Assignable
 指定类型可从另一类型赋值
(概念)
SwappableSwappableWith
 指定一个类型能进行交换，或两个类型能彼此交换
(概念)
比较概念
定义于头文件 <experimental/ranges/concepts>
定义于命名空间 std::experimental::ranges
Boolean
 指定类型能用于布尔语境
(概念)
WeaklyEqualityComparableWith
 指定两个类型能用运算符 == 和 != 比较相等性
(概念)
EqualityComparableEqualityComparableWith
 指定运算符 == 是等价关系
(概念)
StrictTotallyOrderedStrictTotallyOrderedWith
 指定该类型上的比较运算符产出全序
(概念)
对象概念
定义于头文件 <experimental/ranges/concepts>
定义于命名空间 std::experimental::ranges
Destructible
 指定该类型对象能被销毁，且能用一元 & 取其地址
(概念)
Constructible
 指定该类型的变量能从一组实参类型进行构造，或绑定到一组实参类型
(概念)
DefaultConstructible
 指定该类型对象能默认构造
(概念)
MoveConstructible
 指定该类型的对象能移动构造
(概念)
CopyConstructible
 指定该类型对象能复制构造及移动构造
(概念)
Movable
 指定该类型的对象能被移动和交换
(概念)
Copyable
 指定该类型对象能被复制、移动和交换
(概念)
Semiregular
 指定类型的对象能被复制、移动、交换及默认构造
(概念)
Regular
 指定类型为正则，即为 Semiregular 且为 EqualityComparable
(概念)
可调用概念
定义于头文件 <experimental/ranges/concepts>
定义于命名空间 std::experimental::ranges
InvocableRegularInvocable
 指定可调用类型能以给定的一组实参调用
(概念)
Predicate
 指定可调用类型是布尔谓词
(概念)
Relation
 指定可调用类型为二元关系
(概念)
StrictWeakOrder
 指定一种 Relation 施加严格弱序
(概念)
随机数生成器概念
定义于头文件 <experimental/ranges/random>
定义于命名空间 std::experimental::ranges
UniformRandomNumberGenerator
 指定类型具备作为均匀随机数生成器的资格
(概念)

通用工具

工具组件
定义于头文件 <experimental/ranges/utility>
定义于命名空间 std::experimental::ranges
swap
 交换两个对象的值
(定制点对象)
exchange
 以新值替换实参并返回其先前的值
(函数模板)
函数对象
定义于头文件 <experimental/ranges/functional>
定义于命名空间 std::experimental::ranges
invoke
 以给定实参调用可调用 (Callable) 对象
(函数模板)
equal_to
 实现 x == y 的函数对象
(类模板)
not_equal_to
 实现 x != y 的函数对象
(类模板)
greater
 实现 x > y 的函数对象
(类模板)
less
 实现 x < y 的函数对象
(类模板)
greater_equal
 实现 x >= y 的函数对象
(类模板)
less_equal
 实现 x <= y 的函数对象
(类模板)
identity
 返回其（未改变的）实参的函数对象
(类)
元编程与类型特性
定义于头文件 <experimental/ranges/type_traits>
定义于命名空间 std::experimental::ranges
is_swappable_withis_swappableis_nothrow_swappable_withis_nothrow_swappable
 检查一个类型的对象是否能与相同或不同类型的对象交换
(类模板)
common_reference
 确定类型集合的公共引用类型
(类模板)
common_type
 确定类型集合的公共类型
(类模板)
有标签的 pair 与 tuple
定义于头文件 <experimental/ranges/utility>
定义于命名空间 std::experimental::ranges
TagSpecifier
 指定类型为标签说明符
(概念)
TaggedType
 指定类型表示一个标签说明符及其元素类型
(概念)
tagged
 为元组式类型增加具名访问器
(类模板)
tagged_pair
 有标签 std::pair 的别名模版
(别名模板)
make_tagged_pair
 用于创建 tagged_pair 的便利函数
(函数模板)
定义于头文件 <experimental/ranges/tuple>
tagged_tuple
 有标签 std::tuple 的别名模版
(别名模板)
make_tagged_tuple
 用于创建 tagged_tuple 的便利函数
(函数模板)
定义于头文件 <experimental/ranges/algorithm>
定义于命名空间 std::experimental::ranges::tag
inin1in2outout1out2funminmaxbeginend
 用于 ranges::tagged 的标签说明符
(类)

迭代器

定义于头文件 <experimental/ranges/iterator>
迭代器相关概念
定义于命名空间 std::experimental::ranges
迭代器概念
Readable
 指定类型通过应用运算符 * 可读
(概念)
Writable
 指定可向迭代器所引用的对象写入值
(概念)
WeaklyIncrementable
 指定 Semiregular 类型能以前后自增运算符自增
(概念)
Incrementable
 指定 WeaklyIncrementable 类型上的自增操作保持相等性，而且该类型 EqualityComparable
(概念)
Iterator
 指定该类型对象能自增并解引用
(概念)
Sentinel
 指定类型的对象是 Iterator 类型的哨位
(概念)
SizedSentinel
 指定能应用 - 运算符到迭代器和哨位，以在常数时间计算其差
(概念)
InputIterator
 指定类型为输入迭代器，即能读其所引用值，且它能前后自增
(概念)
OutputIterator
 指定类型为给定值类型的输出迭代器，即能把该类型的值写入它，且它能前后自增
(概念)
ForwardIterator
 指定 InputIterator 为向前迭代器，支持相等比较和多趟
(概念)
BidirectionalIterator
 指定 ForwardIterator 为双向迭代器，支持向后移动
(概念)
RandomAccessIterator
 指定 BidirectionalIterator 为随机访问迭代器，支持常数时间前进和下标访问
(概念)
间接可调用概念
IndirectUnaryInvocableIndirectRegularUnaryInvocable
 指定可调用对象能以解引用一个 Readable 类型的结果调用
(概念)
IndirectUnaryPredicate
 指定可调用对象，以解引用某个 Readable 类型的结果调用时，满足 Predicate
(概念)
IndirectRelation
 指定可调用对象以解引用某些 Readable 类型的结果调用时，满足 Relation
(概念)
IndirectStrictWeakOrder
 指定可调用对象，以解引用某些 Readable 类型的结果调用时，满足 StrictWeakOrder
(概念)
常用算法要求
IndirectlyMovable
 指定值可从 Readable 类型移动到 Writable 类型
(概念)
IndirectlyMovableStorable
 指定类型可从 Readable 类型移动到 Writable 类型，且移动可以通过中间对象进行
(概念)
IndirectlyCopyable
 指定值可从 Readable 类型复制到 Writable 类型
(概念)
IndirectlyCopyableStorable
 指定值可从 Readable 类型复制到 Writable 类型，且该复制可能通过中间对象进行
(概念)
IndirectlySwappable
 指定两个 Readable 类型所引用的值可交换
(概念)
IndirectlyComparable
 指定两个 Readable 类型所引用的值能比较
(概念)
Permutable
 指定原位重排元素的算法的公共要求
(概念)
Mergeable
 指定算法的要求，该算法需要通过复制元素归并已排序序列到输出序列
(概念)
Sortable
 指定重排元素为有序序列的算法的公共要求
(概念)
概念工具
indirect_result_of
 计算在某 Readable 类型集合的解引用结果上调用可调用对象的结果
(类模板)
projected
 用于指定接受投影的算法上的制约的帮助模板
(类模板)
迭代器原语
迭代器工具
定义于命名空间 std::experimental::ranges
iter_move
 转型解引用对象的结果为其所关联的右值引用类型
(定制点对象)
iter_swap
 交换两个可解引用对象所引用的值
(定制点对象)
迭代器特性
定义于命名空间 std::experimental::ranges
difference_type
 获得 WeaklyIncrementable 类型的差类型
(类模板)
value_type
 获得 Readable 类型的值类型
(类模板)
iterator_category
 获得输入迭代器类型的迭代器类别
(类模板)
iterator_traits
 汇集迭代器的关联类型的兼容性特性类
(别名模板)
reference_trvalue_reference_titer_common_reference_t
 获得可解引用对象的关联引用类型
(别名模板)
迭代器类别标签
定义于命名空间 std::experimental::ranges
input_iterator_tagoutput_iterator_tagforward_iterator_tagbidirectional_iterator_tagrandom_access_iterator_tag
 用于指示迭代器类别的空类
(类)
std::iterator_traits 特化
定义于命名空间 std
std::iterator_traits<InputIterator>std::iterator_traits<OutputIterator>
 为范围 TS 迭代器特化 std::iterator_traits
(类模板特化)
迭代器操作
定义于命名空间 std::experimental::ranges
advance
 令迭代器前进给定的距离
(函数模板)
distance
 返回迭代器和哨位之间的距离，或范围起始和结尾间的距离
(函数模板)
next
 自增迭代器
(函数模板)
prev
 自减迭代器
(函数模板)
迭代器适配器
定义于命名空间 std::experimental::ranges
reverse_iterator
 用于逆序遍历的迭代器适配器
(类模板)
back_insert_iterator
 用于在容器尾插入的迭代器适配器
(类模板)
front_insert_iterator
 用于在容器首插入的迭代器适配器
(类模板)
insert_iterator
 用于插入元素到容器中的迭代器适配器
(类模板)
move_iterator
 解引用为右值引用的迭代器适配器
(类模板)
move_sentinel
 为 move_iterator 所用的哨位适配器
(类模板)
common_iterator
 将迭代器-哨位对适配成公共迭代器类型，以用于遗留算法
(类模板)
counted_iterator
 保持距起始位置距离踪迹的迭代器适配器
(类模板)
default_sentinel
 知晓其范围的迭代器类型所用的空哨位类型
(类)
dangling
 可能悬垂的迭代器的包装器
(类模板)
safe_iterator_t
 以 dangling 包装右值范围的迭代器类型的别名模版
(别名模板)
unreachable
 用于与任何迭代器一同指示无限范围的哨位类型
(类)
流迭代器
定义于命名空间 std::experimental::ranges
istream_iterator
 从 std::basic_istream 读取的输入迭代器
(类模板)
ostream_iterator
 写入 std::basic_ostream 的输出迭代器
(类模板)
istreambuf_iterator
 从 std::basic_streambuf 读取的输入迭代器
(类模板)
ostreambuf_iterator
 写入 std::basic_streambuf 的输出迭代器
(类模板)

范围

定义于头文件 <experimental/ranges/range>
范围概念
Range
 指定类型为范围，即它提供 begin 迭代器和 end 哨位
(概念)
SizedRange
 指定范围以常数时间知晓其大小
(概念)
View
 指定范围为视图，即它拥有常数时间的复制/移动/赋值
(概念)
BoundedRange
 指定范围拥有等同的迭代器和哨位类型
(概念)
InputRange
 指定范围的迭代器满足 InputIterator
(概念)
OutputRange
 指定范围的迭代器满足 OutputIterator
(概念)
ForwardRange
 指定范围的迭代器满足 ForwardIterator
(概念)
BidirectionalRange
 指定范围的迭代器满足 BidirectionalIterator
(概念)
RandomAccessRange
 指定范围的迭代器满足 RandomAccessIterator
(概念)
范围访问
定义于命名空间 std::experimental::ranges
begincbegin
 返回指向范围起始的迭代器
(定制点对象)
endcend
 返回指向范围末尾的迭代器
(定制点对象)
rbegincrbegin
 获得指向范围的逆向迭代器
(定制点对象)
rendcrend
 获得指向范围的逆向尾迭代器
(定制点对象)
范围原语
定义于命名空间 std::experimental::ranges
size
 获得能在常数时间计算大小的范围的大小
(定制点对象)
empty
 检查范围是否为空
(定制点对象)
datacdata
 获得指向连续范围起始的指针
(定制点对象)
iterator_tsentinel_t
 获得范围的迭代器类型与哨位类型
(别名模板)

算法

定义于头文件 <experimental/ranges/algorithm>
不修改序列的操作
定义于命名空间 std::experimental::ranges
all_ofany_ofnone_of
 检查谓词是否对范围中所有、任一或无元素为 true
(函数模板)
for_each
 应用函数到元素范围
(函数模板)
countcount_if
 返回满足特定判别标准的元素数
(函数模板)
mismatch
 寻找两个范围出现不同的首个位置
(函数模板)
equal
 确定元素的二个集合是否相同
(函数模板)
lexicographical_compare
 当一个范围按字典顺序小于另一个范围时，返回 true
(函数模板)
findfind_iffind_if_not
 寻找首个满足特定判别标准的元素
(函数模板)
find_end
 在特定范围中寻找最后出现的元素序列
(函数模板)
find_first_of
 搜索元素集中的任何元素
(函数模板)
adjacent_find
 寻找头两个相等（或满足给定谓词）的相邻项
(函数模板)
search
 搜索一个元素范围
(函数模板)
search_n
 在范围中搜索一定量的某个元素的连续副本
(函数模板)
修改序列的操作
定义于命名空间 std::experimental::ranges
copycopy_if
 将某一范围的元素复制到一个新的位置
(函数模板)
copy_n
 将一定数目的元素复制到一个新的位置
(函数模板)
copy_backward
 按从后往前的顺序复制一个范围内的元素
(函数模板)
move
 将某一范围的元素移动到一个新的位置
(函数模板)
move_backward
 按从后往前的顺序移动某一范围的元素到新的位置
(函数模板)
fill
 将一个特定值赋值给一个元素范围
(函数模板)
fill_n
 将一个值赋值给一定数量的元素
(函数模板)
transform
 应用一个函数到元素范围
(函数模板)
generate
 保存函数结果于一个范围中
(函数模板)
generate_n
 保存 N 次应用一个函数的结果
(函数模板)
removeremove_if
 移除满足特定判别标准的元素
(函数模板)
remove_copyremove_copy_if
 复制元素范围，忽略满足特定判别标准的元素
(函数模板)
replacereplace_if
 将所有满足特定判别标准的值替换为另一值
(函数模板)
replace_copyreplace_copy_if
 复制范围，以另一值替换满足特定判别标准的元素
(函数模板)
swap_ranges
 交换两个元素范围
(函数模板)
reverse
 逆转范围中的元素顺序
(函数模板)
reverse_copy
 创建一个范围的逆向副本
(函数模板)
rotate
 旋转范围中的元素顺序
(函数模板)
rotate_copy
 复制并旋转元素范围
(函数模板)
shuffle
 随机重排范围中的元素
(函数模板)
unique
 移除范围中连续的重复元素
(函数模板)
unique_copy
 创建某范围的不含连续重复元素的副本
(函数模板)
划分操作
定义于命名空间 std::experimental::ranges
is_partitioned
 判断范围是否已按给定的谓词划分
(函数模板)
partition
 将范围中的元素分为两组
(函数模板)
partition_copy
 复制一个范围，将各元素分为两组
(函数模板)
stable_partition
 划分元素到两个组中，同时保持其相对顺序
(函数模板)
partition_point
 定位已划分范围的划分点
(函数模板)
排序操作
定义于命名空间 std::experimental::ranges
is_sorted
 检查范围是否以升序排序
(函数模板)
is_sorted_until
 寻找最大已排序子范围
(函数模板)
sort
 将范围按升序排序
(函数模板)
partial_sort
 排序一个范围的前 N 个元素
(函数模板)
partial_sort_copy
 对范围内的元素进行复制并部分排序
(函数模板)
stable_sort
 将范围内的元素排序，同时保持相等的元素之间的顺序
(函数模板)
nth_element
 将给定的范围部分排序，确保其按给定元素划分
(函数模板)
二分搜索操作（在已排序范围上）
定义于命名空间 std::experimental::ranges
lower_bound
 返回指向首个不小于给定值的元素的迭代器
(函数模板)
upper_bound
 返回指向首个大于固定值的元素的迭代器
(函数模板)
binary_search
 确定元素是否存在于固定范围中
(函数模板)
equal_range
 返回匹配特定关键的元素范围
(函数模板)
集合操作（在已排序范围上）
定义于命名空间 std::experimental::ranges
merge
 归并两个已排序范围
(函数模板)
inplace_merge
 就地归并两个已排序范围
(函数模板)
includes
 若一个集合是另一个的子集则返回 true
(函数模板)
set_difference
 计算两个集合的差集
(函数模板)
set_intersection
 计算两个集合的交集
(函数模板)
set_symmetric_difference
 计算两个集合的对称差
(函数模板)
set_union
 计算两个集合的并集
(函数模板)
堆操作
定义于命名空间 std::experimental::ranges
is_heap
 检查给定范围是否为一个最大堆
(函数模板)
is_heap_until
 寻找作为最大堆的最大子范围
(函数模板)
make_heap
 从元素范围中创建出最大堆
(函数模板)
push_heap
 添加元素到最大堆
(函数模板)
pop_heap
 从最大堆移除最大元素
(函数模板)
sort_heap
 将最大堆转化成以升序排序的元素范围
(函数模板)
最小/最大操作
定义于命名空间 std::experimental::ranges
max
 返回给定值的较大者
(函数模板)
max_element
 返回范围中的最大元素
(函数模板)
min
 返回给定值的较小者
(函数模板)
min_element
 返回范围中的最小元素
(函数模板)
minmax
 返回二个元素的较小和较大者
(函数模板)
minmax_element
 返回范围中的最小和最大元素
(函数模板)
排列操作
定义于命名空间 std::experimental::ranges
is_permutation
 判断一个序列是否为另一个序列的排列
(函数模板)
next_permutation
 产生某个元素范围的按字典顺序的下一个较大的排列
(函数模板)
prev_permutation
 产生某个元素范围的按字典顺序的下一个较小的排列
(函数模板)


std::experimental::ranges::all_of, std::experimental::ranges::any_of, std::experimental::ranges::none_of

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/algorithm>
template< ranges::InputIterator I, ranges::Sentinel <I> S,

class Proj = ranges::identity,
ranges::IndirectUnaryPredicate < ranges::projected <I, Proj>> Pred >

bool all_of( I first, S last, Pred pred, Proj proj = Proj{} );
 (1) (范围 TS)
template< ranges::InputRange Rng, class Proj = ranges::identity,

ranges::IndirectUnaryPredicate <
ranges::projected <ranges::iterator_t<Rng>, Proj>
> Pred >

bool all_of( Rng&& rng, Pred pred, Proj proj = Proj{} );
 (2) (范围 TS)
template< ranges::InputIterator I, ranges::Sentinel <I> S,

class Proj = ranges::identity,
ranges::IndirectUnaryPredicate < ranges::projected <I, Proj>> Pred >

bool any_of( I first, S last, Pred pred, Proj proj = Proj{} );
 (3) (范围 TS)
template< ranges::InputRange Rng, class Proj = ranges::identity,

ranges::IndirectUnaryPredicate <
ranges::projected <ranges::iterator_t<Rng>, Proj>
> Pred >

bool any_of( Rng&& rng, Pred pred, Proj proj = Proj{} );
 (4) (范围 TS)
template< ranges::InputIterator I, ranges::Sentinel <I> S,

class Proj = identity,
ranges::IndirectUnaryPredicate < ranges::projected <I, Proj>> Pred >

bool none_of( I first, S last, Pred pred, Proj proj = Proj{} );
 (5) (范围 TS)
template< ranges::InputRange Rng, class Proj = ranges::identity,

ranges::IndirectUnaryPredicate <
ranges::projected <ranges::iterator_t<Rng>, Proj>
> Pred >

bool none_of( Rng&& rng, Pred pred, Proj proj = Proj{} );
 (6) (范围 TS)
1) 检查一元谓词 pred 是否对范围 [first, last) 中的所有元素返回 true 。
3) 检查一元谓词 pred 是否对范围 [first, last) 中至少一个元素返回 true 。
5) 检查一元谓词 pred 是否不对范围 [first, last) 中任何元素返回 true 。
2,4,6) 同 (1,3,5) ，但以 rng 为源范围，如同使用 ranges::begin(rng) 和 ranges::end(rng) 。

参数

first, last | - | 要检验的元素范围
rng | - | 要检验的元素范围
pred | - | 应用到投影后元素的谓词
proj | - | 应用到元素的投影

返回值

1-2) 若 pred 对范围中所有元素返回 true 则为 true ，否则为 false 。若范围为空则返回 true 。
3-4) 若 pred 对范围中至少一个元素返回 true 则为 true ，否则为 false 。若范围为空则返回 false 。
5-6) 若 pred 不对范围中任何元素返回 true 则为 true ，否则为 false 。若范围为空则返回 true 。

复杂度

1-6) 至多应用 last - first 次谓词，应用 last - first 次投影。

可能的实现

版本一
template< ranges::InputIterator I, ranges::Sentinel<I> S, class Proj = ranges::identity,
   ranges::IndirectUnaryPredicate<ranges::projected<I, Proj>> Pred >
bool all_of( I first, S last, Pred pred, Proj proj = Proj{} )
{
   return ranges::find_if_not(first, last, std::ref(pred), std::ref(proj)) == last;
}

template< ranges::InputRange Rng, class Proj = ranges::identity,
   ranges::IndirectUnaryPredicate<ranges::projected<ranges::iterator_t<Rng>, Proj>> Pred >
bool all_of( Rng&& rng, Pred pred, Proj proj = Proj{} )
{
   return ranges::all_of(ranges::begin(rng), ranges::end(rng), std::ref(pred), std::ref(proj));
}
版本二
template< ranges::InputIterator I, ranges::Sentinel<I> S, class Proj = ranges::identity,
   ranges::IndirectUnaryPredicate<ranges::projected<I, Proj>> Pred >
bool any_of( I first, S last, Pred pred, Proj proj = Proj{} )
{
   return ranges::find_if(first, last, std::ref(pred), std::ref(proj)) != last;
}

template< ranges::InputRange Rng, class Proj = ranges::identity,
   ranges::IndirectUnaryPredicate<ranges::projected<ranges::iterator_t<Rng>, Proj>> Pred >
bool any_of( Rng&& rng, Pred pred, Proj proj = Proj{} )
{
   return ranges::any_of(ranges::begin(rng), ranges::end(rng), std::ref(pred), std::ref(proj));
}
版本三
template< ranges::InputIterator I, ranges::Sentinel<I> S, class Proj = identity,
   ranges::IndirectUnaryPredicate<ranges::projected<I, Proj>> Pred >
bool none_of( I first, S last, Pred pred, Proj proj = Proj{} )
{
   return ranges::find_if(first, last, std::ref(pred), std::ref(proj)) == last;
}

template< ranges::InputRange Rng, class Proj = ranges::identity,
   ranges::IndirectUnaryPredicate<ranges::projected<ranges::iterator_t<Rng>, Proj>> Pred >
bool none_of( Rng&& rng, Pred pred, Proj proj = Proj{} )
{
   return ranges::none_of(ranges::begin(rng), ranges::end(rng), std::ref(pred), std::ref(proj));
}

示例

#include <vector>
#include <numeric>
#include <experimental/ranges/algorithm>
#include <experimental/ranges/iterator>
#include <iterator>
#include <iostream>
#include <functional>

namespace ranges = std::experimental::ranges;

int main()
{
    std::vector<int> v(10, 2);
    std::partial_sum(v.cbegin(), v.cend(), v.begin());
    std::cout << "Among the numbers: ";
    ranges::copy(v, ranges::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';

    if (ranges::all_of(v.cbegin(), v.cend(), [](int i){ return i % 2 == 0; })) {
        std::cout << "All numbers are even\n";
    }
    if (ranges::none_of(v, std::bind(std::modulus<int>(), std::placeholders::_1, 2))) {
        std::cout << "None of them are odd\n";
    }
    struct DivisibleBy
    {
        const int d;
        DivisibleBy(int n) : d(n) {}
        bool operator()(int n) const { return n % d == 0; }
    };

    if (ranges::any_of(v, DivisibleBy(7))) {
        std::cout << "At least one number is divisible by 7\n";
    }
}

输出：

Among the numbers: 2 4 6 8 10 12 14 16 18 20
All numbers are even
None of them are odd
At least one number is divisible by 7

参阅

all_ofany_ofnone_of
(C++11)(C++11)(C++11)
 检查谓词是否对范围中所有、任一或无元素为 true
(函数模板)


std::experimental::ranges::copy, std::experimental::ranges::copy_if

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/algorithm>
template < ranges::InputIterator I, ranges::Sentinel <I> S,

ranges::WeaklyIncrementable O >
requires ranges::IndirectlyCopyable <I, O>
ranges::tagged_pair<ranges::tag::in(I), ranges::tag::out(O)>

copy(I first, S last, O result);
 (1) (范围 TS)
template < ranges::InputRange Rng, ranges::WeaklyIncrementable O >

requires ranges::IndirectlyCopyable <ranges::iterator_t<Rng>, O>
ranges::tagged_pair<
ranges::tag::in(ranges::safe_iterator_t<Rng>), ranges::tag::out(O)>

copy(Rng&& rng, O result);
 (2) (范围 TS)
template < ranges::InputIterator I, ranges::Sentinel <I> S,

ranges::WeaklyIncrementable O,
class Proj = ranges::identity,
ranges::IndirectUnaryPredicate < ranges::projected <I, Proj>> Pred >
requires ranges::IndirectlyCopyable <I, O>
ranges::tagged_pair<ranges::tag::in(I), ranges::tag::out(O)>

copy_if(I first, S last, O result, Pred pred, Proj proj = Proj{});
 (3) (范围 TS)
template < ranges::InputRange Rng, ranges::WeaklyIncrementable O,

class Proj = ranges::identity,
ranges::IndirectUnaryPredicate <
ranges::projected <ranges::iterator_t<Rng>, Proj>> Pred >
requires ranges::IndirectlyCopyable <iterator_t<Rng>, O>
ranges::tagged_pair<
ranges::tag::in(ranges::safe_iterator_t<Rng>), ranges::tag::out(O)>

copy_if(Rng&& rng, O result, Pred pred, Proj proj = Proj{});
 (4) (范围 TS)

复制源范围（ [first,last) 或 rng ）中的元素到始于 result 的目标范围中，从源范围的首元素开始，后续到末元素。

1) 复制范围 [first, last) 中的所有元素。对每个非负整数 n < (last - first) 进行 *(result + n) = *(first + n) 。若 result 在范围 [first, last) 内则行为未定义。此情况下可用 ranges::copy_backward 代替。
2) 同 (1) ，但以 rng 为源范围，如同用 ranges::copy(ranges::begin(rng), ranges::end(rng), result); ，除了不可复制 result 。
3) 仅复制应用谓词 pred 到投影 proj 所投影的元素值时，对其返回 true 的元素。保持复制后的元素顺序。若源与目标范围重叠则行为未定义。
4) 同 (3) ，但以 rng 为源范围，如同用 ranges::copy_if(ranges::begin(rng), ranges::end(rng), result, pred, proj); ，除了不可复制 result 、 pred 和 proj 。

参数

first, last | - | 要复制的元素范围
rng | - | 要复制的元素范围
result | - | 目标范围的起始
pred | - | 要应用到投影后元素的谓词
proj | - | 要应用到元素的投影

返回值

含有以下二个成员的 tagged_pair 对象：

  • 第一成员有标签 tag::in ，为源范围的尾后迭代器（即比较等于哨位 last 的 I 类型迭代器）。
  • 第二成员有标签 tag::out ，为结果范围的尾后迭代器。

复杂度

1) 准确赋值 ranges::distance(first, last) 次。
2) 准确赋值 ranges::distance(rng) 次。
3) 准确应用 ranges::distance(first, last) 次对应的投影和谓词。
3) 准确应用 ranges::distance(rng) 次对应的投影和谓词。

可能的实现

版本一
template <ranges::InputIterator I, ranges::Sentinel<I> S, ranges::WeaklyIncrementable O>
  requires ranges::IndirectlyCopyable<I, O>()
ranges::tagged_pair<ranges::tag::in(I), ranges::tag::out(O)>
  copy(I first, S last, O result)
{
    for (; first != last; ++first, (void)++result)
        *result = *first;
    return {first, result};
}
版本二
template <ranges::InputRange Rng, ranges::WeaklyIncrementable O>
  requires ranges::IndirectlyCopyable<ranges::iterator_t<Rng>, O>()
ranges::tagged_pair<ranges::tag::in(ranges::safe_iterator_t<Rng>), ranges::tag::out(O)>
  copy(Rng&& rng, O result)
{
   return ranges::copy(ranges::begin(rng), ranges::end(rng), result);
}
版本三
template <ranges::InputIterator I, ranges::Sentinel<I> S, ranges::WeaklyIncrementable O,
          class Proj = ranges::identity,
          ranges::IndirectUnaryPredicate<ranges::projected<I, Proj>> Pred>
  requires ranges::IndirectlyCopyable<I, O>()
ranges::tagged_pair<ranges::tag::in(I), ranges::tag::out(O)>
  copy_if(I first, S last, O result, Pred pred, Proj proj = Proj{})
{
    for (; first != last; ++first) {
        if (ranges::invoke(pred, ranges::invoke(proj, *first))){
            *result = *first;
            ++result;
        }
    }
    return {first, result};
}
版本四
template <ranges::InputRange Rng, ranges::WeaklyIncrementable O,
          class Proj = ranges::identity,
          ranges::IndirectUnaryPredicate<
              ranges::projected<ranges::iterator_t<Rng>, Proj>> Pred>
  requires ranges::IndirectlyCopyable<ranges::iterator_t<Rng>, O>()
ranges::tagged_pair<ranges::tag::in(ranges::safe_iterator_t<Rng>), ranges::tag::out(O)>
  copy_if(Rng&& rng, O result, Pred pred, Proj proj = Proj{})
{
   return ranges::copy_if(ranges::begin(rng), ranges::end(rng), result, pred, proj);
}

示例

下列代码用 copy 复制一个 vector 的内容给另一个，并显示结果 vector ：

#include <experimental/ranges/algorithm>
#include <iostream>
#include <vector>
#include <experimental/ranges/iterator>
#include <numeric>

int main()
{
    // 参阅 http://zh.cppreference.com/w/cpp/language/namespace_alias
    namespace ranges = std::experimental::ranges;

    std::vector<int> from_vector(10);
    std::iota(from_vector.begin(), from_vector.end(), 0);

    std::vector<int> to_vector;
    ranges::copy_if(from_vector.begin(), from_vector.end(),
                    ranges::back_inserter(to_vector),
                    [](const auto i) {
                       return i % 3;
                    });
// 或替用的
//  std::vector<int> to_vector(from_vector.size());
//  std::copy(from_vector, to_vector.begin());

    std::cout << "to_vector contains: ";

    ranges::copy(to_vector, ranges::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
}

输出：

to_vector contains: 1 2 4 5 7 8

参阅

copycopy_if (C++11) | 将某一范围的元素复制到一个新的位置 (函数模板)
copy_backward | 按从后往前的顺序复制一个范围内的元素 (函数模板)
reverse_copy | 创建一个范围的逆向副本 (函数模板)
copy_n | 将一定数目的元素复制到一个新的位置 (函数模板)
fill | 将一个特定值赋值给一个元素范围 (函数模板)
remove_copyremove_copy_if | 复制元素范围，忽略满足特定判别标准的元素 (函数模板)


std::experimental::ranges::equal

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/algorithm>
template< InputIterator I1, Sentinel<I1> S1, InputIterator I2, Sentinel<I2> S2,

class Pred = ranges::equal_to<>,
class Proj1 = ranges::identity, class Proj2 = ranges::identity >
requires IndirectlyComparable<I1, I2, Pred, Proj1, Proj2>
bool equal(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = Pred{},

Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});
 (1) (范围 TS)
template< InputRange R1, InputRange R2, class Pred = ranges::equal_to<>,

class Proj1 = ranges::identity, class Proj2 = ranges::identity >
requires IndirectlyComparable<ranges::iterator_t<R1>, ranges::iterator_t<R2>,
Pred, Proj1, Proj2>
bool equal(R1&& r1, R2&& r2, Pred pred = Pred{},

Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});
 (2) (范围 TS)
template< InputIterator I1, Sentinel<I1> S1, class I2,

class Pred = ranges::equal_to<>,
class Proj1 = ranges::identity, class Proj2 = ranges::identity >
requires InputIterator< std::decay_t <I2>> && !Range<I2> &&
IndirectlyComparable<I1, std::decay_t <I2>, Pred, Proj1, Proj2>
bool equal(I1 first1, S1 last1, I2&& first2_, Pred pred = Pred{},

Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});
 (3) (范围 TS)
(弃用)
template< InputRange R1, class I2, class Pred = ranges::equal_to<>,

class Proj1 = ranges::identity, class Proj2 = ranges::identity >
requires InputIterator< std::decay_t <I2>> && !Range<I2> &&
IndirectlyComparable<ranges::iterator_t<R1>, std::decay_t <I2>, Pred, Proj1, Proj2>
bool equal(R1&& r1, I2&& first2_, Pred pred = Pred{},

Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});
 (4) (范围 TS)
(弃用)
1) 若范围 [first1, last1) 等于 [first2, last2) 则返回 true ，否则返回 false 。
2) 同 (1) ，但以 r1 为第一源范围并以 r2 为第二源范围，如同以 ranges::begin(r1) 为 first1 ，以 ranges::end(r1) 为 last1 ，以 ranges::begin(r2) 为 first2 并以 ranges::end(r2) 为 last2 。
3) 同 (1) ，除了在穷尽第一范围或检测到首个不匹配时认为第二范围结束。等价于 return last1 == ranges::mismatch(first1, last1, std::forward <I2>(first2_), comp, proj1, proj2).in1(); 。
4) 同 (3) ，但以 r1 为第一源范围，如同以 ranges::begin(r1) 为 first1 并以 ranges::end(r1) 为 last1 。

若二个范围有相同数量的元素，且对于范围 [first1,last1) 中的每个迭代器 i ， ranges::invoke(pred, ranges::invoke(proj1, *i), ranges::invoke(proj2, *(first2 + (i - first1)))) 为 true ，则认为二个范围相等。

尽管声明描述如上，算法声明的模板形参的实际数量和顺序是未指定的。从而若在调用算法时使用显式模板实参，则程序很可能不可移植。

参数

first1, last1 | - | 第一元素范围
r1 | - | 第一元素范围
first2, last2 | - | 第二元素范围
r2 | - | 第二元素范围
first2_ | - | 第二元素范围的起始
pred | - | 应用到投影后元素的谓词
proj1 | - | 应用到第一范围中元素的投影
proj2 | - | 应用到第二范围中元素的投影

返回值

若二个范围相等则为 true ，否则返回 false 。

注意

不应该用 ranges::equal 比较来自 std::unordered_set 、 std::unordered_multiset 、 std::unordered_map 或 std::unordered_multimap 的迭代器所组成的范围，因为即使二个容器存储相同的元素，在容器中存储元素的顺序也可能不同。

比较整个容器是否相等时，通常更偏好使用对应容器的 operator== 。

复杂度

1-2) 若满足 SizedSentinel<S1, I1> && SizedSentinel<S2, I2> 且 last1 - first1 != last2 - first2 ，则不应用谓词和投影。否则至多应用 min(last1 - first1, last2 - first2) 次谓词及各一次投影。
3-4) 至多应用 last1 - first1 次谓词及各一次投影。

可能的实现

namespace detail
{
    template< InputIterator I1, SizedSentinel<I1> S1,
              InputIterator I2, SizedSentinel<I1> S2 >
    bool check_size(I1& first1, S1& last1, I2& first2, S2& last2)
    {
        return last1 - first1 != last2 - first2;
    }

    template< InputIterator I1, Sentinel<I1> S1, InputIterator I2, Sentinel<I1> S2 >
    bool check_size(I1& first1, S1& last1, I2& first2, S2& last2)
    {
        return false;
    }
}

template< InputIterator I1, Sentinel<I1> S1, InputIterator I2, Sentinel<I2> S2,
          class Pred = ranges::equal_to<>,
          class Proj1 = ranges::identity, class Proj2 = ranges::identity >
  requires IndirectlyComparable<I1, I2, Pred, Proj1, Proj2>
bool equal(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = Pred{},
           Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{})
{
    if(detail::check_size(first1, last1, first2, last2)) return false;
    for(; first1 != last1 && first2 != last2; (void) ++first1, (void)++first2) {
        if(!ranges::invoke(pred, ranges::invoke(proj1, *first1),
                                 ranges::invoke(proj2, *first2))) {
            return false;
        }
    }
    return first1 == last1 && first2 == last2;
}

示例

本节未完成
原因：暂无示例

参阅

equal | 确定两个元素集合是否是相同的 (函数模板)
findfind_iffind_if_not | 寻找首个满足特定判别标准的元素 (函数模板)
lexicographical_compare | 当一个范围按字典顺序小于另一个范围时，返回 true (函数模板)
mismatch | 寻找两个范围出现不同的首个位置 (函数模板)
search | 搜索一个元素范围 (函数模板)


std::experimental::ranges::for_each

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/algorithm>
template< InputIterator I, Sentinel<I> S, class Proj = ranges::identity,

IndirectUnaryInvocable<projected<I, Proj>> Fun >
ranges::tagged_pair<tag::in(I), tag::fun(Fun)>

for_each(I first, S last, Fun f, Proj proj = Proj{});
 (1) (范围 TS)
template< InputRange R, class Proj = ranges::identity,

IndirectUnaryInvocable<projected<ranges::iterator_t<R>, Proj>> Fun >
ranges::tagged_pair<tag::in(ranges::safe_iterator_t<R>), tag::fun(Fun)>

for_each(R&& r, Fun f, Proj proj = Proj{});
 (2) (范围 TS)
1) 按顺序，调用给定的函数对象 f 到在解引用范围 [first, last) 中的每个迭代器时调用的投影 proj 的结果（即 ranges::invoke(f, ranges::invoke(proj, *i)) ）。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

对于两个重载，若迭代器类型可变，则 f 可以通过解引用后的迭代器修改范围的元素。若 f 返回结果，则湖绿结果。

不同于另外的算法，不允许 for_each 复制序列中的元素，即使它们为可平凡复制。

不同于 std::for_each （它只要求可移动构造 (MoveConstructible) ），这些函数要求 Fun 实现 CopyConstructible 。

尽管声明描述如上，算法声明的模板形参的实际数量和顺序是未指定的。从而若在调用算法时使用显式模板实参，则程序很可能不可移植。

参数

first, last | - | 要应用函数到的范围
r | - | 要应用函数到的范围
f | - | 应用到每个投影后的范围中元素的可调用对象
proj | - | 应用到元素的投影

返回值

含有列二个成员的 tagged_pair ：

  • 第一成员带标签 tag::in ，是源范围的尾后迭代器（即比较等于哨位 last 的 I 类型迭代器）。
  • 第二成员带标签 tag::fun ，（在该函数对象的所有应用后）从 std::move(f) 初始化。

复杂度

准确应用 last - first 次 f 和 proj 。

可能的实现

template< InputIterator I, Sentinel<I> S, class Proj = ranges::identity,
          IndirectUnaryInvocable<ranges::projected<I, Proj>> Fun >
auto for_each(I first, S last, Fun f, Proj proj = Proj{})
    -> ranges::tagged_pair<tag::in(I), tag::fun(Fun)>
{
    for(; first != last; ++first) {
        ranges::invoke(f, ranges::invoke(proj, *first));
    }
    return {std::move(first), std::move(f)};
}

示例

本节未完成
原因：暂无示例

参阅

transform | 应用一个函数到元素范围 (函数模板)
范围 for 循环 (C++11) | 执行范围上的循环
for_each | 应用函数到范围中的元素 (函数模板)
for_each_n (C++17) | 应用一个函数对象到序列的前 n 个元素 (函数模板)


std::experimental::ranges::sort

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/algorithm>
template< ranges::RandomAccessIterator I, ranges::Sentinel <I> S,

class Comp = ranges::less<>, class Proj = ranges::identity>
requires ranges::Sortable <I, Comp, Proj>

I sort( I first, S last, Comp comp = Comp{}, Proj proj = Proj{} );
 (1) (范围 TS)
template< ranges::RandomAccessRange Rng,

class Comp = ranges::less<>, class Proj = ranges::identity>
requires ranges::Sortable <ranges::iterator_t<Rng>, Comp, Proj>
ranges::safe_iterator_t<Rng> sort( Rng&& rng, Comp comp = Comp{},

Proj proj = Proj{} );
 (2) (范围 TS)
1) 以升序排序范围 [first, last) 中的元素。不保证保持相等元素的顺序。在应用投影 proj 后用 comp 比较元素。
2) 排序范围 rng 中的元素，如同用 return ranges::sort(ranges::begin(rng), ranges::end(rng), comp, proj); 。

参数

first, last | - | 要排序的元素范围
rng | - | 要排序的元素范围
comp | - | 要使用的比较器
proj | - | 要应用到范围中元素的投影

返回值

指向范围尾后一位置的迭代器（即它对于重载 (1) 等于 last ，对于重载 ranges::end(rng) 等于 (2) ）。

复杂度

O(N·log(N)) 次比较，其中 N 等于范围中的元素数。

示例

本节未完成
原因：暂无示例

参阅

sort
 将范围按升序排序
(函数模板)


std::experimental::ranges::tag::in, in1, in2, out, out1, out2, fun, min, max, begin, end

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/algorithm>
struct in { /* implementation-defined */ };

struct in1 { /* implementation-defined */ };
struct in2 { /* implementation-defined */ };
struct out { /* implementation-defined */ };
struct out1 { /* implementation-defined */ };
struct out2 { /* implementation-defined */ };
struct fun { /* implementation-defined */ };
struct min { /* implementation-defined */ };
struct max { /* implementation-defined */ };
struct begin { /* implementation-defined */ };

struct end { /* implementation-defined */ };
 (范围 TS)

这些类是 ranges::tagged 所用的 TagSpecifier 。

指定符的名称亦为其所对应的元素名。例如， ranges::tagged< std::pair <int, int>, tag::min, tag::max> 提供一组名为 min 的具名访问器和一组名为 max 的具名访问器。


std::experimental::ranges::Assignable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts>
template < class T, class U >

concept bool Assignable =
std::is_lvalue_reference <T>::value &&
ranges::CommonReference <
const std::remove_reference_t <T>&,
const std::remove_reference_t <U>&> &&
requires(T t, U&& u) {
{ t = std::forward <U>(u) } -> ranges::Same <T>&&;

};
 (范围 TS)

概念 Assignable<T, U> 指定类型和值类别为 U 所指定的表达式能被赋值给类型为 T 所指定的左值表达式。

给定

  • t ， std::remove_reference_t <T> 类型的指代对象 o 的左值，
  • u ，使得 decltype((u)) 为 U 的表达式，
  • u2 ，等于 u 的另一对象。

Assignable<T, U> 得到满足，仅若

  • std::addressof (t = u) == std::addressof (o) （即赋值表达式产生指代左运算数的左值）；
  • 求值 t = u 后：
    • t 等于 u2 ，除非 u 是指代 o 的非 const 亡值（即赋值是自移动赋值），
    • 若 u 为泛左值：
      • 若它是非 const 亡值，则其所指代的对象在合法但未指定的状态；
      • 否则，不修改其所指代的对象；

Assignable<T, U> 与 std::is_lvalue_reference <T>::value 间不必有任何蕴含关系。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常运算数。必须不修改常运算数。

注意

{ expression } -> Same<T>&& 形式的推导制约等效地要求 decltype((expression))&& 为与 T&& 准确相同的类型。这会制约表达式的类型与其值类别。

赋值不需要是全函数。特别是，若赋值给某对象 x 能导致修改某个其他对象 y ，则 x = y 可能不在 = 的定义域中。若右运算数直接或间接地为左运算数所占有（例如用基于结点的数据结构中的指向结点的智能指针，或用类似 std::vector < std::any > 的构造），则这通常会发生。


std::experimental::ranges::Boolean

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts>
template <class B>

concept bool Boolean =
ranges::Movable < std::decay_t <B>> &&
requires(const std::remove_reference_t <B>& b1,
const std::remove_reference_t <B>& b2, const bool a) {
{ b1 } -> ranges::ConvertibleTo <bool>&&;
{ !b1 } -> ranges::ConvertibleTo <bool>&&;
{ b1 && a } -> ranges::Same <bool>&&;
{ b1 || a } -> ranges::Same <bool>&&;
{ b1 && b2 } -> ranges::Same <bool>&&;
{ a && b2 } -> ranges::Same <bool>&&;
{ b1 || b2 } -> ranges::Same <bool>&&;
{ a || b2 } -> ranges::Same <bool>&&;
{ b1 == b2 } -> ranges::ConvertibleTo <bool>&&;
{ b1 == a } -> ranges::ConvertibleTo <bool>&&;
{ a == b2 } -> ranges::ConvertibleTo <bool>&&;
{ b1 != b2 } -> ranges::ConvertibleTo <bool>&&;
{ b1 != a } -> ranges::ConvertibleTo <bool>&&;
{ a != b2 } -> ranges::ConvertibleTo <bool>&&;

};
 (范围 TS)

概念 Boolean<B> 指定可用于布尔语境的类型的要求。对于要满足 Boolean 的类型，逻辑运算符必须拥有通常行为（包括短路求值）。更精确地说，给定

  • b1 、 b2 ，二个 const std::remove_reference_t <B> 类型左值，

Boolean<B> 仅若满足下列条件才得到满足：

  • bool(b1) == !bool(!b1)
  • b1 && b2 、 b1 && bool(b2) 和 bool(b1) && b2 全部等于 bool(b1) && bool(b2) 并拥有相同的短路求值；
  • b1 || b2 、 b1 || bool(b2) 和 bool(b1) || b2 全部等于 bool(b1) || bool(b2) ，并拥有相同的短路求值；
  • bool(b1 == b2) 、 bool(b1 == bool(b2)) 和 bool(bool(b1) == b2) 全部等于 (bool(b1) == bool(b2)) ；
  • bool(b1 != b2) 、 bool(b1 != bool(b2)) 和 bool(bool(b1) != b2) 全部等于 (bool(b1) != bool(b2)) 。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常运算数。必须不修改常运算数。

隐式表达式变种

使用不修改某 const 左值运算数的表达式的 requires 表达式亦隐式要求该表达式的额外变种对给定运算数接受非 const 左值或（可为 const 的）右值，除非以有区别的语义显式要求这种表达式变种。这些隐式表达式变种必须符合与声明的表达式的相同的语义。不指定实现以何种程度校验变种的语法。

注意

Boolean 的例子包含 bool 、 std::true_type 和 std::bitset <N>::reference 。指针不是 Boolean 类型。

{ expression } -> Same<T>&& 形式的推导制约等效地要求 decltype((expression))&& 为与 T&& 准确相同的类型。这会制约表达式的类型与其值类别。


std::experimental::ranges::Common

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts>
template <class T, class U>

concept bool Common =
ranges::Same <ranges::common_type_t<T, U>, ranges::common_type_t<U, T>> &&
ranges::ConvertibleTo <T, ranges::common_type_t<T, U>> &&
ranges::ConvertibleTo <U, ranges::common_type_t<T, U>> &&
ranges::CommonReference <
std::add_lvalue_reference_t <const T>,
std::add_lvalue_reference_t <const U>> &&
ranges::CommonReference <
std::add_lvalue_reference_t <common_type_t<T, U>>,
ranges::common_reference_t<
std::add_lvalue_reference_t <const T>,

std::add_lvalue_reference_t <const U>>>;
 (范围 TS)

概念 Common<T, U> 指定二个类型 T 与 U 共享能一同转换到 共用类型（由 ranges::common_type_t 计算）。

Common<T, U> 仅若满足下列条件才得到满足。给定表达式 t 和 u ，满足 decltype((t)) 为 T 而 decltype((u)) 为 U ，

  • ranges::common_type_t<T, U>(t) 等于 ranges::common_type_t<T, U>(t) ，若且唯若 t 是保持相等性的表达式；且
  • ranges::common_type_t<T, U>(u) 等于 ranges::common_type_t<T, U>(u) ，若且唯若 u 是保持相等性的表达式。

换言之，到共用类型的转换必须不改变原表达式的相等性保持属性。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

参阅

common_type | 确定类型集合的公共类型 (类模板)
common_reference | 确定类型集合的公共引用类型 (类模板)
CommonReference | 指定两个类型共有一个公共引用类型 (概念)


std::experimental::ranges::CommonReference

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts>
template < class T, class U >

concept bool CommonReference =
ranges::Same <ranges::common_reference_t<T, U>, ranges::common_reference_t<U, T>> &&
ranges::ConvertibleTo <T, ranges::common_reference_t<T, U>> &&

ranges::ConvertibleTo <U, ranges::common_reference_t<T, U>>;
 (范围 TS)

概念 CommonReference<T, U> 指定二个类型 T 与 U 共享都能转换到的共用引用类型（由 ranges::common_reference_t 计算）。

CommonReference<T, U> 仅若满足下列条件才得到满足。给定表达式 t 和 u 使得 decltype((t)) 为 T 而 decltype((u)) 为 U ，

  • 若且唯若 t 为保持相等性的表达式， ranges::common_reference_t<T, U>(t) 才等于 ranges::common_reference_t<T, U>(t) ；且
  • 若且唯若 u 为保持相等性的表达式， ranges::common_reference_t<T, U>(u) 才等于 ranges::common_reference_t<T, U>(u) 。

换言之，转换到共用引用类型必须不改变原表达式的相等性保持属性。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

参阅

common_reference | 确定类型集合的公共引用类型 (类模板)
Common | 指定两个类型共有一个公共类型 (概念)
common_type | 确定类型集合的公共类型 (类模板)


std::experimental::ranges::Constructible

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts> |
template < class T, class... Args > concept bool Constructible = ranges::Destructible <T> && std::is_constructible <T, Args...>::value; | (范围 TS)

Constructible 概念指定 T 类型变量能以给定的参数类型集合 Args... 初始化。

Constructible<T, Args...> 与 std::is_constructible <T, Args...>::value 间不必有任何蕴含关系。

参阅

is_constructibleis_trivially_constructibleis_nothrow_constructible
(C++11)(C++11)(C++11)
 检查类型是否带有针对特定实参的构造函数
(类模板)


std::experimental::ranges::ConvertibleTo

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts>
template <class From, class To>

concept bool ConvertibleTo =
std::is_convertible <From, To>::value &&
requires(From (&f)()) {
static_cast<To>(f());

};
 (范围 TS)

概念 ConvertibleTo<From, To> 指定拥有 From 所指定的类型和值类别的表达式能隐式和显式转换为类型 To ，且二种转换形式等价。

具体而言， ConvertibleTo<From, To> 仅若满足以下条件才得到满足。给定虚设函数 To test(From (&f)()) { return f(); } 和 From () 类型函数 F ，使得表达式 F() 保持相等性（见后述），而

  • 以下之一
    • To 既非对象类型亦非到对象引用类型，或
    • static_cast<To>(f()) 等于 test(f) ，且
  • 下列之一为真：
    • From 不是到对象引用类型，或
    • From 为到非 const 限定的右值引用类型，且 f() 所引用对象的结果状态合法，但在任一上述表达式后未指定；或
    • f() 所指代的对象不为任一上述表达式所修改。

ConvertibleTo<From, To> 与 std::is_convertible <From, To>::value 间不必有任何蕴含关系。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常运算数。必须不修改常运算数。

参阅

is_convertibleis_nothrow_convertible
(C++11)(C++20)
 检查是否能转换一个类型为另一类型
(类模板)


std::experimental::ranges::CopyConstructible

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts>
template <class T>

concept bool CopyConstructible =
ranges::MoveConstructible <T> &&
ranges::Constructible <T, T&> && ranges::ConvertibleTo <T&, T> &&
ranges::Constructible <T, const T&> && ranges::ConvertibleTo <const T&, T> &&

ranges::Constructible <T, const T> && ranges::ConvertibleTo <const T, T>;
 (范围 TS)

概念CopyConstructible 得到满足，若 T 为左值引用类型，或若它是MoveConstructible对象类型，其中该类型对象能在直接和复制初始化语境中，从该类型（可能为 const 的）左值或 const 右值以通常语义构造（构造副本而不更改源）。

更精确而言，若 T 为对象类型，则 CopyConstructible<T> 仅若满足下列条件才得到满足，给定

  • v ，（可为 const 的） T 类型左值或 const T 类型右值，

下列为真

  • 定义 T u = v; 后， u 等于 v ；
  • T{v} 等于 v 。

参阅

is_copy_constructibleis_trivially_copy_constructibleis_nothrow_copy_constructible
(C++11)(C++11)(C++11)
 检查类型是否拥有复制构造函数
(类模板)


std::experimental::ranges::Copyable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts>
template <class T>

concept bool Copyable =
ranges::CopyConstructible <T> &&
ranges::Movable <T> &&

ranges::Assignable <T&, const T&>;
 (范围 TS)

概念 Copyable<T> 指定 T 为 Movable 对象类型，并且亦能复制（即它支持复制构造和复制赋值）。

注解

Copyable<T> 亦有意要求 ranges::Assignable <T&, const T> （从 const 右值赋值）和 ranges::Assignable <T&, T&> （从非 const 左值赋值）得到满足。

参阅

Movable
 指定该类型的对象能被移动和交换
(概念)


std::experimental::ranges::DefaultConstructible

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts> |
template < class T > concept bool DefaultConstructible = ranges::Constructible <T>; | (范围 TS)

DefaultConstructible 概念为问题为能否以无参数构造类型时的常见情况提供快捷方式。

参阅

Constructible | 指定该类型的变量能从一组实参类型进行构造，或绑定到一组实参类型 (概念)
is_default_constructibleis_trivially_default_constructibleis_nothrow_default_constructible (C++11)(C++11)(C++11) | 检查类型是否有默认构造函数 (类模板)


std::experimental::ranges::DerivedFrom

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts> |
template < class T, class U > concept bool DerivedFrom = std::is_base_of <U, T>::value && std::is_convertible < std::remove_cv_t <T>*, std::remove_cv_t <U>*>::value; | (范围 TS)

概念 DerivedFrom<T, U> 若且唯若 U 为类类型且为 T 或 T 的无歧义公开基类才得到满足。

无关乎在其上述描述中使用 std::is_base_of 和 std::is_convertible 。不要求 DerivedFrom 在其实现中使用用它们。故而 DerivedFrom<T, U> 和 std::is_base_of <U,T>::value 或 std::is_convertible < std::remove_cv_t <T>*, std::remove_cv_t <U>*>::value 间不必有任何蕴含关系。

参阅

is_base_of (C++11) | 检查一个类型是否派生自另一个类型 (类模板)
is_convertibleis_nothrow_convertible (C++11)(C++20) | 检查是否能转换一个类型为另一类型 (类模板)


std::experimental::ranges::Destructible

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts> |
template < class T > concept bool Destructible = std::is_nothrow_destructible <T>::value; | (范围 TS)

概念 Destructible 指定所有能在其生存期结尾安全销毁的类型（包括引用类型）。

Destructible<T> 与 std::is_nothrow_destructible <T>::value 间不需要有任何蕴含关系。

注意

不同于主要 C++ 标准中的可析构 (Destructible) 库概念， ranges::Destructible 要求析构函数为 noexcept(true) ，而不仅是在调用时不抛异常，并且允许引用类型和数组类型。

参阅

is_destructibleis_trivially_destructibleis_nothrow_destructible
(C++11)(C++11)(C++11)
 检查类型是否拥有未被弃置的析构函数
(类模板)


std::experimental::ranges::EqualityComparable, std::experimental::ranges::EqualityComparableWith

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts>
template < class T >
concept bool EqualityComparable = ranges::WeaklyEqualityComparableWith <T, T>;
 (1) (范围 TS)
template <class T, class U>

concept bool EqualityComparableWith =
ranges::EqualityComparable<T> &&
ranges::EqualityComparable<U> &&
ranges::CommonReference <
const std::remove_reference_t <T>&,
const std::remove_reference_t <U>&> &&
ranges::EqualityComparable<
ranges::common_reference_t<
const std::remove_reference_t <T>&,
const std::remove_reference_t <U>&>> &&

ranges::WeaklyEqualityComparableWith <T, U>;
 (2) (范围 TS)
1) 概念 EqualityComparable<T> 指定 T 上的比较运算符 == 与 != 反应相等性： == 若且唯若运算数相等才产出 true 。
EqualityComparable<T> 仅若符合下列条件才得到满足。给定 T 类型对象 a 与 b ，若且唯若 a 与 b 相等 bool(a == b) 才为 true 。伴随 a == b 保持相等性的要求，这蕴含 == 对称且传递，进而 == 对所有至少等于一个其他对象的对象 a 自反。
2) 概念 EqualityComparableWith<T, U> 指定（可能混合的） T 与 U 运算数上的 == 与 != 产出的结果与相等性一致。比较混合运算数生成的结果等价于比较转换到其共用类型的运算数。
正式而言， EqualityComparableWith<T, U> 仅若符合下列条件才得到满足。给定任何 const std::remove_reference_t <T> 类型左值 t 与任何 const std::remove_reference_t <U> 类型左值 u ，并令 C 为 ranges::common_reference_t<const std::remove_reference_t <T>&, const std::remove_reference_t <U>&> ，有 bool(t == u) == bool(C(t) == C(u)) 。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

隐式表达式变种

使用不修改某 const 左值运算数的表达式的 requires 表达式亦隐式要求该表达式的额外变种对给定运算数接受非 const 左值或（可为 const 的）右值，除非以有区别的语义显式要求这种表达式变种。这些隐式表达式变种必须符合与声明的表达式的相同的语义。不指定实现以何种程度校验变种的语法。


std::experimental::ranges::Integral

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts> |
template < class T > concept bool Integral = std::is_integral <T>::value; | (范围 TS)

概念 Integral<T> 若且唯若 T 为整数类型才得到满足。

Integral<T> 与 std::is_integral <T>::value 间不需要有任何蕴含关系。

参阅

is_integral
(C++11)
 检查类型是否为整型
(类模板)


std::experimental::ranges::Invocable, std::experimental::ranges::RegularInvocable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts>
template < class F, class... Args >

concept bool Invocable =
requires(F&& f, Args&&... args) {
ranges::invoke( std::forward <F>(f), std::forward <Args>(args)...);
/* 不要求保持相等性 */

};
 (范围 TS)
template < class F, class... Args >
concept bool RegularInvocable = Invocable<F, Args...>;
 (范围 TS)

Invocable 概念指定能用函数 ranges::invoke 以参数类型 Args... 调用可调用类型 F 。

RegularInvocable 概念添加 invoke 表达式保持相等性且不修改函数对象或参数的要求到 Invocable 概念。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

注意

Invocable 与 RegularInvocable 间的区别是纯语义上的。

随机数生成器可满足 Invocable ，但不能满足 RegularInvocable （除了搞笑 的）。


std::experimental::ranges::Movable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts>
template < class T >

concept bool Movable =
std::is_object <T>::value &&
ranges::MoveConstructible <T> &&
ranges::Assignable <T&, T> &&

ranges::Swappable <T>;
 (范围 TS)

概念 Movable<T> 指定 T 是能移动（即移动构造、移动赋值且 T 的左值能交换）的对象类型。

Movable<T> 与 std::is_object <T>::value 间不需要任何蕴含关系。

参阅

Copyable
 指定该类型对象能被复制、移动和交换
(概念)


std::experimental::ranges::MoveConstructible

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts> |
template < class T > concept bool MoveConstructible = ranges::Constructible <T, T> && ranges::ConvertibleTo <T, T>; | (范围 TS)

概念 MoveConstructible 若 T 为引用类型，或若它是对象类型，其中能在直接和复制初始化语境中从该类型的右值以通常语义构造该类型对象，则得到满足。

更精确而言，若 T 是对象类型，则 MoveConstructible<T> 仅若满足下列条件才得到满足。给定

  • rv ， T 类型右值，与
  • u2 ，等于 rv 的 T 类型独立对象，

下列为真：

  • 定义 T u = rv; 后， u 等于 u2 ；
  • T{rv} 等于 u2 ；且
  • 若 T 无 const 限定，则 rv 的结果状态（在上述任一条中求值定义/表达式后）合法且未指定，否则它不更改。

参阅

is_move_constructibleis_trivially_move_constructibleis_nothrow_move_constructible
(C++11)(C++11)(C++11)
 检查类型是否能从右值引用构造
(类模板)


std::experimental::ranges::Predicate

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts> |
template < class F, class... Args > concept bool Predicate = ranges::RegularInvocable <F, Args...> && ranges::Boolean < std::result_of_t <F&&(Args&&...)>>; | (范围 TS)

概念 Predicate<F, Args...> 指定 F 是谓词并接受类型和值类别由 Args... 编码的参数，即能以这些参数调用它以产生 Boolean 结果。

注意 RegularInvocable 要求调用既不修改可调用对象亦不修改参数，且保持相等性。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。


std::experimental::ranges::Regular

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts> |
template <class T> concept bool Regular = ranges::Semiregular <T> && ranges::EqualityComparable <T>; | (范围 TS)

Regular 概念指定类型为常规，即它为可复制、可默认构造、且可比较相等。表现类似如 int 的内建类型，且能以 == 比较的类型满足该概念。


std::experimental::ranges::Relation

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts>
template <class R, class T, class U>

concept bool Relation =
ranges::Predicate <R, T, T> &&
ranges::Predicate <R, U, U> &&
ranges::CommonReference <
const std::remove_reference_t <T>&,
const std::remove_reference_t <U>&> &&
ranges::Predicate <R,
ranges::common_reference_t<
const std::remove_reference_t <T>&,
const std::remove_reference_t <U>&>,
ranges::common_reference_t<
const std::remove_reference_t <T>&,
const std::remove_reference_t <U>&>> &&
ranges::Predicate <R, T, U> &&

ranges::Predicate <R, U, T>;
 (1) (范围 TS)

概念 Relation<R, T, U> 指定 R 在类型和值类别由 T 或 U 编码的表达式集合上定义二元关系。

给定

  • r ，有 decltype((r)) 为 R 的表达式，
  • t ，有 decltype((t)) 为 T 的表达式，
  • u ，有 decltype((u)) 为 U 的表达式，

并令 C 为 ranges::common_reference_t<const std::remove_reference_t <T>&, const std::remove_reference_t <U>&> ，

则 Relation<R, T, U> 仅若

  • bool(r(t, u)) == bool(r(C(t), C(u))) 且
  • bool(r(u, t)) == bool(r(C(u), C(t)))

才得到满足


std::experimental::ranges::Same

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts> |
template < class T, class U > concept bool Same = std::is_same <T, U>::value; // 见后方 | (范围 TS)

概念 Same<T, U> 若且唯若 T 与 U 代表同一类型才得到满足。

无关乎说明使用， Same<T, U> 与 std::is_same <T, U>::value 间不必有蕴含关系。

为制约检查的目的， Same<T, U> 隐含 Same<U, T> 。

注意

Same 的制约检查上的额外要求与 std::is_same 相异。

参阅

is_same
(C++11)
 检查两个类型是否相同
(类模板)


std::experimental::ranges::Semiregular

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts> |
template <class T> concept bool Semiregular = ranges::Copyable <T> && ranges::DefaultConstructible <T>; | (范围 TS)

Semiregular 概念指定类型为可复制和可默认构造。表现类似如 int 的内建类型的类型满足该概念，除了它们可能不支持以 == 比较。


std::experimental::ranges::SignedIntegral

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts> |
template < class T > concept bool SignedIntegral = Integral<T> && std::is_signed <T>::value; | (范围 TS)

概念 SignedIntegral<T>() 若且唯若 T 为整数类型且 std::is_signed <T>::value 为 true 才得到满足。

SignedIntegral<T> 与 std::is_signed <T>::value 间不需要有任何蕴含关系。

注意

SignedIntegral<T>() 可为非有符号整数类型的类型满足，例如 char （在 char 为有符号的系统上）。

参阅

is_integral (C++11) | 检查类型是否为整型 (类模板)
is_signed (C++11) | 检查类型是否为有符号算术类型 (类模板)


std::experimental::ranges::StrictTotallyOrdered, std::experimental::ranges::StrictTotallyOrderedWith

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts>
template <class T>

concept bool StrictTotallyOrdered =
ranges::EqualityComparable <T> &&
requires(const std::remove_reference_t <T>& a,
const std::remove_reference_t <T>& b) {
{ a < b } -> ranges::Boolean &&;
{ a > b } -> ranges::Boolean &&;
{ a <= b } -> ranges::Boolean &&;
{ a >= b } -> ranges::Boolean &&;

};
 (1) (范围 TS)
template <class T, class U>

concept bool StrictTotallyOrderedWith =
ranges::StrictTotallyOrdered<T> &&
ranges::StrictTotallyOrdered<U> &&
ranges::CommonReference <
const std::remove_reference_t <T>&,
const std::remove_reference_t <U>&> &&
ranges::StrictTotallyOrdered<
ranges::common_reference_t<
const std::remove_reference_t <T>&,
const std::remove_reference_t <U>&>> &&
ranges::EqualityComparableWith <T, U> &&
requires(const std::remove_reference_t <T>& t,
const std::remove_reference_t <U>& u) {
{ t < u } -> ranges::Boolean &&;
{ t > u } -> ranges::Boolean &&;
{ t <= u } -> ranges::Boolean &&;
{ t >= u } -> ranges::Boolean &&;
{ u < t } -> ranges::Boolean &&;
{ u > t } -> ranges::Boolean &&;
{ u <= t } -> ranges::Boolean &&;
{ u >= t } -> ranges::Boolean &&;

};
 (2) (范围 TS)
1) 概念 StrictTotallyOrdered<T> 指定 T 上的比较运算符 ==,!=,<,>,<=,>= 产出的结果与 T 上的严格全序一致。

StrictTotallyOrdered<T> 仅若符合下列条件才得到满足。给定 const std::remove_reference_t <T> 类型左值 a 、 b 和 c ：

  • bool(a < b) 、 bool(a > b) 与 bool(a == b) 有且只有一个为 true ；
  • 若 bool(a < b) 与 bool(b < c) 均为 true ，则 bool(a < c) 为 true ；
  • bool(a > b) == bool(b < a)
  • bool(a >= b) == !bool(a < b)
  • bool(a <= b) == !bool(b < a)
2) 概念 StrictTotallyOrderedWith<T, U> 指定（可混合的） T 与 U 运算数上的比较运算符 ==,!=,<,>,<=,>= 产出的结果与严格全序一致。比较混合的运算数产出的结果等价于比较转换到其共用类型的运算数。

正式而言， StrictTotallyOrderedWith<T, U> 仅若符合下列条件才得到满足。给定任何 const std::remove_reference_t <T> 类型左值 t 与任何 const std::remove_reference_t <U> 类型左值 u ，并令 C 为 ranges::common_reference_t<const std::remove_reference_t <T>&, const std::remove_reference_t <U>&> ：

  • bool(t < u) == bool(C(t) < C(u))
  • bool(t > u) == bool(C(t) > C(u))
  • bool(t <= u) == bool(C(t) <= C(u))
  • bool(t >= u) == bool(C(t) >= C(u))
  • bool(u < t) == bool(C(u) < C(t))
  • bool(u > t) == bool(C(u) > C(t))
  • bool(u <= t) == bool(C(u) <= C(t))
  • bool(u >= t) == bool(C(u) >= C(t))

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常运算数。必须不修改常运算数。

隐式表达式变种

使用不修改某 const 左值运算数的表达式的 requires 表达式亦隐式要求该表达式的额外变种对给定运算数接受非 const 左值或（可为 const 的）右值，除非以有区别的语义显式要求这种表达式变种。这些隐式表达式变种必须符合与声明的表达式的相同的语义。不指定实现以何种程度校验变种的语法。


std::experimental::ranges::StrictWeakOrder

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts> |  |
template < class R, class T, class U > concept bool StrictWeakOrder = ranges::Relation <R, T, U>; | (1) | (范围 TS)

概念 StrictWeakOrder<R, T, U> 指定 Relation R 蕴含其参数上的严格弱序。若满足下列条件则 r 是严格弱序

  • 非自反：对于所有 x ， r(x, x) 为 false ；
  • 传递：对于所有 a 、 b 和 c ，若 r(a, b) 和 r(b, c) 都为 true 则 r(a, c) 为 true ；
  • 令 e(a, b) 为 !r(a, b) && !r(b, a) ，则 e 是传递的： e(a, b) && e(b, c) 蕴含 e(a, c) 。

在这些条件下，能证明 e 是等价关系，而 r 在 e 所确定的等价类上引入严格全序。

注意

Relation 与 StrictWeakOrder 间的区别是纯语义的。


std::experimental::ranges::Swappable, std::experimental::ranges::SwappableWith

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts>
template< class T >

concept bool Swappable =
requires(T& a, T& b) {
ranges::swap(a, b);

};
 (1) (范围 TS)
template< class T, class U >

concept bool SwappableWith =
ranges::CommonReference <
const std::remove_reference_t <T>&,
const std::remove_reference_t <U>&> &&
requires(T&& t, U&& u) {
ranges::swap( std::forward <T>(t), std::forward <T>(t));
ranges::swap( std::forward <U>(u), std::forward <U>(u));
ranges::swap( std::forward <T>(t), std::forward <U>(u));
ranges::swap( std::forward <U>(u), std::forward <T>(t));

};
 (2) (范围 TS)

概念 Swappable<T> 指定 T 类型左值可交换。

概念 SwappableWith<T, U> 指定属于 T 和 U 所编码的类型和值类别的表达式彼此可交换。 SwappableWith<T, U> 仅若调用 ranges::swap(t, u) 交换 t 与 u 的值，即给定等于 t 的独立对象 t2 和等于 u 的独立对象 u2 ，求值 ranges::swap(t, u) 或 ranges::swap(u, t) 后 t2 等于 u 且 u2 等于 t ，才得到满足。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常运算数。必须不修改常运算数。


std::experimental::ranges::UniformRandomNumberGenerator

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/random>
template <class G>

concept bool UniformRandomNumberGenerator =
ranges::Invocable <G&> &&
ranges::UnsignedIntegral < std::result_of_t <G&()>> &&
requires {
{ G::min() } -> ranges::Same < std::result_of_t <G&()>>&&;
{ G::max() } -> ranges::Same < std::result_of_t <G&()>>&&;

};
 (范围 TS)

概念 UniformRandomNumberGenerator<G> 指定 G 是均匀随机数生成器的类型，即 G 类型对象是返回无符号整数的函数对象，使得可能结果范围中的每个值都拥有（概念上）相等的被返回概率。

UniformRandomNumberGenerator<G> 仅若符合下列条件才得到满足。给定任何 G 类型对象 g ：

  • G::min() 与 G::max() 是纯右值常量表达式；
  • G::min() < G::max()
  • g() 在 [G::min(), G::max()] 范围中
  • g() 拥有均摊常数复杂度。


std::experimental::ranges::UnsignedIntegral

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts> |
template < class T > concept bool UnsignedIntegral = Integral<T> && !SignedIntegral<T>; | (范围 TS)

概念 UnsignedIntegral<T>() 若且唯若 T 为整数类型且 std::is_signed <T>::value 为 false 才得到满足。

注意

UnsignedIntegral<T>() 可能为非无符号整数类型的类型满足，例如 bool 。

参阅

is_integral (C++11) | 检查类型是否为整型 (类模板)
is_signed (C++11) | 检查类型是否为有符号算术类型 (类模板)


std::experimental::ranges::WeaklyEqualityComparableWith

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/concepts>
template <class T, class U>

concept bool WeaklyEqualityComparableWith =
requires(const std::remove_reference_t <T>& t,
const std::remove_reference_t <U>& u) {
{ t == u } -> ranges::Boolean &&;
{ t != u } -> ranges::Boolean &&;
{ u == t } -> ranges::Boolean &&;
{ u != t } -> ranges::Boolean &&;

};
 (范围 TS)

概念 WeaklyEqualityComparableWith<T, U> 指定能用 == 和 != 相互比较（以任一顺序） T 类型对象和 U 类型对象的相等性，而比较结果一致。更正式地说， WeaklyEqualityComparableWith<T, U> 仅若满足下列条件才得到满足。给定

  • t ， const std::remove_reference_t <T> 类型左值，和
  • u ， const std::remove_reference_t <U> 类型左值

下列为真：

  • t == u 、 u == t 、 t != u 、 u != t 拥有相同的定义域；
  • bool(u == t) == bool(t == u) ；
  • bool(t != u) == !bool(t == u) ；且
  • bool(u != t) == bool(t != u) 。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常运算数。必须不修改常运算数。

隐式表达式变种

使用不修改某 const 左值运算数的表达式的 requires 表达式亦隐式要求该表达式的额外变种对给定运算数接受非 const 左值或（可为 const 的）右值，除非以有区别的语义显式要求这种表达式变种。这些隐式表达式变种必须符合与声明的表达式的相同的语义。不指定实现以何种程度校验变种的语法。

参阅

EqualityComparableEqualityComparableWith
 指定运算符 == 是等价关系
(概念)


std::experimental::ranges::equal_to

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/functional>
template< class T = void >

requires ranges::EqualityComparable <T> ||
ranges::Same <T, void> ||
/* 二个 const T 左值上的 == 调用比较指针的内建运算符 */

struct equal_to;
 (范围 TS)
template <>
struct equal_to<void>;
 (范围 TS)

进行比较的函数对象。初等模板在 T 类型 const 左值上调用 operator == 。特化 equal_to<void> 从实参推导函数调用运算符的形参（但非返回类型）。

equal_to 的所有特化均为 Semiregular 。

成员类型

成员类型 | 定义
is_transparent (仅为 equal_to<void> 特化的成员) | /* 未指定 */

成员函数

operator()
 检查参数是否相等
(公开成员函数)

std::experimental::ranges::equal_to::operator()

constexpr bool operator()(const T& x, const T& y) const;
 (1) (仅为初等 equal_to<T> 模板的成员)
template< class T, class U >

requires ranges::EqualityComparableWith <T, U> ||
/* std::declval<T>() == std::declval<U>()
解析成比较指针的内建运算符 */

constexpr bool operator()(T&& t, U&& u) const;
 (2) (仅为 equal_to<void> 特化的成员)
1) 比较 x 与 y 。等价于 return ranges::equal_to<>{}(x, y) ；
2) 比较 t 与 u ，等价于 return std::forward <T>(t) == std::forward <U>(u); ，除非表达式解析成调用比较指针的内建 operator == 。

当调用 (1) 或 (2) 会调用比较 P 类型指针的内建运算符时，替而以下列方式确定结果：

  • 若（可能被转换的）第一参数值和（可能被转换的）第二参数值，在实现定义的、所有 P 类型指针值上的严格全序中，一者先于另一者，则返回 false 。此严格全序与内建运算符 < 、 > 、 <= 和 >= 所蕴含的偏序一致。
  • 否则（无一先于另一者）返回 true 。

除非从 T 和 U 到 P 的转换序列均保持相等性（见后述），否则行为未定义。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

注意

不同于 std::equal_to ， ranges::equal_to 要求 == 与 != 均合法（通过 EqualityComparable 和 EqualityComparableWith 制约）。

示例

本节未完成
原因：暂无示例

参阅

equal_to
 实现 x == y 的函数对象
(类模板)


std::experimental::ranges::greater

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/functional>
template< class T = void >

requires ranges::StrictTotallyOrdered <T> ||
ranges::Same <T, void> ||
/* 二个 const T 左值上的 < 调用比较指针的内建运算符 */

struct greater;
 (范围 TS)
template <>
struct greater<void>;
 (范围 TS)

进行比较的函数对象。初等模板在 T 类型 const 左值上以倒序调用 operator< 。特化 greater<void> 从实参推导函数调用运算符的形参类型（但非返回类型）。

greater 的所有特化均为 Semiregular 。

成员类型

成员类型 | 定义
is_transparent (仅为 greater<void> 特化的成员) | /* 未指定 */

成员函数

operator()
 检查第一参数是否大于第二个
(公开成员函数)

std::experimental::ranges::greater::operator()

constexpr bool operator()(const T& x, const T& y) const;
 (1) (仅为初等 greater<T> 模板的成员)
template< class T, class U >

requires ranges::StrictTotallyOrderedWith <T, U> ||
/* std::declval<T>() < std::declval<U>()
解析成比较指针的内建运算符 */

constexpr bool operator()(T&& t, U&& u) const;
 (2) (仅为 greater<void> 特化的成员)
1) 比较 x 与 y 。等价于 return ranges::less<>{}(y, x) ；
2) 比较 t 与 u 。等价于 return ranges::less<>{}( std::forward <U>(u), std::forward <T>(t)); 。

注意

不同于 std::greater ， ranges::greater 要求全部六个比较运算符 < 、 <= 、 > 、 >= 、 == 及 != 均合法（通过 StrictTotallyOrdered 与 StrictTotallyOrderedWith 制约）并且完全以 ranges::less 定义。然而，实现可以自由地直接使用 operator> ，因为这些概念要求比较运算符的结果一致。

示例

本节未完成
原因：暂无示例

参阅

greater
 实现 x > y 的函数对象
(类模板)


std::experimental::ranges::greater_equal

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/functional>
template< class T = void >

requires ranges::StrictTotallyOrdered <T> ||
ranges::Same <T, void> ||
/* 二个 const T 左值上的 < 调用比较指针的内建运算符 */

struct greater_equal;
 (范围 TS)
template <>
struct greater_equal<void>;
 (范围 TS)

进行比较的函数对象。初等模板调用 T 类型 const 左值上的 operator< 并对结果取反。特化 greater_equal<void> 从实参推导函数调用运算符的形参类型（但非返回类型）。

greater_equal 的所有特化均为 Semiregular 。

成员类型

成员类型 | 定义
is_transparent (仅为 greater_equal<void> 特化的成员) | /* 未指定 */

成员函数

operator()
 检查第一参数是否大于或等于第二个
(公开成员函数)

std::experimental::ranges::greater_equal::operator()

constexpr bool operator()(const T& x, const T& y) const;
 (1) (仅为初等 greater_equal<T> 模板的成员)
template< class T, class U >

requires ranges::StrictTotallyOrderedWith <T, U> ||
/* std::declval<T>() < std::declval<U>()
解析成比较指针的内建运算符 */

constexpr bool operator()(T&& t, U&& u) const;
 (2) (仅为 greater_equal<void> 特化的成员)
1) 比较 x 与 y 。等价于 return !ranges::less<>{}(x, y) ；
2) 比较 t 与 u 。等价于 return !ranges::less<>{}( std::forward <T>(t), std::forward <U>(u)); 。

注意

不同于 std::greater_equal ， ranges::greater_equal 要求六个比较运算符 < 、 <= 、 > 、 >= 、 == 及 != 均合法（通过 StrictTotallyOrdered 与 StrictTotallyOrderedWith 制约）并且完全以 ranges::less 定义。然而，实现可以自由地直接使用 operator>= ，因为这些运算符要求比较运算符的结果一致。

示例

本节未完成
原因：暂无示例

参阅

greater_equal
 实现 x >= y 的函数对象
(类模板)


std::experimental::ranges::identity

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/functional> |
struct identity; | (范围 TS)

ranges::identity 是函数对象类型，其 operator() 返回不更改的参数。所有范围 TS 算法以之为默认投影。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 返回不更改的参数
(公开成员函数)

std::experimental::ranges::identity::operator()

template< class T>
constexpr T&& operator()( T&& t ) const noexcept;

返回 std::forward <T>(t) 。

参数

t - 要返回的参数

返回值

std::forward <T>(t) 。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::experimental::ranges::invoke

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/functional> |
template < class F, class... Args > std::result_of_t <F&&(Args&&...)> invoke(F&& f, Args&&... args); | (范围 TS)

以参数 args 调用可调用 (Callable) 对象 f ，并返回结果，如同用 return INVOKE( std::forward <F>(f), std::forward <Args>(args)...); ，其中 INVOKE(f, t1, t2, ..., tN) 定义如下：

  • 若 f 为类 T 的指向成员函数指针：
  • 若 std::is_base_of <T, std::decay_t <decltype(t1)>>::value 为 true ，则 INVOKE(f, t1, t2, ..., tN) 等价于 (t1.*f)(t2, ..., tN)
  • 否则， INVOKE(f, t1, t2, ..., tN) 等价于 ((*t1).*f)(t2, ..., tN) 。
  • 否则，若 N == 1 且 f 为类 T 的指向数据成员指针：
  • 若 std::is_base_of <T, std::decay_t <decltype(t1)>>::value 为 true ，则 INVOKE(f, t1) 等价于 t1.*f 。
  • 否则， INVOKE(f, t1) 等价于 (*t1).*f 。
  • 否则 INVOKE(f, t1, t2, ..., tN) 等价于 f(t1, t2, ..., tN) （即 f 是函数对象 (FunctionObject) ）。

参数

f | - | 要调用的可调用 (Callable) 对象
args | - | 传递给 f 的参数

参阅

invokeinvoke_r
(C++17)(C++23)
 以给定实参和可能指定的返回类型 (C++23 起)调用任意可调用 (Callable) 对象
(函数模板)


std::experimental::ranges::less

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/functional>
template< class T = void >

requires ranges::StrictTotallyOrdered <T> ||
ranges::Same <T, void> ||
/* 二个 const T 左值上的 < 调用比较指针的内建运算符 */

struct less;
 (范围 TS)
template <>
struct less<void>;
 (范围 TS)

进行比较的函数对象。初等模板在 T 类型左值上调用 operator< 。特化 less<void> 从实参推导函数调用运算符的形参类型（但非返回类型）。

less 的所有特化均为 Semiregular 。

成员类型

成员类型 | 定义
is_transparent (仅为 less<void> 特化的成员) | /* 未指定 */

成员函数

operator()
 检查第一参数是否小于第二个
(公开成员函数)

std::experimental::ranges::less::operator()

constexpr bool operator()(const T& x, const T& y) const;
 (1) (仅为初等 less<T> 模板的成员)
template< class T, class U >

requires ranges::StrictTotallyOrderedWith <T, U> ||
/* std::declval<T>() < std::declval<U>()
解析成比较指针的内建运算符 */

constexpr bool operator()(T&& t, U&& u) const;
 (2) (仅为 less<void> 特化的成员)
1) 比较 x 与 y 。等价于 return ranges::less<>{}(x, y) ；
2) 比较 t 与 u ，等价于 return std::forward <T>(t) < std::forward <U>(u); ，除非该表达式解析成调用比较指针的内建 operator< 。

当调用 (1) 或 (2) 会调用比较 P 类型指针的内建运算符时，替而按下列方式确定结果：

  • 若在所有 P 类型指针值上的实现定义的严格全序中，第一参数的（可能转换的）值先于第二参数的（可能转换的）值，则返回 true 。此严格全序与内建运算符 < 、 > 、 <= 及 >= 所蕴含的偏序一致。
  • 否则返回 false 。

除非从 T 和 U 到 P 的转换序列均保持相等性（见后述），否则行为未定义。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

注意

不同于 std::less ， ranges::less 要求六个比较运算符 < 、 <= 、 > 、 >= 、 == 和 != 均合法（通过 StrictTotallyOrdered 与 StrictTotallyOrderedWith 制约）。

示例

本节未完成
原因：暂无示例

参阅

less
 实现 x < y 的函数对象
(类模板)


std::experimental::ranges::less_equal

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/functional>
template< class T = void >

requires ranges::StrictTotallyOrdered <T> ||
ranges::Same <T, void> ||
/* 二个 const T 左值上的 < 调用比较指针的内建运算符 */

struct less_equal;
 (范围 TS)
template <>
struct less_equal<void>;
 (范围 TS)

进行比较的函数对象。初等模板以参数倒序调用 T 类型 const 左值上的 operator< 并对结果取反。特化 less_equal<void> 从实参推导函数调用运算符的形参类型（但非返回类型）。

less_equal 的所有特化均为 Semiregular 。

成员类型

成员类型 | 定义
is_transparent (仅为 less_equal<void> 特化的成员) | /* 未指定 */

成员函数

operator()
 检查第一参数是否小于或等于第二个
(公开成员函数)

std::experimental::ranges::less_equal::operator()

constexpr bool operator()(const T& x, const T& y) const;
 (1) (仅为初等 less_equal<T> 模板的成员)
template< class T, class U >

requires ranges::StrictTotallyOrderedWith <T, U> ||
/* std::declval<T>() < std::declval<U>()
解析成比较指针的内建运算符 */

constexpr bool operator()(T&& t, U&& u) const;
 (2) (仅为 less_equal<void> 特化的成员)
1) 比较 x 与 y 。等价于 return !ranges::less<>{}(y, x) ；
2) 比较 t 与 u 。等价于 return !ranges::less<>{}( std::forward <U>(u), std::forward <T>(t)); 。

注意

不同于 std::less_equal ， ranges::less_equal 要求六个比较运算符 < 、 <= 、 > 、 >= 、 == 及 != 均合法（通过 StrictTotallyOrdered 与 StrictTotallyOrderedWith 制约）并且完全以 ranges::less 定义。然而实现可以自由地直接用 operator<= ，因为这些概念要求比较运算符的结果一致。

示例

本节未完成
原因：暂无示例

参阅

less_equal
 实现 x <= y 的函数对象
(类模板)


std::experimental::ranges::not_equal_to

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/functional>
template< class T = void >

requires ranges::EqualityComparable <T> ||
ranges::Same <T, void> ||
/* 二个 const T 左值上的 == 调用比较指针的内建运算符 */

struct not_equal_to;
 (范围 TS)
template <>
struct not_equal_to<void>;
 (范围 TS)

进行比较的函数对象。初等模板在 T 类型 const 左值上调用 operator == 并对结果取反。特化 not_equal_to<void> 从实参推导函数调用运算符的形参类型（但非返回类型）。

not_equal_to 的所有特化均为 Semiregular 。

成员类型

成员类型 | 定义
is_transparent (仅为 not_equal_to<void> 特化的成员) | /* 未指定 */

成员函数

operator()
 检查参数是否不相等
(公开成员函数)

std::experimental::ranges::not_equal_to::operator()

constexpr bool operator()(const T& x, const T& y) const;
 (1) (仅为初等 not_equal_to<T> 模板的成员)
template< class T, class U >

requires ranges::EqualityComparableWith <T, U> ||
/* std::declval<T>() == std::declval<U>()
解析成比较指针的内建运算符 */

constexpr bool operator()(T&& t, U&& u) const;
 (2) (仅为 not_equal_to<void> 特化的成员)
1) 比较 x 与 y 。等价于 return !ranges::equal_to<>{}(x, y) ；
2) 比较 t 与 u 。等价于 return !ranges::equal_to<>{}( std::forward <T>(t), std::forward <U>(u)); 。

注意

不同于 std::not_equal_to ， ranges::not_equal_to 要求 == 与 != 均合法（通过 EqualityComparable 和 EqualityComparableWith 制约），而它完全用 ranges::equal_to 定义。然而，实现可以自由地直接使用 operator!= ，因为这些概念要求 == 与 != 的结果一致。

示例

本节未完成
原因：暂无示例

参阅

not_equal_to
 实现 x != y 的函数对象
(类模板)


std::experimental::ranges::BidirectionalIterator

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template < class I >

concept bool BidirectionalIterator =
ranges::ForwardIterator <I> &&
ranges::DerivedFrom <
ranges::iterator_category_t<I>, ranges::bidirectional_iterator_tag
> &&
requires(I i) {
{ --i } -> ranges::Same <I>&;
{ i-- } -> ranges::Same <I>&&;

};
 (范围 TS)

概念 BidirectionalIterator<I> 细化 ForwardIterator ，添加后移迭代器的能力。

称双向迭代器 r 可自减，若且唯若存在某个 s 使得 ++s == r 。所有可自减迭代器 r 应当在表达式 --r 和 r-- 的定义域中。

令 a 与 b 为 I 类型的可自减对象。 BidirectionalIterator<I> 仅若符合下列条件才得到满足：

  • 前自减生成指代运算数的左值： std::addressof (--a) == std::addressof (a) ；
  • 后自减生成运算数先前的值：若 bool(a == b) ，则 bool(a-- == b) 。
  • 后自减和前自减在运算数上进行相同操作：若 bool(a == b) ，则求值 a-- 与 --b 两者后， bool(a == b) 仍然成立。
  • 自增和自减互逆：
  • 若 a 可自增且 bool(a == b) ，则 bool(--(++a) == b) 。
  • 若 bool(a == b) ，则 bool(++(--a) == b) 。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常运算数。必须不修改常运算数。


std::experimental::ranges::ForwardIterator

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template < class I >

concept bool ForwardIterator =
ranges::InputIterator <I> &&
ranges::DerivedFrom <ranges::iterator_category_t<I>, ranges::forward_iterator_tag> &&
ranges::Incrementable <I> &&

ranges::Sentinel <I, I>;
 (范围 TS)

概念 ForwardIterator<I> 细化 InputIterator ，添加相等比较和多趟保证。

== 对于向前迭代器的定义域是同一底层序列上的迭代器的定义域，除了值初始化的同类型迭代器可能彼此比较，并应当比较相等。

在 [i, s) 一直代表范围时，从指向范围 [i, s) 中的向前迭代器获得的指针和引用必须保持合法。

令 a 与 b 为二个 I 类型的可解引用迭代器。 ForwardIterator<I> 仅若符合下列条件才得到满足：

  • a == b 隐含 ++a == ++b ；且
  • 表达式 ([](X x){++x;}(a), *a) 等价于 *a ，即自增 a 的副本在解引用 a

这被称为多趟保证。

注意

向前迭代器不能“贮藏”：它不能返回到其自身内对象的引用，因为向前迭代器的析构会非法化这种引用。


std::experimental::ranges::Incrementable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template <class I>

concept bool Incrementable =
ranges::Regular <I> &&
ranges::WeaklyIncrementable <I> &&
requires(I i) {
{ i++ } -> ranges::Same <I>&&;

};
 (范围 TS)

概念 Incrementable<I> 指定能（用前和后自增运算符）自增的类型上的要求。要求自增运算（包括 WeaklyIncrementable 所要求者）保持相等性，并要求该类型为 EqualityComparable 。

令 a 与 b 为 I 类型的可自增对象。 Incrementable<I> 仅若下列条件成立才得到满足：

  • 若 bool(a == b) 则 bool(a++ == b) 。
  • 若 bool(a == b) 则 bool(void(a++), a) == ++b) 。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常运算数。必须不修改常运算数。

注意

a 等于 b 的要求蕴含 ++a 等于 ++b ，这允许用 Incrementable 类型进行多趟算法。


std::experimental::ranges::IndirectRelation

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template < class F, class I1, class I2 = I1 >

concept bool IndirectRelation =
ranges::Readable <I1> && ranges::Readable <I2> &&
ranges::CopyConstructible <F> &&
ranges::Relation <F&, ranges::value_type_t<I1>&, ranges::value_type_t<I2>&> &&
ranges::Relation <F&, ranges::value_type_t<I1>&, ranges::reference_t<I2>> &&
ranges::Relation <F&, ranges::reference_t<I1>, ranges::value_type_t<I2>&> &&
ranges::Relation <F&, ranges::reference_t<I1>, ranges::reference_t<I2>> &&
ranges::Relation <
F&, ranges::iter_common_reference_t<I1>, ranges::iter_common_reference_t<I2>

>;
 (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::IndirectStrictWeakOrder

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template < class F, class I1, class I2 = I1 >

concept bool IndirectStrictWeakOrder =
ranges::Readable <I1> && ranges::Readable <I2> &&
ranges::CopyConstructible <F> &&
ranges::StrictWeakOrder <F&, ranges::value_type_t<I1>&, ranges::value_type_t<I2>&> &&
ranges::StrictWeakOrder <F&, ranges::value_type_t<I1>&, ranges::reference_t<I2>> &&
ranges::StrictWeakOrder <F&, ranges::reference_t<I1>, ranges::value_type_t<I2>&> &&
ranges::StrictWeakOrder <F&, ranges::reference_t<I1>, ranges::reference_t<I2>> &&
ranges::StrictWeakOrder <F&, ranges::iter_common_reference_t<I1>,

ranges::iter_common_reference_t<I2>>;
 (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::IndirectUnaryInvocable, std::experimental::ranges::IndirectRegularUnaryInvocable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template <class F, class I>

concept bool IndirectUnaryInvocable =
ranges::Readable <I> && ranges::CopyConstructible <F> &&
ranges::Invocable <F&, ranges::value_type_t<I>&> &&
ranges::Invocable <F&, ranges::reference_t<I>> &&
ranges::Invocable <F&, ranges::iter_common_reference_t<I>> &&
ranges::CommonReference <
std::result_of_t <F&(ranges::value_type_t<I>&)>,

std::result_of_t <F&(ranges::reference_t<I>&&)>>;
 (范围 TS)
template <class F, class I>

concept bool IndirectRegularUnaryInvocable =
ranges::Readable <I> && ranges::CopyConstructible <F> &&
ranges::RegularInvocable <F&, ranges::value_type_t<I>&> &&
ranges::RegularInvocable <F&, ranges::reference_t<I>> &&
ranges::RegularInvocable <F&, ranges::iter_common_reference_t<I>> &&
ranges::CommonReference <
std::result_of_t <F&(ranges::value_type_t<I>&)>,

std::result_of_t <F&(ranges::reference_t<I>&&)>>;
 (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::IndirectUnaryPredicate

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template <class F, class I>

concept bool IndirectUnaryPredicate =
ranges::Readable <I> && ranges::CopyConstructible <F> &&
ranges::Predicate <F&, ranges::value_type_t<I>&> &&
ranges::Predicate <F&, ranges::reference_t<I>> &&

ranges::Predicate <F&, ranges::iter_common_reference_t<I>>;
 (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::IndirectlyComparable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template < class I1, class I2, class R = ranges::equal_to<>,

class P1 = ranges::identity, class P2 = ranges::identity >
concept bool IndirectlyComparable =

ranges::IndirectRelation <R, ranges::projected <I1, P1>, ranges::projected <I2, P2>>;
 (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::IndirectlyCopyable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator> |
template < class In, class Out > concept bool IndirectlyCopyable = ranges::Readable <In> && ranges::Writable <Out, ranges::reference_t<In>>; | (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::IndirectlyCopyableStorable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template <class In, class Out>

concept bool IndirectlyCopyableStorable =
ranges::IndirectlyCopyable <In, Out> &&
ranges::Writable <Out, const ranges::value_type_t<In>&> &&
ranges::Copyable <ranges::value_type_t<In>> &&
ranges::Constructible <ranges::value_type_t<In>, ranges::reference_t<In>> &&

ranges::Assignable <ranges::value_type_t<In>&, ranges::reference_t<In>>;
 (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::IndirectlyMovable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator> |
template <class In, class Out> concept bool IndirectlyMovable = ranges::Readable <In> && ranges::Writable <Out, ranges::rvalue_reference_t<In>>; | (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::IndirectlyMovableStorable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template < class In, class Out >

concept bool IndirectlyMovableStorable =
ranges::IndirectlyMovable <In, Out> &&
ranges::Writable <Out, ranges::value_type_t<In>> &&
ranges::Movable <ranges::value_type_t<In>> &&
ranges::Constructible <ranges::value_type_t<In>, ranges::rvalue_reference_t<In>> &&

ranges::Assignable <ranges::value_type_t<In>&, ranges::rvalue_reference_t<In>>;
 (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::IndirectlySwappable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template <class I1, class I2 = I1>

concept bool IndirectlySwappable =
ranges::Readable <I1> && ranges::Readable <I2> &&
requires(I1&& i1, I2&& i2) {
ranges::iter_swap( std::forward <I1>(i1), std::forward <I2>(i2));
ranges::iter_swap( std::forward <I2>(i2), std::forward <I1>(i1));
ranges::iter_swap( std::forward <I1>(i1), std::forward <I1>(i1));
ranges::iter_swap( std::forward <I2>(i2), std::forward <I2>(i2));

};
 (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::InputIterator

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template < class I >

concept bool InputIterator =
ranges::Iterator <I> && ranges::Readable <I> &&
requires { typename ranges::iterator_category_t<I>; } &&

ranges::DerivedFrom <ranges::iterator_category_t<I>, ranges::input_iterator_tag>;
 (范围 TS)

InputIterator 概念是 Iterator 的细化，添加能读取被引用值的要求（经由 Readable ）和迭代器类别标签存在的要求。

注意

不同于 C++ 标准中的输入迭代器要求，范围 TS 中的 InputIterator 不要求 EqualityComparable 。


std::experimental::ranges::Iterator

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template <class I>

concept bool Iterator =
requires(I i) {
{ *i } -> auto&&; // 要求： i 可解引用
} &&

ranges::WeaklyIncrementable <I>;
 (范围 TS)

Iterator 概念组成迭代器分类学的基础；每个迭代器都满足 Iterator 要求。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常运算数。必须不修改常运算数。

注意

Iterator 自身仅指定解引用和自增迭代器的操作。大多数算法将要求额外操作：

  • 比较迭代器与哨位（见 Sentinel ）；
  • 从迭代器读取值（见 Readable 及 InputIterator ）；
  • 写入值到迭代器（见 Writable 及 OutputIterator ）
  • 更丰富的迭代器动作集合（见 ForwardIterator 、 BidirectionalIterator 、 RandomAccessIterator ）

-> auto&& 制约解引用的结果类型不能为 void 。


std::experimental::ranges::Mergeable

< cpp‎ | experimental‎ | ranges
template < class I1, class I2, class Out, class R = ranges::less<>,

class P1 = ranges::identity, class P2 = ranges::identity >
concept bool Mergeable =
ranges::InputIterator <I1> &&
ranges::InputIterator <I2> &&
ranges::WeaklyIncrementable <Out> &&
ranges::IndirectlyCopyable <I1, Out> &&
ranges::IndirectlyCopyable <I2, Out> &&
ranges::IndirectStrictWeakOrder <
R, ranges::projected <I1, P1>, ranges::projected <I2, P2>

>;
 (范围 TS)

Mergeable 概念指定通过复制元素，归并排序序列到输出序列中的算法（例如 ranges::merge ）的常用要求。


std::experimental::ranges::OutputIterator

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template <class I, class T>

concept bool OutputIterator =
ranges::Iterator <I> && ranges::Writable <I, T> &&
requires(I i, T&& t) {
*i++ = std::forward <T>(t); // 不要求保持相等性

};
 (范围 TS)

OutputIterator 概念是 Iterator 的细化，添加了能用于写入值类型和值类别为 T 所编码的值的要求（经由 Writable ）。不要求 EqualityComparable 。

令 E 为满足 decltype((E)) 为 T 的表达式，而 i 为 I 类型的可解引用对象。 OutputIterator<I, T> 仅若 *i++ = E; 拥有等价于 *i = E; ++i; 的效果才得到满足

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

注意

不同于 C++ 标准中的输出迭代器要求，范围 TS 中的 OutputIterator 不要求定义迭代器类别标签。

输出迭代器上的算法应该为单趟。


std::experimental::ranges::Permutable

< cpp‎ | experimental‎ | ranges
template <class I>

concept bool Permutable =
ranges::ForwardIterator <I> &&
ranges::IndirectlyMovableStorable <I, I> &&

ranges::IndirectlySwappable <I, I>;
 (范围 TS)

Permutable 概念指定通过移动或交换元素，原位重排它们的算法（例如 ranges::rotate ）的常用要求。


std::experimental::ranges::RandomAccessIterator

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template <class I>

concept bool RandomAccessIterator =
ranges::BidirectionalIterator <I> &&
ranges::DerivedFrom <
ranges::iterator_category_t<I>, ranges::random_access_iterator_tag
> &&
ranges::StrictTotallyOrdered <I> &&
ranges::SizedSentinel <I, I> &&
requires(I i, const I j, const ranges::difference_type_t<I> n) {
{ i += n } -> ranges::Same <I>&;
{ j + n } -> ranges::Same <I>&&;
{ n + j } -> ranges::Same <I>&&;
{ i -= n } -> ranges::Same <I>&;
{ j - n } -> ranges::Same <I>&&;
j[n];
requires ranges::Same <decltype(j[n]), ranges::reference_t<I>>;

};
 (范围 TS)

概念 RandomAccessIterator<I> 细化 BidirectionalIterator ，添加用 += 、 -= 、 + 和 - 运算符的常数时间前进、用 - 的常数时间距离计算，及带下标的数组记法支持。

令 a 与 b 为 I 类型的合法迭代器，使得从 a 可抵达 b ，并令 n 为等于 b - a 的 ranges::difference_type_t<I> 类型值。 RandomAccessIterator<I> 仅若符合下列条件才得到满足：

  • (a += n) 等于 b 。
  • std::addressof (a += n) 等于 std::addressof (a) 。
  • (a + n) 等于 (a += n) 。
  • (a + n) 等于 (n + a) 。
  • 对于任何二个正整数 x 与 y ，若 a + (x + y) 合法，则 a + (x + y) 等于 (a + x) + y 。
  • a + 0 等于 a 。
  • 若 (a + (n - 1)) 合法，则 --b 等于 (a + (n - 1)) 。
  • (b += -n) 与 (b -= n) 都等于 a 。
  • std::addressof (b -= n) 等于 std::addressof (b) 。
  • (b - n) 等于 (b -= n) 。
  • 若 b 可解引用，则 a[n] 合法并等于 *b 。
  • bool(a <= b) 为 true 。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常运算数。必须不修改常运算数。

隐式表达式变种

使用不修改某 const 左值运算数的表达式的 requires 表达式亦隐式要求该表达式的额外变种对给定运算数接受非 const 左值或（可为 const 的）右值，除非以有区别的语义显式要求这种表达式变种。这些隐式表达式变种必须符合与声明的表达式的相同的语义。不指定实现以何种程度校验变种的语法。


std::experimental::ranges::Readable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template < class In >

concept bool Readable =
requires {
typename ranges::value_type_t<In>;
typename ranges::reference_t<In>;
typename ranges::rvalue_reference_t<In>;
} &&
ranges::CommonReference <
ranges::reference_t<In>&&, ranges::value_type_t<In>&
> &&
ranges::CommonReference <
ranges::reference_t<In>&&, ranges::rvalue_reference_t<In>&&
> &&
ranges::CommonReference <
ranges::rvalue_reference_t<In>&&, const ranges::value_type_t<In>&

>;
 (范围 TS)

概念 Readable 为通过应用 operator* 可读的类型，例如指针、智能指针和迭代器所满足。


std::experimental::ranges::Sentinel

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator> |
template < class S, class I > concept bool Sentinel = ranges::Semiregular <S> && ranges::Iterator <I> && ranges::WeaklyEqualityComparableWith <S, I>; | (范围 TS)

Sentinel 概念描述其值代表范围的 Iterator 类型与 Semiregular 类型间的关系。

令 s 与 i 分别表示 S 与 I 类型的值，使得 [i, s) 代表范围。 Sentinel<S, I> 仅若下列条件成立才得到满足：

  • i == s 为良定义。
  • 若 bool(i != s) 则 i 可解引用且 [++i, s) 代表范围。

== 能随时间而更改。给定迭代器 i 和哨位 s 并使得 [i, s) 代表范围且 i != s ，不要求自增任何等于 i 的迭代器后 [i, s) 继续代表范围（从而这种自增后不再要求 i == s 是良定义的）。


std::experimental::ranges::SizedSentinel

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template <class S, class I>

concept bool SizedSentinel =
ranges::Sentinel <S, I> &&
!ranges::disable_sized_sentinel< std::remove_cv_t <S>, std::remove_cv_t <I>> &&
requires(const I& i, const S& s) {
{ s - i } -> ranges::Same <ranges::difference_type_t<I>>&&;
{ i - s } -> ranges::Same <ranges::difference_type_t<I>>&&;

};
 (1) (范围 TS)
template <class S, class I>
constexpr bool disable_sized_sentinel = false;
 (1) (范围 TS)

SizedSentinel 概念指定能在常数时间内相减迭代器类型 I 的对象和哨位类型 S 的对象，计算其间的距离。

令 i 为 I 类型迭代器，而 s 为 S 类型哨位，使得 [i, s) 代表范围。令 N 为需要应用 ++i 以令 bool(i == s) 为 true 的最小次数。则 SizedSentinel<S, I> 仅若符合下列条件才得到满足：

  • 若 N 能以 ranges::difference_type_t<I> 表示，则 s - i 良定义并等于 N ；且
  • 若 -N 能以 ranges::difference_type_t<I> 表示，则 i - s 良定义并等于 -N 。

变量模板 disable_sized_sentinel 通过特化变量模板为拥有值 true ，为能相减但不符合 SizedSentinel 语义要求的迭代器和哨位提供撤出概念的机制。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常运算数。必须不修改常运算数。

隐式表达式变种

使用不修改某 const 左值运算数的表达式的 requires 表达式亦隐式要求该表达式的额外变种对给定运算数接受非 const 左值或（可为 const 的）右值，除非以有区别的语义显式要求这种表达式变种。这些隐式表达式变种必须符合与声明的表达式的相同的语义。不指定实现以何种程度校验变种的语法。


std::experimental::ranges::Sortable

< cpp‎ | experimental‎ | ranges
template <class I, class R = ranges::less<>, class P = ranges::identity>

concept bool Sortable =
ranges::Permutable <I> &&

ranges::IndirectStrictWeakOrder <R, ranges::projected <I, P>>;
 (范围 TS)

Sortable 概念指定将序列排列成有序序列的算法（例如 ranges::sort ）的常用要求。


std::experimental::ranges::WeaklyIncrementable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template <class I>

concept bool WeaklyIncrementable =
ranges::Semiregular <I> &&
requires(I i) {
typename ranges::difference_type_t<I>;
requires ranges::SignedIntegral <ranges::difference_type_t<I>>;
{ ++i } -> ranges::Same <I>&; /* 不要求保持相等性 */
i++; /* 不要求保持相等性 */

};
 (范围 TS)

概念 WeaklyIncrementable<I> 指定能（以前和后自增运算符）自增的类型上的要求。自增运算不需要保持相等性，而且类型不必为 EqualityComparable 。

令 i 为 I 类型对象。若 i 在前和后自增的定义域中，则说它可自增。 WeaklyIncrementable<I> 仅若下列条件成立才得到满足：

  • ++i 与 i++ 有相同的定义域；
  • 若 i 可自增，则：
    • ++i 与 i++ 均令 i 前进到下个元素；且
    • ++i 与 i 指代同一对象。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

注意

对于 WeaklyIncrementable 类型， a 等于 b 不蕴含 ++a 等于 ++b 。在这种类型上的算法应该为单趟，且决不试图二次经过相同值。


std::experimental::ranges::Writable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template< class Out, class T >

concept bool Writable =
requires(Out&& o, T&& t) {
*o = std::forward <T>(t);
* std::forward <Out>(o) = std::forward <T>(t);
const_cast<const ranges::reference_t<Out>&&>(*o) =
std::forward <T>(t);
const_cast<const ranges::reference_t<Out>&&>(* std::forward <Out>(o)) =
std::forward <T>(t);
};

/* 上述四个表达式都不要求保持相等性 */
 (范围 TS)

概念 Writable<Out, T> 指定写入类型和值类别为 T 所编码的值到迭代器 Out 所引用对象的要求。

令 E 为满足 decltype((E)) 为 T 的表达式，而 o 为 Out 类型的可解引用对象，则 Writable<Out, T> 仅若符合下列条件才得到满足：

  • 若 ranges::Readable <Out> && ranges::Same <ranges::value_type_t<Out>, std::decay_t <T>> 得到满足，则在任何上述赋值后 *o 等于 E 在赋值前的值。

不要求 o 在求值任何上述赋值表达式后可解引用。若 E 为亡值，则其代表的对象的结果状态合法但未指定。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其运算数组成。
  • 表达式的输出由其结果和表达式所修改的所有运算数（若存在）组成。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

注解

operator* 仅有的合法用法是在赋值表达式左侧。通过可写类型相同值的赋值可以只发生一次。

带 const_cast 的要求表达式阻止有纯右值 reference 类型的 Readable 对象意外地满足 Writable 的语法要求，同时容许代理引用继续工作，只要其常性是浅的。见范围 TS 问题 381 。


std::experimental::ranges::advance

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
namespace {

constexpr /* unspecified */ advance = /* unspecified */;

}
 (范围 TS)
(定制点对象)
调用签名
template< Iterator I >
constexpr void advance(I& i, ranges::difference_type_t<I> n);
 (1)
template< Iterator I, Sentinel<I> S >
constexpr void advance(I& i, S bound);
 (2)
template< Iterator I, Sentinel<I> S >

constexpr ranges::difference_type_t<I>

advance(I& i, ranges::difference_type_t<I> n, S bound);
 (3)

前进迭代器 i n 次，或直至抵达 bound ，先到为止。

1) 若 I 满足 RandomAccessIterator ，则等价于 i += n 。否则自增（或若 n 为负则自减） i n 次。若 n 为负且 I 不满足 BidirectionalIterator 则行为未定义。
2) 若满足 Assignable<I&, S> ，则等价于 {{{1}}} 。
否则，若 [i, bound) 不代表范围，则行为未定义。
否则，若 SizedSentinel<S, I> 得到满足，则等价于 ranges::advance(i, bound - i) 。
否则，自增 i 直至 i == bound 。
3) 若 SizedSentinel<S, I> 得到满足，则若 |n| >= |bound - i| 则等价于 ranges::advance(i, bound) ，否则等价于 ranges::advance(i, n) 。
否则自增（或若 n 为负则自减） i n 次或直至 i == bound ，先到为止。
若 n > 0 ，则 [i, bound) 应当代表一个范围；若 n == 0 ，则 {{[i, bound)}} 或 [bound, i) 应当代表一个范围；若 n < 0 ，则 [bound, i) 应当代表一个范围，且 I 与 S 应当是同一类型，且 I 必须满足 BidirectionalIterator 。否则，行为未定义。

定制点对象

名称 ranges::advance 代表一个定制点对象，它是字面 Semiregular 类类型的函数对象（为说明目的以 AdvanceT 表示）。AdvanceT 的所有实例均相等。从而能自由地复制 ranges::advance ，且能交替使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面给 ranges::advance 的参数要求，则 AdvanceT 将满足 ranges::Invocable <const AdvanceT, Args...> 。否则，没有 AdvanceT 的函数调用运算符参与重载决议。

在每个定义 ranges::advance 的翻译单元中，它都指代定制点对象的同一实例。（这表示能自由地在类似 inline 函数和函数模板的东西中使用它，而不违反单一定义规则。）

返回值

1-2) （无）
3) 由于抵达 bound 而不进行的自增/自减次数。换言之为 n - M ，其中 M 是从 i 的开始位置到结束位置的距离，而若结束位置在开始位置之前则为负。

示例

本节未完成
原因：暂无示例

参阅

advance | 令迭代器前进给定的距离 (函数模板)
distance | 返回迭代器和哨位之间的距离，或范围起始和结尾间的距离 (函数模板)
next | 自增迭代器 (函数模板)
prev | 自减迭代器 (函数模板)


std::experimental::ranges::dangling, std::experimental::ranges::safe_iterator_t

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template < ranges::CopyConstructible T>

class dangling {
public:
dangling() requires ranges::DefaultConstructible <T>();
dangling(T t);
T get_unsafe() const;

};
 (范围 TS)
template< ranges::Range R>

using safe_iterator_t = std::conditional_t < std::is_lvalue_reference <R>::value,
ranges::iterator_t<R>,

ranges::dangling<ranges::iterator_t<R>>;
 (范围 TS)

类模板 dangling 是围绕对象的简单包装器，指示被包装对象可以悬垂，即它指代生存期可以已经结束的另一对象。

若范围为右值范围，则别名模版 safe_iterator_t 返回包装于 dangling 中的 R 类型迭代器（以非左值引用类型的 R 指示）。

接受左值范围并返回指向其中的迭代器范围算法使用它们。

成员函数

std::experimental::ranges::dangling::dangling

dangling() requires ranges::DefaultConstructible <T>(); | (1)
dangling(T t); | (2)
1) 默认构造函数。值初始化被包装对象。
2) 以 t 初始化被包装对象。注意此构造函数定义从 T 到 dangling<T> 的隐式转换。

std::experimental::ranges::dangling::get_unsafe

T get_unsafe() const;

返回被包装对象的副本。


std::experimental::ranges::difference_type

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template< class I >
struct difference_type { };
 (1)
template< class T >
struct difference_type<T*>;
 (2)
template< class T >
struct difference_type<const T> : difference_type< std::decay_t <T>> { };
 (3)
template <class T>

requires requires { typename T::difference_type; }

struct difference_type<T>;
 (4)
template <class T>

requires !requires { typename T::difference_type; } &&
requires(const T& a, const T& b) { { a - b } -> Integral; }

struct difference_type<T>;
 (5)

计算类型 I 的关联差类型，若它存在。用户可对程序定义类型特化 difference_type 。

1) 初等模板是空 struct 。
2) 对指针的特化。若 T 是对象类型，则提供等于 std::ptrdiff_t 的成员类型 type 。否则，无成员 type 。
3) 对 const 限定类型的特化。
4) 对定义公开可访问成员类型 difference_type 的类型的特化。提供等于 T::difference_type 的成员类型 type 。
5) 对不定义公开且可访问成员类型 difference_type ，但支持减法的类型的特化。提供等于 std::make_signed_t <decltype( std::declval <T>() - std::declval <T>())> 的成员类型 type 。

辅助别名模版

template< class T > using difference_type_t = typename ranges::difference_type<T>::type; | (范围 TS)

示例

本节未完成
原因：暂无示例

参阅

WeaklyIncrementable | 指定 Semiregular 类型能以前后自增运算符自增 (概念)
iterator_traits | 汇集迭代器的关联类型的兼容性特性类 (别名模板)


std::experimental::ranges::distance

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
namespace {

constexpr /* unspecified */ distance = /* unspecified */;

}
 (范围 TS)
(定制点对象)
调用签名
template< Iterator I, Sentinel<I> S >
constexpr ranges::difference_type_t<I> distance(I first, S last);
 (1)
template< Range R >
constexpr ranges::difference_type_t<ranges::iterator_t<R>> distance(R&& r);
 (2)
template< SizedRange R >
constexpr ranges::difference_type_t<ranges::iterator_t<R>> distance(R&& r);
 (3)

返回 first 与 last 间的距离，或范围 r 的首尾间的距离。

1) 若 SizedSentinel<S, I> 得到满足，则等价于 return last - first; 。否则，返回从 first 得到 last 所需的自增次数。若 [first, last) 不代表范围，则 I 与 S 必须为同一类型且必须实现 SizedSentinel ，而 [last, first) 必须指代一个范围。否则，行为未定义。
2) 等价于 return ranges::distance(ranges::begin(r), ranges::end(r)); 。
3) 等价于 return ranges::size(r); 。

若在实例化点前未包含头文件 <experimental/ranges/range> ，则实例化重载 (2-3) 可能为病式。

定制点对象

名称 ranges::distance 代表一个定制点对象，它是字面 Semiregular 类类型的函数对象（为说明目的以 DistanceT 表示）。DistanceT 的所有实例均相等。从而能自由地复制 ranges::distance ，且能交替使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面给 ranges::distance 的参数要求，则 DistanceT 将满足 ranges::Invocable <const DistanceT, Args...> 。否则，没有 DistanceT 的函数调用运算符参与重载决议。

在每个定义 ranges::distance 的翻译单元中，它都指代定制点对象的同一实例。（这表示能自由地在类似 inline 函数和函数模板的东西中使用它，而不违反单一定义规则。）

返回值

first 与 last 间的距离，或范围 r 的首尾间的距离。

示例

本节未完成
原因：暂无示例

参阅

distance | 返回两个迭代器间的距离 (函数模板)
advance | 令迭代器前进给定的距离 (函数模板)
next | 自增迭代器 (函数模板)
prev | 自减迭代器 (函数模板)
size | 获得能在常数时间计算大小的范围的大小 (定制点对象)


std::experimental::ranges::indirect_result_of

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template< class > struct indirect_result_of { };

template< class F, class... Is >
requires Invocable<F, ranges::reference_t<Is>...>
struct indirect_result_of<F(Is...)>

: std::result_of <F(ranges::reference_t<Is>&&...)> { };
 (范围 TS)


std::experimental::ranges::iterator_category

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template< class I >
struct iterator_category { };
 (1)
template< class T >
struct iterator_category<T*>;
 (2)
template< class T >
struct iterator_category<const T> : iterator_category<T> { };
 (3)
template <class T>

requires requires { typename T::iterator_category; }

struct iterator_category<T>;
 (4)

计算类 I 的迭代器类别，若它存在。用户可以对程序定义类型特化 iterator_category 。

1) 初等模板是空结构体。
2) 对指针的特化。若 T 是对象类型，则提供等于 ranges::random_access_iterator_tag 的成员类型 type 。否则，无成员 type 。
3) 对 const 限定类型的特化。
4) 对定义公开且可访问的成员类型 iterator_category 的类型的特化。若 T::iterator_category 与命名空间 std 中的迭代器类别标签之一相同或从它派生，则将它映射到描述如下的命名空间 ranges 中的对应标签。否则，提供等于 T::iterator_category 的成员类型 type 。
  • 若 T::iterator_category 与 std::random_access_iterator_tag 相同或自之派生，则提供等于 ranges::random_access_iterator_tag 的成员类型 type 。
  • 否则，若 T::iterator_category 与 std::bidirectional_iterator_tag 相同或自之派生，则提供等于 ranges::bidirectional_iterator_tag 的成员类型 type 。
  • 否则，若 T::iterator_category 与 std::forward_iterator_tag 相同或自之派生，则提供等于 ranges::forward_iterator_tag 的成员类型 type 。
  • 否则，若 T::iterator_category 与 std::input_iterator_tag 相同或自之派生，则提供等于 ranges::input_iterator_tag 的成员类型 type 。
  • 否则，若 T::iterator_category 与 std::output_iterator_tag 相同或自之派生，则无成员 type 。

辅助别名模版

template< class T > using iterator_category_t = typename ranges::iterator_category<T>::type; | (范围 TS)

示例

本节未完成
原因：暂无示例

参阅

input_iterator_tagoutput_iterator_tagforward_iterator_tagbidirectional_iterator_tagrandom_access_iterator_tagcontiguous_iterator_tag (C++20) | 用于指示迭代器类别的空类类型 (类)
input_iterator_tagoutput_iterator_tagforward_iterator_tagbidirectional_iterator_tagrandom_access_iterator_tag | 用于指示迭代器类别的空类 (类)
iterator_traits | 汇集迭代器的关联类型的兼容性特性类 (别名模板)


std::experimental::ranges::input_iterator_tag, std::experimental::ranges::output_iterator_tag, std::experimental::ranges::forward_iterator_tag, std::experimental::ranges::bidirectional_iterator_tag, std::experimental::ranges::random_access_iterator_tag

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
struct input_iterator_tag { };
struct output_iterator_tag { };
struct forward_iterator_tag : public input_iterator_tag { };
struct bidirectional_iterator_tag : public forward_iterator_tag { };
struct random_access_iterator_tag : public bidirectional_iterator_tag { };

定义迭代器的类别。每个标签是空类型，且对应五个迭代器类别之一：

  • input_iterator_tag 对应 InputIterator 。
  • forward_iterator_tag 对应 ForwardIterator 。
  • bidirectional_iterator_tag 对应 BidirectionalIterator 。
  • random_access_iterator_tag 对应 RandomAccessIterator 。
  • output_iterator_tag 对应 OutputIterator ；它不被使用，仅因后兼容性提供。

迭代器类别标签携带信息，能以之为该类别所隐含的特定要求集选择最有效的算法。然而更好的是基于概念的重载。

对每个 InputIterator 类型 I ，必须定义 ranges::iterator_category_t<I> 为描述该迭代器行为的最特定的类别标签的别名。

示例

本节未完成
原因：暂无示例

参阅

input_iterator_tagoutput_iterator_tagforward_iterator_tagbidirectional_iterator_tagrandom_access_iterator_tagcontiguous_iterator_tag (C++20) | 用于指示迭代器类别的空类类型 (类)
iterator_traits | 汇集迭代器的关联类型的兼容性特性类 (别名模板)


std::experimental::ranges::next

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
namespace {

constexpr /* unspecified */ next = /* unspecified */;

}
 (范围 TS)
(定制点对象)
调用签名
template< Iterator I >
constexpr I next(I i);
 (1)
template< Iterator I >
constexpr I next(I i, ranges::difference_type_t<I> n);
 (2)
template< Iterator I, Sentinel<I> S >
constexpr I next(I i, S bound);
 (3)
template< Iterator I, Sentinel<I> S >
constexpr I next(I i, ranges::difference_type_t<I> n, S bound);
 (4)

前进迭代器 i n 次，或直至抵达 bound ，先到为止，并返回前进的迭代器。

1) 等价于 ++i; return i; 。
2) 等价于 ranges::advance(i, n); return i; 。
3) 等价于 ranges::advance(i, bound); return i; 。
4) 等价于 ranges::advance(i, n, bound); return i; 。

定制点对象

名称 ranges::next 代表一个定制点对象，它是字面 Semiregular 类类型的函数对象（为说明目的以 NextT 表示）。NextT 的所有实例均相等。从而能自由地复制 ranges::next ，且能交替使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面给 ranges::next 的参数要求，则 NextT 将满足 ranges::Invocable <const NextT, Args...> 。否则，没有 NextT 的函数调用运算符参与重载决议。

在每个定义 ranges::next 的翻译单元中，它都指代定制点对象的同一实例。（这表示能自由地在类似 inline 函数和函数模板的东西中使用它，而不违反单一定义规则。）

返回值

前进的迭代器。

注意

虽然对重载 (2) 忽略 n 表现为如同 n 为 1 ，对重载 (4) 忽略 n 表现为 n 为无穷大（始终前进到 bound ）。

示例

本节未完成
原因：暂无示例

参阅

next (C++11) | 令迭代器自增 (函数模板)
advance | 令迭代器前进给定的距离 (函数模板)
prev | 自减迭代器 (函数模板)
distance | 返回迭代器和哨位之间的距离，或范围起始和结尾间的距离 (函数模板)


std::experimental::ranges::prev

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
namespace {

constexpr /* unspecified */ prev = /* unspecified */;

}
 (范围 TS)
(定制点对象)
调用签名
template< Iterator I >
constexpr I prev(I i);
 (1)
template< Iterator I >
constexpr I prev(I i, ranges::difference_type_t<I> n);
 (2)
template< Iterator I >
constexpr I prev(I i, ranges::difference_type_t<I> n, I bound);
 (3)

自减迭代器 i n 次，或直至抵达 bound ，先到为止，并返回自减的迭代器。

1) 等价于 --i; return i; 。
2) 等价于 ranges::advance(i, -n); return i; 。
3) 等价于 ranges::advance(i, -n, bound); return i; 。

定制点对象

名称 ranges::prev 代表一个定制点对象，它是字面 Semiregular 类类型的函数对象（为说明目的以 PrevT 表示）。PrevT 的所有实例均相等。从而能自由地复制 ranges::prev ，且能交替使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面给 ranges::prev 的参数要求，则 PrevT 将满足 ranges::Invocable <const PrevT, Args...> 。否则，没有 PrevT 的函数调用运算符参与重载决议。

在每个定义 ranges::prev 的翻译单元中，它都指代定制点对象的同一实例。（这表示能自由地在类似 inline 函数和函数模板的东西中使用它，而不违反单一定义规则。）

返回值

自减的迭代器。

示例

本节未完成
原因：暂无示例

参阅

prev (C++11) | 令迭代器自减 (函数模板)
advance | 令迭代器前进给定的距离 (函数模板)
next | 自增迭代器 (函数模板)
distance | 返回迭代器和哨位之间的距离，或范围起始和结尾间的距离 (函数模板)


std::experimental::ranges::projected

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template < ranges::Readable I, ranges::IndirectRegularUnaryInvocable <I> Proj>

struct projected {
using value_type =
std::remove_cv_t <
std::remove_reference_t <ranges::indirect_result_of_t<Proj&(I)>>
>;
ranges::indirect_result_of_t<Proj&(I)> operator*() const;
};

template < ranges::WeaklyIncrementable I, class Proj>
struct difference_type<projected<I, Proj>> {
using type = ranges::difference_type_t<I>;

};
 (范围 TS)

类模板 projected 把 Readable类型 I 和函数 Proj 打包成新的可读 (Readable) 类型，其 reference 为应用 Proj 到 I 的 reference 类型的结果。它单独为简化制约规定而存在，故而其 operator*() 可以不实际定义。


std::experimental::ranges::reference_t, std::experimental::ranges::rvalue_reference_t, std::experimental::ranges::iter_common_reference_t

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template <class T>
concept bool /*dereferenceable*/ = requires(T& t) { {*t} -> auto&&; }; // 仅为说明
template< /*dereferenceable*/ T >
using reference_t = decltype(*declval<T&>());
 (1) (范围 TS)
template< /*dereferenceable*/ T >

requires requires(T& t) { { ranges::iter_move(t) } -> auto&&; }

using rvalue_reference_t = decltype(ranges::iter_move(declval<T&>()));
 (2) (范围 TS)
template< Readable T >

using iter_common_reference_t =
ranges::common_reference_t<ranges::reference_t<T>,

ranges::value_type_t<T>&>;
 (3) (范围 TS)
1) 获得可解引用类型 T 的引用类型。
2) 获得可解引用类型 T 的右值引用类型，即 ranges::iter_move 的返回类型。
3) 计算 Readable 的共用引用类型。这是其引用类型及到其值类型的左值引用的共用引用类型。

注意

-> auto&& 制约检查表达式的类型是否非 void 。


std::experimental::ranges::value_type

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/iterator>
template< class I >
struct value_type { };
 (1)
template< class T >
struct value_type<T*>;
 (2)
template< class I >

requires std::is_array <I>::value

struct value_type<I> : value_type< std::decay_t <I>> { };
 (3)
template< class T >
struct value_type<const T> : value_type< std::decay_t <T>> { };
 (4)
template <class T>

requires requires { typename T::value_type; }

struct value_type<T>;
 (5)
template <class T>

requires requires { typename T::element_type; }

struct value_type<T>;
 (6)

计算类型 I 的关联值类型，若它存在。用户可对程序定义类型特化 value_type 。

1) 初等模板是空 struct 。
2) 对指针的特化。若 T 是对象类型，则提供等于 std::remove_cv_t <T> 的成员类型 type 。否则，无成员 type 。
3) 对数组类型的特化。
4) 对 const 限定类型的特化。
5) 对定义公开且可访问成员类型 value_type 的类型的特化。若 T::value_type 是对象类型，则提供等于 T::value_type 的成员类型 type 。否则无成员 type 。
6) 对定义公开且可访问成员类型 element_type 的类型（例如 std::shared_ptr ）的特化。若 T::element_type 是对象类型，则提供等于 std::remove_cv_t <typename T::element_type> 的成员类型 type 。否则无成员类型 type 。

辅助别名模版

template< class T > using value_type_t = typename ranges::value_type<T>::type; | (范围 TS)

注意

若类型一同含有 value_type 成员和 element_type 成员，则特化 (5) 和 (6) 有歧义。

value_type 被有意用于如迭代器的 Readable 。它并非被有意用于范围。

示例

本节未完成
原因：暂无示例

参阅

Readable | 指定类型通过应用运算符 * 可读 (概念)
iterator_traits | 汇集迭代器的关联类型的兼容性特性类 (别名模板)


std::experimental::ranges::BidirectionalRange

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/range> |
template <class T> concept bool BidirectionalRange = ranges::ForwardRange <T> && ranges::BidirectionalIterator <ranges::iterator_t<T>>; | (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::BoundedRange

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/range> |
template <class T> concept bool BoundedRange = ranges::Range <T> && ranges::Same <ranges::iterator_t<T>, ranges::sentinel_t<T>>; | (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::ForwardRange

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/range> |
template <class T> concept bool ForwardRange = ranges::InputRange <T> && ranges::ForwardIterator <ranges::iterator_t<T>>; | (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::InputRange

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/range> |
template <class T> concept bool InputRange = ranges::Range <T> && ranges::InputIterator <ranges::iterator_t<T>>; | (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::OutputRange

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/range> |
template <class R, class T> concept bool OutputRange = ranges::Range <R> && ranges::OutputIterator <ranges::iterator_t<R>, T>; | (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::RandomAccessRange

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/range> |
template <class T> concept bool RandomAccessRange = ranges::BidirectionalRange <T> && ranges::RandomAccessIterator <ranges::iterator_t<T>>; | (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::Range

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/range>
template < class T >

concept bool Range =
requires(T&& t) {
ranges::begin(t); /* 不必保持相等性（见后述） */
ranges::end(t);

};
 (范围 TS)

给定 std::remove_reference_t <T> 类型左值 t ， Range<T> 仅若下列条件成立才得到满足

  • [ranges::begin(t), ranges::end(t)) 代表一个范围；
  • ranges::begin(t) 和 ranges::end(t) 均为均摊常数时间且不修改内容。
  • 若 ranges::iterator_t<T> 满足ForwardIterator，则 ranges::begin(t) 保持相等性。


std::experimental::ranges::SizedRange

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/range>
template <class T>

concept bool SizedRange =
ranges::Range <T> &&
!ranges::disable_sized_range< std::remove_cv_t < std::remove_reference_t <T>>> &&
requires(T& t) {
{ ranges::size(t) }
-> ranges::ConvertibleTo <ranges::difference_type_t<ranges::iterator_t<T>>>;

};
 (范围 TS)
本节未完成
原因：添加描述和额外通告


std::experimental::ranges::View

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/range>
template <class T>

concept bool View = ranges::Range <T> && ranges::Semiregular <T>

&& /* view-predicate<T> */;
 (范围 TS)
template<class T>
struct enable_view {};
 (范围 TS)
struct view_base {};
 (范围 TS)

概念 View<T> 指定半常规范围 T 拥有常数时间的复制、移动和赋值操作。

概念的 /* view-predicate<T> */ 部分定义如下：

  • 若 qualified-id ranges::enable_view<T>::type 合法并代表一个范围，则为 ranges::enable_view<T>::type::value ；
  • 否则，若 std::is_base_of_v <ranges::view_base, T> 为 true ，则为 true ；
  • 否则，若 T 是 std::initializer_list 、 std::set 、 std::multiset 、 std::unordered_set 或 std::unordered_multiset 的特化，则为 false ；
  • 否则，若 T 与 const T 均满足Range且 ranges::reference_t <ranges::iterator_t<T>> 与 ranges::reference_t<ranges::iterator_t<const T>> 不是同一类型，则为 false ；
  • 否则为 true 。


std::experimental::ranges::iterator_t, std::experimental::ranges::sentinel_t

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/range> |  |
template< class T > using iterator_t = decltype(ranges::begin(declval<T&>())); | (1) | (范围 TS)
template< class T > using sentinel_t = decltype(ranges::end(declval<T&>())); | (2) | (范围 TS)

获得范围 T 的迭代器和哨位类型。


std::experimental::ranges::common_reference

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/type_traits> |
template< class... T > struct common_reference; | (范围 TS)

确定类型 T... 的公共引用类型，即 T... 中所有类型能转换或绑定到的类型。若这种类型存在（如按照后述规则所确定），则成员 type 指名该类型。否则，无成员 type 。若 T... 中的任何类型为（可有 cv 限定的） void 以外的不完整类型，则行为未定义。

给定引用类型是， common_reference 试图寻找所有提供的引用类型都能绑定到的引用类型，但若找不到这种引用类型，则可能返回非引用类型。

  • 若 sizeof...(T) 为零，则无成员 type 。
  • 若 sizeof...(T) 为一（即 T... 仅含一个类型 T0 ），则成员 type 指名与 T0 相同的类型。
  • 若 sizeof...(T) 为二（即 T... 含二个类型 T1 和 T2 ），则：
    • 若 T1 和 T2 都是引用类型，而 T1 和 T2 的简单共用引用类型 S 存在，则成员类型 type 指名 S ；
    • 否则，若 basic_common_reference<T1R, T2R, T1Q, T2Q>::type 存在，其中 TiR 为 std::remove_cv_t < std::remove_reference_t <Ti>> ，而 TiQ 为使得 TiQ<TiR> 为 Ti 的别名模版，则成员类型 type 指名该类型；
    • 否则，若 decltype(false? val<T1>() : val<T2>()) 是合法类型，其中 val 为函数模板 template<class T> T val(); ，则成员类型 type 指名该类型；
    • 否则，若 ranges::common_type_t<T1, T2> 为合法类型，则成员类型 type 为该类型；
    • 否则，无成员 type 。
  • 若 sizeof...(T) 大于二（即 T... 由 T1, T2, R... 组成），则若 ranges::common_reference_t<T1, T2> 存在，且 ranges::common_reference_t<ranges::common_reference_t<T1, T2>, R...> 存在，则成员类型 type 指代它。所有其他情况下，无成员类型 type 。

二个引用类型 T1 和 T2 的简单共用引用类型定义如下：

  • 若 T1 为 cv1 X & 而 T2 为 cv2 Y & （即都是左值引用）：则其简单共用引用类型为 decltype(false? std::declval <cv12 X &>() : std::declval <cv12 Y &>()) ，其中 cv12 为 cv1 与 cv2 的联合，若该类型存在且为引用类型；
  • 若 T1 a与 T2 均为右值引用类型：若 T1 & 和 T2 & 的简单共用引用类型（按照前一条确定）存在，则令 C 代表该类型的对应右值引用类型。若 std::is_convertible <T1, C>::value 与 std::is_convertible <T2, C>::value 均为 true ，则 T1 与 T2 的简单共用引用类型为 C 。
  • 否则，二个类型之一必须为左值引用类型 A & 而另一个必须为右值引用类型 B && （ A 与 B 可为 cv 限定）。令 D 代表 A & 与 B const & 的简单共用引用类型，若它存在。若 D 存在且 std::is_convertible <B &&, D>::value 为 true ，则简单共用引用类型为 D 。
  • 否则，无简单共用引用类型。

成员类型

名称 | 定义
type | 所有 T... 的共用引用类型

辅助类型

template< class... T >
using common_reference_t = typename common_reference<T...>::type;
template< class T, class U, template<class> class TQual, template<class> class UQual >
struct basic_common_reference { };

类模板 basic_common_reference 是定制点，允许用户影响 common_reference 对用户定义类型（常为代理引用）的结果。初等模板为空。

特化

若 std::is_same <T, std::decay_t <T>> 与 std::is_same <U, std::decay_t <U>> 皆为 true ，且它们至少有一个依赖于用户定义类型，则程序可以在前二个形参 T 和 U 上特化 basic_common_reference<T, U, TQual, UQual> 。

若这种特化拥有名为 type 的成员，则它必须是指名 TQual<T> 和 UQual<U> 都能转换到的类型的公开且无歧义的成员类型。另外， ranges::basic_common_reference<T, U, TQual, UQual>::type 和 ranges::basic_common_reference<U, T, UQual, TQual>::type 必须指代同一类型。

程序不可以在第三或第四形参上特化 basic_common_reference ，亦不可特化 common_reference 自身。以违背这些规则的方式添加特化的程序拥有未定义行为。

注意

本节未完成

示例

本节未完成
原因：暂无示例

参阅

common_type (C++11) | 确定一组类型的公共类型 (类模板)
common_type | 确定类型集合的公共类型 (类模板)
CommonReference | 指定两个类型共有一个公共引用类型 (概念)


std::experimental::ranges::common_type

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/type_traits> |
template< class... T > struct common_type; | (范围 TS)

确定所有类型 T... 中的共用类型，即所有 T... 都能隐式转换到的类型。若这种类型存在（按照后述规则确定），则成员 type 指名该类型。否则无成员 type 。若 T... 中的任何类型是异于（可有 cv 限定的） void 的不完整类型，则行为未定义。

  • 若 sizeof...(T) 为零，则无成员 type 。
  • 若 sizeof...(T) 为一（即 T... 仅含一个类型 T0 ），则成员 type 指名与 std::decay_t <T0> 相同的类型。
  • 若 sizeof...(T) 为二（即 T... 准确含二个类型 T1 和 T2 ），则
  • 若应用 std::decay 到 T1 和 T2 的至少一个产生不同类型，则成员 type 指名与 ranges::common_type_t< std::decay_t <T1>, std::decay_t <T2>> 相同的类型，若它存在；若不存在，则无成员 type 。
  • 否则，（而且除非有对于 ranges::common_type<T1, T2> 的用户特化），若 std::common_type_t <T1, T2> 为良式，则成员 type 指代该类型；
  • 否则，成员 type 指代类型 std::decay_t <decltype(false ? std::declval <const T1&>() : std::declval <const T2&>())> ，若该条件表达式为良式；若该表达式非良式，则无成员 type 。
  • 若 sizeof...(T) 大于二（即 T... 由类型 T1, T2, R... 组成），则若 ranges::common_type_t<T1, T2> 存在，则 type 代表 ranges::common_type_t<ranges::common_type_t<T1, T2>, R...> ，若这种类型存在。所有其他情况下，无成员 type 。

成员类型

名称 | 定义
type | 所有 T... 的共用类型

辅助类型

template< class... T >
using common_type_t = typename common_type<T...>::type;

特化

用户可以对类型 T1 和 T2 特化 common_type ，若

  • T1 与 T2 的至少一个依赖于用户定义类型，且
  • std::decay 对于 T1 和 T2 都是恒等变换。

若这种特化拥有名为 type 的成员，则它必须为指名无 cv 限定的非引用类型的公开且无歧义的成员类型，而 T1 与 T2 都可显式转换到它。另外， ranges::common_type_t<T1, T2> 与 ranges::common_type_t<T2, T1> 必须代表同一类型。

以违背这些规则的方式添加 common_type 特化的程序拥有未定义行为。

注意

对于不受提升影响的算术类型，共用类型可视为（可为混合模式的）算术表达式，如 T0() + T1() + ... + Tn() 的类型。

示例

本节未完成
原因：暂无示例

参阅

common_type (C++11) | 确定一组类型的公共类型 (类模板)
common_reference | 确定类型集合的公共引用类型 (类模板)


std::experimental::ranges::is_swappable_with, std::experimental::ranges::is_swappable, std::experimental::ranges::is_nothrow_swappable_with, std::experimental::ranges::is_nothrow_swappable

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/type_traits> |  |
template <class T, class U> struct is_swappable_with; | (1) | (范围 TS)
template <class T> struct is_swappable; | (2) | (范围 TS)
template <class T, class U> struct is_nothrow_swappable_with; | (3) | (范围 TS)
template <class T> struct is_nothrow_swappable; | (4) | (范围 TS)
1) 若表达式 ranges::swap( std::declval <T>(), std::declval <U>()) 和 ranges::swap( std::declval <U>(), std::declval <T>()) 在当做不求值运算数时均为良式，则提供等于 true 的成员常量 value 。否则 value 等于 false 。如同从与任一类型无关的语境进行访问检查。
2) 若 T 不是可引用类型（即可有 cv 限定的 void 或是带 cv-qualifier-seq 或 ref-qualifier 的函数类型），则提供等于 false 的成员常量 value 。否则，提供等于 ranges::is_swappable_with<T&, T&>::value 的成员常量 value 。
3) 同 (1) ，但已知来自 (1) 的两个表达式求值均不抛出异常。
4) 同 (2) ，但使用 is_nothrow_swappable_with 。

T 与 U 应当均为完整类型、（可有 cv 限定的） void 或未知边界数组。否则行为未定义。

辅助变量模板

template <class T, class U> constexpr bool is_swappable_with_v = is_swappable_with<T, U>::value; | (1) | (范围 TS)
template <class T> constexpr bool is_swappable_v = is_swappable<T>::value; | (2) | (范围 TS)
template <class T, class U> constexpr bool is_nothrow_swappable_with_v = is_nothrow_swappable_with<T, U>::value; | (3) | (范围 TS)
template <class T> constexpr bool is_nothrow_swappable_v = is_nothrow_swappable<T>::value; | (4) | (范围 TS)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 与 U 可交换则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注意

此特性不检查 swap 表达式的立即语境外的任何内容：若使用 T 或 U 会触发模板特化、生成隐式定义的特殊成员函数等，而这些内容有错误，则即使 ranges::is_swappable_with<T,U>::value 能编译并求值为 true ，实际交换也可能无法编译。

示例

本节未完成
原因：暂无示例

参阅

SwappableSwappableWith | 指定一个类型能进行交换，或两个类型能彼此交换 (概念)
is_swappable_withis_swappableis_nothrow_swappable_withis_nothrow_swappable (C++17)(C++17)(C++17)(C++17) | 检查一个类型的对象是否能与同类型或不同类型的对象交换 (类模板)


std::experimental::ranges::TagSpecifier

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/utility> |
template< class T > concept bool TagSpecifier = /* implementation-defined */; | (范围 TS)

概念 TagSpecifier<T> 若且唯若 T 是为 ranges::tagged 所用的标签指定符才得到满足。

范围 TS 提供 <experimental/ranges/algorithm> 中的标签指定符集合。用户不能定义自己的标签指定符。

参阅

tagged | 为元组式类型增加具名访问器 (类模板)
inin1in2outout1out2funminmaxbeginend | 用于 ranges::tagged 的标签说明符 (类)


std::experimental::ranges::TaggedType

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/utility> |
template< class T > concept bool TaggedType = /* implementation-defined */; | (范围 TS)

概念 TaggedType<T> 若且唯若 T 为形式为 R(A) 的函数类型才得到满足，其中 R 是 TagSpecifier 。

这些类型为便利别名模板 tagged_tuple 和 tagged_pair 所用。

参阅

tagged_tuple | 有标签 std::tuple 的别名模版 (别名模板)
tagged_pair | 有标签 std::pair 的别名模版 (别名模板)
inin1in2outout1out2funminmaxbeginend | 用于 ranges::tagged 的标签说明符 (类)


std::experimental::ranges::exchange

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/utility>
template< ranges::MoveConstructible T, class U = T >

requires ranges::Assignable <T&, U>

constexpr T exchange(T& obj, U&& new_val) noexcept(/* see below */);
 (范围 TS)

以 new_value 替换 obj 的值并返回 obj 的旧值，如同用以下方式

T old_value = std::move(obj);
obj = std::forward<U>(new_value);
return old_value;

参数

obj | - | 要替换其值的对象
new_value | - | 要赋给 obj 的值

返回值

obj 的旧值。

异常

noexcept 说明：
noexcept( std::is_nothrow_move_constructible <T>::value &&
std::is_nothrow_assignable <T&, U>::value)

示例

本节未完成
原因：暂无示例

参阅

exchange
(C++14)
 将实参替换为一个新值，并返回其先前值
(函数模板)


std::experimental::ranges::make_tagged_pair

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/utility>
template< ranges::TagSpecifier Tag1, ranges::TagSpecifier Tag2, class T1, class T2>
constexpr ranges::tagged</*see below*/, Tag1, Tag2> make_tagged_pair(T1&& x, T2&& y);
 (范围 TS)

创建 tagged_pair 的便利函数，从参数推导元素类型（必须显式指定标签指定符）。

返回类型的 see below 部分是 decltype( std::make_pair ( std::forward <T1>(x), std::forward <T2>(y))) 。

返回值

R( std::forward <T1>(x), std::forward <T2>(y)) ，其中 R 是返回类型。

参阅

TaggedType | 指定类型表示一个标签说明符及其元素类型 (概念)
tagged | 为元组式类型增加具名访问器 (类模板)
tagged_pair | 有标签 std::pair 的别名模版 (别名模板)
tagged_tuple | 有标签 std::tuple 的别名模版 (别名模板)
make_tagged_tuple | 用于创建 tagged_tuple 的便利函数 (函数模板)
inin1in2outout1out2funminmaxbeginend | 用于 ranges::tagged 的标签说明符 (类)


std::experimental::ranges::make_tagged_tuple

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/tuple>
template< ranges::TagSpecifier... Tags, class... Types>

requires sizeof...(Tags) == sizeof...(Types)

constexpr ranges::tagged</*see below*/, Tags...> make_tagged_tuple(Types&&... t);
 (范围 TS)

创建 tagged_tuple 的便利函数模板，从参数推导元素类型（必须显式指定标签指定符）。

返回类型的 see below 部分是 decltype( std::make_tuple ( std::forward <Types>(t)...)) 。

返回值

R( std::forward <Types>(t)...) ，其中 R 为返回类型。

参阅

TaggedType | 指定类型表示一个标签说明符及其元素类型 (概念)
tagged | 为元组式类型增加具名访问器 (类模板)
tagged_pair | 有标签 std::pair 的别名模版 (别名模板)
make_tagged_pair | 用于创建 tagged_pair 的便利函数 (函数模板)
tagged_tuple | 有标签 std::tuple 的别名模版 (别名模板)
inin1in2outout1out2funminmaxbeginend | 用于 ranges::tagged 的标签说明符 (类)


std::experimental::ranges::swap

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/utility>
namespace {

constexpr /* unspecified */ swap = /* unspecified */;

}
 (范围 TS)
(定制点对象)
调用签名
template< class T, class U >

requires /* see below */

void swap(T&& t, U&& u) noexcept(/* see below */);

交换 t 和 u 所引用的值。

调用 ranges::swap 等价于：

1) (void)swap( std::forward <T>(t), std::forward <U>(u)) ，若该表达式合法，其中以下列候选进行重载决议：
  • template<class T> void swap(T&, T&) = delete;
  • template<class T, std::size_t N> void swap(T(&)[N], T(&)[N]) = delete;
  • 参数依赖查找所找到的任何 swap 的声明。
若重载决议所选择的函数不交换 t 和 u 所引用的值，则程序为为病式；不要求诊断。
2) 否则为 (void)ranges::swap_ranges(t, u) ，若 T 和 U 为到相等长度（但元素类型可能不同）的数组类型的左值引用，且 ranges::swap(*t, *u) 为合法表达式；
3) 否则，若 T 与 U 均为 V& ，而 V 是满足 ranges::MoveConstructible <V> 和 ranges::Assignable <V&, V> 要求的某个类型，则如同用 V v{std::move(t)}; t = std::move(u); u = std::move(v); 交换其被引用值。若任一概念的语义要求未得到满足，则程序为病式；不要求诊断。
4) 所有其他情况下，对 ranges::swap 的调用为病式。

若 ranges::swap 调用的每个函数（按上述方式指定）都能用于常量表达式中，则亦能如此使用它。

定制点对象

名称 ranges::swap 代表一个定制点对象，它是字面 Semiregular 类类型的函数对象（为说明目的以 SwapT 表示）。SwapT 的所有实例均相等。从而能自由地复制 ranges::swap ，且能交替使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面给 ranges::swap 的参数要求，则 SwapT 将满足 ranges::Invocable <const SwapT, Args...> 。否则，没有 SwapT 的函数调用运算符参与重载决议。

在每个定义 ranges::swap 的翻译单元中，它都指代定制点对象的同一实例。（这表示能自由地在类似 inline 函数和函数模板的东西中使用它，而不违反单一定义规则。）

异常

1)
noexcept 说明：
noexcept(noexcept((void)swap( std::forward <T>(t), std::forward <T>(u))))
，其中按上述方式找到 swap 。
2)
noexcept 说明：
noexcept(noexcept(ranges::swap(*t, *u)))
3)
noexcept 说明：
noexcept( std::is_nothrow_move_constructible <V>::value &&
std::is_nothrow_move_assignable <V>::value)

示例

本节未完成
原因：暂无示例

参阅

swap
 交换两个对象的值
(函数模板)


std::experimental::ranges::tagged

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/utility>
template< class Base, ranges::TagSpecifier... Tags >

requires sizeof...(Tags) <= std::tuple_size <Base>::value

struct tagged;
 (范围 TS)

类模板 tagged 将标签指定符 Tags... 所指定的具名访问器集合增设到其所公开派生的仿 tuple 类 Base 。按顺序应用标签： Tags... 中第 i 个标签指定符对应 tuple 的第 i 个元素。

Tags... 中的标签指定符应当是独一无二的。否则行为未定义。

不可能通过指向异于 Base 的任何基类的指针删除 tagged 的实例。

成员函数

(构造函数) | 构造 tagged 对象 (公开成员函数)
operator= | 赋值 tagged 对象 (公开成员函数)
swap | 交换二个 tagged 对象的内容 (公开成员函数)

具名元素访问器

对于 Tags... 中对应元素名为 name 的第 N 个标签指定符， tagged 提供如下的名为 name 的具名访问器：

constexpr decltype(auto) name() &       { return std::get<N>(*this); }
constexpr decltype(auto) name() const & { return std::get<N>(*this); }
constexpr decltype(auto) name() &&      { return std::get<N>(std::move(*this)); }

非成员函数

ranges::swap(ranges::tagged)
 为 tagged 对象特化 swap
(函数)

仿 tuple 访问

std::tuple_size<std::experimental::ranges::tagged> | 获得 tagged 的大小 (类模板特化)
std::tuple_element<std::experimental::ranges::tagged> | 获得 tagged 的元素的类型 (类模板特化)

参阅

TagSpecifier | 指定类型为标签说明符 (概念)
tagged_pair | 有标签 std::pair 的别名模版 (别名模板)
make_tagged_pair | 用于创建 tagged_pair 的便利函数 (函数模板)
tagged_tuple | 有标签 std::tuple 的别名模版 (别名模板)
make_tagged_tuple | 用于创建 tagged_tuple 的便利函数 (函数模板)
inin1in2outout1out2funminmaxbeginend | 用于 ranges::tagged 的标签说明符 (类)


std::experimental::ranges::tagged<Base,Tags...>::operator=

< cpp‎ | experimental‎ | ranges‎ | utility/tagged
tagged &operator=(tagged&& that) = default;
 (1)
tagged &operator=(const tagged& that) = default;
 (2)
template <class Other>

requires ranges::Assignable <Base&, Other>
constexpr tagged& operator=(ranges::tagged<Other, Tags...>&& that)

noexcept( std::is_nothrow_assignable <Base&, Other>::value);
 (3)
template <class Other>

requires ranges::Assignable <Base&, const Other&>

constexpr tagged& operator=(const ranges::tagged<Other, Tags...>& that);
 (4)
template <class U>

requires ranges::Assignable <Base&, U> && ! ranges::Same < std::decay_t <U>, tagged>

constexpr tagged& operator=(U&& that) noexcept( std::is_nothrow_assignable <Base&, U>::value);
 (5)

赋值 that 的内容给 *this 。

1-2) tagged 拥有默认化的复制和移动赋值运算符，它们调用 Base 的对应赋值运算符。
3) 源自带匹配标签的相异 tagged 特化的转换移动赋值运算符。等价于 static_cast<Base&>(*this) = static_cast<Other&&>(that); 。
4) 源自带匹配标签的相异 tagged 特化转换复制赋值运算符。等价于 static_cast<Base&>(*this) = static_cast<const Other&>(that); 。
5) 赋值 that 给 Base 子对象。等价于 static_cast<Base&>(*this) = std::forward <U>(that); 。

返回值

*this 。


std::experimental::ranges::tagged<Base,Tags...>::swap

< cpp‎ | experimental‎ | ranges‎ | utility/tagged
constexpr void swap(tagged& rhs) noexcept(/* see below */)
requires ranges::Swappable <Base>;

如同以 ranges::swap(static_cast<Base&>(*this), static_cast<Base&>(rhs)); 交换 *this 与 rhs 的内容。

异常

noexcept 说明：
noexcept(noexcept(ranges::swap( std::declval <Base&>(), std::declval <Base&>())))

参阅

ranges::swap(ranges::tagged)
 为 tagged 对象特化 swap
(函数)


std::experimental::ranges::swap (ranges::tagged)

< cpp‎ | experimental‎ | ranges‎ | utility/tagged
friend constexpr void swap(tagged& lhs, tagged& rhs) noexcept(noexcept(lhs.swap(rhs)))
requires ranges::Swappable <Base>;

如同以 lhs.swap(rhs); 交换 *this 与 rhs 的内容。

此函数对通常无限定或有限定查找不可见，而只能在 tagged 为参数的关联类时由实参依赖查找找到。

注解

不同于标准库中的大多数非成员 swap ，此 swap 是声明于 tagged 体中的隐藏友元，而非函数模板。函数声明中的 tagged 是注入类名。

参阅

swap
 交换二个 tagged 对象的内容
(公开成员函数)


std::experimental::ranges::tagged<Base,Tags...>::tagged

< cpp‎ | experimental‎ | ranges‎ | utility/tagged
using Base::Base;
 (1)
tagged() = default;
 (2)
tagged(tagged&& that) = default;
 (3)
tagged(const tagged& that) = default;
 (4)
tagged(Base&& that) noexcept( std::is_nothrow_move_constructible <Base>::value)
requires ranges::MoveConstructible <Base>;
 (5)
tagged(const Base& that) noexcept( std::is_nothrow_copy_constructible <Base>::value)
requires ranges::CopyConstructible <Base>;
 (6)
template <class Other>

requires ranges::Constructible <Base, Other>
constexpr tagged(ranges::tagged<Other, Tags...> && that)

noexcept( std::is_nothrow_constructible <Base, Other>::value);
 (7)
template <class Other>

requires ranges::Constructible <Base, const Other&>

constexpr tagged(const ranges::tagged<Other, Tags...> &that);
 (8)

构造 tagged 对象。

1) tagged<Base, Tags...> 继承 Base 的构造函数。
2-4) tagged 拥有默认化的默认、赋值和移动构造函数，它们调用 Base 的对应构造函数。
5) 源自 Base 的转换移动构造函数。以 std::move(that) 初始化 Base 子对象。
6) 源自 Base 的转换复制构造函数。以 that 初始化 Base 子对象。
7) 源自带匹配标签的相异 tagged 特化的转换移动构造函数。以 static_cast<Other&&>(that) 初始化 Base 子对象。
8) 源自带匹配标签的相异 tagged 特化的转换复制构造函数。以 static_cast<const Other&>(that) 初始化 Base 子对象。


std::tuple_element<std::experimental::ranges::tagged>

< cpp‎ | experimental‎ | ranges‎ | utility/tagged
template< std::size_t N, class Base, class... Tags >

struct tuple_element<N, std::experimental::ranges::tagged<Base, Tags...>>

: std::tuple_element <N, Base> { };
 (范围 TS)

std::tuple_element 对 tagged 的偏特化提供用仿 tuple 语法编译时访问 tagged 元素类型的能力。它简单地转发到 std::tuple_element <N, Base> 。

成员类型

成员类型 | 定义
type | std::tuple_element_t <N, Base>

参阅

std::tuple_element<std::tuple> (C++11) | 获得指定元素的类型 (类模板特化)
std::tuple_element<std::array> (C++11) | 获得 array 元素的类型 (类模板特化)
std::tuple_element<std::pair> (C++11) | 获得 pair 中元素的类型 (类模板特化)
std::tuple_size<std::experimental::ranges::tagged> | 获得 tagged 的大小 (类模板特化)


std::tuple_size<std::experimental::ranges::tagged>

< cpp‎ | experimental‎ | ranges‎ | utility/tagged
template< class Base, class... Tags >

struct tuple_size<std::experimental::ranges::tagged<Base, Tags...>>

: std::tuple_size <Base> { };
 (范围 TS)

std::tuple_size 对 tagged 的部分特化提供用仿 tuple 语法获得 tagged 对象中元素的能力。它简单地转发到 std::tuple_size <Base> 。

继承自 std::integral_constant

成员常量

value
[静态]
 std::tuple_size <Base>::value
(公开静态成员常量)

成员函数

operator std::size_t | 转换对象为 std::size_t ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | std::size_t
type | std::integral_constant < std::size_t, value>

参阅

std::tuple_size<std::tuple> (C++11) | 在编译时获得 tuple 的大小 (类模板特化)
std::tuple_size<std::array> (C++11) | 获得 array 的大小 (类模板特化)
std::tuple_size<std::pair> (C++11) | 获得 pair 的大小 (类模板特化)
std::tuple_element<std::experimental::ranges::tagged> | 获得 tagged 的元素的类型 (类模板特化)


std::experimental::ranges::tagged_pair

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/utility>
template< ranges::TaggedType T1, ranges::TaggedType T2 >
using tagged_pair = /* see below */;
 (范围 TS)

用于命名包装 std::pair 的 ranges::tagged 的便利别名模版。

TaggedType 是 S(T) 类型函数，其中 S 为 TagSpecifier 而 T 为元素类型。

tagged_pair<S1(T1), S2(T2)> is an alias for ranges::tagged< std::pair <T1, T2>, S1, S2>.

注意

因为用函数类型“粘”着标签指定符和对应的元素类型，故应用通常参数类型调整。具体而言即移除顶层 cv 限定符并调整数组类型为指针： tagged_pair<tag::in(const int* const), tag::out(int[])> 即是 ranges::tagged< std::pair <const int*, int*>, tag::in, tag::out> 。

参阅

TaggedType | 指定类型表示一个标签说明符及其元素类型 (概念)
tagged | 为元组式类型增加具名访问器 (类模板)
make_tagged_pair | 用于创建 tagged_pair 的便利函数 (函数模板)
tagged_tuple | 有标签 std::tuple 的别名模版 (别名模板)
make_tagged_tuple | 用于创建 tagged_tuple 的便利函数 (函数模板)
inin1in2outout1out2funminmaxbeginend | 用于 ranges::tagged 的标签说明符 (类)


std::experimental::ranges::tagged_tuple

< cpp‎ | experimental‎ | ranges
定义于头文件 <experimental/ranges/tuple>
template< ranges::TaggedType... Types >
using tagged_tuple = /* see below */;
 (范围 TS)

用于命名包装 std::tuple 的 ranges::tagged 的便利别名模板。

TaggedType 是函数类型 S(T) ，其中 S 为 TagSpecifier 而 T 是元素类型。

tagged_tuple<S1(T1), ..., SN(TN)> 是 ranges::tagged< std::tuple <T1, ..., TN>, S1, ..., SN> 的别名。

注意

因为用函数类型“粘”着标签指定符和对应的元素类型，故应用通常参数类型调整。具体而言即移除顶层 cv 限定符并调整数组类型为指针： tagged_tuple<tag::in(const int* const), tag::out(int[])> 即是 ranges::tagged< std::tuple <const int*, int*>, tag::in, tag::out> 。

参阅

TaggedType | 指定类型表示一个标签说明符及其元素类型 (概念)
tagged | 为元组式类型增加具名访问器 (类模板)
tagged_pair | 有标签 std::pair 的别名模版 (别名模板)
make_tagged_pair | 用于创建 tagged_pair 的便利函数 (函数模板)
make_tagged_tuple | 用于创建 tagged_tuple 的便利函数 (函数模板)
inin1in2outout1out2funminmaxbeginend | 用于 ranges::tagged 的标签说明符 (类)


反射扩展

< cpp‎ | experimental

C++ 反射扩展， ISO/IEC TS 23619:2021 ，指定对核心语言的更改并对 C++ 标准库定义此页面上列出的新组件。

反射 TS 基于 C++20 标准（除了概念的定义以概念 TS 的风格指定）。

核心语言更改

reflexpr 说明符

reflexpr-说明符 形式为 reflexpr ( reflexpr-操作数 ) ，并指定一个元对象类型（见后述）。

reflexpr-操作数 能为下列之一：

:: | (1)
类型标识 | (2)
嵌套名说明符(可选) 命名空间名 | (3)
标识表达式 | (4)
( 表达式 ) | (5)
函数调用表达式 | (6)
函数式类型转换表达式 | (7)

其中 函数调用表达式 为

后缀表达式 ( 表达式列表(可选) )

而 函数式类型转换表达式 为以下种类的进行显式转型的表达式：

简单类型说明符 ( 表达式列表(可选) ) | (1)
typename-说明符 ( 表达式列表(可选) ) | (2)
简单类型说明符 花括号初始化器列表 | (3)
typename-说明符 花括号初始化器列表 | (4)

给 reflexpr-说明符 的操作数应当是类型、命名空间、枚举项、变量、数据成员、函数形参、被捕获实体、 函数调用表达式 或 函数式类型转换表达式 及有括号表达式。 reflexpr(::) 反射全局命名空间。

对于形式为 ( 表达式 ) 的 reflexpr-操作数 ， 表达式 应当为（可能有多重括号的） 函数调用表达式 或 函数式类型转换表达式 。

若无括号的操作数能被当作 类型标识 或 函数式类型转换表达式 ，则它被当作 类型标识 。能用括号消歧义函数风格转型与 类型标识 。例如，给定的拥有默认构造函数的类类型 X ， reflexpr(X()) 反射函数类型 X() ，而 reflexpr((X())) 反射表达式 X() 。

若操作数一并指代别名和类名，则 reflexpr 说明符所表示的类型反射别名并满足 reflect::Alias 。

若操作数指代声明被围绕在块作用域内的名字且该具名实体既非捕获亦非函数形参，则程序非良构。

元对象类型

元对象类型是无名、不完整的命名空间作用域类类型。一个类型满足概念 reflect::Object 当且仅当它是元对象类型。元对象类型亦可能满足其他概念，取决于 reflexpr 的操作数。

重复应用 reflexpr 到同一操作数是产生同一类型还是不同类型是未指定的。若元对象类型反射不完整类类型，则不能应用某些类型变换。

元对象类型允许通过类型表征或其上的类型变换查询 reflexpr 的操作数的某些属性。

重载决议

若 函数调用表达式 的 后缀表达式 拥有类类型，例如 是 函数调用表达式 e(args) 中的 e 拥有类类型，则 后缀表达式 （ e ）的类型的用户定义转换函数不应当被使用。

若 后缀表达式 不拥有类类型，则它应当指名作为重载决议唯一结果的函数。

struct Functor {
    void operator()(int) const;

    using fptr_t = void(*)(std::nullptr_t);
    operator fptr_t() const;
};

using Meta0 = reflexpr(Functor{}(0));          // OK
// using Meta1 = reflexpr(Functor{}(nullptr)); // 错误：使用了转换函数

反射相关

别名是 typedef 声明、别名声明或 using 声明所引入的名字。

实体或别名 B 反射相关到实体或别名 A ，若

  1. A 与 B 为同一实体或别名，
  2. A 为变量或枚举项而 B 为 A 的类型，
  3. A 为枚举而 B 为 A 的底层类型，
  4. A 为类而 B 为 A 的成员或基类，
  5. A 为指代实体 B 的非模板别名，
  6. A 不是全局命名空间而 B 是 A 的外围类或外围命名空间，
  7. A 为有括号表达式 ( B ) ，
  8. A 为闭包类型 B 的 lambda 捕获，
  9. A 为 lambda 捕获 B 的闭包类型，
  10. B 为 函数式类型转换表达式 A 所指定的类型，
  11. B 为重载决议对 函数调用表达式 A 所选择的函数，
  12. B 为函数 A 的返回类型、形参类型或函数类型，或
  13. B 反射相关到实体或别名 X 而 X 反射相关到 A 。

反射相关关系为自反和传递，但非对称。

不正式而言， B 反射相关到 A 的情况表示 B 参与 A 的声明或定义。

零或多次相继应用产生元对象类型的类型变换到 reflexpr-说明符 所代表的类型，使得用户能查阅反射相关到操作数的实体和别名；我们称这种元对象类型反射相应的反射相关的类型或实体。

struct X;
struct B {
    using X = ::X;
    typedef X Y;
};
struct D : B {
    using B::Y;
};
// ::X ，但非 B::X 或 B::Y 反射相关到 D::Y

杂项

  • 用作 reflexpr-操作数 的表达式为不求值表达式并被潜在常量求值。
  • 对于确定以捕获默认在 lambda 表达式中捕获的变量的目的，不认为 reflexpr 操作数是不求值操作数。
  • 元对象类型 T 所反射的函数或拥有静态存储期的变量被 std::experimental::reflect::get_pointer<T> 的特化 odr 式使用，如同通过取指名该函数或变量的标识表达式的地址。
  • 元对象类型能有多于一个定义，只要此类型上的所有操作都产生相同的常量表达式结果。
  • 一个类型为待决，若它为 reflexpr 说明符所指代，且操作数
    • 为类型待决表达式或（可能有括号的） 函数式类型转换表达式 且至少拥有一个类型待决的立即子表达式，或
    • 指代待决类型或未知特化的成员或值待决的常量表达式。

关键词

reflexpr

预定义功能特性测试宏

__cpp_reflection
 至少为 201902 的值，指示反射 TS 受到支持
(宏常量)

库支持

概念

定义于头文件 <experimental/reflect>
定义于命名空间 std::experimental::reflect
定义于内联命名空间 std::experimental::reflect::v1
Object (反射 TS) | 指定类型为元对象类型 (概念)
ObjectSequence (反射 TS) | 指定元对象类型为元对象序列类型 (概念)
TemplateParameterScope (反射 TS) | 指定元对象类型反射模板形参作用域 (概念)
Named (反射 TS) | 指定元对象类型反射具有关联（可能为空的）名字的实体 (概念)
Alias (反射 TS) | 指定元对象类型反射类型别名、命名空间别名或由 using 声明引入的别名 (概念)
RecordMember (反射 TS) | 指定元对象类型反射类的 成员说明 (概念)
Enumerator (反射 TS) | 指定元对象类型反射枚举项 (概念)
Variable (反射 TS) | 指定元对象类型反射变量或数据成员 (概念)
ScopeMember (反射 TS) | 指定元对象类型满足 RecordMember 、 Enumerator 或 Variable ，或反射全局命名空间以外的命名空间 (概念)
Typed (反射 TS) | 指定元对象类型反射具有类型的实体 (概念)
Namespace (反射 TS) | 指定元对象类型反射命名空间 (概念)
GlobalScope (反射 TS) | 指定元对象类型反射全局命名空间 (概念)
Class (反射 TS) | 指定元对象类型反射非联合类类型 (概念)
Enum (反射 TS) | 指定元对象类型反射枚举类型 (概念)
Record (反射 TS) | 指定元对象类型反射类类型 (概念)
Scope (反射 TS) | 指定元对象类型反射命名空间、类、枚举、闭包类型、模板实参作用域 (概念)
Type (反射 TS) | 指定元对象类型反射一个类型 (概念)
Constant (反射 TS) | 指定元对象类型反射枚举项或 constexpr 变量 (概念)
Base (反射 TS) | 指定元对象类型反射从 get_base_classes 获得的直接基类 (概念)
FunctionParameter (反射 TS) | 指定元对象类型反射模板形参 (概念)
Callable (反射 TS) | 指定元对象类型反射函数（包括构造函数与析构函数） (概念)
Expression (反射 TS) | 指定元对象类型反射表达式 (概念)
ParenthesizedExpression (反射 TS) | 指定元对象类型反射有括号表达式 (概念)
FunctionCallExpression (反射 TS) | 指定元对象类型反射 函数调用表达式 (概念)
FunctionalTypeConversion (反射 TS) | 指定元对象类型反射 函数式类型转换表达式 (概念)
Function (反射 TS) | 指定元对象类型反射函数（不含构造函数与析构函数） (概念)
MemberFunction (反射 TS) | 指定元对象类型反射成员函数I（不含构造函数与析构函数） (概念)
SpecialMemberFunction (反射 TS) | 指定元对象类型反射特殊成员函数 (概念)
Constructor (反射 TS) | 指定元对象类型反射构造函数 (概念)
Destructor (反射 TS) | 指定元对象类型反射析构函数 (概念)
Operator (反射 TS) | 指定元对象类型反射运算符函数或转换函数 (概念)
ConversionOperator (反射 TS) | 指定元对象类型反射转换函数 (概念)
Lambda (反射 TS) | 指定元对象类型反射非泛型 lambda 的闭包类型 (概念)
LambdaCapture (反射 TS) | 指定元对象类型反射 lambda 捕获 (概念)

元对象操作

定义于头文件 <experimental/reflect>
定义于命名空间 std::experimental::reflect
定义于内联命名空间 std::experimental::reflect::v1
Object 操作
reflects_same
(反射 TS)
 检查二个元对象类型是否反射同一实体或别名
(类模板)
get_source_line
(反射 TS)
 获得被反射实体或别名的声明的预设行号
(类模板)
get_source_column
(反射 TS)
 获得被反射实体或别名的声明的实现定义列号
(类模板)
get_source_file_name
(反射 TS)
 获得被反射实体或别名的声明的预设文件名
(类模板)
ObjectSequence 操作
get_size
(反射 TS)
 获得元对象序列的大小
(类模板)
get_element
(反射 TS)
 获得元对象序列中拥有给定下标的元对象类型
(类模板)
unpack_sequence
(反射 TS)
 应用模板到元对象序列
(类模板)
Named 操作
is_unnamed
(反射 TS)
 检查被反射实体或别名是否具名
(类模板)
get_name
(反射 TS)
 获得被反射实体或别名的无限定名
(类模板)
get_display_name
(反射 TS)
 获得被反射实体或别名的实现定义显示名
(类模板)
Alias 操作
get_alias
(反射 TS)
 获得反射被反射别名的关联实体的元对象类型
(类模板)
Type 操作
get_type
(反射 TS)
 获得反射被反射实体或别名的类型的元对象类型
(类模板)
get_reflected_type
(反射 TS)
 获得反射被反射实体或别名的类型
(类模板)
is_enum
(反射 TS)
 检查元对象类型是否反射枚举类型
(类模板)
is_union
(反射 TS)
 检查元对象类型是否反射联合体类型
(类模板)
uses_class_keyuses_struct_key
(反射 TS)
 分别检查元对象类型是否反射声明使用 class 或 struct 的非联合类类型
(类模板)
ScopeMember 操作
get_scope
(反射 TS)
 获得反射被反射实体或别名的作用域的元对象类型
(类模板)
Base 操作
get_class
(反射 TS)
 获得反射给定基类关系中基类的元对象类型
(类模板)
RecordMember 与 Base 操作
is_public
(反射 TS)
 检查被反射的成员或基类是否为公开
(类模板)
is_protected
(反射 TS)
 检查被反射的成员或基类是否为受保护
(类模板)
is_private
(反射 TS)
 检查被反射的成员或基类是否为私有
(类模板)
Record 操作
get_public_data_membersget_accessible_data_membersget_data_members
(反射 TS)
 获得元素反射被反射类的公开、可访问或全部数据成员的元对象序列类型
(类模板)
get_public_member_functionsget_accessible_member_functionsget_member_functions
(反射 TS)
 获得元素反射被反射类的公开、可访问或全部成员函数的元对象序列类型
(类模板)
get_constructors
(反射 TS)
 获得元素反射被反射类的全部构造函数的的元对象序列类型
(类模板)
get_operators
(反射 TS)
 获得元素反射声明于被反射类中的所有运算符函数及转换函数的的元对象序列类型
(类模板)
get_destructor
(反射 TS)
 获得反射被反射类的析构函数的元对象类型
(类模板)
get_public_member_typesget_accessible_member_typesget_member_types
(反射 TS)
 获得元素反射被反射类的公开、可访问或全部成员类型的元对象序列类型
(类模板)
get_public_base_classesget_accessible_base_classesget_base_classes
(反射 TS)
 获得元素反射被反射类的公开、可访问或全部基类的元对象序列类型
(类模板)
Enum 操作
is_scoped_enum
(反射 TS)
 检查被反射枚举是否有作用域
(类模板)
get_enumerators
(反射 TS)
 获得元素反射被反射枚举的枚举项的元对象序列类型
(类模板)
get_underlying_type
(反射 TS)
 获得反射被反射枚举的底层类型的元对象类型
(类模板)
Variable 操作
get_constant
(反射 TS)
 获得作为常量表达式的被反射变量的值
(类模板)
is_thread_local
(反射 TS)
 检查变量是否声明带 thread_local
(类模板)
FunctionParameter 操作
has_default_argument
(反射 TS)
 检查被反射的形参是否有默认实参
(类模板)
Callable 操作
get_parameters
(反射 TS)
 获得元素反射被反射函数的形参的元对象序列类型
(类模板)
is_vararg
(反射 TS)
 检查被反射函数的形参列表是否含有省略号形参
(类模板)
is_noexcept
(反射 TS)
 检查被反射函数是否为不抛出
(类模板)
is_deleted
(反射 TS)
 检查被反射函数是否为被删除
(类模板)
Variable 与 Callable 操作
is_constexpr
(反射 TS)
 检查被反射变量或函数是否为 constexpr
(类模板)
Namespace 与 Callable 操作
is_inline
(反射 TS)
 检查被反射的命名空间或函数是否为 inline
(类模板)
ParenthesizedExpression 操作
get_subexpression
(反射 TS)
 获得反射被反射的有括号表达式的无括号表达式的元对象类型
(类模板)
FunctionCallExpression 操作
get_callable
(反射 TS)
 获得反射被反射的 函数调用表达式 中的函数的元对象类型
(类模板)
FunctionalTypeConversion 操作
get_constructor
(反射 TS)
 获得反射被反射的 函数式类型转换表达式 中的构造函数的元对象类型
(类模板)
Variable 与 Function 操作
get_pointer
(反射 TS)
 获得被反射变量或函数的地址，或指向非静态成员的成员指针值
(类模板)
MemberFunction 函数
is_constis_volatilehas_lvalueref_qualifierhas_rvalueref_qualifier
(反射 TS)
 分别检查被反射成员函数是否声明带 const、 volatile、 & 或 && 限定符
(类模板)
is_override
(反射 TS)
 检查被反射的成员函数是否重写基类的成员函数
(类模板)
Record 与 MemberFunction 操作
is_final
(反射 TS)
 检查被反射的类或成员函数是否标记为 final
(类模板)
Variable 与 MemberFunction 操作
is_static
(反射 TS)
 检查被反射的变量是否拥有静态存储期，或被反射的成员函数是否为静态
(类模板)
SpecialMemberFunction 操作
is_implicitly_declared
(反射 TS)
 检查被反射的特殊成员函数是否为隐式声明
(类模板)
is_defaulted
(反射 TS)
 检查被反射的成员函数是否在其首条声明预置
(类模板)
Constructor 与 ConversionOperator 操作
is_explicit
(反射 TS)
 检查被反射的构造函数或转换函数是否声明带 explicit
(类模板)
MemberFunction 与 Destructor 操作
is_virtual
(反射 TS)
 检查被反射的成员函数是否为虚
(类模板)
is_pure_virtual
(反射 TS)
 检查被反射的成员函数是否为纯虚
(类模板)
Lambda 操作
get_captures
(反射 TS)
 获得元素反射被反射闭包类型的捕获的元对象序列类型
(类模板)
uses_default_copy_captureuses_default_reference_capture
(反射 TS)
 分别检查被反射闭包类型的 lambda 表达式的捕获默认是否为 = 或 &
(类模板)
is_call_operator_const
(反射 TS)
 检查被反射闭包类型的 operator() 是否声明带 const
(类模板)
LambdaCapture 操作
is_explictly_captured
(反射 TS)
 检查被反射的 lambda 捕获是否被显式捕获
(类模板)
is_init_capture
(反射 TS)
 检查被反射的 lambda 捕获是否为初始化捕获
(类模板)

库功能特性测试宏

定义于头文件 <experimental/reflect>
__cpp_lib_reflection
 至少为 201902 的值，指示反射 TS 的支持库受到支持
(宏常量)

概念的满足

下表列出反射一个操作数的类型是否满足一个反射 TS 所引入的概念。

类别 | reflexpr 操作数 | 满足的概念
类型 | 指代联合体的 类名 | reflect::Union
 | 指代闭包类型的 类名 | reflect::Lambda
 | 指代非 union 类的 类名 | reflect::Record
 | 枚举名 | reflect::Enum
 | 模板 类型形参 | reflect::Type, reflect::Alias
 | decltype-说明符 | reflect::Type, reflect::Alias
 | using 声明所引入的 类型名 | reflect::Type, reflect::Alias, reflect::ScopedMember
 | 任何其他 typedef-名 | reflect::Type, reflect::Alias
 | 任何其他 类型标识 | reflect::Type
命名空间 | 命名空间别名 | reflect::Namespace, reflect::Alias
 | 全局命名空间 | reflect::GlobalScope
 | 任何其他命名空间 | reflect::Namespace
表达式 | 数据成员名 | reflect::Variable
 | 变量名 | reflect::Variable
 | 枚举项名 | reflect::Enumerator
 | 函数形参名 | reflect::FunctionParameter
 | 被捕获实体之名 | reflect::LambdaCapture
 | 带括号表达式 | reflect::ParenthesizedExpression
 | 函数调用表达式 | reflect::FunctionCallExpression
 | 函数式类型转换表达式 | reflect::FunctionalTypeConversion

若形式为标识表达式的操作数为常量表达式，则该 reflexpr 说明符所指定的类型亦满足 reflect::Constant 。

若 reflexpr 操作数指代类成员，则该 reflexpr 说明符所表示的类型亦满足 reflect::RecordMember 。

参阅

type_info | 含有某个类型的信息，由实现生成。 这是 typeid 运算符所返回的类。 (类)
<type_traits> (C++11) | 编译时类型信息


std::experimental::reflect::Object

< cpp‎ | experimental‎ | reflect
定义于头文件 <experimental/reflect> |
template< class T > concept bool Object = /* see below */; | (反射 TS)

Object 概念当且仅当 T 为元对象类型才得到满足。

示例

#include<experimental/reflect>

namespace reflect = std::experimental::reflect;

template<reflect::Object M>
struct meta_t {
    template<reflect::Object M1>
    friend constexpr operator==(meta_t, meta_t<M1>) noexcept
    {
        return reflect::reflects_same_v<M, M1>;
    }
    template<reflect::Object M1>
    friend constexpr operator!=(meta_t, meta_t<M1>) noexcept
    {
        return !reflect::reflects_same_v<M, M1>;
    }
};

template<reflect::Object M>
constexpr meta_t<M> meta{};

int main()
{
    static_assert(meta<reflexpr(int)> == meta<reflexpr(signed int)>, "");
    // meta<int>; // 错误： int 不是元对象类型
}


std::experimental::reflect::ObjectSequence

< cpp‎ | experimental‎ | reflect
定义于头文件 <experimental/reflect> |
template< class T > concept bool ObjectSequence = Object<T> && /* see below */; | (反射 TS)

ObjectSequence 概念为元对象序列类型所满足。

元对象序列类型是从生成序列的元对象操作，如 get_data_members 获得的元对象类型。元对象序列类型中的每个元素均为元对象类型。

示例

#include<type_traits>
#include<tuple>
#include<cmath>
#include<experimental/reflect>

using reflect = std::experimental::reflect;

template<reflect::Typed... Ms>
using tuple_from_seq_t = std::tuple<reflect::get_reflected_type_t<
    reflect::get_type_t<Ms>>...>;

template<reflect::Record T>
using collect_tuple = reflect::unpack_sequence_t<
    tuple_from_seq_t,
    reflect::get_data_members<T>>;

int main()
{
    static_assert(reflect::ObjectSequence<
                      reflect::get_data_members<reflexpr(std::div_t)>>, "");
    static_assert(std::is_same<collect_tuple<reflexpr(std::div_t)>,
                               std::tuple<int, int>>::value, "");
}

参阅

本节未完成
原因：模板化


std::experimental::reflect::get_source_line

< cpp‎ | experimental‎ | reflect
定义于头文件 <experimental/reflect> |
template< Object T > struct get_source_line; | (反射 TS)

提供等于 T 所反射的实体或 typedef 名的声明的预设行号的成员常量 value 。

辅助变量模板

template< class T > constexpr auto get_source_line_v = get_source_line<T>::value; | (反射 TS)

继承自 std::integral_constant

成员常量

value
[静态]
 T 所反射的实体或 typedef 名的声明的预设行号
(公开静态成员常量)

成员函数

operator std::uint_least32_t | 转换对象为 std::uint_least32_t ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | std::uint_least32_t
type | std::integral_constant < std::uint_least32_t, value>

示例

下列代码展示对象或类的源码行。

#include<experimental/reflect>
#include<iostream>

using refl = std::experimental::reflect;

float f;
struct P{};

int main()
{
    std::cout << refl::get_source_line_v<reflexpr(f)> << '\n';
    std::cout << refl::get_source_line_v<reflexpr(P)> << '\n';
}

输出：

6
7

参阅

line | 返回此对象所表示的行号 (std::source_location 的公开成员函数)
source_line (C++23) | 获取词法上与该 stacktrace_entry 所表示的求值相关的行号 (std::stacktrace_entry 的公开成员函数)


std::experimental::reseed

< cpp‎ | experimental
定义于头文件 <experimental/random> |  |
void reseed(); | (1) | (库基础 TS v2)
void reseed(std::default_random_engine::result_type value); | (2) | (库基础 TS v2)

重播种逐线程随机数引擎和 randint 所用的任何 std::uniform_int_distribution 实例。

1) 设置逐线程引擎为不可预测状态。
2) 如同用 g.seed(value) 播种逐线程引擎 g 。

参数

value - 新种子的值

提醒

对 randint 的后继调用不依赖于调用 reseed 之前的逐线程引擎所产生的值。

示例

#include <experimental/random>
#include <iostream>

auto main() -> int
{
    std::experimental::reseed();

    std::cout << "Random 2-digit decimal numbers: ";

    for (auto i = 0; i != 3; ++i)
    {
        std::cout << std::experimental::randint(10, 99) << ' ';
    }
}

可能的输出：

Random 2-digit decimal numbers: 41 60 56

参阅

randint
 生成指定范围中的随机整数
(函数模板)


std::experimental::pmr::resource_adaptor

< cpp‎ | experimental
定义于头文件 <experimental/memory_resource> |
template< class Alloc > using resource_adaptor = /*resource-adaptor-imp*/< typename std::allocator_traits <Allocator>:: template rebind_alloc<char>>; | (库基础 TS)
template< class Alloc > class /*resource-adaptor-imp*/ : public memory_resource; // 仅用于阐释 | (库基础 TS)

别名模版 resource_adaptor 将分配器类型 Allocator 与 memory_resource 接口适配。在实际适配前（用 resource-adaptor-imp 类模板）将分配器重绑定到 char 类型，故适配同一分配器的模板特化总是生成同一类型，无关乎分配器模板原先实例化所用的值类型。

resource-adaptor-imp 是类模板，成员描述如下。名称 resource-adaptor-imp 仅为阐释用途，而非强制规定。

除了符合分配器 (Allocator) 要求， Alloc 还必须额外满足下列要求：

  • std::allocator_traits <Alloc>::pointer 应当等同于 Alloc::value_type* 。
  • std::allocator_traits <Alloc>::const_pointer 应当等同于 Alloc::value_type const* 。
  • std::allocator_traits <Alloc>::void_pointer 应当等同于 void* 。
  • std::allocator_traits <Alloc>::const_const_pointer 应当等同于 void const* 。

本页面中的类型 memory_resorce 在 LFTS v1 与 v2 中代表 std::experimental::pmr::memory_resource ，但从 LFTS v3 起代表 std::pmr::memory_resource 。

resource-adaptor-imp 的成员类型

成员类型 | 定义
allocator_type | Alloc

resource-adaptor-imp 的成员函数

resource-adaptor-imp::resource-adaptor-imp

/*resource-adaptor-imp*/() = default;
 (1) (库基础 TS)
/*resource-adaptor-imp*/(const /*resource-adaptor-imp*/& other)
= default;
 (2) (库基础 TS)
/*resource-adaptor-imp*/(/*resource-adaptor-imp*/&& other)
= default;
 (3) (库基础 TS)
explicit /*resource-adaptor-imp*/(const Alloc& a2);
 (4) (库基础 TS)
explicit /*resource-adaptor-imp*/(Alloc&& a2);
 (5) (库基础 TS)
1) 默认构造函数。默认构造被包装分配器。
2) 复制构造函数。从 other 所包装的分配器复制构造被包装分配器。
3) 移动构造函数。从 other 所包装的分配器移动构造被包装分配器。
4) 以 a2 初始化被包装分配器。
5) 以 std::move(a2) 初始化被包装分配器。

参数

other | - | 复制或移动来源的另一 resource-adaptor-imp 对象
a2 | - | 复制或移动来源的另一 Alloc 对象

resource-adaptor-imp::get_allocator

allocator_type get_allocator() const; | (库基础 TS)

返回被包装分配器的副本。

resource-adaptor-imp::operator=

/*resource-adaptor-imp*/& operator=(const /*resource-adaptor-imp*/& other)
= default;
 (库基础 TS)

默认化的复制赋值运算符。从 other 的被包装分配器复制赋值被包装分配器。

resource-adaptor-imp::do_allocate

protected: virtual void* do_allocate( std::size_t bytes, std::size_t alignment); | (库基础 TS)

用被包装分配器的 allocate 成员函数分配内存。

resource-adaptor-imp::do_deallocate

protected: virtual void do_deallocate(void *p, std::size_t bytes, std::size_t alignment); | (库基础 TS)

用被包装分配器的 deallocate 成员函数解分配 p 所指向的存储。

p 必须已经用比较等于被包装分配器的分配器的 allocate 成员函数分配，而且之后必须未被解分配。

resource-adaptor-imp::do_is_equal

protected: virtual bool do_is_equal(const memory_resource& other) const noexcept; | (库基础 TS)

令 p 为 dynamic_cast<const /*resource-adaptor-imp*/*>(&other) 。若 p 为空指针值则返回 false 。否则返回用 operator== 比较 *p 和 *this 所包装的分配器的结果。


std::experimental::sample

< cpp‎ | experimental
定义于头文件 <experimental/algorithm> |  |
template< class PopulationIterator, class SampleIterator, class Distance, class URBG > SampleIterator sample( PopulationIterator first, PopulationIterator last, SampleIterator out, Distance n, URBG&& g); | (1) | (库基础 TS)
template< class PopulationIterator, class SampleIterator, class Distance > SampleIterator sample( PopulationIterator first, PopulationIterator last, SampleIterator out, Distance n); | (2) | (库基础 TS v2)

在序列 [first; last) 中选择 n 个元素，使得每个元素拥有相等的出现概率，并写入被选择元素到输出迭代器 out 。

若n 大于序列中的元素数，则选择 last-first 个元素。

仅若 PopulationIterator 满足老式向前迭代器 (LegacyForwardIterator) 的要求，算法才稳定。

1) 用随机数生成器 g 生成随机数。
2) 用逐线程引擎生成随机数。

参数

first, last | - | 指示从中抽样的范围（总体）的一对迭代器
out | - | 要写入样本到其中的输出迭代器。必须不在 [first;last) 范围中
n | - | 样本数
g | - | 用作随机源的随机数生成器
- PopulationIterator 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- SampleIterator 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- 若 PopulationIterator 不满足老式向前迭代器 (LegacyForwardIterator) ，则 SampleIterator 必须亦满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求
- PopulationIterator 的 value_type 必须可写入到 out
- Distance 必须为整数类型
- URBG 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求，而其返回类型必须可转换为 Distance

返回值

返回输出的最后样本后的 out 的副本，即样本范围的末尾。

复杂度

与 std::distance (first,last) 成线性。

注意

此函数可以实现选择抽样或蓄水池抽样。

示例

#include <iostream>
#include <random>
#include <string>
#include <iterator>
#include <experimental/algorithm>

int main()
{
    std::string in = "abcdefgh", out;
    std::experimental::sample(in.begin(), in.end(), std::back_inserter(out),
                              5, std::mt19937{std::random_device{}()});
    std::cout << "five random letters out of " << in << " : " << out << '\n';
}

可能的输出：

five random letters out of abcdefgh : cdefg

参阅

random_shuffleshuffle
(C++17 前)(C++11)
 随机重排范围中的元素
(函数模板)


std::experimental::scope_exit

< cpp‎ | experimental

定义于头文件 <experimental/scope> |
template<class EF> class scope_exit; | (库基础 TS v3)

类模板 scope_exit 是通用的作用域防护，有意使它在退出作用域时调用其退出函数。

scope_exit 非可复制构造 (CopyConstructible) 、可复制赋值 (CopyAssignable) 或可移动赋值 (MoveAssignable) ，然而若 EF 满足某些要求则它可能为可移动构造 (MoveConstructible) ，这允许包装 scope_exit 到另一对象中。

scope_exit 可为活跃，即在析构时调用其退出函数，或为不活跃，即在析构时不做任何事。在从退出函数构造后 scope_exit 为活跃。

scope_exit 能因手动或自动（由移动构造函数）在它上调用 release() 后变得不活跃。亦可由从另一不活跃的 scope_exit 初始化获得不活跃的 scope_exit 。一旦 scope_exit 不活跃，则它不能再次变得活跃。

一个 scope_exit 等效地保有一个 EF 与一个指示它是否活跃的 bool 标签。

模板形参

EF - 退出函数的类型
类型要求
-
EF 可为：
  • 可析构 (Destructible) 的函数对象 (FunctionObject) 类型
  • 到函数对象 (FunctionObject) 的左值引用
  • 到函数的左值引用
-
以无参数调用 std::remove_reference_t <EF> 的左值必须为良构。

成员函数

(构造函数)
 构造新的 scope_exit
(公开成员函数)
(析构函数)
 在退出作用域时调用退出函数，若 scope_exit 为活跃，然后销毁 scope_exit
(公开成员函数)
operator=
[被删除]
 scope_exit 不可赋值
(公开成员函数)
修改器
release
 使 scope_exit 不活跃
(公开成员函数)

推导指引

注解

构造拥有动态存储期的 scope_exit 可能导致不期待的行为。

若存储于 scope_exit 对象的 EF 引用到定义它的函数的局部变量，例如为按引用捕获该变量的 lambda ，则在该 scope_exit 的析构函数执行并调用退出函数时该变量可能已经被返回。这能导致令人诧异的行为。

示例

本节未完成
原因：暂无示例

参阅

scope_fail | 包装函数对象并在通过异常退出作用域时调用 (类模板)
scope_success | 包装函数对象并在正常退出作用域时调用 (类模板)
default_delete (C++11) | unique_ptr 的默认删除器 (类模板)


std::experimental::scope_exit 的推导指引

< cpp‎ | experimental‎ | scope exit

定义于头文件 <experimental/scope> |
template<class EF> scope_exit(EF) -> scope_exit<EF>; | (库基础 TS v3)

为 std::experimental::scope_exit 提供一个推导指引以允许从函数或函数对象类型实参推导。

（在函数到指针退化后，若它存在）复制或移动实参到构造的 scope_exit 中。

示例

本节未完成
原因：暂无示例


std::experimental::scope_exit<EF>::release

< cpp‎ | experimental‎ | scope exit

void release() noexcept; | (库基础 TS v3)

使 scope_exit 不活跃

一旦 scope_exit 不活跃，则它无法再次变得活跃，而它将不会在析构时调用其退出函数。

参数

（无）

返回值

（无）

注解

可以手动或由 scope_exit 的移动构造函数自动调用 release 。

示例

本节未完成
原因：暂无示例

参阅

(构造函数) | 构造新的 scope_exit (公开成员函数)
(析构函数) | 在退出作用域时调用退出函数，若 scope_exit 为活跃，然后销毁 scope_exit (公开成员函数)


std::experimental::scope_exit<EF>::scope_exit

< cpp‎ | experimental‎ | scope exit

template <class Fn> explicit scope_exit( Fn&& fn ) noexcept(/*see below*/); | (1) | (库基础 TS v3)
scope_exit( scope_exit&& other ) noexcept(/*see below*/); | (2) | (库基础 TS v3)
scope_exit( const scope_exit& ) = delete; | (3) | (库基础 TS v3)

从函数、函数对象或另一 scope_exit 创建 scope_exit 。

1) 以函数或函数对象初始化退出函数。构造的 scope_exit 为活跃。
若 Fn 不是左值引用类型且 std::is_nothrow_constructible_v <EF, Fn> 为 true ，则以 std::forward <Fn>(fn) ，否则以 fn 初始化存储的 EF 。
若初始化存储的 EF 抛异常，则调用 fn() 。
此重载仅若 std::is_same_v <std::remove_cvref_t<Fn>, scope_exit> 为 false 且 std::is_constructible_v <EF, Fn> 为 true 才参与重载决议。
若函数调用表达式 fn() 为谬构，则程序为谬构。
若调用 fn() 抛出异常或导致未定义行为，则行为未定义，即使未调用 fn 。
2) 移动构造函数。以 other 的存储的 EF 初始化存储的 EF 。构造的 scope_exit 为活跃当且仅当 other 在构造前活跃。
若 std::is_nothrow_move_constructible_v <EF> 为 true ，则以 std::forward <EF>(other.exitfun) ，否则以 other.exitfun 初始化存储的 EF （以 exitfun 代表）。
在成功移动构造后调用 other.release() 而 other 变为不活跃。
此重载仅若 std::is_nothrow_move_constructible_v <EF> 为 true 或 std::is_copy_constructible_v <EF> 为 true 才参与重载决议。
若有下列情况则行为未定义
  • std::is_nothrow_move_constructible_v <EF> 为 true 而 EF 不满足可移动构造 (MoveConstructible) 的要求，或
  • std::is_nothrow_move_constructible_v <EF> 为 false 而 EF 不满足可复制构造 (CopyConstructible) 的要求。
3) scope_exit 非可复制构造 (CopyConstructible) 。

参数

fn | - | 用于初始化存储的 EF 的函数或函数对象
other | - | 要移动的 scope_exit

异常

初始化存储的 EF 期间抛出的任何异常。

1)
noexcept 说明：
noexcept( std::is_nothrow_constructible_v <EF, Fn> ||
std::is_nothrow_constructible_v <EF, Fn&>)
2)
noexcept 说明：
noexcept( std::is_nothrow_move_constructible_v <EF> ||
std::is_nothrow_copy_constructible_v <EF>)

示例

本节未完成
原因：暂无示例

参阅

release
 使 scope_exit 不活跃
(公开成员函数)


std::experimental::scope_exit<EF>::~scope_exit

< cpp‎ | experimental‎ | scope exit

~scope_exit() noexcept; | (库基础 TS v3)

调用退出函数，若 scope_exit 活跃，然后销毁存储的 EF （若它为异常对象）与任何其他非静态数据成员。

参阅

release
 使 scope_exit 不活跃
(公开成员函数)


std::experimental::scope_fail

< cpp‎ | experimental

定义于头文件 <experimental/scope> |
template<class EF> class scope_fail; | (库基础 TS v3)

类模板 scope_fail 是通用的作用域防护，有意使它在经由异常退出作用域时调用其退出函数。

scope_fail 非可复制构造 (CopyConstructible) 、可复制赋值 (CopyAssignable) 或可移动赋值 (MoveAssignable) ，然而若 EF 满足某些要求则它可能为可移动构造 (MoveConstructible) ，这允许包装 scope_fail 到另一对象中。

scope_fail 可为活跃，即在析构时调用其退出函数，或为不活跃，即在析构时不做任何事。在从退出函数构造后 scope_fail 为活跃。

scope_fail 能因手动或自动（由移动构造函数）在它上调用 release() 后变得不活跃。亦可由从另一不活跃的 scope_fail 初始化获得不活跃的 scope_fail 。一旦 scope_fail 不活跃，则它不能再次变得活跃。

一个 scope_fail 等效地保有一个 EF 与一个指示它是否活跃的 bool 标签，还有一个用于检测是否在栈回溯期间调用析构函数的未捕捉异常的计数器。

模板形参

EF - 退出函数的类型
类型要求
-
EF 可为：
  • 可析构 (Destructible) 的函数对象 (FunctionObject) 类型
  • 到函数对象 (FunctionObject) 的左值引用
  • 到函数的左值引用
-
以无参数调用 std::remove_reference_t <EF> 的左值必须为良构。

成员函数

(构造函数)
 构造新的 scope_fail
(公开成员函数)
(析构函数)
 在经由异常退出作用域时调用退出函数，若 scope_fail 为活跃，然后销毁 scope_fail
(公开成员函数)
operator=
[被删除]
 scope_fail 不可赋值
(公开成员函数)
修改器
release
 使 scope_fail 不活跃
(公开成员函数)

推导指引

注解

构造拥有动态存储期的 scope_fail 可能导致不期待的行为。

从创建于另一线程的 scope_fail 构造 scope_fail 亦可能导致不期待的行为，因为可能在析构期间比较从另一线程获得的未捕捉异常计数。

示例

本节未完成
原因：暂无示例

参阅

scope_exit | 包装函数对象并在退出作用域时调用 (类模板)
scope_success | 包装函数对象并在正常退出作用域时调用 (类模板)
default_delete (C++11) | unique_ptr 的默认删除器 (类模板)


std::experimental::scope_fail 的推导指引

< cpp‎ | experimental‎ | scope fail

定义于头文件 <experimental/scope> |
template<class EF> scope_fail(EF) -> scope_fail<EF>; | (库基础 TS v3)

为 std::experimental::scope_fail 提供一个推导指引以允许从函数或函数对象类型实参推导。

（在函数到指针退化后，若它存在）复制或移动实参到构造的 scope_fail 中。

示例

本节未完成
原因：暂无示例


std::experimental::scope_fail<EF>::release

< cpp‎ | experimental‎ | scope fail

void release() noexcept; | (库基础 TS v3)

使 scope_fail 不活跃

一旦 scope_fail 不活跃，则它无法再次变得活跃，而它将不会在析构时调用其退出函数。

参数

（无）

返回值

（无）

注解

可以手动或由 scope_fail 的移动构造函数自动调用 release 。

示例

本节未完成
原因：暂无示例

参阅

(构造函数) | 构造新的 scope_fail (公开成员函数)
(析构函数) | 在经由异常退出作用域时调用退出函数，若 scope_fail 为活跃，然后销毁 scope_fail (公开成员函数)


std::experimental::scope_fail<EF>::scope_fail

< cpp‎ | experimental‎ | scope fail

template <class Fn> explicit scope_fail( Fn&& fn ) noexcept(/*see below*/); | (1) | (库基础 TS v3)
scope_fail( scope_fail&& other ) noexcept(/*see below*/); | (2) | (库基础 TS v3)
scope_fail( const scope_fail& ) = delete; | (3) | (库基础 TS v3)

从函数、函数对象或另一 scope_fail 创建 scope_fail 。

1) 以函数或函数对象初始化退出函数，并如同以 std::uncaught_exceptions() 初始化未捕捉异常计数。构造的 scope_fail 为活跃。
若 Fn 不是左值引用类型且 std::is_nothrow_constructible_v <EF, Fn> 为 true ，则以 std::forward <Fn>(fn) ，否则以 fn 初始化存储的 EF 。
若初始化存储的 EF 抛异常，则调用 fn() 。
此重载仅若 std::is_same_v <std::remove_cvref_t<Fn>, scope_fail> 为 false 且 std::is_constructible_v <EF, Fn> 为 true 才参与重载决议。
若函数调用表达式 fn() 为谬构，则程序为谬构。
若调用 fn() 抛出异常或导致未定义行为，则行为未定义，即使未调用 fn 。
2) 移动构造函数。以 other 的存储的 EF 初始化存储的 EF ，并以 other 的未捕捉异常计数初始化未捕捉异常计数。构造的 scope_fail 为活跃当且仅当 other 在构造前活跃。
若 std::is_nothrow_move_constructible_v <EF> 为 true ，则以 std::forward <EF>(other.exitfun) ，否则以 other.exitfun 初始化存储的 EF （以 exitfun 代表）。
在成功移动构造后调用 other.release() 而 other 变为不活跃。
此重载仅若 std::is_nothrow_move_constructible_v <EF> 为 true 或 std::is_copy_constructible_v <EF> 为 true 才参与重载决议。
若有下列情况则行为未定义
  • std::is_nothrow_move_constructible_v <EF> 为 true 而 EF 不满足可移动构造 (MoveConstructible) 的要求，或
  • std::is_nothrow_move_constructible_v <EF> 为 false 而 EF 不满足可复制构造 (CopyConstructible) 的要求。
3) scope_fail 非可复制构造 (CopyConstructible) 。

参数

fn | - | 用于初始化存储的 EF 的函数或函数对象
other | - | 要移动的 scope_fail

异常

初始化存储的 EF 期间抛出的任何异常。

1)
noexcept 说明：
noexcept( std::is_nothrow_constructible_v <EF, Fn> ||
std::is_nothrow_constructible_v <EF, Fn&>)
2)
noexcept 说明：
noexcept( std::is_nothrow_move_constructible_v <EF> ||
std::is_nothrow_copy_constructible_v <EF>)

示例

本节未完成
原因：暂无示例

参阅

uncaught_exceptionuncaught_exceptions (C++20 中移除)(C++17) | 检查当前是否正在进行异常处理 (函数)
release | 使 scope_fail 不活跃 (公开成员函数)


std::experimental::scope_fail<EF>::~scope_fail

< cpp‎ | experimental‎ | scope fail

~scope_fail() noexcept; | (库基础 TS v3)

调用退出函数，若 std::uncaught_exceptions() 的结果大于未捕捉异常计数（常在栈回溯时）且 scope_fail 活跃，然后销毁存储的 EF （若它为异常对象）与任何其他非静态数据成员。

注解

是否在栈回溯时调用析构函数可由比较 std::uncaught_exceptions() 的结果与 scope_fail 中的未捕捉异常计数器检测。

参阅

release
 使 scope_fail 不活跃
(公开成员函数)


std::experimental::scope_success

< cpp‎ | experimental

定义于头文件 <experimental/scope> |
template<class EF> class scope_success; | (库基础 TS v3)

类模板 scope_success 是通用的作用域防护，有意使它在正常退出作用域时调用其退出函数。

scope_success 非可复制构造 (CopyConstructible) 、可复制赋值 (CopyAssignable) 或可移动赋值 (MoveAssignable) ，然而若 EF 满足某些要求则它可能为可移动构造 (MoveConstructible) ，这允许包装 scope_success 到另一对象中。

scope_success 可为活跃，即在析构时调用其退出函数，或为不活跃，即在析构时不做任何事。在从退出函数构造后 scope_success 为活跃。

scope_success 能因手动或自动（由移动构造函数）在它上调用 release() 后变得不活跃。亦可由从另一不活跃的 scope_success 初始化获得不活跃的 scope_success 。一旦 scope_success 不活跃，则它不能再次变得活跃。

一个 scope_success 等效地保有一个 EF 与一个指示它是否活跃的 bool 标签，还有一个用于检测是否在栈回溯期间调用析构函数的未捕捉异常的计数器。

模板形参

EF - 退出函数的类型
类型要求
-
EF 可为：
  • 可析构 (Destructible) 的函数对象 (FunctionObject) 类型
  • 到函数对象 (FunctionObject) 的左值引用
  • 到函数的左值引用
-
以无参数调用 std::remove_reference_t <EF> 的左值必须为良构。

成员函数

(构造函数)
 构造新的 scope_success
(公开成员函数)
(析构函数)
 在正常退出作用域时调用退出函数，若 scope_success 为活跃，然后销毁 scope_success
(公开成员函数)
operator=
[被删除]
 scope_success 不可赋值
(公开成员函数)
修改器
release
 使 scope_success 不活跃
(公开成员函数)

推导指引

注解

构造拥有动态存储期的 scope_success 可能导致不期待的行为。

从创建于另一线程的 scope_success 构造 scope_success 亦可能导致不期待的行为，因为可能在析构期间比较从另一线程获得的未捕捉异常计数。

若存储于 scope_success 对象的 EF 引用到定义它的函数的局部变量，例如为按引用捕获该变量的 lambda ，则在该 scope_success 的析构函数执行并调用退出函数时该变量可能已经被返回。这能导致令人诧异的行为。

示例

本节未完成
原因：暂无示例

参阅

scope_exit | 包装函数对象并在退出作用域时调用 (类模板)
scope_fail | 包装函数对象并在通过异常退出作用域时调用 (类模板)
default_delete (C++11) | unique_ptr 的默认删除器 (类模板)


std::experimental::scope_success 的推导指引

< cpp‎ | experimental‎ | scope success

定义于头文件 <experimental/scope> |
template<class EF> scope_success(EF) -> scope_success<EF>; | (库基础 TS v3)

为 std::experimental::scope_success 提供一个推导指引以允许从函数或函数对象类型实参推导。

（在函数到指针退化后，若它存在）复制或移动实参到构造的 scope_success 中。

示例

本节未完成
原因：暂无示例


std::experimental::scope_success<EF>::release

< cpp‎ | experimental‎ | scope success

void release() noexcept; | (库基础 TS v3)

使 scope_success 不活跃

一旦 scope_success 不活跃，则它无法再次变得活跃，而它将不会在析构时调用其退出函数。

参数

（无）

返回值

（无）

注解

可以手动或由 scope_success 的移动构造函数自动调用 release 。

示例

本节未完成
原因：暂无示例

参阅

(构造函数) | 构造新的 scope_success (公开成员函数)
(析构函数) | 在正常退出作用域时调用退出函数，若 scope_success 为活跃，然后销毁 scope_success (公开成员函数)


std::experimental::scope_success<EF>::scope_success

< cpp‎ | experimental‎ | scope success

template <class Fn> explicit scope_success( Fn&& fn ) noexcept(/*see below*/); | (1) | (库基础 TS v3)
scope_success( scope_success&& other ) noexcept(/*see below*/); | (2) | (库基础 TS v3)
scope_success( const scope_success& ) = delete; | (3) | (库基础 TS v3)

从函数、函数对象或另一 scope_success 创建 scope_success 。

1) 以函数或函数对象初始化退出函数，并如同以 std::uncaught_exceptions() 初始化未捕捉异常计数。构造的 scope_success 为活跃。
若 Fn 不是左值引用类型且 std::is_nothrow_constructible_v <EF, Fn> 为 true ，则以 std::forward <Fn>(fn) ，否则以 fn 初始化存储的 EF 。
此重载仅若 std::is_same_v <std::remove_cvref_t<Fn>, scope_success> 为 false 且 std::is_constructible_v <EF, Fn> 为 true 才参与重载决议。
若函数调用表达式 fn() 为谬构，则程序为谬构。
若调用 fn() 导致未定义行为，则行为未定义，即使未调用 fn 。
2) 移动构造函数。以 other 的存储的 EF 初始化存储的 EF ，并以 other 的未捕捉异常计数初始化未捕捉异常计数。构造的 scope_success 为活跃当且仅当 other 在构造前活跃。
若 std::is_nothrow_move_constructible_v <EF> 为 true ，则以 std::forward <EF>(other.exitfun) ，否则以 other.exitfun 初始化存储的 EF （以 exitfun 代表）。
在成功移动构造后调用 other.release() 而 other 变为不活跃。
此重载仅若 std::is_nothrow_move_constructible_v <EF> 为 true 或 std::is_copy_constructible_v <EF> 为 true 才参与重载决议。
若有下列情况则行为未定义
  • std::is_nothrow_move_constructible_v <EF> 为 true 而 EF 不满足可移动构造 (MoveConstructible) 的要求，或
  • std::is_nothrow_move_constructible_v <EF> 为 false 而 EF 不满足可复制构造 (CopyConstructible) 的要求。
3) scope_success 非可复制构造 (CopyConstructible) 。

参数

fn | - | 用于初始化存储的 EF 的函数或函数对象
other | - | 要移动的 scope_success

异常

初始化存储的 EF 期间抛出的任何异常。

1)
noexcept 说明：
noexcept( std::is_nothrow_constructible_v <EF, Fn> ||
std::is_nothrow_constructible_v <EF, Fn&>)
2)
noexcept 说明：
noexcept( std::is_nothrow_move_constructible_v <EF> ||
std::is_nothrow_copy_constructible_v <EF>)

示例

本节未完成
原因：暂无示例

参阅

uncaught_exceptionuncaught_exceptions (C++20 中移除)(C++17) | 检查当前是否正在进行异常处理 (函数)
release | 使 scope_success 不活跃 (公开成员函数)


std::experimental::scope_success<EF>::~scope_success

< cpp‎ | experimental‎ | scope success

~scope_success() noexcept(noexcept( std::declval <EF&>()())); | (库基础 TS v3)

调用退出函数，若 std::uncaught_exceptions() 的结果小于未捕捉异常计数（常在通常退出时）且 scope_success 活跃，然后销毁存储的 EF （若它为异常对象）与任何其他非静态数据成员。

异常

抛出任何推出函数所抛的异常。

注解

是否在栈回溯时调用析构函数可由比较 std::uncaught_exceptions() 的结果与 scope_success 中的未捕捉异常计数器检测。

不同于 C++ 标准库及其他 C++ TR/TS 中的类或类模板特化，容许 scope_success 的析构函数被容许抛出异常。

参阅

release
 使 scope_success 不活跃
(公开成员函数)


std::experimental::erase_if (std::set)

< cpp‎ | experimental

定义于头文件 <experimental/set> |
template <class Key, class Compare, class Alloc, class Pred> void erase_if( std::set <Key,Compare,Alloc>& c, Pred pred); | (库基础 TS v2)

从容器擦除所有满足谓词 pred 的元素。等价于

for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}

参数

c | - | 要从中擦除的容器
pred | - | 确定该擦除哪些元素的谓词

复杂度

线性。

示例

#include <experimental/set>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& container)
{
    os << "{ ";
    for (const auto& item : container) {
        os << item << ' ';
    }
    return os << "}";
}

int main()
{
    std::set<int> data { 3, 3, 4, 5, 5, 6, 6, 7, 2, 1, 0 };

    std::cout << "Original:\n" << data << '\n';

    auto divisible_by_3 = [](auto const& x) { return (x % 3) == 0; };

    std::experimental::erase_if(data, divisible_by_3);

    std::cout << "Erase all items divisible by 3:\n" << data << '\n';
}

输出：

Original:
{ 0 1 2 3 4 5 6 7 }
Erase all items divisible by 3:
{ 1 2 4 5 7 }

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::experimental::shared_future

< cpp‎ | experimental
定义于头文件 <experimental/shared_future> |  |
template< class T > class shared_future; | (1) | (并发 TS)
template< class T > class shared_future<T&>; | (2) | (并发 TS)
template<> class shared_future<void>; | (3) | (并发 TS)

类模板 std::experimental::shared_future 以下列操作扩展 std::shared_future ：

  • 从 future<shared_future<T>> 构造的解包装构造函数；
  • 查询共享状态是否就绪的成员函数 is_ready ；以及
  • 附着持续到 future 的成员函数 then 。

std::experimental::shared_future 与 std::shared_future 间无交互。

成员函数

(构造函数) | 构造 shared_future (公开成员函数)
is_ready | 检查共享状态是否就绪 (公开成员函数)
then | 附着持续到 shared_future (公开成员函数)
operator= | 赋值内容 (公开成员函数)

等同于 std::shared_future 的成员

成员函数

(析构函数)
 destructs the future object
(std::shared_future<T> 的公开成员函数)
获取结果
get
 返回结果
(std::shared_future<T> 的公开成员函数)
状态
valid
 检查 future 是否拥有共享状态
(std::shared_future<T> 的公开成员函数)
wait
 等待结果变得可用
(std::shared_future<T> 的公开成员函数)
wait_for
 等待结果，如果在指定的超时间隔后仍然无法得到结果，则返回。
(std::shared_future<T> 的公开成员函数)
wait_until
 等待结果，如果在已经到达指定的时间点时仍然无法得到结果，则返回。
(std::shared_future<T> 的公开成员函数)

示例

本节未完成
原因：暂无示例

参阅

future
(并发 TS)
 以持续和其他特性增强的 std::future 版本
(类模板)


std::experimental::shared_future<T>::is_ready

< cpp‎ | experimental‎ | shared future

bool is_ready() const;

检查关联的共享状态是否就绪。

若 valid() 为 false 则行为未定义。

参数

（无）

返回值

若关联的共享状态就绪则为 true ，否则为 false 。

示例

本节未完成
原因：暂无示例

参阅

valid
 检查 future 是否拥有共享状态
(std::shared_future<T> 的公开成员函数)


std::experimental::shared_future<T>::operator=

< cpp‎ | experimental‎ | shared future
std::experimental::shared_future<T>& operator=( const std::experimental::shared_future<T>& other ); | (1)
std::experimental::shared_future<T>& operator=( std::experimental::shared_future<T>&& other ) noexcept; | (2)

赋值另一 std::experimental::shared_future 对象的内容。

1) 释放任何共享状态并赋值 other 的内容给 *this 。赋值后， this->valid() == other.valid() 。
2) 释放任何共享状态并移动赋值 other 的内容给 *this 。赋值后， other.valid() == false 而 this->valid() 将生成与 other.valid() 在赋值前相同的值。

参数

other - 赋值来源的 std::experimental::shared_future

返回值

*this


std::experimental::shared_future<T>::shared_future

< cpp‎ | experimental‎ | shared future

shared_future() noexcept; | (1)
shared_future(std::experimental::shared_future<T>&& f) noexcept; | (2)
shared_future(const std::experimental::shared_future<T>& f); | (3)
shared_future(std::experimental::future<std::experimental::shared_future<T>> && other) noexcept; | (4)
shared_future(std::experimental::future<T>&& f) noexcept; | (5)
1) 默认构造函数。构造不指代共享状态的空 shared_future 对象。
2) 构造 shared_future ，转移 f 所保有的共享状态，若存在。构造后 f.valid() 为 false 。
3) 构造 shared_future ，与 f 指代同一共享状态，若共享状态存在。
4) 从 other 所指代的共享状态构造 shared_future 对象。结果 shared_future 的对象在下列之一发生时变为就绪：
  • other 与 other.get() 均就绪。存储来自 other.get() 的值或异常到与结果 shared_future 状态关联的共享状态中。
  • other 就绪，但 other.get() 非法。存储以 std::future_errc::broken_promise 为错误条件的 std::future_error 类型异常到与结果 shared_future 对象关联的共享状态中。
此构造函数返回后， valid() == true 而 other.valid() == false 。
5) 构造 shared_future 对象，转移 f 所保有的共享状态，若存在。构造后 f.valid() 为 false 。

参数

f | - | 用以初始化的另一 future 对象
other | - | 要解包装的 std::experimental::future 对象

示例

本节未完成
原因：暂无示例

参阅

(构造函数)
 构造 future 对象
(std::shared_future<T> 的公开成员函数)


std::experimental::shared_future<T>::then

< cpp‎ | experimental‎ | shared future

template < class F >
future</* see below */> then(F&& func) const;

附着持续 func 到 *this 。若 *this 无关联共享状态（即 valid() == false ）则行为未定义。

创建与要返回的 future 对象关联的共享状态，和如同用 DECAY_COPY( std::forward <F>(func)) 构造，在调用 then 的线程中求值的 func 的副本 fd ，其中 DECAY_COPY 定义为

template <class T>
std::decay_t<T> DECAY_COPY(T&& v) {
    return std::forward<T>(v);
}

当前与 *this 关联的共享状态就绪时，在未指定的执行线程上调用持续 INVOKE(std::move(fd), *this) ，其中 INVOKE 是 可调用 (Callable) 中定义的操作。若该表达式非法，则行为未定义。

将从持续返回的任何值存储为返回的 future 对象的共享状态中的结果。将任何从持续的执行传播的异常存储为返回的 future 对象的共享状态中的异常结果。

令 U 为持续的返回类型（即 std::result_of_t < std::decay_t <F>(const std::experimental::shared_future<T> &)> ）。若 U 为对于某类型 T2 的 std::experimental::future<T2> ，则 then 的返回类型为 std::experimental::future<T2> ，否则它为 std::experimental::future<U> 。这被称为隐式解包装。

若发生隐式解包装且持续返回非法的 future ，则用以 std::future_errc::broken_promise 为错误条件的 std::future_error 类型异常令共享状态就绪。

此函数返回后， valid() 为 true 。

参数

func - 要附着的持续。

返回值

与此对象所创建的共享状态关联的 std::experimental::future 对象。对于返回的对象 valid() == true 。

示例

本节未完成
原因：暂无示例


std::experimental::shuffle

< cpp‎ | experimental
定义于头文件 <experimental/algorithm> |
template< class RandomIt> void shuffle( RandomIt first, RandomIt last); | (库基础 TS v2)

重排序给定范围 [first, last) 中的元素，使得这些元素的每个可能排列拥有相等的出现概率，以逐线程引擎为随机数生成器。

参数

first, last - 要打乱的元素范围
-
RandomIt 必须满足值可交换 (ValueSwappable) 和 老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。

返回值

（无）

复杂度

与 first 和 last 间的距离成线性。

示例

本节未完成
原因：暂无示例

参阅

random_shuffleshuffle
(C++17 前)(C++11)
 随机重排范围中的元素
(函数模板)


数据并行向量库

< cpp‎ | experimental
定义于头文件 <experimental/simd>

主类

simd (并行 TS v2) | 数据并行向量类型 (类模板)
simd_mask (并行 TS v2) | 元素类型为 bool 的数据并行类型 (类模板)

ABI 标签

定义于命名空间 std::experimental::simd_abi
scalar (并行 TS v2) | 存储单个元素的标签类型 (typedef)
fixed_size (并行 TS v2) | 存储指定数量元素的标签类型 (别名模板)
compatible (并行 TS v2) | 确保 ABI 兼容性的标签类型 (别名模板)
native (并行 TS v2) | 最有效率的标签类型 (别名模板)
max_fixed_size (并行 TS v2) | 保证支持的固定最大元素数 (常量)
deducededuce_t (并行 TS v2) | 获得给定的元素类型及元素数的 ABI 类型 (类模板)

对齐标签

element_aligned_tag element_aligned (并行 TS v2) | 指示元素对齐的标签类型 (类)
vector_aligned_tag vector_aligned (并行 TS v2) | 指示向量类型对齐的标签类型 (类)
overaligned_tag overaligned (并行 TS v2) | 指示指定对齐的标签类型 (类模板)

where_expression

const_where_expression (并行 TS v2) | 以非修改操作选择的元素 (类模板)
where_expression (并行 TS v2) | 以修改操作选择的元素 (类模板)
where (并行 TS v2) | 产生 const_where_expression 和 where_expression (函数模板)

转型

simd_cast static_simd_cast (并行 TS v2) | 逐元素 static_cast (函数模板)
to_fixed_size to_compatible to_native (并行 TS v2) | 逐元素 ABI 转型 (函数模板)
split (并行 TS v2) | 分割单个 simd 对象为多个 (函数模板)
concat (并行 TS v2) | 连接多个 simd 对象为单个 (函数模板)

算法

min (并行 TS v2) | 逐元素 min 操作 (函数模板)
max (并行 TS v2) | 逐元素 max 操作 (函数模板)
minmax (并行 TS v2) | 逐元素 minmax 操作 (函数模板)
clamp (并行 TS v2) | 逐元素 clamp 操作 (函数模板)

规约

reduce (并行 TS v2) | 规约向量为单个元素 (函数模板)
hmin (并行 TS v2) | 返回最小元素 (函数模板)
hmax (并行 TS v2) | 返回最大元素 (函数模板)

掩码规约

all_of any_of none_of some_of (并行 TS v2) | true 值数上的谓词 (函数模板)
popcount (并行 TS v2) | 返回 true 值数 (函数模板)
find_first_set find_last_set (并行 TS v2) | 返回首个或最末 true 值的位置 (函数模板)

特性

is_simd is_simd_mask (并行 TS v2) | 检查类型是否为 simd 或 simd_mask 类型 (类模板)
is_abi_tag (并行 TS v2) | 检查类型是否为 ABI 标签类型 (类模板)
is_simd_flag_type (并行 TS v2) | 检查类型是否为 simd 标志类型 (类模板)
simd_size (并行 TS v2) | 获得给定的元素类型及 ABI 的元素数 (类模板)
memory_alignment (并行 TS v2) | 获得 vector_aligned 的适当对齐 (类模板)
rebind_simd resize_simd (并行 TS v2) | 更改 simd 或 simd_mask 的元素数或元素类型 (类模板)

数学函数

示例


std::experimental::simd_cast, std::experimental::static_simd_cast

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd>
template < class T, class Abi >

fixed_size_simd<T, simd_size_v<T, Abi>>

to_fixed_size( const simd<T, Abi>& v ) noexcept;
 (1) (并行 TS v2)
template < class T, class Abi >

fixed_size_simd_mask<T, simd_size_v<T, Abi>>

to_fixed_size( const simd_mask<T, Abi>& v ) noexcept;
 (2) (并行 TS v2)
template < class T, std::size_t N >

native_simd<T>

to_native( const fixed_size_simd<T, N>& v ) noexcept;
 (3) (并行 TS v2)
template < class T, std::size_t N >

native_simd_mask<T>

to_native( const fixed_size_simd_mask<T, N>>& v ) noexcept;
 (4) (并行 TS v2)
template < class T, std::size_t N >

simd<T>

to_compatible( const fixed_size_simd<T, N>& v ) noexcept;
 (5) (并行 TS v2)
template < class T, std::size_t N >

simd_mask<T>

to_compatible( const fixed_size_simd_mask<T, N>& v ) noexcept;
 (6) (并行 TS v2)

返回有相同元素但有不同 ABI 的 simd 或 simd_mask 对象。

3-6) 这些函数仅若 N 与返回类型的大小相同才参与重载决议。

参数

v - 输入的 simd 或 simd_mask 对象

返回值

拥有指定 ABI 的 simd 或 simd_mask 对象。

示例


std::experimental::clamp

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |
template < class T, class Abi > simd<T, Abi> clamp( const simd<T, Abi>& v, const simd<T, Abi>& lo, const simd<T, Abi>& hi ); | (并行 TS v2)

参数

v | - | 要夹住的元素
lo, hi | - | 夹住 v 的边界

返回值

对所有 i ∈ [0, size()) 逐元素应用 std::clamp(v[i], lo[i], hi[i]) 的结果。

示例

参阅


std::experimental::simd_abi::compatible

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |
template < class T > using compatible = /*implementation-defined*/; | (并行 TS v2)

compatible<T> 是 ABI 标签的实现定义别名。

注意

意图是用 ABI 标签产生对于元素类型 T 最高效的数据并行执行，并确保目标架构上的翻译单元间的 ABI 兼容性。

参阅

scalar (并行 TS v2) | 存储单个元素的标签类型 (typedef)
fixed_size (并行 TS v2) | 存储指定数量元素的标签类型 (别名模板)
native (并行 TS v2) | 最有效率的标签类型 (别名模板)
deducededuce_t (并行 TS v2) | 获得给定的元素类型及元素数的 ABI 类型 (类模板)


std::experimental::concat

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd>
template < class T, class... Abis >

simd<T, simd_abi::deduce_t<T, (simd_size_v<T, Abis> + ...)>>

concat( const simd<T, Abis>&... vs );
 (1)
template <class T, class... Abis>

simd_mask<T, simd_abi::deduce_t<T, (simd_size_v<T, Abis> + ...)>>

concat( const simd_mask<T, Abis>&... vs );
 (2)

连接输入的 simd 或 simd_mask 对象。

参数

vs - 输入的 simd 或 simd_mask 参数包

返回值

连接结果，单个 simd 或 simd_mask 对象。

示例


std::experimental::const_where_expression

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |
template < class M, class V > class const_where_expression; | (并行 TS v2)

类模板 const_where_expression 抽象给定的算术或数据并行类型 const 对象的被选择元素的概念。被选择元素表示对于所有 i ∈ {j ∈ ℕ | j < M::size() ⋀ mask[j]} 的 data[i] 。

模板形参

M | - | 掩码类型
V | - | 要应用 M 到其上的值类型

(M, V) 的合法组合是： (simd_mask<T, Abi>, const simd<T, Abi>) 、 (simd_mask<T, Abi>, const simd_mask<T, Abi>) 、 (bool, const T) 。

成员函数

operator- | 取选择元素的相反数 (公开成员函数)
copy_to | 存储选择的元素到地址 (公开成员函数)

示例


std::experimental::simd_abi::deduce

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd>
template < class T, std::size_t N, class ...Abis >
struct deduce;
 (并行 TS v2)

类型 deduce<T, N, Abis...>::type 当且仅当符合下列条件才存在：

  • T 是可向量化的类型，且
  • simd_abi::fixed_size<N> 得到支持，且
  • Abis... 中的每个元素均为 ABI 标签

当 deduce<T, N, Abis...>::type 存在时以 DA 指代它，则

  • simd_size_v<T, DA> == N
  • simd<T, DA> 可默认构造，即它受支持
  • 若 N==1 则 DA 为 simd_abi::scalar ，否则它是实现定义的

成员类型

名字 | 定义
type | 适合给定元素类型 T 和大小 N 的 ABI 标签类型

辅助类型

template < class T, std::size_t N, class ...Abis >
using deduce_t = typename deduce<T, N, Abis...>::type;
 (并行 TS v2)

注解

simd_abi::deduce 对 SFINAE 友好。

通过此设施推导的 ABI 标签是实现质量特性。简单的实现可以简单地返回 fixed_size<N> 。优化的实现可以对大多数输入返回实现定义的扩展 ABI 标签。从而若你需要给定元素数的 ABI 标签，就使用 fixed_size ，否则更应该用 deduce_t 。

示例

本节未完成
原因：暂无示例

参阅

scalar (并行 TS v2) | 存储单个元素的标签类型 (typedef)
fixed_size (并行 TS v2) | 存储指定数量元素的标签类型 (别名模板)
compatible (并行 TS v2) | 确保 ABI 兼容性的标签类型 (别名模板)
native (并行 TS v2) | 最有效率的标签类型 (别名模板)


std::experimental::element_aligned_tag, std::experimental::element_aligned

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd>
struct element_aligned_tag {};
inline constexpr element_aligned_tag element_aligned{};
 (并行 TS v2)

此标签类型指示 copy_from 和 copy_to 的缓冲器对齐到其元素的对齐。

参阅


std::experimental::simd_abi::fixed_size

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |
template < int N > struct fixed_size {}; | (并行 TS v2)

simd_abi::fixed_size<N> 标签类型确保数据并行类型存储并操纵 N 个元素（即 simd<T, simd_abi::fixed_size<N>>::size() 返回 N ）。实现应当支持至少全部 N ∈ [1 … 32] 。另外，对于每个受支持的 simd<T, Abi> ，其中 Abi 是实现定义的 ABI 标签，应当支持 N = simd<T, Abi>::size() 。

注意

实现可以选择对使用相同 simd_abi::fixed_size<N> 标签的 simd 和 simd_mask 实例化放弃不同翻译单元间的 ABI 兼容性。否则， simd<T, Abi> 的效率可能优于 simd<T, fixed_size<simd_size_v<T, Abi>>> （其中 Abi 不是 simd_abi::fixed_size 的实例）。

参阅

max_fixed_size (并行 TS v2) | 保证支持的固定最大元素数 (常量)
scalar (并行 TS v2) | 存储单个元素的标签类型 (typedef)
compatible (并行 TS v2) | 确保 ABI 兼容性的标签类型 (别名模板)
native (并行 TS v2) | 最有效率的标签类型 (别名模板)
deducededuce_t (并行 TS v2) | 获得给定的元素类型及元素数的 ABI 类型 (类模板)


std::experimental::is_abi_tag

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |
template< class T > struct is_abi_tag; | (并行 TS v2)

若 T 是 simd_abi 命名空间中的 ABI 标签类型，则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_abi_tag_v = is_abi_tag<T>::value; | (并行 TS v2)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为 ABI 标签类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <experimental/simd>
#include <iostreams>

int main()
{
    namespace stdx = std::experimental;
    std::cout << stdx::is_abi_tag_v<stdx::simd_abi::scalar> << '\n';
    std::cout << stdx::is_abi_tag_v<int> << '\n';
}

输出：

true
false

参阅

is_simd_flag_type
(并行 TS v2)
 检查类型是否为 simd 标志类型
(类模板)


std::experimental::is_simd, std::experimental::is_simd_mask

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |  |
template< class T > struct is_simd; | (1) | (并行 TS v2)
template< class T > struct is_simd_mask; | (2) | (并行 TS v2)
1) 若 T 为 simd 类模板的特化，则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。
2) 若 T 是 simd_mask 类模板的特化，则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_simd_v = is_simd<T>::value; | (并行 TS v2)
template< class T > inline constexpr bool is_simd_mask_v = is_simd_mask<T>::value; | (并行 TS v2)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为 simd/simd_mask 类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <experimental/simd>
#include <iostream>

int main()
{
    namespace stdx = std::experimental;
    std::cout
    << std::boolalpha
    << stdx::is_simd_v<stdx::simd<float>> << '\n';
    << stdx::is_simd_v<int> << '\n';
    << stdx::is_simd_mask_v<stdx::simd_mask<float>> << '\n';
    << stdx::is_simd_mask_v<int> << '\n';
}

输出：

true
false
true
false

参阅

is_simd_mask
(并行 TS v2)
 检查类型是否为 simd_mask 类型
(类模板)


std::experimental::is_simd_flag_type

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |
template< class T > struct is_simd_flag_type; | (并行 TS v2)

若 T 为 simd 或 simd_mask 的 copy_from 、 copy_to 或对应的加载构造函数的第二参数的合法类型，则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_simd_flag_type_v = is_simd_flag_type<T>::value; | (并行 TS v2)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为加载/存储标志类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <experimental/simd>
#include <iostreams>

int main()
{
    namespace stdx = std::experimental;
    std::cout << stdx::is_simd_flag_type_v<stdx::element_aligned_tag> << '\n';
    std::cout << stdx::is_simd_flag_type_v<int> << '\n';
}

输出：

true
false

参阅

is_abi_tag
(并行 TS v2)
 检查类型是否为 ABI 标签类型
(类模板)


std::experimental::max

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |
template < class T, class Abi > simd<T, Abi> max( const simd<T, Abi>& a, const simd<T, Abi>& b ) noexcept; | (并行 TS v2)

参数

a | - | 求 max 的第一元素向量
b | - | 求 max 的第二元素向量

返回值

对所有 i ∈ [0, size()) 逐元素应用二元 std::max (a[i], b[i]) 的结果。

示例

参阅


std::experimental::simd_abi::max_fixed_size

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |
template < class T > inline constexpr int max_fixed_size = /*implementation-defined*/; | (并行 TS v2)

max_fixed_size<T> 的值声明实现支持 N <= max_fixed_size<T> 的 simd<T, fixed_size<N>> 实例。

注意

实现是否支持 N > max_fixed_size<T> 的 simd<T, fixed_size<N>> 是未指定的。 max_fixed_size<T> 的值可能依赖于编译器标志，并且可能在不同编译器版本间更改。


std::experimental::min

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |
template < class T, class Abi > simd<T, Abi> min( const simd<T, Abi>& a, const simd<T, Abi>& b ) noexcept; | (并行 TS v2)

参数

a | - | 求 min 的第一元素向量
b | - | 求 min 的第二元素向量

返回值

对所有 i ∈ [0, size()) 逐元素应用二元 std::min (a[i], b[i]) 的结果。

示例

参阅


std::experimental::minmax

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd>
template < class T, class Abi >

std::pair <simd<T, Abi>, simd<T, Abi>>

minmax( const simd<T, Abi>& a, const simd<T, Abi>& b ) noexcept;
 (并行 TS v2)

一并返回逐元素最小结果和逐元素最大结果。

返回值

a | - | 求 minmax 的第一元素向量
b | - | 求 minmax 的第二元素向量

返回值

对象 r ，其中 r.first 的第 i 元素为 std::min (a[i], b[i]) ，而 r.second 的第 i 元素为 std::max (a[i], b[i]) 。

示例

参阅


std::experimental::simd_abi::native

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |
template < class T > using native = /*implementation-defined*/; | (并行 TS v2)

native<T> 是 ABI 标签的实现定义别名。这是用于高效显式向量化的初等标签。

注意

意图是用该 ABI 标签产生对于元素类型 T 最高效的，在当前目标系统上受支持的数据并行执行。对于无 ISA 扩展的目标架构， native<T> 和 compatible<T> 别名很可能相同。对于有 ISA 扩展的结构，编译器标志可能影响 native<T> 别名，而 compatible<T> 会不依赖这种标志而保持相同。

参阅

scalar (并行 TS v2) | 存储单个元素的标签类型 (typedef)
fixed_size (并行 TS v2) | 存储指定数量元素的标签类型 (别名模板)
compatible (并行 TS v2) | 确保 ABI 兼容性的标签类型 (别名模板)
deducededuce_t (并行 TS v2) | 获得给定的元素类型及元素数的 ABI 类型 (类模板)


std::experimental::overaligned_tag, std::experimental::overaligned

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd>
template < std::size_t N >

struct overaligned_tag {};

template < std::size_t N >

inline constexpr overaligned_tag<N> overaligned{};
 (并行 TS v2)

此标签类型指示 copy_from 和 copy_to 的缓冲区对齐到 N 。

参阅


std::experimental::rebind_simd, std::experimental::resize_simd

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |  |
template< class T, class V > struct rebind_simd; | (1) | (并行 TS v2)
template< int N, class V > struct resize_simd; | (2) | (并行 TS v2)

创建拥有不同元素类型或大小的 simd 或 simd_mask 类型。新类型可能使用异于 V::abi_type 的 ABI 标签类型。

1) 更改元素类型为 T 并保持大小不变。
2) 更改大小为 N 并保持元素类型不变。

模板形参

T | - | 新元素类型； bool 以外的算术类型
N | - | 新的元素数
V | - | simd 或 simd_mask 类型

成员类型

名称 | 定义
type | 拥有不同元素类型 (1) 或大小 (2) 的 simd 或 simd_mask 类型

辅助类型

template< class T, class V > using rebind_simd_t = typename rebind_simd<T, V>::type; | (并行 TS v2)
template< int N, class V > using resize_simd_t = typename resize_simd<N, V>::type; | (并行 TS v2)

示例

#include <experimental/simd>
#include <iostream>

namespace stdx = std::experimental;
using floatv = stdx::native_simd<float>;

// 内部使用双精度
floatv dp(floatv x)
{
    using doublev = stdx::rebind_simd_t<double, floatv>;
    return stdx::static_simd_cast<floatv>(stdx::simd_cast<doublev>(x) - 1.234);
}

template <class T>
stdx::resize_simd_t<T::size() / 2, T> partial_reduction(T x)
{
    auto [lo, hi] = stdx::split<stdx::resize_simd_t<T::size() / 2, T>>(x);
    return lo + hi;
}

int main()
{
    floatv x([](auto i) { return 1.234f + std::numeric_limits<float>::epsilon() * i; });
    x = dp(x);
    const auto y = partial_reduction(x);
    for (unsigned i = 0; i < y.size(); ++i)
        std::cout << y[i] << ' ';
    std::cout << '\n';
}

参阅

deducededuce_t
(并行 TS v2)
 获得给定的元素类型及元素数的 ABI 类型
(类模板)


std::experimental::simd_abi::scalar

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |
using scalar = /*unspecified*/; | (并行 TS v2)

带 scalar ABI 标签的数据并行类型等价于单个元素类型。然而它支持完整的 simd 及 simd_mask 接口，从而简化泛型代码的开发。

注意

scalar 不是 fixed_size<1> 的别名。

参阅

fixed_size (并行 TS v2) | 存储指定数量元素的标签类型 (别名模板)
compatible (并行 TS v2) | 确保 ABI 兼容性的标签类型 (别名模板)
native (并行 TS v2) | 最有效率的标签类型 (别名模板)
deducededuce_t (并行 TS v2) | 获得给定的元素类型及元素数的 ABI 类型 (类模板)


std::experimental::simd

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd>
template< class T, class Abi = simd_abi::compatible<T> >
class simd;
 (并行 TS v2)

类模板 simd 是数据并行类型。给定的 simd 实例化的宽度是常量表达式，由模板形参确定。

ABI 标签是 simd_abi 命名空间中的类型，指示数据并行类型对象的大小和二进制表示。

模板形参

T | - | 元素类型
Abi | - | 用于确定元素数和存储的标签类型

辅助别名模版

template< class T, int N >
using fixed_size_simd = std::experimental::simd<T, std::experimental::simd_abi::fixed_size<N>>;
template< class T, int N >
using native_simd = std::experimental::simd<T, std::experimental::simd_abi::native>;

成员类型

成员类型 | 定义
value_type | T
reference | 实现定义
mask_type | simd_mask<T, Abi>
abi_type | Abi

成员函数

(构造函数) | 构造 simd 对象 (公开成员函数)
copy_from | 从地址加载 (公开成员函数)
copy_to | 存储到地址 (公开成员函数)
operator[] | 访问指定的元素 (公开成员函数)
operator++ operator-- | 逐元素自增与自减 (公开成员函数)
operator! operator~ operator+ operator- | 逐元素一元运算符 (公开成员函数)
size [静态] | 返回元素数 (公开静态成员函数)

非成员函数

operator+ operator- operator* operator/ operator% operator& operator| operator^ operator<< operator>> operator<< operator>> | 逐元素二元运算符 (函数)
operator+= operator-= operator*= operator/= operator%= operator&= operator|= operator^= operator<<= operator>>= operator<<= operator>>= | 逐元素复合赋值运算符 (函数)
operator== operator!= operator>= operator<= operator> operator< | 逐元素关系运算符 (函数)

示例


std::experimental::simd_cast, std::experimental::static_simd_cast

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |  |
template < class V, class T, class Abi > /*see below*/ simd_cast( const simd<T, Abi>& v ); | (1) | (并行 TS v2)
template < class V, class T, class Abi > /*see below*/ static_simd_cast( const simd<T, Abi>& v ); | (2) | (并行 TS v2)

转型 simd 对象到另一 simd 对象。若 V 为 T ，则返回 simd<T, Abi> ；否则，若 V 为标量类型，则返回 simd<V, simd_abi::fixed_size<simd<T, Abi>::size()>> 。否则， V 必须是 simd 类型，而函数返回 V 。

1) 此函数不参与重载决议，除非
  • 输入元素的每个可能值都能以输出元素表示
  • is_simd_v<V> 为 false 或 V::size() 为 simd<T, Abi>::size()
2) 此函数仅若 is_simd_v<V> 或 V::size() 为 simd<T, Abi>::size() 才参与重载决议。

参数

v - 输入的 simd 对象

返回值

第 i 元素初始化为 static_cast<To>(v[i]) 的 simd 对象，其中 To 是指定的输出元素类型。

示例


std::experimental::simd_mask

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd>
template< class T, class Abi = simd_abi::compatible<T> >
class simd_mask;
 (并行 TS v2)

类模板 simd_mask 是元素类型为 bool 的数据并行类型。给定的 simd_mask 实例化的宽度是常量表达式，由模板形参确定。具体来说， simd_mask<T, Abi>::size() 始终为 simd<T, Abi>::size() 。

模板形参

T | - | 应用 simd_mask 的元素类型
Abi | - | 应用 simd_mask 的 ABI 类型

辅助别名模版

模板 | 定义
template <class T, int N> using fixed_size_simd_mask | simd_mask<T, simd_abi::fixed_size<N>>
template <class T> using native_simd_mask | simd_mask<T, simd_abi::native>

成员类型

成员类型 | 定义
value_type | bool
reference | 实现定义
simd_type | simd<T, Abi>
abi_type | Abi

成员函数

(构造函数) | 构造 simd_mask 对象 (公开成员函数)
copy_from | 从地址加载 (公开成员函数)
copy_to | 存储到地址 (公开成员函数)
operator[] | 访问指定的元素 (公开成员函数)
operator! | 取反每个元素 (公开成员函数)
size [静态] | 返回元素数 (公开静态成员函数)

非成员函数

operator&& operator|| | 逐元素逻辑运算符 (函数)
operator& operator| operator^ | 逐元素逐位运算符 (函数)
operator&= operator|= operator^= | 逐元素复合赋值运算符 (函数)
operator== operator!= | 逐元素关系运算符 (函数)

示例


std::experimental::split

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd>
template < std::size_t... Sizes, class T, class Abi >

std::tuple <simd<T, simd_abi::deduce_t<T, Sizes>>...>

split( const simd<T, Abi>& v );
 (1) (并行 TS v2)
template < std::size_t... Sizes, class T, class Abi >

std::tuple <simd_mask<T, simd_abi::deduce_t<T, Sizes>>...>

split( const simd_mask<T, Abi>& v );
 (2) (并行 TS v2)
template < class V, class Abi >

std::array <V, simd_size_v<typename V::value_type, Abi> / V::size()>

split( const simd<typename V::value_type, Abi>& v );
 (3) (并行 TS v2)
template < class V, class Abi >

std::array <V, simd_size_v<typename V::value_type, Abi> / V::size()>

split( const simd_mask<typename V::value_type, Abi>& v );
 (4) (并行 TS v2)

分割输入的 simd 或 simd_mask 对象到多个 simd 或 simd_mask 对象中。

1-2) 分割输入对象到潜在地类型不同的对象（例如拥有不同大小的类型）中。这些函数仅若 Sizes... 求和为 v.size() 才参与重载决议。
3-4) 分割输入对象到对象的 array 中，这些函数不参与重载决议，除非
  • 对于为 simd 或 simd_mask 的 v ， array 元素必须分别拥有 simd 或 simd_mask 类型；
  • simd_size_v<typename V::value_type, Abi> 是 V::size() 的整数倍。

参数

v - 输入的 simd 或 simd_mask 对象

返回值

1-2) 含有分割的 simd 或 simd_mask 对象的 tuple 。
3-4) 含有分割的 simd 或 simd_mask 对象的 array 。

示例


std::experimental::vector_aligned_tag, std::experimental::vector_aligned

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd>
struct vector_aligned_tag {};
inline constexpr vector_aligned_tag vector_aligned{};
 (并行 TS v2)

此标签类型指示 copy_from 和 copy_to 的缓冲区对齐到 memory_alignment_v<T, U> ，其中赋值操作在 simd/simd_mask 类型 T 上操作，而缓冲区的元素类型为 U 。

注意

此标签类型允许实现按向量对齐的加载和存储。

参阅


std::experimental::where

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |  |
template < class T, class Abi > where_expression<simd_mask<T, Abi>, simd<T, Abi>> where( const typename simd<T, Abi>::mask_type& mask, simd<T, Abi>& value) noexcept; | (1) | (并行 TS v2)
template < class T, class Abi > const_where_expression<simd_mask<T, Abi>, const simd<T, Abi>> where( const typename simd<T, Abi>::mask_type& mask, const simd<T, Abi>& value) noexcept; | (2) | (并行 TS v2)
template < class T, class Abi > where_expression<simd_mask<T, Abi>, simd_mask<T, Abi>> where( const nodeduce_t<simd_mask<T, Abi>>& mask, simd_mask<T, Abi>& value) noexcept; | (3) | (并行 TS v2)
template < class T, class Abi > const_where_expression<simd_mask<T, Abi>, const simd_mask<T, Abi>> where( const nodeduce_t<simd_mask<T, Abi>>& mask, const simd_mask<T, Abi>& value) noexcept; | (4) | (并行 TS v2)
template < class T > where_expression<bool, T> where( /*see below*/ mask, T& value ) noexcept; | (5) | (并行 TS v2)
template < class T > const_where_expression<bool, const T> where( /*see below*/ mask, const T& value ) noexcept; | (6) | (并行 TS v2)

构造新的 const_where_expression 或 where_expression 。

1-6) 从给定的 mask 和 value 参数构造 where_expression 。

参数

1-4)
mask | - | simd_mask 对象
value | - | 到应用掩码于其上的对象的引用
5-6)
mask | - | bool 类型掩码
value | - | 到应用掩码于其上的标量的引用

返回值

构造的 const_where_expression 或 where_expression 。

注意

5-6) 使用掩码的实现定义类型，以之禁用从其他类型到 bool 的隐式转换。

示例


std::experimental::where_expression

< cpp‎ | experimental‎ | simd
定义于头文件 <experimental/simd> |
template < class M, class V > class where_expression; | (并行 TS v2)

类模板 where_expression 抽象给定的算术或数据并行类型非 const 对象的被选择元素的概念。被选择元素表示对于所有 i ∈ {j ∈ ℕ0 | j < M::size() ⋀ mask[j]} 的 data[i] 。

模板形参

M | - | 掩码类型
V | - | 应用 M 到其上的值类型

(M, V) 的合法组合是： (simd_mask<T, Abi>, simd<T, Abi>) 、 (simd_mask<T, Abi>, simd_mask<T, Abi>) 、 (bool, T) 。

成员函数

operator= | 赋值被选择位置 (公开成员函数)
operator+= operator-= operator*= operator/= operator%= operator&= operator|= operator^= operator<<= operator>>= | 复合赋值运算符 (公开成员函数)
operator++ operator-- | 自增和自减运算符 (公开成员函数)
copy_from | 从地址加载到被选择位置 (公开成员函数)

示例


std::experimental::source_location

< cpp‎ | experimental
定义于头文件 <experimental/source_location> |
struct source_location; | (库基础 TS v2)

source_location 类表示关于源码的某些信息，例如文件名、行号和函数名。之前，欲获得关于调用点的此信息（为了记录、测试或调试的目的）的函数必须用宏将如 __LINE__ 和 __FILE__ 的预定义宏展开于调用方的环境。 source_location 类提供一个更好的替用品。

成员函数

创建
(构造函数)
 创建拥有实现定义值的新 source_location
(公开成员函数)
current
[静态]
 创建新的 source_location
(公开静态成员函数)
其他特殊成员函数
(析构函数)
(隐式声明)
 析构 source_location
(公开成员函数)
operator=
(隐式声明)
 隐式声明的复制/移动赋值运算符
(公开成员函数)
域访问
line
 返回此对象所表示的行号
(公开成员函数)
column
 返回此对象所表示的列号
(公开成员函数)
file_name
 返回此对象所表示的文件名
(公开成员函数)
function_name
 返回此对象所表示的函数名，若它存在
(公开成员函数)

示例

#include <iostream>
#include <string_view>
#include <experimental/source_location>

void log(const std::string_view& message, const std::experimental::source_location& location = std::experimental::source_location::current())
{
    std::cout << "info:"
              << location.file_name() << ":"
              << location.line() << " "
              << message << '\n';
}

int main()
{
    log("Hello world!");
}

可能的输出：

info:main.cpp:15 Hello world!


std::experimental::source_location::column

< cpp‎ | experimental‎ | source location
constexpr std::uint_least32_t column() const noexcept; | (库基础 TS v2)

返回此对象所表示的，表示距行首的某偏移的实现定义值（即列号）。

参数

（无）

返回值

此对象所表示的，表示距行首的某偏移的实现定义值（即列号）。

示例

#include <iostream>
#include <string_view>
#include <experimental/source_location>

template<typename T = std::experimental::source_location>
inline void pos(const T& location = T::current())
{
    std::cout
        << "("
        << location.line()
        << ':'
        << location.column()
        << ") ";
}

auto main() -> int
{
    pos(); std::cout << "Proxima\n";
    pos(); std::cout << "Centauri\n";
}

可能的输出：

(18:5) Proxima
(19:5) Centauri

参阅

line | 返回此对象所表示的行号 (公开成员函数)
file_name | 返回此对象所表示的文件名 (公开成员函数)
function_name | 返回此对象所表示的函数名，若它存在 (公开成员函数)


std::experimental::source_location::current

< cpp‎ | experimental‎ | source location
static constexpr source_location current() noexcept; | (库基础 TS v2)

构造新的 source_location 对象。

返回值

若直接调用 current() （通过指名 current() 的函数调用），则返回拥有表示调用位置的实现定义值的 source_location 对象。该值应该以和预定义宏 __LINE__ 及 __FILE__ 相同的方式受 #line 预处理器指令影响。

若以任何其他方式调用 current() ，则返回值未指定。

提醒

若将 current() 用于非静态数据成员的初始化器，则返回值对应初始化该数据成员的构造函数或聚合初始化的位置。

注意

current() 被用于默认参数时，返回值将对应在调用点对 current() 调用的位置。

参数

（无）

参阅

(构造函数)
 创建拥有实现定义值的新 source_location
(公开成员函数)


std::experimental::source_location::file_name

< cpp‎ | experimental‎ | source location
constexpr const char* file_name() const noexcept; | (库基础 TS v2)

返回此对象所表示的当前源文件名，表示为空终止字节字符串。

参数

（无）

返回值

此对象所表示的当前源文件名，表示为空终止字节字符串。

示例

#include <experimental/source_location>
#include <iostream>

inline void print_this_file_name(
    const std::experimental::source_location& location
        = std::experimental::source_location::current())
{
    // 含有此函数调用点的文件名
    std::cout << "File: " << location.file_name() << '\n';
}

int main()
{
    print_this_file_name();
}

可能的输出：

File: main.cpp

参阅

line | 返回此对象所表示的行号 (公开成员函数)
column | 返回此对象所表示的列号 (公开成员函数)
function_name | 返回此对象所表示的函数名，若它存在 (公开成员函数)


std::experimental::source_location::function_name

< cpp‎ | experimental‎ | source location
constexpr const char* function_name() const noexcept; | (库基础 TS v2)

返回与此对象所表示的位置关联的函数名，若它存在。

参数

（无）

返回值

若此对象表示函数体中的位置，则返回对应该函数名的实现定义的空终止字节字符串。

否则，返回空字符串。

示例

以下示例展示可以如何用 std::source_location::function_name() 打印函数、构造函数、析构函数或重载的 operator() 的名字。

#include <experimental/source_location>
#include <iostream>
#include <string_view>

inline void function_name(
    const std::string_view signature = "()",
    const std::experimental::source_location& location
        = std::experimental::source_location::current())
{
    std::cout
        << location.function_name() // <- 调用方的名字！
        << signature
        << '\n';
}

void foo() { function_name(); }

struct S {
    S() { function_name(); }
    S(int) { function_name("(int)"); }
    S& operator=(S const&) { function_name("(const S&)"); return *this; }
    S& operator=(S&&) { function_name("(S&&)"); return *this; }
    ~S() { function_name(); }
};

int main()
{
    foo();
    S p;
    S q{42};
    p = q;
    p = std::move(q);
}

可能的输出：

foo()
S()
S(int)
operator=(const S&)
operator=(S&&)
~S()
~S()

参阅

line | 返回此对象所表示的行号 (公开成员函数)
column | 返回此对象所表示的列号 (公开成员函数)
file_name | 返回此对象所表示的文件名 (公开成员函数)


std::experimental::source_location::line

< cpp‎ | experimental‎ | source location
constexpr std::uint_least32_t line() const noexcept; | (库基础 TS v2)

返回此对象所表示的行号。

参数

（无）

返回值

此对象所表示的行号。

示例

#include <experimental/source_location>
#include <string_view>
#include <iostream>
using std::experimental::source_location;

inline void cur_line(
    const std::string_view message = "",
    const source_location& location = source_location::current())
{
    std::cout
        << location.line() // <- 调用点的行号
        << ") "
        << message;
}

auto main() -> int
{
    cur_line("++" "\n");
    cur_line(); std::cout << "Hello," "\n";
    cur_line(); std::cout << "C++20!" "\n";
    cur_line("--" "\n");
}

输出：

18) ++
19) Hello,
20) C++20!
21) --

参阅

column | 返回此对象所表示的列号 (公开成员函数)
file_name | 返回此对象所表示的文件名 (公开成员函数)
function_name | 返回此对象所表示的函数名，若它存在 (公开成员函数)


std::experimental::source_location::source_location

< cpp‎ | experimental‎ | source location
constexpr source_location() noexcept; | (1) | (库基础 TS v2)
source_location( const source_location& other ) = default; | (2) | (库基础 TS v2) (隐式声明)
source_location( source_location&& other ) = default; | (3) | (库基础 TS v2) (隐式声明)
1) 构造 source_location 对象，其值为实现定义。
2-3) 隐式声明的复制和移动构造函数。

参数

other - 要复制的另一 source_location

参阅

current
[静态]
 创建新的 source_location
(公开静态成员函数)


数学特殊函数

< cpp‎ | experimental

数学特殊函数库 (The Mathematical Special Functions library) ， ISO/IEC 29124:2010 ，指定对于 C++ 标准库的扩展，它包含数学特殊函数（原为 ISO/IEC TR 19768:2007 的一部分）。

此库中的特殊函数实现于 boost.math ，当前可用它们的编译器和平台多于可用此标准的实现者。在写此内容时，宣称直接支持的编译器唯有 gcc ，版本 6.1 。

函数

定义于头文件 <cmath>
assoc_laguerreassoc_laguerrefassoc_laguerrel | 关联拉盖尔多项式 (函数)
assoc_legendreassoc_legendrefassoc_legendrel | 关联勒让德多项式 (函数)
betabetafbetal | beta 函数 (函数)
comp_ellint_1comp_ellint_1fcomp_ellint_1l | 第一类完全椭圆积分 (函数)
comp_ellint_2comp_ellint_2fcomp_ellint_2l | 第二类完全椭圆积分 (函数)
comp_ellint_3comp_ellint_3fcomp_ellint_3l | 第三类完全椭圆积分 (函数)
cyl_bessel_icyl_bessel_ifcyl_bessel_il | 常规修正柱贝塞尔函数 (函数)
cyl_bessel_jcyl_bessel_jfcyl_bessel_jl | 第一类柱贝塞尔函数 (函数)
cyl_bessel_kcyl_bessel_kfcyl_bessel_kl | 非常规修正柱贝塞尔函数 (函数)
cyl_neumanncyl_neumannfcyl_neumannl | 柱诺依曼函数 (函数)
ellint_1ellint_1fellint_1l | 第一类不完全椭圆积分 (函数)
ellint_2ellint_2fellint_2l | 第二类不完全椭圆积分 (函数)
ellint_3ellint_3fellint_3l | 第三类不完全椭圆积分 (函数)
expintexpintfexpintl | 指数积分 (函数)
hermitehermitefhermitel | 埃尔米特多项式 (函数)
legendrelegendreflegendrel | 勒让德多项式 (函数)
laguerrelaguerreflaguerrel | 拉盖尔多项式 (函数)
riemann_zetariemann_zetafriemann_zetal | 黎曼 zeta 函数 (函数)
sph_besselsph_besselfsph_bessell | 第一类球贝塞尔函数 (函数)
sph_legendresph_legendrefsph_legendrel | 球关联勒让德函数 (函数)
sph_neumannsph_neumannfsph_neumannl | 球诺依曼函数 (函数)

宏

__STDCPP_MATH_SPEC_FUNCS__
 至少为 201003L 的值，指示支持 ISO/IEC 29124:2010
(宏常量)


std::experimental::to_array

< cpp‎ | experimental
定义于头文件 <experimental/array>
template <class T, std::size_t N>
constexpr std::array < std::remove_cv_t <T>, N> to_array(T (&a)[N]);
 (库基础 TS v2)

从内建数组 a 创建 std::array 。 std::array 的元素从 a 的对应元素复制初始化。

参数

a - 用于初始化 std::array 的内建数组

返回值

从 a 的元素复制初始化对应元素的 std::array 对象。

可能的实现

namespace detail {
template <class T, std::size_t N, std::size_t... I>
constexpr std::array<std::remove_cv_t<T>, N>
    to_array_impl(T (&a)[N], std::index_sequence<I...>)
{
    return { {a[I]...} };
}
}

template <class T, std::size_t N>
constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N])
{
    return detail::to_array_impl(a, std::make_index_sequence<N>{});
}

示例

#include <cstdlib>
#include <cassert>
#include <experimental/array>
#include <unistd.h>

// mkstemp(3) 可工作
template <std::size_t N>
int tempfd(char const (&tmpl)[N])
{
    auto s = std::experimental::to_array(tmpl);
    int fd = mkstemp(s.data());
    if (fd != -1)
        unlink(s.data());

    return fd;
}

int main()
{
    int fd = tempfd("/tmp/test.XXXXXX");
    int rt = close(fd);
    assert(rt == 0);
}

参阅

make_array
 创建 std::array 对象，从参数推导出其大小和可选的元素类型
(函数模板)


std::experimental::unique_resource

< cpp‎ | experimental
定义于头文件 <experimental/scope> |
template<class R, class D> class unique_resource; | (库基础 TS v3)

unique_resource 是通用的资源柄 RAII 包装，通过柄占有并管理资源，并在 unique_resource 销毁时释放该资源。

在以下任一情况发生时，用 D 类型删除器释放资源：

  • 销毁管理的 unique_resource 对象
  • 经由 operator= 或 reset() 赋另一资源给 unique_resource 对象。

若 R 为对象类型则令 RS 为 R ，否则为 std::reference_wrapper < std::remove_reference_t <R>> ：

  • unique_resource 等效地保有包装或作为资源柄的 RS 类型子对象、 D 类型删除器及指示包装是否占有资源的 bool 标志。
  • 为解释目的，称 RS 为存储的资源柄，存储（若 R 为对象类型）或包装（若 R 为引用类型）的 R 为底层资源柄。 LFTS 不使用此二用语。

模板形参

R | - | 资源柄类型
D | - | 删除器类型
类型要求
- R 应当为对象类型或到对象的左值引用类型。令 UnrefR 为 std::remove_reference_t <R> ，则 UnrefR 应当为可移动构造 (MoveConstructible) ，而若 UnrefR 非可复制构造 (CopyConstructible) ，则 std::is_nothrow_move_constructible_v <UnrefR> 应当为 true 。
- D 应当为可析构 (Destructible) 且可移动构造 (MoveConstructible) 的函数对象 (FunctionObject) 类型，而若 D 非可复制构造 (CopyConstructible) ，则 std::is_nothrow_move_constructible_v <R> 应当为 true 。 给定 D 类型左值 d 与 UnrefR 类型左值 r ，表达式 d(r) 应当为良构。

成员函数

(构造函数)
 构造新的 unique_resource
(公开成员函数)
(析构函数)
 释放被管理资源，若它存在
(公开成员函数)
operator=
 赋值 unique_resource
(公开成员函数)
修改器
release
 放弃所有权
(公开成员函数)
reset
 释放或替换被管理的资源
(公开成员函数)
观察器
get
 访问底层资源柄
(公开成员函数)
get_deleter
 访问用于释放被管理资源的删除器
(公开成员函数)
operator*operator->
 访问被指向者，若资源柄为指针
(公开成员函数)

非成员函数

make_unique_resource_checked
 创建 unique_resource ，检查非法值
(函数模板)

推导指引

注解

满足可空指针 (NullablePointer) 的资源柄类型亦能由 std::unique_ptr 管理。不同于 unique_ptr ， unique_resource 不要求可空指针 (NullablePointer) 。

示例

本节未完成
原因：暂无示例

参阅

unique_ptr
(C++11)
 拥有独有对象所有权语义的智能指针
(类模板)


std::experimental::unique_resource 的推导指引

< cpp‎ | experimental‎ | unique resource
定义于头文件 <experimental/scope> |
template<class R, class D> unique_resource(R, D) -> unique_resource<R, D>; | (库基础 TS v3)

为 std::experimental::unique_resource 提供一个推导指引以允许从给定的资源柄和删除器推导。

复制或移动参数（在数组到指针与函数到指针衰变后，若存在）到构造的 unique_resource 中。

示例

本节未完成
原因：暂无示例


std::experimental::unique_resource<R, D>::get

< cpp‎ | experimental‎ | unique resource
const R& get() const noexcept; | (库基础 TS v3)

访问底层资源柄。

参数

（无）

返回值

底层资源柄。

示例

本节未完成
原因：暂无示例

参阅

operator*operator-> | 访问被指向者，若资源柄为指针 (公开成员函数)
get | 返回指向被管理对象的指针 (std::unique_ptr<T,Deleter> 的公开成员函数)


std::experimental::unique_resource<R, D>::get_deleter

< cpp‎ | experimental‎ | unique resource
const D& get_deleter() const noexcept; | (库基础 TS v3)

访问会用于释放管理的资源的删除器对象。

参数

（无）

返回值

存储的删除器。

示例

本节未完成
原因：暂无示例

参阅

get_deleter
 返回用于析构被管理对象的删除器
(std::unique_ptr<T,Deleter> 的公开成员函数)


std::experimental::make_unique_resource_checked

< cpp‎ | experimental‎ | unique resource
定义于头文件 <experimental/scope>
template <class R, class D, class S = std::decay_t <R>>

std::experimental::unique_resource< std::decay_t <R>, std::decay_t <D>>
make_unique_resource_checked(R&& r, const S& invalid, D&& d)

noexcept(/*see below*/);
 (库基础 TS v3)

创建 unique_resource ，以 std::forward <R>(r) 初始化其存储的资源柄，以 std::forward <D>(d) 初始化其删除器。创建的 unique_resource 占有资源当且仅当 bool(r == invalid) 为 false 。

若 r == invalid 不能按语境转换成 bool，则程序为谬构，而若该转换导致未定义行为或抛异常，则行为未定义。

参数

r | - | 资源柄
d | - | 用于释放资源的删除器
invalid | - | 指示资源柄为非法的值

返回值

如上所述的 unique_resource 。

异常

存储的资源柄与删除器的初始化中抛出的任何异常。

noexcept 说明：
noexcept(

std::is_nothrow_constructible_v < std::decay_t <R>, R> &&
std::is_nothrow_constructible_v < std::decay_t <D>, D>

)

注解

make_unique_resource_checked 存在是为了避免以非法参数调用删除器函数。

复制或移动资源柄 r 到返回值中，而创建的 unique_resource 始终保有拥有对象类型的底层资源柄。

示例

#include <cstdio>
#include <experimental/scope>

int main()
{
    // 避免在 fclose 失败时调用 fclose
    auto file = std::experimental::make_unique_resource_checked(
        std::fopen("potentially_nonexistent_file.txt", "r"),
        nullptr,
        [](std::FILE *fptr){ std::fclose(fptr); }
    );
    if (file.get()) {
        std::puts("The file exits.");
    }
    else {
        std::puts("The file does not exist.");
    }
}

可能的输出：

The file does not exist.

参阅


std::experimental::unique_resource<R, D>::operator*, std::experimental::unique_resource<R, D>::operator->

< cpp‎ | experimental‎ | unique resource
std::add_lvalue_reference_t < std::remove_pointer_t <R>>
operator*() const noexcept;
 (1) (库基础 TS v3)
R operator->() const noexcept;
 (2) (库基础 TS v3)
1) 访问作为指针的底层资源柄所指向的对象或函数。此函数仅若 std::is_pointer_v <R> 为 true 且 std::is_void_v < std::remove_pointer_t <R>> 为 false 才参与重载决议。若资源柄不指向对象或函数，则行为未定义。
2) 获取作为指针的底层资源柄的副本。此函数仅若 std::is_pointer_v <R> 为 true 才参与重载决议。常用返回值访问被指向的对象。

参数

（无）

返回值

1) 底层资源柄所指向的函数或对象。
2) 底层资源柄的副本。

示例

本节未完成
原因：暂无示例

参阅

get | 访问底层资源柄 (公开成员函数)
operator*operator-> | 解引用指向被管理对象的指针 (std::unique_ptr<T,Deleter> 的公开成员函数)


std::experimental::unique_resource<R, D>::operator=

< cpp‎ | experimental‎ | unique resource
unique_resource& operator=( unique_resource&& other )
noexcept(/*see below*/);
 (库基础 TS v3)

移动赋值运算符。以 other 的被管理资源替换被管理资源。

正式而言，令 RS 为存储的资源柄的类型：

  • 首先，调用 reset() 释放当前占有的资源，若存在。
  • 然后以 other 的存储的资源柄与删除器赋值存储的资源柄与删除器。若 std::is_nothrow_move_assignable_v <RS> 或 std::is_nothrow_move_assignable_v <D> 为 true ，则分别应用 std::move 到 other 的存储的资源柄或删除器。首先执行存储的资源柄的赋值，除非 std::is_nothrow_move_assignable_v <D> 为 false 而 std::is_nothrow_move_assignable_v <RS> 为 true 。
  • 最后，设置 *this 为占有资源当且仅当赋值前 other 占有它，并设置 other 为不占有资源。

若 std::is_nothrow_move_assignable_v <RS> 为 true ，则 RS 应当满足可移动赋值 (MoveAssignable) 要求；否则 RS 应当满足可复制赋值 (CopyAssignable) 要求。若 std::is_nothrow_move_assignable_v <D> 为 true ，则 D 应当满足可移动赋值 (MoveAssignable) 要求；否则 D 应当满足可复制赋值 (CopyAssignable) 要求。不满足上述要求导致未定义行为。

参数

other - 将要被转移所有权的资源包装

返回值

*this

异常

任何复制赋值中抛出的异常。

noexcept 说明：
noexcept( std::is_nothrow_move_assignable_v <RS> && std::is_nothrow_move_assignable_v <D>)

注解

若复制成员抛出异常，则此机制置 other 于不变并使 *this 在被释放状态。

示例

本节未完成
原因：暂无示例

参阅

reset | 释放或替换被管理的资源 (公开成员函数)
operator= | 为unique_ptr赋值 (std::unique_ptr<T,Deleter> 的公开成员函数)


std::experimental::unique_resource<R, D>::release

< cpp‎ | experimental‎ | unique resource
void release() noexcept; | (库基础 TS v3)

释放资源的所有权，若存在。调用后析构函数将不会执行删除器，除非在之后为管理新资源调用 reset 。

不同于 std::unique_ptr::release ，不要求此函数修改存储的资源柄。

参数

（无）

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

release
 返回一个指向被管理对象的指针，并释放所有权
(std::unique_ptr<T,Deleter> 的公开成员函数)


std::experimental::unique_resource<R, D>::reset

< cpp‎ | experimental‎ | unique resource
void reset() noexcept; | (1) | (库基础 TS v3)
template <class RR> void reset( RR&& r ); | (2) | (库基础 TS v3)
1) 若 unique_resource 占有资源，则通过以底层资源柄调用删除器释放它。调用后 unique_resource 不占有资源。
2) 通过调用 (1) 然后若 std::is_nothrow_assignable_v <RS, RR> 为 true 则以 std::forward <RR>(r) ，否则以 std::as_const (r) 赋值存储的资源柄替换资源，其中 RS 是存储的资源柄的类型。调用后 unique_resource 占有资源。
若存储的资源柄的复制赋值抛异常，则调用 del_(r) ，其中 del 是删除器对象。
此重载仅若选择的赋值存储的资源柄的赋值表达式为良构才参与重载决议。
若 del_(r) 为谬构则程序为谬构。
若 del_(r) 导致未定义行为或抛异常则行为未定义。

参数

r - 要管理的新资源的资源柄

返回值

（无）

异常

2) 任何赋值存储的资源柄时抛出的异常。

注解

该机制确保无资源泄漏。

示例

本节未完成
原因：暂无示例

参阅

reset
 替换被管理对象
(std::unique_ptr<T,Deleter> 的公开成员函数)


std::experimental::unique_resource<R, D>::unique_resource

< cpp‎ | experimental‎ | unique resource
unique_resource(); | (1) | (库基础 TS v3)
template <class RR, class DD> unique_resource( RR&& r, DD&& d ) noexcept(/*see below*/) | (2) | (库基础 TS v3)
unique_resource( unique_resource&& other ); | (3) | (库基础 TS v3)

为解释目的使用下列项目：

  • RS 为存储的资源柄的类型。
  • 表达式 res_ 指代底层资源柄。
  • del_ 指代删除器对象。
1) 默认构造函数。值初始化存储的资源柄与删除器。构造的的 unique_resource 不拥有资源。
此重载仅若 std::is_default_constructible_v <R> 与 std::is_default_constructible_v <D> 均为 true 才参与重载决议。
2) 若 std::is_nothrow_constructible_v <RS, RR> 为 true 则以 std::forward <RR>(r) ，否则以 r 初始化存储的资源柄。若存储的资源柄的初始化抛异常，则调用 d(r) 。
然后，若 std::is_nothrow_constructible_v <D, DD> 为 true 则以 std::forward <DD>(d) ，否则以 d 初始化删除器。若删除器的初始化跑一次，则调用 d(res_) 。
构造的 unique_resource 占有资源。
此重载仅若 std::is_constructible_v <RS, RR> 、 std::is_constructible_v <D , DD> 、 std::is_nothrow_constructible_v <RS, RR> || std::is_constructible_v <RS, RR&> 和 std::is_nothrow_constructible_v <D, DD> || std::is_constructible_v <D, DD&> 都为 true 才参与重载决议。
若表达式 d(r) 、 d(res_) 与 del_(res_) 的任一者为谬构，则程序为谬构。
若表达式 d(r) 、 d(res_) 与 del_(res_) 的任一者导致未定义行为或抛异常，则行为未定义。
3) 移动构造函数。用 other 的存储的资源柄初始化存储的资源柄，若 std::is_nothrow_move_constructible_v <RS> 为 true 则使用 std::move 。若底层资源柄的初始化抛异常，则不修改 other 。
然后，用 other 的删除器初始化删除器，若 std::is_nothrow_move_constructible_v <D> 为 true 则使用 std::move 。若删除器的初始化抛异常且 std::is_nothrow_move_constructible_v <RS> 为 true 而 other 占有资源，则以 res_ 调用 other 的删除器释放资源，然后调用 other.release() 。
构造后，构造的 unique_resource 占有资源当且仅当 other 在构造前占有资源，并设置 other 为不占有资源。

参数

r | - | 资源柄
d | - | 用于释放资源的删除器
other | - | 要获得其所有权的 unique_resource

异常

任何初始化存储的资源柄或删除器时抛出的异常。

2)
noexcept 说明：
noexcept((

std::is_nothrow_constructible_v <RS, RR> || std::is_nothrow_constructible_v <RS, RR&>
) &&
(
std::is_nothrow_constructible_v <D, DD> || std::is_nothrow_constructible_v <D, DD&>

))
3)
noexcept 说明：
noexcept(

std::is_nothrow_move_constructible_v <R1> && std::is_nothrow_move_constructible_v <D>

)

注解

这些构造函数的机制确保无资源泄漏。

示例

本节未完成
原因：暂无示例

参阅

(构造函数)
 构造新的unique_ptr
(std::unique_ptr<T,Deleter> 的公开成员函数)


std::experimental::unique_resource<R, D>::~unique_resource

< cpp‎ | experimental‎ | unique resource
~unique_resource(); | (库基础 TS v3)

若 unique_resource 占有资源，则以底层资源柄调用删除器释放它，等价于调用 reset() 。然后销毁存储的资源柄与删除器。

参阅

reset | 释放或替换被管理的资源 (公开成员函数)
(析构函数) | 析构所管理的对象，如果存在的话 (std::unique_ptr<T,Deleter> 的公开成员函数)


std::experimental::erase_if (std::unordered_map)

< cpp‎ | experimental

定义于头文件 <experimental/unordered_map> |
template <class Key, class T, class Hash, class KeyEqual, class Alloc, class Pred> void erase_if( std::unordered_map <Key,T,Hash,KeyEqual,Alloc>& c, Pred pred); | (库基础 TS v2)

从容器擦除所有满足谓词 pred 的元素。等价于

for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}

参数

c | - | 要从中擦除的容器
pred | - | 确定该擦除哪些元素的谓词

复杂度

线性。

示例

#include <experimental/unordered_map>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& cont)
{
    os << "{";
    for (const auto& item : cont) {
        os << "{" << item.first << ", " << item.second << "}";
    }
    return os << "}";
}

int main()
{
    std::unordered_map<int, char> data {{1, 'a'},{2, 'b'},{3, 'c'},{4, 'd'},
                                        {5, 'e'},{4, 'f'},{5, 'g'},{5, 'g'}};
    std::cout << "Original:\n" << data << '\n';

    std::experimental::erase_if(data, [](const auto& item) {
        return (item.first & 1) == 1;
    });

    std::cout << "Erase items with odd keys:\n" << data << '\n';
}

可能的输出：

Original:
{{5, e}{4, d}{3, c}{2, b}{1, a}}
Erase items with odd keys:
{{4, d}{2, b}}

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::experimental::erase_if (std::unordered_multimap)

< cpp‎ | experimental

定义于头文件 <experimental/unordered_map> |
template <class Key, class T, class Hash, class KeyEqual, class Alloc, class Pred> void erase_if( std::unordered_multimap <Key,T,Hash,KeyEqual,Alloc>& c, Pred pred); | (库基础 TS v2)

从容器擦除所有满足谓词 pred 的元素。等价于

for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}

参数

c | - | 要从中擦除的容器
pred | - | 确定该擦除哪些元素的谓词

复杂度

线性。

示例

#include <experimental/unordered_map>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& cont)
{
    os << "{";
    for (const auto& item : cont) {
        os << "{" << item.first << ", " << item.second << "}";
    }
    return os << "}";
}

int main()
{
    std::unordered_multimap<int, char> data {{1, 'a'},{2, 'b'},{3, 'c'},{4, 'd'},
                                             {5, 'e'},{4, 'f'},{5, 'g'},{5, 'g'}};
    std::cout << "Original:\n" << data << '\n';

    std::experimental::erase_if(data, [](const auto& item) {
        return (item.first & 1) == 1;
    });

    std::cout << "Erase items with odd keys:\n" << data << '\n';
}

可能的输出：

Original:
{{5, g}{5, g}{5, e}{4, f}{4, d}{3, c}{2, b}{1, a}}
Erase items with odd keys:
{{4, f}{4, d}{2, b}}

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::experimental::erase_if (std::unordered_multiset)

< cpp‎ | experimental

定义于头文件 <experimental/unordered_set> |
template <class Key, class Hash, class KeyEqual, class Alloc, class Pred> void erase_if( std::unordered_multiset <Key,Hash,KeyEqual,Alloc>& c, Pred pred); | (库基础 TS v2)

从容器擦除所有满足谓词 pred 的元素。等价于

for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}

参数

c | - | 要从中擦除的容器
pred | - | 确定该擦除哪些元素的谓词

复杂度

线性。

示例

#include <experimental/unordered_set>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& container)
{
    os << "{ ";
    for (const auto& item : container) {
        os << item << ' ';
    }
    return os << "}";
}

int main()
{
    std::unordered_multiset<int> data { 3, 3, 4, 5, 5, 6, 6, 7, 2, 1, 0 };

    std::cout << "Original:\n" << data << '\n';

    auto divisible_by_3 = [](auto const& x) { return (x % 3) == 0; };

    std::experimental::erase_if(data, divisible_by_3);

    std::cout << "Erase all items divisible by 3:\n" << data << '\n';
}

可能的输出：

Original:
{ 0 1 2 7 6 6 5 5 4 3 3 }
Erase all items divisible by 3:
{ 1 2 7 5 5 4 }

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::experimental::erase_if (std::unordered_set)

< cpp‎ | experimental

定义于头文件 <experimental/unordered_set> |
template <class Key, class Hash, class KeyEqual, class Alloc, class Pred> void erase_if( std::unordered_set <Key,Hash,KeyEqual,Alloc>& c, Pred pred); | (库基础 TS v2)

从容器擦除所有满足谓词 pred 的元素。等价于

for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}

参数

c | - | 要从中擦除的容器
pred | - | 确定该擦除哪些元素的谓词

复杂度

线性。

示例

#include <experimental/unordered_set>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& container)
{
    os << "{ ";
    for (const auto& item : container) {
        os << item << ' ';
    }
    return os << "}";
}

int main()
{
    std::unordered_set<int> data { 3, 3, 4, 5, 5, 6, 6, 7, 2, 1, 0 };

    std::cout << "Original:\n" << data << '\n';

    auto divisible_by_3 = [](auto const& x) { return (x % 3) == 0; };

    std::experimental::erase_if(data, divisible_by_3);

    std::cout << "Erase all items divisible by 3:\n" << data << '\n';
}

可能的输出：

Original:
{ 0 1 2 7 6 5 4 3 }
Erase all items divisible by 3:
{ 1 2 7 5 4 }

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::experimental::erase (std::vector)

< cpp‎ | experimental

定义于头文件 <experimental/vector> |
template <class T, class A, class U> void erase( std::vector <T, A>& c, const U& value); | (库基础 TS v2)

从容器擦除所有比较等于 value 的元素。等价于 c.erase(std::remove(c.begin(), c.end(), value), c.end());

参数

c | - | 要从中擦除的容器
value | - | 要移除的值

复杂度

线性。

示例

#include <experimental/vector>
#include <iostream>

auto show = [](const auto& container) {
    for (auto e : container) {
        std::cout << e;
    }
    std::cout << '\n';
};

int main()
{
    std::vector<int> data{1,1,1,4,1,1,1,2,1,1,1};
    show(data);
    std::experimental::erase(data, 1);
    show(data);
}

输出：

11141112111
42

参阅

removeremove_if | 移除满足特定判别标准的元素 (函数模板)
erase_if(std::vector) (库基础 2 TS) | 从 std::vector 擦除所有满足谓词的元素 (函数模板)


std::experimental::erase_if (std::vector)

< cpp‎ | experimental

定义于头文件 <experimental/vector> |
template <class T, class Alloc, class Pred> void erase_if( std::vector <T,Alloc>& c, Pred pred); | (库基础 TS v2)

从容器擦除所有满足谓词 pred 的元素。等价于 c.erase( std::remove_if (c.begin(), c.end(), pred), c.end());

参数

c | - | 要从中擦除的容器
pred | - | 确定该擦除哪些元素的谓词

复杂度

线性。

示例

#include <experimental/vector>
#include <iostream>

template<typename Os, typename Container>
inline Os& operator<<(Os& os, Container const& container)
{
    os << "{ ";
    for (const auto& item : container) {
        os << item << ' ';
    }
    return os << "}";
}

int main()
{
    std::vector<int> data { 3, 3, 4, 5, 5, 6, 6, 7, 2, 1, 0 };

    std::cout << "Original:\n" << data << '\n';

    auto divisible_by_3 = [](auto const& x) { return (x % 3) == 0; };

    std::experimental::erase_if(data, divisible_by_3);

    std::cout << "Erase all items divisible by 3:\n" << data << '\n';
}

输出：

Original:
{ 3 3 4 5 5 6 6 7 2 1 0 }
Erase all items divisible by 3:
{ 4 5 5 7 2 1 }

参阅

removeremove_if | 移除满足特定判别标准的元素 (函数模板)
erase(std::vector) (库基础 2 TS) | 从 std::vector 擦除所有等于特定值的元素 (函数模板)


std::experimental::void_t

< cpp‎ | experimental
定义于头文件 <experimental/type_traits> |
template< class... > using void_t = void; | (库基础 TS v2)

工具元函数，映射任何类型序列到类型 void 。

注解

此工具原函数用于在 SFINAE 语境中检测非良构的类型。它首先作为 std::void_t 被投票选入 C++17 ，然后才同样作为 std::experimental::void_t 加入库基础 TS ，因为检测手法依赖它，而 LFTS v2 基于 C++14 。

参阅

void_t
(C++17)
 void 变参别名模板
(别名模板)


std::experimental::when_all

< cpp‎ | experimental
定义于头文件 <experimental/future>
template < class InputIt >

auto when_all(InputIt first, InputIt last)

-> future< std::vector <typename std::iterator_traits <InputIt>::value_type>>;
 (1) (并发 TS)
template < class... Futures >

auto when_all(Futures&&... futures)

-> future< std::tuple < std::decay_t <Futures>...>>;
 (2) (并发 TS)

创建 future 对象，它将在所有输入 future 和 shared_future 就绪后变为就绪。若任何输入 future 或 shared_future 非法则行为未定义。

具体而言，令 Sequence 对 (1) 为 std::vector <typename std::iterator_traits <InputIt>::value_type> ，对 (2) 为 std::tuple < std::decay_t <Futures>...> 。此函数模板创建含 Sequence 的共享状态，并返回指代该共享状态的 future 。移动每个输入 future 到共享状态中的 Sequence 的对应对象中，复制每个输入 shared_future 到共享状态中的 Sequence 中的对应对象。 Sequence 中的对象顺序匹配参数的顺序。

1) 此函数仅若 InputIt 的值类型（即 typename std::iterator_traits <InputIt>::value_type ）为 std::experimental::future 或 std::experimental::shared_future 才参与重载决议。
2) 此函数仅若每个参数为（可有 cv 限定的） std::experimental::shared_future 或无 cv 限定的 std::experimental::future 才参与重载决议（正式而言，对于 Futures 中的每个 Fn ，要么 std::remove_reference_t <Fn> 为 std::experimental::future<Rn> ，要么 std::decay_t <Fn> 为 std::experimental::shared_future<Rn> ）。

此调用后，每个输入 future 不再合法；每个输入 shared_future 保持合法。

返回值

指代调用所创建的共享状态的 future 。该 future 始终 valid() ，而它在调用的所有输入 future 和 shared_future 就绪时变为就绪。

1) 若范围为空（即 first == last ），则返回的 future 含有空 vector 且立即就绪。
2) 若不提供参数，则返回 future<std::tuple<>> 且立即就绪。


std::experimental::when_any

< cpp‎ | experimental
定义于头文件 <experimental/future>
template < class Sequence >

struct when_any_result {
std::size_t index;
Sequence futures;

};
 (并发 TS)
template < class InputIt >

auto when_any(InputIt first, InputIt last);
-> future<when_any_result<
std::vector <typename std::iterator_traits <InputIt>::value_type>

>>
 (1) (并发 TS)
template < class... Futures >

auto when_any(Futures&&... futures)

-> future<when_any_result< std::tuple < std::decay_t <Futures>...>>>;
 (2) (并发 TS)

创建 future 对象，它在至少一个输入 future 和 shared_future 就绪时变为就绪。若任何输入 future 或 shared_future 非法则行为未定义。

具体而言，令 Sequence 对 (1) 为 std::vector <typename std::iterator_traits <InputIt>::value_type> ，对 (2) 为 std::tuple < std::decay_t <Futures>...> 。此函数模板创建含 when_any_result<Sequence> 的共享状态，并返回指代该共享状态的 future 。移动每个输入 future 到共享状态中的 when_any_result<Sequence> 的 futures 成员的对应对象中，复制每个输入 shared_future 到共享状态中的 when_any_result<Sequence> 的 futures 成员中的对应对象。 Sequence 中的对象顺序匹配参数的顺序。

1) 此函数仅若 InputIt 的值类型（即 typename std::iterator_traits <InputIt>::value_type ）为 std::experimental::future 或 std::experimental::shared_future 才参与重载决议。
2) 此函数仅若每个参数为（可有 cv 限定的） std::experimental::shared_future 或无 cv 限定的 std::experimental::future 才参与重载决议（正式而言，对于 Futures 中的每个 Fn ，要么 std::remove_reference_t <Fn> 为 std::experimental::future<Rn> ，要么 std::decay_t <Fn> 为 std::experimental::shared_future<Rn> ）。

此调用后，每个输入 future 不再合法；每个输入 shared_future 保持合法。

返回值

指代此调用所创建的共享状态的 future 。该 future 始终为 valid() ，而它在至少一个调用的输入 future 和 shared_future 就绪时变为就绪。 when_any_result 的 index 成员含有 futures 成员中就绪的 future 或 shared_future 的位置。

1) 若范围为空（即 first == last ），则返回的 future 立即就绪； when_any_result 的 futures 域为空 vector ，而 index 域为 size_t(-1) 。
2) 若不提供参数，则返回的 future 立即就绪； when_any_result 的 futures 域为空 tuple ，而 index 域为 size_t(-1) 。


功能特性测试 (C++20)

< cpp

标准中为 C++11 和其后所引入的 C++ 语言和程序库的功能特性定义了一组预处理器宏。标准有意使之成为检测这些功能特性是否存在的一种简单且可移植的方式。

属性

__has_cpp_attribute( 属性记号 )

检查（宏展开后） 属性记号 所指名的属性的存在。

对于标准属性，它将展开成该属性被添加到工作草案中时的年份和月份（见下表），特定于厂商的属性则以某个非零值确定。

能在 #if 与 #elif 的表达式中展开 __has_cpp_attribute 。 #ifdef 、 #ifndef 和 defined 把它当做已定义的宏，但不能在别处使用它。

属性记号 | 属性 | 值 | 标准
carries_dependency | [[carries_dependency]] | 200809L | (C++11)
deprecated | [[deprecated]] | 201309L | (C++14)
fallthrough | [[fallthrough]] | 201603L | (C++17)
likely | [[likely]] | 201803L | (C++20)
maybe_unused | [[maybe_unused]] | 201603L | (C++17)
no_unique_address | [[no_unique_address]] | 201803L | (C++20)
nodiscard | [[nodiscard]] | 201603L | (C++17)
 |  | 201907L | (C++20)
noreturn | [[noreturn]] | 200809L | (C++11)
unlikely | [[unlikely]] | 201803L | (C++20)

语言功能特性

下列宏预定义于每个翻译单元。每个宏都展开成对应于相应功能特性被包含到工作草案时的年份与月份的整数字面量。

当功能特性发生了显著变更时，宏会相应地更新。

宏名 | 功能特性 | 值 | 标准
__cpp_aggregate_bases | 拥有基类的聚合类 | 201603L | (C++17)
__cpp_aggregate_nsdmi | 拥有默认成员初始化器的聚合类 | 201304L | (C++14)
__cpp_aggregate_paren_init | 形式为直接初始化的聚合初始化 | 201902L | (C++20)
__cpp_alias_templates | 别名模版 | 200704L | (C++11)
__cpp_aligned_new | 过对齐数据的动态内存分配 | 201606L | (C++17)
__cpp_attributes | 属性 | 200809L | (C++11)
__cpp_binary_literals | 二进制字面量 | 201304L | (C++14)
__cpp_capture_star_this | 以 [=,*this] 进行 *this 的按值 lambda 捕获 | 201603L | (C++17)
__cpp_char8_t | char8_t | 201811L | (C++20)
__cpp_concepts | 概念 | 201907L | (C++20)
__cpp_conditional_explicit | explicit(bool) | 201806L | (C++20)
__cpp_consteval | 立即函数 | 201811L | (C++20)
__cpp_constexpr | constexpr | 200704L | (C++11)
 | 放松 constexpr 函数上的限制和及非 const 的 constexpr 非静态成员函数 | 201304L | (C++14)
 | Constexpr lambda | 201603L | (C++17)
 | constexpr 函数中的平凡默认初始化与汇编声明 | 201907L | (C++20)
 | constexpr 函数中的非字面变量、标签及 goto 语句 | 202110L | (C++23)
__cpp_constexpr_dynamic_alloc | constexpr 函数中的动态存储期操作 | 201907L | (C++20)
__cpp_constexpr_in_decltype | 在为常量求值所需要时生成函数和变量的定义 | 201711L | (C++20)
__cpp_constinit | constinit | 201907L | (C++20)
__cpp_coroutines | 协程 | 201902L | (C++20)
__cpp_decltype | decltype | 200707L | (C++11)
__cpp_decltype_auto | 常规函数的返回类型推导 | 201304L | (C++14)
__cpp_deduction_guides | 类模板的模板实参推导 | 201703L | (C++17)
 | 聚合体与别名的 CTAD | 201907L | (C++20)
__cpp_delegating_constructors | 委托构造函数 | 200604L | (C++11)
__cpp_designated_initializers | 指派初始化器 | 201707L | (C++20)
__cpp_enumerator_attributes | 枚举项的属性 | 201411L | (C++17)
__cpp_explicit_this_parameter | 显式对象形参 | 202110L | (C++23)
__cpp_fold_expressions | 折叠表达式 | 201603L | (C++17)
__cpp_generic_lambdas | 泛型 lambda 表达式 | 201304L | (C++14)
 | 泛型 lambda 的显式模板形参列表 | 201707L | (C++20)
__cpp_guaranteed_copy_elision | 通过简化值类别保证复制消除 | 201606L | (C++17)
__cpp_hex_float | 十六进制浮点字面量 | 201603L | (C++17)
__cpp_if_consteval | consteval if | 202106L | (C++23)
__cpp_if_constexpr | constexpr if | 201606L | (C++17)
__cpp_impl_coroutine | 协程（编译器支持） | 201902L | (C++20)
__cpp_impl_destroying_delete | 销毁的 operator delete （编译器支持） | 201806L | (C++20)
__cpp_impl_three_way_comparison | 三路比较（编译器支持） | 201907L | (C++20)
__cpp_inheriting_constructors | 继承构造函数 | 200802L | (C++11)
 | 重述继承构造函数 | 201511L | (C++17)
__cpp_init_captures | Lambda 初始化捕获 | 201304L | (C++14)
 | Lambda 初始化捕获中的包展开 | 201803L | (C++20)
__cpp_initializer_lists | 列表初始化与 std::initializer_list | 200806L | (C++11)
__cpp_inline_variables | inline 变量 | 201606L | (C++17)
__cpp_lambdas | Lambda 表达式 | 200907L | (C++11)
__cpp_modules | 模块 | 201907L | (C++20)
__cpp_multidimensional_subscript | 多维下标运算符 | 202110L | (C++23)
__cpp_namespace_attributes | 命名空间的属性 | 201411L | (C++17)
__cpp_noexcept_function_type | 令异常规定为类型系统的一部分 | 201510L | (C++17)
__cpp_nontype_template_args | 允许全部非类型模板实参的常量求值 | 201411L | (C++17)
 | 非类型模板形参中的类类型与浮点类型 | 201911L | (C++20)
__cpp_nontype_template_parameter_auto | 以 auto 声明非类型模板形参 | 201606L | (C++17)
__cpp_nsdmi | 非静态数据成员初始化器 | 200809L | (C++11)
__cpp_range_based_for | 基于范围的 for 循环 | 200907L | (C++11)
 | 拥有相异的 begin/end 类型的基于范围的 for 循环 | 201603L | (C++17)
__cpp_raw_strings | 原始字符串字面量 | 200710L | (C++11)
__cpp_ref_qualifiers | 引用限定符 | 200710L | (C++11)
__cpp_return_type_deduction | 常规函数的返回类型推导 | 201304L | (C++14)
__cpp_rvalue_references | 右值引用 | 200610L | (C++11)
__cpp_size_t_suffix | size_t 与其有符号版本的字面量后缀 | 202011L | (C++23)
__cpp_sized_deallocation | 具大小解分配 | 201309L | (C++14)
__cpp_static_assert | static_assert | 200410L | (C++11)
 | 单参数的 static_assert | 201411L | (C++17)
__cpp_structured_bindings | 结构化绑定 | 201606L | (C++17)
__cpp_template_template_args | 模板模板实参的匹配 | 201611L | (C++17)
__cpp_threadsafe_static_init | 带并发的动态初始化和销毁 | 200806L | (C++11)
__cpp_unicode_characters | 新字符类型（ char16_t 与 char32_t ） | 200704L | (C++11)
__cpp_unicode_literals | Unicode 字符串字面量 | 200710L | (C++11)
__cpp_user_defined_literals | 用户定义字面量 | 200809L | (C++11)
__cpp_using_enum | using enum | 201907L | (C++20)
__cpp_variable_templates | 变量模板 | 201304L | (C++14)
__cpp_variadic_templates | 变参模板 | 200704L | (C++11)
__cpp_variadic_using | using 声明中的包展开 | 201611L | (C++17)

标准库功能特性

如果包含了头文件 <version> 或下表中的任意对应头文件，则下列各个宏有定义。每个宏都展开成其对应的功能特性被包含于工作草案时的年份与月份的相应整数字面量。

当功能特性发生了显著变更时，宏会相应地更新。

宏名 | 功能特性 | 值 | 头文件 | 标准
__cpp_lib_adaptor_iterator_pair_constructor | std::stack 与 std::queue 的迭代器对构造函数 | 202106L | <stack> <queue> | (C++23)
__cpp_lib_addressof_constexpr | constexpr std::addressof | 201603L | <memory> | (C++17)
__cpp_lib_allocate_at_least | std::allocate_at_least 等 | 202106L | <memory> | (C++23)
__cpp_lib_allocator_traits_is_always_equal | std::allocator_traits::is_always_equal | 201411L | <memory> <scoped_allocator> <string> <deque> <forward_list> <list> <vector> <map> <set> <unordered_map> <unordered_set> | (C++17)
__cpp_lib_any | std::any | 201606L | <any> | (C++17)
__cpp_lib_apply | std::apply | 201603L | <tuple> | (C++17)
__cpp_lib_array_constexpr | std::reverse_iterator 、 std::move_iterator 、 std::array 及范围访问的 constexpr | 201603L | <iterator> <array> | (C++17)
 | 常量表达式迭代器 (ConstexprIterator) ； std::array 的 constexpr 比较；杂项 constexpr （ std::array::fill 等） | 201811L | <iterator> <array> | (C++20)
__cpp_lib_as_const | std::as_const | 201510L | <utility> | (C++17)
__cpp_lib_associative_heterogeneous_erasure | 关联容器与无序关联容器中的异质擦除 | 202110L | <map> <set> <unordered_map> <unordered_set> | (C++23)
__cpp_lib_assume_aligned | std::assume_aligned | 201811L | <memory> | (C++20)
__cpp_lib_atomic_flag_test | std::atomic_flag::test | 201907L | <atomic> | (C++20)
__cpp_lib_atomic_float | 浮点原子类型 | 201711L | <atomic> | (C++20)
__cpp_lib_atomic_is_always_lock_free | constexpr atomic<T>::is_always_lock_free | 201603L | <atomic> | (C++17)
__cpp_lib_atomic_lock_free_type_aliases | 原子免锁整数类型（ std::atomic_signed_lock_free 、 std::atomic_unsigned_lock_free ） | 201907L | <atomic> | (C++20)
__cpp_lib_atomic_ref | std::atomic_ref | 201806L | <atomic> | (C++20)
__cpp_lib_atomic_shared_ptr | std::atomic<std::shared_ptr> | 201711L | <memory> | (C++20)
__cpp_lib_atomic_value_initialization | 修正原子初始化（默认值初始化 std::atomic ） | 201911L | <atomic> <memory> | (C++20)
__cpp_lib_atomic_wait | 高效的 std::atomic 等待 | 201907L | <atomic> | (C++20)
__cpp_lib_barrier | std::barrier | 201907L | <barrier> | (C++20)
__cpp_lib_bind_front | std::bind_front | 201907L | <functional> | (C++20)
__cpp_lib_bit_cast | std::bit_cast | 201806L | <bit> | (C++20)
__cpp_lib_bitops | 位操作 | 201907L | <bit> | (C++20)
__cpp_lib_bool_constant | std::bool_constant | 201505L | <type_traits> | (C++17)
__cpp_lib_bounded_array_traits | std::is_bounded_array 、 std::is_unbounded_array | 201902L | <type_traits> | (C++20)
__cpp_lib_boyer_moore_searcher | std::boyer_moore_searcher|搜索器 | 201603L | <functional> | (C++17)
__cpp_lib_byte | std::byte | 201603L | <cstddef> | (C++17)
__cpp_lib_byteswap | std::byteswap | 202110L | <bit> | (C++23)
__cpp_lib_char8_t | char8_t 的库支持 | 201907L | <atomic> <filesystem> <istream> <limits> <locale> <ostream> <string> <string_view> | (C++20)
__cpp_lib_chrono | std::chrono::duration 与 std::chrono::time_point 的舍入函数 | 201510L | <chrono> | (C++17)
 | std::chrono::duration 与 std::chrono::time_point 的所有成员函数的 constexpr | 201611L | <chrono> | (C++17)
 | 日历与时区 | 201907L | <chrono> | (C++20)
__cpp_lib_chrono_udls | 时间类型的用户定义字面量 | 201304L | <chrono> | (C++14)
__cpp_lib_clamp | std::clamp | 201603L | <algorithm> | (C++17)
__cpp_lib_complex_udls | std::complex 的用户定义字面量 | 201309L | <complex> | (C++14)
__cpp_lib_concepts | 标准库概念 | 202002L | <concepts> | (C++20)
__cpp_lib_constexpr_algorithms | 算法的 constexpr | 201806L | <algorithm> | (C++20)
__cpp_lib_constexpr_complex | std::complex 的 constexpr | 201711L | <complex> | (C++20)
__cpp_lib_constexpr_dynamic_alloc | std::allocator 与相关工具的 | 201907L | <memory> | (C++20)
__cpp_lib_constexpr_functional | 杂项 constexpr （ std::default_searcher ）； constexpr INVOKE | 201907L | <functional> | (C++20)
__cpp_lib_constexpr_iterator | 杂项 constexpr （ std::insert_iterator 等） | 201811L | <iterator> | (C++20)
__cpp_lib_constexpr_memory | std::pointer_traits 中的 constexpr | 201811L | <memory> | (C++20)
__cpp_lib_constexpr_numeric | <numeric> 算法的 constexpr | 201911L | <numeric> | (C++20)
__cpp_lib_constexpr_string | std::string 的 constexpr | 201907L | <string> | (C++20)
__cpp_lib_constexpr_string_view | 杂项 constexpr （ std::string_view::copy ） | 201811L | <string_view> | (C++20)
__cpp_lib_constexpr_tuple | 杂项 constexpr （ std::tuple::operator= 等） | 201811L | <tuple> | (C++20)
__cpp_lib_constexpr_typeinfo | std::type_info::operator== 的 constexpr | 202106L | <typeinfo> | (C++23)
__cpp_lib_constexpr_utility | 杂项 constexpr （ std::pair::operator= 等） | 201811L | <utility> | (C++20)
__cpp_lib_constexpr_vector | std::vector 的 constexpr | 201907L | <vector> | (C++20)
__cpp_lib_coroutine | 协程（库支持） | 201902L | <coroutine> | (C++20)
__cpp_lib_destroying_delete | 销毁的 operator delete （库支持） | 201806L | <new> | (C++20)
__cpp_lib_enable_shared_from_this | 再次启用 shared_from_this | 201603L | <memory> | (C++17)
__cpp_lib_endian | std::endian | 201907L | <bit> | (C++20)
__cpp_lib_erase_if | 统一容器擦除 | 202002L | <string> <deque> <forward_list> <list> <vector> <map> <set> <unordered_map> <unordered_set> | (C++20)
__cpp_lib_exchange_function | std::exchange | 201304L | <utility> | (C++14)
__cpp_lib_execution | 执行策略 | 201603L | <execution> | (C++17)
 | std::execution::unsequenced_policy | 201902L | <execution> | (C++20)
__cpp_lib_filesystem | 文件系统库 | 201703L | <filesystem> | (C++17)
__cpp_lib_format | 文本格式化 | 201907L | <format> | (C++20)
 | 编译时格式字符串检查；减少 std::vformat_to 的参数化 | 202106L | <format> | (C++23)
 | 修复 chrono 格式化器中的本地环境处理；格式化参数中使用转发引用 | 202110L | <format> | (C++23)
__cpp_lib_gcd_lcm | std::gcd、 std::lcm | 201606L | <numeric> | (C++17)
__cpp_lib_generic_associative_lookup | 关联容器中的异质比较查找 | 201304L | <map> <set> | (C++14)
__cpp_lib_generic_unordered_lookup | 无序关联容器中的异质比较查找 | 201811L | <unordered_map> <unordered_set> | (C++20)
__cpp_lib_hardware_interference_size | constexpr std::hardware_{constructive, destructive}_interference_size | 201703L | <new> | (C++17)
__cpp_lib_has_unique_object_representations | std::has_unique_object_representations | 201606L | <type_traits> | (C++17)
__cpp_lib_hypot | std::hypot 的 3 参数重载 | 201603L | <cmath> | (C++17)
__cpp_lib_incomplete_container_elements | 标准容器的最小不完整类型支持 | 201505L | <forward_list> <list> <vector> | (C++17)
__cpp_lib_int_pow2 | 整数的 2 的幂运算（ std::has_single_bit 、 std::bit_ceil 、 std::bit_floor 、 std::bit_length ） | 202002L | <bit> | (C++20)
__cpp_lib_integer_comparison_functions | 整数比较函数 | 202002L | <utility> | (C++20)
__cpp_lib_integer_sequence | 编译时整数序列 | 201304L | <utility> | (C++14)
__cpp_lib_integral_constant_callable | std::integral_constant::operator() | 201304L | <type_traits> | (C++14)
__cpp_lib_interpolate | std::lerp 与 std::midpoint | 201902L | <cmath> <numeric> | (C++20)
__cpp_lib_invoke | std::invoke() | 201411L | <functional> | (C++17)
__cpp_lib_invoke_r | std::invoke_r | 202106L | <functional> | (C++23)
__cpp_lib_is_aggregate | std::is_aggregate | 201703L | <type_traits> | (C++17)
__cpp_lib_is_constant_evaluated | std::is_constant_evaluated | 201811L | <type_traits> | (C++20)
__cpp_lib_is_final | std::is_final | 201402L | <type_traits> | (C++14)
__cpp_lib_is_invocable | std::is_invocable 、 std::invoke_result | 201703L | <type_traits> | (C++17)
__cpp_lib_is_layout_compatible | std::is_layout_compatible | 201907L | <type_traits> | (C++20)
__cpp_lib_is_nothrow_convertible | std::is_nothrow_convertible | 201806L | <type_traits> | (C++20)
__cpp_lib_is_null_pointer | std::is_null_pointer | 201309L | <type_traits> | (C++14)
__cpp_lib_is_pointer_interconvertible | 指针可互转换特征 | 201907L | <type_traits> | (C++20)
__cpp_lib_is_scoped_enum | std::is_scoped_enum | 202011L | <type_traits> | (C++23)
__cpp_lib_is_swappable | [nothrow-]swappable 特征 | 201603L | <type_traits> | (C++17)
__cpp_lib_jthread | 停止记号与结合线程 | 201911L | <stop_token> <thread> | (C++20)
__cpp_lib_latch | std::latch | 201907L | <latch> | (C++20)
__cpp_lib_launder | 核心问题 1776 ：替换含引用成员的类对象（ std::launder ） | 201606L | <new> | (C++17)
__cpp_lib_list_remove_return_type | 更改 std::forward_list 与 std::list remove() 、 remove_if() 及 unique() 成员的返回类型 | 201806L | <forward_list> <list> | (C++20)
__cpp_lib_logical_traits | 逻辑运算符类型特征 | 201510L | <type_traits> | (C++17)
__cpp_lib_make_from_tuple | std::make_from_tuple() | 201606L | <tuple> | (C++17)
__cpp_lib_make_reverse_iterator | std::make_reverse_iterator | 201402L | <iterator> | (C++14)
__cpp_lib_make_unique | std::make_unique | 201304L | <memory> | (C++14)
__cpp_lib_map_try_emplace | std::map::try_emplace, std::map::insert_or_assign | 201411L | <map> | (C++17)
__cpp_lib_math_constants | 数学常数 | 201907L | <numbers> | (C++20)
__cpp_lib_math_special_functions | C++17 的数学特殊函数 | 201603L | <cmath> | (C++17)
__cpp_lib_memory_resource | std::pmr::memory_resource | 201603L | <memory_resource> | (C++17)
__cpp_lib_monadic_optional | std::optional 中的单子操作 | 202110L | <optional> | (C++23)
__cpp_lib_move_only_function | std::move_only_function | 202110L | <functional> | (C++23)
__cpp_lib_node_extract | 拼接 map 与 set （ std::map::extract 、 std::map::merge 、 std::map::insert(node_type) 等） | 201606L | <map> <set> <unordered_map> <unordered_set> | (C++17)
__cpp_lib_nonmember_container_access | std::size() 、 std::data() 及 std::empty() | 201411L | <iterator> <array> <deque> <forward_list> <list> <map> <regex> <set> <string> <unordered_map> <unordered_set> <vector> | (C++17)
__cpp_lib_not_fn | std::not_fn() | 201603L | <functional> | (C++17)
__cpp_lib_null_iterators | 空老式向前迭代器 (LegacyForwardIterator) | 201304L | <iterator> | (C++14)
__cpp_lib_optional | std::optional | 201606L | <optional> | (C++17)
 | 完全 constexpr std::optional | 202106L | <optional> | (C++23)
__cpp_lib_out_ptr | std::out_ptr、 std::inout_ptr | 202106L | <memory> | (C++23)
__cpp_lib_parallel_algorithm | 并行算法 | 201603L | <algorithm> <numeric> | (C++17)
__cpp_lib_polymorphic_allocator | std::pmr::polymorphic_allocator<> 作为词汇类型 | 201902L | <memory_resource> | (C++20)
__cpp_lib_quoted_string_io | std::quoted | 201304L | <iomanip> | (C++14)
__cpp_lib_ranges | 范围库与受约束算法 | 201911L | <algorithm> <functional> <iterator> <memory> <ranges> | (C++20)
 | 不可默认初始化的视图 | 202106L |  | (C++23)
 | 带所有权的视图 | 202110L |  | (C++23)
__cpp_lib_ranges_starts_ends_with | std::ranges::starts_with、 std::ranges::ends_with | 202106L | <algorithm> | (C++23)
__cpp_lib_ranges_zip | std::ranges::zip_view、 std::ranges::zip_transform_view、 std::ranges::adjacent_view、 std::ranges::adjacent_transform_view | 202110L | <ranges> <tuple> <utility> | (C++23)
__cpp_lib_raw_memory_algorithms | 扩展内存管理工具 | 201606L | <memory> | (C++17)
__cpp_lib_remove_cvref | std::remove_cvref | 201711L | <type_traits> | (C++20)
__cpp_lib_result_of_sfinae | std::result_of 与 SFINAE | 201210L | <type_traits> <functional> | (C++14)
__cpp_lib_robust_nonmodifying_seq_ops | 使不修改序列的操作更稳健（ std::mismatch 、 std::equal 及 std::is_permutation 的双范围重载） | 201304L | <algorithm> | (C++14)
__cpp_lib_sample | std::sample | 201603L | <algorithm> | (C++17)
__cpp_lib_scoped_lock | std::scoped_lock | 201703L | <mutex> | (C++17)
__cpp_lib_semaphore | std::counting_semaphore 、 std::binary_semaphore | 201907L | <semaphore> | (C++20)
__cpp_lib_shared_mutex | std::shared_mutex （无时限） | 201505L | <shared_mutex> | (C++17)
__cpp_lib_shared_ptr_arrays | std::shared_ptr<T[]> | 201611L | <memory> | (C++17)
 | std::make_shared 的数组支持 | 201707L | <memory> | (C++20)
__cpp_lib_shared_ptr_weak_type | shared_ptr::weak_type | 201606L | <memory> | (C++17)
__cpp_lib_shared_timed_mutex | std::shared_timed_mutex | 201402L | <shared_mutex> | (C++14)
__cpp_lib_shift | std::shift_left 与 std::shift_right | 201806L | <algorithm> | (C++20)
__cpp_lib_smart_ptr_for_overwrite | 用默认初始化创建智能指针（ std::allocate_shared_for_overwrite 、 std::make_shared_for_overwrite 、 std::make_unique_for_overwrite ） | 201811L | <memory> | (C++20)
__cpp_lib_source_location | 源码信息捕获（ std::source_location ） | 201907L | <source_location> | (C++20)
__cpp_lib_span | std::span | 202002L | <span> | (C++20)
__cpp_lib_spanstream | std::spanbuf、 std::spanstream | 202106L | <spanstream> | (C++23)
__cpp_lib_ssize | std::ssize 与无符号的 std::span::size | 201902L | <iterator> | (C++20)
__cpp_lib_stacktrace | 栈踪库 | 202011L | <stacktrace> | (C++23)
__cpp_lib_starts_ends_with | 字符串前缀与后缀检查（ std::string 与 std::string_view 的 starts_with() 与 ends_with() ） | 201711L | <string> <string_view> | (C++20)
__cpp_lib_stdatomic_h | C 原子操作的兼容头文件 | 202011L | <stdatomic.h> | (C++23)
__cpp_lib_string_contains | std::basic_string 与 std::basic_string_view 的 contains 函数 | 202011L | <string> <string_view> | (C++23)
__cpp_lib_string_resize_and_overwrite | std::basic_string::resize_and_overwrite | 202110L | <string> | (C++23)
__cpp_lib_string_udls | 字符串类型的用户定义字面量 | 201304L | <string> | (C++14)
__cpp_lib_string_view | std::string_view | 201606L | <string> <string_view> | (C++17)
 | 常量表达式迭代器 (ConstexprIterator) | 201803L | <string> <string_view> | (C++20)
__cpp_lib_syncbuf | 同步缓冲的输出流（ std::syncbuf 、 std::osyncstream ）与操纵符 | 201803L | <syncstream> | (C++20)
__cpp_lib_three_way_comparison | 三路比较（库支持）；添加三路比较到标准库 | 201907L | <compare> | (C++20)
__cpp_lib_to_address | 转换指针为裸指针（ std::to_address ） | 201711L | <memory> | (C++20)
__cpp_lib_to_array | std::to_array | 201907L | <array> | (C++20)
__cpp_lib_to_chars | 初等字符串转换（ std::to_chars 、 std::from_chars ） | 201611L | <charconv> | (C++17)
__cpp_lib_to_underlying | std::to_underlying | 202102L | <utility> | (C++23)
__cpp_lib_transformation_trait_aliases | 变换特征的别名模板 | 201304L | <type_traits> | (C++14)
__cpp_lib_transparent_operators | 通透运算符函数对象（ std::less<> 等） | 201210L | <functional> | (C++14)
 | 通透的 std::owner_less （ std::owner_less<void> ） | 201510L | <memory> <functional> | (C++17)
__cpp_lib_tuple_element_t | std::tuple_element_t | 201402L | <tuple> | (C++14)
__cpp_lib_tuples_by_type | 按类型寻址 tuple | 201304L | <tuple> <utility> | (C++14)
__cpp_lib_type_identity | std::type_identity | 201806L | <type_traits> | (C++20)
__cpp_lib_type_trait_variable_templates | 类型特征变量模板（ std::is_void_v 等） | 201510L | <type_traits> | (C++17)
__cpp_lib_uncaught_exceptions | std::uncaught_exceptions | 201411L | <exception> | (C++17)
__cpp_lib_unordered_map_try_emplace | std::unordered_map::try_emplace 、 std::unordered_map::insert_or_assign | 201411L | <unordered_map> | (C++17)
__cpp_lib_unwrap_ref | std::unwrap_ref_decay 与 std::unwrap_reference | 201811L | <type_traits> | (C++20)
__cpp_lib_variant | std::variant ： C++17 的类型安全联合体 | 201606L | <variant> | (C++17)
 | std::variant 的派生类的 std::visit | 202102L | <variant> | (C++23)
 | 完全 constexpr std::variant | 202106L | <variant> | (C++23)
__cpp_lib_void_t | std::void_t | 201411L | <type_traits> | (C++17)

示例

正常使用

#ifdef __has_include                           // 检查 __has_include 是否存在
#  if __has_include(<optional>)                // 检查标准库
#    include <optional>
#  elif __has_include(<experimental/optional>) // 检查实验版本
#    include <experimental/optional>
#  elif __has_include(<boost/optional.hpp>)    // 尝试外部库
#    include <boost/optional.hpp>
#  else                                        // 完全找不到
#     error "Missing <optional>"
#  endif
#endif

#ifdef __has_cpp_attribute                      // 检查 __has_cpp_attribute 是否存在
#  if __has_cpp_attribute(deprecated)           // 检查一个属性
#    define DEPRECATED(msg) [[deprecated(msg)]]
#  endif
#endif
#ifndef DEPRECATED
#    define DEPRECATED(msg)
#endif

DEPRECATED("foo() has been deprecated") void foo();

#if __cpp_constexpr >= 201304                   // 检查功能特性的指定版本
#  define CONSTEXPR constexpr
#else
#  define CONSTEXPR inline
#endif

CONSTEXPR int bar(unsigned i)
{
#ifdef __cpp_binary_literals                    // 检查功能特性是否存在
    unsigned mask1 = 0b11000000;
    unsigned mask2 = 0b00000111;
#else
    unsigned mask1 = 0xA0;
    unsigned mask2 = 0x07;
#endif
    if ( i & mask1 )
        return 1;
    if ( i & mask2 )
        return 2;
    return 0;
}

int main()
{
}

编译器功能特性放出

以下示例放出 C++ 编译器功能特性与属性。

#if __cplusplus < 201100
#  error "C++11 or better is required"
#endif

#include <algorithm>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <string>

#ifdef __has_include
# if __has_include(<version>)
#   include <version>
# endif
#endif

#define COMPILER_FEATURE_VALUE(value) #value
#define COMPILER_FEATURE_ENTRY(name) { #name, COMPILER_FEATURE_VALUE(name) },

#ifdef __has_cpp_attribute
# define COMPILER_ATTRIBUTE_VALUE_AS_STRING(s) #s
# define COMPILER_ATTRIBUTE_AS_NUMBER(x) COMPILER_ATTRIBUTE_VALUE_AS_STRING(x)
# define COMPILER_ATTRIBUTE_ENTRY(attr) \
  { #attr, COMPILER_ATTRIBUTE_AS_NUMBER(__has_cpp_attribute(attr)) },
#else
# define COMPILER_ATTRIBUTE_ENTRY(attr) { #attr, "_" },
#endif

// 更改这些选项以仅打印所需的信息。
static struct PrintOptions {
    constexpr static bool titles               = 1;
    constexpr static bool attributes           = 1;
    constexpr static bool general_features     = 1;
    constexpr static bool core_features        = 1;
    constexpr static bool lib_features         = 1;
    constexpr static bool supported_features   = 1;
    constexpr static bool unsupported_features = 1;
    constexpr static bool sorted_by_value      = 0;
    constexpr static bool cxx11                = 1;
    constexpr static bool cxx14                = 1;
    constexpr static bool cxx17                = 1;
    constexpr static bool cxx20                = 1;
    constexpr static bool cxx23                = 1;
}   print;

struct CompilerFeature {
    CompilerFeature(const char* name = nullptr, const char* value = nullptr)
        : name(name), value(value) {}
    const char* name; const char* value;
};

static CompilerFeature cxx[] = {
COMPILER_FEATURE_ENTRY(__cplusplus)
COMPILER_FEATURE_ENTRY(__cpp_exceptions)
COMPILER_FEATURE_ENTRY(__cpp_rtti)
#if 0
COMPILER_FEATURE_ENTRY(__GNUC__)
COMPILER_FEATURE_ENTRY(__GNUC_MINOR__)
COMPILER_FEATURE_ENTRY(__GNUC_PATCHLEVEL__)
COMPILER_FEATURE_ENTRY(__GNUG__)
COMPILER_FEATURE_ENTRY(__clang__)
COMPILER_FEATURE_ENTRY(__clang_major__)
COMPILER_FEATURE_ENTRY(__clang_minor__)
COMPILER_FEATURE_ENTRY(__clang_patchlevel__)
#endif
};
static CompilerFeature cxx11[] = {
COMPILER_FEATURE_ENTRY(__cpp_alias_templates)
COMPILER_FEATURE_ENTRY(__cpp_attributes)
COMPILER_FEATURE_ENTRY(__cpp_constexpr)
COMPILER_FEATURE_ENTRY(__cpp_decltype)
COMPILER_FEATURE_ENTRY(__cpp_delegating_constructors)
COMPILER_FEATURE_ENTRY(__cpp_inheriting_constructors)
COMPILER_FEATURE_ENTRY(__cpp_initializer_lists)
COMPILER_FEATURE_ENTRY(__cpp_lambdas)
COMPILER_FEATURE_ENTRY(__cpp_nsdmi)
COMPILER_FEATURE_ENTRY(__cpp_range_based_for)
COMPILER_FEATURE_ENTRY(__cpp_raw_strings)
COMPILER_FEATURE_ENTRY(__cpp_ref_qualifiers)
COMPILER_FEATURE_ENTRY(__cpp_rvalue_references)
COMPILER_FEATURE_ENTRY(__cpp_static_assert)
COMPILER_FEATURE_ENTRY(__cpp_threadsafe_static_init)
COMPILER_FEATURE_ENTRY(__cpp_unicode_characters)
COMPILER_FEATURE_ENTRY(__cpp_unicode_literals)
COMPILER_FEATURE_ENTRY(__cpp_user_defined_literals)
COMPILER_FEATURE_ENTRY(__cpp_variadic_templates)
};
static CompilerFeature cxx14[] = {
COMPILER_FEATURE_ENTRY(__cpp_aggregate_nsdmi)
COMPILER_FEATURE_ENTRY(__cpp_binary_literals)
COMPILER_FEATURE_ENTRY(__cpp_constexpr)
COMPILER_FEATURE_ENTRY(__cpp_decltype_auto)
COMPILER_FEATURE_ENTRY(__cpp_generic_lambdas)
COMPILER_FEATURE_ENTRY(__cpp_init_captures)
COMPILER_FEATURE_ENTRY(__cpp_return_type_deduction)
COMPILER_FEATURE_ENTRY(__cpp_sized_deallocation)
COMPILER_FEATURE_ENTRY(__cpp_variable_templates)
};
static CompilerFeature cxx14lib[] = {
COMPILER_FEATURE_ENTRY(__cpp_lib_chrono_udls)
COMPILER_FEATURE_ENTRY(__cpp_lib_complex_udls)
COMPILER_FEATURE_ENTRY(__cpp_lib_exchange_function)
COMPILER_FEATURE_ENTRY(__cpp_lib_generic_associative_lookup)
COMPILER_FEATURE_ENTRY(__cpp_lib_integer_sequence)
COMPILER_FEATURE_ENTRY(__cpp_lib_integral_constant_callable)
COMPILER_FEATURE_ENTRY(__cpp_lib_is_final)
COMPILER_FEATURE_ENTRY(__cpp_lib_is_null_pointer)
COMPILER_FEATURE_ENTRY(__cpp_lib_make_reverse_iterator)
COMPILER_FEATURE_ENTRY(__cpp_lib_make_unique)
COMPILER_FEATURE_ENTRY(__cpp_lib_null_iterators)
COMPILER_FEATURE_ENTRY(__cpp_lib_quoted_string_io)
COMPILER_FEATURE_ENTRY(__cpp_lib_result_of_sfinae)
COMPILER_FEATURE_ENTRY(__cpp_lib_robust_nonmodifying_seq_ops)
COMPILER_FEATURE_ENTRY(__cpp_lib_shared_timed_mutex)
COMPILER_FEATURE_ENTRY(__cpp_lib_string_udls)
COMPILER_FEATURE_ENTRY(__cpp_lib_transformation_trait_aliases)
COMPILER_FEATURE_ENTRY(__cpp_lib_transparent_operators)
COMPILER_FEATURE_ENTRY(__cpp_lib_tuple_element_t)
COMPILER_FEATURE_ENTRY(__cpp_lib_tuples_by_type)
};

static CompilerFeature cxx17[] = {
COMPILER_FEATURE_ENTRY(__cpp_aggregate_bases)
COMPILER_FEATURE_ENTRY(__cpp_aligned_new)
COMPILER_FEATURE_ENTRY(__cpp_capture_star_this)
COMPILER_FEATURE_ENTRY(__cpp_constexpr)
COMPILER_FEATURE_ENTRY(__cpp_deduction_guides)
COMPILER_FEATURE_ENTRY(__cpp_enumerator_attributes)
COMPILER_FEATURE_ENTRY(__cpp_fold_expressions)
COMPILER_FEATURE_ENTRY(__cpp_guaranteed_copy_elision)
COMPILER_FEATURE_ENTRY(__cpp_hex_float)
COMPILER_FEATURE_ENTRY(__cpp_if_constexpr)
COMPILER_FEATURE_ENTRY(__cpp_inheriting_constructors)
COMPILER_FEATURE_ENTRY(__cpp_inline_variables)
COMPILER_FEATURE_ENTRY(__cpp_namespace_attributes)
COMPILER_FEATURE_ENTRY(__cpp_noexcept_function_type)
COMPILER_FEATURE_ENTRY(__cpp_nontype_template_args)
COMPILER_FEATURE_ENTRY(__cpp_nontype_template_parameter_auto)
COMPILER_FEATURE_ENTRY(__cpp_range_based_for)
COMPILER_FEATURE_ENTRY(__cpp_static_assert)
COMPILER_FEATURE_ENTRY(__cpp_structured_bindings)
COMPILER_FEATURE_ENTRY(__cpp_template_template_args)
COMPILER_FEATURE_ENTRY(__cpp_variadic_using)
};
static CompilerFeature cxx17lib[] = {
COMPILER_FEATURE_ENTRY(__cpp_lib_addressof_constexpr)
COMPILER_FEATURE_ENTRY(__cpp_lib_allocator_traits_is_always_equal)
COMPILER_FEATURE_ENTRY(__cpp_lib_any)
COMPILER_FEATURE_ENTRY(__cpp_lib_apply)
COMPILER_FEATURE_ENTRY(__cpp_lib_array_constexpr)
COMPILER_FEATURE_ENTRY(__cpp_lib_as_const)
COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_is_always_lock_free)
COMPILER_FEATURE_ENTRY(__cpp_lib_bool_constant)
COMPILER_FEATURE_ENTRY(__cpp_lib_boyer_moore_searcher)
COMPILER_FEATURE_ENTRY(__cpp_lib_byte)
COMPILER_FEATURE_ENTRY(__cpp_lib_chrono)
COMPILER_FEATURE_ENTRY(__cpp_lib_clamp)
COMPILER_FEATURE_ENTRY(__cpp_lib_enable_shared_from_this)
COMPILER_FEATURE_ENTRY(__cpp_lib_execution)
COMPILER_FEATURE_ENTRY(__cpp_lib_filesystem)
COMPILER_FEATURE_ENTRY(__cpp_lib_gcd_lcm)
COMPILER_FEATURE_ENTRY(__cpp_lib_hardware_interference_size)
COMPILER_FEATURE_ENTRY(__cpp_lib_has_unique_object_representations)
COMPILER_FEATURE_ENTRY(__cpp_lib_hypot)
COMPILER_FEATURE_ENTRY(__cpp_lib_incomplete_container_elements)
COMPILER_FEATURE_ENTRY(__cpp_lib_invoke)
COMPILER_FEATURE_ENTRY(__cpp_lib_is_aggregate)
COMPILER_FEATURE_ENTRY(__cpp_lib_is_invocable)
COMPILER_FEATURE_ENTRY(__cpp_lib_is_swappable)
COMPILER_FEATURE_ENTRY(__cpp_lib_launder)
COMPILER_FEATURE_ENTRY(__cpp_lib_logical_traits)
COMPILER_FEATURE_ENTRY(__cpp_lib_make_from_tuple)
COMPILER_FEATURE_ENTRY(__cpp_lib_map_try_emplace)
COMPILER_FEATURE_ENTRY(__cpp_lib_math_special_functions)
COMPILER_FEATURE_ENTRY(__cpp_lib_memory_resource)
COMPILER_FEATURE_ENTRY(__cpp_lib_node_extract)
COMPILER_FEATURE_ENTRY(__cpp_lib_nonmember_container_access)
COMPILER_FEATURE_ENTRY(__cpp_lib_not_fn)
COMPILER_FEATURE_ENTRY(__cpp_lib_optional)
COMPILER_FEATURE_ENTRY(__cpp_lib_parallel_algorithm)
COMPILER_FEATURE_ENTRY(__cpp_lib_raw_memory_algorithms)
COMPILER_FEATURE_ENTRY(__cpp_lib_sample)
COMPILER_FEATURE_ENTRY(__cpp_lib_scoped_lock)
COMPILER_FEATURE_ENTRY(__cpp_lib_shared_mutex)
COMPILER_FEATURE_ENTRY(__cpp_lib_shared_ptr_arrays)
COMPILER_FEATURE_ENTRY(__cpp_lib_shared_ptr_weak_type)
COMPILER_FEATURE_ENTRY(__cpp_lib_string_view)
COMPILER_FEATURE_ENTRY(__cpp_lib_to_chars)
COMPILER_FEATURE_ENTRY(__cpp_lib_transparent_operators)
COMPILER_FEATURE_ENTRY(__cpp_lib_type_trait_variable_templates)
COMPILER_FEATURE_ENTRY(__cpp_lib_uncaught_exceptions)
COMPILER_FEATURE_ENTRY(__cpp_lib_unordered_map_try_emplace)
COMPILER_FEATURE_ENTRY(__cpp_lib_variant)
COMPILER_FEATURE_ENTRY(__cpp_lib_void_t)
};

static CompilerFeature cxx20[] = {
COMPILER_FEATURE_ENTRY(__cpp_aggregate_paren_init)
COMPILER_FEATURE_ENTRY(__cpp_char8_t)
COMPILER_FEATURE_ENTRY(__cpp_concepts)
COMPILER_FEATURE_ENTRY(__cpp_conditional_explicit)
COMPILER_FEATURE_ENTRY(__cpp_consteval)
COMPILER_FEATURE_ENTRY(__cpp_constexpr)
COMPILER_FEATURE_ENTRY(__cpp_constexpr_dynamic_alloc)
COMPILER_FEATURE_ENTRY(__cpp_constexpr_in_decltype)
COMPILER_FEATURE_ENTRY(__cpp_constinit)
COMPILER_FEATURE_ENTRY(__cpp_deduction_guides)
COMPILER_FEATURE_ENTRY(__cpp_designated_initializers)
COMPILER_FEATURE_ENTRY(__cpp_generic_lambdas)
COMPILER_FEATURE_ENTRY(__cpp_impl_coroutine)
COMPILER_FEATURE_ENTRY(__cpp_impl_destroying_delete)
COMPILER_FEATURE_ENTRY(__cpp_impl_three_way_comparison)
COMPILER_FEATURE_ENTRY(__cpp_init_captures)
COMPILER_FEATURE_ENTRY(__cpp_modules)
COMPILER_FEATURE_ENTRY(__cpp_nontype_template_args)
COMPILER_FEATURE_ENTRY(__cpp_using_enum)
};
static CompilerFeature cxx20lib[] = {
COMPILER_FEATURE_ENTRY(__cpp_lib_array_constexpr)
COMPILER_FEATURE_ENTRY(__cpp_lib_assume_aligned)
COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_flag_test)
COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_float)
COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_lock_free_type_aliases)
COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_ref)
COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_shared_ptr)
COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_value_initialization)
COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_wait)
COMPILER_FEATURE_ENTRY(__cpp_lib_barrier)
COMPILER_FEATURE_ENTRY(__cpp_lib_bind_front)
COMPILER_FEATURE_ENTRY(__cpp_lib_bit_cast)
COMPILER_FEATURE_ENTRY(__cpp_lib_bitops)
COMPILER_FEATURE_ENTRY(__cpp_lib_bounded_array_traits)
COMPILER_FEATURE_ENTRY(__cpp_lib_char8_t)
COMPILER_FEATURE_ENTRY(__cpp_lib_chrono)
COMPILER_FEATURE_ENTRY(__cpp_lib_concepts)
COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_algorithms)
COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_complex)
COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_dynamic_alloc)
COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_functional)
COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_iterator)
COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_memory)
COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_numeric)
COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_string)
COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_string_view)
COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_tuple)
COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_utility)
COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_vector)
COMPILER_FEATURE_ENTRY(__cpp_lib_coroutine)
COMPILER_FEATURE_ENTRY(__cpp_lib_destroying_delete)
COMPILER_FEATURE_ENTRY(__cpp_lib_endian)
COMPILER_FEATURE_ENTRY(__cpp_lib_erase_if)
COMPILER_FEATURE_ENTRY(__cpp_lib_execution)
COMPILER_FEATURE_ENTRY(__cpp_lib_format)
COMPILER_FEATURE_ENTRY(__cpp_lib_generic_unordered_lookup)
COMPILER_FEATURE_ENTRY(__cpp_lib_int_pow2)
COMPILER_FEATURE_ENTRY(__cpp_lib_integer_comparison_functions)
COMPILER_FEATURE_ENTRY(__cpp_lib_interpolate)
COMPILER_FEATURE_ENTRY(__cpp_lib_is_constant_evaluated)
COMPILER_FEATURE_ENTRY(__cpp_lib_is_layout_compatible)
COMPILER_FEATURE_ENTRY(__cpp_lib_is_nothrow_convertible)
COMPILER_FEATURE_ENTRY(__cpp_lib_is_pointer_interconvertible)
COMPILER_FEATURE_ENTRY(__cpp_lib_jthread)
COMPILER_FEATURE_ENTRY(__cpp_lib_latch)
COMPILER_FEATURE_ENTRY(__cpp_lib_list_remove_return_type)
COMPILER_FEATURE_ENTRY(__cpp_lib_math_constants)
COMPILER_FEATURE_ENTRY(__cpp_lib_polymorphic_allocator)
COMPILER_FEATURE_ENTRY(__cpp_lib_ranges)
COMPILER_FEATURE_ENTRY(__cpp_lib_remove_cvref)
COMPILER_FEATURE_ENTRY(__cpp_lib_semaphore)
COMPILER_FEATURE_ENTRY(__cpp_lib_shared_ptr_arrays)
COMPILER_FEATURE_ENTRY(__cpp_lib_shift)
COMPILER_FEATURE_ENTRY(__cpp_lib_smart_ptr_for_overwrite)
COMPILER_FEATURE_ENTRY(__cpp_lib_source_location)
COMPILER_FEATURE_ENTRY(__cpp_lib_span)
COMPILER_FEATURE_ENTRY(__cpp_lib_ssize)
COMPILER_FEATURE_ENTRY(__cpp_lib_starts_ends_with)
COMPILER_FEATURE_ENTRY(__cpp_lib_string_view)
COMPILER_FEATURE_ENTRY(__cpp_lib_syncbuf)
COMPILER_FEATURE_ENTRY(__cpp_lib_three_way_comparison)
COMPILER_FEATURE_ENTRY(__cpp_lib_to_address)
COMPILER_FEATURE_ENTRY(__cpp_lib_to_array)
COMPILER_FEATURE_ENTRY(__cpp_lib_type_identity)
COMPILER_FEATURE_ENTRY(__cpp_lib_unwrap_ref)
};

static CompilerFeature cxx23[] = {
//< 继续填充
COMPILER_FEATURE_ENTRY(__cpp_if_consteval)
COMPILER_FEATURE_ENTRY(__cpp_size_t_suffix)
};
static CompilerFeature cxx23lib[] = {
//< 继续填充
COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_typeinfo)
COMPILER_FEATURE_ENTRY(__cpp_lib_invoke_r)
COMPILER_FEATURE_ENTRY(__cpp_lib_is_scoped_enum)
COMPILER_FEATURE_ENTRY(__cpp_lib_stacktrace)
COMPILER_FEATURE_ENTRY(__cpp_lib_stdatomic_h)
COMPILER_FEATURE_ENTRY(__cpp_lib_string_contains)
COMPILER_FEATURE_ENTRY(__cpp_lib_to_underlying)
COMPILER_FEATURE_ENTRY(__cpp_lib_variant)
};

static CompilerFeature attributes[] = {
COMPILER_ATTRIBUTE_ENTRY(carries_dependency)
COMPILER_ATTRIBUTE_ENTRY(deprecated)
COMPILER_ATTRIBUTE_ENTRY(fallthrough)
COMPILER_ATTRIBUTE_ENTRY(likely)
COMPILER_ATTRIBUTE_ENTRY(maybe_unused)
COMPILER_ATTRIBUTE_ENTRY(nodiscard)
COMPILER_ATTRIBUTE_ENTRY(noreturn)
COMPILER_ATTRIBUTE_ENTRY(no_unique_address)
COMPILER_ATTRIBUTE_ENTRY(unlikely)
};

constexpr bool is_feature_supported(const CompilerFeature& x) {
    return x.value[0] != '_' && x.value[0] != '0' ;
}

inline void print_compiler_feature(const CompilerFeature& x) {
    constexpr static int max_name_length = 44; //< Update if necessary
    std::string value{ is_feature_supported(x) ? x.value : "------" };
    if (value.back() == 'L') value.pop_back(); //~ 201603L -> 201603
    // value.insert(4, 1, '-'); //~ 201603 -> 2016-03
    if ( (print.supported_features && is_feature_supported(x))
        or (print.unsupported_features && !is_feature_supported(x))) {
            std::cout << std::left << std::setw(max_name_length)
                      << x.name << " " << value << '\n';
    }
}

template<std::size_t N>
inline void show(char const* title, CompilerFeature (&features)[N]) {
    if (print.titles) {
        std::cout << '\n' << std::left << title << '\n';
    }
    if (print.sorted_by_value) {
        std::sort(std::begin(features), std::end(features),
            [](CompilerFeature const& lhs, CompilerFeature const& rhs) {
                return std::strcmp(lhs.value, rhs.value) < 0;
            });
    }
    for (const CompilerFeature& x : features) {
        print_compiler_feature(x);
    }
}

int main() {
    if (print.general_features) show("C++ GENERAL", cxx);
    if (print.cxx11 && print.core_features) show("C++11 CORE", cxx11);
    if (print.cxx14 && print.core_features) show("C++14 CORE", cxx14);
    if (print.cxx14 && print.lib_features ) show("C++14 LIB" , cxx14lib);
    if (print.cxx17 && print.core_features) show("C++17 CORE", cxx17);
    if (print.cxx17 && print.lib_features ) show("C++17 LIB" , cxx17lib);
    if (print.cxx20 && print.core_features) show("C++20 CORE", cxx20);
    if (print.cxx20 && print.lib_features ) show("C++20 LIB" , cxx20lib);
    if (print.cxx23 && print.core_features) show("C++23 CORE", cxx23);
    if (print.cxx23 && print.lib_features ) show("C++23 LIB" , cxx23lib);
    if (print.attributes) show("ATTRIBUTES", attributes);
}

可能的输出：

C++ GENERAL
__cplusplus                                  202002
__cpp_exceptions                             199711
__cpp_rtti                                   199711

C++11 CORE
__cpp_alias_templates                        200704
__cpp_attributes                             200809
__cpp_constexpr                              201907
__cpp_decltype                               200707
__cpp_delegating_constructors                200604
__cpp_inheriting_constructors                201511
__cpp_initializer_lists                      200806
__cpp_lambdas                                200907
__cpp_nsdmi                                  200809
__cpp_range_based_for                        201603
__cpp_raw_strings                            200710
__cpp_ref_qualifiers                         200710
__cpp_rvalue_references                      200610
__cpp_static_assert                          201411
__cpp_threadsafe_static_init                 200806
__cpp_unicode_characters                     200704
__cpp_unicode_literals                       200710
__cpp_user_defined_literals                  200809
__cpp_variadic_templates                     200704

C++14 CORE
__cpp_aggregate_nsdmi                        201304
__cpp_binary_literals                        201304
__cpp_constexpr                              201907
__cpp_decltype_auto                          201304
__cpp_generic_lambdas                        201707
__cpp_init_captures                          201803
__cpp_return_type_deduction                  201304
__cpp_sized_deallocation                     ------
__cpp_variable_templates                     201304

... truncated ...

参阅

  • 库功能特性测试宏 (C++20) 定义于 <version>
  • 特性测试推荐的官方文档
  • 试出编译器特性的源码


文件系统库

< cpp

文件系统库提供在文件系统与其组件，例如路径、常规文件与目录上进行操作的设施。

文件系统库原作为 boost.filesystem 开发，出版为技术规范 ISO/IEC TS 18822:2015 ，并最终从 C++17 开始并入 ISO C++ 。现在 boost 实现可用的编译器和平台于多于 C++17 库。

若层级文件系统不能为实现所访问，或若它不提供必要的兼容性，则文件系统库设施可能不可用。若底层文件系统不支持，则一些特性可能不可用（例如 FAT 文件系统缺少符号链接并禁止多重硬链接）。这些情况下必须报告错误。

若对此库的函数的调用引入文件系统竞争，即多个线程、进程或计算机交错地访问并修改文件系统中的同一对象，则行为未定义。

库范畴定义

  • 文件：持有数据的文件系统对象，能被写入或读取，或二者皆可。文件拥有名称及属性，属性之一是文件类型：
  • 目录：表现为目录条目的容器的文件，目录条目标识其他文件（其中一些可以是另外的嵌套的目录）。讨论到具体文件时，包含该文件目录条目的目录是其父目录。父目录能以相对路径名 ".." 表示。
  • 硬链接：关联一个名字到一个既存文件的目录条目。若支持多重硬链接，则文件在最后一个到它的硬链接被移除后才被移除。
  • 符号链接：关联一个名词到一个路径的目录条目，路径可以存在亦可不存在。
  • 常规文件：不是其他文件类型的文件。
  • 文件名：命名一个文件的字符串。容许字符、大小写区别、最大长度以及被禁止名称是实现定义的。名称 "." （点）与 ".." （双点）在库层次拥有特殊含义。
  • 路径：标识一个文件的元素序列。它以可选的 根名 （例如 Windows 上的 "C:" 或 "//server" ）开始，后随可选的 根目录 （例如 Unix 上的 "/" ），后随零或更多个文件名（除了最后一个都必须是目录或到目录的链接）的序列。表示路径的字符串（路径名）的原生格式（如哪些字符被用作分隔符）与字符编码是实现定义的，库提供路径的可移植表示。
  • 绝对路径：无歧义地标识一个文件位置的路径。
  • 规范路径：不包含符号链接、 "." 或 ".." 元素的绝对路径。
  • 相对路径：标识相对于文件系统中某位置的文件位置的路径。特殊路径名 "." （点，“当前目录”）和 ".." （双点、“父目录”）是相对路径。

类
定义于头文件 <filesystem>
定义于命名空间 std::filesystem
path
(C++17)
 表示路径
(类)
filesystem_error
(C++17)
 文件系统错误时抛出的异常
(类)
directory_entry
(C++17)
 目录条目
(类)
directory_iterator
(C++17)
 指向目录内容的迭代器
(类)
recursive_directory_iterator
(C++17)
 指向一个目录及其子目录的内容的迭代器
(类)
file_status
(C++17)
 表示文件类型及权限
(类)
space_info
(C++17)
 关于文件系统上空闲及可用空间的信息
(类)
file_type
(C++17)
 文件的类型
(枚举)
perms
(C++17)
 标识文件系统权限
(枚举)
perm_options
(C++17)
 指定权限操作的语义
(枚举)
copy_options
(C++17)
 指定复制操作的语义
(枚举)
directory_options
(C++17)
 用于迭代目录内容的选项
(枚举)
file_time_type
(C++17)
 表示文件时间值
(typedef)

非成员函数
定义于头文件 <filesystem>
定义于命名空间 std::filesystem
absolute
(C++17)
 组成一个绝对路径
(函数)
canonicalweakly_canonical
(C++17)
 组成一个规范路径
(函数)
relativeproximate
(C++17)
 组成一个相对路径
(函数)
copy
(C++17)
 复制文件或目录
(函数)
copy_file
(C++17)
 复制文件内容
(函数)
copy_symlink
(C++17)
 复制一个符号链接
(函数)
create_directorycreate_directories
(C++17)(C++17)
 创建新目录
(函数)
create_hard_link
(C++17)
 创建一个硬链接
(函数)
create_symlinkcreate_directory_symlink
(C++17)(C++17)
 创建一个符号链接
(函数)
current_path
(C++17)
 返回或设置当前工作目录
(函数)
exists
(C++17)
 检查路径是否指代既存的文件系统对象
(函数)
equivalent
(C++17)
 检查两个路径是否指代同一文件系统对象
(函数)
file_size
(C++17)
 返回文件的大小
(函数)
hard_link_count
(C++17)
 返回指代特定文件的硬链接数
(函数)
last_write_time
(C++17)
 获取或设置最近一次数据修改的时间
(函数)
permissions
(C++17)
 修改文件访问权限
(函数)
read_symlink
(C++17)
 获得符号链接的目标
(函数)
removeremove_all
(C++17)(C++17)
 移除一个文件或空目录
移除一个文件或递归地移除一个目录及其所有内容
(函数)
rename
(C++17)
 移动或重命名一个文件或目录
(函数)
resize_file
(C++17)
 以截断或填充零更改一个常规文件的大小
(函数)
space
(C++17)
 确定文件系统上的可用空闲空间
(函数)
statussymlink_status
(C++17)(C++17)
 确定文件属性
确定文件属性，检查符号链接目标
(函数)
temp_directory_path
(C++17)
 返回一个适用于临时文件的目录
(函数)
文件类型
is_block_file
(C++17)
 检查给定的路径是否表示块设备
(函数)
is_character_file
(C++17)
 检查给定的路径是否表示字符设备
(函数)
is_directory
(C++17)
 检查给定的路径是否表示一个目录
(函数)
is_empty
(C++17)
 检查给定的路径是否表示一个空文件或空目录
(函数)
is_fifo
(C++17)
 检查给定的路径是否表示一个命名管道
(函数)
is_other
(C++17)
 检查参数是否表示一个其他文件
(函数)
is_regular_file
(C++17)
 检查参数是否表示一个常规文件
(函数)
is_socket
(C++17)
 检查参数是否表示一个具名 IPC 套接字
(函数)
is_symlink
(C++17)
 检查参数是否表示一个符号链接
(函数)
status_known
(C++17)
 检查文件状态是否已知
(函数)

注解

使用此库可能要求额外的编译器/链接器选项。 9.1 前的 GNU 实现要求用 -lstdc++fs 链接，而 LLVM 9.0 前的 LLVM 实现要求用 -lc++fs 链接。

参阅


std::filesystem::absolute

< cpp‎ | filesystem
定义于头文件 <filesystem>
path absolute(const std::filesystem::path & p);
path absolute(const std::filesystem::path & p, std::error_code & ec);
 (1) (C++17 起)

返回与 p 引用同一文件系统位置的路径，满足 is_absolute() 为 true 。不抛出重载在错误时返回默认构造的路径。

参数

p | - | 要转换成绝对形式的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

返回与 p 引用同一文件的绝对（尽管不必规范）路径名

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

鼓励实现认为 p 不存在不是错误。

对于基于 POSIX 的操作系统， std::filesystem::absolute(p) 等价于 std::filesystem::current_path () / p

对于 Windows ， absolute 可以实现为对 GetFullPathNameW 的调用。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    fs::path p = "C:cl.exe";
    std::cout << "Current path is " << fs::current_path() << '\n'
              << "Absolute path for " << p << " is " << fs::absolute(p) << '\n';
// 实际位置： "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\cl.exe"
}

可能的输出：

Current path is "D:/local/ConsoleApplication1"
Absolute path for "C:cl.exe" is "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\cl.exe"

参阅

canonicalweakly_canonical (C++17) | 组成一个规范路径 (函数)
relativeproximate (C++17) | 组成一个相对路径 (函数)


std::filesystem::canonical, std::filesystem::weakly_canonical

< cpp‎ | filesystem
定义于头文件 <filesystem>
path canonical( const std::filesystem::path & p,
const std::filesystem::path & base = std::filesystem::current_path () );
 (1) (C++17 起)
path canonical( const std::filesystem::path & p,
std::error_code & ec );
 (2) (C++17 起)
path canonical( const std::filesystem::path & p,

const std::filesystem::path & base,

std::error_code & ec );
 (3) (C++17 起)
path weakly_canonical(const std::filesystem::path & p);
 (4) (C++17 起)
path weakly_canonical(const std::filesystem::path & p,
std::error_code & ec);
 (5) (C++17 起)
1-3) 转换路径 p 为规范绝对路径，即在其通用格式表示中无点、双点元素或符号链接的绝对路径。若 p 不是绝对路径，则该函数表现为首先用 absolute(p, base) 或对于 (2) 则是 absolute(p) ，将它设为绝对。路径 p 必须存在。
4-5) 返回由 operator/= 从不带 base 参数调用 canonical() 的结果，和以由 p 的存在的前导元素（如以 status(p) 或 status(p, ec) 确定），若有这些，后随 p 的不存在元素组成，若有这些，组成的路径。产生的路径为正常形式。

参数

p | - | 可以为绝对或相对于 base 的路径；对于 canonical 必须是存在的路径
base | - | 用于 p 为相对的情形的基础路径
ec | - | 存储错误状态的错误码

返回值

1-3) 解析到与 absolute(p, base) 为相同文件的绝对路径（或对于 (2) 与 absolute(p) 相同）。
4-5) canonical(x)/y 形式的正常路径，其中 x 是由 p 中存在的元素的最长前导序列组成的路径，而 y 是由 p 中剩余尾随的不存在元素组成的路径

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p，第二 path 参数 base 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

函数 canonical() 模仿 POSIX realpath 。

引入函数 weakly_canonical() 以简化 relative() 的操作语义。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    fs::path p = fs::path("..") / ".." / "AppData";
    std::cout << "Current path is " << fs::current_path() << '\n'
              << "Canonical path for " << p << " is " << canonical(p) << '\n';
}

可能的输出：

Current path is "C:\Users\abcdef\AppData\Local\Temp"
Canonical path for "..\..\AppData" is "C:\Users\abcdef\AppData"

参阅

path (C++17) | 表示路径 (类)
absolute (C++17) | 组成一个绝对路径 (函数)
relativeproximate (C++17) | 组成一个相对路径 (函数)


std::filesystem::copy

< cpp‎ | filesystem
定义于头文件 <filesystem>
void copy( const std::filesystem::path & from,

const std::filesystem::path & to );
void copy( const std::filesystem::path & from,
const std::filesystem::path & to,

std::error_code & ec );
 (1) (C++17 起)
void copy( const std::filesystem::path & from,

const std::filesystem::path & to,
std::filesystem::copy_options options );
void copy( const std::filesystem::path & from,
const std::filesystem::path & to,
std::filesystem::copy_options options,

std::error_code & ec );
 (2) (C++17 起)

复制文件与目录，带一些选项

1) 默认，等价于以 copy_options::none 为选项的 (2)
2) 复制文件或目录 from 到文件或目录 to ，使用 options 所指定的复制选项。若 options 中存在 copy_options 任一选项组中多于一个的选项（即使在无关乎 copy 的 copy_file 组中）

行为如下：

  • 首先，在做任何事前，以对下列之一者不多于一次的调用，获得 from 的类型与权限
  • 调用 std::filesystem::symlink_status ，若 copy_options::skip_symlinks 、 copy_options::copy_symlinks 或 copy_options::create_symlinks 存在于 options ；
  • 否则调用 std::filesystem::status 。
  • 若需要，则以对下列之一者不多于一次的调用，获取 to 的状态
  • 若 copy_options::skip_symlinks 或 copy_options::create_symlinks 存在于 options ，则调用 std::filesystem::symlink_status ；
  • 否则调用 std::filesystem::status （包括 copy_options::copy_symlinks 存在于 options 的情况）。
  • 若 from 或 to 拥有实现定义的文件类型，则此函数的效果是实现定义的。
  • 若 from 不存在，则报告错误。
  • 若 from 与 to 是如 std::filesystem::equivalent 所确定的同一文件，则报告错误
  • 若 from 或 to 不是常规文件、目录或符号链接，如 std::filesystem::is_other 所确定，则报告错误
  • 若 from 是目录，但 to 是常规文件，则报告错误
  • 若 from 是符号链接，则
  • 若 copy_options::skip_symlink 存在于 options ，则不做任何事。
  • 否则，若 to 不存在且 copy_options::copy_symlinks 存在于 options ，则表现如同 copy_symlink(from, to)
  • 否则，报告错误
  • 否则，若 from 是常规文件，则
  • 若 copy_options::directories_only 存在于 options ，则不做任何事
  • 否则，若 copy_options::create_symlinks 存在于 options ，则创建到 to 的符号链接。注意： from 必须是绝对路径，除非 to 在当前目录中。
  • 否则，若 copy_options::create_hard_links 存在于 options ，则创建到 to 的硬链接
  • 否则，若 to 是目录，则表现如同 copy_file(from, to/from.filename(), options) （创建 from 的副本，作为 to 目录中的文件）
  • 否则，表现如同 copy_file(from, to, options) （复制文件）
  • 否则，若 from 是目录而 options 中设置了 copy_options::create_symlinks ，则以等于 std::make_error_code( std::errc::is_a_directory ) 的错误码报告错误。
  • 否则，若 from 是目录且 options 拥有 copy_options::recursive 或是 copy_options::none ，则
  • 若 to 不存在，则首先执行 create_directory(to, from) （创建拥有旧目录属性副本的新目录）
  • 然后，不管 to 已存在还是刚被创建，在 from 所含有的文件上迭代，如同用 for (const std::filesystem::directory_entry & x : std::filesystem::directory_iterator (from)) ，并对于每个目录入口，递归地调用 copy(x.path(), to/x.path().filename(), options | in-recursive-copy) ，其中 in-recursive-copy 是于 options 设置时无其他效果的特殊位。（设置此位的独有目的是若 options 为 copy_options::none 则阻止递归复制子目录）
  • 否则不做任何事。

参数

from | - | 源文件、目录或符号链接的路径
to | - | 目标文件、目录或符号链接的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

（无）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 from，第二 path 参数 to 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注解

复制目录时的默认行为是非递归复制：复制文件，但不复制子目录：

// 给定
// /dir1 含有 /dir1/file1 、 /dir1/file2 、 /dir1/dir2
// 而 /dir1/dir2 含有 /dir1/dir2/file3
std::filesystem::copy("/dir1", "/dir3");
// 之后
// 创建 /dir3 （拥有 /dir1 的属性）
// /dir1/file1 被复制到 /dir3/file1
// /dir1/file2 被复制到 /dir3/file2

而带有 copy_options::recursive 时，亦复制子目录，递归地带有其内容。

// ……但在下一句后
std::filesystem::copy("/dir1", "/dir3", std::filesystem::copy_options::recursive);
// 创建 /dir3 （拥有 /dir1 的属性）
// /dir1/file1 被复制到 /dir3/file1
// /dir1/file2 被复制到 /dir3/file2
// 创建 /dir3/dir2 （拥有 /dir1/dir2 的属性）
// /dir1/dir2/file3 被复制到 /dir3/dir2/file3

示例

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    fs::create_directories("sandbox/dir/subdir");
    std::ofstream("sandbox/file1.txt").put('a');
    fs::copy("sandbox/file1.txt", "sandbox/file2.txt"); // 复制文件
    fs::copy("sandbox/dir", "sandbox/dir2"); // 复制目录（非递归）
    const auto copyOptions = fs::copy_options::update_existing
                           | fs::copy_options::recursive
                           | fs::copy_options::directories_only
                           ;
    fs::copy("sandbox", "sandbox_copy", copyOptions);
    static_cast<void>(std::system("tree"));
    fs::remove_all("sandbox");
    fs::remove_all("sandbox_copy");
}

可能的输出：

.
├── sandbox
│   ├── dir
│   │   └── subdir
│   ├── dir2
│   ├── file1.txt
│   └── file2.txt
└── sandbox_copy
    ├── dir
    │   └── subdir
    └── dir2

8 directories, 2 files

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3013 | C++17 | error_code 重载被标记为 noexcept 但能分配内存 | 移除 noexcept
LWG 2682 | C++17 | 试图为目录创建符号链接会成功但不做任何事 | 报告错误

参阅

copy_options (C++17) | 指定复制操作的语义 (枚举)
copy_symlink (C++17) | 复制一个符号链接 (函数)
copy_file (C++17) | 复制文件内容 (函数)


std::filesystem::copy_file

< cpp‎ | filesystem
定义于头文件 <filesystem>
bool copy_file( const std::filesystem::path & from,

const std::filesystem::path & to );
bool copy_file( const std::filesystem::path & from,
const std::filesystem::path & to,

std::error_code & ec );
 (1) (C++17 起)
bool copy_file( const std::filesystem::path & from,

const std::filesystem::path & to,
std::filesystem::copy_options options );
bool copy_file( const std::filesystem::path & from,
const std::filesystem::path & to,
std::filesystem::copy_options options,

std::error_code & ec );
 (2) (C++17 起)
1) 默认，等价于以 copy_options::none 为 options 的 (2)
2) 从 from 到 to 复制单个文件，使用 options 所指示的复制选项。若 options 中存在任一 copy_options 选项组中多于一个的选项，则行为未定义（即使在无关乎 copy_file 的组中）。
  • 若 !is_regular_file(from) （因为源文件不存在或它不是常规文件），则报告错误
  • 否则，若目标文件不存在，则
  • 复制 from 所解析到的文件的内容及属性到 to 所解析到者（跟随符号链接）
  • 否则，若目标文件已存在……
  • 若下列之一为真则报告错误：
  • to 与 from 相同，以 equivalent(from, to) 确定；
  • to 不是常规文件，以 !is_regular_file(to) 确定
  • options 中未设置任何 copy_file 控制选项
  • 否则，若 copy_options::skip_existing 设置于 options ，则不做任何事
  • 否则，若 copy_options::overwrite_existing 设置于 options ，则复制 from 所解析到的文件的内容及属性到 to 所解析到的文件
  • 否则，若 copy_options::update_existing 设置于 options ，则仅若 from 按 last_write_time() 定义新于 to 才复制

若错误发生，则不抛出重载返回 false 。

参数

from | - | 源文件的路径
to | - | 目标文件的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

若文件被复制则返回 true ，否则返回 false 。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 from，第二 path 参数 to 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

函数最多引入一次对 status(to) 的直接或间接调用（均用于确定文件是否存在，及对于 copy_options::update_existing 选项，确定其最后写入时间）

当 copy_file 被用于复制目录时报告错误：用 copy 复制它们。

copy_file 跟随符号链接：用 copy_symlink 或 copy 带 copy_options::copy_symlinks 复制它们。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3014 | C++17 | error_code 重载被标记为 noexcept 但能分配内存 | 移除 noexcept

示例

#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    fs::create_directory("sandbox");
    std::ofstream("sandbox/file1.txt").put('a');

    fs::copy_file("sandbox/file1.txt", "sandbox/file2.txt");

    // 现在 sandbox 中有二个文件：
    std::cout << "file1.txt holds : "
              << std::ifstream("sandbox/file1.txt").rdbuf() << '\n';
    std::cout << "file2.txt holds : "
              << std::ifstream("sandbox/file2.txt").rdbuf() << '\n';

    // 复制目录失败
    fs::create_directory("sandbox/abc");
    try {
        fs::copy_file("sandbox/abc", "sandbox/def");
    } catch(fs::filesystem_error& e) {
        std::cout << "Could not copy sandbox/abc: " << e.what() << '\n';
    }
    fs::remove_all("sandbox");
}

可能的输出：

file1.txt holds : a
file2.txt holds : a
Could not copy sandbox/abc: copy_file: Is a directory: "sandbox/abc", "sandbox/def"

参阅

copy_options (C++17) | 指定复制操作的语义 (枚举)
copy_symlink (C++17) | 复制一个符号链接 (函数)
copy (C++17) | 复制文件或目录 (函数)


std::filesystem::copy_options

< cpp‎ | filesystem
定义于头文件 <filesystem> |
enum class copy_options { none = /* unspecified */, skip_existing = /* unspecified */, overwrite_existing = /* unspecified */, update_existing = /* unspecified */, recursive = /* unspecified */, copy_symlinks = /* unspecified */, skip_symlinks = /* unspecified */, directories_only = /* unspecified */, create_symlinks = /* unspecified */, create_hard_links = /* unspecified */ }; | (C++17 起)

此类型代表控制 copy() 及 copy_file() 函数行为的可用选项。

copy_options 满足位掩码类型 (BitmaskType) 的要求（表示位运算符 operator& 、 operator| 、 operator^ 、 operator~ 、 operator&= 、 operator|= 及 operator^= 对此类型定义）。 none 代表空位掩码；每个其他枚举项都代表有别的位掩码元素。

成员常量

每个下列选项组中至多存在一个选项，否则复制函数的行为未定义。

成员常量 | 含义
文件已存在时控制 copy_file() 的选项
none | 报告错误（默认行为）
skip_existing | 保持既存文件，而不报告错误。
overwrite_existing | 替换既存文件。
update_existing | 替换既存文件，仅若它旧于被复制的文件
在子目录上控制 copy() 效果的选项
none | 跳过子目录（默认行为）
recursive | 递归地复制子目录及其内容
在符号链接上控制 copy() 效果的选项
none | 跟随符号链接（默认行为）
copy_symlinks | 复制符号链接为符号链接，而非其所指的文件
skip_symlinks | 忽略符号链接
控制 copy() 所做的复制类型的选项
none | 复制文件内容（默认行为）
directories_only | 复制目录结构，但不复制任何非目录文件
create_symlinks | 创建指向原有文件的符号链接，而不创建文件副本。注意：源路径必须是绝对路径，除非目标路径在当前目录中。
create_hard_links | 创建解析到与原有文件相同文件的硬链接，而不创建文件副本

示例

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    fs::create_directories("sandbox/dir/subdir");
    std::ofstream("sandbox/file1.txt").put('a');
    fs::copy("sandbox/file1.txt", "sandbox/file2.txt"); // 复制文件
    fs::copy("sandbox/dir", "sandbox/dir2"); // 复制目录（非递归）
    const auto copyOptions = fs::copy_options::update_existing
                           | fs::copy_options::recursive
                           | fs::copy_options::directories_only
                           ;
    fs::copy("sandbox", "sandbox_copy", copyOptions);
    static_cast<void>(std::system("tree"));
    fs::remove_all("sandbox");
    fs::remove_all("sandbox_copy");
}

可能的输出：

.
├── sandbox
│   ├── dir
│   │   └── subdir
│   ├── dir2
│   ├── file1.txt
│   └── file2.txt
└── sandbox_copy
    ├── dir
    │   └── subdir
    └── dir2

8 directories, 2 files

参阅

copy (C++17) | 复制文件或目录 (函数)
copy_file (C++17) | 复制文件内容 (函数)


std::filesystem::copy_symlink

< cpp‎ | filesystem
定义于头文件 <filesystem>
void copy_symlink( const std::filesystem::path & from,
const std::filesystem::path & to);
 (1) (C++17 起)
void copy_symlink( const std::filesystem::path & from,

const std::filesystem::path & to,

std::error_code & ec );
 (2) (C++17 起)

复制符号链接到另一位置。

1) 等效于调用 f(read_symlink(from), to) ，其中 f 是 create_symlink 或 create_directory_symlink ，依赖于 from 解析为文件或目录。
2) 等效于调用 f(read_symlink(from, ec), to, ec) ，其中 f 是 create_symlink 或 create_directory_symlink ，依赖于 from 解析为文件或目录。

参数

from | - | 要复制的符号链接的路径
to | - | 新符号链接的目标路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

（无）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 from，第二 path 参数 to 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

参阅

copy (C++17) | 复制文件或目录 (函数)
copy_file (C++17) | 复制文件内容 (函数)
create_symlinkcreate_directory_symlink (C++17)(C++17) | 创建一个符号链接 (函数)
read_symlink (C++17) | 获得符号链接的目标 (函数)


std::filesystem::create_directory, std::filesystem::create_directories

< cpp‎ | filesystem
定义于头文件 <filesystem>
bool create_directory( const std::filesystem::path & p );
bool create_directory( const std::filesystem::path & p, std::error_code & ec ) noexcept;
 (1) (C++17 起)
bool create_directory( const std::filesystem::path & p,

const std::filesystem::path & existing_p );
bool create_directory( const std::filesystem::path & p,
const std::filesystem::path & existing_p,

std::error_code & ec ) noexcept;
 (2) (C++17 起)
bool create_directories( const std::filesystem::path & p );
bool create_directories( const std::filesystem::path & p, std::error_code & ec );
 (3) (C++17 起)
1) 如同用 POSIX mkdir() 以 static_cast<int>( std::filesystem::perms::all ) 为第二参数创建目录 p （亲目录必须已经存在）。若该函数因为 p 解析到既存目录而失败，则不报告错误。否则在失败时报告错误。
2) 同 (1) ，除了新目录的属性复制自 existing_p （必须是已存在的目录）。复制的属性是取决于操作系统：在 POSIX 系统上，如同按照下方复制属性
stat(existing_p.c_str(), &attributes_stat)
mkdir(p.c_str(), attributes_stat.st_mode)
在 Windows 操作系统上，不复制 existing_p 的属性。
3) 对每个尚未存在的 p 的元素执行 (1) 。若 p 已存在，则函数不做任何事（不把此条件当做错误）。

参数

p | - | 要创建的新目录的路径
existing_p | - | 要自之复制属性的目录的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

若创建了 p 所解析到的目录则为 true ，否则为 false 。

异常

1,3) 不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。
2) 不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p，第二 path 参数 existing_p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注解

保持属性的重载 (2) 被 copy() 在递归地复制目录时隐式调用。其在 boost.filesystem 的等价物是 copy_directory （参数顺序相反）

示例

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    fs::current_path(fs::temp_directory_path());
    fs::create_directories("sandbox/1/2/a");
    fs::create_directory("sandbox/1/2/b");
    fs::permissions("sandbox/1/2/b", fs::perms::others_all, fs::perm_options::remove);
    fs::create_directory("sandbox/1/2/c", "sandbox/1/2/b");
    std::system("ls -l sandbox/1/2");
    std::system("tree sandbox");
    fs::remove_all("sandbox");
}

可能的输出：

drwxr-xr-x 2 user group 4096 Apr 15 09:33 a
drwxr-x--- 2 user group 4096 Apr 15 09:33 b
drwxr-x--- 2 user group 4096 Apr 15 09:33 c
sandbox
└── 1
    └── 2
        ├── a
        ├── b
        └── c

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2935 | C++17 | 若目标已存在但非目录，则为错误 | 不再是错误
LWG 3014 | C++17 | create_directories 的 error_code 重载被标记为 noexcept 但能分配内存 | 移除 noexcept
P1164R1 | C++17 | 已存在的非目录文件导致的创建失败不是错误 | 使之为错误

参阅

create_symlinkcreate_directory_symlink (C++17)(C++17) | 创建一个符号链接 (函数)
copy (C++17) | 复制文件或目录 (函数)
perms (C++17) | 标识文件系统权限 (枚举)


std::filesystem::create_hard_link

< cpp‎ | filesystem
定义于头文件 <filesystem>
void create_hard_link( const std::filesystem::path & target,

const path& std::filesystem::link );
void create_hard_link( const std::filesystem::path & target,
const path& std::filesystem::link,

std::error_code & ec );
 (C++17 起)

创建硬链接 link ，将其目标设为 target ，如同用 POSIX link() ：路径名 target 必须存在。

一旦创建， link 与 target 就是指代同一文件的二个逻辑名（它们等价）。即使原名 target 被删除，文件也会继续存在，并可以 link 访问。

参数

target | - | 要链接到的文件或目录名
link | - | 新硬链接的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

（无）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 target，第二 path 参数 link 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

一些操作系统完全不支持硬链接，或仅对常规文件支持。

某些文件系统不支持符号链接，无关乎操作系统，例如用于某些内存卡和闪存驱动器的 FAT 系统。

某些文件系统限制每个文件的链接数。

典型的到目录的硬链接对超级用户限制。

典型的硬链接不能跨越文件系统边界。

特殊路径名点（"."）是到其亲目录的硬链接。特殊路径名双点（".."）是到其亲目录的亲目录的硬链接。

示例

#include <iostream>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    fs::create_directories("sandbox/subdir");
    std::ofstream("sandbox/a").put('a'); // 创建常规文件
    fs::create_hard_link("sandbox/a", "sandbox/b");
    fs::remove("sandbox/a");
    // 通过存活的硬链接读取原始文件
    char c = std::ifstream("sandbox/b").get();
    std::cout << c << '\n';
    fs::remove_all("sandbox");
}

输出：

a

参阅

create_symlinkcreate_directory_symlink (C++17)(C++17) | 创建一个符号链接 (函数)
hard_link_count (C++17) | 返回指代特定文件的硬链接数 (函数)


std::filesystem::create_symlink, std::filesystem::create_directory_symlink

< cpp‎ | filesystem
定义于头文件 <filesystem>
void create_symlink( const std::filesystem::path & target,

const std::filesystem::path & link );
void create_symlink( const std::filesystem::path & target,
const std::filesystem::path & link,

std::error_code & ec );
 (1) (C++17 起)
void create_directory_symlink( const std::filesystem::path & target,

const std::filesystem::path & link );
void create_directory_symlink( const std::filesystem::path & target,
const std::filesystem::path & link,

std::error_code & ec );
 (2) (C++17 起)

创建符号链接 link ，其目标设为 target ，如同用 POSIX symlink() ：路径名 target 可以非法或不存在。

一些操作系统要求符号链接的创建鉴别该链接是否到目录。可移植的代码应用 (2) 创建目录符号链接，而非 (1) ，即使 POSIX 系统不作区别。

参数

target | - | 指定符号链接所至的路径，不必存在
link | - | 新符号链接的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

（无）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 target，第二 path 参数 link 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

一些操作系统完全不支持符号链接，或对常规文件支持。

某些文件系统不支持符号链接，无关乎操作系统，例如用于某些内存卡和闪存驱动器的 FAT 系统。

类似硬链接，符号链接允许一个文件拥有多个逻辑名。硬链接的存在保证文件的存在，即使原始文件名被移除。符号链接无这种保障；实际上， target 参数所指名的文件不必在链接创建时存在。符号链接能跨越文件系统边界。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    fs::create_directories("sandbox/subdir");
    fs::create_symlink("target", "sandbox/sym1");
    fs::create_directory_symlink("subdir", "sandbox/sym2");

    for(auto it = fs::directory_iterator("sandbox"); it != fs::directory_iterator(); ++it)
        if(is_symlink(it->symlink_status()))
            std::cout << *it << "->" << read_symlink(*it) << '\n';

    fs::remove_all("sandbox");
}

可能的输出：

"sandbox/sym1"->"target"
"sandbox/sym2"->"subdir"

参阅

statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)
read_symlink (C++17) | 获得符号链接的目标 (函数)
create_hard_link (C++17) | 创建一个硬链接 (函数)


std::filesystem::current_path

< cpp‎ | filesystem
定义于头文件 <filesystem> |  |
path current_path(); | (1) | (C++17 起)
path current_path( std::error_code & ec ); | (2) | (C++17 起)
void current_path( const std::filesystem::path & p ); | (3) | (C++17 起)
void current_path( const std::filesystem::path & p, std::error_code & ec ); | (4) | (C++17 起)

返回或更改当前路径。

1-2) 返回当前工作目录的绝对路径，如同通过 POSIX getcwd 取得（以原生格式）。若错误发生则 (2) 返回 path() 。
3-4) 更改当前工作目录到 p ，如同通过 POSIX chdir 。

参数

p | - | 更改当前工作目录所到的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

1-2) 返回当前工作目录。
3-4) （无）

异常

1-2) 不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。
3-4) 不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

当前工作目录是与进程关联的目录，它被用作相对路径的路径名解析中的起始位置。

许多操作系统返回的当前路径是危险的全局变量。第三方或系统库函数，或另一线程可能未经期待地更改它。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    std::cout << "Current path is " << fs::current_path() << '\n';
}

可能的输出：

Current path is "D:/local/ConsoleApplication1"


std::filesystem::directory_entry

< cpp‎ | filesystem
定义于头文件 <filesystem> |
class directory_entry; | (C++17 起)

表示目录条目。该对象存储一个 path 作为成员，并可能也在目录迭代过程中存储附带的文件属性（硬链接数、状态、符号链接状态、文件大小、及最后写入时间）。

成员函数

(构造函数)
 构造一个 directory_entry
(公开成员函数)
(析构函数)
 默认析构函数
(公开成员函数)
修改器
operator=
 赋值内容
(公开成员函数)
assign
 赋值内容
(公开成员函数)
replace_filename
 设置文件名
(公开成员函数)
refresh
 更新缓存的文件属性
(公开成员函数)
观察器
pathoperator const path&
 返回该目录项代表的路径
(公开成员函数)
exists
 检查 directory_entry 是否代表既存文件系统对象
(公开成员函数)
is_block_file
 检查 directory_entry 是否代表阻塞设备
(公开成员函数)
is_character_file
 检查 directory_entry 是否代表字符设备
(公开成员函数)
is_directory
 检查 directory_entry 是否代表目录
(公开成员函数)
is_fifo
 检查 directory_entry 是否代表具名管道
(公开成员函数)
is_other
 检查 directory_entry 是否代表其他文件
(公开成员函数)
is_regular_file
 检查 directory_entry 是否代表常规文件
(公开成员函数)
is_socket
 检查 directory_entry 是否代表具名 IPC 接头
(公开成员函数)
is_symlink
 检查 directory_entry 是否代表符号链接
(公开成员函数)
file_size
 返回 directory_entry 所指代的文件大小
(公开成员函数)
hard_link_count
 返回引用到该 directory_entry 所表示的文件的硬链接数
(公开成员函数)
last_write_time
 获取或设置 directory_entry 所代表的文件的最后数据修改时间
(公开成员函数)
statussymlink_status
 此 directory_entry 所指代的文件的状态
此 directory_entry 所指代的文件的符号链接状态
(公开成员函数)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 比较二个目录条目
(公开成员函数)

非成员函数

operator<<
 进行 directory_entry 上的流输出
(函数)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3171 | C++17 | directory_entry 不能由 operator<< 插入，因为 LWG2989 | 重新使输出可能


std::filesystem::directory_entry::assign

< cpp‎ | filesystem‎ | directory entry
void assign( const std::filesystem::path & p );
void assign( const std::filesystem::path & p, std::error_code & ec );
 (C++17 起)

复制新的内容到 directory_entry 对象。设置到 p 的路径并调用 refresh 更新缓存的属性。若发生错误，则缓存属性的值是未指定的。

参数

p | - | directory_entry 将指代的文件系统对象的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

（无）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

本节未完成
原因：暂无示例

参阅

operator=
 赋值内容
(公开成员函数)


std::filesystem::directory_entry::directory_entry

< cpp‎ | filesystem‎ | directory entry
directory_entry() noexcept = default;
 (1) (C++17 起)
directory_entry( const directory_entry& ) = default;
 (2) (C++17 起)
directory_entry( directory_entry&& ) noexcept = default;
 (3) (C++17 起)
explicit directory_entry( const std::filesystem::path & p );
directory_entry( const std::filesystem::path & p, std::error_code & ec );
 (4) (C++17 起)

构造新的 directory_entry 对象。

1) 默认构造函数。
2) 默认的复制构造函数。
3) 默认的移动构造函数。
4) 以路径 p 初始化 directory_entry ，并调用 refresh 更新缓存的属性。若发生错误，则不抛出重载令 directory_entry 保持保有默认构造的路径。

参数

p | - | directory_entry 将指代的文件系统对象的路径
ec | - | 不抛出重载中报告错误的输出参数

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

本节未完成
原因：暂无示例


std::filesystem::directory_entry::exists

< cpp‎ | filesystem‎ | directory entry
bool exists() const;
bool exists( std::error_code & ec ) const noexcept;
 (C++17 起)

检查所指的对象是否存在。各自等效于返回 std::filesystem::exists(status()) 或 std::filesystem::exists(status(ec))

参数

ec - 不抛出重载中报告错误的输出参数

返回值

若被指代文件系统对象存在则为 true。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>

namespace fs = std::filesystem;

int main()
{
    // 存储当前路径以在退出时恢复
    const auto old_current_path = fs::current_path();

    // 在临时目录中创建 "sanbox" 目录
    const auto dir_sandbox = fs::temp_directory_path() / "sandbox";

    if (!fs::create_directory(dir_sandbox)) {
        std::cout << "ERROR #1" << '\n';
        return -1;
    }

    fs::current_path(dir_sandbox); // 切换到新创建的目录

    fs::directory_entry entry_sandbox { dir_sandbox };
    if (!entry_sandbox.exists()) {
        std::cout << "ERROR #2" << '\n';
        return -1;
    }

    std::cout << "Current dir: " << entry_sandbox.path().filename() << '\n';

    fs::path path_tmp_file = dir_sandbox / "tmp_file";

    std::ofstream file( path_tmp_file.string() ); // 创建常规文件
    file << "cppreference.com"; // 写 16 字节
    file.flush();

    fs::directory_entry entry_tmp_file{ path_tmp_file };

    if (entry_tmp_file.exists()) {
        std::cout << "File " << entry_tmp_file.path().filename()
                  << " has size: " << entry_tmp_file.file_size() << '\n';
    } else {
        std::cout << "ERROR #3" << '\n';
    }

    // 清理
    fs::current_path(old_current_path);
    fs::remove_all(dir_sandbox);
}

可能的输出：

Current dir: "sandbox"
File "tmp_file" has size: 16

参阅

exists
(C++17)
 检查路径是否指代既存的文件系统对象
(函数)


std::filesystem::directory_entry::file_size

< cpp‎ | filesystem‎ | directory entry
std::uintmax_t file_size() const;
std::uintmax_t file_size( std::error_code & ec ) const noexcept;
 (C++17 起)

若文件大小缓存于此 directory_entry ，则返回缓存值。否则各返回 std::filesystem::file_size(path()) 或 std::filesystem::file_size(path(), ec)

参数

ec - 不抛出重载中报告错误的输出参数

返回值

所指代文件系统对象的大小

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

以下程序以人类可读的形式打印出给定目录中的文件以及其大小。

#include <filesystem>
#include <iostream>
#include <cstdint>
#include <cmath>

struct HumanReadable {
    uintmax_t size {};

    template <typename Os> friend Os& operator<< (Os& os, HumanReadable hr)
    {
        int i{};
        double mantissa = hr.size;
        for (; mantissa >= 1024.; ++i) {
            mantissa /= 1024.;
        }
        mantissa = std::ceil(mantissa * 10.) / 10.;
        os << mantissa << "BKMGTPE"[i];
        return i == 0 ? os : os << "B (" << hr.size << ')';
    }
};

int main(int argc, const char* argv[])
{
    namespace fs = std::filesystem;

    const auto dir = argc == 2 ? fs::path { argv[1] } : fs::current_path();

    for (fs::directory_entry const& entry : fs::directory_iterator(dir)) {
        if (entry.is_regular_file()) {
            std::cout << entry.path().filename()
                      << " size: " << HumanReadable{entry.file_size()} << "\n";
        }
    }
}

可能的输出：

"boost_1_73_0.tar.bz2" size: 104.2MB (109247910)
"CppCon 2018 - Jon Kalb “Copy Elision”.mp4" size: 15.7MB (16411990)
"cppreference-doc-20190607.tar.xz" size: 6.3MB (6531336)
"hana.hpp" size: 6.7KB (6807)

参阅

file_size
(C++17)
 返回文件的大小
(函数)


std::filesystem::directory_entry::hard_link_count

< cpp‎ | filesystem‎ | directory entry
std::uintmax_t hard_link_count() const;
std::uintmax_t hard_link_count( std::error_code & ec ) const noexcept;
 (C++17 起)

若硬链接数缓冲于此 directory_entry ，则返回缓冲的值。否则，各返回 std::filesystem::hard_link_count(path()) 或 std::filesystem::hard_link_count(path(), ec)

参数

ec - 不抛出重载中报告错误的输出参数

返回值

被引用文件系统对象的硬链接数

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

本节未完成
原因：暂无示例

参阅

hard_link_count
(C++17)
 返回指代特定文件的硬链接数
(函数)


std::filesystem::directory_entry::is_block_file

< cpp‎ | filesystem‎ | directory entry
bool is_block_file() const;
bool is_block_file( std::error_code & ec ) const noexcept;
 (C++17 起)

检查所指向对象是否阻塞设备。各自等效于返回 std::filesystem::is_block_file(status()) 或 std::filesystem::is_block_file(status(ec))

参数

ec - 不抛出重载中报告错误的输出参数

返回值

若所指代文件系统对象是阻塞设备则为 true ，否则为 false 。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

本节未完成
原因：暂无示例

参阅

is_block_file
(C++17)
 检查给定的路径是否表示块设备
(函数)


std::filesystem::directory_entry::is_character_file

< cpp‎ | filesystem‎ | directory entry
bool is_character_file() const;
bool is_character_file( std::error_code & ec ) const noexcept;
 (C++17 起)

检查所指的对象是否字符设备。各自等效于返回 std::filesystem::is_character_file(status()) 或 std::filesystem::is_character_file(status(ec))

参数

ec - 不抛出重载中报告错误的输出参数

返回值

若所指带文件系统对象是字符设备则为 true ，否则为 false 。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

本节未完成
原因：暂无示例

参阅

is_character_file
(C++17)
 检查给定的路径是否表示字符设备
(函数)


std::filesystem::directory_entry::is_directory

< cpp‎ | filesystem‎ | directory entry
bool is_directory() const;
bool is_directory( std::error_code & ec ) const noexcept;
 (C++17 起)

检查所指对象是否目录。各自等效于返回 std::filesystem::is_directory(status()) 或 std::filesystem::is_directory(status(ec))

参数

ec - 不抛出重载中报告错误的输出参数

返回值

若所指代文件系统对象是目录则为 true ，否则为 false 。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

#include <iostream>
#include <filesystem>

namespace fs = std::filesystem;

int main()
{
    fs::directory_entry d1(".");
    fs::directory_entry d2("file.txt");
    fs::directory_entry d3("new_dir");

    std::cout << std::boolalpha
              << ". d1 " << d1.is_directory() << '\n'
              << "file.txt d2 " << d2.is_directory() << '\n'
              // false ，因为未创建它
              << "new_dir d3 " << d3.is_directory() << '\n';

    fs::create_directory("new_dir");

    std::cout << "new_dir d3 before refresh " << d3.is_directory() << '\n';
    d3.refresh();
    std::cout << "new_dir d3 after refresh " << d3.is_directory() << '\n';
}

可能的输出：

. d1 true
file.txt d2 false
new_dir d3 false
new_dir d3 before refresh false
new_dir d3 after refresh true

参阅

is_directory
(C++17)
 检查给定的路径是否表示一个目录
(函数)


std::filesystem::directory_entry::is_fifo

< cpp‎ | filesystem‎ | directory entry
bool is_fifo() const;
bool is_fifo( std::error_code & ec ) const noexcept;
 (C++17 起)

检查所指对象是否 FIFO 或管道文件。各等效于返回 std::filesystem::is_fifo(status()) 或 std::filesystem::is_fifo(status(ec))

参数

ec - 不抛出重载中报告错误的输出参数

返回值

若所指代的文件系统对象是 FIFO 或管道文件则为 true ，否则为 false 。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

本节未完成
原因：暂无示例

参阅

is_fifo
(C++17)
 检查给定的路径是否表示一个命名管道
(函数)


std::filesystem::directory_entry::is_other

< cpp‎ | filesystem‎ | directory entry
bool is_other() const;
bool is_other( std::error_code & ec ) const noexcept;
 (C++17 起)

检查所指对象是否一个其他文件（非常规文件、目录或符号链接）。各等效于返回 std::filesystem::is_other(status()) 或 std::filesystem::is_other(status(ec))

参数

ec - 不抛出重载中报告错误的输出参数

返回值

若所指代文件系统对象是其他文件则为 true ，否则为 false 。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

本节未完成
原因：暂无示例

参阅

is_other
(C++17)
 检查参数是否表示一个其他文件
(函数)


std::filesystem::directory_entry::is_regular_file

< cpp‎ | filesystem‎ | directory entry
bool is_regular_file() const;
bool is_regular_file( std::error_code & ec ) const noexcept;
 (C++17 起)

检查所指的对象是否常规文件。各等效于返回 std::filesystem::is_regular_file(status()) 或 std::filesystem::is_regular_file(status(ec))

参数

ec - 不抛出重载中报告错误的输出参数

返回值

若所指代文件系统对象为常规文件，则为 true ，否则为 false 。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

#include <filesystem>
#include <iostream>
#include <string>

namespace fs = std::filesystem;

int main(int argc, const char* argv[])
{
    // 打印出目录 'dir' 中的所有常规文件。
    try {
        const auto dir = argc == 2
                             ? fs::path{ argv[1] }
                             : fs::current_path();

        std::cout << "Current dir: " << dir << '\n'
                  << std::string(40, '-') << '\n';

        for (fs::directory_entry const& entry : fs::directory_iterator(dir)) {
            if (entry.is_regular_file()) {
                std::cout << entry.path().filename() << '\n';
            }
        }
    } catch(fs::filesystem_error const& e) {
        std::cout << e.what() << '\n';
    }
}

可能的输出：

Current dir: "/tmp/1588616534.9884143"
----------------------------------------
"main.cpp"
"a.out"

参阅

is_regular_file
(C++17)
 检查参数是否表示一个常规文件
(函数)


std::filesystem::directory_entry::is_socket

< cpp‎ | filesystem‎ | directory entry
bool is_socket() const;
bool is_socket( std::error_code & ec ) const noexcept;
 (C++17 起)

检查所指对象是否具名接头。各自等效于返回 std::filesystem::is_socket(status()) 或 std::filesystem::is_socket(status(ec))

参数

ec - 不抛出重载中报告错误的输出参数

返回值

若所引用文件系统对象是具名接头则为 true ，否则为 false 。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

本节未完成
原因：暂无示例

参阅

is_socket
(C++17)
 检查参数是否表示一个具名 IPC 套接字
(函数)


std::filesystem::directory_entry::is_symlink

< cpp‎ | filesystem‎ | directory entry
bool is_symlink() const;
bool is_symlink( std::error_code & ec ) const noexcept;
 (C++17 起)

检查所指向对象是否符号链接。各等效于返回 std::filesystem::is_symlink(symlink_status()) 或 std::filesystem::is_symlink(symlink_status(ec))

参数

ec - 不抛出重载中报告错误的输出参数

返回值

若被指代的文件系统对象是符号链接，则为 true ，否则为 false 。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

本节未完成
原因：暂无示例

参阅

is_symlink
(C++17)
 检查参数是否表示一个符号链接
(函数)


std::filesystem::directory_entry::last_write_time

< cpp‎ | filesystem‎ | directory entry
std::filesystem::file_time_type last_write_time() const;
std::filesystem::file_time_type last_write_time( std::error_code & ec ) const noexcept;
 (C++17 起)

若最后修改时间缓存于此 directory_entry ，则返回缓存值。否则，各返回 std::filesystem::last_write_time(path()) 或 std::filesystem::last_write_time(path(), ec)

参数

ec - 不抛出重载中报告错误的输出参数

返回值

被指代文件系统对象的最后修改时间

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

本节未完成
原因：暂无示例

参阅

last_write_time
(C++17)
 获取或设置最近一次数据修改的时间
(函数)


std::filesystem::directory_entry::operator=

< cpp‎ | filesystem‎ | directory entry
directory_entry& operator=( const directory_entry& other ) = default; | (1) | (C++17 起)
directory_entry& operator=( directory_entry&& other ) noexcept = default; | (2) | (C++17 起)

以 other 的内容（路径及缓存属性，若存在）替换该 directory_entry 的内容。

directory_entry 的复制与移动赋值运算符均为默认。

参数

other - 另一个 directory_entry

返回值

*this

示例

本节未完成
原因：暂无示例

参阅

assign
 赋值内容
(公开成员函数)


std::filesystem::directory_entry::operator==,!=,<,<=,>,>=,<=>

< cpp‎ | filesystem‎ | directory entry
bool operator==( const directory_entry& rhs ) const noexcept; | (1) | (C++17 起)
bool operator!=( const directory_entry& rhs ) const noexcept; | (2) | (C++17 起) (C++20 前)
bool operator<( const directory_entry& rhs ) const noexcept; | (3) | (C++17 起) (C++20 前)
bool operator<=( const directory_entry& rhs ) const noexcept; | (4) | (C++17 起) (C++20 前)
bool operator>( const directory_entry& rhs ) const noexcept; | (5) | (C++17 起) (C++20 前)
bool operator>=( const directory_entry& rhs ) const noexcept; | (6) | (C++17 起) (C++20 前)
std::strong_ordering operator<=>( const directory_entry& rhs ) const noexcept; | (7) | (C++20 起)

与目录条目 rhs 比较路径。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

rhs - 要比较的 directory_entry

返回值

1) 若 path() == rhs.path() 则为 true ，否则为 false 。
2) 若 path() != rhs.path() 则为 true ，否则为 false 。
3) 若 path() < rhs.path() 则为 true ，否则为 false 。
4) 若 path() <= rhs.path() 则为 true ，否则为 false 。
5) 若 path() > rhs.path() 则为 true ，否则为 false 。
6) 若 path() >= rhs.path() 则为 true ，否则为 false 。
7) path() <=> rhs.path() 的结果。

参阅

pathoperator const path&
 返回该目录项代表的路径
(公开成员函数)


operator<<(std::filesystem::directory_entry)

< cpp‎ | filesystem‎ | directory entry
template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&

operator<<( std::basic_ostream <CharT,Traits>& os, const directory_entry& d );
 (C++17 起)

进行 directory_entry d 上的流输出。等价于 return os << d.path(); 。

此函数模板对通常无限定或有限定查找不可见，而只能在 std::filesystem::directory_entry 为参数的关联类时由实参依赖查找找到。这阻止 using namespace std::filesystem; using 指令存在时不想要的转换。

参数

os | - | 要进行输出的流
d | - | 要插入的 directory_entry

返回值

os

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    const auto entries = {
        fs::directory_entry{fs::current_path()},
        fs::directory_entry{fs::temp_directory_path()}
    };

    for (const fs::directory_entry& de : entries) {
        std::cout << de << '\n';
    }
}

可能的输出：

"/home/猫"
"/tmp"

参阅

operator<<operator>>
 进行路径上的流输入及输出
(函数)


std::filesystem::directory_entry::path

< cpp‎ | filesystem‎ | directory entry
const std::filesystem::path & path() const noexcept; | (C++17 起)
operator const std::filesystem::path & () const noexcept; | (C++17 起)

返回 directory_entry 所保有的路径对象。

参数

（无）

返回值

directory_entry 所保有的 path 对象。

示例

#include <filesystem>
#include <fstream>
#include <iostream>

namespace fs = std::filesystem;

std::string get_stem(const fs::path &p) { return (p.stem().string()); }
void create_file(const fs::path &p) { std::ofstream o{p}; }

int main()
{
        const fs::path dir{"tmp_dir"};
        fs::create_directory(dir);
        create_file(dir / "one");
        create_file(dir / "two");
        create_file(dir / "three");

        for (const auto &file : fs::directory_iterator(dir)) {
                // 显式转换
                std::cout << get_stem(file.path()) << '\n';

                // 隐式转换
                std::cout << get_stem(file) << '\n';
        }

        fs::remove_all(dir);
}

可能的输出：

two
two
one
one
three
three

参阅

本节未完成


std::filesystem::directory_entry::refresh

< cpp‎ | filesystem‎ | directory entry
void refresh() const;
void refresh( std::error_code & ec ) noexcept;
 (C++17 起)

检验此 directory_entry 所指代的文件系统对象，并为令 status() 、 exists() 、 is_regular_file() 可获取其属性，而存储属性及其他状态访问器。

若发生错误，则任何缓冲的属性的值是未指定的

参数

ec - 不抛出重载中报告错误的输出参数

返回值

（无）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

许多遍历目录的低层 OS API 将下个目录条目与文件属性一同获取。若它们存在，则 directory_iterator 的构造函数和非 const 函数将这些属性存储于所指向的 directory_entry 中，而不调用 directory_entry::refresh 。这使得程序能够在迭代目录条目的同时检验其属性，而不进行额外的系统调用。

示例

本节未完成
原因：暂无示例

参阅

statussymlink_status | 此 directory_entry 所指代的文件的状态 此 directory_entry 所指代的文件的符号链接状态 (公开成员函数)
exists | 检查 directory_entry 是否代表既存文件系统对象 (公开成员函数)
is_block_file | 检查 directory_entry 是否代表阻塞设备 (公开成员函数)
is_character_file | 检查 directory_entry 是否代表字符设备 (公开成员函数)
is_directory | 检查 directory_entry 是否代表目录 (公开成员函数)
is_fifo | 检查 directory_entry 是否代表具名管道 (公开成员函数)
is_other | 检查 directory_entry 是否代表其他文件 (公开成员函数)
is_regular_file | 检查 directory_entry 是否代表常规文件 (公开成员函数)
is_socket | 检查 directory_entry 是否代表具名 IPC 接头 (公开成员函数)
is_symlink | 检查 directory_entry 是否代表符号链接 (公开成员函数)
file_size | 返回 directory_entry 所指代的文件大小 (公开成员函数)
hard_link_count | 返回引用到该 directory_entry 所表示的文件的硬链接数 (公开成员函数)
last_write_time | 获取或设置 directory_entry 所代表的文件的最后数据修改时间 (公开成员函数)


std::filesystem::directory_entry::replace_filename

< cpp‎ | filesystem‎ | directory entry
void replace_filename( const std::filesystem::path & p );
void replace_filename( const std::filesystem::path & p, std::error_code & ec );
 (C++17 起)

更改 directory_entry 的文件名。

等效于以 path.replace_filename(p) 修改路径成员，并调用 refresh 更新缓存的属性。若发生错误，则缓存属性的值是未指定的。

此函数不向文件系统提交任何更改。

参数

p | - | 要附加到当前存储路径的亲路径的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

（无）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

#include <iostream>
#include <filesystem>

int main()
{
    namespace fs = std::filesystem;
    {
        fs::directory_entry entry{ "omega" };
        std::cout << entry << '\n';
        entry.replace_filename("alpha");
        std::cout << entry << '\n';
    }{
        fs::directory_entry entry{ "/omega/" };
        std::cout << entry << '\n';
        entry.replace_filename("alpha");
        std::cout << entry << '\n';
    }
}

输出：

"omega"
"alpha"
"/omega/"
"/omega/alpha"

参阅

assign | 赋值内容 (公开成员函数)
replace_filename | 以另一路径替换最末的路径组分 (std::filesystem::path 的公开成员函数)


std::filesystem::directory_entry::status, std::filesystem::directory_entry::symlink_status

< cpp‎ | filesystem‎ | directory entry
std::filesystem::file_status status() const;
std::filesystem::file_status status( std::error_code & ec ) const noexcept;
 (1) (C++17 起)
std::filesystem::file_status symlink_status() const;
std::filesystem::file_status symlink_status( std::error_code & ec ) const noexcept;
 (2) (C++17 起)
1) 返回入口的状态，如同用 status 的调用确定（跟随符号链接至其目标）
2) 返回入口的状态，如同用 symlink_status 的调用确定（不跟随符号链接）

参数

ec - 不抛出重载中报告错误的输出参数

返回值

入口所指代的文件的状态。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

许多遍历目录的低层 OS API 将下个目录条目与文件属性一同获取。若它们存在，则 directory_iterator 的构造函数和非 const 函数将这些属性存储于所指向的 directory_entry 中，而不调用 directory_entry::refresh 。这使得程序能够在迭代目录条目的同时检验其属性，而不进行额外的系统调用。

示例

#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>

namespace fs = std::filesystem;

void demo_status(const fs::path& p, fs::file_status s)
{
    std::cout << p;
    // 变体： switch(s.type()) { case fs::file_type::regular: ...}
    if(fs::is_regular_file(s)) std::cout << " is a regular file\n";
    if(fs::is_directory(s)) std::cout << " is a directory\n";
    if(fs::is_block_file(s)) std::cout << " is a block device\n";
    if(fs::is_character_file(s)) std::cout << " is a character device\n";
    if(fs::is_fifo(s)) std::cout << " is a named IPC pipe\n";
    if(fs::is_socket(s)) std::cout << " is a named IPC socket\n";
    if(fs::is_symlink(s)) std::cout << " is a symlink\n";
    if(!fs::exists(s)) std::cout << " does not exist\n";
}
int main()
{
    // 创建不同种类的文件
    fs::create_directory("sandbox");
    std::ofstream("sandbox/file"); // 创建常规文件
    fs::create_directory("sandbox/dir");
    mkfifo("sandbox/pipe", 0644);
    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    std::strcpy(addr.sun_path, "sandbox/sock");
    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
    bind(fd, (struct sockaddr*)&addr, sizeof addr);
    fs::create_symlink("file", "sandbox/symlink");

    // 演示不同的状态访问器
    for(auto it = fs::directory_iterator("sandbox"); it != fs::directory_iterator(); ++it)
        demo_status(*it, it->symlink_status()); // 从 directory_entry 使用缓冲的状态
    demo_status("dev/null", fs::status("/dev/null")); // 直接调用 status
    demo_status("dev/sda", fs::status("/dev/sda"));
    demo_status("sandbox/no", fs::status("/sandbox/no"));

    // 清理
    close(fd);
    fs::remove_all("sandbox");
}

可能的输出：

"sandbox/file" is a regular file
"sandbox/dir" is a directory
"sandbox/pipe" is a named IPC pipe
"sandbox/sock" is a named IPC socket
"sandbox/symlink" is a symlink
"dev/null" is a character device
"dev/sda" is a block device
"sandbox/no" does not exist

参阅

refresh | 更新缓存的文件属性 (公开成员函数)
exists | 检查 directory_entry 是否代表既存文件系统对象 (公开成员函数)
is_block_file | 检查 directory_entry 是否代表阻塞设备 (公开成员函数)
is_character_file | 检查 directory_entry 是否代表字符设备 (公开成员函数)
is_directory | 检查 directory_entry 是否代表目录 (公开成员函数)
is_fifo | 检查 directory_entry 是否代表具名管道 (公开成员函数)
is_other | 检查 directory_entry 是否代表其他文件 (公开成员函数)
is_regular_file | 检查 directory_entry 是否代表常规文件 (公开成员函数)
is_socket | 检查 directory_entry 是否代表具名 IPC 接头 (公开成员函数)
is_symlink | 检查 directory_entry 是否代表符号链接 (公开成员函数)
file_size | 返回 directory_entry 所指代的文件大小 (公开成员函数)
hard_link_count | 返回引用到该 directory_entry 所表示的文件的硬链接数 (公开成员函数)
last_write_time | 获取或设置 directory_entry 所代表的文件的最后数据修改时间 (公开成员函数)


std::filesystem::directory_iterator

< cpp‎ | filesystem
定义于头文件 <filesystem> |
class directory_iterator; | (C++17 起)

directory_iterator 是一个迭代于目录的 directory_entry 元素上的老式输入迭代器 (LegacyInputIterator) （但不造访子目录）。迭代顺序是未指定的，除了每个目录条目只被造访一次。跳过特殊路径名 dot 和 dot-dot 。

若前移 directory_iterator 越过了最终目录条目，则它变为等于默认构造的迭代器，亦称为终止迭代器。二个终止迭代器始终相等，解引用或自增终止迭代器是未定义行为。

若在创建目录迭代器之后将文件或目录删除或添加到目录树，则是否会通过迭代器观察到更改是未指定的。

成员类型

成员类型 | 定义
value_type | std::filesystem::directory_entry
difference_type | std::ptrdiff_t
pointer | const std::filesystem::directory_entry *
reference | const std::filesystem::directory_entry &
iterator_category | std::input_iterator_tag

成员函数

(构造函数) | 构造 directory_iterator (公开成员函数)
(析构函数) | 默认析构函数 (公开成员函数)
operator= | 对内容赋值 (公开成员函数)
operator*operator-> | 访问所指的目录条目 (公开成员函数)
incrementoperator++ | 前进到下个目录条目 (公开成员函数)

非成员函数

begin(std::filesystem::directory_iterator)end(std::filesystem::directory_iterator)
 基于范围的 for 循环支持
(函数)

另外按老式输入迭代器 (LegacyInputIterator) 所要求提供 operator== 和 operator!= (C++20 前)operator== (C++20 起) 。

是否提供 operator!= （因为它能从 operator== 合成），以及 (C++20 起)相等运算符是成员还是非成员是未指定的。

辅助模板

namespace std::ranges {

template<>
inline constexpr bool
enable_borrowed_range<std::filesystem::directory_iterator> = true;

}
 (C++20 起)
namespace std::ranges {

template<>
inline constexpr bool enable_view<std::filesystem::directory_iterator> = true;

}
 (C++20 起)

这些对 directory_iterator 的特化使之为 borrowed_range 及 view 。

注解

许多遍历目录的低层 OS API 将下个目录条目与文件属性一同获取。若它们存在，则 directory_iterator 的构造函数和非 const 函数将这些属性存储于所指向的 directory_entry 中，而不调用 directory_entry::refresh 。这使得程序能够在迭代目录条目的同时检验其属性，而不进行额外的系统调用。

示例

#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    fs::create_directories("sandbox/a/b");
    std::ofstream("sandbox/file1.txt");
    std::ofstream("sandbox/file2.txt");
    for(auto& p: fs::directory_iterator("sandbox"))
        std::cout << p.path() << '\n';
    fs::remove_all("sandbox");
}

可能的输出：

"sandbox/a"
"sandbox/file1.txt"
"sandbox/file2.txt"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3480 | C++20 | directory_iterator 既非 borrowed_range 亦非 view | 它都是

参阅

recursive_directory_iterator (C++17) | 指向一个目录及其子目录的内容的迭代器 (类)
directory_options (C++17) | 用于迭代目录内容的选项 (枚举)
directory_entry (C++17) | 目录条目 (类)


std::filesystem::begin(directory_iterator), std::filesystem::end(directory_iterator)

< cpp‎ | filesystem‎ | directory iterator
定义于头文件 <filesystem> |  |
directory_iterator begin( directory_iterator iter ) noexcept; | (1) | (C++17 起)
directory_iterator end( directory_iterator ) noexcept; | (2) | (C++17 起)
1) 返回不更改的 iter 。
2) 返回默认构造的 directory_iterator ，它用作尾迭代器，忽略参数。

这些非模板函数允许将 directory_iterator 用于基于范围的 for 循环并使 directory_iterator 为 range 类型 (C++20 起)。

参数

iter - directory_iterator

返回值

1) 不更改的 iter 。
2) 尾迭代器（默认构造的 directory_iterator ）。

示例

#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    fs::create_directories("sandbox/a/b");
    std::ofstream("sandbox/file1.txt");
    std::ofstream("sandbox/file2.txt");
    for(auto& p: fs::directory_iterator("sandbox"))
        std::cout << p << '\n';
    fs::remove_all("sandbox");
}

可能的输出：

"sandbox/a"
"sandbox/file1.txt"
"sandbox/file2.txt"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3480 | C++17 | end 按引用接收参数 | 按值接收参数

参阅

begin(std::filesystem::recursive_directory_iterator)end(std::filesystem::recursive_directory_iterator)
 基于范围的 for 循环支持
(函数)


std::filesystem::directory_iterator::directory_iterator

< cpp‎ | filesystem‎ | directory iterator
directory_iterator() noexcept;
 (1) (C++17 起)
explicit directory_iterator( const std::filesystem::path & p );
 (2) (C++17 起)
directory_iterator( const std::filesystem::path & p,
std::filesystem::directory_options options);
 (3) (C++17 起)
directory_iterator( const std::filesystem::path & p, std::error_code & ec );
 (4) (C++17 起)
directory_iterator( const std::filesystem::path & p,

std::filesystem::directory_options options,

std::error_code & ec );
 (5) (C++17 起)
directory_iterator( const directory_iterator& ) = default;
 (6) (C++17 起)
directory_iterator( directory_iterator&& ) = default;
 (7) (C++17 起)

构造新的目录迭代器。

1) 构造尾迭代器。
2) 构造指代 p 所标识的目录的首个目录条目的目录迭代器。若 p 指代不存在的文件或不指代目录，则抛出 std::filesystem::filesystem_error 。
3) 同 (2) ，但若 options 中设置了 std::filesystem::directory_options::skip_permission_denied 且构造遇到权限拒绝错误，则构造尾迭代器且不报告错误。
4) 构造指代 p 所标识目录的首个目录条目的目录迭代器。若 p 指代不存在的文件或不指代目录，则返回尾迭代器并设置 ec 。
5) 同 (4) ，但若 options 中设置了 std::filesystem::directory_options::skip_permission_denied 且构造遇到权限拒绝错误，则构造尾迭代器且不报告错误。

参数

p | - | 要创建迭代器的路径
ec | - | 存储错误状态的错误码

异常

2-5) 不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

欲在当前目录迭代，则应以 directory_iterator(".") 构造迭代器，而非 directory_iterator("") 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3013 | C++17 | error_code 重载被标记为 noexcept 但能分配内存 | 移除 noexcept


std::filesystem::directory_iterator::operator++, std::filesystem::directory_iterator::increment

< cpp‎ | filesystem‎ | directory iterator
directory_iterator& operator++();
directory_iterator& increment( std::error_code & ec );
 (C++17 起)

前移迭代器到下个条目。非法化所有 *this 的先前值的副本。

本节未完成

参数

ec - 存储错误状态的错误码

返回值

*this

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3013 | C++17 | error_code 重载被标记为 noexcept 但能分配内存 | 移除 noexcept


std::filesystem::directory_iterator::operator*, std::filesystem::directory_iterator::operator->

< cpp‎ | filesystem‎ | directory iterator
const std::filesystem::directory_entry & operator*() const; | (1) | (C++17 起)
const std::filesystem::directory_entry * operator->() const; | (2) | (C++17 起)

访问迭代器所指的 directory_entry 。

尾迭代器上的 operator* 或 operator-> 产生未定义行为。

参数

（无）

返回值

1) 此迭代器所指代的 directory_entry 的值。
2) 指向此迭代器所指代的 directory_entry 的指针。

异常

可能抛出实现定义的异常。

参阅

operator*operator->
 访问所指的目录条目
(std::filesystem::recursive_directory_iterator 的公开成员函数)


std::filesystem::directory_iterator::operator=

< cpp‎ | filesystem‎ | directory iterator
directory_iterator& operator=(const directory_iterator &other) = default;

directory_iterator& operator=(directory_iterator &&other) = default;
 (C++17 起)

对目录迭代器内容赋值。

本节未完成

参数

other - 要赋值的迭代器

返回值

*this

异常

本节未完成


std::filesystem::directory_options

< cpp‎ | filesystem
定义于头文件 <filesystem> |
enum class directory_options { none = /* unspecified */, follow_directory_symlink = /* unspecified */, skip_permission_denied = /* unspecified */ }; | (C++17 起)

此类型代表控制 directory_iterator 及 recursive_directory_iterator 行为的可用选项。

directory_options 满足位掩码类型 (BitmaskType) 的要求（表示位运算符 operator& 、 operator| 、 operator^ 、 operator~ 、 operator&= 、 operator|= 及 operator^= 对此类型定义）。 none 表示空位掩码；每个其他枚举项表示不同的位掩码元素。

成员常量

成员常量 | 含义
none | （默认）跳过符号链接，权限拒绝是错误。
follow_directory_symlink | 跟随而非跳过符号链接。
skip_permission_denied | 跳过若不跳过就会产生权限拒绝错误的目录。

参阅

(构造函数) | 构造 directory_iterator (std::filesystem::directory_iterator 的公开成员函数)
(构造函数) | 构造递归目录迭代器 (std::filesystem::recursive_directory_iterator 的公开成员函数)


std::filesystem::equivalent

< cpp‎ | filesystem
定义于头文件 <filesystem>
bool equivalent( const std::filesystem::path & p1,

const std::filesystem::path & p2 );
bool equivalent( const std::filesystem::path & p1,
const std::filesystem::path & p2,

std::error_code & ec ) noexcept;
 (C++17 起)

检查路径 p1 与 p2 是否解析到同一文件系统实体。

若 p1 或 p2 不存在则报告错误。

不抛出重载在错误时返回 false 。

参数

p1, p2 | - | 要检测等价性的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

若 p1 与 p2 指代同一文件或目录且其文件状态相同则为 true 。否则为 false 。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p1，第二 path 参数 p2 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注解

若二个路径解析到的候选实体位于同设备的同一位置，则认为它们解析到同一文件系统实体。对于 POSIX ，这表明其如同以 POSIX stat() 获得的 POSIX stat 结构的 st_dev 与 st_ino 成员相等。

通常，所有同一文件的目录或硬链接等价，而同一文件系统上的符号链接与其目标等价。

示例

#include <iostream>
#include <cstdint>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    // 硬链接等价
    fs::path p1 = ".";
    fs::path p2 = fs::current_path();
    if(fs::equivalent(p1, p2))
        std::cout << p1 << " is equivalent to " << p2 << '\n';

    // 符号链接等价
    for(const fs::path lib : {"/lib/libc.so.6", "/lib/x86_64-linux-gnu/libc.so.6"}) {
        try {
          p2 = lib.parent_path() / fs::read_symlink(lib);
        } catch(std::filesystem::filesystem_error const& ex) {
            std::cout << ex.what() << '\n';
            continue;
        }
        if(fs::equivalent(lib, p2))
            std::cout << lib << " is equivalent to " << p2 << '\n';
    }
}

可能的输出：

"." is equivalent to "/var/tmp/test"
filesystem error: read_symlink: No such file or directory [/lib/libc.so.6]
"/lib/x86_64-linux-gnu/libc.so.6" is equivalent to "/lib/x86_64-linux-gnu/libc-2.23.so"

参阅

statussymlink_status
(C++17)(C++17)
 确定文件属性
确定文件属性，检查符号链接目标
(函数)


std::filesystem::exists

< cpp‎ | filesystem
定义于头文件 <filesystem>
bool exists( std::filesystem::file_status s )
 (1) (C++17 起)
bool exists( const std::filesystem::path & p );
bool exists( const std::filesystem::path & p, std::error_code & ec )
 (2) (C++17 起)

检查给定的文件状态或路径是否对应已存在的文件或目录。

1) 等价于 status_known(s) && s.type() != file_type::not_found.
2) 令 s 分别为如同以 status(p) 或 status(p, ec) （跟随符号链接）确定的 std::filesystem::file_status 。返回 exists(s) 。若 status_known(s) 则不抛出重载调用 ec.clear() 。

参数

s | - | 要检验的文件状态
p | - | 要检验的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

若给定路径或文件状态对应存在的文件或目录，则返回 true ，否则返回 false 。

异常

2) 不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

此函数提供的信息通常亦可作为目录迭代的副产物提供。在迭代中，调用 exists(*iterator) 的效率低于 exists(iterator->status())

示例

本节未完成
原因：切换到 directory_entry::exists
#include <iostream>
#include <fstream>
#include <cstdint>
#include <filesystem>
namespace fs = std::filesystem;

void demo_exists(const fs::path& p, fs::file_status s = fs::file_status{})
{
    std::cout << p;
    if(fs::status_known(s) ? fs::exists(s) : fs::exists(p))
        std::cout << " exists\n";
    else
        std::cout << " does not exist\n";
}
int main()
{
    fs::create_directory("sandbox");
    std::ofstream("sandbox/file"); // 创建常规文件
    fs::create_symlink("non-existing", "sandbox/symlink");

    demo_exists("sandbox");
    for(auto it = fs::directory_iterator("sandbox"); it != fs::directory_iterator(); ++it)
        demo_exists(*it, it->status()); // 使用来自 directory_entry 的缓存状态
    fs::remove_all("sandbox");
}

输出：

"sandbox" exists
"sandbox/file" exists
"sandbox/symlink" does not exist

参阅

statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)
file_status (C++17) | 表示文件类型及权限 (类)
exists | 检查 directory_entry 是否代表既存文件系统对象 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::file_size

< cpp‎ | filesystem
定义于头文件 <filesystem>
std::uintmax_t file_size( const std::filesystem::path & p );
std::uintmax_t file_size( const std::filesystem::path & p, std::error_code & ec );
 (1) (C++17 起)

若 p 不存在则报告错误。

对于常规文件 p ，返回其大小，如同以读取由 POSIX stat 获得的结构体的 st_size 成员确定（跟随符号链接）

尝试确定目录（以及其他非常规文件或符号链接）的大小的结果是实现定义的。

错误时不抛出重载返回 static_cast< std::uintmax_t >(-1) 。

参数

p | - | 要检验的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

文件大小，以字节计。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

#include <iostream>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    fs::path p = fs::current_path() / "example.bin";
    std::ofstream(p).put('a'); // 创建文件大小为 1
    std::cout << "File size = " << fs::file_size(p) << '\n';
    fs::remove(p);

    try {
        fs::file_size("/dev"); // 试图获取目录的大小
    } catch(fs::filesystem_error& e) {
        std::cout << e.what() << '\n';
    }
}

可能的输出：

File size = 1
filesystem error: cannot get file size: Is a directory [/dev]

参阅

resize_file (C++17) | 以截断或填充零更改一个常规文件的大小 (函数)
space (C++17) | 确定文件系统上的可用空闲空间 (函数)
file_size | 返回 directory_entry 所指代的文件大小 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::file_status

< cpp‎ | filesystem
定义于头文件 <filesystem> |
class file_status; | (C++17 起)

存储关于文件类型与权限的信息。

成员函数

(构造函数) | 构造 file_status 对象 (公开成员函数)
operator= | 对内容赋值 (公开成员函数)
(析构函数) | 隐式析构函数 (公开成员函数)
type | 获取或设置文件类型 (公开成员函数)
permissions | 获取或设置文件权限 (公开成员函数)

非成员函数

operator==
(C++20)
 比较二个 file_status 对象
(函数)

参阅

statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)
statussymlink_status | 此 directory_entry 所指代的文件的状态 此 directory_entry 所指代的文件的符号链接状态 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::file_status::file_status

< cpp‎ | filesystem‎ | file status
file_status() noexcept : file_status( std::filesystem::file_type::none ) { }
 (1) (C++17 起)
file_status( const file_status& ) noexcept = default;
 (2) (C++17 起)
file_status( file_status&& ) noexcept = default;
 (3) (C++17 起)
explicit file_status(

std::filesystem::file_type type,

std::filesystem::perms permissions = std::filesystem::perms::unknown ) noexcept;
 (4) (C++17 起)

构造新的 file_status 对象。

1) 默认构造函数以 std::filesystem::file_type::none 调用 (4) 。
2-3) 默认化复制与移动构造函数。
4) 以 type 为类型， permissions 为权限，初始化 file_status 对象。

参数

type | - | 文件状态的类型
permissions | - | 文件状态的权限

示例

本节未完成
原因：暂无示例


std::filesystem::file_status::operator=

< cpp‎ | filesystem‎ | file status
file_status& operator=( const file_status& other ) noexcept = default; | (1) | (C++17 起)
file_status& operator=( file_status&& other ) noexcept = default; | (2) | (C++17 起)

以另一个 file_status 对象复制或移动赋值。

参数

other - 要赋值的另一个 file_status 对象

返回值

*this

示例

本节未完成
原因：暂无示例


operator==(std::filesystem::file_status)

< cpp‎ | filesystem‎ | file status
friend bool operator==( const file_status& lhs, const file_status& rhs ) noexcept; | (C++20 起)

检查二个 file_status 值是否相等，即是否其所表示的类型与权限分别相同。

此函数对通常无限定或有限定查找不可见，而只能在 std::filesystem::file_status 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

参数

lhs, rhs - 要比较的 file_status 值

返回值

lhs.type() == rhs.type() && lhs.permissions() == rhs.permissions()

参阅

type | 获取或设置文件类型 (公开成员函数)
permissions | 获取或设置文件权限 (公开成员函数)


std::filesystem::file_status::permissions

< cpp‎ | filesystem‎ | file status
std::filesystem::perms permissions() const noexcept; | (1) | (C++17 起)
void permissions( std::filesystem::perms perm ) noexcept; | (2) | (C++17 起)

访问文件权限信息。

1) 返回文件权限信息。
2) 设置文件权限为 perm 。

参数

perm - 要设置的文件权限

返回值

1) 文件权限信息。
2) （无）

示例

本节未完成
原因：暂无示例


std::filesystem::file_status::type

< cpp‎ | filesystem‎ | file status
std::filesystem::file_type type() const noexcept; | (1) | (C++17 起)
void type( std::filesystem::file_type type ) noexcept; | (2) | (C++17 起)

访问文件类型信息。

1) 返回文件类型信息。
2) 设置文件类型信息为 type 。

参数

type - 要设置的文件类型

返回值

1) 文件类型信息。
2) （无）

示例

本节未完成
原因：暂无示例


std::filesystem::file_time_type

< cpp‎ | filesystem
定义于头文件 <filesystem> |
using file_time_type = std::chrono::time_point </*trivial-clock*/>; | (C++17 起) (C++20 前)
using file_time_type = std::chrono::time_point <std::chrono::file_clock>; | (C++20 起)

表示文件时间。

trivial-clock 是一个满足平凡时钟 (TrivialClock) ，并足以表示文件系统提供的文件时间值与精度的实现定义类型。

 (C++20 前)

示例

#include <iostream>
#include <chrono>
#include <iomanip>
#include <fstream>
#include <filesystem>

using namespace std::chrono_literals;
int main()
{
    auto p = std::filesystem::temp_directory_path() / "example.bin";
    std::ofstream(p.c_str()).put('a'); // 创建文件

    auto print_last_write_time = [](std::filesystem::file_time_type const& ftime) {
        std::time_t cftime = std::chrono::system_clock::to_time_t(
            std::chrono::file_clock::to_sys(ftime));
        std::cout << "File write time is " << std::asctime(std::localtime(&cftime));
    };

    auto ftime = std::filesystem::last_write_time(p);
    print_last_write_time(ftime);

    std::filesystem::last_write_time(p, ftime + 1h); // 向未来移动文件时间 1 小时
    ftime = std::filesystem::last_write_time(p); // 从文件系统回读
    print_last_write_time(ftime);

    std::filesystem::remove(p);
}

可能的输出：

File write time is Sun May  9 23:29:58 2021
File write time is Mon May 10 00:29:58 2021

参阅

last_write_time
(C++17)
 获取或设置最近一次数据修改的时间
(函数)


std::filesystem::file_type

< cpp‎ | filesystem
定义于头文件 <filesystem> |
enum class file_type { none = /* unspecified */, not_found = /* unspecified */, regular = /* unspecified */, directory = /* unspecified */, symlink = /* unspecified */, block = /* unspecified */, character = /* unspecified */, fifo = /* unspecified */, socket = /* unspecified */, unknown = /* unspecified */, /* implementation-defined */ }; | (C++17 起)

file_type 定义常量，指示路径所指代的文件或目录的类型。枚举项的值各异。

本节未完成

常量

常量 | 含义
none | 指示文件状态未被求值，或求值时出错
not_found | 指示文件未找到（这不被认为是错误）
regular | 常规文件
directory | 目录
symlink | 符号链接
block | 阻塞特殊文件
character | 字符特殊文件
fifo | FIFO （又称管道）文件
socket | 接头文件
实现定义 | 每个实现支持的附加文件类型的附加实现定义常量
unknown | 文件存在但无法确定其类型

参阅

本节未完成


std::filesystem::filesystem_error

< cpp‎ | filesystem
定义于头文件 <filesystem> |
class filesystem_error; | (C++17 起)

类 std::filesystem::filesystem_error 定义文件系统库中函数的抛出版重载所抛出的异常对象。

cpp/error/exception cpp/error/runtime error cpp/error/system error

继承图

成员函数

(构造函数) | 构造异常对象 (公开成员函数)
operator= | 替换异常对象 (公开成员函数)
path1path2 | 返回导致错误的操作所涉及的路径 (公开成员函数)
what | 返回解释性字符串 (公开成员函数)

继承自 std::system_error

成员函数

code | 返回错误码 (std::system_error 的公开成员函数)
what [虚] | 返回解释性字符串 (std::system_error 的虚公开成员函数)

继承自 std::runtime_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

注解

为确保 filesystem_error 的复制函数为 noexcept ，典型实现将保有 what() 的返回值的对象和 path1() 与 path2() 所分别引用的二个 std::filesystem::path 对象存储于分离分配的引用计数存储。

当前 MS STL 实现不合标准：上述对象被直接存储在 filesystem 对象中，这使得复制函数不是 noexcept 。

示例

本节未完成
原因：暂无示例


std::filesystem::filesystem_error::filesystem_error

< cpp‎ | filesystem‎ | filesystem error
filesystem_error( const std::string & what_arg,
std::error_code ec );
 (1) (C++17 起)
filesystem_error( const std::string & what_arg,

const std::filesystem::path & p1,

std::error_code ec );
 (2) (C++17 起)
filesystem_error( const std::string & what_arg,

const std::filesystem::path & p1,
const std::filesystem::path & p2,

std::error_code ec );
 (3) (C++17 起)
filesystem_error( const filesystem_error& other ) noexcept;
 (4) (C++17 起)

构造新的文件系统错误对象。

1-3) 设置错误码为 ec ，可选地将导致该错误的操作中设计的路径设为 p1 和 p2 。构造后 what() 返回含有 what_arg 的 string （假定它不含内嵌的空字符 ）。若未提供一个或两个 path 参数，则用 path 代替。
4) 复制构造函数。以 other 的内容初始化内容。若 *this 与 other 均拥有动态类型 std::filesystem_error::filesystem_error 则 std::strcmp (what(), other.what()) == 0 。

参数

what_arg | - | 解释字符串
ec | - | 依赖特定操作系统的错误的错误码
p1, p2 | - | 引发系统错误的操作中涉及的路径
other | - | 要复制的另一 filesystem_error 对象

注解

因为不容许复制 std::filesystem::filesystem_error 抛异常，解释字符串常被在内部存储于分离分配的引用计数存储。这也是无构造函数接收 std::string&& 的原因：它总是要复制内容。

典型实现亦将 path1() 与 path2() 所引用的 path 对象存储于引用计数存储。

示例

本节未完成
原因：暂无示例


std::filesystem::filesystem_error::operator=

< cpp‎ | filesystem‎ | filesystem error
filesystem_error& operator=( const filesystem_error& other ) noexcept; | (C++17 起)

以 other 的内容赋值内容。若 *this 与 other 均拥有动态类型 std::filesystem::filesystem_error 则赋值后 std::strcmp (what(), other.what()) == 0 。

参数

other - 用以赋值的另一 filesystem_error 对象

返回值

*this

注解

典型的实现在引用计数的存储中存储 path1() 与 path2() 所引用的 path 对象。结果是 *this 与 other 通常在赋值后共享其 path 对象。

示例

本节未完成
原因：暂无示例


std::filesystem::filesystem_error::path1, std::filesystem::filesystem_error::path2

< cpp‎ | filesystem‎ | filesystem error
const std::filesystem::path & path1() const noexcept; | (C++17 起)
const std::filesystem::path & path2() const noexcept; | (C++17 起)

返回存储于异常对象中的路径。

参数

（无）

返回值

到构造函数所存储的 path 参数的副本的引用。

示例

#include <cstdio>
#include <filesystem>
#include <iostream>

int main()
{
    const std::filesystem::path old_p{std::tmpnam(nullptr)},
                                new_p{std::tmpnam(nullptr)};
    try {
        std::filesystem::rename(old_p, new_p); // 因为 old_p 不存在而抛出
    }
    catch(std::filesystem::filesystem_error const& ex) {
        std::cout
            << "what():  " << ex.what() << '\n'
            << "path1(): " << ex.path1() << '\n'
            << "path2(): " << ex.path2() << '\n';
    }
}

可能的输出：

what():  filesystem error: cannot rename: No such file or directory [/tmp/fileIzzRLB] [/tmp/fileiUDWlV]
path1(): "/tmp/fileIzzRLB"
path2(): "/tmp/fileiUDWlV"


std::filesystem::filesystem_error::what

< cpp‎ | filesystem‎ | filesystem error
const char* what() const noexcept override; | (C++17 起)

返回解释性字节字符串。此解释性字符串含有在 构造时传递的解释字符串。鼓励实现在返回的字符串中包含原生格式的 path1() 和 path2() 的路径名，还有 std::system_error::what() 字符串。

参数

（无）

示例

本节未完成
原因：暂无示例


std::filesystem::hard_link_count

< cpp‎ | filesystem
定义于头文件 <filesystem>
std::uintmax_t hard_link_count( const std::filesystem::path & p );
std::uintmax_t hard_link_count( const std::filesystem::path & p, std::error_code & ec );
 (1) (C++17 起)

返回路径 p 所标识的文件系统对象的硬链接数。

非抛出重载在错误时返回 static_cast<uintmax_t>(-1) 。

参数

p | - | 要检测的路径
ec | - | 非抛出重载中报告错误的输出参数

返回值

p 的硬链接数

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    // 在 POSIX 风格文件系统上，每个目录至少有 2 个硬链接：
    // 其自身与特殊成员名 "."
    fs::path p = fs::current_path();
    std::cout << "Number of hard links for current path is "
              << fs::hard_link_count(p) << '\n';

    // 每个 ".." 是到亲目录的应谅解，故对任何目录的硬链接综述是 2 加上直接子目录数
    p = fs::current_path() / ".."; // 每个双点是到亲目录的硬链接
    std::cout << "Number of hard links for .. is "
              << fs::hard_link_count(p) << '\n';
}

可能的输出：

Number of hard links for current path is 2
Number of hard links for .. is 3

参阅

create_hard_link (C++17) | 创建一个硬链接 (函数)
hard_link_count | 返回引用到该 directory_entry 所表示的文件的硬链接数 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::is_block_file

< cpp‎ | filesystem
定义于头文件 <filesystem>
bool is_block_file( std::filesystem::file_status s ) noexcept;
 (1) (C++17 起)
bool is_block_file( const std::filesystem::path & p );
bool is_block_file( const std::filesystem::path & p, std::error_code & ec ) noexcept;
 (2) (C++17 起)

检查给定的文件状态或路径是否对应一个阻塞特殊文件，如同通过 POSIX S_ISBLK 确定。阻塞特殊文件的例子是阻塞设备，例如 Linux 上的 /dev/sda 或 /dev/loop0 。

1) 等价于 s.type() == file_type::block.
2) 等价于 is_block_file(status(p)) 或 is_block_file(status(p, ec)).

参数

s | - | 要检查的文件状态
p | - | 要检验的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

若 p 所指示的文件或 s 所指示的类型指代一个阻塞设备，则返回 true。若错误发生则不抛出重载返回 false 。

异常

2) 不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>

namespace fs = std::filesystem;

void demo_status(const fs::path& p, fs::file_status s)
{
    std::cout << p;
    // 变体： switch(s.type()) { case fs::file_type::regular: ...}
    if(fs::is_regular_file(s)) std::cout << " is a regular file\n";
    if(fs::is_directory(s)) std::cout << " is a directory\n";
    if(fs::is_block_file(s)) std::cout << " is a block device\n";
    if(fs::is_character_file(s)) std::cout << " is a character device\n";
    if(fs::is_fifo(s)) std::cout << " is a named IPC pipe\n";
    if(fs::is_socket(s)) std::cout << " is a named IPC socket\n";
    if(fs::is_symlink(s)) std::cout << " is a symlink\n";
    if(!fs::exists(s)) std::cout << " does not exist\n";
}
int main()
{
    // 创建不同种类的文件
    fs::create_directory("sandbox");
    std::ofstream("sandbox/file"); // 创建常规文件
    fs::create_directory("sandbox/dir");
    mkfifo("sandbox/pipe", 0644);
    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    std::strcpy(addr.sun_path, "sandbox/sock");
    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
    bind(fd, (struct sockaddr*)&addr, sizeof addr);
    fs::create_symlink("file", "sandbox/symlink");

    // 演示不同的状态访问器
    for(auto it = fs::directory_iterator("sandbox"); it != fs::directory_iterator(); ++it)
        demo_status(*it, it->symlink_status()); // 从 directory_entry 使用缓冲的状态
    demo_status("dev/null", fs::status("/dev/null")); // 直接调用 status
    demo_status("dev/sda", fs::status("/dev/sda"));
    demo_status("sandbox/no", fs::status("/sandbox/no"));

    // 清理
    close(fd);
    fs::remove_all("sandbox");
}

可能的输出：

"sandbox/file" is a regular file
"sandbox/dir" is a directory
"sandbox/pipe" is a named IPC pipe
"sandbox/sock" is a named IPC socket
"sandbox/symlink" is a symlink
"dev/null" is a character device
"dev/sda" is a block device
"sandbox/no" does not exist

参阅

statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)
file_status (C++17) | 表示文件类型及权限 (类)
status_known (C++17) | 检查文件状态是否已知 (函数)
is_character_file (C++17) | 检查给定的路径是否表示字符设备 (函数)
is_directory (C++17) | 检查给定的路径是否表示一个目录 (函数)
is_fifo (C++17) | 检查给定的路径是否表示一个命名管道 (函数)
is_other (C++17) | 检查参数是否表示一个其他文件 (函数)
is_regular_file (C++17) | 检查参数是否表示一个常规文件 (函数)
is_socket (C++17) | 检查参数是否表示一个具名 IPC 套接字 (函数)
is_symlink (C++17) | 检查参数是否表示一个符号链接 (函数)
exists (C++17) | 检查路径是否指代既存的文件系统对象 (函数)
is_block_file | 检查 directory_entry 是否代表阻塞设备 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::is_character_file

< cpp‎ | filesystem
定义于头文件 <filesystem>
bool is_character_file( std::filesystem::file_status s ) noexcept;
 (1) (C++17 起)
bool is_character_file( const std::filesystem::path & p );
bool is_character_file( const std::filesystem::path & p, std::error_code & ec ) noexcept;
 (2) (C++17 起)

检查给定文件状态或路径是否对应一个字符特殊文件，如同 POSIX S_ISCHR 所确定。字符特殊文件的例子是字符设备，例如 Linux 上的 /dev/null 、 /dev/tty 、 /dev/audio 或 /dev/nvram 。

1) 等价于 s.type() == file_type::character.
2) 各等价于 is_character_file(status(p)) 或 is_character_file(status(p, ec))

参数

s | - | 要检查的文件状态
p | - | 要检验的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

若 p 所指示的文件或 s 所指示的类型指代字符设备则为 true ，否则为 false 。不抛出重载在错误发生时返回 false 。

异常

2) 不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>

namespace fs = std::filesystem;

void demo_status(const fs::path& p, fs::file_status s)
{
    std::cout << p;
    // 变体： switch(s.type()) { case fs::file_type::regular: ...}
    if(fs::is_regular_file(s)) std::cout << " is a regular file\n";
    if(fs::is_directory(s)) std::cout << " is a directory\n";
    if(fs::is_block_file(s)) std::cout << " is a block device\n";
    if(fs::is_character_file(s)) std::cout << " is a character device\n";
    if(fs::is_fifo(s)) std::cout << " is a named IPC pipe\n";
    if(fs::is_socket(s)) std::cout << " is a named IPC socket\n";
    if(fs::is_symlink(s)) std::cout << " is a symlink\n";
    if(!fs::exists(s)) std::cout << " does not exist\n";
}
int main()
{
    // 创建不同种类的文件
    fs::create_directory("sandbox");
    std::ofstream("sandbox/file"); // 创建常规文件
    fs::create_directory("sandbox/dir");
    mkfifo("sandbox/pipe", 0644);
    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    std::strcpy(addr.sun_path, "sandbox/sock");
    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
    bind(fd, (struct sockaddr*)&addr, sizeof addr);
    fs::create_symlink("file", "sandbox/symlink");

    // 演示不同的状态访问器
    for(auto it = fs::directory_iterator("sandbox"); it != fs::directory_iterator(); ++it)
        demo_status(*it, it->symlink_status()); // 从 directory_entry 使用缓冲的状态
    demo_status("dev/null", fs::status("/dev/null")); // 直接调用 status
    demo_status("dev/sda", fs::status("/dev/sda"));
    demo_status("sandbox/no", fs::status("/sandbox/no"));

    // 清理
    close(fd);
    fs::remove_all("sandbox");
}

可能的输出：

"sandbox/file" is a regular file
"sandbox/dir" is a directory
"sandbox/pipe" is a named IPC pipe
"sandbox/sock" is a named IPC socket
"sandbox/symlink" is a symlink
"dev/null" is a character device
"dev/sda" is a block device
"sandbox/no" does not exist

参阅

statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)
file_status (C++17) | 表示文件类型及权限 (类)
status_known (C++17) | 检查文件状态是否已知 (函数)
is_block_file (C++17) | 检查给定的路径是否表示块设备 (函数)
is_directory (C++17) | 检查给定的路径是否表示一个目录 (函数)
is_fifo (C++17) | 检查给定的路径是否表示一个命名管道 (函数)
is_other (C++17) | 检查参数是否表示一个其他文件 (函数)
is_regular_file (C++17) | 检查参数是否表示一个常规文件 (函数)
is_socket (C++17) | 检查参数是否表示一个具名 IPC 套接字 (函数)
is_symlink (C++17) | 检查参数是否表示一个符号链接 (函数)
exists (C++17) | 检查路径是否指代既存的文件系统对象 (函数)
is_character_file | 检查 directory_entry 是否代表字符设备 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::is_directory

< cpp‎ | filesystem
定义于头文件 <filesystem>
bool is_directory( std::filesystem::file_status s ) noexcept;
 (1) (C++17 起)
bool is_directory( const std::filesystem::path & p );
bool is_directory( const std::filesystem::path & p, std::error_code & ec ) noexcept;
 (2) (C++17 起)

检查给定文件状态或路径是否对应一个目录。

1) 等价于 s.type() == file_type::directory 。
2) 分别等价于 is_directory(status(p)) 或 is_directory(status(p, ec)) 。

参数

s | - | 要检查的文件状态
p | - | 要查询的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

若 p 所指示的文件或 s 所指示的类型指代目录则为 true ，否则为 false 。不抛出重载在错误发生时返回 false 。

异常

2) 不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>

namespace fs = std::filesystem;

void demo_status(const fs::path& p, fs::file_status s)
{
    std::cout << p;
    // 变体： switch(s.type()) { case fs::file_type::regular: ...}
    if(fs::is_regular_file(s)) std::cout << " is a regular file\n";
    if(fs::is_directory(s)) std::cout << " is a directory\n";
    if(fs::is_block_file(s)) std::cout << " is a block device\n";
    if(fs::is_character_file(s)) std::cout << " is a character device\n";
    if(fs::is_fifo(s)) std::cout << " is a named IPC pipe\n";
    if(fs::is_socket(s)) std::cout << " is a named IPC socket\n";
    if(fs::is_symlink(s)) std::cout << " is a symlink\n";
    if(!fs::exists(s)) std::cout << " does not exist\n";
}
int main()
{
    // 创建不同种类的文件
    fs::create_directory("sandbox");
    std::ofstream("sandbox/file"); // 创建常规文件
    fs::create_directory("sandbox/dir");
    mkfifo("sandbox/pipe", 0644);
    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    std::strcpy(addr.sun_path, "sandbox/sock");
    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
    bind(fd, (struct sockaddr*)&addr, sizeof addr);
    fs::create_symlink("file", "sandbox/symlink");

    // 演示不同的状态访问器
    for(auto it = fs::directory_iterator("sandbox"); it != fs::directory_iterator(); ++it)
        demo_status(*it, it->symlink_status()); // 从 directory_entry 使用缓冲的状态
    demo_status("dev/null", fs::status("/dev/null")); // 直接调用 status
    demo_status("dev/sda", fs::status("/dev/sda"));
    demo_status("sandbox/no", fs::status("/sandbox/no"));

    // 清理
    close(fd);
    fs::remove_all("sandbox");
}

可能的输出：

"sandbox/file" is a regular file
"sandbox/dir" is a directory
"sandbox/pipe" is a named IPC pipe
"sandbox/sock" is a named IPC socket
"sandbox/symlink" is a symlink
"dev/null" is a character device
"dev/sda" is a block device
"sandbox/no" does not exist

参阅

statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)
file_status (C++17) | 表示文件类型及权限 (类)
status_known (C++17) | 检查文件状态是否已知 (函数)
is_block_file (C++17) | 检查给定的路径是否表示块设备 (函数)
is_character_file (C++17) | 检查给定的路径是否表示字符设备 (函数)
is_fifo (C++17) | 检查给定的路径是否表示一个命名管道 (函数)
is_other (C++17) | 检查参数是否表示一个其他文件 (函数)
is_regular_file (C++17) | 检查参数是否表示一个常规文件 (函数)
is_socket (C++17) | 检查参数是否表示一个具名 IPC 套接字 (函数)
is_symlink (C++17) | 检查参数是否表示一个符号链接 (函数)
exists (C++17) | 检查路径是否指代既存的文件系统对象 (函数)
is_directory | 检查 directory_entry 是否代表目录 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::is_empty

< cpp‎ | filesystem
定义于头文件 <filesystem>
bool is_empty( const std::filesystem::path & p );
bool is_empty( const std::filesystem::path & p, std::error_code & ec );
 (C++17 起)

检查给定路径是否指代一个空文件或目录。

参数

p | - | 要检验的路径
ec | - | 错误情况下修改的错误码

返回值

若 p 所指示的文件指代空文件或目录则为 true ，否则为 false 。不抛出重载在错误发生时返回 false 。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

#include <filesystem>
#include <fstream>
#include <iostream>
#include <cstdio>

int main()
{
    namespace fs = std::filesystem;

    const fs::path tmp_dir{ fs::temp_directory_path() };
    std::cout << std::boolalpha
              << "Temp dir: " << tmp_dir << '\n'
              << "is_empty(): " << fs::is_empty(tmp_dir) << '\n';

    const fs::path tmp_name{ tmp_dir / std::tmpnam(nullptr) };
    std::cout << "Temp file: " << tmp_name << '\n';

    std::ofstream file{ tmp_name.string() };
    std::cout << "is_empty(): " << fs::is_empty(tmp_name) << '\n';
    file << "cppreference.com";
    file.flush();
    std::cout << "is_empty(): " << fs::is_empty(tmp_name) << '\n'
              << "file_size(): " << fs::file_size(tmp_name) << '\n';
    file.close();
    fs::remove(tmp_name);
}

可能的输出：

Temp dir: "/tmp"
is_empty(): false
Temp file: "/tmp/fileCqd9DM"
is_empty(): true
is_empty(): false
file_size(): 16

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3013 | C++17 | error_code 重载被标记为 noexcept 但能分配内存 | 移除 noexcept

参阅

statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)
exists (C++17) | 检查路径是否指代既存的文件系统对象 (函数)


std::filesystem::is_fifo

< cpp‎ | filesystem
定义于头文件 <filesystem>
bool is_fifo( std::filesystem::file_status s ) noexcept;
 (1) (C++17 起)
bool is_fifo( const std::filesystem::path & p );
bool is_fifo( const std::filesystem::path & p, std::error_code & ec ) noexcept;
 (2) (C++17 起)

检查给定文件状态或路径是否对应一个 FIFO 或管道文件，以 POSIX S_ISFIFO 确定。

1) 等价于 s.type() == file_type::fifo 。
2) 分别等价于 is_fifo(status(p)) 或 is_fifo(status(p, ec)) 。

参数

s | - | 要检查的文件状态
p | - | 要查询的状态
ec | - | 错误情况下修改的错误码

返回值

若 p 所指示的文件或 s 所指示的类型指代 FIFO 管道则为 true ，否则为 false 。不抛出重载在错误发生时返回 false 。

异常

2) 不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>

namespace fs = std::filesystem;

void demo_status(const fs::path& p, fs::file_status s)
{
    std::cout << p;
    // 变体： switch(s.type()) { case fs::file_type::regular: ...}
    if(fs::is_regular_file(s)) std::cout << " is a regular file\n";
    if(fs::is_directory(s)) std::cout << " is a directory\n";
    if(fs::is_block_file(s)) std::cout << " is a block device\n";
    if(fs::is_character_file(s)) std::cout << " is a character device\n";
    if(fs::is_fifo(s)) std::cout << " is a named IPC pipe\n";
    if(fs::is_socket(s)) std::cout << " is a named IPC socket\n";
    if(fs::is_symlink(s)) std::cout << " is a symlink\n";
    if(!fs::exists(s)) std::cout << " does not exist\n";
}
int main()
{
    // 创建不同种类的文件
    fs::create_directory("sandbox");
    std::ofstream("sandbox/file"); // 创建常规文件
    fs::create_directory("sandbox/dir");
    mkfifo("sandbox/pipe", 0644);
    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    std::strcpy(addr.sun_path, "sandbox/sock");
    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
    bind(fd, (struct sockaddr*)&addr, sizeof addr);
    fs::create_symlink("file", "sandbox/symlink");

    // 演示不同的状态访问器
    for(auto it = fs::directory_iterator("sandbox"); it != fs::directory_iterator(); ++it)
        demo_status(*it, it->symlink_status()); // 从 directory_entry 使用缓冲的状态
    demo_status("dev/null", fs::status("/dev/null")); // 直接调用 status
    demo_status("dev/sda", fs::status("/dev/sda"));
    demo_status("sandbox/no", fs::status("/sandbox/no"));

    // 清理
    close(fd);
    fs::remove_all("sandbox");
}

可能的输出：

"sandbox/file" is a regular file
"sandbox/dir" is a directory
"sandbox/pipe" is a named IPC pipe
"sandbox/sock" is a named IPC socket
"sandbox/symlink" is a symlink
"dev/null" is a character device
"dev/sda" is a block device
"sandbox/no" does not exist

参阅

statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)
file_status (C++17) | 表示文件类型及权限 (类)
status_known (C++17) | 检查文件状态是否已知 (函数)
is_block_file (C++17) | 检查给定的路径是否表示块设备 (函数)
is_character_file (C++17) | 检查给定的路径是否表示字符设备 (函数)
is_directory (C++17) | 检查给定的路径是否表示一个目录 (函数)
is_other (C++17) | 检查参数是否表示一个其他文件 (函数)
is_regular_file (C++17) | 检查参数是否表示一个常规文件 (函数)
is_socket (C++17) | 检查参数是否表示一个具名 IPC 套接字 (函数)
is_symlink (C++17) | 检查参数是否表示一个符号链接 (函数)
exists (C++17) | 检查路径是否指代既存的文件系统对象 (函数)
is_fifo | 检查 directory_entry 是否代表具名管道 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::is_other

< cpp‎ | filesystem
定义于头文件 <filesystem>
bool is_other( std::filesystem::file_status s ) noexcept;
 (1) (C++17 起)
bool is_other( const std::filesystem::path & p );
bool is_other( const std::filesystem::path & p, std::error_code & ec ) noexcept;
 (2) (C++17 起)

检查给定文件状态或路径是否对应其他类型的文件。即文件存在，但既非常规文件，亦非目录或符号链接。

1) 等价于 exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s) 。
2) 各等价于 is_other(status(p)) 或 is_other(status(p, ec)) 。

参数

s | - | 要检查的文件状态
p | - | 要检验的路径
ec | - | 存储错误状态的错误码

返回值

若 p 所指示的文件或 s 所指示的类型指代不是常规文件、目录或符号链接则为 true ，否则为 false 。不抛出重载在错误发生时返回 false 。

异常

2) 不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

本节未完成
原因：暂无示例

参阅

statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)
file_status (C++17) | 表示文件类型及权限 (类)
status_known (C++17) | 检查文件状态是否已知 (函数)
is_block_file (C++17) | 检查给定的路径是否表示块设备 (函数)
is_character_file (C++17) | 检查给定的路径是否表示字符设备 (函数)
is_directory (C++17) | 检查给定的路径是否表示一个目录 (函数)
is_fifo (C++17) | 检查给定的路径是否表示一个命名管道 (函数)
is_regular_file (C++17) | 检查参数是否表示一个常规文件 (函数)
is_socket (C++17) | 检查参数是否表示一个具名 IPC 套接字 (函数)
is_symlink (C++17) | 检查参数是否表示一个符号链接 (函数)
exists (C++17) | 检查路径是否指代既存的文件系统对象 (函数)
is_other | 检查 directory_entry 是否代表其他文件 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::is_regular_file

< cpp‎ | filesystem
定义于头文件 <filesystem>
bool is_regular_file( std::filesystem::file_status s ) noexcept;
 (1) (C++17 起)
bool is_regular_file( const std::filesystem::path & p );
bool is_regular_file( const std::filesystem::path & p, std::error_code & ec ) noexcept;
 (2) (C++17 起)

检查给定文件状态或路径是否对应常规文件。

1) 等价于 s.type() == file_type::regular 。
2) 分别等价于 is_regular_file(status(p)) 或 is_regular_file(status(p, ec)) 。

参数

s | - | 要检验的文件状态
p | - | 要检验的路径
ec | - | 存储错误状态的错误码

返回值

若 p 所指示的文件或 s 所指示的类型指代常规文件，则为 true ，否则为 false 。不抛出重载在错误发生时返回 false 。

异常

2) 不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

抛出重载还指定为若 status(p) 会抛出，则抛出 std::filesystem::filesystem_error 。

示例

#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>

namespace fs = std::filesystem;

void demo_status(const fs::path& p, fs::file_status s)
{
    std::cout << p;
    // 变体： switch(s.type()) { case fs::file_type::regular: ...}
    if(fs::is_regular_file(s)) std::cout << " is a regular file\n";
    if(fs::is_directory(s)) std::cout << " is a directory\n";
    if(fs::is_block_file(s)) std::cout << " is a block device\n";
    if(fs::is_character_file(s)) std::cout << " is a character device\n";
    if(fs::is_fifo(s)) std::cout << " is a named IPC pipe\n";
    if(fs::is_socket(s)) std::cout << " is a named IPC socket\n";
    if(fs::is_symlink(s)) std::cout << " is a symlink\n";
    if(!fs::exists(s)) std::cout << " does not exist\n";
}
int main()
{
    // 创建不同种类的文件
    fs::create_directory("sandbox");
    std::ofstream("sandbox/file"); // 创建常规文件
    fs::create_directory("sandbox/dir");
    mkfifo("sandbox/pipe", 0644);
    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    std::strcpy(addr.sun_path, "sandbox/sock");
    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
    bind(fd, (struct sockaddr*)&addr, sizeof addr);
    fs::create_symlink("file", "sandbox/symlink");

    // 演示不同的状态访问器
    for(auto it = fs::directory_iterator("sandbox"); it != fs::directory_iterator(); ++it)
        demo_status(*it, it->symlink_status()); // 从 directory_entry 使用缓冲的状态
    demo_status("dev/null", fs::status("/dev/null")); // 直接调用 status
    demo_status("dev/sda", fs::status("/dev/sda"));
    demo_status("sandbox/no", fs::status("/sandbox/no"));

    // 清理
    close(fd);
    fs::remove_all("sandbox");
}

可能的输出：

"sandbox/file" is a regular file
"sandbox/dir" is a directory
"sandbox/pipe" is a named IPC pipe
"sandbox/sock" is a named IPC socket
"sandbox/symlink" is a symlink
"dev/null" is a character device
"dev/sda" is a block device
"sandbox/no" does not exist

参阅

statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)
file_status (C++17) | 表示文件类型及权限 (类)
status_known (C++17) | 检查文件状态是否已知 (函数)
is_block_file (C++17) | 检查给定的路径是否表示块设备 (函数)
is_character_file (C++17) | 检查给定的路径是否表示字符设备 (函数)
is_directory (C++17) | 检查给定的路径是否表示一个目录 (函数)
is_fifo (C++17) | 检查给定的路径是否表示一个命名管道 (函数)
is_other (C++17) | 检查参数是否表示一个其他文件 (函数)
is_socket (C++17) | 检查参数是否表示一个具名 IPC 套接字 (函数)
is_symlink (C++17) | 检查参数是否表示一个符号链接 (函数)
exists (C++17) | 检查路径是否指代既存的文件系统对象 (函数)
is_regular_file | 检查 directory_entry 是否代表常规文件 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::is_socket

< cpp‎ | filesystem
定义于头文件 <filesystem>
bool is_socket( std::filesystem::file_status s ) noexcept;
 (1) (C++17 起)
bool is_socket( const std::filesystem::path & p );
bool is_socket( const std::filesystem::path & p, std::error_code & ec ) noexcept;
 (2) (C++17 起)

检查给定文件状态或路径是否对应一个具名 IPC 接头，以 POSIX S_IFSOCK 确定。

1) 等价于 s.type() == file_type::socket 。
2) 等价于 is_socket(status(p)) 或 is_socket(status(p, ec)) 。

参数

s | - | 要检查的文件状态
p | - | 要检验的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

若 p 所指示的文件或 s 所指示的类型指代具名接头，则为 true ，否则为 false 。不抛出重载在错误发生时返回 false 。

异常

2,3) 不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

具名接头是以 socket 与 bind POSIX API 构造的 UNIX 域接头，可用于高级的进程间通讯。特别是它们可用于在从一个运行的进程传递打开的文件描述符到另一个。

示例

#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>

namespace fs = std::filesystem;

void demo_status(const fs::path& p, fs::file_status s)
{
    std::cout << p;
    // 变体： switch(s.type()) { case fs::file_type::regular: ...}
    if(fs::is_regular_file(s)) std::cout << " is a regular file\n";
    if(fs::is_directory(s)) std::cout << " is a directory\n";
    if(fs::is_block_file(s)) std::cout << " is a block device\n";
    if(fs::is_character_file(s)) std::cout << " is a character device\n";
    if(fs::is_fifo(s)) std::cout << " is a named IPC pipe\n";
    if(fs::is_socket(s)) std::cout << " is a named IPC socket\n";
    if(fs::is_symlink(s)) std::cout << " is a symlink\n";
    if(!fs::exists(s)) std::cout << " does not exist\n";
}
int main()
{
    // 创建不同种类的文件
    fs::create_directory("sandbox");
    std::ofstream("sandbox/file"); // 创建常规文件
    fs::create_directory("sandbox/dir");
    mkfifo("sandbox/pipe", 0644);
    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    std::strcpy(addr.sun_path, "sandbox/sock");
    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
    bind(fd, (struct sockaddr*)&addr, sizeof addr);
    fs::create_symlink("file", "sandbox/symlink");

    // 演示不同的状态访问器
    for(auto it = fs::directory_iterator("sandbox"); it != fs::directory_iterator(); ++it)
        demo_status(*it, it->symlink_status()); // 从 directory_entry 使用缓冲的状态
    demo_status("dev/null", fs::status("/dev/null")); // 直接调用 status
    demo_status("dev/sda", fs::status("/dev/sda"));
    demo_status("sandbox/no", fs::status("/sandbox/no"));

    // 清理
    close(fd);
    fs::remove_all("sandbox");
}

可能的输出：

"sandbox/file" is a regular file
"sandbox/dir" is a directory
"sandbox/pipe" is a named IPC pipe
"sandbox/sock" is a named IPC socket
"sandbox/symlink" is a symlink
"dev/null" is a character device
"dev/sda" is a block device
"sandbox/no" does not exist

参阅

statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)
file_status (C++17) | 表示文件类型及权限 (类)
status_known (C++17) | 检查文件状态是否已知 (函数)
is_block_file (C++17) | 检查给定的路径是否表示块设备 (函数)
is_character_file (C++17) | 检查给定的路径是否表示字符设备 (函数)
is_directory (C++17) | 检查给定的路径是否表示一个目录 (函数)
is_fifo (C++17) | 检查给定的路径是否表示一个命名管道 (函数)
is_other (C++17) | 检查参数是否表示一个其他文件 (函数)
is_regular_file (C++17) | 检查参数是否表示一个常规文件 (函数)
is_symlink (C++17) | 检查参数是否表示一个符号链接 (函数)
exists (C++17) | 检查路径是否指代既存的文件系统对象 (函数)
is_socket | 检查 directory_entry 是否代表具名 IPC 接头 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::is_symlink

< cpp‎ | filesystem
定义于头文件 <filesystem>
bool is_symlink( std::filesystem::file_status s ) noexcept;
 (1) (C++17 起)
bool is_symlink( const std::filesystem::path & p );
bool is_symlink( const std::filesystem::path & p, std::error_code & ec ) noexcept;
 (2) (C++17 起)

检查给定文件状态或目录是否对应一个符号链接，以 POSIX S_IFLNK 检验。

1) 等价于 s.type() == file_type::symlink 。
2) 等价于 is_symlink(symlink_status(p)) 或 is_symlink(symlink_status(p, ec)) 。

参数

s | - | 要检测的文件状态
p | - | 要检测的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

若 p 所指示的文件或 s 所指示的类型指代一个符号链接，则返回 true 。不抛出重载在错误发生时返回 false 。

异常

2) 不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>

namespace fs = std::filesystem;

void demo_status(const fs::path& p, fs::file_status s)
{
    std::cout << p;
    // 变体： switch(s.type()) { case fs::file_type::regular: ...}
    if(fs::is_regular_file(s)) std::cout << " is a regular file\n";
    if(fs::is_directory(s)) std::cout << " is a directory\n";
    if(fs::is_block_file(s)) std::cout << " is a block device\n";
    if(fs::is_character_file(s)) std::cout << " is a character device\n";
    if(fs::is_fifo(s)) std::cout << " is a named IPC pipe\n";
    if(fs::is_socket(s)) std::cout << " is a named IPC socket\n";
    if(fs::is_symlink(s)) std::cout << " is a symlink\n";
    if(!fs::exists(s)) std::cout << " does not exist\n";
}
int main()
{
    // 创建不同种类的文件
    fs::create_directory("sandbox");
    std::ofstream("sandbox/file"); // 创建常规文件
    fs::create_directory("sandbox/dir");
    mkfifo("sandbox/pipe", 0644);
    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    std::strcpy(addr.sun_path, "sandbox/sock");
    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
    bind(fd, (struct sockaddr*)&addr, sizeof addr);
    fs::create_symlink("file", "sandbox/symlink");

    // 演示不同的状态访问器
    for(auto it = fs::directory_iterator("sandbox"); it != fs::directory_iterator(); ++it)
        demo_status(*it, it->symlink_status()); // 从 directory_entry 使用缓冲的状态
    demo_status("dev/null", fs::status("/dev/null")); // 直接调用 status
    demo_status("dev/sda", fs::status("/dev/sda"));
    demo_status("sandbox/no", fs::status("/sandbox/no"));

    // 清理
    close(fd);
    fs::remove_all("sandbox");
}

可能的输出：

"sandbox/file" is a regular file
"sandbox/dir" is a directory
"sandbox/pipe" is a named IPC pipe
"sandbox/sock" is a named IPC socket
"sandbox/symlink" is a symlink
"dev/null" is a character device
"dev/sda" is a block device
"sandbox/no" does not exist

参阅

statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)
file_status (C++17) | 表示文件类型及权限 (类)
status_known (C++17) | 检查文件状态是否已知 (函数)
is_block_file (C++17) | 检查给定的路径是否表示块设备 (函数)
is_character_file (C++17) | 检查给定的路径是否表示字符设备 (函数)
is_directory (C++17) | 检查给定的路径是否表示一个目录 (函数)
is_fifo (C++17) | 检查给定的路径是否表示一个命名管道 (函数)
is_other (C++17) | 检查参数是否表示一个其他文件 (函数)
is_regular_file (C++17) | 检查参数是否表示一个常规文件 (函数)
is_socket (C++17) | 检查参数是否表示一个具名 IPC 套接字 (函数)
exists (C++17) | 检查路径是否指代既存的文件系统对象 (函数)
is_symlink | 检查 directory_entry 是否代表符号链接 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::last_write_time

< cpp‎ | filesystem
定义于头文件 <filesystem>
std::filesystem::file_time_type last_write_time(const std::filesystem::path & p);

std::filesystem::file_time_type last_write_time(const std::filesystem::path & p,

std::error_code & ec)
 (1) (C++17 起)
void last_write_time(const std::filesystem::path & p,

std::filesystem::file_time_type new_time);
void last_write_time(const std::filesystem::path & p,
std::filesystem::file_time_type new_time,

std::error_code & ec);
 (2) (C++17 起)
1) 返回 p 的最后修改时间，如同通过访问 POSIX stat 的 st_mtime 确定（跟随符号链接） 不抛出重载在错误时返回 file_time_type::min() 。
2) 更改 p 的最后修改时间，如同用 POSIX futimens （跟随符号链接）

参数

p | - | 要检验或修改的路径
new_time | - | 新的修改时间
ec | - | 不抛出重载中报告错误的输出参数

返回值

1) p 的最后修改时间
2) （无）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

不保证在设置写入时间后， (1) 的返回值立即等于传递给 (2) 的参数，因为文件系统时间可能比 file_time_type 更为颗粒化。

示例

#include <iostream>
#include <chrono>
#include <iomanip>
#include <fstream>
#include <filesystem>

using namespace std::chrono_literals;
int main()
{
    auto p = std::filesystem::temp_directory_path() / "example.bin";
    std::ofstream(p.c_str()).put('a'); // 创建文件

    auto print_last_write_time = [](std::filesystem::file_time_type const& ftime) {
        std::time_t cftime = std::chrono::system_clock::to_time_t(
            std::chrono::file_clock::to_sys(ftime));
        std::cout << "File write time is " << std::asctime(std::localtime(&cftime));
    };

    auto ftime = std::filesystem::last_write_time(p);
    print_last_write_time(ftime);

    std::filesystem::last_write_time(p, ftime + 1h); // 向未来移动文件时间 1 小时
    ftime = std::filesystem::last_write_time(p); // 从文件系统回读
    print_last_write_time(ftime);

    std::filesystem::remove(p);
}

可能的输出：

File write time is Sun May  9 23:29:58 2021
File write time is Mon May 10 00:29:58 2021

参阅

file_time_type (C++17) | 表示文件时间值 (typedef)
last_write_time | 获取或设置 directory_entry 所代表的文件的最后数据修改时间 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::path

< cpp‎ | filesystem
定义于头文件 <filesystem> |
class path; | (C++17 起)

类型 path 的对象表示文件系统上的路径。只有路径的语法外观得到处理：路径名可能表示不存在的路径，或甚至不允许存在于当前文件系统或操作系统的路径。

路径名拥有下列语法：

  1. 根名(可选) ：标识具有多根的文件系统（如 "C:" 或 "//myserver" ）的根。有歧义的情况下，将组成合法 根名 的最长序列当做 根名 。标准库可以在 OS API 所了解的 根名 外，定义额外的 根名 。
  2. 根目录(可选) ：目录分隔符，若存在，则标记此路径为绝对。若缺失（且异于根名的首元素是文件名），则路径为相对且要求另一路径作为解决此文件名的起始位置。
  3. 零或多个下列者：
  • 文件名 ：不由目录分隔符或偏好目录分隔符组成的字符序列（操作系统或文件系统可能加上附加限制）。此名称可能标识一个文件、硬链接或目录。辨别二种特殊的 文件名 ：
  • 点 ：由单个点字符 . 构成的文件名是指代当前目录的目录名
  • 点点 ：由二个点字符 .. 构成的文件名是指代父目录的目录名。
  • 目录分隔符 ：正斜杠字符 / 或作为 path::preferred_separator 提供的另一种字符。若重复此字符，则它被处理成单个目录分隔符： /usr///////lib 与 /usr/lib 相同

路径能以下列算法正常化：

  1. 若路径为空，则停止（空路径的正常形式是空路径）
  2. 替换每个 目录分隔符 （可以由多重斜杠组成）为单个 path::preferred_separator 。
  3. 替换 根名 中的每个斜杠字符为 path::preferred_separator 。
  4. 移除每个 点 和立即后随的 目录分隔符 。
  5. 移除每个立即后随 目录分隔符 和一个 点点 的非 点点 文件名，还有立即跟随的 目录分隔符 。
  6. 若存在 根目录 ，则移除立即跟随它们的所有 点点 及任何 目录分隔符 。
  7. 若最终文件名是 点点 ，则移除任何尾随的 目录分隔符 。
  8. 若路径为空，则添加一个 点 （ ./ 的正常形式是 . ）

路径可由 begin() 与 end() 函数返回的迭代器逐元素遍历，这会以通用格式查看路径，并在根名、根目录及后继文件名元素上迭代（跳过目录分隔符，除了标识根目录者）。若路径中的最后元素是目录分隔符，则最后的迭代器将解引用为空元素。

调用任何的 path 非 const 成员函数会令所有引用该对象元素的迭代器非法。

若 OS 使用异于上述可移植通用语法的原生语法，则库函数被定义为接受“受检测格式”，以接受两种格式的路径名：当且仅当受检测格式匹配通用格式，但不为操作系统作为原生路径接受，才采用受检测格式参数。原生格式在目录路径名和文件路径名有别的 OS 上，若通用路径名以目录分隔符终止，则将它当做目录路径，否则当做常规文件。

任何情况下， path 类表型如同它以原生格式存储路径名，并自动于所需场合转换它为通用格式（每个成员函数都指定它转译的路径格式）

POSIX 系统上，通用格式就是原生格式，并且没有必要区别或转换它们。

路径可隐式转换自及转换成 std::basic_string ，这使得在文件 API 上使用它们可行，例如作为到 std::ifstream::open 的参数

成员类型与常量

类型 | 定义
value_type | 文件系统原生编码所用的字符类型： POSIX 上为 char ， Windows 上为 wchar_t
string_type | std::basic_string <value_type>
const_iterator | value_type 为 path 的常老式双向迭代器 (LegacyBidirectionalIterator)
iterator | const_iterator 的别名
format
 确定如何转译路径名的字符串表示

亦定义下列枚举项：

常量 | 解释
native_format | 原生路径格式
generic_format | 通用路径格式
auto_format | 实现定义格式，可能处自动检测

(枚举)

成员常量

constexpr value_type preferred_separator
[静态]
 在可移植的 / 之外可用的另一种目录分隔符。 Windows 上它是反斜杠字符 \ 。 POSIX 上它是与可移植分隔符相同的斜杠 /
(公开静态成员常量)

成员函数

(构造函数)
 构造一个 path
(公开成员函数)
(析构函数)
 销毁 path 对象
(公开成员函数)
operator=
 赋值另一个路径
(公开成员函数)
assign
 赋值内容
(公开成员函数)
连接
appendoperator/=
 添加元素到带目录分隔符的路径
(公开成员函数)
concatoperator+=
 连接二个路径而不加入目录分隔符
(公开成员函数)
修改器
clear
 擦除内容
(公开成员函数)
make_preferred
 转换目录分隔符为偏好的目录分隔符
(公开成员函数)
remove_filename
 移除文件名路径组分
(公开成员函数)
replace_filename
 以另一路径替换最末的路径组分
(公开成员函数)
replace_extension
 替换扩展名
(公开成员函数)
swap
 交换两个路径
(公开成员函数)
格式观察器
c_strnativeoperator string_type
 返回路径的原生版本
(公开成员函数)
stringwstringu8stringu16stringu32string
 返回转换到字符串的原生路径名格式
(公开成员函数)
generic_stringgeneric_wstringgeneric_u8stringgeneric_u16stringgeneric_u32string
 返回转换到字符串的通用路径名格式
(公开成员函数)
比较
compare
 以字典序比较二个路径的字典表示
(公开成员函数)
生成
lexically_normallexically_relativelexically_proximate
 转换路径到正常形式
转换路径到相对形式
转换路径到准确形式
(公开成员函数)
分解
root_name
 若存在则返回路径的根名
(公开成员函数)
root_directory
 若存在则返回路径的根目录
(公开成员函数)
root_path
 若存在则返回路径的根路径
(公开成员函数)
relative_path
 返回相对根路径的路径
(公开成员函数)
parent_path
 返回亲路径的路径
(公开成员函数)
filename
 返回文件名路径组分
(公开成员函数)
stem
 返回主干路径组分
(公开成员函数)
extension
 返回文件扩展名路径组分
(公开成员函数)
查询
empty
 检查路径是否为空
(公开成员函数)
has_root_pathhas_root_namehas_root_directoryhas_relative_pathhas_parent_pathhas_filenamehas_stemhas_extension
 检查对应路径元素是否非空
(公开成员函数)
is_absoluteis_relative
 检查 root_path() 是否唯一标识文件系统位置
(公开成员函数)
迭代器
beginend
 访问作为元素序列的路径的迭代器
(公开成员函数)

非成员函数

std::swap(std::filesystem::path) | 交换二个路径 (函数)
hash_value | 计算路径对象的哈希值 (函数)
operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 前)(C++20 前)(C++20 前)(C++20 前)(C++20 前)(C++20) | 以字典序比较二个路径 (函数)
operator/ | 用目录分隔符连接二个路径 (函数)
operator<<operator>> | 进行路径上的流输入及输出 (函数)
u8path (C++17)(C++20 中弃用) | 从 UTF-8 编码的源创建 path (函数)


std::filesystem::path::append, std::filesystem::path::operator/=

< cpp‎ | filesystem‎ | path
path& operator/=(const path& p); | (1) | (C++17 起)
template< class Source > path& operator/=( const Source& source ); | (2) | (C++17 起)
template< class Source > path& append( const Source& source ); | (3) | (C++17 起)
template< class InputIt > path& append( InputIt first, InputIt last ); | (4) | (C++17 起)
1) 若 p.is_absolute() || (p.has_root_name() && p.root_name() != root_name()) ，则以 p 替换当前路径，如同用 operator=(p) 并终止。
* 否则，若 p.has_root_directory() ，则移除 *this 的通用格式路径名的任何根目录及整个相对路径
* 否则，若 has_filename() || (!has_root_directory() && is_absolute()) ，则附加 path::preferred_separator 到 *this 的通用格式
* 用以上之一处理后，附加 p 的原生格式路径名，从其通用格式忽略任何 root-name ，到 *this 的原生格式。
// 其中 "//host" 是根名
path("//host")  / "foo" // 结果是      "//host/foo" （附加分隔符）
path("//host/") / "foo" // 结果亦为    "//host/foo" （附加，无分隔符）

// POSIX 上，
path("foo") / ""      // 结果是 "foo/" （附加）
path("foo") / "/bar"; // 结果是 "/bar" （替换）

// Windows 上，
path("foo") / "C:/bar";  // 结果是 "C:/bar"    （替换）
path("foo") / "C:";      // 结果是 "C:"        （替换）
path("C:") / "";         // 结果是 "C:"        （附加，不带分隔符）
path("C:foo") / "/bar";  // 生成   "C:/bar"    （移除相对路径后附加）
path("C:foo") / "C:bar"; // 生成   "C:foo/bar" （附加，忽略 p 的根名）
2,3) 同 (1) ，除了接受任何 std::basic_string 、 std::basic_string_view ，空终止多字符字符串，或指向空终止多字符序列的输入迭代器。等价于 return operator/=(path(source)); 。
4) 同 (1) ，但接受任何指代多字符字符串的迭代器对。等价于 return operator/=(path(first, last));

(2) 与 (3) 仅若 Source 与 path 不是同一类型，而且：

  • Source 是 std::basic_string 或 std::basic_string_view 的特化，或
  • std::iterator_traits < std::decay_t <Source>>::value_type 合法并代表可能有 const 限定的编码字符类型（ char 、 char8_t 、 (C++20 起)char16_t 、 char32_t 或 wchar_t ）

才参与重载决议

参数

p | - | 要添加的路径
source | - | std::basic_string 、 std::basic_string_view 、空终止多字节/宽字符串、或指向空终止多字符序列的输入迭代器，它表示路径名（以可移植或原生格式）
first, last | - | 一对指定表示路径名的多字符序列的老式输入迭代器 (LegacyInputIterator)
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- InputIt 的 value_type 必须是编码字符（ char 、 wchar_t 、 char16_t 及 char32_t ）类型之一

返回值

*this

异常

若内存分配失败则可能抛出 std::bad_alloc 。

注意

这些函数等效地生成以 *this 为起始目录的环境中，参数路径 p 的含义估计。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
    fs::path p1 = "C:";
    p1 /= "Users"; // 不插入分隔符
    std::cout << "\"C:\" / \"Users\" == " << p1 << '\n';
    p1 /= "batman"; // 插入 fs::path::preferred_separator ，在 Windows 上为 '\'
    std::cout << "\"C:\" / \"Users\" / \"batman\" == " << p1 << '\n';
}

可能的输出：

"C:" / "Users" == "C:Users"
"C:" / "Users" / "batman" == "C:Users\batman"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3244 | C++17 | 缺失 Source 不能为 path 的制约 | 已添加

参阅

concatoperator+= | 连接二个路径而不加入目录分隔符 (公开成员函数)
operator/ | 用目录分隔符连接二个路径 (函数)


std::filesystem::path::assign

< cpp‎ | filesystem‎ | path
path& assign( string_type&& source ); | (1) | (C++17 起)
template< class Source > path& assign( const Source& source ); | (2) | (C++17 起)
template< class InputIt > path& assign( InputIt first, InputIt last ); | (3) | (C++17 起)

以从给定字符序列构造的新路径替换 path 对象的内容。

1) 以受检测格式字符串 source 所标识的路径名赋值，字符串留在合法但未指定的状态。
2) 以受检测格式的字符范围 source 所标识的路径名赋值。
3) 以受检测格式字符范围 [first, last) 所标识的路径名赋值。

(2) 仅若 Source 与 path 不是同一类型，而且：

  • Source 是 std::basic_string 或 std::basic_string_view 的特化，或
  • std::iterator_traits < std::decay_t <Source>>::value_type 合法并代表可能有 const 限定的编码字符类型（ char 、 char8_t 、 (C++20 起)char16_t 、 char32_t 或 wchar_t ）

才参与重载决议

参数

source | - | 所用的字符范围，表示为 std::basic_string 、 std::basic_string_view 、指向空终止字符/宽字符串的指针，或是一个指向空终止字符/宽字符序列的输入迭代器
first, last | - | 所用的字符范围
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- InputIt 的 value_type 必须是编码字符类型（ char 、 wchar_t 、 char16_t 及 char32_t ）之一

返回值

*this

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3244 | C++17 | 缺失 Source 不能为 path 的制约 | 已添加

参阅

operator=
 赋值另一个路径
(公开成员函数)


std::filesystem::path::begin, std::filesystem::path::end

< cpp‎ | filesystem‎ | path
iterator begin() const; | (1) | (C++17 起)
iterator end() const; | (2) | (C++17 起)
1) 返回指向路径首元素的迭代器。若路径为空，则返回的迭代器等于 end() 。
2) 返回路径最后元素后一位的迭代器。解引用此迭代器是未定义行为。

这对迭代器所指代的序列由下列内容组成：

  1. 根名 （若存在）
  2. 根目录 （若存在）
  3. 文件名 的序列，忽略任何目录分隔符
  4. 若在路径最后的 文件名 后有目录分隔符，则尾迭代器前的最后元素是空元素。

参数

（无）

返回值

1) 指向路径首元素的迭代器。
2) 路径结束后一位的迭代器。

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    const fs::path p =
#   ifdef _WIN32
        "C:\\users\\abcdef\\AppData\\Local\\Temp\\";
#   else
        "/home/user/.config/Cppcheck/Cppcheck-GUI.conf";
#   endif
    std::cout << "Examining the path " << p << " through iterators gives\n";
    for (auto it = p.begin(); it != p.end(); ++it)
        std::cout << *it << " │ ";
    std::cout << '\n';
}

可能的输出：

--- Windows ---
Examining the path "C:\users\abcdef\AppData\Local\Temp\" through iterators gives
"C:" │ "/" │ "users" │ "abcdef" │ "AppData" │ "Local" │ "Temp" │ "" │

--- UNIX ---
Examining the path "/home/user/.config/Cppcheck/Cppcheck-GUI.conf" through iterators gives
"/" │ "home" │ "user" │ ".config" │ "Cppcheck" │ "Cppcheck-GUI.conf" │


std::filesystem::path::clear

< cpp‎ | filesystem‎ | path
void clear() noexcept; | (C++17 起)

清空存储的路径名。调用后 empty() 为 true 。

参数

（无）

返回值

（无）


std::filesystem::path::compare

< cpp‎ | filesystem‎ | path
int compare( const path& p ) const noexcept;
 (1) (C++17 起)
int compare( const string_type& str ) const;
int compare( std::basic_string_view <value_type> str ) const;
 (2) (C++17 起)
int compare( const value_type* s ) const;
 (3) (C++17 起)

比较 path 与另一 path 的字典表示。

1) 若 root_name().native().compare(p.root_name().native()) 非零，则返回该值。
否则若 has_root_directory() != p.has_root_directory() ，则若 has_root_directory() 为 false 则返回小于零的值，否则返回大于零的值。
否则返回比较小于、等于或大于 0 的值，若 path 的相对部分 (relative_path()) 分别按字典序小于、等于或大于 p 的相对部分 (p.relative_path()) 。逐元素进行比较，如同从begin() 到 end() 迭代 path 。
2) 等价于 compare(path(str)) 。
3) 等价于 compare(path(s)) 。

参数

p | - | 要比较的 path
str | - | 表示要比较的表示路径的字符串或字符串视图
s | - | 表示要比较的路径的空终止字符串

返回值

若 path 按字典序小于给定 path 则为小于 0 的值。

若 path 按字典序等于给定 path 则为等于 0 的值。

若 path 按字典序大于给定 path 则为大于 0 的值。

异常

2-3) 可能抛出实现定义的异常。

注解

对于双路比较，二元运算符可能更适合。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
void demo(int rc, fs::path p1, fs::path p2) {
    if(rc < 0) std::cout << p1 << " < " << p2 << '\n';
    else if(rc > 0) std::cout << p1 << " > "  << p2 << '\n';
    else if(rc == 0) std::cout << p1 << " == " << p2 << '\n';
}
int main() {
    fs::path p1 = "/a/b/"; // 对于字典序迭代如同 "/a/b"
    fs::path p2 = "/a/b/c";
    demo(p1.compare(p2), p1, p2);
    demo(p1.compare("a/c"), p1, "a/c"); // 绝对路径先序于相对路径
}

输出：

"/a/b/" < "/a/b/c"
"/a/b/" > "a/c"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2936 | C++17 | 直接比较所有路径元素 | 分开处理根名与根目录

参阅

operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 前)(C++20 前)(C++20 前)(C++20 前)(C++20 前)(C++20)
 以字典序比较二个路径
(函数)


std::filesystem::path::concat, std::filesystem::path::operator+=

< cpp‎ | filesystem‎ | path
path& operator+=( const path& p );
 (1) (C++17 起)
path& operator+=( const string_type& str );
path& operator+=( std::basic_string_view <value_type> str );
 (2) (C++17 起)
path& operator+=( const value_type* ptr );
 (3) (C++17 起)
path& operator+=( value_type x );
 (4) (C++17 起)
template< class CharT >
path& operator+=( CharT x );
 (5) (C++17 起)
template< class Source >
path& operator+=( const Source& source );
 (6) (C++17 起)
template< class Source >
path& concat( const Source& source );
 (7) (C++17 起)
template< class InputIt >
path& concat( InputIterator first, InputIterator last );
 (8) (C++17 起)

连接当前路径与参数。

1-3,6-7) 后附 path(other).native() 到以原生格式存储于 *this 的路径名。这会直接操纵 native() 的值，并且可能无法在操作系统间移植。
4-5) 同 return *this += std::basic_string_view (&x, 1);
8) 同 return *this += path(first, last);

(6) 与 (7) 仅若 Source 与 path 不是同一类型，而且：

  • Source 是 std::basic_string 或 std::basic_string_view 的特化，或
  • std::iterator_traits < std::decay_t <Source>>::value_type 合法并代表可能有 const 限定的编码字符类型（ char 、 char8_t 、 (C++20 起)char16_t 、 char32_t 或 wchar_t ）

才参与重载决议

参数

p | - | 要附加的路径
str | - | 要附加的字符串或字符串视图
ptr | - | 指向要附加的空终止字符串起始的指针
x | - | 要附加的单个字符
source | - | std::basic_string 、 std::basic_string_view 、空终止多字符字符串或指向空终止多字符序列的输入迭代器，它表示路径名（以可执行或原生格式）
first, last | - | 一对指定代表路径名的字符序列的老式输入迭代器 (LegacyInputIterator)
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- InputIt 的 value_type 必须是编码字符类型（char 、 wchar_t 、 char16_t 及 char32_t）之一
- CharT 必须是编码字符类型（char 、 wchar_t 、 char16_t 及 char32_t）之一

返回值

*this

异常

若内存分配失败则可能抛出 std::bad_alloc 。

注解

不同于 append() 或 operator/= ，决不放入附加的分隔符。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main() {
    fs::path p1; // 空路径
    p1 += "var"; // 不插入分隔符
    std::cout << "\"\" + \"var\" == " << p1 << '\n';
    p1 += "lib"; // does not insert a separator
    std::cout << "\"\" + \"var\" + \"lib\" == " << p1 << '\n';
}

输出：

"" + "var" == "var"
"" + "var" + "lib" == "varlib"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3055 | C++17 | 连接单个字符的规定为谬构 | 使之为良构
LWG 3244 | C++17 | 缺失 Source 不能为 path 的制约 | 已添加

参阅

appendoperator/= | 添加元素到带目录分隔符的路径 (公开成员函数)
operator/ | 用目录分隔符连接二个路径 (函数)


std::filesystem::path::empty

< cpp‎ | filesystem‎ | path
bool empty() const noexcept; | (C++17 起) (C++20 前)
[[nodiscard]] bool empty() const noexcept; | (C++20 起)

检查通用格式的路径是否为空。

参数

（无）

返回值

若路径为空则为 true ，否则为 false 。

注意

可以通过调用 clear 和默认构造 path 获得空路径。若对应组分不存在于路径中，则路径分解函数（如 extension ）亦可以返回空路径。

空路径被分类为相对路径。

参阅

(构造函数)
 构造一个 path
(公开成员函数)


std::filesystem::path::extension

< cpp‎ | filesystem‎ | path
path extension() const; | (C++17 起)

返回 *this 的通用格式视图的文件名的扩展名。

若通用格式路径的 filename() 组分含有句号（ . ），且不是特殊文件系统元素 dot 或 dot-dot 之一，则扩展名是从最右的句号开始（含句号）到路径名尾的子串。

若文件名的首个字符是句号，则忽略该句号（类似 ".profile" 的文件名不被当做扩展名）

若路径名是 . 或 .. ，或若 filename() 不含有 . 字符，则返回空路径。

实现可以为添加了附加元素到扩展名的文件系统定义附加行为（例如作为另一种数据流或带分区数据集的名称）。

参数

（无）

返回值

当前路径名的扩展名，或若无扩展名则为空路径。

异常

可能抛出实现定义的异常。

注解

此函数返回的扩展名包含点，令程序可以分辨以点结束的文件（函数返回 "." ）和无扩展名的文件（函数返回 "" ）

在非 POSIX 系统上，可能有 p.stem()+p.extension() != p.filename() ，即使通用格式版本是相同的。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    std::cout
        << fs::path("/foo/bar.txt").extension() << '\n'
        << fs::path("/foo/bar.").extension() << '\n'
        << fs::path("/foo/bar").extension() << '\n'
        << fs::path("/foo/bar.txt/bar.cc").extension() << '\n'
        << fs::path("/foo/bar.txt/bar.").extension() << '\n'
        << fs::path("/foo/bar.txt/bar").extension() << '\n'
        << fs::path("/foo/.").extension() << '\n'
        << fs::path("/foo/..").extension() << '\n'
        << fs::path("/foo/.hidden").extension() << '\n'
        << fs::path("/foo/..bar").extension() << '\n'
        << fs::path("/foo/bar.txt.bak").extension() << '\n'
    ;

}

输出：

".txt"
"."
""
".cc"
"."
""
""
""
""
".bar"
".bak"

参阅

filename | 返回文件名路径组分 (公开成员函数)
stem | 返回主干路径组分 (公开成员函数)
replace_extension | 替换扩展名 (公开成员函数)
has_extension | 检查对应路径元素是否非空 (公开成员函数)


std::filesystem::path::filename

< cpp‎ | filesystem‎ | path
path filename() const; | (C++17 起)

返回路径的通用格式文件名组分。

等价于 relative_path().empty() ? path() : *--end() 。

参数

（无）

返回值

path 所标识的文件名。

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    std::cout << fs::path("/foo/bar.txt").filename() << '\n'
              << fs::path("/foo/.bar").filename() << '\n'
              << fs::path("/foo/bar/").filename() << '\n'
              << fs::path("/foo/.").filename() << '\n'
              << fs::path("/foo/..").filename() << '\n'
              << fs::path(".").filename() << '\n'
              << fs::path("..").filename() << '\n'
              << fs::path("/").filename() << '\n'
              << fs::path("//host").filename() << '\n';
}

可能的输出：

"bar.txt"
".bar"
""
"."
".."
"."
".."
""
"host"

参阅

extension | 返回文件扩展名路径组分 (公开成员函数)
stem | 返回主干路径组分 (公开成员函数)
replace_filename | 以另一路径替换最末的路径组分 (公开成员函数)
has_filename | 检查对应路径元素是否非空 (公开成员函数)


std::filesystem::path::format

< cpp‎ | filesystem‎ | path
enum format { native_format, generic_format, auto_format }; | (C++17 起)

确定路径名的字符串表示如何为接受字符串的 std::filesystem::path 构造函数所转译。

常量

定义于头文件 <filesystem>
值 | 解释
native_format | 原生路径名格式
generic_format | 通用路径名格式
auto_format | 实现定义路径名格式，可行的场合自动检测

注意

在 POSIX 系统上，原生与通用格式无区别。

参阅

(构造函数)
 构造一个 path
(公开成员函数)


std::filesystem::path::generic_string, std::filesystem::path::generic_wstring, std::filesystem::path::generic_u8string, std::filesystem::path::generic_u16string, std::filesystem::path::generic_u32string

< cpp‎ | filesystem‎ | path
template< class CharT, class Traits = std::char_traits <CharT>,

class Alloc = std::allocator <CharT> >
std::basic_string <CharT, Traits, Alloc>

generic_string( const Alloc& a = Alloc() ) const;
 (1) (C++17 起)
(2) (C++17 起)
std::string generic_string() const;
std::wstring generic_wstring() const;
std::u16string generic_u16string() const;
std::u32string generic_u32string() const;
(3)
std::string generic_u8string() const;
 (C++17 起)
(C++20 前)
std::u8string generic_u8string() const;
 (C++20 起)

返回通用路径名格式的内部路径名，转换到指定的字符串格式。若存在转换，则按下列方式进行：

  • 若 path::value_type 是 char ，若转换存在，则转换是依赖系统的。这是在典型 POSIX 系统（例如 Linux ）上的情形，其中原生字符编码是 UTF-8 且 string() 不进行转换。
  • 否则，若 path::value_type 是 wchar_t ，若转换存在，则是未指定的。这是在 Windows 上的情形，其中 wchar_t 为 16 位且原生编码为 UTF-16 。
  • 否则，若 path::value_type 是 char16_t ，则原生编码是 UTF-16 而转换方法未指定。
  • 否则，若 path::value_type 是 char32_t ，则原生编码是 UTF-32 而转换方法未指定。
  • 否则，若 path::value_type 是 char8_t ，则原生编码是 UTF-8 而转换方法未指定。

以 / 字符为作目录分隔符。

1) 所有内存分配由 a 进行。
3) u8string() 情形下结果的编码始终是 UTF-8 。

参数

a - 构造字符串用的分配器
类型要求
-
CharT 必须是编码字符类型之一（ char、 wchar_t、 char8_t (C++20 起)、 char16_t 及 char32_t ）

返回值

通用路径名格式的内部路径名，转换到指定的字符串类型。

异常

可能抛出实现定义的异常。

示例

#include <cstddef>
#include <filesystem>
#include <iomanip>
#include <iostream>
#include <span>
#include <string_view>

void print(std::string_view rem, auto const& str) {
    std::cout << rem << std::hex << std::uppercase << std::setfill('0');
    for (const auto b : std::as_bytes(std::span{str})) {
        std::cout << std::setw(2) << std::to_integer<unsigned>(b) << ' ';
    }
    std::cout << '\n';
}

int main()
{
    std::filesystem::path p{"/家/屋"};
    std::cout << p << '\n';

    print("string    : ", p.generic_string   ());
    print("u8string  : ", p.generic_u8string ());
    print("u16string : ", p.generic_u16string());
    print("u32string : ", p.generic_u32string());
//  print("wstring   : ", p.generic_wstring  ());
//  gcc-11.0.0 2020.12.30 仍然失败， clang-10 - ok
}

可能的输出：

"/家/屋"
string    : 2F E5 AE B6 2F E5 B1 8B
u8string  : 2F E5 AE B6 2F E5 B1 8B
u16string : 2F 00 B6 5B 2F 00 4B 5C
u32string : 2F 00 00 00 B6 5B 00 00 2F 00 00 00 4B 5C 00 00

参阅

stringwstringu8stringu16stringu32string
 返回转换到字符串的原生路径名格式
(公开成员函数)


std::filesystem::path::has_root_path, std::filesystem::path::has_root_name, std::filesystem::path::has_root_directory, std::filesystem::path::has_relative_path, std::filesystem::path::has_parent_path, std::filesystem::path::has_filename, std::filesystem::path::has_stem, std::filesystem::path::has_ex

std::filesystem::path::has_root_path, std::filesystem::path::has_root_name, std::filesystem::path::has_root_directory, std::filesystem::path::has_relative_path, std::filesystem::path::has_parent_path, std::filesystem::path::has_filename, std::filesystem::path::has_stem, std::filesystem::path::has_extension

< cpp‎ | filesystem‎ | path
bool has_root_path() const; | (1) | (C++17 起)
bool has_root_name() const; | (2) | (C++17 起)
bool has_root_directory() const; | (3) | (C++17 起)
bool has_relative_path() const; | (4) | (C++17 起)
bool has_parent_path() const; | (5) | (C++17 起)
bool has_filename() const; | (6) | (C++17 起)
bool has_stem() const; | (7) | (C++17 起)
bool has_extension() const; | (8) | (C++17 起)

检查路径是否含有相应路径元素。

1) 检查 root_path() 是否为空。
2) 检查 root_name() 是否为空。
3) 检查 root_directory() 是否为空。
4) 检查 relative_path() 是否为空。
5) 检查 parent_path() 是否为空。
6) 检查 filename() 是否为空。
7) 检查 stem() 是否为空。
8) 检查 extension() 是否为空。

参数

（无）

返回值

若对应路径组分为非空则返回 true ，否则返回 false 。

异常

可能抛出实现定义的异常。

参阅

empty
 检查路径是否为空
(公开成员函数)


std::filesystem::hash_value

< cpp‎ | filesystem‎ | path
定义于头文件 <filesystem> |
std::size_t hash_value( const std::filesystem::path & p ) noexcept; | (C++17 起)

参数

p - std::filesystem::path 对象

返回值

哈希值，满足若对于二个路径有 {c|1=p1 == p2}} 则 hash_value(p1) == hash_value(p2) 。

注解

二个路径的相等是分离比较每个组分来确定的，故例如 "a//b" 等于 "a/b" 且拥有相同的 hash_value 。

hash_value 源于 Boost.filesystem 库，其中它因与 boost.hash （在可用处调用实参依赖查找所找到的 hash_value 或 boost::hash_value ）的互动能力得到使用。

示例

#include <cassert>
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <filesystem>
#include <unordered_set>
namespace fs = std::filesystem;

void show_hash(fs::path const& p)
{
    std::cout << std::hex << std::uppercase << std::setw(16)
              << fs::hash_value(p) << " : " << p << '\n';
}

int main()
{
    auto tmp1 = fs::path{"/tmp"};
    auto tmp2 = fs::path{"/tmp/../tmp"};
    assert( ! (tmp1 == tmp2) );
    assert( fs::equivalent(tmp1, tmp2) );
    show_hash( tmp1 );
    show_hash( tmp2 );

    for (auto s : {"/a///b", "/a//b", "/a/c", "...", "..", ".", ""})
        show_hash(s);

    // A hash function object to work with unordered_* containers:
    struct PathHash {
        std::size_t operator()(fs::path const& p) const noexcept {
            return fs::hash_value(p);
        }
    };
    std::unordered_set<fs::path, PathHash> dirs {
        "/bin", "/bin", "/lib", "/lib", "/opt", "/opt", "/tmp", "/tmp/../tmp"
    };
    for (fs::path const& p: dirs) { std::cout << p << ' '; }
}

可能的输出：

6050C47ADB62DFE5 : "/tmp"
62795A58B69AD90A : "/tmp/../tmp"
FF302110C9991974 : "/a///b"
FF302110C9991974 : "/a//b"
FD6167277915D464 : "/a/c"
C42040F82CD8B542 : "..."
D2D30154E0B78BBC : ".."
D18C722215ED0530 : "."
               0 : ""
"/tmp/../tmp" "/opt" "/lib" "/tmp" "/bin"

参阅

compare | 以字典序比较二个路径的字典表示 (公开成员函数)
operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 前)(C++20 前)(C++20 前)(C++20 前)(C++20 前)(C++20) | 以字典序比较二个路径 (函数)
equivalent (C++17) | 检查两个路径是否指代同一文件系统对象 (函数)
hash (C++11) | 散列函数对象 (类模板)


std::filesystem::path::is_absolute,is_relative

< cpp‎ | filesystem‎ | path
bool is_absolute() const; | (1) | (C++17 起)
bool is_relative() const; | (2) | (C++17 起)

检查路径是绝对还是相对。绝对路径是无歧义地标识文件位置，无需到另外的起始位置的引用的路径。若原生格式路径为绝对，则首个版本返回 true ，否则返回 false ；第二版本相反。

参数

（无）

返回值

1) 若 path 为绝对则为 true ，否则为 false 。
2) 若 path 为绝对则为 false ，否则为 true 。

异常

可能抛出实现定义的异常。

注解

路径 "/" 在 POSIX OS 上是绝对的，但在 Windows 上是相对的。

参阅

absolute
(C++17)
 组成一个绝对路径
(函数)


std::filesystem::path::lexically_normal, std::filesystem::path::lexically_relative, std::filesystem::path::lexically_proximate

< cpp‎ | filesystem‎ | path
path lexically_normal() const; | (1) | (C++17 起)
path lexically_relative(const path& base) const; | (2) | (C++17 起)
path lexically_proximate(const path& base) const; | (3) | (C++17 起)
1) 返回以其通用格式转换成正规形式的 *this
2) 返回设为相对 base 的 *this 。
  • 首先，若 root_name() != base.root_name() 为 true 或 is_absolute() != base.is_absolute() 为 true 或 (!has_root_directory() && base.has_root_directory()) 为 true 或 relative_path() 或 base.relative_path() 中的任何文件名能转译为 根名, ，则返回默认构造的 path 。
  • 否则，首先确定 *this 和 base 的首个不匹配元素，如同以 auto [a, b] = mismatch(begin(), end(), base.begin(), base.end()) ，然后
  • 若 a == end() 且 b == base.end() ，则返回 path(".") ；
  • 否则，定义 N 为 [b, base.end()) 中既非 dot 亦非 dot-dot 的非空文件名元素数减去 dot-dot 文件名元素数。若 N < 0 则返回默认构造的 path 。
  • 否则，若 N = 0 且 a == end() || a->empty() ，则返回 path(".") 。
  • 否则返回由以下方式合成的对象
  • 默认构造 path() 后
  • 应用 N 次 operator/=(path("..")) ，之后
  • 对半开范围 [a, end()) 中的每个元素应用一次 operator/=
3) 若 lexically_relative(base) 的值不是空路径，则返回它。否则返回 *this 。

参数

（无）

返回值

1) 路径的正规形式
2) 路径的相对形式
3) 路径的近似形式

异常

可能抛出实现定义的异常。

注解

这些转换是纯文字的。它们不检查路径是否存在，不跟随符号链接，且完全不访问文件系统。关于 lexically_relative 与 lexically_proximate 跟随符号链接的对应版本，见 relative 与 proximate 。

Windows 上返回路径拥有反斜杠（偏好分隔符）。

POSIX 上相对路径中的文件名均不可接受为 根名 。

示例

#include <iostream>
#include <filesystem>
#include <cassert>
namespace fs = std::filesystem;

int main()
{
    assert(fs::path("foo/./bar/..").lexically_normal() == "foo/");
    assert(fs::path("foo/.///bar/../").lexically_normal() == "foo/");

    assert(fs::path("/a/d").lexically_relative("/a/b/c") == "../../d");
    assert(fs::path("/a/b/c").lexically_relative("/a/d") == "../b/c");
    assert(fs::path("a/b/c").lexically_relative("a") == "b/c");
    assert(fs::path("a/b/c").lexically_relative("a/b/c/x/y") == "../..");
    assert(fs::path("a/b/c").lexically_relative("a/b/c") == ".");
    assert(fs::path("a/b").lexically_relative("c/d") == "../../a/b");
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3070 | C++17 | 亦能为根名的文件名可能导致诧异的结果 | 当作错误情况
LWG 3096 | C++17 | 错误地处理了尾随 "/" 和 "/." | 已更正

参阅

relativeproximate
(C++17)
 组成一个相对路径
(函数)


std::filesystem::path::make_preferred

< cpp‎ | filesystem‎ | path
path& make_preferred(); | (C++17 起)

将路径的通用格式视图中的所有目录分隔符转换成偏好目录分隔符。

例如，在 Windows 上 \ 是偏好分隔符， foo/bar 将被转换为 foo\bar 。

参数

（无）

返回值

*this

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

本节未完成


std::filesystem::path::c_str, std::filesystem::path::native, std::filesystem::path::operator string_type()

< cpp‎ | filesystem‎ | path
const value_type* c_str() const noexcept; | (1) | (C++17 起)
const string_type& native() const noexcept; | (2) | (C++17 起)
operator string_type() const; | (3) | (C++17 起)

访问作为字符串的原生路径名。

1) 等价于 native().c_str() 。
2) 以引用返回路径名的原生格式表示。
3) 以值返回路径名的原生格式表示。

参数

（无）

返回值

路径名的原生格式表示，使用原生语法、原生字符类型，及原生字符编码。此字符串适用于 OS API 。

注意

提供转换函数 (3) 以令接受 std::basic_string 文件名的 API 能使用路径名而无需更改代码。

示例

#include <cstdio>
#ifdef _MSC_VER
#include <io.h>
#include <fcntl.h>
#else
#include <locale>
#include <clocale>
#endif
#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
#ifdef _MSC_VER
    _setmode(_fileno(stderr), _O_WTEXT);
#else
    std::setlocale(LC_ALL, "");
    std::locale::global(std::locale(""));
    std::cout.imbue(std::locale());
    std::wcerr.imbue(std::locale());
#endif

    fs::path p = fs::u8path(u8"要らない.txt");
    std::ofstream(p) << "File contents"; // 在 LWG2676 前 MSVC 上使用 operator string_type()
                                         // ，其中 string_type 是 wstring ，仅根据非标准扩展工作
                                         // LWG2676 后使用新的 fstream 构造函数

    // 原生字符串表示可用于 OS API
    if (std::FILE* f =
#ifdef _MSC_VER
                _wfopen(p.c_str(), L"r")
#else
                std::fopen(p.c_str(), "r")
#endif
        )
    {
        int ch;
        while((ch=fgetc(f))!= EOF) putchar(ch);
        std::fclose(f);
    }

    // 多字节与宽字节表示可用于输出
    std::cout << "\nFile name in narrow multibyte encoding: " << p.string() << '\n';
    std::wcerr << "File name in wide encoding: " << p.wstring() << '\n';

    fs::remove(p);
}

输出：

File contents
File name in narrow multibyte encoding: 要らない.txt
File name in wide encoding: 要らない.txt

参阅

stringwstringu8stringu16stringu32string | 返回转换到字符串的原生路径名格式 (公开成员函数)
generic_stringgeneric_wstringgeneric_u8stringgeneric_u16stringgeneric_u32string | 返回转换到字符串的通用路径名格式 (公开成员函数)


std::filesystem::path::operator=

< cpp‎ | filesystem‎ | path
path& operator=( const path& p ); | (1) | (C++17 起)
path& operator=( path&& p ) noexcept; | (2) | (C++17 起)
path& operator=(string_type&& source); | (3) | (C++17 起)
template< class Source > path& operator=( const Source& source ); | (4) | (C++17 起)
1) 以原生和通用格式均与 p 相同的路径名替换 *this 的内容。
2) 以原生和通用格式均与 p 相同的路径名替换 *this 的内容，可能使用移动语义： p 留在合法但未指定的状态。
3) 以从受检测格式的 source 构造的新 path 值替换 *this 的内容。 source 留合法但未指定的状态。等价于 assign(source) 。
4) 从受检测格式的 source ，如同以 path 构造函数的重载 (4) 构造的新 path 值替换 *this 的内容。等价于 assign(source) 。

(4) 仅若 Source 与 path 不是同一类型，而且：

  • Source 是 std::basic_string 或 std::basic_string_view 的特化，或
  • std::iterator_traits < std::decay_t <Source>>::value_type 合法并代表可能有 const 限定的编码字符类型（ char 、 char8_t 、 (C++20 起)char16_t 、 char32_t 或 wchar_t ）

才参与重载决议

参数

p | - | 要赋值的路径
source | - | std::basic_string 、 std::basic_string_view 、指向空终止字符/宽字符串的指针，或指向空终止字符/宽字符序列的输入迭代器。字符类型必须是 char 、char8_t (C++20 起) 、 char16_t 、 char32_t 、 wchar_t 之一

返回值

*this

参阅

#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    fs::path p = "C:/users/abcdef/AppData/Local";
    p = p / "Temp"; // 移动赋值
    const wchar_t* wstr = L"D:/猫.txt";
    p = wstr; // 从源赋值
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3244 | C++17 | 缺失 Source 不能为 path 的制约 | 已添加

参阅

assign | 赋值内容 (公开成员函数)
(构造函数) | 构造一个 path (公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::filesystem::path)

< cpp‎ | filesystem‎ | path
friend bool operator==( const path& lhs, const path& rhs ) noexcept;
 (1) (C++17 起)
friend bool operator!=( const path& lhs, const path& rhs ) noexcept;
 (2) (C++17 起)
(C++20 前)
friend bool operator<( const path& lhs, const path& rhs ) noexcept;
 (3) (C++17 起)
(C++20 前)
friend bool operator<=( const path& lhs, const path& rhs ) noexcept;
 (4) (C++17 起)
(C++20 前)
friend bool operator>( const path& lhs, const path& rhs ) noexcept;
 (5) (C++17 起)
(C++20 前)
friend bool operator>=( const path& lhs, const path& rhs ) noexcept;
 (6) (C++17 起)
(C++20 前)
friend std::strong_ordering
operator<=>( const path& lhs, const path& rhs ) noexcept;
 (7) (C++20 起)

以字典序比较二个path 。

1) 检查 lhs 与 rhs 是否相等。等价于 !(lhs < rhs) && !(rhs < lhs) 。
2) 检查 lhs 与 rhs 是否不相等，等价于 !(lhs == rhs) 。
3) 检查 lhs 是否小于 rhs 。等价于 lhs.compare(rhs) < 0 。
4) 检查 lhs 是否小于或等于 rhs 。等价于 !(rhs < lhs) 。
5) 检查 lhs 是否大于 rhs 。等价于 rhs < lhs 。
6) 检查 lhs 是否大于或等于 rhs 。等价于 !(lhs < rhs) 。
7) 获得 lhs 与 rhs 的三路比较结果。等价于 lhs.compare(rhs) <=> 0 。

这些函数对通常无限定或有限定查找不可见，而只能在 std::filesystem::path 为参数的关联类时由实参依赖查找找到。这阻止 using namespace std::filesystem; using 指令存在的情况下的不想要的转换。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的路径

返回值

1-6) 若对应比较关系成立则返回 true ，否则返回 false 。
7) 若 lhs 小于 rhs 则为 std::strong_ordering::less ，否则若 rhs 小于 lhs 则为 std::strong_ordering::greater ，否则为 std::string_ordering::equal 。

注解

路径相等与等价有不同语义。

相等情况下，以 operator== 确定，只比较字典表示。从而 path("a") == path("b") 决不可能为 true 。

等价情况下，以 std::filesystem::equivalent() 确定，检查二个路径是否解析到同一文件系统对象。从而若路径解析到同一文件，则 equivalent("a", "b") 将返回 true 。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3065 | C++17 | 允许 using 指令存在的情况下比较任何能转换成 path 的类型 | 使之为隐藏的友元

参阅

compare | 以字典序比较二个路径的字典表示 (公开成员函数)
equivalent (C++17) | 检查两个路径是否指代同一文件系统对象 (函数)


operator<<,>>(std::filesystem::path)

< cpp‎ | filesystem‎ | path
template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&

operator<<( std::basic_ostream <CharT,Traits>& os, const path& p );
 (1) (C++17 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&

operator>>( std::basic_istream <CharT,Traits>& is, path& p );
 (2) (C++17 起)

进行路径 p 上的流输入或输出。使用 std::quoted ，使得之后从流输入运算符读取时空格不导致截断。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::filesystem::path 为参数的关联类时由实参依赖查找找到。这在 using namespace std::filesystem; using 指令存在时阻止不想要的转换。

参数

os | - | 要进行输出的流
is | - | 要进行输入的流
p | - | 要插入或释出的路径

返回值

1) os
2) is

异常

可能抛出实现定义的异常。

可能的实现

版本一
template< class CharT, class Traits >
friend std::basic_ostream<CharT,Traits>&
    operator<<( std::basic_ostream<CharT,Traits>& os, const path& p )
{
    os << std::quoted(p.string<CharT,Traits>());
    return os;
}
版本二
template< class CharT, class Traits >
friend std::basic_istream<CharT,Traits>&
    operator>>( std::basic_istream<CharT,Traits>& is, path& p )
{
    std::basic_string<CharT, Traits> t;
    is >> std::quoted(t);
    p = t;
    return is;
}

示例

#include <iostream>
#include <filesystem>
int main()
{
    std::cout << std::filesystem::current_path() << '\n';
    std::cout << std::filesystem::temp_directory_path() << '\n';
}

可能的输出：

"/home/user"
"/tmp"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2989 | C++17 | 允许在 using 指令存在时插入任何能转换到 path 的表达式 | 使之为隐藏的友元


std::filesystem::operator/(std::filesystem::path)

< cpp‎ | filesystem‎ | path
friend path operator/( const path& lhs, const path& rhs ); | (C++17 起)

若适合（细节见 operator/= ），则以偏好目录分隔符连接二个路径组分。

等效于返回 path(lhs) /= rhs 。

此函数对通常无限定或有限定查找不可见，而只能在 std::filesystem::path 为参数的关联类时由实参依赖查找找到。这阻止存在 using namespace std::filesystem; using 指令情况下的不想要的转换。

参数

lhs, rhs - 要连接的路径

返回值

路径连接的结果。

示例

#include <iostream>
#include <filesystem>

int main() {
    std::filesystem::path p = "C:";
    std::cout << "\"C:\" / \"Users\" / \"batman\" == "
              << p / "Users" / "batman" << '\n';
}

可能的输出：

"C:" / "Users" / "batman" == "C:Users\batman"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3065 | C++17 | 允许存在 using 指令的情况下连接一切可转换成 path 的值 | 使之为隐藏友元

参阅

appendoperator/=
 添加元素到带目录分隔符的路径
(公开成员函数)


std::filesystem::path::parent_path

< cpp‎ | filesystem‎ | path
path parent_path() const; | (C++17 起)

返回到亲目录的路径。

若 has_relative_path() 返回 false ，则结果是 *this 的副本。否则结果是通用格式路径名为 *this 的通用路径名在其迭代中产生少一个元素的最长前缀。

参数

（无）

返回值

到亲目录的路径。

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    for(fs::path p : {"/var/tmp/example.txt", "/", "/var/tmp/."})
        std::cout << "The parent path of " << p
                  << " is " << p.parent_path() << '\n';
}

可能的输出：

The parent path of "/var/tmp/example.txt" is "/var/tmp"
The parent path of "/" is "/"
The parent path of "/var/tmp/." is "/var/tmp"


std::filesystem::path::path

< cpp‎ | filesystem‎ | path
path() noexcept; | (1) | (C++17 起)
path( const path& p ); | (2) | (C++17 起)
path( path&& p ) noexcept; | (3) | (C++17 起)
path( string_type&& source, format fmt = auto_format ); | (4) | (C++17 起)
template< class Source > path( const Source& source, format fmt = auto_format ); | (5) | (C++17 起)
template< class InputIt > path( InputIt first, InputIt last, format fmt = auto_format ); | (6) | (C++17 起)
template< class Source > path( const Source& source, const std::locale & loc, format fmt = auto_format ); | (7) | (C++17 起)
template< class InputIt > path( InputIt first, InputIt last, const std::locale & loc, format fmt = auto_format ); | (8) | (C++17 起)

构造新的 path 对象。

1) 构造空路径。
2) 复制构造函数。构造一个路径，其原生与通用格式的路径名均与 p 相同
3) 移动构造函数。构造一个路径，其原生与通用格式的路径名均与 p 相同， p 留在合法而未指定的状态。
4-6) 从 source (4,5) 提供的字符序列构造路径（按 fmt 的指定转译格式），源可以是一个指向空终值字符/宽字符序列的指针或输入迭代器、 std::basic_string 或 std::basic_string_view ，或作为一对输入迭代器 [first, last) 提供 (6) 。允许字符类型 char 、char8_t (C++20 起) 、 char16_t 、 char32_t 、 wchar_t ，而且原生字符集的转换方法依赖于 source 所用的字符类型
  • 若源字符类型是 char ，则源的编码假定为原生窄字符编码（故在 POSIX 系统上不用转换）
  • 若源字符类型是 char8_t ，则使用从 UTF-8 到原生文件系统编码的转换。
 (C++20 起)
  • 若源字符类型是 char16_t ，则使用从 UTF-16 到原生文件系统编码的转换。
  • 若源字符类型是 char32_t ，则使用从 UTF-32 到原生文件系统编码的转换。
  • 若源字符类型是 wchar_t ，则输入被假定为原生宽字符编码（故在 Windos 上不用转换）
7-8) 从 source (7) 提供的从字符序列构造路径（按 fmt 的指定转译格式），源可以是指向空终止字符序列的指针或输入迭代器、 std::string 、 std::basic_string_view ，或由一对输入迭代器 [first, last) (8) 所代表。仅允许的字符类型是 char 。用 loc 进行字符编码转换。若 value_type 是 wchar_t ，则使用 loc 的 std::codecvt <wchar_t, char, std::mbstate_t > 平面从宽字符转换。否则，首先用 std::codecvt <wchar_t, char, std::mbstate_t > 平面转换到宽字符，再用 loc 的 std::codecvt <wchar_t,value_type> 平面转换到文件系统原生字符类型。

(5) 与 (7) 仅若 Source 与 path 不是同一类型，而且：

  • Source 是 std::basic_string 或 std::basic_string_view 的特化，或
  • std::iterator_traits < std::decay_t <Source>>::value_type 合法并代表可能有 const 限定的编码字符类型（ char 、 char8_t 、 (C++20 起)char16_t 、 char32_t 或 wchar_t ）

才参与重载决议

参数

p | - | 要复制的路径
source | - | std::basic_string 、 std::basic_string_view ，指向空终止字符串的指针，或拥有字符 value_type 并指向空终止字符序列的的输入迭代器（对于重载 (6) 字符类型必须是 char ）
first, last | - | 一对指定字符序列的老式输入迭代器 (LegacyInputIterator)
fmt | - | path::format 类型的枚举项，指定路径名格式如何转译
loc | - | 定义编码转换所用的本地环境
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- InputIt 的 value_type 必须是字符类型 char 、char8_t (C++20 起) 、 wchar_t 、 char16_t 及 char32_t 之一，以使用重载 (6)
- InputIt 的 value_type 必须是 char ，以使用 (8)

异常

2, 4-8) 可能抛出实现定义的异常。

注解

关于从 Unicode 字符串生成可移植路径名，见 u8path 。 | (C++20 前)
源为 char8_t 的序列时， path 构造函数支持从 UTF-8 字符串创建。 | (C++20 起)

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    fs::path p1 = "/usr/lib/sendmail.cf"; // 可移植格式
    fs::path p2 = "C:\\users\\abcdef\\AppData\\Local\\Temp\\"; // 原生格式
    fs::path p3 = L"D:/猫.txt"; // 宽字符串

    std::cout << "p1 = " << p1 << '\n'
              << "p2 = " << p2 << '\n'
              << "p3 = " << p3 << '\n';
}

输出：

p1 = "/usr/lib/sendmail.cf"
p2 = "C:\users\abcdef\AppData\Local\Temp\"
p3 = "D:/猫.txt"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3244 | C++17 | 缺失 Source 不能为 path 的制约 | 已添加

参阅

u8path
(C++17)(C++20 中弃用)
 从 UTF-8 编码的源创建 path
(函数)


std::filesystem::path::relative_path

< cpp‎ | filesystem‎ | path
path relative_path() const; | (C++17 起)

返回相对于 根路径 的路径，即由 *this 在 根路径 后的每个通用格式路径组分组成的路径名。若 *this 是空路径，则返回空路径。

参数

（无）

返回值

相对于根路径的路径。

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    fs::path p = fs::current_path();

    std::cout << "The current path " << p << " decomposes into:\n"
              << "root-path " << p.root_path() << '\n'
              << "relative path " << p.relative_path() << '\n';
}

可能的输出：

The current path "C:\Users\abcdef\Local Settings\temp" decomposes into:
root-path "C:\"
relative path "Users\abcdef\Local Settings\temp"

参阅

root_name | 若存在则返回路径的根名 (公开成员函数)
root_directory | 若存在则返回路径的根目录 (公开成员函数)
root_path | 若存在则返回路径的根路径 (公开成员函数)


std::filesystem::path::remove_filename

< cpp‎ | filesystem‎ | path
path& remove_filename(); | (C++17 起)

从给定的通用格式路径移除单个通用格式文件名组分（由 filename 返回）。

此函数完成后， has_filename 返回 false 。

参数

（无）

返回值

*this

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{

    std::cout << fs::path("foo/bar").remove_filename() << '\n'
              << fs::path("foo/").remove_filename() << '\n'
              << fs::path("/foo").remove_filename() << '\n'
              << fs::path("/").remove_filename() << '\n';
}

输出：

"foo/"
"foo/"
"/"
"/"

参阅

filename | 返回文件名路径组分 (公开成员函数)
replace_filename | 以另一路径替换最末的路径组分 (公开成员函数)
has_filename | 检查对应路径元素是否非空 (公开成员函数)


std::filesystem::path::replace_extension

< cpp‎ | filesystem‎ | path
path& replace_extension( const path& replacement = path() ); | (C++17 起)

以 replacement 替换扩展名，或在使用 replacement 的默认值时移除它。

首先，若此路径拥有 extension() ，则首先从路径名的通用格式视角移除它。

然后若 replacement 非空且不以点字符开始，则添加点字符到路径名的通用格式视图。

然后如同用 operator+=(replacement) 后附 replacement 。

参数

replacement - 要替换的扩展名

返回值

*this

异常

可能抛出实现定义的异常。

注解

replacement 的类型是 std::filesystem::path ，即使并非有意用它表示文件系统上的对象，这是为了正确认定文件系统字符编码。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    fs::path p = "/foo/bar.jpeg";
    std::cout << "Was: " << p << '\n';
    p.replace_extension(".jpg");
    std::cout << "Now: " << p << '\n';
}

输出：

Was: "/foo/bar.jpeg"
Now: "/foo/bar.jpg"

参阅

extension | 返回文件扩展名路径组分 (公开成员函数)
filename | 返回文件名路径组分 (公开成员函数)
stem | 返回主干路径组分 (公开成员函数)
has_extension | 检查对应路径元素是否非空 (公开成员函数)


std::filesystem::path::replace_filename

< cpp‎ | filesystem‎ | path
path& replace_filename( const path& replacement ); | (C++17 起)

以 replacement 替换单个文件名组分。

等价于： remove_filename(); return operator/=(replacement); 。

参数

replacement - 用于替换文件名组分的 path

返回值

*this

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{

    std::cout << fs::path("/foo").replace_filename("bar") << '\n'
              << fs::path("/").replace_filename("bar") << '\n';
}

输出：

"/bar"
"bar"

参阅

replace_extension | 替换扩展名 (公开成员函数)
filename | 返回文件名路径组分 (公开成员函数)
remove_filename | 移除文件名路径组分 (公开成员函数)
has_filename | 检查对应路径元素是否非空 (公开成员函数)


std::filesystem::path::root_directory

< cpp‎ | filesystem‎ | path
path root_directory() const; | (C++17 起)

返回通用格式路径的根目录。若路径（以通用格式）不包含根目录，则返回 path() 。

参数

（无）

返回值

路径的根目录。

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    fs::path p = fs::current_path();

    std::cout << "The current path " << p << " decomposes into:\n"
              << "root name " << p.root_name() << '\n'
              << "root directory " << p.root_directory() << '\n'
              << "relative path " << p.relative_path() << '\n';
}

可能的输出：

The current path "C:\Users\abcdef\Local Settings\temp" decomposes into:
root name "C:"
root directory "\"
relative path "Users\abcdef\Local Settings\temp"

参阅

root_name | 若存在则返回路径的根名 (公开成员函数)
root_path | 若存在则返回路径的根路径 (公开成员函数)


std::filesystem::path::root_name

< cpp‎ | filesystem‎ | path
path root_name() const; | (C++17 起)

返回通用格式路径的根名。若路径（以通用格式）不包含根名，则返回 path() 。

参数

（无）

返回值

路径的根名。

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    std::cout << "Current root name is: " << fs::current_path().root_name() << '\n';
}

可能的输出：

Current root name is: "C:"

参阅

root_directory | 若存在则返回路径的根目录 (公开成员函数)
root_path | 若存在则返回路径的根路径 (公开成员函数)


std::filesystem::path::root_path

< cpp‎ | filesystem‎ | path
path root_path() const; | (C++17 起)

返回路径的根路径。若路径不包含根路径，则返回 path() 。

等效地返回 root_name() / root_directory() 。

参数

（无）

返回值

路径的根路径。

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    std::cout << "Current root path is: " << fs::current_path().root_path() << '\n';
}

可能的输出：

Current root path is: "C:\"

参阅

root_name | 若存在则返回路径的根名 (公开成员函数)
root_directory | 若存在则返回路径的根目录 (公开成员函数)


std::filesystem::path::stem

< cpp‎ | filesystem‎ | path
path stem() const; | (C++17 起)

返回通用格式路径所标识的文件名，剥去其扩展名。

返回从 filename() 的开始到不含最后一个句号（ . ）字符的子串，有下列例外：

若文件名的首字符是句号，则忽略该句号（类似 ".profile" 的文件名不被当做扩展名）

若文件名是特殊文件系统组分 dot 或 dot-dot ，或若它无句号，则函数返回整个 filename() 。

参数

（无）

返回值

路径所标识的文件名的主干。

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    std::cout << fs::path("/foo/bar.txt").stem() << '\n'
              << fs::path("/foo/.bar").stem() << '\n';

    for (fs::path p = "foo.bar.baz.tar"; !p.extension().empty(); p = p.stem())
        std::cout << p.extension() << '\n';
}

输出：

"bar"
".bar"
".tar"
".baz"
".bar"

参阅

filename | 返回文件名路径组分 (公开成员函数)
extension | 返回文件扩展名路径组分 (公开成员函数)


std::filesystem::path::string, std::filesystem::path::wstring, std::filesystem::path::u8string, std::filesystem::path::u16string, std::filesystem::path::u32string

< cpp‎ | filesystem‎ | path
template< class CharT, class Traits = std::char_traits <CharT>,

class Alloc = std::allocator <CharT> >
std::basic_string <CharT, Traits, Alloc>

string( const Alloc& a = Alloc() ) const;
 (1) (C++17 起)
(2) (C++17 起)
std::string string() const;
std::wstring wstring() const;
std::u16string u16string() const;
std::u32string u32string() const;
(3)
std::string u8string() const;
 (C++17 起)
(C++20 前)
std::u8string u8string() const;
 (C++20 起)

返回原生路径名格式的内部路径名，转换到指定的字符串类型。若存在转换，则按下列方式进行：

  • 若 path::value_type 是 char ，若转换存在，则转换是依赖系统的。这是在典型 POSIX 系统（例如 Linux ）上的情形，其中原生字符编码是 UTF-8 且 string() 不进行转换。
  • 否则，若 path::value_type 是 wchar_t ，若转换存在，则是未指定的。这是在 Windows 上的情形，其中 wchar_t 为 16 位且原生编码为 UTF-16 。
  • 否则，若 path::value_type 是 char16_t ，则原生编码是 UTF-16 而转换方法未指定。
  • 否则，若 path::value_type 是 char32_t ，则原生编码是 UTF-32 而转换方法未指定。
  • 否则，若 path::value_type 是 char8_t ，则原生编码是 UTF-8 而转换方法未指定。
1) 所有内存分配由 a 进行。
3) u8string() 情形的编码结果始终是 UTF-8 。

参数

（无）

返回值

转换到指定字符串类型的原生路径名格式的内部路径名。

异常

可能抛出实现定义的异常。

示例

#include <cstdio>
#ifdef _MSC_VER
#include <io.h>
#include <fcntl.h>
#else
#include <locale>
#include <clocale>
#endif
#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
#ifdef _MSC_VER
    _setmode(_fileno(stderr), _O_WTEXT);
#else
    std::setlocale(LC_ALL, "");
    std::locale::global(std::locale(""));
    std::cout.imbue(std::locale());
    std::wcerr.imbue(std::locale());
#endif

    fs::path p = fs::u8path(u8"要らない.txt");
    std::ofstream(p) << "File contents"; // 在 LWG2676 前 MSVC 上使用 operator string_type()
                                         // ，其中 string_type 是 wstring ，仅根据非标准扩展工作
                                         // LWG2676 后使用新的 fstream 构造函数

    // 原生字符串表示可用于 OS API
    if (std::FILE* f =
#ifdef _MSC_VER
                _wfopen(p.c_str(), L"r")
#else
                std::fopen(p.c_str(), "r")
#endif
        )
    {
        int ch;
        while((ch=fgetc(f))!= EOF) putchar(ch);
        std::fclose(f);
    }

    // 多字节与宽字节表示可用于输出
    std::cout << "\nFile name in narrow multibyte encoding: " << p.string() << '\n';
    std::wcerr << "File name in wide encoding: " << p.wstring() << '\n';

    fs::remove(p);
}

输出：

File contents
File name in narrow multibyte encoding: 要らない.txt
File name in wide encoding: 要らない.txt

参阅

generic_stringgeneric_wstringgeneric_u8stringgeneric_u16stringgeneric_u32string
 返回转换到字符串的通用路径名格式
(公开成员函数)


std::filesystem::path::swap

< cpp‎ | filesystem‎ | path
void swap( path& other ) noexcept; | (1) | (C++17 起)

交换 *this 与 other 的内容（原生与通用格式一同）。

参数

other - 要交换内容的另一个 path

返回值

（无）

复杂度

常数。

参阅

std::swap(std::filesystem::path)
 交换二个路径
(函数)


std::filesystem::swap(std::filesystem::path)

< cpp‎ | filesystem‎ | path
定义于头文件 <filesystem> |
void swap( std::filesystem::path & lhs, std::filesystem::path & rhs ) noexcept; | (C++17 起)

交换 lhs 与 rhs 的状态。等效于调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的 path

返回值

（无）

参阅

swap
 交换两个路径
(公开成员函数)


std::filesystem::u8path

< cpp‎ | filesystem‎ | path
定义于头文件 <filesystem> |  |
template< class Source > std::filesystem::path u8path( const Source& source ); | (1) | (C++17 起) (C++20 中弃用)
template< class InputIt > std::filesystem::path u8path( InputIt first, InputIt last ); | (2) | (C++17 起) (C++20 中弃用)

从 UTF-8 编码的 char 或 char8_t (C++20 起) 序列构造 path p ，源作为 std::string 或 std::string_view ，或空终止多字节字符串，或作为一对迭代器 [first, last) 提供。

  • 若 path::value_type 是 char 且原生编码为 UTF-8 ，则直接如同以 path(source) 或 path(first, last) 构造 path 。这是使用 Unicode 的 POSIX 系统的典型情况，例如 Linux 。
  • 否则，若 path::value_type 是 wchar_t 且原生编码是 UTF-16 （这是 Windows 上的情况），或若 path::value_type 是 char16_t （原生编码保证为 UTF-16 ）或 char32_t （原生编码保证为

UTF-32），则首先转换 UTF-8 字符序列为 path::string_type 类型的临时字符串 tmp ，然后如同以 path(tmp) 构造新 path

  • 否则（对于非 UTF-8 窄字符编码与非 UTF-16 wchar_t ），首先转换 UTF-8 字符序列到 std::u32string 类型的临时 UTF-32 编码字符串 tmp ，然后如同用 path(tmp) 构造新 path （此 path 被采用于使用非 Unicode 多字节或单字节编码的文件系统的 POSIX 系统上）

参数

source | - | UTF-8 编码的 std::string 、 std::string_view ，指向空终止多字节字符串的指针，或指向空终止多字节字符串的以 char 为 value_type 的输入迭代器
first, last | - | 一对指定 UTF-8 编码字符序列的老式输入迭代器 (LegacyInputIterator)
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- Source 或 InputIt 的值类型必须是 char 或 char8_t (C++20 起)

返回值

将输入字符串从 UTF-8 转换到文件系统原生字符编码后，构造的路径。

异常

若内存分配失败则可能抛出 std::bad_alloc 。

注解

在原生路径格式异于通用路径格式的系统上（ Windows 与 POSIX 均不是此种系统的例子），若此函数的参数使用通用格式，则它会被转换成原生格式。

示例

#include <cstdio>
#ifdef _MSC_VER
#include <io.h>
#include <fcntl.h>
#else
#include <locale>
#include <clocale>
#endif
#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
#ifdef _MSC_VER
    _setmode(_fileno(stderr), _O_WTEXT);
#else
    std::setlocale(LC_ALL, "");
    std::locale::global(std::locale(""));
    std::cout.imbue(std::locale());
    std::wcerr.imbue(std::locale());
#endif

    fs::path p = fs::u8path(u8"要らない.txt");
    std::ofstream(p) << "File contents"; // 在 LWG2676 前 MSVC 上使用 operator string_type()
                                         // ，其中 string_type 是 wstring ，仅根据非标准扩展工作
                                         // LWG2676 后使用新的 fstream 构造函数

    // 原生字符串表示可用于 OS API
    if (std::FILE* f =
#ifdef _MSC_VER
                _wfopen(p.c_str(), L"r")
#else
                std::fopen(p.c_str(), "r")
#endif
        )
    {
        int ch;
        while((ch=fgetc(f))!= EOF) putchar(ch);
        std::fclose(f);
    }

    // 多字节与宽字节表示可用于输出
    std::cout << "\nFile name in narrow multibyte encoding: " << p.string() << '\n';
    std::wcerr << "File name in wide encoding: " << p.wstring() << '\n';

    fs::remove(p);
}

输出：

File contents
File name in narrow multibyte encoding: 要らない.txt
File name in wide encoding: 要らない.txt

参阅

path
(C++17)
 表示路径
(类)


std::filesystem::path::~path

< cpp‎ | filesystem‎ | path
~path(); | (C++17 起)

销毁 path 对象。


std::filesystem::perm_options

< cpp‎ | filesystem
定义于头文件 <filesystem> |
enum class perm_options { replace = /* unspecified */, add = /* unspecified */, remove = /* unspecified */, nofollow = /* unspecified */ }; | (C++17 起)

此类型代表控制函数 permissions() 行为的可用选项。

perm_options 满足满足位掩码类型 (BitmaskType) 的要求（表示位运算符 operator& 、 operator| 、 operator^ 、 operator~ 、 operator&= 、 operator|= 及 operator^= 对此类型定义）

成员常量

add 、 remove 、 replace 至多可以存在一个，否则 permissions 函数的行为未定义。

成员常量 | 含义
replace | 以给 permissions() 的参数完全替换权限（默认行为）
add | 以当前权限和参数的逐位或替换权限
remove | 以当前权限和参数取反结果的逐位与替换权限
nofollow | permissions 将更改符号链接自身，而非其所代表的文件

示例

#include <fstream>
#include <bitset>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

void demo_perms(fs::perms p)
{
    std::cout << ((p & fs::perms::owner_read) != fs::perms::none ? "r" : "-")
              << ((p & fs::perms::owner_write) != fs::perms::none ? "w" : "-")
              << ((p & fs::perms::owner_exec) != fs::perms::none ? "x" : "-")
              << ((p & fs::perms::group_read) != fs::perms::none ? "r" : "-")
              << ((p & fs::perms::group_write) != fs::perms::none ? "w" : "-")
              << ((p & fs::perms::group_exec) != fs::perms::none ? "x" : "-")
              << ((p & fs::perms::others_read) != fs::perms::none ? "r" : "-")
              << ((p & fs::perms::others_write) != fs::perms::none ? "w" : "-")
              << ((p & fs::perms::others_exec) != fs::perms::none ? "x" : "-")
              << '\n';
}
int main()
{
    std::ofstream("test.txt"); // 创建文件

    std::cout << "Created file with permissions: ";
    demo_perms(fs::status("test.txt").permissions());

    fs::permissions("test.txt",
                    fs::perms::owner_all | fs::perms::group_all,
                    fs::perm_options::add);

    std::cout << "After adding o+rwx and g+rwx:  ";
    demo_perms(fs::status("test.txt").permissions());

    fs::remove("test.txt");
}

可能的输出：

Created file with permissions: rw-r--r--
After adding o+rwx and g+wrx:  rwxrwxr--

参阅

permissions (C++17) | 修改文件访问权限 (函数)
perms (C++17) | 标识文件系统权限 (枚举)


std::filesystem::permissions

< cpp‎ | filesystem
定义于头文件 <filesystem>
void permissions(const std::filesystem::path & p,

std::filesystem::perms prms,
std::filesystem::perm_options opts = perm_options::replace);
void permissions(const std::filesystem::path & p,
std::filesystem::perms prms,
std::error_code & ec) noexcept;
void permissions(const std::filesystem::path & p,
std::filesystem::perms prms,
std::filesystem::perm_options opts,

std::error_code & ec);
 (C++17 起)

更改 p 所决定的文件的访问权限，如同用 POSIX fchmodat 。跟随符号链接，除非在 opts 中设置了 perm_options::nofollow 。

第二个签名表现如同以设为 perm_options::replace 的 opts 调用

效果按如下方式依赖于 prms 与 opts ：

  • 若 opts 是 perm_options::replace ，则准确设置文件权限为 prms & std::filesystem::perms::mask （表示应用 prms 的每个合法位）
  • 若 opts 是 perm_options::add ，则准确设置文件权限为 status(p).permissions() | (prms & perms::mask) （表示每个设于 prms 却不在当前文件权限中的合法位被添加到文件权限）
  • 若 opts 是 perm_options::remove ，则准确设置文件权限为 status(p).permissions() & ~(prms & perms::mask) （表示每个 prms 中清除却设于当前文件权限中的有效位从文件权限被清除）

opts 要求 replace 、 add 或 remove 中有且仅有一者被设置。

不抛出重载在错误时无特殊行动。

参数

p | - | 要检验的路劲
prms | - | 要设置、添加或移除的权限
opts | - | 控制此函数所采用行动的选项
ec | - | 不抛出重载中报告错误的输出参数

返回值

（无）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

权限不必用位实现，但概念上用该方式处理它们。

某些系统上某些权限位可能被忽略，而更改某些位可能自动影响其他（例如在无拥有者/群/全体区别的平台上，设置三者任一部分都会写入三者全体的位集）

示例

#include <fstream>
#include <bitset>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

void demo_perms(fs::perms p)
{
    std::cout << ((p & fs::perms::owner_read) != fs::perms::none ? "r" : "-")
              << ((p & fs::perms::owner_write) != fs::perms::none ? "w" : "-")
              << ((p & fs::perms::owner_exec) != fs::perms::none ? "x" : "-")
              << ((p & fs::perms::group_read) != fs::perms::none ? "r" : "-")
              << ((p & fs::perms::group_write) != fs::perms::none ? "w" : "-")
              << ((p & fs::perms::group_exec) != fs::perms::none ? "x" : "-")
              << ((p & fs::perms::others_read) != fs::perms::none ? "r" : "-")
              << ((p & fs::perms::others_write) != fs::perms::none ? "w" : "-")
              << ((p & fs::perms::others_exec) != fs::perms::none ? "x" : "-")
              << '\n';
}
int main()
{
    std::ofstream("test.txt"); // 创建文件

    std::cout << "Created file with permissions: ";
    demo_perms(fs::status("test.txt").permissions());

    fs::permissions("test.txt",
                    fs::perms::owner_all | fs::perms::group_all,
                    fs::perm_options::add);

    std::cout << "After adding o+rwx and g+rwx:  ";
    demo_perms(fs::status("test.txt").permissions());

    fs::remove("test.txt");
}

可能的输出：

Created file with permissions: rw-r--r--
After adding o+rwx and g+wrx:  rwxrwxr--

参阅

perms (C++17) | 标识文件系统权限 (枚举)
statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)


std::filesystem::perms

< cpp‎ | filesystem
定义于头文件 <filesystem> |
enum class perms; | (C++17 起)

此类型代表文件访问权限。 perms 满足位掩码类型 (BitmaskType) 的要求（表示位运算符 operator& 、 operator| 、 operator^ 、 operator~ 、 operator&= 、 operator|= 及 operator^= 对此类型定义）

访问权限模仿 POSIX 权限位，而且任何单独的文件权限（由 status 报告）都是下列位的某些组合：

成员常量

成员常量 | 值（八进制） | POSIX 等价 | 含义
none | ​0​ |  | 未设权限位
owner_read | 0400 | S_IRUSR | 文件拥有者拥有读权限
owner_write | 0200 | S_IWUSR | 文件拥有者拥有写权限
owner_exec | 0100 | S_IXUSR | 文件拥有着拥有执行/查找权限
owner_all | 0700 | S_IRWXU | 文件拥有者拥有读、写、执行/查找权限 等价于 owner_read | owner_write | owner_exec
group_read | 040 | S_IRGRP | 文件用户组拥有读权限
group_write | 020 | S_IWGRP | 文件用户组拥有写权限
group_exec | 010 | S_IXGRP | 文件用户组拥有执行/查找权限
group_all | 070 | S_IRWXG | 文件用户组拥有读、写、执行/查找权限 等价于 group_read | group_write | group_exec
others_read | 04 | S_IROTH | 其他用户拥有读权限
others_write | 02 | S_IWOTH | 其他用户拥有写权限
others_exec | 01 | S_IXOTH | 其他用户拥有执行/查找权限
others_all | 07 | S_IRWXO | 其他用户拥有拥有读、写及执行/查找权限 等价于 others_read | others_write | others_exec
all | 0777 |  | 所有用户拥有读、写及执行/查找权限 等价于 owner_all | group_all | others_all
set_uid | 04000 | S_ISUID | 在执行上设置用户 ID 为文件拥有者的用户 ID
set_gid | 02000 | S_ISGID | 在执行上设置组 ID 为文件用户的组 ID
sticky_bit | 01000 | S_ISVTX | 实现定义的含义，不过 POSIX XSI 指定在设置于目录时，唯有文件拥有者可以删除文件，即使该目录对其他人可写（与 /tmp 一并使用）
mask | 07777 |  | 所有合法权限位。 等价于 all | set_uid | set_gid | sticky_bit

另外，定义此类型的下列常量，它不表示权限：

成员常量 | 值（十六进制） | 含义
unknown | 0xFFFF | 未知权限（例如当 file_status 以不带权限创建时）

注意

权限不必用位实现，但概念上用该方式处理它们。

某些系统上某些权限位可能被忽略，而更改某些位可能自动影响其他（例如在无拥有者/群/全体区别的平台上，设置三者任一部分都会写入三者全体的位集）

示例

#include <fstream>
#include <bitset>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

void demo_perms(fs::perms p)
{
    std::cout << ((p & fs::perms::owner_read) != fs::perms::none ? "r" : "-")
              << ((p & fs::perms::owner_write) != fs::perms::none ? "w" : "-")
              << ((p & fs::perms::owner_exec) != fs::perms::none ? "x" : "-")
              << ((p & fs::perms::group_read) != fs::perms::none ? "r" : "-")
              << ((p & fs::perms::group_write) != fs::perms::none ? "w" : "-")
              << ((p & fs::perms::group_exec) != fs::perms::none ? "x" : "-")
              << ((p & fs::perms::others_read) != fs::perms::none ? "r" : "-")
              << ((p & fs::perms::others_write) != fs::perms::none ? "w" : "-")
              << ((p & fs::perms::others_exec) != fs::perms::none ? "x" : "-")
              << '\n';
}
int main()
{
    std::ofstream("test.txt"); // 创建文件

    std::cout << "Created file with permissions: ";
    demo_perms(fs::status("test.txt").permissions());

    fs::permissions("test.txt",
                    fs::perms::owner_all | fs::perms::group_all,
                    fs::perm_options::add);

    std::cout << "After adding o+rwx and g+rwx:  ";
    demo_perms(fs::status("test.txt").permissions());

    fs::remove("test.txt");
}

可能的输出：

Created file with permissions: rw-r--r--
After adding o+rwx and g+wrx:  rwxrwxr--

参阅

statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)
permissions (C++17) | 修改文件访问权限 (函数)


std::filesystem::read_symlink

< cpp‎ | filesystem
定义于头文件 <filesystem>
std::filesystem::path read_symlink(const std::filesystem::path & p);

std::filesystem::path read_symlink(const std::filesystem::path & p,

std::error_code & ec);
 (C++17 起)

若 p 指代符号链接，则返回新的 path 对象，它指代符号链接的目标。

若 p 不指代符号链接，则发生错误。

不抛出重载在错误时返回空路径。

参数

p | - | 符号链接的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

符号链接的目标（可以不存在）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    // 在典型的 Linux 上， /lib/libc.so.6 是一个符号链接
    fs::path p = "/lib/libc.so.6";
    if(exists(p) && is_symlink(p))
        std::cout << p << " -> " << read_symlink(p) << '\n';
    else
        std::cout << p << " does not exist or is not a symlink\n";
}

可能的输出：

"/lib/libc.so.6" -> "libc-2.12.so"

参阅

is_symlink (C++17) | 检查参数是否表示一个符号链接 (函数)
create_symlinkcreate_directory_symlink (C++17)(C++17) | 创建一个符号链接 (函数)
copy_symlink (C++17) | 复制一个符号链接 (函数)
statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)


std::filesystem::recursive_directory_iterator

< cpp‎ | filesystem
定义于头文件 <filesystem> |
class recursive_directory_iterator; | (C++17 起)

recursive_directory_iterator 是在目录的 directory_entry 元素上，及递归地在所有子目录的目录条目上迭代的老式输入迭代器 (LegacyInputIterator) 。迭代顺序是未指定的，除了只造访一次每个目录条目。

默认不跟随符号链接，但这可以通过在构造时指定目录选项 follow_directory_symlink 启用。

跳过特殊路径名 dot 和 dot-dot 。

若 recursive_directory_iterator 被前移越过了顶层目录的最终目录迭代器，则它变得等于默认构造的迭代器，亦称作尾迭代器。两个尾迭代器始终相等，解引用或自增尾迭代器是未定义行为。

若在递归目录迭代器创建后，文件或目录被删除或添加到目录树，则更改是否会通过迭代器观察到是未指定的。

若目录结构含有环，则可能无法抵达尾迭代器。

成员类型

成员类型 | 定义
value_type | std::filesystem::directory_entry
difference_type | std::ptrdiff_t
pointer | const std::filesystem::directory_entry *
reference | const std::filesystem::directory_entry &
iterator_category | std::input_iterator_tag

成员函数

(构造函数)
 构造递归目录迭代器
(公开成员函数)
(析构函数)
 默认析构函数
(公开成员函数)
观察器
operator*operator->
 访问所指的目录条目
(公开成员函数)
options
 返回影响迭代的当前活跃选项
(公开成员函数)
depth
 返回当前递归深度
(公开成员函数)
recursion_pending
 检查对当前目录是否禁用递归
(公开成员函数)
修改器
operator=
 对内容赋值
(公开成员函数)
incrementoperator++
 前移到下个目录条目
(公开成员函数)
pop
 在目录层级中将迭代器上移一层
(公开成员函数)
disable_recursion_pending
 在下次自增前禁用递归
(公开成员函数)

非成员函数

begin(std::filesystem::recursive_directory_iterator)end(std::filesystem::recursive_directory_iterator)
 基于范围的 for 循环支持
(函数)

另外按老式输入迭代器 (LegacyInputIterator) 所要求提供 operator== 和 operator!= (C++20 前)operator== (C++20 起) 。

是否提供 operator!= （因为它能从 operator== 合成），以及 (C++20 起)相等运算符是成员还是非成员是未指定的。

辅助模板

namespace std::ranges {

template<>
inline constexpr bool
enable_borrowed_range<std::filesystem::recursive_directory_iterator> = true;

}
 (C++20 起)
namespace std::ranges {

template<>
inline constexpr bool
enable_view<std::filesystem::recursive_directory_iterator> = true;

}
 (C++20 起)

这些对 recursive_directory_iterator 的特化使之为 borrowed_range 及 view 。

注解

recursive_directory_iterator 通常保有指向实现对象的引用计数指针（以满足老式输入迭代器 (LegacyInputIterator) 的浅复制语义），该对象保有：

  • 组成递归栈的非递归 directory_iterator 的容器（例如 std::vector ）
  • 递归深度计数器（能以 depth() 访问）
  • 用于构造的目录选项（能以 options() 访问）
  • 递归挂起标志（可用 recursion_pending() 访问，可以与目录选项结合以节省空间）

示例

#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    fs::create_directories("sandbox/a/b");
    std::ofstream("sandbox/file1.txt");
    fs::create_symlink("a", "sandbox/syma");
    for(auto& p: fs::recursive_directory_iterator("sandbox"))
        std::cout << p.path() << '\n';
    fs::remove_all("sandbox");
}

可能的输出：

"sandbox/a"
"sandbox/a/b"
"sandbox/file1.txt"
"sandbox/syma"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3480 | C++20 | recursive_directory_iterator 既非 borrowed_range 亦非 view | 它都是

参阅

directory_iterator (C++17) | 指向目录内容的迭代器 (类)
directory_entry (C++17) | 目录条目 (类)
directory_options (C++17) | 用于迭代目录内容的选项 (枚举)


std::filesystem::begin(recursive_directory_iterator), std::filesystem::end(recursive_directory_iterator)

< cpp‎ | filesystem‎ | recursive directory iterator
定义于头文件 <filesystem> |  |
recursive_directory_iterator begin( recursive_directory_iterator iter ) noexcept; | (1) | (C++17 起)
recursive_directory_iterator end( recursive_directory_iterator ) noexcept; | (2) | (C++17 起)
1) 返回不更改的 iter 。
2) 返回默认构造的 recursive_directory_iterator ，其作用为尾迭代器。忽略参数。

非成员函数使得以基于范围的 for 循环使用 recursive_directory_iterator 可行并使 recursive_directory_iterator 为 range 类型 (C++20 起)。

参数

iter - recursive_directory_iterator

返回值

1) 不更改的 iter 。
2) 尾迭代器（默认构造的 recursive_directory_iterator ）。

示例

#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iostream>
namespace fs = std::filesystem;

int main()
{
    fs::current_path(fs::temp_directory_path());
    fs::create_directories("sandbox/a/b");
    std::ofstream("sandbox/file1.txt");
    fs::create_symlink("a", "sandbox/syma");

    std::cout << "Print dir structure using OS specific command 'tree':\n";
    std::system("tree --noreport sandbox");

    std::cout << "\nPrint dir structure using directory iterator:\n";
    for(auto& p: fs::recursive_directory_iterator("sandbox"))
        std::cout << p << '\n';

    fs::remove_all("sandbox");
}

可能的输出：

Print dir structure using OS specific command 'tree':
sandbox
├── a
│   └── b
├── file1.txt
└── syma -> a

Print dir structure using directory iterator:
"sandbox/syma"
"sandbox/file1.txt"
"sandbox/a"
"sandbox/a/b"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3480 | C++17 | end 按引用接收参数 | 按值接收参数

参阅

begin(std::filesystem::directory_iterator)end(std::filesystem::directory_iterator)
 基于范围的 for 循环支持
(函数)


std::filesystem::recursive_directory_iterator::depth

< cpp‎ | filesystem‎ | recursive directory iterator
int depth() const; | (C++17 起)

返回从起始目录到当前被迭代目录的目录层数，即目录层级的当前深度。

起始目录拥有深度 0 ，其子目录拥有深度 1 ，以此类推。

若 *this 是尾迭代器则行为未定义。

参数

（无）

返回值

目录层级的当前深度。

异常

不抛出。

示例

此示例用迭代深度计算目录树打印的缩进

#include <fstream>
#include <iostream>
#include <string>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    fs::current_path(fs::temp_directory_path());
    fs::create_directories("sandbox/a/b/c");
    fs::create_directories("sandbox/a/b/d/e");
    std::ofstream("sandbox/a/b/file1.txt");
    fs::create_symlink("a", "sandbox/syma");
    for(auto i = fs::recursive_directory_iterator("sandbox");
             i != fs::recursive_directory_iterator();
           ++i ) {
        std::cout << std::string(i.depth(), ' ') << *i;
        if(fs::is_symlink(i->symlink_status()))
            std::cout << " -> " << fs::read_symlink(*i);
        std::cout << '\n';
    }
    fs::remove_all("sandbox");
}

输出：

"sandbox/a"
 "sandbox/a/b"
  "sandbox/a/b/c"
  "sandbox/a/b/d"
   "sandbox/a/b/d/e"
  "sandbox/a/b/file1.txt"
"sandbox/syma" -> "a"


std::filesystem::recursive_directory_iterator::disable_recursion_pending

< cpp‎ | filesystem‎ | recursive directory iterator
void disable_recursion_pending(); | (C++17 起)

禁用到当前所指代的子目录的递归，若子目录存在。

该调用修改迭代器上的递归挂起标志，调用方法使得下次调用 increment 时，迭代器将在当前目录前进，即使未造访当前指代的子目录。

可以用 recursion_pending() 查询递归挂起标志的状态，此调用后它为 false 。 increment 后它被重置为 true ，其初值亦为 true 。

若 *this 是尾迭代器则行为未定义。

参数

（无）

异常

可能抛出实现定义的异常。

示例

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    fs::create_directories("sandbox/a/b/c");
    fs::create_directories("sandbox/a/b/d/e");
    std::ofstream("sandbox/a/b/file1.txt");
    std::system("tree sandbox");
    fs::create_symlink("a", "sandbox/syma");
    for(auto i = fs::recursive_directory_iterator("sandbox");
             i != fs::recursive_directory_iterator();
           ++i ) {
        std::cout << std::string(i.depth(), ' ') << *i;
        if(fs::is_symlink(i->symlink_status()))
            std::cout << " -> " << fs::read_symlink(*i);
        std::cout << '\n';

        // 不下降到 "b"
        if(i->path().filename() == "b")
            i.disable_recursion_pending();
    }
    fs::remove_all("sandbox");
}

可能的输出：

sandbox
├── a
│   └── b
│       ├── c
│       ├── d
│       │   └── e
│       └── file1.txt
└── syma -> a

"sandbox/a"
  "sandbox/a/b"
"sandbox/syma" -> "a"

参阅

recursion_pending | 检查对当前目录是否禁用递归 (公开成员函数)
incrementoperator++ | 前移到下个目录条目 (公开成员函数)


std::filesystem::recursive_directory_iterator::operator++, std::filesystem::recursive_directory_iterator::increment

< cpp‎ | filesystem‎ | recursive directory iterator
recursive_directory_iterator& operator++(); | (C++17 起)
recursive_directory_iterator& increment( std::error_code & ec ); | (C++17 起)

前进迭代器到下个条目。非法化所有 *this 的先前值的副本。

若当前被迭代目录没有剩下更多条目，则回撤迭代到亲目录。若亲目录亦无能迭代的兄弟条目，则重复此过程。若抵达已被递归迭代的目录层级的亲目录（在 depth() == 0) 无更多可选择条目），则设置 *this 为尾迭代器。

否则，若 *this 代表目录，则若满足下列条件则迭代进入它：

  • disable_recursion_pending() 在此次自增前未被调用，即 recursion_pending() == true 。
  • 目录不是符号链接或启用跟随符号链接，即至少下列之一为 true ：
    • !is_symlink((*this)->symlink_status()) 。
    • (options() & directory_options::follow_directory_symlink) != directory_options::none) 。

参数

ec - 要存储错误状态的错误码

返回值

*this

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3013 | C++17 | error_code 重载被标记为 noexcept 但能分配内存 | 移除 noexcept


std::filesystem::recursive_directory_iterator::operator*, std::filesystem::recursive_directory_iterator::operator->

< cpp‎ | filesystem‎ | recursive directory iterator
const std::filesystem::directory_entry & operator*() const; | (1) | (C++17 起)
const std::filesystem::directory_entry * operator->() const; | (2) | (C++17 起)

访问所指的 directory_entry

尾迭代器上的 operator* 或 operator-> 产生未定义行为。

参数

（无）

返回值

1) 此迭代器所指代的 directory_entry 的值
2) 指向此迭代器所指代的 directory_entry 的指针

异常

可能抛出实现定义的异常。

参阅

operator*operator->
 访问所指的目录条目
(std::filesystem::directory_iterator 的公开成员函数)


std::filesystem::recursive_directory_iterator::operator=

< cpp‎ | filesystem‎ | recursive directory iterator
recursive_directory_iterator& operator=( const recursive_directory_iterator& other ) = default; | (C++17 起)
recursive_directory_iterator& operator=( recursive_directory_iterator&& other ) = default; | (C++17 起)

赋值递归目录迭代器。

参数

other - 要赋值的另一个目录迭代器

返回值

*this

异常

可能抛出实现定义的异常。

本节未完成


std::filesystem::recursive_directory_iterator::options

< cpp‎ | filesystem‎ | recursive directory iterator
directory_options options() const; | (C++17 起)

返回影响目录迭代的选项。选项可以只在构造目录迭代器时提供。

若未提供选项参数，则返回 options::none 。

参数

（无）

返回值

影响目录迭代的有效选项。

异常

不抛出。


std::filesystem::recursive_directory_iterator::pop

< cpp‎ | filesystem‎ | recursive directory iterator
void pop(); | (1) | (C++17 起)
void pop( std::error_code & ec); | (2) | (C++17 起)

在目录层级中上移一层迭代器。非法化所有 *this 的先前值的副本。

若亲目录在迭代的目录层级之外（即 depth() == 0 ），则设 *this 为尾目录迭代器。

参数

ec - 要设置错误状态到的错误码

返回值

（无）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。


std::filesystem::recursive_directory_iterator::recursion_pending

< cpp‎ | filesystem‎ | recursive directory iterator
bool recursion_pending() const; | (C++17 起)

若下次自增将导致迭代进入 *this 当前所指代的目录，则返回 true 。

此函数在构造或自增的随后返回 true 。递归可通过 disable_recursion_pending() 禁用。

参数

（无）

返回值

若下次自增将迭代进入当前指代目录，则为 true ，否则为 false 。

异常

不抛出。


std::filesystem::recursive_directory_iterator::recursive_directory_iterator

< cpp‎ | filesystem‎ | recursive directory iterator
recursive_directory_iterator() noexcept;
 (1) (C++17 起)
recursive_directory_iterator( const recursive_directory_iterator& rhs );
 (2) (C++17 起)
recursive_directory_iterator( recursive_directory_iterator&& rhs ) noexcept;
 (3) (C++17 起)
explicit recursive_directory_iterator( const std::filesystem::path & p );
 (4) (C++17 起)
recursive_directory_iterator(

const std::filesystem::path & p,

std::filesystem::directory_options options );
 (4) (C++17 起)
recursive_directory_iterator(

const std::filesystem::path & p,
std::filesystem::directory_options options,

std::error_code & ec );
 (5) (C++17 起)
recursive_directory_iterator( const std::filesystem::path & p, std::error_code & ec );
 (6) (C++17 起)

构造新的递归目录迭代器。

1) 默认构造函数。构造尾迭代器。
2) 复制构造函数。
3) 移动构造函数。
4-6) 构造代表 p 所解析到的目录的首个条目的迭代器。
本节未完成
原因：错误

参数

rhs | - | 要复制或移动的迭代器
p | - | 要迭代于其上，及递归地迭代于其子目录上的路径
options | - | 迭代所用的目录选项
ec | - | 存储错误状态的错误码

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

递归目录迭代器默认不允许跟随目录符号链接。欲启用此行为，须在 options 选项集中指定 directory_options::follow_directory_symlink 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3013 | C++17 | error_code 重载被标记为 noexcept 但能分配内存 | 移除 noexcept


std::filesystem::relative, std::filesystem::proximate

< cpp‎ | filesystem
定义于头文件 <filesystem>
path relative( const std::filesystem::path & p,
std::error_code & ec);
 (1) (C++17 起)
path relative( const std::filesystem::path & p,

const std::filesystem::path & base = std::filesystem::current_path ());
path relative( const std::filesystem::path & p,
const std::filesystem::path & base,

std::error_code & ec);
 (2) (C++17 起)
path proximate( const std::filesystem::path & p,
std::error_code & ec);
 (3) (C++17 起)
path proximate( const std::filesystem::path & p,

const std::filesystem::path & base = std::filesystem::current_path ());
path proximate( const std::filesystem::path & p,
const std::filesystem::path & base,

std::error_code & ec);
 (4) (C++17 起)
1) 返回 relative(p, current_path(), ec)
2) 返回设为相对于 base 的 p 。在其他处理前解析符号链接并正常化 p 与 base 。等效于返回 weakly_canonical(p).lexically_relative(weakly_canonical(base)) 或 weakly_canonical(p, ec).lexically_relative(weakly_canonical(base, ec)) ，除了错误码形式在首次错误出现时返回 path() ，若有错误。
3) 返回 proximate(p, current_path(), ec)
4) 等效于返回 weakly_canonical(p).lexically_proximate(weakly_canonical(base)) 或 weakly_canonical(p, ec).lexically_proximate(weakly_canonical(base, ec)) ，除了错误码形式在首次错误出现时返回 path() ，若有错误。

参数

p | - | 既存路径
base | - | 基路径， p 将相对于它被设为相对/接近
ec | - | 存储错误状态的错误码

返回值

1) 设为相对于 base 的 p 。
2) 设为接近 base 的 p 。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p，第二 path 参数 base 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

本节未完成
原因：暂无示例

参阅

path (C++17) | 表示路径 (类)
absolute (C++17) | 组成一个绝对路径 (函数)
canonicalweakly_canonical (C++17) | 组成一个规范路径 (函数)


std::filesystem::remove, std::filesystem::remove_all

< cpp‎ | filesystem
定义于头文件 <filesystem>
bool remove(const std::filesystem::path & p);
bool remove(const std::filesystem::path & p, std::error_code & ec) noexcept;
 (1) (C++17 起)
std::uintmax_t remove_all(const std::filesystem::path & p);
std::uintmax_t remove_all(const std::filesystem::path & p, std::error_code & ec);
 (2) (C++17 起)
1) 删除路径 p 所标识的文件或空目录，如同用 POSIX remove 。不跟随符号链接（移除符号链接，而非其目标）
2) 递归地删除 p 的内容（若它是目录）及其所有子目录的内容，然后删除 p 自身，如同重复应用 POSIX remove 。不跟随符号链接（移除符号链接，而非其目标）

参数

p | - | 要删除的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

1) 若文件被删除则为 true ，若文件不存在则为 false 。接受 error_code& 参数的重载在错误时返回 false 。
2) 返回被删除的文件及目录数量（可以是零，若用以起始的 p 不存在）。接受 error_code& 参数的重载在错误时返回 static_cast< std::uintmax_t >(-1) 。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

在 POSIX 系统上，此函数通常按需调用 unlink 和 rmdir ，在 Windows 上则是 RemoveDirectoryW 和 DeleteFileW 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3014 | C++17 | remove_all 的 error_code 重载被标记为 noexcept 但能分配内存 | 移除 noexcept

示例

#include <iostream>
#include <cstdint>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    fs::path dir = fs::temp_directory_path();
    fs::create_directories(dir / "abcdef/example");
    std::uintmax_t n = fs::remove_all(dir / "abcdef");
    std::cout << "Deleted " << n << " files or directories\n";
}

可能的输出：

Deleted 2 files or directories

参阅

remove
 删除文件
(函数)


std::filesystem::rename

< cpp‎ | filesystem
定义于头文件 <filesystem>
void rename(const std::filesystem::path & old_p,

const std::filesystem::path & new_p);
void rename(const std::filesystem::path & old_p,
const std::filesystem::path & new_p,

std::error_code & ec);
 (C++17 起)

移动或重命名 old_p 所标识的文件系统对象到 new_p ，如同用 POSIX rename ：

  • 若 old_p 是非目录文件，则 new_p 必须是下列之一：
  • 与 old_p 为相同文件，或到它的硬链接：此情况不做任何事
  • 既存的非目录文件： new_p 首先被删除，然后因为删除不允许其他进程观测 new_p ，并将路径名 new_p 链接到该文件，而 old_p 从该文件接触链接。要求含有 old_p 的目录和含有 new_p 的目录的写权限。
  • 既存目录中的不存在文件：链接路径名 new_p 到该文件，并从该文件解链接 old_p 。要求含有 old_p 的目录和含有 new_p 的目录的写权限。
  • 若 old_p 是目录，则 new_p 必须是下列之一：
  • 与 old_p 为相同文件或到它的硬链接：此情况不做任何事
  • 既存目录：在 POSIX 系统上若 new_p 为空则删除之，但这在其他系统上可能是错误。若费错误，则首先删除 new_p ，然后因为删除不允许其他进程观测 new_p ，并将路径名 new_p 链接到该目录，将 old_p 从该目录解除链接。要求含有 old_p 的目录和含有 new_p 的目录的写权限。
  • 不存在的目录，不以目录分隔符终止，且亲目录存在：将路径名 new_p 链接到该目录，且从该目录解链接 old_p 。要求含有 old_p 的目录和含有 new_p 的目录的写权限。
  • 不跟随符号链接：若 old_p 是符号链接，则重命名它自身，而非其目标。若 new_p 是既存符号链接，则删除它自身，而非其目标。

若有如下情况则重命名失败

  • new_p 以 dot 或 dot-dot 结束
  • new_p 以目录分隔符结尾，指名一个不存在的目录
  • old_p 是一个目录，其祖先是 new_p

参数

old_p | - | 要移动或重命名的路径
new_p | - | 移动/重命名操作的目标路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

（无）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 old_p，第二 path 参数 new_p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

示例

#include <iostream>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    fs::path p = fs::current_path() / "sandbox";
    fs::create_directories(p/"from");
    std::ofstream(p/"from/file1.txt").put('a');
    fs::create_directory(p/"to");

//    fs::rename(p/"from/file1.txt", p/"to/"); // 错误： to 是目录
    fs::rename(p/"from/file1.txt", p/"to/file2.txt"); // OK
//    fs::rename(p/"from", p/"to"); // 错误： to 非空
    fs::rename(p/"from", p/"to/subdir"); // OK

    fs::remove_all(p);
}

参阅

rename | 重命名文件 (函数)
removeremove_all (C++17)(C++17) | 移除一个文件或空目录 移除一个文件或递归地移除一个目录及其所有内容 (函数)


std::filesystem::resize_file

< cpp‎ | filesystem
定义于头文件 <filesystem>
void resize_file(const std::filesystem::path & p,

std::uintmax_t new_size);
void resize_file(const std::filesystem::path & p,
std::uintmax_t new_size,

std::error_code & ec) noexcept;
 (C++17 起)

更改 p 所指名的的常规文件大小，如同用 POSIX truncate ：若先前的文件大小大于 new_size ，则文件的剩余部分被舍弃。若先前的文件大小小于 new_size ，则增加文件大小，而且新区域如同以零填充。

参数

p | - | 要重设大小的路径
new_size | - | 文件将会拥有的大小
ec | - | 不抛出重载中报告错误的输出参数

返回值

（无）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

在支持稀疏文件的系统上，增加文件大小并不会增加其在文件系统上占用的空间：空间分配仅当非零字节写入文件时发生。

示例

演示在空闲空间创建稀疏文件的效果

#include <iostream>
#include <iomanip>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    fs::path p = fs::current_path() / "example.bin";
    std::ofstream(p).put('a');
    std::cout << "File size: " << std::setw(10) << fs::file_size(p)
              << " Free space: " << fs::space(p).free << '\n';
    fs::resize_file(p, 1024*1024*1024); // 重设大小为 1 G
    std::cout << "File size: " << fs::file_size(p)
              << " Free space: " << fs::space(p).free << '\n';
    fs::remove(p);
}

可能的输出：

File size:          1 Free space: 3724541952
File size: 1073741824 Free space: 3724476416

参阅

file_size (C++17) | 返回文件的大小 (函数)
space (C++17) | 确定文件系统上的可用空闲空间 (函数)


std::filesystem::space

< cpp‎ | filesystem
定义于头文件 <filesystem>
std::filesystem::space_info space(const std::filesystem::path & p);

std::filesystem::space_info space(const std::filesystem::path & p,

std::error_code & ec) noexcept;
 (C++17 起)

确定路径名 p 定位于其上的文件系统信息，如同用 POSIX statvfs

植入并返回一个 space_info 类型的对象，从 POSIX struct statvfs 的如下成员设置：

  • space_info.capacity 如同被设为 f_blocks*f_frsize
  • space_info.free 被设为 f_bfree*f_frsize
  • space_info.available 被设为 f_bavail*f_frsize
  • 任何不能确定的成员被设为 static_cast<uintmax_t>(-1)

不抛出重载在错误时设所有成员为 static_cast<uintmax_t>(-1) 。

参数

p | - | 要检验的路径
ec | - | 不抛出重载的报告错误的输出参数

返回值

文件系统信息（ space_info 对象）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

space_info.available 可以小于或等于 space_info.free

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    fs::space_info devi = fs::space("/dev/null");
    fs::space_info tmpi = fs::space("/tmp");

    std::cout << ".        Capacity       Free      Available\n"
              << "/dev:   " << devi.capacity << "   "
              << devi.free << "   " << devi.available  << '\n'
              << "/tmp: " << tmpi.capacity << " "
              << tmpi.free << " " << tmpi.available  << '\n';
}

可能的输出：

.         Capacity       Free      Available
/dev:   4175114240   4175110144   4175110144
/tmp: 420651237376 411962273792 390570749952

参阅

space_info
(C++17)
 关于文件系统上空闲及可用空间的信息
(类)


std::filesystem::space_info

< cpp‎ | filesystem
定义于头文件 <filesystem>
struct space_info {

std::uintmax_t capacity;
std::uintmax_t free;
std::uintmax_t available;

};
 (C++17 起)

代表以 space 确定的文件系统信息。

成员对象

capacity | 文件系统的总大小，以字节计 (公开成员对象)
free | 文件系统的空闲空间，以字节计 (公开成员对象)
available | 非特权进程可用的空闲空间（可以小于或等于 free ） (公开成员对象)

非成员函数

operator==
(C++20)
 比较二个 space_info
(函数)

operator==(std::filesystem::space_info)

friend bool operator==( const space_info&, const space_info& ) = default; | (C++20 起)

检查两个参数的 capacity 、 free 及 available 是否分别相等。

此函数对通常无限定或有限定查找不可见，而只能在 std::filesystem::space_info 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    fs::space_info devi = fs::space("/dev/null");
    fs::space_info tmpi = fs::space("/tmp");

    std::cout << ".        Capacity       Free      Available\n"
              << "/dev:   " << devi.capacity << "   "
              << devi.free << "   " << devi.available  << '\n'
              << "/tmp: " << tmpi.capacity << " "
              << tmpi.free << " " << tmpi.available  << '\n';
}

可能的输出：

.         Capacity       Free      Available
/dev:   4175114240   4175110144   4175110144
/tmp: 420651237376 411962273792 390570749952

参阅

space
(C++17)
 确定文件系统上的可用空闲空间
(函数)


std::filesystem::status, std::filesystem::symlink_status

< cpp‎ | filesystem
定义于头文件 <filesystem>
std::filesystem::file_status status(const std::filesystem::path & p)

std::filesystem::file_status status(const std::filesystem::path & p,

std::error_code & ec)
 (1) (C++17 起)
std::filesystem::file_status symlink_status(const std::filesystem::path & p)

std::filesystem::file_status symlink_status(const std::filesystem::path & p,

std::error_code & ec)
 (2) (C++17 起)
1) 确定 p 所标识的文件系统对象的类型与属性，如同用 POSIX stat （符号链接跟随到其目标）。在下列描述中， prms 是 (m & perms::mask) 的结果，其中 m 如同通过从 POSIX struct stat 采用 st_mode 获得，并将其转换为类型 std::filesystem::perms 。
  • 若 p 是常规文件（如同以 POSIX S_ISREG ）则返回 file_status(file_type::regular, prms) 。
  • 若 p 是目录（如同以 POSIX S_ISDIR ），则返回 file_status(file_type::directory, prms)
  • 若 p 是阻塞特殊文件（如同以 POSIX S_ISBLK ），则返回 file_status(file_type::block, prms)
  • 若 p 是字符特殊文件（如同以 POSIX S_ISCHR ），则返回 file_status(file_type::character, prms)
  • 若 p 是 FIFO 或管道文件（如同以 POSIX S_ISFIFO ），则返回 file_status(file_type::fifo, prms)
  • 若 p 是接头（如同以 POSIX S_ISSOCK ），则返回 file_status(file_type::socket, prms)
  • 若 p 拥有实现定义文件类型，则返回 file_status(file_type::A, prms) ，其中 A 是该类型的实现定义的 file_type 常量。
  • 若 p 不存在，则返回 file_status(file_type::not_found)
  • 若 p 存在但文件属性无法确定，例如因为权限缺失，则返回 file_status(file_type::unknown)
  • 若在知晓 p 是否存在时就发生错误，则不抛出重载设置 ec 并返回 file_status(file_type::none) ，而抛出重载抛出 filesystem_error
  • 否则，返回 file_status(file_type::unknown, prms)
2) 同 (1) ，除了行为如同使用 POSIX lstat （不跟随符号链接）：
  • 若 p 是符号链接，则返回 file_status(file_type::symlink)

参数

p | - | 要检验的路径
ec | - | 不抛出重载中报告错误的输出参数

返回值

文件状态（一个 file_status 对象）

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 p 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

此函数提供的信息通常也作为目录迭代的副产物提供，而且可能为 directory_entry 的成员函数所获取。在目录迭代期间，不需要再次调用 status 。

示例

#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <filesystem>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>

namespace fs = std::filesystem;

void demo_status(const fs::path& p, fs::file_status s)
{
    std::cout << p;
    // 变体： switch(s.type()) { case fs::file_type::regular: ...}
    if(fs::is_regular_file(s)) std::cout << " is a regular file\n";
    if(fs::is_directory(s)) std::cout << " is a directory\n";
    if(fs::is_block_file(s)) std::cout << " is a block device\n";
    if(fs::is_character_file(s)) std::cout << " is a character device\n";
    if(fs::is_fifo(s)) std::cout << " is a named IPC pipe\n";
    if(fs::is_socket(s)) std::cout << " is a named IPC socket\n";
    if(fs::is_symlink(s)) std::cout << " is a symlink\n";
    if(!fs::exists(s)) std::cout << " does not exist\n";
}
int main()
{
    // 创建不同种类的文件
    fs::create_directory("sandbox");
    std::ofstream("sandbox/file"); // 创建常规文件
    fs::create_directory("sandbox/dir");
    mkfifo("sandbox/pipe", 0644);
    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    std::strcpy(addr.sun_path, "sandbox/sock");
    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
    bind(fd, (struct sockaddr*)&addr, sizeof addr);
    fs::create_symlink("file", "sandbox/symlink");

    // 演示不同的状态访问器
    for(auto it = fs::directory_iterator("sandbox"); it != fs::directory_iterator(); ++it)
        demo_status(*it, it->symlink_status()); // 从 directory_entry 使用缓冲的状态
    demo_status("dev/null", fs::status("/dev/null")); // 直接调用 status
    demo_status("dev/sda", fs::status("/dev/sda"));
    demo_status("sandbox/no", fs::status("/sandbox/no"));

    // 清理
    close(fd);
    fs::remove_all("sandbox");
}

可能的输出：

"sandbox/file" is a regular file
"sandbox/dir" is a directory
"sandbox/pipe" is a named IPC pipe
"sandbox/sock" is a named IPC socket
"sandbox/symlink" is a symlink
"dev/null" is a character device
"dev/sda" is a block device
"sandbox/no" does not exist

参阅

file_status (C++17) | 表示文件类型及权限 (类)
status_known (C++17) | 检查文件状态是否已知 (函数)
is_block_file (C++17) | 检查给定的路径是否表示块设备 (函数)
is_character_file (C++17) | 检查给定的路径是否表示字符设备 (函数)
is_directory (C++17) | 检查给定的路径是否表示一个目录 (函数)
is_fifo (C++17) | 检查给定的路径是否表示一个命名管道 (函数)
is_other (C++17) | 检查参数是否表示一个其他文件 (函数)
is_regular_file (C++17) | 检查参数是否表示一个常规文件 (函数)
is_socket (C++17) | 检查参数是否表示一个具名 IPC 套接字 (函数)
is_symlink (C++17) | 检查参数是否表示一个符号链接 (函数)
exists (C++17) | 检查路径是否指代既存的文件系统对象 (函数)
statussymlink_status | 此 directory_entry 所指代的文件的状态 此 directory_entry 所指代的文件的符号链接状态 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::status_known

< cpp‎ | filesystem
定义于头文件 <filesystem> |  |
bool status_known( std::filesystem::file_status s ) noexcept; | (1) | (C++17 起)

检查给定文件状态是否已知，等价于 s.type() != file_type::none 。

参数

s - 要检测的文件状态

返回值

若给定文件状态是已知文件状态，则为 true

注意

无关乎名称，该函数检查 file_type::none 的文件状态（表示错误出现），而非 file_type::unknown （表示文件存在，但其类型无法确定）。

参阅

statussymlink_status (C++17)(C++17) | 确定文件属性 确定文件属性，检查符号链接目标 (函数)
statussymlink_status | 此 directory_entry 所指代的文件的状态 此 directory_entry 所指代的文件的符号链接状态 (std::filesystem::directory_entry 的公开成员函数)


std::filesystem::temp_directory_path

< cpp‎ | filesystem
定义于头文件 <filesystem>
path temp_directory_path();
path temp_directory_path( std::error_code & ec );
 (1) (C++17 起)

返回适用于临时文件的目录位置。

参数

（无）

返回值

适合于临时文件的目录。路径保证存在并且是目录。接受 error_code& 参数的重载在错误时返回空路径。

异常

不接受 std::error_code & 参数的重载在底层 OS API 错误时抛出 filesystem_error ，以第一 path 参数 要返回的路径 和作为错误码参数的 OS 错误码构造。若 OS API 调用失败，则接受 std::error_code & 参数的重载设置该参数为 OS API 错误码，而若不出现错误则执行 ec.clear() 。若内存分配失败，则任何不标记为 noexcept 的重载可能抛出 std::bad_alloc 。

注意

在 POSIX 系统上，路径可以是指定于环境变量者 TMPDIR 、 TMP 、 TEMP 、 TEMPDIR 之一，而且若不指定它们的任一者，则返回路径 "/tmp" 。

在 Windows 系统上，典型的路径是 GetTempPath 所返回者。

示例

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    std::cout << "Temp directory is " << fs::temp_directory_path() << '\n';
}

可能的输出：

Temp directory is "C:\Windows\TEMP\"

参阅

tmpfile
 创建并打开一个临时、自动移除的文件
(函数)


独立与宿主实现

< cpp

C++ 标准定义了两种实现：有宿主 (hosted) 与独立 (freestanding) 实现。 C++ 标准对有宿主实现所规定的标准库头文件集合比对独立实现所规定的大很多。独立实现中程序可能在没有操作系统的情况下运行。

宏 __STDC_HOSTED__ 对宿主实现预定义为 1 ，对独立实现为 0 。

 (C++11 起)

针对多线程执行与数据竞争的规定

独立 | 有宿主
独立实现下，程序能否拥有多于一个执行线程由实现定义。 | 有宿主实现下， C++ 程序可以拥有多于一个同时运行的线程。
 (C++11 起)

针对 main 函数的要求

独立 | 有宿主
独立实现中，是否要求程序定义 main 函数是由实现定义的。启动与终止过程是由实现定义的；启动过程中包含执行具有静态存储期的命名空间作用域对象的构造函数；终止过程中包含执行具有静态存储期的对象的析构函数。 | 有宿主实现中，程序必须包含一个名为 main 的全局函数。程序执行时启动一个主执行线程，在其中调用 main 函数，并且具有静态存储期的变量将在该线程中被初始化和销毁。

针对标准库头文件的规定

独立实现拥有由实现定义的头文件集合。此集合至少包含下表中的头文件：

独立实现所规定的头文件
类型 | <cstddef>
实现的属性 | <limits> <cfloat> <climits> (C++11 起) <version> (C++20 起)
整数类型 | <cstdint> (C++11 起)
启动与终止 | <cstdlib> (部分)[1]
动态内存管理 | <new>
类型鉴别 | <typeinfo>
源文件位置 | <source_location> (C++20 起)
异常处理 | <exception>
初始化器列表 | <initializer_list> (C++11 起)
比较 | <compare> (C++20 起)
协程支持 | <coroutine> (C++20 起)
其他运行时支持 | <cstdarg>
基础库概念 | <concepts> (C++20 起)
类型特征 | <type_traits> (C++11 起)
位操作 | <bit> (C++20 起)
原子类型 | <atomic> (C++11 起)[2]
 | <ciso646> (C++11 起)(C++20 前)
已弃用的头文件 | <cstdalign> <cstdbool> (C++11 起)(C++20 前)
  1. ↑ 头文件 <cstdlib> 的受支持版本应当至少声明函数 std::abort 、 std::atexit 、 std::exit 、 std::at_quick_exit 及 std::quick_exit (C++11 起) 。
  2. ↑ 始终免锁的整数原子类型的支持，以及类型别名 std::atomic_signed_lock_free 与 std::atomic_unsigned_lock_free 是否存在在自立实现是实现定义的。 (C++20 起)

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 4.1 Implementation compliance [intro.compliance](p: 7)
  • 6.9.2 Multi-threaded executions and data races [intro.multithread](p: 77)
  • 6.9.3.1 main function [basic.start.main](p: 82)
  • 16.5.1.3 Freestanding implementations [compliance](p: 470)
  • C++17 标准（ISO/IEC 14882:2017）：
  • 4.1 Implementation compliance [intro.compliance](p: 5)
  • 4.7 Multi-threaded executions and data races [intro.multithread](p: 15)
  • 6.6.1 main function [basic.start.main](p: 66)
  • 20.5.1.3 Freestanding implementations [compliance](p: 458)
  • C++14 标准（ISO/IEC 14882:2014）：
  • 1.4 Implementation compliance [intro.compliance](p: 5)
  • 1.10 Multi-threaded executions and data races [intro.multithread](p: 11)
  • 3.6.1 Main function [basic.start.main](p: 62)
  • 17.6.1.3 Freestanding implementations [compliance](p: 441)
  • C++11 标准（ISO/IEC 14882:2011）：
  • 1.4 Implementation compliance [intro.compliance](p: 5)
  • 1.10 Multi-threaded executions and data races [intro.multithread](p: 11)
  • 3.6.1 Main function [basic.start.main](p: 58)
  • 17.6.1.3 Freestanding implementations [compliance](p: 408)
  • C++03 标准（ISO/IEC 14882:2003）：
  • 1.4 Implementation compliance [intro.compliance](p: 3)
  • 3.6.1 Main function [basic.start.main](p: 43)
  • 17.4.1.3 Freestanding implementations [lib.compliance](p: 326)

参阅


C++ 标准库头文件

< cpp

C++ 标准库的接口由下列头文件的汇集定义。

概念库
<concepts>
(C++20)
 基础库概念

协程库
<coroutine>
(C++20)
 协程支持库

工具库
<cstdlib>
 通用工具：程序控制、动态内存分配、随机数、排序与搜索
<csignal>
 信号管理的函数与宏常量
<csetjmp>
 保存（及跳转）到执行环境的宏（与函数）
<cstdarg>
 变长实参列表的处理
<typeinfo>
 运行时类型信息工具
<typeindex>
(C++11)
 std::type_index
<type_traits>
(C++11)
 编译时类型信息
<bitset>
 std::bitset 类模板
<functional>
 函数对象、函数调用、绑定操作及引用包装
<utility>
 多种工具组件
<ctime>
 C 风格日期/时间工具
<chrono>
(C++11)
 C++ 时间工具
<cstddef>
 标准宏与 typedef
<initializer_list>
(C++11)
 std::initializer_list 类模板
<tuple>
(C++11)
 std::tuple 类模板
<any>
(C++17)
 std::any 类
<optional>
(C++17)
 std::optional 类模板
<variant>
(C++17)
 std::variant 类模板
<compare>
(C++20)
 三路比较运算符支持
<version>
(C++20)
 提供依赖实现的库信息
<source_location>
(C++20)
 提供获得源码位置的手段
<stacktrace>
(C++23)
 栈踪库
动态内存管理
<new>
 低层内存管理工具
<memory>
 高层内存管理工具
<scoped_allocator>
(C++11)
 嵌套分配器类
<memory_resource>
(C++17)
 多态分配器与内存资源
数值极限
<climits>
 整数类型的极限
<cfloat>
 浮点类型的极限
<cstdint>
(C++11)
 定宽整数类型与其他类型的极限
<cinttypes>
(C++11)
 格式化宏、 intmax_t 与 uintmax_t 数学与转换
<limits>
 查询算术类型属性的一致方式
错误处理
<exception>
 异常处理工具
<stdexcept>
 标准异常对象
<cassert>
 比较其实参与零的条件编译宏
<system_error>
(C++11)
 定义 std::error_code ，依赖平台的错误码
<cerrno>
 含有最后一次错误号的宏

字符串库
<cctype>
 确定窄字符类别的函数
<cwctype>
 确定宽字符的类别的函数
<cstring>
 多种窄字符串处理函数
<cwchar>
 多种宽与多字节字符串处理函数
<cuchar>
(C++11)
 C 风格 Unicode 字符转换函数
<string>
 std::basic_string 类模板
<string_view>
(C++17)
 std::basic_string_view 类模板
<charconv>
(C++17)
 std::to_chars 与 std::from_chars
<format>
(C++20)
 格式化库，包括 std::format

容器库
<array>
(C++11)
 std::array 容器
<vector>
 std::vector 容器
<deque>
 std::deque 容器
<list>
 std::list 容器
<forward_list>
(C++11)
 std::forward_list 容器
<set>
 std::set 与 std::multiset 关联容器
<map>
 std::map 与 std::multimap 关联容器
<unordered_set>
(C++11)
 std::unordered_set 与 std::unordered_multiset 无序关联容器
<unordered_map>
(C++11)
 std::unordered_map 与 std::unordered_multimap 无序关联容器
<stack>
 std::stack 容器适配器
<queue>
 std::queue 与 std::priority_queue 容器适配器
<span>
(C++20)
 std::span 视图

迭代器库
<iterator>
 范围迭代器

范围库
<ranges>
(C++20)
 范围访问、元件、要求、工具及适配器

算法库
<algorithm>
 在范围上操作的算法
<execution>
(C++17)
 并行版本算法的预定义执行策略

数值库
<cmath>
 常用数学函数
<complex>
 复数类型
<valarray>
 表示和操纵值的数组的类
<random>
(C++11)
 随机数生成器与分布
<numeric>
 范围中的值上的数值运算
<ratio>
(C++11)
 编译时有理数算术
<cfenv>
(C++11)
 浮点环境访问函数
<bit>
(C++20)
 位操纵函数
<numbers>
(C++20)
 数学常数

本地化库
<locale>
 本地化工具
<clocale>
 C 本地化工具
<codecvt>
(C++11)(C++17 中弃用)
 Unicode 转换设施

输入/输出库
<iosfwd>
 输入/输出库中所有类的前置声明
<ios>
 std::ios_base 类、 std::basic_ios 类模板与数个 typedef
<istream>
 std::basic_istream 类模板与数个 typedef
<ostream>
 std::basic_ostream 、 std::basic_iostream 类模板与数个 typedef
<iostream>
 数个标准流对象
<fstream>
 std::basic_fstream 、 std::basic_ifstream 、 std::basic_ofstream 类模板及数个 typedef
<sstream>
 std::basic_stringstream 、 std::basic_istringstream 、 std::basic_ostringstream 类模板与数个 typedef
<syncstream>
(C++20)
 std::basic_osyncstream 、 std::basic_syncbuf 及 typedef
<spanstream>
(C++23)
 std::basic_spanstream、 std::basic_ispanstream、 std::basic_ospanstream 类模板与 typedef
<strstream>
(C++98 中弃用)
 std::strstream 、 std::istrstream 、 std::ostrstream
<iomanip>
 格式化输入与输出的辅助函数
<streambuf>
 std::basic_streambuf 类模板
<cstdio>
 C 风格输入输出函数

文件系统库
<filesystem>
(C++17)
 std::path 类与支持函数

正则表达式库
<regex>
(C++11)
 支持正则表达式处理的类、算法及迭代器

原子操作库
<atomic>
(C++11)
 原子操作库

线程支持库
<thread>
(C++11)
 std::thread 类与支持函数
<stop_token>
(C++20)
 std::jthread 的停止记号
<mutex>
(C++11)
 互斥元件
<shared_mutex>
(C++14)
 共享互斥元件
<future>
(C++11)
 异步计算元件
<condition_variable>
(C++11)
 线程等待条件
<semaphore>
(C++20)
 信号量
<latch>
(C++20)
 闩
<barrier>
(C++20)
 屏障

C 兼容头文件

对于一些形式为 xxx.h 的 C 标准库头文件，C++ 标准库同时包含同名的头文件和拥有形式 cxxx 的头文件（所有有意义的 cxxx 头文件列于上方）。形为 xxx.h 的头文件有意仅用于互操作。C++ 源文件有可能需要包含这些头文件之一以作为合法的 ISO C。不有意同样成为合法 ISO C 的源文件不应使用任何 C 头文件。

除了 complex.h 这一例外，C++ 标准库中包含的每个 xxx.h 头文件都将其对应的 cxxx 中本应置于 std 命名空间中的每个名字放在全局命名空间中。

允许这些头文件也在 std 命名空间中声明同样的名字，而且允许对应的 cxxx 头文件也在全局命名空间中声明同样的名字：包含 <cstdlib> 肯定会提供 std::malloc，亦可提供 ::malloc。包含 <stdlib.h> 肯定会提供 ::malloc，亦可提供 std::malloc。这甚至适用于并非 C 标准库一部分的函数和函数重载。

注：xxx.h 头文件在 C++98 中弃用并在 C++23 中解除弃用。对纯 C++ 代码不鼓励使用这些头文件，但它们不会在将来被移除。

<assert.h> | 表现同 <cassert>
<ctype.h> | 表现如同将每个来自 <cctype> 的名字置于全局命名空间
<errno.h> | 表现同 <cerrno>
<fenv.h> (C++11) | 表现如同将每个来自 <cfenv> 的名字置于全局命名空间
<float.h> | 表现同 <cfloat>
<inttypes.h> (C++11) | 表现如同将每个来自 <cinttypes> 的名字置于全局命名空间
<limits.h> | 表现同 <climits>
<locale.h> | 表现如同将每个来自 <clocale> 的名字置于全局命名空间
<math.h> | 表现如同将每个来自 <cmath> 的名字置于全局命名空间， 除了数学特殊函数的名字
<setjmp.h> | 表现如同将每个来自 <csetjmp> 的名字置于全局命名空间
<signal.h> | 表现如同将每个来自 <csignal> 的名字置于全局命名空间
<stdarg.h> | 表现如同将每个来自 <cstdarg> 的名字置于全局命名空间
<stddef.h> | 表现如同将每个来自 <cstddef> 的名字置于全局命名空间， 除了 std::byte 与相关函数的名字
<stdint.h> (C++11) | 表现如同将每个来自 <cstdint> 的名字置于全局命名空间
<stdio.h> | 表现如同将每个来自 <cstdio> 的名字置于全局命名空间
<stdlib.h> | 表现如同将每个来自 <cstdlib> 的名字置于全局命名空间
<string.h> | 表现如同将每个来自 <cstring> 的名字置于全局命名空间
<time.h> | 表现如同将每个来自 <ctime> 的名字置于全局命名空间
<uchar.h> (C++11) | 表现如同将每个来自 <cuchar> 的名字置于全局命名空间
<wchar.h> | 表现如同将每个来自 <cwchar> 的名字置于全局命名空间
<wctype.h> | 表现如同将每个来自 <cwctype> 的名字置于全局命名空间

特殊 C 兼容头文件

头文件 <stdatomic.h> 声明在亦在 C 标准库中提供的名称，并定义在 C 中为关键词的 _Atomic 宏。不同于其他 xxx.h 头文件，不提供对应的 <cstdatomic> 。

<stdatomic.h>
(C++23)
 定义 _Atomic 并提供 C 标准库中的对应组件

空 C 头文件

头文件 <complex.h>、<ccomplex>、<tgmath.h> 及 <ctgmath> 不含有任何来自 C 标准库的内容，而且不过是包含其他来自 C++ 标准库的头文件。

<ccomplex> (C++11)(C++17 中弃用)(C++20 中移除) | 简单地包含头文件 <complex>
<complex.h> (C++11) | 简单地包含头文件 <complex>
<ctgmath> (C++11)(C++17 中弃用)(C++20 中移除) | 简单地包含头文件 <complex> 与 <cmath> ：等价于 C 头文件 tgmath.h 的重载已于前述头文件提供
<tgmath.h> (C++11) | 简单地包含头文件 <complex> 与 <cmath>

无意义的 C 头文件

头文件 <ciso646>、<cstdalign> 及 <cstdbool> 在 C++ 中无意义，因为它们在 C 中提供的宏是 C++ 的关键词。

<ciso646> (C++20 中移除) | 空头文件。 C 中 iso646.h 中出现的宏是 C++ 中的关键词
<iso646.h> | 无效果
<cstdalign> (C++11)(C++17 中弃用)(C++20 中移除) | 定义一个兼容性宏常量
<stdalign.h> (C++11) | 定义一个兼容性宏常量
<cstdbool> (C++11)(C++17 中弃用)(C++20 中移除) | 定义一个兼容性宏常量
<stdbool.h> (C++11) | 定义一个兼容性宏常量

不受支持的 C 头文件

C++ 不包含 C 头文件 <stdatomic.h>、 (C++23 前)<stdnoreturn.h> 及 <threads.h> 而且它们无 cxxx 等价版本。

实验性库

C++ TR/TS 亦定义数个头文件的汇集。

参阅


标准库头文件 <algorithm>

< cpp‎ | header

此头文件是算法库的一部分。

包含
<initializer_list>
(C++11)
 std::initializer_list 类模板

类
定义于命名空间 std::ranges
返回类型
ranges::in_fun_result
(C++20)
 提供存储一个迭代器与一个函数对象为单个单元的方式
(类模板)
ranges::in_in_result
(C++20)
 提供存储二个迭代器为单个单元的方式
(类模板)
ranges::in_out_result
(C++20)
 提供存储二个迭代器为单个单元的方式
(类模板)
ranges::in_in_out_result
(C++20)
 提供存储三个迭代器为单个单元的方式
(类模板)
ranges::in_out_out_result
(C++20)
 提供存储三个迭代器为单个单元的方式
(类模板)
ranges::min_max_result
(C++20)
 提供存储二个同类型对象或引用为单个单元的方式
(类模板)
ranges::in_found_result
(C++20)
 提供存储一个迭代器与一个布尔标志为单个单元的方式
(类模板)

函数
不修改序列的操作
all_ofany_ofnone_of
(C++11)(C++11)(C++11)
 检查谓词是否对范围中所有、任一或无元素为 true
(函数模板)
for_each
 应用函数到范围中的元素
(函数模板)
for_each_n
(C++17)
 应用一个函数对象到序列的前 n 个元素
(函数模板)
countcount_if
 返回满足指定判别标准的元素数
(函数模板)
mismatch
 寻找两个范围出现不同的首个位置
(函数模板)
findfind_iffind_if_not
(C++11)
 寻找首个满足特定判别标准的元素
(函数模板)
find_end
 在特定范围中寻找最后出现的元素序列
(函数模板)
find_first_of
 搜索元素集合中的任意元素
(函数模板)
adjacent_find
 查找首对相邻的相同（或满足给定谓词的）元素
(函数模板)
search
 搜索一个元素范围
(函数模板)
search_n
 在范围中搜索一定量的某个元素的连续副本
(函数模板)
修改序列的操作
copycopy_if
(C++11)
 将某一范围的元素复制到一个新的位置
(函数模板)
copy_n
(C++11)
 将一定数目的元素复制到一个新的位置
(函数模板)
copy_backward
 按从后往前的顺序复制一个范围内的元素
(函数模板)
move
(C++11)
 将某一范围的元素移动到一个新的位置
(函数模板)
move_backward
(C++11)
 按从后往前的顺序移动某一范围的元素到新的位置
(函数模板)
fill
 将一个给定值复制赋值给一个范围内的每个元素
(函数模板)
fill_n
 将一个给定值复制赋值给一个范围内的 N 个元素
(函数模板)
transform
 将一个函数应用于某一范围的各个元素，并在目标范围存储结果
(函数模板)
generate
 将相继的函数调用结果赋值给一个范围中的每个元素
(函数模板)
generate_n
 将相继的函数调用结果赋值给一个范围中的 N 个元素
(函数模板)
removeremove_if
 移除满足特定判别标准的元素
(函数模板)
remove_copyremove_copy_if
 复制一个范围的元素，忽略满足特定判别标准的元素
(函数模板)
replacereplace_if
 将所有满足特定判别标准的值替换为另一个值
(函数模板)
replace_copyreplace_copy_if
 复制一个范围内的元素，并将满足特定判别标准的元素替换为另一个值
(函数模板)
swap
 交换两个对象的值
(函数模板)
swap_ranges
 交换两个范围的元素
(函数模板)
iter_swap
 交换两个迭代器所指向的元素
(函数模板)
reverse
 逆转范围中的元素顺序
(函数模板)
reverse_copy
 创建一个范围的逆向副本
(函数模板)
rotate
 旋转范围中的元素顺序
(函数模板)
rotate_copy
 复制并旋转元素范围
(函数模板)
shift_leftshift_right
(C++20)
 迁移范围中的元素
(函数模板)
random_shuffleshuffle
(C++17 前)(C++11)
 随机重排范围中的元素
(函数模板)
sample
(C++17)
 从一个序列中随机选择 n 个元素
(函数模板)
unique
 移除范围内的连续重复元素
(函数模板)
unique_copy
 创建某范围的不含连续重复元素的副本
(函数模板)
划分操作
is_partitioned
(C++11)
 判断范围是否已按给定的谓词划分
(函数模板)
partition
 将范围中的元素分为两组
(函数模板)
partition_copy
(C++11)
 复制一个范围，将各元素分为两组
(函数模板)
stable_partition
 将元素分为两组，同时保留其相对顺序
(函数模板)
partition_point
(C++11)
 定位已划分范围的划分点
(函数模板)
排序操作
is_sorted
(C++11)
 检查范围是否已按升序排列
(函数模板)
is_sorted_until
(C++11)
 找出最大的已排序子范围
(函数模板)
sort
 将范围按升序排序
(函数模板)
partial_sort
 排序一个范围的前 N 个元素
(函数模板)
partial_sort_copy
 对范围内的元素进行复制并部分排序
(函数模板)
stable_sort
 将范围内的元素排序，同时保持相等的元素之间的顺序
(函数模板)
nth_element
 将给定的范围部分排序，确保其按给定元素划分
(函数模板)
（已排序范围上的）二分搜索操作
lower_bound
 返回指向第一个不小于给定值的元素的迭代器
(函数模板)
upper_bound
 返回指向第一个大于给定值的元素的迭代器
(函数模板)
binary_search
 确定元素是否存在于某范围中
(函数模板)
equal_range
 返回匹配特定键值的元素范围
(函数模板)
其他已排序范围上的操作
merge
 归并两个已排序的范围
(函数模板)
inplace_merge
 就地归并两个有序范围
(函数模板)
（已排序范围上的）集合操作
includes
 若一个序列是另一个的子列则返回 true
(函数模板)
set_difference
 计算两个集合的差集
(函数模板)
set_intersection
 计算两个集合的交集
(函数模板)
set_symmetric_difference
 计算两个集合的对称差
(函数模板)
set_union
 计算两个集合的并集
(函数模板)
堆操作
is_heap
 检查给定范围是否为一个最大堆
(函数模板)
is_heap_until
(C++11)
 查找能成为最大堆的最大子范围
(函数模板)
make_heap
 从一个元素范围创建出一个最大堆
(函数模板)
push_heap
 将一个元素加入到一个最大堆
(函数模板)
pop_heap
 从最大堆中移除最大元素
(函数模板)
sort_heap
 将一个最大堆变成一个按升序排序的元素范围
(函数模板)
最小/最大操作
max
 返回各给定值中的较大者
(函数模板)
max_element
 返回范围内的最大元素
(函数模板)
min
 返回各给定值中的较小者
(函数模板)
min_element
 返回范围内的最小元素
(函数模板)
minmax
(C++11)
 返回两个元素的较小和较大者
(函数模板)
minmax_element
(C++11)
 返回范围内的最小元素和最大元素
(函数模板)
clamp
(C++17)
 在一对边界值间夹逼一个值
(函数模板)
比较操作
equal
 确定两个元素集合是否是相同的
(函数模板)
lexicographical_compare
 当一个范围按字典顺序小于另一个范围时，返回 true
(函数模板)
lexicographical_compare_three_way
(C++20)
 用三路比较比较两个范围
(函数模板)
排列操作
is_permutation
(C++11)
 判断一个序列是否为另一个序列的排列
(函数模板)
next_permutation
 产生某个元素范围的按字典顺序的下一个较大的排列
(函数模板)
prev_permutation
 产生某个元素范围的按字典顺序的下一个较小的排列
(函数模板)

仿函数实体
定义于命名空间 std::ranges
不修改序列的操作
ranges::all_ofranges::any_ofranges::none_of
(C++20)(C++20)(C++20)
 检查谓词是否对范围中所有、任一或无元素为 true
(niebloid)
ranges::for_each
(C++20)
 应用函数到范围中的元素
(niebloid)
ranges::for_each_n
(C++20)
 应用函数对象到序列的首 n 个元素
(niebloid)
ranges::countranges::count_if
(C++20)(C++20)
 返回满足指定判别标准的元素数
(niebloid)
ranges::mismatch
(C++20)
 寻找两个范围出现不同的首个位置
(niebloid)
ranges::findranges::find_ifranges::find_if_not
(C++20)(C++20)(C++20)
 寻找首个满足特定判别标准的元素
(niebloid)
ranges::find_end
(C++20)
 在特定范围中寻找最后出现的元素序列
(niebloid)
ranges::find_first_of
(C++20)
 搜索元素集合中的任一元素
(niebloid)
ranges::adjacent_find
(C++20)
 查找首对相邻的相同（或满足给定谓词的）元素
(niebloid)
ranges::search
(C++20)
 搜索一个元素范围
(niebloid)
ranges::search_n
(C++20)
 在范围中搜索一定量的某个元素的连续副本
(niebloid)
ranges::starts_with
(C++23)
 检查一个范围是否始于另一范围
(niebloid)
ranges::ends_with
(C++23)
 检查一个范围是否终于另一范围
(niebloid)
修改序列的操作
ranges::copyranges::copy_if
(C++20)(C++20)
 将某一范围的元素复制到一个新的位置
(niebloid)
ranges::copy_n
(C++20)
 将一定数目的元素复制到一个新的位置
(niebloid)
ranges::copy_backward
(C++20)
 按从后往前的顺序复制一个范围内的元素
(niebloid)
ranges::move
(C++20)
 将某一范围的元素移动到一个新的位置
(niebloid)
ranges::move_backword
(C++20)
 按从后往前的顺序移动某一范围的元素到新的位置
(niebloid)
ranges::fill
(C++20)
 将一个给定值复制赋值给一个范围内的每个元素
(niebloid)
ranges::fill_n
(C++20)
 将一个值复制赋值给一定量的元素
(niebloid)
ranges::transform
(C++20)
 将一个函数应用于某一范围的各个元素
(niebloid)
ranges::generate
(C++20)
 保存函数结果到一个范围中
(niebloid)
ranges::generate_n
(C++20)
 保存 N 次函数应用的结果
(niebloid)
ranges::removeranges::remove_if
(C++20)(C++20)
 移除满足特定判别标准的元素
(niebloid)
ranges::remove_copyranges::remove_copy_if
(C++20)(C++20)
 复制一个范围的元素，忽略满足特定判别标准的元素
(niebloid)
ranges::replaceranges::replace_if
(C++20)(C++20)
 将所有满足特定判别标准的值替换为另一个值
(niebloid)
ranges::replace_copyranges::replace_copy_if
(C++20)(C++20)
 复制一个范围内的元素，并将满足特定判别标准的元素替换为另一个值
(niebloid)
ranges::swap_ranges
(C++20)
 交换两个范围的元素
(niebloid)
ranges::reverse
(C++20)
 逆转范围中的元素顺序
(niebloid)
ranges::revserse_copy
(C++20)
 创建一个范围的逆向副本
(niebloid)
ranges::rotate
(C++20)
 旋转范围中的元素顺序
(niebloid)
ranges::rotate_copy
(C++20)
 复制并旋转元素范围
(niebloid)
ranges::sample
(C++20)
 从序列中随机选择 n 个元素
(niebloid)
ranges::shuffle
(C++20)
 随机重排范围中的元素
(niebloid)
ranges::unique
(C++20)
 移除范围中的连续重复元素
(niebloid)
ranges::unique_copy
(C++20)
 创建某范围的不含连续重复元素的副本
(niebloid)
划分操作
ranges::is_partitioned
(C++20)
 判断范围是否已按给定的谓词划分
(niebloid)
ranges::partition
(C++20)
 将范围中的元素分为二组
(niebloid)
ranges::partition_copy
(C++20)
 复制一个范围，将各元素分为二组
(niebloid)
ranges::stable_partition
(C++20)
 将元素分成二组，同时保持其相对顺序
(niebloid)
ranges::partition_point
(C++20)
 定位已划分范围的划分点
(niebloid)
排序操作
ranges::is_sorted
(C++20)
 检查范围是否以升序排序
(niebloid)
ranges::is_sorted_until
(C++20)
 寻找最大的已排序子范围
(niebloid)
ranges::sort
(C++20)
 将范围按升序排序
(niebloid)
ranges::partial_sort
(C++20)
 排序一个范围的前 N 个元素
(niebloid)
ranges::partial_sort_copy
(C++20)
 对范围内的元素进行复制并部分排序
(niebloid)
ranges::stable_sort
(C++20)
 将范围内的元素排序，同时保持相等的元素之间的顺序
(niebloid)
ranges::nth_element
(C++20)
 将给定的范围部分排序，确保其按给定元素划分
(niebloid)
（已排序范围上的）集合操作
ranges::lower_bound
(C++20)
 返回指向首个不小于给定值的元素的迭代器
(niebloid)
ranges::upper_bound
(C++20)
 返回指向首个大于某值的元素的迭代器
(niebloid)
ranges::binary_search
(C++20)
 确定元素是否存在于某范围中
(niebloid)
ranges::equal_ranges
(C++20)
 返回匹配特定值的元素范围
(niebloid)
其他已排序范围上的操作
ranges::merge
(C++20)
 归并二个已排序范围
(niebloid)
ranges::inplace_merge
(C++20)
 在原位归并两个有序范围
(niebloid)
（已排序范围上的）集合操作
ranges::includes
(C++20)
 若一个序列是另一个的子列则返回 true
(niebloid)
ranges::set_difference
(C++20)
 计算两个集合的差集
(niebloid)
ranges::set_intersection
(C++20)
 计算两个集合的交集
(niebloid)
ranges::set_symmetric_difference
(C++20)
 计算两个集合的对称差
(niebloid)
ranges::set_union
(C++20)
 计算两个集合的并集
(niebloid)
堆操作
ranges::is_heap
(C++20)
 检查给定范围是否为最大堆
(niebloid)
ranges::is_heap_until
(C++20)
 寻找能成为最大堆的最大子范围
(niebloid)
ranges::make_heap
(C++20)
 从一个元素范围创建出一个最大堆
(niebloid)
ranges::push_heap
(C++20)
 将一个元素加入到一个最大堆
(niebloid)
ranges::pop_heap
(C++20)
 从最大堆中移除最大元素
(niebloid)
ranges::sort_heap
(C++20)
 将一个最大堆变成一个按升序排序的元素范围
(niebloid)
最小/最大操作
ranges::max
(C++20)
 返回给定值的较大者
(niebloid)
ranges::max_element
(C++20)
 返回范围中的最大元素
(niebloid)
ranges::min
(C++20)
 返回给定值的较小者
(niebloid)
ranges::min_element
(C++20)
 返回范围中的最小元素
(niebloid)
ranges::minmax
(C++20)
 返回两个元素的较小和较大者
(niebloid)
ranges::minmax_element
(C++20)
 返回范围中的最小和最大元素
(niebloid)
ranges::clamp
(C++20)
 在一对边界值间夹一个值
(niebloid)
比较操作
ranges::equal
(C++20)
 确定两个元素集合是否是相同的
(niebloid)
ranges::lexicographical_compare
(C++20)
 当一个范围按字典顺序小于另一个范围时，返回 true
(niebloid)
排列操作
ranges::is_permutation
(C++20)
 确定一个序列是否为另一序列的重排
(niebloid)
ranges::next_permutation
(C++20)
 产生某个元素范围的按字典序下一个较大的排列
(niebloid)

概要

#include <initializer_list>

namespace std {
  namespace ranges {
    // 算法结果类型
    template<class I, class F> struct in_fun_result;
    template<class I1, class I2> struct in_in_result;
    template<class I, class O> struct in_out_result;
    template<class I1, class I2, class O> struct in_in_out_result;
    template<class I, class O1, class O2> struct in_out_out_result;
    template<class T> struct min_max_result;
    template<class I> struct in_found_result;
  }

  // 不修改序列的操作
  // 全部
  template<class InputIter, class Pred>
    constexpr bool all_of(InputIter first, InputIter last, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    bool all_of(ExecutionPolicy&& exec,
                ForwardIter first, ForwardIter last, Pred pred);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr bool all_of(I first, S last, Pred pred, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr bool all_of(R&& r, Pred pred, Proj proj = {});
  }

  // 任何
  template<class InputIter, class Pred>
    constexpr bool any_of(InputIter first, InputIter last, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    bool any_of(ExecutionPolicy&& exec,
                ForwardIter first, ForwardIter last, Pred pred);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr bool any_of(I first, S last, Pred pred, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr bool any_of(R&& r, Pred pred, Proj proj = {});
  }

  // 无一
  template<class InputIter, class Pred>
    constexpr bool none_of(InputIter first, InputIter last, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    bool none_of(ExecutionPolicy&& exec,
                 ForwardIter first, ForwardIter last, Pred pred);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr bool none_of(I first, S last, Pred pred, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr bool none_of(R&& r, Pred pred, Proj proj = {});
  }

  // 对每个
  template<class InputIter, class Function>
    constexpr Function for_each(InputIter first, InputIter last, Function f);
  template<class ExecutionPolicy, class ForwardIter, class Function>
    void for_each(ExecutionPolicy&& exec,
                  ForwardIter first, ForwardIter last, Function f);

  namespace ranges {
    template<class I, class F>
      using for_each_result = in_fun_result<I, F>;

    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirectly_unary_invocable<projected<I, Proj>> Fun>
      constexpr for_each_result<I, Fun>
        for_each(I first, S last, Fun f, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirectly_unary_invocable<projected<iterator_t<R>, Proj>> Fun>
      constexpr for_each_result<borrowed_iterator_t<R>, Fun>
        for_each(R&& r, Fun f, Proj proj = {});
  }

  template<class InputIter, class Size, class Function>
    constexpr InputIter for_each_n(InputIter first, Size n, Function f);
  template<class ExecutionPolicy, class ForwardIter, class Size, class Function>
    ForwardIter for_each_n(ExecutionPolicy&& exec,
                               ForwardIter first, Size n, Function f);

  namespace ranges {
    template<class I, class F>
      using for_each_n_result = in_fun_result<I, F>;

    template<input_iterator I, class Proj = identity,
             indirectly_unary_invocable<projected<I, Proj>> Fun>
      constexpr for_each_n_result<I, Fun>
        for_each_n(I first, iter_difference_t<I> n, Fun f, Proj proj = {});
  }

  // 寻找
  template<class InputIter, class T>
    constexpr InputIter find(InputIter first, InputIter last,
                                 const T& value);
  template<class ExecutionPolicy, class ForwardIter, class T>
    ForwardIter find(ExecutionPolicy&& exec,
                         ForwardIter first, ForwardIter last,
                         const T& value);
  template<class InputIter, class Pred>
    constexpr InputIter find_if(InputIter first, InputIter last,
                                    Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    ForwardIter find_if(ExecutionPolicy&& exec,
                            ForwardIter first, ForwardIter last,
                            Pred pred);
  template<class InputIter, class Pred>
    constexpr InputIter find_if_not(InputIter first, InputIter last,
                                        Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    ForwardIter find_if_not(ExecutionPolicy&& exec,
                                ForwardIter first, ForwardIter last,
                                Pred pred);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S, class T, class Proj = identity>
      requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
      constexpr I find(I first, S last, const T& value, Proj proj = {});
    template<input_range R, class T, class Proj = identity>
      requires indirect_binary_predicate<ranges::equal_to,
                                         projected<iterator_t<R>, Proj>, const T*>
      constexpr borrowed_iterator_t<R>
        find(R&& r, const T& value, Proj proj = {});
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr I find_if(I first, S last, Pred pred, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr borrowed_iterator_t<R>
        find_if(R&& r, Pred pred, Proj proj = {});
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr I find_if_not(I first, S last, Pred pred, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr borrowed_iterator_t<R>
        find_if_not(R&& r, Pred pred, Proj proj = {});
  }

  // 寻找末尾
  template<class ForwardIter1, class ForwardIter2>
    constexpr ForwardIter1
      find_end(ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2);
  template<class ForwardIter1, class ForwardIter2, class BinaryPred>
    constexpr ForwardIter1
      find_end(ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2,
               BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    ForwardIter1
      find_end(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2);
  template<class ExecutionPolicy, class ForwardIter1,
           class ForwardIter2, class BinaryPred>
    ForwardIter1
      find_end(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2,
               BinaryPred pred);

  namespace ranges {
    template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2, sentinel_for<I2> S2,
             class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr subrange<I1>
        find_end(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                 Proj1 proj1 = {}, Proj2 proj2 = {});
    template<forward_range R1, forward_range R2,
             class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr borrowed_subrange_t<R1>
        find_end(R1&& r1, R2&& r2, Pred pred = {},
                 Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // 寻找首个
  template<class InputIter, class ForwardIter>
    constexpr InputIter
      find_first_of(InputIter first1, InputIter last1,
                    ForwardIter first2, ForwardIter last2);
  template<class InputIter, class ForwardIter, class BinaryPred>
    constexpr InputIter
      find_first_of(InputIter first1, InputIter last1,
                    ForwardIter first2, ForwardIter last2,
                    BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    ForwardIter1
      find_first_of(ExecutionPolicy&& exec,
                    ForwardIter1 first1, ForwardIter1 last1,
                    ForwardIter2 first2, ForwardIter2 last2);
  template<class ExecutionPolicy, class ForwardIter1,
           class ForwardIter2, class BinaryPred>
    ForwardIter1
      find_first_of(ExecutionPolicy&& exec,
                    ForwardIter1 first1, ForwardIter1 last1,
                    ForwardIter2 first2, ForwardIter2 last2,
                    BinaryPred pred);

  namespace ranges {
    template<input_iterator I1, sentinel_for<I1> S1, forward_iterator I2, sentinel_for<I2> S2,
             class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr I1 find_first_of(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                                 Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, forward_range R2,
             class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr borrowed_iterator_t<R1>
        find_first_of(R1&& r1, R2&& r2, Pred pred = {},
                      Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // 寻找毗邻
  template<class ForwardIter>
    constexpr ForwardIter
      adjacent_find(ForwardIter first, ForwardIter last);
  template<class ForwardIter, class BinaryPred>
    constexpr ForwardIter
      adjacent_find(ForwardIter first, ForwardIter last,
                    BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter
      adjacent_find(ExecutionPolicy&& exec,
                    ForwardIter first, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter, class BinaryPred>
    ForwardIter
      adjacent_find(ExecutionPolicy&& exec,
                    ForwardIter first, ForwardIter last,
                    BinaryPred pred);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_binary_predicate<projected<I, Proj>,
                                       projected<I, Proj>> Pred = ranges::equal_to>
      constexpr I adjacent_find(I first, S last, Pred pred = {},
                                Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_binary_predicate<projected<iterator_t<R>, Proj>,
                                       projected<iterator_t<R>, Proj>> Pred = ranges::equal_to>
      constexpr borrowed_iterator_t<R>
        adjacent_find(R&& r, Pred pred = {}, Proj proj = {});
  }

  // 计数
  template<class InputIter, class T>
    constexpr typename iterator_traits<InputIter>::difference_type
      count(InputIter first, InputIter last, const T& value);
  template<class ExecutionPolicy, class ForwardIter, class T>
    typename iterator_traits<ForwardIter>::difference_type
      count(ExecutionPolicy&& exec,
            ForwardIter first, ForwardIter last, const T& value);
  template<class InputIter, class Pred>
    constexpr typename iterator_traits<InputIter>::difference_type
      count_if(InputIter first, InputIter last, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    typename iterator_traits<ForwardIter>::difference_type
      count_if(ExecutionPolicy&& exec,
               ForwardIter first, ForwardIter last, Pred pred);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S, class T, class Proj = identity>
      requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
      constexpr iter_difference_t<I>
        count(I first, S last, const T& value, Proj proj = {});
    template<input_range R, class T, class Proj = identity>
      requires indirect_binary_predicate<ranges::equal_to,
                                         projected<iterator_t<R>, Proj>, const T*>
      constexpr range_difference_t<R>
        count(R&& r, const T& value, Proj proj = {});
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr iter_difference_t<I>
        count_if(I first, S last, Pred pred, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr range_difference_t<R>
        count_if(R&& r, Pred pred, Proj proj = {});
  }

  // 不匹配
  template<class InputIter1, class InputIter2>
    constexpr pair<InputIter1, InputIter2>
      mismatch(InputIter1 first1, InputIter1 last1,
               InputIter2 first2);
  template<class InputIter1, class InputIter2, class BinaryPred>
    constexpr pair<InputIter1, InputIter2>
      mismatch(InputIter1 first1, InputIter1 last1,
               InputIter2 first2, BinaryPred pred);
  template<class InputIter1, class InputIter2>
    constexpr pair<InputIter1, InputIter2>
      mismatch(InputIter1 first1, InputIter1 last1,
               InputIter2 first2, InputIter2 last2);
  template<class InputIter1, class InputIter2, class BinaryPred>
    constexpr pair<InputIter1, InputIter2>
      mismatch(InputIter1 first1, InputIter1 last1,
               InputIter2 first2, InputIter2 last2,
               BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    pair<ForwardIter1, ForwardIter2>
      mismatch(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class BinaryPred>
    pair<ForwardIter1, ForwardIter2>
      mismatch(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    pair<ForwardIter1, ForwardIter2>
      mismatch(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class BinaryPred>
    pair<ForwardIter1, ForwardIter2>
      mismatch(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2,
               BinaryPred pred);

  namespace ranges {
    template<class I1, class I2>
      using mismatch_result = in_in_result<I1, I2>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
             class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr mismatch_result<I1, I2>
        mismatch(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                 Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2,
             class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr mismatch_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
        mismatch(R1&& r1, R2&& r2, Pred pred = {},
                 Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // 相等
  template<class InputIter1, class InputIter2>
    constexpr bool equal(InputIter1 first1, InputIter1 last1,
                         InputIter2 first2);
  template<class InputIter1, class InputIter2, class BinaryPred>
    constexpr bool equal(InputIter1 first1, InputIter1 last1,
                         InputIter2 first2, BinaryPred pred);
  template<class InputIter1, class InputIter2>
    constexpr bool equal(InputIter1 first1, InputIter1 last1,
                         InputIter2 first2, InputIter2 last2);
  template<class InputIter1, class InputIter2, class BinaryPred>
    constexpr bool equal(InputIter1 first1, InputIter1 last1,
                         InputIter2 first2, InputIter2 last2,
                         BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    bool equal(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class BinaryPred>
    bool equal(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    bool equal(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class BinaryPred>
    bool equal(ExecutionPolicy&& exec,
               ForwardIter1 first1, ForwardIter1 last1,
               ForwardIter2 first2, ForwardIter2 last2,
               BinaryPred pred);

  namespace ranges {
    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
             class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr bool equal(I1 first1, S1 last1, I2 first2, S2 last2,
                           Pred pred = {},
                           Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr bool equal(R1&& r1, R2&& r2, Pred pred = {},
                           Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // 为排列
  template<class ForwardIter1, class ForwardIter2>
    constexpr bool is_permutation(ForwardIter1 first1, ForwardIter1 last1,
                                  ForwardIter2 first2);
  template<class ForwardIter1, class ForwardIter2, class BinaryPred>
    constexpr bool is_permutation(ForwardIter1 first1, ForwardIter1 last1,
                                  ForwardIter2 first2, BinaryPred pred);
  template<class ForwardIter1, class ForwardIter2>
    constexpr bool is_permutation(ForwardIter1 first1, ForwardIter1 last1,
                                  ForwardIter2 first2, ForwardIter2 last2);
  template<class ForwardIter1, class ForwardIter2, class BinaryPred>
    constexpr bool is_permutation(ForwardIter1 first1, ForwardIter1 last1,
                                  ForwardIter2 first2, ForwardIter2 last2,
                                  BinaryPred pred);

  namespace ranges {
    template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
             sentinel_for<I2> S2, class Proj1 = identity, class Proj2 = identity,
             indirect_equivalence_relation<projected<I1, Proj1>,
                                           projected<I2, Proj2>> Pred = ranges::equal_to>
      constexpr bool is_permutation(I1 first1, S1 last1, I2 first2, S2 last2,
                                    Pred pred = {},
                                    Proj1 proj1 = {}, Proj2 proj2 = {});
    template<forward_range R1, forward_range R2,
             class Proj1 = identity, class Proj2 = identity,
             indirect_equivalence_relation<projected<iterator_t<R1>, Proj1>,
                                           projected<iterator_t<R2>, Proj2>>
               Pred = ranges::equal_to>
      constexpr bool is_permutation(R1&& r1, R2&& r2, Pred pred = {},
                                    Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // 搜索
  template<class ForwardIter1, class ForwardIter2>
    constexpr ForwardIter1
      search(ForwardIter1 first1, ForwardIter1 last1,
             ForwardIter2 first2, ForwardIter2 last2);
  template<class ForwardIter1, class ForwardIter2, class BinaryPred>
    constexpr ForwardIter1
      search(ForwardIter1 first1, ForwardIter1 last1,
             ForwardIter2 first2, ForwardIter2 last2,
             BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    ForwardIter1
      search(ExecutionPolicy&& exec,
             ForwardIter1 first1, ForwardIter1 last1,
             ForwardIter2 first2, ForwardIter2 last2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class BinaryPred>
    ForwardIter1
      search(ExecutionPolicy&& exec,
             ForwardIter1 first1, ForwardIter1 last1,
             ForwardIter2 first2, ForwardIter2 last2,
             BinaryPred pred);

  namespace ranges {
    template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
             sentinel_for<I2> S2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr subrange<I1>
        search(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
               Proj1 proj1 = {}, Proj2 proj2 = {});
    template<forward_range R1, forward_range R2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr borrowed_subrange_t<R1>
        search(R1&& r1, R2&& r2, Pred pred = {},
               Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  template<class ForwardIter, class Size, class T>
    constexpr ForwardIter
      search_n(ForwardIter first, ForwardIter last,
               Size count, const T& value);
  template<class ForwardIter, class Size, class T, class BinaryPred>
    constexpr ForwardIter
      search_n(ForwardIter first, ForwardIter last,
               Size count, const T& value, BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter, class Size, class T>
    ForwardIter
      search_n(ExecutionPolicy&& exec,
               ForwardIter first, ForwardIter last,
               Size count, const T& value);
  template<class ExecutionPolicy, class ForwardIter, class Size, class T,
           class BinaryPred>
    ForwardIter
      search_n(ExecutionPolicy&& exec,
               ForwardIter first, ForwardIter last,
               Size count, const T& value,
               BinaryPred pred);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class T,
             class Pred = ranges::equal_to, class Proj = identity>
      requires indirectly_comparable<I, const T*, Pred, Proj>
      constexpr subrange<I>
        search_n(I first, S last, iter_difference_t<I> count,
                 const T& value, Pred pred = {}, Proj proj = {});
    template<forward_range R, class T, class Pred = ranges::equal_to,
             class Proj = identity>
      requires indirectly_comparable<iterator_t<R>, const T*, Pred, Proj>
      constexpr borrowed_subrange_t<R>
        search_n(R&& r, range_difference_t<R> count,
                 const T& value, Pred pred = {}, Proj proj = {});
  }

  template<class ForwardIter, class Searcher>
    constexpr ForwardIter
      search(ForwardIter first, ForwardIter last, const Searcher& searcher);

  namespace ranges {
    // 始于
    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
             class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr bool starts_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                                 Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr bool starts_with(R1&& r1, R2&& r2, Pred pred = {},
                                 Proj1 proj1 = {}, Proj2 proj2 = {});

    // 终于
    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
             class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
      requires (forward_iterator<I1> || sized_sentinel_for<S1, I1>) &&
               (forward_iterator<I2> || sized_sentinel_for<S2, I2>) &&
               indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
      constexpr bool ends_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                               Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, class Pred = ranges::equal_to,
             class Proj1 = identity, class Proj2 = identity>
      requires (forward_range<R1> || sized_range<R1>) &&
               (forward_range<R2> || sized_range<R2>) &&
               indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
      constexpr bool ends_with(R1&& r1, R2&& r2, Pred pred = {},
                               Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // 修改序列的操作
  // 复制
  template<class InputIter, class OutputIter>
    constexpr OutputIter copy(InputIter first, InputIter last,
                                  OutputIter result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    ForwardIter2 copy(ExecutionPolicy&& exec,
                          ForwardIter1 first, ForwardIter1 last,
                          ForwardIter2 result);

  namespace ranges {
    template<class I, class O>
      using copy_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, weakly_incrementable O>
      requires indirectly_copyable<I, O>
      constexpr copy_result<I, O>
        copy(I first, S last, O result);
    template<input_range R, weakly_incrementable O>
      requires indirectly_copyable<iterator_t<R>, O>
      constexpr copy_result<borrowed_iterator_t<R>, O>
        copy(R&& r, O result);
  }

  template<class InputIter, class Size, class OutputIter>
    constexpr OutputIter copy_n(InputIter first, Size n,
                                    OutputIter result);
  template<class ExecutionPolicy, class ForwardIter1, class Size,
           class ForwardIter2>
    ForwardIter2 copy_n(ExecutionPolicy&& exec,
                            ForwardIter1 first, Size n,
                            ForwardIter2 result);

  namespace ranges {
    template<class I, class O>
      using copy_n_result = in_out_result<I, O>;

    template<input_iterator I, weakly_incrementable O>
      requires indirectly_copyable<I, O>
      constexpr copy_n_result<I, O>
        copy_n(I first, iter_difference_t<I> n, O result);
  }

  template<class InputIter, class OutputIter, class Pred>
    constexpr OutputIter copy_if(InputIter first, InputIter last,
                                     OutputIter result, Pred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class Pred>
    ForwardIter2 copy_if(ExecutionPolicy&& exec,
                             ForwardIter1 first, ForwardIter1 last,
                             ForwardIter2 result, Pred pred);

  namespace ranges {
    template<class I, class O>
      using copy_if_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      requires indirectly_copyable<I, O>
      constexpr copy_if_result<I, O>
        copy_if(I first, S last, O result, Pred pred, Proj proj = {});
    template<input_range R, weakly_incrementable O, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires indirectly_copyable<iterator_t<R>, O>
      constexpr copy_if_result<borrowed_iterator_t<R>, O>
        copy_if(R&& r, O result, Pred pred, Proj proj = {});
  }

  template<class BidirectionalIter1, class BidirectionalIter2>
    constexpr BidirectionalIter2
      copy_backward(BidirectionalIter1 first, BidirectionalIter1 last,
                    BidirectionalIter2 result);

  namespace ranges {
    template<class I1, class I2>
      using copy_backward_result = in_out_result<I1, I2>;

    template<bidirectional_iterator I1, sentinel_for<I1> S1, bidirectional_iterator I2>
      requires indirectly_copyable<I1, I2>
      constexpr copy_backward_result<I1, I2>
        copy_backward(I1 first, S1 last, I2 result);
    template<bidirectional_range R, bidirectional_iterator I>
      requires indirectly_copyable<iterator_t<R>, I>
      constexpr copy_backward_result<borrowed_iterator_t<R>, I>
        copy_backward(R&& r, I result);
  }

  // 移动
  template<class InputIter, class OutputIter>
    constexpr OutputIter move(InputIter first, InputIter last,
                                  OutputIter result);
  template<class ExecutionPolicy, class ForwardIter1,
           class ForwardIter2>
    ForwardIter2 move(ExecutionPolicy&& exec,
                          ForwardIter1 first, ForwardIter1 last,
                          ForwardIter2 result);

  namespace ranges {
    template<class I, class O>
      using move_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, weakly_incrementable O>
      requires indirectly_movable<I, O>
      constexpr move_result<I, O>
        move(I first, S last, O result);
    template<input_range R, weakly_incrementable O>
      requires indirectly_movable<iterator_t<R>, O>
      constexpr move_result<borrowed_iterator_t<R>, O>
        move(R&& r, O result);
  }

  template<class BidirectionalIter1, class BidirectionalIter2>
    constexpr BidirectionalIter2
      move_backward(BidirectionalIter1 first, BidirectionalIter1 last,
                    BidirectionalIter2 result);

  namespace ranges {
    template<class I1, class I2>
      using move_backward_result = in_out_result<I1, I2>;

    template<bidirectional_iterator I1, sentinel_for<I1> S1, bidirectional_iterator I2>
      requires indirectly_movable<I1, I2>
      constexpr move_backward_result<I1, I2>
        move_backward(I1 first, S1 last, I2 result);
    template<bidirectional_range R, bidirectional_iterator I>
      requires indirectly_movable<iterator_t<R>, I>
      constexpr move_backward_result<borrowed_iterator_t<R>, I>
        move_backward(R&& r, I result);
  }

  // 交换
  template<class ForwardIter1, class ForwardIter2>
    constexpr ForwardIter2 swap_ranges(ForwardIter1 first1, ForwardIter1 last1,
                                           ForwardIter2 first2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    ForwardIter2 swap_ranges(ExecutionPolicy&& exec,
                                 ForwardIter1 first1, ForwardIter1 last1,
                                 ForwardIter2 first2);

  namespace ranges {
    template<class I1, class I2>
      using swap_ranges_result = in_in_result<I1, I2>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2>
      requires indirectly_swappable<I1, I2>
      constexpr swap_ranges_result<I1, I2>
        swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2);
    template<input_range R1, input_range R2>
      requires indirectly_swappable<iterator_t<R1>, iterator_t<R2>>
      constexpr swap_ranges_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
        swap_ranges(R1&& r1, R2&& r2);
  }

  template<class ForwardIter1, class ForwardIter2>
    constexpr void iter_swap(ForwardIter1 a, ForwardIter2 b);

  // 变换
  template<class InputIter, class OutputIter, class UnaryOperation>
    constexpr OutputIter
      transform(InputIter first1, InputIter last1,
                OutputIter result, UnaryOperation op);
  template<class InputIter1, class InputIter2, class OutputIter,
           class BinaryOperation>
    constexpr OutputIter
      transform(InputIter1 first1, InputIter1 last1,
                InputIter2 first2, OutputIter result,
                BinaryOperation binary_op);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class UnaryOperation>
    ForwardIter2
      transform(ExecutionPolicy&& exec,
                ForwardIter1 first1, ForwardIter1 last1,
                ForwardIter2 result, UnaryOperation op);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter, class BinaryOperation>
    ForwardIter
      transform(ExecutionPolicy&& exec,
                ForwardIter1 first1, ForwardIter1 last1,
                ForwardIter2 first2, ForwardIter result,
                BinaryOperation binary_op);

  namespace ranges {
    template<class I, class O>
      using unary_transform_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
             copy_constructible F, class Proj = identity>
      requires indirectly_writable<O, indirect_result_t<F&, projected<I, Proj>>>
      constexpr unary_transform_result<I, O>
        transform(I first1, S last1, O result, F op, Proj proj = {});
    template<input_range R, weakly_incrementable O, copy_constructible F,
             class Proj = identity>
      requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R>, Proj>>>
      constexpr unary_transform_result<borrowed_iterator_t<R>, O>
        transform(R&& r, O result, F op, Proj proj = {});

    template<class I1, class I2, class O>
      using binary_transform_result = in_in_out_result<I1, I2, O>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
             weakly_incrementable O, copy_constructible F, class Proj1 = identity,
             class Proj2 = identity>
      requires indirectly_writable<O, indirect_result_t<F&, projected<I1, Proj1>,
                                             projected<I2, Proj2>>>
      constexpr binary_transform_result<I1, I2, O>
        transform(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                  F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, weakly_incrementable O,
             copy_constructible F, class Proj1 = identity, class Proj2 = identity>
      requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R1>, Proj1>,
                                             projected<iterator_t<R2>, Proj2>>>
      constexpr binary_transform_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
        transform(R1&& r1, R2&& r2, O result,
                  F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // 替换
  template<class ForwardIter, class T>
    constexpr void replace(ForwardIter first, ForwardIter last,
                           const T& old_value, const T& new_value);
  template<class ExecutionPolicy, class ForwardIter, class T>
    void replace(ExecutionPolicy&& exec,
                 ForwardIter first, ForwardIter last,
                 const T& old_value, const T& new_value);
  template<class ForwardIter, class Pred, class T>
    constexpr void replace_if(ForwardIter first, ForwardIter last,
                              Pred pred, const T& new_value);
  template<class ExecutionPolicy, class ForwardIter, class Pred, class T>
    void replace_if(ExecutionPolicy&& exec,
                    ForwardIter first, ForwardIter last,
                    Pred pred, const T& new_value);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S, class T1, class T2, class Proj = identity>
      requires indirectly_writable<I, const T2&> &&
               indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T1*>
      constexpr I
        replace(I first, S last, const T1& old_value, const T2& new_value, Proj proj = {});
    template<input_range R, class T1, class T2, class Proj = identity>
      requires indirectly_writable<iterator_t<R>, const T2&> &&
               indirect_binary_predicate<ranges::equal_to,
                                         projected<iterator_t<R>, Proj>, const T1*>
      constexpr borrowed_iterator_t<R>
        replace(R&& r, const T1& old_value, const T2& new_value, Proj proj = {});
    template<input_iterator I, sentinel_for<I> S, class T, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      requires indirectly_writable<I, const T&>
      constexpr I replace_if(I first, S last, Pred pred, const T& new_value, Proj proj = {});
    template<input_range R, class T, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires indirectly_writable<iterator_t<R>, const T&>
      constexpr borrowed_iterator_t<R>
        replace_if(R&& r, Pred pred, const T& new_value, Proj proj = {});
  }

  template<class InputIter, class OutputIter, class T>
    constexpr OutputIter replace_copy(InputIter first, InputIter last,
                                          OutputIter result,
                                          const T& old_value, const T& new_value);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2, class T>
    ForwardIter2 replace_copy(ExecutionPolicy&& exec,
                                  ForwardIter1 first, ForwardIter1 last,
                                  ForwardIter2 result,
                                  const T& old_value, const T& new_value);
  template<class InputIter, class OutputIter, class Pred, class T>
    constexpr OutputIter replace_copy_if(InputIter first, InputIter last,
                                             OutputIter result,
                                             Pred pred, const T& new_value);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class Pred, class T>
    ForwardIter2 replace_copy_if(ExecutionPolicy&& exec,
                                     ForwardIter1 first, ForwardIter1 last,
                                     ForwardIter2 result,
                                     Pred pred, const T& new_value);

  namespace ranges {
    template<class I, class O>
      using replace_copy_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, class T1, class T2,
             output_iterator<const T2&> O, class Proj = identity>
      requires indirectly_copyable<I, O> &&
               indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T1*>
      constexpr replace_copy_result<I, O>
        replace_copy(I first, S last, O result, const T1& old_value, const T2& new_value,
                     Proj proj = {});
    template<input_range R, class T1, class T2, output_iterator<const T2&> O,
             class Proj = identity>
      requires indirectly_copyable<iterator_t<R>, O> &&
               indirect_binary_predicate<ranges::equal_to,
                                         projected<iterator_t<R>, Proj>, const T1*>
      constexpr replace_copy_result<borrowed_iterator_t<R>, O>
        replace_copy(R&& r, O result, const T1& old_value, const T2& new_value,
                     Proj proj = {});

    template<class I, class O>
      using replace_copy_if_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, class T, output_iterator<const T&> O,
             class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
      requires indirectly_copyable<I, O>
      constexpr replace_copy_if_result<I, O>
        replace_copy_if(I first, S last, O result, Pred pred, const T& new_value,
                        Proj proj = {});
    template<input_range R, class T, output_iterator<const T&> O, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires indirectly_copyable<iterator_t<R>, O>
      constexpr replace_copy_if_result<borrowed_iterator_t<R>, O>
        replace_copy_if(R&& r, O result, Pred pred, const T& new_value,
                        Proj proj = {});
  }

  // 填充
  template<class ForwardIter, class T>
    constexpr void fill(ForwardIter first, ForwardIter last, const T& value);
  template<class ExecutionPolicy, class ForwardIter, class T>
    void fill(ExecutionPolicy&& exec,
              ForwardIter first, ForwardIter last, const T& value);
  template<class OutputIter, class Size, class T>
    constexpr OutputIter fill_n(OutputIter first, Size n, const T& value);
  template<class ExecutionPolicy, class ForwardIter,
           class Size, class T>
    ForwardIter fill_n(ExecutionPolicy&& exec,
                           ForwardIter first, Size n, const T& value);

  namespace ranges {
    template<class T, output_iterator<const T&> O, sentinel_for<O> S>
      constexpr O fill(O first, S last, const T& value);
    template<class T, output_range<const T&> R>
      constexpr borrowed_iterator_t<R> fill(R&& r, const T& value);
    template<class T, output_iterator<const T&> O>
      constexpr O fill_n(O first, iter_difference_t<O> n, const T& value);
  }

  // 生成
  template<class ForwardIter, class Generator>
    constexpr void generate(ForwardIter first, ForwardIter last,
                            Generator gen);
  template<class ExecutionPolicy, class ForwardIter, class Generator>
    void generate(ExecutionPolicy&& exec,
                  ForwardIter first, ForwardIter last,
                  Generator gen);
  template<class OutputIter, class Size, class Generator>
    constexpr OutputIter generate_n(OutputIter first, Size n, Generator gen);
  template<class ExecutionPolicy, class ForwardIter, class Size, class Generator>
    ForwardIter generate_n(ExecutionPolicy&& exec,
                               ForwardIter first, Size n, Generator gen);

  namespace ranges {
    template<input_or_output_iterator O, sentinel_for<O> S, copy_constructible F>
      requires invocable<F&> && indirectly_writable<O, invoke_result_t<F&>>
      constexpr O generate(O first, S last, F gen);
    template<class R, copy_constructible F>
      requires invocable<F&> && output_range<R, invoke_result_t<F&>>
      constexpr borrowed_iterator_t<R> generate(R&& r, F gen);
    template<input_or_output_iterator O, copy_constructible F>
      requires invocable<F&> && indirectly_writable<O, invoke_result_t<F&>>
      constexpr O generate_n(O first, iter_difference_t<O> n, F gen);
  }

  // 移除
  template<class ForwardIter, class T>
    constexpr ForwardIter remove(ForwardIter first, ForwardIter last,
                                     const T& value);
  template<class ExecutionPolicy, class ForwardIter, class T>
    ForwardIter remove(ExecutionPolicy&& exec,
                           ForwardIter first, ForwardIter last,
                           const T& value);
  template<class ForwardIter, class Pred>
    constexpr ForwardIter remove_if(ForwardIter first, ForwardIter last,
                                        Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    ForwardIter remove_if(ExecutionPolicy&& exec,
                              ForwardIter first, ForwardIter last,
                              Pred pred);

  namespace ranges {
    template<permutable I, sentinel_for<I> S, class T, class Proj = identity>
      requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
      constexpr subrange<I> remove(I first, S last, const T& value, Proj proj = {});
    template<forward_range R, class T, class Proj = identity>
      requires permutable<iterator_t<R>> &&
               indirect_binary_predicate<ranges::equal_to,
                                         projected<iterator_t<R>, Proj>, const T*>
      constexpr borrowed_subrange_t<R>
        remove(R&& r, const T& value, Proj proj = {});
    template<permutable I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr subrange<I> remove_if(I first, S last, Pred pred, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires permutable<iterator_t<R>>
      constexpr borrowed_subrange_t<R>
        remove_if(R&& r, Pred pred, Proj proj = {});
  }

  template<class InputIter, class OutputIter, class T>
    constexpr OutputIter
      remove_copy(InputIter first, InputIter last,
                  OutputIter result, const T& value);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class T>
    ForwardIter2
      remove_copy(ExecutionPolicy&& exec,
                  ForwardIter1 first, ForwardIter1 last,
                  ForwardIter2 result, const T& value);
  template<class InputIter, class OutputIter, class Pred>
    constexpr OutputIter
      remove_copy_if(InputIter first, InputIter last,
                     OutputIter result, Pred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class Pred>
    ForwardIter2
      remove_copy_if(ExecutionPolicy&& exec,
                     ForwardIter1 first, ForwardIter1 last,
                     ForwardIter2 result, Pred pred);

  namespace ranges {
    template<class I, class O>
      using remove_copy_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class T,
             class Proj = identity>
      requires indirectly_copyable<I, O> &&
               indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
      constexpr remove_copy_result<I, O>
        remove_copy(I first, S last, O result, const T& value, Proj proj = {});
    template<input_range R, weakly_incrementable O, class T, class Proj = identity>
      requires indirectly_copyable<iterator_t<R>, O> &&
               indirect_binary_predicate<ranges::equal_to,
                                         projected<iterator_t<R>, Proj>, const T*>
      constexpr remove_copy_result<borrowed_iterator_t<R>, O>
        remove_copy(R&& r, O result, const T& value, Proj proj = {});

    template<class I, class O>
      using remove_copy_if_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
             class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
      requires indirectly_copyable<I, O>
      constexpr remove_copy_if_result<I, O>
        remove_copy_if(I first, S last, O result, Pred pred, Proj proj = {});
    template<input_range R, weakly_incrementable O, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires indirectly_copyable<iterator_t<R>, O>
      constexpr remove_copy_if_result<borrowed_iterator_t<R>, O>
        remove_copy_if(R&& r, O result, Pred pred, Proj proj = {});
  }

  // 归一
  template<class ForwardIter>
    constexpr ForwardIter unique(ForwardIter first, ForwardIter last);
  template<class ForwardIter, class BinaryPred>
    constexpr ForwardIter unique(ForwardIter first, ForwardIter last,
                                     BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter unique(ExecutionPolicy&& exec,
                           ForwardIter first, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter, class BinaryPred>
    ForwardIter unique(ExecutionPolicy&& exec,
                           ForwardIter first, ForwardIter last,
                           BinaryPred pred);

  namespace ranges {
    template<permutable I, sentinel_for<I> S, class Proj = identity,
             indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
      constexpr subrange<I> unique(I first, S last, C comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to>
      requires permutable<iterator_t<R>>
      constexpr borrowed_subrange_t<R>
        unique(R&& r, C comp = {}, Proj proj = {});
  }

  template<class InputIter, class OutputIter>
    constexpr OutputIter
      unique_copy(InputIter first, InputIter last,
                  OutputIter result);
  template<class InputIter, class OutputIter, class BinaryPred>
    constexpr OutputIter
      unique_copy(InputIter first, InputIter last,
                  OutputIter result, BinaryPred pred);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    ForwardIter2
      unique_copy(ExecutionPolicy&& exec,
                  ForwardIter1 first, ForwardIter1 last,
                  ForwardIter2 result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class BinaryPred>
    ForwardIter2
      unique_copy(ExecutionPolicy&& exec,
                  ForwardIter1 first, ForwardIter1 last,
                  ForwardIter2 result, BinaryPred pred);

  namespace ranges {
    template<class I, class O>
      using unique_copy_result = in_out_result<I, O>;

    template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Proj = identity,
             indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
      requires indirectly_copyable<I, O> &&
               (forward_iterator<I> ||
                (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) ||
                indirectly_copyable_storable<I, O>)
      constexpr unique_copy_result<I, O>
        unique_copy(I first, S last, O result, C comp = {}, Proj proj = {});
    template<input_range R, weakly_incrementable O, class Proj = identity,
             indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to>
      requires indirectly_copyable<iterator_t<R>, O> &&
               (forward_iterator<iterator_t<R>> ||
                (input_iterator<O> && same_as<range_value_t<R>, iter_value_t<O>>) ||
                indirectly_copyable_storable<iterator_t<R>, O>)
      constexpr unique_copy_result<borrowed_iterator_t<R>, O>
        unique_copy(R&& r, O result, C comp = {}, Proj proj = {});
  }

  // 逆转
  template<class BidirectionalIter>
    constexpr void reverse(BidirectionalIter first, BidirectionalIter last);
  template<class ExecutionPolicy, class BidirectionalIter>
    void reverse(ExecutionPolicy&& exec,
                 BidirectionalIter first, BidirectionalIter last);

  namespace ranges {
    template<bidirectional_iterator I, sentinel_for<I> S>
      requires permutable<I>
      constexpr I reverse(I first, S last);
    template<bidirectional_range R>
      requires permutable<iterator_t<R>>
      constexpr borrowed_iterator_t<R> reverse(R&& r);
  }

  template<class BidirectionalIter, class OutputIter>
    constexpr OutputIter
      reverse_copy(BidirectionalIter first, BidirectionalIter last,
                   OutputIter result);
  template<class ExecutionPolicy, class BidirectionalIter, class ForwardIter>
    ForwardIter
      reverse_copy(ExecutionPolicy&& exec,
                   BidirectionalIter first, BidirectionalIter last,
                   ForwardIter result);

  namespace ranges {
    template<class I, class O>
      using reverse_copy_result = in_out_result<I, O>;

    template<bidirectional_iterator I, sentinel_for<I> S, weakly_incrementable O>
      requires indirectly_copyable<I, O>
      constexpr reverse_copy_result<I, O>
        reverse_copy(I first, S last, O result);
    template<bidirectional_range R, weakly_incrementable O>
      requires indirectly_copyable<iterator_t<R>, O>
      constexpr reverse_copy_result<borrowed_iterator_t<R>, O>
        reverse_copy(R&& r, O result);
  }

  // 旋转
  template<class ForwardIter>
    constexpr ForwardIter rotate(ForwardIter first,
                                     ForwardIter middle,
                                     ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter rotate(ExecutionPolicy&& exec,
                           ForwardIter first,
                           ForwardIter middle,
                           ForwardIter last);

  namespace ranges {
    template<permutable I, sentinel_for<I> S>
      constexpr subrange<I> rotate(I first, I middle, S last);
    template<forward_range R>
      requires permutable<iterator_t<R>>
      constexpr borrowed_subrange_t<R> rotate(R&& r, iterator_t<R> middle);
  }

  template<class ForwardIter, class OutputIter>
    constexpr OutputIter
      rotate_copy(ForwardIter first, ForwardIter middle,
                  ForwardIter last, OutputIter result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    ForwardIter2
      rotate_copy(ExecutionPolicy&& exec,
                  ForwardIter1 first, ForwardIter1 middle,
                  ForwardIter1 last, ForwardIter2 result);

  namespace ranges {
    template<class I, class O>
      using rotate_copy_result = in_out_result<I, O>;

    template<forward_iterator I, sentinel_for<I> S, weakly_incrementable O>
      requires indirectly_copyable<I, O>
      constexpr rotate_copy_result<I, O>
        rotate_copy(I first, I middle, S last, O result);
    template<forward_range R, weakly_incrementable O>
      requires indirectly_copyable<iterator_t<R>, O>
      constexpr rotate_copy_result<borrowed_iterator_t<R>, O>
        rotate_copy(R&& r, iterator_t<R> middle, O result);
  }

  // 采样
  template<class PopulationIter, class SampleIter,
           class Distance, class UniformRandomBitGenerator>
    SampleIter sample(PopulationIter first, PopulationIter last,
                          SampleIter out, Distance n,
                          UniformRandomBitGenerator&& g);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S,
             weakly_incrementable O, class Gen>
      requires (forward_iterator<I> || random_access_iterator<O>) &&
               indirectly_copyable<I, O> &&
               uniform_random_bit_generator<remove_reference_t<Gen>>
      O sample(I first, S last, O out, iter_difference_t<I> n, Gen&& g);
    template<input_range R, weakly_incrementable O, class Gen>
      requires (forward_range<R> || random_access_iterator<O>) &&
               indirectly_copyable<iterator_t<R>, O> &&
               uniform_random_bit_generator<remove_reference_t<Gen>>
      O sample(R&& r, O out, range_difference_t<R> n, Gen&& g);
  }

  // 打乱
  template<class RandomAccessIter, class UniformRandomBitGenerator>
    void shuffle(RandomAccessIter first,
                 RandomAccessIter last,
                 UniformRandomBitGenerator&& g);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S, class Gen>
      requires permutable<I> &&
               uniform_random_bit_generator<remove_reference_t<Gen>>
      I shuffle(I first, S last, Gen&& g);
    template<random_access_range R, class Gen>
      requires permutable<iterator_t<R>> &&
               uniform_random_bit_generator<remove_reference_t<Gen>>
      borrowed_iterator_t<R> shuffle(R&& r, Gen&& g);
  }

  // 迁移
  template<class ForwardIter>
    constexpr ForwardIter
      shift_left(ForwardIter first, ForwardIter last,
                 typename iterator_traits<ForwardIter>::difference_type n);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter
      shift_left(ExecutionPolicy&& exec,
                 ForwardIter first, ForwardIter last,
                 typename iterator_traits<ForwardIter>::difference_type n);
  template<class ForwardIter>
    constexpr ForwardIter
      shift_right(ForwardIter first, ForwardIter last,
                  typename iterator_traits<ForwardIter>::difference_type n);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter
      shift_right(ExecutionPolicy&& exec,
                  ForwardIter first, ForwardIter last,
                  typename iterator_traits<ForwardIter>::difference_type n);

  // 排序与相关操作
  // 排序
  template<class RandomAccessIter>
    constexpr void sort(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr void sort(RandomAccessIter first, RandomAccessIter last,
                        Compare comp);
  template<class ExecutionPolicy, class RandomAccessIter>
    void sort(ExecutionPolicy&& exec,
              RandomAccessIter first, RandomAccessIter last);
  template<class ExecutionPolicy, class RandomAccessIter, class Compare>
    void sort(ExecutionPolicy&& exec,
              RandomAccessIter first, RandomAccessIter last,
              Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr I
        sort(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr borrowed_iterator_t<R>
        sort(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class RandomAccessIter>
    void stable_sort(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    void stable_sort(RandomAccessIter first, RandomAccessIter last,
                     Compare comp);
  template<class ExecutionPolicy, class RandomAccessIter>
    void stable_sort(ExecutionPolicy&& exec,
                     RandomAccessIter first, RandomAccessIter last);
  template<class ExecutionPolicy, class RandomAccessIter, class Compare>
    void stable_sort(ExecutionPolicy&& exec,
                     RandomAccessIter first, RandomAccessIter last,
                     Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<I, Comp, Proj>
      I stable_sort(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      borrowed_iterator_t<R>
        stable_sort(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class RandomAccessIter>
    constexpr void partial_sort(RandomAccessIter first, RandomAccessIter middle,
                                RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr void partial_sort(RandomAccessIter first, RandomAccessIter middle,
                                RandomAccessIter last, Compare comp);
  template<class ExecutionPolicy, class RandomAccessIter>
    void partial_sort(ExecutionPolicy&& exec,
                      RandomAccessIter first, RandomAccessIter middle,
                      RandomAccessIter last);
  template<class ExecutionPolicy, class RandomAccessIter, class Compare>
    void partial_sort(ExecutionPolicy&& exec,
                      RandomAccessIter first, RandomAccessIter middle,
                      RandomAccessIter last, Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr I
        partial_sort(I first, I middle, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr borrowed_iterator_t<R>
        partial_sort(R&& r, iterator_t<R> middle, Comp comp = {},
                     Proj proj = {});
  }

  template<class InputIter, class RandomAccessIter>
    constexpr RandomAccessIter
      partial_sort_copy(InputIter first, InputIter last,
                        RandomAccessIter result_first,
                        RandomAccessIter result_last);
  template<class InputIter, class RandomAccessIter, class Compare>
    constexpr RandomAccessIter
      partial_sort_copy(InputIter first, InputIter last,
                        RandomAccessIter result_first,
                        RandomAccessIter result_last,
                        Compare comp);
  template<class ExecutionPolicy, class ForwardIter, class RandomAccessIter>
    RandomAccessIter
      partial_sort_copy(ExecutionPolicy&& exec,
                        ForwardIter first, ForwardIter last,
                        RandomAccessIter result_first,
                        RandomAccessIter result_last);
  template<class ExecutionPolicy, class ForwardIter, class RandomAccessIter,
           class Compare>
    RandomAccessIter
      partial_sort_copy(ExecutionPolicy&& exec,
                        ForwardIter first, ForwardIter last,
                        RandomAccessIter result_first,
                        RandomAccessIter result_last,
                        Compare comp);

  namespace ranges {
    template<class I, class O>
      using partial_sort_copy_result = in_out_result<I, O>;

    template<input_iterator I1, sentinel_for<I1> S1,
             random_access_iterator I2, sentinel_for<I2> S2,
             class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
      requires indirectly_copyable<I1, I2> && sortable<I2, Comp, Proj2> &&
               indirect_strict_weak_order<Comp, projected<I1, Proj1>, projected<I2, Proj2>>
      constexpr partial_sort_copy_result<I1, I2>
        partial_sort_copy(I1 first, S1 last, I2 result_first, S2 result_last,
                          Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, random_access_range R2, class Comp = ranges::less,
             class Proj1 = identity, class Proj2 = identity>
      requires indirectly_copyable<iterator_t<R1>, iterator_t<R2>> &&
               sortable<iterator_t<R2>, Comp, Proj2> &&
               indirect_strict_weak_order<Comp, projected<iterator_t<R1>, Proj1>,
                                          projected<iterator_t<R2>, Proj2>>
      constexpr partial_sort_copy_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
        partial_sort_copy(R1&& r, R2&& result_r, Comp comp = {},
                          Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  template<class ForwardIter>
    constexpr bool is_sorted(ForwardIter first, ForwardIter last);
  template<class ForwardIter, class Compare>
    constexpr bool is_sorted(ForwardIter first, ForwardIter last,
                             Compare comp);
  template<class ExecutionPolicy, class ForwardIter>
    bool is_sorted(ExecutionPolicy&& exec,
                   ForwardIter first, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter, class Compare>
    bool is_sorted(ExecutionPolicy&& exec,
                   ForwardIter first, ForwardIter last,
                   Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
      constexpr bool is_sorted(I first, S last, Comp comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr bool is_sorted(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class ForwardIter>
    constexpr ForwardIter
      is_sorted_until(ForwardIter first, ForwardIter last);
  template<class ForwardIter, class Compare>
    constexpr ForwardIter
      is_sorted_until(ForwardIter first, ForwardIter last,
                      Compare comp);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter
      is_sorted_until(ExecutionPolicy&& exec,
                      ForwardIter first, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter, class Compare>
    ForwardIter
      is_sorted_until(ExecutionPolicy&& exec,
                      ForwardIter first, ForwardIter last,
                      Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
      constexpr I is_sorted_until(I first, S last, Comp comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr borrowed_iterator_t<R>
        is_sorted_until(R&& r, Comp comp = {}, Proj proj = {});
  }

  // 第 N 元素
  template<class RandomAccessIter>
    constexpr void nth_element(RandomAccessIter first, RandomAccessIter nth,
                               RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr void nth_element(RandomAccessIter first, RandomAccessIter nth,
                               RandomAccessIter last, Compare comp);
  template<class ExecutionPolicy, class RandomAccessIter>
    void nth_element(ExecutionPolicy&& exec,
                     RandomAccessIter first, RandomAccessIter nth,
                     RandomAccessIter last);
  template<class ExecutionPolicy, class RandomAccessIter, class Compare>
    void nth_element(ExecutionPolicy&& exec,
                     RandomAccessIter first, RandomAccessIter nth,
                     RandomAccessIter last, Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr I
        nth_element(I first, I nth, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr borrowed_iterator_t<R>
        nth_element(R&& r, iterator_t<R> nth, Comp comp = {}, Proj proj = {});
  }

  // 二分搜索
  template<class ForwardIter, class T>
    constexpr ForwardIter
      lower_bound(ForwardIter first, ForwardIter last,
                  const T& value);
  template<class ForwardIter, class T, class Compare>
    constexpr ForwardIter
      lower_bound(ForwardIter first, ForwardIter last,
                  const T& value, Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity,
             indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
      constexpr I lower_bound(I first, S last, const T& value, Comp comp = {},
                              Proj proj = {});
    template<forward_range R, class T, class Proj = identity,
             indirect_strict_weak_order<const T*, projected<iterator_t<R>, Proj>> Comp =
               ranges::less>
      constexpr borrowed_iterator_t<R>
        lower_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {});
  }

  template<class ForwardIter, class T>
    constexpr ForwardIter
      upper_bound(ForwardIter first, ForwardIter last,
                  const T& value);
  template<class ForwardIter, class T, class Compare>
    constexpr ForwardIter
      upper_bound(ForwardIter first, ForwardIter last,
                  const T& value, Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity,
             indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
      constexpr I upper_bound(I first, S last, const T& value, Comp comp = {}, Proj proj = {});
    template<forward_range R, class T, class Proj = identity,
             indirect_strict_weak_order<const T*, projected<iterator_t<R>, Proj>> Comp =
               ranges::less>
      constexpr borrowed_iterator_t<R>
        upper_bound(R&& r, const T& value, Comp comp = {}, Proj proj = {});
  }

  template<class ForwardIter, class T>
    constexpr pair<ForwardIter, ForwardIter>
      equal_range(ForwardIter first, ForwardIter last,
                  const T& value);
  template<class ForwardIter, class T, class Compare>
    constexpr pair<ForwardIter, ForwardIter>
      equal_range(ForwardIter first, ForwardIter last,
                  const T& value, Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity,
             indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
      constexpr subrange<I>
        equal_range(I first, S last, const T& value, Comp comp = {}, Proj proj = {});
    template<forward_range R, class T, class Proj = identity,
             indirect_strict_weak_order<const T*, projected<iterator_t<R>, Proj>> Comp =
               ranges::less>
      constexpr borrowed_subrange_t<R>
        equal_range(R&& r, const T& value, Comp comp = {}, Proj proj = {});
  }

  template<class ForwardIter, class T>
    constexpr bool
      binary_search(ForwardIter first, ForwardIter last,
                    const T& value);
  template<class ForwardIter, class T, class Compare>
    constexpr bool
      binary_search(ForwardIter first, ForwardIter last,
                    const T& value, Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity,
             indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
      constexpr bool binary_search(I first, S last, const T& value, Comp comp = {},
                                   Proj proj = {});
    template<forward_range R, class T, class Proj = identity,
             indirect_strict_weak_order<const T*, projected<iterator_t<R>, Proj>> Comp =
               ranges::less>
      constexpr bool binary_search(R&& r, const T& value, Comp comp = {},
                                   Proj proj = {});
  }

  // 划分
  template<class InputIter, class Pred>
    constexpr bool is_partitioned(InputIter first, InputIter last, Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    bool is_partitioned(ExecutionPolicy&& exec,
                        ForwardIter first, ForwardIter last, Pred pred);

  namespace ranges {
    template<input_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr bool is_partitioned(I first, S last, Pred pred, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr bool is_partitioned(R&& r, Pred pred, Proj proj = {});
  }

  template<class ForwardIter, class Pred>
    constexpr ForwardIter partition(ForwardIter first,
                                        ForwardIter last,
                                        Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class Pred>
    ForwardIter partition(ExecutionPolicy&& exec,
                              ForwardIter first,
                              ForwardIter last,
                              Pred pred);

  namespace ranges {
    template<permutable I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr subrange<I>
        partition(I first, S last, Pred pred, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires permutable<iterator_t<R>>
      constexpr borrowed_subrange_t<R>
        partition(R&& r, Pred pred, Proj proj = {});
  }

  template<class BidirectionalIter, class Pred>
    BidirectionalIter stable_partition(BidirectionalIter first,
                                           BidirectionalIter last,
                                           Pred pred);
  template<class ExecutionPolicy, class BidirectionalIter, class Pred>
    BidirectionalIter stable_partition(ExecutionPolicy&& exec,
                                           BidirectionalIter first,
                                           BidirectionalIter last,
                                           Pred pred);

  namespace ranges {
    template<bidirectional_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      requires permutable<I>
      subrange<I> stable_partition(I first, S last, Pred pred, Proj proj = {});
    template<bidirectional_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires permutable<iterator_t<R>>
      borrowed_subrange_t<R> stable_partition(R&& r, Pred pred, Proj proj = {});
  }

  template<class InputIter, class OutputIter1,
           class OutputIter2, class Pred>
    constexpr pair<OutputIter1, OutputIter2>
      partition_copy(InputIter first, InputIter last,
                     OutputIter1 out_true, OutputIter2 out_false,
                     Pred pred);
  template<class ExecutionPolicy, class ForwardIter, class ForwardIter1,
           class ForwardIter2, class Pred>
    pair<ForwardIter1, ForwardIter2>
      partition_copy(ExecutionPolicy&& exec,
                     ForwardIter first, ForwardIter last,
                     ForwardIter1 out_true, ForwardIter2 out_false,
                     Pred pred);

  namespace ranges {
    template<class I, class O1, class O2>
      using partition_copy_result = in_out_out_result<I, O1, O2>;

    template<input_iterator I, sentinel_for<I> S,
             weakly_incrementable O1, weakly_incrementable O2,
             class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
      requires indirectly_copyable<I, O1> && indirectly_copyable<I, O2>
      constexpr partition_copy_result<I, O1, O2>
        partition_copy(I first, S last, O1 out_true, O2 out_false, Pred pred,
                       Proj proj = {});
    template<input_range R, weakly_incrementable O1, weakly_incrementable O2,
             class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      requires indirectly_copyable<iterator_t<R>, O1> &&
               indirectly_copyable<iterator_t<R>, O2>
      constexpr partition_copy_result<borrowed_iterator_t<R>, O1, O2>
        partition_copy(R&& r, O1 out_true, O2 out_false, Pred pred, Proj proj = {});
  }

  template<class ForwardIter, class Pred>
    constexpr ForwardIter
      partition_point(ForwardIter first, ForwardIter last,
                      Pred pred);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_unary_predicate<projected<I, Proj>> Pred>
      constexpr I partition_point(I first, S last, Pred pred, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
      constexpr borrowed_iterator_t<R>
        partition_point(R&& r, Pred pred, Proj proj = {});
  }

  // 归并
  template<class InputIter1, class InputIter2, class OutputIter>
    constexpr OutputIter
      merge(InputIter1 first1, InputIter1 last1,
            InputIter2 first2, InputIter2 last2,
            OutputIter result);
  template<class InputIter1, class InputIter2, class OutputIter,
           class Compare>
    constexpr OutputIter
      merge(InputIter1 first1, InputIter1 last1,
            InputIter2 first2, InputIter2 last2,
            OutputIter result, Compare comp);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter>
    ForwardIter
      merge(ExecutionPolicy&& exec,
            ForwardIter1 first1, ForwardIter1 last1,
            ForwardIter2 first2, ForwardIter2 last2,
            ForwardIter result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter, class Compare>
    ForwardIter
      merge(ExecutionPolicy&& exec,
            ForwardIter1 first1, ForwardIter1 last1,
            ForwardIter2 first2, ForwardIter2 last2,
            ForwardIter result, Compare comp);

  namespace ranges {
    template<class I1, class I2, class O>
      using merge_result = in_in_out_result<I1, I2, O>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
             weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity,
             class Proj2 = identity>
      requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
      constexpr merge_result<I1, I2, O>
        merge(I1 first1, S1 last1, I2 first2, S2 last2, O result,
              Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, weakly_incrementable O, class Comp = ranges::less,
             class Proj1 = identity, class Proj2 = identity>
      requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
      constexpr merge_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
        merge(R1&& r1, R2&& r2, O result,
              Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  template<class BidirectionalIter>
    void inplace_merge(BidirectionalIter first,
                       BidirectionalIter middle,
                       BidirectionalIter last);
  template<class BidirectionalIter, class Compare>
    void inplace_merge(BidirectionalIter first,
                       BidirectionalIter middle,
                       BidirectionalIter last, Compare comp);
  template<class ExecutionPolicy, class BidirectionalIter>
    void inplace_merge(ExecutionPolicy&& exec,
                       BidirectionalIter first,
                       BidirectionalIter middle,
                       BidirectionalIter last);
  template<class ExecutionPolicy, class BidirectionalIter, class Compare>
    void inplace_merge(ExecutionPolicy&& exec,
                       BidirectionalIter first,
                       BidirectionalIter middle,
                       BidirectionalIter last, Compare comp);

  namespace ranges {
    template<bidirectional_iterator I, sentinel_for<I> S, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<I, Comp, Proj>
      I inplace_merge(I first, I middle, S last, Comp comp = {}, Proj proj = {});
    template<bidirectional_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      borrowed_iterator_t<R>
        inplace_merge(R&& r, iterator_t<R> middle, Comp comp = {},
                      Proj proj = {});
  }

  // 集合操作
  template<class InputIter1, class InputIter2>
    constexpr bool includes(InputIter1 first1, InputIter1 last1,
                            InputIter2 first2, InputIter2 last2);
  template<class InputIter1, class InputIter2, class Compare>
    constexpr bool includes(InputIter1 first1, InputIter1 last1,
                            InputIter2 first2, InputIter2 last2,
                            Compare comp);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    bool includes(ExecutionPolicy&& exec,
                  ForwardIter1 first1, ForwardIter1 last1,
                  ForwardIter2 first2, ForwardIter2 last2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class Compare>
    bool includes(ExecutionPolicy&& exec,
                  ForwardIter1 first1, ForwardIter1 last1,
                  ForwardIter2 first2, ForwardIter2 last2,
                  Compare comp);

  namespace ranges {
    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
             class Proj1 = identity, class Proj2 = identity,
             indirect_strict_weak_order<projected<I1, Proj1>, projected<I2, Proj2>> Comp =
               ranges::less>
      constexpr bool includes(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp = {},
                              Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, class Proj1 = identity,
             class Proj2 = identity,
             indirect_strict_weak_order<projected<iterator_t<R1>, Proj1>,
                                        projected<iterator_t<R2>, Proj2>> Comp = ranges::less>
      constexpr bool includes(R1&& r1, R2&& r2, Comp comp = {},
                              Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  template<class InputIter1, class InputIter2, class OutputIter>
    constexpr OutputIter
      set_union(InputIter1 first1, InputIter1 last1,
                InputIter2 first2, InputIter2 last2,
                OutputIter result);
  template<class InputIter1, class InputIter2, class OutputIter, class Compare>
    constexpr OutputIter
                set_union(InputIter1 first1, InputIter1 last1,
                InputIter2 first2, InputIter2 last2,
                OutputIter result, Compare comp);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter>
    ForwardIter
      set_union(ExecutionPolicy&& exec,
                ForwardIter1 first1, ForwardIter1 last1,
                ForwardIter2 first2, ForwardIter2 last2,
                ForwardIter result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter, class Compare>
    ForwardIter
      set_union(ExecutionPolicy&& exec,
                ForwardIter1 first1, ForwardIter1 last1,
                ForwardIter2 first2, ForwardIter2 last2,
                ForwardIter result, Compare comp);

  namespace ranges {
    template<class I1, class I2, class O>
      using set_union_result = in_in_out_result<I1, I2, O>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
             weakly_incrementable O, class Comp = ranges::less,
             class Proj1 = identity, class Proj2 = identity>
      requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
      constexpr set_union_result<I1, I2, O>
        set_union(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {},
                  Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, weakly_incrementable O,
             class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
      requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
      constexpr set_union_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
        set_union(R1&& r1, R2&& r2, O result, Comp comp = {},
                  Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  template<class InputIter1, class InputIter2, class OutputIter>
    constexpr OutputIter
      set_intersection(InputIter1 first1, InputIter1 last1,
                       InputIter2 first2, InputIter2 last2,
                       OutputIter result);
  template<class InputIter1, class InputIter2, class OutputIter, class Compare>
    constexpr OutputIter
      set_intersection(InputIter1 first1, InputIter1 last1,
                       InputIter2 first2, InputIter2 last2,
                       OutputIter result, Compare comp);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter>
    ForwardIter
      set_intersection(ExecutionPolicy&& exec,
                       ForwardIter1 first1, ForwardIter1 last1,
                       ForwardIter2 first2, ForwardIter2 last2,
                       ForwardIter result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter, class Compare>
    ForwardIter
      set_intersection(ExecutionPolicy&& exec,
                       ForwardIter1 first1, ForwardIter1 last1,
                       ForwardIter2 first2, ForwardIter2 last2,
                       ForwardIter result, Compare comp);

  namespace ranges {
    template<class I1, class I2, class O>
      using set_intersection_result = in_in_out_result<I1, I2, O>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
             weakly_incrementable O, class Comp = ranges::less,
             class Proj1 = identity, class Proj2 = identity>
      requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
      constexpr set_intersection_result<I1, I2, O>
        set_intersection(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                         Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, weakly_incrementable O,
             class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
      requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
      constexpr set_intersection_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
        set_intersection(R1&& r1, R2&& r2, O result,
                         Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  template<class InputIter1, class InputIter2, class OutputIter>
    constexpr OutputIter
      set_difference(InputIter1 first1, InputIter1 last1,
                     InputIter2 first2, InputIter2 last2,
                     OutputIter result);
  template<class InputIter1, class InputIter2, class OutputIter, class Compare>
    constexpr OutputIter
      set_difference(InputIter1 first1, InputIter1 last1,
                     InputIter2 first2, InputIter2 last2,
                     OutputIter result, Compare comp);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter>
    ForwardIter
      set_difference(ExecutionPolicy&& exec,
                     ForwardIter1 first1, ForwardIter1 last1,
                     ForwardIter2 first2, ForwardIter2 last2,
                     ForwardIter result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter, class Compare>
    ForwardIter
      set_difference(ExecutionPolicy&& exec,
                     ForwardIter1 first1, ForwardIter1 last1,
                     ForwardIter2 first2, ForwardIter2 last2,
                     ForwardIter result, Compare comp);

  namespace ranges {
    template<class I, class O>
      using set_difference_result = in_out_result<I, O>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
             weakly_incrementable O, class Comp = ranges::less,
             class Proj1 = identity, class Proj2 = identity>
      requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
      constexpr set_difference_result<I1, O>
        set_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                       Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, weakly_incrementable O,
             class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
      requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
      constexpr set_difference_result<borrowed_iterator_t<R1>, O>
        set_difference(R1&& r1, R2&& r2, O result,
                       Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  template<class InputIter1, class InputIter2, class OutputIter>
    constexpr OutputIter
      set_symmetric_difference(InputIter1 first1, InputIter1 last1,
                               InputIter2 first2, InputIter2 last2,
                               OutputIter result);
  template<class InputIter1, class InputIter2, class OutputIter, class Compare>
    constexpr OutputIter
      set_symmetric_difference(InputIter1 first1, InputIter1 last1,
                               InputIter2 first2, InputIter2 last2,
                               OutputIter result, Compare comp);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter>
    ForwardIter
      set_symmetric_difference(ExecutionPolicy&& exec,
                               ForwardIter1 first1, ForwardIter1 last1,
                               ForwardIter2 first2, ForwardIter2 last2,
                               ForwardIter result);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class ForwardIter, class Compare>
    ForwardIter
      set_symmetric_difference(ExecutionPolicy&& exec,
                               ForwardIter1 first1, ForwardIter1 last1,
                               ForwardIter2 first2, ForwardIter2 last2,
                               ForwardIter result, Compare comp);

  namespace ranges {
    template<class I1, class I2, class O>
      using set_symmetric_difference_result = in_in_out_result<I1, I2, O>;

    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
             weakly_incrementable O, class Comp = ranges::less,
             class Proj1 = identity, class Proj2 = identity>
      requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
      constexpr set_symmetric_difference_result<I1, I2, O>
        set_symmetric_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                                 Comp comp = {}, Proj1 proj1 = {},
                                 Proj2 proj2 = {});
    template<input_range R1, input_range R2, weakly_incrementable O,
             class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
      requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
      constexpr set_symmetric_difference_result<borrowed_iterator_t<R1>,
                                                borrowed_iterator_t<R2>, O>
        set_symmetric_difference(R1&& r1, R2&& r2, O result, Comp comp = {},
                                 Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // 堆操作
  template<class RandomAccessIter>
    constexpr void push_heap(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr void push_heap(RandomAccessIter first, RandomAccessIter last,
                             Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr I
        push_heap(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr borrowed_iterator_t<R>
        push_heap(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class RandomAccessIter>
    constexpr void pop_heap(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr void pop_heap(RandomAccessIter first, RandomAccessIter last,
                            Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr I
        pop_heap(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr borrowed_iterator_t<R>
        pop_heap(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class RandomAccessIter>
    constexpr void make_heap(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr void make_heap(RandomAccessIter first, RandomAccessIter last,
                             Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr I
        make_heap(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr borrowed_iterator_t<R>
        make_heap(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class RandomAccessIter>
    constexpr void sort_heap(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr void sort_heap(RandomAccessIter first, RandomAccessIter last,
                             Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr I
        sort_heap(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Comp = ranges::less, class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr borrowed_iterator_t<R>
        sort_heap(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class RandomAccessIter>
    constexpr bool is_heap(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr bool is_heap(RandomAccessIter first, RandomAccessIter last,
                           Compare comp);
  template<class ExecutionPolicy, class RandomAccessIter>
    bool is_heap(ExecutionPolicy&& exec,
                 RandomAccessIter first, RandomAccessIter last);
  template<class ExecutionPolicy, class RandomAccessIter, class Compare>
    bool is_heap(ExecutionPolicy&& exec,
                 RandomAccessIter first, RandomAccessIter last,
                 Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
      constexpr bool is_heap(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Proj = identity,
             indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr bool is_heap(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class RandomAccessIter>
    constexpr RandomAccessIter
      is_heap_until(RandomAccessIter first, RandomAccessIter last);
  template<class RandomAccessIter, class Compare>
    constexpr RandomAccessIter
      is_heap_until(RandomAccessIter first, RandomAccessIter last,
                    Compare comp);
  template<class ExecutionPolicy, class RandomAccessIter>
    RandomAccessIter
      is_heap_until(ExecutionPolicy&& exec,
                    RandomAccessIter first, RandomAccessIter last);
  template<class ExecutionPolicy, class RandomAccessIter, class Compare>
    RandomAccessIter
      is_heap_until(ExecutionPolicy&& exec,
                    RandomAccessIter first, RandomAccessIter last,
                    Compare comp);

  namespace ranges {
    template<random_access_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
      constexpr I is_heap_until(I first, S last, Comp comp = {}, Proj proj = {});
    template<random_access_range R, class Proj = identity,
             indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr borrowed_iterator_t<R>
        is_heap_until(R&& r, Comp comp = {}, Proj proj = {});
  }

  // 最小与最大
  template<class T> constexpr const T& min(const T& a, const T& b);
  template<class T, class Compare>
    constexpr const T& min(const T& a, const T& b, Compare comp);
  template<class T>
    constexpr T min(initializer_list<T> t);
  template<class T, class Compare>
    constexpr T min(initializer_list<T> t, Compare comp);

  namespace ranges {
    template<class T, class Proj = identity,
             indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
      constexpr const T& min(const T& a, const T& b, Comp comp = {}, Proj proj = {});
    template<copyable T, class Proj = identity,
             indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
      constexpr T min(initializer_list<T> r, Comp comp = {}, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
      requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
      constexpr range_value_t<R>
        min(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class T> constexpr const T& max(const T& a, const T& b);
  template<class T, class Compare>
    constexpr const T& max(const T& a, const T& b, Compare comp);
  template<class T>
    constexpr T max(initializer_list<T> t);
  template<class T, class Compare>
    constexpr T max(initializer_list<T> t, Compare comp);

  namespace ranges {
    template<class T, class Proj = identity,
             indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
      constexpr const T& max(const T& a, const T& b, Comp comp = {}, Proj proj = {});
    template<copyable T, class Proj = identity,
             indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
      constexpr T max(initializer_list<T> r, Comp comp = {}, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
      requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
      constexpr range_value_t<R>
        max(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class T> constexpr pair<const T&, const T&> minmax(const T& a, const T& b);
  template<class T, class Compare>
    constexpr pair<const T&, const T&> minmax(const T& a, const T& b, Compare comp);
  template<class T>
    constexpr pair<T, T> minmax(initializer_list<T> t);
  template<class T, class Compare>
    constexpr pair<T, T> minmax(initializer_list<T> t, Compare comp);

  namespace ranges {
    template<class T>
      using minmax_result = min_max_result<T>;

    template<class T, class Proj = identity,
             indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
      constexpr minmax_result<const T&>
        minmax(const T& a, const T& b, Comp comp = {}, Proj proj = {});
    template<copyable T, class Proj = identity,
             indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
      constexpr minmax_result<T>
        minmax(initializer_list<T> r, Comp comp = {}, Proj proj = {});
    template<input_range R, class Proj = identity,
             indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
      requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
      constexpr minmax_result<range_value_t<R>>
        minmax(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class ForwardIter>
    constexpr ForwardIter min_element(ForwardIter first, ForwardIter last);
  template<class ForwardIter, class Compare>
    constexpr ForwardIter min_element(ForwardIter first, ForwardIter last,
                                          Compare comp);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter min_element(ExecutionPolicy&& exec,
                                ForwardIter first, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter, class Compare>
    ForwardIter min_element(ExecutionPolicy&& exec,
                                ForwardIter first, ForwardIter last,
                                Compare comp);

  namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
      constexpr I min_element(I first, S last, Comp comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr borrowed_iterator_t<R>
        min_element(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class ForwardIter>
    constexpr ForwardIter max_element(ForwardIter first, ForwardIter last);
  template<class ForwardIter, class Compare>
    constexpr ForwardIter max_element(ForwardIter first, ForwardIter last,
                                          Compare comp);
  template<class ExecutionPolicy, class ForwardIter>
    ForwardIter max_element(ExecutionPolicy&& exec,
                                ForwardIter first, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter, class Compare>
    ForwardIter max_element(ExecutionPolicy&& exec,
                                ForwardIter first, ForwardIter last,
                                Compare comp);

 namespace ranges {
    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
      constexpr I max_element(I first, S last, Comp comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr borrowed_iterator_t<R>
        max_element(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class ForwardIter>
    constexpr pair<ForwardIter, ForwardIter>
      minmax_element(ForwardIter first, ForwardIter last);
  template<class ForwardIter, class Compare>
    constexpr pair<ForwardIter, ForwardIter>
      minmax_element(ForwardIter first, ForwardIter last, Compare comp);
  template<class ExecutionPolicy, class ForwardIter>
    pair<ForwardIter, ForwardIter>
      minmax_element(ExecutionPolicy&& exec,
                     ForwardIter first, ForwardIter last);
  template<class ExecutionPolicy, class ForwardIter, class Compare>
    pair<ForwardIter, ForwardIter>
      minmax_element(ExecutionPolicy&& exec,
                     ForwardIter first, ForwardIter last, Compare comp);

  namespace ranges {
    template<class I>
      using minmax_element_result = min_max_result<I>;

    template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
             indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
      constexpr minmax_element_result<I>
        minmax_element(I first, S last, Comp comp = {}, Proj proj = {});
    template<forward_range R, class Proj = identity,
             indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
      constexpr minmax_element_result<borrowed_iterator_t<R>>
        minmax_element(R&& r, Comp comp = {}, Proj proj = {});
  }

  // 有界值
  template<class T>
    constexpr const T& clamp(const T& v, const T& lo, const T& hi);
  template<class T, class Compare>
    constexpr const T& clamp(const T& v, const T& lo, const T& hi, Compare comp);

  namespace ranges {
    template<class T, class Proj = identity,
             indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
      constexpr const T&
        clamp(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {});
  }

  // 字典序比较
  template<class InputIter1, class InputIter2>
    constexpr bool
      lexicographical_compare(InputIter1 first1, InputIter1 last1,
                              InputIter2 first2, InputIter2 last2);
  template<class InputIter1, class InputIter2, class Compare>
    constexpr bool
      lexicographical_compare(InputIter1 first1, InputIter1 last1,
                              InputIter2 first2, InputIter2 last2,
                              Compare comp);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2>
    bool
      lexicographical_compare(ExecutionPolicy&& exec,
                              ForwardIter1 first1, ForwardIter1 last1,
                              ForwardIter2 first2, ForwardIter2 last2);
  template<class ExecutionPolicy, class ForwardIter1, class ForwardIter2,
           class Compare>
    bool
      lexicographical_compare(ExecutionPolicy&& exec,
                              ForwardIter1 first1, ForwardIter1 last1,
                              ForwardIter2 first2, ForwardIter2 last2,
                              Compare comp);

  namespace ranges {
    template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
             class Proj1 = identity, class Proj2 = identity,
             indirect_strict_weak_order<projected<I1, Proj1>, projected<I2, Proj2>> Comp =
               ranges::less>
      constexpr bool
        lexicographical_compare(I1 first1, S1 last1, I2 first2, S2 last2,
                                Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
    template<input_range R1, input_range R2, class Proj1 = identity,
             class Proj2 = identity,
             indirect_strict_weak_order<projected<iterator_t<R1>, Proj1>,
                                        projected<iterator_t<R2>, Proj2>> Comp = ranges::less>
      constexpr bool
        lexicographical_compare(R1&& r1, R2&& r2, Comp comp = {},
                                Proj1 proj1 = {}, Proj2 proj2 = {});
  }

  // 三路比较算法
  template<class InputIter1, class InputIter2, class Cmp>
    constexpr auto
      lexicographical_compare_three_way(InputIter1 b1, InputIter1 e1,
                                        InputIter2 b2, InputIter2 e2,
                                        Cmp comp)
        -> decltype(comp(*b1, *b2));
  template<class InputIter1, class InputIter2>
    constexpr auto
      lexicographical_compare_three_way(InputIter1 b1, InputIter1 e1,
                                        InputIter2 b2, InputIter2 e2);

  // 排列
  template<class BidirectionalIter>
    constexpr bool next_permutation(BidirectionalIter first,
                                    BidirectionalIter last);
  template<class BidirectionalIter, class Compare>
    constexpr bool next_permutation(BidirectionalIter first,
                                    BidirectionalIter last, Compare comp);

  namespace ranges {
    template<class I>
      using next_permutation_result = in_found_result<I>;

    template<bidirectional_iterator I, sentinel_for<I> S, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr next_permutation_result<I>
        next_permutation(I first, S last, Comp comp = {}, Proj proj = {});
    template<bidirectional_range R, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr next_permutation_result<borrowed_iterator_t<R>>
        next_permutation(R&& r, Comp comp = {}, Proj proj = {});
  }

  template<class BidirectionalIter>
    constexpr bool prev_permutation(BidirectionalIter first,
                                    BidirectionalIter last);
  template<class BidirectionalIter, class Compare>
    constexpr bool prev_permutation(BidirectionalIter first,
                                    BidirectionalIter last, Compare comp);

  namespace ranges {
    template<class I>
      using prev_permutation_result = in_found_result<I>;

    template<bidirectional_iterator I, sentinel_for<I> S, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<I, Comp, Proj>
      constexpr prev_permutation_result<I>
        prev_permutation(I first, S last, Comp comp = {}, Proj proj = {});
    template<bidirectional_range R, class Comp = ranges::less,
             class Proj = identity>
      requires sortable<iterator_t<R>, Comp, Proj>
      constexpr prev_permutation_result<borrowed_iterator_t<R>>
        prev_permutation(R&& r, Comp comp = {}, Proj proj = {});
  }
}

类模板 std::ranges::in_fun_result

namespace std::ranges {
  template<class I, class F>
  struct in_fun_result {
    [[no_unique_address]] I in;
    [[no_unique_address]] F fun;

    template<class I2, class F2>
      requires convertible_to<const I&, I2> && convertible_to<const F&, F2>
    constexpr operator in_fun_result<I2, F2>() const & {
      return {in, fun};
    }

    template<class I2, class F2>
      requires convertible_to<I, I2> && convertible_to<F, F2>
    constexpr operator in_fun_result<I2, F2>() && {
      return {std::move(in), std::move(fun)};
    }
  };
}

类模板 std::ranges::in_in_result

namespace std::ranges {
  template<class I1, class I2>
  struct in_in_result {
    [[no_unique_address]] I1 in1;
    [[no_unique_address]] I2 in2;

    template<class II1, class II2>
      requires convertible_to<const I1&, II1> && convertible_to<const I2&, II2>
    constexpr operator in_in_result<II1, II2>() const & {
      return {in1, in2};
    }

    template<class II1, class II2>
      requires convertible_to<I1, II1> && convertible_to<I2, II2>
    constexpr operator in_in_result<II1, II2>() && {
      return {std::move(in1), std::move(in2)};
    }
  };
}

类模板 std::ranges::in_out_result

namespace std::ranges {
  template<class I, class O>
  struct in_out_result {
    [[no_unique_address]] I in;
    [[no_unique_address]] O out;

    template<class I2, class O2>
      requires convertible_to<const I&, I2> && convertible_to<const O&, O2>
    constexpr operator in_out_result<I2, O2>() const & {
      return {in, out};
    }

    template<class I2, class O2>
      requires convertible_to<I, I2> && convertible_to<O, O2>
    constexpr operator in_out_result<I2, O2>() && {
      return {std::move(in), std::move(out)};
    }
  };
}

类模板 std::ranges::in_in_out_result

namespace std::ranges {
  template<class I1, class I2, class O>
  struct in_in_out_result {
    [[no_unique_address]] I1 in1;
    [[no_unique_address]] I2 in2;
    [[no_unique_address]] O  out;

    template<class II1, class II2, class OO>
      requires convertible_to<const I1&, II1> &&
               convertible_to<const I2&, II2> &&
               convertible_to<const O&, OO>
    constexpr operator in_in_out_result<II1, II2, OO>() const & {
      return {in1, in2, out};
    }

    template<class II1, class II2, class OO>
      requires convertible_to<I1, II1> &&
               convertible_to<I2, II2> &&
               convertible_to<O, OO>
    constexpr operator in_in_out_result<II1, II2, OO>() && {
      return {std::move(in1), std::move(in2), std::move(out)};
    }
  };
}

类模板 std::ranges::in_out_out_result

namespace std::ranges {
  template<class I, class O1, class O2>
  struct in_out_out_result {
    [[no_unique_address]] I  in;
    [[no_unique_address]] O1 out1;
    [[no_unique_address]] O2 out2;

    template<class II, class OO1, class OO2>
      requires convertible_to<const I&, II> &&
               convertible_to<const O1&, OO1> &&
               convertible_to<const O2&, OO2>
    constexpr operator in_out_out_result<II, OO1, OO2>() const & {
      return {in, out1, out2};
    }

    template<class II, class OO1, class OO2>
      requires convertible_to<I, II> &&
               convertible_to<O1, OO1> &&
               convertible_to<O2, OO2>
    constexpr operator in_out_out_result<II, OO1, OO2>() && {
      return {std::move(in), std::move(out1), std::move(out2)};
    }
  };
}

类模板 std::ranges::min_max_result

namespace std::ranges {
  template<class T>
  struct min_max_result {
    [[no_unique_address]] T min;
    [[no_unique_address]] T max;

    template<class T2>
      requires convertible_to<const T&, T2>
    constexpr operator min_max_result<T2>() const & {
      return {min, max};
    }

    template<class T2>
      requires convertible_to<T, T2>
    constexpr operator min_max_result<T2>() && {
      return {std::move(min), std::move(max)};
    }
  };
}

类模板 std::ranges::in_found_result

namespace std::ranges {
  template<class I>
  struct in_found_result {
    [[no_unique_address]] I in;
    bool found;

    template<class I2>
      requires convertible_to<const I&, I2>
    constexpr operator in_found_result<I2>() const & {
      return {in, found};
    }
    template<class I2>
      requires convertible_to<I, I2>
    constexpr operator in_found_result<I2>() && {
      return {std::move(in), found};
    }
  };
}


标准库头文件 <any>

< cpp‎ | header

此头文件是通用工具库的一部分。

类
any
(C++17)
 可保有任何可复制构造 (CopyConstructible) 类型的实例的对象。
(类)
bad_any_cast
(C++17)
 当类型不匹配时按值返回形式的 any_cast 所抛出的异常
(类)

函数
std::swap(std::any)
(C++17)
 特化 std::swap 算法
(函数)
make_any
(C++17)
 创建 any 对象
(函数模板)
any_cast
(C++17)
 对被容纳对象的类型安全访问
(函数模板)

概要

namespace std {
  // 类 bad_any_cast
  class bad_any_cast;

  // 类 any
  class any;

  // 非成员函数
  void swap(any& x, any& y) noexcept;

  template<class T, class... Args>
    any make_any(Args&&... args);
  template<class T, class U, class... Args>
    any make_any(initializer_list<U> il, Args&&... args);

  template<class T>
    T any_cast(const any& operand);
  template<class T>
    T any_cast(any& operand);
  template<class T>
    T any_cast(any&& operand);

  template<class T>
    const T* any_cast(const any* operand) noexcept;
  template<class T>
    T* any_cast(any* operand) noexcept;
}

类 std::bad_any_cast

namespace std {
  class bad_any_cast : public bad_cast {
  public:
    // 特殊成员函数的规范见 [exception]
    const char* what() const noexcept override;
  };
}

类 std::any

namespace std {
  class any {
  public:
    // 构造与析构
    constexpr any() noexcept;

    any(const any& other);
    any(any&& other) noexcept;

    template<class T>
      any(T&& value);

    template<class T, class... Args>
      explicit any(in_place_type_t<T>, Args&&...);
    template<class T, class U, class... Args>
      explicit any(in_place_type_t<T>, initializer_list<U>, Args&&...);

    ~any();

    // 赋值
    any& operator=(const any& rhs);
    any& operator=(any&& rhs) noexcept;

    template<class T>
      any& operator=(T&& rhs);

    // 修改器
    template<class T, class... Args>
      decay_t<T>& emplace(Args&&...);
    template<class T, class U, class... Args>
      decay_t<T>& emplace(initializer_list<U>, Args&&...);
    void reset() noexcept;
    void swap(any& rhs) noexcept;

    // 观察器
    bool has_value() const noexcept;
    const type_info& type() const noexcept;
  };
}


标准库头文件 <array>

< cpp‎ | header

此头文件是容器库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
<initializer_list>
(C++11)
 std::initializer_list 类模板

类
array
(C++11)
 静态的连续数组
(类模板)
tuple_size
(C++11)
 获得元组式类型的元素数
(类模板)
tuple_element
(C++11)
 获得元组式类型的元素类型
(类模板)
std::tuple_size<std::array>
(C++11)
 获得 array 的大小
(类模板特化)
std::tuple_element<std::array>
(C++11)
 获得 array 元素的类型
(类模板特化)

函数
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 array 中的值
(函数模板)
std::swap(std::array)
(C++11)
 特化 std::swap 算法
(函数模板)
to_array
(C++20)
 从内建数组创建 std::array 对象
(函数模板)
std::get(std::array)
 访问 array 的一个元素
(函数模板)
范围访问
begincbegin
(C++11)(C++14)
 返回指向容器或数组起始的迭代器
(函数模板)
endcend
(C++11)(C++14)
 返回指向容器或数组结尾的迭代器
(函数模板)
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
sizessize
(C++17)(C++20)
 返回容器或数组的大小
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)

概要

#include <compare>
#include <initializer_list>

namespace std {
  // 类模板 array
  template<class T, size_t N> struct array;

  template<class T, size_t N>
    constexpr bool operator==(const array<T, N>& x, const array<T, N>& y);
  template<class T, size_t N>
    constexpr /*synth-three-way-result*/<T>
      operator<=>(const array<T, N>& x, const array<T, N>& y);

  // 特化的算法
  template<class T, size_t N>
    constexpr void swap(array<T, N>& x, array<T, N>& y) noexcept(noexcept(x.swap(y)));

  // array 创建函数
  template<class T, size_t N>
    constexpr array<remove_cv_t<T>, N> to_array(T (&a)[N]);
  template<class T, size_t N>
    constexpr array<remove_cv_t<T>, N> to_array(T (&&a)[N]);

  // tuple 接口
  template<class T> struct tuple_size;
  template<size_t I, class T> struct tuple_element;
  template<class T, size_t N>
    struct tuple_size<array<T, N>>;
  template<size_t I, class T, size_t N>
    struct tuple_element<I, array<T, N>>;
  template<size_t I, class T, size_t N>
    constexpr T& get(array<T, N>&) noexcept;
  template<size_t I, class T, size_t N>
    constexpr T&& get(array<T, N>&&) noexcept;
  template<size_t I, class T, size_t N>
    constexpr const T& get(const array<T, N>&) noexcept;
  template<size_t I, class T, size_t N>
    constexpr const T&& get(const array<T, N>&&) noexcept;
}

类模板 std::array

namespace std {
  template<class T, size_t N>
  struct array {
    // 类型
    using value_type             = T;
    using pointer                = T*;
    using const_pointer          = const T*;
    using reference              = T&;
    using const_reference        = const T&;
    using size_type              = size_t;
    using difference_type        = ptrdiff_t;
    using iterator               = /* 由实现定义 */;
    using const_iterator         = /* 由实现定义 */;
    using reverse_iterator       = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

    // 聚合类型无显式的构造/复制/销毁

    constexpr void fill(const T& u);
    constexpr void swap(array&) noexcept(is_nothrow_swappable_v<T>);

    // 迭代器
    constexpr iterator               begin() noexcept;
    constexpr const_iterator         begin() const noexcept;
    constexpr iterator               end() noexcept;
    constexpr const_iterator         end() const noexcept;

    constexpr reverse_iterator       rbegin() noexcept;
    constexpr const_reverse_iterator rbegin() const noexcept;
    constexpr reverse_iterator       rend() noexcept;
    constexpr const_reverse_iterator rend() const noexcept;

    constexpr const_iterator         cbegin() const noexcept;
    constexpr const_iterator         cend() const noexcept;
    constexpr const_reverse_iterator crbegin() const noexcept;
    constexpr const_reverse_iterator crend() const noexcept;

    // 容量
    [[nodiscard]] constexpr bool empty() const noexcept;
    constexpr size_type size() const noexcept;
    constexpr size_type max_size() const noexcept;

    // 元素访问
    constexpr reference       operator[](size_type n);
    constexpr const_reference operator[](size_type n) const;
    constexpr reference       at(size_type n);
    constexpr const_reference at(size_type n) const;
    constexpr reference       front();
    constexpr const_reference front() const;
    constexpr reference       back();
    constexpr const_reference back() const;

    constexpr T *       data() noexcept;
    constexpr const T * data() const noexcept;
  };

  template<class T, class... U>
    array(T, U...) -> array<T, 1 + sizeof...(U)>;
}


标准库头文件 <atomic>

< cpp‎ | header

此头文件是原子操作库的一部分。

类
atomic
(C++11)
 atomic 类模板及其针对布尔、整型和指针类型的特化
(类模板)
atomic_ref
(C++20)
 提供非原子对象上的原子操作
(类模板)
atomic_flag
(C++11)
 免锁的布尔原子类型
(类)
memory_order
(C++11)
 为给定的原子操作定义内存顺序约束
(枚举)
atomic_bool
(C++11)
 std::atomic <bool>
(typedef)
atomic_char
(C++11)
 std::atomic <char>
(typedef)
atomic_schar
(C++11)
 std::atomic <signed char>
(typedef)
atomic_uchar
(C++11)
 std::atomic <unsigned char>
(typedef)
atomic_short
(C++11)
 std::atomic <short>
(typedef)
atomic_ushort
(C++11)
 std::atomic <unsigned short>
(typedef)
atomic_int
(C++11)
 std::atomic <int>
(typedef)
atomic_uint
(C++11)
 std::atomic <unsigned int>
(typedef)
atomic_long
(C++11)
 std::atomic <long>
(typedef)
atomic_ulong
(C++11)
 std::atomic <unsigned long>
(typedef)
atomic_llong
(C++11)
 std::atomic <long long>
(typedef)
atomic_ullong
(C++11)
 std::atomic <unsigned long long>
(typedef)
atomic_char8_t
(C++20)
 std::atomic <char8_t>
(typedef)
atomic_char16_t
(C++11)
 std::atomic <char16_t>
(typedef)
atomic_char32_t
(C++11)
 std::atomic <char32_t>
(typedef)
atomic_wchar_t
(C++11)
 std::atomic <wchar_t>
(typedef)
atomic_int8_t
(C++11)(可选)
 std::atomic < std::int8_t >
(typedef)
atomic_uint8_t
(C++11)(可选)
 std::atomic < std::uint8_t >
(typedef)
atomic_int16_t
(C++11)(可选)
 std::atomic < std::int16_t >
(typedef)
atomic_uint16_t
(C++11)(可选)
 std::atomic < std::uint16_t >
(typedef)
atomic_int32_t
(C++11)(可选)
 std::atomic < std::int32_t >
(typedef)
atomic_uint32_t
(C++11)(可选)
 std::atomic < std::uint32_t >
(typedef)
atomic_int64_t
(C++11)(可选)
 std::atomic < std::int64_t >
(typedef)
atomic_uint64_t
(C++11)(可选)
 std::atomic < std::uint64_t >
(typedef)
atomic_int_least8_t
(C++11)
 std::atomic < std::int_least8_t >
(typedef)
atomic_uint_least8_t
(C++11)
 std::atomic < std::uint_least8_t >
(typedef)
atomic_int_least16_t
(C++11)
 std::atomic < std::int_least16_t >
(typedef)
atomic_uint_least16_t
(C++11)
 std::atomic < std::uint_least16_t >
(typedef)
atomic_int_least32_t
(C++11)
 std::atomic < std::int_least32_t >
(typedef)
atomic_uint_least32_t
(C++11)
 std::atomic < std::uint_least32_t >
(typedef)
atomic_int_least64_t
(C++11)
 std::atomic < std::int_least64_t >
(typedef)
atomic_uint_least64_t
(C++11)
 std::atomic < std::uint_least64_t >
(typedef)
atomic_int_fast8_t
(C++11)
 std::atomic < std::int_fast8_t >
(typedef)
atomic_uint_fast8_t
(C++11)
 std::atomic < std::uint_fast8_t >
(typedef)
atomic_int_fast16_t
(C++11)
 std::atomic < std::int_fast16_t >
(typedef)
atomic_uint_fast16_t
(C++11)
 std::atomic < std::uint_fast16_t >
(typedef)
atomic_int_fast32_t
(C++11)
 std::atomic < std::int_fast32_t >
(typedef)
atomic_uint_fast32_t
(C++11)
 std::atomic < std::uint_fast32_t >
(typedef)
atomic_int_fast64_t
(C++11)
 std::atomic < std::int_fast64_t >
(typedef)
atomic_uint_fast64_t
(C++11)
 std::atomic < std::uint_fast64_t >
(typedef)
atomic_intptr_t
(C++11)(可选)
 std::atomic < std::intptr_t >
(typedef)
atomic_uintptr_t
(C++11)(可选)
 std::atomic < std::uintptr_t >
(typedef)
atomic_size_t
(C++11)
 std::atomic < std::size_t >
(typedef)
atomic_ptrdiff_t
(C++11)
 std::atomic < std::ptrdiff_t >
(typedef)
atomic_intmax_t
(C++11)
 std::atomic < std::intmax_t >
(typedef)
atomic_uintmax_t
(C++11)
 std::atomic < std::uintmax_t >
(typedef)
atomic_signed_lock_free
(C++20)
 免锁且对于等待/提醒最高效的有符号整数原子类型
(typedef)
atomic_unsigned_lock_free
(C++20)
 免锁且对于等待/提醒最高效的无符号整数原子类型
(typedef)

函数
atomic_is_lock_free
(C++11)
 检查对该原子类型的操作是否是无锁的
(函数模板)
atomic_storeatomic_store_explicit
(C++11)(C++11)
 原子地以非原子实参替换原子对象的值
(函数模板)
atomic_loadatomic_load_explicit
(C++11)(C++11)
 原子地获得存储于原子对象的值
(函数模板)
atomic_exchangeatomic_exchange_explicit
(C++11)(C++11)
 原子地以非原子实参的值替换原子对象的值，并返回该原子对象的旧值
(函数模板)
atomic_compare_exchange_weakatomic_compare_exchange_weak_explicitatomic_compare_exchange_strongatomic_compare_exchange_strong_explicit
(C++11)(C++11)(C++11)(C++11)
 原子地比较原子对象和非原子实参的值，若相等则进行 atomic_exchange，若不相等则进行 atomic_load
(函数模板)
atomic_fetch_addatomic_fetch_add_explicit
(C++11)(C++11)
 将非原子值加到原子对象，并获得原子对象的先前值
(函数模板)
atomic_fetch_subatomic_fetch_sub_explicit
(C++11)(C++11)
 从原子对象减去非原子值，并获得原子对象的先前值
(函数模板)
atomic_fetch_andatomic_fetch_and_explicit
(C++11)(C++11)
 将原子对象替换为与非原子实参逻辑与的结果，并获得原子对象的先前值
(函数模板)
atomic_fetch_oratomic_fetch_or_explicit
(C++11)(C++11)
 将原子对象替换为与非原子实参逻辑或的结果，并获得原子对象的先前值
(函数模板)
atomic_fetch_xoratomic_fetch_xor_explicit
(C++11)(C++11)
 将原子对象替换为与非原子实参逻辑异或的结果，并获得原子对象的先前值
(函数模板)
atomic_waitatomic_wait_explicit
(C++20)(C++20)
 阻塞线程直至被提醒且原子值更改
(函数模板)
atomic_notify_one
(C++20)
 提醒一个在 atomic_wait 中阻塞的线程
(函数模板)
atomic_notify_all
(C++20)
 提醒所有在 atomic_wait 中阻塞的线程
(函数模板)
atomic_flag_testatomic_flag_test_explicit
(C++20)(C++20)
 原子地返回标志的值
(函数)
atomic_flag_test_and_setatomic_flag_test_and_set_explicit
(C++11)(C++11)
 原子地设置标志为 true 并返回其先前值
(函数)
atomic_flag_clearatomic_flag_clear_explicit
(C++11)(C++11)
 原子地设置标志值为 false
(函数)
atomic_flag_waitatomic_flag_wait_explicit
(C++20)(C++20)
 阻塞线程，直至被提醒且标志更改
(函数)
atomic_flag_notify_one
(C++20)
 提醒一个在 atomic_flag_wait 中阻塞的线程
(函数)
atomic_flag_notify_all
(C++20)
 提醒所有在 atomic_flag_wait 中阻塞的线程
(函数)
atomic_init
(C++11)(C++20 中弃用)
 对默认构造的原子对象进行非原子初始化
(函数模板)
kill_dependency
(C++11)
 从 std::memory_order_consume 依赖树移除指定对象
(函数模板)
atomic_thread_fence
(C++11)
 通用的依赖内存顺序的栅栏同步原语
(函数)
atomic_signal_fence
(C++11)
 线程与执行于同一线程的信号处理函数间的栅栏
(函数)

宏
ATOMIC_VAR_INIT
(C++11)(C++20 中弃用)
 静态存储期的原子对象的常量初始化
(宏函数)
ATOMIC_FLAG_INIT
(C++11)(C++20 中弃用)
 将 std::atomic_flag 初始化为 false
(宏常量)

概要

namespace std {
  /* C++20 前：
  typedef enum memory_order {
    memory_order_relaxed,
    memory_order_consume,
    memory_order_acquire,
    memory_order_release,
    memory_order_acq_rel,
    memory_order_seq_cst
  } memory_order;
  */

  enum class memory_order : /* 未指明 */ {
    relaxed, consume, acquire, release, acq_rel, seq_cst
  };
  inline constexpr memory_order memory_order_relaxed = memory_order::relaxed;
  inline constexpr memory_order memory_order_consume = memory_order::consume;
  inline constexpr memory_order memory_order_acquire = memory_order::acquire;
  inline constexpr memory_order memory_order_release = memory_order::release;
  inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel;
  inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst;

  template<class T>
    T kill_dependency(T y) noexcept;

  // 免锁属性
  #define ATOMIC_BOOL_LOCK_FREE /* 未指明 */
  #define ATOMIC_CHAR_LOCK_FREE /* 未指明 */
  #define ATOMIC_CHAR8_T_LOCK_FREE /* 未指明 */
  #define ATOMIC_CHAR16_T_LOCK_FREE /* 未指明 */
  #define ATOMIC_CHAR32_T_LOCK_FREE /* 未指明 */
  #define ATOMIC_WCHAR_T_LOCK_FREE /* 未指明 */
  #define ATOMIC_SHORT_LOCK_FREE /* 未指明 */
  #define ATOMIC_INT_LOCK_FREE /* 未指明 */
  #define ATOMIC_LONG_LOCK_FREE /* 未指明 */
  #define ATOMIC_LLONG_LOCK_FREE /* 未指明 */
  #define ATOMIC_POINTER_LOCK_FREE /* 未指明 */

  // 类模板 atomic_ref
  template<class T> struct atomic_ref;
  // partial specialization for pointers
  template<class T> struct atomic_ref<T*>;

  // 类模板 atomic
  template<class T> struct atomic;
  // partial specialization for pointers
  template<class T> struct atomic<T*>;

  // 非成员函数
  template<class T>
    bool atomic_is_lock_free(const volatile atomic<T>*) noexcept;
  template<class T>
    bool atomic_is_lock_free(const atomic<T>*) noexcept;
  template<class T>
    void atomic_store(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
  template<class T>
    void atomic_store(atomic<T>*, typename atomic<T>::value_type) noexcept;
  template<class T>
    void atomic_store_explicit(volatile atomic<T>*, typename atomic<T>::value_type,
                               memory_order) noexcept;
  template<class T>
    void atomic_store_explicit(atomic<T>*, typename atomic<T>::value_type,
                               memory_order) noexcept;
  template<class T>
    T atomic_load(const volatile atomic<T>*) noexcept;
  template<class T>
    T atomic_load(const atomic<T>*) noexcept;
  template<class T>
    T atomic_load_explicit(const volatile atomic<T>*, memory_order) noexcept;
  template<class T>
    T atomic_load_explicit(const atomic<T>*, memory_order) noexcept;
  template<class T>
    T atomic_exchange(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
  template<class T>
    T atomic_exchange(atomic<T>*, typename atomic<T>::value_type) noexcept;
  template<class T>
    T atomic_exchange_explicit(volatile atomic<T>*, typename atomic<T>::value_type,
                               memory_order) noexcept;
  template<class T>
    T atomic_exchange_explicit(atomic<T>*, typename atomic<T>::value_type,
                               memory_order) noexcept;
  template<class T>
    bool atomic_compare_exchange_weak(volatile atomic<T>*,
                                      typename atomic<T>::value_type*,
                                      typename atomic<T>::value_type) noexcept;
  template<class T>
    bool atomic_compare_exchange_weak(atomic<T>*,
                                      typename atomic<T>::value_type*,
                                      typename atomic<T>::value_type) noexcept;
  template<class T>
    bool atomic_compare_exchange_strong(volatile atomic<T>*,
                                        typename atomic<T>::value_type*,
                                        typename atomic<T>::value_type) noexcept;
  template<class T>
    bool atomic_compare_exchange_strong(atomic<T>*,
                                        typename atomic<T>::value_type*,
                                        typename atomic<T>::value_type) noexcept;
  template<class T>
    bool atomic_compare_exchange_weak_explicit(volatile atomic<T>*,
                                               typename atomic<T>::value_type*,
                                               typename atomic<T>::value_type,
                                               memory_order, memory_order) noexcept;
  template<class T>
    bool atomic_compare_exchange_weak_explicit(atomic<T>*,
                                               typename atomic<T>::value_type*,
                                               typename atomic<T>::value_type,
                                               memory_order, memory_order) noexcept;
  template<class T>
    bool atomic_compare_exchange_strong_explicit(volatile atomic<T>*,
                                                 typename atomic<T>::value_type*,
                                                 typename atomic<T>::value_type,
                                                 memory_order, memory_order) noexcept;
  template<class T>
    bool atomic_compare_exchange_strong_explicit(atomic<T>*,
                                                 typename atomic<T>::value_type*,
                                                 typename atomic<T>::value_type,
                                                 memory_order, memory_order) noexcept;

  template<class T>
    T atomic_fetch_add(volatile atomic<T>*, typename atomic<T>::difference_type) noexcept;
  template<class T>
    T atomic_fetch_add(atomic<T>*, typename atomic<T>::difference_type) noexcept;
  template<class T>
    T atomic_fetch_add_explicit(volatile atomic<T>*, typename atomic<T>::difference_type,
                                memory_order) noexcept;
  template<class T>
    T atomic_fetch_add_explicit(atomic<T>*, typename atomic<T>::difference_type,
                                memory_order) noexcept;
  template<class T>
    T atomic_fetch_sub(volatile atomic<T>*, typename atomic<T>::difference_type) noexcept;
  template<class T>
    T atomic_fetch_sub(atomic<T>*, typename atomic<T>::difference_type) noexcept;
  template<class T>
    T atomic_fetch_sub_explicit(volatile atomic<T>*, typename atomic<T>::difference_type,
                                memory_order) noexcept;
  template<class T>
    T atomic_fetch_sub_explicit(atomic<T>*, typename atomic<T>::difference_type,
                                memory_order) noexcept;
  template<class T>
    T atomic_fetch_and(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
  template<class T>
    T atomic_fetch_and(atomic<T>*, typename atomic<T>::value_type) noexcept;
  template<class T>
    T atomic_fetch_and_explicit(volatile atomic<T>*, typename atomic<T>::value_type,
                                memory_order) noexcept;
  template<class T>
    T atomic_fetch_and_explicit(atomic<T>*, typename atomic<T>::value_type,
                                memory_order) noexcept;
  template<class T>
    T atomic_fetch_or(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
  template<class T>
    T atomic_fetch_or(atomic<T>*, typename atomic<T>::value_type) noexcept;
  template<class T>
    T atomic_fetch_or_explicit(volatile atomic<T>*, typename atomic<T>::value_type,
                               memory_order) noexcept;
  template<class T>
    T atomic_fetch_or_explicit(atomic<T>*, typename atomic<T>::value_type,
                               memory_order) noexcept;
  template<class T>
    T atomic_fetch_xor(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
  template<class T>
    T atomic_fetch_xor(atomic<T>*, typename atomic<T>::value_type) noexcept;
  template<class T>
    T atomic_fetch_xor_explicit(volatile atomic<T>*, typename atomic<T>::value_type,
                                memory_order) noexcept;
  template<class T>
    T atomic_fetch_xor_explicit(atomic<T>*, typename atomic<T>::value_type,
                                memory_order) noexcept;

  template<class T>
    void atomic_wait(const volatile atomic<T>*, typename atomic<T>::value_type);
  template<class T>
    void atomic_wait(const atomic<T>*, typename atomic<T>::value_type);
  template<class T>
    void atomic_wait_explicit(const volatile atomic<T>*, typename atomic<T>::value_type,
                              memory_order);
  template<class T>
    void atomic_wait_explicit(const atomic<T>*, typename atomic<T>::value_type,
                              memory_order);
  template<class T>
    void atomic_notify_one(volatile atomic<T>*);
  template<class T>
    void atomic_notify_one(atomic<T>*);
  template<class T>
    void atomic_notify_all(volatile atomic<T>*);
  template<class T>
    void atomic_notify_all(atomic<T>*);

  // 类型别名
  using atomic_bool           = atomic<bool>;
  using atomic_char           = atomic<char>;
  using atomic_schar          = atomic<signed char>;
  using atomic_uchar          = atomic<unsigned char>;
  using atomic_short          = atomic<short>;
  using atomic_ushort         = atomic<unsigned short>;
  using atomic_int            = atomic<int>;
  using atomic_uint           = atomic<unsigned int>;
  using atomic_long           = atomic<long>;
  using atomic_ulong          = atomic<unsigned long>;
  using atomic_llong          = atomic<long long>;
  using atomic_ullong         = atomic<unsigned long long>;
  using atomic_char8_t        = atomic<char8_t>;
  using atomic_char16_t       = atomic<char16_t>;
  using atomic_char32_t       = atomic<char32_t>;
  using atomic_wchar_t        = atomic<wchar_t>;

  using atomic_int8_t         = atomic<int8_t>;
  using atomic_uint8_t        = atomic<uint8_t>;
  using atomic_int16_t        = atomic<int16_t>;
  using atomic_uint16_t       = atomic<uint16_t>;
  using atomic_int32_t        = atomic<int32_t>;
  using atomic_uint32_t       = atomic<uint32_t>;
  using atomic_int64_t        = atomic<int64_t>;
  using atomic_uint64_t       = atomic<uint64_t>;

  using atomic_int_least8_t   = atomic<int_least8_t>;
  using atomic_uint_least8_t  = atomic<uint_least8_t>;
  using atomic_int_least16_t  = atomic<int_least16_t>;
  using atomic_uint_least16_t = atomic<uint_least16_t>;
  using atomic_int_least32_t  = atomic<int_least32_t>;
  using atomic_uint_least32_t = atomic<uint_least32_t>;
  using atomic_int_least64_t  = atomic<int_least64_t>;
  using atomic_uint_least64_t = atomic<uint_least64_t>;

  using atomic_int_fast8_t    = atomic<int_fast8_t>;
  using atomic_uint_fast8_t   = atomic<uint_fast8_t>;
  using atomic_int_fast16_t   = atomic<int_fast16_t>;
  using atomic_uint_fast16_t  = atomic<uint_fast16_t>;
  using atomic_int_fast32_t   = atomic<int_fast32_t>;
  using atomic_uint_fast32_t  = atomic<uint_fast32_t>;
  using atomic_int_fast64_t   = atomic<int_fast64_t>;
  using atomic_uint_fast64_t  = atomic<uint_fast64_t>;

  using atomic_intptr_t       = atomic<intptr_t>;
  using atomic_uintptr_t      = atomic<uintptr_t>;
  using atomic_size_t         = atomic<size_t>;
  using atomic_ptrdiff_t      = atomic<ptrdiff_t>;
  using atomic_intmax_t       = atomic<intmax_t>;
  using atomic_uintmax_t      = atomic<uintmax_t>;

  using atomic_signed_lock_free   = /* 见描述 */;
  using atomic_unsigned_lock_free = /* 见描述 */;

  // 标志类型与操作
  struct atomic_flag;

  bool atomic_flag_test(const volatile atomic_flag*) noexcept;
  bool atomic_flag_test(const atomic_flag*) noexcept;
  bool atomic_flag_test_explicit(const volatile atomic_flag*, memory_order) noexcept;
  bool atomic_flag_test_explicit(const atomic_flag*, memory_order) noexcept;
  bool atomic_flag_test_and_set(volatile atomic_flag*) noexcept;
  bool atomic_flag_test_and_set(atomic_flag*) noexcept;
  bool atomic_flag_test_and_set_explicit(volatile atomic_flag*, memory_order) noexcept;
  bool atomic_flag_test_and_set_explicit(atomic_flag*, memory_order) noexcept;
  void atomic_flag_clear(volatile atomic_flag*) noexcept;
  void atomic_flag_clear(atomic_flag*) noexcept;
  void atomic_flag_clear_explicit(volatile atomic_flag*, memory_order) noexcept;
  void atomic_flag_clear_explicit(atomic_flag*, memory_order) noexcept;

  void atomic_flag_wait(const volatile atomic_flag*, bool) noexcept;
  void atomic_flag_wait(const atomic_flag*, bool) noexcept;
  void atomic_flag_wait_explicit(const volatile atomic_flag*,
                                 bool, memory_order) noexcept;
  void atomic_flag_wait_explicit(const atomic_flag*,
                                 bool, memory_order) noexcept;
  void atomic_flag_notify_one(volatile atomic_flag*) noexcept;
  void atomic_flag_notify_one(atomic_flag*) noexcept;
  void atomic_flag_notify_all(volatile atomic_flag*) noexcept;
  void atomic_flag_notify_all(atomic_flag*) noexcept;

  // 栅栏
  extern "C" void atomic_thread_fence(memory_order) noexcept;
  extern "C" void atomic_signal_fence(memory_order) noexcept;
}
// 弃用
namespace std {
  template<class T>
    void atomic_init(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
  template<class T>
    void atomic_init(atomic<T>*, typename atomic<T>::value_type) noexcept;

  #define ATOMIC_VAR_INIT(value) /* 见描述 */

  #define ATOMIC_FLAG_INIT /* 见描述 */
}

类模板 std::atomic

namespace std {
  template<class T> struct atomic {
    using value_type = T;

    static constexpr bool is_always_lock_free = /* 实现定义 */;
    bool is_lock_free() const volatile noexcept;
    bool is_lock_free() const noexcept;

    // 原子类型上的操作
    constexpr atomic() noexcept(is_nothrow_default_constructible_v<T>);
    constexpr atomic(T) noexcept;
    atomic(const atomic&) = delete;
    atomic& operator=(const atomic&) = delete;
    atomic& operator=(const atomic&) volatile = delete;

    T load(memory_order = memory_order::seq_cst) const volatile noexcept;
    T load(memory_order = memory_order::seq_cst) const noexcept;
    operator T() const volatile noexcept;
    operator T() const noexcept;
    void store(T, memory_order = memory_order::seq_cst) volatile noexcept;
    void store(T, memory_order = memory_order::seq_cst) noexcept;
    T operator=(T) volatile noexcept;
    T operator=(T) noexcept;

    T exchange(T, memory_order = memory_order::seq_cst) volatile noexcept;
    T exchange(T, memory_order = memory_order::seq_cst) noexcept;
    bool compare_exchange_weak(T&, T, memory_order, memory_order) volatile noexcept;
    bool compare_exchange_weak(T&, T, memory_order, memory_order) noexcept;
    bool compare_exchange_strong(T&, T, memory_order, memory_order) volatile noexcept;
    bool compare_exchange_strong(T&, T, memory_order, memory_order) noexcept;
    bool compare_exchange_weak(T&, T,
                               memory_order = memory_order::seq_cst) volatile noexcept;
    bool compare_exchange_weak(T&, T, memory_order = memory_order::seq_cst) noexcept;
    bool compare_exchange_strong(T&, T,
                                 memory_order = memory_order::seq_cst) volatile noexcept;
    bool compare_exchange_strong(T&, T, memory_order = memory_order::seq_cst) noexcept;

    void wait(T, memory_order = memory_order::seq_cst) const volatile noexcept;
    void wait(T, memory_order = memory_order::seq_cst) const noexcept;
    void notify_one() volatile noexcept;
    void notify_one() noexcept;
    void notify_all() volatile noexcept;
    void notify_all() noexcept;
  };
}

std::atomic 对整数类型的特化

namespace std {
  template<> struct atomic</* 整型 */> {
    using value_type = /* 整型 */;
    using difference_type = value_type;

    static constexpr bool is_always_lock_free = /* 实现定义 */;
    bool is_lock_free() const volatile noexcept;
    bool is_lock_free() const noexcept;

    constexpr atomic() noexcept;
    constexpr atomic(/* 整型 */) noexcept;
    atomic(const atomic&) = delete;
    atomic& operator=(const atomic&) = delete;
    atomic& operator=(const atomic&) volatile = delete;

    void store(/* 整型 */, memory_order = memory_order::seq_cst) volatile noexcept;
    void store(/* 整型 */, memory_order = memory_order::seq_cst) noexcept;
    /* 整型 */ operator=(/* 整型 */) volatile noexcept;
    /* 整型 */ operator=(/* 整型 */) noexcept;
    /* 整型 */ load(memory_order = memory_order::seq_cst) const volatile noexcept;
    /* 整型 */ load(memory_order = memory_order::seq_cst) const noexcept;
    operator /* 整型 */() const volatile noexcept;
    operator /* 整型 */() const noexcept;

    /* 整型 */ exchange(/* 整型 */,
                        memory_order = memory_order::seq_cst) volatile noexcept;
    /* 整型 */ exchange(/* 整型 */,
                        memory_order = memory_order::seq_cst) noexcept;
    bool compare_exchange_weak(/* 整型 */&, /* 整型 */,
                               memory_order, memory_order) volatile noexcept;
    bool compare_exchange_weak(/* 整型 */&, /* 整型 */,
                               memory_order, memory_order) noexcept;
    bool compare_exchange_strong(/* 整型 */&, /* 整型 */,
                                 memory_order, memory_order) volatile noexcept;
    bool compare_exchange_strong(/* 整型 */&, /* 整型 */,
                                 memory_order, memory_order) noexcept;
    bool compare_exchange_weak(/* 整型 */&, /* 整型 */,
                               memory_order = memory_order::seq_cst) volatile noexcept;
    bool compare_exchange_weak(/* 整型 */&, /* 整型 */,
                               memory_order = memory_order::seq_cst) noexcept;
    bool compare_exchange_strong(/* 整型 */&, /* 整型 */,
                                 memory_order = memory_order::seq_cst) volatile noexcept;
    bool compare_exchange_strong(/* 整型 */&, /* 整型 */,
                                 memory_order = memory_order::seq_cst) noexcept;

    /* 整型 */ fetch_add(/* 整型 */,
                         memory_order = memory_order::seq_cst) volatile noexcept;
    /* 整型 */ fetch_add(/* 整型 */,
                         memory_order = memory_order::seq_cst) noexcept;
    /* 整型 */ fetch_sub(/* 整型 */,
                         memory_order = memory_order::seq_cst) volatile noexcept;
    /* 整型 */ fetch_sub(/* 整型 */,
                         memory_order = memory_order::seq_cst) noexcept;
    /* 整型 */ fetch_and(/* 整型 */,
                         memory_order = memory_order::seq_cst) volatile noexcept;
    /* 整型 */ fetch_and(/* 整型 */,
                         memory_order = memory_order::seq_cst) noexcept;
    /* 整型 */ fetch_or(/* 整型 */,
                         memory_order = memory_order::seq_cst) volatile noexcept;
    /* 整型 */ fetch_or(/* 整型 */,
                         memory_order = memory_order::seq_cst) noexcept;
    /* 整型 */ fetch_xor(/* 整型 */,
                         memory_order = memory_order::seq_cst) volatile noexcept;
    /* 整型 */ fetch_xor(/* 整型 */,
                         memory_order = memory_order::seq_cst) noexcept;

    /* 整型 */ operator++(int) volatile noexcept;
    /* 整型 */ operator++(int) noexcept;
    /* 整型 */ operator--(int) volatile noexcept;
    /* 整型 */ operator--(int) noexcept;
    /* 整型 */ operator++() volatile noexcept;
    /* 整型 */ operator++() noexcept;
    /* 整型 */ operator--() volatile noexcept;
    /* 整型 */ operator--() noexcept;
    /* 整型 */ operator+=(/* 整型 */) volatile noexcept;
    /* 整型 */ operator+=(/* 整型 */) noexcept;
    /* 整型 */ operator-=(/* 整型 */) volatile noexcept;
    /* 整型 */ operator-=(/* 整型 */) noexcept;
    /* 整型 */ operator&=(/* 整型 */) volatile noexcept;
    /* 整型 */ operator&=(/* 整型 */) noexcept;
    /* 整型 */ operator|=(/* 整型 */) volatile noexcept;
    /* 整型 */ operator|=(/* 整型 */) noexcept;
    /* 整型 */ operator^=(/* 整型 */) volatile noexcept;
    /* 整型 */ operator^=(/* 整型 */) noexcept;

    void wait(/* 整型 */,
              memory_order = memory_order::seq_cst) const volatile noexcept;
    void wait(/* 整型 */, memory_order = memory_order::seq_cst) const noexcept;
    void notify_one() volatile noexcept;
    void notify_one() noexcept;
    void notify_all() volatile noexcept;
    void notify_all() noexcept;
  };
}

std::atomic 对浮点类型的特化

namespace std {
  template<> struct atomic</* 浮点 */> {
    using value_type = /* 浮点 */;
    using difference_type = value_type;

    static constexpr bool is_always_lock_free = /* 实现定义 */;
    bool is_lock_free() const volatile noexcept;
    bool is_lock_free() const noexcept;

    constexpr atomic() noexcept;
    constexpr atomic(/* 浮点 */) noexcept;
    atomic(const atomic&) = delete;
    atomic& operator=(const atomic&) = delete;
    atomic& operator=(const atomic&) volatile = delete;

    void store(/* 浮点 */,
               memory_order = memory_order_seq_cst) volatile noexcept;
    void store(/* 浮点 */,
               memory_order = memory_order_seq_cst) noexcept;
    /* 浮点 */ operator=(/* 浮点 */) volatile noexcept;
    /* 浮点 */ operator=(/* 浮点 */) noexcept;
    /* 浮点 */ load(memory_order = memory_order_seq_cst) volatile noexcept;
    /* 浮点 */ load(memory_order = memory_order_seq_cst) noexcept;
    operator /* 浮点 */() volatile noexcept;
    operator /* 浮点 */() noexcept;

    /* 浮点 */ exchange(/* 浮点 */,
                            memory_order = memory_order_seq_cst) volatile noexcept;
    /* 浮点 */ exchange(/* 浮点 */,
                            memory_order = memory_order_seq_cst) noexcept;
    bool compare_exchange_weak(/* 浮点 */&, /* 浮点 */,
                               memory_order, memory_order) volatile noexcept;
    bool compare_exchange_weak(/* 浮点 */&, /* 浮点 */,
                               memory_order, memory_order) noexcept;
    bool compare_exchange_strong(/* 浮点 */&, /* 浮点 */,
                                 memory_order, memory_order) volatile noexcept;
    bool compare_exchange_strong(/* 浮点 */&, /* 浮点 */,
                                 memory_order, memory_order) noexcept;
    bool compare_exchange_weak(/* 浮点 */&, /* 浮点 */,
                               memory_order = memory_order_seq_cst) volatile noexcept;
    bool compare_exchange_weak(/* 浮点 */&, /* 浮点 */,
                               memory_order = memory_order_seq_cst) noexcept;
    bool compare_exchange_strong(/* 浮点 */&, /* 浮点 */,
                                 memory_order = memory_order_seq_cst) volatile noexcept;
    bool compare_exchange_strong(/* 浮点 */&, /* 浮点 */,
                                 memory_order = memory_order_seq_cst) noexcept;

    /* 浮点 */ fetch_add(/* 浮点 */,
                             memory_order = memory_order_seq_cst) volatile noexcept;
    /* 浮点 */ fetch_add(/* 浮点 */,
                             memory_order = memory_order_seq_cst) noexcept;
    /* 浮点 */ fetch_sub(/* 浮点 */,
                             memory_order = memory_order_seq_cst) volatile noexcept;
    /* 浮点 */ fetch_sub(/* 浮点 */,
                             memory_order = memory_order_seq_cst) noexcept;

    /* 浮点 */ operator+=(/* 浮点 */) volatile noexcept;
    /* 浮点 */ operator+=(/* 浮点 */) noexcept;
    /* 浮点 */ operator-=(/* 浮点 */) volatile noexcept;
    /* 浮点 */ operator-=(/* 浮点 */) noexcept;

    void wait(/* 浮点 */,
              memory_order = memory_order::seq_cst) const volatile noexcept;
    void wait(/* 浮点 */,
              memory_order = memory_order::seq_cst) const noexcept;
    void notify_one() volatile noexcept;
    void notify_one() noexcept;
    void notify_all() volatile noexcept;
    void notify_all() noexcept;
  };
}

std::atomic 对指针类型的特化

namespace std {
  template<class T> struct atomic<T*> {
    using value_type = T*;
    using difference_type = ptrdiff_t;

    static constexpr bool is_always_lock_free = /* 实现定义 */;
    bool is_lock_free() const volatile noexcept;
    bool is_lock_free() const noexcept;

    constexpr atomic() noexcept;
    constexpr atomic(T*) noexcept;
    atomic(const atomic&) = delete;
    atomic& operator=(const atomic&) = delete;
    atomic& operator=(const atomic&) volatile = delete;

    void store(T*, memory_order = memory_order::seq_cst) volatile noexcept;
    void store(T*, memory_order = memory_order::seq_cst) noexcept;
    T* operator=(T*) volatile noexcept;
    T* operator=(T*) noexcept;
    T* load(memory_order = memory_order::seq_cst) const volatile noexcept;
    T* load(memory_order = memory_order::seq_cst) const noexcept;
    operator T*() const volatile noexcept;
    operator T*() const noexcept;

    T* exchange(T*, memory_order = memory_order::seq_cst) volatile noexcept;
    T* exchange(T*, memory_order = memory_order::seq_cst) noexcept;
    bool compare_exchange_weak(T*&, T*, memory_order, memory_order) volatile noexcept;
    bool compare_exchange_weak(T*&, T*, memory_order, memory_order) noexcept;
    bool compare_exchange_strong(T*&, T*, memory_order, memory_order) volatile noexcept;
    bool compare_exchange_strong(T*&, T*, memory_order, memory_order) noexcept;
    bool compare_exchange_weak(T*&, T*,
                               memory_order = memory_order::seq_cst) volatile noexcept;
    bool compare_exchange_weak(T*&, T*,
                               memory_order = memory_order::seq_cst) noexcept;
    bool compare_exchange_strong(T*&, T*,
                                 memory_order = memory_order::seq_cst) volatile noexcept;
    bool compare_exchange_strong(T*&, T*,
                                 memory_order = memory_order::seq_cst) noexcept;

    T* fetch_add(ptrdiff_t, memory_order = memory_order::seq_cst) volatile noexcept;
    T* fetch_add(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept;
    T* fetch_sub(ptrdiff_t, memory_order = memory_order::seq_cst) volatile noexcept;
    T* fetch_sub(ptrdiff_t, memory_order = memory_order::seq_cst) noexcept;

    T* operator++(int) volatile noexcept;
    T* operator++(int) noexcept;
    T* operator--(int) volatile noexcept;
    T* operator--(int) noexcept;
    T* operator++() volatile noexcept;
    T* operator++() noexcept;
    T* operator--() volatile noexcept;
    T* operator--() noexcept;
    T* operator+=(ptrdiff_t) volatile noexcept;
    T* operator+=(ptrdiff_t) noexcept;
    T* operator-=(ptrdiff_t) volatile noexcept;
    T* operator-=(ptrdiff_t) noexcept;

    void wait(T*, memory_order = memory_order::seq_cst) const volatile noexcept;
    void wait(T*, memory_order = memory_order::seq_cst) const noexcept;
    void notify_one() volatile noexcept;
    void notify_one() noexcept;
    void notify_all() volatile noexcept;
    void notify_all() noexcept;
  };
}

类模板 std::atomic_ref

namespace std {
  template<class T> struct atomic_ref {
  private:
    T* ptr;             // 仅用于阐释
  public:
    using value_type = T;
    static constexpr size_t required_alignment = /* 实现定义 */;

    static constexpr bool is_always_lock_free = /* 实现定义 */;
    bool is_lock_free() const noexcept;

    explicit atomic_ref(T&);
    atomic_ref(const atomic_ref&) noexcept;
    atomic_ref& operator=(const atomic_ref&) = delete;

    void store(T, memory_order = memory_order_seq_cst) const noexcept;
    T operator=(T) const noexcept;
    T load(memory_order = memory_order_seq_cst) const noexcept;
    operator T() const noexcept;

    T exchange(T, memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_weak(T&, T,
                               memory_order, memory_order) const noexcept;
    bool compare_exchange_strong(T&, T,
                                 memory_order, memory_order) const noexcept;
    bool compare_exchange_weak(T&, T,
                               memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_strong(T&, T,
                                 memory_order = memory_order_seq_cst) const noexcept;

    void wait(T, memory_order = memory_order::seq_cst) const noexcept;
    void notify_one() const noexcept;
    void notify_all() const noexcept;
  };
}

std::atomic_ref 对整数类型的特化

namespace std {
  template<> struct atomic_ref</* 整型 */> {
  private:
    /* 整型 */* ptr;        // 仅用于阐释
  public:
    using value_type = /* 整型 */;
    using difference_type = value_type;
    static constexpr size_t required_alignment = /* 实现定义 */;

    static constexpr bool is_always_lock_free = /* 实现定义 */;
    bool is_lock_free() const noexcept;

    explicit atomic_ref(/* 整型 */&);
    atomic_ref(const atomic_ref&) noexcept;
    atomic_ref& operator=(const atomic_ref&) = delete;

    void store(/* 整型 */, memory_order = memory_order_seq_cst) const noexcept;
    /* 整型 */ operator=(/* 整型 */) const noexcept;
    /* 整型 */ load(memory_order = memory_order_seq_cst) const noexcept;
    operator /* 整型 */() const noexcept;

    /* 整型 */ exchange(/* 整型 */,
                      memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_weak(/* 整型 */&, /* 整型 */,
                               memory_order, memory_order) const noexcept;
    bool compare_exchange_strong(/* 整型 */&, /* 整型 */,
                                 memory_order, memory_order) const noexcept;
    bool compare_exchange_weak(/* 整型 */&, /* 整型 */,
                               memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_strong(/* 整型 */&, /* 整型 */,
                                 memory_order = memory_order_seq_cst) const noexcept;

    /* 整型 */ fetch_add(/* 整型 */,
                       memory_order = memory_order_seq_cst) const noexcept;
    /* 整型 */ fetch_sub(/* 整型 */,
                       memory_order = memory_order_seq_cst) const noexcept;
    /* 整型 */ fetch_and(/* 整型 */,
                       memory_order = memory_order_seq_cst) const noexcept;
    /* 整型 */ fetch_or(/* 整型 */,
                      memory_order = memory_order_seq_cst) const noexcept;
    /* 整型 */ fetch_xor(/* 整型 */,
                       memory_order = memory_order_seq_cst) const noexcept;

    /* 整型 */ operator++(int) const noexcept;
    /* 整型 */ operator--(int) const noexcept;
    /* 整型 */ operator++() const noexcept;
    /* 整型 */ operator--() const noexcept;
    /* 整型 */ operator+=(/* 整型 */) const noexcept;
    /* 整型 */ operator-=(/* 整型 */) const noexcept;
    /* 整型 */ operator&=(/* 整型 */) const noexcept;
    /* 整型 */ operator

std::atomic_ref 对浮点类型的特化

namespace std {
  template<> struct atomic_ref</* 浮点 */> {
  private:
    /* 浮点 */* ptr;  // 仅用于阐释
  public:
    using value_type = /* 浮点 */;
    using difference_type = value_type;
    static constexpr size_t required_alignment = /* 实现定义 */;

    static constexpr bool is_always_lock_free = /* 实现定义 */;
    bool is_lock_free() const noexcept;

    explicit atomic_ref(/* 浮点 */&);
    atomic_ref(const atomic_ref&) noexcept;
    atomic_ref& operator=(const atomic_ref&) = delete;

    void store(/* 浮点 */, memory_order = memory_order_seq_cst) const noexcept;
    /* 浮点 */ operator=(/* 浮点 */) const noexcept;
    /* 浮点 */ load(memory_order = memory_order_seq_cst) const noexcept;
    operator /* 浮点 */() const noexcept;

    /* 浮点 */ exchange(/* 浮点 */,
                            memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_weak(/* 浮点 */&, /* 浮点 */,
                               memory_order, memory_order) const noexcept;
    bool compare_exchange_strong(/* 浮点 */&, /* 浮点 */,
                                 memory_order, memory_order) const noexcept;
    bool compare_exchange_weak(/* 浮点 */&, /* 浮点 */,
                               memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_strong(/* 浮点 */&, /* 浮点 */,
                                 memory_order = memory_order_seq_cst) const noexcept;

    /* 浮点 */ fetch_add(/* 浮点 */,
                             memory_order = memory_order_seq_cst) const noexcept;
    /* 浮点 */ fetch_sub(/* 浮点 */,
                             memory_order = memory_order_seq_cst) const noexcept;

    /* 浮点 */ operator+=(/* 浮点 */) const noexcept;
    /* 浮点 */ operator-=(/* 浮点 */) const noexcept;

    void wait(/* 浮点 */, memory_order = memory_order::seq_cst) const noexcept;
    void notify_one() const noexcept;
    void notify_all() const noexcept;
  };
}

std::atomic_ref 对指针类型的特化

namespace std {
  template<class T> struct atomic_ref<T*> {
  private:
    T** ptr;        // 仅用于阐释
  public:
    using value_type = T*;
    using difference_type = ptrdiff_t;
    static constexpr size_t required_alignment = /* 实现定义 */;

    static constexpr bool is_always_lock_free = /* 实现定义 */;
    bool is_lock_free() const noexcept;

    explicit atomic_ref(T*&);
    atomic_ref(const atomic_ref&) noexcept;
    atomic_ref& operator=(const atomic_ref&) = delete;

    void store(T*, memory_order = memory_order_seq_cst) const noexcept;
    T* operator=(T*) const noexcept;
    T* load(memory_order = memory_order_seq_cst) const noexcept;
    operator T*() const noexcept;

    T* exchange(T*, memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_weak(T*&, T*,
                               memory_order, memory_order) const noexcept;
    bool compare_exchange_strong(T*&, T*,
                                 memory_order, memory_order) const noexcept;
    bool compare_exchange_weak(T*&, T*,
                               memory_order = memory_order_seq_cst) const noexcept;
    bool compare_exchange_strong(T*&, T*,
                                 memory_order = memory_order_seq_cst) const noexcept;

    T* fetch_add(difference_type, memory_order = memory_order_seq_cst) const noexcept;
    T* fetch_sub(difference_type, memory_order = memory_order_seq_cst) const noexcept;

    T* operator++(int) const noexcept;
    T* operator--(int) const noexcept;
    T* operator++() const noexcept;
    T* operator--() const noexcept;
    T* operator+=(difference_type) const noexcept;
    T* operator-=(difference_type) const noexcept;

    void wait(T*, memory_order = memory_order::seq_cst) const noexcept;
    void notify_one() const noexcept;
    void notify_all() const noexcept;
  };
}

类 std::atomic_flag

namespace std {
  struct atomic_flag {
    constexpr atomic_flag() noexcept;
    atomic_flag(const atomic_flag&) = delete;
    atomic_flag& operator=(const atomic_flag&) = delete;
    atomic_flag& operator=(const atomic_flag&) volatile = delete;

    bool test(memory_order = memory_order::seq_cst) const volatile noexcept;
    bool test(memory_order = memory_order::seq_cst) const noexcept;
    bool test_and_set(memory_order = memory_order::seq_cst) volatile noexcept;
    bool test_and_set(memory_order = memory_order::seq_cst) noexcept;
    void clear(memory_order = memory_order::seq_cst) volatile noexcept;
    void clear(memory_order = memory_order::seq_cst) noexcept;

    void wait(bool, memory_order = memory_order::seq_cst) const volatile noexcept;
    void wait(bool, memory_order = memory_order::seq_cst) const noexcept;
    void notify_one() volatile noexcept;
    void notify_one() noexcept;
    void notify_all() volatile noexcept;
    void notify_all() noexcept;
  };
}


标准库头文件 <barrier>

< cpp‎ | header

此头文件是线程支持库的一部分。

类
barrier
(C++20)
 可复用的线程屏障
(类模板)

概要

namespace std {
  template<class CompletionFunction = /* 见描述 */>
    class barrier;
}

类模板 std::barrier

namespace std {
  template<class CompletionFunction = /* see description */>
  class barrier {
  public:
    using arrival_token =  /* see description */;

    static constexpr ptrdiff_t max() noexcept;

    constexpr explicit barrier(ptrdiff_t expected,
                               CompletionFunction f = CompletionFunction());
    ~barrier();

    barrier(const barrier&) = delete;
    barrier& operator=(const barrier&) = delete;

    [[nodiscard]] arrival_token arrive(ptrdiff_t update = 1);
    void wait(arrival_token&& arrival) const;

    void arrive_and_wait();
    void arrive_and_drop();

  private:
    CompletionFunction completion;      // 仅用于阐释
  };
}


标准库头文件 <bit>

< cpp‎ | header

此头文件是数值库的一部分。

类型
endian
(C++20)
 指示标量类型的端序
(枚举)

函数
bit_cast
(C++20)
 将一个类型的对象表示重解释为另一类型的对象表示
(函数模板)
byteswap
(C++23)
 反转给定整数值中的字节
(函数模板)
has_single_bit
(C++20)
 检查一个数是否为二的整数次幂
(函数模板)
bit_ceil
(C++20)
 寻找不小于给定值的最小的二的整数次幂
(函数模板)
bit_floor
(C++20)
 寻找不大于给定值的最大的二的整数次幂
(函数模板)
bit_width
(C++20)
 寻找表示给定值所需的最小位数
(函数模板)
rotl
(C++20)
 计算逐位左旋转的结果
(函数模板)
rotr
(C++20)
 计算逐位右旋转的结果
(函数模板)
countl_zero
(C++20)
 从最高位起计量连续的 0 位的数量
(函数模板)
countl_one
(C++20)
 从最高位起计量连续的 1 位的数量
(函数模板)
countr_zero
(C++20)
 从最低位起计量连续的 0 位的数量
(函数模板)
countr_one
(C++20)
 从最低位起计量连续的 1 位的数量
(函数模板)
popcount
(C++20)
 计量无符号整数中为 1 的位的数量
(函数模板)

概要

namespace std {
  // bit_cast
  template<class To, class From>
    constexpr To bit_cast(const From& from) noexcept;

  // 位交换
  template <class T>
  constexpr T byteswap (T value) noexcept;

  // 2 的整数次幂
  template<class T>
    constexpr bool has_single_bit(T x) noexcept;
  template<class T>
    constexpr T bit_ceil(T x);
  template<class T>
    constexpr T bit_floor(T x) noexcept;
  template<class T>
    constexpr T bit_width(T x) noexcept;

  // 旋转
  template<class T>
    [[nodiscard]] constexpr T rotl(T x, int s) noexcept;
  template<class T>
    [[nodiscard]] constexpr T rotr(T x, int s) noexcept;

  // 计数
  template<class T>
    constexpr int countl_zero(T x) noexcept;
  template<class T>
    constexpr int countl_one(T x) noexcept;
  template<class T>
    constexpr int countr_zero(T x) noexcept;
  template<class T>
    constexpr int countr_one(T x) noexcept;
  template<class T>
    constexpr int popcount(T x) noexcept;

  // 端序
  enum class endian {
    little = /* 见描述 */,
    big    = /* 见描述 */,
    native = /* 见描述 */
  };
}


标准库头文件 <bitset>

< cpp‎ | header

此头文件是通用工具库的一部分。

包含
<string>
 std::basic_string 类模板
<iosfwd>
 输入/输出库中所有类的前置声明

类
bitset
 实现常量长度的位数组
(类模板)
std::hash<std::bitset>
(C++11)
 std::bitset 的散列支持
(类模板特化)
前置声明
定义于头文件 <functional>
hash
(C++11)
 散列函数对象
(类模板)

函数
operator&operator|operator^
 在 bitset 上执行二元逻辑操作
(函数)
operator<<operator>>
 执行 bitset 的流输入和输出
(函数)

概要

#include <string>
#include <iosfwd>   // 为 istream 、 ostream

namespace std {
  template<size_t N> class bitset;

  // bitset 运算符
  template<size_t N>
    bitset<N> operator&(const bitset<N>&, const bitset<N>&) noexcept;
  template<size_t N>
    bitset<N> operator|(const bitset<N>&, const bitset<N>&) noexcept;
  template<size_t N>
    bitset<N> operator^(const bitset<N>&, const bitset<N>&) noexcept;
  template<class CharT, class Traits, size_t N>
    basic_istream<CharT, Traits>&
      operator>>(basic_istream<CharT, Traits>& is, bitset<N>& x);
  template<class CharT, class Traits, size_t N>
    basic_ostream<CharT, Traits>&
      operator<<(basic_ostream<CharT, Traits>& os, const bitset<N>& x);
}

类模板 std::bitset

namespace std {
  template<size_t N> class bitset {
  public:
    // 位引用
    class reference {
      friend class bitset;
      reference() noexcept;

    public:
      reference(const reference&) = default;
      ~reference();
      reference& operator=(bool x) noexcept;            // 针对 b[i] = x;
      reference& operator=(const reference&) noexcept;  // 针对 b[i] = b[j];
      bool operator~() const noexcept;                  // 翻转位
      operator bool() const noexcept;                   // 针对 x = b[i];
      reference& flip() noexcept;                       // 针对 b[i].flip();
    };

    // 构造函数
    constexpr bitset() noexcept;
    constexpr bitset(unsigned long long val) noexcept;
    template<class CharT, class Traits, class Allocator>
      explicit bitset(
        const basic_string<CharT, Traits, Allocator>& str,
        typename basic_string<CharT, Traits, Allocator>::size_type pos = 0,
        typename basic_string<CharT, Traits, Allocator>::size_type n
          = basic_string<CharT, Traits, Allocator>::npos,
        CharT zero = CharT('0'),
        CharT one = CharT('1'));
    template<class CharT>
      explicit bitset(
        const charT* str,
        typename basic_string<CharT>::size_type n = basic_string<CharT>::npos,
        CharT zero = CharT('0'),
        CharT one = CharT('1'));

    // bitset 操作
    bitset& operator&=(const bitset& rhs) noexcept;
    bitset& operator|=(const bitset& rhs) noexcept;
    bitset& operator^=(const bitset& rhs) noexcept;
    bitset& operator<<=(size_t pos) noexcept;
    bitset& operator>>=(size_t pos) noexcept;
    bitset& set() noexcept;
    bitset& set(size_t pos, bool val = true);
    bitset& reset() noexcept;
    bitset& reset(size_t pos);
    bitset  operator~() const noexcept;
    bitset& flip() noexcept;
    bitset& flip(size_t pos);

    // 元素访问
    constexpr bool operator[](size_t pos) const;        // 针对 b[i];
    reference operator[](size_t pos);                   // 针对 b[i];

    unsigned long to_ulong() const;
    unsigned long long to_ullong() const;
    template<class CharT = char,
             class Traits = char_Traits<CharT>,
             class Allocator = allocator<CharT>>
      basic_string<CharT, Traits, Allocator>
        to_string(CharT zero = CharT('0'), CharT one = CharT('1')) const;

    size_t count() const noexcept;
    constexpr size_t size() const noexcept;
    bool operator==(const bitset& rhs) const noexcept;
    bool test(size_t pos) const;
    bool all() const noexcept;
    bool any() const noexcept;
    bool none() const noexcept;
    bitset operator<<(size_t pos) const noexcept;
    bitset operator>>(size_t pos) const noexcept;
  };

  // 散列支持
  template<class T> struct hash;
  template<size_t N> struct hash<bitset<N>>;
}


标准库头文件 <cassert>

< cpp‎ | header

此头文件原作为 <assert.h> 存在于 C 标准库。

此头文件是错误处理库的一部分。

宏
assert
 若用户指定的条件非 true 则中断程序。可以在发行构建中禁用
(宏函数)

概要

#define assert(E) /* 见描述 */


标准库头文件 <ccomplex>

< cpp‎ | header

此头文件原作为 <complex.h> 存在于 C 标准库。

包含
<complex>
(C++11)
 复数类型

注解

此头文件于 C++17 中弃用并于 C++20 中移除。对应的 <complex.h> 在 C++20 中仍可用。


标准库头文件 <cctype>

< cpp‎ | header

此头文件原作为 <ctype.h> 存在于 C 标准库。

此头文件是空终止字节字符串库的一部分。

函数
isalnum
 检查字符是否为字母或数字
(函数)
isalpha
 检查字符是否为字母
(函数)
islower
 检查字符是否为小写
(函数)
isupper
 检查字符是否为大写字符
(函数)
isdigit
 检查字符是否为数字
(函数)
isxdigit
 检查字符是为十六进制字符
(函数)
iscntrl
 检查字符是否为控制字符
(函数)
isgraph
 检查字符是否为图形字符
(函数)
isspace
 检查字符是否为空白间隔字符
(函数)
isblank
(C++11)
 检查字符是否为空白字符
(函数)
isprint
 检查字符是否为打印字符
(函数)
ispunct
 检查字符是否为标点符
(函数)
tolower
 转换字符为小写
(函数)
toupper
 转换字符为大写
(函数)

概要

namespace std {
  int isalnum(int c);
  int isalpha(int c);
  int isblank(int c);
  int iscntrl(int c);
  int isdigit(int c);
  int isgraph(int c);
  int islower(int c);
  int isprint(int c);
  int ispunct(int c);
  int isspace(int c);
  int isupper(int c);
  int isxdigit(int c);
  int tolower(int c);
  int toupper(int c);
}


标准库头文件 <cerrno>

< cpp‎ | header

此头文件原作为 <errno.h> 存在于 C 标准库。

此头文件是错误处理库的一部分。

宏

errno | 展开成 POSIX 兼容的线程局域错误号变量的宏 (宏变量)
E2BIG (C++11) | 参数列表过长 (宏常量)
EACCES (C++11) | 禁止访问 (宏常量)
EADDRINUSE (C++11) | 地址在使用中 (宏常量)
EADDRNOTAVAIL (C++11) | 地址不可用 (宏常量)
EAFNOSUPPORT (C++11) | 不支持的地址系列 (宏常量)
EAGAIN (C++11) | 资源不可用，须重试 (宏常量)
EALREADY (C++11) | 连接已在进行 (宏常量)
EBADF (C++11) | 无效文件描述符 (宏常量)
EBADMSG (C++11) | 无效消息 (宏常量)
EBUSY (C++11) | 设备或资源忙 (宏常量)
ECANCELED (C++11) | 操作已取消 (宏常量)
ECHILD (C++11) | 无子进程 (宏常量)
ECONNABORTED (C++11) | 连接被打断 (宏常量)
ECONNREFUSED (C++11) | 连接被拒绝 (宏常量)
ECONNRESET (C++11) | 连接被重置 (宏常量)
EDEADLK (C++11) | 可能发生资源死锁 (宏常量)
EDESTADDRREQ (C++11) | 要求目标地址 (宏常量)
EDOM | 数学参数在函数定义域外 (宏常量)
EEXIST (C++11) | 文件已存在 (宏常量)
EFAULT (C++11) | 无效地址 (宏常量)
EFBIG (C++11) | 文件过大 (宏常量)
EHOSTUNREACH (C++11) | 主机不可抵达 (宏常量)
EIDRM (C++11) | 标识符被移除 (宏常量)
EILSEQ (C++11) | 非法字节序列 (宏常量)
EINPROGRESS (C++11) | 操作已在进行 (宏常量)
EINTR (C++11) | 函数被中断 (宏常量)
EINVAL (C++11) | 无效参数 (宏常量)
EIO (C++11) | I/O 错误 (宏常量)
EISCONN (C++11) | 套接字已连接 (宏常量)
EISDIR (C++11) | 此项目是目录 (宏常量)
ELOOP (C++11) | 符号链接级别过多 (宏常量)
EMFILE (C++11) | 文件描述符值过大 (宏常量)
EMLINK (C++11) | 链接过多 (宏常量)
EMSGSIZE (C++11) | 消息过大 (宏常量)
ENAMETOOLONG (C++11) | 文件名过长 (宏常量)
ENETDOWN (C++11) | 网络已关闭 (宏常量)
ENETRESET (C++11) | 连接被网络打断 (宏常量)
ENETUNREACH (C++11) | 网络不可达 (宏常量)
ENFILE (C++11) | 系统中打开文件过多 (宏常量)
ENOBUFS (C++11) | 无缓冲空间可用 (宏常量)
ENODATA (C++11) | 流头部读取队列中无消息 (宏常量)
ENODEV (C++11) | 设备不存在 (宏常量)
ENOENT (C++11) | 文件或目录不存在 (宏常量)
ENOEXEC (C++11) | 可执行文件格式错误 (宏常量)
ENOLCK (C++11) | 无可用锁 (宏常量)
ENOLINK (C++11) | 链接已切断 (宏常量)
ENOMEM (C++11) | 空间不足 (宏常量)
ENOMSG (C++11) | 无所需类型的消息 (宏常量)
ENOPROTOOPT (C++11) | 协议不可用 (宏常量)
ENOSPC (C++11) | 设备无剩余空间 (宏常量)
ENOSR (C++11) | 无流资源 (宏常量)
ENOSTR (C++11) | 此项目非流 (宏常量)
ENOSYS (C++11) | 不支持的函数 (宏常量)
ENOTCONN (C++11) | 未连接的套接字 (宏常量)
ENOTDIR (C++11) | 此项目非目录 (宏常量)
ENOTEMPTY (C++11) | 目录非空 (宏常量)
ENOTRECOVERABLE (C++11) | 状态不可恢复 (宏常量)
ENOTSOCK (C++11) | 此项目非套接字 (宏常量)
ENOTSUP (C++11) | 不支持 (宏常量)
ENOTTY (C++11) | 不适合的 I/O 控制操作 (宏常量)
ENXIO (C++11) | 设备或地址不存在 (宏常量)
EOPNOTSUPP (C++11) | 套接字不支持的操作 (宏常量)
EOVERFLOW (C++11) | 值过大而无法存入数据类型 (宏常量)
EOWNERDEAD (C++11) | 先前拥有者已死 (宏常量)
EPERM (C++11) | 操作不允许 (宏常量)
EPIPE (C++11) | 管道损坏 (宏常量)
EPROTO (C++11) | 协议错误 (宏常量)
EPROTONOSUPPORT (C++11) | 不支持的协议 (宏常量)
EPROTOTYPE (C++11) | 错误的套接字协议类型 (宏常量)
ERANGE | 结果过大 (宏常量)
EROFS (C++11) | 只读文件系统 (宏常量)
ESPIPE (C++11) | 非法寻位 (宏常量)
ESRCH (C++11) | 无此进程 (宏常量)
ETIME (C++11) | 流 ioctl() 超时 (宏常量)
ETIMEDOUT (C++11) | 连接超时 (宏常量)
ETXTBSY (C++11) | 文本文件忙 (宏常量)
EWOULDBLOCK (C++11) | 操作可能阻塞 (宏常量)
EXDEV (C++11) | 跨设备链接 (宏常量)

注解

头文件 <cerrno> 基于 C 标准库头文件 errno.h ，然而 C++ 主要从 POSIX 标准，而非 C 标准库采用 <cerrno> 所定义的宏。

参阅

  • 错误号的值的描述


标准库头文件 <cfenv>

< cpp‎ | header

此头文件原作为 <fenv.h> 存在于 C 标准库。

此头文件是浮点环境库的一部分。

类型

fenv_t | 表示整个浮点环境的类型
fexcept_t | 汇集地表示所有浮点状态标志的类型

函数

feclearexcept (C++11) | 清除指定的浮点状态标志 (函数)
fetestexcept (C++11) | 确定设置了哪个指定的浮点状态标志 (函数)
feraiseexcept (C++11) | 引发指定的浮点异常 (函数)
fegetexceptflagfesetexceptflag (C++11)(C++11) | 从浮点环境（或向其中）复制指定的浮点状态标志 (函数)
fegetroundfesetround (C++11)(C++11) | 获取或设置舍入方向 (函数)
fegetenvfesetenv (C++11) | 保存或恢复当前浮点环境 (函数)
feholdexcept (C++11) | 保存环境，清除所有状态标志，并忽略所有将来的错误 (函数)
feupdateenv (C++11) | 恢复浮点环境并引发之前引发的异常 (函数)

宏

FE_ALL_EXCEPTFE_DIVBYZEROFE_INEXACTFE_INVALIDFE_OVERFLOWFE_UNDERFLOW (C++11) | 浮点异常 (宏常量)
FE_DOWNWARDFE_TONEARESTFE_TOWARDZEROFE_UPWARD (C++11) | 浮点舍入方向 (宏常量)
FE_DFL_ENV (C++11) | 默认浮点环境 (宏常量)

概要

namespace std {
    // 类型
    typedef /*对象类型*/ fenv_t;
    typedef /*整数类型*/ fexcept_t;

    // 函数
    int feclearexcept(int except);
    int fegetexceptflag(fexcept_t *pflag, int except);
    int feraiseexcept(int except);
    int fesetexceptflag(const fexcept_t *pflag, int except);
    int fetestexcept(int except);
    int fegetround(void);
    int fesetround(int mode);
    int fegetenv(fenv_t *penv);
    int feholdexcept(fenv_t *penv);
    int fesetenv(const fenv_t *penv);
    int feupdateenv(const fenv_t *penv);
}


标准库头文件 <cfloat>

< cpp‎ | header

此头文件原作为 <float.h> 存在于 C 标准库。

此头文件是类型支持库的一部分，特别是它是 C 数值极限接口的一部分。

宏

FLT_RADIX | 所有三种浮点类型的表示所用的基数（整数底） (宏常量)
DECIMAL_DIG (C++11) | 从 long double 转换到至少有 DECIMAL_DIG 位数字的十进制表示，再转换回 long double 为恒等转换：这是序列化/反序列化 long double 所要求的十进制精度（参阅 std::numeric_limits::max_digits10） (宏常量)
FLT_DECIMAL_DIGDBL_DECIMAL_DIGLDBL_DECIMAL_DIG (C++17) | 从 float/double/long double 转换到至少有 FLT_DECIMAL_DIG/DBL_DECIMAL_DIG/LDBL_DECIMAL_DIG 位数字的十进制，再转换回原类型为恒等转换：这是序列化/反序列化浮点值所要求的十进制精度（参阅 std::numeric_limits::max_digits10）。分别定义为至少 6、10 和 10，对于 IEEE float 为 9，对于 IEEE double 为 17。 (宏常量)
FLT_MINDBL_MINLDBL_MIN | 分别为 float、double 与 long double 的最小规格化正数值 (宏常量)
FLT_TRUE_MINDBL_TRUE_MINLDBL_TRUE_MIN (C++17) | 分别为 float、double 与 long double 的最小正数值 (宏常量)
FLT_MAXDBL_MAXLDBL_MAX | 分别为 float、double 与 long double 的最大有限值 (宏常量)
FLT_EPSILONDBL_EPSILONLDBL_EPSILON | 分别为 1.0 和 float、double 及 long double 的下一个可表示值之差 (宏常量)
FLT_DIGDBL_DIGLDBL_DIG | 保证能在文本→ float/double/long double →文本的往返转换中保留而不会因舍入或溢出发生改变的的十进制位数（解释参阅 std::numeric_limits::digits10） (宏常量)
FLT_MANT_DIGDBL_MANT_DIGLDBL_MANT_DIG | 分别为能无精度损失地表示成 float、double 及 long double 的基数 FLT_RADIX 的数字位数 (宏常量)
FLT_MIN_EXPDBL_MIN_EXPLDBL_MIN_EXP | 分别为能够使FLT_RADIX 的该整数减一次幂为规格化的 float、double 与 long double 的最小负整数 (宏常量)
FLT_MIN_10_EXPDBL_MIN_10_EXPLDBL_MIN_10_EXP | 分别为能够使 10 的该整数减一次幂为规格化的 float、double 与 long double 的最小负整数 (宏常量)
FLT_MAX_EXPDBL_MAX_EXPLDBL_MAX_EXP | 分别为能够使 FLT_RADIX 的该整数减一次幂为可表示的有限的 float、double 与 long double 的最大正整数 (宏常量)
FLT_MAX_10_EXPDBL_MAX_10_EXPLDBL_MAX_10_EXP | 分别为能够使 10 的该整数减一次幂为可表示的有限的 float、double 与 long double 的最大正整数 (宏常量)
FLT_ROUNDS | 浮点算术的默认舍入模式 (宏常量)
FLT_EVAL_METHOD (C++11) | 指定进行所有算术运算所用的精度 (宏常量)
FLT_HAS_SUBNORMDBL_HAS_SUBNORMLDBL_HAS_SUBNORM (C++17) | 指明类型是否支持非正规数值：-1 为不确定，0 为不支持，1 为支持。 (宏常量)

概要

#define FLT_ROUNDS /* 见定义 */
#define FLT_EVAL_METHOD /* 见定义 */
#define FLT_HAS_SUBNORM /* 见定义 */
#define DBL_HAS_SUBNORM /* 见定义 */
#define LDBL_HAS_SUBNORM /* 见定义 */
#define FLT_RADIX /* 见定义 */
#define FLT_MANT_DIG /* 见定义 */
#define DBL_MANT_DIG /* 见定义 */
#define LDBL_MANT_DIG /* 见定义 */
#define FLT_DECIMAL_DIG /* 见定义 */
#define DBL_DECIMAL_DIG /* 见定义 */
#define LDBL_DECIMAL_DIG /* 见定义 */
#define DECIMAL_DIG /* 见定义 */
#define FLT_DIG /* 见定义 */
#define DBL_DIG /* 见定义 */
#define LDBL_DIG /* 见定义 */
#define FLT_MIN_EXP /* 见定义 */
#define DBL_MIN_EXP /* 见定义 */
#define LDBL_MIN_EXP /* 见定义 */
#define FLT_MIN_10_EXP /* 见定义 */
#define DBL_MIN_10_EXP /* 见定义 */
#define LDBL_MIN_10_EXP /* 见定义 */
#define FLT_MAX_EXP /* 见定义 */
#define DBL_MAX_EXP /* 见定义 */
#define LDBL_MAX_EXP /* 见定义 */
#define FLT_MAX_10_EXP /* 见定义 */
#define DBL_MAX_10_EXP /* 见定义 */
#define LDBL_MAX_10_EXP /* 见定义 */
#define FLT_MAX /* 见定义 */
#define DBL_MAX /* 见定义 */
#define LDBL_MAX /* 见定义 */
#define FLT_EPSILON /* 见定义 */
#define DBL_EPSILON /* 见定义 */
#define LDBL_EPSILON /* 见定义 */
#define FLT_MIN /* 见定义 */
#define DBL_MIN /* 见定义 */
#define LDBL_MIN /* 见定义 */
#define FLT_TRUE_MIN /* 见定义 */
#define DBL_TRUE_MIN /* 见定义 */
#define LDBL_TRUE_MIN /* 见定义 */


标准库头文件 <charconv>

< cpp‎ | header

类
chars_format
(C++17)
 指定 std::to_chars 和 std::from_chars 所用的格式
(枚举)

函数
from_chars
(C++17)
 转换字符序列到整数或浮点值
(函数)
to_chars
(C++17)
 转换整数或浮点值到字符序列
(函数)

概要

namespace std {
  // 初等数值转换的浮点格式
  enum class chars_format {
    scientific = /* 未指明 */,
    fixed = /* 未指明 */,
    hex = /* 未指明 */,
    general = fixed | scientific
  };

  // 初等数值输出转换
  struct to_chars_result {
    char* ptr;
    errc ec;
    friend bool operator==(const to_chars_result&, const to_chars_result&) = default;
  };

  to_chars_result to_chars(char* first, char* last,
                           /* 见描述 */ value, int base = 10);
  to_chars_result to_chars(char* first, char* last, bool value, int base = 10) = delete;

  to_chars_result to_chars(char* first, char* last, float value);
  to_chars_result to_chars(char* first, char* last, double value);
  to_chars_result to_chars(char* first, char* last, long double value);

  to_chars_result to_chars(char* first, char* last, float value, chars_format fmt);
  to_chars_result to_chars(char* first, char* last, double value, chars_format fmt);
  to_chars_result to_chars(char* first, char* last, long double value, chars_format fmt);

  to_chars_result to_chars(char* first, char* last, float value,
                           chars_format fmt, int precision);
  to_chars_result to_chars(char* first, char* last, double value,
                           chars_format fmt, int precision);
  to_chars_result to_chars(char* first, char* last, long double value,
                           chars_format fmt, int precision);

  // 初等数值输入转换
  struct from_chars_result {
    const char* ptr;
    errc ec;
    friend bool operator==(const from_chars_result&, const from_chars_result&) = default;
  };

  from_chars_result from_chars(const char* first, const char* last,
                               /* 见描述 */& value, int base = 10);

  from_chars_result from_chars(const char* first, const char* last, float& value,
                               chars_format fmt = chars_format::general);
  from_chars_result from_chars(const char* first, const char* last, double& value,
                               chars_format fmt = chars_format::general);
  from_chars_result from_chars(const char* first, const char* last, long double& value,
                               chars_format fmt = chars_format::general);
}


标准库头文件 <chrono>

< cpp‎ | header

此头文件是日期和时间库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持

类
时长
定义于命名空间 std::chrono
duration
(C++11)
 时间区间
(类模板)
treat_as_floating_point
(C++11)
 指示时长可转换为拥有不同计次的时长
(类模板)
duration_values
(C++11)
 构造给定类型计次的零、最小及最大值
(类模板)
便利时长 typedef
定义于命名空间 std::chrono
std::chrono::nanoseconds(C++11) | Period 为 std::nano 的时长类型
std::chrono::microseconds(C++11) | Period 为 std::micro 的时长类型
std::chrono::milliseconds(C++11) | Period 为 std::milli 的时长类型
std::chrono::seconds(C++11) | Period 为 std::ratio <1> 的时长类型
std::chrono::minutes(C++11) | Period 为 std::ratio <60> 的时长类型
std::chrono::hours(C++11) | Period 为 std::ratio <3600> 的时长类型
std::chrono::days(C++20) | Period 为 std::ratio <86400> 的时长类型
std::chrono::weeks(C++20) | Period 为 std::ratio <604800> 的时长类型
std::chrono::months(C++20) | Period 为 std::ratio <2629746> 的时长类型
std::chrono::years(C++20) | Period 为 std::ratio <31556952> 的时长类型
时间点
定义于命名空间 std::chrono
time_point
(C++11)
 时间中的点
(类模板)
clock_time_conversion
(C++20)
 定义如何转换一个时钟的时间点为另一个的特性类
(类模板)
时钟
定义于命名空间 std::chrono
is_clockis_clock_v
(C++20)
 确定类型是否为时钟 (Clock)
(类模板) (变量模板)
system_clock
(C++11)
 来自系统范畴实时时钟的挂钟时间
(类)
steady_clock
(C++11)
 决不会调整的单调时钟
(类)
high_resolution_clock
(C++11)
 拥有可用的最短嘀嗒周期的时钟
(类)
utc_clock
(C++20)
 协调世界时 (UTC) 的时钟 (Clock)
(类)
tai_clock
(C++20)
 国际原子时 (TAI) 的时钟 (Clock)
(类)
gps_clock
(C++20)
 GPS 时间的时钟 (Clock)
(类)
file_clock
(C++20)
 用于文件时间的时钟 (Clock)
(typedef)
local_t
(C++20)
 表示本地时间的伪时钟
(类)
日历
定义于命名空间 std::chrono
last_spec
(C++20)
 指示一个月中最后日期或星期的标签类
(类)
day
(C++20)
 表示月之日期
(类)
month
(C++20)
 表示年之月份
(类)
year
(C++20)
 表示格里高利历中的年
(类)
weekday
(C++20)
 表示格里高利历中星期之日
(类)
weekday_indexed
(C++20)
 表示月份的第 n 个 weekday
(类)
weekday_last
(C++20)
 表示月份的最后一个 weekday
(类)
month_day
(C++20)
 表示特定 month 的特定 day
(类)
month_day_last
(C++20)
 表示特定 month 的最后一日
(类)
month_weekday
(C++20)
 表示特定 month 的第 n 个 weekday
(类)
month_weekday_last
(C++20)
 表示特定 month 的最后一个 weekday
(类)
year_month
(C++20)
 表示特定 year 的特定 month
(类)
year_month_day
(C++20)
 表示特定的 year 、 month 和 day
(类)
year_month_day_last
(C++20)
 表示特定 year 和 month 的最后一日
(类)
year_month_weekday
(C++20)
 表示特定 year 和 month 的第 n 个 weekday
(类)
year_month_weekday_last
(C++20)
 表示特定 year 和 month 的最后一个 weekday
(类)
当天时刻
定义于命名空间 std::chrono
hh_mm_ss
(C++20)
 表示当天时刻
(类模板)
时区
定义于命名空间 std::chrono
tzdb
(C++20)
 描述 IANA 时区数据库的副本
(类)
tzdb_list
(C++20)
 表示 tzdb 的链表
(类)
time_zone
(C++20)
 表示时区
(类)
sys_info
(C++20)
 表示在特定时间点的关于时区的信息
(类)
local_info
(C++20)
 表示关于从本地时间转换到 UNIX 时间的信息
(类)
choose
(C++20)
 选择应如何解析歧义的本地时间
(枚举)
zoned_traits
(C++20)
 zoned_time 所用的时区指针的特性类
(类模板)
zoned_time
(C++20)
 表示时区和时间点
(类)
time_zone_link
(C++20)
 表示时区的替用名
(类)
nonexistent_local_time
(C++20)
 抛出以报告本地时间不存在的异常
(类)
ambiguous_local_time
(C++20)
 抛出以报告本地时间有歧义的异常
(类)
闰秒
定义于命名空间 std::chrono
leap_second
(C++20)
 含有关于插入闰秒的信息
(类)
leap_second_info
(C++20)
 闰秒插入信息
(类)
特化
定义于命名空间 std

std::common_type<std::chrono::duration> (C++11) | 特化 std::common_type 特征 (类模板特化)
std::common_type<std::chrono::time_point> (C++11) | 特化 std::common_type 特征 (类模板特化)
std::formatter<std::chrono::duration> (C++20) | std::formatter 的特化，按提供的格式格式化 duration (类模板特化)
std::formatter<std::chrono::sys_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 sys_time (类模板特化)
std::formatter<std::chrono::utc_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 utc_time (类模板特化)
std::formatter<std::chrono::tai_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 tai_time (类模板特化)
std::formatter<std::chrono::gps_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 gps_time (类模板特化)
std::formatter<std::chrono::file_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 file_time (类模板特化)
std::formatter<std::chrono::local_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 local_time (类模板特化)
std::formatter<std::chrono::day> (C++20) | std::formatter 的特化，按照提供的格式格式化 day (类模板特化)
std::formatter<std::chrono::month> (C++20) | std::formatter 的特化，按照提供的格式格式化 month (类模板特化)
std::formatter<std::chrono::year> (C++20) | std::formatter 的特化，按照提供的格式格式化 year (类模板特化)
std::formatter<std::chrono::weekday> (C++20) | std::formatter 的特化，按照提供的格式格式化 weekday (类模板特化)
std::formatter<std::chrono::weekday_indexed> (C++20) | std::formatter 的特化，按照提供的格式格式化 weekday_indexed (类模板特化)
std::formatter<std::chrono::weekday_last> (C++20) | std::formatter 的特化，按照提供的格式格式化 weekday_last (类模板特化)
std::formatter<std::chrono::month_day> (C++20) | std::formatter 的特化，按照提供的格式格式化 month_day (类模板特化)
std::formatter<std::chrono::month_day_last> (C++20) | std::formatter 的特化，按照提供的格式格式化 month_day_last (类模板特化)
std::formatter<std::chrono::month_weekday> (C++20) | std::formatter 的特化，按照提供的格式格式化 month_weekday (类模板特化)
std::formatter<std::chrono::month_weekday_last> (C++20) | std::formatter 的特化，按照提供的格式格式化 month_weekday_last (类模板特化)
std::formatter<std::chrono::year_month> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month (类模板特化)
std::formatter<std::chrono::year_month_day> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month_day (类模板特化)
std::formatter<std::chrono::year_month_day_last> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month_day_last (类模板特化)
std::formatter<std::chrono::year_month_weekday> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month_weekday (类模板特化)
std::formatter<std::chrono::year_month_weekday_last> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month_weekday_last (类模板特化)
std::formatter<std::chrono::hh_mm_ss> (C++20) | std::formatter 的特化，按照提供的格式格式化 hh_mm_ss (类模板特化)
std::formatter<std::chrono::sys_info> (C++20) | std::formatter 的特化，按照提供的格式格式化 sys_info (类模板特化)
std::formatter<std::chrono::local_info> (C++20) | std::formatter 的特化，按照提供的格式格式化 local_info (类模板特化)
std::formatter<std::chrono::zoned_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 zoned_time (类模板特化)

函数
时长
定义于命名空间 std::chrono
operator+operator-operator*operator/operator%
(C++11)
 实现以时长为实参的算术运算
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++11)(C++11)(C++20 中移除)(C++11)(C++11)(C++11)(C++11)(C++20)
 比较两个时长
(函数模板)
duration_cast
(C++11)
 转换时长到另一个拥有不同嘀嗒间隔的时长
(函数模板)
floor(std::chrono::duration)
(C++17)
 以向下取整的方式，将一个时长转换为另一个时长
(函数模板)
ceil(std::chrono::duration)
(C++17)
 以向上取整的方式，将一个时长转换为另一个时长
(函数模板)
round(std::chrono::duration)
(C++17)
 转换时长到另一个时长，就近取整，偶数优先
(函数模板)
abs(std::chrono::duration)
(C++17)
 获取时长的绝对值
(函数模板)
时间点
定义于命名空间 std::chrono
operator+operator-
(C++11)
 实施涉及时间点的加法和减法运算
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++11)(C++11)(C++20 中移除)(C++11)(C++11)(C++11)(C++11)(C++20)
 比较两个时间点
(函数模板)
time_point_cast
(C++11)
 转换时间点为同一时钟上拥有不同时长的另一时间点
(函数模板)
floor(std::chrono::time_point)
(C++17)
 转换 time_point 到另一个，向下取整
(函数模板)
ceil(std::chrono::time_point)
(C++17)
 转换 time_point 到另一个，向上取整
(函数模板)
round(std::chrono::time_point)
(C++17)
 转换 time_point 到另一个，就近取整，偶数优先
(函数模板)
from_stream(std::chrono::sys_time)
(C++20)
 按照给定的格式从流分析 sys_time
(函数模板)
from_stream(std::chrono::utc_time)
(C++20)
 按照给定的格式从流分析 utc_time
(函数模板)
from_stream(std::chrono::tai_time)
(C++20)
 按照给定的格式从流分析 tai_time
(函数模板)
from_stream(std::chrono::gps_time)
(C++20)
 按照给定的格式从流分析 gps_time
(函数模板)
from_stream(std::chrono::file_time)
(C++20)
 按照给定的格式从流分析 file_time
(函数模板)
from_stream(std::chrono::local_time)
(C++20)
 按照给定的格式从流分析 local_time
(函数模板)
clock_cast
(C++20)
 转换一个时钟的时间点为另一个
(函数模板)
日历
定义于命名空间 std::chrono
operator==operator<=>
(C++20)
 比较二个 day 值
(函数)
operator==operator<=>
(C++20)
 比较二个 month 值
(函数)
operator==operator<=>
(C++20)
 比较二个 year 值
(函数)
operator==
(C++20)
 比较二个 weekday 值
(函数)
operator==
(C++20)
 比较二个 weekday_indexed 值
(函数)
operator==
(C++20)
 比较二个 weekday_last 值
(函数)
operator==operator<=>
(C++20)
 比较二个 month_day 值
(函数)
operator==operator<=>
(C++20)
 比较二个 month_day_last 值
(函数)
operator==
(C++20)
 比较二个 month_weekday 值
(函数)
operator==
(C++20)
 比较二个 month_weekday_last 值
(函数)
operator==operator<=>
(C++20)
 比较二个 year_month 值
(函数)
operator==operator<=>
(C++20)
 比较二个 year_month_day 值
(函数)
operator==operator<=>
(C++20)
 比较二个 year_month_day_last 值
(函数)
operator==
(C++20)
 比较二个 year_month_weekday 值
(函数)
operator==
(C++20)
 比较二个 year_month_weekday_last 值
(函数)
operator+operator-
(C++20)
 加或减日数和 day ，或求二个 day 间的差
(函数)
operator+operator-
(C++20)
 进行 month 上的算术
(函数)
operator+operator-
(C++20)
 进行 year 上的算术
(函数)
operator+operator-
(C++20)
 在 weekday 上进行算术
(函数)
operator+operator-
(C++20)
 进行 year_month 上的算术
(函数)
operator+operator-
(C++20)
 将 year_month_day 与一定量的年数或月数相加或相减
(函数)
operator+operator-
(C++20)
 将 year_month_day_last 和一定数量的 years 或 months 相加或相减
(函数)
operator+operator-
(C++20)
 将 year_month_weekday 与一定数量的 years 或 months 相加或相减
(函数)
operator+operator-
(C++20)
 将 year_month_weekday_last 与一定数量的 years 或 months 相加或相减
(函数)
operator/
(C++20)
 创建格里高利历日期的约定语法
(函数)
当天时刻
定义于命名空间 std::chrono
is_amis_pmmake12make24
(C++20)
 在 12 时和 24 时格式当天时刻之间翻译
(函数)
时区
定义于命名空间 std::chrono
get_tzdbget_tzdb_listreload_tzdbremote_version
(C++20)
 访问和控制全球时区数据库信息
(函数)
locate_zone
(C++20)
 定位基于其名称的 time_zone
(函数)
operator==operator<=>
(C++20)
 比较二个 time_zone 对象
(函数)
operator==
(C++20)
 比较二个 zoned_time 值
(函数模板)
operator==operator<=>
(C++20)
 比较二个 time_zone_link 对象
(函数)
闰秒
定义于命名空间 std::chrono
get_leap_second_info
(C++20)
 从 utc_time 对象获得闰秒插入信息
(函数模板)
operator==operator<operator<=operator>operator>=operator<=>
(C++20)
 比较二个 leap_second 值或一个 leap_second 值与一个 sys_time
(函数模板)
I/O
定义于命名空间 std::chrono
operator<<
(C++20)
 进行 duration 上的流输出
(函数模板)
operator<<(std::chrono::sys_time)
(C++20)
 进行 sys_time 上的流输出
(函数模板)
operator<<(std::chrono::utc_time)
(C++20)
 进行 utc_time 上的流输出
(函数模板)
operator<<(std::chrono::tai_time)
(C++20)
 进行 tai_time 上的流输出
(函数模板)
operator<<(std::chrono::gps_time)
(C++20)
 进行 gps_time 上的流输出
(函数模板)
operator<<(std::chrono::file_time)
(C++20)
 进行 file_time 上的流输出
(函数模板)
operator<<
(C++20)
 输出 day 到流
(函数模板)
operator<<
(C++20)
 输出 month 到流中
(函数模板)
operator<<
(C++20)
 输出 year 到流
(函数模板)
operator<<
(C++20)
 输出 weekday 到流中
(函数模板)
operator<<
(C++20)
 输出 weekday_indexed 到流中
(函数模板)
operator<<
(C++20)
 输出 weekday_last 到流中
(函数模板)
operator<<
(C++20)
 输出 month_day 到流中
(函数模板)
operator<<
(C++20)
 输出 month_day_last 到流中
(函数模板)
operator<<
(C++20)
 输出 month_weekday 到流中
(函数模板)
operator<<
(C++20)
 输出 month_weekday_last 到流中
(函数模板)
operator<<
(C++20)
 输出 year_month 到流中
(函数模板)
operator<<
(C++20)
 输出 year_month_day 到流中
(函数模板)
operator<<
(C++20)
 输出 year_month_day_last 到流中
(函数模板)
operator<<
(C++20)
 输出 year_month_weekday 到流中
(函数模板)
operator<<
(C++20)
 输出 year_month_weekday_last 到流中
(函数模板)
operator<<
(C++20)
 输出 hh_mm_ss 到流中
(函数模板)
operator<<
(C++20)
 输出 sys_info 到流中
(函数模板)
operator<<
(C++20)
 输出 local_info 对象到流中
(函数模板)
operator<<
(C++20)
 输出 zoned_time 到流中
(函数模板)
from_stream
(C++20)
 按照提供的格式从流分析 day
(函数模板)
from_stream
(C++20)
 按照提供的格式从流分析 month
(函数模板)
from_stream
(C++20)
 按照提供的格式从流分析 year
(函数模板)
from_stream
(C++20)
 按照提供的格式从流分析 weekday
(函数模板)
from_stream
(C++20)
 按照提供的格式从流分析 month_day
(函数模板)
from_stream
(C++20)
 按照提供的格式从流分析 year_month
(函数模板)
from_stream
(C++20)
 按照给定的格式从流分析 year_month_day
(函数模板)
parse
(C++20)
 从流分析 chrono 对象
(函数模板)
字面量
定义于内联命名空间 std::literals::chrono_literals
operator""h
(C++14)
 表示小时的 std::chrono::duration 字面量
(函数)
operator""min
(C++14)
 表示分钟的 std::chrono::duration 字面量
(函数)
operator""s
(C++14)
 表示秒的 std::chrono::duration 字面量
(函数)
operator""ms
(C++14)
 表示毫秒的 std::chrono::duration 字面量
(函数)
operator""us
(C++14)
 表示微秒的 std::chrono::duration 字面量
(函数)
operator""ns
(C++14)
 表示纳秒的 std::chrono::duration 字面量
(函数)
operator""d
(C++20)
 表示月内日期的 std::chrono::day 字面量
(函数)
operator""y
(C++20)
 表示特定年的 std::chrono::year 字面量
(函数)

概要

#include <compare>

namespace std {
  namespace chrono {
    // 类模板 duration
    template<class Rep, class Period = ratio<1>> class duration;

    // 类模板 time_point
    template<class Clock, class Duration = typename Clock::duration> class time_point;
  }

  // common_type 特化
  template<class Rep1, class Period1, class Rep2, class Period2>
    struct common_type<chrono::duration<Rep1, Period1>,
                       chrono::duration<Rep2, Period2>>;

  template<class Clock, class Duration1, class Duration2>
    struct common_type<chrono::time_point<Clock, Duration1>,
                       chrono::time_point<Clock, Duration2>>;

  namespace chrono {
    // 定制特征
    template<class Rep> struct treat_as_floating_point;
    template<class Rep>
      inline constexpr bool treat_as_floating_point_v = treat_as_floating_point<Rep>::value;

    template<class Rep> struct duration_values;

    template<class T> struct is_clock;
    template<class T> inline constexpr bool is_clock_v = is_clock<T>::value;

    // duration 算术
    template<class Rep1, class Period1, class Rep2, class Period2>
      constexpr common_type_t<duration<Rep1, Period1>, duration<Rep2, Period2>>
        operator+(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
    template<class Rep1, class Period1, class Rep2, class Period2>
      constexpr common_type_t<duration<Rep1, Period1>, duration<Rep2, Period2>>
        operator-(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
    template<class Rep1, class Period, class Rep2>
      constexpr duration<common_type_t<Rep1, Rep2>, Period>
        operator*(const duration<Rep1, Period>& d, const Rep2& s);
    template<class Rep1, class Rep2, class Period>
      constexpr duration<common_type_t<Rep1, Rep2>, Period>
        operator*(const Rep1& s, const duration<Rep2, Period>& d);
    template<class Rep1, class Period, class Rep2>
      constexpr duration<common_type_t<Rep1, Rep2>, Period>
        operator/(const duration<Rep1, Period>& d, const Rep2& s);
    template<class Rep1, class Period1, class Rep2, class Period2>
      constexpr common_type_t<Rep1, Rep2>
        operator/(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
    template<class Rep1, class Period, class Rep2>
      constexpr duration<common_type_t<Rep1, Rep2>, Period>
        operator%(const duration<Rep1, Period>& d, const Rep2& s);
    template<class Rep1, class Period1, class Rep2, class Period2>
      constexpr common_type_t<duration<Rep1, Period1>, duration<Rep2, Period2>>
        operator%(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);

    // duration 比较
    template<class Rep1, class Period1, class Rep2, class Period2>
      constexpr bool operator==(const duration<Rep1, Period1>& lhs,
                                const duration<Rep2, Period2>& rhs);
    template<class Rep1, class Period1, class Rep2, class Period2>
      constexpr bool operator< (const duration<Rep1, Period1>& lhs,
                                const duration<Rep2, Period2>& rhs);
    template<class Rep1, class Period1, class Rep2, class Period2>
      constexpr bool operator> (const duration<Rep1, Period1>& lhs,
                                const duration<Rep2, Period2>& rhs);
    template<class Rep1, class Period1, class Rep2, class Period2>
      constexpr bool operator<=(const duration<Rep1, Period1>& lhs,
                                const duration<Rep2, Period2>& rhs);
    template<class Rep1, class Period1, class Rep2, class Period2>
      constexpr bool operator>=(const duration<Rep1, Period1>& lhs,
                                const duration<Rep2, Period2>& rhs);
    template<class Rep1, class Period1, class Rep2, class Period2>
      requires /* 见描述 */
      constexpr auto operator<=>(const duration<Rep1, Period1>& lhs,
                                 const duration<Rep2, Period2>& rhs);

    // 转换
    template<class ToDuration, class Rep, class Period>
      constexpr ToDuration duration_cast(const duration<Rep, Period>& d);
    template<class ToDuration, class Rep, class Period>
      constexpr ToDuration floor(const duration<Rep, Period>& d);
    template<class ToDuration, class Rep, class Period>
      constexpr ToDuration ceil(const duration<Rep, Period>& d);
    template<class ToDuration, class Rep, class Period>
      constexpr ToDuration round(const duration<Rep, Period>& d);

    // duration I/O
    template<class CharT, class Traits, class Rep, class Period>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os,
                   const duration<Rep, Period>& d);
    template<class CharT, class Traits, class Rep, class Period, class Alloc = allocator<CharT>>
      basic_istream<CharT, Traits>&
        from_stream(basic_istream<CharT, Traits>& is, const CharT* fmt,
                    duration<Rep, Period>& d,
                    basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
                    minutes* offset = nullptr);

    // 便利 typedef
    using nanoseconds  = duration</* 至少有 64 位的有符号整数类型 */, nano>;
    using microseconds = duration</* 至少有 55 位的有符号整数类型 */, micro>;
    using milliseconds = duration</* 至少有 45 位的有符号整数类型 */, milli>;
    using seconds      = duration</* 至少有 35 位的有符号整数类型 */>;
    using minutes      = duration</* 至少有 29 位的有符号整数类型 */,
                                  ratio<  60>>;
    using hours        = duration</* 至少有 23 位的有符号整数类型 */,
                                  ratio<3600>>;
    using days         = duration</* 至少有 25 位的有符号整数类型 */,
                                  ratio_multiply<ratio<24>, hours::period>>;
    using weeks        = duration</* 至少有 22 位的有符号整数类型 */,
                                  ratio_multiply<ratio<7>, days::period>>;
    using years        = duration</* 至少有 17 位的有符号整数类型 */,
                                  ratio_multiply<ratio<146097, 400>, days::period>>;
    using months       = duration</* 至少有 20 位的有符号整数类型 */,
                                  ratio_divide<years::period, ratio<12>>>;

    // time_point 算术
    template<class Clock, class Duration1, class Rep2, class Period2>
      constexpr time_point<Clock, common_type_t<Duration1, duration<Rep2, Period2>>>
        operator+(const time_point<Clock, Duration1>& lhs, const duration<Rep2, Period2>& rhs);
    template<class Rep1, class Period1, class Clock, class Duration2>
      constexpr time_point<Clock, common_type_t<duration<Rep1, Period1>, Duration2>>
        operator+(const duration<Rep1, Period1>& lhs, const time_point<Clock, Duration2>& rhs);
    template<class Clock, class Duration1, class Rep2, class Period2>
      constexpr time_point<Clock, common_type_t<Duration1, duration<Rep2, Period2>>>
        operator-(const time_point<Clock, Duration1>& lhs, const duration<Rep2, Period2>& rhs);
    template<class Clock, class Duration1, class Duration2>
      constexpr common_type_t<Duration1, Duration2>
        operator-(const time_point<Clock, Duration1>& lhs,
                  const time_point<Clock, Duration2>& rhs);

    // time_point 比较
    template<class Clock, class Duration1, class Duration2>
       constexpr bool operator==(const time_point<Clock, Duration1>& lhs,
                                 const time_point<Clock, Duration2>& rhs);
    template<class Clock, class Duration1, class Duration2>
       constexpr bool operator< (const time_point<Clock, Duration1>& lhs,
                                 const time_point<Clock, Duration2>& rhs);
    template<class Clock, class Duration1, class Duration2>
       constexpr bool operator> (const time_point<Clock, Duration1>& lhs,
                                 const time_point<Clock, Duration2>& rhs);
    template<class Clock, class Duration1, class Duration2>
       constexpr bool operator<=(const time_point<Clock, Duration1>& lhs,
                                 const time_point<Clock, Duration2>& rhs);
    template<class Clock, class Duration1, class Duration2>
       constexpr bool operator>=(const time_point<Clock, Duration1>& lhs,
                                 const time_point<Clock, Duration2>& rhs);
    template<class Clock, class Duration1, three_way_comparable_with<Duration1> Duration2>
       constexpr auto operator<=>(const time_point<Clock, Duration1>& lhs,
                                  const time_point<Clock, Duration2>& rhs);

    // 转换
    template<class ToDuration, class Clock, class Duration>
      constexpr time_point<Clock, ToDuration>
        time_point_cast(const time_point<Clock, Duration>& t);
    template<class ToDuration, class Clock, class Duration>
      constexpr time_point<Clock, ToDuration> floor(const time_point<Clock, Duration>& tp);
    template<class ToDuration, class Clock, class Duration>
      constexpr time_point<Clock, ToDuration> ceil(const time_point<Clock, Duration>& tp);
    template<class ToDuration, class Clock, class Duration>
      constexpr time_point<Clock, ToDuration> round(const time_point<Clock, Duration>& tp);

    // 特化的算法
    template<class Rep, class Period>
      constexpr duration<Rep, Period> abs(duration<Rep, Period> d);

    // 类 system_clock
    class system_clock;

    template<class Duration>
      using sys_time  = time_point<system_clock, Duration>;
    using sys_seconds = sys_time<seconds>;
    using sys_days    = sys_time<days>;

    template<class CharT, class Traits, class Duration>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const sys_time<Duration>& tp);

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const sys_days& dp);

    template<class CharT, class Traits, class Duration, class Alloc = allocator<CharT>>
      basic_istream<CharT, Traits>&
        from_stream(basic_istream<CharT, Traits>& is, const CharT* fmt,
                    sys_time<Duration>& tp,
                    basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
                    minutes* offset = nullptr);

    // 类 utc_clock
    class utc_clock;

    template<class Duration>
      using utc_time  = time_point<utc_clock, Duration>;
    using utc_seconds = utc_time<seconds>;

    template<class CharT, class Traits, class Duration>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const utc_time<Duration>& t);
    template<class CharT, class Traits, class Duration, class Alloc = allocator<CharT>>
      basic_istream<CharT, Traits>&
        from_stream(basic_istream<CharT, Traits>& is, const CharT* fmt,
                    utc_time<Duration>& tp,
                    basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
                    minutes* offset = nullptr);

    struct leap_second_info;

    template<class Duration>
      leap_second_info get_leap_second_info(const utc_time<Duration>& ut);

    // 类 tai_clock
    class tai_clock;

    template<class Duration>
      using tai_time  = time_point<tai_clock, Duration>;
    using tai_seconds = tai_time<seconds>;

    template<class CharT, class Traits, class Duration>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const tai_time<Duration>& t);
    template<class CharT, class Traits, class Duration, class Alloc = allocator<CharT>>
      basic_istream<CharT, Traits>&
        from_stream(basic_istream<CharT, Traits>& is, const CharT* fmt,
                    tai_time<Duration>& tp,
                    basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
                    minutes* offset = nullptr);

    // 类 gps_clock
    class gps_clock;

    template<class Duration>
      using gps_time  = time_point<gps_clock, Duration>;
    using gps_seconds = gps_time<seconds>;

    template<class CharT, class Traits, class Duration>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const gps_time<Duration>& t);
    template<class CharT, class Traits, class Duration, class Alloc = allocator<CharT>>
      basic_istream<CharT, Traits>&
        from_stream(basic_istream<CharT, Traits>& is, const CharT* fmt,
                    gps_time<Duration>& tp,
                    basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
                    minutes* offset = nullptr);

    // 类型 file_clock
    using file_clock = /* 见描述 */;

    template<class Duration>
      using file_time = time_point<file_clock, Duration>;

    template<class CharT, class Traits, class Duration>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const file_time<Duration>& tp);
    template<class CharT, class Traits, class Duration, class Alloc = allocator<CharT>>
      basic_istream<CharT, Traits>&
        from_stream(basic_istream<CharT, Traits>& is, const CharT* fmt,
                    file_time<Duration>& tp,
                    basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
                    minutes* offset = nullptr);

    // 类 steady_clock
    class steady_clock;

    // 类 high_resolution_clock
    class high_resolution_clock;

    // 本地时间
    struct local_t {};
    template<class Duration>
      using local_time  = time_point<local_t, Duration>;
    using local_seconds = local_time<seconds>;
    using local_days    = local_time<days>;

    template<class CharT, class Traits, class Duration>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const local_time<Duration>& tp);
    template<class CharT, class Traits, class Duration, class Alloc = allocator<CharT>>
      basic_istream<CharT, Traits>&
        from_stream(basic_istream<CharT, Traits>& is, const CharT* fmt,
                    local_time<Duration>& tp,
                    basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
                    minutes* offset = nullptr);

    // time_point 转换
    template<class DestClock, class SourceClock>
      struct clock_time_conversion;

    template<class DestClock, class SourceClock, class Duration>
      auto clock_cast(const time_point<SourceClock, Duration>& t);

    // 类 last_spec
    struct last_spec;

    // 类 day
    class day;

    constexpr bool operator==(const day& x, const day& y) noexcept;
    constexpr strong_ordering operator<=>(const day& x, const day& y) noexcept;

    constexpr day  operator+(const day&  x, const days& y) noexcept;
    constexpr day  operator+(const days& x, const day&  y) noexcept;
    constexpr day  operator-(const day&  x, const days& y) noexcept;
    constexpr days operator-(const day&  x, const day&  y) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const day& d);
    template<class CharT, class Traits, class Alloc = allocator<CharT>>
      basic_istream<CharT, Traits>&
        from_stream(basic_istream<CharT, Traits>& is, const CharT* fmt,
                    day& d, basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
                    minutes* offset = nullptr);

    // 类 month
    class month;

    constexpr bool operator==(const month& x, const month& y) noexcept;
    constexpr strong_ordering operator<=>(const month& x, const month& y) noexcept;

    constexpr month  operator+(const month&  x, const months& y) noexcept;
    constexpr month  operator+(const months& x,  const month& y) noexcept;
    constexpr month  operator-(const month&  x, const months& y) noexcept;
    constexpr months operator-(const month&  x,  const month& y) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const month& m);
    template<class CharT, class Traits, class Alloc = allocator<CharT>>
      basic_istream<CharT, Traits>&
        from_stream(basic_istream<CharT, Traits>& is, const CharT* fmt,
                    month& m, basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
                    minutes* offset = nullptr);

    // 类 year
    class year;

    constexpr bool operator==(const year& x, const year& y) noexcept;
    constexpr strong_ordering operator<=>(const year& x, const year& y) noexcept;

    constexpr year  operator+(const year&  x, const years& y) noexcept;
    constexpr year  operator+(const years& x, const year&  y) noexcept;
    constexpr year  operator-(const year&  x, const years& y) noexcept;
    constexpr years operator-(const year&  x, const year&  y) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const year& y);

    template<class CharT, class Traits, class Alloc = allocator<CharT>>
      basic_istream<CharT, Traits>&
        from_stream(basic_istream<CharT, Traits>& is, const CharT* fmt,
                    year& y, basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
                    minutes* offset = nullptr);

    // 类 weekday
    class weekday;

    constexpr bool operator==(const weekday& x, const weekday& y) noexcept;

    constexpr weekday operator+(const weekday& x, const days&    y) noexcept;
    constexpr weekday operator+(const days&    x, const weekday& y) noexcept;
    constexpr weekday operator-(const weekday& x, const days&    y) noexcept;
    constexpr days    operator-(const weekday& x, const weekday& y) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const weekday& wd);

    template<class CharT, class Traits, class Alloc = allocator<CharT>>
      basic_istream<CharT, Traits>&
        from_stream(basic_istream<CharT, Traits>& is, const CharT* fmt,
                    weekday& wd, basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
                    minutes* offset = nullptr);

    // 类 weekday_indexed
    class weekday_indexed;

    constexpr bool operator==(const weekday_indexed& x, const weekday_indexed& y) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const weekday_indexed& wdi);

    // 类 weekday_last
    class weekday_last;

    constexpr bool operator==(const weekday_last& x, const weekday_last& y) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const weekday_last& wdl);

    // 类 month_day
    class month_day;

    constexpr bool operator==(const month_day& x, const month_day& y) noexcept;
    constexpr strong_ordering operator<=>(const month_day& x, const month_day& y) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const month_day& md);

    template<class CharT, class Traits, class Alloc = allocator<CharT>>
      basic_istream<CharT, Traits>&
        from_stream(basic_istream<CharT, Traits>& is, const CharT* fmt,
                    month_day& md, basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
                    minutes* offset = nullptr);

    // 类 month_day_last
    class month_day_last;

    constexpr bool operator==(const month_day_last& x, const month_day_last& y) noexcept;
    constexpr strong_ordering operator<=>(const month_day_last& x,
                                          const month_day_last& y) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const month_day_last& mdl);

    // 类 month_weekday
    class month_weekday;

    constexpr bool operator==(const month_weekday& x, const month_weekday& y) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const month_weekday& mwd);

    // 类 month_weekday_last
    class month_weekday_last;

    constexpr bool operator==(const month_weekday_last& x, const month_weekday_last& y) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const month_weekday_last& mwdl);

    // 类 year_month
    class year_month;

    constexpr bool operator==(const year_month& x, const year_month& y) noexcept;
    constexpr strong_ordering operator<=>(const year_month& x, const year_month& y) noexcept;

    constexpr year_month operator+(const year_month& ym, const months& dm) noexcept;
    constexpr year_month operator+(const months& dm, const year_month& ym) noexcept;
    constexpr year_month operator-(const year_month& ym, const months& dm) noexcept;
    constexpr months operator-(const year_month& x, const year_month& y) noexcept;
    constexpr year_month operator+(const year_month& ym, const years& dy) noexcept;
    constexpr year_month operator+(const years& dy, const year_month& ym) noexcept;
    constexpr year_month operator-(const year_month& ym, const years& dy) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const year_month& ym);

    template<class CharT, class Traits, class Alloc = allocator<CharT>>
      basic_istream<CharT, Traits>&
        from_stream(basic_istream<CharT, Traits>& is, const CharT* fmt,
                    year_month& ym, basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
                    minutes* offset = nullptr);

    // 类 year_month_day
    class year_month_day;

    constexpr bool operator==(const year_month_day& x, const year_month_day& y) noexcept;
    constexpr strong_ordering operator<=>(const year_month_day& x,
                                          const year_month_day& y) noexcept;

    constexpr year_month_day operator+(const year_month_day& ymd, const months& dm) noexcept;
    constexpr year_month_day operator+(const months& dm, const year_month_day& ymd) noexcept;
    constexpr year_month_day operator+(const year_month_day& ymd, const years& dy) noexcept;
    constexpr year_month_day operator+(const years& dy, const year_month_day& ymd) noexcept;
    constexpr year_month_day operator-(const year_month_day& ymd, const months& dm) noexcept;
    constexpr year_month_day operator-(const year_month_day& ymd, const years& dy) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const year_month_day& ymd);

    template<class CharT, class Traits, class Alloc = allocator<CharT>>
      basic_istream<CharT, Traits>&
        from_stream(basic_istream<CharT, Traits>& is, const CharT* fmt,
                    year_month_day& ymd,
                    basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
                    minutes* offset = nullptr);

    // 类 year_month_day_last
    class year_month_day_last;

    constexpr bool operator==(const year_month_day_last& x,
                              const year_month_day_last& y) noexcept;
    constexpr strong_ordering operator<=>(const year_month_day_last& x,
                                          const year_month_day_last& y) noexcept;

    constexpr year_month_day_last
      operator+(const year_month_day_last& ymdl, const months& dm) noexcept;
    constexpr year_month_day_last
      operator+(const months& dm, const year_month_day_last& ymdl) noexcept;
    constexpr year_month_day_last
      operator+(const year_month_day_last& ymdl, const years& dy) noexcept;
    constexpr year_month_day_last
      operator+(const years& dy, const year_month_day_last& ymdl) noexcept;
    constexpr year_month_day_last
      operator-(const year_month_day_last& ymdl, const months& dm) noexcept;
    constexpr year_month_day_last
      operator-(const year_month_day_last& ymdl, const years& dy) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const year_month_day_last& ymdl);

    // 类 year_month_weekday
    class year_month_weekday;

    constexpr bool operator==(const year_month_weekday& x,
                              const year_month_weekday& y) noexcept;

    constexpr year_month_weekday
      operator+(const year_month_weekday& ymwd, const months& dm) noexcept;
    constexpr year_month_weekday
      operator+(const months& dm, const year_month_weekday& ymwd) noexcept;
    constexpr year_month_weekday
      operator+(const year_month_weekday& ymwd, const years& dy) noexcept;
    constexpr year_month_weekday
      operator+(const years& dy, const year_month_weekday& ymwd) noexcept;
    constexpr year_month_weekday
      operator-(const year_month_weekday& ymwd, const months& dm) noexcept;
    constexpr year_month_weekday
      operator-(const year_month_weekday& ymwd, const years& dy) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const year_month_weekday& ymwdi);

    // 类 year_month_weekday_last
    class year_month_weekday_last;

    constexpr bool operator==(const year_month_weekday_last& x,
                              const year_month_weekday_last& y) noexcept;

    constexpr year_month_weekday_last
      operator+(const year_month_weekday_last& ymwdl, const months& dm) noexcept;
    constexpr year_month_weekday_last
      operator+(const months& dm, const year_month_weekday_last& ymwdl) noexcept;
    constexpr year_month_weekday_last
      operator+(const year_month_weekday_last& ymwdl, const years& dy) noexcept;
    constexpr year_month_weekday_last
      operator+(const years& dy, const year_month_weekday_last& ymwdl) noexcept;
    constexpr year_month_weekday_last
      operator-(const year_month_weekday_last& ymwdl, const months& dm) noexcept;
    constexpr year_month_weekday_last
      operator-(const year_month_weekday_last& ymwdl, const years& dy) noexcept;

    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const year_month_weekday_last& ymwdl);

    // 公历约定语法运算符
    constexpr year_month
      operator/(const year& y, const month& m) noexcept;
    constexpr year_month
      operator/(const year& y, int m) noexcept;
    constexpr month_day
      operator/(const month& m, const day& d) noexcept;
    constexpr month_day
      operator/(const month& m, int d) noexcept;
    constexpr month_day
      operator/(int m, const day& d) noexcept;
    constexpr month_day
      operator/(const day& d, const month& m) noexcept;
    constexpr month_day
      operator/(const day& d, int m) noexcept;
    constexpr month_day_last
      operator/(const month& m, last_spec) noexcept;
    constexpr month_day_last
      operator/(int m, last_spec) noexcept;
    constexpr month_day_last
      operator/(last_spec, const month& m) noexcept;
    constexpr month_day_last
      operator/(last_spec, int m) noexcept;
    constexpr month_weekday
      operator/(const month& m, const weekday_indexed& wdi) noexcept;
    constexpr month_weekday
      operator/(int m, const weekday_indexed& wdi) noexcept;
    constexpr month_weekday
      operator/(const weekday_indexed& wdi, const month& m) noexcept;
    constexpr month_weekday
      operator/(const weekday_indexed& wdi, int m) noexcept;
    constexpr month_weekday_last
      operator/(const month& m, const weekday_last& wdl) noexcept;
    constexpr month_weekday_last
      operator/(int m, const weekday_last& wdl) noexcept;
    constexpr month_weekday_last
      operator/(const weekday_last& wdl, const month& m) noexcept;
    constexpr month_weekday_last
      operator/(const weekday_last& wdl, int m) noexcept;
    constexpr year_month_day
      operator/(const year_month& ym, const day& d) noexcept;
    constexpr year_month_day
      operator/(const year_month& ym, int d) noexcept;
    constexpr year_month_day
      operator/(const year& y, const month_day& md) noexcept;
    constexpr year_month_day
      operator/(int y, const month_day& md) noexcept;
    constexpr year_month_day
      operator/(const month_day& md, const year& y) noexcept;
    constexpr year_month_day
      operator/(const month_day& md, int y) noexcept;
    constexpr year_month_day_last
      operator/(const year_month& ym, last_spec) noexcept;
    constexpr year_month_day_last
      operator/(const year& y, const month_day_last& mdl) noexcept;
    constexpr year_month_day_last
      operator/(int y, const month_day_last& mdl) noexcept;
    constexpr year_month_day_last
      operator/(const month_day_last& mdl, const year& y) noexcept;
    constexpr year_month_day_last
      operator/(const month_day_last& mdl, int y) noexcept;
    constexpr year_month_weekday
      operator/(const year_month& ym, const weekday_indexed& wdi) noexcept;
    constexpr year_month_weekday
      operator/(const year& y, const month_weekday& mwd) noexcept;
    constexpr year_month_weekday
      operator/(int y, const month_weekday& mwd) noexcept;
    constexpr year_month_weekday
      operator/(const month_weekday& mwd, const year& y) noexcept;
    constexpr year_month_weekday
      operator/(const month_weekday& mwd, int y) noexcept;
    constexpr year_month_weekday_last
      operator/(const year_month& ym, const weekday_last& wdl) noexcept;
    constexpr year_month_weekday_last
      operator/(const year& y, const month_weekday_last& mwdl) noexcept;
    constexpr year_month_weekday_last
      operator/(int y, const month_weekday_last& mwdl) noexcept;
    constexpr year_month_weekday_last
      operator/(const month_weekday_last& mwdl, const year& y) noexcept;
    constexpr year_month_weekday_last
      operator/(const month_weekday_last& mwdl, int y) noexcept;

    // 类模板 hh_mm_ss
    template<class Duration> class hh_mm_ss;

    template<class CharT, class Traits, class Duration>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const hh_mm_ss<Duration>& hms);

    // 12/24 时制函数
    constexpr bool is_am(const hours& h) noexcept;
    constexpr bool is_pm(const hours& h) noexcept;
    constexpr hours make12(const hours& h) noexcept;
    constexpr hours make24(const hours& h, bool is_pm) noexcept;

    // 时区数据库
    struct tzdb;
    class tzdb_list;

    // 时区数据库访问
    const tzdb& get_tzdb();
    tzdb_list& get_tzdb_list();
    const time_zone* locate_zone(string_view tz_name);
    const time_zone* current_zone();

    // 远程时区数据库支持
    const tzdb& reload_tzdb();
    string remote_version();

    // 异常类
    class nonexistent_local_time;
    class ambiguous_local_time;

    // 信息类
    struct sys_info;
    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const sys_info& si);

    struct local_info;
    template<class CharT, class Traits>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const local_info& li);

    // 类 time_zone
    enum class choose {earliest, latest};
    class time_zone;

    bool operator==(const time_zone& x, const time_zone& y) noexcept;
    strong_ordering operator<=>(const time_zone& x, const time_zone& y) noexcept;

    // 类模板 zoned_traits
    template<class T> struct zoned_traits;

    // 类模板 zoned_time
    template<class Duration, class TimeZonePtr = const time_zone*> class zoned_time;

    using zoned_seconds = zoned_time<seconds>;

    template<class Duration1, class Duration2, class TimeZonePtr>
      bool operator==(const zoned_time<Duration1, TimeZonePtr>& x,
                      const zoned_time<Duration2, TimeZonePtr>& y);

    template<class CharT, class Traits, class Duration, class TimeZonePtr>
      basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os,
                   const zoned_time<Duration, TimeZonePtr>& t);

    // 闰秒支持
    class leap_second;

    bool operator==(const leap_second& x, const leap_second& y);
    strong_ordering operator<=>(const leap_second& x, const leap_second& y);

    template<class Duration>
      constexpr bool operator==(const leap_second& x, const sys_time<Duration>& y);
    template<class Duration>
      constexpr bool operator< (const leap_second& x, const sys_time<Duration>& y);
    template<class Duration>
      constexpr bool operator< (const sys_time<Duration>& x, const leap_second& y);
    template<class Duration>
      constexpr bool operator> (const leap_second& x, const sys_time<Duration>& y);
    template<class Duration>
      constexpr bool operator> (const sys_time<Duration>& x, const leap_second& y);
    template<class Duration>
      constexpr bool operator<=(const leap_second& x, const sys_time<Duration>& y);
    template<class Duration>
      constexpr bool operator<=(const sys_time<Duration>& x, const leap_second& y);
    template<class Duration>
      constexpr bool operator>=(const leap_second& x, const sys_time<Duration>& y);
    template<class Duration>
      constexpr bool operator>=(const sys_time<Duration>& x, const leap_second& y);
    template<class Duration>
      requires three_way_comparable_with<sys_seconds, sys_time<Duration>>
      constexpr auto operator<=>(const leap_second& x, const sys_time<Duration>& y);

    // 类 time_zone_link
    class time_zone_link;

    bool operator==(const time_zone_link& x, const time_zone_link& y);
    strong_ordering operator<=>(const time_zone_link& x, const time_zone_link& y);

    // formatting
    template<class Duration> struct /*local-time-format-t*/;    // 仅用于阐释
    template<class Duration>
      /*local-time-format-t*/<Duration>
        local_time_format(local_time<Duration> time, const string* abbrev = nullptr,
                          const seconds* offset_sec = nullptr);
  }

  template<class Rep, class Period, class CharT>
    struct formatter<chrono::duration<Rep, Period>, CharT>;
  template<class Duration, class CharT>
    struct formatter<chrono::sys_time<Duration>, CharT>;
  template<class Duration, class CharT>
    struct formatter<chrono::utc_time<Duration>, CharT>;
  template<class Duration, class CharT>
    struct formatter<chrono::tai_time<Duration>, CharT>;
  template<class Duration, class CharT>
    struct formatter<chrono::gps_time<Duration>, CharT>;
  template<class Duration, class CharT>
    struct formatter<chrono::file_time<Duration>, CharT>;
  template<class Duration, class CharT>
    struct formatter<chrono::local_time<Duration>, CharT>;
  template<class Duration, class CharT>
    struct formatter<chrono::/*local-time-format-t*/<Duration>, CharT>;
  template<class CharT> struct formatter<chrono::day, CharT>;
  template<class CharT> struct formatter<chrono::month, CharT>;
  template<class CharT> struct formatter<chrono::year, CharT>;
  template<class CharT> struct formatter<chrono::weekday, CharT>;
  template<class CharT> struct formatter<chrono::weekday_indexed, CharT>;
  template<class CharT> struct formatter<chrono::weekday_last, CharT>;
  template<class CharT> struct formatter<chrono::month_day, CharT>;
  template<class CharT> struct formatter<chrono::month_day_last, CharT>;
  template<class CharT> struct formatter<chrono::month_weekday, CharT>;
  template<class CharT> struct formatter<chrono::month_weekday_last, CharT>;
  template<class CharT> struct formatter<chrono::year_month, CharT>;
  template<class CharT> struct formatter<chrono::year_month_day, CharT>;
  template<class CharT> struct formatter<chrono::year_month_day_last, CharT>;
  template<class CharT> struct formatter<chrono::year_month_weekday, CharT>;
  template<class CharT> struct formatter<chrono::year_month_weekday_last, CharT>;
  template<class Rep, class Period, class CharT>
    struct formatter<chrono::hh_mm_ss<duration<Rep, Period>>, CharT>;
  template<class CharT> struct formatter<chrono::sys_info, CharT>;
  template<class CharT> struct formatter<chrono::local_info, CharT>;
  template<class Duration, class TimeZonePtr, class CharT>
    struct formatter<chrono::zoned_time<Duration, TimeZonePtr>, CharT>;

  namespace chrono {
    // 分析
    template<class charT, class Parsable>
      /* 未指明 */
        parse(const charT* fmt, Parsable& tp);

    template<class CharT, class Traits, class Alloc, class Parsable>
      /* 未指明 */
        parse(const basic_string<CharT, Traits, Alloc>& format, Parsable& tp);

    template<class charT, class traits, class Alloc, class Parsable>
      /* 未指明 */
        parse(const charT* fmt, Parsable& tp,
              basic_string<charT, traits, Alloc>& abbrev);

    template<class CharT, class Traits, class Alloc, class Parsable>
      /* 未指明 */
        parse(const basic_string<CharT, Traits, Alloc>& format, Parsable& tp,
              basic_string<CharT, Traits, Alloc>& abbrev);

    template<class charT, class Parsable>
      /* 未指明 */
        parse(const charT* fmt, Parsable& tp, minutes& offset);

    template<class CharT, class Traits, class Alloc, class Parsable>
      /* 未指明 */
        parse(const basic_string<CharT, Traits, Alloc>& format, Parsable& tp,
              minutes& offset);

    template<class charT, class traits, class Alloc, class Parsable>
      /* 未指明 */
        parse(const charT* fmt, Parsable& tp,
              basic_string<charT, traits, Alloc>& abbrev, minutes& offset);

    template<class CharT, class Traits, class Alloc, class Parsable>
      /* 未指明 */
        parse(const basic_string<CharT, Traits, Alloc>& format, Parsable& tp,
              basic_string<CharT, Traits, Alloc>& abbrev, minutes& offset);

    // 日历常量
    inline constexpr last_spec last{};

    inline constexpr weekday Sunday{0};
    inline constexpr weekday Monday{1};
    inline constexpr weekday Tuesday{2};
    inline constexpr weekday Wednesday{3};
    inline constexpr weekday Thursday{4};
    inline constexpr weekday Friday{5};
    inline constexpr weekday Saturday{6};

    inline constexpr month January{1};
    inline constexpr month February{2};
    inline constexpr month March{3};
    inline constexpr month April{4};
    inline constexpr month May{5};
    inline constexpr month June{6};
    inline constexpr month July{7};
    inline constexpr month August{8};
    inline constexpr month September{9};
    inline constexpr month October{10};
    inline constexpr month November{11};
    inline constexpr month December{12};
  }

  inline namespace literals {
  inline namespace chrono_literals {
    // suffixes for duration literals
    constexpr chrono::hours                    operator""h(unsigned long long);
    constexpr chrono::duration</* 未指明 */,
                               ratio<3600, 1>> operator""h(long double);

    constexpr chrono::minutes                operator""min(unsigned long long);
    constexpr chrono::duration</* 未指明 */,
                               ratio<60, 1>> operator""min(long double);

    constexpr chrono::seconds                     operator""s(unsigned long long);
    constexpr chrono::duration</* 未指明 */> operator""s(long double);

    constexpr chrono::milliseconds                       operator""ms(unsigned long long);
    constexpr chrono::duration</* 未指明 */, milli> operator""ms(long double);

    constexpr chrono::microseconds                       operator""us(unsigned long long);
    constexpr chrono::duration</* 未指明 */, micro> operator""us(long double);

    constexpr chrono::nanoseconds                       operator""ns(unsigned long long);
    constexpr chrono::duration</* 未指明 */, nano> operator""ns(long double);

    // 非成员函数
    constexpr chrono::day  operator""d(unsigned long long d) noexcept;

    // 非成员函数
    constexpr chrono::year operator""y(unsigned long long y) noexcept;
  }
  }

  namespace chrono {
    using namespace literals::chrono_literals;
  }
}

类模板 std::chrono::duration

namespace std::chrono {
  template<class Rep, class Period = ratio<1>>
  class duration {
  public:
    using rep    = Rep;
    using period = typename Period::type;

  private:
    rep rep_;       // 仅用于阐释

  public:
    // 构造/复制/销毁
    constexpr duration() = default;
    template<class Rep2>
      constexpr explicit duration(const Rep2& r);
    template<class Rep2, class Period2>
      constexpr duration(const duration<Rep2, Period2>& d);
    ~duration() = default;
    duration(const duration&) = default;
    duration& operator=(const duration&) = default;

    // 观察器
    constexpr rep count() const;

    // 算术
    constexpr common_type_t<duration> operator+() const;
    constexpr common_type_t<duration> operator-() const;
    constexpr duration& operator++();
    constexpr duration  operator++(int);
    constexpr duration& operator--();
    constexpr duration  operator--(int);

    constexpr duration& operator+=(const duration& d);
    constexpr duration& operator-=(const duration& d);

    constexpr duration& operator*=(const rep& rhs);
    constexpr duration& operator/=(const rep& rhs);
    constexpr duration& operator%=(const rep& rhs);
    constexpr duration& operator%=(const duration& rhs);

    // 特殊值
    static constexpr duration zero() noexcept;
    static constexpr duration min() noexcept;
    static constexpr duration max() noexcept;
  };
}

类模板 std::chrono::time_point

namespace std::chrono {
  template<class Clock, class Duration = typename Clock::duration>
  class time_point {
  public:
    using clock    = Clock;
    using duration = Duration;
    using rep      = typename duration::rep;
    using period   = typename duration::period;

  private:
    duration d_;                                                // 仅用于阐释

  public:
    // 构造
    constexpr time_point();                                     // 拥有纪元值
    constexpr explicit time_point(const duration& d);           // 同 time_point() + d
    template<class Duration2>
      constexpr time_point(const time_point<clock, Duration2>& t);

    // 观察器
    constexpr duration time_since_epoch() const;

    // 算术
    constexpr time_point& operator++();
    constexpr time_point operator++(int);
    constexpr time_point& operator--();
    constexpr time_point operator--(int);
    constexpr time_point& operator+=(const duration& d);
    constexpr time_point& operator-=(const duration& d);

    // 特殊值
    static constexpr time_point min() noexcept;
    static constexpr time_point max() noexcept;
  };
}

类模板 std::common_type 对 std::chrono::duration 的特化

namespace std {
  template<class Rep1, class Period1, class Rep2, class Period2>
    struct common_type<chrono::duration<Rep1, Period1>,
                       chrono::duration<Rep2, Period2>> {
      using type = chrono::duration<common_type_t<Rep1, Rep2>, /* 见描述 */>;
    };
}

类模板 std::common_type 对 std::chrono::time_point 的特化

namespace std {
  template<class Clock, class Duration1, class Duration2>
    struct common_type<chrono::time_point<Clock, Duration1>,
                       chrono::time_point<Clock, Duration2>> {
      using type = chrono::time_point<Clock, common_type_t<Duration1, Duration2>>;
    };
}

类模板 std::chrono::treat_as_floating_point

template<class Rep> struct treat_as_floating_point : is_floating_point<Rep> { };

类模板 std::chrono::duration_values

namespace std::chrono {
  template<class Rep>
    struct duration_values {
    public:
      static constexpr Rep zero() noexcept;
      static constexpr Rep min() noexcept;
      static constexpr Rep max() noexcept;
    };
}

类 std::chrono::system_clock

namespace std::chrono {
  class system_clock {
  public:
    using rep        = /* 见描述 */;
    using period     = ratio</* 未指明 */, /* 未指明 */>;
    using duration   = chrono::duration<rep, period>;
    using time_point = chrono::time_point<system_clock>;
    static constexpr bool is_steady = /* 未指明 */;

    static time_point now() noexcept;

    // 映射到/自 C 类型 time_t
    static time_t      to_time_t  (const time_point& t) noexcept;
    static time_point  from_time_t(time_t t) noexcept;
  };
}

类 std::chrono::utc_clock

namespace std::chrono {
  class utc_clock {
  public:
    using rep                       = /* 有符号算术类型 */;
    using period                    = ratio</* 未指明 */, /* 未指明 */>;
    using duration                  = chrono::duration<rep, period>;
    using time_point                = chrono::time_point<utc_clock>;
    static constexpr bool is_steady = /* 未指明 */;

    static time_point now();

    template<class Duration>
      static sys_time<common_type_t<Duration, seconds>>
        to_sys(const utc_time<Duration>& t);
    template<class Duration>
      static utc_time<common_type_t<Duration, seconds>>
        from_sys(const sys_time<Duration>& t);
  };
}

类 std::chrono::tai_clock

namespace std::chrono {
  class tai_clock {
  public:
    using rep                       = /* 有符号算术类型 */;
    using period                    = ratio</* 未指明 */, /* 未指明 */>;
    using duration                  = chrono::duration<rep, period>;
    using time_point                = chrono::time_point<tai_clock>;
    static constexpr bool is_steady = /* 未指明 */;

    static time_point now();

    template<class Duration>
      static sys_time<common_type_t<Duration, seconds>>
        to_sys(const tai_time<Duration>& t);
    template<class Duration>
      static tai_time<common_type_t<Duration, seconds>>
        from_sys(const sys_time<Duration>& t);
  };
}

类 std::chrono::gps_clock

namespace std::chrono {
  class gps_clock {
  public:
    using rep                       = /* 有符号算术类型 */;
    using period                    = ratio</* 未指明 */, /* 未指明 */>;
    using duration                  = chrono::duration<rep, period>;
    using time_point                = chrono::time_point<gps_clock>;
    static constexpr bool is_steady = /* 未指明 */;

    static time_point now();

    template<class Duration>
      static sys_time<common_type_t<Duration, seconds>>
        to_sys(const gps_time<Duration>& t);
    template<class Duration>
      static gps_time<common_type_t<Duration, seconds>>
        from_sys(const sys_time<Duration>& t);
  };
}

类 std::chrono::steady_clock

namespace std::chrono {
  class steady_clock {
  public:
    using rep        = /* 未指明 */;
    using period     = ratio</* 未指明 */, /* 未指明 */>;
    using duration   = chrono::duration<rep, period>;
    using time_point = chrono::time_point</* 未指明 */, duration>;
    static constexpr bool is_steady = true;

    static time_point now() noexcept;
  };
}

类 std::chrono::high_resolution_clock

namespace std::chrono {
  class high_resolution_clock {
  public:
    using rep        = /* 未指明 */;
    using period     = ratio</* 未指明 */, /* 未指明 */>;
    using duration   = chrono::duration<rep, period>;
    using time_point = chrono::time_point</* 未指明 */, duration>;
    static constexpr bool is_steady = /* 未指明 */;

    static time_point now() noexcept;
  };
}

类模板 std::chrono::clock_time_conversion

namespace std::chrono {
  template<class DestClock, class SourceClock>
  struct clock_time_conversion {};

  template<class Clock>
  struct clock_time_conversion<Clock, Clock> {
    template<class Duration>
      time_point<Clock, Duration>
        operator()(const time_point<Clock, Duration>& t) const;
  };

  template<>
  struct clock_time_conversion<system_clock, system_clock> {
    template<class Duration>
      sys_time<Duration>
        operator()(const sys_time<Duration>& t) const;
  };

  template<>
  struct clock_time_conversion<utc_clock, utc_clock> {
    template<class Duration>
      utc_time<Duration>
        operator()(const utc_time<Duration>& t) const;
  };

  template<>
  struct clock_time_conversion<utc_clock, system_clock> {
    template<class Duration>
      utc_time<common_type_t<Duration, seconds>>
        operator()(const sys_time<Duration>& t) const;
  };

  template<>
  struct clock_time_conversion<system_clock, utc_clock> {
    template<class Duration>
      sys_time<common_type_t<Duration, seconds>>
        operator()(const utc_time<Duration>& t) const;
  };

  template<class SourceClock>
  struct clock_time_conversion<system_clock, SourceClock> {
    template<class Duration>
      auto operator()(const time_point<SourceClock, Duration>& t) const
        -> decltype(SourceClock::to_sys(t));
  };

  template<class DestClock>
  struct clock_time_conversion<DestClock, system_clock> {
    template<class Duration>
      auto operator()(const sys_time<Duration>& t) const
        -> decltype(DestClock::from_sys(t));
  };

  template<class SourceClock>
  struct clock_time_conversion<utc_clock, SourceClock> {
    template<class Duration>
      auto operator()(const time_point<SourceClock, Duration>& t) const
        -> decltype(SourceClock::to_utc(t));
  };

  template<class DestClock>
  struct clock_time_conversion<DestClock, utc_clock> {
    template<class Duration>
      auto operator()(const utc_time<Duration>& t) const
        -> decltype(DestClock::from_utc(t));
  };
}

类 std::chrono::last_spec

namespace std::chrono {
  struct last_spec {
    explicit last_spec() = default;
  };
}

类 std::chrono::day

namespace std::chrono {
  class day {
    unsigned char d_;           // 仅用于阐释
  public:
    day() = default;
    constexpr explicit day(unsigned d) noexcept;

    constexpr day& operator++()    noexcept;
    constexpr day  operator++(int) noexcept;
    constexpr day& operator--()    noexcept;
    constexpr day  operator--(int) noexcept;

    constexpr day& operator+=(const days& d) noexcept;
    constexpr day& operator-=(const days& d) noexcept;

    constexpr explicit operator unsigned() const noexcept;
    constexpr bool ok() const noexcept;
  };
}

类 std::chrono::month

namespace std::chrono {
  class month {
    unsigned char m_;           // 仅用于阐释
  public:
    month() = default;
    constexpr explicit month(unsigned m) noexcept;

    constexpr month& operator++()    noexcept;
    constexpr month  operator++(int) noexcept;
    constexpr month& operator--()    noexcept;
    constexpr month  operator--(int) noexcept;

    constexpr month& operator+=(const months& m) noexcept;
    constexpr month& operator-=(const months& m) noexcept;

    constexpr explicit operator unsigned() const noexcept;
    constexpr bool ok() const noexcept;
  };
}

类 std::chrono::year

namespace std::chrono {
  class year {
    short y_;                   // 仅用于阐释
  public:
    year() = default;
    constexpr explicit year(int y) noexcept;

    constexpr year& operator++()    noexcept;
    constexpr year  operator++(int) noexcept;
    constexpr year& operator--()    noexcept;
    constexpr year  operator--(int) noexcept;

    constexpr year& operator+=(const years& y) noexcept;
    constexpr year& operator-=(const years& y) noexcept;

    constexpr year operator+() const noexcept;
    constexpr year operator-() const noexcept;

    constexpr bool is_leap() const noexcept;

    constexpr explicit operator int() const noexcept;
    constexpr bool ok() const noexcept;

    static constexpr year min() noexcept;
    static constexpr year max() noexcept;
  };
}

类 std::chrono::weekday

namespace std::chrono {
  class weekday {
    unsigned char wd_;          // 仅用于阐释
  public:
    weekday() = default;
    constexpr explicit weekday(unsigned wd) noexcept;
    constexpr weekday(const sys_days& dp) noexcept;
    constexpr explicit weekday(const local_days& dp) noexcept;

    constexpr weekday& operator++()    noexcept;
    constexpr weekday  operator++(int) noexcept;
    constexpr weekday& operator--()    noexcept;
    constexpr weekday  operator--(int) noexcept;

    constexpr weekday& operator+=(const days& d) noexcept;
    constexpr weekday& operator-=(const days& d) noexcept;

    constexpr unsigned c_encoding() const noexcept;
    constexpr unsigned iso_encoding() const noexcept;
    constexpr bool ok() const noexcept;

    constexpr weekday_indexed operator[](unsigned index) const noexcept;
    constexpr weekday_last    operator[](last_spec) const noexcept;
  };
}

类 std::chrono::weekday_indexed

namespace std::chrono {
  class weekday_indexed {
    chrono::weekday  wd_;       // 仅用于阐释
    unsigned char    index_;    // 仅用于阐释

  public:
    weekday_indexed() = default;
    constexpr weekday_indexed(const chrono::weekday& wd, unsigned index) noexcept;

    constexpr chrono::weekday weekday() const noexcept;
    constexpr unsigned        index()   const noexcept;
    constexpr bool ok() const noexcept;
  };
}

类 std::chrono::weekday_last

namespace std::chrono {
  class weekday_last {
    chrono::weekday wd_;                // 仅用于阐释

    public:
    constexpr explicit weekday_last(const chrono::weekday& wd) noexcept;

    constexpr chrono::weekday weekday() const noexcept;
    constexpr bool ok() const noexcept;
  };
}

类 std::chrono::month_day

namespace std::chrono {
  class month_day {
    chrono::month m_;           // 仅用于阐释
    chrono::day   d_;           // 仅用于阐释

  public:
    month_day() = default;
    constexpr month_day(const chrono::month& m, const chrono::day& d) noexcept;

    constexpr chrono::month month() const noexcept;
    constexpr chrono::day   day()   const noexcept;
    constexpr bool ok() const noexcept;
  };
}

类 std::chrono::month_day_last

namespace std::chrono {
  class month_day_last {
    chrono::month m_;                   // 仅用于阐释

  public:
    constexpr explicit month_day_last(const chrono::month& m) noexcept;

    constexpr chrono::month month() const noexcept;
    constexpr bool ok() const noexcept;
  };
}

类 std::chrono::month_weekday

namespace std::chrono {
  class month_weekday {
    chrono::month           m_;         // 仅用于阐释
    chrono::weekday_indexed wdi_;       // 仅用于阐释
  public:
    constexpr month_weekday(const chrono::month& m,
                            const chrono::weekday_indexed& wdi) noexcept;

    constexpr chrono::month           month()           const noexcept;
    constexpr chrono::weekday_indexed weekday_indexed() const noexcept;
    constexpr bool ok() const noexcept;
  };
}

类 std::chrono::month_weekday_last

namespace std::chrono {
  class month_weekday_last {
    chrono::month        m_;    // 仅用于阐释
    chrono::weekday_last wdl_;  // 仅用于阐释
  public:
    constexpr month_weekday_last(const chrono::month& m,
                                 const chrono::weekday_last& wdl) noexcept;

    constexpr chrono::month        month()        const noexcept;
    constexpr chrono::weekday_last weekday_last() const noexcept;
    constexpr bool ok() const noexcept;
  };
}

类 std::chrono::year_month

namespace std::chrono {
  class year_month {
    chrono::year  y_;           // 仅用于阐释
    chrono::month m_;           // 仅用于阐释

  public:
    year_month() = default;
    constexpr year_month(const chrono::year& y, const chrono::month& m) noexcept;

    constexpr chrono::year  year()  const noexcept;
    constexpr chrono::month month() const noexcept;

    constexpr year_month& operator+=(const months& dm) noexcept;
    constexpr year_month& operator-=(const months& dm) noexcept;
    constexpr year_month& operator+=(const years& dy)  noexcept;
    constexpr year_month& operator-=(const years& dy)  noexcept;

    constexpr bool ok() const noexcept;
  };
}

类 std::chrono::year_month_day

namespace std::chrono {
  class year_month_day {
    chrono::year  y_;           // 仅用于阐释
    chrono::month m_;           // 仅用于阐释
    chrono::day   d_;           // 仅用于阐释

  public:
    year_month_day() = default;
    constexpr year_month_day(const chrono::year& y, const chrono::month& m,
                             const chrono::day& d) noexcept;
    constexpr year_month_day(const year_month_day_last& ymdl) noexcept;
    constexpr year_month_day(const sys_days& dp) noexcept;
    constexpr explicit year_month_day(const local_days& dp) noexcept;

    constexpr year_month_day& operator+=(const months& m) noexcept;
    constexpr year_month_day& operator-=(const months& m) noexcept;
    constexpr year_month_day& operator+=(const years& y)  noexcept;
    constexpr year_month_day& operator-=(const years& y)  noexcept;

    constexpr chrono::year  year()  const noexcept;
    constexpr chrono::month month() const noexcept;
    constexpr chrono::day   day()   const noexcept;

    constexpr          operator sys_days()   const noexcept;
    constexpr explicit operator local_days() const noexcept;
    constexpr bool ok() const noexcept;
  };
}

类 std::chrono::year_month_day_last

namespace std::chrono {
  class year_month_day_last {
    chrono::year           y_;          // 仅用于阐释
    chrono::month_day_last mdl_;        // 仅用于阐释

  public:
    constexpr year_month_day_last(const chrono::year& y,
                                  const chrono::month_day_last& mdl) noexcept;

    constexpr year_month_day_last& operator+=(const months& m) noexcept;
    constexpr year_month_day_last& operator-=(const months& m) noexcept;
    constexpr year_month_day_last& operator+=(const years& y)  noexcept;
    constexpr year_month_day_last& operator-=(const years& y)  noexcept;

    constexpr chrono::year           year()           const noexcept;
    constexpr chrono::month          month()          const noexcept;
    constexpr chrono::month_day_last month_day_last() const noexcept;
    constexpr chrono::day            day()            const noexcept;

    constexpr          operator sys_days()   const noexcept;
    constexpr explicit operator local_days() const noexcept;
    constexpr bool ok() const noexcept;
  };
}

类 std::chrono::year_month_weekday

namespace std::chrono {
  class year_month_weekday {
    chrono::year            y_;         // 仅用于阐释
    chrono::month           m_;         // 仅用于阐释
    chrono::weekday_indexed wdi_;       // 仅用于阐释

  public:
    year_month_weekday() = default;
    constexpr year_month_weekday(const chrono::year& y, const chrono::month& m,
                                 const chrono::weekday_indexed& wdi) noexcept;
    constexpr year_month_weekday(const sys_days& dp) noexcept;
    constexpr explicit year_month_weekday(const local_days& dp) noexcept;

    constexpr year_month_weekday& operator+=(const months& m) noexcept;
    constexpr year_month_weekday& operator-=(const months& m) noexcept;
    constexpr year_month_weekday& operator+=(const years& y)  noexcept;
    constexpr year_month_weekday& operator-=(const years& y)  noexcept;

    constexpr chrono::year            year()            const noexcept;
    constexpr chrono::month           month()           const noexcept;
    constexpr chrono::weekday         weekday()         const noexcept;
    constexpr unsigned                index()           const noexcept;
    constexpr chrono::weekday_indexed weekday_indexed() const noexcept;

    constexpr          operator sys_days()   const noexcept;
    constexpr explicit operator local_days() const noexcept;
    constexpr bool ok() const noexcept;
  };
}

类 std::chrono::year_month_weekday_last

namespace std::chrono {
  class year_month_weekday_last {
    chrono::year         y_;    // 仅用于阐释
    chrono::month        m_;    // 仅用于阐释
    chrono::weekday_last wdl_;  // 仅用于阐释

  public:
    constexpr year_month_weekday_last(const chrono::year& y, const chrono::month& m,
                                      const chrono::weekday_last& wdl) noexcept;

    constexpr year_month_weekday_last& operator+=(const months& m) noexcept;
    constexpr year_month_weekday_last& operator-=(const months& m) noexcept;
    constexpr year_month_weekday_last& operator+=(const years& y)  noexcept;
    constexpr year_month_weekday_last& operator-=(const years& y)  noexcept;

    constexpr chrono::year         year()         const noexcept;
    constexpr chrono::month        month()        const noexcept;
    constexpr chrono::weekday      weekday()      const noexcept;
    constexpr chrono::weekday_last weekday_last() const noexcept;

    constexpr          operator sys_days()   const noexcept;
    constexpr explicit operator local_days() const noexcept;
    constexpr bool ok() const noexcept;
  };
}

类模板 std::chrono::hh_mm_ss

namespace std::chrono {
  template<class Duration> class hh_mm_ss {
  public:
    static constexpr unsigned fractional_width = /* 见描述 */;
    using precision                            = /* 见描述 */;

    constexpr hh_mm_ss() noexcept : hh_mm_ss{Duration::zero()} {}
    constexpr explicit hh_mm_ss(Duration d);

    constexpr bool is_negative() const noexcept;
    constexpr chrono::hours hours() const noexcept;
    constexpr chrono::minutes minutes() const noexcept;
    constexpr chrono::seconds seconds() const noexcept;
    constexpr precision subseconds() const noexcept;

    constexpr explicit operator precision() const noexcept;
    constexpr precision to_duration() const noexcept;

  private:
    bool            is_neg;     // 仅用于阐释
    chrono::hours   h;          // 仅用于阐释
    chrono::minutes m;          // 仅用于阐释
    chrono::seconds s;          // 仅用于阐释
    precision       ss;         // 仅用于阐释
  };
}

类 std::chrono::tzdb

namespace std::chrono {
  struct tzdb {
    string                 version;
    vector<time_zone>      zones;
    vector<time_zone_link> links;
    vector<leap_second>    leap_seconds;

    const time_zone* locate_zone(string_view tz_name) const;
    const time_zone* current_zone() const;
  };
}

类 std::chrono::tzdb_list

namespace std::chrono {
  class tzdb_list {
  public:
    tzdb_list(const tzdb_list&) = delete;
    tzdb_list& operator=(const tzdb_list&) = delete;

    // 未指明的额外构造函数

    class const_iterator;

    const tzdb& front() const noexcept;

    const_iterator erase_after(const_iterator p);

    const_iterator begin() const noexcept;
    const_iterator end()   const noexcept;

    const_iterator cbegin() const noexcept;
    const_iterator cend()   const noexcept;
  };
}

类 std::chrono::nonexistent_local_time

namespace std::chrono {
  class nonexistent_local_time : public runtime_error {
  public:
    template<class Duration>
      nonexistent_local_time(const local_time<Duration>& tp, const local_info& i);
  };
}

类 std::chrono::ambiguous_local_time

namespace std::chrono {
  class ambiguous_local_time : public runtime_error {
  public:
    template<class Duration>
      ambiguous_local_time(const local_time<Duration>& tp, const local_info& i);
  };
}

类 std::chrono::sys_info

namespace std::chrono {
  struct sys_info {
    sys_seconds   begin;
    sys_seconds   end;
    seconds       offset;
    minutes       save;
    string        abbrev;
  };
}

类 std::chrono::local_info

namespace std::chrono {
  struct local_info {
    static constexpr int unique      = 0;
    static constexpr int nonexistent = 1;
    static constexpr int ambiguous   = 2;

    int result;
    sys_info first;
    sys_info second;
  };
}

类 std::chrono::time_zone

namespace std::chrono {
  class time_zone {
  public:
    time_zone(time_zone&&) = default;
    time_zone& operator=(time_zone&&) = default;

    // 未指明的额外构造函数

    string_view name() const noexcept;

    template<class Duration> sys_info   get_info(const sys_time<Duration>& st)   const;
    template<class Duration> local_info get_info(const local_time<Duration>& tp) const;

    template<class Duration>
      sys_time<common_type_t<Duration, seconds>>
        to_sys(const local_time<Duration>& tp) const;

    template<class Duration>
      sys_time<common_type_t<Duration, seconds>>
        to_sys(const local_time<Duration>& tp, choose z) const;

    template<class Duration>
      local_time<common_type_t<Duration, seconds>>
        to_local(const sys_time<Duration>& tp) const;
  };
}

类模板 std::chrono::zoned_traits

namespace std::chrono {
  template<class T> struct zoned_traits {};

  template<> struct zoned_traits<const time_zone*> {
    static const time_zone* default_zone();
    static const time_zone* locate_zone(string_view name);
  };
}

类模板 std::chrono::zoned_time

namespace std::chrono {
  template<class Duration, class TimeZonePtr = const time_zone*>
  class zoned_time {
  public:
    using duration = common_type_t<Duration, seconds>;

  private:
    TimeZonePtr        zone_;                   // 仅用于阐释
    sys_time<duration> tp_;                     // 仅用于阐释

    using traits = zoned_traits<TimeZonePtr>;   // 仅用于阐释

  public:
    zoned_time();
    zoned_time(const zoned_time&) = default;
    zoned_time& operator=(const zoned_time&) = default;

    zoned_time(const sys_time<Duration>& st);
    explicit zoned_time(TimeZonePtr z);
    explicit zoned_time(string_view name);

    template<class Duration2>
      zoned_time(const zoned_time<Duration2, TimeZonePtr>& zt);

    zoned_time(TimeZonePtr z,    const sys_time<Duration>& st);
    zoned_time(string_view name, const sys_time<Duration>& st);

    zoned_time(TimeZonePtr z,    const local_time<Duration>& tp);
    zoned_time(string_view name, const local_time<Duration>& tp);
    zoned_time(TimeZonePtr z,    const local_time<Duration>& tp, choose c);
    zoned_time(string_view name, const local_time<Duration>& tp, choose c);

    template<class Duration2, class TimeZonePtr2>
      zoned_time(TimeZonePtr z, const zoned_time<Duration2, TimeZonePtr2>& zt);
    template<class Duration2, class TimeZonePtr2>
      zoned_time(TimeZonePtr z, const zoned_time<Duration2, TimeZonePtr2>& zt, choose);

    template<class Duration2, class TimeZonePtr2>
      zoned_time(string_view name, const zoned_time<Duration2, TimeZonePtr2>& zt);
    template<class Duration2, class TimeZonePtr2>
      zoned_time(string_view name, const zoned_time<Duration2, TimeZonePtr2>& zt, choose);

    zoned_time& operator=(const sys_time<Duration>& st);
    zoned_time& operator=(const local_time<Duration>& ut);

    operator sys_time<duration>() const;
    explicit operator local_time<duration>() const;

    TimeZonePtr          get_time_zone()  const;
    local_time<duration> get_local_time() const;
    sys_time<duration>   get_sys_time()   const;
    sys_info             get_info()       const;
  };

  zoned_time() -> zoned_time<seconds>;

  template<class Duration>
    zoned_time(sys_time<Duration>)
      -> zoned_time<common_type_t<Duration, seconds>>;

  template<class TimeZonePtrOrName>
    using /*time-zone-representation*/ =        // 仅用于阐释
      conditional_t<is_convertible_v<TimeZonePtrOrName, string_view>,
                    const time_zone*,
                    remove_cvref_t<TimeZonePtrOrName>>;

  template<class TimeZonePtrOrName>
    zoned_time(TimeZonePtrOrName&&)
      -> zoned_time<seconds, /*time-zone-representation*/<TimeZonePtrOrName>>;

  template<class TimeZonePtrOrName, class Duration>
    zoned_time(TimeZonePtrOrName&&, sys_time<Duration>)
      -> zoned_time<common_type_t<Duration, seconds>,
                    /*time-zone-representation*/<TimeZonePtrOrName>>;

  template<class TimeZonePtrOrName, class Duration>
    zoned_time(TimeZonePtrOrName&&, local_time<Duration>,
               choose = choose::earliest)
      -> zoned_time<common_type_t<Duration, seconds>,
                    /*time-zone-representation*/<TimeZonePtrOrName>>;

  template<class Duration, class TimeZonePtrOrName, class TimeZonePtr2>
    zoned_time(TimeZonePtrOrName&&, zoned_time<Duration, TimeZonePtr2>,
               choose = choose::earliest)
      -> zoned_time<common_type_t<Duration, seconds>,
                    /*time-zone-representation*/<TimeZonePtrOrName>>;
}

类 std::chrono::leap_second

namespace std::chrono {
  class leap_second {
  public:
    leap_second(const leap_second&)            = default;
    leap_second& operator=(const leap_second&) = default;

    // 未指明的额外构造函数

    constexpr sys_seconds date() const noexcept;
    constexpr seconds value() const noexcept;
  };
}

类 std::chrono::time_zone_link

namespace std::chrono {
  class time_zone_link {
  public:
    time_zone_link(time_zone_link&&)            = default;
    time_zone_link& operator=(time_zone_link&&) = default;

    // 未指明的额外构造函数

    string_view name()   const noexcept;
    string_view target() const noexcept;
  };
}

类模板 local-time-format-t

namespace std::chrono {
  template<class Duration> struct /*local-time-format-t*/ {       // 仅用于阐释
    local_time<Duration> time;                                    // 仅用于阐释
    const string* abbrev;                                         // 仅用于阐释
    const seconds* offset_sec;                                    // 仅用于阐释
  };
}


标准库头文件 <cinttypes>

< cpp‎ | header

此头文件原作为 <inttypes.h> 存在于 C 标准库。

包含
<cstdint>
(C++11)
 定宽整数类型与其他类型的极限

类型
imaxdiv_t
(C++11)
 结构体类型，由 std::imaxdiv 函数返回
(typedef)

函数
abs(std::intmax_t)imaxabs
(C++11)(C++11)
 计算整数值的绝对值（ \(\small{|x|}\)|x| ）
(函数)
div(std::intmax_t)imaxdiv
(C++11)(C++11)
 计算整数除法的商和余数
(函数)
strtoimaxstrtoumax
(C++11)(C++11)
 转换字节字符串为 std::intmax_t 或 std::uintmax_t
(函数)
wcstoimaxwcstoumax
(C++11)(C++11)
 转换宽字符串为 std::intmax_t 或 std::uintmax_t
(函数)

宏
std::fprintf 函数族的格式常量
PRId8PRId16PRId32PRId64PRIdLEAST8PRIdLEAST16PRIdLEAST32PRIdLEAST64PRIdFAST8PRIdFAST16PRIdFAST32PRIdFAST64PRIdMAXPRIdPTR
(C++11)
 格式转换说明符，分别用于输出 std::int8_t、std::int16_t、std::int32_t、std::int64_t、std::int_least8_t、std::int_least16_t、std::int_least32_t、std::int_least64_t、std::int_fast8_t、std::int_fast16_t、std::int_fast32_t、std::int_fast64_t、std::intmax_t、std::intptr_t 类型的有符号十进制整数值，等价于对于 int 的 d
(宏常量)
PRIi8PRIi16PRIi32PRIi64PRIiLEAST8PRIiLEAST16PRIiLEAST32PRIiLEAST64PRIiFAST8PRIiFAST16PRIiFAST32PRIiFAST64PRIiMAXPRIiPTR
(C++11)
 格式转换说明符，分别用于输出 std::int8_t、std::int16_t、std::int32_t、std::int64_t、std::int_least8_t、std::int_least16_t、std::int_least32_t、std::int_least64_t、std::int_fast8_t、std::int_fast16_t、std::int_fast32_t、std::int_fast64_t、std::intmax_t、std::intptr_t 类型的有符号十进制整数值，等价于对于 int 的 i
(宏常量)
PRIu8PRIu16PRIu32PRIu64PRIuLEAST8PRIuLEAST16PRIuLEAST32PRIuLEAST64PRIuFAST8PRIuFAST16PRIuFAST32PRIuFAST64PRIuMAXPRIuPTR
(C++11)
 格式转换说明符，分别用于输出 std::uint8_t、std::uint16_t、std::uint32_t、std::uint64_t、std::uint_least8_t、std::uint_least16_t、std::uint_least32_t、std::uint_least64_t、std::uint_fast8_t、std::uint_fast16_t、std::uint_fast32_t、std::uint_fast64_t、std::uintmax_t、std::uintptr_t 类型的无符号十进制整数值，等价于对于 unsigned int 的 u
(宏常量)
PRIo8PRIo16PRIo32PRIo64PRIoLEAST8PRIoLEAST16PRIoLEAST32PRIoLEAST64PRIoFAST8PRIoFAST16PRIoFAST32PRIoFAST64PRIoMAXPRIoPTR
(C++11)
 格式转换说明符，分别用于输出 std::uint8_t、std::uint16_t、std::uint32_t、std::uint64_t、std::uint_least8_t、std::uint_least16_t、std::uint_least32_t、std::uint_least64_t、std::uint_fast8_t、std::uint_fast16_t、std::uint_fast32_t、std::uint_fast64_t、std::uintmax_t、std::uintptr_t 类型的无符号八进制整数值，等价于对于 unsigned int 的 o
(宏常量)
PRIx8PRIx16PRIx32PRIx64PRIxLEAST8PRIxLEAST16PRIxLEAST32PRIxLEAST64PRIxFAST8PRIxFAST16PRIxFAST32PRIxFAST64PRIxMAXPRIxPTR
(C++11)
 格式转换说明符，分别用于输出 std::uint8_t、std::uint16_t、std::uint32_t、std::uint64_t、std::uint_least8_t、std::uint_least16_t、std::uint_least32_t、std::uint_least64_t、std::uint_fast8_t、std::uint_fast16_t、std::uint_fast32_t、std::uint_fast64_t、std::uintmax_t、std::uintptr_t 类型的无符号小写十六进制整数值，等价于对于 unsigned int 的 x
(宏常量)
PRIX8PRIX16PRIX32PRIX64PRIXLEAST8PRIXLEAST16PRIXLEAST32PRIXLEAST64PRIXFAST8PRIXFAST16PRIXFAST32PRIXFAST64PRIXMAXPRIXPTR
(C++11)
 格式转换说明符，分别用于输出 std::uint8_t、std::uint16_t、std::uint32_t、std::uint64_t、std::uint_least8_t、std::uint_least16_t、std::uint_least32_t、std::uint_least64_t、std::uint_fast8_t、std::uint_fast16_t、std::uint_fast32_t、std::uint_fast64_t、std::uintmax_t、std::uintptr_t 类型的无符号大写十六进制整数值，等价于对于 unsigned int 的 X
(宏常量)
std::fscanf 函数族的格式常量
SCNd8SCNd16SCNd32SCNd64SCNdLEAST8SCNdLEAST16SCNdLEAST32SCNdLEAST64SCNdFAST8SCNdFAST16SCNdFAST32SCNdFAST64SCNdMAXSCNdPTR
(C++11)
 格式转换说明符，分别用于输入 std::int8_t、std::int16_t、std::int32_t、std::int64_t、std::int_least8_t、std::int_least16_t、std::int_least32_t、std::int_least64_t、std::int_fast8_t、std::int_fast16_t、std::int_fast32_t、std::int_fast64_t、std::intmax_t、std::intptr_t 类型的有符号十进制整数值，等价于对于 int 的 d
(宏常量)
SCNi8SCNi16SCNi32SCNi64SCNiLEAST8SCNiLEAST16SCNiLEAST32SCNiLEAST64SCNiFAST8SCNiFAST16SCNiFAST32SCNiFAST64SCNiMAXSCNiPTR
(C++11)
 格式转换说明符，分别用于输入 std::int8_t、std::int16_t、std::int32_t、std::int64_t、std::int_least8_t、std::int_least16_t、std::int_least32_t、std::int_least64_t、std::int_fast8_t、std::int_fast16_t、std::int_fast32_t、std::int_fast64_t、std::intmax_t、std::intptr_t 类型的有符号十进制/八进制/十六进制整数值，等价于对于 int 的 i
(宏常量)
SCNu8SCNu16SCNu32SCNu64SCNuLEAST8SCNuLEAST16SCNuLEAST32SCNuLEAST64SCNuFAST8SCNuFAST16SCNuFAST32SCNuFAST64SCNuMAXSCNuPTR
(C++11)
 格式转换说明符，分别用于输入 std::uint8_t、std::uint16_t、std::uint32_t、std::uint64_t、std::uint_least8_t、std::uint_least16_t、std::uint_least32_t、std::uint_least64_t、std::uint_fast8_t、std::uint_fast16_t、std::uint_fast32_t、std::uint_fast64_t、std::uintmax_t、std::uintptr_t 类型的无符号十进制整数值，等价于对于 unsigned int 的 u
(宏常量)
SCNo8SCNo16SCNo32SCNo64SCNoLEAST8SCNoLEAST16SCNoLEAST32SCNoLEAST64SCNoFAST8SCNoFAST16SCNoFAST32SCNoFAST64SCNoMAXSCNoPTR
(C++11)
 格式转换说明符，分别用于输入 std::uint8_t、std::uint16_t、std::uint32_t、std::uint64_t、std::uint_least8_t、std::uint_least16_t、std::uint_least32_t、std::uint_least64_t、std::uint_fast8_t、std::uint_fast16_t、std::uint_fast32_t、std::uint_fast64_t、std::uintmax_t、std::uintptr_t 类型的无符号八进制整数值，等价于对于 unsigned int 的 o
(宏常量)
SCNx8SCNx16SCNx32SCNx64SCNxLEAST8SCNxLEAST16SCNxLEAST32SCNxLEAST64SCNxFAST8SCNxFAST16SCNxFAST32SCNxFAST64SCNxMAXSCNxPTR
(C++11)
 格式转换说明符，分别用于输入 std::uint8_t、std::uint16_t、std::uint32_t、std::uint64_t、std::uint_least8_t、std::uint_least16_t、std::uint_least32_t、std::uint_least64_t、std::uint_fast8_t、std::uint_fast16_t、std::uint_fast32_t、std::uint_fast64_t、std::uintmax_t、std::uintptr_t 类型的无符号十六进制整数值，等价于对于 unsigned int 的 x
(宏常量)

概要

#include <cstdint>

namespace std {
  using imaxdiv_t = /* 见描述 */;

  intmax_t imaxabs(intmax_t j);
  imaxdiv_t imaxdiv(intmax_t numer, intmax_t denom);
  intmax_t strtoimax(const char* nptr, char** endptr, int base);
  uintmax_t strtoumax(const char* nptr, char** endptr, int base);
  intmax_t wcstoimax(const wchar_t* nptr, wchar_t** endptr, int base);
  uintmax_t wcstoumax(const wchar_t* nptr, wchar_t** endptr, int base);

  intmax_t abs(intmax_t);               // 可选，见描述
  imaxdiv_t div(intmax_t, intmax_t);    // 可选，见描述
}

#define PRIdN /* 见描述 */
#define PRIiN /* 见描述 */
#define PRIoN /* 见描述 */
#define PRIuN /* 见描述 */
#define PRIxN /* 见描述 */
#define PRIXN /* 见描述 */
#define SCNdN /* 见描述 */
#define SCNiN /* 见描述 */
#define SCNoN /* 见描述 */
#define SCNuN /* 见描述 */
#define SCNxN /* 见描述 */
#define PRIdLEASTN /* 见描述 */
#define PRIiLEASTN /* 见描述 */
#define PRIoLEASTN /* 见描述 */
#define PRIuLEASTN /* 见描述 */
#define PRIxLEASTN /* 见描述 */
#define PRIXLEASTN /* 见描述 */
#define SCNdLEASTN /* 见描述 */
#define SCNiLEASTN /* 见描述 */
#define SCNoLEASTN /* 见描述 */
#define SCNuLEASTN /* 见描述 */
#define SCNxLEASTN /* 见描述 */
#define PRIdFASTN /* 见描述 */
#define PRIiFASTN /* 见描述 */
#define PRIoFASTN /* 见描述 */
#define PRIuFASTN /* 见描述 */
#define PRIxFASTN /* 见描述 */
#define PRIXFASTN /* 见描述 */
#define SCNdFASTN /* 见描述 */
#define SCNiFASTN /* 见描述 */
#define SCNoFASTN /* 见描述 */
#define SCNuFASTN /* 见描述 */
#define SCNxFASTN /* 见描述 */
#define PRIdMAX /* 见描述 */
#define PRIiMAX /* 见描述 */
#define PRIoMAX /* 见描述 */
#define PRIuMAX /* 见描述 */
#define PRIxMAX /* 见描述 */
#define PRIXMAX /* 见描述 */
#define SCNdMAX /* 见描述 */
#define SCNiMAX /* 见描述 */
#define SCNoMAX /* 见描述 */
#define SCNuMAX /* 见描述 */
#define SCNxMAX /* 见描述 */
#define PRIdPTR /* 见描述 */
#define PRIiPTR /* 见描述 */
#define PRIoPTR /* 见描述 */
#define PRIuPTR /* 见描述 */
#define PRIxPTR /* 见描述 */
#define PRIXPTR /* 见描述 */
#define SCNdPTR /* 见描述 */
#define SCNiPTR /* 见描述 */
#define SCNoPTR /* 见描述 */
#define SCNuPTR /* 见描述 */
#define SCNxPTR /* 见描述 */


标准库头文件 <ciso646>

< cpp‎ | header

此头文件原作为 <iso646.h> 存在于 C 标准库。

兼容性头文件，在 C 中定义代用运算符表示，而它们在 C++ 中是关键词。

这表明在服从标准的实现中，包含此头文件无效果。

注解

在旧的或非标准编译器中，使用代用运算符表示可能仍需要包含此头文件。

C++20 前，包含 <ciso646> 有时作为一种技巧，用于获得实现特定的库版本宏而不导致其他效果。

C++20 开始，为此目的添加了头文件 <version>。

此头文件于 C++20 中移除。对应的 <iso646.h> 在 C++20 中仍可用。

#include <ciso646>
#ifdef _LIBCPP_VERSION
#error Using LLVM libc++
#elif __GLIBCXX__ // 注意：仅 6.1 或更新的版本在 ciso646 中定义它
#error Using GNU libstdc++
#elif _CPPLIB_VER // 注意：为 Visual Studio 所用
#error Using Dinkumware STL
#else
#error Using an unknown standard library
#endif


标准库头文件 <climits>

< cpp‎ | header

此头文件原作为 <limits.h> 存在于 C 标准库。

此头文件是类型支持库的一部分，特别是它是 C 数值极限接口的一部分。

宏

CHAR_BIT | 字节的位数 (宏常量)
MB_LEN_MAX | 多字节字符的最大字节数 (宏常量)
CHAR_MIN | char 的最小值 (宏常量)
CHAR_MAX | char 的最大值 (宏常量)
SCHAR_MINSHRT_MININT_MINLONG_MINLLONG_MIN (C++11) | 分别为 signed char、short、int、long 及 long long 的最小值 (宏常量)
SCHAR_MAXSHRT_MAXINT_MAXLONG_MAXLLONG_MAX (C++11) | 分别为 signed char、short、int、long 及 long long 的最大值 (宏常量)
UCHAR_MAXUSHRT_MAXUINT_MAXULONG_MAXULLONG_MAX (C++11) | 分别为 unsigned char、unsigned short、unsigned int、 unsigned long 及 unsigned long long 的最大值 (宏常量)

概要

#define CHAR_BIT /* 见定义 */
#define SCHAR_MIN /* 见定义 */
#define SCHAR_MAX /* 见定义 */
#define UCHAR_MAX /* 见定义 */
#define CHAR_MIN /* 见定义 */
#define CHAR_MAX /* 见定义 */
#define MB_LEN_MAX /* 见定义 */
#define SHRT_MIN /* 见定义 */
#define SHRT_MAX /* 见定义 */
#define USHRT_MAX /* 见定义 */
#define INT_MIN /* 见定义 */
#define INT_MAX /* 见定义 */
#define UINT_MAX /* 见定义 */
#define LONG_MIN /* 见定义 */
#define LONG_MAX /* 见定义 */
#define ULONG_MAX /* 见定义 */
#define LLONG_MIN /* 见定义 */
#define LLONG_MAX /* 见定义 */
#define ULLONG_MAX /* 见定义 */


标准库头文件 <clocale>

< cpp‎ | header

此头文件原作为 <locale.h> 存在于 C 标准库。

此头文件是本地化库的一部分。

类型
lconv
 std::localeconv 所返回的格式化细节
(类)

常量
NULL
 实现定义的空指针常量
(宏常量)
LC_ALLLC_COLLATELC_CTYPELC_MONETARYLC_NUMERICLC_TIME
 std::setlocale 所用的本地环境类别
(宏常量)

函数
setlocale
 获取和设置当前 C 本地环境
(函数)
localeconv
 查询当前本地环境的数值和货币格式化细节
(函数)

概要

namespace std {
  struct lconv;

  char* setlocale(int category, const char* locale);
  lconv* localeconv();
}

#define NULL /* 见描述 */
#define LC_ALL /* 见描述 */
#define LC_COLLATE /* 见描述 */
#define LC_CTYPE /* 见描述 */
#define LC_MONETARY /* 见描述 */
#define LC_NUMERIC /* 见描述 */
#define LC_TIME /* 见描述 */

注解

  • NULL 亦定义于下列头文件：
    • <cstring>
    • <ctime>
    • <cstddef>
    • <cstdio>
    • <cwchar>


标准库头文件 <cmath>

< cpp‎ | header

此头文件原作为 <math.h> 存在于 C 标准库。

此头文件是数值库的一部分。

类型
float_t
(C++11)
 至少和 float 一样宽的最高效浮点类型
(typedef)
double_t
(C++11)
 至少和 double 一样宽的最高效浮点类型
(typedef)

宏
HUGE_VALFHUGE_VALHUGE_VALL
(C++11)(C++11)
 分别指出 float、double 和 long double 的上溢值
(宏常量)
INFINITY
(C++11)
 求值为正无穷大或保证使 float 上溢的值
(宏常量)
NAN
(C++11)
 求值为 float 类型的静默 NAN
(宏常量)
math_errhandlingMATH_ERRNOMATH_ERREXCEPT
(C++11)(C++11)(C++11)
 定义常用数学函数所用的错误处理机制
(宏常量)
分类
FP_NORMALFP_SUBNORMALFP_ZEROFP_INFINITEFP_NAN
(C++11)(C++11)(C++11)(C++11)(C++11)
 指示浮点类别
(宏常量)

函数
基本运算
abs(float)fabsfabsffabsl
(C++11)(C++11)
 浮点值的绝对值（ \(\small{|x|}\)|x| ）
(函数)
fmodfmodffmodl
(C++11)(C++11)
 浮点除法运算的余数
(函数)
remainderremainderfremainderl
(C++11)(C++11)(C++11)
 除法运算的有符号余数
(函数)
remquoremquofremquol
(C++11)(C++11)(C++11)
 除法运算的有符号余数和最后三个二进制位
(函数)
fmafmaffmal
(C++11)(C++11)(C++11)
 混合的乘加运算
(函数)
fmaxfmaxffmaxl
(C++11)(C++11)(C++11)
 两个浮点值的较大者
(函数)
fminfminffminl
(C++11)(C++11)(C++11)
 两个浮点值的较小者
(函数)
fdimfdimffdiml
(C++11)(C++11)(C++11)
 两个浮点值的正数差（ \({\small\max{(0, x-y)} }\)max(0, x-y) ）
(函数)
nannanfnanl
(C++11)(C++11)(C++11)
 非数（NaN）
(函数)
线性插值
lerp
(C++20)
 线性插值函数
(函数)
指数函数
expexpfexpl
(C++11)(C++11)
 返回 e 的给定次幂（ \({\small e^x}\)ex ）
(函数)
exp2exp2fexp2l
(C++11)(C++11)(C++11)
 返回 2 的给定次幂（ \({\small 2^x}\)2x ）
(函数)
expm1expm1fexpm1l
(C++11)(C++11)(C++11)
 返回 e 的给定次幂减一（ \({\small e^x-1}\)ex-1 ）
(函数)
loglogflogl
(C++11)(C++11)
 计算自然（以 e 为底）对数（ \({\small \ln{x} }\)ln(x) ）
(函数)
log10log10flog10l
(C++11)(C++11)
 计算常用（以 10 为底）对数（ \({\small \log_{10}{x} }\)log10(x) ）
(函数)
log2log2flog2l
(C++11)(C++11)(C++11)
 给定数值的以 2 为底的对数（ \({\small \log_{2}{x} }\)log2(x) ）
(函数)
log1plog1pflog1pl
(C++11)(C++11)(C++11)
 1 加上给定数值的自然（以 e 为底）对数（ \({\small \ln{(1+x)} }\)ln(1+x) ）
(函数)
幂函数
powpowfpowl
(C++11)(C++11)
 求某数的给定次幂（ \(\small{x^y}\)xy ）
(函数)
sqrtsqrtfsqrtl
(C++11)(C++11)
 计算平方根（ \(\small{\sqrt{x} }\)√x ）
(函数)
cbrtcbrtfcbrtl
(C++11)(C++11)(C++11)
 计算立方根（ \(\small{\sqrt[3]{x} }\)3√x ）
(函数)
hypothypotfhypotl
(C++11)(C++11)(C++11)
 计算两个给定数的平方和的平方根（ \(\scriptsize{\sqrt{x^2+y^2} }\)√x2
+y2
 ）
(函数)
三角函数
sinsinfsinl
(C++11)(C++11)
 计算正弦（ \({\small\sin{x} }\)sin(x) ）
(函数)
coscosfcosl
(C++11)(C++11)
 计算余弦（ \({\small\cos{x} }\)cos(x) ）
(函数)
tantanftanl
(C++11)(C++11)
 计算正切（ \({\small\tan{x} }\)tan(x) ）
(函数)
asinasinfasinl
(C++11)(C++11)
 计算反正弦（ \({\small\arcsin{x} }\)arcsin(x) ）
(函数)
acosacosfacosl
(C++11)(C++11)
 计算反余弦（ \({\small\arccos{x} }\)arccos(x) ）
(函数)
atanatanfatanl
(C++11)(C++11)
 计算反正切（ \({\small\arctan{x} }\)arctan(x) ）
(函数)
atan2atan2fatan2l
(C++11)(C++11)
 反正切，用符号确定象限
(函数)
双曲函数
sinhsinhfsinhl
(C++11)(C++11)
 计算双曲正弦（ \({\small\sinh{x} }\)sinh(x) ）
(函数)
coshcoshfcoshl
(C++11)(C++11)
 计算双曲余弦（ \({\small\cosh{x} }\)cosh(x) ）
(函数)
tanhtanhftanhl
(C++11)(C++11)
 计算双曲正切（ \({\small\tanh{x} }\)tanh(x) ）
(函数)
asinhasinhfasinhl
(C++11)(C++11)(C++11)
 计算反双曲正弦（ \({\small\operatorname{arsinh}{x} }\)arsinh(x) ）
(函数)
acoshacoshfacoshl
(C++11)(C++11)(C++11)
 计算反双曲余弦（ \({\small\operatorname{arcosh}{x} }\)arcosh(x) ）
(函数)
atanhatanhfatanhl
(C++11)(C++11)(C++11)
 计算反双曲正切（ \({\small\operatorname{artanh}{x} }\)artanh(x) ）
(函数)
误差与伽马函数
erferfferfl
(C++11)(C++11)(C++11)
 误差函数
(函数)
erfcerfcferfcl
(C++11)(C++11)(C++11)
 补误差函数
(函数)
tgammatgammaftgammal
(C++11)(C++11)(C++11)
 gamma 函数
(函数)
lgammalgammaflgammal
(C++11)(C++11)(C++11)
 gamma 函数的自然对数
(函数)
临近整数的浮点运算
ceilceilfceill
(C++11)(C++11)
 不小于给定值的最接近整数值
(函数)
floorfloorffloorl
(C++11)(C++11)
 不大于给定值的最接近整数
(函数)
trunctruncftruncl
(C++11)(C++11)(C++11)
 绝对值不大于给定值的最接近整数
(函数)
roundroundfroundllroundlroundflroundlllroundllroundfllroundl
(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)
 最接近整数，中间情况下向远离零舍入
(函数)
nearbyintnearbyintfnearbyintl
(C++11)(C++11)(C++11)
 使用当前舍入模式的最接近整数
(函数)
rintrintfrintllrintlrintflrintlllrintllrintfllrintl
(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)
 使用当前舍入模式的最接近整数
若结果有别则有异常
(函数)
浮点操纵函数
frexpfrexpffrexpl
(C++11)(C++11)
 将数分解为有效数字和 2 的幂次
(函数)
ldexpldexpfldexpl
(C++11)(C++11)
 将数乘以 2 的幂次
(函数)
modfmodffmodfl
(C++11)(C++11)
 分解数为整数和小数部分
(函数)
scalbnscalbnfscalbnlscalblnscalblnfscalblnl
(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)
 将数乘以 FLT_RADIX 的幂次
(函数)
ilogbilogbfilogbl
(C++11)(C++11)(C++11)
 提取数的指数
(函数)
logblogbflogbl
(C++11)(C++11)(C++11)
 提取数的指数
(函数)
nextafternextafterfnextafterlnexttowardnexttowardfnexttowardl
(C++11)(C++11) (C++11)(C++11)(C++11)(C++11)
 趋向给定值的下个可表示浮点值
(函数)
copysigncopysignfcopysignl
(C++11)(C++11)(C++11)
 复制浮点值的符号
(函数)
分类与比较
fpclassify
(C++11)
 归类给定的浮点值
(函数)
isfinite
(C++11)
 检查给定数是否拥有有限值
(函数)
isinf
(C++11)
 检查给定数是否为无限
(函数)
isnan
(C++11)
 检查给定的数是否 NaN
(函数)
isnormal
(C++11)
 检查给定数是否正规
(函数)
signbit
(C++11)
 检查给定数是否为负
(函数)
isgreater
(C++11)
 检查第一个浮点实参是否大于第二个
(函数)
isgreaterequal
(C++11)
 检查第一个浮点实参是否大于或等于第二个
(函数)
isless
(C++11)
 检查第一个浮点实参是否小于第二个
(函数)
islessequal
(C++11)
 检查第一个浮点实参是否小于或等于第二个
(函数)
islessgreater
(C++11)
 检查第一个浮点实参是否小于或大于第二个
(函数)
isunordered
(C++11)
 检查两个浮点值是否无顺序
(函数)
数学特殊函数
assoc_laguerreassoc_laguerrefassoc_laguerrel
(C++17)(C++17)(C++17)
 连带拉盖尔多项式
(函数)
assoc_legendreassoc_legendrefassoc_legendrel
(C++17)(C++17)(C++17)
 连带勒让德多项式
(函数)
betabetafbetal
(C++17)(C++17)(C++17)
 beta 函数
(函数)
comp_ellint_1comp_ellint_1fcomp_ellint_1l
(C++17)(C++17)(C++17)
 第一类（完全）椭圆积分
(函数)
comp_ellint_2comp_ellint_2fcomp_ellint_2l
(C++17)(C++17)(C++17)
 第二类（完全）椭圆积分
(函数)
comp_ellint_3comp_ellint_3fcomp_ellint_3l
(C++17)(C++17)(C++17)
 第三类（完全）椭圆积分
(函数)
cyl_bessel_icyl_bessel_ifcyl_bessel_il
(C++17)(C++17)(C++17)
 规则变形圆柱贝塞尔函数
(函数)
cyl_bessel_jcyl_bessel_jfcyl_bessel_jl
(C++17)(C++17)(C++17)
 （第一类）圆柱贝塞尔函数
(函数)
cyl_bessel_kcyl_bessel_kfcyl_bessel_kl
(C++17)(C++17)(C++17)
 不规则变形圆柱贝塞尔函数
(函数)
cyl_neumanncyl_neumannfcyl_neumannl
(C++17)(C++17)(C++17)
 圆柱诺依曼函数
(函数)
ellint_1ellint_1fellint_1l
(C++17)(C++17)(C++17)
 第一类（不完全）椭圆积分
(函数)
ellint_2ellint_2fellint_2l
(C++17)(C++17)(C++17)
 第二类（不完全）椭圆积分
(函数)
ellint_3ellint_3fellint_3l
(C++17)(C++17)(C++17)
 第三类（不完全）椭圆积分
(函数)
expintexpintfexpintl
(C++17)(C++17)(C++17)
 指数积分
(函数)
hermitehermitefhermitel
(C++17)(C++17)(C++17)
 埃尔米特多项式
(函数)
legendrelegendreflegendrel
(C++17)(C++17)(C++17)
 勒让德多项式
(函数)
laguerrelaguerreflaguerrel
(C++17)(C++17)(C++17)
 拉盖尔多项式
(函数)
riemann_zetariemann_zetafriemann_zetal
(C++17)(C++17)(C++17)
 黎曼 zeta 函数
(函数)
sph_besselsph_besselfsph_bessell
(C++17)(C++17)(C++17)
 （第一类）球面贝塞尔函数
(函数)
sph_legendresph_legendrefsph_legendrel
(C++17)(C++17)(C++17)
 球面连带勒让德函数
(函数)
sph_neumannsph_neumannfsph_neumannl
(C++17)(C++17)(C++17)
 球面诺依曼函数
(函数)

概要

namespace std {
  using float_t = /* 见描述 */;
  using double_t = /* 见描述 */;
}

#define HUGE_VAL /* 见描述 */
#define HUGE_VALF /* 见描述 */
#define HUGE_VALL /* 见描述 */
#define INFINITY /* 见描述 */
#define NAN /* 见描述 */
#define FP_INFINITE /* 见描述 */
#define FP_NAN /* 见描述 */
#define FP_NORMAL /* 见描述 */
#define FP_SUBNORMAL /* 见描述 */
#define FP_ZERO /* 见描述 */
#define FP_FAST_FMA /* 见描述 */
#define FP_FAST_FMAF /* 见描述 */
#define FP_FAST_FMAL /* 见描述 */
#define FP_ILOGB0 /* 见描述 */
#define FP_ILOGBNAN /* 见描述 */
#define MATH_ERRNO /* 见描述 */
#define MATH_ERREXCEPT /* 见描述 */

#define math_errhandling /* 见描述 */

namespace std {
  float acos(float x);
  double acos(double x);
  long double acos(long double x);
  float acosf(float x);
  long double acosl(long double x);

  float asin(float x);
  double asin(double x);
  long double asin(long double x);
  float asinf(float x);
  long double asinl(long double x);

  float atan(float x);
  double atan(double x);
  long double atan(long double x);
  float atanf(float x);
  long double atanl(long double x);

  float atan2(float y, float x);
  double atan2(double y, double x);
  long double atan2(long double y, long double x);
  float atan2f(float y, float x);
  long double atan2l(long double y, long double x);

  float cos(float x);
  double cos(double x);
  long double cos(long double x);
  float cosf(float x);
  long double cosl(long double x);

  float sin(float x);
  double sin(double x);
  long double sin(long double x);
  float sinf(float x);
  long double sinl(long double x);

  float tan(float x);
  double tan(double x);
  long double tan(long double x);
  float tanf(float x);
  long double tanl(long double x);

  float acosh(float x);
  double acosh(double x);
  long double acosh(long double x);
  float acoshf(float x);
  long double acoshl(long double x);

  float asinh(float x);
  double asinh(double x);
  long double asinh(long double x);
  float asinhf(float x);
  long double asinhl(long double x);

  float atanh(float x);
  double atanh(double x);
  long double atanh(long double x);
  float atanhf(float x);
  long double atanhl(long double x);

  float cosh(float x);
  double cosh(double x);
  long double cosh(long double x);
  float coshf(float x);
  long double coshl(long double x);

  float sinh(float x);
  double sinh(double x);
  long double sinh(long double x);
  float sinhf(float x);
  long double sinhl(long double x);

  float tanh(float x);
  double tanh(double x);
  long double tanh(long double x);
  float tanhf(float x);
  long double tanhl(long double x);

  float exp(float x);
  double exp(double x);
  long double exp(long double x);
  float expf(float x);
  long double expl(long double x);

  float exp2(float x);
  double exp2(double x);
  long double exp2(long double x);
  float exp2f(float x);
  long double exp2l(long double x);

  float expm1(float x);
  double expm1(double x);
  long double expm1(long double x);
  float expm1f(float x);
  long double expm1l(long double x);

  float frexp(float value, int* exp);
  double frexp(double value, int* exp);
  long double frexp(long double value, int* exp);
  float frexpf(float value, int* exp);
  long double frexpl(long double value, int* exp);

  int ilogb(float x);
  int ilogb(double x);
  int ilogb(long double x);
  int ilogbf(float x);
  int ilogbl(long double x);

  float ldexp(float x, int exp);
  double ldexp(double x, int exp);
  long double ldexp(long double x, int exp);
  float ldexpf(float x, int exp);
  long double ldexpl(long double x, int exp);

  float log(float x);
  double log(double x);
  long double log(long double x);
  float logf(float x);
  long double logl(long double x);

  float log10(float x);
  double log10(double x);
  long double log10(long double x);
  float log10f(float x);
  long double log10l(long double x);

  float log1p(float x);
  double log1p(double x);
  long double log1p(long double x);
  float log1pf(float x);
  long double log1pl(long double x);

  float log2(float x);
  double log2(double x);
  long double log2(long double x);
  float log2f(float x);
  long double log2l(long double x);

  float logb(float x);
  double logb(double x);
  long double logb(long double x);
  float logbf(float x);
  long double logbl(long double x);

  float modf(float value, float* iptr);
  double modf(double value, double* iptr);
  long double modf(long double value, long double* iptr);
  float modff(float value, float* iptr);
  long double modfl(long double value, long double* iptr);

  float scalbn(float x, int n);
  double scalbn(double x, int n);
  long double scalbn(long double x, int n);
  float scalbnf(float x, int n);
  long double scalbnl(long double x, int n);

  float scalbln(float x, long int n);
  double scalbln(double x, long int n);
  long double scalbln(long double x, long int n);
  float scalblnf(float x, long int n);
  long double scalblnl(long double x, long int n);

  float cbrt(float x);
  double cbrt(double x);
  long double cbrt(long double x);
  float cbrtf(float x);
  long double cbrtl(long double x);

  // 绝对值
  int abs(int j);
  long int abs(long int j);
  long long int abs(long long int j);
  float abs(float j);
  double abs(double j);
  long double abs(long double j);

  float fabs(float x);
  double fabs(double x);
  long double fabs(long double x);
  float fabsf(float x);
  long double fabsl(long double x);

  float hypot(float x, float y);
  double hypot(double x, double y);
  long double hypot(long double x, long double y);
  float hypotf(float x, float y);
  long double hypotl(long double x, long double y);

  // 三维斜边
  float hypot(float x, float y, float z);
  double hypot(double x, double y, double z);
  long double hypot(long double x, long double y, long double z);

  float pow(float x, float y);
  double pow(double x, double y);
  long double pow(long double x, long double y);
  float powf(float x, float y);
  long double powl(long double x, long double y);

  float sqrt(float x);
  double sqrt(double x);
  long double sqrt(long double x);
  float sqrtf(float x);
  long double sqrtl(long double x);

  float erf(float x);
  double erf(double x);
  long double erf(long double x);
  float erff(float x);
  long double erfl(long double x);

  float erfc(float x);
  double erfc(double x);
  long double erfc(long double x);
  float erfcf(float x);
  long double erfcl(long double x);

  float lgamma(float x);
  double lgamma(double x);
  long double lgamma(long double x);
  float lgammaf(float x);
  long double lgammal(long double x);

  float tgamma(float x);
  double tgamma(double x);
  long double tgamma(long double x);
  float tgammaf(float x);
  long double tgammal(long double x);

  float ceil(float x);
  double ceil(double x);
  long double ceil(long double x);
  float ceilf(float x);
  long double ceill(long double x);

  float floor(float x);
  double floor(double x);
  long double floor(long double x);
  float floorf(float x);
  long double floorl(long double x);

  float nearbyint(float x);
  double nearbyint(double x);
  long double nearbyint(long double x);
  float nearbyintf(float x);
  long double nearbyintl(long double x);

  float rint(float x);
  double rint(double x);
  long double rint(long double x);
  float rintf(float x);
  long double rintl(long double x);

  long int lrint(float x);
  long int lrint(double x);
  long int lrint(long double x);
  long int lrintf(float x);
  long int lrintl(long double x);

  long long int llrint(float x);
  long long int llrint(double x);
  long long int llrint(long double x);
  long long int llrintf(float x);
  long long int llrintl(long double x);

  float round(float x);
  double round(double x);
  long double round(long double x);
  float roundf(float x);
  long double roundl(long double x);

  long int lround(float x);
  long int lround(double x);
  long int lround(long double x);
  long int lroundf(float x);
  long int lroundl(long double x);

  long long int llround(float x);
  long long int llround(double x);
  long long int llround(long double x);
  long long int llroundf(float x);
  long long int llroundl(long double x);

  float trunc(float x);
  double trunc(double x);
  long double trunc(long double x);
  float truncf(float x);
  long double truncl(long double x);

  float fmod(float x, float y);
  double fmod(double x, double y);
  long double fmod(long double x, long double y);
  float fmodf(float x, float y);
  long double fmodl(long double x, long double y);

  float remainder(float x, float y);
  double remainder(double x, double y);
  long double remainder(long double x, long double y);
  float remainderf(float x, float y);
  long double remainderl(long double x, long double y);

  float remquo(float x, float y, int* quo);
  double remquo(double x, double y, int* quo);
  long double remquo(long double x, long double y, int* quo);
  float remquof(float x, float y, int* quo);
  long double remquol(long double x, long double y, int* quo);

  float copysign(float x, float y);
  double copysign(double x, double y);
  long double copysign(long double x, long double y);
  float copysignf(float x, float y);
  long double copysignl(long double x, long double y);

  double nan(const char* tagp);
  float nanf(const char* tagp);
  long double nanl(const char* tagp);

  float nextafter(float x, float y);
  double nextafter(double x, double y);
  long double nextafter(long double x, long double y);
  float nextafterf(float x, float y);
  long double nextafterl(long double x, long double y);

  float nexttoward(float x, long double y);
  double nexttoward(double x, long double y);
  long double nexttoward(long double x, long double y);
  float nexttowardf(float x, long double y);
  long double nexttowardl(long double x, long double y);

  float fdim(float x, float y);
  double fdim(double x, double y);
  long double fdim(long double x, long double y);
  float fdimf(float x, float y);
  long double fdiml(long double x, long double y);

  float fmax(float x, float y);
  double fmax(double x, double y);
  long double fmax(long double x, long double y);
  float fmaxf(float x, float y);
  long double fmaxl(long double x, long double y);

  float fmin(float x, float y);
  double fmin(double x, double y);
  long double fmin(long double x, long double y);
  float fminf(float x, float y);
  long double fminl(long double x, long double y);

  float fma(float x, float y, float z);
  double fma(double x, double y, double z);
  long double fma(long double x, long double y, long double z);
  float fmaf(float x, float y, float z);
  long double fmal(long double x, long double y, long double z);

  // 线性插值
  constexpr float lerp(float a, float b, float t) noexcept;
  constexpr double lerp(double a, double b, double t) noexcept;
  constexpr long double lerp(long double a, long double b, long double t) noexcept;

  // 分类/比较函数
  int fpclassify(float x);
  int fpclassify(double x);
  int fpclassify(long double x);

  bool isfinite(float x);
  bool isfinite(double x);
  bool isfinite(long double x);

  bool isinf(float x);
  bool isinf(double x);
  bool isinf(long double x);

  bool isnan(float x);
  bool isnan(double x);
  bool isnan(long double x);

  bool isnormal(float x);
  bool isnormal(double x);
  bool isnormal(long double x);

  bool signbit(float x);
  bool signbit(double x);
  bool signbit(long double x);

  bool isgreater(float x, float y);
  bool isgreater(double x, double y);
  bool isgreater(long double x, long double y);

  bool isgreaterequal(float x, float y);
  bool isgreaterequal(double x, double y);
  bool isgreaterequal(long double x, long double y);

  bool isless(float x, float y);
  bool isless(double x, double y);
  bool isless(long double x, long double y);

  bool islessequal(float x, float y);
  bool islessequal(double x, double y);
  bool islessequal(long double x, long double y);

  bool islessgreater(float x, float y);
  bool islessgreater(double x, double y);
  bool islessgreater(long double x, long double y);

  bool isunordered(float x, float y);
  bool isunordered(double x, double y);
  bool isunordered(long double x, long double y);

  // 数学特殊函数

  // 连带拉盖尔多项式
  double       assoc_laguerre(unsigned n, unsigned m, double x);
  float        assoc_laguerref(unsigned n, unsigned m, float x);
  long double  assoc_laguerrel(unsigned n, unsigned m, long double x);

  // 连带勒让德多项式
  double       assoc_legendre(unsigned l, unsigned m, double x);
  float        assoc_legendref(unsigned l, unsigned m, float x);
  long double  assoc_legendrel(unsigned l, unsigned m, long double x);

  // beta 函数
  double       beta(double x, double y);
  float        betaf(float x, float y);
  long double  betal(long double x, long double y);

  // 第一类完全椭圆积分
  double       comp_ellint_1(double k);
  float        comp_ellint_1f(float k);
  long double  comp_ellint_1l(long double k);

  // 第二类完全椭圆积分
  double       comp_ellint_2(double k);
  float        comp_ellint_2f(float k);
  long double  comp_ellint_2l(long double k);

  // 第三类完全椭圆积分
  double       comp_ellint_3(double k, double nu);
  float        comp_ellint_3f(float k, float nu);
  long double  comp_ellint_3l(long double k, long double nu);

  // 规则变形圆柱贝塞尔函数
  double       cyl_bessel_i(double nu, double x);
  float        cyl_bessel_if(float nu, float x);
  long double  cyl_bessel_il(long double nu, long double x);

  // 第一类圆柱贝塞尔函数
  double       cyl_bessel_j(double nu, double x);
  float        cyl_bessel_jf(float nu, float x);
  long double  cyl_bessel_jl(long double nu, long double x);

  // 不规则变形圆柱贝塞尔函数
  double       cyl_bessel_k(double nu, double x);
  float        cyl_bessel_kf(float nu, float x);
  long double  cyl_bessel_kl(long double nu, long double x);

  // 圆柱诺伊曼函数；
  // 第二类圆柱贝塞尔函数
  double       cyl_neumann(double nu, double x);
  float        cyl_neumannf(float nu, float x);
  long double  cyl_neumannl(long double nu, long double x);

  // 第一类不完全椭圆积分
  double       ellint_1(double k, double phi);
  float        ellint_1f(float k, float phi);
  long double  ellint_1l(long double k, long double phi);

  // 第二类不完全椭圆积分
  double       ellint_2(double k, double phi);
  float        ellint_2f(float k, float phi);
  long double  ellint_2l(long double k, long double phi);

  // 第三类不完全椭圆积分
  double       ellint_3(double k, double nu, double phi);
  float        ellint_3f(float k, float nu, float phi);
  long double  ellint_3l(long double k, long double nu, long double phi);

  // 指数积分
  double       expint(double x);
  float        expintf(float x);
  long double  expintl(long double x);

  // 埃尔米特多项式
  double       hermite(unsigned n, double x);
  float        hermitef(unsigned n, float x);
  long double  hermitel(unsigned n, long double x);

  // 拉盖尔多项式
  double       laguerre(unsigned n, double x);
  float        laguerref(unsigned n, float x);
  long double  laguerrel(unsigned n, long double x);

  // 勒让德多项式
  double       legendre(unsigned l, double x);
  float        legendref(unsigned l, float x);
  long double  legendrel(unsigned l, long double x);

  // 黎曼 zeta 函数
  double       riemann_zeta(double x);
  float        riemann_zetaf(float x);
  long double  riemann_zetal(long double x);

  // 第一类球面贝塞尔函数
  double       sph_bessel(unsigned n, double x);
  float        sph_besself(unsigned n, float x);
  long double  sph_bessell(unsigned n, long double x);

  // 球面连带勒让德函数
  double       sph_legendre(unsigned l, unsigned m, double theta);
  float        sph_legendref(unsigned l, unsigned m, float theta);
  long double  sph_legendrel(unsigned l, unsigned m, long double theta);

  // 球面诺依曼函数；
  // 第二类球面贝塞尔函数
  double       sph_neumann(unsigned n, double x);
  float        sph_neumannf(unsigned n, float x);
  long double  sph_neumannl(unsigned n, long double x);
}


标准库头文件 <codecvt>

< cpp‎ | header

此头文件是本地化库的一部分。

类
codecvt_utf8
(C++11)(C++17 中弃用)
 在 UTF-8 与 UCS2/UCS4 间转换
(类模板)
codecvt_utf16
(C++11)(C++17 中弃用)
 在 UTF-16 与 UCS2/UCS4 间转换
(类模板)
codecvt_utf8_utf16
(C++11)(C++17 中弃用)
 在 UTF-8 与 UTF-16 间转换
(类模板)
codecvt_mode
(C++11)(C++17 中弃用)
 用于改变标准 codecvt 刻面行为的标签
(枚举)

概要

namespace std {
  enum codecvt_mode {
    consume_header = 4,
    generate_header = 2,
    little_endian = 1
  };

  template<class Elem, unsigned long Maxcode = 0x10ffff,
           codecvt_mode Mode = (codecvt_mode)0>
    class codecvt_utf8;

  template<class Elem, unsigned long Maxcode = 0x10ffff,
           codecvt_mode Mode = (codecvt_mode)0>
    class codecvt_utf16;

  template<class Elem, unsigned long Maxcode = 0x10ffff,
           codecvt_mode Mode = (codecvt_mode)0>
    class codecvt_utf8_utf16;
}

类 std::codecvt_utf8

namespace std {
  template<class Elem, unsigned long Maxcode = 0x10ffff,
           codecvt_mode Mode = (codecvt_mode)0>
    class codecvt_utf8 : public codecvt<Elem, char, mbstate_t> {
    public:
      explicit codecvt_utf8(size_t refs = 0);
      ~codecvt_utf8();
    };
}

类 std::codecvt_utf16

namespace std {
  template<class Elem, unsigned long Maxcode = 0x10ffff,
           codecvt_mode Mode = (codecvt_mode)0>
    class codecvt_utf16 : public codecvt<Elem, char, mbstate_t> {
    public:
      explicit codecvt_utf16(size_t refs = 0);
      ~codecvt_utf16();
    };
}

类 std::codecvt_utf8_utf16

namespace std {
  template<class Elem, unsigned long Maxcode = 0x10ffff,
           codecvt_mode Mode = (codecvt_mode)0>
    class codecvt_utf8_utf16 : public codecvt<Elem, char, mbstate_t> {
    public:
      explicit codecvt_utf8_utf16(size_t refs = 0);
      ~codecvt_utf8_utf16();
    };
}


标准库头文件 <compare>

< cpp‎ | header

此头文件是语言支持库的一部分。

概念
three_way_comparablethree_way_comparable_with
(C++20)
 指定运算符 <=> 在给定类型上产生一致的结果
(概念)

类
partial_ordering
(C++20)
 三路比较的结果类型，支持所有 6 种运算符，不可替换，并允许不可比较的值
(类)
weak_ordering
(C++20)
 三路比较的结果类型，支持所有 6 种运算符且不可替换
(类)
strong_ordering
(C++20)
 三路比较的结果类型，支持所有 6 种运算符且可替换
(类)
common_comparison_category
(C++20)
 给定的全部类型都能转换到的最强比较类别
(类模板)
compare_three_way_result
(C++20)
 获得三路比较运算符 <=> 在给定类型上的结果
(类模板)
compare_three_way
(C++20)
 实现 x <=> y 的函数对象
(类)

定制点对象
strong_order
(C++20)
 进行三路比较并产生 std::strong_ordering 类型结果
(定制点对象)
weak_order
(C++20)
 进行三路比较并产生 std::weak_ordering 类型结果
(定制点对象)
partial_order
(C++20)
 进行三路比较并产生 std::partial_ordering 类型结果
(定制点对象)
compare_strong_order_fallback
(C++20)
 进行三路比较并产生 std::strong_ordering 类型的结果，即使 operator<=> 不可用
(定制点对象)
compare_weak_order_fallback
(C++20)
 进行三路比较并产生 std::weak_ordering 类型的结果，即使 operator<=> 不可用
(定制点对象)
compare_partial_order_fallback
(C++20)
 进行三路比较并产生 std::partial_ordering 类型的结果，即使 operator<=> 不可用
(定制点对象)

函数
is_eqis_neqis_ltis_lteqis_gtis_gteq
(C++20)
 具名比较函数
(函数)

概要

namespace std {
  // 比较类别类型
  class partial_ordering;
  class weak_ordering;
  class strong_ordering;

  // 具名比较函数
  constexpr bool is_eq  (partial_ordering cmp) noexcept { return cmp == 0; }
  constexpr bool is_neq (partial_ordering cmp) noexcept { return cmp != 0; }
  constexpr bool is_lt  (partial_ordering cmp) noexcept { return cmp < 0; }
  constexpr bool is_lteq(partial_ordering cmp) noexcept { return cmp <= 0; }
  constexpr bool is_gt  (partial_ordering cmp) noexcept { return cmp > 0; }
  constexpr bool is_gteq(partial_ordering cmp) noexcept { return cmp >= 0; }

  // 共用比较类别类型
  template<class... Ts>
  struct common_comparison_category {
    using type = /* 见描述 */;
  };
  template<class... Ts>
    using common_comparison_category_t = typename common_comparison_category<Ts...>::type;

  // 概念 three_way_comparable
  template<class T, class Cat = partial_ordering>
    concept three_way_comparable = /* 见描述 */;
  template<class T, class U, class Cat = partial_ordering>
    concept three_way_comparable_with = /* 见描述 */;

  // 三路比较的结果
  template<class T, class U = T> struct compare_three_way_result;

  template<class T, class U = T>
    using compare_three_way_result_t = typename compare_three_way_result<T, U>::type;

  // 类 compare_three_way
  struct compare_three_way;

  // 比较算法
  inline namespace /* 未指明 */ {
    inline constexpr /* 未指明 */ strong_order = /* 未指明 */;
    inline constexpr /* 未指明 */ weak_order = /* 未指明 */;
    inline constexpr /* 未指明 */ partial_order = /* 未指明 */;
    inline constexpr /* 未指明 */ compare_strong_order_fallback = /* 未指明 */;
    inline constexpr /* 未指明 */ compare_weak_order_fallback = /* 未指明 */;
    inline constexpr /* 未指明 */ compare_partial_order_fallback = /* 未指明 */;
  }
}

概念 three_way_comparable

namespace std {
  template<class T, class Cat>
    concept __ComparesAs =                // 仅用于阐释
      same_as<common_comparison_category_t<T, Cat>, Cat>;

  template<class T, class U>
    concept __PartiallyOrderedWith =      // 仅用于阐释
      requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {
        { t <  u } -> boolean-testable;
        { t >  u } -> boolean-testable;
        { t <= u } -> boolean-testable;
        { t >= u } -> boolean-testable;
        { u <  t } -> boolean-testable;
        { u >  t } -> boolean-testable;
        { u <= t } -> boolean-testable;
        { u >= t } -> boolean-testable;
      };

  template<class T, class Cat = partial_ordering>
    concept three_way_comparable =
      __WeaklyEqualityComparableWith<T, T> &&
      __PartiallyOrderedWith<T, T> &&
      requires(const remove_reference_t<T>& a, const remove_reference_t<T>& b) {
        { a <=> b } -> __ComparesAs<Cat>;
      };
}

概念 three_way_comparable_with

namespace std {
  template<class T, class U, class Cat = partial_ordering>
    concept three_way_comparable_with =
      __WeaklyEqualityComparableWith<T, U> &&
      __PartiallyOrderedWith<T, U> &&
      three_way_comparable<T, Cat> &&
      three_way_comparable<U, Cat> &&
      common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&> &&
      three_way_comparable<
        common_reference_t<
          const remove_reference_t<T>&, const remove_reference_t<U>&>, Cat> &&
      requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {
        { t <=> u } -> __ComparesAs<Cat>;
        { u <=> t } -> __ComparesAs<Cat>;
      };
}

类 std::partial_ordering

namespace std {
  class partial_ordering {
    int value;          // 仅用于阐释
    bool is_ordered;    // 仅用于阐释

    // 仅用于阐释的构造函数
    constexpr explicit
      partial_ordering(eq v) noexcept :
        value(int(v)), is_ordered(true) {}      // 仅用于阐释
    constexpr explicit
      partial_ordering(ord v) noexcept :
        value(int(v)), is_ordered(true) {}     // 仅用于阐释
    constexpr explicit
      partial_ordering(ncmp v) noexcept :
        value(int(v)), is_ordered(false) {}   // 仅用于阐释

  public:
    // 合法值
    static const partial_ordering less;
    static const partial_ordering equivalent;
    static const partial_ordering greater;
    static const partial_ordering unordered;

    // 比较
    friend constexpr bool operator==(partial_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool
      operator==(partial_ordering v, partial_ordering w) noexcept = default;
    friend constexpr bool operator< (partial_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool operator> (partial_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool operator<=(partial_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool operator>=(partial_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool operator< (/* 未指明 */, partial_ordering v) noexcept;
    friend constexpr bool operator> (/* 未指明 */, partial_ordering v) noexcept;
    friend constexpr bool operator<=(/* 未指明 */, partial_ordering v) noexcept;
    friend constexpr bool operator>=(/* 未指明 */, partial_ordering v) noexcept;
    friend constexpr partial_ordering
      operator<=>(partial_ordering v, /* 未指明 */) noexcept;
    friend constexpr partial_ordering
      operator<=>(/* 未指明 */, partial_ordering v) noexcept;
  };

  // 合法值的定义
  inline constexpr partial_ordering partial_ordering::less(ord::less);
  inline constexpr partial_ordering partial_ordering::equivalent(eq::equivalent);
  inline constexpr partial_ordering partial_ordering::greater(ord::greater);
  inline constexpr partial_ordering partial_ordering::unordered(ncmp::unordered);
}

类 std::weak_ordering

namespace std {
  class weak_ordering {
    int value;  // 仅用于阐释

    // 仅用于阐释的构造函数
    constexpr explicit weak_ordering(eq v) noexcept : value(int(v)) {}  // 仅用于阐释
    constexpr explicit weak_ordering(ord v) noexcept : value(int(v)) {} // 仅用于阐释

  public:
    // 合法值
    static const weak_ordering less;
    static const weak_ordering equivalent;
    static const weak_ordering greater;

    // 转换
    constexpr operator partial_ordering() const noexcept;

    // 比较
    friend constexpr bool operator==(weak_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool operator==(weak_ordering v, weak_ordering w) noexcept = default;
    friend constexpr bool operator< (weak_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool operator> (weak_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool operator<=(weak_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool operator>=(weak_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool operator< (/* 未指明 */, weak_ordering v) noexcept;
    friend constexpr bool operator> (/* 未指明 */, weak_ordering v) noexcept;
    friend constexpr bool operator<=(/* 未指明 */, weak_ordering v) noexcept;
    friend constexpr bool operator>=(/* 未指明 */, weak_ordering v) noexcept;
    friend constexpr weak_ordering
      operator<=>(weak_ordering v, /* 未指明 */) noexcept;
    friend constexpr weak_ordering
      operator<=>(/* 未指明 */, weak_ordering v) noexcept;
  };

  // 合法值的定义
  inline constexpr weak_ordering weak_ordering::less(ord::less);
  inline constexpr weak_ordering weak_ordering::equivalent(eq::equivalent);
  inline constexpr weak_ordering weak_ordering::greater(ord::greater);
}

类 std::strong_ordering

namespace std {
  class strong_ordering {
    int value;  // 仅用于阐释

    // 仅用于阐释的构造函数
    constexpr explicit strong_ordering(eq v) noexcept :
      value(int(v)) {}    // 仅用于阐释
    constexpr explicit strong_ordering(ord v) noexcept :
      value(int(v)) {}   // 仅用于阐释

  public:
    // 合法值
    static const strong_ordering less;
    static const strong_ordering equal;
    static const strong_ordering equivalent;
    static const strong_ordering greater;

    // 转换
    constexpr operator partial_ordering() const noexcept;
    constexpr operator weak_ordering() const noexcept;

    // 比较
    friend constexpr bool operator==(strong_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool
      operator==(strong_ordering v, strong_ordering w) noexcept = default;
    friend constexpr bool operator< (strong_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool operator> (strong_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool operator<=(strong_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool operator>=(strong_ordering v, /* 未指明 */) noexcept;
    friend constexpr bool operator< (/* 未指明 */, strong_ordering v) noexcept;
    friend constexpr bool operator> (/* 未指明 */, strong_ordering v) noexcept;
    friend constexpr bool operator<=(/* 未指明 */, strong_ordering v) noexcept;
    friend constexpr bool operator>=(/* 未指明 */, strong_ordering v) noexcept;
    friend constexpr strong_ordering
      operator<=>(strong_ordering v, /* 未指明 */) noexcept;
    friend constexpr strong_ordering
    operator<=>(/* 未指明 */, strong_ordering v) noexcept;
  };

  // 合法值的定义
  inline constexpr strong_ordering strong_ordering::less(ord::less);
  inline constexpr strong_ordering strong_ordering::equal(eq::equal);
  inline constexpr strong_ordering strong_ordering::equivalent(eq::equivalent);
  inline constexpr strong_ordering strong_ordering::greater(ord::greater);
}

类 std::compare_three_way

namespace std {
  struct compare_three_way {
    template<class T, class U>
    constexpr auto operator()(T&& t, U&& u) const;

    using is_transparent = /* 未指明 */;
  };
}

参阅


标准库头文件 <complex>

< cpp‎ | header

此头文件是数值库的一部分。

类

complex | 复数类型 (类模板)
complex<float>complex<double>complex<long double> | 复数类型 (类模板特化)

函数

运算
operator+operator-
 对复数运用一元运算符
(函数模板)
operator+operator-operator*operator/
 在两个复数，或一个复数与一个标量上进行复数算术运算
(函数模板)
operator==operator!=
(C++20 中移除)
 比较两个复数，或一个复数与一个标量
(函数模板)
operator<<operator>>
 复数的序列化和反序列化
(函数模板)
real
 返回实部
(函数模板)
imag
 返回虚部
(函数模板)
abs(std::complex)
 返回复数的模
(函数模板)
arg
 返回辐角
(函数模板)
norm
 返回模(范数)的平方
(函数模板)
conj
 返回复共轭
(函数模板)
proj
(C++11)
 返回到黎曼球上的投影
(函数模板)
polar
 从模和辐角构造复数
(函数模板)
指数函数
exp(std::complex)
 以 e 为底复数的指数
(函数模板)
log(std::complex)
 沿负实轴切割的复自然对数
(函数模板)
log10(std::complex)
 沿负实轴分割的复常用对数
(函数模板)
幂函数
pow(std::complex)
 复数幂，一或两个参数可为复数
(函数模板)
sqrt(std::complex)
 右半平面范围中的复平方根
(函数模板)
三角函数
sin(std::complex)
 计算复数的正弦（ \({\small\sin{z} }\)sin(z) ）
(函数模板)
cos(std::complex)
 计算复数的余弦（ \({\small\cos{z} }\)cos(z) ）
(函数模板)
tan(std::complex)
 计算复数的正切（ \({\small\tan{z} }\)tan(z) ）
(函数模板)
asin(std::complex)
(C++11)
 计算复数的反正弦（ \({\small\arcsin{z} }\)arcsin(z) ）
(函数模板)
acos(std::complex)
(C++11)
 计算复数的反余弦（ \({\small\arccos{z} }\)arccos(z) ）
(函数模板)
atan(std::complex)
(C++11)
 计算复数的反正切（ \({\small\arctan{z} }\)arctan(z) ）
(函数模板)
双曲函数
sinh(std::complex)
 计算复数的双曲正弦（ \({\small\sinh{z} }\)sinh(z) ）
(函数模板)
cosh(std::complex)
 计算复数的双曲余弦（ \({\small\cosh{z} }\)cosh(z) ）
(函数模板)
tanh(std::complex)
 计算复数的双曲正切（ \({\small\tanh{z} }\)tanh(z) ）
(函数模板)
asinh(std::complex)
(C++11)
 计算复数的反双曲正弦（ \({\small\operatorname{arsinh}{z} }\)arsinh(z) ）
(函数模板)
acosh(std::complex)
(C++11)
 计算复数的反双曲余弦（ \({\small\operatorname{arcosh}{z} }\)arcosh(z) ）
(函数模板)
atanh(std::complex)
(C++11)
 计算复数的反双曲正切（ \({\small\operatorname{artanh}{z} }\)artanh(z) ）
(函数模板)
字面量
operator""ifoperator""ioperator""il
(C++14)
 表示纯虚数的 std::complex 字面量
(函数)

概要

namespace std {

    template<class T> class complex;

    template<> class complex<float>;
    template<> class complex<double>;
    template<> class complex<long double>;

    // 运算符：
    template<class T> constexpr complex<T> operator+(
        const complex<T>&, const complex<T>&);
    template<class T> constexpr complex<T> operator+(const complex<T>&, const T&);
    template<class T> constexpr complex<T> operator+(const T&, const complex<T>&);

    template<class T> constexpr complex<T> operator-(
        const complex<T>&, const complex<T>&);
    template<class T> constexpr complex<T> operator-(const complex<T>&, const T&);
    template<class T> constexpr complex<T> operator-(const T&, const complex<T>&);

    template<class T> constexpr complex<T> operator*(
        const complex<T>&, const complex<T>&);
    template<class T> constexpr complex<T> operator*(const complex<T>&, const T&);
    template<class T> constexpr complex<T> operator*(const T&, const complex<T>&);

    template<class T> constexpr complex<T> operator/(
        const complex<T>&, const complex<T>&);
    template<class T> constexpr complex<T> operator/(const complex<T>&, const T&);
    template<class T> constexpr complex<T> operator/(const T&, const complex<T>&);

    template<class T> constexpr complex<T> operator+(const complex<T>&);
    template<class T> constexpr complex<T> operator-(const complex<T>&);

    template<class T> constexpr bool operator==(
        const complex<T>&, const complex<T>&);
    template<class T> constexpr bool operator==(const complex<T>&, const T&);
    template<class T> constexpr bool operator==(const T&, const complex<T>&);

    template<class T> constexpr bool operator!=(const complex<T>&, const complex<T>&);
    template<class T> constexpr bool operator!=(const complex<T>&, const T&);
    template<class T> constexpr bool operator!=(const T&, const complex<T>&);

    template<class T, class charT, class traits>
    basic_istream<charT, traits>&
    operator>>(basic_istream<charT, traits>&, complex<T>&);

    template<class T, class charT, class traits>
    basic_ostream<charT, traits>&
    operator<<(basic_ostream<charT, traits>&, const complex<T>&);

    // 值：
    template<class T> constexpr T real(const complex<T>&);
    template<class T> constexpr T imag(const complex<T>&);

    template<class T> T abs(const complex<T>&);
    template<class T> T arg(const complex<T>&);
    template<class T> constexpr T norm(const complex<T>&);

    template<class T> constexpr complex<T> conj(const complex<T>&);
    template<class T> complex<T> proj(const complex<T>&);
    template<class T> complex<T> polar(const T&, const T& = 0);

    // 超越函数：
    template<class T> complex<T> acos(const complex<T>&);
    template<class T> complex<T> asin(const complex<T>&);
    template<class T> complex<T> atan(const complex<T>&);

    template<class T> complex<T> acosh(const complex<T>&);
    template<class T> complex<T> asinh(const complex<T>&);
    template<class T> complex<T> atanh(const complex<T>&);

    template<class T> complex<T> cos  (const complex<T>&);
    template<class T> complex<T> cosh (const complex<T>&);
    template<class T> complex<T> exp  (const complex<T>&);
    template<class T> complex<T> log  (const complex<T>&);
    template<class T> complex<T> log10(const complex<T>&);

    template<class T> complex<T> pow(const complex<T>&, const T&);
    template<class T> complex<T> pow(const complex<T>&, const complex<T>&);
    template<class T> complex<T> pow(const T&, const complex<T>&);

    template<class T> complex<T> sin    (const complex<T>&);
    template<class T> complex<T> sinh   (const complex<T>&);
    template<class T> complex<T> sqrt   (const complex<T>&);
    template<class T> complex<T> tan    (const complex<T>&);
    template<class T> complex<T> tanh   (const complex<T>&);

    // 复数字面量：
    inline namespace literals {
    inline namespace complex_literals {
        constexpr complex<long double> operator""il(long double);
        constexpr complex<long double> operator""il(unsigned long long);
        constexpr complex<double> operator""i(long double);
        constexpr complex<double> operator""i(unsigned long long);
        constexpr complex<float> operator""if(long double);
        constexpr complex<float> operator""if(unsigned long long);
    }
    }
}

类 std::complex

template<class T>
class complex {
public:
    typedef T value_type;
    constexpr complex(const T& re = T(), const T& im = T());
    constexpr complex(const complex&);
    template<class X> constexpr complex(const complex<X>&);

    constexpr T real() const;
    constexpr void real(T);
    constexpr T imag() const;
    constexpr void imag(T);

    constexpr complex<T>& operator= (const T&);
    constexpr complex<T>& operator+=(const T&);
    constexpr complex<T>& operator-=(const T&);
    constexpr complex<T>& operator*=(const T&);
    constexpr complex<T>& operator/=(const T&);

    constexpr complex& operator=(const complex&);
    template<class X> constexpr complex<T>& operator= (const complex<X>&);
    template<class X> constexpr complex<T>& operator+=(const complex<X>&);
    template<class X> constexpr complex<T>& operator-=(const complex<X>&);
    template<class X> constexpr complex<T>& operator*=(const complex<X>&);
    template<class X> constexpr complex<T>& operator/=(const complex<X>&);

};

std::complex 特化

template<> class complex<float> {
public:
    typedef float value_type;

    constexpr complex(float re = 0.0f, float im = 0.0f);
    explicit constexpr complex(const complex<double>&);
    explicit constexpr complex(const complex<long double>&);

    constexpr float real() const;
    constexpr void real(float);
    constexpr float imag() const;
    constexpr void imag(float);

    constexpr complex<float>& operator= (float);
    constexpr complex<float>& operator+=(float);
    constexpr complex<float>& operator-=(float);
    constexpr complex<float>& operator*=(float);
    constexpr complex<float>& operator/=(float);

    constexpr complex<float>& operator=(const complex<float>&);
    template<class X> constexpr complex<float>& operator= (const complex<X>&);
    template<class X> constexpr complex<float>& operator+=(const complex<X>&);
    template<class X> constexpr complex<float>& operator-=(const complex<X>&);
    template<class X> constexpr complex<float>& operator*=(const complex<X>&);
    template<class X> constexpr complex<float>& operator/=(const complex<X>&);
};

template<> class complex<double> {
public:
    typedef double value_type;

    constexpr complex(double re = 0.0, double im = 0.0);
    constexpr complex(const complex<float>&);
    explicit constexpr complex(const complex<long double>&);

    constexpr double real() const;
    constexpr void real(double);
    constexpr double imag() const;
    constexpr void imag(double);

    constexpr complex<double>& operator= (double);
    constexpr complex<double>& operator+=(double);
    constexpr complex<double>& operator-=(double);
    constexpr complex<double>& operator*=(double);
    constexpr complex<double>& operator/=(double);

    constexpr complex<double>& operator=(const complex<double>&);
    template<class X> constexpr complex<double>& operator= (const complex<X>&);
    template<class X> constexpr complex<double>& operator+=(const complex<X>&);
    template<class X> constexpr complex<double>& operator-=(const complex<X>&);
    template<class X> constexpr complex<double>& operator*=(const complex<X>&);
    template<class X> constexpr complex<double>& operator/=(const complex<X>&);
};

template<> class complex<long double> {
public:
    typedef long double value_type;

    constexpr complex(long double re = 0.0L, long double im = 0.0L);
    constexpr complex(const complex<float>&);
    constexpr complex(const complex<double>&);

    constexpr long double real() const;
    constexpr void real(long double);
    constexpr long double imag() const;
    constexpr void imag(long double);

    constexpr complex<long double>& operator=(const complex<long double>&);
    constexpr complex<long double>& operator= (long double);
    constexpr complex<long double>& operator+=(long double);
    constexpr complex<long double>& operator-=(long double);
    constexpr complex<long double>& operator*=(long double);
    constexpr complex<long double>& operator/=(long double);

    template<class X> constexpr complex<long double>& operator= (const complex<X>&);
    template<class X> constexpr complex<long double>& operator+=(const complex<X>&);
    template<class X> constexpr complex<long double>& operator-=(const complex<X>&);
    template<class X> constexpr complex<long double>& operator*=(const complex<X>&);
    template<class X> constexpr complex<long double>& operator/=(const complex<X>&);

};


标准库头文件 <concepts>

< cpp‎ | header

此头文件是概念库的一部分。

概念
核心语言概念
same_as
(C++20)
 指定一个类型与另一类型相同
(概念)
derived_from
(C++20)
 指定一个类型派生自另一类型
(概念)
convertible_to
(C++20)
 指定一个类型能隐式转换成另一类型
(概念)
common_reference_with
(C++20)
 指定两个类型共有一个公共引用类型
(概念)
common_with
(C++20)
 指定两个类型共有一个公共类型
(概念)
integral
(C++20)
 指定类型为整型类型
(概念)
signed_integral
(C++20)
 指定类型为有符号的整型类型
(概念)
unsigned_integral
(C++20)
 指定类型为无符号的整型类型
(概念)
floating_point
(C++20)
 指定类型为浮点类型
(概念)
assignable_from
(C++20)
 指定一个类型能从另一类型赋值
(概念)
swappableswappable_with
(C++20)
 指定一个类型能进行交换，或两个类型能彼此交换
(概念)
destructible
(C++20)
 指定能销毁该类型的对象
(概念)
constructible_from
(C++20)
 指定该类型的变量能从一组实参类型进行构造，或绑定到一组实参类型
(概念)
default_initializable
(C++20)
 指定能默认构造一个类型的对象
(概念)
move_constructible
(C++20)
 指定能移动构造一个类型的对象
(概念)
copy_constructible
(C++20)
 指定能复制构造和移动构造一个类型的对象
(概念)
比较概念
equality_comparableequality_comparable_with
(C++20)
 指定运算符 == 为等价关系
(概念)
totally_orderedtotally_ordered_with
(C++20)
 指定比较运算符在该类型上产生全序
(概念)
对象概念
movable
(C++20)
 指定能移动及交换一个类型的对象
(概念)
copyable
(C++20)
 指定能复制、移动及交换一个类型的对象
(概念)
semiregular
(C++20)
 指定能赋值、移动、交换及默认构造一个类型的对象
(概念)
regular
(C++20)
 指定类型为正则，即它既为 semiregular 亦为 equality_comparable
(概念)
可调用概念
invocableregular_invocable
(C++20)
 指定能以给定的一组实参类型调用的可调用类型
(概念)
predicate
(C++20)
 指定可调用类型为布尔谓词
(概念)
relation
(C++20)
 指定可调用类型为二元关系
(概念)
equivalence_relation
(C++20)
 指定 relation 施加等价关系
(概念)
strict_weak_order
(C++20)
 指定一个 relation 所强加的是严格弱序
(概念)

定制点对象
ranges::swap
(C++20)
 交换两个对象的值
(定制点对象)

概要

namespace std {
  // 语言相关概念
  // 概念 same_as
  template<class T, class U>
    concept same_as = /* 见描述 */;

  // 概念 derived_from
  template<class Derived, class Base>
    concept derived_from = /* 见描述 */;

  // 概念 convertible_to
  template<class From, class To>
    concept convertible_to = /* 见描述 */;

  // 概念 common_reference_with
  template<class T, class U>
    concept common_reference_with = /* 见描述 */;

  // 概念 common_with
  template<class T, class U>
    concept common_with = /* 见描述 */;

  // 算术概念
  template<class T>
    concept integral = /* 见描述 */;
  template<class T>
    concept signed_integral = /* 见描述 */;
  template<class T>
    concept unsigned_integral = /* 见描述 */;
  template<class T>
    concept floating_point = /* 见描述 */;

  // 概念 assignable_from
  template<class LHS, class RHS>
    concept assignable_from = /* 见描述 */;

  // 概念 swappable
  namespace ranges {
    inline namespace /* 未指明 */ {
      inline constexpr /* 未指明 */ swap = /* 未指明 */;
    }
  }
  template<class T>
    concept swappable = /* 见描述 */;
  template<class T, class U>
    concept swappable_with = /* 见描述 */;

  // 概念 destructible
  template<class T>
    concept destructible = /* 见描述 */;

  // 概念 constructible_from
  template<class T, class... Args>
    concept constructible_from = /* 见描述 */;

  // 概念 default_initializable
  template<class T>
    concept default_initializable = /* 见描述 */;

  // 概念 move_constructible
  template<class T>
    concept move_constructible = /* 见描述 */;

  // 概念 copy_constructible
  template<class T>
    concept copy_constructible = /* 见描述 */;

  // 比较概念
  // 概念 equality_comparable
  template<class T>
    concept equality_comparable = /* 见描述 */;
  template<class T, class U>
    concept equality_comparable_with = /* 见描述 */;

  // 概念 totally_ordered
  template<class T>
    concept totally_ordered = /* 见描述 */;
  template<class T, class U>
    concept totally_ordered_with = /* 见描述 */;

  // 对象概念
  template<class T>
    concept movable = /* 见描述 */;
  template<class T>
    concept copyable = /* 见描述 */;
  template<class T>
    concept semiregular = /* 见描述 */;
  template<class T>
    concept regular = /* 见描述 */;

  // 可调用概念
  // 概念 invocable
  template<class F, class... Args>
    concept invocable = /* 见描述 */;

  // 概念 regular_invocable
  template<class F, class... Args>
    concept regular_invocable = /* 见描述 */;

  // 概念 predicate
  template<class F, class... Args>
    concept predicate = /* 见描述 */;

  // 概念 relation
  template<class R, class T, class U>
    concept relation = /* 见描述 */;

  // 概念 equivalence_relation
  template<class R, class T, class U>
    concept equivalence_relation = /* 见描述 */;

  // 概念 strict_weak_order
  template<class R, class T, class U>
    concept strict_weak_order = /* 见描述 */;
}

概念 same_as

template<class T, class U>
  concept __SameImpl = is_same_v<T, U>;  // 仅为阐释

template<class T, class U>
  concept same_as = __SameImpl<T, U> && __SameImpl<U, T>;

概念 derived_from

template<class Derived, class Base>
  concept derived_from =
    is_base_of_v<Base, Derived> &&
    is_convertible_v<const volatile Derived*, const volatile Base*>;

概念 convertible_to

template<class From, class To>
  concept convertible_to =
    is_convertible_v<From, To> &&
    requires(From (&f)()) {
      static_cast<To>(f());
    };

概念 common_reference_with

template<class T, class U>
  concept common_reference_with =
    same_as<common_reference_t<T, U>, common_reference_t<U, T>> &&
    convertible_to<T, common_reference_t<T, U>> &&
    convertible_to<U, common_reference_t<T, U>>;

概念 common_with

template<class T, class U>
  concept common_with =
    same_as<common_type_t<T, U>, common_type_t<U, T>> &&
    requires {
      static_cast<common_type_t<T, U>>(declval<T>());
      static_cast<common_type_t<T, U>>(declval<U>());
    } &&
    common_reference_with<
      add_lvalue_reference_t<const T>,
      add_lvalue_reference_t<const U>> &&
    common_reference_with<
      add_lvalue_reference_t<common_type_t<T, U>>,
      common_reference_t<
        add_lvalue_reference_t<const T>,
        add_lvalue_reference_t<const U>>>;

概念 integral

template<class T>
  concept integral = is_integral_v<T>;

概念 signed_integral

template<class T>
  concept signed_integral = integral<T> && is_signed_v<T>;

概念 unsigned_integral

template<class T>
  concept unsigned_integral = integral<T> && !signed_integral<T>;

概念 floating_point

template<class T>
  concept floating_point = is_floating_point_v<T>;

概念 assignable_from

template<class LHS, class RHS>
  concept assignable_from =
    is_lvalue_reference_v<LHS> &&
    common_reference_with<
      const remove_reference_t<LHS>&,
      const remove_reference_t<RHS>&> &&
    requires(LHS lhs, RHS&& rhs) {
      { lhs = std::forward<RHS>(rhs) } -> same_as<LHS>;

概念 swappable

template<class T>
  concept swappable = requires(T& a, T& b) { ranges::swap(a, b); };

概念 swappable_with

template<class T, class U>
  concept swappable_with =
    common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&> &&
    requires(T&& t, U&& u) {
      ranges::swap(std::forward<T>(t), std::forward<T>(t));
      ranges::swap(std::forward<U>(u), std::forward<U>(u));
      ranges::swap(std::forward<T>(t), std::forward<U>(u));
      ranges::swap(std::forward<U>(u), std::forward<T>(t));
    };

概念 destructible

template<class T>
  concept destructible = is_nothrow_destructible_v<T>;

概念 constructible_from

template<class T, class... Args>
  concept constructible_from = destructible<T> && is_constructible_v<T, Args...>;

概念 default_initializable

template<class T>
  inline constexpr bool __is_default_initializable = /* 见描述 */;  // 仅用于阐释

template<class T>
  concept default_initializable = constructible_from<T> &&
                                  requires{ T{}; } &&
                                  __is_default_initializable<T>;

概念 move_constructible

template<class T>
  concept move_constructible = constructible_from<T, T> && convertible_to<T, T>;

概念 copy_constructible

template<class T>
  concept copy_constructible =
    move_constructible<T> &&
    constructible_from<T, T&> && convertible_to<T&, T> &&
    constructible_from<T, const T&> && convertible_to<const T&, T> &&
    constructible_from<T, const T> && convertible_to<const T, T>;

概念 equality_comparable

template<class T, class U>
  concept __WeaklyEqualityComparableWith = // 仅为阐释
    requires(const remove_reference_t<T>& t,
             const remove_reference_t<U>& u) {
      { t == u } -> boolean-testable;
      { t != u } -> boolean-testable;
      { u == t } -> boolean-testable;
      { u != t } -> boolean-testable;
    };

template<class T>
  concept equality_comparable = __WeaklyEqualityComparableWith<T, T>;

概念 equality_comparable_with

template<class T, class U>
  concept equality_comparable_with =
    equality_comparable<T> && equality_comparable<U> &&
    common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&> &&
    equality_comparable<
      common_reference_t<
        const remove_reference_t<T>&,
        const remove_reference_t<U>&>> &&
    __WeaklyEqualityComparableWith<T, U>;

概念 totally_ordered

template<class T>
  concept totally_ordered =
    equality_comparable<T> &&
    requires(const remove_reference_t<T>& a,
             const remove_reference_t<T>& b) {
      { a <  b } -> boolean-testable;
      { a >  b } -> boolean-testable;
      { a <= b } -> boolean-testable;
      { a >= b } -> boolean-testable;
    };

概念 totally_ordered_with

template<class T, class U>
  concept totally_ordered_with =
    totally_ordered<T> && totally_ordered<U> &&
    common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&> &&
    totally_ordered<
      common_reference_t<
        const remove_reference_t<T>&,
        const remove_reference_t<U>&>> &&
    equality_comparable_with<T, U> &&
    requires(const remove_reference_t<T>& t,
             const remove_reference_t<U>& u) {
      { t <  u } -> boolean-testable;
      { t >  u } -> boolean-testable;
      { t <= u } -> boolean-testable;
      { t >= u } -> boolean-testable;
      { u <  t } -> boolean-testable;
      { u >  t } -> boolean-testable;
      { u <= t } -> boolean-testable;
      { u >= t } -> boolean-testable;
    };

概念 movable

template<class T>
  concept movable = is_object_v<T> && move_constructible<T> &&
                    assignable_from<T&, T> && swappable<T>;

概念 copyable

template<class T>
  concept copyable = copy_constructible<T> && movable<T> && assignable_from<T&, T&> &&
                     assignable_from<T&, const T&> && assignable_from<T&, const T>;

概念 semiregular

template<class T>
  concept semiregular = copyable<T> && default_initializable<T>;

概念 regular

template<class T>
  concept regular = semiregular<T> && equality_comparable<T>;

概念 invocable

template<class F, class... Args>
  concept invocable = requires(F&& f, Args&&... args) {
    invoke(std::forward<F>(f), std::forward<Args>(args)...);
      // 不要求保持相等性
  };

概念 regular_invocable

template<class F, class... Args>
  concept regular_invocable = invocable<F, Args...>;

概念 predicate

template<class F, class... Args>
  concept predicate =
    regular_invocable<F, Args...> && boolean-testable<invoke_result_t<F, Args...>>;

概念 relation

template<class R, class T, class U>
  concept relation =
    predicate<R, T, T> && predicate<R, U, U> &&
    predicate<R, T, U> && predicate<R, U, T>;

概念 equivalence_relation

template<class R, class T, class U>
  concept equivalence_relation = relation<R, T, U>;

概念 strict_weak_order

template<class R, class T, class U>
  concept strict_weak_order = relation<R, T, U>;


标准库头文件 <condition_variable>

< cpp‎ | header

此头文件是线程支持库的一部分。

类
condition_variable
(C++11)
 提供与 std::unique_lock 关联的条件变量
(类)
condition_variable_any
(C++11)
 提供与任何锁类型关联的条件变量
(类)
cv_status
(C++11)
 列出条件变量上定时等待的可能结果
(枚举)

函数
notify_all_at_thread_exit
(C++11)
 安排到在此线程完全结束时对 notify_all 的调用
(函数)

概要

namespace std {
  class condition_variable;
  class condition_variable_any;

  void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);

  enum class cv_status { no_timeout, timeout };
}

类 std::condition_variable

namespace std {
  class condition_variable {
  public:
    condition_variable();
    ~condition_variable();

    condition_variable(const condition_variable&) = delete;
    condition_variable& operator=(const condition_variable&) = delete;

    void notify_one() noexcept;
    void notify_all() noexcept;
    void wait(unique_lock<mutex>& lock);
    template<class Pred>
      void wait(unique_lock<mutex>& lock, Pred pred);
    template<class Clock, class Duration>
      cv_status wait_until(unique_lock<mutex>& lock,
                           const chrono::time_point<Clock, Duration>& abs_time);
    template<class Clock, class Duration, class Pred>
      bool wait_until(unique_lock<mutex>& lock,
                      const chrono::time_point<Clock, Duration>& abs_time, Pred pred);
    template<class Rep, class Period>
      cv_status wait_for(unique_lock<mutex>& lock,
                         const chrono::duration<Rep, Period>& rel_time);
    template<class Rep, class Period, class Pred>
      bool wait_for(unique_lock<mutex>& lock,
                    const chrono::duration<Rep, Period>& rel_time, Pred pred);

    using native_handle_type = /* 由实现定义 */;
    native_handle_type native_handle();
  };
}

类 std::condition_variable_any

namespace std {
  class condition_variable_any {
  public:
    condition_variable_any();
    ~condition_variable_any();

    condition_variable_any(const condition_variable_any&) = delete;
    condition_variable_any& operator=(const condition_variable_any&) = delete;

    void notify_one() noexcept;
    void notify_all() noexcept;

    // 不可中断等待
    template<class Lock>
      void wait(Lock& lock);
    template<class Lock, class Pred>
      void wait(Lock& lock, Pred pred);

    template<class Lock, class Clock, class Duration>
      cv_status wait_until(Lock& lock,
                           const chrono::time_point<Clock, Duration>& abs_time);
    template<class Lock, class Clock, class Duration, class Pred>
      bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time,
                      Pred pred);
    template<class Lock, class Rep, class Period>
      cv_status wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time);
    template<class Lock, class Rep, class Period, class Pred>
      bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Pred pred);

    // 可中断等待
    template<class Lock, class Pred>
      bool wait(Lock& lock, stop_token stoken, Pred pred);
    template<class Lock, class Clock, class Duration, class Pred>
      bool wait_until(Lock& lock, stop_token stoken,
                      const chrono::time_point<Clock, Duration>& abs_time, Pred pred);
    template<class Lock, class Rep, class Period, class Pred>
      bool wait_for(Lock& lock, stop_token stoken,
                    const chrono::duration<Rep, Period>& rel_time, Pred pred);
  };
}


标准库头文件 <coroutine>

< cpp‎ | header

此头文件是协程支持库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持

类
coroutine_traits
(C++20)
 用于发现协程承诺类型的特征类型
(类模板)
coroutine_handle
(C++20)
 用于指代暂停或执行的协程
(类模板)
std::hash<std::coroutine_handle>
(C++20)
 std::coroutine_handle 的散列支持
(类模板特化)
无操作协程
noop_coroutine_promise
(C++20)
 用于无可观察作用的协程
(类)
noop_coroutine_handle
(C++20)
 std::coroutine_handle<std::noop_coroutine_promise> ，有意用于指代无操作协程
(typedef)
平凡可等待体
suspend_never
(C++20)
 指示 await 表达式应该决不暂停
(类)
suspend_always
(C++20)
 指示 await 表达式应该始终暂停
(类)

函数
operator==operator<=>
(C++20)
 比较二个 coroutine_handle 对象
(函数)
无操作协程
noop_coroutine
(C++20)
 创建在等待或销毁时无可观察作用的协程柄
(函数)

概要

#include <compare>

namespace std {
  // 协程表征
  template<class R, class... ArgTypes>
    struct coroutine_traits;

  // 协程柄
  template<class Promise = void>
    struct coroutine_handle;

  // 比较运算符
  constexpr bool operator==(coroutine_handle<> x, coroutine_handle<> y) noexcept;
  constexpr strong_ordering operator<=>(coroutine_handle<> x, coroutine_handle<> y) noexcept;

  // 散列支持
  template<class T> struct hash;
  template<class P> struct hash<coroutine_handle<P>>;

  // 无操作协程
  struct noop_coroutine_promise;

  template<> struct coroutine_handle<noop_coroutine_promise>;
  using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;

  noop_coroutine_handle noop_coroutine() noexcept;

  // 平凡可等待体
  struct suspend_never;
  struct suspend_always;
}

类模板 std::coroutine_handle

namespace std {
  template<>
  struct coroutine_handle<void>
  {
    // 构造/重置
    constexpr coroutine_handle() noexcept;
    constexpr coroutine_handle(nullptr_t) noexcept;
    coroutine_handle& operator=(nullptr_t) noexcept;

    // 导入/导出
    constexpr void* address() const noexcept;
    static constexpr coroutine_handle from_address(void* addr);

    // 观察器
    constexpr explicit operator bool() const noexcept;
    bool done() const;

    // 恢复
    void operator()() const;
    void resume() const;
    void destroy() const;

  private:
    void* ptr;  // 仅用于阐释
  };

  template<class Promise>
  struct coroutine_handle
  {
    // 构造/重置
    constexpr coroutine_handle() noexcept;
    constexpr coroutine_handle(nullptr_t) noexcept;
    static coroutine_handle from_promise(Promise&);
    coroutine_handle& operator=(nullptr_t) noexcept;

    // 导出/导入
    constexpr void* address() const noexcept;
    static constexpr coroutine_handle from_address(void* addr);

    // 转换
    constexpr operator coroutine_handle<>() const noexcept;

    // 观察器
    constexpr explicit operator bool() const noexcept;
    bool done() const;

    // 恢复
    void operator()() const;
    void resume() const;
    void destroy() const;

    // 承诺访问
    Promise& promise() const;

  private:
    void* ptr;  // 仅用于阐释
  };
}

类 std::noop_coroutine_promise

namespace std {
  struct noop_coroutine_promise {};
}

类 std::coroutine_handle<std::noop_coroutine_promise>

namespace std {
  template<>
  struct coroutine_handle<noop_coroutine_promise>
  {
    // 转换
    constexpr operator coroutine_handle<>() const noexcept;

    // 观察器
    constexpr explicit operator bool() const noexcept;
    constexpr bool done() const noexcept;

    // 恢复
    constexpr void operator()() const noexcept;
    constexpr void resume() const noexcept;
    constexpr void destroy() const noexcept;

    // 承诺访问
    noop_coroutine_promise& promise() const noexcept;

    // 地址
    constexpr void* address() const noexcept;
  private:
    coroutine_handle(/* 未指明 */);
    void* ptr;  // 仅用于阐释
  };
}

类 std::suspend_never

namespace std {
  struct suspend_never {
    constexpr bool await_ready() const noexcept { return true; }
    constexpr void await_suspend(coroutine_handle<>) const noexcept {}
    constexpr void await_resume() const noexcept {}
  };
}

类 std::suspend_always

namespace std {
  struct suspend_always {
    constexpr bool await_ready() const noexcept { return false; }
    constexpr void await_suspend(coroutine_handle<>) const noexcept {}
    constexpr void await_resume() const noexcept {}
  };
}


标准库头文件 <csetjmp>

< cpp‎ | header

此头文件原作为 <setjmp.h> 存在于 C 标准库。

此头文件是程序支持库的一部分。

类型
jmp_buf
 执行语境类型
(typedef)

宏
setjmp
 保存语境
(宏函数)

函数
longjmp
 跳转到指定位置
(函数)

概要

namespace std {
  using jmp_buf = /* 见描述 */ ;
  [[noreturn]] void longjmp(jmp_buf env, int val);
}
#define setjmp(env) /* 见描述 */


标准库头文件 <csignal>

< cpp‎ | header

此头文件原作为 <signal.h> 存在于 C 标准库。

此头文件是程序支持库的一部分。

typedef
sig_atomic_t
 能从异步信号处理函数作为原子实体访问的整数类型
(typedef)

宏
SIGABRTSIGFPESIGILLSIGINTSIGSEGVSIGTERM
 定义信号类型
(宏常量)
SIG_DFLSIG_IGN
 定义信号处理策略
(宏常量)
SIG_ERR
 signal 的返回值，说明遇到错误
(宏常量)

函数
signal
 为特定信号设置信号处理函数
(函数)
raise
 为特定信号运行信号处理函数
(函数)

概要

namespace std {
  using sig_atomic_t = /* 见描述 */ ;
  extern "C" using /* signal-handler */ = void(int); // 仅为阐释
  /*signal-handler*/ * signal(int sig, /*signal-handler*/ * func);
}
#define SIG_DFL /* 见描述 */
#define SIG_ERR /* 见描述 */
#define SIG_IGN /* 见描述 */
#define SIGABRT /* 见描述 */
#define SIGFPE /* 见描述 */
#define SIGILL /* 见描述 */
#define SIGINT /* 见描述 */
#define SIGSEGV /* 见描述 */
#define SIGTERM /* 见描述 */


标准库头文件 <cstdalign>

< cpp‎ | header

此头文件原作为 <stdalign.h> 存在于 C 标准库。

C 兼容头文件。

宏
__alignas_is_defined
(C++11)
 C 兼容宏常量，展开成整数字面量 1
(宏常量)

注解

此头文件于 C++17 中弃用并于 C++20 中移除。对应的 <stdalign.h> 在 C++20 中仍可用。


标准库头文件 <cstdarg>

< cpp‎ | header

此头文件原作为 <stdarg.h> 存在于 C 标准库。

此头文件提供对 C 风格变参函数的支持。

类型
va_list
 保有 va_start、va_arg、va_end 和 va_copy 所需的信息
(typedef)

宏
va_start
 启用对可变函数实参的访问
(宏函数)
va_arg
 访问下一个可变函数实参
(宏函数)
va_copy
(C++11)
 制造可变函数实参的副本
(宏函数)
va_end
 结束对可变函数实参的遍历
(宏函数)

概要

namespace std {
  using va_list = /* 见描述 */ ;
}
#define va_arg(V, P) /* 见描述 */
#define va_copy(VDST, VSRC) /* 见描述 */
#define va_end(V) /* 见描述 */
#define va_start(V, P) /* 见描述 */


标准库头文件 <cstdbool>

< cpp‎ | header

此头文件原作为 <stdbool.h> 存在于 C 标准库。

兼容性头文件，在 C 中定义 true、false 及 bool，它们在 C++ 中是关键词。

宏
__bool_true_false_are_defined
(C++11)
 C 兼容宏常量，展开成整数字面量 1
(宏常量)

注解

此头文件于 C++17 中弃用并于 C++20 中移除。对应的 <stdbool.h> 在 C++20 中仍可用。


标准库头文件 <cstddef>

< cpp‎ | header

此头文件原作为 <stddef.h> 存在于 C 标准库。

此头文件是工具库的一部分。

宏
NULL
 实现定义的空指针常量
(宏常量)
offsetof
 从标准布局类型的起始到其指定成员的字节偏移量
(宏函数)

类型
size_t
 sizeof 运算符返回的无符号整数类型
(typedef)
ptrdiff_t
 在两个指针相减时返回的有符号整数类型
(typedef)
nullptr_t
(C++11)
 空指针字面量 nullptr 的类型
(typedef)
max_align_t
(C++11)
 具有不小于任何基础类型的内存对齐需求的平凡类型
(typedef)
byte
(C++17)
 字节类型
(枚举)

概要

namespace std {
  using ptrdiff_t = /* 见描述 */;
  using size_t = /* 见描述 */;
  using max_align_t = /* 见描述 */;
  using nullptr_t = decltype(nullptr);

  enum class byte : unsigned char {};

  // 字节类型运算
  template<class IntType>
    constexpr byte& operator<<=(byte& b, IntType shift) noexcept;
  template<class IntType>
    constexpr byte operator<<(byte b, IntType shift) noexcept;
  template<class IntType>
    constexpr byte& operator>>=(byte& b, IntType shift) noexcept;
  template<class IntType>
    constexpr byte operator>>(byte b, IntType shift) noexcept;
  constexpr byte& operator|=(byte& l, byte r) noexcept;
  constexpr byte operator|(byte l, byte r) noexcept;
  constexpr byte& operator&=(byte& l, byte r) noexcept;
  constexpr byte operator&(byte l, byte r) noexcept;
  constexpr byte& operator^=(byte& l, byte r) noexcept;
  constexpr byte operator^(byte l, byte r) noexcept;
  constexpr byte operator~(byte b) noexcept;
  template<class IntType>
    constexpr IntType to_integer(byte b) noexcept;
}

#define NULL /* 见描述 */
#define offsetof(P, D) /* 见描述 */

注解

  • NULL 亦定义于下列头文件：
    • <clocale>
    • <ctime>
    • <cstring>
    • <cstdio>
    • <cstdlib>
    • <cwchar>
  • std::size_t 亦定义于下列头文件：
    • <ctime>
    • <cstring>
    • <cstdio>
    • <cwchar>
    • <cuchar> (C++17 起)


标准库头文件 <cstdint>

< cpp‎ | header

此头文件原作为 <stdint.h> 存在于 C 标准库。

此头文件是类型支持库的一部分，提供定宽整数类型和部分 C 数值极限接口。

类型

定义于头文件 <cstdint>
int8_tint16_tint32_tint64_t (可选) | 分别为宽度恰为 8、16、32 和 64 位的有符号整数类型 无填充位并对负值使用补码 （仅若实现支持该类型才提供） (typedef)
int_fast8_tint_fast16_tint_fast32_tint_fast64_t | 分别为宽度至少有 8、16、32 和 64 位的最快的有符号整数类型 (typedef)
int_least8_tint_least16_tint_least32_tint_least64_t | 分别为宽度至少有 8、16、32 和 64 位的最小的有符号整数类型 (typedef)
intmax_t | 最大宽度的有符号整数类型 (typedef)
intptr_t (可选) | 足以保有指针的有符号整数类型 (typedef)
uint8_tuint16_tuint32_tuint64_t (可选) | 宽度恰为 8、16、32 和 64 位的无符号整数类型 （仅若实现支持该类型才提供） (typedef)
uint_fast8_tuint_fast16_tuint_fast32_tuint_fast64_t | 分别为宽度至少有 8、16、32 和 64 位的最快无符号整数类型 (typedef)
uint_least8_tuint_least16_tuint_least32_tuint_least64_t | 分别为宽度至少有 8、16、32 和 64 位的最小无符号整数类型 (typedef)
uintmax_t | 最大宽度的无符号整数类型 (typedef)
uintptr_t (可选) | 足以保有指针的无符号整数类型 (typedef)

宏

定义于头文件 <cstdint>
有符号整数：最小值
INT8_MININT16_MININT32_MININT64_MIN
(可选)
 int8_t、int16_t、int32_t、int64_t 类型对象的最小值
(宏常量)
INT_FAST8_MININT_FAST16_MININT_FAST32_MININT_FAST64_MIN
 int_fast8_t、int_fast16_t、int_fast32_t、int_fast64_t 类型对象的最小值
(宏常量)
INT_LEAST8_MININT_LEAST16_MININT_LEAST32_MININT_LEAST64_MIN
 int_least8_t、int_least16_t、int_least32_t、int_least64_t 类型对象的最小值
(宏常量)
INTPTR_MIN
(可选)
 intptr_t 类型对象的最小值
(宏常量)
INTMAX_MIN
 intmax_t 类型对象的最小值
(宏常量)
有符号整数：最大值
INT8_MAXINT16_MAXINT32_MAXINT64_MAX
(可选)
 int8_t、int16_t、int32_t、int64_t 类型对象的最大值
(宏常量)
INT_FAST8_MAXINT_FAST16_MAXINT_FAST32_MAXINT_FAST64_MAX
 int_fast8_t、int_fast16_t、int_fast32_t、int_fast64_t 类型对象的最大值
(宏常量)
INT_LEAST8_MAXINT_LEAST16_MAXINT_LEAST32_MAXINT_LEAST64_MAX
 int_least8_t、int_least16_t、int_least32_t、int_least64_t 类型对象的最大值
(宏常量)
INTPTR_MAX
(可选)
 intptr_t 类型对象的最大值
(宏常量)
INTMAX_MAX
 intmax_t 类型对象的最大值
(宏常量)
无符号整数：最大值
UINT8_MAXUINT16_MAXUINT32_MAXUINT64_MAX
(可选)
 uint8_t、uint16_t、uint32_t、uint64_t 类型对象的最大值
(宏常量)
UINT_FAST8_MAXUINT_FAST16_MAXUINT_FAST32_MAXUINT_FAST64_MAX
 uint_fast8_t、uint_fast16_t、uint_fast32_t、uint_fast64_t 类型对象的最大值
(宏常量)
UINT_LEAST8_MAXUINT_LEAST16_MAXUINT_LEAST32_MAXUINT_LEAST64_MAX
 uint_least8_t、uint_least16_t、uint_least32_t、uint_least64_t 类型对象的最大值
(宏常量)
UINTPTR_MAX
(可选)
 uintptr_t 类型对象的最大值
(宏常量)
UINTMAX_MAX
 uintmax_t 类型对象的最大值
(宏常量)
其他整数类型的极限
PTRDIFF_MIN
(C++11)
 std::ptrdiff_t 类型对象的最小值
(宏常量)
PTRDIFF_MAX
(C++11)
 std::ptrdiff_t 类型对象的最大值
(宏常量)
SIZE_MAX
(C++11)
 std::size_t 类型对象的最大值
(宏常量)
SIG_ATOMIC_MIN
(C++11)
 std::sig_atomic_t 类型对象的最小值
(宏常量)
SIG_ATOMIC_MAX
(C++11)
 std::sig_atomic_t 类型对象的最大值
(宏常量)
WCHAR_MIN
(C++11)
 wchar_t 类型对象的最小值
(宏常量)
WCHAR_MAX
(C++11)
 wchar_t 类型对象的最大值
(宏常量)
WINT_MIN
(C++11)
 std::wint_t 类型对象的最小值
(宏常量)
WINT_MAX
(C++11)
 std::wint_t 类型对象的最大值
(宏常量)
整数常量的函数宏
INT8_CINT16_CINT32_CINT64_C
 展开成拥有其实参所指定的值且类型分别为 int_least8_t、int_least16_t、int_least32_t、int_least64_t 的提升类型的整数常量表达式
(宏函数)
INTMAX_C
 展开成拥有其实参所指定的值且类型为 intmax_t 的整数常量表达式
(宏函数)
UINT8_CUINT16_CUINT32_CUINT64_C
 展开成拥有其实参所指定的值且类型分别为 uint_least8_t、uint_least16_t、uint_least32_t、uint_least64_t 的提升类型的整数常量表达式
(宏函数)
UINTMAX_C
 展开成拥有其实参所指定的值且类型为 uintmax_t 的整数常量表达式
(宏函数)

概要

namespace std {
  using int8_t         = /* 有符号整数类型 */; // 可选
  using int16_t        = /* 有符号整数类型 */; // 可选
  using int32_t        = /* 有符号整数类型 */; // 可选
  using int64_t        = /* 有符号整数类型 */; // 可选
  using intN_t         = /* 见描述 */;        // 可选，见描述

  using int_fast8_t    = /* 有符号整数类型 */;
  using int_fast16_t   = /* 有符号整数类型 */;
  using int_fast32_t   = /* 有符号整数类型 */;
  using int_fast64_t   = /* 有符号整数类型 */;
  using int_fastN_t    = /* 见描述 */;        // 可选，见描述

  using int_least8_t   = /* 有符号整数类型 */;
  using int_least16_t  = /* 有符号整数类型 */;
  using int_least32_t  = /* 有符号整数类型 */;
  using int_least64_t  = /* 有符号整数类型 */;
  using int_leastN_t   = /* 见描述 */;        // 可选，见描述

  using intmax_t       = /* 有符号整数类型 */;
  using intptr_t       = /* 有符号整数类型 */; // 可选

  using uint8_t        = /* 无符号整数类型 */; // 可选
  using uint16_t       = /* 无符号整数类型 */; // 可选
  using uint32_t       = /* 无符号整数类型 */; // 可选
  using uint64_t       = /* 无符号整数类型 */; // 可选
  using uintN_t        = /* 见描述 */;        // 可选，见描述

  using uint_fast8_t   = /* 无符号整数类型 */;
  using uint_fast16_t  = /* 无符号整数类型 */;
  using uint_fast32_t  = /* 无符号整数类型 */;
  using uint_fast64_t  = /* 无符号整数类型 */;
  using uint_fastN_t   = /* 见描述 */;        // 可选，见描述

  using uint_least8_t  = /* 无符号整数类型 */;
  using uint_least16_t = /* 无符号整数类型 */;
  using uint_least32_t = /* 无符号整数类型 */;
  using uint_least64_t = /* 无符号整数类型 */;
  using uint_leastN_t  = /* 见描述 */;        // 可选，见描述

  using uintmax_t      = /* 无符号整数类型 */;
  using uintptr_t      = /* 无符号整数类型 */; // 可选
}

#define INTN_MIN         /* 见描述 */
#define INTN_MAX         /* 见描述 */
#define UINTN_MAX        /* 见描述 */

#define INT_FASTN_MIN    /* 见描述 */
#define INT_FASTN_MAX    /* 见描述 */
#define UINT_FASTN_MAX   /* 见描述 */

#define INT_LEASTN_MIN   /* 见描述 */
#define INT_LEASTN_MAX   /* 见描述 */
#define UINT_LEASTN_MAX  /* 见描述 */

#define INTMAX_MIN       /* 见描述 */
#define INTMAX_MAX       /* 见描述 */
#define UINTMAX_MAX      /* 见描述 */

#define INTPTR_MIN       /* 见描述 */         // 可选
#define INTPTR_MAX       /* 见描述 */         // 可选
#define UINTPTR_MAX      /* 见描述 */         // 可选

#define PTRDIFF_MIN      /* 见描述 */
#define PTRDIFF_MAX      /* 见描述 */
#define SIZE_MAX         /* 见描述 */

#define SIG_ATOMIC_MIN   /* 见描述 */
#define SIG_ATOMIC_MAX   /* 见描述 */

#define WCHAR_MIN        /* 见描述 */
#define WCHAR_MAX        /* 见描述 */

#define WINT_MIN         /* 见描述 */
#define WINT_MAX         /* 见描述 */

#define INTN_C(value)    /* 见描述 */
#define UINTN_C(value)   /* 见描述 */
#define INTMAX_C(value)  /* 见描述 */
#define UINTMAX_C(value) /* 见描述 */


标准库头文件 <cstdio>

< cpp‎ | header

此头文件原作为 <stdio.h> 存在于 C 标准库。

此头文件是 C 风格输入/输出库的一部分。

类型
FILE
 对象类型，足以保有控制 C I/O 流所需的全部信息
(typedef)
fpos_t
 完整非数组对象类型，足以唯一指定文件中的位置，包含其多字节剖析状态
(typedef)
size_t
 sizeof 运算符返回的无符号整数类型
(typedef)

宏
NULL
 实现定义的空指针常量
(宏常量)
stdinstdoutstderr
 与输入流关联到 FILE* 类型表达式
与输出流关联的 FILE* 类型表达式
与错误输出流关联的 FILE* 类型表达式
(宏常量)
EOF
 拥有 int 类型和负值的整数常量表达式
(宏常量)
FOPEN_MAX
 能同时打开的文件数
(宏常量)
FILENAME_MAX
 要保有最长受支持文件名的 char 数组所需的长度
(宏常量)
BUFSIZ
 std::setbuf 所用的缓冲区大小
(宏常量)
_IOFBF_IOLBF_IONBF
 给 std::setbuf 的参数，指示全缓冲 I/O
给 std::setbuf 的参数，指示行缓冲 I/O
给 std::setbuf 的参数，指示无缓冲 I/O
(宏常量)
SEEK_SETSEEK_CURSEEK_END
 给 std::fseek 的参数，指示从文件起始寻位
给 std::fseek 的参数，指示从当前文件位置寻位
给 std::fseek 的参数，指示从文件尾寻位
(宏常量)
TMP_MAX
 std::tmpnam 所能生成的唯一文件名的最大数量
(宏常量)
L_tmpnam
 保有 std::tmpnam 结果的 char 数组所需的大小
(宏常量)

函数
文件访问
fopen
 打开文件
(函数)
freopen
 以不同名称打开既存流
(函数)
fclose
 关闭文件
(函数)
fflush
 将输出流与实际文件同步
(函数)
setbuf
 为文件流设置缓冲区
(函数)
setvbuf
 为文件流设置缓冲区与其大小
(函数)
直接输入/输出
fread
 从文件读取
(函数)
fwrite
 写入文件
(函数)
无格式输入/输出
窄字符
fgetcgetc
 从文件流获取字符
(函数)
fgets
 从文件流获取字符串
(函数)
fputcputc
 写字符到文件流
(函数)
fputs
 写字符串到文件流
(函数)
getchar
 从 stdin 读取字符
(函数)
gets
(C++11 中弃用)(C++14 中移除)
 从 stdin 读取字符串
(函数)
putchar
 写字符到 stdout
(函数)
puts
 写字符串到 stdout
(函数)
ungetc
 把字符放回文件流
(函数)
有格式输入/输出
窄/多字节字符
scanffscanfsscanf
 从 stdin、文件流或缓冲区读取有格式输入
(函数)
vscanfvfscanfvsscanf
(C++11)(C++11)(C++11)
 使用可变实参列表
从 stdin、文件流或缓冲区读取有格式输入
(函数)
printffprintfsprintfsnprintf
(C++11)
 打印有格式输出到 stdout、文件流或缓冲区
(函数)
vprintfvfprintfvsprintfvsnprintf
(C++11)
 使用可变实参列表
打印有格式输出到 stdout、文件流或缓冲区
(函数)
文件寻位
ftell
 返回当前文件位置指示器
(函数)
fgetpos
 获取文件位置指示器
(函数)
fseek
 移动文件位置指示器到文件中的指定位置
(函数)
fsetpos
 移动文件位置指示器到文件中的指定位置
(函数)
rewind
 移动文件位置指示器到文件起始
(函数)
错误处理
clearerr
 清除错误
(函数)
feof
 检查文件尾
(函数)
ferror
 检查文件错误
(函数)
perror
 显示对应当前错误的字符串于 stderr
(函数)
文件上的操作
remove
 删除文件
(函数)
rename
 重命名文件
(函数)
tmpfile
 创建并打开一个临时、自动移除的文件
(函数)
tmpnam
 返回一个唯一独有的文件名
(函数)

概要

namespace std {
  using size_t = /* 见描述 */;
  using FILE = /* 见描述 */;
  using fpos_t = /* 见描述 */;
}

#define NULL /* 见描述 */
#define _IOFBF /* 见描述 */
#define _IOLBF /* 见描述 */
#define _IONBF /* 见描述 */
#define BUFSIZ /* 见描述 */
#define EOF /* 见描述 */
#define FOPEN_MAX /* 见描述 */
#define FILENAME_MAX /* 见描述 */
#define L_tmpnam /* 见描述 */
#define SEEK_CUR /* 见描述 */
#define SEEK_END /* 见描述 */
#define SEEK_SET /* 见描述 */
#define TMP_MAX /* 见描述 */
#define stderr /* 见描述 */
#define stdin /* 见描述 */
#define stdout /* 见描述 */

namespace std {
  int remove(const char* filename);
  int rename(const char* old_p, const char* new_p);
  FILE* tmpfile();
  char* tmpnam(char* s);
  int fclose(FILE* stream);
  int fflush(FILE* stream);
  FILE* fopen(const char* filename, const char* mode);
  FILE* freopen(const char* filename, const char* mode, FILE* stream);
  void setbuf(FILE* stream, char* buf);
  int setvbuf(FILE* stream, char* buf, int mode, size_t size);
  int fprintf(FILE* stream, const char* format, ...);
  int fscanf(FILE* stream, const char* format, ...);
  int printf(const char* format, ...);
  int scanf(const char* format, ...);
  int snprintf(char* s, size_t n, const char* format, ...);
  int sprintf(char* s, const char* format, ...);
  int sscanf(const char* s, const char* format, ...);
  int vfprintf(FILE* stream, const char* format, va_list arg);
  int vfscanf(FILE* stream, const char* format, va_list arg);
  int vprintf(const char* format, va_list arg);
  int vscanf(const char* format, va_list arg);
  int vsnprintf(char* s, size_t n, const char* format, va_list arg);
  int vsprintf(char* s, const char* format, va_list arg);
  int vsscanf(const char* s, const char* format, va_list arg);
  int fgetc(FILE* stream);
  char* fgets(char* s, int n, FILE* stream);
  int fputc(int c, FILE* stream);
  int fputs(const char* s, FILE* stream);
  int getc(FILE* stream);
  int getchar();
  int putc(int c, FILE* stream);
  int putchar(int c);
  int puts(const char* s);
  int ungetc(int c, FILE* stream);
  size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream);
  size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream);
  int fgetpos(FILE* stream, fpos_t* pos);
  int fseek(FILE* stream, long int offset, int whence);
  int fsetpos(FILE* stream, const fpos_t* pos);
  long int ftell(FILE* stream);
  void rewind(FILE* stream);
  void clearerr(FILE* stream);
  int feof(FILE* stream);
  int ferror(FILE* stream);
  void perror(const char* s);
}

注解

  • NULL 亦定义于下列头文件：
    • <clocale>
    • <ctime>
    • <cstddef>
    • <cstring>
    • <cwchar>
    • <cstdlib>
  • std::size_t 亦定义于下列头文件：
    • <ctime>
    • <cstddef>
    • <cstring>
    • <cwchar>
    • <cuchar> (C++17 起)
    • <cstdlib>


标准库头文件 <cstdlib>

< cpp‎ | header

此头文件原作为 <stdlib.h> 存在于 C 标准库。

此头文件提供杂项工具。此处所定义的各个符号为多个标准库组件所用。

类型
div_t
 结构体类型，std::div 函数的返回值
(typedef)
ldiv_t
 结构体类型，std::ldiv 函数的返回值
(typedef)
lldiv_t
(C++11)
 结构体类型，std::lldiv 函数的返回值
(typedef)
size_t
 sizeof 运算符返回的无符号整数类型
(typedef)

宏常量
EXIT_SUCCESSEXIT_FAILURE
 指示程序执行的执行状态
(宏常量)
MB_CUR_MAX
 当前本地环境中多字节字符的最大字节数
(宏常量)
NULL
 实现定义的空指针常量
(宏常量)
RAND_MAX
 std::rand 生成的最大可能值
(宏常量)

函数
进程控制
abort
 导致非正常的程序终止（不进行清理）
(函数)
exit
 导致正常的程序终止并进行清理
(函数)
quick_exit
(C++11)
 导致快速程序终止，不进行完全的清理
(函数)
_Exit
(C++11)
 导致正常的程序终止，不进行清理
(函数)
atexit
 注册将于调用 std::exit() 时被调用的函数
(函数)
at_quick_exit
(C++11)
 注册将于调用 quick_exit 时被调用的函数
(函数)
system
 调用宿主环境的命令处理器
(函数)
getenv
 访问环境变量列表
(函数)
内存管理
malloc
 分配内存
(函数)
aligned_alloc
(C++17)
 分配对齐的内存
(函数)
calloc
 分配并清零内存
(函数)
realloc
 扩张或收缩之前分配的内存块
(函数)
free
 解分配之前分配的内存
(函数)
数值字符串转换
atof
 转换字节字符串为浮点值
(函数)
atoiatolatoll
(C++11)
 转换字节字符串为整数值
(函数)
strtolstrtoll
(C++11)
 转换字节字符串为整数值
(函数)
strtoulstrtoull
(C++11)
 转换字节字符串为无符号整数值
(函数)
strtofstrtodstrtold
 转换字节字符串为浮点值
(函数)
宽字符串操纵
mblen
 返回下一个多字节字符中的字节数
(函数)
mbtowc
 将下一个多字节字符转换成宽字符
(函数)
wctomb
 转换宽字符为其多字节表示
(函数)
mbstowcs
 转换窄多字节字符串为宽字符串
(函数)
wcstombs
 转换宽字符串为窄多字节字符串
(函数)
杂项算法与数学
rand
 生成伪随机数
(函数)
srand
 初始化伪随机数生成器
(函数)
qsort
 对未指定类型的元素的一个范围进行排序
(函数)
bsearch
 在未指定类型的数组中搜索元素
(函数)
abs(int)labsllabs
(C++11)
 计算整数值的绝对值（ \(\small{|x|}\)|x| ）
(函数)
div(int)ldivlldiv
(C++11)
 计算整数除法的商和余数
(函数)

概要

namespace std {
  using size_t = /* 见描述 */;
  using div_t = /* 见描述 */;
  using ldiv_t = /* 见描述 */;
  using lldiv_t = /* 见描述 */;
}

#define NULL  /* 见描述 */
#define EXIT_FAILURE  /* 见描述 */
#define EXIT_SUCCESS  /* 见描述 */
#define RAND_MAX  /* 见描述 */
#define MB_CUR_MAX  /* 见描述 */

namespace std {
  // 仅用于阐释的函数类型别名
  extern "C" using /*c-atexit-handler*/ = void();                        // 仅用于阐释
  extern "C++" using /*atexit-handler*/ = void();                        // 仅用于阐释
  extern "C" using /*c-compare-pred*/ = int(const void*, const void*);   // 仅用于阐释
  extern "C++" using /*compare-pred*/ = int(const void*, const void*);   // 仅用于阐释

  // 启动与终止
  [[noreturn]] void abort() noexcept;
  int atexit(/*c-atexit-handler*/* func) noexcept;
  int atexit(/*atexit-handler*/* func) noexcept;
  int at_quick_exit(/*c-atexit-handler*/* func) noexcept;
  int at_quick_exit(/*atexit-handler*/* func) noexcept;
  [[noreturn]] void exit(int status);
  [[noreturn]] void _Exit(int status) noexcept;
  [[noreturn]] void quick_exit(int status) noexcept;

  char* getenv(const char* name);
  int system(const char* string);

  // C 库内存分配
  void* aligned_alloc(size_t alignment, size_t size);
  void* calloc(size_t nmemb, size_t size);
  void free(void* ptr);
  void* malloc(size_t size);
  void* realloc(void* ptr, size_t size);

  double atof(const char* nptr);
  int atoi(const char* nptr);
  long int atol(const char* nptr);
  long long int atoll(const char* nptr);
  double strtod(const char* nptr, char** endptr);
  float strtof(const char* nptr, char** endptr);
  long double strtold(const char* nptr, char** endptr);
  long int strtol(const char* nptr, char** endptr, int base);
  long long int strtoll(const char* nptr, char** endptr, int base);
  unsigned long int strtoul(const char* nptr, char** endptr, int base);
  unsigned long long int strtoull(const char* nptr, char** endptr, int base);

  // 多字节/宽字符串及字符转换函数
  int mblen(const char* s, size_t n);
  int mbtowc(wchar_t* pwc, const char* s, size_t n);
  int wctomb(char* s, wchar_t wchar);
  size_t mbstowcs(wchar_t* pwcs, const char* s, size_t n);
  size_t wcstombs(char* s, const wchar_t* pwcs, size_t n);

  // C 标准库算法
  void* bsearch(const void* key, const void* base, size_t nmemb, size_t size,
                /*c-compare-pred*/* compar);
  void* bsearch(const void* key, const void* base, size_t nmemb, size_t size,
                /*compare-pred*/* compar);
  void qsort(void* base, size_t nmemb, size_t size, /*c-compare-pred*/* compar);
  void qsort(void* base, size_t nmemb, size_t size, /*compare-pred*/* compar);

  // 低质量随机数生成
  int rand();
  void srand(unsigned int seed);

  // 绝对值
  int abs(int j);
  long int abs(long int j);
  long long int abs(long long int j);
  float abs(float j);
  double abs(double j);
  long double abs(long double j);

  long int labs(long int j);
  long long int llabs(long long int j);

  div_t div(int numer, int denom);
  ldiv_t div(long int numer, long int denom);
  lldiv_t div(long long int numer, long long int denom);
  ldiv_t ldiv(long int numer, long int denom);
  lldiv_t lldiv(long long int numer, long long int denom);
}

参阅

  • 程序支持工具
  • 伪随机数生成
  • 常用数学函数
  • C 内存管理库
  • 空终止字节字符串
  • 空终止多字节字符串
  • 算法库


标准库头文件 <cstring>

< cpp‎ | header

此头文件原作为 <string.h> 存在于 C 标准库。

此头文件用于 C 风格空终止字节字符串。

宏

NULL
 实现定义的空指针常量
(宏常量)

类型

size_t
 sizeof 运算符返回的无符号整数类型
(typedef)

函数

字符串操纵
strcpy
 复制一个字符串给另一个
(函数)
strncpy
 复制来自一个字符串的一定量字符给另一个
(函数)
strcat
 连接两个字符串
(函数)
strncat
 连接两个字符串的一定量字符
(函数)
strxfrm
 变换字符串，使得 strcmp 会返回与 strcoll 相同的结果
(函数)
字符串检验
strlen
 返回给定字符串的长度
(函数)
strcmp
 比较两个字符串
(函数)
strncmp
 比较两个字符串的一定量字符
(函数)
strcoll
 按照当前本地环境比较两个字符串
(函数)
strchr
 寻找字符的首次出现
(函数)
strrchr
 寻找字符的最后出现
(函数)
strspn
 返回仅由另一字节字符串中找到的字符组成的最大起始段的长度
(函数)
strcspn
 返回仅由另一字节字符串中找不到的字符组成的最大起始段的长度
(函数)
strpbrk
 寻找任何来自分隔符集合的字符的首个位置
(函数)
strstr
 寻找字符子串的首次出现
(函数)
strtok
 寻找字节字符串中的下个记号
(函数)
字符数组操纵
memchr
 在数组中搜索字符的首次出现
(函数)
memcmp
 比较两个缓冲区
(函数)
memset
 以一个字符填充缓冲区
(函数)
memcpy
 复制一个缓冲区到另一个
(函数)
memmove
 移动一个缓冲区到另一个
(函数)
杂项
strerror
 返回给定错误码的文本版本
(函数)

注意

  • NULL 亦定义于下列头文件：
    • <clocale>
    • <ctime>
    • <cstddef>
    • <cstdio>
    • <cwchar>
  • std::size_t 亦定义于下列头文件：
    • <ctime>
    • <cstddef>
    • <cstdio>
    • <cuchar> (C++17 起)
    • <cwchar>


标准库头文件 <ctgmath>

< cpp‎ | header

此头文件原作为 <tgmath.h> 存在于 C 标准库。

此头文件是数值库的一部分。

包含
<complex>
(C++11)
 复数类型
<cmath>
(C++11)
 常用数学函数

注解

此头文件于 C++17 中弃用并于 C++20 中移除。对应的 <tgmath.h> 在 C++20 中仍可用。


标准库头文件 <ctime>

< cpp‎ | header

此头文件原作为 <time.h> 存在于 C 标准库。

此头文件是 C 风格日期和时间库的一部分。

宏常量
CLOCKS_PER_SEC
 每秒的处理器始时钟嘀嗒数
(宏常量)
NULL
 实现定义的空指针常量
(宏常量)

类型
clock_t
 进程运行时间
(typedef)
size_t
 sizeof 运算符返回的无符号整数类型
(typedef)
time_t
 从纪元起的时间类型
(typedef)
tm
 日历时间类型
(类)
timespec
(C++17)
 以秒和纳秒表示的时间
(结构体)

函数
时间操作
clock
 返回自程序启动时起的原始处理器时钟时间
(函数)
time
 返回自纪元起计的系统当前时间
(函数)
difftime
 计算时间之间的差
(函数)
timespec_get
(C++17)
 返回基于给定时间基底的日历时间
(函数)
格式转换
ctime
 转换 time_t 对象为文本表示
(函数)
asctime
 转换 tm 对象为文本表示
(函数)
strftime
 转换 tm 对象到自定义的文本表示
(函数)
wcsftime
 转换 tm 对象为定制的宽字符串文本表示
(函数)
gmtime
 转换纪元起时间为以协调世界时表示的日历时间
(函数)
localtime
 转换纪元起时间为以本地时间表示的日历时间
(函数)
mktime
 转换日历时间为纪元起的时间
(函数)

概要

#define NULL /* 见描述 */
#define CLOCKS_PER_SEC /* 见描述 */
#define TIME_UTC /* 见描述 */

namespace std {
  using size_t = /* 见描述 */;
  using clock_t = /* 见描述 */;
  using time_t = /* 见描述 */;

  struct timespec;
  struct tm;

  clock_t clock();
  double difftime(time_t time1, time_t time0);
  time_t mktime(tm* timeptr);
  time_t time(time_t* timer);
  int timespec_get(timespec* ts, int base);
  char* asctime(const tm* timeptr);
  char* ctime(const time_t* timer);
  tm* gmtime(const time_t* timer);
  tm* localtime(const time_t* timer);
  size_t strftime(char* s, size_t maxsize, const char* format, const tm* timeptr);
}

类 std::timespec

struct timespec {
  std::time_t tv_sec;
  long tv_nsec;
};

类 std::tm

struct tm {
  int tm_sec;
  int tm_min;
  int tm_hour;
  int tm_mday;
  int tm_mon;
  int tm_year;
  int tm_wday;
  int tm_yday;
  int tm_isdst;
};


标准库头文件 <cuchar>

< cpp‎ | header

此头文件原作为 <uchar.h> 存在于 C 标准库。

此头文件是空终止多字节字符串库的一部分。

宏
__STDC_UTF_16__
(C++11)
 指示 mbrtoc16 与 c16rtomb 使用 UTF-16 编码
(宏常量)
__STDC_UTF_32__
(C++11)
 指示 mbrtoc32 与 c32rtomb 使用 UTF-32 编码
(宏常量)

类型
mbstate_t
 迭代多字节字符串所需的转换状态信息
(类)
size_t
 sizeof 运算符返回的无符号整数类型
(typedef)

函数
mbrtoc16
(C++11)
 转换窄多字节字符为 UTF-16 编码
(函数)
c16rtomb
(C++11)
 转换 16 位宽字符为窄多字节字符串
(函数)
mbrtoc32
(C++11)
 转换窄多字节字符为 UTF-32 编码
(函数)
c32rtomb
(C++11)
 转换 32 位宽字符为窄多字节字符串
(函数)
mbrtoc8
(C++20)
 转换窄多字节字符为 UTF-8 编码
(函数)
c8rtomb
(C++20)
 转换 UTF-8 字符串为窄多字节编码
(函数)

概要

namespace std {
  using mbstate_t = /* 见描述 */;
  using size_t = /* 见描述 */;

  size_t mbrtoc8(char8_t* pc8, const char* s, size_t n, mbstate_t* ps);
  size_t c8rtomb(char* s, char8_t c8, mbstate_t* ps);
  size_t mbrtoc16(char16_t* pc16, const char* s, size_t n, mbstate_t* ps);
  size_t c16rtomb(char* s, char16_t c16, mbstate_t* ps);
  size_t mbrtoc32(char32_t* pc32, const char* s, size_t n, mbstate_t* ps);
  size_t c32rtomb(char* s, char32_t c32, mbstate_t* ps);
}


标准库头文件 <cwchar>

< cpp‎ | header

此头文件原作为 <wchar.h> 存在于 C 标准库。

此头文件是空终止宽及多字节字符串库的一部分。它亦提供一些 C 风格 I/O 函数和源自 C 风格日期的转换。

宏

NULL | 实现定义的空指针常量 (宏常量)
WEOF | 用于指示错误的 wint_t 类型非字符值 (宏常量)
WCHAR_MIN | wchar_t 的最小合法值 (宏常量)
WCHAR_MAX | wchar_t 的最大合法值 (宏常量)

类型

mbstate_t | 迭代多字节字符串所需的转换状态信息 (类)
size_t | sizeof 运算符返回的无符号整数类型 (typedef)
wint_t | 能保有任何合法宽字符和至少多一个值的整数类型
tm | 日历时间类型 (类)

函数

字符串操纵
wcscpy
 复制一个宽字符串到另一个
(函数)
wcsncpy
 复制来自一个宽字符串的一定量宽字符到另一个
(函数)
wcscat
 后附一个宽字符串的副本到另一个
(函数)
wcsncat
 后附来自一个宽字符串的一定量宽字符到另一个
(函数)
wcsxfrm
 变换宽字符串，使得 wcscmp 会产生与 wsccoll 相同的结果
(函数)
字符串检验
wcslen
 返回宽字符串长度
(函数)
wcscmp
 比较两个宽字符串
(函数)
wcsncmp
 比较来自两个宽字符串的一定量宽字符
(函数)
wcscoll
 按照当前本地环境比较两个宽字符串
(函数)
wcschr
 寻找宽字符串中宽字符的首次出现
(函数)
wcsrchr
 在宽字符串中寻找宽字符的最后一次出现
(函数)
wcsspn
 返回仅由另一宽字符串中找到的宽字符组成的最大起始段的长度
(函数)
wcscspn
 返回仅由另一宽字符串中找不到的宽字符组成的最大起始段的长度
(函数)
wcspbrk
 在一个宽字符串中，寻找另一宽字符串中任何字符的首个位置
(函数)
wcsstr
 在另一宽字符串中寻找宽字符串的首次出现
(函数)
wcstok
 寻找宽字符串中的下一个记号
(函数)
宽字符数组操纵
wmemcpy
 在两个不重叠数组间复制一定量宽字符
(函数)
wmemmove
 在两个可能重叠的数组间复制一定量宽字符
(函数)
wmemcmp
 比较来自两个数组的一定量宽字符
(函数)
wmemchr
 寻找宽字符数组中宽字符的首次出现
(函数)
wmemset
 复制给定宽字符到宽字符数组的每个位置
(函数)
多字节/宽字符转换
mbsinit
 检查 mbstate_t 对象是否表示初始迁移状态
(函数)
btowc
 若可能，则加宽单字节窄字符为宽字符
(函数)
wctob
 若可能，则窄化宽字符为单字节窄字符
(函数)
mbrlen
 给定状态，返回下一个多字节字符中的字节数
(函数)
mbrtowc
 给定状态，转换下个多字节字符为宽字符
(函数)
wcrtomb
 给定状态，转换宽字符到其多字节表示
(函数)
mbsrtowcs
 给定状态，转换窄多字节字符串到宽字符串
(函数)
wcsrtombs
 给定状态，转换宽字符串为窄多字节字符串
(函数)
输入/输出
fgetwcgetwc
 从文件流获取宽字符
(函数)
fgetws
 从文件流获取宽字符串
(函数)
fputwcputwc
 写宽字符到文件流
(函数)
fputws
 写宽字符串到文件流
(函数)
getwchar
 从 stdin 读取宽字符
(函数)
putwchar
 写宽字符到 stdout
(函数)
ungetwc
 把宽字符放回文件流
(函数)
fwide
 在宽字符 I/O 和窄字符 I/O 间切换文件流
(函数)
wscanffwscanfswscanf
 从 stdin、文件流或缓冲区读取有格式宽字符输入
(函数)
vwscanfvfwscanfvswscanf
(C++11)(C++11)(C++11)
 使用可变实参列表
从 stdin、文件流或缓冲区读取有格式宽字符输入
(函数)
wprintffwprintfswprintf
 打印有格式宽字符输出到 stdout、文件流或缓冲区
(函数)
vwprintfvfwprintfvswprintf
 使用可变实参列表打印
有格式宽字符输出到 stdout、文件流或缓冲区
(函数)
字符串转换
wcsftime
 转换 tm 对象为定制的宽字符串文本表示
(函数)
wcstolwcstoll
 转换宽字符串为整数值
(函数)
wcstoulwcstoull
 转换宽字符串为无符号整数值
(函数)
wcstofwcstodwcstold
 转换宽字符串为浮点值
(函数)

注意

  • NULL 亦定义于下列头文件：
    • <cstddef>
    • <cstring>
    • <ctime>
    • <clocale>
    • <cstdio>
  • std::size_t 亦定义于下列头文件：
    • <cstddef>
    • <ctime>
    • <cstdio>
  • std::wint_t 亦定义于下列头文件：
    • <cwctype>
  • std::tm 亦定义于下列头文件：
    • <ctime>


标准库头文件 <cwctype>

< cpp‎ | header

此头文件原作为 <wctype.h> 存在于 C 标准库。

此头文件是 C 风格空终止宽字符串库的一部分。

类型

wctrans_t | 保有本地环境特定的字符映射的标量类型
wctype_t | 保有本地环境特定的字符映射的标量类型
wint_t | 能保有任何合法宽字符和至少多一个值的整数类型

宏

WEOF
 用于指示错误的 wint_t 类型非字符值
(宏常量)

函数

字符分类
iswalnum
 检查宽字符是否为字母数字
(函数)
iswalpha
 检查宽字符是否为字母
(函数)
iswlower
 检查宽字符是否为小写
(函数)
iswupper
 检查宽字符是否为大写
(函数)
iswdigit
 检查宽字符是否为数字
(函数)
iswxdigit
 检查宽字符是否为十六进制字符
(函数)
iswcntrl
 检查宽字符是否为控制字符
(函数)
iswgraph
 检查宽字符是否为图形字符
(函数)
iswspace
 检查宽字符是否为空白间隔字符
(函数)
iswblank
(C++11)
 检查宽字符是否为空白字符
(函数)
iswprint
 检查宽字符是否为打印字符
(函数)
iswpunct
 检查宽字符是否为标点字符
(函数)
iswctype
 按照指定的 LC_TYPE 类别分类宽字符
(函数)
wctype
 在当前 C 本地环境中查找字符分类类别
(函数)
字符操纵
towlower
 转换宽字符为小写
(函数)
towupper
 转换宽字符为大写
(函数)
towctrans
 按照指定的 LC_TYPE 映射类别进行字符映射
(函数)
wctrans
 在当前 C 本地环境中查找字符映射类别
(函数)


标准库头文件 <deque>

< cpp‎ | header

此头文件是容器库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
<initializer_list>
(C++11)
 std::initializer_list 类模板

类
deque
 双端队列
(类模板)

函数
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 deque 中的值
(函数模板)
std::swap(std::deque)
 特化 std::swap 算法
(函数模板)
erase(std::deque)erase_if(std::deque)
(C++20)
 擦除所有满足特定判别标准的元素
(函数模板)
范围访问
begincbegin
(C++11)(C++14)
 返回指向容器或数组起始的迭代器
(函数模板)
endcend
(C++11)(C++14)
 返回指向容器或数组结尾的迭代器
(函数模板)
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
sizessize
(C++17)(C++20)
 返回容器或数组的大小
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)

概要

#include <compare>
#include <initializer_list>

namespace std {
  // 类模板 deque
  template<class T, class Allocator = allocator<T>> class deque;

  template<class T, class Allocator>
    bool operator==(const deque<T, Allocator>& x, const deque<T, Allocator>& y);
  template<class T, class Allocator>
    /*synth-three-way-result*/<T> operator<=>(const deque<T, Allocator>& x,
                                              const deque<T, Allocator>& y);

  template<class T, class Allocator>
    void swap(deque<T, Allocator>& x, deque<T, Allocator>& y)
      noexcept(noexcept(x.swap(y)));

  template<class T, class Allocator, class U>
    typename deque<T, Allocator>::size_type
      erase(deque<T, Allocator>& c, const U& value);
  template<class T, class Allocator, class Predicate>
    typename deque<T, Allocator>::size_type
      erase_if(deque<T, Allocator>& c, Predicate pred);

  namespace pmr {
    template<class T>
      using deque = std::deque<T, polymorphic_allocator<T>>;
  }
}

类模板 std::deque

namespace std {
  template<class T, class Allocator = allocator<T>>
  class deque {
  public:
    // 类型
    using value_type             = T;
    using allocator_type         = Allocator;
    using pointer                = typename allocator_traits<Allocator>::pointer;
    using const_pointer          = typename allocator_traits<Allocator>::const_pointer;
    using reference              = value_type&;
    using const_reference        = const value_type&;
    using size_type              = /* 由实现定义 */;
    using difference_type        = /* 由实现定义 */;
    using iterator               = /* 由实现定义 */;
    using const_iterator         = /* 由实现定义 */;
    using reverse_iterator       = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

    // 构造/复制/销毁
    deque() : deque(Allocator()) { }
    explicit deque(const Allocator&);
    explicit deque(size_type n, const Allocator& = Allocator());
    deque(size_type n, const T& value, const Allocator& = Allocator());
    template<class InputIt>
      deque(InputIt first, InputIt last, const Allocator& = Allocator());
    deque(const deque& x);
    deque(deque&&);
    deque(const deque&, const Allocator&);
    deque(deque&&, const Allocator&);
    deque(initializer_list<T>, const Allocator& = Allocator());

    ~deque();
    deque& operator=(const deque& x);
    deque& operator=(deque&& x)
      noexcept(allocator_traits<Allocator>::is_always_equal::value);
    deque& operator=(initializer_list<T>);
    template<class InputIt>
      void assign(InputIt first, InputIt last);
    void assign(size_type n, const T& t);
    void assign(initializer_list<T>);
    allocator_type get_allocator() const noexcept;

    // 迭代器
    iterator               begin() noexcept;
    const_iterator         begin() const noexcept;
    iterator               end() noexcept;
    const_iterator         end() const noexcept;
    reverse_iterator       rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator       rend() noexcept;
    const_reverse_iterator rend() const noexcept;

    const_iterator         cbegin() const noexcept;
    const_iterator         cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // 容量
    [[nodiscard]] bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;
    void      resize(size_type sz);
    void      resize(size_type sz, const T& c);
    void      shrink_to_fit();

    // 元素访问
    reference       operator[](size_type n);
    const_reference operator[](size_type n) const;
    reference       at(size_type n);
    const_reference at(size_type n) const;
    reference       front();
    const_reference front() const;
    reference       back();
    const_reference back() const;

    // 修改器
    template<class... Args> reference emplace_front(Args&&... args);
    template<class... Args> reference emplace_back(Args&&... args);
    template<class... Args> iterator emplace(const_iterator position, Args&&... args);

    void push_front(const T& x);
    void push_front(T&& x);
    void push_back(const T& x);
    void push_back(T&& x);

    iterator insert(const_iterator position, const T& x);
    iterator insert(const_iterator position, T&& x);
    iterator insert(const_iterator position, size_type n, const T& x);
    template<class InputIt>
      iterator insert(const_iterator position, InputIt first, InputIt last);
    iterator insert(const_iterator position, initializer_list<T>);

    void pop_front();
    void pop_back();

    iterator erase(const_iterator position);
    iterator erase(const_iterator first, const_iterator last);
    void     swap(deque&)
      noexcept(allocator_traits<Allocator>::is_always_equal::value);
    void     clear() noexcept;
  };

  template<class InputIt, class Allocator = allocator</*iter-value-type*/<InputIt>>>
    deque(InputIt, InputIt, Allocator = Allocator())
      -> deque</*iter-value-type*/<InputIt>, Allocator>;

  // 交换
  template<class T, class Allocator>
    void swap(deque<T, Allocator>& x, deque<T, Allocator>& y)
      noexcept(noexcept(x.swap(y)));
}


标准库头文件 <exception>

< cpp‎ | header

此头文件是错误处理库的一部分。

类
exception
 标准库组件抛出的各种异常的基类
(类)
nested_exception
(C++11)
 用于捕获并存储当前异常的混入类型
(类)
bad_exception
 当 std::current_exception 无法复制异常对象时抛出的异常
(类)
unexpected_handler
(C++17 中移除)
 std::unexpected 所调用的函数类型
(typedef)
terminate_handler
 std::terminate 所调用的函数类型
(typedef)
exception_ptr
(C++11)
 用于处理异常对象的共享指针类型
(typedef)

函数
unexpected
(C++17 中移除)
 违背动态异常说明时调用的函数
(函数)
uncaught_exceptionuncaught_exceptions
(C++20 中移除)(C++17)
 检查当前是否正在进行异常处理
(函数)
make_exception_ptr
(C++11)
 从异常对象创建一个std::exception_ptr
(函数模板)
current_exception
(C++11)
 捕获当前异常到 std::exception_ptr 之中
(函数)
rethrow_exception
(C++11)
 从一个 std::exception_ptr 抛出异常
(函数)
throw_with_nested
(C++11)
 抛出实参，带上混入的 std::nested_exception
(函数模板)
rethrow_if_nested
(C++11)
 抛出 std::nested_exception 中的异常
(函数模板)
terminate
 异常处理失败时调用的函数
(函数)
get_terminate
(C++11)
 获得当前的 terminate_handler
(函数)
set_terminate
 更改将被 std::terminate 调用的函数
(函数)
get_unexpected
(C++11)(C++17 中移除)
 获得当前的 unexpected_handler
(函数)
set_unexpected
(C++17 中移除)
 更改要被 std::unexpected 调用的函数
(函数)

概要

namespace std {
  class exception;
  class bad_exception;
  class nested_exception;

  using terminate_handler = void (*)();
  terminate_handler get_terminate() noexcept;
  terminate_handler set_terminate(terminate_handler f) noexcept;
  [[noreturn]] void terminate() noexcept;

  int uncaught_exceptions() noexcept;

  using exception_ptr = /* 未指明 */;

  exception_ptr current_exception() noexcept;
  [[noreturn]] void rethrow_exception(exception_ptr p);
  template<class E> exception_ptr make_exception_ptr(E e) noexcept;

  template<class T> [[noreturn]] void throw_with_nested(T&& t);
  template<class E> void rethrow_if_nested(const E& e);
}

类 std::exception

namespace std {
  class exception {
  public:
    exception() noexcept;
    exception(const exception&) noexcept;
    exception& operator=(const exception&) noexcept;
    virtual ~exception();
    virtual const char* what() const noexcept;
  };
}

类 std::bad_exception

namespace std {
  class bad_exception : public exception {
  public:
    // 特殊成员函数的规定见 [exception]
    const char* what() const noexcept override;
  };
}

类 std::nested_exception

namespace std {
  class nested_exception {
  public:
    nested_exception() noexcept;
    nested_exception(const nested_exception&) noexcept = default;
    nested_exception& operator=(const nested_exception&) noexcept = default;
    virtual ~nested_exception() = default;

    // 访问函数
    [[noreturn]] void rethrow_nested() const;
    exception_ptr nested_ptr() const noexcept;
  };

  template<class T> [[noreturn]] void throw_with_nested(T&& t);
  template<class E> void rethrow_if_nested(const E& e);
}

参阅

  • 错误处理


标准库头文件 <execution>

< cpp‎ | header

此头文件是算法库的一部分。

类
is_execution_policy
(C++17)
 测试一个类是否表示某种执行策略
(类模板)
定义于命名空间 std::execution
sequenced_policyparallel_policyparallel_unsequenced_policyunsequenced_policy
(C++17)(C++17)(C++17)(C++20)
 执行策略类型
(类)

常量
定义于命名空间 std::execution
seqparpar_unsequnseq
(C++17)(C++17)(C++17)(C++20)
 全局执行策略对象
(常量)

概要

namespace std {
  // 执行策略类型特征
  template<class T> struct is_execution_policy;
  template<class T>
  inline constexpr bool is_execution_policy_v = is_execution_policy<T>::value;
}

namespace std::execution {
  // 顺序执行策略
  class sequenced_policy;

  // 并行执行策略
  class parallel_policy;

  // 并行及无序执行策略
  class parallel_unsequenced_policy;

  // 无序执行策略
  class unsequenced_policy;

  // 执行策略对象
  inline constexpr sequenced_policy            seq{ /* 未指明 */ };
  inline constexpr parallel_policy             par{ /* 未指明 */ };
  inline constexpr parallel_unsequenced_policy par_unseq{ /* 未指明 */ };
  inline constexpr unsequenced_policy          unseq{ /* 未指明 */ };
}


实验性 C++ 标准库头文件

< cpp‎ | header

实验性 C++ 标准库（即 C++ TR/TS 所引入的库）由下列头文件的汇集定义。

文件系统 TS
<experimental/filesystem> (文件系统 TS) | 文件系统库

并行 TS
<experimental/algorithm> (并行 TS) | 非数值并行算法
<experimental/execution_policy> (并行 TS) | 执行策略
<experimental/exception_list> (并行 TS) | 并行异常
<experimental/numeric> (并行 TS) | 数值并行算法

库基础 TS v1
<experimental/algorithm> (库基础 TS) | sample 与 search
<experimental/any> (库基础 TS) | any
<experimental/chrono> (库基础 TS) | 类型特征的变量模板
<experimental/deque> (库基础 TS) | 使用多态分配器的容器的便利别名
<experimental/forward_list> (库基础 TS) | 使用多态分配器的容器的便利别名
<experimental/future> (库基础 TS) | 使用多态分配器的 promise 与 packaged_task
<experimental/list> (库基础 TS) | 使用多态分配器的容器的便利别名
<experimental/functional> (库基础 TS) | 搜索器与使用多态分配器的 function
<experimental/map> (库基础 TS) | 使用多态分配器的容器的便利别名
<experimental/memory> (库基础 TS) | 带数组支持的 shared_ptr 与 weak_ptr
<experimental/memory_resource> (库基础 TS) | 多态分配器与内存资源
<experimental/optional> (库基础 TS) | optional
<experimental/ratio> (库基础 TS) | 类型特征的变量模板
<experimental/regex> (库基础 TS) | 使用多态分配器的容器的便利别名
<experimental/set> (库基础 TS) | 使用多态分配器的容器的便利别名
<experimental/string> (库基础 TS) | 使用多态分配器的容器的便利别名
<experimental/string_view> (库基础 TS) | basic_string_view
<experimental/system_error> (库基础 TS) | 类型特征的变量模板
<experimental/tuple> (库基础 TS) | 类型特征的变量模板与 apply
<experimental/type_traits> (库基础 TS) | 类型特征的变量模板与 invocation_type
<experimental/unordered_map> (库基础 TS) | 使用多态分配器的容器的便利别名
<experimental/unordered_set> (库基础 TS) | 使用多态分配器的容器的便利别名
<experimental/utility> (库基础 TS) | erased_type
<experimental/vector> (库基础 TS) | 使用多态分配器的容器的便利别名

并发扩展
<experimental/atomic> (并发 TS) | atomic_shared_ptr 与 atomic_weak_ptr
<experimental/barrier> (并发 TS) | barrier 与 flex_barrier
<experimental/future> (并发 TS) | std::future 的扩展
<experimental/latch> (并发 TS) | latch

库基础 TS v2
<experimental/algorithm> (库基础 TS v2) | sample 与 shuffle
<experimental/array> (库基础 TS v2) | make_array 与 to_array
<experimental/deque> (库基础 TS v2) | erase 与 erase_if
<experimental/forward_list> (库基础 TS v2) | erase 与 erase_if
<experimental/functional> (库基础 TS v2) | not_fn
<experimental/iterator> (库基础 TS v2) | ostream_joiner
<experimental/list> (库基础 TS v2) | erase 与 erase_if
<experimental/map> (库基础 TS v2) | erase_if 与 erase_if
<experimental/memory> (库基础 TS v2) | observer_ptr
<experimental/numeric> (库基础 TS v2) | gcd 与 lcm
<experimental/propagate_const> (库基础 TS v2) | propagate_const
<experimental/random> (库基础 TS v2) | randint 与 reseed
<experimental/set> (库基础 TS v2) | erase_if 与 erase_if
<experimental/source_location> (库基础 TS v2) | source_location
<experimental/string> (库基础 TS v2) | erase 与 erase_if
<experimental/type_traits> (库基础 TS v2) | 元函数与检测手法
<experimental/unordered_map> (库基础 TS v2) | erase_if 与 erase_if
<experimental/unordered_set> (库基础 TS v2) | erase_if 与 erase_if
<experimental/vector> (库基础 TS v2) | erase 与 erase_if

范围 TS
<experimental/ranges/algorithm> (范围 TS) | 算法库
<experimental/ranges/concepts> (范围 TS) | 概念库
<experimental/ranges/functional> (范围 TS) | 函数对象
<experimental/ranges/iterator> (范围 TS) | 迭代器库
<experimental/ranges/random> (范围 TS) | UniformRandomNumberGenerator 概念
<experimental/ranges/range> (范围 TS) | 范围库
<experimental/ranges/tuple> (范围 TS) | 有标签元组
<experimental/ranges/type_traits> (范围 TS) | 元编程与类型特征
<experimental/ranges/utility> (范围 TS) | 工具组件

网络 TS
<experimental/buffer> (网络 TS) | 缓冲区
<experimental/executor> (网络 TS) | 异步模型
<experimental/internet> (网络 TS) | 互联网协议
<experimental/io_context> (网络 TS) | 基本 I/O 服务
<experimental/net> (网络 TS) | 包含每个其他网络 TS 头文件的便利头文件
<experimental/netfwd> (网络 TS) | 含有主要网络 TS 组件的向前声明
<experimental/socket> (网络 TS) | 套接
<experimental/timer> (网络 TS) | 定时器

并行 TS v2
<experimental/algorithm> (并行 TS v2) | 非数值并行算法
<experimental/execution_policy> (并行 TS v2) | unseq 与 vec 策略
<experimental/simd> (并行 TS v2) | 数据并行类型
<experimental/task_block> (并行 TS v2) | 任务块

反射 TS
<experimental/reflect> (反射 TS) | 静态反射支持库

库基础 TS v3
<experimental/scope> (库基础 TS v3) | scope_exit 、 scope_fail 、 scope_success 及 unique_resource


实验性库头文件 <experimental/any>

< cpp‎ | header‎ | experimental

此头文件是库基础 TS (v1, v2) 的一部分。

类

名字 | 描述
bad_any_cast (库基础 TS) | 由失败的 any_cast 所抛出的异常。 (类)
any (库基础 TS) | 保有满足 ValueType 要求的任意类型的实例的对象。 (类)

函数

swap | 交换两个 any 实例 (函数)
any_cast | 对被容纳对象的类型安全访问 (函数模板)

概要

namespace std {
namespace experimental {
inline namespace fundamentals_v1 {

  class bad_any_cast : public bad_cast
  {
  public:
    virtual const char* what() const noexcept;
  };

  class any
  {
  public:
    // 6.3.1，any 构造/析构
    any() noexcept;

    any(const any& other);
    any(any&& x) noexcept;

    template <class ValueType>
        any(ValueType&& value);

    ~any();

    // 6.3.2，any 赋值
    any& operator=(const any& rhs);
    any& operator=(any&& rhs) noexcept;

    template <class ValueType>
      any& operator=(ValueType&& rhs);

    // 6.3.3，any 修改函数
    void clear() noexcept;
    void swap(any& rhs) noexcept;

    // 6.3.4，any 探察函数
    bool empty() const noexcept;
    const type_info& type() const noexcept;
  };

  // 6.4，非成员函数
  void swap(any& x, any& y) noexcept;

  template<class ValueType>
    ValueType any_cast(const any& operand);
  template<class ValueType>
    ValueType any_cast(any& operand);
  template<class ValueType>
    ValueType any_cast(any&& operand);

  template<class ValueType>
    const ValueType* any_cast(const any* operand) noexcept;
  template<class ValueType>
    ValueType* any_cast(any* operand) noexcept;

} // namespace fundamentals_v1
} // namespace experimental
} // namespace std


实验性库头文件 <experimental/filesystem>

< cpp‎ | header‎ | experimental

此头文件是文件系统库的一部分。

定义于命名空间 std::experimental::filesystem
定义于内联命名空间 std::experimental::filesystem::v1

类
path
 表示一个路径
(类)
filesystem_error
 文件系统错误时抛出的异常
(类)
directory_entry
 目录条目
(类)
directory_iterator
 指向目录内容的迭代器
(类)
recursive_directory_iterator
 指向目录及其子目录的内容的迭代器
(类)
file_status
 表示文件类型及权限
(类)
space_info
 关于文件系统上自由及可用空间的信息
(类)
file_type
 文件的类型
(枚举)
perms
 标识文件系统权限
(枚举)
copy_options
 指定复制操作的语义
(枚举)
directory_options
 用于迭代目录内容的选项
(枚举)
file_time_type
 表示文件时间值
(typedef)

函数
swap(std::experimental::filesystem::path)
 交换两个路径
(函数)
hash_value
 计算 path 对象的散列值
(函数)
operator==operator!=operator<operator<=operator>operator>=
 按字典序比较两个路径
(函数)
operator/
 以一个目录分隔符连接两个路径
(函数)
operator<<operator>>
 实施 path 的流输入/输出
(函数)
u8path
 从 UTF-8 编码的源创建 path
(函数)
filesystem::begin(filesystem::directory_iterator)filesystem::end(filesystem::directory_iterator)
 支持基于范围的 for 循环
(函数)
filesystem::begin(filesystem::recursive_directory_iterator)filesystem::end(filesystem::recursive_directory_iterator)
 支持基于范围的 for 循环
(函数)
absolutesystem_complete
 组成一个绝对路径
转换路径为绝对路径，复现 OS 特定的行为
(函数)
canonical
 组成一个规范路径
(函数)
copy
 复制文件或目录
(函数)
copy_file
 复制文件内容
(函数)
copy_symlink
 复制一个符号链接
(函数)
create_directorycreate_directories
 创建新目录
(函数)
create_hard_link
 创建一个硬链接
(函数)
create_symlinkcreate_directory_symlink
 创建一个符号链接
(函数)
current_path
 返回当前工作目录
(函数)
exists
 检查路径是否指代既存的文件系统对象
(函数)
equivalent
 检查两个路径是否指代同一文件系统对象
(函数)
file_size
 返回文件的大小
(函数)
hard_link_count
 返回指代特定文件的硬链接数
(函数)
last_write_time
 获取或设置最近一次数据修改的时间
(函数)
permissions
 修改文件访问权限
(函数)
read_symlink
 获得符号链接的目标
(函数)
removeremove_all
 移除一个文件或空目录
移除一个文件或递归地移除一个目录与其全部内容
(函数)
rename
 移动或重命名一个文件或目录
(函数)
resize_file
 以截断或填充零更改一个常规文件的大小
(函数)
space
 确定文件系统上的可用空闲空间
(函数)
statussymlink_status
 确定文件属性
确定文件属性，检查符号链接目标
(函数)
temp_directory_path
 返回一个适用于临时文件的目录
(函数)
文件类型
is_block_file
 检查给定路径是否指代块设备
(函数)
is_character_file
 检查给定路径是否指代字符设备
(函数)
is_directory
 检查给定路径是否指代一个目录
(函数)
is_empty
 检查给定路径是否指代一个空的文件或目录
(函数)
is_fifo
 检查给定路径是否指代一个命名管道
(函数)
is_other
 检查参数是否指代一个其他文件
(函数)
is_regular_file
 检查参数是否指代一个常规文件
(函数)
is_socket
 检查参数是否指代一个具名 IPC 套接字
(函数)
is_symlink
 检查参数是否指代一个符号链接
(函数)
status_known
 检查文件状态是否已知
(函数)


实验性库头文件 <experimental/memory_resource>

< cpp‎ | header‎ | experimental

此头文件是库基础 TS (v1, v2, v3) 的一部分。

类

定义于命名空间 std::experimental::pmr
memory_resource | 一个抽象接口，用于各种封装内存资源的类 (类)
synchronized_pool_resource | 线程安全的 memory_resource，用于管理具有不同块大小的池中的分配 (类)
unsynchronized_pool_resource | 线程不安全的 memory_resource，用于管理具有不同块大小的池中的分配 (类)
monotonic_buffer_resource | 一种特殊用途的 memory_resource，仅在资源被销毁时才释放所分配内存 (类)
polymorphic_allocator | 以 memory_resource 构造，支持基于它的运行时多态的分配器 (类模板)
resource_adaptor | 适配一个分配器为一个 memory_resource (别名模板)

函数

定义于命名空间 std::experimental::pmr
比较
operator==operator!=
 比较两个 memory_resource
(函数)
operator==operator!=
 比较两个分配器
(函数模板)
全局内存资源
new_delete_resource
 返回一个静态的程序范围 memory_resource，它使用全局 operator new 与 operator delete 分配和解分配内存
(函数)
null_memory_resource
 返回一个不进行任何分配的静态 memory_resource
(函数)
缺省内存资源
get_default_resource
 获取缺省 memory_resource
(函数)
set_default_resource
 设置缺省 memory_resource
(函数)

概要

namespace std {
namespace experimental {
inline namespace fundamentals_v1 {
namespace pmr {

  class memory_resource;

  bool operator==(const memory_resource& a,
                  const memory_resource& b) noexcept;
  bool operator!=(const memory_resource& a,
                  const memory_resource& b) noexcept;

  template <class Tp> class polymorphic_allocator;

  template <class T1, class T2>
  bool operator==(const polymorphic_allocator<T1>& a,
                  const polymorphic_allocator<T2>& b) noexcept;
  template <class T1, class T2>
  bool operator!=(const polymorphic_allocator<T1>& a,
                  const polymorphic_allocator<T2>& b) noexcept;

  // 名字 resource_adaptor_imp 仅用于阐释。
  template <class Allocator> class resource_adaptor_imp;

  template <class Allocator>
    using resource_adaptor = resource_adaptor_imp<
      typename allocator_traits<Allocator>::template rebind_alloc<char>>;

  // 全局内存资源
  memory_resource* new_delete_resource() noexcept;
  memory_resource* null_memory_resource() noexcept;

  // 缺省内存资源
  memory_resource* set_default_resource(memory_resource* r) noexcept;
  memory_resource* get_default_resource() noexcept;

  // 标准内存资源
  struct pool_options;
  class synchronized_pool_resource;
  class unsynchronized_pool_resource;
  class monotonic_buffer_resource;

} // namespace pmr
} // namespace fundamentals_v1
} // namespace experimental
} // namespace std


实验性库头文件 <experimental/optional>

< cpp‎ | header‎ | experimental

此头文件是库基础 TS (v1, v2) 的一部分。

类

名字 | 说明
optional (库基础 TS) | 可能或可能不保有一个对象的包装器 (类模板)
bad_optional_access (库基础 TS) | 指示进行了到不含值的 optional 的有检查访问的异常 (类)
in_place_t (库基础 TS) | 用于 optional 类型的就地构造的消歧义标签类型 (类)
std::hash<std::experimental::optional> | 特化 std::hash 算法 (类模板特化)
nullopt_t (库基础 TS) | 带未初始化状态的 optional 类型的指示器 (类)

函数

比较
operator==operator!=operator<operator<=operator>operator>=
 比较 optional 对象
(函数模板)
特化的算法
std::swap(std::experimental::optional)
 特化 std::swap 算法
(函数)
make_optional
 创建一个 optional 对象
(函数模板)
散列支持

概要

namespace std {
  namespace experimental {
  inline namespace fundamentals_v1 {

    // 5.4，用于对象类型的 optional
    template <class T> class optional;

    // 5.5，就地构造
    struct in_place_t{};
    constexpr in_place_t in_place{};

    // 5.6，无值状态指示器
    struct nullopt_t{see below};
    constexpr nullopt_t nullopt(unspecified);

    // 5.7，类 bad_optional_access
    class bad_optional_access;

    // 5.8，关系运算符
    template <class T>
      constexpr bool operator==(const optional<T>&, const optional<T>&);
    template <class T>
      constexpr bool operator!=(const optional<T>&, const optional<T>&);
    template <class T>
      constexpr bool operator<(const optional<T>&, const optional<T>&);
    template <class T>
      constexpr bool operator>(const optional<T>&, const optional<T>&);
    template <class T>
      constexpr bool operator<=(const optional<T>&, const optional<T>&);
    template <class T>
      constexpr bool operator>=(const optional<T>&, const optional<T>&);

    // 5.9，与 nullopt 比较
    template <class T> constexpr bool operator==(const optional<T>&, nullopt_t) noexcept;
    template <class T> constexpr bool operator==(nullopt_t, const optional<T>&) noexcept;
    template <class T> constexpr bool operator!=(const optional<T>&, nullopt_t) noexcept;
    template <class T> constexpr bool operator!=(nullopt_t, const optional<T>&) noexcept;
    template <class T> constexpr bool operator<(const optional<T>&, nullopt_t) noexcept;
    template <class T> constexpr bool operator<(nullopt_t, const optional<T>&) noexcept;
    template <class T> constexpr bool operator<=(const optional<T>&, nullopt_t) noexcept;
    template <class T> constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept;
    template <class T> constexpr bool operator>(const optional<T>&, nullopt_t) noexcept;
    template <class T> constexpr bool operator>(nullopt_t, const optional<T>&) noexcept;
    template <class T> constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept;
    template <class T> constexpr bool operator>=(nullopt_t, const optional<T>&) noexcept;

    // 5.10，与 T 比较
    template <class T> constexpr bool operator==(const optional<T>&, const T&);
    template <class T> constexpr bool operator==(const T&, const optional<T>&);
    template <class T> constexpr bool operator!=(const optional<T>&, const T&);
    template <class T> constexpr bool operator!=(const T&, const optional<T>&);
    template <class T> constexpr bool operator<(const optional<T>&, const T&);
    template <class T> constexpr bool operator<(const T&, const optional<T>&);
    template <class T> constexpr bool operator<=(const optional<T>&, const T&);
    template <class T> constexpr bool operator<=(const T&, const optional<T>&);
    template <class T> constexpr bool operator>(const optional<T>&, const T&);
    template <class T> constexpr bool operator>(const T&, const optional<T>&);
    template <class T> constexpr bool operator>=(const optional<T>&, const T&);
    template <class T> constexpr bool operator>=(const T&, const optional<T>&);

    // 5.11，特化的算法
    template <class T> void swap(optional<T>&, optional<T>&) noexcept(see below);
    template <class T> constexpr optional<see below> make_optional(T&&);

  } // namespace fundamentals_v1
  } // namespace experimental

  // 5.12，散列支持
  template <class T> struct hash;
  template <class T> struct hash<experimental::optional<T>>;

} // namespace std


实验性库头文件 <experimental/ranges/algorithm>

< cpp‎ | header‎ | experimental

此头文件是范围库的一部分。

标签说明符

定义于命名空间 std::experimental::ranges::tag
inin1in2outout1out2funminmaxbeginend
 用于 ranges::tagged 的标签说明符
(类)

不修改序列的操作

定义于命名空间 std::experimental::ranges
all_ofany_ofnone_of | 检查谓词是否对范围中所有、任一或无元素为 true (函数模板)
for_each | 应用函数到元素范围 (函数模板)
countcount_if | 返回满足特定判别标准的元素数 (函数模板)
mismatch | 寻找两个范围出现不同的首个位置 (函数模板)
equal | 确定元素的二个集合是否相同 (函数模板)
lexicographical_compare | 当一个范围按字典顺序小于另一个范围时，返回 true (函数模板)
findfind_iffind_if_not | 寻找首个满足特定判别标准的元素 (函数模板)
find_end | 在特定范围中寻找最后出现的元素序列 (函数模板)
find_first_of | 搜索元素集中的任何元素 (函数模板)
adjacent_find | 寻找头两个相等（或满足给定谓词）的相邻项 (函数模板)
search | 搜索一个元素范围 (函数模板)
search_n | 在范围中搜索一定量的某个元素的连续副本 (函数模板)

修改序列的操作

定义于命名空间 std::experimental::ranges
copycopy_if | 将某一范围的元素复制到一个新的位置 (函数模板)
copy_n | 将一定数目的元素复制到一个新的位置 (函数模板)
copy_backward | 按从后往前的顺序复制一个范围内的元素 (函数模板)
move | 将某一范围的元素移动到一个新的位置 (函数模板)
move_backward | 按从后往前的顺序移动某一范围的元素到新的位置 (函数模板)
fill | 将一个特定值赋值给一个元素范围 (函数模板)
fill_n | 将一个值赋值给一定数量的元素 (函数模板)
transform | 应用一个函数到元素范围 (函数模板)
generate | 保存函数结果于一个范围中 (函数模板)
generate_n | 保存 N 次应用一个函数的结果 (函数模板)
removeremove_if | 移除满足特定判别标准的元素 (函数模板)
remove_copyremove_copy_if | 复制元素范围，忽略满足特定判别标准的元素 (函数模板)
replacereplace_if | 将所有满足特定判别标准的值替换为另一值 (函数模板)
replace_copyreplace_copy_if | 复制范围，以另一值替换满足特定判别标准的元素 (函数模板)
swap_ranges | 交换两个元素范围 (函数模板)
reverse | 逆转范围中的元素顺序 (函数模板)
reverse_copy | 创建一个范围的逆向副本 (函数模板)
rotate | 旋转范围中的元素顺序 (函数模板)
rotate_copy | 复制并旋转元素范围 (函数模板)
shuffle | 随机重排范围中的元素 (函数模板)
unique | 移除范围中连续的重复元素 (函数模板)
unique_copy | 创建某范围的不含连续重复元素的副本 (函数模板)

划分操作

定义于命名空间 std::experimental::ranges
is_partitioned | 判断范围是否已按给定的谓词划分 (函数模板)
partition | 将范围中的元素分为两组 (函数模板)
partition_copy | 复制一个范围，将各元素分为两组 (函数模板)
stable_partition | 划分元素到两个组中，同时保持其相对顺序 (函数模板)
partition_point | 定位已划分范围的划分点 (函数模板)

排序操作

定义于命名空间 std::experimental::ranges
is_sorted | 检查范围是否以升序排序 (函数模板)
is_sorted_until | 寻找最大已排序子范围 (函数模板)
sort | 将范围按升序排序 (函数模板)
partial_sort | 排序一个范围的前 N 个元素 (函数模板)
partial_sort_copy | 对范围内的元素进行复制并部分排序 (函数模板)
stable_sort | 将范围内的元素排序，同时保持相等的元素之间的顺序 (函数模板)
nth_element | 将给定的范围部分排序，确保其按给定元素划分 (函数模板)

（已排序范围上的）二分搜索操作

定义于命名空间 std::experimental::ranges
lower_bound | 返回指向首个不小于给定值的元素的迭代器 (函数模板)
upper_bound | 返回指向首个大于固定值的元素的迭代器 (函数模板)
binary_search | 确定元素是否存在于固定范围中 (函数模板)
equal_range | 返回匹配特定关键的元素范围 (函数模板)

（已排序范围上的）集合操作

定义于命名空间 std::experimental::ranges
merge | 归并两个已排序范围 (函数模板)
inplace_merge | 就地归并两个已排序范围 (函数模板)
includes | 若一个集合是另一个的子集则返回 true (函数模板)
set_difference | 计算两个集合的差集 (函数模板)
set_intersection | 计算两个集合的交集 (函数模板)
set_symmetric_difference | 计算两个集合的对称差 (函数模板)
set_union | 计算两个集合的并集 (函数模板)

堆操作

定义于命名空间 std::experimental::ranges
is_heap | 检查给定范围是否为一个最大堆 (函数模板)
is_heap_until | 寻找作为最大堆的最大子范围 (函数模板)
make_heap | 从元素范围中创建出最大堆 (函数模板)
push_heap | 添加元素到最大堆 (函数模板)
pop_heap | 从最大堆移除最大元素 (函数模板)
sort_heap | 将最大堆转化成以升序排序的元素范围 (函数模板)

最小/最大操作

定义于命名空间 std::experimental::ranges
max | 返回给定值的较大者 (函数模板)
max_element | 返回范围中的最大元素 (函数模板)
min | 返回给定值的较小者 (函数模板)
min_element | 返回范围中的最小元素 (函数模板)
minmax | 返回二个元素的较小和较大者 (函数模板)
minmax_element | 返回范围中的最小和最大元素 (函数模板)

排列操作

定义于命名空间 std::experimental::ranges
is_permutation | 判断一个序列是否为另一个序列的排列 (函数模板)
next_permutation | 产生某个元素范围的按字典顺序的下一个较大的排列 (函数模板)
prev_permutation | 产生某个元素范围的按字典顺序的下一个较小的排列 (函数模板)

概要

#include <initializer_list>

namespace std { namespace experimental { namespace ranges { inline namespace v1 {

namespace tag {
  struct in;
  struct in1;
  struct in2;
  struct out;
  struct out1;
  struct out2;
  struct fun;
  struct min;
  struct max;
  struct begin;
  struct end;
}

template <InputIterator I, Sentinel<I> S, class Proj = identity,
    IndirectUnaryPredicate<projected<I, Proj>> Pred>
  bool all_of(I first, S last, Pred pred, Proj proj = Proj{});

template <InputRange Rng, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  bool all_of(Rng&& rng, Pred pred, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, class Proj = identity,
    IndirectUnaryPredicate<projected<I, Proj>> Pred>
  bool any_of(I first, S last, Pred pred, Proj proj = Proj{});

template <InputRange Rng, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  bool any_of(Rng&& rng, Pred pred, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, class Proj = identity,
    IndirectUnaryPredicate<projected<I, Proj>> Pred>
  bool none_of(I first, S last, Pred pred, Proj proj = Proj{});

template <InputRange Rng, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  bool none_of(Rng&& rng, Pred pred, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, class Proj = identity,
    IndirectUnaryInvocable<projected<I, Proj>> Fun>
  tagged_pair<tag::in(I), tag::fun(Fun)>
    for_each(I first, S last, Fun f, Proj proj = Proj{});

template <InputRange Rng, class Proj = identity,
    IndirectUnaryInvocable<projected<iterator_t<Rng>, Proj>> Fun>
  tagged_pair<tag::in(safe_iterator_t<Rng>), tag::fun(Fun)>
    for_each(Rng&& rng, Fun f, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, class T, class Proj = identity>
  requires IndirectRelation<equal_to<>, projected<I, Proj>, const T*>
  I find(I first, S last, const T& value, Proj proj = Proj{});

template <InputRange Rng, class T, class Proj = identity>
  requires IndirectRelation<equal_to<>, projected<iterator_t<Rng>, Proj>, const T*>
  safe_iterator_t<Rng>
    find(Rng&& rng, const T& value, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, class Proj = identity,
    IndirectUnaryPredicate<projected<I, Proj>> Pred>
  I find_if(I first, S last, Pred pred, Proj proj = Proj{});

template <InputRange Rng, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  safe_iterator_t<Rng>
    find_if(Rng&& rng, Pred pred, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, class Proj = identity,
    IndirectUnaryPredicate<projected<I, Proj>> Pred>
  I find_if_not(I first, S last, Pred pred, Proj proj = Proj{});

template <InputRange Rng, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  safe_iterator_t<Rng>
    find_if_not(Rng&& rng, Pred pred, Proj proj = Proj{});

template <ForwardIterator I1, Sentinel<I1> S1, ForwardIterator I2,
    Sentinel<I2> S2, class Proj = identity,
    IndirectRelation<I2, projected<I1, Proj>> Pred = equal_to<>>
  I1
    find_end(I1 first1, S1 last1, I2 first2, S2 last2,
             Pred pred = Pred{}, Proj proj = Proj{});

template <ForwardRange Rng1, ForwardRange Rng2, class Proj = identity,
    IndirectRelation<iterator_t<Rng2>,
      projected<iterator_t<Rng>, Proj>> Pred = equal_to<>>
  safe_iterator_t<Rng1>
    find_end(Rng1&& rng1, Rng2&& rng2, Pred pred = Pred{}, Proj proj = Proj{});

template <InputIterator I1, Sentinel<I1> S1, ForwardIterator I2, Sentinel<I2> S2,
    class Proj1 = identity, class Proj2 = identity,
    IndirectRelation<projected<I1, Proj1>, projected<I2, Proj2>> Pred = equal_to<>>
  I1
    find_first_of(I1 first1, S1 last1, I2 first2, S2 last2,
                  Pred pred = Pred{},
                  Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputRange Rng1, ForwardRange Rng2, class Proj1 = identity,
    class Proj2 = identity,
    IndirectRelation<projected<iterator_t<Rng1>, Proj1>,
      projected<iterator_t<Rng2>, Proj2>> Pred = equal_to<>>
  safe_iterator_t<Rng1>
    find_first_of(Rng1&& rng1, Rng2&& rng2,
                  Pred pred = Pred{},
                  Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <ForwardIterator I, Sentinel<I> S, class Proj = identity,
    IndirectRelation<projected<I, Proj>> Pred = equal_to<>>
  I
    adjacent_find(I first, S last, Pred pred = Pred{},
                  Proj proj = Proj{});

template <ForwardRange Rng, class Proj = identity,
    IndirectRelation<projected<iterator_t<Rng>, Proj>> Pred = equal_to<>>
  safe_iterator_t<Rng>
    adjacent_find(Rng&& rng, Pred pred = Pred{}, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, class T, class Proj = identity>
  requires IndirectRelation<equal_to<>, projected<I, Proj>, const T*>
  difference_type_t<I>
    count(I first, S last, const T& value, Proj proj = Proj{});

template <InputRange Rng, class T, class Proj = identity>
  requires IndirectRelation<equal_to<>, projected<iterator_t<Rng>, Proj>, const T*>
  difference_type_t<iterator_t<Rng>>
    count(Rng&& rng, const T& value, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, class Proj = identity,
    IndirectUnaryPredicate<projected<I, Proj>> Pred>
  difference_type_t<I>
    count_if(I first, S last, Pred pred, Proj proj = Proj{});

template <InputRange Rng, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  difference_type_t<iterator_t<Rng>>
    count_if(Rng&& rng, Pred pred, Proj proj = Proj{});

template <InputIterator I1, Sentinel<I1> S1, InputIterator I2, Sentinel<I2> S2,
    class Proj1 = identity, class Proj2 = identity,
    IndirectRelation<projected<I1, Proj1>, projected<I2, Proj2>> Pred = equal_to<>>
  tagged_pair<tag::in1(I1), tag::in2(I2)>
    mismatch(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = Pred{},
             Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputRange Rng1, InputRange Rng2,
    class Proj1 = identity, class Proj2 = identity,
    IndirectRelation<projected<iterator_t<Rng1>, Proj1>,
      projected<iterator_t<Rng2>, Proj2>> Pred = equal_to<>>
  tagged_pair<tag::in1(safe_iterator_t<Rng1>),
              tag::in2(safe_iterator_t<Rng2>)>
    mismatch(Rng1&& rng1, Rng2&& rng2, Pred pred = Pred{},
             Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputIterator I1, Sentinel<I1> S1, InputIterator I2, Sentinel<I2> S2,
    class Pred = equal_to<>, class Proj1 = identity, class Proj2 = identity>
  requires IndirectlyComparable<I1, I2, Pred, Proj1, Proj2>
  bool equal(I1 first1, S1 last1, I2 first2, S2 last2,
             Pred pred = Pred{},
             Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputRange Rng1, InputRange Rng2, class Pred = equal_to<>,
    class Proj1 = identity, class Proj2 = identity>
  requires IndirectlyComparable<iterator_t<Rng1>, iterator_t<Rng2>, Pred, Proj1, Proj2>
  bool equal(Rng1&& rng1, Rng2&& rng2, Pred pred = Pred{},
             Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <ForwardIterator I1, Sentinel<I1> S1, ForwardIterator I2,
    Sentinel<I2> S2, class Pred = equal_to<>, class Proj1 = identity,
    class Proj2 = identity>
  requires IndirectlyComparable<I1, I2, Pred, Proj1, Proj2>
  bool is_permutation(I1 first1, S1 last1, I2 first2, S2 last2,
                      Pred pred = Pred{},
                      Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <ForwardRange Rng1, ForwardRange Rng2, class Pred = equal_to<>,
    class Proj1 = identity, class Proj2 = identity>
  requires IndirectlyComparable<iterator_t<Rng1>, iterator_t<Rng2>, Pred, Proj1, Proj2>
  bool is_permutation(Rng1&& rng1, Rng2&& rng2, Pred pred = Pred{},
                      Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <ForwardIterator I1, Sentinel<I1> S1, ForwardIterator I2,
    Sentinel<I2> S2, class Pred = equal_to<>,
    class Proj1 = identity, class Proj2 = identity>
  requires IndirectlyComparable<I1, I2, Pred, Proj1, Proj2>
  I1
    search(I1 first1, S1 last1, I2 first2, S2 last2,
           Pred pred = Pred{},
           Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <ForwardRange Rng1, ForwardRange Rng2, class Pred = equal_to<>,
    class Proj1 = identity, class Proj2 = identity>
  requires IndirectlyComparable<iterator_t<Rng1>, iterator_t<Rng2>, Pred, Proj1, Proj2>
  safe_iterator_t<Rng1>
    search(Rng1&& rng1, Rng2&& rng2, Pred pred = Pred{},
           Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <ForwardIterator I, Sentinel<I> S, class T,
    class Pred = equal_to<>, class Proj = identity>
  requires IndirectlyComparable<I, const T*, Pred, Proj>
  I
    search_n(I first, S last, difference_type_t<I> count,
             const T& value, Pred pred = Pred{},
             Proj proj = Proj{});

template <ForwardRange Rng, class T, class Pred = equal_to<>,
    class Proj = identity>
  requires IndirectlyComparable<iterator_t<Rng>, const T*, Pred, Proj>
  safe_iterator_t<Rng>
    search_n(Rng&& rng, difference_type_t<iterator_t<Rng>> count,
             const T& value, Pred pred = Pred{}, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, WeaklyIncrementable O>
  requires IndirectlyCopyable<I, O>
  tagged_pair<tag::in(I), tag::out(O)>
    copy(I first, S last, O result);

template <InputRange Rng, WeaklyIncrementable O>
  requires IndirectlyCopyable<iterator_t<Rng>, O>
  tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(O)>
    copy(Rng&& rng, O result);

template <InputIterator I, WeaklyIncrementable O>
  requires IndirectlyCopyable<I, O>
  tagged_pair<tag::in(I), tag::out(O)>
    copy_n(I first, difference_type_t<I> n, O result);

template <InputIterator I, Sentinel<I> S, WeaklyIncrementable O, class Proj = identity,
    IndirectUnaryPredicate<projected<I, Proj>> Pred>
  requires IndirectlyCopyable<I, O>
  tagged_pair<tag::in(I), tag::out(O)>
    copy_if(I first, S last, O result, Pred pred, Proj proj = Proj{});

template <InputRange Rng, WeaklyIncrementable O, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  requires IndirectlyCopyable<iterator_t<Rng>, O>
  tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(O)>
    copy_if(Rng&& rng, O result, Pred pred, Proj proj = Proj{});

template <BidirectionalIterator I1, Sentinel<I1> S1, BidirectionalIterator I2>
  requires IndirectlyCopyable<I1, I2>
  tagged_pair<tag::in(I1), tag::out(I2)>
    copy_backward(I1 first, S1 last, I2 result);

template <BidirectionalRange Rng, BidirectionalIterator I>
  requires IndirectlyCopyable<iterator_t<Rng>, I>
  tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(I)>
    copy_backward(Rng&& rng, I result);

template <InputIterator I, Sentinel<I> S, WeaklyIncrementable O>
  requires IndirectlyMovable<I, O>
  tagged_pair<tag::in(I), tag::out(O)>
    move(I first, S last, O result);

template <InputRange Rng, WeaklyIncrementable O>
  requires IndirectlyMovable<iterator_t<Rng>, O>
  tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(O)>
    move(Rng&& rng, O result);

template <BidirectionalIterator I1, Sentinel<I1> S1, BidirectionalIterator I2>
  requires IndirectlyMovable<I1, I2>
  tagged_pair<tag::in(I1), tag::out(I2)>
    move_backward(I1 first, S1 last, I2 result);

template <BidirectionalRange Rng, BidirectionalIterator I>
  requires IndirectlyMovable<iterator_t<Rng>, I>
  tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(I)>
    move_backward(Rng&& rng, I result);

template <ForwardIterator I1, Sentinel<I1> S1, ForwardIterator I2, Sentinel<I2> S2>
  requires IndirectlySwappable<I1, I2>
  tagged_pair<tag::in1(I1), tag::in2(I2)>
    swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2);

template <ForwardRange Rng1, ForwardRange Rng2>
  requires IndirectlySwappable<iterator_t<Rng1>, iterator_t<Rng2>>
  tagged_pair<tag::in1(safe_iterator_t<Rng1>), tag::in2(safe_iterator_t<Rng2>)>
    swap_ranges(Rng1&& rng1, Rng2&& rng2);

template <InputIterator I, Sentinel<I> S, WeaklyIncrementable O,
    CopyConstructible F, class Proj = identity>
  requires Writable<O, indirect_result_of_t<F&(projected<I, Proj>)>>
  tagged_pair<tag::in(I), tag::out(O)>
    transform(I first, S last, O result, F op, Proj proj = Proj{});

template <InputRange Rng, WeaklyIncrementable O, CopyConstructible F,
    class Proj = identity>
  requires Writable<O, indirect_result_of_t<F&(
    projected<iterator_t<R>, Proj>)>>
  tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(O)>
    transform(Rng&& rng, O result, F op, Proj proj = Proj{});

template <InputIterator I1, Sentinel<I1> S1, InputIterator I2, Sentinel<I2> S2,
    WeaklyIncrementable O, CopyConstructible F, class Proj1 = identity,
    class Proj2 = identity>
  requires Writable<O, indirect_result_of_t<F&(projected<I1, Proj1>,
    projected<I2, Proj2>)>>
  tagged_tuple<tag::in1(I1), tag::in2(I2), tag::out(O)>
    transform(I1 first1, S1 last1, I2 first2, S2 last2, O result,
              F binary_op, Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputRange Rng1, InputRange Rng2, WeaklyIncrementable O,
    CopyConstructible F, class Proj1 = identity, class Proj2 = identity>
  requires Writable<O, indirect_result_of_t<F&(
    projected<iterator_t<Rng1>, Proj1>, projected<iterator_t<Rng2>, Proj2>)>>
  tagged_tuple<tag::in1(safe_iterator_t<Rng1>),
               tag::in2(safe_iterator_t<Rng2>),
               tag::out(O)>
    transform(Rng1&& rng1, Rng2&& rng2, O result,
              F binary_op, Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputIterator I, Sentinel<I> S, class T1, class T2, class Proj = identity>
  requires Writable<I, const T2&> &&
    IndirectRelation<equal_to<>, projected<I, Proj>, const T1*>
  I
    replace(I first, S last, const T1& old_value, const T2& new_value, Proj proj = Proj{});

template <InputRange Rng, class T1, class T2, class Proj = identity>
  requires Writable<iterator_t<Rng>, const T2&> &&
    IndirectRelation<equal_to<>, projected<iterator_t<Rng>, Proj>, const T1*>
  safe_iterator_t<Rng>
    replace(Rng&& rng, const T1& old_value, const T2& new_value, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, class T, class Proj = identity,
    IndirectUnaryPredicate<projected<I, Proj>> Pred>
  requires Writable<I, const T&>
  I
    replace_if(I first, S last, Pred pred, const T& new_value, Proj proj = Proj{});

template <InputRange Rng, class T, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  requires Writable<iterator_t<Rng>, const T&>
  safe_iterator_t<Rng>
    replace_if(Rng&& rng, Pred pred, const T& new_value, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, class T1, class T2, OutputIterator<const T2&> O,
    class Proj = identity>
  requires IndirectlyCopyable<I, O> &&
    IndirectRelation<equal_to<>, projected<I, Proj>, const T1*>
  tagged_pair<tag::in(I), tag::out(O)>
    replace_copy(I first, S last, O result, const T1& old_value, const T2& new_value,
                 Proj proj = Proj{});

template <InputRange Rng, class T1, class T2, OutputIterator<const T2&> O,
    class Proj = identity>
  requires IndirectlyCopyable<iterator_t<Rng>, O> &&
    IndirectRelation<equal_to<>, projected<iterator_t<Rng>, Proj>, const T1*>
  tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(O)>
    replace_copy(Rng&& rng, O result, const T1& old_value, const T2& new_value,
                 Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, class T, OutputIterator<const T&> O,
    class Proj = identity, IndirectUnaryPredicate<projected<I, Proj>> Pred>
  requires IndirectlyCopyable<I, O>
  tagged_pair<tag::in(I), tag::out(O)>
    replace_copy_if(I first, S last, O result, Pred pred, const T& new_value,
                    Proj proj = Proj{});

template <InputRange Rng, class T, OutputIterator<const T&> O, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  requires IndirectlyCopyable<iterator_t<Rng>, O>
  tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(O)>
    replace_copy_if(Rng&& rng, O result, Pred pred, const T& new_value,
                    Proj proj = Proj{});

template <class T, OutputIterator<const T&> O, Sentinel<O> S>
  O fill(O first, S last, const T& value);

template <class T, OutputRange<const T&> Rng>
  safe_iterator_t<Rng>
    fill(Rng&& rng, const T& value);

template <class T, OutputIterator<const T&> O>
  O fill_n(O first, difference_type_t<O> n, const T& value);

template <Iterator O, Sentinel<O> S, CopyConstructible F>
  requires Invocable<F&> && Writable<O, result_of_t<F&()>>
  O generate(O first, S last, F gen);

template <class Rng, CopyConstructible F>
  requires Invocable<F&> && OutputRange<Rng, result_of_t<F&()>>
  safe_iterator_t<Rng>
    generate(Rng&& rng, F gen);

template <Iterator O, CopyConstructible F>
  requires Invocable<F&> && Writable<O, result_of_t<F&()>>
  O generate_n(O first, difference_type_t<O> n, F gen);

template <ForwardIterator I, Sentinel<I> S, class T, class Proj = identity>
  requires Permutable<I> &&
    IndirectRelation<equal_to<>, projected<I, Proj>, const T*>
  I remove(I first, S last, const T& value, Proj proj = Proj{});

template <ForwardRange Rng, class T, class Proj = identity>
  requires Permutable<iterator_t<Rng>> &&
    IndirectRelation<equal_to<>, projected<iterator_t<Rng>, Proj>, const T*>
  safe_iterator_t<Rng>
    remove(Rng&& rng, const T& value, Proj proj = Proj{});

template <ForwardIterator I, Sentinel<I> S, class Proj = identity,
    IndirectUnaryPredicate<projected<I, Proj>> Pred>
  requires Permutable<I>
    I remove_if(I first, S last, Pred pred, Proj proj = Proj{});

template <ForwardRange Rng, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  requires Permutable<iterator_t<Rng>>
  safe_iterator_t<Rng>
    remove_if(Rng&& rng, Pred pred, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, WeaklyIncrementable O, class T,
    class Proj = identity>
  requires IndirectlyCopyable<I, O> &&
    IndirectRelation<equal_to<>, projected<I, Proj>, const T*>
  tagged_pair<tag::in(I), tag::out(O)>
    remove_copy(I first, S last, O result, const T& value, Proj proj = Proj{});

template <InputRange Rng, WeaklyIncrementable O, class T, class Proj = identity>
  requires IndirectlyCopyable<iterator_t<Rng>, O> &&
    IndirectRelation<equal_to<>, projected<iterator_t<Rng>, Proj>, const T*>
  tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(O)>
    remove_copy(Rng&& rng, O result, const T& value, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, WeaklyIncrementable O,
    class Proj = identity, IndirectUnaryPredicate<projected<I, Proj>> Pred>
  requires IndirectlyCopyable<I, O>
  tagged_pair<tag::in(I), tag::out(O)>
    remove_copy_if(I first, S last, O result, Pred pred, Proj proj = Proj{});

template <InputRange Rng, WeaklyIncrementable O, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  requires IndirectlyCopyable<iterator_t<Rng>, O>
  tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(O)>
    remove_copy_if(Rng&& rng, O result, Pred pred, Proj proj = Proj{});

template <ForwardIterator I, Sentinel<I> S, class Proj = identity,
    IndirectRelation<projected<I, Proj>> R = equal_to<>>
  requires Permutable<I>
  I unique(I first, S last, R comp = R{}, Proj proj = Proj{});

template <ForwardRange Rng, class Proj = identity,
    IndirectRelation<projected<iterator_t<Rng>, Proj>> R = equal_to<>>
  requires Permutable<iterator_t<Rng>>
  safe_iterator_t<Rng>
    unique(Rng&& rng, R comp = R{}, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, WeaklyIncrementable O,
    class Proj = identity, IndirectRelation<projected<I, Proj>> R = equal_to<>>
  requires IndirectlyCopyable<I, O> &&
    (ForwardIterator<I> ||
    (InputIterator<O> && Same<value_type_t<I>, value_type_t<O>>) ||
    IndirectlyCopyableStorable<I, O>)
  tagged_pair<tag::in(I), tag::out(O)>
    unique_copy(I first, S last, O result, R comp = R{}, Proj proj = Proj{});

template <InputRange Rng, WeaklyIncrementable O, class Proj = identity,
    IndirectRelation<projected<iterator_t<Rng>, Proj>> R = equal_to<>>
  requires IndirectlyCopyable<iterator_t<Rng>, O> &&
    (ForwardIterator<iterator_t<Rng>> ||
    (InputIterator<O> && Same<value_type_t<iterator_t<Rng>>, value_type_t<O>>) ||
    IndirectlyCopyableStorable<iterator_t<Rng>, O>)
  tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(O)>
    unique_copy(Rng&& rng, O result, R comp = R{}, Proj proj = Proj{});

template <BidirectionalIterator I, Sentinel<I> S>
  requires Permutable<I>
  I reverse(I first, S last);

template <BidirectionalRange Rng>
  requires Permutable<iterator_t<Rng>>
  safe_iterator_t<Rng>
    reverse(Rng&& rng);

template <BidirectionalIterator I, Sentinel<I> S, WeaklyIncrementable O>
  requires IndirectlyCopyable<I, O>
  tagged_pair<tag::in(I), tag::out(O)> reverse_copy(I first, S last, O result);

template <BidirectionalRange Rng, WeaklyIncrementable O>
  requires IndirectlyCopyable<iterator_t<Rng>, O>
  tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(O)>
    reverse_copy(Rng&& rng, O result);

template <ForwardIterator I, Sentinel<I> S>
  requires Permutable<I>
  tagged_pair<tag::begin(I), tag::end(I)>
    rotate(I first, I middle, S last);

template <ForwardRange Rng>
  requires Permutable<iterator_t<Rng>>
  tagged_pair<tag::begin(safe_iterator_t<Rng>),
              tag::end(safe_iterator_t<Rng>)>
    rotate(Rng&& rng, iterator_t<Rng> middle);

template <ForwardIterator I, Sentinel<I> S, WeaklyIncrementable O>
  requires IndirectlyCopyable<I, O>
  tagged_pair<tag::in(I), tag::out(O)>
    rotate_copy(I first, I middle, S last, O result);

template <ForwardRange Rng, WeaklyIncrementable O>
  requires IndirectlyCopyable<iterator_t<Rng>, O>
  tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(O)>
    rotate_copy(Rng&& rng, iterator_t<Rng> middle, O result);

template <RandomAccessIterator I, Sentinel<I> S, class Gen>
  requires Permutable<I> &&
    UniformRandomNumberGenerator<remove_reference_t<Gen>> &&
    ConvertibleTo<result_of_t<Gen&()>, difference_type_t<I>>
  I shuffle(I first, S last, Gen&& g);

template <RandomAccessRange Rng, class Gen>
  requires Permutable<I> &&
    UniformRandomNumberGenerator<remove_reference_t<Gen>> &&
    ConvertibleTo<result_of_t<Gen&()>, difference_type_t<I>>
  safe_iterator_t<Rng>
    shuffle(Rng&& rng, Gen&& g);

template <InputIterator I, Sentinel<I> S, class Proj = identity,
    IndirectUnaryPredicate<projected<I, Proj>> Pred>
  bool is_partitioned(I first, S last, Pred pred, Proj proj = Proj{});

template <InputRange Rng, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  bool
    is_partitioned(Rng&& rng, Pred pred, Proj proj = Proj{});

template <ForwardIterator I, Sentinel<I> S, class Proj = identity,
    IndirectUnaryPredicate<projected<I, Proj>> Pred>
  requires Permutable<I>
    I partition(I first, S last, Pred pred, Proj proj = Proj{});

template <ForwardRange Rng, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  requires Permutable<iterator_t<Rng>>
  safe_iterator_t<Rng>
    partition(Rng&& rng, Pred pred, Proj proj = Proj{});

template <BidirectionalIterator I, Sentinel<I> S, class Proj = identity,
    IndirectUnaryPredicate<projected<I, Proj>> Pred>
  requires Permutable<I>
  I stable_partition(I first, S last, Pred pred, Proj proj = Proj{});

template <BidirectionalRange Rng, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  requires Permutable<iterator_t<Rng>>
  safe_iterator_t<Rng>
    stable_partition(Rng&& rng, Pred pred, Proj proj = Proj{});

template <InputIterator I, Sentinel<I> S, WeaklyIncrementable O1, WeaklyIncrementable O2,
    class Proj = identity, IndirectUnaryPredicate<projected<I, Proj>> Pred>
  requires IndirectlyCopyable<I, O1> && IndirectlyCopyable<I, O2>
  tagged_tuple<tag::in(I), tag::out1(O1), tag::out2(O2)>
    partition_copy(I first, S last, O1 out_true, O2 out_false, Pred pred,
                   Proj proj = Proj{});

template <InputRange Rng, WeaklyIncrementable O1, WeaklyIncrementable O2,
    class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  requires IndirectlyCopyable<iterator_t<Rng>, O1> &&
    IndirectlyCopyable<iterator_t<Rng>, O2>
  tagged_tuple<tag::in(safe_iterator_t<Rng>), tag::out1(O1), tag::out2(O2)>
    partition_copy(Rng&& rng, O1 out_true, O2 out_false, Pred pred, Proj proj = Proj{});

template <ForwardIterator I, Sentinel<I> S, class Proj = identity,
    IndirectUnaryPredicate<projected<I, Proj>> Pred>
  I partition_point(I first, S last, Pred pred, Proj proj = Proj{});

template <ForwardRange Rng, class Proj = identity,
    IndirectUnaryPredicate<projected<iterator_t<Rng>, Proj>> Pred>
  safe_iterator_t<Rng>
    partition_point(Rng&& rng, Pred pred, Proj proj = Proj{});

template <RandomAccessIterator I, Sentinel<I> S, class Comp = less<>,
    class Proj = identity>
  requires Sortable<I, Comp, Proj>
    I sort(I first, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessRange Rng, class Comp = less<>, class Proj = identity>
  requires Sortable<iterator_t<Rng>, Comp, Proj>
  safe_iterator_t<Rng>
    sort(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessIterator I, Sentinel<I> S, class Comp = less<>,
    class Proj = identity>
  requires Sortable<I, Comp, Proj>
    I stable_sort(I first, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessRange Rng, class Comp = less<>, class Proj = identity>
  requires Sortable<iterator_t<Rng>, Comp, Proj>
  safe_iterator_t<Rng>
    stable_sort(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessIterator I, Sentinel<I> S, class Comp = less<>,
    class Proj = identity>
  requires Sortable<I, Comp, Proj>
    I partial_sort(I first, I middle, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessRange Rng, class Comp = less<>, class Proj = identity>
  requires Sortable<iterator_t<Rng>, Comp, Proj>
  safe_iterator_t<Rng>
    partial_sort(Rng&& rng, iterator_t<Rng> middle, Comp comp = Comp{},
                 Proj proj = Proj{});

template <InputIterator I1, Sentinel<I1> S1, RandomAccessIterator I2, Sentinel<I2> S2,
    class Comp = less<>, class Proj1 = identity, class Proj2 = identity>
  requires IndirectlyCopyable<I1, I2> && Sortable<I2, Comp, Proj2> &&
    IndirectStrictWeakOrder<Comp, projected<I1, Proj1>, projected<I2, Proj2>>
  I2
    partial_sort_copy(I1 first, S1 last, I2 result_first, S2 result_last,
                      Comp comp = Comp{}, Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputRange Rng1, RandomAccessRange Rng2, class Comp = less<>,
    class Proj1 = identity, class Proj2 = identity>
  requires IndirectlyCopyable<iterator_t<Rng1>, iterator_t<Rng2>> &&
    Sortable<iterator_t<Rng2>, Comp, Proj2> &&
    IndirectStrictWeakOrder<Comp, projected<iterator_t<Rng1>, Proj1>,
      projected<iterator_t<Rng2>, Proj2>>
  safe_iterator_t<Rng2>
    partial_sort_copy(Rng1&& rng, Rng2&& result_rng, Comp comp = Comp{},
                      Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <ForwardIterator I, Sentinel<I> S, class Proj = identity,
    IndirectStrictWeakOrder<projected<I, Proj>> Comp = less<>>
  bool is_sorted(I first, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardRange Rng, class Proj = identity,
    IndirectStrictWeakOrder<projected<iterator_t<Rng>, Proj>> Comp = less<>>
  bool
    is_sorted(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardIterator I, Sentinel<I> S, class Proj = identity,
    IndirectStrictWeakOrder<projected<I, Proj>> Comp = less<>>
  I is_sorted_until(I first, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardRange Rng, class Proj = identity,
    IndirectStrictWeakOrder<projected<iterator_t<Rng>, Proj>> Comp = less<>>
  safe_iterator_t<Rng>
    is_sorted_until(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessIterator I, Sentinel<I> S, class Comp = less<>,
    class Proj = identity>
  requires Sortable<I, Comp, Proj>
    I nth_element(I first, I nth, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessRange Rng, class Comp = less<>, class Proj = identity>
  requires Sortable<iterator_t<Rng>, Comp, Proj>
  safe_iterator_t<Rng>
    nth_element(Rng&& rng, iterator_t<Rng> nth, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardIterator I, Sentinel<I> S, class T, class Proj = identity,
    IndirectStrictWeakOrder<const T*, projected<I, Proj>> Comp = less<>>
  I
    lower_bound(I first, S last, const T& value, Comp comp = Comp{},
                Proj proj = Proj{});

template <ForwardRange Rng, class T, class Proj = identity,
    IndirectStrictWeakOrder<const T*, projected<iterator_t<Rng>, Proj>> Comp = less<>>
  safe_iterator_t<Rng>
    lower_bound(Rng&& rng, const T& value, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardIterator I, Sentinel<I> S, class T, class Proj = identity,
    IndirectStrictWeakOrder<const T*, projected<I, Proj>> Comp = less<>>
  I
    upper_bound(I first, S last, const T& value, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardRange Rng, class T, class Proj = identity,
    IndirectStrictWeakOrder<const T*, projected<iterator_t<Rng>, Proj>> Comp = less<>>
  safe_iterator_t<Rng>
    upper_bound(Rng&& rng, const T& value, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardIterator I, Sentinel<I> S, class T, class Proj = identity,
    IndirectStrictWeakOrder<const T*, projected<I, Proj>> Comp = less<>>
  tagged_pair<tag::begin(I), tag::end(I)>
    equal_range(I first, S last, const T& value, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardRange Rng, class T, class Proj = identity,
    IndirectStrictWeakOrder<const T*, projected<iterator_t<Rng>, Proj>> Comp = less<>>
  tagged_pair<tag::begin(safe_iterator_t<Rng>),
              tag::end(safe_iterator_t<Rng>)>
    equal_range(Rng&& rng, const T& value, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardIterator I, Sentinel<I> S, class T, class Proj = identity,
    IndirectStrictWeakOrder<const T*, projected<I, Proj>> Comp = less<>>
  bool
    binary_search(I first, S last, const T& value, Comp comp = Comp{},
                  Proj proj = Proj{});

template <ForwardRange Rng, class T, class Proj = identity,
    IndirectStrictWeakOrder<const T*, projected<iterator_t<Rng>, Proj>> Comp = less<>>
  bool
    binary_search(Rng&& rng, const T& value, Comp comp = Comp{},
                  Proj proj = Proj{});

template <InputIterator I1, Sentinel<I1> S1, InputIterator I2, Sentinel<I2> S2,
    WeaklyIncrementable O, class Comp = less<>, class Proj1 = identity,
    class Proj2 = identity>
  requires Mergeable<I1, I2, O, Comp, Proj1, Proj2>
  tagged_tuple<tag::in1(I1), tag::in2(I2), tag::out(O)>
    merge(I1 first1, S1 last1, I2 first2, S2 last2, O result,
          Comp comp = Comp{}, Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputRange Rng1, InputRange Rng2, WeaklyIncrementable O, class Comp = less<>,
    class Proj1 = identity, class Proj2 = identity>
  requires Mergeable<iterator_t<Rng1>, iterator_t<Rng2>, O, Comp, Proj1, Proj2>
  tagged_tuple<tag::in1(safe_iterator_t<Rng1>),
               tag::in2(safe_iterator_t<Rng2>),
               tag::out(O)>
    merge(Rng1&& rng1, Rng2&& rng2, O result,
          Comp comp = Comp{}, Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <BidirectionalIterator I, Sentinel<I> S, class Comp = less<>,
    class Proj = identity>
  requires Sortable<I, Comp, Proj>
  I
    inplace_merge(I first, I middle, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <BidirectionalRange Rng, class Comp = less<>, class Proj = identity>
  requires Sortable<iterator_t<Rng>, Comp, Proj>
  safe_iterator_t<Rng>
    inplace_merge(Rng&& rng, iterator_t<Rng> middle, Comp comp = Comp{},
                  Proj proj = Proj{});

template <InputIterator I1, Sentinel<I1> S1, InputIterator I2, Sentinel<I2> S2,
    class Proj1 = identity, class Proj2 = identity,
    IndirectStrictWeakOrder<projected<I1, Proj1>, projected<I2, Proj2>> Comp = less<>>
  bool
    includes(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp = Comp{},
             Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputRange Rng1, InputRange Rng2, class Proj1 = identity,
    class Proj2 = identity,
    IndirectStrictWeakOrder<projected<iterator_t<Rng1>, Proj1>,
      projected<iterator_t<Rng2>, Proj2>> Comp = less<>>
  bool
    includes(Rng1&& rng1, Rng2&& rng2, Comp comp = Comp{},
             Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputIterator I1, Sentinel<I1> S1, InputIterator I2, Sentinel<I2> S2,
    WeaklyIncrementable O, class Comp = less<>,
    class Proj1 = identity, class Proj2 = identity>
  requires Mergeable<I1, I2, O, Comp, Proj1, Proj2>
  tagged_tuple<tag::in1(I1), tag::in2(I2), tag::out(O)>
    set_union(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = Comp{},
              Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputRange Rng1, InputRange Rng2, WeaklyIncrementable O,
    class Comp = less<>, class Proj1 = identity, class Proj2 = identity>
  requires Mergeable<iterator_t<Rng1>, iterator_t<Rng2>, O, Comp, Proj1, Proj2>
  tagged_tuple<tag::in1(safe_iterator_t<Rng1>),
               tag::in2(safe_iterator_t<Rng2>),
               tag::out(O)>
    set_union(Rng1&& rng1, Rng2&& rng2, O result, Comp comp = Comp{},
              Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputIterator I1, Sentinel<I1> S1, InputIterator I2, Sentinel<I2> S2,
    WeaklyIncrementable O, class Comp = less<>,
    class Proj1 = identity, class Proj2 = identity>
  requires Mergeable<I1, I2, O, Comp, Proj1, Proj2>
  O
    set_intersection(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                     Comp comp = Comp{}, Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputRange Rng1, InputRange Rng2, WeaklyIncrementable O,
    class Comp = less<>, class Proj1 = identity, class Proj2 = identity>
  requires Mergeable<iterator_t<Rng1>, iterator_t<Rng2>, O, Comp, Proj1, Proj2>
  O
    set_intersection(Rng1&& rng1, Rng2&& rng2, O result,
                     Comp comp = Comp{}, Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputIterator I1, Sentinel<I1> S1, InputIterator I2, Sentinel<I2> S2,
    WeaklyIncrementable O, class Comp = less<>,
    class Proj1 = identity, class Proj2 = identity>
  requires Mergeable<I1, I2, O, Comp, Proj1, Proj2>
  tagged_pair<tag::in1(I1), tag::out(O)>
    set_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                   Comp comp = Comp{}, Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputRange Rng1, InputRange Rng2, WeaklyIncrementable O,
    class Comp = less<>, class Proj1 = identity, class Proj2 = identity>
  requires Mergeable<iterator_t<Rng1>, iterator_t<Rng2>, O, Comp, Proj1, Proj2>
  tagged_pair<tag::in1(safe_iterator_t<Rng1>), tag::out(O)>
    set_difference(Rng1&& rng1, Rng2&& rng2, O result,
                   Comp comp = Comp{}, Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputIterator I1, Sentinel<I1> S1, InputIterator I2, Sentinel<I2> S2,
    WeaklyIncrementable O, class Comp = less<>,
    class Proj1 = identity, class Proj2 = identity>
  requires Mergeable<I1, I2, O, Comp, Proj1, Proj2>
  tagged_tuple<tag::in1(I1), tag::in2(I2), tag::out(O)>
    set_symmetric_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                             Comp comp = Comp{}, Proj1 proj1 = Proj1{},
                             Proj2 proj2 = Proj2{});

template <InputRange Rng1, InputRange Rng2, WeaklyIncrementable O,
    class Comp = less<>, class Proj1 = identity, class Proj2 = identity>
  requires Mergeable<iterator_t<Rng1>, iterator_t<Rng2>, O, Comp, Proj1, Proj2>
  tagged_tuple<tag::in1(safe_iterator_t<Rng1>),
               tag::in2(safe_iterator_t<Rng2>),
               tag::out(O)>
    set_symmetric_difference(Rng1&& rng1, Rng2&& rng2, O result, Comp comp = Comp{},
                             Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <RandomAccessIterator I, Sentinel<I> S, class Comp = less<>,
    class Proj = identity>
  requires Sortable<I, Comp, Proj>
  I push_heap(I first, S last, Comp comp = Comp{}, Proj proj == Proj{});

template <RandomAccessRange Rng, class Comp = less<>, class Proj = identity>
  requires Sortable<iterator_t<Rng>, Comp, Proj>
  safe_iterator_t<Rng>
    push_heap(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessIterator I, Sentinel<I> S, class Comp = less<>,
    class Proj = identity>
  requires Sortable<I, Comp, Proj>
  I pop_heap(I first, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessRange Rng, class Comp = less<>, class Proj = identity>
  requires Sortable<iterator_t<Rng>, Comp, Proj>
  safe_iterator_t<Rng>
    pop_heap(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessIterator I, Sentinel<I> S, class Comp = less<>,
    class Proj = identity>
  requires Sortable<I, Comp, Proj>
  I make_heap(I first, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessRange Rng, class Comp = less<>, class Proj = identity>
  requires Sortable<iterator_t<Rng>, Comp, Proj>
  safe_iterator_t<Rng>
    make_heap(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessIterator I, Sentinel<I> S, class Comp = less<>,
    class Proj = identity>
  requires Sortable<I, Comp, Proj>
  I sort_heap(I first, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessRange Rng, class Comp = less<>, class Proj = identity>
  requires Sortable<iterator_t<Rng>, Comp, Proj>
  safe_iterator_t<Rng>
    sort_heap(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessIterator I, Sentinel<I> S, class Proj = identity,
    IndirectStrictWeakOrder<projected<I, Proj>> Comp = less<>>
  bool is_heap(I first, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessRange Rng, class Proj = identity,
    IndirectStrictWeakOrder<projected<iterator_t<Rng>, Proj>> Comp = less<>>
  bool
    is_heap(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessIterator I, Sentinel<I> S, class Proj = identity,
    IndirectStrictWeakOrder<projected<I, Proj>> Comp = less<>>
  I is_heap_until(I first, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <RandomAccessRange Rng, class Proj = identity,
    IndirectStrictWeakOrder<projected<iterator_t<Rng>, Proj>> Comp = less<>>
  safe_iterator_t<Rng>
    is_heap_until(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <class T, class Proj = identity,
    IndirectStrictWeakOrder<projected<const T*, Proj>> Comp = less<>>
  constexpr const T& min(const T& a, const T& b, Comp comp = Comp{}, Proj proj = Proj{});

template <Copyable T, class Proj = identity,
    IndirectStrictWeakOrder<projected<const T*, Proj>> Comp = less<>>
  constexpr T min(initializer_list<T> t, Comp comp = Comp{}, Proj proj = Proj{});

template <InputRange Rng, class Proj = identity,
    IndirectStrictWeakOrder<projected<iterator_t<Rng>, Proj>> Comp = less<>>
  requires Copyable<value_type_t<iterator_t<Rng>>>
  value_type_t<iterator_t<Rng>>
    min(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <class T, class Proj = identity,
    IndirectStrictWeakOrder<projected<const T*, Proj>> Comp = less<>>
  constexpr const T& max(const T& a, const T& b, Comp comp = Comp{}, Proj proj = Proj{});

template <Copyable T, class Proj = identity,
    IndirectStrictWeakOrder<projected<const T*, Proj>> Comp = less<>>
  constexpr T max(initializer_list<T> t, Comp comp = Comp{}, Proj proj = Proj{});

template <InputRange Rng, class Proj = identity,
    IndirectStrictWeakOrder<projected<iterator_t<Rng>, Proj>> Comp = less<>>
  requires Copyable<value_type_t<iterator_t<Rng>>>
  value_type_t<iterator_t<Rng>>
    max(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <class T, class Proj = identity,
    IndirectStrictWeakOrder<projected<const T*, Proj>> Comp = less<>>
  constexpr tagged_pair<tag::min(const T&), tag::max(const T&)>
    minmax(const T& a, const T& b, Comp comp = Comp{}, Proj proj = Proj{});

template <Copyable T, class Proj = identity,
    IndirectStrictWeakOrder<projected<const T*, Proj>> Comp = less<>>
  constexpr tagged_pair<tag::min(T), tag::max(T)>
    minmax(initializer_list<T> t, Comp comp = Comp{}, Proj proj = Proj{});

template <InputRange Rng, class Proj = identity,
    IndirectStrictWeakOrder<projected<iterator_t<Rng>, Proj>> Comp = less<>>
  requires Copyable<value_type_t<iterator_t<Rng>>>
  tagged_pair<tag::min(value_type_t<iterator_t<Rng>>),
              tag::max(value_type_t<iterator_t<Rng>>)>
    minmax(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardIterator I, Sentinel<I> S, class Proj = identity,
    IndirectStrictWeakOrder<projected<I, Proj>> Comp = less<>>
  I min_element(I first, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardRange Rng, class Proj = identity,
    IndirectStrictWeakOrder<projected<iterator_t<Rng>, Proj>> Comp = less<>>
  safe_iterator_t<Rng>
    min_element(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardIterator I, Sentinel<I> S, class Proj = identity,
    IndirectStrictWeakOrder<projected<I, Proj>> Comp = less<>>
  I max_element(I first, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardRange Rng, class Proj = identity,
    IndirectStrictWeakOrder<projected<iterator_t<Rng>, Proj>> Comp = less<>>
  safe_iterator_t<Rng>
    max_element(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardIterator I, Sentinel<I> S, class Proj = identity,
    IndirectStrictWeakOrder<projected<I, Proj>> Comp = less<>>
  tagged_pair<tag::min(I), tag::max(I)>
    minmax_element(I first, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <ForwardRange Rng, class Proj = identity,
    IndirectStrictWeakOrder<projected<iterator_t<Rng>, Proj>> Comp = less<>>
  tagged_pair<tag::min(safe_iterator_t<Rng>),
              tag::max(safe_iterator_t<Rng>)>
    minmax_element(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <InputIterator I1, Sentinel<I1> S1, InputIterator I2, Sentinel<I2> S2,
    class Proj1 = identity, class Proj2 = identity,
    IndirectStrictWeakOrder<projected<I1, Proj1>, projected<I2, Proj2>> Comp = less<>>
  bool
    lexicographical_compare(I1 first1, S1 last1, I2 first2, S2 last2,
                            Comp comp = Comp{},
                            Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <InputRange Rng1, InputRange Rng2, class Proj1 = identity,
    class Proj2 = identity,
    IndirectStrictWeakOrder<projected<iterator_t<Rng1>, Proj1>,
      projected<iterator_t<Rng2>, Proj2>> Comp = less<>>
  bool
    lexicographical_compare(Rng1&& rng1, Rng2&& rng2, Comp comp = Comp{},
                            Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{});

template <BidirectionalIterator I, Sentinel<I> S, class Comp = less<>,
    class Proj = identity>
  requires Sortable<I, Comp, Proj>
  bool next_permutation(I first, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <BidirectionalRange Rng, class Comp = less<>,
    class Proj = identity>
  requires Sortable<iterator_t<Rng>, Comp, Proj>
  bool
    next_permutation(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

template <BidirectionalIterator I, Sentinel<I> S, class Comp = less<>,
    class Proj = identity>
  requires Sortable<I, Comp, Proj>
  bool prev_permutation(I first, S last, Comp comp = Comp{}, Proj proj = Proj{});

template <BidirectionalRange Rng, class Comp = less<>,
    class Proj = identity>
  requires Sortable<iterator_t<Rng>, Comp, Proj>
  bool
    prev_permutation(Rng&& rng, Comp comp = Comp{}, Proj proj = Proj{});

}}}}


实验性库头文件 <experimental/ranges/concepts>

< cpp‎ | header‎ | experimental

此头文件是范围库的一部分。

核心语言概念

定义于命名空间 std::experimental::ranges
Same | 指定类型与另一类型相同 (概念)
DerivedFrom | 指定该类型从另一类型派生 (概念)
ConvertibleTo | 指定类型能隐式转换成另一类型 (概念)
CommonReference | 指定两个类型共有一个公共引用类型 (概念)
Common | 指定两个类型共有一个公共类型 (概念)
Integral | 指定类型为整型类型 (概念)
SignedIntegral | 指定类型为有符号的整型类型 (概念)
UnsignedIntegral | 指定类型为无符号的整型类型 (概念)
Assignable | 指定类型可从另一类型赋值 (概念)
SwappableSwappableWith | 指定一个类型能进行交换，或两个类型能彼此交换 (概念)

比较概念

定义于命名空间 std::experimental::ranges
Boolean | 指定类型能用于布尔语境 (概念)
WeaklyEqualityComparableWith | 指定两个类型能用运算符 == 和 != 比较相等性 (概念)
EqualityComparableEqualityComparableWith | 指定运算符 == 是等价关系 (概念)
StrictTotallyOrderedStrictTotallyOrderedWith | 指定该类型上的比较运算符产出全序 (概念)

对象概念

定义于命名空间 std::experimental::ranges
Destructible | 指定该类型对象能被销毁，且能用一元 & 取其地址 (概念)
Constructible | 指定该类型的变量能从一组实参类型进行构造，或绑定到一组实参类型 (概念)
DefaultConstructible | 指定该类型对象能默认构造 (概念)
MoveConstructible | 指定该类型的对象能移动构造 (概念)
CopyConstructible | 指定该类型对象能复制构造及移动构造 (概念)
Movable | 指定该类型的对象能被移动和交换 (概念)
Copyable | 指定该类型对象能被复制、移动和交换 (概念)
Semiregular | 指定类型的对象能被复制、移动、交换及默认构造 (概念)
Regular | 指定类型为正则，即为 Semiregular 且为 EqualityComparable (概念)

可调用概念

定义于命名空间 std::experimental::ranges
InvocableRegularInvocable | 指定可调用类型能以给定的一组实参调用 (概念)
Predicate | 指定可调用类型是布尔谓词 (概念)
Relation | 指定可调用类型为二元关系 (概念)
StrictWeakOrder | 指定一种 Relation 施加严格弱序 (概念)

概要

namespace std { namespace experimental { namespace ranges { inline namespace v1 {

template <class T, class U>
concept bool Same = /* 见定义 */;

template <class T, class U>
concept bool DerivedFrom = /* 见定义 */;

template <class T, class U>
concept bool ConvertibleTo = /* 见定义 */;

template <class T, class U>
concept bool CommonReference = /* 见定义 */;

template <class T, class U>
concept bool Common = /* 见定义 */;

template <class T>
concept bool Integral = /* 见定义 */;

template <class T>
concept bool SignedIntegral = /* 见定义 */;

template <class T>
concept bool UnsignedIntegral = /* 见定义 */;

template <class T, class U>
concept bool Assignable = /* 见定义 */;

template <class T>
concept bool Swappable = /* 见定义 */;

template <class T, class U>
concept bool SwappableWith = /* 见定义 */;

template <class T>
concept bool Destructible = /* 见定义 */;

template <class T, class... Args>
concept bool Constructible = /* 见定义 */;

template <class T>
concept bool DefaultConstructible = /* 见定义 */;

template <class T>
concept bool MoveConstructible = /* 见定义 */;

template <class T>
concept bool CopyConstructible = /* 见定义 */;

template <class B>
concept bool Boolean = /* 见定义 */;

template <class T, class U>
concept bool WeaklyEqualityComparableWith = /* 见定义 */;

template <class T>
concept bool EqualityComparable = /* 见定义 */;

template <class T, class U>
concept bool EqualityComparableWith = /* 见定义 */;

template <class T>
concept bool StrictTotallyOrdered = /* 见定义 */;

template <class T, class U>
concept bool StrictTotallyOrderedWith = /* 见定义 */;

template <class T>
concept bool Movable = /* 见定义 */;

template <class T>
concept bool Copyable = /* 见定义 */;

template <class T>
concept bool Semiregular = /* 见定义 */;

template <class T>
concept bool Regular = /* 见定义 */;

template <class F, class... Args>
concept bool Invocable = /* 见定义 */;

template <class F, class... Args>
concept bool RegularInvocable = /* 见定义 */;

template <class F, class... Args>
concept bool Predicate = /* 见定义 */;

template <class R, class T, class U>
concept bool Relation = /* 见定义 */;

template <class R, class T, class U>
concept bool StrictWeakOrder = /* 见定义 */;

}}}}


实验性库头文件 <experimental/ranges/functional>

< cpp‎ | header‎ | experimental

此头文件是范围库的一部分。

函数对象

定义于命名空间 std::experimental::ranges
invoke | 以给定实参调用可调用 (Callable) 对象 (函数模板)
equal_to | 实现 x == y 的函数对象 (类模板)
not_equal_to | 实现 x != y 的函数对象 (类模板)
greater | 实现 x > y 的函数对象 (类模板)
less | 实现 x < y 的函数对象 (类模板)
greater_equal | 实现 x >= y 的函数对象 (类模板)
less_equal | 实现 x <= y 的函数对象 (类模板)
identity | 返回其（未改变的）实参的函数对象 (类)

概要

namespace std { namespace experimental { namespace ranges { inline namespace v1 {

template <class F, class... Args>
std::result_of_t<F&&(Args&&...)> invoke(F&& f, Args&&... args);

template <class T = void>
  requires /* 见定义 */
struct equal_to;

template <class T = void>
  requires /* 见定义 */
struct not_equal_to;

template <class T = void>
  requires /* 见定义 */
struct greater;

template <class T = void>
  requires /* 见定义 */
struct less;

template <class T = void>
  requires /* 见定义 */
struct greater_equal;

template <class T = void>
  requires /* 见定义 */
struct less_equal;

template <> struct equal_to<void>;
template <> struct not_equal_to<void>;
template <> struct greater<void>;
template <> struct less<void>;
template <> struct greater_equal<void>;
template <> struct less_equal<void>;

struct identity;

}}}}


实验性库头文件 <experimental/ranges/iterator>

< cpp‎ | header‎ | experimental

此头文件是范围库的一部分。

迭代器相关概念

定义于命名空间 std::experimental::ranges

迭代器概念

Readable | 指定类型通过应用运算符 * 可读 (概念)
Writable | 指定可向迭代器所引用的对象写入值 (概念)
WeaklyIncrementable | 指定 Semiregular 类型能以前后自增运算符自增 (概念)
Incrementable | 指定 WeaklyIncrementable 类型上的自增操作保持相等性，而且该类型 EqualityComparable (概念)
Iterator | 指定该类型对象能自增并解引用 (概念)
Sentinel | 指定类型的对象是 Iterator 类型的哨位 (概念)
SizedSentinel | 指定能应用 - 运算符到迭代器和哨位，以在常数时间计算其差 (概念)
InputIterator | 指定类型为输入迭代器，即能读其所引用值，且它能前后自增 (概念)
OutputIterator | 指定类型为给定值类型的输出迭代器，即能把该类型的值写入它，且它能前后自增 (概念)
ForwardIterator | 指定 InputIterator 为向前迭代器，支持相等比较和多趟 (概念)
BidirectionalIterator | 指定 ForwardIterator 为双向迭代器，支持向后移动 (概念)
RandomAccessIterator | 指定 BidirectionalIterator 为随机访问迭代器，支持常数时间前进和下标访问 (概念)

间接可调用概念

IndirectUnaryInvocableIndirectRegularUnaryInvocable | 指定可调用对象能以解引用一个 Readable 类型的结果调用 (概念)
IndirectUnaryPredicate | 指定可调用对象，以解引用某个 Readable 类型的结果调用时，满足 Predicate (概念)
IndirectRelation | 指定可调用对象以解引用某些 Readable 类型的结果调用时，满足 Relation (概念)
IndirectStrictWeakOrder | 指定可调用对象，以解引用某些 Readable 类型的结果调用时，满足 StrictWeakOrder (概念)

常用算法要求

IndirectlyMovable | 指定值可从 Readable 类型移动到 Writable 类型 (概念)
IndirectlyMovableStorable | 指定类型可从 Readable 类型移动到 Writable 类型，且移动可以通过中间对象进行 (概念)
IndirectlyCopyable | 指定值可从 Readable 类型复制到 Writable 类型 (概念)
IndirectlyCopyableStorable | 指定值可从 Readable 类型复制到 Writable 类型，且该复制可能通过中间对象进行 (概念)
IndirectlySwappable | 指定两个 Readable 类型所引用的值可交换 (概念)
IndirectlyComparable | 指定两个 Readable 类型所引用的值能比较 (概念)
Permutable | 指定原位重排元素的算法的公共要求 (概念)
Mergeable | 指定算法的要求，该算法需要通过复制元素归并已排序序列到输出序列 (概念)
Sortable | 指定重排元素为有序序列的算法的公共要求 (概念)

概念工具

indirect_result_of | 计算在某 Readable 类型集合的解引用结果上调用可调用对象的结果 (类模板)
projected | 用于指定接受投影的算法上的制约的帮助模板 (类模板)

迭代器原语

迭代器工具

定义于命名空间 std::experimental::ranges
iter_move | 转型解引用对象的结果为其所关联的右值引用类型 (定制点对象)
iter_swap | 交换两个可解引用对象所引用的值 (定制点对象)

迭代器特征

定义于命名空间 std::experimental::ranges
difference_type | 获得 WeaklyIncrementable 类型的差类型 (类模板)
value_type | 获得 Readable 类型的值类型 (类模板)
iterator_category | 获得输入迭代器类型的迭代器类别 (类模板)
iterator_traits | 汇集迭代器的关联类型的兼容性特性类 (别名模板)
reference_trvalue_reference_titer_common_reference_t | 获得可解引用对象的关联引用类型 (别名模板)

迭代器类别标签

定义于命名空间 std::experimental::ranges
input_iterator_tagoutput_iterator_tagforward_iterator_tagbidirectional_iterator_tagrandom_access_iterator_tag
 用于指示迭代器类别的空类
(类)

std::iterator_traits 的特化

定义于命名空间 std
std::iterator_traits<InputIterator>std::iterator_traits<OutputIterator>
 为范围 TS 迭代器特化 std::iterator_traits
(类模板特化)

迭代器操作

定义于命名空间 std::experimental::ranges
advance | 令迭代器前进给定的距离 (函数模板)
distance | 返回迭代器和哨位之间的距离，或范围起始和结尾间的距离 (函数模板)
next | 自增迭代器 (函数模板)
prev | 自减迭代器 (函数模板)

迭代器适配器

定义于命名空间 std::experimental::ranges
reverse_iterator | 用于逆序遍历的迭代器适配器 (类模板)
back_insert_iterator | 用于在容器尾插入的迭代器适配器 (类模板)
front_insert_iterator | 用于在容器首插入的迭代器适配器 (类模板)
insert_iterator | 用于插入元素到容器中的迭代器适配器 (类模板)
move_iterator | 解引用为右值引用的迭代器适配器 (类模板)
move_sentinel | 为 move_iterator 所用的哨位适配器 (类模板)
common_iterator | 将迭代器-哨位对适配成公共迭代器类型，以用于遗留算法 (类模板)
counted_iterator | 保持距起始位置距离踪迹的迭代器适配器 (类模板)
default_sentinel | 知晓其范围的迭代器类型所用的空哨位类型 (类)
dangling | 可能悬垂的迭代器的包装器 (类模板)
safe_iterator_t | 以 dangling 包装右值范围的迭代器类型的别名模版 (别名模板)
unreachable | 用于与任何迭代器一同指示无限范围的哨位类型 (类)

流迭代器

定义于命名空间 std::experimental::ranges
istream_iterator | 从 std::basic_istream 读取的输入迭代器 (类模板)
ostream_iterator | 写入 std::basic_ostream 的输出迭代器 (类模板)
istreambuf_iterator | 从 std::basic_streambuf 读取的输入迭代器 (类模板)
ostreambuf_iterator | 写入 std::basic_streambuf 的输出迭代器 (类模板)

概要

namespace std { namespace experimental { namespace ranges { inline namespace v1 {

template <class T> concept bool /* dereferenceable */ // 仅用于阐释
  = requires(T& t) { {*t} -> auto&&; };

namespace {
  constexpr /* 未指明 */ iter_move = /* 未指明 */;
  constexpr /* 未指明 */ iter_swap = /* 未指明 */;
}

template <class> struct difference_type;
template <class T> using difference_type_t
  = typename difference_type<T>::type;

template <class> struct value_type;
template <class T> using value_type_t
  = typename value_type<T>::type;

template <class> struct iterator_category;
template <class T> using iterator_category_t
  = typename iterator_category<T>::type;

template </* dereferenceable */ T> using reference_t
  = decltype(*declval<T&>());

template </* dereferenceable */ T>
    requires /* 见定义 */ using rvalue_reference_t
  = decltype(ranges::iter_move(declval<T&>()));

template <class In>
concept bool Readable = /* 见定义 */;

template <class Out, class T>
concept bool Writable = /* 见定义 */;

template <class I>
concept bool WeaklyIncrementable = /* 见定义 */;

template <class I>
concept bool Incrementable = /* 见定义 */;

template <class I>
concept bool Iterator = /* 见定义 */;

template <class S, class I>
concept bool Sentinel = /* 见定义 */;

template <class S, class I>
  constexpr bool disable_sized_sentinel = false;

template <class S, class I>
concept bool SizedSentinel = /* 见定义 */;

template <class I>
concept bool InputIterator = /* 见定义 */;

template <class I>
concept bool OutputIterator = /* 见定义 */;

template <class I>
concept bool ForwardIterator = /* 见定义 */;

template <class I>
concept bool BidirectionalIterator = /* 见定义 */;

template <class I>
concept bool RandomAccessIterator = /* 见定义 */;

template <class F, class I>
concept bool IndirectUnaryInvocable = /* 见定义 */;

template <class F, class I>
concept bool IndirectRegularUnaryInvocable = /* 见定义 */;

template <class F, class I>
concept bool IndirectUnaryPredicate = /* 见定义 */;

template <class F, class I1, class I2 = I1>
concept bool IndirectRelation = /* 见定义 */;

template <class F, class I1, class I2 = I1>
concept bool IndirectStrictWeakOrder = /* 见定义 */;

template <class> struct indirect_result_of;

template <class F, class... Is>
  requires Invocable<F, reference_t<Is>...>
struct indirect_result_of<F(Is...)>;

template <class F>
using indirect_result_of_t
  = typename indirect_result_of<F>::type;

template <Readable I, IndirectRegularUnaryInvocable<I> Proj>
struct projected;

template <WeaklyIncrementable I, class Proj>
struct difference_type<projected<I, Proj>>;

template <class In, class Out>
concept bool IndirectlyMovable = /* 见定义 */;

template <class In, class Out>
concept bool IndirectlyMovableStorable = /* 见定义 */;

template <class In, class Out>
concept bool IndirectlyCopyable = /* 见定义 */;

template <class In, class Out>
concept bool IndirectlyCopyableStorable = /* 见定义 */;

template <class I1, class I2 = I1>
concept bool IndirectlySwappable = /* 见定义 */;

template <class I1, class I2, class R = equal_to<>, class P1 = identity,
    class P2 = identity>
concept bool IndirectlyComparable = /* 见定义 */;

template <class I>
concept bool Permutable = /* 见定义 */;

template <class I1, class I2, class Out,
    class R = less<>, class P1 = identity, class P2 = identity>
concept bool Mergeable = /* 见定义 */;

template <class I, class R = less<>, class P = identity>
concept bool Sortable = /* 见定义 */;

template <class Iterator> using iterator_traits = /* 见定义 */;

template <Readable T> using iter_common_reference_t
  = common_reference_t<reference_t<T>, value_type_t<T>&>;

struct output_iterator_tag { };
struct input_iterator_tag { };
struct forward_iterator_tag : input_iterator_tag { };
struct bidirectional_iterator_tag : forward_iterator_tag { };
struct random_access_iterator_tag : bidirectional_iterator_tag { };

namespace {
  constexpr /* 未指明 */ advance = /* 未指明 */;
  constexpr /* 未指明 */ distance = /* 未指明 */;
  constexpr /* 未指明 */ next = /* 未指明 */;
  constexpr /* 未指明 */ prev = /* 未指明 */;
}

template <BidirectionalIterator I> class reverse_iterator;

template <class I1, class I2>
    requires EqualityComparableWith<I1, I2>
  constexpr bool operator==(
    const reverse_iterator<I1>& x,
    const reverse_iterator<I2>& y);
template <class I1, class I2>
    requires EqualityComparableWith<I1, I2>
  constexpr bool operator!=(
    const reverse_iterator<I1>& x,
    const reverse_iterator<I2>& y);
template <class I1, class I2>
    requires StrictTotallyOrderedWith<I1, I2>
  constexpr bool operator<(
    const reverse_iterator<I1>& x,
    const reverse_iterator<I2>& y);
template <class I1, class I2>
    requires StrictTotallyOrderedWith<I1, I2>
  constexpr bool operator>(
    const reverse_iterator<I1>& x,
    const reverse_iterator<I2>& y);
template <class I1, class I2>
    requires StrictTotallyOrderedWith<I1, I2>
  constexpr bool operator>=(
    const reverse_iterator<I1>& x,
    const reverse_iterator<I2>& y);
template <class I1, class I2>
    requires StrictTotallyOrderedWith<I1, I2>
  constexpr bool operator<=(
    const reverse_iterator<I1>& x,
    const reverse_iterator<I2>& y);

template <class I1, class I2>
    requires SizedSentinel<I1, I2>
  constexpr difference_type_t<I2> operator-(
    const reverse_iterator<I1>& x,
    const reverse_iterator<I2>& y);
template <RandomAccessIterator I>
  constexpr reverse_iterator<I> operator+(
    difference_type_t<I> n,
    const reverse_iterator<I>& x);

template <BidirectionalIterator I>
constexpr reverse_iterator<I> make_reverse_iterator(I i);

template <class Container> class back_insert_iterator;
template <class Container>
  back_insert_iterator<Container> back_inserter(Container& x);

template <class Container> class front_insert_iterator;
template <class Container>
  front_insert_iterator<Container> front_inserter(Container& x);

template <class Container> class insert_iterator;
template <class Container>
  insert_iterator<Container> inserter(Container& x, iterator_t<Container> i);

template <InputIterator I> class move_iterator;

template <class I1, class I2>
    requires EqualityComparableWith<I1, I2>
  constexpr bool operator==(
    const move_iterator<I1>& x, const move_iterator<I2>& y);
template <class I1, class I2>
    requires EqualityComparableWith<I1, I2>
  constexpr bool operator!=(
    const move_iterator<I1>& x, const move_iterator<I2>& y);
template <class I1, class I2>
    requires StrictTotallyOrderedWith<I1, I2>
  constexpr bool operator<(
    const move_iterator<I1>& x, const move_iterator<I2>& y);
template <class I1, class I2>
    requires StrictTotallyOrderedWith<I1, I2>
  constexpr bool operator<=(
    const move_iterator<I1>& x, const move_iterator<I2>& y);
template <class I1, class I2>
    requires StrictTotallyOrderedWith<I1, I2>
  constexpr bool operator>(
    const move_iterator<I1>& x, const move_iterator<I2>& y);
template <class I1, class I2>
    requires StrictTotallyOrderedWith<I1, I2>
  constexpr bool operator>=(
    const move_iterator<I1>& x, const move_iterator<I2>& y);

template <class I1, class I2>
    requires SizedSentinel<I1, I2>
  constexpr difference_type_t<I2> operator-(
    const move_iterator<I1>& x,
    const move_iterator<I2>& y);
template <RandomAccessIterator I>
  constexpr move_iterator<I> operator+(
    difference_type_t<I> n,
    const move_iterator<I>& x);

template <InputIterator I>
  constexpr move_iterator<I> make_move_iterator(I i);

template <Semiregular S> class move_sentinel;

template <class I, Sentinel<I> S>
  constexpr bool operator==(
    const move_iterator<I>& i, const move_sentinel<S>& s);
template <class I, Sentinel<I> S>
  constexpr bool operator==(
    const move_sentinel<S>& s, const move_iterator<I>& i);
template <class I, Sentinel<I> S>
  constexpr bool operator!=(
    const move_iterator<I>& i, const move_sentinel<S>& s);
template <class I, Sentinel<I> S>
  constexpr bool operator!=(
    const move_sentinel<S>& s, const move_iterator<I>& i);

template <class I, SizedSentinel<I> S>
  constexpr difference_type_t<I> operator-(
    const move_sentinel<S>& s, const move_iterator<I>& i);
template <class I, SizedSentinel<I> S>
  constexpr difference_type_t<I> operator-(
    const move_iterator<I>& i, const move_sentinel<S>& s);

template <Semiregular S>
  constexpr move_sentinel<S> make_move_sentinel(S s);

template <Iterator I, Sentinel<I> S>
  requires !Same<I, S>
class common_iterator;

template <Readable I, class S>
struct value_type<common_iterator<I, S>>;

template <InputIterator I, class S>
struct iterator_category<common_iterator<I, S>>;

template <ForwardIterator I, class S>
struct iterator_category<common_iterator<I, S>>;

template <class I1, class I2, Sentinel<I2> S1, Sentinel<I1> S2>
bool operator==(
  const common_iterator<I1, S1>& x, const common_iterator<I2, S2>& y);
template <class I1, class I2, Sentinel<I2> S1, Sentinel<I1> S2>
  requires EqualityComparableWith<I1, I2>
bool operator==(
  const common_iterator<I1, S1>& x, const common_iterator<I2, S2>& y);
template <class I1, class I2, Sentinel<I2> S1, Sentinel<I1> S2>
bool operator!=(
  const common_iterator<I1, S1>& x, const common_iterator<I2, S2>& y);

template <class I2, SizedSentinel<I2> I1, SizedSentinel<I2> S1, SizedSentinel<I1> S2>
difference_type_t<I2> operator-(
  const common_iterator<I1, S1>& x, const common_iterator<I2, S2>& y);

class default_sentinel;

template <Iterator I> class counted_iterator;

template <class I1, class I2>
    requires Common<I1, I2>
  constexpr bool operator==(
    const counted_iterator<I1>& x, const counted_iterator<I2>& y);
constexpr bool operator==(
  const counted_iterator<auto>& x, default_sentinel);
constexpr bool operator==(
  default_sentinel, const counted_iterator<auto>& x);
template <class I1, class I2>
    requires Common<I1, I2>
  constexpr bool operator!=(
    const counted_iterator<I1>& x, const counted_iterator<I2>& y);
constexpr bool operator!=(
  const counted_iterator<auto>& x, default_sentinel y);
constexpr bool operator!=(
  default_sentinel x, const counted_iterator<auto>& y);
template <class I1, class I2>
    requires Common<I1, I2>
  constexpr bool operator<(
    const counted_iterator<I1>& x, const counted_iterator<I2>& y);
template <class I1, class I2>
    requires Common<I1, I2>
  constexpr bool operator<=(
    const counted_iterator<I1>& x, const counted_iterator<I2>& y);
template <class I1, class I2>
    requires Common<I1, I2>
  constexpr bool operator>(
    const counted_iterator<I1>& x, const counted_iterator<I2>& y);
template <class I1, class I2>
    requires Common<I1, I2>
  constexpr bool operator>=(
    const counted_iterator<I1>& x, const counted_iterator<I2>& y);

template <class I1, class I2>
    requires Common<I1, I2>
  constexpr difference_type_t<I2> operator-(
    const counted_iterator<I1>& x, const counted_iterator<I2>& y);
template <class I>
  constexpr difference_type_t<I> operator-(
    const counted_iterator<I>& x, default_sentinel y);
template <class I>
  constexpr difference_type_t<I> operator-(
    default_sentinel x, const counted_iterator<I>& y);
template <RandomAccessIterator I>
  constexpr counted_iterator<I>
    operator+(difference_type_t<I> n, const counted_iterator<I>& x);

template <Iterator I>
  constexpr counted_iterator<I> make_counted_iterator(I i, difference_type_t<I> n);

class unreachable;
template <Iterator I>
  constexpr bool operator==(const I&, unreachable) noexcept;
template <Iterator I>
  constexpr bool operator==(unreachable, const I&) noexcept;
template <Iterator I>
  constexpr bool operator!=(const I&, unreachable) noexcept;
template <Iterator I>
  constexpr bool operator!=(unreachable, const I&) noexcept;

template <class T> class dangling;

template <class T, class charT = char, class traits = char_traits<charT>,
    class Distance = ptrdiff_t>
  class istream_iterator;

template <class T, class charT, class traits, class Distance>
  bool operator==(const istream_iterator<T, charT, traits, Distance>& x,
    const istream_iterator<T, charT, traits, Distance>& y);
template <class T, class charT, class traits, class Distance>
  bool operator==(default_sentinel x,
    const istream_iterator<T, charT, traits, Distance>& y);
template <class T, class charT, class traits, class Distance>
  bool operator==(const istream_iterator<T, charT, traits, Distance>& x,
    default_sentinel y);
template <class T, class charT, class traits, class Distance>
  bool operator!=(const istream_iterator<T, charT, traits, Distance>& x,
    const istream_iterator<T, charT, traits, Distance>& y);
template <class T, class charT, class traits, class Distance>
  bool operator!=(default_sentinel x,
    const istream_iterator<T, charT, traits, Distance>& y);
template <class T, class charT, class traits, class Distance>
  bool operator!=(const istream_iterator<T, charT, traits, Distance>& x,
    default_sentinel y);

template <class T, class charT = char, class traits = char_traits<charT>>
  class ostream_iterator;

template <class charT, class traits = char_traits<charT> >
  class istreambuf_iterator;

template <class charT, class traits>
  bool operator==(const istreambuf_iterator<charT, traits>& a,
    const istreambuf_iterator<charT, traits>& b);
template <class charT, class traits>
  bool operator==(default_sentinel a,
    const istreambuf_iterator<charT, traits>& b);
template <class charT, class traits>
  bool operator==(const istreambuf_iterator<charT, traits>& a,
    default_sentinel b);
template <class charT, class traits>
  bool operator!=(const istreambuf_iterator<charT, traits>& a,
    const istreambuf_iterator<charT, traits>& b);
template <class charT, class traits>
  bool operator!=(default_sentinel a,
    const istreambuf_iterator<charT, traits>& b);
template <class charT, class traits>
  bool operator!=(const istreambuf_iterator<charT, traits>& a,
    default_sentinel b);

template <class charT, class traits = char_traits<charT> >
  class ostreambuf_iterator;

}}}}

namespace std {
  template <experimental::ranges::Iterator Out>
    struct iterator_traits<Out>;
  template <experimental::ranges::InputIterator In>
    struct iterator_traits<In>;
  template <experimental::ranges::InputIterator In>
      requires experimental::ranges::Sentinel<In, In>
    struct iterator_traits;
}


实验性库头文件 <experimental/ranges/random>

< cpp‎ | header‎ | experimental

此头文件是范围库的一部分。

随机数生成器概念

定义于命名空间 std::experimental::ranges
UniformRandomNumberGenerator
 指定类型具备作为均匀随机数生成器的资格
(概念)

概要

namespace std { namespace experimental { namespace ranges { inline namespace v1 {

template <class G>
concept bool UniformRandomNumberGenerator = /* 见定义 */;

}}}}


标准库头文件 <experimental/ranges/range>

< cpp‎ | header‎ | experimental

此头文件是范围库的一部分。

范围概念

定义于命名空间 std::experimental::ranges
Range | 指定类型为范围，即它提供 begin 迭代器和 end 哨位 (概念)
SizedRange | 指定范围以常数时间知晓其大小 (概念)
View | 指定范围为视图，即它拥有常数时间的复制/移动/赋值 (概念)
BoundedRange | 指定范围拥有等同的迭代器和哨位类型 (概念)
InputRange | 指定范围的迭代器满足 InputIterator (概念)
OutputRange | 指定范围的迭代器满足 OutputIterator (概念)
ForwardRange | 指定范围的迭代器满足 ForwardIterator (概念)
BidirectionalRange | 指定范围的迭代器满足 BidirectionalIterator (概念)
RandomAccessRange | 指定范围的迭代器满足 RandomAccessIterator (概念)

范围访问

定义于命名空间 std::experimental::ranges
begincbegin | 返回指向范围起始的迭代器 (定制点对象)
endcend | 返回指向范围末尾的迭代器 (定制点对象)
rbegincrbegin | 获得指向范围的逆向迭代器 (定制点对象)
rendcrend | 获得指向范围的逆向尾迭代器 (定制点对象)

范围原语

定义于命名空间 std::experimental::ranges
size | 获得能在常数时间计算大小的范围的大小 (定制点对象)
empty | 检查范围是否为空 (定制点对象)
datacdata | 获得指向连续范围起始的指针 (定制点对象)
iterator_tsentinel_t | 获得范围的迭代器类型与哨位类型 (别名模板)

概要

#include <experimental/ranges/iterator>

namespace std { namespace experimental { namespace ranges { inline namespace v1 {

namespace {
  constexpr /* 未指明 */ begin = /* 未指明 */;
  constexpr /* 未指明 */ end = /* 未指明 */;
  constexpr /* 未指明 */ cbegin = /* 未指明 */;
  constexpr /* 未指明 */ cend = /* 未指明 */;
  constexpr /* 未指明 */ rbegin = /* 未指明 */;
  constexpr /* 未指明 */ rend = /* 未指明 */;
  constexpr /* 未指明 */ crbegin = /* 未指明 */;
  constexpr /* 未指明 */ crend = /* 未指明 */;
}

namespace {
  constexpr /* 未指明 */ size = /* 未指明 */;
  constexpr /* 未指明 */ empty = /* 未指明 */;
  constexpr /* 未指明 */ data = /* 未指明 */;
  constexpr /* 未指明 */ cdata = /* 未指明 */;
}

template <class T>
using iterator_t = decltype(ranges::begin(declval<T&>()));

template <class T>
using sentinel_t = decltype(ranges::end(declval<T&>()));

template <class>
constexpr bool disable_sized_range = false;

template <class T>
struct enable_view { };

struct view_base { };

template <class T>
concept bool Range = /* 见定义 */;

template <class T>
concept bool SizedRange = /* 见定义 */;

template <class T>
concept bool View = /* 见定义 */;

template <class T>
concept bool BoundedRange = /* 见定义 */;

template <class T>
concept bool InputRange = /* 见定义 */;

template <class R, class T>
concept bool OutputRange = /* 见定义 */;

template <class T>
concept bool ForwardRange = /* 见定义 */;

template <class T>
concept bool BidirectionalRange = /* 见定义 */;

template <class T>
concept bool RandomAccessRange = /* 见定义 */;

}}}}


实验性库头文件 <experimental/ranges/tuple>

< cpp‎ | header‎ | experimental

此头文件是范围库的一部分。

带标签元组

定义于命名空间 std::experimental::ranges
tagged_tuple | 有标签 std::tuple 的别名模版 (别名模板)
make_tagged_tuple | 用于创建 tagged_tuple 的便利函数 (函数模板)

概要

namespace std { namespace experimental { namespace ranges { inline namespace v1 {

template <TaggedType... Types>
using tagged_tuple = tagged<tuple</* TAGELEM */(Types)...>,
                            /* TAGSPEC */(Types)...>;

template <TagSpecifier... Tags, class... Types>
  requires sizeof...(Tags) == sizeof...(Types)
    constexpr /* 见定义 */ make_tagged_tuple(Types&&... t);

}}}}


实验性库头文件 <experimental/ranges/type_traits>

< cpp‎ | header‎ | experimental

此头文件是范围的一部分。

元编程与类型特征

定义于命名空间 std::experimental::ranges
is_swappable_withis_swappableis_nothrow_swappable_withis_nothrow_swappable | 检查一个类型的对象是否能与相同或不同类型的对象交换 (类模板)
common_reference | 确定类型集合的公共引用类型 (类模板)
common_type | 确定类型集合的公共类型 (类模板)

概要

namespace std { namespace experimental { namespace ranges { inline namespace v1 {

template <class T, class U> struct is_swappable_with;
template <class T> struct is_swappable;

template <class T, class U> struct is_nothrow_swappable_with;
template <class T> struct is_nothrow_swappable;

template <class T, class U> constexpr bool is_swappable_with_v
  = is_swappable_with<T, U>::value;
template <class T> constexpr bool is_swappable_v
  = is_swappable<T>::value;

template <class T, class U> constexpr bool is_nothrow_swappable_with_v
  = is_nothrow_swappable_with<T, U>::value;
template <class T> constexpr bool is_nothrow_swappable_v
  = is_nothrow_swappable<T>::value;

template <class... T> struct common_type;
template <class T, class U, template <class> class TQual, template <class> class UQual>
  struct basic_common_reference { };
template <class... T> struct common_reference;

template <class... T>
  using common_type_t = typename common_type<T...>::type;
template <class... T>
  using common_reference_t = typename common_reference<T...>::type;

}}}}


实验性库头文件 <experimental/ranges/utility>

< cpp‎ | header‎ | experimental

此头文件是范围库的一部分。

工具组件

定义于命名空间 std::experimental::ranges
swap | 交换两个对象的值 (定制点对象)
exchange | 以新值替换实参并返回其先前的值 (函数模板)

标签概念

定义于命名空间 std::experimental::ranges
TagSpecifier | 指定类型为标签说明符 (概念)
TaggedType | 指定类型表示一个标签说明符及其元素类型 (概念)

带标签对偶

定义于命名空间 std::experimental::ranges
tagged | 为元组式类型增加具名访问器 (类模板)
tagged_pair | 有标签 std::pair 的别名模版 (别名模板)
make_tagged_pair | 用于创建 tagged_pair 的便利函数 (函数模板)

概要

namespace std { namespace experimental { namespace ranges { inline namespace v1 {

namespace {
  constexpr /* 未指明 */ swap = /* 未指明 */;
}

template<MoveConstructible T, class U = T>
  requires Assignable<T&, U>
constexpr T exchange(T& obj, U&& new_val) noexcept(/* 见定义 */);

template <class T>
concept bool TagSpecifier = /* 见定义 */;

template <class F>
concept bool TaggedType = /* 见定义 */;

template <class Base, TagSpecifier... Tags>
  requires sizeof...(Tags) <= std::tuple_size<Base>::value
struct tagged;

template <TaggedType T1, TaggedType T2>
using tagged_pair = /* 见定义 */;

template <TagSpecifier Tag1, TagSpecifier Tag2, class T1, class T2>
constexpr /* 见定义 */ make_tagged_pair(T1&& x, T2&& y);

}}}}

namespace std {

template <class Base, class... Tags>
struct tuple_size<experimental::ranges::tagged<Base, Tags...>>;

template <size_t N, class Base, class... Tags>
struct tuple_element<N, experimental::ranges::tagged<Base, Tags...>>;

}


实验性库头文件 <experimental/reflect>

< cpp‎ | header‎ | experimental

此头文件是反射 TS 的一部分。

定义于命名空间 std::experimental::reflect
定义于内联命名空间 std::experimental::reflect::v1

概念
Object
(反射 TS)
 指定类型为元对象类型
(概念)
ObjectSequence
(反射 TS)
 指定元对象类型为元对象序列类型
(概念)
TemplateParameterScope
(反射 TS)
 指定元对象类型反射模板形参作用域
(概念)
Named
(反射 TS)
 指定元对象类型反射具有关联（可能为空的）名字的实体
(概念)
Alias
(反射 TS)
 指定元对象类型反射类型别名、命名空间别名或由 using 声明引入的别名
(概念)
RecordMember
(反射 TS)
 指定元对象类型反射类的 成员说明
(概念)
Enumerator
(反射 TS)
 指定元对象类型反射枚举项
(概念)
Variable
(反射 TS)
 指定元对象类型反射变量或数据成员
(概念)
ScopeMember
(反射 TS)
 指定元对象类型满足 RecordMember 、 Enumerator 或 Variable ，或反射全局命名空间以外的命名空间
(概念)
Typed
(反射 TS)
 指定元对象类型反射具有类型的实体
(概念)
Namespace
(反射 TS)
 指定元对象类型反射命名空间
(概念)
GlobalScope
(反射 TS)
 指定元对象类型反射全局命名空间
(概念)
Class
(反射 TS)
 指定元对象类型反射非联合类类型
(概念)
Enum
(反射 TS)
 指定元对象类型反射枚举类型
(概念)
Record
(反射 TS)
 指定元对象类型反射类类型
(概念)
Scope
(反射 TS)
 指定元对象类型反射命名空间、类、枚举、闭包类型、模板实参作用域
(概念)
Type
(反射 TS)
 指定元对象类型反射一个类型
(概念)
Constant
(反射 TS)
 指定元对象类型反射枚举项或 constexpr 变量
(概念)
Base
(反射 TS)
 指定元对象类型反射从 get_base_classes 获得的直接基类
(概念)
FunctionParameter
(反射 TS)
 指定元对象类型反射模板形参
(概念)
Callable
(反射 TS)
 指定元对象类型反射函数（包括构造函数与析构函数）
(概念)
Expression
(反射 TS)
 指定元对象类型反射表达式
(概念)
ParenthesizedExpression
(反射 TS)
 指定元对象类型反射有括号表达式
(概念)
FunctionCallExpression
(反射 TS)
 指定元对象类型反射 函数调用表达式
(概念)
FunctionalTypeConversion
(反射 TS)
 指定元对象类型反射 函数式类型转换表达式
(概念)
Function
(反射 TS)
 指定元对象类型反射函数（不含构造函数与析构函数）
(概念)
MemberFunction
(反射 TS)
 指定元对象类型反射成员函数I（不含构造函数与析构函数）
(概念)
SpecialMemberFunction
(反射 TS)
 指定元对象类型反射特殊成员函数
(概念)
Constructor
(反射 TS)
 指定元对象类型反射构造函数
(概念)
Destructor
(反射 TS)
 指定元对象类型反射析构函数
(概念)
Operator
(反射 TS)
 指定元对象类型反射运算符函数或转换函数
(概念)
ConversionOperator
(反射 TS)
 指定元对象类型反射转换函数
(概念)
Lambda
(反射 TS)
 指定元对象类型反射非泛型 lambda 的闭包类型
(概念)
LambdaCapture
(反射 TS)
 指定元对象类型反射 lambda 捕获
(概念)

类
Object 操作
reflects_same
(反射 TS)
 检查二个元对象类型是否反射同一实体或别名
(类模板)
get_source_line
(反射 TS)
 获得被反射实体或别名的声明的预设行号
(类模板)
get_source_column
(反射 TS)
 获得被反射实体或别名的声明的实现定义列号
(类模板)
get_source_file_name
(反射 TS)
 获得被反射实体或别名的声明的预设文件名
(类模板)
ObjectSequence 操作
get_size
(反射 TS)
 获得元对象序列的大小
(类模板)
get_element
(反射 TS)
 获得元对象序列中拥有给定下标的元对象类型
(类模板)
unpack_sequence
(反射 TS)
 应用模板到元对象序列
(类模板)
Named 操作
is_unnamed
(反射 TS)
 检查被反射实体或别名是否为无名
(类模板)
get_name
(反射 TS)
 获得被反射实体或别名的无限定名
(类模板)
get_display_name
(反射 TS)
 获得被反射实体或别名的实现定义显示名
(类模板)
Alias 操作
get_alias
(反射 TS)
 获得反射被反射别名的关联实体的元对象类型
(类模板)
Type 操作
get_type
(反射 TS)
 获得反射被反射实体或别名的类型的元对象类型
(类模板)
get_reflected_type
(反射 TS)
 获得反射被反射实体或别名的类型
(类模板)
is_enum
(反射 TS)
 检查元对象类型是否反射枚举类型
(类模板)
is_union
(反射 TS)
 检查元对象类型是否反射联合体类型
(类模板)
uses_class_keyuses_struct_key
(反射 TS)
 分别检查元对象类型是否反射声明使用 class 或 struct 的非联合类类型
(类模板)
ScopeMember 操作
get_scope
(反射 TS)
 获得反射被反射实体或别名的作用域的元对象类型
(类模板)
Base 操作
get_class
(反射 TS)
 获得反射给定基类关系中基类的元对象类型
(类模板)
RecordMember 与 Base 操作
is_public
(反射 TS)
 检查被反射的成员或基类是否为公开
(类模板)
is_protected
(反射 TS)
 检查被反射的成员或基类是否为受保护
(类模板)
is_private
(反射 TS)
 检查被反射的成员或基类是否为私有
(类模板)
Record 操作
get_public_data_membersget_accessible_data_membersget_data_members
(反射 TS)
 获得元素反射被反射类的公开、可访问或全部数据成员的元对象序列类型
(类模板)
get_public_member_functionsget_accessible_member_functionsget_member_functions
(反射 TS)
 获得元素反射被反射类的公开、可访问或全部成员函数的元对象序列类型
(类模板)
get_constructors
(反射 TS)
 获得元素反射被反射类的全部构造函数的的元对象序列类型
(类模板)
get_operators
(反射 TS)
 获得元素反射声明于被反射类中的所有运算符函数及转换函数的的元对象序列类型
(类模板)
get_destructor
(反射 TS)
 获得反射被反射类的析构函数的元对象类型
(类模板)
get_public_member_typesget_accessible_member_typesget_member_types
(反射 TS)
 获得元素反射被反射类的公开、可访问或全部成员类型的元对象序列类型
(类模板)
get_public_base_classesget_accessible_base_classesget_base_classes
(反射 TS)
 获得元素反射被反射类的公开、可访问或全部基类的元对象序列类型
(类模板)
Enum 操作
is_scoped_enum
(反射 TS)
 检查被反射枚举是否有作用域
(类模板)
get_enumerators
(反射 TS)
 获得元素反射被反射枚举的枚举项的元对象序列类型
(类模板)
get_underlying_type
(反射 TS)
 获得反射被反射枚举的底层类型的元对象类型
(类模板)
Variable 操作
get_constant
(反射 TS)
 获得作为常量表达式的被反射变量的值
(类模板)
is_thread_local
(反射 TS)
 检查变量是否声明带 thread_local
(类模板)
FunctionParameter 操作
has_default_argument
(反射 TS)
 检查被反射的形参是否有默认实参
(类模板)
Callable 操作
get_parameters
(反射 TS)
 获得元素反射被反射函数的形参的元对象序列类型
(类模板)
is_vararg
(反射 TS)
 检查被反射函数的形参列表是否含有省略号形参
(类模板)
is_noexcept
(反射 TS)
 检查被反射函数是否为不抛出
(类模板)
is_deleted
(反射 TS)
 检查被反射函数是否为被删除
(类模板)
Variable 与 Callable 操作
is_constexpr
(反射 TS)
 检查被反射变量或函数是否为 constexpr
(类模板)
Namespace 与 Callable 操作
is_inline
(反射 TS)
 检查被反射的命名空间或函数是否为 inline
(类模板)
ParenthesizedExpression 操作
get_subexpression
(反射 TS)
 获得反射被反射的有括号表达式的无括号表达式的元对象类型
(类模板)
FunctionCallExpression 操作
get_callable
(反射 TS)
 获得反射被反射的 函数调用表达式 中的函数的元对象类型
(类模板)
FunctionalTypeConversion 操作
get_constructor
(反射 TS)
 获得反射被反射的 函数式类型转换表达式 中的构造函数的元对象类型
(类模板)
Variable 与 Function 操作
get_pointer
(反射 TS)
 获得被反射变量或函数的地址，或指向非静态成员的成员指针值
(类模板)
MemberFunction 函数
is_constis_volatilehas_lvalueref_qualifierhas_rvalueref_qualifier
(反射 TS)
 分别检查被反射成员函数是否声明带 const、 volatile、 & 或 && 限定符
(类模板)
is_override
(反射 TS)
 检查被反射的成员函数是否重写基类的成员函数
(类模板)
Record 与 MemberFunction 操作
is_final
(反射 TS)
 检查被反射的类或成员函数是否标记为 final
(类模板)
Variable 与 MemberFunction 操作
is_static
(反射 TS)
 检查被反射的变量是否拥有静态存储期，或被反射的成员函数是否为静态
(类模板)
SpecialMemberFunction 操作
is_implicitly_declared
(反射 TS)
 检查被反射的特殊成员函数是否为隐式声明
(类模板)
is_defaulted
(反射 TS)
 检查被反射的成员函数是否在其首条声明预置
(类模板)
Constructor 与 ConversionOperator 操作
is_explicit
(反射 TS)
 检查被反射的构造函数或转换函数是否声明带 explicit
(类模板)
MemberFunction 与 Destructor 操作
is_virtual
(反射 TS)
 检查被反射的成员函数是否为虚
(类模板)
is_pure_virtual
(反射 TS)
 检查被反射的成员函数是否为纯虚
(类模板)
Lambda 操作
get_captures
(反射 TS)
 获得元素反射被反射闭包类型的捕获的元对象序列类型
(类模板)
uses_default_copy_captureuses_default_reference_capture
(反射 TS)
 分别检查被反射闭包类型的 lambda 表达式的捕获默认是否为 = 或 &
(类模板)
is_call_operator_const
(反射 TS)
 检查被反射闭包类型的 operator() 是否声明带 const
(类模板)
LambdaCapture 操作
is_explictly_captured
(反射 TS)
 检查被反射的 lambda 捕获是否被显式捕获
(类模板)
is_init_capture
(反射 TS)
 检查被反射的 lambda 捕获是否为初始化捕获
(类模板)

概要

namespace std::experimental::reflect {
inline namespace v1 {

// 21.12.3 Concepts for meta-object types
template <class T>
concept Object = /* 见描述 */;
template <class T>
concept ObjectSequence = /* 见描述 */; // 细化 Object
template <class T>
concept TemplateParameterScope = /* 见描述 */; // 细化 Scope
template <class T>
concept Named = /* 见描述 */;          // 细化 Object
template <class T>
concept Alias = /* 见描述 */;          // 细化 Named 与 ScopeMember
template <class T>
concept RecordMember = /* 见描述 */;   // 细化 ScopeMember
template <class T>
concept Enumerator = /* 见描述 */;     // 细化 Constant
template <class T>
concept Variable = /* 见描述 */;       // 细化 Typed 与 ScopeMember
template <class T>
concept ScopeMember = /* 见描述 */;    // 细化 Named
template <class T>
concept Typed = /* 见描述 */;          // 细化 Object
template <class T>
concept Namespace = /* 见描述 */;      // 细化 Named 与 Scope
template <class T>
concept GlobalScope = /* 见描述 */;    // 细化 Namespace
template <class T>
concept Class = /* 见描述 */;          // 细化 Record
template <class T>
concept Enum = /* 见描述 */;           // 细化 Type, Scope, 与 ScopeMember
template <class T>
concept Record = /* 见描述 */;         // 细化 Type, Scope, 与 ScopeMember
template <class T>
concept Scope = /* 见描述 */;          // 细化 Object
template <class T>
concept Type = /* 见描述 */;           // 细化 Named
template <class T>
concept Constant = /* 见描述 */;       // 细化 Typed 与 ScopeMember
template <class T>
concept Base = /* 见描述 */;           // 细化 Object
template <class T>
concept FunctionParameter = /* 见描述 */; // 细化 Typed 与 ScopeMember
template <class T>
concept Callable = /* 见描述 */;       // 细化 Scope 与 ScopeMember
template <class T>
concept Expression = /* 见描述 */;     // 细化 Object
template <class T>
concept ParenthesizedExpression = /* 见描述 */; // 细化 Expression
template <class T>
concept FunctionCallExpression = /* 见描述 */; // 细化 Expression
template <class T>
concept FunctionalTypeConversion = /* 见描述 */; // 细化 Expression
template <class T>
concept Function = /* 见描述 */;       // 细化 Typed 与 Callable
template <class T>
concept MemberFunction = /* 见描述 */; // 细化 RecordMember 与 Function
template <class T>
concept SpecialMemberFunction = /* 见描述 */; // 细化 RecordMember
template <class T>
concept Constructor = /* 见描述 */;    // 细化 Callable 与 RecordMember
template <class T>
concept Destructor = /* 见描述 */;     // 细化 Callable 与 SpecialMemberFunction
template <class T>
concept Operator = /* 见描述 */;       // 细化 Function
template <class T>
concept ConversionOperator = /* 见描述 */; // 细化 MemberFunction 与 Operator
template <class T>
concept Lambda = /* 见描述 */;         // 细化 Type 与 Scope
template <class T>
concept LambdaCapture = /* 见描述 */;  // 细化 Variable

// 21.12.4 Meta-object operations
// Multi-concept operations
template <Object T> struct is_public;
template <Object T> struct is_protected;
template <Object T> struct is_private;
template <Object T> struct is_constexpr;
template <Object T> struct is_static;
template <Object T> struct is_final;
template <Object T> struct is_explicit;
template <Object T> struct is_inline;
template <Object T> struct is_virtual;
template <Object T> struct is_pure_virtual;
template <Object T> struct get_pointer;

template <class T>
requires RecordMember<T> || Base<T>
  constexpr auto is_public_v = is_public<T>::value;
template <class T>
requires RecordMember<T> || Base<T>
  constexpr auto is_protected_v = is_protected<T>::value;
template <class T>
requires RecordMember<T> || Base<T>
  constexpr auto is_private_v = is_private<T>::value;
template <class T>
requires Variable<T> || Callable<T>
  constexpr auto is_constexpr_v = is_constexpr<T>::value;
template <class T>
requires Variable<T> || MemberFunction<T>
  constexpr auto is_static_v = is_static<T>::value;
template <class T>
requires Class<T> || MemberFunction<T>
  constexpr auto is_final_v = is_final<T>::value;
template <class T>
requires Constructor<T> || ConversionOperator<T>
  constexpr auto is_explicit_v = is_explicit<T>::value;
template <class T>
requires Namespace<T> || Callable<T>
  constexpr auto is_inline_v = is_inline<T>::value;
template <class T>
requires Base<T> || MemberFunction<T> || Destructor<T>
  constexpr auto is_virtual_v = is_virtual<T>::value;
template <class T>
requires MemberFunction<T> || Destructor<T>
  constexpr auto is_pure_virtual_v = is_pure_virtual<T>::value;
template <class T>
requires Variable<T> || Function<T>
  constexpr auto get_pointer_v = get_pointer<T>::value;

// 21.12.4.1 Object operations
template <Object T1, Object T2> struct reflects_same;
template <Object T> struct get_source_line;
template <Object T> struct get_source_column;
template <Object T> struct get_source_file_name;

template <Object T1, Object T2>
  constexpr auto reflects_same_v = reflects_same<T1, T2>::value;
template <class T>
  constexpr auto get_source_line_v = get_source_line<T>::value;
template <class T>
  constexpr auto get_source_column_v = get_source_column<T>::value;
template <class T>
  constexpr auto get_source_file_name_v = get_source_file_name<T>::value;

// 21.12.4.2 ObjectSequence operations
template <ObjectSequence T> struct get_size;
template <size_t I, ObjectSequence T> struct get_element;
template <template <class...> class Tpl, ObjectSequence T>
  struct unpack_sequence;

template <ObjectSequence T>
  constexpr auto get_size_v = get_size<T>::value;
template <size_t I, ObjectSequence T>
  using get_element_t = typename get_element<I, T>::type;
template <template <class...> class Tpl, ObjectSequence T>
  using unpack_sequence_t = typename unpack_sequence<Tpl, T>::type;

// 21.12.4.3 Named operations
template <Named T> struct is_unnamed;
template <Named T> struct get_name;
template <Named T> struct get_display_name;

template <Named T>
  constexpr auto is_unnamed_v = is_unnamed<T>::value;
template <Named T>
  constexpr auto get_name_v = get_name<T>::value;
template <Named T>
  constexpr auto get_display_name_v = get_display_name<T>::value;

// 21.12.4.4 Alias operations
template <Alias T> struct get_aliased;

template <Alias T>
  using get_aliased_t = typename get_aliased<T>::type;

// 21.12.4.5 Type operations
template <Typed T> struct get_type;
template <Type T> struct get_reflected_type;
template <Type T> struct is_enum;
template <Class T> struct uses_class_key;
template <Class T> struct uses_struct_key;
template <Type T> struct is_union;

template <Typed T>
  using get_type_t = typename get_type<T>::type;
template <Type T>
  using get_reflected_type_t = typename get_reflected_type<T>::type;
template <Type T>
  constexpr auto is_enum_v = is_enum<T>::value;
template <Class T>
  constexpr auto uses_class_key_v = uses_class_key<T>::value;
template <Class T>
  constexpr auto uses_struct_key_v = uses_struct_key<T>::value;
template <Type T>
  constexpr auto is_union_v = is_union<T>::value;

// 21.12.4.6 Member operations
template <ScopeMember T> struct get_scope;
template <RecordMember T> struct is_public<T>;
template <RecordMember T> struct is_protected<T>;
template <RecordMember T> struct is_private<T>;
template <ScopeMember T>
  using get_scope_t = typename get_scope<T>::type;

// 21.12.4.7 Record operations
template <Record T> struct get_public_data_members;
template <Record T> struct get_accessible_data_members;
template <Record T> struct get_data_members;
template <Record T> struct get_public_member_functions;
template <Record T> struct get_accessible_member_functions;
template <Record T> struct get_member_functions;
template <Record T> struct get_public_member_types;
template <Record T> struct get_accessible_member_types;
template <Record T> struct get_member_types;
template <Record T> struct get_constructors;
template <Record T> struct get_destructor;
template <Record T> struct get_operators;
template <Class T> struct get_public_base_classes;
template <Class T> struct get_accessible_base_classes;
template <Class T> struct get_base_classes;
template <Class T> struct is_final<T>;

template <Record T>
  using get_public_data_members_t = typename get_public_data_members<T>::type;
template <Record T>
  using get_accessible_data_members_t = typename get_accessible_data_members<T>::type;
template <Record T>
  using get_data_members_t = typename get_data_members<T>::type;
template <Record T>
  using get_public_member_functions_t = typename get_public_member_functions<T>::type;
template <Record T>
  using get_accessible_member_functions_t = typename get_accessible_member_functions<T>::type;
template <Record T>
  using get_member_functions_t = typename get_member_functions<T>::type;
template <Record T>
  using get_public_member_types_t = typename get_public_member_types<T>::type;
template <Record T>
  using get_accessible_member_types_t = typename get_accessible_member_types<T>::type;
template <Record T>
  using get_member_types_t = typename get_member_types<T>::type;
template <Record T>
  using get_constructors_t = typename get_constructors<T>::type;
template <Record T>
  using get_destructor_t = typename get_destructor<T>::type;
template <Record T>
  using get_operators_t = typename get_operators<T>::type;
template <Class T>
  using get_public_base_classes_t = typename get_public_base_classes<T>::type;
template <Class T>
  using get_accessible_base_classes_t = typename get_accessible_base_classes<T>::type;
template <Class T>
  using get_base_classes_t = typename get_base_classes<T>::type;

// 21.12.4.8 Enum operations
template <Enum T> struct is_scoped_enum;
template <Enum T> struct get_enumerators;
template <Enum T> struct get_underlying_type;

template <Enum T>
  constexpr auto is_scoped_enum_v = is_scoped_enum<T>::value;
template <Enum T>
  using get_enumerators_t = typename get_enumerators<T>::type;
template <Enum T>
  using get_underlying_type_t = typename get_underlying_type<T>::type;

// 21.12.4.9 Value operations
template <Constant T> struct get_constant;
template <Variable T> struct is_constexpr<T>;
template <Variable T> struct is_static<T>;
template <Variable T> struct is_thread_local;
template <Variable T> struct get_pointer<T>;

template <Constant T>
  constexpr auto get_constant_v = get_constant<T>::value;
template <Variable T>
  constexpr auto is_thread_local_v = is_thread_local<T>::value;

// 21.12.4.10 Base operations
template <Base T> struct get_class;
template <Base T> struct is_virtual<T>;
template <Base T> struct is_public<T>;
template <Base T> struct is_protected<T>;
template <Base T> struct is_private<T>;

template <Base T>
  using get_class_t = typename get_class<T>::type;

// 21.12.4.11 Namespace operations
template <Namespace T> struct is_inline<T>;

// 21.12.4.12 FunctionParameter operations
template <FunctionParameter T> struct has_default_argument;

template <FunctionParameter T>
  constexpr auto has_default_argument_v = has_default_argument<T>::value;

// 21.12.4.13 Callable operations
template <Callable T> struct get_parameters;
template <Callable T> struct is_vararg;
template <Callable T> struct is_constexpr<T>;
template <Callable T> struct is_noexcept;
template <Callable T> struct is_inline<T>;
template <Callable T> struct is_deleted;

template <Callable T>
  using get_parameters_t = typename get_parameters<T>::type;
template <Callable T>
  constexpr auto is_vararg_v = is_vararg<T>::value;
template <Callable T>
  constexpr auto is_deleted_v = is_deleted<T>::value;

// 21.12.4.14 ParenthesizedExpression operations
template <ParenthesizedExpression T> struct get_subexpression;

template <ParenthesizedExpression T>
  using get_subexpression_t = typename get_subexpression<T>::type;

// 21.12.4.15 FunctionCallExpression operations
template <FunctionCallExpression T> struct get_callable;

template <FunctionCallExpression T>
  using get_callable_t = typename get_callable<T>::type;

// 21.12.4.16 FunctionalTypeConversion operations
template <FunctionalTypeConversion T> struct get_constructor;

template <FunctionalTypeConversion T>
  using get_constructor_t = typename get_constructor<T>::type;

// 21.12.4.17 Function operations
template <Function T> struct get_pointer<T>;

// 21.12.4.18 MemberFunction operations
template <MemberFunction T> struct is_static<T>;
template <MemberFunction T> struct is_const;
template <MemberFunction T> struct is_volatile;
template <MemberFunction T> struct has_lvalueref_qualifier;
template <MemberFunction T> struct has_rvalueref_qualifier;
template <MemberFunction T> struct is_virtual<T>;
template <MemberFunction T> struct is_pure_virtual<T>;
template <MemberFunction T> struct is_override;
template <MemberFunction T> struct is_final<T>;

template <MemberFunction T>
  constexpr auto is_const_v = is_const<T>::value;
template <MemberFunction T>
  constexpr auto is_volatile_v = is_volatile<T>::value;
template <MemberFunction T>
  constexpr auto has_lvalueref_qualifier_v = has_lvalueref_qualifier<T>::value;
template <MemberFunction T>
  constexpr auto has_rvalueref_qualifier_v = has_rvalueref_qualifier<T>::value;
template <MemberFunction T>
  constexpr auto is_override_v = is_override<T>::value;

// 21.12.4.19 SpecialMemberFunction operations
template <SpecialMemberFunction T> struct is_implicitly_declared;
template <SpecialMemberFunction T> struct is_defaulted;

template <SpecialMemberFunction T>
  constexpr auto is_implicitly_declared_v = is_implicitly_declared<T>::value;
template <SpecialMemberFunction T>
  constexpr auto is_defaulted_v = is_defaulted<T>::value;

// 21.12.4.20 Constructor operations
template <Constructor T> struct is_explicit<T>;

// 21.12.4.21 Destructor operations
template <Destructor T> struct is_virtual<T>;
template <Destructor T> struct is_pure_virtual<T>;

// 21.12.4.22 ConversionOperator operations
template <ConversionOperator T> struct is_explicit<T>;

// 21.12.4.23 Lambda operations
template <Lambda T> struct get_captures;
template <Lambda T> struct uses_default_copy_capture;
template <Lambda T> struct uses_default_reference_capture;
template <Lambda T> struct is_call_operator_const;

template <Lambda T>
  using get_captures_t = typename get_captures<T>::type;
template <Lambda T>
  constexpr auto uses_default_copy_capture_v = uses_default_copy_capture<T>::value;
template <Lambda T>
  constexpr auto uses_default_reference_capture_v = uses_default_reference_capture<T>::value;
template <Lambda T>
  constexpr auto is_call_operator_const_v = is_call_operator_const<T>::value;

// 21.12.4.24 LambdaCapture operations
template <LambdaCapture T> struct is_explicitly_captured;
template <LambdaCapture T> struct is_init_capture;

template <LambdaCapture T>
  constexpr auto is_explicitly_captured_v = is_explicitly_captured<T>::value;
template <LambdaCapture T>
  constexpr auto is_init_capture_v = is_init_capture<T>::value;

} // inline namespace v1
} // namespace std::experimental::reflect


实验性库头文件 <experimental/string_view>

< cpp‎ | header‎ | experimental

此头文件是库基础 TS (v1, v2) 的一部分。

类

名字 | 说明
std::experimental::basic_string_view (库基础 TS) | 表示到某个字符串的引用的类模板 (类模板)
std::experimental::string_view (库基础 TS) | std::experimental::basic_string_view <char> (typedef)
std::experimental::wstring_view (库基础 TS) | std::experimental::basic_string_view <wchar_t> (typedef)
std::experimental::u16string_view (库基础 TS) | std::experimental::basic_string_view <char16_t> (typedef)
std::experimental::u32string_view (库基础 TS) | std::experimental::basic_string_view <char32_t> (typedef)
std::hash < std::experimental::string_view > (库基础 TS) | (类模板特化)
std::hash < std::experimental::u16string_view > (库基础 TS) | (类模板特化)
std::hash < std::experimental::u32string_view > (库基础 TS) | (类模板特化)
std::hash < std::experimental::wstring_view > (库基础 TS) | (类模板特化)

函数

operator==operator!=operator<operator>operator<=operator>=
 以字典序比较两个视图
(函数模板)
输出
operator<<
 进行视图的流输出
(函数模板)

概要

namespace std {
  namespace experimental {
  inline namespace fundamentals_v1 {

    // 7.2，类模板 basic_string_view
    template<class charT, class traits = char_traits<charT>>
        class basic_string_view;

    // 7.9，basic_string_view 的非成员比较函数
    template<class charT, class traits>
    constexpr bool operator==(basic_string_view<charT, traits> x,
                              basic_string_view<charT, traits> y) noexcept;
    template<class charT, class traits>
    constexpr bool operator!=(basic_string_view<charT, traits> x,
                              basic_string_view<charT, traits> y) noexcept;
    template<class charT, class traits>
    constexpr bool operator< (basic_string_view<charT, traits> x,
                                 basic_string_view<charT, traits> y) noexcept;
    template<class charT, class traits>
    constexpr bool operator> (basic_string_view<charT, traits> x,
                              basic_string_view<charT, traits> y) noexcept;
    template<class charT, class traits>
    constexpr bool operator<=(basic_string_view<charT, traits> x,
                                 basic_string_view<charT, traits> y) noexcept;
    template<class charT, class traits>
    constexpr bool operator>=(basic_string_view<charT, traits> x,
                              basic_string_view<charT, traits> y) noexcept;
    // 见下文，充足的比较函数的额外重载

    // 7.10，插入符与提取符
    template<class charT, class traits>
      basic_ostream<charT, traits>&
        operator<<(basic_ostream<charT, traits>& os,
                   basic_string_view<charT, traits> str);

    // basic_string_view typedef 名
    typedef basic_string_view<char> string_view;
    typedef basic_string_view<char16_t> u16string_view;
    typedef basic_string_view<char32_t> u32string_view;
    typedef basic_string_view<wchar_t> wstring_view;

  }  // namespace fundamentals_v1
  }  // namespace experimental

  // 7.11，散列支持
  template <class T> struct hash;
  template <> struct hash<experimental::string_view>;
  template <> struct hash<experimental::u16string_view>;
  template <> struct hash<experimental::u32string_view>;
  template <> struct hash<experimental::wstring_view>;

}  // namespace std


标准库头文件 <filesystem>

< cpp‎ | header

此头文件是文件系统支持库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
定义于命名空间 std::filesystem

类
path
(C++17)
 表示路径
(类)
filesystem_error
(C++17)
 文件系统错误时抛出的异常
(类)
directory_entry
(C++17)
 目录条目
(类)
directory_iterator
(C++17)
 指向目录内容的迭代器
(类)
recursive_directory_iterator
(C++17)
 指向一个目录及其子目录的内容的迭代器
(类)
file_status
(C++17)
 表示文件类型及权限
(类)
space_info
(C++17)
 关于文件系统上空闲及可用空间的信息
(类)
file_type
(C++17)
 文件的类型
(枚举)
perms
(C++17)
 标识文件系统权限
(枚举)
perm_options
(C++17)
 指定权限操作的语义
(枚举)
copy_options
(C++17)
 指定复制操作的语义
(枚举)
directory_options
(C++17)
 用于迭代目录内容的选项
(枚举)
file_time_type
(C++17)
 表示文件时间值
(typedef)

函数
u8path
(C++17)(C++20 中弃用)
 从 UTF-8 编码的源创建 path
(函数)
absolute
(C++17)
 组成一个绝对路径
(函数)
canonicalweakly_canonical
(C++17)
 组成一个规范路径
(函数)
relativeproximate
(C++17)
 组成一个相对路径
(函数)
copy
(C++17)
 复制文件或目录
(函数)
copy_file
(C++17)
 复制文件内容
(函数)
copy_symlink
(C++17)
 复制一个符号链接
(函数)
create_directorycreate_directories
(C++17)(C++17)
 创建新目录
(函数)
create_hard_link
(C++17)
 创建一个硬链接
(函数)
create_symlinkcreate_directory_symlink
(C++17)(C++17)
 创建一个符号链接
(函数)
current_path
(C++17)
 返回或设置当前工作目录
(函数)
exists
(C++17)
 检查路径是否指代既存的文件系统对象
(函数)
equivalent
(C++17)
 检查两个路径是否指代同一文件系统对象
(函数)
file_size
(C++17)
 返回文件的大小
(函数)
hard_link_count
(C++17)
 返回指代特定文件的硬链接数
(函数)
last_write_time
(C++17)
 获取或设置最近一次数据修改的时间
(函数)
permissions
(C++17)
 修改文件访问权限
(函数)
read_symlink
(C++17)
 获得符号链接的目标
(函数)
removeremove_all
(C++17)(C++17)
 移除一个文件或空目录
移除一个文件或递归地移除一个目录及其所有内容
(函数)
rename
(C++17)
 移动或重命名一个文件或目录
(函数)
resize_file
(C++17)
 以截断或填充零更改一个常规文件的大小
(函数)
space
(C++17)
 确定文件系统上的可用空闲空间
(函数)
statussymlink_status
(C++17)(C++17)
 确定文件属性
确定文件属性，检查符号链接目标
(函数)
temp_directory_path
(C++17)
 返回一个适用于临时文件的目录
(函数)
文件类型
is_block_file
(C++17)
 检查给定的路径是否表示块设备
(函数)
is_character_file
(C++17)
 检查给定的路径是否表示字符设备
(函数)
is_directory
(C++17)
 检查给定的路径是否表示一个目录
(函数)
is_empty
(C++17)
 检查给定的路径是否表示一个空文件或空目录
(函数)
is_fifo
(C++17)
 检查给定的路径是否表示一个命名管道
(函数)
is_other
(C++17)
 检查参数是否表示一个其他文件
(函数)
is_regular_file
(C++17)
 检查参数是否表示一个常规文件
(函数)
is_socket
(C++17)
 检查参数是否表示一个具名 IPC 套接字
(函数)
is_symlink
(C++17)
 检查参数是否表示一个符号链接
(函数)
status_known
(C++17)
 检查文件状态是否已知
(函数)

概要

#include <compare>

namespace std::filesystem {
  // 路径
  class path;

  // 路径非成员函数
  void swap(path& lhs, path& rhs) noexcept;
  size_t hash_value(const path& p) noexcept;

  // 文件系统错误
  class filesystem_error;

  // 目录条目
  class directory_entry;

  // 目录迭代器
  class directory_iterator;

  // 目录迭代器的范围访问
  directory_iterator begin(directory_iterator iter) noexcept;
  directory_iterator end(directory_iterator) noexcept;

  // 递归目录迭代器
  class recursive_directory_iterator;

  // 递归目录迭代器的范围访问
  recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept;
  recursive_directory_iterator end(recursive_directory_iterator) noexcept;

  // 文件状况
  class file_status;

  struct space_info {
    uintmax_t capacity;
    uintmax_t free;
    uintmax_t available;

    friend bool operator==(const space_info&, const space_info&) = default;
  };

  // 枚举
  enum class file_type;
  enum class perms;
  enum class perm_options;
  enum class copy_options;
  enum class directory_options;

  using file_time_type = chrono::time_point<chrono::file_clock>;

  // 文件系统操作
  path absolute(const path& p);
  path absolute(const path& p, error_code& ec);

  path canonical(const path& p);
  path canonical(const path& p, error_code& ec);

  void copy(const path& from, const path& to);
  void copy(const path& from, const path& to, error_code& ec);
  void copy(const path& from, const path& to, copy_options options);
  void copy(const path& from, const path& to, copy_options options,
            error_code& ec);

  bool copy_file(const path& from, const path& to);
  bool copy_file(const path& from, const path& to, error_code& ec);
  bool copy_file(const path& from, const path& to, copy_options option);
  bool copy_file(const path& from, const path& to, copy_options option,
                 error_code& ec);

  void copy_symlink(const path& existing_symlink, const path& new_symlink);
  void copy_symlink(const path& existing_symlink, const path& new_symlink,
                    error_code& ec) noexcept;

  bool create_directories(const path& p);
  bool create_directories(const path& p, error_code& ec);

  bool create_directory(const path& p);
  bool create_directory(const path& p, error_code& ec) noexcept;

  bool create_directory(const path& p, const path& attributes);
  bool create_directory(const path& p, const path& attributes,
                        error_code& ec) noexcept;

  void create_directory_symlink(const path& to, const path& new_symlink);
  void create_directory_symlink(const path& to, const path& new_symlink,
                                error_code& ec) noexcept;

  void create_hard_link(const path& to, const path& new_hard_link);
  void create_hard_link(const path& to, const path& new_hard_link,
                        error_code& ec) noexcept;

  void create_symlink(const path& to, const path& new_symlink);
  void create_symlink(const path& to, const path& new_symlink,
                      error_code& ec) noexcept;

  path current_path();
  path current_path(error_code& ec);
  void current_path(const path& p);
  void current_path(const path& p, error_code& ec) noexcept;

  bool equivalent(const path& p1, const path& p2);
  bool equivalent(const path& p1, const path& p2, error_code& ec) noexcept;

  bool exists(file_status s) noexcept;
  bool exists(const path& p);
  bool exists(const path& p, error_code& ec) noexcept;

  uintmax_t file_size(const path& p);
  uintmax_t file_size(const path& p, error_code& ec) noexcept;

  uintmax_t hard_link_count(const path& p);
  uintmax_t hard_link_count(const path& p, error_code& ec) noexcept;

  bool is_block_file(file_status s) noexcept;
  bool is_block_file(const path& p);
  bool is_block_file(const path& p, error_code& ec) noexcept;

  bool is_character_file(file_status s) noexcept;
  bool is_character_file(const path& p);
  bool is_character_file(const path& p, error_code& ec) noexcept;

  bool is_directory(file_status s) noexcept;
  bool is_directory(const path& p);
  bool is_directory(const path& p, error_code& ec) noexcept;

  bool is_empty(const path& p);
  bool is_empty(const path& p, error_code& ec);

  bool is_fifo(file_status s) noexcept;
  bool is_fifo(const path& p);
  bool is_fifo(const path& p, error_code& ec) noexcept;

  bool is_other(file_status s) noexcept;
  bool is_other(const path& p);
  bool is_other(const path& p, error_code& ec) noexcept;

  bool is_regular_file(file_status s) noexcept;
  bool is_regular_file(const path& p);
  bool is_regular_file(const path& p, error_code& ec) noexcept;

  bool is_socket(file_status s) noexcept;
  bool is_socket(const path& p);
  bool is_socket(const path& p, error_code& ec) noexcept;

  bool is_symlink(file_status s) noexcept;
  bool is_symlink(const path& p);
  bool is_symlink(const path& p, error_code& ec) noexcept;

  file_time_type last_write_time(const path& p);
  file_time_type last_write_time(const path& p, error_code& ec) noexcept;
  void last_write_time(const path& p, file_time_type new_time);
  void last_write_time(const path& p, file_time_type new_time,
                       error_code& ec) noexcept;

  void permissions(const path& p, perms prms, perm_options opts=perm_options::replace);
  void permissions(const path& p, perms prms, error_code& ec) noexcept;
  void permissions(const path& p, perms prms, perm_options opts, error_code& ec);

  path proximate(const path& p, error_code& ec);
  path proximate(const path& p, const path& base = current_path());
  path proximate(const path& p, const path& base, error_code& ec);

  path read_symlink(const path& p);
  path read_symlink(const path& p, error_code& ec);

  path relative(const path& p, error_code& ec);
  path relative(const path& p, const path& base = current_path());
  path relative(const path& p, const path& base, error_code& ec);

  bool remove(const path& p);
  bool remove(const path& p, error_code& ec) noexcept;

  uintmax_t remove_all(const path& p);
  uintmax_t remove_all(const path& p, error_code& ec);

  void rename(const path& from, const path& to);
  void rename(const path& from, const path& to, error_code& ec) noexcept;

  void resize_file(const path& p, uintmax_t size);
  void resize_file(const path& p, uintmax_t size, error_code& ec) noexcept;

  space_info space(const path& p);
  space_info space(const path& p, error_code& ec) noexcept;

  file_status status(const path& p);
  file_status status(const path& p, error_code& ec) noexcept;

  bool status_known(file_status s) noexcept;

  file_status symlink_status(const path& p);
  file_status symlink_status(const path& p, error_code& ec) noexcept;

  path temp_directory_path();
  path temp_directory_path(error_code& ec);

  path weakly_canonical(const path& p);
  path weakly_canonical(const path& p, error_code& ec);
}

namespace std::ranges {
  template<>
  inline constexpr bool enable_borrowed_range<filesystem::directory_iterator> = true;
  template<>
  inline constexpr bool
    enable_borrowed_range<filesystem::recursive_directory_iterator> = true;

  template<>
  inline constexpr bool enable_view<filesystem::directory_iterator> = true;
  template<>
  inline constexpr bool enable_view<filesystem::recursive_directory_iterator> = true;
}

// 弃用
namespace std::filesystem {
  template<class Source>
    path u8path(const Source& source);
  template<class InputIterator>
    path u8path(InputIt first, InputIt last);
}

类 std::filesystem::path

namespace std::filesystem {
  class path {
  public:
    using value_type  = /* 见描述 */;
    using string_type = basic_string<value_type>;
    static constexpr value_type preferred_separator = /* 见描述 */;

    // 枚举 format
    enum format;

    // 构造函数与析构函数
    path() noexcept;
    path(const path& p);
    path(path&& p) noexcept;
    path(string_type&& source, format fmt = auto_format);
    template<class Source>
      path(const Source& source, format fmt = auto_format);
    template<class InputIt>
      path(InputIt first, InputIt last, format fmt = auto_format);
    template<class Source>
      path(const Source& source, const locale& loc, format fmt = auto_format);
    template<class InputIt>
      path(InputIt first, InputIt last, const locale& loc, format fmt = auto_format);
    ~path();

    // 赋值
    path& operator=(const path& p);
    path& operator=(path&& p) noexcept;
    path& operator=(string_type&& source);
    path& assign(string_type&& source);
    template<class Source>
      path& operator=(const Source& source);
    template<class Source>
      path& assign(const Source& source);
    template<class InputIt>
      path& assign(InputIt first, InputIt last);

    // 后附
    path& operator/=(const path& p);
    template<class Source>
      path& operator/=(const Source& source);
    template<class Source>
      path& append(const Source& source);
    template<class InputIt>
      path& append(InputIt first, InputIt last);

    // 连接
    path& operator+=(const path& x);
    path& operator+=(const string_type& x);
    path& operator+=(basic_string_view<value_type> x);
    path& operator+=(const value_type* x);
    path& operator+=(value_type x);
    template<class Source>
      path& operator+=(const Source& x);
    template<class ECharT>
      path& operator+=(ECharT x);
    template<class Source>
      path& concat(const Source& x);
    template<class InputIt>
      path& concat(InputIt first, InputIt last);

    // 修改器
    void  clear() noexcept;
    path& make_preferred();
    path& remove_filename();
    path& replace_filename(const path& replacement);
    path& replace_extension(const path& replacement = path());
    void  swap(path& rhs) noexcept;

    // 非成员函数
    friend bool operator==(const path& lhs, const path& rhs) noexcept;
    friend strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept;

    friend path operator/ (const path& lhs, const path& rhs);

    // 原生格式观察器
    const string_type& native() const noexcept;
    const value_type*  c_str() const noexcept;
    operator string_type() const;

    template<class ECharT, class Traits = char_traits<ECharT>,
             class Allocator = allocator<ECharT>>
      basic_string<ECharT, Traits, Allocator>
        string(const Allocator& a = Allocator()) const;
    std::string    string() const;
    std::wstring   wstring() const;
    std::u8string  u8string() const;
    std::u16string u16string() const;
    std::u32string u32string() const;

    // 通用格式观察器
    template<class ECharT, class Traits = char_traits<ECharT>,
             class Allocator = allocator<ECharT>>
      basic_string<ECharT, Traits, Allocator>
        generic_string(const Allocator& a = Allocator()) const;
    std::string    generic_string() const;
    std::wstring   generic_wstring() const;
    std::u8string  generic_u8string() const;
    std::u16string generic_u16string() const;
    std::u32string generic_u32string() const;

    // 比较
    int compare(const path& p) const noexcept;
    int compare(const string_type& s) const;
    int compare(basic_string_view<value_type> s) const;
    int compare(const value_type* s) const;

    // 分解
    path root_name() const;
    path root_directory() const;
    path root_path() const;
    path relative_path() const;
    path parent_path() const;
    path filename() const;
    path stem() const;
    path extension() const;

    // 查询
    [[nodiscard]] bool empty() const noexcept;
    bool has_root_name() const;
    bool has_root_directory() const;
    bool has_root_path() const;
    bool has_relative_path() const;
    bool has_parent_path() const;
    bool has_filename() const;
    bool has_stem() const;
    bool has_extension() const;
    bool is_absolute() const;
    bool is_relative() const;

    // 生成
    path lexically_normal() const;
    path lexically_relative(const path& base) const;
    path lexically_proximate(const path& base) const;

    // 迭代器
    class iterator;
    using const_iterator = iterator;

    iterator begin() const;
    iterator end() const;

    // path 插入器与提取器
    template<class CharT, class Traits>
      friend basic_ostream<CharT, Traits>&
        operator<<(basic_ostream<CharT, Traits>& os, const path& p);
    template<class CharT, class Traits>
      friend basic_istream<CharT, Traits>&
        operator>>(basic_istream<CharT, Traits>& is, path& p);
  };
}

类 std::filesystem::filesystem_error

namespace std::filesystem {
  class filesystem_error : public system_error {
  public:
    filesystem_error(const string& what_arg, error_code ec);
    filesystem_error(const string& what_arg,
                     const path& p1, error_code ec);
    filesystem_error(const string& what_arg,
                     const path& p1, const path& p2, error_code ec);

    const path& path1() const noexcept;
    const path& path2() const noexcept;
    const char* what() const noexcept override;
  };
}

类 std::filesystem::directory_entry

namespace std::filesystem {
  class directory_entry {
  public:
    // 构造函数与析构函数
    directory_entry() noexcept = default;
    directory_entry(const directory_entry&) = default;
    directory_entry(directory_entry&&) noexcept = default;
    explicit directory_entry(const filesystem::path& p);
    directory_entry(const filesystem::path& p, error_code& ec);
    ~directory_entry();

    // 赋值
    directory_entry& operator=(const directory_entry&) = default;
    directory_entry& operator=(directory_entry&&) noexcept = default;

    // 修改器
    void assign(const filesystem::path& p);
    void assign(const filesystem::path& p, error_code& ec);
    void replace_filename(const filesystem::path& p);
    void replace_filename(const filesystem::path& p, error_code& ec);
    void refresh();
    void refresh(error_code& ec) noexcept;

    // 观察器
    const filesystem::path& path() const noexcept;
    operator const filesystem::path&() const noexcept;
    bool exists() const;
    bool exists(error_code& ec) const noexcept;
    bool is_block_file() const;
    bool is_block_file(error_code& ec) const noexcept;
    bool is_character_file() const;
    bool is_character_file(error_code& ec) const noexcept;
    bool is_directory() const;
    bool is_directory(error_code& ec) const noexcept;
    bool is_fifo() const;
    bool is_fifo(error_code& ec) const noexcept;
    bool is_other() const;
    bool is_other(error_code& ec) const noexcept;
    bool is_regular_file() const;
    bool is_regular_file(error_code& ec) const noexcept;
    bool is_socket() const;
    bool is_socket(error_code& ec) const noexcept;
    bool is_symlink() const;
    bool is_symlink(error_code& ec) const noexcept;
    uintmax_t file_size() const;
    uintmax_t file_size(error_code& ec) const noexcept;
    uintmax_t hard_link_count() const;
    uintmax_t hard_link_count(error_code& ec) const noexcept;
    file_time_type last_write_time() const;
    file_time_type last_write_time(error_code& ec) const noexcept;
    file_status status() const;
    file_status status(error_code& ec) const noexcept;
    file_status symlink_status() const;
    file_status symlink_status(error_code& ec) const noexcept;

    bool operator==(const directory_entry& rhs) const noexcept;
    strong_ordering operator<=>(const directory_entry& rhs) const noexcept;

    // 插入器
    template<class charT, class traits>
      friend basic_ostream<charT, traits>&
        operator<<(basic_ostream<charT, traits>& os, const directory_entry& d);

  private:
    filesystem::path pathobject;        // 仅用于阐释
    friend class directory_iterator;    // 仅用于阐释
  };
}

类 std::filesystem::directory_iterator

namespace std::filesystem {
  class directory_iterator {
  public:
    using iterator_category = input_iterator_tag;
    using value_type        = directory_entry;
    using difference_type   = ptrdiff_t;
    using pointer           = const directory_entry*;
    using reference         = const directory_entry&;

    // 成员函数
    directory_iterator() noexcept;
    explicit directory_iterator(const path& p);
    directory_iterator(const path& p, directory_options options);
    directory_iterator(const path& p, error_code& ec);
    directory_iterator(const path& p, directory_options options,
                       error_code& ec);
    directory_iterator(const directory_iterator& rhs);
    directory_iterator(directory_iterator&& rhs) noexcept;
    ~directory_iterator();

    directory_iterator& operator=(const directory_iterator& rhs);
    directory_iterator& operator=(directory_iterator&& rhs) noexcept;

    const directory_entry& operator*() const;
    const directory_entry* operator->() const;
    directory_iterator&    operator++();
    directory_iterator&    increment(error_code& ec);

    // 其他按输入迭代器要求的成员
  };
}

类 std::filesystem::recursive_directory_iterator

namespace std::filesystem {
  class recursive_directory_iterator {
  public:
    using iterator_category = input_iterator_tag;
    using value_type        = directory_entry;
    using difference_type   = ptrdiff_t;
    using pointer           = const directory_entry*;
    using reference         = const directory_entry&;

    // 构造函数与析构函数
    recursive_directory_iterator() noexcept;
    explicit recursive_directory_iterator(const path& p);
    recursive_directory_iterator(const path& p, directory_options options);
    recursive_directory_iterator(const path& p, directory_options options,
                                 error_code& ec);
    recursive_directory_iterator(const path& p, error_code& ec);
    recursive_directory_iterator(const recursive_directory_iterator& rhs);
    recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept;
    ~recursive_directory_iterator();

    // 观察器
    directory_options  options() const;
    int                depth() const;
    bool               recursion_pending() const;

    const directory_entry& operator*() const;
    const directory_entry* operator->() const;

    // 修改器
    recursive_directory_iterator&
      operator=(const recursive_directory_iterator& rhs);
    recursive_directory_iterator&
      operator=(recursive_directory_iterator&& rhs) noexcept;

    recursive_directory_iterator& operator++();
    recursive_directory_iterator& increment(error_code& ec);

    void pop();
    void pop(error_code& ec);
    void disable_recursion_pending();

    // 其他按输入迭代器要求的成员
  };
}

类 std::filesystem::file_status

namespace std::filesystem {
  class file_status {
  public:
    // 构造函数与析构函数
    file_status() noexcept : file_status(file_type::none) {}
    explicit file_status(file_type ft,
                         perms prms = perms::unknown) noexcept;
    file_status(const file_status&) noexcept = default;
    file_status(file_status&&) noexcept = default;
    ~file_status();

    // 赋值
    file_status& operator=(const file_status&) noexcept = default;
    file_status& operator=(file_status&&) noexcept = default;

    // 修改器
    void       type(file_type ft) noexcept;
    void       permissions(perms prms) noexcept;

    // 观察器
    file_type  type() const noexcept;
    perms      permissions() const noexcept;

    friend bool operator==(const file_status& lhs, const file_status& rhs) noexcept
      { return lhs.type() == rhs.type() && lhs.permissions() == rhs.permissions(); }
  };
}


标准库头文件 <format>

< cpp‎ | header

此头文件是格式化库的一部分。

类
formatter
(C++20)
 定义给定类型的格式化规则的类模板
(类模板)
basic_format_parse_contextformat_parse_contextwformat_parse_context
(C++20)(C++20)(C++20)
 格式化字符串分析器状态
(类模板)
basic_format_contextformat_contextwformat_context
(C++20)(C++20)(C++20)
 格式化状态，包括所有格式化参数和输出迭代器
(类模板)
basic_format_arg
(C++20)
 提供对用户定义格式化器的格式化参数的访问的类模板
(类模板)
basic_format_argsformat_argswformat_args
(C++20)(C++20)(C++20)
 提供对所有格式化参数的访问的类
(类模板)
format_error
(C++20)
 格式化错误时抛出的异常类型
(类)

函数
format
(C++20)
 在新 string 中存储参数的格式化表示
(函数模板)
format_to
(C++20)
 通过输出迭代器写其参数的格式化表示
(函数模板)
format_to_n
(C++20)
 通过输出迭代器写其参数的格式化表示，不超出指定的大小
(函数模板)
formatted_size
(C++20)
 确定存储其参数的格式化表示所需的字符数
(函数模板)
vformat
(C++20)
 std::format 的使用类型擦除的参数表示的非模板变体
(函数)
vformat_to
(C++20)
 std::format_to 的使用类型擦除的参数表示的非模板变体
(函数模板)
visit_format_arg
(C++20)
 用户定义格式化器的参数观览接口
(函数模板)
make_format_argsmake_wformat_args
(C++20)(C++20)
 创建引用所有格式化参数的类型擦除对象，可转换到 format_args
(函数模板)

概要

namespace std {
  // 格式化函数
  template<class... Args>
    string format(string_view fmt, const Args&... args);
  template<class... Args>
    wstring format(wstring_view fmt, const Args&... args);
  template<class... Args>
    string format(const locale& loc, string_view fmt, const Args&... args);
  template<class... Args>
    wstring format(const locale& loc, wstring_view fmt, const Args&... args);

  string vformat(string_view fmt, format_args args);
  wstring vformat(wstring_view fmt, wformat_args args);
  string vformat(const locale& loc, string_view fmt, format_args args);
  wstring vformat(const locale& loc, wstring_view fmt, wformat_args args);

  template<class Out, class... Args>
    Out format_to(Out out, string_view fmt, const Args&... args);
  template<class Out, class... Args>
    Out format_to(Out out, wstring_view fmt, const Args&... args);
  template<class Out, class... Args>
    Out format_to(Out out, const locale& loc, string_view fmt, const Args&... args);
  template<class Out, class... Args>
    Out format_to(Out out, const locale& loc, wstring_view fmt, const Args&... args);

  template<class Out>
    Out vformat_to(Out out, string_view fmt,
                   format_args_t<type_identity_t<Out>, char> args);
  template<class Out>
    Out vformat_to(Out out, wstring_view fmt,
                   format_args_t<type_identity_t<Out>, wchar_t> args);
  template<class Out>
    Out vformat_to(Out out, const locale& loc, string_view fmt,
                   format_args_t<type_identity_t<Out>, char> args);
  template<class Out>
    Out vformat_to(Out out, const locale& loc, wstring_view fmt,
                   format_args_t<type_identity_t<Out>, wchar_t> args);

  template<class Out> struct format_to_n_result {
    Out out;
    iter_difference_t<Out> size;
  };
  template<class Out, class... Args>
    format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                        string_view fmt, const Args&... args);
  template<class Out, class... Args>
    format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                        wstring_view fmt, const Args&... args);
  template<class Out, class... Args>
    format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                        const locale& loc, string_view fmt,
                                        const Args&... args);
  template<class Out, class... Args>
    format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
                                        const locale& loc, wstring_view fmt,
                                        const Args&... args);

  template<class... Args>
    size_t formatted_size(string_view fmt, const Args&... args);
  template<class... Args>
    size_t formatted_size(wstring_view fmt, const Args&... args);
  template<class... Args>
    size_t formatted_size(const locale& loc, string_view fmt, const Args&... args);
  template<class... Args>
    size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args);

  // 格式化器
  template<class T, class charT = char> struct formatter;

  // 类模板 basic_format_parse_context
  template<class charT> class basic_format_parse_context;
  using format_parse_context = basic_format_parse_context<char>;
  using wformat_parse_context = basic_format_parse_context<wchar_t>;

  template<class Out, class charT> class basic_format_context;
  using format_context = basic_format_context<unspecified, char>;
  using wformat_context = basic_format_context<unspecified, wchar_t>;

  // 实参
  // 类模板 basic_format_arg
  template<class Context> class basic_format_arg;

  template<class Visitor, class Context>
    /* 见描述 */ visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);

  // class template format-arg-store
  template<class Context, class... Args> struct /*format-arg-store*/;  // 仅为阐释

  template<class Context = format_context, class... Args>
    /*format-arg-store*/<Context, Args...>
      make_format_args(const Args&... args);
  template<class... Args>
    /*format-arg-store*/<wformat_context, Args...>
      make_wformat_args(const Args&... args);

  // 类模板 basic_format_args
  template<class Context> class basic_format_args;
  using format_args = basic_format_args<format_context>;
  using wformat_args = basic_format_args<wformat_context>;

  template<class Out, class charT>
    using format_args_t = basic_format_args<basic_format_context<Out, charT>>;

  // 类 format_error
  class format_error;
}

类模板 std::basic_format_parse_context

namespace std {
  template<class charT>
  class basic_format_parse_context {
  public:
    using char_type = charT;
    using const_iterator = typename basic_string_view<charT>::const_iterator;
    using iterator = const_iterator;

  private:
    iterator begin_;                                    // 仅为阐释
    iterator end_;                                      // 仅为阐释
    enum indexing { unknown, manual, automatic };       // 仅为阐释
    indexing indexing_;                                 // 仅为阐释
    size_t next_arg_id_;                                // 仅为阐释
    size_t num_args_;                                   // 仅为阐释

  public:
    constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt,
                                                  size_t num_args = 0) noexcept;
    basic_format_parse_context(const basic_format_parse_context&) = delete;
    basic_format_parse_context& operator=(const basic_format_parse_context&) = delete;

    constexpr const_iterator begin() const noexcept;
    constexpr const_iterator end() const noexcept;
    constexpr void advance_to(const_iterator it);

    constexpr size_t next_arg_id();
    constexpr void check_arg_id(size_t id);
  };
}

类模板 std::basic_format_context

namespace std {
  template<class Out, class charT>
  class basic_format_context {
    basic_format_args<basic_format_context> args_;      // 仅为阐释
    Out out_;                                           // 仅为阐释

  public:
    using iterator = Out;
    using char_type = charT;
    template<class T> using formatter_type = formatter<T, charT>;

    basic_format_arg<basic_format_context> arg(size_t id) const;
    std::locale locale();

    iterator out();
    void advance_to(iterator it);
  };
}

类模板 std::basic_format_arg

namespace std {
  template<class Context>
  class basic_format_arg {
  public:
    class handle;

  private:
    using char_type = typename Context::char_type;                     // 仅为阐释

    variant<monostate, bool, char_type,
            int, unsigned int, long long int, unsigned long long int,
            float, double, long double,
            const char_type*, basic_string_view<char_type>,
            const void*, handle> value;                                // 仅为阐释

    template<class T> explicit basic_format_arg(const T& v) noexcept;  // 仅为阐释
    explicit basic_format_arg(float n) noexcept;                       // 仅为阐释
    explicit basic_format_arg(double n) noexcept;                      // 仅为阐释
    explicit basic_format_arg(long double n) noexcept;                 // 仅为阐释
    explicit basic_format_arg(const char_type* s);                     // 仅为阐释

    template<class traits>
      explicit basic_format_arg(
        basic_string_view<char_type, traits> s) noexcept;              // 仅为阐释

    template<class traits, class Allocator>
      explicit basic_format_arg(
        const basic_string<char_type, traits, Allocator>& s) noexcept; // 仅为阐释

    explicit basic_format_arg(nullptr_t) noexcept;                     // 仅为阐释

    template<class T>
      explicit basic_format_arg(const T* p) noexcept;                  // 仅为阐释

  public:
    basic_format_arg() noexcept;

    explicit operator bool() const noexcept;
  };
}

类 std::basic_format_arg::handle

namespace std {
  template<class Context>
  class basic_format_arg<Context>::handle {
    const void* ptr_;                                           // 仅为阐释
    void (*format_)(basic_format_parse_context<char_type>&,
                    Context&, const void*);                     // 仅为阐释

    template<class T> explicit handle(const T& val) noexcept;   // 仅为阐释

    friend class basic_format_arg<Context>;                     // 仅为阐释

  public:
    void format(basic_format_parse_context<char_type>&, Context& ctx) const;
  };
}

类模板 format-arg-store

namespace std {
  template<class Context, class... Args>
  struct /*format-arg-store*/ {      // 仅为阐释
    array<basic_format_arg<Context>, sizeof...(Args)> args;
  };
}

类模板 std::basic_format_args

namespace std {
  template<class Context>
  class basic_format_args {
    size_t size_;                               // 仅为阐释
    const basic_format_arg<Context>* data_;     // 仅为阐释

  public:
    basic_format_args() noexcept;

    template<class... Args>
      basic_format_args(const /*format-arg-store*/<Context, Args...>& store) noexcept;

    basic_format_arg<Context> get(size_t i) const noexcept;
  };
}

类 std::format_error

namespace std {
  class format_error : public runtime_error {
  public:
    explicit format_error(const string& what_arg);
    explicit format_error(const char* what_arg);
  };
}


标准库头文件 <forward_list>

< cpp‎ | header

此头文件是容器库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
<initializer_list>
(C++11)
 std::initializer_list 类模板

类
forward_list
(C++11 起)
 单链表
(类模板)

函数
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 forward_list 中的值
(函数模板)
std::swap(std::forward_list)
(C++11)
 特化 std::swap 算法
(函数模板)
erase(std::forward_list)erase_if(std::forward_list)
(C++20)
 擦除所有满足特定判别标准的元素
(函数模板)
范围访问
begincbegin
(C++11)(C++14)
 返回指向容器或数组起始的迭代器
(函数模板)
endcend
(C++11)(C++14)
 返回指向容器或数组结尾的迭代器
(函数模板)
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
sizessize
(C++17)(C++20)
 返回容器或数组的大小
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)

概要

#include <compare>
#include <initializer_list>

namespace std {
  // 类模板 forward_list
  template<class T, class Allocator = allocator<T>> class forward_list;

  template<class T, class Allocator>
    bool operator==(const forward_list<T, Allocator>& x,
                    const forward_list<T, Allocator>& y);
  template<class T, class Allocator>
    /*synth-three-way-result*/<T> operator<=>(const forward_list<T, Allocator>& x,
                                              const forward_list<T, Allocator>& y);

  template<class T, class Allocator>
    void swap(forward_list<T, Allocator>& x, forward_list<T, Allocator>& y)
      noexcept(noexcept(x.swap(y)));

  template<class T, class Allocator, class U>
    typename forward_list<T, Allocator>::size_type
      erase(forward_list<T, Allocator>& c, const U& value);
  template<class T, class Allocator, class Predicate>
    typename forward_list<T, Allocator>::size_type
      erase_if(forward_list<T, Allocator>& c, Predicate pred);

  namespace pmr {
    template<class T>
      using forward_list = std::forward_list<T, polymorphic_allocator<T>>;
  }
}

类模板 std::forward_list

namespace std {
  template<class T, class Allocator = allocator<T>>
  class forward_list {
  public:
    // 类型
    using value_type      = T;
    using allocator_type  = Allocator;
    using pointer         = typename allocator_traits<Allocator>::pointer;
    using const_pointer   = typename allocator_traits<Allocator>::const_pointer;
    using reference       = value_type&;
    using const_reference = const value_type&;
    using size_type       = /* 由实现定义 */;
    using difference_type = /* 由实现定义 */;
    using iterator        = /* 由实现定义 */;
    using const_iterator  = /* 由实现定义 */;

    // 构造/复制/销毁
    forward_list() : forward_list(Allocator()) { }
    explicit forward_list(const Allocator&);
    explicit forward_list(size_type n, const Allocator& = Allocator());
    forward_list(size_type n, const T& value, const Allocator& = Allocator());
    template<class InputIt>
      forward_list(InputIt first, InputIt last, const Allocator& = Allocator());
    forward_list(const forward_list& x);
    forward_list(forward_list&& x);
    forward_list(const forward_list& x, const Allocator&);
    forward_list(forward_list&& x, const Allocator&);
    forward_list(initializer_list<T>, const Allocator& = Allocator());
    ~forward_list();
    forward_list& operator=(const forward_list& x);
    forward_list& operator=(forward_list&& x)
      noexcept(allocator_traits<Allocator>::is_always_equal::value);
    forward_list& operator=(initializer_list<T>);
    template<class InputIt>
      void assign(InputIt first, InputIt last);
    void assign(size_type n, const T& t);
    void assign(initializer_list<T>);
    allocator_type get_allocator() const noexcept;

    // 迭代器
    iterator before_begin() noexcept;
    const_iterator before_begin() const noexcept;
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;

    const_iterator cbegin() const noexcept;
    const_iterator cbefore_begin() const noexcept;
    const_iterator cend() const noexcept;

    // 容量
    [[nodiscard]] bool empty() const noexcept;
    size_type max_size() const noexcept;

    // 元素访问
    reference front();
    const_reference front() const;

    // 修改器
    template<class... Args> reference emplace_front(Args&&... args);
    void push_front(const T& x);
    void push_front(T&& x);
    void pop_front();

    template<class... Args>
      iterator emplace_after(const_iterator position, Args&&... args);
    iterator insert_after(const_iterator position, const T& x);
    iterator insert_after(const_iterator position, T&& x);

    iterator insert_after(const_iterator position, size_type n, const T& x);
    template<class InputIt>
      iterator insert_after(const_iterator position, InputIt first, InputIt last);
    iterator insert_after(const_iterator position, initializer_list<T> il);

    iterator erase_after(const_iterator position);
    iterator erase_after(const_iterator position, const_iterator last);
    void swap(forward_list&)
      noexcept(allocator_traits<Allocator>::is_always_equal::value);

    void resize(size_type sz);
    void resize(size_type sz, const value_type& c);
    void clear() noexcept;

    // forward_list 操作
    void splice_after(const_iterator position, forward_list& x);
    void splice_after(const_iterator position, forward_list&& x);
    void splice_after(const_iterator position, forward_list& x, const_iterator i);
    void splice_after(const_iterator position, forward_list&& x, const_iterator i);
    void splice_after(const_iterator position, forward_list& x,
                      const_iterator first, const_iterator last);
    void splice_after(const_iterator position, forward_list&& x,
                      const_iterator first, const_iterator last);

    size_type remove(const T& value);
    template<class Predicate> size_type remove_if(Predicate pred);

    size_type unique();
    template<class BinaryPredicate> size_type unique(BinaryPredicate binary_pred);

    void merge(forward_list& x);
    void merge(forward_list&& x);
    template<class Compare> void merge(forward_list& x, Compare comp);
    template<class Compare> void merge(forward_list&& x, Compare comp);

    void sort();
    template<class Compare> void sort(Compare comp);

    void reverse() noexcept;
  };

  template<class InputIt, class Allocator = allocator</*iter-value-type*/<InputIt>>>
    forward_list(InputIt, InputIt, Allocator = Allocator())
      -> forward_list</*iter-value-type*/<InputIt>, Allocator>;

  // 交换
  template<class T, class Allocator>
    void swap(forward_list<T, Allocator>& x, forward_list<T, Allocator>& y)
      noexcept(noexcept(x.swap(y)));
}


标准库头文件 <fstream>

< cpp‎ | header

此头文件是输入/输出库的一部分。

类
basic_filebuf
 抽象原生文件设备
(类模板)
basic_ifstream
 实现高层文件流输入操作
(类模板)
basic_ofstream
 实现高层文件流输出操作
(类模板)
basic_fstream
 实现高层文件流输入/输出操作
(类模板)
filebuf std::basic_filebuf <char>
(typedef)
wfilebuf std::basic_filebuf <wchar_t>
(typedef)
ifstream std::basic_ifstream <char>
(typedef)
wifstream std::basic_ifstream <wchar_t>
(typedef)
ofstream std::basic_ofstream <char>
(typedef)
wofstream std::basic_ofstream <wchar_t>
(typedef)
fstream std::basic_fstream <char>
(typedef)
wfstream std::basic_fstream <wchar_t>
(typedef)

函数
std::swap(std::basic_filebuf)
(C++11)
 特化 std::swap 算法
(函数模板)
std::swap(std::basic_ifstream)
(C++11)
 特化 std::swap 算法
(函数模板)
std::swap(std::basic_ofstream)
(C++11)
 特化 std::swap 算法
(函数模板)
std::swap(std::basic_fstream)
(C++11)
 特化 std::swap 算法
(函数模板)

概要

namespace std {
  template<class charT, class traits = char_traits<charT>>
    class basic_filebuf;
  using filebuf  = basic_filebuf<char>;
  using wfilebuf = basic_filebuf<wchar_t>;

  template<class charT, class traits = char_traits<charT>>
    class basic_ifstream;
  using ifstream  = basic_ifstream<char>;
  using wifstream = basic_ifstream<wchar_t>;

  template<class charT, class traits = char_traits<charT>>
    class basic_ofstream;
  using ofstream  = basic_ofstream<char>;
  using wofstream = basic_ofstream<wchar_t>;

  template<class charT, class traits = char_traits<charT>>
    class basic_fstream;
  using fstream  = basic_fstream<char>;
  using wfstream = basic_fstream<wchar_t>;
}

类模板 std::basic_filebuf

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_filebuf : public basic_streambuf<CharT, Traits> {
  public:
    using char_type   = CharT;
    using int_type    = typename Traits::int_type;
    using pos_type    = typename Traits::pos_type;
    using off_type    = typename Traits::off_type;
    using traits_type = Traits;

    // 构造函数/析构函数
    basic_filebuf();
    basic_filebuf(const basic_filebuf&) = delete;
    basic_filebuf(basic_filebuf&& rhs);
    virtual ~basic_filebuf();

    // 赋值与交换
    basic_filebuf& operator=(const basic_filebuf&) = delete;
    basic_filebuf& operator=(basic_filebuf&& rhs);
    void swap(basic_filebuf& rhs);

    // 成员
    bool is_open() const;
    basic_filebuf* open(const char* s, ios_base::openmode mode);
    basic_filebuf* open(const filesystem::path::value_type* s,
                        ios_base::openmode mode);   // 仅宽系统
    basic_filebuf* open(const string& s,
                        ios_base::openmode mode);
    basic_filebuf* open(const filesystem::path& s,
                        ios_base::openmode mode);
    basic_filebuf* close();

  protected:
    // 覆盖的虚函数
    streamsize showmanyc() override;
    int_type underflow() override;
    int_type uflow() override;
    int_type pbackfail(int_type c = Traits::eof()) override;
    int_type overflow (int_type c = Traits::eof()) override;

    basic_streambuf<CharT, Traits>* setbuf(char_type* s,
                                           streamsize n) override;
    pos_type seekoff(off_type off, ios_base::seekdir way,
                     ios_base::openmode which
                      = ios_base::in | ios_base::out) override;
    pos_type seekpos(pos_type sp,
                     ios_base::openmode which
                      = ios_base::in | ios_base::out) override;
    int      sync() override;
    void     imbue(const locale& loc) override;
  };

  template<class CharT, class Traits>
    void swap(basic_filebuf<CharT, Traits>& x,
              basic_filebuf<CharT, Traits>& y);
}

类模板 std::basic_ifstream

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_ifstream : public basic_istream<CharT, Traits> {
  public:
    using char_type   = CharT;
    using int_type    = typename Traits::int_type;
    using pos_type    = typename Traits::pos_type;
    using off_type    = typename Traits::off_type;
    using traits_type = Traits;

    // 构造函数
    basic_ifstream();
    explicit basic_ifstream(const char* s,
                            ios_base::openmode mode = ios_base::in);
    explicit basic_ifstream(const filesystem::path::value_type* s,
                            ios_base::openmode mode = ios_base::in);// 仅宽系统
    explicit basic_ifstream(const string& s,
                            ios_base::openmode mode = ios_base::in);
    explicit basic_ifstream(const filesystem::path& s,
                            ios_base::openmode mode = ios_base::in);
    basic_ifstream(const basic_ifstream&) = delete;
    basic_ifstream(basic_ifstream&& rhs);

    // 赋值与交换
    basic_ifstream& operator=(const basic_ifstream&) = delete;
    basic_ifstream& operator=(basic_ifstream&& rhs);
    void swap(basic_ifstream& rhs);

    // 成员
    basic_filebuf<CharT, Traits>* rdbuf() const;

    bool is_open() const;
    void open(const char* s, ios_base::openmode mode = ios_base::in);
    void open(const filesystem::path::value_type* s,
              ios_base::openmode mode = ios_base::in);  // 仅宽系统
    void open(const string& s, ios_base::openmode mode = ios_base::in);
    void open(const filesystem::path& s, ios_base::openmode mode = ios_base::in);
    void close();
  private:
    basic_filebuf<CharT, Traits> sb;    // 仅用于阐释
  };

  template<class CharT, class Traits>
    void swap(basic_ifstream<CharT, Traits>& x,
              basic_ifstream<CharT, Traits>& y);
}

类模板 std::basic_ofstream

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_ofstream : public basic_ostream<CharT, Traits> {
  public:
    using char_type   = CharT;
    using int_type    = typename Traits::int_type;
    using pos_type    = typename Traits::pos_type;
    using off_type    = typename Traits::off_type;
    using traits_type = Traits;

    // 构造函数
    basic_ofstream();
    explicit basic_ofstream(const char* s,
                            ios_base::openmode mode = ios_base::out);
    explicit basic_ofstream(const filesystem::path::value_type* s,  // 仅宽系统
                            ios_base::openmode mode = ios_base::out);
    explicit basic_ofstream(const string& s,
                            ios_base::openmode mode = ios_base::out);
    explicit basic_ofstream(const filesystem::path& s,
                            ios_base::openmode mode = ios_base::out);
    basic_ofstream(const basic_ofstream&) = delete;
    basic_ofstream(basic_ofstream&& rhs);

    // 赋值与交换
    basic_ofstream& operator=(const basic_ofstream&) = delete;
    basic_ofstream& operator=(basic_ofstream&& rhs);
    void swap(basic_ofstream& rhs);

    // 成员
    basic_filebuf<CharT, Traits>* rdbuf() const;

    bool is_open() const;
    void open(const char* s, ios_base::openmode mode = ios_base::out);
    void open(const filesystem::path::value_type* s,
              ios_base::openmode mode = ios_base::out);     // 仅宽系统
    void open(const string& s, ios_base::openmode mode = ios_base::out);
    void open(const filesystem::path& s, ios_base::openmode mode = ios_base::out);
    void close();
  private:
    basic_filebuf<CharT, Traits> sb;    // 仅用于阐释
  };

  template<class CharT, class Traits>
    void swap(basic_ofstream<CharT, Traits>& x,
              basic_ofstream<CharT, Traits>& y);
}

类模板 std::basic_fstream

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_fstream : public basic_iostream<CharT, Traits> {
  public:
    using char_type   = CharT;
    using int_type    = typename Traits::int_type;
    using pos_type    = typename Traits::pos_type;
    using off_type    = typename Traits::off_type;
    using traits_type = Traits;

    // 构造函数
    basic_fstream();
    explicit basic_fstream(
      const char* s,
      ios_base::openmode mode = ios_base::in | ios_base::out);
    explicit basic_fstream(
      const filesystem::path::value_type* s,
      ios_base::openmode mode = ios_base::in | ios_base::out);    // 仅宽系统
    explicit basic_fstream(
      const string& s,
      ios_base::openmode mode = ios_base::in | ios_base::out);
    explicit basic_fstream(
      const filesystem::path& s,
      ios_base::openmode mode = ios_base::in | ios_base::out);
    basic_fstream(const basic_fstream&) = delete;
    basic_fstream(basic_fstream&& rhs);

    // 赋值与交换
    basic_fstream& operator=(const basic_fstream&) = delete;
    basic_fstream& operator=(basic_fstream&& rhs);
    void swap(basic_fstream& rhs);

    // 成员
    basic_filebuf<CharT, Traits>* rdbuf() const;
    bool is_open() const;
    void open(
      const char* s,
      ios_base::openmode mode = ios_base::in | ios_base::out);
    void open(
      const filesystem::path::value_type* s,
      ios_base::openmode mode = ios_base::in | ios_base::out);    // 仅宽系统
    void open(
      const string& s,
      ios_base::openmode mode = ios_base::in | ios_base::out);
    void open(
      const filesystem::path& s,
      ios_base::openmode mode = ios_base::in | ios_base::out);
    void close();

  private:
    basic_filebuf<CharT, Traits> sb;    // 仅宽系统
  };

  template<class CharT, class Traits>
    void swap(basic_fstream<CharT, Traits>& x,
              basic_fstream<CharT, Traits>& y);
}


标准库头文件 <functional>

< cpp‎ | header

此头文件是函数对象库的一部分并提供标准散列函数。

命名空间
placeholders (C++11) 对 std::bind 表达式中的未绑定实参提供占位符

类
包装
function
(C++11)
 包装具有指定函数调用签名的任意可复制构造类型的可调用对象
(类模板)
move_only_function
(C++23)
 包装具有指定函数调用签名的任意类型的可调用对象
(类模板)
mem_fn
(C++11)
 从成员指针创建出函数对象
(函数模板)
reference_wrapper
(C++11)
 可复制构造 (CopyConstructible) 且可复制赋值 (CopyAssignable) 的引用包装器
(类模板)
辅助类
bad_function_call
(C++11)
 调用空的 std::function 时抛出的异常
(类)
is_bind_expression
(C++11)
 指示对象为 std::bind 表达式，或能被用作这种表达式
(类模板)
is_placeholder
(C++11)
 表明一个对象是标准占位符，或者可以用作标准占位符
(类模板)
算术运算
plus
 实现 x + y 的函数对象
(类模板)
minus
 实现 x - y 的函数对象
(类模板)
multiplies
 实现 x * y 的函数对象
(类模板)
divides
 实现 x / y 的函数对象
(类模板)
modulus
 实现 x % y 的函数对象
(类模板)
negate
 实现 -x 的函数对象
(类模板)
比较
equal_to
 实现 x == y 的函数对象
(类模板)
not_equal_to
 实现 x != y 的函数对象
(类模板)
greater
 实现 x > y 的函数对象
(类模板)
less
 实现 x < y 的函数对象
(类模板)
greater_equal
 实现 x >= y 的函数对象
(类模板)
less_equal
 实现 x <= y 的函数对象
(类模板)
概念约束的比较
ranges::equal_to
(C++20)
 实现 x == y 的函数对象
(类)
ranges::not_equal_to
(C++20)
 实现 x != y 的函数对象
(类)
ranges::greater
(C++20)
 实现 x > y 的函数对象
(类)
ranges::less
(C++20)
 实现 x < y 的函数对象
(类)
ranges::greater_equal
(C++20)
 实现 x >= y 的函数对象
(类)
ranges::less_equal
(C++20)
 实现 x <= y 的函数对象
(类)
compare_three_way
(C++20)
 实现 x <=> y 的函数对象
(类)
逻辑运算
logical_and
 实现 x && y 的函数对象
(类模板)
logical_or
 实现 x || y 的函数对象
(类模板)
logical_not
 实现 !x 的函数对象
(类模板)
逐位运算
bit_and
 实现 x & y 的函数对象
(类模板)
bit_or
 实现 x | y 的函数对象
(类模板)
bit_xor
 实现 x ^ y 的函数对象
(类模板)
bit_not
(C++14)
 实现 ~x 的函数对象
(类模板)
取反器
not_fn
(C++17)
 创建返回其保有的函数对象的结果之补的函数对象
(函数模板)
恒等
identity
(C++20)
 返回其未修改的参数的函数对象
(类)
搜索器
default_searcher
(C++17)
 标准 C++ 库搜索算法实现
(类模板)
boyer_moore_searcher
(C++17)
 Boyer-Moore 搜索算法实现
(类模板)
boyer_moore_horspool_searcher
(C++17)
 Boyer-Moore-Horspool 搜索算法实现
(类模板)
散列
hash
(C++11)
 散列函数对象
(类模板)
std::hash<Arithmetic>std::hash<Enumeration>std::hash<std::nullptr_t>std::hash<T*>
(C++11)
 std::hash 对基础、枚举以及指针类型的特化
(类模板特化)

常量
定义于命名空间 std::placeholders
_1, _2, _3, _4, ...
(C++11)
 用作 std::bind 表达式中的未绑定实参的占位符
(常量)

函数
bind_front
(C++20)
 按顺序绑定一定数量的参数到函数对象
(函数模板)
bind
(C++11)
 绑定一或多个实参到函数对象
(函数模板)
refcref
(C++11)(C++11)
 创建具有从其实参推导的类型的 std::reference_wrapper
(函数模板)
invokeinvoke_r
(C++17)(C++23)
 以给定实参和可能指定的返回类型 (C++23 起)调用任意可调用 (Callable) 对象
(函数模板)

C++11 中弃用并于 C++17 移除

基类
unary_function
(C++11 中弃用)(C++17 中移除)
 与适配器兼容的一元函数基类
(类模板)
binary_function
(C++11 中弃用)(C++17 中移除)
 与适配器兼容的二元函数基类
(类模板)
绑定器
binder1stbinder2nd
(C++11 中弃用)(C++17 中移除)
 持有一个二元函数及其实参之一的函数对象
(类模板)
bind1stbind2nd
(C++11 中弃用)(C++17 中移除)
 将一个实参绑定到二元函数
(函数模板)
函数适配器
pointer_to_unary_function
(C++11 中弃用)(C++17 中移除)
 适配器兼容的包装，用于包装一元函数的指针
(类模板)
pointer_to_binary_function
(C++11 中弃用)(C++17 中移除)
 适配器兼容的包装，用于包装二元函数的指针
(类模板)
ptr_fun
(C++11 中弃用)(C++17 中移除)
 从函数指针创建与适配器兼容的函数对象包装器
(函数模板)
mem_fun_tmem_fun1_tconst_mem_fun_tconst_mem_fun1_t
(C++11 中弃用)(C++17 中移除)
 指向零元或一元成员函数指针的包装器，可以一个对象指针调用
(类模板)
mem_fun
(C++11 中弃用)(C++17 中移除)
 从成员函数指针创建包装器，可以一个对象指针调用
(函数模板)
mem_fun_ref_tmem_fun1_ref_tconst_mem_fun_ref_tconst_mem_fun1_ref_t
(C++11 中弃用)(C++17 中移除)
 指向零元或一元成员函数指针的包装器，可以一个对象引用调用
(类模板)
mem_fun_ref
(C++11 中弃用)(C++17 中移除)
 从成员函数指针创建包装器，能以一个对象引用调用
(函数模板)

C++17 中弃用并于 C++20 移除

取反器
unary_negate
(C++17 中弃用)(C++20 中移除)
 包装器函数对象，返回所持有的一元谓词的补
(类模板)
binary_negate
(C++17 中弃用)(C++20 中移除)
 包装器函数对象，返回所持有的二元谓词的补
(类模板)
not1
(C++17 中弃用)(C++20 中移除)
 构造定制的 std::unary_negate 对象
(函数模板)
not2
(C++17 中弃用)(C++20 中移除)
 构造定制的 std::binary_negate 对象
(函数模板)

概要

namespace std {
  // invoke
  template<class F, class... Args>
    constexpr invoke_result_t<F, Args...> invoke(F&& f, Args&&... args)
      noexcept(is_nothrow_invocable_v<F, Args...>);
  template<class R, class F, class... Args>
    constexpr R invoke_r(F&& f, Args&&... args)
      noexcept(is_nothrow_invocable_r_v<R, F, Args...>);

  // reference_wrapper
  template<class T> class reference_wrapper;

  template<class T> constexpr reference_wrapper<T> ref(T&) noexcept;
  template<class T> constexpr reference_wrapper<const T> cref(const T&) noexcept;
  template<class T> void ref(const T&&) = delete;
  template<class T> void cref(const T&&) = delete;

  template<class T>
    constexpr reference_wrapper<T> ref(reference_wrapper<T>) noexcept;
  template<class T>
    constexpr reference_wrapper<const T> cref(reference_wrapper<T>) noexcept;

  template<class T> struct unwrap_reference;
  template<class T> using unwrap_reference_t = typename unwrap_reference<T>::type;
  template<class T> struct unwrap_ref_decay;
  template<class T> using unwrap_ref_decay_t = typename unwrap_ref_decay<T>::type;

  // 算术运算
  template<class T = void> struct plus;
  template<class T = void> struct minus;
  template<class T = void> struct multiplies;
  template<class T = void> struct divides;
  template<class T = void> struct modulus;
  template<class T = void> struct negate;
  template<> struct plus<void>;
  template<> struct minus<void>;
  template<> struct multiplies<void>;
  template<> struct divides<void>;
  template<> struct modulus<void>;
  template<> struct negate<void>;

  // 比较
  template<class T = void> struct equal_to;
  template<class T = void> struct not_equal_to;
  template<class T = void> struct greater;
  template<class T = void> struct less;
  template<class T = void> struct greater_equal;
  template<class T = void> struct less_equal;
  template<> struct equal_to<void>;
  template<> struct not_equal_to<void>;
  template<> struct greater<void>;
  template<> struct less<void>;
  template<> struct greater_equal<void>;
  template<> struct less_equal<void>;

  // 逻辑运算
  template<class T = void> struct logical_and;
  template<class T = void> struct logical_or;
  template<class T = void> struct logical_not;
  template<> struct logical_and<void>;
  template<> struct logical_or<void>;
  template<> struct logical_not<void>;

  // 逐位运算
  template<class T = void> struct bit_and;
  template<class T = void> struct bit_or;
  template<class T = void> struct bit_xor;
  template<class T = void> struct bit_not;
  template<> struct bit_and<void>;
  template<> struct bit_or<void>;
  template<> struct bit_xor<void>;
  template<> struct bit_not<void>;

  // identity
  struct identity;

  // 函数模板 not_fn
  template<class F> constexpr /* 未指明 */ not_fn(F&& f);

  // 函数模板 bind_front
  template<class F, class... Args> constexpr /* 未指明 */ bind_front(F&&, Args&&...);

  // bind
  template<class T> struct is_bind_expression;
  template<class T> struct is_placeholder;

  template<class F, class... BoundArgs>
    constexpr /* 未指明 */ bind(F&&, BoundArgs&&...);
  template<class R, class F, class... BoundArgs>
    constexpr /* 未指明 */ bind(F&&, BoundArgs&&...);

  namespace placeholders {
    // M 是实现定义的占位符数
    /* 见描述 */ _1;
    /* 见描述 */ _2;
               .
               .
               .
    /* 见描述 */ _M;
  }

  // 成员函数适配器
  template<class R, class T>
    constexpr /* 未指明 */ mem_fn(R T::*) noexcept;

  // 多态函数包装
  class bad_function_call;

  template<class> class function; // not defined
  template<class R, class... ArgTypes> class function<R(ArgTypes...)>;

  template<class R, class... ArgTypes>
    void swap(function<R(ArgTypes...)>&, function<R(ArgTypes...)>&) noexcept;

  template<class R, class... ArgTypes>
    bool operator==(const function<R(ArgTypes...)>&, nullptr_t) noexcept;

  // 搜索器
  template<class ForwardIter, class BinaryPredicate = equal_to<>>
    class default_searcher;

  template<class RandomAccessIter,
           class Hash = hash<typename iterator_traits<RandomAccessIter>::value_type>,
           class BinaryPredicate = equal_to<>>
    class boyer_moore_searcher;

  template<class RandomAccessIter,
           class Hash = hash<typename iterator_traits<RandomAccessIter>::value_type>,
           class BinaryPredicate = equal_to<>>
    class boyer_moore_horspool_searcher;

  // 散列函数主模板
  template<class T>
    struct hash;

  // 函数对象绑定器
  template<class T>
    inline constexpr bool is_bind_expression_v = is_bind_expression<T>::value;
  template<class T>
    inline constexpr int is_placeholder_v = is_placeholder<T>::value;

  namespace ranges {
    // 概念约束的比较
    struct equal_to;
    struct not_equal_to;
    struct greater;
    struct less;
    struct greater_equal;
    struct less_equal;
  }
}

类模板 std::reference_wrapper

namespace std {
  template<class T> class reference_wrapper {
  public:
    // 类型
    using type = T;

    // 构造/复制/析构
    template<class U>
      constexpr reference_wrapper(U&&) noexcept(see below);
    constexpr reference_wrapper(const reference_wrapper& x) noexcept;

    // 赋值
    constexpr reference_wrapper& operator=(const reference_wrapper& x) noexcept;

    // 访问
    constexpr operator T& () const noexcept;
    constexpr T& get() const noexcept;

    // 调用
    template<class... ArgTypes>
      constexpr invoke_result_t<T&, ArgTypes...> operator()(ArgTypes&&...) const;
  };
  template<class T>
    reference_wrapper(T&) -> reference_wrapper<T>;
}

类模板 std::unwrap_reference

namespace std {
  template<class T>
    struct unwrap_reference;
}

类模板 std::unwrap_ref_decay

namespace std {
  template<class T>
    struct unwrap_ref_decay;
}

类模板 std::plus

namespace std {
  template<class T = void> struct plus {
    constexpr T operator()(const T& x, const T& y) const;
  };

  template<> struct plus<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) + std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::minus

namespace std {
  template<class T = void> struct minus {
    constexpr T operator()(const T& x, const T& y) const;
  };

  template<> struct minus<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) - std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::multiplies

namespace std {
  template<class T = void> struct multiplies {
    constexpr T operator()(const T& x, const T& y) const;
  };

  template<> struct multiplies<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) * std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::divides

namespace std {
  template<class T = void> struct divides {
    constexpr T operator()(const T& x, const T& y) const;
  };

  template<> struct divides<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) / std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::modulus

namespace std {
  template<class T = void> struct modulus {
    constexpr T operator()(const T& x, const T& y) const;
  };

  template<> struct modulus<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) % std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::negate

namespace std {
  template<class T = void> struct negate {
    constexpr T operator()(const T& x) const;
  };

  template<> struct negate<void> {
    template<class T> constexpr auto operator()(T&& t) const
      -> decltype(-std::forward<T>(t));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::equal_to

namespace std {
  template<class T = void> struct equal_to {
    constexpr bool operator()(const T& x, const T& y) const;
  };

  template<> struct equal_to<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) == std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::not_equal_to

namespace std {
  template<class T = void> struct not_equal_to {
    constexpr bool operator()(const T& x, const T& y) const;
  };

  template<> struct not_equal_to<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) != std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::greater

namespace std {
  template<class T = void> struct greater {
    constexpr bool operator()(const T& x, const T& y) const;
  };

  template<> struct greater<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) > std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::less

namespace std {
  template<class T = void> struct less {
    constexpr bool operator()(const T& x, const T& y) const;
  };

  template<> struct less<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) < std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::greater_equal

namespace std {
  template<class T = void> struct greater_equal {
    constexpr bool operator()(const T& x, const T& y) const;
  };

  template<> struct greater_equal<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) >= std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::less_equal

namespace std {
  template<class T = void> struct less_equal {
    constexpr bool operator()(const T& x, const T& y) const;
  };

  template<> struct less_equal<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) <= std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类 std::ranges::equal_to

namespace std::ranges {
  struct equal_to {
    template<class T, class U>
    constexpr bool operator()(T&& t, U&& u) const;

    using is_transparent = /* 未指明 */;
  };
}

类 std::ranges::not_equal_to

namespace std::ranges {
  struct not_equal_to {
    template<class T, class U>
    constexpr bool operator()(T&& t, U&& u) const;

    using is_transparent = /* 未指明 */;
  };
}

类 std::ranges::greater

namespace std::ranges {
  struct greater {
    template<class T, class U>
    constexpr bool operator()(T&& t, U&& u) const;

    using is_transparent = /* 未指明 */;
  };
}

类 std::ranges::less

namespace std::ranges {
  struct less {
    template<class T, class U>
    constexpr bool operator()(T&& t, U&& u) const;

    using is_transparent = /* 未指明 */;
  };
}

类 std::ranges::greater_equal

namespace std::ranges {
  struct greater_equal {
    template<class T, class U>
    constexpr bool operator()(T&& t, U&& u) const;

    using is_transparent = /* 未指明 */;
  };
}

类 std::ranges::less_equal

namespace std::ranges {
  struct less_equal {
    template<class T, class U>
    constexpr bool operator()(T&& t, U&& u) const;

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::logical_and

namespace std {
  template<class T = void> struct logical_and {
    constexpr bool operator()(const T& x, const T& y) const;
  };

  template<> struct logical_and<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) && std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::logical_or

namespace std {
  template<class T = void> struct logical_or {
    constexpr bool operator()(const T& x, const T& y) const;
  };

  template<> struct logical_or<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) || std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::logical_not

namespace std {
  template<class T = void> struct logical_not {
    constexpr bool operator()(const T& x) const;
  };

  template<> struct logical_not<void> {
    template<class T> constexpr auto operator()(T&& t) const
      -> decltype(!std::forward<T>(t));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::bit_and

namespace std {
  template<class T = void> struct bit_and {
    constexpr T operator()(const T& x, const T& y) const;
  };

  template<> struct bit_and<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) & std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::bit_or

namespace std {
  template<class T = void> struct bit_or {
    constexpr T operator()(const T& x, const T& y) const;
  };

  template<> struct bit_or<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) | std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::bit_xor

namespace std {
  template<class T = void> struct bit_xor {
    constexpr T operator()(const T& x, const T& y) const;
  };

  template<> struct bit_xor<void> {
    template<class T, class U> constexpr auto operator()(T&& t, U&& u) const
      -> decltype(std::forward<T>(t) ^ std::forward<U>(u));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::bit_not

namespace std {
  template<class T = void> struct bit_not {
    constexpr T operator()(const T& x) const;
  };

  template<> struct bit_not<void> {
    template<class T> constexpr auto operator()(T&& t) const
      -> decltype(~std::forward<T>(t));

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::identity

namespace std {
  struct identity {
    template<class T>
      constexpr T&& operator()(T&& t) const noexcept;

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::is_bind_expression

namespace std {
  template<class T> struct is_bind_expression;
}

类模板 std::is_placeholder

namespace std {
  template<class T> struct is_placeholder;
}

类 std::bad_function_call

namespace std {
  class bad_function_call : public exception {
  public:
    // 特殊成员函数的规定见 [exception]
    const char* what() const noexcept override;
  };
}

类模板 std::function

namespace std {
  template<class> class function; // 不定义

  template<class R, class... ArgTypes>
  class function<R(ArgTypes...)> {
  public:
    using result_type = R;

    // 构造/复制/销毁
    function() noexcept;
    function(nullptr_t) noexcept;
    function(const function&);
    function(function&&) noexcept;
    template<class F> function(F);

    function& operator=(const function&);
    function& operator=(function&&);
    function& operator=(nullptr_t) noexcept;
    template<class F> function& operator=(F&&);
    template<class F> function& operator=(reference_wrapper<F>) noexcept;

    ~function();

    // function 修改器
    void swap(function&) noexcept;

    // function 容量
    explicit operator bool() const noexcept;

    // function 调用
    R operator()(ArgTypes...) const;

    // function 目标访问
    const type_info& target_type() const noexcept;
    template<class T>       T* target() noexcept;
    template<class T> const T* target() const noexcept;
  };

  template<class R, class... ArgTypes>
    function(R(*)(ArgTypes...)) -> function<R(ArgTypes...)>;

  template<class F> function(F) -> function</* see description */>;

  // 空指针比较函数
  template<class R, class... ArgTypes>
    bool operator==(const function<R(ArgTypes...)>&, nullptr_t) noexcept;

  // 特化的算法
  template<class R, class... ArgTypes>
    void swap(function<R(ArgTypes...)>&, function<R(ArgTypes...)>&) noexcept;
}

类模板 std::move_only_function

namespace std {
  template<class... S> class move_only_function; // 不定义

  template<class R, class... ArgTypes>
  class move_only_function<R(ArgTypes...) /*cv-ref*/ noexcept(/*noex*/)> {
  public:
    using result_type = R;

    // 构造/移动/销毁
    move_only_function() noexcept;
    move_only_function(nullptr_t) noexcept;
    move_only_function(move_only_function&&) noexcept;
    template<class F> move_only_function(F&&);

    template<class T, class... Args>
      explicit move_only_function(in_place_type_t<T>, Args&&...);
    template<class T, class U, class... Args>
      explicit move_only_function(in_place_type_t<T>, initializer_list<U>, Args&&...);

    move_only_function& operator=(move_only_function&&);
    move_only_function& operator=(nullptr_t) noexcept;
    template<class F> move_only_function& operator=(F&&);

    ~move_only_function();

    // move_only_function 调用
    explicit operator bool() const noexcept;

    R operator()(ArgTypes...) /*cv-ref*/ noexcept(/*noex*/);

    // move_only_function 工具
    void swap(move_only_function&) noexcept;

    friend void swap(move_only_function&, move_only_function&) noexcept;

    friend bool operator==(const move_only_function&, nullptr_t) noexcept;

  private:
    template<class VT>
      static constexpr bool /*is-callable-from*/ = /* 见描述 */; // 仅用于阐释
  };
}

类模板 std::default_searcher

namespace std {
  template<class ForwardIter1, class BinaryPredicate = equal_to<>>
    class default_searcher {
    public:
      constexpr default_searcher(ForwardIter1 pat_first, ForwardIter1 pat_last,
                                 BinaryPredicate pred = BinaryPredicate());

      template<class ForwardIter2>
        constexpr pair<ForwardIter2, ForwardIter2>
          operator()(ForwardIter2 first, ForwardIter2 last) const;

    private:
      ForwardIter1 pat_first_;            // 仅为阐释
      ForwardIter1 pat_last_;             // 仅为阐释
      BinaryPredicate pred_;              // 仅为阐释
  };
}

类模板 std::boyer_moore_searcher

namespace std {
  template<class RandomAccessIter1,
           class Hash = hash<typename iterator_traits<RandomAccessIter1>::value_type>,
           class BinaryPredicate = equal_to<>>
    class boyer_moore_searcher {
    public:
      boyer_moore_searcher(RandomAccessIter1 pat_first,
                           RandomAccessIter1 pat_last,
                           Hash hf = Hash(),
                           BinaryPredicate pred = BinaryPredicate());

      template<class RandomAccessIter2>
        pair<RandomAccessIter2, RandomAccessIter2>
          operator()(RandomAccessIter2 first, RandomAccessIter2 last) const;

    private:
      RandomAccessIter1 pat_first_;       // 仅为阐释
      RandomAccessIter1 pat_last_;        // 仅为阐释
      Hash hash_;                         // 仅为阐释
      BinaryPredicate pred_;              // 仅为阐释
    };
}

类模板 std::boyer_moore_horspool_searcher

namespace std {
  template<class RandomAccessIter1,
           class Hash = hash<typename iterator_traits<RandomAccessIter1>::value_type>,
           class BinaryPredicate = equal_to<>>
    class boyer_moore_horspool_searcher {
    public:
      boyer_moore_horspool_searcher(RandomAccessIter1 pat_first,
                                    RandomAccessIter1 pat_last,
                                    Hash hf = Hash(),
                                    BinaryPredicate pred = BinaryPredicate());

      template<class RandomAccessIter2>
        pair<RandomAccessIter2, RandomAccessIter2>
          operator()(RandomAccessIter2 first, RandomAccessIter2 last) const;

    private:
      RandomAccessIter1 pat_first_;       // 仅为阐释
      RandomAccessIter1 pat_last_;        // 仅为阐释
      Hash hash_;                         // 仅为阐释
      BinaryPredicate pred_;              // 仅为阐释
  };
}

参阅

<string> | 针对 std::string、std::u16string、std::u32string、std::wstring 特化 std::hash
<string_view> | 针对 std::string_view、std::u16string_view、std::u32string_view、std::wstring_view 特化 std::hash
<system_error> | 针对 std::error_code 特化 std::hash
<bitset> | 针对 std::bitset 特化 std::hash
<memory> | 针对 std::unique_ptr、std::shared_ptr 特化 std::hash
<typeindex> | 针对 std::type_index 特化 std::hash
<vector> | 针对 std::vector <bool> 特化 std::hash
<thread> | 针对 std::thread::id 特化 std::hash
<optional> | 针对 std::optional 特化 std::hash
<variant> | 针对 std::variant 特化 std::hash
<coroutine> | 针对 std::coroutine_handle 特化 std::hash
<stacktrace> | 针对 std::stacktrace_entry 及 std::basic_stacktrace 特化 std::hash


标准库头文件 <future>

< cpp‎ | header

此头文件是线程支持库的一部分。

类
promise
(C++11)
 存储一个值以进行异步获取
(类模板)
packaged_task
(C++11)
 打包一个函数，存储其返回值以进行异步获取
(类模板)
future
(C++11)
 等待被异步设置的值
(类模板)
shared_future
(C++11)
 等待被异步设置的值（可能为其他 future 所引用）
(类模板)
launch
(C++11)
 指定 std::async 所用的运行策略
(枚举)
future_status
(C++11)
 指定在 std::future 和 std::shared_future 上的定时等待的结果
(枚举)
future_error
(C++11)
 报告与 future 或 promise 有关的错误
(类)
future_errc
(C++11)
 鉴别 future 错误码
(枚举)
std::uses_allocator<std::promise>
(C++11)
 特化 std::uses_allocator 类型特征
(类模板特化)
std::uses_allocator<std::packaged_task>
(C++11)(C++17 前)
 特化 std::uses_allocator 类型特征
(类模板特化)

函数
async
(C++11)
 异步运行一个函数（有可能在新线程中执行），并返回保有其结果的 std::future
(函数模板)
future_category
(C++11)
 鉴别 future 错误类别
(函数)
std::swap(std::promise)
(C++11)
 特化 std::swap 算法
(函数模板)
std::swap(std::packaged_task)
(C++11)
 特化 std::swap 算法
(函数模板)

概要

namespace std {
  enum class future_errc {
    broken_promise = /* 由实现定义 */,
    future_already_retrieved = /* 由实现定义 */,
    promise_already_satisfied = /* 由实现定义 */,
    no_state = /* 由实现定义 */
  };

  enum class launch : /* 未指明 */ {
    async = /* 未指明 */,
    deferred = /* 未指明 */,
    /* 由实现定义 */
  };

  enum class future_status {
    ready,
    timeout,
    deferred
  };

  template<> struct is_error_code_enum<future_errc> : public true_type { };
  error_code make_error_code(future_errc e) noexcept;
  error_condition make_error_condition(future_errc e) noexcept;

  const error_category& future_category() noexcept;

  class future_error;

  template<class R> class promise;
  template<class R> class promise<R&>;
  template<> class promise<void>;

  template<class R>
    void swap(promise<R>& x, promise<R>& y) noexcept;

  template<class R, class Alloc>
    struct uses_allocator<promise<R>, Alloc>;

  template<class R> class future;
  template<class R> class future<R&>;
  template<> class future<void>;

  template<class R> class shared_future;
  template<class R> class shared_future<R&>;
  template<> class shared_future<void>;

  template<class> class packaged_task;  // 不定义
  template<class R, class... ArgTypes>
    class packaged_task<R(ArgTypes...)>;

  template<class R, class... ArgTypes>
    void swap(packaged_task<R(ArgTypes...)>&, packaged_task<R(ArgTypes...)>&) noexcept;

  template<class F, class... Args>
    [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>>
      async(F&& f, Args&&... args);
  template<class F, class... Args>
    [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>>
      async(launch policy, F&& f, Args&&... args);
}

类 std::future_error

namespace std {
  class future_error : public logic_error {
  public:
    explicit future_error(future_errc e);

    const error_code& code() const noexcept;
    const char*       what() const noexcept;

  private:
    error_code ec_;             // 仅用于阐释
  };
}

类模板 std::promise

namespace std {
  template<class R>
  class promise {
  public:
    promise();
    template<class Allocator>
      promise(allocator_arg_t, const Allocator& a);
    promise(promise&& rhs) noexcept;
    promise(const promise&) = delete;
    ~promise();

    // 赋值
    promise& operator=(promise&& rhs) noexcept;
    promise& operator=(const promise&) = delete;
    void swap(promise& other) noexcept;

    // 取得结果
    future<R> get_future();

    // 设置结果
    void set_value(/* 见描述 */);
    void set_exception(exception_ptr p);

    // 以延迟提醒设置结果
    void set_value_at_thread_exit(/* 见描述 */);
    void set_exception_at_thread_exit(exception_ptr p);
  };

  template<class R>
    void swap(promise<R>& x, promise<R>& y) noexcept;

  template<class R, class Alloc>
    struct uses_allocator<promise<R>, Alloc>;
}

类模板 std::future

namespace std {
  template<class R>
  class future {
  public:
    future() noexcept;
    future(future&&) noexcept;
    future(const future&) = delete;
    ~future();
    future& operator=(const future&) = delete;
    future& operator=(future&&) noexcept;
    shared_future<R> share() noexcept;

    // 取得值
    /* 见描述 */ get();

    // functions to check state
    bool valid() const noexcept;

    void wait() const;
    template<class Rep, class Period>
      future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;
    template<class Clock, class Duration>
      future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
  };
}

类模板 std::shared_future

namespace std {
  template<class R>
  class shared_future {
  public:
    shared_future() noexcept;
    shared_future(const shared_future& rhs) noexcept;
    shared_future(future<R>&&) noexcept;
    shared_future(shared_future&& rhs) noexcept;
    ~shared_future();
    shared_future& operator=(const shared_future& rhs) noexcept;
    shared_future& operator=(shared_future&& rhs) noexcept;

    // 取得值
    /* 见描述 */ get() const;

    // 检查状态的函数
    bool valid() const noexcept;

    void wait() const;
    template<class Rep, class Period>
      future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;
    template<class Clock, class Duration>
      future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
  };
}

类模板 std::packaged_task

namespace std {
  template<class> class packaged_task;  // 不定义

  template<class R, class... ArgTypes>
  class packaged_task<R(ArgTypes...)> {
  public:
    // 构造与析构
    packaged_task() noexcept;
    template<class F>
      explicit packaged_task(F&& f);
    ~packaged_task();

    // 无复制
    packaged_task(const packaged_task&) = delete;
    packaged_task& operator=(const packaged_task&) = delete;

    // 移动支持
    packaged_task(packaged_task&& rhs) noexcept;
    packaged_task& operator=(packaged_task&& rhs) noexcept;
    void swap(packaged_task& other) noexcept;

    bool valid() const noexcept;

    // 结果取得
    future<R> get_future();

    // 执行
    void operator()(ArgTypes... );
    void make_ready_at_thread_exit(ArgTypes...);

    void reset();
  };

  template<class R, class... ArgTypes>
  packaged_task(R (*)(ArgTypes...)) -> packaged_task<R(ArgTypes...)>;

  template<class F> packaged_task(F) -> packaged_task</* 见描述 */>;

  template<class R, class... ArgTypes>
    void swap(packaged_task<R(ArgTypes...)>& x, packaged_task<R(ArgTypes...)>& y) noexcept;
}


标准库头文件 <initializer_list>

< cpp‎ | header

此头文件是工具库的一部分。

类
initializer_list
(C++11)
 在列表初始化中创建临时数组然后引用它
(类模板)

函数
std::begin(std::initializer_list)
(C++11)
 特化 std::begin
(函数模板)
std::end(std::initializer_list)
(C++11)
 特化 std::end
(函数模板)

概要

namespace std {
  template<class E> class initializer_list {
  public:
    using value_type = E;
    using reference = const E&;
    using const_reference = const E&;
    using size_type = size_t;

    using iterator = const E*;
    using const_iterator = const E*;

    constexpr initializer_list() noexcept;

    constexpr size_t size() const noexcept;     // 元素数量
    constexpr const E* begin() const noexcept;  // 首元素
    constexpr const E* end() const noexcept;    // 末元素后一位置
  };

  // initializer_list 范围访问
  template<class E> constexpr const E* begin(initializer_list<E> il) noexcept;
  template<class E> constexpr const E* end(initializer_list<E> il) noexcept;
}


标准库头文件 <iomanip>

< cpp‎ | header

此头文件是输入/输出库的一部分。

函数
resetiosflags
 清除指定的 ios_base 标志
(函数)
setiosflags
 设置指定的 ios_base 标志
(函数)
setbase
 更改用于整数 I/O 的基数
(函数)
setfill
 更改填充字符
(函数模板)
setprecision
 更改浮点精度
(函数)
setw
 更改下个输入/输出域的宽度
(函数)
get_money
(C++11)
 剖析货币值
(函数模板)
put_money
(C++11)
 格式化并输出货币值
(函数模板)
get_time
(C++11)
 剖析指定格式的日期/时间值
(函数模板)
put_time
(C++11)
 按照指定格式格式化并输出日期/时间值
(函数模板)
quoted
(C++14)
 插入和读取带有内嵌空格的被引号括起来的字符串
(函数模板)

概要

namespace std {
  // 类型 T1 、 T2 ……为未指明的实现类型
  /*T1*/ resetiosflags(ios_base::fmtflags mask);
  /*T2*/ setiosflags  (ios_base::fmtflags mask);
  /*T3*/ setbase(int base);
  template<class CharT> /*T4*/ setfill(CharT c);
  /*T5*/ setprecision(int n);
  /*T6*/ setw(int n);
  template<class MoneyT> /*T7*/ get_money(MoneyT& mon, bool intl = false);
  template<class MoneyT> /*T8*/ put_money(const MoneyT& mon, bool intl = false);
  template<class CharT> /*T9*/ get_time(struct tm* tmb, const CharT* fmt);
  template<class CharT> /*T10*/ put_time(const struct tm* tmb, const CharT* fmt);

  template<class CharT>
    /*T11*/ quoted(const CharT* s, CharT delim = CharT('"'), CharT escape = CharT('\\'));

  template<class CharT, class Traits, class Allocator>
    /*T12*/ quoted(const basic_string<CharT, Traits, Allocator>& s,
               CharT delim = CharT('"'), CharT escape = CharT('\\'));

  template<class CharT, class Traits, class Allocator>
    /*T13*/ quoted(basic_string<CharT, Traits, Allocator>& s,
               CharT delim = CharT('"'), CharT escape = CharT('\\'));

  template<class CharT, class Traits>
    /*T14*/ quoted(basic_string_view<CharT, Traits> s,
               CharT delim = CharT('"'), CharT escape = CharT('\\'));
}


标准库头文件 <ios>

< cpp‎ | header

此头文件是输入/输出库的一部分。

包含
<iosfwd>
 输入/输出库中所有类的前置声明

类
ios_base
 管理格式化标志和输入/输出异常
(类)
basic_ios
 管理任意流缓冲
(类模板)
fpos
 表示流或文件中的绝对位置
(类模板)
io_errc
(C++11)
 IO 流的错误码
(枚举)
is_error_code_enum<std::io_errc>
(C++11)
 扩充类型特征 std::is_error_code_enum 以鉴别 iostream 错误码
(类模板特化)
streamoff
 表示相对的文件/流位置（距 fpos 的偏移），足以表示任何文件大小
(typedef)
streamsize
 表示一次 I/O 操作中转移的字符数或 I/O 缓冲区的大小
(typedef)

函数
iostream_category
(C++11)
 鉴别 iostream 错误类别
(函数)
make_error_code(std::io_errc)
(C++11)
 构造一个 iostream 错误码
(函数)
make_error_condition(std::io_errc)
(C++11)
 构造一个 iostream error_condition
(函数)
boolalphanoboolalpha
 在布尔值的文本和数值表示间切换
(函数)
showbasenoshowbase
 控制是否使用前缀指示数值基数
(函数)
showpointnoshowpoint
 控制浮点表示是否始终包含小数点
(函数)
showposnoshowpos
 控制是否将 + 号与非负数一同使用
(函数)
skipwsnoskipws
 控制是否跳过输入上的前导空白符
(函数)
uppercasenouppercase
 控制一些输出操作是否使用大写字母
(函数)
unitbufnounitbuf
 控制是否每次操作后冲洗输出
(函数)
internalleftright
 设置填充字符的布置
(函数)
dechexoct
 更改用于整数 I/O 的基数
(函数)
fixedscientifichexfloatdefaultfloat
(C++11)(C++11)
 更改用于浮点 I/O 的格式化
(函数)

概要

#include <iosfwd>

namespace std {
  using streamoff  = /* 由实现定义 */;
  using streamsize = /* 由实现定义 */;
  template<class StateT> class fpos;

  class ios_base;
  template<class CharT, class Traits = char_traits<CharT>>
    class basic_ios;

  // 操纵符
  ios_base& boolalpha  (ios_base& str);
  ios_base& noboolalpha(ios_base& str);

  ios_base& showbase   (ios_base& str);
  ios_base& noshowbase (ios_base& str);

  ios_base& showpoint  (ios_base& str);
  ios_base& noshowpoint(ios_base& str);

  ios_base& showpos    (ios_base& str);
  ios_base& noshowpos  (ios_base& str);

  ios_base& skipws     (ios_base& str);
  ios_base& noskipws   (ios_base& str);

  ios_base& uppercase  (ios_base& str);
  ios_base& nouppercase(ios_base& str);

  ios_base& unitbuf    (ios_base& str);
  ios_base& nounitbuf  (ios_base& str);

  // 调整域
  ios_base& internal   (ios_base& str);
  ios_base& left       (ios_base& str);
  ios_base& right      (ios_base& str);

  // 基底域
  ios_base& dec        (ios_base& str);
  ios_base& hex        (ios_base& str);
  ios_base& oct        (ios_base& str);

  // 浮点域
  ios_base& fixed      (ios_base& str);
  ios_base& scientific (ios_base& str);
  ios_base& hexfloat   (ios_base& str);
  ios_base& defaultfloat(ios_base& str);

  // 错误报告
  enum class io_errc {
    stream = 1
  };

  template<> struct is_error_code_enum<io_errc> : public true_type { };
  error_code make_error_code(io_errc e) noexcept;
  error_condition make_error_condition(io_errc e) noexcept;
  const error_category& iostream_category() noexcept;
}

类 std::ios_base

namespace std {
  class ios_base {
  public:
    class failure;              // 见描述

    // fmtflags
    using fmtflags = /*位掩码类型-1*/;
    static constexpr fmtflags boolalpha = /* 未指明 */;
    static constexpr fmtflags dec = /* 未指明 */;
    static constexpr fmtflags fixed = /* 未指明 */;
    static constexpr fmtflags hex = /* 未指明 */;
    static constexpr fmtflags internal = /* 未指明 */;
    static constexpr fmtflags left = /* 未指明 */;
    static constexpr fmtflags oct = /* 未指明 */;
    static constexpr fmtflags right = /* 未指明 */;
    static constexpr fmtflags scientific = /* 未指明 */;
    static constexpr fmtflags showbase = /* 未指明 */;
    static constexpr fmtflags showpoint = /* 未指明 */;
    static constexpr fmtflags showpos = /* 未指明 */;
    static constexpr fmtflags skipws = /* 未指明 */;
    static constexpr fmtflags unitbuf = /* 未指明 */;
    static constexpr fmtflags uppercase = /* 未指明 */;
    static constexpr fmtflags adjustfield = /* 见描述 */;
    static constexpr fmtflags basefield = /* 见描述 */;
    static constexpr fmtflags floatfield = /* 见描述 */;

    // iostate
    using iostate = /*位掩码类型-2*/;
    static constexpr iostate badbit = /* 未指明 */;
    static constexpr iostate eofbit = /* 未指明 */;
    static constexpr iostate failbit = /* 未指明 */;
    static constexpr iostate goodbit = /* 见描述 */;

    // openmode
    using openmode = /*位掩码类型-3*/;
    static constexpr openmode app = /* 未指明 */;
    static constexpr openmode ate = /* 未指明 */;
    static constexpr openmode binary = /* 未指明 */;
    static constexpr openmode in = /* 未指明 */;
    static constexpr openmode out = /* 未指明 */;
    static constexpr openmode trunc = /* 未指明 */;

    // seekdir
    using seekdir = /*位掩码类型-4*/;
    static constexpr seekdir beg = /* 未指明 */;
    static constexpr seekdir cur = /* 未指明 */;
    static constexpr seekdir end = /* 未指明 */;

    class Init;

    // fmtflags 状态
    fmtflags flags() const;
    fmtflags flags(fmtflags fmtfl);
    fmtflags setf(fmtflags fmtfl);
    fmtflags setf(fmtflags fmtfl, fmtflags mask);
    void unsetf(fmtflags mask);

    streamsize precision() const;
    streamsize precision(streamsize prec);
    streamsize width() const;
    streamsize width(streamsize wide);

    // 本地环境
    locale imbue(const locale& loc);
    locale getloc() const;

    // 存储
    static int xalloc();
    long&  iword(int idx);
    void*& pword(int idx);

    // 析构函数
    virtual ~ios_base();

    // 回调
    enum event { erase_event, imbue_event, copyfmt_event };
    using event_callback = void (*)(event, ios_base&, int idx);
    void register_callback(event_callback fn, int idx);

    ios_base(const ios_base&) = delete;
    ios_base& operator=(const ios_base&) = delete;

    static bool sync_with_stdio(bool sync = true);

  protected:
    ios_base();

  private:
    static int index;           // 仅用于阐释
    long*  iarray;              // 仅用于阐释
    void** parray;              // 仅用于阐释
  };
}

类 std::ios_base::failure

namespace std {
  class ios_base::failure : public system_error {
  public:
    explicit failure(const string& msg, const error_code& ec = io_errc::stream);
    explicit failure(const char* msg, const error_code& ec = io_errc::stream);
  };
}

类 std::ios_base::Init

namespace std {
  class ios_base::Init {
  public:
    Init();
    Init(const Init&) = default;
    ~Init();
    Init& operator=(const Init&) = default;
  private:
    static int init_cnt;        // 仅用于阐释
  };
}

类模板 std::fpos

namespace std {
  template<class StateT> class fpos {
  public:
    // 成员
    StateT state() const;
    void state(stateT);
  private;
    StateT st;                  // 仅用于阐释
  };
}

类模板 std::basic_ios

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_ios : public ios_base {
  public:
    using char_type   = CharT;
    using int_type    = typename Traits::int_type;
    using pos_type    = typename Traits::pos_type;
    using off_type    = typename Traits::off_type;
    using traits_type = Traits;

    // 标志函数
    explicit operator bool() const;
    bool operator!() const;
    iostate rdstate() const;
    void clear(iostate state = goodbit);
    void setstate(iostate state);
    bool good() const;
    bool eof()  const;
    bool fail() const;
    bool bad()  const;

    iostate exceptions() const;
    void exceptions(iostate except);

    // 构造函数/析构函数
    explicit basic_ios(basic_streambuf<CharT, Traits>* sb);
    virtual ~basic_ios();

    // 成员
    basic_ostream<CharT, Traits>* tie() const;
    basic_ostream<CharT, Traits>* tie(basic_ostream<CharT, Traits>* tiestr);

    basic_streambuf<CharT, Traits>* rdbuf() const;
    basic_streambuf<CharT, Traits>* rdbuf(basic_streambuf<CharT, Traits>* sb);

    basic_ios& copyfmt(const basic_ios& rhs);

    char_type fill() const;
    char_type fill(char_type ch);

    locale imbue(const locale& loc);

    char      narrow(char_type c, char dfault) const;
    char_type widen(char c) const;

    basic_ios(const basic_ios&) = delete;
    basic_ios& operator=(const basic_ios&) = delete;

  protected:
    basic_ios();
    void init(basic_streambuf<CharT, Traits>* sb);
    void move(basic_ios& rhs);
    void move(basic_ios&& rhs);
    void swap(basic_ios& rhs) noexcept;
    void set_rdbuf(basic_streambuf<CharT, Traits>* sb);

  };
}


标准库头文件 <iosfwd>

< cpp‎ | header

此头文件含有输入/输出库的前置声明。

前置声明
定义于头文件 <string>
std::char_traits | 描述字符类型的性质的类模板 (类模板)
std::char_traits <char> | (类模板特化)
std::char_traits <wchar_t> | (类模板特化)
std::char_traits <char8_t> (C++20) | (类模板特化)
std::char_traits <char16_t> (C++11) | (类模板特化)
std::char_traits <char32_t> (C++11) | (类模板特化)
定义于头文件 <memory>
allocator
 默认的分配器
(类模板)
定义于头文件 <ios>
basic_ios
 管理任意流缓冲
(类模板)
fpos
 表示流或文件中的绝对位置
(类模板)
定义于头文件 <streambuf>
basic_streambuf
 抽象原生设备
(类模板)
定义于头文件 <ostream>
basic_ostream
 包装给定的抽象设备（std::basic_streambuf）
并提供高层输出接口
(类模板)
定义于头文件 <istream>
basic_istream
 包装给定的抽象设备（std::basic_streambuf）
并提供高层输入接口
(类模板)
basic_iostream
 包装给定的抽象设备（std::basic_streambuf）
并提供高层输入/输出接口
(类模板)
定义于头文件 <fstream>
basic_filebuf
 抽象原生文件设备
(类模板)
basic_ifstream
 实现高层文件流输入操作
(类模板)
basic_ofstream
 实现高层文件流输出操作
(类模板)
basic_fstream
 实现高层文件流输入/输出操作
(类模板)
定义于头文件 <sstream>
basic_stringbuf
 实现原生字符串设备
(类模板)
basic_istringstream
 实现高层字符串流输入操作
(类模板)
basic_ostringstream
 实现高层字符串流输出操作
(类模板)
basic_stringstream
 实现高层字符串流输入/输出操作
(类模板)
定义于头文件 <syncstream>
basic_syncbuf
(C++20)
 同步输出设备的包装
(类模板)
basic_osyncstream
(C++20)
 同步输出流的包装
(类模板)
定义于头文件 <strstream>
strstreambuf
(C++98 中弃用)
 实现原生字符数组设备
(类)
istrstream
(C++98 中弃用)
 实现字符数组输入操作
(类)
ostrstream
(C++98 中弃用)
 实现字符数组输出操作
(类)
strstream
(C++98 中弃用)
 实现字符数组输入/输出操作
(类)

typedef 与特化
std::streampos | std::fpos < std::char_traits <char>::state_type>
std::wstreampos | std::fpos < std::char_traits <wchar_t>::state_type>
std::u8streampos | std::fpos < std::char_traits <char8_t>::state_type>
std::u16streampos | std::fpos < std::char_traits <char16_t>::state_type>
std::u32streampos | std::fpos < std::char_traits <char32_t>::state_type>
另外，对于每个声明于此头文件的类模板 std::basic_T，分别声明了 std::T 和 std::wT 为 std::basic_T<char> 和 std::basic_T<wchar_t> 的同义词。

概要

namespace std {
  template<class CharT> struct char_traits;
  template<> struct char_traits<char>;
  template<> struct char_traits<char8_t>;
  template<> struct char_traits<char16_t>;
  template<> struct char_traits<char32_t>;
  template<> struct char_traits<wchar_t>;

  template<class T> class allocator;

  template<class CharT, class Traits = char_traits<CharT>>
    class basic_ios;
  template<class CharT, class Traits = char_traits<CharT>>
    class basic_streambuf;
  template<class CharT, class Traits = char_traits<CharT>>
    class basic_istream;
  template<class CharT, class Traits = char_traits<CharT>>
    class basic_ostream;
  template<class CharT, class Traits = char_traits<CharT>>
    class basic_iostream;

  template<class CharT, class Traits = char_traits<CharT>>
           class Allocator = allocator<CharT>>
    class basic_stringbuf;
  template<class CharT, class Traits = char_traits<CharT>>
           class Allocator = allocator<CharT>>
    class basic_istringstream;
  template<class CharT, class Traits = char_traits<CharT>>
           class Allocator = allocator<CharT>>
    class basic_ostringstream;
  template<class CharT, class Traits = char_traits<CharT>>
           class Allocator = allocator<CharT>>
    class basic_stringstream;

  template<class CharT, class Traits = char_traits<CharT>>
    class basic_filebuf;
  template<class CharT, class Traits = char_traits<CharT>>
    class basic_ifstream;
  template<class CharT, class Traits = char_traits<CharT>>
    class basic_ofstream;
  template<class CharT, class Traits = char_traits<CharT>>
    class basic_fstream;

  template<class CharT, class Traits = char_traits<CharT>>
           class Allocator = allocator<CharT>>
    class basic_syncbuf;
  template<class CharT, class Traits = char_traits<CharT>>
           class Allocator = allocator<CharT>>
    class basic_osyncstream;

  template<class CharT, class Traits = char_traits<CharT>>
    class istreambuf_iterator;
  template<class CharT, class Traits = char_traits<CharT>>
    class ostreambuf_iterator;

  using ios  = basic_ios<char>;
  using wios = basic_ios<wchar_t>;

  using streambuf = basic_streambuf<char>;
  using istream   = basic_istream<char>;
  using ostream   = basic_ostream<char>;
  using iostream  = basic_iostream<char>;

  using stringbuf     = basic_stringbuf<char>;
  using istringstream = basic_istringstream<char>;
  using ostringstream = basic_ostringstream<char>;
  using stringstream  = basic_stringstream<char>;

  using filebuf  = basic_filebuf<char>;
  using ifstream = basic_ifstream<char>;
  using ofstream = basic_ofstream<char>;
  using fstream  = basic_fstream<char>;

  using syncbuf     = basic_syncbuf<char>;
  using osyncstream = basic_osyncstream<char>;

  using wstreambuf = basic_streambuf<wchar_t>;
  using wistream   = basic_istream<wchar_t>;
  using wostream   = basic_ostream<wchar_t>;
  using wiostream  = basic_iostream<wchar_t>;

  using wstringbuf     = basic_stringbuf<wchar_t>;
  using wistringstream = basic_istringstream<wchar_t>;
  using wostringstream = basic_ostringstream<wchar_t>;
  using wstringstream  = basic_stringstream<wchar_t>;

  using wfilebuf  = basic_filebuf<wchar_t>;
  using wifstream = basic_ifstream<wchar_t>;
  using wofstream = basic_ofstream<wchar_t>;
  using wfstream  = basic_fstream<wchar_t>;

  using wsyncbuf     = basic_syncbuf<wchar_t>;
  using wosyncstream = basic_osyncstream<wchar_t>;

  template<class State> class fpos;
  using streampos = fpos<char_traits<char>::state_type>;
  using wstreampos = fpos<char_traits<wchar_t>::state_type>;
  using u8streampos = fpos<char_traits<char8_t>::state_type>;
  using u16streampos = fpos<char_traits<char16_t>::state_type>;
  using u32streampos = fpos<char_traits<char32_t>::state_type>;
}

// 弃用
namespace std {
  class strstreambuf;
  class istrstream;
  class ostrstream;
  class strstream;
}


标准库头文件 <iostream>

< cpp‎ | header

此头文件是输入/输出库的一部分。

包含 <iostream> 表现为如同它定义一个 std::ios_base::Init 类型的静态存储期对象：若它是首个要被构造的 std::ios_base::Init 对象，则其构造函数初始化各个标准流对象，而若它是最后被销毁的 std::ios_base::Init 对象，则其析构函数将会冲洗这些对象（除了 cin 和 wcin）。

包含
<ios>
(C++11)
 std::ios_base 类、 std::basic_ios 类模板与数个 typedef
<streambuf>
(C++11)
 std::basic_streambuf 类模板
<istream>
(C++11)
 std::basic_istream 类模板与数个 typedef
<ostream>
(C++11)
 std::basic_ostream 、 std::basic_iostream 类模板与数个 typedef

对象
cinwcin
 从标准 C 输入流 stdin 中读取
(全局对象)
coutwcout
 写入到标准 C 输出流 stdout
(全局对象)
cerrwcerr
 写入到标准 C 错误流 stderr， 无缓冲
(全局对象)
clogwclog
 写入到标准 C 错误流 stderr
(全局对象)

概要

#include <ios>
#include <streambuf>
#include <istream>
#include <ostream>

namespace std {
  extern istream cin;
  extern ostream cout;
  extern ostream cerr;
  extern ostream clog;

  extern wistream wcin;
  extern wostream wcout;
  extern wostream wcerr;
  extern wostream wclog;
}


标准库头文件 <istream>

< cpp‎ | header

此头文件是输入/输出库的一部分。

basic_istream
 包装给定的抽象设备（std::basic_streambuf）
并提供高层输入接口
(类模板)
std::istream std::basic_istream <char>
(typedef)
std::wistream std::basic_istream <wchar_t>
(typedef)
basic_iostream
 包装给定的抽象设备（std::basic_streambuf）
并提供高层输入/输出接口
(类模板)
std::iostream std::basic_iostream <char>
(typedef)
std::wiostream std::basic_iostream <wchar_t>
(typedef)

函数
operator>>(std::basic_istream)
 提取字符和字符数组
(函数模板)
操纵符
ws
 消耗空白符
(函数模板)

概要

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
    class basic_istream;

  using istream  = basic_istream<char>;
  using wistream = basic_istream<wchar_t>;

  template<class CharT, class Traits = char_traits<CharT>>
    class basic_iostream;

  using iostream  = basic_iostream<char>;
  using wiostream = basic_iostream<wchar_t>;

  template<class CharT, class Traits>
    basic_istream<CharT, Traits>& ws(basic_istream<CharT, Traits>& is);

  template<class Istream, class T>
    Istream&& operator>>(Istream&& is, T&& x);
}

类模板 std::basic_istream

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_istream : virtual public basic_ios<CharT, Traits> {
  public:
    // 类型（继承自 basic_ios ）
    using char_type   = CharT;
    using int_type    = typename Traits::int_type;
    using pos_type    = typename Traits::pos_type;
    using off_type    = typename Traits::off_type;
    using traits_type = Traits;

    // 构造函数/析构函数
    explicit basic_istream(basic_streambuf<CharT, Traits>* sb);
    virtual ~basic_istream();

    // 前置工序/后置工序
    class sentry;

    // 有格式输出
    basic_istream<CharT, Traits>&
      operator>>(basic_istream<CharT, Traits>& (*pf)(basic_istream<CharT, Traits>&));
    basic_istream<CharT, Traits>&
      operator>>(basic_ios<CharT, Traits>& (*pf)(basic_ios<CharT, Traits>&));
    basic_istream<CharT, Traits>&
      operator>>(ios_base& (*pf)(ios_base&));

    basic_istream<CharT, Traits>& operator>>(bool& n);
    basic_istream<CharT, Traits>& operator>>(short& n);
    basic_istream<CharT, Traits>& operator>>(unsigned short& n);
    basic_istream<CharT, Traits>& operator>>(int& n);
    basic_istream<CharT, Traits>& operator>>(unsigned int& n);
    basic_istream<CharT, Traits>& operator>>(long& n);
    basic_istream<CharT, Traits>& operator>>(unsigned long& n);
    basic_istream<CharT, Traits>& operator>>(long long& n);
    basic_istream<CharT, Traits>& operator>>(unsigned long long& n);
    basic_istream<CharT, Traits>& operator>>(float& f);
    basic_istream<CharT, Traits>& operator>>(double& f);
    basic_istream<CharT, Traits>& operator>>(long double& f);

    basic_istream<CharT, Traits>& operator>>(void*& p);
    basic_istream<CharT, Traits>& operator>>(basic_streambuf<char_type, Traits>* sb);

    // 无格式输出
    streamsize gcount() const;
    int_type get();
    basic_istream<CharT, Traits>& get(char_type& c);
    basic_istream<CharT, Traits>& get(char_type* s, streamsize n);
    basic_istream<CharT, Traits>& get(char_type* s, streamsize n, char_type delim);
    basic_istream<CharT, Traits>& get(basic_streambuf<char_type, Traits>& sb);
    basic_istream<CharT, Traits>&
      get(basic_streambuf<char_type, Traits>& sb, char_type delim);

    basic_istream<CharT, Traits>& getline(char_type* s, streamsize n);
    basic_istream<CharT, Traits>& getline(char_type* s, streamsize n, char_type delim);

    basic_istream<CharT, Traits>& ignore(streamsize n = 1, int_type delim = Traits::eof());
    int_type                      peek();
    basic_istream<CharT, Traits>& read    (char_type* s, streamsize n);
    streamsize                    readsome(char_type* s, streamsize n);

    basic_istream<CharT, Traits>& putback(char_type c);
    basic_istream<CharT, Traits>& unget();
    int sync();

    pos_type tellg();
    basic_istream<CharT, Traits>& seekg(pos_type);
    basic_istream<CharT, Traits>& seekg(off_type, ios_base::seekdir);

  protected:
    // 复制/移动构造函数
    basic_istream(const basic_istream&) = delete;
    basic_istream(basic_istream&& rhs);

    // 赋值与交换
    basic_istream& operator=(const basic_istream&) = delete;
    basic_istream& operator=(basic_istream&& rhs);
    void swap(basic_istream& rhs);
  };

  // 字符提取模板
  template<class CharT, class Traits>
    basic_istream<CharT, Traits>& operator>>(basic_istream<CharT, Traits>&, CharT&);
  template<class Traits>
    basic_istream<char, Traits>& operator>>(basic_istream<char, Traits>&, unsigned char&);
  template<class Traits>
    basic_istream<char, Traits>& operator>>(basic_istream<char, Traits>&, signed char&);

  template<class CharT, class Traits, size_t N>
    basic_istream<CharT, Traits>&
      operator>>(basic_istream<CharT, Traits>&, CharT(&)[N]);
  template<class Traits, size_t N>
    basic_istream<char, Traits>&
      operator>>(basic_istream<char, Traits>&, unsigned char(&)[N]);
  template<class Traits, size_t N>
    basic_istream<char, Traits>&
      operator>>(basic_istream<char, Traits>&, signed char(&)[N]);
}

类 std::basic_istream::sentry

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_istream<CharT, Traits>::sentry {
    bool ok_;                   // 仅用于阐释
  public:
    explicit sentry(basic_istream<CharT, Traits>& is, bool noskipws = false);
    ~sentry();
    explicit operator bool() const { return ok_; }
    sentry(const sentry&) = delete;
    sentry& operator=(const sentry&) = delete;
  };
}

类模板 std::basic_iostream

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_iostream
    : public basic_istream<CharT, Traits>,
      public basic_ostream<CharT, Traits> {
  public:
    using char_type   = CharT;
    using int_type    = typename Traits::int_type;
    using pos_type    = typename Traits::pos_type;
    using off_type    = typename Traits::off_type;
    using traits_type = Traits;

    // 构造函数
    explicit basic_iostream(basic_streambuf<CharT, Traits>* sb);

    // 析构函数
    virtual ~basic_iostream();

  protected:
    // 构造函数
    basic_iostream(const basic_iostream&) = delete;
    basic_iostream(basic_iostream&& rhs);

    // 赋值与交换
    basic_iostream& operator=(const basic_iostream&) = delete;
    basic_iostream& operator=(basic_iostream&& rhs);
    void swap(basic_iostream& rhs);
  };
}


标准库头文件 <iterator>

< cpp‎ | header

此头文件是迭代器库的一部分。

概念
迭代器概念
indirectly_readable
(C++20)
 指定类型通过应用运算符 * 可读
(概念)
indirectly_writable
(C++20)
 指定可向迭代器所引用的对象写入值
(概念)
weakly_incrementable
(C++20)
 指定 semiregular 类型能以前后自增运算符自增
(概念)
incrementable
(C++20)
 指定 weakly_incrementable 类型上的自增操作保持相等性，而且该类型为 equality_comparable
(概念)
input_or_output_iterator
(C++20)
 指定该类型对象可以自增且可以解引用
(概念)
sentinel_for
(C++20)
 指定类型为某个 input_or_output_iterator 类型的哨位类型
(概念)
sized_sentinel_for
(C++20)
 指定可对一个迭代器和一个哨位应用 - 运算符，以在常数时间计算其距离
(概念)
input_iterator
(C++20)
 指定类型为输入迭代器，即可读取其所引用的值，且可前/后自增
(概念)
output_iterator
(C++20)
 指定类型为给定的值类型的输出迭代器，即可向其写入该类型的值，且可前/后自增
(概念)
forward_iterator
(C++20)
 指定 input_iterator 为向前迭代器，支持相等比较与多趟操作
(概念)
bidirectional_iterator
(C++20)
 指定 forward_iterator 为双向迭代器，支持向后移动
(概念)
random_access_iterator
(C++20)
 指定 bidirectional_iterator 为随机访问迭代器，支持常数时间内的前进和下标访问
(概念)
contiguous_iterator
(C++20)
 指定 random_access_iterator 为连续迭代器，指代内存中连续相接的元素
(概念)
间接可调用概念
indirectly_unary_invocableindirectly_regular_unary_invocable
(C++20)(C++20)
 指定可调用类型能以解引用某个 indirectly_readable 类型的结果进行调用
(概念)
indirect_unary_predicate
(C++20)
 指定可调用类型，在以解引用一个 indirectly_readable 类型的结果进行调用时，满足 predicate
(概念)
indirect_binary_predicate
(C++20)
 指定可调用类型，在以解引用两个 indirectly_readable 类型的结果进行调用时，满足 predicate
(概念)
indirect_equivalence_relation
(C++20)
 指定可调用类型，在以解引用两个 indirectly_readable 类型的结果进行调用时，满足 equivalence_relation
(概念)
indirect_strict_weak_order
(C++20)
 指定可调用类型，在以解引用两个 indirectly_readable 类型的结果进行调用时，满足 strict_weak_order
(概念)
常用算法要求
indirectly_movable
(C++20)
 指定可从 indirectly_readable 类型移动值给 indirectly_writable 类型
(概念)
indirectly_movable_storable
(C++20)
 指定可从 indirectly_readable 类型移动值给 indirectly_writable 类型，且该移动可以通过中间对象进行
(概念)
indirectly_copyable
(C++20)
 指定可从 indirectly_readable 类型复制值给 indirectly_writable 类型
(概念)
indirectly_copyable_storable
(C++20)
 指定可从 indirectly_readable 类型复制值给 indirectly_writable 类型，且该复制可以通过中间对象进行
(概念)
indirectly_swappable
(C++20)
 指定能交换两个 indirectly_readable 类型所引用的值
(概念)
indirectly_comparable
(C++20)
 指定能比较两个 indirectly_readable 类型所引用的值
(概念)
permutable
(C++20)
 指定在原位重排元素的算法的共同要求
(概念)
mergeable
(C++20)
 指定通过复制元素将已排序序列归并到输出序列中的算法的要求
(概念)
sortable
(C++20)
 指定重排序列为有序序列的算法的共用要求
(概念)

类
算法工具
indirect_result_t
(C++20)
 计算在解引用某组 indirectly_readable 类型的结果上调用可调用对象的结果
(别名模板)
projected
(C++20)
 用于对接受投影的算法指定约束的辅助模板
(类模板)
关联类型
incrementable_traits
(C++20)
 计算 weakly_incrementable 类型的差类型
(类模板)
indirectly_readable_traits
(C++20)
 计算 indirectly_readable 类型的值类型
(类模板)
iter_value_titer_reference_titer_difference_titer_rvalue_reference_titer_common_reference_t
(C++20)(C++20)(C++20)(C++20)(C++20)
 计算迭代器的关联类型
(别名模板)
原语
iterator_traits
 为迭代器各项性质提供统一接口
(类模板)
input_iterator_tagoutput_iterator_tagforward_iterator_tagbidirectional_iterator_tagrandom_access_iterator_tagcontiguous_iterator_tag
(C++20)
 用于指示迭代器类别的空类类型
(类)
iterator
(C++17 中弃用)
 用于简化简单的迭代器的必要类型定义的基类
(类模板)
适配器
reverse_iterator
 逆序遍历的迭代器适配器
(类模板)
move_iterator
(C++11)
 解引用结果为右值引用的迭代器适配器
(类模板)
move_sentinel
(C++20)
 用于 std::move_iterator 的哨位适配器
(类模板)
common_iterator
(C++20)
 适配一个迭代器类型及其哨位为一个公共迭代器类型
(类模板)
default_sentinel_t
(C++20)
 用于知晓其边界的迭代器的默认哨位
(类)
counted_iterator
(C++20)
 对到范围结尾距离进行跟踪的迭代器适配器
(类模板)
unreachable_sentinel_t
(C++20)
 始终与任何 weakly_incrementable 类型比较都不相等的哨位
(类)
back_insert_iterator
 用于在容器尾部插入的迭代器适配器
(类模板)
front_insert_iterator
 用于在容器头部插入的迭代器适配器
(类模板)
insert_iterator
 用于插入容器的迭代器适配器
(类模板)
流迭代器
istream_iterator
 从 std::basic_istream 读取的输入迭代器
(类模板)
ostream_iterator
 写入 std::basic_ostream 的输出迭代器
(类模板)
istreambuf_iterator
 从 std::basic_streambuf 读取的输入迭代器
(类模板)
ostreambuf_iterator
 写入 std::basic_streambuf 的输出迭代器
(类模板)

定制点对象
定义于命名空间 std::ranges
iter_move
(C++20)
 将解引用迭代器的结果转型为其关联的右值引用类型
(定制点对象)
iter_swap
(C++20)
 交换两个可解引用对象所引用的值
(定制点对象)

函数
适配器
make_reverse_iterator
(C++14)
 创建拥有从实参推出的类型的 std::reverse_iterator
(函数模板)
make_move_iterator
(C++11)
 创建拥有从实参推出的类型的 std::move_iterator
(函数模板)
front_inserter
 创建拥有从实参推出的类型的 std::front_insert_iterator
(函数模板)
back_inserter
 创建拥有从实参推出的类型的 std::back_insert_iterator
(函数模板)
inserter
 创建拥有从实参推出的类型的 std::insert_iterator
(函数模板)
非成员函数
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++11)(C++11)(C++20 中移除)(C++11)(C++11)(C++11)(C++11)(C++20)
 比较底层迭代器
(函数模板)
operator+
(C++11)
 令迭代器前进
(函数模板)
operator-
(C++11)
 计算两个迭代器适配器间的距离
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20)
 比较底层迭代器
(函数模板)
operator+
 令迭代器前进
(函数模板)
operator-
 计算两个迭代器适配器间的距离
(函数模板)
operator==operator!=
(C++20 中移除)
 比较两个 istream_iterator
(函数模板)
operator==operator!=
(C++20 中移除)
 比较两个 istreambuf_iterator
(函数模板)
操作
advance
 令迭代器前进给定的距离
(函数模板)
distance
 返回两个迭代器间的距离
(函数模板)
next
(C++11)
 令迭代器自增
(函数模板)
prev
(C++11)
 令迭代器自减
(函数模板)
ranges::advance
(C++20)
 令迭代器前进给定的距离或到给定的边界
(niebloid)
ranges::distance
(C++20)
 返回迭代器与哨位间的距离，或范围起始与结尾间的距离
(niebloid)
ranges::next
(C++20)
 自增迭代器给定的距离或到边界
(niebloid)
ranges::prev
(C++20)
 自减迭代器给定的距离或到边界
(niebloid)
范围访问
begincbegin
(C++11)(C++14)
 返回指向容器或数组起始的迭代器
(函数模板)
endcend
(C++11)(C++14)
 返回指向容器或数组结尾的迭代器
(函数模板)
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
sizessize
(C++17)(C++20)
 返回容器或数组的大小
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)

概要

#include <concepts>

namespace std {
  template<class T> using __with_reference = T&;  // 仅用于阐释
  template<class T> concept __Referenceable       // 仅用于阐释
    = requires { typename __with_reference<T>; };
  template<class T> concept __Dereferenceable     // 仅用于阐释
    = requires(T& t) {
      { *t } -> __Referenceable;  // 不要求保持相等性
    };

  // 关联类型
  // 可自增特征
  template<class> struct incrementable_traits;
  template<class T>
    using iter_difference_t = /* 见描述 */;

  // 间接可读特征
  template<class> struct indirectly_readable_traits;
  template<class T>
    using iter_value_t = /* 见描述 */;

  // 迭代器特征
  template<class I> struct iterator_traits;
  template<class T> requires is_object_v<T> struct iterator_traits<T*>;

  template<__Dereferenceable T>
    using iter_reference_t = decltype(*declval<T&>());

  namespace ranges {
    // 定制点
    inline namespace /* 未指明 */ {
      // ranges​::​iter_move
      inline constexpr /* 未指明 */ iter_move = /* 未指明 */;

      // ranges​::​iter_swap
      inline constexpr /* 未指明 */ iter_swap = /* 未指明 */;
    }
  }

  template<__Dereferenceable T>
    requires requires(T& t) {
      { ranges::iter_move(t) } -> __Referenceable;
    }
  using iter_rvalue_reference_t
    = decltype(ranges::iter_move(declval<T&>()));

  // 迭代器概念
  // 概念 indirectly_readable
  template<class In>
    concept indirectly_readable = /* 见描述 */;

  template<indirectly_readable T>
    using iter_common_reference_t =
      common_reference_t<iter_reference_t<T>, iter_value_t<T>&>;

  // 概念 indirectly_writable
  template<class Out, class T>
    concept indirectly_writable = /* 见描述 */;

  // 概念 weakly_incrementable
  template<class I>
    concept weakly_incrementable = /* 见描述 */;

  // 概念 incrementable
  template<class I>
    concept incrementable = /* 见描述 */;

  // 概念 input_or_output_iterator
  template<class I>
    concept input_or_output_iterator = /* 见描述 */;

  // 概念 sentinel_for
  template<class S, class I>
    concept sentinel_for = /* 见描述 */;

  // 概念 sized_sentinel_for
  template<class S, class I>
    inline constexpr bool disable_sized_sentinel = false;

  template<class S, class I>
    concept sized_sentinel_for = /* 见描述 */;

  // 概念 input_iterator
  template<class I>
    concept input_iterator = /* 见描述 */;

  // 概念 output_iterator
  template<class I, class T>
    concept output_iterator = /* 见描述 */;

  // 概念 forward_iterator
  template<class I>
    concept forward_iterator = /* 见描述 */;

  // 概念 bidirectional_iterator
  template<class I>
    concept bidirectional_iterator = /* 见描述 */;

  // 概念 random_access_iterator
  template<class I>
    concept random_access_iterator = /* 见描述 */;

  // 概念 contiguous_iterator
  template<class I>
    concept contiguous_iterator = /* 见描述 */;

  // 间接可调用要求
  // 间接可调用
  template<class F, class I>
    concept indirectly_unary_invocable = /* 见描述 */;

  template<class F, class I>
    concept indirectly_regular_unary_invocable = /* 见描述 */;

  template<class F, class I>
    concept indirect_unary_predicate = /* 见描述 */;

  template<class F, class I1, class I2>
    concept indirect_binary_predicate = /* 见描述 */;

  template<class F, class I1, class I2 = I1>
    concept indirect_equivalence_relation = /* 见描述 */;

  template<class F, class I1, class I2 = I1>
    concept indirect_strict_weak_order = /* 见描述 */;

  template<class F, class... Is>
    requires (indirectly_readable<Is> && ...) && invocable<F, iter_reference_t<Is>...>
      using indirect_result_t = invoke_result_t<F, iter_reference_t<Is>...>;

  // projected
  template<indirectly_readable I, indirectly_regular_unary_invocable<I> Proj>
    struct projected;

  template<weakly_incrementable I, class Proj>
    struct incrementable_traits<projected<I, Proj>>;

  // 常用算法要求
  // 概念 indirectly_movable
  template<class In, class Out>
    concept indirectly_movable = /* 见描述 */;

  template<class In, class Out>
    concept indirectly_movable_storable = /* 见描述 */;

  // 概念 indirectly_copyable
  template<class In, class Out>
    concept indirectly_copyable = /* 见描述 */;

  template<class In, class Out>
    concept indirectly_copyable_storable = /* 见描述 */;

  // 概念 indirectly_swappable
  template<class I1, class I2 = I1>
    concept indirectly_swappable = /* 见描述 */;

  // 概念 indirectly_comparable
  template<class I1, class I2, class R, class P1 = identity, class P2 = identity>
    concept indirectly_comparable = /* 见描述 */;

  // 概念 permutable
  template<class I>
    concept permutable = /* 见描述 */;

  // 概念 mergeable
  template<class I1, class I2, class Out,
      class R = ranges::less, class P1 = identity, class P2 = identity>
    concept mergeable = /* 见描述 */;

  // 概念 sortable
  template<class I, class R = ranges::less, class P = identity>
    concept sortable = /* 见描述 */;

  // 原语
  // 迭代器标签
  struct input_iterator_tag { };
  struct output_iterator_tag { };
  struct forward_iterator_tag: public input_iterator_tag { };
  struct bidirectional_iterator_tag: public forward_iterator_tag { };
  struct random_access_iterator_tag: public bidirectional_iterator_tag { };
  struct contiguous_iterator_tag: public random_access_iterator_tag { };

  // 迭代器操作
  template<class InputIter, class Distance>
    constexpr void
      advance(InputIter& i, Distance n);
  template<class InputIter>
    constexpr typename iterator_traits<InputIter>::difference_type
      distance(InputIter first, InputIter last);
  template<class InputIter>
    constexpr InputIter
      next(InputIter x, typename iterator_traits<InputIter>::difference_type n = 1);
  template<class BidirectionalIter>
    constexpr BidirectionalIter
      prev(BidirectionalIter x,
           typename iterator_traits<BidirectionalIter>::difference_type n = 1);

  // 范围迭代器操作
  namespace ranges {
    // ranges​::​advance
    template<input_or_output_iterator I>
      constexpr void advance(I& i, iter_difference_t<I> n);
    template<input_or_output_iterator I, sentinel_for<I> S>
      constexpr void advance(I& i, S bound);
    template<input_or_output_iterator I, sentinel_for<I> S>
      constexpr iter_difference_t<I> advance(I& i, iter_difference_t<I> n, S bound);

    // ranges​::​distance
    template<input_or_output_iterator I, sentinel_for<I> S>
      constexpr iter_difference_t<I> distance(I first, S last);
    template<range R>
      constexpr range_difference_t<R> distance(R&& r);

    // ranges​::​next
    template<input_or_output_iterator I>
      constexpr I next(I x);
    template<input_or_output_iterator I>
      constexpr I next(I x, iter_difference_t<I> n);
    template<input_or_output_iterator I, sentinel_for<I> S>
      constexpr I next(I x, S bound);
    template<input_or_output_iterator I, sentinel_for<I> S>
      constexpr I next(I x, iter_difference_t<I> n, S bound);

    // ranges​::​prev
    template<bidirectional_iterator I>
      constexpr I prev(I x);
    template<bidirectional_iterator I>
      constexpr I prev(I x, iter_difference_t<I> n);
    template<bidirectional_iterator I>
      constexpr I prev(I x, iter_difference_t<I> n, I bound);
  }

  // 预定义迭代器与哨位
  // 逆向迭代器
  template<class Iter> class reverse_iterator;

  template<class Iter1, class Iter2>
    constexpr bool operator==(
      const reverse_iterator<Iter1>& x,
      const reverse_iterator<Iter2>& y);
  template<class Iter1, class Iter2>
    constexpr bool operator!=(
      const reverse_iterator<Iter1>& x,
      const reverse_iterator<Iter2>& y);
  template<class Iter1, class Iter2>
    constexpr bool operator<(
      const reverse_iterator<Iter1>& x,
      const reverse_iterator<Iter2>& y);
  template<class Iter1, class Iter2>
    constexpr bool operator>(
      const reverse_iterator<Iter1>& x,
      const reverse_iterator<Iter2>& y);
  template<class Iter1, class Iter2>
    constexpr bool operator<=(
      const reverse_iterator<Iter1>& x,
      const reverse_iterator<Iter2>& y);
  template<class Iter1, class Iter2>
    constexpr bool operator>=(
      const reverse_iterator<Iter1>& x,
      const reverse_iterator<Iter2>& y);
  template<class Iter1, three_way_comparable_with<Iter1> Iter2>
    constexpr compare_three_way_result_t<Iter1, Iter2>
      operator<=>(const reverse_iterator<Iter1>& x, const reverse_iterator<Iter2>& y);

  template<class Iter1, class Iter2>
    constexpr auto operator-(
      const reverse_iterator<Iter1>& x,
      const reverse_iterator<Iter2>& y) -> decltype(y.base() - x.base());
  template<class Iter>
    constexpr reverse_iterator<Iter>
      operator+(
    typename reverse_iterator<Iter>::difference_type n,
    const reverse_iterator<Iter>& x);

  template<class Iter>
    constexpr reverse_iterator<Iter> make_reverse_iterator(Iter i);

  template<class Iter1, class Iter2>
      requires (!sized_sentinel_for<Iter1, Iter2>)
    inline constexpr bool disable_sized_sentinel<reverse_iterator<Iter1>,
                                                 reverse_iterator<Iter2>> = true;

  // 插入迭代器
  template<class Container> class back_insert_iterator;
  template<class Container>
    constexpr back_insert_iterator<Container> back_inserter(Container& x);

  template<class Container> class front_insert_iterator;
  template<class Container>
    constexpr front_insert_iterator<Container> front_inserter(Container& x);

  template<class Container> class insert_iterator;
  template<class Container>
    constexpr insert_iterator<Container>
      inserter(Container& x, ranges::iterator_t<Container> i);

  // 移动迭代器与哨位
  template<class Iter> class move_iterator;

  template<class Iter1, class Iter2>
    constexpr bool operator==(
      const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
  template<class Iter1, class Iter2>
    constexpr bool operator<(
      const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
  template<class Iter1, class Iter2>
    constexpr bool operator>(
      const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
  template<class Iter1, class Iter2>
    constexpr bool operator<=(
      const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
  template<class Iter1, class Iter2>
    constexpr bool operator>=(
      const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
  template<class Iter1, three_way_comparable_with<Iter1> Iter2>
    constexpr compare_three_way_result_t<Iter1, Iter2>
      operator<=>(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);

  template<class Iter1, class Iter2>
    constexpr auto operator-(
    const move_iterator<Iter1>& x,
    const move_iterator<Iter2>& y) -> decltype(x.base() - y.base());
  template<class Iter>
    constexpr move_iterator<Iter> operator+(
      typename move_iterator<Iter>::difference_type n, const move_iterator<Iter>& x);

  template<class Iter>
    constexpr move_iterator<Iter> make_move_iterator(Iter i);

  template<semiregular S> class move_sentinel;

  // 公共迭代器
  template<input_or_output_iterator I, sentinel_for<I> S>
    requires (!same_as<I, S>)
      class common_iterator;

  template<class I, class S>
    struct incrementable_traits<common_iterator<I, S>>;

  template<input_iterator I, class S>
    struct iterator_traits<common_iterator<I, S>>;

  // 默认哨位
  struct default_sentinel_t;
  inline constexpr default_sentinel_t default_sentinel{};

  // 计数迭代器
  template<input_or_output_iterator I> class counted_iterator;

  template<class I>
    struct incrementable_traits<counted_iterator<I>>;

  template<input_iterator I>
    struct iterator_traits<counted_iterator<I>>;

  // 不可达哨位
  struct unreachable_sentinel_t;
  inline constexpr unreachable_sentinel_t unreachable_sentinel{};

  // 流迭代器
  template<class T, class charT = char, class traits = char_traits<charT>,
           class Distance = ptrdiff_t>
  class istream_iterator;
  template<class T, class charT, class traits, class Distance>
    bool operator==(const istream_iterator<T,charT,traits,Distance>& x,
            const istream_iterator<T,charT,traits,Distance>& y);

  template<class T, class charT = char, class traits = char_traits<charT>>
      class ostream_iterator;

  template<class charT, class traits = char_traits<charT>>
    class istreambuf_iterator;
  template<class charT, class traits>
    bool operator==(const istreambuf_iterator<charT,traits>& a,
            const istreambuf_iterator<charT,traits>& b);

  template<class charT, class traits = char_traits<charT>>
    class ostreambuf_iterator;

  // 范围访问
  template<class C> constexpr auto begin(C& c) -> decltype(c.begin());
  template<class C> constexpr auto begin(const C& c) -> decltype(c.begin());
  template<class C> constexpr auto end(C& c) -> decltype(c.end());
  template<class C> constexpr auto end(const C& c) -> decltype(c.end());
  template<class T, size_t N> constexpr T* begin(T (&a)[N]) noexcept;
  template<class T, size_t N> constexpr T* end(T (&a)[N]) noexcept;
  template<class C> constexpr auto cbegin(const C& c) noexcept(noexcept(std::begin(c)))
    -> decltype(std::begin(c));
  template<class C> constexpr auto cend(const C& c) noexcept(noexcept(std::end(c)))
    -> decltype(std::end(c));
  template<class C> constexpr auto rbegin(C& c) -> decltype(c.rbegin());
  template<class C> constexpr auto rbegin(const C& c) -> decltype(c.rbegin());
  template<class C> constexpr auto rend(C& c) -> decltype(c.rend());
  template<class C> constexpr auto rend(const C& c) -> decltype(c.rend());
  template<class T, size_t N> constexpr reverse_iterator<T*> rbegin(T (&a)[N]);
  template<class T, size_t N> constexpr reverse_iterator<T*> rend(T (&a)[N]);
  template<class E> constexpr reverse_iterator<const E*> rbegin(initializer_list<E> il);
  template<class E> constexpr reverse_iterator<const E*> rend(initializer_list<E> il);
  template<class C> constexpr auto crbegin(const C& c) -> decltype(std::rbegin(c));
  template<class C> constexpr auto crend(const C& c) -> decltype(std::rend(c));

  template<class C> constexpr auto size(const C& c) -> decltype(c.size());
  template<class T, size_t N> constexpr size_t size(const T (&a)[N]) noexcept;
  template<class C> constexpr auto ssize(const C& c)
    -> common_type_t<ptrdiff_t, make_signed_t<decltype(c.size())>>;
  template<class T, ptrdiff_t N> constexpr ptrdiff_t ssize(const T (&a)[N]) noexcept;
  template<class C> [[nodiscard]] constexpr auto empty(const C& c) -> decltype(c.empty());
  template<class T, size_t N> [[nodiscard]] constexpr bool empty(const T (&a)[N]) noexcept;
  template<class E> [[nodiscard]] constexpr bool empty(initializer_list<E> il) noexcept;
  template<class C> constexpr auto data(C& c) -> decltype(c.data());
  template<class C> constexpr auto data(const C& c) -> decltype(c.data());
  template<class T, size_t N> constexpr T* data(T (&a)[N]) noexcept;
  template<class E> constexpr const E* data(initializer_list<E> il) noexcept;
}

概念 indirectly_readable

namespace std {
  template<class In>
    concept __IndirectlyReadableImpl = // 仅用于阐释
      requires(const In in) {
        typename iter_value_t<In>;
        typename iter_reference_t<In>;
        typename iter_rvalue_reference_t<In>;
        { *in } -> same_as<iter_reference_t<In>>
        { iter_move(in) } -> same_as<iter_rvalue_reference_t<In>>
      } &&
      common_reference_with<iter_reference_t<In>&&, iter_value_t<In>&> &&
      common_reference_with<iter_reference_t<In>&&, iter_rvalue_reference_t<In>&&> &&
      common_reference_with<iter_rvalue_reference_t<In>&&, const iter_value_t<In>&>;

  template<class In>
    concept indirectly_readable =
      __IndirectlyReadableImpl<remove_cvref_t<In>>
}

概念 indirectly_writable

namespace std {
  template<class Out, class T>
    concept indirectly_writable =
      requires(Out&& o, T&& t) {
        *o = std::forward<T>(t); // 不要求保持相等性
        *std::forward<Out>(o) = std::forward<T>(t);
        // 不要求保持相等性
        const_cast<const iter_reference_t<Out>&&>(*o) =
        std::forward<T>(t); // 不要求保持相等性
        const_cast<const iter_reference_t<Out>&&>(*std::forward<Out>(o)) =
        std::forward<T>(t); // 不要求保持相等性
      };
}

概念 weakly_incrementable

namespace std {
  template<class T>
    inline constexpr bool __is_integer_like = /* 见描述 */; // 仅用于阐释

  template<class T>
    inline constexpr bool __is_signed_integer_like =  // 仅用于阐释
      /* 见描述 */;

  template<class I>
    concept weakly_incrementable =
      default_initializable<I> && movable<I> &&
      requires(I i) {
        typename iter_difference_t<I>;
        requires __is_signed_integer_like<iter_difference_t<I>>;
        { ++i } -> same_as<I&>;   // 不要求保持相等性
        i++;                      // 不要求保持相等性
      };
}

概念 incrementable

namespace std {
  template<class I>
    concept incrementable =
      regular<I> &&
      weakly_incrementable<I> &&
      requires(I i) {
        { i++ } -> same_as<I>;
      };
}

概念 input_or_output_iterator

namespace std {
  template<class I>
    concept input_or_output_iterator =
      requires(I i) {
        { *i } -> can-reference;
      } &&
      weakly_incrementable<I>;
}

概念 sentinel_for

namespace std {
  template<class S, class I>
    concept sentinel_for =
      semiregular<S> &&
      input_or_output_iterator<I> &&
      __WeaklyEqualityComparableWith<S, I>;
}

概念 sized_sentinel_for

namespace std {
  template<class S, class I>
    concept sized_sentinel_for =
      sentinel_for<S, I> &&
      !disable_sized_sentinel<remove_cv_t<S>, remove_cv_t<I>> &&
      requires(const I& i, const S& s) {
        { s - i } -> same_as<iter_difference_t<I>>;
        { i - s } -> same_as<iter_difference_t<I>>;
      };
}

概念 input_iterator

namespace std {
  template<class I>
    concept input_iterator =
      input_or_output_iterator<I> &&
      indirectly_readable<I> &&
      requires { typename /*ITER_CONCEPT*/(I); } &&
      derived_from</*ITER_CONCEPT*/(I), input_iterator_tag>;
}

概念 output_iterator

namespace std {
  template<class I, class T>
    concept output_iterator =
      input_or_output_iterator<I> &&
      indirectly_writable<I, T> &&
      requires(I i, T&& t) {
        *i++ = std::forward<T>(t); // 不要求保持相等性
      };
}

概念 forward_iterator

namespace std {
  template<class I>
    concept forward_iterator =
      input_iterator<I> &&
      derived_from</*ITER_CONCEPT*/(I), forward_iterator_tag> &&
      incrementable<I> &&
      sentinel_for<I, I>;
}

概念 bidirectional_iterator

namespace std {
  template<class I>
    concept bidirectional_iterator =
      forward_iterator<I> &&
      derived_from</*ITER_CONCEPT*/(I), bidirectional_iterator_tag> &&
      requires(I i) {
        { --i } -> same_as<I&>;
        { i-- } -> same_as<I>;
      };
}

概念 random_access_iterator

namespace std {
  template<class I>
    concept random_access_iterator =
      bidirectional_iterator<I> &&
      derived_from</*ITER_CONCEPT*/(I), random_access_iterator_tag> &&
      totally_ordered<I> &&
      sized_sentinel_for<I, I> &&
      requires(I i, const I j, const iter_difference_t<I> n) {
        { i += n } -> same_as<I&>;
        { j +  n } -> same_as<I>;
        { n +  j } -> same_as<I>;
        { i -= n } -> same_as<I&>;
        { j -  n } -> same_as<I>;
        {  j[n]  } -> same_as<iter_reference_t<I>>;
      };
}

概念 contiguous_iterator

namespace std {
  template<class I>
    concept contiguous_iterator =
      random_access_iterator<I> &&
      derived_from</*ITER_CONCEPT*/(I), contiguous_iterator_tag> &&
      is_lvalue_reference_v<iter_reference_t<I>> &&
      same_as<iter_value_t<I>, remove_cvref_t<iter_reference_t<I>>> &&
      requires(const I& i) {
        { to_address(i) } -> same_as<add_pointer_t<iter_reference_t<I>>>;
      };
}

概念 indirectly_unary_invocable

namespace std {
  template<class F, class I>
    concept indirectly_unary_invocable =
      indirectly_readable<I> &&
      copy_constructible<F> &&
      invocable<F&, iter_value_t<I>&> &&
      invocable<F&, iter_reference_t<I>> &&
      invocable<F&, iter_common_reference_t<I>> &&
      common_reference_with<
        invoke_result_t<F&, iter_value_t<I>&>,
        invoke_result_t<F&, iter_reference_t<I>>>;
}

概念 indirectly_regular_unary_invocable

namespace std {
  template<class F, class I>
    concept indirectly_regular_unary_invocable =
      indirectly_readable<I> &&
      copy_constructible<F> &&
      regular_invocable<F&, iter_value_t<I>&> &&
      regular_invocable<F&, iter_reference_t<I>> &&
      regular_invocable<F&, iter_common_reference_t<I>> &&
      common_reference_with<
        invoke_result_t<F&, iter_value_t<I>&>,
        invoke_result_t<F&, iter_reference_t<I>>>;
}

概念 indirect_unary_predicate

namespace std {
  template<class F, class I>
    concept indirect_unary_predicate =
      indirectly_readable<I> &&
      copy_constructible<F> &&
      predicate<F&, iter_value_t<I>&> &&
      predicate<F&, iter_reference_t<I>> &&
      predicate<F&, iter_common_reference_t<I>>;
}

概念 indirect_binary_predicate

namespace std {
  template<class F, class I1, class I2 = I1>
    concept indirect_binary_predicate =
      indirectly_readable<I1> && indirectly_readable<I2> &&
      copy_constructible<F> &&
      predicate<F&, iter_value_t<I1>&, iter_value_t<I2>&> &&
      predicate<F&, iter_value_t<I1>&, iter_reference_t<I2>> &&
      predicate<F&, iter_reference_t<I1>, iter_value_t<I2>&> &&
      predicate<F&, iter_reference_t<I1>, iter_reference_t<I2>> &&
      predicate<F&, iter_common_reference_t<I1>, iter_common_reference_t<I2>>;
}

概念 indirect_equivalence_relation

namespace std {
  template<class F, class I1, class I2 = I1>
    concept indirect_equivalence_relation =
      indirectly_readable<I1> && indirectly_readable<I2> &&
      copy_constructible<F> &&
      equivalence_relation<F&, iter_value_t<I1>&, iter_value_t<I2>&> &&
      equivalence_relation<F&, iter_value_t<I1>&, iter_reference_t<I2>> &&
      equivalence_relation<F&, iter_reference_t<I1>, iter_value_t<I2>&> &&
      equivalence_relation<F&, iter_reference_t<I1>, iter_reference_t<I2>> &&
      equivalence_relation<F&, iter_common_reference_t<I1>, iter_common_reference_t<I2>>;
}

概念 indirect_strict_weak_order

namespace std {
  template<class F, class I1, class I2 = I1>
    concept indirect_strict_weak_order =
      indirectly_readable<I1> && indirectly_readable<I2> &&
      copy_constructible<F> &&
      strict_weak_order<F&, iter_value_t<I1>&, iter_value_t<I2>&> &&
      strict_weak_order<F&, iter_value_t<I1>&, iter_reference_t<I2>> &&
      strict_weak_order<F&, iter_reference_t<I1>, iter_value_t<I2>&> &&
      strict_weak_order<F&, iter_reference_t<I1>, iter_reference_t<I2>> &&
      strict_weak_order<F&, iter_common_reference_t<I1>, iter_common_reference_t<I2>>;
}

概念 indirectly_movable

namespace std {
  template<class In, class Out>
    concept indirectly_movable =
      indirectly_readable<In> &&
      indirectly_writable<Out, iter_rvalue_reference_t<In>>;
}

概念 indirectly_movable_storable

namespace std {
  template<class In, class Out>
    concept indirectly_movable_storable =
      indirectly_movable<In, Out> &&
      indirectly_writable<Out, iter_value_t<In>> &&
      movable<iter_value_t<In>> &&
      constructible_from<iter_value_t<In>, iter_rvalue_reference_t<In>> &&
      assignable_from<iter_value_t<In>&, iter_rvalue_reference_t<In>>;
}

概念 indirectly_copyable

namespace std {
  template<class In, class Out>
    concept indirectly_copyable =
      indirectly_readable<In> &&
      indirectly_writable<Out, iter_reference_t<In>>;
}

概念 indirectly_copyable_storable

namespace std {
  template<class In, class Out>
    concept indirectly_copyable_storable =
      indirectly_copyable<In, Out> &&
      indirectly_writable<Out, iter_value_t<In>&> &&
      indirectly_writable<Out, const iter_value_t<In>&> &&
      indirectly_writable<Out, iter_value_t<In>&&> &&
      indirectly_writable<Out, const iter_value_t<In>&&> &&
      copyable<iter_value_t<In>> &&
      constructible_from<iter_value_t<In>, iter_reference_t<In>> &&
      assignable_from<iter_value_t<In>&, iter_reference_t<In>>;
}

概念 indirectly_swappable

namespace std {
  template<class I1, class I2 = I1>
    concept indirectly_swappable =
      indirectly_readable<I1> && indirectly_readable<I2> &&
      requires(const I1 i1, const I2 i2) {
        ranges::iter_swap(i1, i1);
        ranges::iter_swap(i2, i2);
        ranges::iter_swap(i1, i2);
        ranges::iter_swap(i2, i1);
      };
}

概念 indirectly_comparable

namespace std {
  template<class I1, class I2, class R, class P1 = identity, class P2 = identity>
    concept indirectly_comparable =
      indirect_relation<R, projected<I1, P1>, projected<I2, P2>>;
}

概念 permutable

namespace std {
  template<class I>
    concept permutable =
      forward_iterator<I> &&
      indirectly_movable_storable<I, I> &&
      indirectly_swappable<I, I>;
}

概念 mergeable

namespace std {
  template<class I1, class I2, class Out, class R = ranges::less,
           class P1 = identity, class P2 = identity>
    concept mergeable =
      input_iterator<I1> &&
      input_iterator<I2> &&
      weakly_incrementable<Out> &&
      indirectly_copyable<I1, Out> &&
      indirectly_copyable<I2, Out> &&
      indirect_strict_weak_order<R, projected<I1, P1>, projected<I2, P2>>;
}

概念 sortable

namespace std {
  template<class I, class R = ranges::less, class P = identity>
    concept sortable =
      permutable<I> &&
      indirect_strict_weak_order<R, projected<I, P>>;
}

类模板 std::incrementable_traits

namespace std {
  template<class> struct incrementable_traits { };

  template<class T>
    requires is_object_v<T>
  struct incrementable_traits<T*> {
    using difference_type = ptrdiff_t;
  };

  template<class I>
  struct incrementable_traits<const I>
    : incrementable_traits<I> { };

  template<class T>
    requires requires { typename T::difference_type; }
  struct incrementable_traits<T> {
    using difference_type = typename T::difference_type;
  };

  template<class T>
    requires (!requires { typename T::difference_type; } &&
              requires(const T& a, const T& b) { { a - b } -> integral; })
  struct incrementable_traits<T> {
    using difference_type = make_signed_t<decltype(declval<T>() - declval<T>())>;
  };

  template<class T>
    using iter_difference_t = /* 见描述 */;
}

类模板 std::indirectly_readable_traits

namespace std {
  template<class> struct __cond_value_type { };   // 仅用于阐释
  template<class T>
    requires is_object_v<T>
  struct __cond_value_type {
    using value_type = remove_cv_t<T>;
  };

  template<class> struct indirectly_readable_traits { };

  template<class T>
  struct indirectly_readable_traits<T*>
    : __cond_value_type<T> { };

  template<class I>
    requires is_array_v<I>
  struct indirectly_readable_traits<I> {
    using value_type = remove_cv_t<remove_extent_t<I>>;
  };

  template<class I>
  struct indirectly_readable_traits<const I>
    : indirectly_readable_traits<I> { };

  template<class T>
    requires requires { typename T::value_type; }
  struct indirectly_readable_traits<T>
    : __cond_value_type<typename T::value_type> { };

  template<class T>
    requires requires { typename T::element_type; }
  struct indirectly_readable_traits<T>
    : __cond_value_type<typename T::element_type> { };
}

类模板 std::projected

namespace std {
  template<indirectly_readable I, indirectly_regular_unary_invocable<I> Proj>
  struct projected {
    using value_type = remove_cvref_t<indirect_result_t<Proj&, I>>;
    indirect_result_t<Proj&, I> operator*() const; // 不定义
  };

  template<weakly_incrementable I, class Proj>
  struct incrementable_traits<projected<I, Proj>> {
    using difference_type = iter_difference_t<I>;
  };
}

类模板 std::iterator_traits

namespace std {
  template<class I>
  struct iterator_traits {
    using iterator_category = /* 见描述 */;
    using value_type        = /* 见描述 */;
    using difference_type   = /* 见描述 */;
    using pointer           = /* 见描述 */;
    using reference         = /* 见描述 */;
  };

  template<class T>
    requires is_object_v<T>
  struct iterator_traits<T*> {
    using iterator_concept  = contiguous_iterator_tag;
    using iterator_category = random_access_iterator_tag;
    using value_type        = remove_cv_t<T>;
    using difference_type   = ptrdiff_t;
    using pointer           = T*;
    using reference         = T&;
  };
}

迭代器标签

namespace std {
  struct input_iterator_tag { };
  struct output_iterator_tag { };
  struct forward_iterator_tag: public input_iterator_tag { };
  struct bidirectional_iterator_tag: public forward_iterator_tag { };
  struct random_access_iterator_tag: public bidirectional_iterator_tag { };
  struct contiguous_iterator_tag: public random_access_iterator_tag { };
}

类模板 std::reverse_iterator

namespace std {
  template<class Iter>
  class reverse_iterator {
  public:
    using iterator_type     = Iter;
    using iterator_concept  = /* 见描述 */;
    using iterator_category = /* 见描述 */;
    using value_type        = iter_value_t<Iter>;
    using difference_type   = iter_difference_t<Iter>;
    using pointer           = typename iterator_traits<Iter>::pointer;
    using reference         = iter_reference_t<Iter>;

    constexpr reverse_iterator();
    constexpr explicit reverse_iterator(Iter x);
    template<class U> constexpr reverse_iterator(const reverse_iterator<U>& u);
    template<class U> constexpr reverse_iterator& operator=(const reverse_iterator<U>& u);

    constexpr Iter base() const;
    constexpr reference operator*() const;
    constexpr pointer   operator->() const requires /* 见描述 */;

    constexpr reverse_iterator& operator++();
    constexpr reverse_iterator  operator++(int);
    constexpr reverse_iterator& operator--();
    constexpr reverse_iterator  operator--(int);

    constexpr reverse_iterator  operator+ (difference_type n) const;
    constexpr reverse_iterator& operator+=(difference_type n);
    constexpr reverse_iterator  operator- (difference_type n) const;
    constexpr reverse_iterator& operator-=(difference_type n);
    constexpr /* 未指明 */ operator[](difference_type n) const;

    friend constexpr iter_rvalue_reference_t<Iter>
      iter_move(const reverse_iterator& i) noexcept(/* 见描述 */);
    template<indirectly_swappable<Iter> Iter2>
      friend constexpr void
        iter_swap(const reverse_iterator& x,
                  const reverse_iterator<Iter2>& y) noexcept(/* 见描述 */);

  protected:
    Iter current;
  };
}

类模板 std::back_insert_iterator

namespace std {
  template<class Container>
  class back_insert_iterator {
  protected:
    Container* container = nullptr;

  public:
    using iterator_category = output_iterator_tag;
    using value_type        = void;
    using difference_type   = ptrdiff_t;
    using pointer           = void;
    using reference         = void;
    using container_type    = Container;

    constexpr back_insert_iterator() noexcept = default;
    constexpr explicit back_insert_iterator(Container& x);
    constexpr back_insert_iterator& operator=(const typename Container::value_type& value);
    constexpr back_insert_iterator& operator=(typename Container::value_type&& value);

    constexpr back_insert_iterator& operator*();
    constexpr back_insert_iterator& operator++();
    constexpr back_insert_iterator  operator++(int);
  };
}

类模板 std::front_insert_iterator

namespace std {
  template<class Container>
  class front_insert_iterator {
  protected:
    Container* container = nullptr;

  public:
    using iterator_category = output_iterator_tag;
    using value_type        = void;
    using difference_type   = ptrdiff_t;
    using pointer           = void;
    using reference         = void;
    using container_type    = Container;

    constexpr front_insert_iterator(Container& x) noexcept = default;
    constexpr explicit front_insert_iterator(Container& x);
    constexpr front_insert_iterator&
      operator=(const typename Container::value_type& value);
    constexpr front_insert_iterator& operator=(typename Container::value_type&& value);

    constexpr front_insert_iterator& operator*();
    constexpr front_insert_iterator& operator++();
    constexpr front_insert_iterator  operator++(int);
  };
}

类模板 std::insert_iterator

namespace std {
  template<class Container>
  class insert_iterator {
  protected:
    Container* container = nullptr;
    ranges::iterator_t<Container> iter = ranges::iterator_t<Container>();

  public:
    using iterator_category = output_iterator_tag;
    using value_type        = void;
    using difference_type   = ptrdiff_t;
    using pointer           = void;
    using reference         = void;
    using container_type    = Container;

    insert_iterator() = default;
    constexpr insert_iterator(Container& x, ranges::iterator_t<Container> i);
    constexpr insert_iterator& operator=(const typename Container::value_type& value);
    constexpr insert_iterator& operator=(typename Container::value_type&& value);

    constexpr insert_iterator& operator*();
    constexpr insert_iterator& operator++();
    constexpr insert_iterator& operator++(int);
  };
}

类模板 std::move_iterator

namespace std {
  template<class Iter>
  class move_iterator {
  public:
    using iterator_type     = Iter;
    using iterator_concept  = input_iterator_tag;
    using iterator_category = /* 见描述 */;
    using value_type        = iter_value_t<Iter>;
    using difference_type   = iter_difference_t<Iter>;
    using pointer           = Iter;
    using reference         = iter_rvalue_reference_t<Iter>;

    constexpr move_iterator();
    constexpr explicit move_iterator(Iter i);
    template<class U> constexpr move_iterator(const move_iterator<U>& u);
    template<class U> constexpr move_iterator& operator=(const move_iterator<U>& u);

    constexpr iterator_type base() const &;
    constexpr iterator_type base() &&;
    constexpr reference operator*() const;
    constexpr pointer operator->() const;

    constexpr move_iterator& operator++();
    constexpr auto operator++(int);
    constexpr move_iterator& operator--();
    constexpr move_iterator operator--(int);

    constexpr move_iterator operator+(difference_type n) const;
    constexpr move_iterator& operator+=(difference_type n);
    constexpr move_iterator operator-(difference_type n) const;
    constexpr move_iterator& operator-=(difference_type n);
    constexpr reference operator[](difference_type n) const;

    template<sentinel_for<Iter> S>
      friend constexpr bool
        operator==(const move_iterator& x, const move_sentinel<S>& y);
    template<sized_sentinel_for<Iter> S>
      friend constexpr iter_difference_t<Iter>
        operator-(const move_sentinel<S>& x, const move_iterator& y);
    template<sized_sentinel_for<Iter> S>
      friend constexpr iter_difference_t<Iter>
        operator-(const move_iterator& x, const move_sentinel<S>& y);
    friend constexpr iter_rvalue_reference_t<Iter>
      iter_move(const move_iterator& i)
        noexcept(noexcept(ranges::iter_move(i.current)));
    template<indirectly_swappable<Iter> Iter2>
      friend constexpr void
        iter_swap(const move_iterator& x, const move_iterator<Iter2>& y)
          noexcept(noexcept(ranges::iter_swap(x.current, y.current)));

  private:
    Iter current;     // 仅用于阐释
  };
}

类模板 std::move_sentinel

namespace std {
  template<semiregular S>
  class move_sentinel {
  public:
    constexpr move_sentinel();
    constexpr explicit move_sentinel(S s);
    template<class S2>
      requires convertible_to<const S2&, S>
        constexpr move_sentinel(const move_sentinel<S2>& s);
    template<class S2>
      requires assignable_from<S&, const S2&>
        constexpr move_sentinel& operator=(const move_sentinel<S2>& s);

    constexpr S base() const;
  private:
    S last;     // 仅用于阐释
  };
}

类模板 std::common_iterator

namespace std {
  template<input_or_output_iterator I, sentinel_for<I> S>
    requires (!same_as<I, S>)
  class common_iterator {
  public:
    constexpr common_iterator() = default;
    constexpr common_iterator(I i);
    constexpr common_iterator(S s);
    template<class I2, class S2>
      requires convertible_to<const I2&, I> && convertible_to<const S2&, S>
        constexpr common_iterator(const common_iterator<I2, S2>& x);

    template<class I2, class S2>
      requires convertible_to<const I2&, I> && convertible_to<const S2&, S> &&
               assignable_from<I&, const I2&> && assignable_from<S&, const S2&>
        common_iterator& operator=(const common_iterator<I2, S2>& x);

    decltype(auto) operator*();
    decltype(auto) operator*() const
      requires dereferenceable<const I>;
    decltype(auto) operator->() const
      requires /* 见描述 */;

    common_iterator& operator++();
    decltype(auto) operator++(int);

    template<class I2, sentinel_for<I> S2>
      requires sentinel_for<S, I2>
    friend bool operator==(
      const common_iterator& x, const common_iterator<I2, S2>& y);
    template<class I2, sentinel_for<I> S2>
      requires sentinel_for<S, I2> && equality_comparable_with<I, I2>
    friend bool operator==(
      const common_iterator& x, const common_iterator<I2, S2>& y);

    template<sized_sentinel_for<I> I2, sized_sentinel_for<I> S2>
      requires sized_sentinel_for<S, I2>
    friend iter_difference_t<I2> operator-(
      const common_iterator& x, const common_iterator<I2, S2>& y);

    friend iter_rvalue_reference_t<I> iter_move(const common_iterator& i)
      noexcept(noexcept(ranges::iter_move(declval<const I&>())))
        requires input_iterator<I>;
    template<indirectly_swappable<I> I2, class S2>
      friend void iter_swap(const common_iterator& x, const common_iterator<I2, S2>& y)
        noexcept(noexcept(ranges::iter_swap(declval<const I&>(), declval<const I2&>())));

  private:
    variant<I, S> v_;   // 仅用于阐释
  };

  template<class I, class S>
  struct incrementable_traits<common_iterator<I, S>> {
    using difference_type = iter_difference_t<I>;
  };

  template<input_iterator I, class S>
  struct iterator_traits<common_iterator<I, S>> {
    using iterator_concept = /* 见描述 */;
    using iterator_category = /* 见描述 */;
    using value_type = iter_value_t<I>;
    using difference_type = iter_difference_t<I>;
    using pointer = /* 见描述 */;
    using reference = iter_reference_t<I>;
  };
}

类 std::default_sentinel_t

namespace std {
  struct default_sentinel_t { };
}

类模板 std::counted_iterator

namespace std {
  template<input_or_output_iterator I>
  class counted_iterator {
  public:
    using iterator_type = I;

    constexpr counted_iterator() = default;
    constexpr counted_iterator(I x, iter_difference_t<I> n);
    template<class I2>
      requires convertible_to<const I2&, I>
        constexpr counted_iterator(const counted_iterator<I2>& x);

    template<class I2>
      requires assignable_from<I&, const I2&>
        constexpr counted_iterator& operator=(const counted_iterator<I2>& x);

    constexpr I base() const & requires copy_constructible<I>;
    constexpr I base() &&;
    constexpr iter_difference_t<I> count() const noexcept;
    constexpr decltype(auto) operator*();
    constexpr decltype(auto) operator*() const
      requires dereferenceable<const I>;

    constexpr counted_iterator& operator++();
    decltype(auto) operator++(int);
    constexpr counted_iterator operator++(int)
      requires forward_iterator<I>;
    constexpr counted_iterator& operator--()
      requires bidirectional_iterator<I>;
    constexpr counted_iterator operator--(int)
      requires bidirectional_iterator<I>;

    constexpr counted_iterator operator+(iter_difference_t<I> n) const
      requires random_access_iterator<I>;
    friend constexpr counted_iterator operator+(
      iter_difference_t<I> n, const counted_iterator& x)
        requires random_access_iterator<I>;
    constexpr counted_iterator& operator+=(iter_difference_t<I> n)
      requires random_access_iterator<I>;

    constexpr counted_iterator operator-(iter_difference_t<I> n) const
      requires random_access_iterator<I>;
    template<common_with<I> I2>
      friend constexpr iter_difference_t<I2> operator-(
        const counted_iterator& x, const counted_iterator<I2>& y);
    friend constexpr iter_difference_t<I> operator-(
      const counted_iterator& x, default_sentinel_t);
    friend constexpr iter_difference_t<I> operator-(
      default_sentinel_t, const counted_iterator& y);
    constexpr counted_iterator& operator-=(iter_difference_t<I> n)
      requires random_access_iterator<I>;

    constexpr decltype(auto) operator[](iter_difference_t<I> n) const
      requires random_access_iterator<I>;

    template<common_with<I> I2>
      friend constexpr bool operator==(
        const counted_iterator& x, const counted_iterator<I2>& y);
    friend constexpr bool operator==(
      const counted_iterator& x, default_sentinel_t);

    template<common_with<I> I2>
      friend constexpr strong_ordering operator<=>(
        const counted_iterator& x, const counted_iterator<I2>& y);

    friend constexpr iter_rvalue_reference_t<I> iter_move(const counted_iterator& i)
      noexcept(noexcept(ranges::iter_move(i.current)))
        requires input_iterator<I>;
    template<indirectly_swappable<I> I2>
      friend constexpr void iter_swap(const counted_iterator& x,
                                      const counted_iterator<I2>& y)
        noexcept(noexcept(ranges::iter_swap(x.current, y.current)));

  private:
    I current = I();                    // 仅用于阐释
    iter_difference_t<I> length = 0;    // 仅用于阐释
  };

  template<class I>
  struct incrementable_traits<counted_iterator<I>> {
    using difference_type = iter_difference_t<I>;
  };

  template<input_iterator I>
  struct iterator_traits<counted_iterator<I>> : iterator_traits<I> {
    using pointer = void;
  };
}

类 std::unreachable_sentinel_t

namespace std {
  struct unreachable_sentinel_t {
    template<weakly_incrementable I>
      friend constexpr bool operator==(unreachable_sentinel_t, const I&) noexcept
      { return false; }
  };
}

类模板 std::istream_iterator

namespace std {
  template<class T, class CharT = char, class Traits = char_traits<CharT>,
           class Distance = ptrdiff_t>
  class istream_iterator {
  public:
    using iterator_category = input_iterator_tag;
    using value_type        = T;
    using difference_type   = Distance;
    using pointer           = const T*;
    using reference         = const T&;
    using char_type         = CharT;
    using traits_type       = Traits;
    using istream_type      = basic_istream<CharT, Traits>;

    constexpr istream_iterator();
    constexpr istream_iterator(default_sentinel_t);
    istream_iterator(istream_type& s);
    istream_iterator(const istream_iterator& x) = default;
    ~istream_iterator() = default;
    istream_iterator& operator=(const istream_iterator&) = default;

    const T& operator*() const;
    const T* operator->() const;
    istream_iterator& operator++();
    istream_iterator  operator++(int);

    friend bool operator==(const istream_iterator& i, default_sentinel_t);

  private:
    basic_istream<CharT, Traits>* in_stream; // 仅用于阐释
    T value;                                 // 仅用于阐释
  };
}

类模板 std::ostream_iterator

namespace std {
  template<class T, class CharT = char, classTraits = char_traits<CharT>>
  class ostream_iterator {
  public:
    using iterator_category = output_iterator_tag;
    using value_type        = void;
    using difference_type   = ptrdiff_t;
    using pointer           = void;
    using reference         = void;
    using char_type         = CharT;
    using traits_type       = Traits;
    using ostream_type      = basic_ostream<CharT, Traits>;

    constexpr ostreambuf_iterator() noexcept = default;
    ostream_iterator(ostream_type& s);
    ostream_iterator(ostream_type& s, const CharT* delimiter);
    ostream_iterator(const ostream_iterator& x);
    ~ostream_iterator();
    ostream_iterator& operator=(const ostream_iterator&) = default;
    ostream_iterator& operator=(const T& value);

    ostream_iterator& operator*();
    ostream_iterator& operator++();
    ostream_iterator& operator++(int);

  private:
    basic_ostream<CharT, Traits>* out_stream = nullptr;          // 仅用于阐释
    const CharT* delim = nullptr;                                // 仅用于阐释
  };
}

类模板 std::istreambuf_iterator

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class istreambuf_iterator {
  public:
    using iterator_category = input_iterator_tag;
    using value_type        = CharT;
    using difference_type   = typename Traits::off_type;
    using pointer           = /* 未指明 */;
    using reference         = CharT;
    using char_type         = CharT;
    using traits_type       = Traits;
    using int_type          = typename Traits::int_type;
    using streambuf_type    = basic_streambuf<CharT, Traits>;
    using istream_type      = basic_istream<CharT, Traits>;

    class proxy;                          // 仅用于阐释

    constexpr istreambuf_iterator() noexcept;
    constexpr istreambuf_iterator(default_sentinel_t) noexcept;
    istreambuf_iterator(const istreambuf_iterator&) noexcept = default;
    ~istreambuf_iterator() = default;
    istreambuf_iterator(istream_type& s) noexcept;
    istreambuf_iterator(streambuf_type* s) noexcept;
    istreambuf_iterator(const proxy& p) noexcept;
    istreambuf_iterator& operator=(const istreambuf_iterator&) noexcept = default;
    CharT operator*() const;
    istreambuf_iterator& operator++();
    proxy operator++(int);
    bool equal(const istreambuf_iterator& b) const;

    friend bool operator==(const istreambuf_iterator& i, default_sentinel_t s);

  private:
    streambuf_type* sbuf_;                // 仅用于阐释
  };

  template<class CharT, class Traits>
  class istreambuf_iterator<CharT, Traits>::proxy { // 仅用于阐释
    CharT keep_;
    basic_streambuf<CharT, Traits>* sbuf_;
    proxy(CharT c, basic_streambuf<CharT, Traits>* sbuf)
      : keep_(c), sbuf_(sbuf) { }
  public:
    CharT operator*() { return keep_; }
  };
}

类模板 std::ostreambuf_iterator

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class ostreambuf_iterator {
  public:
    using iterator_category = output_iterator_tag;
    using value_type        = void;
    using difference_type   = ptrdiff_t;
    using pointer           = void;
    using reference         = void;
    using char_type         = CharT;
    using traits_type       = Traits;
    using streambuf_type    = basic_streambuf<CharT, Traits>;
    using ostream_type      = basic_ostream<CharT, Traits>;

    constexpr ostreambuf_iterator() noexcept = default;
    ostreambuf_iterator(ostream_type& s) noexcept;
    ostreambuf_iterator(streambuf_type* s) noexcept;
    ostreambuf_iterator& operator=(CharT c);

    ostreambuf_iterator& operator*();
    ostreambuf_iterator& operator++();
    ostreambuf_iterator& operator++(int);
    bool failed() const noexcept;

  private:
    streambuf_type* sbuf_ = nullptr;    // 仅用于阐释
  };
}

类模板 std::iterator

namespace std {
  template<class Category, class T, class Distance = ptrdiff_t,
           class Pointer = T*, class Reference = T&>
  struct iterator {
    typedef Category  iterator_category;
    typedef T         value_type;
    typedef Distance  difference_type;
    typedef Pointer   pointer;
    typedef Reference reference;
  };
}


标准库头文件 <latch>

< cpp‎ | header

此头文件是线程支持库的一部分。

类
latch
(C++20)
 单次使用的线程屏障
(类)

概要

namespace std {
  class latch;
}

类 std::latch

namespace std {
  class latch {
  public:
    static constexpr ptrdiff_t max() noexcept;

    constexpr explicit latch(ptrdiff_t expected);
    ~latch();

    latch(const latch&) = delete;
    latch& operator=(const latch&) = delete;

    void count_down(ptrdiff_t update = 1);
    bool try_wait() const noexcept;
    void wait() const;
    void arrive_and_wait(ptrdiff_t update = 1);

  private:
    ptrdiff_t counter;  // 仅用于阐释
  };
}


标准库头文件 <limits>

< cpp‎ | header

此头文件是类型支持库的一部分。

声明

numeric_limits | 提供查询所有基础数值类型的性质的接口。 (类模板)
float_round_style | 指示浮点舍入模式 (枚举)
float_denorm_style | 指示浮点非规格化模式 (枚举)

概要

namespace std {
    template<class T> class numeric_limits;

    enum float_round_style {
        round_indeterminate         = -1,
        round_toward_zero           =  0,
        round_to_nearest            =  1,
        round_toward_infinity       =  2,
        round_toward_neg_infinity   =  3,
    };

    enum float_denorm_style {
        denorm_indeterminate = -1,
        denorm_absent        =  0,
        denorm_present       =  1
    };

    template<> class numeric_limits<bool>;

    template<> class numeric_limits<char>;
    template<> class numeric_limits<signed char>;
    template<> class numeric_limits<unsigned char>;
    template<> class numeric_limits<char8_t>;
    template<> class numeric_limits<char16_t>;
    template<> class numeric_limits<char32_t>;
    template<> class numeric_limits<wchar_t>;

    template<> class numeric_limits<short>;
    template<> class numeric_limits<int>;
    template<> class numeric_limits<long>;
    template<> class numeric_limits<long long>;
    template<> class numeric_limits<unsigned short>;
    template<> class numeric_limits<unsigned int>;
    template<> class numeric_limits<unsigned long>;
    template<> class numeric_limits<unsigned long long>;

    template<> class numeric_limits<float>;
    template<> class numeric_limits<double>;
    template<> class numeric_limits<long double>;
}

类模板 std::numeric_limits

template<class T> class numeric_limits {
public:
    static constexpr bool is_specialized = false;

    static constexpr T min() noexcept { return T(); }
    static constexpr T max() noexcept { return T(); }
    static constexpr T lowest() noexcept { return T(); }

    static constexpr int digits = 0;
    static constexpr int digits10 = 0;
    static constexpr int max_digits10 = 0;

    static constexpr bool is_signed = false;
    static constexpr bool is_integer = false;
    static constexpr bool is_exact = false;
    static constexpr int radix = 0;
    static constexpr T epsilon() noexcept { return T(); }
    static constexpr T round_error() noexcept { return T(); }

    static constexpr int min_exponent = 0;
    static constexpr int min_exponent10 = 0;
    static constexpr int max_exponent = 0;
    static constexpr int max_exponent10 = 0;

    static constexpr bool has_infinity = false;
    static constexpr bool has_quiet_NaN = false;
    static constexpr bool has_signaling_NaN = false;
    static constexpr float_denorm_style has_denorm = denorm_absent;
    static constexpr bool has_denorm_loss = false;
    static constexpr T infinity() noexcept { return T(); }
    static constexpr T quiet_NaN() noexcept { return T(); }
    static constexpr T signaling_NaN() noexcept { return T(); }
    static constexpr T denorm_min() noexcept { return T(); }

    static constexpr bool is_iec559 = false;
    static constexpr bool is_bounded = false;
    static constexpr bool is_modulo = false;

    static constexpr bool traps = false;
    static constexpr bool tinyness_before = false;
    static constexpr float_round_style round_style = round_toward_zero;

};

std::numeric_limits <bool> 特化

template<> class numeric_limits<bool> {
public:
    static constexpr bool is_specialized = true;

    static constexpr bool min() noexcept { return false; }
    static constexpr bool max() noexcept { return true; }
    static constexpr bool lowest() noexcept { return false; }

    static constexpr int digits = 1;
    static constexpr int digits10 = 0;
    static constexpr int max_digits10 = 0;

    static constexpr bool is_signed = false;
    static constexpr bool is_integer = true;
    static constexpr bool is_exact = true;
    static constexpr int radix = 2;
    static constexpr bool epsilon() noexcept { return 0; }
    static constexpr bool round_error() noexcept { return 0; }

    static constexpr int min_exponent = 0;
    static constexpr int min_exponent10 = 0;
    static constexpr int max_exponent = 0;
    static constexpr int max_exponent10 = 0;

    static constexpr bool has_infinity = false;
    static constexpr bool has_quiet_NaN = false;
    static constexpr bool has_signaling_NaN = false;
    static constexpr float_denorm_style has_denorm = denorm_absent;
    static constexpr bool has_denorm_loss = false;
    static constexpr bool infinity() noexcept { return 0; }
    static constexpr bool quiet_NaN() noexcept { return 0; }
    static constexpr bool signaling_NaN() noexcept { return 0; }
    static constexpr bool denorm_min() noexcept { return 0; }

    static constexpr bool is_iec559 = false;
    static constexpr bool is_bounded = true;
    static constexpr bool is_modulo = false;

    static constexpr bool traps = false;
    static constexpr bool tinyness_before = false;
    static constexpr float_round_style round_style = round_toward_zero;

};


标准库头文件 <list>

< cpp‎ | header

此头文件是容器库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
<initializer_list>
(C++11)
 std::initializer_list 类模板

类
list
 双链表
(类模板)

函数
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 list 中的值
(函数模板)
std::swap(std::list)
 特化 std::swap 算法
(函数模板)
erase(std::list)erase_if(std::list)
(C++20)
 擦除所有满足特定判别标准的元素
(函数模板)
范围访问
begincbegin
(C++11)(C++14)
 返回指向容器或数组起始的迭代器
(函数模板)
endcend
(C++11)(C++14)
 返回指向容器或数组结尾的迭代器
(函数模板)
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
sizessize
(C++17)(C++20)
 返回容器或数组的大小
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)

概要

#include <compare>
#include <initializer_list>

namespace std {
  // 类模板 list
  template<class T, class Allocator = allocator<T>> class list;

  template<class T, class Allocator>
    bool operator==(const list<T, Allocator>& x, const list<T, Allocator>& y);
  template<class T, class Allocator>
    /*synth-three-way-result*/<T> operator<=>(const list<T, Allocator>& x,
                                              const list<T, Allocator>& y);

  template<class T, class Allocator>
    void swap(list<T, Allocator>& x, list<T, Allocator>& y)
      noexcept(noexcept(x.swap(y)));

  template<class T, class Allocator, class U>
    typename list<T, Allocator>::size_type
      erase(list<T, Allocator>& c, const U& value);
  template<class T, class Allocator, class Predicate>
    typename list<T, Allocator>::size_type
      erase_if(list<T, Allocator>& c, Predicate pred);

  namespace pmr {
    template<class T>
      using list = std::list<T, polymorphic_allocator<T>>;
  }
}

类模板 std::list

namespace std {
  template<class T, class Allocator = allocator<T>>
  class list {
  public:
    // 类型
    using value_type             = T;
    using allocator_type         = Allocator;
    using pointer                = typename allocator_traits<Allocator>::pointer;
    using const_pointer          = typename allocator_traits<Allocator>::const_pointer;
    using reference              = value_type&;
    using const_reference        = const value_type&;
    using size_type              = /* 由实现定义 */;
    using difference_type        = /* 由实现定义 */;
    using iterator               = /* 由实现定义 */;
    using const_iterator         = /* 由实现定义 */;
    using reverse_iterator       = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

    // 构造/复制/销毁
    list() : list(Allocator()) { }
    explicit list(const Allocator&);
    explicit list(size_type n, const Allocator& = Allocator());
    list(size_type n, const T& value, const Allocator& = Allocator());
    template<class InputIt>
      list(InputIt first, InputIt last, const Allocator& = Allocator());
    list(const list& x);
    list(list&& x);
    list(const list&, const Allocator&);
    list(list&&, const Allocator&);
    list(initializer_list<T>, const Allocator& = Allocator());
    ~list();
    list& operator=(const list& x);
    list& operator=(list&& x)
      noexcept(allocator_traits<Allocator>::is_always_equal::value);
    list& operator=(initializer_list<T>);
    template<class InputIt>
      void assign(InputIt first, InputIt last);
    void assign(size_type n, const T& t);
    void assign(initializer_list<T>);
    allocator_type get_allocator() const noexcept;

    // 迭代器
    iterator               begin() noexcept;
    const_iterator         begin() const noexcept;
    iterator               end() noexcept;
    const_iterator         end() const noexcept;
    reverse_iterator       rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator       rend() noexcept;
    const_reverse_iterator rend() const noexcept;

    const_iterator         cbegin() const noexcept;
    const_iterator         cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // 容量
    [[nodiscard]] bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;
    void      resize(size_type sz);
    void      resize(size_type sz, const T& c);

    // 元素访问
    reference       front();
    const_reference front() const;
    reference       back();
    const_reference back() const;

    // 修改器
    template<class... Args> reference emplace_front(Args&&... args);
    template<class... Args> reference emplace_back(Args&&... args);
    void push_front(const T& x);
    void push_front(T&& x);
    void pop_front();
    void push_back(const T& x);
    void push_back(T&& x);
    void pop_back();

    template<class... Args> iterator emplace(const_iterator position, Args&&... args);
    iterator insert(const_iterator position, const T& x);
    iterator insert(const_iterator position, T&& x);
    iterator insert(const_iterator position, size_type n, const T& x);
    template<class InputIt>
      iterator insert(const_iterator position, InputIt first, InputIt last);
    iterator insert(const_iterator position, initializer_list<T> il);

    iterator erase(const_iterator position);
    iterator erase(const_iterator position, const_iterator last);
    void     swap(list&) noexcept(allocator_traits<Allocator>::is_always_equal::value);
    void     clear() noexcept;

    // list 操作
    void splice(const_iterator position, list& x);
    void splice(const_iterator position, list&& x);
    void splice(const_iterator position, list& x, const_iterator i);
    void splice(const_iterator position, list&& x, const_iterator i);
    void splice(const_iterator position, list& x,
                const_iterator first, const_iterator last);
    void splice(const_iterator position, list&& x,
                const_iterator first, const_iterator last);

    size_type remove(const T& value);
    template<class Predicate> size_type remove_if(Predicate pred);

    size_type unique();
    template<class BinaryPredicate>
      size_type unique(BinaryPredicate binary_pred);

    void merge(list& x);
    void merge(list&& x);
    template<class Compare> void merge(list& x, Compare comp);
    template<class Compare> void merge(list&& x, Compare comp);

    void sort();
    template<class Compare> void sort(Compare comp);

    void reverse() noexcept;
  };

  template<class InputIt, class Allocator = allocator</*iter-value-type*/<InputIt>>>
    list(InputIt, InputIt, Allocator = Allocator())
      -> list</*iter-value-type*/<InputIt>, Allocator>;

  // 交换
  template<class T, class Allocator>
    void swap(list<T, Allocator>& x, list<T, Allocator>& y)
      noexcept(noexcept(x.swap(y)));
}


标准库头文件 <locale>

< cpp‎ | header

此头文件是本地化库的一部分。

类
locale
 用以封装文化差异的多态刻面的集合
(类)
字符串与流转换
wstring_convert
(C++11)(C++17 中弃用)
 进行宽字符串和字节字符串之间的转换
(类模板)
wbuffer_convert
(C++11)(C++17 中弃用)
 进行字节流缓冲区和宽流缓冲区间的转换
(类模板)
刻面类别的基类
ctype_base
 定义字符分类类别
(类)
codecvt_base
 定义字符转换错误
(类)
messages_base
 定义消息目录类型
(类)
time_base
 定义日期格式常量
(类)
money_base
 定义货币格式化模式
(类)
刻面类别
ctype
 定义字符分类表
(类模板)
ctype<char>
 std::ctype 对于 char 类型的特化
(类模板特化)
codecvt
 在字符编码间转换，包括 UTF-8、UTF-16、UTF-32
(类模板)
collate
 定义字典序比较和字符串的散列
(类模板)
messages
 实现从消息目录获取字符串
(类模板)
time_get
 从输入字符序列中解析时间/日期值到 std::tm 中
(类模板)
time_put
 格式化 std::tm 内容为字符序列以输出
(类模板)
num_get
 从输入字符序列中解析数字值
(类模板)
num_put
 格式化数值为字符序列以输出
(类模板)
numpunct
 定义数值标点规则
(类模板)
money_get
 从输入字符序列中解析并构造货币值
(类模板)
money_put
 格式化货币值为字符序列以输出
(类模板)
moneypunct
 定义 std::money_get 与 std::money_put 所用的货币格式解析器的参数
(类模板)
特定于本地环境的刻面类别
ctype_byname
 表示系统提供的具名本地环境的 std::ctype
(类模板)
codecvt_byname
 表示系统提供的具名本地环境的 std::codecvt
(类模板)
messages_byname
 表示系统提供的具名本地环境的 std::messages
(类模板)
collate_byname
 表示系统提供的具名本地环境的 std::collate
(类模板)
time_get_byname
 表示系统提供的具名本地环境的 std::time_get
(类模板)
time_put_byname
 表示系统提供的具名本地环境的 std::time_put
(类模板)
numpunct_byname
 表示系统提供的具名本地环境的 std::numpunct
(类模板)
moneypunct_byname
 表示系统提供的具名本地环境的 std::moneypunct
(类模板)

函数
本地环境与刻面
use_facet
 从本地环境获得一个刻面
(函数模板)
has_facet
 检查本地环境是否实现特定的刻面
(函数模板)
字符分类
isspace(std::locale)
 检查字符是否被本地环境分类为空白
(函数模板)
isblank(std::locale)
(C++11)
 检查字符是否被本地环境分类为空格字符
(函数模板)
iscntrl(std::locale)
 检查字符是否被本地环境分类为控制字符
(函数模板)
isupper(std::locale)
 检查字符是否被本地环境分类为大写
(函数模板)
islower(std::locale)
 检查字符是否被本地环境分类为小写
(函数模板)
isalpha(std::locale)
 检查字符是否被本地环境分类为字母
(函数模板)
isdigit(std::locale)
 检查字符是否被本地环境分类为数字
(函数模板)
ispunct(std::locale)
 检查字符是否被本地环境分类为标点
(函数模板)
isxdigit(std::locale)
 检查字符是否被本地环境分类为十六进制数字
(函数模板)
isalnum(std::locale)
 检查字符是否被本地环境分类为字母或数字
(函数模板)
isprint(std::locale)
 检查字符是否被本地环境分类为可打印字符
(函数模板)
isgraph(std::locale)
 检查字符是否被本地环境分类为图形字符
(函数模板)
字符转换
toupper(std::locale)
 用本地环境的 ctype 刻面将字符转换为大写
(函数模板)
tolower(std::locale)
 用本地环境的 ctype 刻面将字符转换为小写
(函数模板)

概要

namespace std {

    // locale ：
    class locale;
    template <class Facet> const Facet& use_facet(const locale&);
    template <class Facet> bool has_facet(const locale&) noexcept;

    // 便利接口：
    template <class charT> bool isspace (charT c, const locale& loc);
    template <class charT> bool isprint (charT c, const locale& loc);
    template <class charT> bool iscntrl (charT c, const locale& loc);
    template <class charT> bool isupper (charT c, const locale& loc);
    template <class charT> bool islower (charT c, const locale& loc);
    template <class charT> bool isalpha (charT c, const locale& loc);
    template <class charT> bool isdigit (charT c, const locale& loc);
    template <class charT> bool ispunct (charT c, const locale& loc);
    template <class charT> bool isxdigit(charT c, const locale& loc);
    template <class charT> bool isalnum (charT c, const locale& loc);
    template <class charT> bool isgraph (charT c, const locale& loc);
    template <class charT> charT toupper(charT c, const locale& loc);
    template <class charT> charT tolower(charT c, const locale& loc);
    template <class Codecvt, class Elem = wchar_t,
              class Wide_alloc = std::allocator<Elem>,
        class Byte_alloc = std::allocator<char> > class wstring_convert;
    template <class Codecvt, class Elem = wchar_t,
              class Tr = char_traits<Elem>> class wbuffer_convert;

    // 字符类型：
    class ctype_base;
    template <class charT> class ctype;
    template <>            class ctype<char>; // 特化
    template <class charT> class ctype_byname;
    class codecvt_base;
    template <class internT, class externT, class stateT> class codecvt;
    template <class internT, class externT, class stateT> class codecvt_byname;

    // 数值：
    template <class charT, class InputIterator = istreambuf_iterator<charT> > class num_get;
    template <class charT, class OutputIterator = osterambuf_iterator<charT> > class num_put;
    template <class charT> class numpunct;
    template <class charT> class numpunct_byname;

    // 校对：
    template <class charT> class collate;
    template <class charT> class collate_byname;

    // 日期与时间：
    class time_base;
    template <class charT, class InputIterator = istreambuf_iterator<charT> >
        class time_get;
    template <class charT, class InputIterator> = istreambuf_iterator<charT> >
        class time_get_byname;
    template <class charT, class OutputIterator> = ostreambuf_iterator<charT> >
        class time_put;
    template <class charT, class OutputIterator> = ostreambuf_iterator<charT> >
        class time_put_byname;

    // 货币：
    class money_base;
    template <class charT, class InputIterator = istreambuf_iterator<charT> > >
        class money_get;
    template <class charT, class OutputIterator = ostreambuf_iterator<charT> > >
        class money_put;
    template <class charT, bool Intl = false> class moneypunct;
    template <class charT, bool Intl = false> class moneypunct_byname;

    // 消息获取：
    class messages_base;
    template <class charT> class messages;
    template <class charT> class messages_byname;
}

类 std::locale

class locale
{
public:
    // types:
    class facet;
    class id;
    typedef int category;
    static const category // 此处所赋之值仅用于阐释
        none    = 0,
        collate = 0x010,
        ctype   = 0x020,
        monetary= 0x040,
        numeric = 0x080,
        time    = 0x100,
        messages= 0x200,
        all = collate | ctype | monetary | numeric | time | messages;

    // 构造/复制/销毁：
    locale() noexcept;
    locale(const locale& other) noexcept;
    explicit locale(const char* std_name);
    explicit locale(const string& std_name);
    locale(const locale& other, const char* std_name, category);
    locale(const locale& other, const string& std_name, category);
    template <class Facet> locale(const locale& other, Facet* f);
    locale(const locale& other, const locale& one, category);
    ~locale();

    // 非虚函数
    const locale& operator=(const locale& other) noexcept;
    template <class Facet> locale combine(const locale& other) const;

    // locale 操作：
    basic_string<char>
    name() const;
    bool operator==(const locale& other) const;
    bool operator!=(const locale& other) const;
    template <class charT, class traits, class Allocator>
    bool operator()(const basic_string<charT,traits,Allocator>& s1,
                    const basic_string<charT,traits,Allocator>& s2) const;

    // 全局 locale 对象：
    static
    locale global(const locale&);
    static const locale& classic();
};

类 std::ctype_base

class ctype_base
{
public:
    typedef /*T*/ mask;

    // 数值仅为说明。
    static const mask space = 1 << 0;
    static const mask print = 1 << 1;
    static const mask cntrl = 1 << 2;
    static const mask upper = 1 << 3;
    static const mask lower = 1 << 4;
    static const mask alpha = 1 << 5;
    static const mask digit = 1 << 6;
    static const mask punct = 1 << 7;
    static const mask xdigit= 1 << 8;
    static const mask blank = 1 << 9;
    static const mask alnum = alpha | digit;
    static const mask graph = alnum | punct;

};

类 std::ctype

template <class charT>
class ctype : public locale::facet, public ctype_base
{
public:
    typedef charT char_type;

    explicit ctype(size_t refs = 0);

    bool is(mask m, charT c) const;
    const charT* is(const charT* low, const charT* high, mask* vec) const;
    const charT* scan_is(mask m,
                         const charT* low, const charT* high) const;
    const charT* scan_not(mask m,
                          const charT* low, const charT* high) const;

    charT           toupper(charT c) const;
    const charT*    toupper(charT* low, const charT* high) const;
    charT           tolower(charT c) const;
    const charT*    tolower(charT* low, const charT* high) const;

    charT       widen(char c) const;
    const char* widen(const char* low, const char* high, charT* to) const;
    char        narrow(charT c, char dfault) const;
    const charT*narrow(const charT* low, const charT*, char dfault,
                        char* to) const;

    static locale::id id;

protected:
    ~ctype();
    virtual bool do_is(mask m, charT c) const;
    virtual const charT* do_is(const charT* low, const charT* high,
                               mask* vec) const;
    virtual const charT* do_scan_is(mask m,
                                    const charT* low, const charT* high) const;
    virtual const charT* do_scan_not(mask m,
                                     const charT* low, const charT* high) const;

    virtual charT do_toupper(charT) const;
    virtual const charT* do_toupper(charT* low, const charT* high) const;
    virtual charT do_tolower(charT) const;
    virtual const charT* do_tolower(charT* low, const charT* high) const;
    virtual charT do_widen(char) const;
    virtual const char*  do_widen(const char* low, const char* high,
                                  charT* dest) const;
    virtual char do_narrow(charT, char dfault) const;
    virtual const charT* do_narrow(const charT* low, const charT* high,
                                   char dfault, char* dest) const;
};

类 std::ctype_byname

template <class charT>
class ctype_byname : public ctype<charT>
{
public:
    typedef typename ctype<charT>::mask mask;
    explicit ctype_byname(const char*, size_t refs = 0);
    explicit ctype_byname(const string&, size_t refs = 0);
    protected:
    ~ctype_byname();
};

类 std::ctype <char>

template <> class ctype<char>
    : public locale::facet, public ctype_base
{
public:
    typedef char char_type;
    explicit ctype(const mask* tab = 0, bool del = false,
                   size_t refs = 0);
    bool is(mask m, char c) const;
    const char* is(const char* low, const char* high, mask* vec) const;
    const char* scan_is (mask m,
                         const char* low, const char* high) const;
    const char* scan_not(mask m,
                         const char* low, const char* high) const;
    char        toupper(char c) const;
    const char* toupper(char* low, const char* high) const;
    char        tolower(char c) const;
    const char* tolower(char* low, const char* high) const;
    char        widen(char c) const;
    const char* widen(const char* low, const char* high, char* to) const;
    char        narrow(char c, char dfault) const;
    const char* narrow(const char* low, const char* high, char dfault,
                       char* to) const;

    static locale::id id;

    static const size_t table_size = implementation-defined;
    const mask* table() const noexcept;
    static const mask* classic_table() noexcept;

protected:
    ~ctype();
    virtual char        do_toupper(char c) const;
    virtual const char* do_toupper(char* low, const char* high) const;
    virtual char        do_tolower(char c) const;
    virtual const char* do_tolower(char* low, const char* high) const;
    virtual char        do_widen(char c) const;
    virtual const char* do_widen(const char* low,
                                 const char* high,
                                 char* to) const;
    virtual char        do_narrow(char c, char dfault) const;
    virtual const char* do_narrow(const char* low,
                                  const char* high,
                                  char dfault, char* to) const;
};

类 std::codecvt_base

class codecvt_base
{
public:
    enum result { ok, partial, error, noconv };
};

类 std::codecvt

template <class internT, class externT, class stateT>
class codecvt : public locale::facet, public codecvt_base
{
public:
        typedef internT intern_type;
        typedef externT extern_type;
        typedef stateT state_type;
        explicit codecvt(size_t refs = 0);
        result out(stateT& state,
                   const internT* from, const internT* from_end,
                   const internT*& from_next,
                   externT* to, externT* to_end, externT*& to_next) const;
        result unshift(stateT& state, externT* to,
                       externT* to_end, externT*& to_next) const;
        result in(stateT& state,
                  const externT* from, const externT* from_end,
                  const externT*& from_next,
                  internT* to,
                  internT* to_end, internT*& to_next) const;
        int encoding() const noexcept;
        bool always_noconv() const noexcept;
        int length(stateT&, const externT* from, const externT* end,
                   size_t max) const;
        int max_length() const noexcept;
        static locale::id id;
protected:
        ~codecvt();
        virtual result do_out(stateT& state,
                              const internT* from, const internT* from_end,
                              const internT*& from_next,
                              externT* to,
                              externT* to_end, externT*& to_next) const;
        virtual result do_in(stateT& state,
                             const externT* from, const externT* from_end,
                             const externT*& from_next,
                             internT* to,
                             internT* to_end, internT*& to_next) const;
        virtual result do_unshift(stateT& state,
                                  externT* to,
                                  externT* to_end, externT*& to_next) const;
        virtual int do_encoding() const noexcept;
        virtual bool do_always_noconv() const noexcept;
        virtual int do_length(stateT&, const externT* from,
                              const externT* end, size_t max) const;
        virtual int do_max_length() const noexcept;
};

类 std::codecvt_byname

template <class internT, class externT, class stateT>
class codecvt_byname : public codecvt<internT, externT, stateT>
{
public:
    explicit codecvt_byname(const char*, size_t refs = 0);
    explicit codecvt_byname(const string&, size_t refs = 0);
protected:
    ~codecvt_byname();
};

类 std::num_get

template <class charT, class InputIterator = istreambuf_iterator<charT> >
class num_get : public locale::facet
{
public:
    typedef charT           char_type;
    typedef InputIterator   iter_type;
    explicit num_get(size_t refs = 0);
    iter_type get(iter_type in, iter_type end, ios_base&,
                  ios_base::iostate& err, bool& v) const;
    iter_type get(iter_type in, iter_type end, ios_base& ,
                  ios_base::iostate& err, long& v) const;
    iter_type get(iter_type in, iter_type end, ios_base& ,
                  ios_base::iostate& err, long long& v) const;
    iter_type get(iter_type in, iter_type end, ios_base&,
                  ios_base::iostate& err, unsigned short& v) const;
    iter_type get(iter_type in, iter_type end, ios_base&,
                  ios_base::iostate& err, unsigned int& v) const;
    iter_type get(iter_type in, iter_type end, ios_base&,
                  ios_base::iostate& err, unsigned long& v) const;
    iter_type get(iter_type in, iter_type end, ios_base& ,
                  ios_base::iostate& err, unsigned long long& v) const;
    iter_type get(iter_type in, iter_type end, ios_base&,
                  ios_base::iostate& err, float& v) const;
    iter_type get(iter_type in, iter_type end, ios_base&,
                  ios_base::iostate& err, double& v) const;
    iter_type get(iter_type in, iter_type end, ios_base&,
                  ios_base::iostate& err, long double& v) const;
    iter_type get(iter_type in, iter_type end, ios_base&,
                  ios_base::iostate& err, void*& v) const;

    static locale::id id;

protected:
    ~num_get();

    virtual iter_type do_get(iter_type, iter_type, ios_base&,
                             ios_base::iostate& err, bool& v) const;
    virtual iter_type do_get(iter_type, iter_type, ios_base&,
                             ios_base::iostate& err, long& v) const;
    virtual iter_type do_get(iter_type, iter_type, ios_base&,
                             ios_base::iostate& err, long long& v) const;
    virtual iter_type do_get(iter_type, iter_type, ios_base&,
                             ios_base::iostate& err, unsigned short& v) const;
    virtual iter_type do_get(iter_type, iter_type, ios_base&,
                             ios_base::iostate& err, unsigned int& v) const;
    virtual iter_type do_get(iter_type, iter_type, ios_base&,
                             ios_base::iostate& err, unsigned long& v) const;
    virtual iter_type do_get(iter_type, iter_type, ios_base&,
                             ios_base::iostate& err, unsigned long long& v) const;
    virtual iter_type do_get(iter_type, iter_type, ios_base&,
                             ios_base::iostate& err, float& v) const;
    virtual iter_type do_get(iter_type, iter_type, ios_base&,
                             ios_base::iostate& err, double& v) const;
    virtual iter_type do_get(iter_type, iter_type, ios_base&,
                             ios_base::iostate& err, long double& v) const;
    virtual iter_type do_get(iter_type, iter_type, ios_base&,
                             ios_base::iostate& err, void*& v) const;
};

类 std::num_put

template <class CharT, class OutputIterator = ostreambuf_iterator<CharT> >
class num_put : public locale::facet
{
public:
    typedef CharT char_type;
    typedef OutputIterator iter_type;

    explicit num_put(size_t refs = 0);

    iter_type put(iter_type s, ios_base& f, char_type fill,
                  bool v) const;
    iter_type put(iter_type s, ios_base& f, char_type fill,
                  long v) const;
    iter_type put(iter_type s, ios_base& f, char_type fill,
                  long long v) const;
    iter_type put(iter_type s, ios_base& f, char_type fill,
                  unsigned long v) const;
    iter_type put(iter_type s, ios_base& f, char_type fill,
                  unsigned long long v) const;
    iter_type put(iter_type s, ios_base& f, char_type fill,
                  double v) const;
    iter_type put(iter_type s, ios_base& f, char_type fill,
                  long double v) const;
    iter_type put(iter_type s, ios_base& f, char_type fill,
                  const void* v) const;

    static locale::id id;

protected:
    ~num_put();

    virtual iter_type do_put(iter_type, ios_base&, char_type fill,
                             bool v) const;
    virtual iter_type do_put(iter_type, ios_base&, char_type fill,
                             long v) const;
    virtual iter_type do_put(iter_type, ios_base&, char_type fill,
                             long long v) const;
    virtual iter_type do_put(iter_type, ios_base&, char_type fill,
                             unsigned long) const;
    virtual iter_type do_put(iter_type, ios_base&, char_type fill,
                             unsigned long long) const;
    virtual iter_type do_put(iter_type, ios_base&, char_type fill,
                             double v) const;
    virtual iter_type do_put(iter_type, ios_base&, char_type fill,
                             long double v) const;
    virtual iter_type do_put(iter_type, ios_base&, char_type fill,
                             const void* v) const;
};

类 std::numpunct

template <class CharT>
class numpunct : public locale::facet
{
public:
    typedef CharT char_type;
    typedef basic_string<CharT> string_type;

    explicit numpunct(size_t refs = 0);

    char_type   decimal_point() const;
    char_type   thousands_sep() const;
    string      grouping()      const;
    string_type truename()      const;
    string_type falsename()     const;

    static locale::id id;

protected:
    ~numpunct(); // 虚函数

    virtual char_type   do_decimal_point() const;
    virtual char_type   do_thousands_sep() const;
    virtual string      do_grouping()      const;
    virtual string_type do_truename()      const; // 对于 bool
    virtual string_type do_falsename()     const; // 对于 bool
};

类 std::numpunct_byname

template <class CharT>
class numpunct_byname : public numpunct<CharT>
{
public:
    typedef CharT char_type;
    typedef basic_string<CharT> string_type;

    explicit numpunct_byname(const char*, size_t refs = 0);
    explicit numpunct_byname(const string&, size_t refs = 0);

protected:
    ~numpunct_byname();
};

类 std::collate

template <class CharT>
class collate : public locale::facet
{
public:
    typedef CharT char_type;
    typedef basic_string<CharT> string_type;

    explicit collate(size_t refs = 0);

    int compare(const CharT* low1, const CharT* high1,
                const CharT* low2, const CharT* high2) const;
    string_type transform(const CharT* low, const CharT* high) const;
    long hash(const CharT* low, const CharT* high) const;

    static locale::id id;

protected:
    ~collate();

    virtual int do_compare(const CharT* low1, const CharT* high1,
                           const CharT* low2, const CharT* high2) const;
    virtual string_type do_transform(const CharT* low,
                                     const CharT* high) const;
    virtual long do_hash (const CharT* low, const CharT* high) const;
};

类 std::collate_byname

template <class CharT>
class collate_byname : public collate<CharT>
{
public:
    typedef basic_string<CharT> string_type;

    explicit collate_byname(const char*, size_t refs = 0);
    explicit collate_byname(const string&, size_t refs = 0);

protected:
    ~collate_byname();
};

类 std::time_base

class time_base
{
public:
    enum dateorder { no_order, dmy, mdy, ymd, ydm };
};

类 std::time_get

template <class CharT, class InputIterator = istreambuf_iterator<CharT> >
class time_get : public locale::facet, public time_base
{
public:
    typedef CharT char_type;
    typedef InputIterator iter_type;

    explicit time_get(size_t refs = 0);

    dateorder date_order() const;
    iter_type get_time(iter_type s, iter_type end, ios_base& f,
                       ios_base::iostate& err, tm* t) const;
    iter_type get_date(iter_type s, iter_type end, ios_base& f,
                       ios_base::iostate& err, tm* t) const;
    iter_type get_weekday(iter_type s, iter_type end, ios_base& f,
                          ios_base::iostate& err, tm* t) const;
    iter_type get_monthname(iter_type s, iter_type end, ios_base& f,
                            ios_base::iostate& err, tm* t) const;
    iter_type get_year(iter_type s, iter_type end, ios_base& f,
                       ios_base::iostate& err, tm* t) const;
    iter_type get(iter_type s, iter_type end, ios_base& f,
                  ios_base::iostate& err, tm* t, char format,
                  char modifier = 0) const;
    iter_type get(iter_type s, iter_type end, ios_base& f,
                  ios_base::iostate& err, tm* t,
                  const char_type* fmt, const char_type* fmtend) const;

    static locale::id id;

protected:
    ~time_get();

    virtual dateorder do_date_order() const;
    virtual iter_type do_get_time(iter_type s, iter_type end, ios_base&,
                                  ios_base::iostate& err, tm* t) const;
    virtual iter_type do_get_date(iter_type s, iter_type end, ios_base&,
                                  ios_base::iostate& err, tm* t) const;
    virtual iter_type do_get_weekday(iter_type s, iter_type end, ios_base&,
                                     ios_base::iostate& err, tm* t) const;
    virtual iter_type do_get_monthname(iter_type s, iter_type end, ios_base&,
                                       ios_base::iostate& err, tm* t) const;
    virtual iter_type do_get_year(iter_type s, iter_type end, ios_base&,
                                  ios_base::iostate& err, tm* t) const;
    virtual iter_type do_get(iter_type s, iter_type end, ios_base& f,
                             ios_base::iostate& err, tm* t,
                             char format, char modifier) const;
};

类 std::time_get_byname

template <class CharT, class InputIterator = istreambuf_iterator<CharT> >
class time_get_byname : public time_get<CharT, InputIterator>
{
public:
    typedef time_base::dateorder dateorder;
    typedef InputIterator iter_type;

    explicit time_get_byname(const char*, size_t refs = 0);
    explicit time_get_byname(const string&, size_t refs = 0);

protected:
    ~time_get_byname();
};

类 std::time_put

template <class CharT, class OutputIterator = ostreambuf_iterator<CharT> >
class time_put : public locale::facet
{
public:
    typedef CharT char_type;
    typedef OutputIterator iter_type;

    explicit time_put(size_t refs = 0);

    // 下列函数以其他成员函数实现。
    iter_type put(iter_type s, ios_base& f, char_type fill, const tm* tmb,
                  const CharT* pattern, const CharT* pat_end) const;
    iter_type put(iter_type s, ios_base& f, char_type fill,
                  const tm* tmb, char format, char modifier = 0) const;

    static locale::id id;

protected:
    ~time_put();

    virtual iter_type do_put(iter_type s, ios_base&, char_type, const tm* t,
                             char format, char modifier) const;
};

类 std::time_put_byname

template <class CharT, class OutputIterator = ostreambuf_iterator<CharT> >
class time_put_byname : public time_put<CharT, OutputIterator>
{
public:
    typedef CharT char_type;
    typedef OutputIterator iter_type;

    explicit time_put_byname(const char*, size_t refs = 0);
    explicit time_put_byname(const string&, size_t refs = 0);

protected:
    ~time_put_byname();
};

类 std::money_get

template <class CharT, class InputIterator = istreambuf_iterator<CharT> >
class money_get : public locale::facet
{
public:
    typedef CharT char_type;
    typedef InputIterator iter_type;
    typedef basic_string<CharT> string_type;

    explicit money_get(size_t refs = 0);

    iter_type get(iter_type s, iter_type end, bool intl, ios_base& f,
                  ios_base::iostate& err, long double& units) const;
    iter_type get(iter_type s, iter_type end, bool intl, ios_base& f,
                  ios_base::iostate& err, string_type& digits) const;

    static locale::id id;

protected:
    ~money_get();

    virtual iter_type do_get(iter_type, iter_type, bool, ios_base&,
                             ios_base::iostate& err,
                             long double& units) const;
    virtual iter_type do_get(iter_type, iter_type, bool, ios_base&,
                             ios_base::iostate& err,
                             string_type& digits) const;
};

类 std::money_put

template <class CharT, class OutputIterator = ostreambuf_iterator<CharT> >
class money_put : public locale::facet
{
public:
    typedef CharT char_type;
    typedef OutputIterator iter_type;
    typedef basic_string<CharT> string_type;

    explicit money_put(size_t refs = 0);

    iter_type put(iter_type s, bool intl, ios_base& f,
                  char_type fill, long double units) const;
    iter_type put(iter_type s, bool intl, ios_base& f,
                  char_type fill, const string_type& digits) const;

    static locale::id id;

protected:
    ~money_put();

    virtual iter_type do_put(iter_type, bool, ios_base&, char_type fill,
                             long double units) const;
    virtual iter_type do_put(iter_type, bool, ios_base&, char_type fill,
                             const string_type& digits) const;
};

类 std::money_base

class money_base
{
public:
    enum part { none, space, symbol, sign, value };
    struct pattern { char field[4]; };
};

类 std::moneypunct

template <class CharT, bool International = false>
class moneypunct : public locale::facet, public money_base
{
public:
    typedef CharT char_type;
    typedef basic_string<CharT> string_type;

    explicit moneypunct(size_t refs = 0);

    CharT       decimal_point() const;
    CharT       thousands_sep() const;
    string      grouping()      const;
    string_type curr_symbol()   const;
    string_type positive_sign() const;
    string_type negative_sign() const;
    int         frac_digits()   const;
    pattern     pos_format()    const;
    pattern     neg_format()    const;

    static locale::id id;
    static const bool intl = International;

protected:
    ~moneypunct();

    virtual CharT       do_decimal_point() const;
    virtual CharT       do_thousands_sep() const;
    virtual string      do_grouping()      const;
    virtual string_type do_curr_symbol()   const;
    virtual string_type do_positive_sign() const;
    virtual string_type do_negative_sign() const;
    virtual int         do_frac_digits()   const;
    virtual pattern     do_pos_format()    const;
    virtual pattern     do_neg_format()    const;
};

类 std::moneypunct_byname

template <class CharT, bool Intl = false>
class moneypunct_byname : public moneypunct<CharT, Intl>
{
public:
    typedef money_base::pattern pattern;
    typedef basic_string<CharT> string_type;

    explicit moneypunct_byname(const char*, size_t refs = 0);
    explicit moneypunct_byname(const string&, size_t refs = 0);

protected:
    ~moneypunct_byname();
};

类 std::messages_base

class messages_base
{
public:
    typedef /* 未指明的有符号整数类型 */ catalog;
};

类 std::messages

template <class CharT>
class messages : public locale::facet, public messages_base {
public:
    typedef CharT char_type;
    typedef basic_string<CharT> string_type;

    explicit messages(size_t refs = 0);

    catalog open(const basic_string<char>& fn, const locale&) const;
    string_type get(catalog c, int set, int msgid,
                    const string_type& dfault) const;
    void close(catalog c) const;

    static locale::id id;

protected:
    ~messages();

    virtual catalog do_open(const basic_string<char>&, const locale&) const;
    virtual string_type do_get(catalog, int set, int msgid,
                               const string_type& dfault) const;
    virtual void do_close(catalog) const;
};

类 std::messages_byname

template <class CharT>
class messages_byname : public messages<CharT>
{
public:
    typedef messages_base::catalog catalog;
    typedef basic_string<CharT> string_type;

    explicit messages_byname(const char*, size_t refs = 0);
    explicit messages_byname(const string&, size_t refs = 0);

protected:
    ~messages_byname();
};

类 std::wstring_convert

template<class Codecvt, class Elem = wchar_t,
    class Wide_alloc = std::allocator<Elem>,
    class Byte_alloc = std::allocator<char> >
class wstring_convert
{
public:
    typedef std::basic_string<char, char_traits<char>, Byte_alloc> byte_string;
    typedef std::basic_string<Elem, char_traits<Elem>, Wide_alloc> wide_string;
    typedef typename Codecvt::state_type state_type;
    typedef typename wide_string::traits_type::int_type int_type;

    explicit wstring_convert(Codecvt* pcvt = new Codecvt);
    wstring_convert(Codecvt* pcvt, state_type state);
    explicit wstring_convert(const byte_string& byte_err,
                             const wide_string& wide_err = wide_string());
    ~wstring_convert();

    wstring_convert(const wstring_convert&) = delete;
    wstring_convert& operator=(const wstring_convert&) = delete;

    wide_string from_bytes(char byte);
    wide_string from_bytes(const char* ptr);
    wide_string from_bytes(const byte_string& str);
    wide_string from_bytes(const char* first, const char* last);
    byte_string to_bytes(Elem wchar);
    byte_string to_bytes(const Elem* wptr);
    byte_string to_bytes(const wide_string& wstr);
    byte_string to_bytes(const Elem* first, const Elem* last);
    size_t converted() const noexcept;
    state_type state() const;

private:
    byte_string byte_err_string; // 仅用于阐释
    wide_string wide_err_string; // 仅用于阐释
    Codecvt* cvtptr;             // 仅用于阐释
    state_type cvtstate;         // 仅用于阐释
    size_t cvtcount;             // 仅用于阐释
};

类 std::wbuffer_convert

template<class Codecvt,
    class Elem = wchar_t,
    class Tr = std::char_traits<Elem> >
class wbuffer_convert : public std::basic_streambuf<Elem, Tr>
{
public:
    typedef typename Codecvt::state_type state_type;

    explicit wbuffer_convert(std::streambuf* bytebuf = 0,
                             Codecvt* pcvt = new Codecvt,
                             state_type state = state_type());
    ~wbuffer_convert();

    wbuffer_convert(const wbuffer_convert&) = delete;
    wbuffer_convert& operator=(const wbuffer_convert&) = delete;

    std::streambuf* rdbuf() const;
    std::streambuf* rdbuf(std::streambuf* bytebuf);
    state_type state() const;
private:
    std::streambuf* bufptr; // 仅用于阐释
    Codecvt* cvtptr;        // 仅用于阐释
    state_type cvtstate;    // 仅用于阐释
};


标准库头文件 <map>

< cpp‎ | header

此头文件是容器库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
<initializer_list>
(C++11)
 std::initializer_list 类模板

类
map
 键值对的集合，按照键排序，键是唯一的
(类模板)
multimap
 键值对的集合，按照键排序
(类模板)

函数
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 map 中的值
(函数模板)
std::swap(std::map)
 特化 std::swap 算法
(函数模板)
erase_if(std::map)
(C++20)
 擦除所有满足特定判别标准的元素
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 multimap 中的值
(函数模板)
std::swap(std::multimap)
 特化 std::swap 算法
(函数模板)
erase_if(std::multimap)
(C++20)
 擦除所有满足特定判别标准的元素
(函数模板)
范围访问
begincbegin
(C++11)(C++14)
 返回指向容器或数组起始的迭代器
(函数模板)
endcend
(C++11)(C++14)
 返回指向容器或数组结尾的迭代器
(函数模板)
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
sizessize
(C++17)(C++20)
 返回容器或数组的大小
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)

概要

#include <compare>
#include <initializer_list>

namespace std {
  // 类模板 map
  template<class Key, class T, class Compare = less<Key>,
           class Allocator = allocator<pair<const Key, T>>>
    class map;

  template<class Key, class T, class Compare, class Allocator>
    bool operator==(const map<Key, T, Compare, Allocator>& x,
                    const map<Key, T, Compare, Allocator>& y);
  template<class Key, class T, class Compare, class Allocator>
    /*synth-three-way-result*/<pair<const Key, T>>
      operator<=>(const map<Key, T, Compare, Allocator>& x,
                  const map<Key, T, Compare, Allocator>& y);

  template<class Key, class T, class Compare, class Allocator>
    void swap(map<Key, T, Compare, Allocator>& x,
              map<Key, T, Compare, Allocator>& y)
      noexcept(noexcept(x.swap(y)));

  template<class Key, class T, class Compare, class Allocator, class Predicate>
    typename map<Key, T, Compare, Allocator>::size_type
      erase_if(map<Key, T, Compare, Allocator>& c, Predicate pred);

  // 类模板 multimap
  template<class Key, class T, class Compare = less<Key>,
           class Allocator = allocator<pair<const Key, T>>>
    class multimap;

  template<class Key, class T, class Compare, class Allocator>
    bool operator==(const multimap<Key, T, Compare, Allocator>& x,
                    const multimap<Key, T, Compare, Allocator>& y);
  template<class Key, class T, class Compare, class Allocator>
    /*synth-three-way-result*/<pair<const Key, T>>
      operator<=>(const multimap<Key, T, Compare, Allocator>& x,
                  const multimap<Key, T, Compare, Allocator>& y);

  template<class Key, class T, class Compare, class Allocator>
    void swap(multimap<Key, T, Compare, Allocator>& x,
              multimap<Key, T, Compare, Allocator>& y)
      noexcept(noexcept(x.swap(y)));

  template<class Key, class T, class Compare, class Allocator, class Predicate>
    typename multimap<Key, T, Compare, Allocator>::size_type
      erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred);

  namespace pmr {
    template<class Key, class T, class Compare = less<Key>>
      using map = std::map<Key, T, Compare,
                           polymorphic_allocator<pair<const Key, T>>>;

    template<class Key, class T, class Compare = less<Key>>
      using multimap = std::multimap<Key, T, Compare,
                                     polymorphic_allocator<pair<const Key, T>>>;
  }
}

类模板 std::map

namespace std {
  template<class Key, class T, class Compare = less<Key>,
           class Allocator = allocator<pair<const Key, T>>>
  class map {
  public:
    // 类型
    using key_type               = Key;
    using mapped_type            = T;
    using value_type             = pair<const Key, T>;
    using key_compare            = Compare;
    using allocator_type         = Allocator;
    using pointer                = typename allocator_traits<Allocator>::pointer;
    using const_pointer          = typename allocator_traits<Allocator>::const_pointer;
    using reference              = value_type&;
    using const_reference        = const value_type&;
    using size_type              = /* 由实现定义 */;
    using difference_type        = /* 由实现定义 */;
    using iterator               = /* 由实现定义 */;
    using const_iterator         = /* 由实现定义 */;
    using reverse_iterator       = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
    using node_type              = /* 未指明 */;
    using insert_return_type     = /*insert-return-type*/<iterator, node_type>;

    class value_compare {
      friend class map;
    protected:
      Compare comp;
      value_compare(Compare c) : comp(c) {}
    public:
      bool operator()(const value_type& x, const value_type& y) const {
        return comp(x.first, y.first);
      }
    };

    // 构造/复制/销毁
    map() : map(Compare()) { }
    explicit map(const Compare& comp, const Allocator& = Allocator());
    template<class InputIt>
      map(InputIt first, InputIt last,
          const Compare& comp = Compare(), const Allocator& = Allocator());
    map(const map& x);
    map(map&& x);
    explicit map(const Allocator&);
    map(const map&, const Allocator&);
    map(map&&, const Allocator&);
    map(initializer_list<value_type>,
      const Compare& = Compare(),
      const Allocator& = Allocator());
    template<class InputIt>
      map(InputIt first, InputIt last, const Allocator& a)
        : map(first, last, Compare(), a) { }
    map(initializer_list<value_type> il, const Allocator& a)
      : map(il, Compare(), a) { }
    ~map();
    map& operator=(const map& x);
    map& operator=(map&& x)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_move_assignable_v<Compare>);
    map& operator=(initializer_list<value_type>);
    allocator_type get_allocator() const noexcept;

    // 迭代器
    iterator               begin() noexcept;
    const_iterator         begin() const noexcept;
    iterator               end() noexcept;
    const_iterator         end() const noexcept;

    reverse_iterator       rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator       rend() noexcept;
    const_reverse_iterator rend() const noexcept;

    const_iterator         cbegin() const noexcept;
    const_iterator         cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // 容量
    [[nodiscard]] bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    // 元素访问
    mapped_type& operator[](const key_type& x);
    mapped_type& operator[](key_type&& x);
    mapped_type&       at(const key_type& x);
    const mapped_type& at(const key_type& x) const;

    // 修改器
    template<class... Args> pair<iterator, bool> emplace(Args&&... args);
    template<class... Args> iterator emplace_hint(const_iterator position, Args&&... args);
    pair<iterator, bool> insert(const value_type& x);
    pair<iterator, bool> insert(value_type&& x);
    template<class P> pair<iterator, bool> insert(P&& x);
    iterator insert(const_iterator position, const value_type& x);
    iterator insert(const_iterator position, value_type&& x);
    template<class P>
      iterator insert(const_iterator position, P&&);
    template<class InputIt>
      void insert(InputIt first, InputIt last);
    void insert(initializer_list<value_type>);

    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    template<class K> node_type extract(K&& x);
    insert_return_type insert(node_type&& nh);
    iterator           insert(const_iterator hint, node_type&& nh);

    template<class... Args>
      pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
    template<class... Args>
      pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
    template<class... Args>
      iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
    template<class... Args>
      iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);
    template<class M>
      pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
    template<class M>
      pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
    template<class M>
      iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
    template<class M>
      iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);

    iterator  erase(iterator position);
    iterator  erase(const_iterator position);
    size_type erase(const key_type& x);
    template<class K> size_type erase(K&& x);
    iterator  erase(const_iterator first, const_iterator last);
    void      swap(map&)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_swappable_v<Compare>);
    void      clear() noexcept;

    template<class C2>
      void merge(map<Key, T, C2, Allocator>& source);
    template<class C2>
      void merge(map<Key, T, C2, Allocator>&& source);
    template<class C2>
      void merge(multimap<Key, T, C2, Allocator>& source);
    template<class C2>
      void merge(multimap<Key, T, C2, Allocator>&& source);

    // 观察器
    key_compare key_comp() const;
    value_compare value_comp() const;

    // map 操作
    iterator       find(const key_type& x);
    const_iterator find(const key_type& x) const;
    template<class K> iterator       find(const K& x);
    template<class K> const_iterator find(const K& x) const;

    size_type      count(const key_type& x) const;
    template<class K> size_type count(const K& x) const;

    bool           contains(const key_type& x) const;
    template<class K> bool contains(const K& x) const;

    iterator       lower_bound(const key_type& x);
    const_iterator lower_bound(const key_type& x) const;
    template<class K> iterator       lower_bound(const K& x);
    template<class K> const_iterator lower_bound(const K& x) const;

    iterator       upper_bound(const key_type& x);
    const_iterator upper_bound(const key_type& x) const;
    template<class K> iterator       upper_bound(const K& x);
    template<class K> const_iterator upper_bound(const K& x) const;

    pair<iterator, iterator>               equal_range(const key_type& x);
    pair<const_iterator, const_iterator>   equal_range(const key_type& x) const;
    template<class K>
      pair<iterator, iterator>             equal_range(const K& x);
    template<class K>
      pair<const_iterator, const_iterator> equal_range(const K& x) const;
  };

  template<class InputIt, class Compare = less</*iter-key-type*/<InputIt>>,
           class Allocator = allocator</*iter-to-alloc-type*/<InputIt>>>
    map(InputIt, InputIt, Compare = Compare(), Allocator = Allocator())
      -> map</*iter-key-type*/<InputIt>, /*iter-mapped-type*/<InputIt>,
             Compare, Allocator>;

  template<class Key, class T, class Compare = less<Key>,
           class Allocator = allocator<pair<const Key, T>>>
    map(initializer_list<pair<Key, T>>, Compare = Compare(), Allocator = Allocator())
      -> map<Key, T, Compare, Allocator>;

  template<class InputIt, class Allocator>
    map(InputIt, InputIt, Allocator)
      -> map</*iter-key-type*/<InputIt>, /*iter-mapped-type*/<InputIt>,
             less</*iter-key-type*/<InputIt>>, Allocator>;

  template<class Key, class T, class Allocator>
    map(initializer_list<pair<Key, T>>, Allocator) -> map<Key, T, less<Key>, Allocator>;

  // 交换
  template<class Key, class T, class Compare, class Allocator>
    void swap(map<Key, T, Compare, Allocator>& x,
              map<Key, T, Compare, Allocator>& y)
      noexcept(noexcept(x.swap(y)));
}

类模板 std::multimap

namespace std {
  template<class Key, class T, class Compare = less<Key>,
           class Allocator = allocator<pair<const Key, T>>>
  class multimap {
  public:
    // 类型
    using key_type               = Key;
    using mapped_type            = T;
    using value_type             = pair<const Key, T>;
    using key_compare            = Compare;
    using allocator_type         = Allocator;
    using pointer                = typename allocator_traits<Allocator>::pointer;
    using const_pointer          = typename allocator_traits<Allocator>::const_pointer;
    using reference              = value_type&;
    using const_reference        = const value_type&;
    using size_type              = /* 由实现定义 */;
    using difference_type        = /* 由实现定义 */;
    using iterator               = /* 由实现定义 */;
    using const_iterator         = /* 由实现定义 */;
    using reverse_iterator       = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
    using node_type              = /* 未指明 */;

    class value_compare {
      friend class multimap;
    protected:
      Compare comp;
      value_compare(Compare c) : comp(c) { }
    public:
      bool operator()(const value_type& x, const value_type& y) const {
        return comp(x.first, y.first);
      }
    };

    // 构造/复制/销毁
    multimap() : multimap(Compare()) { }
    explicit multimap(const Compare& comp, const Allocator& = Allocator());
    template<class InputIt>
      multimap(InputIt first, InputIt last,
               const Compare& comp = Compare(),
               const Allocator& = Allocator());
    multimap(const multimap& x);
    multimap(multimap&& x);
    explicit multimap(const Allocator&);
    multimap(const multimap&, const Allocator&);
    multimap(multimap&&, const Allocator&);
    multimap(initializer_list<value_type>,
      const Compare& = Compare(),
      const Allocator& = Allocator());
    template<class InputIt>
      multimap(InputIt first, InputIt last, const Allocator& a)
        : multimap(first, last, Compare(), a) { }
    multimap(initializer_list<value_type> il, const Allocator& a)
      : multimap(il, Compare(), a) { }
    ~multimap();
    multimap& operator=(const multimap& x);
    multimap& operator=(multimap&& x)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_move_assignable_v<Compare>);
    multimap& operator=(initializer_list<value_type>);
    allocator_type get_allocator() const noexcept;

    // 迭代器
    iterator               begin() noexcept;
    const_iterator         begin() const noexcept;
    iterator               end() noexcept;
    const_iterator         end() const noexcept;

    reverse_iterator       rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator       rend() noexcept;
    const_reverse_iterator rend() const noexcept;

    const_iterator         cbegin() const noexcept;
    const_iterator         cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // 容量
    [[nodiscard]] bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    // 修改器
    template<class... Args> iterator emplace(Args&&... args);
    template<class... Args> iterator emplace_hint(const_iterator position, Args&&... args);
    iterator insert(const value_type& x);
    iterator insert(value_type&& x);
    template<class P> iterator insert(P&& x);
    iterator insert(const_iterator position, const value_type& x);
    iterator insert(const_iterator position, value_type&& x);
    template<class P> iterator insert(const_iterator position, P&& x);
    template<class InputIt>
      void insert(InputIt first, InputIt last);
    void insert(initializer_list<value_type>);

    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    template<class K> node_type extract(K&& x);
    iterator insert(node_type&& nh);
    iterator insert(const_iterator hint, node_type&& nh);

    iterator  erase(iterator position);
    iterator  erase(const_iterator position);
    size_type erase(const key_type& x);
    template<class K> size_type erase(K&& x);
    iterator  erase(const_iterator first, const_iterator last);
    void      swap(multimap&)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_swappable_v<Compare>);
    void      clear() noexcept;

    template<class C2>
      void merge(multimap<Key, T, C2, Allocator>& source);
    template<class C2>
      void merge(multimap<Key, T, C2, Allocator>&& source);
    template<class C2>
      void merge(map<Key, T, C2, Allocator>& source);
    template<class C2>
      void merge(map<Key, T, C2, Allocator>&& source);

    // 观察器
    key_compare key_comp() const;
    value_compare value_comp() const;

    // map 操作
    iterator       find(const key_type& x);
    const_iterator find(const key_type& x) const;
    template<class K> iterator       find(const K& x);
    template<class K> const_iterator find(const K& x) const;

    size_type      count(const key_type& x) const;
    template<class K> size_type count(const K& x) const;

    bool           contains(const key_type& x) const;
    template<class K> bool contains(const K& x) const;

    iterator       lower_bound(const key_type& x);
    const_iterator lower_bound(const key_type& x) const;
    template<class K> iterator       lower_bound(const K& x);
    template<class K> const_iterator lower_bound(const K& x) const;

    iterator       upper_bound(const key_type& x);
    const_iterator upper_bound(const key_type& x) const;
    template<class K> iterator       upper_bound(const K& x);
    template<class K> const_iterator upper_bound(const K& x) const;

    pair<iterator, iterator>               equal_range(const key_type& x);
    pair<const_iterator, const_iterator>   equal_range(const key_type& x) const;
    template<class K>
      pair<iterator, iterator>             equal_range(const K& x);
    template<class K>
      pair<const_iterator, const_iterator> equal_range(const K& x) const;
  };

  template<class InputIt, class Compare = less</*iter-key-type*/<InputIt>>,
           class Allocator = allocator</*iter-to-alloc-type*/<InputIt>>>
    multimap(InputIt, InputIt, Compare = Compare(), Allocator = Allocator())
      -> multimap</*iter-key-type*/<InputIt>, /*iter-mapped-type*/<InputIt>,
                  Compare, Allocator>;

  template<class Key, class T, class Compare = less<Key>,
           class Allocator = allocator<pair<const Key, T>>>
    multimap(initializer_list<pair<Key, T>>, Compare = Compare(), Allocator = Allocator())
      -> multimap<Key, T, Compare, Allocator>;

  template<class InputIt, class Allocator>
    multimap(InputIt, InputIt, Allocator)
      -> multimap</*iter-key-type*/<InputIt>, /*iter-mapped-type*/<InputIt>,
                  less</*iter-key-type*/<InputIt>>, Allocator>;

  template<class Key, class T, class Allocator>
    multimap(initializer_list<pair<Key, T>>, Allocator)
      -> multimap<Key, T, less<Key>, Allocator>;

  // 交换
  template<class Key, class T, class Compare, class Allocator>
    void swap(multimap<Key, T, Compare, Allocator>& x,
              multimap<Key, T, Compare, Allocator>& y)
      noexcept(noexcept(x.swap(y)));
}


标准库头文件 <memory>

< cpp‎ | header

此头文件是动态内存管理库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持

类
指针特征
pointer_traits
(C++11)
 提供关于指针式类型的信息
(类模板)
垃圾收集器支持
pointer_safety
(C++11)(C++23 中移除)
 列出指针安全模式
(枚举)
分配器
allocator
 默认的分配器
(类模板)
allocator_traits
(C++11)
 提供关于分配器类型的信息
(类模板)
allocation_result
(C++23)
 记录由 allocate_at_least 分配的存储的地址与实际大小
(类模板)
allocator_arg_t
(C++11)
 标签类型，用于选择具分配器的构造函数重载
(类)
uses_allocator
(C++11)
 检查指定的类型是否支持使用分配器的构造
(类模板)
未初始化存储
raw_storage_iterator
(C++17 中弃用)(C++20 中移除)
 允许标准算法存储结果于未初始化内存的迭代器
(类模板)
智能指针
unique_ptr
(C++11)
 拥有独有对象所有权语义的智能指针
(类模板)
shared_ptr
(C++11)
 拥有共享对象所有权语义的智能指针
(类模板)
weak_ptr
(C++11)
 到 std::shared_ptr 所管理对象的弱引用
(类模板)
auto_ptr
(C++17 中移除)
 拥有严格对象所有权语义的智能指针
(类模板)
辅助类
std::atomic<std::shared_ptr>
(C++20)
 原子共享指针
(类模板特化)
std::atomic<std::weak_ptr>
(C++20)
 原子弱指针
(类模板特化)
owner_less
(C++11)
 提供基于所有者的，共享指针和弱指针的混合类型的排序
(类模板)
enable_shared_from_this
(C++11)
 允许对象创建指代自身的 shared_ptr
(类模板)
bad_weak_ptr
(C++11)
 访问指向已销毁对象的 weak_ptr 时抛出的异常
(类)
default_delete
(C++11)
 unique_ptr 的默认删除器
(类模板)
std::hash<std::unique_ptr>
(C++11)
 std::unique_ptr 的散列支持
(类模板特化)
std::hash<std::shared_ptr>
(C++11)
 std::shared_ptr 的散列支持
(类模板特化)
智能指针适配器
out_ptr_t
(C++23)
 与外来指针设置器交互，并在析构时重设智能指针
(类模板)
inout_ptr_t
(C++23)
 与外来指针设置器交互，从智能指针获得初始指针值，并在析构时重设它
(类模板)
前置声明
定义于头文件 <functional>
hash
(C++11)
 散列函数对象
(类模板)
定义于头文件 <atomic>
atomic
(C++11)
 atomic 类模板及其针对布尔、整型和指针类型的特化
(类模板)

常量
allocator_arg
(C++11)
 用于选择具分配器的构造函数的 std::allocator_arg_t 对象
(常量)

函数
分配器
allocate_at_least
(C++23)
 经由分配器分配至少与请求的大小一样大的存储
(函数模板)
杂项
to_address
(C++20)
 从指针式类型获得裸指针
(函数模板)
addressof
(C++11)
 获得对象的实际地址，即使其重载了 & 运算符
(函数模板)
align
(C++11)
 对齐缓冲区中的指针
(函数)
assume_aligned
(C++20)
 告知编译器指针已对齐
(函数模板)
垃圾收集器支持
declare_reachable
(C++11)(C++23 中移除)
 声明一个对象不能被回收
(函数)
undeclare_reachable
(C++11)(C++23 中移除)
 声明一个对象可以被回收
(函数模板)
declare_no_pointers
(C++11)(C++23 中移除)
 声明该内存区域不含可追踪指针
(函数)
undeclare_no_pointers
(C++11)(C++23 中移除)
 取消 std::declare_no_pointers 的效果
(函数)
get_pointer_safety
(C++11)(C++23 中移除)
 返回当前的指针安全模式
(函数)
未初始化存储
uninitialized_copy
 将范围内的对象复制到未初始化的内存区域
(函数模板)
uninitialized_copy_n
(C++11)
 将指定数量的对象复制到未初始化的内存区域
(函数模板)
uninitialized_fill
 复制一个对象到以范围定义的未初始化内存区域
(函数模板)
uninitialized_fill_n
 复制一个对象到以起点和计数定义的未初始化内存区域
(函数模板)
uninitialized_move
(C++17)
 移动一个范围的对象到未初始化的内存区域
(函数模板)
uninitialized_move_n
(C++17)
 移动一定数量对象到未初始化内存区域
(函数模板)
uninitialized_default_construct
(C++17)
 在范围所定义的未初始化的内存区域以默认初始化构造对象
(函数模板)
uninitialized_default_construct_n
(C++17)
 在起始和计数所定义的未初始化内存区域用默认初始化构造对象
(函数模板)
uninitialized_value_construct
(C++17)
 在范围所定义的未初始化内存中用值初始化构造对象
(函数模板)
uninitialized_value_construct_n
(C++17)
 在起始和计数所定义的未初始化内存区域以值初始化构造对象
(函数模板)
construct_at
(C++20)
 在给定地址创建对象
(函数模板)
destroy_at
(C++17)
 销毁在给定地址的对象
(函数模板)
destroy
(C++17)
 销毁一个范围中的对象
(函数模板)
destroy_n
(C++17)
 销毁范围中一定数量的对象
(函数模板)
get_temporary_buffer
(C++17 中弃用)(C++20 中移除)
 获得未初始化存储
(函数模板)
return_temporary_buffer
(C++17 中弃用)(C++20 中移除)
 释放未初始化存储
(函数模板)
智能指针非成员操作
make_uniquemake_unique_for_overwrite
(C++14)(C++20)
 创建管理一个新对象的独占指针
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20)
 与另一个 unique_ptr 或 nullptr 进行比较
(函数模板)
make_sharedmake_shared_for_overwrite
(C++20)
 创建管理一个新对象的共享指针
(函数模板)
allocate_sharedallocate_shared_for_overwrite
(C++20)
 创建管理一个用分配器分配的新对象的共享指针
(函数模板)
static_pointer_castdynamic_pointer_castconst_pointer_castreinterpret_pointer_cast
(C++17)
 应用 static_cast、dynamic_cast、const_cast 或 reinterpret_cast 到被存储指针
(函数模板)
get_deleter
 返回指定类型中的删除器，若其拥有
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 与另一个 shared_ptr 或 nullptr 进行比较
(函数模板)
operator<<
 将存储的指针的值输出到输出流
(函数模板)
std::swap(std::unique_ptr)
(C++11)
 特化 std::swap 算法
(函数模板)
std::swap(std::weak_ptr)
(C++11)
 特化 std::swap 算法
(函数模板)
std::swap(std::shared_ptr)
(C++11)
 特化 std::swap 算法
(函数模板)
智能指针适配器创建
out_ptr
(C++23)
 以关联的智能指针和重设参数创建 out_ptr_t
(函数模板)
inout_ptr
(C++23)
 以关联的智能指针和重设参数创建 inout_ptr_t
(函数模板)
std::atomic_is_lock_free(std::shared_ptr)std::atomic_load(std::shared_ptr)std::atomic_load_explicit(std::shared_ptr)std::atomic_store(std::shared_ptr)std::atomic_store_explicit(std::shared_ptr)std::atomic_exchange(std::shared_ptr)std::atomic_exchange_explicit(std::shared_ptr)std::atomic_compare_exchange_weak(std::shared_ptr)std::atomic_compare_exchange_strong(std::shared_ptr)std::atomic_compare_exchange_weak_explicit(std::shared_ptr)std::atomic_compare_exchange_strong_explicit(std::shared_ptr)
(C++20 中弃用)
 特化的原子操作
(函数模板)

仿函数实体
定义于命名空间 std::ranges
未初始化存储
ranges::uninitialized_copy
(C++20)
 复制元素范围到未初始化的内存区域
(niebloid)
ranges::uninitialized_copy_n
(C++20)
 复制一定量元素到未初始化的内存区域
(niebloid)
ranges::uninitialized_fill
(C++20)
 复制一个对象到范围所定义的未初始化的内存区域
(niebloid)
ranges::uninitialized_fill_n
(C++20)
 复制一个对象到起始与计数所定义的未初始化的内存区域
(niebloid)
ranges::uninitialized_move
(C++20)
 移动对象范围到未初始化的内存区域
(niebloid)
ranges::uninitialized_move_n
(C++20)
 移动一定量对象到未初始化的内存区域
(niebloid)
ranges::uninitialized_default_construct
(C++20)
 在范围所定义的未初始化的内存区域以默认初始化构造对象
(niebloid)
ranges::uninitialized_default_construct_n
(C++20)
 在起始与计数所定义的未初始化的内存区域以默认初始化构造对象
(niebloid)
ranges::uninitialized_value_construct
(C++20)
 在范围所定义的未初始化的内存区域以值初始化构造对象
(niebloid)
ranges::uninitialized_value_construct_n
(C++20)
 在起始与计数所定义的未初始化的内存区域以值初始化构造对象
(niebloid)
ranges::construct_at
(C++20)
 在给定地址创建对象
(niebloid)
ranges::destroy_at
(C++20)
 销毁位于给定地址的元素
(niebloid)
ranges::destroy
(C++20)
 销毁范围中的元素
(niebloid)
ranges::destroy_n
(C++20)
 销毁范围中一定量的元素
(niebloid)

概要

#include <compare>

namespace std {
  // 指针特征
  template<class Ptr> struct pointer_traits;
  template<class T> struct pointer_traits<T*>;

  // 指针转换
  template<class T>
    constexpr T* to_address(T* p) noexcept;
  template<class Ptr>
    constexpr auto to_address(const Ptr& p) noexcept;

  // 指针对齐
  void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
  template<size_t N, class T>
    [[nodiscard]] constexpr T* assume_aligned(T* ptr);

  // 分配器参数标签
  struct allocator_arg_t { explicit allocator_arg_t() = default; };
  inline constexpr allocator_arg_t allocator_arg{};

  // uses_allocator
  template<class T, class Alloc> struct uses_allocator;

  // uses_allocator
  template<class T, class Alloc>
    inline constexpr bool uses_allocator_v = uses_allocator<T, Alloc>::value;

  // 使用分配器构造
  template<class T, class Alloc, class... Args>
    constexpr auto uses_allocator_construction_args(const Alloc& alloc,
                                                    Args&&... args) noexcept;
  template<class T, class Alloc, class Tuple1, class Tuple2>
    constexpr auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t,
                                                    Tuple1&& x, Tuple2&& y) noexcept;
  template<class T, class Alloc>
    constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept;
  template<class T, class Alloc, class U, class V>
    constexpr auto uses_allocator_construction_args(const Alloc& alloc,
                                                    U&& u, V&& v) noexcept;
  template<class T, class Alloc, class U, class V>
    constexpr auto uses_allocator_construction_args(const Alloc& alloc,
                                                    const pair<U, V>& pr) noexcept;
  template<class T, class Alloc, class U, class V>
    constexpr auto uses_allocator_construction_args(const Alloc& alloc,
                                                    pair<U, V>&& pr) noexcept;
  template<class T, class Alloc, class... Args>
    constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args);
  template<class T, class Alloc, class... Args>
    constexpr T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc,
                                                         Args&&... args);

  // 分配器特征
  template<class Alloc> struct allocator_traits;

  template<class Pointer>
  struct allocation_result {
    Pointer ptr;
    size_t count;
  };

  template<class Allocator>
    [[nodiscard]] constexpr allocation_result<typename allocator_traits<Allocator>::pointer>
      allocate_at_least(Allocator& a, size_t n);

  // 默认分配器
  template<class T> class allocator;
  template<class T, class U>
    constexpr bool operator==(const allocator<T>&, const allocator<U>&) noexcept;

  // addressof
  template<class T>
    constexpr T* addressof(T& r) noexcept;
  template<class T>
    const T* addressof(const T&&) = delete;

  // 特化的算法
  // 特殊内存概念
  template<class I>
    concept no-throw-input-iterator = /* 见描述 */;    // 仅用于阐释
  template<class I>
    concept no-throw-forward-iterator = /* 见描述 */;  // 仅用于阐释
  template<class S, class I>
    concept no-throw-sentinel-for = /* 见描述 */;      // 仅用于阐释
  template<class R>
    concept no-throw-input-range = /* 见描述 */;       // 仅用于阐释
  template<class R>
    concept no-throw-forward-range = /* 见描述 */;     // 仅用于阐释

  template<class NoThrowForwardIt>
    void uninitialized_default_construct(NoThrowForwardIt first,
                                         NoThrowForwardIt last);
  template<class ExecutionPolicy, class NoThrowForwardIt>
    void uninitialized_default_construct(ExecutionPolicy&& exec,
                                         NoThrowForwardIt first,
                                         NoThrowForwardIt last);
  template<class NoThrowForwardIt, class Size>
    NoThrowForwardIt
      uninitialized_default_construct_n(NoThrowForwardIt first, Size n);
  template<class ExecutionPolicy, class NoThrowForwardIt, class Size>
    NoThrowForwardIt
      uninitialized_default_construct_n(ExecutionPolicy&& exec,
                                        NoThrowForwardIt first, Size n);

  namespace ranges {
    template<no-throw-forward-iterator I, no-throw-sentinel-for<I> S>
      requires default_initializable<iter_value_t<I>>
        I uninitialized_default_construct(I first, S last);
    template<no-throw-forward-range R>
      requires default_initializable<range_value_t<R>>
        borrowed_iterator_t<R> uninitialized_default_construct(R&& r);

    template<no-throw-forward-iterator I>
      requires default_initializable<iter_value_t<I>>
        I uninitialized_default_construct_n(I first, iter_difference_t<I> n);
  }

  template<class NoThrowForwardIterator>
    void uninitialized_value_construct(NoThrowForwardIterator first,
                                       NoThrowForwardIterator last);
  template<class ExecutionPolicy, class NoThrowForwardIt>
    void uninitialized_value_construct(ExecutionPolicy&& exec,
                                       NoThrowForwardIt first,
                                       NoThrowForwardIt last);
  template<class NoThrowForwardIt, class Size>
    NoThrowForwardIt
      uninitialized_value_construct_n(NoThrowForwardIt first, Size n);
  template<class ExecutionPolicy, class NoThrowForwardIt, class Size>
    NoThrowForwardIt
      uninitialized_value_construct_n(ExecutionPolicy&& exec,
                                      NoThrowForwardIt first, Size n);

  namespace ranges {
    template<no-throw-forward-iterator I, no-throw-sentinel-for<I> S>
      requires default_initializable<iter_value_t<I>>
        I uninitialized_value_construct(I first, S last);
    template<no-throw-forward-range R>
      requires default_initializable<range_value_t<R>>
        borrowed_iterator_t<R> uninitialized_value_construct(R&& r);

    template<no-throw-forward-iterator I>
      requires default_initializable<iter_value_t<I>>
        I uninitialized_value_construct_n(I first, iter_difference_t<I> n);
  }

  template<class InputIt, class NoThrowForwardIt>
    NoThrowForwardIt uninitialized_copy(InputIt first, InputIt last,
                                        NoThrowForwardIt result);
  template<class ExecutionPolicy, class ForwardIt, class NoThrowForwardIt>
    NoThrowForwardIt uninitialized_copy(ExecutionPolicy&& exec,
                                        ForwardIt first, ForwardIt last,
                                        NoThrowForwardIt result);
  template<class InputIt, class Size, class NoThrowForwardIt>
    NoThrowForwardIt uninitialized_copy_n(InputIt first, Size n,
                                          NoThrowForwardIt result);
  template<class ExecutionPolicy, class ForwardIt, class Size,
           class NoThrowForwardIt>
    NoThrowForwardIt uninitialized_copy_n(ExecutionPolicy&& exec,
                                          ForwardIt first, Size n,
                                          NoThrowForwardIt result);

  namespace ranges {
    template<class I, class O>
      using uninitialized_copy_result = in_out_result<I, O>;
    template<input_iterator I, sentinel_for<I> S1,
             no-throw-forward-iterator O, no-throw-sentinel-for<O> S2>
      requires constructible_from<iter_value_t<O>, iter_reference_t<I>>
        uninitialized_copy_result<I, O>
          uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast);
    template<input_range IR, no-throw-forward-range OR>
      requires constructible_from<range_value_t<OR>, range_reference_t<IR>>
        uninitialized_copy_result<borrowed_iterator_t<IR>, borrowed_iterator_t<OR>>
          uninitialized_copy(IR&& in_range, OR&& out_range);

    template<class I, class O>
      using uninitialized_copy_n_result = in_out_result<I, O>;
    template<input_iterator I, no-throw-forward-iterator O, no-throw-sentinel-for<O> S>
      requires constructible_from<iter_value_t<O>, iter_reference_t<I>>
        uninitialized_copy_n_result<I, O>
          uninitialized_copy_n(I ifirst, iter_difference_t<I> n, O ofirst, S olast);
  }

  template<class InputIt, class NoThrowForwardIt>
    NoThrowForwardIt uninitialized_move(InputIt first, InputIt last,
                                        NoThrowForwardIt result);
  template<class ExecutionPolicy, class ForwardIt, class NoThrowForwardIt>
    NoThrowForwardIt uninitialized_move(ExecutionPolicy&& exec,
                                        ForwardIt first, ForwardIt last,
                                        NoThrowForwardIt result);
  template<class InputIt, class Size, class NoThrowForwardIt>
    pair<InputIt, NoThrowForwardIt>
      uninitialized_move_n(InputIt first, Size n, NoThrowForwardIt result);
  template<class ExecutionPolicy, class ForwardIt, class Size,
           class NoThrowForwardIt>
    pair<ForwardIt, NoThrowForwardIt>
      uninitialized_move_n(ExecutionPolicy&& exec,
                           ForwardIt first, Size n, NoThrowForwardIt result);

  namespace ranges {
    template<class I, class O>
      using uninitialized_move_result = in_out_result<I, O>;
    template<input_iterator I, sentinel_for<I> S1,
             no-throw-forward-iterator O, no-throw-sentinel-for<O> S2>
      requires constructible_from<iter_value_t<O>, iter_rvalue_reference_t<I>>
        uninitialized_move_result<I, O>
          uninitialized_move(I ifirst, S1 ilast, O ofirst, S2 olast);
    template<input_range IR, no-throw-forward-range OR>
      requires constructible_from<range_value_t<OR>, range_rvalue_reference_t<IR>>
        uninitialized_move_result<borrowed_iterator_t<IR>, borrowed_iterator_t<OR>>
          uninitialized_move(IR&& in_range, OR&& out_range);

    template<class I, class O>
      using uninitialized_move_n_result = in_out_result<I, O>;
    template<input_iterator I,
             no-throw-forward-iterator O, no-throw-sentinel-for<O> S>
      requires constructible_from<iter_value_t<O>, iter_rvalue_reference_t<I>>
        uninitialized_move_n_result<I, O>
          uninitialized_move_n(I ifirst, iter_difference_t<I> n, O ofirst, S olast);
  }

  template<class NoThrowForwardIt, class T>
    void uninitialized_fill(NoThrowForwardIt first, NoThrowForwardIt last,
                            const T& x);
  template<class ExecutionPolicy, class NoThrowForwardIt, class T>
    void uninitialized_fill(ExecutionPolicy&& exec,
                            NoThrowForwardIt first, NoThrowForwardIt last,
                            const T& x);
  template<class NoThrowForwardIt, class Size, class T>
    NoThrowForwardIt
      uninitialized_fill_n(NoThrowForwardIt first, Size n, const T& x);
  template<class ExecutionPolicy, class NoThrowForwardIt, class Size, class T>
    NoThrowForwardIt
      uninitialized_fill_n(ExecutionPolicy&& exec,
                           NoThrowForwardIt first, Size n, const T& x);

  namespace ranges {
    template<no-throw-forward-iterator I, no-throw-sentinel-for<I> S, class T>
      requires constructible_from<iter_value_t<I>, const T&>
        I uninitialized_fill(I first, S last, const T& x);
    template<no-throw-forward-range R, class T>
      requires constructible_from<range_value_t<R>, const T&>
        borrowed_iterator_t<R> uninitialized_fill(R&& r, const T& x);

    template<no-throw-forward-iterator I, class T>
      requires constructible_from<iter_value_t<I>, const T&>
        I uninitialized_fill_n(I first, iter_difference_t<I> n, const T& x);
  }

  // construct_at
  template<class T, class... Args>
    constexpr T* construct_at(T* location, Args&&... args);

  namespace ranges {
    template<class T, class... Args>
      constexpr T* construct_at(T* location, Args&&... args);
  }

  // destroy
  template<class T>
    constexpr void destroy_at(T* location);
  template<class NoThrowForwardIt>
    constexpr void destroy(NoThrowForwardIt first, NoThrowForwardIt last);
  template<class ExecutionPolicy, class NoThrowForwardIt>
    void destroy(ExecutionPolicy&& exec,
                 NoThrowForwardIt first, NoThrowForwardIt last);
  template<class NoThrowForwardIt, class Size>
    constexpr NoThrowForwardIt destroy_n(NoThrowForwardIt first, Size n);
  template<class ExecutionPolicy, class NoThrowForwardIt, class Size>
    NoThrowForwardIt destroy_n(ExecutionPolicy&& exec,
                               NoThrowForwardIt first, Size n);

  namespace ranges {
    template<destructible T>
      constexpr void destroy_at(T* location) noexcept;

    template<no-throw-input-iterator I, no-throw-sentinel-for<I> S>
      requires destructible<iter_value_t<I>>
        constexpr I destroy(I first, S last) noexcept;
    template<no-throw-input-range R>
      requires destructible<range_value_t<R>>
        constexpr borrowed_iterator_t<R> destroy(R&& r) noexcept;

    template<no-throw-input-iterator I>
      requires destructible<iter_value_t<I>>
        constexpr I destroy_n(I first, iter_difference_t<I> n) noexcept;
  }

  // 类模板 unique_ptr
  template<class T> struct default_delete;
  template<class T> struct default_delete<T[]>;
  template<class T, class D = default_delete<T>> class unique_ptr;
  template<class T, class D> class unique_ptr<T[], D>;

  template<class T, class... Args>
    unique_ptr<T> make_unique(Args&&... args);                                  // T 非数组
  template<class T>
    unique_ptr<T> make_unique(size_t n);                                        // T 为 U[]
  template<class T, class... Args>
    /* 未指明 */ make_unique(Args&&...) = delete;                                // T 为 U[N]

  template<class T>
    unique_ptr<T> make_unique_for_overwrite();                                  // T 非数组
  template<class T>
    unique_ptr<T> make_unique_for_overwrite(size_t n);                          // T 为 U[]
  template<class T, class... Args>
    /* 未指明 */ make_unique_for_overwrite(Args&&...) = delete;                  // T 为 U[N]

  template<class T, class D>
    void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y) noexcept;

  template<class T1, class D1, class T2, class D2>
    bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template<class T1, class D1, class T2, class D2>
    bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template<class T1, class D1, class T2, class D2>
    bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template<class T1, class D1, class T2, class D2>
    bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template<class T1, class D1, class T2, class D2>
    bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template<class T1, class D1, class T2, class D2>
    requires three_way_comparable_with<typename unique_ptr<T1, D1>::pointer,
                                       typename unique_ptr<T2, D2>::pointer>
    compare_three_way_result_t<typename unique_ptr<T1, D1>::pointer,
                               typename unique_ptr<T2, D2>::pointer>
      operator<=>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);

  template<class T, class D>
    bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept;
  template<class T, class D>
    bool operator<(const unique_ptr<T, D>& x, nullptr_t);
  template<class T, class D>
    bool operator<(nullptr_t, const unique_ptr<T, D>& y);
  template<class T, class D>
    bool operator>(const unique_ptr<T, D>& x, nullptr_t);
  template<class T, class D>
    bool operator>(nullptr_t, const unique_ptr<T, D>& y);
  template<class T, class D>
    bool operator<=(const unique_ptr<T, D>& x, nullptr_t);
  template<class T, class D>
    bool operator<=(nullptr_t, const unique_ptr<T, D>& y);
  template<class T, class D>
    bool operator>=(const unique_ptr<T, D>& x, nullptr_t);
  template<class T, class D>
    bool operator>=(nullptr_t, const unique_ptr<T, D>& y);
  template<class T, class D>
    requires three_way_comparable<typename unique_ptr<T, D>::pointer>
    compare_three_way_result_t<typename unique_ptr<T, D>::pointer>
      operator<=>(const unique_ptr<T, D>& x, nullptr_t);

  template<class E, class T, class Y, class D>
    basic_ostream<E, T>& operator<<(basic_ostream<E, T>& os, const unique_ptr<Y, D>& p);

  // 类 bad_weak_ptr
  class bad_weak_ptr;

  // 类模板 shared_ptr
  template<class T> class shared_ptr;

  // shared_ptr 创建
  template<class T, class... Args>
    shared_ptr<T> make_shared(Args&&... args);                                  // T 非数组
  template<class T, class A, class... Args>
    shared_ptr<T> allocate_shared(const A& a, Args&&... args);                  // T 非数组

  template<class T>
    shared_ptr<T> make_shared(size_t N);                                        // T 为 U[]
  template<class T, class A>
    shared_ptr<T> allocate_shared(const A& a, size_t N);                        // T 为 U[]

  template<class T>
    shared_ptr<T> make_shared();                                                // T 为 U[N]
  template<class T, class A>
    shared_ptr<T> allocate_shared(const A& a);                                  // T 为 U[N]

  template<class T>
    shared_ptr<T> make_shared(size_t N, const remove_extent_t<T>& u);           // T 为 U[]
  template<class T, class A>
    shared_ptr<T> allocate_shared(const A& a, size_t N,
                                  const remove_extent_t<T>& u);                 // T 为 U[]

  template<class T>
    shared_ptr<T> make_shared(const remove_extent_t<T>& u);                     // T 为 U[N]
  template<class T, class A>
    shared_ptr<T> allocate_shared(const A& a, const remove_extent_t<T>& u);     // T 为 U[N]

  template<class T>
    shared_ptr<T> make_shared_for_overwrite();                                  // T 非 U[]
  template<class T, class A>
    shared_ptr<T> allocate_shared_for_overwrite(const A& a);                    // T 非 U[]

  template<class T>
    shared_ptr<T> make_shared_for_overwrite(size_t N);                          // T 为 U[]
  template<class T, class A>
    shared_ptr<T> allocate_shared_for_overwrite(const A& a, size_t N);          // T 为 U[]

  // shared_ptr 比较
  template<class T, class U>
    bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;
  template<class T, class U>
    strong_ordering operator<=>(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;

  template<class T>
    bool operator==(const shared_ptr<T>& x, nullptr_t) noexcept;
  template<class T>
    strong_ordering operator<=>(const shared_ptr<T>& x, nullptr_t) noexcept;

  // shared_ptr 特化算法
  template<class T>
    void swap(shared_ptr<T>& a, shared_ptr<T>& b) noexcept;

  // shared_ptr 转型
  template<class T, class U>
    shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r) noexcept;
  template<class T, class U>
    shared_ptr<T> static_pointer_cast(shared_ptr<U>&& r) noexcept;
  template<class T, class U>
    shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& r) noexcept;
  template<class T, class U>
    shared_ptr<T> dynamic_pointer_cast(shared_ptr<U>&& r) noexcept;
  template<class T, class U>
    shared_ptr<T> const_pointer_cast(const shared_ptr<U>& r) noexcept;
  template<class T, class U>
    shared_ptr<T> const_pointer_cast(shared_ptr<U>&& r) noexcept;
  template<class T, class U>
    shared_ptr<T> reinterpret_pointer_cast(const shared_ptr<U>& r) noexcept;
  template<class T, class U>
    shared_ptr<T> reinterpret_pointer_cast(shared_ptr<U>&& r) noexcept;

  // shared_ptr get_deleter
  template<class D, class T>
    D* get_deleter(const shared_ptr<T>& p) noexcept;

  // shared_ptr I/O
  template<class E, class T, class Y>
    basic_ostream<E, T>& operator<<(basic_ostream<E, T>& os, const shared_ptr<Y>& p);

  // 类模板 weak_ptr
  template<class T> class weak_ptr;

  // weak_ptr 特化算法
  template<class T> void swap(weak_ptr<T>& a, weak_ptr<T>& b) noexcept;

  // 类模板 owner_less
  template<class T = void> struct owner_less;

  // 类模板 enable_shared_from_this
  template<class T> class enable_shared_from_this;

  // 散列支持
  template<class T> struct hash;
  template<class T, class D> struct hash<unique_ptr<T, D>>;
  template<class T> struct hash<shared_ptr<T>>;

  // 原子智能指针
  template<class T> struct atomic;
  template<class T> struct atomic<shared_ptr<T>>;
  template<class T> struct atomic<weak_ptr<T>>;

  // 类模板 out_ptr_t
  template<class Smart, class Pointer, class... Args>
    class out_ptr_t;

  // 函数模板 out_ptr
  template<class Pointer = void, class Smart, class... Args>
    auto out_ptr(Smart& s, Args&&... args);

  // 类模板 inout_ptr_t
  template<class Smart, class Pointer, class... Args>
    class inout_ptr_t;

  // 函数模板 inout_ptr
  template<class Pointer = void, class Smart, class... Args>
    auto inout_ptr(Smart& s, Args&&... args);
}

// 弃用
namespace std {
  template<class T>
    bool atomic_is_lock_free(const shared_ptr<T>* p);

  template<class T>
    shared_ptr<T> atomic_load(const shared_ptr<T>* p);
  template<class T>
    shared_ptr<T> atomic_load_explicit(const shared_ptr<T>* p, memory_order mo);

  template<class T>
    void atomic_store(shared_ptr<T>* p, shared_ptr<T> r);
  template<class T>
    void atomic_store_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);

  template<class T>
    shared_ptr<T> atomic_exchange(shared_ptr<T>* p, shared_ptr<T> r);
  template<class T>
    shared_ptr<T> atomic_exchange_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);

  template<class T>
    bool atomic_compare_exchange_weak(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);
  template<class T>
    bool atomic_compare_exchange_strong(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);
  template<class T>
    bool atomic_compare_exchange_weak_explicit(
      shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w,
      memory_order success, memory_order failure);
  template<class T>
    bool atomic_compare_exchange_strong_explicit(
      shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w,
      memory_order success, memory_order failure);
}

辅助概念

template<class I>
concept no-throw-input-iterator = // 仅用于阐释
  input_iterator<I> &&
  is_lvalue_reference_v<iter_reference_t<I>> &&
  same_as<remove_cvref_t<iter_reference_t<I>>, iter_value_t<I>>;

template<class S, class I>
concept no-throw-sentinel-for = sentinel_for<S, I>; // 仅用于阐释

template<class R>
concept no-throw-input-range = // 仅用于阐释
  ranges::range<R> &&
  no-throw-input-iterator<ranges::iterator_t<R>> &&
  no-throw-sentinel-for<ranges::sentinel_t<R>, ranges::iterator_t<R>>;

template<class I>
concept no-throw-forward-iterator = // 仅用于阐释
  no-throw-input-iterator<I> &&
  forward_iterator<I> &&
  no-throw-sentinel-for<I, I>;

template<class R>
concept no-throw-forward-range = // 仅用于阐释
  no-throw-input-range<R> &&
  no-throw-forward-iterator<ranges::iterator_t<R>>;

注意：这些名字仅用于阐释，它们不是接口的一部分。

类模板 std::pointer_traits

namespace std {
  template<class Ptr> struct pointer_traits {
    using pointer         = Ptr;
    using element_type    = /* 见描述 */;
    using difference_type = /* 见描述 */;

    template<class U> using rebind = /* 见描述 */;

    static pointer pointer_to(/* 见描述 */ r);
  };

  template<class T> struct pointer_traits<T*> {
    using pointer         = T*;
    using element_type    = T;
    using difference_type = ptrdiff_t;

    template<class U> using rebind = U*;

    static constexpr pointer pointer_to(/* 见描述 */ r) noexcept;
  };
}

类 std::allocator_arg_t

namespace std {
  struct allocator_arg_t { explicit allocator_arg_t() = default; };
  inline constexpr allocator_arg_t allocator_arg{};
}

类模板 std::allocator_traits

namespace std {
  template<class Alloc> struct allocator_traits {
    using allocator_type     = Alloc;

    using value_type         = typename Alloc::value_type;

    using pointer            = /* 见描述 */;
    using const_pointer      = /* 见描述 */;
    using void_pointer       = /* 见描述 */;
    using const_void_pointer = /* 见描述 */;

    using difference_type    = /* 见描述 */;
    using size_type          = /* 见描述 */;

    using propagate_on_container_copy_assignment = /* 见描述 */;
    using propagate_on_container_move_assignment = /* 见描述 */;
    using propagate_on_container_swap            = /* 见描述 */;
    using is_always_equal                        = /* 见描述 */;

    template<class T> using rebind_alloc = /* 见描述 */;
    template<class T> using rebind_traits = allocator_traits<rebind_alloc<T>>;

    [[nodiscard]] static pointer allocate(Alloc& a, size_type n);
    [[nodiscard]] static pointer allocate(Alloc& a, size_type n,
                                          const_void_pointer hint);

    static void deallocate(Alloc& a, pointer p, size_type n);

    template<class T, class... Args>
      static void construct(Alloc& a, T* p, Args&&... args);

    template<class T>
      static void destroy(Alloc& a, T* p);

    static size_type max_size(const Alloc& a) noexcept;

    static Alloc select_on_container_copy_construction(const Alloc& rhs);
  };
}

类模板 std::allocator

namespace std {
  template<class T> class allocator {
   public:
    using value_type                             = T;
    using size_type                              = size_t;
    using difference_type                        = ptrdiff_t;
    using propagate_on_container_move_assignment = true_type;

    constexpr allocator() noexcept;
    constexpr allocator(const allocator&) noexcept;
    template<class U> constexpr allocator(const allocator<U>&) noexcept;
    constexpr ~allocator();
    constexpr allocator& operator=(const allocator&) = default;

    [[nodiscard]] constexpr T* allocate(size_t n);
    [[nodiscard]] constexpr allocation_result<T*> allocate_at_least(size_t n);
    constexpr void deallocate(T* p, size_t n);

    // 弃用
    using is_always_equal = true_type;
  };
}

类模板 std::default_delete

namespace std {
  template<class T> struct default_delete {
    constexpr default_delete() noexcept = default;
    template<class U> default_delete(const default_delete<U>&) noexcept;
    void operator()(T*) const;
  };

  template<class T> struct default_delete<T[]> {
    constexpr default_delete() noexcept = default;
    template<class U> default_delete(const default_delete<U[]>&) noexcept;
    template<class U> void operator()(U* ptr) const;
  };
}

类模板 std::unique_ptr

namespace std {
  template<class T, class D = default_delete<T>> class unique_ptr {
  public:
    using pointer      = /* 见描述 */;
    using element_type = T;
    using deleter_type = D;

    // 构造函数
    constexpr unique_ptr() noexcept;
    explicit unique_ptr(pointer p) noexcept;
    unique_ptr(pointer p, /* 见描述 */ d1) noexcept;
    unique_ptr(pointer p, /* 见描述 */ d2) noexcept;
    unique_ptr(unique_ptr&& u) noexcept;
    constexpr unique_ptr(nullptr_t) noexcept;
    template<class U, class E>
      unique_ptr(unique_ptr<U, E>&& u) noexcept;

    // 析构函数
    ~unique_ptr();

    // 赋值
    unique_ptr& operator=(unique_ptr&& u) noexcept;
    template<class U, class E>
      unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;
    unique_ptr& operator=(nullptr_t) noexcept;

    // 观察器
    add_lvalue_reference_t<T> operator*() const noexcept(/* 见描述 */);
    pointer operator->() const noexcept;
    pointer get() const noexcept;
    deleter_type& get_deleter() noexcept;
    const deleter_type& get_deleter() const noexcept;
    explicit operator bool() const noexcept;

    // 修改器
    pointer release() noexcept;
    void reset(pointer p = pointer()) noexcept;
    void swap(unique_ptr& u) noexcept;

    // 禁用从左值复制
    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;
  };

  template<class T, class D> class unique_ptr<T[], D> {
  public:
    using pointer      = /* 见描述 */;
    using element_type = T;
    using deleter_type = D;

    // 构造函数
    constexpr unique_ptr() noexcept;
    template<class U> explicit unique_ptr(U p) noexcept;
    template<class U> unique_ptr(U p, /* 见描述 */ d) noexcept;
    template<class U> unique_ptr(U p, /* 见描述 */ d) noexcept;
    unique_ptr(unique_ptr&& u) noexcept;
    template<class U, class E>
      unique_ptr(unique_ptr<U, E>&& u) noexcept;
    constexpr unique_ptr(nullptr_t) noexcept;

    // 析构函数
    ~unique_ptr();

    // 赋值
    unique_ptr& operator=(unique_ptr&& u) noexcept;
    template<class U, class E>
      unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;
    unique_ptr& operator=(nullptr_t) noexcept;

    // 观察器
    T& operator[](size_t i) const;
    pointer get() const noexcept;
    deleter_type& get_deleter() noexcept;
    const deleter_type& get_deleter() const noexcept;
    explicit operator bool() const noexcept;

    // 修改器
    pointer release() noexcept;
    template<class U> void reset(U p) noexcept;
    void reset(nullptr_t = nullptr) noexcept;
    void swap(unique_ptr& u) noexcept;

    // 禁用从左值复制
    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;
  };
}

类 std::bad_weak_ptr

namespace std {
  class bad_weak_ptr : public exception {
  public:
    bad_weak_ptr() noexcept;
  };
}

类模板 std::shared_ptr

namespace std {
  template<class T> class shared_ptr {
  public:
    using element_type = remove_extent_t<T>;
    using weak_type    = weak_ptr<T>;

    // 构造函数
    constexpr shared_ptr() noexcept;
    constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { }
    template<class Y>
      explicit shared_ptr(Y* p);
    template<class Y, class D>
      shared_ptr(Y* p, D d);
    template<class Y, class D, class A>
      shared_ptr(Y* p, D d, A a);
    template<class D>
      shared_ptr(nullptr_t p, D d);
    template<class D, class A>
      shared_ptr(nullptr_t p, D d, A a);
    template<class Y>
      shared_ptr(const shared_ptr<Y>& r, element_type* p) noexcept;
    template<class Y>
      shared_ptr(shared_ptr<Y>&& r, element_type* p) noexcept;
    shared_ptr(const shared_ptr& r) noexcept;
    template<class Y>
      shared_ptr(const shared_ptr<Y>& r) noexcept;
    shared_ptr(shared_ptr&& r) noexcept;
    template<class Y>
      shared_ptr(shared_ptr<Y>&& r) noexcept;
    template<class Y>
      explicit shared_ptr(const weak_ptr<Y>& r);
    template<class Y, class D>
      shared_ptr(unique_ptr<Y, D>&& r);

    // 析构函数
    ~shared_ptr();

    // 赋值
    shared_ptr& operator=(const shared_ptr& r) noexcept;
    template<class Y>
      shared_ptr& operator=(const shared_ptr<Y>& r) noexcept;
    shared_ptr& operator=(shared_ptr&& r) noexcept;
    template<class Y>
      shared_ptr& operator=(shared_ptr<Y>&& r) noexcept;
    template<class Y, class D>
      shared_ptr& operator=(unique_ptr<Y, D>&& r);

    // 修改器
    void swap(shared_ptr& r) noexcept;
    void reset() noexcept;
    template<class Y>
      void reset(Y* p);
    template<class Y, class D>
      void reset(Y* p, D d);
    template<class Y, class D, class A>
      void reset(Y* p, D d, A a);

    // 观察器
    element_type* get() const noexcept;
    T& operator*() const noexcept;
    T* operator->() const noexcept;
    element_type& operator[](ptrdiff_t i) const;
    long use_count() const noexcept;
    explicit operator bool() const noexcept;
    template<class U>
      bool owner_before(const shared_ptr<U>& b) const noexcept;
    template<class U>
      bool owner_before(const weak_ptr<U>& b) const noexcept;
  };

  template<class T>
    shared_ptr(weak_ptr<T>) -> shared_ptr<T>;
  template<class T, class D>
    shared_ptr(unique_ptr<T, D>) -> shared_ptr<T>;
}

类模板 std::weak_ptr

namespace std {
  template<class T> class weak_ptr {
  public:
    using element_type = remove_extent_t<T>;

    // 构造函数
    constexpr weak_ptr() noexcept;
    template<class Y>
      weak_ptr(const shared_ptr<Y>& r) noexcept;
    weak_ptr(const weak_ptr& r) noexcept;
    template<class Y>
      weak_ptr(const weak_ptr<Y>& r) noexcept;
    weak_ptr(weak_ptr&& r) noexcept;
    template<class Y>
      weak_ptr(weak_ptr<Y>&& r) noexcept;

    // 析构函数
    ~weak_ptr();

    // 赋值
    weak_ptr& operator=(const weak_ptr& r) noexcept;
    template<class Y>
      weak_ptr& operator=(const weak_ptr<Y>& r) noexcept;
    template<class Y>
      weak_ptr& operator=(const shared_ptr<Y>& r) noexcept;
    weak_ptr& operator=(weak_ptr&& r) noexcept;
    template<class Y>
      weak_ptr& operator=(weak_ptr<Y>&& r) noexcept;

    // 修改器
    void swap(weak_ptr& r) noexcept;
    void reset() noexcept;

    // 观察器
    long use_count() const noexcept;
    bool expired() const noexcept;
    shared_ptr<T> lock() const noexcept;
    template<class U>
      bool owner_before(const shared_ptr<U>& b) const noexcept;
    template<class U>
      bool owner_before(const weak_ptr<U>& b) const noexcept;
  };

  template<class T>
    weak_ptr(shared_ptr<T>) -> weak_ptr<T>;
}

类模板 std::owner_less

namespace std {
  template<class T = void> struct owner_less;

  template<class T> struct owner_less<shared_ptr<T>> {
    bool operator()(const shared_ptr<T>&, const shared_ptr<T>&) const noexcept;
    bool operator()(const shared_ptr<T>&, const weak_ptr<T>&) const noexcept;
    bool operator()(const weak_ptr<T>&, const shared_ptr<T>&) const noexcept;
  };

  template<class T> struct owner_less<weak_ptr<T>> {
    bool operator()(const weak_ptr<T>&, const weak_ptr<T>&) const noexcept;
    bool operator()(const shared_ptr<T>&, const weak_ptr<T>&) const noexcept;
    bool operator()(const weak_ptr<T>&, const shared_ptr<T>&) const noexcept;
  };

  template<> struct owner_less<void> {
    template<class T, class U>
      bool operator()(const shared_ptr<T>&, const shared_ptr<U>&) const noexcept;
    template<class T, class U>
      bool operator()(const shared_ptr<T>&, const weak_ptr<U>&) const noexcept;
    template<class T, class U>
      bool operator()(const weak_ptr<T>&, const shared_ptr<U>&) const noexcept;
    template<class T, class U>
      bool operator()(const weak_ptr<T>&, const weak_ptr<U>&) const noexcept;

    using is_transparent = /* 未指明 */;
  };
}

类模板 std::enable_shared_from_this

namespace std {
  template<class T> class enable_shared_from_this {
  protected:
    constexpr enable_shared_from_this() noexcept;
    enable_shared_from_this(const enable_shared_from_this&) noexcept;
    enable_shared_from_this& operator=(const enable_shared_from_this&) noexcept;
    ~enable_shared_from_this();

  public:
    shared_ptr<T> shared_from_this();
    shared_ptr<T const> shared_from_this() const;
    weak_ptr<T> weak_from_this() noexcept;
    weak_ptr<T const> weak_from_this() const noexcept;

  private:
    mutable weak_ptr<T> weak_this;  // 仅用于阐释
  };
}

类模板 std::atomic 对 std::shared_ptr 的特化

namespace std {
  template<class T> struct atomic<shared_ptr<T>> {
    using value_type = shared_ptr<T>;
    static constexpr bool is_always_lock_free = /* 由实现定义 */;

    bool is_lock_free() const noexcept;
    void store(shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
    shared_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept;
    operator shared_ptr<T>() const noexcept;

    shared_ptr<T> exchange(shared_ptr<T> desired,
                           memory_order order = memory_order::seq_cst) noexcept;

    bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired,
                               memory_order success, memory_order failure) noexcept;
    bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired,
                                 memory_order success, memory_order failure) noexcept;

    bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired,
                               memory_order order = memory_order::seq_cst) noexcept;
    bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired,
                                 memory_order order = memory_order::seq_cst) noexcept;

    constexpr atomic() noexcept = default;
    atomic(shared_ptr<T> desired) noexcept;
    atomic(const atomic&) = delete;
    void operator=(const atomic&) = delete;
    void operator=(shared_ptr<T> desired) noexcept;

  private:
    shared_ptr<T> p;            // 仅用于阐释
  };
}

类模板 std::atomic 对 std::weak_ptr 的特化

namespace std {
  template<class T> struct atomic<weak_ptr<T>> {
    using value_type = weak_ptr<T>;
    static constexpr bool is_always_lock_free = /* 由实现定义 */;

    bool is_lock_free() const noexcept;
    void store(weak_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
    weak_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept;
    operator weak_ptr<T>() const noexcept;

    weak_ptr<T> exchange(weak_ptr<T> desired,
                         memory_order order = memory_order::seq_cst) noexcept;

    bool compare_exchange_weak(weak_ptr<T>& expected, weak_ptr<T> desired,
                               memory_order success, memory_order failure) noexcept;
    bool compare_exchange_strong(weak_ptr<T>& expected, weak_ptr<T> desired,
                                 memory_order success, memory_order failure) noexcept;

    bool compare_exchange_weak(weak_ptr<T>& expected, weak_ptr<T> desired,
                               memory_order order = memory_order::seq_cst) noexcept;
    bool compare_exchange_strong(weak_ptr<T>& expected, weak_ptr<T> desired,
                                 memory_order order = memory_order::seq_cst) noexcept;

    constexpr atomic() noexcept = default;
    atomic(weak_ptr<T> desired) noexcept;
    atomic(const atomic&) = delete;
    void operator=(const atomic&) = delete;
    void operator=(weak_ptr<T> desired) noexcept;

  private:
    weak_ptr<T> p;              // 仅用于阐释
  };
}

类模板 std::out_ptr_t

namespace std {
  template<class Smart, class Pointer, class... Args>
  class out_ptr_t {
  public:
    explicit out_ptr_t(Smart&, Args...);
    out_ptr_t(const out_ptr_t&) = delete;

    ~out_ptr_t();

    operator Pointer*() const noexcept;
    operator void**() const noexcept;

  private:
    Smart& s;                   // 仅用于阐释
    tuple<Args...> a;           // 仅用于阐释
    Pointer p;                  // 仅用于阐释
  };
}

类模板 std::in_out_ptr_t

namespace std {
  template<class Smart, class Pointer, class... Args>
  class inout_ptr_t {
  public:
    explicit inout_ptr_t(Smart&, Args...);
    inout_ptr_t(const inout_ptr_t&) = delete;

    ~inout_ptr_t();

    operator Pointer*() const noexcept;
    operator void**() const noexcept;

  private:
    Smart& s;                   // 仅用于阐释
    tuple<Args...> a;           // 仅用于阐释
    Pointer p;                  // 仅用于阐释
  };
}


标准库头文件 <memory_resource>

< cpp‎ | header

此头文件是动态内存管理库的一部分。

类
定义于命名空间 std::pmr
polymorphic_allocator
(C++17)
 以 std::memory_resource 构造，支持基于它的运行时多态的分配器
(类模板)
memory_resource
(C++17)
 一个抽象接口，用于各种封装内存资源的类
(类)
pool_options
(C++17)
 一组池资源的构造函数选项
(类)
synchronized_pool_resource
(C++17)
 线程安全的 std::pmr::memory_resource，用于管理具有不同块大小的池中的分配
(类)
unsynchronized_pool_resource
(C++17)
 线程不安全的 std::pmr::memory_resource，用于管理具有不同块大小的池中的分配
(类)
monotonic_buffer_resource
(C++17)
 一种特殊用途的 std::pmr::memory_resource，仅在资源被销毁时才释放所分配内存
(类)

函数
定义于命名空间 std::pmr
new_delete_resource
(C++17)
 返回一个静态的程序范围 std::pmr::memory_resource，它使用全局 operator new 与 operator delete 分配和解分配内存
(函数)
null_memory_resource
(C++17)
 返回一个不进行任何分配的静态 std::pmr::memory_resource
(函数)
get_default_resource
(C++17)
 获取缺省 std::pmr::memory_resource
(函数)
set_default_resource
(C++17)
 设置缺省 std::pmr::memory_resource
(函数)

概要

namespace std::pmr {
  // 类 memory_resource
  class memory_resource;

  bool operator==(const memory_resource& a, const memory_resource& b) noexcept;

  // 类模板 polymorphic_allocator
  template<class Tp> class polymorphic_allocator;

  template<class T1, class T2>
    bool operator==(const polymorphic_allocator<T1>& a,
                    const polymorphic_allocator<T2>& b) noexcept;

  // 全局内存资源
  memory_resource* new_delete_resource() noexcept;
  memory_resource* null_memory_resource() noexcept;
  memory_resource* set_default_resource(memory_resource* r) noexcept;
  memory_resource* get_default_resource() noexcept;

  // 池资源类
  struct pool_options;
  class synchronized_pool_resource;
  class unsynchronized_pool_resource;
  class monotonic_buffer_resource;
}

类 std::pmr::memory_resource

namespace std::pmr {
  class memory_resource {
    static constexpr size_t max_align = alignof(max_align_t);   // 仅用于阐释

  public:
    memory_resource() = default;
    memory_resource(const memory_resource&) = default;
    virtual ~memory_resource();

    memory_resource& operator=(const memory_resource&) = default;

    [[nodiscard]] void* allocate(size_t bytes, size_t alignment = max_align);
    void deallocate(void* p, size_t bytes, size_t alignment = max_align);

    bool is_equal(const memory_resource& other) const noexcept;

  private:
    virtual void* do_allocate(size_t bytes, size_t alignment) = 0;
    virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0;

    virtual bool do_is_equal(const memory_resource& other) const noexcept = 0;
  };
}

类模板 std::pmr::polymorphic_allocator

namespace std::pmr {
  template<class Tp = byte> class polymorphic_allocator {
    memory_resource* memory_rsrc;       // 仅用于阐释

  public:
    using value_type = Tp;

    // 构造函数
    polymorphic_allocator() noexcept;
    polymorphic_allocator(memory_resource* r);

    polymorphic_allocator(const polymorphic_allocator& other) = default;

    template<class U>
      polymorphic_allocator(const polymorphic_allocator<U>& other) noexcept;

    polymorphic_allocator& operator=(const polymorphic_allocator&) = delete;

    // 成员函数
    [[nodiscard]] Tp* allocate(size_t n);
    void deallocate(Tp* p, size_t n);

    [[nodiscard]] void* allocate_bytes(size_t nbytes,
                                       size_t alignment = alignof(max_align_t));
    void deallocate_bytes(void* p, size_t nbytes, size_t alignment = alignof(max_align_t));
    template<class T> [[nodiscard]] T* allocate_object(size_t n = 1);
    template<class T> void deallocate_object(T* p, size_t n = 1);
    template<class T, class... CtorArgs>
      [[nodiscard]] T* new_object(CtorArgs&&... ctor_args);
    template<class T> void delete_object(T* p);

    template<class T, class... Args>
      void construct(T* p, Args&&... args);

    template<class T>
      void destroy(T* p); // 弃用

    polymorphic_allocator select_on_container_copy_construction() const;

    memory_resource* resource() const;
  };
}

类 std::pmr::pool_options

namespace std::pmr {
  struct pool_options {
    size_t max_blocks_per_chunk = 0;
    size_t largest_required_pool_block = 0;
  };
}

类 std::pmr::synchronized_pool_resource

namespace std::pmr {
  class synchronized_pool_resource : public memory_resource {
  public:
    synchronized_pool_resource(const pool_options& opts, memory_resource* upstream);

    synchronized_pool_resource()
        : synchronized_pool_resource(pool_options(), get_default_resource()) {}
    explicit synchronized_pool_resource(memory_resource* upstream)
        : synchronized_pool_resource(pool_options(), upstream) {}
    explicit synchronized_pool_resource(const pool_options& opts)
        : synchronized_pool_resource(opts, get_default_resource()) {}

    synchronized_pool_resource(const synchronized_pool_resource&) = delete;
    virtual ~synchronized_pool_resource();

    synchronized_pool_resource& operator=(const synchronized_pool_resource&) = delete;

    void release();
    memory_resource* upstream_resource() const;
    pool_options options() const;

  protected:
    void* do_allocate(size_t bytes, size_t alignment) override;
    void do_deallocate(void* p, size_t bytes, size_t alignment) override;

    bool do_is_equal(const memory_resource& other) const noexcept override;
  };
}

类 std::pmr::unsynchronized_pool_resource

namespace std::pmr {
  class unsynchronized_pool_resource : public memory_resource {
  public:
    unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream);

    unsynchronized_pool_resource()
        : unsynchronized_pool_resource(pool_options(), get_default_resource()) {}
    explicit unsynchronized_pool_resource(memory_resource* upstream)
        : unsynchronized_pool_resource(pool_options(), upstream) {}
    explicit unsynchronized_pool_resource(const pool_options& opts)
        : unsynchronized_pool_resource(opts, get_default_resource()) {}

    unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete;
    virtual ~unsynchronized_pool_resource();

    unsynchronized_pool_resource& operator=(const unsynchronized_pool_resource&) = delete;

    void release();
    memory_resource* upstream_resource() const;
    pool_options options() const;

  protected:
    void* do_allocate(size_t bytes, size_t alignment) override;
    void do_deallocate(void* p, size_t bytes, size_t alignment) override;

    bool do_is_equal(const memory_resource& other) const noexcept override;
  };
}

类 std::pmr::monotonic_buffer_resource

namespace std::pmr {
  class monotonic_buffer_resource : public memory_resource {
    memory_resource* upstream_rsrc;     // 仅用于阐释
    void* current_buffer;               // 仅用于阐释
    size_t next_buffer_size;            // 仅用于阐释

  public:
    explicit monotonic_buffer_resource(memory_resource* upstream);
    monotonic_buffer_resource(size_t initial_size, memory_resource* upstream);
    monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream);

    monotonic_buffer_resource()
      : monotonic_buffer_resource(get_default_resource()) {}
    explicit monotonic_buffer_resource(size_t initial_size)
      : monotonic_buffer_resource(initial_size, get_default_resource()) {}
    monotonic_buffer_resource(void* buffer, size_t buffer_size)
      : monotonic_buffer_resource(buffer, buffer_size, get_default_resource()) {}

    monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;

    virtual ~monotonic_buffer_resource();

    monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete;

    void release();
    memory_resource* upstream_resource() const;

  protected:
    void* do_allocate(size_t bytes, size_t alignment) override;
    void do_deallocate(void* p, size_t bytes, size_t alignment) override;

    bool do_is_equal(const memory_resource& other) const noexcept override;
  };
}


标准库头文件 <mutex>

< cpp‎ | header

此头文件是线程支持库的一部分。

类
mutex
(C++11)
 提供基本互斥设施
(类)
timed_mutex
(C++11)
 提供互斥设施，实现有时限锁定
(类)
recursive_mutex
(C++11)
 提供能被同一线程递归锁定的互斥设施
(类)
recursive_timed_mutex
(C++11)
 提供能被同一线程递归锁定的互斥设施，并实现有时限锁定
(类)
lock_guard
(C++11)
 实现严格基于作用域的互斥体所有权包装器
(类模板)
unique_lock
(C++11)
 实现可移动的互斥体所有权包装器
(类模板)
scoped_lock
(C++17)
 用于多个互斥体的免死锁 RAII 封装器
(类模板)
defer_lock_ttry_to_lock_tadopt_lock_t
(C++11)(C++11)(C++11)
 用于指定锁定策略的标签类型
(类)
once_flag
(C++11)
 确保 call_once 只调用函数一次的帮助对象
(类)

常量
defer_locktry_to_lockadopt_lock
(C++11)(C++11)(C++11)
 用于指定锁定策略的标签常量
(常量)

函数
try_lock
(C++11)
 试图通过重复调用 try_lock 获得互斥体的所有权
(函数模板)
lock
(C++11)
 锁定指定的互斥体，若任何一个不可用则阻塞
(函数模板)
call_once
(C++11)
 仅调用函数一次，即使从多个线程调用
(函数模板)
std::swap(std::unique_lock)
(C++11)
 std::swap 对 unique_lock 的特化
(函数模板)

概要

namespace std {
  class mutex;
  class recursive_mutex;
  class timed_mutex;
  class recursive_timed_mutex;

  struct defer_lock_t { explicit defer_lock_t() = default; };
  struct try_to_lock_t { explicit try_to_lock_t() = default; };
  struct adopt_lock_t { explicit adopt_lock_t() = default; };

  inline constexpr defer_lock_t  defer_lock { };
  inline constexpr try_to_lock_t try_to_lock { };
  inline constexpr adopt_lock_t  adopt_lock { };

  template<class Mutex> class lock_guard;
  template<class... MutexTypes> class scoped_lock;
  template<class Mutex> class unique_lock;

  template<class Mutex>
    void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;

  template<class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...);
  template<class L1, class L2, class... L3> void lock(L1&, L2&, L3&...);

  struct once_flag;

  template<class Callable, class... Args>
    void call_once(once_flag& flag, Callable&& func, Args&&... args);
}

类 std::mutex

namespace std {
  class mutex {
  public:
    constexpr mutex() noexcept;
    ~mutex();

    mutex(const mutex&) = delete;
    mutex& operator=(const mutex&) = delete;

    void lock();
    bool try_lock();
    void unlock();

    using native_handle_type = /* 由实现定义 */;
    native_handle_type native_handle();
  };
}

类 std::recursive_mutex

namespace std {
  class recursive_mutex {
  public:
    recursive_mutex();
    ~recursive_mutex();

    recursive_mutex(const recursive_mutex&) = delete;
    recursive_mutex& operator=(const recursive_mutex&) = delete;

    void lock();
    bool try_lock() noexcept;
    void unlock();

    using native_handle_type = /* 由实现定义 */;
    native_handle_type native_handle();
  };
}

类 std::timed_mutex

namespace std {
  class timed_mutex {
  public:
    timed_mutex();
    ~timed_mutex();

    timed_mutex(const timed_mutex&) = delete;
    timed_mutex& operator=(const timed_mutex&) = delete;

    void lock();    // 阻塞
    bool try_lock();
    template<class Rep, class Period>
      bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template<class Clock, class Duration>
      bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    void unlock();

    using native_handle_type = /* 由实现定义 */;
    native_handle_type native_handle();
  };
}

类 std::recursive_timed_mutex

namespace std {
  class recursive_timed_mutex {
  public:
    recursive_timed_mutex();
    ~recursive_timed_mutex();

    recursive_timed_mutex(const recursive_timed_mutex&) = delete;
    recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;

    void lock();    // 阻塞
    bool try_lock() noexcept;
    template<class Rep, class Period>
      bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template<class Clock, class Duration>
      bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    void unlock();

    using native_handle_type = /* 由实现定义 */;
    native_handle_type native_handle();
  };
}

类模板 std::lock_guard

namespace std {
  template<class Mutex>
  class lock_guard {
  public:
    using mutex_type = Mutex;

    explicit lock_guard(mutex_type& m);
    lock_guard(mutex_type& m, adopt_lock_t);
    ~lock_guard();

    lock_guard(const lock_guard&) = delete;
    lock_guard& operator=(const lock_guard&) = delete;

  private:
    mutex_type& pm;             // 仅用于阐释
  };
}

类模板 std::scoped_lock

namespace std {
  template<class... MutexTypes>
  class scoped_lock {
  public:
    using mutex_type = Mutex;   // 若 MutexTypes... 仅由单个类型 Mutex 组成

    explicit scoped_lock(MutexTypes&... m);
    explicit scoped_lock(adopt_lock_t, MutexTypes&... m);
    ~scoped_lock();

    scoped_lock(const scoped_lock&) = delete;
    scoped_lock& operator=(const scoped_lock&) = delete;

  private:
    tuple<MutexTypes&...> pm;   // 仅用于阐释
  };
}

类模板 std::unique_lock

namespace std {
  template<class Mutex>
  class unique_lock {
  public:
    using mutex_type = Mutex;

    // 构造/复制/销毁
    unique_lock() noexcept;
    explicit unique_lock(mutex_type& m);
    unique_lock(mutex_type& m, defer_lock_t) noexcept;
    unique_lock(mutex_type& m, try_to_lock_t);
    unique_lock(mutex_type& m, adopt_lock_t);
    template<class Clock, class Duration>
      unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
    template<class Rep, class Period>
      unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
    ~unique_lock();

    unique_lock(const unique_lock&) = delete;
    unique_lock& operator=(const unique_lock&) = delete;

    unique_lock(unique_lock&& u) noexcept;
    unique_lock& operator=(unique_lock&& u);

    // 锁定
    void lock();
    bool try_lock();

    template<class Rep, class Period>
      bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template<class Clock, class Duration>
      bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);

    void unlock();

    // 修改器
    void swap(unique_lock& u) noexcept;
    mutex_type* release() noexcept;

    // 观察器
    bool owns_lock() const noexcept;
    explicit operator bool () const noexcept;
    mutex_type* mutex() const noexcept;

  private:
    mutex_type* pm;             // 仅用于阐释
    bool owns;                  // 仅用于阐释
  };

  template<class Mutex>
    void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
}

类 std::once_flag

struct once_flag {
    constexpr once_flag() noexcept;
    once_flag(const once_flag&) = delete;
    once_flag& operator=(const once_flag&) = delete;
};


标准库头文件 <new>

< cpp‎ | header

此头文件是动态内存管理库的一部分，特别提供低层内存管理特性。

类
bad_alloc
 内存分配失败时抛出的异常
(类)
bad_array_new_length
(C++11)
 在分配有非法长度的数组时抛出的异常
(类)
nothrow_t
 用于选择不抛出分配函数的标签类型
(类)
align_val_t
(C++17)
 用于向带对齐分配及解分配函数传递对齐值的类型
(枚举)
destroying_delete_t
(C++20)
 用于鉴别 operator delete 的销毁删除重载的标签类型
(类)

类型
new_handler
 new 处理函数的函数指针类型
(typedef)

常量
nothrow
 用于选择不抛出分配函数的 nothrow_t 类型对象
(常量)
hardware_destructive_interference_sizehardware_constructive_interference_size
(C++17)
 避免假共享的最小偏移
促使真共享的最大偏移
(常量)

函数
operator newoperator new[]
 分配函数
(函数)
operator deleteoperator delete[]
 解分配函数
(函数)
get_new_handler
(C++11)
 获得当前的 new 处理函数
(函数)
set_new_handler
 注册一个 new 处理函数
(函数)
launder
(C++17)
 指针优化屏障
(函数模板)

概要

namespace std {
  // 存储分配错误
  class bad_alloc;
  class bad_array_new_length;

  struct destroying_delete_t {
    explicit destroying_delete_t() = default;
  };
  inline constexpr destroying_delete_t destroying_delete{};

  // 全局 operator new 控制
  enum class align_val_t : size_t {};

  struct nothrow_t { explicit nothrow_t() = default; };
  extern const nothrow_t nothrow;

  using new_handler = void (*)();
  new_handler get_new_handler() noexcept;
  new_handler set_new_handler(new_handler new_p) noexcept;

  // 指针优化屏障
  template<class T> [[nodiscard]] constexpr T* launder(T* p) noexcept;

  // 硬件干涉大小
  inline constexpr size_t hardware_destructive_interference_size = /* 由实现定义 */;
  inline constexpr size_t hardware_constructive_interference_size = /* 由实现定义 */;
}

// 存储分配与解分配
[[nodiscard]] void* operator new(std::size_t size);
[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment);
[[nodiscard]] void* operator new(std::size_t size, const std::nothrow_t&) noexcept;
[[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment,
                                 const std::nothrow_t&) noexcept;

void  operator delete(void* ptr) noexcept;
void  operator delete(void* ptr, std::size_t size) noexcept;
void  operator delete(void* ptr, std::align_val_t alignment) noexcept;
void  operator delete(void* ptr, std::size_t size, std::align_val_t alignment) noexcept;
void  operator delete(void* ptr, const std::nothrow_t&) noexcept;
void  operator delete(void* ptr, std::align_val_t alignment,
                      const std::nothrow_t&) noexcept;

[[nodiscard]] void* operator new[](std::size_t size);
[[nodiscard]] void* operator new[](std::size_t size, std::align_val_t alignment);
[[nodiscard]] void* operator new[](std::size_t size, const std::nothrow_t&) noexcept;
[[nodiscard]] void* operator new[](std::size_t size, std::align_val_t alignment,
                                   const std::nothrow_t&) noexcept;

void  operator delete[](void* ptr) noexcept;
void  operator delete[](void* ptr, std::size_t size) noexcept;
void  operator delete[](void* ptr, std::align_val_t alignment) noexcept;
void  operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexcept;
void  operator delete[](void* ptr, const std::nothrow_t&) noexcept;
void  operator delete[](void* ptr, std::align_val_t alignment,
                        const std::nothrow_t&) noexcept;

[[nodiscard]] void* operator new  (std::size_t size, void* ptr) noexcept;
[[nodiscard]] void* operator new[](std::size_t size, void* ptr) noexcept;
void  operator delete  (void* ptr, void*) noexcept;
void  operator delete[](void* ptr, void*) noexcept;


标准库头文件 <numbers>

< cpp‎ | header

此头文件是数值库的一部分。

数学常数 (C++20 起)

头文件 <numbers> 提供数个数学常数，例如 std::numbers::pi 或 std::numbers::sqrt2 。

概要

namespace std::numbers {
  template<class T> inline constexpr T e_v          = /* 未指明 */;
  template<class T> inline constexpr T log2e_v      = /* 未指明 */;
  template<class T> inline constexpr T log10e_v     = /* 未指明 */;
  template<class T> inline constexpr T pi_v         = /* 未指明 */;
  template<class T> inline constexpr T inv_pi_v     = /* 未指明 */;
  template<class T> inline constexpr T inv_sqrtpi_v = /* 未指明 */;
  template<class T> inline constexpr T ln2_v        = /* 未指明 */;
  template<class T> inline constexpr T ln10_v       = /* 未指明 */;
  template<class T> inline constexpr T sqrt2_v      = /* 未指明 */;
  template<class T> inline constexpr T sqrt3_v      = /* 未指明 */;
  template<class T> inline constexpr T inv_sqrt3_v  = /* 未指明 */;
  template<class T> inline constexpr T egamma_v     = /* 未指明 */;
  template<class T> inline constexpr T phi_v        = /* 未指明 */;

  template<floating_point T> inline constexpr T e_v<T>          = /* 见描述 */;
  template<floating_point T> inline constexpr T log2e_v<T>      = /* 见描述 */;
  template<floating_point T> inline constexpr T log10e_v<T>     = /* 见描述 */;
  template<floating_point T> inline constexpr T pi_v<T>         = /* 见描述 */;
  template<floating_point T> inline constexpr T inv_pi_v<T>     = /* 见描述 */;
  template<floating_point T> inline constexpr T inv_sqrtpi_v<T> = /* 见描述 */;
  template<floating_point T> inline constexpr T ln2_v<T>        = /* 见描述 */;
  template<floating_point T> inline constexpr T ln10_v<T>       = /* 见描述 */;
  template<floating_point T> inline constexpr T sqrt2_v<T>      = /* 见描述 */;
  template<floating_point T> inline constexpr T sqrt3_v<T>      = /* 见描述 */;
  template<floating_point T> inline constexpr T inv_sqrt3_v<T>  = /* 见描述 */;
  template<floating_point T> inline constexpr T egamma_v<T>     = /* 见描述 */;
  template<floating_point T> inline constexpr T phi_v<T>        = /* 见描述 */;

  inline constexpr double e          = e_v<double>;
  inline constexpr double log2e      = log2e_v<double>;
  inline constexpr double log10e     = log10e_v<double>;
  inline constexpr double pi         = pi_v<double>;
  inline constexpr double inv_pi     = inv_pi_v<double>;
  inline constexpr double inv_sqrtpi = inv_sqrtpi_v<double>;
  inline constexpr double ln2        = ln2_v<double>;
  inline constexpr double ln10       = ln10_v<double>;
  inline constexpr double sqrt2      = sqrt2_v<double>;
  inline constexpr double sqrt3      = sqrt3_v<double>;
  inline constexpr double inv_sqrt3  = inv_sqrt3_v<double>;
  inline constexpr double egamma     = egamma_v<double>;
  inline constexpr double phi        = phi_v<double>;
}


标准库头文件 <numeric>

< cpp‎ | header

此头文件是数值库的一部分。

函数
iota
(C++11)
 用从起始值开始连续递增的值填充一个范围
(函数模板)
accumulate
 对一个范围内的元素求和
(函数模板)
reduce
(C++17)
 类似 std::accumulate，但不依序执行
(函数模板)
transform_reduce
(C++17)
 应用一个函数对象，然后以乱序规约
(函数模板)
inner_product
 计算两个范围的元素的内积
(函数模板)
adjacent_difference
 计算范围内各相邻元素之间的差
(函数模板)
partial_sum
 计算范围内元素的部分和
(函数模板)
inclusive_scan
(C++17)
 类似 std::partial_sum，第 i 个和中包含第 i 个输入
(函数模板)
exclusive_scan
(C++17)
 类似 std::partial_sum，第 i 个和中排除第 i 个输入
(函数模板)
transform_inclusive_scan
(C++17)
 应用一个函数对象，然后进行包含扫描
(函数模板)
transform_exclusive_scan
(C++17)
 应用一个函数对象，然后进行排除扫描
(函数模板)
gcd
(C++17)
 返回二个整数最大公约数的 constexpr 函数模板
(函数模板)
lcm
(C++17)
 返回二个整数最小公倍数的 constexpr 函数模板
(函数模板)
midpoint
(C++20)
 两个数值或指针间的中点
(函数模板)

概要

namespace std {
  // 累加
  template<class InputIt, class T>
    constexpr T accumulate(InputIt first, InputIt last, T init);
  template<class InputIt, class T, class BinaryOperation>
    constexpr T accumulate(InputIt first, InputIt last, T init, BinaryOperation binary_op);

  // 规约
  template<class InputIt>
    constexpr typename iterator_traits<InputIt>::value_type
      reduce(InputIt first, InputIt last);
  template<class InputIt, class T>
    constexpr T reduce(InputIt first, InputIt last, T init);
  template<class InputIt, class T, class BinaryOperation>
    constexpr T reduce(InputIt first, InputIt last, T init, BinaryOperation binary_op);
  template<class ExecutionPolicy, class ForwardIt>
    typename iterator_traits<ForwardIt>::value_type
      reduce(ExecutionPolicy&& exec,
             ForwardIt first, ForwardIt last);
  template<class ExecutionPolicy, class ForwardIt, class T>
    T reduce(ExecutionPolicy&& exec,
             ForwardIt first, ForwardIt last, T init);
  template<class ExecutionPolicy, class ForwardIt, class T, class BinaryOperation>
    T reduce(ExecutionPolicy&& exec,
             ForwardIt first, ForwardIt last, T init, BinaryOperation binary_op);

  // 内积
  template<class InputIt1, class InputIt2, class T>
    constexpr T inner_product(InputIt1 first1, InputIt1 last1,
                              InputIt2 first2, T init);
  template<class InputIt1, class InputIt2, class T,
           class BinaryOperation1, class BinaryOperation2>
    constexpr T inner_product(InputIt1 first1, InputIt1 last1,
                              InputIt2 first2, T init,
                              BinaryOperation1 binary_op1,
                              BinaryOperation2 binary_op2);

  // 变换规约
  template<class InputIt1, class InputIt2, class T>
    constexpr T transform_reduce(InputIt1 first1, InputIt1 last1,
                                 InputIt2 first2,
                                 T init);
  template<class InputIt1, class InputIt2, class T,
           class BinaryOperation1, class BinaryOperation2>
    constexpr T transform_reduce(InputIt1 first1, InputIt1 last1,
                                 InputIt2 first2,
                                 T init,
                                 BinaryOperation1 binary_op1,
                                 BinaryOperation2 binary_op2);
  template<class InputIt, class T,
           class BinaryOperation, class UnaryOperation>
    constexpr T transform_reduce(InputIt first, InputIt last,
                                 T init,
                                 BinaryOperation binary_op, UnaryOperation unary_op);
  template<class ExecutionPolicy,
           class ForwardIt1, class ForwardIt2, class T>
    T transform_reduce(ExecutionPolicy&& exec,
                       ForwardIt1 first1, ForwardIt1 last1,
                       ForwardIt2 first2,
                       T init);
  template<class ExecutionPolicy,
           class ForwardIt1, class ForwardIt2, class T,
           class BinaryOperation1, class BinaryOperation2>
    T transform_reduce(ExecutionPolicy&& exec,
                       ForwardIt1 first1, ForwardIt1 last1,
                       ForwardIt2 first2,
                       T init,
                       BinaryOperation1 binary_op1,
                       BinaryOperation2 binary_op2);
  template<class ExecutionPolicy,
           class ForwardIt, class T,
           class BinaryOperation, class UnaryOperation>
    T transform_reduce(ExecutionPolicy&& exec,
                       ForwardIt first, ForwardIt last,
                       T init,
                       BinaryOperation binary_op, UnaryOperation unary_op);

  // 部分和
  template<class InputIt, class OutputIt>
    constexpr OutputIt partial_sum(InputIt first,
                                   InputIt last,
                                   OutputIt result);
  template<class InputIt, class OutputIt, class BinaryOperation>
    constexpr OutputIt partial_sum(InputIt first,
                                   InputIt last,
                                   OutputIt result,
                                   BinaryOperation binary_op);

  // 排除扫描
  template<class InputIt, class OutputIt, class T>
    constexpr OutputIt exclusive_scan(InputIt first, InputIt last,
                                      OutputIt result,
                                      T init);
  template<class InputIt, class OutputIt, class T, class BinaryOperation>
    constexpr OutputIt exclusive_scan(InputIt first, InputIt last,
                                      OutputIt result,
                                      T init, BinaryOperation binary_op);
  template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T>
    ForwardIt2 exclusive_scan(ExecutionPolicy&& exec,
                              ForwardIt1 first, ForwardIt1 last,
                              ForwardIt2 result,
                              T init);
  template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class T,
           class BinaryOperation>
    ForwardIt2 exclusive_scan(ExecutionPolicy&& exec,
                              ForwardIt1 first, ForwardIt1 last,
                              ForwardIt2 result,
                              T init, BinaryOperation binary_op);

  // 包含扫描
  template<class InputIt, class OutputIt>
    constexpr OutputIt inclusive_scan(InputIt first, InputIt last, OutputIt result);
  template<class InputIt, class OutputIt, class BinaryOperation>
    constexpr OutputIt inclusive_scan(InputIt first, InputIt last,
                                      OutputIt result,
                                      BinaryOperation binary_op);
  template<class InputIt, class OutputIt, class BinaryOperation, class T>
    constexpr OutputIt inclusive_scan(InputIt first, InputIt last,
                                      OutputIt result,
                                      BinaryOperation binary_op, T init);
  template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2>
    ForwardIt2 inclusive_scan(ExecutionPolicy&& exec,
                              ForwardIt1 first, ForwardIt1 last,
                              ForwardIt2 result);
  template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
           class BinaryOperation>
    ForwardIt2 inclusive_scan(ExecutionPolicy&& exec,
                              ForwardIt1 first, ForwardIt1 last,
                              ForwardIt2 result,
                              BinaryOperation binary_op);
  template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
           class BinaryOperation, class T>
    ForwardIt2 inclusive_scan(ExecutionPolicy&& exec,
                              ForwardIt1 first, ForwardIt1 last,
                              ForwardIt2 result,
                              BinaryOperation binary_op, T init);

  // 变换排除扫描
  template<class InputIt, class OutputIt, class T,
           class BinaryOperation, class UnaryOperation>
    constexpr OutputIt transform_exclusive_scan(InputIt first, InputIt last,
                                                OutputIt result,
                                                T init,
                                                BinaryOperation binary_op,
                                                UnaryOperation unary_op);
  template<class ExecutionPolicy,
           class ForwardIt1, class ForwardIt2, class T,
           class BinaryOperation, class UnaryOperation>
    ForwardIt2 transform_exclusive_scan(ExecutionPolicy&& exec,
                                        ForwardIt1 first, ForwardIt1 last,
                                        ForwardIt2 result,
                                        T init,
                                        BinaryOperation binary_op,
                                        UnaryOperation unary_op);

  // 变换包含扫描
  template<class InputIt, class OutputIt,
           class BinaryOperation, class UnaryOperation>
    constexpr OutputIt transform_inclusive_scan(InputIt first, InputIt last,
                                                OutputIt result,
                                                BinaryOperation binary_op,
                                                UnaryOperation unary_op);
  template<class InputIt, class OutputIt,
           class BinaryOperation, class UnaryOperation, class T>
    constexpr OutputIt transform_inclusive_scan(InputIt first, InputIt last,
                                                OutputIt result,
                                                BinaryOperation binary_op,
                                                UnaryOperation unary_op,
                                                T init);
  template<class ExecutionPolicy,
           class ForwardIt1, class ForwardIt2,
           class BinaryOperation, class UnaryOperation>
    ForwardIt2 transform_inclusive_scan(ExecutionPolicy&& exec,
                                        ForwardIt1 first, ForwardIt1 last,
                                        ForwardIt2 result,
                                        BinaryOperation binary_op,
                                        UnaryOperation unary_op);
  template<class ExecutionPolicy,
           class ForwardIt1, class ForwardIt2,
           class BinaryOperation, class UnaryOperation, class T>
    ForwardIt2 transform_inclusive_scan(ExecutionPolicy&& exec,
                                        ForwardIt1 first, ForwardIt1 last,
                                        ForwardIt2 result,
                                        BinaryOperation binary_op,
                                        UnaryOperation unary_op,
                                        T init);

  // 相邻差
  template<class InputIt, class OutputIt>
    constexpr OutputIt adjacent_difference(InputIt first, InputIt last,
                                           OutputIt result);
  template<class InputIt, class OutputIt, class BinaryOperation>
    constexpr OutputIt adjacent_difference(InputIt first, InputIt last,
                                           OutputIt result,
                                           BinaryOperation binary_op);
  template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2>
    ForwardIt2 adjacent_difference(ExecutionPolicy&& exec,
                                   ForwardIt1 first, ForwardIt1 last,
                                   ForwardIt2 result);
  template<class ExecutionPolicy, class ForwardIt1, class ForwardIt2,
           class BinaryOperation>
    ForwardIt2 adjacent_difference(ExecutionPolicy&& exec,
                                   ForwardIt1 first, ForwardIt1 last,
                                   ForwardIt2 result,
                                   BinaryOperation binary_op);

  // iota
  template<class ForwardIt, class T>
    constexpr void iota(ForwardIt first, ForwardIt last, T value);

  // 最大公约数
  template<class M, class N>
    constexpr common_type_t<M, N> gcd(M m, N n);

  // 最小公倍数
  template<class M, class N>
    constexpr common_type_t<M, N> lcm(M m, N n);

  // 中点
  template<class T>
    constexpr T midpoint(T a, T b) noexcept;
  template<class T>
    constexpr T* midpoint(T* a, T* b);
}


标准库头文件 <optional>

< cpp‎ | header

包含
<compare>
(C++20)
 三路比较运算符支持

类
optional
(C++17)
 可能或可能不保有一个对象的包装器
(类模板)
bad_optional_access
(C++17)
 指示进行了到不含值的 optional 的有检查访问的异常
(类)
std::hash<std::optional>
(C++17)
 特化 std::hash 算法
(类模板特化)
nullopt_t
(C++17)
 带未初始化状态的 optional 类型的指示器
(类)
前置声明
定义于头文件 <functional>
hash
(C++11)
 散列函数对象
(类模板)

常量
nullopt
(C++17)
 nullopt_t 类型对象
(常量)

函数
比较
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++17)(C++17)(C++17)(C++17)(C++17)(C++17)(C++20)
 比较 optional 对象
(函数模板)
特化的算法
std::swap(std::optional)
(C++17)
 特化 std::swap 算法
(函数模板)
make_optional
(C++17)
 创建一个 optional 对象
(函数模板)

概要

#include <compare>

namespace std {
  // 类模板 optional
  template<class T>
    class optional;

  // 无值状态指示器
  struct nullopt_t{/* 见描述 */};
  inline constexpr nullopt_t nullopt(/* 未指明 */);

  // 类 bad_optional_access
  class bad_optional_access;

  // 关系运算符
  template<class T, class U>
    constexpr bool operator==(const optional<T>&, const optional<U>&);
  template<class T, class U>
    constexpr bool operator!=(const optional<T>&, const optional<U>&);
  template<class T, class U>
    constexpr bool operator<(const optional<T>&, const optional<U>&);
  template<class T, class U>
    constexpr bool operator>(const optional<T>&, const optional<U>&);
  template<class T, class U>
    constexpr bool operator<=(const optional<T>&, const optional<U>&);
  template<class T, class U>
    constexpr bool operator>=(const optional<T>&, const optional<U>&);
  template<class T, three_way_comparable_with<T> U>
    constexpr compare_three_way_result_t<T,U>
      operator<=>(const optional<T>&, const optional<U>&);

  // 与 nullopt 比较
  template<class T> constexpr bool operator==(const optional<T>&, nullopt_t) noexcept;
  template<class T>
    constexpr strong_ordering operator<=>(const optional<T>&, nullopt_t) noexcept;

  // 与 T 比较
  template<class T, class U> constexpr bool operator==(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator==(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator!=(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator!=(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator<(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator<(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator>(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator>(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator<=(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator<=(const T&, const optional<U>&);
  template<class T, class U> constexpr bool operator>=(const optional<T>&, const U&);
  template<class T, class U> constexpr bool operator>=(const T&, const optional<U>&);
  template<class T, three_way_comparable_with<T> U>
    constexpr compare_three_way_result_t<T,U>
      operator<=>(const optional<T>&, const U&);

  // 特化的算法
  template<class T>
    constexpr void swap(optional<T>&, optional<T>&) noexcept(/* 见描述 */);

  template<class T>
    constexpr optional</* 见描述 */> make_optional(T&&);
  template<class T, class... Args>
    constexpr optional<T> make_optional(Args&&... args);
  template<class T, class U, class... Args>
    constexpr optional<T> make_optional(initializer_list<U> il, Args&&... args);

  // 散列支持
  template<class T> struct hash;
  template<class T> struct hash<optional<T>>;
}

类模板 std::optional

namespace std {
  template<class T>
  class optional {
  public:
    using value_type = T;

    // 构造函数
    constexpr optional() noexcept;
    constexpr optional(nullopt_t) noexcept;
    constexpr optional(const optional&);
    constexpr optional(optional&&) noexcept(/* 见描述 */);
    template<class... Args>
      constexpr explicit optional(in_place_t, Args&&...);
    template<class U, class... Args>
      constexpr explicit optional(in_place_t, initializer_list<U>, Args&&...);
    template<class U = T>
      constexpr explicit(/* 见描述 */) optional(U&&);
    template<class U>
      constexpr explicit(/* 见描述 */) optional(const optional<U>&);
    template<class U>
      constexpr explicit(/* 见描述 */) optional(optional<U>&&);

    // 析构函数
    constexpr ~optional();

    // 赋值
    constexpr optional& operator=(nullopt_t) noexcept;
    constexpr optional& operator=(const optional&);
    constexpr optional& operator=(optional&&) noexcept(/* 见描述 */);
    template<class U = T> constexpr optional& operator=(U&&);
    template<class U> constexpr optional& operator=(const optional<U>&);
    template<class U> constexpr optional& operator=(optional<U>&&);
    template<class... Args> constexpr T& emplace(Args&&...);
    template<class U, class... Args> constexpr T& emplace(initializer_list<U>, Args&&...);

    // 交换
    constexpr void swap(optional&) noexcept(/* 见描述 */);

    // 观察器
    constexpr const T* operator->() const noexcept;
    constexpr T* operator->() noexcept;
    constexpr const T& operator*() const& noexcept;
    constexpr T& operator*() & noexcept;
    constexpr T&& operator*() && noexcept;
    constexpr const T&& operator*() const&& noexcept;
    constexpr explicit operator bool() const noexcept;
    constexpr bool has_value() const noexcept;
    constexpr const T& value() const&;
    constexpr T& value() &;
    constexpr T&& value() &&;
    constexpr const T&& value() const&&;
    template<class U> constexpr T value_or(U&&) const&;
    template<class U> constexpr T value_or(U&&) &&;

    // 单子操作
    template <class F> constexpr auto and_then(F&& f) &;
    template <class F> constexpr auto and_then(F&& f) &&;
    template <class F> constexpr auto and_then(F&& f) const&;
    template <class F> constexpr auto and_then(F&& f) const&&;
    template <class F> constexpr auto transform(F&& f) &;
    template <class F> constexpr auto transform(F&& f) &&;
    template <class F> constexpr auto transform(F&& f) const&;
    template <class F> constexpr auto transform(F&& f) const&&;
    template <class F> constexpr optional or_else(F&& f) &&;
    template <class F> constexpr optional or_else(F&& f) const&;

    // 修改器
    constexpr void reset() noexcept;

  private:
    T *val;         // 仅用于阐释
  };

  template<class T>
    optional(T) -> optional<T>;
}


标准库头文件 <ostream>

< cpp‎ | header

此头文件是输入/输出库的一部分。

类
basic_ostream
 包装给定的抽象设备（std::basic_streambuf）
并提供高层输出接口
(类模板)
std::ostream std::basic_ostream <char>
(typedef)
std::wostream std::basic_ostream <wchar_t>
(typedef)

函数
operator<<(std::basic_ostream)
 插入字符数据
(函数)
操纵符
endl
 输出 '\n' 并冲洗输出流
(函数模板)
ends
 输出 '\0'
(函数模板)
flush
 冲洗输出流
(函数模板)
emit_on_flushnoemit_on_flush
(C++20)
 控制流的 basic_syncbuf 是否在冲入时发射
(函数模板)
flush_emit
(C++20)
 冲入流，而若它使用 basic_syncbuf 则发射其内容
(函数模板)

概要

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
    class basic_ostream;

  using ostream  = basic_ostream<char>;
  using wostream = basic_ostream<wchar_t>;

  template<class CharT, class Traits>
    basic_ostream<CharT, Traits>& endl(basic_ostream<CharT, Traits>& os);
  template<class CharT, class Traits>
    basic_ostream<CharT, Traits>& ends(basic_ostream<CharT, Traits>& os);
  template<class CharT, class Traits>
    basic_ostream<CharT, Traits>& flush(basic_ostream<CharT, Traits>& os);

  template<class CharT, class Traits>
    basic_ostream<CharT, Traits>& emit_on_flush(basic_ostream<CharT, Traits>& os);
  template<class CharT, class Traits>
    basic_ostream<CharT, Traits>& noemit_on_flush(basic_ostream<CharT, Traits>& os);
  template<class CharT, class Traits>
    basic_ostream<CharT, Traits>& flush_emit(basic_ostream<CharT, Traits>& os);

  template<class Ostream, class T>
    Ostream&& operator<<(Ostream&& os, const T& x);
}

类模板 std::basic_ostream

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_ostream : virtual public basic_ios<CharT, Traits> {
  public:
    // 类型（继承自 basic_ios ）
    using char_type   = CharT;
    using int_type    = typename Traits::int_type;
    using pos_type    = typename Traits::pos_type;
    using off_type    = typename Traits::off_type;
    using traits_type = Traits;

    // 构造函数/析构函数
    explicit basic_ostream(basic_streambuf<char_type, Traits>* sb);
    virtual ~basic_ostream();

    // 前置工序/后置工序
    class sentry;

    // 有格式输出
    basic_ostream<CharT, Traits>&
      operator<<(basic_ostream<CharT, Traits>& (*pf)(basic_ostream<CharT, Traits>&));
    basic_ostream<CharT, Traits>&
      operator<<(basic_ios<CharT, Traits>& (*pf)(basic_ios<CharT, Traits>&));
    basic_ostream<CharT, Traits>&
      operator<<(ios_base& (*pf)(ios_base&));

    basic_ostream<CharT, Traits>& operator<<(bool n);
    basic_ostream<CharT, Traits>& operator<<(short n);
    basic_ostream<CharT, Traits>& operator<<(unsigned short n);
    basic_ostream<CharT, Traits>& operator<<(int n);
    basic_ostream<CharT, Traits>& operator<<(unsigned int n);
    basic_ostream<CharT, Traits>& operator<<(long n);
    basic_ostream<CharT, Traits>& operator<<(unsigned long n);
    basic_ostream<CharT, Traits>& operator<<(long long n);
    basic_ostream<CharT, Traits>& operator<<(unsigned long long n);
    basic_ostream<CharT, Traits>& operator<<(float f);
    basic_ostream<CharT, Traits>& operator<<(double f);
    basic_ostream<CharT, Traits>& operator<<(long double f);

    basic_ostream<CharT, Traits>& operator<<(const void* p);
    basic_ostream<CharT, Traits>& operator<<(const volatile void* val);
    basic_ostream<CharT, Traits>& operator<<(nullptr_t);
    basic_ostream<CharT, Traits>& operator<<(basic_streambuf<char_type, Traits>* sb);

    // 无格式输出
    basic_ostream<CharT, Traits>& put(char_type c);
    basic_ostream<CharT, Traits>& write(const char_type* s, streamsize n);

    basic_ostream<CharT, Traits>& flush();

    // 巡位
    pos_type tellp();
    basic_ostream<CharT, Traits>& seekp(pos_type);
    basic_ostream<CharT, Traits>& seekp(off_type, ios_base::seekdir);

  protected:
    // 复制/移动构造函数
    basic_ostream(const basic_ostream&) = delete;
    basic_ostream(basic_ostream&& rhs);

    // 赋值与交换
    basic_ostream& operator=(const basic_ostream&) = delete;
    basic_ostream& operator=(basic_ostream&& rhs);
    void swap(basic_ostream& rhs);
  };

  // 字符插入器
  template<class CharT, class Traits>
    basic_ostream<CharT, Traits>& operator<<(basic_ostream<CharT, Traits>&, CharT);
  template<class CharT, class Traits>
    basic_ostream<CharT, Traits>& operator<<(basic_ostream<CharT, Traits>&, char);
  template<class Traits>
    basic_ostream<char, Traits>& operator<<(basic_ostream<char, Traits>&, char);

  template<class Traits>
    basic_ostream<char, Traits>& operator<<(basic_ostream<char, Traits>&, signed char);
  template<class Traits>
    basic_ostream<char, Traits>& operator<<(basic_ostream<char, Traits>&, unsigned char);

  template<class Traits>
    basic_ostream<char, Traits>&
      operator<<(basic_ostream<char, Traits>&, wchar_t) = delete;
  template<class Traits>
    basic_ostream<char, Traits>&
      operator<<(basic_ostream<char, Traits>&, char8_t) = delete;
  template<class Traits>
    basic_ostream<char, Traits>&
      operator<<(basic_ostream<char, Traits>&, char16_t) = delete;
  template<class Traits>
    basic_ostream<char, Traits>&
      operator<<(basic_ostream<char, Traits>&, char32_t) = delete;
  template<class Traits>
    basic_ostream<wchar_t, Traits>&
      operator<<(basic_ostream<wchar_t, Traits>&, char8_t) = delete;
  template<class Traits>
    basic_ostream<wchar_t, Traits>&
      operator<<(basic_ostream<wchar_t, Traits>&, char16_t) = delete;
  template<class Traits>
    basic_ostream<wchar_t, Traits>&
      operator<<(basic_ostream<wchar_t, Traits>&, char32_t) = delete;

  template<class CharT, class Traits>
    basic_ostream<CharT, Traits>&
      operator<<(basic_ostream<CharT, Traits>&, const CharT*);
  template<class CharT, class Traits>
    basic_ostream<CharT, Traits>&
      operator<<(basic_ostream<CharT, Traits>&, const char*);
  template<class Traits>
    basic_ostream<char, Traits>&
      operator<<(basic_ostream<char, Traits>&, const char*);

  template<class Traits>
    basic_ostream<char, Traits>&
      operator<<(basic_ostream<char, Traits>&, const signed char*);
  template<class Traits>
    basic_ostream<char, Traits>&
      operator<<(basic_ostream<char, Traits>&, const unsigned char*);

  template<class Traits>
    basic_ostream<char, Traits>&
      operator<<(basic_ostream<char, Traits>&, const wchar_t*) = delete;
  template<class Traits>
    basic_ostream<char, Traits>&
      operator<<(basic_ostream<char, Traits>&, const char8_t*) = delete;
  template<class Traits>
    basic_ostream<char, Traits>&
      operator<<(basic_ostream<char, Traits>&, const char16_t*) = delete;
  template<class Traits>
    basic_ostream<char, Traits>&
      operator<<(basic_ostream<char, Traits>&, const char32_t*) = delete;
  template<class Traits>
    basic_ostream<wchar_t, Traits>&
      operator<<(basic_ostream<wchar_t, Traits>&, const char8_t*) = delete;
  template<class Traits>
    basic_ostream<wchar_t, Traits>&
      operator<<(basic_ostream<wchar_t, Traits>&, const char16_t*) = delete;
  template<class Traits>
    basic_ostream<wchar_t, Traits>&
      operator<<(basic_ostream<wchar_t, Traits>&, const char32_t*) = delete;
}

类 std::basic_ostream::sentry

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_ostream<CharT, Traits>::sentry {
    bool ok_;       // 仅用于阐释
  public:
    explicit sentry(basic_ostream<CharT, Traits>& os);
    ~sentry();
    explicit operator bool() const { return ok_; }

    sentry(const sentry&) = delete;
    sentry& operator=(const sentry&) = delete;
  };
}


标准库头文件 <queue>

< cpp‎ | header

此头文件是容器库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
<initializer_list>
(C++11)
 std::initializer_list 类模板

类
queue
 适配一个容器以提供队列（FIFO 数据结构）
(类模板)
priority_queue
 适配一个容器以提供优先级队列
(类模板)
std::uses_allocator<std::queue>
(C++11)
 特化 std::uses_allocator 类型特征
(类模板特化)
std::uses_allocator<std::priority_queue>
(C++11)
 特化 std::uses_allocator 类型特征
(类模板特化)

函数
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20)
 按照字典顺序比较 queue 中的值
(函数模板)
std::swap(std::queue)
(C++11)
 特化 std::swap 算法
(函数模板)
std::swap(std::priority_queue)
(C++11)
 特化 std::swap 算法
(函数模板)

概要

#include <compare>
#include <initializer_list>

namespace std {
  template<class T, class Container = deque<T>> class queue;

  template<class T, class Container>
    bool operator==(const queue<T, Container>& x, const queue<T, Container>& y);
  template<class T, class Container>
    bool operator!=(const queue<T, Container>& x, const queue<T, Container>& y);
  template<class T, class Container>
    bool operator< (const queue<T, Container>& x, const queue<T, Container>& y);
  template<class T, class Container>
    bool operator> (const queue<T, Container>& x, const queue<T, Container>& y);
  template<class T, class Container>
    bool operator<=(const queue<T, Container>& x, const queue<T, Container>& y);
  template<class T, class Container>
    bool operator>=(const queue<T, Container>& x, const queue<T, Container>& y);
  template<class T, three_way_comparable Container>
    compare_three_way_result_t<Container>
      operator<=>(const queue<T, Container>& x, const queue<T, Container>& y);

  template<class T, class Container>
    void swap(queue<T, Container>& x, queue<T, Container>& y)
      noexcept(noexcept(x.swap(y)));
  template<class T, class Container, class Alloc>
    struct uses_allocator<queue<T, Container>, Alloc>;

  template<class T, class Container = vector<T>,
           class Compare = less<typename Container::value_type>>
    class priority_queue;

  template<class T, class Container, class Compare>
    void swap(priority_queue<T, Container, Compare>& x,
              priority_queue<T, Container, Compare>& y) noexcept(noexcept(x.swap(y)));
  template<class T, class Container, class Compare, class Alloc>
    struct uses_allocator<priority_queue<T, Container, Compare>, Alloc>;
}

类模板 std::queue

namespace std {
  template<class T, class Container = deque<T>>
  class queue {
  public:
    using value_type      = typename Container::value_type;
    using reference       = typename Container::reference;
    using const_reference = typename Container::const_reference;
    using size_type       = typename Container::size_type;
    using container_type  =          Container;

  protected:
    Container c;

  public:
    queue() : queue(Container()) {}
    explicit queue(const Container&);
    explicit queue(Container&&);
    template<class InputIt> queue(InputIt first, InputIt last);
    template<class Alloc> explicit queue(const Alloc&);
    template<class Alloc> queue(const Container&, const Alloc&);
    template<class Alloc> queue(Container&&, const Alloc&);
    template<class Alloc> queue(const queue&, const Alloc&);
    template<class Alloc> queue(queue&&, const Alloc&);
    template<class InputIt, class Alloc>
      queue(InputIt first, InputIt last, const Alloc&);

    [[nodiscard]] bool empty() const    { return c.empty(); }
    size_type         size()  const     { return c.size(); }
    reference         front()           { return c.front(); }
    const_reference   front() const     { return c.front(); }
    reference         back()            { return c.back(); }
    const_reference   back() const      { return c.back(); }
    void push(const value_type& x)      { c.push_back(x); }
    void push(value_type&& x)           { c.push_back(std::move(x)); }
    template<class... Args>
      decltype(auto) emplace(Args&&... args)
        { return c.emplace_back(std::forward<Args>(args)...); }
    void pop()                          { c.pop_front(); }
    void swap(queue& q) noexcept(is_nothrow_swappable_v<Container>)
      { using std::swap; swap(c, q.c); }
  };

  template<class Container>
    queue(Container) -> queue<typename Container::value_type, Container>;

  template<class InputIt>
    queue(InputIt, InputIt) -> queue</*iter-value-type*/<InputIt>>;

  template<class Container, class Allocator>
    queue(Container, Allocator) -> queue<typename Container::value_type, Container>;

  template<class InputIt, class Allocator>
    queue(InputIt, InputIt, Allocator)
      -> queue</*iter-value-type*/<InputIt>, deque</*iter-value-type*/<InputIt>,
               Allocator>>;

  template<class T, class Container, class Alloc>
    struct uses_allocator<queue<T, Container>, Alloc>
      : uses_allocator<Container, Alloc>::type { };
}

类模板 std::priority_queue

namespace std {
  template<class T, class Container = vector<T>,
           class Compare = less<typename Container::value_type>>
  class priority_queue {
  public:
    using value_type      = typename Container::value_type;
    using reference       = typename Container::reference;
    using const_reference = typename Container::const_reference;
    using size_type       = typename Container::size_type;
    using container_type  = Container;
    using value_compare   = Compare;

  protected:
    Container c;
    Compare comp;

  public:
    priority_queue() : priority_queue(Compare()) {}
    explicit priority_queue(const Compare& x) : priority_queue(x, Container()) {}
    priority_queue(const Compare& x, const Container&);
    priority_queue(const Compare& x, Container&&);
    template<class InputIt>
      priority_queue(InputIt first, InputIt last, const Compare& x = Compare());
    template<class InputIt>
      priority_queue(InputIt first, InputIt last, const Compare& x,
                     const Container&);
    template<class InputIt>
      priority_queue(InputIt first, InputIt last, const Compare& x,
                     Container&&);
    template<class Alloc> explicit priority_queue(const Alloc&);
    template<class Alloc> priority_queue(const Compare&, const Alloc&);
    template<class Alloc> priority_queue(const Compare&, const Container&, const Alloc&);
    template<class Alloc> priority_queue(const Compare&, Container&&, const Alloc&);
    template<class Alloc> priority_queue(const priority_queue&, const Alloc&);
    template<class Alloc> priority_queue(priority_queue&&, const Alloc&);
    template<class InputIt, class Alloc>
      priority_queue(InputIt, InputIt, const Alloc&);
    template<class InputIt, class Alloc>
      priority_queue(InputIt, InputIt, const Compare&, const Alloc&);
    template<class InputIt, class Alloc>
      priority_queue(InputIt, InputIt, const Compare&, const Container&,
                     const Alloc&);
    template<class InputIt, class Alloc>
      priority_queue(InputIt, InputIt, const Compare&, Container&&, const Alloc&);

    [[nodiscard]] bool empty() const { return c.empty(); }
    size_type size()  const          { return c.size(); }
    const_reference   top() const    { return c.front(); }
    void push(const value_type& x);
    void push(value_type&& x);
    template<class... Args> void emplace(Args&&... args);
    void pop();
    void swap(priority_queue& q) noexcept(is_nothrow_swappable_v<Container> &&
                                          is_nothrow_swappable_v<Compare>)
      { using std::swap; swap(c, q.c); swap(comp, q.comp); }
  };

  template<class Compare, class Container>
    priority_queue(Compare, Container)
      -> priority_queue<typename Container::value_type, Container, Compare>;

  template<class InputIt,
           class Compare = less</*iter-value-type*/<InputIt>>,
           class Container = vector</*iter-value-type*/<InputIt>>>
    priority_queue(InputIt, InputIt, Compare = Compare(), Container = Container())
      -> priority_queue</*iter-value-type*/<InputIt>, Container, Compare>;

  template<class Compare, class Container, class Allocator>
    priority_queue(Compare, Container, Allocator)
      -> priority_queue<typename Container::value_type, Container, Compare>;

  template<class InputIt, class Allocator>
    priority_queue(InputIt, InputIt, Allocator)
      -> priority_queue</*iter-value-type*/<InputIt>,
                        vector</*iter-value-type*/<InputIt>, Allocator>,
                        less</*iter-value-type*/<InputIt>>>;

  template<class InputIt, class Compare, class Allocator>
    priority_queue(InputIt, InputIt, Compare, Allocator)
      -> priority_queue</*iter-value-type*/<InputIt>,
                        vector</*iter-value-type*/<InputIt>, Allocator>, Compare>;

  template<class InputIt, class Compare, class Container, class Allocator>
    priority_queue(InputIt, InputIt, Compare, Container, Allocator)
      -> priority_queue<typename Container::value_type, Container, Compare>;

  // 不提供相等

  template<class T, class Container, class Compare, class Alloc>
    struct uses_allocator<priority_queue<T, Container, Compare>, Alloc>
      : uses_allocator<Container, Alloc>::type { };
}


标准库头文件 <random>

< cpp‎ | header

此头文件是伪随机数生成库的一部分。

包含
<initializer_list>
(C++11)
 std::initializer_list 类模板

概念
均匀随机位生成器要求
uniform_random_bit_generator
(C++20)
 指定类型具备作为均匀随机位生成器的资格
(概念)

类
随机数引擎
linear_congruential_engine
(C++11)
 实现线性同余算法
(类模板)
mersenne_twister_engine
(C++11)
 实现梅森缠绕器算法
(类模板)
subtract_with_carry_engine
(C++11)
 实现带进位减（一种延迟斐波那契）算法
(类模板)
随机数引擎适配器
discard_block_engine
(C++11)
 舍弃随机数引擎的某些输出
(类模板)
independent_bits_engine
(C++11)
 将一个随机数引擎的输出打包为指定位数的块
(类模板)
shuffle_order_engine
(C++11)
 以不同顺序发送一个随机数引擎的输出
(类模板)
预定义生成器
minstd_rand0(C++11) std::linear_congruential_engine < std::uint_fast32_t, 16807, 0, 2147483647>

由 Lewis、Goodman 及 Miller 发现于 1969，由 Park 与 Miller 于 1988 采纳为“最小标准”
minstd_rand(C++11) std::linear_congruential_engine < std::uint_fast32_t, 48271, 0, 2147483647>

较新的“最小标准”，为 Park、 Miller 及 Stockmeyer 于 1993 推荐
mt19937(C++11)

std::mersenne_twister_engine < std::uint_fast32_t, 32, 624, 397, 31,
0x9908b0df, 11,
0xffffffff, 7,
0x9d2c5680, 15,
0xefc60000, 18, 1812433253>
32 位梅森缠绕器，由松本与西村设计于 1998
mt19937_64(C++11)

std::mersenne_twister_engine < std::uint_fast64_t, 64, 312, 156, 31,
0xb5026f5aa96619e9, 29,
0x5555555555555555, 17,
0x71d67fffeda60000, 37,
0xfff7eee000000000, 43, 6364136223846793005>
64 位梅森缠绕器，由松本与西村设计于 2000
ranlux24_base(C++11) | std::subtract_with_carry_engine < std::uint_fast32_t, 24, 10, 24>
ranlux48_base(C++11) | std::subtract_with_carry_engine < std::uint_fast64_t, 48, 5, 12>
ranlux24(C++11) std::discard_block_engine < std::ranlux24_base, 223, 23>

24 位 RANLUX 生成器，由 Martin Lüscher 与 Fred James 设计于 1994
ranlux48(C++11) std::discard_block_engine < std::ranlux48_base, 389, 11>

48 位 RANLUX 生成器，由 Martin Lüscher 与 Fred James 设计于 1994
knuth_b(C++11) | std::shuffle_order_engine < std::minstd_rand0, 256>
default_random_engine(C++11) | 实现定义
非确定性随机数
random_device
(C++11)
 使用硬件熵源的非确定随机数生成器
(类)
均匀分布
uniform_int_distribution
(C++11)
 产生在一个范围上均匀分布的整数值
(类模板)
uniform_real_distribution
(C++11)
 产生在一个范围上均匀分布的实数值
(类模板)
伯努利分布
bernoulli_distribution
(C++11)
 产生伯努利分布上的 bool 值。
(类)
binomial_distribution
(C++11)
 产生二项分布上的整数值。
(类模板)
negative_binomial_distribution
(C++11)
 产生负二项分布上的整数值。
(类模板)
geometric_distribution
(C++11)
 产生几何分布上的整数值。
(类模板)
泊松分布
poisson_distribution
(C++11)
 产生泊松分布上的整数值。
(类模板)
exponential_distribution
(C++11)
 产生指数分布上的实数值。
(类模板)
gamma_distribution
(C++11)
 产生 Γ 分布上的实数值
(类模板)
weibull_distribution
(C++11)
 产生威布尔分布上的实数值。
(类模板)
extreme_value_distribution
(C++11)
 产生极值分布上的实数值。
(类模板)
正态分布
normal_distribution
(C++11)
 产生标准正态（高斯）分布上的实数值。
(类模板)
lognormal_distribution
(C++11)
 产生对数正态分布上的实数值。
(类模板)
chi_squared_distribution
(C++11)
 产生 χ2 分布上的实数值。
(类模板)
cauchy_distribution
(C++11)
 产生柯西分布上的实数值。
(类模板)
fisher_f_distribution
(C++11)
 产生费舍尔 F 分布上的实数值。
(类模板)
student_t_distribution
(C++11)
 产生学生 t 分布上的实数值。
(类模板)
采样分布
discrete_distribution
(C++11)
 产生离散分布上的随机整数。
(类模板)
piecewise_constant_distribution
(C++11)
 产生分布在常子区间上的实数值。
(类模板)
piecewise_linear_distribution
(C++11)
 产生分布在定义的子区间上的实数值。
(类模板)
工具
seed_seq
(C++11)
 通用的偏差消除的混淆种子序列生成器
(类)

函数
generate_canonical
(C++11)
 给定精度的均匀分布在 [0, 1) 上的实数值
(函数模板)

概要

#include <initializer_list>

namespace std {
  // 均匀随机位生成器要求
  template<class G>
    concept uniform_random_bit_generator = /* 见描述 */;

  // 类模板 linear_congruential_engine
  template<class UIntType, UIntType a, UIntType c, UIntType m>
    class linear_congruential_engine;

  // 类模板 mersenne_twister_engine
  template<class UIntType, size_t w, size_t n, size_t m, size_t r,
           UIntType a, size_t u, UIntType d, size_t s,
           UIntType b, size_t t,
           UIntType c, size_t l, UIntType f>
    class mersenne_twister_engine;

  // 类模板 subtract_with_carry_engine
  template<class UIntType, size_t w, size_t s, size_t r>
    class subtract_with_carry_engine;

  // 类模板 discard_block_engine
  template<class Engine, size_t p, size_t r>
    class discard_block_engine;

  // 类模板 independent_bits_engine
  template<class Engine, size_t w, class UIntType>
    class independent_bits_engine;

  // 类模板 shuffle_order_engine
  template<class Engine, size_t k>
    class shuffle_order_engine;

  // 带预定义形参的引擎及引擎适配器
  using minstd_rand0  = /* 见描述 */;
  using minstd_rand   = /* 见描述 */;
  using mt19937       = /* 见描述 */;
  using mt19937_64    = /* 见描述 */;
  using ranlux24_base = /* 见描述 */;
  using ranlux48_base = /* 见描述 */;
  using ranlux24      = /* 见描述 */;
  using ranlux48      = /* 见描述 */;
  using knuth_b       = /* 见描述 */;

  using default_random_engine = /* 见描述 */;

  // 类 random_device
  class random_device;

  // 类 seed_seq
  class seed_seq;

  // 函数模板 generate_canonical
  template<class RealType, size_t bits, class URBG>
    RealType generate_canonical(URBG& g);

  // 类模板 uniform_int_distribution
  template<class IntType = int>
    class uniform_int_distribution;

  // 类模板 uniform_real_distribution
  template<class RealType = double>
    class uniform_real_distribution;

  // 类 bernoulli_distribution
  class bernoulli_distribution;

  // 类模板 binomial_distribution
  template<class IntType = int>
    class binomial_distribution;

  // 类模板 geometric_distribution
  template<class IntType = int>
    class geometric_distribution;

  // 类模板 negative_binomial_distribution
  template<class IntType = int>
    class negative_binomial_distribution;

  // 类模板 poisson_distribution
  template<class IntType = int>
    class poisson_distribution;

  // 类模板 exponential_distribution
  template<class RealType = double>
    class exponential_distribution;

  // 类模板 gamma_distribution
  template<class RealType = double>
    class gamma_distribution;

  // 类模板 weibull_distribution
  template<class RealType = double>
    class weibull_distribution;

  // 类模板 extreme_value_distribution
  template<class RealType = double>
    class extreme_value_distribution;

  // 类模板 normal_distribution
  template<class RealType = double>
    class normal_distribution;

  // 类模板 lognormal_distribution
  template<class RealType = double>
    class lognormal_distribution;

  // 类模板 chi_squared_distribution
  template<class RealType = double>
    class chi_squared_distribution;

  // 类模板 cauchy_distribution
  template<class RealType = double>
    class cauchy_distribution;

  // 类模板 fisher_f_distribution
  template<class RealType = double>
    class fisher_f_distribution;

  // 类模板 student_t_distribution
  template<class RealType = double>
    class student_t_distribution;

  // 类模板 discrete_distribution
  template<class IntType = int>
    class discrete_distribution;

  // 类模板 piecewise_constant_distribution
  template<class RealType = double>
    class piecewise_constant_distribution;

  // 类模板 piecewise_linear_distribution
  template<class RealType = double>
    class piecewise_linear_distribution;
}

概念 uniform_random_bit_generator

namespace std {
  template<class G>
    concept uniform_random_bit_generator =
      invocable<G&> && unsigned_integral<invoke_result_t<G&>> &&
      requires {
        { G::min() } -> same_as<invoke_result_t<G&>>;
        { G::max() } -> same_as<invoke_result_t<G&>>;
        requires bool_constant<(G::min() < G::max())>::value;
      };
}

类模板 std::linear_congruential_engine

namespace std {
  template<class UIntType, UIntType a, UIntType c, UIntType m>
    class linear_congruential_engine {
    public:
      // 类型
      using result_type = UIntType;

      // 引擎特征
      static constexpr result_type multiplier = a;
      static constexpr result_type increment = c;
      static constexpr result_type modulus = m;
      static constexpr result_type min() { return c == 0u ? 1u: 0u; }
      static constexpr result_type max() { return m - 1u; }
      static constexpr result_type default_seed = 1u;

      // 构造函数与播种函数
      linear_congruential_engine() : linear_congruential_engine(default_seed) {}
      explicit linear_congruential_engine(result_type s);
      template<class Sseq> explicit linear_congruential_engine(Sseq& q);
      void seed(result_type s = default_seed);
      template<class Sseq> void seed(Sseq& q);

      // 生成函数
      result_type operator()();
      void discard(unsigned long long z);
    };
}

类模板 std::mersenne_twister_engine

namespace std {
  template<class UIntType, size_t w, size_t n, size_t m, size_t r,
           UIntType a, size_t u, UIntType d, size_t s,
           UIntType b, size_t t,
           UIntType c, size_t l, UIntType f>
    class mersenne_twister_engine {
    public:
      // 类型
      using result_type = UIntType;

      // 引擎特征
      static constexpr size_t word_size = w;
      static constexpr size_t state_size = n;
      static constexpr size_t shift_size = m;
      static constexpr size_t mask_bits = r;
      static constexpr UIntType xor_mask = a;
      static constexpr size_t tempering_u = u;
      static constexpr UIntType tempering_d = d;
      static constexpr size_t tempering_s = s;
      static constexpr UIntType tempering_b = b;
      static constexpr size_t tempering_t = t;
      static constexpr UIntType tempering_c = c;
      static constexpr size_t tempering_l = l;
      static constexpr UIntType initialization_multiplier = f;
      static constexpr result_type min() { return 0; }
      static constexpr result_type max() { return /* pow(2, w) - 1 */; }
      static constexpr result_type default_seed = 5489u;

      // 构造函数与播种函数
      mersenne_twister_engine() : mersenne_twister_engine(default_seed) {}
      explicit mersenne_twister_engine(result_type value);
      template<class Sseq> explicit mersenne_twister_engine(Sseq& q);
      void seed(result_type value = default_seed);
      template<class Sseq> void seed(Sseq& q);

      // 生成函数
      result_type operator()();
      void discard(unsigned long long z);
    };
}

类模板 std::subtract_with_carry_engine

namespace std {
  template<class UIntType, size_t w, size_t s, size_t r>
    class subtract_with_carry_engine {
    public:
      // 类型
      using result_type = UIntType;

      // 引擎特征
      static constexpr size_t word_size = w;
      static constexpr size_t short_lag = s;
      static constexpr size_t long_lag = r;
      static constexpr result_type min() { return 0; }
      static constexpr result_type max() { return /* pow(2, w) - 1 */; }
      static constexpr result_type default_seed = 19780503u;

      // 构造函数与播种函数
      subtract_with_carry_engine() : subtract_with_carry_engine(default_seed) {}
      explicit subtract_with_carry_engine(result_type value);
      template<class Sseq> explicit subtract_with_carry_engine(Sseq& q);
      void seed(result_type value = default_seed);
      template<class Sseq> void seed(Sseq& q);

      // 生成函数
      result_type operator()();
      void discard(unsigned long long z);
    };
}

类模板 std::discard_block_engine

namespace std {
  template<class Engine, size_t p, size_t r>
    class discard_block_engine {
    public:
      // 类型
      using result_type = typename Engine::result_type;

      // 引擎特征
      static constexpr size_t block_size = p;
      static constexpr size_t used_block = r;
      static constexpr result_type min() { return Engine::min(); }
      static constexpr result_type max() { return Engine::max(); }

      // 构造函数与播种函数
      discard_block_engine();
      explicit discard_block_engine(const Engine& e);
      explicit discard_block_engine(Engine&& e);
      explicit discard_block_engine(result_type s);
      template<class Sseq> explicit discard_block_engine(Sseq& q);
      void seed();
      void seed(result_type s);
      template<class Sseq> void seed(Sseq& q);

      // 生成函数
      result_type operator()();
      void discard(unsigned long long z);

      // 属性函数
      const Engine& base() const noexcept { return e; };

    private:
      Engine e;   // 仅用于阐释
      int n;      // 仅用于阐释
    };
}

类模板 std::independent_bits_engine

namespace std {
  template<class Engine, size_t w, class UIntType>
    class independent_bits_engine {
    public:
      // 类型
      using result_type = UIntType;

      // 引擎特征
      static constexpr result_type min() { return 0; }
      static constexpr result_type max() { return /* pow(2, w) - 1 */; }

      // 构造函数与播种函数
      independent_bits_engine();
      explicit independent_bits_engine(const Engine& e);
      explicit independent_bits_engine(Engine&& e);
      explicit independent_bits_engine(result_type s);
      template<class Sseq> explicit independent_bits_engine(Sseq& q);
      void seed();
      void seed(result_type s);
      template<class Sseq> void seed(Sseq& q);

      // 生成函数
      result_type operator()();
      void discard(unsigned long long z);

      // 属性函数
      const Engine& base() const noexcept { return e; };

    private:
      Engine e;   // 仅用于阐释
    };
}

类模板 std::shuffle_order_engine

namespace std {
  template<class Engine, size_t k>
    class shuffle_order_engine {
    public:
      // 类型
      using result_type = typename Engine::result_type;

      // 引擎特征
      static constexpr size_t table_size = k;
      static constexpr result_type min() { return Engine::min(); }
      static constexpr result_type max() { return Engine::max(); }

      // 构造函数与播种函数
      shuffle_order_engine();
      explicit shuffle_order_engine(const Engine& e);
      explicit shuffle_order_engine(Engine&& e);
      explicit shuffle_order_engine(result_type s);
      template<class Sseq> explicit shuffle_order_engine(Sseq& q);
      void seed();
      void seed(result_type s);
      template<class Sseq> void seed(Sseq& q);

      // 生成函数
      result_type operator()();
      void discard(unsigned long long z);

      // 属性函数
      const Engine& base() const noexcept { return e; };

    private:
      Engine e;           // 仅用于阐释
      result_type V[k];   // 仅用于阐释
      result_type Y;      // 仅用于阐释
    };
}

带预定义形参的引擎及引擎适配器

namespace std {
  using minstd_rand0 =
        linear_congruential_engine<uint_fast32_t, 16'807, 0, 2'147'483'647>;
  using minstd_rand =
        linear_congruential_engine<uint_fast32_t, 48'271, 0, 2'147'483'647>;
  using mt19937 =
        mersenne_twister_engine<uint_fast32_t, 32, 624, 397, 31,
         0x9908'b0df, 11, 0xffff'ffff, 7, 0x9d2c'5680, 15, 0xefc6'0000, 18, 1'812'433'253>;
  using mt19937_64 =
        mersenne_twister_engine<uint_fast64_t, 64, 312, 156, 31,
         0xb502'6f5a'a966'19e9, 29, 0x5555'5555'5555'5555, 17,
         0x71d6'7fff'eda6'0000, 37, 0xfff7'eee0'0000'0000, 43, 6'364'136'223'846'793'005>;
  using ranlux24_base =
        subtract_with_carry_engine<uint_fast32_t, 24, 10, 24>;
  using ranlux48_base =
        subtract_with_carry_engine<uint_fast64_t, 48, 5, 12>;
  using ranlux24 = discard_block_engine<ranlux24_base, 223, 23>;
  using ranlux48 = discard_block_engine<ranlux48_base, 389, 11>;
  using knuth_b = shuffle_order_engine<minstd_rand0,256>;
  using default_random_engine = /* 由实现定义 */;
}

类 std::random_device

namespace std {
  class random_device {
  public:
    // 类型
    using result_type = unsigned int;

    // 生成器特征
    static constexpr result_type min() { return numeric_limits<result_type>::min(); }
    static constexpr result_type max() { return numeric_limits<result_type>::max(); }

    // 构造函数
    random_device() : random_device(/* 由实现定义 */) {}
    explicit random_device(const string& token);

    // 生成函数
    result_type operator()();

    // 属性函数
    double entropy() const noexcept;

    // 无复制函数
    random_device(const random_device&) = delete;
    void operator=(const random_device&) = delete;
  };
}

类 std::seed_seq

namespace std {
  class seed_seq {
  public:
    // 类型
    using result_type = uint_least32_t;

    // 构造函数
    seed_seq();
    template<class T>
      seed_seq(initializer_list<T> il);
    template<class InputIt>
      seed_seq(InputIt begin, InputIt end);

    // 生成函数
    template<class RandomAccessIt>
      void generate(RandomAccessIt begin, RandomAccessIt end);

    // 属性函数
    size_t size() const noexcept;
    template<class OutputIt>
      void param(OutputIt dest) const;

    // 无复制函数
    seed_seq(const seed_seq&) = delete;
    void operator=(const seed_seq&) = delete;

  private:
    vector<result_type> v;        // 仅用于阐释
  };
}

类模板 std::uniform_int_distribution

namespace std {
  template<class IntType = int>
    class uniform_int_distribution {
    public:
      // 类型
      using result_type = IntType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      uniform_int_distribution() : uniform_int_distribution(0) {}
      explicit uniform_int_distribution(IntType a,
                                        IntType b = numeric_limits<IntType>::max());
      explicit uniform_int_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      result_type a() const;
      result_type b() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::uniform_real_distribution

namespace std {
  template<class RealType = double>
    class uniform_real_distribution {
    public:
      // 类型
      using result_type = RealType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      uniform_real_distribution() : uniform_real_distribution(0.0) {}
      explicit uniform_real_distribution(RealType a, RealType b = 1.0);
      explicit uniform_real_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      result_type a() const;
      result_type b() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类 std::bernoulli_distribution

namespace std {
  class bernoulli_distribution {
  public:
    // 类型
    using result_type = bool;
    using param_type  = /* 未指明 */;

    // 构造函数与重置函数
    bernoulli_distribution() : bernoulli_distribution(0.5) {}
    explicit bernoulli_distribution(double p);
    explicit bernoulli_distribution(const param_type& parm);
    void reset();

    // 生成函数
    template<class URBG>
      result_type operator()(URBG& g);
    template<class URBG>
      result_type operator()(URBG& g, const param_type& parm);

    // 属性函数
    double p() const;
    param_type param() const;
    void param(const param_type& parm);
    result_type min() const;
    result_type max() const;
  };
}

类模板 std::binomial_distribution

namespace std {
  template<class IntType = int>
    class binomial_distribution {
    public:
      // 类型
      using result_type = IntType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      binomial_distribution() : binomial_distribution(1) {}
      explicit binomial_distribution(IntType t, double p = 0.5);
      explicit binomial_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      IntType t() const;
      double p() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::geometric_distribution

namespace std {
  template<class IntType = int>
    class geometric_distribution {
    public:
      // 类型
      using result_type = IntType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      geometric_distribution() : geometric_distribution(0.5) {}
      explicit geometric_distribution(double p);
      explicit geometric_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      double p() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::negative_binomial_distribution

namespace std {
  template<class IntType = int>
    class negative_binomial_distribution {
    public:
      // 类型
      using result_type = IntType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      negative_binomial_distribution() : negative_binomial_distribution(1) {}
      explicit negative_binomial_distribution(IntType k, double p = 0.5);
      explicit negative_binomial_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      IntType k() const;
      double p() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::poisson_distribution

namespace std {
  template<class IntType = int>
    class poisson_distribution {
    public:
      // 类型
      using result_type = IntType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      poisson_distribution() : poisson_distribution(1.0) {}
      explicit poisson_distribution(double mean);
      explicit poisson_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      double mean() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::exponential_distribution

namespace std {
  template<class RealType = double>
    class exponential_distribution {
    public:
      // 类型
      using result_type = RealType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      exponential_distribution() : exponential_distribution(1.0) {}
      explicit exponential_distribution(RealType lambda);
      explicit exponential_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      RealType lambda() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
  };
}

类模板 std::gamma_distribution

namespace std {
  template<class RealType = double>
    class gamma_distribution {
    public:
      // 类型
      using result_type = RealType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      gamma_distribution() : gamma_distribution(1.0) {}
      explicit gamma_distribution(RealType alpha, RealType beta = 1.0);
      explicit gamma_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      RealType alpha() const;
      RealType beta() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::weibull_distribution

namespace std {
  template<class RealType = double>
    class weibull_distribution {
    public:
      // 类型
      using result_type = RealType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      weibull_distribution() : weibull_distribution(1.0) {}
      explicit weibull_distribution(RealType a, RealType b = 1.0);
      explicit weibull_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      RealType a() const;
      RealType b() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::extreme_value_distribution

namespace std {
  template<class RealType = double>
    class extreme_value_distribution {
    public:
      // 类型
      using result_type = RealType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      extreme_value_distribution() : extreme_value_distribution(0.0) {}
      explicit extreme_value_distribution(RealType a, RealType b = 1.0);
      explicit extreme_value_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      RealType a() const;
      RealType b() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::normal_distribution

namespace std {
  template<class RealType = double>
    class normal_distribution {
    public:
      // 类型
      using result_type = RealType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      normal_distribution() : normal_distribution(0.0) {}
      explicit normal_distribution(RealType mean, RealType stddev = 1.0);
      explicit normal_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      RealType mean() const;
      RealType stddev() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::lognormal_distribution

namespace std {
  template<class RealType = double>
    class lognormal_distribution {
    public:
      // 类型
      using result_type = RealType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      lognormal_distribution() : lognormal_distribution(0.0) {}
      explicit lognormal_distribution(RealType m, RealType s = 1.0);
      explicit lognormal_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      RealType m() const;
      RealType s() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::chi_squared_distribution

namespace std {
  template<class RealType = double>
    class chi_squared_distribution {
    public:
      // 类型
      using result_type = RealType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      chi_squared_distribution() : chi_squared_distribution(1.0) {}
      explicit chi_squared_distribution(RealType n);
      explicit chi_squared_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      RealType n() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::cauchy_distribution

namespace std {
  template<class RealType = double>
    class cauchy_distribution {
    public:
      // 类型
      using result_type = RealType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      cauchy_distribution() : cauchy_distribution(0.0) {}
      explicit cauchy_distribution(RealType a, RealType b = 1.0);
      explicit cauchy_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      RealType a() const;
      RealType b() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };

类模板 std::fisher_f_distribution

namespace std {
  template<class RealType = double>
    class fisher_f_distribution {
    public:
      // 类型
      using result_type = RealType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      fisher_f_distribution() : fisher_f_distribution(1.0) {}
      explicit fisher_f_distribution(RealType m, RealType n = 1.0);
      explicit fisher_f_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      RealType m() const;
      RealType n() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::student_t_distribution

namespace std {
  template<class RealType = double>
    class student_t_distribution {
    public:
      // 类型
      using result_type = RealType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      student_t_distribution() : student_t_distribution(1.0) {}
      explicit student_t_distribution(RealType n);
      explicit student_t_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      RealType n() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::discrete_distribution

namespace std {
  template<class IntType = int>
    class discrete_distribution {
    public:
      // 类型
      using result_type = IntType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      discrete_distribution();
      template<class InputIt>
        discrete_distribution(InputIt firstW, InputIt lastW);
      discrete_distribution(initializer_list<double> wl);
      template<class UnaryOperation>
        discrete_distribution(size_t nw, double xmin, double xmax, UnaryOperation fw);
      explicit discrete_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      vector<double> probabilities() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::piecewise_constant_distribution

namespace std {
   template<class RealType = double>
    class piecewise_constant_distribution {
    public:
      // 类型
      using result_type = RealType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      piecewise_constant_distribution();
      template<class InputItB, class InputItW>
        piecewise_constant_distribution(InputItB firstB, InputItB lastB, InputItW firstW);
      template<class UnaryOperation>
        piecewise_constant_distribution(initializer_list<RealType> bl, UnaryOperation fw);
      template<class UnaryOperation>
        piecewise_constant_distribution(size_t nw, RealType xmin, RealType xmax,
                                        UnaryOperation fw);
      explicit piecewise_constant_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      vector<result_type> intervals() const;
      vector<result_type> densities() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}

类模板 std::piecewise_linear_distribution

namespace std {
  template<class RealType = double>
    class piecewise_linear_distribution {
    public:
      // 类型
      using result_type = RealType;
      using param_type  = /* 未指明 */;

      // 构造函数与重置函数
      piecewise_linear_distribution();
      template<class InputItB, class InputItW>
        piecewise_linear_distribution(InputItB firstB, InputItB lastB, InputItW firstW);
      template<class UnaryOperation>
        piecewise_linear_distribution(initializer_list<RealType> bl, UnaryOperation fw);
      template<class UnaryOperation>
        piecewise_linear_distribution(size_t nw, RealType xmin, RealType xmax,
                                      UnaryOperation fw);
      explicit piecewise_linear_distribution(const param_type& parm);
      void reset();

      // 生成函数
      template<class URBG>
        result_type operator()(URBG& g);
      template<class URBG>
        result_type operator()(URBG& g, const param_type& parm);

      // 属性函数
      vector<result_type> intervals() const;
      vector<result_type> densities() const;
      param_type param() const;
      void param(const param_type& parm);
      result_type min() const;
      result_type max() const;
    };
}


标准库头文件 <ranges>

< cpp‎ | header

此头文件是范围库的一部分。

命名空间别名

namespace std {

namespace views = ranges::views;

}

提供命名空间别名 std::views，作为 std::ranges::views 的简称。

概念
范围概念
定义于命名空间 std::ranges
ranges::range
(C++20)
 指定类型为范围，即它同时提供 begin 迭代器和 end 哨位
(概念)
ranges::sized_range
(C++20)
 指定范围可在常数时间内知晓其大小
(概念)
ranges::view
(C++20)
 指定范围为视图，即它拥有常数时间的复制/移动/赋值
(概念)
ranges::input_range
(C++20)
 指定范围的迭代器类型满足 input_iterator
(概念)
ranges::output_range
(C++20)
 指定范围的迭代器类型满足 output_iterator
(概念)
ranges::forward_range
(C++20)
 指定范围的迭代器类型满足 forward_iterator
(概念)
ranges::bidirectional_range
(C++20)
 指定范围的迭代器类型满足 bidirectional_iterator
(概念)
ranges::random_access_range
(C++20)
 指定范围的迭代器类型满足 random_access_iterator
(概念)
ranges::contiguous_range
(C++20)
 指定范围的迭代器类型满足 contiguous_iterator
(概念)
ranges::common_range
(C++20)
 指定范围拥有相同的迭代器和哨位类型
(概念)
ranges::viewable_range
(C++20)
 指定针对 range 的要求，令其可安全转换为 view
(概念)

类
范围原语
定义于命名空间 std::ranges
ranges::iterator_tranges::sentinel_tranges::range_difference_tranges::range_size_tranges::range_value_tranges::range_reference_tranges::range_rvalue_reference_t
(C++20)
 获得范围的关联类型
(别名模板)
视图
定义于命名空间 std::ranges
ranges::view_interface
(C++20)
 用于定义 view 的辅助类模板，使用奇异递归模板模式
(类模板)
ranges::subrange
(C++20)
 将迭代器/哨位对结合为一个 view
(类模板)
悬垂迭代器处理
定义于命名空间 std::ranges
ranges::dangling
(C++20)
 占位类型，指示不应返回迭代器或子范围，因为它可能悬垂
(类)
ranges::borrowed_iterator_tranges::borrowed_subrange_t
(C++20)
 获得塑造 borrowed_range 的迭代器类型或子范围类型
(别名模板)
工厂
定义于命名空间 std::ranges
ranges::empty_viewviews::empty
(C++20)
 无元素的空 view
(类模板) (变量模板)
ranges::single_viewviews::single
(C++20)
 含有具有指定值的单个元素的 view
(类模板) (定制点对象)
ranges::iota_viewviews::iota
(C++20)
 由通过重复对某个初值自增所生成的序列组成的 view
(类模板) (定制点对象)
views::counted
(C++20)
 从迭代器和计数创建子范围
(定制点对象)
适配器
定义于命名空间 std::ranges
views::all_tviews::all
(C++20)
 包含 range 的所有元素的 view
(别名模板) (范围适配器对象)
ranges::ref_view
(C++20)
 某个其他 range 的元素的 view
(类模板)
ranges::filter_viewviews::filter
(C++20)
 由 range 中满足某个谓词的元素构成的 view
(类模板) (范围适配器对象)
ranges::transform_viewviews::transform
(C++20)
 对序列的每个元素应用某个变换函数的 view
(类模板) (范围适配器对象)
ranges::take_viewviews::take
(C++20)
 由另一 view 的前 N 个元素组成的 view
(类模板) (范围适配器对象)
ranges::join_viewviews::join
(C++20)
 由拉平 range 的 view 所获得的序列构成的 view
(类模板) (范围适配器对象)
ranges::split_viewviews::split
(C++20)
 用某个分隔符切割另一 view 所获得的子范围的 view
(类模板) (范围适配器对象)
ranges::common_viewviews::common
(C++20)
 转换 view 为 common_range
(类模板) (范围适配器对象)
ranges::reverse_viewviews::reverse
(C++20)
 以逆序迭代另一双向视图上的元素的 view
(类模板) (范围适配器对象)

定制点对象
范围访问
定义于命名空间 std::ranges
ranges::begin
(C++20)
 返回指向范围起始的迭代器
(定制点对象)
ranges::end
(C++20)
 返回指示范围结尾的哨位
(定制点对象)
ranges::rbegin
(C++20)
 返回指向范围的逆向迭代器
(定制点对象)
ranges::rend
(C++20)
 返回指向范围的逆向尾迭代器
(定制点对象)
ranges::size
(C++20)
 返回等于范围大小的整数
(定制点对象)
ranges::empty
(C++20)
 检查范围是否为空
(定制点对象)
ranges::data
(C++20)
 获得指向连续范围的起始的指针
(定制点对象)

概要

#include <initializer_list>
#include <iterator>

namespace std::ranges {
  inline namespace /* 未指明 */ {
    // 范围访问
    inline constexpr /* 未指明 */ begin = /* 未指明 */;
    inline constexpr /* 未指明 */ end = /* 未指明 */;
    inline constexpr /* 未指明 */ cbegin = /* 未指明 */;
    inline constexpr /* 未指明 */ cend = /* 未指明 */;
    inline constexpr /* 未指明 */ rbegin = /* 未指明 */;
    inline constexpr /* 未指明 */ rend = /* 未指明 */;
    inline constexpr /* 未指明 */ crbegin = /* 未指明 */;
    inline constexpr /* 未指明 */ crend = /* 未指明 */;

    inline constexpr /* 未指明 */ size = /* 未指明 */;
    inline constexpr /* 未指明 */ empty = /* 未指明 */;
    inline constexpr /* 未指明 */ data = /* 未指明 */;
    inline constexpr /* 未指明 */ cdata = /* 未指明 */;
  }

  // 范围
  template<class T>
    using iterator_t = decltype(ranges::begin(declval<T&>()));

  template<class T>
    using sentinel_t = decltype(ranges::end(declval<T&>()));

  template<class T>
    concept Range = /* 见定义 */;

  // 有大小范围
  template<class>
    inline constexpr bool disable_sized_range = false;

  template<class T>
    concept SizedRange = /* 见定义 */;

  // 视图
  template<class T>
    inline constexpr bool enable_view = /* 见定义 */;

  struct view_base { };

  template<class T>
    concept View = /* 见定义 */;

  // 其他范围细化
  template<class R, class T>
    concept OutputRange = /* 见定义 */;

  template<class T>
    concept InputRange = /* 见定义 */;

  template<class T>
    concept ForwardRange = /* 见定义 */;

  template<class T>
    concept BidirectionalRange = /* 见定义 */;

  template<class T>
    concept RandomAccessRange = /* 见定义 */;

  template<class T>
    concept ContiguousRange = /* 见定义 */;

  template<class T>
    concept CommonRange = /* 见定义 */;

  template<class T>
    concept ViewableRange = /* 见定义 */;

  // 类模板 view_interface
  template<class D>
    requires is_class_v<D> && Same<D, remove_cv_t<D>>
  class view_interface;

  // 子范围
  enum class subrange_kind : bool { unsized, sized };

  template<Iterator I, Sentinel<I> S = I, subrange_kind K = /* 见定义 */>
    requires (K == subrange_kind::sized || !SizedSentinel<S, I>)
  class subrange;

  // 悬垂迭代器处理
  struct dangling;

  template<Range R>
    using safe_iterator_t = conditional_t<__ForwardingRange<R>, iterator_t<R>, dangling>;

  template<Range R>
    using safe_subrange_t =
      conditional_t<__ForwardingRange<R>, subrange<iterator_t<R>>, dangling>;

  // 空视图
  template<class T>
    requires is_object_v<T>
  class empty_view;

  namespace view {
    template<class T>
      inline constexpr empty_view<T> empty{};
  }

  // 单体视图
  template<CopyConstructible T>
    requires is_object_v<T>
  class single_view;

  namespace view { inline constexpr /* 未指明 */ single = /* 未指明 */; }

  // iota 视图
  template<WeaklyIncrementable W, Semiregular Bound = unreachable_sentinel_t>
    requires __WeaklyEqualityComparableWith<W, Bound>
  class iota_view;

  namespace view { inline constexpr /* 未指明 */ iota = /* 未指明 */; }

  // 全视图
  namespace view { inline constexpr /* 未指明 */ all = /* 未指明 */; }

  template<ViewableRange R>
    using all_view = decltype(view::all(declval<R>()));

  template<Range R>
    requires is_object_v<R>
  class ref_view;

  // 过滤视图
  template<InputRange V, IndirectUnaryPredicate<iterator_t<V>> Pred>
    requires View<V> && is_object_v<Pred>
  class filter_view;

  namespace view { inline constexpr /* 未指明 */ filter = /* 未指明 */; }

  // 变换视图
  template<InputRange V, CopyConstructible F>
    requires View<V> && is_object_v<F> &&
             RegularInvocable<F&, iter_reference_t<iterator_t<V>>>
  class transform_view;

  namespace view { inline constexpr /* 未指明 */ transform = /* 未指明 */; }

  // 取部分视图
  template<View> class take_view;

  namespace view { inline constexpr /* 未指明 */ take = /* 未指明 */; }

  // 连接视图
  template<InputRange V>
    requires View<V> && InputRange<iter_reference_t<iterator_t<V>>> &&
             (is_reference_v<iter_reference_t<iterator_t<V>>> ||
              View<iter_value_t<iterator_t<V>>>)
  class join_view;

  namespace view { inline constexpr /* 未指明 */ join = /* 未指明 */; }

  // 分割视图
  template<class R>
    concept __TinyRange = /* 见定义 */;   // 仅用于阐释

  template<InputRange V, ForwardRange Pattern>
    requires View<V> && View<Pattern> &&
             IndirectlyComparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
             (ForwardRange<V> || __TinyRange<Pattern>)
  class split_view;

  namespace view { inline constexpr /* 未指明 */ split = /* 未指明 */; }

  // 计数视图
  namespace view { inline constexpr /* 未指明 */ counted = /* 未指明 */; }

  // 公共视图
  template<View V>
    requires (!CommonRange<V>)
  class common_view;

  namespace view { inline constexpr /* 未指明 */ common = /* 未指明 */; }

  // 逆向视图
  template<View V>
    requires BidirectionalRange<V>
  class reverse_view;

  namespace view { inline constexpr /* 未指明 */ reverse = /* 未指明 */; }
}

namespace std {
  namespace view = ranges::view;

  template<class I, class S, ranges::subrange_kind K>
  struct tuple_size<ranges::subrange<I, S, K>>
    : integral_constant<size_t, 2> {};
  template<class I, class S, ranges::subrange_kind K>
  struct tuple_element<0, ranges::subrange<I, S, K>> {
    using type = I;
  };
  template<class I, class S, ranges::subrange_kind K>
  struct tuple_element<1, ranges::subrange<I, S, K>> {
    using type = S;
  };
}

概念 range

namespace std::ranges {
  template< class T >
    concept range = requires(T& t) {
      ranges::begin(t); // 对向前迭代器保持相等性
      ranges::end(t);
  };
}

概念 sized_range

namespace std::ranges {
  template< class T >
    concept sized_range = range<T> &&
      requires(T& t) {
        ranges::size(t);
      };
}

概念 view

namespace std::ranges {
  template<class T>
    inline constexpr bool enable_view = derived_from<T, view_base>;

  template<class T>
    concept view = range<T>
                && movable<T>
                && default_initializable<T>
                && enable_view<T>;
}

概念 output_range

namespace std::ranges {
  template<class R, class T>
    concept output_range =
      range<R> && output_iterator<iterator_t<R>, T>;
}

概念 input_range

namespace std::ranges {
  template<class T>
    concept input_range =
      range<T> && input_iterator<iterator_t<T>>;
}

概念 forward_range

namespace std::ranges {
  template<class T>
    concept forward_range =
      input_range<T> && forward_iterator<iterator_t<T>>;
}

概念 bidirectional_range

namespace std::ranges {
  template<class T>
    concept bidirectional_range =
      forward_range<T> && bidirectional_iterator<iterator_t<T>>;
}

概念 random_access_range

namespace std::ranges {
  template<class T>
    concept random_access_range =
      bidirectional_range<T> && random_access_iterator<iterator_t<T>>;
}

概念 contiguous_range

namespace std::ranges {
  template<class T>
    concept contiguous_range =
      random_access_range<T> && contiguous_iterator<iterator_t<T>> &&
        requires(T& t) {
          { ranges::data(t) } -> same_as<add_pointer_t<range_reference_t<T>>>;
        };
}

概念 common_range

namespace std::ranges {
  template<class T>
    concept common_range =
      range<T> && same_as<iterator_t<T>, sentinel_t<T>>;
}

概念 viewable_range

{{source|1= namespace std::ranges {

 template<class T>
   concept viewable_range =
     range<T> && (borrowed_range<T> || view<remove_cvref_t<T>>);

}

辅助概念

namespace std::ranges { // 未指定，仅用于名字查找
  template<class R>
    concept __SimpleView =                        // 仅用于阐释
      View<R> && Range<const R> &&
      Same<iterator_t<R>, iterator_t<const R>> &&
      Same<sentinel_t<R>, sentinel_t<const R>>;

  template<InputIterator I>
    concept __HasArrow =                          // 仅用于阐释
      is_pointer_v<I> || requires(I i) { i.operator->(); };

  template<class T, class U>
    concept __NotSameAs =                         // 仅用于阐释
      !Same<remove_cvref_t<T>, remove_cvref_t<U>>;

  template<class I>
    concept _Decrementable =                      // 仅用于阐释
      Incrementable<I> && requires(I i) {
        { --i } -> Same<I&>;
        { i-- } -> Same<I>;
      };

  template<class I>
    concept _Advanceable =                        // 仅用于阐释
      _Decrementable<I> && StrictTotallyOrdered<I> &&
      requires(I i, const I j, const iter_difference_t<I> n) {
        { i += n } -> Same<I&>;
        { i -= n } -> Same<I&>;
        { j +  n } -> Same<I>;
        { n +  j } -> Same<I>;
        { j -  n } -> Same<I>;
        { j -  j } -> Same<iter_difference_t<I>>;
      };
}

注意：这些名字仅用于阐释目的，它们不是接口的一部分。

类模板 std::ranges::view_interface

namespace std::ranges {
  template<class D>
    requires is_class_v<D> && Same<D, remove_cv_t<D>>
  class view_interface : public view_base {
  private:
    constexpr D& derived() noexcept {                   // 仅用于阐释
      return static_cast<D&>(*this);
    }
    constexpr const D& derived() const noexcept {       // 仅用于阐释
      return static_cast<const D&>(*this);
    }
  public:
    constexpr bool empty() requires ForwardRange<D> {
      return ranges::begin(derived()) == ranges::end(derived());
    }
    constexpr bool empty() const requires ForwardRange<const D> {
      return ranges::begin(derived()) == ranges::end(derived());
    }

    constexpr explicit operator bool()
      requires requires { ranges::empty(derived()); } {
        return !ranges::empty(derived());
      }
    constexpr explicit operator bool() const
      requires requires { ranges::empty(derived()); } {
        return !ranges::empty(derived());
      }

    constexpr auto data() requires ContiguousIterator<iterator_t<D>> {
      return ranges::empty(derived()) ? nullptr : addressof(*ranges::begin(derived()));
    }
    constexpr auto data() const
      requires Range<const D> && ContiguousIterator<iterator_t<const D>> {
        return ranges::empty(derived()) ? nullptr : addressof(*ranges::begin(derived()));
      }

    constexpr auto size() requires ForwardRange<D> &&
      SizedSentinel<sentinel_t<D>, iterator_t<D>> {
        return ranges::end(derived()) - ranges::begin(derived());
      }
    constexpr auto size() const requires ForwardRange<const D> &&
      SizedSentinel<sentinel_t<const D>, iterator_t<const D>> {
        return ranges::end(derived()) - ranges::begin(derived());
      }

    constexpr decltype(auto) front() requires ForwardRange<D>;
    constexpr decltype(auto) front() const requires ForwardRange<const D>;

    constexpr decltype(auto) back() requires BidirectionalRange<D> && CommonRange<D>;
    constexpr decltype(auto) back() const
      requires BidirectionalRange<const D> && CommonRange<const D>;

    template<RandomAccessRange R = D>
      constexpr decltype(auto) operator[](iter_difference_t<iterator_t<R>> n) {
        return ranges::begin(derived())[n];
      }
    template<RandomAccessRange R = const D>
      constexpr decltype(auto) operator[](iter_difference_t<iterator_t<R>> n) const {
        return ranges::begin(derived())[n];
      }
  };
}

类模板 std::ranges::subrange

namespace std::ranges {
  template<class T>
    concept __PairLike =                                // 仅用于阐释
      !is_reference_v<T> && requires(T t) {
        typename tuple_size<T>::type;   // 确保 tuple_size<T> 完整
        requires DerivedFrom<tuple_size<T>, integral_constant<size_t, 2>>;
        typename tuple_element_t<0, remove_const_t<T>>;
        typename tuple_element_t<1, remove_const_t<T>>;
        { get<0>(t) } -> const tuple_element_t<0, T>&;
        { get<1>(t) } -> const tuple_element_t<1, T>&;
      };

  template<class T, class U, class V>
    concept __PairLikeConvertibleTo =                   // 仅用于阐释
      !Range<T> && __PairLike<remove_reference_t<T>> &&
      requires(T&& t) {
        { get<0>(std::forward<T>(t)) } -> ConvertibleTo<U>;
        { get<1>(std::forward<T>(t)) } -> ConvertibleTo<V>;
      };

  template<class T, class U, class V>
    concept __PairLikeConvertibleFrom =                 // 仅用于阐释
      !Range<T> && __PairLike<T> && Constructible<T, U, V>;

  template<class T>
    concept __IteratorSentinelPair =                    // 仅用于阐释
      !Range<T> && __PairLike<T> &&
      Sentinel<tuple_element_t<1, T>, tuple_element_t<0, T>>;

  template<Iterator I, Sentinel<I> S = I, subrange_kind K =
      SizedSentinel<S, I> ? subrange_kind::sized : subrange_kind::unsized>
    requires (K == subrange_kind::sized || !SizedSentinel<S, I>)
  class subrange : public view_interface<subrange<I, S, K>> {
  private:
    static constexpr bool StoreSize =                   // 仅用于阐释
      K == subrange_kind::sized && !SizedSentinel<S, I>;
    I begin_ = I();                                     // 仅用于阐释
    S end_ = S();                                       // 仅用于阐释
    iter_difference_t<I> size_ = 0;                     // 仅用于阐释；
                                                        // 仅当 StoreSize 为 true 时才存在
  public:
    subrange() = default;

    constexpr subrange(I i, S s) requires (!StoreSize);

    constexpr subrange(I i, S s, iter_difference_t<I> n)
      requires (K == subrange_kind::sized);

    template<__NotSameAs<subrange> R>
      requires __ForwardingRange<R> &&
        ConvertibleTo<iterator_t<R>, I> && ConvertibleTo<sentinel_t<R>, S>
    constexpr subrange(R&& r) requires (!StoreSize || SizedRange<R>);

    template<__ForwardingRange R>
      requires ConvertibleTo<iterator_t<R>, I> && ConvertibleTo<sentinel_t<R>, S>
    constexpr subrange(R&& r, iter_difference_t<I> n)
      requires (K == subrange_kind::sized)
        : subrange{ranges::begin(r), ranges::end(r), n}
    {}

    template<__NotSameAs<subrange> PairLike>
      requires __PairLikeConvertibleTo<PairLike, I, S>
    constexpr subrange(PairLike&& r) requires (!StoreSize)
      : subrange{std::get<0>(std::forward<PairLike>(r)),
                 std::get<1>(std::forward<PairLike>(r))}
    {}

    template<__PairLikeConvertibleTo<I, S> PairLike>
    constexpr subrange(PairLike&& r, iter_difference_t<I> n)
      requires (K == subrange_kind::sized)
      : subrange{std::get<0>(std::forward<PairLike>(r)),
                 std::get<1>(std::forward<PairLike>(r)), n}
    {}

    template<__NotSameAs<subrange> PairLike>
      requires __PairLikeConvertibleFrom<PairLike, const I&, const S&>
    constexpr operator PairLike() const;

    constexpr I begin() const;
    constexpr S end() const;

    constexpr bool empty() const;
    constexpr iter_difference_t<I> size() const
      requires (K == subrange_kind::sized);

    [[nodiscard]] constexpr subrange next(iter_difference_t<I> n = 1) const;
    [[nodiscard]] constexpr subrange prev(iter_difference_t<I> n = 1) const
      requires BidirectionalIterator<I>;
    constexpr subrange& advance(iter_difference_t<I> n);

    friend constexpr I begin(subrange&& r) { return r.begin(); }
    friend constexpr S end(subrange&& r) { return r.end(); }
  };

  template<Iterator I, Sentinel<I> S>
    subrange(I, S, iter_difference_t<I>) -> subrange<I, S, subrange_kind::sized>;

  template<__IteratorSentinelPair P>
    subrange(P) -> subrange<tuple_element_t<0, P>, tuple_element_t<1, P>>;

  template<__IteratorSentinelPair P>
    subrange(P, iter_difference_t<tuple_element_t<0, P>>) ->
      subrange<tuple_element_t<0, P>, tuple_element_t<1, P>, subrange_kind::sized>;

  template<__ForwardingRange R>
    subrange(R&&) ->
      subrange<iterator_t<R>, sentinel_t<R>,
               (SizedRange<R> || SizedSentinel<sentinel_t<R>, iterator_t<R>>)
                 ? subrange_kind::sized : subrange_kind::unsized>;

  template<__ForwardingRange R>
    subrange(R&&, iter_difference_t<iterator_t<R>>) ->
      subrange<iterator_t<R>, sentinel_t<R>, subrange_kind::sized>;

  template<size_t N, class I, class S, subrange_kind K>
    requires (N < 2)
  constexpr auto get(const subrange<I, S, K>& r);
}

namespace std {
  using ranges::get;
}

类 std::ranges::dangling

namespace std::ranges {
  struct dangling {
    constexpr dangling() noexcept = default;
    template<class... Args>
      constexpr dangling(Args&&...) noexcept { }
  };
}

类模板 std::ranges::empty_view

namespace std::ranges {
  template<class T>
    requires is_object_v<T>
  class empty_view : public view_interface<empty_view<T>> {
  public:
    static constexpr T* begin() noexcept { return nullptr; }
    static constexpr T* end() noexcept { return nullptr; }
    static constexpr T* data() noexcept { return nullptr; }
    static constexpr ptrdiff_t size() noexcept { return 0; }
    static constexpr bool empty() noexcept { return true; }

    friend constexpr T* begin(empty_view) noexcept { return nullptr; }
    friend constexpr T* end(empty_view) noexcept { return nullptr; }
  };
}

类模板 std::ranges::empty_view

namespace std::ranges {
  template<CopyConstructible T>
    requires is_object_v<T>
  class single_view : public view_interface<single_view<T>> {
  private:
    semiregular_box<T> value_;  // 仅用于阐释
  public:
    single_view() = default;
    constexpr explicit single_view(const T& t);
    constexpr explicit single_view(T&& t);
    template<class... Args>
      requires Constructible<T, Args...>
    constexpr single_view(in_place_t, Args&&... args);

    constexpr T* begin() noexcept;
    constexpr const T* begin() const noexcept;
    constexpr T* end() noexcept;
    constexpr const T* end() const noexcept;
    static constexpr ptrdiff_t size() noexcept;
    constexpr T* data() noexcept;
    constexpr const T* data() const noexcept;
  };
}

类模板 std::ranges::iota_view

namespace std::ranges {
  template<class I>
    concept _Decrementable =    // 仅用于阐释
      /* 见定义 */;
  template<class I>
    concept _Advanceable =      // 仅用于阐释
      /* 见定义 */;

  template<WeaklyIncrementable W, Semiregular Bound = unreachable_sentinel_t>
    requires __WeaklyEqualityComparableWith<W, Bound>
  class iota_view : public view_interface<iota_view<W, Bound>> {
  private:
    // 类 iota_view​::​iterator
    struct iterator;            // 仅用于阐释
    // 类 iota_view​::​sentinel
    struct sentinel;            // 仅用于阐释
    W value_ = W();             // 仅用于阐释
    Bound bound_ = Bound();     // 仅用于阐释
  public:
    iota_view() = default;
    constexpr explicit iota_view(W value);
    constexpr iota_view(type_identity_t<W> value,
                        type_identity_t<Bound> bound);

    constexpr iterator begin() const;
    constexpr sentinel end() const;
    constexpr iterator end() const requires Same<W, Bound>;

    constexpr auto size() const
      requires (Same<W, Bound> && _Advanceable<W>) ||
               (Integral<W> && Integral<Bound>) ||
               SizedSentinel<Bound, W>
    { return bound_ - value_; }
  };

  template<class W, class Bound>
    requires (!Integral<W> || !Integral<Bound> || is_signed_v<W> == is_signed_v<Bound>)
  iota_view(W, Bound) -> iota_view<W, Bound>;
}

类 std::ranges::iota_view::iterator

namespace std::ranges {
  template<class W, class Bound>
  struct iota_view<W, Bound>::iterator {
  private:
    W value_ = W();             // 仅用于阐释
  public:
    using iterator_category = /* 见定义 */;
    using value_type = W;
    using difference_type = iter_difference_t<W>;

    iterator() = default;
    constexpr explicit iterator(W value);

    constexpr W operator*() const noexcept(is_nothrow_copy_constructible_v<W>);

    constexpr iterator& operator++();
    constexpr void operator++(int);
    constexpr iterator operator++(int) requires Incrementable<W>;

    constexpr iterator& operator--() requires _Decrementable<W>;
    constexpr iterator operator--(int) requires _Decrementable<W>;

    constexpr iterator& operator+=(difference_type n)
      requires _Advanceable<W>;
    constexpr iterator& operator-=(difference_type n)
      requires _Advanceable<W>;
    constexpr W operator[](difference_type n) const
      requires _Advanceable<W>;

    friend constexpr bool operator==(const iterator& x, const iterator& y)
      requires EqualityComparable<W>;
    friend constexpr bool operator!=(const iterator& x, const iterator& y)
      requires EqualityComparable<W>;

    friend constexpr bool operator<(const iterator& x, const iterator& y)
      requires StrictTotallyOrdered<W>;
    friend constexpr bool operator>(const iterator& x, const iterator& y)
      requires StrictTotallyOrdered<W>;
    friend constexpr bool operator<=(const iterator& x, const iterator& y)
      requires StrictTotallyOrdered<W>;
    friend constexpr bool operator>=(const iterator& x, const iterator& y)
      requires StrictTotallyOrdered<W>;

    friend constexpr iterator operator+(iterator i, difference_type n)
      requires _Advanceable<W>;
    friend constexpr iterator operator+(difference_type n, iterator i)
      requires _Advanceable<W>;

    friend constexpr iterator operator-(iterator i, difference_type n)
      requires _Advanceable<W>;
    friend constexpr difference_type operator-(const iterator& x, const iterator& y)
      requires _Advanceable<W>;
  };
}

类 std::ranges::iota_view::sentinel

namespace std::ranges {
  template<class W, class Bound>
  struct iota_view<W, Bound>::sentinel {
  private:
    Bound bound_ = Bound();     // 仅用于阐释
  public:
    sentinel() = default;
    constexpr explicit sentinel(Bound bound);

    friend constexpr bool operator==(const iterator& x, const sentinel& y);
    friend constexpr bool operator==(const sentinel& x, const iterator& y);
    friend constexpr bool operator!=(const iterator& x, const sentinel& y);
    friend constexpr bool operator!=(const sentinel& x, const iterator& y);
  };
}

类模板 std::ranges::ref_view

namespace std::ranges {
  template<Range R>
    requires is_object_v<R>
  class ref_view : public view_interface<ref_view<R>> {
  private:
    R* r_ = nullptr;            // 仅用于阐释
  public:
    constexpr ref_view() noexcept = default;

    template<__NotSameAs<ref_view> T>
      requires /* 见定义 */
    constexpr ref_view(T&& t);

    constexpr R& base() const { return *r_; }

    constexpr iterator_t<R> begin() const { return ranges::begin(*r_); }
    constexpr sentinel_t<R> end() const { return ranges::end(*r_); }

    constexpr bool empty() const
      requires requires { ranges::empty(*r_); }
    { return ranges::empty(*r_); }

    constexpr auto size() const requires SizedRange<R>
    { return ranges::size(*r_); }

    constexpr auto data() const requires ContiguousRange<R>
    { return ranges::data(*r_); }

    friend constexpr iterator_t<R> begin(ref_view r)
    { return r.begin(); }

    friend constexpr sentinel_t<R> end(ref_view r)
    { return r.end(); }
  };
  template<class R>
    ref_view(R&) -> ref_view<R>;
}

类模板 std::ranges::filter_view

namespace std::ranges {
  template<InputRange V, IndirectUnaryPredicate<iterator_t<V>> Pred>
    requires View<V> && is_object_v<Pred>
  class filter_view : public view_interface<filter_view<V, Pred>> {
  private:
    V base_ = V();                  // 仅用于阐释
    semiregular_box<Pred> pred_;    // 仅用于阐释

    // 类 filter_view​::​iterator
    class iterator;                 // 仅用于阐释
    // 类 filter_view​::​sentinel
    class sentinel;                 // 仅用于阐释

  public:
    filter_view() = default;
    constexpr filter_view(V base, Pred pred);
    template<InputRange R>
      requires ViewableRange<R> && Constructible<V, all_view<R>>
    constexpr filter_view(R&& r, Pred pred);

    constexpr V base() const;

    constexpr iterator begin();
    constexpr auto end() {
      if constexpr (CommonRange<V>)
        return iterator{*this, ranges::end(base_)};
      else
        return sentinel{*this};
    }
  };

  template<class R, class Pred>
    filter_view(R&&, Pred) -> filter_view<all_view<R>, Pred>;
}

类 std::ranges::filter_view::iterator

namespace std::ranges {
  template<class V, class Pred>
  class filter_view<V, Pred>::iterator {
  private:
    iterator_t<V> current_ = iterator_t<V>();   // 仅用于阐释
    filter_view* parent_ = nullptr;             // 仅用于阐释
  public:
    using iterator_concept  = /* 见定义 */;
    using iterator_category = /* 见定义 */;
    using value_type        = iter_value_t<iterator_t<V>>;
    using difference_type   = iter_difference_t<iterator_t<V>>;

    iterator() = default;
    constexpr iterator(filter_view& parent, iterator_t<V> current);

    constexpr iterator_t<V> base() const;
    constexpr iter_reference_t<iterator_t<V>> operator*() const;
    constexpr iterator_t<V> operator->() const
      requires has-arrow<iterator_t<V>>;

    constexpr iterator& operator++();
    constexpr void operator++(int);
    constexpr iterator operator++(int) requires ForwardRange<V>;

    constexpr iterator& operator--() requires BidirectionalRange<V>;
    constexpr iterator operator--(int) requires BidirectionalRange<V>;

    friend constexpr bool operator==(const iterator& x, const iterator& y)
      requires EqualityComparable<iterator_t<V>>;
    friend constexpr bool operator!=(const iterator& x, const iterator& y)
      requires EqualityComparable<iterator_t<V>>;

    friend constexpr iter_rvalue_reference_t<iterator_t<V>> iter_move(const iterator& i)
      noexcept(noexcept(ranges::iter_move(i.current_)));
    friend constexpr void iter_swap(const iterator& x, const iterator& y)
      noexcept(noexcept(ranges::iter_swap(x.current_, y.current_)))
      requires IndirectlySwappable<iterator_t<V>>;
  };
}

类 std::ranges::filter_view::sentinel

namespace std::ranges {
  template<class V, class Pred>
  class filter_view<V, Pred>::sentinel {
  private:
    sentinel_t<V> end_ = sentinel_t<V>();       // 仅用于阐释
  public:
    sentinel() = default;
    constexpr explicit sentinel(filter_view& parent);

    constexpr sentinel_t<V> base() const;

    friend constexpr bool operator==(const iterator& x, const sentinel& y);
    friend constexpr bool operator==(const sentinel& x, const iterator& y);
    friend constexpr bool operator!=(const iterator& x, const sentinel& y);
    friend constexpr bool operator!=(const sentinel& x, const iterator& y);
  };
}

类模板 std::ranges::transform_view

namespace std::ranges {
  template<InputRange V, CopyConstructible F>
    requires View<V> && is_object_v<F> &&
             RegularInvocable<F&, iter_reference_t<iterator_t<V>>>
  class transform_view : public view_interface<transform_view<V, F>> {
  private:
    // 类模板 transform_view​::​iterator
    template<bool> struct iterator;             // 仅用于阐释
    // 类模板 transform_view​::​sentinel
    template<bool> struct sentinel;             // 仅用于阐释

    V base_ = V();                              // 仅用于阐释
    semiregular_box<F> fun_;                    // 仅用于阐释

  public:
    transform_view() = default;
    constexpr transform_view(V base, F fun);
    template<InputRange R>
      requires ViewableRange<R> && Constructible<V, all_view<R>>
    constexpr transform_view(R&& r, F fun);

    constexpr V base() const;

    constexpr iterator<false> begin();
    constexpr iterator<true> begin() const
      requires Range<const V> &&
               RegularInvocable<const F&, iter_reference_t<iterator_t<const V>>>;

    constexpr sentinel<false> end();
    constexpr iterator<false> end() requires CommonRange<V>;
    constexpr sentinel<true> end() const
      requires Range<const V> &&
               RegularInvocable<const F&, iter_reference_t<iterator_t<const V>>>;
    constexpr iterator<true> end() const
      requires CommonRange<const V> &&
               RegularInvocable<const F&, iter_reference_t<iterator_t<const V>>>;

    constexpr auto size() requires SizedRange<V> { return ranges::size(base_); }
    constexpr auto size() const requires SizedRange<const V>
    { return ranges::size(base_); }
  };

  template<class R, class F>
    transform_view(R&&, F) -> transform_view<all_view<R>, F>;
}

类模板 std::ranges::transform_view::iterator

namespace std::ranges {
  template<class V, class F>
  template<bool Const>
  class transform_view<V, F>::iterator {
  private:
    using Parent =                              // 仅用于阐释
      conditional_t<Const, const transform_view, transform_view>;
    using Base   =                              // 仅用于阐释
      conditional_t<Const, const V, V>;
    iterator_t<Base> current_ =                 // 仅用于阐释
      iterator_t<Base>();
    Parent* parent_ = nullptr;                  // 仅用于阐释
  public:
    using iterator_concept  = /* 见定义 */;
    using iterator_category = /* 见定义 */;
    using value_type        =
      remove_cvref_t<invoke_result_t<F&, iter_reference_t<iterator_t<Base>>>>;
    using difference_type   = iter_difference_t<iterator_t<Base>>;

    iterator() = default;
    constexpr iterator(Parent& parent, iterator_t<Base> current);
    constexpr iterator(iterator<!Const> i)
      requires Const && ConvertibleTo<iterator_t<V>, iterator_t<Base>>;

    constexpr iterator_t<Base> base() const;
    constexpr decltype(auto) operator*() const
    { return invoke(*parent_->fun_, *current_); }

    constexpr iterator& operator++();
    constexpr void operator++(int);
    constexpr iterator operator++(int) requires ForwardRange<Base>;

    constexpr iterator& operator--() requires BidirectionalRange<Base>;
    constexpr iterator operator--(int) requires BidirectionalRange<Base>;

    constexpr iterator& operator+=(difference_type n)
      requires RandomAccessRange<Base>;
    constexpr iterator& operator-=(difference_type n)
      requires RandomAccessRange<Base>;
    constexpr decltype(auto) operator[](difference_type n) const
      requires RandomAccessRange<Base>
    { return invoke(*parent_->fun_, current_[n]); }

    friend constexpr bool operator==(const iterator& x, const iterator& y)
      requires EqualityComparable<iterator_t<Base>>;
    friend constexpr bool operator!=(const iterator& x, const iterator& y)
      requires EqualityComparable<iterator_t<Base>>;

    friend constexpr bool operator<(const iterator& x, const iterator& y)
      requires RandomAccessRange<Base>;
    friend constexpr bool operator>(const iterator& x, const iterator& y)
      requires RandomAccessRange<Base>;
    friend constexpr bool operator<=(const iterator& x, const iterator& y)
      requires RandomAccessRange<Base>;
    friend constexpr bool operator>=(const iterator& x, const iterator& y)
      requires RandomAccessRange<Base>;

    friend constexpr iterator operator+(iterator i, difference_type n)
      requires RandomAccessRange<Base>;
    friend constexpr iterator operator+(difference_type n, iterator i)
      requires RandomAccessRange<Base>;

    friend constexpr iterator operator-(iterator i, difference_type n)
      requires RandomAccessRange<Base>;
    friend constexpr difference_type operator-(const iterator& x, const iterator& y)
      requires RandomAccessRange<Base>;

    friend constexpr decltype(auto) iter_move(const iterator& i)
      noexcept(noexcept(invoke(*i.parent_->fun_, *i.current_)))
    {
      if constexpr (is_lvalue_reference_v<decltype(*i)>)
        return std::move(*i);
      else
        return *i;
    }

    friend constexpr void iter_swap(const iterator& x, const iterator& y)
      noexcept(noexcept(ranges::iter_swap(x.current_, y.current_)))
      requires IndirectlySwappable<iterator_t<Base>>;
  };
}

类模板 std::ranges::transform_view::sentinel

namespace std::ranges {
  template<class V, class F>
  template<bool Const>
  class transform_view<V, F>::sentinel {
  private:
    using Parent =                                      // 仅用于阐释
      conditional_t<Const, const transform_view, transform_view>;
    using Base = conditional_t<Const, const V, V>;      // 仅用于阐释
    sentinel_t<Base> end_ = sentinel_t<Base>();         // 仅用于阐释
  public:
    sentinel() = default;
    constexpr explicit sentinel(sentinel_t<Base> end);
    constexpr sentinel(sentinel<!Const> i)
      requires Const && ConvertibleTo<sentinel_t<V>, sentinel_t<Base>>;

    constexpr sentinel_t<Base> base() const;

    friend constexpr bool operator==(const iterator<Const>& x, const sentinel& y);
    friend constexpr bool operator==(const sentinel& x, const iterator<Const>& y);
    friend constexpr bool operator!=(const iterator<Const>& x, const sentinel& y);
    friend constexpr bool operator!=(const sentinel& x, const iterator<Const>& y);

    friend constexpr iter_difference_t<iterator_t<Base>>
      operator-(const iterator<Const>& x, const sentinel& y)
        requires SizedSentinel<sentinel_t<Base>, iterator_t<Base>>;
    friend constexpr iter_difference_t<iterator_t<Base>>
      operator-(const sentinel& y, const iterator<Const>& x)
        requires SizedSentinel<sentinel_t<Base>, iterator_t<Base>>;
  };
}

类模板 std::ranges::take_view

namespace std::ranges {
  template<View V>
  class take_view : public view_interface<take_view<V>> {
  private:
    V base_ = V();                                      // 仅用于阐释
    iter_difference_t<iterator_t<V>> count_ = 0;        // 仅用于阐释
    // 类模板 take_view​::​sentinel
    template<bool> struct sentinel;                     // 仅用于阐释
  public:
    take_view() = default;
    constexpr take_view(V base, iter_difference_t<iterator_t<V>> count);
    template<ViewableRange R>
      requires Constructible<V, all_view<R>>
    constexpr take_view(R&& r, iter_difference_t<iterator_t<V>> count);

    constexpr V base() const;

    constexpr auto begin() requires (!__SimpleView<V>) {
      if constexpr (SizedRange<V>) {
        if constexpr (RandomAccessRange<V>)
          return ranges::begin(base_);
        else
          return counted_iterator{ranges::begin(base_), size()};
      } else
        return counted_iterator{ranges::begin(base_), count_};
    }

    constexpr auto begin() const requires Range<const V> {
      if constexpr (SizedRange<const V>) {
        if constexpr (RandomAccessRange<const V>)
          return ranges::begin(base_);
        else
          return counted_iterator{ranges::begin(base_), size()};
      } else
        return counted_iterator{ranges::begin(base_), count_};
    }

    constexpr auto end() requires (!__SimpleView<V>) {
      if constexpr (SizedRange<V>) {
        if constexpr (RandomAccessRange<V>)
          return ranges::begin(base_) + size();
        else
          return default_sentinel;
      } else
        return sentinel<false>{ranges::end(base_)};
    }

    constexpr auto end() const requires Range<const V> {
      if constexpr (SizedRange<const V>) {
        if constexpr (RandomAccessRange<const V>)
          return ranges::begin(base_) + size();
        else
          return default_sentinel;
      } else
        return sentinel<true>{ranges::end(base_)};
    }

    constexpr auto size() requires SizedRange<V> {
      auto n = ranges::size(base_);
      return ranges::min(n, static_cast<decltype(n)>(count_));
    }

    constexpr auto size() const requires SizedRange<const V> {
      auto n = ranges::size(base_);
      return ranges::min(n, static_cast<decltype(n)>(count_));
    }
  };

  template<Range R>
    take_view(R&&, iter_difference_t<iterator_t<R>>)
      -> take_view<all_view<R>>;
}

类模板 std::ranges::take_view::sentinel

namespace std::ranges {
  template<class V>
  template<bool Const>
  class take_view<V>::sentinel {
  private:
    using Base = conditional_t<Const, const V, V>;      // 仅用于阐释
    using CI = counted_iterator<iterator_t<Base>>;      // 仅用于阐释
    sentinel_t<Base> end_ = sentinel_t<Base>();         // 仅用于阐释
  public:
    sentinel() = default;
    constexpr explicit sentinel(sentinel_t<Base> end);
    constexpr sentinel(sentinel<!Const> s)
      requires Const && ConvertibleTo<sentinel_t<V>, sentinel_t<Base>>;

    constexpr sentinel_t<Base> base() const;

    friend constexpr bool operator==(const sentinel& x, const CI& y);
    friend constexpr bool operator==(const CI& y, const sentinel& x);
    friend constexpr bool operator!=(const sentinel& x, const CI& y);
    friend constexpr bool operator!=(const CI& y, const sentinel& x);
  };
}

类模板 std::ranges::join_view

namespace std::ranges {
  template<InputRange V>
    requires View<V> && InputRange<iter_reference_t<iterator_t<V>>> &&
             (is_reference_v<iter_reference_t<iterator_t<V>>> ||
              View<iter_value_t<iterator_t<V>>>)
  class join_view : public view_interface<join_view<V>> {
  private:
    using InnerRng =                    // 仅用于阐释
      iter_reference_t<iterator_t<V>>;
    // 类模板 join_view​::​iterator
    template<bool Const>
      struct iterator;                  // 仅用于阐释
    // 类模板 join_view​::​sentinel
    template<bool Const>
      struct sentinel;                  // 仅用于阐释

    V base_ = V();                      // 仅用于阐释
    all_view<InnerRng> inner_ =         // 仅用于阐释，
      all_view<InnerRng>();             // 仅当 !is_reference_v<InnerRng> 时才存在
  public:
    join_view() = default;
    constexpr explicit join_view(V base);

    template<InputRange R>
      requires ViewableRange<R> && Constructible<V, all_view<R>>
    constexpr explicit join_view(R&& r);

    constexpr auto begin() {
      return iterator<__SimpleView<V>>{*this, ranges::begin(base_)};
    }

    constexpr auto begin() const
    requires InputRange<const V> &&
             is_reference_v<iter_reference_t<iterator_t<const V>>> {
      return iterator<true>{*this, ranges::begin(base_)};
    }

    constexpr auto end() {
      if constexpr (ForwardRange<V> &&
                    is_reference_v<InnerRng> && ForwardRange<InnerRng> &&
                    CommonRange<V> && CommonRange<InnerRng>)
        return iterator<__SimpleView<V>>{*this, ranges::end(base_)};
      else
        return sentinel<__SimpleView<V>>{*this};
    }

    constexpr auto end() const
    requires InputRange<const V> &&
             is_reference_v<iter_reference_t<iterator_t<const V>>> {
      if constexpr (ForwardRange<const V> &&
                    is_reference_v<iter_reference_t<iterator_t<const V>>> &&
                    ForwardRange<iter_reference_t<iterator_t<const V>>> &&
                    CommonRange<const V> &&
                    CommonRange<iter_reference_t<iterator_t<const V>>>)
        return iterator<true>{*this, ranges::end(base_)};
      else
        return sentinel<true>{*this};
    }
  };

  template<class R>
    explicit join_view(R&&) -> join_view<all_view<R>>;
}

类模板 std::ranges::join_view::iterator

namespace std::ranges {
template<class V>
  template<bool Const>
  struct join_view<V>::iterator {
  private:
    using Parent =                                              // 仅用于阐释
      conditional_t<Const, const join_view, join_view>;
    using Base   = conditional_t<Const, const V, V>;            // 仅用于阐释

    static constexpr bool ref_is_glvalue =                      // 仅用于阐释
      is_reference_v<iter_reference_t<iterator_t<Base>>>;

    iterator_t<Base> outer_ = iterator_t<Base>();               // 仅用于阐释
    iterator_t<iter_reference_t<iterator_t<Base>>> inner_ =     // 仅用于阐释
      iterator_t<iter_reference_t<iterator_t<Base>>>();
    Parent* parent_ = nullptr;                                  // 仅用于阐释

    constexpr void satisfy();                                   // 仅用于阐释
  public:
    using iterator_concept  = /* 见定义 */;
    using iterator_category = /* 见定义 */;
    using value_type        =
      iter_value_t<iterator_t<iter_reference_t<iterator_t<Base>>>>;
    using difference_type   = /* 见定义 */;

    iterator() = default;
    constexpr iterator(Parent& parent, iterator_t<V> outer);
    constexpr iterator(iterator<!Const> i)
      requires Const &&
               ConvertibleTo<iterator_t<V>, iterator_t<Base>> &&
               ConvertibleTo<iterator_t<InnerRng>,
                             iterator_t<iter_reference_t<iterator_t<Base>>>>;

    constexpr decltype(auto) operator*() const { return *inner_; }

    constexpr iterator_t<Base> operator->() const
      requires __HasArrow<iterator_t<Base>>;

    constexpr iterator& operator++();
    constexpr void operator++(int);
    constexpr iterator operator++(int)
      requires ref_is_glvalue && ForwardRange<Base> &&
               ForwardRange<iter_reference_t<iterator_t<Base>>>;

    constexpr iterator& operator--()
      requires ref_is_glvalue && BidirectionalRange<Base> &&
               BidirectionalRange<iter_reference_t<iterator_t<Base>>>;

    constexpr iterator operator--(int)
      requires ref_is_glvalue && BidirectionalRange<Base> &&
               BidirectionalRange<iter_reference_t<iterator_t<Base>>>;

    friend constexpr bool operator==(const iterator& x, const iterator& y)
      requires ref_is_glvalue && EqualityComparable<iterator_t<Base>> &&
               EqualityComparable<iterator_t<iter_reference_t<iterator_t<Base>>>>;

    friend constexpr bool operator!=(const iterator& x, const iterator& y)
      requires ref_is_glvalue && EqualityComparable<iterator_t<Base>> &&
               EqualityComparable<iterator_t<iter_reference_t<iterator_t<Base>>>>;

    friend constexpr decltype(auto) iter_move(const iterator& i)
    noexcept(noexcept(ranges::iter_move(i.inner_))) {
      return ranges::iter_move(i.inner_);
    }

    friend constexpr void iter_swap(const iterator& x, const iterator& y)
      noexcept(noexcept(ranges::iter_swap(x.inner_, y.inner_)));
  };
}

类模板 std::ranges::join_view::sentinel

namespace std::ranges {
  template<class V>
  template<bool Const>
  struct join_view<V>::sentinel {
  private:
    using Parent =                                      // 仅用于阐释
      conditional_t<Const, const join_view, join_view>;
    using Base   = conditional_t<Const, const V, V>;    // 仅用于阐释
    sentinel_t<Base> end_ = sentinel_t<Base>();         // 仅用于阐释
  public:
    sentinel() = default;

    constexpr explicit sentinel(Parent& parent);
    constexpr sentinel(sentinel<!Const> s)
      requires Const && ConvertibleTo<sentinel_t<V>, sentinel_t<Base>>;

    friend constexpr bool operator==(const iterator<Const>& x, const sentinel& y);
    friend constexpr bool operator==(const sentinel& x, const iterator<Const>& y);
    friend constexpr bool operator!=(const iterator<Const>& x, const sentinel& y);
    friend constexpr bool operator!=(const sentinel& x, const iterator<Const>& y);
  };
}

类模板 std::ranges::split_view

namespace std::ranges {
  template<auto> struct __require_constant;     // 仅用于阐释

  template<class R>
  concept __TinyRange =                         // 仅用于阐释
    SizedRange<R> &&
    requires { typename __require_constant<remove_reference_t<R>::size()>; } &&
    (remove_reference_t<R>::size() <= 1);

  template<InputRange V, ForwardRange Pattern>
    requires View<V> && View<Pattern> &&
             IndirectlyComparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
             (ForwardRange<V> || __TinyRange<Pattern>)
  class split_view : public view_interface<split_view<V, Pattern>> {
  private:
    V base_ = V();                              // 仅用于阐释
    Pattern pattern_ = Pattern();               // 仅用于阐释
    iterator_t<V> current_ = iterator_t<V>();   // 仅用于阐释，
                                                // 仅当 !ForwardRange<V> 时才存在
    // 类模板 split_view​::​outer_iterator
    template<bool> struct outer_iterator;       // 仅用于阐释
    // 类模板 split_view​::​inner_iterator
    template<bool> struct inner_iterator;       // 仅用于阐释
  public:
    split_view() = default;
    constexpr split_view(V base, Pattern pattern);

    template<InputRange R, ForwardRange P>
      requires Constructible<V, all_view<R>> &&
               Constructible<Pattern, all_view<P>>
    constexpr split_view(R&& r, P&& p);

    template<InputRange R>
      requires Constructible<V, all_view<R>> &&
               Constructible<Pattern, single_view<iter_value_t<iterator_t<R>>>>
    constexpr split_view(R&& r, iter_value_t<iterator_t<R>> e);

    constexpr auto begin() {
      if constexpr (ForwardRange<V>)
        return outer_iterator<__SimpleView<V>>{*this, ranges::begin(base_)};
      else {
        current_ = ranges::begin(base_);
        return outer_iterator<false>{*this};
      }
    }

    constexpr auto begin() const requires ForwardRange<V> && ForwardRange<const V> {
      return outer_iterator<true>{*this, ranges::begin(base_)};
    }

    constexpr auto end() requires ForwardRange<V> && CommonRange<V> {
      return outer_iterator<__SimpleView<V>>{*this, ranges::end(base_)};
    }

    constexpr auto end() const {
      if constexpr (ForwardRange<V> && ForwardRange<const V> && CommonRange<const V>)
        return outer_iterator<true>{*this, ranges::end(base_)};
      else
        return default_sentinel;
    }
  };

  template<class R, class P>
    split_view(R&&, P&&) -> split_view<all_view<R>, all_view<P>>;

  template<InputRange R>
    split_view(R&&, iter_value_t<iterator_t<R>>)
      -> split_view<all_view<R>, single_view<iter_value_t<iterator_t<R>>>>;
}

类模板 std::ranges::split_view::outer_iterator

namespace std::ranges {
  template<class V, class Pattern>
  template<bool Const>
  struct split_view<V, Pattern>::outer_iterator {
  private:
    using Parent =                              // 仅用于阐释
      conditional_t<Const, const split_view, split_view>;
    using Base   =                              // 仅用于阐释
      conditional_t<Const, const V, V>;
    Parent* parent_ = nullptr;                  // 仅用于阐释
    iterator_t<Base> current_ =                 // 仅用于阐释，
      iterator_t<Base>();                       // 仅当 V 构成 ForwardRange 时才存在

  public:
    using iterator_concept  =
      conditional_t<ForwardRange<Base>, forward_iterator_tag, input_iterator_tag>;
    using iterator_category = input_iterator_tag;
    struct value_type;
    using difference_type   = iter_difference_t<iterator_t<Base>>;

    outer_iterator() = default;
    constexpr explicit outer_iterator(Parent& parent)
      requires (!ForwardRange<Base>);
    constexpr outer_iterator(Parent& parent, iterator_t<Base> current)
      requires ForwardRange<Base>;
    constexpr outer_iterator(outer_iterator<!Const> i)
      requires Const && ConvertibleTo<iterator_t<V>, iterator_t<const V>>;

    constexpr value_type operator*() const;

    constexpr outer_iterator& operator++();
    constexpr decltype(auto) operator++(int) {
      if constexpr (ForwardRange<Base>) {
        auto tmp = *this;
        ++*this;
        return tmp;
      } else
        ++*this;
    }

    friend constexpr bool operator==(const outer_iterator& x, const outer_iterator& y)
      requires ForwardRange<Base>;
    friend constexpr bool operator!=(const outer_iterator& x, const outer_iterator& y)
      requires ForwardRange<Base>;

    friend constexpr bool operator==(const outer_iterator& x, default_sentinel_t);
    friend constexpr bool operator==(default_sentinel_t, const outer_iterator& x);
    friend constexpr bool operator!=(const outer_iterator& x, default_sentinel_t y);
    friend constexpr bool operator!=(default_sentinel_t y, const outer_iterator& x);
  };
}

类 std::ranges::split_view::outer_iterator::value_type

namespace std::ranges {
  template<class V, class Pattern>
  template<bool Const>
  struct split_view<V, Pattern>::outer_iterator<Const>::value_type {
  private:
    outer_iterator i_ = outer_iterator();               // 仅用于阐释
  public:
    value_type() = default;
    constexpr explicit value_type(outer_iterator i);

    constexpr inner_iterator<Const> begin() const;
    constexpr default_sentinel_t end() const;
  };
}

类模板 std::ranges::split_view::inner_iterator

namespace std::ranges {
  template<class V, class Pattern>
  template<bool Const>
  struct split_view<V, Pattern>::inner_iterator {
  private:
    using Base =
      conditional_t<Const, const V, V>;                 // 仅用于阐释
    outer_iterator<Const> i_ = outer_iterator<Const>(); // 仅用于阐释
    bool incremented_ = false;                          // 仅用于阐释
  public:
    using iterator_concept  = typename outer_iterator<Const>::iterator_concept;
    using iterator_category = /* 见定义 */;
    using value_type        = iter_value_t<iterator_t<Base>>;
    using difference_type   = iter_difference_t<iterator_t<Base>>;

    inner_iterator() = default;
    constexpr explicit inner_iterator(outer_iterator<Const> i);

    constexpr decltype(auto) operator*() const { return *i_.current; }

    constexpr inner_iterator& operator++();
    constexpr decltype(auto) operator++(int) {
      if constexpr (ForwardRange<V>) {
        auto tmp = *this;
        ++*this;
        return tmp;
      } else
        ++*this;
    }

    friend constexpr bool operator==(const inner_iterator& x, const inner_iterator& y)
      requires ForwardRange<Base>;
    friend constexpr bool operator!=(const inner_iterator& x, const inner_iterator& y)
      requires ForwardRange<Base>;

    friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t);
    friend constexpr bool operator==(default_sentinel_t, const inner_iterator& x);
    friend constexpr bool operator!=(const inner_iterator& x, default_sentinel_t y);
    friend constexpr bool operator!=(default_sentinel_t y, const inner_iterator& x);

    friend constexpr decltype(auto) iter_move(const inner_iterator& i)
    noexcept(noexcept(ranges::iter_move(i.i_.current))) {
      return ranges::iter_move(i.i_.current);
    }

    friend constexpr void iter_swap(const inner_iterator& x, const inner_iterator& y)
      noexcept(noexcept(ranges::iter_swap(x.i_.current, y.i_.current)))
      requires IndirectlySwappable<iterator_t<Base>>;
  };
}

类模板 std::ranges::common_view

namespace std::ranges {
  template<View V>
    requires (!CommonRange<V>)
  class common_view : public view_interface<common_view<V>> {
  private:
    V base_ = V();  // 仅用于阐释
  public:
    common_view() = default;

    constexpr explicit common_view(V r);

    template<ViewableRange R>
      requires (!CommonRange<R> && Constructible<V, all_view<R>>)
    constexpr explicit common_view(R&& r);

    constexpr V base() const;

    constexpr auto size() requires SizedRange<V> {
      return ranges::size(base_);
    }
    constexpr auto size() const requires SizedRange<const V> {
      return ranges::size(base_);
    }

    constexpr auto begin() {
      if constexpr (RandomAccessRange<V> && SizedRange<V>)
        return ranges::begin(base_);
      else
        return common_iterator<iterator_t<V>, sentinel_t<V>>(ranges::begin(base_));
    }

    constexpr auto begin() const requires Range<const V> {
      if constexpr (RandomAccessRange<const V> && SizedRange<const V>)
        return ranges::begin(base_);
      else
        return
          common_iterator<iterator_t<const V>, sentinel_t<const V>>(ranges::begin(base_));
    }

    constexpr auto end() {
      if constexpr (RandomAccessRange<V> && SizedRange<V>)
        return ranges::begin(base_) + ranges::size(base_);
      else
        return common_iterator<iterator_t<V>, sentinel_t<V>>(ranges::end(base_));
    }

    constexpr auto end() const requires Range<const V> {
      if constexpr (RandomAccessRange<const V> && SizedRange<const V>)
        return ranges::begin(base_) + ranges::size(base_);
      else
        return
          common_iterator<iterator_t<const V>, sentinel_t<const V>>(ranges::end(base_));
    }
  };

  template<class R>
    common_view(R&&) -> common_view<all_view<R>>;
}

类模板 std::ranges::reverse_view

namespace std::ranges {
  template<View V>
    requires BidirectionalRange<V>
  class reverse_view : public view_interface<reverse_view<V>> {
  private:
    V base_ = V();  // 仅用于阐释
  public:
    reverse_view() = default;

    constexpr explicit reverse_view(V r);

    template<ViewableRange R>
      requires BidirectionalRange<R> && Constructible<V, all_view<R>>
    constexpr explicit reverse_view(R&& r);

    constexpr V base() const;

    constexpr reverse_iterator<iterator_t<V>> begin();
    constexpr reverse_iterator<iterator_t<V>> begin() requires CommonRange<V>;
    constexpr reverse_iterator<iterator_t<const V>> begin() const
      requires CommonRange<const V>;

    constexpr reverse_iterator<iterator_t<V>> end();
    constexpr reverse_iterator<iterator_t<const V>> end() const
      requires CommonRange<const V>;

    constexpr auto size() requires SizedRange<V> {
      return ranges::size(base_);
    }
    constexpr auto size() const requires SizedRange<const V> {
      return ranges::size(base_);
    }
  };

  template<class R>
    reverse_view(R&&) -> reverse_view<all_view<R>>;
}


标准库头文件 <ratio>

< cpp‎ | header

此头文件是编译时有理数算术库的一部分。

类
ratio
 表示精确的有理分数
(类模板)
算术
ratio_add
(C++11)
 在编译时相加两个 ratio 对象
(别名模板)
ratio_subtract
(C++11)
 在编译时相减两个 ratio 对象
(别名模板)
ratio_multiply
(C++11)
 在编译时相乘两个 ratio 对象
(别名模板)
ratio_divide
(C++11)
 在编译时相除两个 ratio 对象
(别名模板)
比较
ratio_equal
(C++11)
 在编译时比较两个 ratio 对象的相等性
(类模板)
ratio_not_equal
(C++11)
 在编译时比较两个 ratio 对象的不相等性
(类模板)
ratio_less
(C++11)
 在编译时比较两个 ratio 对象的小于关系
(类模板)
ratio_less_equal
(C++11)
 在编译时比较两个 ratio 对象的小于或等于关系
(类模板)
ratio_greater
(C++11)
 在编译时比较两个 ratio 对象的大于关系
(类模板)
ratio_greater_equal
(C++11)
 在编译时比较两个 ratio 对象的大于或等于关系
(类模板)
常量
yocto | std::ratio <1, 1000000000000000000000000>，若 std::intmax_t 能表示分母
zepto | std::ratio <1, 1000000000000000000000>，若 std::intmax_t 能表示分母
atto | std::ratio <1, 1000000000000000000>
femto | std::ratio <1, 1000000000000000>
pico | std::ratio <1, 1000000000000>
nano | std::ratio <1, 1000000000>
micro | std::ratio <1, 1000000>
milli | std::ratio <1, 1000>
centi | std::ratio <1, 100>
deci | std::ratio <1, 10>
deca | std::ratio <10, 1>
hecto | std::ratio <100, 1>
kilo | std::ratio <1000, 1>
mega | std::ratio <1000000, 1>
giga | std::ratio <1000000000, 1>
tera | std::ratio <1000000000000, 1>
peta | std::ratio <1000000000000000, 1>
exa | std::ratio <1000000000000000000, 1>
zetta | std::ratio <1000000000000000000000, 1>，若 std::intmax_t 能表示分子
yotta | std::ratio <1000000000000000000000000, 1>，若 std::intmax_t 能表示分子

概要

namespace std {

    // 类模板 ratio
    template <intmax_t N, intmax_t D = 1>
    class ratio {
    public:
        typedef ratio<num, den> type;
        static constexpr intmax_t num;
        static constexpr intmax_t den;
    };

    // ratio 算术
    template <class R1, class   R2> using   ratio_add      = /*ratio*/;
    template <class R1, class   R2> using   ratio_subtract = /*ratio*/;
    template <class R1, class   R2> using   ratio_multiply = /*ratio*/;
    template <class R1, class   R2> using   ratio_divide   = /*ratio*/;

    // ratio 比较
    template <class R1, class R2> struct ratio_equal;
    template <class R1, class R2> struct ratio_not_equal;
    template <class R1, class R2> struct ratio_less;
    template <class R1, class R2> struct ratio_less_equal;
    template <class R1, class R2> struct ratio_greater;
    template <class R1, class R2> struct ratio_greater_equal;

    // 便利 SI typedef
    typedef ratio<1, 1000000000000000000000000> yocto;
    typedef ratio<1,    1000000000000000000000> zepto;
    typedef ratio<1,       1000000000000000000> atto;
    typedef ratio<1,          1000000000000000> femto;
    typedef ratio<1,             1000000000000> pico;
    typedef ratio<1,                1000000000> nano;
    typedef ratio<1,                   1000000> micro;
    typedef ratio<1,                      1000> milli;
    typedef ratio<1,                       100> centi;
    typedef ratio<1,                        10> deci;
    typedef ratio<                       10, 1> deca;
    typedef ratio<                      100, 1> hecto;
    typedef ratio<                     1000, 1> kilo;
    typedef ratio<                  1000000, 1> mega;
    typedef ratio<               1000000000, 1> giga;
    typedef ratio<            1000000000000, 1> tera;
    typedef ratio<         1000000000000000, 1> peta;
    typedef ratio<      1000000000000000000, 1> exa;
    typedef ratio<   1000000000000000000000, 1> zetta;
    typedef ratio<1000000000000000000000000, 1> yotta;

}


标准库头文件 <regex>

< cpp‎ | header

此头文件是正则表达式库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
<initializer_list>
(C++11)
 std::initializer_list 类模板

类
basic_regex
(C++11)
 正则表达式对象
(类模板)
sub_match
(C++11)
 标识子表达式所匹配的字符序列
(类模板)
match_results
(C++11)
 标识一个正则表达式匹配，包含所有子表达式匹配
(类模板)
regex_iterator
(C++11)
 迭代一个字符序列中的所有正则表达式匹配
(类模板)
regex_token_iterator
(C++11)
 迭代给定字符串中的所有正则表达式匹配中的指定子表达式，或迭代未匹配的子字符串
(类模板)
regex_error
(C++11)
 报告正则表达式库生成的错误
(类)
regex_traits
(C++11)
 提供正则表达式库所需的关于字符类型的元信息
(类模板)
regex 常量类型
定义于命名空间 std::regex_constants
syntax_option_type
(C++11)
 控制正则表达式行为的通用选项
(typedef)
match_flag_type
(C++11)
 特定于匹配的选项
(typedef)
error_type
(C++11)
 描述不同类型的匹配错误
(typedef)

函数
算法
regex_match
(C++11)
 尝试匹配一个正则表达式到整个字符序列
(函数模板)
regex_search
(C++11)
 尝试匹配一个正则表达式到字符序列的任何部分
(函数模板)
regex_replace
(C++11)
 以格式化的替换文本来替换正则表达式匹配的出现位置
(函数模板)
非成员操作
std::swap(std::basic_regex)
(C++11)
 特化 std::swap 算法
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 比较一个 sub_match 与另一 sub_match 、字符串或字符
(函数模板)
operator<<
 输出匹配的字符子序列
(函数模板)
operator==operator!=
(C++20 中移除)
 以字典序比较两个匹配结果的值
(函数模板)
std::swap(std::match_results)
(C++11)
 特化 std::swap 算法
(函数模板)
范围访问
begincbegin
(C++11)(C++14)
 返回指向容器或数组起始的迭代器
(函数模板)
endcend
(C++11)(C++14)
 返回指向容器或数组结尾的迭代器
(函数模板)
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
sizessize
(C++17)(C++20)
 返回容器或数组的大小
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)

概要

#include <compare>
#include <initializer_list>

namespace std {
  // regex 常量
  namespace regex_constants {
    using syntax_option_type = /*T1*/;
    using match_flag_type = /*T2*/;
    using error_type = /*T3*/;
  }

  // 类 regex_error
  class regex_error;

  // 类模板 regex_traits
  template<class CharT> struct regex_traits;

  // 类模板 basic_regex
  template<class CharT, class Traits = regex_traits<CharT>> class basic_regex;

  using regex  = basic_regex<char>;
  using wregex = basic_regex<wchar_t>;

  // basic_regex 交换
  template<class CharT, class Traits>
    void swap(basic_regex<CharT, Traits>& e1, basic_regex<CharT, Traits>& e2);

  // 类模板 sub_match
  template<class BiIt>
    class sub_match;

  using csub_match  = sub_match<const char*>;
  using wcsub_match = sub_match<const wchar_t*>;
  using ssub_match  = sub_match<string::const_iterator>;
  using wssub_match = sub_match<wstring::const_iterator>;

  // sub_match 非成员运算符
  template<class BiIt>
    bool operator==(const sub_match<BiIt>& lhs, const sub_match<BiIt>& rhs);
  template<class BiIt>
    auto operator<=>(const sub_match<BiIt>& lhs, const sub_match<BiIt>& rhs);

  template<class BiIt, class ST, class SA>
    bool operator==(
      const sub_match<BiIt>& lhs,
      const basic_string<typename iterator_traits<BiIt>::value_type, ST, SA>& rhs);
  template<class BiIt, class ST, class SA>
    auto operator<=>(
      const sub_match<BiIt>& lhs,
      const basic_string<typename iterator_traits<BiIt>::value_type, ST, SA>& rhs);

  template<class BiIt>
    bool operator==(const sub_match<BiIt>& lhs,
                    const typename iterator_traits<BiIt>::value_type* rhs);
  template<class BiIt>
    auto operator<=>(const sub_match<BiIt>& lhs,
                     const typename iterator_traits<BiIt>::value_type* rhs);

  template<class BiIt>
    bool operator==(const sub_match<BiIt>& lhs,
                    const typename iterator_traits<BiIt>::value_type& rhs);
  template<class BiIt>
    auto operator<=>(const sub_match<BiIt>& lhs,
                     const typename iterator_traits<BiIt>::value_type& rhs);

  template<class CharT, class ST, class BiIt>
    basic_ostream<CharT, ST>&
      operator<<(basic_ostream<CharT, ST>& os, const sub_match<BiIt>& m);

  // 类模板 match_results
  template<class BiIt,
           class Allocator = allocator<sub_match<BiIt>>>
    class match_results;

  using cmatch  = match_results<const char*>;
  using wcmatch = match_results<const wchar_t*>;
  using smatch  = match_results<string::const_iterator>;
  using wsmatch = match_results<wstring::const_iterator>;

  // match_results 比较
  template<class BiIt, class Allocator>
    bool operator==(const match_results<BiIt, Allocator>& m1,
                    const match_results<BiIt, Allocator>& m2);

  // match_results 交换
  template<class BiIt, class Allocator>
    void swap(match_results<BiIt, Allocator>& m1, match_results<BiIt, Allocator>& m2);

  // 函数模板 regex_match
  template<class BiIt, class Allocator, class CharT, class Traits>
    bool regex_match(BiIt first, BiIt last,
                     match_results<BiIt, Allocator>& m,
                     const basic_regex<CharT, Traits>& e,
                     regex_constants::match_flag_type flags =
                       regex_constants::match_default);
  template<class BiIt, class CharT, class Traits>
    bool regex_match(BiIt first, BiIt last,
                     const basic_regex<CharT, Traits>& e,
                     regex_constants::match_flag_type flags =
                       regex_constants::match_default);
  template<class CharT, class Allocator, class Traits>
    bool regex_match(const CharT* str, match_results<const CharT*, Allocator>& m,
                     const basic_regex<CharT, Traits>& e,
                     regex_constants::match_flag_type flags =
                       regex_constants::match_default);
  template<class ST, class SA, class Allocator, class CharT, class Traits>
    bool regex_match(const basic_string<CharT, ST, SA>& s,
                     match_results<typename basic_string<CharT, ST, SA>::const_iterator,
                                   Allocator>& m,
                     const basic_regex<CharT, Traits>& e,
                     regex_constants::match_flag_type flags =
                       regex_constants::match_default);
  template<class ST, class SA, class Allocator, class CharT, class Traits>
    bool regex_match(const basic_string<CharT, ST, SA>&&,
                     match_results<typename basic_string<CharT, ST, SA>::const_iterator,
                                   Allocator>&,
                     const basic_regex<CharT, Traits>&,
                     regex_constants::match_flag_type =
                       regex_constants::match_default) = delete;
  template<class CharT, class Traits>
    bool regex_match(const CharT* str,
                     const basic_regex<CharT, Traits>& e,
                     regex_constants::match_flag_type flags =
                       regex_constants::match_default);
  template<class ST, class SA, class CharT, class Traits>
    bool regex_match(const basic_string<CharT, ST, SA>& s,
                     const basic_regex<CharT, Traits>& e,
                     regex_constants::match_flag_type flags =
                       regex_constants::match_default);

  // 函数模板 regex_search
  template<class BiIt, class Allocator, class CharT, class Traits>
    bool regex_search(BiIt first, BiIt last,
                      match_results<BiIt, Allocator>& m,
                      const basic_regex<CharT, Traits>& e,
                      regex_constants::match_flag_type flags =
                        regex_constants::match_default);
  template<class BiIt, class CharT, class Traits>
    bool regex_search(BiItfirst, BiIt last,
                      const basic_regex<CharT, Traits>& e,
                      regex_constants::match_flag_type flags =
                        regex_constants::match_default);
  template<class CharT, class Allocator, class Traits>
    bool regex_search(const CharT* str,
                      match_results<const CharT*, Allocator>& m,
                      const basic_regex<CharT, Traits>& e,
                      regex_constants::match_flag_type flags =
                        regex_constants::match_default);
  template<class CharT, class Traits>
    bool regex_search(const CharT* str,
                      const basic_regex<CharT, Traits>& e,
                      regex_constants::match_flag_type flags =
                        regex_constants::match_default);
  template<class ST, class SA, class CharT, class Traits>
    bool regex_search(const basic_string<CharT, ST, SA>& s,
                      const basic_regex<CharT, Traits>& e,
                      regex_constants::match_flag_type flags =
                        regex_constants::match_default);
  template<class ST, class SA, class Allocator, class CharT, class Traits>
    bool regex_search(const basic_string<CharT, ST, SA>& s,
                      match_results<typename basic_string<CharT, ST, SA>::const_iterator,
                                    Allocator>& m,
                      const basic_regex<CharT, Traits>& e,
                      regex_constants::match_flag_type flags =
                        regex_constants::match_default);
  template<class ST, class SA, class Allocator, class CharT, class Traits>
    bool regex_search(const basic_string<CharT, ST, SA>&&,
                      match_results<typename basic_string<CharT, ST, SA>::const_iterator,
                                    Allocator>&,
                      const basic_regex<CharT, Traits>&,
                      regex_constants::match_flag_type
                        = regex_constants::match_default) = delete;

  // 函数模板 regex_replace
  template<class OutputIt, class BiIt,
            class Traits, class CharT, class ST, class SA>
    OutputIt
      regex_replace(OutputIt out,
                    BiIt first, BiIt last,
                    const basic_regex<CharT, Traits>& e,
                    const basic_string<CharT, ST, SA>& fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
  template<class OutputIt, class BiIt, class Traits, class CharT>
    OutputIt
      regex_replace(OutputIt out,
                    BiIt first, BiIt last,
                    const basic_regex<CharT, Traits>& e,
                    const CharT* fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
  template<class Traits, class CharT, class ST, class SA, class FST, class FSA>
    basic_string<CharT, ST, SA>
      regex_replace(const basic_string<CharT, ST, SA>& s,
                    const basic_regex<CharT, Traits>& e,
                    const basic_string<CharT, FST, FSA>& fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
  template<class Traits, class CharT, class ST, class SA>
    basic_string<CharT, ST, SA>
      regex_replace(const basic_string<CharT, ST, SA>& s,
                    const basic_regex<CharT, Traits>& e,
                    const CharT* fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
  template<class Traits, class CharT, class ST, class SA>
    basic_string<CharT>
      regex_replace(const CharT* s,
                    const basic_regex<CharT, Traits>& e,
                    const basic_string<CharT, ST, SA>& fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);
  template<class Traits, class CharT>
    basic_string<CharT>
      regex_replace(const CharT* s,
                    const basic_regex<CharT, Traits>& e,
                    const CharT* fmt,
                    regex_constants::match_flag_type flags =
                      regex_constants::match_default);

  // 类模板 regex_iterator
  template<class BiIt,
            class CharT = typename iterator_traits<BiIt>::value_type,
            class Traits = regex_traits<CharT>>
    class regex_iterator;

  using cregex_iterator  = regex_iterator<const char*>;
  using wcregex_iterator = regex_iterator<const wchar_t*>;
  using sregex_iterator  = regex_iterator<string::const_iterator>;
  using wsregex_iterator = regex_iterator<wstring::const_iterator>;

  // 类模板 regex_token_iterator
  template<class BiIt,
            class CharT = typename iterator_traits<BiIt>::value_type,
            class Traits = regex_traits<CharT>>
    class regex_token_iterator;

  using cregex_token_iterator  = regex_token_iterator<const char*>;
  using wcregex_token_iterator = regex_token_iterator<const wchar_t*>;
  using sregex_token_iterator  = regex_token_iterator<string::const_iterator>;
  using wsregex_token_iterator = regex_token_iterator<wstring::const_iterator>;

  namespace pmr {
    template<class BiIt>
      using match_results =
        std::match_results<BiIt, polymorphic_allocator<sub_match<BiIt>>>;

    using cmatch  = match_results<const char*>;
    using wcmatch = match_results<const wchar_t*>;
    using smatch  = match_results<string::const_iterator>;
    using wsmatch = match_results<wstring::const_iterator>;
  }
}

位掩码类型 std::regex_constants::syntax_option_type

namespace std::regex_constants {
  using syntax_option_type = /*T1*/;
  inline constexpr syntax_option_type icase = /* 未指明 */;
  inline constexpr syntax_option_type nosubs = /* 未指明 */;
  inline constexpr syntax_option_type optimize = /* 未指明 */;
  inline constexpr syntax_option_type collate = /* 未指明 */;
  inline constexpr syntax_option_type ECMAScript = /* 未指明 */;
  inline constexpr syntax_option_type basic = /* 未指明 */;
  inline constexpr syntax_option_type extended = /* 未指明 */;
  inline constexpr syntax_option_type awk = /* 未指明 */;
  inline constexpr syntax_option_type grep = /* 未指明 */;
  inline constexpr syntax_option_type egrep = /* 未指明 */;
  inline constexpr syntax_option_type multiline = /* 未指明 */;
}

位掩码类型 std::regex_constants::match_flag_type

namespace std::regex_constants {
  using match_flag_type = /*T2*/;
  inline constexpr match_flag_type match_default = {};
  inline constexpr match_flag_type match_not_bol = /* 未指明 */;
  inline constexpr match_flag_type match_not_eol = /* 未指明 */;
  inline constexpr match_flag_type match_not_bow = /* 未指明 */;
  inline constexpr match_flag_type match_not_eow = /* 未指明 */;
  inline constexpr match_flag_type match_any = /* 未指明 */;
  inline constexpr match_flag_type match_not_null = /* 未指明 */;
  inline constexpr match_flag_type match_continuous = /* 未指明 */;
  inline constexpr match_flag_type match_prev_avail = /* 未指明 */;
  inline constexpr match_flag_type format_default = {};
  inline constexpr match_flag_type format_sed = /* 未指明 */;
  inline constexpr match_flag_type format_no_copy = /* 未指明 */;
  inline constexpr match_flag_type format_first_only = /* 未指明 */;
}

被枚举类型 std::regex_constants::error_type

namespace std::regex_constants {
  using error_type = /*T3*/;
  inline constexpr error_type error_collate = /* 未指明 */;
  inline constexpr error_type error_ctype = /* 未指明 */;
  inline constexpr error_type error_escape = /* 未指明 */;
  inline constexpr error_type error_backref = /* 未指明 */;
  inline constexpr error_type error_brack = /* 未指明 */;
  inline constexpr error_type error_paren = /* 未指明 */;
  inline constexpr error_type error_brace = /* 未指明 */;
  inline constexpr error_type error_badbrace = /* 未指明 */;
  inline constexpr error_type error_range = /* 未指明 */;
  inline constexpr error_type error_space = /* 未指明 */;
  inline constexpr error_type error_badrepeat = /* 未指明 */;
  inline constexpr error_type error_complexity = /* 未指明 */;
  inline constexpr error_type error_stack = /* 未指明 */;
}

类 std::regex_error

namespace std {
  class regex_error : public runtime_error {
  public:
    explicit regex_error(regex_constants::error_type ecode);
    regex_constants::error_type code() const;
  };
}

类模板 std::regex_traits

namespace std {
  template<class CharT>
    struct regex_traits {
      using char_type       = CharT;
      using string_type     = basic_string<char_type>;
      using locale_type     = locale;
      using char_class_type = /* 位掩码类型 */;

      regex_traits();
      static size_t length(const char_type* p);
      CharT translate(CharT c) const;
      CharT translate_nocase(CharT c) const;
      template<class ForwardIt>
        string_type transform(ForwardIt first, ForwardIt last) const;
      template<class ForwardIt>
        string_type transform_primary(ForwardIt first, ForwardIt last) const;
      template<class ForwardIt>
        string_type lookup_collatename(ForwardIt first, ForwardIt last) const;
      template<class ForwardIt>
        char_class_type lookup_classname(ForwardIt first, ForwardIt last,
                                         bool icase = false) const;
      bool isctype(CharT c, char_class_type f) const;
      int value(CharT ch, int radix) const;
      locale_type imbue(locale_type l);
      locale_type getloc() const;
    };
}

类模板 std::basic_regex

namespace std {
  template<class CharT, class Traits = regex_traits<CharT>>
    class basic_regex {
    public:
      // 类型
      using value_type  =          CharT;
      using Traits_type =          Traits;
      using string_type = typename Traits::string_type;
      using flag_type   =          regex_constants::syntax_option_type;
      using locale_type = typename Traits::locale_type;

      // 常量
      static constexpr flag_type icase = regex_constants::icase;
      static constexpr flag_type nosubs = regex_constants::nosubs;
      static constexpr flag_type optimize = regex_constants::optimize;
      static constexpr flag_type collate = regex_constants::collate;
      static constexpr flag_type ECMAScript = regex_constants::ECMAScript;
      static constexpr flag_type basic = regex_constants::basic;
      static constexpr flag_type extended = regex_constants::extended;
      static constexpr flag_type awk = regex_constants::awk;
      static constexpr flag_type grep = regex_constants::grep;
      static constexpr flag_type egrep = regex_constants::egrep;
      static constexpr flag_type multiline = regex_constants::multiline;

      // 构造/复制/销毁
      basic_regex();
      explicit basic_regex(const CharT* p, flag_type f = regex_constants::ECMAScript);
      basic_regex(const CharT* p, size_t len, flag_type f = regex_constants::ECMAScript);
      basic_regex(const basic_regex&);
      basic_regex(basic_regex&&) noexcept;
      template<class ST, class SA>
        explicit basic_regex(const basic_string<CharT, ST, SA>& s,
                             flag_type f = regex_constants::ECMAScript);
      template<class ForwardIt>
        basic_regex(ForwardIt first, ForwardIt last,
                    flag_type f = regex_constants::ECMAScript);
      basic_regex(initializer_list<CharT> il, flag_type f = regex_constants::ECMAScript);

      ~basic_regex();

      // 赋值
      basic_regex& operator=(const basic_regex& e);
      basic_regex& operator=(basic_regex&& e) noexcept;
      basic_regex& operator=(const CharT* p);
      basic_regex& operator=(initializer_list<CharT> il);
      template<class ST, class SA>
        basic_regex& operator=(const basic_string<CharT, ST, SA>& s);

      basic_regex& assign(const basic_regex& e);
      basic_regex& assign(basic_regex&& e) noexcept;
      basic_regex& assign(const CharT* p, flag_type f = regex_constants::ECMAScript);
      basic_regex& assign(const CharT* p, size_t len,
                          flag_type f = regex_constants::ECMAScript);
      template<class ST, class SA>
        basic_regex& assign(const basic_string<CharT, ST, SA>& s,
                            flag_type f = regex_constants::ECMAScript);
      template<class InputIt>
        basic_regex& assign(InputIt first, InputIt last,
                            flag_type f = regex_constants::ECMAScript);
      basic_regex& assign(initializer_list<CharT>,
                          flag_type f = regex_constants::ECMAScript);

      // const 操作
      unsigned mark_count() const;
      flag_type flags() const;

      // 本地环境
      locale_type imbue(locale_type loc);
      locale_type getloc() const;

      // 交换
      void swap(basic_regex&);
    };

  template<class ForwardIt>
    basic_regex(ForwardIt, ForwardIt,
                regex_constants::syntax_option_type = regex_constants::ECMAScript)
      -> basic_regex<typename iterator_traits<ForwardIt>::value_type>;
}

类模板 std::sub_match

namespace std {
  template<class BiIt>
    class sub_match : public pair<BiIt, BiIt> {
    public:
      using value_type      = typename iterator_traits<BiIt>::value_type;
      using difference_type = typename iterator_traits<BiIt>::difference_type;
      using iterator        = BiIt;
      using string_type     = basic_string<value_type>;

      bool matched;

      constexpr sub_match();

      difference_type length() const;
      operator string_type() const;
      string_type str() const;

      int compare(const sub_match& s) const;
      int compare(const string_type& s) const;
      int compare(const value_type* s) const;
    };
}

类模板 std::match_results

namespace std {
  template<class BiIt,
           class Allocator = allocator<sub_match<BiIt>>>
    class match_results {
    public:
      using value_type      = sub_match<BiIt>;
      using const_reference = const value_type&;
      using reference       = value_type&;
      using const_iterator  = /* 由实现定义 */;
      using iterator        = const_iterator;
      using difference_type = typename iterator_traits<BiIt>::difference_type;
      using size_type       = typename allocator_traits<Allocator>::size_type;
      using allocator_type  = Allocator;
      using char_type       = typename iterator_traits<BiIt>::value_type;
      using string_type     = basic_string<char_type>;

      // 构造/复制/销毁
      match_results() : match_results(Allocator()) {}
      explicit match_results(const Allocator&);
      match_results(const match_results& m);
      match_results(match_results&& m) noexcept;
      match_results& operator=(const match_results& m);
      match_results& operator=(match_results&& m);
      ~match_results();

      // 状态
      bool ready() const;

      // 大小
      size_type size() const;
      size_type max_size() const;
      [[nodiscard]] bool empty() const;

      // 元素访问
      difference_type length(size_type sub = 0) const;
      difference_type position(size_type sub = 0) const;
      string_type str(size_type sub = 0) const;
      const_reference operator[](size_type n) const;

      const_reference prefix() const;
      const_reference suffix() const;
      const_iterator begin() const;
      const_iterator end() const;
      const_iterator cbegin() const;
      const_iterator cend() const;

      // 格式
      template<class OutputIt>
        OutputIt
          format(OutputIt out,
                 const char_type* fmt_first, const char_type* fmt_last,
                 regex_constants::match_flag_type flags =
                   regex_constants::format_default) const;
      template<class OutputIt, class ST, class SA>
        OutputIt
          format(OutputIt out,
                 const basic_string<char_type, ST, SA>& fmt,
                 regex_constants::match_flag_type flags =
                   regex_constants::format_default) const;
      template<class ST, class SA>
        basic_string<char_type, ST, SA>
          format(const basic_string<char_type, ST, SA>& fmt,
                 regex_constants::match_flag_type flags =
                   regex_constants::format_default) const;
      string_type
        format(const char_type* fmt,
               regex_constants::match_flag_type flags =
                 regex_constants::format_default) const;

      // 分配器
      allocator_type get_allocator() const;

      // 交换
      void swap(match_results& that);
    };
}


标准库头文件 <scoped_allocator>

< cpp‎ | header

此头文件是动态内存管理库的一部分。

类
scoped_allocator_adaptor
(C++11)
 为多级容器实现的多级分配器
(类模板)

函数
operator==operator!=
(C++20 中移除)
 比较两个 scoped_allocator_adaptor 实例
(std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...> 的公开成员函数)

概要

namespace std {
  // 类模板 scoped_allocator_adaptor
  template<class OuterAlloc, class... InnerAlloc>
    class scoped_allocator_adaptor;

  // 有作用域分配器运算符
  template<class OuterA1, class OuterA2, class... InnerAllocs>
    bool operator==(const scoped_allocator_adaptor<OuterA1, InnerAllocs...>& a,
                    const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& b) noexcept;
}

类模板 std::scoped_allocator_adaptor

namespace std {
  template<class OuterAlloc, class... InnerAllocs>
  class scoped_allocator_adaptor : public OuterAlloc {
  private:
    using OuterTraits = allocator_traits<OuterAlloc>;   // 仅用于阐释
    scoped_allocator_adaptor<InnerAllocs...> inner;     // 仅用于阐释

  public:
    using outer_allocator_type = OuterAlloc;
    using inner_allocator_type = /* 见描述 */;

    using value_type           = typename OuterTraits::value_type;
    using size_type            = typename OuterTraits::size_type;
    using difference_type      = typename OuterTraits::difference_type;
    using pointer              = typename OuterTraits::pointer;
    using const_pointer        = typename OuterTraits::const_pointer;
    using void_pointer         = typename OuterTraits::void_pointer;
    using const_void_pointer   = typename OuterTraits::const_void_pointer;

    using propagate_on_container_copy_assignment = /* 见描述 */;
    using propagate_on_container_move_assignment = /* 见描述 */;
    using propagate_on_container_swap            = /* 见描述 */;
    using is_always_equal                        = /* 见描述 */;

    template<class Tp> struct rebind {
      using other = scoped_allocator_adaptor<
        OuterTraits::template rebind_alloc<Tp>, InnerAllocs...>;
    };

    scoped_allocator_adaptor();
    template<class OuterA2>
      scoped_allocator_adaptor(OuterA2&& outerAlloc,
                               const InnerAllocs&... innerAllocs) noexcept;

    scoped_allocator_adaptor(const scoped_allocator_adaptor& other) noexcept;
    scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept;

    template<class OuterA2>
      scoped_allocator_adaptor(
        const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& other) noexcept;
    template<class OuterA2>
      scoped_allocator_adaptor(
        scoped_allocator_adaptor<OuterA2, InnerAllocs...>&& other) noexcept;

    scoped_allocator_adaptor& operator=(const scoped_allocator_adaptor&) = default;
    scoped_allocator_adaptor& operator=(scoped_allocator_adaptor&&) = default;

    ~scoped_allocator_adaptor();

    inner_allocator_type& inner_allocator() noexcept;
    const inner_allocator_type& inner_allocator() const noexcept;
    outer_allocator_type& outer_allocator() noexcept;
    const outer_allocator_type& outer_allocator() const noexcept;

    [[nodiscard]] pointer allocate(size_type n);
    [[nodiscard]] pointer allocate(size_type n, const_void_pointer hint);
    void deallocate(pointer p, size_type n);
    size_type max_size() const;

    template<class T, class... Args>
      void construct(T* p, Args&&... args);

    template<class T>
      void destroy(T* p);

    scoped_allocator_adaptor select_on_container_copy_construction() const;
  };

  template<class OuterAlloc, class... InnerAllocs>
    scoped_allocator_adaptor(OuterAlloc, InnerAllocs...)
      -> scoped_allocator_adaptor<OuterAlloc, InnerAllocs...>;
}


标准库头文件 <semaphore>

< cpp‎ | header

此头文件是线程支持库的一部分。

类
counting_semaphore
(C++20)
 实现非负资源计数的信号量
(类模板)
binary_semaphore
(C++20)
 仅拥有二个状态的信号量
(typedef)

概要

namespace std {
  template<ptrdiff_t LeastMaxValue = /* 实现定义 */>
    class counting_semaphore;

  using binary_semaphore = counting_semaphore<1>;
}

类模板 std::counting_semaphore

namespace std {
  template<ptrdiff_t LeastMaxValue = /* 实现定义 */>
  class counting_semaphore {
  public:
    static constexpr ptrdiff_t max() noexcept;

    constexpr explicit counting_semaphore(ptrdiff_t desired);
    ~counting_semaphore();

    counting_semaphore(const counting_semaphore&) = delete;
    counting_semaphore& operator=(const counting_semaphore&) = delete;

    void release(ptrdiff_t update = 1);
    void acquire();
    bool try_acquire() noexcept;
    template<class Rep, class Period>
      bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time);
    template<class Clock, class Duration>
      bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time);

  private:
    ptrdiff_t counter;          // 仅用于阐释
  };
}


标准库头文件 <set>

< cpp‎ | header

此头文件是容器库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
<initializer_list>
(C++11)
 std::initializer_list 类模板

类
set
 唯一键的集合，按照键排序
(类模板)
multiset
 键的集合，按照键排序
(类模板)

函数
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 set 中的值
(函数模板)
std::swap(std::set)
 特化 std::swap 算法
(函数模板)
erase_if(std::set)
(C++20)
 擦除所有满足特定判别标准的元素
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 multiset 中的值
(函数模板)
std::swap(std::multiset)
 特化 std::swap 算法
(函数模板)
erase_if(std::multiset)
(C++20)
 擦除所有满足特定判别标准的元素
(函数模板)
范围访问
begincbegin
(C++11)(C++14)
 返回指向容器或数组起始的迭代器
(函数模板)
endcend
(C++11)(C++14)
 返回指向容器或数组结尾的迭代器
(函数模板)
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
sizessize
(C++17)(C++20)
 返回容器或数组的大小
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)

概要

#include <compare>
#include <initializer_list>

namespace std {
  // 类模板 set
  template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
    class set;

  template<class Key, class Compare, class Allocator>
    bool operator==(const set<Key, Compare, Allocator>& x,
                    const set<Key, Compare, Allocator>& y);
  template<class Key, class Compare, class Allocator>
    /*synth-three-way-result*/<Key> operator<=>(const set<Key, Compare, Allocator>& x,
                                                const set<Key, Compare, Allocator>& y);

  template<class Key, class Compare, class Allocator>
    void swap(set<Key, Compare, Allocator>& x,
              set<Key, Compare, Allocator>& y)
      noexcept(noexcept(x.swap(y)));

  template<class Key, class Compare, class Allocator, class Predicate>
    typename set<Key, Compare, Allocator>::size_type
      erase_if(set<Key, Compare, Allocator>& c, Predicate pred);

  // 类模板 multiset
  template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
    class multiset;

  template<class Key, class Compare, class Allocator>
    bool operator==(const multiset<Key, Compare, Allocator>& x,
                    const multiset<Key, Compare, Allocator>& y);
  template<class Key, class Compare, class Allocator>
    /*synth-three-way-result*/<Key>
      operator<=>(const multiset<Key, Compare, Allocator>& x,
                  const multiset<Key, Compare, Allocator>& y);

  template<class Key, class Compare, class Allocator>
    void swap(multiset<Key, Compare, Allocator>& x,
              multiset<Key, Compare, Allocator>& y)
      noexcept(noexcept(x.swap(y)));

  template<class Key, class Compare, class Allocator, class Predicate>
    typename multiset<Key, Compare, Allocator>::size_type
      erase_if(multiset<Key, Compare, Allocator>& c, Predicate pred);

  namespace pmr {
    template<class Key, class Compare = less<Key>>
      using set = std::set<Key, Compare, polymorphic_allocator<Key>>;

    template<class Key, class Compare = less<Key>>
      using multiset = std::multiset<Key, Compare, polymorphic_allocator<Key>>;
  }
}

类模板 std::set

namespace std {
  template<class Key, class Compare = less<Key>,
           class Allocator = allocator<Key>>
  class set {
  public:
    // 类型
    using key_type               = Key;
    using key_compare            = Compare;
    using value_type             = Key;
    using value_compare          = Compare;
    using allocator_type         = Allocator;
    using pointer                = typename allocator_traits<Allocator>::pointer;
    using const_pointer          = typename allocator_traits<Allocator>::const_pointer;
    using reference              = value_type&;
    using const_reference        = const value_type&;
    using size_type              = /* 由实现定义 */;
    using difference_type        = /* 由实现定义 */;
    using iterator               = /* 由实现定义 */;
    using const_iterator         = /* 由实现定义 */;
    using reverse_iterator       = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
    using node_type              = /* 未指明 */;
    using insert_return_type     = /*insert-return-type*/<iterator, node_type>;

    // 构造/复制/销毁
    set() : set(Compare()) { }
    explicit set(const Compare& comp, const Allocator& = Allocator());
    template<class InputIt>
      set(InputIt first, InputIt last,
          const Compare& comp = Compare(), const Allocator& = Allocator());
    set(const set& x);
    set(set&& x);
    explicit set(const Allocator&);
    set(const set&, const Allocator&);
    set(set&&, const Allocator&);
    set(initializer_list<value_type>, const Compare& = Compare(),
        const Allocator& = Allocator());
    template<class InputIt>
      set(InputIt first, InputIt last, const Allocator& a)
        : set(first, last, Compare(), a) { }
    set(initializer_list<value_type> il, const Allocator& a)
      : set(il, Compare(), a) { }
    ~set();
    set& operator=(const set& x);
    set& operator=(set&& x)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_move_assignable_v<Compare>);
    set& operator=(initializer_list<value_type>);
    allocator_type get_allocator() const noexcept;

    // 迭代器
    iterator               begin() noexcept;
    const_iterator         begin() const noexcept;
    iterator               end() noexcept;
    const_iterator         end() const noexcept;

    reverse_iterator       rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator       rend() noexcept;
    const_reverse_iterator rend() const noexcept;

    const_iterator         cbegin() const noexcept;
    const_iterator         cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // 容量
    [[nodiscard]] bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    // 修改器
    template<class... Args> pair<iterator, bool> emplace(Args&&... args);
    template<class... Args> iterator emplace_hint(const_iterator position, Args&&... args);
    pair<iterator,bool> insert(const value_type& x);
    pair<iterator,bool> insert(value_type&& x);
    iterator insert(const_iterator position, const value_type& x);
    iterator insert(const_iterator position, value_type&& x);
    template<class InputIt>
      void insert(InputIt first, InputIt last);
    void insert(initializer_list<value_type>);

    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    template<class K> node_type extract(K&& x);
    insert_return_type insert(node_type&& nh);
    iterator           insert(const_iterator hint, node_type&& nh);

    iterator  erase(iterator position);
    iterator  erase(const_iterator position);
    size_type erase(const key_type& x);
    template<class K> size_type erase(K&& x);
    iterator  erase(const_iterator first, const_iterator last);
    void      swap(set&)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_swappable_v<Compare>);
    void      clear() noexcept;

    template<class C2>
      void merge(set<Key, C2, Allocator>& source);
    template<class C2>
      void merge(set<Key, C2, Allocator>&& source);
    template<class C2>
      void merge(multiset<Key, C2, Allocator>& source);
    template<class C2>
      void merge(multiset<Key, C2, Allocator>&& source);

    // 观察器
    key_compare key_comp() const;
    value_compare value_comp() const;

    // set 操作
    iterator       find(const key_type& x);
    const_iterator find(const key_type& x) const;
    template<class K> iterator       find(const K& x);
    template<class K> const_iterator find(const K& x) const;

    size_type      count(const key_type& x) const;
    template<class K> size_type count(const K& x) const;

    bool           contains(const key_type& x) const;
    template<class K> bool contains(const K& x) const;

    iterator       lower_bound(const key_type& x);
    const_iterator lower_bound(const key_type& x) const;
    template<class K> iterator       lower_bound(const K& x);
    template<class K> const_iterator lower_bound(const K& x) const;

    iterator       upper_bound(const key_type& x);
    const_iterator upper_bound(const key_type& x) const;
    template<class K> iterator       upper_bound(const K& x);
    template<class K> const_iterator upper_bound(const K& x) const;

    pair<iterator, iterator>               equal_range(const key_type& x);
    pair<const_iterator, const_iterator>   equal_range(const key_type& x) const;
    template<class K>
      pair<iterator, iterator>             equal_range(const K& x);
    template<class K>
      pair<const_iterator, const_iterator> equal_range(const K& x) const;
  };

  template<class InputIt,
           class Compare = less</*iter-value-type*/<InputIt>>,
           class Allocator = allocator</*iter-value-type*/<InputIt>>>
    set(InputIt, InputIt,
        Compare = Compare(), Allocator = Allocator())
      -> set</*iter-value-type*/<InputIt>, Compare, Allocator>;

  template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
    set(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
      -> set<Key, Compare, Allocator>;

  template<class InputIt, class Allocator>
    set(InputIt, InputIt, Allocator)
      -> set</*iter-value-type*/<InputIt>,
             less</*iter-value-type*/<InputIt>>, Allocator>;

  template<class Key, class Allocator>
    set(initializer_list<Key>, Allocator) -> set<Key, less<Key>, Allocator>;

  // 交换
  template<class Key, class Compare, class Allocator>
    void swap(set<Key, Compare, Allocator>& x,
              set<Key, Compare, Allocator>& y)
      noexcept(noexcept(x.swap(y)));
}

类模板 std::multiset

namespace std {
  template<class Key, class Compare = less<Key>,
           class Allocator = allocator<Key>>
  class multiset {
  public:
    // 类型
    using key_type               = Key;
    using key_compare            = Compare;
    using value_type             = Key;
    using value_compare          = Compare;
    using allocator_type         = Allocator;
    using pointer                = typename allocator_traits<Allocator>::pointer;
    using const_pointer          = typename allocator_traits<Allocator>::const_pointer;
    using reference              = value_type&;
    using const_reference        = const value_type&;
    using size_type              = /* 由实现定义 */;
    using difference_type        = /* 由实现定义 */;
    using iterator               = /* 由实现定义 */;
    using const_iterator         = /* 由实现定义 */;
    using reverse_iterator       = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
    using node_type              = /* 未指明 */;

    // 构造/复制/销毁
    multiset() : multiset(Compare()) { }
    explicit multiset(const Compare& comp, const Allocator& = Allocator());
    template<class InputIt>
      multiset(InputIt first, InputIt last,
               const Compare& comp = Compare(), const Allocator& = Allocator());
    multiset(const multiset& x);
    multiset(multiset&& x);
    explicit multiset(const Allocator&);
    multiset(const multiset&, const Allocator&);
    multiset(multiset&&, const Allocator&);
    multiset(initializer_list<value_type>, const Compare& = Compare(),
             const Allocator& = Allocator());
    template<class InputIt>
      multiset(InputIt first, InputIt last, const Allocator& a)
        : multiset(first, last, Compare(), a) { }
    multiset(initializer_list<value_type> il, const Allocator& a)
      : multiset(il, Compare(), a) { }
    ~multiset();
    multiset& operator=(const multiset& x);
    multiset& operator=(multiset&& x)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_move_assignable_v<Compare>);
    multiset& operator=(initializer_list<value_type>);
    allocator_type get_allocator() const noexcept;

    // 迭代器
    iterator               begin() noexcept;
    const_iterator         begin() const noexcept;
    iterator               end() noexcept;
    const_iterator         end() const noexcept;

    reverse_iterator       rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator       rend() noexcept;
    const_reverse_iterator rend() const noexcept;

    const_iterator         cbegin() const noexcept;
    const_iterator         cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // 容量
    [[nodiscard]] bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    // 修改器
    template<class... Args> iterator emplace(Args&&... args);
    template<class... Args> iterator emplace_hint(const_iterator position, Args&&... args);
    iterator insert(const value_type& x);
    iterator insert(value_type&& x);
    iterator insert(const_iterator position, const value_type& x);
    iterator insert(const_iterator position, value_type&& x);
    template<class InputIt>
      void insert(InputIt first, InputIt last);
    void insert(initializer_list<value_type>);

    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    template<class K> node_type extract(K&& x);
    iterator insert(node_type&& nh);
    iterator insert(const_iterator hint, node_type&& nh);

    iterator  erase(iterator position);
    iterator  erase(const_iterator position);
    size_type erase(const key_type& x);
    template<class K> size_type erase(K&& x);
    iterator  erase(const_iterator first, const_iterator last);
    void      swap(multiset&)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_swappable_v<Compare>);
    void      clear() noexcept;

    template<class C2>
      void merge(multiset<Key, C2, Allocator>& source);
    template<class C2>
      void merge(multiset<Key, C2, Allocator>&& source);
    template<class C2>
      void merge(set<Key, C2, Allocator>& source);
    template<class C2>
      void merge(set<Key, C2, Allocator>&& source);

    // 观察器
    key_compare key_comp() const;
    value_compare value_comp() const;

    // set 操作
    iterator       find(const key_type& x);
    const_iterator find(const key_type& x) const;
    template<class K> iterator       find(const K& x);
    template<class K> const_iterator find(const K& x) const;

    size_type      count(const key_type& x) const;
    template<class K> size_type count(const K& x) const;

    bool           contains(const key_type& x) const;
    template<class K> bool contains(const K& x) const;

    iterator       lower_bound(const key_type& x);
    const_iterator lower_bound(const key_type& x) const;
    template<class K> iterator       lower_bound(const K& x);
    template<class K> const_iterator lower_bound(const K& x) const;

    iterator       upper_bound(const key_type& x);
    const_iterator upper_bound(const key_type& x) const;
    template<class K> iterator       upper_bound(const K& x);
    template<class K> const_iterator upper_bound(const K& x) const;

    pair<iterator, iterator>               equal_range(const key_type& x);
    pair<const_iterator, const_iterator>   equal_range(const key_type& x) const;
    template<class K>
      pair<iterator, iterator>             equal_range(const K& x);
    template<class K>
      pair<const_iterator, const_iterator> equal_range(const K& x) const;
  };

  template<class InputIt,
           class Compare = less</*iter-value-type*/<InputIt>>,
           class Allocator = allocator</*iter-value-type*/<InputIt>>>
    multiset(InputIt, InputIt,
             Compare = Compare(), Allocator = Allocator())
      -> multiset</*iter-value-type*/<InputIt>, Compare, Allocator>;

  template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
    multiset(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
      -> multiset<Key, Compare, Allocator>;

  template<class InputIt, class Allocator>
    multiset(InputIt, InputIt, Allocator)
      -> multiset</*iter-value-type*/<InputIt>,
                  less<iter-value-type<InputIt>>, Allocator>;

  template<class Key, class Allocator>
    multiset(initializer_list<Key>, Allocator) -> multiset<Key, less<Key>, Allocator>;

  // 交换
  template<class Key, class Compare, class Allocator>
    void swap(multiset<Key, Compare, Allocator>& x,
              multiset<Key, Compare, Allocator>& y)
      noexcept(noexcept(x.swap(y)));
}


标准库头文件 <shared_mutex>

< cpp‎ | header

此头文件是线程支持库的一部分。

类
shared_mutex
(C++17)
 提供共享互斥设施
(类)
shared_timed_mutex
(C++14)
 提供共享互斥设施并实现有时限锁定
(类)
shared_lock
(C++14)
 实现可移动的共享互斥体所有权封装器
(类模板)

函数
std::swap(std::shared_lock)
(C++14)
 std::swap 对 shared_lock 的特化
(函数模板)

概要

namespace std {
  class shared_mutex;
  class shared_timed_mutex;
  template<class Mutex> class shared_lock;
  template<class Mutex>
    void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
}

类 std::shared_mutex

namespace std {
  class shared_mutex {
  public:
    shared_mutex();
    ~shared_mutex();

    shared_mutex(const shared_mutex&) = delete;
    shared_mutex& operator=(const shared_mutex&) = delete;

    // 排他性所有权
    void lock();                // 阻塞
    bool try_lock();
    void unlock();

    // 共享所有权
    void lock_shared();         // 阻塞
    bool try_lock_shared();
    void unlock_shared();

    using native_handle_type = /* 由实现定义 */;
    native_handle_type native_handle();
  };
}

类 std::shared_timed_mutex

namespace std {
  class shared_timed_mutex {
  public:
    shared_timed_mutex();
    ~shared_timed_mutex();

    shared_timed_mutex(const shared_timed_mutex&) = delete;
    shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;

    // 排他性所有权
    void lock();                // 阻塞
    bool try_lock();
    template<class Rep, class Period>
      bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template<class Clock, class Duration>
      bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    void unlock();

    // 共享所有权
    void lock_shared();         // 阻塞
    bool try_lock_shared();
    template<class Rep, class Period>
      bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
    template<class Clock, class Duration>
      bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
    void unlock_shared();
  };
}

类模板 std::shared_lock

namespace std {
  template<class Mutex>
  class shared_lock {
  public:
    using mutex_type = Mutex;

    // 构造/复制/析构
    shared_lock() noexcept;
    explicit shared_lock(mutex_type& m);        // 阻塞
    shared_lock(mutex_type& m, defer_lock_t) noexcept;
    shared_lock(mutex_type& m, try_to_lock_t);
    shared_lock(mutex_type& m, adopt_lock_t);
    template<class Clock, class Duration>
      shared_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
    template<class Rep, class Period>
      shared_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
    ~shared_lock();

    shared_lock(const shared_lock&) = delete;
    shared_lock& operator=(const shared_lock&) = delete;

    shared_lock(shared_lock&& u) noexcept;
    shared_lock& operator=(shared_lock&& u) noexcept;

    // 锁定
    void lock();                                // 阻塞
    bool try_lock();
    template<class Rep, class Period>
      bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template<class Clock, class Duration>
      bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    void unlock();

    // 修改器
    void swap(shared_lock& u) noexcept;
    mutex_type* release() noexcept;

    // 观察器
    bool owns_lock() const noexcept;
    explicit operator bool () const noexcept;
    mutex_type* mutex() const noexcept;

  private:
    mutex_type* pm;                             // 仅用于阐释
    bool owns;                                  // 仅用于阐释
  };

  template<class Mutex>
    void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
}


标准库头文件 <source_location>

< cpp‎ | header

此头文件是工具库的一部分。

类
source_location
(C++20)
 表示关于源码的信息，例如文件名、行号以及函数名的类
(类)

概要

namespace std {
  struct source_location;
}

类 std::source_location

namespace std {
  struct source_location {
    // 源位置构造
    static consteval source_location current() noexcept;
    constexpr source_location() noexcept;

    // 源位置域访问
    constexpr uint_least32_t line() const noexcept;
    constexpr uint_least32_t column() const noexcept;
    constexpr const char* file_name() const noexcept;
    constexpr const char* function_name() const noexcept;

  private:
    uint_least32_t line_;               // 仅为阐释
    uint_least32_t column_;             // 仅为阐释
    const char* file_name_;             // 仅为阐释
    const char* function_name_;         // 仅为阐释
  };
}


标准库头文件 <span>

< cpp‎ | header

此头文件是容器库的一部分。

类
span
(C++20)
 对象的连续序列上的无所有权视图
(类模板)

常量
dynamic_extent
(C++20)
 size_t 类型常量，指明 span 拥有动态长度
(常量)

函数
as_bytesas_writable_bytes
 转换 span 为对其底层字节的视图
(函数模板)
范围访问
begincbegin
(C++11)(C++14)
 返回指向容器或数组起始的迭代器
(函数模板)
endcend
(C++11)(C++14)
 返回指向容器或数组结尾的迭代器
(函数模板)
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
sizessize
(C++17)(C++20)
 返回容器或数组的大小
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)

概要

namespace std {
  // 常量
  inline constexpr size_t dynamic_extent = numeric_limits<size_t>::max();

  // 类模板 span
  template<class ElementType, size_t Extent = dynamic_extent>
    class span;

  template<class ElementType, size_t Extent>
    inline constexpr bool ranges::enable_borrowed_range<span<ElementType, Extent>> = true;

  // 对象表示的视图
  template<class ElementType, size_t Extent>
    span<const byte,
         Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>
      as_bytes(span<ElementType, Extent> s) noexcept;

  template<class ElementType, size_t Extent>
    span<byte, Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent>
      as_writable_bytes(span<ElementType, Extent> s) noexcept;
}

类模板 std::span

namespace std {
  template<class ElementType, size_t Extent = dynamic_extent>
  class span {
  public:
    // 常量与类型
    using element_type = ElementType;
    using value_type = remove_cv_t<ElementType>;
    using size_type = size_t;
    using difference_type = ptrdiff_t;
    using pointer = element_type*;
    using const_pointer = const element_type*;
    using reference = element_type&;
    using const_reference = const element_type&;
    using iterator = /* 由实现定义 */;
    using reverse_iterator = std::reverse_iterator<iterator>;
    static constexpr size_type extent = Extent;

    // 构造函数、复制与赋值
    constexpr span() noexcept;
    template<class It>
      constexpr explicit(extent != dynamic_extent) span(It first, size_type count);
    template<class It, class End>
      constexpr explicit(extent != dynamic_extent) span(It first, End last);
    template<size_t N>
      constexpr span(type_identity_t<element_type> (&arr)[N]) noexcept;
    template<class T, size_t N>
      constexpr span(array<T, N>& arr) noexcept;
    template<class T, size_t N>
      constexpr span(const array<T, N>& arr) noexcept;
    template<class R>
      constexpr explicit(extent != dynamic_extent) span(R&& r);
    constexpr span(const span& other) noexcept = default;
    template<class OtherElementType, size_t OtherExtent>
      constexpr explicit(/* 见描述 */)
        span(const span<OtherElementType, OtherExtent>& s) noexcept;

    ~span() noexcept = default;

    constexpr span& operator=(const span& other) noexcept = default;

    // 子视图
    template<size_t Count>
      constexpr span<element_type, Count> first() const;
    template<size_t Count>
      constexpr span<element_type, Count> last() const;
    template<size_t Offset, size_t Count = dynamic_extent>
      constexpr span<element_type, /* see description */> subspan() const;

    constexpr span<element_type, dynamic_extent> first(size_type count) const;
    constexpr span<element_type, dynamic_extent> last(size_type count) const;
    constexpr span<element_type, dynamic_extent> subspan(
      size_type offset, size_type count = dynamic_extent) const;

    // 观察器
    constexpr size_type size() const noexcept;
    constexpr size_type size_bytes() const noexcept;
    [[nodiscard]] constexpr bool empty() const noexcept;

    // 元素访问
    constexpr reference operator[](size_type idx) const;
    constexpr reference front() const;
    constexpr reference back() const;
    constexpr pointer data() const noexcept;

    // 迭代器支持
    constexpr iterator begin() const noexcept;
    constexpr iterator end() const noexcept;
    constexpr reverse_iterator rbegin() const noexcept;
    constexpr reverse_iterator rend() const noexcept;

  private:
    pointer data_;              // 仅用于阐释
    size_type size_;            // 仅用于阐释
  };

  template<class It, class EndOrSize>
    span(It, EndOrSize) -> span<remove_reference_t<iter_reference_t<It>>>;
  template<class T, size_t N>
    span(T (&)[N]) -> span<T, N>;
  template<class T, size_t N>
    span(array<T, N>&) -> span<T, N>;
  template<class T, size_t N>
    span(const array<T, N>&) -> span<const T, N>;
  template<class R>
    span(R&&) -> span<remove_reference_t<ranges::range_reference_t<R>>>;
}


标准库头文件 <spanstream>

< cpp‎ | header

此头文件是输入/输出库的一部分。

类
basic_spanbuf
(C++23)
 实现原始固定字符缓冲区设备
(类模板)
basic_ispanstream
(C++23)
 实现固定字符缓冲区输入操作
(类模板)
basic_ospanstream
(C++23)
 实现固定字符缓冲区输出操作
(类模板)
basic_spanstream
(C++23)
 实现固定字符缓冲区输入/输出操作
(类模板)
spanbuf(C++23) std::basic_spanbuf<char>
(typedef)
wspanbuf(C++23) std::basic_spanbuf<wchar_t>
(typedef)
ispanstream(C++23) std::basic_ispanstream<char>
(typedef)
wispanstream(C++23) std::basic_ispanstream<wchar_t>
(typedef)
ospanstream(C++23) std::basic_ospanstream<char>
(typedef)
wospanstream(C++23) std::basic_ospanstream<wchar_t>
(typedef)
spanstream(C++23) std::basic_spanstream<char>
(typedef)
wspanstream(C++23) std::basic_spanstream<wchar_t>
(typedef)

函数
std::swap(std::basic_spanbuf)
(C++23)
 特化 std::swap 算法
(函数模板)
std::swap(std::basic_ispanstream)
(C++23)
 特化 std::swap 算法
(函数模板)
std::swap(std::basic_ospanstream)
(C++23)
 特化 std::swap 算法
(函数模板)
std::swap(std::basic_spanstream)
(C++23)
 特化 std::swap 算法
(函数模板)

概要

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
    class basic_spanbuf;

  using spanbuf = basic_spanbuf<char>;
  using wspanbuf = basic_spanbuf<wchar_t>;

  template<class CharT, class Traits = char_traits<CharT>>
    class basic_ispanstream;

  using ispanstream = basic_ispanstream<char>;
  using wispanstream = basic_ispanstream<wchar_t>;

  template<class CharT, class Traits = char_traits<CharT>>
    class basic_ospanstream;

  using ospanstream = basic_ospanstream<char>;
  using wospanstream = basic_ospanstream<wchar_t>;

  template<class CharT, class Traits = char_traits<CharT>>
    class basic_spanstream;

  using spanstream = basic_spanstream<char>;
  using wspanstream = basic_spanstream<wchar_t>;
}

类模板 std::basic_spanbuf

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_spanbuf
    : public basic_streambuf<CharT, Traits> {
  public:
    using char_type      = CharT;
    using int_type       = typename Traits::int_type;
    using pos_type       = typename Traits::pos_type;
    using off_type       = typename Traits::off_type;
    using traits_type    = Traits;

    // 构造函数
    basic_spanbuf() : basic_spanbuf(ios_base::in | ios_base::out) {}
    explicit basic_spanbuf(ios_base::openmode which)
      : basic_spanbuf(std::span<CharT>(), which) {}
    explicit basic_spanbuf(
      std::span<CharT> s,
      ios_base::openmode which = ios_base::in | ios_base::out);
    basic_spanbuf(const basic_spanbuf&) = delete;
    basic_spanbuf(basic_spanbuf&& rhs);

    // 赋值与交换
    basic_spanbuf& operator=(const basic_spanbuf&) = delete;
    basic_spanbuf& operator=(basic_spanbuf&& rhs);
    void swap(basic_spanbuf& rhs);

    // 获取与设置
    std::span<CharT> span() const noexcept;
    void span(std::span<CharT> s) noexcept;

  protected:
    // 重写的虚函数
    basic_streambuf<CharT, Traits>* setbuf(CharT*, streamsize) override;
    pos_type seekoff(off_type off, ios_base::seekdir way,
                     ios_base::openmode which
                       = ios_base::in | ios_base::out) override;
    pos_type seekpos(pos_type sp,
                     ios_base::openmode which
                       = ios_base::in | ios_base::out) override;

  private:
    ios_base::openmode mode; // 仅用于阐释
    std::span<CharT> buf; // 仅用于阐释
  };

  template<class CharT, class Traits>
    void swap(basic_spanbuf<CharT, Traits>& x,
              basic_spanbuf<CharT, Traits>& y);
}

类模板 std::basic_ispanstream

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_ispanstream
    : public basic_istream<CharT, Traits> {
  public:
    using char_type      = CharT;
    using int_type       = typename Traits::int_type;
    using pos_type       = typename Traits::pos_type;
    using off_type       = typename Traits::off_type;
    using traits_type    = Traits;

    // 构造函数
    explicit basic_ispanstream(
      std::span<CharT> s,
      ios_base::openmode which = ios_base::in);
    basic_ispanstream(const basic_ispanstream&) = delete;
    basic_ispanstream(basic_ispanstream&& rhs);
    template<class ROS>
    explicit basic_ispanstream(ROS&& s);

    // 赋值与交换
    basic_ispanstream& operator=(const basic_ispanstream&) = delete;
    basic_ispanstream& operator=(basic_ispanstream&& rhs);
    void swap(basic_ispanstream& rhs);

    // 成员
    basic_spanbuf<CharT, Traits>* rdbuf() const noexcept;
    std::span<const CharT> span() const noexcept;
    void span(std::span<CharT> s) noexcept;
    template<class ROS>
    void span(ROS&& s) noexcept;

  private:
    basic_spanbuf<CharT, Traits> sb; // 仅用于阐释
  };

  template<class CharT, class Traits>
    void swap(basic_ispanstream<CharT, Traits>& x,
              basic_ispanstream<CharT, Traits>& y);
}

类模板 std::basic_ospanstream

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_ospanstream
    : public basic_ostream<CharT, Traits> {
  public:
    using char_type      = CharT;
    using int_type       = typename Traits::int_type;
    using pos_type       = typename Traits::pos_type;
    using off_type       = typename Traits::off_type;
    using traits_type    = Traits;

    // 构造函数
    explicit basic_ospanstream(
      std::span<CharT> s,
      ios_base::openmode which = ios_base::out);
    basic_ospanstream(const basic_ospanstream&) = delete;
    basic_ospanstream(basic_ospanstream&& rhs);

    // 赋值与交换
    basic_ospanstream& operator=(const basic_ospanstream&) = delete;
    basic_ospanstream& operator=(basic_ospanstream&& rhs);
    void swap(basic_ospanstream& rhs);

    // 成员
    basic_spanbuf<CharT, Traits>* rdbuf() const noexcept;
    std::span<CharT> span() const noexcept;
    void span(std::span<CharT> s) noexcept;

  private:
    basic_spanbuf<CharT, Traits> sb; // 仅用于阐释
  };

  template<class CharT, class Traits>
    void swap(basic_ospanstream<CharT, Traits>& x,
              basic_ospanstream<CharT, Traits>& y);
}

类模板 std::basic_spanstream

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_spanstream
    : public basic_iostream<CharT, Traits> {
  public:
    using char_type     = charT;
    using int_type      = typename Traits::int_type;
    using pos_type      = typename Traits::pos_type;
    using off_type      = typename Traits::off_type;
    using traits_type   = Traits;

    // 构造函数
    explicit basic_spanstream(
      std::span<CharT> s,
      ios_base::openmode which = ios_base::out | ios_base::in);
    basic_spanstream(const basic_spanstream&) = delete;
     basic_spanstream(basic_spanstream&& rhs);

     // 赋值与交换
    basic_spanstream& operator=(const basic_spanstream&) = delete;
    basic_spanstream& operator=(basic_spanstream&& rhs);
    void swap(basic_spanstream& rhs);

    // 成员
    basic_spanbuf<CharT, Traits>* rdbuf() const noexcept;
    std::span<CharT> span() const noexcept;
    void span(std::span<CharT> s) noexcept;

  private:
    basic_spanbuf<CharT, Traits> sb; // 仅用于阐释
  };

  template<class CharT, class Traits>
    void swap(basic_spanstream<CharT, Traits>& x,
              basic_spanstream<CharT, Traits>& y);
}


标准库头文件 <sstream>

< cpp‎ | header

此头文件是输入/输出库的一部分。

类
basic_stringbuf
 实现原生字符串设备
(类模板)
basic_istringstream
 实现高层字符串流输入操作
(类模板)
basic_ostringstream
 实现高层字符串流输出操作
(类模板)
basic_stringstream
 实现高层字符串流输入/输出操作
(类模板)
stringbuf std::basic_stringbuf <char>
(typedef)
wstringbuf std::basic_stringbuf <wchar_t>
(typedef)
istringstream std::basic_istringstream <char>
(typedef)
wistringstream std::basic_istringstream <wchar_t>
(typedef)
ostringstream std::basic_ostringstream <char>
(typedef)
wostringstream std::basic_ostringstream <wchar_t>
(typedef)
stringstream std::basic_stringstream <char>
(typedef)
wstringstream std::basic_stringstream <wchar_t>
(typedef)

函数
std::swap(std::basic_stringbuf)
(C++11)
 特化 std::swap 算法
(函数模板)
std::swap(std::basic_istringstream)
(C++11)
 特化 std::swap 算法
(函数模板)
std::swap(std::basic_ostringstream)
(C++11)
 特化 std::swap 算法
(函数模板)
std::swap(std::basic_stringstream)
(C++11)
 特化 std::swap 算法
(函数模板)

概要

namespace std {
  template<class CharT, class Traits = char_traits<CharT>,
           class Allocator = allocator<CharT>>
    class basic_stringbuf;

  using stringbuf  = basic_stringbuf<char>;
  using wstringbuf = basic_stringbuf<wchar_t>;

  template<class CharT, class Traits = char_traits<CharT>,
           class Allocator = allocator<CharT>>
    class basic_istringstream;

  using istringstream  = basic_istringstream<char>;
  using wistringstream = basic_istringstream<wchar_t>;

  template<class CharT, class Traits = char_traits<CharT>,
           class Allocator = allocator<CharT>>
    class basic_ostringstream;
  using ostringstream  = basic_ostringstream<char>;
  using wostringstream = basic_ostringstream<wchar_t>;

  template<class CharT, class Traits = char_traits<CharT>,
           class Allocator = allocator<CharT>>
    class basic_stringstream;
  using stringstream  = basic_stringstream<char>;
  using wstringstream = basic_stringstream<wchar_t>;
}

类模板 std::basic_stringbuf

namespace std {
  template<class CharT, class Traits = char_traits<CharT>,
           class Allocator = allocator<CharT>>
  class basic_stringbuf : public basic_streambuf<CharT, Traits> {
  public:
    using char_type      = CharT;
    using int_type       = typename Traits::int_type;
    using pos_type       = typename Traits::pos_type;
    using off_type       = typename Traits::off_type;
    using Traits_type    = Traits;
    using allocator_type = Allocator;

    // 构造函数
    basic_stringbuf() : basic_stringbuf(ios_base::in | ios_base::out) {}
    explicit basic_stringbuf(ios_base::openmode which);
    explicit basic_stringbuf(
      const basic_string<CharT, Traits, Allocator>& s,
      ios_base::openmode which = ios_base::in | ios_base::out);
    explicit basic_stringbuf(const Allocator& a)
      : basic_stringbuf(ios_base::in | ios_base::out, a) {}
    basic_stringbuf(ios_base::openmode which, const Allocator& a);
    explicit basic_stringbuf(
      basic_string<CharT, Traits, Allocator>&& s,
      ios_base::openmode which = ios_base::in | ios_base::out);
    template<class SAlloc>
      basic_stringbuf(
        const basic_string<CharT, Traits, SAlloc>& s, const Allocator& a)
        : basic_stringbuf(s, ios_base::in | ios_base::out, a) {}
    template<class SAlloc>
      basic_stringbuf(
        const basic_string<CharT, Traits, SAlloc>& s,
        ios_base::openmode which, const Allocator& a);
    template<class SAlloc>
      explicit basic_stringbuf(
        const basic_string<CharT, Traits, SAlloc>& s,
        ios_base::openmode which = ios_base::in | ios_base::out);
    basic_stringbuf(const basic_stringbuf&) = delete;
    basic_stringbuf(basic_stringbuf&& rhs);
    basic_stringbuf(basic_stringbuf&& rhs, const Allocator& a);

    // 赋值与交换
    basic_stringbuf& operator=(const basic_stringbuf&) = delete;
    basic_stringbuf& operator=(basic_stringbuf&& rhs);
    void swap(basic_stringbuf& rhs) noexcept(see below);

    // 获取器与设置器
    allocator_type get_allocator() const noexcept;

    basic_string<CharT, Traits, Allocator> str() const &;
    template<class SAlloc>
      basic_string<CharT,Traits,SAlloc> str(const SAlloc& sa) const;
    basic_string<CharT, Traits, Allocator> str() &&;
    basic_string_view<CharT, Traits> view() const noexcept;

    void str(const basic_string<CharT, Traits, Allocator>& s);
    template<class SAlloc>
      void str(const basic_string<CharT, Traits, SAlloc>& s);
    void str(basic_string<CharT, Traits, Allocator>&& s);

  protected:
    // 覆写的虚函数
    int_type underflow() override;
    int_type pbackfail(int_type c = Traits::eof()) override;
    int_type overflow (int_type c = Traits::eof()) override;
    basic_streambuf<CharT, Traits>* setbuf(CharT*, streamsize) override;

    pos_type seekoff(off_type off, ios_base::seekdir way,
                     ios_base::openmode which
                      = ios_base::in | ios_base::out) override;
    pos_type seekpos(pos_type sp,
                     ios_base::openmode which
                      = ios_base::in | ios_base::out) override;

  private:
    ios_base::openmode mode;                        // 仅用于阐释
    basic_string<CharT, Traits, Allocator> buf;     // 仅用于阐释
    void init_buf_ptrs();                           // 仅用于阐释
  };

  template<class CharT, class Traits, class Allocator>
    void swap(basic_stringbuf<CharT, Traits, Allocator>& x,
              basic_stringbuf<CharT, Traits, Allocator>& y) noexcept(noexcept(x.swap(y)));
}

类模板 std::basic_istringstream

namespace std {
  template<class CharT, class Traits = char_traits<CharT>,
           class Allocator = allocator<CharT>>
  class basic_istringstream : public basic_istream<CharT, Traits> {
  public:
    using char_type      = CharT;
    using int_type       = typename Traits::int_type;
    using pos_type       = typename Traits::pos_type;
    using off_type       = typename Traits::off_type;
    using Traits_type    = Traits;
    using allocator_type = Allocator;

    // 构造函数
    basic_istringstream() : basic_istringstream(ios_base::in) {}
    explicit basic_istringstream(ios_base::openmode which);
    explicit basic_istringstream(
      const basic_string<CharT, Traits, Allocator>& s,
      ios_base::openmode which = ios_base::in);
    basic_istringstream(ios_base::openmode which, const Allocator& a);
    explicit basic_istringstream(
      basic_string<CharT, Traits, Allocator>&& s,
      ios_base::openmode which = ios_base::in);
    template<class SAlloc>
      basic_istringstream(
        const basic_string<CharT, Traits, SAlloc>& s, const Allocator& a)
        : basic_istringstream(s, ios_base::in, a) {}
    template<class SAlloc>
      basic_istringstream(
        const basic_string<CharT, Traits, SAlloc>& s,
        ios_base::openmode which, const Allocator& a);
    template<class SAlloc>
      explicit basic_istringstream(
        const basic_string<CharT, Traits, SAlloc>& s,
        ios_base::openmode which = ios_base::in);
    basic_istringstream(const basic_istringstream&) = delete;
    basic_istringstream(basic_istringstream&& rhs);

    // 赋值与交换
    basic_istringstream& operator=(const basic_istringstream&) = delete;
    basic_istringstream& operator=(basic_istringstream&& rhs);
    void swap(basic_istringstream& rhs);

    // 成员
    basic_stringbuf<CharT, Traits, Allocator>* rdbuf() const;
    basic_string<CharT, Traits, Allocator> str() const &;
    template<class SAlloc>
      basic_string<CharT,Traits,SAlloc> str(const SAlloc& sa) const;
    basic_string<CharT, Traits, Allocator> str() &&;
    basic_string_view<CharT, Traits> view() const noexcept;

    void str(const basic_string<CharT, Traits, Allocator>& s);
    template<class SAlloc>
      void str(const basic_string<CharT, Traits, SAlloc>& s);
    void str(basic_string<CharT, Traits, Allocator>&& s);

  private:
    basic_stringbuf<CharT, Traits, Allocator> sb;   // 仅用于阐释
  };

  template<class CharT, class Traits, class Allocator>
    void swap(basic_istringstream<CharT, Traits, Allocator>& x,
              basic_istringstream<CharT, Traits, Allocator>& y);
}

类模板 std::basic_ostringstream

namespace std {
  template<class CharT, class Traits = char_traits<CharT>,
           class Allocator = allocator<CharT>>
  class basic_ostringstream : public basic_ostream<CharT, Traits> {
  public:
    using char_type      = CharT;
    using int_type       = typename Traits::int_type;
    using pos_type       = typename Traits::pos_type;
    using off_type       = typename Traits::off_type;
    using Traits_type    = Traits;
    using allocator_type = Allocator;

    // 构造函数
    basic_ostringstream() : basic_ostringstream(ios_base::out) {}
    explicit basic_ostringstream(ios_base::openmode which);
    explicit basic_ostringstream(
      const basic_string<CharT, Traits, Allocator>& s,
      ios_base::openmode which = ios_base::out);
    basic_ostringstream(ios_base::openmode which, const Allocator& a);
    explicit basic_ostringstream(
      basic_string<CharT, Traits, Allocator>&& s,
      ios_base::openmode which = ios_base::out);
    template<class SAlloc>
      basic_ostringstream(
        const basic_string<CharT, Traits, SAlloc>& s, const Allocator& a)
        : basic_ostringstream(s, ios_base::out, a) {}
    template<class SAlloc>
      basic_ostringstream(
        const basic_string<CharT, Traits, SAlloc>& s,
        ios_base::openmode which, const Allocator& a);
    template<class SAlloc>
      explicit basic_ostringstream(
        const basic_string<CharT, Traits, SAlloc>& s,
        ios_base::openmode which = ios_base::out);
    basic_ostringstream(const basic_ostringstream&) = delete;
    basic_ostringstream(basic_ostringstream&& rhs);

    // 赋值与交换
    basic_ostringstream& operator=(const basic_ostringstream&) = delete;
    basic_ostringstream& operator=(basic_ostringstream&& rhs);
    void swap(basic_ostringstream& rhs);

    // 成员
    basic_stringbuf<CharT, Traits, Allocator>* rdbuf() const;

    basic_string<CharT, Traits, Allocator> str() const &;
    template<class SAlloc>
      basic_string<CharT,Traits,SAlloc> str(const SAlloc& sa) const;
    basic_string<CharT, Traits, Allocator> str() &&;
    basic_string_view<CharT, Traits> view() const noexcept;

    void str(const basic_string<CharT, Traits, Allocator>& s);
    template<class SAlloc>
      void str(const basic_string<CharT, Traits, SAlloc>& s);
    void str(basic_string<CharT, Traits, Allocator>&& s);

   private:
    basic_stringbuf<CharT, Traits, Allocator> sb;   // 仅用于阐释
  };

  template<class CharT, class Traits, class Allocator>
    void swap(basic_ostringstream<CharT, Traits, Allocator>& x,
              basic_ostringstream<CharT, Traits, Allocator>& y);
}

类模板 std::basic_stringstream

namespace std {
  template<class CharT, class Traits = char_traits<CharT>,
           class Allocator = allocator<CharT>>
  class basic_stringstream : public basic_iostream<CharT, Traits> {
  public:
    using char_type      = CharT;
    using int_type       = typename Traits::int_type;
    using pos_type       = typename Traits::pos_type;
    using off_type       = typename Traits::off_type;
    using Traits_type    = Traits;
    using allocator_type = Allocator;

    // 构造函数
    basic_stringstream() : basic_stringstream(ios_base::out | ios_base::in) {}
    explicit basic_stringstream(ios_base::openmode which);
    explicit basic_stringstream(
      const basic_string<CharT, Traits, Allocator>& s,
      ios_base::openmode which = ios_base::out | ios_base::in);
    basic_stringstream(ios_base::openmode which, const Allocator& a);
    explicit basic_stringstream(
      basic_string<CharT, Traits, Allocator>&& s,
      ios_base::openmode which = ios_base::out | ios_base::in);
    template<class SAlloc>
      basic_stringstream(
        const basic_string<CharT, Traits, SAlloc>& s, const Allocator& a)
        : basic_stringstream(s, ios_base::out | ios_base::in, a) {}
    template<class SAlloc>
      basic_stringstream(
        const basic_string<CharT, Traits, SAlloc>& s,
        ios_base::openmode which, const Allocator& a);
    template<class SAlloc>
      explicit basic_stringstream(
        const basic_string<CharT, Traits, SAlloc>& s,
        ios_base::openmode which = ios_base::out | ios_base::in);
    basic_stringstream(const basic_stringstream&) = delete;
    basic_stringstream(basic_stringstream&& rhs);

    // 赋值与交换
    basic_stringstream& operator=(const basic_stringstream&) = delete;
    basic_stringstream& operator=(basic_stringstream&& rhs);
    void swap(basic_stringstream& rhs);

    // 成员
    basic_stringbuf<CharT, Traits, Allocator>* rdbuf() const;

    basic_string<CharT, Traits, Allocator> str() const &;
    template<class SAlloc>
      basic_string<CharT,Traits,SAlloc> str(const SAlloc& sa) const;
    basic_string<CharT, Traits, Allocator> str() &&;
    basic_string_view<CharT, Traits> view() const noexcept;

    void str(const basic_string<CharT, Traits, Allocator>& s);
    template<class SAlloc>
      void str(const basic_string<CharT, Traits, SAlloc>& s);
    void str(basic_string<CharT, Traits, Allocator>&& s);

  private:
    basic_stringbuf<CharT, Traits> sb;  // 仅用于阐释
  };

  template<class CharT, class Traits, class Allocator>
    void swap(basic_stringstream<CharT, Traits, Allocator>& x,
              basic_stringstream<CharT, Traits, Allocator>& y);
}


标准库头文件 <stack>

< cpp‎ | header

此头文件是容器库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
<initializer_list>
(C++11)
 std::initializer_list 类模板

类
stack
 适配一个容器以提供栈（LIFO 数据结构）
(类模板)
std::uses_allocator<std::stack>
(C++11)
 特化 std::uses_allocator 类型特征
(类模板特化)

函数
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20)
 按照字典顺序比较 stack 中的值
(函数模板)
std::swap(std::stack)
(C++11)
 特化 std::swap 算法
(函数模板)

概要

#include <compare>
#include <initializer_list>

namespace std {
  template<class T, class Container = deque<T>> class stack;

  template<class T, class Container>
    bool operator==(const stack<T, Container>& x, const stack<T, Container>& y);
  template<class T, class Container>
    bool operator!=(const stack<T, Container>& x, const stack<T, Container>& y);
  template<class T, class Container>
    bool operator< (const stack<T, Container>& x, const stack<T, Container>& y);
  template<class T, class Container>
    bool operator> (const stack<T, Container>& x, const stack<T, Container>& y);
  template<class T, class Container>
    bool operator<=(const stack<T, Container>& x, const stack<T, Container>& y);
  template<class T, class Container>
    bool operator>=(const stack<T, Container>& x, const stack<T, Container>& y);
  template<class T, three_way_comparable Container>
    compare_three_way_result_t<Container>
      operator<=>(const stack<T, Container>& x, const stack<T, Container>& y);

  template<class T, class Container>
    void swap(stack<T, Container>& x, stack<T, Container>& y)
      noexcept(noexcept(x.swap(y)));
  template<class T, class Container, class Alloc>
    struct uses_allocator<stack<T, Container>, Alloc>;
}

类模板 std::stack

namespace std {
  template<class T, class Container = deque<T>>
  class stack {
  public:
    using value_type      = typename Container::value_type;
    using reference       = typename Container::reference;
    using const_reference = typename Container::const_reference;
    using size_type       = typename Container::size_type;
    using container_type  = Container;

  protected:
    Container c;

  public:
    stack() : stack(Container()) {}
    explicit stack(const Container&);
    explicit stack(Container&&);
    template<class InputIt> stack(InputIt first, InputIt last);
    template<class Alloc> explicit stack(const Alloc&);
    template<class Alloc> stack(const Container&, const Alloc&);
    template<class Alloc> stack(Container&&, const Alloc&);
    template<class Alloc> stack(const stack&, const Alloc&);
    template<class Alloc> stack(stack&&, const Alloc&);
    template<class InputIt, class Alloc>
      stack(InputIt first, InputIt last, const Alloc&);

    [[nodiscard]] bool empty() const    { return c.empty(); }
    size_type size()  const             { return c.size(); }
    reference         top()             { return c.back(); }
    const_reference   top() const       { return c.back(); }
    void push(const value_type& x)      { c.push_back(x); }
    void push(value_type&& x)           { c.push_back(std::move(x)); }
    template<class... Args>
      decltype(auto) emplace(Args&&... args)
        { return c.emplace_back(std::forward<Args>(args)...); }
    void pop()                          { c.pop_back(); }
    void swap(stack& s) noexcept(is_nothrow_swappable_v<Container>)
      { using std::swap; swap(c, s.c); }
  };

  template<class Container>
    stack(Container) -> stack<typename Container::value_type, Container>;

  template<class InputIt>
    stack(InputIt, InputIt) -> stack</*iter-value-type*/<InputIt>>;

  template<class Container, class Allocator>
    stack(Container, Allocator) -> stack<typename Container::value_type, Container>;

  template<class InputIt, class Allocator>
    stack(InputIt, InputIt, Allocator)
      -> stack</*iter-value-type*/<InputIt>, deque</*iter-value-type*/<InputIt>,
               Allocator>>;

  template<class T, class Container, class Alloc>
    struct uses_allocator<stack<T, Container>, Alloc>
      : uses_allocator<Container, Alloc>::type { };
}


标准库头文件 <stacktrace>

< cpp‎ | header

此头文件是通用工具库的一部分。

类
stacktrace_entry
(C++23)
 栈踪中求值的表示
(类)
basic_stacktrace
(C++23)
 由栈踪条目组成的调用序列的近似表示
(类模板)
std::hash<std::stacktrace_entry>
(C++23)
 std::stacktrace_entry 的散列支持
(类模板特化)
std::hash<std::basic_stacktrace>
(C++23)
 std::basic_stacktrace 的散列支持
(类模板特化)
前置声明
定义于头文件 <functional>
hash
(C++11)
 散列函数对象
(类模板)

函数
std::swap(std::basic_stacktrace)
(C++23)
 特化 std::swap 算法
(函数模板)
to_string
(C++23)
 返回拥有 stacktrace_entry 的描述的字符串
(函数)
to_string
(C++23)
 返回拥有 basic_stacktrace 的描述的字符串
(函数模板)
operator<<
(C++23)
 进行 stacktrace_entry 的流输出
(函数模板)
operator<<
(C++23)
 进行 basic_stracktrace 的流输出
(函数模板)

概要

namespace std {
  // 类 stacktrace_entry
  class stacktrace_entry;

  // 类模板 basic_stacktrace
  template<class Allocator>
    class basic_stacktrace;

  // basic_stacktrace typedef 名
  using stacktrace = basic_stacktrace<allocator<stacktrace_entry>>;

  // 非成员函数
  template<class Allocator>
    void swap(basic_stacktrace<Allocator>& a, basic_stacktrace<Allocator>& b)
      noexcept(noexcept(a.swap(b)));

  string to_string(const stacktrace_entry& f);

  template<class Allocator>
    string to_string(const basic_stacktrace<Allocator>& st);

  template<class CharT, class traits>
    basic_ostream<CharT, traits>&
      operator<<(basic_ostream<CharT, traits>& os, const stacktrace_entry& f);

  template<class CharT, class Traits, class Allocator>
    basic_ostream<CharT, traits>&
      operator<<(basic_ostream<CharT, Traits>& os, const basic_stacktrace<Allocator>& st);

  namespace pmr {
    using stacktrace = std::basic_stacktrace<polymorphic_allocator<stacktrace_entry>>;
  }

  // 散列支持
  template<class T> struct hash;
  template<> struct hash<stacktrace_entry>;
  template<class Allocator> struct hash<basic_stacktrace<Allocator>>;
}

类 std::stacktrace_entry

namespace std {
  class stacktrace_entry {
  public:
    using native_handle_type = /* 由实现定义 */;

    // 构造函数
    constexpr stacktrace_entry() noexcept;
    constexpr stacktrace_entry(const stacktrace_entry& other) noexcept;
    constexpr stacktrace_entry& operator=(const stacktrace_entry& other) noexcept;

    ~stacktrace_entry();

    // 观察器
    constexpr native_handle_type native_handle() const noexcept;
    constexpr explicit operator bool() const noexcept;

    // 查询
    string description() const;
    string source_file() const;
    uint_least32_t source_line() const;

    // 比较
    friend constexpr bool operator==(const stacktrace_entry& x,
                                     const stacktrace_entry& y) noexcept;
    friend constexpr strong_ordering operator<=>(const stacktrace_entry& x,
                                                 const stacktrace_entry& y) noexcept;
  };
}

类模板 std::basic_stacktrace

namespace std {
  template<class Allocator>
  class basic_stacktrace {
  public:
    using value_type = stacktrace_entry;
    using const_reference = const value_type&;
    using reference = value_type&;
    using const_iterator = /* 由实现定义 */;
    using iterator = const_iterator;
    using reverse_iterator = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
    using difference_type = /* 由实现定义 */;
    using size_type = /* 由实现定义 */;
    using allocator_type = Allocator;

    // 创建与赋值
    static basic_stacktrace
      current(const allocator_type& alloc = allocator_type()) noexcept;
    static basic_stacktrace
      current(size_type skip, const allocator_type& alloc = allocator_type()) noexcept;
    static basic_stacktrace
      current(size_type skip, size_type max_depth,
              const allocator_type& alloc = allocator_type()) noexcept;

    basic_stacktrace() noexcept(is_nothrow_default_constructible_v<allocator_type>);
    explicit basic_stacktrace(const allocator_type& alloc) noexcept;

    basic_stacktrace(const basic_stacktrace& other);
    basic_stacktrace(basic_stacktrace&& other) noexcept;
    basic_stacktrace(const basic_stacktrace& other, const allocator_type& alloc);
    basic_stacktrace(basic_stacktrace&& other, const allocator_type& alloc);
    basic_stacktrace& operator=(const basic_stacktrace& other);
    basic_stacktrace& operator=(basic_stacktrace&& other) noexcept(
        allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
        allocator_traits<Allocator>::is_always_equal::value);

    ~basic_stacktrace();

    // 观察器
    allocator_type get_allocator() const noexcept;

    const_iterator begin() const noexcept;
    const_iterator end() const noexcept;
    const_reverse_iterator rbegin() const noexcept;
    const_reverse_iterator rend() const noexcept;

    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    [[nodiscard]] bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    const_reference operator[](size_type) const;
    const_reference at(size_type) const;

    // 比较
    template<class Allocator2>
    friend bool operator==(const basic_stacktrace& x,
                           const basic_stacktrace<Allocator2>& y) noexcept;
    template<class Allocator2>
    friend strong_ordering operator<=>(const basic_stacktrace& x,
                                       const basic_stacktrace<Allocator2>& y) noexcept;

    // 修改器
    void swap(basic_stacktrace& other)
      noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value ||
        allocator_traits<Allocator>::is_always_equal::value);

  private:
    vector<value_type, allocator_type> frames_;         // 仅用于阐释
  };
}


标准库头文件 <stdatomic.h>

< cpp‎ | header

此头文件最初在 C 标准库。

此头文件是原子操作库的一部分。

未指定 <stdatomic.h> 是否提供任何命名空间 std 中的声明。

宏
_Atomic
(C++23)
 使得 _Atomic(T) 等同于 std::atomic <T> 的兼容性宏
(宏函数)

类型
atomic_flag
(C++11)
 免锁的布尔原子类型
(类)
memory_order
(C++11)
 为给定的原子操作定义内存顺序约束
(枚举)
atomic_bool
(C++11)
 std::atomic <bool>
(typedef)
atomic_char
(C++11)
 std::atomic <char>
(typedef)
atomic_schar
(C++11)
 std::atomic <signed char>
(typedef)
atomic_uchar
(C++11)
 std::atomic <unsigned char>
(typedef)
atomic_short
(C++11)
 std::atomic <short>
(typedef)
atomic_ushort
(C++11)
 std::atomic <unsigned short>
(typedef)
atomic_int
(C++11)
 std::atomic <int>
(typedef)
atomic_uint
(C++11)
 std::atomic <unsigned int>
(typedef)
atomic_long
(C++11)
 std::atomic <long>
(typedef)
atomic_ulong
(C++11)
 std::atomic <unsigned long>
(typedef)
atomic_llong
(C++11)
 std::atomic <long long>
(typedef)
atomic_ullong
(C++11)
 std::atomic <unsigned long long>
(typedef)
atomic_char8_t
(C++20)
 std::atomic <char8_t>
(typedef)
atomic_char16_t
(C++11)
 std::atomic <char16_t>
(typedef)
atomic_char32_t
(C++11)
 std::atomic <char32_t>
(typedef)
atomic_wchar_t
(C++11)
 std::atomic <wchar_t>
(typedef)
atomic_int8_t
(C++11)(可选)
 std::atomic < std::int8_t >
(typedef)
atomic_uint8_t
(C++11)(可选)
 std::atomic < std::uint8_t >
(typedef)
atomic_int16_t
(C++11)(可选)
 std::atomic < std::int16_t >
(typedef)
atomic_uint16_t
(C++11)(可选)
 std::atomic < std::uint16_t >
(typedef)
atomic_int32_t
(C++11)(可选)
 std::atomic < std::int32_t >
(typedef)
atomic_uint32_t
(C++11)(可选)
 std::atomic < std::uint32_t >
(typedef)
atomic_int64_t
(C++11)(可选)
 std::atomic < std::int64_t >
(typedef)
atomic_uint64_t
(C++11)(可选)
 std::atomic < std::uint64_t >
(typedef)
atomic_int_least8_t
(C++11)
 std::atomic < std::int_least8_t >
(typedef)
atomic_uint_least8_t
(C++11)
 std::atomic < std::uint_least8_t >
(typedef)
atomic_int_least16_t
(C++11)
 std::atomic < std::int_least16_t >
(typedef)
atomic_uint_least16_t
(C++11)
 std::atomic < std::uint_least16_t >
(typedef)
atomic_int_least32_t
(C++11)
 std::atomic < std::int_least32_t >
(typedef)
atomic_uint_least32_t
(C++11)
 std::atomic < std::uint_least32_t >
(typedef)
atomic_int_least64_t
(C++11)
 std::atomic < std::int_least64_t >
(typedef)
atomic_uint_least64_t
(C++11)
 std::atomic < std::uint_least64_t >
(typedef)
atomic_int_fast8_t
(C++11)
 std::atomic < std::int_fast8_t >
(typedef)
atomic_uint_fast8_t
(C++11)
 std::atomic < std::uint_fast8_t >
(typedef)
atomic_int_fast16_t
(C++11)
 std::atomic < std::int_fast16_t >
(typedef)
atomic_uint_fast16_t
(C++11)
 std::atomic < std::uint_fast16_t >
(typedef)
atomic_int_fast32_t
(C++11)
 std::atomic < std::int_fast32_t >
(typedef)
atomic_uint_fast32_t
(C++11)
 std::atomic < std::uint_fast32_t >
(typedef)
atomic_int_fast64_t
(C++11)
 std::atomic < std::int_fast64_t >
(typedef)
atomic_uint_fast64_t
(C++11)
 std::atomic < std::uint_fast64_t >
(typedef)
atomic_intptr_t
(C++11)(可选)
 std::atomic < std::intptr_t >
(typedef)
atomic_uintptr_t
(C++11)(可选)
 std::atomic < std::uintptr_t >
(typedef)
atomic_size_t
(C++11)
 std::atomic < std::size_t >
(typedef)
atomic_ptrdiff_t
(C++11)
 std::atomic < std::ptrdiff_t >
(typedef)
atomic_intmax_t
(C++11)
 std::atomic < std::intmax_t >
(typedef)
atomic_uintmax_t
(C++11)
 std::atomic < std::uintmax_t >
(typedef)

函数
atomic_is_lock_free
(C++11)
 检查对该原子类型的操作是否是无锁的
(函数模板)
atomic_storeatomic_store_explicit
(C++11)(C++11)
 原子地以非原子实参替换原子对象的值
(函数模板)
atomic_loadatomic_load_explicit
(C++11)(C++11)
 原子地获得存储于原子对象的值
(函数模板)
atomic_exchangeatomic_exchange_explicit
(C++11)(C++11)
 原子地以非原子实参的值替换原子对象的值，并返回该原子对象的旧值
(函数模板)
atomic_compare_exchange_weakatomic_compare_exchange_weak_explicitatomic_compare_exchange_strongatomic_compare_exchange_strong_explicit
(C++11)(C++11)(C++11)(C++11)
 原子地比较原子对象和非原子实参的值，若相等则进行 atomic_exchange，若不相等则进行 atomic_load
(函数模板)
atomic_fetch_addatomic_fetch_add_explicit
(C++11)(C++11)
 将非原子值加到原子对象，并获得原子对象的先前值
(函数模板)
atomic_fetch_subatomic_fetch_sub_explicit
(C++11)(C++11)
 从原子对象减去非原子值，并获得原子对象的先前值
(函数模板)
atomic_fetch_andatomic_fetch_and_explicit
(C++11)(C++11)
 将原子对象替换为与非原子实参逻辑与的结果，并获得原子对象的先前值
(函数模板)
atomic_fetch_oratomic_fetch_or_explicit
(C++11)(C++11)
 将原子对象替换为与非原子实参逻辑或的结果，并获得原子对象的先前值
(函数模板)
atomic_fetch_xoratomic_fetch_xor_explicit
(C++11)(C++11)
 将原子对象替换为与非原子实参逻辑异或的结果，并获得原子对象的先前值
(函数模板)
atomic_flag_test_and_setatomic_flag_test_and_set_explicit
(C++11)(C++11)
 原子地设置标志为 true 并返回其先前值
(函数)
atomic_flag_clearatomic_flag_clear_explicit
(C++11)(C++11)
 原子地设置标志值为 false
(函数)
atomic_thread_fence
(C++11)
 通用的依赖内存顺序的栅栏同步原语
(函数)
atomic_signal_fence
(C++11)
 线程与执行于同一线程的信号处理函数间的栅栏
(函数)

概要

template<class T>
  using __std_atomic = std::atomic<T>;        // 仅用于阐释

#define _Atomic(T) __std_atomic<T>

#define ATOMIC_BOOL_LOCK_FREE /* 见描述 */
#define ATOMIC_CHAR_LOCK_FREE /* 见描述 */
#define ATOMIC_CHAR16_T_LOCK_FREE /* 见描述 */
#define ATOMIC_CHAR32_T_LOCK_FREE /* 见描述 */
#define ATOMIC_WCHAR_T_LOCK_FREE /* 见描述 */
#define ATOMIC_SHORT_LOCK_FREE /* 见描述 */
#define ATOMIC_INT_LOCK_FREE /* 见描述 */
#define ATOMIC_LONG_LOCK_FREE /* 见描述 */
#define ATOMIC_LLONG_LOCK_FREE /* 见描述 */
#define ATOMIC_POINTER_LOCK_FREE /* 见描述 */

using std::memory_order;                // 见描述
using std::memory_order_relaxed;        // 见描述
using std::memory_order_consume;        // 见描述
using std::memory_order_acquire;        // 见描述
using std::memory_order_release;        // 见描述
using std::memory_order_acq_rel;        // 见描述
using std::memory_order_seq_cst;        // 见描述

using std::atomic_flag;                 // 见描述

using std::atomic_bool;                 // 见描述
using std::atomic_char;                 // 见描述
using std::atomic_schar;                // 见描述
using std::atomic_uchar;                // 见描述
using std::atomic_short;                // 见描述
using std::atomic_ushort;               // 见描述
using std::atomic_int;                  // 见描述
using std::atomic_uint;                 // 见描述
using std::atomic_long;                 // 见描述
using std::atomic_ulong;                // 见描述
using std::atomic_llong;                // 见描述
using std::atomic_ullong;               // 见描述
using std::atomic_char8_t;              // 见描述
using std::atomic_char16_t;             // 见描述
using std::atomic_char32_t;             // 见描述
using std::atomic_wchar_t;              // 见描述
using std::atomic_int8_t;               // 见描述
using std::atomic_uint8_t;              // 见描述
using std::atomic_int16_t;              // 见描述
using std::atomic_uint16_t;             // 见描述
using std::atomic_int32_t;              // 见描述
using std::atomic_uint32_t;             // 见描述
using std::atomic_int64_t;              // 见描述
using std::atomic_uint64_t;             // 见描述
using std::atomic_int_least8_t;         // 见描述
using std::atomic_uint_least8_t;        // 见描述
using std::atomic_int_least16_t;        // 见描述
using std::atomic_uint_least16_t;       // 见描述
using std::atomic_int_least32_t;        // 见描述
using std::atomic_uint_least32_t;       // 见描述
using std::atomic_int_least64_t;        // 见描述
using std::atomic_uint_least64_t;       // 见描述
using std::atomic_int_fast8_t;          // 见描述
using std::atomic_uint_fast8_t;         // 见描述
using std::atomic_int_fast16_t;         // 见描述
using std::atomic_uint_fast16_t;        // 见描述
using std::atomic_int_fast32_t;         // 见描述
using std::atomic_uint_fast32_t;        // 见描述
using std::atomic_int_fast64_t;         // 见描述
using std::atomic_uint_fast64_t;        // 见描述
using std::atomic_intptr_t;             // 见描述
using std::atomic_uintptr_t;            // 见描述
using std::atomic_size_t;               // 见描述
using std::atomic_ptrdiff_t;            // 见描述
using std::atomic_intmax_t;             // 见描述
using std::atomic_uintmax_t;            // 见描述

using std::atomic_is_lock_free;                         // 见描述
using std::atomic_load;                                 // 见描述
using std::atomic_load_explicit;                        // 见描述
using std::atomic_store;                                // 见描述
using std::atomic_store_explicit;                       // 见描述
using std::atomic_exchange;                             // 见描述
using std::atomic_exchange_explicit;                    // 见描述
using std::atomic_compare_exchange_strong;              // 见描述
using std::atomic_compare_exchange_strong_explicit;     // 见描述
using std::atomic_compare_exchange_weak;                // 见描述
using std::atomic_compare_exchange_weak_explicit;       // 见描述
using std::atomic_fetch_add;                            // 见描述
using std::atomic_fetch_add_explicit;                   // 见描述
using std::atomic_fetch_sub;                            // 见描述
using std::atomic_fetch_sub_explicit;                   // 见描述
using std::atomic_fetch_or;                             // 见描述
using std::atomic_fetch_or_explicit;                    // 见描述
using std::atomic_fetch_and;                            // 见描述
using std::atomic_fetch_and_explicit;                   // 见描述
using std::atomic_flag_test_and_set;                    // 见描述
using std::atomic_flag_test_and_set_explicit;           // 见描述
using std::atomic_flag_clear;                           // 见描述
using std::atomic_flag_clear_explicit;                  // 见描述

using std::atomic_thread_fence;                         // 见描述
using std::atomic_signal_fence;                         // 见描述


标准库头文件 <stdexcept>

< cpp‎ | header

此头文件是错误处理库的一部分。

类
logic_error
 指示违背逻辑前提条件或类不变量的异常类
(类)
invalid_argument
 报告非法参数的异常类
(类)
domain_error
 报告定义域错误的异常类
(类)
length_error
 报告试图超出最大允许大小的异常类
(类)
out_of_range
 报告参数落在期待范围外的异常类
(类)
runtime_error
 指示条件只可于运行时检测的异常类
(类)
range_error
 报告内部计算中值域错误的异常类
(类)
overflow_error
 报告算术上溢的异常类
(类)
underflow_error
 报告算术下溢的异常类
(类)

概要

namespace std {
  class logic_error;
    class domain_error;
    class invalid_argument;
    class length_error;
    class out_of_range;
  class runtime_error;
    class range_error;
    class overflow_error;
    class underflow_error;
}

类 std::logic_error

namespace std {
  class logic_error : public exception {
  public:
    explicit logic_error(const string& what_arg);
    explicit logic_error(const char* what_arg);
  };
}

类 std::domain_error

namespace std {
  class domain_error : public logic_error {
  public:
    explicit domain_error(const string& what_arg);
    explicit domain_error(const char* what_arg);
  };
}

类 std::invalid_argument

namespace std {
  class invalid_argument : public logic_error {
  public:
    explicit invalid_argument(const string& what_arg);
    explicit invalid_argument(const char* what_arg);
  };
}

类 std::length_error

namespace std {
  class length_error : public logic_error {
  public:
    explicit length_error(const string& what_arg);
    explicit length_error(const char* what_arg);
  };
}

类 std::out_of_range

namespace std {
  class out_of_range : public logic_error {
  public:
    explicit out_of_range(const string& what_arg);
    explicit out_of_range(const char* what_arg);
  };
}

类 std::runtime_error

namespace std {
  class runtime_error : public exception {
  public:
    explicit runtime_error(const string& what_arg);
    explicit runtime_error(const char* what_arg);
  };
}

类 std::range_error

namespace std {
  class range_error : public runtime_error {
  public:
    explicit range_error(const string& what_arg);
    explicit range_error(const char* what_arg);
  };
}

类 std::overflow_error

namespace std {
  class overflow_error : public runtime_error {
  public:
    explicit overflow_error(const string& what_arg);
    explicit overflow_error(const char* what_arg);
  };
}

类 std::underflow_error

namespace std {
  class underflow_error : public runtime_error {
  public:
    explicit underflow_error(const string& what_arg);
    explicit underflow_error(const char* what_arg);
  };
}

参阅

exception
 标准库组件抛出的各种异常的基类
(类)


标准库头文件 <stop_token>

< cpp‎ | header

此头文件是线程支持库的一部分。

类
stop_token
(C++20)
 查询是否已经做出 std::jthread 取消请求的接口
(类)
stop_source
(C++20)
 表示请求停止一个或多个 std::jthread 的类
(类)
stop_callback
(C++20)
 在 std::jthread 取消上注册回调的接口
(类模板)
nostopstate_t
(C++20)
 用于 stop_source 构造函数的占位符类型
(类)

常量
nostopstate
(C++20)
 用于 stop_source 构造函数的 std::nostopstate_t 实例
(常量)

概要

namespace std {
  // 类 stop_token
  class stop_token;

  // 类 stop_source
  class stop_source;

  // 无共享停止状态指示器
  struct nostopstate_t {
    explicit nostopstate_t() = default;
  };
  inline constexpr nostopstate_t nostopstate{};

  // 类 stop_callback
  template<class Callback>
  class stop_callback;
}

类 std::stop_token

namespace std {
  class stop_token {
  public:
    // 构造函数、复制与赋值
    stop_token() noexcept;

    stop_token(const stop_token&) noexcept;
    stop_token(stop_token&&) noexcept;
    stop_token& operator=(const stop_token&) noexcept;
    stop_token& operator=(stop_token&&) noexcept;
    ~stop_token();
    void swap(stop_token&) noexcept;

    // 停止处理
    [[nodiscard]] bool stop_requested() const noexcept;
    [[nodiscard]] bool stop_possible() const noexcept;

    [[nodiscard]]
    friend bool operator==(const stop_token& lhs, const stop_token& rhs) noexcept;
    friend void swap(stop_token& lhs, stop_token& rhs) noexcept;
  };
}

类 std::stop_source

namespace std {
  // 无共享停止状态指示器
  struct nostopstate_t {
    explicit nostopstate_t() = default;
  };
  inline constexpr nostopstate_t nostopstate{};

  class stop_source {
  public:
    // 构造函数、复制与赋值
    stop_source();
    explicit stop_source(nostopstate_t) noexcept;

    stop_source(const stop_source&) noexcept;
    stop_source(stop_source&&) noexcept;
    stop_source& operator=(const stop_source&) noexcept;
    stop_source& operator=(stop_source&&) noexcept;
    ~stop_source();
    void swap(stop_source&) noexcept;

    // 停止处理
    [[nodiscard]] stop_token get_token() const noexcept;
    [[nodiscard]] bool stop_possible() const noexcept;
    [[nodiscard]] bool stop_requested() const noexcept;
    bool request_stop() noexcept;

    [[nodiscard]] friend bool
    operator==(const stop_source& lhs, const stop_source& rhs) noexcept;
    friend void swap(stop_source& lhs, stop_source& rhs) noexcept;
  };
}

类模板 std::stop_callback

namespace std {
  template<class Callback>
  class stop_callback {
  public:
    using callback_type = Callback;

    // 构造函数与析构函数
    template<class C>
    explicit stop_callback(const stop_token& st, C&& cb)
        noexcept(is_nothrow_constructible_v<Callback, C>);
    template<class C>
    explicit stop_callback(stop_token&& st, C&& cb)
        noexcept(is_nothrow_constructible_v<Callback, C>);
    ~stop_callback();

    stop_callback(const stop_callback&) = delete;
    stop_callback(stop_callback&&) = delete;
    stop_callback& operator=(const stop_callback&) = delete;
    stop_callback& operator=(stop_callback&&) = delete;

  private:
    Callback callback;      // 仅用于阐释
  };

  template<class Callback>
  stop_callback(stop_token, Callback) -> stop_callback<Callback>;
}


标准库头文件 <streambuf>

< cpp‎ | header

此头文件是输入/输出库的一部分。

类
basic_streambuf
 抽象原生设备
(类模板)
streambuf std::basic_streambuf <char>
(typedef)
wstreambuf std::basic_streambuf <wchar_t>
(typedef)

概要

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
    class basic_streambuf;
  using streambuf  = basic_streambuf<char>;
  using wstreambuf = basic_streambuf<wchar_t>;
}

类模板 std::basic_streambuf

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_streambuf {
  public:
    using char_type   = CharT;
    using int_type    = typename Traits::int_type;
    using pos_type    = typename Traits::pos_type;
    using off_type    = typename Traits::off_type;
    using traits_type = Traits;

    virtual ~basic_streambuf();

    // 本地环境
    locale   pubimbue(const locale& loc);
    locale   getloc() const;

    // buffer and positioning
    basic_streambuf* pubsetbuf(char_type* s, streamsize n);
    pos_type pubseekoff(off_type off, ios_base::seekdir way,
                        ios_base::openmode which
                          = ios_base::in | ios_base::out);
    pos_type pubseekpos(pos_type sp,
                        ios_base::openmode which
                          = ios_base::in | ios_base::out);
    int      pubsync();

    // 获取与放置区
    // 获取区
    streamsize in_avail();
    int_type snextc();
    int_type sbumpc();
    int_type sgetc();
    streamsize sgetn(char_type* s, streamsize n);

    // 回放
    int_type sputbackc(char_type c);
    int_type sungetc();

    // 放置区
    int_type   sputc(char_type c);
    streamsize sputn(const char_type* s, streamsize n);

  protected:
    basic_streambuf();
    basic_streambuf(const basic_streambuf& rhs);
    basic_streambuf& operator=(const basic_streambuf& rhs);

    void swap(basic_streambuf& rhs);

    // 获取区访问
    char_type* eback() const;
    char_type* gptr()  const;
    char_type* egptr() const;
    void       gbump(int n);
    void       setg(char_type* gbeg, char_type* gnext, char_type* gend);

    // 放置区访问
    char_type* pbase() const;
    char_type* pptr() const;
    char_type* epptr() const;
    void       pbump(int n);
    void       setp(char_type* pbeg, char_type* pend);

    // 虚函数
    // 本地环境
    virtual void imbue(const locale& loc);

    // buffer management and positioning
    virtual basic_streambuf* setbuf(char_type* s, streamsize n);
    virtual pos_type seekoff(off_type off, ios_base::seekdir way,
                             ios_base::openmode which
                               = ios_base::in | ios_base::out);
    virtual pos_type seekpos(pos_type sp,
                             ios_base::openmode which
                               = ios_base::in | ios_base::out);
    virtual int      sync();

    // 获取区
    virtual streamsize showmanyc();
    virtual streamsize xsgetn(char_type* s, streamsize n);
    virtual int_type   underflow();
    virtual int_type   uflow();

    // 回放
    virtual int_type   pbackfail(int_type c = Traits::eof());

    // 放置区
    virtual streamsize xsputn(const char_type* s, streamsize n);
    virtual int_type   overflow(int_type c = Traits::eof());
  };
}


标准库头文件 <string>

< cpp‎ | header

此头文件是字符串库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
<initializer_list>
(C++11)
 std::initializer_list 类模板

类
char_traits
 描述字符类型的性质的类模板
(类模板)
std::char_traits <char> | (类模板特化)
std::char_traits <wchar_t> | (类模板特化)
std::char_traits <char8_t> (C++20) | (类模板特化)
std::char_traits <char16_t> (C++11) | (类模板特化)
std::char_traits <char32_t> (C++11) | (类模板特化)
basic_string
 存储并操作字符序列
(类模板)
std::string | std::basic_string <char> (typedef)
std::u8string (C++20) | std::basic_string <char8_t> (typedef)
std::u16string (C++11) | std::basic_string <char16_t> (typedef)
std::u32string (C++11) | std::basic_string <char32_t> (typedef)
std::wstring | std::basic_string <wchar_t> (typedef)
std::pmr::basic_string (C++17) | (别名模板)
std::pmr::string (C++17) | std::pmr::basic_string<char> (typedef)
std::pmr::u8string (C++20) | std::pmr::basic_string<char8_t> (typedef)
std::pmr::u16string (C++17) | std::pmr::basic_string<char16_t> (typedef)
std::pmr::u32string (C++17) | std::pmr::basic_string<char32_t> (typedef)
std::pmr::wstring (C++17) | std::pmr::basic_string<wchar_t> (typedef)
std::hash < std::string > (C++11) | (类模板特化)
std::hash <std::u8string> (C++20) | (类模板特化)
std::hash < std::u16string > (C++11) | (类模板特化)
std::hash < std::u32string > (C++11) | (类模板特化)
std::hash < std::wstring > (C++11) | (类模板特化)
std::hash < std::pmr::string > (C++20) | (类模板特化)
std::hash <std::pmr::u8string> (C++20) | (类模板特化)
std::hash < std::pmr::u16string > (C++20) | (类模板特化)
std::hash < std::pmr::u32string > (C++20) | (类模板特化)
std::hash < std::pmr::wstring > (C++20) | (类模板特化)

函数
operator+
 连接两个字符串或者一个字符串和一个字符
(函数模板)
operator==operator!=operator<operator>operator<=operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 以字典序比较两个字符串
(函数模板)
std::swap(std::basic_string)
 特化 std::swap 算法
(函数模板)
输入/输出
operator<<operator>>
 执行字符串的流输入与输出
(函数模板)
getline
 从 I/O 流读取数据到字符串
(函数模板)
数值转换
stoistolstoll
(C++11)(C++11)(C++11)
 转换字符串为有符号整数
(函数)
stoulstoull
(C++11)(C++11)
 转换字符串为无符号整数
(函数)
stofstodstold
(C++11)(C++11)(C++11)
 转换字符串为浮点值
(函数)
to_string
(C++11)
 转换整数或浮点值为 string
(函数)
to_wstring
(C++11)
 转换整数或浮点值为 wstring
(函数)
范围访问
begincbegin
(C++11)(C++14)
 返回指向容器或数组起始的迭代器
(函数模板)
endcend
(C++11)(C++14)
 返回指向容器或数组结尾的迭代器
(函数模板)
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
sizessize
(C++17)(C++20)
 返回容器或数组的大小
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)
字面量
定义于内联命名空间 std::literals::string_literals
operator""s
(C++14)
 转换字符数组字面量为 basic_string
(函数)

概要

#include <compare>
#include <initializer_list>

namespace std {
  // 字符特征
  template<class charT> struct char_traits;
  template<> struct char_traits<char>;
  template<> struct char_traits<char8_t>;
  template<> struct char_traits<char16_t>;
  template<> struct char_traits<char32_t>;
  template<> struct char_traits<wchar_t>;

  // basic_string
  template<class CharT, class Traits = char_traits<CharT>,
           class Allocator = allocator<CharT>>
    class basic_string;

  template<class CharT, class Traits, class Allocator>
    constexpr basic_string<CharT, Traits, Allocator>
      operator+(const basic_string<CharT, Traits, Allocator>& lhs,
                const basic_string<CharT, Traits, Allocator>& rhs);
  template<class CharT, class Traits, class Allocator>
    constexpr basic_string<CharT, Traits, Allocator>
      operator+(basic_string<CharT, Traits, Allocator>&& lhs,
                const basic_string<CharT, Traits, Allocator>& rhs);
  template<class CharT, class Traits, class Allocator>
    constexpr basic_string<CharT, Traits, Allocator>
      operator+(const basic_string<CharT, Traits, Allocator>& lhs,
                basic_string<CharT, Traits, Allocator>&& rhs);
  template<class CharT, class Traits, class Allocator>
    constexpr basic_string<CharT, Traits, Allocator>
      operator+(basic_string<CharT, Traits, Allocator>&& lhs,
                basic_string<CharT, Traits, Allocator>&& rhs);
  template<class CharT, class Traits, class Allocator>
    constexpr basic_string<CharT, Traits, Allocator>
      operator+(const CharT* lhs,
                const basic_string<CharT, Traits, Allocator>& rhs);
  template<class CharT, class Traits, class Allocator>
    constexpr basic_string<CharT, Traits, Allocator>
      operator+(const CharT* lhs,
                basic_string<CharT, Traits, Allocator>&& rhs);
  template<class CharT, class Traits, class Allocator>
    constexpr basic_string<CharT, Traits, Allocator>
      operator+(CharT lhs,
                const basic_string<CharT, Traits, Allocator>& rhs);
  template<class CharT, class Traits, class Allocator>
    constexpr basic_string<CharT, Traits, Allocator>
      operator+(CharT lhs,
                basic_string<CharT, Traits, Allocator>&& rhs);
  template<class CharT, class Traits, class Allocator>
    constexpr basic_string<CharT, Traits, Allocator>
      operator+(const basic_string<CharT, Traits, Allocator>& lhs,
                const CharT* rhs);
  template<class CharT, class Traits, class Allocator>
    constexpr basic_string<CharT, Traits, Allocator>
      operator+(basic_string<CharT, Traits, Allocator>&& lhs,
                const CharT* rhs);
  template<class CharT, class Traits, class Allocator>
    constexpr basic_string<CharT, Traits, Allocator>
      operator+(const basic_string<CharT, Traits, Allocator>& lhs,
                CharT rhs);
  template<class CharT, class Traits, class Allocator>
    constexpr basic_string<CharT, Traits, Allocator>
      operator+(basic_string<CharT, Traits, Allocator>&& lhs,
                CharT rhs);

  template<class CharT, class Traits, class Allocator>
    constexpr bool
      operator==(const basic_string<CharT, Traits, Allocator>& lhs,
                 const basic_string<CharT, Traits, Allocator>& rhs) noexcept;
  template<class CharT, class Traits, class Allocator>
    constexpr bool operator==(const basic_string<CharT, Traits, Allocator>& lhs,
                              const CharT* rhs);

  template<class CharT, class Traits, class Allocator>
    constexpr /* 见描述 */
      operator<=>(const basic_string<CharT, Traits, Allocator>& lhs,
                  const basic_string<CharT, Traits, Allocator>& rhs) noexcept;
  template<class CharT, class Traits, class Allocator>
    constexpr /* 见描述 */
      operator<=>(const basic_string<CharT, Traits, Allocator>& lhs,
                  const CharT* rhs);

  // 交换
  template<class CharT, class Traits, class Allocator>
    constexpr void
      swap(basic_string<CharT, Traits, Allocator>& lhs,
           basic_string<CharT, Traits, Allocator>& rhs)
        noexcept(noexcept(lhs.swap(rhs)));

  // 插入器与提取器
  template<class CharT, class Traits, class Allocator>
    basic_istream<CharT, Traits>&
      operator>>(basic_istream<CharT, Traits>& is,
                 basic_string<CharT, Traits, Allocator>& str);
  template<class CharT, class Traits, class Allocator>
    basic_ostream<CharT, Traits>&
      operator<<(basic_ostream<CharT, Traits>& os,
                 const basic_string<CharT, Traits, Allocator>& str);
  template<class CharT, class Traits, class Allocator>
    basic_istream<CharT, Traits>&
      getline(basic_istream<CharT, Traits>& is,
              basic_string<CharT, Traits, Allocator>& str,
              CharT delim);
  template<class CharT, class Traits, class Allocator>
    basic_istream<CharT, Traits>&
      getline(basic_istream<CharT, Traits>&& is,
              basic_string<CharT, Traits, Allocator>& str,
              CharT delim);
  template<class CharT, class Traits, class Allocator>
    basic_istream<CharT, Traits>&
      getline(basic_istream<CharT, Traits>& is,
              basic_string<CharT, Traits, Allocator>& str);
  template<class CharT, class Traits, class Allocator>
    basic_istream<CharT, Traits>&
      getline(basic_istream<CharT, Traits>&& is,
              basic_string<CharT, Traits, Allocator>& str);

  // 擦除
  template<class CharT, class Traits, class Allocator, class U>
    constexpr typename basic_string<CharT, Traits, Allocator>::size_type
      erase(basic_string<CharT, Traits, Allocator>& c, const U& value);
  template<class CharT, class Traits, class Allocator, class Pred>
    constexpr typename basic_string<CharT, Traits, Allocator>::size_type
      erase_if(basic_string<CharT, Traits, Allocator>& c, Pred pred);

  // basic_string typedef 名
  using string    = basic_string<char>;
  using u8string  = basic_string<char8_t>;
  using u16string = basic_string<char16_t>;
  using u32string = basic_string<char32_t>;
  using wstring   = basic_string<wchar_t>;

  // 数值转换
  int stoi(const string& str, size_t* idx = nullptr, int base = 10);
  long stol(const string& str, size_t* idx = nullptr, int base = 10);
  unsigned long stoul(const string& str, size_t* idx = nullptr, int base = 10);
  long long stoll(const string& str, size_t* idx = nullptr, int base = 10);
  unsigned long long stoull(const string& str, size_t* idx = nullptr, int base = 10);
  float stof(const string& str, size_t* idx = nullptr);
  double stod(const string& str, size_t* idx = nullptr);
  long double stold(const string& str, size_t* idx = nullptr);
  string to_string(int val);
  string to_string(unsigned val);
  string to_string(long val);
  string to_string(unsigned long val);
  string to_string(long long val);
  string to_string(unsigned long long val);
  string to_string(float val);
  string to_string(double val);
  string to_string(long double val);

  int stoi(const wstring& str, size_t* idx = nullptr, int base = 10);
  long stol(const wstring& str, size_t* idx = nullptr, int base = 10);
  unsigned long stoul(const wstring& str, size_t* idx = nullptr, int base = 10);
  long long stoll(const wstring& str, size_t* idx = nullptr, int base = 10);
  unsigned long long stoull(const wstring& str, size_t* idx = nullptr, int base = 10);
  float stof(const wstring& str, size_t* idx = nullptr);
  double stod(const wstring& str, size_t* idx = nullptr);
  long double stold(const wstring& str, size_t* idx = nullptr);
  wstring to_wstring(int val);
  wstring to_wstring(unsigned val);
  wstring to_wstring(long val);
  wstring to_wstring(unsigned long val);
  wstring to_wstring(long long val);
  wstring to_wstring(unsigned long long val);
  wstring to_wstring(float val);
  wstring to_wstring(double val);
  wstring to_wstring(long double val);

  namespace pmr {
    template<class CharT, class Traits = char_traits<CharT>>
      using basic_string = std::basic_string<CharT, Traits, polymorphic_allocator<CharT>>;

    using string    = basic_string<char>;
    using u8string  = basic_string<char8_t>;
    using u16string = basic_string<char16_t>;
    using u32string = basic_string<char32_t>;
    using wstring   = basic_string<wchar_t>;
  }

  // 散列支持
  template<class T> struct hash;
  template<> struct hash<string>;
  template<> struct hash<u8string>;
  template<> struct hash<u16string>;
  template<> struct hash<u32string>;
  template<> struct hash<wstring>;
  template<> struct hash<pmr::string>;
  template<> struct hash<pmr::u8string>;
  template<> struct hash<pmr::u16string>;
  template<> struct hash<pmr::u32string>;
  template<> struct hash<pmr::wstring>;

  inline namespace literals {
  inline namespace string_literals {
    // basic_string 字面量后缀
    constexpr string    operator""s(const char* str, size_t len);
    constexpr u8string  operator""s(const char8_t* str, size_t len);
    constexpr u16string operator""s(const char16_t* str, size_t len);
    constexpr u32string operator""s(const char32_t* str, size_t len);
    constexpr wstring   operator""s(const wchar_t* str, size_t len);
  }
  }
}

类模板 std::char_traits

namespace std {
  template<> struct char_traits<char> {
    using char_type  = char;
    using int_type   = int;
    using off_type   = streamoff;
    using pos_type   = streampos;
    using state_type = mbstate_t;
    using comparison_category = strong_ordering;

    static constexpr void assign(char_type& c1, const char_type& c2) noexcept;
    static constexpr bool eq(char_type c1, char_type c2) noexcept;
    static constexpr bool lt(char_type c1, char_type c2) noexcept;

    static constexpr int compare(const char_type* s1, const char_type* s2, size_t n);
    static constexpr size_t length(const char_type* s);
    static constexpr const char_type* find(const char_type* s, size_t n,
                                           const char_type& a);
    static constexpr char_type* move(char_type* s1, const char_type* s2, size_t n);
    static constexpr char_type* copy(char_type* s1, const char_type* s2, size_t n);
    static constexpr char_type* assign(char_type* s, size_t n, char_type a);

    static constexpr int_type not_eof(int_type c) noexcept;
    static constexpr char_type to_char_type(int_type c) noexcept;
    static constexpr int_type to_int_type(char_type c) noexcept;
    static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept;
    static constexpr int_type eof() noexcept;
  };

  template<> struct char_traits<char8_t> {
    using char_type  = char8_t;
    using int_type   = unsigned int;
    using off_type   = streamoff;
    using pos_type   = u8streampos;
    using state_type = mbstate_t;
    using comparison_category = strong_ordering;

    static constexpr void assign(char_type& c1, const char_type& c2) noexcept;
    static constexpr bool eq(char_type c1, char_type c2) noexcept;
    static constexpr bool lt(char_type c1, char_type c2) noexcept;

    static constexpr int compare(const char_type* s1, const char_type* s2, size_t n);
    static constexpr size_t length(const char_type* s);
    static constexpr const char_type* find(const char_type* s, size_t n,
                                           const char_type& a);
    static constexpr char_type* move(char_type* s1, const char_type* s2, size_t n);
    static constexpr char_type* copy(char_type* s1, const char_type* s2, size_t n);
    static constexpr char_type* assign(char_type* s, size_t n, char_type a);
    static constexpr int_type not_eof(int_type c) noexcept;
    static constexpr char_type to_char_type(int_type c) noexcept;
    static constexpr int_type to_int_type(char_type c) noexcept;
    static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept;
    static constexpr int_type eof() noexcept;
  };

  template<> struct char_traits<char16_t> {
    using char_type  = char16_t;
    using int_type   = uint_least16_t;
    using off_type   = streamoff;
    using pos_type   = u16streampos;
    using state_type = mbstate_t;
    using comparison_category = strong_ordering;

    static constexpr void assign(char_type& c1, const char_type& c2) noexcept;
    static constexpr bool eq(char_type c1, char_type c2) noexcept;
    static constexpr bool lt(char_type c1, char_type c2) noexcept;

    static constexpr int compare(const char_type* s1, const char_type* s2, size_t n);
    static constexpr size_t length(const char_type* s);
    static constexpr const char_type* find(const char_type* s, size_t n,
                                           const char_type& a);
    static constexpr char_type* move(char_type* s1, const char_type* s2, size_t n);
    static constexpr char_type* copy(char_type* s1, const char_type* s2, size_t n);
    static constexpr char_type* assign(char_type* s, size_t n, char_type a);

    static constexpr int_type not_eof(int_type c) noexcept;
    static constexpr char_type to_char_type(int_type c) noexcept;
    static constexpr int_type to_int_type(char_type c) noexcept;
    static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept;
    static constexpr int_type eof() noexcept;
  };

  template<> struct char_traits<char32_t> {
    using char_type  = char32_t;
    using int_type   = uint_least32_t;
    using off_type   = streamoff;
    using pos_type   = u32streampos;
    using state_type = mbstate_t;
    using comparison_category = strong_ordering;

    static constexpr void assign(char_type& c1, const char_type& c2) noexcept;
    static constexpr bool eq(char_type c1, char_type c2) noexcept;
    static constexpr bool lt(char_type c1, char_type c2) noexcept;

    static constexpr int compare(const char_type* s1, const char_type* s2, size_t n);
    static constexpr size_t length(const char_type* s);
    static constexpr const char_type* find(const char_type* s, size_t n,
                                           const char_type& a);
    static constexpr char_type* move(char_type* s1, const char_type* s2, size_t n);
    static constexpr char_type* copy(char_type* s1, const char_type* s2, size_t n);
    static constexpr char_type* assign(char_type* s, size_t n, char_type a);

    static constexpr int_type not_eof(int_type c) noexcept;
    static constexpr char_type to_char_type(int_type c) noexcept;
    static constexpr int_type to_int_type(char_type c) noexcept;
    static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept;
    static constexpr int_type eof() noexcept;
  };

  template<> struct char_traits<wchar_t> {
    using char_type  = wchar_t;
    using int_type   = wint_t;
    using off_type   = streamoff;
    using pos_type   = wstreampos;
    using state_type = mbstate_t;
    using comparison_category = strong_ordering;

    static constexpr void assign(char_type& c1, const char_type& c2) noexcept;
    static constexpr bool eq(char_type c1, char_type c2) noexcept;
    static constexpr bool lt(char_type c1, char_type c2) noexcept;

    static constexpr int compare(const char_type* s1, const char_type* s2, size_t n);
    static constexpr size_t length(const char_type* s);
    static constexpr const char_type* find(const char_type* s, size_t n,
                                           const char_type& a);
    static constexpr char_type* move(char_type* s1, const char_type* s2, size_t n);
    static constexpr char_type* copy(char_type* s1, const char_type* s2, size_t n);
    static constexpr char_type* assign(char_type* s, size_t n, char_type a);

    static constexpr int_type not_eof(int_type c) noexcept;
    static constexpr char_type to_char_type(int_type c) noexcept;
    static constexpr int_type to_int_type(char_type c) noexcept;
    static constexpr bool eq_int_type(int_type c1, int_type c2) noexcept;
    static constexpr int_type eof() noexcept;
  };
}

类模板 std::basic_string

namespace std {
  template<class CharT, class Traits = char_traits<CharT>,
           class Allocator = allocator<CharT>>
  class basic_string {
  public:
    // 类型
    using Traits_type            = Traits;
    using value_type             = CharT;
    using allocator_type         = Allocator;
    using size_type              = typename allocator_traits<Allocator>::size_type;
    using difference_type        = typename allocator_traits<Allocator>::difference_type;
    using pointer                = typename allocator_traits<Allocator>::pointer;
    using const_pointer          = typename allocator_traits<Allocator>::const_pointer;
    using reference              = value_type&;
    using const_reference        = const value_type&;

    using iterator               = /* 由实现定义 */;
    using const_iterator         = /* 由实现定义 */;
    using reverse_iterator       = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
    static const size_type npos  = -1;

    // 构造/复制/销毁
    constexpr basic_string() noexcept(noexcept(Allocator()))
      : basic_string(Allocator()) { }
    constexpr explicit basic_string(const Allocator& a) noexcept;
    constexpr basic_string(const basic_string& str);
    constexpr basic_string(basic_string&& str) noexcept;
    constexpr basic_string(const basic_string& str, size_type pos,
                           const Allocator& a = Allocator());
    constexpr basic_string(const basic_string& str, size_type pos, size_type n,
                           const Allocator& a = Allocator());
    template<class T>
      constexpr basic_string(const T& t, size_type pos, size_type n,
                             const Allocator& a = Allocator());
    template<class T>
      constexpr explicit basic_string(const T& t, const Allocator& a = Allocator());
    constexpr basic_string(const CharT* s, size_type n, const Allocator& a = Allocator());
    constexpr basic_string(const CharT* s, const Allocator& a = Allocator());
    constexpr basic_string(nullptr_t) = delete;
    constexpr basic_string(size_type n, CharT c, const Allocator& a = Allocator());
    template<class InputIt>
      constexpr basic_string(InputIt begin, InputIt end,
                             const Allocator& a = Allocator());
    constexpr basic_string(initializer_list<CharT>, const Allocator& = Allocator());
    constexpr basic_string(const basic_string&, const Allocator&);
    constexpr basic_string(basic_string&&, const Allocator&);
    constexpr ~basic_string();

    constexpr basic_string& operator=(const basic_string& str);
    constexpr basic_string& operator=(basic_string&& str)
      noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
               allocator_traits<Allocator>::is_always_equal::value);
    template<class T>
      constexpr basic_string& operator=(const T& t);
    constexpr basic_string& operator=(const CharT* s);
    constexpr basic_string& operator=(nullptr_t) = delete;
    constexpr basic_string& operator=(CharT c);
    constexpr basic_string& operator=(initializer_list<CharT>);

    // 迭代器
    constexpr iterator       begin() noexcept;
    constexpr const_iterator begin() const noexcept;
    constexpr iterator       end() noexcept;
    constexpr const_iterator end() const noexcept;

    constexpr reverse_iterator       rbegin() noexcept;
    constexpr const_reverse_iterator rbegin() const noexcept;
    constexpr reverse_iterator       rend() noexcept;
    constexpr const_reverse_iterator rend() const noexcept;

    constexpr const_iterator         cbegin() const noexcept;
    constexpr const_iterator         cend() const noexcept;
    constexpr const_reverse_iterator crbegin() const noexcept;
    constexpr const_reverse_iterator crend() const noexcept;

    // 容量
    constexpr size_type size() const noexcept;
    constexpr size_type length() const noexcept;
    constexpr size_type max_size() const noexcept;
    constexpr void resize(size_type n, CharT c);
    constexpr void resize(size_type n);
    constexpr size_type capacity() const noexcept;
    constexpr void reserve(size_type res_arg);
    void reserve(); // 弃用
    constexpr void shrink_to_fit();
    constexpr void clear() noexcept;
    [[nodiscard]] constexpr bool empty() const noexcept;

    // 元素访问
    constexpr const_reference operator[](size_type pos) const;
    constexpr reference       operator[](size_type pos);
    constexpr const_reference at(size_type n) const;
    constexpr reference       at(size_type n);

    constexpr const CharT& front() const;
    constexpr CharT&       front();
    constexpr const CharT& back() const;
    constexpr CharT&       back();

    // 修改器
    constexpr basic_string& operator+=(const basic_string& str);
    template<class T>
      constexpr basic_string& operator+=(const T& t);
    constexpr basic_string& operator+=(const CharT* s);
    constexpr basic_string& operator+=(CharT c);
    constexpr basic_string& operator+=(initializer_list<CharT>);
    constexpr basic_string& append(const basic_string& str);
    constexpr basic_string& append(const basic_string& str,
                                   size_type pos, size_type n = npos);
    template<class T>
      constexpr basic_string& append(const T& t);
    template<class T>
      constexpr basic_string& append(const T& t, size_type pos, size_type n = npos);
    constexpr basic_string& append(const CharT* s, size_type n);
    constexpr basic_string& append(const CharT* s);
    constexpr basic_string& append(size_type n, CharT c);
    template<class InputIt>
      constexpr basic_string& append(InputIt first, InputIt last);
    constexpr basic_string& append(initializer_list<CharT>);

    constexpr void push_back(CharT c);

    constexpr basic_string& assign(const basic_string& str);
    constexpr basic_string& assign(basic_string&& str)
      noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
               allocator_traits<Allocator>::is_always_equal::value);
    constexpr basic_string& assign(const basic_string& str,
                                   size_type pos, size_type n = npos);
    template<class T>
      constexpr basic_string& assign(const T& t);
    template<class T>
      constexpr basic_string& assign(const T& t, size_type pos, size_type n = npos);
    constexpr basic_string& assign(const CharT* s, size_type n);
    constexpr basic_string& assign(const CharT* s);
    constexpr basic_string& assign(size_type n, CharT c);
    template<class InputIt>
      constexpr basic_string& assign(InputIt first, InputIt last);
    constexpr basic_string& assign(initializer_list<CharT>);

    constexpr basic_string& insert(size_type pos, const basic_string& str);
    constexpr basic_string& insert(size_type pos1, const basic_string& str,
                                   size_type pos2, size_type n = npos);
    template<class T>
      constexpr basic_string& insert(size_type pos, const T& t);
    template<class T>
      constexpr basic_string& insert(size_type pos1, const T& t,
                                     size_type pos2, size_type n = npos);
    constexpr basic_string& insert(size_type pos, const CharT* s, size_type n);
    constexpr basic_string& insert(size_type pos, const CharT* s);
    constexpr basic_string& insert(size_type pos, size_type n, CharT c);
    constexpr iterator insert(const_iterator p, CharT c);
    constexpr iterator insert(const_iterator p, size_type n, CharT c);
    template<class InputIt>
      constexpr iterator insert(const_iterator p,
                                InputIt first, InputIt last);
    constexpr iterator insert(const_iterator p, initializer_list<CharT>);

    constexpr basic_string& erase(size_type pos = 0, size_type n = npos);
    constexpr iterator erase(const_iterator p);
    constexpr iterator erase(const_iterator first, const_iterator last);

    constexpr void pop_back();

    constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str);
    constexpr basic_string& replace(size_type pos1, size_type n1, const basic_string& str,
                                    size_type pos2, size_type n2 = npos);
    template<class T>
      constexpr basic_string& replace(size_type pos1, size_type n1, const T& t);
    template<class T>
      constexpr basic_string& replace(size_type pos1, size_type n1, const T& t,
                                      size_type pos2, size_type n2 = npos);
    constexpr basic_string& replace(size_type pos, size_type n1,
                                    const CharT* s, size_type n2);
    constexpr basic_string& replace(size_type pos, size_type n1, const CharT* s);
    constexpr basic_string& replace(size_type pos, size_type n1, size_type n2, CharT c);
    constexpr basic_string& replace(const_iterator i1, const_iterator i2,
                                    const basic_string& str);
    template<class T>
      constexpr basic_string& replace(const_iterator i1, const_iterator i2, const T& t);
    constexpr basic_string& replace(const_iterator i1, const_iterator i2, const CharT* s,
                                    size_type n);
    constexpr basic_string& replace(const_iterator i1, const_iterator i2, const CharT* s);
    constexpr basic_string& replace(const_iterator i1, const_iterator i2,
                                    size_type n, CharT c);
    template<class InputIt>
      constexpr basic_string& replace(const_iterator i1, const_iterator i2,
                                      InputIt j1, InputIt j2);
    constexpr basic_string& replace(const_iterator, const_iterator,
                                    initializer_list<CharT>);

    constexpr size_type copy(CharT* s, size_type n, size_type pos = 0) const;

    constexpr void swap(basic_string& str)
      noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value ||
               allocator_traits<Allocator>::is_always_equal::value);

    // 字符串操作
    constexpr const CharT* c_str() const noexcept;
    constexpr const CharT* data() const noexcept;
    constexpr CharT* data() noexcept;
    constexpr operator basic_string_view<CharT, Traits>() const noexcept;
    constexpr allocator_type get_allocator() const noexcept;

    template<class T>
      constexpr size_type find(const T& t, size_type pos = 0) const
        noexcept(/* 见描述 */);
    constexpr size_type find(const basic_string& str, size_type pos = 0) const noexcept;
    constexpr size_type find(const CharT* s, size_type pos, size_type n) const;
    constexpr size_type find(const CharT* s, size_type pos = 0) const;
    constexpr size_type find(CharT c, size_type pos = 0) const noexcept;
    template<class T>
      constexpr size_type rfind(const T& t, size_type pos = npos) const
        noexcept(/* 见描述 */);
    constexpr size_type rfind(const basic_string& str,
                              size_type pos = npos) const noexcept;
    constexpr size_type rfind(const CharT* s, size_type pos, size_type n) const;
    constexpr size_type rfind(const CharT* s, size_type pos = npos) const;
    constexpr size_type rfind(CharT c, size_type pos = npos) const noexcept;

    template<class T>
      constexpr size_type find_first_of(const T& t, size_type pos = 0) const
        noexcept(/* 见描述 */);
    constexpr size_type find_first_of(const basic_string& str,
                                      size_type pos = 0) const noexcept;
    constexpr size_type find_first_of(const CharT* s, size_type pos, size_type n) const;
    constexpr size_type find_first_of(const CharT* s, size_type pos = 0) const;
    constexpr size_type find_first_of(CharT c, size_type pos = 0) const noexcept;
    template<class T>
      constexpr size_type find_last_of(const T& t, size_type pos = npos) const
        noexcept(/* 见描述 */);
    constexpr size_type find_last_of(const basic_string& str,
                                     size_type pos = npos) const noexcept;
    constexpr size_type find_last_of(const CharT* s, size_type pos, size_type n) const;
    constexpr size_type find_last_of(const CharT* s, size_type pos = npos) const;
    constexpr size_type find_last_of(CharT c, size_type pos = npos) const noexcept;

    template<class T>
      constexpr size_type find_first_not_of(const T& t, size_type pos = 0) const
        noexcept(/* 见描述 */);
    constexpr size_type find_first_not_of(const basic_string& str,
                                          size_type pos = 0) const noexcept;
    constexpr size_type find_first_not_of(const CharT* s,
                                          size_type pos, size_type n) const;
    constexpr size_type find_first_not_of(const CharT* s, size_type pos = 0) const;
    constexpr size_type find_first_not_of(CharT c, size_type pos = 0) const noexcept;
    template<class T>
      constexpr size_type find_last_not_of(const T& t, size_type pos = npos) const
        noexcept(/* 见描述 */);
    constexpr size_type find_last_not_of(const basic_string& str,
                                         size_type pos = npos) const noexcept;
    constexpr size_type find_last_not_of(const CharT* s, size_type pos, size_type n) const;
    constexpr size_type find_last_not_of(const CharT* s, size_type pos = npos) const;
    constexpr size_type find_last_not_of(CharT c, size_type pos = npos) const noexcept;

    constexpr basic_string substr(size_type pos = 0, size_type n = npos) const;

    template<class T>
      constexpr int compare(const T& t) const noexcept(/* 见描述 */);
    template<class T>
      constexpr int compare(size_type pos1, size_type n1, const T& t) const;
    template<class T>
      constexpr int compare(size_type pos1, size_type n1, const T& t,
                            size_type pos2, size_type n2 = npos) const;
    constexpr int compare(const basic_string& str) const noexcept;
    constexpr int compare(size_type pos1, size_type n1, const basic_string& str) const;
    constexpr int compare(size_type pos1, size_type n1, const basic_string& str,
                          size_type pos2, size_type n2 = npos) const;
    constexpr int compare(const CharT* s) const;
    constexpr int compare(size_type pos1, size_type n1, const CharT* s) const;
    constexpr int compare(size_type pos1, size_type n1, const CharT* s, size_type n2) const;

    constexpr bool starts_with(basic_string_view<CharT, Traits> x) const noexcept;
    constexpr bool starts_with(CharT x) const noexcept;
    constexpr bool starts_with(const CharT* x) const;
    constexpr bool ends_with(basic_string_view<CharT, Traits> x) const noexcept;
    constexpr bool ends_with(CharT x) const noexcept;
    constexpr bool ends_with(const CharT* x) const;

    constexpr bool contains(basic_string_view<CharT, Traits> x) const noexcept;
    constexpr bool contains(CharT x) const noexcept;
    constexpr bool contains(const CharT* x) const;
  };

  template<class InputIt,
           class Allocator = allocator<typename iterator_traits<InputIt>::value_type>>
    basic_string(InputIt, InputIt, Allocator = Allocator())
      -> basic_string<typename iterator_traits<InputIt>::value_type,
                      char_traits<typename iterator_traits<InputIt>::value_type>,
                      Allocator>;

  template<class CharT,
           class Traits,
           class Allocator = allocator<CharT>>
    explicit basic_string(basic_string_view<CharT, Traits>, const Allocator& = Allocator())
      -> basic_string<CharT, Traits, Allocator>;

  template<class CharT,
           class Traits,
           class Allocator = allocator<CharT>>
    basic_string(basic_string_view<CharT, Traits>,
                 typename /* 见描述 */::size_type,
                 typename /* 见描述 */::size_type,
                 const Allocator& = Allocator())
      -> basic_string<CharT, Traits, Allocator>;
}


标准库头文件 <string_view>

< cpp‎ | header

此头文件是字符串库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持

类
basic_string_view
(C++17)
 只读的字符串视图
(类模板)
std::string_view (C++17) | std::basic_string_view <char>
std::u8string_view (C++20) | std::basic_string_view <char8_t>
std::u16string_view (C++17) | std::basic_string_view <char16_t>
std::u32string_view (C++17) | std::basic_string_view <char32_t>
std::wstring_view (C++17) | std::basic_string_view <wchar_t>
std::hash<std::string_view>std::hash<std::wstring_view>std::hash<std::u8string_view>std::hash<std::u16string_view>std::hash<std::u32string_view>
(C++17)(C++17)(C++20)(C++17)(C++17)
 string_view 的散列支持
(类模板特化)
前置声明
定义于头文件 <functional>
hash
(C++11)
 散列函数对象
(类模板)

函数
operator==operator!=operator<operator>operator<=operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 以字典序比较两个字符串视图
(函数模板)
operator<<
 进行字符串视图的流输出
(函数模板)
swap
 交换两个对象的值
(函数模板)
范围访问
begincbegin
(C++11)(C++14)
 返回指向容器或数组起始的迭代器
(函数模板)
endcend
(C++11)(C++14)
 返回指向容器或数组结尾的迭代器
(函数模板)
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
sizessize
(C++17)(C++20)
 返回容器或数组的大小
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)
字面量
定义于内联命名空间 std::literals::string_view_literals
operator""sv
(C++17)
 创建一个字符数组字面量的字符串视图
(函数)

概要

#include <compare>

namespace std {
  // 类模板 basic_string_view
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_string_view;

  template<class CharT, class Traits>
    inline constexpr bool ranges::enable_view<basic_string_view<CharT, Traits>> = true;
  template<class CharT, class Traits>
    inline constexpr bool ranges::enable_borrowed_range<basic_string_view<CharT, Traits>> =
      true;

  // 非成员函数
  template<class CharT, class Traits>
    constexpr bool operator==(basic_string_view<CharT, Traits> x,
                              basic_string_view<CharT, Traits> y) noexcept;
  template<class CharT, class Traits>
    constexpr /* 见描述 */
      operator<=>(basic_string_view<CharT, Traits> x,
                  basic_string_view<CharT, Traits> y) noexcept;

  // 充足的比较函数额外重载

  // 插入器与提取器
  template<class CharT, class Traits>
    basic_ostream<CharT, Traits>&
      operator<<(basic_ostream<CharT, Traits>& os,
                 basic_string_view<CharT, Traits> str);

  // basic_string_view typedef 名
  using string_view    = basic_string_view<char>;
  using u8string_view  = basic_string_view<char8_t>;
  using u16string_view = basic_string_view<char16_t>;
  using u32string_view = basic_string_view<char32_t>;
  using wstring_view   = basic_string_view<wchar_t>;

  // 散列支持
  template<class T> struct hash;
  template<> struct hash<string_view>;
  template<> struct hash<u8string_view>;
  template<> struct hash<u16string_view>;
  template<> struct hash<u32string_view>;
  template<> struct hash<wstring_view>;

  inline namespace literals {
  inline namespace string_view_literals {
    // basic_string_view 字面量的后缀
    constexpr string_view    operator""sv(const char* str, size_t len) noexcept;
    constexpr u8string_view  operator""sv(const char8_t* str, size_t len) noexcept;
    constexpr u16string_view operator""sv(const char16_t* str, size_t len) noexcept;
    constexpr u32string_view operator""sv(const char32_t* str, size_t len) noexcept;
    constexpr wstring_view   operator""sv(const wchar_t* str, size_t len) noexcept;
  }
  }
}

类模板 std::basic_string_view

namespace std {
  template<class CharT, class Traits = char_traits<CharT>>
  class basic_string_view {
  public:
    // 类型
    using Traits_type            = Traits;
    using value_type             = CharT;
    using pointer                = value_type*;
    using const_pointer          = const value_type*;
    using reference              = value_type&;
    using const_reference        = const value_type&;
    using const_iterator         = /* 由实现定义 */
    using iterator               = const_iterator;
    using const_reverse_iterator = reverse_iterator<const_iterator>;
    using reverse_iterator       = const_reverse_iterator;
    using size_type              = size_t;
    using difference_type        = ptrdiff_t;
    static constexpr size_type npos = size_type(-1);

    // 构造与赋值
    constexpr basic_string_view() noexcept;
    constexpr basic_string_view(const basic_string_view&) noexcept = default;
    constexpr basic_string_view& operator=(const basic_string_view&) noexcept = default;
    constexpr basic_string_view(const CharT* str);
    constexpr basic_string_view(nullptr_t) = delete;
    constexpr basic_string_view(const CharT* str, size_type len);
    template<class It, class End>
      constexpr basic_string_view(It begin, End end);
    template<class R>
      constexpr basic_string_view(R&& r);

    // 迭代器支持
    constexpr const_iterator begin() const noexcept;
    constexpr const_iterator end() const noexcept;
    constexpr const_iterator cbegin() const noexcept;
    constexpr const_iterator cend() const noexcept;
    constexpr const_reverse_iterator rbegin() const noexcept;
    constexpr const_reverse_iterator rend() const noexcept;
    constexpr const_reverse_iterator crbegin() const noexcept;
    constexpr const_reverse_iterator crend() const noexcept;

    // 容量
    constexpr size_type size() const noexcept;
    constexpr size_type length() const noexcept;
    constexpr size_type max_size() const noexcept;
    [[nodiscard]] constexpr bool empty() const noexcept;

    // 元素访问
    constexpr const_reference operator[](size_type pos) const;
    constexpr const_reference at(size_type pos) const;
    constexpr const_reference front() const;
    constexpr const_reference back() const;
    constexpr const_pointer data() const noexcept;

    // 修改器
    constexpr void remove_prefix(size_type n);
    constexpr void remove_suffix(size_type n);
    constexpr void swap(basic_string_view& s) noexcept;

    // 字符串操作
    constexpr size_type copy(CharT* s, size_type n, size_type pos = 0) const;

    constexpr basic_string_view substr(size_type pos = 0, size_type n = npos) const;

    constexpr int compare(basic_string_view s) const noexcept;
    constexpr int compare(size_type pos1, size_type n1, basic_string_view s) const;
    constexpr int compare(size_type pos1, size_type n1, basic_string_view s,
                          size_type pos2, size_type n2) const;
    constexpr int compare(const CharT* s) const;
    constexpr int compare(size_type pos1, size_type n1, const CharT* s) const;
    constexpr int compare(size_type pos1, size_type n1, const CharT* s,
                          size_type n2) const;

    constexpr bool starts_with(basic_string_view x) const noexcept;
    constexpr bool starts_with(CharT x) const noexcept;
    constexpr bool starts_with(const CharT* x) const;
    constexpr bool ends_with(basic_string_view x) const noexcept;
    constexpr bool ends_with(CharT x) const noexcept;
    constexpr bool ends_with(const CharT* x) const;

    constexpr bool contains(basic_string_view x) const noexcept;
    constexpr bool contains(CharT x) const noexcept;
    constexpr bool contains(const CharT* x) const;

    // 搜索
    constexpr size_type find(basic_string_view s, size_type pos = 0) const noexcept;
    constexpr size_type find(CharT c, size_type pos = 0) const noexcept;
    constexpr size_type find(const CharT* s, size_type pos, size_type n) const;
    constexpr size_type find(const CharT* s, size_type pos = 0) const;
    constexpr size_type rfind(basic_string_view s, size_type pos = npos) const noexcept;
    constexpr size_type rfind(CharT c, size_type pos = npos) const noexcept;
    constexpr size_type rfind(const CharT* s, size_type pos, size_type n) const;
    constexpr size_type rfind(const CharT* s, size_type pos = npos) const;

    constexpr size_type find_first_of(basic_string_view s,
                                      size_type pos = 0) const noexcept;
    constexpr size_type find_first_of(CharT c, size_type pos = 0) const noexcept;
    constexpr size_type find_first_of(const CharT* s, size_type pos, size_type n) const;
    constexpr size_type find_first_of(const CharT* s, size_type pos = 0) const;
    constexpr size_type find_last_of(basic_string_view s,
                                     size_type pos = npos) const noexcept;
    constexpr size_type find_last_of(CharT c, size_type pos = npos) const noexcept;
    constexpr size_type find_last_of(const CharT* s, size_type pos, size_type n) const;
    constexpr size_type find_last_of(const CharT* s, size_type pos = npos) const;
    constexpr size_type find_first_not_of(basic_string_view s,
                                          size_type pos = 0) const noexcept;
    constexpr size_type find_first_not_of(CharT c, size_type pos = 0) const noexcept;
    constexpr size_type find_first_not_of(const CharT* s, size_type pos,
                                          size_type n) const;
    constexpr size_type find_first_not_of(const CharT* s, size_type pos = 0) const;
    constexpr size_type find_last_not_of(basic_string_view s,
                                       size_type pos = npos) const noexcept;
    constexpr size_type find_last_not_of(CharT c, size_type pos = npos) const noexcept;
    constexpr size_type find_last_not_of(const CharT* s, size_type pos,
                                         size_type n) const;
    constexpr size_type find_last_not_of(const CharT* s, size_type pos = npos) const;

  private:
    const_pointer data_;          // 仅用于阐释
    size_type size_;              // 仅用于阐释
  };

  // 推导指引
  template<class It, class End>
    basic_string_view(It, End) -> basic_string_view<iter_value_t<It>>;

  template<class R>
    basic_string_view(R&&) -> basic_string_view<ranges::range_value_t<R>>;
}


标准库头文件 <strstream>

< cpp‎ | header

此头文件是输入/输出库的一部分。

类
strstreambuf
(C++98 中弃用)
 实现原生字符数组设备
(类)
istrstream
(C++98 中弃用)
 实现字符数组输入操作
(类)
ostrstream
(C++98 中弃用)
 实现字符数组输出操作
(类)
strstream
(C++98 中弃用)
 实现字符数组输入/输出操作
(类)

概要

namespace std {
  class strstreambuf;
  class istrstream;
  class ostrstream;
  class strstream;
}

类 std::strstreambuf

namespace std {
  class strstreambuf : public basic_streambuf<char> {
  public:
    strstreambuf() : strstreambuf(0) {}
    explicit strstreambuf(streamsize alsize_arg);
    strstreambuf(void* (*palloc_arg)(size_t), void (*pfree_arg)(void*));
    strstreambuf(char* gnext_arg, streamsize n, char* pbeg_arg = nullptr);
    strstreambuf(const char* gnext_arg, streamsize n);

    strstreambuf(signed char* gnext_arg, streamsize n,
                 signed char* pbeg_arg = nullptr);
    strstreambuf(const signed char* gnext_arg, streamsize n);
    strstreambuf(unsigned char* gnext_arg, streamsize n,
                 unsigned char* pbeg_arg = nullptr);
    strstreambuf(const unsigned char* gnext_arg, streamsize n);

    virtual ~strstreambuf();

    void  freeze(bool freezefl = true);
    char* str();
    int   pcount();

  protected:
    int_type overflow (int_type c = EOF) override;
    int_type pbackfail(int_type c = EOF) override;
    int_type underflow() override;
    pos_type seekoff(off_type off, ios_base::seekdir way,
                     ios_base::openmode which = ios_base::in | ios_base::out) override;
    pos_type seekpos(pos_type sp,
                     ios_base::openmode which = ios_base::in | ios_base::out) override;
    streambuf* setbuf(char* s, streamsize n) override;

  private:
    using strstate = /*位掩码类型*/;      // 仅用于阐释
    static const strstate allocated;    // 仅用于阐释
    static const strstate constant;     // 仅用于阐释
    static const strstate dynamic;      // 仅用于阐释
    static const strstate frozen;       // 仅用于阐释
    strstate strmode;                   // 仅用于阐释
    streamsize alsize;                  // 仅用于阐释
    void* (*palloc)(size_t);            // 仅用于阐释
    void (*pfree)(void*);               // 仅用于阐释
  };
}

类 std::istrstream

namespace std {
  class istrstream : public basic_istream<char> {
  public:
    explicit istrstream(const char* s);
    explicit istrstream(char* s);
    istrstream(const char* s, streamsize n);
    istrstream(char* s, streamsize n);
    virtual ~istrstream();

    strstreambuf* rdbuf() const;
    char* str();
  private:
    strstreambuf sb;            // 仅用于阐释
  };
}

类 std::ostrstream

namespace std {
  class ostrstream : public basic_ostream<char> {
  public:
    ostrstream();
    ostrstream(char* s, int n, ios_base::openmode mode = ios_base::out);
    virtual ~ostrstream();

    strstreambuf* rdbuf() const;
    void freeze(bool freezefl = true);
    char* str();
    int pcount() const;
  private:
    strstreambuf sb;            // 仅用于阐释
  };
}

类 std::strstream

namespace std {
  class strstream
    : public basic_iostream<char> {
  public:
    // 类型
    using char_type = char;
    using int_type  = char_traits<char>::int_type;
    using pos_type  = char_traits<char>::pos_type;
    using off_type  = char_traits<char>::off_type;

    // 构造函数/析构函数
    strstream();
    strstream(char* s, int n,
              ios_base::openmode mode = ios_base::in | ios_base::out);
    virtual ~strstream();

    // 成员
    strstreambuf* rdbuf() const;
    void freeze(bool freezefl = true);
    int pcount() const;
    char* str();

  private:
    strstreambuf sb;            // 仅用于阐释
  };
}


标准库头文件 <syncstream>

< cpp‎ | header

此头文件是输入/输出库的一部分。

包含
<ostream>
(C++20)
 std::basic_ostream 、 std::basic_iostream 类模板与数个 typedef

类
basic_syncbuf
(C++20)
 同步输出设备的包装
(类模板)
basic_osyncstream
(C++20)
 同步输出流的包装
(类模板)
syncbuf(C++20) std::basic_syncbuf<char>
(typedef)
wsyncbuf(C++20) std::basic_syncbuf<wchar_t>
(typedef)
osyncstream(C++20) std::basic_osyncstream<char>
(typedef)
wosyncstream(C++20) std::basic_osyncstream<wchar_t>
(typedef)

函数
std::swap(std::basic_syncbuf)
(C++20)
 特化 std::swap 算法
(函数模板)

概要

#include <ostream>

namespace std {
  template<class CharT, class Traits = char_traits<CharT>,
           class Allocator = allocator<CharT>>
    class basic_syncbuf;

  using syncbuf = basic_syncbuf<char>;
  using wsyncbuf = basic_syncbuf<wchar_t>;

  template<class CharT, class Traits = char_traits<CharT>,
           class Allocator = allocator<CharT>>
    class basic_osyncstream;

  using osyncstream = basic_osyncstream<char>;
  using wosyncstream = basic_osyncstream<wchar_t>;
}

类模板 std::basic_syncbuf

namespace std {
  template<class CharT, class Traits = char_traits<CharT>,
           class Allocator = allocator<CharT>>
  class basic_syncbuf : public basic_streambuf<CharT, Traits> {
  public:
    using char_type      = CharT;
    using int_type       = typename Traits::int_type;
    using pos_type       = typename Traits::pos_type;
    using off_type       = typename Traits::off_type;
    using traits_type    = Traits;
    using allocator_type = Allocator;

    using streambuf_type = basic_streambuf<CharT, Traits>;

    // 构造与析构
    basic_syncbuf()
      : basic_syncbuf(nullptr) {}
    explicit basic_syncbuf(streambuf_type* obuf)
      : basic_syncbuf(obuf, Allocator()) {}
    basic_syncbuf(streambuf_type*, const Allocator&);
    basic_syncbuf(basic_syncbuf&&);
    ~basic_syncbuf();

    // 赋值与交换
    basic_syncbuf& operator=(basic_syncbuf&&);
    void swap(basic_syncbuf&);

    // 成员函数
    bool emit();
    streambuf_type* get_wrapped() const noexcept;
    allocator_type get_allocator() const noexcept;
    void set_emit_on_sync(bool) noexcept;

  protected:
    // 覆盖的虚函数
    int sync() override;

  private:
    streambuf_type* wrapped;    // 仅用于阐释
    bool emit_on_sync{};        // 仅用于阐释
  };

  // 特化的算法
  template<class CharT, class Traits, class Allocator>
    void swap(basic_syncbuf<CharT, Traits, Allocator>&,
              basic_syncbuf<CharT, Traits, Allocator>&);
}

类模板 std::basic_osyncstream

namespace std {
  template<class CharT, class Traits = char_traits<CharT>,
           class Allocator = allocator<CharT>>
  class basic_syncbuf : public basic_streambuf<CharT, Traits> {
  public:
    using char_type      = CharT;
    using int_type       = typename Traits::int_type;
    using pos_type       = typename Traits::pos_type;
    using off_type       = typename Traits::off_type;
    using traits_type    = Traits;
    using allocator_type = Allocator;

    using streambuf_type = basic_streambuf<CharT, Traits>;

    // 构造与析构
    basic_syncbuf()
      : basic_syncbuf(nullptr) {}
    explicit basic_syncbuf(streambuf_type* obuf)
      : basic_syncbuf(obuf, Allocator()) {}
    basic_syncbuf(streambuf_type*, const Allocator&);
    basic_syncbuf(basic_syncbuf&&);
    ~basic_syncbuf();

    // 赋值与交换
    basic_syncbuf& operator=(basic_syncbuf&&);
    void swap(basic_syncbuf&);

    // 成员函数
    bool emit();
    streambuf_type* get_wrapped() const noexcept;
    allocator_type get_allocator() const noexcept;
    void set_emit_on_sync(bool) noexcept;

  protected:
    // 覆盖的虚函数
    int sync() override;

  private:
    streambuf_type* wrapped;    // 仅用于阐释
    bool emit_on_sync{};        // 仅用于阐释
  };

  // 特化的算法
  template<class CharT, class Traits, class Allocator>
    void swap(basic_syncbuf<CharT, Traits, Allocator>&,
              basic_syncbuf<CharT, Traits, Allocator>&);
}


标准库头文件 <system_error>

< cpp‎ | header

此头文件是错误处理库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持

类
error_category
(C++11)
 错误类别的基类
(类)
error_condition
(C++11)
 保有可移植的错误码
(类)
errc
(C++11)
 列出所有标准 <cerrno> 宏常量的 std::error_condition 枚举
(类)
error_code
(C++11)
 保有依赖于平台的错误码
(类)
system_error
(C++11)
 用于报告拥有 error_code 的错误条件的异常类
(类)
is_error_code_enum
(C++11)
 鉴别类是否可作为 error_code 枚举
(类模板)
is_error_condition_enum
(C++11)
 鉴别枚举是否可作为 std::error_condition
(类模板)
std::hash<std::error_code>
(C++11)
 std::error_code 的散列支持
(类模板特化)
前置声明
定义于头文件 <functional>
hash
(C++11)
 散列函数对象
(类模板)

函数
generic_category
(C++11)
 鉴别通用错误类别
(函数)
system_category
(C++11)
 鉴别操作系统错误类别
(函数)
operator==operator!=operator<operator<=>
(C++20 中移除)(C++20 中移除)(C++20)
 比较两个 error_code
(函数)
operator<<
 输出值和类别名到输出流
(函数)
make_error_code(std::errc)
(C++11)
 构造 std::errc 错误码
(函数)
operator==operator!=operator<operator<=>
(C++20 中移除)(C++20 中移除)(C++20)
 比较 error_condition 和 error_code
(函数)
make_error_condition(std::errc)
(C++11)
 构造 std::errc 错误条件
(函数)

概要

#include <compare>

namespace std {
  class error_category;
  const error_category& generic_category() noexcept;
  const error_category& system_category() noexcept;

  class error_code;
  class error_condition;
  class system_error;

  template<class T>
    struct is_error_code_enum : public false_type {};

  template<class T>
    struct is_error_condition_enum : public false_type {};

  enum class errc {
    address_family_not_supported,       // EAFNOSUPPORT
    address_in_use,                     // EADDRINUSE
    address_not_available,              // EADDRNOTAVAIL
    already_connected,                  // EISCONN
    argument_list_too_long,             // E2BIG
    argument_out_of_domain,             // EDOM
    bad_address,                        // EFAULT
    bad_file_descriptor,                // EBADF
    bad_message,                        // EBADMSG
    broken_pipe,                        // EPIPE
    connection_aborted,                 // ECONNABORTED
    connection_already_in_progress,     // EALREADY
    connection_refused,                 // ECONNREFUSED
    connection_reset,                   // ECONNRESET
    cross_device_link,                  // EXDEV
    destination_address_required,       // EDESTADDRREQ
    device_or_resource_busy,            // EBUSY
    directory_not_empty,                // ENOTEMPTY
    executable_format_error,            // ENOEXEC
    file_exists,                        // EEXIST
    file_too_large,                     // EFBIG
    filename_too_long,                  // ENAMETOOLONG
    function_not_supported,             // ENOSYS
    host_unreachable,                   // EHOSTUNREACH
    identifier_removed,                 // EIDRM
    illegal_byte_sequence,              // EILSEQ
    inappropriate_io_control_operation, // ENOTTY
    interrupted,                        // EINTR
    invalid_argument,                   // EINVAL
    invalid_seek,                       // ESPIPE
    io_error,                           // EIO
    is_a_directory,                     // EISDIR
    message_size,                       // EMSGSIZE
    network_down,                       // ENETDOWN
    network_reset,                      // ENETRESET
    network_unreachable,                // ENETUNREACH
    no_buffer_space,                    // ENOBUFS
    no_child_process,                   // ECHILD
    no_link,                            // ENOLINK
    no_lock_available,                  // ENOLCK
    no_message_available,               // ENODATA
    no_message,                         // ENOMSG
    no_protocol_option,                 // ENOPROTOOPT
    no_space_on_device,                 // ENOSPC
    no_stream_resources,                // ENOSR
    no_such_device_or_address,          // ENXIO
    no_such_device,                     // ENODEV
    no_such_file_or_directory,          // ENOENT
    no_such_process,                    // ESRCH
    not_a_directory,                    // ENOTDIR
    not_a_socket,                       // ENOTSOCK
    not_a_stream,                       // ENOSTR
    not_connected,                      // ENOTCONN
    not_enough_memory,                  // ENOMEM
    not_supported,                      // ENOTSUP
    operation_canceled,                 // ECANCELED
    operation_in_progress,              // EINPROGRESS
    operation_not_permitted,            // EPERM
    operation_not_supported,            // EOPNOTSUPP
    operation_would_block,              // EWOULDBLOCK
    owner_dead,                         // EOWNERDEAD
    permission_denied,                  // EACCES
    protocol_error,                     // EPROTO
    protocol_not_supported,             // EPROTONOSUPPORT
    read_only_file_system,              // EROFS
    resource_deadlock_would_occur,      // EDEADLK
    resource_unavailable_try_again,     // EAGAIN
    result_out_of_range,                // ERANGE
    state_not_recoverable,              // ENOTRECOVERABLE
    stream_timeout,                     // ETIME
    text_file_busy,                     // ETXTBSY
    timed_out,                          // ETIMEDOUT
    too_many_files_open_in_system,      // ENFILE
    too_many_files_open,                // EMFILE
    too_many_links,                     // EMLINK
    too_many_symbolic_link_levels,      // ELOOP
    value_too_large,                    // EOVERFLOW
    wrong_protocol_type,                // EPROTOTYPE
  };

  template<> struct is_error_condition_enum<errc> : true_type {};

  // 非成员函数
  error_code make_error_code(errc e) noexcept;

  template<class charT, class traits>
    basic_ostream<charT, traits>&
      operator<<(basic_ostream<charT, traits>& os, const error_code& ec);

  // 非成员函数
  error_condition make_error_condition(errc e) noexcept;

  // 比较函数
  bool operator==(const error_code& lhs, const error_code& rhs) noexcept;
  bool operator==(const error_code& lhs, const error_condition& rhs) noexcept;
  bool operator==(const error_condition& lhs, const error_condition& rhs) noexcept;
  strong_ordering operator<=>(const error_code& lhs,
                              const error_code& rhs) noexcept;
  strong_ordering operator<=>(const error_condition& lhs,
                              const error_condition& rhs) noexcept;

  // 散列支持
  template<class T> struct hash;
  template<> struct hash<error_code>;
  template<> struct hash<error_condition>;

  // 系统错误支持
  template<class T>
    inline constexpr bool is_error_code_enum_v = is_error_code_enum<T>::value;
  template<class T>
    inline constexpr bool is_error_condition_enum_v = is_error_condition_enum<T>::value;
}

类 std::error_category

namespace std {
  class error_category {
  public:
    constexpr error_category() noexcept;
    virtual ~error_category();
    error_category(const error_category&) = delete;
    error_category& operator=(const error_category&) = delete;
    virtual const char* name() const noexcept = 0;
    virtual error_condition default_error_condition(int ev) const noexcept;
    virtual bool equivalent(int code, const error_condition& condition) const noexcept;
    virtual bool equivalent(const error_code& code, int condition) const noexcept;
    virtual string message(int ev) const = 0;

    bool operator==(const error_category& rhs) const noexcept;
    strong_ordering operator<=>(const error_category& rhs) const noexcept;
  };

  const error_category& generic_category() noexcept;
  const error_category& system_category() noexcept;
}

类 std::error_code

namespace std {
  class error_code {
  public:
    // 构造函数
    error_code() noexcept;
    error_code(int val, const error_category& cat) noexcept;
    template<class ErrorCodeEnum>
      error_code(ErrorCodeEnum e) noexcept;

    // 修改器
    void assign(int val, const error_category& cat) noexcept;
    template<class ErrorCodeEnum>
      error_code& operator=(ErrorCodeEnum e) noexcept;
    void clear() noexcept;

    // 观察器
    int value() const noexcept;
    const error_category& category() const noexcept;
    error_condition default_error_condition() const noexcept;
    string message() const;
    explicit operator bool() const noexcept;

  private:
    int val_;                   // 仅用于阐释
    const error_category* cat_; // 仅用于阐释
  };

  // 非成员函数
  error_code make_error_code(errc e) noexcept;

  template<class charT, class traits>
    basic_ostream<charT, traits>&
      operator<<(basic_ostream<charT, traits>& os, const error_code& ec);
}

类 std::error_condition

namespace std {
  class error_condition {
  public:
    // 构造函数
    error_condition() noexcept;
    error_condition(int val, const error_category& cat) noexcept;
    template<class ErrorConditionEnum>
      error_condition(ErrorConditionEnum e) noexcept;

    // 修改器
    void assign(int val, const error_category& cat) noexcept;
    template<class ErrorConditionEnum>
      error_condition& operator=(ErrorConditionEnum e) noexcept;
    void clear() noexcept;

    // 观察器
    int value() const noexcept;
    const error_category& category() const noexcept;
    string message() const;
    explicit operator bool() const noexcept;

  private:
    int val_;                   // 仅用于阐释
    const error_category* cat_; // 仅用于阐释
  };
}

类 std::system_error

namespace std {
  class system_error : public runtime_error {
  public:
    system_error(error_code ec, const string& what_arg);
    system_error(error_code ec, const char* what_arg);
    system_error(error_code ec);
    system_error(int ev, const error_category& ecat, const string& what_arg);
    system_error(int ev, const error_category& ecat, const char* what_arg);
    system_error(int ev, const error_category& ecat);
    const error_code& code() const noexcept;
    const char* what() const noexcept override;
  };
}


标准库头文件 <thread>

< cpp‎ | header

此头文件是线程支持库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持

命名空间
this_thread 提供访问当前执行线程的函数

类
thread
(C++11)
 管理单独的线程
(类)
jthread
(C++20)
 有自动合并和取消支持的 std::thread
(类)
std::hash<std::thread::id>
 特化 std::hash
(类模板特化)

函数
std::swap(std::thread)
(C++11)
 特化 std::swap 算法
(函数)
operator==operator!=operator< operator<= operator> operator>= operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 比较两个 thread::id 对象
(函数)
operator<<
 序列化 thread::id 对象
(函数模板)
定义于命名空间 std::this_thread
yield
(C++11)
 建议实现重新调度各执行线程
(函数)
get_id
(C++11)
 返回当前线程的线程 id
(函数)
sleep_for
(C++11)
 使当前线程的执行停止指定的时间段
(函数)
sleep_until
(C++11)
 使当前线程的执行停止直到指定的时间点
(函数)

概要

#include <compare>

namespace std {
  class thread;

  void swap(thread& x, thread& y) noexcept;

  // 类 jthread
  class jthread;

  namespace this_thread {
    thread::id get_id() noexcept;

    void yield() noexcept;
    template<class Clock, class Duration>
      void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
    template<class Rep, class Period>
      void sleep_for(const chrono::duration<Rep, Period>& rel_time);
  }
}

类 std::thread

namespace std {
  class thread {
  public:
    // 类型
    class id;
    using native_handle_type = /* 由实现定义 */;

    // 构造/复制/销毁
    thread() noexcept;
    template<class F, class... Args> explicit thread(F&& f, Args&&... args);
    ~thread();
    thread(const thread&) = delete;
    thread(thread&&) noexcept;
    thread& operator=(const thread&) = delete;
    thread& operator=(thread&&) noexcept;

    // 成员
    void swap(thread&) noexcept;
    bool joinable() const noexcept;
    void join();
    void detach();
    id get_id() const noexcept;
    native_handle_type native_handle();

    // 静态成员
    static unsigned int hardware_concurrency() noexcept;
  };
}

类 std::jthread

namespace std {
  class jthread {
  public:
    // 类型
    using id = thread::id;
    using native_handle_type = thread::native_handle_type;

    // 构造函数、移动与赋值
    jthread() noexcept;
    template<class F, class... Args> explicit jthread(F&& f, Args&&... args);
    ~jthread();
    jthread(const jthread&) = delete;
    jthread(jthread&&) noexcept;
    jthread& operator=(const jthread&) = delete;
    jthread& operator=(jthread&&) noexcept;

    // 成员
    void swap(jthread&) noexcept;
    [[nodiscard]] bool joinable() const noexcept;
    void join();
    void detach();
    [[nodiscard]] id get_id() const noexcept;
    [[nodiscard]] native_handle_type native_handle();

    // 停止记号处理
    [[nodiscard]] stop_source get_stop_source() noexcept;
    [[nodiscard]] stop_token get_stop_token() const noexcept;
    bool request_stop() noexcept;

    // 特化的算法
    friend void swap(jthread& lhs, jthread& rhs) noexcept;

    // 静态成员
    [[nodiscard]] static unsigned int hardware_concurrency() noexcept;

  private:
    stop_source ssource;        // 仅用于阐释
  };
}

类 std::thread::id

namespace std {
  class thread::id {
  public:
    id() noexcept;
  };

  bool operator==(thread::id x, thread::id y) noexcept;
  strong_ordering operator<=>(thread::id x, thread::id y) noexcept;

  template<class charT, class traits>
    basic_ostream<charT, traits>&
      operator<<(basic_ostream<charT, traits>& out, thread::id id);

  // 散列支持
  template<class T> struct hash;
  template<> struct hash<thread::id>;
}


标准库头文件 <tuple>

< cpp‎ | header

此头文件是通用工具库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持

类
tuple
(C++11)
 实现固定大小的容器，它保有类型可以相异的元素
(类模板)
tuple_size
(C++11)
 获得元组式类型的元素数
(类模板)
tuple_element
(C++11)
 获得元组式类型的元素类型
(类模板)
std::tuple_size<std::tuple>
(C++11)
 在编译时获得 tuple 的大小
(类模板特化)
std::tuple_element<std::tuple>
(C++11)
 获得指定元素的类型
(类模板特化)
std::uses_allocator<std::tuple>
(C++11)
 特化 std::uses_allocator 类型特征
(类模板特化)

常量
ignore
 用 tie 解包 tuple 时用来跳过元素的占位符
(常量)

函数
make_tuple
 创建一个 tuple 对象，其类型根据各实参类型定义
(函数模板)
tie
 创建左值引用的 tuple，或将 tuple 解包为独立对象
(函数模板)
forward_as_tuple
 创建转发引用的 tuple
(函数模板)
tuple_cat
 通过连接任意数量的元组来创建一个tuple
(函数模板)
std::get(std::tuple)
 元组式访问指定的元素
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按字典顺序比较 tuple 中的值
(函数模板)
std::swap(std::tuple)
(C++11)
 特化 std::swap 算法
(函数模板)
apply
(C++17)
 以一个实参的元组来调用函数
(函数模板)
make_from_tuple
(C++17)
 以一个实参元组构造对象
(函数模板)

概要

#include <compare>

namespace std {
  // 类模板 tuple
  template<class... Types>
    class tuple;

  // tuple 创建函数
  inline constexpr /* 未指定 */ ignore;

  template<class... TTypes>
    constexpr tuple<unwrap_ref_decay_t<TTypes>...> make_tuple(TTypes&&...);

  template<class... TTypes>
    constexpr tuple<TTypes&&...> forward_as_tuple(TTypes&&...) noexcept;

  template<class... TTypes>
    constexpr tuple<TTypes&...> tie(TTypes&...) noexcept;

  template<class... Tuples>
    constexpr tuple<CTypes...> tuple_cat(Tuples&&...);

  // 以参数的 tuple 调用函数
  template<class F, class Tuple>
    constexpr decltype(auto) apply(F&& f, Tuple&& t);

  template<class T, class Tuple>
    constexpr T make_from_tuple(Tuple&& t);

  // tuple 辅助类
  template<class T> struct tuple_size;                  // 不定义
  template<class T> struct tuple_size<const T>;

  template<class... Types> struct tuple_size<tuple<Types...>>;

  template<size_t I, class T> struct tuple_element;     // 不定义
  template<size_t I, class T> struct tuple_element<I, const T>;

  template<size_t I, class... Types>
    struct tuple_element<I, tuple<Types...>>;

  template<size_t I, class T>
    using tuple_element_t = typename tuple_element<I, T>::type;

  // 元素访问
  template<size_t I, class... Types>
    constexpr tuple_element_t<I, tuple<Types...>>& get(tuple<Types...>&) noexcept;
  template<size_t I, class... Types>
    constexpr tuple_element_t<I, tuple<Types...>>&& get(tuple<Types...>&&) noexcept;
  template<size_t I, class... Types>
    constexpr const tuple_element_t<I, tuple<Types...>>&
      get(const tuple<Types...>&) noexcept;
  template<size_t I, class... Types>
    constexpr const tuple_element_t<I, tuple<Types...>>&&
      get(const tuple<Types...>&&) noexcept;
  template<class T, class... Types>
    constexpr T& get(tuple<Types...>& t) noexcept;
  template<class T, class... Types>
    constexpr T&& get(tuple<Types...>&& t) noexcept;
  template<class T, class... Types>
    constexpr const T& get(const tuple<Types...>& t) noexcept;
  template<class T, class... Types>
    constexpr const T&& get(const tuple<Types...>&& t) noexcept;

  // 关系运算符
  template<class... TTypes, class... UTypes>
    constexpr bool operator==(const tuple<TTypes...>&, const tuple<UTypes...>&);
  template<class... TTypes, class... UTypes>
    constexpr common_comparison_category_t</*synth-three-way-result*/<TTypes, UTypes>...>
      operator<=>(const tuple<TTypes...>&, const tuple<UTypes...>&);

  // 分配器相关特征
  template<class... Types, class Alloc>
    struct uses_allocator<tuple<Types...>, Alloc>;

  // 特化的算法
  template<class... Types>
    constexpr void
      swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(/* 见描述 */);

  // tuple 辅助类
  template<class T>
    inline constexpr size_t tuple_size_v = tuple_size<T>::value;
}

// 弃用
namespace std {
  template<class T> class tuple_size<volatile T>;
  template<class T> class tuple_size<const volatile T>;

  template<size_t I, class T> class tuple_element<I, volatile T>;
  template<size_t I, class T> class tuple_element<I, const volatile T>;
}

类模板 std::tuple

namespace std {
  template<class... Types>
  class tuple {
  public:
    // tuple 创建
    constexpr explicit(/* 见描述 */) tuple();
    constexpr explicit(/* 见描述 */)
      tuple(const Types&...);         // 仅若 sizeof...(Types) >= 1
    template<class... UTypes>
      constexpr explicit(/* 见描述 */)
        tuple(UTypes&&...);           // 仅若 sizeof...(Types) >= 1

    tuple(const tuple&) = default;
    tuple(tuple&&) = default;

    template<class... UTypes>
      constexpr explicit(/* 见描述 */) tuple(const tuple<UTypes...>&);
    template<class... UTypes>
      constexpr explicit(/* 见描述 */) tuple(tuple<UTypes...>&&);

    template<class U1, class U2>
      constexpr explicit(/* 见描述 */)
        tuple(const pair<U1, U2>&);   // 仅若 sizeof...(Types) == 2
    template<class U1, class U2>
      constexpr explicit(/* 见描述 */)
        tuple(pair<U1, U2>&&);        // 仅若 sizeof...(Types) == 2

    // allocator-extended constructors
    template<class Alloc>
      constexpr explicit(/* 见描述 */)
        tuple(allocator_arg_t, const Alloc& a);
    template<class Alloc>
      constexpr explicit(/* 见描述 */)
        tuple(allocator_arg_t, const Alloc& a, const Types&...);
    template<class Alloc, class... UTypes>
      constexpr explicit(/* 见描述 */)
        tuple(allocator_arg_t, const Alloc& a, UTypes&&...);
    template<class Alloc>
      constexpr tuple(allocator_arg_t, const Alloc& a, const tuple&);
    template<class Alloc>
      constexpr tuple(allocator_arg_t, const Alloc& a, tuple&&);
    template<class Alloc, class... UTypes>
      constexpr explicit(/* 见描述 */)
        tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&);
    template<class Alloc, class... UTypes>
      constexpr explicit(/* 见描述 */)
        tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);
    template<class Alloc, class U1, class U2>
      constexpr explicit(/* 见描述 */)
        tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&);
    template<class Alloc, class U1, class U2>
      constexpr explicit(/* 见描述 */)
        tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);

    // tuple 赋值
    constexpr tuple& operator=(const tuple&);
    constexpr tuple& operator=(tuple&&) noexcept(/* 见描述 */);

    template<class... UTypes>
      constexpr tuple& operator=(const tuple<UTypes...>&);
    template<class... UTypes>
      constexpr tuple& operator=(tuple<UTypes...>&&);

    template<class U1, class U2>
      constexpr tuple& operator=(const pair<U1, U2>&); // 仅若 sizeof...(Types) == 2
    template<class U1, class U2>
      constexpr tuple& operator=(pair<U1, U2>&&);      // 仅若 sizeof...(Types) == 2

    // tuple 交换
    constexpr void swap(tuple&) noexcept(/* 见描述 */);
  };

  template<class... UTypes>
    tuple(UTypes...) -> tuple<UTypes...>;
  template<class T1, class T2>
    tuple(pair<T1, T2>) -> tuple<T1, T2>;
  template<class Alloc, class... UTypes>
    tuple(allocator_arg_t, Alloc, UTypes...) -> tuple<UTypes...>;
  template<class Alloc, class T1, class T2>
    tuple(allocator_arg_t, Alloc, pair<T1, T2>) -> tuple<T1, T2>;
  template<class Alloc, class... UTypes>
    tuple(allocator_arg_t, Alloc, tuple<UTypes...>) -> tuple<UTypes...>;
}


标准库头文件 <type_traits>

< cpp‎ | header

此头文件是类型支持库的一部分。

类
辅助类
integral_constantbool_constant
(C++11)(C++17)
 具有指定值的指定类型的编译期常量
(类模板)
true_type | std::integral_constant <bool, true>
false_type | std::integral_constant <bool, false>
基础类型分类
is_void
(C++11)
 检查类型是否为 void
(类模板)
is_null_pointer
(C++14)
 检查类型是否为 std::nullptr_t
(类模板)
is_integral
(C++11)
 检查类型是否为整型
(类模板)
is_floating_point
(C++11)
 检查类型是否是浮点类型
(类模板)
is_array
(C++11)
 检查类型是否是数组类型
(类模板)
is_enum
(C++11)
 检查类型是否是枚举类型
(类模板)
is_union
(C++11)
 检查类型是否为联合体类型
(类模板)
is_class
(C++11)
 检查类型是否非联合类类型
(类模板)
is_function
(C++11)
 检查是否为函数类型
(类模板)
is_pointer
(C++11)
 检查类型是否为指针类型
(类模板)
is_lvalue_reference
(C++11)
 检查类型是否为左值引用
(类模板)
is_rvalue_reference
(C++11)
 检查类型是否为右值引用
(类模板)
is_member_object_pointer
(C++11)
 检查类型是否为指向非静态成员对象的指针
(类模板)
is_member_function_pointer
(C++11)
 检查类型是否为指向非静态成员函数的指针
(类模板)
复合类型分类
is_fundamental
(C++11)
 检查是否是基础类型
(类模板)
is_arithmetic
(C++11)
 检查类型是否为算术类型
(类模板)
is_scalar
(C++11)
 检查类型是否为标量类型
(类模板)
is_object
(C++11)
 检查是否是对象类型
(类模板)
is_compound
(C++11)
 检查是否为复合类型
(类模板)
is_reference
(C++11)
 检查类型是否为左值引用或右值引用
(类模板)
is_member_pointer
(C++11)
 检查类型是否为指向非静态成员函数或对象的指针类型
(类模板)
类型的性质
is_const
(C++11)
 检查类型是否为 const 限定
(类模板)
is_volatile
(C++11)
 检查类型是否为 volatile 限定
(类模板)
is_trivial
(C++11)
 检查类型是否平凡
(类模板)
is_trivially_copyable
(C++11)
 检查类型是否可平凡复制
(类模板)
is_standard_layout
(C++11)
 检查是否是一个标准布局类型
(类模板)
is_pod
(C++11)(C++20 中弃用)
 检查类型是否为简旧数据（POD）类型
(类模板)
is_literal_type
(C++11)(C++17 中弃用)(C++20 中移除)
 检查类型是否为字面类型
(类模板)
has_unique_object_representations
(C++17)
 检查是否该类型对象的每一位都对其值有贡献
(类模板)
is_empty
(C++11)
 检查类型是否为类（但非联合体）类型且无非静态数据成员
(类模板)
is_polymorphic
(C++11)
 检查类型是否为多态类类型
(类模板)
is_abstract
(C++11)
 检查类型是否为抽象类类型
(类模板)
is_final
(C++14)
 检查类型是否为 final 类类型
(类模板)
is_aggregate
(C++17)
 检查类型是否聚合类型
(类模板)
is_signed
(C++11)
 检查类型是否为有符号算术类型
(类模板)
is_unsigned
(C++11)
 检查类型是否为无符号算术类型
(类模板)
is_bounded_array
(C++20)
 检查类型是否为有已知边界的数组类型
(类模板)
is_unbounded_array
(C++20)
 检查类型是否为有未知边界的数组类型
(类模板)
is_scoped_enum
(C++23)
 检查类型是否为有作用域枚举类型
(类模板)
受支持操作
is_constructibleis_trivially_constructibleis_nothrow_constructible
(C++11)(C++11)(C++11)
 检查类型是否带有针对特定实参的构造函数
(类模板)
is_default_constructibleis_trivially_default_constructibleis_nothrow_default_constructible
(C++11)(C++11)(C++11)
 检查类型是否有默认构造函数
(类模板)
is_copy_constructibleis_trivially_copy_constructibleis_nothrow_copy_constructible
(C++11)(C++11)(C++11)
 检查类型是否拥有复制构造函数
(类模板)
is_move_constructibleis_trivially_move_constructibleis_nothrow_move_constructible
(C++11)(C++11)(C++11)
 检查类型是否能从右值引用构造
(类模板)
is_assignableis_trivially_assignableis_nothrow_assignable
(C++11)(C++11)(C++11)
 检查类型是否拥有针对特定实参的赋值运算符
(类模板)
is_copy_assignableis_trivially_copy_assignableis_nothrow_copy_assignable
(C++11)(C++11)(C++11)
 检查类型是否拥有复制赋值运算符
(类模板)
is_move_assignableis_trivially_move_assignableis_nothrow_move_assignable
(C++11)(C++11)(C++11)
 检查类型是否有拥有移动赋值运算符
(类模板)
is_destructibleis_trivially_destructibleis_nothrow_destructible
(C++11)(C++11)(C++11)
 检查类型是否拥有未被弃置的析构函数
(类模板)
has_virtual_destructor
(C++11)
 检查类型是否拥有虚析构函数
(类模板)
is_swappable_withis_swappableis_nothrow_swappable_withis_nothrow_swappable
(C++17)(C++17)(C++17)(C++17)
 检查一个类型的对象是否能与同类型或不同类型的对象交换
(类模板)
性质查询
alignment_of
(C++11)
 获取类型的对齐要求
(类模板)
rank
(C++11)
 获取数组类型的维数
(类模板)
extent
(C++11)
 获取数组类型在指定维度的大小
(类模板)
类型关系
is_same
(C++11)
 检查两个类型是否相同
(类模板)
is_base_of
(C++11)
 检查一个类型是否派生自另一个类型
(类模板)
is_convertibleis_nothrow_convertible
(C++11)(C++20)
 检查是否能转换一个类型为另一类型
(类模板)
is_layout_compatible
(C++20)
 检查二个类型是否布局兼容
(类模板)
is_pointer_interconvertible_base_of
(C++20)
 检查一个类型是否为另一类型的指针可互转换（起始）基类
(类模板)
is_invocableis_invocable_ris_nothrow_invocableis_nothrow_invocable_r
(C++17)
 检查类型能否以给定的实参类型调用（如同以 std::invoke）
(类模板)
常-易变性说明符
remove_cvremove_constremove_volatile
(C++11)(C++11)(C++11)
 从给定类型移除 const 或/与 volatile 限定符
(类模板)
add_cvadd_constadd_volatile
(C++11)(C++11)(C++11)
 添加 const 或/与 volatile 限定符到给定类型
(类模板)
引用
remove_reference
(C++11)
 从给定类型移除引用
(类模板)
add_lvalue_referenceadd_rvalue_reference
(C++11)(C++11)
 向给定类型添加左值或右值引用
(类模板)
指针
remove_pointer
(C++11)
 移除给定类型的一层指针
(类模板)
add_pointer
(C++11)
 对给定类型添加一层指针
(类模板)
符号修饰符
make_signed
(C++11)
 使给定的整型类型有符号
(类模板)
make_unsigned
(C++11)
 使给定的整型类型无符号
(类模板)
数组
remove_extent
(C++11)
 从给定数组类型移除一个维度
(类模板)
remove_all_extents
(C++11)
 移除给定数组类型的所有维度
(类模板)
杂项变换
aligned_storage
(C++11)
 定义适于用作给定大小的类型的未初始化存储的类型
(类模板)
aligned_union
(C++11)
 定义适于用作所有给定类型的未初始化存储的类型
(类模板)
decay
(C++11)
 实施当按值传递实参给函数时所进行的类型变换
(类模板)
remove_cvref
(C++20)
 将 std::remove_cv 与 std::remove_reference 结合
(类模板)
enable_if
(C++11)
 条件性地从重载决议移除函数重载或模板特化
(类模板)
conditional
(C++11)
 基于编译时布尔值选择一个类型或另一个
(类模板)
common_type
(C++11)
 确定一组类型的公共类型
(类模板)
common_referencebasic_common_reference
(C++20)
 确定类型组的共用引用类型
(类模板)
underlying_type
(C++11)
 获取给定枚举类型的底层整数类型
(类模板)
result_ofinvoke_result
(C++11)(C++20 中移除)(C++17)
 推导以一组实参调用一个可调用对象的结果类型
(类模板)
void_t
(C++17)
 void 变参别名模板
(别名模板)
type_identity
(C++20)
 返回不更改的类型实参
(类模板)
类型特征的运算
conjunction
(C++17)
 变参的逻辑与元函数
(类模板)
disjunction
(C++17)
 变参的逻辑或元函数
(类模板)
negation
(C++17)
 逻辑非元函数
(类模板)

函数
成员关系
is_pointer_interconvertible_with_class
(C++20)
 检查一个类型的对象是否与该类型的指定子对象指针可互转换
(函数模板)
is_corresponding_member
(C++20)
 检查二个指定成员是否在二个指定类型中的公共起始序列中彼此对应
(函数模板)
常量求值语境
is_constant_evaluated
(C++20)
 检测调用是否在常量求值的语境内发生
(函数)

概要

namespace std {
  // 辅助类：
  template <class T, T v> struct integral_constant;
  template <bool B>
  using bool_constant = integral_constant<bool, B>;
  using true_type = bool_constant<true>;
  using false_type = bool_constant<false>;

  // 基础类型分类：
  template <class T> struct is_void;
  template <class T> struct is_null_pointer;
  template <class T> struct is_integral;
  template <class T> struct is_floating_point;
  template <class T> struct is_array;
  template <class T> struct is_pointer;
  template <class T> struct is_lvalue_reference;
  template <class T> struct is_rvalue_reference;
  template <class T> struct is_member_object_pointer;
  template <class T> struct is_member_function_pointer;
  template <class T> struct is_enum;
  template <class T> struct is_union;
  template <class T> struct is_class;
  template <class T> struct is_function;

  // 复合类型分类：
  template <class T> struct is_reference;
  template <class T> struct is_arithmetic;
  template <class T> struct is_fundamental;
  template <class T> struct is_object;
  template <class T> struct is_scalar;
  template <class T> struct is_compound;
  template <class T> struct is_member_pointer;

  // 类型的性质：
  template <class T> struct is_const;
  template <class T> struct is_volatile;
  template <class T> struct is_trivial;
  template <class T> struct is_trivially_copyable;
  template <class T> struct is_standard_layout;
  template <class T> struct is_pod;
  template <class T> struct is_empty;
  template <class T> struct is_polymorphic;
  template <class T> struct is_abstract;
  template <class T> struct is_final;
  template <class T> struct is_aggregate;
  template <class T> struct is_signed;
  template <class T> struct is_unsigned;
  template <class T> struct is_bounded_array;
  template <class T> struct is_unbounded_array;
  template <class T> struct is_scoped_enum;

  template <class T, class... Args> struct is_constructible;
  template <class T> struct is_default_constructible;
  template <class T> struct is_copy_constructible;
  template <class T> struct is_move_constructible;
  template <class T, class U> struct is_assignable;
  template <class T> struct is_copy_assignable;
  template <class T> struct is_move_assignable;
  template <class T, class U> struct is_swappable_with;
  template <class T> struct is_swappable;
  template <class T> struct is_destructible;
  template <class T, class... Args> struct is_trivially_constructible;
  template <class T> struct is_trivially_default_constructible;
  template <class T> struct is_trivially_copy_constructible;
  template <class T> struct is_trivially_move_constructible;
  template <class T, class U> struct is_trivially_assignable;
  template <class T> struct is_trivially_copy_assignable;
  template <class T> struct is_trivially_move_assignable;
  template <class T> struct is_trivially_destructible;
  template <class T, class... Args> struct is_nothrow_constructible;
  template <class T> struct is_nothrow_default_constructible;
  template <class T> struct is_nothrow_copy_constructible;
  template <class T> struct is_nothrow_move_constructible;
  template <class T, class U> struct is_nothrow_assignable;
  template <class T> struct is_nothrow_copy_assignable;
  template <class T> struct is_nothrow_move_assignable;
  template <class T, class U> struct is_nothrow_swappable_with;
  template <class T> struct is_nothrow_swappable;
  template <class T> struct is_nothrow_destructible;
  template <class T> struct has_virtual_destructor;
  template <class T> struct has_unique_object_representations;

  // 类型性质查询：
  template <class T> struct alignment_of;
  template <class T> struct rank;
  template <class T, unsigned I = 0> struct extent;

  // 类型关系：
  template <class T, class U> struct is_same;
  template <class Base, class Derived> struct is_base_of;
  template <class From, class To> struct is_convertible;
  template <class From, class To> struct is_nothrow_convertible;
  template <class T, class U> struct is_layout_compatible;
  template <class Base, class Derived> struct is_pointer_interconvertible_base_of;
  template <class Fn, class... ArgTypes> struct is_invocable;
  template <class R, class Fn, class... ArgTypes> struct is_invocable_r;
  template <class Fn, class... ArgTypes> struct is_nothrow_invocable;
  template <class R, class Fn, class... ArgTypes> struct is_nothrow_invocable_r;

  // const-volatile 修改：
  template <class T> struct remove_const;
  template <class T> struct remove_volatile;
  template <class T> struct remove_cv;
  template <class T> struct add_const;
  template <class T> struct add_volatile;
  template <class T> struct add_cv;
  template <class T>
  using remove_const_t = typename remove_const<T>::type;
  template <class T>
  using remove_volatile_t = typename remove_volatile<T>::type;
  template <class T>
  using remove_cv_t = typename remove_cv<T>::type;
  template <class T>
  using add_const_t = typename add_const<T>::type;
  template <class T>
  using add_volatile_t = typename add_volatile<T>::type;
  template <class T>
  using add_cv_t = typename add_cv<T>::type;

  // 引用修改：
  template <class T> struct remove_reference;
  template <class T> struct add_lvalue_reference;
  template <class T> struct add_rvalue_reference;
  template <class T>
  using remove_reference_t = typename remove_reference<T>::type;
  template <class T>
  using add_lvalue_reference_t = typename add_lvalue_reference<T>::type;
  template <class T>
  using add_rvalue_reference_t = typename add_rvalue_reference<T>::type;

  // 正负号修改：
  template <class T> struct make_signed;
  template <class T> struct make_unsigned;
  template <class T>
  using make_signed_t = typename make_signed<T>::type;
  template <class T>
  using make_unsigned_t = typename make_unsigned<T>::type;

  // 数组修改：
  template <class T> struct remove_extent;
  template <class T> struct remove_all_extents;
  template <class T>
  using remove_extent_t = typename remove_extent<T>::type;
  template <class T>
  using remove_all_extents_t = typename remove_all_extents<T>::type;

  // 指针修改：
  template <class T> struct remove_pointer;
  template <class T> struct add_pointer;
  template <class T>
  using remove_pointer_t = typename remove_pointer<T>::type;
  template <class T>
  using add_pointer_t = typename add_pointer<T>::type;

  // 其他变换：
  template <size_t Len,
  size_t Align = /* 默认对齐 */ >
  struct aligned_storage;
  template <size_t Len, class... Types> struct aligned_union;
  template <class T> struct decay;
  template <class T> struct remove_cvref;
  template <bool, class T = void> struct enable_if;
  template <bool, class T, class F> struct conditional;
  template <class... T> struct common_type;
  template <class T> struct underlying_type;
  template <class> class result_of; // 不定义
  template <class F, class... ArgTypes> class result_of<F(ArgTypes...)>;
  template <class F, class... ArgTypes> class invoke_result;
  template <size_t Len,
  size_t Align = /* 默认对齐 */ >
  using aligned_storage_t = typename aligned_storage<Len, Align>::type;
  template <size_t Len, class... Types>
  using aligned_union_t = typename aligned_union<Len, Types...>::type;
  template <class T>
  using decay_t = typename decay<T>::type;
  template <class T>
  using remove_cvref_t = typename remove_cvref<T>::type;
  template <bool b, class T = void>
  using enable_if_t = typename enable_if<b, T>::type;
  template <bool b, class T, class F>
  using conditional_t = typename conditional<b, T, F>::type;
  template <class... T>
  using common_type_t = typename common_type<T...>::type;
  template <class T>
  using underlying_type_t = typename underlying_type<T>::type;
  template <class T>
  using result_of_t = typename result_of<T>::type;
  template <class F, class... ArgTypes>
  using invoke_result_t = typename invoke_result<F, ArgTypes...>::type;
  template <class...>
  using void_t = void;

  // 逻辑运算符特征：
  template<class... B> struct conjunction;
  template<class... B> struct disjunction;
  template<class B> struct negation;

  // 基础类型分类
  template <class T> inline constexpr bool is_void_v
  = is_void<T>::value;
  template <class T> inline constexpr bool is_null_pointer_v
  = is_null_pointer<T>::value;
  template <class T> inline constexpr bool is_integral_v
  = is_integral<T>::value;
  template <class T> inline constexpr bool is_floating_point_v
  = is_floating_point<T>::value;
  template <class T> inline constexpr bool is_array_v
  = is_array<T>::value;
  template <class T> inline constexpr bool is_pointer_v
  = is_pointer<T>::value;
  template <class T> inline constexpr bool is_lvalue_reference_v
  = is_lvalue_reference<T>::value;
  template <class T> inline constexpr bool is_rvalue_reference_v
  = is_rvalue_reference<T>::value;
  template <class T> inline constexpr bool is_member_object_pointer_v
  = is_member_object_pointer<T>::value;
  template <class T> inline constexpr bool is_member_function_pointer_v
  = is_member_function_pointer<T>::value;
  template <class T> inline constexpr bool is_enum_v
  = is_enum<T>::value;
  template <class T> inline constexpr bool is_union_v
  = is_union<T>::value;
  template <class T> inline constexpr bool is_class_v
  = is_class<T>::value;
  template <class T> inline constexpr bool is_function_v
  = is_function<T>::value;

  // 复合类型分类
  template <class T> inline constexpr bool is_reference_v
  = is_reference<T>::value;
  template <class T> inline constexpr bool is_arithmetic_v
  = is_arithmetic<T>::value;
  template <class T> inline constexpr bool is_fundamental_v
  = is_fundamental<T>::value;
  template <class T> inline constexpr bool is_object_v
  = is_object<T>::value;
  template <class T> inline constexpr bool is_scalar_v
  = is_scalar<T>::value;
  template <class T> inline constexpr bool is_compound_v
  = is_compound<T>::value;
  template <class T> inline constexpr bool is_member_pointer_v
  = is_member_pointer<T>::value;

  // 类型的性质
  template <class T> inline constexpr bool is_const_v
  = is_const<T>::value;
  template <class T> inline constexpr bool is_volatile_v
  = is_volatile<T>::value;
  template <class T> inline constexpr bool is_trivial_v
  = is_trivial<T>::value;
  template <class T> inline constexpr bool is_trivially_copyable_v
  = is_trivially_copyable<T>::value;
  template <class T> inline constexpr bool is_standard_layout_v
  = is_standard_layout<T>::value;
  template <class T> inline constexpr bool is_pod_v
  = is_pod<T>::value;
  template <class T> inline constexpr bool is_empty_v
  = is_empty<T>::value;
  template <class T> inline constexpr bool is_polymorphic_v
  = is_polymorphic<T>::value;
  template <class T> inline constexpr bool is_abstract_v
  = is_abstract<T>::value;
  template <class T> inline constexpr bool is_final_v
  = is_final<T>::value;
  template <class T> inline constexpr bool is_aggregate_v
  = is_aggregate<T>::value;
  template <class T> inline constexpr bool is_signed_v
  = is_signed<T>::value;
  template <class T> inline constexpr bool is_unsigned_v
  = is_unsigned<T>::value;
  template <class T> inline constexpr bool is_bounded_array_v
  = is_bounded_array<T>::value;
  template <class T> inline constexpr bool is_unbounded_array_v
  = is_unbounded_array<T>::value;
  template <class T> inline constexpr bool is_scoped_enum_v
  = is_scoped_enum<T>::value;
  template <class T, class... Args> inline constexpr bool is_constructible_v
  = is_constructible<T, Args...>::value;
  template <class T> inline constexpr bool is_default_constructible_v
  = is_default_constructible<T>::value;
  template <class T> inline constexpr bool is_copy_constructible_v
  = is_copy_constructible<T>::value;
  template <class T> inline constexpr bool is_move_constructible_v
  = is_move_constructible<T>::value;
  template <class T, class U> inline constexpr bool is_assignable_v
  = is_assignable<T, U>::value;
  template <class T> inline constexpr bool is_copy_assignable_v
  = is_copy_assignable<T>::value;
  template <class T> inline constexpr bool is_move_assignable_v
  = is_move_assignable<T>::value;
  template <class T, class U> inline constexpr bool is_swappable_with_v
  = is_swappable_with<T, U>::value;
  template <class T> inline constexpr bool is_swappable_v
  = is_swappable<T>::value;
  template <class T> inline constexpr bool is_destructible_v
  = is_destructible<T>::value;
  template <class T, class... Args> inline constexpr bool is_trivially_constructible_v
  = is_trivially_constructible<T, Args...>::value;
  template <class T> inline constexpr bool is_trivially_default_constructible_v
  = is_trivially_default_constructible<T>::value;
  template <class T> inline constexpr bool is_trivially_copy_constructible_v
  = is_trivially_copy_constructible<T>::value;
  template <class T> inline constexpr bool is_trivially_move_constructible_v
  = is_trivially_move_constructible<T>::value;
  template <class T, class U> inline constexpr bool is_trivially_assignable_v
  = is_trivially_assignable<T, U>::value;
  template <class T> inline constexpr bool is_trivially_copy_assignable_v
  = is_trivially_copy_assignable<T>::value;
  template <class T> inline constexpr bool is_trivially_move_assignable_v
  = is_trivially_move_assignable<T>::value;
  template <class T> inline constexpr bool is_trivially_destructible_v
  = is_trivially_destructible<T>::value;
  template <class T, class... Args> inline constexpr bool is_nothrow_constructible_v
  = is_nothrow_constructible<T, Args...>::value;
  template <class T> inline constexpr bool is_nothrow_default_constructible_v
  = is_nothrow_default_constructible<T>::value;
  template <class T> inline constexpr bool is_nothrow_copy_constructible_v
  = is_nothrow_copy_constructible<T>::value;
  template <class T> inline constexpr bool is_nothrow_move_constructible_v
  = is_nothrow_move_constructible<T>::value;
  template <class T, class U> inline constexpr bool is_nothrow_assignable_v
  = is_nothrow_assignable<T, U>::value;
  template <class T> inline constexpr bool is_nothrow_copy_assignable_v
  = is_nothrow_copy_assignable<T>::value;
  template <class T> inline constexpr bool is_nothrow_move_assignable_v
  = is_nothrow_move_assignable<T>::value;
  template <class T, class U> inline constexpr bool is_nothrow_swappable_with_v
  = is_nothrow_swappable_with<T, U>::value;
  template <class T> inline constexpr bool is_nothrow_swappable_v
  = is_nothrow_swappable<T>::value;
  template <class T> inline constexpr bool is_nothrow_destructible_v
  = is_nothrow_destructible<T>::value;
  template <class T> inline constexpr bool has_virtual_destructor_v
  = has_virtual_destructor<T>::value;
  template <class T> inline constexpr bool has_unique_object_representations_v
  = has_unique_object_representations<T>::value;

  // 类型性质查询
  template <class T> inline constexpr size_t alignment_of_v
  = alignment_of<T>::value;
  template <class T> inline constexpr size_t rank_v
  = rank<T>::value;
  template <class T, unsigned I = 0> inline constexpr size_t extent_v
  = extent<T, I>::value;

  // 类型关系
  template <class T, class U> inline constexpr bool is_same_v
  = is_same<T, U>::value;
  template <class Base, class Derived> inline constexpr bool is_base_of_v
  = is_base_of<Base, Derived>::value;
  template <class From, class To> inline constexpr bool is_convertible_v
  = is_convertible<From, To>::value;
  template<class From, class To>
    inline constexpr bool is_nothrow_convertible_v
      = is_nothrow_convertible<From, To>::value;
  template<class T, class U>
    inline constexpr bool is_layout_compatible_v = is_layout_compatible<T, U>::value;
  template<class Base, class Derived>
    inline constexpr bool is_pointer_interconvertible_base_of_v
      = is_pointer_interconvertible_base_of<Base, Derived>::value;

  template <class Fn, class... ArgTypes>
  inline constexpr bool is_invocable_v
    = is_invocable<Fn, ArgTypes...>::value;
  template <class R, class Fn, class... ArgTypes>
  inline constexpr bool is_invocable_r_v
    = is_invocable_r<R, Fn, ArgTypes...>::value;
  template <class Fn, class... ArgTypes>
  inline constexpr bool is_nothrow_invocable_v
    = is_nothrow_invocable<Fn, ArgTypes...>::value;
  template <class R, class Fn, class... ArgTypes>
  inline constexpr bool is_nothrow_invocable_r_v
    = is_nothrow_invocable_r<R, Fn, ArgTypes...>::value;

  // 逻辑运算符特征：
  template<class... B> inline constexpr bool conjunction_v = conjunction<B...>::value;
  template<class... B> inline constexpr bool disjunction_v = disjunction<B...>::value;
  template<class B> inline constexpr bool negation_v = negation<B>::value;

  // 成员关系
  template <class S, class M>
    constexpr bool is_pointer_interconvertible_with_class(M S::*m) noexcept;
  template <class S1, class S2, class M1, class M2>
    constexpr bool is_corresponding_member(M1 S1::*m1, M2 S2::*m2) noexcept;

  // 常量求值语境
  constexpr bool is_constant_evaluated() noexcept;
} // namespace std

类模板 std::integral_constant

namespace std {
  template <class T, T v>
  struct integral_constant {
    static constexpr T value = v;
    using value_type = T;
    using type = integral_constant<T, v>;
    constexpr operator value_type() const noexcept { return value; }
    constexpr value_type operator()() const noexcept { return value; }
  };
}


标准库头文件 <typeindex>

< cpp‎ | header

此头文件是类型支持库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持

类
type_index
(C++11)
 针对 type_info 对象的包装，它能用作关联容器和无序关联容器的索引。
(类)
std::hash<std::type_index>
(C++11)
 std::type_index 的散列支持
(类模板特化)
前置声明
定义于头文件 <functional>
hash
(C++11)
 散列函数对象
(类模板)

概要

#include <compare>

namespace std {
  class type_index;
  template<class T> struct hash;
  template<> struct hash<type_index>;
}

类 std::type_index

class type_index {
  public:
    type_index(const type_info& rhs) noexcept;
    bool operator==(const type_index& rhs) const noexcept;
    bool operator< (const type_index& rhs) const noexcept;
    bool operator> (const type_index& rhs) const noexcept;
    bool operator<=(const type_index& rhs) const noexcept;
    bool operator>=(const type_index& rhs) const noexcept;
    strong_ordering operator<=>(const type_index& rhs) const noexcept;
    size_t hash_code() const noexcept;
    const char* name() const noexcept;

  private:
    const type_info* target; // 仅用于阐释
    // 注意，此处使用了指针而非引用，
    // 表示预置的复制/移动构造函数及赋值运算符均有所提供并按预期工作。
  };
}


标准库头文件 <typeinfo>

< cpp‎ | header

此头文件是类型支持库的一部分。

类

type_info | 含有某个类型的信息，由实现生成。 这是 typeid 运算符所返回的类。 (类)
bad_typeid | 当 typeid 表达式中的实参为空值时抛出的异常 (类)
bad_cast | 由非法的 dynamic_cast 表达式抛出的异常，即引用类型转型失败 (类)

概要

namespace std {
  class type_info;
  class bad_cast;
  class bad_typeid;
}

类 std::type_info

namespace std {
  class type_info {
  public:
    virtual ~type_info();
    constexpr bool operator==(const type_info& rhs) const noexcept;
    bool before(const type_info& rhs) const noexcept;
    size_t hash_code() const noexcept;
    const char* name() const noexcept;

    type_info(const type_info&) = delete;                   // 不能复制
    type_info& operator=(const type_info&) = delete;        // 不能复制
  };
}

类 std::bad_cast

namespace std {
  class bad_cast : public exception {
  public:
    // 特殊成员函数的规定见 [exception]
    const char* what() const noexcept override;
  };
}

类 std::bad_typeid

namespace std {
  class bad_typeid : public exception {
  public:
    // 特殊成员函数的规定见 [exception]
    const char* what() const noexcept override;
  };
}


标准库头文件 <unordered_map>

< cpp‎ | header

此头文件是容器库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
<initializer_list>
(C++11)
 std::initializer_list 类模板

类
unordered_map
(C++11 起)
 键值对的集合，按照键生成散列，键是唯一的
(类模板)
unordered_multimap
(C++11 起)
 键值对的集合，按照键生成散列
(类模板)

函数
operator==operator!=
(C++20 中移除)
 比较 unordered_map 中的值
(函数模板)
std::swap(std::unordered_map)
(C++11)
 特化 std::swap 算法
(函数模板)
erase_if(std::unordered_map)
(C++20)
 擦除所有满足特定判别标准的元素
(函数模板)
operator==operator!=
(C++20 中移除)
 比较 unordered_multimap 中的值
(函数模板)
std::swap(std::unordered_multimap)
(C++11)
 特化 std::swap 算法
(函数模板)
erase_if(std::unordered_multimap)
(C++20)
 擦除所有满足特定判别标准的元素
(函数模板)
范围访问
begincbegin
(C++11)(C++14)
 返回指向容器或数组起始的迭代器
(函数模板)
endcend
(C++11)(C++14)
 返回指向容器或数组结尾的迭代器
(函数模板)
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
sizessize
(C++17)(C++20)
 返回容器或数组的大小
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)

概要

#include <compare>
#include <initializer_list>

namespace std {
  // 类模板 unordered_map
  template<class Key,
           class T,
           class Hash = hash<Key>,
           class Pred = equal_to<Key>,
           class Alloc = allocator<pair<const Key, T>>>
    class unordered_map;

  // 类模板 unordered_multimap
  template<class Key,
           class T,
           class Hash = hash<Key>,
           class Pred = equal_to<Key>,
           class Alloc = allocator<pair<const Key, T>>>
    class unordered_multimap;

  template<class Key, class T, class Hash, class Pred, class Alloc>
    bool operator==(const unordered_map<Key, T, Hash, Pred, Alloc>& a,
                    const unordered_map<Key, T, Hash, Pred, Alloc>& b);

  template<class Key, class T, class Hash, class Pred, class Alloc>
    bool operator==(const unordered_multimap<Key, T, Hash, Pred, Alloc>& a,
                    const unordered_multimap<Key, T, Hash, Pred, Alloc>& b);

  template<class Key, class T, class Hash, class Pred, class Alloc>
    void swap(unordered_map<Key, T, Hash, Pred, Alloc>& x,
              unordered_map<Key, T, Hash, Pred, Alloc>& y)
      noexcept(noexcept(x.swap(y)));

  template<class Key, class T, class Hash, class Pred, class Alloc>
    void swap(unordered_multimap<Key, T, Hash, Pred, Alloc>& x,
              unordered_multimap<Key, T, Hash, Pred, Alloc>& y)
      noexcept(noexcept(x.swap(y)));

  template<class K, class T, class H, class P, class A, class Predicate>
    typename unordered_map<K, T, H, P, A>::size_type
      erase_if(unordered_map<K, T, H, P, A>& c, Predicate pred);

  template<class K, class T, class H, class P, class A, class Predicate>
    typename unordered_multimap<K, T, H, P, A>::size_type
      erase_if(unordered_multimap<K, T, H, P, A>& c, Predicate pred);

  namespace pmr {
    template<class Key,
             class T,
             class Hash = hash<Key>,
             class Pred = equal_to<Key>>
      using unordered_map =
        std::unordered_map<Key, T, Hash, Pred,
                           polymorphic_allocator<pair<const Key, T>>>;
    template<class Key,
             class T,
             class Hash = hash<Key>,
             class Pred = equal_to<Key>>
      using unordered_multimap =
        std::unordered_multimap<Key, T, Hash, Pred,
                                polymorphic_allocator<pair<const Key, T>>>;

  }
}

类模板 std::unordered_map

namespace std {
  template<class Key,
           class T,
           class Hash = hash<Key>,
           class Pred = equal_to<Key>,
           class Allocator = allocator<pair<const Key, T>>>
  class unordered_map {
  public:
    // 类型
    using key_type             = Key;
    using mapped_type          = T;
    using value_type           = pair<const Key, T>;
    using hasher               = Hash;
    using key_equal            = Pred;
    using allocator_type       = Allocator;
    using pointer              = typename allocator_traits<Allocator>::pointer;
    using const_pointer        = typename allocator_traits<Allocator>::const_pointer;
    using reference            = value_type&;
    using const_reference      = const value_type&;
    using size_type            = /* 由实现定义 */;
    using difference_type      = /* 由实现定义 */;

    using iterator             = /* 由实现定义 */;
    using const_iterator       = /* 由实现定义 */;
    using local_iterator       = /* 由实现定义 */;
    using const_local_iterator = /* 由实现定义 */;
    using node_type            = /* 未指明 */;
    using insert_return_type   = /*insert-return-type*/<iterator, node_type>;

    // 构造/复制/销毁
    unordered_map();
    explicit unordered_map(size_type n,
                           const hasher& hf = hasher(),
                           const key_equal& eql = key_equal(),
                           const allocator_type& a = allocator_type());
    template<class InputIt>
      unordered_map(InputIt f, InputIt l,
                    size_type n = /* 见描述 */,
                    const hasher& hf = hasher(),
                    const key_equal& eql = key_equal(),
                    const allocator_type& a = allocator_type());
    unordered_map(const unordered_map&);
    unordered_map(unordered_map&&);
    explicit unordered_map(const Allocator&);
    unordered_map(const unordered_map&, const Allocator&);
    unordered_map(unordered_map&&, const Allocator&);
    unordered_map(initializer_list<value_type> il,
                  size_type n = /* 见描述 */,
                  const hasher& hf = hasher(),
                  const key_equal& eql = key_equal(),
                  const allocator_type& a = allocator_type());
    unordered_map(size_type n, const allocator_type& a)
      : unordered_map(n, hasher(), key_equal(), a) { }
    unordered_map(size_type n, const hasher& hf, const allocator_type& a)
      : unordered_map(n, hf, key_equal(), a) { }
    template<class InputIt>
      unordered_map(InputIt f, InputIt l, size_type n, const allocator_type& a)
        : unordered_map(f, l, n, hasher(), key_equal(), a) { }
    template<class InputIt>
      unordered_map(InputIt f, InputIt l, size_type n, const hasher& hf,
                    const allocator_type& a)
        : unordered_map(f, l, n, hf, key_equal(), a) { }
    unordered_map(initializer_list<value_type> il, size_type n, const allocator_type& a)
      : unordered_map(il, n, hasher(), key_equal(), a) { }
    unordered_map(initializer_list<value_type> il, size_type n, const hasher& hf,
                  const allocator_type& a)
      : unordered_map(il, n, hf, key_equal(), a) { }
    ~unordered_map();
    unordered_map& operator=(const unordered_map&);
    unordered_map& operator=(unordered_map&&)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_move_assignable_v<Hash> &&
               is_nothrow_move_assignable_v<Pred>);
    unordered_map& operator=(initializer_list<value_type>);
    allocator_type get_allocator() const noexcept;

    // 迭代器
    iterator       begin() noexcept;
    const_iterator begin() const noexcept;
    iterator       end() noexcept;
    const_iterator end() const noexcept;
    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;

    // 容量
    [[nodiscard]] bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    // 修改器
    template<class... Args> pair<iterator, bool> emplace(Args&&... args);
    template<class... Args> iterator emplace_hint(const_iterator position, Args&&... args);
    pair<iterator, bool> insert(const value_type& obj);
    pair<iterator, bool> insert(value_type&& obj);
    template<class P> pair<iterator, bool> insert(P&& obj);
    iterator       insert(const_iterator hint, const value_type& obj);
    iterator       insert(const_iterator hint, value_type&& obj);
    template<class P> iterator insert(const_iterator hint, P&& obj);
    template<class InputIt> void insert(InputIt first, InputIt last);
    void insert(initializer_list<value_type>);

    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    template<class K> node_type extract(K&& x);
    insert_return_type insert(node_type&& nh);
    iterator           insert(const_iterator hint, node_type&& nh);

    template<class... Args>
      pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
    template<class... Args>
      pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
    template<class... Args>
      iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
    template<class... Args>
      iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);
    template<class M>
      pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
    template<class M>
      pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
    template<class M>
      iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
    template<class M>
      iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);

    iterator  erase(iterator position);
    iterator  erase(const_iterator position);
    size_type erase(const key_type& k);
    template<class K> size_type erase(K&& x);
    iterator  erase(const_iterator first, const_iterator last);
    void      swap(unordered_map&)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_swappable_v<Hash> &&
               is_nothrow_swappable_v<Pred>);
    void      clear() noexcept;

    template<class H2, class P2>
      void merge(unordered_map<Key, T, H2, P2, Allocator>& source);
    template<class H2, class P2>
      void merge(unordered_map<Key, T, H2, P2, Allocator>&& source);
    template<class H2, class P2>
      void merge(unordered_multimap<Key, T, H2, P2, Allocator>& source);
    template<class H2, class P2>
      void merge(unordered_multimap<Key, T, H2, P2, Allocator>&& source);

    // 观察器
    hasher hash_function() const;
    key_equal key_eq() const;

    // map 操作
    iterator         find(const key_type& k);
    const_iterator   find(const key_type& k) const;
    template<class K>
      iterator       find(const K& k);
    template<class K>
      const_iterator find(const K& k) const;
    template<class K>
    size_type        count(const key_type& k) const;
    template<class K>
      size_type      count(const K& k) const;
    bool             contains(const key_type& k) const;
    template<class K>
      bool           contains(const K& k) const;
    pair<iterator, iterator>               equal_range(const key_type& k);
    pair<const_iterator, const_iterator>   equal_range(const key_type& k) const;
    template<class K>
      pair<iterator, iterator>             equal_range(const K& k);
    template<class K>
      pair<const_iterator, const_iterator> equal_range(const K& k) const;

    // 元素访问
    mapped_type& operator[](const key_type& k);
    mapped_type& operator[](key_type&& k);
    mapped_type& at(const key_type& k);
    const mapped_type& at(const key_type& k) const;

    // 桶接口
    size_type bucket_count() const noexcept;
    size_type max_bucket_count() const noexcept;
    size_type bucket_size(size_type n) const;
    size_type bucket(const key_type& k) const;
    local_iterator begin(size_type n);
    const_local_iterator begin(size_type n) const;
    local_iterator end(size_type n);
    const_local_iterator end(size_type n) const;
    const_local_iterator cbegin(size_type n) const;
    const_local_iterator cend(size_type n) const;

    // 散列策略
    float load_factor() const noexcept;
    float max_load_factor() const noexcept;
    void max_load_factor(float z);
    void rehash(size_type n);
    void reserve(size_type n);
  };

  template<class InputIt,
           class Hash = hash</*iter-key-type*/<InputIt>>,
           class Pred = equal_to</*iter-key-type*/<InputIt>>,
           class Allocator = allocator</*iter-to-alloc-type*/<InputIt>>>
    unordered_map(InputIt, InputIt,
                  typename /* 见描述 */::size_type = /* 见描述 */,
                  Hash = Hash(), Pred = Pred(), Allocator = Allocator())
      -> unordered_map</*iter-key-type*/<InputIt>, /*iter-mapped-type*/<InputIt>,
                       Hash, Pred, Allocator>;

  template<class Key, class T, class Hash = hash<Key>,
           class Pred = equal_to<Key>, class Allocator = allocator<pair<const Key, T>>>
    unordered_map(initializer_list<pair<Key, T>>,
                  typename /* 见描述 */::size_type = /* 见描述 */,
                  Hash = Hash(), Pred = Pred(), Allocator = Allocator())
      -> unordered_map<Key, T, Hash, Pred, Allocator>;

  template<class InputIt, class Allocator>
    unordered_map(InputIt, InputIt, typename /* 见描述 */::size_type, Allocator)
      -> unordered_map</*iter-key-type*/<InputIt>, /*iter-mapped-type*/<InputIt>,
                       hash</*iter-key-type*/<InputIt>>,
                       equal_to</*iter-key-type*/<InputIt>>, Allocator>;

  template<class InputIt, class Allocator>
    unordered_map(InputIt, InputIt, Allocator)
      -> unordered_map</*iter-key-type*/<InputIt>, /*iter-mapped-type*/<InputIte>,
                       hash</*iter-key-type*/<InputIt>>,
                       equal_to</*iter-key-type*/<InputIt>>, Allocator>;

  template<class InputIt, class Hash, class Allocator>
    unordered_map(InputIt, InputIt,
                  typename /* 见描述 */::size_type, Hash, Allocator)
      -> unordered_map</*iter-key-type*/<InputIt>, /*iter-mapped-type*/<InputIt>, Hash,
                       equal_to</*iter-key-type*/<InputIt>>, Allocator>;

  template<class Key, class T, class Allocator>
    unordered_map(initializer_list<pair<Key, T>>,
                  typename /* 见描述 */::size_type, Allocator)
      -> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;

  template<class Key, class T, class Allocator>
    unordered_map(initializer_list<pair<Key, T>>, Allocator)
      -> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;

  template<class Key, class T, class Hash, class Allocator>
    unordered_map(initializer_list<pair<Key, T>>,
                  typename /* 见描述 */::size_type, Hash, Allocator)
      -> unordered_map<Key, T, Hash, equal_to<Key>, Allocator>;

  // 交换
  template<class Key, class T, class Hash, class Pred, class Alloc>
    void swap(unordered_map<Key, T, Hash, Pred, Alloc>& x,
              unordered_map<Key, T, Hash, Pred, Alloc>& y)
      noexcept(noexcept(x.swap(y)));
}

类模板 std::unordered_multimap=

namespace std {
  template<class Key,
           class T,
           class Hash = hash<Key>,
           class Pred = equal_to<Key>,
           class Allocator = allocator<pair<const Key, T>>>
  class unordered_multimap {
  public:
    // 类型
    using key_type             = Key;
    using mapped_type          = T;
    using value_type           = pair<const Key, T>;
    using hasher               = Hash;
    using key_equal            = Pred;
    using allocator_type       = Allocator;
    using pointer              = typename allocator_traits<Allocator>::pointer;
    using const_pointer        = typename allocator_traits<Allocator>::const_pointer;
    using reference            = value_type&;
    using const_reference      = const value_type&;
    using size_type            = /* 由实现定义 */;
    using difference_type      = /* 由实现定义 */;

    using iterator             = /* 由实现定义 */;
    using const_iterator       = /* 由实现定义 */;
    using local_iterator       = /* 由实现定义 */;
    using const_local_iterator = /* 由实现定义 */;
    using node_type            = /* 未指明 */;

    // 构造/复制/销毁
    unordered_multimap();
    explicit unordered_multimap(size_type n,
                                const hasher& hf = hasher(),
                                const key_equal& eql = key_equal(),
                                const allocator_type& a = allocator_type());
    template<class InputIt>
      unordered_multimap(InputIt f, InputIt l,
                         size_type n = /* 见描述 */,
                         const hasher& hf = hasher(),
                         const key_equal& eql = key_equal(),
                         const allocator_type& a = allocator_type());
    unordered_multimap(const unordered_multimap&);
    unordered_multimap(unordered_multimap&&);
    explicit unordered_multimap(const Allocator&);
    unordered_multimap(const unordered_multimap&, const Allocator&);
    unordered_multimap(unordered_multimap&&, const Allocator&);
    unordered_multimap(initializer_list<value_type> il,
                       size_type n = /* 见描述 */,
                       const hasher& hf = hasher(),
                       const key_equal& eql = key_equal(),
                       const allocator_type& a = allocator_type());
    unordered_multimap(size_type n, const allocator_type& a)
      : unordered_multimap(n, hasher(), key_equal(), a) { }
    unordered_multimap(size_type n, const hasher& hf, const allocator_type& a)
      : unordered_multimap(n, hf, key_equal(), a) { }
    template<class InputIt>
      unordered_multimap(InputIt f, InputIt l, size_type n, const allocator_type& a)
        : unordered_multimap(f, l, n, hasher(), key_equal(), a) { }
    template<class InputIt>
      unordered_multimap(InputIt f, InputIt l, size_type n, const hasher& hf,
                         const allocator_type& a)
        : unordered_multimap(f, l, n, hf, key_equal(), a) { }
    unordered_multimap(initializer_list<value_type> il, size_type n,
                       const allocator_type& a)
      : unordered_multimap(il, n, hasher(), key_equal(), a) { }
    unordered_multimap(initializer_list<value_type> il, size_type n, const hasher& hf,
                       const allocator_type& a)
      : unordered_multimap(il, n, hf, key_equal(), a) { }
    ~unordered_multimap();
    unordered_multimap& operator=(const unordered_multimap&);
    unordered_multimap& operator=(unordered_multimap&&)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_move_assignable_v<Hash> &&
               is_nothrow_move_assignable_v<Pred>);
    unordered_multimap& operator=(initializer_list<value_type>);
    allocator_type get_allocator() const noexcept;

    // 迭代器
    iterator       begin() noexcept;
    const_iterator begin() const noexcept;
    iterator       end() noexcept;
    const_iterator end() const noexcept;
    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;

    // 容量
    [[nodiscard]] bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    // 修改器
    template<class... Args> iterator emplace(Args&&... args);
    template<class... Args> iterator emplace_hint(const_iterator position, Args&&... args);
    iterator insert(const value_type& obj);
    iterator insert(value_type&& obj);
    template<class P> iterator insert(P&& obj);
    iterator insert(const_iterator hint, const value_type& obj);
    iterator insert(const_iterator hint, value_type&& obj);
    template<class P> iterator insert(const_iterator hint, P&& obj);
    template<class InputIt> void insert(InputIt first, InputIt last);
    void insert(initializer_list<value_type>);

    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    template<class K> node_type extract(K&& x);
    iterator insert(node_type&& nh);
    iterator insert(const_iterator hint, node_type&& nh);

    iterator  erase(iterator position);
    iterator  erase(const_iterator position);
    size_type erase(const key_type& k);
    template<class K> size_type erase(K&& x);
    iterator  erase(const_iterator first, const_iterator last);
    void      swap(unordered_multimap&)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_swappable_v<Hash> &&
               is_nothrow_swappable_v<Pred>);
    void      clear() noexcept;

    template<class H2, class P2>
      void merge(unordered_multimap<Key, T, H2, P2, Allocator>& source);
    template<class H2, class P2>
      void merge(unordered_multimap<Key, T, H2, P2, Allocator>&& source);
    template<class H2, class P2>
      void merge(unordered_map<Key, T, H2, P2, Allocator>& source);
    template<class H2, class P2>
      void merge(unordered_map<Key, T, H2, P2, Allocator>&& source);

    // 观察器
    hasher hash_function() const;
    key_equal key_eq() const;

    // map 操作
    iterator         find(const key_type& k);
    const_iterator   find(const key_type& k) const;
    template<class K>
      iterator       find(const K& k);
    template<class K>
      const_iterator find(const K& k) const;
    size_type        count(const key_type& k) const;
    template<class K>
      size_type      count(const K& k) const;
    bool             contains(const key_type& k) const;
    template<class K>
      bool           contains(const K& k) const;
    pair<iterator, iterator>               equal_range(const key_type& k);
    pair<const_iterator, const_iterator>   equal_range(const key_type& k) const;
    template<class K>
      pair<iterator, iterator>             equal_range(const K& k);
    template<class K>
      pair<const_iterator, const_iterator> equal_range(const K& k) const;

    // 桶接口
    size_type bucket_count() const noexcept;
    size_type max_bucket_count() const noexcept;
    size_type bucket_size(size_type n) const;
    size_type bucket(const key_type& k) const;
    local_iterator begin(size_type n);
    const_local_iterator begin(size_type n) const;
    local_iterator end(size_type n);
    const_local_iterator end(size_type n) const;
    const_local_iterator cbegin(size_type n) const;
    const_local_iterator cend(size_type n) const;

    // 散列策略
    float load_factor() const noexcept;
    float max_load_factor() const noexcept;
    void max_load_factor(float z);
    void rehash(size_type n);
    void reserve(size_type n);
  };

  template<class InputIt,
           class Hash = hash</*iter-key-type*/<InputIt>>,
           class Pred = equal_to</*iter-key-type*/<InputIt>>,
           class Allocator = allocator</*iter-to-alloc-type*/<InputIt>>>
    unordered_multimap(InputIt, InputIt,
                       typename /* 见描述 */::size_type = /* 见描述 */,
                       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
      -> unordered_multimap<iter-key-type<InputIt>, iter-mapped-type<InputIt>,
                            Hash, Pred, Allocator>;

  template<class Key, class T, class Hash = hash<Key>,
           class Pred = equal_to<Key>, class Allocator = allocator<pair<const Key, T>>>
    unordered_multimap(initializer_list<pair<Key, T>>,
                       typename /* 见描述 */::size_type = /* 见描述 */,
                       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
      -> unordered_multimap<Key, T, Hash, Pred, Allocator>;

  template<class InputIt, class Allocator>
    unordered_multimap(InputIt, InputIt, typename /* 见描述 */::size_type,
                       Allocator)
      -> unordered_multimap</*iter-key-type*/<InputIt>, /*iter-mapped-type*/<InputIt>,
                            hash</*iter-key-type*/<InputIt>>,
                            equal_to</*iter-key-type*/<InputIt>>, Allocator>;

  template<class InputIt, class Allocator>
    unordered_multimap(InputIt, InputIt, Allocator)
      -> unordered_multimap</*iter-key-type*/<InputIt>, /*iter-mapped-type*/<InputIt>,
                            hash</*iter-key-type*/<InputIt>>,
                            equal_to</*iter-key-type*/<InputIt>>, Allocator>;

  template<class InputIt, class Hash, class Allocator>
    unordered_multimap(InputIt, InputIt, typename /* 见描述 */::size_type, Hash,
                       Allocator)
      -> unordered_multimap</*iter-key-type*/<InputIt>, iter-mapped-type<InputIt>, Hash,
                            equal_to</*iter-key-type*/<InputIt>>, Allocator>;

  template<class Key, class T, class Allocator>
    unordered_multimap(initializer_list<pair<Key, T>>,
                       typename /* 见描述 */::size_type, Allocator)
      -> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;

  template<class Key, class T, class Allocator>
    unordered_multimap(initializer_list<pair<Key, T>>, Allocator)
      -> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;

  template<class Key, class T, class Hash, class Allocator>
    unordered_multimap(initializer_list<pair<Key, T>>,
                       typename /* 见描述 */::size_type, Hash, Allocator)
      -> unordered_multimap<Key, T, Hash, equal_to<Key>, Allocator>;

  // 交换
  template<class Key, class T, class Hash, class Pred, class Alloc>
    void swap(unordered_multimap<Key, T, Hash, Pred, Alloc>& x,
              unordered_multimap<Key, T, Hash, Pred, Alloc>& y)
      noexcept(noexcept(x.swap(y)));
}


标准库头文件 <unordered_set>

< cpp‎ | header

此头文件是容器库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
<initializer_list>
(C++11)
 std::initializer_list 类模板

类
unordered_set
(C++11 起)
 唯一键的集合，按照键生成散列
(类模板)
unordered_multiset
(C++11 起)
 键的集合，按照键生成散列
(类模板)

函数
operator==operator!=
(C++20 中移除)
 比较 unordered_set 中的值
(函数模板)
std::swap(std::unordered_set)
(C++11)
 特化 std::swap 算法
(函数模板)
erase_if(std::unordered_set)
(C++20)
 擦除所有满足特定判别标准的元素
(函数模板)
operator==operator!=
(C++20 中移除)
 比较 unordered_multiset 中的值
(函数模板)
std::swap(std::unordered_multiset)
(C++11)
 特化 std::swap 算法
(函数模板)
erase_if(std::unordered_multiset)
(C++20)
 擦除所有满足特定判别标准的元素
(函数模板)
范围访问
begincbegin
(C++11)(C++14)
 返回指向容器或数组起始的迭代器
(函数模板)
endcend
(C++11)(C++14)
 返回指向容器或数组结尾的迭代器
(函数模板)
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
sizessize
(C++17)(C++20)
 返回容器或数组的大小
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)

概要

#include <compare>
#include <initializer_list>

namespace std {
  // 类模板 unordered_set
  template<class Key,
           class Hash = hash<Key>,
           class Pred = equal_to<Key>,
           class Alloc = allocator<Key>>
    class unordered_set;

  // 类模板 unordered_multiset
  template<class Key,
           class Hash = hash<Key>,
           class Pred = equal_to<Key>,
           class Alloc = allocator<Key>>
    class unordered_multiset;

  template<class Key, class Hash, class Pred, class Alloc>
    bool operator==(const unordered_set<Key, Hash, Pred, Alloc>& a,
                    const unordered_set<Key, Hash, Pred, Alloc>& b);

  template<class Key, class Hash, class Pred, class Alloc>
    bool operator==(const unordered_multiset<Key, Hash, Pred, Alloc>& a,
                    const unordered_multiset<Key, Hash, Pred, Alloc>& b);

  template<class Key, class Hash, class Pred, class Alloc>
    void swap(unordered_set<Key, Hash, Pred, Alloc>& x,
              unordered_set<Key, Hash, Pred, Alloc>& y)
      noexcept(noexcept(x.swap(y)));

  template<class Key, class Hash, class Pred, class Alloc>
    void swap(unordered_multiset<Key, Hash, Pred, Alloc>& x,
              unordered_multiset<Key, Hash, Pred, Alloc>& y)
      noexcept(noexcept(x.swap(y)));

  template<class K, class H, class P, class A, class Predicate>
    typename unordered_set<K, H, P, A>::size_type
      erase_if(unordered_set<K, H, P, A>& c, Predicate pred);

  template<class K, class H, class P, class A, class Predicate>
    typename unordered_multiset<K, H, P, A>::size_type
      erase_if(unordered_multiset<K, H, P, A>& c, Predicate pred);

  namespace pmr {
    template<class Key,
             class Hash = hash<Key>,
             class Pred = equal_to<Key>>
      using unordered_set = std::unordered_set<Key, Hash, Pred,
                                               polymorphic_allocator<Key>>;

    template<class Key,
             class Hash = hash<Key>,
             class Pred = equal_to<Key>>
      using unordered_multiset = std::unordered_multiset<Key, Hash, Pred,
                                                         polymorphic_allocator<Key>>;
  }
}

类模板 std::unordered_set

namespace std {
  template<class Key,
           class Hash = hash<Key>,
           class Pred = equal_to<Key>,
           class Allocator = allocator<Key>>
  class unordered_set {
  public:
    // 类型
    using key_type             = Key;
    using value_type           = Key;
    using hasher               = Hash;
    using key_equal            = Pred;
    using allocator_type       = Allocator;
    using pointer              = typename allocator_traits<Allocator>::pointer;
    using const_pointer        = typename allocator_traits<Allocator>::const_pointer;
    using reference            = value_type&;
    using const_reference      = const value_type&;
    using size_type            = /* 由实现定义 */;
    using difference_type      = /* 由实现定义 */;

    using iterator             = /* 由实现定义 */;
    using const_iterator       = /* 由实现定义 */;
    using local_iterator       = /* 由实现定义 */;
    using const_local_iterator = /* 由实现定义 */;
    using node_type            = /* 未指明 */;
    using insert_return_type   = /*insert-return-type*/<iterator, node_type>;

    // 构造/复制/销毁
    unordered_set();
    explicit unordered_set(size_type n,
                           const hasher& hf = hasher(),
                           const key_equal& eql = key_equal(),
                           const allocator_type& a = allocator_type());
    template<class InputIt>
      unordered_set(InputIt f, InputIt l,
                    size_type n = /* 见描述 */,
                    const hasher& hf = hasher(),
                    const key_equal& eql = key_equal(),
                    const allocator_type& a = allocator_type());
    unordered_set(const unordered_set&);
    unordered_set(unordered_set&&);
    explicit unordered_set(const Allocator&);
    unordered_set(const unordered_set&, const Allocator&);
    unordered_set(unordered_set&&, const Allocator&);
    unordered_set(initializer_list<value_type> il,
                  size_type n = /* 见描述 */,
                  const hasher& hf = hasher(),
                  const key_equal& eql = key_equal(),
                  const allocator_type& a = allocator_type());
    unordered_set(size_type n, const allocator_type& a)
      : unordered_set(n, hasher(), key_equal(), a) { }
    unordered_set(size_type n, const hasher& hf, const allocator_type& a)
      : unordered_set(n, hf, key_equal(), a) { }
    template<class InputIt>
      unordered_set(InputIt f, InputIt l, size_type n, const allocator_type& a)
        : unordered_set(f, l, n, hasher(), key_equal(), a) { }
    template<class InputIt>
      unordered_set(InputIt f, InputIt l, size_type n, const hasher& hf,
                    const allocator_type& a)
      : unordered_set(f, l, n, hf, key_equal(), a) { }
    unordered_set(initializer_list<value_type> il, size_type n, const allocator_type& a)
      : unordered_set(il, n, hasher(), key_equal(), a) { }
    unordered_set(initializer_list<value_type> il, size_type n, const hasher& hf,
                  const allocator_type& a)
      : unordered_set(il, n, hf, key_equal(), a) { }
    ~unordered_set();
    unordered_set& operator=(const unordered_set&);
    unordered_set& operator=(unordered_set&&)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_move_assignable_v<Hash> &&
               is_nothrow_move_assignable_v<Pred>);
    unordered_set& operator=(initializer_list<value_type>);
    allocator_type get_allocator() const noexcept;

    // 迭代器
    iterator       begin() noexcept;
    const_iterator begin() const noexcept;
    iterator       end() noexcept;
    const_iterator end() const noexcept;
    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;

    // 容量
    [[nodiscard]] bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    // 修改器
    template<class... Args> pair<iterator, bool> emplace(Args&&... args);
    template<class... Args> iterator emplace_hint(const_iterator position, Args&&... args);
    pair<iterator, bool> insert(const value_type& obj);
    pair<iterator, bool> insert(value_type&& obj);
    iterator insert(const_iterator hint, const value_type& obj);
    iterator insert(const_iterator hint, value_type&& obj);
    template<class InputIt> void insert(InputIt first, InputIt last);
    void insert(initializer_list<value_type>);

    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    template<class K> node_type extract(K&& x);
    insert_return_type insert(node_type&& nh);
    iterator           insert(const_iterator hint, node_type&& nh);

    iterator  erase(iterator position);
    iterator  erase(const_iterator position);
    size_type erase(const key_type& k);
    template<class K> size_type erase(K&& x);
    iterator  erase(const_iterator first, const_iterator last);
    void      swap(unordered_set&)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_swappable_v<Hash> &&
               is_nothrow_swappable_v<Pred>);
    void      clear() noexcept;

    template<class H2, class P2>
      void merge(unordered_set<Key, H2, P2, Allocator>& source);
    template<class H2, class P2>
      void merge(unordered_set<Key, H2, P2, Allocator>&& source);
    template<class H2, class P2>
      void merge(unordered_multiset<Key, H2, P2, Allocator>& source);
    template<class H2, class P2>
      void merge(unordered_multiset<Key, H2, P2, Allocator>&& source);

    // 观察器
    hasher hash_function() const;
    key_equal key_eq() const;

    // set 操作
    iterator         find(const key_type& k);
    const_iterator   find(const key_type& k) const;
    template<class K>
      iterator       find(const K& k);
    template<class K>
      const_iterator find(const K& k) const;
    size_type        count(const key_type& k) const;
    template<class K>
      size_type      count(const K& k) const;
    bool             contains(const key_type& k) const;
    template<class K>
      bool           contains(const K& k) const;
    pair<iterator, iterator>               equal_range(const key_type& k);
    pair<const_iterator, const_iterator>   equal_range(const key_type& k) const;
    template<class K>
      pair<iterator, iterator>             equal_range(const K& k);
    template<class K>
      pair<const_iterator, const_iterator> equal_range(const K& k) const;

    // 桶接口
    size_type bucket_count() const noexcept;
    size_type max_bucket_count() const noexcept;
    size_type bucket_size(size_type n) const;
    size_type bucket(const key_type& k) const;
    local_iterator begin(size_type n);
    const_local_iterator begin(size_type n) const;
    local_iterator end(size_type n);
    const_local_iterator end(size_type n) const;
    const_local_iterator cbegin(size_type n) const;
    const_local_iterator cend(size_type n) const;

    // 散列策略
    float load_factor() const noexcept;
    float max_load_factor() const noexcept;
    void max_load_factor(float z);
    void rehash(size_type n);
    void reserve(size_type n);
  };

  template<class InputIt,
           class Hash = hash</*iter-value-type*/<InputIt>>,
           class Pred = equal_to</*iter-value-type*/<InputIt>>,
           class Allocator = allocator</*iter-value-type*/<InputIt>>>
    unordered_set(InputIt, InputIt,
                  typename /* 见描述 */::size_type = /* 见描述 */,
                  Hash = Hash(), Pred = Pred(), Allocator = Allocator())
      -> unordered_set</*iter-value-type*/<InputIt>,
                       Hash, Pred, Allocator>;

  template<class T, class Hash = hash<T>,
           class Pred = equal_to<T>, class Allocator = allocator<T>>
    unordered_set(initializer_list<T>,
                  typename /* 见描述 */::size_type = /* 见描述 */,
                  Hash = Hash(), Pred = Pred(), Allocator = Allocator())
      -> unordered_set<T, Hash, Pred, Allocator>;

  template<class InputIt, class Allocator>
    unordered_set(InputIt, InputIt, typename /* 见描述 */::size_type, Allocator)
      -> unordered_set</*iter-value-type*/<InputIt>,
                       hash</*iter-value-type*/<InputIt>>,
                       equal_to</*iter-value-type*/<InputIt>>,
                       Allocator>;

  template<class InputIt, class Hash, class Allocator>
    unordered_set(InputIt, InputIt, typename /* 见描述 */::size_type,
                  Hash, Allocator)
      -> unordered_set</*iter-value-type*/<InputIt>, Hash,
                       equal_to</*iter-value-type*/<InputIt>>,
                       Allocator>;

  template<class T, class Allocator>
    unordered_set(initializer_list<T>, typename /* 见描述 */::size_type,
                  Allocator)
      -> unordered_set<T, hash<T>, equal_to<T>, Allocator>;

  template<class T, class Hash, class Allocator>
    unordered_set(initializer_list<T>, typename /* 见描述 */::size_type,
                  Hash, Allocator)
      -> unordered_set<T, Hash, equal_to<T>, Allocator>;

  // 交换
  template<class Key, class Hash, class Pred, class Alloc>
    void swap(unordered_set<Key, Hash, Pred, Alloc>& x,
              unordered_set<Key, Hash, Pred, Alloc>& y)
      noexcept(noexcept(x.swap(y)));
}

类模板 std::unordered_multiset

namespace std {
  template<class Key,
           class Hash = hash<Key>,
           class Pred = equal_to<Key>,
           class Allocator = allocator<Key>>
  class unordered_multiset {
  public:
    // 类型
    using key_type             = Key;
    using value_type           = Key;
    using hasher               = Hash;
    using key_equal            = Pred;
    using allocator_type       = Allocator;
    using pointer              = typename allocator_traits<Allocator>::pointer;
    using const_pointer        = typename allocator_traits<Allocator>::const_pointer;
    using reference            = value_type&;
    using const_reference      = const value_type&;
    using size_type            = /* 由实现定义 */;
    using difference_type      = /* 由实现定义 */;

    using iterator             = /* 由实现定义 */;
    using const_iterator       = /* 由实现定义 */;
    using local_iterator       = /* 由实现定义 */;
    using const_local_iterator = /* 由实现定义 */;
    using node_type            = /* 未指明 */;

    // 构造/复制/销毁
    unordered_multiset();
    explicit unordered_multiset(size_type n,
                                const hasher& hf = hasher(),
                                const key_equal& eql = key_equal(),
                                const allocator_type& a = allocator_type());
    template<class InputIt>
      unordered_multiset(InputIt f, InputIt l,
                         size_type n = /* 见描述 */,
                         const hasher& hf = hasher(),
                         const key_equal& eql = key_equal(),
                         const allocator_type& a = allocator_type());
    unordered_multiset(const unordered_multiset&);
    unordered_multiset(unordered_multiset&&);
    explicit unordered_multiset(const Allocator&);
    unordered_multiset(const unordered_multiset&, const Allocator&);
    unordered_multiset(unordered_multiset&&, const Allocator&);
    unordered_multiset(initializer_list<value_type> il,
                       size_type n = /* 见描述 */,
                       const hasher& hf = hasher(),
                       const key_equal& eql = key_equal(),
                       const allocator_type& a = allocator_type());
    unordered_multiset(size_type n, const allocator_type& a)
      : unordered_multiset(n, hasher(), key_equal(), a) { }
    unordered_multiset(size_type n, const hasher& hf, const allocator_type& a)
      : unordered_multiset(n, hf, key_equal(), a) { }
    template<class InputIt>
      unordered_multiset(InputIt f, InputIt l, size_type n, const allocator_type& a)
        : unordered_multiset(f, l, n, hasher(), key_equal(), a) { }
    template<class InputIt>
      unordered_multiset(InputIt f, InputIt l, size_type n, const hasher& hf,
                         const allocator_type& a)
      : unordered_multiset(f, l, n, hf, key_equal(), a) { }
    unordered_multiset(initializer_list<value_type> il, size_type n,
                       const allocator_type& a)
      : unordered_multiset(il, n, hasher(), key_equal(), a) { }
    unordered_multiset(initializer_list<value_type> il, size_type n, const hasher& hf,
                       const allocator_type& a)
      : unordered_multiset(il, n, hf, key_equal(), a) { }
    ~unordered_multiset();
    unordered_multiset& operator=(const unordered_multiset&);
    unordered_multiset& operator=(unordered_multiset&&)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_move_assignable_v<Hash> &&
               is_nothrow_move_assignable_v<Pred>);
    unordered_multiset& operator=(initializer_list<value_type>);
    allocator_type get_allocator() const noexcept;

    // 迭代器
    iterator       begin() noexcept;
    const_iterator begin() const noexcept;
    iterator       end() noexcept;
    const_iterator end() const noexcept;
    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;

    // 容量
    [[nodiscard]] bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    // 修改器
    template<class... Args> iterator emplace(Args&&... args);
    template<class... Args> iterator emplace_hint(const_iterator position, Args&&... args);
    iterator insert(const value_type& obj);
    iterator insert(value_type&& obj);
    iterator insert(const_iterator hint, const value_type& obj);
    iterator insert(const_iterator hint, value_type&& obj);
    template<class InputIt> void insert(InputIt first, InputIt last);
    void insert(initializer_list<value_type>);

    node_type extract(const_iterator position);
    node_type extract(const key_type& x);
    template<class K> node_type extract(K&& x);
    iterator insert(node_type&& nh);
    iterator insert(const_iterator hint, node_type&& nh);

    iterator  erase(iterator position);
    iterator  erase(const_iterator position);
    size_type erase(const key_type& k);
    template<class K> size_type erase(K&& x);
    iterator  erase(const_iterator first, const_iterator last);
    void      swap(unordered_multiset&)
      noexcept(allocator_traits<Allocator>::is_always_equal::value &&
               is_nothrow_swappable_v<Hash> &&
               is_nothrow_swappable_v<Pred>);
    void      clear() noexcept;

    template<class H2, class P2>
      void merge(unordered_multiset<Key, H2, P2, Allocator>& source);
    template<class H2, class P2>
      void merge(unordered_multiset<Key, H2, P2, Allocator>&& source);
    template<class H2, class P2>
      void merge(unordered_set<Key, H2, P2, Allocator>& source);
    template<class H2, class P2>
      void merge(unordered_set<Key, H2, P2, Allocator>&& source);

    // 观察器
    hasher hash_function() const;
    key_equal key_eq() const;

    // set 操作
    iterator         find(const key_type& k);
    const_iterator   find(const key_type& k) const;
    template<class K>
      iterator       find(const K& k);
    template<class K>
      const_iterator find(const K& k) const;
    size_type        count(const key_type& k) const;
    template<class K>
      size_type      count(const K& k) const;
    bool             contains(const key_type& k) const;
    template<class K>
      bool           contains(const K& k) const;
    pair<iterator, iterator>               equal_range(const key_type& k);
    pair<const_iterator, const_iterator>   equal_range(const key_type& k) const;
    template<class K>
      pair<iterator, iterator>             equal_range(const K& k);
    template<class K>
      pair<const_iterator, const_iterator> equal_range(const K& k) const;

    // 桶接口
    size_type bucket_count() const noexcept;
    size_type max_bucket_count() const noexcept;
    size_type bucket_size(size_type n) const;
    size_type bucket(const key_type& k) const;
    local_iterator begin(size_type n);
    const_local_iterator begin(size_type n) const;
    local_iterator end(size_type n);
    const_local_iterator end(size_type n) const;
    const_local_iterator cbegin(size_type n) const;
    const_local_iterator cend(size_type n) const;

    // 散列策略
    float load_factor() const noexcept;
    float max_load_factor() const noexcept;
    void max_load_factor(float z);
    void rehash(size_type n);
    void reserve(size_type n);
  };

  template<class InputIt,
           class Hash = hash</*iter-value-type*/<InputIt>>,
           class Pred = equal_to</*iter-value-type*/<InputIt>>,
           class Allocator = allocator</*iter-value-type*/<InputIt>>>
    unordered_multiset(InputIt, InputIt,
                       /* 见描述 */::size_type = /* 见描述 */,
                       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
      -> unordered_multiset</*iter-value-type*/<InputIt>,
                            Hash, Pred, Allocator>;

  template<class T, class Hash = hash<T>,
           class Pred = equal_to<T>, class Allocator = allocator<T>>
    unordered_multiset(initializer_list<T>,
                       typename /* 见描述 */::size_type = /* 见描述 */,
                       Hash = Hash(), Pred = Pred(), Allocator = Allocator())
      -> unordered_multiset<T, Hash, Pred, Allocator>;

  template<class InputIt, class Allocator>
    unordered_multiset(InputIt, InputIt, typename /* 见描述 */::size_type,
                       Allocator)
      -> unordered_multiset</*iter-value-type*/<InputIt>,
                            hash</*iter-value-type*/<InputIt>>,
                            equal_to</*iter-value-type*/<InputIt>>,
                            Allocator>;

  template<class InputIt, class Hash, class Allocator>
    unordered_multiset(InputIt, InputIt, typename /* 见描述 */::size_type,
                       Hash, Allocator)
      -> unordered_multiset</*iter-value-type*/<InputIt>, Hash,
                            equal_to</*iter-value-type*/<InputIt>>,
                            Allocator>;

  template<class T, class Allocator>
    unordered_multiset(initializer_list<T>, typename /* 见描述 */::size_type,
                       Allocator)
      -> unordered_multiset<T, hash<T>, equal_to<T>, Allocator>;

  template<class T, class Hash, class Allocator>
    unordered_multiset(initializer_list<T>, typename /* 见描述 */::size_type,
                       Hash, Allocator)
      -> unordered_multiset<T, Hash, equal_to<T>, Allocator>;

  // swap
  template<class Key, class Hash, class Pred, class Alloc>
    void swap(unordered_multiset<Key, Hash, Pred, Alloc>& x,
              unordered_multiset<Key, Hash, Pred, Alloc>& y)
      noexcept(noexcept(x.swap(y)));
}


标准库头文件 <utility>

< cpp‎ | header

此头文件是通用工具库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
<initializer_list>
(C++11)
 std::initializer_list 类模板

命名空间
rel_ops 提供自动的比较运算符
定义于命名空间 std::rel_ops
operator!=operator>operator<=operator>=
(C++20 中弃用)
 自动生成基于用户定义的 operator== 和 operator< 的比较运算符
(函数模板)

函数
swap
 交换两个对象的值
(函数模板)
exchange
(C++14)
 将实参替换为一个新值，并返回其先前值
(函数模板)
forward
(C++11)
 转发一个函数实参
(函数模板)
move
(C++11)
 获得右值引用
(函数模板)
move_if_noexcept
(C++11)
 若移动构造函数不抛出则获得右值引用
(函数模板)
as_const
(C++17)
 获得到其实参的 const 引用
(函数模板)
declval
(C++11)
 获取到其实参的引用，用于不求值语境中
(函数模板)
cmp_equalcmp_not_equalcmp_lesscmp_greatercmp_less_equalcmp_greater_equal
(C++20)
 比较二个整数值，而无转换所致的值更改
(函数模板)
in_range
(C++20)
 检查整数值是否在给定整数类型的范围内
(函数模板)
make_pair
 创建一个 pair 对象，其类型根据各实参类型定义
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按字典序比较 pair 中的值
(函数模板)
std::swap(std::pair)
(C++11)
 特化 std::swap 算法
(函数模板)
std::get(std::pair)
(C++11)
 访问 pair 的一个元素
(函数模板)

类
pair
 实现二元组，即一对值
(类模板)
tuple_size
(C++11)
 获得元组式类型的元素数
(类模板)
tuple_element
(C++11)
 获得元组式类型的元素类型
(类模板)
std::tuple_size<std::pair>
(C++11)
 获得 pair 的大小
(类模板特化)
std::tuple_element<std::pair>
(C++11)
 获得 pair 中元素的类型
(类模板特化)
integer_sequence
(C++14)
 实现编译时整数数列
(类模板)
前置声明
定义于头文件 <tuple>
tuple
(C++11)
 实现固定大小的容器，它保有类型可以相异的元素
(类模板)

辅助项
piecewise_construct_t
(C++11)
 用于为逐段构造选择正确函数重载的标签类型
(类)
piecewise_construct
(C++11)
 用于为逐段构造的函数消歧义的 piecewise_construct_t 类型的对象
(常量)
in_place in_place_type in_place_index in_place_t in_place_type_t in_place_index_t
(C++17)
 原位构造标签
(类模板)

概要

#include <compare>
#include <initializer_list>

namespace std {
  // swap
  template<class T>
    constexpr void swap(T& a, T& b) noexcept(/* 见描述 */);
  template<class T, size_t N>
    constexpr void swap(T (&a)[N], T (&b)[N]) noexcept(is_nothrow_swappable_v<T>);

  // exchange
  template<class T, class U = T>
    constexpr T exchange(T& obj, U&& new_val);

  // forward/move
  template<class T>
    constexpr T&& forward(remove_reference_t<T>& t) noexcept;
  template<class T>
    constexpr T&& forward(remove_reference_t<T>&& t) noexcept;
  template<class T>
    constexpr remove_reference_t<T>&& move(T&&) noexcept;
  template<class T>
    constexpr conditional_t<
        !is_nothrow_move_constructible_v<T> && is_copy_constructible_v<T>, const T&, T&&>
      move_if_noexcept(T& x) noexcept;

  // as_const
  template<class T>
    constexpr add_const_t<T>& as_const(T& t) noexcept;
  template<class T>
    void as_const(const T&&) = delete;

  // declval
  template<class T>
    add_rvalue_reference_t<T> declval() noexcept;   // 作为不求值操作数

  // 整数比较函数
  template<class T, class U>
    constexpr bool cmp_equal(T t, U u) noexcept;
  template<class T, class U>
    constexpr bool cmp_not_equal(T t, U u) noexcept;

  template<class T, class U>
    constexpr bool cmp_less(T t, U u) noexcept;
  template<class T, class U>
    constexpr bool cmp_greater(T t, U u) noexcept;
  template<class T, class U>
    constexpr bool cmp_less_equal(T t, U u) noexcept;
  template<class T, class U>
    constexpr bool cmp_greater_equal(T t, U u) noexcept;

  template<class R, class T>
    constexpr bool in_range(T t) noexcept;

  // 编译时整数数列
  template<class T, T...>
    struct integer_sequence;
  template<size_t... I>
    using index_sequence = integer_sequence<size_t, I...>;

  template<class T, T N>
    using make_integer_sequence = integer_sequence<T, /* 见描述 */>;
  template<size_t N>
    using make_index_sequence = make_integer_sequence<size_t, N>;

  template<class... T>
    using index_sequence_for = make_index_sequence<sizeof...(T)>;

  // 类模板 pair
  template<class T1, class T2>
    struct pair;

  // pair 特化算法
  template<class T1, class T2>
    constexpr bool operator==(const pair<T1, T2>&, const pair<T1, T2>&);
  template<class T1, class T2>
    constexpr common_comparison_category_t</*synth-three-way-result*/<T1>,
                                           /*synth-three-way-result*/<T2>>
      operator<=>(const pair<T1, T2>&, const pair<T1, T2>&);

  template<class T1, class T2>
    constexpr void swap(pair<T1, T2>& x, pair<T1, T2>& y) noexcept(noexcept(x.swap(y)));

  template<class T1, class T2>
    constexpr /* 见描述 */ make_pair(T1&&, T2&&);

  // 对 pair 的仿 tuple 访问
  template<class T> struct tuple_size;
  template<size_t I, class T> struct tuple_element;

  template<class T1, class T2> struct tuple_size<pair<T1, T2>>;
  template<size_t I, class T1, class T2> struct tuple_element<I, pair<T1, T2>>;

  template<size_t I, class T1, class T2>
    constexpr tuple_element_t<I, pair<T1, T2>>& get(pair<T1, T2>&) noexcept;
  template<size_t I, class T1, class T2>
    constexpr tuple_element_t<I, pair<T1, T2>>&& get(pair<T1, T2>&&) noexcept;
  template<size_t I, class T1, class T2>
    constexpr const tuple_element_t<I, pair<T1, T2>>& get(const pair<T1, T2>&) noexcept;
  template<size_t I, class T1, class T2>
    constexpr const tuple_element_t<I, pair<T1, T2>>&& get(const pair<T1, T2>&&) noexcept;
  template<class T1, class T2>
    constexpr T1& get(pair<T1, T2>& p) noexcept;
  template<class T1, class T2>
    constexpr const T1& get(const pair<T1, T2>& p) noexcept;
  template<class T1, class T2>
    constexpr T1&& get(pair<T1, T2>&& p) noexcept;
  template<class T1, class T2>
    constexpr const T1&& get(const pair<T1, T2>&& p) noexcept;
  template<class T2, class T1>
    constexpr T2& get(pair<T1, T2>& p) noexcept;
  template<class T2, class T1>
    constexpr const T2& get(const pair<T1, T2>& p) noexcept;
  template<class T2, class T1>
    constexpr T2&& get(pair<T1, T2>&& p) noexcept;
  template<class T2, class T1>
    constexpr const T2&& get(const pair<T1, T2>&& p) noexcept;

  // pair 逐片构造
  struct piecewise_construct_t {
    explicit piecewise_construct_t() = default;
  };
  inline constexpr piecewise_construct_t piecewise_construct{};
  template<class... Types> class tuple;         // 定义于 <tuple>

  // 原位构造
  struct in_place_t {
    explicit in_place_t() = default;
  };
  inline constexpr in_place_t in_place{};

  template<class T>
    struct in_place_type_t {
      explicit in_place_type_t() = default;
    };
  template<class T> inline constexpr in_place_type_t<T> in_place_type{};

  template<size_t I>
    struct in_place_index_t {
      explicit in_place_index_t() = default;
    };
  template<size_t I> inline constexpr in_place_index_t<I> in_place_index{};
}

// 弃用
namespace std::rel_ops {
  template<class T> bool operator!=(const T&, const T&);
  template<class T> bool operator> (const T&, const T&);
  template<class T> bool operator<=(const T&, const T&);
  template<class T> bool operator>=(const T&, const T&);
}

类模板 std::integer_sequence

namespace std {
  template<class T, T... I> struct integer_sequence {
    using value_type = T;
    static constexpr size_t size() noexcept { return sizeof...(I); }
  };
}

类模板 std::pair

namespace std {
  template<class T1, class T2>
  struct pair {
    using first_type  = T1;
    using second_type = T2;

    T1 first;
    T2 second;

    pair(const pair&) = default;
    pair(pair&&) = default;
    constexpr explicit(/* 见描述 */) pair();
    constexpr explicit(/* 见描述 */) pair(const T1& x, const T2& y);
    template<class U1 = T1, class U2 = T2>
      constexpr explicit(/* 见描述 */) pair(U1&& x, U2&& y);
    template<class U1, class U2>
      constexpr explicit(/* 见描述 */) pair(const pair<U1, U2>& p);
    template<class U1, class U2>
      constexpr explicit(/* 见描述 */) pair(pair<U1, U2>&& p);
    template<class... Args1, class... Args2>
      constexpr pair(piecewise_construct_t,
                     tuple<Args1...> first_args, tuple<Args2...> second_args);

    constexpr pair& operator=(const pair& p);
    template<class U1, class U2>
      constexpr pair& operator=(const pair<U1, U2>& p);
    constexpr pair& operator=(pair&& p) noexcept(/* 见描述 */);
    template<class U1, class U2>
      constexpr pair& operator=(pair<U1, U2>&& p);

    constexpr void swap(pair& p) noexcept(/* 见描述 */);
  };

  template<class T1, class T2>
    pair(T1, T2) -> pair<T1, T2>;
}

参阅

<tuple>
(C++11)
 std::tuple 类模板
工具库


标准库头文件 <valarray>

< cpp‎ | header

此头文件是数值库的一部分。

类
valarray
 数值数组与数组切片
(类模板)
slice
 valarray 的 BLAS 式切片：起始下标、长度、跨度
(类)
slice_array
 到 valarray 应用 slice 后的子集的代理
(类模板)
gslice
 valarray 的通用切片：起始下标、长度集、步幅集
(类)
gslice_array
 valarray 应用 gslice 后的子集的代理
(类模板)
mask_array
 到应用布尔掩码 operator[] 后的 valarray 子集的代理
(类模板)
indirect_array
 到应用间接 operator[] 后的 valarray 子集的代理。
(类模板)

函数
操作
std::swap(std::valarray)
(C++11)
 特化 std::swap() 算法
(函数模板)
std::begin(std::valarray)
(C++11)
 特化的 std::begin
(函数模板)
std::end(std::valarray)
(C++11)
 特化的 std::end
(函数模板)
operator+operator-operator*operator/operator%operator&operator|operator^operator<<operator>>operator&&operator||
 对两个 valarray 的每个元素，或一个 valarray 的每个元素和一个值运用二元运算符
(函数模板)
operator==operator!=operator<operator<=operator>operator>=
 比较两个 valarrays，或比较一个 valarray 和一个值
(函数模板)
abs(std::valarray)
 应用函数 std::abs 到 valarray 的每个元素
(函数模板)
指数函数
exp(std::valarray)
 应用函数 std::exp 到 valarray 的每个元素
(函数模板)
log(std::valarray)
 应用函数 std::log 到 valarray 的每个元素
(函数模板)
log10(std::valarray)
 应用函数 std::log10 到 valarray 的每个元素
(函数模板)
幂函数
pow(std::valarray)
 应用函数 std::pow 到二个 valarray 或一个 valarray 与一个值
(函数模板)
sqrt(std::valarray)
 应用函数 std::sqrt 到 valarray 的每个元素
(函数模板)
三角函数
sin(std::valarray)
 对 valarray 的每个元素应用std::sin函数
(函数模板)
cos(std::valarray)
 应用函数 std::cos 到 valarray 的每个元素
(函数模板)
tan(std::valarray)
 应用函数 std::tan 到 valarray 的每个元素
(函数模板)
asin(std::valarray)
 应用函数 std::asin 到 valarray 的每个元素
(函数模板)
acos(std::valarray)
 应用函数 std::acos 到 valarray 的每个元素
(函数模板)
atan(std::valarray)
 应用函数 std::atan 到 valarray 的每个元素
(函数模板)
atan2(std::valarray)
 应用函数 std::atan2 到一个 valarray 和一个值
(函数模板)
双曲函数
sinh(std::valarray)
 在 valarray 的每个元素上调用 std::sinh 函数
(函数模板)
cosh(std::valarray)
 在 valarray 的每个元素上调用 std::cosh 函数
(函数模板)
tanh(std::valarray)
 在 valarray 的每个元素上调用 std::tanh 函数
(函数模板)

概要

#include <initializer_list>

namespace std {
  template<class T> class valarray;         // T 类型的数组
  class slice;                              // 数组上的 BLAS 式切片
  template<class T> class slice_array;
  class gslice;                             // 数组上的广义切片
  template<class T> class gslice_array;
  template<class T> class mask_array;       // 掩码数组
  template<class T> class indirect_array;   // 间接数组

  template<class T> void swap(valarray<T>&, valarray<T>&) noexcept;

  template<class T> valarray<T> operator* (const valarray<T>&, const valarray<T>&);
  template<class T> valarray<T> operator* (const valarray<T>&,
                                           const typename valarray<T>::value_type&);
  template<class T> valarray<T> operator* (const typename valarray<T>::value_type&,
                                           const valarray<T>&);

  template<class T> valarray<T> operator/ (const valarray<T>&, const valarray<T>&);
  template<class T> valarray<T> operator/ (const valarray<T>&,
                                           const typename valarray<T>::value_type&);
  template<class T> valarray<T> operator/ (const typename valarray<T>::value_type&,
                                           const valarray<T>&);

  template<class T> valarray<T> operator% (const valarray<T>&, const valarray<T>&);
  template<class T> valarray<T> operator% (const valarray<T>&,
                                           const typename valarray<T>::value_type&);
  template<class T> valarray<T> operator% (const typename valarray<T>::value_type&,
                                           const valarray<T>&);

  template<class T> valarray<T> operator+ (const valarray<T>&, const valarray<T>&);
  template<class T> valarray<T> operator+ (const valarray<T>&,
                                           const typename valarray<T>::value_type&);
  template<class T> valarray<T> operator+ (const typename valarray<T>::value_type&,
                                           const valarray<T>&);

  template<class T> valarray<T> operator- (const valarray<T>&, const valarray<T>&);
  template<class T> valarray<T> operator- (const valarray<T>&,
                                           const typename valarray<T>::value_type&);
  template<class T> valarray<T> operator- (const typename valarray<T>::value_type&,
                                           const valarray<T>&);

  template<class T> valarray<T> operator^ (const valarray<T>&, const valarray<T>&);
  template<class T> valarray<T> operator^ (const valarray<T>&,
                                           const typename valarray<T>::value_type&);
  template<class T> valarray<T> operator^ (const typename valarray<T>::value_type&,
                                           const valarray<T>&);

  template<class T> valarray<T> operator& (const valarray<T>&, const valarray<T>&);
  template<class T> valarray<T> operator& (const valarray<T>&,
                                           const typename valarray<T>::value_type&);
  template<class T> valarray<T> operator& (const typename valarray<T>::value_type&,
                                           const valarray<T>&);

  template<class T> valarray<T> operator| (const valarray<T>&, const valarray<T>&);
  template<class T> valarray<T> operator| (const valarray<T>&,
                                           const typename valarray<T>::value_type&);
  template<class T> valarray<T> operator| (const typename valarray<T>::value_type&,
                                           const valarray<T>&);

  template<class T> valarray<T> operator<<(const valarray<T>&, const valarray<T>&);
  template<class T> valarray<T> operator<<(const valarray<T>&,
                                           const typename valarray<T>::value_type&);
  template<class T> valarray<T> operator<<(const typename valarray<T>::value_type&,
                                           const valarray<T>&);

  template<class T> valarray<T> operator>>(const valarray<T>&, const valarray<T>&);
  template<class T> valarray<T> operator>>(const valarray<T>&,
                                           const typename valarray<T>::value_type&);
  template<class T> valarray<T> operator>>(const typename valarray<T>::value_type&,
                                           const valarray<T>&);

  template<class T> valarray<bool> operator&&(const valarray<T>&, const valarray<T>&);
  template<class T> valarray<bool> operator&&(const valarray<T>&,
                                              const typename valarray<T>::value_type&);
  template<class T> valarray<bool> operator&&(const typename valarray<T>::value_type&,
                                              const valarray<T>&);

  template<class T> valarray<bool> operator||(const valarray<T>&, const valarray<T>&);
  template<class T> valarray<bool> operator||(const valarray<T>&,
                                              const typename valarray<T>::value_type&);
  template<class T> valarray<bool> operator||(const typename valarray<T>::value_type&,
                                              const valarray<T>&);

  template<class T> valarray<bool> operator==(const valarray<T>&, const valarray<T>&);
  template<class T> valarray<bool> operator==(const valarray<T>&,
                                              const typename valarray<T>::value_type&);
  template<class T> valarray<bool> operator==(const typename valarray<T>::value_type&,
                                              const valarray<T>&);
  template<class T> valarray<bool> operator!=(const valarray<T>&, const valarray<T>&);
  template<class T> valarray<bool> operator!=(const valarray<T>&,
                                              const typename valarray<T>::value_type&);
  template<class T> valarray<bool> operator!=(const typename valarray<T>::value_type&,
                                              const valarray<T>&);

  template<class T> valarray<bool> operator< (const valarray<T>&, const valarray<T>&);
  template<class T> valarray<bool> operator< (const valarray<T>&,
                                              const typename valarray<T>::value_type&);
  template<class T> valarray<bool> operator< (const typename valarray<T>::value_type&,
                                              const valarray<T>&);
  template<class T> valarray<bool> operator> (const valarray<T>&, const valarray<T>&);
  template<class T> valarray<bool> operator> (const valarray<T>&,
                                              const typename valarray<T>::value_type&);
  template<class T> valarray<bool> operator> (const typename valarray<T>::value_type&,
                                              const valarray<T>&);
  template<class T> valarray<bool> operator<=(const valarray<T>&, const valarray<T>&);
  template<class T> valarray<bool> operator<=(const valarray<T>&,
                                              const typename valarray<T>::value_type&);
  template<class T> valarray<bool> operator<=(const typename valarray<T>::value_type&,
                                              const valarray<T>&);
  template<class T> valarray<bool> operator>=(const valarray<T>&, const valarray<T>&);
  template<class T> valarray<bool> operator>=(const valarray<T>&,
                                              const typename valarray<T>::value_type&);
  template<class T> valarray<bool> operator>=(const typename valarray<T>::value_type&,
                                              const valarray<T>&);

  template<class T> valarray<T> abs  (const valarray<T>&);
  template<class T> valarray<T> acos (const valarray<T>&);
  template<class T> valarray<T> asin (const valarray<T>&);
  template<class T> valarray<T> atan (const valarray<T>&);

  template<class T> valarray<T> atan2(const valarray<T>&, const valarray<T>&);
  template<class T> valarray<T> atan2(const valarray<T>&,
                                      const typename valarray<T>::value_type&);
  template<class T> valarray<T> atan2(const typename valarray<T>::value_type&,
                                      const valarray<T>&);

  template<class T> valarray<T> cos  (const valarray<T>&);
  template<class T> valarray<T> cosh (const valarray<T>&);
  template<class T> valarray<T> exp  (const valarray<T>&);
  template<class T> valarray<T> log  (const valarray<T>&);
  template<class T> valarray<T> log10(const valarray<T>&);

  template<class T> valarray<T> pow(const valarray<T>&, const valarray<T>&);
  template<class T> valarray<T> pow(const valarray<T>&,
                                    const typename valarray<T>::value_type&);
  template<class T> valarray<T> pow(const typename valarray<T>::value_type&,
                                    const valarray<T>&);

  template<class T> valarray<T> sin  (const valarray<T>&);
  template<class T> valarray<T> sinh (const valarray<T>&);
  template<class T> valarray<T> sqrt (const valarray<T>&);
  template<class T> valarray<T> tan  (const valarray<T>&);
  template<class T> valarray<T> tanh (const valarray<T>&);

  template<class T> /* 未指明 1 */ begin(valarray<T>& v);
  template<class T> /* 未指明 2 */ begin(const valarray<T>& v);
  template<class T> /* 未指明 1 */ end(valarray<T>& v);
  template<class T> /* 未指明 2 */ end(const valarray<T>& v);
}

类模板 std::valarray

namespace std {
  template<class T> class valarray {
  public:
    using value_type = T;

    // 构造/析构
    valarray();
    explicit valarray(size_t);
    valarray(const T&, size_t);
    valarray(const T*, size_t);
    valarray(const valarray&);
    valarray(valarray&&) noexcept;
    valarray(const slice_array<T>&);
    valarray(const gslice_array<T>&);
    valarray(const mask_array<T>&);
    valarray(const indirect_array<T>&);
    valarray(initializer_list<T>);
    ~valarray();

    // 赋值
    valarray& operator=(const valarray&);
    valarray& operator=(valarray&&) noexcept;
    valarray& operator=(initializer_list<T>);
    valarray& operator=(const T&);
    valarray& operator=(const slice_array<T>&);
    valarray& operator=(const gslice_array<T>&);
    valarray& operator=(const mask_array<T>&);
    valarray& operator=(const indirect_array<T>&);

    // 元素访问
    const T&          operator[](size_t) const;
    T&                operator[](size_t);

    // 子集操作
    valarray          operator[](slice) const;
    slice_array<T>    operator[](slice);
    valarray          operator[](const gslice&) const;
    gslice_array<T>   operator[](const gslice&);
    valarray          operator[](const valarray<bool>&) const;
    mask_array<T>     operator[](const valarray<bool>&);
    valarray          operator[](const valarray<size_t>&) const;
    indirect_array<T> operator[](const valarray<size_t>&);

    // 一元运算符
    valarray operator+() const;
    valarray operator-() const;
    valarray operator~() const;
    valarray<bool> operator!() const;

    // 复合赋值
    valarray& operator*= (const T&);
    valarray& operator/= (const T&);
    valarray& operator%= (const T&);
    valarray& operator+= (const T&);
    valarray& operator-= (const T&);
    valarray& operator^= (const T&);
    valarray& operator&= (const T&);
    valarray& operator|= (const T&);
    valarray& operator<<=(const T&);
    valarray& operator>>=(const T&);

    valarray& operator*= (const valarray&);
    valarray& operator/= (const valarray&);
    valarray& operator%= (const valarray&);
    valarray& operator+= (const valarray&);
    valarray& operator-= (const valarray&);
    valarray& operator^= (const valarray&);
    valarray& operator|= (const valarray&);
    valarray& operator&= (const valarray&);
    valarray& operator<<=(const valarray&);
    valarray& operator>>=(const valarray&);

    // 成员函数
    void swap(valarray&) noexcept;

    size_t size() const;

    T sum() const;
    T min() const;
    T max() const;

    valarray shift (int) const;
    valarray cshift(int) const;
    valarray apply(T func(T)) const;
    valarray apply(T func(const T&)) const;
    void resize(size_t sz, T c = T());
  };

  template<class T, size_t cnt> valarray(const T(&)[cnt], size_t) -> valarray<T>;
}

类 std::slice

namespace std {
  class slice {
  public:
    slice();
    slice(size_t, size_t, size_t);

    size_t start() const;
    size_t size() const;
    size_t stride() const;

    friend bool operator==(const slice& x, const slice& y);
  };
}

类模板 std::slice_array

namespace std {
  template<class T> class slice_array {
  public:
    using value_type = T;

    void operator=  (const valarray<T>&) const;
    void operator*= (const valarray<T>&) const;
    void operator/= (const valarray<T>&) const;
    void operator%= (const valarray<T>&) const;
    void operator+= (const valarray<T>&) const;
    void operator-= (const valarray<T>&) const;
    void operator^= (const valarray<T>&) const;
    void operator&= (const valarray<T>&) const;
    void operator|= (const valarray<T>&) const;
    void operator<<=(const valarray<T>&) const;
    void operator>>=(const valarray<T>&) const;

    slice_array(const slice_array&);
    ~slice_array();
    const slice_array& operator=(const slice_array&) const;
    void operator=(const T&) const;

    slice_array() = delete;     // 上面声明的复制构造函数所隐含
  };
}

类 std::gslice

namespace std {
  class gslice {
  public:
    gslice();
    gslice(size_t s, const valarray<size_t>& l, const valarray<size_t>& d);

    size_t           start() const;
    valarray<size_t> size() const;
    valarray<size_t> stride() const;
  };
}

类模板 std::gslice_array

namespace std {
  template<class T> class gslice_array {
  public:
    using value_type = T;

    void operator=  (const valarray<T>&) const;
    void operator*= (const valarray<T>&) const;
    void operator/= (const valarray<T>&) const;
    void operator%= (const valarray<T>&) const;
    void operator+= (const valarray<T>&) const;
    void operator-= (const valarray<T>&) const;
    void operator^= (const valarray<T>&) const;
    void operator&= (const valarray<T>&) const;
    void operator|= (const valarray<T>&) const;
    void operator<<=(const valarray<T>&) const;
    void operator>>=(const valarray<T>&) const;

    gslice_array(const gslice_array&);
    ~gslice_array();
    const gslice_array& operator=(const gslice_array&) const;
    void operator=(const T&) const;

    gslice_array() = delete;    // 上面声明的复制构造函数所隐含
  };
}

类模板 std::mask_array

namespace std {
  template<class T> class mask_array {
  public:
    using value_type = T;

    void operator=  (const valarray<T>&) const;
    void operator*= (const valarray<T>&) const;
    void operator/= (const valarray<T>&) const;
    void operator%= (const valarray<T>&) const;
    void operator+= (const valarray<T>&) const;
    void operator-= (const valarray<T>&) const;
    void operator^= (const valarray<T>&) const;
    void operator&= (const valarray<T>&) const;
    void operator|= (const valarray<T>&) const;
    void operator<<=(const valarray<T>&) const;
    void operator>>=(const valarray<T>&) const;

    mask_array(const mask_array&);
    ~mask_array();
    const mask_array& operator=(const mask_array&) const;
    void operator=(const T&) const;

    mask_array() = delete;      // 上面声明的复制构造函数所隐含
  };
}

类模板 std::indirect_array

namespace std {
  template<class T> class indirect_array {
  public:
    using value_type = T;

    void operator=  (const valarray<T>&) const;
    void operator*= (const valarray<T>&) const;
    void operator/= (const valarray<T>&) const;
    void operator%= (const valarray<T>&) const;
    void operator+= (const valarray<T>&) const;
    void operator-= (const valarray<T>&) const;
    void operator^= (const valarray<T>&) const;
    void operator&= (const valarray<T>&) const;
    void operator|= (const valarray<T>&) const;
    void operator<<=(const valarray<T>&) const;
    void operator>>=(const valarray<T>&) const;

    indirect_array(const indirect_array&);
    ~indirect_array();
    const indirect_array& operator=(const indirect_array&) const;
    void operator=(const T&) const;

    indirect_array() = delete;  // 上面声明的复制构造函数所隐含
  };
}


标准库头文件 <variant>

< cpp‎ | header

此头文件是通用工具库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持

类
variant
(C++17)
 类型安全的可辨识联合体
(类模板)
monostate
(C++17)
 用作非可默认构造类型的 variant 的首个可选项的占位符类型
(类)
bad_variant_access
(C++17)
 非法地访问 variant 的值时抛出的异常
(类)
variant_sizevariant_size_v
(C++17)
 在编译时获得 variant 可选项列表的大小
(类模板) (变量模板)
variant_alternativevariant_alternative_t
(C++17)
 在编译时获得以其下标指定的可选项的类型
(类模板) (别名模板)
std::hash<std::variant>
(C++17)
 特化 std::hash 算法
(类模板特化)

常量
variant_npos
(C++17)
 非法状态的 variant 的下标
(常量)

函数
visit
(C++17)
 以一或多个 variant 所保有的各实参调用所提供的函数对象
(函数模板)
holds_alternative
(C++17)
 检查某个 variant 是否当前持有某个给定类型
(函数模板)
std::get(std::variant)
(C++17)
 以给定索引或类型（若类型唯一）读取 variant 的值，错误时抛出异常
(函数模板)
get_if
(C++17)
 以给定索引或类型（若其唯一），获得指向被指向的 variant 的值的指针，错误时返回空指针
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++17)(C++17)(C++17)(C++17)(C++17)(C++17)(C++20)
 以所含值比较 variant 对象
(函数模板)
std::swap(std::variant)
(C++17)
 特化 std::swap 算法
(函数模板)

概要

#include <compare>

namespace std {
  // 类模板 variant
  template<class... Types>
    class variant;

  // variant helper classes
  template<class T> struct variant_size;                        // 不定义
  template<class T> struct variant_size<const T>;
  template<class T>
    inline constexpr size_t variant_size_v = variant_size<T>::value;

  template<class... Types>
    struct variant_size<variant<Types...>>;

  template<size_t I, class T> struct variant_alternative;       // 不定义
  template<size_t I, class T> struct variant_alternative<I, const T>;
  template<size_t I, class T>
    using variant_alternative_t = typename variant_alternative<I, T>::type;

  template<size_t I, class... Types>
    struct variant_alternative<I, variant<Types...>>;

  inline constexpr size_t variant_npos = -1;

  // 值访问
  template<class T, class... Types>
    constexpr bool holds_alternative(const variant<Types...>&) noexcept;

  template<size_t I, class... Types>
    constexpr variant_alternative_t<I, variant<Types...>>& get(variant<Types...>&);
  template<size_t I, class... Types>
    constexpr variant_alternative_t<I, variant<Types...>>&& get(variant<Types...>&&);
  template<size_t I, class... Types>
    constexpr const variant_alternative_t<I, variant<Types...>>&
      get(const variant<Types...>&);
  template<size_t I, class... Types>
    constexpr const variant_alternative_t<I, variant<Types...>>&&
      get(const variant<Types...>&&);

  template<class T, class... Types>
    constexpr T& get(variant<Types...>&);
  template<class T, class... Types>
    constexpr T&& get(variant<Types...>&&);
  template<class T, class... Types>
    constexpr const T& get(const variant<Types...>&);
  template<class T, class... Types>
    constexpr const T&& get(const variant<Types...>&&);

  template<size_t I, class... Types>
    constexpr add_pointer_t<variant_alternative_t<I, variant<Types...>>>
      get_if(variant<Types...>*) noexcept;
  template<size_t I, class... Types>
    constexpr add_pointer_t<const variant_alternative_t<I, variant<Types...>>>
      get_if(const variant<Types...>*) noexcept;

  template<class T, class... Types>
    constexpr add_pointer_t<T>
      get_if(variant<Types...>*) noexcept;
  template<class T, class... Types>
    constexpr add_pointer_t<const T>
      get_if(const variant<Types...>*) noexcept;

  // 关系运算符
  template<class... Types>
    constexpr bool operator==(const variant<Types...>&, const variant<Types...>&);
  template<class... Types>
    constexpr bool operator!=(const variant<Types...>&, const variant<Types...>&);
  template<class... Types>
    constexpr bool operator<(const variant<Types...>&, const variant<Types...>&);
  template<class... Types>
    constexpr bool operator>(const variant<Types...>&, const variant<Types...>&);
  template<class... Types>
    constexpr bool operator<=(const variant<Types...>&, const variant<Types...>&);
  template<class... Types>
    constexpr bool operator>=(const variant<Types...>&, const variant<Types...>&);
  template<class... Types> requires (three_way_comparable<Types> && ...)
    constexpr common_comparison_category_t<compare_three_way_result_t<Types>...>
      operator<=>(const variant<Types...>&, const variant<Types...>&);

  // 观览
  template<class Visitor, class... Variants>
    constexpr /* 见描述 */ visit(Visitor&&, Variants&&...);
  template<class R, class Visitor, class... Variants>
    constexpr R visit(Visitor&&, Variants&&...);

  // 类 monostate
  struct monostate;

  // monostate 关系运算符
  constexpr bool operator==(monostate, monostate) noexcept;
  constexpr strong_ordering operator<=>(monostate, monostate) noexcept;

  // 特化的算法
  template<class... Types>
    constexpr void swap(variant<Types...>&,
                        variant<Types...>&) noexcept(/* 见描述 */);

  // 类 bad_variant_access
  class bad_variant_access;

  // 散列支持
  template<class T> struct hash;
  template<class... Types> struct hash<variant<Types...>>;
  template<> struct hash<monostate>;
}

// 弃用
namespace std {
  template<class T> struct variant_size<volatile T>;
  template<class T> struct variant_size<const volatile T>;

  template<size_t I, class T> struct variant_alternative<I, volatile T>;
  template<size_t I, class T> struct variant_alternative<I, const volatile T>;
}

类模板 std::variant

namespace std {
  template<class... Types>
  class variant {
  public:
    // 构造函数
    constexpr variant() noexcept(/* 见描述 */);
    constexpr variant(const variant&);
    constexpr variant(variant&&) noexcept(/* 见描述 */);

    template<class T>
      constexpr variant(T&&) noexcept(/* 见描述 */);

    template<class T, class... Args>
      constexpr explicit variant(in_place_type_t<T>, Args&&...);
    template<class T, class U, class... Args>
      constexpr explicit variant(in_place_type_t<T>, initializer_list<U>, Args&&...);

    template<size_t I, class... Args>
      constexpr explicit variant(in_place_index_t<I>, Args&&...);
    template<size_t I, class U, class... Args>
      constexpr explicit variant(in_place_index_t<I>, initializer_list<U>, Args&&...);

    // 析构函数
    constexpr ~variant();

    // 赋值
    constexpr variant& operator=(const variant&);
    constexpr variant& operator=(variant&&) noexcept(/* 见描述 */);

    template<class T> constexpr variant& operator=(T&&) noexcept(/* 见描述 */);

    // 修改器
    template<class T, class... Args>
      constexpr T& emplace(Args&&...);
    template<class T, class U, class... Args>
      constexpr T& emplace(initializer_list<U>, Args&&...);
    template<size_t I, class... Args>
      constexpr variant_alternative_t<I, variant<Types...>>& emplace(Args&&...);
    template<size_t I, class U, class... Args>
      constexpr variant_alternative_t<I, variant<Types...>>&
        emplace(initializer_list<U>, Args&&...);

    // 值状态
    constexpr bool valueless_by_exception() const noexcept;
    constexpr size_t index() const noexcept;

    // 交换
    constexpr void swap(variant&) noexcept(/* 见描述 */);
  };
}

类 std::monostate

struct monostate{};

类 std::bad_variant_access

class bad_variant_access : public exception {
public:
  // 特殊成员函数的规范见 [exception]
  const char* what() const noexcept override;
};


标准库头文件 <vector>

< cpp‎ | header

此头文件是容器库的一部分。

包含
<compare>
(C++20)
 三路比较运算符支持
<initializer_list>
(C++11)
 std::initializer_list 类模板

类
vector
 动态的连续数组
(类模板)
vector<bool>
 节省空间的动态 bitset
(类模板特化)
std::hash<std::vector<bool>>
(C++11)
 std::vector <bool> 的散列支持
(类模板特化)
前置声明
定义于头文件 <functional>
hash
(C++11)
 散列函数对象
(类模板)

函数
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 vector 中的值
(函数模板)
std::swap(std::vector)
 特化 std::swap 算法
(函数模板)
erase(std::vector)erase_if(std::vector)
(C++20)
 擦除所有满足特定判别标准的元素
(函数模板)
范围访问
begincbegin
(C++11)(C++14)
 返回指向容器或数组起始的迭代器
(函数模板)
endcend
(C++11)(C++14)
 返回指向容器或数组结尾的迭代器
(函数模板)
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
sizessize
(C++17)(C++20)
 返回容器或数组的大小
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)

概要

#include <compare>
#include <initializer_list>

namespace std {
  // 类模板 vector
  template<class T, class Allocator = allocator<T>> class vector;

  template<class T, class Allocator>
    constexpr bool operator==(const vector<T, Allocator>& x,
                              const vector<T, Allocator>& y);
  template<class T, class Allocator>
    constexpr /*synth-three-way-result*/<T> operator<=>(const vector<T, Allocator>& x,
                                                        const vector<T, Allocator>& y);

  template<class T, class Allocator>
    constexpr void swap(vector<T, Allocator>& x, vector<T, Allocator>& y)
      noexcept(noexcept(x.swap(y)));

  template<class T, class Allocator, class U>
    constexpr typename vector<T, Allocator>::size_type
      erase(vector<T, Allocator>& c, const U& value);
  template<class T, class Allocator, class Predicate>
    constexpr typename vector<T, Allocator>::size_type
      erase_if(vector<T, Allocator>& c, Predicate pred);

  // 类 vector<bool>
  template<class Allocator> class vector<bool, Allocator>;

  // 散列支持
  template<class T> struct hash;
  template<class Allocator> struct hash<vector<bool, Allocator>>;

  namespace pmr {
    template<class T>
      using vector = std::vector<T, polymorphic_allocator<T>>;
  }
}

类模板 std::vector

namespace std {
  template<class T, class Allocator = allocator<T>>
  class vector {
  public:
    // 类型
    using value_type             = T;
    using allocator_type         = Allocator;
    using pointer                = typename allocator_traits<Allocator>::pointer;
    using const_pointer          = typename allocator_traits<Allocator>::const_pointer;
    using reference              = value_type&;
    using const_reference        = const value_type&;
    using size_type              = /* 由实现定义 */;
    using difference_type        = /* 由实现定义 */;
    using iterator               = /* 由实现定义 */;
    using const_iterator         = /* 由实现定义 */;
    using reverse_iterator       = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

    // 构造/复制/销毁
    constexpr vector() noexcept(noexcept(Allocator())) : vector(Allocator()) { }
    constexpr explicit vector(const Allocator&) noexcept;
    constexpr explicit vector(size_type n, const Allocator& = Allocator());
    constexpr vector(size_type n, const T& value, const Allocator& = Allocator());
    template<class InputIt>
      constexpr vector(InputIt first, InputIt last, const Allocator& = Allocator());
    constexpr vector(const vector& x);
    constexpr vector(vector&&) noexcept;
    constexpr vector(const vector&, const Allocator&);
    constexpr vector(vector&&, const Allocator&);
    constexpr vector(initializer_list<T>, const Allocator& = Allocator());
    constexpr ~vector();
    constexpr vector& operator=(const vector& x);
    constexpr vector& operator=(vector&& x)
      noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
               allocator_traits<Allocator>::is_always_equal::value);
    constexpr vector& operator=(initializer_list<T>);
    template<class InputIt>
      constexpr void assign(InputIt first, InputIt last);
    constexpr void assign(size_type n, const T& u);
    constexpr void assign(initializer_list<T>);
    constexpr allocator_type get_allocator() const noexcept;

    // 迭代器
    constexpr iterator               begin() noexcept;
    constexpr const_iterator         begin() const noexcept;
    constexpr iterator               end() noexcept;
    constexpr const_iterator         end() const noexcept;
    constexpr reverse_iterator       rbegin() noexcept;
    constexpr const_reverse_iterator rbegin() const noexcept;
    constexpr reverse_iterator       rend() noexcept;
    constexpr const_reverse_iterator rend() const noexcept;

    constexpr const_iterator         cbegin() const noexcept;
    constexpr const_iterator         cend() const noexcept;
    constexpr const_reverse_iterator crbegin() const noexcept;
    constexpr const_reverse_iterator crend() const noexcept;

    // 容量
    [[nodiscard]] constexpr bool empty() const noexcept;
    constexpr size_type size() const noexcept;
    constexpr size_type max_size() const noexcept;
    constexpr size_type capacity() const noexcept;
    constexpr void      resize(size_type sz);
    constexpr void      resize(size_type sz, const T& c);
    constexpr void      reserve(size_type n);
    constexpr void      shrink_to_fit();

    // 元素访问
    constexpr reference       operator[](size_type n);
    constexpr const_reference operator[](size_type n) const;
    constexpr const_reference at(size_type n) const;
    constexpr reference       at(size_type n);
    constexpr reference       front();
    constexpr const_reference front() const;
    constexpr reference       back();
    constexpr const_reference back() const;

    // 数据访问
    constexpr T*       data() noexcept;
    constexpr const T* data() const noexcept;

    // 修改器
    template<class... Args> constexpr reference emplace_back(Args&&... args);
    constexpr void push_back(const T& x);
    constexpr void push_back(T&& x);
    constexpr void pop_back();

    template<class... Args>
      constexpr iterator emplace(const_iterator position, Args&&... args);
    constexpr iterator insert(const_iterator position, const T& x);
    constexpr iterator insert(const_iterator position, T&& x);
    constexpr iterator insert(const_iterator position, size_type n, const T& x);
    template<class InputIt>
      constexpr iterator insert(const_iterator position,
                                InputIt first, InputIt last);
    constexpr iterator insert(const_iterator position, initializer_list<T> il);
    constexpr iterator erase(const_iterator position);
    constexpr iterator erase(const_iterator first, const_iterator last);
    constexpr void     swap(vector&)
      noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value ||
               allocator_traits<Allocator>::is_always_equal::value);
    constexpr void     clear() noexcept;
  };

  template<class InputIt, class Allocator = allocator</*iter-value-type*/<InputIt>>>
    vector(InputIt, InputIt, Allocator = Allocator())
      -> vector</*iter-value-type*/<InputIt>, Allocator>;

  // 交换
  template<class T, class Allocator>
    constexpr void swap(vector<T, Allocator>& x, vector<T, Allocator>& y)
      noexcept(noexcept(x.swap(y)));
}

类模板 std::vector 对 bool 的特化

namespace std {
  template<class Allocator>
  class vector<bool, Allocator> {
  public:
    // 类型
    using value_type             = bool;
    using allocator_type         = Allocator;
    using pointer                = /* 由实现定义 */;
    using const_pointer          = /* 由实现定义 */;
    using const_reference        = bool;
    using size_type              = /* 由实现定义 */;
    using difference_type        = /* 由实现定义 */;
    using iterator               = /* 由实现定义 */;
    using const_iterator         = /* 由实现定义 */;
    using reverse_iterator       = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

    // 位引用
    class reference {
      friend class vector;
      constexpr reference() noexcept;
    public:
      constexpr reference(const reference&) = default;
      constexpr ~reference();
      constexpr operator bool() const noexcept;
      constexpr reference& operator=(const bool x) noexcept;
      constexpr reference& operator=(const reference& x) noexcept;
      constexpr void flip() noexcept;   // 翻转位
    };

    // 构造/复制/销毁
    constexpr vector() : vector(Allocator()) { }
    constexpr explicit vector(const Allocator&);
    constexpr explicit vector(size_type n, const Allocator& = Allocator());
    constexpr vector(size_type n, const bool& value, const Allocator& = Allocator());
    template<class InputIt>
      constexpr vector(InputIt first, InputIt last, const Allocator& = Allocator());
    constexpr vector(const vector& x);
    constexpr vector(vector&& x);
    constexpr vector(const vector&, const Allocator&);
    constexpr vector(vector&&, const Allocator&);
    constexpr vector(initializer_list<bool>, const Allocator& = Allocator()));
    constexpr ~vector();
    constexpr vector& operator=(const vector& x);
    constexpr vector& operator=(vector&& x);
    constexpr vector& operator=(initializer_list<bool>);
    template<class InputIt>
      constexpr void assign(InputIt first, InputIt last);
    constexpr void assign(size_type n, const bool& t);
    constexpr void assign(initializer_list<bool>);
    constexpr allocator_type get_allocator() const noexcept;

    // 迭代器
    constexpr iterator               begin() noexcept;
    constexpr const_iterator         begin() const noexcept;
    constexpr iterator               end() noexcept;
    constexpr const_iterator         end() const noexcept;
    constexpr reverse_iterator       rbegin() noexcept;
    constexpr const_reverse_iterator rbegin() const noexcept;
    constexpr reverse_iterator       rend() noexcept;
    constexpr const_reverse_iterator rend() const noexcept;

    constexpr const_iterator         cbegin() const noexcept;
    constexpr const_iterator         cend() const noexcept;
    constexpr const_reverse_iterator crbegin() const noexcept;
    constexpr const_reverse_iterator crend() const noexcept;

    // 容量
    [[nodiscard]] constexpr bool empty() const noexcept;
    constexpr size_type size() const noexcept;
    constexpr size_type max_size() const noexcept;
    constexpr size_type capacity() const noexcept;
    constexpr void      resize(size_type sz, bool c = false);
    constexpr void      reserve(size_type n);
    constexpr void      shrink_to_fit();

    // 元素访问
    constexpr reference       operator[](size_type n);
    constexpr const_reference operator[](size_type n) const;
    constexpr const_reference at(size_type n) const;
    constexpr reference       at(size_type n);
    constexpr reference       front();
    constexpr const_reference front() const;
    constexpr reference       back();
    constexpr const_reference back() const;

    // 修改器
    template<class... Args> constexpr reference emplace_back(Args&&... args);
    constexpr void push_back(const bool& x);
    constexpr void pop_back();
    template<class... Args>
      constexpr iterator emplace(const_iterator position, Args&&... args);
    constexpr iterator insert(const_iterator position, const bool& x);
    constexpr iterator insert(const_iterator position, size_type n, const bool& x);
    template<class InputIt>
      constexpr iterator insert(const_iterator position,
                                InputIt first, InputIt last);
    constexpr iterator insert(const_iterator position, initializer_list<bool> il);

    constexpr iterator erase(const_iterator position);
    constexpr iterator erase(const_iterator first, const_iterator last);
    constexpr void swap(vector&);
    constexpr static void swap(reference x, reference y) noexcept;
    constexpr void flip() noexcept;     // 翻转所有位
    constexpr void clear() noexcept;
  };
}


标准库头文件 <version>

< cpp‎ | header

此头文件是语言支持库的一部分。

此头文件提供关于标准库的依赖实现的信息（例如实现特定的库标准宏）。

包含 <version> 亦会定义所有库功能特性测试宏。

注解

C++20 前，有时会为此目的包含 <ciso646>。


索引

< cpp

此工作在进行中，可能存在不准确处。

C++ 标准库中定义的符号列表见 std 符号索引。

拼音： A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

英文： A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

拼音 A

alignas
alignof
<algorithm>
<array> (C++11 起)
ASCII
asm
<atomic> (C++11 起)

拼音 B

变参数（variadic arguments）
表达式（expression）
标识符（identifier）
bool

拼音 C

成员函数（member function）
抽象类（abstract class）
纯右值（prvalue）(C++11 起)
初始化（initialization）

常量（constant）
复制（copy）
花括号（brace，参阅聚合体初始化）
聚合体（aggregate）
列表（list）
零（zero）
默认（default）
引用（reference）
值（value）
直接（direct）

初始化器列表（initializer list）

拼音 D

decltype (C++11)
对象（object）

拼音 E

explicit

拼音 F

泛左值（glvalue）
浮点类型（floating point type）

拼音 G

构造函数（constructor）

复制（copy）
继承（inheriting）(C++11)
默认（default）
委托（delegating）(C++11)
移动（move）(C++11)
转换（converting）

关键词，C++（keyword, C++）

拼音 H

汇编（assembly）

拼音 I

<initializer_list> (C++11 起)
int（参阅整数类型）
<iomanip>
<ios>
<iosfwd>
<iostream>
<iterator>

拼音 J

静态数据成员（static data members）

拼音 L

类（class）
类模板（class template）
类数据成员（class data member）
类型（type）
类型别名（type alias）
联合体（union）

拼音 M

main()
模板（template）
mutable

拼音 N

内存模型（memory model）

拼音 R

容器（container）

拼音 S

SFINAE（Substitution Failure Is Not An Error，替换失败不是错误）
short（参阅整数类型）
short int（参阅整数类型）
属性（attribute）(C++11)
数组（array）
signed（参阅整数类型）
signed int（参阅整数类型）
signed long（参阅整数类型）
signed long int（参阅整数类型）
signed long long（参阅整数类型）
signed long long int（参阅整数类型）
signed short（参阅整数类型）
signed short int（参阅整数类型）
static

拼音 T

this
头文件（header）

<algorithm>
<array> (C++11 起)
<atomic> (C++11 起)
<bitset>
<cassert>
<ccomplex> (C++11 起)
<cctype>
<cerrno>
<cfenv> (C++11 起)
<cfloat>
<chrono>
<cinttypes> (C++11 起)
<ciso646>
<climits>
<clocale>
<cmath>
<codecvt> (C++11 起)
<condition_variable> (C++11 起)
<complex>
<csignal>
<csetjmp>
<cstdalign> (C++11 起)
<cstdarg>
<cstdbool> (C++11 起)
<cstddef>
<cstdint> (C++11 起)
<cstdio>
<ctime>
<ctgmath> (C++11 起)
<cwchar>
<cwctype>
<cuchar>
<exception>
<forward_list> (C++11 起)
<fstream>
<functional>
<future> (C++11 起)
<initializer_list> (C++11 起)
<iomanip>
<ios>
<iosfwd>
<iostream>
<iterator>
<locale>
<limits>
<list>
<map>
<memory>
<mutex> (C++11 起)
<new>
<numeric>
<queue>
<random> (C++11 起)
<ratio> (C++11 起)
<regex> (C++11 起)
<scoped_allocator> (C++11 起)
<set>
<shared_mutex> (C++11 起)
<sstream>
<stack>
<stdexcept>
<streambuf>
<string>
<strstream>
<system_error>
<thread> (C++11 起)
<tuple> (C++11 起)
<typeindex> (C++11 起)
<type_traits> (C++11 起)
<unordered_map> (C++11 起)
<unordered_set> (C++11 起)
<utility>
<valarray>
<vector>

typedef
typeid

拼音 W

亡值（xvalue）
位域（bit field）

拼音 V

void

拼音 Y

用户定义字面量（user-defined literals）(C++11 起)
右值（rvalue）(C++11 前)
原子操作（atomic operation）
预处理器（preprocessor）
运算符（operator）
运算符优先级（operator precedence）

拼音 Z

整数类型（integer type）
值类别（value category）
指针（pointer）
转换、类型（conversion, type）
转型、类型（casting, type；参阅转换、类型）
转型运算符（casting operator，参阅转换、类型）

const_cast
dynamic_cast
reinterpret_cast
static_cast

注释（comment）

C风格（C-style）
C++风格（C++-style）

字符类型（character type）
字节（byte）
作用域（scope）

函数（function）
函数原型（function prototype）
块（block）
类（class）
枚举（enumeration）
命名空间（namespace）
模板参数（template parameter）

左值（lvalue）

A

abstract class（抽象类）
alignas
alignof
<algorithm>
array（数组）
<array> (C++11 起)
ASCII
asm
assembly（汇编）
<atomic> (C++11 起)
atomic operation（原子操作）
attribute（属性）(C++11)

B

bit field（位域）
bool
byte（字节）

C

casting operator（转型运算符，参阅转换、类型）

const_cast
dynamic_cast
reinterpret_cast
static_cast

casting, type（转型、类型，参阅转换、类型）
character type（字符类型）
class（类）
class data member（类数据成员）
class template（类模板）
comment（注释）

C-style（C 风格注释）
C++-style（C++ 风格注释）

constructor（构造函数）

converting（转换构造函数）
copy（复制构造函数）
default（默认构造函数）
delegating（委托构造函数）(C++11)
inheriting（继承构造函数）(C++11)
move（移动构造函数）(C++11)

container（容器）
conversion, type（转换、类型）

D

decltype (C++11)

E

expression（表达式）
explicit

F

floating point type（浮点类型）

G

glvalue（泛左值）

H

header（头文件）

<algorithm>
<array> (C++11 起)
<atomic> (C++11 起)
<bitset>
<cassert>
<ccomplex> (C++11 起)
<cctype>
<cerrno>
<cfenv> (C++11 起)
<cfloat>
<chrono>
<cinttypes> (C++11 起)
<ciso646>
<climits>
<clocale>
<cmath>
<codecvt> (C++11 起)
<condition_variable> (C++11 起)
<complex>
<csignal>
<csetjmp>
<cstdalign> (C++11 起)
<cstdarg>
<cstdbool> (C++11 起)
<cstddef>
<cstdint> (C++11 起)
<cstdio>
<ctime>
<ctgmath> (C++11 起)
<cwchar>
<cwctype>
<cuchar>
<exception>
<forward_list> (C++11 起)
<fstream>
<functional>
<future> (C++11 起)
<initializer_list> (C++11 起)
<iomanip>
<ios>
<iosfwd>
<iostream>
<iterator>
<locale>
<limits>
<list>
<map>
<memory>
<mutex> (C++11 起)
<new>
<numeric>
<queue>
<random> (C++11 起)
<ratio> (C++11 起)
<regex> (C++11 起)
<scoped_allocator> (C++11 起)
<set>
<shared_mutex> (C++11 起)
<sstream>
<stack>
<stdexcept>
<streambuf>
<string>
<strstream>
<system_error>
<thread> (C++11 起)
<tuple> (C++11 起)
<typeindex> (C++11 起)
<type_traits> (C++11 起)
<unordered_map> (C++11 起)
<unordered_set> (C++11 起)
<utility>
<valarray>
<vector>

I

identifier（标识符）
initialization（初始化）

aggregate（聚合体初始化）
brace（花括号初始化，参阅聚合体初始化）
constant（常量初始化）
copy（复制初始化）
default（默认初始化）
direct（直接初始化）
list（列表初始化）
reference（引用初始化）
value（值初始化）
zero（零初始化）

initializer list（初始化器列表）
<initializer_list> (C++11 起)
int（参阅整数类型）
integer type（整数类型）
<iomanip>
<ios>
<iosfwd>
<iostream>
<iterator>

K

keyword, C++（关键词，C++）

L

lvalue（左值）

M

main()
member function（成员函数）
memory model（内存模型）
mutable

O

object（对象）
operator（运算符）
operator precedence（运算符优先级）

P

pointer（指针）
preprocessor（预处理器）
prvalue（纯右值）(C++11 起)

R

rvalue（右值）(C++11 前)

S

scope（作用域）

class（类作用域）
block（块作用域）
enumeration（枚举作用域）
function prototype（函数原型作用域）
function（函数作用域）
namespace（命名空间作用域）
template parameter（模板参数作用域）

SFINAE（Substitution Failure Is Not An Error，替换失败不是错误）
short（参阅整数类型）
short int（参阅整数类型）
signed（参阅整数类型）
signed int（参阅整数类型）
signed long（参阅整数类型）
signed long int（参阅整数类型）
signed long long（参阅整数类型）
signed long long int（参阅整数类型）
signed short（参阅整数类型）
signed short int（参阅整数类型）
static
static data members（静态数据成员）

T

template（模板）
this
type（类型）
type alias（类型别名）
typedef
typeid

U

union（联合体）
user-defined literals（用户定义字面量）(C++11 起)

V

value category（值类别）
variadic_arguments（变参数）
void

X

xvalue（亡值）


输入/输出库

< cpp

C++ 包含两个输入/输出库：现代的、基于流的 I/O 库和 C 风格 I/O 函数的标准集合。

基于流的 I/O

基于流的输入/输出库围绕抽象的输入/输出设备组织。这些抽象设备允许相同代码处理对文件、内存流或随即进行任意操作（例如压缩）的自定义适配器设备的输入/输出。

大多数已经被类模板化，故它们能被适配到任何标准字符类型。为最常用的基本字符类型（ char 和 wchar_t ）提供分离的 typedef 。以下列层次将类组织：

cpp/io/ios base cpp/io/basic ios cpp/io/basic istream cpp/io/basic ifstream cpp/io/basic istringstream cpp/io/basic ostream cpp/io/basic ofstream cpp/io/basic ostringstream cpp/io/basic fstream cpp/io/basic stringstream cpp/io/basic iostream

继承图

抽象
定义于头文件 <ios>
ios_base
 管理格式化标志和输入/输出异常
(类)
basic_ios
 管理任意流缓冲
(类模板)
定义于头文件 <streambuf>
basic_streambuf
 抽象原生设备
(类模板)
定义于头文件 <ostream>
basic_ostream
 包装给定的抽象设备（std::basic_streambuf）
并提供高层输出接口
(类模板)
定义于头文件 <istream>
basic_istream
 包装给定的抽象设备（std::basic_streambuf）
并提供高层输入接口
(类模板)
basic_iostream
 包装给定的抽象设备（std::basic_streambuf）
并提供高层输入/输出接口
(类模板)
文件 I/O 实现
定义于头文件 <fstream>
basic_filebuf
 抽象原生文件设备
(类模板)
basic_ifstream
 实现高层文件流输入操作
(类模板)
basic_ofstream
 实现高层文件流输出操作
(类模板)
basic_fstream
 实现高层文件流输入/输出操作
(类模板)
字符串 I/O 实现
定义于头文件 <sstream>
basic_stringbuf
 实现原生字符串设备
(类模板)
basic_istringstream
 实现高层字符串流输入操作
(类模板)
basic_ostringstream
 实现高层字符串流输出操作
(类模板)
basic_stringstream
 实现高层字符串流输入/输出操作
(类模板)
数组 I/O 实现
定义于头文件 <spanstream>
basic_spanbuf
(C++23)
 实现原始固定字符缓冲区设备
(类模板)
basic_ispanstream
(C++23)
 实现固定字符缓冲区输入操作
(类模板)
basic_ospanstream
(C++23)
 实现固定字符缓冲区输出操作
(类模板)
basic_spanstream
(C++23)
 实现固定字符缓冲区输入/输出操作
(类模板)
定义于头文件 <strstream>
strstreambuf
(C++98 中弃用)
 实现原生字符数组设备
(类)
istrstream
(C++98 中弃用)
 实现字符数组输入操作
(类)
ostrstream
(C++98 中弃用)
 实现字符数组输出操作
(类)
strstream
(C++98 中弃用)
 实现字符数组输入/输出操作
(类)
同步的输出
定义于头文件 <syncstream>
basic_syncbuf
(C++20)
 同步输出设备的包装
(类模板)
basic_osyncstream
(C++20)
 同步输出流的包装
(类模板)

typedef

提供对常用字符类型的下列 typedef ：

typedef basic_ios<char>                ios;
typedef basic_ios<wchar_t>            wios;

typedef basic_streambuf<char>     streambuf;
typedef basic_streambuf<wchar_t> wstreambuf;
typedef basic_filebuf<char>         filebuf;
typedef basic_filebuf<wchar_t>     wfilebuf;
typedef basic_stringbuf<char>     stringbuf;
typedef basic_stringbuf<wchar_t> wstringbuf;
typedef basic_syncbuf<char>         syncbuf; // C++20
typedef basic_syncbuf<wchar_t>     wsyncbuf; // C++20
typedef basic_spanbuf<char>         spanbuf; // C++23
typedef basic_spanbuf<wchar_t>     wspanbuf; // C++23

typedef basic_istream<char>         istream;
typedef basic_istream<wchar_t>     wistream;
typedef basic_ostream<char>         ostream;
typedef basic_ostream<wchar_t>     wostream;
typedef basic_iostream<char>       iostream;
typedef basic_iostream<wchar_t>   wiostream;

typedef basic_ifstream<char>       ifstream;
typedef basic_ifstream<wchar_t>   wifstream;
typedef basic_ofstream<char>       ofstream;
typedef basic_ofstream<wchar_t>   wofstream;
typedef basic_fstream<char>         fstream;
typedef basic_fstream<wchar_t>     wfstream;

typedef basic_istringstream<char>     istringstream;
typedef basic_istringstream<wchar_t> wistringstream;
typedef basic_ostringstream<char>     ostringstream;
typedef basic_ostringstream<wchar_t> wostringstream;
typedef basic_stringstream<char>       stringstream;
typedef basic_stringstream<wchar_t>   wstringstream;

typedef basic_osyncstream<char>     osyncstream; // C++20
typedef basic_osyncstream<wchar_t> wosyncstream; // C++20

typedef basic_ispanstream<char>     ispanstream; // C++23
typedef basic_ispanstream<wchar_t> wispanstream; // C++23
typedef basic_ospanstream<char>     ospanstream; // C++23
typedef basic_ospanstream<wchar_t> wospanstream; // C++23
typedef basic_spanstream<char>       spanstream; // C++23
typedef basic_spanstream<wchar_t>   wspanstream; // C++23

预定义标准流对象

定义于头文件 <iostream>
cinwcin | 从标准 C 输入流 stdin 中读取 (全局对象)
coutwcout | 写入到标准 C 输出流 stdout (全局对象)
cerrwcerr | 写入到标准 C 错误流 stderr， 无缓冲 (全局对象)
clogwclog | 写入到标准 C 错误流 stderr (全局对象)

I/O 操纵符

基于流的 I/O 库用 I/O 操纵符（例如 std::boolalpha 、 std::hex 等）控制流的行为。

类型

定义下列辅助类型：

定义于头文件 <ios>
streamoff | 表示相对的文件/流位置（距 fpos 的偏移），足以表示任何文件大小 (typedef)
streamsize | 表示一次 I/O 操作中转移的字符数或 I/O 缓冲区的大小 (typedef)
fpos | 表示流或文件中的绝对位置 (类模板)

提供下列 std::fpos < std::mbstate_t > 的 typedef 名：

定义于头文件 <iosfwd>
Type | Definition
streampos | std::fpos < std::char_traits <char>::state_type>
wstreampos | std::fpos < std::char_traits <wchar_t>::state_type>
u8streampos (C++20) | std::fpos < std::char_traits <char8_t>::state_type>
u16streampos (C++11) | std::fpos < std::char_traits <char16_t>::state_type>
u32streampos (C++11) | std::fpos < std::char_traits <char32_t>::state_type>

错误类别接口

定义于头文件 <ios>
io_errc (C++11) | IO 流的错误码 (枚举)
iostream_category (C++11) | 鉴别 iostream 错误类别 (函数)

C 风格 I/O

C++ 亦包含 C 所定义的输入/输出函数，如 std::fopen 、 std::getc 等。


std::basic_filebuf

< cpp‎ | io
定义于头文件 <fstream>
template<

class CharT,
class Traits = std::char_traits <CharT>

> class basic_filebuf : public std::basic_streambuf <CharT, Traits>

std::basic_filebuf 是关联字符序列为文件的 std::basic_streambuf 。输入序列和输出序列都关联到同一文件，并为两种操作维护连接文件位置。

函数 underflow() 和 overflow()/sync() 进行文件和缓冲区的获取放置区之间的实际 I/O 。 CharT 不是 char 时，多数实现在文件存储多字节字符，并用 std::codecvt 刻面进行宽/多字节字符转换。

亦为常用字符类型定义二个特化：

定义于头文件 <streambuf>
类型 | 定义
filebuf | basic_filebuf<char>
wfilebuf | basic_filebuf<wchar_t>

成员类型

定义类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | 要求为 std::fpos <Traits::state_type> 的 Traits::pos_type
off_type | Traits::off_type

成员函数

公开成员函数
(构造函数)
 构造 basic_filebuf 对象
(公开成员函数)
operator=
(C++11)
 赋值 basic_filebuf 对象
(公开成员函数)
swap
(C++11)
 交换二个 basic_filebuf 对象
(公开成员函数)
(析构函数)
[虚]
 析构 basic_filebuf 对象并且若打开则关闭文件
(虚公开成员函数)
is_open
 检查关联文件是否打开
(公开成员函数)
open
 打开文件并配置它为关联字符序列
(公开成员函数)
close
 冲入放置区缓冲区并关闭关联的文件
(公开成员函数)

受保护成员函数
showmanyc
[虚]
 可选地提供可用于从文件输入的字符数
(虚受保护成员函数)
underflow
[虚]
 从关联文件读取
(虚受保护成员函数)
uflow
[虚]
 从关联文件读取，并令获取区的下一位置指针前进
(虚受保护成员函数)
pbackfail
[虚]
 回退输出序列以放回字符，不影响关联文件
(虚受保护成员函数)
overflow
[虚]
 从放置区写字符到关联的文件
(虚受保护成员函数)
setbuf
[虚]
 提供用户供应的缓冲区，或将此 filebuf 转变为无缓冲
(虚受保护成员函数)
seekoff
[虚]
 用相对寻址重寻位文件位置
(虚受保护成员函数)
seekpos
[虚]
 用绝对寻址重寻位文件位置
(虚受保护成员函数)
sync
[虚]
 从放置区写字符到关联文件
(虚受保护成员函数)
imbue
[虚]
 更改关联的本地环境
(虚受保护成员函数)

非成员函数

std::swap(std::basic_filebuf)
(C++11)
 特化 std::swap 算法
(函数模板)

继承自 std::basic_streambuf

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(析构函数)
[虚]
 析构 basic_streambuf 对象
(std::basic_streambuf<CharT,Traits> 的虚公开成员函数)
本地环境
pubimbue
 调用 imbue()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
getloc
 获得相关本地环境的副本
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
寻位
pubsetbuf
 调用 setbuf()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubseekoff
 调用 seekoff()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubseekpos
 调用 seekpos()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubsync
 调用 sync()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
获取区
in_avail
 获得获取区中立即可用的字符数
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
snextc
 令输入序列前进，读取一个字符而不再次前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sbumpcstossc
(C++17 中移除)
 从输入序列读取一个字符并令序列前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sgetc
 从输入序列读取一个字符，而不令序列前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sgetn
 调用 xsgetn()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
放置区
sputc
 写一个字符到放置区域，并令 next 指针前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sputn
 调用 xsputn()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
回放
sputbackc
 在输入序列中放回一个字符
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sungetc
 回移一位输出序列中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的公开成员函数)

受保护成员函数

(构造函数)
 构造 basic_streambuf 对象
(受保护成员函数)
operator=
(C++11)
 替换 basic_streambuf 对象
(受保护成员函数)
swap
(C++11)
 交换二个 basic_streambuf 对象
(受保护成员函数)
本地环境
imbue
[虚]
 更改关联的本地环境
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
寻位
setbuf
[虚]
 若容许则以用户定义数组替换缓冲区
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
seekoff
[虚]
 用相对寻址重定位输入序列、输出序列或两者中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
seekpos
[虚]
 用绝对寻址重定位输入序列、输出序列或两者中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
sync
[虚]
 将缓冲与关联的字符序列同步
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
获取区
showmanyc
[虚]
 若已知，则获得关联输入序列中可用于输入的字符数
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
underflow
[虚]
 从关联输入序列读取字符到获取区
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
uflow
[虚]
 从输入序列读取字符到获取区，并令下一位置指针前进
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
xsgetn
[虚]
 从输入序列读取多个字符
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
ebackgptregptr
 返回指向获取区起始、当前字符和末尾的指针
(受保护成员函数)
gbump
 令输出序列中的下一位置指针前进
(受保护成员函数)
setg
 重定位输出序列的起始、下一位置和终止指针
(受保护成员函数)
放置区
xsputn
[虚]
 将多个字符写到输出序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
overflow
[虚]
 从放置区写入字符到关联的输出序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
pbasepptrepptr
 返回指向放置区的起始、当前字符和末尾的指针
(受保护成员函数)
pbump
 令输出序列中的下一位置指针前进
(受保护成员函数)
setp
 重定位输出序列的起始、下一位置和终止指针
(受保护成员函数)
回放
pbackfail
[虚]
 将字符放回输入序列，可能修改输入序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)

参阅

FILE
 对象类型，足以保有控制 C I/O 流所需的全部信息
(typedef)


std::basic_filebuf<CharT,Traits>::basic_filebuf

< cpp‎ | io‎ | basic filebuf
basic_filebuf(); | (1) |
basic_filebuf( const std::basic_filebuf & rhs ) = delete; | (2) | (C++11 起)
basic_filebuf( std::basic_filebuf && rhs ); | (3) | (C++11 起)

构造新的 std::basic_filebuf 对象。

1) 构造 std::basic_filebuf 对象，以调用 std::basic_streambuf 的默认构造函数初始化基类。创建的 basic_filebuf 不与文件关联，而 is_open() 返回 false 。
2) 复制构造函数被删除； std::basic_filebuf 非可复制构造 (CopyConstructible) 。
3) 通过从另一 std::basic_filebuf 对象 rhs 移动所有内容，包含缓冲区、关联的文件、 locale 、打开模式、 is_open 变量和所有其他状态移动构造 std::basic_filebuf 对象。移动后， rhs 不与文件关联且 rhs.is_open()==false 。保证 rhs 的基类和 *this 的基类 std::basic_streambuf 的成员指针指向不同缓冲区，除非它们为空。

参数

rhs - 另一 basic_filebuf

注意

典型地为 std::basic_fstream 的构造函数所调用。

示例

本节未完成
原因：暂无示例

参阅

operator= (C++11) | 赋值 basic_filebuf 对象 (公开成员函数)
(析构函数) [虚] | 析构 basic_filebuf 对象并且若打开则关闭文件 (虚公开成员函数)


std::basic_filebuf<CharT,Traits>::close

< cpp‎ | io‎ | basic filebuf
std::basic_filebuf <CharT, Traits>* close();

若放置区存在（即为写入打开文件），则首先调用 overflow(Traits::eof()) 写入所有未决输出到文件，包含任何反迁移序列。

若在 underflow() 、 overflow() 、 seekpos() 和 seekoff() 之中最近调用的函数是 overflow() ，则可能多次调用 std::codecvt::unshift() 以确定按照感染的本地环境的反迁移序列，并将该序列以 overflow(Traits::eof()) 写入文件。

然后，如同用 std::fclose() 关闭文件，不考虑任何之前调用成功或失败。

若作出的任何函数调用，包含对 std::fclose() 的调用失败，则返回空指针。若作出的任何函数调用抛出异常，则捕捉该异常并在调用 std::fclose() 后重抛。若该文件已关闭，则立即返回空指针。

任何情况下，都更新 is_open() 所访问的私有成员变量。

参数

（无）

返回值

成功时为 this ，失败时为空指针。

注意

close() 典型地通过 std::basic_filebuf 的析构函数调用（继而典型地为 std::basic_fstream 的析构函数所调用）。

示例

本节未完成
原因：暂无示例

参阅

is_open | 检查关联文件是否打开 (公开成员函数)
(析构函数) [虚] | 析构 basic_filebuf 对象并且若打开则关闭文件 (虚公开成员函数)


std::basic_filebuf<CharT,Traits>::imbue

< cpp‎ | io‎ | basic filebuf
protected:
virtual void imbue( const std::locale & loc )

更改关联的本地环境，使得此调用后（和另一 imbue() 调用前）所有插入或释出的字符以 loc 的 std::codecvt 平面转换。

若旧 locale 的编码依赖状态，且文件未被寻位到起始，则新的 locale 必须与先前感染者拥有相同的 std::codecvt 平面。

参数

loc - 要与流感染的 locale

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

imbue [虚] | 更改关联的本地环境 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
imbue | 设置本地环境 (std::basic_ios<CharT,Traits> 的公开成员函数)


std::basic_filebuf<CharT,Traits>::is_open

< cpp‎ | io‎ | basic filebuf
bool is_open() const;

若最近到 open() 的调用成功且之后无到 close() 的调用则返回 true 。

参数

（无）

返回值

若关联文件打开则为 true ，否则为 false 。

注意

此函数典型地为 std::basic_fstream::is_open() 所调用。

示例

#include <fstream>
#include <iostream>

int main()
{
    std::ifstream fs("test.txt");
    std::filebuf fb;
    fb.open("test.txt", std::ios_base::in);
    std::cout << std::boolalpha
              << "direct call: " << fb.is_open() << '\n'
              << "through streambuf: " << fs.rdbuf()->is_open() << '\n'
              << "through fstream: " << fs.is_open() << '\n';
}

输出：

direct call: true
through streambuf: true
through fstream: true

参阅

open | 打开文件并配置它为关联字符序列 (公开成员函数)
close | 冲入放置区缓冲区并关闭关联的文件 (公开成员函数)


std::basic_filebuf<CharT,Traits>::open

< cpp‎ | io‎ | basic filebuf
std::basic_filebuf <CharT, Traits>* open( const char* s,
std::ios_base::openmode mode )
 (1)
std::basic_filebuf <CharT, Traits>* open( const std::string & str,
std::ios_base::openmode mode )
 (2) (C++11 起)
std::basic_filebuf <CharT, Traits>* open( const std::filesystem::path & p,
std::ios_base::openmode mode )
 (3) (C++17 起)
std::basic_filebuf <CharT, Traits>* open( const std::filesystem::path::value_type* s,
std::ios_base::openmode mode )
 (4) (C++17 起)

打开拥有给定名称（ s 、 p.c_str() (C++17 起) 或 str.c_str() ，取决于重载）的文件。

仅若 std::filesystem::path::value_type 非 char 才提供重载 (4) 。

 (C++17 起)

如同通过以按下列方式确定的第二参数 (mode) 调用 std::fopen 打开文件：

mode | openmode & ~ate | 若文件已存在的动作 | 若文件不存在的动作
"r" | in | 从头读取 | 打开失败
"w" | out, out|trunc | 销毁内容 | 创建新文件
"a" | app, out|app | 后附到文件 | 创建新文件
"r+" | out|in | 从头读取 | 错误
"w+" | out|in|trunc | 销毁内容 | 创建新文件
"a+" | out|in|app, in|app | 写入到结尾 | 创建新文件
"rb" | binary|in | 从头读取 | 打开失败
"wb" | binary|out, binary|out|trunc | 销毁内容 | 创建新文件
"ab" | binary|app, binary|out|app | 写入结尾 | 创建新文件
"r+b" | binary|out|in | 从头读取 | 错误
"w+b" | binary|out|in|trunc | 销毁内容 | 创建新文件
"a+b" | binary|out|in|app, binary|in|app | 写入到结尾 | 创建新文件

若 openmode 不是列出的模式之一，则 open() 失败。

若打开操作成功且 openmode & std::ios_base::ate != 0 （设置了 ate 位），则重寻位文件位置到文件尾，如同用调用 std::fseek (file, 0, SEEK_END ) ，其中 file 是调用 fopen 返回的指针。若寻位失败，则调用 close() 并返回空指针以指示失败。

若关联文件已打开，则立即返回空指针。

参数

s, str, p | - | 要打开的文件名； s 必须指向空终止字符串
openmode | - | 文件打开模式， std::ios_base 模式的二进制或

返回值

成功时为 this ，失败时为空指针。

注意

常由 std::basic_fstream 的构造函数或 open() 成员函数调用 open() 。

示例

本节未完成
原因：暂无示例

参阅

is_open | 检查关联文件是否打开 (公开成员函数)
close | 冲入放置区缓冲区并关闭关联的文件 (公开成员函数)


std::basic_filebuf<CharT,Traits>::operator=

< cpp‎ | io‎ | basic filebuf
std::basic_filebuf & operator=( std::basic_filebuf && rhs ); | (C++11 起)
std::basic_filebuf & operator=( const std::basic_filebuf & rhs ) = delete; |

赋值另一 basic_filebuf 对象。

1) 首先调用 close() 关闭关联文件，然后移动 rhs 的内容到 *this 中：获取与放置缓冲区、本地环境、打开模式、打开标志及任何其他状态。移动后， rhs 不与文件关联且 rhs.is_open() == false 。
2) 复制赋值运算符被删除； basic_filebuf 不可复制赋值 (CopyAssignable) 。

参数

rhs - 将被移动的另一 basic_filebuf

返回值

*this

示例

#include <fstream>
#include <string>
#include <iostream>

int main()
{

    std::ifstream fin("test.in"); // 只读
    std::ofstream fout("test.out"); // 只写

    std::string s;
    getline(fin, s);
    std::cout << s << '\n'; // 输出

    *fin.rdbuf() = std::move(*fout.rdbuf());

    getline(fin, s);
    std::cout << s << '\n'; // 空行

    std::cout << std::boolalpha << fout.is_open() << '\n'; // 打印 "false"

}

参阅

(构造函数) | 构造 basic_filebuf 对象 (公开成员函数)
swap (C++11) | 交换二个 basic_filebuf 对象 (公开成员函数)


std::basic_filebuf<CharT,Traits>::overflow

< cpp‎ | io‎ | basic filebuf
protected:
virtual int_type overflow ( int_type c = Traits::eof() );

从放置区写一些数据到关联字符序列（到文件）。

表现类似基类的 std::basic_streambuf::overflow ，除了要写入数据。首先用感染的 locale 的 std::codecvt::out 转换字符为外部（可能为多字节）表示，并存储于临时缓冲区中（分配所需大小），然后用文件 I/O 复制所有完全转换的字节到文件。

若 std::codecvt::always_noconv 为 true ，则可以跳过对 std::codecvt::out 的调用。

若转换因 std::codecvt_base::error 失败，则返回 Traits::eof() 而不尝试任何输出。

若未打开关联文件（ is_open() == false ），则在做任何事前返回 Traits::eof() 。

参数

（无）

返回值

指示成功的 Traits::not_eof(c) 或指示失败的 Traits::eof() 。

示例

本节未完成
原因：暂无示例

参阅

overflow [虚] | 从放置区写入字符到关联的输出序列 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
underflow [虚] | 从关联文件读取 (虚受保护成员函数)


std::basic_filebuf<CharT,Traits>::pbackfail

< cpp‎ | io‎ | basic filebuf
protected:
virtual int_type pbackfail( int_type c = Traits::eof() )

此受保护虚函数为公开函数 basic_streambuf::sungetc 和 basic_streambuf::sputbackc 所调用（继而为 basic_istream::unget 和 basic_istream::putback 所调用）。

1) 调用方请求将获取区后备一个字符（以无参数调用 pbackfail() ），该情况下，此函数于前一字节位置开始重读文件，并自减 basic_streambuf::gptr() ，例如通过调用 gbump(-1) 。
2) 调用方试图回放异于之前取得的字符（以需要放回的字符调用 pbackfail() ），该情况下
a) 首先检查是否有回放位置，若无则通过于前一字节位置开始重读文件，后备获取区。
a) 然后检查什么字符在回放位置。若其处保有的字符已等于 c ，以 Traits::eq(to_char_type(c), gptr()[-1]) 确定，则简单地自减 basic_streambuf::gptr() 。
b) 否则，若允许缓冲修改其自身的获取区，则自减 basic_streambuf::gptr() 并写入 c 到调整后的 gptr() 所指向的位置。

此函数决不修改文件，仅修改内存中缓冲区的获取区。

若文件未打开（ is_open()==false ），则此函数立即返回 Traits::eof() 。

参数

c - 要放回的字符，或为指示请求后备缓冲区的 Traits::eof()

返回值

成功时为 c ，除非 c 为 Traits::eof() ，该情况下返回 Traits::not_eof(c) 。

失败时为 Traits::eof() 。

示例

本节未完成
原因：暂无示例

参阅

pbackfail [虚] | 将字符放回输入序列，可能修改输入序列 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
sungetc | 回移一位输出序列中的下一位置指针 (std::basic_streambuf<CharT,Traits> 的公开成员函数)
sputbackc | 在输入序列中放回一个字符 (std::basic_streambuf<CharT,Traits> 的公开成员函数)
unget | 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符 (std::basic_istream<CharT,Traits> 的公开成员函数)
putback | 往输入流中退回一个字符 (std::basic_istream<CharT,Traits> 的公开成员函数)


std::basic_filebuf<CharT,Traits>::seekoff

< cpp‎ | io‎ | basic filebuf
protected:

virtual pos_type seekoff( off_type off,
std::ios_base::seekdir dir,

std::ios_base::openmode which = std::ios_base::in | std::ios_base::out );

若可能，则重寻位文件指针到距文件起始、结尾或当前位置准确 off 个字符的位置（取决于 dir 的值）。

若关联文件未打开（ is_open()==false ），则立即失败。

若多字节字符编码依赖状态（ codecvt::encoding() 返回 -1 ）或为变长（ codecvt::encoding() 返回 ​0​ ），而偏移 off 非 ​0​ ，则立即失败：此函数无法确定对应 off 个字符的字节数。

若 dir 不是 std::basic_ios::cur 或偏移 off 非 ​0​ ，且此 filebuf 对象上最近做的操作是输出（即放置缓冲区非空，或最近调用的函数是 overflow() ），则调用 std::codecvt::unshift 确定需要的反迁移序列，并通过调用 overflow() 写入该序列到文件。

然后转换参数 dir 为 int 类型值 whence 如下：

dir 的值 | whence 的值
std::basic_ios::beg | SEEK_SET
std::basic_ios::end | SEEK_END
std::basic_ios::cur | SEEK_CUR

然后，若字符编码为定宽（ codecvt::encoding() 返回某个正值 width ），则如同用 std::fseek (file, width*off, whence) 移动文件指针。

否则，如同用 std::fseek (file, 0, whence) 移动文件指针。

基类函数签名所要求的 openmode 参数通常被忽略，因为 std::basic_filebuf 只维护一个文件位置。

参数

off - 要设置位置指示器到的相对位置。
dir - 定义要应用相对偏移到的基位置。它能为下列常量之一：
常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置
which - 定义要影响输入和/或输出序列的哪一个。它能为下列常量之一或其组合：
常量 | 解释
in | 影响输入序列
out | 影响输出序列

返回值

新构造的 pos_type 类型对象，存储结果文件位置，或在失败时为 pos_type(off_type(-1)) 。

注意

seekoff() 为 std::basic_streambuf::pubseekoff 所调用，它又为 std::basic_istream::seekg 、 std::basic_ostream::seekp 、 std::basic_istream::tellg 和 std::basic_ostream::tellp 所调用。

示例

#include <iostream>
#include <fstream>
#include <locale>
int main()
{
    // 准备 10 字节文件，保有 4 个 UTF8 中的字符
    std::ofstream("text.txt") << u8"z\u00df\u6c34\U0001d10b"; // 或 u8"zß水𝄋"
                                           // 或 "\x7a\xc3\x9f\xe6\xb0\xb4\xf0\x9d\x84\x8b";

    // 用非转换编码打开
    std::ifstream f1("text.txt");
    std::cout << "f1's locale's encoding() returns "
              << std::use_facet<std::codecvt<char, char, std::mbstate_t>>(f1.getloc()).encoding() << '\n'
              << "pubseekoff(3, beg) returns " << f1.rdbuf()->pubseekoff(3, std::ios_base::beg) << '\n'
              << "pubseekoff(0, end) returns " << f1.rdbuf()->pubseekoff(0, std::ios_base::end) << '\n';;

    // 用 UTF-8 打开
    std::wifstream f2("text.txt");
    f2.imbue(std::locale("en_US.UTF-8"));
    std::cout << "f2's locale's encoding() returns "
              << std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(f2.getloc()).encoding() << '\n'
              << "pubseekoff(3, beg) returns " << f2.rdbuf()->pubseekoff(3, std::ios_base::beg) << '\n'
              << "pubseekoff(0, end) returns " << f2.rdbuf()->pubseekoff(0, std::ios_base::end) << '\n';

}

输出：

f1's locale's encoding() returns 1
pubseekoff(3, beg) returns 3
pubseekoff(0, end) returns 10
f2's locale's encoding() returns 0
pubseekoff(3, beg) returns -1
pubseekoff(0, end) returns 10

参阅

pubseekoff
 调用 seekoff()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
seekpos
[虚]
 用绝对寻址重寻位文件位置
(虚受保护成员函数)
fseek
 移动文件位置指示器到文件中的指定位置
(函数)


std::basic_filebuf<CharT,Traits>::seekpos

< cpp‎ | io‎ | basic filebuf
protected:

virtual pos_type seekpos( pos_type sp,

std::ios_base::openmode which = std::ios_base::in | std::ios_base::out );

若可能，则重寻位文件指针到 sp 所指示的位置。

若关联文件未打开（ is_open()==false ），则立即失败。

若文件为写入打开，则首先用 overflow() 写入放置区和任何当前感染的 locale 所要求的反迁移序列。

然后如同通过调用 std::fsetpos() 重寻位指针。

若文件为读取打开，则若需要则更新获取区。

若 sp 不是由在同一文件上调用 seekoff() 或 seekpos() 获得，则行为未定义。

参数

sp - 之前在同一文件上调用 seekoff() 或 seekpos() 获得的文件位置
which - 确定要影响输入和/或输出序列的哪个。它能为下列常量之一或其组合：
常量 | 解释
in | 影响输入序列
out | 影响输出序列

返回值

成功时为 sp ，失败时为 pos_type(off_type(-1)) 。

注意

seekpos() 为 std::basic_streambuf::pubseekpos() 所调用，后者为 std::basic_istream::seekg() 和 std::basic_ostream::seekp() 的单参数版本调用。

许多实现不于 seekpos() 中更新获取区，而是委托给下次 sgetc() 所调用的 underflow() 。

示例

一些实现上， seekpos() 清空获取区并需要第二个 underflow() 以观测效果

#include <fstream>
#include <iostream>

struct mybuf : std::filebuf
{
    pos_type seekpos(pos_type sp, std::ios_base::openmode which) {
         std::cout << "Before seekpos(" << sp << "), size of the get area is "
                   << egptr()-eback() << " with "
                   << egptr()-gptr() << " read positions available\n";
         pos_type rc = std::filebuf::seekpos(sp, which);
         std::cout << "seekpos() returns " << rc << ".\nAfter the call, "
                   << "size of the get area is "
                   << egptr()-eback() << " with "
                   << egptr()-gptr() << " read positions available\n";
// 若 seekpos() 清空获取区则反注释
//         std::filebuf::underflow();
//         std::cout << "after forced underflow(), size of the get area is "
//                   << egptr()-eback() << " with "
//                   << egptr()-gptr() << " read positions available\n";
        return rc;
    }
};

int main()
{
    mybuf buf;
    buf.open("test.txt", std::ios_base::in);
    std::istream stream(&buf);
    stream.get(); // 读一个字符以强制 underflow()
    stream.seekg(2);
}

可能的输出：

Before seekpos(2), size of the get area is 110 with 109 read positions available
seekpos() returns 2.
After the call, size of the get area is 110 with 108 read positions available

参阅

pubseekpos
 调用 seekpos()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
seekoff
[虚]
 用相对寻址重寻位文件位置
(虚受保护成员函数)
fseek
 移动文件位置指示器到文件中的指定位置
(函数)


std::basic_filebuf<CharT,Traits>::setbuf

< cpp‎ | io‎ | basic filebuf
protected:
virtual std::basic_streambuf <CharT, Traits>* setbuf( char_type* s, std::streamsize n )

若 s 为空指针且 n 为零，则 filebuf 变为对输出无缓冲，这表示 pbase() 和 pptr() 为空，而任何输出都被立即发送到文件。

否则，如同调用 setbuf() ，以用户提供的首元素为s 所指向的字符数组替换内部缓冲区（受控制字符序列），并允许此 std::basic_filebuf 将该数组中的至多 n 个字节用于缓冲。

此函数为受保护虚，它仅可通过 pubsetbuf() 或从导出自 std::basic_filebuf 的用户定义类调用。

参数

s | - | 指向用户提供缓冲区的首个 CharT 的指针或空指针
n | - | 用户提供缓冲区中的 CharT 元素数或零

返回值

this 。

注意

可以使用此函数时的条件，和使用提供的缓冲区的方式是实现定义的。

  • GCC 4.6 libstdc++
setbuf() 仅可在 std::basic_filebuf 未与文件关联时调用（否则无效果）。拥有用户提供的缓冲区时，每次从文件读取 n-1 字节。
  • Clang++3.0 libc++
setbuf() 可在打开文件后，但要在任何 I/O 前调用（否则可能崩溃）。拥有用户提供缓冲区时，从文件读取适合缓冲区的 4096 最大倍数字节。
  • Visual Studio 2010
setbuf() 可在任何时候调用，即使在某个 I/O 发生后。缓冲区的当前内容若存在则丢失。

标准不定义此函数的任何行为，除了要求在任何 I/O 发生前调用的 setbuf(0, 0) 设置输出为无缓冲。

示例

为读取提供 10k 缓冲区。 Linux 上，可用 strace 工具观察实际读取的字节数

#include <fstream>
#include <iostream>
#include <string>

int main()
{
        int cnt = 0;
        std::ifstream file;
        char buf[10241];

        file.rdbuf()->pubsetbuf(buf, sizeof buf);
        file.open("/usr/share/dict/words");

        for (std::string line; getline(file, line); )
                ++cnt;
        std::cout << cnt << '\n';
}

参阅

pubsetbuf
 调用 setbuf()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
setvbuf
 为文件流设置缓冲区与其大小
(函数)


std::basic_filebuf<CharT,Traits>::showmanyc

< cpp‎ | io‎ | basic filebuf
protected:
virtual std::streamsize showmanyc()

若实现，则返回从文件留待读取的字符数。

参数

（无）

返回值

可从文件读取的字符数，或若抵达文件尾则为 -1 。

注意

此函数为可选。若不实现，则此函数返回 ​0​ （因为基类版本 std::basic_streambuf::showmanyc 得到调用）。

无论是否实现，若获取区为空，则此函数为 std::basic_streambuf::in_avail 所正常调用。

此函数的名称表示“流：多少字符？”，故它读作“ S how many C ”，而不是“ show many C ”。

示例

查看是否为 filebuf 实现 showmanyc() 的实现测试

#include <fstream>
#include <iostream>

struct mybuf : std::filebuf
{
     using std::filebuf::showmanyc;
};

int main()
{
    mybuf fin;
    fin.open("main.cpp", std::ios_base::in);
    std::cout << "showmanyc() returns " << fin.showmanyc() << '\n';
}

可能的输出：

showmanyc() returns 267

参阅

in_avail | 获得获取区中立即可用的字符数 (std::basic_streambuf<CharT,Traits> 的公开成员函数)
readsome | 读并取走已经可用的字符块 (std::basic_istream<CharT,Traits> 的公开成员函数)


std::basic_filebuf<CharT,Traits>::swap

< cpp‎ | io‎ | basic filebuf
void swap( std::basic_filebuf & rhs ); | (C++11 起)

交换 *this 与 rhs 的状态和内容。

参数

rhs - 另一 basic_filebuf

返回值

（无）

注意

在交换 std::fstream 对象时自动调用此函数，很少需要直接调用它。

示例

#include <fstream>
#include <string>
#include <iostream>

int main()
{
    std::ifstream fin("test.in"); // 只读
    std::ofstream fout("test.out"); // 只写

    std::string s;
    getline(fin, s);
    std::cout << s << '\n'; // 输出 test.in 的第一行

    fin.rdbuf()->swap(*fout.rdbuf()); // 交换底层缓冲

    getline(fin, s); // 失败：不能从只写 filebuf 读取
    std::cout << s << '\n'; // 打印空行
}

参阅

operator= (C++11) | 赋值 basic_filebuf 对象 (公开成员函数)
std::swap(std::basic_filebuf) (C++11) | 特化 std::swap 算法 (函数模板)
swap (C++11) | 交换二个文件流 (std::basic_fstream<CharT,Traits> 的公开成员函数)


std::swap(std::basic_filebuf)

< cpp‎ | io‎ | basic filebuf
template< class CharT, class Traits >

void swap( std::basic_filebuf <CharT,Traits>& lhs,

std::basic_filebuf <CharT,Traits>& rhs );
 (C++11 起)

为 std::basic_filebuf 特化 std::swap 算法。交换 lhs 与 rhs 的内部状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的 std::basic_filebuf 对象

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

swap (C++11) | 交换二个 basic_filebuf 对象 (公开成员函数)
swap | 交换两个对象的值 (函数模板)


std::basic_filebuf<CharT,Traits>::sync

< cpp‎ | io‎ | basic filebuf
protected:
virtual int sync()

若放置区存在（例如文件为写入打开），则调用 overflow() 写入所有未处理输出到文件，然后如同以调用 std::fflush 冲入文件。

若获取区存在（例如文件为读取打开），则效果是实现定义的。典型实现可能清空获取区，并将当前文件位置后移对应的字节数。

参数

（无）

返回值

成功情况下为 ​0​ ，失败情况下为 -1 。

注意

对于输出流， close() 、 seekoff() 和 seekpos() 隐式调用，而 std::basic_streambuf::pubsync() 显式调用 sync() 或其等价内容。

示例

本节未完成
原因：暂无示例

参阅

pubsync
 调用 sync()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
fflush
 将输出流与实际文件同步
(函数)


std::basic_filebuf<CharT,Traits>::uflow

< cpp‎ | io‎ | basic filebuf
protected:
virtual int_type uflow()

表现类似 underflow() ，除了若 underflow() 成功（不返回 Traits::eof() ），则令获取区的下一位置指针前进。换言之，消耗一个 underflow() 所获得的字符。

参数

（无）

返回值

成功情况下为读取并消耗的字符值，失败情况下为 Traits::eof() 。

示例

本节未完成
原因：暂无示例

参阅

uflow [虚] | 从输入序列读取字符到获取区，并令下一位置指针前进 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
underflow [虚] | 从关联文件读取 (虚受保护成员函数)
overflow [虚] | 从放置区写字符到关联的文件 (虚受保护成员函数)


std::basic_filebuf<CharT,Traits>::underflow

< cpp‎ | io‎ | basic filebuf
protected:
virtual int_type underflow()

读取更多数据到输入区中。

表现类似基类 std::basic_streambuf::underflow ，除了要从关联字符序列（文件）读取数据到获取区中。首先从文件读取字符到临时缓冲区（分配所需大小），然后用感染的 locale 的 std::codecvt::in 转换外部（典型为多字节）表示为之后用于填充获取区的内部形式。若该 locale 的 std::codecvt::always_noconv 返回 true 则可以跳过转换。

参数

（无）

返回值

成功情况下为 Traits::to_int_type(*gptr()) （待处理序列的首字符），失败情况下为 Traits::eof() 。

示例

#include <fstream>
#include <iostream>

struct mybuf : std::filebuf
{
    int underflow() {
         std::cout << "Before underflow(): size of the get area is "
                   << egptr()-eback() << " with "
                   << egptr()-gptr() << " read positions available\n";
         int rc = std::filebuf::underflow();
         std::cout << "underflow() returns " << rc << ".\nAfter the call, "
                   << "size of the get area is "
                   << egptr()-eback() << " with "
                   << egptr()-gptr() << " read positions available\n";
        return rc;
    }
};

int main()
{
    mybuf buf;
    buf.open("test.txt", std::ios_base::in);
    std::istream stream(&buf);
    while(stream.get()) ;
}

可能的输出：

Before underflow(): size of the get area is 0 with 0 read positions available
underflow() returns 73.
After the call, size of the get area is 110 with 110 read positions available
Before underflow(): size of the get area is 110 with 0 read positions available
underflow() returns -1.
After the call, size of the get area is 0 with 0 read positions available

参阅

underflow [虚] | 从关联输入序列读取字符到获取区 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
underflow [虚] | 返回输入序列中可用的下一字符 (std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
underflow [虚] | 从输入序列读取一个字符而不前进下一位置指针 (std::strstreambuf 的虚受保护成员函数)
uflow [虚] | 从关联文件读取，并令获取区的下一位置指针前进 (虚受保护成员函数)
overflow [虚] | 从放置区写字符到关联的文件 (虚受保护成员函数)
sgetc | 从输入序列读取一个字符，而不令序列前进 (std::basic_streambuf<CharT,Traits> 的公开成员函数)


std::basic_filebuf<CharT,Traits>::~basic_filebuf

< cpp‎ | io‎ | basic filebuf
virtual ~basic_filebuf();

调用 close() 关闭关联文件，并销毁 basic_filebuf 的所有其他成员。若 close() 抛出异常，则捕获异常且不重抛。

参数

（无）

返回值

（无）

注意

典型地为 std::basic_fstream 析构函数所调用。

示例

本节未完成
原因：暂无示例

参阅

(构造函数) | 构造 basic_filebuf 对象 (公开成员函数)
close | 冲入放置区缓冲区并关闭关联的文件 (公开成员函数)


std::basic_fstream

< cpp‎ | io
定义于头文件 <fstream>
template<

class CharT,
class Traits = std::char_traits <CharT>

> class basic_fstream : public std::basic_iostream <CharT, Traits>

类模板 basic_fstream 实现基于文件的流上的高层输入/输出。它将 std::basic_iostream 的高层接口赋予基于文件的缓冲（ std::basic_filebuf ）。

std::basic_fstream 的典型实现只保有一个非导出数据成员： std::basic_filebuf <CharT, Traits> 的实例。

cpp/io/ios base cpp/io/basic ios cpp/io/basic istream cpp/io/basic ostream cpp/io/basic iostream

继承图

亦定义二个对于常用字符类型的特化：

定义于头文件 <fstream>
类型 | 定义
fstream | basic_fstream<char>
wfstream | basic_fstream<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(构造函数)
 构造文件流
(公开成员函数)
(析构函数)
[虚] (隐式声明)
 析构 basic_fstream 和关联的缓冲区，并关闭文件
(虚公开成员函数)
operator=
(C++11)
 移动文件流
(公开成员函数)
swap
(C++11)
 交换二个文件流
(公开成员函数)
rdbuf
 返回底层未处理的文件设备对象
(公开成员函数)
文件操作
is_open
 检查流是否有关联文件
(公开成员函数)
open
 打开文件，并将它与流关联
(公开成员函数)
close
 关闭关联文件
(公开成员函数)

非成员函数

std::swap(std::basic_fstream)
(C++11)
 特化 std::swap 算法
(函数模板)

继承自 std::basic_istream

成员函数

有格式输入
operator>>
 提取带格式数据
(std::basic_istream<CharT,Traits> 的公开成员函数)
无格式输入
get
 从流中读并取走（移除类似指针向下一个元素移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
peek
 仅读出但不取走（不移除类似指针并未移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
unget
 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
putback
 往输入流中退回一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
getline
 一直读并取走字符，直至找到给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
ignore
 读且取走并舍弃字符，直至发现给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
read
 读并取走一块字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
readsome
 读并取走已经可用的字符块
(std::basic_istream<CharT,Traits> 的公开成员函数)
gcount
 返回上次无格式输出操作所取走的字符数量
(std::basic_istream<CharT,Traits> 的公开成员函数)
寻位
tellg
 返回输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
seekg
 设置输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
杂项
sync
 与底层存储设备同步
(std::basic_istream<CharT,Traits> 的公开成员函数)

成员类

sentry
 实现为输出操作准备流的基本逻辑
(std::basic_istream<CharT,Traits> 的公开成员类)

继承自 std::basic_ostream

成员函数

有格式输出
operator<<
 插入带格式数据
(std::basic_ostream<CharT,Traits> 的公开成员函数)
无格式输出
put
 插入字符
(std::basic_ostream<CharT,Traits> 的公开成员函数)
write
 插入字符块
(std::basic_ostream<CharT,Traits> 的公开成员函数)
寻位
tellp
 返回输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
seekp
 设置输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
杂项
flush
 与底层存储设备同步
(std::basic_ostream<CharT,Traits> 的公开成员函数)

成员类

sentry
 为输出操作实现流准备的基本逻辑
(std::basic_ostream<CharT,Traits> 的公开成员类)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)

参阅

getline
 从 I/O 流读取数据到字符串
(函数模板)

示例

#include <iostream>
#include <fstream>
#include <string>

int main() {
  std::string filename = "test.bin";
  std::fstream s(filename, std::fstream::binary | std::fstream::trunc | std::fstream::in | std::fstream::out);
  if (!s.is_open()) {
    std::cout << "failed to open " << filename << '\n';
  } else {
    // 写入
    double d = 3.14;
    s.write(reinterpret_cast<char*>(&d), sizeof d); // 二进制输出
    s << 123 << "abc";                              // 文本输出

    // 对于 fstream ，这会移动文件位置指针（放置与获取）
    s.seekp(0);

    // 读取
    s.read(reinterpret_cast<char*>(&d), sizeof d); // 二进制输入
    int n;
    std::string str;
    if (s >> n >> str)                             // 文本输入
      std::cout << "read back from file: " << d << ' ' << n << ' ' << str << '\n';
  }
}

输出：

read back from file: 3.14 123 abc


std::basic_fstream<CharT,Traits>::basic_fstream

< cpp‎ | io‎ | basic fstream

basic_fstream();
 (1)
explicit basic_fstream( const char* filename,
std::ios_base::openmode mode = ios_base::in|ios_base::out );
 (2)
explicit basic_fstream( const std::filesystem::path::value_type* filename,
std::ios_base::openmode mode = ios_base::in|ios_base::out );
 (3) (C++17 起)
explicit basic_fstream( const std::string & filename,
std::ios_base::openmode mode = ios_base::in|ios_base::out );
 (4) (C++11 起)
template< class T >

explicit basic_fstream( const T& filename,

std::ios_base::openmode mode = ios_base::in|ios_base::out );
 (5) (C++17 起)
basic_fstream( basic_fstream&& other );
 (6) (C++11 起)
basic_fstream( const basic_fstream& rhs) = delete;
 (7) (C++11 起)

构造新的文件流。

1) 默认构造函数：构造不关联到文件的流：默认构造 std::basic_filebuf 并构造拥有指向此默认构造的 std::basic_filebuf 成员的基类。
2-3) 首先，进行同默认构造函数的步骤，然后通过调用 rdbuf()->open(filename, mode)（该调用效果上的细节见 std::basic_filebuf::open ）关联流与文件。若 open() 调用返回空指针，则设置 setstate(failbit) 。仅若 std::filesystem::path::value_type 非 char 才提供重载 (3) 。 (C++17 起)
4-5) 同 basic_fstream(filename.c_str(), mode) 。 (5) 仅若 T 为 std::filesystem::path 才参与重载决议。 (C++17 起)
6) 移动构造函数：首先，从 other 移动构造基类（这不影响 rdbuf() 指针），然后移动构造 std::basic_filebuf 成员，再调用 this->set_rdbuf() 安装新的 basic_filebuf 为基类中的 rdbuf() 指针。
7) 复制构造函数被删除：此类不可复制。

参数

filename - 要打开的文件名
mode - 指定打开模式。可使用下列常量或它们之间的逐位或：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾
other - 用作源的另一文件流

示例

#include <fstream>
#include <utility>
#include <string>
int main()
{
    std::fstream f0;
    std::fstream f1("test.bin", std::ios::binary);
    std::string name = "example.txt";
    std::fstream f2(name);
    std::fstream f3(std::move(f1));
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3430 | C++17 | std::filesystem::path 重载导致了不想要的转换 | 使之为模板以避免

参阅

open | 打开文件，并将它与流关联 (公开成员函数)
open | 打开文件并配置它为关联字符序列 (std::basic_filebuf<CharT,Traits> 的公开成员函数)
set_rdbuf | 替换 rdbuf 而不清除其错误状态 (受保护成员函数)
(构造函数) | 构造对象 (std::basic_iostream<CharT,Traits> 的公开成员函数)


std::basic_fstream<CharT,Traits>::close

< cpp‎ | io‎ | basic fstream

void close();

关闭关联文件。

等效地调用 rdbuf()->close() 。若操作期间出现错误，则调用 setstate(failbit) 。

参数

（无）

返回值

（无）

注意

此函数为 basic_fstream 的析构函数在流对象离开作用域时调用，通常不直接调用。

示例

#include <string>
#include <fstream>
#include <iostream>

int main()
{
    std::fstream f1("example1", std::ios::out),
                 f2("example2", std::ios::out),
                 f3("example3", std::ios::out);

    std::cout << std::boolalpha
              << f1.is_open() << '\n'
              << f2.is_open() << '\n'
              << f3.is_open() << '\n';

    f1.close();
    f2.close();

    std::cout << f1.is_open() << '\n'
              << f2.is_open() << '\n'
              << f3.is_open() << '\n';
}

可能的输出：

true
true
true
false
false
true

参阅

is_open | 检查流是否有关联文件 (公开成员函数)
open | 打开文件，并将它与流关联 (公开成员函数)
close | 冲入放置区缓冲区并关闭关联的文件 (std::basic_filebuf<CharT,Traits> 的公开成员函数)


std::basic_fstream<CharT,Traits>::is_open

< cpp‎ | io‎ | basic fstream

bool is_open(); | (C++11 前)
bool is_open() const; | (C++11 起)

检查文件流是否有关联文件。

等效地调用 rdbuf()->is_open() 。

参数

（无）

返回值

若文件流有关联文件，则为 true ，否则为 false 。

示例

#include <string>
#include <fstream>
#include <iostream>

int main()
{
    std::string filename = "some_file";

    std::fstream fs(filename, std::ios::in);

    std::cout << std::boolalpha;
    std::cout << "fs.is_open() = " << fs.is_open() << '\n';

    if(!fs.is_open())
    {
       fs.clear();
       fs.open(filename, std::ios::out);
       std::cout << "fs.is_open() = " << fs.is_open() << '\n';
    }
}

可能的输出：

fs.is_open() = false
fs.is_open() = true

参阅

open | 打开文件，并将它与流关联 (公开成员函数)
close | 关闭关联文件 (公开成员函数)


std::basic_fstream<CharT,Traits>::open

< cpp‎ | io‎ | basic fstream

void open( const char *filename,
ios_base::openmode mode = ios_base::in|ios_base::out );
 (1)
void open( const std::filesystem::path::value_type *filename,
ios_base::openmode mode = ios_base::in|ios_base::out );
 (2) (C++17 起)
void open( const std::string &filename,
ios_base::openmode mode = ios_base::in|ios_base::out );
 (3) (C++11 起)
void open( const std::filesystem::path &filename,
ios_base::openmode mode = ios_base::in|ios_base::out );
 (4) (C++17 起)

将名为 filename 的文件打开并与文件流关联。

失败时调用 setstate(failbit) 。

成功时调用 clear() 。 (C++11 起)
1-2) 等效地调用 rdbuf()->open(filename, mode). （该调用效果上的细节见 std::basic_filebuf::open ）。仅若 std::filesystem::path::value_type 非 char 才提供重载 (2) 。 (C++17 起)
3-4) 等效地调用 (1-2) ，如同以 open(filename.c_str(), mode) 。

参数

filename - 要打开的文件名
mode - 指定打开模式。它是位掩码类型，定义下列常量：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

返回值

（无）

示例

#include <string>
#include <fstream>
#include <iostream>

int main()
{
    std::string filename = "example.123";

    std::fstream fs;

    fs.open(filename);

    if(!fs.is_open())
    {
       fs.clear();
       fs.open(filename, std::ios::out); // 创建文件。
       fs.close();
       fs.open(filename);
    }

    std::cout << std::boolalpha;
    std::cout << "fs.is_open() = " << fs.is_open() << '\n';
    std::cout << "fs.good() = " << fs.good() << '\n';
}

参阅

is_open | 检查流是否有关联文件 (公开成员函数)
close | 关闭关联文件 (公开成员函数)
open | 打开文件并配置它为关联字符序列 (std::basic_filebuf<CharT,Traits> 的公开成员函数)


std::basic_fstream<CharT,Traits>::operator=

< cpp‎ | io‎ | basic fstream
basic_fstream& operator=( basic_fstream&& other ); | (C++11 起)

移动赋值文件流 other 给 *this ，等效地移动赋值 std::basic_iostream 基类和关联的 std::basic_filebuf 。

将 other 置为无关联文件。注意基类移动赋值交换 *this 与 other 间的所有流状态变量（除了 rdbuf ）。

参数

other - 要移动的文件流。

返回值

*this

示例

本节未完成
原因：暂无示例

参阅

swap (C++11) | 交换二个文件流 (公开成员函数)
operator= (C++11) | 赋值 basic_filebuf 对象 (std::basic_filebuf<CharT,Traits> 的公开成员函数)
operator= (C++11) | 移动赋值另一 basic_iostream (受保护成员函数)


std::basic_fstream<CharT,Traits>::rdbuf

< cpp‎ | io‎ | basic fstream

std::basic_filebuf <CharT, Traits>* rdbuf() const; | (C++11 起)

返回指向底层未处理文件设备对象的指针。

参数

（无）

返回值

指向底层未处理文件设备对象的指针。

示例

本节未完成
原因：暂无示例


std::basic_fstream<CharT,Traits>::swap

< cpp‎ | io‎ | basic fstream

void swap( basic_fstream& other ); | (C++11 起)

交换流与 other 的状态。

通过调用 basic_iostream<CharT, Traits>::swap(other) 和 rdbuf()->swap(other.rdbuf()) 进行。

参数

other - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

operator= (C++11) | 移动文件流 (公开成员函数)
swap (C++11) | 交换二个 basic_filebuf 对象 (std::basic_filebuf<CharT,Traits> 的公开成员函数)


std::swap(std::basic_fstream)

< cpp‎ | io‎ | basic fstream

template< class CharT, class Traits >
void swap( basic_fstream<CharT,Traits> &lhs, basic_fstream<CharT,Traits> &rhs );

为 std::basic_fstream 特化 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++11)
 交换二个文件流
(公开成员函数)


std::basic_ifstream

< cpp‎ | io
定义于头文件 <fstream>
template<

class CharT,
class Traits = std::char_traits <CharT>

> class basic_ifstream : public std::basic_istream <CharT, Traits>

类模板 basic_ifstream 实现文件流上的高层输入操作。它将 std::basic_istream 的高层接口赋予基于文件的流缓冲（ std::basic_filebuf ）。

std::basic_ifstream 的典型实现仅保有一个非导出数据成员： std::basic_filebuf <CharT, Traits> 的实例。

cpp/io/ios base cpp/io/basic ios cpp/io/basic istream

继承图

亦定义二个对于常用字符类型的特化：

定义于头文件 <fstream>
类型 | 定义
ifstream | basic_ifstream<char>
wifstream | basic_ifstream<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(构造函数)
 构造文件流
(公开成员函数)
(析构函数)
[虚] (隐式声明)
 析构 basic_ifstream 和关联的缓冲区，并关闭文件
(虚公开成员函数)
operator=
(C++11)
 移动文件流
(公开成员函数)
swap
(C++11)
 交换二个文件流
(公开成员函数)
rdbuf
 返回底层未处理的文件设备对象
(公开成员函数)
文件操作
is_open
 检查流是否有关联文件
(公开成员函数)
open
 打开文件，并将它与流关联
(公开成员函数)
close
 关闭关联文件
(公开成员函数)

非成员函数

std::swap(std::basic_ifstream)
(C++11)
 特化 std::swap 算法
(函数模板)

继承自 std::basic_istream

成员函数

有格式输入
operator>>
 提取带格式数据
(std::basic_istream<CharT,Traits> 的公开成员函数)
无格式输入
get
 从流中读并取走（移除类似指针向下一个元素移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
peek
 仅读出但不取走（不移除类似指针并未移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
unget
 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
putback
 往输入流中退回一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
getline
 一直读并取走字符，直至找到给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
ignore
 读且取走并舍弃字符，直至发现给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
read
 读并取走一块字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
readsome
 读并取走已经可用的字符块
(std::basic_istream<CharT,Traits> 的公开成员函数)
gcount
 返回上次无格式输出操作所取走的字符数量
(std::basic_istream<CharT,Traits> 的公开成员函数)
寻位
tellg
 返回输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
seekg
 设置输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
杂项
sync
 与底层存储设备同步
(std::basic_istream<CharT,Traits> 的公开成员函数)

成员类

sentry
 实现为输出操作准备流的基本逻辑
(std::basic_istream<CharT,Traits> 的公开成员类)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)

示例

#include <iostream>
#include <fstream>
#include <string>

int main() {
  std::string filename = "Test.b";
  // 准备读取文件
  double d = 3.14;
  std::ofstream(filename, std::ios::binary).write(reinterpret_cast<char*>(&d), sizeof d)
     << 123 << "abc";
  // 打开文件以读取
  std::ifstream istrm(filename, std::ios::binary);
  if (!istrm.is_open()) {
    std::cout << "failed to open " << filename << '\n';
  } else {
    double d;
    istrm.read(reinterpret_cast<char*>(&d), sizeof d); // 二进制输入
    int n;
    std::string s;
    if (istrm >> n >> s)                               // 文本输入
      std::cout << "read back from file: " << d << ' ' << n << ' ' << s << '\n';
  }
}

输出：

read back from file: 3.14 123 abc


std::basic_ifstream<CharT,Traits>::basic_ifstream

< cpp‎ | io‎ | basic ifstream

basic_ifstream();
 (1)
explicit basic_ifstream( const char* filename,
std::ios_base::openmode mode = ios_base::in );
 (2)
explicit basic_ifstream( const std::filesystem::path::value_type* filename,
std::ios_base::openmode mode = ios_base::in );
 (3) (C++17 起)
explicit basic_ifstream( const std::string & filename,
std::ios_base::openmode mode = ios_base::in );
 (4) (C++11 起)
template< class T >

explicit basic_ifstream( const T& filename,

std::ios_base::openmode mode = ios_base::in );
 (5) (C++17 起)
basic_ifstream( basic_ifstream&& other );
 (6) (C++11 起)
basic_ifstream( const basic_ifstream& rhs) = delete;
 (7) (C++11 起)

构造新的文件流。

1) 默认构造函数：构造不关联到文件的流：默认构造 std::basic_filebuf 并构造拥有指向此默认构造的 std::basic_filebuf 成员的基类。
2-3) 首先，进行同默认构造函数的步骤，然后通过调用 rdbuf()->open(filename, mode | std::ios_base::in )（该调用效果上的细节见 std::basic_filebuf::open ）关联流与文件。若 open() 调用返回空指针，则设置 setstate(failbit) 。仅若 std::filesystem::path::value_type 非 char 才提供重载 (3) 。 (C++17 起)
4-5) 同 basic_ifstream(filename.c_str(), mode) 。 (5) 仅若 T 为 std::filesystem::path 才参与重载决议。 (C++17 起)
6) 移动构造函数：首先，从 other 移动构造基类（这不影响 rdbuf() 指针），然后移动构造 std::basic_filebuf 成员，再调用 this->set_rdbuf() 安装新的 basic_filebuf 为基类中的 rdbuf() 指针。
7) 复制构造函数被删除：此类不可复制。

参数

filename - 要打开的文件名
mode - 指定打开模式。可使用下列常量或它们之间的逐位或：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾
other - 用作源的另一文件流

示例

#include <fstream>
#include <utility>
#include <string>
int main()
{
    std::ifstream f0;
    std::ifstream f1("test.bin", std::ios::binary);
    std::string name = "example.txt";
    std::ifstream f2(name);
    std::ifstream f3(std::move(f1));
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3430 | C++17 | std::filesystem::path 重载导致了不想要的转换 | 使之为模板以避免

参阅

open | 打开文件，并将它与流关联 (公开成员函数)
open | 打开文件并配置它为关联字符序列 (std::basic_filebuf<CharT,Traits> 的公开成员函数)
set_rdbuf | 替换 rdbuf 而不清除其错误状态 (受保护成员函数)
(构造函数) | 构造对象 (std::basic_istream<CharT,Traits> 的公开成员函数)


std::basic_ifstream<CharT,Traits>::close

< cpp‎ | io‎ | basic ifstream

void close();

关闭关联文件。

等效地调用 rdbuf()->close() 。若操作期间出现错误，则调用 setstate(failbit) 。

参数

（无）

返回值

（无）

注意

此函数为 basic_ifstream 的析构函数在流对象离开作用域时调用，通常不直接调用。

示例

本节未完成
原因：暂无示例

参阅

is_open | 检查流是否有关联文件 (公开成员函数)
open | 打开文件，并将它与流关联 (公开成员函数)
close | 冲入放置区缓冲区并关闭关联的文件 (std::basic_filebuf<CharT,Traits> 的公开成员函数)


std::basic_ifstream<CharT,Traits>::is_open

< cpp‎ | io‎ | basic ifstream

bool is_open(); | (C++11 前)
bool is_open() const; | (C++11 起)

检查文件流是否有关联文件。

等效地调用 rdbuf()->is_open() 。

参数

（无）

返回值

若文件流有关联文件，则为 true ，否则为 false 。

示例

#include <string>
#include <fstream>
#include <iostream>
// 此文件名为 main.cpp

bool file_exists(const std::string& str)
{
   std::ifstream fs(str);
   return fs.is_open();
}

int main()
{
  std::boolalpha(std::cout);
  std::cout << file_exists("main.cpp")  << '\n'
            << file_exists("strange_file") << '\n';
}

可能的输出：

true
false

参阅

open | 打开文件，并将它与流关联 (公开成员函数)
close | 关闭关联文件 (公开成员函数)


std::basic_ifstream<CharT,Traits>::open

< cpp‎ | io‎ | basic ifstream

void open( const char *filename,
ios_base::openmode mode = ios_base::in );
 (1)
void open( const std::filesystem::path::value_type *filename,
ios_base::openmode mode = ios_base::in );
 (2) (C++17 起)
void open( const std::string &filename,
ios_base::openmode mode = ios_base::in );
 (3) (C++11 起)
void open( const std::filesystem::path &filename,
ios_base::openmode mode = ios_base::in );
 (4) (C++17 起)

将名为 filename 的文件打开并与文件流关联。

失败时调用 setstate(failbit) 。

成功时调用 clear() 。 (C++11 起)
1-2) 等效地调用 rdbuf()->open(filename, mode | ios_base::in). （该调用效果上的细节见 std::basic_filebuf::open ）。仅若 std::filesystem::path::value_type 非 char 才提供重载 (2) 。 (C++17 起)
3-4) 等效地调用 (1-2) ，如同以 open(filename.c_str(), mode) 。

参数

filename - 要打开的文件名
mode - 指定打开模式。它是位掩码类型，定义下列常量：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

is_open | 检查流是否有关联文件 (公开成员函数)
close | 关闭关联文件 (公开成员函数)
open | 打开文件并配置它为关联字符序列 (std::basic_filebuf<CharT,Traits> 的公开成员函数)


std::basic_ifstream<CharT,Traits>::operator=

< cpp‎ | io‎ | basic ifstream
basic_ifstream& operator=( basic_ifstream&& other ); | (C++11 起)

移动赋值文件流 other 给 *this ，等效地移动赋值 std::basic_istream 基类和关联的 std::basic_filebuf 。

将 other 置为无关联文件。注意基类移动赋值交换 *this 与 other 间的所有流状态变量（除了 rdbuf ）。

参数

other - 要移动的文件流。

返回值

*this

示例

本节未完成
原因：暂无示例

参阅

swap (C++11) | 交换二个文件流 (公开成员函数)
operator= (C++11) | 赋值 basic_filebuf 对象 (std::basic_filebuf<CharT,Traits> 的公开成员函数)
operator= (C++11) | 从另一 basic_istream 移动赋值 (受保护成员函数)


std::basic_ifstream<CharT,Traits>::rdbuf

< cpp‎ | io‎ | basic ifstream

std::basic_filebuf <CharT, Traits>* rdbuf() const; | (C++11 起)

返回指向底层未处理文件设备对象的指针。

参数

（无）

返回值

指向底层未处理文件设备对象的指针。

示例

本节未完成
原因：暂无示例


std::basic_ifstream<CharT,Traits>::swap

< cpp‎ | io‎ | basic ifstream

void swap( basic_ifstream& other ); | (C++11 起)

交换流与 other 的状态。

通过调用 basic_istream<CharT, Traits>::swap(other) 和 rdbuf()->swap(other.rdbuf()) 进行。

参数

other - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

operator= (C++11) | 移动文件流 (公开成员函数)
swap (C++11) | 交换二个 basic_filebuf 对象 (std::basic_filebuf<CharT,Traits> 的公开成员函数)


std::swap(std::basic_ifstream)

< cpp‎ | io‎ | basic ifstream

template< class CharT, class Traits >
void swap( basic_ifstream<CharT,Traits> &lhs, basic_ifstream<CharT,Traits> &rhs );

为 std::basic_ifstream 特化 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++11)
 交换二个文件流
(公开成员函数)


std::basic_ios

< cpp‎ | io
定义于头文件 <ios>
template<

class CharT,
class Traits = std::char_traits <CharT>

> class basic_ios : public std::ios_base

类 std::basic_ios 提供设施，以对拥有 std::basic_streambuf 接口的对象赋予接口。数个 std::basic_ios 对象能指涉一个实际的 std::basic_streambuf 对象。

cpp/io/ios base

继承图

还提供了两个对常见的字符类型的特化：

类型 | 定义
ios | basic_ios<char>
wios | basic_ios<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

公开成员函数

(构造函数)
 构造对象
(公开成员函数)
(析构函数)
 析构对象
(公开成员函数)
operator=
 复制赋值运算符被删除
(公开成员函数)
状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(公开成员函数)
eof
 检查是否到达了文件末尾
(公开成员函数)
fail
 检查是否发生了可恢复的错误
(公开成员函数)
bad
 检查是否已发生不可恢复的错误
(公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(公开成员函数)
rdstate
 返回状态标志
(公开成员函数)
setstate
 设置状态标志
(公开成员函数)
clear
 修改状态标志
(公开成员函数)
格式化
copyfmt
 复制格式化信息
(公开成员函数)
fill
 管理填充字符
(公开成员函数)
杂项
exceptions
 管理异常掩码
(公开成员函数)
imbue
 设置本地环境
(公开成员函数)
rdbuf
 管理相关的流缓冲区
(公开成员函数)
tie
 管理绑定的流
(公开成员函数)
narrow
 窄化字符
(公开成员函数)
widen
 拓宽字符
(公开成员函数)

受保护成员函数

init | 初始化一个默认构造的std::basic_ios (受保护成员函数)
move (C++11) | 从另一 std::basic_ios 移动，除了 rdbuf (受保护成员函数)
swap (C++11) | 与另一 std::basic_ios 交换，除了 rdbuf (受保护成员函数)
set_rdbuf | 替换 rdbuf 而不清除其错误状态 (受保护成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)

注意

std::basic_ios 的直接实现仅储存以下成员（它们完全取决于模板形参，从而不能为 std::ios_base 的一部分）：

  • 用于填充的字符（参见 fill() ）
  • 绑定的流指针（参见 tie() ）
  • 关联的流缓冲区指针（参见 rdbuf() ）

实际实现各异：

Microsoft Visual Studio 储存了这三个成员。

LLVM libc++ 少储存了一个成员：它将 rdbuf 指针储存为 ios_base 的 void* 成员。

GNU libstdc++ 储存了 4 个额外的成员：三个缓存的 facet 和一个用于标识填充是否已初始化的标记。


std::basic_ios<CharT,Traits>::bad

< cpp‎ | io‎ | basic ios
bool bad() const;

若关联的流上已出现不可恢复的错误则返回 true 。尤其是若 rdstate() 中设置了 badbit 则返回 true 。

设置 badbit 的条件列表见 ios_base::iostate 。

参数

（无）

返回值

若出现不可恢复的错误则为 true ，否则为 false 。

示例

#include <iostream>
#include <fstream>
#include <cstdlib>
int main()
{
    std::ifstream file("test.txt");
    if(!file)  // operator! 用于此
    {
        std::cout << "File opening failed\n";
        return EXIT_FAILURE;
    }

    // 典型的 C++ I/O 循环以 I/O 函数的返回值为循环控制条件，
    // operator bool() 用于此
    for(int n; file >> n; ) {
       std::cout << n << ' ';
    }
    std::cout << '\n';

    if (file.bad())
        std::cout << "I/O error while reading\n";
    else if (file.eof())
        std::cout << "End of file reached successfully\n";
    else if (file.fail())
        std::cout << "Non-integer data encountered\n";
}

参阅

下表显示 basic_ios 访问器（ good()、 fail() 等）对于 ios_base::iostate 标志的所有可能组合的值：

ios_base::iostate 标志 |  |  | basic_ios 访问器
eofbit | failbit | badbit | good() | fail() | bad() | eof() | operator bool | operator!
false | false | false | true | false | false | false | true | false
false | false | true | false | true | true | false | false | true
false | true | false | false | true | false | false | false | true
false | true | true | false | true | true | false | false | true
true | false | false | false | false | false | true | true | false
true | false | true | false | true | true | true | false | true
true | true | false | false | true | false | true | false | true
true | true | true | false | true | true | true | false | true


std::basic_ios<CharT,Traits>::basic_ios

< cpp‎ | io‎ | basic ios
protected: basic_ios(); | (1)
public: explicit basic_ios( std::basic_streambuf <CharT,Traits>* sb ); | (2)
 | (3)
private: basic_ios(const basic_ios&); |  | (C++11 前)
public: basic_ios(const basic_ios& ) = delete; |  | (C++11 起)

构造新的 basic_ios 对象。

1) 默认构造函数。不初始化内部状态。必须在首次使用对象或析构函数前调用 init() ，否则行为未定义。
2) 以调用init(sb) 初始化内部状态。设置关联流缓冲为 sb 。
3) C++11 前复制构造函数声明为 private: 且不定义，而在 C++11 中声明为被删除： I/O 流非可复制构造 (CopyConstructible) 。

参数

sb - 要关联的流缓冲


std::basic_ios<CharT,Traits>::clear

< cpp‎ | io‎ | basic ios
void clear( std::ios_base::iostate state = std::ios_base::goodbit );

通过以 state 的值赋值，设置流错误状态标志。默认赋值 std::ios_base::goodbit ，它拥有的效果为清除所有错误状态标志。

若 rdbuf() 为空指针（即无关联的流缓冲），则赋值 state | badbit 。可能抛出异常。

参数

state - 新的错误状态标志设置。它能为下列常量的组合：
常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

返回值

（无）

异常

本节未完成
原因：也链接到 basic_ios::exceptions

示例

无参数的 clear() 能用于在不期待的输入后反设置 failbit

#include <iostream>
#include <string>

int main()
{
    double n;
    while( std::cout << "Please, enter a number\n"
           && ! (std::cin >> n) )
    {
        std::cin.clear();
        std::string line;
        std::getline(std::cin, line);
        std::cout << "I am sorry, but '" << line << "' is not a number\n";
    }
    std::cout << "Thank you for entering the number " << n << '\n';
}

参阅

setstate | 设置状态标志 (公开成员函数)
rdstate | 返回状态标志 (公开成员函数)


std::basic_ios<CharT,Traits>::copyfmt

< cpp‎ | io‎ | basic ios
basic_ios& copyfmt(const basic_ios& other);

若 other 与 *this 指代同一对象，则无效果。否则复制流 other 的状态到 *this 中。以下列序列进行：

1) 传递 erase_event 为参数，调用 register_callback() 所注册的每个回调。
2) 从 other 复制所有成员对象到 *this ，除了 rdstate() 、异常掩码和 rdbuf() 。特别是复制本地环境、格式化标志、数组 std::ios_base::iword 和 std::ios_base::pword 的内容（但不是 iword 和 pword 指针本身）、回调和 tie 的流。
3) 传递 copyfmt_event为参数，调用 register_callback() 所注册的每个回调。
4) 从 other 复制异常掩码到 *this ，如同通过调用 exceptions(other.exceptions()) 。

参数

other - 用作源的另一流

返回值

*this

注意

通过回调的第二趟可用于深复制 std::ios_base::pword 中的指针所指向的用户定义对象。

copyfmt() 可用于保存和恢复流状态。 Boost 为相同目的提供更加细粒度的 IO state savers 库。

示例

令 ofstream 对象 "out" 表现准确地类似 std::cout ，包括格式化、 tie() 到 std::cin 等。

#include <iostream>
#include <fstream>

int main()
{
    std::ofstream out;

    out.copyfmt(std::cout); // 复制 rdstate 和 rdbuf 外的所有内容
    out.clear(std::cout.rdstate()); // 复制 rdstate
    out.basic_ios<char>::rdbuf(std::cout.rdbuf()); // 共享缓冲

    out << "Hello, world\n";
}

输出：

Hello, world


std::basic_ios<CharT,Traits>::eof

< cpp‎ | io‎ | basic ios
bool eof() const;

若关联流已抵达文件尾则返回 true 。尤其是若 rdstate() 中设置了 eofbit 则返回 true 。

设置 eofbit 的条件列表见 ios_base::iostate 。

参数

（无）

返回值

若遇到文件尾条件则为 true ，否则为 false 。

注意

此函数只报告最近的 I/O 操作所设置的流状态；它不检测关联的数据源。例如，若最近的 I/O 为返回文件最后字节的 get() ，则 eof() 返回 false 。下个 get() 无法读取任何内容，并设置 eofbit 。之后 eof() 才返回 true 。

典型使用中，输入流处理在任何错误上停止。然后能用 eof() 和 fail() 区别不同的错误条件。

示例

#include <iostream>
#include <fstream>
#include <cstdlib>
int main()
{
    std::ifstream file("test.txt");
    if(!file)  // operator! 用于此
    {
        std::cout << "File opening failed\n";
        return EXIT_FAILURE;
    }

    // 典型的 C++ I/O 循环以 I/O 函数的返回值为循环控制条件，
    // operator bool() 用于此
    for(int n; file >> n; ) {
       std::cout << n << ' ';
    }
    std::cout << '\n';

    if (file.bad())
        std::cout << "I/O error while reading\n";
    else if (file.eof())
        std::cout << "End of file reached successfully\n";
    else if (file.fail())
        std::cout << "Non-integer data encountered\n";
}

参阅

下表显示 basic_ios 访问器（ good()、 fail() 等）对于 ios_base::iostate 标志的所有可能组合的值：

ios_base::iostate 标志 |  |  | basic_ios 访问器
eofbit | failbit | badbit | good() | fail() | bad() | eof() | operator bool | operator!
false | false | false | true | false | false | false | true | false
false | false | true | false | true | true | false | false | true
false | true | false | false | true | false | false | false | true
false | true | true | false | true | true | false | false | true
true | false | false | false | false | false | true | true | false
true | false | true | false | true | true | true | false | true
true | true | false | false | true | false | true | false | true
true | true | true | false | true | true | true | false | true
feof
 检查文件尾
(函数)


std::basic_ios<CharT,Traits>::exceptions

< cpp‎ | io‎ | basic ios
std::ios_base::iostate exceptions() const; | (1)
void exceptions( std::ios_base::iostate except ); | (2)

获取和设置流的异常掩码。异常掩码确定在哪些错误状态出现时抛出 failure 类型异常。

1) 返回异常掩码。
2) 设置异常掩码为 except 。

参数

except - 异常掩码

返回值

1) 当前异常掩码。
2) （无）

注意

本节未完成
原因：讨论 LWG2349 ，并从 ios_base::clear 及从有/无格式输入/输出函数要求页面的链接（或者在要求页面的上详述行为并从此处链接更好）。参阅 stackoverflow.com/a/35089910

示例

#include <iostream>
#include <fstream>

int main()
{
    int ivalue;
    try {
        std::ifstream in("in.txt");
        in.exceptions(std::ifstream::failbit);
        in >> ivalue;
    } catch (std::ios_base::failure &fail) {
        // 此处处理异常
    }
}


std::basic_ios<CharT,Traits>::fail

< cpp‎ | io‎ | basic ios
bool fail() const;

若关联流上已发生错误则返回 true 。特别是若 rdstate() 中设置了 badbit 或 failbit 则返回 true 。

设置 failbit 或 badbit 的条件列表见 ios_base::iostate 。

参数

（无）

返回值=

若已出现错误则为 true ，否则为 false 。

示例

#include <iostream>
#include <fstream>
#include <cstdlib>
int main()
{
    std::ifstream file("test.txt");
    if(!file)  // operator! 用于此
    {
        std::cout << "File opening failed\n";
        return EXIT_FAILURE;
    }

    // 典型的 C++ I/O 循环以 I/O 函数的返回值为循环控制条件，
    // operator bool() 用于此
    for(int n; file >> n; ) {
       std::cout << n << ' ';
    }
    std::cout << '\n';

    if (file.bad())
        std::cout << "I/O error while reading\n";
    else if (file.eof())
        std::cout << "End of file reached successfully\n";
    else if (file.fail())
        std::cout << "Non-integer data encountered\n";
}

参阅

下表显示 basic_ios 访问器（ good()、 fail() 等）对于 ios_base::iostate 标志的所有可能组合的值：

ios_base::iostate 标志 |  |  | basic_ios 访问器
eofbit | failbit | badbit | good() | fail() | bad() | eof() | operator bool | operator!
false | false | false | true | false | false | false | true | false
false | false | true | false | true | true | false | false | true
false | true | false | false | true | false | false | false | true
false | true | true | false | true | true | false | false | true
true | false | false | false | false | false | true | true | false
true | false | true | false | true | true | true | false | true
true | true | false | false | true | false | true | false | true
true | true | true | false | true | true | true | false | true
ferror
 检查文件错误
(函数)


std::basic_ios<CharT,Traits>::fill

< cpp‎ | io‎ | basic ios
CharT fill() const; | (1)
CharT fill( CharT ch ); | (2)

管理用于填充输入转换到指定宽度的填充字符。

1) 返回当前的填充字符
2) 设置填充字符为 ch ，返回填充字符的先前值

参数

ch - 用作填充字符的字符

返回值

调用函数前的填充字符。

示例

#include <iostream>
#include <iomanip>

int main ()
{
  std::cout << "With default setting : " << std::setw(10) << 40 << '\n';
  char prev = std::cout.fill('x');
  std::cout << "Replaced '" << prev << "' with '"
            << std::cout.fill() << "': " << std::setw(10) << 40 << '\n';
}

输出：

With default setting :         40
Replaced ' ' with 'x': xxxxxxxx40

参阅

setfill
 更改填充字符
(函数模板)


std::basic_ios<CharT,Traits>::good

< cpp‎ | io‎ | basic ios
bool good() const;

若流上的最近 I/O 操作成功完成则返回 true 。特别是返回 rdstate() == 0 的结果。

设置流状态位的条件列表，见 ios_base::iostate 。

参数

（无）

返回值

若流未出现错误则为 true ，否则为 false 。

示例

本节未完成
原因：暂无示例

参阅

下表显示 basic_ios 访问器（ good()、 fail() 等）对于 ios_base::iostate 标志的所有可能组合的值：

ios_base::iostate 标志 |  |  | basic_ios 访问器
eofbit | failbit | badbit | good() | fail() | bad() | eof() | operator bool | operator!
false | false | false | true | false | false | false | true | false
false | false | true | false | true | true | false | false | true
false | true | false | false | true | false | false | false | true
false | true | true | false | true | true | false | false | true
true | false | false | false | false | false | true | true | false
true | false | true | false | true | true | true | false | true
true | true | false | false | true | false | true | false | true
true | true | true | false | true | true | true | false | true


std::basic_ios<CharT,Traits>::imbue

< cpp‎ | io‎ | basic ios
std::locale imbue( const std::locale & loc );

替换当前本地环境。等效地调用 ios_base::imbue(loc) ，而若有关联流缓冲（ rdbuf() != 0 ），则再调用 rdbuf()->pubimbue(loc) 。

参数

loc - 新的 locale

返回值

先前的 locale ，以 ios_base::imbue(loc) 返回。

异常

可能抛出实现定义的异常。

参数

#include <iostream>
#include <sstream>
#include <locale>

int main()
{
    std::istringstream iss;
    iss.imbue(std::locale("en_US.UTF8"));

    std::cout << "Current locale: " << iss.getloc().name() << '\n';

    iss.imbue(std::locale());
    std::cout << "Global locale : " << iss.getloc().name() << '\n';
}

输出：

Current locale: en_US.UTF8
Global locale : C


std::basic_ios<CharT,Traits>::init

< cpp‎ | io‎ | basic ios
protected:
void init( std::basic_streambuf <CharT,Traits>* sb );

设置关联流缓冲为 sb 并初始化内部状态。

后置条件如下：

元素 | 值
rdbuf() | sb
tie() | 空指针
rdstate() | 若 sb 不是空指针, 则为 goodbit ，否则为 badbit
exceptions() | goodbit
flags() | skipws | dec
width() | ​0​
precision() | 6
fill() | widen(' ')
getloc() | std::locale () 所返回的值的副本

此成员函数为受保护：一旦知晓实际缓冲区类型，则它为派生流类 std::basic_istream 和 std::basic_ostream 的构造函数所调用。直至调用此函数前，默认构造的 std::basic_ios 每个成员函数（包括析构函数）都引发未定义行为。注意 basic_ios 是虚基类，从而其构造函数不为直接派生类的构造函数所调用，此乃二阶段初始化为必须的原因。

参数

sb - 要关联到的流缓冲

参阅

(构造函数)
 构造对象
(公开成员函数)


std::basic_ios<CharT,Traits>::move

< cpp‎ | io‎ | basic ios
protected: void move( basic_ios& other ); | (C++11 起)
protected: void move( basic_ios&& other ); | (C++11 起)

以 other 的状态替换当前状态，除了关联的 rdbuf 。调用后 other 在合法，但未指定的状态。调用此函数后， rdbuf() 返回空指针，而 other.rdbuf() 返回与调用前相同的值，且 other.tie() 返回空指针。

此成员函数受保护：它为派生流类 std::basic_ostream 和 std::basic_istream 的受保护移动构造函数所调用，进而为进一步派生的流类，如 std::basic_ofstream 的公开移动构造函数所调用，它们知道如何正确地移动关联流缓冲。

参数

other - 转移状态来源的 basic_ios 对象

返回值

（无）

参阅

swap
(C++11)
 与另一 std::basic_ios 交换，除了 rdbuf
(受保护成员函数)


std::basic_ios<CharT,Traits>::narrow

< cpp‎ | io‎ | basic ios
char narrow( char_type c, char dfault ) const;

转换当前本地环境限定的字符 c 到其标准等价物。若需要则将结果从 char_type 转换到 char 。若不能进行转换，则函数返回 dfault 。

等效地调用 std::use_facet < std::ctype <char_type> >(getloc()).narrow(c, dfault); 。

参数

c | - | 要转换的字符
dfault | - | 若转化不成功则返回的字符

返回值

转换到标准等价物再到 char 的字符。若转换失败则返回 dfault 。

参阅

widen | 拓宽字符 (公开成员函数)
narrow | 调用 do_narrow (std::ctype<CharT> 的公开成员函数)
wctob | 若可能，则窄化宽字符为单字节窄字符 (函数)


std::basic_ios<CharT,Traits>::operator!

< cpp‎ | io‎ | basic ios
bool operator!() const;

若关联流上已出现错误则返回 true 。特别是若 rdstate() 中设置了 failbit 或 badbit 则返回 true 。

参数

（无）

返回值

若已出现错误则为 true ，否则为 false 。

示例

#include <iostream>
#include <fstream>
#include <cstdlib>
int main()
{
    std::ifstream file("test.txt");
    if(!file)  // operator! 用于此
    {
        std::cout << "File opening failed\n";
        return EXIT_FAILURE;
    }

    // 典型的 C++ I/O 循环以 I/O 函数的返回值为循环控制条件，
    // operator bool() 用于此
    for(int n; file >> n; ) {
       std::cout << n << ' ';
    }
    std::cout << '\n';

    if (file.bad())
        std::cout << "I/O error while reading\n";
    else if (file.eof())
        std::cout << "End of file reached successfully\n";
    else if (file.fail())
        std::cout << "Non-integer data encountered\n";
}

参阅

下表显示 basic_ios 访问器（ good()、 fail() 等）对于 ios_base::iostate 标志的所有可能组合的值：

ios_base::iostate 标志 |  |  | basic_ios 访问器
eofbit | failbit | badbit | good() | fail() | bad() | eof() | operator bool | operator!
false | false | false | true | false | false | false | true | false
false | false | true | false | true | true | false | false | true
false | true | false | false | true | false | false | false | true
false | true | true | false | true | true | false | false | true
true | false | false | false | false | false | true | true | false
true | false | true | false | true | true | true | false | true
true | true | false | false | true | false | true | false | true
true | true | true | false | true | true | true | false | true


std::basic_ios<CharT,Traits>::operator bool

< cpp‎ | io‎ | basic ios
operator void*() const; | (1) | (C++11 前)
explicit operator bool() const; | (2) | (C++11 起)

检查流是否无错误。

1) 若 fail() 返回 true 则返回空指针，否则返回非空指针。此指针可隐式转换为 bool ，并可用于布尔语境。
2) 若流无错误且已为 I/O 操作就绪则返回 true 。尤其是返回 !fail() 。

此运算符使得以流和返回到流引用的函数为循环条件可行，产生惯用的 C++ 输入循环，例如 while(stream >> value) {...} 或 while(getline(stream, string)){...} 。这种循环仅若输入操作成功才执行循环体。

参数

（无）

返回值

若流无错误则为 true ，否则为 false 。

示例

#include <iostream>
#include <sstream>

int main()
{
    std::istringstream s("1 2 3 error");
    int n;
    std::cout << std::boolalpha << "s is " << static_cast<bool>(s) << '\n';
    while (s >> n) {
        std::cout << n << '\n';
    }
    std::cout << "s is " << static_cast<bool>(s) << '\n';
}

输出：

s is true
1
2
3
s is false

参阅

下表显示 basic_ios 访问器（ good()、 fail() 等）对于 ios_base::iostate 标志的所有可能组合的值：

ios_base::iostate 标志 |  |  | basic_ios 访问器
eofbit | failbit | badbit | good() | fail() | bad() | eof() | operator bool | operator!
false | false | false | true | false | false | false | true | false
false | false | true | false | true | true | false | false | true
false | true | false | false | true | false | false | false | true
false | true | true | false | true | true | false | false | true
true | false | false | false | false | false | true | true | false
true | false | true | false | true | true | true | false | true
true | true | false | false | true | false | true | false | true
true | true | true | false | true | true | true | false | true


std::basic_ios<CharT,Traits>::rdbuf

< cpp‎ | io‎ | basic ios
std::basic_streambuf <CharT, Traits>* rdbuf() const; | (1)
std::basic_streambuf <CharT, Traits>* rdbuf( std::basic_streambuf <CharT, Traits>* sb ); | (2)

管理关联的流缓冲。

1) 返回关联的流缓冲。若无关联流缓冲，则返回空指针。
2) 设置关联流缓冲为 sb 。通过调用 clear() 清除错误状态。返回操作前的关联流缓冲。若无关联流缓冲，则返回空指针。

参数

sb - 要关联的流缓冲

返回值

关联的流缓冲，或若无关联流缓冲则为空指针。

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <sstream>

int main()
{
    std::ostringstream local;
    auto cout_buff = std::cout.rdbuf(); // 保存指向 std::cout 缓冲的指针

    std::cout.rdbuf(local.rdbuf()); // 以 'local' 对象的缓冲
        // 替换内部的 std::cout 缓冲

    // 现在 std::cout 以 'local' 缓冲工作
    // 你看不到此消息
    std::cout << "some message";

    // 回到旧缓冲
    std::cout.rdbuf(cout_buff);

    // 你将看到此消息
    std::cout << "back to default buffer\n";

    // 打印 'local' 内容
    std::cout << "local content: " << local.str() << "\n";
}

输出：

back to default buffer
local content: some message

参阅

set_rdbuf
 替换 rdbuf 而不清除其错误状态
(受保护成员函数)


std::basic_ios<CharT,Traits>::rdstate

< cpp‎ | io‎ | basic ios
iostate rdstate() const;

返回当前错误状态。

参数

（无）

返回值

当前错误状态。它是位掩码类型，并且能是下列常量的组合：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

示例

#include <iostream>
#include <sstream>

int main()
{
  std::ostringstream stream;

  if (stream.rdstate() == std::ios_base::goodbit) {
    std::cout << "stream state is goodbit\n";
  }

  stream.setstate(std::ios_base::eofbit);

  // 检查状态为准确的 eofbit （无 failbit 且无 badbit ）
  if (stream.rdstate() == std::ios_base::eofbit) {
    std::cout << "stream state is eofbit\n";
  }
}

输出：

stream state is goodbit
stream state is eofbit

参阅

setstate | 设置状态标志 (公开成员函数)
clear | 修改状态标志 (公开成员函数)


std::basic_ios<CharT,Traits>::set_rdbuf

< cpp‎ | io‎ | basic ios
protected: void set_rdbuf( std::basic_streambuf <CharT,Traits>* sb ); | (C++11 起)

设置关联流缓冲为 sb 而不清除错误状态。

此成员函数受保护：它为派生流，如 std::basic_ofstream 或 std::basic_istringstream 的移动构造函数所调用，作为构造基类和移动流缓冲后的最终步骤：只有最终导出流类知道如何正确移动流缓冲，但需要令 std::basic_ios 意识到流的新位置，使得其公开成员函数能访问它。

参数

sb - 要访问的流缓冲

返回值

（无）

异常

不抛出。

示例

本节未完成
原因：暂无示例

参阅

rdbuf
 管理相关的流缓冲区
(公开成员函数)


std::basic_ios<CharT,Traits>::setstate

< cpp‎ | io‎ | basic ios
void setstate( iostate state );

在当前已设置表之外，设置流错误状态标志 state 。实质上调用 clear(rdstate() | state) 。可能抛出异常。

参数

state - 要设置的流错误状态标志。能为下列常量的组合：
常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

返回值

（无）

示例

#include <iostream>
#include <sstream>

int main()
{
    std::ostringstream stream;

    if (!stream.fail()) {
        std::cout << "stream is not fail\n";
    }

    stream.setstate(std::ios_base::failbit);

    if (stream.fail()) {
        std::cout << "now stream is fail\n";
    }

    if (!stream.good()) {
        std::cout << "and stream is not good\n";
    }
}

输出：

stream is not fail
now stream is fail
and stream is not good

参阅

rdstate | 返回状态标志 (公开成员函数)
clear | 修改状态标志 (公开成员函数)


std::basic_ios<CharT,Traits>::swap

< cpp‎ | io‎ | basic ios
protected: void swap( basic_ios& other ) noexcept; | (C++11 起)

交换 *this 与 other 的状态，除了关联的 rdbuf 对象。 rdbuf() 和 other.rdbuf() 返回与调用前相同的值。

此 swap 函数受保护：它为派生流类，如 std::basic_ofstream 或 std::basic_istringstream 的成员函数所调用，它们知道如何正确地交换关联的流缓冲。

参数

other - 要与之交换状态的 basic_ios 对象

返回值

（无）

参阅

move
(C++11)
 从另一 std::basic_ios 移动，除了 rdbuf
(受保护成员函数)


std::basic_ios<CharT,Traits>::tie

< cpp‎ | io‎ | basic ios
std::basic_ostream <CharT,Traits>* tie() const; | (1)
std::basic_ostream <CharT,Traits>* tie( std::basic_ostream <CharT,Traits>* str ); | (2)

管理联系流。联系流是输出流，它与流缓冲（ rdbuf() ）所控制的输出序列同步，即在任何 *this 上的输入/输出操作前，在联系流上调用 flush() 。

1) 返回当前联系流。若无联系流，则返回空指针。
2) 设置当前联系流为 str 。返回操作前的联系流。若无联系流，则返回空指针。

参数

str - 要设为联系流的输出流

返回值

联系流，或若无联系流则为空指针。

异常

可能抛出实现定义的异常。

注解

默认情况下，联系标准流 cin 和 cerr 到 cout 。类似地，联系其宽对应版本 wcin 和 wcerr 到 wcout 。

示例

#include <iostream>
#include <fstream>
#include <string>

int main()
{
    std::ofstream os("test.txt");
    std::ifstream is("test.txt");
    std::string value("0");

    os << "Hello";
    is >> value;

    std::cout << "Result before tie(): \"" << value << "\"\n";
    is.clear();
    is.tie(&os);

    is >> value;

    std::cout << "Result after tie(): \"" << value << "\"\n";
}

输出：

Result before tie(): "0"
Result after tie(): "Hello"


std::basic_ios<CharT,Traits>::widen

< cpp‎ | io‎ | basic ios
char_type widen( char c ) const;

转换字符 c 到其在当前本地环境的等价物。若需要，则将结果从 char 转换为用于流内的字符类型。

等效地调用 std::use_facet < std::ctype <char_type> >(getloc()).widen(c) 。

参数

c - 要转换的字符

返回值

转换为 char_type 的字符

参阅

narrow | 窄化字符 (公开成员函数)
do_widen [虚] | 将一或多个字符从 char 转换为 charT (std::ctype<CharT> 的虚受保护成员函数)
btowc | 若可能，则加宽单字节窄字符为宽字符 (函数)


std::basic_ios<CharT,Traits>::~basic_ios

< cpp‎ | io‎ | basic ios
virtual ~basic_ios();

销毁 basic_ios 对象。不进行 rdbuf 上的操作，不销毁它。

注意

此析构函数为 virtual ，因为其基类析构函数 ios_base::~ios_base 为虚。


std::basic_iostream

< cpp‎ | io
定义于头文件 <istream>
template<

class CharT,
class Traits = std::char_traits <CharT>

> class basic_iostream;

类模板 basic_iostream 提供流上的高层输入/输出支持。受支持操作包含读或写及格式化。此功能为 basic_streambuf 类所提供，在接口上实现。通过 basic_ios 类访问缓冲区。

cpp/io/ios base cpp/io/basic ios cpp/io/basic istream cpp/io/basic ostream

继承图

为常用字符类型定义二个特化：

定义于头文件 <istream>
类型 | 定义
iostream | basic_iostream<char>
wiostream | basic_iostream<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(构造函数) | 构造对象 (公开成员函数)
(析构函数) [虚] | 析构对象 (虚公开成员函数)

受保护成员函数

operator= (C++11) | 移动赋值另一 basic_iostream (受保护成员函数)
swap (C++11) | 与另一 basic_iostream 交换状态 (公开成员函数)

继承自 std::basic_istream

成员函数

有格式输入
operator>>
 提取带格式数据
(std::basic_istream<CharT,Traits> 的公开成员函数)
无格式输入
get
 从流中读并取走（移除类似指针向下一个元素移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
peek
 仅读出但不取走（不移除类似指针并未移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
unget
 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
putback
 往输入流中退回一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
getline
 一直读并取走字符，直至找到给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
ignore
 读且取走并舍弃字符，直至发现给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
read
 读并取走一块字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
readsome
 读并取走已经可用的字符块
(std::basic_istream<CharT,Traits> 的公开成员函数)
gcount
 返回上次无格式输出操作所取走的字符数量
(std::basic_istream<CharT,Traits> 的公开成员函数)
寻位
tellg
 返回输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
seekg
 设置输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
杂项
sync
 与底层存储设备同步
(std::basic_istream<CharT,Traits> 的公开成员函数)

成员类

sentry
 实现为输出操作准备流的基本逻辑
(std::basic_istream<CharT,Traits> 的公开成员类)

继承自 std::basic_ostream

成员函数

有格式输出
operator<<
 插入带格式数据
(std::basic_ostream<CharT,Traits> 的公开成员函数)
无格式输出
put
 插入字符
(std::basic_ostream<CharT,Traits> 的公开成员函数)
write
 插入字符块
(std::basic_ostream<CharT,Traits> 的公开成员函数)
寻位
tellp
 返回输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
seekp
 设置输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
杂项
flush
 与底层存储设备同步
(std::basic_ostream<CharT,Traits> 的公开成员函数)

成员类

sentry
 为输出操作实现流准备的基本逻辑
(std::basic_ostream<CharT,Traits> 的公开成员类)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)

参阅

输入/输出操纵符


std::basic_iostream<CharT,Traits>::basic_iostream

< cpp‎ | io‎ | basic iostream
explicit basic_iostream( std::basic_streambuf <CharT,Traits>* sb ); | (1) |
basic_iostream( const basic_iostream& other ) = delete; | (2) | (C++11 起)
protected: basic_iostream( basic_iostream&& other ); | (3) | (C++11 起)

构造新的流对象。

1) 以 streambuf sb 初始化。基类初始化为 basic_istream<CharT,Traits>(sb) 和 basic_ostream<CharT,Traits>(sb) 。调用后 rdbuf() == sb 而 gcount() == 0 。
2) 不允许复制构造。
3) 移动构造函数：移动构造第一基类 basic_istream 为 basic_istream<CharT,Traits>(std::move(rhs)); ，这会继续移动构造并初始化虚基类 std::basic_ios 。另一基类 basic_ostream 的初始化是实现定义的（例如，可以添加不做任何事的受保护默认构造函数到 std::basic_ostream ），因为移动构造不能使用 rhs 二次。此移动构造函数受保护：它为导出流类 std::basic_fstream 和 std::basic_stringstream 的移动构造函数在它们移动并关联流缓冲前调用。

参数

sb | - | 用以初始化的 streambuf
other | - | 用以初始化的另一流

参阅

operator=
(C++11)
 移动赋值另一 basic_iostream
(受保护成员函数)


std::basic_iostream<CharT,Traits>::operator=

< cpp‎ | io‎ | basic iostream
basic_iostream& operator=( const basic_iostream& other ) = delete; | (1) |
protected: basic_iostream& operator=( basic_iostream&& other ); | (2) | (C++11 起)

赋值另一流对象。

1) 不允许复制赋值。
2) 移动赋值另一流对象。等效地调用 swap(rhs) 。此移动赋值运算符受保护：它为导出流类 std::basic_stringstream 和 std::basic_fstream 的移动赋值运算符所调用，这些运算符知晓如何正确地移动赋值关联的流缓冲。

参数

other - 要赋值其状态的另一流

返回值

*this

参阅

(构造函数)
 构造对象
(公开成员函数)


std::basic_iostream<CharT,Traits>::swap

< cpp‎ | io‎ | basic iostream
protected: void swap( basic_iostream& other ); | (C++11 起)

与另一输入/输出流交换状态。等效地调用 basic_istream<CharT,Traits>::swap(other) 。

此成员函数受保护：导出流类 std::basic_stringstream 和 std::basic_fstream 的 swap 成员函数知晓如何正确交换关联缓冲区，并调用此函数。

参数

other - 要交换状态的另一流

返回值

*this


std::basic_iostream<CharT,Traits>::~basic_iostream

< cpp‎ | io‎ | basic iostream
virtual ~basic_iostream();

析构输入/输出流。

注意

此析构函数不在底层流缓冲（ rdbuf() ）上进行任何操作：导出流，如 std::basic_fstream 和 std::basic_stringstream 的析构函数负责调用流缓冲的析构函数。


std::basic_ispanstream

< cpp‎ | io
定义于头文件 <spanstream> |
template< class CharT, class Traits = std::char_traits <CharT> > class basic_ispanstream; | (C++23 起)

类模板 std::basic_ispantream 实现基于固定缓冲区的流上的输入操作。

此类实质上在低层包装 std::basic_spanbuf 类型的原生设备实现到 std::basic_istream 的高层接口中。提供对独有的 std::basic_spanbuf 成员的完整接口。

std::basic_ispantream 的典型实现仅添加一个成员子对象：包装的 std::basic_spanbuf 。

cpp/io/ios base cpp/io/basic ios cpp/io/basic istream

继承图

亦为常用字符类型定义二个特化：

定义于头文件 <spanstream>
类型 | 定义
ispanstream | ispanstream<char>
wispanstream | ispanstream<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(构造函数)
(C++23)
 构造 basic_ispanstream
(公开成员函数)
(析构函数)
[虚] (C++23)
 销毁 basic_ispanstream
(虚公开成员函数)
operator=
(C++23)
 移动赋值 basic_ispanstream
(公开成员函数)
swap
(C++23)
 交换二个 basic_ispanstream 对象
(公开成员函数)
rdbuf
(C++23)
 获得包装的原生 span 设备对象的地址
(公开成员函数)
底层缓冲区操作
span
(C++23)
 获取或设置包装的 span 设备对象的底层缓冲区
(公开成员函数)

非成员函数

std::swap(std::basic_ispanstream)
(C++23)
 特化 std::swap 算法
(函数模板)

继承自 std::basic_istream

成员函数

有格式输入
operator>>
 提取带格式数据
(std::basic_istream<CharT,Traits> 的公开成员函数)
无格式输入
get
 从流中读并取走（移除类似指针向下一个元素移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
peek
 仅读出但不取走（不移除类似指针并未移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
unget
 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
putback
 往输入流中退回一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
getline
 一直读并取走字符，直至找到给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
ignore
 读且取走并舍弃字符，直至发现给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
read
 读并取走一块字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
readsome
 读并取走已经可用的字符块
(std::basic_istream<CharT,Traits> 的公开成员函数)
gcount
 返回上次无格式输出操作所取走的字符数量
(std::basic_istream<CharT,Traits> 的公开成员函数)
寻位
tellg
 返回输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
seekg
 设置输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
杂项
sync
 与底层存储设备同步
(std::basic_istream<CharT,Traits> 的公开成员函数)

成员类

sentry
 实现为输出操作准备流的基本逻辑
(std::basic_istream<CharT,Traits> 的公开成员类)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)


std::basic_ispanstream<CharT,Traits>::basic_ispanstream

< cpp‎ | io‎ | basic ispanstream

explicit basic_ispanstream( std::span<CharT> s, std::ios_base::openmode mode =
std::ios_base::in );
 (1) (C++23 起)
template< class ROS >
explicit basic_ispanstream( ROS&& r );
 (2) (C++23 起)
basic_ispanstream( basic_ispanstream&& rhs );
 (3) (C++23 起)
basic_ispanstream( const basic_ispanstream& ) = delete;
 (4) (C++23 起)

构造新的 basic_ispanstream 。

1) 以 s 所引用的存储为包装的 std::basic_spanbuf 设备的初始底层缓冲区。以 basic_spanbuf<Char, Traits>(s, mode | std::ios_base::in ) 构造包装的 std::basic_spanbuf 对象。
2) 以 r 转换到 std::span<const CharT> 后所引用的存储为包装的 std::basic_spanbuf 设备的初始底层缓冲区。以模式 std::ios_base::in 打开包装的 std::basic_spanbuf 对象。此重载仅若 ROS 实现 borrowed_range ， std::convertible_to<ROS, std::span<CharT>> 为 false 且 std::convertible_to<ROS, std::span<const CharT>> 为 true才参与重载决议 。
3) 移动构造函数。从 rhs 的 std::basic_istream 基类子对象和包装的 std::basic_spanbuf 移动构造对应的子对象，然后以 *this 中包装的 std::basic_spanbuf 的地址调用 set_rdbuf 以安装它。
4) 复制构造函数被删除。 basic_ispanstream 不可复制。

参数

s - 引用要作为流的初始底层缓冲区的存储的 std::span
r - 要用作流的初始底层缓冲区的 borrowed_range
mode - 指定打开模式。可以用下列常量或它们之间的逐位或：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾
other - 要移动的另一 basic_ispanstream

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

(构造函数)
(C++23)
 构造 basic_spanbuf 对象
(std::basic_spanbuf<CharT,Traits> 的公开成员函数)


std::basic_ispanstream<CharT,Traits>::operator=

< cpp‎ | io‎ | basic ispanstream

basic_ispanstream& operator=( basic_ispanstream&& other ); | (1) | (C++23 起)
basic_ispanstream& operator=( const basic_ispanstream& ) = delete; | (2) | (C++23 起)
1) 移动赋值 other 给 *this ，等效地移动赋值 std::basic_istream 基类子对象和包装的 std::basic_spanbuf 。
2) 复制赋值运算符被删除。 basic_ispanstream 不可复制赋值。

注意基类的移动赋值运算符在 *this 与 other 间交换所有流状态变量（除了 rdbuf() ）。

包装于 other 的 std::basic_spanbuf 在移动赋值后是否仍然保有底层缓冲区是实现定义的。

参数

other - 要移动的另一流

返回值

*this

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

operator= (C++23) | 赋值 basic_spanbuf 对象 (std::basic_spanbuf<CharT,Traits> 的公开成员函数)
operator= (C++11) | 从另一 basic_istream 移动赋值 (受保护成员函数)


std::basic_ispanstream<CharT,Traits>::rdbuf

< cpp‎ | io‎ | basic ispanstream

std::basic_spanbuf<CharT, Traits>* rdbuf() const noexcept; | (C++23 起)

返回指向包装的原生设备对象的指针。

参数

（无）

返回值

指向包装的原生设备对象的指针。

示例

本节未完成
原因：暂无示例


std::basic_ispanstream<CharT,Traits>::span

< cpp‎ | io‎ | basic ispanstream

std::span<const CharT> span() const noexcept; | (1) | (C++23 起)
void span( std::span<CharT> s ) noexcept; | (2) | (C++23 起)
template< class ROS > void span( ROS&& r ) noexcept; | (3) | (C++23 起)
1) 若包装的 std::basic_spanbuf 的打开模式中设置了 std::ios_base::out ，则获取引用被写入区域的 span ，否则获取引用底层缓冲区的 span 。
2) 使包装的 std::basic_spanbuf 进行 s 所引用的缓冲区上的 I/O 。
3) 同 (2) ，除了如同通过
std::span<const CharT> cs{ std::forward <ROS>(r)};
std::span<CharT> s{const_cast<CharT*>(cs.data()), cs.size()};
获得 s 。此重载仅若 ROS 实现 borrowed_range ， std::convertible_to<ROS, std::span<CharT>> 为 false 而 std::convertible_to<ROS, std::span<const CharT>> 为 true 才参与重载决议。

参数

s | - | 引用要用作流的新底层缓冲区的 std::span
r | - | 要用做流的新底层缓冲区的 borrowed_range

返回值

1) 引用底层缓冲区或已写入区域的 std::span ，取决于包装的 std::basic_spanbuf 的打开模式。
2-3) （无）

示例

本节未完成
原因：暂无示例

参阅

span
(C++23)
 根据模式获得或初始化底层缓冲区
(std::basic_spanbuf<CharT,Traits> 的公开成员函数)


std::basic_ispanstream<CharT,Traits>::swap

< cpp‎ | io‎ | basic ispanstream

void swap( basic_ispanstream& other ); | (C++23 起)

和 other 交换流状态。

这是通过调用 std::basic_istream <CharT, Traits>::swap(other) 和交换包装的 std::basic_spanbuf 对象（可通过 *rdbuf() 访问）进行的。

参数

other - 要与之交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++23)
 交换二个 basic_spanbuf 对象
(std::basic_spanbuf<CharT,Traits> 的公开成员函数)


std::swap(std::basic_ispanstream)

< cpp‎ | io‎ | basic ispanstream

定义于头文件 <spanstream>
template< class CharT, class Traits >

void swap( std::basic_ispanstream<CharT, Traits>& lhs,

std::basic_ispanstream<CharT, Traits>& rhs );
 (C++23 起)

对 std::basic_ispanstream 重载 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++23)
 交换二个 basic_ispanstream 对象
(公开成员函数)


std::basic_istream

< cpp‎ | io
定义于头文件 <istream>
template<

class CharT,
class Traits = std::char_traits <CharT>

> class basic_istream : virtual public std::basic_ios <CharT, Traits>

类模板 basic_istream 提供字符流上的高层输入支持。受支持操作包含带格式的输入（例如整数值或空白符分隔的字符与字符串）和无格式输入（例如未处理字符和字符数组）。此功能以通过 basic_ios 基类访问的底层 basic_streambuf 类所提供的接口实现。大多数库实现中， basic_istream 有一个非继承数据成员：用于存储 basic_istream::gcount() 所返回的值。

cpp/io/ios base cpp/io/basic ios

继承图

它对常用字符类型定义了二个具体类：

定义于头文件 <istream>
类型 | 定义
istream | basic_istream<char>
wistream | basic_istream<wchar_t>

全局对象

标准库提供二个全局 basic_istream 对象。

定义于头文件 <iostream>
cinwcin
 从标准 C 输入流 stdin 中读取
(全局对象)

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(构造函数)
 构造对象
(公开成员函数)
(析构函数)
[虚]
 析构对象
(虚公开成员函数)
operator=
(C++11)
 从另一 basic_istream 移动赋值
(受保护成员函数)
带格式的输入
operator>>
 提取带格式数据
(公开成员函数)
无格式输入
get
 从流中读并取走（移除类似指针向下一个元素移动）一个字符
(公开成员函数)
peek
 仅读出但不取走（不移除类似指针并未移动）一个字符
(公开成员函数)
unget
 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符
(公开成员函数)
putback
 往输入流中退回一个字符
(公开成员函数)
getline
 一直读并取走字符，直至找到给定字符
(公开成员函数)
ignore
 读且取走并舍弃字符，直至发现给定字符
(公开成员函数)
read
 读并取走一块字符
(公开成员函数)
readsome
 读并取走已经可用的字符块
(公开成员函数)
gcount
 返回上次无格式输出操作所取走的字符数量
(公开成员函数)
寻位
tellg
 返回输入位置指示器
(公开成员函数)
seekg
 设置输入位置指示器
(公开成员函数)
杂项
sync
 与底层存储设备同步
(公开成员函数)
swap
(C++11)
 交换流对象，除了关联的缓冲区
(受保护成员函数)

成员类

sentry
 实现为输出操作准备流的基本逻辑
(公开成员类)

非成员函数

operator>>(std::basic_istream)
 提取字符和字符数组
(函数模板)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)


std::basic_istream<CharT,Traits>::basic_istream

< cpp‎ | io‎ | basic istream
explicit basic_istream( std::basic_streambuf <CharT, Traits>* sb); | (1) |
protected: basic_istream( const basic_istream& rhs ) = delete; | (2) | (C++11 起)
protected: basic_istream( basic_istream&& rhs ); | (3) | (C++11 起)

1) 构造 basic_istream 对象，通过调用 basic_ios::init(sb) 赋初始值给基类。初始化 gcount() 的值为零。

2) 复制构造函数为受保护，且被删除。输入流不可复制。

3) 移动构造函数从 rhs 复制 gcount() 的值，设置 rhs 的 gcount() 值为零，并使用 basic_ios<CharT, Traits>::move(rhs) 从 rhs 移动所有 basic_ios 成员，除了 rdbuf() 到 *this 中。此移动构造函数受保护：它为可移动输入流类 std::basic_ifstream 和 std::basic_istringstream 的移动构造函数调用，它们知道如何正确地移动关联流缓冲。

参数

sb - 用作底层设备的流缓冲

示例

#include <sstream>
#include <iostream>

int main()
{
    std::istringstream s1("hello");
    std::istream s2(s1.rdbuf());                        // OK ： s2 与 s1 共享缓冲

//    std::istream s3(std::istringstream("test"));      // 错误：移动构造函数为受保护
//    std::istream s4(s2);                              // 错误：复制构造函数被删除
    std::istringstream s5(std::istringstream("world")); // OK ：导出类调用移动构造函数

    std::cout << s2.rdbuf() << ' ' << s5.rdbuf() << '\n';
}

输出：

hello world


std::basic_istream<CharT,Traits>::gcount

< cpp‎ | io‎ | basic istream
std::streamsize gcount() const;

返回最近的无格式输入操作所提取的字符数，或若该数不可表示则返回 std::streamsize 的最大可表示值。

basic_istream 的下列成员函数更改后继的 gcount() 调用的值：

  • 移动构造函数
  • swap()
  • get()
  • getline()
  • ignore()
  • read()
  • readsome()
  • operator>>(basic_streambuf*)

下列函数设置 gcount() 为零：

  • 构造函数
  • putback()
  • unget()
  • peek()

参数

（无）

返回值

最近的无格式输入操作所提取的字符数，或若该数不可表示则返回 std::streamsize 的最大可表示值。

示例

#include <iostream>
#include <sstream>

int main()
{
    char x[20];
    std::istringstream stream("Hello World");

    stream.read(x, sizeof x);
    std::cout << "Characters extracted: " << stream.gcount();
}

输出：

Characters extracted: 11

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3464 | C++98 | 结果溢出时返回值未指定 | 返回最大值


std::basic_istream<CharT,Traits>::get

< cpp‎ | io‎ | basic istream
int_type get(); | (1)
basic_istream& get( char_type& ch ); | (2)
basic_istream& get( char_type* s, std::streamsize count ); | (3)
basic_istream& get( char_type* s, std::streamsize count, char_type delim ); | (4)
basic_istream& get( basic_streambuf& strbuf ); | (5)
basic_istream& get( basic_streambuf& strbuf, char_type delim ); | (6)

从流释出字符或多个字符。

所有版本都表现为无格式输入函数 (UnformattedInputFunction) 。构造并检查 sentry 对象后，这些函数进行下列内容：

1) 读取一个字符，若可用则返回它。否则，返回 Traits::eof() 并设置 failbit 和 eofbit 。
2) 读取一个字符，而若可用则存储于 ch 。否则，保留 ch 不修改并设置 failbit 和 eofbit 。注意此函数不在类型 signed char 和 unsigned char 重载，不同于有格式字符输入 operator>> 。
3) 同 get(s, count, widen('\n')) ，即读取至多 count-1 个字符并存储它们到 s 所指向的字符串中，直至找到 '\n' 。
4) 读取字符并存储它们到首元素为 s 所指向的字符数组的相继位置。释出并存储字符，直至出现任何下列条件：
  • 已存储 count - 1 个字符
  • 输入序列中出现文件尾条件（调用 setstate(eofbit) ）
  • 下个可用输入字符 c 等于 delim ，以 Traits::eq(c, delim) 确定。不释出此字符（不同于 basic_istream::getline() ）。
若未释出字符，则调用 setstate(failbit) 。任何情况下，若 count>0 ，则存储空字符（ CharT() ）于数组的下个相继位置。
5) 同 get(strbuf, widen('\n')) ，即读取可用字符并插入它们到给定的 basic_streambuf 对象，直至找到 '\n' 。
6) 读取字符并插入它们到给定的 basic_streambuf 对象所控制的输出序列。释出并插入字符到 strbuf 中，直至出现任何下列条件：
  • 输入序列中出现文件尾条件
  • 插入输出序列失败（该情况下不释出无法插入的字符）
  • 下个可用输入字符 c 等于 delim ，以 Traits::eq(c, delim) 确定。不释出此字符。
  • 出现异常（该情况下捕获而不重抛异常）。
若未释出字符，则调用 setstate(failbit) 。

所有版本都设置 gcount() 的值为释出的字符数。

参数

ch | - | 到要写入结果到的字符的引用
s | - | 指向要存储结果到的字符串的指针
count | - | s 所指向的字符串的大小
delim | - | 用以停止释出的分隔字符。不释出且不存储它。
strbuf | - | 要读取内容到的流缓冲

返回值

1) 释出的字符或 Traits::eof()
2-6) *this

异常

若出现错误（错误状态标志不是 goodbit ）并且设置了 exceptions() 为对该状态抛出则为 failure 。

若内部操作抛出异常，则捕获它并设置 badbit 。若对 badbit 设置了 exceptions() ，则重抛该异常。

示例

#include <sstream>
#include <iostream>

int main()
{
    std::istringstream s1("Hello, world.");
    char c1 = s1.get(); // 读取'H'
    std::cout << "after reading " << c1 << ", gcount() == " <<  s1.gcount() << '\n';
    char c2;
    s1.get(c2);         // 读取 'e'
    char str[5];
    s1.get(str, 5);     // 读取 "llo,"
    std::cout << "after reading " << str << ", gcount() == " <<  s1.gcount() << '\n';
    std::cout << c1 << c2 << str;
    s1.get(*std::cout.rdbuf()); // 读取剩余，不包括 '\n'
    std::cout << "\nAfter the last get(), gcount() == " << s1.gcount() << '\n';
}

输出：

after reading H, gcount() == 1
after reading llo,, gcount() == 4
Hello, world.
After the last get(), gcount() == 7

参阅

read | 读并取走一块字符 (公开成员函数)
operator>> | 提取带格式数据 (公开成员函数)
operator>>(std::basic_istream) | 提取字符和字符数组 (函数模板)


std::basic_istream<CharT,Traits>::getline

< cpp‎ | io‎ | basic istream
basic_istream& getline( char_type* s, std::streamsize count ); | (1)
basic_istream& getline( char_type* s, std::streamsize count, char_type delim ); | (2)

从流释出字符，直至行尾或指定的分隔符 delim 。

第一版本等价于 getline(s, count, widen('\n')) 。

表现为无格式输入函数 (UnformattedInputFunction) 。构造并检查 sentry 对象后，从 *this 释出字符并存储它们于首元素为 s 所指向的数组的相继位置，直至出现任何下列条件（按出示顺序测试）：

  • 输入序列中出现文件尾条件（该情况下执行 setstate(eofbit) ）
  • 下个可用字符 c 是以 Traits::eq(c, delim) 确定的分隔符。释出该分隔符（不同于 basic_istream::get() ）并计入 gcount() ，但不存储它。
  • 已经释出 count-1 个字符（该情况下执行 setstate(failbit) ）。

若函数未释出字符（即 count < 1 ），则执行 setstate(failbit) 。

任何情况下，若 count>0 ，则它存储空字符 CharT() 到数组的下个相继位置，并更新 gcount() 。

注意

因为条件 #2 在条件 #3 前测试，故准确适合缓冲区的输入行不会触发 failbit 。

因为终止字符计为释出的字符，故空输入行不触发 failbit 。

参数

s | - | 指向要存储字符到的字符串的指针
count | - | s 所指向的字符串的大小
delim | - | 释出所终止于的分隔字符。释出但不存储它。

返回值

*this

异常

若出现错误（错误状态标志不是 goodbit ）并且设置了 exceptions() 为对该状态抛出则为 failure 。

若内部操作抛出异常，则捕获它并设置 badbit 。若对 badbit 设置了 exceptions() ，则重抛该异常。

示例

#include <iostream>
#include <sstream>
#include <vector>
#include <array>

int main()
{
    std::istringstream input("abc|def|gh");
    std::vector<std::array<char, 4>> v;

    // 注意：下列循环在从  getline() 返回的流上的
    // std::ios_base::operator bool() 返回 false 时终止
    for (std::array<char, 4> a; input.getline(&a[0], 4, '|'); ) {
        v.push_back(a);
    }

    for (auto& a : v) {
        std::cout << &a[0] << '\n';
    }
}

输出：

abc
def
gh

参阅

getline | 从 I/O 流读取数据到字符串 (函数模板)
operator>> | 提取带格式数据 (公开成员函数)
get | 从流中读并取走（移除类似指针向下一个元素移动）一个字符 (公开成员函数)
read | 读并取走一块字符 (公开成员函数)


std::basic_istream<CharT,Traits>::ignore

< cpp‎ | io‎ | basic istream
basic_istream& ignore( std::streamsize count = 1, int_type delim = Traits::eof() );

从输入流释出并舍弃字符，直至并包含 delim 。

ignore 表现为无格式输入函数 (UnformattedInputFunction) 。构造并检查 sentry 对象后，它从流释出并舍弃字符，直至出现任一下列条件：

  • 已释出 count 个字符。在 count 等于 std::numeric_limits < std::streamsize >::max() 的特殊情况下禁用此测试。
  • 输入序列中出现文件尾条件，该情况下函数调用 setstate(eofbit) 。
  • 输入序列中下个可用字符 c 为 delim ，以 Traits::eq_int_type(Traits::to_int_type(c), delim) 确定。释出并舍弃分隔符。若 Traits::eof() 为则禁用此测试。

参数

count | - | 要释出的字符数
delim | - | 释出所止于的分隔字符。亦释出之。

返回值

*this

异常

若出现错误（错误状态标志不是 goodbit ）并且设置了 exceptions() 为对该状态抛出则为 failure 。

若内部操作抛出异常，则捕获它并设置 badbit 。若对 badbit 设置了 exceptions() ，则重抛该异常。

示例

下列代码用 ignore 跳过非数值输入：

#include <iostream>
#include <sstream>
#include <limits>

int main()
{
    std::istringstream input("1\n"
                             "some non-numeric input\n"
                             "2\n");
    for(;;) {
        int n;
        input >> n;

        if (input.eof() || input.bad()) {
            break;
        } else if (input.fail()) {
            input.clear(); // 反设置 failbit
            input.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 跳过坏输入
        } else {
            std::cout << n << '\n';
        }
    }
}

输出：

1
2

参阅

get | 从流中读并取走（移除类似指针向下一个元素移动）一个字符 (公开成员函数)
getline | 一直读并取走字符，直至找到给定字符 (公开成员函数)


std::basic_istream<CharT,Traits>::operator=

< cpp‎ | io‎ | basic istream
protected: basic_istream& operator=( const basic_istream& rhs ) = delete; | (1) |
protected: basic_istream& operator=( basic_istream&& rhs ); | (2) | (C++11 起)

1) 复制赋值运算符受保护且被删除。输入流不可复制赋值 (CopyAssignable) 。

2) 移动赋值运算符和 rhs 交换 the gcount() 值和所有基类的数据成员，除了 rdbuf() ，如同以调用 swap(*rhs) 。此移动赋值运算符为受保护：它只为导出的可移动输入流类 std::basic_ifstream 和 std::basic_istringstream 的移动赋值运算符调用，它们知道如何正确地移动赋值关联的流缓冲。

参数

rhs - 要赋值给 *this 的 basic_istream 对象

示例

#include <sstream>
#include <iostream>

int main()
{
    std::istringstream s1;
    s1 = std::istringstream("test"); // OK

    std::cin = std::istringstream("test"); // 错误： 'operator=' 为受保护
}


std::basic_istream<CharT,Traits>::operator>>

< cpp‎ | io‎ | basic istream
basic_istream& operator>>( short& value );
basic_istream& operator>>( unsigned short& value );
 (1)
basic_istream& operator>>( int& value );
basic_istream& operator>>( unsigned int& value );
 (2)
basic_istream& operator>>( long& value );
basic_istream& operator>>( unsigned long& value );
 (3)
basic_istream& operator>>( long long& value );
basic_istream& operator>>( unsigned long long& value );
 (4) (C++11 起)
basic_istream& operator>>( float& value );

basic_istream& operator>>( double& value );

basic_istream& operator>>( long double& value );
 (5)
basic_istream& operator>>( bool& value );
 (6)
basic_istream& operator>>( void*& value );
 (7)
basic_istream& operator>>( std::ios_base & (*func)( std::ios_base &) );
 (8)
basic_istream& operator>>( std::basic_ios <CharT,Traits>&
(*func)( std::basic_ios <CharT,Traits>&) );
 (9)
basic_istream& operator>>( basic_istream& (*func)(basic_istream&) );
 (10)
basic_istream& operator>>( std::basic_streambuf <CharT,Traits>* sb );
 (11)

从输入流提取值。

1-4) 提取整数值，潜在地跳过前导空格。存储值到给定的引用 value 。
此函数表现为有格式输入函数 (FormattedInputFunction) 。构造并检查 sentry 对象，可能跳过前导空格后，通过调用 std::num_get::get() 提取整数值。
5) 提取浮点值，潜在地跳过前导空格。存储值到给定的引用 value 。
此函数表现为有格式输入函数 (FormattedInputFunction) 。构造并检查 sentry 对象，可能跳过前导空格后，通过调用 std::num_get::get() 提取浮点值。
6) 提取布尔值，潜在地跳过前导空格。存储值到给定的引用 value 。
此函数表现为有格式输入函数 (FormattedInputFunction) 。构造并检查 sentry 对象，可能跳过前导空格后，通过调用 std::num_get::get() 提取 bool 值。
7) 提取泛用指针值，潜在地跳过前导空格。存储值到给定的引用 value 。
此函数表现为有格式输入函数 (FormattedInputFunction) 。构造并检查 sentry 对象，可能跳过前导空格后，通过调用 std::num_get::get() 提取泛用指针值。
8-10) 调用 func(*this) ，其中 func 为 I/O 操纵符。
11) 表现为无格式输入函数 (UnformattedInputFunction) 。在构造并检查 sentry 对象后，从输入流提取所有数据并将它存储到 sb 。若满足下列条件之一则提取停止：
  • 输入序列上出现文件尾；
  • 输出序列中插入失败（该情况下不提取要被插入的字符）；
  • 出现异常（该情况下捕捉异常，而仅若 exceptions() 中启用了 failbit 才重抛）。
任一情况下，存储提取的字符数于成员变量中，其值可由对 gcount() 的后继调用访问。若 sb 为空指针或未插入字符到 sb 中，则调用 setstate(failbit) （若启用则会抛出 std::ios_base::failure ）。

若提取失败，则写入零到 value 并设置 failbit 。若提取结果对于 value 过大或过小，则写入 std::numeric_limits <T>::max() 或 std::numeric_limits <T>::min() 并设置 failbit 标志。

参数

value | - | 到要存储提取值到的整数或浮点值的引用
func | - | 指向 I/O 操纵符函数的指针
sb | - | 指向要写入全部数据到的流缓冲的指针

返回值

1-9,11) *this
10) func(*this)

示例

#include <iostream>
#include <iomanip>
#include <sstream>

int main()
{
    std::string input = "41 3.14 false hello world";
    std::istringstream stream(input);
    int n;
    double f;
    bool b;

    stream >> n >> f >> std::boolalpha >> b;
    std::cout << "n = " << n << '\n'
              << "f = " << f << '\n'
              << "b = " << std::boolalpha << b << '\n';

    // 用 streambuf 重载提取剩余内容
    stream >> std::cout.rdbuf();
    std::cout << '\n';
}

输出：

n = 41
f = 3.14
b = false
hello world

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 696 | C++98 | 提取失败时不更改 value | 设为零或最大/最小值

参阅

operator>>(std::basic_istream) | 提取字符和字符数组 (函数模板)
operator<<operator>> | 执行字符串的流输入与输出 (函数模板)
operator<<operator>> | 执行 bitset 的流输入和输出 (函数)
operator<<operator>> | 复数的序列化和反序列化 (函数模板)
operator<<operator>> (C++11) | 执行伪随机数引擎的流输入和输出 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)
read | 读并取走一块字符 (公开成员函数)
readsome | 读并取走已经可用的字符块 (公开成员函数)
get | 从流中读并取走（移除类似指针向下一个元素移动）一个字符 (公开成员函数)
getline | 一直读并取走字符，直至找到给定字符 (公开成员函数)
from_chars (C++17) | 转换字符序列到整数或浮点值 (函数)


operator>>(std::basic_istream)

< cpp‎ | io‎ | basic istream
定义于头文件 <istream>
template< class CharT, class Traits >

basic_istream<CharT,Traits>& operator>>( basic_istream<CharT,Traits>& st, CharT& ch );

template< class Traits >
basic_istream<char,Traits>& operator>>( basic_istream<char,Traits>& st, signed char& ch );

template< class Traits >

basic_istream<char,Traits>& operator>>( basic_istream<char,Traits>& st, unsigned char& ch );
 (1)
(2)
template< class CharT, class Traits>

basic_istream<CharT,Traits>& operator>>( basic_istream<CharT,Traits>& st, CharT* s );

template< class Traits >
basic_istream<char,Traits>& operator>>( basic_istream<char,Traits>& st, signed char* s );

template< class Traits >

basic_istream<char,Traits>& operator>>( basic_istream<char,Traits>& st, unsigned char* s );
 (C++20 前)
template< class CharT, class Traits, std::size_t N >

basic_istream<CharT,Traits>& operator>>( basic_istream<CharT,Traits>& st, CharT (&s)[N] );

template< class Traits, std::size_t N >
basic_istream<char,Traits>& operator>>( basic_istream<char,Traits>& st, signed char (&s)[N] );

template< class Traits, std::size_t N >

basic_istream<char,Traits>& operator>>( basic_istream<char,Traits>& st, unsigned char (&s)[N] );
 (C++20 起)
template< class Istream, class T >
Istream&& operator>>( Istream&& st, T&& value );
 (3) (C++11 起)

1-2) 进行字符输入操作。
1) 表现为有格式输入函数 (FormattedInputFunction) 。在构造并检查 sentry 对象，因而可能跳过前导空白符后，释出一个字符并存储之到 ch。若无字符可用，则设置 failbit （在有格式输入函数 (FormattedInputFunction) 所要求的设置 eofbit 外）。
2) 表现为有格式输入函数 (FormattedInputFunction) 。在构造并检查 sentry 对象，因而可能跳过前导空白后，释出相继字符，并存储它们到 s 指向其首元素的字符数组 (C++20 前)的相继位置。若满足下列条件之一，则释出停止：
  • 找到空白字符（以 ctype<CharT> 平面确定）。不释出该空白字符。
  • 释出了 st.width() - 1 个字符（若 st.width() 大于零）
 (C++20 前)
  • 释出了 min( std::size_t (st.width()), N) - 1 个字符（若 st.width() 大于零）
  • 否则为释出了 N - 1 个字符
 (C++20 起)
  • 输入序列中出现文件尾（也会设置 eofbit ）
任一情况下，存储额外的空字符值 CharT() 于输出结尾。若未释出字符，则设置 failbit （仍写入空字符到输出的首位置）。最后调用 st.width(0) 取消 std::setw 的效果，若存在。
3) 给定到输入流对象的右值引用，调用适合的释出运算符（等价于 st >> std::forward <T>(value) ）。此重载仅若表达式 st >> std::forward <T>(value) 为良构且 Istream 为公开且无歧义派生自 std::ios_base 的类类型才参与重载决议。

注解

释出作为流的最末字符的单个字符不会设置 eofbit ：这异于有格式输入函数，例如以 operator>> 释出最末的整数，但此行为匹配 std::scanf 用 "%c" 格式指定符的行为。

参数

st | - | 要自之释出数据的输入流
ch | - | 到要存储释出字符的字符的引用
s | - | 指针，指向 (C++20 前)要存储释出字符的字符数组

返回值

st

示例

#include <iostream>
#include <iomanip>
#include <sstream>

int main()
{
    std::string input = "n greetings";
    std::istringstream stream(input);
    char c;
    const int MAX = 6;
    char cstr[MAX];

    stream >> c >> std::setw(MAX) >> cstr;
    std::cout << "c = " << c << '\n'
              << "cstr = " << cstr << '\n';

    double f;
    std::istringstream("1.23") >> f; // 右值流释出
    std::cout << "f = " << f << '\n';
}

输出：

c = n
cstr = greet
f = 1.23

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 1203 | C++11 | 右值流的重载返回到基类的左值引用 | 返回到派生类的右值引用
LWG 2328 | C++11 | 右值流的重载要求另一参数为左值 | 使之接受右值
LWG 2534 | C++11 | 右值流的重载未被制约 | 已制约

参阅

operator>>
 提取带格式数据
(公开成员函数)


std::basic_istream<CharT,Traits>::peek

< cpp‎ | io‎ | basic istream
int_type peek();

表现为无格式输入函数 (UnformattedInputFunction) 。构造并测试 sentry 对象后，从输入流读取下个字符而不释出它。

参数

（无）

返回值

若 good() == true ，则返回获得自 rdbuf()->sgetc() 的下个字符。

否则，返回 Traits::eof() 。

异常

若出现错误（错误状态标志不是 goodbit ）并且设置了 exceptions() 为对该状态抛出则为 failure 。

若内部操作抛出异常，则捕获它并设置 badbit 。若对 badbit 设置了 exceptions() ，则重抛该异常。

示例

#include <sstream>
#include <iostream>
int main()
{
    std::istringstream s1("Hello, world.");
    char c1 = s1.peek();
    char c2 = s1.get();
    std::cout << "Peeked: " << c1 << " got: " << c2 << '\n';
}

输出：

Peeked: H got: H

参阅

sgetc | 从输入序列读取一个字符，而不令序列前进 (std::basic_streambuf<CharT,Traits> 的公开成员函数)
get | 从流中读并取走（移除类似指针向下一个元素移动）一个字符 (公开成员函数)
unget | 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符 (公开成员函数)


std::basic_istream<CharT,Traits>::putback

< cpp‎ | io‎ | basic istream
basic_istream& putback( char_type ch );

回放字符 ch 到输入流，从使得下个释出的字符将为 ch 。

首先清除 eofbit ，然后表现为无格式输入函数 (UnformattedInputFunction) 。构造并检查 sentry 对象后，若 rdbuf() 非空，则调用 rdbuf()->sputbackc(ch) ，若 ch 不等于最近输出的字符，则它调用 rdbuf()->pbackfail(ch) 。

若 rdbuf() 为空或若 rdbuf->sputbackc(ch) 返回 Traits::eof() ，则调用 setstate(badbit) 。

任何情况下，设置 gcount() 计数器为零。

参数

ch - 要放入输入流的字符

返回值

*this

异常

若出现错误（错误状态标志不是 goodbit ）并且设置了 exceptions() 为对该状态抛出则为 failure 。

若内部操作抛出异常，则捕获它并设置 badbit 。若对 badbit 设置了 exceptions() ，则重抛该异常。

示例

演示修改和非修改 putback() 间的差异

#include <sstream>
#include <iostream>

int main()
{
    std::stringstream s1("Hello, world"); // IO 流
    s1.get();
    if (s1.putback('Y')) // 修改缓冲区
        std::cout << s1.rdbuf() << '\n';
    else
        std::cout << "putback failed\n";

    std::istringstream s2("Hello, world"); // 仅输入流
    s2.get();
    if (s2.putback('Y')) // cannot modify input-only buffer
        std::cout << s2.rdbuf() << '\n';
    else
        std::cout << "putback failed\n";

    s2.clear();
    if (s2.putback('H')) // 非修改回放
        std::cout << s2.rdbuf() << '\n';
    else
        std::cout << "putback failed\n";
}

输出：

Yello, world
putback failed
Hello, world

参阅

sputbackc | 在输入序列中放回一个字符 (std::basic_streambuf<CharT,Traits> 的公开成员函数)
unget | 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符 (公开成员函数)
peek | 仅读出但不取走（不移除类似指针并未移动）一个字符 (公开成员函数)


std::basic_istream<CharT,Traits>::read

< cpp‎ | io‎ | basic istream
basic_istream& read( char_type* s, std::streamsize count );

从流释出字符。

表现为无格式输入函数 (UnformattedInputFunction) 。构造并检查 sentry 对象后，释出字符并存储它们到首元素为 s 所指向的字符数组的相继位置。释出并存储字符，直至出现任何下列条件：

  • 释出并存储了 count 个字符
  • 输入序列上的文件尾条件（该情况下调用 setstate(failbit|eofbit) ）。成功释出的字符数能用 gcount() 查询。

参数

s | - | 指向要存储字符到的字符数组的指针
count | - | 要读取的字符数

返回值

*this

异常

若出现错误（错误状态标志不是 goodbit ）并且设置了 exceptions() 为对该状态抛出则为 failure 。

若内部操作抛出异常，则捕获它并设置 badbit 。若对 badbit 设置了 exceptions() ，则重抛该异常。

注意

使用非转换的本地环境时（默认本地环境为非转换），此函数在 std::basic_ifstream 中的覆写者可以为零复制的大块 I/O 优化（通过覆写 std::streambuf::xsgetn ）。

示例

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstdint>

int main()
{
    // read() 常用于二进制 I/O
    std::string bin = {'\x12', '\x12', '\x12', '\x12'};
    std::istringstream raw(bin);
    std::uint32_t n;
    if(raw.read(reinterpret_cast<char*>(&n), sizeof n))
        std::cout << std::hex << std::showbase << n << '\n';

    // 为下个片段准备文件
    std::ofstream("test.txt", std::ios::binary) << "abcd1\nabcd2\nabcd3";

    // 读取整个文件到 string
    if(std::ifstream is{"test.txt", std::ios::binary | std::ios::ate}) {
        auto size = is.tellg();
        std::string str(size, '\0'); // 构造 string 为流大小
        is.seekg(0);
        if(is.read(&str[0], size))
            std::cout << str << '\n';
    }
}

输出：

0x12121212
abcd1
abcd2
abcd3

参阅

write | 插入字符块 (std::basic_ostream<CharT,Traits> 的公开成员函数)
operator>> | 提取带格式数据 (公开成员函数)
readsome | 读并取走已经可用的字符块 (公开成员函数)
get | 从流中读并取走（移除类似指针向下一个元素移动）一个字符 (公开成员函数)
getline | 一直读并取走字符，直至找到给定字符 (公开成员函数)
fread | 从文件读取 (函数)


std::basic_istream<CharT,Traits>::readsome

< cpp‎ | io‎ | basic istream
std::streamsize readsome( char_type* s, std::streamsize count );

从输入流释出至多 count 个立即可用的字符。存储释出的字符于 s 所指向的字符数组。

表现为无格式输入函数 (UnformattedInputFunction) 。构造并检查 sentry 对象后，

  • 若 rdbuf()->in_avail() == -1 ，则调用 setstate(eofbit) 而不释出字符。
  • 若 rdbuf()->in_avail() == 0 ，则不释出字符。
  • 若 rdbuf()->in_avail() > 0 ，则释出 std::min (rdbuf()->in_avail(), count) 个字符，并存储它们到首元素为 s 所指向的字符数组的相继位置。

参数

s | - | 指向要存储字符到的字符数组的指针
count | - | 要读取的最大字符数

返回值

实际释出的字符数。

异常

若出现错误（错误状态标志不是 goodbit ）并且设置了 exceptions() 为对该状态抛出则为 failure 。

若内部操作抛出异常，则捕获它并设置 badbit 。若对 badbit 设置了 exceptions() ，则重抛该异常。

注意

此函数的行为是高度实现限定的。例如，以 std::ifstream 使用时，某些库实现在文件打开时立即以数据填充底层 filebuf （而这种实现上 readsome() 读取的数据潜在地，但不必为整个文件），而其他实现仅在请求实际输入操作时从文件读取（而文件打开后立即作出的 readsome() 决不释出任何字符）。类似地，调用 std::cin.readsome() 可能返回所有悬置的未处理控制台输入，或可能始终返回零并且不释出字符。

示例

#include <iostream>
#include <sstream>

int main()
{
    char c[10] = {};
    std::istringstream input("This is sample text."); // std::stringbuf 令个缓冲可用于无阻塞读取
    input.readsome(c, 5); // 读取 'This ' 并存储于 c[0] .. c[4]
    input.readsome(c, 9); // 读取 'is sample' 并存储于 c[0] .. c[8]
    std::cout << c;
}

输出：

is sample

参阅

read | 读并取走一块字符 (公开成员函数)
in_avail | 获得获取区中立即可用的字符数 (std::basic_streambuf<CharT,Traits> 的公开成员函数)


std::basic_istream<CharT,Traits>::seekg

< cpp‎ | io‎ | basic istream
basic_istream& seekg( pos_type pos );
basic_istream& seekg( off_type off, std::ios_base::seekdir dir);

设置当前关联 streambuf 对象的输入位置指示器，失败的情况下调用 setstate( std::ios_base::failbit ) 。

进行任何其他动作前， seekg 清除 eofbit 。

 (C++11 起)

seekg 表现为无格式输入函数 (UnformattedInputFunction) ，除了不影响 gcount() 。构造并检查 sentry 对象后，

1) 设置输入位置指示器为绝对（相对于文件起始）值 pos 。具体而言，执行 rdbuf()->pubseekpos(pos, std::ios_base::in ) 。
2) 设置输入位置指示器为相对于 dir 所定义位置的 off 。具体而言，执行 rdbuf()->pubseekoff(off, dir, std::ios_base::in ) 。

参数

pos - 设置输入位置指示器到的绝对位置。
off - 设置输入位置指示器到的相对位置。
dir - 定义应用相对偏移到的基位置。它能为下列常量之一：
常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

返回值

*this

异常

若出现错误（错误状态标志不是 goodbit ）并且设置了 exceptions() 为对该状态抛出则为 failure 。

若内部操作抛出异常，则捕获它并设置 badbit 。若对 badbit 设置了 exceptions() ，则重抛该异常。

示例

#include <iostream>
#include <string>
#include <sstream>

int main()
{
    std::string str = "Hello, world";
    std::istringstream in(str);
    std::string word1, word2;

    in >> word1;
    in.seekg(0); // 回溯
    in >> word2;

    std::cout << "word1 = " << word1 << '\n'
              << "word2 = " << word2 << '\n';
}

输出：

word1 = Hello,
word2 = Hello,

参阅

tellg | 返回输入位置指示器 (公开成员函数)
tellp | 返回输出位置指示器 (std::basic_ostream<CharT,Traits> 的公开成员函数)
seekp | 设置输出位置指示器 (std::basic_ostream<CharT,Traits> 的公开成员函数)


std::basic_istream<CharT,Traits>::sentry

< cpp‎ | io‎ | basic istream
class sentry;

类 basic_istream::sentry 的对象在每个执行输入（有格式和无格式）的 std::basic_istream 成员函数起始的块作用域构造。其构造函数准备输入流：检查流是否已在失败状态，冲入 tie() 过的输出流，除非设置 noskipws 标志否则跳过前导空白符，并若需要则进行其他实现定义任务。若需要，则在析构函数中进行所有清理，从而若输入过程中抛出异常则保证清理发生。

成员类型

traits_type Traits

成员函数

(构造函数) | 构造 sentry 对象。在此完成所有准备任务。 (公开成员函数)
(析构函数) | 若需要，则在有格式输入或异常后终止化流对象 (公开成员函数)
operator= [被删除] | 不可复制赋值 (公开成员函数)
operator bool | 检查流对象的准备是否成功 (公开成员函数)

std::basic_istream::sentry::sentry

explicit sentry( std::basic_istream <CharT,Traits>& is, bool noskipws = false);

为有格式输入准备流。

若 is.good() 为 false ，则调用 is.setstate(failbit)(C++11 起) 并返回。否则，若 is.tie() 不是空指针，则调用 is.tie()->flush() 将输出序列与外部流同步。若 is.tie() 的放置区为空则可抑制此调用。实现可以延迟到 flush 的调用，直至出现调用 is.rdbuf()->underflow() 。若在销毁 sentry 对象前不出现这种调用，则它可被完全消除。

若 noskipws 为零且 is.flags() & ios_base::skipws 非零，则函数释出并舍弃所有空白符，直至下个可用字符不是空白符（由当前 is 中感染的本地环境确定）。若 is.rdbuf()->sbumpc() 或 is.rdbuf()->sgetc() 返回 traits::eof() ，则函数调用 setstate(failbit | eofbit) （可能抛出 std::ios_base::failure ）。

可以发生另外的实现定义准备，可能调用 setstate(failbit) （可能抛出 std::ios_base::failure ）。

若准备完成后 is.good() == true ，则对 operator bool 的任何后继调用将返回 true 。

参数

is | - | 要准备的文件流
noskipws | - | 若不应跳过空白符则为 true

异常

若在跳过空白符时出现文件尾条件则为 std::ios_base::failure 。

std::basic_istream::sentry::~sentry

~sentry();

不做任何事。

std::basic_istream::sentry::operator bool

explicit operator bool() const;

检查输入流准备是否成功。

参数

（无）

返回值

若输入流初始化成功则为 true ，否则为 false 。

示例

#include <iostream>
#include <sstream>

struct Foo
{
   char n[5];
};

std::istream& operator>>(std::istream& is, Foo& f)
{
    std::istream::sentry s(is);
    if (s)
        is.read(f.n, 5);
    return is;
}

int main()
{
    std::string input = "   abcde";
    std::istringstream stream(input);
    Foo f;
    stream >> f;
    std::cout.write(f.n, 5);
    std::cout << '\n';
}

输出：

abcde

参阅

operator>> | 提取带格式数据 (公开成员函数)
operator>>(std::basic_istream) | 提取字符和字符数组 (函数模板)


std::basic_istream<CharT,Traits>::swap

< cpp‎ | io‎ | basic istream
protected: void swap(basic_istream& rhs); | (C++11 起)

调用 basic_ios::swap(rhs) 交换基类的所有数据成员，除了 rdbuf() ，再交换 *this 和 rhs 间的 gcount() 计数器值。此 swap 函数受保护：它为可交换输入流类 std::basic_ifstream 和 std::basic_istringstream 的 swap 函数所调用，它们知道如何正确地交换关联流缓冲。

参数

rhs - 与之交换的同一类型的不同 basic_istream 对象

示例

#include <sstream>
#include <iostream>
#include <utility>
int main()
{
    std::istringstream s1("hello");
    std::istringstream s2("bye");

    s1.swap(s2); // OK ： istringstream 拥有公开的 swap()
    std::swap(s1, s2); // OK ：调用 s1.swap(s2)
//  std::cin.swap(s2); // 错误： swap 是受保护成员

    std::cout << s1.rdbuf();
}

输出：

hello


std::basic_istream<CharT,Traits>::sync

< cpp‎ | io‎ | basic istream
int sync();

将输入缓冲区与关联数据源同步。

表现为无格式输入函数 (UnformattedInputFunction) ，除了不影响 gcount() 构造并检查 sentry 对象后，

若 rdbuf() 为空指针，则返回 -1 。

否则调用 rdbuf()->pubsync() 。若该函数返回 -1 ，则调用 setstate(badbit) 并返回 -1 。否则返回 ​0​ 。

参数

（无）

返回值

成功时为 ​0​ ，失败时或若流不支持此操作（无缓冲）则为 -1 。

注意

同 readsome() ，此函数是否对库提供的流做任何事是实现定义的。意图典型地是为了令下个读取操作拾取任何在流缓冲最后填充其获取区后，可能已对关联输入序列做出的更改。为达成之， sync() 可以清空获取区，或重填充它，或不做任何事。值得注意的例外是 Visual Studio ，其中此操作在以标准输入流调用时舍弃未处理的输出。

示例

演示以文件输入使用输入流 sync() ，在一些平台上实现。

#include <iostream>
#include <fstream>

void file_abc()
{
    std::ofstream f("test.txt");
    f << "abc\n";
}

void file_123()
{
    std::ofstream f("test.txt");
    f << "123\n";
}

int main()
{
    file_abc(); // 文件现在含 "abc"
    std::ifstream f("test.txt");
    std::cout << "Reading from the file\n";
    char c;
    f >> c; std::cout << c;
    file_123(); // 文件现在含 "123"
    f >> c; std::cout << c;
    f >> c; std::cout << c << '\n';
    f.close();

    file_abc(); // 文件现在含 "abc"
    f.open("test.txt");
    std::cout << "Reading from the file, with sync()\n";
    f >> c; std::cout << c;
    file_123(); // 文件现在含 "123"
    f.sync();
    f >> c; std::cout << c;
    f >> c; std::cout << c << '\n';
}

可能的输出：

Reading from the file
abc
Reading from the file, with sync()
a23

参阅

sync [虚] | 将缓冲与关联的字符序列同步 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
flush | 与底层存储设备同步 (std::basic_ostream<CharT,Traits> 的公开成员函数)


std::basic_istream<CharT,Traits>::tellg

< cpp‎ | io‎ | basic istream
pos_type tellg();

返回当前关联的 streambuf 对象的输入位置指示器。

表现为无格式输入函数 (UnformattedInputFunction) ，除了不影响 gcount() 。构造并检查 sentry 对象后，若 fail() == true ，则返回 pos_type(-1) 。否则，返回 rdbuf()->pubseekoff(0, std::ios_base::cur, std::ios_base::in ) 。

参数

（无）

返回值

成功时为获取指针的当前位置，失败时为 pos_type(-1) 。

异常

若出现错误（错误状态标志不是 goodbit ）并且设置了 exceptions() 为对该状态抛出则为 failure 。

若内部操作抛出异常，则捕获它并设置 badbit 。若对 badbit 设置了 exceptions() ，则重抛该异常。

示例

#include <iostream>
#include <string>
#include <sstream>

int main()
{
    std::string str = "Hello, world";
    std::istringstream in(str);
    std::string word;
    in >> word;
    std::cout << "After reading the word \"" << word
              << "\" tellg() returns " << in.tellg() << '\n';
}

输出：

After reading the word "Hello," tellg() returns 6

参阅

seekoff [虚] | 用相对寻址重寻位文件位置 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)
seekoff [虚] | 用相对寻址，重定位输入序列、输出序列或两者中的下一位置指针 (std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
seekoff [虚] | 用相对寻址重寻位输入序列、输出序列或两者中的下一位置指针 (std::strstreambuf 的虚受保护成员函数)
seekg | 设置输入位置指示器 (公开成员函数)
tellp | 返回输出位置指示器 (std::basic_ostream<CharT,Traits> 的公开成员函数)
seekp | 设置输出位置指示器 (std::basic_ostream<CharT,Traits> 的公开成员函数)


std::basic_istream<CharT,Traits>::unget

< cpp‎ | io‎ | basic istream
basic_istream& unget();

令最近释出的字符再次可用。

首先清除 eofbit 。

 (C++11 起)

然后函数表现为无格式输入函数 (UnformattedInputFunction) 。构造并检查 sentry 对象后，若设置了任何 ios_base::iostate 标志，则函数设置 failbit 并返回。否则，调用 rdbuf()->sungetc() 。

若 rdbuf()->sungetc() 返回 Traits::eof() ，则调用 setstate(badbit) 。

任何情况下，设置 gcount() 计数器为零。

参数

（无）

返回值

*this

异常

若出现错误（错误状态标志不是 goodbit ）并且设置了 exceptions() 为对该状态抛出则为 failure 。

若内部操作抛出异常，则捕获它并设置 badbit 。若对 badbit 设置了 exceptions() ，则重抛该异常。

示例

#include <sstream>
#include <iostream>

int main()
{
    std::istringstream s1("Hello, world.");
    char c1 = s1.get();
    if (s1.unget())
    {
        char c2 = s1.get();
        std::cout << "Got: " << c1 << " got again: " << c2 << '\n';
    }
}

输出：

Got: H got again: H

参阅

sungetc | 回移一位输出序列中的下一位置指针 (std::basic_streambuf<CharT,Traits> 的公开成员函数)
get | 从流中读并取走（移除类似指针向下一个元素移动）一个字符 (公开成员函数)
peek | 仅读出但不取走（不移除类似指针并未移动）一个字符 (公开成员函数)
putback | 往输入流中退回一个字符 (公开成员函数)


std::basic_istream<CharT,Traits>::~basic_istream

< cpp‎ | io‎ | basic istream
virtual ~basic_istream();

析构输入流。

注意

此析构函数不在底层流缓冲（ rdbuf() ）上进行任何操作：导出输入流，如 std::basic_ifstream 和 std::basic_istringstream 的析构函数负责调用流缓冲的析构函数。

示例

#include <sstream>
#include <iostream>

void print_stringbuf(std::streambuf* p)
{
    std::istream buf(p); // buf 与 s1 共享缓冲
    int n;
    buf >> n;
    std::cout << n;
} // 调用 buf 的析构函数。 p 保持不受影响

int main()
{
    std::istringstream s1("10 20");
    print_stringbuf(s1.rdbuf());
    int n;
    s1 >> n;
    std::cout << ',' << n << '\n';
}

输出：

10,20


std::basic_istringstream

< cpp‎ | io
定义于头文件 <sstream>
template<

class CharT,
class Traits = std::char_traits <CharT>,
class Allocator = std::allocator <CharT>

> class basic_istringstream;

类模板 std::basic_istringstream 实现基于字符串的流上的输入与输出操作。它等效地存储一个 std::basic_string 的实例，并在其上进行输入操作。

该类实际上在低层包装 std::basic_stringbuf 的原生字符串设备到 std::basic_istream 的高层接口中。提供到独有 std::basic_stringbuf 成员的完整接口。

cpp/io/ios base cpp/io/basic ios cpp/io/basic istream

继承图

亦定义对于常用字符类型的二个特化：

定义于头文件 <sstream>
类型 | 定义
istringstream | basic_istringstream<char>
wistringstream | basic_istringstream<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type
allocator_type | Allocator

成员函数

(构造函数)
 构造字符串流
(公开成员函数)
operator=
(C++11)
 移动字符串流
(公开成员函数)
swap
(C++11)
 交换两个字符串流
(公开成员函数)
rdbuf
 返回底层未处理的字符串设备对象
(公开成员函数)
字符串操作
str
 获取或设置底层字符串设备对象的内容
(公开成员函数)
view
(C++20)
 获得底层字符串设备的内容上的视图
(公开成员函数)

非成员函数

std::swap(std::basic_istringstream)
(C++11)
 特化 std::swap 算法
(函数模板)

继承自 std::basic_istream

成员函数

有格式输入
operator>>
 提取带格式数据
(std::basic_istream<CharT,Traits> 的公开成员函数)
无格式输入
get
 从流中读并取走（移除类似指针向下一个元素移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
peek
 仅读出但不取走（不移除类似指针并未移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
unget
 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
putback
 往输入流中退回一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
getline
 一直读并取走字符，直至找到给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
ignore
 读且取走并舍弃字符，直至发现给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
read
 读并取走一块字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
readsome
 读并取走已经可用的字符块
(std::basic_istream<CharT,Traits> 的公开成员函数)
gcount
 返回上次无格式输出操作所取走的字符数量
(std::basic_istream<CharT,Traits> 的公开成员函数)
寻位
tellg
 返回输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
seekg
 设置输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
杂项
sync
 与底层存储设备同步
(std::basic_istream<CharT,Traits> 的公开成员函数)

成员类

sentry
 实现为输出操作准备流的基本逻辑
(std::basic_istream<CharT,Traits> 的公开成员类)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)


std::basic_istringstream<CharT,Traits,Allocator>::basic_istringstream

< cpp‎ | io‎ | basic istringstream

basic_istringstream()
: basic_istringstream( std::ios_base::in ) { }
 (1) (C++11 起)
(2)
explicit basic_istringstream( std::ios_base::openmode mode = std::ios_base::in );
 (C++11 前)
explicit basic_istringstream( std::ios_base::openmode mode );
 (C++11 起)
explicit basic_istringstream( const std::basic_string <CharT,Traits,Allocator>& str,
std::ios_base::openmode mode = std::ios_base::in );
 (3)
basic_istringstream( basic_istringstream&& other );
 (4) (C++11 起)
basic_istringstream( std::ios_base::openmode mode, const Allocator& a );
 (5) (C++20 起)
explicit basic_istringstream( std::basic_string <CharT,Traits,Allocator>&& str,
std::ios_base::openmode mode = std::ios_base::in );
 (6) (C++20 起)
template<class SAlloc>

basic_istringstream( const std::basic_string <CharT,Traits,SAlloc>& str,
const Allocator& a )

: basic_istringstream(str, std::ios_base::in, a) { }
 (7) (C++20 起)
template<class SAlloc>

basic_istringstream( const std::basic_string <CharT,Traits,SAlloc>& str,

std::ios_base::openmode mode, const Allocator& a );
 (8) (C++20 起)
template<class SAlloc>

explicit basic_istringstream( const std::basic_string <CharT,Traits,SAlloc>& str,

std::ios_base::openmode mode = std::ios_base::in );
 (9) (C++20 起)

构造新的字符串流。

1) 默认构造函数。以默认打开模式构造新的底层字符串设备。
2) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(mode | std::ios_base::in ) 构造底层 basic_stringbuf 对象。
3) 以 str 的副本为底层字符串设备的初始内容。以 basic_stringbuf<Char,Traits,Allocator>(str, mode | std::ios_base::in ) 构造底层 basic_stringbuf 对象。
4) 移动构造函数。用移动语义，构造拥有 other 的状态的字符串流。
5) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(mode | std::ios_base::in, a) 构造底层 basic_stringbuf 对象。
6) 用 str 移动构造底层字符串设备的内容。以 basic_stringbuf<Char,Traits,Allocator>(std::move(str), mode | std::ios_base::in ) 构造底层 basic_stringbuf 对象。
7) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(str, std::ios_base::in, a) 构造底层 basic_stringbuf 对象。
8) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(str, mode | std::ios_base::in, a) 构造底层 basic_stringbuf 对象。
9) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(str, mode | std::ios_base::in ) 构造底层 basic_stringbuf 对象。

参数

str - 用于初始化字符串流内容的字符串
mode - 指定流打开模式。它是位掩码类型，定义下列常量：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾
other - 用作源的另一字符串流

注解

在短的循环中，例如在用于字符串转换时构造单次使用的 basic_istringstream 对象，开销可能显著高于调用 str 并复用同一对象。

示例

#include <iostream>
#include <sstream>
int main()
{
    // 默认构造函数（输入/输出流）
    std::stringstream buf1;
    buf1 << 7;
    int n = 0;
    buf1 >> n;
    std::cout << "buf1 = " << buf1.str() << " n = " << n << '\n';

    // 输入流
    std::istringstream inbuf("-10");
    inbuf >> n;
    std::cout << "n = " << n << '\n';

    // 输出流在 append 模式 (C++11)
    std::ostringstream buf2("test", std::ios_base::ate);
    buf2 << '1';
    std::cout << buf2.str() << '\n';
}

输出：

buf1 = 7 n = 7
n = -10
test1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式

参阅

str | 获取或设置底层字符串设备对象的内容 (公开成员函数)
(构造函数) | 构造一个 basic_stringbuf 对象 (std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)


std::basic_istringstream::operator=

< cpp‎ | io‎ | basic istringstream
basic_istringstream& operator=( basic_istringstream&& other ); | (C++11 起)

移动赋值字符串流 other 给 *this ，等效的移动赋值 std::basic_istream 基类和关联的 std::basic_stringbuf 。

注意，基类移动赋值交换 *this 与 other 间的所有流状态变量（除了 rdbuf ）。

参数

other - 移动来源的字符串流

返回值

*this

示例

本节未完成
原因：暂无示例

参阅

swap (C++11) | 交换两个字符串流 (公开成员函数)
operator= (C++11) | 赋值 basic_stringbuf 对象 (std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)
operator= (C++11) | 从另一 basic_istream 移动赋值 (受保护成员函数)


std::basic_istringstream::rdbuf

< cpp‎ | io‎ | basic istringstream

std::basic_stringbuf <CharT, Traits, Allocator>* rdbuf() const;

返回指向底层未处理字符串设备对象的指针。

参数

（无）

返回值

指向底层未处理字符串设备对象的指针。

示例

本节未完成
原因：暂无示例


std::basic_istringstream<CharT,Traits,Allocator>::str

< cpp‎ | io‎ | basic istringstream

 | (1) |
std::basic_string <CharT,Traits,Allocator> str() const; |  |  | (C++20 前)
std::basic_string <CharT,Traits,Allocator> str() const&; |  |  | (C++20 起)
template<class SAlloc> std::basic_string <CharT,Traits,SAlloc> str( const SAlloc& a ) const; | (2) | (C++20 起)
std::basic_string <CharT,Traits,Allocator> str() &&; | (3) | (C++20 起)
void str( const std::basic_string <CharT,Traits,Allocator>& s ); | (4) |
template<class SAlloc> void str( const std::basic_string <CharT,Traits, SAlloc>& s ); | (5) | (C++20 起)
void str( std::basic_string <CharT,Traits,Allocator>&& s ); | (6) | (C++20 起)

管理底层字符串对象的内容。

1) 返回底层字符串的副本。等价于 return rdbuf()->str(); 。
2) 返回底层字符串的副本，以 a 为分配器。等价于 return rdbuf()->str(a); 。
3) 返回从底层字符串移动构造的字符串。等价于 return std::move(*rdbuf()).str(); 。
4-5) 替换底层字符串。等价于 rdbuf()->str(s); 。
6) 替换底层字符串。等价于 rdbuf()->str(std::move(s)); 。

参数

s | - | 底层字符串的新内容
a | - | 用于构造返回的字符串的分配器

返回值

1-2) 底层字符串对象的副本。
3) 从底层字符串对象移动构造的字符串。
4-6) （无）

注解

str 所返回的底层字符串副本是将于表达式结尾析构的临时对象，故在 str() 的结果上直接调用 c_str() （例如 auto *ptr = out.str().c_str(); 中）导致悬垂指针。

示例

#include <sstream>
#include <iostream>
int main()
{
    int n;

    std::istringstream in;  // 亦可使用 in("1 2")
    in.str("1 2");
    in >> n;
    std::cout << "after reading the first int from \"1 2\", the int is "
              << n << ", str() = \"" << in.str() << "\"\n";

    std::ostringstream out("1 2");
    out << 3;
    std::cout << "after writing the int '3' to output stream \"1 2\""
              << ", str() = \"" << out.str() << "\"\n";

    std::ostringstream ate("1 2", std::ios_base::ate);
    ate << 3;
    std::cout << "after writing the int '3' to append stream \"1 2\""
              << ", str() = \"" << ate.str() << "\"\n";
}

输出：

after reading the first int from "1 2", the int is 1, str() = "1 2"
after writing the int '3' to output stream "1 2", str() = "3 2"
after writing the int '3' to append stream "1 2", str() = "1 23"

参阅

str
 替换或获得关联字符串的副本
(std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)


std::basic_istringstream::swap

< cpp‎ | io‎ | basic istringstream

void swap( basic_istringstream& other ); | (C++11 起)

交换流与 other 的状态。

通过调用 basic_istream<CharT, Traits>::swap(other) 和 rdbuf()->swap(*other.rdbuf()) 进行。

参数

other - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

operator= (C++11) | 移动字符串流 (公开成员函数)
swap (C++11) | 交换二个 basic_stringbuf 对象 (std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)


std::swap(std::basic_istringstream)

< cpp‎ | io‎ | basic istringstream

定义于头文件 <sstream>
template< class CharT, class Traits, class Alloc >

void swap( std::basic_istringstream <CharT,Traits,Alloc>& lhs,

std::basic_istringstream <CharT,Traits,Alloc>& rhs );
 (C++11 起)

对 std::basic_istringstream 重载 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++11)
 交换两个字符串流
(公开成员函数)


std::basic_istringstream<CharT,Traits,Allocator>::view

< cpp‎ | io‎ | basic istringstream

std::basic_string_view <CharT, Traits> view() const noexcept; | (C++20 起)

获得底层字符串对象上的 std::basic_string_view 。等价于 return rdbuf()->view(); 。

参数

（无）

返回值

底层字符串对象上的 std::basic_string_view 。

示例

本节未完成
原因：暂无示例

参阅

view
(C++20)
 获得底层字符序列上的视图
(std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)


std::basic_ofstream

< cpp‎ | io
定义于头文件 <fstream>
template<

class CharT,
class Traits = std::char_traits <CharT>

> class basic_ofstream : public std::basic_ostream <CharT, Traits>

类模板 basic_ofstream 实现文件上基于流的高层输出操作。它将 std::basic_ostream 的高层接口赋予基于文件的流缓冲（ std::basic_filebuf ）。

std::basic_ofstream 典型实现只保有一个非导出成员： std::basic_filebuf <CharT, Traits> 的实例。

cpp/io/ios base cpp/io/basic ios cpp/io/basic ostream

继承图

亦对常用字符类型定义二个特化：

定义于头文件 <fstream>
类型 | 定义
ofstream | basic_ofstream<char>
wofstream | basic_ofstream<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(构造函数)
 构造文件流
(公开成员函数)
(析构函数)
[虚] (隐式声明)
 析构 basic_ofstream 和关联的缓冲区，并关闭文件
(虚公开成员函数)
operator=
(C++11)
 移动文件流
(公开成员函数)
swap
(C++11)
 交换二个文件流
(公开成员函数)
rdbuf
 返回底层未处理的文件设备对象
(公开成员函数)
文件操作
is_open
 检查流是否有关联文件
(公开成员函数)
open
 打开文件，并将它与流关联
(公开成员函数)
close
 关闭关联文件
(公开成员函数)

非成员函数

std::swap(std::basic_ofstream)
(C++11)
 特化 std::swap 算法
(函数模板)

继承自 std::basic_ostream

成员函数

有格式输出
operator<<
 插入带格式数据
(std::basic_ostream<CharT,Traits> 的公开成员函数)
无格式输出
put
 插入字符
(std::basic_ostream<CharT,Traits> 的公开成员函数)
write
 插入字符块
(std::basic_ostream<CharT,Traits> 的公开成员函数)
寻位
tellp
 返回输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
seekp
 设置输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
杂项
flush
 与底层存储设备同步
(std::basic_ostream<CharT,Traits> 的公开成员函数)

成员类

sentry
 为输出操作实现流准备的基本逻辑
(std::basic_ostream<CharT,Traits> 的公开成员类)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)

示例

#include <iostream>
#include <fstream>
#include <string>

int main() {
        std::string filename = "Test.b";
        {
                std::ofstream ostrm(filename, std::ios::binary);
                double d = 3.14;
                ostrm.write(reinterpret_cast<char*>(&d), sizeof d); // 二进制输出
                ostrm << 123 << "abc" << '\n';                      // 文本输出
        }

        // 回读
        std::ifstream istrm(filename, std::ios::binary);
        double d;
        istrm.read(reinterpret_cast<char*>(&d), sizeof d);
        int n;
        std::string s;
        istrm >> n >> s;
        std::cout << " read back: " << d << " " << n << " " << s << '\n';
}

输出：

read back: 3.14 123 abc


std::basic_ofstream<CharT,Traits>::basic_ofstream

< cpp‎ | io‎ | basic ofstream

basic_ofstream();
 (1)
explicit basic_ofstream( const char* filename,
std::ios_base::openmode mode = ios_base::out );
 (2)
explicit basic_ofstream( const std::filesystem::path::value_type* filename,
std::ios_base::openmode mode = ios_base::out );
 (3) (C++17 起)
explicit basic_ofstream( const std::string & filename,
std::ios_base::openmode mode = ios_base::out );
 (4) (C++11 起)
template< class T >

explicit basic_ofstream( const T& filename,

std::ios_base::openmode mode = ios_base::out );
 (5) (C++17 起)
basic_ofstream( basic_ofstream&& other );
 (6) (C++11 起)
basic_ofstream( const basic_ofstream& rhs) = delete;
 (7) (C++11 起)

构造新的文件流。

1) 默认构造函数：构造不关联到文件的流：默认构造 std::basic_filebuf 并构造拥有指向此默认构造的 std::basic_filebuf 成员的基类。
2-3) 首先，进行同默认构造函数的步骤，然后通过调用 rdbuf()->open(filename, mode | std::ios_base::out )（该调用效果上的细节见 std::basic_filebuf::open ）关联流与文件。若 open() 调用返回空指针，则设置 setstate(failbit) 。仅若 std::filesystem::path::value_type 非 char 才提供重载 (3) 。 (C++17 起)
4-5) 同 basic_ofstream(filename.c_str(), mode) 。 (5) 仅若 T 为 std::filesystem::path 才参与重载决议。 (C++17 起)注意，尽管默认模式是 out ，效果等同于描述于 std::filebuf::open 的 out|trunc 的效果。
6) 移动构造函数：首先，从 other 移动构造基类（这不影响 rdbuf() 指针），然后移动构造 std::basic_filebuf 成员，再调用 this->set_rdbuf() 安装新的 basic_filebuf 为基类中的 rdbuf() 指针。
7) 复制构造函数被删除：此类不可复制。

参数

filename - 要打开的文件名
mode - 指定打开模式。可使用下列常量或它们之间的逐位或：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾
other - 用作源的另一文件流

示例

#include <fstream>
#include <utility>
#include <string>
int main()
{
    std::ofstream f0;
    std::ofstream f1("test.bin", std::ios::binary);
    std::string name = "example.txt";
    std::ofstream f2(name);
    std::ofstream f3(std::move(f1));
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3430 | C++17 | std::filesystem::path 重载导致了不想要的转换 | 使之为模板以避免

参阅

open | 打开文件，并将它与流关联 (公开成员函数)
open | 打开文件并配置它为关联字符序列 (std::basic_filebuf<CharT,Traits> 的公开成员函数)
set_rdbuf | 替换 rdbuf 而不清除其错误状态 (受保护成员函数)
(构造函数) | 构造对象 (std::basic_ostream<CharT,Traits> 的公开成员函数)


std::basic_ofstream<CharT,Traits>::close

< cpp‎ | io‎ | basic ofstream

void close();

关闭关联文件。

等效地调用 rdbuf()->close() 。若操作期间出现错误，则调用 setstate(failbit) 。

参数

（无）

返回值

（无）

注意

此函数为 basic_ofstream 的析构函数在流对象离开作用域时调用，通常不直接调用。

示例

本节未完成
原因：暂无示例

参阅

is_open | 检查流是否有关联文件 (公开成员函数)
open | 打开文件，并将它与流关联 (公开成员函数)
close | 冲入放置区缓冲区并关闭关联的文件 (std::basic_filebuf<CharT,Traits> 的公开成员函数)


std::basic_ofstream<CharT,Traits>::is_open

< cpp‎ | io‎ | basic ofstream

bool is_open(); | (C++11 前)
bool is_open() const; | (C++11 起)

检查文件流是否有关联文件。

等效地调用 rdbuf()->is_open() 。

参数

（无）

返回值

若文件流有关联文件，则为 true ，否则为 false 。

示例

本节未完成
原因：暂无示例

参阅

open | 打开文件，并将它与流关联 (公开成员函数)
close | 关闭关联文件 (公开成员函数)


std::basic_ofstream<CharT,Traits>::open

< cpp‎ | io‎ | basic ofstream

void open( const char *filename,
ios_base::openmode mode = ios_base::out );
 (1)
void open( const std::filesystem::path::value_type *filename,
ios_base::openmode mode = ios_base::out );
 (2) (C++17 起)
void open( const std::string &filename,
ios_base::openmode mode = ios_base::out );
 (3) (C++11 起)
void open( const std::filesystem::path &filename,
ios_base::openmode mode = ios_base::out );
 (4) (C++17 起)

将名为 filename 的文件打开并与文件流关联。

失败时调用 setstate(failbit) 。

成功时调用 clear() 。 (C++11 起)
1-2) 等效地调用 rdbuf()->open(filename, mode | ios_base::out). （该调用效果上的细节见 std::basic_filebuf::open ）。仅若 std::filesystem::path::value_type 非 char 才提供重载 (2) 。 (C++17 起)
3-4) 等效地调用 (1-2) ，如同以 open(filename.c_str(), mode) 。

参数

filename - 要打开的文件名
mode - 指定打开模式。它是位掩码类型，定义下列常量：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

is_open | 检查流是否有关联文件 (公开成员函数)
close | 关闭关联文件 (公开成员函数)
open | 打开文件并配置它为关联字符序列 (std::basic_filebuf<CharT,Traits> 的公开成员函数)


std::basic_ofstream<CharT,Traits>::operator=

< cpp‎ | io‎ | basic ofstream
basic_ofstream& operator=( basic_ofstream&& other ); | (C++11 起)

移动赋值文件流 other 给 *this ，等效地移动赋值 std::basic_ostream 基类和关联的 std::basic_filebuf 。

将 other 置为无关联文件。注意基类移动赋值交换 *this 与 other 间的所有流状态变量（除了 rdbuf ）。

参数

other - 要移动的文件流。

返回值

*this

示例

本节未完成
原因：暂无示例

参阅

swap (C++11) | 交换二个文件流 (公开成员函数)
operator= (C++11) | 赋值 basic_filebuf 对象 (std::basic_filebuf<CharT,Traits> 的公开成员函数)
operator= (C++11) | 从另一 basic_ostream 移动赋值 (受保护成员函数)


std::basic_ofstream<CharT,Traits>::rdbuf

< cpp‎ | io‎ | basic ofstream

std::basic_filebuf <CharT, Traits>* rdbuf() const; | (C++11 起)

返回指向底层未处理文件设备对象的指针。

参数

（无）

返回值

指向底层未处理文件设备对象的指针。

示例

本节未完成
原因：暂无示例


std::basic_ofstream<CharT,Traits>::swap

< cpp‎ | io‎ | basic ofstream

void swap( basic_ofstream& other ); | (C++11 起)

交换流与 other 的状态。

通过调用 basic_ostream<CharT, Traits>::swap(other) 和 rdbuf()->swap(other.rdbuf()) 进行。

参数

other - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

operator= (C++11) | 移动文件流 (公开成员函数)
swap (C++11) | 交换二个 basic_filebuf 对象 (std::basic_filebuf<CharT,Traits> 的公开成员函数)


std::swap(std::basic_ofstream)

< cpp‎ | io‎ | basic ofstream

template< class CharT, class Traits >
void swap( basic_ofstream<CharT,Traits> &lhs, basic_ofstream<CharT,Traits> &rhs );

为 std::basic_ofstream 特化 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++11)
 交换二个文件流
(公开成员函数)


std::basic_ospanstream

< cpp‎ | io
定义于头文件 <spanstream> |
template< class CharT, class Traits = std::char_traits <CharT> > class basic_ospanstream; | (C++23 起)

类模板 std::basic_ospanstream 实现基于固定缓冲区的流上的输出操作。

此类实质上在低层包装 std::basic_spanbuf 类型的原生设备实现到 std::basic_ostream 的高层接口中。提供对独有的 std::basic_spanbuf 成员的完整接口。

std::basic_ospantream 的典型实现仅添加一个成员子对象：包装的 std::basic_spanbuf 。

cpp/io/ios base cpp/io/basic ios cpp/io/basic ostream

继承图

亦为常用字符类型定义二个特化：

定义于头文件 <spanstream>
类型 | 定义
ospanstream | basic_ospanstream<char>
wospanstream | basic_ospanstream<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(构造函数)
(C++23)
 构造 basic_ospanstream
(公开成员函数)
(析构函数)
[虚] (C++23)
 销毁 basic_ospanstream
(虚公开成员函数)
operator=
(C++23)
 移动赋值 basic_ospanstream
(公开成员函数)
swap
(C++23)
 交换二个 basic_ospanstream 对象
(公开成员函数)
rdbuf
(C++23)
 获得包装的原生 span 设备对象的地址
(公开成员函数)
底层缓冲区操作
span
(C++23)
 获取或设置包装的 span 设备对象的底层缓冲区
(公开成员函数)

非成员函数

std::swap(std::basic_ospanstream)
(C++23)
 特化 std::swap 算法
(函数模板)

继承自 std::basic_ostream

成员函数

有格式输出
operator<<
 插入带格式数据
(std::basic_ostream<CharT,Traits> 的公开成员函数)
无格式输出
put
 插入字符
(std::basic_ostream<CharT,Traits> 的公开成员函数)
write
 插入字符块
(std::basic_ostream<CharT,Traits> 的公开成员函数)
寻位
tellp
 返回输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
seekp
 设置输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
杂项
flush
 与底层存储设备同步
(std::basic_ostream<CharT,Traits> 的公开成员函数)

成员类

sentry
 为输出操作实现流准备的基本逻辑
(std::basic_ostream<CharT,Traits> 的公开成员类)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)


std::basic_ospanstream<CharT,Traits>::basic_ospanstream

< cpp‎ | io‎ | basic ospanstream

explicit basic_ospanstream( std::span<CharT> s, std::ios_base::openmode mode =
std::ios_base::out );
 (1) (C++23 起)
basic_ospanstream( basic_ospanstream&& rhs );
 (2) (C++23 起)
basic_ospanstream( const basic_ospanstream& ) = delete;
 (3) (C++23 起)

构造新的 basic_ospanstream 。

1) 以 s 所引用的存储为包装的 std::basic_spanbuf 设备的初始底层缓冲区。以 basic_spanbuf<Char, Traits>(s, mode | std::ios_base::out ) 构造包装的 std::basic_spanbuf 对象。
2) 移动构造函数。从 rhs 的 std::basic_ostream 基类子对象和包装的 std::basic_spanbuf 移动构造对应的子对象，然后以 *this 中包装的 std::basic_spanbuf 的地址调用 set_rdbuf 以安装它。
3) 复制构造函数被删除。 basic_ospanstream 不可复制。

参数

s - 引用要作为流的初始底层缓冲区的存储的 std::span
mode - 指定打开模式。可以用下列常量或它们之间的逐位或：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾
other - 要移动的另一 basic_ospanstream

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

(构造函数)
(C++23)
 构造 basic_spanbuf 对象
(std::basic_spanbuf<CharT,Traits> 的公开成员函数)


std::basic_ospanstream<CharT,Traits>::operator=

< cpp‎ | io‎ | basic ospanstream

basic_ospanstream& operator=( basic_ospanstream&& other ); | (1) | (C++23 起)
basic_ospanstream& operator=( const basic_ospanstream& ) = delete; | (2) | (C++23 起)
1) 移动赋值 other 给 *this ，等效地移动赋值 std::basic_ostream 基类子对象和包装的 std::basic_spanbuf 。
2) 复制赋值运算符被删除。 basic_ospanstream 不可复制赋值。

注意基类的移动赋值运算符在 *this 与 other 间交换所有流状态变量（除了 rdbuf() ）。

包装于 other 的 std::basic_spanbuf 在移动赋值后是否仍然保有底层缓冲区是实现定义的。

参数

other - 要移动的另一流

返回值

*this

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

operator= (C++23) | 赋值 basic_spanbuf 对象 (std::basic_spanbuf<CharT,Traits> 的公开成员函数)
operator= (C++11) | 从另一 basic_ostream 移动赋值 (受保护成员函数)


std::basic_ospanstream<CharT,Traits>::rdbuf

< cpp‎ | io‎ | basic ospanstream

std::basic_spanbuf<CharT, Traits>* rdbuf() const noexcept; | (C++23 起)

返回指向包装的原生设备对象的指针。

参数

（无）

返回值

指向包装的原生设备对象的指针。

示例

本节未完成
原因：暂无示例


std::basic_ospanstream<CharT,Traits>::span

< cpp‎ | io‎ | basic ospanstream

std::span<CharT> span() const noexcept; | (1) | (C++23 起)
void span( std::span<CharT> s ) noexcept; | (2) | (C++23 起)
1) 若包装的 std::basic_spanbuf 的打开模式中设置了 std::ios_base::out ，则获取引用被写入区域的 span ，否则获取引用底层缓冲区的 span 。
2) 使包装的 std::basic_spanbuf 进行 s 所引用的缓冲区上的 I/O 。

参数

s - 引用要用作流的新底层缓冲区的 std::span

返回值

1) 引用底层缓冲区或已写入区域的 std::span ，取决于包装的 std::basic_spanbuf 的打开模式。
2) （无）

示例

本节未完成
原因：暂无示例

参阅

span
(C++23)
 根据模式获得或初始化底层缓冲区
(std::basic_spanbuf<CharT,Traits> 的公开成员函数)


std::basic_ospanstream<CharT,Traits>::swap

< cpp‎ | io‎ | basic ospanstream

void swap( basic_ospanstream& other ); | (C++23 起)

和 other 交换流状态。

这是通过调用 std::basic_ostream <CharT, Traits>::swap(other) 和交换包装的 std::basic_spanbuf 对象（可通过 *rdbuf() 访问）进行的。

参数

other - 要与之交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++23)
 交换二个 basic_spanbuf 对象
(std::basic_spanbuf<CharT,Traits> 的公开成员函数)


std::swap(std::basic_ospanstream)

< cpp‎ | io‎ | basic ospanstream

定义于头文件 <spanstream>
template< class CharT, class Traits >

void swap( std::basic_ospanstream<CharT, Traits>& lhs,

std::basic_ospanstream<CharT, Traits>& rhs );
 (C++23 起)

对 std::basic_ospanstream 重载 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++23)
 交换二个 basic_ospanstream 对象
(公开成员函数)


std::basic_ostream

< cpp‎ | io
定义于头文件 <ostream>
template<

class CharT,
class Traits = std::char_traits <CharT>

> class basic_ostream : virtual public std::basic_ios <CharT, Traits>

类模板 basic_ostream 提供字符流上的高层输出操作。受支持操作包含有格式输出（例如整数值）和无格式输出（例如生字符和字符数组）。此功能以 basic_streambuf 类所提供的接口实现，通过 basic_ios 基类访问。典型的实现中， basic_ostream 无非继承的数据成员。

cpp/io/ios base cpp/io/basic ios

继承图

亦提供二个对常见字符类型的特化：

定义于头文件 <ostream>
类型 | 定义
ostream | basic_ostream<char>
wostream | basic_ostream<wchar_t>

全局对象

标准库提供六个全局 basic_ostream 对象。

定义于头文件 <iostream>
coutwcout | 写入到标准 C 输出流 stdout (全局对象)
cerrwcerr | 写入到标准 C 错误流 stderr， 无缓冲 (全局对象)
clogwclog | 写入到标准 C 错误流 stderr (全局对象)

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(构造函数)
 构造对象
(公开成员函数)
(析构函数)
[虚]
 析构对象
(虚公开成员函数)
operator=
(C++11)
 从另一 basic_ostream 移动赋值
(受保护成员函数)
有格式输出
operator<<
 插入带格式数据
(公开成员函数)
无格式输出
put
 插入字符
(公开成员函数)
write
 插入字符块
(公开成员函数)
寻位
tellp
 返回输出位置指示器
(公开成员函数)
seekp
 设置输出位置指示器
(公开成员函数)
杂项
flush
 与底层存储设备同步
(公开成员函数)
swap
(C++11)
 交换流对象，除了关联缓冲区
(受保护成员函数)

成员类

sentry
 为输出操作实现流准备的基本逻辑
(公开成员类)

非成员函数

operator<<(std::basic_ostream)
 插入字符数据
(函数)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)


std::basic_ostream<CharT,Traits>::basic_ostream

< cpp‎ | io‎ | basic ostream
explicit basic_ostream( std::basic_streambuf <CharT, Traits>* sb ); | (1) |
protected: basic_ostream( const basic_ostream& rhs ) = delete; | (2) | (C++11 起)
protected: basic_ostream( basic_ostream&& rhs ); | (3) | (C++11 起)

1) 构造 basic_ostream 对象，通过调用 basic_ios::init(sb) 赋初值给基类。

2) 复制构造函数被删除。输出流不可复制。

3) 移动构造函数用 basic_ios<CharT, Traits>::move(rhs) 从 rhs 移动所有 basic_ios ，除了 rdbuf() 到 *this 中。此移动构造函数受保护：它为可移动输出流类 std::basic_ofstream 和 std::basic_ostringstream 的移动构造函数所调用，它们知道如何正确地移动关联的流缓冲。

参数

sb | - | 用作输出序列的流缓冲
rhs | - | 初始化来源的 basic_ostream

示例

#include <sstream>
#include <utility>
#include <iostream>

int main()
{
    // 错误：复制构造函数被删除
//  std::ostream myout(std::cout);

    // OK ：与 cout 共享缓冲
    std::ostream myout(std::cout.rdbuf());

    // 错误：移动构造函数受保护
//  std::ostream s2(std::move(std::ostringstream() << 7.1));

    // OK ：通过导出类调用移动构造函数
    std::ostringstream s2(std::move(std::ostringstream() << 7.1));
    myout << s2.str() << '\n';
}

输出：

7.1


std::basic_ostream<CharT,Traits>::flush

< cpp‎ | io‎ | basic ostream
basic_ostream& flush();

写入未提交更改到底层输出序列。

若 rdbuf() 为空指针，则不做任何事。

否则，表现为无格式输出函数 (UnformattedOutputFunction) (C++11 起)。构造并检查 sentry 对象后，调用 rdbuf()->pubsync() 。若该调用返回 -1 ，则调用 setstate(badbit) 。

参数

（无）

返回值

*this

异常

若 exceptions()&badbit!=0 则可能抛出 std::ios_base::failure 。

示例

#include <thread>
#include <iostream>
#include <chrono>
void f()
{
    std::cout << "Output from thread...";
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "...thread calls flush()\n";
    std::cout.flush();
}

int main()
{
    std::thread t1(f);
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::clog << "Output from main\n";
    t1.join();
}

输出：

Output from main
Output from thread.....thread calls flush()

参阅

pubsync
 调用 sync()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sync
[虚]
 将缓冲与关联的字符序列同步
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
flush
 冲洗输出流
(函数模板)
endl
 输出 '\n' 并冲洗输出流
(函数模板)
sync
 与底层存储设备同步
(std::basic_istream<CharT,Traits> 的公开成员函数)


std::basic_ostream<CharT,Traits>::operator=

< cpp‎ | io‎ | basic ostream
protected: basic_ostream& operator=( const basic_ostream& rhs ) = delete; | (1) |
protected: basic_ostream& operator=( basic_ostream&& rhs ); | (2) | (C++11 起)

1) 复制赋值运算符为被保护，企鹅杯删除。输出流不可复制赋值 (CopyAssignable) 。

2) 移动赋值运算符如同以调用 swap(*rhs) 与 rhs 交换基类的所有数据成员，除了 rdbuf() 。此移动赋值运算符为受保护：它只为导出可移动输出流类 std::basic_ofstream 和 std::basic_ostringstream 的移动赋值运算符所调用，它们知道如何正确移动赋值关联的流缓冲。

参数

rhs - 要赋值给 *this 的 basic_ostream 对象

示例

#include <sstream>
#include <utility>
#include <iostream>
int main()
{
    std::ostringstream s;
//  std::cout = s;                             // 错误：复制赋值运算符被删除
//  std::cout = std::move(s);                  // 错误：移动赋值运算符为受保护
    s = std::move(std::ostringstream() << 42); // OK ：通过导出类移动
    std::cout << s.str() << '\n';
}

输出：

42


std::basic_ostream<CharT,Traits>::operator<<

< cpp‎ | io‎ | basic ostream
basic_ostream& operator<<( short value );
basic_ostream& operator<<( unsigned short value );
 (1)
basic_ostream& operator<<( int value );
basic_ostream& operator<<( unsigned int value );
 (2)
basic_ostream& operator<<( long value );
basic_ostream& operator<<( unsigned long value );
 (3)
basic_ostream& operator<<( long long value );
basic_ostream& operator<<( unsigned long long value );
 (4) (C++11 起)
basic_ostream& operator<<( float value );

basic_ostream& operator<<( double value );

basic_ostream& operator<<( long double value );
 (5)
basic_ostream& operator<<( bool value );
 (6)
basic_ostream& operator<<( const void* value );
 (7)
basic_ostream& operator<<( const volatile void* value );
 (8) (C++23 起)
basic_ostream& operator<<( std::nullptr_t );
 (9) (C++17 起)
basic_ostream& operator<<( std::basic_streambuf <CharT, Traits>* sb );
 (10)
basic_ostream& operator<<(
std::ios_base & (*func)( std::ios_base &) );
 (11)
basic_ostream& operator<<(
std::basic_ios <CharT,Traits>& (*func)( std::basic_ios <CharT,Traits>&) );
 (12)
basic_ostream& operator<<(
std::basic_ostream <CharT,Traits>& (*func)( std::basic_ostream <CharT,Traits>&) );
 (13)

插入数据到流。

1-2) 表现同有格式输出函数 (FormattedOutputFunction) 。在构造并检查 sentry 对象后，若 value 为 short 或 int ，则将它转型为 unsigned short 或 unsigned int ，若 ios_base::flags() & ios_base::basefield 为 ios_base::oct 或 ios_base::hex 。之后，不论任何情况，将它转型为 long 并按 (3) 中方式输出。若 value 是 unsigned short 或 unsigned int ，则将它转型为 unsigned long 并按 (3) 中方式输出。
3-7) 表现同有格式输出函数 (FormattedOutputFunction) 。在构造并检查 sentry 对象后，通过调用 num_put::put() 插入整数、浮点数、布尔或通用指针值。若在输出中遇到文件尾（ put().failed() == true ），则设置 ios::badbit 。
8) 将 value 转型到 const void* 并按 (7) 输出。
9) 如同用 *this << s 输出实现定义的字符串，其中 s 是空终止字符类型字符串。
10) 表现同无格式输出函数 (UnformattedOutputFunction) 。在构造并检查 sentry 对象后，检查 sb 是否空指针。若它是，则执行 setstate(badbit) 并退出。否则，从 sb 所控制的输入序列释出字符，并将它们插入到 *this ，直至满足下列条件之一为止：
  • 输入序列上出现文件尾；
  • 插入输出序列失败（该情况下不会释出要被插入的字符）；
  • 发生异常（该情况下异常被捕捉）。
若没有插入字符，则执行 setstate(failbit) 。若在释放中抛出异常，则设置 failbit ，而且若 failbit 设置于 exceptions() ，则重抛异常。
11-13) 调用 func(*this) 。这些重载用于实现输出 I/O 操纵符，例如 std::endl 。

参数

value | - | 要插入的整数、浮点、布尔或指针值
func | - | 要调用的函数
sb | - | 指向要自之读取数据的 streambuffer 的指针

返回值

1-11) *this
12) func(*this)

注解

无对指向非静态数据成员指针、指向 volatile 指针 (C++23 前)或函数指针（除了拥有 (11-13) 重载所接受之签名者）的重载。试图输出这种对象会引发到 bool 的隐式转换，并对于任何非空指针值打印值 1 （除非设置了 boolalpha ，该情况下打印 true ）。

字符与字符串参数（例如拥有 char 类型或 const char* 类型者）以 operator<< 的非成员重载处理。试图用成员函数调用语法（例如 std::cout.operator<<('c'); ）会调用重载 (2-4) 之一，并输出数字值。试图用成员函数调用语法输出字符串会调用重载 (7) ，并替而打印指针值。

示例

#include <iostream>
#include <iomanip>
#include <sstream>
int main()
{
    std::istringstream input(" \"Some text.\" ");
    volatile int n = 42;
    double f = 3.14;
    bool b = true;
    std::cout << n   // int 重载
              << ' ' // 非成员重载
              << std::boolalpha << b // bool 重载
              << " " // non-member overload
              << std::fixed << f // double 重载
              << input.rdbuf() // streambuf 重载
              << &n // bool 重载： volatile int* 不转换成 const void*
              << std::endl; // 函数重载
}

输出：

42 true 3.140000 "Some text." true

参阅

operator<<(std::basic_ostream) | 插入字符数据 (函数)
operator<<operator>> | 执行字符串的流输入与输出 (函数模板)
operator<<operator>> | 执行 bitset 的流输入和输出 (函数)
operator<<operator>> | 复数的序列化和反序列化 (函数模板)
operator<<operator>> (C++11) | 执行伪随机数引擎的流输入和输出 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)
put | 插入字符 (公开成员函数)
write | 插入字符块 (公开成员函数)
to_chars (C++17) | 转换整数或浮点值到字符序列 (函数)


operator<<(std::basic_ostream)

< cpp‎ | io‎ | basic ostream
定义于头文件 <ostream>
basic_ostream 与字符
(1)
template< class CharT, class Traits>

basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os,

CharT ch );
template< class CharT, class Traits>

basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os,

char ch );
template< class Traits >

basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,

char ch );
template< class Traits >

basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,

signed char ch );
template< class Traits >

basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,

unsigned char ch );
basic_ostream 与字符数组
(2)
template< class CharT, class Traits >

basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os,

const CharT* s );
template< class CharT, class Traits >

basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os,

const char* s );
template< class Traits >

basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,

const char* s );
template< class Traits >

basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,

const signed char* s );
template< class Traits >

basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,

const unsigned char* s );
basic_ostream 右值
template< class Ostream, class T >

Ostream&& operator<<( Ostream&& os,

const T& value );
 (3) (C++11 起)
basic_ostream 与 UTF 字符/数组的被删除重载
(4) (C++20 起)
template< class Traits >

basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,

wchar_t ch ) = delete;
template< class Traits >

basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,

char8_t ch ) = delete;
template< class Traits >

basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,

char16_t ch ) = delete;
template< class Traits >

basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,

char32_t ch ) = delete;
template< class Traits >

basic_ostream<wchar_t,Traits>& operator<<( basic_ostream<wchar_t,Traits>& os,

char8_t ch ) = delete;
template< class Traits >

basic_ostream<wchar_t,Traits>& operator<<( basic_ostream<wchar_t,Traits>& os,

char16_t ch ) = delete;
template< class Traits >

basic_ostream<wchar_t,Traits>& operator<<( basic_ostream<wchar_t,Traits>& os,

char32_t ch ) = delete;
template< class Traits >

basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,

const wchar_t* ch ) = delete;
template< class Traits >

basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,

const char8_t* ch ) = delete;
template< class Traits >

basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,

const char16_t* ch ) = delete;
template< class Traits >

basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,

const char32_t* ch ) = delete;
template< class Traits >

basic_ostream<wchar_t,Traits>& operator<<( basic_ostream<wchar_t,Traits>& os,

const char8_t* ch ) = delete;
template< class Traits >

basic_ostream<wchar_t,Traits>& operator<<( basic_ostream<wchar_t,Traits>& os,

const char16_t* ch ) = delete;
template< class Traits >

basic_ostream<wchar_t,Traits>& operator<<( basic_ostream<wchar_t,Traits>& os,

const char32_t* ch ) = delete;

插入字符或字符串。

1) 表现如有格式输出函数 (FormattedOutputFunction) 。在构造并检查 sentry 对象后，插入字符 ch 。若字符类型不是 CharT ，则它首先以 os.widen(ch) 转换。按下列方式确定填充：若 os.width()>1 ，则添加 os.width()-1 个 os.fill() 的副本到输出字符，以组成输出字符序列。 若 (out.flags()& std::ios_base::adjustfield ) == std::ios_base::left ，则填充字符被置于输出字符之后，否则在之前。插入前，调用 os.width(0) 以取消 std::setw 的效果，若它存在。
2) 表现如有格式输出函数 (FormattedOutputFunction) 。在构造并检查 sentry 对象后，插入来自首元素为 s 所指向的字符数组的相继字符。
  • 对于第一和第三重载（其中 CharT 匹配 ch 的类型），准确插入 traits::length(s) 个字符。
  • 对于第二重载，准确插入 std::char_traits <char>::length(s) 个字符。
  • 对于最后二个重载，准确插入 traits::length(reinterpret_cast<const char*>(s)) 个字符。

在插入前，首先，用 os.widen() 加宽所有字符，然后按下列方式确定填充：若要插入的字符数少于 os.width() ，则添加足够数量的 os.fill() 副本到字符序列，以令其长等于 os.width() 。若 (out.flags()& std::ios_base::adjustfield ) == std::ios_base::left ，则添加填充字符到输出序列的末尾，否则添加它们到序列之前。 在插入后，调用 width(0) 取消 std::setw 的效果，若它存在。

若 s 为空指针则行为未定义。
3) 给定到输出流对象的右值引用，调用适当的插入运算符（等价于 os << value ）。此重载仅若表达式 os << value 为良构且 Ostream 是公开且无歧义地派生自 std::ios_base 的类类型才参与重载决议。
4) 接受 char16_t 、 char32_t 的（或其空终止序列的）重载被删除：不允许 std::cout << u'X' 。之前，这些会打印整数或指针值。

参数

os | - | 要插入数据的输出流
ch | - | 要插入的字符
s | - | 指向要插入的字符串的指针

返回值

1-2) os
3) std::move(os)

注解

在 LWG#1203 前，如 ( std::ostringstream () << 1.2).str() 的代码无法编译。

示例

#include <iostream>
#include <fstream>

int main()
{
    std::cout << "Hello, world" // const char* 重载
              << '\n';          // char 重载
    std::ofstream("test.txt") << 1.2; // 右值重载
}

输出：

Hello, world

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 1203 | C++11 | 右值流的重载返回到基类的左值引用 | 返回到派生类的右值引用
LWG 2534 | C++11 | 右值流的重载未被制约 | 已制约

参阅

operator<< | 插入带格式数据 (公开成员函数)
widen | 拓宽字符 (std::basic_ios<CharT,Traits> 的公开成员函数)


std::basic_ostream<CharT,Traits>::put

< cpp‎ | io‎ | basic ostream
basic_ostream& put( char_type ch );

表现为无格式输出函数 (UnformattedOutputFunction) 。构造并检查 sentry 对象后，写字符 ch 到输出流。

若输出因任何原因失败，则设置 badbit 。

参数

ch - 要写入的字符

返回值

*this

注意

此函数不对 signed char 或 unsigned char 类型重载，不同于有格式的 operator<< 。

不同于有格式输出函数，若输出失败，则此函数不设置 failbit 。

示例

#include <fstream>
#include <iostream>

int main()
{
    std::cout.put('a'); // 正常用法
    std::cout.put('\n');

    std::ofstream s("/does/not/exist/");
    s.clear(); // 假装流是好的
    std::cout << "Unformatted output: ";
    s.put('c'); // 这将设置 badbit ，但非 failbit
    std::cout << " fail=" << bool(s.rdstate() & s.failbit);
    std::cout << " bad=" << s.bad() << '\n';
    s.clear();
    std::cout << "Formatted output:   ";
    s << 'c'; // 这将设置 badbit 和 failbit
    std::cout << " fail=" << bool(s.rdstate() & s.failbit);
    std::cout << " bad=" << s.bad() << '\n';
}

输出：

a
Unformatted output:  fail=0 bad=1
Formatted output:    fail=1 bad=1

参阅

operator<<(std::basic_ostream) | 插入字符数据 (函数)
write | 插入字符块 (公开成员函数)


std::basic_ostream<CharT,Traits>::seekp

< cpp‎ | io‎ | basic ostream
basic_ostream& seekp( pos_type pos ); | (1)
basic_ostream& seekp( off_type off, std::ios_base::seekdir dir ); | (2)

设置当前关联 streambuf 对象的输出位置指示器。

表现为无格式输出函数 (UnformattedOutputFunction) （除了不实际进行输出）。在构造并检查 sentry 对象后，

 (C++11 起)
1) 通过调用 rdbuf()->pubseekpos(pos, std::ios_base::out ) ，设置输出位置指示器为绝对（相对于文件起始）值 pos 。若调用返回 (pos_type)-1 ，则执行 setstate(failbit) 。
2) 通过调用 rdbuf()->pubseekoff(off, dir, std::ios_base::out ) 设置输出位置指示器为相对于 dir 的偏移 off 。若调用返回 (pos_type)-1 ，则执行 setstate(failbit) 。

参数

pos - 要设置输出位置指示器到的绝对位置。
off - 要设置输出位置指示器到的相对位置（正或负）。
dir - 定义应用相对偏移到的基位置。它能为下列常量之一：
常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

返回值

*this

异常

1-2) 若 exceptions() & failbit != 0 ，则失败情况下可以抛出 std::ios_base::failure 。

示例

#include <sstream>
#include <iostream>

int main()
{
    std::ostringstream os("hello, world");
    os.seekp(7);
    os << 'W';
    os.seekp(0, std::ios_base::end);
    os << '!';
    os.seekp(0);
    os << 'H';
    std::cout << os.str() << '\n';
}

输出：

Hello, World!

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2341 | C++98 | 二个重载在失败时表现有别 | 使之一致

参阅

tellp | 返回输出位置指示器 (公开成员函数)
tellg | 返回输入位置指示器 (std::basic_istream<CharT,Traits> 的公开成员函数)
seekg | 设置输入位置指示器 (std::basic_istream<CharT,Traits> 的公开成员函数)


std::basic_ostream<CharT,Traits>::sentry

< cpp‎ | io‎ | basic ostream
class sentry;

类 basic_ostream::sentry 的对象在 std::basic_ostream 的每个进行输出（有格式与无格式）的成员函数起始的局部作用域中构造。其构造函数准备输出流：检查流是否已在失败状态，冲入所 tie() 的输出流，并且若需要则进行其他实现定义的任务。实现定义的清理，还有若有必要的输出流冲入，在析构函数中进行，从而保证若输出中抛出异常则得到执行。

成员函数

(构造函数) | 构造 sentry 对象。所有准备任务都在此完成。 (公开成员函数)
(析构函数) | 在有格式输入后或异常后终止化流对象，若有必要 (公开成员函数)
operator= | 赋值运算符被删除 (公开成员函数)
operator bool | 检查流对象的准备是否成功 (公开成员函数)

std::basic_ostream::sentry::sentry

explicit sentry( std::basic_ostream <CharT,Traits>& os );

为有格式输出准备流。

若 os.good() 为 false 则返回。否则若 os.tie() 不是空指针，则调用 os.tie()->flush() 以令输出序列同步于外部流。在准备中，构造函数可能调用 setstate(failbit) （它可能抛出 std::ios_base::failure ）。

若在准备完成后 os.good() == true ，则任何对 operator bool 的后继调用都会返回 true 。

参数

os - 要准备的输出流

异常

若文件尾条件出现则为 std::ios_base::failure。

std::basic_ostream::sentry::~sentry

~sentry();

若 (os.flags() & std::ios_base::unitbuf ) && ! std::uncaught_exception () && os.good()) 为 true ，则调用 os.rdbuf()->pubsync() 。若该函数返回 -1 ，则于 os.rdstate() 中设置 badbit ，而不传播异常。

std::basic_ostream::sentry::operator bool

explicit operator bool() const;

检查输出流的准备是否成功。

参数

（无）

返回值

若输出流的准备成功则为 true ，否则为 false 。

示例

#include <iostream>
#include <sstream>

struct Foo
{
    char n[6];
};

std::ostream& operator<<(std::ostream& os, Foo& f)
{
    std::ostream::sentry s(os);
    if (s) {
        os.write(f.n, 5);
    }
    return os;
}

int main()
{
    Foo f = { "abcde" };
    std::cout << f << '\n';
}

输出：

abcde

参阅

operator<<
 插入带格式数据
(公开成员函数)


std::basic_ostream<CharT,Traits>::swap

< cpp‎ | io‎ | basic ostream
protected: void swap(basic_ostream& rhs); | (C++11 起)

调用 basic_ios::swap(rhs) 交换 *this 和 rhs 间的基类数据成员，除了 rdbuf() 。此 swap 函数受保护：它为可交换输出流类 std::basic_ofstream 和 std::basic_ostringstream 的 swap 函数所调用，这些函数知晓如何正确交换关联的流缓冲。

参数

rhs - 要与之交换的同类型 basic_ostream

示例

#include <sstream>
#include <iostream>
#include <utility>
int main()
{
    std::ostringstream s1("hello");
    std::ostringstream s2("bye");

    s1.swap(s2); // OK ： ostringstream 拥有公开 swap()
    std::swap(s1, s2); // OK ：调用 s1.swap(s2)

//  std::cout.swap(s2); // 错误： swap 是受保护成员

    std::cout << s1.str() << '\n';
}

输出：

hello


std::basic_ostream<CharT,Traits>::tellp

< cpp‎ | io‎ | basic ostream
pos_type tellp();

返回当前关联的 streambuf 对象的输出位置指示器。

表现为无格式输出函数 (UnformattedOutputFunction) （除了不实际进行输出）。在构造并检查 sentry 对象后，

 (C++11 起)

若 fail()==true ，则返回 pos_type(-1) 。否则，返回 rdbuf()->pubseekoff(0, std::ios_base::cur, std::ios_base::out ) 。

参数

（无）

返回

成功时为当前输出位置指示器，若出现失败则为 pos_type(-1) 。

示例

#include <iostream>
#include <sstream>
int main()
{
    std::ostringstream s;
    std::cout << s.tellp() << '\n';
    s << 'h';
    std::cout << s.tellp() << '\n';
    s << "ello, world ";
    std::cout << s.tellp() << '\n';
    s << 3.14 << '\n';
    std::cout << s.tellp() << '\n' << s.str();
}

输出：

0
1
13
18
hello, world 3.14

参阅

seekp | 设置输出位置指示器 (公开成员函数)
tellg | 返回输入位置指示器 (std::basic_istream<CharT,Traits> 的公开成员函数)
seekg | 设置输入位置指示器 (std::basic_istream<CharT,Traits> 的公开成员函数)


std::basic_ostream<CharT,Traits>::write

< cpp‎ | io‎ | basic ostream
basic_ostream& write( const char_type* s, std::streamsize count );

表现为无格式输出函数 (UnformattedOutputFunction) 。构造并检查 sentry 对象后，输出来自首元素为 s 所指向的字符数组中的相继位置的字符。插入字符到输出序列，直至出现下列条件之一：

  • 准确插入了 count 个字符
  • 插入到输出序列失败（该情况下调用 setstate(badbit) ）

参数

s | - | 指向要写入的字符串的指针
count | - | 要写入的字符数

返回值

*this

异常

若出现错误（错误状态标志不是 goodbit ）并且设置了 exceptions() 为对该状态抛出则为 failure 。

若内部操作抛出异常，则捕获它并设置 badbit 。若对 badbit 设置了 exceptions() ，则重抛该异常。

注解

此函数不对 signed char 或 unsigned char 类型重载，不同于有格式的 operator<< 。

而且，不同于有格式输出函数，此函数在失败时不设置 failbit 。

使用非转换本地环境（默认本地环境为非转换）时， std::basic_ofstream 中此函数的覆写者可为零复制大块 I/O 优化（通过覆写 std::streambuf::xsputn ）。

示例

此函数可用于输出对象表示，即二进制输出

#include <iostream>

int main()
{
    int n = 0x41424344;
    std::cout.write(reinterpret_cast<char*>(&n), sizeof n) << '\n';

    char c[]="This is sample text.";
    std::cout.write(c, 4).write("!\n", 2);
}

可能的输出：

DCBA
This

参阅

operator<<(std::basic_ostream) | 插入字符数据 (函数)
put | 插入字符 (公开成员函数)


std::basic_ostream<CharT,Traits>::~basic_ostream

< cpp‎ | io‎ | basic ostream
virtual ~basic_ostream();

销毁 basic_ostream 对象。此析构函数不进行底层流缓冲（ rdbuf() ）上的任何操作：导出输出流，如 std::basic_ofstream 与 std::basic_ostringstream 的析构函数负责调用流缓冲的析构函数。

示例

#include <sstream>
#include <iostream>
void add_words(std::streambuf* p)
{
    std::ostream buf(p); // buf 与 s 共享缓冲
    buf << " is the answer";
} // 调用 buf 的析构函数。 p 保持不受影响。
int main()
{
    std::ostringstream s;
    s << 42;
    add_words(s.rdbuf());
    s << ".";
    std::cout << s.str() << '\n';
}

输出：

42 is the answer.


std::basic_ostringstream

< cpp‎ | io
定义于头文件 <sstream>
template<

class CharT,
class Traits = std::char_traits <CharT>,
class Allocator = std::allocator <CharT>

> class basic_ostringstream;

类模板 std::basic_ostringstream 实现基于字符串的流上的输入与输出操作。它等效地存储一个 std::basic_string 的实例，并在其上进行输出操作。

该类实际上在低层包装 std::basic_stringbuf 的原生字符串设备到 std::basic_ostream 的高层接口中。提供到独有 std::basic_stringbuf 成员的完整接口。

cpp/io/ios base cpp/io/basic ios cpp/io/basic ostream

继承图

亦定义对常用字符类型的二个特化：

定义于头文件 <sstream>
类型 | 定义
ostringstream | basic_ostringstream<char>
wostringstream | basic_ostringstream<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type
allocator_type | Allocator

成员函数

(构造函数)
 构造字符串流
(公开成员函数)
operator=
(C++11)
 移动字符串流
(公开成员函数)
swap
(C++11)
 交换两个字符串流
(公开成员函数)
rdbuf
 返回底层未处理的字符串设备对象
(公开成员函数)
字符串操作
str
 获取或设置底层字符串设备对象的内容
(公开成员函数)
view
(C++20)
 获得底层字符串设备的内容上的视图
(公开成员函数)

非成员函数

std::swap(std::basic_ostringstream)
(C++11)
 特化 std::swap 算法
(函数模板)

继承自 std::basic_ostream

成员函数

有格式输出
operator<<
 插入带格式数据
(std::basic_ostream<CharT,Traits> 的公开成员函数)
无格式输出
put
 插入字符
(std::basic_ostream<CharT,Traits> 的公开成员函数)
write
 插入字符块
(std::basic_ostream<CharT,Traits> 的公开成员函数)
寻位
tellp
 返回输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
seekp
 设置输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
杂项
flush
 与底层存储设备同步
(std::basic_ostream<CharT,Traits> 的公开成员函数)

成员类

sentry
 为输出操作实现流准备的基本逻辑
(std::basic_ostream<CharT,Traits> 的公开成员类)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)


std::basic_ostringstream<CharT,Traits,Allocator>::basic_ostringstream

< cpp‎ | io‎ | basic ostringstream

basic_ostringstream()
: basic_ostringstream( std::ios_base::out ) { }
 (1) (C++11 起)
(2)
explicit basic_ostringstream( std::ios_base::openmode mode = std::ios_base::out );
 (C++11 前)
explicit basic_ostringstream( std::ios_base::openmode mode );
 (C++11 起)
explicit basic_ostringstream( const std::basic_string <CharT,Traits,Allocator>& str,
std::ios_base::openmode mode = std::ios_base::out );
 (3)
basic_ostringstream( basic_ostringstream&& other );
 (4) (C++11 起)
basic_ostringstream( std::ios_base::openmode mode, const Allocator& a );
 (5) (C++20 起)
explicit basic_ostringstream( std::basic_string <CharT,Traits,Allocator>&& str,
std::ios_base::openmode mode = std::ios_base::out );
 (6) (C++20 起)
template<class SAlloc>

basic_ostringstream( const std::basic_string <CharT,Traits,SAlloc>& str,
const Allocator& a )

: basic_ostringstream(str, std::ios_base::out, a) { }
 (7) (C++20 起)
template<class SAlloc>

basic_ostringstream( const std::basic_string <CharT,Traits,SAlloc>& str,

std::ios_base::openmode mode, const Allocator& a );
 (8) (C++20 起)
template<class SAlloc>

explicit basic_ostringstream( const std::basic_string <CharT,Traits,SAlloc>& str,

std::ios_base::openmode mode = std::ios_base::out );
 (9) (C++20 起)

构造新的字符串流。

1) 默认构造函数。以默认打开模式构造新的底层字符串设备。
2) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(mode | std::ios_base::out ) 构造底层 basic_stringbuf 对象。
3) 以 str 的副本为底层字符串设备的初始内容。以 basic_stringbuf<Char,Traits,Allocator>(str, mode | std::ios_base::out ) 构造底层 basic_stringbuf 对象。
4) 移动构造函数。用移动语义，构造拥有 other 的状态的字符串流。
5) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(mode | std::ios_base::out, a) 构造底层 basic_stringbuf 对象。
6) 用 str 移动构造底层字符串设备的内容。以 basic_stringbuf<Char,Traits,Allocator>(std::move(str), mode | std::ios_base::out ) 构造底层 basic_stringbuf 对象。
7) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(str, std::ios_base::out, a) 构造底层 basic_stringbuf 对象。
8) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(str, mode | std::ios_base::out, a) 构造底层 basic_stringbuf 对象。
9) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(str, mode | std::ios_base::out ) 构造底层 basic_stringbuf 对象。此重载仅若 SAlloc 与 Allocator 不是同一类型才参与重载决议。

参数

str - 用于初始化字符串流内容的字符串
mode - 指定流打开模式。它是位掩码类型，定义下列常量：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾
other - 用作源的另一字符串流

注解

在短的循环中，例如在用于字符串转换时构造单次使用的 basic_ostringstream 对象，开销可能显著高于调用 str 并复用同一对象。

示例

#include <iostream>
#include <sstream>
int main()
{
    // 默认构造函数（输入/输出流）
    std::stringstream buf1;
    buf1 << 7;
    int n = 0;
    buf1 >> n;
    std::cout << "buf1 = " << buf1.str() << " n = " << n << '\n';

    // 输入流
    std::istringstream inbuf("-10");
    inbuf >> n;
    std::cout << "n = " << n << '\n';

    // 输出流在 append 模式 (C++11)
    std::ostringstream buf2("test", std::ios_base::ate);
    buf2 << '1';
    std::cout << buf2.str() << '\n';
}

输出：

buf1 = 7 n = 7
n = -10
test1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式

参阅

str | 获取或设置底层字符串设备对象的内容 (公开成员函数)
(构造函数) | 构造一个 basic_stringbuf 对象 (std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)


std::basic_ostringstream::operator=

< cpp‎ | io‎ | basic ostringstream
basic_ostringstream& operator=( basic_ostringstream&& other ); | (C++11 起)

移动赋值字符串流 other 给 *this ，等效的移动赋值 std::basic_ostream 基类和关联的 std::basic_stringbuf 。

注意，基类移动赋值交换 *this 与 other 间的所有流状态变量（除了 rdbuf ）。

参数

other - 移动来源的字符串流

返回值

*this

示例

本节未完成
原因：暂无示例

参阅

swap (C++11) | 交换两个字符串流 (公开成员函数)
operator= (C++11) | 赋值 basic_stringbuf 对象 (std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)
operator= (C++11) | 从另一 basic_ostream 移动赋值 (受保护成员函数)


std::basic_ostringstream::rdbuf

< cpp‎ | io‎ | basic ostringstream

std::basic_stringbuf <CharT, Traits, Allocator>* rdbuf() const;

返回指向底层未处理字符串设备对象的指针。

参数

（无）

返回值

指向底层未处理字符串设备对象的指针。

示例

本节未完成
原因：暂无示例


std::basic_ostringstream<CharT,Traits,Allocator>::str

< cpp‎ | io‎ | basic ostringstream

 | (1) |
std::basic_string <CharT,Traits,Allocator> str() const; |  |  | (C++20 前)
std::basic_string <CharT,Traits,Allocator> str() const&; |  |  | (C++20 起)
template<class SAlloc> std::basic_string <CharT,Traits,SAlloc> str( const SAlloc& a ) const; | (2) | (C++20 起)
std::basic_string <CharT,Traits,Allocator> str() &&; | (3) | (C++20 起)
void str( const std::basic_string <CharT,Traits,Allocator>& s ); | (4) |
template<class SAlloc> void str( const std::basic_string <CharT,Traits, SAlloc>& s ); | (5) | (C++20 起)
void str( std::basic_string <CharT,Traits,Allocator>&& s ); | (6) | (C++20 起)

管理底层字符串对象的内容。

1) 返回底层字符串的副本。等价于 return rdbuf()->str(); 。
2) 返回底层字符串的副本，以 a 为分配器。等价于 return rdbuf()->str(a); 。
3) 返回从底层字符串移动构造的字符串。等价于 return std::move(*rdbuf()).str(); 。
4-5) 替换底层字符串。等价于 rdbuf()->str(s); 。
6) 替换底层字符串。等价于 rdbuf()->str(std::move(s)); 。

参数

s | - | 底层字符串的新内容
a | - | 用于构造返回的字符串的分配器

返回值

1-2) 底层字符串对象的副本。
3) 从底层字符串对象移动构造的字符串。
4-6) （无）

注解

str 所返回的底层字符串副本是将于表达式结尾析构的临时对象，故在 str() 的结果上直接调用 c_str() （例如 auto *ptr = out.str().c_str(); 中）导致悬垂指针。

示例

#include <sstream>
#include <iostream>
int main()
{
    int n;

    std::istringstream in;  // 亦可使用 in("1 2")
    in.str("1 2");
    in >> n;
    std::cout << "after reading the first int from \"1 2\", the int is "
              << n << ", str() = \"" << in.str() << "\"\n";

    std::ostringstream out("1 2");
    out << 3;
    std::cout << "after writing the int '3' to output stream \"1 2\""
              << ", str() = \"" << out.str() << "\"\n";

    std::ostringstream ate("1 2", std::ios_base::ate);
    ate << 3;
    std::cout << "after writing the int '3' to append stream \"1 2\""
              << ", str() = \"" << ate.str() << "\"\n";
}

输出：

after reading the first int from "1 2", the int is 1, str() = "1 2"
after writing the int '3' to output stream "1 2", str() = "3 2"
after writing the int '3' to append stream "1 2", str() = "1 23"

参阅

str
 替换或获得关联字符串的副本
(std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)


std::basic_ostringstream::swap

< cpp‎ | io‎ | basic ostringstream

void swap( basic_ostringstream& other ); | (C++11 起)

交换流与 other 的状态。

通过调用 basic_ostream<CharT, Traits>::swap(other) 和 rdbuf()->swap(*other.rdbuf()) 进行。

参数

other - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

operator= (C++11) | 移动字符串流 (公开成员函数)
swap (C++11) | 交换二个 basic_stringbuf 对象 (std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)


std::swap(std::basic_ostringstream)

< cpp‎ | io‎ | basic ostringstream

定义于头文件 <sstream>
template< class CharT, class Traits, class Alloc >

void swap( std::basic_ostringstream <CharT,Traits,Alloc>& lhs,

std::basic_ostringstream <CharT,Traits,Alloc>& rhs );
 (C++11 起)

对 std::basic_ostringstream 重载 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++11)
 交换两个字符串流
(公开成员函数)


std::basic_ostringstream<CharT,Traits,Allocator>::view

< cpp‎ | io‎ | basic ostringstream

std::basic_string_view <CharT, Traits> view() const noexcept; | (C++20 起)

获得底层字符串对象上的 std::basic_string_view 。等价于 return rdbuf()->view(); 。

参数

（无）

返回值

底层字符串对象上的 std::basic_string_view 。

示例

本节未完成
原因：暂无示例

参阅

view
(C++20)
 获得底层字符序列上的视图
(std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)


std::basic_osyncstream

< cpp‎ | io
定义于头文件 <syncstream>
template<

class CharT,
class Traits = std::char_traits <CharT>,
class Allocator = std::allocator <CharT>

> class basic_osyncstream: public std::basic_ostream <CharT, Traits>
 (C++20 起)

类模板 std::basic_osyncstream 是 std::basic_syncbuf 的便利包装。它提供机制以同步写入同一流的线程。

它能用作具名变量：

{
    std::osyncstream sync_out(std::cout); // std::cout 的同步包装
    sync_out << "Hello, ";
    sync_out << "World!";
    sync_out << std::endl; // 注意有冲入，但仍未进行
    sync_out << "and more!\n";
} // 转移字符并冲入 std::cout

还有临时量：

std::osyncstream(std::cout) << "Hello, " << "World!" << '\n';

它提供保证：所有对最终目标缓冲（上例中为 std::cout ）作出的输出将免除数据竞争，而且将不以任何方式穿插或截断，只要每次对该最终目标缓冲的写入都通过 std::basic_osyncstream （可以不同的）实例进行。

std::basic_osyncstream 的典型实现仅保有一个数据成员：被包装的 std::basic_syncbuf 。

cpp/io/ios base cpp/io/basic ios cpp/io/basic ostream

继承图

亦定义二个对常用字符类型的特化：

定义于头文件 <syncstream>
类型 | 定义
osyncstream | basic_osyncstream<char>
wosyncstream | basic_osyncstream<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type
allocator_type | Allocator
streambuf_type | std::basic_streambuf <CharT, Traits>
syncbuf_type | std::basic_syncbuf<CharT, Traits, Allocator>

成员函数

(构造函数) | 构造 basic_osyncstream (公开成员函数)
operator= | 赋值 basic_osyncstream (公开成员函数)
(析构函数) | 销毁 basic_osyncstream 并发射其内部缓冲区 (公开成员函数)
rdbuf | 获得指向底层 basic_syncbuf 的指针 (公开成员函数)
get_wrapped | 获得指向最终目标流缓冲的指针 (公开成员函数)
emit | 调用底层 basic_syncbuf 上的 emit 以传输其内部数据到最终目标 (公开成员函数)

继承自 std::basic_ostream

成员函数

有格式输出
operator<<
 插入带格式数据
(std::basic_ostream<CharT,Traits> 的公开成员函数)
无格式输出
put
 插入字符
(std::basic_ostream<CharT,Traits> 的公开成员函数)
write
 插入字符块
(std::basic_ostream<CharT,Traits> 的公开成员函数)
寻位
tellp
 返回输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
seekp
 设置输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
杂项
flush
 与底层存储设备同步
(std::basic_ostream<CharT,Traits> 的公开成员函数)

成员类

sentry
 为输出操作实现流准备的基本逻辑
(std::basic_ostream<CharT,Traits> 的公开成员类)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)


std::basic_osyncstream<CharT,Traits,Allocator>::basic_osyncstream

< cpp‎ | io‎ | basic osyncstream
basic_osyncstream( streambuf_type* buf, const Allocator& a);
 (1)
explicit basic_osyncstream( streambuf_type* buf )
: basic_osyncstream( buf, Allocator() ) {}
 (2)
basic_osyncstream( std::basic_ostream <CharT, Traits>& os, const Allocator& a)
: basic_osyncstream( os.rdbuf(), a) {}
 (3)
explicit basic_osyncstream( std::basic_ostream <CharT, Traits>& os )
: basic_osyncstream( os, Allocator() ) {}
 (4)
basic_osyncstream( std::basic_osyncstream&& other) noexcept;
 (5)

构造新的同步输出流。

1-4) 以提供的缓冲和分配器构造私有成员 std::basic_syncbuf ，并以指向成员 std::basic_streambuf 的指针初始化基类。
5) 移动构造函数。从 other 的对应子对象移动构造 std::basic_ostream 基类和 std::basic_syncbuf 成员，然后以指向新构造的底层 std::basic_syncbuf 的指针调用 set_rdbuf 以完成基类的初始化。此移动构造函数后， other.get_wrapped() 返回 nullptr ，而 other 的析构不产生输出。

参数

buf | - | 指向将被包装的 std::basic_streambuf 的指针
os | - | 到 std::basic_ostream 的引用，将包装其 rdbuf()
a | - | 传递给成员 std::basic_syncbuf 的构造函数的分配器
other | - | 移动来源的另一 osyncstream

示例

本节未完成
原因：暂无示例

参阅

(构造函数)
 构造 basic_syncbuf 对象
(std::basic_syncbuf<CharT,Traits,Allocator> 的公开成员函数)


std::basic_osyncstream<CharT,Traits,Allocator>::emit

< cpp‎ | io‎ | basic osyncstream
void emit();

通过在底层 std::basic_syncbuf 上调用 emit() ，发射所有缓冲的输出并执行任何未决的冲入。

参数

（无）

示例

#include <syncstream>
#include <iostream>
int main()
{
  {
    std::osyncstream bout(std::cout);
    std::bout << "Hello," << '\n'; // 不冲入
    std::bout.emit(); // 传输字符； cout 不冲入
    std::bout << "World!" << std::endl; // 提醒冲入； cout 不冲入
    std::bout.emit(); // 传输字符； cout 冲入
    std::bout << "Greetings." << '\n'; // 不冲入
  } // 析构函数调用 emit() ：传输字符； cout 不冲入

  // emit 能用于被包装流上的局部异常处理
  std::osyncstream bout(std::cout);
  bout << "Hello, " << "World!" << '\n';
  try {
    bout.emit();
  } catch (...) {
    // 处理异常
  }
}

输出：

Hello,
World!
Greetings.
Hello, World!

参阅

(析构函数) | 销毁 basic_osyncstream 并发射其内部缓冲区 (公开成员函数)
emit | 原子地传输整个内部缓冲区给被包装 streambuf (std::basic_syncbuf<CharT,Traits,Allocator> 的公开成员函数)


std::basic_osyncstream<CharT,Traits,Allocator>::get_wrapped

< cpp‎ | io‎ | basic osyncstream
streambuf_type* get_wrapped() const noexcept;

返回指向被包装的 std::basic_streambuf 的指针，通过在底层 std::basic_syncbuf 上调用 get_wrapped() 获得。

参数

（无）

示例

能安全地在不同的同步输出流中再次包装被包装缓冲

#include <syncstream>
#include <iostream>
int main()
{
  std::osyncstream bout1(std::cout);
  bout1 << "Hello, ";
  {
    std::osyncstream(bout1.get_wrapped()) << "Goodbye, " << "Planet!" << '\n';
  } // 发射临时缓冲的内容
  bout1 << "World!" << '\n';
} // 发射 bout1 的内容

输出：

Goodbye, Planet!
Hello, World!

参阅

(析构函数) | 销毁 basic_osyncstream 并发射其内部缓冲区 (公开成员函数)
get_wrapped | 获得被包装的 streambuf 指针 (std::basic_syncbuf<CharT,Traits,Allocator> 的公开成员函数)


std::basic_osyncstream<CharT,Traits,Allocator>::operator=

< cpp‎ | io‎ | basic osyncstream
basic_osyncstream& operator=( std::basic_osyncstream&& other) noexcept;

移动赋值同步输出流。

从 other 的对应成员移动赋值被包装的 std::basic_syncbuf （此移动赋值后， other.get_wrapped() 返回空指针，而 other 的析构不产生输出；发射任何待决的缓冲输出）并移动赋值基类 std::basic_ostream （这会在 *this 和 other 间交换所有流状态变量，除了 rdbuf ）。

参数

other - 要移动的另一 osyncstream

示例

本节未完成
原因：暂无示例

参阅

(构造函数) | 构造 basic_osyncstream (公开成员函数)
(析构函数) | 销毁 basic_osyncstream 并发射其内部缓冲区 (公开成员函数)
emit | 调用底层 basic_syncbuf 上的 emit 以传输其内部数据到最终目标 (公开成员函数)


std::basic_osyncstream<CharT,Traits,Allocator>::rdbuf

< cpp‎ | io‎ | basic osyncstream
syncbuf_type* rdbuf() const noexcept;

返回指向底层 std::basic_syncbuf 的指针。

参数

（无）

示例

本节未完成
原因：暂无示例

参阅

get_wrapped
 获得指向最终目标流缓冲的指针
(公开成员函数)


std::basic_osyncstream<CharT,Traits,Allocator>::~basic_osyncstream

< cpp‎ | io‎ | basic osyncstream
~basic_osyncstream();

销毁同步输出流。

成员 std::basic_syncbuf 的析构将发射任何未发射的缓冲输出。

参数

（无）

示例

本节未完成
原因：暂无示例

参阅

(析构函数)
 析构 basic_syncbuf 并发射其内部缓冲区
(std::basic_syncbuf<CharT,Traits,Allocator> 的公开成员函数)


std::basic_spanbuf

< cpp‎ | io
定义于头文件 <spanstream> |
template< class CharT, class Traits = std::char_traits <CharT> > class basic_spanbuf : public std::basic_streambuf <CharT, Traits> | (C++23 起)

std::basic_spanbuf 关联字符序列为内存中固定位置的任意字符序列的 std::basic_streambuf ，它能从 std::span<CharT> 初始化，并能被用作 std::span<CharT> 的实例。

std::basic_spanbuf 进行固定缓冲区上的 I/O ，从而它在耗尽底层缓冲区时不尝试获得新的缓冲区。

std::basic_spanbuf 的典型实现添加二个成员子对象：一个记录打开模式的 std::ios_base::openmode 与一个引用底层缓冲区的 std::span<CharT> 。

亦为常用字符类型定义二个特化：

定义于头文件 <spanstream>
类型 | 定义
spanbuf | basic_spanbuf<char>
wspanbuf | basic_spanbuf<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

公开成员函数
(构造函数)
(C++23)
 构造 basic_spanbuf 对象
(公开成员函数)
(析构函数)
[虚] (C++23)
 销毁 basic_spanbuf 对象
(虚公开成员函数)
operator=
(C++23)
 赋值 basic_spanbuf 对象
(公开成员函数)
swap
(C++23)
 交换二个 basic_spanbuf 对象
(公开成员函数)
span
(C++23)
 根据模式获得或初始化底层缓冲区
(公开成员函数)
受保护成员函数
setbuf
[虚] (C++23)
 试图以数组替换控制的底层字符序列
(虚受保护成员函数)
seekoff
[虚] (C++23)
 用相对寻址重定位输入序列、输出序列或两者的下一位置指针
(虚受保护成员函数)
seekpos
[虚] (C++23)
 用绝对寻址重定位输入序列、输出序列或两者的下一位置指针
(虚受保护成员函数)

非成员函数

std::swap(std::basic_spanbuf)
(C++23)
 特化 std::swap 算法
(函数模板)

继承自 std::basic_streambuf

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(析构函数)
[虚]
 析构 basic_streambuf 对象
(std::basic_streambuf<CharT,Traits> 的虚公开成员函数)
本地环境
pubimbue
 调用 imbue()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
getloc
 获得相关本地环境的副本
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
寻位
pubsetbuf
 调用 setbuf()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubseekoff
 调用 seekoff()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubseekpos
 调用 seekpos()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubsync
 调用 sync()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
获取区
in_avail
 获得获取区中立即可用的字符数
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
snextc
 令输入序列前进，读取一个字符而不再次前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sbumpcstossc
(C++17 中移除)
 从输入序列读取一个字符并令序列前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sgetc
 从输入序列读取一个字符，而不令序列前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sgetn
 调用 xsgetn()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
放置区
sputc
 写一个字符到放置区域，并令 next 指针前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sputn
 调用 xsputn()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
回放
sputbackc
 在输入序列中放回一个字符
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sungetc
 回移一位输出序列中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的公开成员函数)

受保护成员函数

(构造函数)
 构造 basic_streambuf 对象
(受保护成员函数)
operator=
(C++11)
 替换 basic_streambuf 对象
(受保护成员函数)
swap
(C++11)
 交换二个 basic_streambuf 对象
(受保护成员函数)
本地环境
imbue
[虚]
 更改关联的本地环境
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
寻位
setbuf
[虚]
 若容许则以用户定义数组替换缓冲区
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
seekoff
[虚]
 用相对寻址重定位输入序列、输出序列或两者中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
seekpos
[虚]
 用绝对寻址重定位输入序列、输出序列或两者中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
sync
[虚]
 将缓冲与关联的字符序列同步
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
获取区
showmanyc
[虚]
 若已知，则获得关联输入序列中可用于输入的字符数
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
underflow
[虚]
 从关联输入序列读取字符到获取区
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
uflow
[虚]
 从输入序列读取字符到获取区，并令下一位置指针前进
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
xsgetn
[虚]
 从输入序列读取多个字符
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
ebackgptregptr
 返回指向获取区起始、当前字符和末尾的指针
(受保护成员函数)
gbump
 令输出序列中的下一位置指针前进
(受保护成员函数)
setg
 重定位输出序列的起始、下一位置和终止指针
(受保护成员函数)
放置区
xsputn
[虚]
 将多个字符写到输出序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
overflow
[虚]
 从放置区写入字符到关联的输出序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
pbasepptrepptr
 返回指向放置区的起始、当前字符和末尾的指针
(受保护成员函数)
pbump
 令输出序列中的下一位置指针前进
(受保护成员函数)
setp
 重定位输出序列的起始、下一位置和终止指针
(受保护成员函数)
回放
pbackfail
[虚]
 将字符放回输入序列，可能修改输入序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)

注解

std::basic_spanbuf 不占有底层缓冲区。

程序员负责确保底层缓冲区在为 std::basic_spanbuf 所使用时处于其生存期中。多于一个线程在通过不同的 std::basic_spanbuf 对象操作同一底层缓冲区时可能需要额外的同步。

参阅

basic_stringbuf | 实现原生字符串设备 (类模板)
strstreambuf (C++98 中弃用) | 实现原生字符数组设备 (类)


std::basic_spanbuf<CharT,Traits>::basic_spanbuf

< cpp‎ | io‎ | basic spanbuf
basic_spanbuf() : basic_spanbuf( std::ios_base::in | std::ios_base::out ) {}
 (1) (C++23 起)
explicit basic_spanbuf( std::ios_base::openmode which )
: basic_spanbuf(std::span<CharT>{}, which) {}
 (2) (C++23 起)
explicit basic_spanbuf( std::span<CharT> buf, std::ios_base::openmode which =
std::ios_base::in | std::ios_base::out );
 (3) (C++23 起)
basic_spanbuf( const basic_spanbuf& ) = delete;
 (4) (C++23 起)
basic_spanbuf( basic_spanbuf&& rhs );
 (5) (C++23 起)
1) 默认构造函数。创建无底层缓冲区且为输入和输出打开的 basic_spanbuf 。指向获取与放置区的指针被设为空指针值。
2) 同 (1) ，除了 basic_spanbuf 以 which 所指定的模式打开。
3) 创建管理 buf 所引用的底层缓冲区（或若 buf 为空则无底层缓冲区），并以 which 所指定的模式打开的 basic_spanbuf 。指向获取与放置区的指针按以下方式设置，或若表格中未提及则设置为空指针值：
打开模式中设置的位 （影响指向获取区的指针） | 设置后的返回值
 | eback() | gptr() | egptr()
std::ios_base::in | s.data() | s.data() | s.data() + s.size()
打开模式中设置的位 （影响指向放置区的指针） | 设置后的返回值
 | pbase() | pptr() | epptr()
std::ios_base::out && ! std::ios_base::ate | s.data() | s.data() | s.data() + s.size()
std::ios_base::out && std::ios_base::ate | s.data() | s.data() + s.size() | s.data() + s.size()
4) 复制构造函数被删除。basic_spanbuf 不可复制。
5) 移动构造函数。从 rhs 的 std::basic_streambuf 基类子对象移动构造该基类子对象。指向获取与放置区的指针、打开模式及底层缓冲区（若存在）等同于 rhs 在构造前的。
rhs 在移动构造后是否仍然保有底层缓冲区是实现定义的。

参数

buf - 引用底层缓冲区的 std::span
rhs - 另一 basic_spanbuf
which - 指定流打开模式。它是位掩码类型，定义下列常量：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

注解

这些构造函数常由 std::basic_ispanstream、 std::basic_ospanstream 及 std::basic_spanstream 的构造函数调用

示例

本节未完成
原因：暂无示例

参阅

(构造函数) (C++23) | 构造 basic_ispanstream (std::basic_ispanstream<CharT,Traits> 的公开成员函数)
(构造函数) (C++23) | 构造 basic_ospanstream (std::basic_ospanstream<CharT,Traits> 的公开成员函数)
(构造函数) (C++23) | 构造 basic_spanstream (std::basic_spanstream<CharT,Traits> 的公开成员函数)


std::basic_spanbuf<CharT,Traits>::operator=

< cpp‎ | io‎ | basic spanbuf
basic_spanbuf& operator=( basic_spanbuf&& rhs ); | (1) | (C++23 起)
basic_spanbuf& operator( const basic_spanbuf& ) = delete; | (2) | (C++23 起)
1) 移动赋值运算符。等价于 auto tmp{std::move(rhs)}; this->swap(tmp); return *this; 。移动赋值后 *this 保有 rhs 在移动赋值前保有的状态。移动赋值后 rhs 是否仍然保有底层缓冲区是实现定义的。
2) 复制赋值运算符被删除； basic_spanbuf 非可复制赋值 (CopyAssignable) 。

参数

rhs - 将作为移动来源的另一 basic_spanbuf

返回值

*this

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

(构造函数) (C++23) | 构造 basic_spanbuf 对象 (公开成员函数)
swap (C++23) | 交换二个 basic_spanbuf 对象 (公开成员函数)


std::basic_spanbuf<CharT,Traits>::seekoff

< cpp‎ | io‎ | basic spanbuf
protected:

pos_type seekoff( off_type off, std::ios_base::seekdir dir,
std::ios_base::openmode which =

std::ios_base::in | std::ios_base::out ) override;
 (C++23 起)

若可能则重寻位指向获取和/或放置区的下一位置指针，为对应准确距缓冲区的获取和/或放置区的起始、末尾或当前位置 off 个字符。

设 n 为底层缓冲区中的 CharT 元素数，或若无底层缓冲区则为 ​0​ ，此函数在以下情况失败：

  • 待重寻位的指向获取和/或放置区的下一位置指针为空，且计算的 newoff （见后述）非零，这可能在无底层缓冲区或 *this 不是以 which 所要求的模式打开时出现，或
  • dir 为 std::ios_base::cur 且 which 中一同设置了 std::ios_base::in 和 std::ios_base::out ，或
  • 计算的 newoff 无法以 off_type 表示、小于零或大于 n 。

newoff 计算如下：

  • 若 dir 为 std::ios_base::beg ，则 newoff 为 off 。
  • 若 dir 为 std::ios_base::cur ，则 newoff 为
    • pptr() - pbase() + off ，若 which 中设置了 std::ios_base::out ，或
    • gptr() - eback() + off ，若 which 中设置了 std::ios_base::in 。
  • 若 dir 为 std::ios_base::end ，则 newoff 为
    • pptr() - pbase() + off ，若 *this 的打开模式中设置了 std::ios_base::out 但非 std::ios_base::in ，
    • 否则为 off + n 。

此函数在成功时重寻位指向获取和/或放置区的下一位置指针为 pbuf + newoff ，若在 which 中相应地设置了 std::ios_base::in 和/或 std::ios_base::out ，其中 pbuf 是指向底层缓冲区的指针，或若无底层缓冲区则为空指针值。

参数

off - 要设置下一位置指针到的相对位置
dir - 定义应用偏移到的基位置。它能为下列常量之一：
常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置
which - 定义影响的是输入序列、输出序列还是两者。它能为下列常量之一或其组合：
常量 | 解释
in | 影响输入序列
out | 影响输出序列

返回值

成功时为 pos_type(newoff) ，失败时为 pos_type(off_type(-1)) 。

示例

本节未完成
原因：暂无示例

参阅

seekoff [虚] | 用相对寻址，重定位输入序列、输出序列或两者中的下一位置指针 (std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
seekoff [虚] | 用相对寻址重寻位输入序列、输出序列或两者中的下一位置指针 (std::strstreambuf 的虚受保护成员函数)


std::basic_spanbuf<CharT,Traits>::seekpos

< cpp‎ | io‎ | basic spanbuf
protected:

pos_type seekpos( pos_type sp, std::ios_base::openmode which =

std::ios_base::in | std::ios_base::out ) override;
 (C++23 起)

若可能，则重寻位指向获取和/或放置区的指针到 sp 所指示的位置。

等价于 return seekoff(off_type(sp), std::ios_base::beg, which); 。

参数

sp - 流位置，例如由 seekoff() 或 seekpos() 获得者
which - 定义影响的是输入序列、输出序列或两者。它能为下列常量之一或其组合：
常量 | 解释
in | 影响输入序列
out | 影响输出序列

返回值

成功时为 sp ，失败时为 pos_type(off_type(-1)) 。

注解

seekpos() 为 std::basic_streambuf::pubseekpos() 所调用，它又为 std::basic_istream::seekg() 和 std::basic_ostream::seekp() 的单参数版本所调用。

示例

本节未完成
原因：暂无示例

参阅

pubseekpos
 调用 seekpos()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
seekpos
[虚]
 用绝对寻址，重定位输入序列、输出序列或两者中的下一位置指针
(std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
seekpos
[虚]
 用绝对寻址重寻位输入序列、输出序列或两者中的下一位置指针
(std::strstreambuf 的虚受保护成员函数)


std::basic_spanbuf<CharT,Traits>::setbuf

< cpp‎ | io‎ | basic spanbuf
protected: std::basic_streambuf <CharT, Traits>* setbuf( CharT *s, std::streamsize n ) override; | (C++23 起)

使 basic_spanbuf 进行缓冲区 [s, s + n) 上的 I/O 。等价地调用 this->span(std::span<CharT>(s, n)) 然后返回 this 。

打开模式中设置的位 （影响指向获取区的指针） | 设置后的返回值
 | eback() | gptr() | egptr()
std::ios_base::in | s | s | s + n
打开模式中设置的位 （影响指向放置区的指针） | 设置后的返回值
 | pbase() | pptr() | epptr()
std::ios_base::out && ! std::ios_base::ate | s | s | s + n
std::ios_base::out && std::ios_base::ate | s | s + n | s + n

此函数为受保护和虚，只可以通过 pubsetbuf() 或派生自 std::basic_spanbuf 的用户定义类的成员函数调用它。

参数

s | - | 指向用户提供的缓冲区的首个 CharT 的指针
n | - | 用户提供的缓冲区中的 CharT 元素数量

返回值

this

注解

弃用的流缓冲 std::strstreambuf 或 boost.IOStreams 设备 boost::basic_array 亦能实现用户提供的 char 数组上的 I/O 缓冲。

示例

本节未完成
原因：暂无示例

参阅

pubsetbuf
 调用 setbuf()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
setbuf
[虚]
 试图以数组替换受控字符序列
(std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
setbuf
[虚]
 试图以数组替换受控制字符序列
(std::strstreambuf 的虚受保护成员函数)


std::basic_spanbuf<CharT,Traits>::span

< cpp‎ | io‎ | basic spanbuf
std::span<CharT> span() const noexcept; | (1) | (C++23 起)
void span( std::span<CharT> s ) noexcept; | (2) | (C++23 起)
1) 若打开模式中设置了 std::ios_base::out 则获取引用被写入区域的 span ，否则获取引用底层缓冲区的 span 。
2) 使 basic_spanbuf 进行 s 所引用的缓冲区上的 I/O 。设置指向获取区、放置区或两者的指针。
打开模式中设置的位 （影响指向获取区的指针） | 设置后的返回值
 | eback() | gptr() | egptr()
std::ios_base::in | s.data() | s.data() | s.data() + s.size()
打开模式中设置的位 （影响指向放置区的指针） | 设置后的返回值
 | pbase() | pptr() | epptr()
std::ios_base::out && ! std::ios_base::ate | s.data() | s.data() | s.data() + s.size()
std::ios_base::out && std::ios_base::ate | s.data() | s.data() + s.size() | s.data() + s.size()

参数

s - 引用用户提供的缓冲区的 std::span

返回值

1) 若打开模式中设置了 std::ios_base::out 则为 std::span<CharT>(pbase(), pptr()) ，否则为引用整个底层缓冲区的 std::span<CharT> 。
2) （无）

示例

本节未完成
原因：暂无示例

参阅

str | 替换或获得关联字符串的副本 (std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)
view (C++20) | 获得底层字符序列上的视图 (std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)
str | 标记缓冲为冻结并返回输入序列的起始指针 (std::strstreambuf 的公开成员函数)


std::basic_spanbuf<CharT,Traits>::swap

< cpp‎ | io‎ | basic spanbuf
void swap( basic_spanbuf& rhs ); | (C++23 起)

交换 *this 与 rhs 的状态。

调用 std::basic_streambuf <Char, Traits>::swap(rhs) ，交换 *this 与 rhs 的打开模式，然后使它们使用对方的底层缓冲区。

参数

rhs - 另一 basic_stringbuf

返回值

（无）

异常

可能抛出实现定义的异常。

注解

在交换流对象时自动调用此函数，需要直接调用的情况是稀少的。

示例

本节未完成
原因：暂无示例

参阅

operator= (C++23) | 赋值 basic_spanbuf 对象 (公开成员函数)
swap (C++23) | 交换二个 basic_ispanstream 对象 (std::basic_ispanstream<CharT,Traits> 的公开成员函数)
swap (C++23) | 交换二个 basic_ospanstream 对象 (std::basic_ospanstream<CharT,Traits> 的公开成员函数)
swap (C++23) | 交换二个 basic_spanstream 对象 (std::basic_spanstream<CharT,Traits> 的公开成员函数)


std::swap(std::basic_spanbuf)

< cpp‎ | io‎ | basic spanbuf
定义于头文件 <spanstream>
template< class CharT, class Traits >

void swap( std::basic_spanbuf<CharT, Traits>& lhs,

std::basic_spanbuf<CharT, Traits>& rhs );
 (C++23 起)

对 std::basic_spanbuf 重载 std::swap 算法。交换 lhs 与 rhs 的状态。等价于 lhs.swap(rhs); 。

参数

lhs, rhs - 要交换状态的 std::basic_spanbuf 对象

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

swap (C++23) | 交换二个 basic_spanbuf 对象 (公开成员函数)
swap | 交换两个对象的值 (函数模板)


std::basic_spanstream

< cpp‎ | io
定义于头文件 <spanstream> |
template< class CharT, class Traits = std::char_traits <CharT> > class basic_spanstream; | (C++23 起)

类模板 std::basic_spanstream 实现基于固定缓冲区的流上的输入和输出操作。

此类实质上在低层包装 std::basic_spanbuf 类型的原生设备实现到 std::basic_iostream 的高层接口中。提供到独有的 std::basic_spanbuf 成员的完整接口。

std::basic_spantream 的典型实现仅添加一个成员子对象：包装的 std::basic_spanbuf 。

cpp/io/ios base cpp/io/basic ios cpp/io/basic istream cpp/io/basic ostream cpp/io/basic iostream

继承图

亦为常用字符类型定义二个特化：

定义于头文件 <spanstream>
类型 | 定义
spanstream | basic_spanstream<char>
wspanstream | basic_spanstream<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(构造函数)
(C++23)
 构造 basic_spanstream
(公开成员函数)
(析构函数)
[虚] (C++23)
 销毁 basic_spanstream
(虚公开成员函数)
operator=
(C++23)
 移动赋值 basic_spanstream
(公开成员函数)
swap
(C++23)
 交换二个 basic_spanstream 对象
(公开成员函数)
rdbuf
(C++23)
 获得包装的原生 span 设备对象的地址
(公开成员函数)
底层缓冲区操作
span
(C++23)
 获取或设置包装的 span 设备对象的底层缓冲区
(公开成员函数)

非成员函数

std::swap(std::basic_spanstream)
(C++23)
 特化 std::swap 算法
(函数模板)

继承自 std::basic_istream

成员函数

有格式输入
operator>>
 提取带格式数据
(std::basic_istream<CharT,Traits> 的公开成员函数)
无格式输入
get
 从流中读并取走（移除类似指针向下一个元素移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
peek
 仅读出但不取走（不移除类似指针并未移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
unget
 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
putback
 往输入流中退回一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
getline
 一直读并取走字符，直至找到给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
ignore
 读且取走并舍弃字符，直至发现给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
read
 读并取走一块字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
readsome
 读并取走已经可用的字符块
(std::basic_istream<CharT,Traits> 的公开成员函数)
gcount
 返回上次无格式输出操作所取走的字符数量
(std::basic_istream<CharT,Traits> 的公开成员函数)
寻位
tellg
 返回输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
seekg
 设置输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
杂项
sync
 与底层存储设备同步
(std::basic_istream<CharT,Traits> 的公开成员函数)

成员类

sentry
 实现为输出操作准备流的基本逻辑
(std::basic_istream<CharT,Traits> 的公开成员类)

继承自 std::basic_ostream

成员函数

有格式输出
operator<<
 插入带格式数据
(std::basic_ostream<CharT,Traits> 的公开成员函数)
无格式输出
put
 插入字符
(std::basic_ostream<CharT,Traits> 的公开成员函数)
write
 插入字符块
(std::basic_ostream<CharT,Traits> 的公开成员函数)
寻位
tellp
 返回输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
seekp
 设置输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
杂项
flush
 与底层存储设备同步
(std::basic_ostream<CharT,Traits> 的公开成员函数)

成员类

sentry
 为输出操作实现流准备的基本逻辑
(std::basic_ostream<CharT,Traits> 的公开成员类)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)


std::basic_spanstream<CharT,Traits>::basic_spanstream

< cpp‎ | io‎ | basic spanstream

explicit basic_spanstream( std::span<CharT> s, std::ios_base::openmode mode =
std::ios_base::in | std::ios_base::out );
 (1) (C++23 起)
basic_spanstream( basic_spanstream&& rhs );
 (2) (C++23 起)
basic_spanstream( const basic_spanstream& ) = delete;
 (3) (C++23 起)

构造新的 basic_spanstream 。

1) 以 s 所引用的存储为包装的 std::basic_spanbuf 设备的初始底层缓冲区。以 basic_spanbuf<Char, Traits>(s, mode) 构造包装的 std::basic_spanbuf 对象。
2) 移动构造函数。从 rhs 的 std::basic_iostream 基类子对象和包装的 std::basic_spanbuf 移动构造对应的子对象，然后以 *this 中包装的 std::basic_spanbuf 的地址调用 set_rdbuf 以安装它。
3) 复制构造函数被删除。 basic_spanstream 不可复制。

参数

s - 引用要作为流的初始底层缓冲区的存储的 std::span
mode - 指定打开模式。可以用下列常量或它们之间的逐位或：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾
other - 要移动的另一 basic_spanstream

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

(构造函数)
(C++23)
 构造 basic_spanbuf 对象
(std::basic_spanbuf<CharT,Traits> 的公开成员函数)


std::basic_spanstream<CharT,Traits>::operator=

< cpp‎ | io‎ | basic spanstream

basic_spanstream& operator=( basic_spanstream&& other ); | (1) | (C++23 起)
basic_spanstream& operator=( const basic_spanstream& ) = delete; | (2) | (C++23 起)
1) 移动赋值 other 给 *this ，等效地移动赋值 std::basic_iostream 基类子对象和包装的 std::basic_spanbuf 。
2) 复制赋值运算符被删除。 basic_spanstream 不可复制赋值。

注意基类的移动赋值运算符在 *this 与 other 间交换所有流状态变量（除了 rdbuf() ）。

包装于 other 的 std::basic_spanbuf 在移动赋值后是否仍然保有底层缓冲区是实现定义的。

参数

other - 要移动的另一流

返回值

*this

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

operator= (C++23) | 赋值 basic_spanbuf 对象 (std::basic_spanbuf<CharT,Traits> 的公开成员函数)
operator= (C++11) | 移动赋值另一 basic_iostream (受保护成员函数)


std::basic_spanstream<CharT,Traits>::rdbuf

< cpp‎ | io‎ | basic spanstream

std::basic_spanbuf<CharT, Traits>* rdbuf() const noexcept; | (C++23 起)

返回指向包装的原生设备对象的指针。

参数

（无）

返回值

指向包装的原生设备对象的指针。

示例

本节未完成
原因：暂无示例


std::basic_spanstream<CharT,Traits>::span

< cpp‎ | io‎ | basic spanstream

std::span<CharT> span() const noexcept; | (1) | (C++23 起)
void span( std::span<CharT> s ) noexcept; | (2) | (C++23 起)
1) 若包装的 std::basic_spanbuf 的打开模式中设置了 std::ios_base::out ，则获取引用被写入区域的 span ，否则获取引用底层缓冲区的 span 。
2) 使包装的 std::basic_spanbuf 进行 s 所引用的缓冲区上的 I/O 。

参数

s - 引用要用作流的新底层缓冲区的 std::span

返回值

1) 引用底层缓冲区或已写入区域的 std::span ，取决于包装的 std::basic_spanbuf 的打开模式。
2) （无）

示例

本节未完成
原因：暂无示例

参阅

span
(C++23)
 根据模式获得或初始化底层缓冲区
(std::basic_spanbuf<CharT,Traits> 的公开成员函数)


std::basic_spanstream<CharT,Traits>::swap

< cpp‎ | io‎ | basic spanstream

void swap( basic_spanstream& other ); | (C++23 起)

和 other 交换流状态。

这是通过调用 std::basic_iostream <CharT, Traits>::swap(other) 和交换包装的 std::basic_spanbuf 对象（可通过 *rdbuf() 访问）进行的。

参数

other - 要与之交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++23)
 交换二个 basic_spanbuf 对象
(std::basic_spanbuf<CharT,Traits> 的公开成员函数)


std::swap(std::basic_spanstream)

< cpp‎ | io‎ | basic spanstream

定义于头文件 <spanstream>
template< class CharT, class Traits >

void swap( std::basic_spanstream<CharT, Traits>& lhs,

std::basic_spanstream<CharT, Traits>& rhs );
 (C++23 起)

对 std::basic_spanstream 重载 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++23)
 交换二个 basic_spanstream 对象
(公开成员函数)


std::basic_streambuf

< cpp‎ | io
定义于头文件 <streambuf>
template<

class CharT,
class Traits = std::char_traits <CharT>

> class basic_streambuf;

类 basic_streambuf 控制字符序列的输入与输出。它包含下列内容并提供到它们的访问：

  1. 受控制字符序列，又称为缓冲区，它可含有为输入操作缓冲的输入序列（又称为获取区），和/或为输出操作缓冲的输出序列（又称为放置区）。
  2. 关联字符序列，又称作源（对于输入）或池（对于输出）。它可以是通过 OS API 访问的实体（文件、 TCP 接头、串行端口、其他字符设备），或者可以是能转译成字符源或池的对象（ std::vector 、数组、字符串字面量）。

I/O 流对象 std::basic_istream 及 std::basic_ostream ，还有所有派生自它们的对象（ std::ofstream 、 std::stringstream 等），都完全以 std::basic_streambuf 实现。

受控制字符序列是 CharT 的数组，它在所有时候都表示子序列，或对着关联字符序列的“窗”。其状态以三个指针描述：

  1. 起始指针 ，始终指向缓冲的最低元素
  2. 下一位置指针 ，指向读或写的下个候选元素
  3. 终止指针 ，指向缓冲区尾后一个位置。

basic_streambuf 对象可支持输入（该情况下起始、下一位置和终止指针所描述的区域被称为获取区）、输出（放置区），或同时输入与输出。在最后一种情况下，跟踪六个指针，它们可能全部指向同一数组的元素，或指向二个单独数组的元素。

若放置区中下一位置指针小于终止指针，则写位置可用。下一位置指针可被解引用和赋值。

若获取区中下一位置指针小于终止指针，则读位置可用。下一位置指针可被解引用和读取。

若获取区中下一位置指针大于起始指针，则回放位置可用，而下一位置指针可以被自减并赋值，以将字符放回到获取区。

受控制序列中的字符表示和编码可以异于关联序列中的字符表示，该情况下典型地用 std::codecvt 本地环境进行转换。常见的例子是通过 std::wfstream 对象访问 UTF-8 （或其他多字节编码）文件：受控制字符序列由 wchar_t 字符组成，但关联序列由字节组成。

std::basic_streambuf 基类的典型实现只保有六个 CharT* 指针和一个 std::locale 副本作为数据成员。另外，实现可以保持缓存的 locale 平面，凡在调用 imbue() 时非法化它。具体的缓冲类，如 std::basic_filebuf 或 std::basic_stringbuf 派生自 std::basic_streambuf 。

标准库提供二个便利 typedef

定义于头文件 <streambuf>
类型 | 定义
streambuf | basic_streambuf<char>
wstreambuf | basic_streambuf<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(析构函数)
[虚]
 析构 basic_streambuf 对象
(虚公开成员函数)
本地环境
pubimbue
 调用 imbue()
(公开成员函数)
getloc
 获得相关本地环境的副本
(公开成员函数)
寻位
pubsetbuf
 调用 setbuf()
(公开成员函数)
pubseekoff
 调用 seekoff()
(公开成员函数)
pubseekpos
 调用 seekpos()
(公开成员函数)
pubsync
 调用 sync()
(公开成员函数)
获取区
in_avail
 获得获取区中立即可用的字符数
(公开成员函数)
snextc
 令输入序列前进，读取一个字符而不再次前进
(公开成员函数)
sbumpcstossc
(C++17 中移除)
 从输入序列读取一个字符并令序列前进
(公开成员函数)
sgetc
 从输入序列读取一个字符，而不令序列前进
(公开成员函数)
sgetn
 调用 xsgetn()
(公开成员函数)
放置区
sputc
 写一个字符到放置区域，并令 next 指针前进
(公开成员函数)
sputn
 调用 xsputn()
(公开成员函数)
回放
sputbackc
 在输入序列中放回一个字符
(公开成员函数)
sungetc
 回移一位输出序列中的下一位置指针
(公开成员函数)

受保护成员函数
(构造函数)
 构造 basic_streambuf 对象
(受保护成员函数)
operator=
(C++11)
 替换 basic_streambuf 对象
(受保护成员函数)
swap
(C++11)
 交换二个 basic_streambuf 对象
(受保护成员函数)
本地环境
imbue
[虚]
 更改关联的本地环境
(虚受保护成员函数)
寻位
setbuf
[虚]
 若容许则以用户定义数组替换缓冲区
(虚受保护成员函数)
seekoff
[虚]
 用相对寻址重定位输入序列、输出序列或两者中的下一位置指针
(虚受保护成员函数)
seekpos
[虚]
 用绝对寻址重定位输入序列、输出序列或两者中的下一位置指针
(虚受保护成员函数)
sync
[虚]
 将缓冲与关联的字符序列同步
(虚受保护成员函数)
获取区
showmanyc
[虚]
 若已知，则获得关联输入序列中可用于输入的字符数
(虚受保护成员函数)
underflow
[虚]
 从关联输入序列读取字符到获取区
(虚受保护成员函数)
uflow
[虚]
 从输入序列读取字符到获取区，并令下一位置指针前进
(虚受保护成员函数)
xsgetn
[虚]
 从输入序列读取多个字符
(虚受保护成员函数)
ebackgptregptr
 返回指向获取区起始、当前字符和末尾的指针
(受保护成员函数)
gbump
 令输出序列中的下一位置指针前进
(受保护成员函数)
setg
 重定位输出序列的起始、下一位置和终止指针
(受保护成员函数)
放置区
xsputn
[虚]
 将多个字符写到输出序列
(虚受保护成员函数)
overflow
[虚]
 从放置区写入字符到关联的输出序列
(虚受保护成员函数)
pbasepptrepptr
 返回指向放置区的起始、当前字符和末尾的指针
(受保护成员函数)
pbump
 令输出序列中的下一位置指针前进
(受保护成员函数)
setp
 重定位输出序列的起始、下一位置和终止指针
(受保护成员函数)
回放
pbackfail
[虚]
 将字符放回输入序列，可能修改输入序列
(虚受保护成员函数)

参阅

FILE
 对象类型，足以保有控制 C I/O 流所需的全部信息
(typedef)


std::basic_streambuf<CharT,Traits>::basic_streambuf

< cpp‎ | io‎ | basic streambuf
protected: basic_streambuf(); | (1) |
protected: basic_streambuf(const basic_streambuf& rhs); | (2) | (C++11 起)
1) 构造 basic_streambuf 对象，初始化六个成员（ eback() 、 gptr() 、 egptr() 、 pbase() 、 pptr() 和 epptr() ）为空指针值， locale 成员为 std::locale () ，构造时的全局 C++ 本地环境的副本。
2) 从 rhs 复制构造，初始化六个指针和 locale 对象为 rhs 所保有值的副本。注意这是浅复制：新构造的 basic_streambuf 的指针指向的字符数组与 rhs 的相同。

两个构造函数均为受保护，而且仅为具体的 streambuf 类，如 std::basic_filebuf 、 std::basic_stringbuf 或 std::strstreambuf 调用。

参数

rhs - 要复制的 streambuf 对象

注解

C++11 前， basic_streambuf 或其任何派生类是否为可复制构造 (CopyConstructible) 是未指定的（ LWG 问题 421 ），而不同的 C++ 库实现提供不同的选项。

示例

本节未完成
原因：暂无示例

参阅

(构造函数) | 构造 basic_filebuf 对象 (std::basic_filebuf<CharT,Traits> 的公开成员函数)
(构造函数) | 构造一个 basic_stringbuf 对象 (std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)
(构造函数) | 构造 strstreambuf 对象 (std::strstreambuf 的公开成员函数)


std::basic_streambuf<CharT,Traits>::gbump

< cpp‎ | io‎ | basic streambuf
void gbump( int count );

跳过获取区中的 count 个字符。通过令获取指针前进 count 个字符。不为下溢做检查。

参数

count - 要跳过的字符数

返回值

（无）

注意

因为此函数接收 int ，故它无法操纵大于 std::numeric_limits<int>::max() 字符的缓冲区（ LWG 255 ）。

示例

本节未完成
原因：暂无示例

参阅

pbump
 令输出序列中的下一位置指针前进
(受保护成员函数)


std::basic_streambuf<CharT,Traits>::getloc

< cpp‎ | io‎ | basic streambuf
std::locale getloc() const;

返回关联的本地环境。

关联的本地环境是在最后一次调用 pubimbue() 时提供的值，或若未调用过该函数，则为在构造 streambuf 时全局本地环境的值（ std::locale ）。

参数

（无）

返回值

关联的本地环境。

示例

本节未完成
原因：暂无示例

参阅

pubimbue
 调用 imbue()
(公开成员函数)


std::basic_streambuf<CharT,Traits>::eback, gptr, egptr

< cpp‎ | io‎ | basic streambuf
char_type* eback() const; | (1)
char_type* gptr() const; | (2)
char_type* egptr() const; | (3)

返回定义获取区的指针。

1) 返回指向获取区起始的指针。

2) 返回指向获取区中当前字符的指针（获取指针）。

3) 返回获取区结尾后一位置的指针。

参数

（无）

返回值

1) 指向获取区起始的指针。

2) 指向获取区中当前字符的指针（获取指针）。

3) 获取区结尾后一位置的指针。

注意

名称 "gptr" 和 "egptr" 指代获取区，而名称 "eback" 指代回放区的结尾：从 gptr 往回步进，能放回字符到 eback 为止。

示例

本节未完成
原因：暂无示例

参阅

pbasepptrepptr
 返回指向放置区的起始、当前字符和末尾的指针
(受保护成员函数)


std::basic_streambuf<CharT,Traits>::in_avail

< cpp‎ | io‎ | basic streambuf
std::streamsize in_avail();

返回获取区中可用的字符数。若读位置可用，则等效地返回 egptr() - gptr() ，获取区的大小。此情况下，返回能从缓冲区释出而不调用 underflow() 的字节数。

若获取区为空，则调用 showmanyc() 确定关联字符序列中可用的字节数。此情况下，返回值是能从缓冲区释出，同时保证 underflow() 不会返回 Traits::eof 的字节数。

参数

（无）

返回值

非阻塞读取的可用字符数（从关联字符序列读取的获取区大小），或若只要 showmanyc() 能告知关联序列中无可用字符则为 -1 。

示例

本节未完成
原因：暂无示例

参阅

showmanyc [虚] | 可选地提供可用于从文件输入的字符数 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)
readsome | 读并取走已经可用的字符块 (std::basic_istream<CharT,Traits> 的公开成员函数)


std::basic_streambuf<CharT,Traits>::operator=

< cpp‎ | io‎ | basic streambuf
basic_streambuf& operator=( const basic_streambuf& other ); | (C++11 起)

赋值 other 的数据成员给 *this 。

参数

other - 要复制的流缓冲

返回值

*this

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例


std::basic_streambuf<CharT,Traits>::overflow

< cpp‎ | io‎ | basic streambuf
virtual int_type overflow( int_type ch = Traits::eof() );

通过保存始于 pbase() 的某个起始字符子序列到输入序列，并更新放置区（若需要），确保放置区有至少一个字符的空间。若 ch 不是 Traits::eof() （即 Traits::eq_int_type(ch, Traits::eof()) != true ），则将它放到放置区或直接保存到输出序列。

函数可以更新 pptr 、 epptr 和 pbase 指针以定义要写入更多数据的位置。失败时，函数确保 pptr() == nullptr 或 pptr() == epptr 。

函数的基类版本不做任何事。允许此函数的导出类版本在耗尽的情况下更新放置区。

参数

ch - 要存储于放置区的字符

返回值

成功时返回不等于 Traits::eof() 的未指定值，失败时返回 Traits::eof() 。

此函数的基类版本返回 Traits::eof() 。

注意

sputc() 和 sputn() 在可能上溢的情况（ pptr() == nullptr 或 pptr() >= epptr() ）下调用此函数。

示例

#include <iostream>
#include <array>

// 以 std::array 实现的 std::ostream 缓冲区
template<std::size_t SIZE, class CharT = char>
class ArrayedStreamBuffer : public std::basic_streambuf<CharT> {
public:

    using Base = std::basic_streambuf<CharT>;
    using char_type = typename Base::char_type;
    using int_type = typename Base::int_type;

    ArrayedStreamBuffer() : buffer_{} // 值初始化 buffer_ 为全零
    {
        Base::setp(buffer_.begin(), buffer_.end()); // 设置 std::basic_streambuf
            // 放置区指针以 'buffer_' 工作
    }

    int_type overflow(int_type ch)
    {
        std::cout << "overflow\n";
        return Base::overflow(ch);
    }

    void print_buffer()
    {
        for (const auto& i: buffer_) {
            if (i == 0) {
                std::cout << "NULL";
            } else {
                std::cout << i;
            }
            std::cout << " ";
        }
        std::cout << "\n";
    }

private:
    std::array<char_type, SIZE> buffer_;
};

int main()
{
    ArrayedStreamBuffer<10> streambuf;
    std::ostream stream(&streambuf);

    stream << "hello";
    streambuf.print_buffer();
    if (stream.good()) {
        std::cout << "stream is good\n";
    }

    stream << "world";
    streambuf.print_buffer();
    if (stream.good()) {
        std::cout << "stream is good\n";
    }

    stream << "!";
    streambuf.print_buffer();
    if (!stream.good()) {
        std::cout << "stream is not good\n";
    }
}

输出：

h e l l o NULL NULL NULL NULL NULL
stream is good
h e l l o w o r l d
stream is good
overflow
h e l l o w o r l d
stream is not good

参阅

uflow [虚] | 从输入序列读取字符到获取区，并令下一位置指针前进 (虚受保护成员函数)
underflow [虚] | 从关联输入序列读取字符到获取区 (虚受保护成员函数)
overflow [虚] | 从放置区写字符到关联的文件 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)
overflow [虚] | 后附字符到输出序列 (std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
overflow [虚] | 后附字符到输出序列，可能重分配或初始地分配缓冲区，若它为动态且未被冻结 (std::strstreambuf 的虚受保护成员函数)


std::basic_streambuf<CharT,Traits>::pbackfail

< cpp‎ | io‎ | basic streambuf
protected:
virtual int_type pbackfail( int_type c = Traits::eof() );

在下列情况之一时，此受保护虚函数为公开成员函数 sungetc() 和 sputbackc() 所调用（它们继而为 basic_istream::unget 和 basic_istream::putback 所调用）：

1) 获取区中无回放位置（以无参数调用 pbackfail() ）。此情形中， pbackfail() 的目的是令获取区后备一个字符，若关联字符序列允许（例如文件支持的 streambuf 可以在提前一个字符的位置，从文件重新加载缓冲区）。
2) 调用方试图回放异于先前取得字符的另一字符（以需要回放的字符调用 pbackfail() ）。此情形中， pbackfail() 的目的是将字符 c 置于获取区中刚好前于 basic_streambuf::gptr() 的位置，以及若可能则修改关联字符序列以反映此更改。这可能涉及如在第一变体中一般的后备获取区。

此函数的默认基类版本不做任何事并于所有情形返回 Traits::eof() 。导出类覆写此函数： basic_stringbuf::pbackfail 、 basic_filebuf::pbackfail 、 strstreambuf::pbackfail ，而且期待用户定义和第三方库流类也覆写此函数。

参数

ch - 要回放的字符，或若只请求放弃则为 Traits::eof()

返回值

失败情况下为 Traits::eof() ，某个不同值指示成功。基类版本始终失败。

示例

本节未完成
原因：暂无示例

参阅

pbackfail [虚] | 回退输出序列以放回字符，不影响关联文件 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)
pbackfail [虚] | 回放字符到输出序列中 (std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
pbackfail [虚] | 回退输入序列以反获取一个字符 (std::strstreambuf 的虚受保护成员函数)
sungetc | 回移一位输出序列中的下一位置指针 (公开成员函数)
sputbackc | 在输入序列中放回一个字符 (公开成员函数)


std::basic_streambuf<CharT,Traits>::pbump

< cpp‎ | io‎ | basic streambuf
void pbump( int count );

重寻位放置指针（ pptr() ） count 个字符，其中 count 可为正或负。不对将指针移出放置区 [pbase(), epptr()) 做检查。

若指针前进，然后调用 overflow() 冲入放置区到关联字符序列，则效果是输出拥有未定义值的额外 count 个字符。

参数

count - 加到放置指针的数

返回值

（无）

注意

因为此函数接收 int ，故它无法操纵大于 std::numeric_limits<int>::max() 字符的缓冲区（ LWG 255 ）。

示例

#include <iostream>
#include <string>
#include <fstream>

struct showput_streambuf : std::filebuf
{
    using std::filebuf::pbump; // 暴露受保护函数
    std::string showput() const {
        return std::string(pbase(), pptr());
    }
};

int main()
{
    showput_streambuf mybuf;
    mybuf.open("test.txt", std::ios_base::out);
    std::ostream str(&mybuf);
    str << "This is a test" << std::flush << "1234";
    std::cout << "The put area contains: " << mybuf.showput() << '\n';
    mybuf.pbump(10);
    std::cout << "after pbump(10), it contains " << mybuf.showput() << '\n';
}

输出：

The put area contains: 1234
after pbump(10), it contains 1234 is a test

参阅

gbump
 令输出序列中的下一位置指针前进
(受保护成员函数)


std::basic_streambuf<CharT,Traits>::pbase, std::basic_streambuf<CharT,Traits>::pptr, std::basic_streambuf<CharT,Traits>::epptr

< cpp‎ | io‎ | basic streambuf
char_type* pbase() const; | (1)
char_type* pptr() const; | (2)
char_type* epptr() const; | (3)

返回定义放置区的指针。

1) 返回指向放置区起始（“基”）的指针。

2) 返回指向放置区中当前字符的指针（放置指针）。

3) 返回指向放置区结尾后一位置的指针。

参数

（无）

返回值

1) 指向放置区起始的指针。

2) 指向放置区中当前字符的指针（放置指针）。

3) 指向放置区结尾后一位置的指针。

示例

本节未完成
原因：暂无示例

参阅

ebackgptregptr
 返回指向获取区起始、当前字符和末尾的指针
(受保护成员函数)


std::basic_streambuf<CharT,Traits>::pubimbue, std::basic_streambuf<CharT,Traits>::imbue

< cpp‎ | io‎ | basic streambuf
std::locale pubimbue( const std::locale & loc ); | (1)
protected: virtual void imbue( const std::locale & loc ); | (2)

更改关联的本地环境。

1) 设置 loc 为本地环境。调用最终导出类的 imbue(loc) 。

2) 此函数的基类版本无效果。导出类可覆写此函数以提示本地环境的更改。最终导出类可以在 imbue() 的调用间缓存本地环境和成员平面。

参数

loc - 要关联的 locale 对象

返回值

1) 先前关联的本地环境。

示例

本节未完成
原因：暂无示例

参阅

getloc
 获得相关本地环境的副本
(公开成员函数)


std::basic_streambuf<CharT,Traits>::pubseekoff, std::basic_streambuf<CharT,Traits>::seekoff

< cpp‎ | io‎ | basic streambuf
pos_type pubseekoff( off_type off, std::ios_base::seekdir dir,
std::ios_base::openmode which = ios_base::in | ios_base::out );
 (1)
protected:

virtual pos_type seekoff( off_type off, std::ios_base::seekdir dir,

std::ios_base::openmode which = ios_base::in | ios_base::out );
 (2)

相对某其他位置，设置输入和/或输出序列的位置指示器。

1) 调用最终导出类的 seekoff(off, dir, which)

2) 此函数的基类版本无效果。导出类可覆写此函数以允许位置指示器的相对寻位。

参数

off - 要设置位置指示器到的相对位置。
dir - 定义要应用相对偏移到的基位置。它能为下列常量之一：
常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置
which - 定义输入和/或输出序列何者有影响。它能为下列常量之一或其组合：
常量 | 解释
in | 影响输入序列
out | 影响输出序列

注意

并非所有参数组合都可以合法，细节见 seekoff 的导出类版本。

返回值

1) seekoff(off, dir, which) 的返回值

2) 位置指示器所定义的结果绝对位置。基类版本返回 pos_type(off_type(-1)) 。

示例

本节未完成
原因：暂无示例

参阅

pubseekpos | 调用 seekpos() (公开成员函数)
seekoff [虚] | 用相对寻址重寻位文件位置 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)
seekoff [虚] | 用相对寻址，重定位输入序列、输出序列或两者中的下一位置指针 (std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
seekoff [虚] | 用相对寻址重寻位输入序列、输出序列或两者中的下一位置指针 (std::strstreambuf 的虚受保护成员函数)


std::basic_streambuf<CharT,Traits>::pubseekpos, std::basic_streambuf<CharT,Traits>::seekpos

< cpp‎ | io‎ | basic streambuf
pos_type pubseekpos( pos_type pos, ios_base::openmode which = ios_base::in | ios_base::out ); | (1)
protected: virtual pos_type seekpos( pos_type pos, ios_base::openmode which = ios_base::in | ios_base::out); | (2)

设置输入和/或输出序列的位置指示器为绝对位置。

1) 调用最终导出类的 seekpos(pos, which)

2) 此函数的基类版本无效果。导出类可覆写此函数以允许位置指示器的绝对寻位。

参数

pos - 要设置位置指示器到的绝对位置。
which - 定义输入和/或输出序列何者有效果。它能为下列常量之一或其组合：
常量 | 解释
in | 影响输入序列
out | 影响输出序列

返回值

1) seekpos(pos, which) 的返回值

2) 位置指示器所定义的结果绝对位置。基类版本返回 pos_type(off_type(-1)) 。

示例

本节未完成
原因：暂无示例

参阅

pubseekoff
 调用 seekoff()
(公开成员函数)


std::basic_streambuf<CharT,Traits>::pubsetbuf, std::basic_streambuf<CharT,Traits>::setbuf

< cpp‎ | io‎ | basic streambuf
basic_streambuf<CharT, Traits>* pubsetbuf( char_type* s, std::streamsize n ) | (1)
protected: virtual basic_streambuf<CharT, Traits>* setbuf( char_type* s, std::streamsize n ) | (2)
1) 调用最终派生类上的 setbuf(s, n)
2) 此函数的基类版本无效果。派生类可覆写此函数，以允许移除或替换受控制字符序列（缓冲区）为用户提供的数组，或为任何实现特定的目的。

参数

s | - | 指向用户提供的缓冲区中首个 CharT 的指针
n | - | 用户提供缓冲区中的 CharT 元素数

返回值

1) setbuf(s, n) 的返回值
2) this

示例

为读取提供 10k 缓冲区。 Linux 上，可用 strace 工具观察实际读取的字节数

#include <fstream>
#include <iostream>
#include <string>

int main()
{
    int cnt = 0;
    std::ifstream file;
    char buf[1024*10 + 1];

    file.rdbuf()->pubsetbuf(buf, sizeof buf);

    file.open("/usr/share/dict/words");

    for (std::string line; getline(file, line);) {
        cnt++;
    }

    std::cout << cnt << '\n';
}

参阅

setbuf [虚] | 试图以数组替换受控字符序列 (std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
setbuf [虚] | 提供用户供应的缓冲区，或将此 filebuf 转变为无缓冲 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)
setbuf [虚] | 试图以数组替换受控制字符序列 (std::strstreambuf 的虚受保护成员函数)
setbuf | 为文件流设置缓冲区 (函数)


std::basic_streambuf<CharT,Traits>::pubsync, std::basic_streambuf<CharT,Traits>::sync

< cpp‎ | io‎ | basic streambuf
int pubsync(); | (1)
protected: virtual int sync(); | (2)

同步受控制字符序列（缓冲区）与关联字符序列。

1) 调用最终导出类的 sync()

2) 此函数的基类版本无效果。导出类可覆写此函数以允许将底层设备与缓冲区同步。

对于输出流，这典型地导致写入放置区的内容到关联序列中，即冲入输出缓冲区。对于输入流，这典型地清空获取区并从关联序列重读取，以拾取最近的更改。默认行为（例如 std::basic_stringbuf 中找到者）不会做任何事。

参数

（无）

返回值

1) sync() 的返回值。

2) 成功时返回 ​0​ ，否则返回 -1 。基类版本返回 ​0​ 。

示例

本节未完成
原因：暂无示例

参阅

sync | 与底层存储设备同步 (std::basic_istream<CharT,Traits> 的公开成员函数)
sync [虚] | 从放置区写字符到关联文件 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)


std::basic_streambuf<CharT,Traits>::sbumpc, std::basic_streambuf<CharT,Traits>::stossc

< cpp‎ | io‎ | basic streambuf
int_type sbumpc(); | (1) |
void stossc(); | (2) | (C++98 中弃用) (C++17 中移除)

读取一个字符并令输入序列前进一个字符。

1) 若输入序列读位置不可用，则返回 uflow() 。否则返回 Traits::to_int_type(*gptr()) 。
2) 同 (1) ，但舍弃结果。

参数

（无）

返回值

1) 获取指针所指向的字符的值，或若读位置不可用则为 Traits::eof() 。

示例

本节未完成
原因：暂无示例

参阅

sgetc | 从输入序列读取一个字符，而不令序列前进 (公开成员函数)
snextc | 令输入序列前进，读取一个字符而不再次前进 (公开成员函数)


std::basic_streambuf<CharT,Traits>::setg

< cpp‎ | io‎ | basic streambuf
void setg( char_type* gbeg, char_type* gcurr, char_type* gend );

设置定义获取区的指针值。特别是调用后 eback() == gbeg ， gptr() == gcurr ， egptr() == gend 。

参数

gbeg | - | 指向获取区新起始的指针
gcurr | - | 指向获取区中新的当前字符的指针（获取指针）
gend | - | 指向获取区新结尾的指针

返回值

（无）

示例

#include <iostream>
#include <sstream>

class null_filter_buf : public std::streambuf {
    std::streambuf* src;
    char ch; // 单字节缓冲区
protected:
    int underflow() {
        traits_type::int_type i;
        while ((i = src->sbumpc()) == '\0') ; // 跳过零
        if (traits_type::not_eof(i)) {
            ch = traits_type::to_char_type(i);
            setg(&ch, &ch, &ch+1); // 使得一个读取位置可用
        }
        return i;
    }
public:
    null_filter_buf(std::streambuf* buf) : src(buf) {
        setg(&ch, &ch+1, &ch+1); // 缓冲区初始为满
    }
};

void filtered_read(std::istream& in)
{
    std::streambuf* orig = in.rdbuf();
    null_filter_buf buf(orig);
    in.rdbuf(&buf);
    for(char c; in.get(c); )
            std::cout << c;
    in.rdbuf(orig);
}

int main()
{
    char a[] = "This i\0s \0an e\0\0\0xample";
    std::istringstream in(std::string(std::begin(a), std::end(a)));
    filtered_read(in);
}

输出：

This is an example

参阅

setp
 重定位输出序列的起始、下一位置和终止指针
(受保护成员函数)


std::basic_streambuf<CharT,Traits>::setp

< cpp‎ | io‎ | basic streambuf
void setp( char_type* pbeg, char_type* pend );

设置定义放置区的指针值。特别是调用后 pbase() == pbeg 、 pptr() == pbeg 、 epptr() == pend 。

参数

pbeg | - | 指向放置区新起始的指针
pend | - | 指向放置区新结尾的指针

返回值

（无）

示例

#include <iostream>
#include <array>

// 以 std::array 实现的 std::ostream 缓冲区
template<std::size_t SIZE, class CharT = char>
class ArrayedStreamBuffer : public std::basic_streambuf<CharT>
{
public:
    using Base = std::basic_streambuf<CharT>;
    using char_type = typename Base::char_type;

    ArrayedStreamBuffer() : buffer_{} // 值初始化 buffer_ 为全零
    {
        Base::setp(buffer_.begin(), buffer_.end()); // 设置 std::basic_streambuf
            // 放置区指针以 'buffer_' 工作
    }

    void print_buffer()
    {
        for (const auto& i: buffer_) {
            if (i == 0) {
                std::cout << "NULL";
            } else {
                std::cout << i;
            }
            std::cout << " ";
        }
        std::cout << "\n";
    }

private:
    std::array<char_type, SIZE> buffer_;
};

int main()
{
    ArrayedStreamBuffer<10> streambuf;
    std::ostream stream(&streambuf);

    stream << "hello";
    stream << ",";

    streambuf.print_buffer();
}

输出：

h e l l o , NULL NULL NULL NULL

参阅

setg
 重定位输出序列的起始、下一位置和终止指针
(受保护成员函数)


std::basic_streambuf<CharT,Traits>::sgetc

< cpp‎ | io‎ | basic streambuf
int_type sgetc();

从输入序列读取一个字符。

若输入序列读位置不可用，则返回 underflow() 。否则返回 Traits::to_int_type(*gptr()) 。

参数

（无）

返回值

获得指针所指向的字符的值。

示例

#include <iostream>
#include <sstream>

int main()
{
    std::stringstream stream("Hello, world");
    std::cout << "sgetc() returned '" << (char)stream.rdbuf()->sgetc() << "'\n";
    std::cout << "peek() returned '" << (char)stream.peek() << "'\n";
    std::cout << "get() returned '" << (char)stream.get() << "'\n";
}

输出：

sgetc() returned 'H'
peek() returned 'H'
get() returned 'H'

参阅

sbumpcstossc (C++17 中移除) | 从输入序列读取一个字符并令序列前进 (公开成员函数)
snextc | 令输入序列前进，读取一个字符而不再次前进 (公开成员函数)


std::basic_streambuf<CharT,Traits>::sgetn, std::basic_streambuf<CharT,Traits>::xsgetn

< cpp‎ | io‎ | basic streambuf
std::streamsize sgetn( char_type* s, std::streamsize count ); | (1)
protected: virtual std::streamsize xsgetn( char_type* s, std::streamsize count ); | (2)
1) 调用最终派生类的 xsgetn(s, count) 。
2) 从输入序列读取 count 个字符，并存储它们到 s 所指向的字符数组。如同用以连续调用 sbumpc() 读取字符。即若少于 count 个字符立即可用，则函数调用 uflow() 以提供更多字符，直至返回 Traits::eof() 。
容许派生自 std::basic_streambuf 的类提供此函数的更高效实现。

参数

s | - | 指向 char_type 数组起始的指针
count | - | 要写入的最大字符数

返回值

成功读取的字符数。若它小于 count ，则输入序列已抵达结尾。

注意

关于“更高效实现”的规则容许大量无中间缓冲的 I/O ：这是一些 iostream 的实现中 std::ifstream::read 简单地传递指针给 POSIX read() 系统调用的原因。

示例

本节未完成
原因：暂无示例

参阅

sputn
 调用 xsputn()
(公开成员函数)


std::basic_streambuf<CharT,Traits>::showmanyc

< cpp‎ | io‎ | basic streambuf
protected:
virtual std::streamsize showmanyc();

估计关联字符序列中可用于输入的字符数。保证直至释出那么多字符时， underflow() 不返回 Traits::eof() 或抛出异常。

参数

（无）

返回值

关联字符序列中确定可用的字符数，或若 showmanyc 能确定不阻塞则无字符可用则为 -1 。若 showmanyc 返回 -1 ，则 underflow() 和 uflow() 肯定会返回 Traits::eof 或抛出。

基类版本返回 ​0​ ，这表示“不缺地你给关联序列中是否有字符可用”。

注意

此函数的名称表示“流：多少字符？”，故它读作“ S how many C ”，而不是“ show many C ”。

示例

本节未完成
原因：暂无示例

参阅

in_avail | 获得获取区中立即可用的字符数 (公开成员函数)
showmanyc [虚] | 可选地提供可用于从文件输入的字符数 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)


std::basic_streambuf<CharT,Traits>::snextc

< cpp‎ | io‎ | basic streambuf
int_type snextc();

令输入序列前进一个字符，并读取一个字符。

函数调用 sbumpc() 令输入序列前进。若该函数返回表示已耗尽输入序列的 Traits::eof() ，且 uflow() 无法取得更多数据，则返回 Traits::eof() 。否则调用 sgetc() 以读取字符。

参数

（无）

返回值

下个字符的值。若已耗尽输入序列，则返回 Traits::eof() 。

示例

本节未完成
原因：暂无示例

参阅

sgetc | 从输入序列读取一个字符，而不令序列前进 (公开成员函数)
sbumpcstossc (C++17 中移除) | 从输入序列读取一个字符并令序列前进 (公开成员函数)


std::basic_streambuf<CharT,Traits>::sputbackc

< cpp‎ | io‎ | basic streambuf
int_type sputbackc( char_type c );

放回字符到获取区。

若回放位置在获取区中可用（ gptr() > eback() ），而字符 c 等于 gptr() 左一位置的字符（以 Traits::eq(c, gptr()[-1]) 确定），则简单地减少下一位置指针（ gptr() ）。

否则，调用 pbackfail(Traits::to_int_type(c)) 放回到获取区，或一同修改获取区和可能的关联字符序列。

I/O 流函数 basic_istream::putback 以此函数实现。

参数

c - 要回放的字符

返回值

若回放位置可用，则返回下一位置指针现在指向的字符，以 Traits::to_int_type(*gptr()) 转换为 int_type 。来自此 streambuf 的下个单字符输入将返回此字符。

若回放位置不可用，则返回 pbackfail() 所返回者，在失败时为 Traits::eof() 。

示例

#include <iostream>
#include <sstream>

int main()
{
    std::stringstream s("abcdef"); // gptr() 指向 "abcdef" 中的 'a'
    std::cout << "Before putback, string holds " << s.str() << '\n';
    char c1 = s.get(); // c1 = 'a' ， gptr() 现在指向 "abcdef" 中的 'b'
    char c2 = s.rdbuf()->sputbackc('z'); // 同 s.putback('z')
                                         // gptr() 现在指向 "zbcdef" 中的 'z'
    std::cout << "After putback, string holds " << s.str() << '\n';
    char c3 = s.get(); // c3 = 'z' ， gptr() 现在指向 "zbcdef" 中的 'b'
    char c4 = s.get(); // c4 = 'b' ， gptr() 现在指向 "zbcdef" 中的 'c'
    std::cout << c1 << c2 << c3 << c4 << '\n';

    s.rdbuf()->sputbackc('b');  // gptr() 现在指向 "zbcdef" 中的 'b'
    s.rdbuf()->sputbackc('z');  // gptr() 现在指向 "zbcdef" 中的 'z'
    int eof = s.rdbuf()->sputbackc('x');  // 无内容能反获取： pbackfail() 失败
    if (eof == EOF)
        std::cout << "No room to putback after 'z'\n";
}

输出：

Before putback, string holds abcdef
After putback, string holds zbcdef
azzb
No room to putback after 'z'

参阅

sungetc | 回移一位输出序列中的下一位置指针 (公开成员函数)
putback | 往输入流中退回一个字符 (std::basic_istream<CharT,Traits> 的公开成员函数)


std::basic_streambuf<CharT,Traits>::sputc

< cpp‎ | io‎ | basic streambuf
int_type sputc( char_type ch );

写一个字符到输出序列。

若输出序列写位置不可用（缓冲区满），则调用 overflow(ch) 。

参数

ch - 要写入的字符

返回值

被写入的字符，成功时用 Traits::to_int_type(ch) 转换成 int_type 。

失败时为 Traits::eof() （为 overflow() 所返回）。

示例

#include <iostream>
#include <sstream>

int main()
{
    std::ostringstream s;
    s.rdbuf()->sputc('a');
    std::cout << s.str() << '\n';
}

输出：

a

参阅

sputn
 调用 xsputn()
(公开成员函数)


std::basic_streambuf<CharT,Traits>::sputn, std::basic_streambuf<CharT,Traits>::xsputn

< cpp‎ | io‎ | basic streambuf
std::streamsize sputn( const char_type* s, std::streamsize count ); | (1)
protected: virtual std::streamsize xsputn( const char_type* s, std::streamsize count ); | (2)
1) 调用最终导出类的 xsputn(s, count) 。
2) 从首元素为 s 所指向的数组写 count 个字符到输出序列。如同以重复调用 sputc() 写入字符。在写入 count 字符后或调用 sputc() 会返回 Traits::eof() 时写入停止。

若放置区变满（ pptr() == epptr() ），则此函数可调用 overflow() ，或以其他未指定手段达成调用 overflow() 的效果。

参数

（无）

返回值

成功写入的字符数。

注解

“以未指定手段达成 overflow() 的效果”容许无中间缓冲的大量 I/O ：这是一些 iostream 的实现中， std::ofstream::write 简单地传递指针给适合的系统调用的缘由。

示例

#include <iostream>
#include <sstream>

int main()
{
    std::ostringstream s1;
    std::streamsize sz = s1.rdbuf()->sputn("This is a test", 14);
    s1 << '\n';
    std::cout << "The call to sputn() returned " << sz << '\n'
              << "The output sequence contains " << s1.str();

    std::istringstream s2;
    sz = s2.rdbuf()->sputn("This is a test", 14);
    std::cout << "The call to sputn() on an input stream returned " << sz << '\n';
}

输出：

The call to sputn() returned 14
The output sequence contains This is a test
The call to sputn() on an input stream returned 0

参阅

sgetn
 调用 xsgetn()
(公开成员函数)


std::basic_streambuf<CharT,Traits>::sungetc

< cpp‎ | io‎ | basic streambuf
int_type sungetc();

若回放位置在获取区中可用（ gptr() > eback() ），则减少下一位置指针（ gptr() ）并返回它现在指向的字符。

若回放位置不可用，则调用 pbackfail() 以在可能的情况下后备输入序列。

I/O 流函数 basic_istream::unget 以此函数实现。

参数

（无）

返回值

若回放位置可用，则返回下一位置指针现在指向的字符，以 Traits::to_int_type(*gptr()) 转换为 int_type 。来自此 streambuf 的下个单字符输入将返回此字符。

若回放位置不可用，则返回 pbackfail() 所返回者，在失败时为 Traits::eof() 。

示例

#include <iostream>
#include <sstream>

int main()
{
    std::stringstream s("abcdef"); // gptr() 指向 'a'
    char c1 = s.get(); // c = 'a', gptr() 现在指向 'b'
    char c2 = s.rdbuf()->sungetc(); // 同 s.unget() ： gptr() 又指向 'a'
    char c3 = s.get(); // c3 = 'a' ， gptr() 现在指向 'b'
    char c4 = s.get(); // c4 = 'b' ， gptr() 现在指向 'c'
    std::cout << c1 << c2 << c3 << c4 << '\n';

    s.rdbuf()->sungetc();  // 回到 'b'
    s.rdbuf()->sungetc();  // 回到 'a'
    int eof = s.rdbuf()->sungetc();  // 无内容可反获取： pbackfail() 失败
    if (eof == EOF)
            std::cout << "Nothing to unget after 'a'\n";
}

输出：

aaab
Nothing to unget after 'a'

参阅

sputbackc | 在输入序列中放回一个字符 (公开成员函数)
unget | 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符 (std::basic_istream<CharT,Traits> 的公开成员函数)


std::basic_streambuf<CharT,Traits>::swap

< cpp‎ | io‎ | basic streambuf
void swap( basic_streambuf& other ); | (C++11 起)

交换流缓冲与 other 的内容。

参数

other - 要交换内容的流缓冲

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例


std::basic_streambuf<CharT,Traits>::uflow

< cpp‎ | io‎ | basic streambuf
virtual int_type uflow();

通过更新指向输入区的指针（若需要），确保输入区中至少一个字符可用。成功时返回字符的值，并令获取指针的值前进一个字符。失败时返回 traits::eof() 。

函数可以更新 gptr 、 egptr 和 eback 指针，以定义新加载的数据位置（若存在）。失败时，函数确保 gptr() == nullptr 或 gptr() == egptr 。

函数的基类版本调用 underflow() 并自增 gptr() 。

参数

（无）

返回值

成功时为获取指针前进一之前所指向的字符的值，否则为 traits::eof() 。

函数的基类版本返回 underflow() 所返回的值。

注意

std::streambuf 的公开函数仅若 gptr() == nullptr 或 gptr() >= egptr() 才调用此函数。

要求不使用获取区且不设置 basic_streambuf 中获取区指针的定制 streambuf 类覆写此函数。

示例

本节未完成
原因：暂无示例

参阅

underflow [虚] | 从关联输入序列读取字符到获取区 (虚受保护成员函数)
overflow [虚] | 从放置区写入字符到关联的输出序列 (虚受保护成员函数)


std::basic_streambuf<CharT,Traits>::underflow

< cpp‎ | io‎ | basic streambuf
virtual int_type underflow();

通过更新指向输入区的指针（若需要），和从输入序列读取更多数据（若可用），确保输入区中至少一个字符可用。成功时返回该字符的值（以 int_type 转换为 Traits::to_int_type(c) ），失败时返回 Traits::eof() 。

函数可以更新 gptr 、 egptr 和 eback 指针，以定义新加载的数据位置（若存在）。失败时，函数确保 gptr() == nullptr 或 gptr() == egptr 。

函数的基类版本不做任何事。导出类可覆写此函数以允许在耗尽情况下更新获取区。

参数

（无）

返回值

成功时为调用后获取指针所指向的字符的值。否则为 Traits::eof() 。

函数的基类版本返回 traits::eof() 。

注意

std::streambuf 的公开函数仅若 gptr() == nullptr 或 gptr() >= egptr() 才调用此函数。

示例

#include <iostream>
#include <sstream>

class null_filter_buf : public std::streambuf {
    std::streambuf* src;
    char ch; // 单字节缓冲区
protected:
    int underflow() {
        traits_type::int_type i;
        while ((i = src->sbumpc()) == '\0') ; // 跳过零
        if (traits_type::not_eof(i)) {
            ch = traits_type::to_char_type(i);
            setg(&ch, &ch, &ch+1); // 使得一个读取位置可用
        }
        return i;
    }
public:
    null_filter_buf(std::streambuf* buf) : src(buf) {
        setg(&ch, &ch+1, &ch+1); // 缓冲区初始为满
    }
};

void filtered_read(std::istream& in)
{
    std::streambuf* orig = in.rdbuf();
    null_filter_buf buf(orig);
    in.rdbuf(&buf);
    for(char c; in.get(c); )
            std::cout << c;
    in.rdbuf(orig);
}

int main()
{
    char a[] = "This i\0s \0an e\0\0\0xample";
    std::istringstream in(std::string(std::begin(a), std::end(a)));
    filtered_read(in);
}

输出：

This is an example

参阅

uflow [虚] | 从输入序列读取字符到获取区，并令下一位置指针前进 (虚受保护成员函数)
overflow [虚] | 从放置区写入字符到关联的输出序列 (虚受保护成员函数)
underflow [虚] | 从关联文件读取 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)
underflow [虚] | 返回输入序列中可用的下一字符 (std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
underflow [虚] | 从输入序列读取一个字符而不前进下一位置指针 (std::strstreambuf 的虚受保护成员函数)


std::basic_streambuf<CharT,Traits>::~basic_streambuf

< cpp‎ | io‎ | basic streambuf
virtual ~basic_streambuf();

此析构函数为空：此 basic_streambuf 的成员（指针和本地环境）与此析构函数返回后的通常对象析构序列一致的顺序析构。然而，因为它被声明为公开虚函数，故通过指向基类的指针删除允许导出自 std::basic_streambuf 的对象。

参数

（无）

示例

#include <iostream>
#include <fstream>

int main()
{
    std::filebuf* fbp = new std::filebuf;
    fbp->open("test.txt", std::ios_base::out);
    fbp->sputn("Hello\n", 6);
    std::streambuf* sbp = fbp;
    delete sbp; // 关闭文件，冲入并写入输出
    std::ifstream f("test.txt");
    std::cout << f.rdbuf(); // 证明
}

输出：

Hello

参阅

(构造函数)
 构造 basic_streambuf 对象
(受保护成员函数)


std::basic_stringbuf

< cpp‎ | io
定义于头文件 <sstream>
template<

class CharT,
class Traits = std::char_traits <CharT>,
class Allocator = std::allocator <CharT>

> class basic_stringbuf : public std::basic_streambuf <CharT, Traits>

std::basic_stringbuf 是关联字符序列为内存常驻的任意字符序列的 std::basic_streambuf 。能从 std::basic_string 的实例初始化它，或将它做成该类的实例。

std::basic_stringbuf 的典型实现保有一个 std::basic_string 类型对象，或等价的可伸缩序列容器作为数据成员，并将它同时用作受控制字符序列（为 std::basic_streambuf 的六个指针所指向的数组）和关联字符序列（所有输入操作的字符源和输出操作的目标）。

另外，典型的实现保有一个 std::ios_base::openmode 类型的数据成员，以指示流的状态（只读、只写、读写、尾端写等）。

若 overflow() 使用过分配策略，则可存储另外的高水位指针，以跟踪最后初始化的字符。

 (C++11 起)

亦提供二个对常用字符类型的特化：

定义于头文件 <sstream>
类型 | 定义
stringbuf | basic_stringbuf<char>
wstringbuf | basic_stringbuf<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type
allocator_type | Allocator

成员函数

公开成员函数
(构造函数)
 构造一个 basic_stringbuf 对象
(公开成员函数)
operator=
(C++11)
 赋值 basic_stringbuf 对象
(公开成员函数)
swap
(C++11)
 交换二个 basic_stringbuf 对象
(公开成员函数)
(析构函数)
[虚] (隐式声明)
 析构 basic_stringbuf 对象和其所保有的 string
(虚公开成员函数)
str
 替换或获得关联字符串的副本
(公开成员函数)
get_allocator
(C++20)
 获得与内部 basic_string 关联的分配器的副本
(公开成员函数)
view
(C++20)
 获得底层字符序列上的视图
(公开成员函数)

受保护成员函数
underflow
[虚]
 返回输入序列中可用的下一字符
(虚受保护成员函数)
pbackfail
[虚]
 回放字符到输出序列中
(虚受保护成员函数)
overflow
[虚]
 后附字符到输出序列
(虚受保护成员函数)
setbuf
[虚]
 试图以数组替换受控字符序列
(虚受保护成员函数)
seekoff
[虚]
 用相对寻址，重定位输入序列、输出序列或两者中的下一位置指针
(虚受保护成员函数)
seekpos
[虚]
 用绝对寻址，重定位输入序列、输出序列或两者中的下一位置指针
(虚受保护成员函数)

非成员函数

std::swap(std::basic_stringbuf)
(C++11)
 特化 std::swap 算法
(函数模板)

继承自 std::basic_streambuf

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(析构函数)
[虚]
 析构 basic_streambuf 对象
(std::basic_streambuf<CharT,Traits> 的虚公开成员函数)
本地环境
pubimbue
 调用 imbue()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
getloc
 获得相关本地环境的副本
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
寻位
pubsetbuf
 调用 setbuf()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubseekoff
 调用 seekoff()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubseekpos
 调用 seekpos()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubsync
 调用 sync()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
获取区
in_avail
 获得获取区中立即可用的字符数
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
snextc
 令输入序列前进，读取一个字符而不再次前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sbumpcstossc
(C++17 中移除)
 从输入序列读取一个字符并令序列前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sgetc
 从输入序列读取一个字符，而不令序列前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sgetn
 调用 xsgetn()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
放置区
sputc
 写一个字符到放置区域，并令 next 指针前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sputn
 调用 xsputn()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
回放
sputbackc
 在输入序列中放回一个字符
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sungetc
 回移一位输出序列中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的公开成员函数)

受保护成员函数

(构造函数)
 构造 basic_streambuf 对象
(受保护成员函数)
operator=
(C++11)
 替换 basic_streambuf 对象
(受保护成员函数)
swap
(C++11)
 交换二个 basic_streambuf 对象
(受保护成员函数)
本地环境
imbue
[虚]
 更改关联的本地环境
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
寻位
setbuf
[虚]
 若容许则以用户定义数组替换缓冲区
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
seekoff
[虚]
 用相对寻址重定位输入序列、输出序列或两者中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
seekpos
[虚]
 用绝对寻址重定位输入序列、输出序列或两者中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
sync
[虚]
 将缓冲与关联的字符序列同步
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
获取区
showmanyc
[虚]
 若已知，则获得关联输入序列中可用于输入的字符数
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
underflow
[虚]
 从关联输入序列读取字符到获取区
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
uflow
[虚]
 从输入序列读取字符到获取区，并令下一位置指针前进
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
xsgetn
[虚]
 从输入序列读取多个字符
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
ebackgptregptr
 返回指向获取区起始、当前字符和末尾的指针
(受保护成员函数)
gbump
 令输出序列中的下一位置指针前进
(受保护成员函数)
setg
 重定位输出序列的起始、下一位置和终止指针
(受保护成员函数)
放置区
xsputn
[虚]
 将多个字符写到输出序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
overflow
[虚]
 从放置区写入字符到关联的输出序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
pbasepptrepptr
 返回指向放置区的起始、当前字符和末尾的指针
(受保护成员函数)
pbump
 令输出序列中的下一位置指针前进
(受保护成员函数)
setp
 重定位输出序列的起始、下一位置和终止指针
(受保护成员函数)
回放
pbackfail
[虚]
 将字符放回输入序列，可能修改输入序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)


std::basic_stringbuf<CharT,Traits,Allocator>::basic_stringbuf

< cpp‎ | io‎ | basic stringbuf
basic_stringbuf()
: basic_stringbuf( std::ios_base::in | std::ios_base::out ) { }
 (1) (C++11 起)
(2)
explicit basic_stringbuf( std::ios_base::openmode which =
std::ios_base::in | std::ios_base::out );
 (C++11 前)
explicit basic_stringbuf( std::ios_base::openmode which );
 (C++11 起)
explicit basic_stringbuf( const std::basic_string <CharT, Traits, Allocator>& s,

std::ios_base::openmode which =

std::ios_base::in | std::ios_base::out );
 (3)
basic_stringbuf( const basic_stringbuf& rhs ) = delete;
 (4) (C++11 起)
basic_stringbuf( basic_stringbuf&& rhs );
 (5) (C++11 起)
explicit basic_stringbuf( const Allocator& a )
: basic_stringbuf( std::ios_base::in | std::ios_base::out, a) { }
 (6) (C++20 起)
basic_stringbuf( std::ios_base::openmode which, const Allocator& a );
 (7) (C++20 起)
explicit basic_stringbuf( std::basic_string <CharT, Traits, Allocator>&& s,

std::ios_base::openmode which =

std::ios_base::in | std::ios_base::out );
 (8) (C++20 起)
template<class SAlloc>

basic_stringbuf( const std::basic_string <CharT, Traits, SAlloc>& s,
const Allocator& a )

: basic_stringbuf(s, std::ios_base::in | std::ios_base::out, a ) { }
 (9) (C++20 起)
template<class SAlloc>

basic_stringbuf( const std::basic_string <CharT, Traits, SAlloc>& s,

std::ios_base::openmode, const Allocator& a );
 (10) (C++20 起)
template<class SAlloc>

explicit basic_stringbuf( const std::basic_string <CharT, Traits, SAlloc>& s
std::ios_base::openmode which =

std::ios_base::in | std::ios_base::out );
 (11) (C++20 起)
basic_stringbuf( basic_stringbuf&& rhs, const Allocator& a );
 (12) (C++20 起)
1) 默认构造函数。是否初始化序列指针 (eback() 、 gptr() 、 egptr() 、 pbase() 、 pptr() 、 epptr()) 为空指针是实现定义的。
2) 构造 std::basic_stringbuf 对象：通过调用 std::basic_streambuf 的默认构造函数初始化基类，以空字符串初始化字符序列，并设置模式为 which 。
3) 通过进行同 (1) 中的的操作构造 std::basic_stringbuf 对象，随后如同通过调用 str(new_str) 初始化关联字符序列。
4) 复制构造函数被删除； std::basic_stringbuf 非可复制构造 (CopyConstructible) 。
5) 通过从另一 std::basic_stringbuf 对象 rhs 移动所有状态，包含关联 string 、打开模式、 locale 和所有其他状态，移动构造 std::basic_stringbuf 对象。移动后，保证 *this 中 std::basic_streambuf 的六个指针异于被移动的 rhs 中的指针，除非它们为空。
6-7) 同 (1-2) ，除了用 a 构造关联 string 。
8) 同 (3) ，除了用 std::move(s) 构造关联 string 。
9-10) 通过进行同 (1) 中的的操作构造 std::basic_stringbuf 对象，随后以 a 为其分配器，用 s 的内容初始化关联 string 。
11) 同 (3) ，除了 s 的分配器的类型不是 Allocator 。此重载仅若 SAlloc 与 Allocator 不是同一类型才参与重载决议。
12) 同 (5) ，除了用 a 构造关联 string 。

参数

s - 用于初始化缓冲区的 basic_string
a - 用于构造内部 basic_string 的另一分配器
rhs - 另一 basic_stringbuf
which - 指定流打开模式。它是位掩码类型，定义下列常量：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

注解

常由 std::basic_stringstream 的构造函数调用。

异于 std::ios_base::in 和 std::ios_base::out 的打开模式支持级别在实现中各异。 C++11 显式指定 str() 中和此构造函数中支持 std::ios_base::ate ，但 std::ios_base::app 、 std::ios_base::trunc 和 std::ios_base::binary 在不同实现上有不同效果。

示例

演示直接调用 basic_stringbuf 的构造函数。

#include <iostream>
#include <sstream>

int main()
{
    // 默认构造函数（ mode = in|out ）
    std::stringbuf buf1;
    buf1.sputc('1');
    std::cout << &buf1 << '\n';

    // 在尾端模式中的 string 构造函数 (C++11)
    std::stringbuf buf2("test", std::ios_base::in
                              | std::ios_base::out
                              | std::ios_base::ate);
    buf2.sputc('1');
    std::cout << &buf2 << '\n';

    // 后附模式测试（结果在编译器间有别）
    std::stringbuf buf3("test", std::ios_base::in
                              | std::ios_base::out
                              | std::ios_base::app);
    buf3.sputc('1');
    buf3.pubseekpos(1);
    buf3.sputc('2');
    std::cout << &buf3 << '\n';
}

输出：

1
test1
est12 (Sun Studio) 2st1 (GCC)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式

参阅

(构造函数)
 构造字符串流
(std::basic_stringstream<CharT,Traits,Allocator> 的公开成员函数)


std::basic_stringbuf<CharT,Traits,Allocator>::get_allocator

< cpp‎ | io‎ | basic stringbuf
allocator_type get_allocator() const noexcept; | (C++20 起)

返回与内部的 basic_string 关联的分配器。

参数

（无）

返回值

关联的分配器。

参阅

get_allocator
 返回关联的分配器
(std::basic_string<CharT,Traits,Allocator> 的公开成员函数)


std::basic_stringbuf<CharT,Traits,Allocator>::operator=

< cpp‎ | io‎ | basic stringbuf
std::basic_stringbuf & operator=( std::basic_stringbuf && rhs ); | (1) | (C++11 起)
std::basic_stringbuf & operator=( const std::basic_stringbuf & rhs ) = delete; | (2) |
1) 移动赋值运算符：移动 rhs 的内容到 *this 中。移动后 *this 拥有 rhs 之前保有的关联 string 、打开模式、本地环境和所有其他状态。保证 *this 中 std::basic_streambuf 的六个指针有别于被移动的 rhs 的对应指针，除非它们为空。
2) 复制赋值运算符被删除； basic_stringbuf 不可复制赋值 (CopyAssignable) 。

参数

rhs - 将被移动的另一 basic_stringbuf

返回值

*this

示例

#include <sstream>
#include <string>
#include <iostream>

int main()
{

    std::istringstream one("one");
    std::ostringstream two("two");

    std::cout << "Before move, one = \"" << one.str() << '"'
              << " two = \"" << two.str() << "\"\n";

    *one.rdbuf() = std::move(*two.rdbuf());

    std::cout << "After move, one = \"" << one.str() << '"'
              << " two = \"" << two.str() << "\"\n";
}

输出：

Before move, one = "one" two = "two"
After move, one = "two" two = ""

参阅

(构造函数)
 构造一个 basic_stringbuf 对象
(公开成员函数)


std::basic_stringbuf<CharT,Traits,Allocator>::overflow

< cpp‎ | io‎ | basic stringbuf
protected:
virtual int_type overflow ( int_type c = Traits::eof() );

后附字符 c 到输出字符序列。

若 c 为文件尾指示器（ traits::eq_int_type(c,traits::eof()) == true ），则不后附字符。函数不做任何操作并返回异于 traits::eof() 的未指定值。

否则，若输出序列拥有可用写位置，或若此函数成功令一个写位置可用，则调用 sputc(c) 并返回 c 。

若 stringbuf 为输出打开（ mode & ios_base::out) != 0 ），则此函数能令写位置可用：此情况下，它重分配（或在最初分配）足够大的缓冲区，以保有整个当前缓冲区加上至少一个字符。若 stringbuf 亦为输入打开（ (mode & ios_base::in) != 0 ），则 overflow 亦会通过移动 egptr() 到指向恰好越过新放置区的位置，来增加获取区的大小。

参数

c - 要存储于放置区的字符

返回值

若失败则为指示失败的 Traits::eof() 。若成功后附字符 c 则为 c 。或若以 Traits::eof() 为参数调用，则为某异于 Traits::eof() 的值。

注意

此函数异于典型的 overflow() ，后者移动缓冲区的内容到关联字符序列，因为 std::basic_stringbuf 的缓冲区和关联序列是同一序列。

示例

在用于执行此示例的实现中， overflow() 过分配放置区为 512 字节：调用 str() 会只返回四个初始字节，但剩下的 508 次对 sputc() 的调用不会要求对 overflow() 的新调用

#include <sstream>
#include <iostream>

struct mybuf : std::stringbuf
{
    mybuf(const std::string& new_str,
          std::ios_base::openmode which = std::ios_base::in|std::ios_base::out)
           : std::stringbuf(new_str, which) {}
    int_type overflow(int_type c = EOF) override
    {
        std::cout << "stringbuf::overflow('" << char(c) << "') called\n"
                  << "Before: size of get area: " << egptr() - eback() << '\n'
                  << "        size of put area: " << epptr() - pbase() << '\n';
        int_type ret = std::stringbuf::overflow(c);
        std::cout << "After : size of get area: " << egptr() - eback() << '\n'
                  << "        size of put area: " << epptr() - pbase() << '\n';
        return ret;
    }
};

int main()
{
    std::cout << "read-write stream:\n";
    mybuf sbuf("   "); // 只读流
    std::iostream stream(&sbuf);
    stream << 1234;
    std::cout << sbuf.str() << '\n';

    std::cout << "\nread-only stream:\n";
    mybuf ro_buf("   ", std::ios_base::in); // 只读流
    std::iostream ro_stream(&ro_buf);
    ro_stream << 1234;

    std::cout << "\nwrite-only stream:\n";
    mybuf wr_buf("   ", std::ios_base::out); // 只写流
    std::iostream wr_stream(&wr_buf);
    wr_stream << 1234;
}

可能的输出：

read-write stream:
stringbuf::overflow('4') called
Before: size of get area: 3
        size of put area: 3
After : size of get area: 4
        size of put area: 512
1234

read-only stream:
stringbuf::overflow('1') called
Before: size of get area: 3
        size of put area: 0
After : size of get area: 3
        size of put area: 0

write-only stream:
stringbuf::overflow('4') called
Before: size of get area: 0
        size of put area: 3
After : size of get area: 0
        size of put area: 512

参阅

overflow [虚] | 从放置区写入字符到关联的输出序列 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
underflow [虚] | 返回输入序列中可用的下一字符 (虚受保护成员函数)


std::basic_stringbuf<CharT,Traits,Allocator>::pbackfail

< cpp‎ | io‎ | basic stringbuf
protected:
virtual int_type pbackfail( int_type c = Traits::eof() )

此受保护虚函数为公开函数 basic_streambuf::sungetc 和 basic_streambuf::sputbackc 所调用（转而为 basic_istream::unget 和 basic_istream::putback 所调用）。

1) 调用方要求获取区后备一个字符（以无参数或以 Traits::eof() 为参数调用 pbackfail() ）
a) 首先，检查是否有回放位置，而若确实无回放位置则失败（ stringbuf 无重读用的外部字符序列）
b) 若调用方错误而回放位置实际上可用，则简单地自减 basic_streambuf::gptr() ，例如以调用 gbump(-1) 。
2) 调用方试图回放的字符异于之前取得者（以要需要放回的字符调用 pbackfail() ），该情况下
a) 首先，检查是否有回放位置，若无则失败。
b) 然后检查会放位置中有什么字符。若其处保有的字符已等于 c ，以 Traits::eq(to_char_type(c), gptr()[-1]) 确定，则简单地自减 basic_streambuf::gptr() 。
c) 否则，若缓冲区仅为读取打开，则失败。
d) 否则，若缓冲区为写入打开（ mode && std::ios_base::out 非零），则自减 basic_streambuf::gptr() 并写入 c 到调整后的 gptr() 所指向的位置。

参数

c - 要返回的字符，或若要求指示获取区的后备则为 Traits::eof()

返回值

成功时为 c ，除非 c 为 Traits::eof() ，该情况下返回 Traits::not_eof(c) 。

失败时为 Traits::eof() 。

示例

本节未完成
原因：暂无示例

参阅

pbackfail [虚] | 将字符放回输入序列，可能修改输入序列 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
sungetc | 回移一位输出序列中的下一位置指针 (std::basic_streambuf<CharT,Traits> 的公开成员函数)
sputbackc | 在输入序列中放回一个字符 (std::basic_streambuf<CharT,Traits> 的公开成员函数)
unget | 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符 (std::basic_istream<CharT,Traits> 的公开成员函数)
putback | 往输入流中退回一个字符 (std::basic_istream<CharT,Traits> 的公开成员函数)


std::basic_stringbuf<CharT,Traits,Allocator>::seekoff

< cpp‎ | io‎ | basic stringbuf
protected:

virtual pos_type seekoff(off_type off,
ios_base::seekdir dir,

ios_base::openmode which = ios_base::in | ios_base::out);

若可能，则重寻位 std::basic_streambuf::gptr 和/或 std::basic_streambuf::pptr 到对应距流的获取和/或放置区起始、结尾或当前位置准确 off 个字符的位置。

  • 若 which 包含 ios_base::in 而此缓冲为读取打开（即 ((which & ios_base::in) == ios_base::in ），则重寻位获取区内的读指针 std::basic_streambuf::gptr 如后述
  • 若 which 包含 ios_base::out 而此缓冲为写入打开（即 (which & ios_base::out) == ios_base::out ），则重寻位放置区内的写指针 std::basic_streambuf::pptr 如后述
  • 若 which 包含 ios_base::in 和 ios_base::out 两者而缓冲为读和写打开（ (which & (ios_base::in|ios_base::out)) ==(ios_base::in|ios_base::out) ）而 dir 为 ios_base::beg 或 ios_base::end 之一，则重寻位读和写指针如后述。
  • 否则，此函数失败。

若重寻位（ gptr 或 pptr 或两者），则按下列方式进行：

1) 若要重寻位的指针为空指针且新偏移 newoff 会为非零，则函数失败。
2) 确定 off_type 类型的新指针偏移 newoff
a) 若 dir == ios_base::beg ，则 newoff 为零
b) 若 dir == ios_base::cur ，则 newoff 为指针的当前位置（ gptr()-eback() 或 pptr()-pbase() ）
c) 若 dir == ios_base::end ，则 newoff 为缓冲区的整个已初始化部分的长度（若使用过分配，则为高水位指针减起始指针）
3) 若 newoff + off < 0 （重寻位会移动指针到缓冲区的起始指针之前）或若 newoff + off 会指向缓冲区结尾后（或若使用过分配，则为缓冲区中最后未初始化字符之后），则函数失败
4) 否则，如同以 gptr() = eback() + newoff + off 或 pptr() = pbase() + newoff + off 赋值指针。

参数

off - 要设置下一位置指针到的相对位置
dir - 定义应用偏移到的基位置。它能为下列常量之一：
常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置
which - 定义影响的是输入序列、输出序列还是两者。它能为下列常量之一或其组合：
常量 | 解释
in | 影响输入序列
out | 影响输出序列

返回值

成功时为 pos_type(newoff) ，失败时或若 pos_type 不能表示结果流位置则为 pos_type(off_type(-1)) 。

示例

#include <iostream>
#include <sstream>

int main()
{
    std::stringstream ss("123"); // 入/出
    std::cout << "put pos = " << ss.tellp()
              << " get pos = " << ss.tellg() << '\n';

    // 两个指针绝对寻位
    ss.rdbuf()->pubseekoff(1, std::ios_base::beg); // 都前移 1
    std::cout << "put pos = " << ss.tellp()
              << " get pos = " << ss.tellg() << '\n';

    // 试图从当前位置前移两个指针 1
    if(-1 == ss.rdbuf()->pubseekoff(1, std::ios_base::cur))
        std::cout << "moving both pointers from current position failed\n";
    std::cout << "put pos = " << ss.tellp()
              << " get pos = " << ss.tellg() << '\n';

    // 前移写指针 1 ，但不前移读指
    // can also be called as ss.seekp(1, std::ios_base::cur);
    ss.rdbuf()->pubseekoff(1, std::ios_base::cur, std::ios_base::out);
    std::cout << "put pos = " << ss.tellp()
              << " get pos = " << ss.tellg() << '\n';

    ss << 'a'; // 写入输出位置
    std::cout << "Wrote 'a' at put position, the buffer is now " << ss.str() << '\n';
    char ch;
    ss >> ch;
    std::cout << "reading at get position gives '" << ch << "'\n";
}

输出：

put pos = 0 get pos = 0
put pos = 1 get pos = 1
moving both pointers from current position failed
put pos = 1 get pos = 1
put pos = 2 get pos = 1
Wrote 'a' at put position, the buffer is now 12a
reading at get position gives '2'

参阅

seekpos [虚] | 用绝对寻址重定位输入序列、输出序列或两者中的下一位置指针 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
seekoff [虚] | 用相对寻址重定位输入序列、输出序列或两者中的下一位置指针 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
seekoff [虚] | 用相对寻址重寻位文件位置 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)


std::basic_stringbuf<CharT,Traits,Allocator>::seekpos

< cpp‎ | io‎ | basic stringbuf
protected:

virtual pos_type seekpos(pos_type sp,

std::ios_base::openmode which = std::ios_base::in | std::ios_base::out );

若可能，则重寻位 std::basic_streambuf::gptr 和/或 std::basic_streambuf::pptr 到 sp 所指示的位置。

等效地执行 seekoff(off_type(sp), std::ios_base::beg, which) 。

参数

sp - 流位置，例如由 seekoff() 或 seekpos() 获得者
which - 定义影响的是输入序列、输出序列或两者。它能为下列常量之一或其组合：
常量 | 解释
in | 影响输入序列
out | 影响输出序列

返回值

成功时为 sp ，失败时为 pos_type(off_type(-1)) 。

注解

seekpos() 为 std::basic_streambuf::pubseekpos() 所调用，它又为 std::basic_istream::seekg() 和 std::basic_ostream::seekp() 的单参数版本所调用。

示例

#include <sstream>
#include <iostream>

struct mybuf : std::stringbuf
{
    mybuf(const std::string& str) : std::stringbuf(str) {}
    pos_type seekpos(pos_type sp, std::ios_base::openmode which) {
         std::cout << "Before seekpos(" << sp << "), size of the get area is "
                   << egptr()-eback() << " with "
                   << egptr()-gptr() << " read positions available\n";
         pos_type rc = std::stringbuf::seekpos(sp, which);
         std::cout << "seekpos() returns " << rc << ".\nAfter the call, "
                   << "size of the get area is "
                   << egptr()-eback() << " with "
                   << egptr()-gptr() << " read positions available\n";
        return rc;
    }
};

int main()
{
    mybuf buf("12345");
    std::iostream stream(&buf);
    stream.seekg(2);
}

输出：

Before seekpos(2), size of the get area is 5 with 5 read positions available
seekpos() returns 2.
After the call, size of the get area is 5 with 3 read positions available

参阅

pubseekpos
 调用 seekpos()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
seekoff
[虚]
 用相对寻址，重定位输入序列、输出序列或两者中的下一位置指针
(虚受保护成员函数)
seekpos
[虚]
 用绝对寻址重寻位文件位置
(std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)
seekpos
[虚]
 用绝对寻址重寻位输入序列、输出序列或两者中的下一位置指针
(std::strstreambuf 的虚受保护成员函数)


std::basic_stringbuf<CharT,Traits,Allocator>::setbuf

< cpp‎ | io‎ | basic stringbuf
protected:
virtual std::basic_streambuf <CharT, Traits>* setbuf( char_type* s, std::streamsize n )

若 s 为空指针且 n 为零，则此函数无效果。

否则，效果是实现定义的：一些实现不做任何事，而一些实现清空当前用作缓冲区的 std::string 成员，并开始以用户提供的大小为 n ，首元素为 s 所指向的字符数组，为输入/输出字符序列的缓冲区。

此函数为受保护虚，仅可通过 pubsetbuf() 或导出自 std::basic_stringbuf 的用户定义类的成员函数调用它。

参数

s | - | 指向用户提供缓冲区首个 CharT 的指针或空指针
n | - | 用户提供缓冲区中的 CharT 元素数或零

返回值

this 。

注意

弃用的流缓冲 std::strstreambuf 或 boost.IOStreams 设备 boost::basic_array 可用于以可移植方式实现用户提供的字符数组上的 I/O 缓冲。

示例

测试 stringstream 的 setbuf 功能

#include <iostream>
#include <sstream>

int main()
{
    std::ostringstream ss;
    char c[1024] = {};
    ss.rdbuf()->pubsetbuf(c, 1024);
    ss << 3.14 << '\n';
    std::cout << c << '\n';
}

输出：

3.14 （ GNU g++/libstdc++ 和 SunPro C++/roguewave 上）
<无> （在 MS Visual Studio 2010 、 SunPro C++/stlport4 、 CLang++/libc++ 上）

参阅

pubsetbuf
 调用 setbuf()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)


std::basic_stringbuf<CharT,Traits,Allocator>::str

< cpp‎ | io‎ | basic stringbuf
 | (1) |
std::basic_string <CharT, Traits, Allocator> str() const; |  |  | (C++20 前)
std::basic_string <CharT, Traits, Allocator> str() const&; |  |  | (C++20 起)
template<class SAlloc> std::basic_string <CharT, Traits, Allocator> str( const SAlloc& a ) const; | (2) | (C++20 起)
std::basic_string <CharT, Traits, Allocator> str() &&; | (3) | (C++20 起)
void str( const std::basic_string <CharT, Traits, Allocator>& s ); | (4) |
template<class SAlloc> void str( const std::basic_string <CharT, Traits, SAlloc>& s ); | (5) | (C++20 起)
void str( std::basic_string <CharT, Traits, Allocator>&& s ); | (6) | (C++20 起)

获取和设置底层字符串。

为解释目的，令 buf_ 代表保有底层字符序列的内部 std::basic_string 对象。定义缓冲指针初始化如下：

  • 对于输入流（ bool(mode & std::ios_base::in ) == true ），使 eback() 指向首字符， gptr() == eback() ，而 egptr() == eback() + buf_.size() ：后继输入将读取首个字符串的字符。
  • 对于输出流（ bool(mode & std::ios_base::out ) == true ），使 pbase() 指向首字符而 epptr() >= pbase() + buf_.size() （允许 epptr() 指向更后，以令后随的 sputc() 不会立即调用 overflow() ）
  • 对于后附流（ bool(mode & std::ios_base::ate ) == true ），使 pptr() == pbase() + buf_.size() ，从而后继输出将被后附到字符串的最后字符。
 (C++11 起)
  • 对于非后附输出流，使 pptr() == pbase() ，从而后继输出将重写字符串的字符。
1) 创建并返回保有此 std::basic_stringbuf 底层字符序列副本的 std::basic_string 。对于仅输入流，返回的字符串含来自范围 [eback(), egptr()) 的字符。对于输入/输出或仅输出流，含有 pbase() 到序列中末字符的字符，不考虑 egptr() 和 epptr() 。

为写入打开的缓冲区中的成员字符序列能为效率目的过分配。该情况下，仅返回初始化的字符：从构造函数 string 参数获得的字符、最近对 str() 的设置器重载的 string 参数的字符或来自写入操作的字符。典型的使用过分配的实现维护一个高水位指针，以跟踪缓冲区已初始化部分的结尾，而此重载返回从 pbase() 到高水位指针的字符。

 (C++11 起)

等价于 return std::basic_string <CharT, Traits, Allocator>(view(), get_allocator()); 。

 (C++20 起)
2) 同 (1) ，除了用 a 构造返回的 std::basic_string 。等价于 return std::basic_string <CharT, Traits, SAlloc>(view(), a); 。此重载仅若 SAlloc 满足分配器 (Allocator) 的要求才参与重载决议。
3) 创建 std::basic_string 对象，如同以 std::move(buf_) 初始化。可能需要首先调节 buf_ 以使之含有同 (1) 的内容。构造该 std::basic_string 对象后，设置 buf_ 为空并进行缓冲指针初始化，然后返回 std::basic_string 对象。
4) 如同用 buf_ = s 替换底层字符序列，然后进行缓冲指针初始化。
5) 同 (4) ，除了 s 的分配器的类型不是 Allocator 。此重载仅若 SAlloc 与 Allocator 不是同一类型才参与重载决议。
6) 如同用 buf_ = std::move(s) 替换底层字符序列，然后进行缓冲指针初始化。

参数

s | - | 保有替换字符序列的 basic_string 对象
a | - | 返回的 basic_string 的所有内存分配所用的分配器

返回值

1-3) 保有此缓冲的底层字符序列的 basic_string 对象。
4-6) （无）

注解

常通过 std::basic_istringstream::str() 、 std::basic_ostringstream::str() 或 std::basic_stringstream::str() 访问此函数。

示例

#include <sstream>
#include <iostream>
int main()
{
    int n;

    std::istringstream in;  // 亦能用 in("1 2")
    in.rdbuf()->str("1 2"); // 设置获取区
    in >> n;
    std::cout << "after reading the first int from \"1 2\", the int is "
              << n << ", str() = \"" << in.rdbuf()->str() << "\"\n"; // 或 in.str()

    std::ostringstream out("1 2");
    out << 3;
    std::cout << "after writing the int '3' to output stream \"1 2\""
              << ", str() = \"" << out.str() << "\"\n";

    std::ostringstream ate("1 2", std::ios_base::ate); // C++11
    ate << 3;
    std::cout << "after writing the int '3' to append stream \"1 2\""
              << ", str() = \"" << ate.str() << "\"\n";
}

输出：

after reading the first int from "1 2", the int is 1, str() = "1 2"
after writing the int '3' to output stream "1 2", str() = "3 2"
after writing the int '3' to append stream "1 2", str() = "1 23"

参阅

str | 获取或设置底层字符串设备对象的内容 (std::basic_stringstream<CharT,Traits,Allocator> 的公开成员函数)
view (C++20) | 获得底层字符序列上的视图 (公开成员函数)


std::basic_stringbuf<CharT,Traits,Allocator>::swap

< cpp‎ | io‎ | basic stringbuf
void swap( std::basic_stringbuf & rhs ); | (C++11 起) (C++20 前)
void swap( std::basic_stringbuf & rhs ) noexcept(/* see below */); | (C++20 起)

交换 *this 和 rhs 的状态与内容。

若 Allocator 不在交换时传播且 *this 与 other 的分配器不相等则行为未定义。

 (C++11 起)

参数

rhs - 另一 basic_stringbuf

返回值

（无）

异常

可能抛出实现定义的异常。

 (C++11 起)
(C++20 前)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::propagate_on_container_swap::value
|| std::allocator_traits <Allocator>::is_always_equal::value)
 (C++20 起)

注解

交换 std::stringstream 对象时自动调用此函数，很少需要直接调用它。

示例

#include <sstream>
#include <string>
#include <iostream>

int main()
{

    std::istringstream one("one");
    std::ostringstream two("two");

    std::cout << "Before swap, one = \"" << one.str() << '"'
              << " two = \"" << two.str() << "\"\n";

    *one.rdbuf()->swap(*two.rdbuf());

    std::cout << "Before swap, one = \"" << one.str() << '"'
              << " two = \"" << two.str() << "\"\n";
}

输出：

Before swap, one = "one" two = "two"
Before swap, one = "two" two = "one"

参阅

(构造函数) | 构造一个 basic_stringbuf 对象 (公开成员函数)
swap (C++11) | 交换两个字符串流 (std::basic_stringstream<CharT,Traits,Allocator> 的公开成员函数)


std::swap(std::basic_stringbuf)

< cpp‎ | io‎ | basic stringbuf
定义于头文件 <sstream>
template< class CharT, class Traits, class Alloc >

void swap( std::basic_stringbuf <CharT,Traits,Alloc>& lhs,

std::basic_stringbuf <CharT,Traits,Alloc>& rhs );
 (C++11 起)
(C++20 前)
template< class CharT, class Traits, class Alloc >

void swap( std::basic_stringbuf <CharT,Traits,Alloc>& lhs,
std::basic_stringbuf <CharT,Traits,Alloc>& rhs )

noexcept(noexcept(lhs.swap(rhs)));
 (C++20 起)

为 std::basic_stringbuf 特化 std::swap 算法。交换 lhs 与 rhs 的内部状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的 std::basic_stringbuf 对象

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

swap (C++11) | 交换二个 basic_stringbuf 对象 (公开成员函数)
swap | 交换两个对象的值 (函数模板)


std::basic_stringbuf<CharT,Traits,Allocator>::underflow

< cpp‎ | io‎ | basic stringbuf
protected:
virtual int_type underflow()

从缓冲的获取区读取下个字符。

具体而言：

1) 若输入序列拥有可用的读位置（ egptr() > gptr() ），则返回 Traits::to_int_type(*gptr()) 。
2) 否则，若 pptr() > egptr() （从上次更改 egptr() 的 overflow() 起插入了一些字符到流中），则通过更改 egptr() 为等于 pptr() ，扩展获取区结尾以包含最近插入的字符，再返回 Traits::to_int_type(*gptr()) 。
3) 否则，返回 Traits::eof() 。

缓冲区中任何已被初始化的字符，无关乎它源自构造函数中传递的字符串还是为 overflow() 所后附，都被认为是输入序列的一部分。

参数

（无）

返回值

成功情况下为 Traits::to_int_type(*gptr()) （获取区中要读取的下个字符），失败情况下为 Traits::eof() 。

示例

#include <sstream>
#include <iostream>

struct mybuf : std::stringbuf
{
    mybuf(const std::string& new_str,
          std::ios_base::openmode which = std::ios_base::in|std::ios_base::out)
           : std::stringbuf(new_str, which) {}

    int_type overflow(int_type c) {
        std::cout << "Before overflow(): get area size is " << egptr()-eback() << ' '
                  << " the put area size is " << epptr()-pbase() << '\n';
        int_type rc = std::stringbuf::overflow(c);
        std::cout << "After overflow(): get area size is " << egptr()-eback() << ' '
                  << " put area size is " << epptr()-pbase() << '\n';
        return rc;
    }

    int_type underflow() {
        std::cout << "Before underflow(): get area size is " << egptr()-eback() << ' '
                  << " put area size is " << epptr()-pbase() << '\n';
        int_type ch = std::stringbuf::underflow();
        std::cout << "After underflow(): get area size is " << egptr()-eback() << ' '
                  << " put area size is " << epptr()-pbase() << '\n';
        if(ch == EOF)
            std::cout << "underflow() returns EOF\n";
        else
            std::cout << "underflow() returns '" << char(ch) << "'\n";
        return ch;
    }
};

int main()
{
    mybuf sbuf("123"); // 读写流
    std::iostream stream(&sbuf);
    int n;
    stream >> n; // 调用 sgetc() 四次
                 // 三次调用返回字符 '1' 、 '2' 、 '3'
                 // 第四次调用， gptr() == egptr() 并调用 underflow()
                 // underflow 返回 EOF
    std::cout << n << '\n';
    stream.clear(); // 清除 eofbit

    stream << "123456"; // 调用 sputc() 6 次
                        // 前三次调用存储 "123" 于既存缓冲区
                        // 第 4 次调用发现 pptr() == epptr() 并调用 overflow()
                        // overflow() 令缓冲区生长并设置 egptr() 为 4
                        // 第 5 和第 6 次调用存储 '5' 和 '6' ，令 pptr() 前进
    stream >> n; // 调用 sgetc() 4 次
                 // 第 1 次调用返回 overflow() 使之可用的 '4'
                 // 第 2 次调用时， egptr() == egptr() 并调用 underflow()
                 // underflow 令 egptr() 前进到等于 pptr() (which is 6)
                 // 第 3 次 sgetc() 返回 '6'
                 // 第 4 次 sgetc() 发现 gptr() == egptr() ，调用 underflow()
                 // underflow() 返回 EOF
    std::cout << n << '\n';
}

可能的输出：

Before underflow(): get area size is 3  put area size is 3
After underflow(): get area size is 3  put area size is 3
underflow() returns EOF
123
Before overflow(): get area size is 3  the put area size is 3
After overflow(): get area size is 4  put area size is 35
Before underflow(): get area size is 4  put area size is 35
After underflow(): get area size is 6  put area size is 35
underflow() returns '5'
Before underflow(): get area size is 6  put area size is 35
After underflow(): get area size is 6  put area size is 35
underflow() returns EOF
456

参阅

underflow [虚] | 从关联输入序列读取字符到获取区 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
underflow [虚] | 从关联文件读取 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)
underflow [虚] | 从输入序列读取一个字符而不前进下一位置指针 (std::strstreambuf 的虚受保护成员函数)
sgetc | 从输入序列读取一个字符，而不令序列前进 (std::basic_streambuf<CharT,Traits> 的公开成员函数)


std::basic_stringbuf<CharT,Traits,Allocator>::view

< cpp‎ | io‎ | basic stringbuf
std::basic_string_view <CharT, Traits> view() const noexcept; | (C++20 起)

创建并返回底层字符序列上的 std::basic_string_view 。

  • 对于仅输入流，返回视图表示范围 [eback(), egptr()) 。
  • 对于输入/输出或仅输出流，引用从 pbase() 到序列中末字符的字符，不考虑 egptr() 和 epptr() 。
  • 若流既非输入亦非输出，则返回 std::basic_string_view <CharT, Traits>{} 。

为写入打开的缓冲区中的成员字符序列能为效率目的过分配。该情况下，仅引用初始化的字符：从构造函数 string 参数获得的字符、最近对 str() 的设置器重载的 string 参数的字符或来自写入操作的字符。典型的使用过分配的实现维护一个高水位指针，以跟踪缓冲区已初始化部分的结尾，而返回的视图引用从 pbase() 到高水位指针的字符。

参数

（无）

返回值

底层字符序列上的视图。

注解

若底层字符序列被销毁或被非法化，则使用返回值是未定义行为，除非返回值为空。

常通过 std::basic_istringstream::view() 、 std::basic_ostringstream::view() 或 std::basic_stringstream::view() 访问此函数。

参阅

str | 替换或获得关联字符串的副本 (公开成员函数)
operator basic_string_view (C++17) | 返回到整个字符串的不可修改的 basic_string_view (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)


std::basic_stringstream

< cpp‎ | io
定义于头文件 <sstream>
template<

class CharT,
class Traits = std::char_traits <CharT>,
class Allocator = std::allocator <CharT>

> class basic_stringstream;

类模板 std::basic_stringstream 实现基于字符串的流上的输入与输出操作。它等效地存储一个 std::basic_string 的实例，并在其上进行输入与输出操作。

该类实际上在低层包装 std::basic_stringbuf 的原生字符串设备到 std::basic_iostream 的高层接口中。提供到独有 std::basic_stringbuf 成员的完整接口。

cpp/io/ios base cpp/io/basic ios cpp/io/basic istream cpp/io/basic ostream cpp/io/basic iostream

继承图

亦为常用字符类型定义二个特化：

定义于头文件 <sstream>
类型 | 定义
stringstream | basic_stringstream<char>
wstringstream | basic_stringstream<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type
allocator_type | Allocator

成员函数

(构造函数)
 构造字符串流
(公开成员函数)
operator=
(C++11)
 移动字符串流
(公开成员函数)
swap
(C++11)
 交换两个字符串流
(公开成员函数)
rdbuf
 返回底层未处理的字符串设备对象
(公开成员函数)
字符串操作
str
 获取或设置底层字符串设备对象的内容
(公开成员函数)
view
(C++20)
 获得底层字符串设备的内容上的视图
(公开成员函数)

非成员函数

std::swap(std::basic_istringstream)
(C++11)
 特化 std::swap 算法
(函数模板)

继承自 std::basic_istream

成员函数

有格式输入
operator>>
 提取带格式数据
(std::basic_istream<CharT,Traits> 的公开成员函数)
无格式输入
get
 从流中读并取走（移除类似指针向下一个元素移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
peek
 仅读出但不取走（不移除类似指针并未移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
unget
 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
putback
 往输入流中退回一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
getline
 一直读并取走字符，直至找到给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
ignore
 读且取走并舍弃字符，直至发现给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
read
 读并取走一块字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
readsome
 读并取走已经可用的字符块
(std::basic_istream<CharT,Traits> 的公开成员函数)
gcount
 返回上次无格式输出操作所取走的字符数量
(std::basic_istream<CharT,Traits> 的公开成员函数)
寻位
tellg
 返回输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
seekg
 设置输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
杂项
sync
 与底层存储设备同步
(std::basic_istream<CharT,Traits> 的公开成员函数)

成员类

sentry
 实现为输出操作准备流的基本逻辑
(std::basic_istream<CharT,Traits> 的公开成员类)

继承自 std::basic_ostream

成员函数

有格式输出
operator<<
 插入带格式数据
(std::basic_ostream<CharT,Traits> 的公开成员函数)
无格式输出
put
 插入字符
(std::basic_ostream<CharT,Traits> 的公开成员函数)
write
 插入字符块
(std::basic_ostream<CharT,Traits> 的公开成员函数)
寻位
tellp
 返回输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
seekp
 设置输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
杂项
flush
 与底层存储设备同步
(std::basic_ostream<CharT,Traits> 的公开成员函数)

成员类

sentry
 为输出操作实现流准备的基本逻辑
(std::basic_ostream<CharT,Traits> 的公开成员类)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)


std::basic_stringstream<CharT,Traits,Allocator>::basic_stringstream

< cpp‎ | io‎ | basic stringstream

basic_stringstream()
: basic_stringstream( std::ios_base::in | std::ios_base::out ) { }
 (1) (C++11 起)
(2)
explicit basic_stringstream( std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out );
 (C++11 前)
explicit basic_stringstream( std::ios_base::openmode mode );
 (C++11 起)
explicit basic_stringstream( const std::basic_string <CharT,Traits,Allocator>& str,
std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out );
 (3)
basic_stringstream( basic_stringstream&& other );
 (4) (C++11 起)
basic_stringstream( std::ios_base::openmode mode, const Allocator& a );
 (5) (C++20 起)
explicit basic_stringstream( std::basic_string <CharT,Traits,Allocator>&& str,
std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out );
 (6) (C++20 起)
template<class SAlloc>

basic_stringstream( const std::basic_string <CharT,Traits,SAlloc>& str,
const Allocator& a )

: basic_stringstream(str, std::ios_base::in | std::ios_base::out, a) { }
 (7) (C++20 起)
template<class SAlloc>

basic_stringstream( const std::basic_string <CharT,Traits,SAlloc>& str,

std::ios_base::openmode mode, const Allocator& a );
 (8) (C++20 起)
template<class SAlloc>

explicit basic_stringstream( const std::basic_string <CharT,Traits,SAlloc>& str,

std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out );
 (9) (C++20 起)

构造新的字符串流。

1) 默认构造函数。以默认打开模式构造新的底层字符串设备。
2) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(mode) 构造底层 basic_stringbuf 对象。
3) 以 str 的副本为底层字符串设备的初始内容。以 basic_stringbuf<Char,Traits,Allocator>(str, mode) 构造底层 basic_stringbuf 对象。
4) 移动构造函数。用移动语义，构造拥有 other 的状态的字符串流。
5) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(mode, a) 构造底层 basic_stringbuf 对象。
6) 用 str 移动构造底层字符串设备的内容。以 basic_stringbuf<Char,Traits,Allocator>(std::move(str), mode) 构造底层 basic_stringbuf 对象。
7) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(str, std::ios_base::in | std::ios_base::out, a) 构造底层 basic_stringbuf 对象。
8) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(str, mode, a) 构造底层 basic_stringbuf 对象。
9) 构造新的底层字符串设备。以 basic_stringbuf<Char,Traits,Allocator>(str, mode) 构造底层 basic_stringbuf 对象。此重载仅若 SAlloc 与 Allocator 不是同一类型才参与重载决议。

参数

str - 用于初始化字符串流内容的字符串
mode - 指定流打开模式。它是位掩码类型，定义下列常量：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾
other - 用作源的另一字符串流

注解

在短的循环中，例如在用于字符串转换时构造单次使用的 basic_stringstream 对象，开销可能显著高于调用 str 并复用同一对象。

示例

#include <iostream>
#include <sstream>
int main()
{
    // 默认构造函数（输入/输出流）
    std::stringstream buf1;
    buf1 << 7;
    int n = 0;
    buf1 >> n;
    std::cout << "buf1 = " << buf1.str() << " n = " << n << '\n';

    // 输入流
    std::istringstream inbuf("-10");
    inbuf >> n;
    std::cout << "n = " << n << '\n';

    // 输出流在 append 模式 (C++11)
    std::ostringstream buf2("test", std::ios_base::ate);
    buf2 << '1';
    std::cout << buf2.str() << '\n';
}

输出：

buf1 = 7 n = 7
n = -10
test1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式

参阅

str | 获取或设置底层字符串设备对象的内容 (公开成员函数)
(构造函数) | 构造一个 basic_stringbuf 对象 (std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)


std::basic_stringstream::operator=

< cpp‎ | io‎ | basic stringstream
basic_stringstream& operator=( basic_stringstream&& other ); | (C++11 起)

移动赋值字符串流 other 给 *this ，等效的移动赋值 std::basic_iostream 基类和关联的 std::basic_stringbuf 。

注意，基类移动赋值交换 *this 与 other 间的所有流状态变量（除了 rdbuf ）。

参数

other - 移动来源的字符串流

返回值

*this

示例

本节未完成
原因：暂无示例

参阅

swap (C++11) | 交换两个字符串流 (公开成员函数)
operator= (C++11) | 赋值 basic_stringbuf 对象 (std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)
operator= (C++11) | 移动赋值另一 basic_iostream (受保护成员函数)


std::basic_stringstream::rdbuf

< cpp‎ | io‎ | basic stringstream

std::basic_stringbuf <CharT, Traits, Allocator>* rdbuf() const;

返回指向底层未处理字符串设备对象的指针。

参数

（无）

返回值

指向底层未处理字符串设备对象的指针。

示例

本节未完成
原因：暂无示例


std::basic_stringstream<CharT,Traits,Allocator>::str

< cpp‎ | io‎ | basic stringstream

 | (1) |
std::basic_string <CharT,Traits,Allocator> str() const; |  |  | (C++20 前)
std::basic_string <CharT,Traits,Allocator> str() const&; |  |  | (C++20 起)
template<class SAlloc> std::basic_string <CharT,Traits,SAlloc> str( const SAlloc& a ) const; | (2) | (C++20 起)
std::basic_string <CharT,Traits,Allocator> str() &&; | (3) | (C++20 起)
void str( const std::basic_string <CharT,Traits,Allocator>& s ); | (4) |
template<class SAlloc> void str( const std::basic_string <CharT,Traits, SAlloc>& s ); | (5) | (C++20 起)
void str( std::basic_string <CharT,Traits,Allocator>&& s ); | (6) | (C++20 起)

管理底层字符串对象的内容。

1) 返回底层字符串的副本。等价于 return rdbuf()->str(); 。
2) 返回底层字符串的副本，以 a 为分配器。等价于 return rdbuf()->str(a); 。
3) 返回从底层字符串移动构造的字符串。等价于 return std::move(*rdbuf()).str(); 。
4-5) 替换底层字符串。等价于 rdbuf()->str(s); 。
6) 替换底层字符串。等价于 rdbuf()->str(std::move(s)); 。

参数

s | - | 底层字符串的新内容
a | - | 用于构造返回的字符串的分配器

返回值

1-2) 底层字符串对象的副本。
3) 从底层字符串对象移动构造的字符串。
4-6) （无）

注解

str 所返回的底层字符串副本是将于表达式结尾析构的临时对象，故在 str() 的结果上直接调用 c_str() （例如 auto *ptr = out.str().c_str(); 中）导致悬垂指针。

示例

#include <sstream>
#include <iostream>
int main()
{
    int n;

    std::istringstream in;  // 亦可使用 in("1 2")
    in.str("1 2");
    in >> n;
    std::cout << "after reading the first int from \"1 2\", the int is "
              << n << ", str() = \"" << in.str() << "\"\n";

    std::ostringstream out("1 2");
    out << 3;
    std::cout << "after writing the int '3' to output stream \"1 2\""
              << ", str() = \"" << out.str() << "\"\n";

    std::ostringstream ate("1 2", std::ios_base::ate);
    ate << 3;
    std::cout << "after writing the int '3' to append stream \"1 2\""
              << ", str() = \"" << ate.str() << "\"\n";
}

输出：

after reading the first int from "1 2", the int is 1, str() = "1 2"
after writing the int '3' to output stream "1 2", str() = "3 2"
after writing the int '3' to append stream "1 2", str() = "1 23"

参阅

str
 替换或获得关联字符串的副本
(std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)


std::basic_stringstream::swap

< cpp‎ | io‎ | basic stringstream

void swap( basic_stringstream& other ); | (C++11 起)

交换流与 other 的状态。

通过调用 basic_iostream<CharT, Traits>::swap(other) 和 rdbuf()->swap(*other.rdbuf()) 进行。

参数

other - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

operator= (C++11) | 移动字符串流 (公开成员函数)
swap (C++11) | 交换二个 basic_stringbuf 对象 (std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)


std::swap(std::basic_stringstream)

< cpp‎ | io‎ | basic stringstream

定义于头文件 <sstream>
template< class CharT, class Traits, class Alloc >

void swap( std::basic_stringstream <CharT,Traits,Alloc>& lhs,

std::basic_stringstream <CharT,Traits,Alloc>& rhs );
 (C++11 起)

对 std::basic_stringstream 重载 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的流

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++11)
 交换两个字符串流
(公开成员函数)


std::basic_stringstream<CharT,Traits,Allocator>::view

< cpp‎ | io‎ | basic stringstream

std::basic_string_view <CharT, Traits> view() const noexcept; | (C++20 起)

获得底层字符串对象上的 std::basic_string_view 。等价于 return rdbuf()->view(); 。

参数

（无）

返回值

底层字符串对象上的 std::basic_string_view 。

示例

本节未完成
原因：暂无示例

参阅

view
(C++20)
 获得底层字符序列上的视图
(std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)


std::basic_syncbuf

< cpp‎ | io
定义于头文件 <syncstream>
template<

class CharT,
class Traits = std::char_traits <CharT>,
class Allocator = std::allocator <CharT>

> class basic_syncbuf : public std::basic_streambuf <CharT, Traits>
 (C++20 起)

std::basic_syncbuf 是 std::basic_streambuf （在构造时作为指针提供）的包装。它在其自身的缓冲区中积累输出，然后在析构和显式请求时将其整个内容原子地传输给被包装缓冲，故而它们作为相接的字符序列出现。保证无数据竞争，而且发送给被包装缓冲的字符无穿插，只要所有其他对同一流缓冲的输出都通过可能不同的 std::basic_syncbuf 实例。

std::basic_syncbuf 的典型实现保有指向一个被包装的 std::basic_streambuf 的指针、一个指示是否在同步（冲入）时将传输其内容给被包装缓冲的布尔标志、一个指示策略非同步时发射（ emit on sync ）时的待决冲入的布尔标志、一个使用 Allocator 的内部缓冲区（如 std::string ）和一个指向互斥的指针，该互斥用于在多个访问同一被包装流缓冲的线程间同步发射（这些互斥可以在以指向 basic_streambuf 对象的指针为关键的哈希映射中）。

同其他 streambuf 类，通常仅通过对应的流 std::osyncstream 而非直接访问 std::basic_syncbuf 。

亦定义对二个常用字符类型的特化：

定义于头文件 <syncstream>
类型 | 定义
syncbuf | basic_syncbuf<char>
wsyncbuf | basic_syncbuf<wchar_t>

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type
allocator_type | Allocator
streambuf_type | std::basic_streambuf <CharT, Traits>

成员函数

公开成员函数
(构造函数)
 构造 basic_syncbuf 对象
(公开成员函数)
operator=
 赋值 basic_syncbuf 对象
(公开成员函数)
swap
 交换二个 basic_syncbuf 对象
(公开成员函数)
(析构函数)
 析构 basic_syncbuf 并发射其内部缓冲区
(公开成员函数)
emit
 原子地传输整个内部缓冲区给被包装 streambuf
(公开成员函数)
get_wrapped
 获得被包装的 streambuf 指针
(公开成员函数)
get_allocator
 获得此 basic_syncbuf 所用的分配器
(公开成员函数)
set_emit_on_sync
 更改当前同步时发射策略
(公开成员函数)

受保护成员函数
sync
 依赖于当前的同步时发射策略，发射或记录待决的冲入
(公开成员函数)

非成员函数

std::swap(std::basic_syncbuf)
(C++20)
 特化 std::swap 算法
(函数模板)

继承自 std::basic_streambuf

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(析构函数)
[虚]
 析构 basic_streambuf 对象
(std::basic_streambuf<CharT,Traits> 的虚公开成员函数)
本地环境
pubimbue
 调用 imbue()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
getloc
 获得相关本地环境的副本
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
寻位
pubsetbuf
 调用 setbuf()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubseekoff
 调用 seekoff()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubseekpos
 调用 seekpos()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubsync
 调用 sync()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
获取区
in_avail
 获得获取区中立即可用的字符数
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
snextc
 令输入序列前进，读取一个字符而不再次前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sbumpcstossc
(C++17 中移除)
 从输入序列读取一个字符并令序列前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sgetc
 从输入序列读取一个字符，而不令序列前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sgetn
 调用 xsgetn()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
放置区
sputc
 写一个字符到放置区域，并令 next 指针前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sputn
 调用 xsputn()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
回放
sputbackc
 在输入序列中放回一个字符
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sungetc
 回移一位输出序列中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的公开成员函数)

受保护成员函数

(构造函数)
 构造 basic_streambuf 对象
(受保护成员函数)
operator=
(C++11)
 替换 basic_streambuf 对象
(受保护成员函数)
swap
(C++11)
 交换二个 basic_streambuf 对象
(受保护成员函数)
本地环境
imbue
[虚]
 更改关联的本地环境
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
寻位
setbuf
[虚]
 若容许则以用户定义数组替换缓冲区
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
seekoff
[虚]
 用相对寻址重定位输入序列、输出序列或两者中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
seekpos
[虚]
 用绝对寻址重定位输入序列、输出序列或两者中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
sync
[虚]
 将缓冲与关联的字符序列同步
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
获取区
showmanyc
[虚]
 若已知，则获得关联输入序列中可用于输入的字符数
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
underflow
[虚]
 从关联输入序列读取字符到获取区
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
uflow
[虚]
 从输入序列读取字符到获取区，并令下一位置指针前进
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
xsgetn
[虚]
 从输入序列读取多个字符
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
ebackgptregptr
 返回指向获取区起始、当前字符和末尾的指针
(受保护成员函数)
gbump
 令输出序列中的下一位置指针前进
(受保护成员函数)
setg
 重定位输出序列的起始、下一位置和终止指针
(受保护成员函数)
放置区
xsputn
[虚]
 将多个字符写到输出序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
overflow
[虚]
 从放置区写入字符到关联的输出序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
pbasepptrepptr
 返回指向放置区的起始、当前字符和末尾的指针
(受保护成员函数)
pbump
 令输出序列中的下一位置指针前进
(受保护成员函数)
setp
 重定位输出序列的起始、下一位置和终止指针
(受保护成员函数)
回放
pbackfail
[虚]
 将字符放回输入序列，可能修改输入序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)


std::basic_syncbuf<CharT,Traits,Allocator>::basic_syncbuf

< cpp‎ | io‎ | basic syncbuf
basic_syncbuf() : basic_syncbuf(nullptr) | (1)
explicit basic_syncbuf( streambuf_type* obuf ) : basic_syncbuf( obuf, Allocator() ) {} | (2)
basic_syncbuf( streambuf_type* obuf, const Allocator& a); | (3)
basic_syncbuf( basic_syncbuf&& rhs); | (4)
1) 默认构造函数：创建 std::basic_syncbuf 的实例，将其同步时发生（ emit-on-sync ）策略设为 false ，被包装流缓冲设为 nullptr ，并以默认构造的 Allocator 为临时存储的分配器。
2,3) 创建 std::basic_syncbuf 的实例，将其同步时发生（ emit-on-sync ）策略设为 false ，被包装流缓冲设为 obuf ，并以 a 为临时存储的分配器。
3) 移动构造函数：通过从另一 std::basic_syncbuf 对象 rhs 移动所有内容，包括临时存储、被包装流指针、策略及所有其他状态（例如互斥指针），移动构造 std::basic_syncbuf 对象。移动后， rhs 不与流关联，而 rhs.get_wrapped()==nullptr 。 rhs 的基类 std::basic_streambuf 的放置区指针保证为空。销毁被移动的 rhs 将不产生任何输出。

参数

obuf | - | 指向要包装的 std::basic_streambuf 的指针
a | - | 用于临时存储的分配器
rhs | - | 作为移动来源的另一 std::basic_syncbuf

异常

2,3) 可能从内部临时存储的构造函数抛出 std::bad_alloc ，或从互斥的构造抛出 std::system_error 。

注解

通常为 std::basic_osyncstream 的适当构造函数所调用。

示例

本节未完成
原因：暂无示例

参阅

sync [虚] | 将缓冲与关联的字符序列同步 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
emit | 原子地传输整个内部缓冲区给被包装 streambuf (公开成员函数)


std::basic_syncbuf<CharT,Traits,Allocator>::emit

< cpp‎ | io‎ | basic syncbuf
bool emit();

原子地传输所有待决输出到被包装流。

所有传输字符到同一被包装流缓冲对象的 emit() 调用以单独全序出现，在该全序中，每个 emit() 调用同步于后继的 emit() 调用，即使这些调用通过不同的 std::basic_syncbuf/std::basic_osyncstream 实例进行。实践中，这表示 emit() 采用与被包装流对象唯一关联的锁：例如，能在一个静态哈希映射中保有锁，其中将被包装流的地址用作关键。

若最近对 emit() 的调用导致调用了 sync ，则它会调用其上的 pubsync() 冲入被包装流。

参数

（无）

返回值

若以下均为真则返回 true ：

  • 有被包装流（被包装的流缓冲指针非空）
  • 已成功将所有字符从临时存储发送到被包装流
  • 若请求调用 pubsync() ，则它亦成功完成。

否则返回 false 。

注意

通常为占有流缓冲的 std::basic_osyncstream 或 std::basic_osyncstream::emit 所调用。

示例

本节未完成
原因：暂无示例

参阅

(析构函数) | 销毁 basic_osyncstream 并发射其内部缓冲区 (std::basic_osyncstream<CharT,Traits,Allocator> 的公开成员函数)
emit | 调用底层 basic_syncbuf 上的 emit 以传输其内部数据到最终目标 (std::basic_osyncstream<CharT,Traits,Allocator> 的公开成员函数)
(构造函数) | 构造 basic_syncbuf 对象 (公开成员函数)


std::basic_syncbuf<CharT,Traits,Allocator>::get_allocator

< cpp‎ | io‎ | basic syncbuf
allocator_type get_allocator() const noexcept;

返回作为构造函数参数传入，或通过赋值运算符替换的分配器的副本。

参数

（无）

示例

本节未完成
原因：暂无示例

参阅

(构造函数) | 构造 basic_syncbuf 对象 (公开成员函数)
operator= | 赋值 basic_syncbuf 对象 (公开成员函数)


std::basic_syncbuf<CharT,Traits,Allocator>::get_wrapped

< cpp‎ | io‎ | basic syncbuf
streambuf_type* get_wrapped() const noexcept;

返回指向被包装的 std::basic_streambuf 的指针。

参数

（无）

注意

不期待直接调用此函数：通过 std::basic_osyncstream::get_wrapped 调用它。

示例

本节未完成
原因：暂无示例

参阅

get_wrapped
 获得指向最终目标流缓冲的指针
(std::basic_osyncstream<CharT,Traits,Allocator> 的公开成员函数)


std::basic_syncbuf<CharT,Traits,Allocator>::operator=

< cpp‎ | io‎ | basic syncbuf
basic_syncbuf& operator=(basic_syncbuf&& other);

首先，调用 emit() 传输所有待决输出（和延迟冲入，若存在）到被包装流。

然后通过从other 移动所有内容，包括临时存储、被包装的流指针、策略及所有其他状态（如互斥指针），进行移动赋值。移动后， other 不与流关联，而 other.get_wrapped()==nullptr 。 other 的 std::basic_streambuf 基类的放置区成员指针保证为空。销毁被移动的 other 将不会产生任何输出。

若 std::allocator_traits <Allocator>::propagate_on_container_move_assignment::value 为 false ，则不更改分配器。否则，移动后 get_allocator() 等于 other.get_allocator() 。

参数

other - 要移动的另一 std::basic_syncbuf

返回值

*this

示例

本节未完成
原因：暂无示例

参阅

operator= | 赋值 basic_osyncstream (std::basic_osyncstream<CharT,Traits,Allocator> 的公开成员函数)
(构造函数) | 构造 basic_syncbuf 对象 (公开成员函数)
emit | 原子地传输整个内部缓冲区给被包装 streambuf (公开成员函数)
swap | 交换二个 basic_syncbuf 对象 (公开成员函数)


std::basic_syncbuf<CharT,Traits,Allocator>::set_emit_on_sync

< cpp‎ | io‎ | basic syncbuf
void set_emit_on_sync( bool b ) noexcept;

更改当前的同步时发射（ emit-on-sync ）策略。

值 false （默认值）指示任何冲入都将被延迟到对 emit 的调用。

值 true 使冲入立即应用。

参数

b - 同步时发生策略的新值

示例

本节未完成
原因：暂无示例

参阅

sync [虚] | 将缓冲与关联的字符序列同步 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
emit | 原子地传输整个内部缓冲区给被包装 streambuf (公开成员函数)
emit_on_flushnoemit_on_flush (C++20) | 控制流的 basic_syncbuf 是否在冲入时发射 (函数模板)


std::basic_syncbuf<CharT,Traits,Allocator>::swap

< cpp‎ | io‎ | basic syncbuf
void swap( basic_syncbuf& other ) noexcept;

交换同步流缓冲的状态与 other 的状态。

参数

other - 要与之交换内容的同步流缓冲

返回值

（无）

示例

本节未完成
原因：暂无示例


std::swap(std::basic_syncbuf)

< cpp‎ | io‎ | basic syncbuf
template< class CharT, class Traits, class Allocator >

void swap( std::basic_syncbuf<CharT, Traits, Allocator>& lhs,

std::basic_syncbuf<CharT, Traits, Allocator>& rhs ) noexcept;
 (C++20 起)

std::swap 算法对 std::basic_syncbuf 的重载。

交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的 std::basic_syncbuf 对象

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

swap | 交换二个 basic_syncbuf 对象 (公开成员函数)
swap | 交换两个对象的值 (函数模板)


std::basic_syncbuf<CharT,Traits,Allocator>::sync

< cpp‎ | io‎ | basic syncbuf
protected:
int sync() override;

首先，以更新适当的私有标志，记录冲入为未决。

然后，若当前的同步时发射（ emit-on-sync ）策略为 true ，则调用 emit() 。

否则，（若同步时发射策略为默认的 false ），则悬挂冲入，直至调用 emit() ，例如通过 std::basic_osyncstream::emit() 或 std::basic_osyncstream::~basic_osyncstream 。

参数

（无）

注意

sync() 或其等价版本为 close() 、 seekoff() 和 seekpos() 所隐式调用，并且为 std::basic_streambuf::pubsync() 所显式调用。

示例

本节未完成
原因：暂无示例

参阅

sync [虚] | 将缓冲与关联的字符序列同步 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
emit | 调用底层 basic_syncbuf 上的 emit 以传输其内部数据到最终目标 (std::basic_osyncstream<CharT,Traits,Allocator> 的公开成员函数)


std::basic_syncbuf<CharT,Traits,Allocator>::~basic_syncbuf

< cpp‎ | io‎ | basic syncbuf
~basic_syncbuf();

调用 emit() 传输所有待决输出（和延迟冲入，若存在）到被包装流。若此调用抛出异常，则捕获并忽略异常。

参数

（无）

注意

通常为拥有它的 std::basic_osyncstream 的析构函数所调用。

示例

本节未完成
原因：暂无示例

参阅

(析构函数) | 销毁 basic_osyncstream 并发射其内部缓冲区 (std::basic_osyncstream<CharT,Traits,Allocator> 的公开成员函数)
(构造函数) | 构造 basic_syncbuf 对象 (公开成员函数)


C 风格文件输入/输出

< cpp‎ | io

C++ 标准库的 C I/O 子集实现 C 风格流输入/输出操作。 <cstdio> 头文件提供通用文件支持并提供有窄和多字节字符输入/输出能力的函数，而 <cwchar> 头文件提供有宽字符输入/输出能力的函数。

C 流为 std::FILE 类型对象所代表，只能通过 std::FILE* 类型指针访问及操作。每个 C 流与外部物理设备（文件、标准输入流、打印机、序列端口等）关联。

类型

定义于头文件 <cstdio>
FILE | 对象类型，足以保有控制 C I/O 流所需的全部信息 (typedef)
fpos_t | 完整非数组对象类型，足以唯一指定文件中的位置，包含其多字节剖析状态 (typedef)

预定义标准流

定义于头文件 <cstdio>
stdinstdoutstderr
 与输入流关联到 FILE* 类型表达式
与输出流关联的 FILE* 类型表达式
与错误输出流关联的 FILE* 类型表达式
(宏常量)

函数

定义于头文件 <cstdio>
文件访问
fopen
 打开文件
(函数)
freopen
 以不同名称打开既存流
(函数)
fclose
 关闭文件
(函数)
fflush
 将输出流与实际文件同步
(函数)
fwide
 在宽字符 I/O 和窄字符 I/O 间切换文件流
(函数)
setbuf
 为文件流设置缓冲区
(函数)
setvbuf
 为文件流设置缓冲区与其大小
(函数)
直接输入/输出
fread
 从文件读取
(函数)
fwrite
 写入文件
(函数)
无格式输入/输出
字节/多字节字符
fgetcgetc
 从文件流获取字符
(函数)
fgets
 从文件流获取字符串
(函数)
fputcputc
 写字符到文件流
(函数)
fputs
 写字符串到文件流
(函数)
getchar
 从 stdin 读取字符
(函数)
gets
(C++11 中弃用)(C++14 中移除)
 从 stdin 读取字符串
(函数)
putchar
 写字符到 stdout
(函数)
puts
 写字符串到 stdout
(函数)
ungetc
 把字符放回文件流
(函数)
宽字符
fgetwcgetwc
 从文件流获取宽字符
(函数)
fgetws
 从文件流获取宽字符串
(函数)
fputwcputwc
 写宽字符到文件流
(函数)
fputws
 写宽字符串到文件流
(函数)
getwchar
 从 stdin 读取宽字符
(函数)
putwchar
 写宽字符到 stdout
(函数)
ungetwc
 把宽字符放回文件流
(函数)
有格式输入/输出
字节/多字节字符
scanffscanfsscanf
 从 stdin、文件流或缓冲区读取有格式输入
(函数)
vscanfvfscanfvsscanf
(C++11)(C++11)(C++11)
 使用可变实参列表
从 stdin、文件流或缓冲区读取有格式输入
(函数)
printffprintfsprintfsnprintf
(C++11)
 打印有格式输出到 stdout、文件流或缓冲区
(函数)
vprintfvfprintfvsprintfvsnprintf
(C++11)
 使用可变实参列表
打印有格式输出到 stdout、文件流或缓冲区
(函数)
宽字符
wscanffwscanfswscanf
 从 stdin、文件流或缓冲区读取有格式宽字符输入
(函数)
vwscanfvfwscanfvswscanf
(C++11)(C++11)(C++11)
 使用可变实参列表
从 stdin、文件流或缓冲区读取有格式宽字符输入
(函数)
wprintffwprintfswprintf
 打印有格式宽字符输出到 stdout、文件流或缓冲区
(函数)
vwprintfvfwprintfvswprintf
 使用可变实参列表打印
有格式宽字符输出到 stdout、文件流或缓冲区
(函数)
文件寻位
ftell
 返回当前文件位置指示器
(函数)
fgetpos
 获取文件位置指示器
(函数)
fseek
 移动文件位置指示器到文件中的指定位置
(函数)
fsetpos
 移动文件位置指示器到文件中的指定位置
(函数)
rewind
 移动文件位置指示器到文件起始
(函数)
错误处理
clearerr
 清除错误
(函数)
feof
 检查文件尾
(函数)
ferror
 检查文件错误
(函数)
perror
 显示对应当前错误的字符串于 stderr
(函数)
文件上的操作
remove
 删除文件
(函数)
rename
 重命名文件
(函数)
tmpfile
 创建并打开一个临时、自动移除的文件
(函数)
tmpnam
 返回一个唯一独有的文件名
(函数)

宏常量

定义于头文件 <cstdio>
EOF
 拥有 int 类型和负值的整数常量表达式
(宏常量)
FOPEN_MAX
 能同时打开的文件数
(宏常量)
FILENAME_MAX
 要保有最长受支持文件名的 char 数组所需的长度
(宏常量)
BUFSIZ
 std::setbuf 所用的缓冲区大小
(宏常量)
_IOFBF_IOLBF_IONBF
 给 std::setbuf 的参数，指示全缓冲 I/O
给 std::setbuf 的参数，指示行缓冲 I/O
给 std::setbuf 的参数，指示无缓冲 I/O
(宏常量)
SEEK_SETSEEK_CURSEEK_END
 给 std::fseek 的参数，指示从文件起始寻位
给 std::fseek 的参数，指示从当前文件位置寻位
给 std::fseek 的参数，指示从文件尾寻位
(宏常量)
TMP_MAX
 std::tmpnam 所能生成的唯一文件名的最大数量
(宏常量)
L_tmpnam
 保有 std::tmpnam 结果的 char 数组所需的大小
(宏常量)

参阅


std::clearerr

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
void clearerr( std::FILE * stream );

重置给定文件流的错误标志和 EOF 指示器。

参数

stream - 要重置错误标志的文件流

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

feof | 检查文件尾 (函数)
perror | 显示对应当前错误的字符串于 stderr (函数)
ferror | 检查文件错误 (函数)


std::fclose

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int fclose( std::FILE * stream );

关闭给定的文件流。冲入任何未写入的缓冲数据到 OS 。舍弃任何未读取的缓冲数据。

无论操作是否成功，流都不再关联到文件，且由 std::setbuf 或 std::setvbuf 分配的缓冲区若存在，则亦被解除关联，并且若使用自动分配则被解分配。

若在 fclose 返回后使用 stream 的值则行为未定义。

参数

stream - 要关闭的文件流

返回值

成功时为 ​0​ ，否则为 EOF 。

示例

#include <cstdio>
#include <cstdlib>

int main()
{
    FILE* fp = std::fopen("test.txt", "r");
    if(!fp) {
        std::perror("File opening failed");
        return EXIT_FAILURE;
    }

    int c; // 注意：是 int 而非 char ，要求处理 EOF
    while ((c = std::fgetc(fp)) != EOF) { // 标准 C I/O 文件读取循环
       std::putchar(c);
    }

    if (std::ferror(fp))
        std::puts("I/O error when reading");
    else if (std::feof(fp))
        std::puts("End of file reached successfully");

    std::fclose(fp);
}

参阅

fopen | 打开文件 (函数)
freopen | 以不同名称打开既存流 (函数)
close | 冲入放置区缓冲区并关闭关联的文件 (std::basic_filebuf<CharT,Traits> 的公开成员函数)


std::feof

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int feof( std::FILE * stream );

检查是否已抵达给定文件流的结尾。

参数

stream - 要检查的文件流

返回值

若已抵达文件流尾则为非零值，否则为 ​0​ 。

注意

此函数只报告最近的 I/O 操作所报告的流状态，它不检验关联数据源。例如，若最近一次 I/O 是返回文件最后字节的 std::fgetc ，则 std::feof 返回零。下个 std::fgetc 失败并更改文件流为文件尾。只在这之后 std::feof 才返回非零。

典型用法中，输入流在任何错误时停止处理；然后用 feof 和 std::ferror 区别不同的错误条件。

示例

#include <cstdio>
#include <cstdlib>

int main()
{
    FILE* fp = std::fopen("test.txt", "r");
    if(!fp) {
        std::perror("File opening failed");
        return EXIT_FAILURE;
    }

    int c; // 注意：是 int 而非 char ，要求处理 EOF
    while ((c = std::fgetc(fp)) != EOF) { // 标准 C I/O 文件读取循环
       std::putchar(c);
    }

    if (std::ferror(fp))
        std::puts("I/O error when reading");
    else if (std::feof(fp))
        std::puts("End of file reached successfully");

    std::fclose(fp);
}

参阅

eof | 检查是否到达了文件末尾 (std::basic_ios<CharT,Traits> 的公开成员函数)
clearerr | 清除错误 (函数)
perror | 显示对应当前错误的字符串于 stderr (函数)
ferror | 检查文件错误 (函数)


std::ferror

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int ferror( std::FILE * stream );

检查给定的流的错误。

参数

stream - 要检查的文件流

返回值

若文件流已出现错误则为非零值，否则为 ​0​ 。

示例

#include <cstdio>
#include <cstdlib>
#include <clocale>
#include <cwchar>

int main(void)
{
    const char *fname = std::tmpnam(nullptr);
    std::FILE* f = std::fopen(fname, "wb");
    std::fputs("\xff\xff\n", f); // 不是合法的 UTF-8 字符序列
    std::fclose(f);

    std::setlocale(LC_ALL, "en_US.utf8");
    f = std::fopen(fname, "rb");
    std::wint_t ch;
    while ((ch=std::fgetwc(f)) != WEOF) // 试图作为 UTF-8 读取
          std::printf("%#x ", ch);

    if (std::feof(f))
        puts("EOF indicator set");
    if (std::ferror(f))
        puts("Error indicator set");
}

输出：

Error indicator set

参阅

clearerr | 清除错误 (函数)
feof | 检查文件尾 (函数)
fail | 检查是否发生了可恢复的错误 (std::basic_ios<CharT,Traits> 的公开成员函数)


std::fflush

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int fflush( std::FILE * stream );

对于输出流（和最近操作为输出的更新流），将来自 stream 缓冲区的未写入数据写入关联的输出设备。

对于输入流（和最近操作为输入的更新流），行为未定义。

若 stream 为空指针，则冲入所有打开的输出流，包含在库包内操作，或其他情况下程序不能直接访问的流。

参数

stream - 要写入的文件流

返回值

成功时返回零。否则返回 EOF 并设置文件流的错误指示器。

注意

POSIX 通过定义其在输入流上的效果扩展 fflush 的规定，只要该流表示文件或另一可寻位设备：该情况下重定位 POSIX 文件指针以匹配 C 流指针（等效地撤销任何读缓冲）并舍弃任何未从流回读的 std::ungetc 或 std::ungetwc 的效果。

参阅

fopen | 打开文件 (函数)
fclose | 关闭文件 (函数)


std::fgetc, std::getc

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int fgetc( std::FILE * stream );
int getc( std::FILE * stream );

读取来自给定输入流的下个字符。

参数

stream - 读取字符的来源

返回值

成功时为获得的字符，失败时为 EOF 。

若文件尾条件导致失败，则另外设置 stream 上的文件尾指示器（见 std::feof() ）。若某些其他错误导致失败，则设置 stream 上的错误指示器（见 std::ferror() ）。

示例

#include <cstdio>
#include <cstdlib>

int main()
{
    FILE* fp = std::fopen("test.txt", "r");
    if(!fp) {
        std::perror("File opening failed");
        return EXIT_FAILURE;
    }

    int c; // 注意：是 int 而非 char ，要求处理 EOF
    while ((c = std::fgetc(fp)) != EOF) { // 标准 C I/O 文件读取循环
       std::putchar(c);
    }

    if (std::ferror(fp))
        std::puts("I/O error when reading");
    else if (std::feof(fp))
        std::puts("End of file reached successfully");

    std::fclose(fp);
}

参阅

gets (C++11 中弃用)(C++14 中移除) | 从 stdin 读取字符串 (函数)
fputcputc | 写字符到文件流 (函数)
ungetc | 把字符放回文件流 (函数)


std::fgetpos

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int fgetpos( std::FILE * stream, std::fpos_t * pos );

获得文件流 stream 的文件位置指示器和当前分析状态（若存在），并将它们存储于 pos 所指向的对象。存储的值仅在作为 std::fsetpos 的输入的情况有意义。

参数

stream | - | 要检验的文件流
pos | - | 指向要存储文件位置指示器到的 fpos_t 对象的指针

返回值

成功时为 ​0​ ，否则非零值。失败时还设置 errno 。

示例

本节未完成
原因：暂无示例

参阅

ftell | 返回当前文件位置指示器 (函数)
fseek | 移动文件位置指示器到文件中的指定位置 (函数)
fsetpos | 移动文件位置指示器到文件中的指定位置 (函数)


std::fgets

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
char* fgets( char* str, int count, std::FILE * stream );

从给定文件流读取最多 count - 1 个字符并将它们存储于 str 所指向的字符数组。若文件尾出现或发现换行符则终止分析，后一情况下 str 将包含一个换行符。若读入字节且无错误发生，则紧随写入到 str 的最后一个字符后写入空字符。

参数

str | - | 指向 char 数组元素的指针
count | - | 要写入的最大字符数（典型地为 str 的长度）
stream | - | 读取数据来源的文件流

返回值

成功时为 str ，失败时为空指针。

若遇到文件尾条件导致了失败，则设置 stream 上的文件尾指示器（见 std::feof() ）。这仅若它导致未读取字符才是失败，该情况下返回空指针且不改变 str 所指向数组的内容（即不以空字符覆写首字节）。

若其他错误条件导致了失败，则设置 stream上的错误指示器（见 std::ferror() ）。 str 所指向的数组内容是不确定的（甚至可以不是空终止的）。

注解

POSIX 额外要求若 fgets 遇到异于文件尾条件的失败则设置 errno 。

尽管标准规范在 count<=1 的情况下不明，常见的实现

  • 若 count < 1 则不做任何事并报告错误
  • 若 count == 1 ，则
  • 某些实现不做任何事并报告错误，
  • 其他实现不读内容，存储零于 str[0] 并报告成功

示例

#include <iostream>
#include <cstdio>
#include <cstdlib>

int main()
{
    std::FILE* tmpf = std::tmpfile();
    std::fputs("Alan Turing\n", tmpf);
    std::fputs("John von Neumann\n", tmpf);
    std::fputs("Alonzo Church\n", tmpf);

    std::rewind(tmpf);
    char buf[8];
    while (std::fgets(buf, sizeof buf, tmpf) != NULL) {
        std::cout << '"' << buf << '"' << '\n';
    }
}

输出：

"Alan Tu"
"ring
"
"John vo"
"n Neuma"
"nn
"
"Alonzo "
"Church
"

参阅

scanffscanfsscanf | 从 stdin、文件流或缓冲区读取有格式输入 (函数)
gets (C++11 中弃用)(C++14 中移除) | 从 stdin 读取字符串 (函数)
fputs | 写字符串到文件流 (函数)


std::fgetwc

< cpp‎ | io‎ | c
定义于头文件 <cwchar>
wint_t fgetwc( std::FILE * stream );
wint_t getwc( std::FILE * stream );

从给定的输入流读取下个宽字符。 getwc() 可实现为宏并且可能求值 stream 多于一次。

本节未完成
原因：宏是否被禁止？

参数

stream - 读取宽字符的来源

返回值

来自流的下个宽字符，或若发生错误或抵达文件尾则为 WEOF 。若发生编码错误，则设置 errno 为 EILSEQ 。

参阅

fgetcgetc | 从文件流获取字符 (函数)
fgetws | 从文件流获取宽字符串 (函数)
fputwcputwc | 写宽字符到文件流 (函数)
ungetwc | 把宽字符放回文件流 (函数)


std::fgetws

< cpp‎ | io‎ | c
定义于头文件 <cwchar>
wchar_t* fgetws( wchar_t* str, int count, std::FILE * stream );

从给定的文件流读取至多 count - 1 个宽字符，并将它们存储于 str 。产生的宽字符串始终是空终止的。若出现文件尾条件或找到换行宽字符则停止分析，后一情况下 str 将含有该宽换行符。

参数

str | - | 要读取字符到的宽字符串
count | - | str 的长度
stream | - | 读取数据来源的文件流

返回值

成功时为 str ，错误时为空指针。

参阅

wscanffwscanfswscanf | 从 stdin、文件流或缓冲区读取有格式宽字符输入 (函数)
fgetwcgetwc | 从文件流获取宽字符 (函数)
fputws | 写宽字符串到文件流 (函数)


std::fopen

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
std::FILE * fopen( const char* filename, const char* mode );

打开 filename 所指示的文件并返回与该文件关联的流。用 mode 确定文件访问模式。

参数

filename - 要关联文件流到的文件名
mode - 确定文件访问模式的空终止字符串
文件访问模式字符串 | 含义 | 解释 | 若文件已存在的行动 | 若文件不存在的行动
"r" | 读 | 为读取打开文件 | 从起始读取 | 打开失败
"w" | 写 | 为写入创建文件 | 销毁内容 | 创建新文件
"a" | 追加 | 追加到文件 | 写入到末尾 | 创建新文件
"r+" | 扩展读 | 为读取/写入打开文件 | 从起始读取 | 错误
"w+" | 扩展写 | 为读取/写入创建文件 | 销毁内容 | 创建新文件
"a+" | 扩展追加 | 为读取/写入打开文件 | 写入到末尾 | 创建新文件
文件访问模式标志 "b" 能可选地指定，以用二进制模式打开文件。此标志在 POSIX 系统上无效果，但例如在 Windows 上，它禁用 '\n' 和 '\x1A' 的特殊处理。 在追加文件访问模式上，写入数据到文件尾，忽略文件位置指示器的当前位置。
文件访问模式标志 "x" 能可选地追加到 "w" 或 "w+" 指定符。此标志强制函数在文件存在的情况下失败，而非重写文件。(C++17)
若模式不是以上字符串之一，则行为未定义。一些实现定义额外的支持模式（例如 MSVC ）。

返回值

若成功，则返回指向控制打开的文件流的对象的指针，并清除文件尾和错误位。流为完全缓冲，除非 filename 指代交互设备。

错误时，返回空指针。 POSIX 要求此情况下设置 errno 。

注意

filename 的格式是实现定义的，且不必指代一个文件（例如它可以是控制台或另一能通过文件系统 API 访问的设备）。在支持的平台上， filename 可包含绝对或相对文件系统路径。

可移植的目录和文件命名，见 C++ 文件系统库或 boost.filesystem 。

示例

#include <cstdio>
#include <cstdlib>

int main()
{
    FILE* fp = std::fopen("test.txt", "r");
    if(!fp) {
        std::perror("File opening failed");
        return EXIT_FAILURE;
    }

    int c; // 注意：是 int 而非 char ，要求处理 EOF
    while ((c = std::fgetc(fp)) != EOF) { // 标准 C I/O 文件读取循环
       std::putchar(c);
    }

    if (std::ferror(fp))
        std::puts("I/O error when reading");
    else if (std::feof(fp))
        std::puts("End of file reached successfully");

    std::fclose(fp);
}

参阅

fclose | 关闭文件 (函数)
fflush | 将输出流与实际文件同步 (函数)
freopen | 以不同名称打开既存流 (函数)


std::fpos_t

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
typedef /* implementation-defined */ fpos_t;

std::fpos_t 是非数组完整对象类型，能用于存储（由 std::fgetpos ）及恢复（由 std::fsetpos ） C 流的位置与多字节分析状态（若存在）。

宽面向的 C 流的多字节分析状态以 std::mbstate_t 对象表示，其值由 std::fgetpos 作为 std::fpos_t 对象的值的一部分存储。

参阅

fgetpos | 获取文件位置指示器 (函数)
fsetpos | 移动文件位置指示器到文件中的指定位置 (函数)
mbstate_t | 迭代多字节字符串所需的转换状态信息 (类)
fpos | 表示流或文件中的绝对位置 (类模板)


std::printf, std::fprintf, std::sprintf, std::snprintf

< cpp‎ | io‎ | c
定义于头文件 <cstdio> |  |
int printf( const char* format, ... ); | (1) |
int fprintf( std::FILE * stream, const char* format, ... ); | (2) |
int sprintf( char* buffer, const char* format, ... ); | (3) |
int snprintf( char* buffer, std::size_t buf_size, const char* format, ... ); | (4) | (C++11 起)

从给定位置加载数据，转换为字符串等价版本，并将结果写入各种池。

1) 写结果到 stdout 。
2) 写结果到文件流 stream 。
3) 写结果到字符串 buffer 。
4) 写结果到字符串 buffer 。至多写 buf_size - 1 个字符。产生的字符串会以空字符终止，除非 buf_size 为零。若 buf_size 为零，则不写入任何内容，且 buffer 可以是空指针，然而依旧计算返回值（会写入的字符数，不包含空终止符）并返回。

若调用 sprintf 或 snprintf 导致在重叠的对象间发生复制，则行为未定义。（例如 sprintf(buf, "%s text", buf); ）

参数

stream - 要写入的输出文件流
buffer - 指向要写入的字符串的指针
buf_size - 写入至多 buf_size - 1 个字符，再加上空终止符
format - 指向指定如何转译数据的空终止多字节字符串的指针。

格式字符串由普通多字节字符（除了 % ）和转换指定构成，前者被复制到输出流而无更改。每个转换指定拥有下列格式：

  • 引入的 % 字符
  • (可选)一或多个修改转换行为的标签：
  • - ：转换结果在域内左校正（默认为右校正）
  • + ：有符号转换的符号始终前置于转换结果（默认结果前置负号仅当它为负）
  • 空格：若有符号转换的结果不以符号开始，或为空，则前置空格于结果。若存在 + 标签则忽略空格。
  • # ：进行替用形式的转换。准确的效果见下表，其他情况下行为未定义。
  • 0 ：对于整数和浮点数转换，使用前导零代替空格字符填充域。对于整数，若显式指定精度，则忽略此标签。对于其他转换，使用此标签导致未定义行为。若存在 - 标签则忽略 0 。
  • (可选)指定最小域宽的整数值或 * 。若有要求，则结果会以空格字符（默认情况）填充，在右校正时于左，左校正时于右。使用 * 的情况下，以一个额外的 int 类型参数指定宽度。若参数值为负数，则它导致指定 - 标签和正域宽。（注意：这是最小宽度：决不被截断值）。
  • (可选)后随整数或 * 或两者皆无的 . 指示转换的精度。在使用 * 的情况下，精度由额外的 int 类型参数指定。若此参数的值为负数，则它被忽略。若既不使用数字亦不使用 * ，则精度采用零。精度的准确效果见下表。
  • (可选)指定参数大小的长度修饰符
  • 转换格式指定符

下列格式指定符可用：

转换
指定符 		解释 参数类型
长度修饰符 hh

(C++11)

 h （无） l ll

(C++11)

 j

(C++11)

 z

(C++11)

 t

(C++11)

 L
% 写字面的 % 。完整转换指定必须是 %% 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
写单个字符。

参数首先被转换成 unsigned char 。 若使用 l 修饰符，则参数首先被转换成字符串，如同通过以 wchar_t[2] 参数使用 %ls 。

 N/A N/A
int
wint_t
 N/A N/A N/A N/A N/A
s
写字符串

参数必须是指向字符数组首元素的指针 精度指定写入最大的字符数。若未指定精度，则写每个字节直到而不含首个空终止符。 若使用 l 指定符，则参数必须是指向 wchar_t 数组首元素的指针，数组会被转换成 char 数组，如同通过以零初始化转换状态调用 wcrtomb 。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
d
i
转换有符号整数为十进制表示 [-]dddd 。

精度指定出现的最小数位数。默认精度是 1 。
若被转换的值和精度都是 ​0​ ，则转换结果无字符。
signed char
short
int
long
long long
intmax_t
有符号 size_t
ptrdiff_t
 N/A
o
转换无符号整数为八进制表示 oooo 。

精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中精度按需增加，以写入一个前导零。 在此情况下若被转换值和精度都是 ​0​ ，则写入单个 ​0​ 。
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
uintmax_t
size_t
ptrdiff_t 的无符号版本
 N/A
x
X
转换无符号整数为十六进制表示 hhhh 。

x 转换使用字母 abcdef 。
X 转换使用 ABCDEF 。
精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中若被转换值为非零则结果有 0x 或 0X 前缀。

 N/A
u
转换无符号整数为十进制表示 dddd 。

精度指定出现的最小数位数。 默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。

 N/A
f
F
转换浮点数为 [-]ddd.ddd 样式的十进制记法。

精度指定小数点字符后出现的准确数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A
double
double (C++11)
 N/A N/A N/A N/A
long double
e
E
转换浮点数为十进制指数记法。

e 转换样式使用 [-]d.ddd e±dd 。
E 转换样式使用 [-]d.ddd E±dd 。
指数至少含二个数位，仅当所需时使用更多数位。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
a
A

(C++11)
转换浮点数为十六进制记法。

a 转换样式使用 [-]0x h.hhh p±d 。
A 转换样式使用 [-]0X h.hhh P±d 。
若参数是正规化的浮点值，则首个十六进制数位非 0 。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度足以准确表示该值。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
g
G
转换浮点数为十进制小数或十进制指数记法，依赖于值和精度。

g 转换样式将进行带样式 e 或 f 的转换。
G 转换样式将进行带样式 E 或 F 的转换。
令 P 等于精度，若它非零，若精度未指定则为 6 ，若精度为 ​0​ 则等于 1 。然后，若带样式 E 的转换会有指数 X ，则：

  • 若 P > X ≥ −4 ，则转换带 f 或 F 风格，及精度 P − 1 − X 。
  • 否则，转换带 e 或 E 风格，及精度 P − 1 。

除非要求替用表示，否则末尾零会被移除，且若不留下小数部分则小数点亦被移除。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
n
返回对函数的此调用迄今为止写入的字符数。

结果被写入到参数所指向的值。 该指定不可含有任何标签、域宽或精度。
signed char*
short*
int*
long*
long long*
intmax_t*
有符号 size_t*
ptrdiff_t*
 N/A
p 写定义指针的实现定义字符序列。 N/A N/A void* N/A N/A N/A N/A N/A N/A

浮点转换函数转换无穷大到 inf 或 infinity 。使用哪个是实现定义的。

非数转换成 nan 或 nan(char_sequence) 。使用哪个是实现定义的。

转换 F 、 E 、 G 、 A 替代上面输出 INF 、 INFINITY 、 NAN。

尽管 %c 期待 int 参数，传递 char 是安全的，因为在调用变参数函数时发生整数提升。

定宽整数类型（ int8_t 等）的正确转换指定定义于头文件 <cinttypes> （尽管 PRIdMAX 、 PRIuMAX 等就是 %jd 、 %ju 等的别名）。

内存写入转换指定符 %n 是安全漏洞的常见目标，这里格式字符串依赖用户输入，而有边界检查的 printf_s 系列函数不支持此转换指定符。

在每个转换指定符的行动后有一个序列点；这允许于同一变量多次存入 %n 的结果，并在同一此调用中打印出先前以 %n 存储的值。

若转换指定非法，则行为未定义。
... - 指定要打印数据的参数。若任何参数类型不是对应转换指定符所期望者，或若参数数量少于 format 所要求这，则行为未定义。若参数数量多于 format 所要求者，则求值后忽略额外参数

返回值

1-2) 若成功则为写入的字符数，若发生错误则为负值。
3) 若成功则为写入的字符数（不包含空终止字符），若发生错误则为负值。
4) 若成功则为会写入充分大缓冲区的字符数（不包含空终止字符），若发生错误则为负值。从而，当且仅当返回值非负且小于 buf_size 才完全写入（空终止）。

注意

POSIX 规定在错误时设置 errno 。它亦指定额外的转换指定，最值得注意的是对参数重排序的支持（紧随 % 后的 n$ 指示第 n 个参数）。

以零 buf_size 和对于 buffer 的空指针调用 std::snprintf 适用于确定容纳输出的所需缓冲区大小：

const char *fmt = "sqrt(2) = %f";
int sz = std::snprintf(nullptr, 0, fmt, std::sqrt(2));
std::vector<char> buf(sz + 1); // 注意为空终止符 +1
std::snprintf(&buf[0], buf.size(), fmt, std::sqrt(2));

示例

#include <cstdio>
#include <limits>
#include <cstdint>
#include <cinttypes>

int main()
{
    std::printf("Strings:\n");

    const char* s = "Hello";
    std::printf("\t[%10s]\n\t[%-10s]\n\t[%*s]\n\t[%-10.*s]\n\t[%-*.*s]\n",
        s, s, 10, s, 4, s, 10, 4, s);

    std::printf("Characters:\t%c %%\n", 65);

    std::printf("Integers\n");
    std::printf("Decimal:\t%i %d %.6i %i %.0i %+i %u\n", 1, 2, 3, 0, 0, 4, -1);
    std::printf("Hexadecimal:\t%x %x %X %#x\n", 5, 10, 10, 6);
    std::printf("Octal:\t%o %#o %#o\n", 10, 10, 4);

    std::printf("Floating point\n");
    std::printf("Rounding:\t%f %.0f %.32f\n", 1.5, 1.5, 1.5);
    std::printf("Padding:\t%05.2f %.2f %5.2f\n", 1.5, 1.5, 1.5);
    std::printf("Scientific:\t%E %e\n", 1.5, 1.5);
    std::printf("Hexadecimal:\t%a %A\n", 1.5, 1.5);
    std::printf("Special values:\t0/0=%g 1/0=%g\n", 0.0/0.0, 1.0/0.0);

    std::printf("Variable width control:\n");
    std::printf("right-justified variable width: '%*c'\n", 5, 'x');
    int r = std::printf("left-justified variable width : '%*c'\n", -5, 'x');
    std::printf("(the last printf printed %d characters)\n", r);

    // 定宽类型
    std::uint32_t val = std::numeric_limits<std::uint32_t>::max();
    std::printf("Largest 32-bit value is %" PRIu32 " or %#" PRIx32 "\n", val, val);
}

输出：

Strings:
        [     Hello]
        [Hello     ]
        [     Hello]
        [Hell      ]
        [Hell      ]
Characters:     A %
Integers
Decimal:        1 2 000003 0  +4 4294967295
Hexadecimal:    5 a A 0x6
Octal:  12 012 04
Floating point
Rounding:       1.500000 2 1.30000000000000004440892098500626
Padding:        01.50 1.50  1.50
Scientific:     1.500000E+00 1.500000e+00
Hexadecimal:    0x1.8p+0 0X1.8P+0
Special values: 0/0=nan 1/0=inf
Variable width control:
right-justified variable width: '    x'
left-justified variable width : 'x    '
(the last printf printed 40 characters)
Largest 32-bit value is 4294967295 or 0xffffffff

参阅

wprintffwprintfswprintf | 打印有格式宽字符输出到 stdout、文件流或缓冲区 (函数)
vprintfvfprintfvsprintfvsnprintf (C++11) | 使用可变实参列表 打印有格式输出到 stdout、文件流或缓冲区 (函数)
fputs | 写字符串到文件流 (函数)
scanffscanfsscanf | 从 stdin、文件流或缓冲区读取有格式输入 (函数)
to_chars (C++17) | 转换整数或浮点值到字符序列 (函数)


std::fputc, std::putc

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int fputc( int ch, std::FILE * stream );
int putc( int ch, std::FILE * stream );

写入字符 ch 到给定输出流 stream 。

在内部，在写入前将字符转换为 unsigned char 。

C 中， putc() 可以实现为宏，而这在 C++ 中被禁止。从而调用 std::fputc() 和 std::putc() 始终拥有相同效果。

参数

ch | - | 要写入的字符
stream | - | 输出流

返回值

成功时，返回被写入字符。

失败时，返回 EOF 并设置 stream 上的错误指示器（见 std::ferror() ）。

示例

#include <cstdio>

int main()
{
    for (char c = 'a'; c != 'z'; c++)
        std::putc(c, stdout);
    std::putc('\n', stdout);

    // putchar 的返回值不等于参数
    int r = 0x1070;
    std::printf("\n0x%x\n", r);
    r = std::putchar(r);
    std::printf("\n0x%x\n", r);
}

输出：

abcdefghijklmnopqrstuvwxy
0x1070
p
0x70

参阅

putchar
 写字符到 stdout
(函数)


std::fputs

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int fputs( const char* str, std::FILE * stream );

写入来自空终止字符串 str 的每个字符到 stream ，如同通过重复执行 std::fputc 。

不写入来自 str 的终止空字符。

参数

str | - | 要写入的空终止字符串
stream | - | 输出流

返回值

成功时，返回非负值。

失败时，返回 EOF 并设置 stream 上的错误指示器（见 std::ferror ）。

注意

相关函数 std::puts 后附新换行符到输出，而 std::fputs 写入不修改的字符串。

不同的实现返回不同的非负数：一些返回最后写入的字符，一些返回写入的字符数（或若字符串长于 INT_MAX 则为该值），一些简单地非负常量，例如零。

示例

#include <cstdio>

int main(void)
{
    int rc = std::fputs("Hello World", stdout);

    if (rc == EOF)
       std::perror("fputs()"); // POSIX 要求设置 errno
}

输出：

Hello World

参阅

printffprintfsprintfsnprintf (C++11) | 打印有格式输出到 stdout、文件流或缓冲区 (函数)
puts | 写字符串到 stdout (函数)
fputws | 写宽字符串到文件流 (函数)
fgets | 从文件流获取字符串 (函数)


std::fputwc

< cpp‎ | io‎ | c
定义于头文件 <cwchar>
wint_t fputwc( wchar_t ch, std::FILE * stream );
wint_t putwc( wchar_t ch, std::FILE * stream );

写入宽字符 ch 到给定的输出流 stream 。 putwc() 可实现为宏并可能求值 stream 多于一次。

本节未完成
原因：是否允许实现为宏？

参数

ch | - | 要写入的宽字符
stream | - | 输出流

返回值

成功时为 ch ，失败时为 WEOF 。若出现编码错误，则设置 errno 为 EILSEQ 。

参阅

fputcputc | 写字符到文件流 (函数)
fputws | 写宽字符串到文件流 (函数)
fgetwcgetwc | 从文件流获取宽字符 (函数)


std::fputws

< cpp‎ | io‎ | c
定义于头文件 <cwchar>
int fputws( const wchar_t* str, std::FILE * stream );

写入来自空终止宽字符串 str 的每个宽字符到输出流 stream ，如同通过重复执行 std::fputwc 。

不写入来自 str 的终止宽字符。

参数

str | - | 要写入的空终止宽字符串
stream | - | 输出流

返回值

成功时返回非负值。

失败时，返回 EOF 并设置 stream 上的错误指示器（见 std::ferror ）。

示例

#include <clocale>
#include <cstdio>
#include <cwchar>

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    int rc = std::fputws(L"御休みなさい", stdout);

    if (rc == EOF)
       std::perror("fputws()"); // POSIX 要求设置 errno
}

输出：

御休みなさい

参阅

fputs | 写字符串到文件流 (函数)
wprintffwprintfswprintf | 打印有格式宽字符输出到 stdout、文件流或缓冲区 (函数)
fputws | 写宽字符串到文件流 (函数)
fgetws | 从文件流获取宽字符串 (函数)


std::fread

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
std::size_t fread( void* buffer, std::size_t size, std::size_t count, std::FILE * stream );

从给定输入流 stream 读取至多 count 个对象到数组 buffer 中，如同以对每个对象调用 size 次 std::fgetc ，并按顺序存储结果到转译为 unsigned char 数组的 buffer 中的相继位置。流的文件位置指示器前进读取的字符数。

若对象不可平凡复制 (TriviallyCopyable) ，则行为未定义。

若出现错误，则流的文件位置指示器的结果值不确定。若读入部分的元素，则元素值不确定。

参数

buffer | - | 指向要读取的数组中首个对象的指针
size | - | 每个对象的字节大小
count | - | 要读取的对象数
stream | - | 读取来源的输入文件流

返回值

成功读取的对象数，若出现错误或文件尾条件，则可能小于 count 。

若 size 或 count 为零，则 fread 返回零且不进行其他动作。

示例

#include <iostream>
#include <cstdio>
#include <fstream>
#include <vector>
int main()
{
    // 准备文件
    std::ofstream("test.txt") << 1 << ' ' << 2 << '\n';
    std::FILE* f = std::fopen("test.txt", "r");

    std::vector<char> buf(4); // char 可平凡复制
    std::fread(&buf[0], sizeof buf[0], buf.size(), f);

    for(char n : buf)
        std::cout << n;

    std::vector<std::string> buf2; // string 不可平凡复制
// 这会导致未定义行为
//    std::fread(&buf2[0], sizeof buf2[0], buf2.size(), f);
}

输出：

1 2

参阅

scanffscanfsscanf | 从 stdin、文件流或缓冲区读取有格式输入 (函数)
fgets | 从文件流获取字符串 (函数)
fwrite | 写入文件 (函数)


std::freopen

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
std::FILE * freopen( const char* filename, const char* mode, std::FILE * stream );

首先，试图关闭与 stream 关联的文件，忽略任何错误。然后，若 filename 非空，则试图用 mode 打开 filename 所指定的文件，如同用 fopen ，然后将该文件与 stream 所指向的文件流关联。若 filename 为空指针，则函数试图重打开已与 stream 关联的文件（此情况下是否允许模式改变是实现定义的）。

参数

filename - 要关联文件流到的文件
mode - 确定新文件打开模式的空终止字符串
文件访问模式字符串 | 含义 | 解释 | 若文件已存在的行动 | 若文件不存在的行动
"r" | 读 | 为读取打开文件 | 从起始读取 | 打开失败
"w" | 写 | 为写入创建文件 | 销毁内容 | 创建新文件
"a" | 追加 | 追加到文件 | 写入到末尾 | 创建新文件
"r+" | 扩展读 | 为读取/写入打开文件 | 从起始读取 | 错误
"w+" | 扩展写 | 为读取/写入创建文件 | 销毁内容 | 创建新文件
"a+" | 扩展追加 | 为读取/写入打开文件 | 写入到末尾 | 创建新文件
文件访问模式标志 "b" 能可选地指定，以用二进制模式打开文件。此标志在 POSIX 系统上无效果，但例如在 Windows 上，它禁用 '\n' 和 '\x1A' 的特殊处理。 在追加文件访问模式上，写入数据到文件尾，忽略文件位置指示器的当前位置。
文件访问模式标志 "x" 能可选地追加到 "w" 或 "w+" 指定符。此标志强制函数在文件存在的情况下失败，而非重写文件。(C++17)
若模式不是以上字符串之一，则行为未定义。一些实现定义额外的支持模式（例如 MSVC ）。
stream - 要修改的文件流

返回值

成功时为 stream ，失败时为空指针。

注解

freopen 是一旦由 I/O 操作或 std::fwide 建立面向后，改变流窄/宽面向的唯一方式。

freopen 的 Microsoft CRT 版本在 filename 为空指针时不支持任何模式更改并将它当作错误（见文档）。可行的替代方案是非标准函数 _setmode() 。

示例

下列代码重定向 stdout 到文件

#include <cstdio>

int main()
{
    std::printf("stdout is printed to console\n");
    if(std::freopen("redir.txt", "w", stdout)) {
        std::printf("stdout is redirected to a file\n"); // 这被写入 redir.txt
        std::fclose(stdout);
    }
}

输出：

stdout is printed to console

参阅

fopen | 打开文件 (函数)
fclose | 关闭文件 (函数)


std::scanf, std::fscanf, std::sscanf

< cpp‎ | io‎ | c
定义于头文件 <cstdio> |
int scanf( const char* format, ... ); | (1)
int fscanf( std::FILE * stream, const char* format, ... ); | (2)
int sscanf( const char* buffer, const char* format, ... ); | (3)

从各种源读取数据，按照 format 转译并存储结果于给定位置。

1) 从 stdin 读数据
2) 从文件流 stream 读数据
3) 从空终止字符串 buffer 读数据

参数

stream - 读取来源的文件流
buffer - 指向读取数据来源的空终止字符串
format - 指向指定如何读取输入的空终止字符串的指针。

格式字符串由下列内容组成

  • 非空白多字节字符，除了 % ：每个格式字符串中的这种字符处理来自输入流的准确同一字符，或若它与流的下个字符比较不相等则导致函数失败。
  • 空白符：任何格式字符串中的单个空白符处理所有来自输入的可用连续空白符（如同通过于循环中调用 isspace 确定）。注意格式字符串中 "\n" 、 " " 、 "\t\t" 或其他空白无区别。
  • 转换说明：每个转换说明拥有下列格式：
  • 引入用 % 字符
  • (可选)赋值抑制字符 * 。若存在此选项，则此函数不将结果赋值给任何接收用参数。
  • (可选)指定最大域宽的整数数字（大于零），即函数进行在当前转换说明所指定的转换时，允许处理的最大字符数。注意若不提供宽度，则 %s 和 %[ 可能导致缓冲区溢出。
  • (可选)指定接收参数大小的长度修饰符，即实际目标类型。这影响转换准确性和溢出规则。默认目标类型对每个转换类型不同（见下表）。
  • 转换格式说明符

下列格式说明符可用：

转换
说明符 		解释 参数类型
长度修饰符 →
 hh

(C++11)

 h （无） l ll

(C++11)

 j

(C++11)

 z

(C++11)

 t

(C++11)

 L
% 匹配字面 % 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
匹配一个字符或字符的序列

若使用了宽度说明符，则匹配准确的宽度个字符（该参数必须是指向有充足空间的数组的指针）。不同于 %s 和 %[ ，它不会在数组后附加空字符。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
s
匹配非空白字符的序列（一个字符串）

若使用宽度说明符，则至多匹配宽度个字符，或匹配到首个提前出现的空白符前。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
[集合]
匹配一个来自 集合 的字符的非空字符序列。

若集合的首字符是 ^ ，则匹配所有不在集合中的字符。若集合以 ] 或 ^] 开始，则 ] 字符亦被包含入集合。在扫描集合的非最初位置的字符 - 是否可以指示范围，如 [0-9] ，是实现定义的。若使用宽度说明符，则最多匹配到宽度。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
d
匹配一个十进制整数。

该数的格式同 strtol() 以值 10 为 base 时所期望者
signed char* 或 unsigned char*
signed short* 或 unsigned short*
signed int* 或 unsigned int*
signed long* 或 unsigned long*
signed long long* 或 unsigned long long*
intmax_t* 或 uintmax_t*
size_t*
ptrdiff_t*
 N/A
i
匹配一个整数。

该数的格式同 strtol() 以值 ​0​ 为 base 时所期望者（基底以首个分析的字符确定）
u
匹配一个无符号十进制整数。

该数的格式同 strtoul() 以值 10 为 base 参数时所期望者。
o
匹配一个无符号八进制数。

该数的格式同 strtoul() 以值 8 为 base 参数时所期望者。
x, X
匹配一个无符号十六进制整数。

该数的格式同 strtoul() 以值 16 为 base 参数时所期望者。
n
返回迄今读取的字符数。

不消耗输出。不增加赋值计数。若此说明符拥有赋值抑制运算符，则行为未定义。
a, A(C++11)
e, E
f, F
g, G
匹配一个浮点数。

该数的格式同 strtof() 所期望者。

 N/A N/A
float*
double*
 N/A N/A N/A N/A
long double*
p
匹配定义一个指针的实现定义的字符序列。

printf 系列函数应该用 %p 格式说明符产生同样的序列。

 N/A N/A
void**
 N/A N/A N/A N/A N/A N/A

对于每个异于 n 的转换说明符，不超过任何指定域宽，且要么是转换说明符所准确期待，要么是其所期待的前缀的最长输入字符序列，即是从流中消耗的内容。此消耗序列后的首个字符若存在，则保持未读取。若被消耗序列长度为零，或被消耗序列不能转换成上面所指定的项目，则发生匹配失败，除非遇到文件尾、编码错误，或阻止从流输入的读取错误，此情况下此为输入失败。

所有异于 [ 、 c 和 n 的转换说明符，在尝试分析输入前消耗并舍弃所有前导空白字符（如同以调用 isspace 来确定）。这些被消耗的字符不计入指定的最大域宽。

转换说明符 lc 、 ls 和 l[ 进行多字节到宽字符转换，如同如同在转换首字符前，通过用初始化到零的 mbstate_t 对象调用 mbrtowc() 。

转换说明符 s 与 [ 始终在匹配字符之后存储一个空字符。目标数组的大小必须至少比指定域宽大一。

定宽整数类型（ int8_t 等）的正确的转换说明定义于头文件 <cinttypes> （虽然 SCNdMAX 、 SCNuMAX 等就是 %jd 、 %ju 等的别名）。

在每个转换说明符后有一个序列点；这允许存储多个域到同一“池”变量中。

在分析以无数字指数为结尾的不完整浮点值，如以转换说明符 %f 分析 "100er" 时，消耗序列 "100e" （可能为合法浮点数的最长前缀），并导致匹配错误（被消耗序列不能转换成浮点数），而留下 "r" 。某些既存实现不遵守此规则并回滚，通过消耗 "100" 而留下 "er" ，例如 glibc 漏洞 1765 。
... - 接收的参数

返回值

成功赋值的参数数（在首个参数赋值前发生匹配失败的情况下可为零），或若在赋值首个接收的参数前输入失败则为 EOF 。

注解

因为大多数转换指定符首先消耗所有连续空白符，如下代码

std::scanf("%d", &a);
std::scanf("%d", &b);

会读取输入于不同行（第二个 %d 会消耗第一个剩下的换行符）或同一行中为空格或制表符所分隔的（第二个 %d 会消耗空格或制表符）二个整数。

不消耗前导空白符的转换指定符，如 %c ，可通过在格式化字符串中用空白符使得它这么做：
std::scanf("%d", &a);
std::scanf(" %c", &c); // 忽略 %d 后的换行符，然后读一个 char

示例

#include <iostream>
#include <clocale>
#include <cstdio>

int main()
{
    int i, j;
    float x, y;
    char str1[10], str2[4];
    wchar_t warr[2];
    std::setlocale(LC_ALL, "en_US.utf8");

    char input[] = u8"25 54.32E-1 Thompson 56789 0123 56ß水";
    // 按如下分析：
    // %d ：整数
    // %f ：浮点值
    // %9s ：至多 9 个非空白字符的字符串
    // %2d ：二位整数（数字 5 与 6 ）
    // %f ：浮点值（数字 7 、 8 、 9 ）
    // %*d 不存储于任何位置的整数
    // ' ' ：所有连续空白符
    // %3[0-9] ：至多 3 位数字的字符串（数字 5 与 6 ）
    // %2lc ：二个宽字符，用多字节到宽转换
    int ret = std::sscanf(input, "%d%f%9s%2d%f%*d %3[0-9]%2lc",
                     &i, &x, str1, &j, &y, str2, warr);

    std::cout << "Converted " << ret << " fields:\n"
              << "i = " << i << "\nx = " << x << '\n'
              << "str1 = " << str1 << "\nj = " << j << '\n'
              << "y = " << y << "\nstr2 = " << str2 << '\n'
              << std::hex << "warr[0] = U+" << warr[0]
              << " warr[1] = U+" << warr[1] << '\n';
}

输出：

Converted 7 fields:
i = 25
x = 5.432
str1 = Thompson
j = 56
y = 789
str2 = 56
warr[0] = U+df warr[1] = U+6c34

参阅

vscanfvfscanfvsscanf (C++11)(C++11)(C++11) | 使用可变实参列表 从 stdin、文件流或缓冲区读取有格式输入 (函数)
fgets | 从文件流获取字符串 (函数)
printffprintfsprintfsnprintf (C++11) | 打印有格式输出到 stdout、文件流或缓冲区 (函数)
from_chars (C++17) | 转换字符序列到整数或浮点值 (函数)


std::fseek

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int fseek( std::FILE * stream, long offset, int origin );

设置文件流 stream 的文件位置指示器为 offset 所指向的值。

若 stream 以二进制模式打开，则新位置准确地是文件起始后（若 origin 为 SEEK_SET ）或当前文件位置后（若 origin 为 SEEK_CUR ），或文件结尾后（若 origin 为 SEEK_END ）的 offset 字节。不要求二进制流支持 SEEK_END ，尤其是是否输出附加的空字节。

若 stream 以文本模式打开，则仅有的受支持 offset 值为零（可用于任何 origin ）和先前在关联到同一个文件的流上对 std::ftell 的调用的返回值（仅可用于 SEEK_SET 的 origin ）。

若 stream 为宽面向，则一同应用对文本和二进制流的限制（允许 std::ftell 的结果与 SEEK_SET 一同使用，并允许零 offset 以 SEEK_SET 和 SEEK_CUR 但非 SEEK_END 为基准）。

除了更改文件位置指示器， fseek 还撤销 std::ungetc 的效果并清除文件尾状态，若可应用。

若发生读或写错误，则设置流的错误指示器（ std::ferror ）而不影响文件位置。

参数

stream | - | 要修改的文件流
offset | - | 相对 origin 迁移的字符数
origin | - | offset 所加上的位置。它能拥有下列值之一： SEEK_SET 、 SEEK_CUR 、 SEEK_END

返回值

成功时为 ​0​ ，否则为非零。

注意

在巡位到宽流的非结尾位置后，下个对任意输出函数的调用可能令剩下的文件内容未定义，例如通过输出一个长度不同的多字节序列。

对于文本流， offset 仅有的合法值是 ​0​ （可应用于任意 origin ）和先前 ftell 调用的返回值（仅可应用于 SEEK_SET ）。

POSIX 允许在文件尾之后巡位。若在此巡位后进行输出，则任何间隙中的读取将返回零字节。在文件系统支持的场合，这会创建一个稀疏文件。

POSIX 亦要求 fseek 先进行 fflush ，若有任何未写入数据（但是否恢复迁移状态是实现定义的）。标准 C++ 文件流保证冲入并反迁移： std::basic_filebuf::seekoff 。

示例

#include <cstdio>
#include <cstdint>
#include <vector>
#include <fstream>
#include <cassert>

int main()
{
    std::ofstream("dummy.nfo") << "sample data\n";

    std::FILE* fp = std::fopen("dummy.nfo", "rb");
    assert(fp);

    std::fseek(fp, 0, SEEK_END); // 寻位到结尾
    std::size_t filesize = std::ftell(fp);

    std::fseek(fp, 0, SEEK_SET); // 寻位到起始
    std::vector<uint8_t> buffer(filesize);
    std::fread(buffer.data(), sizeof(uint8_t), buffer.size(), fp);

    std::fclose(fp);
    std::printf("i've read %zi bytes\n", filesize);
}

输出：

i've read 12 bytes

参阅

fsetpos | 移动文件位置指示器到文件中的指定位置 (函数)
fgetpos | 获取文件位置指示器 (函数)
ftell | 返回当前文件位置指示器 (函数)
rewind | 移动文件位置指示器到文件起始 (函数)


std::fsetpos

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int fsetpos( std::FILE * stream, const std::fpos_t * pos );

按照 pos 所指向的值，设置 C 文件流 stream 的文件位置指示器和多字节分析状态（若存在）。

除了建立新的分析状态和位置，调用此函数还会撤销 std::ungetc 的效果，并若设置了文件尾状态则清除之。

若读或写失败，则设置流的错误指示器（ std::ferror ）。

参数

stream | - | 要修改的文件流
pos | - | 指向 fpos_t 对象的指针，该对象获得自对与同一文件关联的流上的 std::fgetpos 调用

返回值

成功时为 ​0​ ，否则为非零值。失败时还设置 errno 。

注意

在寻位到宽流的非结尾位置后，下个对任何输出函数的调用可能使剩下的文件内容未定义，例如通过输出不同长度的多字节序列。

参阅

fgetpos | 获取文件位置指示器 (函数)
ftell | 返回当前文件位置指示器 (函数)
fseek | 移动文件位置指示器到文件中的指定位置 (函数)


std::ftell

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
long ftell( std::FILE * stream );

返回文件流 stream 的文件位置指示器的当前值。

若流以二进制模式打开，则此函数获得的值是距文件起始的字节数。

若流以文本模式打开，则此函数的返回值是未指定的，而且仅若作为 std::fseek 的输入才有意义。

参数

stream - 要检验的文件流

返回值

成功时为文件位置指示器，若失败出现则为 -1L 。失败时亦设置 errno 。

参数

本节未完成
原因：暂无示例

参阅

fgetpos | 获取文件位置指示器 (函数)
fseek | 移动文件位置指示器到文件中的指定位置 (函数)
fsetpos | 移动文件位置指示器到文件中的指定位置 (函数)
tellg | 返回输入位置指示器 (std::basic_istream<CharT,Traits> 的公开成员函数)
tellp | 返回输出位置指示器 (std::basic_ostream<CharT,Traits> 的公开成员函数)


std::fwide

< cpp‎ | io‎ | c
定义于头文件 <cwchar>
int fwide( std::FILE * stream, int mode );

若 mode > 0 ，则试图令 stream 为宽面向。若 mode < 0 ，则试图令 stream 为字节面向。若 mode==0 ，则只查询流的当前面向。

若流的当前面向已决定（通过执行输出或通过之前调用 fwide ），则此函数不做任何事。

参数

stream | - | 指向要修改或查询的 C I/O 流的指针
mode | - | 大于零的整数值设置流为宽，小于零者设置流为窄，零值仅查询

返回值

若此调用后流为宽面向则为大于零的整数，若此调用后流为字节面向则为小于零的整数，若流无面向则为零。

参阅

fopen
 打开文件
(函数)


std::wprintf, std::fwprintf, std::swprintf

< cpp‎ | io‎ | c
定义于头文件 <cwchar> |
int wprintf( const wchar_t* format, ... ); | (1)
int fwprintf( std::FILE * stream, const wchar_t* format, ... ); | (2)
int swprintf( wchar_t* buffer, std::size_t size, const wchar_t* format, ... ); | (3)

从给定位置加载数据，转换它们到宽字符串等价版本，并写入结果到各种池。

1) 写结果到 stdout 。
2) 写结果到文件流 stream 。
3) 写结果到宽字符串 buffer 。至多写入 size-1 个宽字符，后随空宽字符。

参数

stream - 要写入的输出文件流
buffer - 指向要写入的宽字符串的指针
size - 至多可写入 size - 1 个字符，再加上空终止符
format - 指向指定转译方式的空终止宽字符串的指针。

格式字符串由普通宽字符（除了 % ）和转换指定构成，前者被复制到输出流而无更改。每个转换指定拥有下列格式：

  • 引入的 % 字符
  • (可选)一或多个修改转换行为的标签：
  • - ：转换结果在域内左校正（默认为右校正）
  • + ：有符号转换的符号始终前置于转换结果（默认结果前置负号仅当它为负）
  • 空格：若有符号转换的结果不以符号开始，或为空，则前置空格于结果。若存在 + 标签则忽略空格。
  • # ：进行替用形式的转换。准确的效果见下表，其他情况下行为未定义。
  • 0 ：对于整数和浮点数转换，使用前导零代替空格字符填充域。对于整数，若显式指定精度，则忽略此标签。对于其他转换，使用此标签导致未定义行为。若存在 - 标签则忽略 0 。
  • (可选)指定最小域宽的整数值或 * 。若有要求，则结果会以空格字符（默认情况）填充，在右校正时于左，左校正时于右。使用 * 的情况下，以一个额外的 int 类型参数指定宽度。若参数值为负数，则它导致指定 - 标签和正域宽。（注意：这是最小宽度：决不被截断值）。
  • (可选)后随整数或 * 或两者皆无的 . 指示转换的精度。在使用 * 的情况下，精度由额外的 int 类型参数指定。若此参数的值为负数，则它被忽略。若既不使用数字亦不使用 * ，则精度采用零。精度的准确效果见下表。
  • (可选)指定参数大小的长度修饰符
  • 转换格式指定符

下列格式指定符可用：

转换
指定符 		解释 参数类型
长度修饰符 hh

(C++11)

 h （无） l ll

(C++11)

 j

(C++11)

 z

(C++11)

 t

(C++11)

 L
% 写字面的 % 。完整转换指定必须是 %% 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
写单个字符。

参数首先被转换成 wchar_t ，如同通过调用 btowc 。 若使用 l 修饰符，则 wint_t 参数首先被转换成 wchar_t 。

 N/A N/A
int
wint_t
 N/A N/A N/A N/A N/A
s
写字符串

参数必须为一个指针，指向包含以初始迁移状态开始的，多字节字符序列的字符数组首元素，数组会被转换成宽字符数组，如同通过以零初始化转换状态调用 mbrtowc 。 精度指定写入的最大宽字符数。若未指定精度，则写每个宽字符直到而不含首个空终止符。 若使用 l 指定符，则参数必须是指向 wchar_t 数组首元素的指针。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
d
i
转换有符号整数为十进制表示 [-]dddd 。

精度指定出现的最小数位数。默认精度是 1 。
若被转换的值和精度都是 ​0​ ，则转换结果无字符。
signed char
short
int
long
long long
intmax_t
有符号 size_t
ptrdiff_t
 N/A
o
转换无符号整数为八进制表示 oooo 。

精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中精度按需增加，以写入一个前导零。 在此情况下若被转换值和精度都是 ​0​ ，则写入单个 ​0​ 。
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
uintmax_t
size_t
ptrdiff_t 的无符号版本
 N/A
x
X
转换无符号整数为十六进制表示 hhhh 。

x 转换使用字母 abcdef 。
X 转换使用 ABCDEF 。
精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中若被转换值为非零则结果有 0x 或 0X 前缀。

 N/A
u
转换无符号整数为十进制表示 dddd 。

精度指定出现的最小数位数。 默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。

 N/A
f
F
转换浮点数为 [-]ddd.ddd 样式的十进制记法。

精度指定小数点字符后出现的准确数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A
double
double (C++11)
 N/A N/A N/A N/A
long double
e
E
转换浮点数为十进制指数记法。

e 转换样式使用 [-]d.ddd e±dd 。
E 转换样式使用 [-]d.ddd E±dd 。
指数至少含二个数位，仅当所需时使用更多数位。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
a
A

(C++11)
转换浮点数为十六进制记法。

a 转换样式使用 [-]0x h.hhh p±d 。
A 转换样式使用 [-]0X h.hhh P±d 。
若参数是正规化的浮点值，则首个十六进制数位非 0 。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度足以准确表示该值。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
g
G
转换浮点数为十进制小数或十进制指数记法，依赖于值和精度。

g 转换样式将进行带样式 e 或 f 的转换。
G 转换样式将进行带样式 E 或 F 的转换。
令 P 等于精度，若它非零，若精度未指定则为 6 ，若精度为 ​0​ 则等于 1 。然后，若带样式 E 的转换会有指数 X ，则：

  • 若 P > X ≥ −4 ，则转换带 f 或 F 风格，及精度 P − 1 − X 。
  • 否则，转换带 e 或 E 风格，及精度 P − 1 。

除非要求替用表示，否则末尾零会被移除，且若不留下小数部分则小数点亦被移除。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
n
返回对函数的此调用迄今为止写入的字符数。

结果被写入到参数所指向的值。 该指定不可含有任何标签、域宽或精度。
signed char*
short*
int*
long*
long long*
intmax_t*
有符号 size_t*
ptrdiff_t*
 N/A
p 写定义指针的实现定义字符序列。 N/A N/A void* N/A N/A N/A N/A N/A N/A

浮点转换函数转换无穷大到 inf 或 infinity 。使用哪个是实现定义的。

非数转换成 nan 或 nan(char_sequence) 。使用哪个是实现定义的。

转换 F 、 E 、 G 、 A 替代上面输出 INF 、 INFINITY 、 NAN。

尽管 %c 期待 int 参数，传递 char 是安全的，因为在调用变参数函数时发生整数提升。

定宽整数类型（ int8_t 等）的正确转换指定定义于头文件 <cinttypes> （尽管 PRIdMAX 、 PRIuMAX 等就是 %jd 、 %ju 等的别名）。

内存写入转换指定符 %n 是安全漏洞的常见目标，这里格式字符串依赖用户输入，而有边界检查的 printf_s 系列函数不支持此转换指定符。

在每个转换指定符的行动后有一个序列点；这允许于同一变量多次存入 %n 的结果，并在同一此调用中打印出先前以 %n 存储的值。

若转换指定非法，则行为未定义。
... - 指定要打印的数据的参数。若任何参数在默认转换后不拥有对应转换指定符所期待的类型，或若参数少于 format 所要求的数量，则行为未定义。若有多于 format 所要求的参数，则求值并忽略额外参数

返回值

1,2) 若成功则为写入的宽字符数，若出现错误则为负值。
3) 若成功则为写入的宽字符数（不计终止空宽字符），或若出现编码错误，或若生成的字符数等于或大于 size （包含 size 为零时）则为负值。

注意

窄字符串提供 std::snprintf ，它使得程序能够确定要求的输出缓冲区大小。不过宽字符串无等价版本，而且为确定缓冲区大小，程序需要调用 std::swprintf ，检查结果值，再重新分配更大的缓冲区，反复尝试直至成功。

示例

#include <iostream>
#include <locale>
#include <clocale>
#include <cwchar>

int main()
{
    char narrow_str[] = "z\u00df\u6c34\U0001f34c";
                    // 或 "zß水🍌"
                    // 或 "\x7a\xc3\x9f\xe6\xb0\xb4\xf0\x9f\x8d\x8c";
    wchar_t warr[29]; // 期待的字符串为 28 字符加 1 个空终止符
    std::setlocale(LC_ALL, "en_US.utf8");

    std::swprintf(warr, sizeof warr/sizeof *warr,
                  L"Converted from UTF-8: '%s'", narrow_str);

    std::wcout.imbue(std::locale("en_US.utf8"));
    std::wcout << warr << '\n';
}

输出：

Converted from UTF-8: 'zß水🍌'

参阅

printffprintfsprintfsnprintf (C++11) | 打印有格式输出到 stdout、文件流或缓冲区 (函数)
vwprintfvfwprintfvswprintf | 使用可变实参列表打印 有格式宽字符输出到 stdout、文件流或缓冲区 (函数)
fputws | 写宽字符串到文件流 (函数)


std::fwrite

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
std::size_t fwrite( const void* buffer, std::size_t size, std::size_t count, std::FILE * stream );

写 count 个来自给定数组 buffer 的对象到输出流stream。如同转译每个对象为 unsigned char 数组，并对每个对象调用 size 次 std::fputc 以将那些 unsigned char 按顺序写入 stream 一般写入。文件位置指示器前进写入的字节数。

若对象不可平凡复制 (TriviallyCopyable) ，则行为未定义。

若出现错误，则文件位置指示器的结果值不确定。

参数

buffer | - | 指向数组中要被写入的首个对象的指针
size | - | 每个对象的大小
count | - | 要被写入的对象数
stream | - | 指向输出流的指针

返回值

成功写入的对象数，若错误发生则可能小于 count 。

若 size 或 count 为零，则 fwrite 返回零并不进行其他行动。

示例

#include <cstdio>
#include <vector>
#include <array>

int main ()
{
    // 写缓冲区到文件
    if(std::FILE* f1 = std::fopen("file.bin", "wb")) {
        std::array<int, 3> v = {42, -1, 7}; // std::array 的底层存储为数组
        std::fwrite(v.data(), sizeof v[0], v.size(), f1);
        std::fclose(f1);
    }

    // 读取同一数据并打印它到标准输出
    if(std::FILE *f2 = std::fopen("file.bin", "rb")) {
        std::vector<int> rbuf(10); // std::vector 的底层存储亦为数组
        std::size_t sz = std::fread(rbuf.data(), sizeof rbuf[0], rbuf.size(), f2);
        std::fclose(f2);
        for(std::size_t n = 0; n < sz; ++n) {
            std::printf("%d\n", rbuf[n]);
        }
    }
}

输出：

42
-1
7

参阅

printffprintfsprintfsnprintf (C++11) | 打印有格式输出到 stdout、文件流或缓冲区 (函数)
fputs | 写字符串到文件流 (函数)
fread | 从文件读取 (函数)


std::wscanf, std::fwscanf, std::swscanf

< cpp‎ | io‎ | c
定义于头文件 <cwchar> |
int wscanf( const wchar_t* format, ... ); | (1)
int fwscanf( std::FILE * stream, const wchar_t* format, ... ); | (2)
int swscanf( const wchar_t* buffer, const wchar_t* format, ... ); | (3)

从各种源读取数据，按照 format 转译，并存储结果于给定位置。

1) 从 stdin 读取数据。
2) 从文件流 stream 读取数据。
3) 从空终止字符串 buffer 读取数据。

参数

stream - 读取来源的输入文件流
buffer - 指向作为读取来源的空终止宽字符串
format - 指向指定如何读取输入的空终止宽字符串的指针。

格式字符串由下列内容组成

  • 非空白宽字符，除了 % ：每个格式字符串中的这种字符处理来自输入流的准确同一字符，或若它与流的下个字符比较不相等则导致函数失败。
  • 空白符：任何格式字符串中的单个空白符处理所有来自输入的可用连续空白符（如同通过于循环中调用 iswspace 确定）。注意格式字符串中 "\n" 、 " " 、 "\t\t" 或其他空白无区别。
  • 转换说明：每个转换说明拥有下列格式：
  • 引入用 % 字符
  • (可选)赋值抑制字符 * 。若存在此选项，则此函数不将结果赋值给任何接收用参数。
  • (可选)指定最大域宽的整数数字（大于零），即函数进行在当前转换说明所指定的转换时，允许处理的最大字符数。注意若不提供宽度，则 %s 和 %[ 可能导致缓冲区溢出。
  • (可选)指定接收参数大小的长度修饰符，即实际目标类型。这影响转换准确性和溢出规则。默认目标类型对每个转换类型不同（见下表）。
  • 转换格式说明符

下列格式说明符可用：

转换
说明符 		解释 参数类型
长度修饰符 →
 hh

(C++11)

 h （无） l ll

(C++11)

 j

(C++11)

 z

(C++11)

 t

(C++11)

 L
% 匹配字面 % 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
匹配一个字符或字符的序列

若使用了宽度说明符，则匹配准确的宽度个宽字符（该参数必须是指向有充足空间的数组的指针）。不同于 %s 和 %[ ，它不会在数组后附加空字符。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
s
匹配非空白字符的序列（一个字符串）

若使用宽度说明符，则至多匹配宽度个字符，或匹配到首个提前出现的空白符前。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
[集合]
匹配一个来自 集合 的字符的非空字符序列。

若集合的首字符是 ^ ，则匹配所有不在集合中的字符。若集合以 ] 或 ^] 开始，则 ] 字符亦被包含入集合。在扫描集合的非最初位置的字符 - 是否可以指示范围，如 [0-9] ，是实现定义的。若使用宽度说明符，则最多匹配到宽度。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
d
匹配一个十进制整数。

该数的格式同 wcstol() 以值 10 为 base 时所期望者
signed char* 或 unsigned char*
signed short* 或 unsigned short*
signed int* 或 unsigned int*
signed long* 或 unsigned long*
signed long long* 或 unsigned long long*
intmax_t* 或 uintmax_t*
size_t*
ptrdiff_t*
 N/A
i
匹配一个整数。

该数的格式同 wcstol() 以值 ​0​ 为 base 时所期望者（基底以首个分析的字符确定）
u
匹配一个无符号十进制整数。

该数的格式同 wcstoul() 以值 10 为 base 参数时所期望者。
o
匹配一个无符号八进制数。

该数的格式同 wcstoul() 以值 8 为 base 参数时所期望者。
x, X
匹配一个无符号十六进制整数。

该数的格式同 wcstoul() 以值 16 为 base 参数时所期望者。
n
返回迄今读取的字符数。

不消耗输出。不增加赋值计数。若此说明符拥有赋值抑制运算符，则行为未定义。
a, A(C++11)
e, E
f, F
g, G
匹配一个浮点数。

该数的格式同 wcstof() 所期望者。

 N/A N/A
float*
double*
 N/A N/A N/A N/A
long double*
p
匹配定义一个指针的实现定义的字符序列。

printf 系列函数应该用 %p 格式说明符产生同样的序列。

 N/A N/A
void**
 N/A N/A N/A N/A N/A N/A

对于每个异于 n 的转换说明符，不超过任何指定域宽，且要么是转换说明符所准确期待，要么是其所期待的前缀的最长输入字符序列，即是从流中消耗的内容。此消耗序列后的首个字符若存在，则保持未读取。若被消耗序列长度为零，或被消耗序列不能转换成上面所指定的项目，则发生匹配失败，除非遇到文件尾、编码错误，或阻止从流输入的读取错误，此情况下此为输入失败。

所有异于 [ 、 c 和 n 的转换说明符，在尝试分析输入前消耗并舍弃所有前导空白字符（如同以调用 iswspace 来确定）。这些被消耗的字符不计入指定的最大域宽。

若不使用长度说明符 l ，则转换说明符 c 、 s 和 [ 进行宽到到多字节字符转换，如同在转换首字符前，通过用初始化到零的 mbstate_t 对象调用 wcrtomb() 。

转换说明符 s 与 [ 始终在匹配字符之后存储一个空字符。目标数组的大小必须至少比指定域宽大一。

定宽整数类型（ int8_t 等）的正确的转换说明定义于头文件 <cinttypes> （虽然 SCNdMAX 、 SCNuMAX 等就是 %jd 、 %ju 等的别名）。

在每个转换说明符后有一个序列点；这允许存储多个域到同一“池”变量中。

在分析以无数字指数为结尾的不完整浮点值，如以转换说明符 %f 分析 "100er" 时，消耗序列 "100e" （可能为合法浮点数的最长前缀），并导致匹配错误（被消耗序列不能转换成浮点数），而留下 "r" 。某些既存实现不遵守此规则并回滚，通过消耗 "100" 而留下 "er" ，例如 glibc 漏洞 1765 。
... - 接收参数

返回值

成功读取的参数数量，或若赋值首个接收参数前出现错误则为 EOF 。

注意

本节未完成
原因：暂无示例

参阅

vwscanfvfwscanfvswscanf
(C++11)(C++11)(C++11)
 使用可变实参列表
从 stdin、文件流或缓冲区读取有格式宽字符输入
(函数)


std::getchar

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int getchar();

从 stdin 读取下个字符。

等价于 std::getc (stdin) 。

参数

（无）

返回值

成功时为获得的字符，失败时为 EOF 。

若文件尾条件导致失败，则另外设置 stdin 上的文件尾指示器（见 feof() ）。若某个其他错误导致失败，则设置 stdin 上的错误指示器（见 ferror() ）。

参阅

fgetcgetc
 从文件流获取字符
(函数)


std::gets

< cpp‎ | io‎ | c
定义于头文件 <cstdio> |
char* gets( char* str ); | (C++11 中弃用) (C++14 中移除)

读取 stdin 到给定字符串，直至找到首个换行字符或文件尾发生。

参数

str - 要写入的字符串

返回值

成功时为 str ，失败时为空指针。

若因文件尾条件失败，则另外设置 stdin 上的文件尾指示器（见 std::feof() ）。若因某些其他错误失败，则设置 stdin 上的错误指示器（见 std::ferror() ）。

注解

此函数不提供给出足够长的输入字符串时，避免目标数组缓冲区溢出的手段。 std::gets 于 C++11 被弃用，并于 C++14 移除。

可使用 std::fgets 替代。

参阅

scanffscanfsscanf | 从 stdin、文件流或缓冲区读取有格式输入 (函数)
fgets | 从文件流获取字符串 (函数)
fputs | 写字符串到文件流 (函数)


std::getwchar

< cpp‎ | io‎ | c
定义于头文件 <cwchar>
wint_t getwchar();

从 stdin 读取下个宽字符。

参数

（无）

返回值

获得的宽字符，或若发生错误或抵达文件尾则为 WEOF 。

参阅

getchar | 从 stdin 读取字符 (函数)
fgetwcgetwc | 从文件流获取宽字符 (函数)


std::perror

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
void perror( const char *s );

打印当前存储于系统变量 errno 的错误码到 stderr 。

通过连接下列组分构成描述：

  • s 所指向的空终止字节字符串的内容后随 ": " （除非 s 为空指针或 s 所指向字符为空字符）
  • 实现定义的，描述存储于 errno 的错误码的错误消息字符串后随 '\n' 。错误消息字符串等同于 std::strerror (errno) 的结果。

参数

s - 指向拥有解释性消息的空终止字符串的指针

返回值

（无）

示例

#include <cmath>
#include <cerrno>
#include <cstdio>

int main()
{
    double not_a_number = std::log(-1.0);
    if (errno == EDOM) {
        std::perror("log(-1) failed");
    }
}

输出：

log(-1) failed: Numerical argument out of domain

参阅

errno | 展开成 POSIX 兼容的线程局域错误号变量的宏 (宏变量)
strerror | 返回给定错误码的文本版本 (函数)


std::putchar

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int putchar( int ch );

写入字符 ch 到 stdout 。在内部，恰于写入前转换字符为 unsigned char 。

等价于 putc(ch, stdout) 。

参数

ch - 要写入的字符

返回值

成功时，返回被写入字符。

失败时，返回 EOF 并设置 stdout 上的错误指示器（见 ferror() ）。

示例

#include <cstdio>

int main()
{
    for (char c = 'a'; c != 'z'; c++)
        std::putchar(c);
    std::putchar('\n');

    // putchar 返回值不等于参数
    int r = 0x1070;
    std::printf("\n0x%x\n", r);
    r = std::putchar(r);
    std::printf("\n0x%x\n", r);
}

输出：

abcdefghijklmnopqrstuvwxy
0x1070
p
0x70

参阅

fputcputc
 写字符到文件流
(函数)


std::puts

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int puts( const char *str );

写入每个来自空终止字符串 str 的字符及附加换行符 '\n' 到输出流 stdout ，如同以重复执行 std::putc 写入。

不写入来自 str 的空终止字符。

参数

str - 要写入的字符串

返回值

成功时返回非负值

失败时，返回 EOF 并设置 stdout 的错误指示器（见 std::ferror() ）。

注意

std::puts 函数后附一个换行字符到输出，而 std::fputs 不这么做。

不同的实现返回不同的非负数：一些返回最后写入的字符，一些返回写入的字符数（或若字符串长于 INT_MAX 则返回它），一些简单地返回非负常量。

在重定向 stdout 到文件时，导致 std::puts 失败的典型原因是用尽了文件系统的空间。

示例

#include <cstdio>

int main()
{
    int rc = std::puts("Hello World");

    if (rc == EOF)
       std::perror("puts()"); // POSIX 要求设置 errno
}

输出：

Hello World

参阅

fputs | 写字符串到文件流 (函数)
printffprintfsprintfsnprintf (C++11) | 打印有格式输出到 stdout、文件流或缓冲区 (函数)


std::putwchar

< cpp‎ | io‎ | c
定义于头文件 <cwchar>
wint_t putwchar( wchar_t ch );

写入宽字符 ch 到 stdout 。

参数

ch - 要写入的宽字符

返回值

成功时为 ch ，失败时为 WEOF 。

返回值

putchar | 写字符到 stdout (函数)
fputwcputwc | 写宽字符到文件流 (函数)


std::remove

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int remove( const char* fname );

删除 fname 所指向的字符串所标识的文件。

若文件为当前进程或另一进程打开，则此函数行为是实现定义的。具体而言， POSIX 系统解链接文件名，到最后一个运行的进程关闭该文件为止，即使这是最后一个到文件的硬链接也不回收文件系统空间。 Windows 不允许删除该文件。

参数

fname - 指向空终止字符串的指针，字符串含标识待删除文件的路径

返回值

成功时为 ​0​ ，错误时为非零值。

注意

POSIX 指定此函数行为的许多额外细节。

标准库亦定义接收一对迭代器和值的函数模板 std::remove ，此重载是标准算法之一。

示例

#include <iostream>
#include <fstream>
#include <cstdio>
int main()
{
    bool ok = static_cast<bool>(std::ofstream("file1.txt").put('a')); // 创建文件
    if(!ok) { std::perror("Error creating file1.txt"); return 1; }
    std::cout << std::ifstream("file1.txt").rdbuf() << '\n'; // 打印格式

    std::remove("file1.txt"); // 删除文件

    bool failed = !std::ifstream("file1.txt");
    if(failed) { std::perror("Error opening deleted file"); return 1; }
}

可能的输出：

a
Error opening deleted file: No such file or directory

参阅

removeremove_all (C++17)(C++17) | 移除一个文件或空目录 移除一个文件或递归地移除一个目录及其所有内容 (函数)
rename | 重命名文件 (函数)


std::rename

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int rename( const char *old_filename, const char *new_filename );

更改文件的文件名。以 old_filename 所指向的字符串标识该文件，以 new_filename 所指向的字符串标识新文件名。

若 new_filename 存在，则行为是实现定义的。

参数

old_filename | - | 指向空终止字符串的指针，字符串含有标识要重命名的文件的路径
new_filename | - | 指向空终止字符串的指针，字符串含有文件的新路径

返回值

成功时为 ​0​ ，错误时为非零值。

注解

POSIX 规定此函数语义上的许多额外细节，它们由 std::filesystem::rename 复制到 C++ 中。

示例

#include <iostream>
#include <fstream>
#include <cstdio>
int main()
{
    bool ok{std::ofstream("from.txt").put('a')}; // 创建并写入文件
    if (!ok) {
        std::perror("Error creating from.txt");
        return 1;
    }

    if (std::rename("from.txt", "to.txt")) {
        std::perror("Error renaming");
        return 1;
    }

    std::cout << std::ifstream("to.txt").rdbuf() << '\n'; // 打印文件
}

输出：

a

参阅

rename (C++17) | 移动或重命名一个文件或目录 (函数)
remove | 删除文件 (函数)


std::rewind

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
void rewind( std::FILE * stream );

移动文件位置指示器到给定文件流的起始。

函数等价于 std::fseek (stream, 0, SEEK_SET ); ，除了它清除文件尾和错误指示器。

此函数丢弃任何来自先前对 ungetc 调用的效果。

参数

stream - 要修改的文件流

返回值

（无）

示例

#include <cstdio>

int main()
{
    std::FILE *f;
    char ch;
    char str[20];

    f = std::fopen("file.txt", "w");
    for (ch = '0'; ch <= '9'; ch++) {
        std::fputc(ch, f);
    }
    std::fclose(f);

    std::FILE* f2 = std::fopen("file.txt", "r");
    unsigned int size = std::fread(str, 1, 10, f2);
    std::puts(str);
    std::printf("\n%u\n",size);

    std::rewind(f2);
    unsigned int size2 = std::fread(str, 1, 10, f2);
    std::puts(str);
    std::printf("\n%u",size2);
    std::fclose(f2);
}

参阅

fseek
 移动文件位置指示器到文件中的指定位置
(函数)


std::setbuf

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
void setbuf( std::FILE * stream, char* buffer );

为 C 流 stream 上进行的 I/O 操作设置内部缓冲区。

若 buffer 非空，则等价于 std::setvbuf (stream, buffer, _IOFBF, BUFSIZ ) 。

若 buffer 为空，则等价于 std::setvbuf (stream, NULL, _IONBF, 0) ，这会关闭缓冲。

参数

stream | - | 要设置缓冲区的文件流
buffer | - | 指向文件流所用的缓冲区的指针。若提供空指针，则关闭缓冲。若它非空，则数组必须足以保有至少 BUFSIZ 个字符

返回值

（无）

注解

若 BUFSIZ 不是适合的缓冲区大小，则能用 std::setvbuf 更改它。

std::setvbuf 亦应当用于检测错误，因为 std::setbuf 不指示成功或失败。

此函数仅可在已将 stream 关联到打开的文件后，但要在任何其他操作（除了对 std::setbuf/std::setvbuf 的失败调用）前使用。

一个常见错误是设置 stdin 或 stdout 的缓冲区为生存期在程序终止前结束的数组：

int main() {
    char buf[BUFSIZ];
    std::setbuf(stdin, buf);
} // buf 的生存期结束，未定义行为

示例

setbuf 可用于禁用要求立即输出的流上的缓冲

#include <cstdio>
#include <thread>
#include <chrono>

int main()
{
    using namespace std::chrono_literals;

    std::setbuf(stdout, NULL); // 无缓冲的 stdout
    std::putchar('a'); // 在无缓冲的流上立即显现
    std::this_thread::sleep_for(1s);
    std::putchar('b');
}

输出：

ab

参阅

setvbuf
 为文件流设置缓冲区与其大小
(函数)


std::setvbuf

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int setvbuf( std::FILE * stream, char* buffer, int mode, std::size_t size );

以 mode 所指示值更改给定文件流 stream 的缓冲模式。另外，

  • 若 buffer 为空指针，则重设内部缓冲区大小为 size 。
  • 若 buffer 不是空指针，则指示流使用始于 buffer 而大小为 size 的用户提供缓冲区。必须在 buffer 所指向的数组的生存期结束前（用 fclose ）关闭流。成功调用 setvbuf 后，数组内容不确定，而任何使用它的尝试是未定义行为。

参数

stream - 要设置缓冲的文件流
buffer - 指向要使用的流缓冲区的指针，或若仅更改大小和模式则为空指针
mode - 使用的缓冲模式。它能是下列值之一：
_IOFBF | 全缓冲：当缓冲区为空时，从流读入数据。或者当缓冲区满时，向流写入数据。
_IOLBF | 行缓冲：每次从流中读入一行数据或向流中写入一行数据。
_IONBF | 无缓冲：直接从流中读入数据或直接向流中写入数据，缓冲设置无效。
size - 缓冲区的大小

返回值

成功时为 ​0​ ，失败时为非零。

注意

此函数仅可在已将 stream 关联到打开的文件后，但要在任何其他操作（除了对 std::setbuf/std::setvbuf 的失败调用）前使用。

不是所有 size 字节都需要用于缓冲：实际缓冲区大小通常向下取整到 2 的倍数、页面大小的倍数等。

多数实现上，行缓冲仅对终端输入流可用。

一个常见错误是设置 stdin 或 stdout 的缓冲区为生存期在程序终止前结束的数组：

int main() {
    char buf[BUFSIZ];
    std::setbuf(stdin, buf);
} // buf 的生存期结束，未定义行为

期待默认缓冲区大小 BUFSIZ 为实现上文件 I/O 的最高效缓冲区大小，但 POSIX fstat 经常提供更好的估计。

示例

更改缓冲区大小的一个使用情况，是在知道更好的缓冲区大小时

#include <iostream>
#include <cstdio>
#include <stdlib.h>
#include <sys/stat.h>

int main()
{
    std::FILE* fp = std::fopen("test.txt", "r");
    if(!fp) {
       std::perror("fopen"); return 1;
    }

    struct stat stats;
    if(fstat(fileno(fp), &stats) == -1) { // 仅限 POSIX
        std::perror("fstat"); return 1;
    }

    std::cout << "BUFSIZ is " << BUFSIZ << ", but optimal block size is "
              << stats.st_blksize << '\n';
    if(std::setvbuf(fp, NULL, _IOFBF, stats.st_blksize) != 0) {
       perror("setvbuf failed"); // POSIX 版本设置 errno
       return 1;
    }

    int ch;
    while((ch=std::fgetc(fp)) != EOF); // 读取整个文件：用 truss/strace 观察
                                       // 所用的 read(2) syscall
    std::fclose(fp);
}

可能的输出：

BUFSIZ is 8192, but optimal block size is 65536

参阅

setbuf | 为文件流设置缓冲区 (函数)
setbuf [虚] | 提供用户供应的缓冲区，或将此 filebuf 转变为无缓冲 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)


stdin, stdout, stderr

< cpp‎ | io‎ | c
定义于头文件 <cstdio> |
#define stdin /* implementation-defined */ | (1)
#define stdout /* implementation-defined */ | (2)
#define stderr /* implementation-defined */ | (3)

预定义三个文本流。这些流在程序启动时隐式打开，且为无面向。

1) 与标准输入流关联，用于读取约定的输入。程序启动时，该流为完全缓冲当且仅当能确定流不引用交互式设备。
2) 与标准输出流关联，用于写入约定的输出。程序启动时，该流为完全缓冲当且仅当能确定流不引用交互式设备。
3) 与标准错误流关联，用于写入诊断输出。程序启动时，该流不为完全缓冲。

何者组成交互式设备是实现定义的。

这些宏展开成 std::FILE * 类型表达式。

注解

尽管 POSIX 不强制， UNIX 约定是 stdin 与 stdout 若与终端关联则为行缓冲，而 stderr 为无缓冲。

这些宏可能展开成可修改左值。若修改任何这些 std::FILE * 左值，则对应的流上的后续操作导致未指明或未定义行为。

示例

此示例展示等价于 std::printf 的函数。

#include <stdarg.h>
#include <stdio.h>

int my_printf(const char * fmt, ...)
{
    std::va_list vl;
    va_start(vl, fmt);
    int ret = std::vfprintf(stdout, fmt, vl);
    va_end(vl);
    return ret;
}

int main()
{
    my_printf("Rounding:\t%f %.0f %.32f\n", 1.5, 1.5, 1.3);
    my_printf("Padding:\t%05.2f %.2f %5.2f\n", 1.5, 1.5, 1.5);
    my_printf("Scientific:\t%E %e\n", 1.5, 1.5);
    my_printf("Hexadecimal:\t%a %A\n", 1.5, 1.5);
}

可能的输出：

Rounding:       1.500000 2 1.30000000000000004440892098500626
Padding:        01.50 1.50  1.50
Scientific:     1.500000E+00 1.500000e+00
Hexadecimal:    0x1.8p+0 0X1.8P+0

参阅

cinwcin | 从标准 C 输入流 stdin 中读取 (全局对象)
coutwcout | 写入到标准 C 输出流 stdout (全局对象)
cerrwcerr | 写入到标准 C 错误流 stderr， 无缓冲 (全局对象)
clogwclog | 写入到标准 C 错误流 stderr (全局对象)


std::tmpfile

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
std::FILE * tmpfile();

创建并打开临时文件。

该文件作为二进制文件、更新模式（如同为 std::fopen 以 "wb+" 模式）打开。该文件的文件名保证在文件系统中唯一。至少可以在程序的生存期内能打开 TMP_MAX 个文件（此极限可能与 tmpnam 共享，并可能为 FOPEN_MAX 进一步限制）。

若程序关闭文件，例如通过执行 std::fclose ，则自动删除文件。

若程序正常退出（通过调用 std::exit 、从 main 返回等，则亦自动删除所有通过调用 std::tmpfile 打开的文件。

若程序非正常退出，则是否删除这些临时文件是实现定义的。

参数

（无）

返回值

关联的文件流，或若出现错误则为空指针。

注解

一些实现（如 Linux ）上，此函数确实从文件系统上创建、打开并立即删除该文件：只要被删除文件的文件开启描述符为程序所管理，该文件就会存在，但只要它被删除，其名就不会出现于任何目录中，从而再无其他进程能打开它。一旦文件描述符被关闭，或一旦程序终止（正常或异常），该文件所占有的空间将被文件系统回收。

一些实现（如 Windows ）上要求提升的权限，因为该函数可能在系统目录中创建临时文件。

示例

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    std::FILE* tmpf = std::tmpfile();
    std::fputs("Hello, world", tmpf);
    std::rewind(tmpf);
    char buf[6];
    std::fgets(buf, sizeof buf, tmpf);
    std::cout << buf << '\n';

    // 显示临时文件名的 Linux 特定方法
    std::cout << fs::read_symlink(
                     fs::path("/proc/self/fd") / std::to_string(fileno(tmpf))
                 ) << '\n';
}

可能的输出：

Hello
"/tmp/tmpfBlY1lI (deleted)"

参阅

tmpnam | 返回一个唯一独有的文件名 (函数)
temp_directory_path (C++17) | 返回一个适用于临时文件的目录 (函数)


std::tmpnam

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
char* tmpnam( char* filename );

创建不指名当前存在的文件的独有文件名，并将它存储于 filename 所指向的字符串。函数足以生成至多 TMP_MAX 个独有的文件名，但其一些或全部可能已在使用中，从而不适合作为返回值。

std::tmpnam 修改静态状态，而且不要求为线程安全。

参数

filename - 指向足以保有至少 L_tmpnam 字节的字符数组的指针，将以数组为结果缓冲区。若传递空指针，则返回指向内部静态缓冲区的指针。

返回值

若 filename 不是空指针则为 filename 。否则为指向内部静态缓冲区的指针。若不能生成适合的文件名，则返回空指针。若无法生成适合文件名，则返回空指针。

注解

尽管 std::tmpnam 所生成的文件名难以猜测，却可能是另一个进程在 std::tmpnam 返回的时刻和此函程序试图使用返回的名称创建文件之间创建的文件的名称。标准函数 std::tmpfile 和 POSIX 函数 mkstemp 无此问题（仅使用 C 标准库创建一个独有的目录仍然要求使用 std::tmpnam ）。

POSIX 系统额外定义名称类似的函数 tempnam() ，它提供对目录的选择（默认是可选定义的宏 P_tmpdir ）。

示例

#include <iostream>
#include <cstdio>
#include <string>

int main()
{
    std::string name1 = std::tmpnam(nullptr);
    std::cout << "temporary file name: " << name1 << '\n';

    char name2[L_tmpnam];
    if (std::tmpnam(name2)) {
        std::cout << "temporary file name: " << name2 << '\n';
    }
}

可能的输出：

temporary file name: /tmp/fileDjwifs
temporary file name: /tmp/fileEv2bfW

参阅

tmpfile | 创建并打开一个临时、自动移除的文件 (函数)
temp_directory_path (C++17) | 返回一个适用于临时文件的目录 (函数)


std::ungetc

< cpp‎ | io‎ | c
定义于头文件 <cstdio>
int ungetc( int ch, std::FILE *stream );

若 ch 不等于 EOF ，则推入字符 ch （转译为 unsigned char ）到与流 stream 关联的输入缓冲区，方式满足从 stream 的后继读取操作将取得该字符。不修改与流关联的外部设备。

流重寻位操作 std::fseek 、 std::fsetpos 和 std::rewind 弃去 ungetc 的效果。

若调用 ungetc 多于一次，而无中间读取或重寻位，则可能失败（换言之，保证大小为 1 的回放缓冲区，但任何更大的缓冲区是实现定义的）。若成功进行多次 ungetc ，则读取操作以 ungetc 的逆序取得回放的字符。

若 ch 等于 EOF ，则操作失败而不影响流。

对 ungetc 的成功调用清除文件尾状态标志 std::feof 。

在二进制流上对 ungetc 的成功调用将流位置指示器减少一（若流位置指示器为零，则行为不确定）。

在文本流上对 ungetc 的成功调用以未指定方式修改流位置指示器，但保证在以读取操作取得所有回放字符后，流位置指示器等于其在 ungetc 之前的值。

参数

ch | - | 要推入输入流缓冲区的字符
stream | - | 要回放字符到的文件流

返回值

成功时返回 ch 。

失败时返回 EOF ，而给定的流保持不变。

注意

实践中，回放缓冲区的大小会在 4k （ Linux 、 MacOS ）和 4 （ Solaris ）或保证的最小值 1 （ HPUX 、 AIX ）间变化。

若回放的字符等于存在于外部字符序列中该位置的字符，则回放缓冲区的表观大小可以更大（实现可以简单地自减读取的文件位置指示器，并避免维护回放缓冲区）。

示例

以其原目的：实现 scanf 演示 ungetc 的使用

#include <cctype>
#include <cstdio>

void demo_scanf(const char* fmt, std::FILE* s) {
    if(*fmt == '%') {
        switch(*++fmt) {
            case 'u': {
                int c;
                while(std::isspace(c=std::getc(s))) {} // 跳过前导空白
                unsigned int num = 0;
                while(std::isdigit(c)) {
                    num = num*10 + c-'0';
                    c = std::getc(s);
                }
                std::printf("%%u scanned %u\n", num);
                std::ungetc(c, s); // 重处理非数位
            }
            case 'c': {
                int c = std::getc(s);
                std::printf("%%c scanned '%c'\n", c);
            }
        }
    }
}

int main()
{
    std::FILE* f = std::fopen("input.txt", "w+");
    std::fputs("123x", f);
    std::rewind(f);
    demo_scanf("%u%c", f);
    std::fclose(f);
}

输出：

%u scanned 123
%c scanned 'x'

参阅

fgetcgetc
 从文件流获取字符
(函数)


std::ungetwc

< cpp‎ | io‎ | c
定义于头文件 <cwchar>
wint_t ungetwc( wint_t ch, std::FILE * stream );

若 ch 不等于 WEOF ，则推入宽字符 ch 到与流 stream 关联的输入缓冲区，方式满足从 stream 的后继读取操作将取得该宽字符。不修改与流关联的外部设备。

流重寻位操作 std::fseek 、 std::fsetpos 和 std::rewind 弃去 ungetwc 的效果。

若调用 ungetwc 多于一次，而无中间读取或重寻位，则可能失败（换言之，保证大小为 1 的回放缓冲区，但任何更大的缓冲区是实现定义的）。若成功进行多次 ungetwc ，则读取操作以 ungetwc 的逆序取得回放的宽字符。

若 ch 等于 WEOF ，则操作失败而不影响流。

对 ungetwc 的成功调用清除文件尾状态标志 feof 。

在流（无论文本还是二进制）上对 ungetwc 的成功调用以未指定方式修改流位置指示器，但保证在以读取操作取得所有回放的宽字符后，流位置指示器等于其在 ungetwc 之前的值。

参数

ch | - | 要推入输入流缓冲区的宽字符
stream | - | 要回放宽字符到的文件流

返回值

成功时返回 ch 。

失败时返回 WEOF ，而给定的流保持不变。

参阅

ungetc | 把字符放回文件流 (函数)
fgetwcgetwc | 从文件流获取宽字符 (函数)


std::vprintf, std::vfprintf, std::vsprintf, std::vsnprintf

< cpp‎ | io‎ | c
定义于头文件 <cstdio> |  |
int vprintf( const char* format, va_list vlist ); | (1) |
int vfprintf( std::FILE * stream, const char* format, va_list vlist ); | (2) |
int vsprintf( char* buffer, const char* format, va_list vlist ); | (3) |
int vsnprintf( char* buffer, std::size_t buf_size, const char* format, va_list vlist ); | (4) | (C++11 起)

从 vlist 所定义的各种位置，转换之为字符串等价版本，并写入结果到各种池。

1) 写结果到 stdout 。
2) 写结果到文件流 stream 。
3) 写结果到字符串 buffer 。
4) 写结果到字符串 buffer 。至多写入 buf_size - 1 个字符。结果字符串将以空字符终止，除非 buf_size 为零。若 buf_size 为零，则不写入内容且 buffer 可为空指针，然而仍然计算并返回返回值（本应写入的字节数，不包含空终止符）。

参数

stream - 要写入的输出文件流
buffer - 指向要写入的字符串的指针
buf_size - 要写入的最大字符数
format - 指向空终止字符串的指针，字符串指定如何转译数据。

格式字符串由普通多字节字符（除了 % ）和转换指定构成，前者被复制到输出流而无更改。每个转换指定拥有下列格式：

  • 引入的 % 字符
  • (可选)一或多个修改转换行为的标签：
  • - ：转换结果在域内左校正（默认为右校正）
  • + ：有符号转换的符号始终前置于转换结果（默认结果前置负号仅当它为负）
  • 空格：若有符号转换的结果不以符号开始，或为空，则前置空格于结果。若存在 + 标签则忽略空格。
  • # ：进行替用形式的转换。准确的效果见下表，其他情况下行为未定义。
  • 0 ：对于整数和浮点数转换，使用前导零代替空格字符填充域。对于整数，若显式指定精度，则忽略此标签。对于其他转换，使用此标签导致未定义行为。若存在 - 标签则忽略 0 。
  • (可选)指定最小域宽的整数值或 * 。若有要求，则结果会以空格字符（默认情况）填充，在右校正时于左，左校正时于右。使用 * 的情况下，以一个额外的 int 类型参数指定宽度。若参数值为负数，则它导致指定 - 标签和正域宽。（注意：这是最小宽度：决不被截断值）。
  • (可选)后随整数或 * 或两者皆无的 . 指示转换的精度。在使用 * 的情况下，精度由额外的 int 类型参数指定。若此参数的值为负数，则它被忽略。若既不使用数字亦不使用 * ，则精度采用零。精度的准确效果见下表。
  • (可选)指定参数大小的长度修饰符
  • 转换格式指定符

下列格式指定符可用：

转换
指定符 		解释 参数类型
长度修饰符 hh

(C++11)

 h （无） l ll

(C++11)

 j

(C++11)

 z

(C++11)

 t

(C++11)

 L
% 写字面的 % 。完整转换指定必须是 %% 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
写单个字符。

参数首先被转换成 unsigned char 。 若使用 l 修饰符，则参数首先被转换成字符串，如同通过以 wchar_t[2] 参数使用 %ls 。

 N/A N/A
int
wint_t
 N/A N/A N/A N/A N/A
s
写字符串

参数必须是指向字符数组首元素的指针 精度指定写入最大的字符数。若未指定精度，则写每个字节直到而不含首个空终止符。 若使用 l 指定符，则参数必须是指向 wchar_t 数组首元素的指针，数组会被转换成 char 数组，如同通过以零初始化转换状态调用 wcrtomb 。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
d
i
转换有符号整数为十进制表示 [-]dddd 。

精度指定出现的最小数位数。默认精度是 1 。
若被转换的值和精度都是 ​0​ ，则转换结果无字符。
signed char
short
int
long
long long
intmax_t
有符号 size_t
ptrdiff_t
 N/A
o
转换无符号整数为八进制表示 oooo 。

精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中精度按需增加，以写入一个前导零。 在此情况下若被转换值和精度都是 ​0​ ，则写入单个 ​0​ 。
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
uintmax_t
size_t
ptrdiff_t 的无符号版本
 N/A
x
X
转换无符号整数为十六进制表示 hhhh 。

x 转换使用字母 abcdef 。
X 转换使用 ABCDEF 。
精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中若被转换值为非零则结果有 0x 或 0X 前缀。

 N/A
u
转换无符号整数为十进制表示 dddd 。

精度指定出现的最小数位数。 默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。

 N/A
f
F
转换浮点数为 [-]ddd.ddd 样式的十进制记法。

精度指定小数点字符后出现的准确数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A
double
double (C++11)
 N/A N/A N/A N/A
long double
e
E
转换浮点数为十进制指数记法。

e 转换样式使用 [-]d.ddd e±dd 。
E 转换样式使用 [-]d.ddd E±dd 。
指数至少含二个数位，仅当所需时使用更多数位。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
a
A

(C++11)
转换浮点数为十六进制记法。

a 转换样式使用 [-]0x h.hhh p±d 。
A 转换样式使用 [-]0X h.hhh P±d 。
若参数是正规化的浮点值，则首个十六进制数位非 0 。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度足以准确表示该值。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
g
G
转换浮点数为十进制小数或十进制指数记法，依赖于值和精度。

g 转换样式将进行带样式 e 或 f 的转换。
G 转换样式将进行带样式 E 或 F 的转换。
令 P 等于精度，若它非零，若精度未指定则为 6 ，若精度为 ​0​ 则等于 1 。然后，若带样式 E 的转换会有指数 X ，则：

  • 若 P > X ≥ −4 ，则转换带 f 或 F 风格，及精度 P − 1 − X 。
  • 否则，转换带 e 或 E 风格，及精度 P − 1 。

除非要求替用表示，否则末尾零会被移除，且若不留下小数部分则小数点亦被移除。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
n
返回对函数的此调用迄今为止写入的字符数。

结果被写入到参数所指向的值。 该指定不可含有任何标签、域宽或精度。
signed char*
short*
int*
long*
long long*
intmax_t*
有符号 size_t*
ptrdiff_t*
 N/A
p 写定义指针的实现定义字符序列。 N/A N/A void* N/A N/A N/A N/A N/A N/A

浮点转换函数转换无穷大到 inf 或 infinity 。使用哪个是实现定义的。

非数转换成 nan 或 nan(char_sequence) 。使用哪个是实现定义的。

转换 F 、 E 、 G 、 A 替代上面输出 INF 、 INFINITY 、 NAN。

尽管 %c 期待 int 参数，传递 char 是安全的，因为在调用变参数函数时发生整数提升。

定宽整数类型（ int8_t 等）的正确转换指定定义于头文件 <cinttypes> （尽管 PRIdMAX 、 PRIuMAX 等就是 %jd 、 %ju 等的别名）。

内存写入转换指定符 %n 是安全漏洞的常见目标，这里格式字符串依赖用户输入，而有边界检查的 printf_s 系列函数不支持此转换指定符。

在每个转换指定符的行动后有一个序列点；这允许于同一变量多次存入 %n 的结果，并在同一此调用中打印出先前以 %n 存储的值。

若转换指定非法，则行为未定义。
vlist - 含有要打印数据的可变参数列表

返回值

1-3) 若成功则为写入的字符数，或若出现错误则为负值。
4) 若成功则为写入的字符数，或若出现错误则为负值。若结果字符串由于 buf_size 限制被截断，则函数返回假如未强加极限则本应写入的总字节数（不包含空终止字符）。

注意

所有这些函数调用 va_arg 至少一次，返回后 arg 的值不确定。这些函数不调用 va_end ，而这必须由调用方进行。

示例

#include <vector>
#include <cstdio>
#include <cstdarg>
#include <ctime>

void debug_log(const char *fmt, ...)
{
    auto t = std::time(nullptr);
    char time_buf[100];
    std::strftime(time_buf, sizeof time_buf, "%D %T", std::gmtime(&t));
    va_list args1;
    va_start(args1, fmt);
    va_list args2;
    va_copy(args2, args1);
    std::vector<char> buf(1 + std::vsnprintf(nullptr, 0, fmt, args1));
    va_end(args1);
    std::vsnprintf(buf.data(), buf.size(), fmt, args2);
    va_end(args2);
    std::printf("%s [debug]: %s\n", time_buf, buf.data());
}

int main()
{
    debug_log("Logging, %d, %d, %d", 1, 2, 3);
}

输出：

04/13/15 15:09:18 [debug]: Logging, 1, 2, 3

参阅

printffprintfsprintfsnprintf (C++11) | 打印有格式输出到 stdout、文件流或缓冲区 (函数)
vscanfvfscanfvsscanf (C++11)(C++11)(C++11) | 使用可变实参列表 从 stdin、文件流或缓冲区读取有格式输入 (函数)


std::vscanf, std::vfscanf, std::vsscanf

< cpp‎ | io‎ | c
定义于头文件 <cstdio> |  |
int vscanf( const char* format, va_list vlist ); | (1) | (C++11 起)
int vfscanf( std::FILE * stream, const char* format, va_list vlist ); | (2) | (C++11 起)
int vsscanf( const char* buffer, const char* format, va_list vlist ); | (3) | (C++11 起)

从各种源读取数据，按照 format 转译并存储结果到 vlist 所定义的位置。

1) 从 stdin 读取数据。
2) 从文件流 stream 读取数据。
3) 从空终止字符串 buffer 读取数据。

参数

stream - 要读取的输入文件流
buffer - 指向要读取的空终止字符串的指针
format - 指向指定如何读取输入的空终止字符串的指针。

格式字符串由下列内容组成

  • 非空白多字节字符，除了 % ：每个格式字符串中的这种字符处理来自输入流的准确同一字符，或若它与流的下个字符比较不相等则导致函数失败。
  • 空白符：任何格式字符串中的单个空白符处理所有来自输入的可用连续空白符（如同通过于循环中调用 isspace 确定）。注意格式字符串中 "\n" 、 " " 、 "\t\t" 或其他空白无区别。
  • 转换说明：每个转换说明拥有下列格式：
  • 引入用 % 字符
  • (可选)赋值抑制字符 * 。若存在此选项，则此函数不将结果赋值给任何接收用参数。
  • (可选)指定最大域宽的整数数字（大于零），即函数进行在当前转换说明所指定的转换时，允许处理的最大字符数。注意若不提供宽度，则 %s 和 %[ 可能导致缓冲区溢出。
  • (可选)指定接收参数大小的长度修饰符，即实际目标类型。这影响转换准确性和溢出规则。默认目标类型对每个转换类型不同（见下表）。
  • 转换格式说明符

下列格式说明符可用：

转换
说明符 		解释 参数类型
长度修饰符 →
 hh

(C++11)

 h （无） l ll

(C++11)

 j

(C++11)

 z

(C++11)

 t

(C++11)

 L
% 匹配字面 % 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
匹配一个字符或字符的序列

若使用了宽度说明符，则匹配准确的宽度个字符（该参数必须是指向有充足空间的数组的指针）。不同于 %s 和 %[ ，它不会在数组后附加空字符。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
s
匹配非空白字符的序列（一个字符串）

若使用宽度说明符，则至多匹配宽度个字符，或匹配到首个提前出现的空白符前。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
[集合]
匹配一个来自 集合 的字符的非空字符序列。

若集合的首字符是 ^ ，则匹配所有不在集合中的字符。若集合以 ] 或 ^] 开始，则 ] 字符亦被包含入集合。在扫描集合的非最初位置的字符 - 是否可以指示范围，如 [0-9] ，是实现定义的。若使用宽度说明符，则最多匹配到宽度。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
d
匹配一个十进制整数。

该数的格式同 strtol() 以值 10 为 base 时所期望者
signed char* 或 unsigned char*
signed short* 或 unsigned short*
signed int* 或 unsigned int*
signed long* 或 unsigned long*
signed long long* 或 unsigned long long*
intmax_t* 或 uintmax_t*
size_t*
ptrdiff_t*
 N/A
i
匹配一个整数。

该数的格式同 strtol() 以值 ​0​ 为 base 时所期望者（基底以首个分析的字符确定）
u
匹配一个无符号十进制整数。

该数的格式同 strtoul() 以值 10 为 base 参数时所期望者。
o
匹配一个无符号八进制数。

该数的格式同 strtoul() 以值 8 为 base 参数时所期望者。
x, X
匹配一个无符号十六进制整数。

该数的格式同 strtoul() 以值 16 为 base 参数时所期望者。
n
返回迄今读取的字符数。

不消耗输出。不增加赋值计数。若此说明符拥有赋值抑制运算符，则行为未定义。
a, A(C++11)
e, E
f, F
g, G
匹配一个浮点数。

该数的格式同 strtof() 所期望者。

 N/A N/A
float*
double*
 N/A N/A N/A N/A
long double*
p
匹配定义一个指针的实现定义的字符序列。

printf 系列函数应该用 %p 格式说明符产生同样的序列。

 N/A N/A
void**
 N/A N/A N/A N/A N/A N/A

对于每个异于 n 的转换说明符，不超过任何指定域宽，且要么是转换说明符所准确期待，要么是其所期待的前缀的最长输入字符序列，即是从流中消耗的内容。此消耗序列后的首个字符若存在，则保持未读取。若被消耗序列长度为零，或被消耗序列不能转换成上面所指定的项目，则发生匹配失败，除非遇到文件尾、编码错误，或阻止从流输入的读取错误，此情况下此为输入失败。

所有异于 [ 、 c 和 n 的转换说明符，在尝试分析输入前消耗并舍弃所有前导空白字符（如同以调用 isspace 来确定）。这些被消耗的字符不计入指定的最大域宽。

转换说明符 lc 、 ls 和 l[ 进行多字节到宽字符转换，如同如同在转换首字符前，通过用初始化到零的 mbstate_t 对象调用 mbrtowc() 。

转换说明符 s 与 [ 始终在匹配字符之后存储一个空字符。目标数组的大小必须至少比指定域宽大一。

定宽整数类型（ int8_t 等）的正确的转换说明定义于头文件 <cinttypes> （虽然 SCNdMAX 、 SCNuMAX 等就是 %jd 、 %ju 等的别名）。

在每个转换说明符后有一个序列点；这允许存储多个域到同一“池”变量中。

在分析以无数字指数为结尾的不完整浮点值，如以转换说明符 %f 分析 "100er" 时，消耗序列 "100e" （可能为合法浮点数的最长前缀），并导致匹配错误（被消耗序列不能转换成浮点数），而留下 "r" 。某些既存实现不遵守此规则并回滚，通过消耗 "100" 而留下 "er" ，例如 glibc 漏洞 1765 。
vlist - 含有接收参数的可变参数列表

返回值

成功读取的参数个数，或若出现失败则为 EOF 。

注解

所有这些函数调用 va_arg 至少一次，返回后 arg 的值不确定。这些函数不调用 va_end ，而这必须由调用方进行。

示例

#include <iostream>
#include <cstdio>
#include <cstdarg>
#include <stdexcept>

void checked_sscanf(int count, const char* buf, const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    if(std::vsscanf(buf, fmt, ap) != count)
        throw std::runtime_error("parsing error");
    va_end(ap);
}

int main()
{
    try {
        int n, m;
        std::cout << "Parsing '1 2'...";
        checked_sscanf(2, "1 2", "%d %d", &n, &m);
        std::cout << "success\n";
        std::cout << "Parsing '1 a'...";
        checked_sscanf(2, "1 a", "%d %d", &n, &m);
        std::cout << "success\n";
    } catch(const std::exception& e)
    {
        std::cout << e.what() << '\n';
    }
}

输出：

Parsing '1 2'...success
Parsing '1 a'...parsing error

参阅

scanffscanfsscanf | 从 stdin、文件流或缓冲区读取有格式输入 (函数)
vprintfvfprintfvsprintfvsnprintf (C++11) | 使用可变实参列表 打印有格式输出到 stdout、文件流或缓冲区 (函数)


std::vwprintf, std::vfwprintf, std::vswprintf

< cpp‎ | io‎ | c
定义于头文件 <cwchar>
int vwprintf( const wchar_t* format, va_list vlist );
 (1)
int vfwprintf( std::FILE * stream, const wchar_t* format, va_list vlist );
 (2)
int vswprintf( const wchar_t* buffer, std::size_t buf_size,
const wchar_t* format, va_list vlist );
 (3)

从 vlist 所定义的位置加载数据，转换为宽字符串等价版本，并将结果写入各种池。

1) 写入结果到 stdout 。
2) 写入结果到文件流 stream 。
3) 写入结果到宽字符串 buffer 。至多写入后随空宽字符的 size-1 个宽字符。

参数

stream - 要写入的输出宽流
buffer - 指向要写入的宽字符串的指针
buf_size - 要写入的最大宽字符数
format - 指向指定如何转译数据的空终止宽字符串的指针。

格式字符串由普通宽字符（除了 % ）和转换指定构成，前者被复制到输出流而无更改。每个转换指定拥有下列格式：

  • 引入的 % 字符
  • (可选)一或多个修改转换行为的标签：
  • - ：转换结果在域内左校正（默认为右校正）
  • + ：有符号转换的符号始终前置于转换结果（默认结果前置负号仅当它为负）
  • 空格：若有符号转换的结果不以符号开始，或为空，则前置空格于结果。若存在 + 标签则忽略空格。
  • # ：进行替用形式的转换。准确的效果见下表，其他情况下行为未定义。
  • 0 ：对于整数和浮点数转换，使用前导零代替空格字符填充域。对于整数，若显式指定精度，则忽略此标签。对于其他转换，使用此标签导致未定义行为。若存在 - 标签则忽略 0 。
  • (可选)指定最小域宽的整数值或 * 。若有要求，则结果会以空格字符（默认情况）填充，在右校正时于左，左校正时于右。使用 * 的情况下，以一个额外的 int 类型参数指定宽度。若参数值为负数，则它导致指定 - 标签和正域宽。（注意：这是最小宽度：决不被截断值）。
  • (可选)后随整数或 * 或两者皆无的 . 指示转换的精度。在使用 * 的情况下，精度由额外的 int 类型参数指定。若此参数的值为负数，则它被忽略。若既不使用数字亦不使用 * ，则精度采用零。精度的准确效果见下表。
  • (可选)指定参数大小的长度修饰符
  • 转换格式指定符

下列格式指定符可用：

转换
指定符 		解释 参数类型
长度修饰符 hh

(C++11)

 h （无） l ll

(C++11)

 j

(C++11)

 z

(C++11)

 t

(C++11)

 L
% 写字面的 % 。完整转换指定必须是 %% 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
写单个字符。

参数首先被转换成 wchar_t ，如同通过调用 btowc 。 若使用 l 修饰符，则 wint_t 参数首先被转换成 wchar_t 。

 N/A N/A
int
wint_t
 N/A N/A N/A N/A N/A
s
写字符串

参数必须为一个指针，指向包含以初始迁移状态开始的，多字节字符序列的字符数组首元素，数组会被转换成宽字符数组，如同通过以零初始化转换状态调用 mbrtowc 。 精度指定写入的最大宽字符数。若未指定精度，则写每个宽字符直到而不含首个空终止符。 若使用 l 指定符，则参数必须是指向 wchar_t 数组首元素的指针。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
d
i
转换有符号整数为十进制表示 [-]dddd 。

精度指定出现的最小数位数。默认精度是 1 。
若被转换的值和精度都是 ​0​ ，则转换结果无字符。
signed char
short
int
long
long long
intmax_t
有符号 size_t
ptrdiff_t
 N/A
o
转换无符号整数为八进制表示 oooo 。

精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中精度按需增加，以写入一个前导零。 在此情况下若被转换值和精度都是 ​0​ ，则写入单个 ​0​ 。
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
uintmax_t
size_t
ptrdiff_t 的无符号版本
 N/A
x
X
转换无符号整数为十六进制表示 hhhh 。

x 转换使用字母 abcdef 。
X 转换使用 ABCDEF 。
精度指定出现的最小数位数。默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。 在替用实现中若被转换值为非零则结果有 0x 或 0X 前缀。

 N/A
u
转换无符号整数为十进制表示 dddd 。

精度指定出现的最小数位数。 默认精度是 1 。 若被转换值和精度都是 ​0​ ，则转换结果无字符。

 N/A
f
F
转换浮点数为 [-]ddd.ddd 样式的十进制记法。

精度指定小数点字符后出现的准确数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A
double
double (C++11)
 N/A N/A N/A N/A
long double
e
E
转换浮点数为十进制指数记法。

e 转换样式使用 [-]d.ddd e±dd 。
E 转换样式使用 [-]d.ddd E±dd 。
指数至少含二个数位，仅当所需时使用更多数位。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度是 6 。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
a
A

(C++11)
转换浮点数为十六进制记法。

a 转换样式使用 [-]0x h.hhh p±d 。
A 转换样式使用 [-]0X h.hhh P±d 。
若参数是正规化的浮点值，则首个十六进制数位非 0 。 若值为 ​0​ ，则指数亦为 ​0​ 。 精度指定小数点字符后出现的最小数位数。 默认精度足以准确表示该值。 在替用实现中即使没有小数点后数位也写小数点。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
g
G
转换浮点数为十进制小数或十进制指数记法，依赖于值和精度。

g 转换样式将进行带样式 e 或 f 的转换。
G 转换样式将进行带样式 E 或 F 的转换。
令 P 等于精度，若它非零，若精度未指定则为 6 ，若精度为 ​0​ 则等于 1 。然后，若带样式 E 的转换会有指数 X ，则：

  • 若 P > X ≥ −4 ，则转换带 f 或 F 风格，及精度 P − 1 − X 。
  • 否则，转换带 e 或 E 风格，及精度 P − 1 。

除非要求替用表示，否则末尾零会被移除，且若不留下小数部分则小数点亦被移除。 无穷大和非数的转换样式见注意。

 N/A N/A N/A N/A N/A N/A
n
返回对函数的此调用迄今为止写入的字符数。

结果被写入到参数所指向的值。 该指定不可含有任何标签、域宽或精度。
signed char*
short*
int*
long*
long long*
intmax_t*
有符号 size_t*
ptrdiff_t*
 N/A
p 写定义指针的实现定义字符序列。 N/A N/A void* N/A N/A N/A N/A N/A N/A

浮点转换函数转换无穷大到 inf 或 infinity 。使用哪个是实现定义的。

非数转换成 nan 或 nan(char_sequence) 。使用哪个是实现定义的。

转换 F 、 E 、 G 、 A 替代上面输出 INF 、 INFINITY 、 NAN。

尽管 %c 期待 int 参数，传递 char 是安全的，因为在调用变参数函数时发生整数提升。

定宽整数类型（ int8_t 等）的正确转换指定定义于头文件 <cinttypes> （尽管 PRIdMAX 、 PRIuMAX 等就是 %jd 、 %ju 等的别名）。

内存写入转换指定符 %n 是安全漏洞的常见目标，这里格式字符串依赖用户输入，而有边界检查的 printf_s 系列函数不支持此转换指定符。

在每个转换指定符的行动后有一个序列点；这允许于同一变量多次存入 %n 的结果，并在同一此调用中打印出先前以 %n 存储的值。

若转换指定非法，则行为未定义。
vlist - 含有待打印数据的可变参数列表

返回值

1,2) 若成功则为写入的宽字符数，若出现错误则为负值。
3) 若成功则为写入的宽字符数（不包含终止空宽字符），若出现编码错误，或若要生成的字符数等于或大于 size 则为负值。

注意

窄字符串提供 std::vsnprintf ，它使得程序能够确定要求的输出缓冲区大小。不过宽字符串无等价版本，而且为确定缓冲区大小，程序需要调用 std::vswprintf 并检查结果值，再重新分配更大的缓冲区，反复尝试直至成功。

示例

本节未完成
原因：暂无示例

参阅

vprintfvfprintfvsprintfvsnprintf (C++11) | 使用可变实参列表 打印有格式输出到 stdout、文件流或缓冲区 (函数)
wprintffwprintfswprintf | 打印有格式宽字符输出到 stdout、文件流或缓冲区 (函数)


std::vwscanf, std::vfwscanf, std::vswscanf

< cpp‎ | io‎ | c
定义于头文件 <cwchar> |  |
int vwscanf( const wchar_t* format, va_list vlist ); | (1) | (C++11 起)
int vfwscanf( std::FILE * stream, const wchar_t* format, va_list vlist ); | (2) | (C++11 起)
int vswscanf( const wchar_t* buffer, const wchar_t* format, va_list vlist ); | (3) | (C++11 起)

从各种源读取数据，按照 format 转译，并存储结果于 vlist 所定义的位置。

1) 从 stdin 读取数据
2) 从文件流 stream 读取数据
3) 从空终止宽字符串 buffer 读取数据

参数

stream - 读取数据来源的输入文件流
buffer - 指向作为读取数据来源的空终止宽字符串的指针
format - 指向指定如何读取输入的空终止宽字符串的指针。

格式字符串由下列内容组成

  • 非空白宽字符，除了 % ：每个格式字符串中的这种字符处理来自输入流的准确同一字符，或若它与流的下个字符比较不相等则导致函数失败。
  • 空白符：任何格式字符串中的单个空白符处理所有来自输入的可用连续空白符（如同通过于循环中调用 iswspace 确定）。注意格式字符串中 "\n" 、 " " 、 "\t\t" 或其他空白无区别。
  • 转换说明：每个转换说明拥有下列格式：
  • 引入用 % 字符
  • (可选)赋值抑制字符 * 。若存在此选项，则此函数不将结果赋值给任何接收用参数。
  • (可选)指定最大域宽的整数数字（大于零），即函数进行在当前转换说明所指定的转换时，允许处理的最大字符数。注意若不提供宽度，则 %s 和 %[ 可能导致缓冲区溢出。
  • (可选)指定接收参数大小的长度修饰符，即实际目标类型。这影响转换准确性和溢出规则。默认目标类型对每个转换类型不同（见下表）。
  • 转换格式说明符

下列格式说明符可用：

转换
说明符 		解释 参数类型
长度修饰符 →
 hh

(C++11)

 h （无） l ll

(C++11)

 j

(C++11)

 z

(C++11)

 t

(C++11)

 L
% 匹配字面 % 。 N/A N/A N/A N/A N/A N/A N/A N/A N/A
c
匹配一个字符或字符的序列

若使用了宽度说明符，则匹配准确的宽度个宽字符（该参数必须是指向有充足空间的数组的指针）。不同于 %s 和 %[ ，它不会在数组后附加空字符。

 N/A N/A
char*
wchar_t*
 N/A N/A N/A N/A N/A
s
匹配非空白字符的序列（一个字符串）

若使用宽度说明符，则至多匹配宽度个字符，或匹配到首个提前出现的空白符前。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
[集合]
匹配一个来自 集合 的字符的非空字符序列。

若集合的首字符是 ^ ，则匹配所有不在集合中的字符。若集合以 ] 或 ^] 开始，则 ] 字符亦被包含入集合。在扫描集合的非最初位置的字符 - 是否可以指示范围，如 [0-9] ，是实现定义的。若使用宽度说明符，则最多匹配到宽度。总是在匹配的字符后存储一个空字符（故参数数组必须有至少宽度 +1 个字符的空间）。
d
匹配一个十进制整数。

该数的格式同 wcstol() 以值 10 为 base 时所期望者
signed char* 或 unsigned char*
signed short* 或 unsigned short*
signed int* 或 unsigned int*
signed long* 或 unsigned long*
signed long long* 或 unsigned long long*
intmax_t* 或 uintmax_t*
size_t*
ptrdiff_t*
 N/A
i
匹配一个整数。

该数的格式同 wcstol() 以值 ​0​ 为 base 时所期望者（基底以首个分析的字符确定）
u
匹配一个无符号十进制整数。

该数的格式同 wcstoul() 以值 10 为 base 参数时所期望者。
o
匹配一个无符号八进制数。

该数的格式同 wcstoul() 以值 8 为 base 参数时所期望者。
x, X
匹配一个无符号十六进制整数。

该数的格式同 wcstoul() 以值 16 为 base 参数时所期望者。
n
返回迄今读取的字符数。

不消耗输出。不增加赋值计数。若此说明符拥有赋值抑制运算符，则行为未定义。
a, A(C++11)
e, E
f, F
g, G
匹配一个浮点数。

该数的格式同 wcstof() 所期望者。

 N/A N/A
float*
double*
 N/A N/A N/A N/A
long double*
p
匹配定义一个指针的实现定义的字符序列。

printf 系列函数应该用 %p 格式说明符产生同样的序列。

 N/A N/A
void**
 N/A N/A N/A N/A N/A N/A

对于每个异于 n 的转换说明符，不超过任何指定域宽，且要么是转换说明符所准确期待，要么是其所期待的前缀的最长输入字符序列，即是从流中消耗的内容。此消耗序列后的首个字符若存在，则保持未读取。若被消耗序列长度为零，或被消耗序列不能转换成上面所指定的项目，则发生匹配失败，除非遇到文件尾、编码错误，或阻止从流输入的读取错误，此情况下此为输入失败。

所有异于 [ 、 c 和 n 的转换说明符，在尝试分析输入前消耗并舍弃所有前导空白字符（如同以调用 iswspace 来确定）。这些被消耗的字符不计入指定的最大域宽。

若不使用长度说明符 l ，则转换说明符 c 、 s 和 [ 进行宽到到多字节字符转换，如同在转换首字符前，通过用初始化到零的 mbstate_t 对象调用 wcrtomb() 。

转换说明符 s 与 [ 始终在匹配字符之后存储一个空字符。目标数组的大小必须至少比指定域宽大一。

定宽整数类型（ int8_t 等）的正确的转换说明定义于头文件 <cinttypes> （虽然 SCNdMAX 、 SCNuMAX 等就是 %jd 、 %ju 等的别名）。

在每个转换说明符后有一个序列点；这允许存储多个域到同一“池”变量中。

在分析以无数字指数为结尾的不完整浮点值，如以转换说明符 %f 分析 "100er" 时，消耗序列 "100e" （可能为合法浮点数的最长前缀），并导致匹配错误（被消耗序列不能转换成浮点数），而留下 "r" 。某些既存实现不遵守此规则并回滚，通过消耗 "100" 而留下 "er" ，例如 glibc 漏洞 1765 。
vlist - 含有接收参数的可变参数列表

返回值

成功读取的参数数量，或若出现失败则为 EOF 。

示例

本节未完成
原因：暂无示例

参阅

wscanffwscanfswscanf
 从 stdin、文件流或缓冲区读取有格式宽字符输入
(函数)


std::cerr, std::wcerr

< cpp‎ | io
定义于头文件 <iostream> |
extern std::ostream cerr; | (1)
extern std::wostream wcerr; | (2)

全局对象 std::cerr 和 std::wcerr 控制到实现定义类型（分别导出自 std::streambuf 和 std::wstreambuf ）的流缓冲，与标准 C 错误输出流 stderr 关联。

保证这些对象在构造首个 std::ios_base::Init 类型对象之前或期间得到初始化，而且可用于带有序初始化的静态对象的构造函数和析构函数（只要在定义对象前包含 <iostream> ）。

除非发出 sync_with_stdio(false) ，有格式和无格式输出从多个线程访问这些对象是安全的。

一旦初始化，则 (std::cerr.flags() & unitbuf) != 0 （ wcerr 也一样），这表示任何发送给这些流对象的输出都被立即冲入到 OS （通过 std::basic_ostream::sentry 的析构函数）。

另外， std::cerr.tie() 返回 & std::cout （对 wcerr 和 wcout 相同），这表示任何 std::cerr 上的输出首先执行 std::cout.flush() （通过 std::basic_ostream::sentry 的构造函数）。(C++11 起)

注解

名称中的 'c' 指代“字符”（ stroustrup.com FAQ ）； cerr 表示“字符错误（流）”而 wcerr 表示“宽字符错误（流）”。

示例

通过 cerr 输出到 stderr ，冲入 cout 上的待处理输出，而通过 clog 输出到 stderr 不会。

#include <thread>
#include <iostream>
#include <chrono>
void f()
{
    std::cout << "Output from thread...";
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "...thread calls flush()" << std::endl;
}

int main()
{
    std::thread t1(f);
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::clog << "This output from main is not tie()'d to cout\n";
    std::cerr << "This output is tie()'d to cout\n";
    t1.join();
}

输出：

This output from main is not tie()'d to cout
Output from thread...This output is tie()'d to cout
...thread calls flush()

参阅

Init | 初始化标准流对象 (std::ios_base 的公开成员类)
clogwclog | 写入到标准 C 错误流 stderr (全局对象)
coutwcout | 写入到标准 C 输出流 stdout (全局对象)
stdinstdoutstderr | 与输入流关联到 FILE* 类型表达式 与输出流关联的 FILE* 类型表达式 与错误输出流关联的 FILE* 类型表达式 (宏常量)


std::cin, std::wcin

< cpp‎ | io
定义于头文件 <iostream> |
extern std::istream cin; | (1)
extern std::wistream wcin; | (2)

全局对象 std::cin 和 std::wcin 控制来自实现定义类型（导出自 std::streambuf ）的流缓冲区的输入，与标准 C 输入流 stdin 关联。

保证在首次构造 std::ios_base::Init 前或期间初始化这些对象，且它们可用于拥有有序初始化的静态对象的构造及析构函数（只要在定义该对象前包含 <iostream> ）。

如果不使用 sync_with_stdio(false)， 则从多个线程访问这些对象，进行有格式和无格式输入是安全的。

一旦构造 std::cin ， std::cin.tie() 就返回 & std::cout ，类似地 std::wcin.tie() 返回 & std::wcout 。这表示若有任何字符正在等待输出，则任何 std::cin 上的格式化输入操作会强制调用 std::cout.flush() 。

注解

名称中的 'c' 指代“character”（ stroustrup.com FAQ ）； cin 表示“字符输入”而 wcin 表示“宽字符输入”。

示例

#include <iostream>
struct Foo {
    int n;
    Foo() {
       std::cout << "Enter n: "; // 不需要冲入
       std::cin >> n;
    }
};
Foo f; // static object
int main()
{
    std::cout << "f.n is " << f.n << '\n';
}

输出：

Enter n: 10
f.n is 10

参阅

Init | 初始化标准流对象 (std::ios_base 的公开成员类)
coutwcout | 写入到标准 C 输出流 stdout (全局对象)
stdinstdoutstderr | 与输入流关联到 FILE* 类型表达式 与输出流关联的 FILE* 类型表达式 与错误输出流关联的 FILE* 类型表达式 (宏常量)


std::clog, std::wclog

< cpp‎ | io
定义于头文件 <iostream> |
extern std::ostream clog; | (1)
extern std::wostream wclog; | (2)

全局对象 std::clog 和 std::wclog 控制实现定义类型（导出自 std::streambuf ）的流缓冲，与标准 C 输出流 stderr 关联，但不同于 std::cerr/std::wcerr ，不自动冲入这些流，且不自动与 cout tie() 。

保证这些对象在构造首个 std::ios_base::Init 类型对象之前或期间得到初始化，而且可用于带有序初始化的静态对象的构造函数和析构函数（只要在定义对象前包含 <iostream> ）。

除非发出 sync_with_stdio(false) ，有格式和无格式输出从多个线程访问这些对象是安全的。

注解

名称中的 'c' 指代“字符”（ stroustrup.com FAQ ）； clog 表示“字符日志”而 wclog 表示“宽字符日志”。

示例

#include <iostream>

struct Foo {
    int n;
    Foo() {
       std::clog << "static constructor\n";
    }
    ~Foo() {
       std::clog << "static destructor\n";
    }
};

Foo f; // 静态对象

int main()
{
    std::clog << "main function\n";
}

输出：

static constructor
main function
static destructor

参阅

Init | 初始化标准流对象 (std::ios_base 的公开成员类)
cerrwcerr | 写入到标准 C 错误流 stderr， 无缓冲 (全局对象)
coutwcout | 写入到标准 C 输出流 stdout (全局对象)
stdinstdoutstderr | 与输入流关联到 FILE* 类型表达式 与输出流关联的 FILE* 类型表达式 与错误输出流关联的 FILE* 类型表达式 (宏常量)


std::cout, std::wcout

< cpp‎ | io
定义于头文件 <iostream> |
extern std::ostream cout; | (1)
extern std::wostream wcout; | (2)

全局对象 std::cout 和 std::wcout 控制到实现定义类型流缓冲（导出自 std::streambuf ）的输出，它与标准 C 输出流 stdout 关联。

保证这些对象在首次构造 std::ios_base::Init 类型对象期间或之前初始化，并可用于拥有有序初始化的静态对象的构造函数和析构函数（只要在定义对象前包含 <iostream> ）。

除非发出 sync_with_stdio(false) ，否则从多个线程为有格式和无格式输出同时访问这些对象是安全的。

一旦初始化，则 std::cout 被 tie() 到 std::cin 而 std::wcout 被 tie() 到 std::wcin ，这表示任何 std::cin 上的输入操作执行 std::cout.flush() （通过 std::basic_istream::sentry 构造函数）。

一旦初始化，则 std::cout 亦被 tie() 到 std::cerr 而 std::wcout 被 tie() 到 std::wcerr ，这表示任何 std::cerr 上的输入操作执行 std::cout.flush() （通过 std::basic_istream::sentry 构造函数）。(C++11 起)

注解

名称中的 'c' 指代“字符”（ stroustrup.com FAQ ）； cout 表示“字符输出”而 wcout 表示“宽字符输出”。

示例

#include <iostream>
struct Foo {
    int n;
    Foo() {
       std::cout << "static constructor\n";
    }
    ~Foo() {
       std::cout << "static destructor\n";
    }
};
Foo f; // 静态对象
int main()
{
    std::cout << "main function\n";
}

输出：

static constructor
main function
static destructor

参阅

Init | 初始化标准流对象 (std::ios_base 的公开成员类)
cerrwcerr | 写入到标准 C 错误流 stderr， 无缓冲 (全局对象)
clogwclog | 写入到标准 C 错误流 stderr (全局对象)
stdinstdoutstderr | 与输入流关联到 FILE* 类型表达式 与输出流关联的 FILE* 类型表达式 与错误输出流关联的 FILE* 类型表达式 (宏常量)


std::fpos

< cpp‎ | io
定义于头文件 <ios>
template< class State >
class fpos;

类模板 std::fpos 的特化标识流或文件中的绝对位置。每个 fpos 类型对象保有流中的字节位置（常为 std::streamoff 类型的私有成员）和当前迁移状态， State 类型值（常为 std::mbstate_t ）。

提供下列 std::fpos< std::mbstate_t > 的 typedef 名（尽管它们在标准中拼写方式不同，它们代表同一类型）：

定义于头文件 <iosfwd>
类型 | 定义
streampos | std::fpos< std::char_traits <char>::state_type>
wstreampos | std::fpos< std::char_traits <wchar_t>::state_type>
u8streampos (C++20) | std::fpos< std::char_traits <char8_t>::state_type>
u16streampos (C++11) | std::fpos< std::char_traits <char16_t>::state_type>
u32streampos (C++11) | std::fpos< std::char_traits <char32_t>::state_type>

fpos 的所有特化都符合可默认构造 (DefaultConstructible) 、可复制构造 (CopyConstructible) 、可复制赋值 (CopyAssignable) 、可析构 (Destructible) 和可相等比较 (EqualityComparable) 要求。

若 State 可平凡复制构造，则 fpos 拥有平凡默认构造函数。 若 State 可平凡复制赋值，则 fpos 拥有平凡复制赋值运算符。 若 State 可平凡析构，则 fpos 拥有平凡析构函数。

模板形参

State - 表示迁移状态的类型
类型要求
-
State 必须满足可析构 (Destructible) 、 可复制赋值 (CopyAssignable) 、 可复制构造 (CopyConstructible) 和 可默认构造 (DefaultConstructible) 的要求。

成员函数

state
 获取/设置迁移状态的值
(公开成员函数)

另外，提供支持下列操作的成员和非成员函数：

  • 默认构造函数，存储零偏移并值初始化状态对象。
  • 非 explicit 的构造函数，接受一个（可为 const 的） std::streamoff 类型参数，存储其偏移并值初始化状态对象。此构造函数必须亦接受特殊值 std::streamoff (-1) ：某些流操作返回以此方式构造的 std::fpos ，以指示错误。
  • 从（可为 const 的） fpos 到 std::streamoff 的显式转换。结果是存储的偏移。
  • 比较二个（可为 const 的） std::fpos 类型，返回可转换为 bool 的类型的 operator== 和 operator!= 。 p != q 等价于 !(p == q) 。
  • operator+ 与 operator- ，使得对于（可为 const 的） fpos<State> 对象 p 和（可为 const 的） std::streamoff 对象 o
  • p + o 拥有 fpos<State> 类型，而存储的偏移为将 o 加到 p 的结果
  • o + p 拥有可转换为 fpos<State> 的类型，而转换结果等于 p + o
  • p - o 拥有 fpos<State> 类型，而存储的偏移为从 p 的偏移减去 o 的结果
  • operator+= 与 operator-= ，能接受一个（可为 const 的） std::streamoff 并分别对存储的偏移加/减之。
  • operator- ，能对二个（可为 const 的） std::fpos 对象相减，产生 std::streamoff ，使得对于二个这种对象 p 与 q 有 p == q + (p - q) 。

注解

一些 I/O 流成员函数返回并操纵成员 typedef pos_type 类型对象。对于流，这些成员 typedef 由模板形参 Traits 提供，默认为 std::char_traits ，它定义其 pos_type 为 std::fpos 的特化。 Traits::pos_type 不是 std::fpos< std::mbstate_t > （别名为 std::streampos、 std::wstreampos 等等）时， I/O 流库的行为是实现定义的。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 57 | C++98 | streampos 与 wstreampos 被矛盾地在要求相同时允许不同 | 澄清为相同
P0759R1 | C++98 | 规定不清晰且不完整 | 已整理
P1148R0 | C++11 | 不明确 u16streampos 和 u32streampos 的定义是什么以及在哪个头文件 | 使之明确

参阅

streamoff | 表示相对的文件/流位置（距 fpos 的偏移），足以表示任何文件大小 (typedef)
tellp | 返回输出位置指示器 (std::basic_ostream<CharT,Traits> 的公开成员函数)
seekp | 设置输出位置指示器 (std::basic_ostream<CharT,Traits> 的公开成员函数)
fgetpos | 获取文件位置指示器 (函数)


std::fpos<State>::state

< cpp‎ | io‎ | fpos
State state() const; | (1)
void state( State st ); | (2)

管理文件位置状态。

1) 返回文件位置状态的值。
2) 以 st 的值替换文件位置状态。

对于 std::fpos 用于标准库的特化， State 始终为 std::mbstate_t 。

参数

st - 状态的新值

返回值

1) fpos 状态的当前值
2) （无）

示例

#include <iostream>
#include <sstream>
#include <cwchar>

int main()
{
    std::istringstream s("test");
    std::mbstate_t st = s.tellg().state();

    if(std::mbsinit(&st))
        std::cout << "The stream is in the initial shift state\n";
}

输出：

The stream is in the initial shift state

参阅

mbstate_t
 迭代多字节字符串所需的转换状态信息
(类)


std::io_errc

< cpp‎ | io
定义于头文件 <ios> |
enum class io_errc; | (C++11 起)

带作用域枚举 std::io_errc 定义 I/O 流报告于 std::ios_base::failure 异常对象的错误码。只要求一个错误码（ std::io_errc::stream ），虽然实现可以定义额外的错误码。因为提供了 std::is_error_code_enum 的适当特化，故 std::io_errc 类型的值能隐式转换成 std::error_code 。

成员常量

枚举常量 | 值
stream | 1

非成员函数

make_error_code(std::io_errc) (C++11) | 构造一个 iostream 错误码 (函数)
make_error_condition(std::io_errc) (C++11) | 构造一个 iostream error_condition (函数)

帮助类

is_error_code_enum<std::io_errc>
(C++11)
 扩充类型特征 std::is_error_code_enum 以鉴别 iostream 错误码
(类模板特化)

示例

#include <iostream>
#include <fstream>
int main()
{
    std::ifstream f("doesn't exist");
    try {
        f.exceptions(f.failbit);
    } catch (const std::ios_base::failure& e) {
        std::cout << "Caught an ios_base::failure.\n";
        if(e.code() == std::io_errc::stream)
            std::cout << "The error code is std::io_errc::stream\n";
    }
}

输出：

Caught an ios_base::failure.
The error code is std::io_errc::stream

参阅

error_code (C++11) | 保有依赖于平台的错误码 (类)
error_condition (C++11) | 保有可移植的错误码 (类)
failure | 流异常 (std::ios_base 的公开成员类)


std::is_error_code_enum<std::io_errc>

< cpp‎ | io‎ | io errc
定义于头文件 <ios> |
template< > struct is_error_code_enum< std::io_errc > : public std::true_type { }; | (C++11 起)

此 std::is_error_code_enum 特化指示其他库组件 std::io_errc 的值是保有错误码的枚举，这使得它们可以隐式转换到并赋值给 std::error_code 类型的对象。

继承自 std::integral_constant

成员常量

value
[静态]
 true
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

e.code() 与 std::io_errc::stream 的比较能编译，因为 std::is_error_code_enum < std::io_errc >::value == true

#include <iostream>
#include <fstream>
int main()
{
    std::ifstream f("doesn't exist");
    try {
        f.exceptions(f.failbit);
    } catch (const std::ios_base::failure& e) {
        std::cout << "Caught an ios_base::failure.\n";
        if(e.code() == std::io_errc::stream)
            std::cout << "The error code is std::io_errc::stream\n";
    }
}

输出：

Caught an ios_base::failure.
The error code is std::io_errc::stream

参阅

is_error_code_enum (C++11) | 鉴别类是否可作为 error_code 枚举 (类模板)
error_code (C++11) | 保有依赖于平台的错误码 (类)
io_errc (C++11) | IO 流的错误码 (枚举)


std::make_error_code(std::io_errc)

< cpp‎ | io‎ | io errc
定义于头文件 <ios> |
std::error_code make_error_code( std::io_errc e ) noexcept; | (C++11 起)

从 std::io_errc 类型的值构造一个 std::error_code 对象，如同通过 return std::error_code (static_cast<int>(e), std::iostream_category ()) 。给定 std::io_errc 参数时，此函数为 std::error_code 的构造函数所调用。

参数

e - 错误码编号

返回值

std::error_code 类型的值，保有来自 e 的错误码编号，关联到错误类别 "iostream" 。

示例

#include <iostream>
#include <system_error>
int main()
{
    std::error_code ec = std::make_error_code(std::io_errc::stream);
    std::cout << "Error code from io_errc::stream has category "
              << ec.category().name() << '\n';
}

输出：

Error code from io_errc::stream has category iostream

参阅

error_code (C++11) | 保有依赖于平台的错误码 (类)
io_errc (C++11) | IO 流的错误码 (枚举)


std::make_error_condition(std::io_errc)

< cpp‎ | io‎ | io errc
定义于头文件 <ios> |
std::error_condition make_error_condition( std::io_errc e ) noexcept; | (C++11 起)

从 std::io_errc 类型的值构造一个 std::error_condition 对象，如同通过 return std::error_condition (static_cast<int>(e), std::iostream_category ()) 。

参数

e - 错误码编号

返回值

std::error_condition 类型的值，保有来自 e 的错误码，关联到错误类别 "iostream" 。

示例

#include <iostream>
#include <system_error>
#include <string>

int main()
{
    std::error_condition ec  = std::make_error_condition(std::io_errc::stream);
    std::cout << "error condition for io_errc::stream has value " << ec.value()
              << "\nand message \"" << ec.message() << "\"\n";
}

输出：

error condition for io_errc::stream has value 1
and message "unspecified iostream_category error"

参阅

error_condition (C++11) | 保有可移植的错误码 (类)
io_errc (C++11) | IO 流的错误码 (枚举)


std::ios_base

< cpp‎ | io
定义于头文件 <ios>
class ios_base;

类 ios_base 是作为所有 I/O 流类的基类工作的多用途类。它维护数种数据：

1) 状态信息：流状态标志；
2) 控制信息：控制输入和输出序列格式化和感染的本地环境的标志；
3) 私有存储：允许 long 和 void* 成员的有下标可扩展数据结构，它可以实现为二个任意长度的数组，或二元素结构体的单个数组，或另一容器；
4) 回调：从 imbue() 、 copyfmt() 和 ~ios_base() 调用的任意数量用户定义函数。

典型实现保有对应下列 fmtflags 、 iostate 、 openmode 及 seekdir 所有值的成员常量，维护当前精度、宽度、格式化标志、异常掩码、缓冲区错误状态、保有回调的可调大小容器、当前感染的 locale 、私有存储的成员变量及 xalloc() 所用的静态整数变量。

成员函数

(构造函数)
 构造对象
(受保护成员函数)
(析构函数)
[虚]
 析构对象
(虚公开成员函数)
格式化
flags
 管理格式标志
(公开成员函数)
setf
 设置特定格式标志
(公开成员函数)
unsetf
 清除特定格式的标志
(公开成员函数)
precision
 管理浮点操作的精度
(公开成员函数)
width
 管理域的宽度
(公开成员函数)
本地环境
imbue
 设置本地环境
(公开成员函数)
getloc
 返回当前本地环境
(公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(公开成员函数)
杂项
register_callback
 注册事件回调函数
(公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(公开静态成员函数)

成员类
failure
 流异常
(公开成员类)
Init
 初始化标准流对象
(公开成员类)

成员类型与常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)
弃用的成员类型
类型 | 解释
io_state(弃用) | 可以像 iostate 一样使用的整数类型
open_mode(弃用) | 可以像 openmode 一样使用的整数类型
seek_dir(弃用) | 可以像 seekdir 一样使用的整数类型
streamoff(弃用) | 可以像 off_type 一样使用的未指定类型，不必是 std::streamoff
streampos(弃用) | 可以像 pos_type 一样使用的未指定类型，不必是 std::streampos
(C++17 前)


std::ios_base::Init

< cpp‎ | io‎ | ios base
class Init;

此类用以确保默认 C++ 流（ std::cin 、 std::cout 等）被正确初始化及析构。此类跟踪它被创建的实例数量，在构造首个实例时创建并初始化 C++ 流，并且在析构最后实例时冲入输出流。

头文件 <iostream> 表现如同它定义（直接或间接）一个有静态存储期的 std::ios_base::Init 实例：这使得在拥有有序初始化的静态对象的构造函数及析构函数中，访问标准 I/O 流是安全的（只要在翻译单元中，定义该对象前包含 #include <iostream> ）。

成员函数

(构造函数) | 若 *this 是首次创建的实例，则初始化默认 C++ 流 (公开成员函数)
(析构函数) | 若 *this 是被最后销毁的实例，则冲入默认 C++ 流 (公开成员函数)

参阅

cinwcin | 从标准 C 输入流 stdin 中读取 (全局对象)
coutwcout | 写入到标准 C 输出流 stdout (全局对象)
cerrwcerr | 写入到标准 C 错误流 stderr， 无缓冲 (全局对象)
clogwclog | 写入到标准 C 错误流 stderr (全局对象)


std::ios_base::event

< cpp‎ | io‎ | ios base
enum event {erase_event, imbue_event, copyfmt_event};

指定在特殊事件时传递给 register_callback() 所注册函数的事件类型。定义下列常量：

常量 | 解释
erase_event | 在 ~ios_base() 或 basic_ios::copyfmt() （发生成员复制前）时发行
imbue_event | 在 imbue() 时发行
copyfmt_event | 在 basic_ios::copyfmt() （发生成员复制后，但在复制异常设置前）发行

示例

本节未完成
原因：暂无示例


std::ios_base::event_callback

< cpp‎ | io‎ | ios base
typedef void (*event_callback)(event type, ios_base& ios, int index);

能用 register_callback() 注册以在特殊事件时调用的函数回调类型。

type 是 ios_base::event 类型值，指示将调用此回调的事件类型。

ios 指代调用回调所用的流对象： std::ios_base 和 std::basic_ios 的成员函数调用回调时，传递 *this 为参数。

index 是注册函数时传递给 register_callback() 的用户提供值。

参阅

copyfmt | 复制格式化信息 (std::basic_ios<CharT,Traits> 的公开成员函数)
imbue | 设置本地环境 (公开成员函数)
(析构函数) [虚] | 析构对象 (虚公开成员函数)
register_callback | 注册事件回调函数 (公开成员函数)


std::ios_base::failure

< cpp‎ | io‎ | ios base
定义于头文件 <ios>
class failure;

类 std::ios_base::failure 定义输入/输出库中的函数在失败时抛出的异常对象。

std::ios_base::failure 可以定义为 std::ios_base 的成员类，或拥有等价功能的另一个类的同义词（ typedef ）。

 (C++17 起)
继承图 | (C++11 前)
继承图 | (C++11 起)

成员函数

(构造函数) | 构造拥有指定消息的新 failure 对象 (公开成员函数)
operator= | 替换 failure 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::ios_base::failure::failure

(1)
explicit failure( const std::string & message );
 (C++11 前)
explicit failure( const std::string & message,
const std::error_code & ec = std::io_errc::stream );
 (C++11 起)
explicit failure( const char* message,
const std::error_code & ec = std::io_errc::stream );
 (2) (C++11 起)
(3)
failure( const failure& other );
 (C++11 前)
failure( const failure& other ) noexcept;
 (C++11 起)
1-2) 以 message 为解释字符串构造异常对象，能在之后用 what() 取得解释字符串。用 ec 鉴别特定的失败理由。 (C++11 起)
3) 复制构造函数。以 other 的内容初始化内容。若 *this 与 other 均拥有动态类型 std::ios_base::failure 则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

message | - | 解释性字符串
ec | - | 鉴别特定失败理由的错误码
other | - | 要复制的另一 failure

注解

因为不容许复制 std::ios_base::failure 抛出异常，通常将此消息在内部存储为分离分配的引用计数字符串。这也是构造函数不接收 std::string&& 参数的理由：无论如何它必须复制内容。

std::ios_base::failure::operator=

failure& operator=( const failure& other ); | (C++11 前)
failure& operator=( const failure& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::ios_base::failure 则赋值后 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 用以赋值的另一异常对象

返回值

*this

std::ios_base::failure::what

virtual const char* what() const throw(); | (C++11 前)
virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::system_error

成员函数

code | 返回错误码 (std::system_error 的公开成员函数)
what [虚] | 返回解释性字符串 (std::system_error 的虚公开成员函数)

继承自 std::runtime_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

示例

#include <iostream>
#include <fstream>
int main()
{
    std::ifstream f("doesn't exist");
    try {
        f.exceptions(f.failbit);
    } catch (const std::ios_base::failure& e)
    {
        std::cout << "Caught an ios_base::failure.\n"
                  << "Explanatory string: " << e.what() << '\n'
                  << "Error code: " << e.code() << '\n';
    }
}

输出：

Caught an ios_base::failure.
Explanatory string: ios_base::clear: unspecified iostream_category error
Error code: iostream:1

参阅

io_errc
(C++11)
 IO 流的错误码
(枚举)


std::ios_base::flags

< cpp‎ | io‎ | ios base
fmtflags flags() const; | (1)
fmtflags flags( fmtflags flags ); | (2)

管理格式化标志。

1) 返回当前格式化设置。

2) 以给定者替换当前设置。

参数

flags - 新格式化设置。它能是下列内容的组合：
常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

返回值

调用函数前的格式化标志

示例

本节未完成
原因：暂无示例

参阅

setf | 设置特定格式标志 (公开成员函数)
unsetf | 清除特定格式的标志 (公开成员函数)


std::ios_base::fmtflags

< cpp‎ | io‎ | ios base
typedef /*implementation defined*/ fmtflags;
static constexpr fmtflags dec = /*implementation defined*/

static constexpr fmtflags oct = /*implementation defined*/
static constexpr fmtflags hex = /*implementation defined*/

static constexpr fmtflags basefield = dec | oct | hex;
static constexpr fmtflags left = /*implementation defined*/

static constexpr fmtflags right = /*implementation defined*/
static constexpr fmtflags internal = /*implementation defined*/

static constexpr fmtflags adjustfield = left | right | internal;
static constexpr fmtflags scientific = /*implementation defined*/

static constexpr fmtflags fixed = /*implementation defined*/

static constexpr fmtflags floatfield = scientific | fixed;
static constexpr fmtflags boolalpha = /*implementation defined*/

static constexpr fmtflags showbase = /*implementation defined*/
static constexpr fmtflags showpoint = /*implementation defined*/
static constexpr fmtflags showpos = /*implementation defined*/
static constexpr fmtflags skipws = /*implementation defined*/
static constexpr fmtflags unitbuf = /*implementation defined*/

static constexpr fmtflags uppercase = /*implementation defined*/

指定可用的格式化标志。它是位掩码类型 (BitmaskType) 。定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

示例

下列示例展示打印同一结果的数种不同方式。

#include <iostream>

int main()
{
    int num = 150;

    // 以 fmtflags 为类成员常量：
    std::cout.setf(std::ios_base::hex, std::ios_base::basefield);
    std::cout.setf(std::ios_base::showbase);
    std::cout << num << '\n';

    // 以 fmtflags 为继承的类成员常量：
    std::cout.setf (std::ios::hex , std::ios::basefield);
    std::cout.setf (std::ios::showbase);
    std::cout << num << '\n';

    // 以 fmtflags 为对象成员常量：
    std::cout.setf(std::cout.hex, std::cout.basefield);
    std::cout.setf(std::cout.showbase);
    std::cout << num << '\n';

    // 以 fmtflags 为类型：
    std::ios_base::fmtflags ff;
    ff = std::cout.flags();
    ff &= ~std::cout.basefield;   // 解除设置 basefield 位
    ff |= std::cout.hex;          // 设置 hex
    ff |= std::cout.showbase;     // 设置 showbase
    std::cout.flags(ff);
    std::cout << num << '\n';

    // 不使用 fmtflags ，但使用操纵符：
    std::cout << std::hex << std::showbase << num << '\n';
}

输出：

0x96
0x96
0x96
0x96
0x96

参阅

flags | 管理格式标志 (公开成员函数)
setf | 设置特定格式标志 (公开成员函数)
unsetf | 清除特定格式的标志 (公开成员函数)
setbase | 更改用于整数 I/O 的基数 (函数)
setfill | 更改填充字符 (函数模板)
fixedscientifichexfloatdefaultfloat (C++11)(C++11) | 更改用于浮点 I/O 的格式化 (函数)
showbasenoshowbase | 控制是否使用前缀指示数值基数 (函数)
boolalphanoboolalpha | 在布尔值的文本和数值表示间切换 (函数)
showposnoshowpos | 控制是否将 + 号与非负数一同使用 (函数)
showpointnoshowpoint | 控制浮点表示是否始终包含小数点 (函数)
unitbufnounitbuf | 控制是否每次操作后冲洗输出 (函数)
skipwsnoskipws | 控制是否跳过输入上的前导空白符 (函数)
uppercasenouppercase | 控制一些输出操作是否使用大写字母 (函数)


std::ios_base::getloc

< cpp‎ | io‎ | ios base
std::locale getloc() const;

返回当前与流关联的 locale 。

参数

（无）

返回值

与流关联的 locale 对象。

示例

#include <iostream>
#include <ctime>
#include <iomanip>
#include <codecvt>

int main()
{
    std::wbuffer_convert<std::codecvt_utf8<wchar_t>> conv(std::cout.rdbuf());
    std::wostream out(&conv);

    out.imbue(std::locale(out.getloc(),
                          new std::time_put_byname<wchar_t>("ja_JP")));

    std::time_t t = std::time(NULL);
    out << std::put_time(std::localtime(&t), L"%A %c") << '\n';
}

输出：

土曜日 2013年09月14日 11時31分15秒

参阅

imbue
 设置本地环境
(公开成员函数)


std::ios_base::imbue

< cpp‎ | io‎ | ios base
std::locale imbue( const std::locale & loc );

设置流的关联本地环境为给定值。在返回前，以 imbue_event 为参数调用 register_callback() 所注册的每个函数。

参数

loc - 要关联到流的新 locale

返回值

操作前与流关联的 locale 对象。

示例

本节未完成
原因：暂无示例

参阅

getloc
 返回当前本地环境
(公开成员函数)


std::ios_base::ios_base

< cpp‎ | io‎ | ios base
 | (1)
private: ios_base( const ios_base& ); |  | (C++11 前)
public: ios_base( const ios_base& ) = delete; |  | (C++11 起)
protected: ios_base(); | (2)

1) 复制构造函数被删除：流不可复制

2) 默认构造函数受保护：只有导出类可构造 std::ios_base 。构造后内部状态未定义。导出类必须在首次使用或析构函数前调用 basic_ios::init() 完成初始化；否则行为未定义。

注意

同样的情况应用于 I/O 层级中的下个类 std::basic_ios 的构造函数。进一步导出的类（ std::istream 与 std::ostream ）始终以具体的 streambuffer 构造，并可能多于一次调用 basic_ios::init() ，以完成其虚基类的初始化。


std::ios_base::iostate

< cpp‎ | io‎ | ios base
typedef /*implementation defined*/ iostate;
static constexpr iostate goodbit = 0;
static constexpr iostate badbit = /*implementation defined*/

static constexpr iostate failbit = /*implementation defined*/

static constexpr iostate eofbit = /*implementation defined*/

指定流状态标志。它是位掩码类型 (BitmaskType) ，定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

eofbit

下列标准库函数设置 eofbit ：

  • string 输入函数 std::getline ，若它以抵达流结尾，而非抵达指定的终止字符完成。
  • basic_istream::operator>> 的数值输入重载，若在 num_get::get 处理的阶段 2 ，读取下个字符时遇到流结尾。取决于分析状态，可能或可能不同时设置 failbit ：例如 int n; istringstream buf("1"); buf >> n; 设置 eofbit ，但不设置 failbit ：成功分析整数 1 并存储之于 n 。另一方面， bool b; istringstream buf("tr"); buf >> boolalpha >> b; 一同设置 eofbit 和 failbit ：无足够的字符完成布尔 true 的分析。
  • operator>>std::basic_istream 的字符释出重载，若在释出字符数量上的限制（若存在）前抵达流结尾。
  • std::get_time I/O 操纵符和任何 std::time_get 分析函数： time_get::get 、 time_get::get_time 、 time_get::get_date 等，若在分析期待的被处理日期/时间值所需的最末字符前抵达流结尾。
  • std::get_money I/O 操纵符和 money_get::get 函数，若在分析期待的被处理货币值所需的最末字符前抵达流结尾。
  • basic_istream::sentry 构造函数，在每个有格式输入函数的起始执行：除非未设置 skipws （例如通过发布 std::noskipws ），否则 sentry 会读取并舍弃前导空白字符。若在此操作中抵达流结尾，则一同设置 eofbit 和 failbit ，并且不发生输入。
  • I/O 操纵符 std::ws ，若它在消耗空白符时抵达流结尾（但不同于有格式输入 sentry ，此情况下它不设置 failbit ）
  • 无格式输入函数 basic_istream::read 、 basic_istream::get 、 basic_istream::peek 和 basic_istream::getline 在抵达流尾时。
  • 舍弃输入函数 basic_istream::ignore ，在抵达指定的分隔字符前抵达流结尾时。
  • 立即输入函数 basic_istream::readsome ，若 basic_streambuf::in_avail 返回 -1

下列函数作为副效应清除 eofbit ：

  • basic_istream::putback
  • basic_istream::unget
  • basic_istream::seekg

注意在几乎所有情况下，若设置 eofbit ，则一同设置 failbit 。

failbit

下列标准库函数设置 failbit ：

  • basic_istream::sentry 构造函数，在每个输入函数起始执行，若流上已设置 eofbit 或 badbit ，或若在消耗前导空白时遇到流结尾。
  • basic_ostream::sentry 构造函数，在每个输出函数起始执行，在实现定义的条件下。
  • operator>>(std::basic_string<>) ，若函数未从输入流释出字符。
  • operator>>(std::complex<>) ，若函数无法释出合法的复数。
  • operator>> 的字符数组和单字符重载，若它们无法释出字符。
  • basic_istream::operator>> 的 streambuf 重载，若 streambuf 参数为空指针或若没有插入字符到 streambuf 。
  • basic_ostream::operator<< 的 streambuf 重载，若函数未插入字符。
  • operator>>(std::bitset<>) ，若函数未从输出流释出字符。
  • std::getline ，若函数未释出字符，或若它要从输入流释出 basic_string::max_size 个字符。
  • basic_istream::operator>> 的数值、指针和布尔输入重载（技术上是它们调用的 num_get::get 的重载），若输入不能分析为合法值，或若分析出的值不适合于目标类型。
  • 时间输入操纵符 std::get_time （技术上是其所调用的 time_get::get ），若输入不能按照给定的格式字符串，无歧义地分析为时间值。
  • 货币输入操纵符 std::get_money （技术上是其所调用的 money_get::get ），若输入不能按照本地环境规则无歧义地分析为货币值。
  • 所有随机数引擎 (RandomNumberEngine) 的释出函数，若遇到错误输入。
  • 所有随机数分布 (RandomNumberDistribution) 的释出函数，若遇到错误输入。
  • 无格式输入函数 basic_istream::get ，若它们无法释出任何字符。
  • basic_istream::getline ，若它未释出字符，若它填充给定的缓冲区而未遇到分隔符，或若提供的缓冲区大小小于 1 。
  • basic_istream::read ，若在能释出所有请求的字符前，输入流上出现文件尾条件。
  • basic_istream::seekg 在失败时。
  • basic_ostream::tellp 在失败时。
  • std::basic_fstream 、 std::basic_ifstream 和 std::basic_ofstream 接收文件名参数的构造函数，若无法打开文件。
  • basic_fstream::open 、 basic_ifstream::open 和 basic_ofstream::open ，若无法打开文件。
  • basic_fstream::close 、 basic_ifstream::close 和 basic_ofstream::close ，若无法关闭文件。

badbit

下列标准库函数设置 badbit ：

  • basic_ostream::put ，若它因任何原因无法插入元素到输出流。
  • basic_ostream::write ，若它因任何原因无法插入元素到输出流。
  • 有格式输出函数 operator<< 、 std::put_money 和 std::put_time ，若它们在完成输出前遇到输出流的结尾。
  • basic_ios::init ，在以对于 rdbuf() 的空指针调用以初始化流时。
  • basic_istream::putback 和 basic_istream::unget ，在以空的 rdbuf() 在流上调用时
  • basic_ostream::operator<<(basic_streambuf*) ，传递空指针为参数时。
  • basic_istream::putback 和 basic_istream::unget ，若

rdbuf()->sputbackc() 或 rdbuf()->sungetc() 返回 traits::eof() 。

  • basic_istream::sync 、 basic_ostream::flush 和 unitbuf 输出流上的每个输出函数，若 rdbuf()->pubsync() 返回 -1 。
  • 每个流 I/O 函数，若任何关联流缓冲的成员函数（如 sbumpc() 、 xsputn() 、 sgetc() 、 overflow() 等）抛出异常。
  • ios_base::iword 和 ios_base::pword 在失败时（例如无法分配内存）。

示例

本节未完成
原因：暂无示例

参阅

下表显示 basic_ios 访问器（ good()、 fail() 等）对于 ios_base::iostate 标志的所有可能组合的值：

ios_base::iostate 标志 |  |  | basic_ios 访问器
eofbit | failbit | badbit | good() | fail() | bad() | eof() | operator bool | operator!
false | false | false | true | false | false | false | true | false
false | false | true | false | true | true | false | false | true
false | true | false | false | true | false | false | false | true
false | true | true | false | true | true | false | false | true
true | false | false | false | false | false | true | true | false
true | false | true | false | true | true | true | false | true
true | true | false | false | true | false | true | false | true
true | true | true | false | true | true | true | false | true
rdstate | 返回状态标志 (std::basic_ios<CharT,Traits> 的公开成员函数)
setstate | 设置状态标志 (std::basic_ios<CharT,Traits> 的公开成员函数)
clear | 修改状态标志 (std::basic_ios<CharT,Traits> 的公开成员函数)


std::ios_base::iword

< cpp‎ | io‎ | ios base
long& iword( int index );

首先，充分地分配或重置私有存储（ long 的动态数组或另一可索引数据结构）以确保 index 是合法下标，然后返回到带下标 index 的私有存储 long 元素。

引用可能被此 ios_base 对象上任何其他操作非法化，包含另一对 iword() 的调用，但维持返回值，使得以相同下标从 iword(index) 读取将产生相同值（直至下次到 copyfmt() 的调用）。值能用于任何目的。必须通过先前的 xalloc() 调用获得元素下标，否则行为未定义。新元素初始化为 0 。

若分配失败，则调用可能抛出 std::ios_base::failure 的 std::basic_ios <>::setstate(badbit) 。

参数

index - 元素的下标值

返回值

到该元素的引用。

异常

设置 badbit 时可能抛出 std::ios_base::failure 。

示例

#include <iostream>
#include <string>

struct Foo {
    static int foo_xalloc;
    std::string data;
    Foo(const std::string& s) : data(s) {}
};

// 分配 Foo 对象所用的 iword 存储
int Foo::foo_xalloc = std::ios_base::xalloc();

// 若 iword 保有 1 则此用户定义 operator<< 打印字符串
std::ostream& operator<<(std::ostream& os, Foo& f)
{
    if(os.iword(Foo::foo_xalloc) == 1)
        return os << std::string(f.data.rbegin(), f.data.rend());
    else
        return os << f.data;
}

// 此 I/O 操纵符在 0 与 1 间翻转存储于 iword 的数
std::ios_base& rev(std::ios_base& os)
{
    os.iword(Foo::foo_xalloc) = !os.iword(Foo::foo_xalloc);
    return os;
}

int main()
{
    Foo f("example");
    std::cout << f << '\n' << rev << f << '\n' << rev << f << '\n';
}

输出：

example
elpmaxe
example

参阅

pword | 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素 (公开成员函数)
xalloc [静态] | 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数 (公开静态成员函数)


std::ios_base::openmode

< cpp‎ | io‎ | ios base
typedef /*implementation defined*/ openmode;
static constexpr openmode app = /*implementation defined*/

static constexpr openmode binary = /*implementation defined*/
static constexpr openmode in = /*implementation defined*/
static constexpr openmode out = /*implementation defined*/
static constexpr openmode trunc = /*implementation defined*/

static constexpr openmode ate = /*implementation defined*/

指定可用的文件打开标志。它是位掩码类型 (BitmaskType) ，下列常量得到定义：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

示例

本节未完成
原因：暂无示例

参阅

open | 打开文件并配置它为关联字符序列 (std::basic_filebuf<CharT,Traits> 的公开成员函数)
(构造函数) | 构造一个 basic_stringbuf 对象 (std::basic_stringbuf<CharT,Traits,Allocator> 的公开成员函数)


std::ios_base::precision

< cpp‎ | io‎ | ios base
streamsize precision() const; | (1)
streamsize precision( streamsize new_precision ); | (2)

管理 std::num_put::do_put 所进行的浮点输出精度（即生成多少数位）。

1) 返回当前精度。
2) 设置精度为给定值。返回先前的精度。

std::basic_ios::init 所建立的默认精度为 6 。

参数

new_precision - 新的精度设置

返回值

调用函数前的精度

示例

#include <iostream>
int main()
{
    const double d = 1.2345678901234;
    std::cout << "The  default precision is " << std::cout.precision() << "\n\n";
    std::cout << "With default precision d is " << d << '\n';
    std::cout.precision(12);
    std::cout << "With high    precision d is " << d << '\n';
}

输出：

The  default precision is 6

With default precision d is 1.23457
With high    precision d is 1.23456789012

参阅

width | 管理域的宽度 (公开成员函数)
setprecision | 更改浮点精度 (函数)


std::ios_base::pword

< cpp‎ | io‎ | ios base
void*& pword( int index );

首先，充分地分配或重置私有存储（ void* 的动态数组或另一可索引数据结构）以确保 index 是合法下标，然后返回到带下标 index 的私有存储 void* 元素。

引用可能被此 ios_base 对象上任何其他操作非法化，包含另一对 pword() 的调用，但维持返回值，使得以相同下标从 pword(index) 读取将产生相同值（直至下次到 copyfmt() 的调用）。值能用于任何目的。元素下标必须由 xalloc() 获得，否则行为未定义。初始化新元素为空指针。

若分配失败，则调用可能抛出 std::ios_base::failure 的 std::basic_ios <>::setstate(badbit) 。

参数

index - 元素的下标值

返回值

到该元素的引用。

异常

设置 badbit 时可能抛出 std::ios_base::failure 。

注解

若存储于 pword 的指针要求管理，则可用 register_callback() 安装按需执行深复制或解分配的处理函数。

示例

将基类 pword 存储用于导出的流对象的运行时类型鉴别。

#include <iostream>

template<class charT, class traits = std::char_traits<charT> >
class mystream : public std::basic_ostream<charT, traits>
{
 public:
    static const int xindex;
    mystream(std::basic_ostream<charT, traits>& ostr) :
        std::basic_ostream<charT, traits>(ostr.rdbuf())
    {
         this->pword(xindex) = this;
    }

    void myfn()
    {
        *this << "[special handling for mystream]";
    }
};

// 每个 mystream 特化从 xalloc() 获得独有的下标
template<class charT, class traits>
const int mystream<charT, traits>::xindex = std::ios_base::xalloc();

// 此 I/O 操纵符将能用于辨识身为 mystream 的 ostream
// 通过查找存储于 pword 的指针
template<class charT, class traits>
std::basic_ostream<charT,traits>& mymanip(std::basic_ostream<charT,traits>& os)
{
 if (os.pword(mystream<charT,traits>::xindex) == &os)
    static_cast<mystream<charT,traits>&>(os).myfn();
 return os;
}

int main()
{
    std::cout << "cout, narrow-character test " << mymanip << '\n';

    mystream<char> myout(std::cout);
    myout << "myout, narrow-character test " << mymanip << '\n';

    std::wcout << "wcout, wide-character test " << mymanip << '\n';

    mystream<wchar_t> mywout(std::wcout);
    mywout << "mywout, wide-character test " << mymanip << '\n';
}

输出：

cout, narrow-character test
myout, narrow-character test [special handling for mystream]
wcout, wide-character test
mywout, wide-character test [special handling for mystream]

参阅

iword | 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素 (公开成员函数)
xalloc [静态] | 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数 (公开静态成员函数)


std::ios_base::register_callback

< cpp‎ | io‎ | ios base
void register_callback( event_callback function, int index );

注册将为 imbue() 、 std::basic_ios::copyfmt() 和 ~ios_base() 调用的用户定义函数。每次都调用每个注册的回调：事件类型（ event 类型值）作为首参数传递，而且可用于区别调用方。

以注册的逆序调用回调（换言之， register_callback() 在回调栈上推入回调对）。若在回调函数内调用 register_callback() 添加新回调，则只在下次事件发生时调用新回调。

不允许用户定义的回调抛异常。

参数

function | - | 事件发生时将调用的函数，作为 event_callback 类型函数指针提供
index | - | 将传递给函数的自定义参数

返回值

（无）

注意

一旦注册，则不能解除注册回调：它在流对象剩下的生存期中保留为其一部分。若需要更改回调的行为，则可通过 iword() 或 pword() 控制。

若注册同一函数多次，则调用它多次。

与回调一同存储的整数值通常为从 xalloc() 获得的下标。

示例

演示用 register_callback 更新本地环境依赖的缓存值，它为自定义的输出运算符所用

#include <iostream>
#include <locale>
#include <functional>

// 缓存本地环境限定的消息及其哈希
typedef std::pair<std::string, std::size_t> cache_t;

// 从本地环境填充缓存的消息及其哈希
void update_cache(cache_t& cache, std::locale loc)
{
    auto& fct = std::use_facet< std::messages<char> >(loc);
    std::messages_base::catalog cat = fct.open("sed", loc);
    cache.first = cat < 0 ? "" : fct.get(cat, 0, 0, "Memory exhausted");
    cache.second = std::hash<std::string>()(cache.first);
}

// 若本地环境更改则更新缓存
void true_callback(std::ios_base::event evt, std::ios_base& str, int idx)
{
    if (evt == std::ios_base::imbue_event)
    {
        cache_t* ptr = static_cast<cache_t*>(str.pword(idx));
        update_cache(*ptr, str.getloc());
    }
}

// 注册 pword() 中的缓存并设置回调
struct CacheSetup
{
    CacheSetup(std::ostream& os, std::ios_base::event_callback f, cache_t* cache)
    {
        int index = std::ostream::xalloc();
        os.pword(index) = cache; // 设置指针指向流中的缓存
        os.register_callback(f, index); // 存储回调和指针的下标
        update_cache(*cache, os.getloc()); // 初始化缓存
    };
};

// 某定制类
struct S { };
// 某定制类的 operator<< 需要到被哈希消息的快速访问
std::ostream& operator<<(std::ostream& os, const S&)
{
   static cache_t cache;
   static CacheSetup setup(os, true_callback, &cache);
   return os << cache.first << " : " << cache.second;
}

int main()
{
    std::locale loc("en_US.utf8");

    S s;
    std::cout.imbue(loc);
    std::cout << s << '\n';

    std::cout.imbue(std::locale(loc, new std::messages_byname<char>("de_DE.utf8")));
    std::cout << s << '\n';

    std::cout.imbue(std::locale(loc, new std::messages_byname<char>("ja_JP.utf8")));
    std::cout << s << '\n';

    std::cout.imbue(std::locale(loc, new std::messages_byname<char>("ru_RU.utf8")));
    std::cout << s << '\n';
}

输出：

Memory exhausted : 2,295,079,096
Speicher erschöpft : 3,139,423,551
メモリーが足りません : 3,837,351,114
Память исчерпана : 3,742,732,851


std::ios_base::seekdir

< cpp‎ | io‎ | ios base
typedef /*implementation defined*/ seekdir;
static constexpr seekdir beg = /*implementation defined*/

static constexpr seekdir end = /*implementation defined*/

static constexpr seekdir cur = /*implementation defined*/

指定文件寻位方向类型。定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

示例

本节未完成
原因：暂无示例

参阅

seekg
 设置输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
seekp
 设置输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
pubseekoff
 调用 seekoff()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)


std::ios_base::setf

< cpp‎ | io‎ | ios base
fmtflags setf( fmtflags flags ); | (1)
fmtflags setf( fmtflags flags, fmtflags mask ); | (2)

设置格式化标志以指定设置。

1) 设置 flags 所标识的格式化标志。等效地进行下列操作： fl = fl | flags ，其中 fl 定义内部格式化标志的状态。
2) 清除 mask 下的格式化标志，并设置被清除的标志为 flags 所指定者。等效地进行下列操作： fl = (fl & ~mask) | (flags & mask) ，其中 fl 定义格式化标志的内部状态。

参数

flags, mask - 新格式化设定。 mask 定义哪些标志可以改变， flags 定义要改变的标志中该设置那些（其他将被清除）。两个参数都能为下列常量的组合：
常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

返回值

调用函数前的格式化标志

示例

#include <iostream>
#include <iomanip>

const double PI = 3.1415926535;

int main()
{
    const int WIDTH = 15;

    std::cout.setf(std::ios::right);  // 等价： cout << right;
    std::cout << std::setw(WIDTH/2) << "radius"
              << std::setw(WIDTH) << "circumference" << '\n';

    std::cout.setf(std::ios::fixed);
    for (double radius = 1; radius <= 6; radius += 0.5) {
        std::cout << std::setprecision(1) << std::setw(WIDTH/2)
                  << radius
                  << std::setprecision(2) << std::setw(WIDTH)
                  << (2 * PI * radius) << '\n';
    }
}

输出：

radius  circumference
    1.0           6.28
    1.5           9.42
    2.0          12.57
    2.5          15.71
    3.0          18.85
    3.5          21.99
    4.0          25.13
    4.5          28.27
    5.0          31.42
    5.5          34.56
    6.0          37.70

参阅

flags | 管理格式标志 (公开成员函数)
unsetf | 清除特定格式的标志 (公开成员函数)


std::ios_base::sync_with_stdio

< cpp‎ | io‎ | ios base
static bool sync_with_stdio( bool sync = true );

设置标准 C++ 流是否与标准 C 流在每次输入/输出操作后同步。

标准 C++ 流为下列者： std::cin 、 std::cout 、 std::cerr 、 std::clog 、 std::wcin 、 std::wcout 、 std::wcerr 和 std::wclog 。

标准 C 流为下列者： stdin 、 stdout 和 stderr 。

对于与 C 流 f 同步的标准流 str ，下列函数对拥有等同的效果：

1) std::fputc (f, c) 和 str.rdbuf()->sputc(c)
2) std::fgetc (f) 和 str.rdbuf()->sbumpc()
3) std::ungetc (c, f) 和 str.rdbuf()->sputbackc(c)

实践中，这表示同步的 C++ 流为无缓冲，而每次 C++ 流上的 I/O 都立即应用到对应 C 流的缓冲区。这使得能自由地混合 C++ 与 C I/O 。

另外，同步的 C++ 流保证为线程安全（从多个线程输出的单独字符可能交错，但无数据竞争）。

若关闭同步，则允许 C++ 标准流独立地缓冲其 I/O ，可认为这在某些情况下更快。

所有八个标准 C++ 流默认与其相应的 C 流同步。

若在标准流上已出现 I/O 后调用此函数，则行为是实现定义的：有的实现无效果，有的实现销毁读取缓冲区。

参数

sync - 新的同步设置

返回值

调用函数前的同步状态

示例

#include <iostream>
#include <cstdio>

int main()
{
    std::ios::sync_with_stdio(false);
    std::cout << "a\n";
    std::printf("b\n");
    std::cout << "c\n";
}

可能的输出：

b
a
c

参阅

coutwcout | 写入到标准 C 输出流 stdout (全局对象)
cerrwcerr | 写入到标准 C 错误流 stderr， 无缓冲 (全局对象)
clogwclog | 写入到标准 C 错误流 stderr (全局对象)


std::ios_base::unsetf

< cpp‎ | io‎ | ios base
void unsetf( fmtflags flags );

反设置 flags 所表示的格式化标志。

参数

flags - 要反设置的格式化标志。它能为下列常量的组合：
常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

flags | 管理格式标志 (公开成员函数)
setf | 设置特定格式标志 (公开成员函数)


std::ios_base::width

< cpp‎ | io‎ | ios base
streamsize width() const; | (1)
streamsize width( streamsize new_width ); | (2)

管理某些输出操作时生成的最小字符数，和某些输出操作时生成的最大字符数。

1) 返回当前域宽。
2) 设置域宽为给定值。返回先前的位宽。

参数

new_width - 设置的新域宽

返回值

调用函数前的域宽

注意

一些 I/O 函数在返回前调用 width(0) ，见 std::setw （这导致此域仅在下次 I/O 函数，而不再任何后继 I/O 时有效）。

此修改器在输入和输出上拥有的准确效果在单独的 I/O 函数之间有别，效果单独描述于每个 operator<< 和 operator>> 重载的页面。

示例

#include <array>
#include <tuple>
#include <ctime>
#include <string>
#include <iostream>
#include <sstream>
#include <iomanip>

int main()
{
    auto str_time = [](int year, int mon, int day)
    {
        constexpr std::array<const char*, 7> week_day{ {
            "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
        } };

        std::tm tm{};
        tm.tm_year = year - 1900;
        tm.tm_mon  = mon - 1;
        tm.tm_mday = day;

        day += mon < 3 ? year-- : year - 2;
        tm.tm_wday = (23 * mon / 9 + day + 4 + year / 4 - year / 100 + year / 400) % 7;

        std::ostringstream out;
        out << week_day[tm.tm_wday] << ", " << std::put_time(&tm, "%B %d, %Y");
        return out.str();
    };

    constexpr int column_size = 4;
    using table_t = std::array<std::string, column_size>;

    table_t headers{ { "Name", "Birthdate", "Death date", "Language Created" } };

    std::array<table_t, 5> data{ {
        { { "Dennis MacAlistair Ritchie", str_time(1941, 9, 9), str_time(2011, 10, 12), "C" } },
        { { "Bjarne Stroustrup", str_time(1950, 12, 30), "", "C++" } },
        { { "Anders Hejlsberg", str_time(1960, 12, 2), "", "C#" } },
        { { "Guido van Rossum", str_time(1956, 1, 31), "", "Python" } },
        { { "Brendan Eich", str_time(1961, 7, 4), "", "Javascript" } }
    } };

    constexpr int name_wid  = 30;
    constexpr int birth_wid = 30;
    constexpr int death_wid = 30;
    constexpr int lang_wid  = 18;

    auto print_line = [](table_t const &tbl)
    {

        auto const &[Name, Birthdate, DeathDate, LanguageCreated] = tbl;

        std::cout.width(name_wid);
        std::cout << ("| " + Name) << '|';

        std::cout.width(birth_wid);
        std::cout << (' ' + Birthdate) << '|';

        std::cout.width(death_wid);
        std::cout << (' ' + DeathDate) << '|';

        std::cout.width(lang_wid);
        std::cout << (' ' + LanguageCreated) << '|';

        std::cout << '\n';
    };

    constexpr int total_wid = name_wid + birth_wid + death_wid + lang_wid + column_size;

    auto print_break = []
    {
        std::cout.width(total_wid);
        std::cout.fill('-');
        std::cout << '-' << std::endl;
        std::cout.fill(' ');
    };

    std::cout.setf(std::ios::left, std::ios::adjustfield);
    print_break();
    print_line(headers);
    print_break();
    for (auto const &entry : data)
        print_line(entry);
    print_break();
}

输出：

----------------------------------------------------------------------------------------------------------------
| Name                        | Birthdate                    | Death date                   | Language Created |
----------------------------------------------------------------------------------------------------------------
| Dennis MacAlistair Ritchie  | Tuesday, September 09, 1941  | Wednesday, October 12, 2011  | C                |
| Bjarne Stroustrup           | Saturday, December 30, 1950  |                              | C++              |
| Anders Hejlsberg            | Friday, December 02, 1960    |                              | C#               |
| Guido van Rossum            | Tuesday, January 31, 1956    |                              | Python           |
| Brendan Eich                | Tuesday, July 04, 1961       |                              | Javascript       |
----------------------------------------------------------------------------------------------------------------

参阅

precision
 管理浮点操作的精度
(公开成员函数)


std::ios_base::xalloc

< cpp‎ | io‎ | ios base
static int xalloc();

返回（程序范围内）唯一的值，它能用于通过调用 iword() 和 pword() 访问 std::ios_base 的私有存储中一个 long 和一个 void* 元素。到 xalloc 的调用不分配内存。

此函数线程安全；从多个线程共时访问不导致数据竞争。 (C++14 起)

等效地自增 std::ios_base 的私有静态数据成员，如同以执行 return index++; ，若 index 是该静态成员的名称（它可以为 std::atomic 或以其他方式以支持多线程共时访问） (C++14 起)。

参数

（无）

返回值

用作 pword/iword 下标的独有整数。

示例

将基类 pword 存储用于导出的流对象的运行时类型鉴别。

#include <iostream>

template<class charT, class traits = std::char_traits<charT> >
class mystream : public std::basic_ostream<charT, traits>
{
 public:
    static const int xindex;
    mystream(std::basic_ostream<charT, traits>& ostr) :
        std::basic_ostream<charT, traits>(ostr.rdbuf())
    {
         this->pword(xindex) = this;
    }

    void myfn()
    {
        *this << "[special handling for mystream]";
    }
};

// 每个 mystream 特化从 xalloc() 获得独有的下标
template<class charT, class traits>
const int mystream<charT, traits>::xindex = std::ios_base::xalloc();

// 此 I/O 操纵符将能用于辨识身为 mystream 的 ostream
// 通过查找存储于 pword 的指针
template<class charT, class traits>
std::basic_ostream<charT,traits>& mymanip(std::basic_ostream<charT,traits>& os)
{
 if (os.pword(mystream<charT,traits>::xindex) == &os)
    static_cast<mystream<charT,traits>&>(os).myfn();
 return os;
}

int main()
{
    std::cout << "cout, narrow-character test " << mymanip << '\n';

    mystream<char> myout(std::cout);
    myout << "myout, narrow-character test " << mymanip << '\n';

    std::wcout << "wcout, wide-character test " << mymanip << '\n';

    mystream<wchar_t> mywout(std::wcout);
    mywout << "mywout, wide-character test " << mymanip << '\n';
}

输出：

cout, narrow-character test
myout, narrow-character test [special handling for mystream]
wcout, wide-character test
mywout, wide-character test [special handling for mystream]

参阅

pword | 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素 (公开成员函数)
iword | 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素 (公开成员函数)


std::ios_base::~ios_base

< cpp‎ | io‎ | ios base
virtual ~ios_base();

销毁 ios_base 对象。

在任何成员函数会产出未定义结果前，调用 register_callback() 传递 erase_event 为参数注册的回调函数。然后解分配任何获得的内存。

不进行 rdbuf 上的操作，不销毁它。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3434 | C++98 | 未要求析构函数归还 iarray 与 parray 的内存 | 已要求


std::iostream_category

< cpp‎ | io
定义于头文件 <ios> |
const std::error_category & iostream_category() noexcept; | (C++11 起)

获得到为 iostream 错误而设的静态 error_category 对象的引用。要求对象覆写虚函数 error_category::name() 以返回指向字符串 "iostream" 的指针。它亦用于鉴别提供于 std::ios_base::failure 类型异常的 error_code 。

参数

（无）

返回值

获得到导出自 std::error_category 的未指定运行时类型的静态对象的引用。

参阅

#include <iostream>
#include <fstream>

int main()
{
    std::ifstream f("doesn't exist");
    try {
        f.exceptions(f.failbit);
    } catch (const std::ios_base::failure& e) {
        std::cout << "Caught an ios_base::failure.\n"
                  << "Error code: " << e.code().value()
                  << " (" << e.code().message() << ")\n"
                  << "Error category: " << e.code().category().name() << '\n';

    }
}

可能的输出：

Caught an ios_base::failure.
Error code: 1 (unspecified iostream_category error)
Error category: iostream

参阅

failure | 流异常 (std::ios_base 的公开成员类)
io_errc (C++11) | IO 流的错误码 (枚举)


std::istrstream

< cpp‎ | io
定义于头文件 <strstream> |
class istrstream : public std::istream | (C++98 中弃用)

类 istrstream 实现基于数组的流上的输入操作。它实际上将原生数组 I/O 设备（ std::strstreambuf ）包装进 std::basic_istream 的高层接口。

istrstream 的典型实现仅保有一个非导出的数据成员： std::strstreambuf 类型对象。

注意

istrstream 从 C++98 起被弃用， std::istringstream 和 boost::iostreams::array_source 是受推荐的替代品。

成员函数

(构造函数) | 构造 strstream ，可选地分配缓冲区 (公开成员函数)
(析构函数) [虚] | 析构 strstream ，可选地解分配缓冲区 (虚公开成员函数)
rdbuf | 获得指向关联 strstreambuf 的指针 (公开成员函数)
str | 访问输出缓冲区 (公开成员函数)

继承自 std::basic_istream

成员函数

有格式输入
operator>>
 提取带格式数据
(std::basic_istream<CharT,Traits> 的公开成员函数)
无格式输入
get
 从流中读并取走（移除类似指针向下一个元素移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
peek
 仅读出但不取走（不移除类似指针并未移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
unget
 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
putback
 往输入流中退回一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
getline
 一直读并取走字符，直至找到给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
ignore
 读且取走并舍弃字符，直至发现给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
read
 读并取走一块字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
readsome
 读并取走已经可用的字符块
(std::basic_istream<CharT,Traits> 的公开成员函数)
gcount
 返回上次无格式输出操作所取走的字符数量
(std::basic_istream<CharT,Traits> 的公开成员函数)
寻位
tellg
 返回输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
seekg
 设置输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
杂项
sync
 与底层存储设备同步
(std::basic_istream<CharT,Traits> 的公开成员函数)

成员类

sentry
 实现为输出操作准备流的基本逻辑
(std::basic_istream<CharT,Traits> 的公开成员类)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)


std::istrstream::istrstream

< cpp‎ | io‎ | istrstream
explicit istrstream(const char* s); | (1)
explicit istrstream(char* s); | (2)
istrstream(const char* s, std::streamsize n); | (3)
istrstream(char* s, std::streamsize n); | (4)

构造新的 istrstream 及其底层 std::strstreambuf 。

1,2) 通过调用 strstreambuf(s,0) 构造底层 std::strstreambuf ，并以该 strstreambuf 的地址初始化基类。若 s 不指向空终止数组的元素，则行为未定义。
3,4) 通过调用 strstreambuf(s,n) 构造底层 std::strstreambuf ，并以该 strstreambuf 的地址初始化基类。若 s 不指向长度至少为 n 个元素的数组的元素，则行为未定义。

参数

s | - | 要用作流内容的 C 字符串或字符数组
n | - | 数组大小

示例

#include <iostream>
#include <strstream>

int main()
{
    std::istrstream s1("1 2 3"); // 字符串字面量
    int n1,n2,n3;
    if(s1 >> n1 >> n2 >> n3)
        std::cout << n1 << ", " << n2 << ", " << n3 << '\n';

    char arr[] = {'4', ' ', '5', ' ', '6'};
    std::istrstream s2(arr, sizeof arr);
    if(s2 >> n1 >> n2 >> n3)
        std::cout << n1 << ", " << n2 << ", " << n3 << '\n';
}

输出：

1, 2, 3
4, 5, 6

参阅

(构造函数) | 构造 strstreambuf 对象 (std::strstreambuf 的公开成员函数)
(构造函数) | 构造 strstream ，可选地分配缓冲区 (std::ostrstream 的公开成员函数)
(构造函数) | 构造 strstream ，可选地分配缓冲区 (std::strstream 的公开成员函数)


std::istrstream::rdbuf

< cpp‎ | io‎ | istrstream

strstreambuf* rdbuf() const;

返回指向关联 std::strstreambuf 的指针，转型走其常性（无关乎成员函数上的 const 限定符）。

参数

（无）

返回值

指向关联 std::strsteambuf 的指针，常性被转型走。

示例

#include <strstream>
int main()
{
    const std::istrstream buf("example");
    std::strstreambuf* ptr = buf.rdbuf();
}


std::istrstream::str

< cpp‎ | io‎ | istrstream

char* str();

冻结缓冲区后，返回指向其起始的指针。等效地调用 rdbuf()->str() 。

参数

（无）

返回值

指向关联 std::strsteambuf 中缓冲区起始的指针，或若无可用缓冲区则为空指针。

示例

本节未完成
原因：暂无示例


std::istrstream::~istrstream

< cpp‎ | io‎ | istrstream
virtual ~istrstream();

销毁 std::istrstream 对象，这亦销毁成员 std::strstreambuf 。

参数

（无）

注意

std::istrstream 的构造函数不以动态分配模式创建底层 std::strstreambuf ，故 std::ostrstream::~ostrstream 或 std::strstream::~strstream 可能有的内存泄露不会应用。

示例

#include <strstream>
#include <iostream>

int main()
{
    {
        std::istrstream s("1.234");
        double d;
        s >> d;
        std::cout << d << '\n';
    } // 调用析构函数
}

输出：

1.234


输入/输出操纵符

< cpp‎ | io

操纵符是令代码能以 operator<< 或 operator>> 控制输入/输出流的帮助函数。

不以参数调用的操纵符（例如 std::cout << std::boolalpha ; 或 std::cin >> std::hex ; ）实现为接受到流的引用为其唯一参数的函数。 basic_ostream::operator<< 和 basic_istream::operator>> 的特别重载版本接受指向这些函数的指针。这些函数（或函数模板的实例化）是标准库中仅有的可取址函数。 (C++20 起)

以参数调用的操纵符（例如 std::cout << std::setw (10); ）实现为返回未指定类型对象的函数。这些操纵符定义其自身的进行请求操作的 operator<< 或 operator>> 。

定义于头文件 <ios>
boolalphanoboolalpha | 在布尔值的文本和数值表示间切换 (函数)
showbasenoshowbase | 控制是否使用前缀指示数值基数 (函数)
showpointnoshowpoint | 控制浮点表示是否始终包含小数点 (函数)
showposnoshowpos | 控制是否将 + 号与非负数一同使用 (函数)
skipwsnoskipws | 控制是否跳过输入上的前导空白符 (函数)
uppercasenouppercase | 控制一些输出操作是否使用大写字母 (函数)
unitbufnounitbuf | 控制是否每次操作后冲洗输出 (函数)
internalleftright | 设置填充字符的布置 (函数)
dechexoct | 更改用于整数 I/O 的基数 (函数)
fixedscientifichexfloatdefaultfloat (C++11)(C++11) | 更改用于浮点 I/O 的格式化 (函数)
定义于头文件 <istream>
ws | 消耗空白符 (函数模板)
定义于头文件 <ostream>
ends | 输出 '\0' (函数模板)
flush | 冲洗输出流 (函数模板)
endl | 输出 '\n' 并冲洗输出流 (函数模板)
emit_on_flushnoemit_on_flush (C++20) | 控制流的 basic_syncbuf 是否在冲入时发射 (函数模板)
flush_emit (C++20) | 冲入流，而若它使用 basic_syncbuf 则发射其内容 (函数模板)
定义于头文件 <iomanip>
resetiosflags | 清除指定的 ios_base 标志 (函数)
setiosflags | 设置指定的 ios_base 标志 (函数)
setbase | 更改用于整数 I/O 的基数 (函数)
setfill | 更改填充字符 (函数模板)
setprecision | 更改浮点精度 (函数)
setw | 更改下个输入/输出域的宽度 (函数)
get_money (C++11) | 剖析货币值 (函数模板)
put_money (C++11) | 格式化并输出货币值 (函数模板)
get_time (C++11) | 剖析指定格式的日期/时间值 (函数模板)
put_time (C++11) | 按照指定格式格式化并输出日期/时间值 (函数模板)
quoted (C++14) | 插入和读取带有内嵌空格的被引号括起来的字符串 (函数模板)


std::boolalpha, std::noboolalpha

< cpp‎ | io‎ | manip
定义于头文件 <ios> |
std::ios_base & boolalpha( std::ios_base & str ); | (1)
std::ios_base & noboolalpha( std::ios_base & str ); | (2)
1) 启用流 str 中的 boolalpha 标志，如同通过调用 str.setf( std::ios_base::boolalpha ) 。
2) 禁用流 str 中的 boolalpha 标志，如同通过调用 str.unsetf( std::ios_base::boolalpha ) 。

std::boolalpha 是 I/O 操纵符，故可用如 out << std::boolalpha 的表达式对任何 std::basic_ostream 类型的 out ，或用如 in >> std::boolalpha 的表达式对任何 std::basic_istream 类型的 in 调用。

参数

str - 到 I/O 流的引用

返回值

str （到操纵后的流的引用）

示例

#include <sstream>
#include <locale>
#include <iostream>
int main()
{
    // boolalpha 输出
    std::cout << std::boolalpha
              << "boolalpha true: " << true << '\n'
              << "boolalpha false: " << false << '\n';
    std::cout << std::noboolalpha
              << "noboolalpha true: " << true << '\n'
              << "noboolalpha false: " << false << '\n';
    // boolalpha 分析
    bool b1, b2;
    std::istringstream is("true false");
    is >> std::boolalpha >> b1 >> b2;
    std::cout << '\"' << is.str() << "\" parsed as " << b1 << ' ' << b2 << '\n';
}

输出：

boolalpha true: true
boolalpha false: false
noboolalpha true: 1
noboolalpha false: 0
"true false" parsed as 1 0

参阅

resetiosflags | 清除指定的 ios_base 标志 (函数)
setiosflags | 设置指定的 ios_base 标志 (函数)
do_truenamedo_falsename [虚] | 提供用作布尔 true 和 false 名称的字符串 (std::numpunct<CharT> 的虚受保护成员函数)


std::emit_on_flush, std::noemit_on_flush

< cpp‎ | io‎ | manip
定义于头文件 <ostream> |  |
template< class CharT, class Traits > std::basic_ostream <CharT, Traits>& emit_on_flush( std::basic_ostream <CharT, Traits>& os ); | (1) | (C++20 起)
template< class CharT, class Traits > std::basic_ostream <CharT, Traits>& noemit_on_flush( std::basic_ostream <CharT, Traits>& os ); | (2) | (C++20 起)

若 os.rdbuf() 实际指向一个 std::basic_syncbuf<CharT, Traits, Allocator> buf ，则控制它是否在冲入时发射（即传输数据到底层流缓冲）：

1) 调用 buf.set_emit_on_sync(true)
2) 调用 buf.set_emit_on_sync(false)

否则，这些操纵符无效果。

这是仅输出的 I/O 操纵符，可用如 out << std::emit_on_flush 的表达式对任何 std::basic_ostream 类型的 out 调用它。

参数

os - 到输出流的引用

返回值

os （到操纵后的流的引用）

示例

本节未完成
原因：暂无示例

参阅

set_emit_on_sync
 更改当前同步时发射策略
(std::basic_syncbuf<CharT,Traits,Allocator> 的公开成员函数)


std::endl

< cpp‎ | io‎ | manip
定义于头文件 <ostream>
template< class CharT, class Traits >
std::basic_ostream <CharT, Traits>& endl( std::basic_ostream <CharT, Traits>& os );

插入换行符到输出序列 os 并冲入它，如同调用 os.put(os.widen('\n')) 后随 os.flush() 。

这是仅输出的 I/O 操纵符，可对任何 std::basic_ostream 类型的 out 以表达式 out << std::endl 调用它。

注意

可用此操纵符立即产生新行的输出，例如在从长时间运行的进程显示输出、记录多个线程的活动或记录可能不期待地崩溃的程序活动时。在调用 std::system 前亦需要 std::cout 的显式冲入，若产生的进程进行任何屏幕 I/O 。多数其他通常的交互 I/O 场景中，使用 std::cout 时 std::endl 是冗余的，因为任何来自 std::cin 的输入、到 std::cerr 的输出或程序终止强制调用 std::cout.flush() 。某些源代码中鼓励用 std::endl 代替 '\n' ，这可能显著地降低输出性能。

多数实现中，标准输出是行缓冲的，而写入 '\n' 就会导致冲入，除非执行 std::ios::sync_with_stdio(false) 。这些情形中，不必要的 endl 只会降低文件输出的性能，而非标准输出的。

此维基上的代码示例遵循 Bjarne Stroustrup和《 C++ 核心方针》，只在需要时冲入标准输出。

需要冲入不完整的行时，可使用 std::flush 操纵符。

需要冲入每个字节的输出时，可使用 std::unitbuf 操纵符。

参数

os - 到输出流的引用

返回值

os （到操纵后流的引用）

示例

以 \n 替代 endl ，输出会相同，但可能不会实时出现。

#include <iostream>
#include <chrono>

template<typename Diff>
void log_progress(Diff d)
{
    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(d).count()
              << " ms passed" << std::endl;
}

int main()
{
    std::cout.sync_with_stdio(false); // 一些平台上 stdout 在写 \n 时冲入
    volatile int sink = 0;

    auto t1 = std::chrono::high_resolution_clock::now();
    for (int j=0; j<5; ++j)
    {
        for (int n=0; n<10000; ++n)
            for (int m=0; m<20000; ++m)
                sink += m*n; // 做一些工作
        auto now = std::chrono::high_resolution_clock::now();
        log_progress(now - t1);
    }
}

可能的输出：

487 ms passed
974 ms passed
1470 ms passed
1965 ms passed
2455 ms passed

参阅

unitbufnounitbuf | 控制是否每次操作后冲洗输出 (函数)
flush | 冲洗输出流 (函数模板)
flush | 与底层存储设备同步 (std::basic_ostream<CharT,Traits> 的公开成员函数)


std::ends

< cpp‎ | io‎ | manip
定义于头文件 <ostream>
template< class CharT, class Traits >
std::basic_ostream <CharT, Traits>& ends( std::basic_ostream <CharT, Traits>& os );

如同以调用 os.put(CharT()) 插入空字符到输出序列中 os 。

这是仅输出的 I/O 操纵符，可以用如 out << std::ends 的表达式对任何 std::basic_ostream 类型的 out 调用。

注意

此操纵符典型地为 std::ostrstream 在关联输出缓冲区需要为空终止，以作为 C 字符串处理时使用。

不同于 std::endl ，此操纵符不冲入流。

参数

os - 到输出流的引用

返回值

os （到插入空字符后的流的引用）

示例

#include <cstdio>
#include <strstream>
int main()
{
    std::ostrstream oss;
    oss << "Sample text: " << 42 << std::ends;
    std::printf("%s\n", oss.str());
    oss.freeze(false); // 启用内存解分配
}

输出：

Sample text: 42

参阅

ostrstream
(C++98 中弃用)
 实现字符数组输出操作
(类)


std::fixed, std::scientific, std::hexfloat, std::defaultfloat

< cpp‎ | io‎ | manip
定义于头文件 <ios> |  |
std::ios_base & fixed( std::ios_base & str ); | (1) |
std::ios_base & scientific( std::ios_base & str ); | (2) |
std::ios_base & hexfloat( std::ios_base & str ); | (3) | (C++11 起)
std::ios_base & defaultfloat( std::ios_base & str ); | (4) | (C++11 起)

修改浮点输入/输出的默认格式化。

1) 如同以调用 str.setf( std::ios_base::fixed, std::ios_base::floatfield ) ，设置流 str 的 floatfield 为 fixed
2) 如同以调用 str.setf( std::ios_base::scientific, std::ios_base::floatfield ) ，设置流 str 的 floatfield 为 scientific
3) 如同以调用 str.setf( std::ios_base::fixed | std::ios_base::scientific, std::ios_base::floatfield ) ，设置流 str 的 floatfield 同时为 fixed 和 scientific 。这启用十六进制浮点格式化。
4) 如同以调用 str.unsetf( std::ios_base::floatfield ) ，设置流 str 的 floatfield 为零，这异于 fixed 和 scientific 。

这是一个 I/O 操纵符，可用如 out << std::fixed 的表达式对任何 std::basic_ostream 类型的 out 或用如 in >> std::scientific 的表达式对任何 std::basic_istream 类型的 in 调用。

参数

str - 到 I/O 流的引用

返回值

str （到操纵后的流的引用）

注意

十六进制浮点格式化忽略流精度规定，如 std::num_put::do_put 的规定所要求。

示例

#include <iostream>
#include <sstream>

int main()
{
    std::cout << "The number 0.01 in fixed:      " << std::fixed << 0.01 << '\n'
              << "The number 0.01 in scientific: " << std::scientific << 0.01 << '\n'
              << "The number 0.01 in hexfloat:   " << std::hexfloat << 0.01 << '\n'
              << "The number 0.01 in default:    " << std::defaultfloat << 0.01 << '\n';
    double f;
    std::istringstream("0x1P-1022") >> std::hexfloat >> f;
    std::cout << "Parsing 0x1P-1022 as hex gives " << f << '\n';
}

输出：

The number 0.01 in fixed:      0.010000
The number 0.01 in scientific: 1.000000e-02
The number 0.01 in hexfloat:   0x1.47ae147ae147bp-7
The number 0.01 in default:    0.01
Parsing 0x1P-1022 as hex gives 2.22507e-308

参阅

setprecision
 更改浮点精度
(函数)


std::flush

< cpp‎ | io‎ | manip
定义于头文件 <ostream>
template< class CharT, class Traits >
std::basic_ostream <CharT, Traits>& flush( std::basic_ostream <CharT, Traits>& os );

如同以调用 os.flush() 冲入输出序列 os 。

这是仅输出的 I/O 操纵符，可以用如 out << std::flush 的表达式对任何 std::basic_ostream 类型的 out 调用。

注意

此操纵符可用于立即产生输出的不完整行，例如在从长时间运行的进程显示输出、记录多个线程的活动或记录可能不期待地崩溃的程序活动时。若产生的进程进行任何屏幕 I/O 大量，则调用 std::system 前亦需要 std::cout 的显式冲入（常见例子为 Windows 上的 std::system ("pause") ）。多数其他通常的交互 I/O 场景中，使用 std::cout 时 std::endl 是冗余的，因为任何来自 std::cin 的输入、到 std::cerr 的输出或程序终止强制调用 std::cout.flush() 。

需要冲入完整行时，可使用 std::endl 操纵符。

每次输出操作都需要冲入时，可使用 std::unitbuf 操纵符。

参数

os - 到输出流的引用

返回值

os （到操纵后的流的引用）

示例

没有 std::flush ，输出相同，但可能不实时出现。

#include <iostream>
#include <chrono>
template<typename Diff>
void log_progress(Diff d)
{
    std::cout << "..("
              << std::chrono::duration_cast<std::chrono::milliseconds>(d).count()
              << " ms).." << std::flush;
}
int main()
{
    volatile int sink=0;

    auto t1 = std::chrono::high_resolution_clock::now();
    for(int j=0; j<5; ++j)
    {
        for(int n=0; n<10000; ++n)
            for(int m=0; m<20000; ++m)
                sink += m*n; // 做一些工作
        auto now = std::chrono::high_resolution_clock::now();
        log_progress(now - t1);
    }
    std::cout << '\n';
}

可能的输出：

..(450 ms)....(901 ms)....(1350 ms)....(1800 ms)....(2250 ms)..

参阅

unitbufnounitbuf | 控制是否每次操作后冲洗输出 (函数)
endl | 输出 '\n' 并冲洗输出流 (函数模板)
flush | 与底层存储设备同步 (std::basic_ostream<CharT,Traits> 的公开成员函数)


std::flush_emit

< cpp‎ | io‎ | manip
定义于头文件 <ostream> |
template< class CharT, class Traits > std::basic_ostream <CharT, Traits>& flush_emit( std::basic_ostream <CharT, Traits>& os ); | (C++20 起)

如同通过调用 os.flush() 冲入输出序列 os 。然后若 os.rdbuf() 实际指向一个 std::basic_syncbuf<CharT, Traits, Allocator> buf ，则调用 buf.emit() 。

这是仅输出的 I/O 操纵符，可用如 out << std::flush_emit 的表达式对任何 std::basic_ostream 类型的 out 调用它。

参数

os - 到输出流的引用

返回值

os （到操纵后的流的引用）

示例

本节未完成
原因：暂无示例

参阅

flush
 与底层存储设备同步
(std::basic_ostream<CharT,Traits> 的公开成员函数)


std::get_money

< cpp‎ | io‎ | manip
定义于头文件 <iomanip> |
template< class MoneyT > /*unspecified*/ get_money( MoneyT& mon, bool intl = false ); | (C++11 起)

用于表达式 in >> get_money(mon, intl) 中时，分析字符输入为 in 中当前感染的 locale 的 std::money_get 平面所指定的货币值，并存储结果于 mon 。

in >> get_money(mon, intl) 中的释出操作表现为有格式输入函数 (FormattedInputFunction) 。

参数

mon | - | 要被写入货币值的变量。能为 long double 或 basic_string 之一
intl | - | 若为 true 则期待找到要求的国际通货字符串，否则期待可选的通货符号

返回值

返回未指定类型对象，使得若 in 为 std::basic_istream <CharT, Traits> 类型输入流的名称，则表达式 in >> get_money(mon, intl) 表现为如同执行下列代码：

typedef std::istreambuf_iterator <CharT, Traits> Iter;
typedef std::money_get <CharT, Iter> MoneyGet;
std::ios_base::iostate err = std::ios_base::goodbit ;
const MoneyGet &mg = std::use_facet <MoneyGet>(in.getloc());
mg.get(Iter(in.rdbuf()), Iter(), intl, in, err, mon);
if ( std::ios_base::goodbit != err)
out.setstate(err);

示例

#include <iostream>
#include <sstream>
#include <locale>
#include <iomanip>

int main()
{
    std::istringstream in("$1,234.56 2.22 USD  3.33");
    long double v1, v2;
    std::string v3;
    in.imbue(std::locale("en_US.UTF-8"));
    in >> std::get_money(v1) >> std::get_money(v2) >> std::get_money(v3, true);
    if (in) {
        std::cout << std::quoted(in.str()) << " parsed as: "
                  << v1 << ", " << v2 << ", " << v3 << '\n';
    } else {
        std::cout << "Parse failed";
    }
}

输出：

"$1,234.56 2.22 USD  3.33" parsed as: 123456, 222, 333

参阅

money_get | 从输入字符序列中解析并构造货币值 (类模板)
put_money (C++11) | 格式化并输出货币值 (函数模板)


std::get_time

< cpp‎ | io‎ | manip
定义于头文件 <iomanip> |
template< class CharT > /*unspecified*/ get_time( std::tm * tmb, const CharT* fmt ); | (C++11 起)

用于表达式 in >> get_time(tmb, fmt) 时，按照格式字符串 fmt 及输入流 in 中当前感染的 locale 的 std::time_get 平面，分析字符输入为日期/时间值。存储结果值于 tmb 所指向的 std::tm 对象中。

参数

tmb - 指向 std::tm 对象的合法指针，结果将存储于其处
fmt - 指向指定转换格式的空终止 CharT 字符串的指针

格式字符串由零或更多转换说明符、空白符和通常字符（除了 % ）组成。期待每个通常字符以大小无关比较匹配输入流中的一个字符。每个空白符匹配输入字符串中的任意空白符。每个转换说明始于 % 字符，可选地后随 E 或 O 修饰符（若本地环境不支持则忽略），后随确定说明符转换行为的字符。格式说明符匹配 POSIX 函数 strptime() ：

转﻿换指﻿定﻿符 | 解释 | 写入域
% | 匹配字面 % 。完整转换说明必须是 %% 。 | （无）
t | 匹配任何空白符。 | （无）
n | 匹配任何空白符。 | （无）
年
Y | 分析完整年为四位十进制数，容许但不要求前导零 | tm_year
EY | 以替用表示分析年，例如 平成23年 在 ja_JP 本地环境中写 2011 到 tm_year | tm_year
y | 分析年的后二位为十进制数。范围 [69,99] 生成 1969 至 1999 的值，范围 [00,68] 生成 2000-2068 | tm_year
Oy | 以替用数值系统分析年的后二位数字，例如 十一 在 ja_JP 本地环境中被分析为 11 | tm_year
Ey | 分析年为从本地环境的替用日历周期 %EC 的偏移 | tm_year
C | 分析年的首 2 位数字为十进制数（范围 [00,99] ） | tm_year
EC | 分析本地环境的替用表示中，年基底（周期）的名称，例如 ja_JP 中的 平成 | tm_year
月
b | 分析月份名，完整或缩写，例如 Oct | tm_mon
h | b 的同义词 | tm_mon
B | b 的同义词 | tm_mon
m | 分析月为十进制数（范围 [01,12] ），容许但不要求前导零 | tm_mon
Om | 用替代数值系统分析月，例如 ja_JP 本地环境中 十二 分析为 12 | tm_mon
星期
U | 分析年之星期为十进制数（星期日是星期的首日）（范围 [00,53] ），容许但不要求前导零 | tm_year, tm_wday, tm_yday
OU | 用替用数值系统，如以 %U 一般分析年之星期，例如 ja_JP 本地环境中 五十二 分析为 52 | tm_year, tm_wday, tm_yday
W | 分析年之星期为十进制数（星期一是星期的首日）（范围 [00,53] ），容许但不要求前导零 | tm_year, tm_wday, tm_yday
OW | 用替用数值系统，如以 %W 一般分析年之星期，例如 ja_JP 本地环境中 五十二 分析为 52 | tm_year, tm_wday, tm_yday
年/月之日
j | 分析年之日为十进制数（范围 [001,366] ），容许但不要求前导零 | tm_yday
d | 分析月之日为十进制数（范围 [01,31] ），容许但不要求前导零 | tm_mday
Od | 用替用数值系统分析月之日，例如 ja_JP 本地环境中 二十七 分析为 27 ，容许但不要求前导零 | tm_mday
e | d 的同义词 | tm_mday
Oe | Od 的同义词 | tm_mday
星期之日
a | 分析星期的日名，完整或缩写版，例如 Fri | tm_wday
A | a 的同义词 | tm_wday
w | 分析星期之日为十进制数，其中星期日为 0 （范围 [0-6] ） | tm_wday
Ow | 用替用数值系统分析星期之日为十进制数，其中星期日为 0 ，例如 ja_JP 本地环境中 二 分析为 2 | tm_wday
时、分、秒
H | 分析时为十进制数，以 24 小时时钟（范围 [00,23] ） ，容许但不要求前导零 | tm_hour
OH | 用替用数值系统分析来自 24 小时时钟的时，例如 ja_JP 本地环境中 十八 分析为 18 | tm_hour
I | 分析时为十进制数，以 12 小时时钟（范围 [01,12] ） ，容许但不要求前导零 | tm_hour
OI | 用替用数值系统分析时，例如 ja_JP 本地环境中 六 分析为 6 | tm_hour
M | 分析分为十进制数（范围 [00,59] ），容许但不要求前导零 | tm_min
OM | 用替用数值系统分析分，例如 ja_JP 本地环境中 二十五 分析为 25 | tm_min
S | 分析秒为十进制数（范围 [00,60] ），容许但不要求前导零 | tm_sec
OS | 用替用数值系统分析秒，例如 ja_JP 本地环境中 二十四 分析为 24 | tm_sec
其他
c | 分析本地环境的标准日期和时间字符串格式，例如 Sun Oct 17 04:41:13 2010 （本地环境依赖） | 所有
Ec | 分析本地环境的替用时期和时间字符串格式，例如期待在 ja_JP 本地环境中以 平成23年 取代 2011年 | 所有
x | 分析本地环境的标准日期表示 | 所有
Ex | 分析本地环境的替用日期表示，例如期待在 ja_JP 本地环境中以 平成23年 取代 2011年 | 所有
X | 分析本地环境的标准时间表示 | 所有
EX | 分析本地环境的替用时间表示 | 所有
D | 等价于 "%m / %d / %y " | tm_mon, tm_mday, tm_year
r | 等价于本地环境的标准 12 小时时钟时间（ POSIX 中为 "%I : %M : %S %p" ） | tm_hour, tm_min, tm_sec
R | 等价于 "%H : %M" | tm_hour, tm_min
T | 等价于 "%H : %M : %S" | tm_hour, tm_min, tm_sec
p | 分析 a.m. 或 p.m. 的本地环境等价版本 | tm_hour

注意：不写入 tm_isdst ，需要用如 mktime 的函数显式设置它。

返回值

返回未指定类型的对象，使得若 in 为 std::basic_istream <CharT, Traits> 类型输出流的名称，则表达式 in >> get_time(tmb, fmt) 表现为如同执行下列代码：

typedef std::istreambuf_iterator <CharT, Traits> Iter;
typedef std::time_get <CharT, Iter> TimeGet;
std::ios_base::iostate err = std::ios_base::goodbit ;
const TimeGet& tg = std::use_facet <TimeGet>(in.getloc());
tg.get(Iter(in.rdbuf()), Iter(), in, err, tmb, fmt, fmt + traits::length(fmt));
if (err != std::ios_base::goodbit )
in.setstate(err);

注意

如 std::time_get::do_get 中所指定，此函数是否清零出现于 fmt 中的格式指定符所不直接选择的 *tmb 中的域，是未指定的：可移植程序应该在调用 std::get_time 前初始化 *tmb 的每个域。

示例

#include <iostream>
#include <sstream>
#include <locale>
#include <iomanip>

int main()
{
    std::tm t = {};
    std::istringstream ss("2011-Februar-18 23:12:34");
    ss.imbue(std::locale("de_DE.utf-8"));
    ss >> std::get_time(&t, "%Y-%b-%d %H:%M:%S");
    if (ss.fail()) {
        std::cout << "Parse failed\n";
    } else {
        std::cout << std::put_time(&t, "%c") << '\n';
    }
}

可能的输出：

Sun Feb 18 23:12:34 2011

参阅

time_get | 从输入字符序列中解析时间/日期值到 std::tm 中 (类模板)
put_time (C++11) | 按照指定格式格式化并输出日期/时间值 (函数模板)


std::dec, std::hex, std::oct

< cpp‎ | io‎ | manip
定义于头文件 <ios> |
std::ios_base & dec( std::ios_base & str ); | (1)
std::ios_base & hex( std::ios_base & str ); | (2)
std::ios_base & oct( std::ios_base & str ); | (3)

修改整数 I/O 的默认数值底。

1) 如同以调用 str.setf( std::ios_base::dec, std::ios_base::basefield ) 设置流 str 的 basefield 为 dec

2) 如同以调用 str.setf( std::ios_base::hex, std::ios_base::basefield ) 设置流 str 的 basefield 为 hex

3) 如同以调用 str.setf( std::ios_base::oct, std::ios_base::basefield ) 设置流 str 的 basefield 为 oct

这是一个 I/O 操纵符，可用如 out << std::hex 的表达式对任何 std::basic_ostream 类型的 out 或用如 in >> std::hex 的表达式对任何 std::basic_istream 类型的 in 调用。

参数

str - 到 I/O 流的引用

返回值

str （到操纵后的流的引用）

示例

#include <iostream>
#include <sstream>
int main()
{
    std::cout << "The number 42 in octal:   " << std::oct << 42 << '\n'
              << "The number 42 in decimal: " << std::dec << 42 << '\n'
              << "The number 42 in hex:     " << std::hex << 42 << '\n';
    int n;
    std::istringstream("2A") >> std::hex >> n;
    std::cout << std::dec << "Parsing \"2A\" as hex gives " << n << '\n';
    // 输出基底是持久的，直至更改
    std::cout << std::hex << "42 as hex gives " << 42
        << " and 21 as hex gives " << 21 << '\n';
}

输出：

The number 42 in octal:   52
The number 42 in decimal: 42
The number 42 in hex:     2a
Parsing "2A" as hex gives 42
42 as hex gives 2a and 21 as hex gives 15

参阅

setbase | 更改用于整数 I/O 的基数 (函数)
showbasenoshowbase | 控制是否使用前缀指示数值基数 (函数)


std::left, std::right, std::internal

< cpp‎ | io‎ | manip
定义于头文件 <ios> |
std::ios_base & left( std::ios_base & str ); | (1)
std::ios_base & right( std::ios_base & str ); | (2)
std::ios_base & internal( std::ios_base & str ); | (3)

修改填充字符的默认定位。 left 与 right 应用到任何输出，而 internal 应用到整数、浮点和货币输出。在输入时无效果。

1) 如同用调用 str.setf( std::ios_base::left, std::ios_base::adjustfield ) ，设置流 str 的 adjustfield 为 left

2) 如同用调用 str.setf( std::ios_base::right, std::ios_base::adjustfield ) ，设置流 str 的 adjustfield 为 right

3) 如同用调用 str.setf( std::ios_base::internal, std::ios_base::adjustfield ) ，设置流 str 的 adjustfield 为 internal

这是一个 I/O 操纵符，可用如 out << std::left 的表达式对任何 std::basic_ostream 类型的 out 或用如 in >> std::left 的表达式对任何 std::basic_istream 类型的 in 调用。

参数

str - 到 I/O 流的引用

返回值

str （到操纵后的流的引用）

示例

#include <iostream>
#include <iomanip>
#include <locale>

int main()
{
    std::cout.imbue(std::locale("en_US.utf8"));
    std::cout << "Left fill:\n" << std::left << std::setfill('*')
              << std::setw(12) << -1.23  << '\n'
              << std::setw(12) << std::hex << std::showbase << 42 << '\n'
              << std::setw(12) << std::put_money(123, true) << "\n\n";

    std::cout << "Internal fill:\n" << std::internal
              << std::setw(12) << -1.23  << '\n'
              << std::setw(12) << 42 << '\n'
              << std::setw(12) << std::put_money(123, true) << "\n\n";

    std::cout << "Right fill:\n" << std::right
              << std::setw(12) << -1.23  << '\n'
              << std::setw(12) << 42 << '\n'
              << std::setw(12) << std::put_money(123, true) << '\n';
}

输出：

Left fill:
-1.23*******
0x2a********
USD *1.23***

Internal fill:
-*******1.23
0x********2a
USD ****1.23

Right fill:
*******-1.23
********0x2a
***USD *1.23

参阅

setw | 更改下个输入/输出域的宽度 (函数)
setfill | 更改填充字符 (函数模板)


std::put_money

< cpp‎ | io‎ | manip
定义于头文件 <iomanip> |
template< class MoneyT > /*unspecified*/ put_money( const MoneyT& mon, bool intl = false ); | (C++11 起)

用于表达式 out << put_money(mon, intl) 时，转换货币值 mon 为 out 中当前感染的 locale 的 std::money_put 平面所指定的字符表示。

out << put_money(mon, intl) 中的插入操作表现为有格式输出函数 (FormattedOutputFunction) 。

参数

mon | - | 货币值， long double 或 std::basic_string 之一
intl | - | 若为 true 则使用国际通货字符串，否则使用通货符号

返回值

返回未指定类型的对象，使若 out 为 std::basic_ostream <CharT, Traits> 类型输出流的名称，则表达式 out << put_money(mon, intl) 表现如同执行下列代码：

typedef std::ostreambuf_iterator <CharT, Traits> Iter;
typedef std::money_put <CharT, Iter> MoneyPut;
const MoneyPut& mp = std::use_facet <MoneyPut>(out.getloc());
const Iter end = mp.put(Iter(out.rdbuf()), intl, out, out.fill(), mon);
if (end.failed())
out.setstate(std::ios::badbit);

示例

#include <iostream>
#include <iomanip>

int main()
{
    long double mon = 123.45; // 或 std::string mon = "123.45";

    std::cout.imbue(std::locale("en_US.UTF-8"));
    std::cout << std::showbase
              << "en_US: " << std::put_money(mon)
              << " or " << std::put_money(mon, true) << '\n';

    std::cout.imbue(std::locale("ru_RU.UTF-8"));
    std::cout << "ru_RU: " << std::put_money(mon)
              << " or " << std::put_money(mon, true) << '\n';

    std::cout.imbue(std::locale("ja_JP.UTF-8"));
    std::cout << "ja_JP: " << std::put_money(mon)
              << " or " << std::put_money(mon, true) << '\n';
}

可能的输出：

en_US: $1.23 or USD  1.23
ru_RU: 1.23 руб or 1.23 RUB
ja_JP: ￥123 or JPY  123

参阅

money_put | 格式化货币值为字符序列以输出 (类模板)
get_money (C++11) | 剖析货币值 (函数模板)


std::put_time

< cpp‎ | io‎ | manip
定义于头文件 <iomanip> |
template< class CharT > /*unspecified*/ put_time( const std::tm * tmb, const CharT* fmt ); | (C++11 起)

用于表达式 out << put_time(tmb, fmt) 时，按照格式字符串 fmt ，按照输出流 out 中当前感染的 locale 的 std::time_put 平面，转换来自给定的日历时间 tmb 的日期和时间信息为字符串，如同通过调用 std::strftime 、 std::wcsftime 或模拟（取决于 CharT ）。

参数

tmb - 指向从 localtime() 或 gmtime() 获得的日历时间结构体的指针
fmt - 指向指定转换格式的空终止 CharT 串的指针。

格式字符串由零或更多个说明符和通常字符（除 % ）构成。所有通常字符，包括空终止字符，都会被复制到输出字符串而不加修改。每个转换说明符都始于 % 字符，可选地跟随 E 或 O 修饰符（若本地环境不支持则忽略），后随决定修饰符行为的字符。下列修饰符格式可用：

转换
说明符 		解释 使用的域
% 写字面的 % 。完整转换说明必须是 %% 。
n
(C++11) 		写换行符
t
(C++11) 		写水平制表符
年
Y | 以 4 位十进制数写年。 | tm_year
EY
(C++11) 		以替用方式写年。例如在 ja_JP 本地环境中，以“平成23年”取代“2011年”。 tm_year
y | 写年的末 2 位十进制数（范围[00,99]）。 | tm_year
Oy
(C++11) 		以替用数字系统写年的末 2 位数字。例如在 ja_JP 本地环境中以“十一”取代“11”。 tm_year
Ey
(C++11) 		将年写作从本地环境的替用时期 %EC 的偏移（本地环境依赖）。 tm_year
C
(C++11) 		写年的首 2 位十进制数（范围 [00,99] ）。 tm_year
EC
(C++11) 		以本地环境的替用表示写年份基底（时期），例如 ja_JP 中的“平成”。 tm_year
G
(C++11) 		写基于 ISO 8601 的年，即是包含指定星期的年份。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
g
(C++11) 		写基于 ISO 8601 的年，即是包含指定星期年份，的后 2 位数（范围 [00,99] ）。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
月
b | 写缩略月名，例如 Oct （本地环境依赖）。 | tm_mon
h
(C++11) 		与 b 同意。 tm_mon
B | 写完整月名，例如 October （本地环境依赖）。 | tm_mon
m | 将月写作十进制数（范围 [01,12] ）。 | tm_mon
Om
(C++11) 		以替用数字系统写月。例如 ja_JP 本地环境中“十二”取代“12”。 tm_mon
星期
U | 以十进制数写年的星期（星期日是星期的首日）（范围 [00,53] ）。 | tm_year, tm_wday, tm_yday
OU
(C++11) 		以替用数值系统写如同用 %U 的年的星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
W | 以十进制数写年的星期（星期一是星期的首日）（范围 [00,53] ）。 | tm_year, tm_wday, tm_yday
OW
(C++11) 		以替用数值系统写如同用 %W 的年的第星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
V
(C++11) 		写 ISO 8601 的年的星期（范围[00,53]）。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
OV
(C++11) 		以替用数值系统写如同用 %V 的年的星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
年/月之日
j | 以十进制数写年的第几日（范围 [001,366] ）。 | tm_yday
d | 以十进制数写月的第几日（范围 [01,31] ）。 | tm_mday
Od
(C++11) 		以替用数字系统写零基的月的第几日。例如 ja_JP 本地环境中“二十七”取代“ 27 ”。

单字符前加空格。

 tm_mday
e
(C++11) 		以十进制数写月的第几日（范围[01,31]）。

单数字前加空格。

 tm_mday
Oe
(C++11) 		以替用数字系统写一基的月的第几日。例如 ja_JP 本地环境中“二十七”取代“27”。

单字符前加空格。

 tm_mday
星期之日
a | 写缩略的星期日期名，例如 Fri （本地环境依赖）。 | tm_wday
A | 写完整的星期日期名，例如 Friday （本地环境依赖）。 | tm_wday
w | 以十进制数写星期日期，其中星期日是 0 （范围 [0-6] ）。 | tm_wday
Ow
(C++11) 		用替用数字系统写星期日期，其中星期日是 0 。例如 ja_JP 本地环境中“二”取代“2”。 tm_wday
u
(C++11) 		十进制数写星期日期，其中星期一是 1 （ ISO 8601 格式）（范围 [1-7] ）。 tm_wday
Ou
(C++11) 		用替用数字系统写星期日期，其中星期一是 1 。例如 ja_JP 本地环境中“二”取代“2”。 tm_wday
时、分、秒
H | 以十进制数写时， 24 小时制（范围 [00-23] ）。 | tm_hour
OH
(C++11) 		以替用数字系统写 24 小时制的时。例如 ja_JP 本地环境中“十八”取代“18”。 tm_hour
I | 以十进制数写时， 12 小时制（范围 [01,12] ）。 | tm_hour
OI
(C++11) 		以替用数字系统写 12 小时制的时。例如 ja_JP 本地环境中“六”取代“6”。 tm_hour
M | 以十进制数写分（范围 [00,59] ）。 | tm_min
OM
(C++11) 		以替用数字系统写分。例如 ja_JP 本地环境中“二十五”取代“25”。 tm_min
S | 以十进制数写秒（范围 [00,60] ）。 | tm_sec
OS
(C++11) 		以替用数字系统写秒。例如 ja_JP 本地环境中“二十四”取代“24”。 tm_sec
其他
c | 写标准日期时间字符串。例如 Sun Oct 17 04:41:13 2010 （本地环境依赖）。 | 全部
Ec
(C++11) 		写替用日期时间字符串。例如 ja_JP 本地环境中“平成23年”取代“2011年”。 全部
x | 写本地化的日期表示（本地环境依赖）。 | 全部
Ex
(C++11) 		写替用日期表示。例如 ja_JP 本地环境中“平成23年”取代“2011年”。 全部
X | 写本地化的时间表示，例如 18:40:20 或 6:40:20 PM （本地环境依赖）。 | 全部
EX
(C++11) 		写替用时间表示（本地环境依赖）。 全部
D
(C++11) 		等价于"%m/%d/%y"。 tm_mon, tm_mday, tm_year
F
(C++11) 		等价于"%Y-%m-%d"（ ISO 8601 日期格式）。 tm_mon, tm_mday, tm_year
r
(C++11) 		写本地化的 12 小时制时间（本地环境依赖）。 tm_hour, tm_min, tm_sec
R
(C++11) 		等价于"%H:%M"。 tm_hour, tm_min
T
(C++11) 		等价于"%H:%M:%S"（ ISO 8601 时间格式）。 tm_hour, tm_min, tm_sec
p | 写本地化的 a.m. 或 p.m. （本地环境依赖）。 | tm_hour
z
(C++11) 		以 ISO 8601 格式（例如 -0430 ）写距 UTC 的偏移，或者倘若时区信息不可用则不写字符。 tm_isdst
Z | 写依赖本地环境的时区名或缩写，或者若时区信息不可用则不写字符。 | tm_isdst

返回值

返回为指定类型的对象，使得若 out 为 std::basic_ostream <CharT, Traits> 类型输出流的名称，则表达式 out << put_time(tmb, fmt) 表现为如同执行下列代码：

typedef std::ostreambuf_iterator <CharT, Traits> Iter;
typedef std::time_put <CharT, Iter> TimePut;
const TimePut& tp = std::use_facet <TimePut>(out.getloc());
const Iter end = tp.put(Iter(out.rdbuf()), out, out.fill(), tmb, fmt, fmt + Traits::length(fmt));
if (end.failed())
out.setstate( std::ios_base::badbit );

示例

#include <iostream>
#include <iomanip>
#include <ctime>

int main()
{
    std::time_t t = std::time(nullptr);
    std::tm tm = *std::localtime(&t);
    std::cout.imbue(std::locale("ru_RU.utf8"));
    std::cout << "ru_RU: " << std::put_time(&tm, "%c %Z") << '\n';
    std::cout.imbue(std::locale("ja_JP.utf8"));
    std::cout << "ja_JP: " << std::put_time(&tm, "%c %Z") << '\n';
}

输出：

ru_RU: Ср. 28 дек. 2011 10:21:16 EST
ja_JP: 2011年12月28日 10時21分16秒 EST

参阅

time_put | 格式化 std::tm 内容为字符序列以输出 (类模板)
get_time (C++11) | 剖析指定格式的日期/时间值 (函数模板)
strftime | 转换 tm 对象到自定义的文本表示 (函数)
wcsftime | 转换 tm 对象为定制的宽字符串文本表示 (函数)


std::quoted

< cpp‎ | io‎ | manip
定义于头文件 <iomanip>
template< class CharT >

/*unspecified*/ quoted(const CharT* s,

CharT delim=CharT('"'), CharT escape=CharT('\\'));
 (1) (C++14 起)
template< class CharT, class Traits, class Allocator >

/*unspecified*/ quoted(const std::basic_string <CharT, Traits, Allocator>& s,

CharT delim=CharT('"'), CharT escape=CharT('\\'));
 (2) (C++14 起)
template< class CharT, class Traits>

/*unspecified*/ quoted( std::basic_string_view <CharT, Traits> s,

CharT delim=CharT('"'), CharT escape=CharT('\\'));
 (3) (C++17 起)
template< class CharT, class Traits, class Allocator >

/*unspecified*/ quoted( std::basic_string <CharT, Traits, Allocator>& s,

CharT delim=CharT('"'), CharT escape=CharT('\\'));
 (4) (C++14 起)

允许插入或释出带引号字符串，例如在 CSV 或 XML 中找到者。

用于表达式 out << quoted(s, delim, escape) ，其中 out 为拥有等于 CharT 的 char_type 的输出流，对于重载 2-4 ，还拥有等于 Traits 的 traits_type 时，表现为有格式输出函数 (FormattedOutputFunction) ，它插入以如下方式构造的字符序列 seq 到 out ：

a) 首先，添加字符 delim 到序列
b) 然后添加每个来自 s 的字符，除了若下个要输出的字符等于 delim 或等于 escape （以流的 traits_type::eq 确定），则首先后附 escape 的额外副本
c) 最后，后附 delim 多一次到 seq

然后，若 seq.size() < out.width() ，则添加 out.width()-seq.size() 个填充字符 out.fill() 副本到序列的末尾（若 out.flags() 中设置了 ios_base::left ）或到序列的起始（所有其他情况下）。

最后，如同以调用 out.rdbuf()->sputn(seq, n) 输出来自每个结果序列的字符，其中 n= std::max (out.width(), seq.size()) ，并调用 out.width(0) 取消 std::setw 的效果，若存在。

4) 用于表达式 in >> quoted(s, delim, escape) 中，其中 in 是拥有等于 CharT 的 char_type 和等于 Traits 的 traits_type 输入流时，用 std::basic_istream::operator>> 按照下列规则从 in 释出字符：
a) 若首个释出的字符不等于 delim （以流的 traits_type::eq 确定），则简单地进行 in >> s 。
b) 否则（若首字符是分隔符）：
1) 关闭输入流上的 skipws 标志
2) 通过调用 s.clear() 清空目标字符串
3) 从 in 释出字符并后附字符到 s ，除了凡在释出 escape 字符时，忽略该字符并后附下个字符到 s 。 !in==true 时或找到未转义的 delim 字符时释出停止。
4) 舍弃最终（未转义）的 delim 字符。
5) 恢复输入流上的 skipws 标志为其原值。

参数

s | - | 要插入或释出的字符串
delim | - | 用作分隔符的字符，默认为 "
escape | - | 用作转义字符的字符，默认为 \

返回值

返回未指定类型对象，使得上述行为发生。

异常

若 operator>> 或 operator<< 抛出则抛出 std::ios_base::failure 。

示例

#include <iostream>
#include <iomanip>
#include <sstream>

int main()
{
    std::stringstream ss;
    std::string in = "String with spaces, and embedded \"quotes\" too";
    std::string out;

    auto show = [&](const auto& what) {
        &what == &in
            ?   std::cout << "read in     [" << in << "]\n"
                          << "stored as   [" << ss.str() << "]\n"
            :   std::cout << "written out [" << out << "]\n\n";
    };

    ss << std::quoted(in);
    show(in);
    ss >> std::quoted(out);
    show(out);

    ss.str(""); // clear the stream buffer

    in = "String with spaces, and embedded $quotes$ too";
    const char delim {'$'};
    const char escape {'%'};

    ss << std::quoted(in, delim, escape);
    show(in);
    ss >> std::quoted(out, delim, escape);
    show(out);
}

输出：

read in     [String with spaces, and embedded "quotes" too]
stored as   ["String with spaces, and embedded \"quotes\" too"]
written out [String with spaces, and embedded "quotes" too]

read in     [String with spaces, and embedded $quotes$ too]
stored as   [$String with spaces, and embedded %$quotes%$ too$]
written out [String with spaces, and embedded $quotes$ too]

参阅


std::resetiosflags

< cpp‎ | io‎ | manip
定义于头文件 <iomanip>
/*unspecified*/ resetiosflags( std::ios_base::fmtflags mask );

用于表达式 out << resetiosflags(mask) 或 in >> resetiosflags(mask) 中时，清除流 out 或 in 中 mask 所指定的所有格式标志。

参数

mask - 要清除的标志位掩码

返回值

返回未指定类型的对象，使得若 str 是 std::basic_ostream <CharT, Traits> 或 std::basic_istream <CharT, Traits> 类型的流名称，则表达式 str << resetiosflags(mask) 或 str >> resetiosflags(mask) 表现为如同执行下列代码：

str.setf( std::ios_base::fmtflags (0), mask);

示例

#include <sstream>
#include <iostream>
#include <iomanip>
int main()
{
    std::istringstream in("10 010 10 010 10 010");
    int n1, n2;
    in >> std::oct >> n1 >> n2;
    std::cout << "Parsing \"10 010\" with std::oct gives:  " << n1 << ' ' << n2 << '\n';
    in >> std::dec >> n1 >> n2;
    std::cout << "Parsing \"10 010\" with std::dec gives:  " << n1 << ' ' << n2 << '\n';
    in >> std::resetiosflags(std::ios_base::basefield) >> n1 >> n2;
    std::cout << "Parsing \"10 010\" with autodetect gives: " << n1 << ' ' << n2 << '\n';
}

输出：

Parsing "10 010" with std::oct gives:  8 8
Parsing "10 010" with std::dec gives:  10 10
Parsing "10 010" with autodetect gives: 10 8

参阅

setf | 设置特定格式标志 (std::ios_base 的公开成员函数)
setiosflags | 设置指定的 ios_base 标志 (函数)


std::setbase

< cpp‎ | io‎ | manip
定义于头文件 <iomanip>
/*unspecified*/ setbase( int base );

设置流的数值底。用于表达式 out << setbase(base) 或 in >> setbase(base) 时，取决于 base 的值，更改流 out 或 in 的 basefield 标志：

  • 值 16 设置 basefield 为 std::ios_base::hex
  • 值 8 设置 std::ios_base::oct
  • 值 10 设置 std::ios_base::dec 。

异于 8 、 10 或 16 的 base 值重置 basefield 为零，这对应十进制输出和依赖前缀的输入。

参数

base - basefield 的新值

返回值

返回未指定类型的对象，使得若 str 为 std::basic_ostream <CharT, Traits> 或 std::basic_istream <CharT, Traits> 类型的流名称，则表达式 str << setbase(base) 或 str >> setbase(base) 表现为如同执行下列代码：

str.setf(base ==  8 ? std::ios_base::oct :
            base == 10 ? std::ios_base::dec :
                base == 16 ? std::ios_base::hex :
                     std::ios_base::fmtflags(0),
         std::ios_base::basefield);

示例

#include <iostream>
#include <sstream>
#include <iomanip>
int main()
{
    std::cout << "Parsing string \"10 0x10 010\"\n";

    int n1, n2, n3;
    std::istringstream s("10 0x10 010");
    s >> std::setbase(16) >> n1 >> n2 >> n3;
    std::cout << "hexadecimal parse: " << n1 << ' ' << n2 << ' ' << n3 << '\n';

    s.clear();
    s.seekg(0);
    s >> std::setbase(0) >> n1 >> n2 >> n3;
    std::cout << "prefix-dependent parse: " << n1 << ' ' << n2 << ' ' << n3 << '\n';

    std::cout << "hex output: " << std::setbase(16)
              << std::showbase << n1 << ' ' << n2 << ' ' << n3 << '\n';
}

输出：

Parsing string "10 0x10 010"
hexadecimal parse: 16 16 16
prefix-dependent parse: 10 16 8
hex output: 0xa 0x10 0x8

参阅

dechexoct | 更改用于整数 I/O 的基数 (函数)
showbasenoshowbase | 控制是否使用前缀指示数值基数 (函数)


std::setfill

< cpp‎ | io‎ | manip
定义于头文件 <iomanip>
template< class CharT >
/*unspecified*/ setfill( CharT c );

用于表达式 out << setfill(c) 时，它设置流 out 的填充字符为 c 。

参数

c - 填充字符的新值

返回值

返回未指定类型对象，使得若 out 为 std::basic_ostream <CharT, Traits> 类型输出流的名称，则表达式 out << setfill(n) 表现如同执行下列代码：

out.fill(n);

注意

可用 std::ostream::fill 获得当前填充字符。

示例

#include <iostream>
#include <iomanip>
int main()
{
    std::cout << "default fill: " << std::setw(10) << 42 << '\n'
              << "setfill('*'): " << std::setfill('*')
                                  << std::setw(10) << 42 << '\n';
}

输出：

default fill:         42
setfill('*'): ********42

参阅

fill | 管理填充字符 (std::basic_ios<CharT,Traits> 的公开成员函数)
internalleftright | 设置填充字符的布置 (函数)
setw | 更改下个输入/输出域的宽度 (函数)


std::setiosflags

< cpp‎ | io‎ | manip
定义于头文件 <iomanip>
/*unspecified*/ setiosflags( std::ios_base::fmtflags mask );

用于表达式 out << setiosflags(mask) 或 in >> setiosflags(mask) 时，设置流 out 或 in 的所有格式标志为 mask 所指定者。

参数

mask - 要设置的位掩码标志

返回值

返回未指定类型的对象，使得若 str 为 std::basic_ostream <CharT, Traits> 或 std::basic_istream <CharT, Traits> 类型的流名称，则表达式 str << setiosflags(mask) 或 str >> setiosflags(mask) 表现为如同执行下列代码：

str.setf(mask);

Example

#include <iostream>
#include <iomanip>

int main()
{
    std::cout <<  std::resetiosflags(std::ios_base::dec)
              <<  std::setiosflags(  std::ios_base::hex
                                   | std::ios_base::uppercase
                                   | std::ios_base::showbase) << 42 << '\n';
}

输出：

0X2A

参阅

setf | 设置特定格式标志 (std::ios_base 的公开成员函数)
resetiosflags | 清除指定的 ios_base 标志 (函数)


std::setprecision

< cpp‎ | io‎ | manip
定义于头文件 <iomanip>
/*unspecified*/ setprecision( int n );

用于表达式 out << setprecision(n) 或 in >> setprecision(n) 时，设置流 out 或 in 的 precision 参数准确为 n 。

参数

n - 精度的新值

返回值

返回未指定类型的对象，使得若 str 是 std::basic_ostream <CharT, Traits> 类型的输出流名称或 std::basic_istream <CharT, Traits> 类型的输入流名称，则表达式 str << setprecision(n) 或 str >> setprecision(n) 表现为如同执行下列代码：

str.precision(n);

示例

#include <iostream>
#include <iomanip>
#include <cmath>
#include <limits>
int main()
{
    const long double pi = std::acos(-1.L);
    std::cout << "default precision (6): " << pi << '\n'
              << "std::setprecision(10): " << std::setprecision(10) << pi << '\n'
              << "max precision:         "
              << std::setprecision(std::numeric_limits<long double>::digits10 + 1)
              << pi << '\n';
}

输出：

default precision (6): 3.14159
std::setprecision(10): 3.141592654
max precision:         3.141592653589793239

参阅

fixedscientifichexfloatdefaultfloat (C++11)(C++11) | 更改用于浮点 I/O 的格式化 (函数)
precision | 管理浮点操作的精度 (std::ios_base 的公开成员函数)


std::setw

< cpp‎ | io‎ | manip
定义于头文件 <iomanip>
/*unspecified*/ setw( int n );

用于表达式 out << setw(n) 或 in >> setw(n) 时，设置流 out 或 in 的 width 参数准确为 n 。

参数

n - width 的新值

返回值

返回未指定类型对象，满足若 str 是 std::basic_ostream <CharT, Traits> 或 std::basic_istream <CharT, Traits> 类型流的名称，则表达式 str << setw(n) 或 str >> setw(n) 表现为如同执行下列代码：

str.width(n);

注意

若调用任何下列函数，则流的宽度属性将被设为零（表示“不指定”）：

  • 输入
  • operator>>(basic_istream&, basic_string&)
  • operator>>(basic_istream&, char*)
  • 输出
  • basic_ostream::operator<<() 的重载 1-7 （在 num_put::put() 的阶段 3 ）
  • operator<<(basic_ostream&, char) 和 operator<<(basic_ostream&, char*)
  • operator<<(basic_ostream&, basic_string&)
  • std::put_money （在 money_put::put() 内）
  • std::quoted （以输出流使用时）

此修改器在输入与输出上的准确效果在单独的 I/O 函数间有别，单独地描述于每个 operator<< 各 operator>> 重载的页面。

示例

#include <sstream>
#include <iostream>
#include <iomanip>

int main()
{
    std::cout << "no setw:" << 42 << '\n'
              << "setw(6):" << std::setw(6) << 42 << '\n'
              << "setw(6), several elements: " << 89 << std::setw(6) << 12 << 34 << '\n';
    std::istringstream is("hello, world");
    char arr[10];
    is >> std::setw(6) >> arr;
    std::cout << "Input from \"" << is.str() << "\" with setw(6) gave \""
              << arr << "\"\n";
}

输出：

no setw:42
setw(6):    42
setw(6), several elements: 89    1234
Input from "hello, world" with setw(6) gave "hello"

参阅

width | 管理域的宽度 (std::ios_base 的公开成员函数)
setfill | 更改填充字符 (函数模板)
internalleftright | 设置填充字符的布置 (函数)


std::showbase, std::noshowbase

< cpp‎ | io‎ | manip
定义于头文件 <ios> |
std::ios_base & showbase( std::ios_base & str ); | (1)
std::ios_base & noshowbase( std::ios_base & str ); | (2)

1) 如同以调用 str.setf( std::ios_base::showbase ) 启用流 str 中的 showbase 标志

2) 如同以调用 str.unsetf( std::ios_base::showbase ) 禁用流 str 中的 showbase 标志

这是 I/O 操纵符，可用如 out << std::showbase 的表达式对任何 std::basic_ostream 类型 out 的，或用如 in >> std::showbase 的表达式对任何 std::basic_istream 类型的 in 调用。

showbase 标志影响整数输出（见 std::num_put::put ）、货币输入（见 std::money_get::get ）和货币输出（见 std::money_put::put ）的行为。

参数

str - 到 I/O 流的引用

返回值

str （到操纵后的流的引用）

注意

按 std::num_put::put 中指定，整数输出中的 showbase 标志表现类似 std::printf 中的 # 格式指定符，这表示输出值为零时不添加数值底前缀。

示例

#include <sstream>
#include <locale>
#include <iostream>
#include <iomanip>
int main()
{
    // showbase 影响八进制和十六进制的输出
    std::cout << std::hex
              << "showbase: " << std::showbase << 42 << '\n'
              << "noshowbase: " << std::noshowbase << 42 << '\n';

    // 及货币值的输入和输出
    std::locale::global(std::locale("en_US.utf8"));
    long double val = 0;
    std::istringstream is("3.14");
    is >> std::showbase >> std::get_money(val);
    std::cout << "With showbase, parsing 3.14 as money gives " << val << '\n';
    is.seekg(0);
    is >> std::noshowbase >> std::get_money(val);
    std::cout << "Without showbase, parsing 3.14 as money gives " << val << '\n';
}

输出：

showbase: 0x2a
noshowbase: 2a
With showbase, parsing 3.14 as money gives 0
Without showbase, parsing 3.14 as money gives 314

参阅

resetiosflags | 清除指定的 ios_base 标志 (函数)
setiosflags | 设置指定的 ios_base 标志 (函数)


std::showpoint, std::noshowpoint

< cpp‎ | io‎ | manip
定义于头文件 <ios> |
std::ios_base & showpoint( std::ios_base & str ); | (1)
std::ios_base & noshowpoint( std::ios_base & str ); | (2)

启用或禁用浮点输出中的无条件小数点包含。在输入上无效果。

1) 如同用调用 str.setf( std::ios_base::showpoint ) 启用流 str 中的 showpoint 标志
2) 如同用调用 str.unsetf( std::ios_base::showpoint ) 禁用流 str 中的 showpoint 标志

这是一个 I/O 操纵符，可用如 out << std::showpoint 的表达式对任何 std::basic_ostream 类型的 out 或用如 in >> std::showpoint 的表达式对任何 std::basic_istream 类型的 in 调用。

由在输出时刻流中感染的 locale 的 numpunct 平面确定用作小数点的字符，如 std::num_put::put 中所描述。

参数

str - 到 I/O 流的引用

返回值

str （到操纵后的流的引用）

示例

#include <iostream>
int main()
{
    std::cout << "1.0 with showpoint: " << std::showpoint << 1.0 << '\n'
              << "1.0 with noshowpoint: " << std::noshowpoint << 1.0 << '\n';
}

输出：

1.0 with showpoint: 1.00000
1.0 with noshowpoint: 1

参阅

resetiosflags | 清除指定的 ios_base 标志 (函数)
setiosflags | 设置指定的 ios_base 标志 (函数)


std::showpos, std::noshowpos

< cpp‎ | io‎ | manip
定义于头文件 <ios> |
std::ios_base & showpos( std::ios_base & str ); | (1)
std::ios_base & noshowpos( std::ios_base & str ); | (2)

启用或禁用非负数输出中的正号 '+' 的显示。在输入上无效果。

1) 如同用调用 str.setf( std::ios_base::showpos ) 启用流 str 中的 showpos 标志 2) 如同用调用 str.unsetf( std::ios_base::showpos ) 禁用流 str 中的 showpos 标志

这是一个 I/O 操纵符，可用如 out << std::showpos 的表达式对任何 std::basic_ostream 类型的 out 或用如 in >> std::showpos 的表达式对任何 std::basic_istream 类型的 in 调用。

参数

str - 到 I/O 流的引用

返回值

str （到操纵后的流的引用）

示例

#include <iostream>
int main()
{
        std::cout << "showpos: " << std::showpos << 42 << ' ' << 3.14 << ' ' << 0 << '\n'
                  << "noshowpos: " << std::noshowpos << 42 << ' ' << 3.14 << ' ' << 0 << '\n';
}

输出：

showpos: +42 +3.14 +0
noshowpos: 42 3.14 0

参阅

resetiosflags | 清除指定的 ios_base 标志 (函数)
setiosflags | 设置指定的 ios_base 标志 (函数)


std::skipws, std::noskipws

< cpp‎ | io‎ | manip
定义于头文件 <ios> |
std::ios_base & skipws( std::ios_base & str ); | (1)
std::ios_base & noskipws( std::ios_base & str ); | (2)

启用或禁用有格式输入函数所做的跳过前导空白符（默认启用）。在输出上无效果。

1) 如同用调用 str.setf( std::ios_base::skipws ) 启用流 str 中的 skipws 标志
2) 如同用调用 str.unsetf( std::ios_base::skipws ) 禁用流 str 中的 skipws 标志

跳过空白符由 std::basic_istream::sentry 的构造函数进行，它读取并舍弃由流所感染的 locale 的 std::ctype 平面分类为空白符的字符。

这是一个 I/O 操纵符，可用如 out << std::noskipws 的表达式对任何 std::basic_ostream 类型的 out 或用如 in >> std::noskipws 的表达式对任何 std::basic_istream 类型的 in 调用。

参数

str - 到 I/O 流的引用

返回值

str （到操纵后的流的引用）

示例

#include <iostream>
#include <sstream>
int main()
{
    char c1, c2, c3;
    std::istringstream("a b c") >> c1 >> c2 >> c3;
    std::cout << "Default  behavior: c1 = " << c1 << " c2 = " << c2 << " c3 = " << c3 << '\n';
    std::istringstream("a b c") >> std::noskipws >> c1 >> c2 >> c3;
    std::cout << "noskipws behavior: c1 = " << c1 << " c2 = " << c2 << " c3 = " << c3 << '\n';
}

输出：

Default  behavior: c1 = a c2 = b c3 = c
noskipws behavior: c1 = a c2 =   c3 = b

参阅

resetiosflags | 清除指定的 ios_base 标志 (函数)
setiosflags | 设置指定的 ios_base 标志 (函数)
ws | 消耗空白符 (函数模板)


std::unitbuf, std::nounitbuf

< cpp‎ | io‎ | manip
定义于头文件 <ios> |
std::ios_base & unitbuf( std::ios_base & str ); | (1)
std::ios_base & nounitbuf( std::ios_base & str ); | (2)

启用或禁用任何输出操作后的自动冲入。在输入时无效果。

1) 如同用调用 str.setf( std::ios_base::unitbuf ) 启用流 str 中的 unitbuf 标志

2) 如同用调用 str.unsetf( std::ios_base::unitbuf ) 禁用流 str 中的 unitbuf 标志

这是一个 I/O 操纵符，可用如 out << std::unitbuf 的表达式对任何 std::basic_ostream 类型的 out 或用如 in >> std::unitbuf 的表达式对任何 std::basic_istream 类型的 in 调用。

注解

在 std::basic_ostream::sentry 对象的析构函数中进行冲入，若 str.flags() & std::ios_base::unitbuf 为 true 则析构函数调用 str.rdbuf()->pubsync() 。

标准输出对象 std::cerr 及 std::wcerr 默认已设置其 unitbuf 位。

参数

str - 到 I/O 流的引用

返回值

str （到操纵后的流的引用）

示例

无 std::unitbuf 或另一显式冲入，输出相同，但不实时出现。

#include <iostream>
#include <chrono>

template<typename Diff>
void log_progress(Diff d)
{
    std::cout << "..("
              << std::chrono::duration_cast<std::chrono::milliseconds>(d).count()
              << " ms)..";
}

int main()
{
    volatile int sink = 0;
    std::cout << std::unitbuf; // 启用自动冲入

    auto t1 = std::chrono::high_resolution_clock::now();
    for (int j = 0; j < 5; ++j)
    {
        for (int n = 0; n < 10000; ++n)
            for (int m = 0; m < 20000; ++m)
                sink += m * n; // 做一些工作
        auto now = std::chrono::high_resolution_clock::now();
        log_progress(now - t1);
    }
    std::cout << '\n';
}

输出：

..(450 ms)....(902 ms)....(1352 ms)....(1802 ms)....(2252 ms)..

参阅

flush | 冲洗输出流 (函数模板)
endl | 输出 '\n' 并冲洗输出流 (函数模板)


std::uppercase, std::nouppercase

< cpp‎ | io‎ | manip
定义于头文件 <ios> |
std::ios_base & uppercase( std::ios_base & str ); | (1)
std::ios_base & nouppercase( std::ios_base & str ); | (2)

启用浮点和十六进制整数输出中大写字符的使用。在输入时无效果。

1) 如同用调用 str.setf( std::ios_base::uppercase ) 启用流 str 中的 uppercase 标志

2) 如同用调用 str.unsetf( std::ios_base::uppercase ) 禁用流 str 中的 uppercase 标志

这是一个 I/O 操纵符，可用如 out << std::uppercase 的表达式对任何 std::basic_ostream 类型的 out 或用如 in >> std::uppercase 的表达式对任何 std::basic_istream 类型的 in 调用。

参数

str - 到 I/O 流的引用

返回值

str （到操纵后的流的引用）

示例

#include <iostream>
int main()
{
    std::cout << std::hex << std::showbase
              << "0x2a with uppercase: " << std::uppercase << 0x2a << '\n'
              << "0x2a with nouppercase: " << std::nouppercase << 0x2a << '\n'
              << "1e-10 with uppercase: " << std::uppercase << 1e-10 << '\n'
              << "1e-10 with nouppercase: " << std::nouppercase << 1e-10 << '\n';
}

输出：

0x2a with uppercase: 0X2A
0x2a with nouppercase: 0x2a
1e-10 with uppercase: 1E-10
1e-10 with nouppercase: 1e-10

参阅

resetiosflags | 清除指定的 ios_base 标志 (函数)
setiosflags | 设置指定的 ios_base 标志 (函数)


std::ws

< cpp‎ | io‎ | manip
定义于头文件 <istream>
template< class CharT, class Traits >
std::basic_istream <CharT,Traits>& ws( std::basic_istream <CharT, Traits>& is );

从输入流舍弃前导空白符。

表现为无格式输入函数 (UnformattedInputFunction) ，除了不修改 is.gcount() 。在构造并检查 sentry 对象后，从流释出并舍弃字符，直至出现任何下列条件之一：

  • 输入序列中出现文件尾条件（该情况下函数调用 setstate(eofbit) 但不设置 failbit ；若调用 ws 前已在 is 上设置 eofbit ，则不适用这条，该情况下 sentry 对象的构造会设置 failbit ）。
  • 输入序列中下个可用字符 c 不是以 std::isspace(c, is.getloc()) 确定的空白字符。不释出该非空白字符。

这是仅为输入的 I/O 操纵符，可用如 in >> std::ws 的表达式对任何 std::basic_istream 类型的 in 调用。

参数

is - 到输入流的引用

返回值

is （到释出连续空白符后的流的引用）

注意

若在调用前在流上设置了 eofbit ，则 sentry 对象的构造将设置 failbit 。

示例

#include <iostream>
#include <istream>
#include <sstream>
#include <string>

int main()
{
    std::istringstream s("     this is a test");
    std::string line;
    std::getline(s >> std::ws, line);
    std::cout << "ws + getline returns: \"" << line << "\"\n";
}

输出：

ws + getline returns: "this is a test"

参阅

ignore
 读且取走并舍弃字符，直至发现给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)


std::ostrstream

< cpp‎ | io
定义于头文件 <strstream> |
class ostrstream : public std::ostream | (C++98 中弃用)

类 ostrstream 实现基于数组的流上的输出操作。它实际上将原生数组 I/O 设备（ std::strstreambuf ）包装到 std::basic_ostream 的高层接口中。

ostrstream 的典型实现仅保有一个非导出的数据成员： std::strstreambuf 类型对象。

注意

在任何对 str() 的调用后，要求调用 freeze(false) 以允许析构函数在必要时解分配缓冲区。

在任何将结果用作 C 字符串的对 str() 调用前，缓冲区必须为空终止，典型地用 std::ends 。

ostrstream 从 C++98 起被弃用， std::ostringstream 和 boost::iostreams::array_sink 是推荐的替代品。

成员函数

(构造函数) | 构造 strstream ，可选地分配缓冲区 (公开成员函数)
(析构函数) [虚] | 析构 strstream ，可选地解分配缓冲区 (虚公开成员函数)
rdbuf | 获得指向关联 strstreambuf 的指针 (公开成员函数)
str | 访问输出缓冲区 (公开成员函数)
freeze | 禁用/启用自动解分配 (公开成员函数)
pcount | 获得写入的字符数 (公开成员函数)

继承自 std::basic_ostream

成员函数

有格式输出
operator<<
 插入带格式数据
(std::basic_ostream<CharT,Traits> 的公开成员函数)
无格式输出
put
 插入字符
(std::basic_ostream<CharT,Traits> 的公开成员函数)
write
 插入字符块
(std::basic_ostream<CharT,Traits> 的公开成员函数)
寻位
tellp
 返回输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
seekp
 设置输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
杂项
flush
 与底层存储设备同步
(std::basic_ostream<CharT,Traits> 的公开成员函数)

成员类

sentry
 为输出操作实现流准备的基本逻辑
(std::basic_ostream<CharT,Traits> 的公开成员类)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)


std::ostrstream::freeze

< cpp‎ | io‎ | ostrstream

void freeze(bool flag = true);

若流用动态分配的数组输出，则禁用（ flag == true ）或启用（ flag == false ）缓冲区的自动分配/解分配。等效地调用 rdbuf()->freeze(flag) 。

注意

调用 str() 后，动态流自动变为冻结。要求在退出创建此 ostrstream 对象于其中的作用域前调用 freeze(false) 。否则析构函数将泄露内存。还有，一旦到被冻结流的附加输出抵达分配的缓冲区结尾，则它可能被截断，这可能令缓冲区为非空终止。

参数

flag - 所欲状态

返回值

（无）

示例

#include <strstream>
#include <iostream>

int main()
{
    std::ostrstream dyn; // 动态分配的输出缓冲区
    dyn << "Test: " << 1.23; // 注意：无 std::ends ，以演示后附
    std::cout << "The output stream contains \"";
    std::cout.write(dyn.str(), dyn.pcount()) << "\"\n";
    // 流现在因 str() 冻结
    dyn << " More text"; // 到冻结流的输出可能被截断
    std::cout << "The output stream contains \"";
    std::cout.write(dyn.str(), dyn.pcount()) << "\"\n";
    dyn.freeze(false); // 必须调用 freeze(false) ，否则析构函数将泄露

    std::ostrstream dyn2; // 动态分配的输出缓冲区
    dyn2 << "Test: " << 1.23; // 注意：无 std::ends
    std::cout << "The output stream contains \"";
    std::cout.write(dyn2.str(), dyn2.pcount()) << "\"\n";
    dyn2.freeze(false);   // str() 后解冻流
    dyn2 << " More text" << std::ends; // 输出将不被截断（缓冲区成长）
    std::cout << "The output stream contains \"" << dyn2.str() << "\"\n";
    dyn2.freeze(false); // 必须调用 freeze(false) ，否则析构函数将泄露
}

可能的输出：

The output stream contains "Test: 1.23"
The output stream contains "Test: 1.23 More "
The output stream contains "Test: 1.23"
The output stream contains "Test: 1.23 More text"

参阅

freeze
 设置/清除缓冲区的冻结状态
(std::strstreambuf 的公开成员函数)


std::ostrstream::ostrstream

< cpp‎ | io‎ | ostrstream
ostrstream(); | (1)
ostrstream(char* s, int n, std::ios_base::openmode mode = std::ios_base::out ); | (2)

构造新的输出 strstream 及其底层 std::strstreambuf 。

1) 默认构造底层 std::strstreambuf ，这创建动态成长的缓冲区，并以该 strstreambuf 成员的地址初始化基类。
2) 以底层 std::strstreambuf 成员的地址初始化基类，该成员以二种可能方式之一初始化，两者都写入用户提供的数组：
a) 若 mode 中未设置 app 位，则通过调用 strstreambuf(s, n, s) 构造缓冲。若首元素为 s 所指向的数组中元素少于 n 个，则行为未定义。
b) 若 mode 中设置了 app 位，则通过调用 strstreambuf(s, n, s + std::strlen (s)) 构造缓冲。若首元素为 s 所指向的数组中元素少于 n 个，或若数组不含合法的空终止字符序列，则行为未定义。

参数

s - 用作输出缓冲区的 char 数组
n - 用作输出缓冲区的数组大小
mode - 指定流打开模式。它是位掩码类型，定义下列常量（尽管只使用 app ）：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

示例

#include <iostream>
#include <strstream>

int main()
{
    std::ostrstream s1; // 动态缓冲区
    s1 << 1 << ' ' << 3.14 << " example\n" << std::ends;
    std::cout << s1.str();
    s1.freeze(false);

    char arr[15] = "Hello";

    std::ostrstream s2(arr, sizeof arr, std::ios_base::app);
    s2 << ", world!" << std::ends;
    std::cout << s2.str() << '\n';
    std::cout << arr << '\n'; // 流使用提供的数组
}

输出：

1 3.14 example
Hello, world!
Hello, world!

参阅

(构造函数) | 构造 strstreambuf 对象 (std::strstreambuf 的公开成员函数)
(构造函数) | 构造 strstream ，可选地分配缓冲区 (std::istrstream 的公开成员函数)
(构造函数) | 构造 strstream ，可选地分配缓冲区 (std::strstream 的公开成员函数)


std::ostrstream::pcount

< cpp‎ | io‎ | ostrstream

int pcount() const;

返回输出于关联 std::strstreambuf 的放置区的字符数。等效地调用 rdbuf()->pcount() 。

参数

（无）

返回值

放置区中的字符数，或若未输出则为零。

示例

#include <strstream>
#include <iostream>

int main()
{
    std::ostrstream dyn; // 动态分配的输出缓冲区
    dyn << "Test: " << 1.23 << std::ends;
    std::cout << "The size of the output is " << dyn.pcount()
              << " and it holds \"" << dyn.str() << "\"\n";
    dyn.freeze(false);

    char buf[10];
    std::ostrstream user(buf, 10); // 用户提供的输出缓冲区
    user << 1.23; // 注意：无 std::ends
    std::cout.write(buf, user.pcount());
    std::cout << '\n';
}

输出：

The size of the output is 11 and it holds "Test: 1.23"
1.23

参阅

pcount
 返回输出序列中下一位置指针减起始指针：写入字符数
(std::strstreambuf 的公开成员函数)


std::ostrstream::rdbuf

< cpp‎ | io‎ | ostrstream

strstreambuf* rdbuf() const;

返回指向关联 std::strstreambuf 的指针，转型走其常性（无关乎成员函数上的 const 限定符）。

参数

（无）

返回值

指向关联 std::strsteambuf 的指针，常性被转型走。

示例

#include <strstream>
int main()
{
    const std::ostrstream buf;
    std::strstreambuf* ptr = buf.rdbuf();
}


std::ostrstream::str

< cpp‎ | io‎ | ostrstream

char* str();

冻结缓冲区后，返回指向其起始的指针。等效地调用 rdbuf()->str() 。

参数

（无）

返回值

指向关联 std::strsteambuf 中缓冲区起始的指针，或若无可用缓冲区则为空指针。

注解

若要将结果用作 C 字符串，则调用 str() 前流缓冲区必须为空终止。常规输出，例如 stream << 1.2 不存储空终止符，必须显式后附它，典型地用操纵符 std::ends 。

调用 str() 后，动态流变为冻结。要求在退出创建此 ostrstream 对象于其中的作用域前调用 freeze(false) 。否则析构函数将泄露内存。还有，一旦到被冻结流的附加输出抵达分配的缓冲区结尾，则它可能被截断，这可能令缓冲区为非空终止。

示例

#include <strstream>
#include <iostream>

int main()
{
    std::ostrstream dyn; // 动态分配的输出缓冲区
    dyn << "Test: " << 1.23; // 不添加 std::ends 以演示后附行为
    std::cout << "The output stream holds \"";
    std::cout.write(dyn.str(), dyn.pcount()) << "\"\n";
    // the stream is now frozen due to str()
    dyn << " More text" << std::ends;
    std::cout << "The output stream holds \"";
    std::cout.write(dyn.str(), dyn.pcount()) << "\"\n";
    dyn.freeze(false);
}

可能的输出：

The stream holds "Test: 1.23"
The stream holds "Test: 1.23 More "

参阅

str
 标记缓冲为冻结并返回输入序列的起始指针
(std::strstreambuf 的公开成员函数)


std::ostrstream::~ostrstream

< cpp‎ | io‎ | ostrstream
virtual ~ostrstream();

销毁 std::ostrstream 对象，这亦销毁成员 std::strstreambuf ，而可能调用解分配函数，若底层缓冲区为动态分配且不被冻结。

参数

（无）

注意

若在动态流上调用 str() 而未在之后调用 freeze(false) ，则此析构函数泄露内存。

示例

#include <strstream>
#include <iostream>

int main()
{
    {
        std::ostrstream s; // 动态缓冲区
        s << 1.23;
        std::cout << s.str() << '\n';
        s.freeze(false);
    } // 调用析构函数，解分配缓冲区

    {
        std::ostrstream s;
        s << 1.23;
        std::cout << s.str() << '\n';
//        buf.freeze(false);
    } // 调用析构函数，内存泄露
}

输出：

1.23
1.23


std::streamoff

< cpp‎ | io
定义于头文件 <ios>
typedef /*unspecified*/ streamoff;

std::streamoff 是足以表示操作系统所支持的最大可能文件大小的有符号整数类型。它典型为对 long long 的 typedef 。

它用于表示从流位置（ std::fpos 类型值）的偏移。某些 I/O 库函数亦用值为 -1 的 std::streamoff 表示错误条件。

与 std::fpos 的关系

  • 二个 std::fpos 对象间的差是 std::streamoff 类型值
  • std::streamoff 类型值可以从 std::fpos 增加或减去，产出不同的 std::fpos 。
  • std::fpos 类型值可隐式转换为 std::streamoff （转换结果为从文件开始的偏移）。
  • std::fpos 类型值可从 std::streamoff 类型值构造

参阅

fpos | 表示流或文件中的绝对位置 (类模板)
seekg | 设置输入位置指示器 (std::basic_istream<CharT,Traits> 的公开成员函数)
seekp | 设置输出位置指示器 (std::basic_ostream<CharT,Traits> 的公开成员函数)


std::streamsize

< cpp‎ | io
定义于头文件 <ios>
typedef /*unspecified*/ streamsize;

类型 std::streamsize 是用于表示 I/O 操作中转移字符数或 I/O 缓冲区大小的有符号整数类型。它被用作 std::size_t 的有符号对应，类似 POSIX 类型 ssize_t 。

决不使用 std::streamsize 的负值，除了在 std::strstreambuf 的构造函数中。

参阅

gcount | 返回上次无格式输出操作所取走的字符数量 (std::basic_istream<CharT,Traits> 的公开成员函数)
ignore | 读且取走并舍弃字符，直至发现给定字符 (std::basic_istream<CharT,Traits> 的公开成员函数)
read | 读并取走一块字符 (std::basic_istream<CharT,Traits> 的公开成员函数)
write | 插入字符块 (std::basic_ostream<CharT,Traits> 的公开成员函数)


std::strstream

< cpp‎ | io
定义于头文件 <strstream> |
class strstream : public std::iostream | (C++98 中弃用)

类 strstream 实现基于数组的流上的输入和输出操作。它实际上将原生数组 I/O 设备（ std::strstreambuf ）包装到 std::basic_iostream 的高层接口中。

strstream 的典型实现仅保有一个非导出的数据成员： std::strstreambuf 类型对象。

注意

在任何对 str() 的调用后，要求调用 freeze(false) 以允许析构函数在必要时解分配缓冲区。

在任何将结果用作 C 字符串的对 str() 调用前，缓冲区必须为空终止，典型地由 std::ends 。

strstream 从 C++98 起被弃用， std::stringstream 和 boost::iostreams::array 是推荐的替代品。

成员函数

(构造函数) | 构造 strstream ，可选地分配缓冲区 (公开成员函数)
(析构函数) [虚] | 析构 strstream ，可选地解分配缓冲区 (虚公开成员函数)
rdbuf | 获得指向关联 strstreambuf 的指针 (公开成员函数)
str | 访问输出缓冲区 (公开成员函数)
freeze | 禁用/启用自动解分配 (公开成员函数)
pcount | 获得写入的字符数 (公开成员函数)

继承自 std::basic_istream

成员函数

有格式输入
operator>>
 提取带格式数据
(std::basic_istream<CharT,Traits> 的公开成员函数)
无格式输入
get
 从流中读并取走（移除类似指针向下一个元素移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
peek
 仅读出但不取走（不移除类似指针并未移动）一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
unget
 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
putback
 往输入流中退回一个字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
getline
 一直读并取走字符，直至找到给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
ignore
 读且取走并舍弃字符，直至发现给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
read
 读并取走一块字符
(std::basic_istream<CharT,Traits> 的公开成员函数)
readsome
 读并取走已经可用的字符块
(std::basic_istream<CharT,Traits> 的公开成员函数)
gcount
 返回上次无格式输出操作所取走的字符数量
(std::basic_istream<CharT,Traits> 的公开成员函数)
寻位
tellg
 返回输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
seekg
 设置输入位置指示器
(std::basic_istream<CharT,Traits> 的公开成员函数)
杂项
sync
 与底层存储设备同步
(std::basic_istream<CharT,Traits> 的公开成员函数)

成员类

sentry
 实现为输出操作准备流的基本逻辑
(std::basic_istream<CharT,Traits> 的公开成员类)

继承自 std::basic_ostream

成员函数

有格式输出
operator<<
 插入带格式数据
(std::basic_ostream<CharT,Traits> 的公开成员函数)
无格式输出
put
 插入字符
(std::basic_ostream<CharT,Traits> 的公开成员函数)
write
 插入字符块
(std::basic_ostream<CharT,Traits> 的公开成员函数)
寻位
tellp
 返回输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
seekp
 设置输出位置指示器
(std::basic_ostream<CharT,Traits> 的公开成员函数)
杂项
flush
 与底层存储设备同步
(std::basic_ostream<CharT,Traits> 的公开成员函数)

成员类

sentry
 为输出操作实现流准备的基本逻辑
(std::basic_ostream<CharT,Traits> 的公开成员类)

继承自 std::basic_ios

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

状态函数
good
 检查是否没有发生错误，例如是否可执行I/O操作
(std::basic_ios<CharT,Traits> 的公开成员函数)
eof
 检查是否到达了文件末尾
(std::basic_ios<CharT,Traits> 的公开成员函数)
fail
 检查是否发生了可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
bad
 检查是否已发生不可恢复的错误
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
operator void*operator bool
(C++11 前)(C++11 起)
 检查是否没有发生错误（!fail()的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdstate
 返回状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
setstate
 设置状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
clear
 修改状态标志
(std::basic_ios<CharT,Traits> 的公开成员函数)
格式化
copyfmt
 复制格式化信息
(std::basic_ios<CharT,Traits> 的公开成员函数)
fill
 管理填充字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
杂项
exceptions
 管理异常掩码
(std::basic_ios<CharT,Traits> 的公开成员函数)
imbue
 设置本地环境
(std::basic_ios<CharT,Traits> 的公开成员函数)
rdbuf
 管理相关的流缓冲区
(std::basic_ios<CharT,Traits> 的公开成员函数)
tie
 管理绑定的流
(std::basic_ios<CharT,Traits> 的公开成员函数)
narrow
 窄化字符
(std::basic_ios<CharT,Traits> 的公开成员函数)
widen
 拓宽字符
(std::basic_ios<CharT,Traits> 的公开成员函数)

继承自 std::ios_base

成员函数

格式化
flags
 管理格式标志
(std::ios_base 的公开成员函数)
setf
 设置特定格式标志
(std::ios_base 的公开成员函数)
unsetf
 清除特定格式的标志
(std::ios_base 的公开成员函数)
precision
 管理浮点操作的精度
(std::ios_base 的公开成员函数)
width
 管理域的宽度
(std::ios_base 的公开成员函数)
本地环境
imbue
 设置本地环境
(std::ios_base 的公开成员函数)
getloc
 返回当前本地环境
(std::ios_base 的公开成员函数)
内部可扩展数组
xalloc
[静态]
 返回能安全用作 pword() 和 iword() 下标的程序范围内独有的整数
(std::ios_base 的公开静态成员函数)
iword
 如果有必要的话，调整私有存储的大小，并且访问位于提供的下标的long元素
(std::ios_base 的公开成员函数)
pword
 若需要则重置私有存储的大小，并访问位于指定下标的 void* 元素
(std::ios_base 的公开成员函数)
杂项
register_callback
 注册事件回调函数
(std::ios_base 的公开成员函数)
sync_with_stdio
[静态]
 设置C++和C的IO库是否可以互操作
(std::ios_base 的公开静态成员函数)
成员类
failure
 流异常
(std::ios_base 的公开成员类)
Init
 初始化标准流对象
(std::ios_base 的公开成员类)

成员类型和常量
类型 解释
openmode
 流打开模式类型

亦定义下列常量：

常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

(typedef)
fmtflags
 格式化标志类型

亦定义下列常量：

常量 | 解释
dec | 为整数 I/O 使用十进制底：见 std::dec
oct | 为整数 I/O 使用八进制底：见 std::oct
hex | 为整数 I/O 使用十六进制底：见 std::hex
basefield | dec|oct|hex 。适用于掩码运算
left | 左校正（添加填充字符到右）：见 std::left
right | 右校正（添加填充字符到左）：见 std::right
internal | 内部校正（添加填充字符到内部选定点）：见 std::internal
adjustfield | left|right|internal 。适用于掩码运算
scientific | 用科学记数法生成浮点类型，或若与 fixed 组合则用十六进制记法：见 std::scientific
fixed | 用定点记法生成浮点类型，或若与 scientific 组合则用十六进制记法：见 std::fixed
floatfield | scientific|fixed 。适用于掩码运算
boolalpha | 以字母数字格式插入并释出 bool 类型：见 std::boolalpha
showbase | 生成为整数输出指示数字基底的前缀，货币 I/O 中要求现金指示器：见 std::showbase
showpoint | 无条件为浮点数输出生成小数点字符：见 std::showpoint
showpos | 为非负数值输出生成 + 字符，见 std::showpos
skipws | 在具体输入操作前跳过前导空白符：见 std::skipws
unitbuf | 在每次输出操作后冲入输出：见 std::unitbuf
uppercase | 在具体输出的输出操作中以大写等价替换小写字符：见 std::uppercase

(typedef)
iostate
 流状态类型

亦定义下列常量：

常量 | 解释
goodbit | 无错误
badbit | 不可恢复的流错误
failbit | 输入/输出操作失败（格式化或提取错误）
eofbit | 关联的输出序列已抵达文件尾

(typedef)
seekdir
 寻位方向类型

亦定义下列常量：

常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置

(typedef)
event
 指定事件类型
(枚举)
event_callback
 回调函数类型
(typedef)


std::strstream::freeze

< cpp‎ | io‎ | strstream

void freeze(bool flag = true);

若流用动态分配的数组输出，则禁用（ flag == true ）或启用（ flag == false ）缓冲区的自动分配/解分配。等效地调用 rdbuf()->freeze(flag) 。

注意

调用 str() 后，动态流自动变为冻结。要求在退出创建此 strstream 对象于其中的作用域前调用 freeze(false) 。否则析构函数将泄露内存。还有，一旦到被冻结流的附加输出抵达分配的缓冲区结尾，则它可能被截断，这可能令缓冲区为非空终止。

参数

flag - 所欲状态

返回值

（无）

示例

#include <strstream>
#include <iostream>

int main()
{
    std::strstream dyn; // 动态分配的输出缓冲区
    dyn << "Test: " << 1.23; // 注意：无 std::ends ，以演示后附
    std::cout << "The output stream contains \"";
    std::cout.write(dyn.str(), dyn.pcount()) << "\"\n";
    // 流现在因 str() 冻结
    dyn << " More text"; // 到冻结流的输出可能被截断
    std::cout << "The output stream contains \"";
    std::cout.write(dyn.str(), dyn.pcount()) << "\"\n";
    dyn.freeze(false); // 必须调用 freeze(false) ，否则析构函数将泄露

    std::strstream dyn2; // 动态分配的输出缓冲区
    dyn2 << "Test: " << 1.23; // 注意：无 std::ends
    std::cout << "The output stream contains \"";
    std::cout.write(dyn2.str(), dyn2.pcount()) << "\"\n";
    dyn2.freeze(false);   // str() 后解冻流
    dyn2 << " More text" << std::ends; // 输出将不被截断（缓冲区成长）
    std::cout << "The output stream contains \"" << dyn2.str() << "\"\n";
    dyn2.freeze(false); // 必须调用 freeze(false) ，否则析构函数将泄露
}

可能的输出：

The output stream contains "Test: 1.23"
The output stream contains "Test: 1.23 More "
The output stream contains "Test: 1.23"
The output stream contains "Test: 1.23 More text"

参阅

freeze
 设置/清除缓冲区的冻结状态
(std::strstreambuf 的公开成员函数)


std::strstream::pcount

< cpp‎ | io‎ | strstream

int pcount() const;

返回输出于关联 std::strstreambuf 的放置区的字符数。等效地调用 rdbuf()->pcount() 。

参数

（无）

返回值

放置区中的字符数，或若未输出则为零。

示例

#include <strstream>
#include <iostream>

int main()
{
    std::strstream dyn; // 动态分配的输出缓冲区
    dyn << "Test: " << 1.23 << std::ends;
    std::cout << "The size of the output is " << dyn.pcount()
              << " and it holds \"" << dyn.str() << "\"\n";
    dyn.freeze(false);

    char buf[10];
    std::strstream user(buf, 10); // 用户提供的输出缓冲区
    user << 1.23; // 注意：无 std::ends
    std::cout.write(buf, user.pcount());
    std::cout << '\n';
}

输出：

The size of the output is 11 and it holds "Test: 1.23"
1.23

参阅

pcount
 返回输出序列中下一位置指针减起始指针：写入字符数
(std::strstreambuf 的公开成员函数)


std::strstream::rdbuf

< cpp‎ | io‎ | strstream

strstreambuf* rdbuf() const;

返回指向关联 std::strstreambuf 的指针，转型走其常性（无关乎成员函数上的 const 限定符）。

参数

（无）

返回值

指向关联 std::strsteambuf 的指针，常性被转型走。

示例

#include <strstream>
int main()
{
    const std::strstream buf;
    std::strstreambuf* ptr = buf.rdbuf();
}


std::strstream::str

< cpp‎ | io‎ | strstream

char* str();

冻结缓冲区后，返回指向其起始的指针。等效地调用 rdbuf()->str() 。

参数

（无）

返回值

指向关联 std::strsteambuf 中缓冲区起始的指针，或若无可用缓冲区则为空指针。

注解

若要将结果用作 C 字符串，则调用 str() 前流缓冲区必须为空终止。常规输出，例如 stream << 1.2 不存储空终止符，必须显式后附它，典型地用操纵符 std::ends 。

调用 str() 后，动态流变为冻结。要求在退出创建此 strstream 对象于其中的作用域前调用 freeze(false) 。否则析构函数将泄露内存。还有，一旦到被冻结流的附加输出抵达分配的缓冲区结尾，则它可能被截断，这可能令缓冲区为非空终止。

示例

#include <strstream>
#include <iostream>

int main()
{
    std::strstream dyn; // 动态分配的输出缓冲区
    dyn << "Test: " << 1.23; // 不添加 std::ends 以演示后附行为
    std::cout << "The output stream holds \"";
    std::cout.write(dyn.str(), dyn.pcount()) << "\"\n";
    // the stream is now frozen due to str()
    dyn << " More text" << std::ends;
    std::cout << "The output stream holds \"";
    std::cout.write(dyn.str(), dyn.pcount()) << "\"\n";
    dyn.freeze(false);
}

可能的输出：

The stream holds "Test: 1.23"
The stream holds "Test: 1.23 More "

参阅

str
 标记缓冲为冻结并返回输入序列的起始指针
(std::strstreambuf 的公开成员函数)


std::strstream::strstream

< cpp‎ | io‎ | strstream
strstream();
 (1)
strstream(char* s, int n, std::ios_base::openmode mode
= std::ios_base::in | std::ios_base::out );
 (2)

构造新的输入/输出 strstream 及其底层 std::strstreambuf 。

1) 默认构造底层 std::strstreambuf ，这创建动态成长的缓冲区，并以该 strstreambuf 成员的地址初始化基类。
2) 以底层 std::strstreambuf 成员的地址初始化基类，该成员以二种可能方式之一初始化，两者都使用用户提供的数组：
a) 若 mode 中未设置 app 位，则通过调用 strstreambuf(s, n, s) 构造缓冲。若首元素为 s 所指向的数组中元素少于 n 个，则行为未定义。
b) 若 mode 中设置了 app 位，则通过调用 strstreambuf(s, n, s + std::strlen (s)) 构造缓冲。若首元素为 s 所指向的数组中元素少于 n 个，或若数组不含合法的空终止字符序列，则行为未定义。

参数

s - 用作输出缓冲区的 char 数组
n - 用作输出缓冲区的数组大小
mode - 指定流打开模式。它是位掩码类型，定义下列常量（尽管只使用 app ）：
常量 | 解释
app | 每次写入前寻位到流结尾
binary | 以二进制模式打开
in | 为读打开
out | 为写打开
trunc | 在打开时舍弃流的内容
ate | 打开后立即寻位到流结尾

示例

#include <iostream>
#include <strstream>
#include <string>

int main()
{
    // dynamic buffer
    std::strstream s1; // 动态缓冲区
    s1 << 1 << ' ' << 3.14 << " example" << std::ends;
    std::cout << "buffer holds '" << s1.str() << "'\n";
    s1.freeze(false);

    int n; double d;
    std::string w;
    s1 >> n >> d >> w;
    std::cout << "Read back: n = " << n
              << " d = " << d
              << " w = '" << w << "'\n";

    // 静态缓冲区
    char arr[20] = "-1 -3.14 ";
    std::strstream s2(arr, sizeof arr, std::ios_base::app);
    s2 << "another" << std::ends;
    std::cout << "buffer holds: '" << s2.str() << "'\n";
    s2 >> n >> d >> w;
    std::cout << "Read back: n = " << n
              << " d = " << d
              << " w = '" << w << "'\n";
}

输出：

buffer holds '1 3.14 example'
Read back: n = 1 d = 3.14 w = 'example'
buffer holds: '-1 -3.14 another'
Read back: n = -1 d = -3.14 w = 'another'

参阅

(构造函数) | 构造 strstreambuf 对象 (std::strstreambuf 的公开成员函数)
(构造函数) | 构造 strstream ，可选地分配缓冲区 (std::istrstream 的公开成员函数)
(构造函数) | 构造 strstream ，可选地分配缓冲区 (std::ostrstream 的公开成员函数)


std::strstream::~strstream

< cpp‎ | io‎ | strstream
virtual ~strstream();

销毁 std::strstream 对象，这亦销毁成员 std::strstreambuf ，而这可能调用解分配函数，若底层缓冲区为动态分配且非冻结。

参数

（无）

注意

若在动态流上调用了 str() 而之后未调用 freeze(false) ，则此析构函数泄露内存。

示例

#include <strstream>
#include <iostream>

int main()
{
    {
        std::ostrstream s; // 动态缓冲区
        s << 1.23 << std::ends;
        std::cout << s.str() << '\n';
        s.freeze(false);
    } // 调用析构函数，解分配缓冲区

    {
        std::ostrstream s;
        s << 1.23 << std::ends;
        std::cout << s.str() << '\n';
//        buf.freeze(false);
    } // 调用析构函数，内存泄漏

    {
        std::istrstream s("1.23"); // 常量缓冲区
        double d;
        s >> d;
        std::cout << d << '\n';
    } // 调用析构函数，无需解分配
}

输出：

1.23
1.23
1.23


std::strstreambuf

< cpp‎ | io
定义于头文件 <strstream> |
class strstreambuf : public std::basic_streambuf <char> | (C++98 中弃用)

std::strstreambuf 是关联字符序列为字符数组的 std::basic_streambuf ，该数组可为常量（例如字符串字面量）、可修改但非动态或动态，该情况下可以允许 std::strstreambuf 重分配数组以适应输出（例如通过调用 delete[] 和 new[] 或用户提供函数）。

std::strstreambuf 的典型实现保有四个私有数据成员：

1) 缓冲区状态，为位掩码类型，能表示四个值“已分配”（析构函数将解分配）、“常量”（不允许输出）、“动态”（输出将解分配）或“冻结”（不允许解分配和重分配）的任何组合；
2) 分配的缓冲区大小（缓冲区的起点不必是特别的数据成员，它可存储于继承的指针 eback() ）；
3) 指向用户提供的分配函数的指针；
4) 指向用户提供的解分配函数的指针。

注意

在任何以动态缓冲区在流上调用 str() 后，要求调用 freeze(false) 以允许 strstreambuf 的析构函数在需要时解分配缓冲区。

成员函数

公开成员函数
(构造函数)
 构造 strstreambuf 对象
(公开成员函数)
(析构函数)
[虚]
 销毁 strstreambuf 对象，可选地解分配字符数组
(虚公开成员函数)
freeze
 设置/清除缓冲区的冻结状态
(公开成员函数)
str
 标记缓冲为冻结并返回输入序列的起始指针
(公开成员函数)
pcount
 返回输出序列中下一位置指针减起始指针：写入字符数
(公开成员函数)

受保护成员函数
underflow
[虚]
 从输入序列读取一个字符而不前进下一位置指针
(虚受保护成员函数)
pbackfail
[虚]
 回退输入序列以反获取一个字符
(虚受保护成员函数)
overflow
[虚]
 后附字符到输出序列，可能重分配或初始地分配缓冲区，若它为动态且未被冻结
(虚受保护成员函数)
setbuf
[虚]
 试图以数组替换受控制字符序列
(虚受保护成员函数)
seekoff
[虚]
 用相对寻址重寻位输入序列、输出序列或两者中的下一位置指针
(虚受保护成员函数)
seekpos
[虚]
 用绝对寻址重寻位输入序列、输出序列或两者中的下一位置指针
(虚受保护成员函数)

继承自 std::basic_streambuf

成员类型

成员类型 | 定义
char_type | CharT
traits_type | Traits ；若 Traits::char_type 不是 CharT 则程序非良构。
int_type | Traits::int_type
pos_type | Traits::pos_type
off_type | Traits::off_type

成员函数

(析构函数)
[虚]
 析构 basic_streambuf 对象
(std::basic_streambuf<CharT,Traits> 的虚公开成员函数)
本地环境
pubimbue
 调用 imbue()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
getloc
 获得相关本地环境的副本
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
寻位
pubsetbuf
 调用 setbuf()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubseekoff
 调用 seekoff()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubseekpos
 调用 seekpos()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
pubsync
 调用 sync()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
获取区
in_avail
 获得获取区中立即可用的字符数
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
snextc
 令输入序列前进，读取一个字符而不再次前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sbumpcstossc
(C++17 中移除)
 从输入序列读取一个字符并令序列前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sgetc
 从输入序列读取一个字符，而不令序列前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sgetn
 调用 xsgetn()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
放置区
sputc
 写一个字符到放置区域，并令 next 指针前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sputn
 调用 xsputn()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
回放
sputbackc
 在输入序列中放回一个字符
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
sungetc
 回移一位输出序列中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的公开成员函数)

受保护成员函数

(构造函数)
 构造 basic_streambuf 对象
(受保护成员函数)
operator=
(C++11)
 替换 basic_streambuf 对象
(受保护成员函数)
swap
(C++11)
 交换二个 basic_streambuf 对象
(受保护成员函数)
本地环境
imbue
[虚]
 更改关联的本地环境
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
寻位
setbuf
[虚]
 若容许则以用户定义数组替换缓冲区
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
seekoff
[虚]
 用相对寻址重定位输入序列、输出序列或两者中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
seekpos
[虚]
 用绝对寻址重定位输入序列、输出序列或两者中的下一位置指针
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
sync
[虚]
 将缓冲与关联的字符序列同步
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
获取区
showmanyc
[虚]
 若已知，则获得关联输入序列中可用于输入的字符数
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
underflow
[虚]
 从关联输入序列读取字符到获取区
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
uflow
[虚]
 从输入序列读取字符到获取区，并令下一位置指针前进
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
xsgetn
[虚]
 从输入序列读取多个字符
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
ebackgptregptr
 返回指向获取区起始、当前字符和末尾的指针
(受保护成员函数)
gbump
 令输出序列中的下一位置指针前进
(受保护成员函数)
setg
 重定位输出序列的起始、下一位置和终止指针
(受保护成员函数)
放置区
xsputn
[虚]
 将多个字符写到输出序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
overflow
[虚]
 从放置区写入字符到关联的输出序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
pbasepptrepptr
 返回指向放置区的起始、当前字符和末尾的指针
(受保护成员函数)
pbump
 令输出序列中的下一位置指针前进
(受保护成员函数)
setp
 重定位输出序列的起始、下一位置和终止指针
(受保护成员函数)
回放
pbackfail
[虚]
 将字符放回输入序列，可能修改输入序列
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)


std::strstreambuf::freeze

< cpp‎ | io‎ | strstreambuf
void freeze( bool freezefl = true );

若缓冲区使用动态分配，则设置流的冻结状态为 freezefl 。

流冻结时， overflow() 不会重分配缓冲区，而析构函数不会解分配缓冲区（因而导致内存泄漏）。

参数

freezefl - 设置冻结状态到的新值

返回值

（无）

注意

每次对 str() 的调用都冻结流，以保持其所返回的指针的合法性。为允许析构函数解分配缓冲区，需要显式调用 freeze(false) 。

示例

此示例中，底层数组的初始分配为 16 字节

#include <strstream>
#include <iostream>

int main()
{
    {
        std::strstream dyn; // 动态分配的读/写缓冲区
        dyn << "Test: " << 1.23; // 注意：无 std::ends ，以演示后附行为
        std::cout << "dynamic buffer holds " << dyn.pcount() << " characters: '";
        std::cout.write(dyn.str(), dyn.pcount()) << "'\n";
        // 缓冲区现在冻结，进一步输出将不使缓冲区增长
        dyn << "more output, hopefully enough to run out of the allocated space" << std::ends;
        std::cout << "After more output, it holds "
                  << dyn.pcount() << " characters: '" << dyn.str() << "'\n";
        dyn.freeze(false); // 在析构函数前解冻
    } // 析构函数释放内存

    {
        char arr[20];
        std::ostrstream st(arr, sizeof arr); // 固定大小缓冲区
        st << 1.23; // 注意：无 std::ends ，以演示后附行为
        std::cout << "static buffer holds "
                  << st.pcount() << " characters: '";
        std::cout.write(st.str(), st.pcount());
        std::cout << "'\n";
        st << "more output, hopefully enough to run out of the allocated space" << std::ends;
        std::cout << "static buffer holds "
                  << st.pcount() << " characters: '";
        std::cout.write(st.str(), st.pcount());
        std::cout << "'\n";
    } // 无待解分配者，无需解冻
}

输出：

dynamic buffer holds 10 characters: 'Test: 1.23'
After more output, it holds 16 characters: 'Test: 1.23more o'
static buffer holds 4 characters: '1.23'
static buffer holds 20 characters: '1.23more output, hop'

参阅

freeze | 禁用/启用自动解分配 (std::strstream 的公开成员函数)
freeze | 禁用/启用自动解分配 (std::ostrstream 的公开成员函数)
(析构函数) [虚] | 销毁 strstreambuf 对象，可选地解分配字符数组 (虚公开成员函数)
overflow [虚] | 后附字符到输出序列，可能重分配或初始地分配缓冲区，若它为动态且未被冻结 (虚受保护成员函数)


std::strstreambuf::overflow

< cpp‎ | io‎ | strstreambuf
protected:
virtual int_type overflow (int_type c = EOF );

后附字符 c 到缓冲的放置区，若可能则重分配。

1) 若 c==EOF ，则不做任何事
2) 否则，若放置区拥有可用的写位置（ pptr() < epptr() ），则如同用 *pptr()++ = c 存储该字符
3) 否则，若流缓冲模式非动态，或流当前为冻结，则函数失败并返回 EOF
4) 否则，函数重分配（或初始分配）足够大以保有当前动态数组（若存在）加至少一个额外写入位置的动态数组。若构造函数中使用了指向分配函数的指针 palloc ，则以 (*palloc)(n) 调用该函数，否则用 new char[n] ，其中 n 为要分配的字节数。若构造函数中使用了指向解分配函数的指针 pfree ，则以 (*pfree)(p) 调用该函数分配先前的数组，否则用 delete[] p ，若需要解分配。若分配失败，则函数失败并返回 EOF 。

参数

c - 要存储于放置区的字符

返回值

若 c== EOF ，则返回异于 EOF 的某值。否则，成功时返回 (unsigned char)(c) ，失败时返回 EOF 。

示例

#include <strstream>
#include <iostream>

struct mybuf : std::strstreambuf
{
    int_type overflow(int_type c)
    {
        std::cout << "Before overflow(): size of the put area is " << epptr()-pbase()
                  << " with " << epptr()-pptr() << " write positions available\n";
        int_type rc = std::strstreambuf::overflow(c);
        std::cout << "After overflow(): size of the put area is " << epptr()-pbase()
                  << " with " << epptr()-pptr() << " write positions available\n";
        return rc;
    }
};

int main()
{
    mybuf sbuf; // 读写动态 strstreambuf
    std::iostream stream(&sbuf);

    stream << "Sufficiently long string to overflow the initial allocation, at least "
           << " on some systems.";
}

可能的输出：

Before overflow(): size of the put area is 16 with 0 write positions available
After overflow(): size of the put area is 32 with 15 write positions available
Before overflow(): size of the put area is 32 with 0 write positions available
After overflow(): size of the put area is 64 with 31 write positions available
Before overflow(): size of the put area is 64 with 0 write positions available
After overflow(): size of the put area is 128 with 63 write positions available

参阅

overflow [虚] | 从放置区写入字符到关联的输出序列 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
overflow [虚] | 后附字符到输出序列 (std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
overflow [虚] | 从放置区写字符到关联的文件 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)
sputc | 写一个字符到放置区域，并令 next 指针前进 (std::basic_streambuf<CharT,Traits> 的公开成员函数)
put | 插入字符 (std::basic_ostream<CharT,Traits> 的公开成员函数)


std::strstreambuf::pbackfail

< cpp‎ | io‎ | strstreambuf
protected:
virtual int_type pbackfail( int_type c = EOF );

此受保护虚函数为公开函数 basic_streambuf::sungetc 和 basic_streambuf::sputbackc 所调用（继而为 basic_istream::unget 和 basic_istream::putback 所调用）。

1) 调用方请求后备获取区一个字符（以无参数或以 EOF 为参数调用 pbackfail() ）
a) 首先，检查是否有回放位置，而若确实没有则失败。（ strstreambuf 无重读用的外部字符源）
b) 若调用方错误而回放位置实际上可用，则简单地自减 basic_streambuf::gptr() ，例如通过调用 gbump(-1) 。
2) 调用方试图回放异于之前取得的字符（以需要放回的字符调用 pbackfail() ）
a) 首先，检查是否有回放位置，若无则失败。
b) 然后检查回放位置有何字符。若其处保有的字符已等于 (char)c ，则简单地自减 basic_streambuf::gptr() 。
c) 否则，若缓冲区不可修改（此 strstreambuf 以字符串字面量或某个其他 const 数组构造），则失败。
d) 否则，自减 basic_streambuf::gptr() 并写入 c 到调整后的 gptr() 所指向的位置。

参数

c - 要放回的字符，或为 Traits::eof() 以指示请求后备获取区

返回值

成功时为 c ，除非 c 为 EOF ，该情况下返回异于 EOF 的未指定值。

失败时为 EOF 。

示例

本节未完成
原因：暂无示例

参阅

pbackfail [虚] | 将字符放回输入序列，可能修改输入序列 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
sungetc | 回移一位输出序列中的下一位置指针 (std::basic_streambuf<CharT,Traits> 的公开成员函数)
sputbackc | 在输入序列中放回一个字符 (std::basic_streambuf<CharT,Traits> 的公开成员函数)
unget | 撤销流中刚取走（移除，类似指针向后退回一个位置）的字符 (std::basic_istream<CharT,Traits> 的公开成员函数)
putback | 往输入流中退回一个字符 (std::basic_istream<CharT,Traits> 的公开成员函数)


std::strstreambuf::pcount

< cpp‎ | io‎ | strstreambuf
int pcount() const;

返回写入输出序列的字符数。

若放置区的下一位置指针（ std::streambuf::pptr() ）为空指针，则返回零。

否则，返回放置区中的下一位置指针减放置区中的起始指针，即 pptr() - pbase() 。

参数

（无）

返回值

写入放置区的字符数。

示例

#include <strstream>
#include <iostream>

int main()
{
    std::strstream dyn; // 动态分配的输出缓冲区
    dyn << "Test: " << 1.23 << std::ends;
    std::strstreambuf* buf = dyn.rdbuf();
    std::cout << "The size of the output is "
              << buf->pcount() // or just buf.pcount()
              << " and it holds \"" << dyn.str() << "\"\n";
    dyn.freeze(false); // 在动态流上调用 .str() 后

    char arr[10];
    std::ostrstream user(arr, 10); // 用户提供的输出缓冲区
    buf = user.rdbuf();
    user << 1.23; // 注意：无 std::ends
    std::cout.write(arr, buf->pcount()); // 或就是 user.pcount()
    std::cout << '\n';

    std::istrstream lit("1 2 3"); // 只读固定大小缓冲区
    buf = lit.rdbuf();
    // istrstream 无成员 pcount() ，故 lit.pcount() 将不工作
    std::cout << "Input-only pcount() = " << buf->pcount() << '\n';
}

输出：

The size of the output is 11 and it holds "Test: 1.23"
1.23
Input-only pcount() = 0

参阅

pcount | 获得写入的字符数 (std::strstream 的公开成员函数)
pcount | 获得写入的字符数 (std::ostrstream 的公开成员函数)


std::strstreambuf::seekoff

< cpp‎ | io‎ | strstreambuf
protected:

virtual pos_type seekoff(off_type off,
ios_base::seekdir way,

ios_base::openmode which = ios_base::in | ios_base::out);

若可能，则重寻位 std::basic_streambuf::gptr 和/或 std::basic_streambuf::pptr 到对应距缓冲的获取和/或放置区起始、结尾或当前位置准确 off 个字符的位置。

  • 若 which 包含 ios_base::in 而此缓冲为读取打开，则以后述方式重寻位获取区内的读指针 std::basic_streambuf::gptr
  • 若 which 包含 ios_base::out 而此缓冲为写入打开，则以后述方式重定位放置区内的写指针 std::basic_streambuf::pptr
  • 若 which 包含 ios_base::in 和 ios_base::out 两者，而缓冲为读取和写入两者打开，且 when 为 ios_base::beg 或 ios_base::end ，则以后述方式重寻位读和写指针。
  • 否则，此函数失败。

若要重寻位指针（ gptr 或 pptr 或两者），则按下列方式进行：

1) 若要重寻位的指针为空指针，而新偏移 newoff 会为非零，则此函数失败。
2) 确定 off_type 类型的新指针偏移 newoff
a) 若 way == ios_base::beg ，则 newoff 为零
b) 若 way == ios_base::cur ，则 newoff 为指针的当前位置（ gptr()-eback() 或 pptr()-pbase() ）
c) 若 way == ios_base::end ，则 newoff 是缓冲区的整个已初始化部分长度（若使用过分配，则为高水位指针减起始指针）
3) 若 newoff + off 为负或在缓冲区的已初始化部分外，则函数失败
4) 否则，如同用 gptr() = eback() + newoff + off 或 pptr() = pbase() + newoff + off 赋值指针。

参数

off - 设置（两个）下一位置指针到的相对位置
way - 定义要应用相对偏移到的基位置。它能为下列常量之一：
常量 | 解释
beg | 流的开始
end | 流的结尾
cur | 流位置指示器的当前位置
which - 定义影响输入序列、输出序列或两者。它能为下列常量之一或其组合：
常量 | 解释
in | 影响输入序列
out | 影响输出序列

返回值

成功时为 pos_type(newoff) ，失败时或若 pos_type 无法表示结果流位置则为 pos_type(off_type(-1)) 。

示例

#include <iostream>
#include <strstream>

int main()
{
    char a[] = "123";
    std::strstream ss(a, sizeof a); // in/out
    std::cout << "put pos = " << ss.tellp()
              << " get pos = " << ss.tellg() << '\n';

    // 绝对寻位两者的指针
    ss.rdbuf()->pubseekoff(1, std::ios_base::beg); // 前移两者
    std::cout << "put pos = " << ss.tellp()
              << " get pos = " << ss.tellg() << '\n';

    // 尝试从当前位置前移二个指针 1 字符
    if(-1 == ss.rdbuf()->pubseekoff(1, std::ios_base::cur))
        std::cout << "moving both pointers from current position failed\n";
    std::cout << "put pos = " << ss.tellp()
              << " get pos = " << ss.tellg() << '\n';

    // 前移写指针 1 字符，但不移动读指针
    // can also be called as ss.seekp(1, std::ios_base::cur);
    ss.rdbuf()->pubseekoff(1, std::ios_base::cur, std::ios_base::out);
    std::cout << "put pos = " << ss.tellp()
              << " get pos = " << ss.tellg() << '\n';

    ss << 'a'; // 写入放置位置
    std::cout << "Wrote 'a' at put position, the buffer is now: '";
    std::cout.write(a, sizeof a);
    std::cout << "'\n";
    char ch;
    ss >> ch;
    std::cout << "reading at get position gives '" << ch << "'\n";
}

输出：

put pos = 0 get pos = 0
put pos = 1 get pos = 1
moving both pointers from current position failed
put pos = 1 get pos = 1
put pos = 2 get pos = 1
Wrote 'a' at put position, the buffer is now: '12a'
reading at get position gives '2'

参阅

seekpos [虚] | 用绝对寻址重定位输入序列、输出序列或两者中的下一位置指针 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
seekoff [虚] | 用相对寻址重定位输入序列、输出序列或两者中的下一位置指针 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
seekoff [虚] | 用相对寻址，重定位输入序列、输出序列或两者中的下一位置指针 (std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
seekoff [虚] | 用相对寻址重寻位文件位置 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)


std::strstreambuf::seekpos

< cpp‎ | io‎ | strstreambuf
protected:

virtual pos_type seekpos(pos_type sp,

std::ios_base::openmode which = std::ios_base::in | std::ios_base::out );

若可能，则重寻位 std::basic_streambuf::gptr 和/或 std::basic_streambuf::pptr 到 sp 所指示的位置。

若 which 中设置了 std::ios_base::in ，则试图重寻位 gptr() （获取区中的下一位置指针）。若 which 中设置了 std::ios_base::out ，则试图重寻位 pptr() （放置区中的下一位置指针）。若 which 中未设置这些位，则操作失败。

以下列方式重寻位每个下一位置指针：

1) 若下一位置指针为空，则操作失败
2) 否则，通过调用 sp.offset() 确定新偏移（ off_type 类型的） newoff 。若 newoff 为负、在缓冲区边界外或非法，则操作失败。
3) 否则，如同用 gptr() = eback()+newoff 或 pptr() = pbase()+newoff 赋值下一位置指针。

参数

sp - 流位置，由 seekoff() 或 seekpos() 所获得者
which - 定义要影响输入序列、输出序列或两者。它能为下列常量之一或其组合：
常量 | 解释
in | 影响输入序列
out | 影响输出序列

返回值

成功时为转换到 pos_type 的结果偏移，失败时为 pos_type(off_type(-1)) 。

注意

seekpos() 为 std::basic_streambuf::pubseekpos() 所调用，后者为 std::basic_istream::seekg() 和 std::basic_ostream::seekp() 的单参数版本所调用。

示例

#include <strstream>
#include <cstring>
#include <iostream>

struct mybuf : std::strstreambuf
{
    mybuf(const char* str) : std::strstreambuf(str, std::strlen(str)) {}
    pos_type seekpos(pos_type sp, std::ios_base::openmode which) {
         std::cout << "Before seekpos(" << sp << "), size of the get area is "
                   << egptr()-eback() << " with "
                   << egptr()-gptr() << " read positions available\n";
         pos_type rc = std::strstreambuf::seekpos(sp, which);
         std::cout << "seekpos() returns " << rc << ".\nAfter the call, "
                   << "size of the get area is "
                   << egptr()-eback() << " with "
                   << egptr()-gptr() << " read positions available\n";
        return rc;
    }
};

int main()
{
    mybuf buf("12345");
    std::iostream stream(&buf);
    stream.seekg(2);
}

输出：

Before seekpos(2), size of the get area is 5 with 5 read positions available
seekpos() returns 2.
After the call, size of the get area is 5 with 3 read positions available

参阅

pubseekpos
 调用 seekpos()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
seekpos
[虚]
 用绝对寻址，重定位输入序列、输出序列或两者中的下一位置指针
(std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
seekpos
[虚]
 用绝对寻址重寻位文件位置
(std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)
seekoff
[虚]
 用相对寻址重寻位输入序列、输出序列或两者中的下一位置指针
(虚受保护成员函数)


std::strstreambuf::setbuf

< cpp‎ | io‎ | strstreambuf
protected:
virtual streambuf<char>* setbuf(char* s, std::streamsize n);

若 s 为空指针且 n 为零，则函数无效果。

否则，效果为实现定义：一些实现不做任何事，而一些实现解分配动态成员数组并使用用户提供的大小为 n ，首元素为 s 所指向的数组。

此函数为受保护虚，它仅可通过 pubsetbuf() 或从导出自 std::strstreambuf 的用户定义类调用。

参数

s | - | 指向用户提供缓冲区中首字节的指针
n | - | 用户提供缓冲区中的字节数

返回值

this

示例

检查是否在动态 strstream 上支持 setbuf() 的实现测试（输出以 Sun Studio 获得）

#include <strstream>
#include <iostream>

int main()
{
    char a[100] = {};
    std::strstream str;
    str.rdbuf()->pubsetbuf(a, sizeof a);
    str << "Test string" << std::ends;
    std::cout << "user-provided buffer holds '" << a << "'\n";
}

可能的输出：

user-provided buffer holds 'Test string'

参阅

pubsetbuf
 调用 setbuf()
(std::basic_streambuf<CharT,Traits> 的公开成员函数)
setbuf
[虚]
 若容许则以用户定义数组替换缓冲区
(std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
setbuf
[虚]
 试图以数组替换受控字符序列
(std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
setbuf
[虚]
 提供用户供应的缓冲区，或将此 filebuf 转变为无缓冲
(std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)


std::strstreambuf::str

< cpp‎ | io‎ | strstreambuf
char* str() const;

调用 freeze() ，然后返回获取区的起始指针， std::streambuf::eback() 。

对于所有通过 std::strstream 提供的接口构造的可写 std::strstreambuf 对象，获取区的起始亦为放置区的起始。

参数

（无）

返回值

eback() 的副本，可能为空指针。

注意

典型地通过 std::strstream 接口调用此函数。

对 freeze() 的调用保证返回指针直至下次对 freeze(false) 的显式调用前保持合法：否则（在动态缓冲上）任何输出操作可能触发缓冲区重分配，而这会非法化指针。它亦导致 std::strstreambuf 的析构函数中的内存泄漏，除非在销毁缓冲（或更常用地为管理它的 std::strstream ）前调用 freeze(false) 。

示例

#include <strstream>
#include <iostream>

int main()
{
    std::strstream dyn; // 动态分配的读/写缓冲区
    dyn << "Test: " << 1.23 << std::ends;
    std::strstreambuf* buf = dyn.rdbuf();
    std::cout << "R/W buffer holds \"" << buf->str() // 或 dyn.str()
              << "\"\n";
    dyn.freeze(false); // 在动态 strstream 上调用 .str() 后

    char arr[10];
    std::ostrstream user(arr, 10); // fixed-size write-only buffer
    buf = user.rdbuf();
    user << 1.23 << std::ends;
    std::cout << "Write-only buffer holds \"" << buf->str() // 或 user.str()
              << "\"\n";

    std::istrstream lit("1 2 3"); // 固定大小只读缓冲区
    buf = lit.rdbuf();
    std::cout << "Read-only buffer holds \"" << buf->str() // 或 lit.str()
              << "\"\n";
}

输出：

R/W buffer holds "Test: 1.23"
Write-only buffer holds "1.23"
Read-only buffer holds "1 2 31 2 3"

参阅

str | 访问输出缓冲区 (std::strstream 的公开成员函数)
str | 访问输出缓冲区 (std::ostrstream 的公开成员函数)
str | 访问输出缓冲区 (std::istrstream 的公开成员函数)


std::strstreambuf::strstreambuf

< cpp‎ | io‎ | strstreambuf
(1)
explicit strstreambuf( std::streamsize alsize = 0 );
 (C++11 前)
strstreambuf() : strstreambuf(0) {}
explicit strstreambuf( std::streamsize alsize );
 (C++11 起)
strstreambuf( void* (*palloc)( std::size_t ), void (*pfree)(void*) );
 (2)
strstreambuf( char* gnext, std::streamsize n, char* pbeg = 0 );
 (3)
strstreambuf( signed char* gnext, std::streamsize n, signed char* pbeg = 0 );
 (4)
strstreambuf( unsigned char* gnext, std::streamsize n, unsigned char* pbeg = 0 );
 (5)
strstreambuf( const char* gnext, std::streamsize n );
 (6)
strstreambuf( const signed char* gnext, std::streamsize n);
 (7)
strstreambuf( const unsigned char* gnext, std::streamsize n );
 (8)
1) 构造 std::strstreambuf 对象：通过调用 std::streambuf 的默认构造函数初始化基类，初始化缓冲状态为“动态”（将按需分配缓冲区），初始化已分配大小为提供的 alsize ，初始化分配和解分配函数为空值（将使用 new[] 与 delete[] ）。
2) 构造 std::strstreambuf 对象：通过调用 std::streambuf 的默认构造函数初始化基类，初始化缓冲状态为“动态”（将按需分配缓冲区），初始化已分配大小为未指定值，初始化分配函数为 palloc ，解分配函数为 pfree 。
3-5) 依下列步骤构造 std::strstreambuf 对象：
a) 通过调用 std::streambuf 的默认构造函数初始化基类
b) 初始化缓冲状态为“冻结”（缓冲区为用户提供的固定大小缓冲区）
c) 以下列方式确定用户提供的数组中的元素数：若 n 大于零，则使用 n 。若 n 为，则执行 std::strlen (gnext) 确定缓冲区大小。若 n 为负，则使用 INT_MAX 。
d) 以下列方式配置 std::basic_streambuf 的指针：若 pbeg 为空指针，则调用 setg(gnext, gnext, gnext + N) 。若 pbeg 不是空指针，则执行 setg(gnext, gnext, pbeg) 和 setp(pbeg, pbeg+N) ，其中 N 是之前确定的数组中的元素数。
6-8) 同 strstreambuf((char*)gnext, n) ，除了在缓冲状态位掩码中设置“常量”（不允许输出到此缓冲区）。

参数

alsize | - | 动态分配的缓冲区的初始大小
palloc | - | 指向用户提供的分配函数的指针
pfree | - | 指向用户提供的解分配函数的指针
gnext | - | 指向用户提供的数组中获取区起始的指针
pbeg | - | 指向用户提供的数组中放置区起始的指针
n | - | 用户提供数组的获取区（若 pbeg 为空）或放置区（若 pbeg 非空）中的字节数

注意

这些构造函数常为 std::strstream 的构造函数所调用

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式

示例

#include <strstream>
#include <iostream>

int main()
{
    std::strstreambuf dyn; // 动态
    std::strstream dyn_s; // 等价的流
    dyn_s << 1.23 << std::ends;
    std::cout << dyn_s.str() << '\n';
    dyn_s.freeze(false);

    char buf[10];
    std::strstreambuf user(buf, 10, buf); // 用户提供的输出缓冲区
    std::ostrstream user_s(buf, 10); // 等价的流
    user_s << 1.23 << std::ends;
    std::cout << buf << '\n';

    std::strstreambuf lit("1 2 3", 5); // 常量
    std::istrstream lit_s("1 2 3"); // 等价的流
    int i, j, k;
    lit_s >> i >> j >> k;
    std::cout << i << ' ' << j << ' ' << k << '\n';
}

输出：

1.23
1.23
1 2 3

参阅

(构造函数)
 构造 strstream ，可选地分配缓冲区
(std::strstream 的公开成员函数)


std::strstreambuf::underflow

< cpp‎ | io‎ | strstreambuf
protected:
virtual int_type underflow();

从缓冲区的获取区读取下个字符。

若输入序列拥有可用读位置（ gptr() < egptr() ），则返回 (unsigned char)(*gptr()) 。

否则，若 pptr() 非空且 pptr() > egptr() （存在放置区，且它位于获取区之后），则以增加 egptr() 到 gptr() 和 pptr() 间的某个值扩展获取区的结尾，以包含最近写入到放置区中的字符，然后返回 (unsigned char)(*gptr()) 。

否则，返回 EOF 以指示失败。

参数

（无）

返回值

成功时为获取区中下个字符 (unsigned char)(*gptr()) ，失败时为 EOF 。

示例

#include <strstream>
#include <iostream>

struct mybuf : std::strstreambuf
{
    int_type overflow(int_type c)
    {
        std::cout << "Before overflow(): size of the get area is " << egptr()-eback()
                  << " size of the put area is " << epptr()-pbase() << '\n';
        int_type rc = std::strstreambuf::overflow(c);
        std::cout << "After overflow(): size of the get area is " << egptr()-eback()
                  << " size of the put area is " << epptr()-pbase() << '\n';
        return rc;
    }

    int_type underflow()
    {
        std::cout << "Before underflow(): size of the get area is " << egptr()-eback()
                  << " size of the put area is " << epptr()-pbase() << '\n';
        int_type ch = std::strstreambuf::underflow();
        std::cout << "After underflow(): size of the get area is " << egptr()-eback()
                  << " size of the put area is " << epptr()-pbase() << '\n';
        if (ch == EOF) {
            std::cout << "underflow() returns EOF\n";
        } else {
            std::cout << "underflow() returns '" << char(ch) << "'\n";
        }
        return ch;
    }
};

int main()
{
    mybuf sbuf; // 读写动态 strstreambuf
    std::iostream stream(&sbuf);

    int n;
    stream >> n;
    stream.clear();
    stream << "123";
    stream >> n;
    std::cout << n << '\n';
}

可能的输出：

Before underflow(): size of the get area is 0 size of the put area is 0
After underflow(): size of the get area is 0 size of the put area is 0
underflow() returns EOF
Before overflow(): size of the get area is 0 size of the put area is 0
After overflow(): size of the get area is 0 size of the put area is 32
Before underflow(): size of the get area is 0 size of the put area is 32
After underflow(): size of the get area is 3 size of the put area is 32
underflow() returns '1'
Before underflow(): size of the get area is 3 size of the put area is 32
After underflow(): size of the get area is 3 size of the put area is 32
underflow() returns EOF
123

参阅

underflow [虚] | 从关联输入序列读取字符到获取区 (std::basic_streambuf<CharT,Traits> 的虚受保护成员函数)
underflow [虚] | 返回输入序列中可用的下一字符 (std::basic_stringbuf<CharT,Traits,Allocator> 的虚受保护成员函数)
underflow [虚] | 从关联文件读取 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)
sgetc | 从输入序列读取一个字符，而不令序列前进 (std::basic_streambuf<CharT,Traits> 的公开成员函数)
get | 从流中读并取走（移除类似指针向下一个元素移动）一个字符 (std::basic_istream<CharT,Traits> 的公开成员函数)


std::strstreambuf::~strstreambuf

< cpp‎ | io‎ | strstreambuf
virtual ~strstreambuf();

销毁 std::strstreambuf 对象。若对象管理动态分配的缓冲区（缓冲状态为“已分配”），且若对象非冻结，则用构造时提供的解分配函数，或若未提供则用 delete[] 解分配缓冲区。

参数

（无）

注意

此析构函数典型地为 std::strstream 的析构函数所调用。

若在动态 strstream 上调用 str() ，而未在之后调用 freeze(false) ，则此析构函数泄露内存。

示例

#include <strstream>
#include <iostream>

void* my_alloc(size_t n)
{
    std::cout << "my_alloc(" << n << ") called\n";
    return new char[n];
}

void my_free(void* p)
{
    std::cout << "my_free() called\n";
    delete[] (char*)p;
}

int main()
{
    {
        std::strstreambuf buf(my_alloc, my_free);
        std::ostream s(&buf);
        s << 1.23 << std::ends;
        std::cout << buf.str() << '\n';
        buf.freeze(false);
    } // 析构函数调用于此，解分配缓冲区

    {
        std::strstreambuf buf(my_alloc, my_free);
        std::ostream s(&buf);
        s << 1.23 << std::ends;
        std::cout << buf.str() << '\n';
//        buf.freeze(false);
    } // 析构函数调用于此，内存泄漏！
}

输出：

my_alloc(4096) called
1.23
my_free() called
my_alloc(4096) called
1.23


迭代器库

< cpp

迭代器库提供了五种迭代器的定义，同时还提供了迭代器特征、适配器及相关的工具函数。

迭代器分类

迭代器共有五 (C++17 前)六 (C++17 起)种：老式输入迭代器 (LegacyInputIterator) 、老式输出迭代器 (LegacyOutputIterator) 、老式向前迭代器 (LegacyForwardIterator) 、老式双向迭代器 (LegacyBidirectionalIterator) 、老式随机访问迭代器 (LegacyRandomAccessIterator) ，及老式连续迭代器 (LegacyContiguousIterator) (C++17 起)。

迭代器的分类的依据并不是迭代器的类型，而是迭代器所支持的操作。换句话说，某个类型只要支持相应的操作，就可以作为迭代器使用。例如，完整对象类型指针支持所有老式随机访问迭代器 (LegacyRandomAccessIterator) 要求的操作，于是任何需要老式随机访问迭代器 (LegacyRandomAccessIterator) 的地方都可以使用指针。

迭代器的所有类别（除了老式输出迭代器 (LegacyOutputIterator) 和老式连续迭代器 (LegacyContiguousIterator) ）能组织到层级中，其中更强力的迭代器类别（如老式随机访问迭代器 (LegacyRandomAccessIterator) ）支持较不强力的类别（例如老式输入迭代器 (LegacyInputIterator) ）的所有操作。若迭代器落入这些类别之一且亦满足老式输出迭代器 (LegacyOutputIterator) 的要求，则称之为可变 迭代器并且支持输入还有输出。称非可变迭代器为常迭代器。

迭代器类别 有﻿定﻿义﻿操﻿作
老式连续迭代器 (LegacyContiguousIterator) 老式随机访问迭代器 (LegacyRandomAccessIterator) 老式双向迭代器 (LegacyBidirectionalIterator) 老式向前迭代器 (LegacyForwardIterator) 老式输入迭代器 (LegacyInputIterator)
  • 读
  • 自增（无多趟）
  • 自增（有多趟）
  • 自减
  • 随机访问
  • 连续存储

称落入上述迭代器类别之一并且亦符合老式输出迭代器 (LegacyOutputIterator) 的迭代器为可变迭代器。
老式输出迭代器 (LegacyOutputIterator)
  • 写
  • 自增（无多趟）

注意：老式连续迭代器 (LegacyContiguousIterator) 类别只在 C++17 中正式规定，但 std::vector 、 std::basic_string 、 std::array ，及 std::valarray 的迭代器还有指向 C 数组中的指针在 C++17 前的代码中通常都被处理成独立类别。

C++20 迭代器概念

C++20 引入基于概念的新迭代器系统，它异于 C++17 迭代器。虽然基础分配法保持类似，但单独的迭代器类别的要求有些区别。

定义于命名空间 std
indirectly_readable (C++20) | 指定类型通过应用运算符 * 可读 (概念)
indirectly_writable (C++20) | 指定可向迭代器所引用的对象写入值 (概念)
weakly_incrementable (C++20) | 指定 semiregular 类型能以前后自增运算符自增 (概念)
incrementable (C++20) | 指定 weakly_incrementable 类型上的自增操作保持相等性，而且该类型为 equality_comparable (概念)
input_or_output_iterator (C++20) | 指定该类型对象可以自增且可以解引用 (概念)
sentinel_for (C++20) | 指定类型为某个 input_or_output_iterator 类型的哨位类型 (概念)
sized_sentinel_for (C++20) | 指定可对一个迭代器和一个哨位应用 - 运算符，以在常数时间计算其距离 (概念)
input_iterator (C++20) | 指定类型为输入迭代器，即可读取其所引用的值，且可前/后自增 (概念)
output_iterator (C++20) | 指定类型为给定的值类型的输出迭代器，即可向其写入该类型的值，且可前/后自增 (概念)
forward_iterator (C++20) | 指定 input_iterator 为向前迭代器，支持相等比较与多趟操作 (概念)
bidirectional_iterator (C++20) | 指定 forward_iterator 为双向迭代器，支持向后移动 (概念)
random_access_iterator (C++20) | 指定 bidirectional_iterator 为随机访问迭代器，支持常数时间内的前进和下标访问 (概念)
contiguous_iterator (C++20) | 指定 random_access_iterator 为连续迭代器，指代内存中连续相接的元素 (概念)

迭代器关联类型

定义于命名空间 std
incrementable_traits (C++20) | 计算 weakly_incrementable 类型的差类型 (类模板)
indirectly_readable_traits (C++20) | 计算 indirectly_readable 类型的值类型 (类模板)
iter_value_titer_reference_titer_difference_titer_rvalue_reference_titer_common_reference_t (C++20)(C++20)(C++20)(C++20)(C++20) | 计算迭代器的关联类型 (别名模板)

迭代器原语

iterator_traits | 为迭代器各项性质提供统一接口 (类模板)
input_iterator_tagoutput_iterator_tagforward_iterator_tagbidirectional_iterator_tagrandom_access_iterator_tagcontiguous_iterator_tag (C++20) | 用于指示迭代器类别的空类类型 (类)
iterator (C++17 中弃用) | 用于简化简单的迭代器的必要类型定义的基类 (类模板)

迭代器定制点

定义于命名空间 std::ranges
iter_move (C++20) | 将解引用迭代器的结果转型为其关联的右值引用类型 (定制点对象)
iter_swap (C++20) | 交换两个可解引用对象所引用的值 (定制点对象)

算法概念与工具

C++20 亦提供简化常用算法操作的约束而设计的概念和工具模板集合。

定义于头文件 <iterator>
定义于命名空间 std
间接可调用对象
indirectly_unary_invocableindirectly_regular_unary_invocable
(C++20)(C++20)
 指定可调用类型能以解引用某个 indirectly_readable 类型的结果进行调用
(概念)
indirect_unary_predicate
(C++20)
 指定可调用类型，在以解引用一个 indirectly_readable 类型的结果进行调用时，满足 predicate
(概念)
indirect_binary_predicate
(C++20)
 指定可调用类型，在以解引用两个 indirectly_readable 类型的结果进行调用时，满足 predicate
(概念)
indirect_equivalence_relation
(C++20)
 指定可调用类型，在以解引用两个 indirectly_readable 类型的结果进行调用时，满足 equivalence_relation
(概念)
indirect_strict_weak_order
(C++20)
 指定可调用类型，在以解引用两个 indirectly_readable 类型的结果进行调用时，满足 strict_weak_order
(概念)
常用算法要求
indirectly_movable
(C++20)
 指定可从 indirectly_readable 类型移动值给 indirectly_writable 类型
(概念)
indirectly_movable_storable
(C++20)
 指定可从 indirectly_readable 类型移动值给 indirectly_writable 类型，且该移动可以通过中间对象进行
(概念)
indirectly_copyable
(C++20)
 指定可从 indirectly_readable 类型复制值给 indirectly_writable 类型
(概念)
indirectly_copyable_storable
(C++20)
 指定可从 indirectly_readable 类型复制值给 indirectly_writable 类型，且该复制可以通过中间对象进行
(概念)
indirectly_swappable
(C++20)
 指定能交换两个 indirectly_readable 类型所引用的值
(概念)
indirectly_comparable
(C++20)
 指定能比较两个 indirectly_readable 类型所引用的值
(概念)
permutable
(C++20)
 指定在原位重排元素的算法的共同要求
(概念)
mergeable
(C++20)
 指定通过复制元素将已排序序列归并到输出序列中的算法的要求
(概念)
sortable
(C++20)
 指定重排序列为有序序列的算法的共用要求
(概念)
工具
indirect_result_t
(C++20)
 计算在解引用某组 indirectly_readable 类型的结果上调用可调用对象的结果
(别名模板)
projected
(C++20)
 用于对接受投影的算法指定约束的辅助模板
(类模板)

迭代器适配器

reverse_iterator | 逆序遍历的迭代器适配器 (类模板)
make_reverse_iterator (C++14) | 创建拥有从实参推出的类型的 std::reverse_iterator (函数模板)
move_iterator (C++11) | 解引用结果为右值引用的迭代器适配器 (类模板)
move_sentinel (C++20) | 用于 std::move_iterator 的哨位适配器 (类模板)
make_move_iterator (C++11) | 创建拥有从实参推出的类型的 std::move_iterator (函数模板)
common_iterator (C++20) | 适配一个迭代器类型及其哨位为一个公共迭代器类型 (类模板)
default_sentinel_t (C++20) | 用于知晓其边界的迭代器的默认哨位 (类)
counted_iterator (C++20) | 对到范围结尾距离进行跟踪的迭代器适配器 (类模板)
unreachable_sentinel_t (C++20) | 始终与任何 weakly_incrementable 类型比较都不相等的哨位 (类)
back_insert_iterator | 用于在容器尾部插入的迭代器适配器 (类模板)
back_inserter | 创建拥有从实参推出的类型的 std::back_insert_iterator (函数模板)
front_insert_iterator | 用于在容器头部插入的迭代器适配器 (类模板)
front_inserter | 创建拥有从实参推出的类型的 std::front_insert_iterator (函数模板)
insert_iterator | 用于插入容器的迭代器适配器 (类模板)
inserter | 创建拥有从实参推出的类型的 std::insert_iterator (函数模板)

流迭代器

istream_iterator | 从 std::basic_istream 读取的输入迭代器 (类模板)
ostream_iterator | 写入 std::basic_ostream 的输出迭代器 (类模板)
istreambuf_iterator | 从 std::basic_streambuf 读取的输入迭代器 (类模板)
ostreambuf_iterator | 写入 std::basic_streambuf 的输出迭代器 (类模板)

迭代器操作

定义于头文件 <iterator>
advance | 令迭代器前进给定的距离 (函数模板)
distance | 返回两个迭代器间的距离 (函数模板)
next (C++11) | 令迭代器自增 (函数模板)
prev (C++11) | 令迭代器自减 (函数模板)
ranges::advance (C++20) | 令迭代器前进给定的距离或到给定的边界 (niebloid)
ranges::distance (C++20) | 返回迭代器与哨位间的距离，或范围起始与结尾间的距离 (niebloid)
ranges::next (C++20) | 自增迭代器给定的距离或到边界 (niebloid)
ranges::prev (C++20) | 自减迭代器给定的距离或到边界 (niebloid)

范围访问

这些非成员函数提供对容器、通常数组，及 std::initializer_list 的通用接口。

定义于头文件 <array>
定义于头文件 <deque>
定义于头文件 <forward_list>
定义于头文件 <iterator>
定义于头文件 <list>
定义于头文件 <map>
定义于头文件 <regex>
定义于头文件 <set>
定义于头文件 <span>
定义于头文件 <string>
定义于头文件 <string_view>
定义于头文件 <unordered_map>
定义于头文件 <unordered_set>
定义于头文件 <vector>
定义于命名空间 std
begincbegin (C++11)(C++14) | 返回指向容器或数组起始的迭代器 (函数模板)
endcend (C++11)(C++14) | 返回指向容器或数组结尾的迭代器 (函数模板)
rbegincrbegin (C++14) | 返回指向一个容器或数组的逆向迭代器 (函数模板)
rendcrend (C++14) | 返回容器或数组的逆向尾迭代器 (函数模板)
sizessize (C++17)(C++20) | 返回容器或数组的大小 (函数模板)
empty (C++17) | 检查容器是否为空 (函数模板)
data (C++17) | 获得指向底层数组的指针 (函数模板)
定义于头文件 <ranges>
定义于头文件 <iterator>
定义于命名空间 std::ranges
ranges::begin (C++20) | 返回指向范围起始的迭代器 (定制点对象)
ranges::cbegin (C++20) | 返回指向只读范围起始的迭代器 (定制点对象)
ranges::end (C++20) | 返回指示范围结尾的哨位 (定制点对象)
ranges::cend (C++20) | 返回指示只读范围结尾的哨位 (定制点对象)
ranges::rbegin (C++20) | 返回指向范围的逆向迭代器 (定制点对象)
ranges::crbegin (C++20) | 返回指向只读范围的逆向迭代器 (定制点对象)
ranges::rend (C++20) | 返回指向范围的逆向尾迭代器 (定制点对象)
ranges::crend (C++20) | 返回指向只读范围的逆向尾迭代器 (定制点对象)
ranges::size (C++20) | 返回等于范围大小的整数 (定制点对象)
ranges::ssize (C++20) | 返回等于范围大小的有符号整数 (定制点对象)
ranges::empty (C++20) | 检查范围是否为空 (定制点对象)
ranges::data (C++20) | 获得指向连续范围的起始的指针 (定制点对象)
ranges::cdata (C++20) | 获得指向只读连续范围的起始的指针 (定制点对象)


std::advance

< cpp‎ | iterator
定义于头文件 <iterator> |
template< class InputIt, class Distance > void advance( InputIt& it, Distance n ); | (C++17 前)
template< class InputIt, class Distance > constexpr void advance( InputIt& it, Distance n ); | (C++17 起)

增加给定的迭代器 it 以 n 个元素的步长。

若 n 为负，则迭代器自减。该情况下， InputIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求，否则行为未定义。

参数

it | - | 要前进的迭代器
n | - | it 要前进的元素数
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

（无）

复杂度

线性。

然而，若 InputIt 额外满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求，则复杂度是常数。

注解

若指定的自增或自减序列要求一个不可自增迭代器（例如尾后迭代器）自增，或不可自减迭代器（例如首迭代器或孤立迭代器）自减，则行为未定义。

可能的实现

参阅 libstdc++ 与 libc++ 中的实现。

版本一
// 经由标签派发的实现，移除 constexpr 后可用于 C++98
namespace detail {

template<class It>
constexpr // C++17 起要求
void do_advance(It& it, typename std::iterator_traits<It>::difference_type n,
                std::input_iterator_tag)
{
    while (n > 0) {
        --n;
        ++it;
    }
}

template<class It>
constexpr // C++17 起要求
void do_advance(It& it, typename std::iterator_traits<It>::difference_type n,
                std::bidirectional_iterator_tag)
{
    while (n > 0) {
        --n;
        ++it;
    }
    while (n < 0) {
        ++n;
        --it;
    }
}

template<class It>
constexpr // C++17 起要求
void do_advance(It& it, typename std::iterator_traits<It>::difference_type n,
                std::random_access_iterator_tag)
{
    it += n;
}

} // namespace detail

template<class It, class Distance>
constexpr // C++17 起
void advance(It& it, Distance n)
{
    detail::do_advance(it, typename std::iterator_traits<It>::difference_type(n),
                       typename std::iterator_traits<It>::iterator_category());
}
版本二
// 经由 constexpr if 的实现，可用于 C++17
template<class It, class Distance>
constexpr void advance(It& it, Distance n)
{
    using category = typename std::iterator_traits<It>::iterator_category;
    static_assert(std::is_base_of_v<std::input_iterator_tag, category>);

    auto dist = typename std::iterator_traits<It>::difference_type(n);
    if constexpr (std::is_base_of_v<std::random_access_iterator_tag, category>)
        it += dist;
    else {
        while (dist > 0) {
            --dist;
            ++it;
        }
        if constexpr (std::is_base_of_v<std::bidirectional_iterator_tag, category>) {
            while (dist < 0) {
                ++dist;
                --it;
            }
        }
    }
}

示例

#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> v{ 3, 1, 4 };

    auto vi = v.begin();

    std::advance(vi, 2);

    std::cout << *vi << '\n';
}

输出：

4

参阅

next (C++11) | 令迭代器自增 (函数模板)
distance | 返回两个迭代器间的距离 (函数模板)


std::back_insert_iterator

< cpp‎ | iterator
定义于头文件 <iterator> |
template< class Container > class back_insert_iterator : public std::iterator < std::output_iterator_tag, void, void, void, void > | (C++17 前)
template< class Container > class back_insert_iterator; | (C++17 起)

std::back_insert_iterator 后附到为之创建它的容器的老式输出迭代器 (LegacyOutputIterator) 。凡在赋值迭代器时调用容器的 push_back() 成员函数（无论是否解引用）。自增 std::back_insert_iterator 是无操作。

成员类型

成员类型 | 定义
iterator_category | std::output_iterator_tag
value_type | void
difference_type
void | (C++20 前)
std::ptrdiff_t | (C++20 起)
pointer | void
reference | void
container_type | Container

要求通过从 std::iterator < std::output_iterator_tag, void, void, void, void> 继承获得成员类型 iterator_category、 value_type、 difference_type、 pointer 及 reference 。

 (C++17 前)

成员函数

(构造函数) | 构造新的 back_insert_iterator (公开成员函数)
operator= | 插入对象到关联的容器 (公开成员函数)
operator* | 无操作 (公开成员函数)
operator++operator++(int) | 无操作 (公开成员函数)

成员对象

成员名称 | 定义
container (受保护成员对象) | 类型 Container* 的指针

示例

#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> v;
    std::generate_n(std::back_insert_iterator<std::vector<int>>(v), // std::back_inserter
                    10, [n = 0]() mutable { return ++n; });         // 可用以简化
    for (int n : v)
        std::cout << n << ' ';
    std::cout << '\n';
}

输出：

1 2 3 4 5 6 7 8 9 10

参阅

back_inserter | 创建拥有从实参推出的类型的 std::back_insert_iterator (函数模板)
front_insert_iterator | 用于在容器头部插入的迭代器适配器 (类模板)
insert_iterator | 用于插入容器的迭代器适配器 (类模板)


std::back_insert_iterator<Container>::back_insert_iterator

< cpp‎ | iterator‎ | back insert iterator

explicit back_insert_iterator( Container& c ); | (C++20 前)
explicit constexpr back_insert_iterator( Container& c ); | (C++20 起)

初始化底层指向容器指针为 std::addressof (c) 。

参数

c - 用以初始化插入器的容器

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | 由于 C++20 迭代器必须为 default_initializable 提供了默认构造函数 | 与该要求一同移除


std::back_insert_iterator<Container>::operator*

< cpp‎ | iterator‎ | back insert iterator

back_insert_iterator& operator*(); | (C++20 前)
constexpr back_insert_iterator& operator*(); | (C++20 起)

不做任何事，提供此函数以满足老式输出迭代器 (LegacyOutputIterator) 的要求。

它返回迭代器自身，这使得可以用诸如 *iter = value 的代码输出（插入）值到底层的容器。

参数

（无）

返回值

*this


std::back_insert_iterator<Container>::operator++

< cpp‎ | iterator‎ | back insert iterator
back_insert_iterator& operator++(); | (C++20 前)
constexpr back_insert_iterator& operator++(); | (C++20 起)
back_insert_iterator operator++( int ); | (C++20 前)
constexpr back_insert_iterator operator++( int ); | (C++20 起)

不做任何事。提供这些运算符以满足老式输出迭代器 (LegacyOutputIterator) 的要求。它们使得表达式 *iter++=value 和 *++iter=value 可用于输出（插入）值到底层的容器。

参数

（无）

返回值

*this


std::back_insert_iterator<Container>::operator=

< cpp‎ | iterator‎ | back insert iterator

 | (1)
back_insert_iterator<Container>& operator=( typename Container::const_reference value ); |  | (C++11 前)
back_insert_iterator<Container>& operator=( const typename Container::value_type& value ); |  | (C++11 起) (C++20 前)
constexpr back_insert_iterator<Container>& operator=( const typename Container::value_type& value ); |  | (C++20 起)
 | (2)
back_insert_iterator<Container>& operator=( typename Container::value_type&& value ); |  | (C++11 起) (C++20 前)
constexpr back_insert_iterator<Container>& operator=( typename Container::value_type&& value ); |  | (C++20 起)

插入给定的 value 到迭代器。

1) 导致 container->push_back(value)
2) 导致 container->push_back(std::move(value))

参数

value - 要插入的值

返回值

*this

示例

#include <iostream>
#include <iterator>
#include <deque>

int main()
{
    std::deque<int> q;
    std::back_insert_iterator< std::deque<int> > it(q);

    for (int i=0; i<10; ++i)
        it = i; // 调用 q.push_back(i)

    for (auto& elem : q) std::cout << elem << ' ';
}

输出：

0 1 2 3 4 5 6 7 8 9


std::back_inserter

< cpp‎ | iterator
定义于头文件 <iterator> |
template< class Container > std::back_insert_iterator <Container> back_inserter( Container& c ); | (C++20 前)
template< class Container > constexpr std::back_insert_iterator <Container> back_inserter( Container& c ); | (C++20 起)

back_inserter 为容器 c 构造 std::back_insert_iterator 的便利函数模板，拥有从参数类型推导的类型。

参数

c - 支持 push_back 操作的容器

返回值

能用于添加元素到容器 c 尾端的 std::back_insert_iterator 。

可能的实现

template< class Container >
std::back_insert_iterator<Container> back_inserter( Container& c )
{
    return std::back_insert_iterator<Container>(c);
}

示例

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

int main()
{
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::fill_n(std::back_inserter(v), 3, -1);
    for (int n : v)
        std::cout << n << ' ';
}

输出：

1 2 3 4 5 6 7 8 9 10 -1 -1 -1

参阅

back_insert_iterator | 用于在容器尾部插入的迭代器适配器 (类模板)
front_inserter | 创建拥有从实参推出的类型的 std::front_insert_iterator (函数模板)
inserter | 创建拥有从实参推出的类型的 std::insert_iterator (函数模板)


std::begin, std::cbegin

< cpp‎ | iterator
定义于头文件 <array>
定义于头文件 <deque>
定义于头文件 <forward_list>
定义于头文件 <iterator>
定义于头文件 <list>
定义于头文件 <map>
定义于头文件 <regex>
定义于头文件 <set>
定义于头文件 <span>
(C++20 起)
定义于头文件 <string>
定义于头文件 <string_view>
(C++17 起)
定义于头文件 <unordered_map>
定义于头文件 <unordered_set>
定义于头文件 <vector>
(1)
template< class C >
auto begin( C& c ) -> decltype(c.begin());
 (C++11 起)
(C++17 前)
template< class C >
constexpr auto begin( C& c ) -> decltype(c.begin());
 (C++17 起)
(1)
template< class C >
auto begin( const C& c ) -> decltype(c.begin());
 (C++11 起)
(C++17 前)
template< class C >
constexpr auto begin( const C& c ) -> decltype(c.begin());
 (C++17 起)
(2)
template< class T, std::size_t N >
T* begin( T (&array)[N] );
 (C++11 起)
(C++14 前)
template< class T, std::size_t N >
constexpr T* begin( T (&array)[N] ) noexcept;
 (C++14 起)
template< class C >

constexpr auto cbegin( const C& c ) noexcept(/* see below */)

-> decltype(std::begin(c));
 (3) (C++14 起)

返回指向给定范围起始的迭代器。

1) 准确返回 c.begin() ，典型地是指向 c 所代表的序列起始的迭代器。若 C 是标准容器 (Container) ，则在 c 不是 const 限定时返回 C::iterator ，否则返回 C::const_iterator 。
2) 返回指向 array 起始的指针。
3) 准确返回 std::begin(c) ，这里 c 始终被视为 const 限定。若 C 是标准容器 (Container) ，则始终返回 C::const_iterator 。

参数

c | - | 带 begin 成员函数的容器或视图
array | - | 任意类型的数组

返回值

指向范围起始的迭代器

异常

3)
noexcept 说明：
noexcept(noexcept(std::begin(c)))

重载

可以为不暴露适合的 begin() 成员函数的类或枚举提供 begin 的自定义重载，从而能迭代它。标准库已提供下列重载：

std::begin(std::initializer_list) (C++11) | 特化 std::begin (函数模板)
std::begin(std::valarray) (C++11) | 特化的 std::begin (函数模板)
begin(std::filesystem::directory_iterator)end(std::filesystem::directory_iterator) | 基于范围的 for 循环支持 (函数)
begin(std::filesystem::recursive_directory_iterator)end(std::filesystem::recursive_directory_iterator) | 基于范围的 for 循环支持 (函数)

同 swap 的使用（于可交换 (Swappable) 描述）， begin 函数在泛型语境中的使用等价于 using std::begin; begin(arg);，这允许 ADL 为用户定义类型所选的重载和出现于同一重载集的标准库函数模板。

template<typename Container, typename Function>
void for_each(Container&& cont, Function f) {
    using std::begin;
    auto it = begin(cont);
    using std::end;
    auto end_it = end(cont);
    while (it != end_it) {
        f(*it);
        ++it;
    }
}

实参依赖查找所找到的 begin 重载能用于定制 std::ranges::begin、 std::ranges::cbegin 及其他依赖于 std::ranges::begin 的定制点对象的行为。

 (C++20 起)

注解

(1,3) 准确地反映 C::begin() 的行为。若该成员函数无合理的实现，则它们的效果可能令人惊异。

std::cbegin 是为统一成员与非成员范围访问引入的。参阅 LWG 问题 2128 。

若 C 是浅 const 的视图，则 std::cbegin 可能返回可变的迭代器。某些用户不期待这种行为。参阅 P2276 与 P2278 。

示例

#include <iostream>
#include <vector>
#include <iterator>

int main()
{
    std::vector<int> v = { 3, 1, 4 };
    auto vi = std::begin(v);
    std::cout << *vi << '\n';

    int a[] = { -5, 10, 15 };
    auto ai = std::begin(a);
    std::cout << *ai << '\n';
}

输出：

3
-5

参阅

endcend (C++11)(C++14) | 返回指向容器或数组结尾的迭代器 (函数模板)
ranges::begin (C++20) | 返回指向范围起始的迭代器 (定制点对象)
ranges::cbegin (C++20) | 返回指向只读范围起始的迭代器 (定制点对象)


std::bidirectional_iterator

< cpp‎ | iterator
定义于头文件 <iterator>
template<class I>

concept bidirectional_iterator =
std::forward_iterator<I> &&
std::derived_from</*ITER_CONCEPT*/<I>, std::bidirectional_iterator_tag > &&
requires(I i) {
{ --i } -> std::same_as<I&>;
{ i-- } -> std::same_as<I>;

};
 (C++20 起)

概念 bidirectional_iterator 细化 forward_iterator ，添加后移迭代器的能力。

迭代器概念确定

此概念的定义通过仅用于阐释的别名模板 /*ITER_CONCEPT*/ 说明。

为确定 /*ITER_CONCEPT*/<I> ，令 ITER_TRAITS<I> 若特化 std::iterator_traits <I> 从主模板生成则指代 I ，否则指代 std::iterator_traits <I> ：

  • 若 ITER_TRAITS<I>::iterator_concept 合法并指名类型，则 /*ITER_CONCEPT*/<I> 指代该类型。
  • 否则，若 ITER_TRAITS<I>::iterator_category 合法并指名类型，则 /*ITER_CONCEPT*/<I> 指代该类型。
  • 否则，若 std::iterator_traits <I> 从主模板生成，则 /*ITER_CONCEPT*/<I> 指代 std::random_access_iterator_tag 。
  • 否则 /*ITER_CONCEPT*/<I> 不指代类型并导致替换失败。

语义要求

称双向迭代器 r 可自减，若且唯若存在某个 s 使得 ++s == r 。

bidirectional_iterator<I> 得到实现，仅若其所蕴含的概念均被实现，且给定二个 I 类型对象 a 与 b ：

  • 若 a 可自减，则 a 在表达式 --a 与 a-- 的定义域中。
  • 前自减生成指代运算数的左值： std::addressof (--a) == std::addressof (a) ；
  • 后自减生成运算数先前的值：若 bool(a == b) ，则 bool(a-- == b) 。
  • 后自减和前自减在运算数上进行相同操作：若 bool(a == b) ，则求值 a-- 与 --b 两者后， bool(a == b) 仍然成立。
  • 自增和自减互逆：
  • 若 a 可自增且 bool(a == b) ，则 bool(--(++a) == b) 。
  • 若 a 可自减且 bool(a == b) ，则 bool(--(++a) == b) 。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

注解

不同于老式双向迭代器 (LegacyBidirectionalIterator) 要求， bidirectional_iterator 概念不要求解引用返回左值。

参阅

forward_iterator
(C++20)
 指定 input_iterator 为向前迭代器，支持相等比较与多趟操作
(概念)


std::common_iterator

< cpp‎ | iterator
定义于头文件 <iterator>
template< std::input_or_output_iterator I, std::sentinel_for<I> S >

requires ( !std::same_as<I, S> && std::copyable<I> )

class common_iterator;
 (C++20 起)

std::common_iterator 是含有迭代器或哨位之一并定义适合的比较运算符 operator== ，从而可以将非共用范围（其中 I 与 S 有别）表示成 common_range 的迭代器 I / 哨位 S 适配器。
能以 std::common_iterator 为迭代器/哨位对所表示的序列与期待 common_range 式序列的遗留函数间的“桥梁”。

成员函数

(构造函数) (C++20) | 构造新的迭代器适配器 (公开成员函数)
operator= (C++20) | 赋值另一迭代器适配器 (公开成员函数)
operator*operator-> (C++20) | 访问被指向的元素 (公开成员函数)
operator++operator++(int) (C++20) | 推进迭代器适配器 (公开成员函数)

成员对象

成员名 | 定义
var (私有) | std::variant <I, S> 类型对象，名字仅用于阐释

非成员函数

operator== (C++20) | 比较底层迭代器或哨位 (函数模板)
operator- (C++20) | 计算二个迭代器适配器间的距离 (函数模板)
iter_move (C++20) | 转型解引用底层迭代器的结果为其所关联的右值引用类型 (函数)
iter_swap (C++20) | 交换二个底层迭代器所指向的对象 (函数模板)

辅助类

std::incrementable_traits<std::common_iterator> (C++20) | 计算 std::common_iterator 类型的关联差类型 (类模板特化)
std::iterator_traits<std::common_iterator> (C++20) | 对 std::counted_iterator 类型的属性提供均一的接口 (类模板特化)

示例

#include <algorithm>
#include <list>
#include <iostream>
#include <iterator>
#include <string>

template <class ForwardIter>
void fire(ForwardIter first, ForwardIter last) {
    std::copy(first, last, std::ostream_iterator<std::string>{std::cout, " "});
}

int main() {
    std::list<std::string> stars{"Pollux", "Arcturus", "Mira", "Aldebaran", "Sun"};
    using IT = std::common_iterator<
                   std::counted_iterator<std::list<std::string>::iterator>,
                   std::default_sentinel_t>;
    fire( IT(std::counted_iterator(stars.begin(), stars.size()-1)),
          IT(std::default_sentinel) );
}

输出：

Pollux Arcturus Mira Aldebaran

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 23.5.4 Common iterators [iterators.common]

参阅

ranges::common_range (C++20) | 指定范围拥有相同的迭代器和哨位类型 (概念)
ranges::common_viewviews::common (C++20) | 转换 view 为 common_range (类模板) (范围适配器对象)


std::common_iterator<I,S>::common_iterator

< cpp‎ | iterator‎ | common iterator
constexpr common_iterator() requires std::default_initializable<I> = default;
 (1) (C++20 起)
constexpr common_iterator( I i );
 (2) (C++20 起)
constexpr common_iterator( S s );
 (3) (C++20 起)
template< class I2, class S2 >

requires std::convertible_to<const I2&, I> &&
std::convertible_to<const S2&, S>

constexpr common_iterator( const common_iterator<I2, S2>& x );
 (4) (C++20 起)

构造新的迭代器适配器，等效地初始化底层 std::variant <I, S> 成员对象 var 以保有一个 I （迭代器）或 S （哨位）对象。

1) 默认构造函数。默认初始化 var 。构造后， var 保有一个值初始化的 I 对象。在产生的迭代器适配器上的操作拥有有定义行为，当且仅当值初始化的 I 上的操作亦拥有有定义行为。
2) 构造后 var 保有一个从 i 移动构造的 I 对象。
3) 构造后 var 保有一个从 s 移动构造的 S 对象。
4) 若 x.var 保有一个 I2 或 S2 ，则构造后 var 分别保有一个从 x.var 所保有的该可选项初始化的 I 或 S 对象。若 x 在非法状态，即 x.var.valueless_by_exception() 为 true 则行为未定义。

参数

i | - | 要适配的迭代器
s | - | 要适配的哨位
x | - | 要转换的迭代器适配器

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>

int main()
{
    std::vector v {3,1,4,1,5,9,2};

    using CI = std::common_iterator<
                   std::counted_iterator<std::vector<int>::iterator>,
                   std::default_sentinel_t
                   >;
    CI unused; // (1)
    CI start  { std::counted_iterator{std::next(begin(v)), ssize(v)-2} }; // (2)
    CI finish { std::default_sentinel }; // (3)
    CI first  { start };  // (4)
    CI last   { finish }; // (4)

    std::copy(first, last, std::ostream_iterator<int>{std::cout, " "});
    std::cout << '\n';

    std::common_iterator<
      std::counted_iterator<
        std::ostream_iterator<double>>,
        std::default_sentinel_t>
        beg { std::counted_iterator{std::ostream_iterator<double>{std::cout,";  "}, 5} },
        end { std::default_sentinel };
    std::iota(beg, end, 3.1);
    std::cout << '\n';
}

输出：

1 4 1 5 9
3.1;  4.1;  5.1;  6.1;  7.1;

参阅

operator=
(C++20)
 赋值另一迭代器适配器
(公开成员函数)


std::incrementable_traits<std::common_iterator>

< cpp‎ | iterator‎ | common iterator
定义于头文件 <iterator>
template< class I, class S >

struct incrementable_traits<std::common_iterator<I, S>> {
using difference_type = std::iter_difference_t<I>;

};
 (C++20 起)

对提供访问 std::common_iterator 类型的差类型提供统一接口。

示例

#include <list>
#include <string>
#include <cstddef>
#include <iterator>
#include <type_traits>

int main()
{
    using CI = std::common_iterator<
                    std::counted_iterator<int*>,
                    std::default_sentinel_t
                    >;
    using CL = std::common_iterator<
                    std::counted_iterator<std::list<std::string>::iterator>,
                    std::default_sentinel_t
                    >;
    CL cl { std::default_sentinel };
    static_assert(
        std::same_as<std::incrementable_traits<CI>::difference_type, std::ptrdiff_t> &&
        std::same_as<std::incrementable_traits<CL>::difference_type, std::ptrdiff_t> &&
        std::same_as<std::incrementable_traits<decltype(cl)>::difference_type, std::ptrdiff_t>
    );
}

参阅

incrementable_traits (C++20) | 计算 weakly_incrementable 类型的差类型 (类模板)
iter_value_titer_reference_titer_difference_titer_rvalue_reference_titer_common_reference_t (C++20)(C++20)(C++20)(C++20)(C++20) | 计算迭代器的关联类型 (别名模板)
std::iterator_traits<std::common_iterator> (C++20) | 对 std::counted_iterator 类型的属性提供均一的接口 (类模板特化)


std::iter_move(std::common_iterator)

< cpp‎ | iterator‎ | common iterator
friend std::iter_rvalue_reference_t<I>

std::iter_move( const std::common_iterator& i )
noexcept(noexcept(ranges::iter_move( std::declval <const I&>()))

requires std::input_iterator<I>;
 (C++20 起)

将解引用底层迭代器的结果转型成其关联右值引用类型。若 i.var 不保有一个 I 对象（即迭代器）则行为未定义。

函数体等价于 return std::ranges​::​iter_move(std::get<I>(i.var)); 。

此函数对通常无限定或有限定查找不可见，而只能在 std::common_iterator<I,S> 为参数的关联类时由实参依赖查找找到。

参数

i - a source iterator adaptor.

返回值

右值引用或纯右值临时量。

复杂度

常数。

示例

#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

void print(auto const& rem, auto const& v) {
    std::cout << rem << "[" << size(v) << "] { ";
    for (int o{}; auto const& s : v)
        std::cout << (o++ == 0 ? "" : ", ") << quoted(s);
    std::cout << " }\n";
}

int main()
{
    std::vector<std::string> p { "Andromeda", "Cassiopeia", "Phoenix" }, q;

    print("p", p), print("q", q);

    using CI = std::common_iterator<
                   std::counted_iterator<std::vector<std::string>::iterator>,
                   std::default_sentinel_t
                   >;
    CI last{ std::default_sentinel };

    for (CI first{ {p.begin(), 2} }; first != last; ++first) {
        q.emplace_back( /* ADL */ iter_move(first) );
    }

    print("p", p), print("q", q);
}

可能的输出：

p[3] { "Andromeda", "Cassiopeia", "Phoenix" }
q[0] {  }
p[3] { "", "", "Phoenix" }
q[2] { "Andromeda", "Cassiopeia" }

参阅

iter_move (C++20) | 将解引用迭代器的结果转型为其关联的右值引用类型 (定制点对象)
iter_move (C++20) | 转型解引用底层迭代器的结果为其所关联的右值引用类型 (函数)
move (C++11) | 获得右值引用 (函数模板)
move_if_noexcept (C++11) | 若移动构造函数不抛出则获得右值引用 (函数模板)
forward (C++11) | 转发一个函数实参 (函数模板)
ranges::move (C++20) | 将某一范围的元素移动到一个新的位置 (niebloid)
ranges::move_backword (C++20) | 按从后往前的顺序移动某一范围的元素到新的位置 (niebloid)


std::iter_swap(std::common_iterator)

< cpp‎ | iterator‎ | common iterator
template< std::indirectly_swappable<I> I2, class S2 > friend constexpr void iter_swap( const common_iterator& x, const std::common_iterator<I2, S2>& y ) noexcept(/*see below*/); | (C++20 起)

交换二个底层迭代器所指向的对象。若 x 不保有 I 对象或 y 不保有 I2 对象（即 x 与 y 中至少一个不保有迭代器）则行为未定义。

函数体等价于 ranges​::​iter_swap(std::get<I>(x.var), std::get<I2>(y.var)) 。

此函数模板对通常无限定或有限定查找不可见，而只能在 std::common_iterator&ltI,S> 为参数的关联类时由实参依赖查找找到。

参数

x, y - 指向要交换的元素的迭代器

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(ranges::iter_swap( std::declval <const I&>(), std::declval <const I2&>())))

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

int main()
{
    std::vector<std::string> v1 { "1", "2", "3", "4", "5" },
                             v2 { "α", "β", "γ", "δ", "ε" };

    using CI = std::common_iterator<
                   std::counted_iterator<std::vector<std::string>::iterator>,
                   std::default_sentinel_t
                   >;

    CI first1 { std::counted_iterator { v1.begin(), 3 } };
    CI first2 { std::counted_iterator { v2.begin(), 4 } };
    CI last   { std::default_sentinel };

    auto print = [&] (auto rem) {
        std::cout << rem << "v1 = ";
        std::ranges::copy(v1, std::ostream_iterator<std::string>{std::cout, " "});
        std::cout << "\nv2 = ";
        std::ranges::copy(v2, std::ostream_iterator<std::string>{std::cout, " "});
        std::cout << '\n';
    };

    print("Before iter_swap:\n");

    for (; first1 != last && first2 != last; ++first1, ++first2) {
        iter_swap( first1, first2 ); // ADL
    }

    print("After iter_swap:\n");
}

输出：

Before iter_swap:
v1 = 1 2 3 4 5
v2 = α β γ δ ε
After iter_swap:
v1 = α β γ 4 5
v2 = 1 2 3 δ ε

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3574 | C++20 | variant 为完全 constexpr (P2231R1) 但 common_iterator 不是 | 亦使之为 constexpr

参阅

swap | 交换两个对象的值 (函数模板)
swap_ranges | 交换两个范围的元素 (函数模板)
iter_swap | 交换两个迭代器所指向的元素 (函数模板)
iter_swap (C++20) | 交换两个可解引用对象所引用的值 (定制点对象)
iter_swap (C++20) | 交换二个底层迭代器所指向的对象 (函数模板)


std::iterator_traits<std::common_iterator>

< cpp‎ | iterator‎ | common iterator
定义于头文件 <iterator>
template< std::input_iterator I, class S >
struct iterator_traits<std::common_iterator<I, S>>;
 (C++20 起)

提供对于 std::common_iterator 类型的属性的统一接口。

成员类型

成员类型 | 定义
iterator_concept std::forward_iterator_tag ，若 I 实现 std::forward_iterator ；
否则为 std::input_iterator_tag
iterator_category std::forward_iterator_tag ，若 std::iterator_traits <I>​::​iterator_category 合法并指代实现 std::derived_from< std::forward_iterator_tag > 的类型；
否则为 std::input_iterator_tag
value_type | std::iter_value_t<I>
difference_type | std::iter_difference_t<I>
pointer 表达式 c.operator->() 的类型，若它为良构，其中 c 为 const std::common_iterator<I, S> 类型左值；
否则为 void
reference | std::iter_reference_t<I>

示例

#include <vector>
#include <iterator>
#include <type_traits>

int main() {
    std::vector v{1,2,3,4};
    using CV = std::common_iterator<
                    std::counted_iterator<std::vector<int>::iterator>,
                    std::default_sentinel_t>;
    CV i { std::counted_iterator { v.begin(), 3 } };
    using TRCV = std::iterator_traits<decltype(i)>;
    static_assert(std::is_same<TRCV::iterator_concept, std::forward_iterator_tag>());
    static_assert(std::is_same<TRCV::iterator_category, std::forward_iterator_tag>());
    static_assert(std::is_same<TRCV::value_type, int>());
    static_assert(std::is_same<TRCV::difference_type, std::vector<int>::difference_type>());
    static_assert(std::is_same<TRCV::pointer, decltype(i.operator->())>());
    static_assert(std::is_same<TRCV::reference, int&>());

    CV s { std::default_sentinel };
    using TRCS = std::iterator_traits<decltype(s)>;
    static_assert(std::is_same<TRCS::iterator_concept, std::forward_iterator_tag>());
    static_assert(std::is_same<TRCS::iterator_category, std::forward_iterator_tag>());
    static_assert(std::is_same<TRCS::value_type, int>());
    static_assert(std::is_same<TRCS::difference_type, std::vector<int>::difference_type>());
    static_assert(std::is_same<TRCS::pointer, decltype(s.operator->())>());
    static_assert(std::is_same<TRCS::reference, int&>());
}

参阅

iterator_traits | 为迭代器各项性质提供统一接口 (类模板)
std::incrementable_traits<std::common_iterator> (C++20) | 计算 std::common_iterator 类型的关联差类型 (类模板特化)


std::common_iterator<I,S>::operator*,->

< cpp‎ | iterator‎ | common iterator
constexpr decltype(auto) operator*();
 (1) (C++20 起)
constexpr decltype(auto) operator*() const
requires /*dereferenceable*/<const I>;
 (2) (C++20 起)
constexpr decltype(auto) operator->() const
requires /* see description */;
 (3) (C++20 起)
辅助类型
class /*proxy*/ { // 仅用于阐释

std::iter_value_t<I> keep_;
constexpr proxy(std::iter_reference_t<I>&& x)
: keep_(std::move(x)) {}
public:
constexpr const std::iter_value_t<I>* operator->() const noexcept {
return std::addressof (keep_);
}

};
 (4) (C++20 起)

返回指向当前元素的指针或引用，或保有它的代理。

若底层 std::variant 成员对象 var 不保有 I 类型对象，即 std::holds_alternative <I>(var) 等于 false 则行为未定义。

令 it 代表 var 所保有的 I 类型迭代器，即 std::get<I>(var) 。

1-2) 返回解引用 it 的结果。
3) 返回指向当前元素的指针或底层迭代器，或保有它的代理：
  • 等价于 return it; ，若 I 为指针类型或若表达式 it.operator->() 为良构，
  • 否则等价于 auto&& tmp = *it; return std::addressof (tmp); ，若 std::iter_reference_t<I> 为引用类型，
  • 否则等价于 return proxy(*it); ，其中 proxy 为仅用于阐释的类 (4) 。
requires 子句中的表达式等价于
std::indirectly_readable<const I> && (

requires(const I& i) { i.operator->(); } ||
std::is_reference_v <std::iter_reference_t<I>> ||
std::constructible_from<std::iter_value_t<I>, std::iter_reference_t<I>>

).

参数

（无）

返回值

1-2) 到当前元素的引用或纯右值临时量。等价于 *it 。
3) 前述的指向当前元素的指针或迭代器，或保有它的代理。

示例

#include <algorithm>
#include <complex>
#include <iostream>
#include <iterator>
#include <initializer_list>
using std::complex_literals::operator""i;
int main() {
    const auto il = {1i,3.14+2i,3i,4i,5i};
    using CI = std::common_iterator<
        std::counted_iterator<decltype(il)::iterator>,
        std::default_sentinel_t>;
    CI ci { std::counted_iterator{
        std::next(begin(il), 1), ssize(il) - 1} };
    std::cout << *ci << ' ' << ci->real() << '\n';
}

输出：

(3.14,2) 3.14

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3574 | C++20 | variant 为完全 constexpr (P2231R1) 但 common_iterator 不是 | 亦使之为 constexpr
LWG 3595 | C++20 | 代理类型的函数缺少 constexpr 与 noexcept | 已添加

参阅

(构造函数)
(C++20)
 构造新的迭代器适配器
(公开成员函数)


operator-(std::common_iterator)

< cpp‎ | iterator‎ | common iterator
template< std::sized_sentinel_for<I> I2, std::sized_sentinel_for<I> S2 >

requires std::sized_sentinel_for<S, I2>
friend constexpr std::iter_difference_t<I2>

operator-( const common_iterator& x, const std::common_iterator<I2, S2>& y );
 (C++20 起)

计算二个迭代器适配器间的差。认为二个哨位相等。

令 var 代表 std::common_iterator 中底层 std::variant 成员对象，若 x 或 y 非法，即 x.var.valueless_by_exception() || y.var.valueless_by_exception() 为 true 则行为未定义。

此函数模板对通常无限定或有限定查找不可见，而只能在 std::common_iterator<I> 为参数的关联类时由实参依赖查找找到。

参数

x, y - 要计算差的迭代器适配器

返回值

  • ​0​ ，若 x.var 保有一个 S 对象而 y.var 保有一个 S2 对象，即它们都保有一个哨位。
  • 否则为 alt_x - alt_y ，其中 alt_x 与 alt_y 分别为 x.var 与 y.var 所保有的可选项（要么是两个迭代器，要么是一个迭代器与一个哨位）。

示例

#include <algorithm>
#include <iostream>
#include <iterator>

int main()
{
    int a[] {0, 1, 2, 3, 4, 5};

    using CI = std::common_iterator<
                   std::counted_iterator<int*>,
                   std::default_sentinel_t
                   >;

    CI i1{ std::counted_iterator{ a + 1, 2 } };
    CI i2{ std::counted_iterator{ a + 1, 3 } };
    CI s1{ std::default_sentinel };
    CI s2{ std::default_sentinel };

    std::cout << (s2 - s1) << ' '
              << (i2 - i1) << ' '
              << (i1 - s1) << '\n';
}

输出：

0 -1 -2

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3574 | C++20 | variant 为完全 constexpr (P2231R1) 但 common_iterator 不是 | 亦使之为 constexpr

参阅

operator++operator++(int)
(C++20)
 推进迭代器适配器
(公开成员函数)


std::common_iterator<I,S>::operator=

< cpp‎ | iterator‎ | common iterator
template< class I2, class S2 >

requires std::convertible_to<const I2&, I> &&
std::convertible_to<const S2&, S> &&
std::assignable_from<I&, const I2&> &&
std::assignable_from<S&, const S2&>

constexpr common_iterator& operator=( const common_iterator<I2, S2>& x );
 (C++20 起)

从 x 的底层 std::variant 成员对象 var 赋值给 *this 的。

令 i 为 x.var.index() 。则此赋值运算符等价于：

  • std::get<i>(var) = std::get<i>(x.var) ，若 var.index() == i ，
  • 否则为 var.emplace<i>(std::get<i>(x.var)) 。

若 x 在非法状态，即 x.var.valueless_by_exception() 等于 true 则行为未定义。

参数

x - 作为复制来源的迭代器

返回值

*this 。

参数

#include <algorithm>
#include <iostream>
#include <iterator>
#include <initializer_list>

int main() {
    const auto il = {1,2,3,4,5,6};
    using CI = std::common_iterator<
                   std::counted_iterator<std::initializer_list<int>::iterator>,
                   std::default_sentinel_t>;
    CI first { std::counted_iterator{std::next(begin(il), 1), ssize(il) - 1} };
    const CI first2 { std::counted_iterator{std::next(begin(il), 2), ssize(il) - 2} };
    const CI last { std::default_sentinel };
    std::copy(first, last, std::ostream_iterator<int>{std::cout, " "});
    std::cout << '\n';
    first = first2;
    std::copy(first, last, std::ostream_iterator<int>{std::cout, " "});
    std::cout << '\n';
}

输出：

2 3 4 5 6
3 4 5 6

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3574 | C++20 | variant 为完全 constexpr (P2231R1) 但 common_iterator 不是 | 亦使之为 constexpr

参阅

(构造函数)
(C++20)
 构造新的迭代器适配器
(公开成员函数)


std::common_iterator<I,S>::operator++

< cpp‎ | iterator‎ | common iterator
constexpr common_iterator& operator++();
 (1) (C++20 起)
constexpr decltype(auto) operator++( int );
 (2) (C++20 起)
辅助类型
class /*postfix_proxy*/ { // 仅用于阐释

std::iter_value_t<I> keep_;
constexpr postfix_proxy(std::iter_reference_t<I>&& x)
: keep_( std::forward <std::iter_reference_t<I>>(x)) {}
public:
constexpr const std::iter_value_t<I>& operator*() const noexcept {
return keep_;
}

};
 (3) (C++20 起)

自增底层迭代器。

若底层 std::variant 成员对象 var 不保有 I 类型对象，即 std::holds_alternative <I>(var) 等于 false 则行为未定义。

令 it 代表 var 所保有的 I 类型迭代器，即 std::get<I>(var) 。

1) 前自增一。等价于 ++it; return *this; 。
2) 后自增一：
  • 等价于 auto tmp = *this; ++*this; return tmp; ，若 I 实现 forward_iterator ，
  • 否则等价于 return it++; ，若变量定义 auto&& ref = *it++; 为良构，或者

std::constructible_from<std::iter_value_t<I>, std::iter_reference_t<I>> 或 std::move_constructible<std::iter_value_t<I>> 为 false ，

  • 否则等价于 postfix_proxy p(**this); ++*this; return p; ，其中 postfix_proxy 为仅用于阐释的辅助类型 (3) 。

参数

（无）

返回值

1) *this 。
2) 前述的更改前的 *this 的副本，或后自增底层迭代器的结果，或保有当前元素的值的代理。

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <initializer_list>

int main()
{
    const auto il = {1, 2, 3, 4, 5, 6};

    using CI = std::common_iterator<
                   std::counted_iterator<std::initializer_list<int>::iterator>,
                   std::default_sentinel_t
                   >;

    for ( CI first { std::counted_iterator{ std::begin(il), std::ssize(il) - 2 } },
             last { std::default_sentinel }; first != last; ) {
        std::cout << *first;
        std::cout << (++first != last ? ", " : "\n");
    }
}

输出：

1, 2, 3, 4

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2259R1 | C++20 | 后自增在更多场合舍弃其结果 | 用代理类保有结果
LWG 3546 | C++20 | 代理对象的初始化有时非良构 | 调整了场合与定义
LWG 3574 | C++20 | variant 为完全 constexpr (P2231R1) 但 common_iterator 不是 | 亦使之为 constexpr
LWG 3595 | C++20 | 代理类型的函数缺少 constexpr 与 noexcept | 已添加

参阅

operator-
 计算两个迭代器适配器间的距离
(函数模板)


operator==(std::common_iterator)

< cpp‎ | iterator‎ | common iterator
template <class I2, std::sentinel_for<I> S2>

requires std::sentinel_for<S, I2>
friend constexpr bool operator==( const common_iterator& x,

const std::common_iterator<I2, S2>& y );
 (1) (C++20 起)
template <class I2, std::sentinel_for<I> S2>

requires std::sentinel_for<S, I2> && std::equality_comparable_with<I, I2>
friend constexpr bool operator==( const common_iterator& x,

const std::common_iterator<I2, S2>& y );
 (2) (C++20 起)

比较底层 std::variant 成员对象 var 所保有的迭代器与/或哨位。认为二个不可比较的迭代器或二个哨位相等。

若 x 或 y 在非法状态，即 x.var.valueless_by_exception() || y.var.valueless_by_exception() 等于 true 则行为未定义。

令 i 为 x.var.index() ， j 为 y.var.index() 。

1) 若 i == j （即 x 与 y 均保有迭代器或哨位）则返回 true ，否则返回 std::get<i>(x.var) == std::get<j>(y.var) ；
2) 若 i == 1 && j == 1 （即 x 与 y 均保有哨位）则返回 true ，否则返回 std::get<i>(x.var) == std::get<j>(y.var) 。

!= 运算符从 operator== 合成。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::common_iterator<I> 为参数的关联类时由实参依赖查找找到。

参数

x, y - 要比较的迭代器适配器

返回值

若底层迭代器与/或哨位相等则为 true 。

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <initializer_list>

int main()
{
    int a[] {0, 1, 2, 3};

    using CI = std::common_iterator<
                   std::counted_iterator<int*>,
                   std::default_sentinel_t
                   >;

    CI i1{ std::counted_iterator{ a + 0, 2 } };
    CI i2{ std::counted_iterator{ a + 1, 2 } };
    CI i3{ std::counted_iterator{ a + 0, 3 } };
    CI i4{ std::counted_iterator{ a + 0, 0 } };
    CI s1{ std::default_sentinel };
    CI s2{ std::default_sentinel };

    std::cout << std::boolalpha
              << (i1 == i2) << ' '   // true
              << (i1 == i3) << ' '   // false
              << (i2 == i3) << ' '   // false
              << (s1 == s2) << ' '   // true
              << (i1 == s1) << ' '   // false
              << (i4 == s1) << '\n'; // true
}

输出：

true false false true false true

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3574 | C++20 | variant 为完全 constexpr (P2231R1) 但 common_iterator 不是 | 亦使之为 constexpr

参阅

operator-
(C++20)
 计算二个迭代器适配器间的距离
(函数模板)


std::contiguous_iterator

< cpp‎ | iterator
定义于头文件 <iterator>
template<class I>

concept contiguous_iterator =
std::random_access_iterator<I> &&
std::derived_from</*ITER_CONCEPT*/<I>, std::contiguous_iterator_tag> &&
std::is_lvalue_reference_v <std::iter_reference_t<I>> &&
std::same_as<
std::iter_value_t<I>, std::remove_cvref_t<std::iter_reference_t<I>>
> &&
requires(const I& i) {
{ std::to_address(i) } ->
std::same_as< std::add_pointer_t <std::iter_reference_t<I>>>;

};
 (C++20 起)

contiguous_iterator 概念细化 random_access_iterator ，通过提供代表的元素连续存储于内存中的保证。

迭代器概念确定

此概念的定义通过仅用于阐释的别名模板 /*ITER_CONCEPT*/ 说明。

为确定 /*ITER_CONCEPT*/<I> ，令 ITER_TRAITS<I> 若特化 std::iterator_traits <I> 从主模板生成则指代 I ，否则指代 std::iterator_traits <I> ：

  • 若 ITER_TRAITS<I>::iterator_concept 合法并指名类型，则 /*ITER_CONCEPT*/<I> 指代该类型。
  • 否则，若 ITER_TRAITS<I>::iterator_category 合法并指名类型，则 /*ITER_CONCEPT*/<I> 指代该类型。
  • 否则，若 std::iterator_traits <I> 从主模板生成，则 /*ITER_CONCEPT*/<I> 指代 std::random_access_iterator_tag 。
  • 否则 /*ITER_CONCEPT*/<I> 不指代类型并导致替换失败。

语义要求

设 a 与 b 为 I 类型的可解引用迭代器， c 为 I 类型的不可解引用迭代器，使得 b 从 a 可抵达而 c 从 b 可抵达。类型 I 实现 contiguous_iterator 仅若其所蕴含的所有概念均被实现，且：

  • std::to_address(a) == std::addressof (*a) ，
  • std::to_address(b) == std::to_address(a) + std::iter_difference_t<I>(b - a) ，并且
  • std::to_address(c) == std::to_address(a) + std::iter_difference_t<I>(c - a) 。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

隐式表达式变种

使用不修改某 const 左值运算数的表达式的 requires 表达式亦隐式要求该表达式的额外变种对给定运算数接受非 const 左值或（可为 const 的）右值，除非以有区别的语义显式要求这种表达式变种。这些隐式表达式变种必须符合与声明的表达式的相同的语义。不指定实现以何种程度校验变种的语法。

注解

每个指向完整对象类型的指针类型都实现 contiguous_iterator 。

标准库中，在 C++17 被要求满足老式连续迭代器 (LegacyContiguousIterator) 要求的迭代器类型，亦在 C++20 中被要求实现 contiguous_iterator 。

参阅

random_access_iterator
(C++20)
 指定 bidirectional_iterator 为随机访问迭代器，支持常数时间内的前进和下标访问
(概念)


std::counted_iterator

< cpp‎ | iterator
定义于头文件 <iterator>
template< std::input_or_output_iterator I >
class counted_iterator;
 (C++20 起)

std::counted_iterator 是表现准确同底层迭代器的迭代器适配器，除了它记录到其范围末尾的距离。此迭代器等于 std::default_sentinel 当且仅当其计数抵达零。

成员类型

成员类型 | 定义
iterator_type | I
value_type | 若 I 实现 indirectly_readable 则为 std::iter_value_t<I> ；否则不定义
difference_type | std::iter_difference_t<I>
iterator_concept | 若 I::iterator_concept 存在则为它；否则不定义
iterator_category | 若 I::iterator_category 存在则为它；否则不定义

成员函数

(构造函数) (C++20) | 构造新的迭代器适配器 (公开成员函数)
operator= (C++20) | 赋值另一迭代器适配器 (公开成员函数)
base (C++20) | 访问底层迭代器 (公开成员函数)
count (C++20) | 返回到末尾的距离 (公开成员函数)
operator*operator-> (C++20) | 访问被指向的元素 (公开成员函数)
operator[] (C++20) | 按索引访问元素 (公开成员函数)
operator++operator++(int)operator+=operator+operator--operator--(int)operator-=operator- (C++20) | 推进或回退迭代器 (公开成员函数)

成员对象

成员名 | 定义
current (私有) | base() 所访问的底层迭代器，名字仅用于阐释
length (私有) | 底层迭代器与其范围末尾的距离，名字仅用于阐释

非成员函数

operator==operator<=> (C++20) | 比较到末尾的距离 (函数模板)
operator==(std::default_sentinel) (C++20) | 检查到末尾的距离是否等于 ​0​ (函数模板)
operator+ (C++20) | 令迭代器前进 (函数模板)
operator- (C++20) | 计算两个迭代器适配器间的距离 (函数模板)
operator-(std::default_sentinel_t) (C++20) | 计算到末尾的有符号距离 (函数模板)
iter_move (C++20) | 转型解引用底层迭代器的结果为其所关联的右值引用类型 (函数)
iter_swap (C++20) | 交换二个底层迭代器所指向的对象 (函数模板)

辅助类

std::iterator_traits<std::counted_iterator>
(C++20)
 对 std::counted_iterator 类型的属性提供均一的接口
(类模板特化)

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
using std::operator""s;

void print(auto const remark, auto const& v) {
    const auto size = std::ssize(v);
    std::cout << remark << "[" << size << "] { ";
    for (auto it = std::counted_iterator{std::cbegin(v), size};
         it != std::default_sentinel; ++it) {
        std::cout << *it << ", ";
    }
    std::cout << "}\n";
}

int main() {
    const auto src = {"Arcturus"s, "Betelgeuse"s, "Canopus"s, "Deneb"s, "Elnath"s };
    print("src", src);
    std::vector<decltype(src)::value_type> dst;
    std::ranges::copy(std::counted_iterator{src.begin(), 3},
                      std::default_sentinel,
                      std::back_inserter(dst));
    print("dst", dst);
}

输出：

src[5] { Arcturus, Betelgeuse, Canopus, Deneb, Elnath, }
dst[3] { Arcturus, Betelgeuse, Canopus, }

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2259R1 | C++20 | 不提供成员 typedef 对 counted_iterator 特化 std::incrementable_traits | 添加成员 typedef 以顾及 iterator_traits 修正 移除了冗余的 std::incrementable_traits 特化

参阅

default_sentinel_t (C++20) | 用于知晓其边界的迭代器的默认哨位 (类)
views::counted (C++20) | 从迭代器和计数创建子范围 (定制点对象)
ranges::take_viewviews::take (C++20) | 由另一 view 的前 N 个元素组成的 view (类模板) (范围适配器对象)


std::counted_iterator<I>::base

< cpp‎ | iterator‎ | counted iterator
constexpr const I& base() const & noexcept; | (1) | (C++20 起)
constexpr I base() &&; | (2) | (C++20 起)

返回底层迭代器。

1) 返回到底层迭代器的引用。
2) 从底层迭代器移动构造返回值。

参数

（无）

返回值

1) 到底层迭代器的引用。
1) 从底层迭代器移动构造的迭代器。

异常

可能抛出实现定义的异常。

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <type_traits>
#include <vector>

int main()
{
    std::vector<int> v = { 0, 1, 2, 3, 4 };

    std::reverse_iterator<std::vector<int>::iterator> reverse{v.rbegin()};

    std::counted_iterator counted{reverse, 3};

    static_assert(std::is_same<decltype(counted.base()),
        std::reverse_iterator<std::vector<int>::iterator>>{});

    std::cout << "Print with reverse_iterator: ";
    for (auto r = counted.base(); r != v.rend(); ++r)
        std::cout << *r << ' ';
    std::cout << '\n';

    std::cout << "Print with counted_iterator: ";
    for (; counted != std::default_sentinel; ++counted)
        std::cout << counted[0] << ' ';
    std::cout << '\n';
}

输出：

Print with reverse_iterator: 4 3 2 1 0
Print with counted_iterator: 4 3 2

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3391 | C++20 | base 的 const 版本返回底层迭代器的副本 | 返回引用
LWG 3593 | C++20 | base 的 const 版本返回引用但可以不是 noexcept | 使之为 noexcept

参阅

operator*operator-> (C++20) | 访问被指向的元素 (公开成员函数)
count (C++20) | 返回到末尾的距离 (公开成员函数)


std::counted_iterator<I>::count

< cpp‎ | iterator‎ | counted iterator
constexpr std::iter_difference_t<I> count() const noexcept; | (C++20 起)

返回底层长度，即到末尾的距离。

参数

（无）

返回值

底层长度。

示例

#include <iostream>
#include <iterator>

int main()
{
    constexpr static auto il = { 1, 2, 3, 4, 5 };
    constexpr std::counted_iterator i1{il.begin() + 1, 3};
    static_assert(i1.count() == 3);
    for (auto i2{i1}; std::default_sentinel != i2; ++i2)
        std::cout << *i2 << ' ';
    std::cout << '\n';
}

输出：

2 3 4

参阅

base
(C++20)
 访问底层迭代器
(公开成员函数)


std::counted_iterator<I>::counted_iterator

< cpp‎ | iterator‎ | counted iterator
constexpr counted_iterator() requires std::default_initializable<I> = default;
 (1) (C++20 起)
constexpr counted_iterator( I x, std::iter_difference_t<I> n );
 (2) (C++20 起)
template< class I2 >

requires std::convertible_to<const I2&, I>

constexpr counted_iterator( const counted_iterator<I2>& other );
 (3) (C++20 起)

构造新的迭代器适配器。

1) 默认构造函数。值初始化底层迭代器并以 ​0​ 初始化底层长度。在结果迭代器上的操作拥有有定义行为当且仅当值初始化的 I 上的对应操作亦拥有有定义行为。
2) 以 std::move(x) 初始化底层迭代器并以 n 初始化底层长度。若 n 为负则行为未定义。
3) 以 other 的对应组分初始化底层迭代器与长度。

参数

x | - | 要适配的迭代器
n | - | 到末尾的距离
other | - | 要转换的迭代器适配器

示例

#include <algorithm>
#include <initializer_list>
#include <iostream>
#include <iterator>

int main() {
    static constexpr auto pi = {3, 1, 4, 1, 5, 9, 2};

    // (1) 默认构造函数：
    constexpr std::counted_iterator<std::initializer_list<int>::iterator> i1{};
    static_assert(i1 == std::default_sentinel);
    static_assert(i1.count() == 0);

    // (2) 分别初始化迭代器与长度：
    constexpr std::counted_iterator<std::initializer_list<int>::iterator> i2{
        pi.begin(), pi.size() - 2
    };
    static_assert(i2.count() == 5);
    static_assert(*i2 == 3 && i2[1] == 1);

    // (3) 转换构造函数：
    std::counted_iterator<std::initializer_list<const int>::iterator> i3{i2};

    std::ranges::copy(i3, std::default_sentinel,
        std::ostream_iterator<const int>{std::cout, " "});
}

输出：

3 1 4 1 5

参阅

operator=
(C++20)
 赋值另一迭代器适配器
(公开成员函数)


std::iter_move(std::counted_iterator)

< cpp‎ | iterator‎ | counted iterator
friend constexpr std::iter_rvalue_reference_t<I>

iter_move( const std::counted_iterator& i )
noexcept(noexcept(ranges::iter_move(i.current)))

requires std::input_iterator<I>;
 (C++20 起)

转型解引用底层迭代器的结果到其关联右值引用类型。若 i.count() 等于 ​0​ 则行为未定义。

函数体等价于 return ranges​::​iter_move(i.current); ，其中 current 为底层迭代器。

此函数对通常无限定或有限定查找不可见，而只能在 std::counted_iterator<I> 为参数的关联类时由实参依赖查找找到。

参数

i - 源迭代器适配器

返回值

右值引用或纯右值临时量。

复杂度

常数。

示例

#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

void print(auto const& rem, auto const& v) {
    for (std::cout << rem << "[" << size(v) << "] { "; auto const& s : v)
        std::cout << quoted(s) << " ";
    std::cout << "}\n";
}

int main()
{
    std::vector<std::string> p { "Alpha", "Bravo", "Charlie" }, q;

    print("p", p), print("q", q);

    using RI = std::counted_iterator<std::vector<std::string>::iterator>;

    for (RI iter{ p.begin(), 2 }; iter != std::default_sentinel; ++iter) {
        q.emplace_back( /* ADL */ iter_move(iter) );
    }

    print("p", p), print("q", q);
}

可能的输出：

p[3] { "Alpha" "Bravo" "Charlie" }
q[0] { }
p[3] { "" "" "Charlie" }
q[2] { "Alpha" "Bravo" }

参阅

iter_move (C++20) | 将解引用迭代器的结果转型为其关联的右值引用类型 (定制点对象)
iter_swap (C++20) | 交换二个底层迭代器所指向的对象 (函数模板)
move (C++11) | 获得右值引用 (函数模板)
move_if_noexcept (C++11) | 若移动构造函数不抛出则获得右值引用 (函数模板)
forward (C++11) | 转发一个函数实参 (函数模板)
ranges::move (C++20) | 将某一范围的元素移动到一个新的位置 (niebloid)
ranges::move_backword (C++20) | 按从后往前的顺序移动某一范围的元素到新的位置 (niebloid)


std::iter_swap(std::counted_iterator)

< cpp‎ | iterator‎ | counted iterator
template< std::indirectly_swappable<I> I2>

friend constexpr void
iter_swap( const counted_iterator& x, const std::counted_iterator<I2>& y )

noexcept(noexcept(ranges::iter_swap(x.current, y.current)));
 (C++20 起)

交换二个底层迭代器所指向的对象。若 x.count() 或 y.count() 等于 ​0​ 则行为未定义。

函数体等价于： ranges​::​iter_swap(x.current, y.current); ，其中 current 为底层迭代器。

此函数模板对通常无限定或有限定查找不可见，而只能在 std::counted_iterator<I> 为参数的关联类时由实参依赖查找找到。

参数

x, y - 要交换所指向元素的迭代器适配器

返回值

（无）

复杂度

常数。

示例

#include <iostream>
#include <iterator>
#include <list>
#include <vector>

int main()
{
    std::vector p { 1, 2, 3, 4 },
                q { 5, 6, 7, 8 };

    std::counted_iterator<std::vector<int>::iterator> ip { p.begin(), 2 };
    std::counted_iterator<std::vector<int>::iterator> iq { q.begin(), 3 };

    std::cout << *ip << ' ' << *iq << '\n';
    iter_swap(ip, iq); // ADL
    std::cout << *ip << ' ' << *iq << '\n';

    std::list x {0, 1, 3};
    std::counted_iterator<std::list<int>::iterator> ix { x.begin(), 2 };
//  iter_swap(ip, ix); // 错误：不可间接交换
}

输出：

1 5
5 1

参阅

swap | 交换两个对象的值 (函数模板)
swap_ranges | 交换两个范围的元素 (函数模板)
iter_swap | 交换两个迭代器所指向的元素 (函数模板)
iter_swap (C++20) | 交换两个可解引用对象所引用的值 (定制点对象)
iter_move (C++20) | 转型解引用底层迭代器的结果为其所关联的右值引用类型 (函数)


std::iterator_traits<std::counted_iterator>

< cpp‎ | iterator‎ | counted iterator
定义于头文件 <iterator>
template< std::input_iterator I >

requires /* see below */
struct iterator_traits<std::counted_iterator<I>> : std::iterator_traits <I> {
using pointer = std::conditional_t <std::contiguous_iterator<I>,
std::add_pointer_t <std::iter_reference_t<I>>,
void>;

};
 (C++20 起)

从定制（从标准部分特化或程序定义特化生成）的 std::iterator_traits <I> 继承属性，调整成员类型 pointer ，其中 I 实现 input_iterator 。

值得注意的是， iterator_concept （若存在）和 iterator_category （若存在）从 std::iterator_traits <I> 继承。

requires 子句中的条件为 true 当且仅当 std::iterator_traits <I> 不从主模板生成。

注解

P2259R1 前，即使 std::iterator_traits <I> 从主模板生成也使用此特化。结果在针对迭代器概念（例如 forward_iterator ）测试 std::counted_iterator<I> 时， /*ITER_CONCEPT*/ 的确定过程不考虑 I::iterator_concept ，从而 std::counted_iterator<I> 有时错误地表现为它无法实现该概念。此错误行为在 10.4 前的 libstdc++ 与 VS 2022 17.0 Preview 3 前的 MSVC STL 中实现。

标准库对指针类型、 std::counted_iterator 及 std::common_iterator 提供 std::iterator_traits 的部分特化。

示例

#include <iterator>
#include <type_traits>
#include <list>
#include <vector>

int main() {
    std::vector v{1,2,3,4};
    std::list l{1,2,3,4};
    std::counted_iterator iv{v.begin(), 3};
    std::counted_iterator il{l.begin(), 3};
    static_assert(std::is_same<int*, std::iterator_traits<decltype(iv)>::pointer>());
    static_assert(std::is_same<void, std::iterator_traits<decltype(il)>::pointer>());
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2259R1 | C++20 | 无 requires 子句 无条件定义 pointer 为 void | 添加约束

参阅

iterator_traits
 为迭代器各项性质提供统一接口
(类模板)


std::counted_iterator<I>::operator*,->

< cpp‎ | iterator‎ | counted iterator
constexpr decltype(auto) operator*(); | (1) | (C++20 起)
constexpr decltype(auto) operator*() const requires /*dereferenceable*/<const I>; | (2) | (C++20 起)
constexpr auto operator->() const noexcept requires std::contiguous_iterator<I>; | (3) | (C++20 起)
1-2) 返回到当前元素的引用。若 this->count() <= 0 则行为未定义。函数体等价于 return *current; 。
3) 返回指向当前元素的指针。函数体等价于 return std::to_address(current); 。

参数

（无）

返回值

指向当前元素的引用或指针。

示例

#include <complex>
#include <iostream>
#include <iterator>
using std::operator""i;

int main()
{
    const auto il = { 1.i, 2.i, 3.i, 4.i, 5.i };

    for (std::counted_iterator i{il.begin() + 1, 3}; i != std::default_sentinel; ++i)
        std::cout << *i << ' ';
    std::cout << '\n';

    for (std::counted_iterator i{il.begin() + 1, 3}; i != std::default_sentinel; ++i)
        std::cout << i->imag() << ' ';
    std::cout << '\n';
}

输出：

(0,2) (0,3) (0,4)
2 3 4

参阅

operator[]
(C++20)
 按索引访问元素
(公开成员函数)


operator+(std::counted_iterator)

< cpp‎ | iterator‎ | counted iterator
friend constexpr counted_iterator operator+(

std::iter_difference_t<I> n, const counted_iterator& x )

requires std::random_access_iterator<I>;
 (C++20 起)

返回前进 n 个位置的迭代器适配器。若 n 大于 x 内记录的长度（即若 x + n 导致未定义行为）则行为未定义。

此函数对通常无限定或有限定查找不可见，而只能在 std::counted_iterator<I> 为参数的关联类时由实参依赖查找找到。

参数

n | - | 要增加迭代器的位置数
x | - | 要增加的迭代器

返回值

等于 x + n 的迭代器适配器。

示例

#include <iostream>
#include <iterator>
#include <list>
#include <vector>

int main()
{
    std::vector v { 0, 1, 2, 3, 4, 5 };
    std::counted_iterator<std::vector<int>::iterator> p{ v.begin() + 1, 4 };
    std::cout << "*p:" << *p << ", count:" << p.count() << '\n';
    std::counted_iterator<std::vector<int>::iterator> q{ 2 + p };
    std::cout << "*q:" << *q << ", count:" << q.count() << '\n';

    std::list l { 6, 7, 8, 9 };
    std::counted_iterator<std::list<int>::iterator> r{ l.begin(), 3 };
    std::cout << "*r:" << *r << ", count:" << r.count() << '\n';
//  auto s { 2 + r }; // 错误：底层迭代器不实现 std::random_access_iterator
}

输出：

*p:1, count:4
*q:3, count:2
*r:6, count:3

参阅

operator++operator++(int)operator+=operator+operator--operator--(int)operator-=operator- (C++20) | 推进或回退迭代器 (公开成员函数)
operator- (C++20) | 计算两个迭代器适配器间的距离 (函数模板)
operator-(std::default_sentinel_t) (C++20) | 计算到末尾的有符号距离 (函数模板)


operator-(std::counted_iterator)

< cpp‎ | iterator‎ | counted iterator
template< std::common_with<I> I2 >

friend constexpr std::iter_difference_t<I2> operator-(

const counted_iterator& x, const counted_iterator<I2>& y );
 (C++20 起)

计算二个迭代器适配器间的距离。

若 x 与 y 不指向同一序列的元素则行为未定义。即必须存在某个 n 使得 std::next (x.base(), x.count() + n) 与 std::next (y.base(), y.count() + n) 指代同一元素。

此函数模板对通常无限定或有限定查找不可见，而只能在 std::counted_iterator<I> 为参数的关联类时由实参依赖查找找到。

参数

x, y - 要计算差的迭代器适配器

返回值

y.count() - x.count() 。

注解

由于长度向下计数，而非向上， operator<=> 的参数在底层比较表达式中的顺序是逆转的，即 y 为 lhs 而 x 为 rhs 。

示例

#include <initializer_list>
#include <iterator>

int main()
{
    static constexpr auto v = {1, 2, 3, 4, 5, 6};
    constexpr std::counted_iterator<std::initializer_list<int>::iterator>
        it1 {v.begin(), 5},
        it2 {it1 + 3},
        it3 {v.begin(), 2};

    static_assert(it1 - it2 == -3);
    static_assert(it2 - it1 == +3);
    // static_assert(it1 - it3 == -3); // UB ： operator- 的操作数不指代同一序列的元素
}

参阅

operator++operator++(int)operator+=operator+operator--operator--(int)operator-=operator- (C++20) | 推进或回退迭代器 (公开成员函数)
operator+ (C++20) | 令迭代器前进 (函数模板)
operator-(std::default_sentinel_t) (C++20) | 计算到末尾的有符号距离 (函数模板)


operator-(std::counted_iterator<I>, std::default_sentinel_t)

< cpp‎ | iterator‎ | counted iterator
friend constexpr std::iter_difference_t<I> operator-(
const counted_iterator& x, std::default_sentinel_t );
 (1) (C++20 起)
friend constexpr std::iter_difference_t<I> operator-(
std::default_sentinel_t, const counted_iterator& y );
 (2) (C++20 起)
1) 返回到末尾的负距离。
2) 返回到末尾的正距离。

此函数模板对通常无限定或有限定查找不可见，而只能在 std::counted_iterator 为参数的关联类时由实参依赖查找找到。

参数

x, y - 要计算距离的迭代器适配器

返回值

1) -x.count() 。
2) y.count() 。

示例

#include <initializer_list>
#include <iterator>

int main()
{
    constexpr static auto v = {1, 2, 3, 4};
    constexpr std::counted_iterator<std::initializer_list<int>::iterator>
        it {v.begin(), 3};
    constexpr auto d1 = it - std::default_sentinel;
    static_assert( d1 == -3 ); // (1)
    constexpr auto d2 = std::default_sentinel - it;
    static_assert( d2 == +3 ); // (2)
}

参阅

operator++operator++(int)operator+=operator+operator--operator--(int)operator-=operator- (C++20) | 推进或回退迭代器 (公开成员函数)
operator+ (C++20) | 令迭代器前进 (函数模板)
operator- (C++20) | 计算两个迭代器适配器间的距离 (函数模板)
default_sentinel_t (C++20) | 用于知晓其边界的迭代器的默认哨位 (类)


std::counted_iterator<I>::operator=

< cpp‎ | iterator‎ | counted iterator
template <class I2>

requires std::assignable_from<I&, const I2&>

constexpr counted_iterator& operator=( const counted_iterator<I2>& other );
 (C++20 起)

从 other 赋值底层迭代器与长度。

参数

other - 作为复制来源的迭代器适配器

返回值

*this 。

示例

#include <algorithm>
#include <cassert>
#include <initializer_list>
#include <iterator>

int main()
{
    auto a = {3, 1, 4, 1, 5, 9, 2};
    std::counted_iterator<std::initializer_list<int>::iterator> p(begin(a), size(a)-2);
    std::counted_iterator<std::initializer_list<int>::iterator> q;
    assert(q.count() == 0);
    assert(q.count() != p.count());
    q = p;
    assert(q.count() == p.count());
    assert(std::ranges::equal(p, std::default_sentinel, q, std::default_sentinel));
}

参阅

(构造函数)
(C++20)
 构造新的迭代器适配器
(公开成员函数)


std::counted_iterator<I>::operator++,+,+=,--,-,-=

< cpp‎ | iterator‎ | counted iterator
constexpr counted_iterator& operator++();
 (1) (C++20 起)
decltype(auto) operator++( int );
 (2) (C++20 起)
constexpr counted_iterator operator++( int )
requires std::forward_iterator<I>;
 (3) (C++20 起)
constexpr counted_iterator& operator--()
requires std::bidirectional_iterator<I>;
 (4) (C++20 起)
constexpr counted_iterator operator--( int )
requires std::bidirectional_iterator<I>;
 (5) (C++20 起)
constexpr counted_iterator operator+( std::iter_difference_t<I> n ) const
requires std::random_access_iterator<I>;
 (6) (C++20 起)
constexpr counted_iterator& operator+=( std::iter_difference_t<I> n )
requires std::random_access_iterator<I>;
 (7) (C++20 起)
constexpr counted_iterator operator-( std::iter_difference_t<I> n ) const
requires std::random_access_iterator<I>;
 (8) (C++20 起)
constexpr counted_iterator& operator-=( std::iter_difference_t<I> n )
requires std::random_access_iterator<I>;
 (9) (C++20 起)

增或减底层迭代器 current 和到末尾的距离 length 。

若 length 会被设为负值则这些函数导致未定义行为。

1) 前自增一。等价于 ++current; --length; return *this; 。
2) 后自增一。等价于 --length; try { return current++; } catch(...) { ++length; throw; } 。
3) 后自增一。等价于 counted_iterator temp{*this}; ++*this; return temp; 。
4) 前自减一。等价于 --current; ++length; return *this; 。
5) 后自减一。等价于 counted_iterator temp{*this}; --*this; return temp; 。
6) 返回前进 n 的迭代器。等价于 return counted_iterator(current + n, length - n); 。
7) 令迭代器前进 n 。等价于 current += n; length -= n; return *this; 。
8) 返回前进 -n 的迭代器。等价于 return counted_iterator(current - n, length + n); 。
9) 令迭代器前进 -n 。等价于 current -= n; length += n; return *this; 。

参数

n - 要增或减迭代器适配器的位置数

返回值

1) *this 。
2-3) 更改前创建的 *this 副本。
4) *this 。
5) 更改前创建的 *this 副本。
6) 前进 n 的迭代器适配器。
7) *this 。
8) 前进 -n 的迭代器适配器。
9) *this 。

示例

#include <cassert>
#include <initializer_list>
#include <iterator>

int main()
{
    const auto v = {1, 2, 3, 4, 5, 6};
    std::counted_iterator<std::initializer_list<int>::iterator> it1 {v.begin(), 5};

    ++it1;              assert(*it1 == 2 && it1.count() == 4);  // (1)
    auto it2 = it1++;   assert(*it2 == 2 && *it1 == 3);         // (3)
    --it1;              assert(*it1 == 2 && it1.count() == 4);  // (4)
    auto it3 = it1--;   assert(*it3 == 2 && *it1 == 1);         // (5)
    auto it4 = it1 + 3; assert(*it4 == 4 && it4.count() == 2);  // (6)
    auto it5 = it4 - 3; assert(*it5 == 1 && it5.count() == 5);  // (8)
    it1 += 3;           assert(*it1 == 4 && it1.count() == 2);  // (7)
    it1 -= 3;           assert(*it1 == 1 && it1.count() == 5);  // (9)
}

参阅

operator+ (C++20) | 令迭代器前进 (函数模板)
operator- (C++20) | 计算两个迭代器适配器间的距离 (函数模板)


std::counted_iterator<I>::operator[]

< cpp‎ | iterator‎ | counted iterator
constexpr decltype(auto) operator[]( std::iter_difference_t<I> n ) const
requires std::random_access_iterator<I>;
 (C++20 起)

访问位于给定位置的元素。若 n 不小于记录的到末尾的距离则行为未定义。

参数

n - 相对当前位置的位移

返回值

this->base()[n] 。

示例

#include <iostream>
#include <iterator>
#include <array>
#include <list>

int main()
{
    std::array array{'A', 'B', 'C', 'D', 'E'};

    std::counted_iterator it{ array.begin() + 1, /*count:*/ 3 };

    for (int i{}; i != it.count(); ++i)
        std::cout << it[i] << ' ';
    std::cout << '\n';

    for (int i{}; i != it.count(); ++i)
        it[i] += ('E' - 'A');

    for (int i{}; i != it.count(); ++i)
        std::cout << it[i] << ' ';
    std::cout << '\n';

    std::list list {'X', 'Y', 'Z', 'W'};
    std::counted_iterator it2{ list.begin(), 3 };
//  char x = it2[0]; // 错误：不满足要求 `random_access_iterator`
    std::cout << *it2 << '\n'; // OK
}

输出：

B C D
F G H
X

参阅

operator*operator->
(C++20)
 访问被指向的元素
(公开成员函数)


operator==,<=>(std::counted_iterator)

< cpp‎ | iterator‎ | counted iterator
template< std::common_with<I> I2 >

friend constexpr bool operator==(

const counted_iterator& x, const counted_iterator<I2>& y );
 (1) (C++20 起)
template< std::common_with<I> I2 >

friend constexpr strong_ordering operator<=>(

const counted_iterator& x, const counted_iterator<I2>& y );
 (2) (C++20 起)

比较底层长度（即到末尾的距离）。

1) 检查长度是否相等。
2) 用运算符 <=> 比较底层长度。

若 x 与 y 不指向同一序列的元素则行为未定义。即必须存在某个 n 使得 std::next (x.base(), x.count() + n) 与 std::next (y.base(), y.count() + n) 指代同一元素。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

此函数模板对通常无限定或有限定查找不可见，而只能在 std::counted_iterator<I> 为参数的关联类时由实参依赖查找找到。

参数

x, y - 迭代器适配器

返回值

1) x.count() == y.count()
2) y.count() <=> x.count()

注解

由于长度向下计数，而非向上， operator<=> 的参数在底层比较表达式中的顺序是逆转的，即 y 为 lhs ， x 为 rhs 。

示例

#include <initializer_list>
#include <iterator>

int main()
{
    static constexpr auto v = {1, 2, 3, 4, 5, 6};
    constexpr std::counted_iterator<std::initializer_list<int>::iterator>
        it1 {v.begin(), 5},
        it2 {v.begin(), 5},
        it3 {v.begin() + 1, 4},
        it4 {v.begin(), 0};
    static_assert( it1 == it2 );
    static_assert( it2 != it3 );
    static_assert( it2 <  it3 );
    static_assert( it1 <= it2 );
    static_assert( it3 != std::default_sentinel );
    static_assert( it4 == std::default_sentinel );

    // it2 == std::counted_iterator{v.begin(), 4}; // UB ：运算数不指代同一序列的元素
}

参阅

operator==(std::default_sentinel) (C++20) | 检查到末尾的距离是否等于 ​0​ (函数模板)
operator+ (C++20) | 令迭代器前进 (函数模板)
operator- (C++20) | 计算两个迭代器适配器间的距离 (函数模板)


operator==(std::counted_iterator<I>, std::default_sentinel_t)

< cpp‎ | iterator‎ | counted iterator
friend constexpr bool operator==( const counted_iterator& x, std::default_sentinel_t ); | (C++20 起)

检查底层长度（即到末尾的距离）是否等于 ​0​ 。

此函数模板对通常无限定或有限定查找不可见，而只能在 std::counted_iterator<I> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

参数

x - 迭代器适配器

返回值

若 x.count() 等于 ​0​ 则为 true ，否则为 false 。

示例

#include <initializer_list>
#include <iterator>

int main()
{
    static constexpr auto v = {1, 2, 3, 4};
    constexpr std::counted_iterator<std::initializer_list<int>::iterator>
        it1 {v.begin(), 3},
        it2 {v.begin(), 0};
    static_assert( it1 != std::default_sentinel );
    static_assert( it2 == std::default_sentinel );
    static_assert( std::default_sentinel != it1 );
    static_assert( std::default_sentinel == it2 );
}

参阅

operator==operator<=>
(C++20)
 比较到末尾的距离
(函数模板)


std::data

< cpp‎ | iterator
定义于头文件 <array>
定义于头文件 <deque>
定义于头文件 <forward_list>
定义于头文件 <iterator>
定义于头文件 <list>
定义于头文件 <map>
定义于头文件 <regex>
定义于头文件 <set>
定义于头文件 <span>
(C++20 起)
定义于头文件 <string>
定义于头文件 <string_view>
(C++17 起)
定义于头文件 <unordered_map>
定义于头文件 <unordered_set>
定义于头文件 <vector>
template <class C>
constexpr auto data(C& c) -> decltype(c.data());
 (1) (C++17 起)
template <class C>
constexpr auto data(const C& c) -> decltype(c.data());
 (2) (C++17 起)
template <class T, std::size_t N>
constexpr T* data(T (&array)[N]) noexcept;
 (3) (C++17 起)
template <class E>
constexpr const E* data( std::initializer_list <E> il) noexcept;
 (4) (C++17 起)

返回指向含有范围元素的内存块的指针。

1,2) 返回 c.data()
3) 返回 array
4) 返回 il.begin()

参数

c | - | 有 data() 方法的容器或视图
array | - | 任意类型的数组
il | - | initializer_list

返回值

指向含有容器范围的内存块的指针。

异常

1) 可能抛出实现定义的异常。

注解

需要对 std::initializer_list 的重载，因为它无成员函数 data 。

可能的实现

版本一
template <class C>
constexpr auto data(C& c) -> decltype(c.data())
{
    return c.data();
}
版本二
template <class C>
constexpr auto data(const C& c) -> decltype(c.data())
{
    return c.data();
}
版本三
template <class T, std::size_t N>
constexpr T* data(T (&array)[N]) noexcept
{
    return array;
}
版本四
template <class E>
constexpr const E* data(std::initializer_list<E> il) noexcept
{
    return il.begin();
}

示例

#include <string>
#include <cstring>
#include <iostream>

int main()
{
    std::string s {"Hello world!\n"};

    char a[20]; // C-style 风格字符串的存储
    std::strcpy(a, std::data(s));
    // C++11 起 [s.data(), s.data() + s.size()] 保证为 NTBS

    std::cout << a;
}

输出：

Hello world!

参阅

ranges::data (C++20) | 获得指向连续范围的起始的指针 (定制点对象)
ranges::cdata (C++20) | 获得指向只读连续范围的起始的指针 (定制点对象)


std::default_sentinel_t, std::default_sentinel

< cpp‎ | iterator
定义于头文件 <iterator> |  |
struct default_sentinel_t { }; | (1) | (C++20 起)
inline constexpr default_sentinel_t default_sentinel{}; | (2) | (C++20 起)
1) default_sentinel_t 是用于表示范围结尾的空类类型。能与知晓其范围边界的迭代器类型（例如 std::counted_iterator ）一同使用它。
2) default_sentinel 是 default_sentinel_t 类型常量。

示例

#include <iterator>
#include <algorithm>
#include <list>
#include <iostream>

int main()
{
    std::list<int> l{3,1,4,1,5,9,2,6};

    std::ranges::copy(std::counted_iterator(std::begin(l), 4),
        std::default_sentinel, std::ostream_iterator<int>{std::cout, " "});
}

输出：

3 1 4 1

参阅

istream_iterator | 从 std::basic_istream 读取的输入迭代器 (类模板)
istreambuf_iterator | 从 std::basic_streambuf 读取的输入迭代器 (类模板)
counted_iterator (C++20) | 对到范围结尾距离进行跟踪的迭代器适配器 (类模板)


std::distance

< cpp‎ | iterator
定义于头文件 <iterator>
template< class InputIt >

typename std::iterator_traits <InputIt>::difference_type

distance( InputIt first, InputIt last );
 (C++17 起为 constexpr)

返回从 first 到 last 的路程。

若 last 不可从 first 通过（可以重复）自增 first 抵达，则行为未定义。 | (C++11 前)
若 InputIt 不是老式随机访问迭代器 (LegacyRandomAccessIterator) ，则若 last 不可从 first 通过（可以重复）自增 first 抵达，则行为未定义。 若 InputIt 是老式随机访问迭代器 (LegacyRandomAccessIterator) ，则若 last 不可从 first 抵达且 first 不可从 last 抵达，则行为未定义。 | (C++11 起)

参数

first | - | 指向首元素的迭代器
last | - | 指向范围尾的迭代器
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。若 InputIt 额外满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求则操作更高效

返回值

从 first 走到 last 所需的自增数。若使用随机访问迭代器且 first 可从 last 抵达，则值可能为负。 (C++11 起)

复杂度

线性。

然而，若 InputIt 额外满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求，则复杂度是常数。

可能的实现

参阅 libstdc++ 与 libc++ 中的实现。

版本一
// 经由标签派发的实现，移除 constexpr 后可用于 C++98
namespace detail {

template<class It>
constexpr // C++17 起要求
typename std::iterator_traits<It>::difference_type
    do_distance(It first, It last, std::input_iterator_tag)
{
    typename std::iterator_traits<It>::difference_type result = 0;
    while (first != last) {
        ++first;
        ++result;
    }
    return result;
}

template<class It>
constexpr // C++17 起要求
typename std::iterator_traits<It>::difference_type
    do_distance(It first, It last, std::random_access_iterator_tag)
{
    return last - first;
}

} // namespace detail

template<class It>
constexpr // C++17 起
typename std::iterator_traits<It>::difference_type
    distance(It first, It last)
{
    return detail::do_distance(first, last,
                               typename std::iterator_traits<It>::iterator_category());
}
版本二
// 经由 constexpr if 的实现，可用于 C++17
template<class It>
constexpr typename std::iterator_traits<It>::difference_type
    distance(It first, It last)
{
    using category = typename std::iterator_traits<It>::iterator_category;
    static_assert(std::is_base_of_v<std::input_iterator_tag, category>);

    if constexpr (std::is_base_of_v<std::random_access_iterator_tag, category>)
        return last - first;
    else {
        typename std::iterator_traits<It>::difference_type result = 0;
        while (first != last) {
            ++first;
            ++result;
        }
        return result;
    }
}

示例

#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> v{ 3, 1, 4 };
    std::cout << "distance(first, last) = "
              << std::distance(v.begin(), v.end()) << '\n'
              << "distance(last, first) = "
              << std::distance(v.end(), v.begin()) << '\n';
}

输出：

distance(first, last) = 3
distance(last, first) = -3

参阅

advance
 令迭代器前进给定的距离
(函数模板)


std::empty

< cpp‎ | iterator
定义于头文件 <array>
定义于头文件 <deque>
定义于头文件 <forward_list>
定义于头文件 <iterator>
定义于头文件 <list>
定义于头文件 <map>
定义于头文件 <regex>
定义于头文件 <set>
定义于头文件 <span>
(C++20 起)
定义于头文件 <string>
定义于头文件 <string_view>
(C++17 起)
定义于头文件 <unordered_map>
定义于头文件 <unordered_set>
定义于头文件 <vector>
(1)
template <class C>
constexpr auto empty(const C& c) -> decltype(c.empty());
 (C++17 起)
(C++20 前)
template <class C>
[[nodiscard]] constexpr auto empty(const C& c) -> decltype(c.empty());
 (C++20 起)
(2)
template <class T, std::size_t N>
constexpr bool empty(const T (&array)[N]) noexcept;
 (C++17 起)
(C++20 前)
template <class T, std::size_t N>
[[nodiscard]] constexpr bool empty(const T (&array)[N]) noexcept;
 (C++20 起)
(3)
template <class E>
constexpr bool empty( std::initializer_list <E> il) noexcept;
 (C++17 起)
(C++20 前)
template <class E>
[[nodiscard]] constexpr bool empty( std::initializer_list <E> il) noexcept;
 (C++20 起)

返回给定的范围是否为空。

1) 返回 c.empty()
2) 返回 false
3) 返回 il.size() == 0

参数

c | - | 拥有 empty 成员函数的容器或视图
array | - | 任意类型的数组
il | - | 一个 initializer_list

返回值

若范围不含有任何元素则为 true 。

异常

1) 可能抛出实现定义的异常。

注解

需要对 std::initializer_list 的重载，因为它无成员函数 empty 。

可能的实现

版本一
template <class C>
[[nodiscard]] constexpr auto empty(const C& c) -> decltype(c.empty())
{
    return c.empty();
}
版本二
template <class T, std::size_t N>
[[nodiscard]] constexpr bool empty(const T (&array)[N]) noexcept
{
    return false;
}
版本三
template <class E>
[[nodiscard]] constexpr bool empty(std::initializer_list<E> il) noexcept
{
    return il.size() == 0;
}

示例

#include <iostream>
#include <vector>

template <class T>
void print(const T& container)
{
    if ( !std::empty(container) )
    {
         std::cout << "Elements:\n";
         for ( const auto& element : container )
             std::cout << element << '\n';
    }
    else
    {
        std::cout << "Empty\n";
    }
}

int main()
{
    std::vector<int> c = { 1, 2, 3 };
    print(c);
    c.clear();
    print(c);

    int array[] = { 4, 5, 6 };
    print(array);

    auto il = { 7, 8, 9 };
    print(il);
}

输出：

Elements:
1
2
3
Empty
Elements:
4
5
6
Elements:
7
8
9

参阅

ranges::empty
(C++20)
 检查范围是否为空
(定制点对象)


std::end, std::cend

< cpp‎ | iterator
定义于头文件 <array>
定义于头文件 <deque>
定义于头文件 <forward_list>
定义于头文件 <iterator>
定义于头文件 <list>
定义于头文件 <map>
定义于头文件 <regex>
定义于头文件 <set>
定义于头文件 <span>
(C++20 起)
定义于头文件 <string>
定义于头文件 <string_view>
(C++17 起)
定义于头文件 <unordered_map>
定义于头文件 <unordered_set>
定义于头文件 <vector>
(1)
template< class C >
auto end( C& c ) -> decltype(c.end());
 (C++11 起)
(C++17 前)
template< class C >
constexpr auto end( C& c ) -> decltype(c.end());
 (C++17 起)
(1)
template< class C >
auto end( const C& c ) -> decltype(c.end());
 (C++11 起)
(C++17 前)
template< class C >
constexpr auto end( const C& c ) -> decltype(c.end());
 (C++17 起)
(2)
template< class T, std::size_t N >
T* end( T (&array)[N] );
 (C++11 起)
(C++14 前)
template< class T, std::size_t N >
constexpr T* end( T (&array)[N] ) noexcept;
 (C++14 起)
template< class C >

constexpr auto cend( const C& c ) noexcept(/* see below */)

-> decltype(std::end(c));
 (3) (C++14 起)

返回指向给定范围结尾（即最末元素的后一元素）的迭代器。

1) 准确返回 c.end() ，典型地是指向 c 所代表的序列末尾后一位置的迭代器。若 C 是标准容器 (Container) ，则在 c 非 const 限定时返回 C::iterator ，否则返回 C::const_iterator 。
2) 返回指向数组 array 末尾的指针。
3) 准确返回 std::end(c) ，这里 c 始终当做 const 限定。若 C 是标准容器 (Container) ，则始终返回 C::const_iterator 。

参数

c | - | 拥有 end 成员函数的容器或视图
array | - | 任意类型的数组

返回值

指向范围结尾的迭代器。注意容器或数组的结尾定义为最后一个合法元素的下一个元素。

异常

3)
noexcept 说明：
noexcept(noexcept(std::end(c)))

重载

可为不暴露适合的 end() 成员函数的类或枚举提供 end 的自定义重载。标准库已提供下列重载：

std::end(std::initializer_list) (C++11) | 特化 std::end (函数模板)
std::end(std::valarray) (C++11) | 特化的 std::end (函数模板)
begin(std::filesystem::directory_iterator)end(std::filesystem::directory_iterator) | 基于范围的 for 循环支持 (函数)
begin(std::filesystem::recursive_directory_iterator)end(std::filesystem::recursive_directory_iterator) | 基于范围的 for 循环支持 (函数)

类似 swap 的使用（于可交换 (Swappable) 描述）， end 函数在泛型语境中的典型使用等价于 using std::end; end(arg); ，这允许 ADL 为用户定义类型所选择的重载，和出现于同一重载集中的标准库函数模板。

template<typename Container, typename Function>
void for_each(Container&& cont, Function f) {
    using std::begin;
    auto it = begin(cont);
    using std::end;
    auto end_it = end(cont);
    while (it != end_it) {
        f(*it);
        ++it;
    }
}

实参依赖查找所找到的 end 重载能用于定制 std::ranges::end、 std::ranges::cend 及其他依赖于 std::ranges::begin 的定制点对象的行为。

 (C++20 起)

注解

(1,3) 准确地反映 C::end() 的行为。若该成员函数无合理的实现，则它们的效果可能令人惊异。

std::cend 是为统一成员与非成员范围访问引入的。参阅 LWG 问题 2128 。

若 C 是浅 const 的视图，则 std::cend 可能返回可变的迭代器。某些用户不期待这种行为。参阅 P2276 与 P2278 。

示例

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

int main()
{
    std::vector<int> v = { 3, 1, 4 };
    if (std::find(std::begin(v), std::end(v), 5) != std::end(v)) {
        std::cout << "found a 5 in vector v!\n";
    }

    int a[] = { 5, 10, 15 };
    if (std::find(std::begin(a), std::end(a), 5) != std::end(a)) {
        std::cout << "found a 5 in array a!\n";
    }
}

输出：

found a 5 in array a!

参阅

begincbegin (C++11)(C++14) | 返回指向容器或数组起始的迭代器 (函数模板)
ranges::end (C++20) | 返回指示范围结尾的哨位 (定制点对象)
ranges::cend (C++20) | 返回指示只读范围结尾的哨位 (定制点对象)


std::forward_iterator

< cpp‎ | iterator
定义于头文件 <iterator>
template<class I>

concept forward_iterator =
std::input_iterator<I> &&
std::derived_from</*ITER_CONCEPT*/<I>, std::forward_iterator_tag > &&
std::incrementable<I> &&

std::sentinel_for<I, I>;
 (C++20 起)

此概念细化 std::input_iterator ，通过要求 I 亦实现 std::incrementable （从而使之适合多趟算法），并保证指向同一范围的二个迭代器可相互比较。

迭代器概念确定

此概念的定义通过仅用于阐释的别名模板 /*ITER_CONCEPT*/ 说明。

为确定 /*ITER_CONCEPT*/<I> ，令 ITER_TRAITS<I> 若特化 std::iterator_traits <I> 从主模板生成则指代 I ，否则指代 std::iterator_traits <I> ：

  • 若 ITER_TRAITS<I>::iterator_concept 合法并指名类型，则 /*ITER_CONCEPT*/<I> 指代该类型。
  • 否则，若 ITER_TRAITS<I>::iterator_category 合法并指名类型，则 /*ITER_CONCEPT*/<I> 指代该类型。
  • 否则，若 std::iterator_traits <I> 从主模板生成，则 /*ITER_CONCEPT*/<I> 指代 std::random_access_iterator_tag 。
  • 否则 /*ITER_CONCEPT*/<I> 不指代类型并导致替换失败。

语义要求

I 实现 std::forward_iterator 当且仅当 I 实现其所蕴含的所有概念，并且给定 I 类型对象 i 与 j ：

  • 若符合下列条件，则迭代器 i 与 j 间的比较拥有定义的结果：
  • i 与 j 为指向同一底层序列的迭代器，或
  • i 与 j 均被值初始化，该情况下它们比较相等。
  • 从指向范围中的向前迭代器获得的指针与引用在该范围存在时保持合法。
  • 若 i 与 j 可解引用，则它们提供多趟保证，即：
  • i == j 蕴含 ++i == ++j ，且
  • ((void)[](auto x){ ++x; }(i), *i) 等价于 *i 。

注解

不同于老式向前迭代器 (LegacyForwardIterator) 要求， forward_iterator 概念不要求解引用返回左值。

参阅

input_iterator
(C++20)
 指定类型为输入迭代器，即可读取其所引用的值，且可前/后自增
(概念)


std::front_insert_iterator

< cpp‎ | iterator
定义于头文件 <iterator> |
template< class Container > class front_insert_iterator : public std::iterator < std::output_iterator_tag, void,void,void,void > | (C++17 前)
template< class Container > class front_insert_iterator; | (C++17 起)

std::front_insert_iterator 是前附元素到为之构造迭代器的老式输出迭代器 (LegacyOutputIterator) 。凡在赋值给（无论是否解引用）迭代器时调用容器的 push_front() 成员函数。自增 std::front_insert_iterator 是无操作。

成员类型

成员类型 | 定义
iterator_category | std::output_iterator_tag
value_type | void
difference_type
void | (C++20 前)
std::ptrdiff_t | (C++20 起)
pointer | void
reference | void
container_type | Container

要求通过从 std::iterator < std::output_iterator_tag, void, void, void, void> 继承获得成员类型 iterator_category、 value_type、 difference_type、 pointer 及 reference 。

 (C++17 前)

成员函数

(构造函数) | 构造新的 front_insert_iterator (公开成员函数)
operator= | 插入对象到关联的容器 (公开成员函数)
operator* | 无操作 (公开成员函数)
operator++operator++(int) | 无操作 (公开成员函数)

成员对象

成员名 | 定义
container (受保护成员对象) | Container* 类型指针

示例

#include <vector>
#include <deque>
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
    std::vector<int> v{1,2,3,4,5};
    std::deque<int> d;
    std::copy(v.begin(), v.end(),
              std::front_insert_iterator<std::deque<int>>(d)); // 或 std::front_inserter(d)
    for(int n : d)
        std::cout << n << ' ';
    std::cout << '\n';
}

输出：

5 4 3 2 1

参阅

front_inserter | 创建拥有从实参推出的类型的 std::front_insert_iterator (函数模板)
back_insert_iterator | 用于在容器尾部插入的迭代器适配器 (类模板)
insert_iterator | 用于插入容器的迭代器适配器 (类模板)


std::front_insert_iterator<Container>::front_insert_iterator

< cpp‎ | iterator‎ | front insert iterator

explicit front_insert_iterator( Container& c ); | (C++20 前)
explicit constexpr front_insert_iterator( Container& c ); | (C++20 起)

初始化底层指向容器指针为 std::addressof (c) 。

参数

c - 用以初始化插入器的容器

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | 由于 C++20 迭代器必须为 default_initializable 提供了默认构造函数 | 与该要求一同移除


std::front_insert_iterator<Container>::operator*

< cpp‎ | iterator‎ | front insert iterator

front_insert_iterator& operator*(); | (C++20 前)
constexpr front_insert_iterator& operator*(); | (C++20 起)

不做任何事，提供此函数以满足老式输出迭代器 (LegacyOutputIterator) 的要求。

它返回迭代器自身，这使得可以用诸如 *iter = value 的代码输出（插入）值到底层的容器。

参数

（无）

返回值

*this


std::front_insert_iterator<Container>::operator++

< cpp‎ | iterator‎ | front insert iterator
front_insert_iterator& operator++(); | (C++20 前)
constexpr front_insert_iterator& operator++(); | (C++20 起)
front_insert_iterator operator++( int ); | (C++20 前)
constexpr front_insert_iterator operator++( int ); | (C++20 起)

不做任何事。提供这些运算符以满足老式输出迭代器 (LegacyOutputIterator) 的要求。它们使得表达式 *iter++=value 和 *++iter=value 可用于输出（插入）值到底层的容器。

参数

（无）

返回值

*this


std::front_insert_iterator<Container>::operator=

< cpp‎ | iterator‎ | front insert iterator

 | (1)
front_insert_iterator<Container>& operator=( typename Container::const_reference value ); |  | (C++11 前)
front_insert_iterator<Container>& operator=( const typename Container::value_type& value ); |  | (C++11 起) (C++20 前)
constexpr front_insert_iterator<Container>& operator=( const typename Container::value_type& value ); |  | (C++20 起)
 | (2)
front_insert_iterator<Container>& operator=( typename Container::value_type&& value ); |  | (C++11 起) (C++20 前)
constexpr front_insert_iterator<Container>& operator=( typename Container::value_type&& value ); |  | (C++20 起)

插入给定的 value 到迭代器。

1) 导致 container->push_front(value)
2) 导致 container->push_front(std::move(value))

参数

value - 要插入的值

返回值

*this

示例

#include <iostream>
#include <iterator>
#include <deque>

int main()
{
    std::deque<int> q;
    std::front_insert_iterator< std::deque<int> > it(q);

    for (int i=0; i<10; ++i)
        it = i; // 调用 q.push_front(i)

    for (auto& elem : q) std::cout << elem << ' ';
}

输出：

9 8 7 6 5 4 3 2 1 0


std::front_inserter

< cpp‎ | iterator
定义于头文件 <iterator> |
template< class Container > std::front_insert_iterator <Container> front_inserter( Container& c ); | (C++20 前)
template< class Container > constexpr std::front_insert_iterator <Container> front_inserter( Container& c ); | (C++20 起)

front_inserter 是为类型从参数类型推导的容器 c 构造 std::front_insert_iterator 的便利函数模板。

参数

c - 支持 push_front 操作的容器

返回值

能用于添加元素到容器 c 起始的 std::front_insert_iterator

可能的实现

template< class Container >
std::front_insert_iterator<Container> front_inserter( Container& c )
{
    return std::front_insert_iterator<Container>(c);
}

示例

#include <vector>
#include <deque>
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
    std::vector<int> v{1, 2, 3, 4, 5};
    std::deque<int> d;
    std::copy(v.begin(), v.end(), std::front_inserter(d));
    for(int n : d)
        std::cout << n << ' ';
}

输出：

5 4 3 2 1

参阅

front_insert_iterator | 用于在容器头部插入的迭代器适配器 (类模板)
back_inserter | 创建拥有从实参推出的类型的 std::back_insert_iterator (函数模板)
inserter | 创建拥有从实参推出的类型的 std::insert_iterator (函数模板)


std::incrementable

< cpp‎ | iterator
定义于头文件 <iterator>
template<class I>

concept incrementable =
std::regular<I> &&
std::weakly_incrementable<I> &&
requires(I i) {
{ i++ } -> std::same_as<I>;

};
 (C++20 起)

此概念指定能以前后自增运算符自增的类型上的要求，其自增运算必须保持相等性，且类型为 std::equality_comparable 。

不同于仅支持单趟算法的 std::weakly_incrementable ，实现 std::incrementable 的类型可用于多趟单方向算法。

语义要求

I 仅若满足下列条件才实现 std::incrementable 。给定类型 I 的二个可自增对象 a 与 b ：

  • bool(a == b) 蕴含 bool(a++ == b) ，且
  • bool(a == b) 蕴含 bool(((void)a++, a) == ++b)

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

参阅

weakly_incrementable (C++20) | 指定 semiregular 类型能以前后自增运算符自增 (概念)
same_as (C++20) | 指定一个类型与另一类型相同 (概念)


std::incrementable_traits

< cpp‎ | iterator
定义于头文件 <iterator>
template< class I >
struct incrementable_traits { };
 (1) (C++20 起)
template< class T >

requires std::is_object_v <T>

struct incrementable_traits<T*>;
 (2) (C++20 起)
template< class T >
struct incrementable_traits<const T> : incrementable_traits<T> { };
 (3) (C++20 起)
template< class T >

requires requires { typename T::difference_type; }

struct incrementable_traits<T>;
 (4) (C++20 起)
template< class T >

requires (!requires { typename T::difference_type; }) &&
requires(const T& a, const T& b) { { a - b } -> std::integral; }

struct incrementable_traits<T>;
 (5) (C++20 起)

计算类型 I 的关联差类型，若它存在。用户可对程序定义类型特化 incrementable_traits 。

1) 初等模板是空 struct 。
2) 对指针的特化。提供等于 std::ptrdiff_t 的成员类型 difference_type 。
3) 对 const 限定类型的特化。
4) 对定义公开可访问成员类型 difference_type 的类型的特化。提供等于 T::difference_type 的成员类型 difference_type 。
5) 对不定义公开可访问成员类型 difference_type 但支持减法的类型的特化。提供等于 std::make_signed_t <decltype( std::declval <T>() - std::declval <T>())> 的成员类型 difference_type 。隐式表达式变种规则（见后述）应用于表达式 a - b 。

隐式表达式变种

使用不修改某 const 左值运算数的表达式的 requires 表达式亦隐式要求该表达式的额外变种对给定运算数接受非 const 左值或（可为 const 的）右值，除非以有区别的语义显式要求这种表达式变种。这些隐式表达式变种必须符合与声明的表达式的相同的语义。不指定实现以何种程度校验变种的语法。

示例

本节未完成
原因：暂无示例

参阅

weakly_incrementable (C++20) | 指定 semiregular 类型能以前后自增运算符自增 (概念)
iter_value_titer_reference_titer_difference_titer_rvalue_reference_titer_common_reference_t (C++20)(C++20)(C++20)(C++20)(C++20) | 计算迭代器的关联类型 (别名模板)
iterator_traits | 为迭代器各项性质提供统一接口 (类模板)


std::indirect_binary_predicate

< cpp‎ | iterator
定义于头文件 <iterator>
template< class F, class I1, class I2 >

concept indirect_binary_predicate =
std::indirectly_readable<I1> &&
std::indirectly_readable<I2> &&
std::copy_constructible<F> &&
std::predicate<F&, std::iter_value_t<I1>&, std::iter_value_t<I2>&> &&
std::predicate<F&, std::iter_value_t<I1>&, std::iter_reference_t<I2>> &&
std::predicate<F&, std::iter_reference_t<I1>, std::iter_value_t<I2>&> &&
std::predicate<F&, std::iter_reference_t<I1>, std::iter_reference_t<I2>> &&

std::predicate<F&, std::iter_common_reference_t<I1>, std::iter_common_reference_t<I2>>;
 (C++20 起)

概念 indirect_binary_predicate 指定调用作为其参数的二元谓词的算法的要求。此概念与 std::predicate 的关键区别是它被应用到 I1 与 I2 所引用的类型，而非 I1 与 I2 自身。

语义要求

F 、 I1 与 I2 实现 indirect_binary_predicate 仅若其所蕴含的所有概念均得到实现。


std::indirect_equivalence_relation

< cpp‎ | iterator
定义于头文件 <iterator>
template<class F, class I1, class I2 = I1>

concept indirect_equivalence_relation =
std::indirectly_readable<I1> &&
std::indirectly_readable<I2> &&
std::copy_constructible<F> &&
std::equivalence_relation<F&, std::iter_value_t<I1>&, std::iter_value_t<I2>&> &&
std::equivalence_relation<F&, std::iter_value_t<I1>&, std::iter_reference_t<I2>> &&
std::equivalence_relation<F&, std::iter_reference_t<I1>, std::iter_value_t<I2>&> &&
std::equivalence_relation<F&, std::iter_reference_t<I1>, std::iter_reference_t<I2>> &&

std::equivalence_relation<F&, std::iter_common_reference_t<I1>, std::iter_common_reference_t<I2>>;
 (C++20 起)

概念 indirect_equivalence_relation 指定调用作为其参数的等价关系的算法的要求。此概念与 std::equivalence_relation 间的关键区别是它被应用到 I1 与 I2 所引用的类型，而非 I1 与 I2 自身。

语义要求

F 、 I1 与 I2 实现 indirect_equivalence_relation 仅若其所蕴含的概念均得以实现。


std::indirect_result_t

< cpp‎ | iterator
定义于头文件 <iterator>
template< class F, class... Is >

requires (std::indirectly_readable<Is> && ...) &&
std::invocable<F, std::iter_reference_t<Is>...>

using indirect_result_t = std::invoke_result_t<F, std::iter_reference_t<Is>...>;
 (C++20 起)

别名模板 indirect_result_t 获得在解引用 indirectly_readable 类型 Is... 的结果上调用 invocable 类型 F 的结果类型。

模板形参

F | - | 可调用类型
Is | - | 解引用到实参的间接可读类型

参阅

result_ofinvoke_result
(C++11)(C++20 中移除)(C++17)
 推导以一组实参调用一个可调用对象的结果类型
(类模板)


std::indirect_strict_weak_order

< cpp‎ | iterator
定义于头文件 <iterator>
template<class F, class I1, class I2 = I1>

concept indirect_strict_weak_order =
std::indirectly_readable<I1> &&
std::indirectly_readable<I2> &&
std::copy_constructible<F> &&
std::strict_weak_order<F&, std::iter_value_t<I1>&, std::iter_value_t<I2>&> &&
std::strict_weak_order<F&, std::iter_value_t<I1>&, std::iter_reference_t<I2>> &&
std::strict_weak_order<F&, std::iter_reference_t<I1>, std::iter_value_t<I2>&> &&
std::strict_weak_order<F&, std::iter_reference_t<I1>, std::iter_reference_t<I2>> &&

std::strict_weak_order<F&, std::iter_common_reference_t<I1>, std::iter_common_reference_t<I2>>;
 (C++20 起)

概念 indirect_strict_weak_order 指定调用作为其参数的严格弱序的算法的要求。此概念与 std::strict_weak_order 间的关键区别是它被应用到 I1 与 I2 所引用的类型，而非 I1 与 I2 自身。

语义要求

F 、 I1 与 I2 实现 indirect_strict_weak_order 仅若其所蕴含的概念均得以实现。


std::indirect_unary_predicate

< cpp‎ | iterator
定义于头文件 <iterator>
template<class F, class I>

concept indirect_unary_predicate =
std::indirectly_readable<I> &&
std::copy_constructible<F> &&
std::predicate<F&, std::iter_value_t<I>&> &&
std::predicate<F&, std::iter_reference_t<I>> &&

std::predicate<F&, std::iter_common_reference_t<I>>;
 (C++20 起)

概念 indirect_unary_predicate 指定调用作为其参数的一元谓词的算法的要求。此概念与 std::predicate 的关键区别是它被应用到 I 所引用的类型，而非 I 自身。

语义要求

F 与 I 实现 indirect_unary_predicate ，仅若其所蕴含的所有概念均得到实现。


std::indirectly_comparable

< cpp‎ | iterator
定义于头文件 <iterator> |
template< class I1, class I2, class R, class P1 = std::identity, class P2 = std::identity > concept indirectly_comparable = std::indirect_binary_predicate<R, std::projected<I1, P1>, std::projected<I2, P2>>; | (C++20 起)

概念 indirectly_comparable 指定横跨二个独立范围比较值的基础算法要求。

语义要求

indirectly_comparable 仅若其所蕴含的概念均被实现才得到实现。

参阅

indirect_binary_predicate
(C++20)
 指定可调用类型，在以解引用两个 indirectly_readable 类型的结果进行调用时，满足 predicate
(概念)


std::indirectly_copyable

< cpp‎ | iterator
定义于头文件 <iterator> |
template<class In, class Out> concept indirectly_copyable = std::indirectly_readable<In> && std::indirectly_writable<Out, iter_reference_t<In>>; | (C++20 起)

indirectly_copyable 概念指定 indirectly_readable 类型与 indirectly_writable 类型间的关系。 indirectly_writable 类型必须能直接复制 indirectly_readable 类型所引用的对象。

参阅

indirectly_movable (C++20) | 指定可从 indirectly_readable 类型移动值给 indirectly_writable 类型 (概念)
indirectly_copyable_storable (C++20) | 指定可从 indirectly_readable 类型复制值给 indirectly_writable 类型，且该复制可以通过中间对象进行 (概念)


std::indirectly_copyable_storable

< cpp‎ | iterator
定义于头文件 <iterator>
template<class In, class Out>

concept indirectly_copyable_storable =
std::indirectly_copyable<In, Out> &&
std::indirectly_writable<Out, std::iter_value_t<In>&> &&
std::indirectly_writable<Out, const std::iter_value_t<In>&> &&
std::indirectly_writable<Out, std::iter_value_t<In>&&> &&
std::indirectly_writable<Out, const std::iter_value_t<In>&&> &&
std::copyable<std::iter_value_t<In>> &&
std::constructible_from<std::iter_value_t<In>, std::iter_reference_t<In>> &&

std::assignable_from<std::iter_value_t<In>&, std::iter_reference_t<In>>;
 (C++20 起)

indirectly_copyable_storable 概念指定 indirectly_readable 与 indirectly_writable 类型间的关系。在 indirectly_writable type. In addition to indirectly_copyable 之外，此概念还指定从 indirectly_readable 类型的复制能通过中间对象进行。

语义要求

In 与 Out 实现 std::indirectly_copyable_storable<In, Out> ，仅若给定 In 类型的可解引用值 i ：

  • 在定义 std::iter_value_t<In> obj(*i); 后， obj 等于 *i 先前代表的值，而
  • 若 std::iter_reference_t<In> 是右值引用类型，则 *i 在 obj 的初始化后被置于合法但未指定的状态。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

参阅

indirectly_copyable (C++20) | 指定可从 indirectly_readable 类型复制值给 indirectly_writable 类型 (概念)
indirectly_movable_storable (C++20) | 指定可从 indirectly_readable 类型移动值给 indirectly_writable 类型，且该移动可以通过中间对象进行 (概念)


std::indirectly_movable

< cpp‎ | iterator
定义于头文件 <iterator> |
template<class In, class Out> concept indirectly_movable = std::indirectly_readable<In> && std::indirectly_writable<Out, iter_rvalue_reference_t<In>>; | (C++20 起)

indirectly_movable 概念指定 indirectly_readable 类型与 indirectly_writable 类型间的关系。 indirectly_writable 类型必须能直接移动 indirectly_readable 类型所引用的对象。

参阅

indirectly_movable_storable (C++20) | 指定可从 indirectly_readable 类型移动值给 indirectly_writable 类型，且该移动可以通过中间对象进行 (概念)
indirectly_copyable (C++20) | 指定可从 indirectly_readable 类型复制值给 indirectly_writable 类型 (概念)


std::indirectly_movable_storable

< cpp‎ | iterator
定义于头文件 <iterator>
template<class In, class Out>

concept indirectly_movable_storable =
std::indirectly_movable<In, Out> &&
std::indirectly_writable<Out, std::iter_value_t<In>> &&
std::movable<std::iter_value_t<In>> &&
std::constructible_from<std::iter_value_t<In>, std::iter_rvalue_reference_t<In>> &&

std::assignable_from<std::iter_value_t<In>&, std::iter_rvalue_reference_t<In>>;
 (C++20 起)

indirectly_movable_storable 概念指定 indirectly_readable 与 indirectly_writable 类型间的关系。在 indirectly_movable 之外，此概念还指定从 indirectly_readable 类型的移动能通过中间对象进行。

语义要求

In 与 Out 实现 std::indirectly_movable_storable<In, Out> ，仅若给定 In 类型的可解引用值 i ：

  • 在定义 std::iter_value_t<In> obj(ranges::iter_move(i)); 后， obj 等于 *i 先前代表的值，而
  • 若 std::iter_rvalue_reference_t<In> 是右值引用类型，则 *i 在 obj 的初始化后被置于合法但未指定的状态。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

参阅

indirectly_movable (C++20) | 指定可从 indirectly_readable 类型移动值给 indirectly_writable 类型 (概念)
indirectly_copyable_storable (C++20) | 指定可从 indirectly_readable 类型复制值给 indirectly_writable 类型，且该复制可以通过中间对象进行 (概念)


std::indirectly_readable

< cpp‎ | iterator
定义于头文件 <iterator>
template<class In>

concept __IndirectlyReadableImpl = // exposition only
requires(const In in) {
typename std::iter_value_t<In>;
typename std::iter_reference_t<In>;
typename std::iter_rvalue_reference_t<In>;
{ *in } -> std::same_as<std::iter_reference_t<In>>;
{ ranges::iter_move(in) } -> std::same_as<std::iter_rvalue_reference_t<In>>;
} &&
std::common_reference_with<
std::iter_reference_t<In>&&, std::iter_value_t<In>&
> &&
std::common_reference_with<
std::iter_reference_t<In>&&, std::iter_rvalue_reference_t<In>&&
> &&
std::common_reference_with<
std::iter_rvalue_reference_t<In>&&, const std::iter_value_t<In>&

>;
 (C++20 起)
template<class In>

concept indirectly_readable =

__IndirectlyReadableImpl<std::remove_cvref_t<In>>;
 (C++20 起)

概念 indirectly_readable 由通过应用 operator* 可读的类型实现，例如指针、智能指针及输入迭代器。

语义要求

给定 I 类型值 i ，仅若被蕴含的所有概念均得到实现且表达式 *i 保持相等性， I 才实现 indirectly_readable 。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。


std::indirectly_readable_traits

< cpp‎ | iterator
定义于头文件 <iterator>
template< class I >
struct indirectly_readable_traits { };
 (1) (C++20 起)
template< class T >
struct indirectly_readable_traits<T*>;
 (2) (C++20 起)
template< class I >

requires std::is_array_v <I>

struct indirectly_readable_traits<I>;
 (3) (C++20 起)
template< class T >

struct indirectly_readable_traits<const T> :

indirectly_readable_traits<T> { };
 (4) (C++20 起)
template </*has-member-value-type*/ T>
struct indirectly_readable_traits<T>;
 (5) (C++20 起)
template </*has-member-element-type*/ T>
struct indirectly_readable_traits<T>;
 (6) (C++20 起)
template </*has-member-value-type*/ T>

requires /*has-member-element-type*/<T>

struct indirectly_readable_traits<T> { };
 (7) (C++20 起)
template </*has-member-value-type*/ T>

requires /*has-member-element-type*/<T> &&
std::same_as< std::remove_cv_t <typename T::element_type>,
std::remove_cv_t <typename T::value_type>>

struct indirectly_readable_traits<T>;
 (8) (C++20 起)

计算类型 I 的关联值类型，若它存在。用户可对程序定义类型特化 indirectly_readable_traits 。

1) 主模板是无成员 value_type 。
2) 对指针的特化。若 T 是对象类型，则提供等于 std::remove_cv_t <T> 的成员类型 value_type 。否则无成员 value_type 。
3) 对数组类型的特化。提供等于 std::remove_cv_t < std::remove_extent_t <I>> 的成员类型 value_type 。
4) 对 const 限定类型的特化。
5) 对定义公开可访问成员类型 value_type 的类型（例如 std::reverse_iterator ）的特化。若 T::value_type 是对象类型，则提供等于 std::remove_cv_t <typename T::value_type> 的成员类型 value_type 。否则无成员 value_type 。
6) 对定义公开可访问成员类型 element_type 的类型（例如 std::shared_ptr ）的特化。若 T::element_type 是对象类型，则提供等于 std::remove_cv_t <typename T::element_type> 的 value_type 。否则无成员 value_type 。
7-8) 对定义公开可访问成员类型 value_type 与 element_type 的类型（例如 std::span ）的特化。若 T::value_type 与 T::element_type 均为对象类型且在移除顶层 cv 限定符后为同一类型，则提供等于 std::remove_cv_t <typename T::value_type> 的成员类型 value_type 。否则无成员 value_type 。

注解

有意将 value_type 对如迭代器的 indirectly_readable 类型使用。并非有意将它对范围使用。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3446 | C++20 | 特化对含有 value_type 和 element_type 两个成员类型的类型有歧义 | 添加了消歧义特化
LWG 3541 | C++20 | LWG 3446 对 value_type 与 element_type 相异的情况引入了硬错误 | 使之导致替换失败

参阅

indirectly_readable (C++20) | 指定类型通过应用运算符 * 可读 (概念)
iter_value_titer_reference_titer_difference_titer_rvalue_reference_titer_common_reference_t (C++20)(C++20)(C++20)(C++20)(C++20) | 计算迭代器的关联类型 (别名模板)
iterator_traits | 为迭代器各项性质提供统一接口 (类模板)


std::indirectly_swappable

< cpp‎ | iterator
定义于头文件 <iterator>
template< class I1, class I2 >

concept indirectly_swappable =
std::indirectly_readable<I1> &&
std::indirectly_readable<I2> &&
requires( const I1 i1, const I2 i2 ) {
ranges::iter_swap(i1, i1);
ranges::iter_swap(i1, i2);
ranges::iter_swap(i2, i1);
ranges::iter_swap(i2, i2);

};
 (C++20 起)

概念 indirectly_swappable 指定分别实现 std::indirectly_readable 的二个类型间的关系，其中能交换其所引用的类型。

语义要求

I1 与 I2 实现 indirectly_swappable ，仅若其所蕴含的概念均得到实现。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

参阅

indirectly_readable (C++20) | 指定类型通过应用运算符 * 可读 (概念)
iter_swap (C++20) | 交换两个可解引用对象所引用的值 (定制点对象)


std::indirect_unary_invocable, std::indirectly_regular_unary_invocable

< cpp‎ | iterator
定义于头文件 <iterator>
template< class F, class I >

concept indirectly_unary_invocable =
std::indirectly_readable<I> &&
std::copy_constructible<F> &&
std::invocable<F&, iter_value_t<I>&> &&
std::invocable<F&, iter_reference_t<I>> &&
std::invocable<F&, iter_common_reference_t<I>> &&
std::common_reference_with<
std::invoke_result_t<F&, std::iter_value_t<I>&>,

std::invoke_result_t<F&, std::iter_reference_t<I>>>;
 (C++20 起)
template< class F, class I >

concept indirectly_regular_unary_invocable =
std::indirectly_readable<I> &&
std::copy_constructible<F> &&
std::regular_invocable<F&, iter_value_t<I>&> &&
std::regular_invocable<F&, iter_reference_t<I>> &&
std::regular_invocable<F&, iter_common_reference_t<I>> &&
std::common_reference_with<
std::invoke_result_t<F&, std::iter_value_t<I>&>,

std::invoke_result_t<F&, std::iter_reference_t<I>>>;
 (C++20 起)

概念 indirectly_unary_invocable 与 indirectly_regular_unary_invocable 指定调用作为其实参的（正则）一元可调用对象的算法的要求。这些概念与 std::invocable 间的关键差异是它们应用到 I 所引用的类型，而非 I 自身。

语义要求

每个概念为 F 与 I 所实现，仅若其所蕴含的所有概念均得到实现。

注解

indirectly_unary_invocable 与 indirectly_regular_unary_invocable 间的区别是纯语义的。


std::indirectly_writable

< cpp‎ | iterator
定义于头文件 <iterator>
template<class Out, class T>

concept indirectly_writable =
requires(Out&& o, T&& t) {
*o = std::forward <T>(t);
* std::forward <Out>(o) = std::forward <T>(t);
const_cast<const std::iter_reference_t<Out>&&>(*o) = std::forward <T>(t);
const_cast<const std::iter_reference_t<Out>&&>(* std::forward <Out>(o)) =
std::forward <T>(t);
};

// 上述四个表达式都不要求保持相等性
 (C++20 起)

概念 indirectly_writable<Out, T> 指定写入类型和值类别为 T 所编码的值到迭代器 Out 所引用对象的要求。

语义要求

令 e 为满足 decltype((e)) 为 T 的表达式，而 o 为 Out 类型的可解引用对象，则 indirectly_writable<Out, T> 仅若符合下列条件才被实现：

  • 若 std::indirectly_readable<Out> 得到实现且 std::iter_value_t<Out> 与 std::decay_t <T> 为同一类型，则在任何上述赋值后 *o 等于 e 在赋值前的值。

不要求 o 在求值任何上述赋值表达式后可解引用。若 e 为亡值，则其代表的对象的结果状态合法但未指定。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

注解

operator* 仅有的合法用法是在赋值表达式左侧。通过相同的间接可写类型值的赋值只可以发生一次。

带 const_cast 的要求表达式阻止有纯右值 reference 类型的 indirectly_readable 对象意外满足 indirectly_writable 的语法要求，同时容许代理引用继续工作，只要其常性是浅的。见范围 TS 问题 381 。


std::input_iterator

< cpp‎ | iterator
定义于头文件 <iterator>
template<class I>

concept input_iterator =
std::input_or_output_iterator<I> &&
std::indirectly_readable<I> &&
requires { typename /*ITER_CONCEPT*/<I>; } &&

std::derived_from</*ITER_CONCEPT*/<I>, std::input_iterator_tag >;
 (C++20 起)

input_iterator 概念是 input_or_output_iterator 的细化，添加能读取被引用值的要求（经由 indirectly_readable ）和迭代器概念标签存在的要求。

迭代器概念确定

此概念的定义通过仅用于阐释的别名模板 /*ITER_CONCEPT*/ 说明。

为确定 /*ITER_CONCEPT*/<I> ，令 ITER_TRAITS<I> 若特化 std::iterator_traits <I> 从主模板生成则指代 I ，否则指代 std::iterator_traits <I> ：

  • 若 ITER_TRAITS<I>::iterator_concept 合法并指名类型，则 /*ITER_CONCEPT*/<I> 指代该类型。
  • 否则，若 ITER_TRAITS<I>::iterator_category 合法并指名类型，则 /*ITER_CONCEPT*/<I> 指代该类型。
  • 否则，若 std::iterator_traits <I> 从主模板生成，则 /*ITER_CONCEPT*/<I> 指代 std::random_access_iterator_tag 。
  • 否则 /*ITER_CONCEPT*/<I> 不指代类型并导致替换失败。

注解

不同于老式输入迭代器 (LegacyInputIterator) 要求， input_iterator 概念不要求 equality_comparable ，因为输入迭代器常与哨位比较。

参阅

input_or_output_iterator
(C++20)
 指定该类型对象可以自增且可以解引用
(概念)


std::input_or_output_iterator

< cpp‎ | iterator
定义于头文件 <iterator>
template <class I>

concept input_or_output_iterator =
requires(I i) {
{ *i } -> __Referenceable;
} &&

std::weakly_incrementable<I>;
 (C++20 起)

input_or_output_iterator 概念组成迭代器分类学的基础；每个迭代器类型都满足 input_or_output_iterator 要求。

仅用于阐释的的概念 __Referenceable 若且唯若表达式 * std::declval <T&>() 合法且拥有可引用类型（特别是非 void ）才得到满足。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

注解

input_or_output_iterator 自身仅指定解引用和自增迭代器的操作。大多数算法将要求额外操作：

  • 比较迭代器与哨位（见 sentinel_for ）；
  • 从迭代器读取值（见 indirectly_readable 及 input_iterator ）；
  • 写入值到迭代器（见 indirectly_writable 及 output_iterator ）
  • 更丰富的迭代器动作集合（见 forward_iterator 、 bidirectional_iterator 、 random_access_iterator ）

不同于老式迭代器 (LegacyIterator) 要求， input_or_output_iterator 概念不要求可复制性。


std::insert_iterator

< cpp‎ | iterator
定义于头文件 <iterator> |
template< class Container > class insert_iterator : public std::iterator < std::output_iterator_tag, void,void,void,void > | (C++17 前)
template< class Container > class insert_iterator; | (C++17 起)

std::insert_iterator 是在提供的迭代器所指向的位置，插入元素到为之构造迭代器的容器的 老式输出迭代器 (LegacyOutputIterator) 。凡在赋值给迭代器时（无论是否解引用）调用元素的 insert() 成员函数。自增 std::insert_iterator 是无操作。

成员类型

成员类型 | 定义
iterator_category | std::output_iterator_tag
value_type | void
difference_type
void | (C++20 前)
std::ptrdiff_t | (C++20 起)
pointer | void
reference | void
container_type | Container

要求通过从 std::iterator < std::output_iterator_tag, void, void, void, void> 继承获得成员类型 iterator_category、 value_type、 difference_type、 pointer 及 reference 。

 (C++17 前)

成员函数

(构造函数) | 构造新的 insert_iterator (公开成员函数)
operator= | 插入对象到关联的容器 (公开成员函数)
operator* | 无操作 (公开成员函数)
operator++operator++(int) | 无操作 (公开成员函数)

成员对象

成员名 | 定义
container (受保护成员对象) | Container* 类型指针
iter (受保护成员对象) | Container::iterator (C++20 前)ranges::iterator_t<Container> (C++20 起) 类型迭代器

示例

#include <vector>
#include <list>
#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    std::vector<int> v{1,2,3,4,5};
    std::list<int> l{-1,-2,-3};
    std::copy(v.begin(), v.end(), // 可用 std::inserter 简化
              std::insert_iterator<std::list<int>>(l, std::next(l.begin())));
    for (int n : l)
        std::cout << n << ' ';
    std::cout << '\n';
}

输出：

-1 1 2 3 4 5 -2 -3

参阅

inserter | 创建拥有从实参推出的类型的 std::insert_iterator (函数模板)
back_insert_iterator | 用于在容器尾部插入的迭代器适配器 (类模板)
front_insert_iterator | 用于在容器头部插入的迭代器适配器 (类模板)


std::insert_iterator<Container>::insert_iterator

< cpp‎ | iterator‎ | insert iterator

insert_iterator( Container& c, typename Container::iterator i ); | (C++20 前)
constexpr insert_iterator( Container& c, ranges::iterator_t<Container> i ); | (C++20 起)

初始化底层指向容器指针为 std::addressof (c) 并初始化底层迭代器为 i 。

参数

c | - | 用以初始化插入器的容器
i | - | 用以初始化插入器的迭代器

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | 由于 C++20 迭代器必须为 default_initializable 提供了默认构造函数 | 与该要求一同移除


std::insert_iterator<Container>::operator*

< cpp‎ | iterator‎ | insert iterator

insert_iterator& operator*(); | (C++20 前)
constexpr insert_iterator& operator*(); | (C++20 起)

不做任何事，提供此函数以满足老式输出迭代器 (LegacyOutputIterator) 的要求。

它返回迭代器自身，这使得可以用诸如 *iter = value 的代码输出（插入）值到底层的容器。

参数

（无）

返回值

*this


std::insert_iterator<Container>::operator++

< cpp‎ | iterator‎ | insert iterator
insert_iterator& operator++(); | (C++20 前)
constexpr insert_iterator& operator++(); | (C++20 起)
insert_iterator& operator++( int ); | (C++20 前)
constexpr insert_iterator& operator++( int ); | (C++20 起)

不做任何事。提供这些运算符以满足老式输出迭代器 (LegacyOutputIterator) 的要求。它们使得表达式 *iter++=value 和 *++iter=value 可用于输出（插入）值到底层的容器。

参数

（无）

返回值

*this


std::insert_iterator<Container>::operator=

< cpp‎ | iterator‎ | insert iterator

 | (1)
insert_iterator<Container>& operator=( typename Container::const_reference value ); |  | (C++11 前)
insert_iterator<Container>& operator=( const typename Container::value_type& value ); |  | (C++11 起) (C++20 前)
constexpr insert_iterator<Container>& operator=( const typename Container::value_type& value ); |  | (C++20 起)
 | (2)
insert_iterator<Container>& operator=( typename Container::value_type&& value ); |  | (C++11 起) (C++20 前)
constexpr insert_iterator<Container>& operator=( typename Container::value_type&& value ); |  | (C++20 起)

插入给定的 value 到迭代器。

1) 导致 iter = container->insert(iter, value); ++iter;
2) 导致 iter = container->insert(iter, std::move(value)); ++iter;

参数

value - 要插入的值

返回值

*this

注意

此函数开创了关联容器的有提示插入（例如 std::set::insert ）和顺序容器的定位插入（例如 std::vector::insert ）间的签名兼容性。

示例

#include <iostream>
#include <iterator>
#include <deque>

int main()
{
    std::deque<int> q;
    std::insert_iterator< std::deque<int> > it(q, q.begin());

    for (int i=0; i<10; ++i)
        it = i; // 插入 i

    for (auto& elem : q) std::cout << elem << ' ';
}

输出：

0 1 2 3 4 5 6 7 8 9


std::inserter

< cpp‎ | iterator
定义于头文件 <iterator>
template< class Container >

std::insert_iterator <Container>

inserter( Container& c, typename Container::iterator i );
 (C++20 前)
template< class Container >

constexpr std::insert_iterator <Container>

inserter( Container& c, ranges::iterator_t<Container> i );
 (C++20 起)

inserter 是为容器 c 与其迭代器 i 构造 std::insert_iterator 的便利函数模板，拥有从参数类型推导的类型。

参数

c | - | 支持 insert 操作的容器
i | - | 指示插入位置的 c 中迭代器

返回值

能用于在 i 所指示位置插入元素到容器 c 的 std::insert_iterator 。

可能的实现

template< class Container >
std::insert_iterator<Container> inserter( Container& c, typename Container::iterator i )
{
    return std::insert_iterator<Container>(c, i);
}

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <set>

int main()
{

    std::multiset<int> s {1, 2, 3};

    // std::inserter 常用于 set
    std::fill_n(std::inserter(s, s.end()), 5, 2);

    for (int n : s)
        std::cout << n << ' ';
    std::cout << '\n';

    std::vector<int> d {100, 200, 300};
    std::vector<int> l {1, 2, 3, 4, 5};

    // 插入顺序容器是，插入点前进，因为每次
    // std::insert_iterator::operator= 都更新目标迭代器
    std::copy(d.begin(), d.end(), std::inserter(l, std::next(l.begin())));

    for (int n : l)
        std::cout << n << ' ';
    std::cout << '\n';
}

输出：

1 2 2 2 2 2 2 3
1 100 200 300 2 3 4 5

参阅

insert_iterator | 用于插入容器的迭代器适配器 (类模板)
back_inserter | 创建拥有从实参推出的类型的 std::back_insert_iterator (函数模板)
front_inserter | 创建拥有从实参推出的类型的 std::front_insert_iterator (函数模板)


std::istream_iterator

< cpp‎ | iterator
定义于头文件 <iterator>
template< class T,

class CharT = char,
class Traits = std::char_traits <CharT>,
class Distance = std::ptrdiff_t >
class istream_iterator: public std::iterator < std::input_iterator_tag,

T, Distance, const T*, const T&>
 (C++17 前)
template< class T,

class CharT = char,
class Traits = std::char_traits <CharT>,
class Distance = std::ptrdiff_t >

class istream_iterator;
 (C++17 起)

std::istream_iterator 是单趟输入迭代器，从为之创建迭代器的 std::basic_istream 对象读取 T 类型的相继对象，通过调用适当的 operator>> 。实际读取操作在自增，而非解引用迭代器时进行。在构造迭代器时读取首个对象。解引用只返回最近读取的对象的副本。

默认构造的 std::istream_iterator 被称为流尾迭代器。合法的 std::istream_iterator 抵达底层流尾时，它变得等于流尾迭代器。解引用和进一步自增它导致未定义行为。

std::istream_iterator 的典型实现保有二个数据成员：指向关联 std::basic_istream 对象的指针和最近读取的 T 类型值。

T 必须满足可默认构造 (DefaultConstructible) 、可复制构造 (CopyConstructible) 和可复制赋值 (CopyAssignable) 要求。

成员类型

成员类型 | 定义
iterator_category | std::input_iterator_tag
value_type | T
difference_type | Distance
pointer | const T*
reference | const T&
char_type | CharT
traits_type | Traits
istream_type | std::basic_istream <CharT, Traits>

要求通过从 std::iterator < std::input_iterator_tag, T, Distance, const T*, const T&> 继承获得成员类型 iterator_category、 value_type、 difference_type、 pointer 及 reference 。

 (C++17 前)

成员函数

(构造函数) | 构造新的 istream_iterator (公开成员函数)
(析构函数) | 析构 istream_iterator ，包含缓冲的值 (公开成员函数)
operator*operator-> | 返回当前元素 (公开成员函数)
operator++operator++(int) | 推进迭代器 (公开成员函数)

非成员函数

operator==operator!=
(C++20 中移除)
 比较两个 istream_iterator
(函数模板)

注解

读字符时， std::istream_iterator 默认跳过空白符（除非用 std::noskipws 或等价物禁用，而 std::istreambuf_iterator 不跳过。另外， std::istreambuf_iterator 更有效率，因为它避免对每个字符构造并析构一次 sentry 对象的开销。

示例

#include <iostream>
#include <sstream>
#include <iterator>
#include <numeric>
#include <algorithm>

int main()
{
    std::istringstream str("0.1 0.2 0.3 0.4");
    std::partial_sum(std::istream_iterator<double>(str),
                     std::istream_iterator<double>(),
                     std::ostream_iterator<double>(std::cout, " "));

    std::istringstream str2("1 3 5 7 8 9 10");
    std::cout << "\nThe first even number is " <<
        *std::find_if(std::istream_iterator<int>(str2),
                      std::istream_iterator<int>(),
                      [](int i){ return i % 2 == 0; })
        << ".\n";
    // " 9 10" 留在流中
}

输出：

0.1 0.3 0.6 1
The first even number is 8.

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0738R2 | C++98 | 首次读取可以延迟到首次解引用 | 首次读取在构造函数中进行

参阅

ostream_iterator | 写入 std::basic_ostream 的输出迭代器 (类模板)
istreambuf_iterator | 从 std::basic_streambuf 读取的输入迭代器 (类模板)


std::istream_iterator<T,CharT,Traits,Distance>::istream_iterator

< cpp‎ | iterator‎ | istream iterator
 | (1) |
istream_iterator(); |  |  | (C++11 前)
constexpr istream_iterator(); |  |  | (C++11 起)
constexpr istream_iterator( std::default_sentinel_t ); | (2) | (C++20 起)
istream_iterator( istream_type& stream ); | (3) |
 | (4) |
istream_iterator( const istream_iterator& other ); |  |  | (C++11 前)
istream_iterator( const istream_iterator& other ) = default; |  |  | (C++11 起)
1) 构造流尾迭代器，值初始化存储的值。若定义 auto x = T(); 中的初始化器是常量初始化器，则此构造函数为 constexpr (C++11 起)。
2) 初始化迭代器并于数据成员中存储 stream 的地址。再从输入流进行首次读取以初始化缓冲数据成员。
3) 构造 other 的副本。若 std::is_trivially_copy_constructible <T>::value 为 true ，则此构造函数为平凡复制构造函数。 (C++11 起)

参数

stream | - | 用于初始化 istream_iterator 的流
other | - | 同类型的另一 istream_iterator

示例

#include <iostream>
#include <iterator>
#include <algorithm>
#include <sstream>
int main()
{
    std::istringstream stream("1 2 3 4 5");
    std::copy(
        std::istream_iterator<int>(stream),
        std::istream_iterator<int>(),
        std::ostream_iterator<int>(std::cout, " ")
    );
}

输出：

1 2 3 4 5

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0738R2 | C++98 | 首次读取可以延迟到首次解引用 | 首次读取在构造函数中进行


std::istream_iterator<T,CharT,Traits,Distance>::operator*, operator->

< cpp‎ | iterator‎ | istream iterator
const T& operator*() const; | (1)
const T* operator->() const; | (2)

返回到当前元素的指针或引用。

若迭代器是流尾迭代器则行为未定义。

参数

（无）

返回值

到当前元素的指针或引用。

异常

可能抛出实现定义的异常。


std::istream_iterator<T,CharT,Traits,Distance>::operator++, operator++(int)

< cpp‎ | iterator‎ | istream iterator
istream_iterator& operator++(); | (1)
istream_iterator operator++(int); | (2)

从底层流读值并存储它到迭代器对象。若读取失败，则迭代器变为流尾迭代器。

若迭代器是流尾迭代器则行为未定义。

参数

（无）

返回值

1) *this 。
2) 保有未更改的值的 istream_iterator 。

异常

可能抛出实现定义的异常。


operator==,!=(std::istream_iterator<T,CharT,Traits,Dist>)

< cpp‎ | iterator‎ | istream iterator
定义于头文件 <iterator>
template< class T, class CharT, class Traits, class Dist >

bool operator==( const std::istream_iterator <T,CharT,Traits,Dist>& lhs,

const std::istream_iterator <T,CharT,Traits,Dist>& rhs );
 (1)
template< class CharT, class Traits >

bool operator!=( const std::istream_iterator <T,CharT,Traits,Dist>& lhs,

const std::istream_iterator <T,CharT,Traits,Dist>& rhs );
 (2) (C++20 前)
friend bool operator==( const istream_iterator& i, std::default_sentinel_t );
 (3) (C++20 起)

检查 lhs 与 rhs 是否相等。二个流迭代器若均为流尾迭代器或均表示同一流则相等。

1) 检查 lhs 是否等于 rhs 。
2) 检查 lhs 是否不等于 rhs 。
3) 检查 lhs 是否为流尾迭代器。
此函数对通常无限定或有限定查找不可见，而只能在 std::istream_iterator<T,CharT,Traits,Dist> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的流迭代器

返回值

1) 若 lhs 等于 rhs 则为 true ，否则为 false 。
2) 若 lhs 不等于 rhs 则为 true ，否则为 false 。
3) 若 lhs 为流尾迭代器则为 true ，否则为 false 。

异常

可能抛出实现定义的异常。


std::istream_iterator<T,CharT,Traits,Distance>::~istream_iterator

< cpp‎ | iterator‎ | istream iterator
~istream_iterator(); | (C++11 前)
~istream_iterator() = default; | (C++11 起)

销毁迭代器，包含缓冲的值。

若 std::is_trivially_destructible <T>::value 为 true ，则此析构函数为平凡析构函数。

 (C++11 起)


std::istreambuf_iterator

< cpp‎ | iterator
定义于头文件 <iterator>
template< class CharT, class Traits = std::char_traits <CharT> >

class istreambuf_iterator : public std::iterator < std::input_iterator_tag,
CharT,
typename Traits::off_type,
/* unspecified, usually CharT* */,

CharT >
 (C++17 前)
template< class CharT, class Traits = std::char_traits <CharT> >
class istreambuf_iterator;
 (C++17 起)

std::istreambuf_iterator 是单趟迭代器，从为之构造迭代器的 std::basic_streambuf 对象读取相继字符。

默认构造的 std::istreambuf_iterator 迭代器被称为流尾迭代器。合法的 std::istreambuf_iterator 抵达底层流结尾时，它变得等于流尾迭代器。解引用或进一步自增它导致未定义行为。

std::istreambuf_iterator 拥有平凡复制构造函数、 constexpr 默认构造函数和平凡析构函数。

 (C++11 起)

成员类型

成员类型 | 定义
iterator_category | std::input_iterator_tag
value_type | CharT
difference_type | Traits::off_type
pointer | /* unspecified, usually CharT* */
reference | CharT
char_type | CharT
traits_type | Traits
int_type | typename traits::int_type
streambuf_type | std::basic_streambuf <CharT, Traits>
istream_type | std::basic_istream <CharT, Traits>
/* proxy */ | 实现定义的类类型。名称 proxy 仅为说明。 proxy 对象保有一个 char_type 字符和一个 streambuf_type* 指针。 以 operator* 解引用 proxy 对象得到存储的字符。

要求通过从 std::iterator < std::input_iterator_tag, CharT, Traits::off_type, /* unspecified, usually CharT* */, CharT> 继承获得成员类型 iterator_category、 value_type、 difference_type、 pointer 及 reference 。

 (C++17 前)

成员函数

(构造函数) | 构造新的 istreambuf_iterator (公开成员函数)
(析构函数) (隐式声明) | 析构 istreambuf_iterator (公开成员函数)
operator*operator-> (C++11 起)(C++17 前) | 获得当前字符的副本 若 CharT 拥有成员，则访问当前字符的成员 (公开成员函数)
operator++operator++(int) | 推进迭代器 (公开成员函数)
equal | 测试两个 istreambuf_iterator 是否均为流尾或均合法 (公开成员函数)

非成员函数

operator==operator!=
(C++20 中移除)
 比较两个 istreambuf_iterator
(函数模板)

示例

#include <string>
#include <sstream>
#include <iostream>
#include <iterator>

int main()
{
    // 典型使用情况：以一对迭代器表示的输入流
    std::istringstream in{"Hello, world"};
    std::istreambuf_iterator<char> it{in}, end;
    std::string ss{it, end};
    std::cout << "ss has " << ss.size() << " bytes; "
                 "it holds \"" << ss << "\"\n";

    // 演示单趟本性
    std::istringstream s{"abc"};
    std::istreambuf_iterator<char> i1{s}, i2{s};
    std::cout << "i1 returns '" << *i1 << "'\n"
                 "i2 returns '" << *i2 << "'\n";
    ++i1;
    std::cout << "after incrementing i1, but not i2\n"
                 "i1 returns '" << *i1 << "'\n"
                 "i2 returns '" << *i2 << "'\n";
    ++i2;
    std::cout << "after incrementing i2, but not i1\n"
                 "i1 returns '" << *i1 << "'\n"
                 "i2 returns '" << *i2 << "'\n";
}

输出：

ss has 12 bytes; it holds "Hello, world"
i1 returns 'a'
i2 returns 'a'
after incrementing i1, but not i2
i1 returns 'b'
i2 returns 'b'
after incrementing i2, but not i1
i1 returns 'c'
i2 returns 'c'

参阅

ostreambuf_iterator | 写入 std::basic_streambuf 的输出迭代器 (类模板)
istream_iterator | 从 std::basic_istream 读取的输入迭代器 (类模板)


std::istreambuf_iterator<CharT,Traits>::equal

< cpp‎ | iterator‎ | istreambuf iterator
bool equal( const istreambuf_iterator& it ) const;

检查 *this 与 it 是否均合法或均非法，无关乎它们所用的流缓冲。

参数

it - 要比较的另一流缓冲迭代器

返回值

若 *this 与 it 均合法或均非法则为 true ，否则为 false 。

异常

可能抛出实现定义的异常。


std::istreambuf_iterator<CharT,Traits>::istreambuf_iterator

< cpp‎ | iterator‎ | istreambuf iterator
 | (1) |
istreambuf_iterator() throw(); |  |  | (C++11 前)
constexpr istreambuf_iterator() noexcept; |  |  | (C++11 起)
constexpr istreambuf_iterator( std::default_sentinel_t ) noexcept; | (2) | (C++20 起)
 | (3) |
istreambuf_iterator( std::basic_istream <CharT,Traits>& is ) throw(); |  |  | (C++11 前)
istreambuf_iterator( std::basic_istream <CharT,Traits>& is ) noexcept; |  |  | (C++11 起)
 | (4) |
istreambuf_iterator( std::basic_streambuf <CharT,Traits>* s ) throw(); |  |  | (C++11 前)
istreambuf_iterator( std::basic_streambuf <CharT,Traits>* s ) noexcept; |  |  | (C++11 起)
 | (5) |
istreambuf_iterator( const /* proxy */& p ) throw(); |  |  | (C++11 前)
istreambuf_iterator( const /* proxy */& p ) noexcept; |  |  | (C++11 起)
istreambuf_iterator( const istreambuf_iterator& ) noexcept = default; | (6) | (C++11 起)
1-2) 构造流尾迭代器。
3) 初始化迭代器并存储 is.rdbuf() 的值于数据成员。若 is.rdbuf() 为空，则构造流尾迭代器。
4) 初始化迭代器并存储 s 的值于数据成员。若 s 为空，则构造流尾迭代器。
6) 等效于以 p 所保有的 streambuf_type* 指针调用 (3) 。
6) 复制构造函数为平凡且为显式默认化。

复制构造函数被等效地隐式声明，且不保证为平凡。

 (C++11 前)

参数

is | - | 获得流缓冲来源的输出流
s | - | 用以初始化迭代器的流缓冲
p | - | 拥有实现定义代理类型的对象


std::istreambuf_iterator<CharT,Traits>::operator*, operator->

< cpp‎ | iterator‎ | istreambuf iterator
CharT operator*() const; | (1) |
pointer operator->() const; | (2) | (C++11 起) (C++17 前)

以调用 sbuf_->sgetc() 读取单个字符，其中 sbuf_ 是存储的指向流缓冲的指针。

若迭代器是流尾迭代器则行为未定义。

参数

（无）

返回值

1) 获得字符的值。
2) 未指定类型对象，满足给定一个 istreambuf_iterator i ，表达式 (*i).m 与 i->m 拥有相同效果。

异常

可能抛出实现定义的异常。


std::istreambuf_iterator<CharT,Traits>::operator++, operator++(int)

< cpp‎ | iterator‎ | istreambuf iterator
istreambuf_iterator& operator++(); | (1)
/* proxy */ operator++(int); | (2)

以调用 sbuf_->sbumpc() 推进迭代器，其中 sbuf_ 是存储的指向流缓冲的指针。

若迭代器是流尾迭代器则行为未定义。

参数

（无）

返回值

1) *this 。
2) 保有经由 operator*() 获得的当前字符和 sbuf_ 指针的 proxy 对象。以 operator* 解引用 proxy 对象得到存储的字符。
名称 proxy 仅用于阐释。

异常

可能抛出实现定义的异常。


operator==,!=(std::istreambuf_iterator<CharT,Traits>)

< cpp‎ | iterator‎ | istreambuf iterator
定义于头文件 <iterator>
template< class CharT, class Traits >

bool operator==( const std::istreambuf_iterator <CharT,Traits>& lhs,

const std::istreambuf_iterator <CharT,Traits>& rhs );
 (1)
template< class CharT, class Traits >

bool operator!=( const std::istreambuf_iterator <CharT,Traits>& lhs,

const std::istreambuf_iterator <CharT,Traits>& rhs );
 (2) (C++20 前)
friend bool operator==( const istreambuf_iterator& lhs,
std::default_sentinel_t );
 (3) (C++20 起)

检查 lhs 与 rhs 是否合法，或是否均为非法，无关乎它们所用的流缓冲区对象。

1) 等价于 lhs.equal(rhs) 。
2) 等价于 !lhs.equal(rhs) 。
3) 检查 lhs 是否非法。等价于 lhs.equal(istreambuf_iterator{}) 。
此函数对通常无限定或有限定查找不可见，而只能在 std::istreambuf_iterator<CharT,Traits> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的流缓冲区迭代器

返回值

1) lhs.equal(rhs) 的结果。
2) !lhs.equal(rhs) 的结果。
3) lhs.equal(istreambuf_iterator{}) 的结果。

异常

可能抛出实现定义的异常。


std::iter_value_t, std::iter_reference_t, std::iter_difference_t, std::iter_rvalue_reference_t, std::iter_common_reference_t

< cpp‎ | iterator
定义于头文件 <iterator>
template< class T >
concept __Referenceable = /* see below */; // 仅用于阐释
template< class T >
using iter_value_t = /* see below */;
 (1) (C++20 起)
template< __Referenceable T >
using iter_reference_t = decltype(* std::declval <T&>());
 (2) (C++20 起)
template< class T >
using iter_difference_t = /* see below */;
 (3) (C++20 起)
template< __Referenceable T>

requires /* see below */

using iter_rvalue_reference_t = decltype(std::iter_move( std::declval <T&>()));
 (4) (C++20 起)
template< std::indirectly_readable T >

using iter_common_reference_t = std::common_reference_t<std::iter_reference_t<T>,

std::iter_value_t<T>&>;
 (5) (C++20 起)

计算迭代器的关联类型。仅用于阐释的概念 __Referenceable 若且唯若表达式 *std::declval<T&>() 合法且拥有可引用类型（特别是非 void ）才得到满足。

1) 计算 T 的值类型。若 std::iterator_traits <std::remove_cvref_t<T>> 未被特化，则 std::iter_value_t<T> 为 std::indirectly_readable_traits<std::remove_cvref_t<T>>::value_type 。否则它是 std::iterator_traits <std::remove_cvref_t<T>>::value_type 。
2) 计算 T 的引用类型。
3) 计算 T 的差类型。若 std::iterator_traits <std::remove_cvref_t<T>> 未被特化，则 std::iter_difference_t<T> 为 std::incrementable_traits<std::remove_cvref_t<T>>::difference_type 。否则它是 std::iterator_traits <std::remove_cvref_t<T>>::difference_type 。
4) 计算 T 的右值引用类型。此别名模版上的制约的 "see below" 部分若且唯若表达式 ranges::iter_move( std::declval <T&>()) 合法且拥有可引用类型（特别是非 void ）才得到满足。
5) 计算 T 的共用引用类型。此乃其引用类型与到其值类型的左值引用类型的共用引用类型。

参阅

indirectly_readable (C++20) | 指定类型通过应用运算符 * 可读 (概念)
weakly_incrementable (C++20) | 指定 semiregular 类型能以前后自增运算符自增 (概念)
indirectly_readable_traits (C++20) | 计算 indirectly_readable 类型的值类型 (类模板)
incrementable_traits (C++20) | 计算 weakly_incrementable 类型的差类型 (类模板)
iterator_traits | 为迭代器各项性质提供统一接口 (类模板)


std::iterator

< cpp‎ | iterator
定义于头文件 <iterator> |
template< class Category, class T, class Distance = std::ptrdiff_t, class Pointer = T*, class Reference = T& > struct iterator; | (C++17 中弃用)

std::iterator 是提供以简化迭代器所要求类型定义的基类。

模板形参

Category | - | 迭代器类别。必须是迭代器类别标签之一。
T | - | 能通过解引用迭代器获得的值的类型。此类型对于输出迭代器应为 void 。
Distance | - | 能用于标识迭代器间距离的类型
Pointer | - | 定义指向被迭代的类型（ T ）的指针
Reference | - | 定义到被迭代的类型（ T ）的引用

成员类型

成员类型 | 定义
iterator_category | Category
value_type | T
difference_type | Distance
pointer | Pointer
reference | Reference

示例

以下示例演示如何通过继承 std::iterator 实现输入迭代器

#include <iostream>
#include <algorithm>

template<long FROM, long TO>
class Range {
public:
    // 通过继承自 std::iterator 提供成员 typedef
    class iterator: public std::iterator<
                        std::input_iterator_tag,   // iterator_category
                        long,                      // value_type
                        long,                      // difference_type
                        const long*,               // pointer
                        long                       // reference
                                      >{
        long num = FROM;
    public:
        explicit iterator(long _num = 0) : num(_num) {}
        iterator& operator++() {num = TO >= FROM ? num + 1: num - 1; return *this;}
        iterator operator++(int) {iterator retval = *this; ++(*this); return retval;}
        bool operator==(iterator other) const {return num == other.num;}
        bool operator!=(iterator other) const {return !(*this == other);}
        reference operator*() const {return num;}
    };
    iterator begin() {return iterator(FROM);}
    iterator end() {return iterator(TO >= FROM? TO+1 : TO-1);}
};

int main() {
    // std::find 要求输入迭代器
    auto range = Range<15, 25>();
    auto itr = std::find(range.begin(), range.end(), 18);
    std::cout << *itr << '\n'; // 18

    // Range::iterator 亦满足基于范围的 for 要求
    for(long l : Range<3, 5>()) {
        std::cout << l << ' '; // 3 4 5
    }
    std::cout << '\n';
}

输出：

18
3 4 5

参阅

iterator_traits | 为迭代器各项性质提供统一接口 (类模板)
input_iterator_tagoutput_iterator_tagforward_iterator_tagbidirectional_iterator_tagrandom_access_iterator_tagcontiguous_iterator_tag (C++20) | 用于指示迭代器类别的空类类型 (类)


std::input_iterator_tag, std::output_iterator_tag, std::forward_iterator_tag, std::bidirectional_iterator_tag, std::random_access_iterator_tag, std::contiguous_iterator_tag

< cpp‎ | iterator
定义于头文件 <iterator> |  |
struct input_iterator_tag { }; | (1) |
struct output_iterator_tag { }; | (2) |
struct forward_iterator_tag : public input_iterator_tag { }; | (3) |
struct bidirectional_iterator_tag : public forward_iterator_tag { }; | (4) |
struct random_access_iterator_tag : public bidirectional_iterator_tag { }; | (5) |
struct contiguous_iterator_tag: public random_access_iterator_tag { }; | (6) | (C++20 起)

定义迭代器的分类。每个标签均为空类型。

迭代器类别

对于每个老式迭代器 (LegacyIterator) 类型 It ， typedef std::iterator_traits <It>::iterator_category 必须定义为这些标签类型之一的别名，以指示 It 所在的最特定的类别。

  1. input_iterator_tag 对应老式输入迭代器 (LegacyInputIterator) 。
  2. output_iterator_tag 对应老式输出迭代器 (LegacyOutputIterator) 。
  3. forward_iterator_tag 对应老式向前迭代器 (LegacyForwardIterator) 。
  4. bidirectional_iterator_tag 对应老式双向迭代器 (LegacyBidirectionalIterator) 。
  5. random_access_iterator_tag 对应老式随机访问迭代器 (LegacyRandomAccessIterator) 。

顾名思义，迭代器分类标签可以用以标示某个迭代器的分类，可以根据这一分类所要求的特性来选择最优算法。

迭代器概念

对每个 input_iterator 类型 It ，可以声明 It::iterator_concept （若 std::iterator_traits <It> 从主模板生成）或 std::iterator_traits <It>::iterator_concept （若 std::iterator_traits <It> 被特化）为这些标签之一的别名，以指示 It 有意实现的最强迭代器概念。

  1. input_iterator_tag 对应 input_iterator 。
  2. forward_iterator_tag 对应 forward_iterator 。
  3. bidirectional_iterator_tag 对应 bidirectional_iterator 。
  4. random_access_iterator_tag 对应 random_access_iterator 。
  5. contiguous_iterator_tag 对应 contiguous_iterator 。

若不提供 iterator_concept ，则以 iterator_category 为后备。若亦不提供 iterator_category （即 It 非 老式迭代器 (LegacyIterator) ），且不特化 std::iterator_traits <It> ，则假设为 random_access_iterator_tag 。

任何情况下，若不支持要求的操作则不满足各个概念，无关乎标签。

 (C++20 起)

注解

老式连续迭代器 (LegacyContiguousIterator) 无分离的标签。即不可能基于其 iterator_category 分辨老式连续迭代器 (LegacyContiguousIterator) 。要定义用于连续迭代器的特化算法，须使用 contiguous_iterator 概念。 (C++20 起)

示例

如果需要根据迭代器分类标签选择算法，常用做法是使用分发函数（也可以通过 std::enable_if 实现）

#include <iostream>
#include <vector>
#include <list>
#include <iterator>

// 经常把实现细节隐藏于细致的命名空间
namespace implementation_details {
template< class BDIter >
void alg(BDIter, BDIter, std::bidirectional_iterator_tag)
{
    std::cout << "alg() called for bidirectional iterator\n";
}

template <class RAIter>
void alg(RAIter, RAIter, std::random_access_iterator_tag)
{
    std::cout << "alg() called for random-access iterator\n";
}
} // namespace implementation_details

template< class Iter >
void alg(Iter first, Iter last)
{
    alg(first, last,
        typename std::iterator_traits<Iter>::iterator_category());
}

int main()
{
    std::vector<int> v;
    alg(v.begin(), v.end());

    std::list<int> l;
    alg(l.begin(), l.end());

//    std::istreambuf_iterator<char> i1(std::cin), i2;
//    alg(i1, i2); // 编译错误：无调用的匹配函数
}

输出：

alg() called for random-access iterator
alg() called for bidirectional iterator

参阅

iterator (C++17 中弃用) | 用于简化简单的迭代器的必要类型定义的基类 (类模板)
iterator_traits | 为迭代器各项性质提供统一接口 (类模板)


std::iterator_traits

< cpp‎ | iterator
定义于头文件 <iterator> |
template< class Iter > struct iterator_traits; |
template< class T > struct iterator_traits<T*>; |
template< class T > struct iterator_traits<const T*>; | (C++20 中移除)

std::iterator_traits 是类型特征类，提供面对老式迭代器 (LegacyIterator) 类型的统一接口。这使得可以仅通过迭代器实现算法。

能对用户定义的迭代器特化模板，使得即使不提供通常的 typedef 也能从迭代器取得信息。

用户定义特化可以定义成员类型 iterator_concept 为迭代器类别标签之一，以指示遵从该迭代器概念。

 (C++20 起)

模版形参

Iter - 需要取得与之相关属性的迭代器类型

成员类型

成员类型 | 定义
difference_type | Iter::difference_type
value_type | Iter::value_type
pointer | Iter::pointer
reference | Iter::reference
iterator_category | Iter::iterator_category

若 Iter 没有全部五个成员类型 difference_type 、 value_type 、 pointer 、 reference 及 iterator_category ，则此模板无任何有那些名称的成员（ std::iterator_traits 对 SFINAE 友好）

 (C++17 起)
(C++20 前)

若 Iter 无 pointer ，但拥有全部其他四个成员类型，则按如下方式声明成员类型：

成员类型 | 定义
difference_type | Iter::difference_type
value_type | Iter::value_type
pointer | void
reference | Iter::reference
iterator_category | Iter::iterator_category

否则，若 Iter 满足仅为说明的概念 __LegacyInputIterator ，则按如下方式声明成员类型：

成员类型 | 定义
difference_type | std::incrementable_traits<Iter>::difference_type
value_type | std::indirectly_readable_traits<Iter>::value_type
pointer | 若合法则为 Iter::pointer ，否则若合法则为 decltype(​std::declval <Iter&>().operator->()) ，否则为 void
reference | 若合法则为 Iter::reference ，否则为 std::iter_reference_t<Iter>
iterator_category 若合法则为 Iter::iterator_category ，
否则若 Iter 满足 __LegacyRandomAccessIterator

则为 std::random_access_iterator_tag ，
否则若 Iter 满足 __LegacyBidirectionalIterator 则为 std::bidirectional_iterator_tag ，
否则若 Iter 满足 __LegacyForwardIterator 则为 std::forward_iterator_tag ，
否则为 std::input_iterator_tag

否则，若 Iter 满足仅为说明的概念 __LegacyIterator ，则按如下方式声明成员类型：

成员类型 | 定义
difference_type | 若合法则为 std::incrementable_traits<Iter>::difference_type ，否则为 void
value_type | void
pointer | void
reference | void
iterator_category | std::output_iterator_tag

否则，此模板无任何有这些名称的成员此模板无任何有那些名称的成员（ std::iterator_traits 对 SFINAE 友好）。

 (C++20 起)

特化

如果要把用户提供的类型作为迭代器使用，该类型特征可以针对这一类型进行特化。标准库中提供了针对指针类型 T * 的两种偏特化，使得可以在任何需要迭代器的算法里使用裸指针。

标准库亦提供对一些标准迭代器适配器的特化。

 (C++20 起)

T * 特化成员类型

仅若 std::is_object_v <T> 为 true 才特化。

 (C++20 起)
成员类型 | 定义
difference_type | std::ptrdiff_t
value_type | T (C++20 前)std::remove_cv_t <T> (C++20 起)
pointer | T*
reference | T&
iterator_category | std::random_access_iterator_tag
iterator_concept(C++20) | std::contiguous_iterator_tag

const T * 特化成员类型

成员类型 | 定义
difference_type | std::ptrdiff_t
value_type | T
pointer | const T*
reference | const T&
iterator_category | std::random_access_iterator_tag
 (C++20 前)

对库类型的特化

std::iterator_traits<std::common_iterator> (C++20) | 对 std::counted_iterator 类型的属性提供均一的接口 (类模板特化)
std::iterator_traits<std::counted_iterator> (C++20) | 对 std::counted_iterator 类型的属性提供均一的接口 (类模板特化)

示例

下列使用展示对双向迭代器的通用 reverse() 实现

#include <iostream>
#include <iterator>
#include <vector>
#include <list>

template<class BidirIt>
void my_reverse(BidirIt first, BidirIt last)
{
    typename std::iterator_traits<BidirIt>::difference_type n = std::distance(first, last);
    --n;
    while(n > 0) {
        typename std::iterator_traits<BidirIt>::value_type tmp = *first;
        *first++ = *--last;
        *last = tmp;
        n -= 2;
    }
}

int main()
{
    std::vector<int> v{1, 2, 3, 4, 5};
    my_reverse(v.begin(), v.end());
    for (int n : v) {
        std::cout << n << ' ';
    }
    std::cout << '\n';

    std::list<int> l{1, 2, 3, 4, 5};
    my_reverse(l.begin(), l.end());
    for (auto n : l) {
        std::cout << n << ' ';
    }
    std::cout << '\n';

    int a[] = {1, 2, 3, 4, 5};
    my_reverse(a, a+5);
    for (int i=0; i<5; ++i) {
        std::cout << a[i] << ' ';
    }
    std::cout << '\n';

//    std::istreambuf_iterator<char> i1(std::cin), i2;
//    my_reverse(i1, i2); // 编译错误

}

输出：

5 4 3 2 1
5 4 3 2 1
5 4 3 2 1

参阅

iterator (C++17 中弃用) | 用于简化简单的迭代器的必要类型定义的基类 (类模板)
input_iterator_tagoutput_iterator_tagforward_iterator_tagbidirectional_iterator_tagrandom_access_iterator_tagcontiguous_iterator_tag (C++20) | 用于指示迭代器类别的空类类型 (类)


std::make_move_iterator

< cpp‎ | iterator
定义于头文件 <iterator> |
template< class Iter > std::move_iterator <Iter> make_move_iterator( Iter i ); | (C++11 起) (C++17 前)
template< class Iter > constexpr std::move_iterator <Iter> make_move_iterator( Iter i ); | (C++17 起)

make_move_iterator 是对给定迭代器 i 构造类型从参数类型推出的 std::move_iterator 的便利函数模板。

参数

i - 转换成移动迭代器的输入迭代器

返回值

可用于从通过 i 访问的元素移动的 std::move_iterator 。

可能的实现

template< class Iter >
constexpr // C++17 起
std::move_iterator<Iter> make_move_iterator( Iter i )
{
    return std::move_iterator<Iter>(std::move(i));
}

示例

#include <iostream>
#include <list>
#include <vector>
#include <string>
#include <iterator>

int main()
{
    std::list<std::string> s{"one", "two", "three"};

    std::vector<std::string> v1(s.begin(), s.end()); // copy

    std::vector<std::string> v2(std::make_move_iterator(s.begin()),
                                std::make_move_iterator(s.end())); // move

    std::cout << "v1 now holds: ";
    for (auto str : v1)
            std::cout << "\"" << str << "\" ";
    std::cout << "\nv2 now holds: ";
    for (auto str : v2)
            std::cout << "\"" << str << "\" ";
    std::cout << "\noriginal list now holds: ";
    for (auto str : s)
            std::cout << "\"" << str << "\" ";
    std::cout << '\n';
}

可能的输出：

v1 now holds: "one" "two" "three"
v2 now holds: "one" "two" "three"
original list now holds: "" "" ""

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2061 | C++11 | make_move_iterator 不将数组参数转换成指针 | 使之转换

参阅

move_iterator (C++11) | 解引用结果为右值引用的迭代器适配器 (类模板)
move (C++11) | 获得右值引用 (函数模板)


std::make_reverse_iterator

< cpp‎ | iterator
定义于头文件 <iterator> |
template <class Iter> std::reverse_iterator <Iter> make_reverse_iterator( Iter i ); | (C++14 起) (C++17 前)
template <class Iter> constexpr std::reverse_iterator <Iter> make_reverse_iterator( Iter i ); | (C++17 起)

make_reverse_iterator 是便利函数模板，对给定的迭代器 i ，构造拥有从参数类型推导的类型的 std::reverse_iterator 。

参数

i - 要转换为逆向迭代器的输入迭代器

返回值

从 i 构造的 std::reverse_iterator

可能的实现

template< class Iter >
constexpr std::reverse_iterator<Iter> make_reverse_iterator( Iter i )
{
    return std::reverse_iterator<Iter>(i);
}

示例

#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>

int main() {
    auto v = std::vector<int>{ 1, 3, 10, 8, 22 };

    std::sort(v.begin(), v.end());
    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ", "));

    std::cout << '\n';

    std::copy(
        std::make_reverse_iterator(v.end()),
        std::make_reverse_iterator(v.begin()),
        std::ostream_iterator<int>(std::cout, ", "));
}

输出：

1, 3, 8, 10, 22,
22, 10, 8, 3, 1,

参阅

reverse_iterator | 逆序遍历的迭代器适配器 (类模板)
rbegincrbegin (C++14) | 返回指向一个容器或数组的逆向迭代器 (函数模板)
rendcrend (C++14) | 返回容器或数组的逆向尾迭代器 (函数模板)


std::mergeable

< cpp‎ | iterator
定义于头文件 <iterator>
template< class I1, class I2, class Out, class R = ranges::less,

class P1 = std::identity, class P2 = std::identity >
concept mergeable =
std::input_iterator<I1> &&
std::input_iterator<I2> &&
std::weakly_incrementable<Out> &&
std::indirectly_copyable<I1, Out> &&
std::indirectly_copyable<I2, Out> &&
std::indirect_strict_weak_order<R,
std::projected<I1, P1>,

std::projected<I2, P2>>;
 (C++20 起)

mergeable 概念指定按照 R 所施加的严格弱序归并二个输入范围到单个输出范围的算法的要求。

语义要求

mergeable 仅若其所蕴含的所有概念均被实现才得以实现。

参阅

ranges::merge (C++20) | 归并二个已排序范围 (niebloid)
ranges::set_union (C++20) | 计算两个集合的并集 (niebloid)
ranges::set_intersection (C++20) | 计算两个集合的交集 (niebloid)
ranges::set_difference (C++20) | 计算两个集合的差集 (niebloid)
ranges::set_symmetric_difference (C++20) | 计算两个集合的对称差 (niebloid)


std::move_iterator

< cpp‎ | iterator
定义于头文件 <iterator> |
template< class Iter > class move_iterator; | (C++11 起)

std::move_iterator 是准确表现为底层迭代器（必须至少是一个老式输入迭代器 (LegacyInputIterator) 或实现 input_iterator (C++20 起)）的迭代器适配器，除了解引用会将底层迭代器返回的值转换为右值。若此迭代器用作输入迭代器，则效果是值被移动，而非复制。

成员类型

成员类型 | 定义
iterator_type | Iter
iterator_category

std::iterator_traits <Iter>::iterator_category

 (C++20 前)

若 std::iterator_traits <Iter>::iterator_category 合法且代表类型：

  • 若 std::iterator_traits <Iter>::iterator_category 实现 std::derived_from< std::random_access_iterator_tag > 则 iterator_category 为 std::random_access_iterator_tag 。
  • 否则成员 iterator_category 与 std::iterator_traits <Iter>::iterator_category 为同一类型。

否则无成员 iterator_category 。

 (C++20 起)
iterator_concept(C++20) | std::input_iterator_tag
value_type
std::iterator_traits <Iter>::value_type | (C++20 前)
std::iter_value_t<Iter> | (C++20 起)
difference_type
std::iterator_traits <Iter>::difference_type | (C++20 前)
std::iter_difference_t<Iter> | (C++20 起)
pointer | Iter
reference
若 std::iterator_traits<Iter>::reference 为引用，则为同一类型的右值引用版本。否则（例如若包装的迭代器以值返回）为不更改的 std::iterator_traits<Iter>::reference | (C++20 前)
std::iter_rvalue_reference_t<Iter> | (C++20 起)

成员函数

(构造函数) (C++11) | 构造新的迭代器适配器 (公开成员函数)
operator= (C++11) | 赋值另一迭代器适配器 (公开成员函数)
base (C++11) | 访问底层迭代器 (公开成员函数)
operator*operator-> (C++11)(C++11)(C++20 中弃用) | 访问被指向的元素 (公开成员函数)
operator[] (C++11) | 按索引访问元素 (公开成员函数)
operator++operator++(int)operator+=operator+operator--operator--(int)operator-=operator- (C++11) | 推进或回退迭代器 (公开成员函数)

成员对象

成员名称 | 定义
current (私有成员对象) | base() 所复制或移动 (C++20 起)的底层迭代器，名称仅用于阐释

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++11)(C++11)(C++20 中移除)(C++11)(C++11)(C++11)(C++11)(C++20) | 比较底层迭代器 (函数模板)
operator==(std::move_sentinel) (C++20) | 比较底层迭代器与底层哨位 (函数模板)
operator+ (C++11) | 令迭代器前进 (函数模板)
operator- (C++11) | 计算两个迭代器适配器间的距离 (函数模板)
operator-(std::move_sentinel) (C++20) | 计算底层迭代器与底层哨位间的距离 (函数模板)
iter_move (C++20) | 转型解引用底层迭代器的结果为其所关联的右值引用类型 (函数)
iter_swap (C++20) | 交换二个底层迭代器所指向的对象 (函数模板)
make_move_iterator (C++11) | 创建拥有从实参推出的类型的 std::move_iterator (函数模板)

示例

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <iterator>
#include <numeric>
#include <string>

int main()
{
    std::vector<std::string> v{"this", "_", "is", "_", "an", "_", "example"};

    auto print_v = [&](auto const rem) {
        std::cout << rem;
        for (const auto& s : v)
            std::cout << std::quoted(s) << ' ';
        std::cout << '\n';
    };

    print_v("Old contents of the vector: ");

    std::string concat = std::accumulate(std::make_move_iterator(v.begin()),
                                         std::make_move_iterator(v.end()),
                                         std::string());

    /* 使用 std::move_iterator 的替代方式可能是：
    using moviter_t = std::move_iterator<std::vector<std::string>::iterator>;
    std::string concat = std::accumulate(moviter_t(v.begin()),
                                         moviter_t(v.end()),
                                         std::string()); */

    print_v("New contents of the vector: ");

    std::cout << "Concatenated as string: " << quoted(concat) << '\n';
}

可能的输出：

Old contents of the vector: "this" "_" "is" "_" "an" "_" "example"
New contents of the vector: "" "" "" "" "" "" ""
Concatenated as string: "this_is_an_example"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2106 | C++11 | 若解引用底层迭代器返回纯右值则 解引用 move_iterator 能返回悬垂引用 | 替而返回对象
P2259R1 | C++20 | 成员 iterator_category 始终有定义 | 仅若 std::iterator_traits <Iter>::iterator_category 存在才定义

参阅

make_move_iterator (C++11) | 创建拥有从实参推出的类型的 std::move_iterator (函数模板)
move_sentinel (C++20) | 用于 std::move_iterator 的哨位适配器 (类模板)


std::move_iterator<Iter>::base

< cpp‎ | iterator‎ | move iterator
 | (1) |
iterator_type base() const; |  |  | (C++11 起) (C++17 前)
constexpr iterator_type base() const; |  |  | (C++17 起) (C++20 前)
constexpr const iterator_type& base() const& noexcept; |  |  | (C++20 起)
constexpr iterator_type base() &&; | (2) | (C++20 起)

返回底层迭代器。

1) 从底层迭代器复制构造返回值。 | (C++20 前)
1) 访问底层迭代器。 | (C++20 起)
2) 从底层迭代器移动构造返回值。

参数

（无）

返回值

1) 底层迭代器的副本。 | (C++20 前)
1) 底层迭代器。 | (C++20 起)
2) 从底层迭代器移动构造的迭代器。

异常

可能抛出实现定义的异常。

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> v{ 0, 1, 2, 3, 4 };
    std::move_iterator<std::vector<int>::reverse_iterator>
        m1{ v.rbegin() },
        m2{ v.rend() };

    std::copy(m1.base(), m2.base(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
}

输出：

4 3 2 1 0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3391 | C++20 | base 的 const 版本复制底层迭代器 | 它替而返回底层迭代器的引用
LWG 3593 | C++20 | base 的 const 版本返回引用但可以不是 noexcept | 使之为 noexcept

参阅

operator*operator->
(C++11)(C++11)(C++20 中弃用)
 访问被指向的元素
(公开成员函数)


std::iter_move(std::move_iterator)

< cpp‎ | iterator‎ | move iterator
friend constexpr std::iter_rvalue_reference_t<Iter>
iter_move( const std::move_iterator & i ) noexcept(/* see below */);
 (C++20 起)

转型解引用底层迭代器的结果到其关联的右值引用类型。

函数体等价于： return std::ranges​::​iter_move(i.current); 。

此函数模板对通常无限定或有限定查找不可见，而只能在 std::move_iterator<Iter> 为参数的关联类时由实参依赖查找找到。

参数

i - 源移动迭代器。

返回值

右值引用或纯右值临时量。

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(ranges::iter_move(i.current)))

示例

#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

void print(auto const& rem, auto const& v) {
    std::cout << rem << "[" << size(v) << "] { ";
    for (int o{}; auto const& s : v)
        std::cout << (o++ == 0 ? "" : ", ") << quoted(s);
    std::cout << " }\n";
}

int main()
{
    std::vector<std::string> p { "Andromeda", "Cassiopeia", "Phoenix" }, q;

    print("p", p), print("q", q);

    using MI = std::move_iterator<std::vector<std::string>::iterator>;

    for (MI first{ p.begin() }, last{ p.end() }; first != last; ++first) {
        q.emplace_back( /* ADL */ iter_move(first) );
    }

    print("p", p), print("q", q);
}

可能的输出：

p[3] { "Andromeda", "Cassiopeia", "Phoenix" }
q[0] {  }
p[3] { "", "", "" }
q[3] { "Andromeda", "Cassiopeia", "Phoenix" }

参阅

iter_move (C++20) | 将解引用迭代器的结果转型为其关联的右值引用类型 (定制点对象)
iter_move (C++20) | 转型解引用调整后的底层迭代器的结果为其所关联的右值引用类型 (函数)
move (C++11) | 获得右值引用 (函数模板)
move_if_noexcept (C++11) | 若移动构造函数不抛出则获得右值引用 (函数模板)
forward (C++11) | 转发一个函数实参 (函数模板)
ranges::move (C++20) | 将某一范围的元素移动到一个新的位置 (niebloid)
ranges::move_backword (C++20) | 按从后往前的顺序移动某一范围的元素到新的位置 (niebloid)


std::iter_swap(std::move_iterator)

< cpp‎ | iterator‎ | move iterator
template< std::indirectly_swappable<Iter> Iter2 >

friend constexpr void
iter_swap( const move_iterator& x, const std::move_iterator <Iter2>& y )

noexcept(/*see below*/);
 (C++20 起)

交换二个底层迭代器所指向的对象。函数体等价于 ranges​::​iter_swap(x.current, y.current); 。

此函数模板对通常无限定或有限定查找不可见，而只能在 std::move_iterator<Iter> 为参数的关联类时由实参依赖查找找到。

参数

x, y - 用于交换元素的移动迭代器。

返回值

（无）

复杂度

常数

异常

noexcept 说明：
noexcept(noexcept( ranges::iter_swap( x.current, y.current ) ))

示例

#include <iostream>
#include <iterator>
#include <string>
#include <vector>

int main()
{
    std::vector<std::string> p { "AA", "EE" },
                             q { "ⱯⱯ", "ƎƎ" };

    std::move_iterator<std::vector<std::string>::iterator>
        x = std::make_move_iterator( p.begin() ),
        y = std::make_move_iterator( q.begin() );

    std::cout << *x << ' ' << *y << '\n';

    iter_swap(x, y); // ADL

    std::cout << *x << ' ' << *y << '\n';
}

输出：

AA ⱯⱯ
ⱯⱯ AA

参阅

swap | 交换两个对象的值 (函数模板)
swap_ranges | 交换两个范围的元素 (函数模板)
iter_swap | 交换两个迭代器所指向的元素 (函数模板)
iter_swap (C++20) | 交换两个可解引用对象所引用的值 (定制点对象)
iter_swap (C++20) | 交换二个调整后的底层迭代器所指向的对象 (函数模板)


std::move_iterator<Iter>::move_iterator

< cpp‎ | iterator‎ | move iterator

 | (1)
move_iterator(); |  | (C++17 前)
constexpr move_iterator(); |  | (C++17 起)
 | (2)
explicit move_iterator( iterator_type x ); |  | (C++17 前)
constexpr explicit move_iterator( iterator_type x ); |  | (C++17 起)
 | (3)
template< class U > move_iterator( const move_iterator<U>& other ); |  | (C++17 前)
template< class U > constexpr move_iterator( const move_iterator<U>& other ); |  | (C++17 起)

构造新的迭代器适配器。

1) 默认构造函数。值初始化底层迭代器。若且唯若值初始化的底层迭代器有受定义行为，产生的迭代器上的操作才一样有受定义行为。
2) 以 x (C++20 前)std::move(x) (C++20 起) 初始化底层迭代器。
3) 以 other 的底层迭代器初始化底层迭代器。若 U 不可转换成 Iter 则行为未定义 (C++20 前)此重载仅若 U 与 Iter 不是同一类型且 std::convertible_to<const U&, Iter> 得到实现才参与重载决议 (C++20 起)。

参数

x | - | 要适配的迭代器
other | - | 要复制的迭代器适配器

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3435 | C++20 | 源自另一 move_iterator 的转换构造函数未受约束 | 已约束

参阅

operator=
(C++11)
 赋值另一迭代器适配器
(公开成员函数)


std::move_iterator<Iter>::operator*,->

< cpp‎ | iterator‎ | move iterator
 | (1)
reference operator* () const; |  | (C++11 起) (C++17 前)
constexpr reference operator* () const; |  | (C++17 起)
 | (2)
pointer operator->() const; |  | (C++11 起) (C++17 前)
constexpr pointer operator->() const; |  | (C++17 起) (C++20 中弃用)

返回到当前元素的右值引用或指针。

1) 等价于 static_cast<reference>(*base()) (C++20 前)ranges::iter_move(base()) (C++20 起) 。
2) 等价于 base() 。

参数

（无）

返回值

1) 到当前元素的右值引用或其副本。
2) 底层迭代器的副本。若直接使用 -> 则最终返回指向当前元素的指针。

注解

注意若直接使用 -> 则 (2) 最终返回指针。解引用指针时，返回值是左值。这可能导致非有意的行为。

示例

#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

void print(auto rem, auto const& v) {
    for (std::cout << rem; auto const& e : v)
        std::cout << quoted(e) << ' ';
    std::cout << '\n';
}

int main()
{
    std::vector<std::string> p{"alpha", "beta", "gamma", "delta"}, q;
    print("1) p: ", p);
    for (std::move_iterator it{p.begin()}, end{p.end()}; it != end; ++it) {
        it->push_back('!'); // 调用 -> string::push_back(char)
        q.emplace_back( *it );
    }
    print("2) p: ", p);
    print("3) q: ", q);

    std::vector v{1,2,3};
    std::move_iterator it{v.begin()};
    // *it = 13; // 错误：将右值用作左值
}

输出：

1) p: "alpha" "beta" "gamma" "delta"
2) p: "" "" "" ""
3) q: "alpha!" "beta!" "gamma!" "delta!"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2106 | C++11 | 若解引用底层迭代器返回纯右值则解引用 move_iterator 能返回悬垂引用 | 替而返回对象

参阅

operator[]
(C++11)
 按索引访问元素
(公开成员函数)


operator+(std::move_iterator)

< cpp‎ | iterator‎ | move iterator

定义于头文件 <iterator> |
template< class Iter > move_iterator<Iter> operator+( typename move_iterator<Iter>::difference_type n, const move_iterator<Iter>& it ); | (C++17 前)
template< class Iter > constexpr move_iterator<Iter> operator+( typename move_iterator<Iter>::difference_type n, const move_iterator<Iter>& it ); | (C++17 起)
返回增加了 n 的 it 。

此重载仅若 it.base() + n 良构并拥有 Iter 类型才参与重载决议。

 (C++20 起)

参数

n | - | 增加迭代器所用的位置数
it | - | 要增加的迭代器适配器

返回值

增加的迭代器，即 move_iterator<Iter>(it.base() + n)

示例

本节未完成
原因：暂无示例

参阅

operator++operator++(int)operator+=operator+operator--operator--(int)operator-=operator-
(C++11)
 推进或回退迭代器
(公开成员函数)


operator-(std::move_iterator)

< cpp‎ | iterator‎ | move iterator

template< class Iterator1, class Iterator2 > auto operator-( const move_iterator<Iterator1>& lhs, const move_iterator<Iterator2>& rhs ) -> decltype(lhs.base() - rhs.base()); | (C++11 起) (C++17 前)
template< class Iterator1, class Iterator2 > constexpr auto operator-( const move_iterator<Iterator1>& lhs, const move_iterator<Iterator2>& rhs ) -> decltype(lhs.base() - rhs.base()); | (C++17 起)

返回二个迭代器适配器间的距离。

参数

lhs, rhs - 要计算距离的迭代器适配器

返回值

lhs.base() - rhs.base()

示例

本节未完成
原因：暂无示例


operator-(std::move_iterator<Iter>, std::move_sentinel)

< cpp‎ | iterator‎ | move iterator
template<std::sized_sentinel_for<Iter> S>

friend constexpr std::iter_difference_t<Iter>

operator-(const std::move_sentinel<S>& s, const move_iterator& i);
 (1) (C++20 起)
template<std::sized_sentinel_for<Iter> S>

friend constexpr std::iter_difference_t<Iter>

operator-(const move_iterator& i, const std::move_sentinel<S>& s);
 (2) (C++20 起)

返回 move_iterator 与 move_sentinel 间的距离。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::move_iterator<Iter> 为参数的关联类时由实参依赖查找找到。

参数

i | - | std::move_iterator<Iter>
s | - | std::move_sentinel<S> ，其中 S 实现 std::sized_sentinel_for<Iter>

返回值

1) s.base() - i.base()
2) i.base() - s.base()

参阅

operator-
(C++11)
 计算两个迭代器适配器间的距离
(函数模板)


std::move_iterator<Iter>::operator=

< cpp‎ | iterator‎ | move iterator

template< class U > move_iterator& operator=( const move_iterator<U>& other ); | (C++17 前)
template< class U > constexpr move_iterator& operator=( const move_iterator<U>& other ); | (C++17 起)

对底层迭代器赋 other 的底层迭代器的值，即 other.base() 。

若 U 不可转换为 Iter 则行为未定义。 | (C++20 前)
此重载仅若 U 与 Iter 不是同一类型且 std::convertible_to<const U&, Iter> 与 std::assignable_from<Iter&, const U&> 均得到实现才参与重载决议。 | (C++20 起)

参数

other - 要赋值的迭代器适配器

返回值

*this

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3435 | C++20 | 转换赋值运算符未受约束 | 已约束

参阅

(构造函数)
(C++11)
 构造新的迭代器适配器
(公开成员函数)


std::move_iterator<Iter>::operator++,+,+=,--,-,-=

< cpp‎ | iterator‎ | move iterator

 | (1)
move_iterator& operator++(); |  | (C++17 前)
constexpr move_iterator& operator++(); |  | (C++17 起)
 | (2)
move_iterator& operator--(); |  | (C++17 前)
constexpr move_iterator& operator--(); |  | (C++17 起)
 | (3)
move_iterator operator++( int ); |  | (C++17 前)
constexpr move_iterator operator++( int ); |  | (C++17 起) (C++20 前)
constexpr auto operator++( int ); |  | (C++20 起)
 | (4)
move_iterator operator--( int ); |  | (C++17 前)
constexpr move_iterator operator--( int ); |  | (C++17 起)
 | (5)
move_iterator operator+( difference_type n ) const; |  | (C++17 前)
constexpr move_iterator operator+( difference_type n ) const; |  | (C++17 起)
 | (6)
move_iterator operator-( difference_type n ) const; |  | (C++17 前)
constexpr move_iterator operator-( difference_type n ) const; |  | (C++17 起)
 | (7)
move_iterator& operator+=( difference_type n ); |  | (C++17 前)
constexpr move_iterator& operator+=( difference_type n ); |  | (C++17 起)
 | (8)
move_iterator& operator-=( difference_type n ); |  | (C++17 前)
constexpr move_iterator& operator-=( difference_type n ); |  | (C++17 起)

自增或自减迭代器。

1-2) 分别前自增或前自减一。
3-4) 分别后自增或后自减一。
5-6) 分别返回前进 n 或 -n 个位置的迭代器。
7-8) 分别令迭代器前进 n 或 -n 个位置。

返回值

1-2) *this
3-4) *this 修改前的副本，然而若 Iter 不实现 forward_iterator ，则后自增运算符不返回这种副本而返回类型为 void (C++20 起)。
5-6) 分别为 move_iterator(base()+n) 或 move_iterator(base()-n) 。
7-8) *this

示例

本节未完成
原因：暂无示例

参阅

operator+
(C++11)
 令迭代器前进
(函数模板)


std::move_iterator<Iter>::operator[]

< cpp‎ | iterator‎ | move iterator

/*unspecified*/ operator[]( difference_type n ) const; | (C++11 起) (C++17 前)
constexpr /*unspecified*/ operator[]( difference_type n ) const; | (C++17 起)

返回在指定相相对位置的引用。

参数

n - 相对于当前位置的位置。

返回值

到在相对位置元素的右值引用，即 std::move(base()[n]) (C++20 前)ranges::iter_move(base() + n) (C++20 起) 。

示例

#include <iomanip>
#include <iostream>
#include <iterator>
#include <list>
#include <string>
#include <vector>

void print(auto rem, auto const& v) {
    for (std::cout << rem; auto const& e : v)
        std::cout << quoted(e) << ' ';
    std::cout << '\n';
}

int main()
{
    std::vector<std::string> p{"alpha", "beta", "gamma", "delta"}, q;
    print("1) p: ", p);

    std::move_iterator it{p.begin()};

    for (size_t t{0U}; t != p.size(); ++t) {
        q.emplace_back( it[t] );
    }

    print("2) p: ", p);
    print("3) q: ", q);

    std::list l{1,2,3};
    std::move_iterator it2{l.begin()};
//  it2[1] = 13;   // 编译错误 ~ 底层迭代器不实现随机访问迭代器
//  *it2 = 999;    // 编译错误：以右值为左值
}

可能的输出：

1) p: "alpha" "beta" "gamma" "delta"
2) p: "" "" "" ""
3) q: "alpha" "beta" "gamma" "delta"

参阅

operator*operator->
(C++11)(C++11)(C++20 中弃用)
 访问被指向的元素
(公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::move_iterator)

< cpp‎ | iterator‎ | move iterator

(1)
template< class Iterator1, class Iterator2 >

bool operator==( const std::move_iterator <Iterator1>& lhs,

const std::move_iterator <Iterator2>& rhs );
 (C++17 前)
template< class Iterator1, class Iterator2 >

constexpr bool operator==( const std::move_iterator <Iterator1>& lhs,

const std::move_iterator <Iterator2>& rhs );
 (C++17 起)
(2)
template< class Iterator1, class Iterator2 >

bool operator!=( const std::move_iterator <Iterator1>& lhs,

const std::move_iterator <Iterator2>& rhs );
 (C++17 前)
template< class Iterator1, class Iterator2 >

constexpr bool operator!=( const std::move_iterator <Iterator1>& lhs,

const std::move_iterator <Iterator2>& rhs );
 (C++17 起)
(C++20 前)
(3)
template< class Iterator1, class Iterator2 >

bool operator<( const std::move_iterator <Iterator1>& lhs,

const std::move_iterator <Iterator2>& rhs );
 (C++17 前)
template< class Iterator1, class Iterator2 >

constexpr bool operator<( const std::move_iterator <Iterator1>& lhs,

const std::move_iterator <Iterator2>& rhs );
 (C++17 起)
(4)
template< class Iterator1, class Iterator2 >

bool operator<=( const std::move_iterator <Iterator1>& lhs,

const std::move_iterator <Iterator2>& rhs );
 (C++17 前)
template< class Iterator1, class Iterator2 >

constexpr bool operator<=( const std::move_iterator <Iterator1>& lhs,

const std::move_iterator <Iterator2>& rhs );
 (C++17 起)
(5)
template< class Iterator1, class Iterator2 >

bool operator>( const std::move_iterator <Iterator1>& lhs,

const std::move_iterator <Iterator2>& rhs );
 (C++17 前)
template< class Iterator1, class Iterator2 >

constexpr bool operator>( const std::move_iterator <Iterator1>& lhs,

const std::move_iterator <Iterator2>& rhs );
 (C++17 起)
(6)
template< class Iterator1, class Iterator2 >

bool operator>=( const std::move_iterator <Iterator1>& lhs,

const std::move_iterator <Iterator2>& rhs );
 (C++17 前)
template< class Iterator1, class Iterator2 >

constexpr bool operator>=( const std::move_iterator <Iterator1>& lhs,

const std::move_iterator <Iterator2>& rhs );
 (C++17 起)
template<class Iterator1, std::three_way_comparable_with<Iterator1> Iterator2>

constexpr std::compare_three_way_result_t<Iterator1, Iterator2>
operator<=>( const std::move_iterator <Iterator1>& x,

const std::move_iterator <Iterator2>& y );
 (7) (C++20 起)

比较底层迭代器。

(1-6) 仅若其底层比较表达式（见后述）为良构且可转换为 bool 才参与重载决议。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的迭代器适配器

返回值

1) lhs.base() == rhs.base()
2) !(lhs == rhs)
3) lhs.base() < rhs.base()
4) !(rhs < lhs)
5) rhs < lhs
6) !(lhs < rhs)
7) lhs.base() <=> rhs.base()

示例

本节未完成
原因：暂无示例


operator==(std::move_iterator<Iter>, std::move_sentinel)

< cpp‎ | iterator‎ | move iterator
template<std::sentinel_for<Iter> S>

friend constexpr bool

operator==(const move_iterator& i, const std::move_sentinel<S>& s);
 (C++20 起)

比较 move_iterator 与 move_sentinel 。

此函数模板对通常无限定或有限定查找不可见，而只能在 std::move_iterator<Iter> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

参数

i | - | std::move_iterator<Iter>
s | - | std::move_sentinel<S> ，其中 S 实现 std::sentinel_for<Iter>

返回值

i.base() == s.base()

参阅

operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++11)(C++11)(C++20 中移除)(C++11)(C++11)(C++11)(C++11)(C++20)
 比较底层迭代器
(函数模板)


std::move_sentinel

< cpp‎ | iterator
定义于头文件 <iterator>
template< std::semiregular S >
class move_sentinel;
 (C++20 起)

std::move_sentinel 是用于与 std::move_iterator 一同代表范围的哨位适配器。

模板形参

S - 底层哨位的类型

成员函数

(构造函数) (C++20) | 构造新的 move_sentinel (公开成员函数)
operator= (C++20) | 赋值一个 move_sentinel 的内容给另一个 (公开成员函数)
base (C++20) | 返回底层哨位的副本 (公开成员函数)

成员对象

成员名 | 定义
last (私有成员对象) | 底层哨位，名字仅为阐释

非成员函数

注解：这些成员函数是 std::move_iterator 的隐藏友元，并且对通常无限定或有限定查找不可见。

operator==(std::move_sentinel) (C++20) | 比较底层迭代器与底层哨位 (函数模板)
operator-(std::move_sentinel) (C++20) | 计算底层迭代器与底层哨位间的距离 (函数模板)

示例

本节未完成
原因：暂无示例

参阅

move_iterator
(C++11)
 解引用结果为右值引用的迭代器适配器
(类模板)


std::move_sentinel<S>::base

< cpp‎ | iterator‎ | move sentinel
constexpr S base() const; | (C++20 起)

返回底层哨位。

参数

（无）

返回值

底层哨位。

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

base
(C++11)
 访问底层迭代器
(std::move_iterator<Iter> 的公开成员函数)


std::move_sentinel<S>::move_sentinel

< cpp‎ | iterator‎ | move sentinel
constexpr move_sentinel();
 (1) (C++20 起)
constexpr explicit move_sentinel( S x );
 (2) (C++20 起)
template< class S2 >

requires std::convertible_to<const S2&, S>

constexpr move_sentinel(const std::move_sentinel<S2>& other);
 (3) (C++20 起)

构造新的哨位适配器。

1) 默认构造函数。值初始化底层哨位。
2) 以 x 初始化底层哨位。
3) 以 other 的底层哨位初始化底层哨位。

参数

x | - | 要适配的哨位
other | - | 要复制的哨位适配器

示例

本节未完成
原因：暂无示例

参阅

(构造函数)
(C++11)
 构造新的迭代器适配器
(std::move_iterator<Iter> 的公开成员函数)


std::move_sentinel<S>::operator=

< cpp‎ | iterator‎ | move sentinel
template<class S2>

requires std::assignable_from<S&, const S2&>

constexpr move_sentinel& operator=(const std::move_sentinel<S2>& other);
 (C++20 起)

赋 other 的底层哨位的值，即 other.base() ，给底层哨位。

参数

other - 要赋值的哨位适配器

返回值

*this

示例

本节未完成
原因：暂无示例

参阅

operator=
(C++11)
 赋值另一迭代器适配器
(std::move_iterator<Iter> 的公开成员函数)


std::next

< cpp‎ | iterator
定义于头文件 <iterator> |
template< class InputIt > InputIt next( InputIt it, typename std::iterator_traits <InputIt>::difference_type n = 1 ); | (C++11 起) (C++17 前)
template< class InputIt > constexpr InputIt next( InputIt it, typename std::iterator_traits <InputIt>::difference_type n = 1 ); | (C++17 起)

返回迭代器 it 的第 n 个后继。

参数

it | - | 迭代器
n | - | 要前进的元素数
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

迭代器 it 的第 n 个后继。

复杂度

线性。

然而，若 InputIt 还满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求，则复杂度为常数。

可能的实现

template<class InputIt>
constexpr // C++17 起
InputIt next(InputIt it,
             typename std::iterator_traits<Input>::difference_type n = 1)
{
    std::advance(it, n);
    return it;
}

注解

尽管表达式 ++c.begin() 通常能编译，然而不保证会这么做： c.begin() 是右值表达式，而无老式输入迭代器 (LegacyInputIterator) 要求指定右值的自增保证进行。尤其是迭代器以指针实现或其 operator++ 为左值引用限定时， ++c.begin() 不能编译，而 std::next(c.begin()) 可以。

示例

#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> v{ 3, 1, 4 };

    auto it = v.begin();

    auto nx = std::next(it, 2);

    std::cout << *it << ' ' << *nx << '\n';
}

输出：

3 4

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2353 | C++11 | next 要求老式向前迭代器 (LegacyForwardIterator) | 允许老式输入迭代器 (LegacyInputIterator)

参阅

prev (C++11) | 令迭代器自减 (函数模板)
advance | 令迭代器前进给定的距离 (函数模板)


std::ostream_iterator

< cpp‎ | iterator
定义于头文件 <iterator> |
template< class T, class CharT = char, class Traits = std::char_traits <CharT> > class ostream_iterator : public std::iterator < std::output_iterator_tag, void, void, void, void> | (C++17 前)
template< class T, class CharT = char, class Traits = std::char_traits <CharT>> class ostream_iterator; | (C++17 起)

std::ostream_iterator 是单趟老式输出迭代器 (LegacyOutputIterator) ，用 operator<< 写入相继 T 类型对象到为之创建迭代器的 std::basic_ostream 对象。每次写操作后写入可选的分隔字符串。写操作在赋值给迭代器时（无论是否解引用）进行。自增 std::ostream_iterator 是无操作。

典型实现中， std::ostream_iterator 仅有的数据成员是指向关联 std::basic_ostream 的指针和指向分隔字符串首字符的指针。

写入字符时， std::ostreambuf_iterator 更有效率，因为它避免对每个字符构造并析构一次 sentry 对象的开销。

成员类型

成员类型 | 定义
iterator_category | std::output_iterator_tag
value_type | void
difference_type
void | (C++20 前)
std::ptrdiff_t | (C++20 起)
pointer | void
reference | void
char_type | CharT
traits_type | Traits
ostream_type | std::basic_ostream <CharT, Traits>

要求通过从 std::iterator < std::output_iterator_tag, void, void, void, void> 继承获得成员类型 iterator_category、 value_type、 difference_type、 pointer 及 reference 。

 (C++17 前)

成员函数

(构造函数) | 构造新的 ostream_iterator (公开成员函数)
(析构函数) | 析构 ostream_iterator (公开成员函数)
operator= | 写对象到关联的输出序列 (公开成员函数)
operator* | 无操作 (公开成员函数)
operator++operator++(int) | 无操作 (公开成员函数)

示例

#include <iostream>
#include <sstream>
#include <iterator>
#include <numeric>

int main()
{
    std::istringstream str("0.1 0.2 0.3 0.4");
    std::partial_sum(std::istream_iterator<double>(str),
                      std::istream_iterator<double>(),
                      std::ostream_iterator<double>(std::cout, " "));
}

输出：

0.1 0.3 0.6 1

参阅

ostreambuf_iterator | 写入 std::basic_streambuf 的输出迭代器 (类模板)
istream_iterator | 从 std::basic_istream 读取的输入迭代器 (类模板)
std::experimental::ostream_joiner (库基础 TS v2) | 写入相继元素到输出流的输出迭代器，以分割器分隔相邻元素 (类模板)


std::ostream_iterator<T,CharT,Traits>::operator*

< cpp‎ | iterator‎ | ostream iterator

ostream_iterator& operator*();

不做任何事，提供此函数以满足老式输出迭代器 (LegacyOutputIterator) 的要求。

它返回迭代器自身，这使得可以用诸如 *iter = value 的代码输出（插入）值到底层的流。

参数

（无）

返回值

*this


std::ostream_iterator<T,CharT,Traits>::operator=

< cpp‎ | iterator‎ | ostream iterator
ostream_iterator& operator=( const T& value );

插入 value 到关联的流，然后插入分隔符，若在构造时指定它。

若 out_stream 是指向关联 std::basic_ostream 的指针而 delim 是在此对象构造时指定的分隔符，则效果等价于

*out_stream << value;
if(delim != 0)
*out_stream << delim;
return *this;

参数

value - 要插入的对象

返回值

*this

注意

T 能是任何拥有用户定义 operator<< 的类。

示例

#include <iostream>
#include <iterator>

int main()
{
    std::ostream_iterator<int> i1(std::cout, ", ");
    *i1++ = 1; // 通常形式，为标准算法所用
    *++i1 = 2;
    i1 = 3; // * 或 ++ 皆非必须
    std::ostream_iterator<double> i2(std::cout);
    i2 = 3.14;
}

输出：

1, 2, 3, 3.14


std::ostream_iterator<T,CharT,Traits>::operator++

< cpp‎ | iterator‎ | ostream iterator
ostream_iterator& operator++();
ostream_iterator& operator++( int );

不做任何事。提供这些运算符以满足老式输出迭代器 (LegacyOutputIterator) 的要求。它们使得表达式 *iter++=value 和 *++iter=value 可用于输出（插入）值到底层的流。

参数

（无）

返回值

*this


std::ostream_iterator<T,CharT,Traits>::ostream_iterator

< cpp‎ | iterator‎ | ostream iterator
ostream_iterator( ostream_type& stream, const CharT* delim ); | (1)
ostream_iterator( ostream_type& stream ); | (2)
1) 以 stream 为关联流并以 delim 为分隔符构造迭代器。
2) 以 stream 为关联流并以空指针为分隔符构造迭代器。

参数

stream | - | 此迭代器所访问的输出流
delim | - | 在每次输出后插入流的空终止字符串

示例

#include <iostream>
#include <iterator>
#include <algorithm>
#include <numeric>
int main()
{
    std::ostream_iterator<char> oo {std::cout};
    std::ostream_iterator<int> i1 {std::cout, ", "};
    std::fill_n(i1, 5, -1);
    *oo++ = '\n';

    std::ostream_iterator<double> i2 {std::cout, "; "};
    *i2++ = 3.14;
    *i2++ = 2.71;
    *oo++ = '\n';

    std::common_iterator<std::counted_iterator<std::ostream_iterator<float>>,
                         std::default_sentinel_t>
        first { std::counted_iterator{std::ostream_iterator<float>{std::cout," ~ "}, 5} },
        last { std::default_sentinel };
    std::iota(first, last, 2.2);
    *oo++ = '\n';
}

输出：

-1, -1, -1, -1, -1,
3.14; 2.71;
2.2 ~ 3.2 ~ 4.2 ~ 5.2 ~ 6.2 ~

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | 由于 C++20 迭代器必须为 default_initializable 提供了默认构造函数 | 与该要求一同移除


std::ostream_iterator<T,CharT,Traits>::~ostream_iterator

< cpp‎ | iterator‎ | ostream iterator
~ostream_iterator()

销毁迭代器。不影响关联的输出流。


std::ostreambuf_iterator

< cpp‎ | iterator
定义于头文件 <iterator>
template< class CharT, class Traits = std::char_traits <CharT> >

class ostreambuf_iterator : public std::iterator < std::output_iterator_tag,

void, void, void, void>
 (C++17 前)
template< class CharT, class Traits = std::char_traits <CharT> >
class ostreambuf_iterator;
 (C++17 起)

std::ostreambuf_iterator 是单趟老式输出迭代器 (LegacyOutputIterator) ，写入相继元素到为之创建迭代器的 std::basic_streambuf 对象。实际写操作在赋值给迭代器（无论是否解引用）时进行。自增 std::ostreambuf_iterator 是无操作。

典型实现中， std::ostreambuf_iterator 仅有的数据成员是指向关联 std::basic_streambuf 的指针，和指示是否抵达文件尾条件的布尔标志。

成员类型

成员类型 | 定义
iterator_category | std::output_iterator_tag
value_type | void
difference_type
void | (C++20 前)
std::ptrdiff_t | (C++20 起)
pointer | void
reference | void
char_type | CharT
traits_type | Traits
streambuf_type | std::basic_streambuf <CharT, Traits>
ostream_type | std::basic_ostream <CharT, Traits>

要求通过从 std::iterator < std::output_iterator_tag, void, void, void, void> 继承获得成员类型 iterator_category、 value_type、 difference_type、 pointer 及 reference 。

 (C++17 前)

成员函数

(构造函数) | 构造新的 ostreambuf_iterator (公开成员函数)
(析构函数) (隐式声明) | 销毁 ostreambuf_iterator (公开成员函数)
operator= | 写字符到关联的输出序列 (公开成员函数)
operator* | 无操作 (公开成员函数)
operator++operator++(int) | 无操作 (公开成员函数)
failed | 测试是否输出失败 (公开成员函数)

示例

#include <string>
#include <algorithm>
#include <iterator>
#include <iostream>

int main()
{
    std::string s = "This is an example\n";
    std::copy(s.begin(), s.end(), std::ostreambuf_iterator<char>(std::cout));
}

输出：

This is an example

参阅

istreambuf_iterator | 从 std::basic_streambuf 读取的输入迭代器 (类模板)
ostream_iterator | 写入 std::basic_ostream 的输出迭代器 (类模板)


std::ostreambuf_iterator<CharT,Traits>::failed

< cpp‎ | iterator‎ | ostreambuf iterator
bool failed() const throw(); | (C++11 前)
bool failed() const noexcept; | (C++11 起)

若迭代器遇到文件尾条件，即若先前对 std::basic_streambuf::sputc （由 operator= 执行）的调用返回 Traits::eof ，则返回 true。

参数

（无）

返回值

若迭代器在输出时已遇到文件尾条件则为 true ，否则为 false 。

示例

本节未完成
原因：暂无示例


std::ostreambuf_iterator<CharT,Traits>::operator*

< cpp‎ | iterator‎ | ostreambuf iterator

ostreambuf_iterator& operator*();

不做任何事，提供此函数以满足老式输出迭代器 (LegacyOutputIterator) 的要求。

它返回迭代器自身，这使得可以用诸如 *iter = value 的代码输出（插入）值到底层的流。

参数

（无）

返回值

*this


std::ostreambuf_iterator<CharT,Traits>::operator=

< cpp‎ | iterator‎ | ostreambuf iterator
ostreambuf_iterator& operator=( CharT c );

若 failed() 返回 false ，则用 pbuf->sputc(c) 插入 c 到关联的输出流缓冲，其中 pbuf 是 streambuf_type* 类型的私有成员。否则，不做任何事。

若调用 pbuf->sputc(c) 返回 Traits::eof ，则设置 failed() 标志为 true 。

参数

c - 要插入的字符

返回值

*this

示例

本节未完成
原因：暂无示例

参阅

sputc
 写一个字符到放置区域，并令 next 指针前进
(std::basic_streambuf<CharT,Traits> 的公开成员函数)


std::ostreambuf_iterator<CharT,Traits>::operator++

< cpp‎ | iterator‎ | ostreambuf iterator
ostreambuf_iterator& operator++();
ostreambuf_iterator& operator++( int );

不做任何事。提供这些运算符以满足老式输出迭代器 (LegacyOutputIterator) 的要求。它们使得表达式 *iter++=value 和 *++iter=value 可用于输出（插入）值到底层的流。

参数

（无）

返回值

*this


std::ostreambuf_iterator<CharT,Traits>::ostreambuf_iterator

< cpp‎ | iterator‎ | ostreambuf iterator
 | (1)
ostreambuf_iterator( streambuf_type* buffer ) throw(); |  | (C++11 前)
ostreambuf_iterator( streambuf_type* buffer ) noexcept; |  | (C++11 起)
 | (2)
ostreambuf_iterator( ostream_type& stream ) throw(); |  | (C++11 前)
ostreambuf_iterator( ostream_type& stream ) noexcept; |  | (C++11 起)
1) 构造迭代器，将私有的 streambuf_type* 成员设为 buffer 并将 failed() 标志设为 false 。若 buffer 是空指针则行为未定义。
2) 同 ostreambuf_iterator(stream.rdbuf()) 。

参数

stream | - | 将关联其 rdbuf() 到此迭代器的输出流
buffer | - | 此迭代器要访问的输出流缓冲

示例

#include <iostream>
#include <fstream>
#include <iterator>
int main()
{
    std::basic_filebuf<char> f;
    f.open("test.txt", std::ios::out);

    std::ostreambuf_iterator<char> out1(&f);

    std::ostreambuf_iterator<wchar_t> out2(std::wcout);

    *out1 = 'a';
    *out2 = L'a';
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | 由于 C++20 迭代器必须为 default_initializable 提供了默认构造函数 | 与该要求一同移除


std::output_iterator

< cpp‎ | iterator
定义于头文件 <iterator>
template <class I, class T>

concept output_iterator =
std::input_or_output_iterator<I> &&
std::indirectly_writable<I, T> &&
requires(I i, T&& t) {
*i++ = std::forward <T>(t); // 不要求保持相等性

};
 (C++20 起)

output_iterator 概念是 input_or_output_iterator 的细化，添加了能用于写入值类型和值类别为 T 所编码的值的要求（经由 indirectly_writable ）。不要求 equality_comparable 。

语义要求

令 E 为满足 decltype((E)) 为 T 的表达式，而 i 为 I 类型的可解引用对象。 output_iterator<I, T> 仅若其所蕴含的概念均被实现，且 *i++ = E; 拥有等价于 *i = E; ++i; 的效果才得以实现。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

注解

不同于老式输出迭代器 (LegacyOutputIterator) 要求， output_iterator 概念不要求定义迭代器类别标签。

输出迭代器上的算法应该为单趟。

参阅

input_or_output_iterator
(C++20)
 指定该类型对象可以自增且可以解引用
(概念)


std::permutable

< cpp‎ | iterator
定义于头文件 <iterator>
template< class I >

concept permutable =
std::forward_iterator<I> &&
std::indirectly_movable_storable<I> &&

std::indirectly_swappable<I>;
 (C++20 起)

概念 permutable 细化 std::forward_iterator ，添加通过移动与交换重排的要求。

语义要求

I 实现 permutable ，仅若其所蕴含的所有概念均得到实现。

参阅

sortable (C++20) | 指定重排序列为有序序列的算法的共用要求 (概念)
ranges::removeranges::remove_if (C++20)(C++20) | 移除满足特定判别标准的元素 (niebloid)
ranges::unique (C++20) | 移除范围中的连续重复元素 (niebloid)
ranges::reverse (C++20) | 逆转范围中的元素顺序 (niebloid)
ranges::rotate (C++20) | 旋转范围中的元素顺序 (niebloid)
ranges::shuffle (C++20) | 随机重排范围中的元素 (niebloid)
ranges::partition (C++20) | 将范围中的元素分为二组 (niebloid)
ranges::stable_partition (C++20) | 将元素分成二组，同时保持其相对顺序 (niebloid)


std::prev

< cpp‎ | iterator
定义于头文件 <iterator> |
template< class BidirIt > BidirIt prev( BidirIt it, typename std::iterator_traits <BidirIt>::difference_type n = 1 ); | (C++11 起) (C++17 前)
template< class BidirIt > constexpr BidirIt prev( BidirIt it, typename std::iterator_traits <BidirIt>::difference_type n = 1 ); | (C++17 起)

返回迭代器 it 的第 n 个前驱。

参数

it | - | 迭代器
n | - | it 要被减少的次数
类型要求
- BidirIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求。

返回值

迭代器 it 的第 n 个前驱。

复杂度

线性。

然而，若 BidirIt 还满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求，则复杂度为常数。

可能的实现

template<class BidirIt>
constexpr // C++17 起
BidirIt prev(BidirIt it, typename std::iterator_traits<BidirIt>::difference_type n = 1)
{
    std::advance(it, -n);
    return it;
}

注解

尽管表达式 --c.end() 通常能编译，然而不保证会这么做： c.end() 是右值表达式，而且无迭代器要求指定右值的自减保证进行。尤其是当迭代器实现为指针或其 operator-- 为左值引用限定时， --c.end() 不能编译，而 std::prev(c.end()) 可以。

示例

#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> v{ 3, 1, 4 };

    auto it = v.end();

    auto pv = std::prev(it, 2);

    std::cout << *pv << '\n';
}

输出：

1

参阅

next (C++11) | 令迭代器自增 (函数模板)
advance | 令迭代器前进给定的距离 (函数模板)


std::projected

< cpp‎ | iterator
定义于头文件 <iterator>
template< std::indirectly_readable I,

std::indirectly_regular_unary_invocable<I> Proj >
struct projected {
using value_type = std::remove_cvref_t<std::indirect_result_t<Proj&, I>>;
std::indirect_result_t<Proj&, I> operator*() const; // 不定义

};
 (1) (C++20 起)
template< std::weakly_incrementable I, class Proj >

struct incrementable_traits<std::projected<I, Proj>> {
using difference_type = std::iter_difference_t<I>;

};
 (2) (C++20 起)
1) 类模板 projected 组合 indirectly_readable 类型 I 与可调用对象类型 Proj 到新的 indirectly_readable 类型中，其引用类型是应用 Proj 到 std::iter_reference_t<I> 的结果。
2) std::incrementable_traits 的此特化使 std::projected<I, Proj> 在 I 为 weakly_incrementable 类型时亦为 weakly_incrementable 类型。

projected 仅用于制约接受可调用对象与投影的算法，从而其 operator*() 不被定义。

模板形参

I | - | 间接可读类型
Proj | - | 应用到解引用的 I 的投影


std::random_access_iterator

< cpp‎ | iterator
定义于头文件 <iterator>
template<class I>

concept random_access_iterator =
std::bidirectional_iterator<I> &&
std::derived_from</*ITER_CONCEPT*/<I>, std::random_access_iterator_tag > &&
std::totally_ordered<I> &&
std::sized_sentinel_for<I, I> &&
requires(I i, const I j, const std::iter_difference_t<I> n) {
{ i += n } -> std::same_as<I&>;
{ j + n } -> std::same_as<I>;
{ n + j } -> std::same_as<I>;
{ i -= n } -> std::same_as<I&>;
{ j - n } -> std::same_as<I>;
{ j[n] } -> std::same_as<std::iter_reference_t<I>>;

};
 (C++20 起)

概念 random_access_iterator 细化 bidirectional_iterator ，添加用 += 、 -= 、 + 和 - 运算符的常数时间前进、用 - 的常数时间距离计算，及带下标的数组记法支持。

迭代器概念确定

此概念的定义通过仅用于阐释的别名模板 /*ITER_CONCEPT*/ 说明。

为确定 /*ITER_CONCEPT*/<I> ，令 ITER_TRAITS<I> 若特化 std::iterator_traits <I> 从主模板生成则指代 I ，否则指代 std::iterator_traits <I> ：

  • 若 ITER_TRAITS<I>::iterator_concept 合法并指名类型，则 /*ITER_CONCEPT*/<I> 指代该类型。
  • 否则，若 ITER_TRAITS<I>::iterator_category 合法并指名类型，则 /*ITER_CONCEPT*/<I> 指代该类型。
  • 否则，若 std::iterator_traits <I> 从主模板生成，则 /*ITER_CONCEPT*/<I> 指代 std::random_access_iterator_tag 。
  • 否则 /*ITER_CONCEPT*/<I> 不指代类型并导致替换失败。

语义要求

令 a 与 b 为 I 类型的合法迭代器，使得从 a 可抵达 b ，并令 n 为等于 b - a 的 std::iter_difference_t<I> 类型值。 random_access_iterator<I> 仅若其所蕴含的概念均被实现并且符合下列条件才得到实现：

  • (a += n) 等于 b 。
  • std::addressof (a += n) 等于 std::addressof (a) 。
  • (a + n) 等于 (a += n) 。
  • (a + n) 等于 (n + a) 。
  • 对于任何二个正整数 x 与 y ，若 a + (x + y) 合法，则 a + (x + y) 等于 (a + x) + y 。
  • a + 0 等于 a 。
  • 若 (a + (n - 1)) 合法，则 --b 等于 (a + (n - 1)) 。
  • (b += -n) 与 (b -= n) 都等于 a 。
  • std::addressof (b -= n) 等于 std::addressof (b) 。
  • (b - n) 等于 (b -= n) 。
  • 若 b 可解引用，则 a[n] 合法并等于 *b 。
  • bool(a <= b) 为 true 。
  • 每个要求的操作均拥有常数时间复杂度。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

隐式表达式变种

使用不修改某 const 左值运算数的表达式的 requires 表达式亦隐式要求该表达式的额外变种对给定运算数接受非 const 左值或（可为 const 的）右值，除非以有区别的语义显式要求这种表达式变种。这些隐式表达式变种必须符合与声明的表达式的相同的语义。不指定实现以何种程度校验变种的语法。

注解

不同于老式随机访问迭代器 (LegacyRandomAccessIterator) 要求， random_access_iterator 概念不要求解引用返回左值。

参阅

bidirectional_iterator
(C++20)
 指定 forward_iterator 为双向迭代器，支持向后移动
(概念)


std::ranges::advance

< cpp‎ | iterator
定义于头文件 <iterator>
调用签名
template< std::input_or_output_iterator I >
constexpr void advance( I& i, std::iter_difference_t<I> n );
 (1) (C++20 起)
template< std::input_or_output_iterator I, std::sentinel_for<I> S >
constexpr void advance( I& i, S bound );
 (2) (C++20 起)
template< std::input_or_output_iterator I, std::sentinel_for<I> S >
constexpr std::iter_difference_t<I> advance( I& i, std::iter_difference_t<I> n, S bound );
 (3) (C++20 起)
1) 自增给定的迭代器 i n 次。
2) 自增给定的迭代器 i 直至 i == bound 。
3) 自增给定的迭代器 i n 次，或直至 i == bound ，取决于何者先来到。

若 n ，则自减迭代器。此情况下， I 必须实现 std::bidirectional_iterator ，而若提供 bound 则 S 必须与 I 为同一类型，否则行为未定义。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

i | - | 要推进的迭代器
bound | - | 指代 i 所指向的范围结尾的迭代器
n | - | i 应自增的次数

返回值

3) n 与 i 所遍历的实际距离的差。

复杂度

线性。

然而，若 I 额外实现 std::random_access_iterator ，或若 S 实现 std::sized_sentinel_for<I> ，或若 I 与 S 实现 std::assignable_from<I&, S> ，则复杂度为常数。

注解

若指定的自增或自减序列会要求自增不可自增的迭代器（例如尾后迭代器）或自减不可自减的迭代器（例如首迭代器或孤立迭代器）则行为未定义。

可能的实现

struct advance_fn {
  template<std::input_or_output_iterator I>
  constexpr void operator()(I& i, std::iter_difference_t<I> n) const
  {
    if constexpr (std::random_access_iterator<I>) {
        i += n;
    }
    else {
        while (n > 0) {
            --n;
            ++i;
        }
        if constexpr (std::bidirectional_iterator<I>) {
            while (n < 0) {
                ++n;
                --i;
            }
        }
    }
  }

  template<std::input_or_output_iterator I, std::sentinel_for<I> S>
  constexpr void operator()(I& i, S bound) const
  {
    if constexpr (std::assignable_from<I&, S>) {
        i = std::move(bound);
    }
    else if constexpr (std::sized_sentinel_for<S, I>) {
        ranges::advance(i, bound - i);
    }
    else {
        while (i != bound) {
            ++i;
        }
    }
  }

  template<std::input_or_output_iterator I, std::sentinel_for<I> S>
  constexpr std::iter_difference_t<I>
  operator()(I& i, std::iter_difference_t<I> n, S bound) const
  {
    if constexpr (std::sized_sentinel_for<S, I>) {
        // std::abs 非 constexpr
        auto abs = [](const std::iter_difference_t<I> x) { return x < 0 ? -x : x; };

        const auto dist = abs(n) - abs(bound - i);
        if (dist < 0) {
            ranges::advance(i, bound);
            return -dist;
        }

        ranges::advance(i, n);
        return 0;
    }
    else {
        while (n > 0 && i != bound) {
            --n;
            ++i;
        }

        if constexpr (std::bidirectional_iterator<I>) {
            while (n < 0 && i != bound) {
                ++n;
                --i;
            }
        }

        return n;
    }
  }
};

inline constexpr auto advance = advance_fn();

示例

#include <iomanip>
#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> v{ 3, 1, 4 };

    auto vi = v.begin();

    std::ranges::advance(vi, 2);
    std::cout << "value: " << *vi << '\n';

    {
        std::ranges::advance(vi, v.end());
        std::cout << std::boolalpha;
        std::cout << "vi == v.end(): " << (vi == v.end()) << '\n';

        std::ranges::advance(vi, -3);
        std::cout << "value: " << *vi << '\n';

        std::cout << "diff: " << std::ranges::advance(vi, 2, v.end()) << ", ";
        std::cout << "value: " << *vi << '\n';

        std::cout << "diff: " << std::ranges::advance(vi, 4, v.end()) << ", ";
        std::cout << "vi == v.end(): " << (vi == v.end()) << '\n';
        std::cout << std::noboolalpha;
    }
}

输出：

value: 4
vi == v.end(): true
value: 3
diff: 0, value: 4
diff: 3, vi == v.end(): true

参阅

ranges::next (C++20) | 自增迭代器给定的距离或到边界 (niebloid)
ranges::prev (C++20) | 自减迭代器给定的距离或到边界 (niebloid)
ranges::distance (C++20) | 返回迭代器与哨位间的距离，或范围起始与结尾间的距离 (niebloid)
advance | 令迭代器前进给定的距离 (函数模板)


std::ranges::distance

< cpp‎ | iterator
定义于头文件 <iterator>
调用签名
template< std::input_or_output_iterator I, std::sentinel_for<I> S >
constexpr std::iter_difference_t<I> distance( I first, S last );
 (1) (C++20 起)
template< ranges::range R>
constexpr ranges::range_difference_t<R> distance(R&& r);
 (2) (C++20 起)
1) 返回从 first 到 last 的自增次数。
2) 同 (1) ，但以 r 为源范围，若 R 实现 ranges::sized_range 则使用 ranges::size(r) ，否则如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first | - | 指向首元素的迭代器
last | - | 代表 first 所指向的范围结尾的哨位
r | - | 要计算距离的范围

返回值

需要从 first 到 last 的自增次数。若 I 与 S 为同一类型并实现 std::sized_sentinel_for<S, I> 而且 first 从 last 可达则值可为负。

复杂度

1) 若 S 实现 std::sized_sentinel_for<S, I> 则为常数，否则为线性。
2) 若 R 实现 ranges::sized_range 则为常数，否则同 (1) 。

可能的实现

struct distance_fn {
  template<std::input_or_output_iterator I, std::sentinel_for<I> S>
  constexpr std::iter_difference_t<I> operator()(I first, S last) const
  {
    if constexpr (std::sized_sentinel_for<S, I>) {
        return last - first;
    }
    else {
        std::iter_difference_t<I> result = 0;
        while (first != last) {
            ++first;
            ++result;
        }
        return result;
    }
  }

  template<ranges::range R>
  constexpr ranges::range_difference_t<R> operator()(R&& r) const
  {
    if constexpr (ranges::sized_range<std::remove_cvref_t<R>>) {
      return static_cast<ranges::range_difference_t<R>>(ranges::size(r));
    }
    else {
      return ranges::distance(ranges::begin(r), ranges::end(r));
    }
  }
};

inline constexpr auto distance = distance_fn{};

示例

#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> v{ 3, 1, 4 };
    namespace ranges = std::ranges;
    std::cout << "distance(first, last) = "
              << ranges::distance(v.begin(), v.end()) << '\n'
              << "distance(last, first) = "
              << ranges::distance(v.end(), v.begin()) << '\n'
              << "distance(v) = " << ranges::distance(v) << '\n';
}

输出：

distance(first, last) = 3
distance(last, first) = -3
distance(v) = 3

参阅

ranges::advance (C++20) | 令迭代器前进给定的距离或到给定的边界 (niebloid)
ranges::countranges::count_if (C++20)(C++20) | 返回满足指定判别标准的元素数 (niebloid)
distance | 返回两个迭代器间的距离 (函数模板)


std::ranges::iter_move

< cpp‎ | iterator
定义于头文件 <iterator>
inline namespace /*unspecified*/ {

inline constexpr /*unspecified*/ iter_move = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T >

requires /* see below */

constexpr decltype(auto) iter_move(T&& t) noexcept(/* see below */);

从给定的迭代器获得右值引用或纯右值临时对象。

调用 ranges::iter_move 表达式等价于：

  1. iter_move( std::forward <T>(t)) ，若 std::remove_cvref_t<T> 为类或枚举类型且该表达式在不求值语境为良构，其中以下列候选进行重载决议：
    • void iter_move();
    • 实参依赖查找所找到的任何 iter_move 声明。
  2. 否则为 std::move(* std::forward <T>(t)) ，若 * std::forward <T>(t) 良构且为左值，
  3. 否则为 * std::forward <T>(t) ，若 * std::forward <T>(t) 良构且为右值。

所有其他情况下，调用 ranges::iter_move 为谬构，这能在 ranges::iter_move(e) 出现于模板实例化的立即语境时导致替换失败。

若 ranges::iter_move(e) 不等于 *e ，则程序为谬构，不要求诊断。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::iter_move 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __iter_move_fn 表示其类型的 cv 无限定版本。

__iter_move_fn 的所有实例均相等。在相同参数上调用类型 __iter_move_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::iter_move 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::iter_move 的参数要求，则 __iter_move_fn 实现 std::invocable<__iter_move_fn, Args...>、 std::invocable<const __iter_move_fn, Args...>、 std::invocable<__iter_move_fn&, Args...> 及 std::invocable<const __iter_move_fn&, Args...> 。否则， __iter_move_fn 的函数调用运算符不参与重载决议。

参阅

iter_move (C++20) | 转型解引用调整后的底层迭代器的结果为其所关联的右值引用类型 (函数)
iter_move (C++20) | 转型解引用底层迭代器的结果为其所关联的右值引用类型 (函数)


std::ranges::iter_swap

< cpp‎ | iterator
定义于头文件 <iterator>
inline namespace /*unspecified*/ {

inline constexpr /*unspecified*/ iter_swap = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class I1, class I2 >

requires /* see below */

constexpr void iter_swap(I1&& i1, I2&& i2) noexcept(/* see below */);

交换二个迭代器所代表的值。

令 i1 与 i2 分别为 I1 与 I2 类型对象，调用 ranges::iter_swap 表达式等价于：

  1. (void)iter_swap( std::forward <I1>(i1), std::forward <I2>(i2)) ，若 std::remove_cvref_t<I1> 或 std::remove_cvref_t<I2> 为类或枚举类型，且该表达式在不求语境中为良构，其中以下列候选进行重载决议：
    • void iter_swap(auto, auto) = delete;
    • 实参依赖查找所找到的任何 iter_swap 声明。
    若选择的重载不交换 i1 与 i2, 的值，则程序为谬构，不要求诊断。
  2. 否则为 ranges::swap(* std::forward <I1>(i1), * std::forward <I2>(i2)) ，若 I1 与 I2 均实现 indirectly_readable 且若 std::iter_reference_t<I1> 与 std::iter_reference_t<I2> 实现 swappable_with 。
  3. 否则为 (void)(* std::forward <I1>(i1) = /*iter_exchange_move*/( std::forward <I2>(i2), std::forward <I1>(i1))) ，若 I1 与 I2 实现 std::indirectly_move_storable<I1, I2> 与 std::indirectly_move_storable<I2, I1> ，其中 iter_exchange_move 是描述于下的的仅用于阐释的函数模板。

所有其他情况下，调用 ranges::iter_swap 为谬构，这能 ranges::iter_swap(e1, e2) 在出现于模板实例化的立即语境时导致替换失败。

仅用于阐释的函数模板 iter_exchange_move 等价地定义为：

template<class X, class Y>
constexpr std::iter_value_t<X> /*iter_exchange_move*/(X&& x, Y&& y)
    noexcept(noexcept(std::iter_value_t<X>(std::move(x)) &&
             noexcept(*x = std::ranges::iter_move(y))))
{
    std::iter_value_t<X> old(std::ranges::iter_move(x));
    *x = std::ranges::iter_move(y);
    return old;
}

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::iter_swap 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __iter_swap_fn 表示其类型的 cv 无限定版本。

__iter_swap_fn 的所有实例均相等。在相同参数上调用类型 __iter_swap_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::iter_swap 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::iter_swap 的参数要求，则 __iter_swap_fn 实现 std::invocable<__iter_swap_fn, Args...>、 std::invocable<const __iter_swap_fn, Args...>、 std::invocable<__iter_swap_fn&, Args...> 及 std::invocable<const __iter_swap_fn&, Args...> 。否则， __iter_swap_fn 的函数调用运算符不参与重载决议。

参阅

iter_swap (C++20) | 交换二个调整后的底层迭代器所指向的对象 (函数模板)
iter_swap (C++20) | 交换二个底层迭代器所指向的对象 (函数模板)
iter_swap | 交换两个迭代器所指向的元素 (函数模板)


std::ranges::next

< cpp‎ | iterator
定义于头文件 <iterator>
调用签名
template< std::input_or_output_iterator I >
constexpr I next( I x );
 (1) (C++20 起)
template< std::input_or_output_iterator I >
constexpr I next( I x, std::iter_difference_t<I> n );
 (2) (C++20 起)
template< std::input_or_output_iterator I, std::sentinel_for<I> S >
constexpr I next( I x, std::iter_difference_t<I> n, S bound );
 (3) (C++20 起)

返回迭代器 i 的第 n 个后继。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

i | - | 迭代器
n | - | 要自增的次数
bound | - | 指代 i 所指向的范围结尾的哨位

返回值

1) 迭代器 i 的后继
2) 迭代器 i 的第 n 个后继
3) 迭代器 i 的第 n 个后继，或首个等于 bound 的迭代器，取决于何者先来到。

复杂度

1) 常数
2) 若 I 实现 std::random_access_iterator 则为常数；否则为线性。
3) 若 I 与 S 实现 std::random_access_iterator<I> 和 std::sized_sentinel_for<S, I> 则为常数；否则为线性。

可能的实现

struct next_fn {
  template<std::input_or_output_iterator I>
  constexpr I operator()(I i) const
  {
    return ++i;
  }

  template< std::input_or_output_iterator I >
  constexpr I operator()(I i, std::iter_difference_t<I> n) const
  {
    ranges::advance(i, n);
    return i;
  }

  template<std::input_or_output_iterator I, std::sentinel_for<I> S>
  constexpr I operator()(I i, std::iter_difference_t<I> n, I bound) const
  {
    ranges::advance(i, n, bound);
    return i;
  }
};

inline constexpr auto next = next_fn();

注解

尽管表达式 ++x.begin() 经常能编译，但不保证如此： x.begin() 是右值表达式，而没有要求指定右值的自增保证能工作。尤其是迭代器实现为指针或其 operator++ 为左值引用限定时， ++x.begin() 不能编译，而 ranges::next(x.begin()) 能。

示例

#include <iomanip>
#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> v{ 3, 1, 4 };
    {
        auto n = std::ranges::next(v.begin());
        std::cout << *n << '\n';
    }
    {
        auto n = std::ranges::next(v.begin(), 2);
        std::cout << *n << '\n';
    }
    {
        auto n = std::ranges::next(v.begin(), 42, v.end());
        std::cout << std::boolalpha;
        std::cout << (n == v.end()) << '\n';
        std::cout << std::noboolalpha;
    }
}

输出：

1
4
true

参阅

ranges::prev (C++20) | 自减迭代器给定的距离或到边界 (niebloid)
ranges::advance (C++20) | 令迭代器前进给定的距离或到给定的边界 (niebloid)
next (C++11) | 令迭代器自增 (函数模板)


std::ranges::prev

< cpp‎ | iterator
定义于头文件 <iterator>
调用签名
template< std::bidirectional_iterator I >
constexpr I prev( I i );
 (1) (C++20 起)
template< std::bidirectional_iterator I >
constexpr I prev( I i, std::iter_difference_t<I> n );
 (2) (C++20 起)
template< std::bidirectional_iterator I >
constexpr I prev( I i, std::iter_difference_t<I> n, I bound );
 (3) (C++20 起)

返回迭代器 i 的第 n 个前驱。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

i | - | 迭代器
n | - | 要减少 i 的次数
bound | - | 代表 i 所指向的范围的起始的迭代器

返回值

1) i 的前驱
2) 迭代器 i 的第 n 个前驱
3) 迭代器 i 的第 n 个前驱，或首个比较等于 bound 的迭代器，取决于何者先来到。

复杂度

1) 常数
2,3) 若 I 实现 std::random_access_iterator<I> 则为常数；否则为线性。

可能的实现

struct prev_fn {
  template<std::bidirectional_iterator I>
  constexpr I operator()(I i) const
  {
    return --i;
  }

  template< std::bidirectional_iterator I >
  constexpr I operator()(I i, std::iter_difference_t<I> n) const
  {
    ranges::advance(i, -n);
    return i;
  }

  template<std::bidirectional_iterator I>
  constexpr I operator()(I i, std::iter_difference_t<I> n, I bound) const
  {
    ranges::advance(i, -n, bound);
    return i;
  }
};

inline constexpr auto prev = prev_fn();

注解

尽管对于容器，表达式 --r.end() 经常能编译，但不保证如此： r.end() 是右值表达式，而无迭代器要求指定右值的自减保证可用。尤其是迭代器实现为指针或其 operator-- 为左值引用限定时， --r.end() 不能编译，而 ranges::prev(r.end()) 能。

不实现 ranges::common_range 的范围加剧了这一情况。例如对于某些底层类型， ranges::transform_view::end 与 ranges::transform_view::begin 拥有不同的返回类型，故 --r.end() 将不能编译。此非 ranges::prev 所能帮助，但有变通方法。

示例

#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> v{ 3, 1, 4 };
    auto pv = std::ranges::prev(v.end(), 2);
    std::cout << *pv << '\n';

    pv = std::ranges::prev(pv, 42, v.begin());
    std::cout << *pv << '\n';
}

输出：

1
3

参阅

ranges::next (C++20) | 自增迭代器给定的距离或到边界 (niebloid)
ranges::advance (C++20) | 令迭代器前进给定的距离或到给定的边界 (niebloid)
prev (C++11) | 令迭代器自减 (函数模板)


std::rbegin, std::crbegin

< cpp‎ | iterator
定义于头文件 <array>
定义于头文件 <deque>
定义于头文件 <forward_list>
定义于头文件 <iterator>
定义于头文件 <list>
定义于头文件 <map>
定义于头文件 <regex>
定义于头文件 <set>
定义于头文件 <span>
(C++20 起)
定义于头文件 <string>
定义于头文件 <string_view>
(C++17 起)
定义于头文件 <unordered_map>
定义于头文件 <unordered_set>
定义于头文件 <vector>
(1)
template< class C >
auto rbegin( C& c ) -> decltype(c.rbegin());
 (C++14 起)
(C++17 前)
template< class C >
constexpr auto rbegin( C& c ) -> decltype(c.rbegin());
 (C++17 起)
(1)
template< class C >
auto rbegin( const C& c ) -> decltype(c.rbegin());
 (C++14 起)
(C++17 前)
template< class C >
constexpr auto rbegin( const C& c ) -> decltype(c.rbegin());
 (C++17 起)
(2)
template< class T, std::size_t N >
std::reverse_iterator <T*> rbegin( T (&array)[N] );
 (C++14 起)
(C++17 前)
template< class T, std::size_t N >
constexpr std::reverse_iterator <T*> rbegin( T (&array)[N] );
 (C++17 起)
(3)
template< class T >
std::reverse_iterator <const T*> rbegin( std::initializer_list <T> il );
 (C++14 起)
(C++17 前)
template< class T >
constexpr std::reverse_iterator <const T*> rbegin( std::initializer_list <T> il);
 (C++17 起)
(4)
template< class C >
auto crbegin( const C& c ) -> decltype(std::rbegin(c));
 (C++14 起)
(C++17 前)
template< class C >
constexpr auto crbegin( const C& c ) -> decltype(std::rbegin(c));
 (C++17 起)

返回指向给定范围逆向起始的迭代器。

1) 返回指向可能有 const 限定的容器或视图 c 逆向起始的迭代器。
2) 返回指向数组 array 逆向起始的 std::reverse_iterator <T*> 。
3) 返回指向 const 限定的容器或视图 c 逆向起始的迭代器。

参数

c | - | 拥有 rbegin 方法的容器
array | - | 任意类型的数组
il | - | initializer_list

返回值

1) c.rbegin()
2) std::reverse_iterator <T*>(array + N)
3) std::reverse_iterator <const T*>(il.end())
4) c.rbegin()

异常

可能抛出实现定义的异常。

重载

可以为未暴露适合的 rbegin() 成员函数的类或枚举提供 rbegin 的自定义重载，使之亦能迭代。

实参依赖查找所找到的 rbegin 重载能用于定制 std::ranges::rbegin 与 std::ranges::crbegin 的行为。

 (C++20 起)

注解

需要对 std::initializer_list 的重载，因为它无成员函数 rbegin 。

示例

#include <iostream>
#include <vector>
#include <iterator>

int main()
{
    std::vector<int> v = { 3, 1, 4 };
    auto vi = std::rbegin(v);
    std::cout << *vi << '\n';

    int a[] = { -5, 10, 15 };
    auto ai = std::rbegin(a);
    std::cout << *ai << '\n';

    auto il = { 3, 1, 4 };
    for (auto it = std::rbegin(il); it != std::rend(il); ++it)
        std::cout << *it << ' ';
}

输出：

4
15
4 1 3

参阅

begincbegin (C++11)(C++14) | 返回指向容器或数组起始的迭代器 (函数模板)
endcend (C++11)(C++14) | 返回指向容器或数组结尾的迭代器 (函数模板)
rendcrend (C++14) | 返回容器或数组的逆向尾迭代器 (函数模板)
ranges::rbegin (C++20) | 返回指向范围的逆向迭代器 (定制点对象)
ranges::crbegin (C++20) | 返回指向只读范围的逆向迭代器 (定制点对象)


std::rend, std::crend

< cpp‎ | iterator
定义于头文件 <array>
定义于头文件 <deque>
定义于头文件 <forward_list>
定义于头文件 <iterator>
定义于头文件 <list>
定义于头文件 <map>
定义于头文件 <regex>
定义于头文件 <set>
定义于头文件 <span>
(C++20 起)
定义于头文件 <string>
定义于头文件 <string_view>
(C++17 起)
定义于头文件 <unordered_map>
定义于头文件 <unordered_set>
定义于头文件 <vector>
(1)
template< class C >
auto rend( C& c ) -> decltype(c.rend());
 (C++14 起)
(C++17 前)
template< class C >
constexpr auto rend( C& c ) -> decltype(c.rend());
 (C++17 起)
(1)
template< class C >
auto rend( const C& c ) -> decltype(c.rend());
 (C++14 起)
(C++17 前)
template< class C >
constexpr auto rend( const C& c ) -> decltype(c.rend());
 (C++17 起)
(2)
template< class T, std::size_t N >
std::reverse_iterator <T*> rend( T (&array)[N] );
 (C++14 起)
(C++17 前)
template< class T, std::size_t N >
constexpr std::reverse_iterator <T*> rend( T (&array)[N] );
 (C++17 起)
(3)
template< class T >
std::reverse_iterator <const T*> rend( std::initializer_list <T> il );
 (C++14 起)
(C++17 前)
template< class T >
constexpr std::reverse_iterator <const T*> rend( std::initializer_list <T> il );
 (C++17 起)
(4)
template< class C >
auto crend( const C& c ) -> decltype(std::rend(c));
 (C++14 起)
(C++17 前)
template< class C >
constexpr auto crend( const C& c ) -> decltype(std::rend(c));
 (C++17 起)

返回值向给定范围逆向结尾的迭代器。

1) 返回指向可能有 const 限定的容器或视图 c 的逆向结尾的迭代器。
2) 返回指向数组 array 逆向结尾的 std::reverse_iterator <T*> 。
2) 返回指向 std::initializer_list il 逆向结尾的 std::reverse_iterator <const T*> 。
3) 返回指向 const 限定的容器或视图 c 逆向结尾的迭代器。

参数

c | - | 拥有 rend 成员函数的容器或视图
array | - | 任意类型的数组
il | - | initializer_list

返回值

1) c.rend()
2) std::reverse_iterator <T*>(array)
3) std::reverse_iterator <const T*>(il.begin())
4) c.rend()

异常

可能抛出实现定义的异常。

重载

可对不暴露适合的 rend() 成员函数的类或枚举提供 rend 的定制重载，从而能迭代它们。

实参依赖查找所找到的 rend 重载能用于定制 std::ranges::rend 与 std::ranges::crend 的行为。

 (C++20 起)

注解

需要对 std::initializer_list 的重载，因为它无成员函数 rend 。

示例

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

int main()
{
    int a[] = {4, 6, -3, 9, 10};
    std::cout << "Array backwards: ";
    std::copy(std::rbegin(a), std::rend(a), std::ostream_iterator<int>(std::cout, " "));

    auto il = { 3, 1, 4 };
    std::cout << "\nstd::initializer_list backwards: ";
    std::copy(std::rbegin(il), std::rend(il), std::ostream_iterator<int>(std::cout, " "));

    std::cout << "\nVector backwards: ";
    std::vector<int> v = {4, 6, -3, 9, 10};
    std::copy(std::rbegin(v), std::rend(v), std::ostream_iterator<int>(std::cout, " "));
}

输出：

Array backwards: 10 9 -3 6 4
std::initializer_list backwards: 4 1 3
Vector backwards: 10 9 -3 6 4

参阅

endcend (C++11)(C++14) | 返回指向容器或数组结尾的迭代器 (函数模板)
rbegincrbegin (C++14) | 返回指向一个容器或数组的逆向迭代器 (函数模板)
begincbegin (C++11)(C++14) | 返回指向容器或数组起始的迭代器 (函数模板)
ranges::rend (C++20) | 返回指向范围的逆向尾迭代器 (定制点对象)
ranges::crend (C++20) | 返回指向只读范围的逆向尾迭代器 (定制点对象)


std::reverse_iterator

< cpp‎ | iterator
定义于头文件 <iterator>
template< class Iter >

class reverse_iterator : public std::iterator <
typename std::iterator_traits <Iter>::iterator_category,
typename std::iterator_traits <Iter>::value_type,
typename std::iterator_traits <Iter>::difference_type,
typename std::iterator_traits <Iter>::pointer,

typename std::iterator_traits <Iter>::reference >
 (C++17 前)
template< class Iter >
class reverse_iterator;
 (C++17 起)

std::reverse_iterator 是一个反转给定必须至少是老式双向迭代器 (LegacyBidirectionalIterator) 或实现 bidirectional_iterator (C++20 起)的迭代器方向的适配器。换言之，提供双向迭代器时， std::reverse_iterator 产生一个新的迭代器，它从底层的双向迭代器所定义的序列的末尾移动到开端。

对于从迭代器 i 构造的 r 逆向迭代器，关系 &*r == &*(i-1) 始终为 true （只要 r 可解引用）；从而构造自末尾后一位置的迭代器的逆向迭代器解引用到序列的最后元素。

这是标准库容器的成员函数 rbegin() 及 rend() 所返回的迭代器。

成员类型

成员类型 | 定义
iterator_type | Iter
iterator_concept(C++20) | 若 Iter 实现 std::random_access_iterator ，则为 std::random_access_iterator_tag 。否则为 std::bidirectional_iterator_tag
iterator_category
std::iterator_traits <Iter>::iterator_category | (C++20 前)
若 std::iterator_traits <Iter>::iterator_category 实现 std::derived_from< std::random_access_iterator_tag > ，则为 std::random_access_iterator_tag 。否则为不更改的 std::iterator_traits <Iter>::iterator_category | (C++20 起)
value_type
std::iterator_traits <Iter>::value_type | (C++20 前)
std::iter_value_t<Iter> | (C++20 起)
difference_type
std::iterator_traits <Iter>::difference_type | (C++20 前)
std::iter_difference_t<Iter> | (C++20 起)
pointer | std::iterator_traits <Iter>::pointer
reference
std::iterator_traits <Iter>::reference | (C++20 前)
std::iter_reference_t<Iter> | (C++20 起)

要求通过从 std::iterator < std::iterator_traits <Iter>::iterator_category
, std::iterator_traits <Iter>::value_type
, std::iterator_traits <Iter>::difference_type
, std::iterator_traits <Iter>::pointer
, std::iterator_traits <Iter>::reference
> 继承获得成员类型 iterator_category 、 value_type 、 difference_type 、 pointer 及 reference 。

 (C++17 前)

成员函数

(构造函数) | 构造新的迭代器适配器 (公开成员函数)
operator= | 赋值另一迭代器适配器 (公开成员函数)
base | 访问底层迭代器 (公开成员函数)
operator*operator-> | 访问被指向的元素 (公开成员函数)
operator[] | 按索引访问元素 (公开成员函数)
operator++operator++(int)operator+=operator+operator--operator--(int)operator-=operator- | 推进或回退迭代器 (公开成员函数)

成员对象

成员名称 | 定义
current (受保护成员对象) | base() 返回其副本的底层迭代器

非成员函数

make_reverse_iterator (C++14) | 创建拥有从实参推出的类型的 std::reverse_iterator (函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20) | 比较底层迭代器 (函数模板)
operator+ | 令迭代器前进 (函数模板)
operator- | 计算两个迭代器适配器间的距离 (函数模板)
iter_move (C++20) | 转型解引用调整后的底层迭代器的结果为其所关联的右值引用类型 (函数)
iter_swap (C++20) | 交换二个调整后的底层迭代器所指向的对象 (函数模板)

辅助模板

template< class Iterator1, class Iterator2 >

requires (!std::sized_sentinal_for<Iterator1, Iterator2>)
inline constexpr bool disable_sized_sentinel_for<
std::reverse_iterator<Iterator1>,

std::reverse_iterator<Iterator2>> = true;
 (C++20 起)

若 reverse_iterator 的特化的底层迭代器不满足 sized_sentinel_for ，则 std::disable_sentinel_for 的此偏特化阻止这些特化满足该概念。

注解

std::reverse_iterator 不可作用于解引用返回到 *this 成员的迭代器（是谓“贮藏迭代器”）。贮藏迭代器的一个例子是 std::filesystem::path::iterator 。

示例

#include <iostream>
#include <string>
#include <iterator>

int main()
{
    std::string s = "Hello, world";
    std::reverse_iterator<std::string::iterator> r = s.rbegin();
    r[7] = 'O'; // 以 'O' 替换 'o'
    r += 7; // 迭代器现在指向 'O'
    std::string rev(r, s.rend());
    std::cout << rev << '\n';
}

输出：

OlleH

参阅

iterator
(C++17 中弃用)
 用于简化简单的迭代器的必要类型定义的基类
(类模板)


std::reverse_iterator<Iter>::base

< cpp‎ | iterator‎ | reverse iterator
iterator_type base() const; | (C++17 前)
constexpr iterator_type base() const; | (C++17 起)

返回底层迭代器。即 std::reverse_iterator (it).base() == it 。

底层迭代器指代（相对于 std::reverse_iterator::iterator_type 的） reverse_iterator 当前所指元素的下一个元素。即 &*(rit.base() - 1) == &*rit 。

参数

（无）

返回值

底层迭代器。

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <iterator>
#include <vector>

int main()
{
  std::vector<int> v = { 0, 1, 2, 3, 4, 5 };

  using RevIt = std::reverse_iterator<std::vector<int>::iterator>;
  {
    const auto it = v.begin() + 3;
    RevIt r_it(it);

    std::cout << "*it == " << *it << ", *r_it.base() == " << *r_it.base()
    << '\n' << "*r_it == " << *r_it <<", *(r_it.base()-1) == " << *(r_it.base()-1) << "\n";
  }
  {
    RevIt r_end(v.begin());
    RevIt r_begin(v.end());

    for (auto it = r_end.base(); it != r_begin.base(); ++it) {
      std::cout << *it << " ";
    }
    std::cout << "\n";
  }
}

输出：

*it == 3, *r_it.base() == 3
*r_it == 2, *(r_it.base()-1) == 2
0 1 2 3 4 5

参阅

operator*operator->
 访问被指向的元素
(公开成员函数)


std::iter_move(std::reverse_iterator)

< cpp‎ | iterator‎ | reverse iterator
friend constexpr std::iter_rvalue_reference_t<Iter>
iter_move( const std::reverse_iterator & i ) noexcept(/* see below */);
 (C++20 起)

转型解引用调节后的底层迭代器的结果到其关联的右值引用类型。

函数体等价于：

auto tmp = i.base();
return std::ranges::iter_move(--tmp);

此函数模板对通常无限定或有限定查找不可见，而只能在 std::reverse_iterator<Iter> 为参数的关联类时由实参依赖查找找到。

参数

i - 源逆向迭代器。

返回值

右值引用或纯右值临时量。

复杂度

常数。

异常

noexcept 说明：
noexcept(

std::is_nothrow_copy_constructible_v <Iter> &&
noexcept(std::ranges::iter_move(-- std::declval <Iter&>()))

)

示例

#include <iomanip>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

void print(auto const& rem, auto const& v) {
    for (std::cout << rem << "[" << size(v) << "] { "; auto const& s : v)
        std::cout << quoted(s) << " ";
    std::cout << "}\n";
}

int main()
{
    std::vector<std::string> p { "Alpha", "Bravo", "Charlie" }, q;

    print("p", p), print("q", q);

    using RI = std::reverse_iterator<std::vector<std::string>::iterator>;

    for (RI iter{ p.rbegin() }, rend{ p.rend() }; iter != rend; ++iter) {
        q.emplace_back( /* ADL */ iter_move(iter) );
    }

    print("p", p), print("q", q);
}

可能的输出：

p[3] { "Alpha" "Bravo" "Charlie" }
q[0] { }
p[3] { "" "" "" }
q[3] { "Charlie" "Bravo" "Alpha" }

参阅

iter_move (C++20) | 将解引用迭代器的结果转型为其关联的右值引用类型 (定制点对象)
iter_move (C++20) | 转型解引用底层迭代器的结果为其所关联的右值引用类型 (函数)
move (C++11) | 获得右值引用 (函数模板)
move_if_noexcept (C++11) | 若移动构造函数不抛出则获得右值引用 (函数模板)
forward (C++11) | 转发一个函数实参 (函数模板)
ranges::move (C++20) | 将某一范围的元素移动到一个新的位置 (niebloid)
ranges::move_backword (C++20) | 按从后往前的顺序移动某一范围的元素到新的位置 (niebloid)


std::iter_swap(std::reverse_iterator)

< cpp‎ | iterator‎ | reverse iterator
template< std::indirectly_swappable<Iter> Iter2 > friend constexpr void iter_swap( const reverse_iterator& x, const std::reverse_iterator <Iter2>& y ) noexcept(/*see below*/); | (C++20 起)

交换二个调整的迭代器所指向的元素。函数体等价于：

auto tmp_x = x.base();
auto tmp_y = y.base();
ranges::iter_swap(--tmp_x, --tmp_y);

此函数模板对通常无限定或有限定查找不可见，而只能在 std::reverse_iterator<Iter> 为参数的关联类时由实参依赖查找找到。

参数

x, y - 要交换元素的逆向迭代器

返回值

（无）

复杂度

常数

异常

noexcept 说明：
noexcept(

std::is_nothrow_copy_constructible_v <Iter> &&
std::is_nothrow_copy_constructible_v <Iter2> &&
noexcept(ranges::iter_swap(-- std::declval <Iter&>(), -- std::declval <Iter2&>()))

)

示例

#include <iostream>
#include <iterator>
#include <list>
#include <vector>

int main()
{
    std::vector v {1, 2, 3};
    std::list   l {4, 5, 6};

    std::reverse_iterator<std::vector<int>::iterator> r1 { v.rbegin() };
    std::reverse_iterator<std::list<int>::iterator>   r2 { l.rbegin() };

    std::cout << *r1 << ' ' << *r2 << '\n';

    iter_swap(r1, r2);

    std::cout << *r1 << ' ' << *r2 << '\n';
}

输出：

3 6
6 3

参阅

swap | 交换两个对象的值 (函数模板)
swap_ranges | 交换两个范围的元素 (函数模板)
iter_swap | 交换两个迭代器所指向的元素 (函数模板)
iter_swap (C++20) | 交换两个可解引用对象所引用的值 (定制点对象)
iter_swap (C++20) | 交换二个底层迭代器所指向的对象 (函数模板)


std::reverse_iterator<Iter>::operator*,->

< cpp‎ | iterator‎ | reverse iterator
(1)
reference operator*() const;
 (C++17 前)
constexpr reference operator*() const;
 (C++17 起)
(2)
pointer operator->() const;
 (C++17 前)
constexpr pointer operator->() const;
 (C++17 起)
(C++20 前)
constexpr pointer operator->() const

requires ( std::is_pointer_v <Iter> ||

requires (const Iter i) { i.operator->(); });
 (C++20 起)

返回指向 current 前一元素的引用或指针。

1) 等价于 Iter tmp = current; return *--tmp; 。
2) 等价于 return std::addressof (operator*()); 。 | (C++20 前)
2) 若 Iter 为指针类型则等价于 return current - 1; 。否则等价于 return std::prev (current).operator->(); 。 | (C++20 起)

参数

（无）

返回值

指向 current 前一元素的引用或指针。

示例

本节未完成
原因：暂无示例

参阅

operator[]
 按索引访问元素
(公开成员函数)


operator+(std::reverse_iterator)

< cpp‎ | iterator‎ | reverse iterator

定义于头文件 <iterator> |
template< class Iter > reverse_iterator<Iter> operator+( typename reverse_iterator<Iter>::difference_type n, const reverse_iterator<Iter>& it ); | (C++17 前)
template< class Iter > constexpr reverse_iterator<Iter> operator+( typename reverse_iterator<Iter>::difference_type n, const reverse_iterator<Iter>& it ); | (C++17 起)

返回增加了 n 的 it 。

参数

n | - | 增加迭代器所用的位置数
it | - | 要增加的迭代器适配器

返回值

增加的迭代器，即 reverse_iterator<Iter>(it.base() - n)

示例

#include <iostream>
#include <iterator>
#include <list>
#include <vector>

int main()
{
    {
        std::vector v {0, 1, 2, 3};
        std::reverse_iterator<std::vector<int>::iterator>
            ri1 { std::reverse_iterator{ v.rbegin() } };
        std::cout << *ri1 << ' '; // 3
        std::reverse_iterator<std::vector<int>::iterator> ri2 { 2 + ri1 };
        std::cout << *ri2 << ' '; // 1
    }
    {
        std::list l {5, 6, 7, 8};
        std::reverse_iterator<std::list<int>::iterator>
            ri1{ std::reverse_iterator{ l.rbegin() } };
        std::cout << *ri1 << '\n'; // 8
    //  auto ri2 { 2 + ri1 }; // 错误：底层迭代器不实现随机访问迭代器
    }
}

输出：

3 1 8

参阅

operator++operator++(int)operator+=operator+operator--operator--(int)operator-=operator-
 推进或回退迭代器
(公开成员函数)


operator-(std::reverse_iterator)

< cpp‎ | iterator‎ | reverse iterator

template< class Iterator > typename reverse_iterator<Iterator>::difference_type operator-( const reverse_iterator<Iterator>& lhs, const reverse_iterator<Iterator>& rhs ); | (C++11 前)
template< class Iterator1, class Iterator2 > auto operator-( const reverse_iterator<Iterator1>& lhs, const reverse_iterator<Iterator2>& rhs ) -> decltype(rhs.base() - lhs.base()); | (C++11 起) (C++17 前)
template< class Iterator1, class Iterator2 > constexpr auto operator-( const reverse_iterator<Iterator1>& lhs, const reverse_iterator<Iterator2>& rhs ) -> decltype(rhs.base() - lhs.base()); | (C++17 起)

返回二个迭代器适配器间的距离。

参数

lhs, rhs - 要计算距离的迭代器适配器

返回值

rhs.base() - lhs.base()

示例

本节未完成
原因：暂无示例


std::reverse_iterator<Iter>::operator=

< cpp‎ | iterator‎ | reverse iterator

template< class U > reverse_iterator& operator=( const reverse_iterator<U>& other ); | (C++17 前)
template< class U > constexpr reverse_iterator& operator=( const reverse_iterator<U>& other ); | (C++17 起)

对底层迭代器赋 other 的底层迭代器的值，即 other.base() 。

此重载仅若 U 与 Iter 不是同一类型且 std::convertible_to<const U&, Iter> 与 std::assignable_from<Iter&, const U&> 均得到实现才参与重载决议。

 (C++20 起)

参数

other - 要赋值的迭代器适配器

返回值

*this

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3435 | C++20 | 转换赋值运算符未受约束 | 已约束

参阅

(构造函数)
 构造新的迭代器适配器
(公开成员函数)


std::reverse_iterator<Iter>::operator++,+,+=,--,-,-=

< cpp‎ | iterator‎ | reverse iterator

 | (1)
reverse_iterator& operator++(); |  | (C++17 前)
constexpr reverse_iterator& operator++(); |  | (C++17 起)
 | (2)
reverse_iterator& operator--(); |  | (C++17 前)
constexpr reverse_iterator& operator--(); |  | (C++17 起)
 | (3)
reverse_iterator operator++( int ); |  | (C++17 前)
constexpr reverse_iterator operator++( int ); |  | (C++17 起)
 | (4)
reverse_iterator operator--( int ); |  | (C++17 前)
constexpr reverse_iterator operator--( int ); |  | (C++17 起)
 | (5)
reverse_iterator operator+( difference_type n ) const; |  | (C++17 前)
constexpr reverse_iterator operator+( difference_type n ) const; |  | (C++17 起)
 | (6)
reverse_iterator operator-( difference_type n ) const; |  | (C++17 前)
constexpr reverse_iterator operator-( difference_type n ) const; |  | (C++17 起)
 | (7)
reverse_iterator& operator+=( difference_type n ); |  | (C++17 前)
constexpr reverse_iterator& operator+=( difference_type n ); |  | (C++17 起)
 | (8)
reverse_iterator& operator-=( difference_type n ); |  | (C++17 前)
constexpr reverse_iterator& operator-=( difference_type n ); |  | (C++17 起)

自增或自减迭代器。应用逆运算到底层迭代器，因为逆序。

1-2) 分别前自增或前自减一。
3-4) 分别后自增或后自减一。
5-6) 分别返回前进 n 或 -n 个位置的迭代器。
7-8) 分别令迭代器前进 n 或 -n 个位置。

返回值

1-2) *this
3-4) *this 修改前的副本。
5-6) 分别为 reverse_iterator(base()-n) 或 reverse_iterator(base()+n) 。
7-8) *this

示例

本节未完成
原因：暂无示例

参阅

operator+
 令迭代器前进
(函数模板)


std::reverse_iterator<Iter>::operator[]

< cpp‎ | iterator‎ | reverse iterator

/*unspecified*/ operator[]( difference_type n ) const; | (C++17 前)
constexpr /*unspecified*/ operator[]( difference_type n ) const; | (C++17 起)

返回在指定相相对位置的引用。

参数

n - 相对于当前位置的位置。

返回值

到在相对位置的元素的引用，即 base()[-n-1] 。

示例

#include <array>
#include <cstddef>
#include <iostream>
#include <iterator>
#include <list>
#include <vector>

int main()
{
    {
        int a[]{0, 1, 2, 3};
        std::reverse_iterator<int*> iter{std::rbegin(a)};
        for (std::size_t i{}; i != std::size(a); ++i)
            std::cout << iter[i] << ' '; // decltype(iter[i]) 为 `int&`
        std::cout << '\n';
    }
    {
        std::vector v{0, 1, 2, 3};
        std::reverse_iterator<std::vector<int>::iterator> iter{std::rbegin(v)};
        for (std::size_t i{}; i != std::size(v); ++i)
            std::cout << iter[i] << ' '; // decltype(iter[i]) 为 `int&`
        std::cout << '\n';
    }
    {
        // constexpr context
        constexpr static std::array<int, 4> z{0, 1, 2, 3};
        constexpr std::reverse_iterator<decltype(z)::const_iterator> it{std::crbegin(z)};
        static_assert(it[1] == 2);
    }
    {
        std::list li{0, 1, 2, 3};
        std::reverse_iterator<std::list<int>::iterator> iter{std::rbegin(li)};
        *iter = 42; // OK
    //  iter[0] = 13; // 编译错误 ~ 底层迭代器不实现随机访问迭代器
    }
}

输出：

3 2 1 0
3 2 1 0

参阅

operator*operator->
 访问被指向的元素
(公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::reverse_iterator)

< cpp‎ | iterator‎ | reverse iterator

(1)
template< class Iterator1, class Iterator2 >

bool operator==( const std::reverse_iterator <Iterator1>& lhs,

const std::reverse_iterator <Iterator2>& rhs );
 (C++17 前)
template< class Iterator1, class Iterator2 >

constexpr bool operator==( const std::reverse_iterator <Iterator1>& lhs,

const std::reverse_iterator <Iterator2>& rhs );
 (C++17 起)
(2)
template< class Iterator1, class Iterator2 >

bool operator!=( const std::reverse_iterator <Iterator1>& lhs,

const std::reverse_iterator <Iterator2>& rhs );
 (C++17 前)
template< class Iterator1, class Iterator2 >

constexpr bool operator!=( const std::reverse_iterator <Iterator1>& lhs,

const std::reverse_iterator <Iterator2>& rhs );
 (C++17 起)
(3)
template< class Iterator1, class Iterator2 >

bool operator<( const std::reverse_iterator <Iterator1>& lhs,

const std::reverse_iterator <Iterator2>& rhs );
 (C++17 前)
template< class Iterator1, class Iterator2 >

constexpr bool operator<( const std::reverse_iterator <Iterator1>& lhs,

const std::reverse_iterator <Iterator2>& rhs );
 (C++17 起)
(4)
template< class Iterator1, class Iterator2 >

bool operator<=( const std::reverse_iterator <Iterator1>& lhs,

const std::reverse_iterator <Iterator2>& rhs );
 (C++17 前)
template< class Iterator1, class Iterator2 >

constexpr bool operator<=( const std::reverse_iterator <Iterator1>& lhs,

const std::reverse_iterator <Iterator2>& rhs );
 (C++17 起)
(5)
template< class Iterator1, class Iterator2 >

bool operator>( const std::reverse_iterator <Iterator1>& lhs,

const std::reverse_iterator <Iterator2>& rhs );
 (C++17 前)
template< class Iterator1, class Iterator2 >

constexpr bool operator>( const std::reverse_iterator <Iterator1>& lhs,

const std::reverse_iterator <Iterator2>& rhs );
 (C++17 起)
(6)
template< class Iterator1, class Iterator2 >

bool operator>=( const std::reverse_iterator <Iterator1>& lhs,

const std::reverse_iterator <Iterator2>& rhs );
 (C++17 前)
template< class Iterator1, class Iterator2 >

constexpr bool operator>=( const std::reverse_iterator <Iterator1>& lhs,

const std::reverse_iterator <Iterator2>& rhs );
 (C++17 起)
template<class Iterator1, std::three_way_comparable_with<Iterator1> Iterator2>

constexpr std::compare_three_way_result_t<Iterator1, Iterator2>
operator<=>( const std::reverse_iterator <Iterator1>& x,

const std::reverse_iterator <Iterator2>& y );
 (7) (C++20 起)

比较底层迭代器。考虑到迭代器顺序是逆向的，而应用逆向比较。

(1-6) 仅若其底层比较表达式（见后述）为良构且可转换为 bool 才参与重载决议。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的迭代器适配器

返回值

1) lhs.base() == rhs.base()
2) lhs.base() != rhs.base()
3) lhs.base() > rhs.base()
4) lhs.base() >= rhs.base()
5) lhs.base() < rhs.base()
6) lhs.base() <= rhs.base()
7) rhs.base() <=> lhs.base()

示例

本节未完成
原因：暂无示例


std::reverse_iterator<Iter>::reverse_iterator

< cpp‎ | iterator‎ | reverse iterator

 | (1)
reverse_iterator(); |  | (C++17 前)
constexpr reverse_iterator(); |  | (C++17 起)
 | (2)
explicit reverse_iterator( iterator_type x ); |  | (C++17 前)
constexpr explicit reverse_iterator( iterator_type x ); |  | (C++17 起)
 | (3)
template< class U > reverse_iterator( const reverse_iterator<U>& other ); |  | (C++17 前)
template< class U > constexpr reverse_iterator( const reverse_iterator<U>& other ); |  | (C++17 起)

构造新的迭代器适配器。

1) 默认构造函数。值初始化底层迭代器。若且唯若值初始化的底层迭代器有受定义行为，产生的迭代器上的操作才一样有受定义行为。
2) 以 x 初始化底层迭代器。
3) 以 other 的底层迭代器初始化底层迭代器。此重载仅若 U 与 Iter 不是同一类型且 std::convertible_to<const U&, Iter> 得到实现才参与重载决议 (C++20 起)。

参数

x | - | 要适配的迭代器
other | - | 要复制的迭代器适配器

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3435 | C++20 | 源自另一 reverse_iterator 的转换构造函数未受约束 | 已约束

参阅

operator=
 赋值另一迭代器适配器
(公开成员函数)


std::sentinel_for

< cpp‎ | iterator
定义于头文件 <iterator>
template<class S, class I>

concept sentinel_for =
std::semiregular<S> &&
std::input_or_output_iterator<I> &&

__WeaklyEqualityComparableWith<S, I>;
 (C++20 起)

sentinel_for 概念描述的 input_or_output_iterator 与 semiregular 类型间的关系，二者的值代表范围。仅用于阐释的概念 __WeaklyEqualityComparableWith 描述于 equality_comparable 。

语义要求

令 s 与 i 分别表示 S 与 I 类型的值，使得 [i, s) 代表范围。 sentinel_for<S, I> 仅若下列条件成立才得到实现：

  • i == s 为良定义。
  • 若 bool(i != s) 则 i 可解引用且 [++i, s) 代表范围。
  • std::assignable_from<I&, S> 要么得到实现，要么不被满足。

== 能随时间而更改。给定迭代器 i 和哨位 s 并使得 [i, s) 代表范围且 i != s ，不要求自增任何等于 i 的迭代器后 [i, s) 继续代表范围（从而这种自增后不再要求 i == s 是良定义的）。

注解

不要求哨位类型与其对应的迭代器类型实现 equality_comparable_with ，因为哨位类型可以不可与自身比较，而且不要求它们拥有共用引用类型。

C++17 起已容许在基于范围的 for 循环中使用异于迭代器类型的哨位类型。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3453 | C++20 | sentinel_for 的语义要求对 ranges::advance 过于宽松 | 已强化


std::size, std::ssize

< cpp‎ | iterator
定义于头文件 <array>
定义于头文件 <deque>
定义于头文件 <forward_list>
定义于头文件 <iterator>
定义于头文件 <list>
定义于头文件 <map>
定义于头文件 <regex>
定义于头文件 <set>
定义于头文件 <span>
(C++20 起)
定义于头文件 <string>
定义于头文件 <string_view>
定义于头文件 <unordered_map>
定义于头文件 <unordered_set>
定义于头文件 <vector>
template <class C>
constexpr auto size(const C& c) -> decltype(c.size());
 (1) (C++17 起)
template <class C>

constexpr auto ssize(const C& c)
-> std::common_type_t < std::ptrdiff_t,

std::make_signed_t <decltype(c.size())>>;
 (2) (C++20 起)
template <class T, std::size_t N>
constexpr std::size_t size(const T (&array)[N]) noexcept;
 (3) (C++17 起)
template <class T, std::ptrdiff_t N>
constexpr std::ptrdiff_t ssize(const T (&array)[N]) noexcept;
 (4) (C++20 起)

返回给定范围的大小。

1-2) 返回 c.size() ，若需要则转换到返回类型。
3-4) 返回 N 。

参数

c | - | 拥有 size 成员函数的容器或视图
array | - | 任意类型的数组

返回值

c 或 array 的大小。

异常

1-2) 可能抛出实现定义的异常。

重载

可以为不暴露适合的 size() 成员函数的类或枚举提供 size 的自定义重载，从而能检测它。

实参依赖查找所找到的 size 重载能用于定制 std::ranges::size、 std::ranges::ssize 及 std::ranges::empty 的行为。

 (C++20 起)

可能的实现

版本一
template <class C>
constexpr auto size(const C& c) -> decltype(c.size())
{
    return c.size();
}
版本二
template <class C>
constexpr auto ssize(const C& c)
    -> std::common_type_t<std::ptrdiff_t,
                          std::make_signed_t<decltype(c.size())>> {
    using R = std::common_type_t<std::ptrdiff_t,
                                 std::make_signed_t<decltype(c.size())>>;
    return static_cast<R>(c.size());
}
版本三
template <class T, std::size_t N>
constexpr std::size_t size(const T (&array)[N]) noexcept
{
    return N;
}
版本四
template <class T, std::ptrdiff_t N>
constexpr std::ptrdiff_t ssize(const T (&array)[N]) noexcept
{
    return N;
}

示例

#include <iostream>
#include <vector>
#include <iterator>

int main()
{
    std::vector<int> v = { 3, 1, 4 };
    std::cout << std::size(v) << '\n';

    int a[] = { -5, 10, 15 };
    std::cout << std::size(a) << '\n';
}

输出：

3
3

参阅

ptrdiff_t | 在两个指针相减时返回的有符号整数类型 (typedef)
size_t | sizeof 运算符返回的无符号整数类型 (typedef)
ranges::size (C++20) | 返回等于范围大小的整数 (定制点对象)
ranges::ssize (C++20) | 返回等于范围大小的有符号整数 (定制点对象)


std::sized_sentinel_for, std::disable_sized_sentinel_for

< cpp‎ | iterator
定义于头文件 <iterator>
template<class S, class I>

concept sized_sentinel_for =
std::sentinel_for<S, I> &&
!std::disable_sized_sentinel_for< std::remove_cv_t <S>, std::remove_cv_t <I>> &&
requires(const I& i, const S& s) {
{ s - i } -> std::same_as<std::iter_difference_t<I>>;
{ i - s } -> std::same_as<std::iter_difference_t<I>>;

};
 (1) (C++20 起)
template<class S, class I>
inline constexpr disable_sized_sentinel_for = false;
 (2) (C++20 起)
1) sized_sentinel_for 概念指定能在常数时间内相减迭代器类型 I 的对象和哨位类型 S 的对象，计算其间的距离。
2) disable_sized_sentinel_for 变量模板能用于阻止能相减但不实际实现 sized_sentinel_for 的迭代器与哨位满足该概念。
允许对 cv 无限定的非数组对象类型 S 与 I 特化该变量模板，只要其中之一是程序定义类型。这种特化必须可用于常量表达式并拥有 const bool 类型。

语义要求

令 i 为 I 类型迭代器，而 s 为 S 类型哨位，使得 [i, s) 代表范围。令 n 为需要应用 ++i 以令 bool(i == s) 为 true 的最小次数。则 S 与 I 实现 sized_sentinel_for<S, I> 仅若：

  • 若 n 能以 ranges::difference_type_t<I> 表示，则 s - i 良定义并等于 n ；且
  • 若 -n 能以 ranges::difference_type_t<I> 表示，则 i - s 良定义并等于 -n 。
  • i 与 s 间的减法拥有常数时间复杂度。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

隐式表达式变种

使用不修改某 const 左值运算数的表达式的 requires 表达式亦隐式要求该表达式的额外变种对给定运算数接受非 const 左值或（可为 const 的）右值，除非以有区别的语义显式要求这种表达式变种。这些隐式表达式变种必须符合与声明的表达式的相同的语义。不指定实现以何种程度校验变种的语法。

参阅

ranges::sized_range (C++20) | 指定范围可在常数时间内知晓其大小 (概念)
ranges::size (C++20) | 返回等于范围大小的整数 (定制点对象)


std::sortable

< cpp‎ | iterator
定义于头文件 <iterator>
template< class I, class R = ranges::less, class P = std::identity >

concept sortable =
std::permutable<I> &&

std::indirect_strict_weak_order<R, std::projected<I, P>>;
 (C++20 起)

sortable 概念指定按照 R 重排范围到有序范围中的算法的要求。

语义要求

std::sortable<I, R, P> 仅若其所蕴含的所有概念均被实现才得以实现。

参阅

ranges::sort (C++20) | 将范围按升序排序 (niebloid)
ranges::stable_sort (C++20) | 将范围内的元素排序，同时保持相等的元素之间的顺序 (niebloid)
ranges::partial_sort (C++20) | 排序一个范围的前 N 个元素 (niebloid)
ranges::nth_element (C++20) | 将给定的范围部分排序，确保其按给定元素划分 (niebloid)
ranges::inplace_merge (C++20) | 在原位归并两个有序范围 (niebloid)
ranges::push_heap (C++20) | 将一个元素加入到一个最大堆 (niebloid)
ranges::pop_heap (C++20) | 从最大堆中移除最大元素 (niebloid)
ranges::make_heap (C++20) | 从一个元素范围创建出一个最大堆 (niebloid)
ranges::sort_heap (C++20) | 将一个最大堆变成一个按升序排序的元素范围 (niebloid)
ranges::next_permutation (C++20) | 产生某个元素范围的按字典序下一个较大的排列 (niebloid)
ranges::prev_permutation (C++20) | 产生某个元素范围的按字典序下一个较小的排列 (niebloid)


std::unreachable_sentinel_t, std::unreachable_sentinel

< cpp‎ | iterator
定义于头文件 <iterator> |  |
struct unreachable_sentinel_t; | (1) | (C++20 起)
inline constexpr unreachable_sentinel_t unreachable_sentinel{}; | (2) | (C++20 起)
1) unreachable_sentinel_t 是能用于表示无界区间“上界”的空类类型。
2) unreachable_sentinel 是 unreachable_sentinel_t 类型常量。

非成员函数

operator==
(C++20)
 比较一个 unreachable_sentinel_t 与任何 weakly_incrementable 类型值
(函数模板)

operator==(std::unreachable_sentinel_t)

template<std::weakly_incrementable I>

friend constexpr bool operator==( unreachable_sentinel_t, const I& ) noexcept

{ return false; }
 (C++20 起)

unreachable_sentinel_t 能与任何 weakly_incrementable 类型比较，而结果始终为 false 。

此函数模板对通常无限定或有限定查找不可见，而只能在 std::unreachable_sentinel_t 为参数的关联类时由实参依赖查找找到。

示例

#include <cstddef>
#include <iterator>
#include <algorithm>
#include <iostream>

template<class CharT>
std::size_t ntcts_len(const CharT *s)
{
    return std::ranges::find(s, std::unreachable_sentinel, CharT{}) - s;
}

int main()
{
    std::cout
        << ntcts_len("The quick brown fox jumps over the lazy dog.") << '\n';
}

输出：

44

参阅

ranges::iota_viewviews::iota
(C++20)
 由通过重复对某个初值自增所生成的序列组成的 view
(类模板) (定制点对象)


std::weakly_incrementable

< cpp‎ | iterator
定义于头文件 <iterator>
template<class I>

concept weakly_incrementable =
std::default_initializable<I> && std::movable<I> &&
requires(I i) {
typename std::iter_difference_t<I>;
requires /*is-signed-integer-like*/<std::iter_difference_t<I>>;
{ ++i } -> std::same_as<I&>; // 不要求保持相等性
i++; // 不要求保持相等性

};
 (C++20 起)

其中 /*is-signed-integer-like*/<I> 当且仅当 I 为有符号整数式类型（见后述）。

此概念指定能以前后自增运算符自增的类型上的要求，不过这些自增运算不要求保持相等性，而且不要求类型自身为 std::equality_comparable 。

对于 std::weakly_incrementable 类型， a == b 不蕴含 ++a == ++b 。弱可自增类型上的算法必须是单趟算法。这些算法能通过 std::istream_iterator 用于作为输入数据源的 istream 。

语义要求

给定类型 I 的任何对象 i ， I 仅若满足下列条件才实现 std::weakly_incrementable

  • 表达式 ++i 与 i++ 拥有相同定义域
  • 若 i 可自增，则 ++i 与 i++ 均增加 i
  • 若 i 可自增，则 std::addressof (++i) == std::addressof (i)

整数式类型

一个整数式类型是（可有 cv 限定的）整数类型（除了 cv bool ）或一个实现提供（非用户提供）的表现同整数类型的类，包括所有运算符、隐式转换及 std::numeric_limits 特化。若一个整数式类型仅表示非负值，则它为无符号整数式，否则它为有符号整数式。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3467 | C++20 | bool 被认为是整数类型 | 已排除
P2325R3 | C++20 | 要求 default_initializable | 不要求

参阅

incrementable
(C++20)
 指定 weakly_incrementable 类型上的自增操作保持相等性，而且该类型为 equality_comparable
(概念)


C++ 关键词

< cpp

这是 C++ 中的保留字列表。因为它们为语言所用，故这些关键词不可用于重定义或重载。

alignas (C++11 起)
alignof (C++11 起)
and
and_eq
asm
atomic_cancel (TM TS)
atomic_commit (TM TS)
atomic_noexcept (TM TS)
auto (1)
bitand
bitor
bool
break
case
catch
char
char8_t (C++20 起)
char16_t (C++11 起)
char32_t (C++11 起)
class (1)
compl
concept (C++20 起)
const
consteval (C++20 起)
constexpr (C++11 起)
constinit (C++20 起)
const_cast
continue
co_await (C++20 起)
co_return (C++20 起)
co_yield (C++20 起)
decltype (C++11 起)

default (1)
delete (1)
do
double
dynamic_cast
else
enum
explicit
export (1)(3)
extern (1)
false
float
for
friend
goto
if
inline (1)
int
long
mutable (1)
namespace
new
noexcept (C++11 起)
not
not_eq
nullptr (C++11 起)
operator
or
or_eq
private
protected
public
reflexpr (反射 TS)

register (2)
reinterpret_cast
requires (C++20 起)
return
short
signed
sizeof (1)
static
static_assert (C++11 起)
static_cast
struct (1)
switch
synchronized (TM TS)
template
this
thread_local (C++11 起)
throw
true
try
typedef
typeid
typename
union
unsigned
using (1)
virtual
void
volatile
wchar_t
while
xor
xor_eq
  • (1) - C++11 中含义改变或添加新含义。
  • (2) - C++17 中含义改变。
  • (3) - C++20 中含义改变。

注意 and、bitor、or、xor、compl、bitand、and_eq、or_eq、xor_eq、not 及 not_eq（还有双标符 <%、%>、<:、:>、%: 及 %:%:）提供标准记号的代用表示方法。

除了关键词外，还有拥有特殊含义的标识符，它们可用作对象或函数的名字，但在某些语境拥有特殊含义。

override (C++11)
final (C++11)
import (C++20)
module (C++20)
transaction_safe (TM TS)
transaction_safe_dynamic (TM TS)

还有，在任何位置含双下划线 __ 的所有标识符，和以一个下划线后随一个大写字母开始的所有标识符，都始终受保留，而所有以单下划线开始的标识符，保留用作全局命名空间中的名称。更多细节见标识符。

命名空间 std 用于放置标准 C++ 库中的名称。关于向它添加名称的规则，见扩充命名空间 std 。

名称 posix 保留作为未来的顶级命名空间。若程序于该命名空间声明或定义任何内容，则行为未定义。

 (C++11 起)

预处理器在预处理指令的语境中识别下列记号：

if
elif
else
endif

ifdef
ifndef
define
undef

include
line
error
pragma

defined
__has_include (C++17 起)
__has_cpp_attribute (C++20 起)

export (C++20)
import (C++20)
module (C++20)

预处理器在预处理指令的语境之外识别下列记号：

_Pragma (C++11 起)

参阅


C++ 关键词：alignas (C++11 起)

< cpp‎ | keyword

用法

  • alignas 说明符 (C++11 起)


C++ 关键词：alignof (C++11 起)

< cpp‎ | keyword

用法

  • alignof 运算符 (C++11 起)

示例

#include <iostream>
#include <cstddef>
int main()
{
    std::cout << alignof(std::max_align_t) << '\n';
}

可能的输出：

16


C++ 关键词：and

< cpp‎ | keyword

用法

  • 代用运算符：用作 && 的替代写法

示例

#include <iostream>

int n;
int main()
{
   if(n > 0 and n < 5)
   {
       std::cout << "n is small and positive\n";
   }
}


C++ 关键词：and_eq

< cpp‎ | keyword

用法

  • 代用运算符：用作 &= 的替代写法

示例

#include <iostream>
#include <bitset>
int main()
{
    std::bitset<4> mask("1100");
    std::bitset<4> val("0111");
    val and_eq mask;
    std::cout << val << '\n';
}

输出：

0100


C++ 关键词：asm

< cpp‎ | keyword

用法

  • 声明内联汇编块


C++ 关键词：auto

< cpp‎ | keyword

用法

  • 自动存储期说明符
 (C++11 前)
  • auto 占位符类型说明符
  • 带尾随返回类型的函数声明
 (C++11 起)
  • 结构化绑定声明
 (C++17 起)


C++ 关键词：bitand

< cpp‎ | keyword

用法

  • 代用运算符：用作 & 的替代写法


C++ 关键词：bitor

< cpp‎ | keyword

用法

  • 代用运算符：用作 | 的替代写法


C++ 关键词：bool

< cpp‎ | keyword

用法

  • bool 类型：用作该类型的声明


C++ 关键词： break

< cpp‎ | keyword

用法

  • break 语句：用作该语句的声明


C++ 关键词：case

< cpp‎ | keyword

用法

  • switch 语句：用作 case 标号的声明


C++ 关键词：catch

< cpp‎ | keyword

用法

  • try-catch 块


C++ 关键词：char

< cpp‎ | keyword

用法

  • char 类型：用作该类型的声明


C++ 关键词：char16_t (C++11 起)

< cpp‎ | keyword

用法

  • char16_t 类型：用作该类型的声明 (C++11 起)


C++ 关键词：char32_t (C++11 起)

< cpp‎ | keyword

用法

  • char32_t 类型：用作该类型的声明 (C++11 起)


C++ 关键词：char8_t (C++20 起)

< cpp‎ | keyword

用法

  • char8_t 类型 (C++20 起)


C++ 关键词：class

< cpp‎ | keyword

用法

  • 声明类
  • 声明有作用域枚举类型
 (C++11 起)
  • 在模板声明中，class 可用于引入类型模板形参与模板模板形参
  • 若作用域中存在具有与某个类类型的名字相同的名字的函数或变量，则 class 可附于类名之前以消歧义，这产生一个详述类型说明符

示例

class Foo;  // 类的前置声明

class Bar { // 类的定义
  public:
    Bar(int i) : m_i(i) {}
  private:
    int m_i;
};

template <class T> // 模板实参
void qux() {
    T t;
}

int main()
{
    Bar Bar(1);
    class Bar Bar2(2); // 详述的类型
}


C++ 关键词：co_await

< cpp‎ | keyword

用法

  • co_await 表达式 (C++20 起)


C++ 关键词：co_return

< cpp‎ | keyword

用法

  • 协程中的 return 语句 (C++20 起)


C++ 关键词：co_yield

< cpp‎ | keyword

用法

  • 从协程产出值 (C++20 起)


C++ 关键词：compl

< cpp‎ | keyword

用法

  • 代用运算符：用作 ~ 的替代写法


C++ 关键词：concept

< cpp‎ | keyword

用法

  • 声明具名类型要求 (C++20 起)


C++ 关键词：const

< cpp‎ | keyword

用法

  • const 类型限定符
  • const 限定的成员函数


C++ 关键词：const_cast

< cpp‎ | keyword

用法

  • const_cast 类型转换表达式：用作该表达式的声明


C++ 关键词：consteval

< cpp‎ | keyword

用法

  • consteval 声明说明符 (C++20 起)
  • 显式指定函数调用运算符为立即函数的 lambda-声明符 (C++20 起)
  • consteval if 语句(C++23 起)


C++ 关键词：constexpr (C++11 起)

< cpp‎ | keyword

用法

  • constexpr 声明说明符 (C++11 起)
  • constexpr if 语句 (C++17 起)


C++ 关键词：constinit

< cpp‎ | keyword

用法

  • constinit 声明说明符 (C++20 起)


C++ 关键词：continue

< cpp‎ | keyword

用法

  • continue 语句：用作该语句的声明


C++ 关键词：decltype

< cpp‎ | keyword

用法

  • decltype 说明符
  • decltype(auto)
 (C++14 起)


C++ 关键词：default

< cpp‎ | keyword

用法

  • switch 语句：用于声明默认情况标号
  • 显式默认化的函数定义：令编译器为某个类生成特殊成员函数 或比较运算符 (C++20 起)的显式指令。
 (C++11 起)


C++ 关键词：delete

< cpp‎ | keyword

用法

  • delete 表达式
  • 解分配函数：作为运算符式的函数名
  • 弃置函数
 (C++11 起)


C++ 关键词：do

< cpp‎ | keyword

用法

  • do-while 循环：用作循环的声明


C++ 关键词：double

< cpp‎ | keyword

用法

  • double 类型：用作该类型的声明
  • long double 类型：在与 long 结合时用作该类型的声明


C++ 关键词：dynamic_cast

< cpp‎ | keyword

用法

  • dynamic_cast 类型转换表达式：用作该表达式的声明


C++ 关键词：else

< cpp‎ | keyword

用法

  • if 语句：用作另一分支的声明


C++ 关键词：enum

< cpp‎ | keyword

用法

  • 声明枚举类型


C++ 关键词：explicit

< cpp‎ | keyword

用法

  • explicit 说明符


C++ 关键词：export

< cpp‎ | keyword

用法

用于标记模板定义为被导出，这允许在其他翻译单元中声明但不定义同一模板。 | (C++11 前)
不使用并保留该关键词。 | (C++11 起) (C++20 前)
标记一个声明、一组声明或另一模块为当前模块所导出。 | (C++20 起)


C++ 关键词：extern

< cpp‎ | keyword

用法

  • 具有外部连接的静态存储期说明符
  • 语言连接说明
  • 显示模板实例化声明（或“extern 模板”）


C++ 关键词：false

< cpp‎ | keyword

用法

  • 布尔字面量


C++ 关键词：final (C++11 起)

< cpp‎ | keyword

用法

  • final 说明符


C++ 关键词：float

< cpp‎ | keyword

用法

  • float 类型：用于该类型的说明


C++ 关键词：for

< cpp‎ | keyword

用法

  • for 循环：用于该循环的声明
  • 基于范围的 for 循环：用于该循环的声明(C++11 起)


C++ 关键词：friend

< cpp‎ | keyword

用法

  • friend 说明符


C++ 关键词：goto

< cpp‎ | keyword

用法

  • goto 语句：用作语句的声明


C++ 关键词：if

< cpp‎ | keyword

用法

  • if 语句：用作 if 语句的声明


cpp/keyword/import

< cpp‎ | keyword

none


C++ 关键词：inline

< cpp‎ | keyword

用法

  • 函数与变量 (C++17 起)的 inline 说明符
  • inline namespace 定义 (C++11 起)


C++ 关键词：int

< cpp‎ | keyword

用法

  • int 类型：用于该类型的声明


C++ 关键词：long

< cpp‎ | keyword

用法

  • long 类型修饰符


C++ 关键词：mutable

< cpp‎ | keyword

用法

  • mutable 类型说明符
  • 从按复制捕获的形参中移除的 const 限定性的 lambda 声明符 (C++11 起)


C++ 关键词：namespace

< cpp‎ | keyword

用法

  • 命名空间声明
  • 命名空间别名声明
  • using 指令


C++ 关键词：new

< cpp‎ | keyword

用法

  • new 表达式
  • 分配函数：作为运算符式的函数名


C++ 关键词：noexcept (C++11 起)

< cpp‎ | keyword

用法

  • noexcept 运算符
  • noexcept 说明符


C++ 关键词：not

< cpp‎ | keyword

用法

  • 代用运算符：用作 ! 的替代写法


C++ 关键词：not_eq

< cpp‎ | keyword

用法

  • 代用运算符：用作 != 的替代写法


C++ 关键词：nullptr (C++11 起)

< cpp‎ | keyword

用法

  • nullptr 指针字面量 (C++11 起)


C++ 关键词：operator

< cpp‎ | keyword

用法

  • 重载运算符的声明


C++ 关键词：or

< cpp‎ | keyword

用法

  • 代用运算符：用作 || 的替代写法


C++ 关键词：or_eq

< cpp‎ | keyword

用法

  • 代用运算符：用作 |= 的替代写法


C++ 关键词：override (C++11 起)

< cpp‎ | keyword

用法

  • override 说明符


C++ 关键词：private

< cpp‎ | keyword

用法

  • private 访问说明符


C++ 关键词：protected

< cpp‎ | keyword

用法

  • protected 访问说明符


C++ 关键词：public

< cpp‎ | keyword

用法

  • public 访问说明符


C++ 关键词：reflexpr (反射 TS)

< cpp‎ | keyword

用途

  1. 获取类类型的成员列表，或者枚举类型的枚举列表
  2. 获得类型或成员的名称
  3. 检测成员是否是静态的，亦可以获取成员是否是一个常量表达式
  4. 检测成员函数是否为虚, 以及其访问级别是 public、 protected 还是 private.
  5. 获取类型定义时在源代码中的的行号或者列号

范例

reflexpr 可以通过带有元信息的对象类型来获取对象的元数据 . 使用 std::reflect::get_data_members_t 可以访问类的反射信息，就如同使用 std::tuple 一般

#include <string>
#include <vector>

struct S {
    int b;
    std::string s;
    std::vector<std::string> v;
};

// Reflection TS
#include <experimental/reflect>
using meta_S = reflexpr(S);
using mem = std::reflect::get_data_members_t<meta_S>;
using meta = std::reflect::get_data_members_t<mem>;
static_assert(std::reflect::is_public_v<meta>); // successful

int main() {}

通过 reflexpr，我们也可以获取类型的名称信息:

#include <string>
#include <string_view>
#include <iostream>
// Reflection TS
#include <experimental/reflect>
template <typename Tp>
constexpr std::string_view nameof() {
 using TpInfo = reflexpr(Tp);
 using aliased_Info = std::experimental::reflect::get_aliased_t<TpInfo>;
 return std::experimental::reflect::get_name_v<aliased_Info>;
}

int main(){
 std::cout << nameof<std::string>() << '\n';
 static_assert(nameof<std::string>() == "basic_string"); // successful
}

这是在反射 TS中获取类型所在命名空间的示例。

namespace Foo{
 struct FooFoo{int FooFooFoo};
}
namespace Bar{
 using BarBar = ::Foo::FooFoo;
}
using BarBarInfo = reflexpr(::Bar::BarBar);
using BarBarScope = ::std::experimental::reflect::get_scope_t<BarBarInfo>; // Bar, not Foo

struct Spam{int SpamSpam;};
struct Grok{
 using GrokGrok = Spam::SpamSpam;
};
using GrokGrokInfo = reflexpr(::Grok::GrokGrok);
using GrokGrokScope = std::experimental::reflect::get_scope_t<GrokGrokInfo>; // Grok, not Spam


C++ 关键词：register

< cpp‎ | keyword

用法

自动存储期说明符 (弃用)。 | (C++17 前)
不使用并保留该关键词。 | (C++17 起)


C++ 关键词：reinterpret_cast

< cpp‎ | keyword

用法

  • reinterpret_cast 类型转换表达式：用作表达式的声明


C++ 关键词：requires

< cpp‎ | keyword

用法

  • 对模板形参指定一个求值为要求的常量表达式 (C++20 起)
  • 于模板声明中指定关联制约 (C++20 起)


C++ 关键词：return

< cpp‎ | keyword

用法

  • return 语句：用作语句的声明


C++ 关键词：short

< cpp‎ | keyword

用法

  • short 类型修饰符


C++ 关键词：signed

< cpp‎ | keyword

用法

  • signed 类型修饰符


C++ 关键词：sizeof

< cpp‎ | keyword

用法

  • sizeof 运算符
  • sizeof... 运算符 (C++11 起)


C++ 关键词：static

< cpp‎ | keyword

用法

  • 声明具有静态存储期和内部连接的命名空间成员
  • 定义具有静态存储期且仅初始化一次的块作用域变量
  • 声明不绑定到特定实例的类成员


C++ 关键词：static_assert (C++11 起)

< cpp‎ | keyword

用法

  • static_assert 声明 (C++11 起)


C++ 关键词：static_cast

< cpp‎ | keyword

用法

  • static_cast 类型转换表达式：用作表达式的声明


C++ 关键词：struct

< cpp‎ | keyword

用法

  • 复合类型的声明
  • 有作用域枚举类型的声明
 (C++11 起)
  • 若存在于作用域中的某个函数或变量所拥有的名字，与某个非联合体类类型的名字相同，则可在其名字之前加上 struct 来消歧义，这产生一个详述类型说明符


C++ 关键词：switch

< cpp‎ | keyword

用法

  • switch 语句：用作该语句的声明


C++ 关键词：template

< cpp‎ | keyword

用法

  • 声明模板
  • 在模板定义中，template 可用于将某个待决名声明为模板。


C++ 关键词：this

< cpp‎ | keyword

用法

  • this 指针


C++ 关键词：thread_local (C++11 起)

< cpp‎ | keyword

用法

  • 线程局域存储期指定符 (C++11 起)

参阅


C++ 关键词：throw

< cpp‎ | keyword

用法

  • throw 表达式
  • 动态异常说明
 (C++17 前)
  • noexcept 说明
 (C++17 起)
(C++20 前)


C++ 关键词：true

< cpp‎ | keyword

用法

  • 布尔字面量


C++ 关键词：try

< cpp‎ | keyword

用法

  • try-catch 块


C++ 关键词：typedef

< cpp‎ | keyword

用法

  • typedef 声明


C++ 关键词：typeid

< cpp‎ | keyword

用法

  • typeid 运算符


C++ 关键词：union

< cpp‎ | keyword

用法

  • 联合体类型的声明
  • 若存在于作用域中的某个函数或变量所拥有的名字与某个联合体类型的名字相同，则可在该名字之前加上 union 以消歧义，这产生详述类型说明符


C++ 关键词：unsigned

< cpp‎ | keyword

用法

  • unsigned 类型修饰符


C++ 关键词：using

< cpp‎ | keyword

用法

  • 对命名空间的 using 指令及对命名空间成员的 using 声明
  • 对类成员的 using 声明
  • 类型别名与别名模板声明 (C++11 起)


C++ 关键词：virtual

< cpp‎ | keyword

用法

  • 虚函数说明符
  • 虚基类说明符


C++ 关键词：void

< cpp‎ | keyword

用法

  • void 类型
  • 无形参函数的形参列表


C++ 关键词：volatile

< cpp‎ | keyword

用法

  • volatile 类型限定符
  • volatile 限定的成员函数


C++ 关键词：wchar_t

< cpp‎ | keyword

用法

  • wchar_t 类型：用作该类型的声明


C++ 关键词：while

< cpp‎ | keyword

用法

  • while 循环：该循环的声明
  • do-while 循环：该循环终止条件的声明


C++ 关键词：xor

< cpp‎ | keyword

用法

  • 代用运算符：作为 ^ 的替代写法


C++ 关键词：xor_eq

< cpp‎ | keyword

用法

  • 代用运算符：用作 ^= 的替代写法


C++ 关键词：typename

< cpp‎ | keyword

用法

  • 在模板声明的模板形参列表中，typename 可用作 class 的代替品，以声明类型模板形参 和模板模板形参 (C++17 起)。
  • 在模板的声明或定义内，typename 可用于声明某个待决的有限定名是类型。
  • 在模板的声明或定义内， (C++11 前)typename 可在非待决的有限定类型名之前使用。此情况下它没有效果。
  • 在类型要求的要求中。(C++20 起)


C++ 语言

< cpp

这是一份核心 C++ 语言构造的参考手册。

基本概念

注释
ASCII 码表
标点
名字与标识符
类型 – 基础类型
对象 – 作用域 – 生存期
定义与 ODR
名字查找
有限定 – 无限定（实参依赖）
“如同”规则
未定义行为
内存模型与数据竞争
字符集与编码
翻译阶段
main 函数
模块 (C++20)

关键词

预处理器

#if - #ifdef - #ifndef - #elif
#elifdef - #elifndef (C++23)
#define - # - ##
#include - #pragma
#line - #error

表达式

值类别
求值顺序与定序
常量表达式
运算符
赋值 – 算术
自增与自减
逻辑 – 比较
成员访问与间接
调用、逗号、三元
sizeof – alignof (C++11)
new – delete – typeid
运算符重载
默认比较 (C++20)
运算符优先级
转换
隐式 – 显式 – 用户定义
static_cast – dynamic_cast
const_cast – reinterpret_cast
字面量
布尔 – 整数 – 浮点
字符 – 字符串
nullptr (C++11)
用户定义 (C++11)

声明

命名空间声明
命名空间别名
引用 – 指针 – 数组
结构化绑定 (C++17)
枚举与枚举项
存储期与链接
翻译单元局部 (C++20)
语言链接
inline 说明符
内联汇编
const/volatile – constexpr (C++11)
consteval (C++20) – constinit (C++20)
decltype (C++11) – auto (C++11)
typedef – 类型别名 (C++11)
详述类型说明符
属性 (C++11) – alignas (C++11)
static_assert (C++11)

初始化

默认初始化
值初始化 (C++03)
复制初始化
直接初始化
聚合初始化
列表初始化 (C++11)
引用初始化
静态非局部初始化
零 – 常量
动态非局部初始化
有序 – 无序
复制消除

函数

函数声明
默认实参
变长实参
Lambda 表达式 (C++11)
实参依赖查找
重载决议
运算符重载
重载集的地址
协程 (C++20)

语句

if – switch
for – 范围 for (C++11)
while – do-while
continue – break – goto – return
synchronized 与 atomic (TM TS)

类

类类型 – 联合类型
注入类名
数据成员 – 位域
成员函数 – this 指针
静态成员 – 嵌套类
派生类 – using 声明
空基类优化
虚函数 – 抽象类
override (C++11) – final (C++11)
成员访问 – friend
构造函数与成员初始化器列表
默认构造函数 – 析构函数
复制构造函数 – 复制赋值
移动构造函数 (C++11)
移动赋值 (C++11)
转换构造函数 – explicit 说明符

模板

模板形参与实参
类模板 – 函数模板
变量模板 (C++14)
类成员模板
模板实参推导
类模板实参推导 (C++17)
显式特化 – 部分特化
形参包 (C++11) – sizeof... (C++11)
折叠表达式 (C++17)
待决名 – SFINAE
约束与概念 (C++20)

异常

throw 表达式
try-catch 块
函数 try 块
noexcept 说明符 (C++11)
noexcept 运算符 (C++11)
动态异常说明 (C++17 前)

杂项

C++ 的历史
扩充命名空间 std
字母缩写

习语

资源获取即初始化
三/五/零法则
指向实现的指针
零开销原则

参阅


零开销原则

< cpp‎ | language

零开销原则是 C++ 设计原则，所说的是：

  1. 你无需为你所不用的付出。
  2. 你所用的正与你所能合理手写的效率相同。

总而言之，这表示不应该添加某特性到 C++ ，如果该特性引发的开销，不论在时间还是空间方面，会大于程序员自己实现该特性产生的开销。

语言中仅有的两个不遵循零开销原则的特性是运行时类型鉴别与异常，从而这是大多数编译器包含关闭它们的开关的原因。

引用

  • C++ 的基础 - Bjarne Stroustrup
  • C++ 异常与代替品 - Bjarne Stroustrup
  • 反碎片化 C++ ：使异常与 RTTI 更廉价且可用 - Herb Sutter


抽象类

< cpp‎ | language

定义不能被实例化，但可用作基类的抽象类型。

语法

纯虚函数是其声明符拥有下列语法的虚函数：

声明符 虚说明符(可选) = 0

在这里序列 = 0 被称作 纯说明符，且要么紧跟 声明符 之后，要么紧跟可选的 虚说明符（override 或 final）之后出现。

纯说明符 不能在成员函数定义中出现。

struct Base { virtual int g(); virtual ~Base() {} };
struct A : Base{
    // OK：声明三个成员虚函数，其中两个是纯虚函数
    virtual int f() = 0, g() override = 0, h();
    // OK：析构函数也可以是纯虚函数
    ~A() = 0;
    // 错误：函数定义中的纯说明符
    virtual int b()=0 {}
};

抽象类（abstract class） 是定义或继承了至少一个最终覆盖函数是 纯虚 的函数的类。

解释

抽象类用于表示一般性概念（例如 Shape、Animal 等），它可用作具体类（例如 Circle、Dog 等）的基类。

除了作为从其派生的类的基类子对象之外，不能创建抽象类的对象，且不能声明抽象类类型的非静态数据成员。

抽象类型不能用作形参类型，函数返回类型，或显式转换的类型（注意，这是在函数定义点和函数调用点检查的，因为在函数声明点其形参和返回类型可以是不完整类型）。

可以声明到抽象类的指针或引用。

struct Abstract {
    virtual void f() = 0; // 纯虚
}; // "Abstract" 是抽象的

struct Concrete : Abstract {
    void f() override {} // 非纯虚
    virtual void g();     // 非纯虚
}; // "Concrete" 不是非抽象的

struct Abstract2 : Concrete {
    void g() override = 0; // 纯虚覆盖函数
}; // "Abstract2" 是抽象的

int main()
{
    // Abstract a; // 错误：不能创建抽象类的对象
    Concrete b; // OK
    Abstract& a = b; // OK：到抽象基类的引用
    a.f(); // 虚派发到 Concrete::f()
    // Abstract2 a2; // 错误：不能创建抽象类的对象（g() 的最终覆盖函数是纯虚的）
}

可以为纯虚函数提供定义（而且如果纯虚函数是析构函数则必须提供）：派生类的成员函数可以自由地用有限定的函数标识调用抽象基类的纯虚函数。此定义必须在类体之外提供（函数声明的语法不允许纯说明符 = 0 和函数体一起出现）。

从抽象类的构造函数或析构函数中进行纯虚函数的虚调用是未定义行为（无论纯虚函数是否拥有定义）。

struct Abstract {
    virtual void f() = 0; // 纯虚
    virtual void g() {} // 非纯虚
    ~Abstract() {
        g(); // OK：调用 Abstract::g()
        // f(); // 未定义行为
        Abstract::f(); // OK：非虚调用
    }
};

// 纯虚函数的定义
void Abstract::f() { std::cout << "A::f()\n"; }

struct Concrete : Abstract {
    void f() override {
        Abstract::f(); // OK：调用纯虚函数
    }
    void g() override {}
    ~Concrete() {
        g(); // OK：调用 Concrete::g()
        f(); // OK：调用 Concrete::f()
    }
};

参阅

  • virtual


访问说明符

< cpp‎ | language

在 class/struct 或 union 的 成员说明 中定义其后继成员的可访问性。

在派生类声明的 基类说明符 中定义继承自其后继的基类的成员的可访问性。

语法

public : 成员说明 | (1)
protected : 成员说明 | (2)
private : 成员说明 | (3)
public 基类 | (4)
protected 基类 | (5)
private 基类 | (6)
1) 该访问说明符之后的各个成员具有公开成员访问
2) 该访问说明符之后的各个成员具有受保护成员访问
3) 该访问说明符之后的各个成员具有私有成员访问
4) 公开继承：该访问说明符之后列出的基类的公开和受保护成员在派生类中保持其成员访问，而基类的私有成员对派生类不可访问
5) 受保护继承：该访问说明符之后列出的基类的公开和受保护成员在派生类中是受保护成员，而基类的私有成员对派生类不可访问
6) 私有继承：该访问说明符之后列出的基类的公开和受保护成员在派生类中是私有成员，而基类的私有成员对派生类不可访问

解释

每个类成员（静态、非静态、函数、类型等）的名字都具有与其关联的“成员访问”。在程序的任何位置使用成员的名字时都会检查其访问，而且如果它不满足访问规则，那么程序不能编译：

#include <iostream>
class Example {
 public:              // 此点后的所有声明都是公开的
    void add(int x) { // 成员 "add" 具有公开访问
        n += x;       // OK：从 Example::add 可以访问私有的 Example::n
    }
 private:             // 此点后的所有声明都是私有的
    int n = 0;        // 成员 "n" 具有私有访问
};
int main()
{
    Example e;
    e.add(1); // OK：从 main 可以访问公开的 Example::add
//  e.n = 7;  // 错误：从 main 不能访问私有的 Example::n
}

访问说明符给予类作者决定哪些类成员能被类的用户所访问（即类的接口），而哪些成员用于内部使用（即其实现）的能力。

细节

类的所有成员（成员函数体，成员对象的初始化器，以及整个嵌套类定义），都拥有对类所能访问的所有名字的访问权。成员函数内的局部类拥有对成员函数所能访问的所有名字的访问权。

以关键词 class 定义的类，其成员和其基类默认具有私有访问。以关键词 struct 定义的类，其成员和其基类默认具有公开访问。union 的成员默认具有公开访问。

如果要向其他函数或类授予对受保护或私有成员的访问权，可以使用友元声明。

可访问性应用到所有名字，而不考虑其来源，因此受检查的是以 typedef 或 using 声明引入的名字，而非其所指涉的名字：

class A : X {
  class B { };  // 在 A 中，B 是私有的
public:
  typedef B BB; // 在 A 中，BB 是公开的
};
void f() {
  A::B y;  // 错误：A::B 是私有的
  A::BB x; // OK：A::BB 是公开的
}

成员访问不影响可见性：私有和私有继承的成员对重载决议可见并被其考虑，到不可访问基类的隐式转换也仍被考虑，等等。成员访问检查是对任何给定语言构造进行解释之后的最后一步。此规则的目的是使得以 public 替换任何 private 时始终不会改变程序的行为。

对于默认函数实参中以及默认模板形参中所使用的名字的访问检查，在声明点而非在使用点进行。

对虚函数的名字的访问规则，在调用点，使用（用于代表调用该成员函数的对象的）表达式的类型进行检查。忽略最终覆盖函数的访问：

struct B { virtual int f(); }; // 在 B 中，f 是公开的
class D : public B { private: int f(); }; // 在 D 中，f 是私有的
void f() {
 D d;
 B& b = d;
 b.f(); // OK：B::f() 是公开的，调用 D::f()，即使它是私有的
 d.f(); // 错误：D::f() 是私有的
}

根据无限定名字查找为私有的名字，有可能通过有限定名字查找访问：

class A {};
class B : private A { };
class C : public B {
   A* p;   // 错误：无限定名字查找找到作为 B 的私有基类的 A
   ::A* q; // OK：有限定名字查找找到命名空间层级的声明
};

如果一个名字可以通过继承图中多条路径访问，那么它的访问是所有路径中带最大访问的路径的访问：

class W { public: void f(); };
class A : private virtual W { };
class B : public virtual W { };
class C : public A, public B {
void f() { W::f(); } // OK： C 可以通过 B 访问 W
};

类中可以以任意顺序出现任意数量的访问说明符。成员访问说明符可能影响类的布局：非静态数据成员的地址只保证对于未被访问说明符分隔 (C++11 前)具有相同访问 (C++11 起)的成员以声明顺序增加。

对于标准布局类型 (StandardLayoutType) ，所有非静态数据成员必须具有相同访问。

 (C++11 起)

在类中重声明成员时，成员访问必须相同：

struct S {
  class A;    // S::A 公开
private:
  class A {}; // 错误：不能更改访问
};

公开成员访问

公开成员组成类公开接口的一部分（公开接口的其他部分是由 ADL 所找到的非成员函数）。

类的公开成员可以在任意位置访问。

class S {
 public: // n、E、A、B、C、U、f 是公开成员
    int n;
    enum E {A, B, C};
    struct U {};
    static void f() {}
};
int main()
{
    S::f();     // S::f 可以在 main 访问
    S s;
    s.n = S::B; // S::n 与 S::B 可以在 main 访问
    S::U x;     // S::U 可以在 main 访问
}

受保护成员访问

受保护成员组成所在类针对其派生类的接口（与类的公开接口有别）。

类的受保护成员只能为下列者所访问

1) 该类的成员和友元
2) 派生自该类的任何类的成员和友元 (C++17 前)，但仅在访问受保护成员所通过的对象的类是该派生类或该派生类的派生类时允许：
struct Base {
 protected:
    int i;
 private:
    void g(Base& b, struct Derived& d);
};

struct Derived : Base {
    void f(Base& b, Derived& d) // 派生类的成员函数
    {
        ++d.i;                  // OK：d 的类型是 Derived
        ++i;                    // OK：隐含的 '*this' 的类型是 Derived
//      ++b.i;                  // 错误：不能通过 Base 访问受保护成员
                                // （否则可能更改另一派生类，假设为 Derived2 的基实现）
    }
};

void Base::g(Base& b, Derived& d) // Base 的成员函数
{
    ++i;                          // OK
    ++b.i;                        // OK
    ++d.i;                        // OK
}

void x(Base& b, Derived& d) // 非成员非友元
{
//    ++b.i;                // 错误：非成员不能访问
//    ++d.i;                // 错误：非成员不能访问
}

组成指向受保护成员的指针时，必须在其声明中使用派生类：

struct Base {
 protected:
    int i;
};

struct Derived : Base {
    void f()
    {
//      int Base::* ptr = &Base::i;    // 错误：必须使用 Derived 来指名
        int Base::* ptr = &Derived::i; // OK
    }
};

私有成员访问

私有成员组成类的实现，以及针对类的其他成员的私有接口。

类的私有成员仅对类的成员和友元可访问，无关乎成员在相同还是不同实例：

class S {
 private:
    int n; // S::n 私有
 public:
    S() : n(10) {}                    // this->n 可以在 S::S 访问
    S(const S& other) : n(other.n) {} // other.n 可以在 S::S 访问
};

显式转型（C 风格与函数风格）允许从派生类左值转型为到其私有基类的引用，或从指向派生类的指针转型为指向其私有基类的指针。

继承

公开、受保护和私有继承的含义，见派生类。


字母缩写

< cpp‎ | language
缩写 | 全名 | 参阅
AAA | Almost Always Auto 几乎始终 auto | GOTW #94
ADL | Argument-Dependent Lookup 实参依赖查找 |
CTAD | Class Template Argument Deduction 类模板实参推导 |
CRTP | Curiously Recurring Template Pattern 奇特重现模板模式 | std::enable_shared_from_this
EBO | Empty Base Optimization 空基类优化 | std::allocator, std::default_delete
ICE | Internal Compiler Error 内部编译器错误 |
NRVO | Named Return Value Optimization 具名返回值优化 |
NSDMI | Non-Static Data Member Initialization 非静态数据成员初始化 |
NTTP | Non-Type Template Parameter 非类型模板形参 |
ODR | One Definition Rule 单一定义规则 |
PIMPL | Pointer to IMPLementation 实现指针（手法） |
RAII | Resource Acquisition Is Initialization 资源获取即初始化 |
RTTI | RunTime Type Identification 运行时类型鉴别 | std::type_info
RVO | Return Value Optimization 返回值优化 |
SBO | Small Buffer Optimization 小缓冲区优化 |
SCARY | Seemingly erroneous (appearing Constrained by conflicting generic parameters), but Actually work with the Right implementation (unconstrained bY the conflict due to minimized dependencies). 看起来错误（表面上由冲突的泛型参数制约），但实际上在正确的实现中有效（由于最小化依赖而无需约束）。 | stroustrup.com/SCARY.pdf
SFINAE | Substitution Failure Is Not An Error 替换失败不是错误 | std::enable_if, std::void_t
SOO | Small Object Optimization 小对象优化 | std::function, std::any
SSO | Small String Optimization 小字符串优化 | std::basic_string
TMP | Template Meta Programming 模板元编程 | <type_traits>
UB | Undefined Behavior 未定义行为 |
UDL | User-Defined Literals 用户定义字面量 |


聚合初始化

< cpp‎ | language

从花括号初始化器列表初始化聚合体。

语法

T 对象 = {实参1, 实参2, ...}; | (1) |
T 对象 {实参1, 实参2, ... }; | (2) | (C++11 起)
T 对象 = { .指派符 = 实参1 , .指派符 { 实参2 } ... }; | (3) | (C++20 起)
T 对象 { .指派符 = 实参1 , .指派符 { 实参2 } ... }; | (4) | (C++20 起)
T 对象 (实参1, 实参2, ...); | (5) | (C++20 起)

解释

聚合初始化对聚合体进行初始化。它是列表初始化 (C++11 起)，或直接初始化 (C++20 起)的一种形式。

聚合体是下列类型之一：

  • 数组类型
  • 符合以下条件的类类型（常为 struct 或 union）
  • 没有私有或受保护的直接 (C++17 起)非静态数据成员
  • 没有用户声明的构造函数
 (C++11 前)
  • 没有用户提供的构造函数（允许显式预置或弃置的构造函数）
 (C++11 起)
(C++17 前)
  • 没有用户提供、继承或 explicit 的构造函数（允许显式预置或弃置的构造函数）
 (C++17 起)
(C++20 前)
  • 没有用户声明或继承的构造函数
 (C++20 起)
  • 没有虚、私有或受保护 (C++17 起)的基类
  • 没有虚成员函数
  • 没有默认成员初始化器
 (C++11 起)
(C++14 前)

聚合初始化的效果是：

  • 每个直接公开基类、 (C++17 起)数组元素或非静态类成员，以数组下标/出现于类定义的顺序，从初始化器列表中的对应子句进行复制初始化。
  • 如果初始化器子句是表达式，那么根据复制初始化允许进行隐式转换，但对于列表初始化形式禁止窄化转换 (C++11 起)。
  • 如果初始化器子句是嵌套的花括号初始化器列表（它不是表达式），那么它对应的数组元素/类成员/公开基类 (C++17 起)从该子句进行列表初始化：聚合初始化是递归的。
  • 如果对象是未知大小的数组，且所提供的花括号环绕的初始化器列表拥有 n 个子句，那么该数组的大小是 n。（注意此时对象不能是非静态数据成员：成员必须拥有完整类型。）
  • 静态数据成员和无名位域在聚合初始化中被跳过。
  • 如果初始化器子句的数量超出所要初始化的成员和基类 (C++17 起)的数量，那么程序非良构。
  • 如果初始化器子句的数量少于成员的数量，或初始化器列表完全为空，那么剩余成员被值初始化。如果这些剩余成员的类型中有引用类型，那么程序非良构。
 (C++11 前)
  • 如果初始化器子句的数量少于成员和基类 (C++17 起)的数量，或初始化器列表完全为空，那么剩余成员和基类 (C++17 起)会按照通常的列表初始化规则（对非类类型和拥有默认构造函数的非聚合类进行值初始化，并对聚合体进行聚合初始化），在类定义中有提供默认成员初始化器的情况下用它初始化，否则 (C++14 起)从空列表复制初始化。如果这些剩余成员的类型中有引用类型，那么程序非良构。
 (C++11 起)
  • 当聚合初始化联合体时，只初始化其首个非静态数据成员。

可消除（省略）环绕嵌套的初始化器列表的花括号，这种情况下，使用所需数量的初始化器子句初始化对应的子聚合体的各个成员或元素，而后继的各个初始化器子句被用于初始化对象中的后续成员。然而，如果对象拥有不带任何成员的子聚合体（空结构体，或只保有静态成员的结构体），则不允许消除花括号而必须使用一个空的嵌套列表 {}。

指派初始化器

语法形式 (3,4) 被称为指派初始化器：每个 指派符 必须指名 T 的一个直接非静态数据成员，而表达式中所用的所有 指派符 必须按照与 T 的数据成员相同的顺序出现。

struct A { int x; int y; int z; };
A a{.y = 2, .x = 1}; // 错误：指派符的顺序不匹配声明顺序
A b{.x = 1, .z = 2}; // OK：b.y 被初始化为 0

指派初始化器所指名的每个直接非静态数据成员，从其指派符后随的对应花括号或等号初始化器初始化。禁止窄化转换。

指派初始化器可用于将联合体初始化为其首个成员之外的状态。只可以为一个联合体提供一个初始化器。

union u { int a; const char* b; };
u f = { .b = "asdf" };         // OK：联合体的活跃成员为 b
u g = { .a = 1, .b = "asdf" }; // 错误：只可提供一个初始化器

对于非联合体的聚合体中未提供指派初始化器的元素，按上述针对初始化器子句的数量少于成员数量时的规则进行初始化（如果提供默认成员初始化器则使用它，否则为空列表初始化）：

struct A {
  string a;
  int b = 42;
  int c = -1;
};
A{.c=21}  // 以 {} 初始化 a，这样会调用默认构造函数
          // 然后以 = 42 初始化 b
          // 然后以 = 21 初始化 c

如果以指派初始化器子句初始化的聚合体拥有一个匿名联合体成员，那么对应的指派初始化器必须指名该匿名联合体的其中一个成员。

注意：乱序的指派初始化、嵌套的指派初始化、指派初始化器与常规初始化器的混合，以及数组的指派初始化在 C 编程语言中受支持，但在 C++ 不允许。

struct A { int x, y; };
struct B { struct A a; };
struct A a = {.y = 1, .x = 2}; // 合法 C，非法 C++（乱序）
int arr[3] = {[1] = 5};        // 合法 C，非法 C++（数组）
struct B b = {.a.x = 0};       // 合法 C，非法 C++（嵌套）
struct A a = {.x = 1, 2};      // 合法 C，非法 C++（混合）
 (C++20 起)

字符数组

通常字符类型（char、 signed char、 unsigned char）、 char8_t (C++20 起)、 char16_t、 char32_t (C++11 起)或 wchar_t 的数组能分别从通常字符串字面量 、 UTF-8 字符串字面量 (C++20 起)、 UTF-16 字符串字面量、 UTF-32 字符串字面量 (C++11 起)或宽字符串字面量初始化，可以以花括号环绕。字符串字面量的相继字符（包含隐含的空终止字符）初始化各数组元素。如果数组大小被指定且大于字符串字面量中的字符数，那么剩余字符会被零初始化。

char a[] = "abc";
// 等价于 char a[4] = {'a', 'b', 'c', '\0'};

//  unsigned char b[3] = "abc"; // 错误：初始化器字符串太长
unsigned char b[5]{"abc"};
// 等价于 unsigned char b[5] = {'a', 'b', 'c', '\0', '\0'};

wchar_t c[] = {L"кошка"}; // 可选的花括号
// 等价于 wchar_t c[6] = {L'к', L'о', L'ш', L'к', L'а', L'\0'};

注解

聚合类或数组可以包含非聚合的公开基类、 (C++17 起)成员或元素，它们以上述方式初始化（例如从对应的初始化器子句复制初始化）

C++11 前，聚合初始化中曾允许窄化转换，但此后不再被允许，但从 C++20 起聚合初始化使用圆括号时允许它们。

C++11 前，由于语法限制，聚合初始化只能用于变量定义，而不能用于构造函数初始化器列表、 new 表达式或临时对象创建。

C 中，长度比字符串字面量的大小少一的字符数组可以从字符串字面量初始化；产生的数组是非空终止的。这在 C++ 中不允许。

示例

#include <string>
#include <array>
struct S {
    int x;
    struct Foo {
        int i;
        int j;
        int a[3];
    } b;
};

union U {
    int a;
    const char* b;
};

int main()
{
    S s1 = { 1, { 2, 3, {4, 5, 6} } };
    S s2 = { 1, 2, 3, 4, 5, 6}; // 相同，但有花括号消除
    S s3{1, {2, 3, {4, 5, 6} } }; // 相同，使用直接列表初始化语法
    S s4{1, 2, 3, 4, 5, 6}; // CWG 1270 前错误：花括号消除仅允许与等号一起使用

    int ar[] = {1,2,3}; // ar 为 int[3]
    int ab[] (1, 2, 3); // (C++20) ab 为 int[3]
//  char cr[3] = {'a', 'b', 'c', 'd'}; // 过多初始化器子句
    char cr[3] = {'a'}; // 数组初始化为 {'a', '\0', '\0'}

    int ar2d1[2][2] = {{1, 2}, {3, 4}}; // 完全花括号的 2D 数组： {1, 2}
                                        //                      {3, 4}
    int ar2d2[2][2] = {1, 2, 3, 4}; // 花括号消除： {1, 2}
                                    //             {3, 4}
    int ar2d3[2][2] = {{1}, {2}};   // 仅第一列： {1, 0}
                                    //           {2, 0}

    std::array<int, 3> std_ar2{ {1,2,3} };    // std::array 是聚合体
    std::array<int, 3> std_ar1 = {1, 2, 3}; // 可以消除花括号

    int ai[] = { 1, 2.0 }; // 从 double 到 int 的窄化转换：
                           // C++11 中错误，C++03 中 OK

    std::string ars[] = {std::string("one"), // 复制初始化
                         "two",              // 转换，然后复制初始化
                         {'t', 'h', 'r', 'e', 'e'} }; // 列表初始化

    U u1 = {1}; // OK，联合体的首个成员
//    U u2 = { 0, "asdf" }; // 错误：用过多的初始化器初始化联合体
//    U u3 = { "asdf" }; // 错误：到 int 的转换无效

    [](auto...) { std::puts("废弃无用的变量。。。 完成。"); } (
        s1, s2, s3, s4, ar, ab, cr, ar2d1, ar2d2, ar2d3, std_ar2, std_ar1, u1
    );
}

// 聚合体
struct base1 { int b1, b2 = 42; };
// 非聚合体
struct base2 {
  base2() : b3(42) {}
  int b3;
};
// C++17 里是聚合体
struct derived : base1, base2 { int d; };
derived d1{ {1, 2}, { }, 4}; // d1.b1 = 1, d1.b2 = 2,  d1.b3 = 42, d1.d = 4
derived d2{ {    }, { }, 4}; // d2.b1 = 0, d2.b2 = 42, d2.b3 = 42, d2.d = 4

输出：

废弃无用的变量。。。 完成。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1270 | C++11 | 仅允许在复制列表初始化中使用花括号消除 | 在别处也允许

参阅

  • 复制消除
  • 初始化
    • 常量初始化
    • 列表初始化
    • 引用初始化
    • 值初始化
    • 零初始化


alignas 说明符 (C++11 起)

< cpp‎ | language

指定类型或对象的对齐要求。

语法

alignas( 表达式 )
alignas( 类型标识 )
alignas( 包 ... )
1) alignas(表达式) 必须是求值为零或合法的对齐或扩展对齐的整型常量表达式。
2) 等价于 alignas(alignof(类型))
3) 等价于对同一说明应用多个 alignas 说明符，逐个对应于形参包的各个成员，形参包可以是类型或非类型形参包。

解释

alignas 说明符可应用于：

  • 类/结构体/联合体或枚举的声明或定义；
  • 非位域类数据成员的声明；
  • 变量声明，除了它不能应用于下列内容：
    • 函数形参；
    • catch 子句的异常形参。

这种声明所声明的对象或类型的对齐要求将等于用于该声明的所有 alignas 说明符中最严格（最大）的非零 表达式，除非这会削弱类型的自然对齐。

如果某个声明上的最严格（最大）alignas 比当它没有任何 alignas 说明符的情况下本应有的对齐更弱（即弱于其原生对齐，或弱于同一对象或类型的另一声明上的 alignas），那么程序非良构：

struct alignas(8) S {};
struct alignas(1) U { S s; }; // 错误：如果没有 alignas(1) 则 U 的对齐将为 8

无效的非零对齐，例如 alignas(3) 非良构。

同一声明上，弱于其他 alignas 的有效的非零对齐被忽略。

始终忽略 alignas(0)。

注解

按 ISO C11 标准，C 语言有 _Alignas 关键词，并于头文件 <stdalign.h> 中将 alignas 定义为展开成该关键词的预处理器宏。

在 C++ 中这是关键词，且

头文件 <stdalign.h> 与 <cstdalign> 并不定义这个宏。不过它们仍定义宏常量 __alignas_is_defined。 | (C++20 前)
头文件 <stdalign.h> 并不定义这个宏。不过它仍定义宏常量 __alignas_is_defined。 | (C++20 起)

关键词

alignas

示例

// 每个 struct_float 类型对象都将被对齐到 alignof(float) 边界
// （通常为 4）：
struct alignas(alignof(float)) struct_float
{
    // 定义在此
};

// sse_t 类型的每个对象将对齐到 32 字节边界
struct alignas(32) sse_t
{
  float sse_data[4];
};

// 数组 "cacheline" 将对齐到 64 字节边界
alignas(64) char cacheline[64];

#include <iostream>
int main()
{
    struct default_aligned { float data[4]; } a, b, c;
    sse_t x, y, z;

    std::cout
        << "alignof(struct_float) = " << alignof(struct_float) << '\n'
        << "sizeof(sse_t) = " << sizeof(sse_t) << '\n'
        << "alignof(sse_t) = " << alignof(sse_t) << '\n'
        << "alignof(cacheline) = " << alignof(alignas(64) char[64]) << '\n'
        << std::hex << std::showbase
        << "&a: " << &a << '\n'
        << "&b: " << &b << '\n'
        << "&c: " << &c << '\n'
        << "&x: " << &x << '\n'
        << "&y: " << &y << '\n'
        << "&z: " << &z << '\n';
}

可能的输出：

alignof(struct_float) = 4
sizeof(sse_t) = 32
alignof(sse_t) = 32
alignof(cacheline) = 64
&a: 0x7fffcec89930
&b: 0x7fffcec89940
&c: 0x7fffcec89950
&x: 0x7fffcec89960
&y: 0x7fffcec89980
&z: 0x7fffcec899a0

参阅

alignof 运算符 (C++11) | 查询类型的对齐要求
alignment_of (C++11) | 获取类型的对齐要求 (类模板)


alignof 运算符(C++11 起)

< cpp‎ | language

查询类型的对齐要求。

语法

alignof( 类型标识 )

返回 std::size_t 类型的值。

解释

返回由类型标识所指示的类型的任何实例所要求的对齐字节数，该类型可以为完整对象类型、元素类型完整的数组类型或者到这些类型之一的引用类型。

若类型为引用类型，则运算符返回被引用类型的对齐；若类型为数组类型，则返回元素类型的对齐要求。

关键词

alignof

注解

有关 alignof 的返回值的含义和性质，参见对齐。

示例

#include <iostream>

struct Foo {
    int   i;
    float f;
    char  c;
};

// 注：下面的 `alignas(alignof(long double))` 如果需要可以简化为
// `alignas(long double)`
struct alignas(alignof(long double)) Foo2 {
    // Foo2 成员的定义...
};

struct Empty {};

struct alignas(64) Empty64 {};

int main()
{
    std::cout << "对齐字节数"  "\n"
        "- char             ：" << alignof(char)    << "\n"
        "- 指针             ：" << alignof(int*)    << "\n"
        "- Foo 类           ：" << alignof(Foo)     << "\n"
        "- Foo2 类          ：" << alignof(Foo2)     << "\n"
        "- 空类             ：" << alignof(Empty)   << "\n"
        "- alignas(64) Empty：" << alignof(Empty64) << "\n";
}

可能的输出：

对齐字节数
- char             ：1
- 指针             ：8
- Foo 类           ：4
- Foo2 类          ：16
- 空类             ：1
- alignas(64) Empty：64

参阅

对齐要求 | 限制对象所能分配于其中的地址
alignas 说明符 (C++11) | 指定该变量的存储应该按指定量对齐
alignment_of (C++11) | 获取类型的对齐要求 (类模板)


数组声明

< cpp‎ | language

声明数组类型的对象。

语法

数组声明是简单声明，其声明符拥有如下形式：

非指针声明符 [ 表达式(可选) ] 属性(可选)
非指针声明符 | - | 任意有效的 声明符，但在以 *、& 或 && 起始时必须用括号环绕。
表达式 | - | 求值为大于零的值的整型常量表达式 (C++14 前) std::size_t 类型的经转换常量表达式 (C++14 起)
属性 | - | (C++11 起) 可选的属性列表

形式为 T a[N]; 的声明，将 a 声明为由 N 个连续分配的 T 类型对象所组成的数组对象。数组元素拥有编号 0, …, N - 1，且可通过下标运算符 [] 访问，如 a[0], …, a[N - 1]。

数组可由任何（除 void 外的）基础类型、指针、成员指针、类、枚举，或从其他已知边界数组类型（这种情况下称数组是多维的）构成。换言之，只有除了未知边界数组以外的对象类型能成为数组类型的元素类型。拥有不完整元素类型的数组类型也是不完整类型。

能在数组的指针或引用的声明中以可能受约束的 (C++20 起) auto 说明符为数组元素类型，这会从初始化器或函数实参 (C++14 起)推导元素类型，例如若 a 为 int[42] 类型左值则 auto (*p)[42] = &a; 合法。

 (C++11 起)

不存在引用的数组或函数的数组。

对数组类型（通过 typedef 或模板操作）应用 cv 限定符，会将限定符应用到其元素类型，但元素为 cv 限定类型的任何数组类型，则被认为拥有相同的 cv 限定性。

// a 与 b 拥有相同的 const 限定类型“含有 5 个 const char 元素的数组”
typedef const char CC;
CC a[5] = {};
typedef char CA[5];
const CA b = {};

在用于 new[] 表达式时，数组的大小可以为零；这种数组无元素：

int* p = new int[0]; // 访问 p[0] 或 *p 是未定义的
delete[] p; // 仍然要求清理

赋值

数组类型的对象不能作为整体修改：虽然它们是左值（即能取数组地址），但它们不能出现在赋值运算符的左侧：

int a[3] = {1, 2, 3}, b[3] = {4, 5, 6};
int (*p)[3] = &a; // OK：能取地址
a = b;            // 错误：a 是数组
struct { int c[3]; } s1, s2 = {3, 4, 5};
s1 = s2; // OK：隐式定义的复制赋值运算符可对数组类型的数据成员赋值

数组到指针的退化

存在从数组类型的左值和右值到指针类型的右值的隐式转换：它构造一个指向数组首元素的指针。凡在数组出现于不期待数组而期待指针的语境中时，均使用这个转换：

#include <iostream>
#include <numeric>
#include <iterator>

void g(int (&a)[3])
{
    std::cout << a[0] << '\n';
}

void f(int* p)
{
    std::cout << *p << '\n';
}

int main()
{
    int a[3] = {1, 2, 3};
    int* p = a;

    std::cout << sizeof a << '\n'  // 打印数组的大小
              << sizeof p << '\n'; // 打印指针的大小

    // 在可接受数组而不可接受指针的地方，只能使用数组
    g(a); // OK：函数以引用接受数组
//  g(p); // 错误

    for(int n: a)              // OK：数组可用于范围 for 循环
        std::cout << n << ' '; // 打印数组的各个元素
//  for(int n: p)              // 错误
//      std::cout << n << ' ';

    std::iota(std::begin(a), std::end(a), 7); // OK：begin 与 end 接受数组
//  std::iota(std::begin(p), std::end(p), 7); // 错误

    // 在可接受指针而不可接受数组处的地方，两者都可以使用
    f(a); // OK：函数接受指针
    f(p); // OK：函数接受指针

    std::cout << *a << '\n' // 打印首元素
              << *p << '\n' // 相同
              << *(a + 1) << ' ' << a[1] << '\n'  // 打印第二元素
              << *(p + 1) << ' ' << p[1] << '\n'; // 相同
}

多维数组

当数组的元素类型是另一数组时，称该数组是多维的：

// 含有 2 个【含有 3 个 int 元素的数组】元素的数组
int a[2][3] = {{1, 2, 3},
               {4, 5, 6}}; // 可视作 2 × 3 矩阵，以行为主布局

注意，应用数组到指针退化时，多维数组转换成指向其首元素的指针（例如，指向其首行或首平面的指针）：数组到指针退化仅应用一次。

int a[2];            // 含有 2 个 int 元素的数组
int* p1 = a;         // 退化到指向 a 的首元素的指针

int b[2][3];         // 含有 2 个【含有 3 个 int 元素的数组】元素的数组
// int** p2 = b;     // 错误：b 不退化到 int**
int (*p2)[3] = b;    // b 退化到指向 b 的首个 3 元素行的指针

int c[2][3][4];      // 含有 2 个【含有 3 个【含有 4 个 int 元素的数组】元素的数组】元素的数组
// int*** p3 = c;    // 错误：c 不退化到 int***
int (*p3)[3][4] = c; // c 退化到指向 c 首个 3 × 4 元素平面的指针

未知边界数组

如果在数组声明中省略 表达式，则声明的类型是“T 的未知边界数组”，这是一种不完整类型，除非在声明时带有聚合初始化器：

extern int x[];      // x 的类型是“边界未知的含有 int 元素的数组”
int a[] = {1, 2, 3}; // a 的类型是“含有 3 个 int 元素的数组”

因为数组元素不能具有未知边界数组类型，所以多维数组只能在第一个维度中有未知边界：

extern int a[][2]; // OK：边界未知的含有【含有 2 个 int 元素的数组】元素的数组
extern int b[2][]; // 错误：数组有不完整类型

可以构成到未知边界数组的引用和指针，但不能从已知边界的数组或指向已知边界数组的指针对其初始化或赋值。注意在 C 编程语言中，指向未知边界数组的指针与指向已知边界数组的指针兼容，从而可以双向转换和赋值。

extern int a1[];
int (&r1)[] = a1;  // OK
int (*p1)[] = &a1; // OK
int (*q)[2] = &a1; // 错误（但 C 中 OK）

int a2[] = {1, 2, 3};
int (&r2)[] = a2;  // 错误
int (*p2)[] = &a2; // 错误（但 C 中 OK）

指向未知边界数组的指针不能参与指针算术且不能用在下标运算符的左侧，但可以解引用。到未知边界数组的引用和指针无法作为函数形参。

数组右值

尽管数组无法从函数按值返回，且不能作为大多数转型表达式的目标，数组纯右值依然可以通过使用类型别名构成，并用花括号初始化的函数式转型来构造数组的临时量。

与类的纯右值类似，数组的纯右值由临时量实质化在求值时转换成亡值。

 (C++17 起)

可以通过访问类右值的数组成员，std::move 或其他返回右值引用的转型或函数调用来直接构成数组的亡值。

#include <iostream>
#include <type_traits>
#include <utility>

void f(int (&&x)[2][3])
{
    std::cout << sizeof x << '\n';
}

struct X
{
    int i[2][3];
} x;

template<typename T> using identity = T;

int main()
{
    std::cout << sizeof X().i << '\n';           // 数组的大小
    f(X().i);                                    // OK：绑定到亡值
//  f(x.i);                                      // 错误：不能绑定到左值

    int a[2][3];
    f(std::move(a));                             // OK：绑定到亡值

    using arr_t = int[2][3];
    f(arr_t{});                                  // OK：绑定到纯右值
    f(identity<int[][3]>{{1, 2, 3}, {4, 5, 6}}); // OK：绑定到纯右值

}

输出：

24
24
24
24
24

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 393 | C++98 | 未知边界的数组或引用不能为函数形参 | 它能
CWG 2397 | C++11 | auto 不能用作元素类型 | 它能

参阅


ASCII 码表

< cpp‎ | language

下列码表含有全部 128 个 ASCII 十进制 (dec) 、八进制 (oct) 、十六进制 (hex) 及字符 (ch) 编码。

dec | oct | hex | ch | dec | oct | hex | ch | dec | oct | hex | ch | dec | oct | hex | ch
0 | 0 | 00 | NUL (空) | 32 | 40 | 20 | (空格) | 64 | 100 | 40 | @ | 96 | 140 | 60 | `
1 | 1 | 01 | SOH (标题开始) | 33 | 41 | 21 | ! | 65 | 101 | 41 | A | 97 | 141 | 61 | a
2 | 2 | 02 | STX (正文开始) | 34 | 42 | 22 | " | 66 | 102 | 42 | B | 98 | 142 | 62 | b
3 | 3 | 03 | ETX (正文结束) | 35 | 43 | 23 | # | 67 | 103 | 43 | C | 99 | 143 | 63 | c
4 | 4 | 04 | EOT (传送结束) | 36 | 44 | 24 | $ | 68 | 104 | 44 | D | 100 | 144 | 64 | d
5 | 5 | 05 | ENQ (询问) | 37 | 45 | 25 | % | 69 | 105 | 45 | E | 101 | 145 | 65 | e
6 | 6 | 06 | ACK (确认) | 38 | 46 | 26 | & | 70 | 106 | 46 | F | 102 | 146 | 66 | f
7 | 7 | 07 | BEL (响铃) | 39 | 47 | 27 | ' | 71 | 107 | 47 | G | 103 | 147 | 67 | g
8 | 10 | 08 | BS (退格) | 40 | 50 | 28 | ( | 72 | 110 | 48 | H | 104 | 150 | 68 | h
9 | 11 | 09 | HT (横向制表) | 41 | 51 | 29 | ) | 73 | 111 | 49 | I | 105 | 151 | 69 | i
10 | 12 | 0a | LF (换行) | 42 | 52 | 2a | * | 74 | 112 | 4a | J | 106 | 152 | 6a | j
11 | 13 | 0b | VT (纵向制表) | 43 | 53 | 2b | + | 75 | 113 | 4b | K | 107 | 153 | 6b | k
12 | 14 | 0c | FF (换页) | 44 | 54 | 2c | , | 76 | 114 | 4c | L | 108 | 154 | 6c | l
13 | 15 | 0d | CR (回车) | 45 | 55 | 2d | - | 77 | 115 | 4d | M | 109 | 155 | 6d | m
14 | 16 | 0e | SO (移出) | 46 | 56 | 2e | . | 78 | 116 | 4e | N | 110 | 156 | 6e | n
15 | 17 | 0f | SI (移入) | 47 | 57 | 2f | / | 79 | 117 | 4f | O | 111 | 157 | 6f | o
16 | 20 | 10 | DLE (退出数据链) | 48 | 60 | 30 | 0 | 80 | 120 | 50 | P | 112 | 160 | 70 | p
17 | 21 | 11 | DC1 (设备控制1) | 49 | 61 | 31 | 1 | 81 | 121 | 51 | Q | 113 | 161 | 71 | q
18 | 22 | 12 | DC2 (设备控制2) | 50 | 62 | 32 | 2 | 82 | 122 | 52 | R | 114 | 162 | 72 | r
19 | 23 | 13 | DC3 (设备控制3) | 51 | 63 | 33 | 3 | 83 | 123 | 53 | S | 115 | 163 | 73 | s
20 | 24 | 14 | DC4 (设备控制4) | 52 | 64 | 34 | 4 | 84 | 124 | 54 | T | 116 | 164 | 74 | t
21 | 25 | 15 | NAK (反确认) | 53 | 65 | 35 | 5 | 85 | 125 | 55 | U | 117 | 165 | 75 | u
22 | 26 | 16 | SYN (同步空闲) | 54 | 66 | 36 | 6 | 86 | 126 | 56 | V | 118 | 166 | 76 | v
23 | 27 | 17 | ETB (传输块结束) | 55 | 67 | 37 | 7 | 87 | 127 | 57 | W | 119 | 167 | 77 | w
24 | 30 | 18 | CAN (取消) | 56 | 70 | 38 | 8 | 88 | 130 | 58 | X | 120 | 170 | 78 | x
25 | 31 | 19 | EM (媒介结束) | 57 | 71 | 39 | 9 | 89 | 131 | 59 | Y | 121 | 171 | 79 | y
26 | 32 | 1a | SUB (替换) | 58 | 72 | 3a | : | 90 | 132 | 5a | Z | 122 | 172 | 7a | z
27 | 33 | 1b | ESC (退出) | 59 | 73 | 3b | ; | 91 | 133 | 5b | [ | 123 | 173 | 7b | {
28 | 34 | 1c | FS (文件分隔符) | 60 | 74 | 3c | < | 92 | 134 | 5c | \ | 124 | 174 | 7c | |
29 | 35 | 1d | GS (组分隔符) | 61 | 75 | 3d | = | 93 | 135 | 5d | ] | 125 | 175 | 7d | }
30 | 36 | 1e | RS (记录分隔符) | 62 | 76 | 3e | > | 94 | 136 | 5e | ^ | 126 | 176 | 7e | ~
31 | 37 | 1f | US (单元分隔符) | 63 | 77 | 3f | ? | 95 | 137 | 5f | _ | 127 | 177 | 7f | DEL (删除)

注意：在 Unicode 中， ASCII 字符块被称作 U+0000..U+007F 基础拉丁（ Basic Latin ）。

示例

#include <iostream>
int main()
{
    std::cout << "Printable ASCII:\n";
    for (char i = 32; i < 127; ++i) {
        std::cout << i << ' ';
        if (i % 16 == 15)
            std::cout << '\n';
    }
}

可能的输出：

Printable ASCII:
  ! " # $ % & ' ( ) * + , - . /
0 1 2 3 4 5 6 7 8 9 : ; < = > ?
@ A B C D E F G H I J K L M N O
P Q R S T U V W X Y Z [ \ ] ^ _
` a b c d e f g h i j k l m n o
p q r s t u v w x y z { | } ~

参阅


汇编声明

< cpp‎ | language

汇编（asm）声明 给予在 C++ 程序中嵌入汇编语言源代码的能力。此声明受条件性支持且由实现定义，意思是它可以不存在，而且即使实现有所提供，它也并不拥有固定的含义。

语法

属性(可选) asm ( 字符串字面量 ) ;
属性 | - | (C++11 起) 任意数量的属性
字符串字面量 | - | 一个字符串字面量

解释

字符串字面量 通常是以汇编语言编写的短程序，该程序会在执行这条声明时执行。不同的 C++ 编译器的汇编声明规则有巨大差异，和与周围的 C++ 代码之间交互的约定也不同。

与其他块声明一样，该声明可出现于块（函数体或其他复合语句）内，并且与所有其他声明一样，此声明也可以在块外出现。

示例

这里演示 GCC 提供的两种内联汇编语法。此程序只在 x86-64 上的 Linux 下正确工作。

#include <iostream>

extern "C" int func();
// func 的定义以汇编语言书写
// 原始字符串字面量可以很有用
asm(R"(
.globl func
    .type func, @function
    func:
    .cfi_startproc
    movl $7, %eax
    ret
    .cfi_endproc
)");

int main()
{
    int n = func();
    // 扩展内联汇编
    asm ("leal (%0,%0,4),%0"
         : "=r" (n)
         : "0" (n));
    std::cout << "7*5 = " << n << std::endl; // 冲刷缓冲区是有意的

    // 标准内联汇编
    asm ("movq $60, %rax\n\t" // Linux 上的“退出”的系统调用序号
         "movq $2,  %rdi\n\t" // 此程序返回 2
         "syscall");
}

输出：

7*5 = 35

外部链接

  • GCC 内联汇编 HOWTO
  • IBM XL C/C++ 内联汇编
  • Intel C++ 内联汇编
  • Visual Studio 2013 内联汇编器
  • Sun Studio 12 Asm 语句
  • 基于 Itanium 的 HP-UX 的内联汇编

参阅


属性说明符序列(C++11 起)

< cpp‎ | language

为类型、对象、代码等引入由实现定义的属性。

[[属性]] [[属性1, 属性2, 属性3(实参)]] [[命名空间::属性(实参)]] alignas-说明符

正式而言，语法是

[[ 属性列表 ]] | (C++11 起)
[[ using 属性命名空间 : 属性列表 ]] | (C++17 起)

其中 属性列表 是由逗号分隔的零或更多个 属性 的序列（可以以指示包展开的省略号 ... 结束）

标识符
属性命名空间 :: 标识符
标识符 ( 实参列表 )
属性命名空间 :: 标识符 ( 实参列表 )
1) 简单属性，例如 [[noreturn]]
2) 有命名空间的属性，例如 [[gnu::unused]]
3) 有实参的属性，例如 [[deprecated("because")]]
4) 既有命名空间又有实参列表的属性

若 using: namespace 出现在属性列表开端，则属性列表中的其他属性均不得指定命名空间：由 using 所指定的命名空间会应用到所有这些属性：

[[using CC: opt(1), debug]] // 同 [[CC::opt(1), CC::debug]]
[[using CC: CC::opt(1)]] // 错误：不能结合 using 和有作用域属性
 (C++17 起)

解释

属性为各种由实现定义的语言扩展（例如 GNU 与 IBM 的语言扩展 __attribute__((...))，微软的语言扩展 __declspec() 等）提供了统一化的语法。

属性可用在 C++ 程序中的几乎所有位置，而且可应用于几乎所有事物：类型、变量、函数、名字、代码块、整个翻译单元，不过每个特定的属性都只在实现允许范围内有效：[[expect_true]] 可能是只能与 if，而非与类声明一同使用的属性，[[omp::parallel()]] 可能是应用到代码块或 for 循环，而非到类型 int 等的属性。（请注意以上两个属性只是虚构的例子，有关标准与一些非标准属性请见下文）

在声明中，属性既可以出现在整个声明之前，也可以直接跟在被声明实体的名字之后，这些情况下它们被组合起来。大多数其他情形中，属性应用于直接位于其之前的实体。

虽然 alignas 说明符拥有不同的语法，但它是属性序列说明符的一部分。它可以出现于 [[...]] 属性出现处，并可与它们混合（假设此处允许使用 alignas）

两个连续的方括号记号（[[）只能出现于引入属性说明符之处，或在属性实参之内。

void f() {
  int y[3];
  y[[] { return 0; }()] = 1;  // 错误
  int i [[cats::meow([[]])]]; // OK
}

除了以下所列出的标准属性之外，实现还可能支持任意拥有由实现定义的行为的非标准属性。所有实现所未知的属性均被忽略，且不产生错误。 (C++17 起)

无 属性命名空间 的属性与名字以 std 或 std 后随一或多个数字的 属性命名空间 为未来标准化保留。即每个非标准属性都在实现提供的 属性命名空间 中，例如 [[gnu::may_alias]]、 [[clang::trivial_abi]] 和 [[msvc::noop_dtor]]。

 (C++20 起)

标准属性

C++ 标准仅定义下列属性。

[[noreturn]](C++11) | 指示函数不返回
[[carries_dependency]](C++11) | 指示释放消费 std::memory_order 中的依赖链传入和传出该函数。
[[deprecated]](C++14) [[deprecated("原因")]](C++14) | 指示允许使用声明有此属性的名称或实体，但因 原因 而不鼓励使用。
[[fallthrough]](C++17) | 指示从前一 case 标号直落是有意的，而在发生直落时给出警告的编译器不应该为此诊断。
[[nodiscard]](C++17) [[nodiscard("原因")]](C++20) | 鼓励编译器在返回值被舍弃时发布警告。
[[maybe_unused]](C++17) | 压制编译器在未使用实体上的警告，若存在。
[[likely]](C++20) [[unlikely]](C++20) | 指示编译器应该针对通过某语句的执行路径比任何其他执行路径更可能或更不可能的情况进行优化。
[[no_unique_address]](C++20) | 指示非静态数据成员不需要拥有不同于其类的所有其他非静态数据成员的地址。
[[optimize_for_synchronized]](TM TS) | 指示应该针对来自 synchronized 语句的调用来优化该函数定义

示例

[[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]]
inline int f(); // 声明 f 带四个属性

[[gnu::always_inline, gnu::const, gnu::hot, nodiscard]]
int f(); // 同上，但使用含有四个属性的单个属性说明符

// C++17:
[[using gnu : const, always_inline, hot]] [[nodiscard]]
int f[[gnu::always_inline]](); // 属性可出现于多个说明符中

int f() { return 0; }

int main() {}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2156R1 | C++11 | 每个标准属性在一个 属性列表 中最多只能出现一次 | 无限制次数

外部链接

  • GCC 中的属性
    • 这些属性可用作 [[gnu::...]] ，见此处
  • Clang 中的属性

参阅


C++ 属性： carries_dependency (C++11 起)

< cpp‎ | language‎ | attributes

指示释放消费 std::memory_order 中的依赖链传进和传出该函数，这允许编译器跳过不必要的内存栅栏指令。

语法

[[carries_dependency]]

解释

指示释放消费 std::memory_order 中的依赖链传进和传出该函数，这允许编译器跳过不必要的内存栅栏指令。

此属性可在两种情形中出现：

1) 它可应用于函数或 lambda 表达式的形参声明，该情况下它指示从该形参的初始化向该对象的左值到右值转换中携带依赖。
2) 它可应用于函数声明整体，该情况下它指示从返回值向函数调用表达式的求值中携带依赖。

此属性必须出现在任意翻译单元中某个函数或其形参之一的首个声明上。若另一翻译单元中的该函数或其形参的首个声明上未使用该属性，则程序非良构；不要求诊断。

用法示例见 std::kill_dependency 。


C++ 属性： deprecated (C++14 起)

< cpp‎ | language‎ | attributes

指示声明有此属性的名字或实体被弃用，即允许但因故不鼓励使用。

语法

[[deprecated]] | (1)
[[deprecated( 字符串字面量 )]] | (2)
字符串字面量 - 能用于解释弃用的理由并/或提议代替用实体的文本

解释

指示允许使用声明有此属性的名称或实体，但因故不鼓励使用。编译器通常会对其使用情况发出警告。若指定了 字符串字面量，则它通常被包含于警告中。

下列名字或实体的声明中允许使用这个属性：

  • class/struct/union：struct [[deprecated]] S;，
  • typedef 名，也包括别名声明：[[deprecated]] typedef S* PS;、using PS [[deprecated]] = S*;，
  • 变量，包括静态数据成员：[[deprecated]] int x;，
  • 非静态数据成员：union U { [[deprecated]] int n; };，
  • 函数：[[deprecated]] void f();，
  • 命名空间：namespace [[deprecated]] NS { int x; }，
  • 枚举：enum [[deprecated]] E {};，
  • 枚举项：enum { A [[deprecated]], B [[deprecated]] = 42 };，
  • 模板特化：template<> struct [[deprecated]] X<int> {};。

声明时未弃用的名字可被重声明为 deprecated。声明为 deprecated 的名字不能通过重声明它而不带此属性变为未弃用。

示例

#include <iostream>

[[deprecated]]
void TriassicPeriod() {
    std::clog << "Triassic Period: [251.9 - 208.5] million years ago.\n";
}

[[deprecated("Use NeogenePeriod() instead.")]]
void JurassicPeriod() {
    std::clog << "Jurassic Period: [201.3 - 152.1] million years ago.\n";
}

[[deprecated("Use calcSomethingDifferently(int).")]]
int calcSomething(int x) {
    return x * 2;
}

int main()
{
    TriassicPeriod();
    JurassicPeriod();
}

可能的输出：

Triassic Period: [251.9 - 208.5] million years ago.
Jurassic Period: [201.3 - 152.1] million years ago.

main.cpp:20:5: warning: 'TriassicPeriod' is deprecated [-Wdeprecated-declarations]
    TriassicPeriod();
    ^
main.cpp:3:3: note: 'TriassicPeriod' has been explicitly marked deprecated here
[[deprecated]]
  ^
main.cpp:21:5: warning: 'JurassicPeriod' is deprecated: Use NeogenePeriod() instead [-Wdeprecated-declarations]
    JurassicPeriod();
    ^
main.cpp:8:3: note: 'JurassicPeriod' has been explicitly marked deprecated here
[[deprecated("Use NeogenePeriod() instead")]]
  ^
2 warnings generated.

参阅


C++ 属性： fallthrough (C++17 起)

< cpp‎ | language‎ | attributes

指示从前一标号直落是有意的，而在发生直落时给出警告的编译器不应诊断它。

语法

[[fallthrough]]

解释

仅可应用到空语句以创建直落语句（ fallthrough statement ）： [[fallthrough]]; 。

直落语句仅可用于 switch 语句中，其中待执行的下个语句是该 switch 语句的带 case 或 default 标号的语句。若直落语句在循环中，则下个（带标号）语句必须是该循环的同一迭代的一部分。

指示从前一标号直落是有意的，而在发生直落时给出警告的编译器不应诊断它。

示例

void f(int n) {
  void g(), h(), i();
  switch (n) {
    case 1:
    case 2:
      g();
     [[fallthrough]];
    case 3: // 直落时不警告
      h();
    case 4: // 编译器可在发生直落时警告
      if(n < 3) {
          i();
          [[fallthrough]]; // OK
      }
      else {
          return;
      }
    case 5:
      while (false) {
        [[fallthrough]]; // 非良构：下一语句不是同一迭代的一部分
      }
    case 6:
      [[fallthrough]]; // 非良构：无后继的 case 或 default 标号
  }
}

参阅


C++ 属性： likely, unlikely (C++20 起)

< cpp‎ | language‎ | attributes

允许编译器为包含该语句的执行路径，比任何其他不包含该语句的执行路径，更可能或更不可能的情况进行优化。

语法

[[likely]] | (1)
[[unlikely]] | (2)

解释

这些属性可应用于标号或语句（除了声明语句）。它们不可同时应用到同一标号或语句。

1) 应用到语句，允许编译器为包含该语句的执行路径，比任何其他不包含该语句的执行路径更可能的情况进行优化。
2) 应用到语句，允许编译器为包含该语句的执行路径，比任何其他不包含该语句的执行路径更不可能的情况进行优化。

当且仅当执行路径中含有到某个标号的跳转时，才认为该执行路径包含该标号：

int f(int i)
{
    switch(i) {
    case 1: [[fallthrough]];
    [[likely]] case 2: return 1;
    }
    return 2;
}

i == 2 被认为比 i 的任何其他值更可能，但 [[likely]] 在 i == 1 的情况无效果，尽管它直落到 case 2: 标号。

示例

#include <iostream>

int f(int i)
{
    if (i < 0) [[unlikely]] {
        return 0;
    }

    return 1;
}

int main()
{
    std::cout << f(-1) << std::endl;

    std::cout << f(1) << std::endl;
}


C++ 属性： maybe_unused (C++17 起)

< cpp‎ | language‎ | attributes

抑制针对未使用实体的警告。

语法

[[maybe_unused]]

解释

此属性可出现在下列实体的声明中：

  • class/struct/union：struct [[maybe_unused]] S;，
  • typedef，包括别名声明：[[maybe_unused]] typedef S* PS;，using PS [[maybe_unused]] = S*;，
  • 变量，包括静态数据成员：[[maybe_unused]] int x;，
  • 非静态数据成员：union U { [[maybe_unused]] int n; };，
  • 函数：[[maybe_unused]] void f();，
  • 枚举：enum [[maybe_unused]] E {};，
  • 枚举项：enum { A [[maybe_unused]], B [[maybe_unused]] = 42 };。

若编译器针对未使用实体发布警告，则对于任何声明为 maybe_unused 的实体抑制该警告。

示例

#include <cassert>

[[maybe_unused]] void f([[maybe_unused]] bool thing1,
                        [[maybe_unused]] bool thing2)
{
   [[maybe_unused]] bool b = thing1 && thing2;
   assert(b); // 发行模式中，assert 在编译中被去掉，因而未使用 b
              // 无警告`，因为它被声明为 [[maybe_unused]]
} // 未使用参数 thing1 与 thing2，无警告

int main() {}

参阅


C++ 属性： no_unique_address (C++20 起)

< cpp‎ | language‎ | attributes

指示此数据成员不需要具有不同于其类的所有其他非静态数据成员的地址。

语法

[[no_unique_address]]

解释

应用到非位域非静态数据成员的声明中所声明的名字。

指示此数据成员不需要具有不同于其类的所有其他非静态数据成员的地址。这表示若该成员拥有空类型（例如无状态分配器），则编译器可将它优化为不占空间，正如同假如它是空基类一样。若该成员非空，则其中的任何尾随填充空间亦可复用于存储其他数据成员。

示例

#include <iostream>

struct Empty {}; // 空类

struct X {
    int i;
    Empty e;
};

struct Y {
    int i;
    [[no_unique_address]] Empty e;
};

struct Z {
    char c;
    [[no_unique_address]] Empty e1, e2;
};

struct W {
    char c[2];
    [[no_unique_address]] Empty e1, e2;
};

int main()
{
    // 任何空类类型对象的大小至少为 1
    static_assert(sizeof(Empty) >= 1);

    // 至少需要多一个字节以给 e 唯一地址
    static_assert(sizeof(X) >= sizeof(int) + 1);

    // 优化掉空成员
    std::cout << "sizeof(Y) == sizeof(int) is " << std::boolalpha
              << (sizeof(Y) == sizeof(int)) << '\n';

    // e1 与 e2 不能共享同一地址，因为它们拥有相同类型，尽管它们标记有 [[no_unique_address]]。
    // 然而，其中一者可以与 c 共享地址。
    static_assert(sizeof(Z) >= 2);

    // e1 与 e2 不能拥有同一地址，但它们之一能与 c[0] 共享，而另一者与 c[1] 共享
    std::cout << "sizeof(W) == 2 is " << (sizeof(W) == 2) << '\n';
}

可能的输出：

sizeof(Y) == sizeof(int) is true
sizeof(W) == 2 is true


C++ 属性： nodiscard (C++17 起)

< cpp‎ | language‎ | attributes

若从并非转型到 void 的弃值表达式中，调用声明为 nodiscard 的函数，或调用按值返回声明为 nodiscard 的枚举或类的函数，则鼓励编译器发布警告。

语法

[[nodiscard]] | (1) |
[[nodiscard( 字符串字面量 )]] | (2) | (C++20 起)
字符串字面量 - 能用于解释结果不应被舍弃的理由的文本

解释

出现在函数声明、枚举声明或类声明中。

若从并非转型到 void 的弃值表达式中，

  • 调用声明为 nodiscard 的函数，或
  • 调用按值返回声明为 nodiscard 的枚举或类的函数，或
  • 以显式类型转换或 static_cast 形式调用声明为 nodiscard 的构造函数，或
  • 以显式类型转换或 static_cast 形式构造声明为 nodiscard 的枚举或类的对象，

则鼓励编译器发布警告。

若指定了 字符串字面量，则它通常被包含于警告中。

 (C++20 起)

示例

struct [[nodiscard]] error_info { };
error_info enable_missile_safety_mode();
void launch_missiles();
void test_missiles() {
   enable_missile_safety_mode(); // 编译器可在舍弃 nodiscard 值时发布警告
   launch_missiles();
}
error_info& foo();
void f1() {
    foo(); // 并非按值返回 nodiscard 类型，无警告
}

标准库

下列标准函数声明为带 nodiscard 属性：

分配函数
operator newoperator new[]
 分配函数
(函数)
allocate
 分配未初始化的存储
(std::allocator<T> 的公开成员函数)
allocate
[静态]
 用分配器分配未初始化的存储
(std::allocator_traits<Alloc> 的公开静态成员函数)
allocate
 分配内存
(std::pmr::memory_resource 的公开成员函数)
allocate
 分配内存
(std::pmr::polymorphic_allocator<T> 的公开成员函数)
allocate
 用外层分配器分配未初始化存储
(std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...> 的公开成员函数)
间接访问
launder
(C++17)
 指针优化屏障
(函数模板)
assume_aligned
(C++20)
 告知编译器指针已对齐
(函数模板)
检查是否为空的函数
empty
(C++17)
 检查容器是否为空
(函数模板)
empty
 检查结点柄是否为空
(node handle 的公开成员函数)
empty
(C++11)
 检查容器是否为空
(std::array<T,N> 的公开成员函数)
empty
 检查字符串是否为空
(std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
empty
 检查视图是否为空
(std::basic_string_view<CharT,Traits> 的公开成员函数)
empty
 检查容器是否为空
(std::deque<T,Allocator> 的公开成员函数)
empty
(C++11)
 检查容器是否为空
(std::forward_list<T,Allocator> 的公开成员函数)
empty
 检查容器是否为空
(std::list<T,Allocator> 的公开成员函数)
empty
 检查容器是否为空
(std::map<Key,T,Compare,Allocator> 的公开成员函数)
empty
 检查匹配是否成功
(std::match_results<BidirIt,Alloc> 的公开成员函数)
empty
 检查容器是否为空
(std::multimap<Key,T,Compare,Allocator> 的公开成员函数)
empty
 检查容器是否为空
(std::multiset<Key,Compare,Allocator> 的公开成员函数)
empty
 检查底层容器是否为空
(std::priority_queue<T,Container,Compare> 的公开成员函数)
empty
 检查底层容器是否为空
(std::queue<T,Container> 的公开成员函数)
empty
 检查容器是否为空
(std::set<Key,Compare,Allocator> 的公开成员函数)
empty
 检查序列是否为空
(std::span<T,Extent> 的公开成员函数)
empty
 检查底层容器是否为空
(std::stack<T,Container> 的公开成员函数)
empty
(C++11)
 检查容器是否为空
(std::unordered_map<Key,T,Hash,KeyEqual,Allocator> 的公开成员函数)
empty
(C++11)
 检查容器是否为空
(std::unordered_multimap<Key,T,Hash,KeyEqual,Allocator> 的公开成员函数)
empty
(C++11)
 检查容器是否为空
(std::unordered_multiset<Key,Hash,KeyEqual,Allocator> 的公开成员函数)
empty
(C++11)
 检查容器是否为空
(std::unordered_set<Key,Hash,KeyEqual,Allocator> 的公开成员函数)
empty
 检查容器是否为空
(std::vector<T,Allocator> 的公开成员函数)
empty
 检查路径是否为空
(std::filesystem::path 的公开成员函数)
杂项
async
(C++11)
 异步运行一个函数（有可能在新线程中执行），并返回保有其结果的 std::future
(函数模板)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P1771R1 | C++17 | 构造函数上的 [[nodiscard]] 无效果 | 若舍弃该对象则能导致警告

参阅


C++ 属性： noreturn (C++11 起)

< cpp‎ | language‎ | attributes

指示函数不返回。

语法

[[noreturn]]

解释

指示函数不返回。

此属性仅应用到函数声明中正在声明的函数名。若拥有此属性的函数实际上返回，则行为未定义。

若函数的任何声明指定此属性，则其首个声明必须指定它。若函数在一个翻译单元中声明为带 [[noreturn]] 属性，而同一函数在另一翻译单元中声明为不带 [[noreturn]] 属性，则程序非良构；不要求诊断。

示例

[[ noreturn ]] void f() {
  throw "error";
  // OK
}

void q [[ noreturn ]] (int i) {
  // 若以 <= 0 的参数调用则行为未定义
  if (i > 0) {
    throw "positive";
  }
}

// void h() [[noreturn]]; // 错误：属性应用到 h 的函数类型，而非 h 自身

标准库

下列标准函数声明带有 noreturn 属性：

终止函数
_Exit
(C++11)
 导致正常的程序终止，不进行清理
(函数)
abort
 导致非正常的程序终止（不进行清理）
(函数)
exit
 导致正常的程序终止并进行清理
(函数)
quick_exit
(C++11)
 导致快速程序终止，不进行完全的清理
(函数)
terminate
 异常处理失败时调用的函数
(函数)
unexpected
(C++17 中移除)
 违背动态异常说明时调用的函数
(函数)
始终抛出异常的函数
rethrow_exception
(C++11)
 从一个 std::exception_ptr 抛出异常
(函数)
rethrow_nested
 抛出其所存储的异常
(std::nested_exception 的公开成员函数)
throw_with_nested
(C++11)
 抛出实参，带上混入的 std::nested_exception
(函数模板)
非局部跳转 (C++17 起)
longjmp
 跳转到指定位置
(函数)

参阅


C++ 属性： optimize_for_synchronized (TM TS)

< cpp‎ | language‎ | attributes

指示应该为来自 synchronized 语句的调用优化函数定义。

语法

[[optimize_for_synchronized]]

解释

应用到函数声明中正在声明的名字，该声明必须是函数的首个声明。

指示应该为来自 synchronized 语句的调用优化函数定义。具体而言，它避免串行化调用函数的同步块，并使得该函数对于大多数调用，但非全部调用事务安全。

示例

本节未完成
原因：暂无示例


占位类型说明符 (C++11 起)

< cpp‎ | language

对于变量，指定要从其初始化器自动推导出其类型。

对于函数，指定要从其 return 语句推导出其返回类型。

 (C++14 起)

对于非类型模板形参，指定要从实参推导出其类型。

 (C++17 起)

语法

类型约束(可选) auto | (1) | (C++11 起)
类型约束(可选) decltype(auto) | (2) | (C++14 起)
类型约束 - (C++20 起) 概念名，可以有限定或后随被 <> 包围的模板实参列表
1) 用模板实参推导的规则推导类型。
2) 类型为 decltype(expr)，其中 expr 是初始化器。

占位符 auto 可伴随如 const 或 & 这样的修饰符，它们参与类型推导。占位符 decltype(auto) 必须是被声明类型的唯一组分。 (C++14 起)

解释

占位类型说明符可出现于下列语境：

  • 变量的类型说明符中：auto x = expr;。从初始化器推导类型。
    如果占位类型说明符是 auto 或 类型约束 auto (C++20 起)，那么采用从函数调用进行模板实参推导的规则，从初始化器推导变量的类型（细节见其他语境）。
    例如，给定 const auto& i = expr;，则 i 的类型恰是某个虚构模板 template<class U> void f(const U& u) 中参数 u 的类型（假如函数调用 f(expr) 通过编译）。因此，取决于初始化器，auto&& 可被推导成左值引用或右值引用类型，这被用于基于范围的 for 循环。

    如果占位类型说明符是 decltype(auto) 或 类型约束 decltype(auto) (C++20 起)，那么推导出的类型是 decltype(expr)，其中 expr 是初始化器。

             (C++14 起)

    如果用占位类型说明符声明多个变量，那么推导出的类型必须互相匹配。例如，声明 auto i = 0, d = 0.0; 非良构，而声明 auto i = 0, *p = &i; 良构并将 auto 推导为 int。

  • new 表达式中的类型标识。从初始化器推导类型。对于 new T init（其中 T 含占位符类型，而 init 是带括号的初始化器或带花括号的初始化器列表），如同在虚设的声明 T x init; 中对变量 x 一般推导 T 的类型。
  • (C++14 起) 函数或 lambda 表达式的返回类型中：auto& f();。从其未舍弃的 (C++17 起) return 语句的操作数推导返回类型。
    见返回类型推导。
  • (C++17 起) 非类型模板形参的形参声明中：template<auto I> struct A;。从对应的实参推导其类型。

auto 说明符亦可出现在显式类型转换的简单类型说明符中： auto(expr) 与 auto{expr} 。从表达式推导其类型。

 (C++23 起)

此外，auto 与 类型约束 auto (C++20 起) 还可出现于：

  • lambda 表达式的形参声明：[](auto&&){}。这种 lambda 表达式是泛型 lambda。
  • (C++20 起) 函数形参声明：void f(auto);。这种函数声明引入简写函数模板。
 (C++14 起)

类型约束

如果 类型约束 存在，令 T 为该占位符的被推导类型，那么 T 必须满足 类型约束 的立即声明的约束。即，

  • 如果 类型约束 是 Concept<A1, ..., An>，那么约束表达式 Concept<T, A1, ..., An> 必须合法并返回 true；
  • 否则（类型约束 是无实参列表的 Concept），约束表达式 Concept<T> 必须合法并返回 true。
 (C++20 起)

注解

C++11 之前，auto 具有存储期说明符的语义。

不允许在一个声明中混合 auto 的变量和函数，如 auto f() -> int, i = 0;。

auto 说明符也可以用于后随尾随返回类型的函数声明符，此时返回类型为其尾随返回类型（它也可以是占位符类型）。

auto (*p)() -> int; // 声明指向【返回 int 的函数】的指针
auto (*q)() -> auto = p; // 声明 q 为指向【返回 T 的函数】的指针
                         // 其中 T 从 p 的类型推导

auto 说明符也可以用于结构化绑定声明。

 (C++17 起)

auto 关键词也可以用于嵌套名说明符。形如 auto:: 的嵌套名说明符是一个占位符，它会遵循受约束类型占位符的推导规则被替换为某个类或枚举类型。

 (概念 TS)

示例

#include <iostream>
#include <utility>

template<class T, class U>
auto add(T t, U u) { return t + u; } // 返回类型是 operator+(T, U) 的类型

// 在其所调用的函数返回引用的情况下
// 函数调用的完美转发必须用 decltype(auto)
template<class F, class... Args>
decltype(auto) PerfectForward(F fun, Args&&... args)
{
    return fun(std::forward<Args>(args)...);
}

template<auto n> // C++17 auto 形参声明
auto f() -> std::pair<decltype(n), decltype(n)> // auto 不能从花括号初始化器列表推导
{
    return {n, n};
}

int main()
{
    auto a = 1 + 2;          // a 的类型是 int
    auto b = add(1, 1.2);    // b 的类型是 double
    static_assert(std::is_same_v<decltype(a), int>);
    static_assert(std::is_same_v<decltype(b), double>);

    auto c0 = a;             // c0 的类型是 int，保有 a 的副本
    decltype(auto) c1 = a;   // c1 的类型是 int，保有 a 的副本
    decltype(auto) c2 = (a); // c2 的类型是 int&，它是 a 的别名
    std::cout << "通过 c2 修改前，a = " << a << '\n';
    ++c2;
    std::cout << "通过 c2 修改后，a = " << a << '\n';

    auto [v, w] = f<0>(); // 结构化绑定声明

    auto d = {1, 2}; // OK：d 的类型是 std::initializer_list<int>
    auto n = {5};    // OK：n 的类型是 std::initializer_list<int>
//  auto e{1, 2};    // C++17 起错误，之前是 std::initializer_list<int>
    auto m{5};       // OK：DR N3922 起 m 的类型是 int，之前是 initializer_list<int>
//  decltype(auto) z = { 1, 2 } // 错误：{1, 2} 不是表达式

    // auto 常用于无名类型，例如 lambda 表达式的类型
    auto lambda = [](int x) { return x + 3; };

//  auto int x; // 于 C++98 合法，C++11 起错误
//  auto x;     // 于 C 合法，于 C++ 错误

    [](...){}(c0, c1, v, w, d, n, m, lambda); // 阻止“变量未使用”警告
}

可能的输出：

通过 c2 修改前，a = 3
通过 c2 修改后，a = 4


位域

< cpp‎ | language

声明具有以位为单位的明确大小的类数据成员。相邻的位域成员可以打包成共享和跨过各个字节。

位域声明是使用下列声明符的类数据成员声明：

标识符(可选) 属性(可选) : 大小 | (1) |
标识符(可选) 属性(可选) : 大小 花括号或等号初始化器 | (2) | (C++20 起)

位域的类型由声明语法的 声明说明符序列 引入.

属性 | - | (C++11 起) 可选的任意数量属性的序列
标识符 | - | 被声明的位域名。名字是可选的：无名位域引入指定数量的填充位
大小 | - | 值大于或等于零的整型常量表达式。大于零时，这是位域将占有的位数。零值只能用于无名位域并具有特殊含义：它指定类定义中的下个位域应始于分配单元的边界。
花括号或等号初始化器 | - | 此位域所使用的默认成员初始化器

解释

位域的类型只能是整型或枚举类型。

位域不能是静态数据成员。

没有位域纯右值：左值到右值转换始终生成位域底层类型的对象。

位域中的位数设置其所能保有的值的极限：

#include <iostream>
struct S {
 // 三位的无符号位域，
 // 允许的值为 0...7
 unsigned int b : 3;
};
int main()
{
    S s = {6};
    ++s.b; // 在位域中存储值 7
    std::cout << s.b << '\n';
    ++s.b; // 值 8 不适合此位域
    std::cout << s.b << '\n'; // 正式来说是由实现定义的行为，通常为 0
}

可能的输出：

7
0

多个相邻位域通常打包在一起（尽管此行为是实现定义的）：

#include <iostream>
struct S {
    // 将通常占用 2 字节：
    // 3 位：b1 的值
    // 2 位：不使用
    // 6 位：b2 的值
    // 2 位：b3 的值
    // 3 位：不使用
    unsigned char b1 : 3, : 2, b2 : 6, b3 : 2;
};
int main()
{
    std::cout << sizeof(S) << '\n'; // 通常打印 2
}

可能的输出：

2

特殊的零大小无名位域可用于强行打破填充。它指定下个位域始于其分配单元的开始处：

#include <iostream>
struct S {
    // 通常将占用 2 字节：
    // 3 位：b1 的值
    // 5 位：不使用
    // 6 位：b2 的值
    // 2 位：b3 的值
    unsigned char b1 : 3;
    unsigned char :0; // 开始新字节
    unsigned char b2 : 6;
    unsigned char b3 : 2;
};
int main()
{
    std::cout << sizeof(S) << '\n'; // 通常打印 2
}

可能的输出：

2

如果位域所指定的大小大于其类型的大小，那么值由类型所限制：std::uint8_t b : 1000; 仍会保有 0 与 255 间的值。额外位成为不使用的填充位。

因为位域不一定始于一个字节的开始处，所以不能取位域的地址。指向位域的指针和非 const 引用是不可行的。从位域初始化 const 引用时，将创建一个临时量（其类型是位域的类型），并以该位域的值复制初始化，而引用绑定到该临时量。

位域没有默认成员初始化器：int b : 1 = 0; 与 int b : 1 {0} 为非良构。

 (C++20 前)

在位域大小与默认初始化器有歧义的情况下，选择组成合法大小的最长记号序列：

int a;
const int b = 0;
struct S {
    // 简单情况
    int x1 : 8 = 42;                // OK："= 42" 是花括号或等号初始化器
    int x2 : 8 { 42 };              // OK："{ 42 }" 是花括号或等号初始化器
    // 歧义
    int y1 : true ? 8 : a = 42;     // OK：不存在花括号或等号初始化器
    int y2 : true ? 8 : b = 42;     // 错误：不能赋值给 const int
    int y3 : (true ? 8 : b) = 42;   // OK："= 42" 是花括号或等号初始化器
    int z : 1 || new int { 0 }; // OK：不存在花括号或等号初始化器
};
 (C++20 起)

注解

位域的下列性质由实现定义：

  • 以范围外的值对有符号位域进行赋值或初始化，或对有符号位域进行自增越过其范围，所产生的值。
  • 任何关于类对象中位域的实际分配细节：
  • 例如，在某些平台上，位域不跨过字节，其他平台上会跨过
  • 还有，在某些平台上，位域从左到右打包，其他为从右到左

在 C 编程语言中，位域的宽度不能超过底层类型的宽度，并且未显式标为 signed 或 unsigned 的 int 位域为有符号或无符号是实现定义的。例如，C 中 int b:3; 可能有值域 0..7 或 -4..3，但 C++ 中只允许后者。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 739 | C++98 | 不显式地为 signed 或 unsigned 的位域的符号性是实现定义的 | 与底层类型一致

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 11.4.9 Bit-fields [class.bit]
  • C++17 标准（ISO/IEC 14882:2017）：
  • 12.2.4 Bit-fields [class.bit]
  • C++14 标准（ISO/IEC 14882:2014）：
  • 9.6 Bit-fields [class.bit]
  • C++11 标准（ISO/IEC 14882:2011）：
  • 9.6 Bit-fields [class.bit]
  • C++03 标准（ISO/IEC 14882:2003）：
  • 9.6 Bit-fields [class.bit]
  • C++98 标准（ISO/IEC 14882:1998）：
  • 9.6 Bit-fields [class.bit]

参阅

bitset
 实现常量长度的位数组
(类模板)


布尔字面量

< cpp‎ | language

语法

true | (1)
false | (2)

解释

布尔字面量是关键词 true 和 false。它们是 bool 类型的纯右值。

注解

从 bool 到其他类型的隐式转换见整数转换，从其他类型到 bool 的隐式转换见布尔转换。

示例

#include <iostream>

int main()
{
  std::cout << std::boolalpha
            << true << '\n'
            << false << '\n'
            << std::noboolalpha
            << true << '\n'
            << false << '\n';
}

输出：

true
false
1
0


break 语句

< cpp‎ | language

导致外围的 for、范围 for、while 或 do-while 循环或 switch 语句终止。

在用条件表达式和条件语句终止循环显得笨拙时使用。

语法

属性(可选) break ;

解释

此语句之后，控制将被转移到紧跟其外围循环或 switch 的下一位置。与退出任何代码块一样，在执行外围循环之后的下一行之前，所有在外围复合语句或循环/switch 的 条件 中声明的具有自动存储期的变量，按照它们构造的逆序销毁。

关键词

break

注解

break 语句不能用于跳出多重嵌套循环。这种情况可以使用 goto 语句。

示例

#include <iostream>

int main()
{
    int i = 2;
    switch (i) {
        case 1: std::cout << "1";   //<---- 可能会有警告：直落
        case 2: std::cout << "2";   //从此 case 标号开始执行（+警告）
        case 3: std::cout << "3";   //<---- 可能会有警告：直落
        case 4:                     //<---- 可能会有警告：直落
        case 5: std::cout << "45";
                break;              //终止后续语句的执行
        case 6: std::cout << "6";
    }

    std::cout << '\n';

    for (int j = 0; j < 2; j++) {
        for (int k = 0; k < 5; k++) {         // break 只会影响此循环
            if (k == 2) break;
            std::cout << j << k << " ";
        }
    }
}

输出：

2345
00 01 10 11

参阅

[[fallthrough]](C++17) 指示从上一个 case 标签的直落是有意的，会对直落进行警告的编译器不应对此进行诊断


用户定义转换函数

< cpp‎ | language

允许从类类型到其他类型的隐式转换或显式转换。

语法

转换函数的声明与非静态成员函数或函数模板类似，但没有参数或显式返回类型，并拥有下列形式的名字：

operator 转换类型标识 | (1) |
explicit operator 转换类型标识 | (2) | (C++11 起)
explicit ( 表达式 ) operator 转换类型标识 | (3) | (C++20 起)
1) 声明用户定义的转换函数，它参与所有隐式和显式转换。
2) 声明用户定义的转换函数，它只会参与直接初始化和显式转换。
3) 声明用户定义的转换函数，它是有条件显式的。

转换类型标识是一个类型标识，但它的声明器中不能出现函数与数组运算符 [] 或 ()（因此转换到诸如数组的指针的类型要求使用类型别名、typedef 或标识模板：见下文）。无论是否使用 typedef，转换类型标识都不能代表数组或函数类型。

尽管用户定义的转换函数的声明中不能出现返回类型，不过声明的文法中的 声明说明符序列可以存在并可包含除了 类型说明符 或关键词 static 之外的任何说明符。尤其是，它不仅允许 explicit，也允许说明符 inline、virtual 、constexpr (C++11 起)、consteval (C++20 起) 及 friend（注意 friend 要求有限定名：friend A::operator B();）。

如果在类 X 中声明这种成员函数，那么它会进行从 X 到 转换类型标识 的转换：

struct X {
    // 隐式转换
    operator int() const { return 7; }

    // 显式转换
    explicit operator int*() const { return nullptr; }

//   错误：转换类型标识中不允许出现数组运算符
//   operator int(*)[3]() const { return nullptr; }
    using arr_t = int[3];
    operator arr_t*() const { return nullptr; } // 可以通过 typedef 转换
//  operator arr_t () const; // 错误：不允许在任何情况下转换到数组
};

int main()
{
    X x;

    int n = static_cast<int>(x);   // OK：设 n 为 7
    int m = x;                     // OK：设 m 为 7

    int* p = static_cast<int*>(x);  // OK：设 p 为空
//  int* q = x; // 错误：没有隐式转换

    int (*pa)[3] = x;  // OK
}

解释

用户定义的转换函数在隐式转换的第二阶段被调用，第二阶段由零或一个转换构造函数或零或一个用户定义转换函数构成。

如果转换函数和转换构造函数都能用于进行某个用户定义转换，那么复制初始化和引用初始化语境中的重载决议同时考虑转换函数和转换构造函数，但在直接初始化语境中只考虑转换构造函数。

struct To {
    To() = default;
    To(const struct From&) {} // 转换构造函数
};

struct From {
    operator To() const {return To();} // 转换函数
};

int main()
{
    From f;
    To t1(f); // 直接初始化：调用构造函数
// （注意，如果转换构造函数不可用，那么会选择隐式的复制构造函数，且调用转换函数以准备其参数）
    To t2 = f; // 复制初始化：有歧义
// （注意，如果转换函数来自非 const 类型，例如 From::operator To();
//  那么它在这种情况下会替代构造函数被选中）
    To t3 = static_cast<To>(f); // 直接初始化：调用构造函数
    const To& r = f; // 引用初始化：有歧义
}

可以定义转换到其（可有 cv 限定的）自身类（或其引用），转换到其自身类的基类（或其引用），和转换到类型 void 的转换函数，但它无法作为转换序列的一部分执行，除非在某些情况下通过虚派发来执行：

struct D;
struct B {
    virtual operator D() = 0;
};
struct D : B
{
    operator D() override { return D(); }
};

int main()
{
    D obj;
    D obj2 = obj; // 不调用 D::operator D()
    B& br = obj;
    D obj3 = br; // 通过虚派发调用 D::operator D()
}

它也能用成员函数调用语法调用：

struct B {};
struct X : B {
    operator B&() { return *this; };
};

int main()
{
    X x;
    B& b1 = x;                  // 不调用 X::operatorB&()
    B& b2 = static_cast<B&>(x); // 不调用 X::operatorB&
    B& b3 = x.operator B&();    // 调用 X::operatorB&
}

显式调用转换函数时，类型标识 是贪心的：它是可作为合法 类型标识 的最长可能的记号序列（包括属性，如果存在）：

& x.operator int * a; // 分析为 & (x.operator int*) a
                      // 而非 & (x.operator int) * a

转换类型标识 中可以使用占位符 auto，以指定一个推导的返回类型：

struct X {
    operator int(); // OK
    operator auto() -> short;  // 错误：尾随返回类型不是此类语法的一部分
    operator auto() const { return 10; } // OK：推导的返回类型
};

注意：转换函数模板不允许具有推导的返回类型。

 (C++14 起)

转换函数可以继承而且可以是虚函数，但不能是静态函数。派生类中的转换函数不会隐藏基类中的转换函数，除非它们转换到同一类型。

转换函数可以是模板成员函数，例如 std::auto_ptr<T>::operator auto_ptr<Y>。其适用的特殊规则参阅成员模板和模板实参推导。


字符字面量

< cpp‎ | language

语法

'c字符 ' | (1) |
u8'c字符 ' | (2) | (C++17 起)
u'c字符 ' | (3) | (C++11 起)
U'c字符 ' | (4) | (C++11 起)
L'c字符 ' | (5) |
'c字符序列 ' | (6) |
L'c字符序列 ' | (7) |
c字符 - 下列之一：
  • 一个基础c字符
  • 一个转义序列，定义见转义序列
  • 一个通用字符名，定义见转义序列
基础c字符 - 来自源字符集 (C++23 前)翻译字符集 (C++23 起)去掉单引号（'）、反斜杠（\）和换行符后的字符
c字符序列 - 两个或更多个 c字符

解释

1) 通常字符字面量，例如 'a' 或 '\n' 或 '\13'。这种字面量具有 char 类型，且其值等于c字符 在执行字符集中的表示 (C++23 前)来自通常字面量编码的对应代码单元 (C++23 起)。
2) UTF-8 字符字面量，例如 u8'a'。这种字面量具有 char (C++20 前)char8_t (C++20 起) 类型，且其值等于 c字符 的 ISO 10646 码位值，只要码位值能以单个 UTF-8 编码单元表示（即 c字符 处于范围 0x0-0x7F（含边界）内）。
3) UTF-16 字符字面量，例如 u'猫'，但不是 u'🍌'（u'\U0001f34c'）。这种字面量具有 char16_t 类型，且其值等于 c字符 的 ISO 10646 码位值，只要该值能以单个 UTF-16 编码单元表示（即 c字符 处于范围 0x0-0xFFFF（含边界）内）。
4) UTF-32 字符字面量，例如 U'猫' 或 U'🍌'。这种字面量具有 char32_t 类型，且其值等于 c字符 的 ISO 10646 码位值。
5) 宽字符字面量，例如 L'β' 或 L'猫'。这种字面量具有 wchar_t 类型，且其值等于c字符 在执行宽字符集中的值 (C++23 前)来自宽字面量编码的对应代码单元 (C++23 起)。
6) 通常多字符字面量（条件性支持），例如 'AB'，具有 int 类型和实现定义的值。
7) 宽多字符字面量（条件性支持），例如 L'AB'，具有 wchar_t 类型和实现定义的值。

不可编码字符

(1) 中，如果 c字符 不是数值转义序列且无法在执行字符集中表示为单个字节，那么该字符字面量受条件性支持，具有 int 类型和实现定义的值。

(2-4) 中，如果 c字符 不是数值转义序列且无法在关联字符编码中表示为单个编码单元，那么字符字面量非良构。

(5) 中, 如果 c字符 不是数值转义序列且无法在执行宽字符集中表示为单个编码单元（例如在 wchar_t 为 16 位的 Windows 上的非 BMP 值），那么该字符字面量受条件性支持，具有 wchar_t 类型和实现定义的值。

数值转义序列

数值（八进制与十六进制）转义序列能用于指定字符的值。

如果字符字面量只包含一个数值转义序列，且该转义序列指定的值能以其类型的无符号版本表示，那么字符字面量拥有与指定值（可能在转换到字符类型后）相同的值。

UTF-N 字符字面量能拥有其类型可表示的任意值。即使该值对应的码位在 Unicode 中不合法或在 UTF-N 中无法以单个编码单元表示，该值的数值转义序列依然可以指定它。例如 u8'\xff' 良构并等于 char8_t(0xFF)。

 (C++23 起)

如果一个通常或宽字符字面量中用来指定值的数值转义序列指定了一个无法分别以 char 或 wchar_t 表示的值，那么该字符字面量的值由实现定义。 | (C++23 前)
如果一个有单个 c字符 的通常或宽字符字面量中用来指定值的数值转义序列所指定的值能分别以 char 或 wchar_t 的底层类型的无符号版本表示，那么该字面量的值是转换到字面量类型的有该无符号整数类型与指定值的整数值。否则程序非良构。 | (C++23 起)

如果一个 UTF-N 字符字面量中用来指定值的数值转义序列所指定的值不能以对应的 charN_t 表示，那么字符字面量的值由实现定义 (C++17 前)程序非良构 (C++17 起)。

 (C++11 起)

注解

多字符字面量是 C 从 B 编程语言继承而来的。尽管 C 或 C++ 标准不指定，大多数编译器（值得注意的例外是 MSVC ）也如 B 中所指定实现多字符字面量：字面量中的每个字符的值以大端序零填充右对齐顺序初始化结果整数的相继字节，例如 '\1' 的值为 0x00000001 而 '\1\2\3\4' 的值为 0x01020304 。

C 中，诸如 'a' 或 '\n' 之类的字符常量具有 int 类型，而非 char。

示例

#include <cstdint>
#include <iomanip>
#include <iostream>
#include <string_view>

template <typename CharT>
void dump(std::string_view s, const CharT c) {
    const uint8_t* data {reinterpret_cast<const uint8_t*>(&c)};
    std::cout << "'" << s << "' \t" << std::hex
              << std::uppercase << std::setfill('0');
    for (auto i {0U}; i != sizeof(CharT); ++i){
        std::cout << std::setw(2) << static_cast<unsigned>(data[i]) << ' ';
    }
    std::cout << '\n';
}

void print(std::string_view str) { std::cout << str; }

int main()
{
    print("字面量十六进制转储 \n"
          "─────── ───────────\n");

    dump("a", 'a');
    dump("🍌", '🍌'); // 实现定义
    print("\n");

    // 通常多字符字面量
    dump("ab", 'ab'); // 实现定义
    print("\n");

    // UTF-16 字符字面量
    char16_t uc1 = u'a'; dump("a", uc1);
    char16_t uc2 = u'¢'; dump("¢", uc2);
    char16_t uc3 = u'猫'; dump("猫", uc3);
//  char16_t uc4 = u'🍌'; dump("🍌", uc4); // 错误： 🍌 映射到两个 UTF-16 编码单元
    print("\n");

    // UTF-32 字符字面量
    char32_t Uc1 = U'a'; dump("a", Uc1);
    char32_t Uc2 = U'¢'; dump("¢", Uc2);
    char32_t Uc3 = U'猫'; dump("猫", Uc3);
    char32_t Uc4 = U'🍌'; dump("🍌", Uc4);
    print("\n");

    // 宽字符字面量
    wchar_t wc1 = L'a'; dump("a", wc1);
    wchar_t wc2 = L'¢'; dump("¢", wc2);
    wchar_t wc3 = L'猫'; dump("猫", wc3);
    wchar_t wc4 = L'🍌'; dump("🍌", wc4);
}

可能的输出：

字面量十六进制转储
─────── ───────────
'a'     61
'🍌'    8C 8D 9F F0

'ab'    62 61 00 00

'a'     61 00
'¢'     A2 00
'猫'    2B 73

'a'     61 00 00 00
'¢'     A2 00 00 00
'猫'    2B 73 00 00
'🍌'    4C F3 01 00

'a'     61 00 00 00
'¢'     A2 00 00 00
'猫'    2B 73 00 00
'🍌'    4C F3 01 00

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 912 | C++98 | 未指明不可编码的通常字符字面量 | 指定为条件性支持
CWG 1024 | C++98 | 要求支持多字符字面量 | 改为条件性支持
CWG 1656 | C++98 | 字符字面量中的数值转义序列的含义不明确 | 已指定

参阅

用户定义字面量 (C++11) 拥有用户定义后缀的字面量


类声明

< cpp‎ | language

类（class）与结构体（struct）是用户定义类型，以 类说明符 定义，它在声明语法的 声明说明符序列 中出现。类说明符拥有下列语法：

类关键词 属性 类头名 基类子句 { 成员说明 }
类关键词 | - | class 或 struct 之一。除了默认成员访问和默认基类访问之外，两个关键词是等同的。
属性 | - | (C++11 起) 可选的任任意数量属性序列，可以包含 alignas 指定符
类头名 | - | 所定义的类的名字。可以有限定，也可以后随关键词 final。名字可以省略，此时类是无名的（注意无名类不能是 final 的）
基类子句 | - | 一或多个基类以及各自所用的继承模型的可选列表（见派生类）
成员说明 | - | 访问说明符、成员对象及成员函数的声明和定义的列表（见下文）

语法综述见类。如果 类关键词 是 union，那么声明引入一个联合体类型。

前置声明

下列形式的声明

类关键词 属性 标识符 ;

声明一个将稍后在此作用域定义的类类型。直到定义出现前，此类名具有不完整类型。这允许类之间彼此引用：

class Vector; // 前置声明
class Matrix {
    // ...
    friend Vector operator*(const Matrix&, const Vector&);
};
class Vector {
    // ...
    friend Vector operator*(const Matrix&, const Vector&);
};

而且如果特定的源文件只用到该类的指针和引用，使用前置声明也可以减少 #include 依赖：

// 在 MyStruct.h 中
#include <iosfwd> // 含有 std::ostream 的前置声明
struct MyStruct {
    int value;
    friend std::ostream& operator<<(std::ostream& os, const S& s);
    // 其定义在 MyStruct.cpp 文件中提供，该文件使用 #include <ostream>
};

如果前置声明在局部作用域出现，那么它会隐藏它的外围作用域中可能出现的先前声明的相同名字的类、变量、函数，以及所有其他声明：

struct s { int a; };
struct s; // 不做任何事（s 已经在此作用域定义）
void g() {
    struct s; // 新的局部结构体“s”的前置声明
              // 它隐藏全局的结构体 s 直至此块结尾
    s* p;     // 指向局部结构体 s 的指针
    struct s { char* p; }; // 局部结构体 s 的定义
}

注意，通过作为其他声明一部分的详述类型说明符也可以引入新的类名，但只有在名字查找无法找到先前声明的有此名的类时才可以。

class U;
namespace ns{
    class Y f(class T p); // 声明函数 ns::f 并声明 ns::T 与 ns::Y
    class U f(); // U 指代 ::U
    Y* p; T* q; // 可以使用到 T 和 Y 的指针及引用
}

成员说明

成员说明，或类定义的体，是花括号环绕的任何数量下列各项的序列：

1) 具有下列形式的成员声明
属性(可选) 声明说明符序列(可选) 成员声明符列表(可选) ;
attr | - | (C++11 起) 可选的任意数量的属性序列
声明说明符序列 | - | 说明符的序列。它只在构造函数，析构函数，以及用户定义转换函数中可以省略。
成员声明符列表 | - | 与 初始化声明符列表相同，但额外允许位域定义、纯说明符 和虚说明符（ override 或 final） (C++11 起)，并且不允许直接非列表初始化语法。

这种声明可以声明静态及非静态的数据成员与成员函数、成员 typedef、成员枚举以及嵌套类。它也可以是友元声明。

class S {
    int d1; // 非静态数据成员
    int a[10] = {1,2}; // 带初始化器的非静态数据成员 (C++11)
    static const int d2 = 1; // 带初始化器的静态数据成员
    virtual void f1(int) = 0; // 纯虚成员函数
    std::string d3, *d4, f2(int); // 两个数据成员和一个成员函数
    enum {NORTH, SOUTH, EAST, WEST};
    struct NestedS {
        std::string s;
    } d5, *d6;
    typedef NestedS value_type, *pointer_type;
};
2) 函数定义，同时声明并定义成员函数或者友元函数。成员函数定义之后的分号是可选的。所有定义于类体之内的函数自动为内联的，除非它们附着到具名模块 (C++20 起)。
class M {
    std::size_t C;
    std::vector<int> data;
 public:
    M(std::size_t R, std::size_t C) : C(C), data(R*C) {} // 构造函数定义
    int operator()(size_t r, size_t c) const { // 成员函数定义
        return data[r*C+c];
    }
    int& operator()(size_t r, size_t c) {  // 另一个成员函数定义
        return data[r*C+c];
    }
};
3) 访问说明符 public:、protected: 和 private:
class S {
 public:
    S();          // 公开的构造函数
    S(const S&);  // 公开的复制构造函数
    virtual ~S(); // 公开的虚析构函数
 private:
    int* ptr; // 私有的数据成员
};
4) using 声明
class Base {
 protected:
     int d;
};
class Derived : public Base {
 public:
    using Base::d; // 令 Base 的受保护成员 d 为 Derived 的公开成员
    using Base::Base; // 继承基类的所有构造函数 (C++11)
};
5) static_assert 声明
template<typename T>
struct Foo {
  static_assert(std::is_floating_point<T>::value, "Foo<T>: T 必须是浮点数");
};
6) 成员模板声明
struct S {
    template<typename T>
    void f(T&& n);

    template<class CharT>
    struct NestedS {
        std::basic_string<CharT> s;
    };
};
7) 别名声明
template <typename T>
struct identity
{
    using type = T;
};
8) 成员类模板的推导指引：
struct S {
    template<class CharT>
    struct NestedS {
        std::basic_string<CharT> s;
    };

    template<class CharT>
    NestedS(std::basic_string<CharT>) -> NestedS<CharT>;
};
 (C++17 起)
9) using enum 声明：
enum class color { red, orange, yellow };

struct highlight {
    using enum color;
};
 (C++20 起)

局部类

类声明可以在函数体内出现，此时它定义局部类。这种类的名字只存在于函数作用域中，且无法在函数外访问。

  • 局部类不能拥有静态数据成员
  • 局部类的成员函数无链接
  • 局部类的成员函数必须完全在类体内定义
  • 除闭包类型以外的 (C++14 起)局部类不能拥有成员模板
  • 局部类不能拥有友元模板
  • 局部类不能在类定义内定义友元函数
  • 函数（包括成员函数）内的局部类的外围函数能访问的名字也可以被该局部类访问。
  • 局部类不能用作模板实参
 (C++11 前)
#include <vector>
#include <algorithm>
#include <iostream>

int main()
{
    std::vector<int> v{1,2,3};
    struct Local {
       bool operator()(int n, int m) {
           return n > m;
       }
    };
    std::sort(v.begin(), v.end(), Local()); // C++11 起
    for(int n: v) std::cout << n << ' ';
}

输出：

3 2 1

参阅


注入类名

< cpp‎ | language

注入类名是在类的作用域内该类自身的名字。

类模板中，注入类名能用作指代当前模板的模板名，或指代当前实例化的类名。

解释

在类作用域中，当前类的名字被当做它如同是一个公开成员名一样；这被称为注入类名（injected-class-name）。该名字的声明点紧跟类定义的开花括号之后。

int X;
struct X {
    void f() {
        X* p; // OK：X 指代注入类名
        ::X* q; // 错误：名称查找找到变量名，它隐藏结构体名
    }
};

与其他成员类似，注入类名会被继承。在私有或受保护继承的场合，某个间接基类的注入类名在派生类中最后可能会无法访问。

struct A {};
struct B : private A {};
struct C : public B {
    A* p; // 错误：注入类名 A 不可访问
    ::A* q; // OK：不使用注入类名
};

在类模板中

与其他类相似，类模板也拥有注入类名。它的注入类名可以被用作模板名或类型名。

下列情况下，注入类名被当做类模板自身的模板名：

  • 它后面跟着 <
  • 它被用作对应某个模板模板形参的模板实参
  • 它是某个友元类模板声明的详述类型说明符中的最后标识符。

否则，它被当做类型名，并等价于模板名后随环绕于 <> 中的该类模板的各个模板形参。

template <template <class, class> class> struct A;

template<class T1, class T2>
struct X {
    X<T1, T2>* p; // OK：X 被当做模板名
    using a = A<X>; // OK：X 被当做模板名
    template<class U1, class U2>
    friend class X; // OK：X 被当做模板名
    X* q; // OK：X 被当做类型名，等价于 X<T1, T2>
};

在类模板特化或部分特化的作用域内，当将注入类名用作类型名时，它等价于模板名后随环绕于 <> 中的该类模板特化或部分特化的各个模板实参。

template<>
struct X<void, void> {
    X* p; // OK：X 被当做类型名，等价于 X<void, void>
    template<class, class>
    friend class X; // OK：X 被当做模板名（与在模板中相同）
    X<void, void>* q; // OK：X 被当做模板名
};
template<class T>
struct X<char, T> {
    X* p, q; // OK：X 被当做类型名，等价于 X<char, T>
    using r = X<int, int>; // OK：可以用它指名另一特化
};

只要在作用域中，类模板或类模板特化的注入类名就能被用作模板名或类型名之一。

template<> class X<int, char> {
    class B {
        X a; // 表示 X<int, char>
        template<class,class> friend class X; // 表示 ::X
    };
};
template <class T> struct Base {
    Base* p;
};
template <class T> struct Derived: public Base<T> {
    typename Derived::Base* p; // 表示 Derived::Base<T>
};
template<class T, template<class> class U = T::template Base> struct Third { };
Third<Derived<int>> t; // OK：默认实参将注入类名用作模板

找到注入类名的查找在某些情况下会导致歧义（例如当在多于一个基类中找到它时）。如果所有找到的注入类名都指代同一类模板的特化，且该名字被用作模板名，那么注入类名指代类模板自身而非其特化，且没有歧义。

template <class T> struct Base {};
template <class T> struct Derived: Base<int>, Base<char> {
    typename Derived::Base b; // 错误：歧义
    typename Derived::Base<double> d; // OK
};

注入类名与构造函数

构造函数没有名字，但在构造函数的声明与定义中，外围类的注入类名被认为是构造函数的名称。

在有限定的名字 C::D 中，如果

  • 名字查找不忽略函数名，且
  • 对 D 在类 C 的作用域中的查找找到了注入类名

那么始终认为该限定名指名 C 的构造函数。这种名字只能用于构造函数的声明中（例如，在友元构造函数声明，构造函数模板特化，构造函数模板实例化，或构造函数定义中），或用于继承构造函数 (C++11 起)。

struct A {
    A();
    A(int);
    template<class T> A(T) {}
};
using A_alias = A;

A::A() {}
A_alias::A(int) {}
template A::A(double);

struct B : A {
    using A_alias::A;
};

A::A a; // 错误：A::A 被认为指名构造函数，而非类型
struct A::A a2; // OK：与 'A a2;' 相同
B::A b; // OK：与 'A b;' 相同


类模板实参推导 (CTAD)(C++17 起)

< cpp‎ | language

为了实例化一个类模板，需要知晓但不需要指定每个模板实参。在下列语境中，编译器会从初始化器的类型推导缺失的模板实参：

  • 任意指定变量及变量模板初始化的声明：
std::pair p(2, 4.5);     // 推导出 std::pair<int, double> p(2, 4.5);
std::tuple t(4, 3, 2.5); // 同 auto t = std::make_tuple(4, 3, 2.5);
std::less l;             // 同 std::less<void> l;
  • new 表达式：
template<class T> struct A
{
    A(T, T);
};
auto y = new A{1, 2}; // 分配的类型是 A<int>
  • 函数式转型表达式：
auto lck = std::lock_guard(mtx);     // 推导出 std::lock_guard<std::mutex>
std::copy_n(vi1, 3,
    std::back_insert_iterator(vi2)); // 推导出 std::back_insert_iterator<T>，
                                     // 其中 T 是容器 vi2 的类型
std::for_each(vi.begin(), vi.end(),
    Foo([&](int i) {...}));          // 推导出 Foo<T>，其中 T 是独有的 lambda 类型
  • 非类型模板形参的类型：
template<class T>
struct X
{
    X(T) {}
    auto operator<=>(const X&) const = default;
};

template<X x> struct Y {};

Y<0> y; // OK，Y<X<int>(0)>
 (C++20 起)

类模板的推导

隐式生成的推导指引

在函数式转型或变量声明中，当类型说明符只包含主类模板 C 的名字（即不带模板实参列表）时，以如下方式组成推导需要用到的候选：

  • 如果已经定义 C，那么对所指名的主模板（如果已经定义）中所声明的每个构造函数（或构造函数模板）Ci，构造一个虚设的函数模板 Fi，使得
  • Fi 的模板形参是 C 的模板形参后随（如果 Ci 是构造函数模板）Ci 的模板形参（也会包含默认模板实参）
  • Fi 的函数形参是构造函数形参
  • Fi 的返回类型是 C 后随 <> 中的类模板的模板形参
  • 如果还没有定义 C 或还没有声明它的任何构造函数，那么添加一个导出自假想的构造函数 C() 的额外的虚设函数模板
  • 在任何情况下，都会添加一个以如上方式导出自假想构造函数 C(C) 的额外的虚设函数模板，它被称为复制推导候选。
  • 另外，如果
  • C 有定义且满足聚合类型的要求，并假设它的任何待决基类都没有虚函数或虚基类），
  • 没有 C 的用户定义推导指引，且
  • 该变量由非空的初始化器列表 arg1, arg2, ..., argn 初始化（可使用指派初始化器），
那么可能会添加聚合推导候选。按以下方式从聚合体元素的类型产生聚合推导候选的形参列表：
  • 设 ei 为要从 argi 初始化的（可能递归的）聚合体元素（公开基类/类成员/数组元素），其中
  • 只会对有非依赖类型或有非依赖边界的数组类型的成员考虑花括号消除，
  • 如果 C（或它的自身就是聚合体的元素）拥有作为包展开的基类：
  • 如果该包展开是尾随的聚合体元素，那么认为它匹配初始化器列表的所有剩余元素；
  • 否则，认为该包为空。
  • 如果没有这种 ei，那么不添加聚合推导候选。
  • 否则，按以下方式确定聚合推导候选的形参列表 T1, T2, ..., Tn：
  • 如果 ei 是数组且 argi 是花括号初始化器列表或字符串字面量，那么 Ti 是到 ei 的类型的右值引用。
  • 否则， Ti 是 ei 的类型。
  • 如果有包因为因为它是非尾随聚合体元素而被跳过，那么在它原本的聚合体元素的位置插入形为 Pj ... 的形参包。（这通常会导致推导失败。）
  • 如果包是尾随的聚合体元素，那么将对应它的尾随形参序列替换成形为 Tn ... 的单个形参。
聚合推导候选是从假想构造函数 C(T1, T2, ..., Tn) 按上述方式得到的虚设函数模板。
在聚合推导候选的模板实参推导中，只有在尾随形参包的元素数无法从其他情况下推导时，才会从尾随函数实参数推导。
template<class T> struct A
{
    T t;
    struct
    {
        long a, b;
    } u;
};
A a{1, 2, 3}; // 聚合推导候选：template<class T> A<T> F(T, long, long);

template<class... Args>
struct B : std::tuple<Args...>, Args... {};
B b{std::tuple<std::any, std::string>{}, std::any{}};

// 聚合推导候选：
//   template<class... Args> B<Args...> F(std::tuple<Args...>, Args...);

// 推导出 b 的类型是 B<std::any, std::string>
 (C++20 起)

然后，针对某个假想类类型的虚设对象的初始化，进行模板实参推导和重载决议，对于组成重载集而言，该类的各构造函数的签名与各个指引（除了返回类型）相匹配，并且由进行类模板实参推导的语境提供它的初始化器。但如果它的初始化器列表由单个（可有 cv 限定的）U 类型的表达式组成，其中 U 是 C 的特化或派生自 C 的特化的类，那么跳过列表初始化的第一阶段（考虑初始化器列表构造函数）。

这些虚设构造函数是该假想类类型的公开成员。如果推导指引从显式的构造函数组成，那么它们也是显式的。如果重载决议失败，那么程序非良构。否则，选中的 F 的返回类型就成为推导出的类模板特化。

template<class T> struct UniquePtr
{
    UniquePtr(T* t);
};
UniquePtr dp{new auto(2.0)};

// 一个声明的构造函数：
// C1：UniquePtr(T*);

// 隐式生成的推导指引集：
// F1：template<class T> UniquePtr<T> F(T *p);
// F2：template<class T> UniquePtr<T> F(UniquePtr<T>); // 复制推导候选

// 要初始化的假想类：
// struct X
// {
//     template<class T> X(T *p);         // 从 F1
//     template<class T> X(UniquePtr<T>); // 从 F2
// };

// X 对象的以“new double(2.0)”为初始化器的直接初始化
// 会选择与 T = double 对应的指引 F1 的构造函数
// 对于 T=double 的 F1，返回类型是 UniquePtr<double>

// 结果：
// UniquePtr<double> dp{new auto(2.0)}

或者，对于更加复杂的例子（注意：“S::N”无法编译：作用域解析限定符无法被推导）：

template<class T> struct S
{
    template<class U> struct N
    {
        N(T);
        N(T, U);
        template<class V> N(V, U);
    };
};

S<int>::N x{2.0, 1};

// 隐式生成的推导指引是（注意已知 T 是 int）
// F1：template<class U> S<int>::N<U> F(int);
// F2：template<class U> S<int>::N<U> F(int, U);
// F3：template<class U, class V> S<int>::N<U> F(V, U);
// F4：template<class U> S<int>::N<U> F(S<int>::N<U>); （复制推导候选）

// 以“{2.0, 1}”为初始化器的直接列表初始化的重载决议
// 选择 U=int 与 V=double 的 F3。
// 返回类型是 S<int>::N<int>

// 结果：
// S<int>::N<int> x{2.0, 1};

用户定义的推导指引

用户定义的推导指引的语法是带尾随返回类型的函数声明的语法，但它以类模板名作为函数名：

explicit说明符(可选) 模板名 ( 形参声明子句 ) -> 简单模板标识 ;

用户定义的推导指引必须指名一个类模板，且必须在类模板的同一语义作用域（可以是命名空间或外围类）中引入，而且对于成员类模板必须拥有同样的访问，但推导指引不会成为该作用域的成员。

推导指引不是函数且没有函数体。推导指引不会被名字查找所找到，并且除了在推导类模板实参时与其他推导指引之间的重载决议之外不会参与重载决议。不能在同一翻译单元中为同一类模板再次声明推导指引。

// 模板的声明
template<class T> struct container
{
    container(T t) {}
    template<class Iter> container(Iter beg, Iter end);
};

// 额外的推导指引
template<class Iter>
container(Iter b, Iter e) -> container<typename std::iterator_traits<Iter>::value_type>;

// 使用
container c(7); // OK：用隐式生成的指引推导出 T=int
std::vector<double> v = {/* ... */};
auto d = container(v.begin(), v.end()); // OK：推导出 T=double
container e{5, 6}; // 错误：std::iterator_traits<int>::value_type 不存在

为重载决议而虚设的构造函数（如上文所述）在对应到从显式构造函数组成的隐式生成的推导指引，或对应到声明为 explicit 的用户定义推导指引时是 explicit 的。像往常一样，在复制初始化语境中忽略这些构造函数：

template<class T> struct A {
    explicit A(const T&, ...) noexcept; // #1
    A(T&&, ...);                        // #2
};

int i;
A a1 = {i, i}; // 错误：不能从 #2 的右值引用推导，且 #1 是 explicit 的，所以复制初始化中不予考虑。
A a2{i, i};    // OK，#1 推导出 A<int> 并且初始化
A a3{0, i};    // OK，#2 推导出 A<int> 并且初始化
A a4 = {0, i}; // OK，#2 推导出 A<int> 并且初始化

template<class T> A(const T&, const T&) -> A<T&>; // #3
template<class T> explicit A(T&&, T&&)  -> A<T>;  // #4

A a5 = {0, 1}; // 错误：#3 推导出 A<int&> 且 #1 和 #2 会生成形参相同的构造函数。
A a6{0, 1};    // OK，#4 推导出 A<int> 并以 #2 初始化
A a7 = {0, i}; // 错误：#3 推导出 A<int&>
A a8{0, i};    // 错误：#3 推导出 A<int&>

在构造函数或构造函数模板的形参列表中使用成员 typedef 或别名模板的行为自身不会使隐式生成的指引的对应形参变为不推导语境。

template<class T> struct B
{
    template<class U> using TA = T;
    template<class U> B(U, TA<U>); // #1
};

// 从 #1 产生的隐式推导指引等价于
// template<class T, class U> B(U, T) -> B<T>;
// 而不是
// template<class T, class U> B(U, typename B<T>::template TA<U>) -> B<T>;
// 后者无法被推导

B b{(int*)0, (char*)0}; // OK，推导出 B<char*>

别名模版的推导

当函数式转型或变量定义用到了以不带实参列表的别名模板 A 为类型说明符的名字，其中 A 定义为 B<ArgList> 的别名，而 B 的作用域为非依赖且 B 是类模板或定义相似的别名模板时，推导将以与类模板相同的方式进行，除了改为从 B 的指引生成指引，方式如下：

  • 对于 B 的每个指引 f，用模板实参推导从 B<ArgList> 推导 f 的返回类型的模板实参，但推导即使在有实参没有被推导出的时候也不会失败。
  • 替换上述推导结果到 f 中，如果替换失败，那么就不会生成指引；否则以 g 代表替换结果构成指引 f'，使得：
  • f' 的形参类型和返回类型与 g 的相同
  • 如果 f 是模板，那么 f' 是模板形参列表包含了以下内容的函数模板；否则（f 不是模板）f' 是函数：
  • 在上述推导出现的 A 的所有模板形参（包含其默认模板实参）
  • 在前一条找到的默认模板实参（如果存在）中出现的 A 的所有模板形参（包含其默认模板实参）
  • 如果再次找到默认模板实参，那么递归地包含在这些默认模板实参中出现的 A 的所有模板形参（包含其默认模板实参）
  • 后随 f 未被推导的模板形参（包含其默认模板实参）
  • f' 的关联约束是 g 的关联约束和当且仅当 A 的实参可以从结果类型推导这一约束的合取。
template<class T> class unique_ptr
{
    /* ... */
};
template<class T> class unique_ptr<T[]>
{
    /* ... */
};

template<class T> unique_ptr(T*) -> unique_ptr<T>;   // #1
template<class T> unique_ptr(T*) -> unique_ptr<T[]>; // #2

template<class T> concept NonArray = !std::is_array_v<T>;
template<NonArray A>
using unique_ptr_nonarray = unique_ptr<A>;
template<class A>
using unique_ptr_array = unique_ptr<A[]>;

// 对 unique_ptr_nonarray 生成的推导指引：
// 从 #1（unique_ptr<T> 从 unique_ptr<A> 的推导产生 T = A）：
// template<class A>
//     requires(argument_of_unique_ptr_nonarray_is_deducible_from<unique_ptr<A>>)
//     auto F(A*) -> unique_ptr<A>;
// 从 #2（unique_ptr<T[]> 从 unique_ptr<A> 的推导不产生结果）：
// template<class T>
//     requires(argument_of_unique_ptr_nonarray_is_deducible_from<unique_ptr<T[]>>)
//     auto F(T*) -> unique_ptr<T[]>;

// 其中 argument_of_unique_ptr_nonarray_is_deducible_from 能定义为
// template<class> class AA;
// template<class A> class AA<unique_ptr_nonarray<A>> {};
// template<class T>
//     concept argument_of_unique_ptr_nonarray_is_deducible_from =
//         requires { sizeof(AA<T>); };

// 对 unique_ptr_array 生成的推导指引：
// 从 #1（unique_ptr<T>从 unique_ptr<A[]> 的推导生成 T = A[]）：
// template<class A>
//     requires(argument_of_unique_ptr_array_is_deducible_from<unique_ptr<A[]>>)
//     auto F(A(*)[]) -> unique_ptr<A[]>;
// 从 #2（unique_ptr<T[]> 从 unique_ptr<A[]> 的推导生成 T = A）：
// template<class A>
//     requires(argument_of_unique_ptr_array_is_deducible_from<unique_ptr<A[]>>)
//     auto F(A*) -> unique_ptr<A[]>;

// 其中 argument_of_unique_ptr_array_is_deducible_from 能定义为
// template<class> class BB;
// template<class A> class BB<unique_ptr_array<A>> {};
// template<class T>
//     concept argument_of_unique_ptr_array_is_deducible_from =
//         requires { sizeof(BB<T>); };

// 用法：
unique_ptr_nonarray p(new int); // 推导出 unique_ptr<int>
// 从 #1 生成的推导指引返回 unique_ptr<int>
// 从 #2 生成的推导指引返回 unique_ptr<int[]>，它被忽略，因为
//   argument_of_unique_ptr_nonarray_is_deducible_from<unique_ptr<int[]>> 得不到满足

unique_ptr_array q(new int[42]); // 推导出 unique_ptr<int[]>
// 从 #1 生成的推导指引失败（不能从 new int[42] 推导出 A(*)[] 中的 A）
// 从 #2 生成的推导指引返回 unique_ptr<int[]>
 (C++20 起)

注解

只有在不存在模板实参列表时才进行类模板实参推导。如果指定了模板实参列表，那么就不会发生推导。

std::tuple t1(1, 2, 3);                // OK：推导
std::tuple<int, int, int> t2(1, 2, 3); // OK：提供了所有实参
std::tuple<> t3(1, 2, 3);              // 错误：tuple<> 中没有匹配的构造函数。不进行推导。
std::tuple<int> t4(1, 2, 3);           // 错误

聚合体的类模板实参推导通常需要用户定义的推导指引：

template<class A, class B> struct Agg
{
    A a;
    B b;
};
// 隐式生成的指引由默认、复制及移动构造函数组成

template<class A, class B> Agg(A a, B b) -> Agg<A, B>;
// ^ 此推导指引在 C++20 中能隐式生成

Agg agg{1, 2.0}; // 从用户定义指引推导出 Agg<int, double>

template <class... T>
array(T&&... t) -> array<std::common_type_t<T...>, sizeof...(T)>;
auto a = array{1, 2, 5u}; // 从用户定义指引推导出 array<unsigned, 3>
 (C++20 前)

用户定义指引不需要是模板：

template<class T> struct S
{
    S(T);
};
S(char const*) -> S<std::string>;
S s{"hello"}; // 推导出 S<std::string>

在类模板的作用域中，没有形参列表的模板名是注入类名，并可以用作类型。这种情况下不发生类模板推导，但必须显式提供其模板形参：

template<class T>
struct X
{
    X(T) {}
    template<class Iter> X(Iter b, Iter e) {}

    template<class Iter>
    auto foo(Iter b, Iter e)
    {
        return X(b, e); // 不推导：X 是当前的 X<T>
    }

    template<class Iter>
    auto bar(Iter b, Iter e)
    {
        return X<typename Iter::value_type>(b, e); 必须指定所需的模板实参
    }

    auto baz()
    {
        return ::X(0); // 不是注入类名；推导为 X<int>
    }
};

在重载决议中，偏序的优先级高于是否从用户定义推导指引生成函数模板：如果从构造函数生成的函数模板比从用户定义的推导指引生成者更特化，那么会选择从构造函数生成的。因为复制推导候选常常比包装构造函数更特殊，所以此规则表明复制通常优于包装。

template<class T> struct A
{
    A(T, int*);     // #1
    A(A<T>&, int*); // #2
    enum { value };
};
template<class T, int N = T::value> A(T&&, int*) -> A<T>; // #3

A a{1, 0}; // 使用 #1 推导出 A<int> 并以 #1 初始化
A b{a, 0}; // 使用 #2（比 #3 更特殊）推导出 A<int> 并以 #2 初始化

当之前的决胜规则（包括偏序）无法分辨两个候选函数模板时，应用下列规则：

  • 由用户定义指引生成的函数模板比从构造函数或构造函数模板隐式生成的函数模板更受偏好。
  • 复制推导候选比所有其他从构造函数或构造函数模板隐式生成的函数模板更受偏好。
  • 从非模板构造函数隐式生成的函数模板比从构造函数模板隐式生成的函数模板更受偏好。
template <class T> struct A
{
    using value_type = T;
    A(value_type); // #1
    A(const A&);   // #2
    A(T, T, int);  // #3
    template<class U>
    A(int, T, U);  // #4
};                 // A(A); #5，复制推导候选

A x(1, 2, 3); // 使用 #3，从非模板构造函数生成

template <class T> A(T) -> A<T>; // #6，比 #5 更不特殊

A a(42);  // 使用 #6 推导出 A<int> 并以 #1 初始化
A b = a;  // 使用 #5 推导出 A<int> 并以 #2 初始化

template <class T> A(A<T>) -> A<A<T>>;  // #7，与 #5 一样特殊

A b2 = a; // 使用 #7 推导出 A<A<int>> 并以 #1 初始化

如果模板形参是类模板形参，那么到该形参的无 cv 限定的右值引用不是转发引用：

template<class T> struct A
{
    template<class U>
    A(T&&, U&&, int*); // #1：T&& 不是转发引用
                       //     U&& 是转发引用
    A(T&&, int*);      // #2：T&& 不是转发引用
};

template<class T> A(T&&, int*) -> A<T>; // #3：T&& 是转发引用

int i, *ip;
A a{i, 0, ip};  // 错误，不能从 #1 推导
A a0{0, 0, ip}; // 使用 #1 推导出 A<int> 并以 #1 初始化
A a2{i, ip};    // 使用 #3 推导出 A<int&> 并以 #2 初始化

当从类模板的某个特化类型的单个实参进行的初始化有问题时，通常与默认的包装相比，更偏好复制推导：

std::tuple t1{1};  //std::tuple<int>
std::tuple t2{t1}; //std::tuple<int>，不是 std::tuple<std::tuple<int>>

std::vector v1{1, 2};   // std::vector<int>
std::vector v2{v1};     // std::vector<int>，不是 std::vector<std::vector<int>>（P0702R1）
std::vector v3{v1, v2}; // std::vector<std::vector<int>>

除了复制 VS. 包装的特殊情形外，列表初始化中保持对初始化器列表构造函数的强偏好。

std::vector v1{1, 2}; // std::vector<int>

std::vector v2(v1.begin(), v1.end()); // std::vector<int>
std::vector v3{v1.begin(), v1.end()}; // std::vector<std::vector<int>::iterator>

在引入类模板实参推导前，避免显式指定实参的常用手段是使用函数模板：

std::tuple p1{1, 1.0};             // std::tuple<int, double>，使用推导
auto p2 = std::make_tuple(1, 1.0); // std::tuple<int, double>，C++17 前

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0702R1 | C++17 | 初始化器列表构造函数能架空复制推导候选，导致产生包装 | 复制时跳过初始化器列表阶段


const_cast 转换

< cpp‎ | language

在有不同 cv 限定的类型间转换。

语法

const_cast < 新类型 > ( 表达式 )

返回 新类型 类型的值。

解释

只有下列转换能用 const_cast 进行。尤其是只有 const_cast 可用于移除常量性或易变性。

1) 两个指向同一类型的可能多级的指针可以互相转换，不受每个层级的 cv 限定符影响。
2) 任何 T 类型的左值可转换为到同一类型 T 的左值或右值引用，cv 限定可更多或更少。同样地，类类型纯右值或任何类型的亡值可转换成具有更多或更少 cv 限定的右值引用。引用 const_cast 的结果指代原对象 (C++17 前)在 表达式 是泛左值时指代原对象，否则指代实质化的临时量 (C++17 起)。
3) 同样的规则适用于可能多层的到数据成员的指针，及可能多层的到已知和未知边界数组（cv 限定元素的数组自身也被认为有 cv 限定） (C++17 起)。
4) 空指针值可转换成 新类型 的空指针值。

同所有转型表达式，结果是：

  • 左值，如果 新类型 是左值引用或到函数类型的右值引用；
  • 亡值，如果 新类型 是到对象类型的右值引用；
  • 否则为纯右值。

注解

函数指针和成员函数指针不可用于 const_cast

const_cast 使得到非 const 类型的引用或指针能够实际指代 const 对象，或到非 volatile 类型的引用或指针能够实际指代 volatile 对象。通过非 const 访问路径修改 const 对象和通过非 volatile 泛左值涉指 volatile 对象是未定义行为。

关键词

const_cast

示例

#include <iostream>

struct type {
    int i;

    type(): i(3) {}

    void f(int v) const {
        // this->i = v;                 // 编译错误：this 是指向 const 的指针
        const_cast<type*>(this)->i = v; // 只要该对象不是 const 就 OK
    }
};

int main()
{
    int i = 3;                 // 不声明 i 为 const
    const int& rci = i;
    const_cast<int&>(rci) = 4; // OK：修改 i
    std::cout << "i = " << i << '\n';

    type t; // 假如这是 const type t，则 t.f(4) 会是未定义行为
    t.f(4);
    std::cout << "type::i = " << t.i << '\n';

    const int j = 3; // 声明 j 为 const
    [[maybe_unused]]
    int* pj = const_cast<int*>(&j);
    // *pj = 4;      // 未定义行为

    [[maybe_unused]]
    void (type::* pmf)(int) const = &type::f; // 指向成员函数的指针
    // const_cast<void(type::*)(int)>(pmf);   // 编译错误：const_cast 不能用于成员函数指针
}

输出：

i = 4
type::i = 4

参阅

  • static_cast
  • dynamic_cast
  • reinterpret_cast
  • 显式转型
  • 隐式转换


常量表达式

< cpp‎ | language

定义能在编译时求值的表达式。

这种表达式能用做非类型模板实参、数组大小，并用于其他要求常量表达式的语境，例如

int n = 1;
std::array<int, n> a1; // 错误：n 不是常量表达式
const int cn = 2;
std::array<int, cn> a2; // OK：cn 是常量表达式

核心常量表达式

核心（core）常量表达式是求值过程中不会对下列任一者求值的表达式：

  1. this 指针，但作为该表达式的一部分求值的 constexpr 函数之中的则不算
  2. (C++23 起) 经过静态或线程存储期变量声明的控制流
  3. 调用未声明为 constexpr 的函数（或构造函数）的函数调用表达式
    constexpr int n = std::numeric_limits<int>::max(); // OK：max() 是 constexpr
constexpr int m = std::time(NULL); // 错误：std::time() 非 constexpr
  4. 对声明为 constexpr 但未定义的函数进行的函数调用
  5. 对 constexpr 函数/构造函数模板实例化进行的函数调用，其中该实例化无法满足 constexpr 函数/构造函数的要求。
  6. (C++20 起) 对 constexpr 虚函数的函数调用，调用所用的对象不可用于常量表达式（见后述）且其生命期始于此表达式之外。
  7. 会超出实现定义限制的表达式
  8. 求值导致任何形式的核心语言未定义行为（包含有符号整数溢出、除以零、数组边界外的指针算术等）的表达式。是否检测标准库的未定义行为是未指明的。
    constexpr double d1 = 2.0/1.0; // OK
constexpr double d2 = 2.0/0.0; // 错误：未定义
constexpr int n = std::numeric_limits<int>::max() + 1; // 错误：溢出
int x, y, z[30];
constexpr auto e1 = &y - &x; // 错误：未定义
constexpr auto e2 = &z[20] - &z[3]; // OK
constexpr std::bitset<2> a;
constexpr bool b = a[2]; // UB，但是否检测未指定
  9. (C++17 前) lambda 表达式
  10. 左值到右值隐式转换，除非……
    1. 应用到指代可用于常量表达式（见后述）的对象的非 volatile 泛左值，
      int main() {
    const std::size_t tabsize = 50;
    int tab[tabsize]; // OK ： tabsize 是常量表达式
                      // 因为 tabsize 可用于常量表达式
                      // 因为它有 const 限定的整数类型，且其初始化器是常量初始化器

    std::size_t n = 50;
    const std::size_t sz = n;
    int tab2[sz]; // 错误： sz 不是常量表达式
                  // 因为 sz 不可用于常量表达式
                  // 因为其初始化器不是常量初始化器
}
}
    2. 或应用到拥有字面类型，并指代生命期始于此表达式的求值之内的非 volatile 对象
  11. 对 union 的不活跃成员或其子对象实施的左值到右值隐式转换或修改操作（即使它与活跃成员共享公共起始序列也是如此）
  12. (C++20 起) 应用到拥有不确定值的对象的左值到右值隐式转换
  13. 对活跃成员（若存在）为 mutable 的 union 调用隐式定义的复制/移动构造函数或复制/移动赋值运算符，除非该 union 对象的生命期始于此表达式的求值之内
  14. (C++17 起) (C++20 前)会更改 union 的活跃成员的赋值表达式，或对重载的赋值运算符的调用
  15. 指代引用类型的变量或数据成员的 标识表达式，除非该引用可用于常量表达式，或其生命始于此表达式的求值之内
  16. 从 cv void* 转换到任何对象指针类型
  17. (C++20 前) dynamic_cast
  18. reinterpret_cast
  19. (C++20 前)伪析构函数调用
  20. (C++14 前)自增或自减运算符

  21. (C++14 起) 修改对象，除非该对象拥有非 volatile 字面类型，且其生命期始于此表达式的求值之内

    constexpr int incr(int& n) {
  return ++n;
}
constexpr int g(int k) {
  constexpr int x = incr(k); // 错误：incr(k) 不是核心常量表达式
                             // 因为 k 的生命期始于表达式 incr(k) 之外
  return x;
}
constexpr int h(int k) {
  int x = incr(k); // OK：不要求 x 以核心常量表达式初始化
  return x;
}
constexpr int y = h(1); // OK：以值 2 初始化 y
                        // h(1) 是核心常量表达式
                        // 因为 k 的生命期始于表达式 h(1) 之内
  22. (C++20 起) 对于生存期不在此表达式的求值内开始的对象的析构函数调用或伪析构函数调用
  23. (C++20 前)应用到多态类型泛左值的 typeid 表达式
  24. new 表达式 ，除非选择的分配函数是全局可替换分配函数且此表达式的求值内解分配其所分配的存储 (C++20 起)
  25. delete 表达式 ，除非它解分配于此表达式的求值内分配的存储区域 (C++20 起)
  26. (C++20 起)调用 std::allocator<T>::allocate ，除非于此表达式的求值内解分配其所分配的存储
  27. (C++20 起)调用 std::allocator<T>::deallocate ，除非它解分配于此表达式的求值内分配的存储区域
  28. (C++20 起) await 表达式或 yield 表达式
  29. (C++20 起)结果未指定三路比较
  30. 结果未指明的相等或关系运算符
  31. (C++14 前)赋值或复合赋值运算符
  32. throw 表达式
  33. (C++20 起) 汇编声明
  34. (C++14 起) 宏 va_arg 的调用，是否能求值宏 va_start 是未指定的
  35. (C++23 起) goto 语句
  36. (C++20 起)会抛出异常的 dynamic_cast 或 typeid 表达式
  37. lambda 表达式中，提及 this 或提及定义于该 lambda 之外的变量，若它是一次 ODR 式使用
    void g() {
  const int n=0;
  constexpr int j=*&n; // OK：lambda 表达式之外
  [=]{ constexpr int i=n;  // OK：'n' 未被 ODR 式使用且未在此处被俘获。
       constexpr int j=*&n;// 非良构：'&n' ODR 式使用了 'n'。
     };
}

    注意，若 ODR 式使用发生于对闭包的函数调用中，则它不涉指 this 或外围变量，因为它所访问的是该闭包的数据成员

    // OK：'v' 与 'm' 被 ODR 式使用，但未出现于嵌套于 lambda 内的常量表达式中
auto monad = [](auto v){return [=]{return v;};};
auto bind = [](auto m){return [=](auto fvm){return fvm(m());};};
// 在常量表达式求值中，创建对自动对象的俘获是 OK 的。
static_assert(bind(monad(2))(monad)() == monad(2)());
             (C++17 起)
本节未完成
原因：需要更多小示例和更少标准用语

注意：核心常量表达式本身并无任何直接的语义含义：表达式必须为常量表达式的子集之一（见后述），才可以在特定语境中使用。

常量表达式

常量表达式（constant expression）是

  • 指代下列之一的左值 (C++14 前)泛左值 (C++14 起)核心常量表达式
  • 拥有静态存储期且非临时的对象，或
  • 拥有静态存储期的临时对象，但其值满足下文对纯右值的约束，或
 (C++14 起)
  • 非立即 (C++20 起)函数
  • 其值满足下列约束的纯右值核心常量表达式：
  • 若其值是类类型对象，则其每个引用类型的非静态数据成员均指代满足上述对左值 (C++14 前)泛左值 (C++14 起)约束的实体
  • 若其值为指针类型，则它保有
  • 拥有静态存储期的对象的地址
  • 拥有静态存储期的对象的末尾后一位置的地址
  • 非立即 (C++20 起)函数的地址
  • 空指针值
  • 若其值是成员函数指针类型，则它不代表立即函数
 (C++20 起)
  • 若其值具有类或数组类型，则每个子对象均满足这些对值的约束
本节未完成
原因：列出要求非整数/经转换的常量表达式的语境？
void test() {
    static const int a = std::random_device{}();
    constexpr const int& ra = a; // OK：a 是泛左值常量表达式
    constexpr int ia = a; // 错误：a 不是纯右值常量表达式

    const int b = 42;
    constexpr const int& rb = b; // 错误：b 不是泛左值常量表达式
    constexpr int ib = b; // OK：b 是纯右值常量表达式
}

整型常量表达式

整型常量表达式是隐式转换成纯右值的整型或无作用域枚举类型的表达式，其中被转换的表达式是核心常量表达式。若将类类型表达式用在期待整型常量表达式之处，则表达式将被按语境隐式转换成整型或无作用域枚举类型。

下列语境要求整型常量表达式：

  • 数组边界
  • new 表达式中首个以外的维度
 (C++14 前)
  • 位域长度
  • 底层类型未固定时的枚举初始化器
  • 对齐。

经转换的常量表达式

T 类型的经转换的常量表达式是隐式转换到 T 类型的表达式，其中被转换后表达式是常量表达式，且隐式转换序列只含有：

  • constexpr 用户定义转换（故类能用于期待整数类型之处）
  • 左值到右值转换
  • 整型提升
  • 非窄化整型转换
  • 数组到指针转换
  • 函数到指针转换
  • 函数指针转换（指向 noexcept 函数的指针到指向函数的指针）
  • 限定性转换
  • 源自 std::nullptr_t 的空指针转换
  • 源自 std::nullptr_t 的空成员指针转换
 (C++17 起)
  • 而若发生任何引用绑定，则它是直接绑定（非构造临时对象者）

下列语境要求经转换的常量表达式：

  • case 表达式
  • 底层类型已固定时的枚举项初始化器
  • 数组边界
  • new 表达式中，第一维以外的维度
 (C++14 起)
  • 整型与枚举 (C++17 前)非类型模板实参。

按语境转换的 bool 类型常量表达式是按语境转换到 bool 的表达式，其中转换后的表达式是常量表达式，且转换序列只含上述转换。

下列语境要求按语境转换的 bool 类型常量表达式：

  • noexcept 规定
  • static_assert 声明
 (C++23 前)
  • constexpr if 语句
 (C++17 起)
(C++23 前)
  • 条件性 explicit 说明符
 (C++20 起)

历史类别

下列常量表达式的类别从 C++14 起不再于标准中使用：

  • 字面常量表达式是非指针字面类型（经语境所要求的转换后）的纯右值核心常量表达式。数组或类类型的字面常量表达式要求每个子对象以常量表达式初始化。
  • 引用常量表达式是指代具有静态存储期的对象或指代函数的左值核心常量表达式。
  • 地址常量表达式是 std::nullptr_t 类型或指针类型（经语境所要求的转换后）的纯右值核心常量表达式，它指向具有静态存储期的对象，指向具有静态存储期的数组末尾后一位置，指向函数，或为空指针。

可用于常量表达式

上述列表中，变量在 P 点可用于常量表达式，

  • 若该变量是
  • constexpr 变量，或
  • 拥有下列类型的常量初始化的变量
  • 引用类型，或
  • const 限定的整数或枚举类型。
  • 而该变量的定义从 P 可达
  • 而若 P 不在与该变量定义相同的翻译单元中（即定义是导入的），则该变量未被初始化为指向或指代，或拥有（可能递归的）子对象或成员指向或指代可用于常量表达式的翻译单元局部实体
 (C++20 起)

对象或引用可用于常量表达式，若它是

  • 可用于常量表达式的变量，或
  • (C++20 起) 模板形参对象，或
  • 字符串字面量对象，或
  • 以上任一者的非 mutable 子对象或引用成员，或
  • 非 volatile 的 const 限定整数类或枚举类型的，以常量表达式初始化的完整临时对象。
const std::size_t sz = 10; // sz 可用于常量表达式

明显常量求值的表达式

下列表达式（包括到目标类型的转换）是明显常量求值的：

  • 语法上要求常量表达式处，包括
  • 数组边界
  • new 表达式中第一维以外的数组长度
  • 位域长度
  • 枚举项初始化器
  • 对齐
  • case 表达式
  • 非类型模板实参
  • noexcept 说明中的表达式
  • static_assert 声明中的表达式
  • 条件性 explicit 说明符中的表达式
 (C++20 起)
  • constexpr if 语句中的条件
 (C++17 起)
  • 立即调用
  • 概念定义、嵌套要求及requires 子句中的约束表达式
 (C++20 起)
  • 可用于常量表达式的变量的初始化器，包括
  • constexpr 变量的初始化器
  • 引用和 const 限定的整数或枚举类型的变量的初始化器，若该初始化器为常量表达式
  • 静态及线程局域变量的初始化器，若该初始化器的所有子表达式（含构造函数调用和隐式转换）均为常量表达式（即该初始化器为常量初始化器）

注意最后两种情况的语境亦接受非常量表达式。

能用 std::is_constant_evaluated 和 if consteval (C++23 起) 检测求值是否出现于明显常量求值语境中。

为测试最后二类条件，编译器可能及对初始化器的试探性地常量求值。不建议依赖此时的结果。

 (C++20 起)

常量求值所需要的函数与变量

下列表达式或转换为潜在常量求值的：

  • 明显常量求值的表达式
  • 潜在求值的表达式
  • 花括号初始化器列表的立即子表达式（可能需要常量求值确定转换是否为窄化）
  • 出现于模板化实体内的取址（一元 &）表达式（可能需要常量求值确定这种表达式是否为值待决）
  • 上述之一的子表达式，除了嵌套的不求值操作数的子表达式

若函数为 constexpr 函数且为潜在常量求值的表达式所指名，则它为常量求值所需要。

若变量为 constexpr 变量或非 volatile 的 const 限定的整数类型或引用类型的变量，且指代它的标识表达式被潜在常量求值，则它为常量求值所需要。

预置的函数的定义及函数模板特化或变量模板特化 (C++14 起)的实例化会被触发，若该函数或变量 (C++14 起)为常量求值所需要。

注解

不容许实现将库函数声明为 constexpr，除非标准说该函数为 constexpr。

常量表达式中不容许具名返回值优化（ NRVO ），而返回值优化（ RVO ）是强制要求的。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1313 | C++11 | 容许未定义行为；且禁止所有指针减法 | 禁止 UB ；同数组内的指针减法 OK
CWG 1581 | C++11 | 未要求定义或实例化常量求值所需要的函数 | 已要求
CWG 1952 | C++11 | 要求诊断标准库未定义行为 | 未指定是否诊断库 UB
CWG 2167 | C++11 | 求值中局部的非成员引用会令求值为非 constexpr | 允许非成员引用
CWG 2299 | C++14 | <cstdarg> 中的宏能否用于常量求值不明确 | 禁止 va_arg ，未指定 va_start
CWG 2490 | C++20 | 常量求值中的（伪）析构函数调用缺少限制 | 添加了限制

参阅

constexpr 说明符 (C++11) | 指定变量或函数的值能在编译时计算
is_literal_type (C++11)(C++17 中弃用)(C++20 中移除) | 检查类型是否为字面类型 (类模板)


常量初始化

< cpp‎ | language

设置静态变量的初值为编译时常量。

语法

static T & 引用 = 常量表达式; | (1)
static T 对象 = 常量表达式; | (2)

解释

静态及线程局部 (C++11 起)对象的常量取代零初始化，并早于所有其他初始化进行。只有下列变量会进行常量初始化：

1) 静态或线程局部 (C++11 起)引用，如果它绑定到了静态泛左值，临时对象（或其子对象） (C++11 起)，或函数，且如果引用的初始化器中每个表达式（包含隐式转换）都是常量表达式。
2) 不由构造函数的调用所初始化的静态或线程局部 (C++11 起)简旧数据类型 (PODType) (C++11 前)对象（不必为类类型），如果对象被值初始化，或者如果它的初始化器中的每个表达式均为常量表达式。
3) 由构造函数的调用所初始化的类类型的静态或线程局部对象，如果构造函数是 constexpr 且所有构造函数实参（包含隐式转换）都是常量表达式，且如果构造函数的初始化器列表中的各初始化器，以及各类成员的花括号或等号初始化器都仅含有常量表达式。
 (C++11 起)

常量初始化的效果与其所对应的初始化的效果相同，但保证它在任何其他静态或线程局部 (C++11 起)对象的初始化前完成，并可能在编译时进行。

注解

如果编译器可以保证其值与当遵循初始化的标准顺序时的结果相同，那么允许它用常量初始化对其他的静态及线程局部 (C++11 起)对象进行初始化。

实践中，常量初始化在编译时进行，并将预先计算的对象表示作为程序映像的一部分（如 .data 段）存储。如果变量既为 const 又被常量初始化，那么它的对象表示可存储于程序映像的只读段（如 .rodata 段）。

示例

#include <iostream>
#include <array>

struct S {
    static const int c;
};
const int d = 10 * S::c; // 非常量表达式：此 S::c 前没有初始化器，此初始化发生晚于常量初始化
const int S::c = 5;      // 常量初始化，保证首先发生
int main()
{
    std::cout << "d = " << d << '\n';
    std::array<int, S::c> a1; // OK：S::c 是常量表达式
//  std::array<int, d> a2;    // 错误：d 不是常量表达式
}

输出：

d = 50

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 441 | C++98 | 不能常量初始化引用 | 使得可常量初始化
CWG 2026 | C++98 | 曾指定始终首先进行零初始化，甚至先于常量初始化 | 如果适用常量初始化则无零初始化

参阅

  • constexpr
  • 构造函数
  • 转换构造函数
  • 复制构造函数
  • 默认构造函数
  • explicit
  • 初始化
    • 聚合初始化
    • 复制初始化
    • 默认初始化
    • 直接初始化
    • 列表初始化
    • 引用初始化
    • 值初始化
    • 零初始化
  • 移动构造函数


consteval 说明符 (C++20 起)

< cpp‎ | language
  • consteval - 指定函数是立即函数（immediate function），即每次调用该函数必须产生编译时常量。

解释

consteval 说明符声明函数或函数模板为立即函数，即该函数的每次潜在求值的调用（即不求值语境外的调用）必须（直接或间接）产生编译时常量表达式。它不可应用于析构函数、分配函数或解分配函数。consteval 说明符蕴含 inline 。同一声明说明符序列中允许出现至多一个 constexpr 、 consteval 及 constinit 说明符。若某个函数或函数模板的任何声明含有 consteval 说明符，则该函数或函数模板的所有声明必须均含该说明符。

立即函数是 constexpr 函数，而且只要情况符合，必须满足适用于 constexpr 函数或 constexpr 构造函数的要求。

当最内层的非块作用域不是某个立即函数的函数形参作用域 或 consteval if 语句的 true 分支 (C++23 起)时，对立即函数的潜在求值的调用必须产生常量表达式；这种调用称为立即调用（immediate invocation）。

consteval int sqr(int n) {
  return n*n;
}
constexpr int r = sqr(100);  // OK

int x = 100;
int r2 = sqr(x);  // 错误：调用不产生常量

consteval int sqrsqr(int n) {
  return sqr(sqr(n)); // 在此点非常量表达式，但是 OK
}

constexpr int dblsqr(int n) {
  return 2*sqr(n); // 错误：外围函数并非 consteval 且 sqr(n) 不是常量
}

指代某个立即函数的标识表达式，仅可出现在立即调用的子表达式内，或某个立即函数语境（即前述的语境，在其中对立即函数的调用不需要是常量表达式）内。可以取得立即函数的指针或引用，但它们不可逃出常量表达式求值：

consteval int f() { return 42; }
consteval auto g() { return &f; }
consteval int h(int (*p)() = g()) { return p(); }
constexpr int r = h();   // OK
constexpr auto e = g();  // 非良构：指向立即函数的指针不是常量表达式的容许结果

关键词

consteval

示例

本节未完成
原因：暂无示例

参阅

  • constexpr
  • constinit
  • 常量表达式


constexpr 说明符(C++11 起)

< cpp‎ | language
  • constexpr - 指定变量或函数的值可以在常量表达式中出现

解释

constexpr 说明符声明编译时可以对函数或变量求值值。这些变量和函数（给定了合适的函数实参的情况下）即可用于需要编译期常量表达式的地方。

声明对象或非静态成员函数 (C++14 前)时使用 constexpr 说明符则同时蕴含 const。声明函数或静态成员变量 (C++17 起)时使用 constexpr 说明符则同时蕴含 inline。如果一个函数或函数模板的某个声明拥有 constexpr 说明符，则其所有声明都必须含有该说明符。

constexpr 变量必须满足下列要求：

  • 它的类型必须是字面类型 (LiteralType) 。
  • 它必须被立即初始化。
  • 它的初始化包括所有隐式转换、构造函数调用等的全表达式必须是常量表达式

  • 它必须拥有常量析构，即：
  • 它不是类类型亦或其（可能多维的）数组，或
  • 它是类类型或其（可能多维的）数组，且该类类型拥有 constexpr 析构函数；对于作用仅为销毁该对象的虚设表达式 e ，如果该对象与其非 mutable 子对象（但非其 mutable 子对象）的生存期始于 e 内，那么 e 是核心常量表达式。
 (C++20 起)

如果 constexpr 变量非翻译单元局部，那么它不应被初始化为指向或指代可用于常量表达式的翻译单元局部实体，或拥有指向或指代这种实体的（可能递归的）子对象。这种初始化在模块接口单元（在其私有模块片段外，如果存在）或模块划分中被禁止，并在任何其他语境中被弃用。

 (C++20 起)

constexpr 函数必须满足下列要求：

  • 它必须非虚
 (C++20 前)
  • 它必须不是协程
 (C++20 起)
  • 它的返回类型（如果存在）必须是字面类型 (LiteralType)
  • 它的每个参数都必须是字面类型 (LiteralType)
  • 对于构造函数与析构函数 (C++20 起)，该类必须无虚基类
  • 至少存在一组实参值，使得函数的一个调用为核心常量表达式的被求值的子表达式（对于构造函数为足以用于常量初始化器） (C++14 起)。不要求诊断是否违反这点。
  • 它的函数体必须不是函数 try 块
 (C++20 前)
  • 函数体必须被弃置或预置，或只含有下列内容：
  • 空语句（仅分号）
  • static_assert 声明
  • 不定义类或枚举的 typedef 声明及别名声明
  • using 声明
  • using 指令
  • 恰好一条 return 语句，当函数不是构造函数时。
 (C++14 前)

  • 函数体必须不含：
  • goto 语句
  • 拥有除 case 和 default 之外的带有标签的语句
  • try 块
  • asm 声明
  • 不进行初始化的变量定义
 (C++20 前)
  • 非字面类型的变量定义
  • 静态或线程存储期变量的定义
（是 =default; 或 =delete; 的函数体均不含任何上述内容。）
 (C++14 起)
(C++23 前)

函数体非 =delete; 的 constexpr 构造函数必须满足下列额外要求：

  • 对于类或结构体的构造函数，每个子对象和每个非变体非静态数据成员必须被初始化。若类是联合体式的类，对于其每个非空匿名联合体成员，必须恰好有一个变体成员被初始化
  • 对于非空联合体的构造函数，恰好有一个非静态数据成员被初始化
 (C++20 前)
  • 每个被选用于初始化非静态成员和基类的构造函数必须是 constexpr 构造函数。

析构函数不能为 constexpr，但能在常量表达式中隐式调用平凡析构函数。

 (C++20 前)

函数体非 =delete; 的 constexpr 析构函数必须满足下列额外要求：

  • 每个用于销毁非静态数据成员与基类的析构函数必须是 constexpr 析构函数。
 (C++20 起)

对于 constexpr 函数模板和类模板的 constexpr 函数成员，必须至少有一个特化满足上述要求。其他特化仍被认为是 constexpr 的，尽管常量表达式中不能出现这种函数的调用。

注解

因为 noexcept 运算符始终对常量表达式返回 true，所以它可以用于检查具体特定的 constexpr 函数调用是否采用常量表达式分支：

constexpr int f();
constexpr bool b1 = noexcept(f()); // false，constexpr 函数未定义
constexpr int f() { return 0; }
constexpr bool b2 = noexcept(f()); // true，f() 是常量表达式
 (C++17 前)

constexpr 构造函数允许用于非字面类型的类。例如，std::unique_ptr 的默认构造函数是 constexpr，允许常量初始化。

引用变量可声明为 constexpr（其初始化器必须是引用常量表达式）：

static constexpr int const& x = 42; // 到 const int 对象的 constexpr 引用
                                    // （该对象拥有静态存储期，因为静态引用延长了生存期）

尽管在 constexpr 函数中允许 try 块与内联汇编，但是常量表达式中仍然不允许抛出异常或执行汇编。

若变量拥有常量析构，则无需为调用其析构函数而生成机器码，即使其析构函数非平凡。

 (C++20 起)

关键词

constexpr

示例

计算阶乘的 C++11 constexpr 函数的定义，及扩展字符串字面量的字面类型：

#include <iostream>
#include <stdexcept>

// C++11 constexpr 函数使用递归而非迭代
// （C++14 constexpr 函数可使用局部变量和循环）
constexpr int factorial(int n)
{
    return n <= 1 ? 1 : (n * factorial(n - 1));
}

// 字面类
class conststr {
    const char* p;
    std::size_t sz;
public:
    template<std::size_t N>
    constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {}

    // constexpr 函数通过抛异常来提示错误
    // C++11 中，它们必须用条件运算符 ?: 来这么做
    constexpr char operator[](std::size_t n) const
    {
        return n < sz ? p[n] : throw std::out_of_range("");
    }
    constexpr std::size_t size() const { return sz; }
};

// C++11 constexpr 函数必须把一切放在单条 return 语句中
// （C++14 无此要求）
constexpr std::size_t countlower(conststr s, std::size_t n = 0,
                                             std::size_t c = 0)
{
    return n == s.size() ? c :
           'a' <= s[n] && s[n] <= 'z' ? countlower(s, n + 1, c + 1) :
                                        countlower(s, n + 1, c);
}

// 输出要求编译时常量的函数，用于测试
template<int n>
struct constN
{
    constN() { std::cout << n << '\n'; }
};

int main()
{
    std::cout << "4! = " ;
    constN<factorial(4)> out1; // 在编译时计算

    volatile int k = 8; // 使用 volatile 防止优化
    std::cout << k << "! = " << factorial(k) << '\n'; // 运行时计算

    std::cout << "\"Hello, world!\" 里小写字母的个数是 ";
    constN<countlower("Hello, world!")> out2; // 隐式转换到常量字符串
}

输出：

4! = 24
8! = 40320
"Hello, world!" 里小写字母的个数是 9

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1911 | C++11 | 非字面类型不允许拥有 constexpr 构造函数 | 在常量初始化中允许
CWG 2004 | C++14 | 在常量表达式中允许复制/移动有 mutable 成员的联合体 | mutable 变体现在无法被隐式复制/移动
CWG 2163 | C++14 | constexpr 函数中禁止 goto，但允许标号 | 标号也被禁止
CWG 2268 | C++14 | cwg 2004 曾禁止了复制/移动有 mutable 成员的联合体 | 在该对象在常量表达式中创建的情况下允许

参阅

  • 常量表达式
  • consteval
  • constinit


constinit 说明符 (C++20 起)

< cpp‎ | language
  • constinit - 断言变量拥有静态初始化，即零初始化与常量初始化，否则程序非良构。

解释

constinit 说明符声明拥有静态或线程存储期的变量。若变量以 constinit 声明，则其初始化声明必须应用 constinit 。若以 constinit 声明的变量拥有动态初始化，则程序非良构。若在初始化声明点无可达的 constinit 声明，则程序非良构，不需要诊断。

constinit 不能和 constexpr 或 consteval 一同使用。声明的变量为引用时， constinit 等价于 constexpr 。声明的变量为对象时， constexpr 强制对象必须拥有静态初始化和常量析构，并使对象有 const 限定，然而 constinit 不强制常量析构和 const 限定。结果是拥有 constexpr 构造函数且无 constexpr 析构函数的类型（例如 std::shared_ptr <T> ）的对象可能可以用 constinit ，但不能用 constexpr 声明。

const char *g() { return "dynamic initialization"; }
constexpr const char *f(bool p) { return p ? "constant initializer" : g(); }

constinit const char *c = f(true); // OK
// constinit const char *d = f(false); // 错误

constinit 亦能用于非初始化声明，以告知编译器 thread_local 变量已被初始化，以减少隐藏的防卫变量所致的开销。

extern thread_local constinit int x;
int f() { return x; } // 无需检查防卫变量

关键词

constinit

示例

本节未完成
原因：暂无示例

参阅

  • consteval
  • constexpr
  • 常量表达式
  • 常量初始化
  • 零初始化


约束与概念 (C++20 起)

< cpp‎ | language
本页面描述了 C++20 接纳的核心语言特性。对于标准库中使用的具名类型要求，见具名要求。有关这个功能特性的概念 TS 版本，见此处。

类模板，函数模板，以及非模板函数（通常是类模板的成员），可以关联到约束（constraint），它指定了对模板实参的一些要求，这些要求可以被用于选择最恰当的函数重载和模板特化。

这种要求的具名集合被称为概念（concept）。每个概念都是谓词，在编译时求值，并在自己被用作约束时成为模板接口的一部分：

#include <string>
#include <cstddef>
#include <concepts>

// 概念 "Hashable" 的声明可以被符合以下条件的任意类型 T 满足：
// 对于 T 类型的值 a，表达式 std::hash<T>{}(a) 可以编译并且它的结果可以转换到 std::size_t
template<typename T>
concept Hashable = requires(T a)
{
    { std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
};

struct meow {};

template<Hashable T>
void f(T); // 受约束的 C++20 函数模板

// 应用相同约束的另一种方式：
// template<typename T>
//     requires Hashable<T>
// void f(T);
//
// template<typename T>
// void f(T) requires Hashable<T>;

int main()
{
    using std::operator""s;

    f("abc"s); // OK，std::string 满足 Hashable
    f(meow{}); // 错误：meow 不满足 Hashable
}

在编译时（模板实例化过程的早期）就检测是否违背约束，这样错误信息就更容易理解：

std::list<int> l = {3,-1,10};
std::sort(l.begin(), l.end());
// 没有概念时典型编译器的诊断：
// 二元表达式的操作数非法 ('std::_List_iterator<int>' 和 'std::_List_iterator<int>')
//                           std::__lg(__last - __first) * 2);
//                                     ~~~~~~ ^ ~~~~~~~
// …… 50 行输出……
//
// 有概念时典型编译器的诊断：
// 错误：无法以 std::_List_iterator<int> 调用 std::sort
// 注意：未满足概念 RandomAccessIterator<std::_List_iterator<int>>

概念的目的是塑造语义分类（Number、Range、RegularFunction）而非语法上的限制（HasPlus、Array）。按照 ISO C++ 核心方针 T.20 所说，“与语法限制相反，真正的概念的一个决定性的特征是有能力指定有意义的语义。”

概念

概念是要求的具名集合。概念的定义必须在命名空间作用域中出现。

概念定义拥有以下形式：

template < 模板形参列表 >

concept 概念名 = 约束表达式;

// 概念
template<class T, class U>
concept Derived = std::is_base_of<U, T>::value;

概念不能递归地提及自身，而且不能受约束：

template<typename T>
concept V = V<T*>; // 错误：递归的概念

template<class T>
concept C1 = true;
template<C1 T>
concept Error1 = true; // 错误：C1 T 试图约束概念定义
template<class T> requires C1<T>
concept Error2 = true; // 错误：requires 子句试图约束概念

概念不能被显式实例化、显式特化或部分特化（不能更改约束的原初定义的含义）。

概念可以在标识表达式中命名。该标识表达式的值在满足约束表达式时是 true，否则是 false。

概念在作为以下内容的一部分时也可以在类型约束中被命名：

  • 类型模板形参声明
  • 占位类型说明符
  • 复合要求

概念在 类型约束 中接受的实参要比它的形参列表要求的要少一个，因为按语境推导出的类型会隐式地用作第一个实参：

template<class T, class U>
concept Derived = std::is_base_of<U, T>::value;

template<Derived<Base> T>
void f(T); // T 被 Derived<T, Base> 约束

约束

约束是逻辑操作和操作数的序列，它了指定对模板实参的要求。它们可以在 requires 表达式（见下文）中出现，也可以直接作为概念的主体。

有三种类型的约束：

1) 合取（conjunction）
2) 析取（disjunction）
3) 不可分割约束（atomic constraint）

对包含遵循以下顺序的操作数的逻辑与表达式进行规范化，确定与一个声明关联的约束：

  • 每个声明中受约束的类型模板形参或带占位类型声明的非类型模板形参所引入的约束表达式，按出现顺序；
  • 模板形参列表之后的 requires 子句中的约束表达式；
  • 简写函数模板声明中每个拥有受约束占位类型的形参所引入的约束表达式;
  • 尾部的 requires 子句中的约束表达式。

这个顺序决定了在检查是否满足时各个约束时的实例化顺序。

受约束的声明只能以相同的语法形式重声明。不要求诊断：

template<Incrementable T>
void f(T) requires Decrementable<T>;

template<Incrementable T>
void f(T) requires Decrementable<T>; // OK：重声明

template<typename T>
    requires Incrementable<T> && Decrementable<T>
void f(T); // 非良构，不要求诊断

// 下列两个声明拥有不同的约束：
// 第一个声明拥有 Incrementable<T> && Decrementable<T>
// 第二个声明拥有 Decrementable<T> && Incrementable<T>
// 尽管它们在逻辑上等价

template<Incrementable T>
void g(T) requires Decrementable<T>;

template<Decrementable T>
void g(T) requires Incrementable<T>; // 非良构，不要求诊断

合取

两个约束的合取是通过在约束表达式中使用 && 运算符来构成的：

template<class T>
concept Integral = std::is_integral<T>::value;
template<class T>
concept SignedIntegral = Integral<T> && std::is_signed<T>::value;
template<class T>
concept UnsignedIntegral = Integral<T> && !SignedIntegral<T>;

两个约束的合取只有在两个约束都被满足时才会得到满足。合取从左到右短路求值（如果不满足左侧的约束，那么就不会尝试对右侧的约束进行模板实参替换：这样就会防止出现立即语境外的替换所导致的失败）。

template<typename T>
constexpr bool get_value() { return T::value; }

template<typename T>
    requires (sizeof(T) > 1 && get_value<T>())
void f(T);   // #1

void f(int); // #2

void g()
{
    f('A'); // OK，调用 #2。当检查 #1 的约束时，
            // 不满足 'sizeof(char) > 1'，故不检查 get_value<T>()
}

析取

两个约束的析取，是通过在约束表达式中使用 || 运算符来构成的：

如果其中一个约束得到满足，那么两个约束的析取的到满足。析取从左到右短路求值（如果满足左侧约束，那么就不会尝试对右侧约束进行模板实参替换）。

template<class T = void>
    requires EqualityComparable<T> || Same<T, void>
struct equal_to;

不可分割约束

不可分割约束由一个表达式 E，和一个从 E 内出现的模板形参到（对受约束实体的各模板形参的有所涉及的）模板实参的映射组成。这种映射被称作形参映射。

不可分割约束在约束规范化过程中形成。E 始终不会是逻辑与（AND）或者逻辑或（OR）表达式（它们分别构成析取和合取）。

对不可分割约束是否满足的检查会通过替换形参映射和各个模板实参到表达式 E 中来进行。如果替换产生了无效的类型或表达式，那么约束就没有被满足。否则，在任何左值到右值转换后，E 应当是 bool 类型的纯右值常量表达式，当且仅当它求值为 true 时该约束得以满足。

E 在替换后的类型必须严格为 bool。不能有任何转换：

template<typename T>
struct S
{
    constexpr operator bool() const { return true; }
};

template<typename T>
    requires (S<T>{})
void f(T);   // #1

void f(int); // #2

void g()
{
    f(0); // 错误：检查 #1 时 S<int>{} 不具有 bool 类型，
          // 尽管 #2 能更好地匹配
}

如果两个不可分割约束由在源码层面上相同的表达式组成，且它们的形参映射等价，那么认为它们等同。

template<class T>
constexpr bool is_meowable = true;

template<class T>
constexpr bool is_cat = true;

template<class T>
concept Meowable = is_meowable<T>;

template<class T>
concept BadMeowableCat = is_meowable<T> && is_cat<T>;

template<class T>
concept GoodMeowableCat = Meowable<T> && is_cat<T>;

template<Meowable T>
void f1(T); // #1

template<BadMeowableCat T>
void f1(T); // #2

template<Meowable T>
void f2(T); // #3

template<GoodMeowableCat T>
void f2(T); // #4

void g()
{
    f1(0); // 错误，有歧义：
           // BadMeowableCat 和 Meowable 中的 is_meowable<T>
           // 构成了有区别的不可分割约束且它们并不等同（因此它们不互相包含）

    f2(0); // OK，调用 #4，它比 #3 更受约束
           // GoodMeowableCat 从 Meowable 获得其 is_meowable<T>
}

约束规范化

约束规范化是将一个约束表达式变换为一个不可分割约束的合取与析取的序列的过程。表达式的范式定义如下：

  • 表达式 (E) 的范式就是 E 的范式；
  • 表达式 E1 && E2 的范式是 E1 和 E2 范式的合取；
  • 表达式 E1 || E2 的范式是 E1 和 E2 范式的析取；
  • 表达式 C<A1, A2, ... , AN>（其中 C 指名某个概念）的范式，是以 A1, A2, ... , AN 对 C 的每个不可分割约束的形参映射中的 C 的对应模板形参进行替换之后，C 的约束表达式的范式。如果在这种形参映射中的替换产生了无效的类型或表达式，那么程序非良构，不要求诊断。
template<typename T>
concept A = T::value || true;

template<typename U>
concept B = A<U*>; // OK：规范化为以下各项的析取
                   // - T::value（映射为 T -> U*）和
                   // - true（映射为空）。
                   // 映射中没有无效类型，尽管 T::value 对所有指针类型均非良构

template<typename V>
concept C = B<V&>; // 规范化为以下的析取
                   // - T::value（映射为 T-> V&*）和
                   // - true（映射为空）。
                   // 映射中构成了无效类型 V&* => 非良构，不要求诊断
  • 任何其他表达式 E 的范式是一条不可分割约束，它的表达式是 E 而它的形参映射是恒等映射。这包括所有折叠表达式，甚至包括以 && 或 || 运算符进行的折叠。

用户定义的 && 或 || 重载在约束规范化上无效。

requires 子句

关键词 requires 用来引入 requires 子句，它指定对各模板实参，或对函数声明的约束。

template<typename T>
void f(T&&) requires Eq<T>; // 可以作为函数声明符的末尾元素出现

template<typename T> requires Addable<T> // 或者在模板形参列表的右边
T add(T a, T b) { return a + b; }

这种情况下，关键词 requires 必须后随某个常量表达式（因此可以写成 requires true），但这是为了使用一个具名概念（如上例），具名概念的一条合取/析取，或者一个 requires 表达式。

表达式必须具有下列形式之一：

  • 初等表达式，例如 Swappable<T>、std::is_integral <T>::value、( std::is_object_v <Args> && ...) 或任何带括号的表达式
  • 以运算符 && 联结的初等表达式的序列
  • 以运算符 || 联结的前述表达式的序列
template<class T>
constexpr bool is_meowable = true;

template<class T>
constexpr bool is_purrable() { return true; }

template<class T>
void f(T) requires is_meowable<T>; // OK

template<class T>
void g(T) requires is_purrable<T>(); // 错误：is_purrable<T>() 不是初等表达式

template<class T>
void h(T) requires (is_purrable<T>()); // OK

requires 表达式

关键词 requires 也用来开始一个 requires 表达式，它是 bool 类型的纯右值表达式，描述对一些模板实参的约束。这种表达式在约束得到满足时是 true，否则是 false：

template<typename T>
concept Addable = requires (T x) { x + x; }; // requires 表达式

template<typename T> requires Addable<T> // requires 子句，不是 requires 表达式
T add(T a, T b) { return a + b; }

template<typename T>
    requires requires (T x) { x + x; } // 随即的约束，注意关键字被使用两次
T add(T a, T b) { return a + b; }

requires 表达式的语法如下：

requires { 要求序列 }
requires ( 形参列表(可选) ) { 要求序列 }
形参列表 | - | 与函数声明中类似的以逗号分隔的形参列表，但不能有默认实参且不能以（并非指定包展开的）省略号结尾。这些形参没有存储期、连接或生存期，它们只会用来辅助进行各个要求的制定。这些形参在 要求序列 的闭 } 前处于作用域中。
要求序列 | - | 要求（requirement）的序列，描述于下（每个要求以分号结尾）。

要求序列 中的每个要求是下列之一：

  • 简单要求（simple requirement）
  • 类型要求（type requirement）
  • 复合要求（compound requirement）
  • 嵌套要求（nested requirement）

要求可以提及处于作用域中的模板形参，由 形参列表 引入的局部形参，以及从它的外围语境中可见的任何其他声明。

对模板化实体的声明中所使用的 requires 表达式进行模板实参替换，可能导致在其要求中形成无效的类型或表达式，或违反这些要求的语义约束。这些情况下，该 requires 表达式求值为 false 而不会导致程序非良构。替换和语义约束检查按词法顺序执行，并在遇到确定 requires 表达式结果的条件时停止。如果替换（如果存在）和语义约束检查成功，那么 requires 表达式求值为 true。

如果对于每一种可能的模板实参 requires 表达式中都会出现替换失败，那么程序非良构，不要求诊断：

template<class T>
concept C = requires
{
    new int[-(int)sizeof(T)]; // 对每个 T 均为无效：非良构，不要求诊断
};

如果 requires 表达式在它的约束中含有无效的类型或表达式，而它并不在模板化实体的声明内出现，那么程序非良构。

简单要求

简单要求是不以 requires 关键词起始的任意表达式语句。它断言该表达式合法。该表达式是不求值操作数；只检查语言正确性。

template<typename T>
concept Addable = requires (T a, T b)
{
    a + b; // “表达式 a + b 是可编译的合法表达式”
};

template <class T, class U = T>
concept Swappable = requires(T&& t, U&& u)
{
    swap(std::forward<T>(t), std::forward<U>(u));
    swap(std::forward<U>(u), std::forward<T>(t));
};

以 requires 关键词起始的要求始终会被解读成嵌套要求。因此简单要求不能以无括号的 requires 表达式起始。

类型要求

类型要求是关键词 typename 后随一个可以有限定的类型名。它的要求是该类型名合法：这可以用来校验某个具名嵌套类型存在，或某个类模板特化指名一个类型，或某个别名模板特化指名一个类型。指名类模板特化的类型要求不要求该类型完整。

template<typename T>
using Ref = T&;

template<typename T>
concept C = requires
{
    typename T::inner; // 要求的嵌套成员名
    typename S<T>;     // 要求的类模板特化
    typename Ref<T>;   // 要求的别名模板替换
};

template <class T, class U>
using CommonType = std::common_type_t<T, U>;

template <class T, class U>
concept Common = requires (T t, U u)
{
    typename CommonType<T, U>; // CommonType<T, U> 合法并指名一个类型
    { CommonType<T, U>{std::forward<T>(t)} };
    { CommonType<T, U>{std::forward<U>(u)} };
};

复合要求

复合要求的形式为

{ 表达式 } noexcept(可选) 返回类型要求(可选) ;
返回类型要求 - -> 类型约束

并断言该具名表达式的各项性质。以下列顺序进行替换和语义约束检查：

1) 替换模板实参（若存在）到 表达式 中；
2) 如果使用了 noexcept，那么 表达式 必须不会抛出；
3) 如果出现了 返回类型规定，那么：
a) 替换模板实参到 返回类型规定 中；
b) decltype((表达式)) 必须满足有该 类型约束 所蕴含的约束。否则，外围 requires 表达式为 false。
template<typename T>
concept C2 = requires(T x)
{
    // 表达式 *x 必须合法
    // 并且类型 T::inner 必须合法
    // 并且 *x 的结果必须可以转换为 T::inner
    {*x} -> std::convertible_to<typename T::inner>;

    // 表达式 x + 1 必须合法
    // 并且 std::Same<decltype((x + 1)), int> 必须被满足
    // 也就是说，(x + 1) 必须是 int 类型的纯右值
    {x + 1} -> std::same_as<int>;

    // 表达式 x * 1 必须合法
    // 并且它的结果必须可以转换到 T
    {x * 1} -> std::convertible_to<T>;
};

嵌套要求

嵌套要求的形式为

requires 约束表达式 ;

它可以用来以局部形参来指定额外的约束。约束表达式 必须被所替换的模板实参（如果存在）所满足。在嵌套要求中进行模板实参的替换所导致的在 约束表达式 中的替换只会进行到足以确定 约束表达式 是否得到满足所需的程度。

template <class T>
concept Semiregular = DefaultConstructible<T> &&
    CopyConstructible<T> && Destructible<T> && CopyAssignable<T> &&
requires(T a, size_t n)
{
    requires Same<T*, decltype(&a)>; // 嵌套：“Same<...> 求值为 true”
    { a.~T() } noexcept; // 复合："a.~T()" 是不抛出的合法表达式
    requires Same<T*, decltype(new T)>; // 嵌套：“Same<...> 求值为 true”
    requires Same<T*, decltype(new T[n])>; // 嵌套
    { delete new T }; // 复合
    { delete new T[n] }; // 复合
};

约束的偏序

在任何进一步的分析之前都会对各个约束进行规范化，对每个具名概念的主体和每个 requires 表达式进行替换，直到剩下不可分割约束的合取与析取的序列为止。

如果根据约束 P 和约束 Q 中的各不可分割约束的同一性可以证明 P 蕴含 Q，那么称 P 归入（subsume） Q。（并进行类型和表达式的等价性分析：N > 0 并不归入 N >= 0）。

具体来说，首先转换 P 为析取范式并转换 Q 为合取范式。当且仅当以下情况下 P 归入 Q：

  • P 的析取范式中的每个析取子句都能归入 Q 的合取范式中的每个合取子句，其中
  • 当且仅当析取子句中存在不可分割约束 U 而合取子句中存在不可分割约束 V，使得 U 归入 V 时，析取子句能归入合取子句；
  • 当且仅当使用上文所述的规则判定为等同时，称不可分割约束 A 能归入不可分割约束 B。

归入关系定义了约束的偏序，用于确定：

  • 重载决议中非模板函数的最佳可行候选
  • 重载集中的非模板函数的地址
  • 模板模板实参的最佳匹配
  • 类模板特化的偏序
  • 函数模板的偏序
本节未完成
原因：从上述内容添加到此的回链

如果声明 D1 和 D2 均受约束，且 D1 关联的约束能归入 D2 关联的约束，（或 D2 没有约束），那么称 D1 与 D2 相比至少一样受约束。如果 D1 至少与 D2 一样受约束，而 D2 并非至少与 D1 一样受约束，那么 D1 比 D2 更受约束。

template<typename T>
concept Decrementable = requires(T t) { --t; };
template<typename T>
concept RevIterator = Decrementable<T> && requires(T t) { *t; };

// RevIterator 能归入 Decrementable，但反之不行

template<Decrementable T>
void f(T); // #1

template<RevIterator T>
void f(T); // #2，比 #1 更受约束

f(0);       // int 只满足 Decrementable，选择 #1
f((int*)0); // int* 满足两个约束，选择 #2，因为它更受约束

template<class T>
void g(T); // #3（无约束）

template<Decrementable T>
void g(T); // #4

g(true); // bool 不满足 Decrementable，选择 #3
g(0);    // int 满足 Decrementable，选择 #4，因为它更受约束

template<typename T>
concept RevIterator2 = requires(T t) { --t; *t; };

template<Decrementable T>
void h(T); // #5

template<RevIterator2 T>
void h(T); // #6

h((int*)0); // 有歧义

关键词

concept, requires


continue 语句

< cpp‎ | language

导致外围 for、范围 for、while 或 do-while 循环体的剩余部分被跳过。

可以在不用它而用条件语句忽略循环的剩余部分显得笨拙时使用。

语法

属性(可选) continue ;

解释

continue 语句导致跳转，如同用 goto 跳转到循环体末尾一样（它只能出现在 for、范围 for、while 及 do-while 循环的循环体内）。

更确切地说，

对于 while 循环，它表现为：

while (/* ... */) {
   // ...
   continue; // 作用如同 goto contin;
   // ...
   contin:;
}

对于 do-while 循环，它表现为：

do {
    // ...
    continue; // 作用如同 goto contin;
    // ...
    contin:;
} while (/* ... */);

对于 for 和范围 for 循环，它表现为：

for (/* ... */) {
    // ...
    continue; // 作用如同 goto contin;
    // ...
    contin:;
}

关键词

continue

示例

#include <iostream>

int main()
{
    for (int i = 0; i < 10; i++) {
        if (i != 5) continue;
        std::cout << i << " ";       // 每次 i!=5 时跳过此语句
    }

    std::cout << '\n';

    for (int j = 0; j < 2; j++) {
        for (int k = 0; k < 5; k++) {   // continue 只会影响此循环
            if (k == 3) continue;
            std::cout << j << k << " "; // 每次 k==3 时跳过此语句
        }
    }
}

输出：

5
00 01 02 04 10 11 12 14

参阅


转换构造函数

< cpp‎ | language

不以说明符 explicit 声明且可以用单个参数调用 (C++11 前)的构造函数被称为转换构造函数（converting constructor）。

与只在直接初始化（包括如 static_cast 这样的显式转换）中被考虑的显式构造函数不同，转换构造函数也会作为用户定义的转换序列中的一部分而在复制初始化的考虑范围内。

通常说法是转换构造函数指定了一个从它的实参类型（如果存在）到它的类类型的隐式转换。注意非显式的用户定义转换函数也指定了一个隐式转换。

隐式声明的及用户定义的非显式复制构造函数与移动构造函数也是转换构造函数。

示例

struct A
{
    A() { }         // 转换构造函数 (C++11 起)
    A(int) { }      // 转换构造函数
    A(int, int) { } // 转换构造函数 (C++11 起)
};

struct B
{
    explicit B() { }
    explicit B(int) { }
    explicit B(int, int) { }
};

int main()
{
    A a1 = 1;      // OK：复制初始化选择 A::A(int)
    A a2(2);       // OK：直接初始化选择 A::A(int)
    A a3{4, 5};    // OK：直接列表初始化选择 A::A(int, int)
    A a4 = {4, 5}; // OK：复制列表初始化选择 A::A(int, int)
    A a5 = (A)1;   // OK：显式转型进行 static_cast，是直接初始化

//  B b1 = 1;      // 错误：复制初始化不考虑 B::B(int)
    B b2(2);       // OK：直接初始化选择 B::B(int)
    B b3{4, 5};    // OK：直接列表初始化选择 B::B(int, int)
//  B b4 = {4, 5}; // 错误：复制列表初始化选择了显式构造函数 B::B(int, int)
    B b5 = (B)1;   // OK：显式转型进行 static_cast，是直接初始化
    B b6;          // OK：默认初始化
    B b7{};        // OK：直接列表初始化
//  B b8 = {};     // 错误：复制列表初始化选择了显式构造函数 B::B()
}


复制赋值运算符

< cpp‎ | language

类 T 的复制赋值运算符是名为 operator= 的非模板非静态成员函数，它接受恰好一个 T、T&、const T&、volatile T& 或 const volatile T& 类型的形参。可复制赋值 (CopyAssignable) 类型必须有公开的复制赋值运算符。

语法

类名 & 类名 :: operator= ( 类名 ) | (1) |
类名 & 类名 :: operator= ( const 类名 & ) | (2) |
类名 & 类名 :: operator= ( const 类名 & ) = default; | (3) | (C++11 起)
类名 & 类名 :: operator= ( const 类名 & ) = delete; | (4) | (C++11 起)

解释

1) 复制赋值运算符在采用复制交换法时的典型声明。
2) 复制赋值运算符在不采用复制交换法时的典型声明。
3) 强制编译器生成复制赋值运算符。
4) 避免隐式复制赋值。

每当重载决议选择复制赋值运算符时，它都会被调用，例如对象出现在赋值表达式左侧时。

隐式声明的复制赋值运算符

如果没有对类类型（struct、class 或 union）提供任何用户定义的复制赋值运算符，那么编译器将始终声明一个，作为类的 inline public 成员。如果满足下列所有条件，那么这个隐式声明的复制赋值运算符拥有形式 T& T::operator=(const T&)：

  • T 的每个直接基类 B 均拥有形参为 B，const B& 或 const volatile B& 的复制赋值运算符；
  • T 的每个类类型或类数组类型的非静态数据成员 M 均拥有形参为 M，const M& 或 const volatile M& 的复制赋值运算符。

否则，隐式声明的复制赋值运算符会被声明为 T& T::operator=(T&)。（注意因为这些规则，隐式声明的复制赋值运算符不能绑定到 volatile 左值实参。）

类可以拥有多个复制赋值运算符，如 T& T::operator=(T&) 和 T& T::operator=(T)。当存在用户定义的复制赋值运算符时，用户仍然可以通过关键词 default 强迫编译器生成隐式声明的复制赋值运算符。 (C++11 起)

隐式声明（或在它的首个声明被预置）的复制赋值运算符具有动态异常说明 (C++17 前)noexcept 说明 (C++17 起)中所描述的异常说明。

因为每个类总是会声明复制赋值运算符，所以基类的赋值运算符始终会被隐藏。当使用 using 声明从基类带入复制赋值运算符，且它的实参类型与派生类的隐式复制赋值运算符的实参类型相同时，该 using 声明也会被隐式声明隐藏。

弃置的隐式声明的复制赋值运算符

如果满足下列任一条件，那么类 T 的隐式声明的复制赋值运算符被定义为弃置的：

  • T 拥有用户声明的移动构造函数；
  • T 拥有用户声明的移动赋值运算符。

否则，它被定义为预置的。

如果满足下列任一条件，那么类 T 的预置的复制赋值运算符被定义为弃置的：

  • T 拥有具有 const 限定的非类类型（或其数组）的非静态数据成员；
  • T 拥有引用类型的非静态数据成员；
  • T 拥有无法复制赋值的非静态数据成员，直接基类或虚基类（对复制赋值的重载决议失败，或选择弃置或不可访问的函数）；
  • T 是联合体式的类，且拥有的某个变体成员对应的复制赋值运算符是非平凡的。

平凡的复制赋值运算符

如果满足下列所有条件，那么类 T 的复制赋值运算符是平凡的：

  • 它不是用户提供的（即它是隐式定义或预置的）；
  • T 没有虚成员函数；
  • T 没有虚基类；
  • 为 T 的每个直接基类选择的复制赋值运算符都是平凡的；
  • 为 T 的每个类类型（或类类型的数组）的非静态数据成员选择的复制赋值运算符都是平凡的。

平凡复制赋值运算符如同用 std::memmove 进行对象表示的复制。所有与 C 语言兼容的数据类型（POD 类型）都可以平凡复制。

合格的复制赋值运算符

被用户声明或者同时被隐式声明且可定义的复制赋值运算符是合格的。

 (C++11 前)

没有被弃置的复制赋值运算符是合格的。

 (C++11 起)
(C++20 前)

满足下列所有条件的复制赋值运算符是合格的：

  • 它没有被弃置，且
  • 满足它的所有关联约束（如果存在），且
  • 没有比它更受约束且拥有相同的第一形参类型和相同的 cv 或引用限定符（如果存在）的复制赋值运算符。
 (C++20 起)

合格复制赋值运算符的平凡性确定该类是否为可平凡复制类型。

隐式定义的复制赋值运算符

如果隐式声明的复制赋值运算符既没有被弃置也不平凡，那么当它被 ODR 式使用 或用于常量求值 (C++14 起)时，它会被编译器定义（即生成并编译函数体）。对于联合体类型，隐式定义的复制赋值运算符（如同以 std::memmove）复制其对象表示。对于非联合类类型（class 与 struct），编译器按照声明顺序对对象的各基类和非静态成员进行逐成员复制赋值，其中对标量进行内建赋值，而对类类型使用复制赋值运算符，

如果满足下列所有条件，那么类 T 的隐式定义的复制赋值运算符是 constexpr 的：

  • T 是字面类型，且
  • 复制每个直接基类子对象时选中的赋值运算符都是 constexpr 函数，且
  • 复制 T 的每个类（或其数组）类型的数据成员时选中的赋值运算符都是 constexpr 函数。
 (C++14 起)

当 T 拥有用户定义的析构函数或用户定义的复制赋值运算符时，隐式定义的复制赋值运算符的生成被弃用。

 (C++11 起)

注解

如果复制和移动赋值运算符都有提供，那么重载决议会在实参是右值（例如无名临时量的纯右值 或 std::move 的结果的亡值）时选择移动赋值，而在实参是左值（具名对象或返回左值引用的函数或运算符）时选择复制赋值。如果只提供了复制赋值，那么重载决议对于所有值类别都会选择它（只要它按值或按到 const 的引用接收其实参），从而当移动赋值不可用时，复制赋值将会成为它的后备。

隐式定义的复制赋值运算符是否会多次对在继承网格中可通过多于一条路径访问的虚基类子对象赋值是未指明的（同样适用于移动赋值）。

有关用户定义的复制赋值运算符应当有哪些行为，见赋值运算符重载。

示例

#include <iostream>
#include <memory>
#include <string>
#include <algorithm>

struct A
{
    int n;
    std::string s1;
    // 用户定义的复制赋值（复制交换法）
    A& operator=(A other)
    {
        std::cout << "A 的复制赋值\n";
        std::swap(n, other.n);
        std::swap(s1, other.s1);
        return *this;
    }
};

struct B : A
{
    std::string s2;
    // 隐式定义的复制赋值
};

struct C
{
    std::unique_ptr<int[]> data;
    std::size_t size;
    // 用户定义的复制赋值（非复制交换法）
    // 注意：复制交换法总是会重新分配资源
    C& operator=(const C& other)
    {
        if (this != &other) // 非自赋值
        {
            if (size != other.size) // 资源无法复用
            {
                data.reset(new int[other.size]);
                size = other.size;
            }
            std::copy(&other.data[0], &other.data[0] + size, &data[0]);
        }
        return *this;
    }
};

int main()
{
    A a1, a2;
    std::cout << "a1 = a2 调用 ";
    a1 = a2; // 用户定义的复制赋值

    B b1, b2;
    b2.s1 = "foo";
    b2.s2 = "bar";
    std::cout << "b1 = b2 调用 ";
    b1 = b2; // 隐式定义的复制赋值
    std::cout << "b1.s1 = " << b1.s1 << " b1.s2 = " << b1.s2 << '\n';
}

输出：

a1 = a2 调用 A 的复制赋值
b1 = b2 调用 A 的复制赋值
b1.s1 = foo b1.s2 = bar

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 2094 | C++11 | volatile 子对象使得预置的默认复制赋值运算符非平凡（CWG 496） | 平凡性不受影响
CWG 2171 | C++11 | operator=(X&) = default 非平凡 | 令它平凡

参阅

  • 转换构造函数
  • 复制构造函数
  • 复制消除
  • 默认构造函数
  • 析构函数
  • explicit
  • 初始化
    • 聚合初始化
    • 常量初始化
    • 复制初始化
    • 默认初始化
    • 直接初始化
    • 初始化列表
    • 列表初始化
    • 引用初始化
    • 值初始化
    • 零初始化
  • 移动赋值
  • 移动构造函数
  • new


复制构造函数

< cpp‎ | language

类 T 的复制构造函数是首个形参是 T&、const T&、volatile T& 或 const volatile T&，而且要么没有其他形参，要么剩余形参均有默认值的非模板构造函数。

语法

类名 ( const 类名 & ) | (1) |
类名 ( const 类名 & ) = default; | (2) | (C++11 起)
类名 ( const 类名 & ) = delete; | (3) | (C++11 起)

其中 类名 必须指名当前类（或类模板的当前实例化），或在命名空间作用域或友元声明中声明时，必须是有限定的类名。

解释

1) 复制构造函数的典型声明。
2) 强制编译器生成复制构造函数。
3) 阻止隐式生成复制构造函数。

复制构造函数会在对象从同类型的另一对象（以直接初始化或复制初始化）初始化时调用（除非重载决议选择了更好的匹配或其调用被消除），情况包括：

  • 初始化：T a = b; 或 T a(b);，其中 b 的类型是 T；
  • 函数实参传递：f(a);，其中 a 的类型是 T 而 f 是 void f(T t)；
  • 函数返回：在像 T f() 这样的函数内部的 return a;，其中 a 的类型是 T 且它没有移动构造函数。

隐式声明的复制构造函数

如果没有向类类型（struct、class 或 union）提供任何用户定义的复制构造函数，那么编译器总是会声明一个复制构造函数作为这个类的非 explicit 的 inline public 成员。如果满足下列所有条件，那么这个隐式声明的复制构造函数拥有形式 T::T(const T&)：

  • T 的每个直接基类和虚基类 B 均拥有形参为 const B& 或 const volatile B& 的复制构造函数；
  • T 的每个类类型或类类型数组的非静态数据成员 M 均拥有形参为 const M& 或 const volatile M& 的复制构造函数。

否则，隐式声明的复制构造函数是 T::T(T&)。（注意因为这些规则，隐式声明的复制构造函数不能绑定到 volatile 左值实参）。

类可以拥有多个复制构造函数，如 T::T(const T&) 和 T::T(T&)。

当存在用户定义的复制构造函数时，用户仍可以使用关键词 default 强制编译器生成隐式声明的复制构造函数。

 (C++11 起)

隐式声明（或在它的首个声明被预置）的复制构造函数具有动态异常说明 (C++17 前) noexcept 说明 (C++17 起)中所描述的异常说明。

弃置的隐式声明的复制构造函数

如果满足下列任一条件，那么不定义类 T 的隐式声明的复制构造函数： | (C++11 前)
如果满足下列任一条件，那么类 T 的隐式声明的复制构造函数被定义为弃置的： | (C++11 起)
  • T 拥有无法复制的非静态数据成员（拥有被弃置、不可访问或有歧义的复制构造函数）；
  • T 拥有无法复制的直接或虚基类（拥有被弃置、不可访问或有歧义的复制构造函数）；
  • T 拥有带被弃置或不可访问的析构函数的直接或虚基类；
  • T 是联合体式的类，且拥有带非平凡复制构造函数的变体成员；
  • T 拥有右值引用类型的数据成员；
  • T 拥有用户定义的移动构造函数或移动赋值运算符（此条件只会导致隐式声明的，而非预置的复制构造函数被弃置）。
 (C++11 起)

平凡的复制构造函数

如果满足下列所有条件，那么类 T 的复制构造函数是平凡的：

  • 它不是用户提供的（即它是隐式定义或预置的）；
  • T 没有虚成员函数；
  • T 没有虚基类；
  • 为 T 的每个直接基类选择的复制构造函数都是平凡的；
  • 为 T 的每个类类型（或类类型数组）的非静态成员选择的复制构造函数都是平凡的；

非联合类的平凡复制构造函数的效果是复制实参的每个标量子对象（递归地包含子对象的子对象，以此类推），且不进行其他动作。不过不需要复制填充字节，甚至只要其值相同，每个复制的子对象的对象表示也不必相同。

可平凡复制 (TriviallyCopyable) 对象可以通过手动复制其对象表示来进行复制，例如用 std::memmove。所有与 C 语言兼容的数据类型（POD 类型）都可以平凡复制。

合格的复制构造函数

被用户声明或者同时被隐式声明且可定义的复制构造函数是合格的。

 (C++11 前)

没有被弃置的复制构造函数是合格的。

 (C++11 起)
(C++20 前)

满足下列所有条件的复制构造函数是合格的：

  • 它没有被弃置，且
  • 满足它的所有关联约束（如果存在），且
  • 没有比它更受约束且拥有相同的第一形参类型的复制构造函数。
 (C++20 起)

合格的复制构造函数的平凡性确定该类是否为隐式生存期类型，以及该类是否为可平凡复制类型。

隐式定义的复制构造函数

如果隐式声明的复制构造函数没有被弃置，那么当它被 ODR 式使用 或用于常量求值 (C++11 起)时，它会被编译器定义（即生成并编译函数体）。对于联合体类型，隐式定义的复制构造函数（如同以 std::memmove）复制它的对象表示。对于非联合类类型（class 与 struct），该构造函数用直接初始化，按照初始化顺序，对对象的各基类和非静态成员进行完整的逐成员复制。如果它满足对于 constexpr 构造函数的要求，那么生成的复制构造函数也是 constexpr 的。 (C++11 起)

当 T 拥有用户定义的析构函数或用户定义的复制赋值运算符时，隐式定义的复制构造函数的生成被弃用。

 (C++11 起)

注解

许多情况下，即使复制构造函数能够产生可观测副作用，它们也会被优化掉，见复制消除。

示例

struct A
{
    int n;
    A(int n = 1) : n(n) { }
    A(const A& a) : n(a.n) { } // 用户定义的复制构造函数
};

struct B : A
{
    // 隐式默认构造函数 B::B()
    // 隐式复制构造函数 B::B(const B&)
};

struct C : B
{
     C() : B() { }
 private:
     C(const C&); // 不可复制，C++98 风格
};

int main()
{
    A a1(7);
    A a2(a1); // 调用复制构造函数
    B b;
    B b2 = b;
    A a3 = b; // 转换到 A& 并调用复制构造函数
    volatile A va(10);
    // A a4 = va; // 编译错误

    C c;
    // C c2 = c; // 编译错误
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 2094 | C++11 | volatile 成员会导致复制非平凡（CWG 496） | 平凡性不受影响
CWG 2171 | C++11 | X(X&) = default 非平凡 | 使它平凡

参阅

  • 转换构造函数
  • 复制赋值
  • 复制消除
  • 默认构造函数
  • 析构函数
  • explicit
  • 初始化
    • 聚合初始化
    • 常量初始化
    • 复制初始化
    • 默认初始化
    • 直接初始化
    • 初始化列表
    • 列表初始化
    • 引用初始化
    • 值初始化
    • 零初始化
  • 移动赋值
  • 移动构造函数
  • new


复制消除

< cpp‎ | language

省略复制及移动 (C++11 起)构造函数，导致零复制的按值传递语义。

解释

强制的复制/移动操作消除

以下情况要求编译器省略类对象的复制和移动构造，即使复制/移动构造函数和析构函数拥有可观察的副作用。这些对象将直接构造到它们本来要复制/移动到的存储中。复制/移动构造函数不必存在或可访问：

  • 在 return 语句中，当操作数是一个与函数返回类型相同的类类型的纯右值（忽略 cv 限定）时：
T f() {
    return T();
}

f(); // 仅调用一次 T 的默认构造函数
返回类型的析构函数必须在 return 语句位置可访问且未被删除，即使没有 T 对象要被销毁。
  • 在对象的初始化中，当初始化器表达式是一个与变量类型相同的类类型的纯右值（忽略 cv 限定）时：
T x = T(T(f())); // 仅调用一次 T 的默认构造函数以初始化 x
只能在已知要初始化的对象不是可能重叠的子对象时应用此规则：
struct C { /* ... */ };
C f();
struct D;
D g();
struct D : C {
    D() : C(f()) { }    // 初始化基类子对象时无消除
    D(int) : D(g()) { } // 无消除，因为正在初始化的 D 对象可能是某个其他类的基类子对象
};

注意：上述规则指定的不是优化：针对纯右值和临时量的 C++17 核心语言规定在本质上不同于之前的 C++ 版本：不再有临时量用于复制/移动。描述 C++17 语义的另一种方式是“传递未实质化的值”：返回并使用纯右值时不实质化临时量。

 (C++17 起)

非强制的复制/移动 (C++11 起)操作消除

下列环境下，允许但不要求编译器省略类对象的复制和移动 (C++11 起)构造，即使复制/移动 (C++11 起)构造函数和析构函数拥有可观察的副作用。这些对象将直接构造到它们本来要复制/移动到的存储中。这是一项优化：即使进行了优化而不调用复制/移动 (C++11 起)构造函数，它仍然必须存在且可访问（如同完全未发生优化），否则程序非良构：

  • return 语句中，当操作数是拥有自动存储期的非 volatile 对象的名字，该名字不是函数形参或 catch 子句形参，且其具有与函数返回类型相同的类类型（忽略 cv 限定）时。这种复制消除的变体被称为 NRVO，“具名返回值优化 (named return value optimization)”。
  • 在对象的初始化中，当源对象是无名临时量且与目标对象具有相同类型（忽略 cv 限定）时。当无名临时量为 return 语句的操作数时，称这种复制消除的变体为 RVO，“返回值优化 (return value optimization)”。
 (C++17 前)

返回值优化是强制要求的，而不再被当做复制消除；见上文。

 (C++17 起)
  • throw 表达式中，当操作数是具有自动存储期的非 volatile 对象的名字，其并非函数形参或 catch 子句形参，且其作用域不延伸超过最内层的 try 块（若有 try 块）时。
  • catch 子句中，当实参与抛出的异常对象具有相同类型（忽略 cv 限定）时，省略异常对象的复制，而该 catch 子句体直接访问该异常对象，如同按引用捕获它一样（不可能从异常对象移动，因为它始终是左值）。如果这种复制消除会因为除了跳过该 catch 子句形参的复制构造函数和析构函数之外的任何原因，导致程序的可观察行为发生改变，则它被禁止（例如，当修改了 catch 子句的实参，并以 throw 重新抛出异常对象时）。
 (C++11 起)
  • 在协程中，可以消除将形参向协程状态内的复制/移动，只要除了对形参的构造函数与析构函数的调用被忽略以外，不改变程序的行为即可。这种情形可以在暂停点后始终不使用形参，或者整个协程状态本就始终不在堆上分配时出现。
 (C++20 起)

进行复制消除时，实现将被省略的复制/移动 (C++11 起)操作的源和目标单纯地当做指代同一对象的两种不同方式，而该对象将在假如不进行优化时两个对象中后被销毁的对象销毁时销毁（但如果被选择的构造函数的形参是对象类型的右值引用，那么该销毁发生于目标对象本应被销毁时） (C++17 起)。

可以连锁多次复制消除，以消除多次复制。

  • 在常量表达式和常量初始化中，保证进行返回值优化（RVO），但禁止具名返回值优化（NRVO）：
struct A {
    void *p;
    constexpr A(): p(this) {}
};

constexpr A g()
{
    A a;
    return a;
}

constexpr A a;          // a.p 指向 a
// constexpr A b = g(); // 错误： b.p 会悬垂，并会指向有自动存储期的临时量

void h()
{
    A c = g();          // c.p 可能指向 c 或转瞬即逝的临时量
}

extern const A d;
constexpr A f()
{
    A e;
    if (&e == &d)
        return A();
    else
        return e;
    // 在常量求值中强制 NRVO 会导致矛盾，即当且仅当不执行 NRVO 时执行 NRVO
}
// constexpr A d = f(); // 错误： d.p 悬垂
 (C++11 起)

注解

复制消除是允许改变可观察副作用的唯一得到允许的优化形式 (C++14 前)两种允许的优化形式之一，另一种是分配消除与扩展 (C++14 起)。因为一些编译器并不在所有允许的场合中进行复制消除（例如 debug 模式下），依赖于复制/移动构造函数和析构函数的副作用的程序是不可移植的。

在 return 语句或 throw 表达式中，如果编译器不能进行复制消除，但满足或本应满足复制消除的条件（不含源是函数形参的情况），即使对象由左值代表，编译器也将尝试使用移动构造函数；细节见 return 语句。

 (C++11 起)

示例

#include <iostream>
#include <vector>

struct Noisy {
    Noisy() { std::cout << "在 " << this << " 构造" << '\n'; }
    Noisy(const Noisy&) { std::cout << "复制构造\n"; }
    Noisy(Noisy&&) { std::cout << "移动构造\n"; }
    ~Noisy() { std::cout << "在 " << this << " 析构" << '\n'; }
};

std::vector<Noisy> f() {
    std::vector<Noisy> v = std::vector<Noisy>(3); // 从临时量 (C++17 前)
                                                  // 从纯右值 (C++17 起)
                                                  // 初始化 v 中的复制消除
    return v; // 从 v 到结果对象的 NRVO（C++17 中仍不保证）
}             // 如果禁用优化，则调用移动构造函数

void g(std::vector<Noisy> arg) {
    std::cout << "arg.size() = " << arg.size() << '\n';
}

int main() {
    std::vector<Noisy> v = f(); // 从 f() 返回的临时量 (C++17 前)
                                // 从纯右值 f() (C++17 起)
                                // 初始化 v 中的复制消除
    g(f());                     // 从 f() 返回的临时量 (C++17 前)
                                // 从纯右值 f() (C++17 起)
                                // 初始化 g() 的形参中的复制消除
}

可能的输出：

在 0x2145c20 构造
在 0x2145c21 构造
在 0x2145c22 构造
在 0x2146c50 构造
在 0x2146c51 构造
在 0x2146c52 构造
arg.size() = 3
在 0x2146c50 析构
在 0x2146c51 析构
在 0x2146c52 析构
在 0x2145c20 析构
在 0x2145c21 析构
在 0x2145c22 析构

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 2022 | C++11 | 常量表达式中曾允许不进行复制消除 | 强制复制消除
CWG 2278 | C++11 | 常量表达式中曾强制 NRVO | 在常量表达式中禁止 NRVO
CWG 2426 | C++17 | 返回纯右值时不要求析构函数 | 潜在调用析构函数

参阅

  • 复制初始化
  • 复制构造函数
  • 移动构造函数


复制初始化

< cpp‎ | language

从另一个对象初始化对象。

语法

目标类型 对象 = 其他对象; | (1) |
目标类型 对象 = {其他对象} ; | (2) | (C++11 前)
函数(其他对象) | (3) |
return 其他对象; | (4) |
throw 对象; catch (目标类型 对象) | (5) |
目标类型 数组[元素个数] = {其他对象序列}; | (6) |

解释

复制初始化在下列情况进行：

1) 当声明非引用类型 目标类型 的具名变量（自动、静态或线程局部），带有以等号后随一个表达式所构成的初始化器时。
2) (C++11 前)当声明标量类型 目标类型 的具名变量，带有以等号后随一个花括号环绕的表达式所构成的初始化器时（注意：从 C++11 开始，这被归类为列表初始化，且不允许窄化转换）。
3) 当按值传递参数到函数时
4) 当从具有返回值的函数返回时
5) 当按值抛出或捕获异常时
6) 作为聚合初始化的一部分，以初始化提供了初始化器的每个元素

复制初始化的效果是：

  • 首先，如果 目标类型 是类类型，且初始化器是纯右值表达式，而其无 cv 限定的类型是与 目标类型 相同的类，那么以初始化器表达式自身而非从它所实质化的临时量初始化目标对象：见复制消除
 (C++17 起)
  • 如果 目标类型 是类类型，且 其他对象 的类型的无 cv 限定版本是 目标类型 或是从 目标类型 派生的类，那么检测 目标类型 的非显式构造函数，并由重载决议选择最佳匹配。然后调用构造函数以初始化该对象。
  • 如果 目标类型 是类类型，且 其他对象 的类型的无 cv 限定版本不是 目标类型 或从 目标类型 派生，或如果 目标类型 是非类类型，但 其他对象 的类型是类类型，那么检测能从 其他对象 的类型转换到 目标类型 （或当 目标类型 是类类型且存在转换函数时，转换到从 目标类型 派生的类型）的用户定义转换序列，并通过重载决议选择最佳者。该转换的结果（如果使用转换构造函数，那么就是无cv 限定的 目标类型 的纯右值临时量 (C++17 前)纯右值表达式 (C++17 起)）会被用于直接初始化该对象。最后一步通常会被优化掉，而直接将转换结果构造于分配给目标对象的内存之中，但即便不会使用，也要求适合的构造函数（移动或复制）是可以访问的。 (C++17 前)
  • 否则（如果 目标类型 和 其他对象 的类型都不是类类型），需要时用标准转换将 其他对象 的值转换成 目标类型 的无 cv 限定版本。

注解

复制初始化不如直接初始化宽容：explicit 构造函数不是转换构造函数，也不会被复制初始化考虑。

struct Exp { explicit Exp(const char*) {} }; // 不能从 const char* 转换
Exp e1("abc");  // OK
Exp e2 = "abc"; // 错误，复制初始化不考虑 explicit 构造函数

struct Imp { Imp(const char*) {} }; // 可以从 const char* 转换
Imp i1("abc");  // OK
Imp i2 = "abc"; // OK

另外，复制初始化中的隐式转换必须从初始化器直接生成 目标类型，然而直接初始化会期待一个从初始化器到 目标类型 的构造函数实参的隐式转换。

struct S { S(std::string) {} }; // 可以从 std::string 转换
S s("abc");   // OK：从 const char[4] 转换到 std::string
S s = "abc";  // 错误：没有从 const char[4] 到 S 的转换
S s = "abc"s; // OK：从 std::string 转换到 S

如果 其他对象 是右值表达式，那么重载决议会选择移动构造函数并在复制初始化期间调用它。没有“移动初始化”的概念。

隐式转换以复制初始化的方式定义：如果能以表达式 E 复制初始化 目标类型 类型对象，那么可以隐式转换 E 到 目标类型。

具名变量的复制初始化中的等号 = 与赋值运算符无关。重载的赋值运算符对复制初始化没有影响。

示例

#include <string>
#include <utility>
#include <memory>

struct A
{
    operator int() { return 12; }
};

struct B
{
    B(int) {}
};

int main()
{
    std::string s = "test";        // OK：构造函数非显式
    std::string s2 = std::move(s); // 此复制初始化进行移动

//  std::unique_ptr<int> p = new int(1); // 错误：构造函数是显式的
    std::unique_ptr<int> p(new int(1));  // OK：直接初始化

    int n = 3.14;    // 浮点整型转换
    const int b = n; // 不受 const 影响
    int c = b;       // ……反之亦然

    A a;
    B b0 = 12;
//  B b1 = a;       // < 错误：要求从 'A' 到非标量类型 'B' 的转换
    B b2{a};        // < 等同：调用 A::operator int() ，然后是::B(int)
    B b3 = {a};     // <
    auto b4 = B{a}; // <

//  b0 = a;         // < 错误：需要重载赋值运算符
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 5 | C++98 | 目标类型的 cv 限定会应用到转换构造函数初始化的临时量 | 临时量不再有 cv 限定

参阅

  • 复制消除
  • 转换构造函数
  • 复制赋值
  • 复制构造函数
  • 默认构造函数
  • 析构函数
  • explicit
  • 初始化
    • 聚合初始化
    • 常量初始化
    • 默认初始化
    • 直接初始化
    • 初始化器列表
    • 列表初始化
    • 引用初始化
    • 值初始化
    • 零初始化
  • 移动赋值
  • 移动构造函数
  • new


协程 (C++20)

< cpp‎ | language

协程是能暂停执行以在之后恢复的函数。协程是无栈的：它们通过返回到调用方暂停执行，并且从栈分离存储恢复执行需要的数据。这样就可以编写异步执行的顺序代码（例如不使用显式的回调来处理非阻塞 I/O），还支持对惰性计算的无限序列上的算法及其他用途。

如果函数的定义进行了下列操作之一，那么它是协程：

  • 用 co_await 运算符暂停执行，直到恢复：
task<> tcp_echo_server() {
  char data[1024];
  while (true) {
    std::size_t n = co_await socket.async_read_some(buffer(data));
    co_await async_write(socket, buffer(data, n));
  }
}
  • 用关键词 co_yield 暂停执行并返回一个值：
generator<int> iota(int n = 0) {
  while(true)
    co_yield n++;
}
  • 用关键词 co_return 完成执行并返回一个值：
lazy<int> f() {
  co_return 7;
}

每个协程必须具有能够满足一组要求的返回类型，标注于下。

限制

协程不能使用变长实参，普通的 return 语句，或占位符返回类型（auto 或 Concept）。

constexpr 函数、构造函数、析构函数及 main 函数 不能是协程。

执行

每个协程均与下列对象关联：

  • 承诺（promise）对象，从协程内部操纵。协程通过此对象提交其结果或异常。
  • 协程句柄 (coroutine handle)，从协程外部操纵。这是用于恢复协程执行或销毁协程帧的非拥有柄。
  • 协程状态 (coroutine state)，它是一个包含以下各项的分配于堆（除非优化掉其分配）的内部对象：
  • 承诺对象
  • 各个形参（全部按值复制）
  • 当前暂停点的某种表示，使得恢复时程序知晓要从何处继续，销毁时知晓有哪些局部变量在作用域内
  • 生存期跨过当前暂停点的局部变量和临时量

当协程开始执行时，它进行下列操作：

  • 用 operator new 分配协程状态对象（见下文）
  • 将所有函数形参复制到协程状态中：按值传递的形参被移动或复制，按引用传递的参数保持为引用（因此，如果在被指代对象的生存期结束后恢复协程，它可能变成悬垂引用）
  • 调用承诺对象的构造函数。如果承诺类型拥有接收所有协程形参的构造函数，那么以复制后的协程实参调用该构造函数。否则调用其默认构造函数。
  • 调用 promise.get_return_object() 并将其结果在局部变量中保持。该调用的结果将在协程首次暂停时返回给调用方。至此并包含这个步骤为止，任何抛出的异常均传播回调用方，而非置于承诺中。
  • 调用 promise.initial_suspend() 并 co_await 其结果。典型的承诺类型要么（对于惰性启动的协程）返回 std::suspend_always，要么（对于急切启动的协程）返回 std::suspend_never。
  • 当 co_await promise.initial_suspend() 恢复时，开始协程体的执行。

当协程抵达暂停点时：

  • 将先前获得的返回对象返回给调用方/恢复方，如果需要则先隐式转换到协程的返回类型。

当协程抵达 co_return 语句时，它进行下列操作：

  • 对下列情形调用 promise.return_void()
  • co_return;
  • co_return expr，其中 expr 具有 void 类型
  • 控制流出返回 void 的协程的结尾。此时如果承诺类型 Promise 没有 Promise::return_void() 成员函数，那么则行为未定义。
  • 或对于 co_return expr 调用 promise.return_value(expr)，其中 expr 具有非 void 类型
  • 以创建的逆序销毁所有具有自动存储期的变量。
  • 调用 promise.final_suspend() 并 co_await 其结果。

如果协程因未捕捉的异常结束，那么它进行下列操作：

  • 捕捉异常并在 catch 块内调用 promise.unhandled_exception()
  • 调用 promise.final_suspend() 并 co_await 其结果（例如，以恢复某个继续或发布其结果）。此时开始恢复协程是未定义行为。

当经由 co_return 或未捕捉异常而终止协程导致协程状态被销毁，或经由其句柄而导致其被销毁时，它进行下列操作：

  • 调用承诺对象的析构函数。
  • 调用各个函数形参副本的析构函数。
  • 调用 operator delete 以释放协程状态所用的内存。
  • 转移执行回到调用方/恢复方。

堆分配

协程状态由非数组 operator new 在堆上分配。

如果承诺类型定义了类级别的替代函数，那么会使用它，否则会使用全局的 operator new。

如果承诺类型定义了接收额外形参的 operator new 的布置形式，且它们所匹配的实参列表中的第一实参是要求的大小（std::size_t 类型），而其余则是各个协程函数实参，那么将这些实参传递给 operator new（这使得能对协程使用前导分配器约定）

以下情况下，可以优化掉对 operator new 的调用（即使使用了自定义分配器）：

  • 协程状态的生存期严格内嵌于调用方的生存期，且
  • 协程帧的大小在调用点已知

此时协程状态嵌入调用方的栈帧（如果调用方是普通函数）或协程状态（如果调用方是协程）之中。

如果分配失败，那么协程抛出 std::bad_alloc，除非承诺类型 Promise 类型定义了成员函数 Promise::get_return_object_on_allocation_failure()。如果定义了该成员函数，那么使用 operator new 的 nothrow 形式进行分配，而在分配失败时，协程会立即将从 Promise::get_return_object_on_allocation_failure() 获得的对象返回给调用方。

承诺类型（Promise）

编译器用 std::coroutine_traits 从协程的返回类型确定承诺类型。

正式而言，令 R 与 Args... 分别代表协程的返回类型与参数类型列表，ClassT 与 /*cv限定*/ （如果存在）分别代表协程所属的类与其 cv 限定，如果定义它为非静态成员函数，以如下方式确定它的承诺类型 ：

  • std::coroutine_traits<R, Args...>::promise_type，如果不定义协程为非静态成员函数，
  • std::coroutine_traits<R, ClassT /*cv限定*/&, Args...>::promise_type，如果定义协程为非右值引用限定的非静态成员函数，
  • std::coroutine_traits<R, ClassT /*cv限定*/&&, Args...>::promise_type，如果定义协程为右值引用限定的非静态成员函数。

例如：

  • 如果定义协程为 task<float> foo( std::string x, bool flag);，那么它的承诺类型是 std::coroutine_traits<task<float>, std::string, bool>::promise_type。
  • 如果定义协程为 task<void> my_class::method1(int x) const;，那么它的承诺类型是 std::coroutine_traits<task<void>, const my_class&, int>::promise_type。
  • 如果定义协程为 task<void> my_class::method1(int x) &&;，那么它的承诺类型是 std::coroutine_traits<task<void>, my_class&&, int>::promise_type。

co_await

一元运算符 co_await 暂停协程并将控制返回给调用方。它的操作数是一个表达式，其类型必须要么定义 operator co_await，要么能以当前协程的 Promise::await_transform 转换到这种类型。

co_await 表达式

首先，以下列方式将 表达式 转换成可等待体（awaitable）：

  • 如果 表达式 由初始暂停点、最终暂停点或 yield 表达式所产生，那么可等待体是 表达式 本身。
  • 否则，如果当前协程的承诺类型拥有成员函数 await_transform，那么可等待体是 promise.await_transform(表达式)。
  • 否则，可等待体是 表达式 本身。

然后以下列方式获得等待器（awaiter）对象：

  • 如果针对 operator co_await 的重载决议给出单个最佳重载，那么等待器是该调用的结果（对于成员重载为 awaitable.operator co_await();，对于非成员重载为 operator co_await(static_cast<Awaitable&&>(awaitable));）
  • 否则，如果重载决议找不到 operator co_await，那么等待器是可等待体本身
  • 否则，如果重载决议有歧义，那么程序非良构

如果上述表达式为纯右值，那么等待器对象是从它实质化的临时量。否则，如果上述表达式为泛左值，那么等待器对象是它所指代的对象。

然后，调用 awaiter.await_ready()（这是当已知结果就绪或可以同步完成时，用以避免暂停开销的快捷方式）。如果它的结果按语境转换成 bool 为 false，那么：

暂停协程（以各局部变量和当前暂停点填充其协程状态）。
调用 awaiter.await_suspend(handle)，其中 handle 是表示当前协程的协程句柄。这个函数内部可以通过这个句柄观察暂停的协程，而且此函数负责调度它以在某个执行器上恢复，或将其销毁（并返回 false 当做调度）
  • 如果 await_suspend 返回 void，那么立即将控制返回给当前协程的调用方/恢复方（此协程保持暂停），否则
  • 如果 await_suspend 返回 bool，那么：
  • 值为 true 时将控制返回给当前协程的调用方/恢复方
  • 值为 false 时恢复当前协程。
  • 如果 await_suspend 返回某个其他协程的协程句柄，那么（通过调用 handle.resume()）恢复该句柄（注意这可以连锁进行，并最终导致当前协程恢复）
  • 如果 await_suspend 抛出异常，那么捕捉该异常，恢复协程，并立即重抛异常
最后，调用 awaiter.await_resume()，它的结果就是整个 co_await expr 表达式的结果。

如果协程在 co_await 表达式中暂停而在后来恢复，那么恢复点处于紧接对 awaiter.await_resume() 的调用之前。

注意，因为协程在进入 awaiter.await_suspend() 前已经完全暂停，所以该函数可以自由地在线程间转移协程柄而无需额外同步。例如，可以将它放入回调，将它调度成在异步 I/O 操作完成时在线程池上运行等。此时因为当前协程可能已被恢复，从而执行了等待器的析构函数，同时由于 await_suspend() 在当前线程上持续执行， await_suspend() 应该把 *this 当作已被销毁并且在柄被发布到其他线程后不再访问它。

示例

#include <coroutine>
#include <iostream>
#include <stdexcept>
#include <thread>

auto switch_to_new_thread(std::jthread& out) {
  struct awaitable {
    std::jthread* p_out;
    bool await_ready() { return false; }
    void await_suspend(std::coroutine_handle<> h) {
      std::jthread& out = *p_out;
      if (out.joinable())
        throw std::runtime_error("jthread 输出参数非空");
      out = std::jthread([h] { h.resume(); });
      // 潜在的未定义行为：访问潜在被销毁的 *this
      // std::cout << "新线程 ID：" << p_out->get_id() << "\n";
      std::cout << "新线程 ID：" << out.get_id() << "\n"; // 这样可以
    }
    void await_resume() {}
  };
  return awaitable{&out};
}

struct task {
    struct promise_type {
        task get_return_object() { return {}; }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void return_void() {}
        void unhandled_exception() {}
    };
};

task resuming_on_new_thread(std::jthread& out) {
  std::cout << "协程开始，线程 ID：" << std::this_thread::get_id() << "\n";
  co_await switch_to_new_thread(out);
  // 等待器在此销毁
  std::cout << "协程恢复，线程 ID：" << std::this_thread::get_id() << "\n";
}

int main() {
  std::jthread out;
  resuming_on_new_thread(out);
}

可能的输出：

协程开始，线程 ID：139972277602112
新线程 ID：139972267284224
协程恢复，线程 ID：139972267284224

注意：等待器对象是协程状态的一部分（作为生存期跨过暂停点的临时量），并且在 co_await 表达式结束前销毁。可以用它维护某些异步 I/O API 所要求的每操作内状态，而无需用到额外的堆分配。

标准库定义了两个平凡的可等待体：std::suspend_always 及 std::suspend_never。

本节未完成
原因：示例

co_yield

yield 表达式向调用方返回一个值并暂停当前协程：它是可恢复生成器函数的常用构建块

co_yield 表达式
co_yield 花括号初始化器列表

它等价于

co_await promise.yield_value(表达式)

典型的生成器的 yield_value 会将其实参存储（复制/移动或仅存储其地址，因为实参的生存期跨过 co_await 内的暂停点）到生成器对象中并返回 std::suspend_always，将控制转移给调用方/恢复方。

本节未完成
原因：示例

库支持

协程支持库定义数个类型，提供协程的编译与运行时支持。


cv（const 与 volatile）类型限定符

< cpp‎ | language

可出现于任何类型说明符（包括声明文法的 声明说明符序列）中，以指定被声明对象或被命名类型的常量性（constness）或易变性（volatility）。

  • const ——定义类型为常量。
  • volatile ——定义类型为易变。

解释

对于除了函数类型或引用类型以外的任何类型 T（包括不完整类型），C++ 类型系统中有另外三个独立的类型：const-限定的 T、volatile-限定的 T 及 const-volatile-限定的 T。

注意：数组类型被当做与其元素类型有相同的 cv 限定。

当对象最初被创建时，所用的 cv 限定符（可以是声明中的 声明说明符序列 或 声明符 的一部分，或者是 new 表达式中的 类型标识 的一部分）决定对象的常量性或易变性，如下所示：

  • const 对象——类型为 const-限定的 对象，或 const 对象的非 mutable 子对象。这种对象不能被修改：直接尝试这么做是编译时错误，而间接尝试这么做（例如通过到非 const 类型的引用或指针修改 const 对象）会导致未定义行为。
  • volatile 对象——类型为 volatile-限定的 对象，或 volatile 对象的子对象，或 const volatile 对象的 mutable 子对象。通过 volatile 限定的类型的泛左值表达式的每次访问（读或写操作、成员函数调用等），都被当作对于优化而言是可见的副作用（即在单个执行线程内，volatile 访问不能被优化掉，或者与另一按顺序早于或按顺序晚于该 volatile 访问的可见副作用进行重排序。这使得 volatile 对象适用于与信号处理函数之间的交流，但不适于与另一执行线程交流，参阅 std::memory_order）。试图通过非 volatile 类型的泛左值涉指 volatile 对象（例如，通过到非 volatile 类型的引用或指针）会导致未定义行为。
  • const volatile 对象——类型为 const-volatile-限定的 对象，const volatile 对象的非 mutable 子对象，volatile 对象的 const 子对象，或 const 对象的非 mutable volatile 子对象。同时表现为 const 对象与 volatile 对象。

mutable 说明符

  • mutable - 容许在即便包含它的对象被声明为 const 时仍可修改声明为 mutable 的类成员。

可出现于非引用非 const 类型的非静态数据成员的声明中：

class X {
  mutable const int* p;         // OK
  mutable int* const q;         // 非良构
};

mutable 用于指定不影响类的外部可观察状态的成员（通常用于互斥体、记忆缓存、惰性求值和访问指令等）。

class ThreadsafeCounter {
  mutable std::mutex m; // “M&M 规则”：mutable 与 mutex 一起出现
  int data = 0;
 public:
  int get() const {
    std::lock_guard<std::mutex> lk(m);
    return data;
  }
  void inc() {
    std::lock_guard<std::mutex> lk(m);
    ++data;
  }
};

转换

存在一种基于限制性的增长顺序的 cv 限定符的偏序。从而可以称类型具有更多或更少的 cv 限定：

  • 无限定 < const
  • 无限定 < volatile
  • 无限定 < const volatile
  • const < const volatile
  • volatile < const volatile

到 cv 限定类型的引用和指针能被隐式转换到更多 cv 限定的类型的引用和指针。特别是允许下列转换：

  • 到无限定类型的引用/指针能被转换成到 const 的引用/指针
  • 到无限定类型的引用/指针能被转换成到 volatile 的引用/指针
  • 到无限定类型的引用/指针能被转换成到 const volatile 的引用/指针
  • 到 const 类型的引用/指针能被转换成到 const volatile 的引用/指针
  • 到 volatile 类型的引用/指针能被转换成到 const volatile 的引用/指针
注意：多级指针另有其他限制。

想要将到 cv 限定类型的引用或指针转换为到更少 cv 限定类型的引用或指针就必须使用 const_cast。

关键词

const, volatile, mutable

注解

在未声明为 extern 的非局部非 volatile 非模板 (C++14 起)非 inline (C++17 起)变量声明上使用 const 限定符，会给予该变量内部连接。这有别于 C，其中 const 文件作用域对象拥有外部连接。

C++ 语言文法把 mutable 当做存储类说明符而非类型限定符，但它不影响存储类或连接。

volatile 的一些用法被弃用：

  • volatile 类型的左值作为内建自增/自减运算符的操作数；
  • volatile 类型的左值作为内建直接/复合赋值运算符的左操作数，除非该直接赋值表达式出现于不求值语境或是弃值表达式；
  • volatile 对象类型作为函数参数类型或返回类型；
  • volatile 限定符在结构化绑定声明中。
 (C++20 起)

示例

int main()
{
    int n1 = 0;           // 非 const 对象
    const int n2 = 0;     // const 对象
    int const n3 = 0;     // const 对象（同 n2）
    volatile int n4 = 0;  // volatile 对象
    const struct
    {
        int n1;
        mutable int n2;
    } x = {0, 0};      // 带 mutable 成员的 const 对象

    n1 = 1; // OK，可修改对象
//  n2 = 2; // 错误：不可修改对象
    n4 = 3; // OK，当做副作用
//  x.n1 = 4; // 错误：const 对象的成员为 const
    x.n2 = 4; // OK，const 对象的 mutable 成员不是 const

    const int& r1 = n1; // 绑定到非 const 对象的 const 引用
//  r1 = 2; // 错误：试图通过到 const 的引用修改
    const_cast<int&>(r1) = 2; // OK，修改非 const 对象 n1

    const int& r2 = n2; // 绑定到 const 对象的 const 引用
//  r2 = 2; // 错误：试图通过到 const 的引用修改
//  const_cast<int&>(r2) = 2; // 未定义行为：试图修改 const 对象 n2
}

输出：

# x86_64 平台上生成的典型机器码
# （只输出贡献可观测副效应的代码）
main:
    movl    $0, -4(%rsp) # volatile int n4 = 0;
    movl    $3, -4(%rsp) # n4 = 3;
    xorl    %eax, %eax   # return 0 （隐式）
    ret

参阅


非静态数据成员

< cpp‎ | language

非静态数据成员是在类的成员说明中声明的。

class S
{
    int n;              // 非静态数据成员
    int& r;             // 引用类型的非静态数据成员
    int a[2] = {1, 2};  // 带默认成员初始化器的非静态数据成员（C++11）
    std::string s, *ps; // 两个非静态数据成员
    struct NestedS
    {
        std::string s;
    } d5;               // 具有嵌套类型的非静态数据成员
    char bit : 2;       // 2 位的位域
};

允许任意简单声明，但

  • 不允许使用 extern 和 register 存储类说明符；
  • 不允许使用 thread_local 存储类说明符（但静态数据成员可以使用）；
 (C++11 起)
  • 不允许不完整类型、抽象类类型及其数组：通常，类 C 不能拥有 C 类型的非静态数据成员，尽管它能拥有 C&（C 的引用）或 C*（C 的指针）类型的非静态数据成员；
  • 当存在至少一个用户定义的构造函数时，非静态数据成员不能拥有与类名相同的名字；
  • auto 说明符不能用于非静态数据成员的声明（尽管在类定义中初始化的静态数据成员可以使用）。
 (C++11 起)

另外，允许位域声明。

布局

当创建某个类 C 的对象时，每个非引用类型的非静态数据成员都在 C 的对象表示的某个部分中分配。引用是否占据存储是由实现定义的，但它们的存储期与以它们作为成员的对象相同。

对于非联合体类类型，非零大小的 (C++20 起)未被访问说明符分隔 (C++11 前)拥有相同成员访问 (C++11 起)的成员，始终按照较后声明的成员在类对象中拥有较高地址的方式分配。被访问说明符分隔 (C++11 前)拥有不同访问控制 (C++11 起)的成员以未指明的顺序分配（编译器可以将它们组合在一起）。 | (C++23 前)
对于非联合体类类型，非零大小的成员始终按照较后声明的成员在类对象中拥有较高地址的方式分配。注意成员的访问控制仍然影响标准布局属性（见后述）。 | (C++23 起)

对齐要求可能需要在成员间，或在类的最后成员之后进行填充。

标准布局

一个类只有在它是简旧数据类型 (PODType) 的情况下是标准布局（standard-layout）的并拥有下述属性。 | (C++11 前)
所有非静态数据成员均拥有相同访问控制，且满足其他特定条件的类被称作标准布局（standard-layout）类型（对其规定的列表见标准布局类型 (StandardLayoutType) ）。 | (C++11 起)

两个标准布局非联合类类型可以拥有非静态数据成员和位域的共同起始序列，它是一个或多个起始成员（按声明顺序）的序列，条件是这些成员拥有布局兼容的类型，均声明有 [[no_unique_address]] 属性或无该属性 (C++20 起)，且当它们是位域时拥有相同宽度。

struct A { int a; char b; };
struct B { const int b1; volatile char b2; };
// A 与 B 的共同起始序列是 A.a, A.b 与 B.b1, B.b2
struct C { int c; unsigned : 0; char b; };
// A 与 C 的共同起始序列是 A.a 与 C.c
struct D { int d; char b : 4; };
// A 与 D 的共同起始序列是 A.a 与 D.d
struct E { unsigned int e; char b; };
// A 与 E 的共同起始序列为空

如果两个标准布局非联合类类型具有同一类型（如果存在 cv 限定符则忽略），或是布局兼容的枚举（即拥有相同底层类型的枚举类型），或它们的'共同起始序列由它们所有的非静态数据成员和位域组成，那么称它们布局兼容（layout compatible）（上例中，A 与 B 布局兼容）

如果两个标准布局联合体类型拥有相同数量的非静态数据成员，且（以任何顺序）对应的非静态数据成员拥有布局兼容的类型，那么称它们布局兼容。

标准布局类型拥有以下特殊性质：

  • 在以非联合类类型 T1 作为活跃成员的标准布局联合体中，容许读取具有非联合类类型 T2 的另一联合体成员的非静态数据成员 m，只要 m 是 T1 与 T2 的共同起始序列的一部分（但通过非 volatile 泛左值读取 volatile 成员是未定义的）。
  • 指向标准布局类类型的指针可以被 reinterpret_cast 成指向其首个非静态非位域数据成员的指针（如果它拥有非静态数据成员），或指向其任何基类子对象的指针（如果有基类） (C++11 起)，反之亦然。换言之，不允许标准布局类型的首个数据成员前有填充。注意严格别名化规则仍然适用于这种转型的结果。
  • 宏 offsetof 可以用于确定任何成员距标准布局类起始的偏移量。

成员初始化

非静态数据成员可以用下列两种方式之一初始化：

1) 在构造函数的成员初始化器列表中。
struct S
{
    int n;
    std::string s;
    S() : n(7) {} // 直接初始化 n，默认初始化 s
};
2) 通过默认成员初始化器，它是成员声明中包含的花括号或等号初始化器，并在成员初始化器列表中忽略该成员的情况下得到使用。
struct S
{
    int n = 7;
    std::string s{'a', 'b', 'c'};
    S() {} // 默认成员初始化器将复制初始化 n，列表初始化 s
};

如果成员拥有默认成员初始化器，并且在构造函数的成员初始化器列表中也有出现，那么对该构造函数忽略默认成员初始化器。

#include <iostream>

int x = 0;
struct S
{
    int n = ++x;
    S() {}                 // 使用默认成员初始化器
    S(int arg) : n(arg) {} // 使用成员初始化器
};

int main()
{
    std::cout << x << '\n'; // 打印 0
    S s1;
    std::cout << x << '\n'; // 打印 1（运行默认初始化器）
    S s2(7);
    std::cout << x << '\n'; // 打印 1（未运行默认初始化器）
}

输出：

0
1
1

不能对位域成员使用默认成员初始化器。

 (C++20 前)

数组类型成员不能从成员初始化器推导其大小：

struct X
{
   int a[] = {1, 2, 3};  // 错误
   int b[3] = {1, 2, 3}; // OK
};

默认成员初始化器不允许导致外围类的预置默认构造函数的隐式定义，或该构造函数的异常说明:

struct node
{
    node* p = new node; // 错误：使用隐式或预置的 node::node()
};

在默认成员初始化器中，引用成员不能绑定到临时量（注意，成员初始化器列表有同样的规则）

struct A
{
    A() = default;     // OK
    A(int v) : v(v) {} // OK
    const int& v = 42; // OK
};

A a1;    // 错误：临时量到引用的非良构绑定
A a2(1); // OK（忽略默认成员初始化器，因为 v 在构造函数中出现）
         // 然而 a2.v 是悬垂引用
 (C++11 起)

如果默认成员初始化器拥有会执行聚合初始化并会使用同一初始化器的子表达式，那么产生错误：

struct A;
extern A a;

struct A
{
    const A& a1{A{a, a}}; // OK
    const A& a2{A{}};     // 错误
};

A a{a, a};                        // OK
 (C++14 起)

用法

非静态数据成员或非静态成员函数的名字只能出现在下列三种情形中：

1) 作为类成员访问表达式的一部分，其中的类要么拥有此成员，要么从拥有此成员的类派生，这包括在任何允许 this 的语境（成员函数体内，成员初始化器列表内，类内默认成员初始化器内）中使用非静态成员的名字时所出现的隐式 this-> 成员访问表达式。
struct S
{
    int m;
    int n;
    int x = m;            // OK：在默认初始化器中允许隐式的 this-> (C++11)
    S(int i) : m(i), n(m) // OK：在成员初始化器列表中允许隐式的 this->
    {
        this->f();        // 显式的成员访问表达式
        f();              // 在成员函数体内允许隐式的 this->
    }
    void f();
};
2) 构成指向非静态成员的指针。
struct S
{
   int m;
   void f();
};

int S::*p = &S::m;       // OK：m 用于构成成员指针
void (S::*fp)() = &S::f; // OK：f 用于构成成员指针
3) （仅对数据成员，而非成员函数）当在不求值操作数中使用时。
struct S
{
   int m;
   static const std::size_t sz = sizeof m; // OK：不求值操作数中的 m
};

std::size_t j = sizeof(S::m + 42); // OK：即便没有 m 的 "this" 对象
注：这种用法是经由 N2253 中 CWG 问题 613 的解决方案允许的，某些编译器（例如 clang）认为它是 C++11 中的改动。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 80 | C++98 | 所有数据成员的名字不能与类名相同（与 C 不兼容） | 非静态数据成员的名字在没有用户 声明的构造函数时可以与类名相同
CWG 613 | C++98 | 不允许非静态数据成员的不求值使用 | 允许这种使用
CWG 1397 | C++11 | 在默认成员初始化器中类被视为完整的 | 默认成员初始化不能触发默认构造函数的定义
CWG 1696 | C++98 | 引用成员能初始化为临时量（其生存期会在构造函数结束时结束） | 这种初始化非良构
CWG 1719 | C++98 | cv 限定不同的类型曾经不是布局兼容的 | 忽略 cv 限定，改进规范
CWG 2254 | C++11 | 指向无数据成员的标准布局类的指针能 reinterpret_cast 到其首个基类 | 能 reinterpret_cast 到其任意基类

参阅

类
静态成员
非静态成员函数
is_standard_layout (C++11) | 检查是否是一个标准布局类型 (类模板)
offsetof | 从标准布局类型的起始到其指定成员的字节偏移量 (宏函数)


声明

< cpp‎ | language

声明将名字引入（或再引入）到 C++ 程序中。每种实体的声明方式都不同。定义是足以使该名字所标识的实体被使用的声明。

声明是下列之一：

  • 函数定义
  • 模板声明（包括部分模板特化）
  • 显式模板实例化
  • 显式模板特化
  • 命名空间定义
  • 链接说明
  • 属性声明（属性 ;）(C++11 起)
  • 空声明（;）(C++11 起)
  • 无 声明说明符序列 的函数声明：
属性(可选) 声明符 ;
属性 | - | (C++11 起) 任意数量属性的序列
声明符 | - | 函数声明符。
此声明必须声明构造函数、析构函数或用户定义的类型转换函数。它只能用作模板声明、显式特化或显式实例化的一部分。
  • 块声明（能在块中出现的声明），它可以是下列之一：
  • 汇编声明
  • 类型别名声明 (C++11 起)
  • 命名空间别名定义
  • using 声明
  • using 指令
  • using enum 声明 (C++20 起)
  • static_assert 声明 (C++11 起)
  • 不可见 enum 声明 (C++11 起)
  • 简单声明

简单声明

简单声明是引入、创建并可选地初始化一个或数个标识符（典型地为变量）的语句。

声明说明符序列 初始化声明符列表(可选) ; | (1)
属性 声明说明符序列 初始化声明符列表; | (2)
属性 | - | (C++11 起) 任何数量属性的序列
声明说明符序列 （decl-specifier-seq） | - | 说明符（specifier）的序列（见下文）
初始化声明符列表 （init-declarator-list） | - | 带可选的初始化器（initializer）的声明符（declarator）的逗号分隔列表。 初始化声明符列表 在声明具名的 class/struct/union 或具名枚举时是可选的

结构化绑定声明也是简单声明。 (C++17 起)

说明符

声明说明符（声明说明符序列）是下列以空白分隔的说明符的序列，顺序不限：

  • typedef 说明符。如果存在，则整个声明是 typedef 声明，且每个声明符引入一个新的类型名，而非对象或函数。
  • 函数说明符（inline、virtual、explicit），仅在函数声明中可以使用。
  • inline 说明符也可以用于变量声明。
 (C++17 起)
  • friend 说明符，可以在类和函数声明中使用。
  • constexpr 说明符，只允许在变量定义，函数及函数模板声明，以及具有字面类型的静态数据成员的声明中使用。
 (C++11 起)
  • consteval 说明符，只允许在函数和函数模板声明中使用。
  • constinit 说明符，只允许在拥有静态或线程存储期的变量声明中使用。constexpr 、 consteval 和 constinit 说明符在一个 声明说明符序列 中最多只能出现一个。
 (C++20 起)
  • 存储类说明符（register、 (C++17 前) static 、thread_local (C++11 起)、extern、mutable）。只能使用一个存储类说明符，但 thread_local 可以与 extern 或 static 一同出现。
  • 类型说明符（类型说明符序列），指名一个类型的说明符的序列。声明所引入的每个实体均为此类型，并可以被声明符修饰（见下文）。这个说明符序列也用于类型标识（type-id）。只有下列说明符是 类型说明符序列 的一部分，顺序不限：
  • 类说明符
  • 枚举说明符
  • 简单类型说明符
  • char 、char8_t (C++20 起)、char16_t、char32_t (C++11 起)、wchar_t、bool、short、int、long、signed、unsigned、float、double、void
  • auto
  • decltype 说明符
 (C++11 起)
  • 先前声明过的类名（可限定）
  • 先前声明过的枚举名（可限定）
  • 先前声明过的 typedef 名 或类型别名 (C++11 起)（可限定）
  • 带模板实参的模板名（可限定，可使用 template 消歧义符）
  • 无模板实参的模板名（可限定）：参阅类模板实参推导
 (C++17 起)
  • 详述类型说明符
  • 关键词 class、struct 或 union，后随先前已定义为 class、struct 或 union 名的标识符（可限定）。
  • 关键词 class、struct 或 union，后随带模板实参的、先前已定义为类模板名字的模板名（可限定，可使用 template 消歧义符）。
  • 关键词 enum 后随先前已定义为枚举名的标识符（可限定）。
  • typename 说明符
  • cv 限定符
每个 声明说明符序列 中只允许一个类型说明符，但有以下例外：
- const 能与自身外的任何类型说明符组合。
- volatile 能与自身外的任何类型说明符组合。
- signed 或 unsigned 能与 char、long、short 或 int 组合。
- short 或 long 能与 int 组合。
- long 能与 double 组合。
- long 能与 long 组合。
 (C++11 起)

属性可以在 声明说明符序列 中出现，此时它们应用于其之前的说明符所确定的类型。

声明说明符序列 中仅有的允许两次出现的说明符是 long（可出现两次）。所有其他重复，例如 const static const 或 virtual inline virtual 均错。

 (C++17 起)

声明符

初始化声明符列表 是一或多个 初始化声明符 的逗号分隔列表，它拥有下列语法：

声明符 初始化器(可选) | (1) |
声明符 requires-子句 | (2) | (C++20 起)
声明符 | - | 声明符
初始化器 | - | 可选的初始化器（除非在必要的场合，例如初始化引用或 const 对象时）。细节见初始化。
requires-子句 | - | requires 子句，向函数声明添加制约

初始化声明符序列 S D1, D2, D3; 中的每个 初始化声明符，均按照如同它是拥有相同说明符的孤立声明来处理：S D1; S D2; S D3;。

每个声明符恰好引入一个对象、引用、函数或（对于 typedef 声明）类型别名，其类型由 声明说明符序列 提供，并可选地被声明符中的运算符，如 &（～的引用）或 []（～的数组）或 ()（返回～的函数）所修饰。可以递归应用这些声明符，如下所示。

声明符 是下列之一：

无限定标识 属性(可选) | (1) |
有限定标识 属性(可选) | (2) |
... 标识符 属性(可选) | (3) | (C++11 起)
* 属性(可选) 限定符(可选) 声明符 | (4) |
嵌套名说明符 * 属性(可选) 限定符(可选) 声明符 | (5) |
& 属性(可选) 声明符 | (6) |
&& 属性(可选) 声明符 | (7) | (C++11 起)
非指针声明符 [ 常量表达式(可选) ] 属性(可选) | (8) |
非指针声明符 ( 形参列表 ) cv限定符(可选) 引用限定符(可选) 异常说明(可选) 属性(可选) | (9) |
1) 所声明的名称。
2) 使用有限定的标识符（有限定标识）定义或重声明先前声明的命名空间成员或类成员的声明符。
3) 形参包，只会在形参声明中出现。
4) 指针声明符：声明 S * D; 将 D 声明为指向 声明说明符序列 所确定的类型 S 的指针。
5) 成员指针声明：声明 S C::* D; 将 D 声明为指向 C 中的类型是 声明说明符序列 所确定的类型 S 的成员的指针。嵌套名说明符 是名字和作用域解析运算符 :: 的序列
6) 左值引用声明符：声明 S & D; 将 D 声明为到 声明说明符序列 所确定的类型 S 的左值引用。
7) 右值引用声明符：声明 S && D; 将 D 声明为到 声明说明符序列 所确定的类型 S 的右值引用。
8) 数组声明符。非指针声明符 为任何合法声明符，但如果它以 *、& 或 && 起始，则必须用括号环绕它。
9) 函数声明符。非指针声明符 为任何合法声明符，但如果它以 *、& 或 && 起始，则必须用括号环绕它。注意最外层函数声明符可以可选的尾随返回类型结尾。 (C++11 起)

所有情况下，属性 均为可选的属性的序列。当其紧跟标识符之后出现时，它应用于所声明的对象。

 (C++11 起)

限定符 是 const 与 volatile 限定符的序列，其中任一限定符在序列中至多出现一次。

本节未完成
原因：解释名字隐藏规则；变量/函数声明如何隐藏同名的类（而非 typedef）

注解

块声明出现在代码块内，而当声明中引入的标识符之前已在某个外层代码块中声明时，该代码块的剩余部分中外层声明被隐藏。

如果一个声明引入了一个具有自动存储期的变量，则它在执行其声明语句时被初始化。退出代码块时，所有在该块中声明的自动变量被以其初始化顺序的相反顺序销毁（与如何退出代码块无关：通过异常、goto 或抵达其结尾）。

示例

class C {
    std::string member; // 声明说明符序列 是 "std::string"
                        // 声明符 是 "member"
} obj, *pObj(&obj);
// 声明说明符序列为 "class C { std::string member; }"
// 声明符 "obj" 定义 C 类型的对象
// 声明符 "*pObj(&obj)" 声明并初始化指向 C 的指针

int a = 1, *p = nullptr, f(), (*pf)(double);
// 声明说明符序列为 int
// 声明符 a=1 定义并初始化 int 类型的变量
// 声明符 *p=nullptr 定义并初始化 int* 类型的变量
// 声明符 (f)() 声明（但不定义）不接收参数并返回 int 的函数
// 声明符 (*pf)(double) 定义一个指向接收 double 并返回 int 的函数的指针

int (*(*foo)(double))[3] = nullptr;
// 声明说明符序列为 int
// 1. 声明符 "(*(*foo)(double))[3]" 是数组声明符；
//    所声明类型是“含有 3 个 int 元素的数组 /嵌套声明符/ ”
// 2. 嵌套声明符是 "(*(*foo)(double))"，它是指针声明符
//    所声明类型是“指向【含有 3 个 int 元素的数组】的指针 /嵌套声明符/”
// 3. 嵌套声明符是 "(*foo)(double)"，它是函数声明符
//    所声明类型是“以【指向含有 3 个 int 元素的数组的指针】
//    为返回值的接受一个 double 参数的函数 /嵌套声明符/”
// 4. 嵌套声明符是 "(*foo)"，它是（带括号，如函数声明符语法所要求的）指针声明符。
//    所声明类型是“指向【以指向含有 3 个 int 元素的数组的指针
//    为返回值的接受一个 double 参数的函数】的指针 /嵌套声明符/”
// 5. 嵌套声明符是 "foo"，它是标识符。
//    该声明声明了对象 foo，它的类型是“指向以指向含有 3 个 int 元素的数组的指针
//    为返回值的接受一个 double 参数的函数的指针”
// 初始化器 "= nullptr" 提供此指针的初值。

参阅


decltype 说明符

< cpp‎ | language

检查实体的声明类型，或表达式的类型和值类别。

语法

decltype ( 实体 ) | (1) | (C++11 起)
decltype ( 表达式 ) | (2) | (C++11 起)

解释

1) 如果实参是没有括号的标识表达式或没有括号的类成员访问表达式，那么 decltype 产生以该表达式命名的实体的类型。如果没有这种实体或该实参指名了一组重载函数，那么程序非良构。
如果实参是指名某个结构化绑定的没有括号的标识表达式，那么 decltype 产生其被引用类型（在关于结构化绑定声明的说明中有所描述）。 | (C++17 起)
如果实参是指名某个非类型模板形参的没有括号的标识表达式，那么 decltype 生成该模板形参的类型（当该模板形参以占位符类型声明时，类型会先进行任何所需的类型推导）。 | (C++20 起)
2) 如果实参是其他类型为 T 的任何表达式，且
a) 如果 表达式 的值类别是亡值，将会 decltype 产生 T&&；
b) 如果 表达式 的值类别是左值，将会 decltype 产生 T&；
c) 如果 表达式 的值类别是纯右值，将会 decltype 产生 T。
如果 表达式 是返回类类型纯右值的函数调用，或是右操作数为这种函数调用的逗号表达式，那么不会对该纯右值引入临时量。 | (C++17 前)
如果 表达式 是除了（可带括号的）立即调用以外的 (C++20 起)纯右值，那么不会从该纯右值实质化临时对象：即这种纯右值没有结果对象。 | (C++17 起)
该类型不需要是完整类型或拥有可用的析构函数，而且类型可以是抽象的。此规则不适用于其子表达式：decltype(f(g())) 中，g() 必须有完整类型，但 f() 不必。

注意如果对象的名字带有括号，那么它会被当做通常的左值表达式，从而 decltype(x) 和 decltype((x)) 通常是不同的类型。

在难以或不可能以标准写法进行声明的类型时，decltype 很有用，例如 lambda 相关类型或依赖于模板形参的类型。

关键词

decltype

示例

#include <iostream>
#include <type_traits>

struct A { double x; };
const A* a;

decltype(a->x) y;       // y 的类型是 double（其声明类型）
decltype((a->x)) z = y; // z 的类型是 const double&（左值表达式）

template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) // 返回类型依赖于模板形参
{                                     // C++14 开始可以推导返回类型
    return t+u;
}

int main()
{
    int i = 33;
    decltype(i) j = i * 2;

    std::cout << "i = " << i << ", "
              << "j = " << j << '\n';

    std::cout << "i 和 j 的类型相同吗？"
              << (std::is_same_v<decltype(i), decltype(j)> ? "相同" : "不同") << '\n';

    auto f = [](int a, int b) -> int
    {
        return a * b;
    };

    decltype(f) g = f; // lambda 的类型是独有且无名的
    i = f(2, 2);
    j = g(3, 3);

    std::cout << "i = " << i << ", "
              << "j = " << j << '\n';
}

输出：

i 和 j 的类型相同吗？相同
i = 33, j = 66
i = 4, j = 9

参阅

auto 说明符 (C++11) | 指定从表达式推导的类型
declval (C++11) | 获取到其实参的引用，用于不求值语境中 (函数模板)


默认实参

< cpp‎ | language

允许调用函数时不提供一个或多个尾部的实参。

通过为函数声明的 形参列表 中的形参使用下列语法来指定默认实参。

属性(可选) 声明说明符序列 声明符 = 初始化器 | (1)
属性(可选) 声明说明符序列 抽象声明符(可选) = 初始化器 | (2)

默认实参用于取代函数调用中缺失的尾部实参：

void point(int x = 3, int y = 4);

point(1,2); // 调用 point(1,2)
point(1);   // 调用 point(1,4)
point();    // 调用 point(3,4)

在函数声明中，所有在拥有默认实参的形参之后的形参必须：

  • 拥有在这个或同一作用域中先前的声明中所提供的默认实参：
int x(int = 1, int); // 错误：只有尾随实参能拥有默认值（假设前面没有 x 的声明）

void f(int n, int k = 1);
void f(int n = 0, int k); // OK：同一作用域中之前的声明为 k 提供了默认实参

void g(int, int = 7);
void h() {
  void g(int = 1, int); // 错误：不在同一作用域
}
  • ...除非该形参是从某个形参包展开得到的：
template<class ...T> struct C { void f(int n = 0, T...); };
C<int> c;  // OK；实例化了声明 void C::f(int n = 0, int)
  • 或者是函数形参包：
template<class...T> void h(int i = 0, T... args); // OK
 (C++11 起)

省略号不是形参，所以它可以跟在带有默认实参的形参之后：

int g(int n = 0, ...); // OK

默认实参只能在函数声明 和 lambda 表达式 (C++11 起)的形参列表中出现，而不能在函数指针、到函数的引用，或在 typedef 声明中出现。模板形参列表为其默认模板实参使用了类似的语法。

对于非模板函数，当在同一作用域中重声明函数时，可以向已声明的函数添加默认实参。在函数调用点，可用的默认实参是由该函数所有可见的声明中所提供的默认实参的并集。重声明不能为已有可见默认值的实参引入默认值（即使值相同）。内层作用域中的重声明不从外层作用域获得默认实参。

void f(int, int);     // #1
void f(int, int = 7); // #2 OK ：添加到默认

void h() {
    f(3); // #1 与 #2 在作用域中；进行对 f(3,7) 的调用
    void f(int = 1, int); // 错误：内层作用域声明不获得默认实参
}

void m() { // 新作用域开始
    void f(int, int); // 内层作用域声明；无默认实参。
    f(4); // 错误：调用 f(int, int) 的实参不足
    void f(int, int = 6);
    f(4); // OK：调用 f(4,6);
    void f(int, int = 6); // 错误：不能在同一作用域中重声明默认实参
}

void f(int = 1, int); // #3 OK，向 #2 添加默认实参

void n() { // 新作用域开始
    f(); // #1、#2 及 #3 在作用域中：调用 f(1, 7);
}

如果一个 inline 函数在不同的翻译单元中声明，那么默认实参的累积集必须在每个翻译单元的结尾相同。

如果一个非 inline 函数在不同翻译单元的同一命名空间作用域中声明，那么对应的默认实参在存在时必须相同（但某些翻译单元中可以缺少一些默认实参）。

 (C++20 起)

如果 friend 声明指定了默认实参，那么它必须是友元函数定义，且该翻译单元中不能有此函数的其他声明。

using 声明将已知的默认实参集承接过来，且如果向函数的命名空间中添加更多默认形参，那么这些默认实参在这条 using 声明可见的任何位置均可见：

namespace N {
    void f(int, int = 1);
}
using N::f;
void g() {
    f(7); // 调用 f(7, 1);
    f();  // 错误
}
namespace N {
    void f(int = 2, int);
}
void h() {
    f();  // 调用 f(2, 1);
}

对默认实参中使用的名字进行查找，检查可访问性，并绑定于声明点，但在函数调用点才执行：

int a = 1;
int f(int);
int g(int x = f(a)); // f 的查找找到 ::f，a 的查找找到 ::a
                     // 不使用 ::a 的值，它在这里是 1
void h()
{
  a = 2;  // 更改 ::a 的值
  {
     int a = 3;
     g();       // 调用 f(2)，然后以它的结果调用 g()
  }
}

对于非模板类的成员函数，类外的定义中允许出现默认实参，并与类体内的声明所提供的默认实参组合。如果类外的默认实参会使成员函数变成默认、复制或移动构造函数，那么程序非良构。对于类模板的成员函数，所有默认实参必须在成员函数的初始声明处提供。

class C {
    void f(int i = 3);
    void g(int i, int j = 99);
    C(int arg); // 非默认构造函数
};
void C::f(int i = 3) {         // 错误：默认实参已指定于类作用域
}
void C::g(int i = 88, int j) { // OK：此翻译单元中，可无实参调用 C::g
}
C::C(int arg = 1) {   // 错误：使之变成了默认构造函数
}

虚函数的覆盖函数不会从基类定义获得默认实参，而在进行虚函数调用时，默认实参根据对象的静态类型确定（注意：这可以通过非虚接口模式避免）。

struct Base {
    virtual void f(int a = 7);
};
struct Derived : Base {
    void f(int a) override;
};
void m() {
    Derived d;
    Base& b = d;
    b.f(); // OK：调用 Derived::f(7)
    d.f(); // 错误：没有默认实参
}

默认实参中不允许使用局部变量，除非用于不求值语境中 (C++14 起)：

void f()
{
    int n = 1;
    extern void g(int x = n); // 错误：局部变量不能为默认
    extern void h(int x = sizeof n); // CWG 2082 起 OK
}

默认实参中不允许 this 指针：

class A {
  void f(A* p = this) { } // 错误：不允许 this
};

默认实参中不允许使用非静态的类成员（即使它们不被求值），除非用于构成成员指针或在成员访问表达式中使用：

int b;
class X {
  int a;
  int mem1(int i = a); // 错误：不能使用非静态数据成员
  int mem2(int i = b); // OK：查找找到静态成员 X::b
  static int b;
};

默认实参中不允许使用函数形参（即使它们不被求值） (C++14 前)除非它们不被求值 (C++14 起)。注意，形参列表中较早出现的形参已在作用域中：

int a;
int f(int a, int b = a); // 错误：形参用作默认实参
int g(int a, int b = sizeof a); // CWG 2082 前错误
                                // CWG 2082 后 OK：可以用于不求值语境

默认实参不是函数类型的一部分：

int f(int = 0);
void h() {
  int j = f(1);
  int k = f();  // 调用 f(0);
}
int (*p1)(int) = &f;
int (*p2)()    = &f; // 错误：f 的类型是 int(int)

如果 lambda 表达式在默认实参中出现，那么它不能显式或隐式捕获任何内容：

void f2() {
    int i = 1;
    void g1(int = ([i]{ return i; })()); // 错误：有捕获内容
    void g2(int = ([i]{ return 0; })()); // 错误：有捕获内容
    void g3(int = ([=]{ return i; })()); // 错误：有捕获内容
    void g4(int = ([=]{ return 0; })());       // OK：无捕获
    void g5(int = ([]{ return sizeof i; })()); // OK：无捕获
}
 (C++11 起)

除了函数调用运算符外，运算符函数不能有默认参数：

class C {
    int operator[](int i = 0); // 非良构
    int operator()(int x = 0); // OK
};

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 2082 | C++14 | 曾禁止默认实参在不求值语境中使用局部变量 | 允许在不求值语境中使用


默认比较(C++20 起)

< cpp‎ | language

提供一种方式，以要求编译器为某个类生成相一致的比较运算符。

语法

返回类型 类名::operator 运算符( const 类名 & ) const &(可选) = default; | (1)
friend 返回类型 operator 运算符( const 类名 &, const 类名 & ) = default; | (2)
friend 返回类型 operator 运算符( 类名, 类名 ) = default; | (3)
运算符 - 比较运算符（<=>，==，!=，<，>，<=，或 >=）
返回类型 - 运算符函数的返回类型
  • 如果运算符是 <=>，必须是 auto 或三种比较类别之一，
  • 其他情况下，必须是 bool

解释

1) 将默认比较函数声明为成员函数。
2) 将默认比较函数声明为非成员函数。
3) 将默认比较函数声明为非成员函数。参数按值传递。

每当有值通过 <，>，<=，>=，或 <=> 被比较且重载决议选择该重载时，三路比较函数（不管是否为默认）会被调用。

每当有值通过 == 或 != 被比较且重载决议选择该重载时，相等比较函数（不管是否为默认）会被调用。

与默认的特殊成员函数类似，默认的比较函数在被 ODR 使用或被常量求值所需时被定义。

默认比较

默认三路比较

默认的 operator<=> 通过依次以计算 <=> 比较基类（从左到右，深度优先），然后是非静态成员（按声明顺序）子对象，递归地展开数组成员（按下标递增），并在发现不相等的结果时提前停止的方式执行字典序比较，即：

for /* T 的每个基类或子对象 o */
   if (auto cmp = static_cast<R>(compare(lhs.o, rhs.o)); cmp != 0) return cmp;
return static_cast<R>(strong_ordering::equal);

虚基子对象是否会多次被比较未被指明。

如果被声明的返回类型是 auto，实际的返回类型是要被比较的基类，成员子对象和成员数组元素的公共比较类别（见 std::common_comparison_category）。这样在编写返回类型非平凡地依赖于成员的场合时会更容易，例如：

template<class T1, class T2>
struct P {
 T1 x1;
 T2 x2;
 friend auto operator<=>(const P&, const P&) = default;
};

将返回类型设为 R ，每一对子对象 a, b 按如下方法进行比较：

  • 如果 a <=> b 可用，比较结果为 static_cast<R>(a <=> b)。
  • 否则，如果 operator<=> 的重载决议为 a <=> b 执行且至少找到一个候选，比较未定义（operator<=> 被定义为弃置的）。
  • 否则，如果 R 不是一个比较类别（见下文）或 a == b 与 a < b 有其一不可用，比较未定义（operator<=> 被定义为弃置的）。
  • 否则，如果 R 是 std::strong_ordering，结果是
a == b ? R::equal :
a < b  ? R::less :
         R::greater
  • 否则，如果 R 是 std::weak_ordering，结果是
a == b ? R::equivalent :
a < b  ? R::less :
         R::greater
  • 否则（R 是 std::partial_ordering），结果是
a == b ? R::equal :
a < b  ? R::less :
b < a  ? R::greater :
         R::unordered

与任何 operator<=> 重载的规则一样，默认的 <=> 重载也允许类型被 <，>，<=，和 >= 比较。

如果 operator<=> 是默认版本且 operator== 完全没有被声明，那么 operator== 将隐式地采用默认版本。

#include <compare>
struct Point {
  int x;
  int y;
  auto operator<=>(const Point&) const = default;
  // ... 非比较函数 ...
};
// 编译器生成全部六个比较运算符

#include <iostream>
#include <set>
int main() {
  Point pt1{1, 1}, pt2{1, 2};
  std::set<Point> s; // ok
  s.insert(pt1);     // ok
  std::cout << std::boolalpha
    << (pt1 == pt2) << ' ' // false；operator== 隐式地采用默认版本
    << (pt1 != pt2) << ' ' // true
    << (pt1 <  pt2) << ' ' // true
    << (pt1 <= pt2) << ' ' // true
    << (pt1 >  pt2) << ' ' // false
    << (pt1 >= pt2) << ' ';// false
}

默认相等比较

类可以定义 operator== 为默认版本，它返回一个 bool 值。这会以声明顺序对每个基类和成员子对象生成一轮相等比较。两个对象在它们每个基类和成员相等时相等。该检测会以声明顺序在找到基类或成员里出现不相等的情况下短路。

与任何 operator== 重载的规则一样，不等测试也能被允许：

struct Point {
  int x;
  int y;
  bool operator==(const Point&) const = default;
  // ... 非比较函数 ...
};
// 编译器生成分成员的相等比较

#include <iostream>
int main() {
  Point pt1{3, 5}, pt2{2, 5};
  std::cout << std::boolalpha
    << (pt1 != pt2) << '\n'  // true
    << (pt1 == pt1) << '\n'; // true
  struct [[maybe_unused]] { int x{}, y{}; } p, q;
  // if (p == q) { } // 错误：'operator==' 未被定义
}

其他默认比较操作符

四个关系运算符（<，>，<=，>=）均可以显式指定为默认版本。默认的关系运算符必须返回 bool。

如果 x <=> y 的重载决议（包括参数交换后的 operator<=>）失败，或 operator@ 无法被应用到 x <=> y 的结果，该操作符是弃置的。否则，默认的 operator@ 在重载决议选择参数顺序不变的 operator<=> 时调用 x <=> y @ 0 ，否则调用 0 @ y <=> x：

struct HasNoRelational {};

struct C {
  friend HasNoRelational operator<=>(const C&, const C&);
  bool operator<(const C&) = default;                       // OK：函数被弃置
};

与此类似，operator!= 也可以显式指定为默认版本。如果 x <=> y 的重载决议失败，或 x == y 结果的类型不为 bool，它也会被弃置。默认的 operator!= 会根据重载决议的选择调用 !(x == y) 或者 !(y == x)。

指定关系运算符使用默认版本可用于创建可取址的函数。其他场合仅需提供 operator<=> 和 operator==。

自定义的比较和比较类别

在默认语义不适用的情况下，例如成员不能按顺序比较，或者不能采用自然比较，那么程序员可以自定义 operator<=> 并让编译器生成合适的比较运算符。比较运算符的种类由用户定义的 operator<=> 决定。

返回类型有三种：

返回类型 | 运算符 | 等价的值 | 无法比较的值
std::strong_ordering | == != < > <= >= | 不可以被区分 | 不允许比较
std::weak_ordering | == != < > <= >= | 可以被区分 | 不允许比较
std::partial_ordering | == != < > <= >= | 可以被区分 | 允许比较

强序

在这个自定义 operator<=> 返回 std::strong_ordering 的例子中，该操作符比较了类的每个成员，只是顺序不同（在这里名在姓前面比较）。

#include <compare>
#include <string>
struct Base {
    std::string zip;
    auto operator<=>(const Base&) const = default;
};
struct TotallyOrdered : Base {
  std::string tax_id;
  std::string first_name;
  std::string last_name;
public:
 // 自定义 operator<=> ，因为我们希望（在比较姓前）先比较名：
 std::strong_ordering operator<=>(const TotallyOrdered& that) const {
   if (auto cmp = (Base&)(*this) <=> (Base&)that; cmp != 0)
       return cmp;
   if (auto cmp = last_name <=> that.last_name; cmp != 0)
       return cmp;
   if (auto cmp = first_name <=> that.first_name; cmp != 0)
       return cmp;
   return tax_id <=> that.tax_id;
 }
 // ... 非比较函数 ...
};
// 编译器生成全部四个关系运算符

#include <cassert>
#include <set>
int main() {
  TotallyOrdered to1{"a","b","c","d"}, to2{"a","b","d","c"};
  std::set<TotallyOrdered> s; // OK
  s.insert(to1); // OK
  assert(to2 <= to1); // OK，调用 <=> 一次
}

注：返回 std::strong_ordering 的操作符需要比较每个成员，因为如果有成员没有被比较，可替换性会受牵连：两个可被区分的值有可能会比较相等。

弱序

在这个自定义 operator<=> 返回 std::weak_ordering 的例子中，该操作符不分大小写地比较了类的字符串成员：这和默认比较不同（因此需要自定义运算符）且通过这种方式比较相等的两个字符串可能可以被区分。

class CaseInsensitiveString {
  std::string s;
public:
  std::weak_ordering operator<=>(const CaseInsensitiveString& b) const {
    return case_insensitive_compare(s.c_str(), b.s.c_str());
  }
  std::weak_ordering operator<=>(const char* b) const {
    return case_insensitive_compare(s.c_str(), b);
  }
  // ... 非比较函数 ...
};

// 编译器生成全部四个关系运算符
CaseInsensitiveString cis1, cis2;
std::set<CaseInsensitiveString> s; // OK
s.insert(/*...*/); // ok
if (cis1 <= cis2) { /*...*/ } // OK，执行一次比较操作

// 编译器也生成了全部八个混合参数的关系运算符
if (cis1 <= "xyzzy") { /*...*/ } // OK，执行一次比较操作
if ("xyzzy" >= cis1) { /*...*/ } // OK，语义相同

注：这个例子展示了参数类型不同的 operator<=> 的效果：它生成了双向的不同类型参数的比较。

偏序

偏序是一种允许无法比较（无序）的值的比较的排序，比如包括 NaN 值的浮点排序，或在这个例子里的没有关联的人：

class PersonInFamilyTree { // ...
public:
  std::partial_ordering operator<=>(const PersonInFamilyTree& that) const {
    if (this->is_the_same_person_as ( that)) return partial_ordering::equivalent;
    if (this->is_transitive_child_of( that)) return partial_ordering::less;
    if (that. is_transitive_child_of(*this)) return partial_ordering::greater;
    return partial_ordering::unordered;
  }
  // ... 非比较函数 ...
};
// 编译器生成全部四个关系运算符
PersonInFamilyTree per1, per2;
if (per1 < per2) { /*...*/ } // OK，per2 是 per1 的先人
else if (per1 > per2) { /*...*/ } // OK，per1 是 per2 的先人
else if (std::is_eq(per1 <=> per2)) { /*...*/ } // OK，per1 是 per2（同一人）
else { /*...*/ } // per1 与 per2 没有（直系）关联
if (per1 <= per2) { /*...*/ } // OK，per2 是 per1 或 per1 的先人
if (per1 >= per2) { /*...*/ } // OK，per1 是 per2 或 per2 的先人
if (std::is_neq(per1 <=> per2)) { /*...*/ } // OK，per1 不是 per2（但可能有直系关联）

参阅

  • 调用重载运算符中的重载决议
  • 内建的三路比较运算符
  • 比较运算符的运算符重载


默认初始化

< cpp‎ | language

这是在不使用初始化器构造变量时执行的初始化。

语法

T 对象 ; | (1)
new T new T ( ) (C++03 前) | (2)

解释

默认初始化在三种情况下进行：

1) 当不带初始化器而声明具有自动、静态或线程局部存储期的变量时；
2) 当以不带初始化器的 new 表达式创建具有动态存储期的对象时，或当以带有由一个空括号对组成的初始化器的 new 表达式创建对象时 (C++03 前)；
3) 当构造函数初始化器列表中未提及某个基类或非静态数据成员，且调用了该构造函数时。

默认初始化的效果是：

  • 如果 T 是非 POD (C++11 前)类类型，那么考虑各构造函数并实施针对空实参列表的重载决议。调用所选的构造函数（即默认构造函数之一），以提供新对象的初始值；
  • 如果 T 是数组类型，那么该数组的每个元素都被默认初始化；
  • 否则，不做任何事：具有自动存储期的对象（及其子对象）被初始化为不确定值。
只有具有自动存储期的（可有 cv 限定的）非 POD 类类型（或其数组）曾被认为在不使用初始化器时默认初始化。具有动态存储期的标量和 POD 类型曾被认为不被初始化（从 C++11 起，这种情况被重新分类为默认初始化的一种形式）。 | (C++11 前)
在（引入值初始化的）C++03 前，表达式 new T()，以及带一个空括号对形式的指名基类或成员的成员初始化器，曾被分类为默认初始化，但对非类类型则指定为零初始化。 | (C++03 前)

如果 T 是有 cv 限定的类型，那么默认初始化会采用其无 cv 限定版本。

 (C++11 前)

const 对象的默认初始化

如果程序调用有 const 限定类型的 T 对象的默认初始化，则 T 应当为 const 可默认构造类类型或其数组。

如果类类型 T 的默认初始化会调用用户提供（不是从基类继承） (C++11 起)的 T 构造函数，或满足以下条件，那么 T 为 const 可默认构造：

  • T 的每个直接非静态数据成员 M 拥有类类型 X （或其数组）， X 为 const 可默认构造，且
  • T 没有直接变体成员，且
 (C++11 前)
  • T 的每个直接非变体非静态数据成员 M 均拥有默认成员初始化器，或如果 M 拥有类类型 X （或其数组）， X 为 const 可默认构造，
  • 如果 T 至少拥有一个非静态数据成员的联合体，刚好有一个变体成员拥有默认成员初始化器，
  • 如果 T 不是联合体，那么对于每个至少拥有一个非静态数据成员的匿名联合体成员（若存在），刚好有一个非静态数据成员拥有默认成员初始化器，且
 (C++11 起)

T 的每个潜在构造的基类均为 const 可默认构造。

从不确定字节读取

使用由默认初始化任何非类类型的变量所取得的不确定的值是未定义行为（特别是，它可能是一种陷阱表示），除了下列情况：

  • 将 unsigned char 或 std::byte (C++17 起) 类型的不确定值赋值给另一拥有（可有 cv 限定的）unsigned char 或 std::byte (C++17 起) 类型的变量（变量的值变为不确定，但该行为不是未定义）；
  • 用 unsigned char 或 std::byte (C++17 起) 类型的不确定值初始化另一拥有（可有 cv 限定的）unsigned char 或 std::byte (C++17 起)类型的变量；
  • 从以下场合产生的 unsigned char 或 std::byte (C++17 起) 类型的不确定值
  • 条件表达式的第二或第三操作数，
  • 逗号运算符的右操作数，
  • 转型或转换到（可有 cv 限定的）unsigned char 或 std::byte (C++17 起)的操作数，
  • 弃值表达式。
int f(bool b)
{
    int x;               // OK：x 的值不确定
    int y = x;           // 未定义行为
    unsigned char c;     // OK：c 的值不确定
    unsigned char d = c; // OK：d 的值不确定
    int e = d;           // 未定义行为
    return b ? d : 0;    // 如果 b 为 true 则行为未定义
}

注解

具有自动和动态存储期的非类变量的默认初始化产生具有不确定值的对象（静态和线程局部对象进行的是零初始化）。

不能默认初始化引用和 const 标量对象。

示例

#include <string>

struct T1 { int mem; };

struct T2
{
    int mem;
    T2() { } // "mem" 不在初始化器列表中
};

int n; // 静态非类，进行两阶段初始化：
       // 1) 零初始化将 n 初始化为零
       // 2) 默认初始化不做任何事，令 n 保留为零

int main()
{
    int n;            // 非类，值不确定
    std::string s;    // 类，调用默认构造函数，值是 ""（空字符串）
    std::string a[2]; // 数组，默认初始化其各元素，值是 {"", ""}
//  int& r;           // 错误：引用
//  const int n;      // 错误：const 的非类
//  const T1 t1;      // 错误：const 的带隐式默认构造函数的类
    T1 t1;            // 类，调用隐式默认构造函数
    const T2 t2;      // const 类，调用用户提供的默认构造函数
                      // t2.mem 被默认初始化（为不确定值）
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 253 | C++98 | const 对象的默认初始化不能调用隐式声明的默认构造函数 | 如果所有子对象已初始化则允许
CWG 616 | C++98 | 任何未初始化对象的左值到右值的转换都是未定义行为 | 允许值不确定的 unsigned char
CWG 1787 | C++98 | 从缓存于寄存器的不确定的 unsigned char 读取是未定义行为 | 赋予良定义

参阅

  • 转换构造函数
  • 默认构造函数
  • explicit
  • 初始化
    • 聚合初始化
    • 常量初始化
    • 复制初始化
    • 直接初始化
    • 列表初始化
    • 引用初始化
    • 值初始化
    • 零初始化
  • new


待决名

< cpp‎ | language

在模板（类模板和函数模板）定义中，某些构造的含义可以在不同的实例化间有所不同。特别是，类型和表达式可能会取决于类型模板形参的类型和非类型模板形参的值。

template<typename T>
struct X : B<T> // "B<T>" 取决于 T
{
    typename T::A* pa; // "T::A" 取决于 T
                       // （此 "typename" 的使用的目的见下文）
    void f(B<T>* pb)
    {
        static int i = B<T>::i; // "B<T>::i" 取决于 T
        pb->j++; // "pb->j" 取决于 T
    }
};

对待决名和非待决名的名字查找和绑定有所不同。

绑定规则

非待决名在模板定义点查找并绑定。即使在模板实例化点有更好的匹配，也保持此绑定：

#include <iostream>
void g(double) { std::cout << "g(double)\n"; }

template<class T>
struct S
{
    void f() const
    {
        g(1); // "g" 是非待决名，现在绑定
    }
};

void g(int) { std::cout << "g(int)\n"; }

int main()
{
    g(1);  // 调用 g(int)

    S<int> s;
    s.f(); // 调用 g(double)
}

如果非待决名的含义在定义点和模板特化的实例化点间有所改变，那么程序非良构，不要求诊断。在下列情形可能会出现这种情况：

  • 非待决名用到的类型在定义点不完整但在实例化点完整
  • 模板定义中对名字的查找找到 using 声明，但实例化中对应作用域找不到任何声明，因为该 using 声明是包展开而对应的包为空
 (C++17 起)
  • 实例化使用了在定义点尚未定义的默认实参或默认模板实参
  • 实例化点的某个常量表达式使用了整型或无作用域枚举类型的 const 对象的值、constexpr 对象的值、引用的值或者 constexpr 函数的定义 (C++11 起)，而该对象/引用/函数 (C++11 起)在模板的定义点还没有定义
  • 该模板在实例化点使用了非待决的类模板特化或变量模板特化 (C++14 起)，而它所用的这个模板，或者从某个在定义点处还没有定义的部分特化所实例化，或者指名了某个在定义点处还没有声明的显式特化。

待决名的绑定则延迟到查找发生时。

查找规则

如名字查找中所讨论的，对于模板中所使用的待决名的查找延迟到模板实参已知时，届时

  • 非 ADL 查找检验从模板定义的语境可见的具有外部连接的函数声明
  • ADL 一并检验从模板定义的语境或从模板实例化的语境可见的具有外部连接的函数声明

（换言之，在模板定义后添加新函数声明不会令其可见，除非通过 ADL）。

此规则的目的是帮助模板实例化抵御 ODR 违规：

// 某个外部库
namespace E
{
    template<typename T>
    void writeObject(const T& t)
    {
        std::cout << "Value = " << t << '\n';
    }
}

// 翻译单元 1：
// 程序员 1 希望允许 E::writeObject 与 vector<int> 一同使用
namespace P1
{
    std::ostream& operator<<(std::ostream& os, const std::vector<int>& v)
    {
        for(int n : v)
            os << n << ' ';
        return os;
    }

    void doSomething()
    {
        std::vector<int> v;
        E::writeObject(v); // 错误：找不到 P1::operator<<
    }
}

// 翻译单元 2：
// 程序员 2 希望允许 E::writeObject 与 vector<int> 一同使用
namespace P2
{
    std::ostream& operator<<(std::ostream& os, const std::vector<int>& v)
    {
        for(int n : v)
            os << n <<':';
        return os << "[]";
    }

    void doSomethingElse()
    {
        std::vector<int> v;
        E::writeObject(v); // 错误：找不到 P2::operator<<
    }
}

在上例中，假如允许从实例化语境对 operator<< 进行非 ADL 查找，那么 E::writeObject<vector<int>> 的实例化会拥有两个不同定义：一个使用 P1::operator<<，一个使用 P2::operator<<。连接器可能无法检测这种 ODR 违规，导致两个实例中都使用其中一个或另一个。

为使得 ADL 检测用户定义命名空间，要么应当将 std::vector 替换成用户定义类，要么它的元素类型需要是用户定义类：

namespace P1
{
    // 如果 C 是在 P1 命名空间中定义的类
    std::ostream& operator<<(std::ostream& os, const std::vector<C>& v)
    {
        for(C n : v)
            os << n;
        return os;
    }

    void doSomething()
    {
        std::vector<C> v;
        E::writeObject(v); // OK：实例化 writeObject(std::vector<P1::C>)
                           //     通过 ADL 找到 P1::operator<<
    }
}

注意：由于此规则，实践中不适合为标准库类型重载运算符：

#include <iostream>
#include <vector>
#include <iterator>
#include <utility>

// 坏主意：全局命名空间中的运算符，但它的实参处于 std:: 中
std::ostream& operator<<(std::ostream& os, std::pair<int, double> p)
{
    return os << p.first << ',' << p.second;
}

int main()
{
    typedef std::pair<int, double> elem_t;
    std::vector<elem_t> v(10);
    std::cout << v[0] << '\n'; // OK，普通查找找到 ::operator<<
    std::copy(v.begin(), v.end(),
              std::ostream_iterator<elem_t>(std::cout, " "));
    // 错误：从 std::ostream_iterator 定义点的普通查找和 ADL 只会考虑 std
    // 命名空间，而且将找到 std::operator<< 的多个重载，因此这种查找会完成。
    // 之后在查找所找到的集合中，重载决议为 elem_t 寻找 operator<< 会失败。
}

注意：在模板定义时，也会发生待决名的有限制的查找（但非绑定），以便将它们与非待决名进行区分，也用于确定它们是当前实例化的成员还是未知特化的成员。此查找所获得的信息可用于检测错误，见下文。

待决类型

下列类型是待决类型：

  • 模板形参
  • 未知特化（见下文）的成员
  • 作为未知特化（见下文）的待决成员的嵌套类/枚举
  • 待决类型的 cv 限定版本
  • 从待决类型构成的复合类型
  • 元素类型待决或边界（如果存在）是值待决的数组类型
  • 形参包含一个或多个函数形参包的函数类型
 (C++11 起)
  • 异常说明是值待决的函数类型
 (C++17 起)
  • 模板标识，其中
  • 模板名是某个模板形参，或者
  • 有任何类型待决，或值待决，或者是包展开 (C++11 起)的模板实参（即使用到的模板标识不带实参列表，如注入类名）
  • 应用到类型待决表达式的 decltype 的结果

应用到类型待决表达式的 decltype 的结果是唯一的待决类型。两个这样的结果只有在它们的表达式等价时才指代同一类型。

 (C++11 起)

注意；当前实例化的 typedef 成员只有在它指代的类型待决时才会是待决的。

类型待决表达式

下列表达式是类型待决的：

  • 含有类型待决的子表达式的表达式
  • this，如果它的类是待决类型
  • 不是概念标识的 (C++20 起) 标识表达式，且
  • 包含某个能被自身的名字查找找到至少一个待决声明的标识符
  • 包含待决的模板标识
  • 包含特殊标识符 __func__（如果某个外围函数是模板，类模板的非模板成员，或泛型 lambda (C++14 起)）
 (C++11 起)
  • 包含到某个待决类型的转换函数名
  • 包含作为未知特化成员的嵌套名说明符或有限定标识
  • 指名当前实例化的某个待决成员，且该成员是“未知边界的数组”类型的静态数据成员
  • 包含某个能被自身的名字查找找到一个或更多的声明为具有返回类型推导的当前实例化的成员函数声明的标识符
 (C++14 起)
  • 包含能被自身的名字查找找到一个初始化器为类型待决的结构化绑定声明的标识符
  • 包含能被自身的名字查找找到类型含占位符 auto 的非类型模板形参的标识符
  • 包含能被自身的名字查找找到以包含占位符类型的类型声明且初始化器是类型待决的变量（例如 auto 静态数据成员）的标识符，
 (C++17 起)
  • 任何到待决类型的转型表达式
  • 创建待决类型对象的 new 表达式
  • 指代当前实例化的某个类型待决的成员的成员访问表达式
  • 指代未知特化的某个成员的成员访问表达式
  • 折叠表达式
 (C++17 起)

注意：字面量、伪析构函数调用、alignof、noexcept (C++11 起)、sizeof、typeid、delete、和 throw 表达式始终不是类型待决的，因为这些表达式的类型不可能待决。

值待决表达式

  • 在要求常量表达式的语境中使用的表达式，且其有任何子表达式是值待决的
  • 标识表达式，其
  • 为概念标识，而其实参有任何待决的
 (C++20 起)
  • 为类型待决的
  • 为某个非类型模板形参的名字
  • 指名某个作为当前实例化的待决成员的静态数据成员，且未被初始化。
  • 指名某个作为当前实例化的待决成员的静态成员函数
  • 为具有整数或枚举 (C++11 前)字面 (C++11 起)类型的常量，并从值待决表达式初始化
  • alignof、noexcept、 (C++11 起) sizeof、typeid 表达式，其实参是类型待决表达式或待决的类型标识
  • 任何向待决类型转换或从值待决表达式转换的转型表达式
  • 取址表达式，其实参是指名某个当前实例化的待决成员的有限定标识
  • 取址表达式，其实参是求值为核心常量表达式的，指代某个作为具有静态或线程 (C++11 起)存储期的对象或成员函数的模板化实体。
  • 折叠表达式
 (C++17 起)

待决名

本节未完成
原因：来自 [temp.dep] 的领句，现在缺失（后随有括号列表的 id 表达式……）
本节未完成
原因：重新遣词以令它更清晰（或至少不要那么吓人），并在 ait 时应用 CWG 问题 591

当前实例化

在类模板定义内（包含它的成员函数和嵌套类），一些名字可以推导为指代当前实例化。这样就可以在定义点，而非在实例化点检测某些错误，并移除对待决名上的 typename 及 template 消歧义符的要求，见下文。

只有下列名字可以指代当前实例化：

  • 在类模板特化中：
  • 嵌套类、类模板成员、嵌套类成员、模板的注入类名、嵌套类的注入类名
  • 在主类模板的定义或在它的成员的定义中：
  • 类模板的名字后随主模板的模板实参列表（或等价的别名模板特化），其中每个实参和它对应的形参等价。注意如果表达式用作非类型模板实参（例如，N+0，其中 N 是形参），那么它即使在值匹配时也不指名当前实例化。
  • 在嵌套的类或类模板的定义中：
  • 被用作当前实例化成员的嵌套类的名字
  • 在部分特化或部分特化的成员的定义中：
  • 类模板的名字后随部分特化的模板实参列表，其中每个实参和它对应的形参等价
template<class T>
class A
{
    A* p1;      // A 是当前实例化
    A<T>* p2;   // A<T> 是当前实例化
    ::A<T>* p4; // ::A<T> 是当前实例化
    A<T*> p3;   // A<T*> 不是当前实例化

    class B
    {
        B* p1;                 // B 是当前实例化
        A<T>::B* p2;           // A<T>::B 是当前实例化
        typename A<T*>::B* p3; // A<T*>::B 不是当前实例化
    };
};

template<class T>
class A<T*>
{
    A<T*>* p1; // A<T*> 是当前实例化
    A<T>* p2;  // A<T> 不是当前实例化
};

template<int I>
struct B
{
    static const int my_I = I;
    static const int my_I2 = I + 0;
    static const int my_I3 = my_I;

    B<my_I>* b3;  // B<my_I> 是当前实例化
    B<my_I2>* b4; // B<my_I2> 不是当前实例化
    B<my_I3>* b5; // B<my_I3> 是当前实例化
};

注意，如果嵌套类派生自它的外围类模板，那么基类也可以是当前实例化。是待决类型但不是当前实例化的基类是待决基类：

template<class T>
struct A
{
    typedef int M;
    struct B
    {
        typedef void M;
        struct C;
    };
};

template<class T>
struct A<T>::B::C : A<T>
{
    M m; // OK, A<T>::M
};

符合以下情况的名字被归类为当前实例化的成员：

  • 由无限定查找在当前实例化或它的非待决基类中所找到的未限定名
  • 限定符（:: 左侧的名字）指名了当前实例化，且查找在当前实例化或其非待决基类中找到的限定名
  • 用于类成员访问表达式的名字（x.y 或 xp->y 中的 y），其中对象表达式（x 或 *xp）是当前实例化，且查找在当前实例化或它的非待决基类中找到了该名字
template <class T>
class A
{
    static const int i = 5;
    int n1[i];       // i 指代当前实例化的成员
    int n2[A::i];    // A::i 指代当前实例化的成员
    int n3[A<T>::i]; // A<T>::i 指代当前实例化的成员
    int f();
};

template <class T>
int A<T>::f()
{
   return i; // i 指代当前实例化的成员
}

当前实例化的成员可以同时是待决和非待决的。

如果当前实例化的某个成员的查找在实例化点和定义点给出不同结果，那么查找有歧义。但要注意，在成员名被使用时，它不会自动转换成类成员访问表达式，只有显式成员访问表达式才会指示当前实例化的成员：

struct A { int m; };
struct B { int m; };

template<typename T>
struct C : A, T
{
    int f() { return this->m; } // 在模板定义语境找到 A::m
    int g() { return m; }       // 在模板定义语境找到 A::m
};

template int C<B>::f(); // 错误：找到 A::m 和 B::m

template int C<B>::g(); // OK：没有在模板定义语境中进行向类成员访问语法的变换

未知特化

在模板定义内，某些名字被推导为属于某个未知特化，特别是，

  • 在 :: 左侧出现了并非当前实例化成员的待决类型的名字的限定名
  • 限定符是当前实例化，且无法在当前实例化或它的任何非待决基类中找到，并存在待决基类的限定名
  • 类成员访问表达式中的成员名（x.y 或 xp->y 中的 y），如果对象表达式（x 或 *xp）的类型是待决类型且非当前实例化
  • 类成员访问表达式中的成员名（x.y 或 xp->y 中的 y），如果对象表达式（x 或 *xp）的类型是当前实例化，且在当前实例化或任何其非待决基类中找不到该名字，并存在待决基类
template<typename T> struct Base {};

template<typename T>
struct Derived : Base<T>
{
    void f()
    {
        // Derived<T> 指代当前实例化
        // 当前实例化没有 'unknown_type' 但有一个待决基类（Base<T>）
        // 因此 unknown_type 是未知特化的成员
        typename Derived<T>::unknown_type z;
    }
};

template<> struct Base<int> // 它在此特化提供
{
    typedef int unknown_type;
};

此分类允许在模板定义（而非实例化）点检测下列错误：

  • 如果有模板定义拥有某个限定名，其中的限定符指代当前实例化，且该名字既不是当前实例化的成员也不是未知特化的成员，那么程序非良构（不要求诊断），即使模板永远不会被实例化。
template<class T>
class A
{
    typedef int type;
    void f()
    {
        A<T>::type i; // OK：'type' 是当前实例化的成员
        typename A<T>::other j; // 错误：

        // 'other' 不是当前实例化的成员，也不是未知特化的成员，
        // 因为 A<T>（指名当前实例化）没有暗藏有 'other' 的待决基类。
    }
};
  • 如果有模板定义拥有某个成员访问表达式，其对象表达式是当前实例化，但其名字既不是当前实例化的成员也不是未知特化的成员，那么程序非良构，即使模板永远不会被实例化。

未知特化的成员始终是待决的，而且它们与所有待决名一样在实例化点进行查找和绑定（见上文）。

待决名的 typename 消歧义符

在模板（包括别名模版）的声明或定义中，不是当前实例化的成员且取决于某个模板形参的名字不会被认为是类型，除非使用关键词 typename 或它已经被设立为类型名（例如用 typedef 声明或通过用作基类名）。

#include <iostream>
#include <vector>

int p = 1;
template<typename T>
void foo(const std::vector<T> &v)
{
    // std::vector<T>::const_iterator 是待决名，
    typename std::vector<T>::const_iterator it = v.begin();

    // 下列内容因为没有 'typename' 而会被解析成
    // 类型待决的成员变量 'const_iterator' 和某变量 'p' 的乘法。
    // 因为在此处有一个可见的全局 'p'，所以此模板定义能编译。
    std::vector<T>::const_iterator* p;

    typedef typename std::vector<T>::const_iterator iter_t;
    iter_t * p2; // iter_t 是待决名，但已知它是类型名
}

template<typename T>
struct S
{
    typedef int value_t; // 当前实例化的成员
    void f()
    {
        S<T>::value_t n{}; // S<T> 待决，但不需要 'typename'
        std::cout << n << '\n';
    }
};

int main()
{
    std::vector<int> v;
    foo(v); // 模板实例化失败：类型 std::vector<int> 中没有
            // 名字是 'const_iterator' 的成员变量
    S<int>().f();
}

关键词 typename 只能以这种方式用于限定名（例如 T::x）之前，但这些名字不必待决。

对前附 typename 的标识符使用通常的有限定名字查找。这与用详述类型说明符的情况不同，不管限定符如何都不改变查找规则：

struct A // A 拥有嵌套变量 X 和嵌套类型 struct X
{
    struct X {};
    int X;
};

struct B
{
    struct X {}; // B 拥有嵌套类型 struct X
};

template<class T>
void f(T t)
{
    typename T::X x;
}

void foo()
{
    A a;
    B b;
    f(b); // OK：实例化 f<B>，T::X 指代 B::X
    f(a); // 错误：不能实例化 f<A>：因为 A::X 的有限定名字查找找到了数据成员
}

关键词 typename 只能在模板声明和定义中使用，而且只能用于可以使用待决名的语境中。这排除了显式特化声明和显式实例化声明。

 (C++11 前)

关键词 typename 即便在模板外也可以使用。

#include <vector>

int main()
{
    typedef typename std::vector<T>::const_iterator iter_t; // C++11 中 OK
    typename std::vector<int> v;                            // C++11 中也 OK
}
 (C++11 起)

某些语境中，只有类型名能合法地出现。在这些语境中，假定待决的限定名指名的就是类型而不必使用 typename：

  • 用作以下各项的（顶层）声明说明符序列 中的声明说明符的限定名：
  • 位于命名空间作用域的简单声明或函数声明；
  • 类成员声明；
  • 类成员声明（包括友元函数声明）中的形参声明，不包括默认实参；
  • 名字有限定的函数或函数模板的声明符的形参声明，不包括默认实参；
  • lambda 表达式的形参声明，不包括默认实参；
  • requires 表达式的形参声明；
  • 非类型模板形参声明中的类型；
  • 在类型标识中出现的限定名，其中最小的外围类型标识是：
  • 不对其类型加括号的 new 表达式中的 类型；
  • 别名声明中的 类型标识；
  • 尾随返回类型，
  • 类型模板形参的默认实参，或
  • static_cast、dynamic_cast、const_cast，或 reinterpret_cast 的 类型标识。
 (C++20 起)

待决名的 template 消歧义符

与此相似，模板定义中不是当前实例化的成员的待决名同样不被认为是模板名，除非使用消歧义关键词 template，或它已被设立为模板名：

template<typename T>
struct S
{
    template<typename U> void foo() {}
};

template<typename T>
void bar()
{
    S<T> s;
    s.foo<T>();          // 错误：< 被解析为小于运算符
    s.template foo<T>(); // OK
}

关键词 template 只能以这种方式用于运算符 ::（作用域解析）、->（通过指针的成员访问）和 .（成员访问）之后，下列表达式都是合法示例：

  • T::template foo<X>();
  • s.template foo<X>();
  • this->template foo<X>();
  • typename T::template iterator<int>::value_type v;

与 typename 的情况一样，即使名字并非待决或它的使用并未在模板的作用域中出现 (C++11 起)，也允许使用 template 前缀。

即使 :: 左侧的名字指代命名空间，也允许使用 template 消歧义符：

template<typename> struct s {};

::template s<void> q; // 允许，但不需要
 (C++17 起)

根据无限定名字查找针对成员访问表达式中的模板名的特殊规则，当非待决的模板名在成员访问表达式中出现时（-> 或 . 后），如果通过表达式语境中的常规名字查找找到了的具有相同名字的类或别名 (C++11 起)模板，那么就不需要消歧义符。然而，如果表达式语境中的查找所找到的模板与类语境中所找到的不同，那么程序非良构。 (C++11 前)

template<int> struct A { int value; };

template<class T>
void f(T t)
{
    t.A<0>::value; // A 的常规查找找到类模板。A<0>::value 指名类 A<0> 的成员
    // t.A < 0;    // 错误：'<' 被当做模板实参列表的起始
}
 (C++23 前)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1413 | C++98 | 未初始化静态数据成员、静态成员函数和类模板的成员的地址未列为值待决 | 已列入
CWG 1850 | C++98 | 含义在定义语境和实例化点之间变更的情况列表不完整 | 使之完整
CWG 2100 | C++98 | 类模板的静态成员常量地址未列为值待决 | 已列入
CWG 2457 | C++11 | 带函数形参包的函数类型未列为待决类型 | 已列入


派生类

< cpp‎ | language

任何类类型（无论是以 类关键词 class 还是 struct 声明）均可被声明为派生于一个或多个基类，各基类也可以派生自其自身的基类，组成继承层级结构。

基类的列表在类声明语法的 基类子句 中提供。基类子句 由字符 : 后随一或多个 基类说明符 的逗号分隔列表组成。

属性(可选) 访问说明符(可选) 虚说明符(可选) 类或-decltype
属性 - (C++11 起) 可选的任意数量属性的序列
访问说明符 - private、public 或 protected 之一
虚说明符 - 关键词 virtual
类或-decltype - 以下之一：
  • 嵌套名说明符(可选) 类型名
  • 嵌套名说明符 template 简单模板标识
  • decltype-说明符
 (C++11 起)

虚说明符 与 访问说明符 可以以任意顺序出现。由于语法限制，详述类型说明符不能直接作为 类或-decltype 出现。

基类子句 中的 基类说明符 可以是包展开。

类或-decltype 不能指代声明为 final 的类或结构体。

 (C++11 起)

如果省略 访问说明符，那么它对以 类关键词 struct 声明的类默认为 public，对以 类关键词 class 声明的类为 private。

struct Base {
    int a, b, c;
};
// 每个 Derived 类型对象包含一个 Base 子对象
struct Derived : Base {
    int b;
};
// 每个 Derived2 类型对象包含 Derived 与 Base 子对象
struct Derived2 : Derived {
    int c;
};

在 基类子句 中列出的 类或-decltype 所指代的类是直接基类。它们的基类是间接基类。同一类不能被多次指定为直接基类，但同一类可以既是直接又是间接基类。

每个直接和间接基类都作为基类子对象，以依赖于 ABI 的偏移量存在于派生类的对象表示中。因为空基类优化，空基类通常不会增加派生类对象的大小。基类子对象的构造函数被派生类的构造函数所调用：可以在成员初始化器列表中向这些构造函数提供实参。

虚基类

对于每个指定为 virtual 的不同基类，最终派生对象中仅含有该类型的一个基类子对象，即使该类在继承层级中出现多次也是如此（只要它每次都以 virtual 继承）。

struct B { int n; };
class X : public virtual B {};
class Y : virtual public B {};
class Z : public B {};
// 每个 AA 类型对象拥有一个 X，一个 Y，一个 Z 和两个 B：
// 一个是 Z 的基类，另一个由 X 与 Y 所共享
struct AA : X, Y, Z {
    void f() {
        X::n = 1; // 修改虚 B 子对象的成员
        Y::n = 2; // 修改同一虚 B 子对象的成员
        Z::n = 3; // 修改非虚 B 子对象的成员

        std::cout << X::n << Y::n << Z::n << '\n'; // 打印 223
    }
};

继承层级有虚基类的例子之一是标准库的 iostream 的继承层级：std::istream 与 std::ostream 使用虚继承从 std::ios 派生。std::iostream 同时派生于 std::istream 和 std::ostream，所以每个 std::iostream 实例含有一个 std::ostream 子对象、一个 std::istream 子对象和只有一个 std::ios 子对象（因此也只有一个 std::ios_base）。

所有虚基类子对象都在任何非虚基类子对象之前初始化，所以只有最终派生类会在它的成员初始化器列表中调用虚基类的构造函数：

struct B {
    int n;
    B(int x) : n(x) {}
};
struct X : virtual B { X() : B(1) {} };
struct Y : virtual B { Y() : B(2) {} };
struct AA : X, Y     { AA() : B(3), X(), Y() {} };

// AA 的默认构造函数调用 X 和 Y 的默认构造函数
// 但这些构造函数不调用 B 的构造函数，因为 B 是虚基类
AA a; // a.n == 3
// X 的默认构造函数调用 B 的构造函数
X x; // x.n == 1

涉及虚继承时，对类成员的无限定名字查找有特殊规则（有时被称为“优先性（dominance）规则”）。

公开继承

当类使用 public 成员访问说明符从基类派生时，基类的所有公开成员可作为派生类的公开成员访问，基类的所有受保护成员可作为派生类的受保护成员访问（基类的私有成员始终不可访问，除非设为友元）。

公开继承塑造了面向对象编程的子类型关系：派生类对象是（IS-A）基类对象。到派生类对象的引用和指针，可被期待到其任何公开基类的引用和指针的代码所用（见 LSP），或者以 DbC 的说法，派生类应该维护其公开基类的类不变式，不应强化其所覆盖的成员函数的任何前条件，或弱化其任何后条件。

#include <vector>
#include <string>
#include <iostream>

struct MenuOption { std::string title; };
// Menu 是 MenuOption 的 vector ：能插入、移除、重排……选项并拥有标题。
class Menu : public std::vector<MenuOption> {
public:
    std::string title;

    void print() const {
        std::cout << title << ":\n";
        for (std::size_t i = 0, s = size(); i < s; ++i)
            std::cout << "  " << (i+1) << ". " << at(i).title << '\n';
    }
};
// 注： Menu::title 没有问题因为它的角色与基类独立。

enum class Color { WHITE, RED, BLUE, GREEN };

void apply_terminal_color(Color) { /* 操作系统特定 */ }

// 这不好！
// ColorMenu 是每个选项都有定制颜色的 Menu 。
class ColorMenu : public Menu {
public:
    std::vector<Color> colors;

    void print() const {
        std::cout << title << ":\n";
        for (std::size_t i = 0, s = size(); i < s; ++i) {
            std::cout << "  " << (i+1) << ". ";
            apply_terminal_color(colors[i]);
            std::cout << at(i).title << '\n';
            apply_terminal_color(Color::WHITE);
        }
    }
};
// ColorMenu 需要下列通过公开继承 Menu 无法满足的不变式，例如：
// - ColorMenu::colors 与 Menu 必须拥有相同数量的元素
// - 为使得有意义，调用 erase() 也应该从 colors 移除元素以保持选项颜色
// 基本上每个对 std::vector 的非 const 方法调用都会破坏 ColorMenu 的不变式
// 并将会需要从用户由正确管理颜色来修复。

int main() {
    ColorMenu color_menu;

    // 这个类的大问题是我们必须保持_Color 与的 Menu 同步。
    color_menu.push_back(MenuOption{"某些选择"});

    // color_menu.print(); // 错误！print() 中的 colors[i] 在范围外

    color_menu.colors.push_back(Color::RED);

    color_menu.print(); // OK ：colors 与 Menu 拥有相同的元素数
}

受保护继承

当类使用 protected 成员访问说明符从基类派生时，基类的所有公开和受保护成员可作为派生类的受保护成员访问（基类的私有成员始终不可访问，除非设为友元）。

受保护继承可用于“受控制的多态”：在派生类的成员中，以及所有进一步派生的类的成员中，派生类是（IS-A）基类：到派生类的引用和指针可用于期待到基类的引用和指针处。

私有继承

当类使用 private 成员访问说明符从基类派生时，基类的所有公开和受保护成员可作为派生类的私有成员访问（基类的私有成员始终不可访问，除非设为友元）。

私有继承常用于基于策略的设计，因为策略常是空基类，而使用基类可以同时启用静多态并活用空基类优化

私有继承也可以用于实现合成关系（基类子对象是派生类对象的实现细节）。除非派生类需要访问基类的受保护成员（包含构造函数），需要覆盖基类的虚成员，需要基类在某个其他基类子对象之前构造或在其之后销毁，需要共享虚基类或需要控制虚基类的构造，否则使用成员方案可以提供更好的封装，而且通常是更受偏好的方式。使用成员来实现合成关系，亦不适用于从参数包进行多重继承的情况，或在编译时通过模板元编程确定各基类身份的情况。

与受保护继承相似，私有继承也可以用于受控制的多态：在派生类的成员内（但不在进一步派生的类中），派生类是（IS-A）基类。

template<typename Transport>
class service : private Transport  // 从 Transport 策略私有继承
{
public:
    void transmit() {
        this->send(...);  // 使用 Transport 提供的任何东西进行发送
    }
};
// TCP 传输策略
class tcp {
public:
    void send(...);
};
// UDP 传输策略
class udp {
public:
    void send(...);
};

service<tcp> service(host, port);
service.transmit(...); // 通过 TCP 发送

成员名字查找

针对类成员进行的无限定和有限定的名字查找规则，详见于名字查找。

参阅

  • 虚函数
  • 抽象类


直接初始化

< cpp‎ | language

从明确的构造函数实参的集合初始化对象。

语法

T 对象 ( 实参 ); T 对象 ( 实参1, 实参2, ... ); | (1) |
T 对象 { 实参 }; | (2) | (C++11 起)
T ( 其他对象 ) T ( 实参1, 实参2, ... ) | (3) |
static_cast< T >( 其他对象 ) | (4) |
new T(实参列表, ...) | (5) |
类::类() : 成员(实参列表, ...) { ... } | (6) |
[实参](){ ... } | (7) | (C++11 起)

解释

在下列场合进行直接初始化：

1) 以表达式或花括号初始化器列表 (C++11 起)的非空带括号列表初始化
2) 以花括号环绕的单个初始化器初始化一个非类类型对象（注意：对于类类型和其他使用花括号初始化器列表的初始化，见列表初始化）
3) 用函数式转型或以带括号的表达式列表初始化纯右值临时量 (C++17 前)纯右值的结果对象 (C++17 起)
4) 用 static_cast 表达式初始化纯右值临时量 (C++17 前)纯右值的结果对象 (C++17 起)
5) 用带有非空初始化器的 new 表达式初始化具有动态存储期的对象
6) 用构造函数初始化器列表初始化基类或非静态成员
7) 在 lambda 表达式中从按复制捕获的变量初始化闭包对象的成员

直接初始化的效果是：

  • 如果 T 是数组类型，那么
  • 程序非良构
 (C++20 前)
  • 按聚合初始化初始化数组，但允许窄化转换，并值初始化任何不带初始化器的元素。
struct A { explicit A(int i = 0) {} };
A a[2](A(1)); // OK：以 A(1) 初始化 a[0] 并以 A() 初始化 a[1]
A b[2]{A(1)}; // 错误：从 {} 隐式复制初始化 b[1] 选择了 explicit 构造函数
 (C++20 起)
  • 如果 T 是类类型，
  • 如果初始化器是纯右值表达式且类型与 T 为相同的类（忽略 cv 限定），则用初始化器表达式自身，而非从它实质化的临时量，初始化目标对象：
    （ C++17 前，编译器可以在此情况下消除源自纯右值的构造，但适合的构造函数仍必须可访问：参阅复制消除）
 (C++17 起)
  • 检验 T 的构造函数并由重载决议选取最佳匹配。然后调用该构造函数初始化对象。
  • 否则，如果目标类型是（可能有 cv 限定）的聚合类，则按聚合初始化中所述进行初始化，但允许窄化转换，不允许指派初始化器，不延长引用所绑定到的临时量的生存期，不进行花括号消除，并值初始化任何无初始化器的元素。
struct B {
  int a;
  int&& r;
};

int f();
int n = 10;

B b1{1, f()};               // OK：延长生存期
B b2(1, f());               // 良构，但有悬垂引用
B b3{1.0, 1};               // 错误：窄化转换
B b4(1.0, 1);               // 良构，但有悬垂引用
B b5(1.0, std::move(n));    // OK
 (C++20 起)
  • 否则，如果 T 是非类类型但源类型是类类型，则检验源类型及其各基类的转换函数，并由重载决议选取最佳匹配。然后用选取的用户定义转换，转换初始化器表达式为所初始化的对象。
  • 否则，如果 T 是 bool 而原类型是 std::nullptr_t，则被初始化对象的值为 false。
  • 否则，在必要时使用标准转换，转换 其他对象 的值为 T 的无 cv 限定版本，而所初始化的对象的初值为（可能为转换后的）该值。

注解

直接初始比复制初始化更宽松：复制初始化仅考虑非 explicit 构造函数和非 explicit 的用户定义转换函数，而直接初始化考虑所有构造函数和所有用户定义转换函数。

在使用直接初始化语法 (1)（带圆括号）的变量声明和函数声明之间有歧义的情况下，编译器始终选择函数声明。此消歧义规则有时是反直觉的，并且已被称为最烦人的分析。

#include <iterator>
#include <string>
#include <fstream>
int main()
{
    std::ifstream file("data.txt");
    // 下面是函数声明：
    std::string str(std::istreambuf_iterator<char>(file),
                    std::istreambuf_iterator<char>());
    // 它声明名为 str 的函数，其返回类型为 std::string，
    // 第一参数拥有 std::istreambuf_iterator<char> 类型和名称 "file"
    // 第二参数无名称并拥有类型 std::istreambuf_iterator<char>()，
    // 它被重写成函数指针类型 std::istreambuf_iterator<char>(*)()

    // C++11 前的修正：用额外括号环绕其中一个实参
    std::string str( (std::istreambuf_iterator<char>(file) ),
                      std::istreambuf_iterator<char>());
    // C++11 后的修正：列表初始化任意实参
    std::string str(std::istreambuf_iterator<char>{file}, {});
}

类似地，在以函数式转型表达式 (3) 为其最左子表达式的表达式语句，和声明语句间有歧义的情况下，以将它当做声明解决歧义。此消歧义是纯语法的：它不考虑语句中出现的名字除了是否为类型名之外的含义。

struct M { };
struct L { L(M&); };

M n;
void f() {
    M(m); // 声明，等价于 M m;
    L(n); // 非良构的声明
    L(l)(m); // 仍然是声明
}

示例

#include <string>
#include <iostream>
#include <memory>

struct Foo {
    int mem;
    explicit Foo(int n) : mem(n) {}
};

int main()
{
    std::string s1("test"); // 自 const char* 的构造函数
    std::string s2(10, 'a');

    std::unique_ptr<int> p(new int(1)); // OK：允许 explicit 构造函数
//  std::unique_ptr<int> p = new int(1); // 错误：构造函数为 explicit

    Foo f(2); // f 被直接初始化：
              // 构造函数形参 n 从右值 2 复制初始化
              // f.mem 从形参 n 直接初始化
//  Foo f2 = 2; // 错误：构造函数为 explicit

    std::cout << s1 << ' ' << s2 << ' ' << *p << ' ' << f.mem  << '\n';
}

输出：

test aaaaaaaaaa 1 2

参阅

  • 复制消除
  • 转换构造函数
  • 复制赋值
  • 复制构造函数
  • 默认构造函数
  • 析构函数
  • explicit
  • 初始化
    • 聚合初始化
    • 常量初始化
    • 默认初始化
    • 直接初始化
    • 初始化器列表
    • 列表初始化
    • 引用初始化
    • 值初始化
    • 零初始化
  • 移动赋值
  • 移动构造函数
  • new


do-while 循环

< cpp‎ | language

重复执行 语句，直到 表达式 的值变成 false。每次重复之后进行检测。

语法

属性(可选) do 语句 while ( 表达式 ) ;
属性 | - | (C++11 起) 任意数量的属性
表达式 | - | 能按语境转换成 bool 的任意表达式。每次重复之后求值表此表达式，且在它产生 false 时退出循环。
语句 | - | 任意语句，通常是复合语句，它是循环体

解释

始终至少执行一次 语句，即使 表达式 始终产生 false。如果希望这种情况下不应执行，那么可以用 while 或 for 循环替代。

如果循环的执行必须在某点终止，那么可以使用 break 语句作为终止语句。

如果循环需要在循环体结尾继续，那么可以使用 continue 语句作为快捷方式。

注意

作为 C++ 向前进展保证的一部分，如果没有可观察行为（不调用 I/O 函数，访问 volatile 对象，或进行原子或同步操作）的循环不会终止，那么它的行为未定义。编译器可以移除这种循环。

关键词

do, while

示例

#include <iostream>
#include <algorithm>
#include <string>

int main()
{
    int j = 2;
    do { // 循环体是复合语句
        j += 2;
        std::cout << j << " ";
    } while (j < 9);
    std::cout << '\n';
    // 使用 do-while 循环的常见情形
    std::string s = "aba";
    std::sort(s.begin(), s.end());
    do std::cout << s << '\n'; // 循环体是表达式语句
    while(std::next_permutation(s.begin(), s.end()));
}

输出：

4 6 8 10
aab
aba
baa

参阅


dynamic_cast 转换

< cpp‎ | language

沿继承层级向上、向下及侧向，安全地转换到其他类的指针和引用。

语法

dynamic_cast < 新类型 > ( 表达式 )
新类型 | - | 指向完整类类型的指针，到完整类类型的引用，或指向（可为 cv 限定的）void 的指针
表达式 | - | 如果 新类型 为引用，则为完整类类型的左值 (C++11 前)泛左值 (C++11 起)表达式，若 新类型 为指针，则为指向完整类类型的指针纯右值。

如果转型成功，则 dynamic_cast 返回 新类型 类型的值。如果转型失败且 新类型 是指针类型，则它返回该类型的空指针。如果转型失败且 新类型 是引用类型，则它抛出与类型 std::bad_cast 的处理块匹配的异常。

解释

只有下列转换在不去除常量性或易变性的场合才能用 dynamic_cast 进行。

1) 如果 表达式 的类型刚好是 新类型 或 新类型 的更少 cv 限定版本，则结果是 表达式 具有 新类型 类型的值。（换言之，dynamic_cast 可以用来添加常量性。隐式转换和 static_cast 也能进行此转换。）
2) 如果 表达式 的值是空指针值，则结果是 新类型 类型的空指针值。
3) 如果 新类型 是到 Base 的指针或引用，且 表达式 的类型是到 Derived 的指针或引用，其中 Base 是 Derived 的一个唯一的和可访问的基类，则结果是到 表达式 所标识的对象中 Base 类子对象的指针或引用。（注意：隐式转换和 static_cast 也能进行此转换。）
4) 如果 表达式 是指向多态类型的指针，且 新类型 是到 void 的指针，则结果是指向 表达式 所指向或引用的最终派生对象的指针。
5) 如果 表达式 是到多态类型 Base 的指针或引用，且 新类型 是到 Derived 类型的指针或引用，则进行运行时检查：
a) 检验 表达式 所指向/标识的最终派生对象。若在该对象中 表达式 指向/指代 Derived 的公开基类，且只有一个 Derived 类型对象从 表达式 所指向/标识的子对象派生，则转型结果指向/指代该 Derived 对象。（“向下转型（downcast）”）
b) 否则，若 表达式 指向/指代最终派生对象的公开基类，而同时最终派生对象拥有 Derived 类型的无歧义公开基类，则转型结果指向/指代该 Derived。（“侧向转型（sidecast）”）
c) 否则，运行时检查失败。若 dynamic_cast 用于指针，则返回 新类型 类型的空指针值。若它用于引用，则抛出 std::bad_cast 异常。
6) 当在构造函数或析构函数中（直接或间接）使用 dynamic_cast，且 表达式 指代正在构造/销毁的对象时，该对象被认为是最终派生对象。若 新类型 不是到构造函数/析构函数自身的类或其基类之一的指针或引用，则行为未定义。

与其他转型表达式相似：

  • 若 新类型 是左值引用类型（表达式 必为左值），则其结果为左值
  • 若 新类型 是右值引用类型（表达式 为完整类类型，可以是左值或右值 (C++17 前)必为泛左值（纯右值被实质化） (C++17 起)），则其结果为亡值
  • 若 新类型 是指针类型，则其结果为纯右值

注解

  • static_cast 也能用来进行向下转型，它避免运行时检查的开销，但只有在程序（通过某些其他逻辑）能够保证 表达式 所指向的对象肯定是 Derived 时才是安全的。
  • 某些形式的 dynamic_cast 依赖于运行时类型鉴别（ RTTI ），即编译的程序中关于每个多态类的信息。编译器通常有选项禁用此信息。

关键词

dynamic_cast

示例

#include <iostream>

struct V {
    virtual void f() {}  // 必须为多态以使用运行时检查的 dynamic_cast
};
struct A : virtual V {};
struct B : virtual V {
  B(V* v, A* a) {
    // 构造中转型（见后述 D 的构造函数中的调用）
    dynamic_cast<B*>(v); // 良好定义：v 有类型 V*，B 的 V 基类，产生 B*
    dynamic_cast<B*>(a); // 未定义行为：a 有类型 A*，A 非 B 的基类
  }
};
struct D : A, B {
    D() : B((A*)this, this) { }
};

struct Base {
    virtual ~Base() {}
};

struct Derived: Base {
    virtual void name() {}
};

int main()
{
    D d; // 最终派生对象
    A& a = d; // 向上转型，可以用 dynamic_cast，但不必须
    D& new_d = dynamic_cast<D&>(a); // 向下转型
    B& new_b = dynamic_cast<B&>(a); // 侧向转型

    Base* b1 = new Base;
    if(Derived* d = dynamic_cast<Derived*>(b1))
    {
        std::cout << "成功从 b1 向下转型到 d\n";
        d->name(); // 可以安全调用
    }

    Base* b2 = new Derived;
    if(Derived* d = dynamic_cast<Derived*>(b2))
    {
        std::cout << "成功从 b2 向下转型到 d\n";
        d->name(); // 可以安全调用
    }

    delete b1;
    delete b2;
}

输出：

成功从 b2 向下转型到 d

参阅

  • const_cast
  • static_cast
  • reinterpret_cast
  • 显式转型
  • 隐式转换


空基类优化

< cpp‎ | language

允许空的基类子对象大小为零。

解释

为保证同一类型的不同对象地址始终有别，要求任何对象或成员子对象的大小至少为 1，即使该类型是空的类类型（即没有非静态数据成员的 class 或 struct）（，除非带有 [[no_unique_address]]，见下文） (C++20 起)。

然而，基类子对象不受这种制约，而且可以完全从对象布局中被优化掉：

#include <cassert>

struct Base {}; // 空类

struct Derived1 : Base {
    int i;
};

int main()
{
    // 任何空类类型的对象大小至少为 1
    assert(sizeof(Base) > 0);

    // 应用空基类优化
    assert(sizeof(Derived1) == sizeof(int));
}

如果首个非静态数据成员的类型与一个空基类的类型相同或者由该空基类派生，那么禁用空基类优化，因为要求两个同类型基类子对象在最终派生类型的对象表示中必须拥有不同地址。

这种情况的典例是 std::reverse_iterator 的朴素实现（派生自空基类 std::iterator），它持有其底层迭代器（同样派生自 std::iterator）为其首个非静态数据成员。

#include <cassert>

struct Base {}; // 空类

struct Derived1 : Base {
    int i;
};

struct Derived2 : Base {
    Base c; // Base，占用 1 字节，后随对 i 的填充
    int i;
};

struct Derived3 : Base {
    Derived1 c; // 从 Base 派生，占用 sizeof(int) 字节
    int i;
};

int main()
{
    // 不应用空基优化，
    // 基类占用 1 字节，Base 成员占用 1 字节
    // 后随 2 个填充字节以满足 int 的对齐要求
    assert(sizeof(Derived2) == 2*sizeof(int));

    // 不应用空基类优化，
    // 基类占用至少 1 字节加填充，
    // 以满足首个成员的对齐要求（其对齐要求与 int 相同）
    assert(sizeof(Derived3) == 3*sizeof(int));
}

标准布局类型 (StandardLayoutType) 必须应用空基类优化以维持指向标准布局对象的指针在用 reinterpret_cast 转换后还指向其首成员，这是标准要求标准布局类型“在同一个类中声明所有非静态数据成员（全在派生类或全在某个基类）”，并且“不能有与首个非静态数据成员类型相同的基类”的原因。

 (C++11 起)

如果空成员子对象使用属性 [[no_unique_address]]，那么允许像空基类一样优化掉它们。取这种成员的地址会产生可能等于同一个对象的某个其他成员的地址。

#include <cassert>

struct Empty {}; // 空类

struct X {
    int i;
    [[no_unique_address]] Empty e;
};

int main()
{
    // 任何空类类型对象的大小至少为 1
    assert(sizeof(Empty) >= 1);

    // 空成员被优化掉
    assert(sizeof(X) == sizeof(int));
}
 (C++20 起)

注解

空基类优化常用于具分配器的标准库类（std::vector、std::function、std::shared_ptr 等），使得当分配器无状态时可避免为其分配器成员占用任何额外存储。这是通过将必要的数据成员之一（例如 vector 的 begin、end 或 capacity 指针）与分配器一起，在 boost::compressed_pair 的某种等价物中存储而实现的。

引用

  • C++11 标准（ISO/IEC 14882:2011）：
  • 5.10 Equality operators [expr.eq](p: 2)
  • 5.3.3 Sizeof [expr.sizeof](p: 2)
  • 9 Classes [class](p: 4,7)
  • 9.2 Class members [class.mem](p: 20)
  • C++98 标准（ISO/IEC 14882:1998）：
  • 5.10 Equality operators [expr.eq](p: 2)
  • 5.3.3 Sizeof [expr.sizeof](p: 2)
  • 9 Classes [class](p: 3)


详述类型说明符

< cpp‎ | language

详述类型说明符可用于指代先前声明的类名（class、struct 或 union）或先前声明的 enum 名，即使该名字被非类型声明所隐藏。它们亦可声明新的类名。

语法

类关键词 类名 | (1)
enum 枚举名 | (2)
类关键词 attr(可选) 标识符 ; | (3)
类关键词 | - | class、struct、union 之一
类名 | - | 先前声明的类类型的名字，可选地有限定，或为先前未作为类型名声明的标识符
枚举名 | - | 先前声明的枚举类型的名字，可选地有限定
1) 类类型的详述类型说明符
2) 枚举类型的详述类型说明符
3) 单独由详述类型说明符组成的声明，总是在含有该声明的作用域中声明一个名为 标识符 的类类型。

不可见枚举声明类似形式 (3)，但在不可见枚举声明之后，枚举类型是完整类型。

解释

形式 (3) 是详述类型说明符的一种特殊情况，通常又称为类的前置声明（forward declaration），有关形式 (3) 的描述，见前置声明。下列内容仅适用于形式 (1) 和 (2)。

详述类型说明符中的 类名 或 枚举名，可以是简单的标识符或是有限定的标识符。根据其表现形式，采用无限定名字查找或有限定名字查找来查找这个名字。但在任一情况下，均不考虑非类型名。

class T {
public:
    class U;
private:
    int U;
};

int main()
{
    int T;
    T t; // 错误：找到局部变量 T
    class T t; // OK：找到 ::T，忽略局部变量 T
    T::U* u; // 错误：T::U 的查找找到私有数据成员
    class T::U* u; // OK：忽略该数据成员
}

如果名字查找找不到先声明的类型名，该详述类型说明符是以 class、struct 或 union 引入的（即并非 enum），并且 类名 是无限定的标识符，则该详述类型说明符是该类名的一条类声明。

template <typename T>
struct Node {
    struct Node* Next; // OK：对 Node 的查找找到注入的类名
    struct Data* Data; // OK：于全局作用域声明类型 Data
                       // 并声明数据成员 Data
    friend class ::List; // 错误：不能引入有限定名
    enum Kind* kind; // 错误：不能引入枚举
};

Data* p; // OK：struct Data 已被声明

若该名字指代某个 typedef 名、类型别名、类型模板形参或别名模版特化，则程序非良构，否则详述类型说明符以与简单类型说明符引入其类型名相同的方式将该名字引入到声明中。

template <typename T>
class Node {
    friend class T; // 错误：类型形参不能出现于详述类型说明符中
};

class A {};
enum b { f, t };

int main()
{
    class A a; // OK：等价于 'A a;'
    enum b flag; // OK：等价于 'b flag;'
}

存在于详述类型说明符中的 类关键词 或 enum 必须与详述类型说明符所指代的名称的声明在种类上一致。

  • 关键词 enum 必须用于指代一个枚举类型（无论有无作用域）
  • 类关键词 union 必须用于指代一个 联合体（union）
  • 类关键词 class 或者 struct 必须用于指代一个非联合体类类型（此处关键词 class 与 struct 可互换）。
enum class E { a, b };
enum E x = E::a; // OK
enum class E y = E::b; // 错误：'enum class' 不能引入详述类型说明符

struct A {};
class A a; // OK

当用作模板实参时，class T 是名为 T 的类型模板形参，而非由详述类型说明符引入其类型 T 的无名非类型模板形参。

引用

  • C++11 标准（ISO/IEC 14882:2011）：
  • 3.4.4 Elaborated type specifiers [basic.lookup.elab]
  • 7.1.6.3 Elaborated type specifiers [dcl.type.elab]
  • C++98 标准（ISO/IEC 14882:1998）：
  • 3.4.4 Elaborated type specifiers [basic.lookup.elab]
  • 7.1.5.3 Elaborated type specifiers [dcl.type.elab]
本节未完成
原因：可能要将 9.1[class.name]/2-3 的大部分从 cpp/language/class 抽出


枚举声明

< cpp‎ | language

枚举（enumeration）是独立的类型，它的值被限制在一个取值范围内（细节见下文），它可以包含数个明确命名的常量（“枚举项（enumerator）”）。各常量的值是某个整型类型（称为该枚举的底层类型（underlying type））的值。

枚举以下列语法定义：

枚举关键词 属性(可选) 枚举名(可选) 枚举基(可选) { 枚举项列表(可选) } | (1) |
枚举关键词 属性(可选) 枚举名 枚举基(可选) ; | (2) | (C++11 起)
1) 枚举说明符，出现于声明语法的 声明说明符序列 ：定义枚举类型与其枚举项。
2) 不可见（opaque）枚举声明：定义枚举类型，但不定义其枚举项：在此声明后，该类型是完整类型，且其大小已知。注意：仅有的在 枚举名 之前出现 嵌套名说明符 的情况，是类模板的有作用域枚举成员的显式特化声明}}。
枚举关键字 -
enum | (C++11 前)
enum、 enum class 或 enum struct 之一 | (C++11 起)
属性 - (C++11 起) 可选的任意数量的属性序列
枚举名 - 所声明的枚举的名字。

只能在非不可见的无作用域枚举声明中省略名字。如果名字存在且此声明是重声明，那么它前面可以带有 嵌套名说明符，即名字和作用域解析运算符 :: 的序列并以作用域解析运算符结尾。

 (C++11 起)
枚举基 - (C++11 起) 冒号 (:)，后随指名某个整型类型的 类型说明符序列（忽略其限定性），该类型将作为此枚举类型的固定底层类型
枚举项列表 - 枚举项定义的逗号分隔列表，每项要么是简单的 标识符，它成为枚举项的名字，要么是带初始化器的标识符：标识符 = 常量表达式。在任一情况下，标识符 可直接后随一个可选的属性说明符序列。 (C++17 起)

有两种截然不同的枚举：无作用域枚举（以 枚举关键词 enum 声明）和有作用域枚举（以 枚举关键词 enum class 或 enum struct 声明）。

无作用域枚举

enum 名字(可选) { 枚举项 = 常量表达式 , 枚举项 = 常量表达式 , ... } | (1) |
enum 名字(可选) : 类型 { 枚举项 = 常量表达式 , 枚举项 = 常量表达式 , ... } | (2) | (C++11 起)
enum 名字 : 类型 ; | (3) | (C++11 起)
1) 声明一个无作用域枚举类型，其底层类型不固定（此时底层类型是由实现定义的某个能表示所有枚举项值的整型类型；此类型不大于 int，除非枚举项的值不能放入 int 或 unsigned int。如果 枚举项列表 为空，则底层类型为如同枚举拥有单个值为 0 的枚举项）。
2) 声明一个底层类型固定的无作用域枚举类型。
3) 无作用域枚举的不可见枚举声明必须指定名字与底层类型。

每个 枚举项 都成为该枚举类型（即 名字）的一个具名常量，在其外围作用域可见，且可用于要求常量的任何位置。

enum Color { red, green, blue };
Color r = red;
switch(r)
{
    case red  : std::cout << "红\n"; break;
    case green: std::cout << "绿\n"; break;
    case blue : std::cout << "蓝\n"; break;
}

每个枚举项都与一个底层类型的值相关联。当在 枚举项列表 中提供了初始化器时，各枚举项的值由那些初始化器所定义。如果首个枚举项无初始化器，那么它的关联值为零。对于其他任何定义中无初始化器的枚举项，其关联值为前一枚举项加一。

enum Foo { a, b, c = 10, d, e = 1, f, g = f + c };
//a = 0, b = 1, c = 10, d = 11, e = 1, f = 2, g = 12

无作用域枚举类型的值可隐式转换为整型类型。如果底层类型不固定，那么该值可转换到下列首个能保有其整个值范围的类型：int、unsigned int、long、unsigned long、long long 或 unsigned long long、拥有更高转换等级的扩展整数类型（按转换等级顺序，有符号优先于无符号） (C++11 起)。如果底层类型固定，那么该值可转换到其提升后的底层类型（在重载决议中优先），之后它能被提升。

enum color { red, yellow, green = 20, blue };
color col = red;
int n = blue; // n == 21

整数、浮点和枚举类型的值可用 static_cast 或显式转型转换到任何枚举类型。如果底层类型不固定且源值在范围外（源值，如果是浮点类型则首先转换到枚举的底层类型，能以足以保有目标枚举的所有枚举项的最小位域表示的情况下在范围内），则行为未定义。否则，结果与隐式转换到底层类型的结果相同。

注意，这种转换后的值不必等于任何为该枚举所定义的具名枚举项。

enum access_t { read = 1, write = 2, exec = 4 }; //枚举项：1、2、4 范围：0..7
access_t rwe = static_cast<access_t>(7);
assert((rwe & read) && (rwe & write) && (rwe & exec));

access_t x = static_cast<access_t>(8.0); // CWG1766 起是未定义行为
access_t y = static_cast<access_t>(8);   // CWG1766 起是未定义行为

enum foo { a = 0, b = UINT_MAX }; // 范围：[0, UINT_MAX]
foo x= foo(-1); // CWG1766 起是未定义行为，即使 foo 的底层类型是 unsigned int

无作用域枚举的 名字 可以忽略：这种声明仅将各枚举项引入到其外围作用域中：

enum { a, b, c = 0, d = a + 2 }; // 定义 a = 0, b = 1, c = 0, d = 2

当无作用域枚举是类成员时，其枚举项可以通过类成员访问运算符 . 和 -> 访问：

struct X
{
    enum direction { left = 'l', right = 'r' };
};
X x;
X* p = &x;

int a = X::direction::left; // 仅从 C++11 开始允许
int b = X::left;
int c = x.left;
int d = p->left;

有作用域枚举

enum struct|class 名字 { 枚举项 = 常量表达式 , 枚举项 = 常量表达式 , ... } | (1)
enum struct|class 名字 : 类型 { 枚举项 = 常量表达式 , 枚举项 = 常量表达式 , ... } | (2)
enum struct|class 名字 ; | (3)
enum struct|class 名字 : 类型 ; | (4)
1) 声明底层类型为 int 的有作用域枚举类型（关键词 class 与 struct 完全等价）
2) 声明底层类型为 类型 的有作用域枚举类型
3) 底层类型为 int 的有作用域枚举类型的不可见枚举声明
4) 底层类型为 类型 的有作用域枚举类型的不可见枚举声明

每个 枚举项 都成为该枚举的类型（即 名字）的具名常量，它为该枚举的作用域所包含，且可用作用域解析运算符访问。没有从有作用域枚举项到整数类型的隐式转换，尽管 static_cast 可用于获得枚举项的数值。

enum class Color { red, green = 20, blue };
Color r = Color::blue;
switch(r)
{
    case Color::red  : std::cout << "红\n"; break;
    case Color::green: std::cout << "绿\n"; break;
    case Color::blue : std::cout << "蓝\n"; break;
}
// int n = r; // 错误：不存在从有作用域枚举到 int 的隐式转换
int n = static_cast<int>(r); // OK, n = 21
 (C++11 起)

枚举在满足下列条件时都能用列表初始化从一个整数初始化而无需转型：

  • 初始化是直接列表初始化
  • 初始化器列表仅有单个元素
  • 枚举是底层类型固定的有作用域枚举或无作用域枚举
  • 转换为非窄化转换

这使得我们能引入新的整数类型（例如 SafeInt）并享受与其底层整数类型相同的既存调用约定，即使 ABI 不利于以值传递/返回结构体。

enum byte : unsigned char {}; // byte 是新的整数类型
byte b { 42 };       // C++17 起 OK（直接列表初始化）
byte c = { 42 };     // 错误
byte d = byte{ 42 }; // C++17 起 OK；与 b 的值相同
byte e { -1 };       // 错误

struct A { byte b; };
A a1 = { { 42 } };     // 错误（构造函数形参的复制列表初始化）
A a2 = { byte{ 42 } }; // C++17 起 OK

void f(byte);
f({ 42 }); // 错误（函数形参的复制列表初始化）

enum class Handle : std::uint32_t { Invalid = 0 };
Handle h { 42 }; // C++17 起 OK
 (C++17 起)

using enum 声明

using enum 嵌套名说明符(可选) 名字 ; (C++20 起)

其中 嵌套名说明符(可选) 名字 不得指名待决类型且必须指名一个枚举类型。

using enum 声明引入其所指名的枚举的枚举项名字，如同用对每个枚举项的 using 声明。在类作用域中时，using enum 声明将其指名的枚举的枚举项名字作为成员添加到作用域，使成员查找能访问它们。

enum class fruit { orange, apple };
struct S {
  using enum fruit; // OK ：引入 orange 与 apple 到 S 中
};
void f()
{
    S s;
    s.orange;  // OK ：指名 fruit::orange
    S::orange; // OK ：指名 fruit::orange
}

引入两个同名的枚举项的两个 using enum 声明会冲突。

enum class fruit { orange, apple };
enum class color { red, orange };
void f()
{
    using enum fruit;    // OK
    // using enum color; // 错误：color::orange 与 fruit::orange 冲突
}
 (C++20 起)

注解

尽管从范围外的值转换到无固定底层类型的枚举由 CWG 问题 1766 设为未定义行为，目前没有编译器在常量求值中对它进行要求的诊断。

示例

#include <iostream>
#include <cstdint>

// 采用 16 位的枚举
enum smallenum: std::int16_t
{
    a,
    b,
    c
};

// color 可为 red （值为 0）、 yellow （值为 1）、 green （值为 20）或 blue （值为 21）
enum color
{
    red,
    yellow,
    green = 20,
    blue
};

// altitude 可为 altitude::high 或 altitude::low
enum class altitude: char
{
     high='h',
     low='l', // C++11 允许额外的逗号
};

// 常量 d 为 0，常量 e 为 1，常量 f 为 3
enum
{
    d,
    e,
    f = e + 2
};

// 枚举类型（有作用域和无作用域）能有重载的运算符
std::ostream& operator<<(std::ostream& os, color c)
{
    switch(c)
    {
        case red   : os << "red";    break;
        case yellow: os << "yellow"; break;
        case green : os << "green";  break;
        case blue  : os << "blue";   break;
        default    : os.setstate(std::ios_base::failbit);
    }
    return os;
}

std::ostream& operator<<(std::ostream& os, altitude al)
{
    return os << static_cast<char>(al);
}

// 有作用域枚举（C++11）能部分地在早期 C++ 版本模拟：

enum struct E11 { x, y }; // C++11 起

struct E98 { enum { x, y }; }; // C++11 前也 OK

namespace N98 { enum { x, y }; } // C++11 前也 OK

struct S98 { static const int x = 0, y = 1; }; // C++11 前也 OK

void emu()
{
    std::cout << (static_cast<int>(E11::y) + E98::y + N98::y + S98::y) << '\n'; // 4
}

namespace cxx20
{
    enum class long_long_long_name { x, y };

    void using_enum_demo()
    {
        std::cout << "C++20 using enum: __cpp_using_enum == ";
        switch (auto rnd = []{return long_long_long_name::x;}; rnd())
        {
        #   if defined(__cpp_using_enum)
            using enum long_long_long_name;
            case x: std::cout << __cpp_using_enum << "; x\n"; break;
            case y: std::cout << __cpp_using_enum << "; y\n"; break;
        #   else
            case long_long_long_name::x: std::cout << "?; x\n"; break;
            case long_long_long_name::y: std::cout << "?; y\n"; break;
        #   endif
        }
    }
}

int main()
{
    color col = red;
    altitude a;
    a = altitude::low;

    std::cout << "col = " << col << '\n'
              << "a = "   << a   << '\n'
              << "f = "   << f   << '\n';

    cxx20::using_enum_demo();
}

输出：

col = red
a = l
f = 3
C++20 using enum: __cpp_using_enum == 201907; x

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1638 | C++11 | 不可见枚举声明的文法禁止用于模板特化 | 容许嵌套类型说明符
CWG 1766 | C++98 | 从范围外的值转型到无固定底层类型的枚举拥有未指明的结果 | 行为未定义

参阅

is_enum (C++11) | 检查类型是否是枚举类型 (类模板)
is_scoped_enum (C++23) | 检查类型是否为有作用域枚举类型 (类模板)
underlying_type (C++11) | 获取给定枚举类型的底层整数类型 (类模板)
to_underlying (C++23) | 转换枚举到其底层类型 (函数模板)


转义序列

< cpp‎ | language

转义序列用于在字符串字面量和字符字面量中表示某些特殊字符。

可以使用下列转义序列：

转义序列 | 描述 | 表示
简单转义序列
\' | 单引号 | ASCII 编码中为字节 0x27
\" | 双引号 | ASCII 编码中为字节 0x22
\? | 问号 | ASCII 编码中为字节 0x3f
\\ | 反斜杠 | ASCII 编码中为字节 0x5c
\a | 响铃 | ASCII 编码中为字节 0x07
\b | 退格 | ASCII 编码中为字节 0x08
\f | 换页 | ASCII 编码中为字节 0x0c
\n | 换行 | ASCII 编码中为字节 0x0a
\r | 回车 | ASCII 编码中为字节 0x0d
\t | 水平制表 | ASCII 编码中为字节 0x09
\v | 垂直制表 | ASCII 编码中为字节 0x0b
数值转义序列
\nnn | 任意八进制值 | 字节 nnn
\xnn | 任意十六进制值 | 字节 nn
条件转义序列[1]
\c | 实现定义 | 实现定义
通用字符名
\unnnn | 任意 Unicode 值： 可能生成多个编码单元 | 编码点 U+nnnn
\Unnnnnnnn | 任意 Unicode 值： 可能生成多个编码单元 | 编码点 U+nnnnnnnn
  1. ↑ 条件转义序列受条件性支持。每个条件转义序列中的字符 c 都是基础源字符集 (C++23 前)基础字符集 (C++23 起)中的成员，且不是任何其他转义序列中后随 \ 的字符。

通用字符名的范围

如果有一个通用字符名对应了一个小于 0xA0 且不是 0x24 ($)、 0x40 (@) 或 0x60 (`) 的码位，那么程序为谬构。换言之，通用字符名不能表达基础源字符集的成员与控制字符（范围为 0x0-0x1F 及 0x7F-0x9F）。 | (C++11 前)
如果在字符和字符串字面量以外有一个通用字符名对应了一个基础源字符集的成员或控制字符的码位，那么程序为谬构。 如果有一个通用字符名对应了一个代理码位（范围 0xD800-0xDFFF，含两端），那么程序为谬构。 如果有一个用于 UTF-16/32 字符串字面量的通用字符名不对应 ISO/IEC 10646 中的任何码位（范围 0x0-0x10FFFF，含两端）那么程序为谬构。 | (C++11 起) (C++20 前)
如果在字符和字符串字面量以外有一个通用字符名对应了一个基础源字符集的成员或控制字符的码位，那么程序为谬构。 如果有一个通用字符名不对应 ISO/IEC 10646 中的任何码位（范围 0x0-0x10FFFF，含两端）或对应了一个代理码位（范围 0xD800-0xDFFF，含两端），那么程序为谬构。 | (C++20 起) (C++23 前)
如果在字符和字符串字面量以外有一个通用字符名对应了一个基础字符集的字符或控制字符的标量值，那么程序为谬构。 如果有一个通用字符名不对应翻译字符集中的任何字符的标量值，那么程序为谬构。 | (C++23 起)

注解

\0 在八进制转义序列中最常用，因为它表示空终止字符串中的空终止字符。

换行符 \n 在用于文本模式 I/O 时有特殊含义：它被转换为操作系统指定的换行符表示，通常是一个字节或字节序列。某些系统转而用长度字段标记其文本行。

八进制转义序列具有三个八进制位的长度限制，但如果遇到首个不是合法八进制位的字符，则在此处提前终止。

十六进制转义序列无长度限制，并在首个不是合法十六进制位的字符处终止。若单个十六进制转义序列所表示的值不适于此字符串字面量或字符常量中使用的字符类型（char、char8_t (C++20 起)、char16_t、char32_t (C++11 起) 或 wchar_t），则其结果未指明。

窄字符串字面量或 16 位字符串字面量中的通用字符名可能映射到多于一个编码单元，例如 \U0001f34c 在 UTF-8 中是 4 个 char 编码单元（\xF0\x9F\x8D\x8C），而在 UTF-16 中是 2 个 char16_t 编码单元（\xD83C\xDF4C）。

 (C++11 起)

问号转义序列 \? 用于阻止在字符串字面量内转译三标符：如 "??/" 的字符串被编译成 "\"，但若如在 "?\?/" 中转义第二个问号，则它变为 "??/" 。由于三标符已从 C++ 移除，问号转义序列不再有必要。它为与 C++14 （及之前标准版本）及 C 的兼容保留。 (C++17 起)

示例

#include <iostream>

int main()
{
    std::cout << "这\n是\n一个\n测试\n\nShe said, \"Sells she seashells on the seashore?\"\n";
}

输出：

这
是
一个
测试

She said, "Sells she seashells on the seashore?"

参阅

  • ASCII 码表


动态异常说明 (C++17 前)

< cpp‎ | language

列出函数可能直接或间接抛出的异常。

语法

throw(类型标识列表(可选)) (1) (C++11 中弃用)
(C++17 中移除)
1) 显式动态异常说明
类型标识列表 - 逗号分隔的类型标识列表，后附省略号（...）的类型标识表示包展开 (C++11 起)

这种说明只能在作为类型为函数类型、函数指针类型、函数引用类型、成员函数指针类型的函数、变量、非静态数据成员的声明符的，顶层函数声明符上和形参的声明符或返回类型的声明符上出现。

void f() throw(int);            // OK：函数声明
void (*pf)() throw (int);       // OK：函数指针声明
void g(void pfa() throw(int));  // OK：函数指针形参声明
typedef int (*pf)() throw(int); // 错误：typedef 声明

解释

如果某个函数的声明将类型 T 列于其动态异常说明，那么该函数可以抛出该类型或从该类型派生的类型的异常。没有类型标识列表的动态异常说明（即 throw()）是不抛出的。带有不抛出动态异常说明的函数不允许任何异常。

异常说明中不能出现不完整类型，除 cv void* 之外的到不完整类型的指针或引用，以及右值引用类型。如果使用数组和函数类型，那么它们会被调整到对应的指针类型。允许形参包。 (C++11 起)

动态异常说明不会被认为是函数类型的一部分。

如果函数抛出了没有列于其异常说明的类型的异常，那么调用函数 std::unexpected。默认的该函数会调用 std::terminate，但它可以（通过 std::set_unexpected）被替换成可能调用 std::terminate 或抛出异常的用户提供的函数。如果异常说明接受从 std::unexpected 抛出的异常，那么栈回溯照常持续。如果它不被接受，但异常说明允许 std::bad_exception，那么抛出 std::bad_exception。否则，调用 std::terminate。

潜在异常

每个函数 f，函数指针 pf，与成员函数指针 pmf 都拥有一个“潜在异常集合”，它由可能抛出的类型构成。所有类型的集合指示可能抛出任何异常。此集合定义如下：

1) 如果 f、pf 或 pmf 的声明使用并非允许所有异常的 (C++11 前)动态异常说明，那么集合由列于该规定的所有类型组成。
2) 否则，如果 f、 pf 或 pmf 的声明有使用 noexcept(true)，那么集合为空。
 (C++11 起)
3) 否则，集合是所有类型的集合。

注意：对于隐式声明的特殊成员函数（构造函数、赋值运算符和析构函数），以及对于继承的构造函数 (C++11 起)，潜在异常的集合是它们会调用的所有函数的潜在异常集合的并集：非变体非静态数据成员、直接基类及适当场合的虚基类的构造函数/赋值运算符/析构函数（还包括默认实参表达式）

每个表达式 e 都拥有一个潜在异常集合。如果 e 是核心常量表达式，那么集合为空，否则集合是 e 的全部直接子表达式（包含默认实参表达式）的潜在异常集合的并集，再与下列取决于 e 的形式的另一个集合合并：

1) 如果 e 是一个函数调用表达式，令 g 代表被调用的函数、函数指针或成员函数指针，那么：
  • 如果 g 的声明使用了动态异常说明，那么添加 g 的潜在异常集合到集合；
  • 如果 g 的声明使用了 noexcept(true)，那么集合为空；
 (C++11 起)
  • 否则，该集合是所有类型的集合。
2) 如果 e 隐式调用了某个函数（它是运算符表达式且该运算符被重载，是 new 表达式且其分配函数被重载，或是完整表达式且调用了临时量的析构函数），那么该集合是这个函数的集合。
3) 如果 e 是一个 throw 表达式，那么该集合是以其操作数所初始化的异常，或对于重抛出表达式（无操作数者）是所有异常的集合。
4) 如果 e 是对多态类型引用的 dynamic_cast，那么该集合由 std::bad_cast 组成。
5) 如果 e 是应用到多解引用指向多态类型指针的 typeid，那么该集合由 std::bad_typeid 组成。
6) 如果 e 是一个拥有非常量数组大小的 new 表达式，且选择的分配函数拥有非空的潜在异常集合，那么该集合由 std::bad_array_new_length 组成。
 (C++11 起)
void f() throw(int); // f() 的集合是“int”
void g();            // g() 的集合是所有类型的集合
struct A { A(); };                  // “new A”的集合是所有类型的集合
struct B { B() noexcept; };         // “B()”的集合为空
struct D() { D() throw (double); }; // “new D”的集合是所有类型的集合

所有隐式声明的成员函数和继承的构造函数 (C++11 起)都拥有异常说明，选择如下：

  • 如果潜在异常的集合是类型全集，那么隐式异常说明允许所有异常（该异常说明被认为存在，即使它不可用代码表达，且表现如同无异常说明） (C++11 前)是 noexcept(false) (C++11 起)。
  • 否则，如果潜在异常的集合非空，那么隐式异常说明列出每个来自该集合的类型
  • 否则，隐式异常说明是 throw() (C++11 前)noexcept(true) (C++11 起)。
struct A
{
    A(int = (A(5), 0)) noexcept;
    A(const A&) throw();
    A(A&&) throw();
    ~A() throw(X);
};

struct B
{
    B() throw();
    B(const B&) = default; // 异常说明是“noexcept(true)”
    B(B&&, int = (throw Y(), 0)) noexcept;
    ~B() throw(Y);
};

int n = 7;
struct D : public A, public B
{
    int * p = new (std::nothrow) int[n];
    // D 拥有下列隐式声明的成员：
    // D::D() throw(X, std::bad_array_new_length);
    // D::D(const D&) noexcept(true);
    // D::D(D&&) throw(Y);
    // D::~D() throw(X, Y);
};

示例

#include <iostream>
#include <exception>
#include <cstdlib>

static_assert(__cplusplus < 201700, "ISO C++17 不允许动态异常说明。");

class X {};
class Y {};
class Z : public X {};
class W {};

void f() throw(X, Y)
{
    int n = 0;
    if (n) throw X(); // OK
    if (n) throw Z(); // OK
    throw W(); // 将调用 std::unexpected()
}

int main()
{
    std::set_unexpected([]
    {
        std::cout << "预料外的异常！" << std::endl; // 需要清除缓冲区
        std::abort();
    });
    f();
}

输出：

预料外的异常！

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 25 | C++98 | 在拥有不同异常说明的指向成员的指针间赋值或初始化的行为未指明 | 应用与函数指针和函数引用相同的限制
CWG 1351 | C++98 C++11 | 不考虑隐式异常说明中的默认实参（C++98）与默认成员初始化器（C++11） | 考虑它们
CWG 2191 | C++98 | typeid 表达式的潜在异常集合可以包含 bad_typeid ，即使不能抛出它 | 只有在能抛出时包含它

参阅

noexcept 说明符 (C++11) 指定函数是否抛出异常


异常

< cpp‎ | language

异常处理提供了一种可以使程序从执行的某点将控制流和信息转移到与执行先前经过的某点相关联的处理代码的方法（换言之，异常处理将控制权沿调用栈向上转移）。

throw 表达式、dynamic_cast、typeid、new 表达式、分配函数，以及专门用来抛出特定异常以指示特定错误状态的任何标准库函数（例如 std::vector::at、std::string::substr 等）都可以抛出异常。

为捕获异常，throw 表达式必须在 try 块或者 try 块中所调用的函数中，而且必须有与异常对象的类型相匹配的 catch 子句。

在声明函数时，可以提供以下说明以限制函数能够抛出的异常类型：

  • 动态异常说明
 (C++17 前)
  • noexcept 说明
 (C++11 起)

异常处理过程中发生的错误由 std::terminate 和 std::unexpected (C++17 前) 处理。

用法

尽管 throw 表达式转移控制到执行栈上方的任意代码块时没有条件限制（类似 std::longjmp），但它的预期用途还是进行错误处理。

错误处理

异常的抛出用于从函数中为错误发信号，其中“错误”通常仅限于以下内容[1][2][3]：

  1. 无法满足后置条件，例如不能产生有效的返回值对象
  2. 无法满足另一个必须调用的函数的前置条件
  3. （对于非私有成员函数）无法（再）建立类不变量

这意味着构造函数（参阅 RAII）和大多数运算符应该通过抛出异常来报告程序错误。

另外，所谓宽契约（wide contract）函数用异常来指示非法输入，例如，std::string::at 没有前置条件，但它会抛出异常以指示下标越界。

异常安全

在函数报告了错误状态后，可以提供附加保证以保障程序的状态。以下是四个被广泛认可的异常保证等级[4][5][6]，每个是另一个的严格超集：

  1. 不抛出（nothrow）（或不失败）异常保证——函数始终不会抛出异常。析构函数和其他可能在栈回溯中调用的函数被期待为不会抛出（以其他方式报告或隐瞒错误）。析构函数默认为 noexcept。 (C++11 起)交换函数（swap），移动构造函数，及为提供强异常保证所使用的其他函数，都被期待为不会失败（函数总是成功）。
  2. 强（strong）异常保证——如果函数抛出异常，那么程序的状态会恰好被回滚到该函数调用前的状态。（例如 std::vector::push_back）
  3. 基础（basic）异常保证——如果函数抛出异常，那么程序处于某个有效状态。不泄漏资源，而所有对象的不变式都保持完好。
  4. 无异常保证——如果函数抛出异常，那么程序可能不会处于有效的状态：可能已经发生了资源泄漏、内存损坏，或其他摧毁不变式的错误。

此外，泛型组件还可以提供异常中性（exception neutral）保证：如果从某个模板形参（例如从 std::sort 的 Compare 函数对象，或从 std::make_shared 中 T 的构造函数）抛出异常，那么它会被无修改地传播给调用方。

异常对象

虽然任意完整类型和指向 void 的 cv 指针都能作为异常对象抛出，但所有标准库函数都以值抛出匿名临时对象，而且这些对象的类型都（直接或间接）派生于 std::exception。用户定义的异常通常遵循此模式。[7][8][9]

为避免不必要的异常对象复制和对象切片，catch 子句在实践中最好以引用捕获。[10][11][12][13]

引用

  1. ↑ H. Sutter (2004) “何时及如何使用异常”于 Dr. Dobb's
  2. ↑ H.Sutter, A. Alexandrescu (2004)，“C++ 编码标准”，第 70 条
  3. ↑ C++ 核心指导方针 I.10
  4. ↑ B. Stroustrup (2000)，“C++ 程序语言” “附录 E”
  5. ↑ H. Sutter (2000) “Exceptional C++”
  6. ↑ D. Abrahams (2001) “泛型组件中的异常安全”
  7. ↑ D. Abrahams (2001) “错误与异常处理”
  8. ↑ isocpp.org Super-FAQ “我应该抛出什么？”
  9. ↑ C++ 核心指导方针 E.14
  10. ↑ C++ 核心指导方针 E.15
  11. ↑ S. Meyers (1996) “More Effective C++” 第 13 条
  12. ↑ isocpp.org 超级 FAQ “我应该捕获什么？”
  13. ↑ H.Sutter, A. Alexandrescu (2004) “C++ 编码标准” 第 73 条


explicit 说明符

< cpp‎ | language
explicit | (1) |
explicit ( 表达式 ) | (2) | (C++20 起)
表达式 - 经按语境转换为 bool 类型的常量表达式
1) 指定构造函数或转换函数 (C++11 起)或推导指引 (C++17 起)为显式，即它不能用于隐式转换和复制初始化。
2) explicit 说明符可以与常量表达式一同使用。函数在且只会在该常量表达式求值为 true 时是显式的。
 (C++20 起)

explicit 说明符只能在类定义之内的构造函数或转换函数 (C++11 起)的 声明说明符序列 中出现。

注解

声明时不带函数说明符 explicit 的拥有单个无默认值形参的 (C++11 前)构造函数被称作转换构造函数。

构造函数（除了复制或移动）和用户定义转换函数都可以是函数模板；explicit 的含义不变。

跟随 explicit 的 ( 记号被解析成 explicit 指定符的一部分：

struct S {
    explicit (S)(const S&);    // C++20 中错误，C++17 中 OK
    explicit (operator int)(); // C++20 中错误，C++17 中 OK
};
 (C++20 起)

示例

struct A
{
    A(int) { }      // 转换构造函数
    A(int, int) { } // 转换构造函数（C++11）
    operator bool() const { return true; }
};

struct B
{
    explicit B(int) { }
    explicit B(int, int) { }
    explicit operator bool() const { return true; }
};

int main()
{
    A a1 = 1;      // OK：复制初始化选择 A::A(int)
    A a2(2);       // OK：直接初始化选择 A::A(int)
    A a3 {4, 5};   // OK：直接列表初始化选择 A::A(int, int)
    A a4 = {4, 5}; // OK：复制列表初始化选择 A::A(int, int)
    A a5 = (A)1;   // OK：显式转型进行 static_cast
    if (a1) ;      // OK：A::operator bool()
    bool na1 = a1; // OK：复制初始化选择 A::operator bool()
    bool na2 = static_cast<bool>(a1); // OK：static_cast 进行直接初始化

//  B b1 = 1;      // 错误：复制初始化不考虑 B::B(int)
    B b2(2);       // OK：直接初始化选择 B::B(int)
    B b3 {4, 5};   // OK：直接列表初始化选择 B::B(int, int)
//  B b4 = {4, 5}; // 错误：复制列表初始化不考虑 B::B(int,int)
    B b5 = (B)1;   // OK：显式转型进行 static_cast
    if (b2) ;      // OK：B::operator bool()
//  bool nb1 = b2; // 错误：复制初始化不考虑 B::operator bool()
    bool nb2 = static_cast<bool>(b2); // OK：static_cast 进行直接初始化
}

参阅

  • 转换构造函数
  • 初始化
  • 复制初始化
  • 直接初始化


显式类型转换

< cpp‎ | language

用显式和隐式转换的组合进行类型之间的转换。

语法

( 新类型 ) 表达式 | (1) |
新类型 ( 表达式 ) | (2) |
新类型 ( 表达式列表 ) | (3) |
新类型 ( ) | (4) |
新类型 { 表达式列表(可选) } | (5) | (C++11 起)
模板名 ( 表达式列表(可选) ) | (6) | (C++17 起)
模板名 { 表达式列表(可选) } | (7) | (C++17 起)
auto ( 表达式 ) | (8) | (C++23 起)
auto { 表达式 } | (9) | (C++23 起)

返回 新类型 类型的值。

解释

1) 遇到 C 风格转型表达式时，编译器尝试将它解释成下列转型表达式，以此顺序：
a) const_cast<新类型>(表达式);
b) static_cast<新类型>(表达式)，带扩展：额外允许将到派生类的指针或引用转型成到无歧义基类的指针或引用（反之亦然），纵使基类不可访问也是如此（即此转型忽略 private 继承说明符）。同样适用于将成员指针转型为指向无歧义非虚基类的成员的指针；
c) static_cast（带扩展）后随 const_cast；
d) reinterpret_cast<新类型>(表达式)；
e) reinterpret_cast 后随 const_cast。
选择首个满足相应转型运算符要求的方式，即便它无法编译（见示例）。若转型能解释成多于一种 static_cast 后随 const_cast 的方式，则它无法编译。
另外，C 风格转型写法允许在不完整类型的指针之间进行双向转型。若 表达式 与 新类型 是指向不完整类型的指针，则选用 static_cast 还是 reinterpret_cast 是未指明的。
2) 函数式转型表达式由一个简单类型说明符或一个 typedef 说明符构成（换言之，它是单个单词的类型名：unsigned int(表达式) 或 int*(表达式) 非法），后随带括号的单个表达式。此转型表达式准确等价于对应的 C 风格转型表达式。
3) 若括号中有多于一个表达式，则 新类型 必须是带有适当声明的构造函数的类。此表达式是 新类型 类型的纯右值，其指代的临时量 (C++17 前)其结果对象 (C++17 起)以 表达式列表 直接初始化。
4) 若 新类型 指名一个非数组完整对象类型，则此表达式是 新类型 类型的纯右值，指代该类型临时量 (C++17 前)其结果对象为该类型（可能添加 cv 限定符） (C++17 起)。若 新类型 是对象类型，则对象被值初始化。若 新类型 是（可有 cv 限定的）void，则表达式是 void 纯右值而无结果对象 (C++17 起)。
5) 单个单词的类型名后随花括号初始化器列表，是指定类型的纯右值，其指代的临时量 (C++17 前)其结果对象 (C++17 起)以指定的花括号初始化器列表 直接列表初始化。若 新类型 是（可有 cv 限定的）void，则表达式是 void 纯右值而无结果对象 (C++17 起)。这是仅有的能创建数组纯右值的表达式。
6,7) 同 (2-5)，但首先进行类模板实参推导。
8,9) auto 说明符被分别替换成以 auto x(expr); （决不转译成函数声明）或 auto x{expr}; 声明的变量 x 的被推导类型。结果始终为对象类型的纯右值。

同所有转型表达式，结果是：

  • 左值，如果 新类型 是左值引用或到函数类型的右值引用；
  • 亡值，如果 新类型 是到对象类型的右值引用；
  • 否则为纯右值。

示例

double f = 3.14;
unsigned int n1 = (unsigned int)f; // C 风格转型
unsigned int n2 = unsigned(f);     // 函数式转型

class C1;
class C2;
C2* foo(C1* p)
{
    return (C2*)p; // 转型不完整类型到不完整类型
}

// 此示例中，C 风格转型被转译成 static_cast
// 尽管它的作用也可与 reinterpret_cast 一致
struct A {};
struct I1 : A {};
struct I2 : A {};
struct D : I1, I2 {};

int main()
{
    D* d = nullptr;
//  A* a = (A*)d;                   // 编译时错误
    A* a = reinterpret_cast<A*>(d); // 可以编译
}

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 7.6.1.4 Explicit type conversion (functional notation) [expr.type.conv]
  • 7.6.3 Explicit type conversion (cast notation) [expr.cast]
  • C++17 标准（ISO/IEC 14882:2017）：
  • 8.2.3 Explicit type conversion (functional notation) [expr.type.conv]
  • 8.4 Explicit type conversion (cast notation) [expr.cast]
  • C++14 标准（ISO/IEC 14882:2014）：
  • 5.2.3 Explicit type conversion (functional notation) [expr.type.conv]
  • 5.4 Explicit type conversion (cast notation) [expr.cast]
  • C++11 标准（ISO/IEC 14882:2011）：
  • 5.2.3 Explicit type conversion (functional notation) [expr.type.conv]
  • 5.4 Explicit type conversion (cast notation) [expr.cast]
  • C++03 标准（ISO/IEC 14882:2003）：
  • 5.2.3 Explicit type conversion (functional notation) [expr.type.conv]
  • 5.4 Explicit type conversion (cast notation) [expr.cast]
  • C++98 标准（ISO/IEC 14882:1998）：
  • 5.2.3 Explicit type conversion (functional notation) [expr.type.conv]
  • 5.4 Explicit type conversion (cast notation) [expr.cast]

参阅

const_cast 转换 | 添加或移除 const
static_cast 转换 | 进行基本转换
dynamic_cast 转换 | 进行有检查的多态转换
reinterpret_cast 转换 | 进行通用低层转换
标准转换 | 从一个类型到另一类型的隐式转换


表达式

< cpp‎ | language

表达式是运算符和它们的操作数的序列，它指定一项计算。

表达式的求值可以产生一个结果（比如 2+2 的求值产生结果 4），也可能产生副作用（比如对 std::printf ("%d",4) 的求值在标准输出上打印字符 '4'）。

概述

  • 值类别（左值 (lvalue)、右值 (rvalue)、泛左值 (glvalue)、纯右值 (prvalue)、亡值 (xvalue)）是根据表达式的值所进行的分类
  • 实参和子表达式的求值顺序指定获得中间结果所用的顺序

运算符

常见运算符
赋值 自增
自减 		算术 逻辑 比较 成员访问 其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
? :
特殊运算符

static_cast 转换一个类型为另一相关类型
dynamic_cast 在继承层级中转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 转换类型到无关类型
C 风格转型 以 static_cast 、 const_cast 及 reinterpret_cast 的混合转换一个类型到另一类型
new 创建有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象，并释放其所拥有的内存区域
sizeof 查询类型的大小
sizeof... 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 查询表达式是否能抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)
  • 运算符优先级定义了运算符绑定到其各实参的顺序
  • 替代表示是一些运算符的其他代用书写方式
  • 运算符重载允许对用户定义的类指定各运算符的行为。

转换

  • 标准转换为从一个类型到另一类型的隐式转换
  • const_cast 转换
  • static_cast 转换
  • dynamic_cast 转换
  • reinterpret_cast 转换
  • 显式转型转换，使用 C 风格写法和函数式写法
  • 用户定义转换使得可以指定源自用户定义类的转换

内存分配

  • new 表达式动态地分配内存
  • delete 表达式动态地解分配内存

其他

  • 常量表达式能在编译期求值并在编译期语境（如模板实参、数组大小等等）中使用
  • sizeof
  • alignof
  • typeid
  • throw 表达式

初等表达式

任何运算符的操作数都可以是其他的表达式或初等表达式（例如，1+2*3 中 operator+ 的操作数是子表达式 2*3 和初等表达式 1）。

初等表达式包括以下各项：

  • 字面量（例如 2 或 "Hello, world"）
  • 标识表达式，包括
    • 经过适当声明的无限定的标识符（例如 n 或 cout），以及
    • 经过适当声明的有限定的标识符（例如 std::string::npos）
  • lambda 表达式 (C++11)
  • 折叠表达式 (C++17)
  • requires 表达式 (C++20)

括号中的任何表达式也被归类为初等表达式：这确保了括号具有比任何运算符更高的优先级。括号保持值、类型和值类别不变。

字面量

字面量是 C++ 程序中用以表现嵌入到源代码中的常量值的记号。

  • 整数字面量是整数类型的十进制、八进制、十六进制或二进制 (C++14 起)的数值
  • 字符字面量是有下列类型之一的单个字符：
  • char 或 wchar_t
  • char16_t 或 char32_t (C++11 起)
  • char8_t (C++20 起)
  • 浮点字面量是 float、double 或 long double 类型的值
  • 字符串字面量是有下列类型之一的字符序列：
  • const char[] 或 const wchar_t[]
  • const char16_t[] 或 const char32_t[] (C++11 起)
  • const char8_t[] (C++20 起)
  • 布尔字面量是 bool 类型的值，即 true 和 false
  • nullptr 是指针字面量，指定一个空指针值 (C++11 起)
  • 用户定义字面量是用户指定的类型的常量值 (C++11 起)

不求值表达式

运算符 typeid、sizeof 、noexcept 和 decltype (C++11 起) 的操作数是不求值表达式（除非运算符为 typeid 而操作数是多态泛左值），因为这些运算符仅查询其操作数的编译期性质。因此，std::size_t n = sizeof( std::cout << 42); 不进行控制台输出。

不求值的运算数被当做完整表达式，即便它们在语法上是某个更大的表达式的操作数也是如此（例如，这意味着 sizeof(T()) 要求 T::~T 可访问）

 (C++14 起)

requires 表达式也是不求值表达式。

 (C++20 起)

弃值表达式

弃值表达式是仅用来实施其副作用的表达式。从这种表达式计算的值被舍弃。这样的表达式包括任何表达式语句的完整表达式，内建逗号运算符的左边的实参，以及转型到类型 void 的转型表达式的实参。

弃值表达式的计算结果永远不进行数组到指针和函数到指针转换。当且仅当该表达式是 volatile 限定的泛左值，并具有下列形式之一（必须为其内建含义，可以有括号）时，进行左值到右值转换：

  • 标识表达式 (id-expression)
  • 数组下标表达式
  • 类成员访问表达式
  • 间接寻址
  • 成员指针操作
  • 条件表达式，其第二个和第三个操作数都是这些表达式中的一种
  • 逗号表达式，其右操作数是这些表达式中的一种。

此外，若该左值拥有 volatile 限定的类类型，则要求用 volatile 复制构造函数来初始化作为结果的右值临时量。

如果表达式（经过可能会发生的任何左值向右值转换之后）是非 void 纯右值，则进行临时量实质化。

当表达式丢弃了声明为 [[nodiscard]] 的值，而它不是转型为 void 的表达式时，编译器可以发布警告。

 (C++17 起)


扩充命名空间 std

< cpp‎ | language

向 std 添加声明

向 namespace std 或 std 中嵌套的任何命名空间添加声明或定义，除了下面提到的少数例外，都是未定义行为：

#include <utility>
namespace std {
    // 向命名空间 std 添加函数：未定义行为
    pair<int, int> operator+(pair<int, int> a, pair<int, int> b) {
        return {a.first+b.first, a.second+b.second};
    }
}

添加模板特化

类模板

对于任何标准库类模板的模板特化，仅当其声明依赖于至少一个程序定义类型，且该特化满足原模板的所有要求时，才允许向命名空间 std 中添加，除非这种特化被禁止。

// 获取主 std::hash 模板的声明。不容许我等自己声明它。
// 保证 <typeindex> 提供这种声明，包含它比 <functional> 低廉很多。

#include <typeindex>

// 特化 std::hash 使得能以 MyType 为
// std::unordered_set 和 std::unordered_map 中的键
namespace std {
    template <> struct hash<MyType> {
      std::size_t operator()(const MyType& t) const { return t.hash(); }
    };
}
  • 对 float、double、long double 以外的类型特化 std::complex 是未指明的。
  • std::numeric_limits 的特化必须对主模板中所有声明为 static const (C++11 前)static constexpr (C++11 起) 的成员进行定义，而且要使得它们能用作整型常量表达式。
  • 除了 std::common_type 与 std::basic_common_reference (C++20 起)之外，<type_traits> 中定义的模板均不可对程序定义类型特化。这包含各种类型特征和 std::integral_constant 类模板。
  • 对程序定义类型特化的 std::hash 必须满足散列 (Hash) 要求。
  • std::atomic 的特化必须拥有被删除的复制构造函数，被删除的复制赋值运算符，及一个 constexpr 值构造函数。
  • std::shared_ptr 及 std::weak_ptr 的特化必须为可复制构造 (CopyConstructible) 且可复制赋值 (CopyAssignable) 。另外，std::shared_ptr 的特化必须可小于比较 (LessThanComparable) ，而且可转换为 bool。
 (C++11 起)
  • std::istreambuf_iterator 的特化必须有平凡复制构造函数、constexpr 默认构造函数，及平凡析构函数。
  • 不可特化 std::unary_function 与 std::binary_function。
 (C++17 前)

声明标准库类或类模板的任何成员类模板的完全或部分特化是未定义行为。

本节未完成
原因：小示例

函数模板与模板的成员函数

对于任何标准库函数模板的模板特化，仅当其声明依赖于至少一个程序定义类型，且该特化满足原模板的所有要求时，才允许向命名空间 std 中添加，除非这种特化被禁止。 | (C++20 前)
声明任何标准库函数模板的完全特化是未定义行为。 | (C++20 起)
本节未完成
原因：小示例

声明标准库类或类模板的任何成员函数模板的完全特化是未定义行为

本节未完成
原因：小示例

声明标准库类模板的任何成员函数的完全特化是未定义行为

本节未完成
原因：小示例

变量模板

声明任何标准库变量模板的完全特化或部分特化是未定义行为，除了显式允许的变量模板。

本节未完成
原因：小示例
(C++14 起)
  • std::disable_sized_sentinel_for 、 std::ranges::disable_sized_range 、 std::ranges::enable_view 与 std::ranges::enable_borrowed_range 的特化必须可用于常量表达式并拥有 const bool 类型。而且
    • std::disable_sized_sentinel_for 可对无 cv 限定的非数组对象类型 S 与 I 特化，其中至少一者须为程序定义类型。
    • std::ranges::disable_sized_range 、 std::ranges::enable_view 与 std::ranges::enable_borrowed_range 可对无 cv 限定的程序定义类型特化。
  • 每个数学常数变量模板均可被部分或显式特化，只要该特化依赖程序定义类型。
 (C++20 起)

模板的显式实例化

对于标准库中定义的类 (C++20 起)模板的显式实例化，仅当其声明依赖于至少一个程序定义类型的名称，且实例化满足标准库对原始模板的要求时，允许进行显示实例化。

本节未完成
原因：小示例

程序定义类型

程序定义特化是既非标准库的一部分亦非实现所定义的显式模板特化或部分特化。

程序定义类型是既非标准库的一部分亦非实现所定义的非闭包类类型或枚举类型 ，或非实现所提供的 lambda 表达式的闭包类型 (C++11 起)，或程序定义特化的实例化。

其他限制

不可将命名空间 std 声明为 inline 命名空间。

可取址函数

若 C++ 程序显式或隐式形成指向标准库函数或标准库函数模板实例化的指针、引用（对于自由函数和静态成员函数）或成员指针（对于非静态成员函数），则程序行为未指明（可能非良构），除非该函数被指定为可取址函数。

标准库中仅有的可取址函数是作为函数（或函数模板实例化），接收一个流对象的引用作为其唯一实参的 I/O 操纵符，如 std::endl、std::boolalpha。

下列代码在 C++17 中有恰当定义，但从 C++20 起导致未指明行为并且可能无法编译：

#include <cmath>
#include <memory>
int main()
{
    auto fptr0 = &std::betaf; // 通过一元 operator&
    auto fptr1 = std::addressof(std::betal) // 通过 std::addressof
    auto fptr2 = std::riemann_zetaf; // 通过函数到指针隐式转换
    auto &fref = std::riemann_zetal; // 形成引用
}
 (C++20 起)


final 说明符 (C++11 起)

< cpp‎ | language

指定某个虚函数不能在派生类中被覆盖，或者某个类不能被派生。

语法

当应用到成员函数时，标识符 final 在类定义中的成员函数声明或成员函数定义的语法中，紧随声明符之后出现。

当应用到类时，标识符 final 在类定义的开头，紧跟类名之后出现。

声明符 虚说明符序列(可选) 纯说明符(可选) | (1)
声明符 虚说明符序列(可选) 函数体 | (2)
类关键词 attr(可选) 类头名 类虚说明符(可选) 基类子句(可选) | (3)
1) 在成员函数声明中，final 可以在紧跟声明符之后的 虚说明符序列 中出现，如果有使用 纯说明符 则在其之前。
2) 在类定义内的成员函数定义中，final 可以在紧跟声明符之后并紧接 函数体 之前的 虚说明符序列 中出现。
3) 在类定义中，final 可以在紧跟类名之后，紧接 基类子句（若使用它）起头的冒号之前，作为 类虚说明符 出现。

情况 (1,2) 中，如果有使用 虚说明符序列，那么它是 override、final、final override 或 override final 之一。情况 (3) 中，如果有使用 类虚说明符 则只允许 final。

解释

当在虚函数声明或定义中使用时，final 说明符确保函数为虚并指定其不可被派生类覆盖，否则程序为谬构（生成编译时错误）。

当在类定义中使用时，final 指定此类不可在另一类的定义中的 基类说明符列表 中出现（换言之，不能派生于它），否则程序非良构（生成编译时错误）。final 也可以用于联合体定义，此时下它没有效果（除了 std::is_final 的输出结果） (C++14 起)，因为不能从联合体派生。

final 是在成员函数声明或类头部中使用时有特殊含义的标识符。其他语境中它未被保留，而且可用于命名对象或函数。

示例

struct Base
{
    virtual void foo();
};

struct A : Base
{
    void foo() final; // Base::foo 被覆盖而 A::foo 是最终覆盖函数
    void bar() final; // 错误： bar 非虚，因此它不能是 final 的
};

struct B final : A // struct B 为 final
{
    void foo() override; // 错误：foo 不能被覆盖，因为它在 A 中是 final 的
};

struct C : B // 错误：B 是 final 的
{
};

可能的输出：

main.cpp:9:10: 错误：'void A::bar()' 标记为 'final'，但不是虚函数
    9 |     void bar() final; // 错误： bar 非虚，因此它不能是 final 的
      |          ^~~
main.cpp:14:10: 错误：虚函数 'virtual void B::foo()' 覆盖 final 函数
   14 |     void foo() override; // 错误：foo 不能被覆盖，因为它在 A 中是 final 的
      |          ^~~
main.cpp:8:10: 注意：函数 'virtual void A::foo()' 被覆盖
    8 |     void foo() final; // Base::foo 被覆盖而 A::foo 是最终覆盖函数
      |          ^~~
main.cpp:17:8: 错误：不能在派生类型 'C' 中派生自 'final' 基类 'B'
   17 | struct C : B // 错误：B 是 final 的
      |

参阅

override 说明符 (C++11) 显式说明方法覆盖另一方法


浮点字面量

< cpp‎ | language

浮点字面量定义了其值于源文件中指定的编译时常量。

语法

数字序列 十进制指数 后缀(可选) | (1) |
数字序列 . 十进制指数(可选) 后缀(可选) | (2) |
数字序列(可选) . 数字序列 十进制指数(可选) 后缀(可选) | (3) |
0x | 0X 十六进制数字序列 十六进制指数 后缀(可选) | (4) | (C++17 起)
0x | 0X 十六进制数字序列 . 十六进制指数 后缀(可选) | (5) | (C++17 起)
0x | 0X 十六进制数字序列(可选) . 十六进制数字序列 十六进制指数 后缀(可选) | (6) | (C++17 起)
1) 数字序列 表示无小数点的整数，此时指数不是可选的：1e10、1e-5L
2) 数字序列 表示带小数点的整数，此时指数是可选的：1.、1.e-2
3) 数字序列 表示小数。指数是可选的：3.14、.1f、0.1e-1L
4) 十六进制 数字序列 表示无基底分隔符的整数。十六进制浮点字面量的指数总是必选的：0x1ffp10、0X0p-1
5) 十六进制 数字序列 表示带基底分隔符的整数。十六进制浮点字面量的指数总是必选的：0x1.p0、0xf.p-1
6) 十六进制 数字序列 表示带基底分隔符的小数。十六进制浮点字面量的指数总是必选的：0x0.123p-1、0xa.bp10l

十进制指数 拥有下列形式

e | E 指数正负号(可选) 数字序列

十六进制指数 拥有下列形式

p | P 指数正负号(可选) 数字序列 (C++17 起)

指数正负号 若存在则为 + 或 -。

后缀 若存在，则为 f、F、l 或 L 之一。后缀决定浮点字面量的类型：

  • （无后缀）定义 double
  • f F 定义 float
  • l L 定义 long double

数位间可插入作为分隔符的单引号（'），在编译时忽略它们。

 (C++14 起)

解释

使用十进制科学计数法，表示浮点字面量的值是有效数字乘以 10 的 十进制指数 次幂。例如 123e4 的数学含义是 123×104。

若浮点字面量以字符序列 0x 或 0X 开始，则该浮点字面量是十六进制浮点字面量。否则，它是十进制浮点字面量。

对于十六进制浮点字面量，其有效数字被解释为十六进制有理数，而指数的 数字序列 被解释成有效数字要放大的 2 的整数幂次。

double d = 0x1.4p3; // 十六进制分数 1.4（十进制 1.25）的 2^3 倍，即 10.0
 (C++17 起)

注解

虽然十六进制浮点字面量直到 C++17 才成为（标准）C++ 的一部分，但是从 C++11 开始它们已经可以通过输入/输出函数被解析和打印：开启 std::hexfloat 的 C++ 输入/输出流和 C 输入/输出流：std::printf，std::scanf 等。格式描述请参考 std::strtof。

示例

#include <iostream>
int main()
{
  std::cout << 58.         << '\n'
            << 4e2         << '\n'
            << 123.456e-67 << '\n'
            << .1E4f       << '\n'
            << 0x10.1p0    << '\n';
            << 0x1e5       << '\n'; // 整数字面量，非浮点字面量
}

输出：

58
400
1.23456e-65
1000
16.0625
485

参阅

用户定义字面量 (C++11) 拥有用户定义后缀的字面量


折叠表达式(C++17 起)

< cpp‎ | language

以二元运算符对形参包进行规约（折叠）。

语法

( 形参包 运算符 ... ) | (1)
( ... 运算符 形参包 ) | (2)
( 形参包 运算符 ... 运算符 初值 ) | (3)
( 初值 运算符 ... 运算符 形参包 ) | (4)
1) 一元右折叠
2) 一元左折叠
3) 二元右折叠
4) 二元左折叠
运算符 | - | 任何下列 32 个二元运算符之一：+ - * / % ^ & | = < > << >> += -= *= /= %= ^= &= |= <<= >>= == != <= >= && || , .* ->*。在二元折叠中，两个 运算符 必须相同。
形参包 | - | 含有未展开的形参包且在顶层不含优先级低于转型（正式而言，是 转型表达式）的运算符的表达式
初值 | - | 不含未展开的形参包且在顶层不含优先级低于转型（正式而言，是 转型表达式）的运算符的表达式

注意开闭括号也是折叠表达式的一部分。

解释

折叠表达式的实例化按以下方式展开成表达式 e：

1) 一元右折叠 (E 运算符 ...) 成为 (E1 运算符 (... 运算符 (EN-1 运算符 EN)))
2) 一元左折叠 (... 运算符 E) 成为 (((E1 运算符 E2) 运算符 ...) 运算符 EN)
3) 二元右折叠 (E 运算符 ... 运算符 I) 成为 (E1 运算符 (... 运算符 (EN−1 运算符 (EN 运算符 I))))
4) 二元左折叠 (I 运算符 ... 运算符 E) 成为 ((((I 运算符 E1) 运算符 E2) 运算符 ...) 运算符 EN)

（其中 N 是包展开中的元素数量）

例如，

template<typename... Args>
bool all(Args... args) { return (... && args); }

bool b = all(true, true, true, false);
 // 在 all() 中，一元左折叠展开成
 // return ((true && true) && true) && false;
 // b 是 false

将一元折叠用于长度为零的包展开时，只能使用下列运算符：

1) 逻辑与（&&）。空包的值为 true
2) 逻辑或（||）。空包的值为 false
3) 逗号运算符（,）。空包的值为 void()

注解

如果用作 初值 或 形参包 的表达式在顶层具有优先级低于转型的运算符，那么它可以加括号：

template<typename ...Args>
int sum(Args&&... args)
{
//  return (args + ... + 1 * 2);   // 错误：优先级低于转型的运算符
    return (args + ... + (1 * 2)); // OK
}

示例

#include <iostream>
#include <vector>
#include <climits>
#include <cstdint>
#include <type_traits>
#include <utility>

template<class ...Args>
void printer(Args&&... args)
{
    (std::cout << ... << args) << '\n';
}

template<class T, class... Args>
void push_back_vec(std::vector<T>& v, Args&&... args)
{
    static_assert((std::is_constructible_v<T, Args&> && ...));
    (v.push_back(args), ...);
}

// 基于 http://stackoverflow.com/a/36937049 的编译期端序交换
template<class T, std::size_t... N>
constexpr T bswap_impl(T i, std::index_sequence<N...>)
{
    return (((i >> N*CHAR_BIT & std::uint8_t(-1)) << (sizeof(T)-1-N)*CHAR_BIT) | ...);
}

template<class T, class U = std::make_unsigned_t<T>>
constexpr U bswap(T i)
{
    return bswap_impl<U>(i, std::make_index_sequence<sizeof(T)>{});
}

int main()
{
    printer(1, 2, 3, "abc");

    std::vector<int> v;
    push_back_vec(v, 6, 2, 45, 12);
    push_back_vec(v, 1, 2, 9);
    for (int i : v) std::cout << i << ' ';

    static_assert(bswap<std::uint16_t>(0x1234u)==0x3412u);
    static_assert(bswap<std::uint64_t>(0x0123456789abcdefULL)==0xefcdab8967452301ULL);
}

输出：

123abc
6 2 45 12 1 2 9


for 循环

< cpp‎ | language

执行一次 初始化语句，然后重复执行 语句 和 迭代表达式，直到 条件 的值变成 false。每次迭代前都进行该检测。

语法

正式语法：
属性(可选) for ( 初始化语句 条件(可选) ; 迭代表达式(可选) ) 语句
非正式语法：
属性(可选) for ( 声明或表达式(可选) ; 声明或表达式(可选) ; 表达式(可选) ) 语句
属性 - (C++11 起) 任意数量的属性
初始化语句 - 下列之一：
  • 一条表达式语句（可以是空语句“;”）
  • 一条简单声明，通常是带初始化器的循环计数变量的声明，但它可以声明任意多个变量或结构化绑定 (C++17 起)
  • 一条别名声明
 (C++23 起)
注意任何 初始化语句 必须以分号 ; 结束，因此它经常被非正式描述为后随分号的表达式或声明。
条件 - 下列之一：
  • 可以按语境转换到 bool 的表达式。在每次重复之前对此表达式求值，且如果它产生 false 则退出循环。
  • 带有花括号或等号初始化器的单一变量声明。初始化器在每次重复之前求值，且如果被声明变量的值转换为 false，那么退出循环。
迭代表达式 - 任意表达式，在循环的每次重复之后并在重复求值 条件 之前求值。通常是增加循环计数器的表达式。
语句 - 任意语句，通常是复合语句，作为循环体

解释

上述语法产生的代码等价于：

{
初始化语句
while ( 条件 ) {
语句
迭代表达式 ;
}

}

但有以下不同：

1) 初始化语句 声明的名字（如果 初始化语句 是声明）和 条件 声明的名字（如果 条件 是声明）处于同一作用域中（也是 语句 的作用域）。
2) 语句 中的 continue 将执行 迭代表达式
3) 空的 条件 等价于 while(true)

如果执行循环时需要在某些点终止，那么可以将 break 语句用作终止语句。

如果执行循环时需要在循环体末尾继续，那么可以将 continue 语句用作捷径。

与 while 循环的情况相同，如果 语句 是单个语句（非复合语句），那么声明于其中的变量的作用域被限制在循环体内，如同一条复合语句。

for (;;)
    int n;
// n 离开作用域

关键词

for

注解

作为 C++ 向前进展保证的一部分，如果没有可观察行为（不调用 I/O 函数，访问 volatile 对象，或进行原子或同步操作）的循环不会终止，那么它的行为未定义。编译器可以移除这种循环。

C++ 中，初始化语句 的作用域与 语句 的作用域一致，而在 C 中 语句 的作用域嵌套于 初始化语句 的作用域中：

for (int i = 0; ; ) {
    long i = 1;   // 在 C 中合法，在 C++ 中非法
    // ...
}

示例

#include <iostream>
#include <vector>

int main()
{
    // 典型的以单语句作为循环体的循环
    for (int i = 0; i < 10; ++i)
        std::cout << i << ' ';
    std::cout << '\n';

    // 初始化语句可以声明多个名字，
    // 只要它们可以使用相同的声明说明符序列
    for (int i = 0, *p = &i; i < 9; i += 2) {
        std::cout << i << ':' << *p << ' ';
    }
    std::cout << '\n';

    // （循环）条件可以是声明
    char cstr[] = "Hello";
    for (int n = 0; char c = cstr[n]; ++n)
        std::cout << c;
    std::cout << '\n';

    // 初始化语句可以使用 auto 类型说明符
    std::vector<int> v = {3, 1, 4, 1, 5, 9};
    for (auto iter = v.begin(); iter != v.end(); ++iter) {
        std::cout << *iter << ' ';
    }
    std::cout << '\n';

   // 初始化语句可以是表达式
    int n = 0;
    for (std::cout << "循环开始\n";
         std::cout << "循环测试\n";
         std::cout << "迭代 " << ++n << '\n')
        if(n > 1)
            break;
    std::cout << '\n';
}

输出：

0 1 2 3 4 5 6 7 8 9
0:0 2:2 4:4 6:6 8:8
Hello
3 1 4 1 5 9
循环开始
循环测试
迭代 1
循环测试
迭代 2
循环测试

参阅

范围 for 循环 (C++11) 执行范围上的循环


友元声明

< cpp‎ | language

友元声明在类体内出现，并向一个函数或另一个类授予对包含友元声明的类的私有及受保护成员的访问权。

语法

friend 函数声明 | (1) |
friend 函数定义 | (2) |
friend 详述类说明符 ; | (3) |
friend 简单类型说明符 ; friend typename-说明符 ; | (4) | (C++11 起)

描述

1) 指明一个或多个函数为此类的友元：
class Y {
    int data; // 私有成员
    // 非成员函数的运算符 operator<< 将拥有对 Y 的私有成员的访问权
    friend std::ostream& operator<<(std::ostream& out, const Y& o);
    friend char* X::foo(int); // 其他类的成员也可以是友元
    friend X::X(char), X::~X(); // 构造函数与析构函数也可以是友元
};
// 友元声明不声明成员函数
// 此 operator<< 作为非成员仍需定义
std::ostream& operator<<(std::ostream& out, const Y& y)
{
    return out << y.data; // 可访问私有成员 Y::data
}
2) （只允许在非局部类的定义中使用）定义一个非成员函数，同时令其为此类的友元。这种非成员函数始终是内联函数 ，除非它附着到一个具名模块 (C++20 起)。
class X {
    int a;
    friend void friend_set(X& p, int i) {
        p.a = i; // 这是非成员函数
    }
 public:
    void member_set(int i) {
        a = i; // 这是成员函数
    }
};
3) 指定以 详述类说明符（见详述类型说明符）指名的 class、struct 或 union 为此类的友元。这意味着该友元的各成员声明和定义可以访问此类的私有与受保护成员，而且该友元也能从此类的私有或受保护成员进行继承。 不需要提前声明用于此 friend 声明的类名。
4) 指定以 简单类型说明符 或 typename-说明符 指名的类型，如果该类型是（可有 cv 限定的）class、struct 或 union，那么该类型是此类的友元；否则忽略该 friend 声明。此声明不前置声明新类型。
class Y {};
class A {
    int data; // 私有数据成员
    class B { }; // 私有嵌套类型
    enum { a = 100 }; // 私有枚举项
    friend class X; // 友元类的前置声明（详述类型说明符）
    friend Y; // 友元类声明（简单类型说明符） (C++11 起)
};

class X : A::B // OK：友元能访问 A::B
{
    A::B mx; // OK：友元的成员能访问 A::B
    class Y {
        A::B my; // OK：友元的嵌套成员能访问 A::B
    };
    int v[A::a]; // OK：友元的成员能访问 A::a
};

注解

友元关系不传递（你朋友的朋友不是你的朋友）。

友元关系不继承（你朋友的孩子不是你的朋友）。

友元函数声明中不允许使用存储类说明符。在友元声明中定义的函数具有外部链接，先前已定义的函数保持其定义时所具有的链接。

访问说明符对于友元声明的含义没有影响（它们可以在 private: 或 public: 区间出现，且没有区别）。

友元类声明不能定义新的类（friend class X {}; 是错的）。

当局部类将一个无限定的函数或类声明为其友元时，只查找在其最内层非类作用域中的函数与类，而非全局函数：

class F {};
int f();
int main()
{
    extern int g();
    class Local { // main() 函数中的局部类
        friend int f(); // 错误，main() 中没有声明该函数
        friend int g(); // OK，main() 中有 g 的声明
        friend class F; // 令局部 F（随后定义）为友元
        friend class ::F; // 令全局 F 为友元
    };
    class F {}; // 局部 F
}

首次在类或类模板 X 中的友元声明中被声明的名字会成为 X 的最内层外围命名空间的成员，但它对于查找不可见（除了考虑 X 的实参依赖查找），除非在该命名空间作用域中提供与之匹配的声明——细节见命名空间。

模板友元

函数模板与类模板声明，都可带 friend 说明符出现于任何非局部类或类模板内（尽管只有函数模板能在授予友元关系的类或类模板内进行定义）。这种情况下，该模板的每个特化都成为友元，不管是被隐式实例化、部分特化或显式特化。

class A {
    template<typename T>
    friend class B; // 每个 B<T> 都是 A 的友元

    template<typename T>
    friend void f(T) {} // 每个 f<T> 都是 A 的友元
};

友元声明不能指代部分特化，但能指代全特化：

template<class T> class A {}; // 主模板
template<class T> class A<T*> {}; // 部分特化
template<> class A<int> {}; // 全特化
class X {
    template<class T> friend class A<T*>; // 错误！
    friend class A<int>; // OK
};

当友元声明指代函数模板的全特化时，不能使用关键词 inline 和默认实参：

template<class T> void f(int);
template<> void f<int>(int);

class X {
    friend void f<int>(int x = 1); // 错误：不允许默认实参
};

模板友元声明可以指名类模板 A 的成员，它可以是成员函数或成员类型（类型必须用详述类型说明符）。这种声明只有在它的 嵌套名说明符 中的最后组分（最后的 :: 左边的名字）是一个指名该类模板的 简单模板标识（模板名后随角括号包围的实参列表）时才是良构的。这种模板友元声明的模板形参必须能从该 简单模板标识 推导。

此时 A 的任何特化的成员都会成为友元。这不并涉及对主模板 A 的实例化：只要求从该特化推导 A 的模板形参成功，以及将推导出的模板实参替换到友元声明中所产生的声明，是该特化的成员的合法声明：

// 主模板
template<class T>
struct A {
  struct B { };
  void f();
  struct D { void g(); };
  T h();
  template<T U> T i();
};
// 全特化
template<>
struct A<int> {
  struct B { };
  int f();
  struct D { void g(); };
  template<int U> int i();
};
// 另一全特化
template<>
struct A<float*> {
    int *h();
};
// 非模板类向类模板 A 的成员授予友元关系
class X {
  template<class T>
  friend struct A<T>::B; // 所有的 A<T>::B 都是友元，包括 A<int>::B

  template<class T>
  friend void A<T>::f();  // A<int>::f() 不是友元，因为其签名不匹配，
                          // 但比如 A<char>::f() 则是友元

//  template<class T>
//  friend void A<T>::D::g(); // 非良构：嵌套名说明符的最后部分，
//                            // A<T>::D:: 中 的 D，不是简单模板标识

  template<class T>
  friend int* A<T*>::h();  // 所有的 A<T*>::h 都是友元：A<float*>::h()、A<int*>::h() 等

  template<class T>
  template<T U>       // A<T>::i() 的所有实例化和 A<int>::i() 都是友元，
  friend T A<T>::i(); // 从而这些函数模板的所有特化都是
};

只有在模板友元声明是定义，且此翻译单元不出现此函数模板的其他声明时，该声明中才允许使用默认模板实参。

 (C++11 起)

模板友元运算符

模板友元的一种常见使用场合是作用于类模板上的非成员运算符重载的声明，例如针对某个用户定义的 Foo<T> 的 operator<<( std::ostream &, const Foo<T>&)。

这种运算符可以在类体内定义，效果是对每个 T 生成独立的非模板 operator<<，并使该非模板 operator<< 为其 Foo<T> 的友元：

#include <iostream>

template<typename T>
class Foo {
 public:
    Foo(const T& val) : data(val) {}
 private:
    T data;

    // 为这个 T 生成非模板 operator<<
    friend std::ostream& operator<<(std::ostream& os, const Foo& obj)
    {
        return os << obj.data;
    }
};

int main()
{
    Foo<double> obj(1.23);
    std::cout << obj << '\n';
}

输出：

1.23

否则，函数模板需要类体之前声明为模板，这种情况下 Foo<T> 内的友元声明可以涉指 operator<< 对其 T 的全特化：

#include <iostream>

template<typename T>
class Foo; // 前置声明，以确保函数声明可行

template<typename T> // 声明
std::ostream& operator<<(std::ostream&, const Foo<T>&);

template<typename T>
class Foo {
 public:
    Foo(const T& val) : data(val) {}
 private:
    T data;

    // 涉指对于这个特定的 T 的全特化
    friend std::ostream& operator<< <> (std::ostream&, const Foo&);
    // 注意：这依赖于声明中的模板实参推导
    // 也可以通过 operator<< <T> 指定模板实参
};

// 定义
template<typename T>
std::ostream& operator<<(std::ostream& os, const Foo<T>& obj)
{
    return os << obj.data;
}

int main()
{
    Foo<double> obj(1.23);
    std::cout << obj << '\n';
}

示例

流插入与提取运算符往往声明为非成员友元：

#include <iostream>
#include <sstream>

class MyClass {
    int i;

    friend std::ostream& operator<<(std::ostream& out, const MyClass& o);
    friend std::istream& operator>>(std::istream& in, MyClass& o);
 public:
    MyClass(int i = 0) : i(i) {}
};

std::ostream& operator<<(std::ostream& out, const MyClass& mc)
{
    return out << mc.i;
}

std::istream& operator>>(std::istream& in, MyClass& mc)
{
    return in >> mc.i;
}

int main()
{
    MyClass mc(7);
    std::cout << mc << '\n';
    std::istringstream("100") >> mc;
    std::cout << mc << '\n';
}

输出：

7
100

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 45 | C++98 | T 的友元类的嵌套类的成员对 T 没有特殊访问权 | 嵌套类拥有和外围类相同的访问权
CWG 500 | C++98 | T 的友元类不能继承自 T 的私有与受保护成员，但其嵌套类可以 | 都可以继承自此类成员

引用

  • C++11 标准（ISO/IEC 14882:2011）：
  • 11.3 Friends [class.friend]
  • 14.5.4 Friends [temp.friend]
  • C++98 标准（ISO/IEC 14882:1998）：
  • 11.3 Friends [class.friend]
  • 14.5.3 Friends [temp.friend]

参阅

类类型 | 定义保有数个数据成员的类型
访问说明符 | 定义类成员的可见性


函数 try 块

< cpp‎ | language

建立围绕整个函数体的异常处理块。

语法

函数 try 块是一种 函数体 的替代语法形式，它是函数定义的一部分。

try 构造函数初始化器(可选) 复合语句 处理块序列
构造函数初始化器 | - | 成员初始化器列表，只能用于构造函数
复合语句 | - | 花括号环绕的语句序列，它组成函数体
处理块序列 | - | 一或多个 catch 子句的序列

解释

函数 try 块将一系列 catch 子句与整个函数体，以及成员初始化器列表（如果用于构造函数）关联起来。从函数体中的任何语句，或（对于构造函数）从任何成员或基类的构造函数，或（对于析构函数）从任何成员或基类的析构函数中抛出的所有异常，以与常规 try 块中抛出的异常时相同方式，将控制转移到 处理块序列 中。

#include <iostream>
#include <string>

struct S {
    std::string m;
    S(const std::string& str, int idx) try : m(str, idx) {
        std::cout << "S(" << str << ", " << idx << ") 构造完成，m = " << m << '\n';
    } catch(const std::exception& e) {
        std::cout << "S(" << str << ", " << idx << ") 失败：" << e.what() << '\n';
    } // 此处有隐含的 "throw;"
};

int main() {
    S s1{"ABC", 1}; // 不抛出（索引在范围内）
    try {
        S s2{"ABC", 4}; // 抛出（越界）
    } catch (std::exception& e) {
        std::cout << "S s2... 抛出了一个异常：" << e.what() << '\n';
    }
}

在进入任何构造函数上的函数 try 块的 catch 子句前，所有完整构造的成员和基类都会被销毁。

如果函数 try 块在委托构造函数上，而它调用的非委托构造函数成功完成，但之后该委托构造函数的函数体抛出了异常，那么此对象的析构函数将在进入函数 try 块的任何 catch 子句之前完成。

 (C++11 起)

在进入析构函数上的函数 try 块的任何 catch 子句之前，所有基类和非变体成员均已被销毁。

如果用于构造函数或析构函数上的函数 try 块的 catch 子句访问了基类或对象的非静态成员，那么行为未定义。

构造函数的函数 try 块中的每个 catch 子句都必须以抛异常终止。如果控制抵达这种异常处理的尾部，那么当前异常被如同用 throw; 来自动重抛。在构造函数的函数 try 块的任何 catch 子句中都不能使用 return 语句。

抵达析构函数的函数 try 块的 catch 子句末尾，也如同用 throw; 来自动重抛当前异常，但可以使用 return 语句。

对于所有其他函数，如果函数返回类型是（可有 cv 限定的）void，那么抵达 catch 子句末尾等价于 return;，否则行为未定义。

注解

函数 try 块的主要目的是应对从构造函数中的成员初始化器列表抛出的异常，进行记录并重抛，修改异常对象并重抛，抛出一个不同的异常，或终止程序。析构函数或常规函数很少用到它们。

函数 try 块不会捕获从按值传递的函数形参的复制/移动构造函数和析构函数中抛出的异常：这些异常是在调用方的语境抛出的。

线程的顶层函数的函数 try 块不会捕获从线程局部对象的构造函数和析构函数（但除了函数作用域的线程局域对象的构造函数）中抛出的异常。

 (C++11 起)

类似地，main() 函数的函数 try 块不会捕获从静态对象的构造函数和析构函数（但除了函数局域静态对象的构造函数）中抛出的异常。

函数形参（但并非在函数自身中声明的任何对象）的作用域和生存期延续到 处理块序列 的结尾。

int f(int n = 2) try {
   ++n; // 使函数形参自增
   throw n;
} catch(...) {
   ++n; // n 处于作用域中且仍然指代函数形参
   assert(n == 4);
   return n;
}


函数声明

< cpp‎ | language

函数声明引入函数名及其类型。函数定义将函数名/类型与函数体关联。

函数声明

函数声明可出现于任何作用域。在类作用域中的函数声明引入成员函数（除非使用 friend 说明符），细节见成员函数和友元函数。

被声明的函数类型由返回类型（return type）（由声明语法的 声明说明符序列 提供）和函数声明符（声明符）组成。

非指针声明符 ( 形参列表 ) cv限定符(可选) 引用限定符(可选) 异常说明(可选) 属性(可选) | (1) |
非指针声明符 ( 形参列表 ) cv限定符(可选) 引用限定符(可选) 异常说明(可选) 属性(可选) -> 尾随返回类型 | (2) | (C++11 起)

（声明符 语法的其他形式见声明页面）

1) 常规函数声明语法
2) 尾随返回类型声明：尾随返回类型只能在最外层函数声明符中使用。此时 声明说明符序列 必须包含关键词 auto
非指针声明符 - 任何合法的 声明符，但如果它以 *、& 或 && 开始，那么它必须被括号环绕。
形参列表 - 函数形参的逗号分隔列表，可以为空（细节见下文）
属性 - (C++11 起) 以逗号分隔且可以为空的属性列表。这些属性应用于函数类型，而非函数自身。在声明符中标识符之后出现的属性与有可能在声明开端出现的属性合并，如果存在。
cv限定符 - const/volatile 限定，只允许在非静态成员函数中使用
引用限定符 - (C++11 起) 引用限定，只允许在非静态成员函数中使用
异常说明 -
动态异常说明 | (C++11 前)
动态异常说明或 noexcept 说明之一 | (C++11 起) (C++17 前)
noexcept 说明 | (C++17 起)

注意，异常说明不是函数类型的一部分。 (C++17 前)
尾随返回类型 - (C++11 起)尾随返回类型，当返回类型取决于实参名时，例如 template <class T, class U> auto add(T t, U u) -> decltype(t + u);，或当返回类型复杂时，例如在 auto fpif(int)->int(*)(int) 中，尾随返回类型很有用

如声明页面所示，声明符可以后随 requires 子句，它声明与该函数关联的制约，而重载决议所要选择的函数必须满足该制约。（例如 void f1(int a) requires true;）注意，关联的制约是函数签名的一部分，但不是函数类型的一部分。

 (C++20 起)

只要 声明说明符序列 允许，函数声明符就可以和其他声明符混合：

// 声明一个 int、一个 int*、一个函数，及一个函数指针
int a = 1, *p = NULL, f(), (*pf)(double);
// 声明说明符序列 是 int
// 声明符 f() 声明（但不定义）一个不接受实参并返回 int 的函数

struct S
{
    virtual int f(char) const, g(int) &&; // 声明两个非静态成员函数
    virtual int f(char), x; // 编译时错误：（声明说明符序列中的）virtual
                            // 只能声明非静态成员函数
};

以 volatile 限定的对象类型作为形参类型或返回类型是被弃用的。

 (C++20 起)

函数的返回类型不能是函数类型或数组类型（但可以是到它们的指针或引用）。

与任何声明相同，声明前出现的属性和声明符中直接跟在标识符之后的属性都会应用到所声明或定义的实体（在这个例子中，应用到函数）：

[[noreturn]] void f [[noreturn]] (); // OK：两个属性都应用到函数 f

然而，（按上述语法）在声明符后出现的属性会应用到函数类型而非函数自身：

void f() [[noreturn]]; // 错误：此属性对函数自身没有影响
 (C++11 起)

与任何声明相同，ret func(params) 所声明的函数 func 的类型为 ret(params)（但适用下文所述的形参类型重编）：参见 类型的命名。

返回类型推导

如果函数声明的 声明说明符序列 包含关键词 auto，那么尾随返回类型可以省略，且编译器将从返回语句中所用的表达式的类型推导出它。如果返回类型没有使用 decltype(auto)，那么推导遵循模板实参推导的规则进行。

int x = 1;
auto f() { return x; }        // 返回类型是 int
const auto& f() { return x; } // 返回类型是 const int&

如果返回类型是 decltype(auto)，那么返回类型是将返回语句中所用的表达式包裹到 decltype 中时所得到的类型：

int x = 1;
decltype(auto) f() { return x; }  // 返回类型是 int，同 decltype(x)
decltype(auto) f() { return(x); } // 返回类型是 int&，同 decltype((x))

（注意：“const decltype(auto)&”是错误的，decltype(auto) 必须独自使用）

如果有多条返回语句，那么它们必须推导出相同的类型：

auto f(bool val)
{
    if(val) return 123;   // 推导返回类型 int
    else return 3.14f;    // 错误：推导返回类型 float
}

如果没有返回语句或返回语句的实参是 void 表达式，那么所声明的返回类型，必须要么是 decltype(auto)，此时推导返回类型是 void，要么是（可有 cv 限定的）auto，此时推导的返回类型则是（相同 cv 限定的）void。

auto f() {}              // 返回 void
auto g() { return f(); } // 返回 void
auto* x() {}             // 错误: 不能从 void 推导 auto*

一旦在函数中见到一条返回语句，那么从该语句推导的返回类型就可以用于函数的剩余部分，包括其他返回语句：

auto sum(int i)
{
    if(i == 1)
        return i;              // sum 的返回类型是 int
    else
        return sum(i - 1) + i; // OK，sum 的返回类型已知
}

如果返回语句使用花括号初始化器列表（brace-init-list），那么不允许推导：

auto func () { return {1, 2, 3}; } // 错误

虚函数 与协程 (C++20 起)不能使用返回类型推导：

struct F
{
    virtual auto f() { return 2; } // 错误
};

如果函数使用返回类型推导，那么它不能用其推导的类型或其他种类的返回类型推导再声明，即使推导出来的类型相同：

auto f();               // 已声明，未定义
auto f() { return 42; } // 已定义，返回类型是 int
int f();                // 错误：不能使用推导的类型
decltype(auto) f();     // 错误：不同种类的推导
auto f();               // OK：再声明

template<typename T>
struct A { friend T frf(T); };
auto frf(int i) { return i; } // 不是 A<int> 的友元

除了用户定义转换函数以外的函数模板可以使用返回类型推导。即使返回语句中的表达式并非待决，推导也在实例化时发生。这种实例化并不处于 SFINAE 的目的的立即语境中。

template<class T> auto f(T t) { return t; }
typedef decltype(f(1)) fint_t;    // 实例化 f<int> 以推导返回类型
template<class T> auto f(T* t) { return *t; }
void g() { int (*p)(int*) = &f; } // 实例化两个 f 以确定返回类型，
                                  // 选择第二个模板重载

使用返回类型推导的函数模板特化必须使用同一返回类型占位符：

template<typename T> auto g(T t) { return t; } // #1
template auto g(int);      // OK，返回类型是 int
//template char g(char);   // 错误，没有匹配的模板

template<> auto g(double); // OK，用未知返回类型的前置声明
template<typename T> T g(T t) { return t; } // OK，不等价于 #1
template char g(char);     // OK，现在有匹配的模板
template auto g(float);    // 仍然匹配 #1
// void h() { return g(42); } // 错误，歧义

显式实例化声明本身并不实例化使用返回类型推导的函数模板：

template<typename T> auto f(T t) { return t; }
extern template auto f(int); // 不实例化 f<int>
int (*p)(int) = f; // 实例化 f<int> 以确定其返回类型，
                   // 但仍需要在程序的别处出现显式实例化的定义
 (C++14 起)

形参列表

形参列表决定调用函数时所能指定的实参。它是形参声明的逗号分隔列表，其中每一项拥有下列语法：

属性(可选) 声明说明符序列 声明符 | (1)
属性(可选) 声明说明符序列 声明符 = 初始化器 | (2)
属性(可选) 声明说明符序列 抽象声明符(可选) | (3)
属性(可选) 声明说明符序列 抽象声明符(可选) = 初始化器 | (4)
void | (5)
1) 声明一个具名（形式）参数。声明说明符序列 和 声明符 的含义见声明页面。
int f(int a, int *p, int (*(*x)(double))[3]);
2) 声明一个带有默认值的具名（形式）参数。
int f(int a = 7, int *p = nullptr, int (*(*x)(double))[3] = nullptr);
3) 声明一个无名形参。
int f(int, int *, int (*(*)(double))[3]);
4) 声明一个具有默认值的无名形参。
int f(int = 7, int * = nullptr, int (*(*)(double))[3] = nullptr);
5) 指示函数不接受形参，它是空参数列表的确切同义词：int f(void); 和 int f(); 声明同一函数。注意类型 void（可以有 cv 限定）不能在其他情况下用于参数列表：int f(void, int); 和 int f(const void); 是错误的（但可以使用其衍生类型，如 void*）。在模板中，只能使用非待决的 void（当以 T = void 实例化时，采用单个 T 类型的形参的函数不会成为无形参函数）。

省略号 ... 可出现于形参列表末尾；这声明一个变参函数（variadic function）：

int printf(const char* fmt ...);

为了与 C89 兼容，当形参列表含有至少一个形参时，省略号前可以出现一个逗号：

int printf(const char* fmt, ...); // OK，同上

尽管 声明说明符序列 蕴含了可以存在类型说明符之外的说明符，但其他可用的说明符只有 register 和 auto (C++11 前)，而且它没有任何效果。

 (C++17 前)

如果任何函数形参使用了占位符（placeholder）（auto 或 概念（concept）类型），那么函数声明转变为简写函数模板声明：

void f1(auto);    // 同 template<class T> void f(T)
void f2(C1 auto); // 如果 C1 是概念，同 template<C1 T> void f7(T)
 (C++20 起)

在函数声明中声明的形参名通常只用作以自身为文档。它们在函数定义中被使用（但仍不强制）。

形参列表中的每个函数形参的类型根据下列规则确定：

1) 首先，以如同在任何声明中的方式，组合声明说明符序列和声明符以确定其类型。
2) 如果类型是“T 的数组”或“T 的未知边界数组”，那么它被替换成类型“T 的指针”
3) 如果类型是函数类型 F，那么它被替换成类型“F 的指针”
4) 从形参类型中丢弃顶层 cv 限定符（此调整只影响函数类型，但不改动形参的性质：int f(const int p, decltype(p)*); 和 int f(int, const int*); 声明同一函数）

因为这些规则，下列函数声明确切地声明同一函数：

int f(char s[3]);
int f(char[]);
int f(char* s);
int f(char* const);
int f(char* volatile s);

下列声明也确切地声明同一函数：

int f(int());
int f(int (*g)());

形参类型不能是含有到未知边界数组的引用或指针的类型，含有这种类型的多级指针/数组，或含有指向以这些类型为形参的函数的指针。

指示可变实参的省略号前不需要有逗号，即使它跟随指示形参包展开的省略号，所以下列函数模板是确切相同的：

template<typename ...Args> void f(Args..., ...);
template<typename ...Args> void f(Args... ...);
template<typename ...Args> void f(Args......);

使用这种声明的例子之一是 std::is_function 的实现。

 (C++11 起)

函数定义

非成员函数的定义只能出现在命名空间作用域中（不存在嵌套函数）。成员函数的定义亦可出现在类定义的体内。它们拥有下列语法：

属性(可选) 声明说明符序列(可选) 声明符 虚声明符序列(可选) 函数体

其中 函数体 是下列之一：

构造函数初始化器(可选) 复合语句 | (1) |
函数-try-块 | (2) |
= delete ; | (3) | (C++11 起)
= default ; | (4) | (C++11 起)
1) 常规函数体
2) 函数 try 块（这是包装在 try/catch 块内的常规函数体）
3) 显式弃置的函数定义
4) 显式预置的函数定义，只能用于特殊成员函数 和比较运算符函数 (C++20 起)
属性 | - | (C++11 起) 以逗号分隔且可以为空的属性列表。这些属性与可能出现在 声明符 中标识符之后的属性结合（见本页顶部）。
声明说明符序列 | - | 带有说明符的返回类型，与声明文法相同
声明符 | - | 函数声明符，与上述函数声明文法相同。和函数声明一样，它可以后随 requires-子句 (C++20 起)
虚说明符序列 | - | (C++11 起) override、final，或它们任意顺序的组合（仅对非静态成员函数允许）
构造函数初始化器 | - | 成员初始化器列表，只能用于构造函数
复合语句 | - | 花括号环绕的语句序列，它们构成函数体
int max(int a, int b, int c)
{
    int m = (a > b)? a : b;
    return (m > c)? m : c;
}
// 声明说明符序列 是“int”
// 声明符是“max(int a, int b, int c)”
// 函数体是 { ... }

函数体是一条复合语句（由一对花括号环绕的零或多条语句），它们在函数调用时被执行。

函数的各个形参类型和返回类型不能是不完整的 类类型，除非函数已显式定义为被弃置 (C++11 起)。完整性检查在函数体的语境中进行，这允许成员函数返回在其中定义它们的类（或其外围类），尽管在定义点它可能不完整（它在函数体内完整）。

在函数定义的 声明符 中声明的形参在函数体内处于作用域中。如果某个形参没有在函数体中使用，那么它不需要具名（只需要使用抽象声明符）

void print(int a, int) // 没有使用第二个形参
{
    std::printf("a = %d\n",a);
}

尽管形参上的顶层 cv 限定符在函数声明中被忽略，它们仍然会修饰形参的类型，这在函数体中可见：

void f(const int n) // 声明 void(int) 类型的函数
{
    // 但在体内，n 的类型是 const int
}

弃置函数

如果使用特殊语法 = delete ;取代函数体，那么该函数被定义为弃置的（deleted）。任何弃置函数的使用都是非良构的（程序无法编译）。这包含调用，包括显式（以函数调用运算符）及隐式（对弃置的重载运算符、特殊成员函数、分配函数等的调用），构成指向弃置函数的指针或成员指针，甚至是在不求值表达式中使用弃置函数。但是，允许隐式 ODR 式使用 刚好被弃置的非纯虚成员函数。

如果函数被重载，那么首先进行重载决议，且仅当选择了弃置函数时程序才非良构。

struct sometype
{
    void* operator new(std::size_t) = delete;
    void* operator new[](std::size_t) = delete;
};
sometype* p = new sometype; // 错误：尝试调用弃置的 sometype::operator new

函数的弃置定义必须是翻译单元中的首条声明：已经声明过的函数不能声明为弃置的：

struct sometype { sometype(); };
sometype::sometype() = delete; // 错误：必须在首条声明弃置

__func__

在函数体内，如同以如下方式定义了函数局部的预定义变量 __func__

static const char __func__[] = "函数名";

此变量具有块作用域及静态存储期：

struct S
{
    S(): s(__func__) {} // OK：初始化器列表是函数体的一部分
    const char* s;
};
void f(const char* s = __func__); // 错误：形参列表是声明符的一部分
 (C++11 起)

注解

在使用直接初始化语法的变量声明和函数声明之间有歧义的情况下，编译器选择函数声明；见直接初始化页面。

示例

本节未完成
原因：移动/清理
#include <iostream>
#include <string>

// 命名空间（文件）作用域中的声明
// （定义在后面提供）
int f1();

// 拥有默认实参的简单函数，不返回内容
void f0(const std::string& arg = "world")
{
    std::cout << "Hello, " << arg << '\n';
}

// 返回指向 f0 的指针的函数
auto fp11() -> void(*)(const std::string&)
{
    return f0;
}

// 返回指向 f0 的指针的函数，C++11 前的风格
void (*fp03())(const std::string&)
{
    return f0;
}

int main()
{
    f0();
    fp11()("test");
    fp03()("again");
    int f2(std::string); // 块作用域中的声明
    std::cout << f2("bad12") << '\n';
}

// 简单的非成员函数，返回 int
int f1()
{
    return 42;
}

// 拥有异常说明和函数 try 块的函数
int f2(std::string str) noexcept try
{
    return std::stoi(str);
}
catch(const std::exception& e)
{
    std::cerr << "stoi() 失败！\n";
    return 0;
}

输出：

Hello, world
Hello, test
Hello, again
stoi() 失败！
0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 393 | C++98 | 含有到未知边界数组的指针/引用的类型不能作为形参 | 允许这些类型
CWG 577 | C++98 | 待决类型 void 可用于声明无形参函数 | 只允许非待决的 void
CWG 1394 | C++11 | 弃置函数不能返回不完整类型 | 允许不完整的返回类型

参阅


函数模板

< cpp‎ | language

函数模板定义一族函数。

语法

template < 形参列表 > 函数声明 | (1) |
template < 形参列表 > requires 约束 函数声明 | (2) | (C++20 起)
带占位符函数声明 | (3) | (C++20 起)
export template < 形参列表 > 函数声明 | (4) | (C++11 前)

解释

形参列表 | - | 非空的模板形参的逗号分隔列表，每项是非类型形参、类型形参、模板形参或这些的形参包之一。与任何模板一样，形参可以受约束。 (C++20 起)
函数声明 | - | 函数声明。所声明的函数名成为模板名。
约束 | - | 约束表达式，它限制此函数模板接受的模板形参。
带占位符函数声明 | - | 函数声明，其中至少一个形参的类型使用了占位符 auto 或 概念 auto：每个占位符都会对应模板形参列表中的一个虚设形参。（见下文“简写函数模板”）

export 是一个可选的修饰符，它声明模板被导出（用于类模板时，它声明所有成员被导出）。对被导出模板进行实例化的文件不需要包含它的定义：声明就足够了。export 的实现稀少而且在细节上相互不一致。

 (C++11 前)

简写函数模板

当函数声明或函数模板声明的形参列表中出现占位符类型（auto 或 概念 auto）时，该声明会声明一个函数模板，并且为每个占位符向模板形参列表追加一个虚设的模板形参：

void f1(auto); // 与 template<class T> void f(T) 相同
void f2(C1 auto); // 如果 C1 是概念，那么与 template<C1 T> void f2(T) 相同
void f3(C2 auto...); // 如果 C2 是概念，那么与 template<C2... Ts> void f3(Ts...) 相同
void f4(const C3 auto*, C4 auto&); // 与 template<C3 T, C4 U> void f4(const T*, U&); 相同
template <class T, C U>
void g(T x, U y, C auto z); // 与 template<class T, C U, C W> void g(T x, U y, W z); 相同

简写函数模板可以和所有函数模板一样进行特化。

template<>
void f4<int>(const int*, const double&); // f4<int, const double> 的特化

 (C++20 起)

函数模板实例化

函数模板自身并不是类型、函数或任何其他实体。不会从只包含模板定义的源文件生成任何代码。模板只有实例化才会有代码出现：必须确定各模板实参，使得编译器能生成实际的函数（或从类模板生成类）。

显式实例化

template 返回类型 名字 < 实参列表 > ( 形参列表 ) ; | (1) |
template 返回类型 名字 ( 形参列表 ) ; | (2) |
extern template 返回类型 名字 < 实参列表 > ( 形参列表 ) ; | (3) | (C++11 起)
extern template 返回类型 名字 ( 形参列表 ) ; | (4) | (C++11 起)
1) 显式实例化定义（显式指定所有无默认值模板形参时不会推导模板实参）
2) 显式实例化定义，对所有形参进行模板实参推导
3) 显式实例化声明（显式指定所有无默认值模板形参时不会推导模板实参）
4) 显式实例化声明，对所有形参进行模板实参推导

显式实例化定义强制实例化它所指代的函数或成员函数。它可以出现在程序中模板定义后的任何位置，而对于给定的实参列表，它在整个程序中只能出现一次，不要求诊断。

显式实例化声明（extern 模板）阻止隐式实例化：本来会导致隐式实例化的代码必须改为使用已在程序的别处所提供的显式实例化。

 (C++11 起)

在函数模板特化或成员函数模板特化的显式实例化中，尾部的各模板实参在能从函数参数推导时不需要指定：

template<typename T>
void f(T s)
{
    std::cout << s << '\n';
}

template void f<double>(double); // 实例化 f<double>(double)
template void f<>(char);         // 实例化 f<char>(char)，推导出模板实参
template void f(int);            // 实例化 f<int>(int)，推导出模板实参

函数模板或类模板成员函数的显式实例化不能使用 inline 或 constexpr。如果显式实例化的声明指名了某个隐式声明的特殊成员函数，那么程序非良构。

构造函数的显式实例化不能使用模板形参列表（语法 (1)），也始终不需要使用，因为能推导它们（语法 (2)）。

预期的析构函数的显式实例化必须指名该类的被选择的析构函数。

 (C++20 起)

显式实例化声明不会抑制 inline 函数，auto 声明，引用，以及类模板特化的隐式实例化。（从而当作为显式实例化声明目标的 inline 函数被 ODR 式使用时，它会为内联而隐式实例化，但此翻译单元中不会生成它的非内联副本）

带有默认实参的函数模板的显式实例化定义不会使用或试图初始化该实参：

char* p = 0;
template<class T> T g(T x = &p) { return x; }
template int g<int>(int); // OK，即使 &p 不是 int。

隐式实例化

当代码在要求存在函数定义的语境中指涉某个函数，或定义存在与否会影响程序语义 (C++11 起)，而这个特定函数尚未被显式实例化时，发生隐式实例化。如果模板实参列表能从语境推导，那么不必提供它。

#include <iostream>

template<typename T>
void f(T s)
{
    std::cout << s << '\n';
}

int main()
{
    f<double>(1); // 实例化并调用 f<double>(double)
    f<>('a');     // 实例化并调用 f<char>(char)
    f(7);         // 实例化并调用 f<int>(int)
    void (*pf)(std::string) = f; // 实例化 f<string>(string)
    pf("∇");                     // 调用 f<string>(string)
}

如果有表达式需要某函数进行常量求值，那么函数定义存在与否会影响程序语义，即使不要求常量求值表达式，或常量表达式求值不使用该定义。

template<typename T> constexpr int f() { return T::value; }
template<bool B, typename T> void g(decltype(B ? f<T>() : 0));
template<bool B, typename T> void g(...);
template<bool B, typename T> void h(decltype(int{B ? f<T>() : 0}));
template<bool B, typename T> void h(...);
void x() {
  g<false, int>(0); // OK： B ? f<T>() : 0 不会潜在常量求值
  h<false, int>(0); // 错误：即使 B 求值为 false 且从 int 到 int 的列表初始化不可能是窄化
                    // 仍实例化 f<int>
}
 (C++11 起)

注意：完全省略 <> 允许重载决议同时检验模板与非模板重载。

模板实参推导

实例化一个函数模板需要知道它的所有模板实参，但不需要指定每个模板实参。编译器会尽可能从函数实参推导缺失的模板实参。这会在尝试进行函数调用以及取函数模板的地址时发生。

template<typename To, typename From> To convert(From f);

void g(double d)
{
    int i = convert<int>(d);    // 调用 convert<int,double>(double)
    char c = convert<char>(d);  // 调用 convert<char,double>(double)
    int(*ptr)(float) = convert; // 实例化 convert<int, float>(float)
}

模板运算符依赖此机制，因为除了将它重写为函数调用表达式之外，不存在为运算符指定模板实参的语法。

#include <iostream>
int main()
{
    std::cout << "Hello, world" << std::endl;
    // operator<< 经由 ADL 查找为 std::operator<<，
    // 然后推导出 operator<<<char, std::char_traits<char>>
    // 同时推导 std::endl 为 &std::endl<char, std::char_traits<char>>
}

模板实参推导在函数模板的名字查找（可能涉及实参依赖查找）之后，重载决议之前进行。

细节见模板实参推导。

显式模板实参

函数模板的模板实参可从以下途径获得：

  • 模板实参推导
  • 默认模板实参
  • 显式指定，可以在下列语境中进行：
  • 在函数调用表达式中
  • 当取函数地址时
  • 当初始化到函数的引用时
  • 当构成成员函数指针时
  • 在显式特化中
  • 在显式实例化中
  • 在友元声明中

不存在为重载的运算符、转换函数和构造函数显式指定模板实参的方法，因为它们不会通过函数名调用。

所指定的各模板实参必须与各模板形参在种类上相匹配（即类型对类型，非类型对非类型，模板对模板）。实参的数量不能多于形参（除非形参中有形参包，这种情况下每个非包形参必须对应一个实参）。

所指定的非类型实参必须要么与其对应的非类型模板形参的类型相匹配，要么可以转换到这些类型。

不参与模板实参推导的函数实参（例如对应的模板实参已经被显式指定）会参与到它对应的函数形参的类型的隐式转换（如在通常重载决议中一样）。

当有额外的实参时，模板实参推导可以扩充显式指定的模板形参包：

template<class ... Types> void f(Types ... values);
void g() {
  f<int*, float*>(0, 0, 0); // Types = {int*, float*, int}
}

模板实参替换

当已经指定、推导出或从默认模板实参获得了所有的模板实参之后，函数形参列表中对模板形参的每次使用都会被替换成对应的模板实参。

函数模板在替换失败时（即以推导或提供的模板实参替换模板形参失败）会从重载集中移除。这样就有许多方式通过模板元编程来操作重载集：细节见 SFINAE。

替换之后，所有数组和函数类型的函数形参都被调整为指针，且所有函数形参都会移除顶层 cv 限定（如在常规函数声明中一样）。

移除顶层 cv 限定并不会影响形参在函数内展现的类型：

template <class T> void f(T t);
template <class X> void g(const X x);
template <class Z> void h(Z z, Z* zp);

// 两个不同的函数的类型相同，但 t 在这些函数中有不同的 cv 限定
f<int>(1);       // 函数类型是 void(int)，t 是 int
f<const int>(1); // 函数类型是 void(int)，t 是 const int

// 两个不同的函数的类型和 x 相同
// （指向这两个函数的指针不相等，且函数局部的静态变量可以拥有不同地址）
g<int>(1);       // 函数类型是 void(int)，x 是 const int
g<const int>(1); // 函数类型是 void(int)，x 是 const int

// 只移除顶层 cv 限定：
h<const int>(1, NULL); // 函数类型是 void(int, const int*)
                       // z 是 const int，zp 是 int*

函数模板重载

函数模板与非模板函数可以重载。

非模板函数与具有相同类型的模板特化始终不同。即使具有相同类型，不同函数模板的特化也始终互不相同。两个具有相同返回类型和相同形参列表的函数模板是不同的，而且可以用显式模板实参列表进行区分。

当使用了类型或非类型模板形参的表达式在函数形参列表或返回类型中出现时，该表达式会为了重载而保留为函数模板签名的一部分：

template<int I, int J> A<I+J> f(A<I>, A<J>); // 重载 #1
template<int K, int L> A<K+L> f(A<K>, A<L>); // 同 #1
template<int I, int J> A<I-J> f(A<I>, A<J>); // 重载 #2

对于两个涉及模板形参的表达式，如果两个包含这些表达式的函数定义根据 单一定义规则相同，那么称它们等价，就是说，除了模板形参的命名可以不同之外，这两个表达式含有相同的记号序列，其中的各个名字通过名字查找都解析到相同的实体。两个 lambda 表达式始终不等价。 (C++20 起)

template <int I, int J> void f(A<I+J>);  // 模板重载 #1
template <int K, int L> void f(A<K+L>);  // 等价于 #1

在确定两个待决表达式是否等价时，只考虑其中所涉及的各待决名，而不考虑名字查找的结果。如果相同模板的多个声明在名字查找的结果上有所不同，那么使用它们中的第一个：

template <class T> decltype(g(T())) h();  // decltype(g(T())) 是待决类型
int g(int);
template <class T> decltype(g(T())) h() { // h() 的再声明使用较早的查找，
    return g(T());                        // 尽管此处的查找找到了 g(int)
}
int i = h<int>(); // 模板实参替换失败；g(int) 不在 h() 的首个声明处的作用域中

当满足下列条件时，认为两个函数模板等价：

  • 它们在同一作用域声明
  • 它们具有相同的名字
  • 它们拥有等价的模板形参列表，意思是列表长度相同，且每对对应的形参均满足下列条件：
  • 两个形参的种类相同（都是类型、都是非类型或都是模板），
  • 它们都是形参包或都不是，
  • 如果是非类型，那么它们的类型等价，
  • 如果是模板，那么它们的模板形参等价，
  • 如果有一个声明带概念名，那么另一个也有等价的概念名。
 (C++20 起)
  • 它们的返回类型和形参列表中所有涉及模板实参的表达式均等价
  • 模板形参列表之后的 requires 子句（如果存在）中的各个表达式均等价
  • 函数声明符之后的 requires 子句（如果存在）中的各个表达式均等价
 (C++20 起)

对于两个涉及模板形参的表达式，如果它们不等价但它们对于任何给定的模板实参集的求值都产生相同的值，那么称它们功能等价。

如果两个函数模板本来可以等价，但它们的返回类型和形参列表中一或多个涉及模板形参的表达式功能等价，那么称它们功能等价。

另外，如果为两个函数模板指定的约束不同，但它们接受且被相同的模板实参列表的集合所满足，那么它们功能等价但不等价。

 (C++20 起)

如果程序含有功能等价但不等价的函数模板声明，那么程序非良构；不要求诊断。

// 等价
template <int I> void f(A<I>, A<I+10>); // 重载 #1
template <int I> void f(A<I>, A<I+10>); // 重载 #1 的再声明

// 不等价
template <int I> void f(A<I>, A<I+10>); // 重载 #1
template <int I> void f(A<I>, A<I+11>); // 重载 #2

// 功能等价但不等价
// 程序非良构，不要求诊断
template <int I> void f(A<I>, A<I+10>);      // 重载 #1
template <int I> void f(A<I>, A<I+1+2+3+4>); // 功能等价

当同一个函数模板特化与多于一个重载的函数模板相匹配时（这通常由模板实参推导所导致），执行重载函数模板的偏序处理以选择最佳匹配。

具体而言，在以下情形中发生偏序处理：

1) 对函数模板特化的调用的重载决议：
template<class X> void f(X a);
template<class X> void f(X* a);
int* p;
f(p);
2) 取函数模板特化的地址时：
template<class X> void f(X a);
template<class X> void f(X* a);
void (*p)(int*) = &f;
3) 选择作为函数模板特化的布置 operator delete 以匹配布置 operator new 时：
本节未完成
原因：小示例
4) 当友元函数声明、显式实例化或显式特化指代函数模板特化时：
template<class X> void f(X a);  // 第一个模板 f
template<class X> void f(X* a); // 第二个模板 f
template<> void f<>(int *a) {}  // 显式特化
// 模板实参推导出现两个候选：
// f<int*>(int*) 与 f<int>(int*)
// 偏序选择 f<int>(int*)，因为它更特殊

非正式而言，“A 比 B 更特殊”意味着“A 比 B 接受更少的类型”。

正式而言，为确定任意两个函数模板中哪个更特殊，偏序处理首先对两个模板之一进行以下变换：

  • 对于每个类型、非类型及模板形参，包括形参包，生成一个唯一的虚构类型、值或模板，并将其替换到模板的函数类型中
  • 如果要比较的两个函数模板中只有一个是成员函数，且该函数模板是某个类 A 的非静态成员，那么向它的形参列表的开头插入一个新的形参，当成员函数模板有 && 限定时，它的类型是 cv A&&，否则是 cv A&（其中 cv 是成员函数模板的 cv 限定）——这有助于对运算符的定序，它们是同时作为成员和非成员函数查找的：
struct A {};
template<class T> struct B {
  template<class R> int operator*(R&);            // #1
};
template<class T, class R> int operator*(T&, R&); // #2
int main() {
  A a;
  B<A> b;
  b * a; // 模板实参推导对于 int B<A>::operator*(R&) 给出 R=A
         //           对于 int operator*(T&, R&)，T=B<A>，R=A
// 为进行偏序处理，将成员 template B<A>::operator*
// 变换成 template<class R> int operator*(B<A>&, R&);
//     int operator*(   T&, R&)  T=B<A>, R=A
// 与  int operator*(B<A>&, R&)  R=A 间的偏序
// 选择 int operator*(B<A>&, A&) 为更特殊者

在按上方描述变换两个模板之一后，以变换后的模板为实参模板，以另一模板的原模板类型为形参模板，执行模板实参推导。然后以第二个模板（进行变换后）为实参，以第一个模板的原始形式为形参重复这一过程。

用于确定顺序的类型取决于语境：

  • 在函数调用的语境中，这些类型是在这个函数调用中具有实参的函数形参的类型（不考虑默认函数实参、形参包和省略号形参——见下文）
  • 在调用用户定义的转换函数的语境中，使用转换函数模板的返回类型
  • 在其他语境中，使用函数模板类型

形参模板中的每个以上列出的类型都会被推导。推导开始前，以下列方式对形参模板的每个形参 P 和实参模板的对应实参 A 进行调整：

  • 如果 P 与 A 此前都是引用类型，那么确定哪个有更多的 cv 限定（其他所有情况下，就偏序目的而言都忽略 cv 限定）
  • 如果 P 是引用类型，那么以它所引用的类型替换它
  • 如果 A 是引用类型，那么以它所引用的类型替换它
  • 如果 P 有 cv 限定，那么 P 被替换为自身的无 cv 限定版本
  • 如果 A 有 cv 限定，那么 A 被替换为自身的无 cv 限定版本

在这些调整后，遵循从类型进行模板实参推导规则，从 A 推导 P 。

如果 P 是函数形参包，那么实参模板的每个剩余形参类型的类型 A 都与该函数参数包的声明符标识的类型 P 进行比较。每次比较都为该函数参数包所展开的模板参数包中的后继位置的进行模板实参的推导。

如果 A 从函数参数包变换而来，那么将它与形参模板的每个剩余形参类型进行比较。

如果变换后的模板 1 的实参 A 可以用来推导模板 2 的对应形参 P，但反之不可，那么对于从这一对 P/A 所推导的类型而言，这个 A 比 P 更特殊。

如果双向推导均成功，且原 P 与 A 都是引用类型，那么做附加的测试：

  • 如果 A 是左值引用而 P 是右值引用，那么认为 A 比 P 更特殊
  • 如果 A 比 P 有更多的 cv 限定，那么认为 A 比 P 更特殊

所有其他情况下，对于这一对 P/A 所推导的类型而言，没有模板比另一个更特殊。

在以两个方向考虑每个 P 与 A 后，如果对于所考虑的每个类型，

  • 模板 1 对所有类型至少与模板 2 一样特殊
  • 模板 1 对某些类型比模板 2 特殊
  • 模板 2 对任何类型都不比模板 1 更特殊，或并非对任何类型都至少一样特殊

那么模板 1 比模板 2 更特殊。如果上述条件在切换模板顺序后为真，那么模板 2 比模板 1 更特殊。否则，没有模板比另一个更特殊。 持平的情况下，如果一个函数模板有一个尾部的形参包而另一个没有，那么认为带有被忽略的形参者比有空形参包者更特殊。

如果在考虑所有的重载模板对之后，有一个无歧义地比所有其他的都更特殊，那么选择这个模板的特化，否则编译失败。

在下列示例中，虚构实参被称为 U1, U2：

template<class T> void f(T);        // 模板 #1
template<class T> void f(T*);       // 模板 #2
template<class T> void f(const T*); // 模板 #3
void m() {
  const int* p;
  f(p); // 重载决议选取：#1：void f(T)  [T = const int *]
        // 　           #2：void f(T*) [T = const int]
        // 　           #3：void f(const T *) [T = int]
// 偏序处理
// 从变换后的 #2 到 #1：从 void(U1*) 到 void(T) ：P=T  A=U1*：推导成功：T=U1*
// 从变换后的 #1 到 #2：从 void(U1)  到 void(T*)：P=T* A=U1 ：推导失败
// 对于 T 而言 #2 比 #1 更特殊
// 从变换后的 #3 到 #1：从 void(const U1*) 到 void(T)：P=T, A=const U1*：成功
// 从变换后的 #1 到 #3：从 void(U1) 到 void(const T*)：P=const T*, A=U1：失败
// 对于 T 而言 #3 比 #1 更特殊
// 从变换后的 #3 到 #2：从 void(const U1*) 到 void(T*)：P=T* A=const U1*：成功
// 从变换后的 #2 到 #3：从 void(U1*) 到 void(const T*)：P=const T* A=U1*：失败
// 对于 T 而言 #3 比 #2 更特殊
// 结果：#3 被选择
// 换言之，f(const T*) 比 f(T) 或 f(T*) 更特殊
}
template<class T> void f(T, T*);   // #1
template<class T> void f(T, int*); // #2
void m(int* p) {
    f(0, p); // #1 的推导：void f(T, T*)   [T = int]
             // #2 的推导：void f(T, int*) [T = int]
// 偏序：
// 从 #2 到 #1：从 void(U1,int*) 到 void(T,T*)：
// P1=T    A1=U1  ：T=U1
// P2=T*   A2=int*：T=int：失败
// 从 #1 到 #2：从 void(U1, U2*) 到 void(T,int*)：
// P1=T    A1=U1  ：T=U1
// P2=int* A2=U2* ：失败
// 对于 T 而言没有更特殊的一方，调用有歧义
}
template<class T> void g(T);  // 模板 #1
template<class T> void g(T&); // 模板 #2
void m() {
  float x;
  g(x); // 从 #1 推导：void g(T)  [T = float]
        // 从 #2 推导：void g(T&) [T = float]
// 偏序：
// 从 #2 到 #1：从 void(U1&) 到 void(T)：
// P=T          A=U1（调整后）：成功
// 从 #1 到 #2：从 void(U1)  到 void(T&)：
// P=T（调整后） A=U1         ：成功
// 对于 T 而言没有更特殊的一方，调用有歧义
}
template<class T> struct A { A(); };

template<class T> void h(const T&); // #1
template<class T> void h(A<T>&);    // #2
void m() {
  A<int> z;
  h(z);  // 从 #1 推导：void h(const T&) [T = A<int>]
         // 从 #2 推导：void h(A<T>&)    [T = int]
// 偏序：
// 从 #2 到 #1：从 void(A<U1>&)    到 void(const T&)：
// P=T    A=A<U1>   ：成功 T=A<U1>
// 从 #1 到 #2：从 void(const U1&) 到 void(A<T>&)：
// P=A<T> A=const U1：失败
// 对于 T 而言 #2 比 #1 更特殊

  const A<int> z2;
  h(z2); // 从 #1 推导：void h(const T&) [T = A<int>]
         // 从 #2 推导：void h(A<T>&)    [T = int]，但替换失败
// 只有一个可选择的重载，不尝试偏序处理，调用 #1
}

因为在调用语境中只考虑有明确的调用实参的形参，所以没有明确的调用实参的形参，包括函数形参包、省略号形参及有默认实参的形参均被忽略：

template<class T> void f(T);         // #1
template<class T> void f(T*, int=1); // #2
void m(int* ip) {
  int* ip;
  f(ip); // 调用 #2（T* 比 T 更特殊）
}
template<class T> void g(T);       // #1
template<class T> void g(T*, ...); // #2
void m(int* ip) {
  g(ip); // 调用 #2（T* 比 T 更特殊）
}
template<class T, class U> struct A { };
template<class T, class U> void f(U, A<U,T>* p = 0); // #1
template<         class U> void f(U, A<U,U>* p = 0); // #2
void h() {
  f<int>(42, (A<int, int>*)0); // 调用 #2
  f<int>(42);                  // 错误：歧义
}
template<class T            > void g(T, T = T()); // #1
template<class T, class... U> void g(T, U...);    // #2
void h() {
  g(42); // 错误：歧义
}
template<class T, class... U> void f(T, U...); // #1
template<class T            > void f(T);       // #2
void h(int i) {
  f(&i); // 因为形参包与无形参之间的决胜规则调用 #2
         // （注意：在 DR692 与 DR1395 之间时有歧义）
}
template<class T, class... U> void g(T*, U...); // #1
template<class T            > void g(T);        // #2
void h(int i) {
  g(&i); // OK：调用 #1（T* 比 T 更特殊）
}
template <class ...T> int f(T*...);  // #1
template <class T>  int f(const T&); // #2
f((int*)0); // OK：选择 #2；非变参模板比变参模板更特殊
            // （DR1395 之前有歧义，因为两个方向的推导均失败）
template<class... Args>           void f(Args... args);        // #1
template<class T1, class... Args> void f(T1 a1, Args... args); // #2
template<class T1, class T2>      void f(T1 a1, T2 a2);        // #3
f();        // 调用 #1
f(1, 2, 3); // 调用 #2
f(1, 2);    // 调用 #3；非变参模板 #3 比变参模板 #1 与 #2 更特殊

在偏序处理内的模板实参推导期间，如果有实参不在任何被偏序考虑的类型中，那么不要求该实参与模板形参相匹配：

template <class T>          T f(int); // #1
template <class T, class U> T f(U);   // #2
void g() {
  f<int>(1); // #1 的特化为显式：T f(int) [T = int]
             // #2 的特化为推导：T f(U)   [T = int, U = int]
// 偏序（只考虑实参类型）：
// 从 #2 到 #1：从 U1(U2)  到 T(int)：失败
// 从 #1 到 #2：从 U1(int) 到 T(U)  ：成功：U=int, T 未使用
// 调用 #1
}

对包含模板形参包的函数模板进行的偏序处理，与为这些模板形参包所推导的实参数量无关。

template<class...> struct Tuple { };
template<          class... Types> void g(Tuple<Types ...>);      // #1
template<class T1, class... Types> void g(Tuple<T1, Types ...>);  // #2
template<class T1, class... Types> void g(Tuple<T1, Types& ...>); // #3

g(Tuple<>());            // 调用 #1
g(Tuple<int, float>());  // 调用 #2
g(Tuple<int, float&>()); // 调用 #3
g(Tuple<int>());         // 调用 #3

本节未完成
原因：14.8.3[temp.over]

为编译对函数模板的调用，编译器必须在非模板重载、模板重载和模板重载的特化间作出决定。

template<class T> void f(T);      // #1：模板重载
template<class T> void f(T*);     // #2：模板重载
void                   f(double); // #3：非模板重载
template<>        void f(int);    // #4：#1 的特化

f('a');        // 调用 #1
f(new int(1)); // 调用 #2
f(1.0);        // 调用 #3
f(1);          // 调用 #4

函数重载 vs 函数特化

注意，只有非模板和主模板重载参与重载决议。特化并不是重载，因此不受考虑。只有在重载决议选择最佳匹配的主函数模板后，才检验它的特化以查看最佳匹配者。

template<class T> void f(T);    // #1：所有类型的重载
template<>        void f(int*); // #2：#1 的特化，针对指向 int 的指针
template<class T> void f(T*);   // #3：所有指针类型的重载

f(new int(1)); // 调用 #3，虽然 #1 的特化是完美匹配

在对翻译单元的头文件进行排序时，记住此规则很重要。有关函数重载与函数特化之间的更多示例在下面展开：

首先考虑一些不使用实参依赖查找的场景。对于这种情况，我们使用调用 (f)(t)。如 ADL 中的描述，将函数名包在括号中可抑制实参依赖查找。

  • 在 g() 中声明的引用点之前的多个 f() 重载。
#include <iostream>
struct A{};
template<class T> void f(T)  {std::cout << "#1\n";} // 在 f() 的引用点前的重载 #1
template<class T> void f(T*) {std::cout << "#2\n";} // 在 f() 的引用点前的重载 #2
template<class T> void g(T* t)
{
    (f)(t); // f() 的引用点
}

int main()
{
    A *p = nullptr;
    g(p);   // g() 和 f() 的引用点
}

// #1 与 #2 都被添加到候选列表；
// 选择 #2 因为它是更好的匹配。

输出：

#2

  • 匹配较好的模板重载在引用点之后声明。
#include <iostream>
struct A{};
template<class T> void f(T)  {std::cout << "#1\n";} // #1
template<class T> void g(T* t)
{
    (f)(t); // f() 的引用点
}
template<class T> void f(T*) {std::cout << "#2\n";} // #2

int main()
{
    A *p = nullptr;
    g(p);   // g() 和 f() 的引用点
}

// 只有 #1 会添加到到候选列表；#2 在引用点之后定义；
// 因此，即使它是较佳匹配，重载也不会考虑它。

输出：

#1

  • 匹配较好的显式模板特化在引用点之后声明。
#include <iostream>
struct A{};
template<class T> void f(T)    {std::cout << "#1\n";} // #1
template<class T> void g(T* t)
{
    (f)(t); // f() 的引用点
}
template<>        void f<>(A*) {std::cout << "#3\n";} // #3

int main()
{
    A *p = nullptr;
    g(p);   // g() 和 f() 的引用点
}

// 添加 #1 到候选列表；#3 是在引用点后定义的较好匹配。候选列表由最终被选择的 #1 组成。
// 之后，在引用点后声明的 #1 的显式特化 #3 被选择，因为它是较好的匹配。
// 此行为由 14.7.3/6 [temp.expl.spec] 掌控且与 ADL 无关。

输出：

#3

  • 匹配较好的模板重载在引用点之后声明。匹配最佳的显式模板特化在这个较好的匹配重载之后声明。
#include <iostream>
struct A{};
template<class T> void f(T)    {std::cout << "#1\n";} // #1
template<class T> void g(T* t)
{
    (f)(t); // f() 的引用点
}
template<class T> void f(T*)   {std::cout << "#2\n";} // #2
template<>        void f<>(A*) {std::cout << "#3\n";} // #3

int main()
{
    A *p = nullptr;
    g(p);   // g() 和 f() 的引用点
}

// #1 是候选列表的唯一成员且它最终被选择。
// 之后，跳过显式特化 #3，因为它实际特化了在引用点后声明的 #2。

输出：

#1

现在让我们考虑使用实参依赖查找的情况（即我们用更常见的调用格式 f(t)）。

  • 匹配较好的模板重载在引用点之后声明。
#include <iostream>
struct A{};
template<class T> void f(T)  {std::cout << "#1\n";} // #1
template<class T> void g(T* t)
{
    f(t); // f() 的引用点
}
template<class T> void f(T*) {std::cout << "#2\n";} // #2

int main()
{
    A *p = nullptr;
    g(p); // g() 和 f() 的引用点
}

// #1 被作为常规查找的结果添加到候选列表；
// #2 在引用点之后定义但经由 ADL 查找添加到候选列表。
// #2 作为较好的匹配被选择。

输出：

#2

  • 匹配较好的模板重载在引用点之后声明。匹配最佳的显式模板特化在这个匹配较好的重载之前声明。
#include <iostream>
struct A{};
template<class T> void f(T)    {std::cout << "#1\n";} // #1
template<class T> void g(T* t)
{
    f(t); // f() 的引用点
}
template<>        void f<>(A*) {std::cout << "#3\n";} // #3
template<class T> void f(T*)   {std::cout << "#2\n";} // #2

int main()
{
    A *p = nullptr;
    g(p); // g() 和 f() 的引用点
}

// #1 被作为常规查找的结果添加到候选列表；
// #2 在引用点之后定义但经由 ADL 查找添加到候选列表。
// 作为较好的匹配，从各主模板中选择 #2。
// 因为 #3 在 #2 之前声明，所以它是 #1 的显式特化。
// 从而最终选择 #2。

输出：

#2

  • 匹配较好的模板重载在引用点之后声明，匹配最佳的显式模板特化最后声明。
#include <iostream>
struct A{};
template<class T> void f(T)    {std::cout << "#1\n";} // #1
template<class T> void g(T* t)
{
    f(t); // f() 的引用点
}
template<class T> void f(T*)   {std::cout << "#2\n";} // #2
template<>        void f<>(A*) {std::cout << "#3\n";} // #3

int main()
{
    A *p = nullptr;
    g(p); // g() 和 f() 的引用点
}

// #1 被作为常规查找的结果添加到候选列表；
// #2 在引用点之后定义但经由 ADL 查找添加到候选列表。
// 作为较好的匹配，从各主模板中选择 #2。
// 因为 #3 在 #2 之后声明，所以它是 #2 的显式特化；
// 从而被选为调用的函数。

输出：

#3

当实参是一些 C++ 基础类型时，没有 ADL 关联的命名空间。因此这些场景与上述非 ADL 示例等同。

有关重载决议的详细规则，见重载决议。

函数模板特化

本节未完成
原因：14.8[temp.fct.spec] (note that 14.8.1[temp.arg.explicit] 已在全特化专题：要么让函数特化到这里：缺少部分特化、与函数重载的交互，或仅引用那边

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 581 | C++98 | 允许构造函数模板的显式特化或实例化中的模板形参列表 | 已禁止
CWG 1321 | C++98 | 不明确首个声明与重声明中的相同待决名是否等价 | 它们等价并且含义与首个声明中的相同
CWG 1395 | C++11 | 从形参包推导 A 时失败，且对于空形参包没有决胜规则 | 允许推导，添加决胜规则

参阅

  • 类模板
  • 函数声明


函数

< cpp‎ | language

函数（function）是把一个语句序列（函数体, function body）关联到一个名字和零或更多个函数形参（function parameter）的列表的 C++ 实体。

// 函数名：“isodd”
// 形参列表拥有一个形参，具有名字 “n” 和类型 int
// 返回类型是 bool
bool isodd(int n)
{                      // 函数体开始
    return n % 2;
}                      // 函数体结束

调用函数时，例如在函数调用表达式中，以各个实参（argument）（可由调用场所提供，或者默认）来初始化各个形参，然后执行函数体中的语句。如果一个函数的形参列表以 ... 结尾，那么额外的实参可以提供给该函数，这样的函数被称为变参函数。

int main()
{
    for(int arg : {-3, -2, -1, 0, 1, 2, 3})
        std::cout << isodd(arg) << ' '; // isodd 被调用 7 次，
                                        // 每次从 arg 复制初始化 n
}

函数调用表达式中无限定的函数名会以一组额外的规则查找，它被称为“实参依赖查找”（argument-dependent lookup/ADL）。

函数可以通过返回或者抛出 异常终止。

函数可以是协程。协程可以暂停执行，以在之后恢复执行。

 (C++20 起)

函数声明可以在任何作用域中出现，但函数定义只能在命名空间作用域出现，或对于成员和友元函数，可以在类作用域中出现。在类体中声明而不带 friend 说明符的函数是类成员函数。这种函数拥有许多附加性质，细节见成员函数。

函数不是对象：不存在函数的数组，而且函数不能按值传递或被其他函数所返回。可以有指向/到除主函数以外的所有函数 (C++20 前)所有非标准库函数和几个标准库函数 (C++20 起)的指针和引用，它们可以用于这些函数自身无法被使用的地方。因此我们说这些函数“可取址”。

每个函数都具有一个类型，它由函数的返回类型，所有形参的类型（进行数组到指针和函数到指针转换后，见形参列表），函数是否为 noexcept (C++17 起)，以及对于非静态成员函数的 cv 限定性和引用限定性 (C++11 起)构成。函数类型同样拥有语言链接。不存在有 cv 限定的函数类型（不要与如 int f() const; 这样的 cv 限定函数类型，或如 std::string const f(); 这样的返回 cv 限定类型的函数相混淆）。如果有任何 cv 限定符被添加到到函数类型的别名，那么它会被忽略。

可以用 lambda 表达式产生无名函数。

 (C++11 起)

同一作用域中，可以有多个函数拥有相同的名称，只要其形参列表，以及对于非静态成员函数的 cv 或引用 (C++11 起)限定不同即可。这被称作函数重载。只有返回类型及 noexcept 说明 (C++17 起)不同的函数声明之间无法重载。重载函数的地址有专门的确定方法。

函数对象

除了函数左值，函数调用表达式还支持函数指针以及重载了函数调用运算符及可转换为函数指针的任何类类型的值（包括 lambda 表达式） (C++11 起)。这些类型被统称为函数对象 (FunctionObject) ，而且在 C++ 标准库中的各处都有使用，示例可见二元谓词 (BinaryPredicate) 和比较 (Compare) 的用法。

标准库也提供数个预定义的函数对象模板，以及一些组成新函数对象的方法（包括 std::less、std::mem_fn、std::bind 和 std::function (C++11 起)）。


goto 语句

< cpp‎ | language

无条件转移控制流。

当使用其他语句不可能将控制转移到所需位置时使用。

语法

属性(可选) goto 标号 ;

解释

goto 语句将控制转移到标号所指定的位置。goto 语句必须与它所用的 标号 处于相同的函数中，它在标号的前后都可以出现。

如果控制的转移退出了任何自动变量的作用域（例如通过回跳到这种变量声明之前的位置，或向前跳出作为变量作用域的复合语句），那么为所有退出作用域的变量以其构造顺序的逆序调用析构函数。

goto 不能将控制转移到 try 块或 catch 子句之内，但能将控制转移离开 try 块或 catch 子句（遵循上述有关作用域中的自动变量的规则）

如果控制被转移进入了任何自动变量的作用域（例如通过向前跳过声明语句），那么程序非良构（不能编译），除非进入作用域的所有变量拥有

1) 标量类型，且声明不带初始化器
2) 拥有平凡默认构造函数和析构函数的类类型，且声明不带初始化器
3) 上述之一的 cv 限定版本
4) 上述之一的数组

（注意：相同规则适用于控制转移的所有形式）

关键词

goto

注意

在 C 编程语言中，goto 语句的限制较少，并且能进入除变长数组或可变修改指针之外的任何变量的作用域。

示例

#include <iostream>

struct Object {
    // 非平凡析构函数
    ~Object() { std::cout << "d"; }
};

struct Trivial {
    double d1;
    double d2;
}; // 平凡构造函数与析构函数

int main()
{
    int a = 10;

    // 使用 goto 循环
label:
    Object obj;
    std::cout << a << " ";
    a = a - 2;

    if (a != 0) {
        goto label;  // 跳出 obj 的作用域，调用 obj 析构函数
    }
    std::cout << '\n';

    // goto 可用于简单地离开多层循环
    for (int x = 0; x < 3; x++) {
        for (int y = 0; y < 3; y++) {
            std::cout << "(" << x << ";" << y << ") " << '\n';
            if (x + y >= 3) {
                goto endloop;
            }
        }
    }
endloop:
    std::cout << '\n';

    goto label2; // 跳入 n 和 t 的作用域
    int n; // 没有初始化器
    Trivial t; // 平凡构造函数/析构函数，没有初始化器
//  int x = 1; // 错误：有初始化器
//  Object obj2; // 错误：没有平凡析构函数
label2:

    {
        Object obj3;
        goto label3; // 向前跳，离开 obj3 的作用域
    }
label3: ;

}

输出：

10 d8 d6 d4 d2
(0;0)
(0;1)
(0;2)
(1;0)
(1;1)
(1;2)

dd

扩展阅读

Edsger W. Dijkstra 的著名文章《我认为 goto 有害》，呈现了此关键词的大意使用会引入的各种微妙问题的考察。

参阅


C++ 的历史

< cpp‎ | language

早期 C++

  • 1979：首次实现“带类的 C（C with Classes）”
  1. 新特性：类，成员函数，派生类，分离编译，公开与私有访问控制，友元，函数实参的类型检查，默认实参，内联函数，重载赋值运算符，构造函数，析构函数，f() 与 f(void) 相同，调用的函数与返回的函数（同步特性，不在 C++ 中）
  2. 库：并发任务库（不在 C++ 中）
  • 1982：出版 C with Classes 参考手册
  • 1984：实现 C84，出版参考手册
  • 1985：Cfront 1.0
  1. 新特性：虚函数，函数与运算符的重载，引用， new 和 delete 运算符， const 关键词，作用域解析运算符
  2. 库添加：复数，字符串，输入/输出流
  • 1985：《C++ 程序设计语言》（The C++ Programming Language），第1版
  • 1986："whatis?" 提案将剩余的设计目标写入文档，包含多继承，异常处理和模板。
  • 1987：GCC 1.15.3 中加入 C++ 支持
  • 1989：Cfront 2.0
  1. 新特性：多继承，成员指针，受保护访问，类型安全的连接，抽象类，静态和 const 限定的成员函数，类特有的 new 和 delete
  2. 库添加：输入/输出操纵符
  • 1990：《带标注的 C++ 参考手册》（The Annotated C++ Reference Manual）

此书按设计描述语言，包含一些仍未实现的特性。它在 ISO 标准前作为事实标准。

  1. 新特性：命名空间，异常处理，嵌套类，模板
  • 1991：Cfront 3.0
  • 1991：《C++ 程序设计语言》（The C++ Programming Language），第2版

标准 C++

  • 1990 ANSI C++ 委员会成立
  • 1991 ISO C++ 委员会成立
  • 1992 STL 以 C++ 实现

C++98/03 时期

  • 1998 C++98 (ISO/IEC 14882:1998)
  1. 新特性：RTTI（dynamic_cast、typeid），协变返回类型，转型运算符，mutable，bool，条件中的声明，模板实例化，成员模板，export
  2. 库添加：本地环境，bitset，valarray，auto_ptr，以及模板化的字符串，输入/输出流和复数。
  3. 基于 STL：容器，算法，迭代器，函数对象
  • 1998 《C++ 程序设计语言》（The C++ Programming Language），第3版
  • 1999 委员会成员成立 Boost 以为标准产生高质量的候选库。
  • 2003 C++03（ISO/IEC 14882:2003）

这是一个次要版本，有意稍多于一个技术更正版本

  1. 新特性：值初始化
C++03 中修正的缺陷报告（核心 92 个，库 125 个）
  • CWG#1
  • CWG#20
  • CWG#21
  • CWG#22
  • CWG#24
  • CWG#25
  • CWG#30
  • CWG#32
  • CWG#33
  • CWG#35
  • CWG#38
  • CWG#40
  • CWG#41
  • CWG#43
  • CWG#48
  • CWG#49
  • CWG#51
  • CWG#52
  • CWG#53
  • CWG#56
  • CWG#59
  • CWG#64
  • CWG#65
  • CWG#67
  • CWG#68
  • CWG#69
  • CWG#73
  • CWG#74
  • CWG#75
  • CWG#76
  • CWG#80
  • CWG#83
  • CWG#84
  • CWG#85
  • CWG#89
  • CWG#90
  • CWG#93
  • CWG#94
  • CWG#98
  • CWG#100
  • CWG#101
  • CWG#103
  • CWG#105
  • CWG#108
  • CWG#116
  • CWG#120
  • CWG#121
  • CWG#123
  • CWG#126
  • CWG#127
  • CWG#128
  • CWG#131
  • CWG#134
  • CWG#135
  • CWG#137
  • CWG#142
  • CWG#145
  • CWG#147
  • CWG#148
  • CWG#149
  • CWG#151
  • CWG#152
  • CWG#153
  • CWG#159
  • CWG#161
  • CWG#163
  • CWG#164
  • CWG#166
  • CWG#171
  • CWG#173
  • CWG#176
  • CWG#178
  • CWG#179
  • CWG#181
  • CWG#183
  • CWG#185
  • CWG#187
  • CWG#188
  • CWG#190
  • CWG#193
  • CWG#194
  • CWG#202
  • CWG#206
  • CWG#210
  • CWG#213
  • CWG#217
  • CWG#227
  • CWG#235
  • CWG#241
  • CWG#249
  • CWG#250
  • CWG#304
  • LWG#1
  • LWG#3
  • LWG#5
  • LWG#7
  • LWG#8
  • LWG#9
  • LWG#11
  • LWG#13
  • LWG#14
  • LWG#15
  • LWG#16
  • LWG#17
  • LWG#18
  • LWG#19
  • LWG#20
  • LWG#21
  • LWG#22
  • LWG#24
  • LWG#25
  • LWG#26
  • LWG#27
  • LWG#28
  • LWG#29
  • LWG#30
  • LWG#31
  • LWG#32
  • LWG#33
  • LWG#34
  • LWG#35
  • LWG#36
  • LWG#37
  • LWG#38
  • LWG#39
  • LWG#40
  • LWG#41
  • LWG#42
  • LWG#46
  • LWG#47
  • LWG#48
  • LWG#50
  • LWG#51
  • LWG#52
  • LWG#53
  • LWG#54
  • LWG#55
  • LWG#56
  • LWG#57
  • LWG#59
  • LWG#60
  • LWG#61
  • LWG#62
  • LWG#63
  • LWG#64
  • LWG#66
  • LWG#68
  • LWG#69
  • LWG#70
  • LWG#71
  • LWG#74
  • LWG#75
  • LWG#78
  • LWG#79
  • LWG#80
  • LWG#83
  • LWG#86
  • LWG#90
  • LWG#106
  • LWG#108
  • LWG#110
  • LWG#112
  • LWG#114
  • LWG#115
  • LWG#119
  • LWG#122
  • LWG#124
  • LWG#125
  • LWG#126
  • LWG#127
  • LWG#129
  • LWG#132
  • LWG#133
  • LWG#134
  • LWG#137
  • LWG#139
  • LWG#141
  • LWG#142
  • LWG#144
  • LWG#146
  • LWG#147
  • LWG#148
  • LWG#150
  • LWG#151
  • LWG#152
  • LWG#154
  • LWG#155
  • LWG#156
  • LWG#158
  • LWG#159
  • LWG#160
  • LWG#161
  • LWG#164
  • LWG#168
  • LWG#169
  • LWG#170
  • LWG#172
  • LWG#173
  • LWG#174
  • LWG#175
  • LWG#176
  • LWG#181
  • LWG#189
  • LWG#193
  • LWG#195
  • LWG#199
  • LWG#208
  • LWG#209
  • LWG#210
  • LWG#211
  • LWG#212
  • LWG#217
  • LWG#220
  • LWG#222
  • LWG#223
  • LWG#224
  • LWG#227
  • 2006 性能 TR（ISO/IEC TR 18015:2006）（ISO 商店）（2006 方案）

此 TR 讨论各种 C++ 抽象的成本，提供实现指引，讨论 C++ 在嵌入式系统中的使用，并引入到 C 的 ISO/IEC TR 18037:2008 <iohw.h> 的 <hardware> 接口。

  • 2007 库扩展 TR1（ISO/IEC TR 19768:2007）（ISO 商店）（2005 方案）。

此 TR 是 C++ 标准库扩展，它添加下列内容到 C++ 标准库：

  1. 来自 Boost：引用包装器，智能指针，成员函数，result_of，bind，function，类型特征，随机数，数学特殊函数，tuple，array，无序容器（包含 hash）和正则表达式。
  2. 来自 C99：C99 中新的来自 math.h 的数学函数，空白字符类，浮点环境，十六进制浮点的 I/O 操纵符，固定大小整型类型，long long 类型，va_copy，snprintf() 和 vfscanf() 函数族及 printf() 和 scanf() 函数族的 C99 转换指定。

除了特殊函数之外的所有 TR1 功能都被包含于 C++11 中，有少量更改。

  • 2010 数学特殊函数（ISO/IEC 29124:2010）（ISO 商店）（2010 方案）

此国际标准是 C++ 标准库扩展，它添加了曾为 TR1 的一部分，但未包含于 C++11 的特殊函数：椭圆积分，指数积分，拉盖尔多项式，勒让德多项式，埃尔米特多项式，贝塞尔函数，诺依曼函数，beta 函数以及黎曼 zeta 函数。此标准被并入 C++17。

C++11 时期

  • 2011 C++11（ISO/IEC 14882:2011）（ISO 商店）（出版后方案）。

引入大量更改，以标准化既存实践，并改进 C++ 程序员可用的抽象

  1. 新语言特性：auto 和 decltype，预置和弃置的函数，final 和 override，尾随返回类型，右值引用，移动构造函数/移动赋值，有作用域 enum，constexpr 和字面类型，列表初始化，委托和继承的构造函数，花括号或等号初始化器，nullptr，long long，char16_t 与 char32_t，类型别名，变参模板，广义化联合体，广义化 POD，Unicode 字符串字面量，用户定义字面量，属性，lambda 表达式，noexcept，alignof 与 alignas，多线程内存模型，线程局域存储，GC 接口，范围 for（基于 Boost 库），静态断言（基于 Boost 库）
  2. 新库特性：原子操作库，emplace() 和遍及既存标准库所有部分的其他右值引用使用，std::initializer_list，有状态和有作用域分配器，forward_list，chrono 库，ratio 库，新算法，Unicode 转换平面
  3. 来自 TR1：所有 TR1，除了特殊函数。
  4. 来自 Boost：线程库，exception_ptr，error_code 和 error_condition，迭代器改进（ std::begin、std::end、std::next、std::prev）
  5. 来自 C：C 风格 Unicode 转换函数
C++11 中修正的缺陷报告（核心 741 个，库 868 个）
  • CWG#4
  • CWG#5
  • CWG#8
  • CWG#9
  • CWG#10
  • CWG#11
  • CWG#16
  • CWG#28
  • CWG#29
  • CWG#39
  • CWG#44
  • CWG#45
  • CWG#54
  • CWG#58
  • CWG#60
  • CWG#62
  • CWG#63
  • CWG#70
  • CWG#77
  • CWG#78
  • CWG#86
  • CWG#87
  • CWG#96
  • CWG#106
  • CWG#112
  • CWG#113
  • CWG#115
  • CWG#118
  • CWG#119
  • CWG#122
  • CWG#124
  • CWG#125
  • CWG#136
  • CWG#139
  • CWG#140
  • CWG#141
  • CWG#143
  • CWG#158
  • CWG#160
  • CWG#162
  • CWG#172
  • CWG#175
  • CWG#177
  • CWG#180
  • CWG#184
  • CWG#195
  • CWG#197
  • CWG#198
  • CWG#199
  • CWG#201
  • CWG#204
  • CWG#207
  • CWG#208
  • CWG#214
  • CWG#215
  • CWG#216
  • CWG#218
  • CWG#220
  • CWG#221
  • CWG#222
  • CWG#224
  • CWG#226
  • CWG#228
  • CWG#237
  • CWG#239
  • CWG#244
  • CWG#245
  • CWG#246
  • CWG#248
  • CWG#252
  • CWG#254
  • CWG#256
  • CWG#257
  • CWG#258
  • CWG#259
  • CWG#261
  • CWG#262
  • CWG#263
  • CWG#270
  • CWG#272
  • CWG#273
  • CWG#274
  • CWG#275
  • CWG#276
  • CWG#277
  • CWG#280
  • CWG#281
  • CWG#283
  • CWG#284
  • CWG#286
  • CWG#288
  • CWG#289
  • CWG#291
  • CWG#295
  • CWG#296
  • CWG#298
  • CWG#299
  • CWG#300
  • CWG#301
  • CWG#302
  • CWG#305
  • CWG#306
  • CWG#309
  • CWG#317
  • CWG#318
  • CWG#319
  • CWG#320
  • CWG#322
  • CWG#323
  • CWG#324
  • CWG#326
  • CWG#327
  • CWG#328
  • CWG#329
  • CWG#331
  • CWG#335
  • CWG#336
  • CWG#337
  • CWG#339
  • CWG#341
  • CWG#345
  • CWG#348
  • CWG#349
  • CWG#351
  • CWG#352
  • CWG#353
  • CWG#354
  • CWG#355
  • CWG#357
  • CWG#362
  • CWG#364
  • CWG#366
  • CWG#367
  • CWG#368
  • CWG#370
  • CWG#372
  • CWG#373
  • CWG#374
  • CWG#377
  • CWG#378
  • CWG#379
  • CWG#381
  • CWG#382
  • CWG#383
  • CWG#385
  • CWG#387
  • CWG#389
  • CWG#390
  • CWG#391
  • CWG#392
  • CWG#394
  • CWG#396
  • CWG#397
  • CWG#398
  • CWG#400
  • CWG#401
  • CWG#403
  • CWG#404
  • CWG#406
  • CWG#407
  • CWG#408
  • CWG#409
  • CWG#410
  • CWG#413
  • CWG#414
  • CWG#415
  • CWG#416
  • CWG#417
  • CWG#420
  • CWG#421
  • CWG#424
  • CWG#425
  • CWG#427
  • CWG#428
  • CWG#429
  • CWG#430
  • CWG#431
  • CWG#432
  • CWG#433
  • CWG#436
  • CWG#437
  • CWG#438
  • CWG#439
  • CWG#441
  • CWG#442
  • CWG#443
  • CWG#446
  • CWG#447
  • CWG#448
  • CWG#450
  • CWG#451
  • CWG#452
  • CWG#454
  • CWG#457
  • CWG#458
  • CWG#460
  • CWG#463
  • CWG#464
  • CWG#466
  • CWG#468
  • CWG#470
  • CWG#474
  • CWG#475
  • CWG#477
  • CWG#479
  • CWG#480
  • CWG#481
  • CWG#484
  • CWG#485
  • CWG#486
  • CWG#488
  • CWG#490
  • CWG#491
  • CWG#492
  • CWG#493
  • CWG#494
  • CWG#495
  • CWG#497
  • CWG#499
  • CWG#500
  • CWG#502
  • CWG#505
  • CWG#506
  • CWG#508
  • CWG#509
  • CWG#510
  • CWG#513
  • CWG#514
  • CWG#515
  • CWG#516
  • CWG#517
  • CWG#518
  • CWG#519
  • CWG#520
  • CWG#521
  • CWG#522
  • CWG#524
  • CWG#525
  • CWG#526
  • CWG#527
  • CWG#530
  • CWG#531
  • CWG#532
  • CWG#534
  • CWG#537
  • CWG#538
  • CWG#540
  • CWG#541
  • CWG#542
  • CWG#543
  • CWG#546
  • CWG#547
  • CWG#551
  • CWG#556
  • CWG#557
  • CWG#558
  • CWG#559
  • CWG#561
  • CWG#564
  • CWG#568
  • CWG#569
  • CWG#570
  • CWG#571
  • CWG#572
  • CWG#573
  • CWG#575
  • CWG#576
  • CWG#580
  • CWG#582
  • CWG#587
  • CWG#588
  • CWG#589
  • CWG#590
  • CWG#592
  • CWG#594
  • CWG#598
  • CWG#599
  • CWG#601
  • CWG#602
  • CWG#603
  • CWG#604
  • CWG#605
  • CWG#606
  • CWG#608
  • CWG#611
  • CWG#612
  • CWG#613
  • CWG#614
  • CWG#615
  • CWG#618
  • CWG#619
  • CWG#620
  • CWG#621
  • CWG#624
  • CWG#625
  • CWG#626
  • CWG#628
  • CWG#629
  • CWG#630
  • CWG#632
  • CWG#633
  • CWG#634
  • CWG#637
  • CWG#638
  • CWG#639
  • CWG#641
  • CWG#642
  • CWG#644
  • CWG#645
  • CWG#647
  • CWG#648
  • CWG#649
  • CWG#650
  • CWG#651
  • CWG#652
  • CWG#653
  • CWG#654
  • CWG#655
  • CWG#656
  • CWG#657
  • CWG#658
  • CWG#659
  • CWG#660
  • CWG#661
  • CWG#663
  • CWG#664
  • CWG#665
  • CWG#666
  • CWG#667
  • CWG#668
  • CWG#671
  • CWG#672
  • CWG#674
  • CWG#676
  • CWG#677
  • CWG#678
  • CWG#679
  • CWG#680
  • CWG#681
  • CWG#683
  • CWG#684
  • CWG#685
  • CWG#686
  • CWG#688
  • CWG#690
  • CWG#691
  • CWG#692
  • CWG#693
  • CWG#694
  • CWG#695
  • CWG#696
  • CWG#699
  • CWG#700
  • CWG#701
  • CWG#702
  • CWG#703
  • CWG#704
  • CWG#705
  • CWG#707
  • CWG#709
  • CWG#710
  • CWG#711
  • CWG#713
  • CWG#714
  • CWG#715
  • CWG#716
  • CWG#717
  • CWG#719
  • CWG#720
  • CWG#721
  • CWG#722
  • CWG#726
  • CWG#730
  • CWG#731
  • CWG#732
  • CWG#734
  • CWG#735
  • CWG#737
  • CWG#738
  • CWG#740
  • CWG#741
  • CWG#743
  • CWG#744
  • CWG#746
  • CWG#749
  • CWG#750
  • CWG#751
  • CWG#752
  • CWG#753
  • CWG#754
  • CWG#756
  • CWG#757
  • CWG#758
  • CWG#759
  • CWG#760
  • CWG#761
  • CWG#762
  • CWG#763
  • CWG#764
  • CWG#765
  • CWG#766
  • CWG#767
  • CWG#768
  • CWG#769
  • CWG#770
  • CWG#771
  • CWG#772
  • CWG#773
  • CWG#774
  • CWG#775
  • CWG#776
  • CWG#777
  • CWG#778
  • CWG#779
  • CWG#782
  • CWG#784
  • CWG#785
  • CWG#786
  • CWG#787
  • CWG#788
  • CWG#789
  • CWG#790
  • CWG#792
  • CWG#793
  • CWG#796
  • CWG#797
  • CWG#798
  • CWG#799
  • CWG#801
  • CWG#803
  • CWG#804
  • CWG#805
  • CWG#806
  • CWG#808
  • CWG#809
  • CWG#810
  • CWG#811
  • CWG#812
  • CWG#814
  • CWG#815
  • CWG#816
  • CWG#817
  • CWG#818
  • CWG#820
  • CWG#823
  • CWG#828
  • CWG#830
  • CWG#831
  • CWG#832
  • CWG#833
  • CWG#834
  • CWG#835
  • CWG#837
  • CWG#838
  • CWG#840
  • CWG#842
  • CWG#845
  • CWG#846
  • CWG#847
  • CWG#850
  • CWG#853
  • CWG#854
  • CWG#855
  • CWG#858
  • CWG#860
  • CWG#861
  • CWG#862
  • CWG#863
  • CWG#864
  • CWG#865
  • CWG#869
  • CWG#872
  • CWG#873
  • CWG#874
  • CWG#876
  • CWG#877
  • CWG#879
  • CWG#880
  • CWG#882
  • CWG#883
  • CWG#884
  • CWG#886
  • CWG#887
  • CWG#888
  • CWG#891
  • CWG#892
  • CWG#896
  • CWG#898
  • CWG#899
  • CWG#904
  • CWG#905
  • CWG#906
  • CWG#908
  • CWG#910
  • CWG#913
  • CWG#915
  • CWG#919
  • CWG#920
  • CWG#921
  • CWG#922
  • CWG#923
  • CWG#924
  • CWG#926
  • CWG#927
  • CWG#928
  • CWG#929
  • CWG#930
  • CWG#931
  • CWG#932
  • CWG#933
  • CWG#934
  • CWG#935
  • CWG#936
  • CWG#938
  • CWG#939
  • CWG#940
  • CWG#941
  • CWG#942
  • CWG#945
  • CWG#946
  • CWG#948
  • CWG#950
  • CWG#951
  • CWG#953
  • CWG#955
  • CWG#956
  • CWG#957
  • CWG#959
  • CWG#960
  • CWG#961
  • CWG#962
  • CWG#963
  • CWG#964
  • CWG#965
  • CWG#966
  • CWG#968
  • CWG#969
  • CWG#970
  • CWG#971
  • CWG#972
  • CWG#973
  • CWG#976
  • CWG#978
  • CWG#979
  • CWG#980
  • CWG#981
  • CWG#983
  • CWG#984
  • CWG#985
  • CWG#986
  • CWG#988
  • CWG#989
  • CWG#990
  • CWG#991
  • CWG#993
  • CWG#994
  • CWG#995
  • CWG#996
  • CWG#997
  • CWG#999
  • CWG#1000
  • CWG#1004
  • CWG#1006
  • CWG#1009
  • CWG#1010
  • CWG#1011
  • CWG#1012
  • CWG#1015
  • CWG#1016
  • CWG#1017
  • CWG#1018
  • CWG#1020
  • CWG#1022
  • CWG#1025
  • CWG#1029
  • CWG#1030
  • CWG#1031
  • CWG#1032
  • CWG#1033
  • CWG#1034
  • CWG#1035
  • CWG#1036
  • CWG#1037
  • CWG#1042
  • CWG#1043
  • CWG#1044
  • CWG#1047
  • CWG#1051
  • CWG#1054
  • CWG#1055
  • CWG#1056
  • CWG#1057
  • CWG#1060
  • CWG#1061
  • CWG#1062
  • CWG#1063
  • CWG#1064
  • CWG#1065
  • CWG#1066
  • CWG#1068
  • CWG#1069
  • CWG#1070
  • CWG#1071
  • CWG#1072
  • CWG#1073
  • CWG#1074
  • CWG#1075
  • CWG#1079
  • CWG#1080
  • CWG#1081
  • CWG#1082
  • CWG#1083
  • CWG#1086
  • CWG#1087
  • CWG#1088
  • CWG#1090
  • CWG#1091
  • CWG#1094
  • CWG#1095
  • CWG#1096
  • CWG#1098
  • CWG#1099
  • CWG#1100
  • CWG#1101
  • CWG#1102
  • CWG#1103
  • CWG#1104
  • CWG#1105
  • CWG#1106
  • CWG#1107
  • CWG#1109
  • CWG#1111
  • CWG#1112
  • CWG#1113
  • CWG#1114
  • CWG#1115
  • CWG#1117
  • CWG#1119
  • CWG#1120
  • CWG#1121
  • CWG#1122
  • CWG#1123
  • CWG#1125
  • CWG#1126
  • CWG#1127
  • CWG#1128
  • CWG#1129
  • CWG#1130
  • CWG#1131
  • CWG#1133
  • CWG#1134
  • CWG#1135
  • CWG#1136
  • CWG#1137
  • CWG#1138
  • CWG#1139
  • CWG#1140
  • CWG#1142
  • CWG#1144
  • CWG#1145
  • CWG#1146
  • CWG#1147
  • CWG#1148
  • CWG#1149
  • CWG#1151
  • CWG#1152
  • CWG#1153
  • CWG#1154
  • CWG#1155
  • CWG#1156
  • CWG#1158
  • CWG#1159
  • CWG#1160
  • CWG#1161
  • CWG#1164
  • CWG#1165
  • CWG#1166
  • CWG#1167
  • CWG#1168
  • CWG#1169
  • CWG#1170
  • CWG#1171
  • CWG#1173
  • CWG#1174
  • CWG#1175
  • CWG#1176
  • CWG#1177
  • CWG#1178
  • CWG#1180
  • CWG#1181
  • CWG#1182
  • CWG#1183
  • CWG#1184
  • CWG#1185
  • CWG#1186
  • CWG#1187
  • CWG#1188
  • CWG#1189
  • CWG#1190
  • CWG#1191
  • CWG#1192
  • CWG#1193
  • CWG#1194
  • CWG#1195
  • CWG#1196
  • CWG#1197
  • CWG#1198
  • CWG#1199
  • CWG#1201
  • CWG#1202
  • CWG#1204
  • CWG#1206
  • CWG#1207
  • CWG#1208
  • CWG#1210
  • CWG#1212
  • CWG#1214
  • CWG#1215
  • CWG#1216
  • CWG#1218
  • CWG#1219
  • CWG#1220
  • CWG#1224
  • CWG#1225
  • CWG#1229
  • CWG#1231
  • CWG#1232
  • CWG#1233
  • CWG#1234
  • CWG#1235
  • CWG#1236
  • CWG#1237
  • CWG#1238
  • CWG#1239
  • CWG#1240
  • CWG#1241
  • CWG#1242
  • CWG#1243
  • CWG#1244
  • CWG#1245
  • CWG#1246
  • LWG#23
  • LWG#44
  • LWG#49
  • LWG#76
  • LWG#91
  • LWG#92
  • LWG#98
  • LWG#103
  • LWG#109
  • LWG#117
  • LWG#118
  • LWG#120
  • LWG#123
  • LWG#130
  • LWG#136
  • LWG#149
  • LWG#153
  • LWG#165
  • LWG#167
  • LWG#171
  • LWG#179
  • LWG#180
  • LWG#182
  • LWG#183
  • LWG#184
  • LWG#185
  • LWG#186
  • LWG#187
  • LWG#198
  • LWG#200
  • LWG#201
  • LWG#202
  • LWG#206
  • LWG#214
  • LWG#221
  • LWG#225
  • LWG#226
  • LWG#228
  • LWG#229
  • LWG#230
  • LWG#231
  • LWG#232
  • LWG#233
  • LWG#234
  • LWG#235
  • LWG#237
  • LWG#238
  • LWG#239
  • LWG#240
  • LWG#241
  • LWG#242
  • LWG#243
  • LWG#247
  • LWG#248
  • LWG#250
  • LWG#251
  • LWG#252
  • LWG#253
  • LWG#254
  • LWG#256
  • LWG#258
  • LWG#259
  • LWG#260
  • LWG#261
  • LWG#262
  • LWG#263
  • LWG#264
  • LWG#265
  • LWG#266
  • LWG#268
  • LWG#270
  • LWG#271
  • LWG#272
  • LWG#273
  • LWG#274
  • LWG#275
  • LWG#276
  • LWG#278
  • LWG#280
  • LWG#281
  • LWG#282
  • LWG#283
  • LWG#284
  • LWG#285
  • LWG#286
  • LWG#288
  • LWG#291
  • LWG#292
  • LWG#294
  • LWG#295
  • LWG#296
  • LWG#297
  • LWG#298
  • LWG#300
  • LWG#301
  • LWG#303
  • LWG#305
  • LWG#306
  • LWG#307
  • LWG#308
  • LWG#310
  • LWG#311
  • LWG#312
  • LWG#315
  • LWG#316
  • LWG#317
  • LWG#318
  • LWG#319
  • LWG#320
  • LWG#321
  • LWG#322
  • LWG#324
  • LWG#325
  • LWG#327
  • LWG#328
  • LWG#329
  • LWG#331
  • LWG#333
  • LWG#334
  • LWG#335
  • LWG#336
  • LWG#337
  • LWG#338
  • LWG#339
  • LWG#340
  • LWG#341
  • LWG#343
  • LWG#345
  • LWG#346
  • LWG#347
  • LWG#349
  • LWG#352
  • LWG#353
  • LWG#354
  • LWG#355
  • LWG#358
  • LWG#359
  • LWG#360
  • LWG#362
  • LWG#363
  • LWG#364
  • LWG#365
  • LWG#369
  • LWG#370
  • LWG#371
  • LWG#373
  • LWG#375
  • LWG#376
  • LWG#379
  • LWG#380
  • LWG#381
  • LWG#383
  • LWG#384
  • LWG#386
  • LWG#387
  • LWG#389
  • LWG#391
  • LWG#395
  • LWG#396
  • LWG#400
  • LWG#401
  • LWG#402
  • LWG#403
  • LWG#404
  • LWG#405
  • LWG#406
  • LWG#407
  • LWG#409
  • LWG#410
  • LWG#411
  • LWG#412
  • LWG#413
  • LWG#414
  • LWG#415
  • LWG#416
  • LWG#419
  • LWG#420
  • LWG#422
  • LWG#425
  • LWG#426
  • LWG#427
  • LWG#428
  • LWG#430
  • LWG#431
  • LWG#432
  • LWG#434
  • LWG#435
  • LWG#436
  • LWG#438
  • LWG#441
  • LWG#442
  • LWG#443
  • LWG#444
  • LWG#445
  • LWG#448
  • LWG#449
  • LWG#453
  • LWG#455
  • LWG#456
  • LWG#457
  • LWG#460
  • LWG#461
  • LWG#464
  • LWG#465
  • LWG#467
  • LWG#468
  • LWG#469
  • LWG#471
  • LWG#473
  • LWG#474
  • LWG#475
  • LWG#478
  • LWG#482
  • LWG#485
  • LWG#488
  • LWG#495
  • LWG#496
  • LWG#497
  • LWG#498
  • LWG#505
  • LWG#507
  • LWG#508
  • LWG#518
  • LWG#519
  • LWG#520
  • LWG#521
  • LWG#522
  • LWG#524
  • LWG#525
  • LWG#527
  • LWG#530
  • LWG#531
  • LWG#533
  • LWG#534
  • LWG#535
  • LWG#537
  • LWG#538
  • LWG#539
  • LWG#540
  • LWG#541
  • LWG#542
  • LWG#543
  • LWG#545
  • LWG#550
  • LWG#551
  • LWG#552
  • LWG#556
  • LWG#559
  • LWG#561
  • LWG#562
  • LWG#563
  • LWG#564
  • LWG#565
  • LWG#566
  • LWG#567
  • LWG#574
  • LWG#575
  • LWG#576
  • LWG#577
  • LWG#578
  • LWG#581
  • LWG#586
  • LWG#589
  • LWG#593
  • LWG#594
  • LWG#595
  • LWG#596
  • LWG#607
  • LWG#608
  • LWG#609
  • LWG#610
  • LWG#611
  • LWG#612
  • LWG#613
  • LWG#616
  • LWG#618
  • LWG#619
  • LWG#620
  • LWG#621
  • LWG#622
  • LWG#623
  • LWG#624
  • LWG#625
  • LWG#628
  • LWG#629
  • LWG#630
  • LWG#634
  • LWG#635
  • LWG#638
  • LWG#640
  • LWG#643
  • LWG#646
  • LWG#650
  • LWG#651
  • LWG#652
  • LWG#654
  • LWG#655
  • LWG#658
  • LWG#659
  • LWG#660
  • LWG#661
  • LWG#664
  • LWG#665
  • LWG#666
  • LWG#671
  • LWG#672
  • LWG#673
  • LWG#674
  • LWG#675
  • LWG#676
  • LWG#677
  • LWG#678
  • LWG#679
  • LWG#680
  • LWG#681
  • LWG#682
  • LWG#685
  • LWG#687
  • LWG#688
  • LWG#689
  • LWG#691
  • LWG#692
  • LWG#693
  • LWG#694
  • LWG#695
  • LWG#696
  • LWG#697
  • LWG#698
  • LWG#699
  • LWG#700
  • LWG#703
  • LWG#704
  • LWG#705
  • LWG#706
  • LWG#709
  • LWG#710
  • LWG#711
  • LWG#712
  • LWG#713
  • LWG#714
  • LWG#715
  • LWG#716
  • LWG#719
  • LWG#720
  • LWG#722
  • LWG#723
  • LWG#724
  • LWG#727
  • LWG#728
  • LWG#732
  • LWG#734
  • LWG#740
  • LWG#742
  • LWG#743
  • LWG#744
  • LWG#746
  • LWG#749
  • LWG#752
  • LWG#753
  • LWG#755
  • LWG#756
  • LWG#758
  • LWG#759
  • LWG#761
  • LWG#762
  • LWG#765
  • LWG#766
  • LWG#767
  • LWG#768
  • LWG#769
  • LWG#770
  • LWG#771
  • LWG#772
  • LWG#774
  • LWG#775
  • LWG#776
  • LWG#777
  • LWG#778
  • LWG#779
  • LWG#780
  • LWG#781
  • LWG#782
  • LWG#783
  • LWG#786
  • LWG#787
  • LWG#788
  • LWG#789
  • LWG#792
  • LWG#793
  • LWG#794
  • LWG#798
  • LWG#800
  • LWG#801
  • LWG#803
  • LWG#804
  • LWG#805
  • LWG#806
  • LWG#807
  • LWG#808
  • LWG#809
  • LWG#810
  • LWG#811
  • LWG#813
  • LWG#814
  • LWG#815
  • LWG#816
  • LWG#817
  • LWG#818
  • LWG#819
  • LWG#820
  • LWG#821
  • LWG#823
  • LWG#824
  • LWG#825
  • LWG#827
  • LWG#828
  • LWG#829
  • LWG#834
  • LWG#835
  • LWG#836
  • LWG#838
  • LWG#842
  • LWG#843
  • LWG#844
  • LWG#845
  • LWG#846
  • LWG#847
  • LWG#848
  • LWG#850
  • LWG#852
  • LWG#853
  • LWG#854
  • LWG#856
  • LWG#857
  • LWG#858
  • LWG#859
  • LWG#860
  • LWG#861
  • LWG#865
  • LWG#866
  • LWG#868
  • LWG#869
  • LWG#870
  • LWG#871
  • LWG#872
  • LWG#874
  • LWG#875
  • LWG#876
  • LWG#878
  • LWG#880
  • LWG#881
  • LWG#882
  • LWG#883
  • LWG#884
  • LWG#885
  • LWG#886
  • LWG#888
  • LWG#889
  • LWG#890
  • LWG#891
  • LWG#893
  • LWG#894
  • LWG#896
  • LWG#897
  • LWG#898
  • LWG#899
  • LWG#900
  • LWG#904
  • LWG#907
  • LWG#908
  • LWG#909
  • LWG#911
  • LWG#920
  • LWG#921
  • LWG#922
  • LWG#923
  • LWG#924
  • LWG#925
  • LWG#929
  • LWG#931
  • LWG#932
  • LWG#934
  • LWG#938
  • LWG#939
  • LWG#940
  • LWG#943
  • LWG#944
  • LWG#947
  • LWG#948
  • LWG#949
  • LWG#950
  • LWG#951
  • LWG#953
  • LWG#954
  • LWG#956
  • LWG#957
  • LWG#958
  • LWG#960
  • LWG#962
  • LWG#963
  • LWG#964
  • LWG#965
  • LWG#966
  • LWG#967
  • LWG#968
  • LWG#970
  • LWG#974
  • LWG#975
  • LWG#976
  • LWG#978
  • LWG#981
  • LWG#982
  • LWG#983
  • LWG#984
  • LWG#985
  • LWG#986
  • LWG#987
  • LWG#990
  • LWG#991
  • LWG#993
  • LWG#994
  • LWG#997
  • LWG#998
  • LWG#999
  • LWG#1004
  • LWG#1006
  • LWG#1011
  • LWG#1012
  • LWG#1014
  • LWG#1019
  • LWG#1021
  • LWG#1030
  • LWG#1033
  • LWG#1034
  • LWG#1037
  • LWG#1038
  • LWG#1039
  • LWG#1040
  • LWG#1043
  • LWG#1044
  • LWG#1045
  • LWG#1046
  • LWG#1047
  • LWG#1048
  • LWG#1049
  • LWG#1050
  • LWG#1054
  • LWG#1055
  • LWG#1065
  • LWG#1066
  • LWG#1070
  • LWG#1071
  • LWG#1073
  • LWG#1075
  • LWG#1079
  • LWG#1088
  • LWG#1089
  • LWG#1090
  • LWG#1093
  • LWG#1094
  • LWG#1095
  • LWG#1097
  • LWG#1098
  • LWG#1100
  • LWG#1103
  • LWG#1104
  • LWG#1106
  • LWG#1108
  • LWG#1110
  • LWG#1113
  • LWG#1114
  • LWG#1116
  • LWG#1117
  • LWG#1118
  • LWG#1122
  • LWG#1123
  • LWG#1126
  • LWG#1129
  • LWG#1130
  • LWG#1131
  • LWG#1133
  • LWG#1134
  • LWG#1135
  • LWG#1136
  • LWG#1137
  • LWG#1138
  • LWG#1143
  • LWG#1144
  • LWG#1145
  • LWG#1146
  • LWG#1147
  • LWG#1151
  • LWG#1152
  • LWG#1157
  • LWG#1158
  • LWG#1159
  • LWG#1160
  • LWG#1161
  • LWG#1162
  • LWG#1163
  • LWG#1165
  • LWG#1166
  • LWG#1170
  • LWG#1171
  • LWG#1172
  • LWG#1174
  • LWG#1177
  • LWG#1178
  • LWG#1180
  • LWG#1181
  • LWG#1182
  • LWG#1183
  • LWG#1185
  • LWG#1187
  • LWG#1189
  • LWG#1191
  • LWG#1192
  • LWG#1193
  • LWG#1194
  • LWG#1195
  • LWG#1196
  • LWG#1197
  • LWG#1198
  • LWG#1199
  • LWG#1204
  • LWG#1205
  • LWG#1206
  • LWG#1207
  • LWG#1208
  • LWG#1209
  • LWG#1210
  • LWG#1211
  • LWG#1212
  • LWG#1215
  • LWG#1216
  • LWG#1218
  • LWG#1220
  • LWG#1221
  • LWG#1222
  • LWG#1225
  • LWG#1226
  • LWG#1227
  • LWG#1229
  • LWG#1231
  • LWG#1234
  • LWG#1237
  • LWG#1240
  • LWG#1241
  • LWG#1244
  • LWG#1245
  • LWG#1247
  • LWG#1248
  • LWG#1249
  • LWG#1250
  • LWG#1252
  • LWG#1253
  • LWG#1254
  • LWG#1255
  • LWG#1256
  • LWG#1257
  • LWG#1258
  • LWG#1260
  • LWG#1261
  • LWG#1262
  • LWG#1264
  • LWG#1266
  • LWG#1267
  • LWG#1268
  • LWG#1269
  • LWG#1270
  • LWG#1271
  • LWG#1272
  • LWG#1273
  • LWG#1274
  • LWG#1275
  • LWG#1276
  • LWG#1277
  • LWG#1278
  • LWG#1279
  • LWG#1280
  • LWG#1281
  • LWG#1283
  • LWG#1284
  • LWG#1285
  • LWG#1286
  • LWG#1287
  • LWG#1288
  • LWG#1290
  • LWG#1291
  • LWG#1292
  • LWG#1293
  • LWG#1294
  • LWG#1295
  • LWG#1297
  • LWG#1298
  • LWG#1299
  • LWG#1300
  • LWG#1303
  • LWG#1304
  • LWG#1305
  • LWG#1306
  • LWG#1307
  • LWG#1309
  • LWG#1310
  • LWG#1311
  • LWG#1312
  • LWG#1316
  • LWG#1319
  • LWG#1321
  • LWG#1322
  • LWG#1323
  • LWG#1324
  • LWG#1325
  • LWG#1326
  • LWG#1327
  • LWG#1328
  • LWG#1329
  • LWG#1332
  • LWG#1333
  • LWG#1334
  • LWG#1335
  • LWG#1337
  • LWG#1338
  • LWG#1339
  • LWG#1340
  • LWG#1344
  • LWG#1345
  • LWG#1346
  • LWG#1347
  • LWG#1349
  • LWG#1353
  • LWG#1354
  • LWG#1355
  • LWG#1356
  • LWG#1357
  • LWG#1360
  • LWG#1362
  • LWG#1363
  • LWG#1364
  • LWG#1365
  • LWG#1366
  • LWG#1367
  • LWG#1368
  • LWG#1370
  • LWG#1372
  • LWG#1377
  • LWG#1378
  • LWG#1379
  • LWG#1380
  • LWG#1381
  • LWG#1382
  • LWG#1383
  • LWG#1384
  • LWG#1385
  • LWG#1386
  • LWG#1387
  • LWG#1388
  • LWG#1389
  • LWG#1390
  • LWG#1391
  • LWG#1392
  • LWG#1393
  • LWG#1394
  • LWG#1397
  • LWG#1399
  • LWG#1400
  • LWG#1401
  • LWG#1402
  • LWG#1403
  • LWG#1404
  • LWG#1405
  • LWG#1407
  • LWG#1408
  • LWG#1409
  • LWG#1410
  • LWG#1412
  • LWG#1414
  • LWG#1416
  • LWG#1417
  • LWG#1418
  • LWG#1420
  • LWG#1421
  • LWG#1423
  • LWG#1424
  • LWG#1425
  • LWG#1426
  • LWG#1427
  • LWG#1428
  • LWG#1429
  • LWG#1430
  • LWG#1431
  • LWG#1432
  • LWG#1435
  • LWG#1436
  • LWG#1437
  • LWG#1438
  • LWG#1439
  • LWG#1440
  • LWG#1441
  • LWG#1445
  • LWG#1447
  • LWG#1448
  • LWG#1449
  • LWG#1453
  • LWG#1455
  • LWG#1457
  • LWG#1460
  • LWG#1462
  • LWG#1464
  • LWG#1465
  • LWG#1466
  • LWG#1467
  • LWG#1468
  • LWG#1469
  • LWG#1474
  • LWG#1478
  • LWG#1479
  • LWG#1480
  • LWG#1481
  • LWG#1482
  • LWG#1487
  • LWG#1490
  • LWG#1491
  • LWG#1492
  • LWG#1494
  • LWG#1497
  • LWG#1498
  • LWG#1501
  • LWG#1502
  • LWG#1504
  • LWG#1505
  • LWG#1507
  • LWG#1508
  • LWG#1513
  • LWG#1514
  • LWG#1515
  • LWG#1516
  • LWG#1517
  • LWG#1518
  • LWG#1519
  • LWG#1520
  • LWG#1522
  • LWG#1523
  • LWG#1524
  • LWG#1525
  • LWG#2000
  • LWG#2001
  • LWG#2002
  • LWG#2004
  • LWG#2007
  • LWG#2008
  • LWG#2014
  • LWG#2017
  • LWG#2019
  • LWG#2020
  • LWG#2022
  • LWG#2023
  • LWG#2024
  • LWG#2025
  • LWG#2027
  • LWG#2029
  • LWG#2030
  • LWG#2031
  • LWG#2032
  • LWG#2034
  • LWG#2037
  • LWG#2041
  • LWG#2042
  • 2011 十进制浮点 TR（ISO/IEC TR 24733:2011）（ISO 商店）（2009 方案）

此 TR 实现来自 IEEE 754-2008 浮点算术标准的十进制浮点类型：std::decimal::decimal32、std::decimal::decimal64 及 std::decimal::decimal128。

  • 2012 标准 C++ 基金会成立
  • 2013 《C++ 程序设计语言》（The C++ Programming Language），第4版

C++14 时期

  • 2014 C++14（ISO 商店）（ANSI 商店）（ 2014 最终方案）

C++ 标准的次要版本

  1. 新语言特性：变量模板，多态 lambda，lambda 俘获表达式，new/delete 消除，放松 constexpr 函数上的限制，二进制字面量，数位分隔符，函数的返回类型推导，带花括号或等号初始化器的类的聚合初始化。
  2. 新库特性：std::make_unique，std::shared_timed_mutex 及 std::shared_lock，std::integer_sequence，std::exchange，std::quoted 以及许多既存库设施的小改进，例如某些算法的双范围重载，类型特征的类型别名，用户定义的 string，duration 和复数字面量等。
C++14 中修正的缺陷报告（核心 276 个，库 158 个）
  • CWG#129
  • CWG#223
  • CWG#240
  • CWG#292
  • CWG#312
  • CWG#332
  • CWG#342
  • CWG#344
  • CWG#388
  • CWG#462
  • CWG#482
  • CWG#483
  • CWG#496
  • CWG#535
  • CWG#539
  • CWG#565
  • CWG#577
  • CWG#583
  • CWG#597
  • CWG#616
  • CWG#623
  • CWG#631
  • CWG#675
  • CWG#712
  • CWG#729
  • CWG#739
  • CWG#755
  • CWG#903
  • CWG#912
  • CWG#974
  • CWG#975
  • CWG#977
  • CWG#1003
  • CWG#1013
  • CWG#1024
  • CWG#1048
  • CWG#1059
  • CWG#1093
  • CWG#1213
  • CWG#1226
  • CWG#1227
  • CWG#1250
  • CWG#1251
  • CWG#1260
  • CWG#1261
  • CWG#1262
  • CWG#1264
  • CWG#1265
  • CWG#1267
  • CWG#1268
  • CWG#1269
  • CWG#1270
  • CWG#1275
  • CWG#1282
  • CWG#1287
  • CWG#1288
  • CWG#1290
  • CWG#1293
  • CWG#1295
  • CWG#1296
  • CWG#1297
  • CWG#1298
  • CWG#1301
  • CWG#1302
  • CWG#1305
  • CWG#1306
  • CWG#1307
  • CWG#1308
  • CWG#1310
  • CWG#1311
  • CWG#1312
  • CWG#1313
  • CWG#1318
  • CWG#1320
  • CWG#1321
  • CWG#1324
  • CWG#1327
  • CWG#1328
  • CWG#1329
  • CWG#1330
  • CWG#1333
  • CWG#1336
  • CWG#1340
  • CWG#1344
  • CWG#1345
  • CWG#1346
  • CWG#1347
  • CWG#1350
  • CWG#1352
  • CWG#1354
  • CWG#1355
  • CWG#1357
  • CWG#1358
  • CWG#1359
  • CWG#1361
  • CWG#1362
  • CWG#1363
  • CWG#1364
  • CWG#1365
  • CWG#1366
  • CWG#1367
  • CWG#1368
  • CWG#1369
  • CWG#1370
  • CWG#1372
  • CWG#1374
  • CWG#1375
  • CWG#1376
  • CWG#1380
  • CWG#1381
  • CWG#1382
  • CWG#1383
  • CWG#1385
  • CWG#1387
  • CWG#1388
  • CWG#1392
  • CWG#1394
  • CWG#1398
  • CWG#1399
  • CWG#1401
  • CWG#1402
  • CWG#1405
  • CWG#1406
  • CWG#1408
  • CWG#1409
  • CWG#1410
  • CWG#1411
  • CWG#1412
  • CWG#1413
  • CWG#1415
  • CWG#1416
  • CWG#1417
  • CWG#1418
  • CWG#1423
  • CWG#1424
  • CWG#1425
  • CWG#1428
  • CWG#1431
  • CWG#1435
  • CWG#1437
  • CWG#1438
  • CWG#1439
  • CWG#1440
  • CWG#1441
  • CWG#1442
  • CWG#1447
  • CWG#1449
  • CWG#1450
  • CWG#1453
  • CWG#1454
  • CWG#1455
  • CWG#1456
  • CWG#1457
  • CWG#1458
  • CWG#1460
  • CWG#1462
  • CWG#1464
  • CWG#1466
  • CWG#1471
  • CWG#1472
  • CWG#1473
  • CWG#1475
  • CWG#1476
  • CWG#1477
  • CWG#1479
  • CWG#1480
  • CWG#1481
  • CWG#1482
  • CWG#1487
  • CWG#1489
  • CWG#1491
  • CWG#1493
  • CWG#1494
  • CWG#1495
  • CWG#1502
  • CWG#1503
  • CWG#1504
  • CWG#1506
  • CWG#1507
  • CWG#1508
  • CWG#1509
  • CWG#1510
  • CWG#1511
  • CWG#1512
  • CWG#1514
  • CWG#1515
  • CWG#1516
  • CWG#1522
  • CWG#1527
  • CWG#1528
  • CWG#1531
  • CWG#1532
  • CWG#1533
  • CWG#1535
  • CWG#1537
  • CWG#1538
  • CWG#1539
  • CWG#1541
  • CWG#1543
  • CWG#1544
  • CWG#1550
  • CWG#1551
  • CWG#1553
  • CWG#1556
  • CWG#1557
  • CWG#1559
  • CWG#1560
  • CWG#1562
  • CWG#1563
  • CWG#1567
  • CWG#1569
  • CWG#1570
  • CWG#1575
  • CWG#1576
  • CWG#1579
  • CWG#1583
  • CWG#1587
  • CWG#1588
  • CWG#1592
  • CWG#1593
  • CWG#1595
  • CWG#1597
  • CWG#1598
  • CWG#1601
  • CWG#1604
  • CWG#1605
  • CWG#1607
  • CWG#1608
  • CWG#1611
  • CWG#1612
  • CWG#1613
  • CWG#1618
  • CWG#1629
  • CWG#1648
  • CWG#1649
  • CWG#1658
  • CWG#1660
  • CWG#1662
  • CWG#1664
  • CWG#1666
  • CWG#1669
  • CWG#1673
  • CWG#1674
  • CWG#1681
  • CWG#1684
  • CWG#1687
  • CWG#1689
  • CWG#1690
  • CWG#1691
  • CWG#1692
  • CWG#1693
  • CWG#1707
  • CWG#1716
  • CWG#1717
  • CWG#1732
  • CWG#1737
  • CWG#1738
  • CWG#1739
  • CWG#1740
  • CWG#1741
  • CWG#1746
  • CWG#1747
  • CWG#1759
  • CWG#1760
  • CWG#1762
  • CWG#1764
  • CWG#1765
  • CWG#1767
  • CWG#1769
  • CWG#1770
  • CWG#1772
  • CWG#1773
  • CWG#1775
  • CWG#1778
  • CWG#1786
  • CWG#1787
  • LWG#1214
  • LWG#1450
  • LWG#2003
  • LWG#2005
  • LWG#2009
  • LWG#2010
  • LWG#2011
  • LWG#2012
  • LWG#2013
  • LWG#2015
  • LWG#2018
  • LWG#2021
  • LWG#2028
  • LWG#2033
  • LWG#2039
  • LWG#2044
  • LWG#2045
  • LWG#2047
  • LWG#2048
  • LWG#2049
  • LWG#2050
  • LWG#2052
  • LWG#2054
  • LWG#2053
  • LWG#2056
  • LWG#2057
  • LWG#2058
  • LWG#2061
  • LWG#2064
  • LWG#2065
  • LWG#2066
  • LWG#2067
  • LWG#2069
  • LWG#2071
  • LWG#2074
  • LWG#2075
  • LWG#2078
  • LWG#2080
  • LWG#2081
  • LWG#2083
  • LWG#2085
  • LWG#2086
  • LWG#2087
  • LWG#2091
  • LWG#2092
  • LWG#2093
  • LWG#2094
  • LWG#2096
  • LWG#2097
  • LWG#2098
  • LWG#2099
  • LWG#2100
  • LWG#2102
  • LWG#2103
  • LWG#2104
  • LWG#2105
  • LWG#2109
  • LWG#2110
  • LWG#2112
  • LWG#2120
  • LWG#2122
  • LWG#2123
  • LWG#2128
  • LWG#2130
  • LWG#2132
  • LWG#2135
  • LWG#2138
  • LWG#2140
  • LWG#2141
  • LWG#2142
  • LWG#2143
  • LWG#2144
  • LWG#2145
  • LWG#2147
  • LWG#2148
  • LWG#2149
  • LWG#2150
  • LWG#2159
  • LWG#2162
  • LWG#2163
  • LWG#2165
  • LWG#2169
  • LWG#2172
  • LWG#2174
  • LWG#2175
  • LWG#2176
  • LWG#2177
  • LWG#2180
  • LWG#2182
  • LWG#2185
  • LWG#2186
  • LWG#2187
  • LWG#2188
  • LWG#2190
  • LWG#2193
  • LWG#2194
  • LWG#2196
  • LWG#2197
  • LWG#2200
  • LWG#2203
  • LWG#2205
  • LWG#2207
  • LWG#2209
  • LWG#2210
  • LWG#2211
  • LWG#2213
  • LWG#2222
  • LWG#2225
  • LWG#2229
  • LWG#2231
  • LWG#2235
  • LWG#2240
  • LWG#2246
  • LWG#2247
  • LWG#2249
  • LWG#2252
  • LWG#2257
  • LWG#2258
  • LWG#2263
  • LWG#2268
  • LWG#2271
  • LWG#2272
  • LWG#2275
  • LWG#2278
  • LWG#2280
  • LWG#2284
  • LWG#2285
  • LWG#2288
  • LWG#2291
  • LWG#2293
  • LWG#2298
  • LWG#2299
  • LWG#2300
  • LWG#2301
  • LWG#2304
  • LWG#2306
  • LWG#2308
  • LWG#2313
  • LWG#2314
  • LWG#2315
  • LWG#2316
  • LWG#2317
  • LWG#2320
  • LWG#2322
  • LWG#2323
  • LWG#2324
  • LWG#2329
  • LWG#2330
  • LWG#2332
  • LWG#2339
  • LWG#2341
  • LWG#2344
  • LWG#2346
  • LWG#2350
  • LWG#2356
  • LWG#2357
  • LWG#2359
  • LWG#2360
  • 2015 文件系统库 TS（ISO/IEC TS 18822:2015）（ISO 商店）（2014 方案）

此 TS 是实验性 C++ 库扩展，它指定基于 boost.filesystem V3 的文件系统库（有一些修改和扩充）。此 TS 被并入 C++17。

  • 2015 并行扩展 TS（ISO/IEC TS 19570:2015）（ISO 商店）（2015 方案）

此 TS 为所有标准库算法标准化了并行和向量并行 API，还添加了新算法，例如 reduce、transform_reduce 和 exclusive_scan。此 TS 被并入 C++17。

  • 2015 事务性内存扩展 TS（ISO/IEC TS 19841:2015）（ISO 商店）（2015 方案）

此 TS 扩展了 C++ 核心语言，添加同步和原子块以及事务安全函数，以实现事务性内存语义。

  • 2015 库基础扩展 TS（ISO/IEC TS 19568:2015）（ISO 商店）（2015 方案）

此 TS 添加数个新组件到 C++ 标准库：optional，any，string_view，sample，search，apply，多态分配器和类型特征的变量模板。此 TS 被并入 C++17。

  • 2015 概念扩展 TS（ISO/IEC TS 19217:2015）（ISO 商店）（2015 方案）

此 TS 扩展了 C++ 核心语言，添加概念（具名类型要求）和制约（模板、函数和变量声明中对允许的类型施加的限制），这有助于元编程并简化模板实例化诊断，见概念。此 TS 已并入 C++20，并有所省略。

  • 2016 并发扩展（ISO/IEC TS 19571:2016）（ISO 商店）（2015 方案）

此 TS 扩展 C++ 库以包含针对 std::future，闩与屏障，以及原子智能指针的数个扩展。

C++17 时期

  • 2017 C++17（ISO 商店）（ANSI 商店）（n4659（2017-03-21 最终草案））
  1. 语言更改：折叠表达式，类模板实参推导，auto 非类型模板形参，编译时 if constexpr，inline 变量，结构化绑定，if 和 switch 的初始化器，u8-char，简化嵌套命名空间，using 声明能声明多个名字，令 noexcept 为类型系统的部分，新的求值顺序规则，带显式对齐的分配函数，受保证的复制消除，__has_include，*this 的 lambda 捕获，constexpr lambda，属性命名空间不必重复，新属性 [[fallthrough]]、[[nodiscard]] 及 [[maybe_unused]]。移除三标符， register 关键词、bool 自增
  2. 库更改： std::variant，std::launder，未初始化内存工具（std::destroy_at/std::destroy/std::destroy_n、std::uninitialized_move、std::uninitialized_value_construct 等），map/set 抽取 及 map/set 合并，byte，std::make_from_tuple，std::to_chars/from_chars，文件系统中的相对路径支持（ proximate、relative、weakly_canonical），文件系统中的目录项缓存，连续迭代器，非成员 size/empty/data，map/unordered_map try_emplace 及 insert_or_assign，uncaught_exceptions，变参 lock_guard，as_const，conjunction/disjunction/negation，类型特征变量 xxx_v，透明的 owner_less，duration 和 time_point 的舍入函数，std::shared_ptr 的数组支持，not_fn，weak_from_this，is_always_lock_free，is_swappable，clamp，3D hypot，缓存线接口，is_invocable，is_aggregate，has_unique_object_representations。弃用 std::iterator，std::raw_storage_iterator，std::get_temporary_buffer，std::is_literal_type，std::result_of，整个 <codecvt>。移除 auto_ptr，已弃用的函数对象，std::random_shuffle，std::unexpected，过时的 iostream 别名。
  3. 来自 TS：文件系统库，库基础 v1（包含 optional、any、string_view、多态分配器、搜索器、apply），并行 v1（包含执行策略、reduce、inclusive_scan、exclusive_scan），但移除 exception_list。来自数学特殊 TR：特殊数学函数，来自库基础 v2：std::gcd、std::lcm
  4. 来自 C11：std::aligned_alloc，std::timespec_get
C++17 中修正的缺陷报告（核心 290 个，库 363 个）
  • CWG#92
  • CWG#150
  • CWG#212
  • CWG#238
  • CWG#242
  • CWG#253
  • CWG#314
  • CWG#330
  • CWG#343
  • CWG#393
  • CWG#426
  • CWG#591
  • CWG#609
  • CWG#636
  • CWG#727
  • CWG#987
  • CWG#1021
  • CWG#1116
  • CWG#1247
  • CWG#1274
  • CWG#1284
  • CWG#1292
  • CWG#1309
  • CWG#1315
  • CWG#1338
  • CWG#1343
  • CWG#1351
  • CWG#1356
  • CWG#1391
  • CWG#1395
  • CWG#1397
  • CWG#1446
  • CWG#1465
  • CWG#1467
  • CWG#1484
  • CWG#1490
  • CWG#1492
  • CWG#1496
  • CWG#1518
  • CWG#1552
  • CWG#1558
  • CWG#1561
  • CWG#1571
  • CWG#1572
  • CWG#1573
  • CWG#1589
  • CWG#1591
  • CWG#1596
  • CWG#1600
  • CWG#1603
  • CWG#1614
  • CWG#1615
  • CWG#1622
  • CWG#1630
  • CWG#1631
  • CWG#1633
  • CWG#1638
  • CWG#1639
  • CWG#1645
  • CWG#1652
  • CWG#1653
  • CWG#1657
  • CWG#1672
  • CWG#1677
  • CWG#1683
  • CWG#1686
  • CWG#1694
  • CWG#1696
  • CWG#1705
  • CWG#1708
  • CWG#1710
  • CWG#1712
  • CWG#1715
  • CWG#1719
  • CWG#1722
  • CWG#1734
  • CWG#1736
  • CWG#1744
  • CWG#1748
  • CWG#1750
  • CWG#1751
  • CWG#1752
  • CWG#1753
  • CWG#1756
  • CWG#1757
  • CWG#1758
  • CWG#1766
  • CWG#1774
  • CWG#1776
  • CWG#1777
  • CWG#1779
  • CWG#1780
  • CWG#1782
  • CWG#1784
  • CWG#1788
  • CWG#1791
  • CWG#1793
  • CWG#1794
  • CWG#1795
  • CWG#1796
  • CWG#1797
  • CWG#1799
  • CWG#1800
  • CWG#1802
  • CWG#1804
  • CWG#1805
  • CWG#1806
  • CWG#1807
  • CWG#1809
  • CWG#1810
  • CWG#1811
  • CWG#1812
  • CWG#1813
  • CWG#1814
  • CWG#1815
  • CWG#1816
  • CWG#1819
  • CWG#1823
  • CWG#1824
  • CWG#1825
  • CWG#1830
  • CWG#1832
  • CWG#1834
  • CWG#1838
  • CWG#1843
  • CWG#1846
  • CWG#1847
  • CWG#1848
  • CWG#1850
  • CWG#1851
  • CWG#1852
  • CWG#1858
  • CWG#1860
  • CWG#1861
  • CWG#1863
  • CWG#1865
  • CWG#1866
  • CWG#1870
  • CWG#1872
  • CWG#1873
  • CWG#1874
  • CWG#1875
  • CWG#1877
  • CWG#1878
  • CWG#1881
  • CWG#1882
  • CWG#1885
  • CWG#1886
  • CWG#1887
  • CWG#1888
  • CWG#1891
  • CWG#1892
  • CWG#1895
  • CWG#1899
  • CWG#1902
  • CWG#1903
  • CWG#1909
  • CWG#1911
  • CWG#1916
  • CWG#1920
  • CWG#1922
  • CWG#1925
  • CWG#1926
  • CWG#1929
  • CWG#1930
  • CWG#1932
  • CWG#1940
  • CWG#1941
  • CWG#1942
  • CWG#1946
  • CWG#1949
  • CWG#1951
  • CWG#1952
  • CWG#1955
  • CWG#1956
  • CWG#1958
  • CWG#1959
  • CWG#1961
  • CWG#1963
  • CWG#1966
  • CWG#1967
  • CWG#1971
  • CWG#1975
  • CWG#1978
  • CWG#1981
  • CWG#1988
  • CWG#1990
  • CWG#1991
  • CWG#1992
  • CWG#1995
  • CWG#1999
  • CWG#2000
  • CWG#2001
  • CWG#2004
  • CWG#2006
  • CWG#2008
  • CWG#2010
  • CWG#2011
  • CWG#2012
  • CWG#2015
  • CWG#2016
  • CWG#2017
  • CWG#2019
  • CWG#2022
  • CWG#2024
  • CWG#2026
  • CWG#2027
  • CWG#2031
  • CWG#2032
  • CWG#2033
  • CWG#2038
  • CWG#2039
  • CWG#2040
  • CWG#2041
  • CWG#2044
  • CWG#2046
  • CWG#2047
  • CWG#2052
  • CWG#2061
  • CWG#2063
  • CWG#2064
  • CWG#2066
  • CWG#2068
  • CWG#2069
  • CWG#2071
  • CWG#2075
  • CWG#2076
  • CWG#2079
  • CWG#2082
  • CWG#2084
  • CWG#2085
  • CWG#2091
  • CWG#2093
  • CWG#2094
  • CWG#2095
  • CWG#2096
  • CWG#2098
  • CWG#2099
  • CWG#2100
  • CWG#2101
  • CWG#2104
  • CWG#2106
  • CWG#2107
  • CWG#2109
  • CWG#2113
  • CWG#2120
  • CWG#2122
  • CWG#2124
  • CWG#2129
  • CWG#2130
  • CWG#2137
  • CWG#2140
  • CWG#2141
  • CWG#2143
  • CWG#2145
  • CWG#2146
  • CWG#2147
  • CWG#2153
  • CWG#2154
  • CWG#2155
  • CWG#2156
  • CWG#2157
  • CWG#2163
  • CWG#2167
  • CWG#2171
  • CWG#2174
  • CWG#2175
  • CWG#2176
  • CWG#2180
  • CWG#2184
  • CWG#2191
  • CWG#2196
  • CWG#2198
  • CWG#2201
  • CWG#2205
  • CWG#2206
  • CWG#2211
  • CWG#2214
  • CWG#2218
  • CWG#2220
  • CWG#2224
  • CWG#2247
  • CWG#2248
  • CWG#2251
  • CWG#2259
  • CWG#2262
  • CWG#2268
  • CWG#2271
  • CWG#2272
  • CWG#2276
  • #LWG839
  • #LWG1041
  • #LWG1150
  • #LWG1169
  • #LWG1201
  • #LWG1526
  • #LWG2016
  • #LWG2051
  • #LWG2059
  • #LWG2062
  • #LWG2063
  • #LWG2072
  • #LWG2076
  • #LWG2101
  • #LWG2106
  • #LWG2108
  • #LWG2111
  • #LWG2118
  • #LWG2119
  • #LWG2127
  • #LWG2129
  • #LWG2133
  • #LWG2156
  • #LWG2160
  • #LWG2166
  • #LWG2168
  • #LWG2170
  • #LWG2179
  • #LWG2181
  • #LWG2192
  • #LWG2208
  • #LWG2212
  • #LWG2217
  • #LWG2218
  • #LWG2219
  • #LWG2221
  • #LWG2223
  • #LWG2224
  • #LWG2228
  • #LWG2230
  • #LWG2232
  • #LWG2233
  • #LWG2234
  • #LWG2239
  • #LWG2241
  • #LWG2244
  • #LWG2245
  • #LWG2250
  • #LWG2259
  • #LWG2260
  • #LWG2261
  • #LWG2266
  • #LWG2273
  • #LWG2274
  • #LWG2276
  • #LWG2294
  • #LWG2296
  • #LWG2309
  • #LWG2310
  • #LWG2312
  • #LWG2325
  • #LWG2328
  • #LWG2336
  • #LWG2340
  • #LWG2343
  • #LWG2353
  • #LWG2354
  • #LWG2361
  • #LWG2364
  • #LWG2365
  • #LWG2367
  • #LWG2368
  • #LWG2369
  • #LWG2370
  • #LWG2376
  • #LWG2377
  • #LWG2378
  • #LWG2380
  • #LWG2384
  • #LWG2385
  • #LWG2387
  • #LWG2391
  • #LWG2393
  • #LWG2394
  • #LWG2396
  • #LWG2397
  • #LWG2399
  • #LWG2400
  • #LWG2401
  • #LWG2403
  • #LWG2404
  • #LWG2406
  • #LWG2407
  • #LWG2408
  • #LWG2411
  • #LWG2415
  • #LWG2419
  • #LWG2420
  • #LWG2422
  • #LWG2424
  • #LWG2425
  • #LWG2426
  • #LWG2427
  • #LWG2428
  • #LWG2433
  • #LWG2434
  • #LWG2435
  • #LWG2436
  • #LWG2437
  • #LWG2438
  • #LWG2439
  • #LWG2440
  • #LWG2441
  • #LWG2442
  • #LWG2443
  • #LWG2445
  • #LWG2447
  • #LWG2448
  • #LWG2450
  • #LWG2454
  • #LWG2455
  • #LWG2456
  • #LWG2458
  • #LWG2459
  • #LWG2460
  • #LWG2462
  • #LWG2464
  • #LWG2465
  • #LWG2466
  • #LWG2467
  • #LWG2468
  • #LWG2469
  • #LWG2470
  • #LWG2473
  • #LWG2475
  • #LWG2476
  • #LWG2477
  • #LWG2482
  • #LWG2483
  • #LWG2484
  • #LWG2485
  • #LWG2486
  • #LWG2487
  • #LWG2488
  • #LWG2489
  • #LWG2492
  • #LWG2495
  • #LWG2501
  • #LWG2502
  • #LWG2503
  • #LWG2505
  • #LWG2510
  • #LWG2514
  • #LWG2519
  • #LWG2520
  • #LWG2523
  • #LWG2529
  • #LWG2531
  • #LWG2534
  • #LWG2536
  • #LWG2537
  • #LWG2540
  • #LWG2542
  • #LWG2543
  • #LWG2544
  • #LWG2545
  • #LWG2548
  • #LWG2549
  • #LWG2550
  • #LWG2554
  • #LWG2556
  • #LWG2557
  • #LWG2559
  • #LWG2560
  • #LWG2562
  • #LWG2565
  • #LWG2566
  • #LWG2567
  • #LWG2569
  • #LWG2571
  • #LWG2572
  • #LWG2576
  • #LWG2577
  • #LWG2578
  • #LWG2579
  • #LWG2581
  • #LWG2582
  • #LWG2583
  • #LWG2584
  • #LWG2585
  • #LWG2586
  • #LWG2587
  • #LWG2589
  • #LWG2590
  • #LWG2591
  • #LWG2596
  • #LWG2598
  • #LWG2663
  • #LWG2664
  • #LWG2665
  • #LWG2667
  • #LWG2669
  • #LWG2670
  • #LWG2671
  • #LWG2672
  • #LWG2673
  • #LWG2674
  • #LWG2676
  • #LWG2677
  • #LWG2678
  • #LWG2679
  • #LWG2680
  • #LWG2681
  • #LWG2683
  • #LWG2684
  • #LWG2685
  • #LWG2686
  • #LWG2687
  • #LWG2688
  • #LWG2689
  • #LWG2694
  • #LWG2696
  • #LWG2698
  • #LWG2699
  • #LWG2704
  • #LWG2706
  • #LWG2707
  • #LWG2709
  • #LWG2710
  • #LWG2711
  • #LWG2712
  • #LWG2715
  • #LWG2716
  • #LWG2718
  • #LWG2719
  • #LWG2720
  • #LWG2721
  • #LWG2722
  • #LWG2723
  • #LWG2724
  • #LWG2725
  • #LWG2726
  • #LWG2727
  • #LWG2728
  • #LWG2729
  • #LWG2732
  • #LWG2734
  • #LWG2735
  • #LWG2736
  • #LWG2738
  • #LWG2739
  • #LWG2740
  • #LWG2742
  • #LWG2744
  • #LWG2747
  • #LWG2748
  • #LWG2749
  • #LWG2752
  • #LWG2753
  • #LWG2754
  • #LWG2755
  • #LWG2756
  • #LWG2757
  • #LWG2758
  • #LWG2759
  • #LWG2760
  • #LWG2763
  • #LWG2765
  • #LWG2767
  • #LWG2768
  • #LWG2769
  • #LWG2770
  • #LWG2771
  • #LWG2773
  • #LWG2776
  • #LWG2777
  • #LWG2778
  • #LWG2781
  • #LWG2782
  • #LWG2784
  • #LWG2785
  • #LWG2786
  • #LWG2787
  • #LWG2788
  • #LWG2789
  • #LWG2790
  • #LWG2791
  • #LWG2793
  • #LWG2794
  • #LWG2795
  • #LWG2796
  • #LWG2798
  • #LWG2799
  • #LWG2801
  • #LWG2802
  • #LWG2803
  • #LWG2804
  • #LWG2805
  • #LWG2806
  • #LWG2807
  • #LWG2809
  • #LWG2810
  • #LWG2812
  • #LWG2817
  • #LWG2824
  • #LWG2825
  • #LWG2826
  • #LWG2830
  • #LWG2834
  • #LWG2835
  • #LWG2837
  • #LWG2838
  • #LWG2842
  • #LWG2850
  • #LWG2853
  • #LWG2855
  • #LWG2857
  • #LWG2861
  • #LWG2862
  • #LWG2863
  • #LWG2864
  • #LWG2866
  • #LWG2867
  • #LWG2868
  • #LWG2869
  • #LWG2872
  • #LWG2873
  • #LWG2874
  • #LWG2875
  • #LWG2876
  • #LWG2877
  • #LWG2878
  • #LWG2879
  • #LWG2880
  • #LWG2882
  • #LWG2887
  • #LWG2888
  • #LWG2889
  • #LWG2890
  • #LWG2895
  • #LWG2900
  • #LWG2901
  • #LWG2903
  • #LWG2904
  • #LWG2905
  • #LWG2908
  • #LWG2911
  • #LWG2912
  • #LWG2913
  • #LWG2914
  • #LWG2915
  • #LWG2917
  • #LWG2918
  • #LWG2919
  • #LWG2920
  • #LWG2921
  • #LWG2924
  • #LWG2925
  • #LWG2926
  • #LWG2927
  • #LWG2928
  • #LWG2934
  • #LWG2956
  • 2017 范围扩展 TS（ISO/IEC TS 21425:2017）（ISO 商店）（2017 方案）

此 TS 扩展 C++ 库，以包含范围——一个新的、更有力的取代迭代器对的抽象，以及范围视图，哨位范围，用于就地变换的投影，新的迭代器及算法。此扩展最终使得能以 sort(v); 排序 vector。

  • 2017 协程扩展 TS（ISO/IEC TS 22277:2017）（ISO 商店）（2017 方案）

此 TS 扩展 C++ 核心语言及标准库，以包含无栈协程（可恢复函数）。它添加了关键词 co_await、co_yield 及 co_return。

  • 2018 网络扩展 TS（ISO/IEC TS 19216:2018）（ISO 商店）（2017 方案）

此 TS 扩展 C++ 库，以包含基于 boost.asio 的 TCP/IP 网络。

  • 2018 模块扩展 TS（ISO/IEC TS 21544:2018）（ISO 商店）（2018 方案）

此 TS 扩展 C++ 核心语言以包含模块。它添加了关键字 module、import，并重新引入带新含义的关键字 export。

  • 2018 并行扩展版本 2 TS（ISO/IEC TS 19570:2018）（ISO 商店）（方案）

此 TS 扩展 C++ 库，使之包含二个新执行策略（unseq 与 vec），添加 reduction_plus 或 for_loop_strided 之类的并行算法，分支合并式并行任务的任务块，SIMD 类型及这些类型上的操作。

C++20 时期

  • 2020 C++20 （ ISO 商店）（ n4860 2020-03-31 最终草案）

主条目： C++20

C++17 后的 C++ 标准主要版本。

未来发展

  • 实验性技术规范
  • 2023 C++23 （ 2021-10-23 草案）

主条目： C++23

C++ 标准的下个主要版本。

参阅

外部链接

  • C++ 的历史：1979-1991
  • 语言在真实世界中为之演化：C++ 1991-2006
  • 标准 C++ 基金会
  • 维基百科上的 C++
  • C++ 标准委员会


if 语句

< cpp‎ | language

有条件地执行另一条语句。

用于需要基于运行时或编译时 (C++17 起)条件或者 if 语句是否在明显常量求值语境下求值 (C++23 起)执行的代码。

语法

属性(可选) if constexpr(可选) ( 初始化语句(可选) 条件 ) true分支语句 | (1) |
属性(可选) if constexpr(可选) ( 初始化语句(可选) 条件 ) true分支语句 else false分支语句 | (2) |
属性(可选) if !(可选) consteval 复合语句 | (3) | (C++23 起)
属性(可选) if !(可选) consteval 复合语句 else 语句 | (4) | (C++23 起)
1) 不带 else 分支的 if 语句
2) 带 else 分支的 if 语句
3) 不带 else 分支的 consteval if 语句
4) 带 else 分支的 consteval if 语句
属性 - (C++11 起) 任意数量的属性
constexpr - (C++17 起) 出现时，该语句即为 constexpr if 语句
初始化语句 - (C++17 起) 下列之一：
  • 一条表达式语句（可以是空语句“;”）
  • 一条简单声明，典型的是带初始化器的变量声明，但它可以声明任意多个变量，或是一条结构化绑定声明
  • 一条别名声明
 (C++23 起)
注意，任何 初始化语句 必然以分号 ; 结束，这是它常被非正式地描述成后随分号的表达式或声明的原因。
条件 - 下列之一：
  • 按语境转换为 bool 的表达式
  • 单个非数组变量的带花括号或等号初始化器的声明
true分支语句 - 任意语句（通常是复合语句），当 条件 求值为 true 时执行
false分支语句 - 任意语句（通常是复合语句），当 条件 求值为 false 时执行
复合语句 - 任意复合语句，在以下场合执行：
  • if 语句在明显常量求值语境下求值，如果 consteval 未前附 !（if consteval）
  • if 语句不在明显常量求值语境下求值，如果 consteval 前附 !（if !consteval）
语句 - 任意语句（只能是复合语句，见下文），在以下场合执行：
  • if 语句不在明显常量求值语境下求值，如果 consteval 未前附 !（if consteval else）
  • if 语句在明显常量求值语境下求值，如果 consteval 前附 !（if !consteval else）

解释

如果 条件 在转换到 bool 后产生 true，那么执行 true分支语句。

如果 if 语句存在 else 部分，且 条件 在转换到 bool 后产生 false，那么执行 false分支语句。

在 if 语句的第二形式（包含 else）中，如果 true分支语句 也是 if 语句，那么内层 if 语句必须也含有 else 部分（换言之，在嵌套 if 语句中 else 关联到最近的尚未有 else 的 if）。

#include <iostream>

int main() {
    // 带 else 子句的简单 if 语句
    int i = 2;
    if (i > 2) {
        std::cout << i << " 大于 2\n";
    } else {
        std::cout << i << " 不大于 2\n";
    }

    // 嵌套 if 语句
    int j = 1;
    if (i > 1)
        if (j > 2)
            std::cout << i << " > 1 且 " << j << " > 2\n";
        else // 此 else 属于 if (j > 2), 而不是 if (i > 1)
            std::cout << i << " > 1 且 " << j << " <= 2\n";

   // 以下声明可用于含 dynamic_cast 的条件
   struct Base {
        virtual ~Base() {}
   };
   struct Derived : Base {
       void df() { std::cout << "df()\n"; }
   };
   Base* bp1 = new Base;
   Base* bp2 = new Derived;

   if (Derived* p = dynamic_cast<Derived*>(bp1)) // 转型失败，返回 nullptr
       p->df();  // 不执行

   if (auto p = dynamic_cast<Derived*>(bp2)) // 转型成功
       p->df();  // 执行
}

输出：

2 不大于 2
2 > 1 且 1 <= 2
df()

带初始化器的 if 语句

如果使用 初始化语句，那么 if 语句等价于

{
初始化语句
if constexpr(可选) ( 条件 )
true分支语句

}

或

{
初始化语句
if constexpr(可选) ( 条件 )
true分支语句
else
false分支语句

}

但 初始化语句 所声明的名字（如果 初始化语句 是声明）和 条件 所声明的名字（如果 条件 是声明）处于同一作用域中，同时也是两条 语句 所在的作用域。

std::map<int, std::string> m;
std::mutex mx;
extern bool shared_flag; // 由 mx 保证
int demo() {
   if (auto it = m.find(10); it != m.end()) { return it->second.size(); }
   if (char buf[10]; std::fgets(buf, 10, stdin)) { m[0] += buf; }
   if (std::lock_guard lock(mx); shared_flag) { unsafe_ping(); shared_flag = false; }
   if (int s; int count = ReadBytesWithSignal(&s)) { publish(count); raise(s); }
   if (auto keywords = {"if", "for", "while"};
       std::any_of(keywords.begin(), keywords.end(),
                   [&s](const char* kw) { return s == kw; })) {
     std::cerr << "Token 不能是关键词\n");
   }
}
 (C++17 起)

constexpr if

以 if constexpr 开始的语句被称为 constexpr if 语句。

在 constexpr if 语句中，条件 的值必须是可按语境转换到 bool 类型的经转换常量表达式 (C++23 前)按语境转换到 bool 的表达式，其中转换为常量表达式 (C++23 起)。如果它的值是 true，那么舍弃 false分支语句（如果存在），否则舍弃 true分支语句。

被舍弃语句中的 return 语句不参与函数返回类型推导：

template <typename T>
auto get_value(T t) {
    if constexpr (std::is_pointer_v<T>)
        return *t; // 对 T = int* 推导返回类型为 int
    else
        return t;  // 对 T = int 推导返回类型为 int
}

被舍弃语句可以 ODR 式使用未定义的变量：

extern int x; // 不需要 x 的定义
int f() {
if constexpr (true)
    return 0;
else if (x)
    return x;
else
    return -x;
}

如果 constexpr if 语句在模板实体内出现，且如果 条件 在实例化后不是值待决的，那么外围模板被实例化时不会实例化被舍弃语句。

template<typename T, typename ... Rest>
void g(T&& p, Rest&& ...rs) {
    // ... 处理 p
    if constexpr (sizeof...(rs) > 0)
        g(rs...); // 始终不会对空实参列表实例化。
}

在模板外，被舍弃语句受到完整的检查。if constexpr 不是 #if 预处理指令的替代品：

void f() {
    if constexpr(false) {
        int i = 0;
        int *p = i; // 在被舍弃语句中仍为错误
    }
}

注意：实例化后仍为值待决的一个例子是嵌套模板，例如：

template<class T> void g() {
    auto lm = [](auto p) {
        if constexpr (sizeof(T) == 1 && sizeof p == 1) {
           // 此条件在 g<T> 实例化后仍为值待决的
        }
    };
}
本节未完成
原因：看起来 P0588R1 改变了状况。

注意：被舍弃语句不能对所有特化均非良构：

template <typename T>
void f() {
    if constexpr (std::is_arithmetic_v<T>)
        // ...
    else
        static_assert(false, "必须是算术类型"); // 非良构：该语句对于所有 T 都非法
}

对这种万应语句的常用变通方案，是一条始终为 false 的类型待决表达式：

template<class T> struct dependent_false : std::false_type {};
template <typename T>
void f() {
     if constexpr (std::is_arithmetic_v<T>)
         // ...
     else
       static_assert(dependent_false<T>::value, "必须是算术类型"); // OK
}

在 constexpr if 的子语句中出现的标号（goto 目标、case 标号和 default:），只能在同一子语句中（由 switch 或 goto）引用。

注意：能以 typedef 声明 或别名声明 (C++23 起)为 constexpr if 语句的初始化语句以减少类型别名的作用域。

本节未完成
原因：暂无示例
(C++17 起)

consteval if

以 if consteval 开始的语句被称为 consteval if 语句。在 consteval if 语句中 复合语句 和 语句 （如果存在）必须是复合语句。

即使 语句 不是复合语句，它也会被视为 consteval if 语句的一部分（因此产生编译错误）：

constexpr void f(bool b) {
    if (true)
        if consteval { }
        else ; // 错误：不是复合语句，else 不与外层 if 关联
}

如果在明显常量求值语境中求值 consteval if 语句，那么执行 复合语句 。否则在 语句 存在时执行它。

在 consteval if 语句中出现的 case 或 default 标签必须关联到同一 if 语句中的 switch 语句。在 consteval if 语句中声明的标签必须只关联到同一子语句中的语句。

如果语句以 if !consteval 开始，那么 复合语句 与 语句 （如果存在）必须都是复合语句。这种语句不被认为是 consteval if 语句，但它等价于 consteval if 语句：

  • if !consteval {/*语句*/} 等价于 if consteval {} else {/*语句*/} 。
  • if !consteval {/*语句1*/} else {/*语句2*/} 等价于 if consteval {/*语句2*/} else {/*语句1*/} 。

consteval if 语句中的 复合语句 （或否定形式中的 语句）是立即函数语境，在其中对立即函数的调用不需要是常量表达式。

#include <cmath>
#include <cstdint>
#include <cstring>
#include <iostream>

constexpr bool is_constant_evaluated() noexcept {
    if consteval { return true; } else { return false; }
}

constexpr bool is_runtime_evaluated() noexcept {
    if not consteval { return true; } else { return false; }
}

consteval std::uint64_t ipow_ct(std::uint64_t base, std::uint8_t exp) {
    if (!base) return base;
    std::uint64_t res{1};
    while (exp) {
        if (exp & 1) res *= base;
        exp /= 2;
        base *= base;
    }
    return res;
}

constexpr std::uint64_t ipow(std::uint64_t base, std::uint8_t exp) {
    if consteval { // 使用编译时友好的算法
        return ipow_ct(base, exp);
    }
    else { // 使用运行时求值
        return std::pow(base, exp);
    }
}

int main(int, const char* argv[]) {
    static_assert(ipow(0,10) == 0 && ipow(2,10) == 1024);
    std::cout << ipow(std::strlen(argv[0]), 3) << '\n';
}
 (C++23 起)

注解

如果 true分支语句 或 false分支语句 不是复合语句，那么按如同是复合语句一样处理：

if (x)
    int i;
// i 不再在作用域中

与下面相同

if (x) {
    int i;
} // i 不再在作用域中

如果 条件 是声明，那么它引入的名字的作用域是两个语句体的合并作用域：

if (int x = f()) {
    int x; // 错误：重复声明了 x
} else {
    int x; // 错误：重复声明了 x
}

如果通过 goto 或 longjmp 进入 true分支语句，那么不执行 false分支语句。

constexpr if 语句的 条件 中不允许内建转换，除了到 bool 的非窄化 整型转换。

 (C++17 起)
(C++23 前)

不允许 switch 和 goto 跳入 constexpr if 语句或 consteval if 语句 (C++23 起)的分支。

 (C++17 起)

关键词

if, else, constexpr, consteval

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 631 | C++98 | 如果通过标签抵达第一子语句则控制流未指明 | 与 C 的行为一致

参阅


隐式转换

< cpp‎ | language

凡是在语境中使用了某种表达式类型 T1，但语境不接受该类型，而接受另一类型 T2 的时候，会进行隐式转换，具体是：

  • 调用以 T2 为形参声明的函数时，以该表达式为实参；
  • 运算符期待 T2，而以该表达式为操作数；
  • 初始化 T2 类型的新对象，包括在返回 T2 的函数中的 return 语句；
  • 将表达式用于 switch 语句（T2 为整型类型）；
  • 将表达式用于 if 语句或循环（T2 为 bool）。

仅当存在一个从 T1 到 T2 的无歧义隐式转换序列时，程序良构（能编译）。

如果所调用的函数或运算符存在多个重载，则将 T1 到每个可用的 T2 都构造隐式转化序列之后，以重载决议规则决定编译哪个重载。

注意：算术表达式中，针对二元运算符的操作数上的隐式转换的目标类型，是以一组单独的通常算术转换的规则所决定的。

转换顺序

隐式转换序列由下列内容依照这个顺序所构成：

1) 零或一个标准转换序列；
2) 零或一个用户定义转换；
3) 零或一个标准转换序列。

当考虑构造函数或用户定义转换函数的实参时，只允许一个标准转换序列（否则将实际上可以将用户定义转换串连起来）。从一个非类类型转换到另一非类类型时，只允许一个标准转换序列。

标准转换序列由下列内容依照这个顺序所构成：

1) 零或一个来自下列集合者：左值到右值转换、数组到指针转换及函数到指针转换；
2) 零或一个数值提升或数值转换；
3) 零或一个函数指针转换；
 (C++17 起)
4) 零或一个限定转换。

用户定义转换由零或一个非 explicit 单实参转换构造函数或非 explicit 转换函数的调用构成。

当且仅当 T2 能从表达式 e 复制初始化，即对于虚设的临时对象 t，声明 T2 t = e; 良构（能编译）时，称表达式 e 可隐式转换为 T2。注意这有别于直接初始化（T2 t(e)），其中还会额外考虑 explicit 构造函数和转换函数。

按语境转换

下列语境中，期待类型 bool，且若声明 bool t(e); 良构则进行隐式转换（即考虑如 explicit T::operator bool() const; 这样的隐式转换函数）。称这种表达式 e 按语境转换为 bool。

  • if、while、for 的控制表达式；
  • 内建逻辑运算符 !、&& 和 || 的操作数；
  • 条件运算符 ?: 的首个操作数；
  • static_assert 声明中的谓词；
  • noexcept 说明符中的表达式；
  • explicit 说明符中的表达式。
 (C++20 起)
(C++11 起)

下列语境中，期待某个语境特定的类型 T，而对于类类型 E 的表达式 e，仅当 E 拥有单个转换到任何可允许类型的非 explicit 用户定义转换函数 (C++14 前)可允许类型中恰好有一个类型 T，使得 E 拥有非 explicit 转换函数，其返回类型为（可有 cv 限定的）T 或到（可有 cv 限定的）T 的引用的，且 e 可隐式转换为 T (C++14 起)时，才得到允许。称这种表达式 e 按语境隐式转换到指定的类型 T。注意，其中不考虑 explicit 转换函数，虽然在按语境转换到 bool 时会考虑它们。 (C++11 起)

  • delete 表达式的实参（T 是任何对象指针类型）；
  • 整型常量表达式，其中使用了字面类（T 是任何整数或无作用域枚举类型，所选中的用户定义转换函数必须是 constexpr）；
  • switch 语句的控制表达式（T 是整数或枚举类型）。
#include <cassert>

template<typename T>
class zero_init
{
    T val;
public:
    zero_init() : val(static_cast<T>(0)) { }
    zero_init(T val) : val(val) { }
    operator T&() { return val; }
    operator T() const { return val; }
};

int main()
{
    zero_init<int> i; assert(i == 0);
    i = 7; assert(i == 7);
    switch(i) { }     // C++14 前错误（多于一个转换函数）
                      // C++14（两个函数均转换到同一类型 int）
    switch(i + 0) { } // 始终 OK（隐式转换）
}

值变换

值变换是更改表达式值类别的转换。每当将表达式用作期待不同值类别的表达式的运算符的操作数时，发生值变换。

左值到右值转换

任何非函数、非数组类型 T 的泛左值，可隐式转换成同类型的纯右值。若 T 为非类类型，则此转换亦移除 cv 限定符。

以下情况下并不访问该左值所指代的对象：

  • 转化发生在不求值语境中，例如作为 sizeof、noexcept、decltype (C++11 起) 或 typeid 的静态形式的操作数
  • 泛左值具有 std::nullptr_t 类型：此情况下结果纯右值是空指针常量 nullptr。
 (C++11 起)
  • 存储于对象的值是编译时常量，且满足某些其他条件（见 ODR 式使用）

若 T 是非类类型，则产生该对象所包含的值作为纯右值结果。对于类类型，此转换

实际上以原泛左值作为复制构造函数的实参，复制构造一个 T 类型的临时对象，并将该临时对象作为纯右值返回。 | (C++17 前)
将泛左值转换为纯右值，其结果对象由该泛左值复制初始化。 | (C++17 起)

这项转换所塑造的是从某个内存位置中读取值到 CPU 寄存器之中的动作。

若泛左值所指代的对象含有不确定值（例如由默认初始化非类类型的自动变量而得），则其行为未定义，除非该不确定值的类型为可有 cv 限定的 unsigned char 或 std::byte (C++17 起)。

若泛左值含有已无效化的指针值，则行为由实现定义（而非未定义）。

数组到指针转换

“T 的 N 元素数组”或“T 的未知边界数组”类型的左值或右值，可隐式转换为“指向 T 的指针”类型的纯右值。若数组是纯右值，则发生临时量实质化。 (C++17 起)产生的指针指向数组首元素（细节参阅数组到指针退化）。

临时量实质化

任何完整类型 T 的纯右值，可转换为同类型 T 的亡值。此转换以该纯右值初始化一个 T 类型的临时对象（以临时对象作为求值该纯右值的结果对象），并产生一个代表该临时对象的亡值。 若 T 是类类型或类类型的数组，则它必须有可访问且未被弃置的析构函数

struct S { int m; };
int k = S().m; // C++17 起成员访问期待泛左值；
               // S() 纯右值被转换为亡值

临时量实质化在下例情况下发生：

  • 绑定引用到纯右值时；
  • 在类纯右值上进行成员访问时；
  • 进行数组到指针转换（见上文）或在数组纯右值上使用下标时；
  • 以花括号初始化器列表初始化 std::initializer_list<T> 类型的对象时；
  • 对纯右值应用 typeid 时（这是不求值表达式的一部分）；
  • 对纯右值应用 sizeof 时（这是不求值表达式的一部分）；
  • 纯右值作为弃值表达式时；

注意临时量实质化在从纯右值初始化同类型对象（由直接初始化或复制初始化）时不出现：直接从初始化器初始化这种对象。这确保“受保证的复制消除”。

 (C++17 起)

函数到指针

函数类型 T 的左值，可隐式转换成指向该函数的指针的纯右值。这不适用于非静态成员函数，因为不存在指代非静态成员函数的左值。

数值提升

整型提升

小整型类型（如 char）的纯右值可转换为较大整型类型（如 int）的纯右值。具体而言，算术运算符不接受小于 int 的类型为其实参，而在左值到右值转换后，若适用则自动实施整型提升。此转换始终保持原值。

以下隐式转换被归类为整型提升：

  • signed char 或 signed short 可转换为 int；
  • 若 int 能保有其整个值范围，则 unsigned char、char8_t (C++20 起) 或 unsigned short 可转换为 int，否则可转换为 unsigned int；
  • char 可转换为 int 或 unsigned int，取决于其底层类型为 signed char 还是 unsigned char（见上文）；
  • wchar_t、char16_t 及 char32_t (C++11 起) 可转换为以下列表中能保有其整个值范围的首个类型：int、unsigned int、long、unsigned long、long long、unsigned long long (C++11 起)；
  • 底层类型不固定的无作用域枚举类型可转换为以下列表中能保有其整个值范围的首个类型：int、unsigned int、long、unsigned long、long long、unsigned long long、扩展整数类型（以大小顺序，有符号优先于无符号） (C++11 起)。若值范围更大，则不应用整型提升；
  • 底层类型固定的无作用域枚举类型可转换为其底层类型，而当底层类型亦适用整型提升时，则亦可转换为提升后的底层类型。到未提升的底层类型的转换，对于重载决议而言为更优；
 (C++11 起)
  • 若 int 能表示位域的整个值范围，则位域类型可转换为 int，否则若 unsigned int 能表示位域的整个值范围，则可转换为 unsigned int，否则不实施整型提升；
  • bool 类型可转换为 int，值 false 变为 ​0​ 而 true 变为 1。

注意，所有其他转换都不是提升；例如重载决议选择 char -> int（提升）优先于 char -> short（转换）。

浮点提升

float 类型纯右值可转换为 double 类型的纯右值。值不更改。

数值转换

不同于提升，数值转换可以更改值，而且有潜在的精度损失。

整型转换

任何整数类型或无作用域枚举类型的纯右值都可隐式转换成任何其他整数类型。若其转换列出于整数类型提升之下，则它是提升而非转换。

  • 若目标类型为无符号，则结果值是等于源值模 2n
     的最小无符号值，其中 n 是用于表示目标类型的位数。
即取决于目标类型更宽或更窄，分别对有符号数进行符号扩展[脚注 1]或截断，而对无符号数进行零扩展或截断。
  • 若目标类型有符号，则当源整数能以目标类型表示时，不更改其值。否则结果是实现定义的 (C++20 前)与源值对 2n
     同余的唯一目标类型值，其中 n 是用于表示目标类型的位数     (C++20 起)    （注意这不同于未定义的有符号整数算术溢出）。
  • 若源类型为 bool，则值 false 转换为目标类型的零，而值 true 转换成目标类型的一（注意若目标类型为 int，则这是整数类型提升，而非整数类型转换）。
  • 若目标类型为 bool，则这是布尔转换（见下文）。

浮点转换

浮点类型的纯右值可转换成任何其他浮点类型的纯右值。若其转换列于浮点提升之下，则它是提升而非转换。

  • 若源值能以目标类型准确表示，则不更改它。
  • 若源值处于目标类型的两个可表示值之间，则结果是两个值之一（选择哪个是实现定义的，不过若支持 IEEE，则舍入默认为到最接近）。
  • 否则，行为未定义。

浮点整型转换

  • 浮点类型的纯右值可隐式转换成任何整数类型的纯右值。截断小数部分，即舍弃小数部分。若结果不能适应到目标类型中，则行为未定义（即使在目标类型为无符号数时，也不实施模算术）。若目标类型为 bool，则这是布尔转换（见下文）。
  • 整数或无作用域枚举类型的纯右值可转换成任何浮点类型的纯右值。若不能正确表示该值，则选择与之最接近的较高值还是最接近的较低值是实现定义的，不过若支持 IEEE，则舍入默认为到最接近。若其值不能适应到目标类型中，则行为未定义。若源类型为 bool，则值 false 转换为零，而值 true 转换为一。

指针转换

  • 空指针常量（见 NULL）能转换成任何指针类型，而结果是该类型的空指针值。允许这种转换（称为空指针转换）作为单次转换，转换到 cv 限定类型，即不认为它是数值和限定性转换的结合。
  • 指向任何（可有 cv 限定的）对象类型 T 的指针的纯右值，可转换成指向（有等同 cv 限定的）void 的指针的纯右值。结果指针与原指针表示内存中的同一位置。若原指针是空指针值，则结果为目标类型的空指针值。
  • 指向派生类类型的（可有 cv 限定的）空指针可转换成指向其（有等同 cv 限定的）基类的指针。若基类不可访问或有歧义，则转换非良构（不能编译）。转换结果是指向原被指向对象内的基类子对象的指针。空指针值转换成目标类型的空指针值。

成员指针转换

  • 空指针常量（见 NULL）可转换成任何成员指针类型，而结果是该类型的空成员指针值。允许这种转换（称为空成员指针转换）作为单次转换，转换到 cv 限定类型，即不认为它是数值和限定性转换的结合。
  • 指向基类 B 中某类型 T 成员的指针纯右值，可转换成指向其派生类 D 中同一类型 T 成员的指针纯右值。若 B 是 D 的间接、有歧义或虚基类，或是 D 的某个中间虚基类的基类，则转换非良构（不能编译）。能以 D 对象解引用结果指针，而它将访问该 D 对象的 B 基类子对象内的成员。空成员指针值转换成目标类型的空成员指针值。

布尔转换

整数、浮点、无作用域枚举、指针和成员指针类型的纯右值，可转换成 bool 类型的纯右值。

零值（对于整数、浮点和无作用域枚举）、空指针值和空成员指针值变为 false。所有其他值变为 true。

直接初始化的语境中，可以 std::nullptr_t 类型纯右值（包括 nullptr）初始化 bool 对象。结果为 false。然而不认为它是隐式转换。

 (C++11 起)

限定性转换

  • 指向有 cv 限定的类型 T 的指针类型的纯右值，可转换为指向有更多 cv 限定的同一类型 T 的指针纯右值（换言之，能添加常性和易变性）。
  • 指向类 X 中有 cv 限定的类型 T 的成员指针的纯右值，可转换成指向类 X 中有更多 cv 限定的类型 T 的成员指针纯右值。

“更多” cv 限定表明

  • 指向无限定类型的指针能转换成指向 const 的指针；
  • 指向无限定类型的指针能转换成指向 volatile 的指针；
  • 指向无限定类型的指针能转换成指向 const volatile 的指针；
  • 指向 const 类型的指针能转换成指向 const volatile 的指针；
  • 指向 volatile 类型的指针能转换成指向 const volatile 的指针。

对于多级指针，应用下列限制：身为 cv1
0 限定指针，指向 cv1
1 限定指针，指向…… cv1
n-1 限定指针，指向 cv1
n 限定 T 的多级指针 P1，可转换成身为 cv2
0 限定指针，指向 cv2
1 限定指针，指向…… cv2
n-1 限定指针，指向 cv2
n 限定 T 的多级指针 P2，仅当

  • 两个指针的级数 n 相同；
  • 在涉及数组类型的每一级，至少一个数组类型拥有未知边界，或两个数组类型均拥有相同大小；
 (C++20 起)
  • 若在 P1 的某级（除了零级）的 cv1
    k     中有 const，则在 P2 的同级 cv2
    k     中有 const；
  • 若在 P1 的某级（除了零级）的 cv1
    k     中有 volatile，则在 P2 的同级 cv2
    k     中有 volatile；
  • 若在 P1 的某级（除了零级）有未知边界数组类型，则在 P2 的同级有未知边界数组类型；
 (C++20 起)
  • 若在某级 k 上，P2 比 P1 有更多 cv 限定或 P1 中有已知边界数组类型而 P2 中有未知边界数组类型 (C++20 起)，则 P2 到 k 为止的每一级（除了零级）cv2
    1    , cv2
    2     ... cv2
    k     上都必须有 const 。
  • 同样的规则用于指向成员的多级指针及指向对象和指向成员的多级混合指针；
  • 同样的规则适用于包含任何级为指向已知边界或未知边界数组（认为有 cv 限定元素的数组自身有等同的 cv 限定）的多级指针；
 (C++14 起)
  • 零级由非多级限定性转换的规则处理。
char** p = 0;
const char** p1 = p; // 错误：2 级有更多 cv 限定但 1 级非 const
const char* const * p2 = p; // OK：2 级有更多 cv 限定并在 1 级添加 const
volatile char * const * p3 = p; // OK：2 级更有 cv 限定并在 1 级添加 const
volatile const char* const* p4 = p2; // OK：2 级更有 cv 限定而 const 已在 1 级

double *a[2][3];
double const * const (*ap)[3] = a; // C++14 起 OK
double * const (*ap1)[] = a; // C++20 起 OK

注意 C 编程语言中，只能添加 const/volatile 到第一级：

char** p = 0;
char * const* p1 = p; // C 与 C++ 中 OK
const char* const * p2 = p; // C 中错误，C++ 中 OK

函数指针转换

  • 指向无抛出函数的指针类型的纯右值，可转换成指向潜在抛出函数的指针纯右值。
  • 指向无抛出成员函数指针类型的纯右值，可转换成指向潜在抛出成员函数的指针纯右值。
void (*p)();
void (**pp)() noexcept = &p; // 错误：不能转换成指向 noexcept 函数的指针

struct S
{
    typedef void (*p)();
    operator p();
};
void (*q)() noexcept = S(); // 错误：不能转换成指向 noexcept 函数的指针
 (C++17 起)

安全 bool 问题

在 C++11 引入显式转换函数之前，设计一个能用于布尔语境的类（比如，if(obj) { ... }）会出现问题：给定一个用户定义转换函数，如 T::operator bool() const;，则隐式转换序列允许再多一步标准转换序列，也就是 bool 结果会转换成 int，允许诸如 obj << 1; 或 int i = obj; 这样的代码。

一个早期的解决方案可参见 std::basic_ios，它定义 operator! 和 operator void*(C++11 前)，使得如 if( std::cin ) {...} 的代码能编译，因为 void* 能转换为 bool，但int n = std::cout ; 不能，因为 void* 不可转换至 int。这仍然允许无意义代码能编译，如 delete std::cout ;。许多 C++11 前的第三方库设计带有更为复杂的解决方案，称作安全 Bool 手法。

显式 bool 转换也能用于解决安全 bool 问题

explicit operator bool() const { ... }
 (C++11 起)

脚注

  1. ↑ 仅若算术为补码才使用，仅对定宽整数类型要求补码。然而注意目前所有拥有 C++ 编译器的平台都使用补码算术。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 330 | C++98 | 从 double * const (*p)[3] 到 double const * const (*p)[3] 的转换非法 | 转换合法
CWG 616 | C++98 | 任何未初始化对象和拥有非法值的指针对象的左值到右值的转换是未定义行为 | 允许不定值的 unsigned char； 使用非法指针由实现定义
CWG 1423 | C++11 | std::nullptr_t 在直接或复制初始化中可转换为 bool | 只允许直接初始化
CWG 1781 | C++11 | std::nullptr_t 到 bool 被认为是隐式转换，尽管只对直接初始化合法 | 不再认为它是隐式转换
CWG 1787 | C++98 | 读取缓存在寄存器中的中间 unsigned char 是未定义行为 | 赋予其良好定义

参阅

  • const_cast
  • static_cast
  • dynamic_cast
  • reinterpret_cast
  • 显式转型
  • 用户定义转换


类型

< cpp‎ | language

对象、引用、函数（包括函数模板特化）和表达式具有称为类型的性质，它限制了对这些实体所容许的操作，并给原本寻常的位序列提供了语义含义。

类型的分类

C++ 类型系统由以下类型组成：

  • 基础类型（参阅 std::is_fundamental）：
  • void 类型（参阅 std::is_void）；
  • std::nullptr_t 类型(C++11 起) （参阅 std::is_null_pointer）；
  • 算术类型（参阅 std::is_arithmetic）：
  • 浮点类型（float、double、long double 及其 cv 限定版本）（参阅 std::is_floating_point）；
  • 整数类型（包括 cv 限定版本，参阅 std::is_integral）：
  • bool 类型；
  • 字符类型：
  • 窄字符类型：
  • 通常字符类型（char、signed char、unsigned char）
  • char8_t 类型(C++20 起)
  • 宽字符类型（char16_t、char32_t、 (C++11 起)wchar_t）；
  • 有符号整数类型（short int、int、long int、long long int (C++11 起)）；
  • 无符号整数类型（unsigned short int、unsigned int、unsigned long int、unsigned long long int (C++11 起)）；
  • 复合类型（参阅 std::is_compound）：
  • 引用类型（参阅 std::is_reference）：
  • 左值引用类型（参阅 std::is_lvalue_reference）；
  • 到对象的左值引用类型；
  • 到函数的左值引用类型；
  • 右值引用类型（参阅 std::is_rvalue_reference）；
  • 到对象的右值引用类型；
  • 到函数的右值引用类型；
 (C++11 起)
  • 指针类型（参阅 std::is_pointer）：
  • 指向对象的指针（对象指针）类型；
  • 指向函数的指针（函数指针）类型；
  • 指向成员的指针（成员指针）类型（参阅 std::is_member_pointer）：
  • 指向数据成员的指针类型（参阅 std::is_member_object_pointer）；
  • 指向成员函数的指针类型（参阅 std::is_member_function_pointer）；
  • 数组类型（参阅 std::is_array）；
  • 函数类型（参阅 std::is_function）；
  • 枚举类型（参阅 std::is_enum）；
  • 类类型：
  • 非联合体类型（参阅 std::is_class）；
  • 联合体类型（参阅 std::is_union）。

对于除引用和函数以外的每个类型，类型系统还支持该类型的三个附加 cv 限定版本（const 、 volatile 及 const volatile）。

根据类型的各项性质，将它们分组到不同的类别之中：

  • 对象类型是非函数类型、非引用类型且非 void 类型的（可有 cv 限定的）类型（参阅 std::is_object）；
  • 标量类型是（可有 cv 限定的）算术、指针、成员指针、枚举和 std::nullptr_t (C++11 起) 类型（参阅 std::is_scalar）；
  • 平凡类型（参阅 std::is_trivial）、 POD 类型（参阅 std::is_pod）、字面类型（参阅 std::is_literal_type）和其他类别，列于类型特征库中，或作为具名类型要求。

类型的命名

通过以下方式来声明一个指代类型的名字：

  • 类声明；
  • 联合体声明；
  • 枚举声明；
  • typedef 声明；
  • 类型别名声明。

在 C++ 程序中对没有名字的类型常常需要被涉指；为此而设的语法被称为 类型标识。命名类型 T 的类型标识的语法与省略了标识符的对 T 类型的变量或函数的声明语法完全一致，但声明语法中的 声明说明符序列 被限制为 类型说明符序列 ，另外仅当类型标识出现于非模板类型别名声明的右侧时才可以定义新类型。

int* p;               // 声明一个指向 int 的指针
static_cast<int*>(p); // 类型标识为 "int*"

int a[3];   // 声明一个含有 3 个 int 的数组
new int[3]; // 类型标识为 "int[3]" （称作 new-类型标识）

int (*(*x[2])())[3];      // 声明一个含有 2 个函数指针的数组
                          // 这些函数指针指向的函数返回指向（含有 3 个 int 的数组）的指针
new (int (*(*[2])())[3]); // 类型标识为 "int (*(*[2])())[3]"

void f(int);                    // 声明一个接收 int 并返回 void 的函数
std::function<void(int)> x = f; // 类型模板形参为类型标识 "void(int)"
std::function<auto(int) -> void> y = f; // 同上

std::vector<int> v;       // 声明一个含有 int 的 vector
sizeof(std::vector<int>); // 类型标识为 "std::vector<int>"

struct { int x; } b;         // 创建一个新类型并声明该类型的一个对象 b
sizeof(struct{ int x; });    // 错误：不能在 sizeof 表达式中定义新类型
using t = struct { int x; }; // 创建一个新类型并声明 t 为该类型的一个别名

sizeof(static int); // 错误：存储类说明符并不是类型说明符序列的一部分
std::function<inline void(int)> f; // 错误：函数说明符也不是

声明文法的 声明符 部分在移除了名字后被称为 抽象声明符 。

类型标识可用于下列情形：

  • 指定转型表达式中的目标类型；
  • 作为 sizeof 、 alignof 、 alignas 、 new 和 typeid 的实参；
  • 在类型别名声明的右侧；
  • 作为函数声明的尾随返回类型；
  • 作为模板类型形参的默认实参；
  • 作为模板类型形参的模板实参；
  • 在动态异常规定中。

类型标识经过一些修改可用于下列情形：

  • 在函数形参列表中（省略形参名时），类型标识中的类型说明符序列以声明说明符序列代替（特别是允许使用某些存储类说明符）；
  • 在用户定义转换函数名中，抽象声明符不能包含函数或数组运算符。
本节未完成
原因：8.2[dcl.ambig.res] ，若能紧凑地总结
本节未完成
原因：提及并链接到 decltype 和 auto

详述类型说明符

详述类型说明符能用于指代先前声明过的类名（类、结构体或联合体）或先前声明过的枚举名，即使该名字被非类型声明隐藏。它们亦可用于声明新的类名。

详见详述类型说明符。

静态类型

对程序进行编译时分析所得到的表达式的类型被称为表达式的静态类型。程序执行时静态类型不会更改。

动态类型

若某个泛左值表达式指代某个多态对象，则其最终派生对象的类型被称为其动态类型。

// 给定
struct B { virtual ~B() {} }; // 多态类型
struct D: B {}; // 多态类型
D d; // 最终派生对象
B* ptr = &d;
// (*ptr) 的静态类型为 B
// (*ptr) 的动态类型为 D

对于纯右值表达式，动态类型始终与静态类型相同。

不完整类型

下列类型是不完整类型：

  • void 类型（可有 cv 限定）；
  • 不完整定义的对象类型：
    • 已声明（例如由前置声明）但未定义的类类型；
    • 未知边界数组；
    • 不完整类型元素的数组
    • 枚举类型，从其声明点到确定其底层类型之间。

下列语境都要求类型 T 完整：

  • 返回类型为 T 或参数类型为 T 的函数的定义或调用；
  • T 类型对象的定义;
  • T 类型非静态数据成员的声明；
  • T 类型对象或元素类型为 T 的数组的 new 表达式；
  • 对 T 类型泛左值实施的左值到右值转换；
  • 到 T 类型的隐式或显式转换；
  • 到 T* 或 T& 类型的 标准转换、dynamic_cast 或 static_cast，不包括从空指针常量或从 void 的指针进行的转换；
  • 对 T 类型表达式运用的类成员访问运算符；
  • 对 T 类型运用的 typeid、sizeof 或 alignof 运算符；
  • 对指向 T 的指针运用的算术运算符；
  • 带有基类 T 的类的定义；
  • 对 T 类型的左值的赋值；
  • 捕获 T、T& 或 T* 类型的异常的 catch 子句。

（通常在必须知道 T 的大小和布局时要求它完整。）

如果翻译单元中出现了这些情况中的任何情况，该类型的定义就必须在相同翻译单元中出现。否则不必出现。

不完整定义的对象类型可以变完整：

  • 类类型（例如 class X）可在翻译单元中的一处不完整而在其之后补充完整；类型 class X 在这两处相同：
class X;              // X 是不完整类型
extern X* xp;         // xp 是指向不完整类型的指针

void foo() {
  xp++;               // 非良构： X 不完整
}

struct X { int i; };  // 现在 X 是完整类型

X x;
void bar() {
  xp = &x;            // OK：类型是“指向 X 的指针”
  xp++;               // OK：X 完整
}
  • 数组对象的声明类型可以是不完整类类型的数组，从而它不完整；若类类型在翻译单元中的后面完整，则该数组类型变得完整；两处的数组类型相同。
  • 数组对象的声明类型可为未知边界数组，从而在翻译单元的一处不完整，并在之后变完整；两处的数组类型（“含有 T 的未知边界数组”与“含有 N 个 T 的元素数组”）不同。

未知边界数组的指针的类型，或由 typedef 声明定义为未知边界数组的类型，无法变得完整。

extern int arr[];   // arr 的类型不完整
typedef int UNKA[]; // UNKA 是不完整类型
UNKA* arrp;         // arrp 是指向不完整类型的指针
UNKA** arrpp;

void foo() {
  arrp++;           // 错误：不完整类型
  arrpp++;          // OK：UNKA* 的大小已知
}

int arr[10];        // 现在 arr 的类型完整了

void bar() {
  arrp = &arr;       // 错误：类型不同
  arrp++;           // 错误：UNKA 无法变得完整
}

参阅


构造函数与成员初始化器列表

< cpp‎ | language

构造函数是类的一种特殊的非静态成员函数，用于初始化该类类型的对象。

在类的构造函数定义中，成员初始化器列表指定各个直接基类、虚基类和非静态数据成员的初始化器。 （请勿与 std::initializer_list 混淆）

构造函数不能是协程。

 (C++20 起)

语法

构造函数用以下形式的成员函数声明符声明：

类名 ( 形参列表(可选) ) 异常说明(可选) 属性(可选) (1)

其中 类名 必须指名当前类（或类模板的当前实例化），或当在命名空间作用域或在友元声明中声明时，它必须是有限定的类名。

构造函数声明的 声明说明符序列 中只允许说明符 friend、inline 、constexpr (C++11 起)、consteval (C++20 起) 及 explicit（尤其是不允许返回类型）。注意 cv 及引用限定符也不受允许；const 与 volatile 语义对于构造过程中的对象没有效果，它们要到最终派生类的构造函数完成才会生效。

任何构造函数的函数定义的函数体可以在复合语句的开花括号之前包含成员初始化器列表，其语法是冒号字符 : 后随一个或多个 成员初始化器 的逗号分隔列表，每项均具有以下语法：

类或标识符 ( 表达式列表(可选) ) | (1) |
类或标识符 花括号初始化器列表 | (2) | (C++11 起)
形参包 ... | (3) | (C++11 起)
1) 用直接初始化，或当 表达式列表 为空时用值初始化，初始化 类或标识符 所指名的基类或成员
2) 用列表初始化（如果列表为空则为值初始化，而在初始化聚合体时为聚合初始化），初始化 类或标识符 所指名的基类或成员
3) 用包展开初始化多个基类
类或标识符 | - | 任何指名非静态数据成员的标识符，或任何指名该类自身（对于委托构造函数）、直接基类或虚基类的类型名。
表达式列表 | - | 传递给基类或成员的参数的逗号分隔列表，可以为空
花括号初始化器列表 | - | 花括号包围的以逗号分隔的初始化器和嵌套的花括号初始化器列表的列表
形参包 | - | 变参模板形参包的名字
struct S {
    int n;
    S(int); // 构造函数声明
    S() : n(7) {} // 构造函数定义
                  // ": n(7)" 是初始化器列表
                  // ": n(7) {}" 是函数体
};
S::S(int x) : n{x} {} // 构造函数定义：": n{x}" 是初始化器列表
int main()
{
    S s; // 调用 S::S()
    S s2(10); // 调用 S::S(int)
}

解释

构造函数没有名字且无法被直接调用。它们在发生初始化时调用，且它们按照初始化的规则进行选择。没有 explicit 说明符的构造函数是转换构造函数。有 constexpr 说明符的构造函数会让其类型成为字面类型 (LiteralType) 。可以不带任何实参调用的构造函数是默认构造函数。可以接收同类型的另一对象为实参的构造函数是复制构造函数和移动构造函数。

在开始执行组成构造函数体的复合语句之前，所有直接基类、虚基类和非静态数据成员的初始化均已结束。这些对象的非默认初始化只能在成员初始化器列表指定。对于不能默认初始化的基类或非静态数据成员，例如引用和 const 限定的类型的成员，必须指定成员初始化器。对没有成员初始化器的匿名联合体或变体成员不进行初始化。

类或标识符 指名虚基类的初始化器，在并非所构造对象的最终派生类的类的构造期间被忽略。

在 表达式列表 或 花括号初始化器列表 中出现的名字在构造函数的作用域中求值：

class X {
    int a, b, i, j;
public:
    const int& r;
    X(int i)
      : r(a) // 初始化 X::r 以指代 X::a
      , b{i} // 初始化 X::b 为形参 i 的值
      , i(i) // 初始化 X::i 为形参 i 的值
      , j(this->i) // 初始化 X::j 为 X::i 的值
    { }
};

成员初始化器所抛出的异常可以被函数 try 块处理。

成员函数（包括虚成员函数）可以从成员初始化器调用，但如果在该点还有直接基类尚未被初始化，那么行为未定义。

对于虚调用（如果在该点已初始化直接基类），适用与从构造函数与析构函数中进行虚函数调用相同的规则：虚成员函数表现如同 *this 的动态类型是正在构造的类的静态类型（动态派发不在继承层级下传），而对纯虚成员函数的虚调用（但非静态调用）是未定义行为。

如果非静态数据成员具有 默认成员初始化器且也在成员初始化器列表中出现，那么使用该成员初始化器而忽略默认成员初始化器：

struct S {
    int n = 42;   // 默认成员初始化器
    S() : n(7) {} // 将设置 n 为 7，而非 42
};
 (C++11 起)

引用成员不能绑定到成员初始化器列表中的临时量：

struct A {
    A() : v(42) { }  // 错误
    const int& v;
};

注：这同样适用于默认成员初始化器。

委托构造函数

如果类自身的名字在初始化器列表中作为 类或标识符 出现，那么该列表只能由这一个成员初始化器组成；这种构造函数被称为委托构造函数（delegating constructor），而构造函数列表的仅有成员所选择的构造函数是目标构造函数。

此时首先由重载决议选择目标构造函数并予以执行，然后控制返回到委托构造函数并执行其函数体。

委托构造函数不能递归。

class Foo {
public:
  Foo(char x, int y) {}
  Foo(int y) : Foo('a', y) {} // Foo(int) 委托到 Foo(char,int)
};

继承的构造函数

见 using 声明。

 (C++11 起)

初始化顺序

列表中的成员初始化器的顺序是不相关的：初始化的实际顺序如下：

1) 如果构造函数是最终派生类的，那么按基类声明的深度优先、从左到右的遍历中的出现顺序（从左到右指的是基说明符列表中所呈现的），初始化各个虚基类
2) 然后，以在此类的基类说明符列表中出现的从左到右顺序，初始化各个直接基类
3) 然后，以类定义中的声明顺序，初始化各个非静态成员。
4) 最后，执行构造函数体

（注意：如果初始化的顺序是由不同构造函数中的成员初始化器列表中的出现所控制，那么析构函数就无法确保销毁顺序是构造顺序的逆序了）

示例

#include <fstream>
#include <string>
#include <mutex>

struct Base {
    int n;
};

struct Class : public Base
{
    unsigned char x;
    unsigned char y;
    std::mutex m;
    std::lock_guard<std::mutex> lg;
    std::fstream f;
    std::string s;

    Class ( int x )
      : Base { 123 }, // 初始化基类
        x ( x ),      // x（成员）以 x（形参）初始化
        y { 0 },      // y 初始化为 0
        f{"test.cc", std::ios::app}, // 在 m 和 lg 初始化之后发生
        s(__func__),  //__func__ 可用，因为初始化器列表是构造函数的一部分
        lg ( m ),     // lg 使用已经初始化的 m
        m{}           // m 在 lg 前初始化，即使它最后出现在此处
    {}                // 空复合语句

    Class ( double a )
      : y ( a+1 ),
        x ( y ), // x 将在 y 前初始化，其值不确定
        lg ( m )
    {} // 基类初始化器未在列表中出现，它被默认初始化（这与使用 Base() 不同，那是值初始化）

    Class()
    try // 函数 try 块在包含初始化器列表的函数体之前开始
      : Class( 0.0 ) // 委托构造函数
    {
        // ...
    }
    catch (...)
    {
        // 初始化中发生的异常
    }
};

int main() {
    Class c;
    Class c1(1);
    Class c2(0.1);
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1696 | C++98 | 引用成员可被初始化为（生存期会在构造函数结尾结束的）临时量 | 这种初始化非良构

引用

  • C++11 标准（ISO/IEC 14882:2011）：
  • 12.1 Constructors [class.ctor]
  • 12.6.2 Initializing bases and members [class.base.init]
  • C++98 标准（ISO/IEC 14882:1998）：
  • 12.1 Constructors [class.ctor]
  • 12.6.2 Initializing bases and members [class.base.init]

参阅

  • 复制消除
  • 转换构造函数
  • 复制赋值
  • 复制构造函数
  • 默认构造函数
  • 析构函数
  • explicit
  • 初始化
    • 聚合初始化
    • 常量初始化
    • 复制初始化
    • 默认初始化
    • 直接初始化
    • 列表初始化
    • 引用初始化
    • 值初始化
    • 零初始化
  • 移动赋值
  • 移动构造函数
  • new


整数字面量

< cpp‎ | language

允许在表达式中直接使用整数类型的值。

语法

整数字面量拥有以下形式

十进制字面量 整数后缀(可选) | (1) |
八进制字面量 整数后缀(可选) | (2) |
十六进制字面量 整数后缀(可选) | (3) |
二进制字面量 整数后缀(可选) | (4) | (C++14 起)

其中

  • 十进制字面量 是一个非零十进制位（1、2、3、4、5、6、7、8、9）后随零或多个十进制位（0、1、2、3、4、5、6、7、8、9）
  • 八进制字面量 是数位零（0）后随零或多个八进制位（0、1、2、3、4、5、6、7）
  • 十六进制字面量 是字符序列 0x 或字符序列 0X 后随一或多个十六进制数位（0、1、2、3、4、5、6、7、8、9、a、A、b、B、c、C、d、D、e、E、f、F）
  • 二进制字面量 是字符序列 0b 或字符序列 0B 后随一或多个二进制位（0、1）
  • 若提供 整数后缀，则可含有下列一或两者（若均提供，则可以任意顺序出现）：
  • 无符号后缀（字符 u 或字符 U）
  • 以下之一
  • 长后缀（字符 l 或字符 L）
  • 长长后缀（字符序列 ll 或字符序列 LL）
 (C++11 起)
  • 大小后缀（字符 z 或字符 Z）
 (C++23 起)

数位间可插入作为分隔符的可选的单引号（'）。编译器会忽略它们。

 (C++14 起)

整数字面量（与任何字面量相同）是初等表达式。

解释

1) 十进制整数字面量（以 10 为底）
2) 八进制整数字面量（以 8 为底）
3) 十六进制整数字面量（以 16 为底，字母 'a' 到 'f' 表示（十进制）值 10 到 15）
4) 二进制整数字面量（以 2 为底）

整数字面量的首位为最高位。

例如，下列变量被初始化到相同值：

int d = 42;
int o = 052;
int x = 0x2a;
int X = 0X2A;
int b = 0b101010; // C++14

例如，下列变量也被初始化为相同值：

unsigned long long l1 = 18446744073709550592ull; // C++11
unsigned long long l2 = 18'446'744'073'709'550'592llu; // C++14
unsigned long long l3 = 1844'6744'0737'0955'0592uLL; // C++14
unsigned long long l4 = 184467'440737'0'95505'92LLU; // C++14

字面量的类型

整数字面量的类型，是依赖于所用数字基底和 整数后缀 的列表中，首个能适合其值的类型。

后缀 十进制底 二进制，十六进制或八进制底
（无后缀）
  • int
  • long int
  • long long int(C++11 起)
  • int
  • unsigned int
  • long int
  • unsigned long int
  • long long int(C++11 起)
  • unsigned long long int(C++11 起)
u 或 U
  • unsigned int
  • unsigned long int
  • unsigned long long int(C++11 起)
  • unsigned int
  • unsigned long int
  • unsigned long long int(C++11 起)
l 或 L
  • long int
  • unsigned long int(C++11 前)
  • long long int(C++11 起)
  • long int
  • unsigned long int
  • long long int(C++11 起)
  • unsigned long long int(C++11 起)
同时有 l/L 和 u/U
  • unsigned long int
  • unsigned long long int(C++11 起)
  • unsigned long int(C++11 起)
  • unsigned long long int(C++11 起)
ll 或 LL
  • long long int(C++11 起)
  • long long int(C++11 起)
  • unsigned long long int(C++11 起)
同时有 ll/LL 和 u/U
  • unsigned long long int(C++11 起)
  • unsigned long long int(C++11 起)
z 或 Z
  • std::size_t 的有符号版本(C++23 起)
  • std::size_t 的有符号版本(C++23 起)
  • std::size_t(C++23 起)
同时有 z/Z 和 u/U
  • std::size_t(C++23 起)
  • std::size_t(C++23 起)

若整数字面量的值过大，而无法符合任何后缀/底组合所允许的类型，且编译器支持扩展整数类型（如 __int128），则字面量可以被授予扩展整数类型——否则程序非良构。

注解

整数字面量中的字母是无关大小写的：0xDeAdBaBeU 与 0XdeadBABEu 表示同一数值（一个例外是 长长后缀，它是 ll 或 LL，而决不能是 lL 或 Ll） (C++11 起)

没有负整数字面量。如 -1 这样的表达式对字面量所表示的值运用一元减运算符，这可能涉及隐式转换。

在 C99 之前的 C 中（但不是 C++ 中），不符合 long int 的无后缀十进制值允许拥有类型 unsigned long int。

当用于 #if 或 #elif 的控制表达式时，全部有符号整数常量表现如同它们具有 std::intmax_t 类型，而全部无符号整数常量表现如同它们具有 std::uintmax_t 类型。

 (C++11 起)

由于最大吞噬规则，以 e 和 E 结束的十六进制整数字面量在后随运算符 + 或 - 时，源码中必须以空白符或括号将它们与运算符分隔：

auto x = 0xE+2.0;   // 错误
auto y = 0xa+2.0;   // OK
auto z = 0xE +2.0;  // OK
auto q = (0xE)+2.0; // OK

否则，将构成一个非法的预处理数字记号，并导致进一步的分析失败。

示例

#include <cstddef>
#include <iostream>
#include <type_traits>

int main()
{
std::cout << 123    << '\n'
          << 0123   << '\n'
          << 0x123  << '\n'
          << 0b10   << '\n'
          << 12345678901234567890ull << '\n'
          << 12345678901234567890u   << '\n'; // 类型是 unsigned long long
                                              // 即使无 long long 后缀

//   std::cout << -9223372036854775808 << '\n'; // 错误：值 9223372036854775808
                // 不吻合 signed long long，这是无后缀整数字面量允许的最大类型
     std::cout << -9223372036854775808u << '\n'; // 应用于无符号值的一元减
                // 从 2^64 减去该值，给出 9223372036854775808
     std::cout << -9223372036854775807 - 1 << '\n'; // 计算值 -9223372036854775808
                                                    // 的正确方式

#if __cpp_size_t_suffix >= 202011L // C++23
     static_assert(std::is_same_v<decltype(0UZ), std::size_t>);
     static_assert(std::is_same_v<decltype(0Z), std::make_signed_t<std::size_t>>);
#endif
}

输出：

123
83
291
2
12345678901234567890
12345678901234567890
9223372036854775808
-9223372036854775808

参阅

用户定义字面量 (C++11) 拥有用户定义后缀的字面量


Lambda 表达式 (C++11 起)

< cpp‎ | language

构造闭包：能够捕获作用域中的变量的无名函数对象。

语法

[ 捕获 ] ( 形参 ) lambda说明符 约束(可选) { 函数体 } | (1) |
[ 捕获 ] { 函数体 } | (2) | (C++23 前)
[ 捕获 ] lambda说明符 { 函数体 } | (2) | (C++23 起)
[ 捕获 ] <模板形参> 约束(可选) ( 形参 ) lambda说明符 约束(可选) { 函数体 } | (3) | (C++20 起)
[ 捕获 ] <模板形参> 约束(可选) { 函数体 } | (4) | (C++20 起) (C++23 前)
[ 捕获 ] <模板形参> 约束(可选) lambda说明符 { 函数体 } | (4) | (C++23 起)
1) 完整声明。
2) 省略形参列表：函数不接收实参，如同形参列表是 ()。
3) 与 1) 相同，但指定泛型 lambda 并显式提供模板形参列表。
4) 与 2) 相同，但指定泛型 lambda 并显式提供模板形参列表。

解释

捕获 - 包含零或更多个捕获符的逗号分隔列表，可以 默认捕获符（capture-default） 起始。

有关捕获符的详细描述，见下文。 如果变量满足下列条件，那么 lambda 表达式在使用它前不需要先捕获：

  • 该变量是非局部变量，或具有静态或线程局部存储期（此时无法捕获该变量），或者
  • 该变量是以常量表达式初始化的引用。

如果变量满足下列条件，那么 lambda 表达式在读取它的值前不需要先捕获：

  • 该变量具有 const 而非 volatile 的整型或枚举类型，并已经用常量表达式初始化，或者
  • 该变量是 constexpr 的且没有 mutable 成员。
<模板形参> - （角括号中的）模板形参列表，用于为泛型 lambda 提供各模板形参的名字（见下文的 闭包类型::operator()）。与在模板声明中相似，模板形参列表可以后附 requires 子句，它指定各模板实参上的约束。

模板形参列表不能为空（不允许 <>）。
形参 - 形参列表，如在具名函数中。
lambda说明符 - 由 说明符、 异常说明、 属性 和 尾随返回类型 按顺序组成，每个组分均非必需
说明符 - 可选的说明符的序列。不提供说明符时复制捕获的对象在 lambda 体内是 const 的。可以使用下列说明符：
  • mutable：允许 函数体 修改复制捕获的对象，以及调用它们的非 const 成员函数
  • constexpr：显式指定函数调用运算符或运算符模板的任意特化为 constexpr 函数。如果没有此说明符但函数调用运算符或任意给定的运算符模板特化恰好满足针对 constexpr 函数的所有要求，那么它也会是 constexpr 的
 (C++17 起)
  • consteval：指定函数调用运算符或任意给定的运算符模板特化为立即函数。不能同时使用 consteval 和 constexpr。
 (C++20 起)
异常说明 - 为闭包类型的 operator() 提供动态异常说明或 (C++20 前) noexcept 说明符
属性 - 为闭包类型的函数调用运算符或运算符模板的类型提供属性说明。这样指定的任何属性均属于函数调用运算符或运算符模板的类型，而非其自身。（例如不能使用 [[noreturn]] ）
尾随返回类型 - -> 返回类型 ，其中 返回类型 指定返回类型。如果没有 尾随返回类型，那么闭包的 operator() 的返回类型从 return 语句推导，如同对于声明返回类型为 auto 的函数的推导一样。
约束 - (C++20 起)向闭包类型的 operator() 添加约束
函数体 - 函数体

当以 auto 为形参类型或显式提供模板形参列表 (C++20 起)时，该 lambda 为泛型 lambda。

 (C++14 起)

lambda 表达式是纯右值表达式，它的类型是独有的无名非联合非聚合类类型，被称为闭包类型（closure type），它（对于 ADL 而言）在含有该 lambda 表达式的最小块作用域、类作用域或命名空间作用域声明。闭包类型有下列成员：

闭包类型::operator()(形参)

返回类型 operator()(形参) const { 函数体 } | (未使用关键词 mutable)
返回类型 operator()(形参) { 函数体 } | (使用了关键词 mutable)
template<模板形参> 返回类型 operator()(形参) const { 函数体 } | (C++14 起) (泛型 lambda)
template<模板形参> 返回类型 operator()(形参) { 函数体 } | (C++14 起) (泛型 lambda，使用了关键词 mutable)

当被调用时，执行 lambda 表达式的函数体。当访问变量时，访问的是其被捕获的副本（对于以复制捕获的实体）或原对象（对于以引用捕获的实体）。除非 lambda 表达式中使用了关键词 mutable，否则函数调用运算符或运算符模板会被 const 限定，且无法从这个 operator() 的内部修改以复制捕获的对象。函数调用运算符或运算符模板始终不被 volatile 限定且始终非虚。

如果函数调用运算符或任意给定的运算符模板特化满足针对 constexpr 函数的要求，那么它始终是 constexpr 的。如果关键词 constexpr 用于 lambda 声明，那么它也是 constexpr 的。

 (C++17 起)

如果在 lambda 表达式中使用关键词 consteval，那么函数调用运算符或任意给定的运算符模板特化是立即函数。

 (C++20 起)

对于 形参 中每个类型指定为 auto 的参数，以其出现顺序向 模板形参 中添加一个虚设的模板形参。当虚设的模板形参所对应的 形参 中的函数形参是函数形参包时，它可以是形参包。

// 泛型 lambda，operator() 是有两个形参的模板
auto glambda = [](auto a, auto&& b) { return a < b; };
bool b = glambda(3, 3.14); // ok

// 泛型 lambda，operator() 是有一个形参的模板
auto vglambda = [](auto printer) {
    return [=](auto&&... ts) // 泛型 lambda，ts 是形参包
    {
        printer(std::forward<decltype(ts)>(ts)...);
        return [=] { printer(ts...); }; // 零元 lambda （不接受形参）
    };
};
auto p = vglambda([](auto v1, auto v2, auto v3) { std::cout << v1 << v2 << v3; });
auto q = p(1, 'a', 3.14); // 输出 1a3.14
q();                      // 输出 1a3.14

闭包类型 的 operator() 不能被显式实例化或显式特化。

 (C++14 起)

如果 lambda 定义使用显式的模板形参列表，那么该模板形参列表会用于 operator()。对于 形参 中每个类型指定为 auto 的形参，都会有一个额外的虚设模板形参追加到模板形参列表尾部：

// 泛型 lambda，operator() 是有两个形参的模板
auto glambda = []<class T>(T a, auto&& b) { return a < b; };

// 泛型 lambda，operator() 是有一个形参包的模板
auto f = []<typename ...Ts>(Ts&& ...ts) {
   return foo(std::forward<Ts>(ts)...);
};
 (C++20 起)

lambda 表达式上的异常说明 异常说明 应用于函数调用运算符或运算符模板。

对于名字查找、确定 this 指针的类型和值以及对于访问非静态类成员而言，闭包类型的函数调用运算符的函数体被认为处于 lambda 表达式的语境中。

struct X {
    int x, y;
    int operator()(int);
    void f()
    {
        // 下列 lambda 的语境是成员函数 X::f
        [=]()->int
        {
            return operator()(this->x + y); // X::operator()(this->x + (*this).y)
                                            // this 拥有类型 X*
        };
    }
};

闭包类型 的 operator() 不能在友元声明中指名。

悬垂引用

如果以引用隐式或显式捕获非引用实体，而在该实体的生存期结束之后调用闭包对象的函数调用运算符或运算符模板特化，那么会发生未定义行为。C++ 的闭包并不延长以引用捕获的对象的生存期。

这同样适用于由 this 捕获对当前 *this 对象。

闭包类型::operator 返回类型(*)(形参)()

无捕获的非泛型 lambda
using F = 返回类型(*)(形参);
operator F() const noexcept;
 (C++17 前)
using F = 返回类型(*)(形参);
constexpr operator F() const noexcept;
 (C++17 起)
无捕获的泛型 lambda
template<模板形参> using fptr_t = /*见下文*/;

template<模板形参>

operator fptr_t<模板形参>() const noexcept;
 (C++14 起)
(C++17 前)
template<模板形参> using fptr_t = /*见下文*/;

template<模板形参>

constexpr operator fptr_t<模板形参>() const noexcept;
 (C++17 起)

只有在 lambda 表达式的捕获符列表为空时才定义这个用户定义转换函数。它是闭包对象的公开、constexpr、 (C++17 起)非虚、非 explicit、const noexcept 成员函数。

如果函数调用运算符（或对于泛型 lambda 为其特化）是立即函数，那么此函数是立即函数。

 (C++20 起)

泛型无捕获 lambda 拥有一个用户定义的转换函数模板，它具有与函数调用运算符模板相同的虚设模板形参列表。如果它的返回类型为空或 auto，那么将由函数模板特化上的返回类型推导获得，而它会以转换函数模板的模板实参推导获得。

void f1(int (*)(int)) {}
void f2(char (*)(int)) {}
void h(int (*)(int)) {} // #1
void h(char (*)(int)) {} // #2
auto glambda = [](auto a) { return a; };
f1(glambda); // OK
f2(glambda); // 错误：不可转换
h(glambda); // OK：调用 #1，因为 #2 不可转换

int& (*fpi)(int*) = [](auto* a)->auto& { return *a; }; // OK
 (C++14 起)

这个转换函数所返回一个指向具有 C++ 语言连接的函数指针，调用该函数的效果与直接调用闭包对象的函数调用运算符相同。

如果函数调用运算符（或对于泛型 lambda 为其特化）是 constexpr 的，那么此函数也是 constexpr 的。

auto Fwd= [](int(*fp)(int), auto a){return fp(a);};
auto C=[](auto a){return a;};
static_assert(Fwd(C,3)==3);// OK
auto NC=[](auto a){ static int s; return a;};
static_assert(Fwd(NC,3)==3); // 错误：因为 static s 而不能为 constexpr 的特化

如果闭包对象的 operator() 具有无抛出异常说明，那么此函数返回的指针具有指向 noexcept 函数的指针类型。 (C++20 前)

 (C++17 起)

闭包类型::闭包类型()

闭包类型() = delete; |
闭包类型() = default; | (C++20 起) (仅当未指定任何捕获时)
闭包类型(const 闭包类型& ) = default; |
闭包类型(闭包类型&& ) = default; |
闭包类型非可默认构造 (DefaultConstructible) 。闭包类型没有默认构造函数。 | (C++20 前)
如果没有指定 捕获，那么闭包类型拥有预置的默认构造函数。否则，它没有默认构造函数（这包含有 默认捕获符（capture-default） 的情况，即使它实际上没有捕获任何变量）。 | (C++20 起)

复制构造函数与移动构造函数声明为预置，并可能按照复制构造函数与移动构造函数的通常规则隐式定义。

闭包类型::operator=(const 闭包类型&)

闭包类型& operator=(const 闭包类型&) = delete;
 (C++20 前)
闭包类型& operator=(const 闭包类型&) = default;
闭包类型& operator=(闭包类型&&) = default;
 (C++20 起)
(仅当未指定任何捕获时)
闭包类型& operator=(const 闭包类型&) = delete;
 (C++20 起)
(其他情况)
复制赋值运算符被定义为弃置的（且未声明移动赋值运算符）。闭包类型非可复制赋值 (CopyAssignable) 。 | (C++20 前)
如果没有指定 捕获，那么闭包类型拥有预置的复制赋值运算符和预置的移动赋值运算符。否则，它拥有弃置的复制赋值运算符（这包含有 默认捕获符 的情况，即使它实际上没有捕获任何变量）。 | (C++20 起)

闭包类型::~闭包类型()

~闭包类型() = default;

析构函数是隐式声明的。

闭包类型::捕获

T1 a;

T2 b;

...

如果 lambda 表达式以复制（隐式地以捕获子句 [=] 或显式地以不含字符 & 的捕获符，例如 [a, b, c]）捕获了任何内容，那么闭包类型包含保有所有被如此捕获的实体的副本的无名非静态数据成员，它们以未指明的顺序声明。

如果数据成员对应的捕获符没有初始化器，那么它们在求值 lambda 表达式时被直接初始化。如果有初始化器，那么按其初始化器的要求初始化（可为复制或直接初始化）。如果捕获了数组，那么各数组元素以下标递增顺序直接初始化。初始化各数据成员所用的顺序是它们的声明顺序（即未指明）。

每个数据成员的类型是其对应被捕获实体的类型，除非实体拥有引用类型（此时到函数的引用被捕获为到被引用函数的左值引用，而到对象的引用被捕获为被引用对象的副本）。

对于以引用捕获（以默认捕获符 [&] 或使用了字符 &，例如 [&a, &b, &c]）的实体，闭包类型中是否声明额外的数据成员是未指明的，但任何这种附加成员必须满足字面类型 (LiteralType) (C++17 起)。

不允许在不求值表达式、模板实参、别名声明、typedef 声明，以及函数（或函数模板）声明中除了函数体和函数的默认实参以外的任何位置中出现 lambda 表达式。

本节未完成
原因：详细阐述 C++20 对此的变更
(C++20 前)

Lambda 捕获

捕获 是一个含有零或更多个捕获符的逗号分隔列表，可以 默认捕获符 开始。默认捕获符只有

  • &（以引用隐式捕获被使用的自动变量）和
  • = （以复制隐式捕获被使用的自动变量）。

当出现任一默认捕获符时，都能隐式捕获当前对象（*this）。当它被隐式捕获时，始终被以引用捕获，即使默认捕获符是 =。当默认捕获符为 = 时，*this 的隐式捕获被弃用。 (C++20 起)

捕获 中单独的捕获符的语法是

标识符 | (1) |
标识符 ... | (2) |
标识符 初始化器 | (3) | (C++14 起)
& 标识符 | (4) |
& 标识符 ... | (5) |
& 标识符 初始化器 | (6) | (C++14 起)
this | (7) |
* this | (8) | (C++17 起)
... 标识符 初始化器 | (9) | (C++20 起)
& ... 标识符 初始化器 | (10) | (C++20 起)
1) 简单以复制捕获
2) 作为包展开的简单以复制捕获
3) 带初始化器的以复制捕获
4) 简单以引用捕获
5) 作为包展开的简单引用捕获
6) 带初始化器的以引用捕获
7) 当前对象的简单以引用捕获
8) 当前对象的简单以复制捕获
9) 用作为包展开的初始化器以复制捕获
10) 用作为包展开的初始化器以引用捕获

当默认捕获符是 & 时，后继的简单捕获符不能以 & 开始。

struct S2 { void f(int i); };
void S2::f(int i)
{
    [&]{};          // OK：默认以引用捕获
    [&, i]{};       // OK：以引用捕获，但 i 以值捕获
    [&, &i] {};     // 错误：以引用捕获为默认时的以引用捕获
    [&, this] {};   // OK：等价于 [&]
    [&, this, i]{}; // OK：等价于 [&, i]
}

当默认捕获符是 = 时，后继的简单捕获符必须以 & 开始，或者为 *this (C++17 起) 或 this (C++20 起)。

struct S2 { void f(int i); };
void S2::f(int i)
{
    [=]{};          // OK：默认以复制捕获
    [=, &i]{};      // OK：以复制捕获，但 i 以引用捕获
    [=, *this]{};   // C++17 前：错误：无效语法
                    // C++17 起：OK：以复制捕获外围的 S2
    [=, this] {};   // C++20 前：错误：= 为默认时的 this
                    // C++20 起：OK：同 [=]
}

任何捕获符只可以出现一次：

struct S2 { void f(int i); };
void S2::f(int i)
{
    [i, i] {};        // 错误：i 重复
    [this, *this] {}; // 错误："this" 重复 (C++17)
}

只有定义于块作用域或默认成员初始化器中的 lambda 表达式能拥有默认捕获符或无初始化器的捕获符。对于这种 lambda 表达式，其可达作用域（reaching scope）定义为其最内层的外围函数（及其形参）内（包含自身）的外围作用域的集合。这其中包含各个嵌套的块作用域，以及当此 lambda 为嵌套的 lambda 时也包含其各个外围 lambda 的作用域。

（除了 this 捕获符之外的）任何无初始化器的捕获符中的 标识符 会使用通常的无限定名字查找在 lambda 的可达作用域中查找。查找结果必须是在可达作用域中声明的且具有自动存储期的变量 ，或对应变量满足这种要求的结构化绑定 (C++20 起)。该实体被显式捕获。

带有初始化器的捕获符的行为如同它声明并显式捕获一个以类型 auto 声明的变量，该变量的声明区是 lambda 表达式体（即它不在其初始化器的作用域中），但：

  • 如果以复制捕获，那么闭包对象的非静态数据成员是指代这个 auto 变量的另一种方式。
  • 如果以引用捕获，那么引用变量的生存期在闭包对象的生存期结束时结束。

这可以用于以像 x = std::move(x) 这样的捕获符捕获仅可移动的类型。

这也可以使通过 const 引用进行捕获成为可能，比如以 &cr = std::as_const (x) 或类似的方式。

int x = 4;
auto y = [&r = x, x = x + 1]()->int
    {
        r += 2;
        return x * x;
    }(); // 更新 ::x 到 6 并初始化 y 为 25。
 (C++14 起)

如果捕获符列表具有默认捕获符，且未显式（以 this 或 *this）捕获其外围对象，或任何在 lambda 体内可 odr 式使用的自动变量，或对应变量拥有自动存储期的结构化绑定 (C++20 起)，那么在以下情况下，它隐式捕获之：

  • lambda 体 ODR 式使用了该实体
  • 或者，该实体在取决于某个泛型 lambda 形参的 (C++17 前)表达式内的潜在求值表达式中被指名（包括在使用非静态类成员的前添加隐含的 this->）。就此目的而言，始终认为 typeid 的操作数被潜在求值。即使实体仅在舍弃语句中被指名，它也可能会被隐式捕获。 (C++17 起)
void f(int, const int (&)[2] = {}) {} // #1
void f(const int&, const int (&)[1]) {} // #2
void test()
{
    const int x = 17;
    auto g0 = [](auto a) { f(x); }; // OK：调用 #1，不捕获 x
    auto g1 = [=](auto a) { f(x); }; // C++14 中不捕获 x，C++17 中捕获 x
                                     // 捕获能被优化掉
    auto g2 = [=](auto a) {
            int selector[sizeof(a) == 1 ? 1 : 2] = {};
            f(x, selector); // OK：这是待决表达式，因此 x 被捕获
    };
    auto g3 = [=](auto a) {
      typeid(a + x);  // 捕获 x，不管 a + x 是否为不求值操作数
    };
}
 (C++14 起)

如果 lambda 体 ODR 式使用了以复制捕获的实体，那么它访问的是闭包类型的成员。如果它未 ODR 式使用该实体，那么访问的是原对象：

void f(const int*);
void g()
{
    const int N = 10;
    [=]{
        int arr[N]; // 非 ODR 式使用：指代 g 的 const int N
        f(&N); // ODR 式使用：导致 N 被（以复制）捕获
               // &N 是闭包对象的成员 N 的地址，而非 g 中的 N
    }();
}
如果 lambda ODR 式使用了以引用捕获的引用，那么它使用原引用所指代的对象，而非被捕获的引用自身：
#include <iostream>

auto make_function(int& x) {
  return [&]{ std::cout << x << '\n'; };
}

int main() {
  int i = 3;
  auto f = make_function(i); // f 中对 x 的使用直接绑定到 i
  i = 5;
  f(); // OK；打印 5
}

在带默认捕获符 = 的 lambda 体内，任何可捕获对实体的类型为如同它被捕获（从而若 lambda 非 mutable 则通常会加上 const 限定），即使该实体在不求值运算数中且未被捕获（例如在 decltype 中）：

void f3() {
    float x, &r = x;
    [=]
    { // x 与 r 不被捕获（在 decltype 的操作数中出现并不是 ODR 式使用）
        decltype(x) y1; // y1 拥有 float 类型
        decltype((x)) y2 = y1; // y2 拥有 float const& 类型，因为此 lambda
                               // 非 mutable 且 x 是左值
        decltype(r) r1 = y1;   // r1 拥有 float& 类型（不考虑变换）
        decltype((r)) r2 = y2; // r2 拥有 float const& 类型
    };
}

lambda （隐式或显式）捕获的任何实体均被该 lambda 表达式 ODR 式使用（因此嵌套的 lambda 的隐式捕获将触发其外围 lambda 的隐式捕获）。

所有隐式捕获的变量必须在 lambda 的可达作用域中声明。

如果 lambda（以 this 或 *this）捕获了其外围对象，那么要么其最接近的外围函数必须是非静态成员函数，要么该 lambda 必须处于某个默认成员初始化器中：

struct s2 {
  double ohseven = .007;
  auto f() { // 以下两个 lambda 的最接近外围函数
    return [this] { // 以引用捕获外围的 s2
      return [*this] { // 以复制捕获外围的 s2  (C++17)
          return ohseven; // OK
       }
     }();
  }
  auto g() {
     return []{ // 无捕获
         return [*this]{}; // 错误：*this 未被外层 lambda 表达式所捕获
      }();
   }
};

如果 lambda 表达式（或泛型 lambda 的函数调用运算符的一个实例化） (C++14 起) ODR 式使用了 this 或任何具有自动存储期的变量，那么它必须被该 lambda 表达式所捕获。

void f1(int i)
{
    int const N = 20;
    auto m1 = [=] {
            int const M = 30;
            auto m2 = [i] {
                    int x[N][M]; // N 与 M 未被 ODR 式使用
                                 // （它们可以不被捕获）
                    x[0][0] = i; // i 被 m2 显式捕获
                                 // 并被 m1 隐式捕获
            };
    };

    struct s1 // f1() 中的局部类
    {
        int f;
        void work(int n) // 非静态成员函数
        {
            int m = n * n;
            int j = 40;
            auto m3 = [this, m] {
                auto m4 = [&, j] { // 错误：j 未被 m3 捕获
                        int x = n; // 错误：n 被 m4 隐式捕获
                                   // 但未被 m3 捕获
                        x += m;    // OK：m 被 m4 捕获
                                   // 且被 m3 显式捕获
                        x += i;    // 错误：i 在可达作用域之外
                                   // （该作用域在 work() 结束）
                        x += f;    // OK：this 被 m4 隐式捕获
                                   // 且被 m3 显式捕获
                };
            };
        }
    };
}

以不带有初始化器的捕获符不能捕获类成员（如上提及，捕获符列表中只能有变量）：

class S {
  int x = 0;
  void f() {
    int i = 0;
//  auto l1 = [i, x]{ use(i, x); };    // 错误：x 不是变量
    auto l2 = [i, x=x]{ use(i, x); };  // OK，复制捕获
    i = 1; x = 1; l2(); // 调用 use(0,0)
    auto l3 = [i, &x=x]{ use(i, x); }; // OK，引用捕获
    i = 2; x = 2; l3(); // 调用 use(1,2)
  }
};

当 lambda 用隐式的以复制捕获捕获某个成员时，它并不产生该成员变量的副本：对成员变量 m 的使用被处理成表达式 (*this).m，而 *this 始终被隐式以引用捕获：

class S {
  int x = 0;
  void f() {
    int i = 0;
    auto l1 = [=]{ use(i, x); }; // 捕获 i 的副本和 this 指针的副本
    i = 1; x = 1; l1(); // 调用 use(0,1)，如同 i 以复制而 x 以引用捕获
    auto l2 = [i, this]{ use(i, x); }; // 同上，改为显式捕获
    i = 2; x = 2; l2(); // 调用 use(1,2)，如同 i 以复制而 x 以引用捕获
    auto l3 = [&]{ use(i, x); }; // 以引用捕获 i，并捕获 this 指针的副本
    i = 3; x = 2; l3(); // 调用 use(3,2)，如同 i 与 x 均以引用捕获
    auto l4 = [i, *this]{ use(i, x); }; // 制造 *this 的副本，包含 x 的副本
    i = 4; x = 4; l4(); // 调用 use(3,2)，如同 i 与 x 均以复制捕获
  }
};

如果 lambda 表达式在默认实参中出现，那么它不能显式或隐式捕获任何变量。

不能捕获匿名联合体的成员。只能以复制捕获位域。

如果嵌套的 lambda m2 捕获了也被其直接外围 lambda m1 所捕获的实体，那么以如下方式将 m2 的捕获进行变换：

  • 如果外围 lambda m1 以复制捕获，那么 m2 捕获 m1 的闭包类型的非静态成员，而非原变量或 this。
  • 如果外围 lambda m1 以引用捕获，那么 m2 捕获原变量或 this。
#include <iostream>

int main()
{
    int a = 1, b = 1, c = 1;

    auto m1 = [a, &b, &c]() mutable {
        auto m2 = [a, b, &c]() mutable {
            std::cout << a << b << c << '\n';
            a = 4; b = 4; c = 4;
        };
        a = 3; b = 3; c = 3;
        m2();
    };

    a = 2; b = 2; c = 2;

    m1();                             // 调用 m2() 并打印 123
    std::cout << a << b << c << '\n'; // 打印 234
}

示例

此示例演示如何传递 lambda 给泛型算法，以及 lambda 表达式所产生的对象能如何存储于 std::function 对象。

#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>

int main()
{
    std::vector<int> c = {1, 2, 3, 4, 5, 6, 7};
    int x = 5;
    c.erase(std::remove_if(c.begin(), c.end(), [x](int n) { return n < x; }), c.end());

    std::cout << "c: ";
    std::for_each(c.begin(), c.end(), [](int i){ std::cout << i << ' '; });
    std::cout << '\n';

    // 闭包的类型不能被指名，但可用 auto 提及
    // C++14 起，lambda 可以有默认实参
    auto func1 = [](int i = 6) { return i + 4; };
    std::cout << "func1: " << func1() << '\n';

    // 与所有可调用对象相同，闭包能可以被捕获到 std::function 之中
    // （这可能带来不必要的开销）
    std::function<int(int)> func2 = [](int i) { return i + 4; };
    std::cout << "func2: " << func2(6) << '\n';

    std::cout << "模仿递归 lambda 调用：\n斐波那契数：";
    auto nth_fibonacci = [](int n) {
        std::function<int(int,int,int)> fib = [&](int a, int b, int n) {
            return n ? fib(a + b, a, n - 1) : b;
        };
        return fib(1, 0, n);
    };
    for (int i{1}; i != 9; ++i) { std::cout << nth_fibonacci(i) << ", "; }

    std::cout << "\n另一种 lambda 递归方案：\n斐波那契数：";
    auto nth_fibonacci2 = [](int n) {
        auto fib = [](auto self, int a, int b, int n) -> int {
            return n ? self(self, a + b, a, n - 1) : b;
        };
        return fib(fib, 1, 0, n);
    };
    for (int i{1}; i != 9; ++i) { std::cout << nth_fibonacci2(i) << ", "; }
}

输出：

c: 5 6 7
func1: 10
func2: 10
模仿递归 lambda 调用：
斐波那契数：1, 1, 2, 3, 5, 8, 13, 21,
另一种 lambda 递归方案：
斐波那契数：1, 1, 2, 3, 5, 8, 13, 21,

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 974 | C++11 | lambda 表达式的形参列表中不能有默认实参 | 允许
CWG 975 | C++11 | 只有在 lambda 体含有单条 return 语句时 才推导闭包的 operator() 的返回类型 | 如同对于 C++14 返回 auto 的函数一般推导
CWG 1722 | C++11 | 无捕获的 lambda 的转换函数的异常说明未指明 | 转换函数为 noexcept
CWG 1891 | C++11 | 闭包带有弃置的默认构造函数和隐含的复制/移动构造函数 | 无默认及预置的复制/移动

参阅

auto 说明符 (C++11) | 指定从表达式推导的类型
function (C++11) | 包装具有指定函数调用签名的任意可复制构造类型的可调用对象 (类模板)


语言链接

< cpp‎ | language

提供以不同程序语言编写的模块间的链接。

extern 字符串字面量 { 声明序列(可选) } | (1)
extern 字符串字面量 声明 | (2)
1) 将语言说明 字符串字面量 应用到声明于 声明序列 中的所有函数类型，具有外部链接的函数名，和具有外部链接的变量。
2) 将语言说明 字符串字面量 应用到单一声明或定义。
字符串字面量 | - | 所要求的语言链接的名字
声明序列 | - | 声明的序列，可以包含嵌套的链接说明
声明 | - | 一个声明

解释

所有函数类型，所有拥有外部链接的函数名，及所有拥有外部链接的变量名，拥有一种称作语言链接的性质。语言链接封装与以另一程序语言编写的模块进行链接的要求的集合：调用约定、名字重整的算法，等等。

只有以下两种语言链接保证受支持：

  1. "C++"，默认的语言链接。
  2. "C"，使得以 C 程序语言编写的函数进行链接，以及在 C++ 程序中定义能从 C 模块调用的函数成为可能。
extern "C"
{
    int open(const char *pathname, int flags); // C 函数声明
}

int main()
{
    int fd = open("test.txt", 0); // 从 C++ 程序调用 C 函数
}

// 此 C++ 函数能从 C 代码调用
extern "C" void handler(int)
{
    std::cout << "Callback invoked\n"; // 它能使用 C++
}

因为语言链接是每个函数类型的一部分，所以函数指针也要维持语言链接。函数类型的语言链接（表示调用约定）和函数名的语言链接（表示名字重整）是彼此独立的：

extern "C" void f1(void(*pf)()); // 声明一个具有 C 链接的函数 f1，
                             // 它返回 void 并接受一个指向返回 void 且不接受形参的 C 函数的指针

extern "C" typedef void FUNC(); // 声明 FUNC 为返回 void 且不接受形参的 C 函数类型

FUNC f2;            // 名字 f2 拥有 C++ 链接，但其类型是 C 函数
extern "C" FUNC f3; // 名字 f3 拥有 C 链接且其类型是 C 函数 void(void)
void (*pf2)(FUNC*); // 名字 pf2 拥有 C++ 链接，且其类型是“指向返回 void 并接受
                    // 一个‘指向返回 void 且不接受形参的 C 函数的指针’的 C++ 函数的指针

extern "C"
{
    static void f4(); // 函数 f4 的名字拥有内部链接（无语言）
                      // 但函数的类型拥有 C 语言链接
}

在同一命名空间中具有相同名字和相同形参列表的两个函数不能拥有两个不同的语言链接（然而需要注意，形参的链接可容许这种重载，例如 std::qsort 和 std::bsearch 的情况）。类似地，同一命名空间中的两个变量不能拥有两种不同的语言链接。

"C" 链接的特殊规则

  1. 当类成员的声明和成员函数类型的声明出现于 "C" 语言块中时，其链接仍保持为 "C++"。
  2. 当两个拥有同一无限定名字的函数声明于不同命名空间，且都拥有 "C" 语言链接时，两个声明表示同一函数。
  3. 当两个拥有 "C" 语言链接和相同名字的变量出现于不同命名空间时，它们表示同一变量。
  4. 一个 "C" 变量和一个 "C" 函数不能拥有相同的名字，与它们是否定义于同一命名空间无关。

注解

语言链接只能在命名空间作用域出现。

语言说明的花括号不建立作用域。

当语言说明发生嵌套时，只有最内层的说明会生效。

函数可以在带语言说明的声明之后，进行不带链接说明的重声明，第二个声明将重复使用首个声明的语言链接。反之则不行：如果首个声明无语言链接，那么链接会被假定为 "C++"，而以其他语言链接重声明则会导致错误。

直接包含于语言链接说明之中的声明，被处理为如同它含有 extern 说明符，用以确定所声明的名字的链接以及它是否为定义。

extern "C" int x; // 声明且非定义
// 上一行等价于 extern "C" { extern int x; }

extern "C" { int x; } // 声明及定义

extern "C" double f();
static double f(); // 错误：链接冲突

extern "C" static void g(); // 错误：链接冲突

extern "C" 允许 C++ 程序中包含（include）含有 C 库函数的声明的头文件，但如果与 C 程序共用相同的头文件，就必须以适当的 #ifdef 隐藏 extern "C"（C 中不允许使用），通常为 __cplusplus：

#ifdef __cplusplus
extern "C" int foo(int, int); // C++ 编译器所见
#else
int foo(int, int);            // C 编译器所见
#endif

在现代编译器中，只有 Oracle Studio 区分带 "C" 与 "C++" 语言链接的函数类型，其他编译器不允许只在语言链接有区别的重载，包括 C++ 标准要求的重载集（ std::qsort、 std::bsearch、 std::signal、 std::atexit 及 std::at_quick_exit ）： GCC bug 2316 、 Clang bug 6277 、 CWG1555 。

extern "C"   using c_predfun   = int(const void*, const void*);
extern "C++" using cpp_predfun = int(const void*, const void*);

// 非良构，但为大多数编译器接受
static_assert(std::is_same<c_predfun, cpp_predfun>::value,
              "C 和 C++ 语言链接不应区分函数类型。");

// 多数编译器中下列声明不声明重载
// 因为 c_predfun 与 cpp_predfun 被认为是同一类型
void qsort(void* base, std::size_t nmemb, std::size_t size, c_predfun*   compar);
void qsort(void* base, std::size_t nmemb, std::size_t size, cpp_predfun* compar);

D缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 4 | C++98 | 具有内部链接的名字可以有语言链接 | 只有具有外部链接的名字才可以

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 9.11 Linkage specifications [dcl.link]
  • C++17 标准（ISO/IEC 14882:2017）：
  • 10.5 Linkage specifications [dcl.link]
  • C++14 标准（ISO/IEC 14882:2014）：
  • 7.5 Linkage specifications [dcl.link]
  • C++11 标准（ISO/IEC 14882:2011）：
  • 7.5 Linkage specifications [dcl.link]
  • C++03 标准（ISO/IEC 14882:2003）：
  • 7.5 Linkage specifications [dcl.link]


生存期

< cpp‎ | language

每个对象和引用都有生存期 (lifetime) ，这是一项运行时性质：每个对象或引用在程序执行时都存在一个时刻开始其生存期，也都存在一个时刻结束其生存期。

对象的生存期始于：

  • 获得拥有其类型的正确大小与对齐的存储，并且
  • 完成其初始化（若存在）（包括不经由构造函数或经由平凡默认构造函数的默认初始化），除非
  • 若该对象是联合体成员或其子对象，则其生存期在该联合体成员是联合体中的被初始化成员，或它被设为活跃才开始，或者
  • 若该对象内嵌于联合体对象，则其生存期开始于平凡特殊成员函数赋值或构造含有它的联合体对象，或者
  • 数组对象的生存期可以因为该对象被 std::allocator::allocate 分配而开始。

某些操作在给定的存储区域中隐式创建对象，并开始其生存期，这些对象拥有隐式生存期类型（见后述）。

对象的生存期结束于：

  • 若它拥有非类类型，则为销毁该对象时（可能经由伪析构函数调用），或者
  • 若它拥有类类型，则为析构函数调用开始时，或者
  • 该对象所占据的存储被释放，或被不内嵌于它的对象所重用。

对象的生存期与它的存储的生存期相同，或者内嵌于其中，参见存储期。

引用的生存期，从其初始化完成之时开始，并与标量对象以相同的方式结束。

注意：被引用对象的生存期可能在引用的生存期结束之前就会结束，这会造成悬垂引用。

非静态数据成员和基类子对象的生存期，按照类初始化顺序开始和结束。

隐式生存期类型

一个对象类型被称为隐式生存期类型，若它是：

  • 标量类型，或
  • 数组类型，或
  • 聚合类类型，或
  • 拥有下列成员的类类型
  • 至少一个平凡的合格构造函数，以及
  • 一个平凡且未被删除的析构函数，
  • 或上述类型之一的 cv 限定版本。

注意若隐式创建的对象的子对象不拥有隐式生存期类型，则其生存期不会隐式开始。

临时对象的生存期

在下列情况中进行纯右值的实质化，从而能将它作为泛左值使用，即 (C++17 起)创建临时对象：

  • 绑定引用到纯右值
  • 以花括号初始化器列表初始化 std::initializer_list <T> 类型的对象时
 (C++11 起)
  • 函数返回纯右值
  • 创建纯右值的类型转换，包括 T(a,b,c) 与 T{}），
  • lambda 表达式
 (C++11 起)
  • 要求对初始化器进行类型转换的复制初始化，
  • 将引用绑定到不同但可以转换的类型，或绑定到位域。
 (C++17 前)
  • 当对类类型的纯右值进行成员访问时
  • 当对数组纯右值进行数组向指针转换或者下标运算时
  • 对 sizeof 和 typeid 的不求值操作数
  • 当纯右值被用作弃值表达式时
  • 如果实现支持的话，在函数调用表达式中传递或者返回可平凡复制 (TriviallyCopyable) 的类型的对象（这对应的是在 CPU 寄存器中传递结构体的情况）时
  • 临时对象的实质化通常会尽可能地被推迟，以免创建不必要的临时对象：参见复制消除
 (C++17 起)

所有临时对象的销毁都是在（词法上）包含创建它的位置的全表达式的求值过程的最后一步进行的，而当创建了多个临时对象时，它们是以其创建的相反顺序销毁的。即便求值过程以抛出异常而终止也是如此。

对此有两种例外情况：

  • 可以通过绑定到 const 左值引用或右值引用 (C++11 起)来延长临时对象的生存期，细节见引用初始化。
  • 在对数组的某个元素使用含有默认实参的默认或复制构造函数进行初始化时，对该默认实参求值所创建的临时对象的生存期将在该数组的下一个元素的初始化开始之前终止。

存储的重用

如果对象可平凡析构，或者程序并不依赖析构函数中的副作用的话，程序不必调用该对象的析构函数。然而如果程序显式终止非可平凡析构对象的生存期的话，它必须确保在可能隐式地调用析构函数前（例如对于自动对象是由于退出作用域或发生异常，对于线程局部对象是由于线程退出，或对于静态对象是由于程序退出），原位构造（比如使用布置 new ）一个新的同类型对象；否则行为未定义。

class T {}; // 平凡
struct B {
    ~B() {} // 非平凡
};
void x() {
    long long n; // 自动、平凡
    new (&n) double(3.14); // 以不同的类型进行重用没有问题
} // OK
void h() {
    B b; // 自动的非可平凡析构对象
    b.~B(); // 生存期结束（不必要，因为没有副作用）
    new (&b) T; // 类型错误：直到析构函数被调用之前都没问题
} // 调用了析构函数：未定义行为

重用某个具有静态、线程局部或者自动存储期的 const 完整对象所占据的存储是未定义行为，因为这种对象可能被存储于只读内存中。

struct B {
    B(); // 非平凡
    ~B(); // 非平凡
};
const B b; // const 静态对象
void h() {
    b.~B(); // b 的生存期结束
    new (const_cast<B*>(&b)) const B; // 未定义行为：试图重用 const 对象
}

一旦在某个对象所曾占据的地址上创建了新的对象，所有原对象的指针、引用及名字都会自动代表新的对象，而且一旦新对象的生存期开始，它们就可以用于操作这个新对象，但仅当新对象可透明替换旧对象才可以。

对象 y 可透明替换对象 x ，若：

  • y 的存储准确地与 x 所占据的存储位置重叠
  • y 与 x 拥有相同类型（忽略顶层 cv 限定符）
  • x 不是完整 const 对象
  • x 与 y 均不是基类子对象，或以 [[no_unique_address]] 声明的成员子对象 (C++20 起)
  • 要么
  • x 与 y 都是完整对象，或
  • x 与 y 分别为对象 ox 与 oy 的直接子对象，而 oy 可透明替换 ox。
struct C {
  int i;
  void f();
  const C& operator=( const C& );
};
const C& C::operator=( const C& other) {
  if ( this != &other ) {
    this->~C();          // *this 的生存期结束
    new (this) C(other); // 创建了 C 类型的新对象
    f();                 // 定义明确的
  }
  return *this;
}
C c1;
C c2;
c1 = c2; // 定义明确的
c1.f();  // 定义明确的；c1 代表 C 类型的一个新对象

如果未能满足以上所列出的各项条件的话，还可以通过采用指针优化屏障 std::launder 来获得指向新对象的有效指针：

struct A {
    virtual int transmogrify();
};

struct B : A {
    int transmogrify() override { ::new(this) A; return 2; }
};

inline int A::transmogrify() { ::new(this) B; return 1; }

void test()
{
    A i;
    int n = i.transmogrify();
    // int m = i.transmogrify(); // 未定义行为：新的 A 对象是基类子对象，而旧的是完整对象
    int m = std::launder(&i)->transmogrify(); // OK
    assert(m + n == 3);
}
 (C++17 起)

相似地，当在类成员或数组元素的存储中创建对象时，只有满足如下条件，所创建的对象才是包含原对象的对象的子对象（成员或元素）：

  • 包含对象的生存期已经开始且尚未结束
  • 新对象的存储与原对象的存储严格重合
  • 新对象和原对象（忽略 cv 限定性）具有相同的类型。

否则不使用 std::launder 就不能以原对象的名字访问新对象：

本节未完成
原因：合适的示例
(C++17 起)

一种特殊情况是，满足以下条件的情况下可以在含有 unsigned char 或 std::byte (C++17 起) 的数组中创建对象（这种情况下称这个数组为对象提供存储）：

  • 数组的生存期已经开始且尚未结束
  • 新对象的存储完全适于数组之内
  • 不存在满足这些约束的，内嵌于该数组的数组对象。

如果该数组的这个部分之前曾为另一个对象提供存储，那个对象的生存期就会因为其存储被重用而结束，不过数组自身的生存期并未结束（其存储并不被当成是被重用了）。

template<typename ...T>
struct AlignedUnion {
  alignas(T...) unsigned char data[maxv(sizeof(T)...)];
};
int f() {
  AlignedUnion<int, char> au;
  int *p = new (au.data) int;     // OK ： au.data 提供存储
  char *c = new (au.data) char(); // OK ： *p 的生存期结束
  char *d = new (au.data + 1) char();
  return *c + *d; // OK
}

在生存期之外进行访问

在对象的生存期开始之前但其存储将要占据的存储已经分配之后，或者在对象的生存期已经结束之后但其所曾占据的存储被重用或释放之前，对代表这个对象的泛左值表达式的以下这些用法是未定义的：

  1. 左值向右值转换（比如对接受其值的函数进行调用），除非正在构造或析构该对象（此时应用不同的规则集合）：
  2. 访问其非静态数据成员或调用非静态成员函数。
  3. 绑定引用到其某个虚基类子对象。
  4. dynamic_cast 或 typeid 表达式。

以上规则也适用于指针（绑定引用到虚基类改为隐式转换为虚基类的指针），并有两条额外的规则：

  1. 对指向没有对象的存储的指针进行 static_cast 时只允许将其强制转换为（可能 cv 限定的）void*。
  2. 转型到 void* 的指向无对象存储的指针，只能被 static_cast 到指向可能 cv 限定的 char 、或可能 cv 限定的 unsigned char 、或可能 cv 限定的 std::byte (C++17 起) 的指针。

在构造和析构的过程中，通常允许调用非静态成员函数，访问非静态数据成员，以及使用 typeid 和 dynamic_cast。然而，因为生存期尚未开始（在构造期间）或已结束（在析构期间），只允许特定的操作。其他限制条件参见在构造和析构过程中调用虚函数。

注解

核心问题 2256 解决前，非类对象（存储期的终止）和类对象（按构造顺序的逆序）的生存期终止规则存在差别：

struct A {
  int* p;
  ~A() { std::cout << *p; } // CWG2256 起为未定义行为： n 不活到 a 的生存期之后
                            // CWG2256 前有恰当定义：打印 123
};
void f() {
  A a;
  int n = 123; // 假如 n 不活到 a 的生存期之后，则能把这条语句优化掉（死存储）
  a.p = &n;
}

RU007 解决前， const 限定类型或引用类型的非静态数据成员使含有它的对象无法为可透明替换，这使得 std::vector 与 std::deque 难以实现：

struct X { const int n; };
union U { X x; float f; };
void tong() {
  U u = { { 1 } };
  u.f = 5.f;                          // OK ：创建 'u' 的新子对象
  X *p = new (&u.x) X {2};            // OK ：创建 'u' 的新子对象
  assert(p->n == 2);                  // OK
  assert(u.x.n == 2);                 // RU007 前未定义：
                                      // 'u.x' 不指名新子对象
  assert(*std::launder(&u.x.n) == 2); // 即使在 RU007 前也 OK
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 201 | C++98 | 要求默认构造函数的默认实参中的临时对象的生存期在数组初始化完成时结束 | 生存期在下个元素初始化之前结束
CWG 2012 | C++98 | 引用的生存期被指定为与存储期匹配，这要求 extern 引用在其初始化器运行前已存活 | 生存期始于初始化
CWG 2107 | C++98 | CWG 124 的解决方案未应用到复制构造函数 | 已应用
P0137R1 | C++98 | 在 unsigned char 数组中创建对象重用其存储 | 其存储不被重用
CWG 2256 | C++98 | 可平凡析构对象的生存期与其他对象不一致 | 使之一致
P1971R0 | C++98 | const 限定类型或引用类型的非静态数据成员使包含它的对象不能为可透明替换 | 移除限制
P2103R0 | C++98 | 可透明替换性不要求保持原结构 | 要求
P0593R6 | C++98 | 伪析构函数调用无效果 | 它销毁对象
CWG 2470 | C++98 | 可以有多于一个数组为同一对象提供存储 | 仅一个提供

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 6.7.3 Object lifetime [basic.life]
  • 11.10.4 Construction and destruction [class.cdtor]
  • C++17 标准（ISO/IEC 14882:2017）：
  • 6.8 Object lifetime [basic.life]
  • 15.7 Construction and destruction [class.cdtor]
  • C++14 标准（ISO/IEC 14882:2014）：
  • 3 Object lifetime [basic.life]
  • 12.7 Construction and destruction [class.cdtor]
  • C++11 标准（ISO/IEC 14882:2011）：
  • 3.8 Object lifetime [basic.life]
  • 12.7 Construction and destruction [class.cdtor]
  • C++03 标准（ISO/IEC 14882:2003）：
  • 3.8 Object lifetime [basic.life]
  • 12.7 Construction and destruction [class.cdtor]
  • C++98 标准（ISO/IEC 14882:1998）：
  • 3.8 Object lifetime [basic.life]
  • 12.7 Construction and destruction [class.cdtor]

参阅


列表初始化 (C++11 起)

< cpp‎ | language

从 花括号初始化器列表 列表初始化对象

语法

直接列表初始化

T 对象 { 实参1, 实参2, ... }; | (1)
T { 实参1, 实参2, ... } | (2)
new T { 实参1, 实参2, ... } | (3)
类 { T 成员 { 实参1, 实参2, ... }; }; | (4)
类::类() : 成员{实参1, 实参2, ...} {... | (5)

复制列表初始化

T 对象 = {实参1, 实参2, ...}; | (6)
函数( { 实参1, 实参2, ... } ) | (7)
return { 实参1, 实参2, ... } ; | (8)
对象[ { 实参1, 实参2, ... } ] | (9)
对象 = { 实参1, 实参2, ... } | (10)
U( { 实参1, 实参2, ... } ) | (11)
类 { T 成员 = { 实参1, 实参2, ... }; }; | (12)

在下列情形进行列表初始化：

  • 直接列表初始化（考虑 explicit 和非 explicit 构造函数）
1) 以 花括号初始化器列表（即花括号环绕的可以为空的表达式或 花括号初始化器列表 的列表）初始化具名变量
2) 以 花括号初始化器列表 初始化无名临时量
3) 以 new 表达式初始化具有动态存储期的对象，它的初始化器是 花括号初始化器列表 列表
4) 在不使用等号的非静态数据成员初始化器中
5) 在构造函数的成员初始化列表中，如果使用 花括号初始化器列表
  • 复制列表初始化（考虑 explicit 和非 explicit 构造函数，但只能调用非 explicit 构造函数）
6) 以等号后的 花括号初始化器列表 初始化具名变量
7) 函数调用表达式中，以 花括号初始化器列表 为实参，以列表初始化对函数形参初始化
8) 在以 花括号初始化器列表 为返回表达式的 return 语句中，以列表初始化对返回的对象初始化
9) 在具有用户定义的 operator[] 的下标表达式中，以列表初始化对重载运算符的形参初始化
10) 在赋值表达式中，以列表初始化对重载的运算符的形参初始化
11) 函数式转型表达式或其他构造函数调用，其中 花括号初始化器列表 用作构造函数实参。以复制初始化对构造函数的形参初始化（注意：此例中的类型 U 不是被列表初始化的类型；但 U 的构造函数的形参是）
12) 在使用等号的非静态数据成员初始化器中

解释

T 类型的对象的列表初始化的效果是：

  • 如果 T 是聚合类且 花括号初始化器列表 拥有单个（可有 cv 限定的）相同类型或派生类型的元素，那么从该元素初始化对象（对于复制列表初始化为复制初始化，对于直接列表初始化为直接初始化）。
  • 否则，如果 T 是字符数组且初始化器列表拥有单个类型适当的字符串字面量元素，那么照常从字符串字面量初始化数组。
  • 否则，如果 T 是聚合类型，那么进行聚合初始化。
  • 否则，如果 花括号初始化器列表 列表为空，且 T 是拥有默认构造函数的类类型，那么进行值初始化。
  • 否则，如果 T 是 std::initializer_list 的特化，则依据其语境以 花括号初始化器列表 所初始化的同类型的纯右值 (C++17 前)直接初始化或复制初始化该 T 对象。
  • 否则，以两个阶段考虑 T 的构造函数：
  • 检验所有接受 std::initializer_list 作为其唯一实参，或如果剩余实参都具有默认值则为其首个实参的构造函数，并通过重载决议与单个 std::initializer_list 类型的实参进行匹配。
  • 如果上一个阶段未产生匹配，那么 T 的所有构造函数都参与针对由 花括号初始化器列表 的各元素所组成的实参集的重载决议，它会受到只允许非窄化转换的限制。如果这个阶段为复制列表初始化产生的最佳匹配是 explicit 构造函数，那么编译失败（注意：简单复制初始化中完全不考虑 explicit 构造函数）。
  • 否则，如果：
    • T 是拥有固定底层类型 U （如果枚举为有作用域且未手工指定其底层类型则为 int）的枚举类型，且
    • 初始化为直接列表初始化，且
    • 花括号初始化器列表 仅拥有一个能隐式转换成 U 的初始化器 v，且
    • 从 v 到 U 的转换不是窄化，
那么以将 v 转换到 U 的结果初始化该枚举。
 (C++17 起)
  • 否则（如果 T 不是类类型），如果 花括号初始化器列表 仅拥有一个元素，且 T 要么不是引用类型，要么是引用类型而其所引用的类型与该元素的类型相同或为其基类，那么直接初始化（直接列表初始化时）或复制初始化（复制列表初始化时）这个 T，但不允许窄化转换。
  • 否则，如果 T 是引用类型，那么就列表初始化一个被引用类型或其对应的已知边界数组类型 (C++20 起)的临时量，并将引用绑定到该临时量。（如果引用是非 const 左值引用则失败）
如果被引用类型是未知边界数组类型 U[] ，那么临时量的类型是 U[N] ，如同它定义为 U temp[]/*初始化器列表*/; ，其中 /*初始化器列表*/ 是 花括号初始化器列表。
 (C++20 起)
  • 否则，如果 花括号初始化器列表 没有任何元素，那么值初始化 T。

窄化转换

列表初始化通过禁止下列转换对隐式转换加以限制：

  • 从浮点类型到整数类型的转换
  • 从 long double 到 double 或 float 的转换，以及从 double 到 float 的转换，除非来源是常量表达式且不发生溢出
  • 从整数类型到浮点类型的转换，除非来源是其值能完全存储于目标类型的常量表达式
  • 从整数或无作用域枚举类型到不能表示原类型所有值的整数类型的转换，除非来源是其值能完全存储于目标类型的常量表达式
  • 从指针或成员指针类型到 bool 的转换

注解

每个初始化器子句均按顺序早于 花括号初始化器列表 中后随于它的任何初始化器子句。这与函数调用表达式相反，它是无顺序的 (C++17 前)不确定顺序的 (C++17 起)。

花括号初始化器列表 不是表达式，因此它没有类型，即 decltype({1,2}) 非良构。没有类型意味着模板类型推导无法推导出与 花括号初始化器列表 相匹配的类型，因此给定声明 template<class T> void f(T); 则表达式 f({1,2,3}) 非良构。然而，模板形参可以另行推导，如 std::vector <int> v( std::istream_iterator <int>( std::cin ), {}) 的情况，其中迭代器类型从首个实参推导，但也被用于第二形参位置。对于使用关键词 auto 的类型推导中有一个例外，在复制列表初始化中将任何 花括号初始化器列表 均推导为 std::initializer_list。

同样因为 花括号初始化器列表 没有类型，所以在将它用作重载函数调用的实参时，适用重载决议的特殊规则。聚合体直接从同类型的单元素 花括号初始化器列表 进行复制/移动初始化，但非聚合体首先考虑 initializer_list 构造函数：

struct X {}; // 聚合体

struct Q {
    Q() = default;
    Q(Q const&) = default;
    Q(std::initializer_list<Q>) {}
};

int main() { // 非聚合体
  X x;
  X x2 = X { x }; // 复制构造函数（非聚合初始化）
  Q q;
  Q q2 = Q { q }; // 初始化器列表构造函数（非复制构造函数）
}

有些编译器（例如 gcc 10）仅在 C++20 模式认为从指针或成员指针到 bool 的转换为窄化。

示例

#include <iostream>
#include <vector>
#include <map>
#include <string>

struct Foo {
    std::vector<int> mem = {1,2,3}; // 非静态成员的列表初始化
    std::vector<int> mem2;
    Foo() : mem2{-1, -2, -3} {} // 构造函数中的成员列表初始化
};

std::pair<std::string, std::string> f(std::pair<std::string, std::string> p)
{
    return {p.second, p.first}; // return 语句中的列表初始化
}

int main()
{
    int n0{};     // 值初始化（为零）
    int n1{1};    // 直接列表初始化
    std::string s1{'a', 'b', 'c', 'd'}; // initializer_list 构造函数调用
    std::string s2{s1, 2, 2};           // 常规构造函数调用
    std::string s3{0x61, 'a'}; // initializer_list 构造函数偏好 (int, char)

    int n2 = {1}; // 复制列表初始化
    double d = double{1.2}; // 纯右值的列表初始化，然后复制初始化
    auto s4 = std::string{"HelloWorld"}; // 同上， C++17 起不创建临时对象

    std::map<int, std::string> m = { // 嵌套列表初始化
           {1, "a"},
           {2, {'a', 'b', 'c'} },
           {3, s1}
    };

    std::cout << f({"hello", "world"}).first // 函数调用中的列表初始化
              << '\n';

    const int (&ar)[2] = {1,2}; // 绑定左值引用到临时数组
    int&& r1 = {1}; // 绑定右值引用到临时 int
//  int& r2 = {2}; // 错误：不能绑定右值到非 const 左值引用

//  int bad{1.0}; // 错误：窄化转换
    unsigned char uc1{10}; // 可以
//  unsigned char uc2{-1}; // 错误：窄化转换

    Foo f;

    std::cout << n0 << ' ' << n1 << ' ' << n2 << '\n'
              << s1 << ' ' << s2 << ' ' << s3 << '\n';
    for(auto p: m)
        std::cout << p.first << ' ' << p.second << '\n';
    for(auto n: f.mem)
        std::cout << n << ' ';
    for(auto n: f.mem2)
        std::cout << n << ' ';
}

输出：

world
0 1 1
abcd cd aa
1 a
2 abc
3 abcd
1 2 3 -1 -2 -3

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1301 | C++11 | 对源自 {} 的初始化首先考虑值初始化 | 首先考虑聚合初始化
CWG 1467 | C++11 | 禁止同类型的聚合体和字符数组初始化； 单元素列表的 initializer_list 构造函数优先级高于复制构造函数 | 允许同类型初始化； 单元素列表直接初始化
CWG 2137 | C++11 | initializer_list 构造函数在从 {X} 初始化时失去复制构造函数的优先级 | 非聚合体首先考虑 initializer_list
CWG 2374 | C++17 | 枚举的直接列表初始化允许了过多的源类型 | 已限制
P1957R2 | C++11 | 从指针/成员指针到 bool 的转换不是窄化 | 使之为窄化

参阅

  • 构造函数
  • 转换构造函数
  • 复制赋值
  • 复制构造函数
  • 复制消除
  • 默认构造函数
  • explicit
  • 初始化
    • 聚合初始化
    • 常量初始化
    • 复制初始化
    • 直接初始化
    • 引用初始化
    • 值初始化
    • 零初始化
  • 移动赋值
  • 移动构造函数
  • new


主函数

< cpp‎ | language

程序应当含有一个名为 main 的全局函数（主函数），它被指定为程序的启动点。它应当有下列形式之一：

int main () { 函数体 } | (1)
int main (int argc, char *argv[]) { 函数体 } | (2)
/* 其他由实现定义的形式，返回类型为 int */ | (3)
argc | - | 非负数，表示从程序运行的环境传递给程序的实参个数。
argv | - | 指针，指向包含 argc + 1 个指针的数组的首元素。数组末元素为空指针，若其前面有任何元素，则它们指向空终止多字节字符串，表示从执行环境传递给程序的若干参数。若 argv[0] 不是空指针，或等价地 argc > 0 ，则它指向表示用于调用程序的名称的字符串，或空字符串。
函数体 | - | 主函数的函数体

名字 argc 和 argv ，以及形参的类型的表示方式是任取的：int main(int ac, char** av) 同样合法。

主函数的一种常见的由实现定义的形式还有（除 argc 和 argv 之外的）第三个参数，类型为 char** ，指向指向执行环境变量的指针数组。

解释

在程序启动时，主函数在初始化具有静态存储期的非局部对象之后被调用。它是程序在有宿主 (hosted)环境（即有操作系统）中所指定的入口点。自立程序（启动加载器，操作系统内核，等等）的入口点则是由实现定义的。

双形参形式的主函数的形参允许从执行环境中传递任意的多字节字符串（它们通常被称为命令行参数），各个指针 argv[1] .. argv[argc-1] 指向对应的每个字符串的第一个字符。指针 argv[0] 指向一个空终止多字节字符串的开头字符，该字符串表示用于执行该程序自身的名字（当执行环境不支持时为空字符串 ""）。这些字符串是可修改的：比如可以用 std::strtok 来使用它们，虽然对它们的修改并不会被传回给执行环境。由 argv 所指向的数组的大小至少为 argc+1，其最后一个元素 argv[argc] 保证为一个空指针。

主函数具有几项特殊性质：

1) 不能在程序的任何地方使用它
a) 尤其不能递归调用它
b) 不能取其地址
2) 不能预定义，不能重载：实际上，名字 main 在全局命名空间中对函数保留（虽然可以用作类、命名空间、枚举和非全局命名空间中的任何实体的名字，但不能在任何命名空间中将名为“main”的函数声明为具有 C 语言链接）。
3) 不能定义为被弃置（ =delete; ），或 (C++11 起)声明为具有 C 语言链接 、constexpr (C++11 起)、consteval (C++20 起)、inline 或 static。
4) 主函数的函数体不需要包含 return 语句：当控制达到主函数体的末尾而未遇到返回语句时，其效果为执行 return 0;。
5) 执行返回（或当到达主函数体的末尾时的隐式返回）等价于先正常离开函数（这将销毁具有自动存储期的对象），然后用和 return 相同的实参来调用 std::exit。（std::exit 随即销毁静态对象并终止程序）
6) (C++14 起) 主函数的返回类型不能被推导（不允许 auto main() {...）。
7) (C++20 起) 主函数不能是协程。

注解

如果以函数 try 块定义主函数，则它捕捉不到（由隐含的 std::exit 所销毁的）静态对象的析构函数所抛出的异常。

将操作系统命令行上给定的参数转换为由 argv 所指代的多字节字符数组的方式，可能涉及到由实现定义的处理过程：

  • 分析 C++ 命令行参数 MSDN
  • Shell 介绍 POSIX

示例

演示如何通知程序：从哪里获得输入，向哪里写入结果。
一种可能的调用方式：./convert table_in.dat table_out.dat

#include <iostream>
#include <iomanip>
#include <cstdlib>

int main(int argc, char *argv[])
{
    std::cout << "argc == " << argc << '\n';

    for(int ndx{}; ndx != argc; ++ndx) {
        std::cout << "argv[" << ndx << "] == " << std::quoted(argv[ndx]) << '\n';
    }
    std::cout << "argv[" << argc << "] == "
              << static_cast<void*>(argv[argc]) << '\n';
    /*...*/
    return argc == 3 ? EXIT_SUCCESS : EXIT_FAILURE; // 可选返回值
}

可能的输出：

argc == 3
argv[0] == "./convert"
argv[1] == "table_in.dat"
argv[2] == "table_out.dat"
argv[3] == 0

参阅


非静态成员函数

< cpp‎ | language

非静态成员函数是在类的成员说明中不带 static 或 friend 说明符声明的函数。（这些关键词的效果见静态成员函数与友元声明）

class S {
    int mf1(); // 非静态成员函数声明
    void mf2() volatile, mf3() &&; // 可以有 cv 限定或引用限定
    int mf4() const { return data; } // 可以内联定义
    virtual void mf5() final; // 可以是虚函数，可以使用 final/override
    S() : data(12) {} // 构造函数也是成员函数
    int data;
};
int S::mf1() { return 7; } // 不内联定义就必须在命名空间定义

允许任何函数声明，外加非静态成员函数专用的语法元素：纯说明符，cv 限定符，引用限定符，final 与 override 说明符 (C++11 起)，以及成员初始化器列表。

可以用以下方式调用类 X 的非静态成员函数：

1) 对 X 类型的对象使用类成员访问运算符调用
2) 对派生自 X 的类的对象调用
3) 从 X 的成员函数体内直接调用
4) 从派生自 X 的类的成员函数体内调用直接调用

在类型不是 X 或派生自 X 的对象上调用类 X 的非静态成员函数的行为未定义。

在 X 的非静态成员函数的体内，任何解析为 X 或 X 的某个基类的非类型非静态成员的标识表达式 e}（例如一个标识符）均被变换为成员访问表达式 (*this).e（除非它已经是成员访问表达式的一部分）。模板定义语境中不会发生这种变换，因此有时需要明确地对某个名字前附 this->，以使其成为待决的名字。

struct S {
    int n;
    void f();
};
void S::f() {
    n = 1; // 变换为 (*this).n = 1;
}
int main() {
    S s1, s2;
    s1.f(); // 更改 s1.n
}

在 X 的非静态成员函数体内，任何解析到 X 或 X 的某个基类的静态成员、枚举项或嵌套类型的无限定标识均被变换为对应的有限定标识。

struct S {
    static int n;
    void f();
};
void S::f() {
    n = 1; // 变换为 S::n = 1;
}
int main() {
    S s1, s2;
    s1.f(); // 更改 S::n
}

有 const 与 volatile 限定的成员函数

非静态成员函数可以带 const、volatile 或 const volatile 限定符声明（这些限定符出现在函数声明中的形参列表之后）。cv 限定性不同的函数具有不同类型，从而可以相互重载。

在有 cv 限定的函数体内，*this 有同样的 cv 限定，例如在 const 成员函数中只能正常地调用其他 const 成员函数。（如果应用了 const_cast，或通过不涉及 this 的访问路径，那么仍然可以调用非 const 成员函数。）

#include <vector>
struct Array {
    std::vector<int> data;
    Array(int sz) : data(sz) {}
    // const 成员函数
    int operator[](int idx) const {
                          // this 具有类型 const Array*
        return data[idx]; // 变换为 (*this).data[idx];
    }
    // 非 const 成员函数
    int& operator[](int idx) {
                          // this 具有类型 Array*
        return data[idx]; // 变换为 (*this).data[idx]
    }
};
int main()
{
    Array a(10);
    a[1] = 1; // OK：a[1] 的类型是 int&
    const Array ca(10);
    ca[1] = 2; // 错误：ca[1] 的类型是 int
}

有引用限定的成员函数

非静态成员函数可以不带引用限定符，带有左值引用限定符（函数名后的 & 记号），或带有右值引用限定符（函数名后的 && 记号）声明。在重载决议中，按下列方式对待类 X 的非静态 cv 限定成员函数：

  • 不带引用限定符：隐式对象形参具有到 cv 限定的 X 的左值引用类型，并额外允许绑定到右值隐含对象实参
  • 左值引用限定符：隐式对象形参具有到 cv 限定的 X 的左值引用类型
  • 右值引用限定符：隐式对象形参具有到 cv 限定的 X 的右值引用类型
#include <iostream>
struct S {
    void f() & { std::cout << "左值\n"; }
    void f() &&{ std::cout << "右值\n"; }
};

int main(){
    S s;
    s.f();            // 打印“左值”
    std::move(s).f(); // 打印“右值”
    S().f();          // 打印“右值”
}

注意：与 cv 限定性不同，引用限定性不改变 this 指针的性质：即使在右值引用限定的函数中，*this 仍是左值表达式。

 (C++11 起)

虚函数和纯虚函数

非静态成员函数可以声明为虚或纯虚函数。细节见虚函数与抽象类。

特殊成员函数

构造函数和析构函数是非静态成员函数，在其声明中使用特殊的语法（细节见其相应页面）。

一些成员函数是特殊的：在某些环境下，即使用户不定义编译器也会定义它们。它们是：

  • 默认构造函数
  • 复制构造函数
  • 移动构造函数
 (C++11 起)
  • 复制赋值运算符
  • 移动赋值运算符
 (C++11 起)

  • 析构函数

             (C++20 前)

    预期的析构函数

             (C++20 起)

    特殊成员函数以及比较运算符 (C++20 起)是仅有的能被预置的函数，即使用 = default 替代函数体进行定义（细节见其相应页面）。

    示例

    #include <iostream>
#include <string>
#include <utility>
#include <exception>

struct S {
    int data;

    // 简单的转换构造函数（声明）
    S(int val);

    // 简单的显式构造函数（声明）
    explicit S(std::string str);

    // const 成员函数（定义）
    virtual int getData() const { return data; }

};

// 构造函数的定义
S::S(int val) : data(val) {
    std::cout << "调用构造函数1，data = " << data << '\n';
}

// 此构造函数拥有 catch 子句
S::S(std::string str) try : data(std::stoi(str)) {
    std::cout << "调用构造函数2，data = " << data << '\n';
} catch(const std::exception&) {
    std::cout << "构造函数2失败，字符串'" << str << "'\n";
    throw; // 构造函数的 catch 子句应该始终再抛出异常
}

struct D : S {
    int data2;
    // 带默认实参的构造函数
    D(int v1, int v2 = 11) : S(v1), data2(v2) {}

    // 虚成员函数
    int getData() const override { return data*data2; }

    // 左值限定的赋值运算符
    D& operator=(D other) & {
        std::swap(other.data, data);
        std::swap(other.data2, data2);
        return *this;
    }
};

int main()
{
    D d1 = 1;
    S s2("2");
    try {
         S s3("不是数字");
    } catch(const std::exception&) {}
    std::cout << s2.getData() << '\n';

   D d2(3, 4);
   d2 = d1; // OK ：赋值给左值
//   D(5) = d1; // 错误：没有适合的 operator= 重载
}

    输出：

    调用构造函数1，data = 1
调用构造函数2，data = 2
构造函数2失败，字符串'不是数字'
2
调用构造函数1，data = 3

    参阅

    • 类
    • 数据成员
    • 静态数据成员


成员模板

< cpp‎ | language

模板声明（类、函数 及变量 (C++14 起)）可以在任何不是局部类的 class、struct 或 union 的成员说明中出现。

#include <iostream>
#include <vector>
#include <algorithm>

struct Printer { // 泛型函子
    std::ostream& os;
    Printer(std::ostream& os) : os(os) {}
    template<typename T>
    void operator()(const T& obj) { os << obj << ' '; } // 成员模板
};

int main()
{
    std::vector<int> v = {1,2,3};
    std::for_each(v.begin(), v.end(), Printer(std::cout));
    std::string s = "abc";
    std::for_each(s.begin(), s.end(), Printer(std::cout));
}

输出：

1 2 3 a b c

在类作用域和外围命名空间作用域中都可以出现成员模板的部分特化。显式特化可以出现在主模板可出现的任何作用域中。

struct A {
    template<class T> struct B;         // 主成员模板
    template<class T> struct B<T*> { }; // OK：部分特化
//  template<> struct B<int*> { };      // 经由 CWG 727 OK：全特化
};
template<> struct A::B<int*> { };       // OK
template<class T> struct A::B<T&> { };  // OK

如果外围类定义也是类模板，那么在类体外定义成员模板时，它带有两组模板形参：一组是外围类的，另一组是其自身的：

template<typename T1>
struct string {
    // 成员模板函数
    template<typename T2>
    int compare(const T2&);
    // 构造函数也可以是模板
    template<typename T2>
    string(const std::basic_string<T2>& s) { /*...*/ }
};
// string<T1>::compare<T2> 的类外定义
template<typename T1> // 对于外围类模板
template<typename T2> // 对于成员模板
int string<T1>::compare(const T2& s) { /* ... */ }

成员函数模板

析构函数和复制构造函数不能是模板。若声明了可用复制构造函数的类型签名实例化的模板构造函数，则替而使用隐式声明的复制构造函数。

成员函数模板不能为虚，且派生类中的成员函数模板不能覆盖来自基类的虚成员函数。

class Base {
    virtual void f(int);
};
struct Derived : Base {
    // 此成员模板不覆盖 Base::f
    template <class T> void f(T);

    // 非模板成员覆盖函数可以调用该模板：
    void f(int i) override {
         f<>(i);
    }
};

可以声明具有相同名字的非模板成员函数和模板成员函数。在冲突的情况下（某个模板特化与非模板函数的签名严格匹配），对该名字和类型的使用指代的是非模板成员，除非提供显式模板实参列表。

template<typename T>
struct A {
    void f(int); // 非模板成员

    template<typename T2>
    void f(T2); // 成员模板
};

// 模板成员定义
template<typename T>
template<typename T2>
void A<T>::f(T2)
{
    // 一些代码
}

int main()
{
    A<char> ac;
    ac.f('c'); // 调用模板函数 A<char>::f<char>(int)
    ac.f(1);   // 调用非模板函数 A<char>::f(int)
    ac.f<>(1); // 调用模板函数 A<char>::f<int>(int)
}

成员函数模板的类外定义必须等价于类内声明（等价性的定义见函数模板重载），否则它被认为是一个重载。

struct X {
    template<class T> T good(T n);
    template<class T> T bad(T n);
};

template<class T> struct identity { using type = T; };

// OK：等价声明
template<class V>
V X::good(V n) { return n; }

// 错误：不与 X 内的任何声明等价
template<class T>
T X::bad(typename identity<T>::type n) { return n; }

转换函数模板

用户定义的转换函数可以是模板。

struct A {
    template<typename T>
    operator T*(); // 转换到指向任何类型的指针
};

// 类外定义
template<typename T>
A::operator T*() {return nullptr;}

// 对 char* 的显式特化
template<>
A::operator char*() {return nullptr;}

// 显式实例化
template A::operator void*();

int main() {
    A a;
    int* ip = a.operator int*(); // 显式调用 A::operator int*()
}

在重载决议中，名字查找不会找到转换函数模板的特化。取而代之的是，所有可见的转换函数模板都会受到考虑，且每个模板实参推导所产生的特化（对于转换函数模板有特殊规则）都会得到使用，如同被名字查找所找到一样。

派生类中的 using 声明不能涉及来自基类的模板转换函数。

用户定义转换函数模板不能有推导的返回类型：

struct S {
  operator auto() const { return 10; } // OK
  template<class T> operator auto() const { return 42; } // 错误
};
 (C++14 起)

成员变量模板

变量模板可以在类作用域内声明，此时它声明静态数据成员模板。细节见变量模板。

 (C++14 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1878 | C++14 | 技术性允许 operator auto | 禁止 operator auto


模块 (C++20 起)

< cpp‎ | language

大多数 C++ 项目用到了多个翻译单元，因此它们需要在那些单元间分享声明和定义。正是因为这样，使用头文件非常重要，例如标准库的声明通过 #include 对应的头提供。

模块是一个用于在翻译单元间分享声明和定义的语言特性。它们可以在某些地方替代使用头文件。

模块和命名空间是正交的。

// helloworld.cpp
export module helloworld;  // 模块声明
import <iostream>;         // 导入声明

export void hello() {      // 导出声明
    std::cout << "Hello world!\n";
}
// main.cpp
import helloworld;  // 导入声明

int main() {
    hello();
}

语法

export(可选) module 模块名 模块分区(可选) 属性(可选) ; | (1)
export 声明 | (2)
export { 声明序列(可选) } | (3)
export(可选) import 模块名 属性(可选) ; | (4)
export(可选) import 模块分区 属性(可选) ; | (5)
export(可选) import 头名 属性(可选) ; | (6)
module ; | (7)
module : private ; | (8)
1) 模块声明。声明当前翻译单元是一个模块单元。
2,3) 导出声明。导出 声明 或 声明序列 中所有具有命名空间作用域的声明。
4,5,6) 导入声明。导入一个模块单元，模块分区，或头单元。
7) 开始一个全局模块片段。
8) 开始一个私有模块片段。

模块声明

翻译单元可以有一个模块声明，这种情况下它们被视为模块单元。模块声明在有提供时必须是翻译单元的首个声明（后面提到的全局模块片段除外）。每个模块单元都对应一个模块名（可以带一个分区），它在模块声明中提供。

export(可选) module 模块名 模块分区(可选) 属性(可选) ;

模块名包含由点分隔的一个或多个标识符（例如：mymodule，mymodule.mysubmodule，mymodule2...）。点没有内在含义，不过它们会非正式地用于表示继承关系。

一个具名模块是一组模块名相同的模块单元。

声明中带有关键词 export 的模块单元是模块接口单元。其他模块单元被称为模块实现单元。

对于每个具名模块，必须有恰好一个未指定模块分区的模块接口单元。这个模块单元被称为主模块接口单元。在导入对应的具名模块时可以使用它导出的内容。

// （每行表示一个单独的翻译单元）

export module A;   // 为具名模块 'A' 声明主模块接口单元
module A;          // 为具名模块 'A' 声明一个模块实现单元
module A;          // 为具名模块 'A' 声明另一个模块实现单元
export module A.B; // 为具名模块 'A.B' 声明主模块接口单元
module A.B;        // 为具名模块 'A.B' 声明一个模块实现单元

导出声明和定义

模块接口单元可以导出声明和定义，这些内容可以导入到其他翻译单元。它们可以有 export 关键词作为前缀，或者处于 export 块中。

export 声明
export { 声明序列(可选) }
export module A;   // 为具名模块 'A' 声明主模块接口单元

// hello() 会在所有导入 'A' 的翻译单元中可见
export char const* hello() { return "hello"; }

// world() 不可见
char const* world() { return "world"; }

// one() 和 zero() 均可见
export {
    int one()  { return 1; }
    int zero() { return 0; }
}

// 也可以导出命名空间：hi::english() 和 hi::french() 均可见
export namespace hi {
    char const* english() { return "Hi!"; }
    char const* french()  { return "Salut!"; }
}

导入模块和头

模块可以通过导入声明导入：

export(可选) import 模块名 属性(可选) ;

所有在给定具名模块的模块接口单元中导出的声明和定义都会在使用导入声明的翻译单元中可见。

导入的声明在模块接口单元里可以再导出。也就是说，如果模块 A 导入 B 后又导出，那么导入 A 也会使所有从 B 导出的内容可见。

在模块单元里，所有导入声明（包括带导出的导入）必须集中在模块声明后以及所有其他声明前。

/////// A.cpp    （'A' 的主模块接口单元）
export module A;

export char const* hello() { return "hello"; }

/////// B.cpp    （'B' 的主模块接口单元）
export module B;

export import A;

export char const* world() { return "world"; }

/////// main.cpp （非模块单元）
#include <iostream>
import B;

int main() {
    std::cout << hello() << ' ' << world() << '\n';
}

在模块单元里（全局模块片段以外）不能使用 #include，因为所有被包含的声明和定义都会作为模块的一部分。头可以改为通过导入声明导入：

export(可选) import 头名 属性(可选) ;

导入一个头文件会使其所有声明和定义可见。预处理宏也会可见（因为预处理器会识别导入声明）。然而与 #include 相反的是，在（导入这个头文件的）翻译单元中定义的预处理宏不会影响头文件的处理。这在某些场合会不方便（某些头文件用预处理宏作为配置方式），这种情况下需要使用全局模块片段。

/////// A.cpp    （'A' 的主模块接口单元）
export module A;

import <iostream>;
export import <string_view>;

export void print(std::string_view message) {
    std::cout << message << std::endl;
}

/////// main.cpp （非模块单元）
import A;

int main() {
    std::string_view message = "Hello, world!";
    print(message);
}

全局模块片段

模块单元可以有全局模块片段前缀，它可以在无法导入头文件时（尤其是在头文件用预处理宏进行配置时）包含它们。

module;

预处理指令序列(可选)

模块声明

如果一个模块单元有一个全局模块片段，那么它的首个声明必须是 module;。然后在全局模块片段中只能出现预处理指令。然后用一个标准的模块声明结束这个全局模块片段，后面就是模块内容。

/////// A.cpp    （'A' 的主模块接口单元）
module;

// 按照 POSIX 标准，定义 _POSIX_C_SOURCE 会向标准头中添加函数。
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>

export module A;

import <ctime>;

// 仅用于演示（差的随机源）。应改为使用 C++ <random>。
export double weak_random() {
    std::timespec ts;
    std::timespec_get(&ts, TIME_UTC); // 来自 <ctime>
    // 按照 POSIX 标准从 <stdlib.h> 提供。
    srand48(ts.tv_nsec);
    // drand48() 返回 0 与 1 之间的一个随机数
    return drand48();
}

/////// main.cpp （非模块单元）
import <iostream>;
import A;

int main() {
    std::cout << "0 与 1 之间的随机值：" << weak_random() << '\n';
}

模块分区

一个模块可以有模块分区单元。它们是模块声明中包含了一个模块分区的模块单元，模块分区在模块名之后，以一个冒号 : 开头。

export module A:B; // 为模块 'A' 分区 'B' 声明一个模块接口单元。

一个模块分区表示恰好一个模块单元（两个模块单元不能指定同一个模块分区）。它们只在自己所在的具名模块内部可见（在该具名模块外的翻译单元不能直接导入这些模块分区）。

模块分区只能被相同具名模块的模块单元导入。

export(可选) import 模块分区 属性(可选) ;
/////// A-B.cpp
export module A:B;
...

/////// A-C.cpp
module A:C;
...

/////// A.cpp
export module A;

import :C;
export import :B;

...

模块分区内的所有声明和定义在将其导入的模块单元中均可见，无论它们是否被导出。

模块分区可以是模块接口单元（如果模块声明中有 export）。它们必须被主模块接口单元在导入同时导出，并且它们导出的语句在模块被导入时均可见。

export(可选) import 模块分区 属性(可选) ;
///////  A.cpp
export module A;   // 主模块接口单元

export import :B;     // Hello() 在导入 'A' 时可见
import :C;            // 现在 WorldImpl() 只对 'A.cpp' 可见
// export import :C;  // 错误：无法导出模块实现单元

// World() 对所有导入 'A' 的翻译单元均可见
export char const* World() {
    return WorldImpl();
}
/////// A-B.cpp
export module A:B; // 模块分区接口单元

// Hello() 对所有导入 'A' 的翻译单元均可见
export char const* Hello() { return "Hello"; }
/////// A-C.cpp
module A:C;        // 模块分区实现单元

// WorldImpl() 对 'A' 中所有导入 ':C' 的翻译单元均可见
char const* WorldImpl() { return "World"; }
/////// main.cpp
import A;
import <iostream>;

int main() {
    std::cout << Hello() << ' ' << World() << '\n';
    // WorldImpl(); // 错误：WorldImpl() 不可见
}

关键词

export，import，module


移动赋值运算符

< cpp‎ | language

类 T 的移动赋值运算符是名为 operator=的非模板非静态成员函数，它接受恰好一个 T&&、const T&&、volatile T&& 或 const volatile T&& 类型的形参。

语法

类名 & 类名 :: operator= ( 类名 && ) | (1) | (C++11 起)
类名 & 类名 :: operator= ( 类名 && ) = default; | (2) | (C++11 起)
类名 & 类名 :: operator= ( 类名 && ) = delete; | (3) | (C++11 起)

解释

1) 移动赋值运算符的典型声明。
2) 强制编译器生成移动赋值运算符。
3) 避免隐式移动赋值。

每当重载决议选择移动赋值运算符时，它都会被调用，例如当对象出现在赋值表达式左侧，而其右侧是同类型或可隐式转换的类型的右值时。

典型的移动赋值运算符“窃取”实参曾保有的资源（例如指向动态分配对象的指针，文件描述符，TCP socket，输入输出流，运行的线程，等等），而非复制它们，并使得实参遗留在某个合法但不确定的状态。例如，从 std::string 或从 std::vector 移动赋值可能导致实参被置空。然而这并不保证会发生。移动赋值与普通赋值相比，其定义较为宽松而非更严格；在完成时，普通赋值必须留下数据的两份副本，而移动赋值只要求留下一份。

隐式声明的移动赋值运算符

如果没有对类类型（struct、class 或 union）提供任何用户定义的移动赋值运算符，且满足下列所有条件：

  • 没有用户声明的复制构造函数；
  • 没有用户声明的移动构造函数；
  • 没有用户声明的复制赋值运算符；
  • 没有用户声明的析构函数，

那么编译器将声明一个，作为类的 inline public 成员，并拥有签名 T& T::operator=(T&&)。

类可以拥有多个移动赋值运算符，如 T& T::operator=(const T&&) 和 T& T::operator=(T&&)。当存在用户定义的移动赋值运算符时，用户仍然可以通过关键词 default 强迫编译器生成隐式声明的移动赋值运算符。

隐式声明（或在其首个声明被预置）的移动赋值运算符具有动态异常说明 (C++17 前)noexcept 说明 (C++17 起)中所描述的异常说明。

因为每个类总是会声明赋值运算符（移动或复制），所以基类的赋值运算符始终被隐藏。当使用 using 声明从基类带入赋值运算符，且它的实参类型与派生类的隐式赋值运算符的实参类型相同时，该 using 声明也会被隐式声明隐藏。

弃置的隐式声明的移动赋值运算符

如果满足下列任一条件，那么类 T 的隐式声明或预置的移动赋值运算符被定义为弃置的：

  • T 拥有 const 限定的非静态数据成员。
  • T 拥有引用类型的非静态数据成员。
  • T 拥有无法移动赋值（拥有被弃置、不可访问或有歧义的移动赋值运算符）的非静态数据成员。
  • T 拥有无法移动赋值（拥有被弃置、不可访问或有歧义的移动赋值运算符）的直接基类或虚基类。

重载决议忽略被弃置的隐式声明的移动赋值运算符。

平凡的移动赋值运算符

如果满足下列所有条件，那么类 T 的移动赋值运算符是平凡的：

  • 它不是用户提供的（即它是隐式定义或预置的）；
  • T 没有虚成员函数；
  • T 没有虚基类；
  • 为 T 的每个直接基类选择的移动赋值运算符都是平凡的；
  • 为 T 的每个类类型（或类类型的数组）的非静态数据成员选择的移动赋值运算符都是平凡的；

平凡移动赋值运算符实施与平凡复制赋值运算符相同的动作，即如同以 std::memmove 进行对象表示的复制。所有与 C 兼容的数据类型（POD 类型）都可以平凡移动。

合格的移动赋值运算符

没有被弃置的移动赋值运算符是合格的。

 (C++20 前)

满足下列所有条件的移动赋值运算符是合格的：

  • 它没有被弃置，且
  • 满足它的所有关联约束（如果存在），且
  • 没有比它更受约束且拥有相同的第一形参类型和相同的 cv 或引用限定符（如果存在）的移动赋值运算符。
 (C++20 起)

合格移动赋值运算符的平凡性确定该类是否为该类是否为可平凡复制类型。

隐式定义的移动赋值运算符

如果隐式声明的移动赋值运算符既没有被弃置也不平凡，那么当它被 ODR 式使用 或用于常量求值 (C++14 起)时，它会被编译器定义（即生成并编译函数体）。

对于联合体类型，隐式定义的移动赋值运算符（如用 std::memmove）复制其对象表示。

对于非联合类类型（class 与 struct），移动赋值运算符按照声明顺序对对象的各直接基类和直接非静态成员进行完整的逐成员移动赋值，其中对标量用内建运算符，对数组用逐元素移动赋值，而对类类型用移动赋值运算符（非虚调用）。

如果满足下列所有条件，那么类 T 的隐式定义的复制赋值运算符是 constexpr 的：

  • T 是字面类型，且
  • 移动每个直接基类子对象时选中的赋值运算符都是 constexpr 函数，且
  • 移动 T 的每个类（或其数组）类型的数据成员时选中的赋值运算符都是 constexpr 函数。
 (C++14 起)

与复制赋值一样，隐式定义的移动赋值运算符是否会多次对在继承网格中可通过多于一条路径访问的虚基类子对象赋值是未指明的：

struct V
{
    V& operator=(V&& other) {
        // 这可能会被调用一或两次
        // 如果调用两次，那么 'other' 是刚被移动的 V 子对象
        return *this;
    }
};
struct A : virtual V { }; // operator= 调用 V::operator=
struct B : virtual V { }; // operator= 调用 V::operator=
struct C : B, A { };      // operator= 调用 B::operator=，然后调用 A::operator=
                          // 但可能只调用一次 V::operator=

int main()
{
  C c1, c2;
  c2 = std::move(c1);
}

注解

如果复制和移动赋值运算符都有提供，那么重载决议会在实参是右值（例如无名临时量的纯右值 或 std::move 的结果的亡值）时选择移动赋值，而在实参是左值（具名对象或返回左值引用的函数或运算符）时选择复制赋值。如果只提供了复制赋值，那么重载决议对于所有值类别都会选择它（只要它按值或按到 const 的引用接收其实参），从而当移动赋值不可用时，复制赋值将会成为它的后备。

隐式定义的移动赋值运算符是否会多次对在继承网格中可通过多于一条路径访问的虚基类子对象赋值是未指明的（同样适用于复制赋值）。

有关用户定义的移动赋值运算符应当有哪些行为，见赋值运算符重载。

示例

#include <string>
#include <iostream>
#include <utility>

struct A
{
    std::string s;
    A() : s("测试") { }
    A(const A& o) : s(o.s) { std::cout << "移动失败！\n"; }
    A(A&& o) : s(std::move(o.s)) { }
    A& operator=(const A& other)
    {
         s = other.s;
         std::cout << "复制赋值\n";
         return *this;
    }
    A& operator=(A&& other)
    {
         s = std::move(other.s);
         std::cout << "移动赋值\n";
         return *this;
    }
};

A f(A a) { return a; }

struct B : A
{
     std::string s2;
     int n;
     // 隐式移动赋值运算符 B& B::operator=(B&&)
     // 调用 A 的移动赋值运算符
     // 调用 s2 的移动赋值运算符
     // 并进行 n 的逐位复制
};

struct C : B
{
    ~C() { } // 析构函数阻止隐式移动赋值
};

struct D : B
{
    D() { }
    ~D() { } // 析构函数本会阻止隐式移动赋值
    D& operator=(D&&) = default; // 无论如何都强制移动赋值
};

int main()
{
    A a1, a2;
    std::cout << "尝试从右值临时量移动赋值 A\n";
    a1 = f(A()); // 从右值临时量移动赋值
    std::cout << "尝试从亡值移动赋值 A\n";
    a2 = std::move(a1); // 从亡值移动赋值

    std::cout << "尝试移动赋值 B\n";
    B b1, b2;
    std::cout << "移动前，b1.s = \"" << b1.s << "\"\n";
    b2 = std::move(b1); // 调用隐式移动赋值
    std::cout << "移动后，b1.s = \"" << b1.s << "\"\n";

    std::cout << "尝试移动赋值 C\n";
    C c1, c2;
    c2 = std::move(c1); // 调用复制赋值运算符

    std::cout << "尝试移动赋值 D\n";
    D d1, d2;
    d2 = std::move(d1);
}

输出：

尝试从右值临时量移动赋值 A
移动赋值
尝试从亡值移动赋值 A
移动赋值
尝试移动赋值 B
移动前，b1.s = "测试"
移动赋值
移动后，b1.s = ""
尝试移动赋值 C
复制赋值
尝试移动赋值 D
移动赋值

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1402 | C++11 | 会调用非平凡复制赋值运算符的预置移动赋值运算符被弃置； 被弃置的预置移动赋值运算符仍参与重载决议 | 允许调用这种复制赋值运算符； 使重载决议将其忽略
CWG 1806 | C++11 | 涉及虚基类的预置移动赋值运算符的规定缺失 | 已添加
CWG 2094 | C++11 | volatile 子对象使预置的移动赋值运算符非平凡（CWG 496） | 平凡性不受影响

参阅

  • 构造函数
  • 转换构造函数
  • 复制赋值
  • 复制构造函数
  • 默认构造函数
  • 析构函数
  • 初始化
    • 聚合初始化
    • 常量初始化
    • 复制初始化
    • 默认初始化
    • 直接初始化
    • 列表初始化
    • 引用初始化
    • 值初始化
    • 零初始化
  • 移动构造函数


移动构造函数

< cpp‎ | language

类 T 的移动构造函数是非模板构造函数，它的首个形参是 T&&、const T&&、volatile T&& 或 const volatile T&&，且没有其他形参，或剩余形参均有默认值。

语法

类名 ( 类名 && ) | (1) | (C++11 起)
类名 ( 类名 && ) = default; | (2) | (C++11 起)
类名 ( 类名 && ) = delete; | (3) | (C++11 起)

其中 类名 必须指名当前类（或类模板的当前实例化），或在命名空间作用域或友元声明中声明时，必须是有限定的类名。

解释

1) 移动构造函数的典型声明。
2) 强制编译器生成移动构造函数。
3) 避免隐式生成移动构造函数。

当从同类型的右值（亡值或纯右值） (C++17 前)亡值 (C++17 起) 初始化（直接初始化或复制初始化）对象时，会调用移动构造函数，情况包括：

  • 初始化：T a = std::move(b); 或 T a(std::move(b));，其中 b 的类型是 T ；
  • 函数实参传递：f(std::move(a));，其中 a 的类型是 T 且 f 是 Ret f(T t) ；
  • 函数返回：在像 T f() 这样的函数中的 return a;，其中 a 的类型是 T，且 T 有移动构造函数。

当初始化器是纯右值时，通常会优化掉 (C++17 前)始终不会进行 (C++17 起)对移动构造函数的调用，见复制消除。

典型的移动构造函数“窃取”实参曾保有的资源（例如指向动态分配对象的指针，文件描述符，TCP socket，输入输出流，运行的线程，等等），而非复制它们，并使其实参遗留在某个合法但不确定的状态。例如，从 std::string 或从 std::vector 移动可以导致实参被置为空。但是不应该依赖此类行为。对于某些类型，例如 std::unique_ptr，移动后的状态是完全指定的。

隐式声明的移动构造函数

如果不对类类型（struct、class 或 union）提供任何用户定义的移动构造函数，且满足下列所有条件：

  • 没有用户声明的复制构造函数；
  • 没有用户声明的复制赋值运算符；
  • 没有用户声明的移动赋值运算符；
  • 没有用户声明的析构函数；

那么编译器将声明一个移动构造函数作为这个类的非 explicit 的 inline public 成员，签名为 T::T(T&&)。

一个类可以拥有多个移动构造函数，例如 T::T(const T&&) 和 T::T(T&&)。当存在用户定义的移动构造函数时，用户仍然可以通过关键词 default 强制编译器生成隐式声明的移动构造函数。

隐式声明（或在其首个声明被预置）的移动构造函数具有动态异常说明 (C++17 前)noexcept 说明 (C++17 起)中所描述的异常说明。

弃置的隐式声明的移动构造函数

如果满足下列任一条件，那么类 T 的隐式声明或预置的移动构造函数被定义为弃置的：

  • T 拥有无法移动（拥有被弃置、不可访问或有歧义的移动构造函数）的非静态数据成员；
  • T 拥有无法移动（拥有被弃置、不可访问或有歧义的移动构造函数）的直接或虚基类；
  • T 拥有带被弃置或不可访问的析构函数的直接或虚基类；
  • T 是联合式的类，且拥有带非平凡移动构造函数的变体成员。

重载决议忽略被弃置的预置移动构造函数（否则它会阻止从右值复制初始化）。

平凡的移动构造函数

如果满足下列所有条件，类 T 移动构造函数是平凡的：

  • 它不是用户提供的（即它是隐式定义或预置的）；
  • T 没有虚成员函数；
  • T 没有虚基类；
  • 为 T 的每个直接基类选择的移动构造函数都是平凡的；
  • 为 T 的每个类类型（或类类型数组）的非静态成员选择的移动构造函数都是平凡的。

平凡的移动构造函数是与平凡的复制构造函数实施相同动作的构造函数，即它如同用 std::memmove 来进行对象表示的复制。所有与 C 兼容的数据类型（POD 类型）都可以平凡移动。

合格的移动构造函数

没有被弃置的移动构造函数是合格的。

 (C++20 前)

满足下列所有条件的移动构造函数是合格的：

  • 它没有被弃置，且
  • 满足它的所有关联约束（如果存在），且
  • 没有比它更受约束且拥有相同的第一形参类型的移动构造函数。
 (C++20 起)

合格的移动构造函数的平凡性确定该类是否为隐式生存期类型，以及该类是否为可平凡复制类型。

隐式定义的移动构造函数

如果隐式声明的移动构造函数没有被弃置也不平凡，那么当它被 ODR 式使用或用于常量求值时，它会被编译器定义（生成并编译函数体）。对于联合体类型，隐式定义的移动构造函数（如同以 std::memmove）复制它的对象表示。对于非联合类类型（class 与 struct），该构造函数用以亡值实参执行的直接初始化，按照初始化顺序，对对象的各基类和非静态成员进行完整的逐对象移动。如果它满足对于 constexpr 构造函数的要求，那么生成的移动构造函数也是 constexpr 的。

注解

为使强异常保证可行，用户定义的移动构造函数不应该抛出异常。例如，std::vector 在需要重新放置元素时，基于 std::move_if_noexcept 在移动和复制之间选择。

如果同时提供了复制和移动构造函数而没有其他可行的构造函数，那么重载决议在实参是相同类型的右值（如 std::move 的结果的亡值，或如无名临时量的纯右值）时选择移动构造函数，而在实参是左值（具名对象或返回左值引用的函数/运算符）时选择复制构造函数。如果只提供复制构造函数，那么重载决议对于所有实参类别都会选择它（只要它接收到 const 的引用，因为右值能绑定到 const 引用），这使得复制可以作为在移动不可用时的后备。

当接收右值引用为其形参时，构造函数被称作“移动构造函数”。它没有义务移动任何内容，不要求类拥有要被移动的资源，而且在受允许（但可能没意义）的以 const 右值引用（const T&&）为形参的情况中，‘移动构造函数’可能无法移动资源。

示例

#include <string>
#include <iostream>
#include <iomanip>
#include <utility>

struct A
{
    std::string s;
    int k;
    A() : s("测试"), k(-1) { }
    A(const A& o) : s(o.s), k(o.k) { std::cout << "移动失败！\n"; }
    A(A&& o) noexcept :
           s(std::move(o.s)),       // 类类型成员的显式移动
           k(std::exchange(o.k, 0)) // 非类类型成员的显式移动
    { }
};

A f(A a)
{
    return a;
}

struct B : A
{
    std::string s2;
    int n;
    // 隐式移动构造函数 B::(B&&)
    // 调用 A 的移动构造函数
    // 调用 s2 的移动构造函数
    // 并进行 n 的逐位复制
};

struct C : B
{
    ~C() { } // 析构函数阻止隐式移动构造函数 C::(C&&)
};

struct D : B
{
    D() { }
    ~D() { }          // 析构函数阻止隐式移动构造函数 D::(D&&)
    D(D&&) = default; // 强制生成移动构造函数
};

int main()
{
    std::cout << "尝试移动 A\n";
    A a1 = f(A()); // 按值返回时，从函数形参移动构造其目标
    std::cout << "移动前，a1.s = " << std::quoted(a1.s)
        << " a1.k = " << a1.k << '\n';
    A a2 = std::move(a1); // 从亡值移动构造
    std::cout << "移动后，a1.s = " << std::quoted(a1.s)
        << " a1.k = " << a1.k << '\n';

    std::cout << "尝试移动 B\n";
    B b1;
    std::cout << "移动前，b1.s = " << std::quoted(b1.s) << "\n";
    B b2 = std::move(b1); // 调用隐式移动构造函数
    std::cout << "移动后，b1.s = " << std::quoted(b1.s) << "\n";

    std::cout << "尝试移动 C\n";
    C c1;
    C c2 = std::move(c1); // 调用复制构造函数

    std::cout << "尝试移动 D\n";
    D d1;
    D d2 = std::move(d1);
}

输出：

尝试移动 A
移动前，a1.s = "测试" a1.k = -1
移动后，a1.s = "" a1.k = 0
尝试移动 B
移动前，b1.s = "测试"
移动后，b1.s = ""
尝试移动 C
移动失败！
尝试移动 D

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1402 | C++11 | 会调用非平凡复制构造函数的预置移动构造函数被弃置； 被弃置的预置移动构造函数仍参与重载决议 | 允许调用这种复制构造函数； 使重载决议将其忽略
CWG 2094 | C++11 | volatile 子对象使移动构造函数非平凡（CWG 496） | 平凡性不受影响


命名空间

< cpp‎ | language

命名空间提供了一种在大项目中避免名字冲突的方法。

在命名空间块内声明的符号被放入一个具名的作用域中，避免这些符号被误认为其他作用域中的同名符号。

多个命名空间块的名字可以相同。这些块中的所有声明在该具名作用域声明。

语法

namespace 命名空间名 { 声明序列 } | (1) |
inline namespace 命名空间名 { 声明序列 } | (2) | (C++11 起)
namespace { 声明序列 } | (3) |
命名空间名::成员名 | (4) |
using namespace 命名空间名; | (5) |
using 命名空间名::成员名; | (6) |
namespace 名字 = 有限定命名空间 ; | (7) |
namespace 命名空间名::成员名 { 声明序列 } | (8) | (C++17 起)
namespace 命名空间名::inline 成员名 { 声明序列 } | (9) | (C++20 起)
1) 命名空间 命名空间名 的具名命名空间定义。
2) 命名空间 命名空间名 的内联命名空间定义。命名空间名 内的声明将在其外围命名空间可见。
3) 无名命名空间定义。其成员具有从声明点到翻译单元结尾的潜在作用域，并具有内部连接。
4) 命名空间名（还有类名）可以出现在作用域解析运算符的左侧，作为有限定的名字查找的一部分。
5) using 指令：从 using 指令之后到指令出现的作用域结尾为止，以对任何名字的无限定名字查找的视点来说，来自 命名空间名 的任何名字均可见，如同它在同时含有该 using 指令和 命名空间名 两者的最接近外围命名空间作用域声明一样。
6) using 声明：令来自命名空间 命名空间名 的符号 成员名 对无限定名字查找可见，如同将它在包含该 using 声明的相同的类作用域、块作用域或命名空间之中声明一样。
7) 命名空间别名定义（namespace-alias-definition）：令 名字 成为另一命名空间的同义词：见命名空间别名。
8) 嵌套命名空间定义：namespace A::B::C { ... } 等价于 namespace A { namespace B { namespace C { ... } } }。
9) 嵌套内联命名空间定义：namespace A::B::inline C { ... } 等价于 namespace A::B { inline namespace C { ... } }。inline 可以在首个以外的每个命名空间名之前出现：namespace A::inline B::C {} 等价于 namespace A { inline namespace B { namespace C {} } }。

解释

命名空间

inline(可选) namespace 属性(可选) 标识符 { 命名空间体 }
inline - (C++11 起) 存在时，此命名空间是内联命名空间（见下文）。如果原初命名空间定义不使用 inline，那么不能出现在扩展命名空间定义中
属性 - (C++17 起) 任意数量的属性的可选序列
标识符 - 下列之一：
  • 先前未使用过的标识符，此时这是原初命名空间定义
  • 命名空间名，此时这是扩展命名空间定义
  • 被 :: 分隔的外围命名空间说明符，以 标识符 结束，此时这是嵌套命名空间定义
 (C++17 起)
命名空间体 - 任何种类（包含类、函数定义和嵌套命名空间等）的声明的可能为空的序列

命名空间定义只允许在命名空间作用域，包括全局作用域中出现。

为了重新打开一个既存的命名空间（正式而言，作为扩展命名空间定义），对用于命名空间定义中的 标识符的查找必须解析为一个命名空间名（而非命名空间别名），该名字被声明为一个外围命名空间或外围命名空间中的内联命名空间的一个成员。

命名空间体 定义了一个命名空间作用域，这将影响名字查找。

出现在 命名空间体（包含嵌套命名空间定义）中的声明所引入的所有名字均成为命名空间 标识符 的成员，无论此命名空间定义是原初命名空间定义（引入 标识符 者）还是扩展命名空间定义（“重打开”已定义命名空间者）。

一个在命名空间体内声明的命名空间成员，可以在该命名空间体外部用显式限定进行定义或再声明

namespace Q {
    namespace V {   // V 是 Q 的成员，且完全在 Q 内定义
// namespace Q::V { // C++17 起可以用来替代以上两行
        class C { void m(); }; // C 是 V 的成员且完全在 V 内定义
                               // C::m 仅被声明
        void f(); // f 是 V 的成员，但只在此声明
    }

    void V::f() // 在 V 外对 V 的成员 f 的定义
                // f 的外围命名空间仍是全局命名空间、Q 与 Q::V
    {
        extern void h(); // 这声明了 ::Q::V::h
    }

    void V::C::m() // 在命名空间外（及类外）对 V::C::m 的定义
                   // 外围命名空间是全局命名空间、Q 与 Q::V
    {}
}

命名空间外的定义和再声明只能出现在

  • 声明点后，
  • 命名空间作用域中，且
  • 作用域的命名空间（包括全局命名空间）包围了原命名空间。
它们也应使用限定标识语法。 (C++14 起)
namespace Q {
    namespace V {  // V 的原初命名空间定义
        void f();  // Q::V::f 的声明
    }

    void V::f() {} // OK
    void V::g() {} // 错误：g() 目前还不是 V 的成员

    namespace V {  // V 的扩展命名空间定义
        void g();  // Q::V::g 的声明
    }
}

namespace R {         // 不是 Q 的外围命名空间
    void Q::V::g() {} // 错误：不能在 R 内定义 Q::V::g
}

void Q::V::g() {}     // OK：全局命名空间包围 Q

在非局部类 X 中由友元声明所引入的名字会成为 X 的最内层外围命名空间的成员，但它们对于通常的名字查找（无限定或有限定）不可见，除非在命名空间作用域中类定义前后提供与之匹配的声明。这种名字可以通过实参依赖查找找到，其中同时考虑命名空间和类。

在确定名字是否与先前声明的名字冲突时，这种友元声明只考虑最内层的外围命名空间。

void h(int);
namespace A {
    class X {
        friend void f(X);       // A::f 是友元
        class Y {
            friend void g();    // A::g 是友元
            friend void h(int); // A::h 是友元，与 ::h 不冲突
        };
    };
    // A::f、A::g 与 A::h 在命名空间作用域不可见
    // 虽然它们是命名空间 A 的成员

    X x;
    void g() { // A::g 的定义
        f(x);  // A::X::f 通过实参依赖查找找到
    }

    void f(X) {}       // A::f 的定义
    void h(int) {}     // A::h 的定义
    // A::f、A::g 与 A::h 现在在命名空间作用域可见
    // 而且它们也是 A::X 与 A::X::Y 的友元
}

内联命名空间

内联命名空间是在其原初命名空间定义中使用了可选的关键词 inline 的命名空间。

在许多情况下（列于下方），内联命名空间的成员都被当做如同它们是其外围命名空间的成员一样。这项性质是传递性的：如果命名空间 N 包含内联命名空间 M，且它又继而包含内联命名空间 O，则 O 的成员能按如同它们是 M 或 N 的成员一样使用。

  • 在外围命名空间中，隐含地插入了一条指名内联命名空间的 using 指令（类似于无名命名空间的隐式 using 指令）
  • 在实参依赖查找中，当一个命名空间被添加到关联命名空间集合时，它的内联命名空间也会一起被添加，且当一个内联命名空间被添加到关联命名空间列表时，它的外围命名空间也会一起被添加。
  • 内联命名空间的每个成员，都能按照如同它是外围命名空间的成员一样，进行部分特化、显式实例化或显式特化。
  • 检验外围命名空间的有限定名字查找将包含来自其各个内联命名空间的名称，即使同一名称已在外围命名空间存在。
{ // C++14 中，std::literals 及其成员命名空间是内联的
    using namespace std::string_literals; // 令来自 std::literals::string_literals
                                          // 的 operator""s 可见
    auto str = "abc"s;
}
{
    using namespace std::literals; // 令 std::literals::string_literals::operator""s 与
                                   // std::literals::chrono_literals::operator""s 均可见
    auto str = "abc"s;
    auto min = 60s;
}
{
    using std::operator""s; // 令 std::literals::string_literals::operator""s 与
                            // std::literals::chrono_literals::operator""s 均可见
    auto str = "abc"s;
    auto min = 60s;
}

注意：上述关于特化的规则允许建立库版本：库模板的不同实现可以在不同的内联命名空间定义，同时仍然允许用户通过主模板的显式特化来扩充父命名空间。

 (C++11 起)

无名命名空间

无名命名空间定义是具有下列形式的命名空间定义。

inline(可选) namespace 属性(可选) { 命名空间体 }
inline | - | (C++11 起) 存在时，此命名空间是内联命名空间
属性 | - | (C++17 起) 任意数量的属性的可选序列

此定义被当做一个拥有独有名字的命名空间定义，与当前作用域中指名此无名命名空间的一条 using 指令 （注：隐式添加的 using 指令使有限定查找和无限定查找可以发现该命名空间，但实参依赖查找不在此列）。

namespace {
    int i; // 定义 ::(独有)::i
}
void f() {
    i++;   // 自增 ::(独有)::i
}

namespace A {
    namespace {
        int i;        // A::(独有)::i
        int j;        // A::(独有)::j
    }
    void g() { i++; } // A::(独有)::i++
}

using namespace A; // 从 A 引入所有名称到全局命名空间
void h() {
    i++;    // 错误：::(独有)::i 与 ::A::(独有)::i 均在作用域中
    A::i++; // OK：自增 A::(独有)::i
    j++;    // OK：自增 A::(独有)::j
}
虽然无名命名空间中的名字可以声明为具有外部连接，但从其他翻译单元无法访问它们，因为其命名空间名是独有的。 | (C++11 前)
无名命名空间以及所有直接或间接在无名命名空间内声明的命名空间都具有内部连接，这表示声在无名命名空间内声明的所有名字都具有内部连接。 | (C++11 起)

using 声明

引入在别处定义的名称到此 using 声明出现的声明性区域。

using typename(可选) 嵌套名说明符 无限定标识 ; | (C++17 前)
using 声明符列表 ; | (C++17 起)
typename | - | 当 using 声明向类模板引入基类的成员类型时，关键词 typename 可在必要时用于解析待决名
嵌套名说明符 | - | 名字与作用域解析运算符 :: 的序列，以作用域解析运算符结束。单个 :: 代表全局命名空间。
无限定标识 | - | 标识表达式
声明符列表 | - | 一或多个形式为 typename(可选) 嵌套名说明符 无限定标识 的声明符的逗号分隔列表。声明符可以后随省略号以指示包展开，但这种形式只在派生类定义中有意义

using 声明可以用于将命名空间的成员引入到其他命名空间和块作用域中，或将基类的成员引入到派生类定义中，或将枚举项引入命名空间、块或类作用域中 (C++20 起)。

拥有多于一个 using 声明符的 using 声明，等价于对应的单个 using 声明符的 using 声明的序列。

 (C++17 起)

对于在派生类定义中的用法，见 using 声明。

由 using 声明引入到命名空间作用域的名字，可以同任何其他名字一样使用，包含从其他作用域进行的有限定查找：

void f();
namespace A {
    void g();
}

namespace X {
    using ::f;        // 全局 f 现在作为 ::X::f 可见
    using A::g;       // A::g 现在作为 ::X::g 可见
    using A::g, A::g; // (C++17) OK：命名空间作用域允许双重声明
}

void h()
{
    X::f(); // 调用 ::f
    X::g(); // 调用 A::g
}

在用 using 声明从命名空间采取成员后，如果该命名空间被扩充并引入了同名的额外声明，则这些额外声明不会通过该 using 声明变为可见（与 using 指令相反）。一个例外是 using 声明指名类模板时：后面引入的部分特化实际上是可见的，因为其查找是通过主模板达成的。

namespace A {
    void f(int);
}
using A::f; // ::f 现在是 A::f(int) 的同义词

namespace A {     // 命名空间扩展
    void f(char); // 不更改 ::f 的含义
}

void foo() {
    f('a'); // 调用 f(int)，即使 f(char) 存在。
}

void bar() {
    using A::f; // 此 f 是 A::f(int) 与 A::f(char) 的同义词
    f('a');     // 调用 f(char)
}

using 声明不能指名模板标识或命名空间，或有作用域的枚举项 (C++20 前)。using 声明中的每个声明符引入一个且只有一个名字，例如枚举 的 using 声明不引入其任何枚举项。

针对相同名字的常规声明的所有制约，隐藏和重载规则，均适用于 using 声明：

namespace A {
    int x;
}

namespace B {
    int i;
    struct g { };
    struct x { };
    void f(int);
    void f(double);
    void g(char); // OK：函数名 g 隐藏类 g
}

void func() {
    int i;
    using B::i;   // 错误：i 声明了两次

    void f(char);
    using B::f;   // OK：f(char)、f(int)、f(double) 是重载
    f(3.5);       // 调用 B::f(double)

    using B::g;
    g('a');       // 调用 B::g(char)
    struct g g1;  // 声明 g1 拥有类型 struct B::g

    using B::x;
    using A::x;   // OK ：隐藏 B::x
    x = 99;       // 赋值给 A::x
    struct x x1;  // 声明 x1 拥有类型 struct B::x
}

如果 using 声明引入了一个函数，则声明一个拥有相同名字和形参列表的函数是非良构的（除非是同一函数的声明）。如果 using 声明引入了一个函数模板，则声明拥有相同名字、形参类型列表、返回类型及模板形参列表的函数模板是非良构的。两个 using 声明可以引入拥有相同名字和形参列表的函数，但试图调用该函数会导致程序非良构。

namespace B {
    void f(int);
    void f(double);
}

namespace C {
    void f(int);
    void f(double);
    void f(char);
}

void h() {
    using B::f;  // 引入 B::f(int)、B::f(double)
    using C::f;  // 引入 C::f(int)、C::f(double) 及 C::f(char)
    f('h');      // 调用 C::f(char)
    f(1);        // 错误：B::f(int) 还是 C::f(int)？
    void f(int); // 错误：f(int) 与 C::f(int) 及 B::f(int) 冲突
}

如果某个实体被声明，但未在某内层命名空间中被定义，然后在外层命名空间中通过 using 声明予以声明，然后在外层命名空间中再出现拥有相同的非限定名的定义，则该定义是外层命名空间的成员，且与 using 声明冲突：

namespace X {
  namespace M {
     void g(); // 声明，但不定义 X::M::g()
  }
  using M::g;
  void g();   // 错误：试图声明与 X::M::g() 冲突的 X::g
}

更一般地，在任何命名空间作用域中出现并用无限定标识符引入名字的一个声明始终向它所在的命名空间中引入一个成员，而并非向任何其他命名空间引入。例外情况是对在内联命名空间定义的主模板进行的显式实例化和显式特化：因为它们不引入新名字，它们在外围命名空间中可以使用无限定标识。

 (C++14 起)

using 指令

using 指令是拥有下列语法的块声明：

属性(可选) using namespace 嵌套名说明符(可选) 命名空间名 ; (1)
属性 | - | (C++11 起) 应用到此 using 指令的任意数量的属性
嵌套名说明符 | - | 名字与作用域解析运算符 :: 的序列，以作用域解析运算符结束。单个 :: 代表全局命名空间。
命名空间名 | - | 命名空间名。查找此名时，查找只考虑命名空间声明

using 指令只能在命名空间作用域和块作用域中出现。从某个 using 指令之后到该指令出现的作用域结尾为止，以任何名字的无限定名字查找的角度，来自 命名空间名 的每个名字均可见，如同它在同时包含该 using 指令和 命名空间名 两者的最接近外围命名空间声明一样。

using 指令不向其所出现的声明性区域添加任何名字（与 using 声明不同），因而并不妨碍再声明相同的名字。

using 指令对于无限定查找是传递性的：如果作用域包含指名 命名空间名 的 using 指令，而它自身包含对某 命名空间名2 的 using 指令，则效果如同第二个命名空间中的 using 指令出现在第一个之中一样。这些传递性命名空间的出现顺序并不影响名字查找。

namespace A {
    int i;
}

namespace B {
    int i;
    int j;
    namespace C {
        namespace D {
            using namespace A; // 将所有来自 A 的名称注入全局命名空间
            int j;
            int k;
            int a = i;         // i 是 B::i，因为 B::i 隐藏 A::i
        }
        using namespace D; // 注入来自 D 的名称到 C
                           // 注入来自 A 的名称到全局命名空间

        int k = 89; // 声明与用 using 引入者等同的名称 OK
        int l = k;  // 歧义：C::k 还是 D::k
        int m = i;  // OK：B::i 隐藏 A::i
        int n = j;  // OK：D::j 隐藏 B::j
    }
}

在使用 using 指令指名某命名空间后，若该命名空间被扩充并向其添加了额外的成员和/或 using 指令，则这些额外成员和额外的命名空间通过该 using 指令可见（与 using 声明相反）

namespace D {
    int d1;
    void f(char);
}
using namespace D; // 引入 D::d1、D::f、D::d2、D::f，
                   // E::e 及 E::f 到全局命名空间！

int d1;            // OK：声明时与 D::d1 不冲突
namespace E {
    int e;
    void f(int);
}

namespace D {          // 命名空间扩展
    int d2;
    using namespace E; // 传递性 using 指令
    void f(int);
}

void f() {
    d1++;    // 错误：歧义：::d1 还是 D::d1？
    ::d1++;  // OK
    D::d1++; // OK
    d2++;    // OK，d2 是 D::d2
    e++;     // OK：因为传递性 using，所以 e 是 E::e
    f(1);    // 错误：歧义：D::f(int) 还是 E::f(int)？
    f('a');  // OK：仅有的 f(char) 是 D::f(char)
}

注解

在任何命名空间作用域中的 using 指令 using namespace std;将命名空间 std 中的所有名字都引入到全局命名空间中（因为全局命名空间是同时包含 std 和任何用户声明命名空间的最近命名空间），这可能导致不合预期的名字冲突。通常认为，在头文件的文件作用域中采用它或其他的 using 指令是不良的实践（SF.7：不要在头文件的全局作用域中写 using namespace）。

示例

此例展示如何用命名空间创建已在 std 命名空间命名的类。

#include <vector>

namespace vec {

    template< typename T >
    class vector {
        // ...
    };

}

int main()
{
    std::vector<int> v1; // 标准 vector。
    vec::vector<int> v2; // 用户定义 vector。

    v1 = v2; // 错误：v1 与 v2 是不同类型的对象。

    {
        using namespace std;
        vector<int> v3; // 同 std::vector
        v1 = v3; // OK
    }

    {
        using vec::vector;
        vector<int> v4; // 同 vec::vector
        v2 = v4; // OK
    }

    return 0;
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1838 | C++14 | 外层命名空间的非限定定义，曾能定义一个 在另一命名空间声明但不定义的实体，并用 using 拉入 | 非限定定义始终指涉其命名空间

参阅

命名空间别名 为既存命名空间创建一个别名


命名空间别名

< cpp‎ | language

命名空间别名允许程序员定义命名空间的另一个名字。

它们常用作长的或嵌套过深的命名空间的简便使用方式。

语法

namespace 别名 = 命名空间名; | (1)
namespace 别名 = ::命名空间名; | (2)
namespace 别名 = 嵌套名::命名空间名; | (3)

解释

新别名 别名 提供另一种访问 命名空间名 的方法。

别名 必须是先前未使用过的名称。别名 在引入它的作用域的期间内有效。

示例

#include <iostream>

namespace foo {
    namespace bar {
         namespace baz {
             int qux = 42;
         }
    }
}

namespace fbz = foo::bar::baz;

int main()
{
    std::cout << fbz::qux << '\n';
}

输出：

42

参阅

命名空间声明 | 标识命名空间
类型别名声明 (C++11) | 创建类型的同义词


嵌套类

< cpp‎ | language

class/struct 或 union 的声明可以在另一个类中出现。这种声明声明一个嵌套类（nested class）。

解释

嵌套类的名字在它的外围类作用域中存在，而且从嵌套类的成员函数中进行名字查找会在检测嵌套类的作用域后访问外围类的作用域。与其外围类的任何成员相似，嵌套类也拥有所有外围类拥有访问权的名字（私有、受保护等）的访问权，但其他方面它是独立的，而且对外围类的 this 指针没有特殊访问权。

嵌套类中的声明只能使用外围类中的类型名、静态成员及枚举项。 | (C++11 前)
嵌套类中的声明能使用外围类的所有成员，遵循非静态成员的常规使用规则。 | (C++11 起)
int x,y; // 全局变量
class enclose // 外围类
{
    // 注：私有成员
    int x;
    static int s;
public:
    struct inner // 嵌套类
    {
        void f(int i)
        {
            x = i; // 错误：不能不带实例地写入非静态的 enclose::x
            int a = sizeof x; // C++11 前错误，C++11 中 OK：sizeof 的操作数不求值，
                              // 可以这样使用非静态的 enclose::x 。
            s = i;   // OK：可以赋值给静态 enclose::s
            ::x = i; // OK：可以赋值给全局 x
            y = i;   // OK：可以赋值给全局 y
        }

        void g(enclose* p, int i)
        {
            p->x = i; // OK：赋值给 enclose::x
        }
    };
};

在嵌套类中定义的友元函数对外围类的成员没有特殊访问权，虽然来自在嵌套类中定义的成员函数体内的查找能找到外围类的私有成员。

嵌套类成员的类外定义在外围类的命名空间中出现：

struct enclose
{
    struct inner
    {
        static int x;
        void f(int i);
    };
};

int enclose::inner::x = 1;       // 定义
void enclose::inner::f(int i) {} // 定义

嵌套类可以前置声明并在之后定义，在外围类的体内或体外均可：

class enclose
 {
    class nested1;    // 前置声明
    class nested2;    // 前置声明
    class nested1 {}; // 嵌套类的定义
};

class enclose::nested2 { }; // 嵌套类的定义

嵌套类声明服从成员访问说明符，从外围类的作用域之外不能指名私有的成员类，尽管可以操作该类的对象：

class enclose
{
    struct nested // 私有成员
    {
        void g() {}
    };
public:
    static nested f() { return nested{}; }
};

int main()
{
    //enclose::nested n1 = e.f(); // 错误：'nested' 是私有的

    enclose::f().g();       // OK：没有指名 'nested'
    auto n2 = enclose::f(); // OK：没有指名 'nested'
    n2.g();
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 45 | C++98 | 嵌套类的成员无法访问外围类及其友元 | 它们和外围类的其他成员有相同的访问权限 （同时解决了 CWG 的8号和10号问题）

引用

  • C++11 标准（ISO/IEC 14882:2011）：
  • 9.7 Nested class declarations [class.nest]
  • C++98 标准（ISO/IEC 14882:1998）：
  • 9.7 Nested class declarations [class.nest]


new 表达式

< cpp‎ | language

创建并初始化拥有动态存储期的对象，这些对象的生存期不受它们创建时所在的作用域限制。

语法

::(可选) new ( 类型 ) 初始化器(可选) | (1)
::(可选) new new类型 初始化器(可选) | (2)
::(可选) new (布置参数) ( 类型 ) 初始化器(可选) | (3)
::(可选) new (布置参数) new类型 初始化器(可选) | (4)
1) 尝试创建类型标识 类型 所指代的类型的一个对象，它可以是数组类型，可以包含占位符类型说明符 (C++11 起)，或包含将由类模板实参推导推出的类模板名 (C++17 起)。
2) 同(1)，但 new类型 不能包含括号：
new int(*[10])(); // 错误：分析成 (new int) (*[10]) ()
new (int (*[10])()); // OK：分配 10 个函数指针的数组
另外，new类型 是贪心的：它将包含可以成为声明符一部分的所有记号：
new int + 1; // OK：分析成 (new int) + 1，增加 new int 所返回的指针
new int * 1; // 错误：分析成 (new int*) (1)
3) 同(1)，但会向分配函数提供额外实参，见布置 new
4) 同(2)，但会向分配函数提供额外实参

符合下列条件之一时，必须要有 初始化器：

  • 类型 或 new类型 是未知边界数组
  • 类型 或 new类型 中使用了占位符，即 auto 或 decltype(auto) (C++14 起)，可能与类型约束结合 (C++20 起)
 (C++11 起)
  • 类型 或 new类型 中使用了类模板，且该模板有实参需要被推导
 (C++17 起)
double* p = new double[]{1,2,3}; // 创建 double[3] 类型的数组
auto p = new auto('c');          // 创建单个 char 类型的对象。p 是一个 char*

auto q = new std::integral auto(1);         // OK: q 是一个 int*
auto q = new std::floating_point auto(true) // 错误：不满足类型约束

auto r = new std::pair(1, true); // OK: r 是一个 std::pair<int, bool>*
auto r = new std::vector;        // 错误：无法推导元素类型

解释

new 表达式尝试申请存储空间，并在已申请的存储空间上，尝试构造并初始化一个无名的对象或对象数组。new 表达式返回一个指向它构造的对象或者对象数组的纯右值指针。

如果 类型 或 new类型 是数组类型，那么它第一维之外的所有维都必须指定为正的整数常量表达式 (C++14 前)类型是 std::size_t 的经转换的常量表达式 (C++14 起)，但（仅当使用无括号语法 (2) 时）第一维可以是整数类型、枚举类型或拥有单个到整数或枚举类型的非 explicit 转换函数的类类型 (C++14 前)任何能转换成 std::size_t 的表达式 (C++14 起)。这是唯一直接创建大小在运行时定义的数组的方法，这种数组常被称作动态数组：

int n = 42;
double a[n][5]; // 错误
auto p1 = new double[n][5];   // OK
auto p2 = new double[5][n];   // 错误：只有第一维可以不是常量
auto p3 = new (double[n][5]); // 错误：语法 (1) 不能用于动态数组

如果第一维中的值（如果需要则转换到整数或枚举类型）为负，那么行为未定义。

 (C++11 前)

下列情况中指定第一维的表达式是错误的：

  • 表达式是非类类型，且其值在转换到 std::size_t 前是负的；
  • 表达式拥有类类型，且其值在用户定义转换函数后，在第二次标准转换前是负的；
  • 表达式的值大于某个实现定义极限；
  • 其值小于花括号初始化器中提供的数组元素数量（也包含字符串字面量中的终止 '\0'）。

如果第一维值因以上任何原因而错误，

  • 如果在转换到 std::size_t 后，第一维是核心常量表达式，那么程序非良构（引发编译时错误）；
  • 否则，如果要调用的分配函数是不抛出的，那么 new 表达式返回请求结果类型的空指针
  • 否则，new 表达式不调用分配函数，而代之以抛出 std::bad_array_new_length 类型或它的派生类的异常
 (C++11 起)

第一维为零是可接受的，分配函数也会被调用。

注意：std::vector 提供了与一维的动态数组类似的功能。

分配

new 表达式通过调用适当的分配函数分配存储。如果 类型 或 new类型 是非数组类型，那么函数名是 operator new。如果 类型 或 new类型 是数组类型，那么函数名是 operator new[]。

如分配函数中所描述，C++ 程序可提供这些函数的全局和类特有替换函数。如果 new 表达式以 :: 运算符开始，如 ::new T 或 ::new T[n]，那么忽略类特有替换函数（在全局作用域中查找函数）。否则，如果 T 是类类型，那么就会从 T 的类作用域中开始查找。

在调用分配函数时，new 表达式将请求的字节数作为 std::size_t 类型的第一参数传递给它，该参数对于非数组 T 恰好是 sizeof(T)。

数组的分配中可能带有一个未指明的开销（overhead），且每次调用 new 的这个开销可能不同，除非选择的分配函数是标准非分配形式。new 表达式所返回的指针等于分配函数所返回的指针加上该值。许多实现使用数组开销存储数组中的对象数量，delete[] 表达式会用它进行正确数量的析构函数调用。另外，如果用 new 分配 char、unsigned char 或 std::byte (C++17 起)的数组，那么它可能从分配函数请求额外内存，以此保证所有不大于请求数组大小的类型的对象在放入所分配的数组中时能够正确对齐。

允许将各个 new 表达式通过可替换分配函数所进行的分配予以省略或合并。在省略的情况下，存储可以由编译器提供，而无需调用分配函数（这也允许优化掉不使用的 new 表达式）。在合并的情况下且满足以下所有条件时，new 表达式 E1 所做的分配可以被扩展，以提供另一个 new 表达式 E2 的额外存储： 1) E1 所分配对象的生存期严格包含 E2 所分配对象的生存期， 2) E1 与 E2 将调用同一可替换全局分配函数 3) 对于抛出异常的分配函数，E1 与 E2 中的异常将首先被同一处理块捕捉。 注意此优化仅在使用 new 表达式，而非调用可替换分配函数的任何其他方法时允许：delete [] new int[10]; 能被优化掉，但 operator delete ( operator new (10)); 不能。 | (C++14 起)
在常量表达式求值期间，始终省略对分配函数的调用。只有在其他情况下调用可替换全局分配函数的 new 表达式能在常量表达式中求值。 | (C++20 起)
布置 new

如果提供了 布置参数，那么它们会作为额外实参传递给分配函数。这些分配函数被称作“布置 new”，这来源于标准分配函数 void* operator new ( std::size_t, void*)，它直接返回未更改的第二实参。它被用于在已分配的存储中构造对象：

// 在任何块作用域内……
{
    alignas(T) unsigned char buf[sizeof(T)];
    // 静态分配拥有自动存储期的存储，对任何对象类型 `T` 足够大。
    T* tptr = new(buf) T; // 构造一个 `T` 对象，将它直接置于
                          // 你预分配的位于内存地址 `buf` 的存储。
    tptr->~T();           // 如果程序依赖对象的析构函数的副作用，你必须**手动**调用它。
}                         // 离开此块作用域自动解分配 `buf` 。

注意：分配器 (Allocator) 类的各成员函数封装了此功能。

在分配具有超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 的对齐要求的对象或这种对象的数组时，new 表达式将对齐要求作为第二实参（以 std::align_val_t 包装）传递给分配函数（对于布置形式，布置参数 被放在对齐之后，作为第三、第四个实参等）。如果重载决议失败（当定义了具有不同签名的类特有分配函数时，会发生此种情况，因为它隐藏了全局版本），那么会以实参列表中不带对齐再次尝试进行重载决议。这允许不关心对齐的类特有分配函数优先于全局的关心对齐的分配函数。

 (C++17 起)
new T;      // 调用 operator new(sizeof(T))
            // (C++17) 或 operator new(sizeof(T), std::align_val_t(alignof(T))))
new T[5];   // 调用 operator new[](sizeof(T)*5 + overhead)
            // (C++17) 或 operator new(sizeof(T)*5+overhead, std::align_val_t(alignof(T))))
new(2,f) T; // 调用 operator new(sizeof(T), 2, f)
            // (C++17) 或 operator new(sizeof(T), std::align_val_t(alignof(T)), 2, f)

如果不抛出的分配函数（例如 new( std::nothrow ) T 所选择的）因为分配失败返回空指针，那么 new 表达式会立即返回，而不会试图初始化对象或调用解分配函数。如果将空指针作为实参传给不分配的布置 new 表达式，而这会使得被选择的标准不分配布置分配函数返回空指针，那么行为未定义。

构造

new 表达式所创建的对象按照下列规则初始化：

  • 对于非数组的 类型 或 new类型，在所得内存区域中构造单个对象。
  • 如果没有 初始化器，那么对象会被默认初始化。
  • 如果 初始化器 是带括号的实参列表，那么对象会被直接初始化。
  • 如果 初始化器 是花括号包围的实参列表，那么对象会被列表初始化。
 (C++11 起)
  • 如果 类型 或 new类型 是数组类型，那么初始化一个数组的对象。
  • 如果没有 初始化器，那么每个元素都会被默认初始化。
  • 如果 初始化器 是一对空括号，那么每个元素被值初始化。
  • 如果 初始化器 是花括号包围的实参列表，那么数组会被聚合初始化。
 (C++11 起)
  • 如果 初始化器 是带括号的实参列表，那么数组会被聚合初始化。
 (C++20 起)

如果初始化因抛出异常而终止（例如来自构造函数），那么 new 表达式在已经分配了任何存储的情况下会调用适当的解分配函数：对于非数组 类型 或 new类型 是 operator delete，而对于数组 类型 或 new类型 是 operator delete []。如果 new 表达式使用 ::new 语法，那么会在全局作用域查找解分配函数，否则如果 T 是类类型，那么会在 T 的作用域查找。如果失败的是常规（非布置）分配函数，那么会遵循 delete 表达式中所述的规则查找解分配函数。对于失败的布置 new，与之匹配的解分配函数中除第一个外的所有形参的类型，必须与布置 new 的各形参类型相同。对解分配函数的调用中，将先前从分配函数取得的值作为第一实参，将对齐作为可选的对齐参数， (C++17 起)并将 布置参数（如果存在）作为额外的布置参数。如果找不到解分配函数，那么不会解分配内存。

内存泄漏

new 表达式所创建的对象（拥有动态存储期的对象）会持续到将 new 表达式所返回的指针用于匹配的 delete 表达式之时。如果指针的原值丢失，那么对象不可达且无法解分配：发生内存泄漏 (memory leak)。

对指针赋值时可能发生：

int* p = new int(7); // 动态分配的 int 带值 7
p = nullptr; // 内存泄漏

或指针离开作用域：

void f()
{
    int* p = new int(7);
} // 内存泄漏

或因为异常：

void f()
{
   int* p = new int(7);
   g();      // 可能抛出异常
   delete p; // 如果没有异常则 ok
} // 如果 g() 抛出异常则内存泄漏

为了简化动态分配的对象管理，通常将 new 表达式的结果存储于智能指针中：std::auto_ptr (C++17 前)std::unique_ptr 或 std::shared_ptr (C++11 起)。这些指针保证在上述情形中执行 delete 表达式。

关键词

new

注解

Itanium C++ ABI 要求数组分配开销在创建的数组元素类型为可平凡析构时为零。MSVC 也是这样。

某些实现（如 VS 2019 v16.7 前的 MSVC）在元素类型非可平凡析构的情况下非分配布置数组 new 时会有非零的数组分配开销，这从 CWG2382 起不再遵从标准。

创建 char、unsigned char 或 std::byte (C++17 起) 的数组的非分配布置数组 new 能用于在给定的存储区域隐式创建对象：它结束与该数组重叠的对象的生存期，然后在该数组中隐式创建隐式生存期类型的对象。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 74 | C++98 | 第一维中的值必须拥有整数类型 | 容许枚举类型
CWG 299 | C++98 | 第一维中的值必须拥有整数或枚举类型 | 容许类类型
CWG 1748 | C++98 | 要求非分配布置 new 检查实参是否为空 | 空实参导致未定义行为
CWG 1992 | C++11 | new ( std::nothrow ) int[N] 可能抛出 bad_array_new_length | 改为返回空指针
P1009R2 | C++11 | new 表达式中不能推导数组边界 | 容许推导
CWG 2382 | C++98 | 非分配布置数组 new 能要求分配开销 | 不允许这种分配开销

参阅

  • 构造函数
  • 复制消除
  • delete
  • 析构函数
  • 初始化
    • 聚合初始化
    • 默认初始化
    • 直接初始化
    • 列表初始化


noexcept 运算符 (C++11 起)

< cpp‎ | language

noexcept 运算符进行编译时检查，如果表达式不会抛出任何异常则返回 true。

它可用于函数模板的 noexcept 说明符中，以声明函数将对某些类型抛出异常，但不对其他类型抛出。

语法

noexcept( 表达式 )

返回 bool 类型的纯右值。

解释

noexcept 运算符不会对 表达式 求值。

如果 表达式 的潜在异常集合为空 (C++17 前)表达式 不会抛出 (C++17 起)，那么结果是 true，否则结果是 false。

关键词

noexcept

示例

#include <iostream>
#include <utility>
#include <vector>

void may_throw();
void no_throw() noexcept;
auto lmay_throw = []{};
auto lno_throw = []() noexcept {};

class T
{
public:
    ~T(){} // 析构函数妨碍了移动构造函数
           // 复制构造函数不会抛出异常
};

class U
{
public:
    ~U(){} // 析构函数妨碍了移动构造函数
           // 复制构造函数可能会抛出异常
    std::vector<int> v;
};

class V
{
public:
    std::vector<int> v;
};

int main()
{
    T t;
    U u;
    V v;

    std::cout << std::boolalpha
        << "may_throw() 可能会抛出异常吗？" << !noexcept(may_throw()) << '\n'
        << "no_throw() 可能会抛出异常吗？" << !noexcept(no_throw()) << '\n'
        << "lmay_throw() 可能会抛出异常吗？" << !noexcept(lmay_throw()) << '\n'
        << "lno_throw() 可能会抛出异常吗？" << !noexcept(lno_throw()) << '\n'
        << "~T() 可能会抛出异常吗？" << !noexcept(std::declval<T>().~T()) << '\n'
        // 注：以下各项测试也要求 ~T() 不会抛出异常
        // 因为 noexcept 中的表达式会构造并销毁临时量
        << "T(T 右值) 可能会抛出异常吗？" << !noexcept(T(std::declval<T>())) << '\n'
        << "T(T 左值) 可能会抛出异常吗？" << !noexcept(T(t)) << '\n'
        << "U(U 右值) 可能会抛出异常吗？" << !noexcept(U(std::declval<U>())) << '\n'
        << "U(U 左值) 可能会抛出异常吗？" << !noexcept(U(u)) << '\n'
        << "V(V 右值) 可能会抛出异常吗？" << !noexcept(V(std::declval<V>())) << '\n'
        << "V(V 左值) 可能会抛出异常吗？" << !noexcept(V(v)) << '\n';
}

输出：

may_throw() 可能会抛出异常吗？true
no_throw() 可能会抛出异常吗？false
lmay_throw() 可能会抛出异常吗？true
lno_throw() 可能会抛出异常吗？false
~T() 可能会抛出异常吗？false
T(T 右值) 可能会抛出异常吗？false
T(T 左值) 可能会抛出异常吗？false
U(U 右值) 可能会抛出异常吗？true
U(U 左值) 可能会抛出异常吗？true
V(V 右值) 可能会抛出异常吗？false
V(V 左值) 可能会抛出异常吗？true

参阅

noexcept 说明符 (C++11) | 指定函数是否抛出异常
动态异常说明 (C++17 前) | 指定函数所抛出的异常 (C++11 中弃用)


noexcept 说明符 (C++11 起)

< cpp‎ | language

指定函数是否抛出异常。

语法

noexcept | (1) |
noexcept(表达式) | (2) |
throw() | (3) | (C++17 起) (C++17 中弃用) (C++20 中移除)
1) 与 noexcept(true) 相同
2) 如果 表达式 求值为 true，那么声明函数不会抛出任何异常。
3) 与 noexcept(true) 相同（C++17 前的语义见动态异常说明）
表达式 - 按语境转换为 bool 类型的常量表达式

解释

noexcept 说明不是函数类型的一部分（正如同动态异常说明），而且只能在声明函数、变量、函数类型的非静态数据成员、函数指针、函数引用或成员函数指针时，以及在以上这些声明中声明类型为函数指针或函数引用的形参或返回类型时，作为 lambda 声明符或顶层函数声明符的一部分出现。它不能在 typedef 或类型别名声明中出现。

void f() noexcept; // 函数 f() 不会抛出
void (*fp)() noexcept(false); // fp 指向可能会抛出的函数
void g(void pfa() noexcept);  // g 接收指向不会抛出的函数的指针
// typedef int (*pf)() noexcept; // 错误
 (C++17 前)

noexcept 说明是函数类型的一部分，可以作为任何函数声明符的一部分出现。

 (C++17 起)

C++ 中的每个函数要么不会抛出，要么有可能会抛出。

  • 有可能会抛出的函数是：
  • 声明带有非空动态异常说明的函数。
 (C++17 前)
  • 声明带有求值为 false 的 表达式 的 noexcept 说明符的函数
  • 声明不带有 noexcept 声明的函数，除了
  • 析构函数，除非有任何可能在构造的基类或成员的析构函数有可能会抛出（见下文）
  • 隐式声明的或在它的首个声明被预置的默认构造函数、复制构造函数、移动构造函数，除非
  • 由构造函数的隐式定义所调用的某个基类或成员的构造函数有可能会抛出（见下文）
  • 这种初始化的某个子表达式，例如默认实参表达式，有可能会抛出（见下文）
  • （默认构造函数的）默认成员初始化器有可能会抛出（见下文）
  • 隐式声明的或在它的首个声明被预置的复制赋值运算符、移动赋值运算符，除非隐式定义中对任何赋值运算符的调用有可能会抛出（见下文）
  • 在它的首个声明被预置的比较运算符，除非它的隐式定义中对任何比较运算符的调用有可能会抛出（见下文）
 (C++20 起)
  • 解分配函数
  • 所有其他函数（以求值为 true 的 表达式 的 noexcept 说明符声明的函数，以及析构函数、预置的特殊成员函数和解分配函数）都不会抛出

显式实例化可以使用 noexcept 说明符，但不要求。如果有使用，那么它的异常说明必须与所有其他声明相同。只有在这些异常说明在同一翻译单元中不相同时才要求诊断。

只有异常说明不同的函数不能重载（与返回类型相似，异常说明是函数类型的一部分，但不是函数签名的一部分） (C++17 起)。

void f() noexcept;
void f(); // 错误：异常说明不同
void g() noexcept(false);
void g(); // OK：g 的两个声明均有可能会抛出

指向不会抛出的函数的指针（包括成员函数指针）能赋值给或用以初始化 (C++17 前)可以隐式转换到 (C++17 起)指向有可能会抛出的函数的指针，但反之不可。

void ft(); // 有可能会抛出
void (*fn)() noexcept = ft; // 错误

如果虚函数不会抛出，那么它每个覆盖的函数的所有声明（包括定义）都必须不抛出，除非覆盖函数被定义为弃置：

struct B {
    virtual void f() noexcept;
    virtual void g();
    virtual void h() noexcept = delete;
};

struct D: B {
    void f();              // 谬构：D::f 有可能会抛出，B::f 不会抛出
    void g() noexcept;     // OK
    void h() = delete;     // OK
};

不会抛出的函数允许调用有可能会抛出的函数。每当抛出异常且对处理块的查找遇到了不会抛出的函数的最外层块时，就调用函数 std::terminate 或 std::unexpected (C++17 前)：

extern void f(); // 有可能会抛出

void g() noexcept {
    f();      // 合法，即使 f 抛出
    throw 42; // 合法，等效于调用 std::terminate
}

函数模板特化的异常说明不随函数声明而实例化；它只会在需要（定义如下）时实例化。

隐式声明的特殊成员函数的异常说明也只会在需要时求值（特别是，派生类成员函数的隐式声明不要求实例化基类成员函数的异常说明）

在需要但尚未实例化某个函数模板特化的 noexcept 说明时，如同对该特化的声明一样，对待决名进行查找并实例化 表达式 中用到的任何模板。

在下列语境中认为需要函数的 noexcept 说明：

  • 在表达式中，函数被重载决议选中
  • 函数被ODR 使用
  • 函数本该被 ODR 使用但在不求值操作数中出现：
template<class T> T f() noexcept(sizeof(T) < 4);

int main() {
    decltype(f<void>()) *p; // f 不求值，但需要 noexcept 说明
                            // 错误，因为实例化 noexcept 说明的实例化要计算 sizeof(void)
}
  • 该特化需要与另一函数声明进行比较（例如在虚函数覆盖或函数模板的显式特化处）
  • 在函数定义中
  • 需要异常说明，因为某个预置特殊成员函数需要检查它以决定它自身的异常说明（这只会在这个预置特殊成员函数自身的异常说明被需要时发生）。
 (C++14 起)

有可能会抛出的表达式的正式定义（用于确定上述析构函数、构造函数和赋值运算符的默认异常说明）是：

以下情况下，表达式 e 有可能会抛出：

  • e 是对有可能会抛出的函数、函数指针或成员函数指针的调用，除非 e 是核心常量表达式 (C++17 前)
  • e 对有可能会抛出的函数进行隐式调用（例如作为重载运算符，new 表达式中的分配函数，函数实参的构造函数，或当 e 为完整表达式时的析构函数）
  • e 是 throw 表达式
  • e 是对多态引用类型进行转型的 dynamic_cast
  • e 是应用于指向多态类型的指针的解引用的 typeid 表达式
  • e 包含有可能会抛出的直接子表达式
struct A {
    A(int = (A(5), 0)) noexcept;
    A(const A&) noexcept;
    A(A&&) noexcept;
    ~A();
};

struct B {
    B() throw();
    B(const B&) = default; // 隐式异常说明是 noexcept(true)
    B(B&&, int = (throw Y(), 0)) noexcept;
    ~B() noexcept(false);
};

int n = 7;
struct D : public A, public B {
    int * p = new int[n];
    // D::D() 有可能会抛出，因为 new 运算符
    // D::D(const D&) 不会抛出
    // D::D(D&&) 有可能会抛出：因为 B 的构造函数的默认实参有可能会抛出
    // D::~D() 有可能会抛出

    // 注意：如果 A::~A() 为虚，那么此程序将为非良构，因为不会抛出的虚函数的覆盖函数不能抛出
};

注解

常量 表达式 的一种用法（与 noexcept 运算符一起）是，定义函数模板，它对一些类型声明 noexcept，但对其他类型不声明。

注意，函数上的 noexcept 说明不是一种编译时检查；它只不过是程序员告知编译器函数是否可以抛出异常的一种方法。编译器能用此信息启用不会抛出的函数上的某些优化，以及启用能在编译时检查特定表达式是否声明为可抛出任何异常的 noexcept 运算符。例如，诸如 std::vector 的容器会在元素的移动构造函数是 noexcept 的情况下移动元素，否则就复制元素（除非复制构造函数不可访问，但有可能会抛出的移动构造函数只会在放弃强异常保证的情况下考虑）。

弃用

noexcept 是 throw() 的改进版本，后者在 C++11 中弃用。与 C++17 前的 throw() 不同，noexcept 不会调用 std::unexpected，并且可能或可能不进行栈回溯，这可能允许编译器实现没有 throw() 的运行时开销的 noexcept。从 C++17 起，throw() 被重定义为严格等价于 noexcept(true)。

关键词

noexcept

示例

// foo 是否声明为 noexcept 取决于 T() 是否会抛出异常
template <class T>
    void foo() noexcept(noexcept(T())) {}

void bar() noexcept(true) {}
void baz() noexcept { throw 42; }  // noexcept 等同于 noexcept(true)

int main()
{
    foo<int>(); // noexcept(noexcept(int())) => noexcept(true)，所以这是可以的

    bar(); // 可以
    baz(); // 能编译，但会在运行时调用 std::terminate
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 2039 | C++11 | 只要求转换前的表达式是常量 | 转换必须也在常量表达式中合法

参阅

noexcept 运算符 (C++11) | 确定表达式是否会抛出任何异常
动态异常说明 (C++17 前) | 指定函数所抛出的异常 (C++11 中弃用)
throw 表达式 | 引发错误并将控制转移到错误处理块
move_if_noexcept (C++11) | 若移动构造函数不抛出则获得右值引用 (函数模板)


nullptr ，指针字面量

< cpp‎ | language

语法

nullptr (C++11 起)

解释

关键词 nullptr 代表指针字面量。它是 std::nullptr_t 类型的纯右值。存在从 nullptr 到任何指针类型及任何成员指针类型的隐式转换。同样的转换对于任何空指针常量也存在，空指针常量包括 std::nullptr_t 的值，以及宏 NULL。

示例

演示 nullptr 保持空指针常量的含义，即使它不再是字面量。

#include <cstddef>
#include <iostream>

template<class T>
constexpr T clone(const T& t)
{
    return t;
}

void g(int*)
{
    std::cout << "函数 g 已调用\n";
}

int main()
{
    g(nullptr);        // 良好
    g(NULL);           // 良好
    g(0);              // 良好

    g(clone(nullptr)); // 良好
//  g(clone(NULL));    // 错误：非字面量的零不能为空指针常量
//  g(clone(0));       // 错误：非字面量的零不能为空指针常量
}

输出：

函数 g 已调用
函数 g 已调用
函数 g 已调用
函数 g 已调用

关键词

nullptr

引用

  • C++17 标准（ISO/IEC 14882:2017）：
  • 7.11 Pointer conversions [conv.ptr]
  • C++14 标准（ISO/IEC 14882:2014）：
  • 4.10 Pointer conversions [conv.ptr]
  • C++11 标准（ISO/IEC 14882:2011）：
  • 4.10 Pointer conversions [conv.ptr]

参阅

NULL | 实现定义的空指针常量 (宏常量)
nullptr_t (C++11) | 空指针字面量 nullptr 的类型 (typedef)


对象

< cpp‎ | language

C++ 程序可以创建、销毁、引用、访问并操作对象。

在 C++ 中，一个对象拥有这些性质：

  • 大小（可以使用 sizeof 获取）；
  • 对齐要求（可以使用 alignof 获取）；
  • 存储期（自动、静态、动态、线程局部）；
  • 生存期（与存储期绑定或者临时）
  • 类型；
  • 值（可能是不确定的，例如默认初始化的非类类型）；
  • 名字（可选）。

以下实体都不是对象：值，引用，函数，枚举项，类型，类的非静态成员，模板，类或函数模板的特化，命名空间，形参包，和 this。

变量由声明所引入，是一个对象或不是对非静态数据成员的引用。

对象创建

对象能由定义、new 表达式、throw 表达式、更改联合体的活跃成员和求值要求临时对象的表达式显式创建。显式对象创建中创建的对象是唯一定义的。

隐式生存期类型的对象也可以由下列操作隐式创建：

  • 开始 char、unsigned char 或 std::byte (C++17 起)数组生存期的操作，该情况下在该数组中创建这种对象，
  • 调用下列分配函数，该情况下在分配的存储中创建这种对象：
  • operator new
  • operator new[]
  • std::malloc
  • std::calloc
  • std::realloc
  • std::aligned_alloc
 (C++17 起)
  • 调用下列对象表示复制函数，该情况下在目标存储区域或结果中创建这种对象：
  • std::memcpy
  • std::memmove
  • std::bit_cast
 (C++20 起)

只要在能给予程序有定义的行为时，同一存储区域中可创建零或多个对象。如果无法这样创建，例如操作冲突，则程序行为未定义。若多个这种隐式创建的对象的集合会给予程序有定义行为，则不指定这些集合中的哪一个被创建。换言之，不要求隐式创建的对象是唯一定义的。

在指定的存储区域内隐式创建对象后，一些操作会生成指向适合的已创建对象的指针。适合的已创建对象与存储区域拥有相同地址。类似地，当且仅当不存在能给予程序有定义行为的指针值时，行为才未定义；而若有多个给予程序有定义行为的值，则不指定产生哪个值。

#include <cstdlib>
struct X { int a, b; };
X *MakeX()
{
    // 可能的有定义行为之一：
    // 调用 std::malloc 隐式创建一个 X 类型对象及其子对象 a 与 b ，并返回指向该 X 对象的指针
    X *p = static_cast<X*>(std::malloc(sizeof(X)));
    p->a = 1;
    p->b = 2;
    return p;
}

调用 std::allocator::allocate 或联合体类型的隐式定义的复制/移动特殊成员函数亦能创建对象。

对象表示与值表示

对于一个 T 类型的对象，其对象表示 (object representation) 是和它开始于同一个地址，且长度为 sizeof(T) 的一段 unsigned char（或等价的 std::byte） (C++17 起)类型的对象序列。

对象的值表示 (value representation)则是用于持有它的类型 T 的值的位的集合。

对于可平凡复制 (TriviallyCopyable) 类型，其值表示是对象表示的一部分，这意味着复制该对象在存储中所占据的字节就足以产生另一个具有相同值的对象（除非这个值是该类型的一个“陷阱表示”，将它读取到 CPU 中会产生一个硬件异常，就像浮点值的 SNaN（“Signaling NaN 发信非数”）或整数值的 NaT（“Not a Thing 非事物”））。

反过来不一定是对的：可平凡复制 (TriviallyCopyable) 类型的两个具有不同对象表示的对象可能表现出相同的值。例如，浮点数有多种位模式都表示相同的特殊值 NaN 。更常见的是，对象表示的一些位可能根本不参与值表示；这些位可能是为了满足对齐要求，位域的大小等得以满足而填充其间的。

#include <cassert>
struct S {
    char c;  // 1 字节值
             // 3 字节填充（假设 alignof(float) == 4 ）
    float f; // 4 字节值  （假设 sizeof(float) == 4 ）
    bool operator==(const S& arg) const { // 基于值的相等
        return c == arg.c && f == arg.f;
    }
};

void f() {
    static_assert(sizeof(S) == 8);
    S s1 = {'a', 3.14};
    S s2 = s1;
    reinterpret_cast<unsigned char*>(&s1)[2] = 'b'; // 更改填充的第 2 字节
    assert(s1 == s2); // 值并未更改
}

对于 char，signed char，和 unsigned char 类型的对象，除非它们是大小过大的位域，否则其对象表示的每个位都参与其值表示，而且每一种位模式都表示一个独立的值（没有填充位或陷阱位，不允许值的多种表示）。

子对象

一个对象可以拥有子对象。子对象包括：

  • 成员对象
  • 基类子对象
  • 数组元素

不是其他任何对象的子对象的对象称为完整对象。

若一个子对象是基类子对象或声明有 [[no_unique_address]] 属性的非静态数据成员 (C++20 起)，则它潜在重叠。

完整对象、成员对象和数组元素也被称为最终派生对象 ，以便和基类子对象区分开。既非潜在重叠亦非位域的对象的大小不能为零（基类子对象的大小可能为零，即使无 [[no_unique_address]] 也是如此 (C++20 起)：参见空基类优化）。

一个对象能含有其他对象，该情况下被含有的对象内嵌于前述对象。若符合下列条件，则对象 a 内嵌于另一对象 b ：

  • a 是 b 的子对象，或
  • b 为 a 提供存储，或
  • 存在对象 c ，其中 a 内嵌于 c 而 c 内嵌于 b 。

任何两个具有交叠的生存期的（非位域）对象必然有不同的地址，除非其中一个对象内嵌于另一个对象，或者两个对象都是同一个完整对象中的不同类型的子对象，且其中一个是大小为零的子对象。

static const char c1 = 'x';
static const char c2 = 'x';
assert(&c1 != &c2); // 值相同，地址不同

多态对象

声明或继承了至少一个虚函数的类类型的对象是多态对象。每个多态对象中，实现都会储存额外的信息（在所有现存的实现中，如果没被编译器优化掉的话，这就是一个指针），它被用于进行虚函数的调用，RTTI 功能特性（dynamic_cast 和 typeid）也用它在运行时确定对象创建时所用的类型，而不管使用它的表达式是什么类型。

对于非多态对象，值的解释方式由使用对象的表达式所确定，这在编译期就已经决定了。

#include <iostream>
#include <typeinfo>
struct Base1 {
    // 多态类型：声明了虚成员
    virtual ~Base1() {}
};
struct Derived1 : Base1 {
    // 多态类型：继承了虚成员
};

struct Base2 {
    // 非多态类型
};
struct Derived2 : Base2 {
    // 非多态类型
};

int main()
{
    Derived1 obj1; // object1 创建为类型 Derived1
    Derived2 obj2; // object2 创建为类型 Derived2

    Base1& b1 = obj1; // b1 指代对象 obj1
    Base2& b2 = obj2; // b2 指代对象 obj2

    std::cout << "b1 的表达式类型: " << typeid(decltype(b1)).name() << '\n'
              << "b2 的表达式类型: " << typeid(decltype(b2)).name() << '\n'
              << "b1 的对象类型: " << typeid(b1).name() << '\n'
              << "b2 的对象类型: " << typeid(b2).name() << '\n'
              << "b1 的大小: " << sizeof b1 << '\n'
              << "b2 的大小: " << sizeof b2 << '\n';
}

可能的输出：

b1 的表达式类型: Base1
b2 的表达式类型: Base2
b1 的对象类型: Derived1
b2 的对象类型: Base2
b1 的大小: 8
b2 的大小: 1

严格的别名使用

在很多情况下，通过类型与对象的创建类型不同的表达式来访问对象都是未定义行为，其例子和例外请参考 reinterpret_cast。

对齐

每个对象类型都具有被称为对齐要求（alignment requirement）的性质，它是一个整数（类型为 std::size_t，总是 2 的幂），表示这个类型的不同对象所能分配放置的连续相邻地址之间的字节数。

可以用 alignof 或 std::alignment_of 来查询类型的对齐要求。可以使用指针对齐函数 std::align 来获取某个缓冲区中经过适当对齐的指针，还可以使用 std::aligned_storage 来获取经过适当对齐的存储区。

 (C++11 起)

每个对象类型在该类型的所有对象上强制该类型的对齐要求；可以使用 alignas 来要求更严格的对齐（更大的对齐要求） (C++11 起)。

为了使类中的所有非静态成员都符合对齐要求，会在一些成员后面插入一些填充。

#include <iostream>

// S 类型的对象可以在任何地址上分配
// 因为 S.a 和 S.b 都可以在任何地址上分配
struct S {
  char a; // 大小：1，对齐：1
  char b; // 大小：1，对齐：1
}; // 大小：2，对齐：1

// X 类型的对象只能在 4 字节边界上分配
// 因为 X.n 必须在 4 字节边界上分配
// 因为 int 的对齐要求（通常）就是 4
struct X {
  int n;  // 大小：4，对齐：4
  char c; // 大小：1，对齐：1
  // 三个填充字节
}; // 大小：8，对齐：4

int main()
{
    std::cout << "sizeof(S) = " << sizeof(S)
              << " alignof(S) = " << alignof(S) << '\n';
    std::cout << "sizeof(X) = " << sizeof(X)
              << " alignof(X) = " << alignof(X) << '\n';
}

可能的输出：

sizeof(S) = 2 alignof(S) = 1
sizeof(X) = 8 alignof(X) = 4

最弱的对齐（最小的对齐要求）是 char、signed char 和 unsigned char 的对齐，等于 1 ；所有类型中最大的基础对齐（fundamental alignment）是实现定义的，并等于 std::max_align_t 的对齐。 (C++11 起)

当使用 alignas 使某个类型的对齐比 std::max_align_t 的更严格（更大）时，称其为具有扩展对齐（extended alignment）要求的类型。具有扩展对齐的类型或包含具有扩展对齐的非静态成员的类类型称为过对齐（over-aligned）类型。 new 表达式、 (C++17 前)std::allocator::allocate 和 std::get_temporary_buffer (C++20 前) 是否支持过对齐类型是由实现定义的。以过对齐类型实例化的分配器 (Allocator) 允许在编译期发生实例化失败，在运行时抛出 std::bad_alloc 异常，静默忽略不支持的对齐要求，也允许正确地处理它们。

 (C++11 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0593R6 | C++98 | 先前的对象模型不支持标准库所要求的许多有用的手法且与 C 中的有效类型不兼容 | 添加了隐式对象创建

参考


代用运算符表示

< cpp‎ | language

C++（及 C）源代码可以用任何包含 ISO 646:1983 不变字符集的非 ASCII 7 位字符集书写。然而，一些 C++ 运算符及标点要求 ISO 646 编码集外的字符：{, }、[, ]、#、\、^、|、~。为了能够使用不存在一些或全部这些符号的字符编码（例如德语 DIN 66003），C++ 定义下列由 ISO 646 兼容字符组成的代用写法。

代用记号

几个使用非 ISO-646 字符的运算符和其他记号都有代用拼写。在语言的所有方面，各个代用拼写都严格与其首选记号的表现相同，除了其拼写（字符串化运算符能使拼写可见）。双字母代用记号有时被称为“双标符 (digraphs)”。

首选 | 代用
&& | and
&= | and_eq
& | bitand
| | bitor
~ | compl
! | not
!= | not_eq
|| | or
|= | or_eq
^ | xor
^= | xor_eq
{ | <%
} | %>
[ | <:
] | :>
# | %:
## | %:%:

当分析器遇到字符序列 <::，且后继字符既非 : 亦非 > 时，< 被当做预处理记号本身，而非代用记号 <:。从而 std::vector <:: std::string > 不会被错误地处理成 std::vector [: std::string >。

 (C++11 起)

注解

字符 & 及 ! 在 ISO-646 下不变，但仍然为使用这些字符的记号提供了代用写法，以便能够适应更加受限的历史字符集。

没有相等运算符的代用拼写 == 如 eq），因为字符 = 已在所有受支持字符集中存在。

与 C 的兼容性

C 编程语言中，同样的单词作为宏定义于包含文件 <iso646.h> 之中。因为 C++ 中它们内建于语言，故 <iso646.h> 的 C++ 版本还有 <ciso646> 不定义任何内容。

三标符 (C++17 中移除)

下列三字符组（三标符，trigraph）在辨识注释和字符串字面量之前被分析，而三标符的每次出现被替换为对应的首选字符：

首选 | 三标符
{ | ??<
} | ??>
[ | ??(
] | ??)
# | ??=
\ | ??/
^ | ??'
| | ??!
~ | ??-

因为三标符的处理非常早，所以如 // Will the next line be executed?????/ 这样的注释实际上会注释掉下一行，而如 "Enter date ??/??/??" 这样的字符串字面量将被分析为 "Enter date \\??"。

关键词

and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, xor_eq

示例

下列示例演示各种代用记号的使用。

%:include <iostream>

struct X
<%
    compl X() <%%> // 析构函数
    X() <%%>
    X(const X bitand) = delete; // 复制构造函数

    bool operator not_eq(const X bitand other)
    <%
       return this not_eq bitand other;
    %>
%>;

int main(int argc, char* argv<::>)
<%
    // 带引用捕获的 lambda
    auto greet = <:bitand:>(const char* name)
    <%
        std::cout << "Hello " << name
                  << " from " << argv<:0:> << '\n';
    %>;

    if (argc > 1 and argv<:1:> not_eq nullptr) <%
        greet(argv<:1:>);
    %>
%>

参阅


算术运算符

< cpp‎ | language

返回特定算术运算的结果。

运算符名 | 语法 | 可重载 | 原型示例（对于 class T）
类内定义 | 类外定义
一元加 | +a | 是 | T T::operator+() const; | T operator+(const T &a);
一元减 | -a | 是 | T T::operator-() const; | T operator-(const T &a);
加法 | a + b | 是 | T T::operator+(const T2 &b) const; | T operator+(const T &a, const T2 &b);
减法 | a - b | 是 | T T::operator-(const T2 &b) const; | T operator-(const T &a, const T2 &b);
乘法 | a * b | 是 | T T::operator*(const T2 &b) const; | T operator*(const T &a, const T2 &b);
除法 | a / b | 是 | T T::operator/(const T2 &b) const; | T operator/(const T &a, const T2 &b);
模 | a % b | 是 | T T::operator%(const T2 &b) const; | T operator%(const T &a, const T2 &b);
逐位非 | ~a | 是 | T T::operator~() const; | T operator~(const T &a);
逐位与 | a & b | 是 | T T::operator&(const T2 &b) const; | T operator&(const T &a, const T2 &b);
逐位或 | a | b | 是 | T T::operator|(const T2 &b) const; | T operator|(const T &a, const T2 &b);
逐位异或 | a ^ b | 是 | T T::operator^(const T2 &b) const; | T operator^(const T &a, const T2 &b);
逐位左移 | a << b | 是 | T T::operator<<(const T2 &b) const; | T operator<<(const T &a, const T2 &b);
逐位右移 | a >> b | 是 | T T::operator>>(const T2 &b) const; | T operator>>(const T &a, const T2 &b);
注解
  • 所有内建运算符都返回值，而大多数用户定义重载亦返回值，从而能以与内建版本相同的方式使用用户定义运算符。不过，用户定义重载中，任何类型都可以作为返回类型（包括 void）。特别是，operator<< 和 operator>> 为流插入和流抽取的重载所返回的是 T&。
  • T2 可以为包括 T 在内的任何类型。

解释

所有算术运算符计算特定算术运算的结果，并返回其结果。不修改实参。

转换

若传递给算术运算符的操作数是整型或无作用域枚举类型，则在任何其他行动前（但在左值到右值转换后，若其适用），对操作数实施整型提升。若操作数之一具有数组或函数类型，则实施数组到指针和函数到指针转换。

对于（除移位之外的）二元运算符，当提升后的操作数拥有不同类型时，实施称为一般算术转换 (usual arithmetic conversion)的一组额外的隐式转换，目的是产生公共类型 (common type)（亦可由 std::common_type 类型特性访问）。若在任何整型提升前，一个操作数为枚举类型而另一操作数为浮点类型或不同的枚举类型，则此行为被弃用。 (C++20 起)

  • 若任一操作数具有有作用域枚举类型，则不进行转换：另一操作数和返回类型必须具有相同类型
  • 否则，若任一操作数为 long double，则将另一操作数转换为 long double
  • 否则，若任一操作数为 double，则将另一操作数转换为 double
  • 否则，若任一操作数为 float，则将另一操作数转换为 float
  • 否则，操作数拥有整数类型（因为 bool、char、char8_t、char16_t、char32_t、wchar_t 和无作用域枚举在此时已被提升），并对其实施整型转换以产生如下的公共类型：
  • 若两个操作数均为有符号或均为无符号，则将拥有较小转换等级的操作数转换为拥有较大整数转换等级的操作数的类型。
  • 否则，若无符号操作数的转换等级大于或等于有符号操作数的转换等级，则将有符号操作数转换为无符号操作数的类型。
  • 否则，若有符号操作数的类型能表示无符号操作数类型的所有值，则将无符号操作数转换为有符号操作数的类型。
  • 否则，将两个操作数都转换为有符号操作数的无符号对应版本。

转换等级（conversion rank）按 bool、signed char、short、int、long、long long 顺序递增。任何无符号类型的等级都等于其对应的有符号类型的等级。char 的等级等于 signed char 和 unsigned char 的等级。char8_t、char16_t、char32_t 和 wchar_t 的等级等于其底层类型的等级。

溢出

无符号整数算术始终进行 modulo 2n
，其中 n 是该整数的位数。例如对于 unsigned int，向 UINT_MAX 加一得到 ​0​，而从 ​0​ 减一得到 UINT_MAX。

有符号整数算术运算溢出（结果类型无法容纳其结果）时，行为未定义，此类操作可能会表现为：

  • 按照表示法的规则（典型为补码）发生回绕，
  • 在某些平台上或由于编译器选项（例如 GCC 和 Clang 中的 -ftrapv）引发陷阱，
  • 在某些时候截断到最小或最大值（在许多 DSP 上）
  • 完全被编译器优化掉。

浮点环境

若支持 #pragma STDC FENV_ACCESS 并设置它为 ON，则所有浮点算术运算符都服从当前浮点舍入方向，并报告 math_errhandling 中指定的浮点算术错误，除非是发生于静态初始化器之中（该情况下不引发浮点异常，且舍入模式为最近舍入）。

浮点缩略

除非支持 #pragma STDC FP_CONTRACT 并设置它为 OFF，否则所有浮点算术都可以如同其中间结果拥有无限范围和精度一般进行，即允许实施省略舍入误差和浮点异常的优化。例如 C++ 允许以单条融合乘加 CPU 指令来实现 (x*y) + z，或把 a = x*x*x*x; 优化为 tmp = x *x; a = tmp*tmp。

无关乎缩略，浮点算术的中间结果可拥有与其类型所指定不同的范围和精度，见 FLT_EVAL_METHOD。

正式来讲，C++ 标准不在浮点运算的精度上做任何保证。

一元算术运算符

一元算术运算符表达式的形式为

+ 表达式 | (1)
- 表达式 | (2)
1) 一元加（提升）。
对于内建运算符，表达式 必须拥有算术、无作用域枚举或指针类型。若操作数具有整型或无作用域枚举类型，则对其实施整型提升，并确定结果类型。
2) 一元减（取反）。
对于内建运算符，表达式 必须拥有算术或无作用域枚举类型。对操作数实施整型提升，并确定结果类型。

内建的一元加运算符返回其操作数的值。仅有的非无操作情形，是当操作数拥有整型类型或无作用域枚举类型时，它将被整型提升所更改，例如将 char 转换为 int，或者当操作数服从左值到右值、数组到指针或函数到指针转换时。

内建的一元减运算符计算其提升后操作数的相反数。对于无符号的 a，-a 的值为 2b
-a，其中 b 为提升后的位数。

在针对用户定义运算符的重载决议中，对于每个 cv 无限定的提升后算术类型 A 和每个类型 T，下列函数签名参与重载决议：

A operator+(A)
T* operator+(T*)
A operator-(A)

#include <iostream>
int main()
{
    char c = 0x6a;
    int n1 = 1;
    unsigned char n2 = 1;
    unsigned int n3 = 1;
    std::cout << "char：" << c << " int：" << +c << '\n'
              << "-1，当 1 的类型是 signed 时：" << -n1 << '\n'
              << "-1，当 1 的类型是 unsigned char 时：" << -n2 << '\n'
              << "-1，当 1 的类型是 unsigned int 时：" << -n3 << '\n';
    char a[3];
    std::cout << "数组大小：" << sizeof a << '\n'
              << "指针大小：" << sizeof +a << '\n';
}

输出：

char：j int：106
-1，当 1 的类型是 signed 时：-1
-1，当 1 的类型是 unsigned char 时：-1
-1，当 1 的类型是 unsigned int 时：4294967295
数组大小：3
指针大小：8

加性运算符

二元加性算术运算符表达式的形式为

左操作数 + 右操作数 | (1)
左操作数 - 右操作数 | (2)
1) 加法
对于内建运算符，左操作数 和 右操作数 必须为下列之一：
  • 都拥有算术或无作用域枚举类型。这种情况下，对两个操作数都实施一般算术转换，并确定结果类型。
  • 一个是指向完整定义的对象的指针类型，另一个拥有整型或无作用域枚举类型。此情况下，结果具有指针的类型。
2) 减法
对于内建运算符，左操作数 和 右操作数 必须为下列之一：
  • 都拥有算术或无作用域枚举类型。这种情况下，对两个操作数都实施一般算术转换，并确定结果类型。
  • 左操作数 为指向完整定义的对象类型的指针，右操作数 拥有整型或无作用域枚举类型。此情况下，结果具有指针的类型。
  • 忽略 cv 限定符时，两者都是指向相同完整定义的对象类型的指针。此情况下，结果类型为 std::ptrdiff_t。

对于算术或枚举类型的操作数，二元加的结果是操作数（经一般算术转换后）的和，而二元减运算符的结果是第一操作数减去第二操作数（经一般算术转换后）的结果，但是，如果该类型支持 IEEE 浮点算术（见 std::numeric_limits::is_iec559），

  • 若操作数之一为 NaN，则结果为 NaN
  • 无穷减无穷为 NaN，并引发 FE_INVALID
  • 无穷加负无穷为 NaN，并引发 FE_INVALID

若任何操作数为指针，则适用下列规则：

  • 把指向非数组对象的指针当做指向大小为 1 的数组的首元素的指针。
  • 若指针 P 指向数组的第 i 个元素，则表达式 P+n、n+P 和 P-n 分别是指向同一数组的第 i+n、第 i+n 和第 i-n 个元素的同类型指针。指针加法的结果亦可为末尾后一位置（one past the end）的指针（即使得 P-1 指向数组末元素的指针 P）。任何其他情形（即试图生成不指向同一数组的任何元素或同一数组末尾后一位置的指针）均引起未定义行为。
  • 若指针 P 指向数组的第 i 个元素，而指针 Q 指向同一数组的第 j 个元素，则表达式 P-Q 拥有值 i-j（若 std::ptrdiff_t 可容纳该值）。两个操作数都必须指向同一数组的元素（或末尾后一位置），否则行为未定义。若结果不能由 std::ptrdiff_t 容纳，则行为未定义。
  • 任何情况下，如果所指向的类型与数组元素类型不同（其中对于每一层元素，若它们自身即为指针，则不考虑其 cv 限定性），则指针算术的行为未定义。特别是，以指向某个派生对象数组中的元素的指向基类指针做指针算术是未定义的。
  • 对指针加或减 ​0​，结果就是该指针，没有更改。若两个指针指向同一对象，或都指向同一数组的末尾后一位置，或都是空指针，则减法的结果等于 ( std::ptrdiff_t )0。

这些指针算术运算符使得指针满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。

在针对用户定义运算符的重载决议中，对于每对提升后的算术类型 L 和 R 和每个对象类型 T，下列函数签名参与重载决议：

LR operator+(L, R)
LR operator-(L, R)
T* operator+(T*, std::ptrdiff_t )
T* operator+( std::ptrdiff_t, T*)
T* operator-(T*, std::ptrdiff_t )
std::ptrdiff_t operator-(T*, T*)

其中 LR 是对 L 和 R 实施一般算术转换的结果。

#include <iostream>
int main()
{
    char c = 2;
    unsigned int un = 2;
    int  n = -10;
    std::cout <<  " 2 + (-10)，当 2 的类型是 char 时     = " << c + n << '\n'
              <<  " 2 + (-10)，当 2 的类型是 unsigned 时 = " << un + n << '\n'
              <<  " -10 - 2.12  = " << n - 2.12 << '\n';

    char a[4] = {'a', 'b', 'c', 'd'};
    char* p = &a[1];
    std::cout << "指针相加的例子：" << *p << *(p + 2)
              << *(2 + p) << *(p - 1) << '\n';
    char* p2 = &a[4];
    std::cout << "指针的差：" << p2 - p << '\n';
}

输出：

 2 + (-10)，当 2 的类型是 char 时     = -8
 2 + (-10)，当 2 的类型是 unsigned 时 = 4294967288
 -10 - 2.12  = -12.12
指针相加的例子：bdda
指针的差：3

乘性运算符

二元乘性运算符表达式的形式为

左操作数 * 右操作数 | (1)
左操作数 / 右操作数 | (2)
左操作数 % 右操作数 | (3)
1) 乘法
对于内建运算符，左操作数 和 右操作数 必须都具有算术或无作用域枚举类型。
2) 除法
对于内建运算符，左操作数 和 右操作数 必须都具有算术或无作用域枚举类型。
3) 求余
对于内建运算符，左操作数 和 右操作数 必须都具有算术或无作用域枚举类型。

这三个运算符均对两个操作数实施一般算术转换，并确定结果类型。

二元运算符 * 进行其操作数（经一般算术转换后）的乘法，但对于浮点乘法，

  • NaN 乘以任何数均得 NaN
  • 无穷乘以零得 NaN 并引发 FE_INVALID

二元运算符 / 将第一操作数除以第二操作数（经一般算术转换后）。

对于整型操作数，它产生代数商，

以实现定义的方向对商进行舍入。 | (C++11 前)
商向零取整（舍弃小数部分）。 | (C++11 起)

若第二操作数为零，则行为未定义，但若进行浮点除法且类型支持 IEEE 浮点算术（见 std::numeric_limits::is_iec559），则：

  • 若操作数之一为 NaN，则结果为 NaN
  • 非零数除以 ±0.0 得到符号正确的无穷，并引发 FE_DIVBYZERO
  • 0.0 除以 0.0 得 NaN，并引发 FE_INVALID

二元运算符 % 产生以第二操作数整除第一操作数的余数（经一般算术转换后；注意各操作数的类型必须都为整型类型）。若商 a/b 能以结果类型表示，则 (a/b)*b + a%b == a。若第二操作数为零，则行为未定义。若商 a/b 不能以结果类型表示，则 a/b 和 a%b 的行为均未定义（这意味着，补码系统上 INT_MIN%-1 为未定义）。

注意：C++11 之前，若二元运算符 % 的一或两个操作数为负，则余数符号是实现定义的，因为它取决于整数除法的舍入方向。函数 std::div 在该情况下提供良好定义的行为。

注意：对于浮点余数，见 std::remainder 和 std::fmod。

在针对用户定义运算符的重载决议中，对于每对提升后的算术类型 LA 与 RA 及每对提升后的整型类型 LI 与 RI，下列函数签名参与重载决议：

LRA operator*(LA, RA)
LRA operator/(LA, RA)
LRI operator%(LI, RI)

其中 LRx 是对 Lx 和 Rx 实施一般算术转换的结果。

#include <iostream>
int main()
{
    char c = 2;
    unsigned int un = 2;
    int  n = -10;
    std::cout <<  "2 * (-10)，当 2 的类型是 char 时     = " << c * n << '\n'
              <<  "2 * (-10)，当 2 的类型是 unsigned 时 = " << un * n << '\n'
              <<  "-10 / 2.12  = " << n / 2.12 << '\n'
              <<  "-10 / 21  = " << n / 21 << '\n'
              <<  "-10 % 21  = " << n % 21 << '\n';
}

输出：

2 * (-10)，当 2 的类型是 char 时     = -20
2 * (-10)，当 2 的类型是 unsigned 时 = 4294967276
-10 / 2.12  = -4.71698
-10 / 21  = 0
-10 % 21  = -10

逐位逻辑运算符

逐位算术运算符表达式的形式为

~ 右操作数 | (1)
左操作数 & 右操作数 | (2)
左操作数 | 右操作数 | (3)
左操作数 ^ 右操作数 | (4)
1) 逐位非（NOT）
2) 逐位与（AND）
3) 逐位或（OR）
4) 逐位异或（XOR）
对于内建运算符，左操作数 和 右操作数 必须都拥有整型或无作用域枚举类型。对两个操作数实施一般算术转换，并确定结果类型。

operator~ 的结果是实参值（提升后）的逐位非（反码）。operator& 的结果是两个操作数值（经一般算术转换后）的逐位与。operator| 的结果是两个操作数值（经一般算术转换后）的逐位或。operator^ 的结果是两个操作数值（经一般算术转换后）的逐位异或。

在针对用户定义运算符的重载决议中，对于每对提升后的整型类型 L 和 R，下列函数签名参与重载决议：

R operator~(R)
LR operator&(L, R)
LR operator^(L, R)
LR operator|(L, R)

其中 LR 是对 L 和 R 实施一般算术转换的结果。

#include <iostream>
#include <iomanip>
#include <bitset>
int main()
{
    uint16_t mask = 0x00f0;
    uint32_t x0 = 0x12345678;
    uint32_t x1 = x0 | mask;
    uint32_t x2 = x0 & ~mask;
    uint32_t x3 = x0 & mask;
    uint32_t x4 = x0 ^ mask;
    uint32_t x5 = ~x0;
    using bin16 = std::bitset<16>;
    using bin32 = std::bitset<32>;
    std::cout << std::hex << std::showbase
              << "\u3000\u3000掩码： " << mask << std::setw(39) << bin16(mask) << '\n'
              << "\u3000\u3000\u3000值： " << x0 << std::setw(33) << bin32(x0) << '\n'
              << "设置各位： " << x1 << std::setw(33) << bin32(x1) << '\n'
              << "清除各位： " << x2 << std::setw(33) << bin32(x2) << '\n'
              << "选择各位： " << x3 << std::setw(39) << bin32(x3) << '\n'
              << "异或各位： " << x4 << std::setw(33) << bin32(x4) << '\n'
              << "取反各位： " << x5 << std::setw(33) << bin32(x5) << '\n';
}

输出：

Mask: 0xf0                                 0000000011110000
Value: 0x12345678          00010010001101000101011001111000
Setting bits: 0x123456f8   00010010001101000101011011111000
Clearing bits: 0x12345608  00010010001101000101011000001000
Selecting bits: 0x70       00000000000000000000000001110000
XOR-ing bits: 0x12345688   00010010001101000101011010001000
Inverting bits: 0xedcba987 11101101110010111010100110000111

移位运算符

移位运算符表达式的形式为

左操作数 << 右操作数 | (1)
左操作数 >> 右操作数 | (2)
1) 将 左操作数 左移 右操作数 位
2) 将 左操作数 右移 右操作数 位
对于内建运算符，左操作数 和 右操作数 必须都具有整型或无作用域枚举类型。对两个运算数实施整型提升。

返回类型是提升后的左操作数的类型。

对于无符号 a，a << b 的值是 a * 2b 对 2N 取模，其中 N 是返回类型中的位数（即进行逐位左移并舍弃移出目标类型的位）。 对于有符号的非负 a，若 a * 2b 能以返回类型的无符号版本表示，则将该值转换到有符号后即是 a << b 的值（这使得以 1<<31 创建 INT_MIN 合法）；否则行为未定义。 对于负 a，a << b 的行为未定义。 对于无符号 a 和有符号的非负 a，a >> b 的值是 a/2b 的整数部分。 对于负 a，a >> b 的值是实现定义的（大多数平台上进行算术右移，故结果保留为负）。 | (C++20 前)
a << b 的值是与 a * 2b 对 2N 同余的唯一值，其中 N 是返回类型中的位数（即进行逐位左移并舍弃移出目标类型的位）。 a >> b 的值是 a/2b 向下取整（换言之，有符号 a 上的右移是算术右移）。 | (C++20 起)

任何情况下，若右操作数的值为负或大于等于提升后左操作数中的位数，则行为未定义。

在针对用户定义运算符的重载决议中，对于每对提升后的整型类型 L 和 R，下列函数签名参与重载决议：

L operator<<(L, R)
L operator>>(L, R)

#include <iostream>
enum {ONE=1, TWO=2};
int main()
{
    std::cout << std::hex << std::showbase;
    char c = 0x10;
    unsigned long long ull = 0x123;
    std::cout << "0x123 << 1 = " << (ull << 1) << '\n'
              << "0x123 << 63 = " << (ull << 63) << '\n' // 无符号中的溢出
              << "0x10 << 10 = " << (c << 10) << '\n';   // 提升 char 到 int
    long long ll = -1000;
    std::cout << std::dec << "-1000 >> 1 = " << (ll >> ONE) << '\n';
}

输出：

0x123 << 1 = 0x246
0x123 << 63 = 0x8000000000000000
0x10 << 10 = 0x4000
-1000 >> 1 = -500

标准库

许多标准库类型都重载了算术运算符。

一元算术运算符

operator+operator- | 实现一元 + 和一元 - (std::chrono::duration<Rep,Period> 的公开成员函数)
operator+operator- | 对复数运用一元运算符 (函数模板)
operator+operator-operator~operator! | 对 valarray 的每个元素运用一元算术运算符 (std::valarray<T> 的公开成员函数)

加性运算符

operator+operator- (C++11) | 实施涉及时间点的加法和减法运算 (函数模板)
operator+operator-operator*operator/operator% (C++11) | 实现以时长为实参的算术运算 (函数模板)
operator+operator- (C++20) | 将 year_month_day 与一定量的年数或月数相加或相减 (函数)
operator+ | 连接两个字符串或者一个字符串和一个字符 (函数模板)
operator+operator- | 推进或减小迭代器 (std::reverse_iterator<Iter> 的公开成员函数)
operator+operator- | 推进或减小迭代器 (std::move_iterator<Iter> 的公开成员函数)
operator+operator-operator*operator/ | 在两个复数，或一个复数与一个标量上进行复数算术运算 (函数模板)
operator+operator-operator*operator/operator%operator&operator|operator^operator<<operator>>operator&&operator|| | 对两个 valarray 的每个元素，或一个 valarray 的每个元素和一个值运用二元运算符 (函数模板)

乘性运算符

operator+operator-operator*operator/operator% (C++11) | 实现以时长为实参的算术运算 (函数模板)
operator+operator-operator*operator/ | 在两个复数，或一个复数与一个标量上进行复数算术运算 (函数模板)
operator+operator-operator*operator/operator%operator&operator|operator^operator<<operator>>operator&&operator|| | 对两个 valarray 的每个元素，或一个 valarray 的每个元素和一个值运用二元运算符 (函数模板)

逐位逻辑运算符

operator&=operator|=operator^=operator~ | 进行二进制与、或、异或及非 (std::bitset<N> 的公开成员函数)
operator&operator|operator^ | 在 bitset 上执行二元逻辑操作 (函数)
operator~ | 对 valarray 的每个元素运用一元算术运算符 (std::valarray<T> 的公开成员函数)
operator^operator&operator| | 对两个 valarray 的每个元素，或一个 valarray 的每个元素和一个值运用二元运算符 (函数模板)

移位运算符

operator<<operator>> | 对两个 valarray 的每个元素，或一个 valarray 的每个元素和一个值运用二元运算符 (函数模板)
operator<<operator>> | 进行二进制左移和右移 (std::bitset<N> 的公开成员函数)

流插入/抽取运算符

整个标准库中，移位运算符常对 I/O 流（ std::ios_base & 或从它派生的类之一）重载，以之为左运算数和返回类型。这种运算符被称为流插入和流抽取运算符：

operator>> | 提取带格式数据 (std::basic_istream<CharT,Traits> 的公开成员函数)
operator>>(std::basic_istream) | 提取字符和字符数组 (函数模板)
operator<< | 插入带格式数据 (std::basic_ostream<CharT,Traits> 的公开成员函数)
operator<<(std::basic_ostream) | 插入字符数据 (函数)
operator<<operator>> | 复数的序列化和反序列化 (函数模板)
operator<<operator>> | 执行 bitset 的流输入和输出 (函数)
operator<<operator>> | 执行字符串的流输入与输出 (函数模板)
operator<<operator>> (C++11) | 执行伪随机数引擎的流输入和输出 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1457 | C++98 | 将正的有符号值的最左端的 1 位移入符号位为未定义行为 | 使之为良定义

参阅

运算符优先级

运算符重载

常见运算符
赋值 自增
自减 		算术 逻辑 比较 成员访问 其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
? :
特殊运算符

static_cast 转换一个类型为另一相关类型
dynamic_cast 在继承层级中转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 转换类型到无关类型
C 风格转型 以 static_cast 、 const_cast 及 reinterpret_cast 的混合转换一个类型到另一类型
new 创建有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象，并释放其所拥有的内存区域
sizeof 查询类型的大小
sizeof... 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 查询表达式是否能抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)


赋值运算符

< cpp‎ | language

赋值运算符修改对象的值。

运算符名 | 语法 | 可重载 | 原型示例（对于 class T）
类内定义 | 类外定义
简单赋值 | a = b | 是 | T& T::operator =(const T2& b); | N/A
加法赋值 | a += b | 是 | T& T::operator +=(const T2& b); | T& operator +=(T& a, const T2& b);
减法赋值 | a -= b | 是 | T& T::operator -=(const T2& b); | T& operator -=(T& a, const T2& b);
乘法赋值 | a *= b | 是 | T& T::operator *=(const T2& b); | T& operator *=(T& a, const T2& b);
除法赋值 | a /= b | 是 | T& T::operator /=(const T2& b); | T& operator /=(T& a, const T2& b);
取模赋值 | a %= b | 是 | T& T::operator %=(const T2& b); | T& operator %=(T& a, const T2& b);
逐位与赋值 | a &= b | 是 | T& T::operator &=(const T2& b); | T& operator &=(T& a, const T2& b);
逐位或赋值 | a |= b | 是 | T& T::operator |=(const T2& b); | T& operator |=(T& a, const T2& b);
逐位异或赋值 | a ^= b | 是 | T& T::operator ^=(const T2& b); | T& operator ^=(T& a, const T2& b);
逐位左移赋值 | a <<= b | 是 | T& T::operator <<=(const T2& b); | T& operator <<=(T& a, const T2& b);
逐位右移赋值 | a >>= b | 是 | T& T::operator >>=(const T2& b); | T& operator >>=(T& a, const T2& b);
注意
  • 所有内建赋值运算符都返回 *this，而大多数用户定义重载亦返回 *this，从而能以与内建版本相同的方式使用用户定义运算符。然而，用户定义运算符重载中，能以任何类型为返回类型（包括 void）。
  • T2 可为包含 T 在内的任何类型

解释

复制赋值运算符以 b 内容的副本替换对象 a 的内容（不修改 b）。对于类类型，这是一种特殊成员函数，描述于复制赋值运算符。

移动赋值运算符以 b 的内容替换对象 a 的内容，并尽可能避免复制（可以修改 b）。对于类类型，这是一种特殊成员函数，描述于移动赋值运算符。 (C++11 起)

 (C++11 起)

对于非类类型，对复制与移动赋值不加以区分，均被称作直接赋值（direct assignment）。

复合赋值（compound assignment）运算符以 a 的值和 b 的值间的二元运算结果替换对象 a 的内容。

内建的直接赋值

直接赋值表达式的形式为

左操作数 = 右操作数 | (1) |
左操作数 = {} | (2) | (C++11 起)
左操作数 = { 右操作数 } | (3) | (C++11 起)

对于内建运算符，左操作数 可拥有任何非 const 标量类型，而 右操作数 必须可隐式转换为 左操作数 的类型。

直接赋值运算符期待以一个可修改左值为其左操作数，以一个右值表达式或花括号初始化器列表 (C++11 起)为其右操作数，并返回一个标识修改后的左操作数的左值。

对于非类类型，首先将右操作数隐式转换为左操作数的无 cv 限定的类型，然后复制其值到左操作数所标识的对象中。

当左操作数拥有引用类型时，赋值运算符修改被引用的对象。

若左右操作数标识的对象之间有重叠，则行为未定义（除非二者严格重叠且类型相同）。

当右运算数为花括号初始化器列表 (brace-init-list)时

  • 若表达式 E1 拥有标量类型，则
  • 表达式 E1 = {} 等价于 E1 = T{}，其中 T 是 E1 的类型。
  • 表达式 E1 = {E2} 等价于 E1 = T{E2}，其中 T 是 E1 的类型。
  • 若表达式 E1 拥有类类型，则语法 E1 = {args...} 生成以花括号初始化器列表为实参对赋值运算符的一次调用，然后遵循重载决议规则选取适合的赋值运算符。需要注意的是，若以某个非类类型为实参的非模板赋值运算符可用，则它胜过 E1 = {} 中的复制/移动赋值，这是因为从 {} 到非类类型属于恒等转换，它优先于从 {} 到类类型的用户定义转换。
 (C++11 起)

以 volatile 限定的非类类型左值为内建直接赋值运算符的左操作数被弃用，除非该赋值表达式出现于不求值语境或是弃值表达式。

 (C++20 起)

针对用户定义运算符的重载决议中，对于每个类型 T，下列函数签名参与重载决议：

T*& operator=(T*&, T*);
T*volatile & operator=(T*volatile &, T*);

对于每个枚举或成员指针类型 T（可选地有 volatile 限定），下列函数签名参与重载决议：

T& operator=(T&, T );

对于每对 A1 和 A2，其中 A1 是算术类型（可选地有 volatile 限定）而 A2 是提升后的算术类型，下列函数签名参与重载决议：

A1& operator=(A1&, A2);

示例

#include <iostream>
int main()
{
    int n = 0;  // 不是赋值
    n = 1;      // 直接赋值
    std::cout << n << ' ';
    n = {};     // 零初始化，然后赋值
    std::cout << n << ' ';
    n = 'a';    // 整型提升，然后赋值
    std::cout << n << ' ';
    n = {'b'};   // 显式转型，然后赋值
    std::cout << n << ' ';
    n = 1.0;    // 浮点转换，然后赋值
    std::cout << n << ' ';
//    n = {1.0}; // 编译错误（窄化转换）

    int& r = n;  // 不是赋值
    int* p;

    r = 2;       // 通过引用赋值
    std::cout << n << '\n';
    p = &n;      // 直接赋值
    p = nullptr; // 空指针转换，然后赋值

    struct {int a; std::string s;} obj;
    obj = {1, "abc"}; // 从花括号初始化器列表赋值
    std::cout << obj.a << ':' << obj.s << '\n';
}

输出：

1 0 97 98 1 2
1:abc

内建的复合赋值

复合赋值表达式的形式为

左操作数 运算符 右操作数 | (1) |
左操作数 运算符 {} | (2) | (C++11 起)
左操作数 运算符 { 右操作数 } | (3) | (C++11 起)
运算符 | - | *=、/=、%=、+=、-=、<<=、>>=、&=、^=、|= 之一
左操作数 | - | 对于内建运算符，左操作数 可具有任何算术类型，但若 运算符 为 += 或 -=，则也接受指针类型，并与 + 和 - 有相同限制
右操作数 | - | 对于内建运算符，右操作数 必须可隐式转换为 左操作数

每个内建复合赋值运算符表达式 E1 op= E2（其中 E1 是可修改左值表达式，而 E2 是右值表达式或花括号初始化器列表 (C++11 起)）的行为与表达式 E1 = E1 op E2 的行为严格相同，但只对表达式 E1 进行一次求值，并且对于顺序不确定的函数而言是一次单个操作（例如 f(a += b, g()) 中，从 g() 内来看，+= 要么完全未开始，要么已完成）。

以 volatile 限定的非类类型左值为内建复合赋值运算符的左操作数被弃用。

 (C++20 起)

在针对用户定义运算符的重载决议中，对每对 A1 和 A2，其中 A1 是算术类型（可选地有 volatile 限定）而 A2 为提升后的算术类型，下列函数签名参与重载决议：

A1& operator*=(A1&, A2);
A1& operator/=(A1&, A2);
A1& operator+=(A1&, A2);
A1& operator-=(A1&, A2);

对于每对 I1 与 I2，其中 I1 是整型类型（可选地有 volatile 限定）而 I2 为提升后的整型类型，下列函数签名参与重载决议：

I1& operator%=(I1&, I2);
I1& operator<<=(I1&, I2);
I1& operator>>=(I1&, I2);
I1& operator&=(I1&, I2);
I1& operator^=(I1&, I2);
I1& operator|=(I1&, I2);

对于每个可选地有 cv 限定的对象类型 T，下列函数签名参与重载决议：

T*& operator+=(T*&, std::ptrdiff_t );
T*& operator-=(T*&, std::ptrdiff_t );
T*volatile & operator+=(T*volatile &, std::ptrdiff_t );
T*volatile & operator-=(T*volatile &, std::ptrdiff_t );

示例

本节未完成
原因：暂无示例

参阅

运算符优先级

运算符重载

常见运算符
赋值 自增
自减 		算术 逻辑 比较 成员访问 其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
? :
特殊运算符

static_cast 转换一个类型为另一相关类型
dynamic_cast 在继承层级中转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 转换类型到无关类型
C 风格转型 以 static_cast 、 const_cast 及 reinterpret_cast 的混合转换一个类型到另一类型
new 创建有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象，并释放其所拥有的内存区域
sizeof 查询类型的大小
sizeof... 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 查询表达式是否能抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)


比较运算符

< cpp‎ | language

比较参数。

运算符名 | 语法 | 可重载 | 原型示例（对 class T）
作为成员函数 | 作为自由（命名空间）函数
等于 | a == b | 是 | bool T::operator ==(const T2 &b) const; | bool operator ==(const T &a, const T2 &b);
不等于 | a != b | 是 | bool T::operator !=(const T2 &b) const; | bool operator !=(const T &a, const T2 &b);
小于 | a < b | 是 | bool T::operator <(const T2 &b) const; | bool operator <(const T &a, const T2 &b);
大于 | a > b | 是 | bool T::operator >(const T2 &b) const; | bool operator >(const T &a, const T2 &b);
小于或等于 | a <= b | 是 | bool T::operator <=(const T2 &b) const; | bool operator <=(const T &a, const T2 &b);
大于或等于 | a >= b | 是 | bool T::operator >=(const T2 &b) const; | bool operator >=(const T &a, const T2 &b);
三路比较(C++20) | a <=> b | 是 | /*见说明*/ T::operator <=>(const T2 &b) const; | /*见说明*/ operator <=>(const T &a, const T2 &b);
注解
  • 内建运算符返回 bool，所以大多数用户定义重载也返回 bool以使用户定义运算符能以与内建运算符相同的方式使用。然而，在用户定义运算符重载中，任何类型都可用作返回类型（包含 void）。
  • T2 可以是包括 T 在内的任何类型

双路比较

双路比较运算符表达式的形式为

左操作数 < 右操作数 | (1)
左操作数 > 右操作数 | (2)
左操作数 <= 右操作数 | (3)
左操作数 >= 右操作数 | (4)
左操作数 == 右操作数 | (5)
左操作数 != 右操作数 | (6)
1) 若 左操作数 小于 右操作数 则返回 true，否则返回 false。
2) 若 左操作数 大于 右操作数 则返回 true，否则返回 false。
3) 若 左操作数 小于或等于 右操作数 则返回 true，否则返回 false。
4) 若 左操作数 大于或等于 右操作数 则返回 true，否则返回 false。
5) 若 左操作数 等于 右操作数 则返回 true，否则返回 false。
6) 若 左操作数 不等于 右操作数 则返回 true，否则返回 false。

所有情况下，对于内建运算符，左操作数 和 右操作数 在应用左值到右值、数组到指针和函数到指针标准转换后，必须具有下列类型之一

  • 算术或枚举类型（见下文的算术比较运算符）
  • 指针类型（见下文的指针比较运算符）

若两个运算数在应用这些转换前均具有数组类型，则这种比较被弃用。 (C++20 起)

任何情况下，结果均为 bool 纯右值。

算术比较运算符

如果两个操作数具有算术或（有作用域或无作用域）枚举类型，则遵循算术运算符的规则，对两个操作数实施一般算术转换。转换之后进行值的比较：

示例
#include <iostream>
int main()
{
    std::cout << std::boolalpha;
    int n = -1;

    int n2 = 1;
    std::cout << " -1 == 1? " << (n == n2) << '\n'
              << "比较两个有符号值：\n"
              << " -1  < 1? " << (n < n2) << '\n'
              << " -1  > 1? " << (n > n2) << '\n';

    unsigned int u = 1;
    std::cout << "比较有符号与无符号值：\n"
              << " -1  < 1? " << (n < u) << '\n'
              << " -1  > 1? " << (n > u) << '\n';

    static_assert(sizeof(unsigned char) < sizeof(int),
                  "不能正确地比较有符号值与较小的无符号值");
    unsigned char uc = 1;
    std::cout << "比较无符号值和较小的有符号值：\n"
              << " -1  < 1? " << (n < uc) << '\n'
              << " -1  > 1? " << (n > uc) << '\n';
}

输出：

 -1 == 1? false
比较两个有符号值：
 -1  < 1? true
 -1  > 1? false
比较有符号与无符号值：
 -1  < 1? false
 -1  > 1? true
比较无符号值和较小的有符号值：
 -1  < 1? true
 -1  > 1? false

指针比较运算符

比较运算符能用于比较二个指针。

只有相等性运算符（operator== 与 operator!=）能用于比较下列指针对：

  • 两个成员指针
  • 一个空指针常量与一个指针或成员指针
  • 一个 std::nullptr_t 值与一个空指针常量（也可以是 std::nullptr_t 值）
 (C++11 起)

首先，对两个操作数应用指针转换（若参数为成员指针则为成员指针转换）、函数指针转换 (C++17 起)和限定性转换，以获得合成指针类型，规则如下：

1) 若两个操作数均为空指针常量，则合成指针类型为 std::nullptr_t
 (C++11 起)
2) 若一个操作数为空指针常量，而另一个为指针，则合成类型正是该指针类型
3) 若两个操作数分别为
  • 指向 cv1 void 的指针，和
  • 指向 cv2 T 的指针，其中 T 为对象类型或 void，
则合成类型为“指向 cv12 void 的指针”，其中 cv12 为 cv1 与 cv2 的合并
4) 若两个操作数的类型分别为
  • 指向（可能 cv 限定的）T1 的指针 P1，和
  • 指向（可能 cv 限定的）T2 的指针 P2，
且如果 T1 与 T2 相同或是 T2 的基类，则合成指针类型为 P1 与 P2 的 cv 结合类型。否则，如果 T2 为 T1 的基类，则合成指针类型为 P2 与 P1 的 cv 结合类型。
5) 若两个操作数的类型分别为
  • 指向 T1 的成员，其类型为（可能 cv 限定的）U1，的指针 MP1，和
  • 指向 T2 的成员，其类型为（可能 cv 限定的）U2，的指针 MP2，
且如果 T1 与 T2 相同或派生自 T2，则合成指针类型为 MP1 和 MP2 的 cv 结合类型。否则，如果 T2 派生自 T1，则合成指针类型为 MP2 与 MP1 的 cv 结合类型。
6) 若操作数 P1 和 P2 的类型具有相同层数的多层混合指针和成员指针类型，而仅在任意层上的 cv 限定性有别，则合成指针类型为 P1 与 P2 的 cv 结合类型

在上面的定义中，两个指针类型 P1 和 P2 的 cv 结合类型，是与 P1 拥有相同的层数且每层具有与 P1 相同类型的类型 P3，其中每层上的 cv 限定性设定如下：

a) 除顶层之外的每层，其 cv 限定性为该层上 P1 与 P2 的 cv 限定性的合并
b) 如果有任何层上得到的 cv 限定性与同一层上 P1 或 P2 的 cv 限定性不同，则对顶层和此层之间的每一层添加 const。

例如，void* 与 const int* 的合成指针类型为 const void*。int** 与 const int** 的合成指针类型为 const int* const*。注意，在 CWG1512 的解决方案之前无法比较 int** 和 const int**。

除上述之外，函数指针和指向 noexcept 函数的指针（只要函数类型相同）的合成指针类型为函数指针。

 (C++17 起)

注意这意味着任何指针都能与 void* 进行比较。

两个（转换后的）对象指针的比较结果定义如下：

1) 若两个指针指向同一数组的不同元素，或同一数组的不同元素内的子对象，则指向拥有较高下标的元素的指针比较大于另一指针。换言之，比较指针的结果与比较其所指向的元素下标结果相同。
2) 若一个指针指向数组元素，或数组元素的子对象，而另一指针指向数组末尾元素后一位置，则后者比较大于前者。指向单个对象的指针被当做指向单元素数组的指针：&obj+1 比较大于 &obj。
3) 若在非联合体类类型的对象内，两个指针指向拥有相同成员访问的 (C++23 前)非零大小的 (C++20 起)不同非静态数据成员，或（递归地）指向这种成员的子对象或数组元素，则指向较后声明的成员的指针比较大于另一指针。换言之，三个成员访问模式的每一者中的类成员按声明顺序置于内存中。

两个（转换后的）指针的相等性比较的结果定义如下：

1) 若两个指针均为空指针值，则它们比较相等
2) 若两个指针均为函数指针且指向同一函数，则它们比较相等
3) 若两个指针均为对象指针且表示相同地址，则它们比较相等（这包括两个指向同一联合体的不同非静态成员的指针，指向标准布局结构体与其首成员的指针，由 reinterpret_cast 关联的指针等）
4) 所有其他指针的比较不相等。

两个（转换后的）成员指针的比较结果定义如下：

1) 若两个成员指针均为空成员指针值，则它们比较相等。
2) 否则，若两个成员指针之一为空成员指针值，则它们比较不相等。
3) 否则，若其中之一为指向虚成员函数的指针，则结果未指明。
4) 否则，当且仅当以一个其关联类类型的假想对象对它们解引用时，它们会指代同一最终派生对象或同一子对象的相同成员，两个成员指针相等。
5) 否则它们的比较不相等。

若指针 p 比较等于指针 q，则 p<=q 和 p>=q 都产出 true 而 p<q 和 p>q 都产出 false。

若指针 p 比较大于指针 q，则 p>=q、p>q、q<=p 和 q<p 都产出 true 而 p<=q、p<q、q>=p 和 q>p 都产出 false。

若未指明两个指针的比较大于或比较相等，则其比较结果未指明。其结果可以是不确定的，并且甚至不必在程序的同一次执行中，在拥有相同操作数的相同表达式的多次求值之间保持一致：

int x, y;

bool f(int* p, int* q) { return p < q; }

assert(f(&x, &y) == f(&x, &y)); // 在遵从标准的实现中可能引发断言

在针对用户定义运算符的重载决议中，对于（包括枚举类型的）每个提升后算术类型 L 和 R，下列函数签名参与重载决议：

bool operator<(L, R);
bool operator>(L, R);
bool operator<=(L, R);
bool operator>=(L, R);
bool operator==(L, R);
bool operator!=(L, R);

对于每个对象指针或函数指针的类型 P，下列函数签名参与重载决议：

bool operator<(P, P);
bool operator>(P, P);
bool operator<=(P, P);
bool operator>=(P, P);
bool operator==(P, P);
bool operator!=(P, P);

对于每个为成员对象指针或成员函数指针或 std::nullptr_t 的类型 MP，下列函数签名参与重载决议：

bool operator==(MP, MP);
bool operator!=(MP, MP);
示例
#include <iostream>
struct Foo  { int n1; int n2; };
union Union { int n; double d; };
int main()
{
    std::cout << std::boolalpha;

    char a[4] = "abc";

    char* p1 = &a[1];
    char* p2 = &a[2];
    std::cout << "指向数组元素的指针：p1 == p2 " << (p1 == p2)
              << ", p1 < p2 "  << (p1 < p2) << '\n';

    Foo f;
    int* p3 = &f.n1;
    int* p4 = &f.n2;
    std::cout << "指向类成员的指针：p3 == p4 " << (p3 == p4)
              << ", p3 < p4 "  << (p3 < p4) << '\n';

    Union u;
    int* p5 = &u.n;
    double* p6 = &u.d;
    std::cout << "指向联合体成员的指针：p5 == (void*)p6 " << (p5 == (void*)p6)
              << ", p5 < p6 "  << (p5 < (void*)p6) << '\n';
}

输出：

指向数组元素的指针：p1 == p2 false, p1 < p2 true
指向类成员的指针：p3 == p4 false, p3 < p4 true
指向联合体成员的指针：p5 == (void*)p6 true, p5 < p6 false

注解

因为这些运算符从左到右组合，故表达式 a<b<c 被分析为 (a<b)<c，而非 a<(b<c) 或 (a<b)&&(b<c)。

#include <iostream>
int main() {
    int a = 3, b = 2, c = 1;
    std::cout << std::boolalpha
        << ( a < b < c ) << '\n' // true ；可能警告
        << ( ( a < b ) < c ) << '\n' // true
        << ( a < ( b < c ) ) << '\n' // false
        << ( ( a < b ) && ( b < c ) ) << '\n'; // false
}

对用户定义的 operator< 的一项常见要求是严格弱序。尤其是，用比较 (Compare) 类型进行工作的标准算法和容器如 std::sort、std::max_element、std::map 等都对此有所要求。

尽管未指明对随机来源（例如不都指向同一数组中的成员）的指针比较的结果，许多实现都提供指针的严格全序，例如若它们被实现为连续的虚拟地址空间中的地址。不这样做的实现（例如并非指针的所有位都是内存地址的一部分而在比较中必须被忽略，或要求进行额外的计算否则指针与整数并非一对一关系），为指针提供具有这项保证的 std::less 的特化。这使得程序可以将随机来源的所有指针都用作标准关联容器（如 std::set 或 std::map）的键。

对于既为可相等比较 (EqualityComparable) 又为可小于比较 (LessThanComparable) 的类型，C++ 标准库在相等（即表达式 a == b 的值），和等价（即表达式 !(a < b) && !(b < a) 的值）之间做出区别。

N3624 中包含的 CWG583 的解决方案移除了指针与空指针常量间的比较。

void f(char * p)
{
  if (p > 0) { /*...*/ } // 用 N3624 出错， N3624 前可编译
  if (p > nullptr) { /*...*/ } // 用 N3624 出错， N3624 前可编译
}
int main( ){ }

三路比较

三路比较运算符表达式的形式为

左操作数 <=> 右操作数

表达式返回一个对象，使得

  • 若 左操作数 < 右操作数 则 (a <=> b) < 0
  • 若 左操作数 > 右操作数 则 (a <=> b) > 0
  • 而若 左操作数 和 右操作数 相等/等价则 (a <=> b) == 0。

如果操作数之一为 bool 类型而另一个不是，程序非良构。

若两个操作数均具有算术类型，或若一个具有无作用域枚举类型而另一个具有整型类型，则对各操作数应用一般算术转换，然后

  • 若需要进行除了从整型类型到浮点类型之外的窄化转换，则程序非良构。
  • 否则，若各操作数均具有整型类型，则运算符产出 std::strong_ordering 类型的纯右值：
  • 若两个操作数算术上相等则为 std::strong_ordering::equal，
  • 若第一操作数算术上小于第二个则为 std::strong_ordering::less
  • 否则为 std::strong_ordering::greater。
  • 否则，操作数均具有浮点类型，而运算符产出 std::partial_ordering 类型的纯右值。表达式 a <=> b 产出
  • 若 a 小于 b 则为 std::partial_ordering::less，
  • 若 a 大于 b 则为 std::partial_ordering::greater，
  • 若 a 等价于 b 则为 std::partial_ordering::equivalent（-0 <=> +0 为等价），
  • 否则为 std::partial_ordering::unordered（NaN <=> 任何值 为无序）。

若两个操作数都具有相同的枚举类型 E，则运算符产出将各操作数转换为 E 的底层类型再对转换后的操作数应用 <=> 的结果。

若至少一个操作数为指针或成员指针，则按需应用数组到指针转换、派生类到基类指针转换、函数指针转换和限定性转换，以将它们转换为同一指针类型，且结果指针类型为对象指针类型，则 p <=> q 返回 std::strong_ordering 类型的纯右值：

  • 若 p == q 则为 std::strong_ordering::equal
  • 若 q > p 则为 std::strong_ordering::less
  • 若 p > q 则为 std::strong_ordering::greater。
  • 若未指明这些指针值的比较（例如它们不指向同一对象或数组之中时），则为未指明的结果。

否则程序非良构。

在针对用户定义运算符的重载决议中，对于指针或枚举类型 T，下列函数签名参与重载决议：

R operator<=>(T, T);

其中 R 是上文所定义的顺序类别类型。

示例

#include <compare>
#include <iostream>

int main() {
    double foo = -0.0;
    double bar = 0.0;

    auto res = foo <=> bar;

    if (res < 0)
        std::cout << "-0 小于 0";
    else if (res > 0)
        std::cout << "-0 大于 0";
    else // (res == 0)
        std::cout << "-0 与 0 相等";
}

输出：

-0 与 0 相等

注解

类类型可以自动生成三路比较，见默认比较。

如果两个运算数均为数组，则三路比较均为非良构。

unsigned int i = 1;
auto r = -1 < i; // 既存陷阱：返回 false
auto r2 = -1 <=> i; // 错误：要求窄化转换

 (C++20 起)

标准库

比较运算符为标准库中的许多类所重载。

operator==operator!=
(C++20 中移除)
 检查对象是否指代相同类型
(std::type_info 的公开成员函数)
operator==operator!=operator<operator<=>
(C++20 中移除)(C++20 中移除)(C++20)
 比较两个 error_code
(函数)
operator==operator!=operator<operator<=>
(C++20 中移除)(C++20 中移除)(C++20)
 比较 error_condition 和 error_code
(函数)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按字典序比较 pair 中的值
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按字典顺序比较 tuple 中的值
(函数模板)
operator==operator!=
(C++20 中移除)
 比较其内容
(std::bitset<N> 的公开成员函数)
operator==operator!=
(C++20 中移除)
 比较两个分配器实例
(std::allocator<T> 的公开成员函数)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20)
 与另一个 unique_ptr 或 nullptr 进行比较
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 与另一个 shared_ptr 或 nullptr 进行比较
(函数模板)
operator==operator!=
(C++20 中移除)
 比较 std::function 和 nullptr
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++11)(C++11)(C++20 中移除)(C++11)(C++11)(C++11)(C++11)(C++20)
 比较两个时长
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++11)(C++11)(C++20 中移除)(C++11)(C++11)(C++11)(C++11)(C++20)
 比较两个时间点
(函数模板)
operator==operator!=
(C++20 中移除)
 比较两个 scoped_allocator_adaptor 实例
(std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...> 的公开成员函数)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20)
 比较底层 std::type_info 对象
(std::type_index 的公开成员函数)
operator==operator!=operator<operator>operator<=operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 以字典序比较两个字符串
(函数模板)
operator==operator!=
(C++20 中移除)
 locale 对象之间的相等性比较
(std::locale 的公开成员函数)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 array 中的值
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 deque 中的值
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 forward_list 中的值
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 list 中的值
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 vector 中的值
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 map 中的值
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 multimap 中的值
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 set 中的值
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 按照字典顺序比较 multiset 中的值
(函数模板)
operator==operator!=
(C++20 中移除)
 比较 unordered_map 中的值
(函数模板)
operator==operator!=
(C++20 中移除)
 比较 unordered_multimap 中的值
(函数模板)
operator==operator!=
(C++20 中移除)
 比较 unordered_set 中的值
(函数模板)
operator==operator!=
(C++20 中移除)
 比较 unordered_multiset 中的值
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20)
 按照字典顺序比较 queue 中的值
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20)
 按照字典顺序比较 stack 中的值
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20)
 比较底层迭代器
(函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++11)(C++11)(C++20 中移除)(C++11)(C++11)(C++11)(C++11)(C++20)
 比较底层迭代器
(函数模板)
operator==operator!=
(C++20 中移除)
 比较两个 istream_iterator
(函数模板)
operator==operator!=
(C++20 中移除)
 比较两个 istreambuf_iterator
(函数模板)
operator==operator!=
(C++20 中移除)
 比较两个复数，或一个复数与一个标量
(函数模板)
operator==operator!=operator<operator<=operator>operator>=
 比较两个 valarrays，或比较一个 valarray 和一个值
(函数模板)
operator==operator!=
(C++11)(C++11)(C++20 中移除)
 比较两个伪随机数引擎的内部状态
(函数)
operator==operator!=
(C++11)(C++11)(C++20 中移除)
 比较两个分布对象
(函数)
operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 比较一个 sub_match 与另一 sub_match 、字符串或字符
(函数模板)
operator==operator!=
(C++20 中移除)
 以字典序比较两个匹配结果的值
(函数模板)
operator==operator!=
(C++20 中移除)
 比较两个 regex_iterator
(std::regex_iterator<BidirIt,CharT,Traits> 的公开成员函数)
operator==operator!=
(C++20 中移除)
 比较两个 regex_token_iterator
(std::regex_token_iterator<BidirIt,CharT,Traits> 的公开成员函数)
operator==operator!=operator< operator<= operator> operator>= operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 比较两个 thread::id 对象
(函数)

命名空间 std::rel_ops 提供了泛型运算符 !=、>、<= 及 >=

定义于头文件 <utility>
定义于命名空间 std::rel_ops
operator!=operator>operator<=operator>=
(C++20 中弃用)
 自动生成基于用户定义的 operator== 和 operator< 的比较运算符
(函数模板)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 583 | C++98 C++11 | 所有六个比较运算符均能用于比较指针和 nullptr (C++11) 或另一空指针常量 (C++98) | 仅允许相等性运算符
CWG 1512 | C++98 | 合成指针类型的规则不完整，从而不允许 int** 与 const int** 间的比较 | 使之完整
CWG 1596 | C++98 | 仅就指针算术的目的认为非数组对象属于拥有一个元素的数组 | 该规则亦适用于比较

参阅

  • 运算符优先级
  • 运算符重载
  • 比较 (Compare) （具名要求）
常见运算符
赋值 自增
自减 		算术 逻辑 比较 成员访问 其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
? :
特殊运算符

static_cast 转换一个类型为另一相关类型
dynamic_cast 在继承层级中转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 转换类型到无关类型
C 风格转型 以 static_cast 、 const_cast 及 reinterpret_cast 的混合转换一个类型到另一类型
new 创建有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象，并释放其所拥有的内存区域
sizeof 查询类型的大小
sizeof... 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 查询表达式是否能抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)


自增/自减运算符

< cpp‎ | language

自增/自减运算符增加或减小对象的值。

运算符名 | 语法 | 可重载 | 原型示例（对于类 class T）
类内定义 | 类外定义
前自增 | ++a | 是 | T& T::operator++(); | T& operator++(T& a);
前自减 | --a | 是 | T& T::operator--(); | T& operator--(T& a);
后自增 | a++ | 是 | T T::operator++(int); | T operator++(T& a, int);
后自减 | a-- | 是 | T T::operator--(int); | T operator--(T& a, int);
注解
  • 内建运算符的前置版本返回引用而后置版本返回值，典型的用户定义重载也遵循该模式，从而使用户定义运算符可以与内建版本相同的方式使用。然而，用户定义重载中，能以任何类型为返回类型（包括 void）。
  • int 形参是用于区别运算符的前置和后置版本的空设形参。调用用户定义的运算符时，该形参中传递的值始终为零，但通过函数调用记法调用这个运算符时可以更改它（例如 a.operator++(2) 或 operator++(a, 2)）。

解释

前自增 与 前自减 运算符增加或减小对象的值，并返回到其结果的引用。

后自增 与 后自减 创建对象的副本，增加或减小对象的值，并返回自增或自减前的副本。

以 volatile 限定的非类类型左值为这些运算符的内建版本的操作数是被弃用的。

 (C++20 起)

内建的前置运算符

前置自增与自减表达式的形式为

++ 表达式
-- 表达式
1) 前置自增（前自增）
2) 前置自减（前自减）

内建前置自增或自减运算符的操作数 表达式 必须是非布尔的 (C++17 起)算术类型或指向完整定义的对象类型的指针类型的可修改（非 const）左值。表达式 ++x 对于非布尔操作数 (C++17 前)严格等价于 x += 1，而表达式 --x 严格等价于 x -= 1，即前置自增与自减是标识修改后的操作数的左值表达式。所有针对算术运算符定义的算术转换规则和指针算术规则都适用，并由此确定应用到操作数的隐式转换（若存在）以及表达式的返回类型。

若前自增运算符的运算数为 bool 类型，则它被设为 true (弃用)。 (C++17 前)

在针对用户定义运算符的重载决议中，对于每个 bool 以外的可选地有 volatile 限定的算术类型 A，和对于每个可选地有 volatile 限定的指向可选地有 cv 限定的对象类型的指针 P，下列函数签名参与重载决议：

A& operator++(A&) |
bool& operator++(bool&) | (弃用)(C++17 前)
P& operator++(P&) |
A& operator--(A&) |
P& operator--(P&) |

内建的后置运算符

后置自增与自减表达式拥有形式

表达式 ++
表达式 --
1) 后置自增（后自增）
2) 后置自减（后自减）

内建后置自增或自减运算符的操作数 表达式 必须是非布尔的 (C++17 起)算术类型或指向完整定义的对象类型的指针类型的可修改（非 const）左值。结果是操作数原值的纯右值副本。作为副作用，表达式 x++ 对于非布尔操作数 (C++17 前)如同 x += 1 一般修改其操作数的值，而表达式 x-- 如同 x -= 1 一般修改其操作数的值。所有为算术运算符定义的算术转换规则和指针算术规则都适用，并由此确定应用到操作数的隐式转换（若存在）以及表达式的返回类型。

若后自增运算符的操作数为 bool 类型，则它被设为 true (弃用)。 (C++17 前)

在针对用户定义运算符的重载决议中，对于每个 bool 以外的可选地有 volatile 限定的算术类型 A，和对于每个可选地有 volatile 限定的指向可选地有 cv 限定的对象类型的指针 P，下列函数签名参与重载决议：

A operator++(A&, int) |
bool operator++(bool&, int) | (弃用)(C++17 前)
P operator++(P&, int) |
A operator--(A&, int) |
P operator--(P&, int) |

示例

#include <iostream>

int main()
{
    int n1 = 1;
    int n2 = ++n1;
    int n3 = ++ ++n1;
    int n4 = n1++;
//  int n5 = n1++ ++;   // 错误
//  int n6 = n1 + ++n1; // 未定义行为
    std::cout << "n1 = " << n1 << '\n'
              << "n2 = " << n2 << '\n'
              << "n3 = " << n3 << '\n'
              << "n4 = " << n4 << '\n';
}

输出：

n1 = 5
n2 = 2
n3 = 4
n4 = 4

注解

因为涉及到了副作用，所以必须谨慎使用内建的自增和自减运算符，以避免违背定序规则所致的未定义行为。

由于后自增和后自减期间会构造对象的临时副本，故在不使用返回值的语境中前自增或前自减运算符通常更有效率。

标准库

自增和自减运算符对许多标准库类型重载。特别是每个老式迭代器 (LegacyIterator) 都重载了 operator++，而且每个老式双向迭代器 (LegacyBidirectionalIterator) 都重载了 operator--，即便这些运算符对于某些特定迭代器是无操作的。

对算术类型的重载
operator++operator++(int)operator--operator--(int)
 令原子值增加或减少一
(std::atomic<T> 的公开成员函数)
operator++operator++(int)operator--operator--(int)
 递增或递减滴答计数
(std::chrono::duration<Rep,Period> 的公开成员函数)
对迭代器类型的重载
operator++operator++(int)
 推进迭代器
(std::raw_storage_iterator<OutputIt,T> 的公开成员函数)
operator++operator++(int)operator+=operator+operator--operator--(int)operator-=operator-
 推进或回退迭代器
(std::reverse_iterator<Iter> 的公开成员函数)
operator++operator++(int)operator+=operator+operator--operator--(int)operator-=operator-
(C++11)
 推进或回退迭代器
(std::move_iterator<Iter> 的公开成员函数)
operator++operator++(int)
 无操作
(std::front_insert_iterator<Container> 的公开成员函数)
operator++operator++(int)
 无操作
(std::back_insert_iterator<Container> 的公开成员函数)
operator++operator++(int)
 无操作
(std::insert_iterator<Container> 的公开成员函数)
operator++operator++(int)
 推进迭代器
(std::istream_iterator<T,CharT,Traits,Distance> 的公开成员函数)
operator++operator++(int)
 无操作
(std::ostream_iterator<T,CharT,Traits> 的公开成员函数)
operator++operator++(int)
 推进迭代器
(std::istreambuf_iterator<CharT,Traits> 的公开成员函数)
operator++operator++(int)
 无操作
(std::ostreambuf_iterator<CharT,Traits> 的公开成员函数)
operator++operator++(int)
 推进迭代器到下一个匹配
(std::regex_iterator<BidirIt,CharT,Traits> 的公开成员函数)
operator++operator++(int)
 推进迭代器到下一个子匹配
(std::regex_token_iterator<BidirIt,CharT,Traits> 的公开成员函数)

参阅

运算符优先级

运算符重载

常见运算符
赋值 自增
自减 		算术 逻辑 比较 成员访问 其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
? :
特殊运算符

static_cast 转换一个类型为另一相关类型
dynamic_cast 在继承层级中转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 转换类型到无关类型
C 风格转型 以 static_cast 、 const_cast 及 reinterpret_cast 的混合转换一个类型到另一类型
new 创建有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象，并释放其所拥有的内存区域
sizeof 查询类型的大小
sizeof... 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 查询表达式是否能抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)


逻辑运算符

< cpp‎ | language

返回布尔运算的结果。

运算符名 | 语法 | 可重载 | 原型示例（对于类 class T ）
类内定义 | 类外定义
非 not a

!a

 是 bool T::operator!() const; bool operator!(const T &a);
与 a and b

a && b

 是 bool T::operator&&(const T2 &b) const; bool operator&&(const T &a, const T2 &b);
同或 a or b

a || b

 是 bool T::operator||(const T2 &b) const; bool operator||(const T &a, const T2 &b);
注解
  • 关键词形式（and、or、not）和符号形式（&&、||、!）的使用可以互相代替（见代用表示）
  • 所有内建运算符都返回 bool，而大多数用户定义重载亦返回 bool，以使用户定义运算符可以与内建版本相同的方式使用。然而，用户定义重载中能以任何类型为返回类型（包括 void）。
  • 内建运算符 && 和 || 进行短路求值（若在求值第一个操作数后结果已知，则不求值第二个），但重载的运算符表现类似函数调用，并始终对两个操作数都进行求值。

解释

逻辑运算符的形式为

! 操作数 | (1)
左操作数 && 右操作数 | (2)
左操作数 || 右操作数 | (3)
1) 逻辑非（NOT）
2) 逻辑与（AND）
3) 逻辑或（inclusive OR）

若操作数并非 bool，则用按语境转换为 bool 规则将它转换为 bool：仅当对某个虚构的临时量 t，声明 bool t(arg) 良构时，它才是良构的。

其结果是 bool 纯右值。

对于内建的逻辑非运算符，若操作数为 false 则结果为 true。否则结果为 false。

对于内建的逻辑与运算符，若两个运算数都是 true 则结果为 true。否则结果为 false。此运算符短路求值：若第一操作数为 false，则不求值第二操作数。

对于内建的逻辑或运算符，若第一或第二操作数之一（或两者同）为 true，则结果为 true。此运算符短路求值：若第一操作数为 true，则不求值第二操作数。

注意逐位逻辑运算符不进行短路求值。

结果

a | true | false
!a | false | true
and |  | a
 |  | true | false
b | true | true | false
 | false | false | false
or |  | a
 |  | true | false
b | true | true | true
 | false | true | false

在面对用户定义运算符的重载决议中，下列内建函数签名参与重载决议：

bool operator!(bool)
bool operator&&(bool, bool)
bool operator||(bool, bool)

示例

#include <iostream>
#include <string>
int main()
{
    int n = 2;
    int* p = &n;
    // 指针可以转换为 bool
    if(    p && *p == 2   // "p &&" 后可安全使用 "*p"
       || !p &&  n != 2 ) // || 的优先级低于 &&
        std::cout << "true\n";

    // 流也可以转换为 bool
    std::cout << "输入 'quit' 以退出。\n";
    for(std::string line;    std::cout << "> "
                          && std::getline(std::cin, line)
                          && line != "quit"; )
        ;
}

输出：

true
输入 'quit' 以退出。
> test
> quit

标准库

因为 operator&& 和 operator|| 的短路求值性质对重载不适用，又因为有布尔语义的类型不常见，故只有二个标准库类重载了这些运算符：

operator!
 对 valarray 的每个元素应用一元算术运算符
(std::valarray<T> 的公开成员函数)
operator&&operator||
 对两个 valarray 的每个元素，或一个 valarray 的每个元素和一个值应用二元运算符
(函数模板)
operator!
 检查是否有错误发生（fail() 的同义词）
(std::basic_ios<CharT,Traits> 的公开成员函数)

参阅

运算符优先级

运算符重载

常见运算符
赋值 自增
自减 		算术 逻辑 比较 成员访问 其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
? :
特殊运算符

static_cast 转换一个类型为另一相关类型
dynamic_cast 在继承层级中转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 转换类型到无关类型
C 风格转型 以 static_cast 、 const_cast 及 reinterpret_cast 的混合转换一个类型到另一类型
new 创建有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象，并释放其所拥有的内存区域
sizeof 查询类型的大小
sizeof... 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 查询表达式是否能抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)


成员访问运算符

< cpp‎ | language

访问其操作数的一个成员。

运算符名 | 语法 | 可重载 | 原型示例（对于 class T ）
类定义内 | 类定义外
下标 a[b] 是 R& T::operator[](S b);

R& T::operator[](S1 s1, ...);

 (C++23 起)
N/A
间接寻址 | *a | 是 | R& T::operator*(); | R& operator*(T a);
取地址 | &a | 是 | R* T::operator&(); | R* operator&(T a);
对象的成员 | a.b | 否 | N/A | N/A
指针的成员 | a->b | 是 | R* T::operator->() | N/A
指向对象的成员的指针 | a.*b | 否 | N/A | N/A
指向指针的成员的指针 | a->*b | 是 | R& T::operator->*(S b); | R& operator->*(T a, S b);
注解
  • 与大多数用户定义的重载相同，返回类型应当与内建运算符所提供的返回类型相匹配，以便用户定义的运算符可以和内建运算符以相同的方式使用。不过，在用户定义的运算符重载中，任何类型都可以作为其返回类型（包括 void）。一个例外是 operator->，它必须返回一个指针或者另一个带有重载的 operator-> 的类以使其真正可用。

解释

内建的下标 (subscript)运算符提供对其指针或数组操作数所指向的对象的访问。

内建的间接寻址 (indirection)运算符提供对其指针操作数所指向的对象或函数的访问。

内建的取地址 (address of)运算符创建指向其对象或函数操作数的指针。

对象的成员和指向对象的成员的指针运算符提供对其对象操作数的数据成员或成员函数的访问。

内建的指针的成员和指向指针的成员的指针运算符提供对其指针操作数所指向的类的数据成员或成员函数的访问。

内建的下标运算符

下标运算符表达式的形式为

表达式1 [ 表达式2 ] | (1) |
表达式1 [ { 表达式, ... } ] | (2) | (C++11)
表达式1 [ 表达式2 , expr, ... ] | (3) | (C++23)
1) 对于内建运算符，表达式之一（表达式1 或 表达式2）必须是“T 的数组”类型的泛左值或“T 的指针”类型的纯右值，而另一表达式（分别为 表达式2 或 表达式1）必须是无作用域枚举或整型类型的纯右值。此表达式的结果类型为 T。 表达式2 不能为无括号的逗号表达式。 (C++23 起)
2) 方括号中有花括号环绕列表的形式仅用于调用重载的 operator[]。
3) 方括号中有逗号分隔的表达式列表的形式仅用于调用重载的 operator[]。

内建下标表达式 E1[E2] 除了求值顺序之外 (C++17 起)与表达式 *(E1 + E2) 严格等同，就是说，它遵循指针算术的规则，将指针操作数（可以是数组到指针转换的结果，但它必须指向某数组的元素或末尾后一位置）调整为指向同数组的另一元素，然后再进行解引用。

应用到数组时，若数组为左值，则 (C++11 起)下标表达式为左值 ，否则为亡值 (C++11 起)。

应用到指针时，下标表达式始终是左值。

类型 T 不得为不完整类型，即使始终不会使用 T 的大小或其内部结构也是如此，如 &x[0]。

以无括号的逗号表达式为下标运算符的第二（右）操作数是被弃用的。 例如， a[b, c] 被弃用而 a[(b, c)] 未被弃用。 | (C++20 起) (C++23 前)
无括号的逗号表达式不能为下标运算符的第二（右）参数。例如 a[b, c] 要么非良构要么等价于 a.operator[](b, c)。 为将逗号表达式用作下标需要括号，例如 a[(b, c)]。 | (C++23 起)

在对于用户定义运算符的重载决议中，对于每个对象类型 T（可有 cv 限定），下列函数签名参与重载决议：

T& operator[](T*, std::ptrdiff_t );
T& operator[]( std::ptrdiff_t, T*);

#include <iostream>

int main()
{
    int a[4] = {1, 2, 3, 4};
    int* p = &a[2];
    std::cout << p[1] << p[-1] << 1[p] << (-1)[p] << '\n';

    std::map<std::pair<int, int>, std::string> m;
    m[{1, 2}] = "abc"; // 使用 [{...}] 版本
}

输出：

4242

内建的间接寻址运算符

间接寻址运算符表达式的形式为

* 表达式

内建间接寻址运算符的操作数必须是对象指针或函数指针，其结果就是 表达式 所指向的指针或函数。

指向（可有 cv 限定）的 void 的指针不能解引用。指向其他不完整类型的指针可以解引用，但产生的左值只能在允许不完整类型的语境中使用，例如初始化一个引用。

在对于用户定义运算符的重载决议中，对于每个要么为（可有 cv 限定的）对象类型要么为（未被 const 或引用限定的）函数类型的类型 T，下列函数签名参与重载决议：

T& operator*(T*);

#include <iostream>

int f() { return 42; }

int main()
{
    int n = 1;
    int* pn = &n;

    int& r = *pn;  // 左值可以绑定到引用
    int m = *pn;   // 间接寻址 + 左值到右值转换

    int (*fp)() = &f;
    int (&fr)() = *fp; // 函数左值可以绑定到引用
}

内建的取地址运算符

取地址运算符表达式的形式为

& 表达式 | (1)
& 类 :: 成员 | (2)
1) 当操作数是某个对象或函数类型 T 的左值表达式时，operator& 创建并返回一个有相同 cv 限定的 T* 类型的纯右值，并指向由该操作数所代表的对象或函数。当其操作数具有不完整类型时，可以构成指针，但若该不完整类型恰好为某个定义了其自身的 operator& 的类，则使用内建还是重载运算符是未指明的。对于其类型带有用户定义的 operator& 的操作数，可以使用 std::addressof 来获取真正的指针。注意，这和 C99 以及其后的 C 语言版本不同，不存在对一元 operator* 运算符的运算结果应用一元 operator& 运算符的特殊情况。
当其操作数为重载函数的名字时，仅当根据其语境可以解析这个重载时才能取得其地址。详细说明参见重载函数的地址。
2) 当其操作数为非静态成员的限定名（比如 &C::member）时，其结果为 C 类中的 T 类型的成员函数指针或数据成员指针的纯右值。注意，&member、C::member，甚至 &(C::member) 都不能用于初始化成员指针。

在对于用户定义运算符的重载决议中，此运算符不引入任何额外函数签名：若存在作为可行函数的重载 operator&，则内建的取址运算符不适用。

void f(int) {}
void f(double) {}
struct A { int i; };
struct B { void f(); };

int main()
{
    int n = 1;
    int* pn = &n; // 指针
    int* pn2 = &*pn; // pn2 == pn
    int A::* mp = &A::i; // 指向数据成员的指针
    void (B::*mpf)() = &B::f; // 指向成员函数的指针

    void (*pf)(int) = &f; // 根据初始化语境进行重载决议
//  auto pf2 = &f; // 错误：重载函数类型有歧义
    auto pf2 = static_cast<void (*)(int)>(&f); // 由于转型进行重载决议
}

内建的成员访问运算符

成员访问运算符表达式的形式为

表达式 . template(可选) 标识表达式 | (1)
表达式 -> template(可选) 标识表达式 | (2)
表达式 . 伪析构函数 | (3)
表达式 -> 伪析构函数 | (4)
1) 第一操作数必须是完整类类型 T 的表达式。
2) 第一操作数必须是指向完整类类型的指针 T* 的表达式。
3,4) 第一操作数必须是标量类型表达式（见下文）。

两种运算符的第一个操作数都被求值，即便它并不是必须的（比如其第二个操作数指名的是静态成员）。

两个运算符的第二个操作数是 T 或 T 的某个无歧义且可访问的基类 B 的数据成员或成员函数的名字（正式的说法是标识表达式（id-expression））（如 E1.E2 或 E1->E2），并可选地有限定（如 E1.B::E2 或 E1->B::E2），可选地使用 template 歧义消解符（如 E1.template E2 或 E1->template E2）。

如果提供的是用户定义的 operator->，则递归地对其所返回的值再次调用 operator->，直到到达返回普通指针的 operator-> 为止。之后再对这个指针采用内建语义。

对于内建类型，表达式 E1->E2 严格等价于 (*E1).E2；因此以下规则仅处理了 E1.E2 的情形。

在表达式 E1.E2 中：

1) 当 E2 为静态数据成员时：
  • 如果 E2 具有引用类型 T& 或 T&&，则其结果为 T 类型的左值，代表 E2 所代表的对象或函数，
  • 否则，其结果为代表该静态数据成员的左值。
基本上，这两种情况下 E1 均被求值随即被丢弃；
2) 当 E2 为非静态数据成员时：
  • 如果 E2 具有引用类型 T& 或 T&&，则其结果为 T 类型的左值，代表 E2 所代表的对象或函数，
  • 否则，如果 E1 为左值，则其结果为代表 E1 的这个非静态数据成员的左值，
  • 否则（E1 为右值 (C++17 前)亡值（可能是从纯右值实质化而来） (C++17 起)），其结果为代表 E1 的这个非静态数据成员的右值 (C++11 前)亡值 (C++11 起)。
若 E2 不是 mutable 成员，则结果的 cv 限定性是 E1 和 E2 的 cv 限定性的合并，否则（E2 是 mutable 成员）为 E1 和 E2 的 volatile 限定性的合并；
3) 当 E2 为静态成员函数时，其结果为代表该静态成员函数的左值。基本上，这种情况下 E1 被求值随即被丢弃；
4) 当 E2 为（包括析构函数在内的）非静态成员函数时，其结果为代表 E1 的这个非静态成员函数的一种特殊的纯右值，它只能用作成员函数调用运算符的左操作数，而不能用于其他目的；
5) 当 E2 为成员枚举项时，其结果为等于 E1 的这个成员枚举项的纯右值；
6) 当 E2 为嵌套类型时，程序非良构（无法编译）；
7) 当 E1 为标量类型而 E2 为一个 ~ 之后跟着代表（移除 cv 限定后）相同类型的类型名或 decltype 说明符，可选地有限定时，其结果为一种特殊的纯右值，它只能用作函数调用运算符的左操作数，而不能用于其他目的。所构成的函数调用表达式被称为伪析构函数调用（pseudo destructor call）。它不接受任何实参，返回 void ，求值 E1 后结束其结果对象的生存期。这是唯一使 operator. 的左操作数具有非类类型的情形。允许进行伪析构函数调用，使得编写代码时无须了解某个给定类型是否存在析构函数成为可能。

operator. 不能重载，而对于 operator-> 来说，在对于用户定义运算符的重载决议中，内建运算符不引入任何额外函数签名：若存在作为可行函数的重载 operator&，则不采用内建的 operator->。

#include <iostream>

struct P
{
    template<typename T>
    static T* ptr() { return new T; }
};

template<typename T>
struct A
{
    A(int n): n(n) {}
    int n;
    static int sn;
    int f() { return 10 + n; }
    static int sf() { return 4; }
    class B {};
    enum E {RED = 1, BLUE = 2};

    void g()
    {
        typedef int U;
        // 待决的模板成员需要关键词 template
        int* p = P().template ptr<U>();
        p->~U(); // U 为 int，调用 int 的伪析构函数
        delete p;
    }
};
template<> int A<P>::sn = 2;

int main()
{
    A<P> a(1);
    std::cout << a.n << ' '
              << a.sn << ' '   // A::sn 也可以
              << a.f() << ' '
              << a.sf() << ' ' // A::sf() 也可以
//            << a.B << ' '    // 错误：不允许嵌套类型
              << a.RED << ' '; // 枚举项
}

输出：

1 2 11 4 1

内建的成员指针访问运算符

通过成员指针进行的成员访问运算符表达式的形式为

左操作数 .* 右操作数 | (1)
左操作数 ->* 右操作数 | (2)
1) 左操作数 必须是类类型 T 的表达式。
2) 左操作数 必须是指向类类型指针 T* 的表达式。

两个运算符的第二操作数都是类型为指向 T 的（数据或函数）成员指针类型，或为指向 T 的无歧义且可访问基类 B 成员指针类型的表达式。

对于内建类型，表达式 E1->*E2 严格等价于 (*E1).*E2；因此以下规则仅处理了 E1.*E2 的情形。

在表达式 E1.*E2 中：

1) 当 E2 为指向数据成员的指针时，
  • 如果 E1 为左值，则其结果为代表这个成员的左值，
  • 否则（E1 为右值 (C++17 前)亡值（可能是从纯右值实质化而来） (C++17 起)），其结果为代表这个数据成员的右值 (C++11 前)亡值 (C++11 起)；
2) 当 E2 为指向成员函数的指针时，其结果为代表这个成员函数的一种特殊的纯右值，它只能用作成员函数调用运算符的左运算数，而不能用于其他目的；
3) cv 限定性的规则与对象的成员运算符相同，但有一条额外规则：指代 mutable 成员的成员指针不能用于改动 const 对象中的这个成员；
4) 当 E2 为空成员指针值时，其行为未定义；
5) 当 E1 的动态类型并不包含 E2 所指代的成员时，其行为未定义；
6) 当 E1 为右值而 E2 指向带有引用限定符 & 的成员函数时，程序非良构，除非该成员函数亦为 const 限定但非 volatile 限定 (C++20 起)；
7) 当 E1 为左值而 E2 指向带有引用限定符 && 的成员函数时，程序非良构。

在对于用户定义运算符的重载决议中，对于每个类型 D, B, R 的组合，其中类类型 B 是与 D 相同的类或 D 的无歧义且可访问基类，而 R 是对象或函数类型，下列函数签名参与重载决议：

R& operator->*(D*, R B::*);

其中两个操作数都可以是 cv 限定的，这种情况下返回类型的 cv 限定性是个操作数的 cv 限定性的合并。

#include <iostream>

struct S
{
    S(int n): mi(n) {}
    mutable int mi;
    int f(int n) { return mi + n; }
};

struct D: public S
{
    D(int n): S(n) {}
};

int main()
{
    int S::* pmi = &S::mi;
    int (S::* pf)(int) = &S::f;

    const S s(7);
//  s.*pmi = 10; // 错误：无法通过 mutable 进行修改
    std::cout << s.*pmi << '\n';

    D d(7); // 基类的指针可以在派生类对象上工作
    D* pd = &d;
    std::cout << (d.*pf)(7) << ' '
              << (pd->*pf)(8) << '\n';
}

输出：

7
14 15

标准库

许多标准容器类都重载了下标运算符

operator[] | 访问指定的位 (std::bitset<N> 的公开成员函数)
operator[] | 提供到被管理数组的有索引访问 (std::unique_ptr<T,Deleter> 的公开成员函数)
operator[] | 访问指定字符 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
operator[] (C++11) | 访问指定的元素 (std::array<T,N> 的公开成员函数)
operator[] | 访问指定的元素 (std::deque<T,Allocator> 的公开成员函数)
operator[] | 访问指定的元素 (std::vector<T,Allocator> 的公开成员函数)
operator[] | 访问或插入指定的元素 (std::map<Key,T,Compare,Allocator> 的公开成员函数)
operator[] (C++11) | 访问或插入指定的元素 (std::unordered_map<Key,T,Hash,KeyEqual,Allocator> 的公开成员函数)
operator[] | 按索引访问元素 (std::reverse_iterator<Iter> 的公开成员函数)
operator[] (C++11) | 按索引访问元素 (std::move_iterator<Iter> 的公开成员函数)
operator[] | 获取/设置 valarray 数组元素、切片或掩码 (std::valarray<T> 的公开成员函数)
operator[] | 返回指定的子匹配 (std::match_results<BidirIt,Alloc> 的公开成员函数)

许多迭代器和智能指针类都重载了间接寻址和成员运算符

operator*operator-> | 解引用指向被管理对象的指针 (std::unique_ptr<T,Deleter> 的公开成员函数)
operator*operator-> | 解引用存储的指针 (std::shared_ptr<T> 的公开成员函数)
operator*operator-> | 访问被管理对象 (std::auto_ptr<T> 的公开成员函数)
operator* | 解引用迭代器 (std::raw_storage_iterator<OutputIt,T> 的公开成员函数)
operator*operator-> | 对递减后的底层迭代器进行解引用 (std::reverse_iterator<Iter> 的公开成员函数)
operator* | 无操作 (std::back_insert_iterator<Container> 的公开成员函数)
operator* | 无操作 (std::front_insert_iterator<Container> 的公开成员函数)
operator* | 无操作 (std::insert_iterator<Container> 的公开成员函数)
operator*operator-> (C++11)(C++11)(C++20 中弃用) | 访问被指向的元素 (std::move_iterator<Iter> 的公开成员函数)
operator*operator-> | 返回当前元素 (std::istream_iterator<T,CharT,Traits,Distance> 的公开成员函数)
operator* | 无操作 (std::ostream_iterator<T,CharT,Traits> 的公开成员函数)
operator*operator-> (C++11 起)(C++17 前) | 获得当前字符的副本 若 CharT 拥有成员，则访问当前字符的成员 (std::istreambuf_iterator<CharT,Traits> 的公开成员函数)
operator* | 无操作 (std::ostreambuf_iterator<CharT,Traits> 的公开成员函数)
operator*operator-> | 访问当前匹配 (std::regex_iterator<BidirIt,CharT,Traits> 的公开成员函数)
operator*operator-> | 访问当前子匹配 (std::regex_token_iterator<BidirIt,CharT,Traits> 的公开成员函数)

标准库中的类都没有重载 operator&。最为人所知的重载 operator& 的例子是微软的 COM 类 CComPtr，但在如 boost.spirit 这样的 EDSL 中也会出现重载它的例子。

标准库中的类都没有重载 operator->*。曾有建议将其作为智能指针接口的一部分，并在 boost.phoenix 中的 actor 上有实际应用，但它在如 cpp.react 这样的 EDSL 中更为常见。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1213 | C++11 | 数组右值的下标操作导致左值 | 重分类为亡值
CWG 1458 | C++98 | 应用 & 到声明 operator& 的不完整类型左值导致未定义行为 | 未指明使用哪个 &

参阅

运算符优先级

运算符重载

常见运算符
赋值 自增
自减 		算术 逻辑 比较 成员访问 其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
? :
特殊运算符

static_cast 转换一个类型为另一相关类型
dynamic_cast 在继承层级中转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 转换类型到无关类型
C 风格转型 以 static_cast 、 const_cast 及 reinterpret_cast 的混合转换一个类型到另一类型
new 创建有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象，并释放其所拥有的内存区域
sizeof 查询类型的大小
sizeof... 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 查询表达式是否能抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)


其他运算符

< cpp‎ | language
运算符名 | 语法 | 可重载 | 原型示例（对于 class T）
 |  |  | 类内定义 | 类外定义
函数调用 | a(a1, a2) | 是 | R T::operator()(Arg1 &a1, Arg2 &a2, ... ...); | N/A
逗号 | a, b | 是 | T2& T::operator,(T2 &b); | T2& operator,(const T &a, T2 &b);
条件 | a ? b : c | 否 | N/A | N/A

解释

函数调用运算符为任何对象提供函数语义。

条件运算符（通俗地称为“三元条件”）检查第一表达式的布尔值，然后根据其结果值，求值并返回第二或第三表达式。

内建的函数调用运算符

函数调用表达式的形式为

函数表达式 ( 实参1, 实参2, 实参3,... )

其中

  • 函数表达式 是指名函数的表达式
  • 实参1, 实参2, 实参3,... 是可能为空的任意表达式的列表，但为避免歧义不允许顶层出现逗号运算符。

指名函数的表达式可以为

a) 指代函数的左值表达式
b) 函数指针
c) 选择成员函数的显式类成员访问表达式
d) 隐式类成员访问表达式，例如在另一成员函数内使用的成员函数名。

由函数表达式 所指代的函数（或成员）名可以是重载的，用重载决议规则决定要调用哪个重载。

若函数表达式 指定成员函数，则它可为虚，这种情况下将以运行时的动态派发调用该函数的最终覆盖函数。

为调用该函数，

以任意顺序对表达式函数表达式 和作为实参所提供的所有表达式实参1、实参2、实参3 等进行求值，它们互相是无顺序的（unsequenced）。 | (C++17 前)
表达式函数表达式 按顺序早于（sequenced before）表达式 实参1、实参2、实参3 以及各默认实参（若存在）。以任意顺序求值各实参表达式，它们互相是顺序不确定的（indeterminately sequenced）。 | (C++17 起)

各个函数形参以其对应实参（若需要，经过隐式转换后）初始化。若没有对应实参，则使用对应的默认实参，而若其不存在则程序非良构。如果所进行的是成员函数调用，则将指向当前对象的 this 指针，如同使用显式转型一般，转换到函数所期待的 this 指针。各个形参的初始化和销毁是在调用方的语境中进行的，这意味着，例如当某个形参的构造函数抛出异常时，不会考虑定义于函数内的异常处理块，即使是函数 try 块也如此。若函数为变参函数，则对省略号形参所匹配的所有实参实施默认实参提升。形参的生存期是结束于定义它的函数返回时，还是外围全表达式的结尾，是由实现定义的。

函数调用表达式的返回类型是被选择函数的返回类型，以静态绑定决定（忽略 virtual 关键词），即使实际调用的覆盖函数返回不同的类型。这允许覆盖函数返回引用或指针，指向派生于基类函数所返回类型的类，即 C++ 支持协变（covariant）返回类型。若 E 指定析构函数，则返回类型为 void。

当一个类类型 X 的对象被传递给函数，或被从函数返回时，如果 X 的每个复制构造函数、移动构造函数和析构函数均为平凡或被弃置（delete）的，并且 X 拥有至少一个未被弃置的复制或移动构造函数，则容许实现创建保有函数形参或结果对象的临时对象。

临时对象分别从函数实参或返回值构造，而函数的形参或返回对象的初始化，如同使用未被弃置的平凡构造函数对临时对象进行复制一样进行（即使该构造函数无法访问，或它并不会被进行对象的复制或移动时的重载决议所选择，也是如此）。

这允许小的类类型（如 std::complex 或 std::span）可以在寄存器中传递给函数或从函数返回。

 (C++17 起)

若函数返回左值引用或到函数的右值引用，则函数调用表达式的值类别为左值，若函数返回到对象的右值引用，则值类别为亡值，否则值类别为纯右值。若函数调用表达式为对象类型的纯右值，则它必须拥有完整对象类型，除非该纯右值不会被实质化，比如 (C++17 起)用作 decltype 的操作数，或用作作为 decltype 操作数的内建逗号运算符表达式的右操作数。

函数调用表达式在语法上与值初始化 T()，函数风格转型表达式 T(A1)，以及临时量的直接初始化 T(A1, A2, A3, ...) 相似，其中 T 是一个类型的名称。

#include <cstdio>
struct S
{
    int f1(double d) {
        return printf("%f \n", d); // 变参函数调用
    }
    int f2() {
        return f1(7); // 成员函数调用，同 this->f1()
                      // 整数形参转换为 double
    }
};
void f() {
   puts("函数已调用"); // 函数调用
}
int main()
{
    f(); // 函数调用
    S s;
    s.f2(); // 成员函数调用
}

输出：

函数已调用
7.000000

内建的逗号运算符

逗号运算符表达式的形式为

表达式1 , 表达式2

逗号表达式 E1, E2 中，对 E1 求值并舍弃其结果（尽管当它具有类类型时，直到包含它的全表达式的结尾之前都不会销毁它），其副作用在表达式 E2 的求值开始前完成（注意，用户定义的 operator, 不能保证定序） (C++17 前)。

逗号表达式结果的类型、值和值类别严格为其第二操作数 E2 的类型、值和值类别。若 E2 为临时量表达式 (C++17 起)，则表达式的结果为该临时量表达式 (C++17 起)。若 E2 为位域，则结果为位域。

各种逗号分隔列表，例如函数实参列表（f(a, b, c)）和初始化器列表 int a[] = {1,2,3}，其中的逗号都不是逗号运算符。若需要在这种语境中使用逗号运算符，则必须加括号：f(a, (n++, n+b), c)。

以无括号的逗号表达式为下标运算符的第二（右）操作数是被弃用的。 例如， a[b, c] 被弃用而 a[(b, c)] 未被弃用。 | (C++20 起) (C++23 前)
无括号的逗号表达式不能为下标运算符的第二（右）参数。例如 a[b, c] 要么非良构要么等价于 a.operator[](b, c)。 为将逗号表达式用作下标需要括号，例如 a[(b, c)]。 | (C++23 起)
#include <iostream>
int main()
{
    int n = 1;
    int m = (++n, std::cout << "n = " << n << '\n', ++n, 2*n);
    std::cout << "m = " << (++m, m) << '\n';
}

输出：

n = 2
m = 7

条件运算符

条件运算符表达式的形式为

表达式1 ? 表达式2 : 表达式3

对条件运算符的第一操作数求值并将其按语境转换为 bool。当第一操作数的值计算和所有副作用完成之后，若结果为 true，则求值第二操作数。若结果为 false，则求值第三操作数。

条件表达式 E1 ? E2 : E3 的类型和值类别按照下列规则确定：

1) 若 E2 或 E3 具有 void 类型，则下列之一必须为真，否则程序非良构：
1.1) E2 或 E3（但非两者）为（可带括号的）throw 表达式。条件运算符的结果具有另一表达式的类型和值类别。若另一表达式为位域，则结果为位域。这种条件运算符常用于 C++14 之前的 C++11 constexpr 编程。
std::string str = 2+2==4 ? "ok" : throw std::logic_error("2+2 != 4");
1.2) E2 和 E3 都具有 void 类型（包括两者均为 throw 表达式的情况）。结果为 void 类型的纯右值。
2+2==4 ? throw 123 : throw 456;
2) 否则，若 E2 或 E3 均为值类别相同的泛左值位域，类型分别为 cv1 T 和 cv2 T，则此节剩下的部分中认为这些操作数都拥有 cv T 类型，其中 cv 是 cv1 与 cv2 的合并。
 (C++14 起)
3) 否则，若 E2 与 E3 拥有不同类型且至少有一个是（可有 cv 限定的）类类型，或都是同一值类别的泛左值且具有除了 cv 限定性之外都相同的类型，则尝试组成隐式转换序列 （其中忽略成员访问，操作数是否为位域，或转换函数是否被弃置） (C++14 起)，从每个操作数转换到由另一操作数所确定的目标类型，如下文所述。一个名为 X 的 TX 类型的操作数，能以如下方式转换成另一名为 Y 的 TY 类型操作数的目标类型：
3.1) 若 Y 为左值，则目标类型为 TY&，且引用必须直接绑定到左值；
3.2) 若 Y 为亡值，则目标类型为 TY&&，且引用必须直接绑定；
3.3) 若 Y 为纯右值，或若两个转换序列都无法组成，且 TX 和 TY 至少有一个是（可为 cv 限定的）类类型，
3.3.1) 若 TX 和 TY（忽略 cv 限定性）为相同类类型，且 TY 至少有 TX 的 cv 限定，则目标类型为 TY,
3.3.2) 否则，若 TY 是 TX 的基类，则目标类型为带有 TX 的 cv 限定符的 TY
struct A {};
struct B : A {};
using T = const B;
A a = true ? A() : T(); // Y = A(), TY = A, X = T(), TX = const B. 目标类型 = const A
3.3.3) 否则，目标类型为 Y 在应用左值到右值、数组到指针和函数到指针标准转换后会有的类型。
3.4) 若两个序列（E2 到 E3 的目标类型和 E3 到 E2 的目标类型）均可组成，或只能组成一个但它是有歧义转换序列，则程序非良构。
3.5) 若恰能组成一个转换序列（注意它仍然可能非良构，例如由于访问违规），则应用该转换序列，此描述的余下部分（从 (4) 之后）中用转换后的操作数取代原操作数。
3.6) 若不能组成任何转换序列，则在此描述的余下部分中保留各操作数不变。
4) 若 E2 与 E3 是同类型和同值类别的泛左值，则结果具有相同的类型和值类别，而若 E2 与 E3 至少有一个是位域，则结果为位域。
5) 否则，结果为纯右值。若 E2 与 E3 具有不同类型，且一者拥有（可为 cv 限定的）类类型，则尝试用下文的各内建候选函数将操作数转换为内建类型，并为此实施重载决议。若重载决议失败，则程序非良构。否则，应用所选择的转换，并在步骤 6 用转换后的操作数取代原操作数。
6) 对第二和第三操作数应用左值到右值、数组到指针和函数到指针转换，然后，
6.1) 若 E2 与 E3 现在均具有相同类型，则结果是该类型的纯右值，指代一个临时对象， (C++17 前)其结果对象 (C++17 起)从求值 E1 后选择的那个操作数进行复制初始化。
6.2) 若 E2 与 E3 均具有算术或枚举类型：则应用一般算术转换将它们变为公共类型，而该类型即是结果。
6.3) 若 E2 与 E3 均为指针，或一个是指针而另一个是空指针常量，则应用指针转换和限定性转换，将它们变为公共类型，而该类型即是结果。
6.4) 若 E2 与 E3 均为成员指针，或一个是成员指针而另一个是空指针常量，则应用成员指针转换和限定性转换，将它们变成公共类型，而该类型即是结果。
6.5) 若 E2 与 E3 均为空指针常量，而至少有一个为 std::nullptr_t 类型，则结果类型为 std::nullptr_t。
6.6) 所有其他情况下，程序非良构。
本节未完成
原因：任何令此更可读，而不遗漏重点的机会？退一步来说，给每条一个一行的小示例会大有裨益

对于每对提升后的算术类型 L 和 R 并对于每个类型 P，其中 P 为指针、成员指针或有作用域枚举类型，下列函数签名在上述规则的步骤 5 参与重载决议：

LR operator?:(bool, L, R );
P operator?:(bool, P, P );

其中 LR 是 L 和 R 上进行的一般算术转换的结果。不能重载运算符 “?:”，这些函数签名只为重载决议的目的存在。

条件运算符的返回类型亦能作为二元类型特性 std::common_type 访问。

#include <string>
#include <iostream>
struct Node
{
    Node* next;
    int data;
    // 深复制的复制构造函数
    Node(const Node& other)
      : next(other.next ? new Node(*other.next) : NULL)
      , data(other.data)
    {}
    Node(int d) : next(NULL), data(d) {}
    ~Node() { delete next ; }
};
int main()
{
    // 简单的右值示例
    int n = 1 > 2 ? 10 : 11;  // 1 > 2 为 false，故 n = 11
    // 简单的左值示例
    int m = 10;
    (n == m ? n : m) = 7; // n == m 为 false，故 m = 7
    std::cout << "n = " << n << "\nm = " << m; // 输出结果
}

输出：

n = 11
m = 7

标准库

标准库中许多类都重载了 operator()，以使其能被用作函数对象。

operator() | 删除对象或数组 (std::default_delete<T> 的公开成员函数)
operator() | 返回两个实参的和 (std::plus<T> 的公开成员函数)
operator() | 返回两个实参的差 (std::minus<T> 的公开成员函数)
operator() | 返回两个实参的乘积 (std::multiplies<T> 的公开成员函数)
operator() | 返回第一个实参除以第二个实参的结果 (std::divides<T> 的公开成员函数)
operator() | 返回第一个实参除以第二个实参的余数 (std::modulus<T> 的公开成员函数)
operator() | 返回其实参的非 (std::negate<T> 的公开成员函数)
operator() | 检查实参是否相等 (std::equal_to<T> 的公开成员函数)
operator() | 检查实参是否不相等 (std::not_equal_to<T> 的公开成员函数)
operator() | 检查第一个实参是否大于第二个实参 (std::greater<T> 的公开成员函数)
operator() | 检查第一个实参是否小于第二个实参 (std::less<T> 的公开成员函数)
operator() | 检查第一个实参是否大于或等于第二个实参 (std::greater_equal<T> 的公开成员函数)
operator() | 检查第一个实参是否小于或等于第二个实参 (std::less_equal<T> 的公开成员函数)
operator() | 返回两个实参的逻辑 AND (std::logical_and<T> 的公开成员函数)
operator() | 返回两个实参的逻辑 OR (std::logical_or<T> 的公开成员函数)
operator() | 返回其实参的逻辑 NOT (std::logical_not<T> 的公开成员函数)
operator() | 返回两个实参的按位 AND 的结果 (std::bit_and<T> 的公开成员函数)
operator() | 返回两个实参的按位 OR 的结果 (std::bit_or<T> 的公开成员函数)
operator() | 返回两个实参的按位 XOR 的结果 (std::bit_xor<T> 的公开成员函数)
operator() | 返回对其所存储的谓词调用的结果的逻辑补 (std::unary_negate<Predicate> 的公开成员函数)
operator() | 返回对其所存储的谓词的调用的结果的逻辑补 (std::binary_negate<Predicate> 的公开成员函数)
operator() | 调用其所存储的函数 (std::reference_wrapper<T> 的公开成员函数)
operator() | 调用其目标 (std::function<R(Args...)> 的公开成员函数)
operator() | 用此 locale 的 collate 刻面以字典序比较两个字符串 (std::locale 的公开成员函数)
operator() | 比较两个 value_type 类型的值 (std::map<Key,T,Compare,Allocator>::value_compare 的公开成员函数)
operator() | 比较两个 value_type 类型的值 (std::multimap<Key,T,Compare,Allocator>::value_compare 的公开成员函数)
operator() | 执行函数 (std::packaged_task<R(Args...)> 的公开成员函数)
operator() (C++11) | 推进引擎状态并返回生成的值 (std::linear_congruential_engine<UIntType,a,c,m> 的公开成员函数)
operator() (C++11) | 生成分布中的下个随机数 (std::uniform_int_distribution<IntType> 的公开成员函数)

标准库中的任何类都不重载逗号运算符。boost 库将 operator, 用于 boost.assign、boost.spirit 和其他库。数据库访问库 SOCI 亦重载 operator,。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1550 | C++98 | 当另一操作数并非 void 时 ?: 中不允许有括号的 throw 表达式 | 接受有括号的 throw 表达式
CWG 1560 | C++98 | ?: 中的 void 操作数导致另一操作数上 无理由的左值到右值转换，始终产生右值 | 带 void 的 ?: 能为左值
CWG 1932 | C++14 | ?: 中缺失同类型位域 | 以底层类型处理
CWG 1895 | C++14 | 不明确弃置或不可访问的转换函数是否阻止 ?: 的转换， 且未考虑从基类到派生类纯右值的转换 | 与重载决议相似的方式处理

参阅

运算符优先级

运算符重载

常见运算符
赋值 自增
自减 		算术 逻辑 比较 成员访问 其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
? :
特殊运算符

static_cast 转换一个类型为另一相关类型
dynamic_cast 在继承层级中转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 转换类型到无关类型
C 风格转型 以 static_cast 、 const_cast 及 reinterpret_cast 的混合转换一个类型到另一类型
new 创建有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象，并释放其所拥有的内存区域
sizeof 查询类型的大小
sizeof... 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 查询表达式是否能抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)


C++ 運算元優先序

< cpp‎ | language

下表列出 C++ 運算元的優先序和结合性。各个運算元以優先序的降序从上至下列出。

優先序 | 運算元 | 描述 | 结合性
1 | :: | 作用域解析 | 从左到右
2 | a++ a-- | 后缀自增与自减
 | type() type{} | 函数风格转型
 | a() | 函数调用
 | a[] | 下标
 | . -> | 成员访问
3 | ++a --a | 前缀自增与自减 | 从右到左
 | +a -a | 一元加与减
 | ! ~ | 逻辑非和逐位非
 | (type) | C 风格转型
 | *a | 间接（解引用）
 | &a | 取址
 | sizeof | 取大小 [注 1]
 | co_await | await 表达式 (C++20)
 | new new[] | 动态内存分配
 | delete delete[] | 动态内存分配
4 | .* ->* | 成员指针 | 从左到右
5 | a*b a/b a%b | 乘法、除法与余数
6 | a+b a-b | 加法与减法
7 | << >> | 逐位左移与右移
8 | <=> | 三路比较運算元 (C++20 起)
9 | < <= | 分别为 < 与 ≤ 的关系運算元
 | > >= | 分别为 > 与 ≥ 的关系運算元
10 | == != | 分别为 = 与 ≠ 的相等性運算元
11 | a&b | 逐位与
12 | ^ | 逐位异或（互斥或）
13 | | | 逐位或（可兼或）
14 | && | 逻辑与
15 | || | 逻辑或
16 | a?b:c | 三元条件 [注 2] | 从右到左
 | throw | throw 運算元
 | co_yield | yield 表达式 (C++20)
 | = | 直接赋值（C++ 类默认提供）
 | += -= | 以和及差复合赋值
 | *= /= %= | 以积、商及余数复合赋值
 | <<= >>= | 以逐位左移及右移复合赋值
 | &= ^= |= | 以逐位与、异或及或复合赋值
17 | , | 逗号 | 从左到右
  1. ↑ sizeof 的操作数不能是 C 风格转型：表达式 sizeof (int) * p 无歧义地解释成 (sizeof(int)) * p ，而非 sizeof((int)*p)。
  2. ↑ 条件運算元中部（? 与 : 之间）的表达式分析为如同其带有括号：忽略其相对于 ?: 的優先序。

分析表达式时，列于上面表中某行的運算元，将比列于低于它的行中拥有较低優先序的任何運算元，更紧密地与其实参相绑定（如同用了括号）。例如，表达式 std::cout << a & b 和 *p++ 会被分析为 ( std::cout << a) & b 和 *(p++)，而非 std::cout << (a & b) 或 (*p)++。

拥有相同優先序的運算元以其结合性的方向与各参数绑定。例如表达式 a = b = c 会被分析为 a = (b = c) 而非 (a = b) = c，因为赋值具有从右到左结合性，但 a + b - c 会被分析为 (a + b) - c 而非 a + (b - c)，因为加法和减法具有从左到右结合性。

结合性规定对于一元運算元是冗余的，只为完备而给出：一元前缀運算元始终从右到左结合（delete ++*p 为 delete(++(*p))）而一元后缀運算元始终从左到右结合（a[1][2]++ 为 ((a[1])[2])++）。要注意，结合性对成员访问運算元是有意义的，即使在它们与一元后缀運算元组合时也是如此：a.b++ 会被分析为 (a.b)++ 而非 a.(b++)。

運算元優先序不受運算元重载影响。例如，std::cout << a ? b : c; 会被分析为 ( std::cout << a) ? b : c;，因为算术左移的優先序高于条件運算元。

注解

優先序和结合性是编译时概念，与求值顺序无关，后者是运行时概念。

标准自身不指定優先序。它们是从文法导出的。

表中并未包括 const_cast、static_cast、dynamic_cast、reinterpret_cast、typeid、sizeof...、noexcept 及 alignof，因为它们决不会有歧义。

一些運算元拥有代用写法（例如，&& 可为 and、|| 可为 or、! 可为 not 等）。

C 中，三元条件運算元拥有高于赋值運算元的優先序。因此，表达式 e = a < d ? a++ : a = d 在 C++ 中剖析成 e = ((a < d) ? (a++) : (a = d))，但在 C 中会由于 C 的语法或语义制约而编译失败。细节见对应的 C 页面。

参阅

常见运算符
赋值 自增
自减 		算术 逻辑 比较 成员访问 其他

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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
? :
特殊运算符

static_cast 转换一个类型为另一相关类型
dynamic_cast 在继承层级中转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 转换类型到无关类型
C 风格转型 以 static_cast 、 const_cast 及 reinterpret_cast 的混合转换一个类型到另一类型
new 创建有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象，并释放其所拥有的内存区域
sizeof 查询类型的大小
sizeof... 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 查询表达式是否能抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)


运算符重载

< cpp‎ | language

为用户定义类型的操作数定制 C++ 运算符。

语法

重载的运算符是具有特殊的函数名的函数：

operator 运算符 | (1) |
operator 类型 | (2) |
operator new operator new [] | (3) |
operator delete operator delete [] | (4) |
operator "" 后缀标识符 | (5) | (C++11 起)
operator co_await | (6) | (C++20 起)
运算符 - 下列运算符之一： + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= <=> (C++20 起) && || ++ -- , ->* -> ( ) [ ]
1) 重载的运算符；
2) 用户定义的转换函数；
3) 分配函数；
4) 解分配函数；
5) 用户定义字面量；
6) 用于 co_await 表达式的重载的 co_await 运算符。

重载的运算符

当表达式中出现某个运算符，且它至少有-一个操作数拥有类类型或枚举类型时，使用重载决议在具有与以下各项匹配的签名的函数中，确定所要调用的用户定义函数：

表达式 | 作为成员函数 | 作为非成员函数 | 示例
@a | (a).operator@ ( ) | operator@ (a) | ! std::cin 调用 std::cin.operator!()
a@b | (a).operator@ (b) | operator@ (a, b) | std::cout << 42 调用 std::cout.operator<<(42)
a=b | (a).operator= (b) | 不能是非成员 | 给定 std::string s; ， s = "abc"; 调用 s.operator=("abc")
a(b...) | (a).operator()(b...) | 不能是非成员 | 给定 std::random_device r; ， auto n = r(); 调用 r.operator()()
a[b] | (a).operator[](b) | 不能是非成员 | 给定 std::map <int, int> m; ， m[1] = 2; 调用 m.operator[](1)
a-> | (a).operator-> ( ) | 不能是非成员 | 给定 auto p = std::make_unique <S>(); p->bar() 调用 p.operator->()
a@ | (a).operator@ (0) | operator@ (a, 0) | 给定 std::vector <int>::iterator i = v.begin(); ， i++ 调用 i.operator++(0)
在这张表中，@ 是表示所有匹配运算符的占位符：@a 是所有前缀运算符，a@ 是除 -> 以外的所有后缀运算符，a@b 是除 = 以外的所有其他运算符。

另外，对于比较运算符 ==, !=, <, >, <=, >=, <=> ，重载决议也会考虑从 operator== 或 operator<=> 生成的重写候选。

 (C++20 起)

注意：对于重载的 co_await 、 (C++20 起) 用户定义转换函数、用户定义字面量、分配与解分配，可分别见其专题。

重载的运算符（但非内建运算符）可用函数记法进行调用：

std::string str = "Hello, ";
str.operator+=("world");                       // 同 str += "world";
operator<<(operator<<(std::cout, str) , '\n'); // 同 std::cout << str << '\n';
                                               // (C++17 起) 但定序不同

限制

  • 不能重载运算符 ::（作用域解析）、.（成员访问）、.*（通过成员指针的成员访问）及 ?:（三元条件）。
  • 不能创建新运算符，例如 **、<> 或 &|。
  • 不可能更改运算符的优先级、结合方向或操作数的数量。
  • 重载的运算符 -> 必须要么返回裸指针，要么（按引用或值）返回同样重载了运算符 -> 的对象。
  • 运算符 && 与 || 的重载失去短路求值。
  • &&、|| 和 ,（逗号）在被重载时失去其特殊的定序性质，并且即使不使用函数调用记法，也表现为与常规的函数调用相似。
 (C++17 前)

规范实现

除了上述限制外，语言对重载运算符的所作所为或返回类型（它不参与重载决议）上没有其他任何制约，但通常期待重载的运算符表现尽可能与内建运算符相似：期待 operator+ 对其实参进行相加而非相乘，期待 operator= 进行赋值，如此等等。期待相关的运算符之间的表现也相似（operator+ 与 operator+= 做同一类加法运算）。返回类型被期待使用该运算符的表达式限制：例如，令赋值运算符按引用返回，以使写出 a = b = c = d 可行，因为内建运算符允许这样做。

常见的重载运算符拥有下列典型、规范形式：[1]

赋值运算符

赋值运算符（operator=）有特殊性质：细节见复制赋值与移动赋值。

对规范的复制赋值运算符，期待它在自赋值时不进行操作，并按引用返回左操作数：

// 复制赋值
T& operator=(const T& other)
{
    // 防止自赋值
    if (this == &other)
        return *this;

    // 假设 *this 保有可重用资源，例如一个分配于堆的缓冲区 mArray
    if (size != other.size) {         // *this 中的存储不可复用
        delete[] mArray;              // 销毁 *this 中的存储
        mArray = nullptr;
        size = 0;                     // 在下一行抛出的情况下维持不变式
        mArray = new int[other.size]; // 分配 *this 中的存储
        size = other.size;
    }

    std::copy(other.mArray, other.mArray + other.size, mArray);
    return *this;
}

对规范的移动赋值，期待它令被移动对象遗留于合法状态（即有完好类不变式的状态），且在自赋值时要么不做任何事，要么至少遗留对象于合法状态，并以非 const 引用返回左操作数，而且是 noexcept 的：

T& operator=(T&& other) noexcept // 移动赋值
{
    if(this != &other) { // 自赋值时无操作（delete[]/size=0 也可以）
        delete[] mArray;                               // 释放 *this 中的资源
        mArray = std::exchange(other.mArray, nullptr); // 令 other 遗留于合法状态
        size = std::exchange(other.size, 0);
    }
    return *this;
}

在复制赋值不能从资源复用中受益的情形下（它不管理堆分配数组，且不含这么做的（可能传递的）成员，例如 std::vector 或 std::string 成员），有一种流行的便捷方式：复制并交换（copy-and-swap）赋值运算符，它按值接收形参（从而根据实参的值类别而同时支持复制和移动赋值），交换形参，并令析构函数进行清理。

// 复制赋值（复制并交换）
T& T::operator=(T other) noexcept // 调用复制/移动构造函数以构造 other
{
    std::swap(size, other.size); // 在 *this 与 other 间交换资源
    std::swap(mArray, other.mArray);
    return *this;
} // 调用 other 的析构函数以释放先前 *this 所保有的资源

这种形式自动提供强异常保证，但禁止资源复用。

流的提取与插入

接受 std::istream & 或 std::ostream & 作为左侧实参的 operator>> 与 operator<< 的重载，被称为插入与提取运算符。因为它们接收用户定义类型为右实参（a@b 中的 b），所以它们必须以非成员实现。

std::ostream& operator<<(std::ostream& os, const T& obj)
{
    // 向流写入 obj
    return os;
}
std::istream& operator>>(std::istream& is, T& obj)
{
    // 从流读取 obj
    if( /* 不能构造 T */ )
        is.setstate(std::ios::failbit);
    return is;
}

这些运算符有时实现为友元函数。

函数调用运算符

当用户定义的类重载了函数调用运算符 operator() 时，它就成为函数对象 (FunctionObject) 类型。

这种类型的对象能用于函数调用式的表达式：

// 此类型的对象表示一个变量的线性函数 a*x + b 。
struct Linear {
    double a, b;

    double operator()(double x) const {
        return a*x + b;
    }
};
int main() {
    Linear f{2, 1}; // 表示函数 2x + 1 。
    Linear g{-1, 0}; // 表示函数 -x 。
    // f 与 g 为能像函数一样使用的对象。

    double f_0 = f(0);
    double f_1 = f(1);

    double g_0 = g(0);
}

下面是不使用重载但拥有缺点的两个替代品。 1. 使用全局变量：

double a, b; // 坏：全局变量。
double linear(double x) {
    return a*x + b;
}
int main() {
    a = 2; b = 1;
    double f_0 = linear(0);
    double f_1 = linear(1);

    // 坏：需要重新赋值参数使得能够计算不同的函数：
    a = -1; b = 0;
    double g_0 = linear(0);
}

2. 使用额外参数：

double linear(double a, double b, double x) {
    return a*x + b;
}
int main() {
    double f_0 = linear(2, 1, 0);
    // 坏：必须重复输入同一参数：
    double f_1 = linear(2, 1, 1);

    double g_0 = linear(-1, 0, 0);
}

从 std::sort 到 std::accumulate 的许多标准算法都接受函数对象 (FunctionObject) 以定制其行为。operator() 没有特别值得注意的规范形式，此处演示其用法：

struct Sum
{
    int sum;
    Sum() : sum(0) { }
    void operator()(int n) { sum += n; }
};
Sum s = std::for_each(v.begin(), v.end(), Sum());

参阅 lambda 。

自增与自减

当表达式中出现后缀自增与自减时，以一个整数实参 0 调用用户定义函数（operator++ 或 operator--）。它典型地实现为 T operator++(int)，其中参数被忽略。后缀自增与自减运算符通常以前缀版本实现：

struct X
{
    // 前缀自增
    X& operator++()
    {
        // 实际上的自增在此进行
        return *this; // 以引用返回新值
    }

    // 后缀自增
    X operator++(int)
    {
        X old = *this; // 复制旧值
        operator++();  // 前缀自增
        return old;    // 返回旧值
    }

    // 前缀自减
    X& operator--()
    {
        // 实际上的自减在此进行
        return *this; // 以引用返回新值
    }

    // 后缀自减
    X operator--(int)
    {
        X old = *this; // 复制旧值
        operator--();  // 前缀自减
        return old;    // 返回旧值
    }
};}
};

尽管前自增/前自减的规范形式是返回引用的，但同任何运算符重载一样，它的返回类型是用户定义的；例如这些运算符对 std::atomic 的重载以值返回。

二元算术运算符

典型情况下，二元运算符都被实现为非成员以维持对称性（例如，将复数与整数相加时，如果 operator+ 是复数类型的成员函数，那么只有复数+整数能编译，而整数+复数不能）。因为对于每个二元算术运算符都存在对应的复合赋值运算符，所以二元运算符的规范形式是基于其对应的复合赋值实现的：

class X
{
 public:
  X& operator+=(const X& rhs) // 复合赋值（不必，但通常是成员函数，以修改私有成员）
  {
    /* 将 rhs 加到 *this 发生于此 */
    return *this; // 以引用返回结果
  }

  // 定义于类体内的友元是 inline 的，且在非 ADL 查找中被隐藏
  friend X operator+(X lhs,        // 按值传递 lhs 有助于优化链状的 a+b+c
                     const X& rhs) // 否则，两个形参都是 const 引用
  {
    lhs += rhs; // 复用复合赋值
    return lhs; // 以值返回结果（使用移动构造函数）
  }
};

比较运算符

标准（库的）算法（如 std::sort）和容器（如 std::set）在默认情况下期待 operator< 对于用户提供的类型有定义，并期待它实现严格弱序（从而满足比较 (Compare) 要求）。一种为结构体实现严格弱序的惯用方式是使用 std::tie 提供的字典序比较：

struct Record
{
    std::string name;
    unsigned int floor;
    double weight;
    friend bool operator<(const Record& l, const Record& r)
    {
        return std::tie(l.name, l.floor, l.weight)
             < std::tie(r.name, r.floor, r.weight); // 保持相同顺序
    }
};

典型地，一旦提供了 operator<，其他关系运算符就都能通过 operator< 来实现。

inline bool operator< (const X& lhs, const X& rhs){ /* 做实际比较 */ }
inline bool operator> (const X& lhs, const X& rhs){ return rhs < lhs; }
inline bool operator<=(const X& lhs, const X& rhs){ return !(lhs > rhs); }
inline bool operator>=(const X& lhs, const X& rhs){ return !(lhs < rhs); }

类似地，不相等运算符典型地通过 operator== 来实现：

inline bool operator==(const X& lhs, const X& rhs){ /* 做实际比较 */ }
inline bool operator!=(const X& lhs, const X& rhs){ return !(lhs == rhs); }

当提供了三路比较（如 std::memcmp 或 std::string::compare）时，所有六个双路比较运算符都能通过它表达：

inline bool operator==(const X& lhs, const X& rhs){ return cmp(lhs,rhs) == 0; }
inline bool operator!=(const X& lhs, const X& rhs){ return cmp(lhs,rhs) != 0; }
inline bool operator< (const X& lhs, const X& rhs){ return cmp(lhs,rhs) <  0; }
inline bool operator> (const X& lhs, const X& rhs){ return cmp(lhs,rhs) >  0; }
inline bool operator<=(const X& lhs, const X& rhs){ return cmp(lhs,rhs) <= 0; }
inline bool operator>=(const X& lhs, const X& rhs){ return cmp(lhs,rhs) >= 0; }

如果定义了 operator== ，那么编译器会自动生成不等运算符。类似地，如果定义了三路比较运算符 operator<=> ，那么编译器会自动生成四个关系运算符。如果定义 operator<=> 为预置，那么编译器会生成 operator== 和 operator<=> ：

struct Record
{
    std::string name;
    unsigned int floor;
    double weight;
    auto operator<=>(const Record&) = default;
};
// 现在能用 ==、!=、<、<=、> 和 >= 比较 Record

细节见默认比较。

 (C++20 起)

数组下标运算符

提供数组式访问并同时允许读写的用户定义类，典型地为 operator[] 定义两个重载：const 和非 const 变体：

struct T
{
          value_t& operator[](std::size_t idx)       { return mVector[idx]; }
    const value_t& operator[](std::size_t idx) const { return mVector[idx]; }
};

如果已知值类型是标量类型，那么 const 变体应按值返回。

当不希望或不可能直接访问容器元素，或者要区别左值（c[i] = v;）和右值（v = c[i];）的不同用法时，operator[] 可以返回代理。示例见 std::bitset::operator[]。

由于 C++23 前下标运算符仅能接收一个下标，为提供多维数组访问语义，例如实现三维数组访问 a[i][j][k] = x;，operator[] 必须返回到二维平面的引用，它必须拥有自己的 operator[] 并返回到一维行的引用，而行必须拥有返回到元素的引用的 operator[]。为避免这种复杂性，一些库选择代之以重载 operator()，使得 3D 访问表达式拥有 Fortran 式的语法 a(i, j, k) = x;。

C++23 起，operator[] 能接收多于一个下标。例如 3D 数组类的一个声明为 T& operator[]( std::size_t x, std::size_t y, std::size_t z); 的 operator[] 能直接访问元素。

逐位算术运算符

实现位掩码类型 (BitmaskType) 的规定的用户定义类和枚举，要求重载逐位算术运算符 operator&、operator|、operator^、operator~、operator&=、operator|= 及 operator^=，而且可重载位移运算符 operator<<、operator>>、operator>>= 及 operator<<=。规范实现通常遵循上述的二元算术运算符。

布尔取反运算符

有意用于布尔语境的用户定义类常重载运算符 operator! 。这种类也会提供用户定义转换函数 explicit operator bool()（标准库样例见 std::basic_ios），而 operator! 的受期待行为是返回 operator bool 的取反。 | (C++11 前)
由于内建运算符 ! 进行按语境到 bool 的转换，有意用于布尔语境的用户定义类可以只提供 operator bool 而无需重载 operator! 。 | (C++11 起)

罕有重载的运算符

下列运算符罕有重载：

  • 取址运算符 operator&。如果对不完整类型的左值应用一元 &，而完整类型声明了重载的 operator&，那么行为未定义 (C++11 前)运算符拥有内建含义还是调用运算符函数是未指明的 (C++11 起)。因为此运算符可能被重载，所以泛型库都用 std::addressof 取得用户定义类型的对象的地址。最为人熟知的规范重载的 operator& 是 Microsoft 类 CComPtrBase。在 boost.spirit 中可以找到该运算符在 EDSL 的使用案例。
  • 布尔逻辑运算符 operator&& 与 operator||。不同于内建版本，重载版本无法实现短路求值。而且不同于内建版本，它们也不会令左操作数的求值按顺序早于右操作数。 (C++17 前)标准库中，这些运算符仅由 std::valarray 重载。
  • 逗号运算符 operator,。不同于内建版本，重载版本不会令左操作数的求值按顺序早于右操作数。 (C++17 前)因为此运算符可能被重载，所以泛型库都用 a,void(),b 这种表达式取代 a,b，以对用户定义类型的表达式按顺序求值。boost 库在 boost.assign、boost.spirit 及几个其他库中使用 operator,。数据库访问库 SOCI 也重载了 operator,。
  • 通过成员指针的成员访问 operator->*。重载此运算符并没有特别缺点，但实践中少有使用。有人推荐这能作为智能指针接口的一部分，且实际上在 boost.phoenix 中的 actor 有实际用途。它在像 cpp.react 这样的 EDSL 中更常见。

示例

#include <iostream>

class Fraction
{
    int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
    int n, d;
public:
    Fraction(int n, int d = 1) : n(n/gcd(n, d)), d(d/gcd(n, d)) { }
    int num() const { return n; }
    int den() const { return d; }
    Fraction& operator*=(const Fraction& rhs)
    {
        int new_n = n * rhs.n/gcd(n * rhs.n, d * rhs.d);
        d = d * rhs.d/gcd(n * rhs.n, d * rhs.d);
        n = new_n;
        return *this;
    }
};
std::ostream& operator<<(std::ostream& out, const Fraction& f)
{
   return out << f.num() << '/' << f.den() ;
}
bool operator==(const Fraction& lhs, const Fraction& rhs)
{
    return lhs.num() == rhs.num() && lhs.den() == rhs.den();
}
bool operator!=(const Fraction& lhs, const Fraction& rhs)
{
    return !(lhs == rhs);
}
Fraction operator*(Fraction lhs, const Fraction& rhs)
{
    return lhs *= rhs;
}

int main()
{
   Fraction f1(3, 8), f2(1, 2), f3(10, 2);
   std::cout << f1 << " * " << f2 << " = " << f1 * f2 << '\n'
             << f2 << " * " << f3 << " = " << f2 * f3 << '\n'
             <<  2 << " * " << f1 << " = " <<  2 * f1 << '\n';
}

输出：

3/8 * 1/2 = 3/16
1/2 * 5/1 = 5/2
2 * 3/8 = 3/4

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1458 | 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
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
? :
特殊运算符

static_cast 转换一个类型为另一相关类型
dynamic_cast 在继承层级中转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 转换类型到无关类型
C 风格转型 以 static_cast 、 const_cast 及 reinterpret_cast 的混合转换一个类型到另一类型
new 创建有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象，并释放其所拥有的内存区域
sizeof 查询类型的大小
sizeof... 查询形参包的大小(C++11 起)
typeid 查询类型的类型信息
noexcept 查询表达式是否能抛出异常(C++11 起)
alignof 查询类型的对齐要求(C++11 起)

引用

  1. ↑ StackOverflow C++ FAQ 上的运算符重载


重载函数的地址

< cpp‎ | language

除了函数调用表达式之外，重载函数的名字还可以出现在下列 7 种发生重载决议的语境中：

1) 对象或引用 声明中的初始化器
2) 赋值运算符的右侧
3) 作为函数调用的实参
4) 作为用户定义运算符的实参
5) return 语句
6) 显式转型或 static_cast 的实参
7) 非类型模板实参

在每个语境中，重载函数的名字可以前附取址运算符 & 并且可以被一组冗余的括号所环绕。

在所有这些语境中，从重载集中选择的函数，是其类型与目标所期待的函数指针、函数引用或成员函数指针类型相匹配的函数，目标分别为：被初始化的对象或引用，赋值的左侧，函数或运算符的形参，函数的返回类型，转型的目标类型，以及模板形参的类型。

函数的形参类型和返回类型必须与目标严格匹配，不考虑隐式转换（例如，在初始化指向返回基类指针的函数的指针时，不会选择返回派生类指针的函数）。

如果函数名指名了某个函数模板，那么首先进行模板实参推导，且如果它成功，那么将会生成一个单独的模板特化并添加到所要考虑的重载集合中。从集合中丢弃所有不满足其关联约束的函数。 (C++20 起)如果集合中有多于一个函数与目标匹配，且至少一个函数是非模板，那么从考虑集合中去除模板特化。对于任何一对非模板函数，如果其中一个比另一个更受约束，那么从集合中丢弃受较少约束的函数。 (C++20 起)如果所有剩余候选者都是模板特化，那么当存在更特殊的模板特化时，移除较不特殊者。如果在各项移除之后还有多于一个候选者，那么程序非良构。

示例

int f(int) { return 1; }
int f(double) { return 2; }

void g( int(&f1)(int), int(*f2)(double) ) {}

template< int(*F)(int) >
struct Templ {};

struct Foo {
    int mf(int) { return 3; }
    int mf(double) { return 4; }
};

struct Emp {
    void operator<<(int (*)(double)) {}
};

int main()
{
    // 1. 初始化
    int (*pf)(double) = f; // 选择 int f(double)
    int (&rf)(int) = f; // 选择 int f(int)
    int (Foo::*mpf)(int) = &Foo::mf; // 选择 int mf(int)

    // 2. 赋值
    pf = nullptr;
    pf = &f; // 选择 int f(double)

    // 3. 函数实参
    g(f, f); // 为第一实参选择 int f(int)
             // 为第二实参选择 int f(double)

    // 4. 用户定义运算符
    Emp{} << f; // 选择 int f(double)

    // 5. 返回值
    auto foo = []() -> int (*)(int) {
        return f; // 选择 int f(int)
    };

    // 6. 转型
    auto p = static_cast<int(*)(int)>(f); // 选择 int f(int)

    // 7. 模板实参
    Templ<f> t;  // 选择 int f(int)
}

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 12.5 Address of overloaded function [over.over]
  • C++17 标准（ISO/IEC 14882:2017）：
  • 16.4 Address of overloaded function [over.over]
  • C++14 标准（ISO/IEC 14882:2014）：
  • 13.4 Address of overloaded function [over.over]
  • C++11 标准（ISO/IEC 14882:2011）：
  • 13.4 Address of overloaded function [over.over]
  • C++03 标准（ISO/IEC 14882:2003）：
  • 13.4 Address of overloaded function [over.over]
  • C++98 标准（ISO/IEC 14882:1998）：
  • 13.4 Address of overloaded function [over.over]


override 说明符(C++11 起)

< cpp‎ | language

指定一个虚函数覆盖另一个虚函数。

语法

如果使用标识符 override，那么它紧随成员函数声明或类定义内的成员函数定义语法中的声明符之后出现。

声明符 虚说明符序列(可选) 纯说明符(可选) | (1)
声明符 虚说明符序列(可选) 函数体 | (2)
1) 在成员函数声明中，override 可以在紧随声明符之后并在 纯说明符 之前（如有使用）的 虚说明符序列 中出现。
2) 在类定义内成员函数定义中，override 可以在紧随声明符之后并紧接 函数体 之前的 虚说明符序列 中出现。

两种情况中，如果使用 虚说明符序列 ，那么它必须是 override、final、final override 或 override final 之一。

解释

在成员函数的声明或定义中，override 说明符确保该函数为虚函数并覆盖某个基类中的虚函数。如果不是这样，那么程序为谬构（生成编译错误）。

override 是在成员函数声明符之后使用时拥有特殊含义的标识符：其他情况下它不是保留的关键词。

示例

struct A
{
    virtual void foo();
    void bar();
};

struct B : A
{
    void foo() const override; // 错误：B::foo 不覆盖 A::foo
                               // （签名不匹配）
    void foo() override; // OK：B::foo 覆盖 A::foo
    void bar() override; // 错误：A::bar 非虚
};

可能的输出：

main.cpp:9:10: 错误：'void B::foo() const' 标记为 'override'，但没有覆盖
    9 |     void foo() const override; // 错误：B::foo 不覆盖 A::foo
      |          ^~~
main.cpp:12:10: 错误：'void B::bar()' 标记为 'override'，但没有覆盖
   12 |     void bar() override; // Error: A::bar 非虚
      |          ^~~

参阅

final 说明符 (C++11) 声明不能被覆盖的方法


形参包 (C++11 起)

< cpp‎ | language

模板形参包是接受零个或更多个模板实参（非类型、类型或模板）的模板形参。函数形参包是接受零个或更多个函数实参的函数形参。

至少有一个形参包的模板被称作变参模板。

语法

模板形参包（在别名模版、类模板、变量模板及函数模板形参列表中出现）

类型 ... 包名(可选) | (1) |
typename|class ... 包名(可选) | (2) |
类型约束 ... 包名(可选) | (3) | (C++20 起)
template < 形参列表 > class ... 包名(可选) | (4) | (C++17 前)
template < 形参列表 > typename|class ... 包名(可选) | (4) | (C++17 起)

函数参数包（声明符的一种形式，在变参函数模板的函数形参列表中出现）

包名 ... 包形参名(可选) (5)

形参包展开（在变参模板体中出现）

模式 ... (6)
1) 可以有名字的非类型模板形参包
2) 可以有名字的类型模板形参包
3) 可以有名字的受约束的类型模板形参包
 (C++20 起)
4) 可以有名字的模板模板形参包
5) 可以有名字的函数形参包
6) 形参包展开：展开成零个或更多个 模式 的逗号分隔列表。模式必须包含至少一个形参包。

解释

变参类模板可以用任意数量的模板实参实例化：

template<class... Types> struct Tuple {};
Tuple<> t0;           // Types 不包含实参
Tuple<int> t1;        // Types 包含一个实参：int
Tuple<int, float> t2; // Types 包含两个实参：int 与 float
Tuple<0> error;       // 错误：0 不是类型

变参函数模板可以用任意数量的函数实参调用（模板实参通过模板实参推导推导）：

template<class... Types> void f(Types... args);
f();       // OK：args 不包含实参
f(1);      // OK：args 包含一个实参：int
f(2, 1.0); // OK：args 包含两个实参：int 与 double

在主类模板中，模板形参包必须是模板形参列表的最后一个形参。在函数模板中，模板参数包可以在列表中更早出现，只要其后的所有形参都可以从函数实参推导或拥有默认实参即可：

template<typename... Ts, typename U> struct Invalid; // 错误：Ts... 不在结尾

template<typename... Ts, typename U, typename=void>
void valid(U, Ts...);    // OK：能推导出 U
// void valid(Ts..., U); // 不能使用：Ts... 在此位置是不推导语境

valid(1.0, 1, 2, 3);     // OK：推导出 U 为 double，Ts 为 {int, int, int}

如果变参模板的每个合法的特化都要求空模板形参包，那么程序非良构，不要求诊断。

包展开

后随省略号且其中至少有一个形参包的名字至少出现了一次的模式会被展开成零个或更多个逗号分隔的模式实例，其中形参包的名字按顺序被替换成包中的各个元素：

template<class... Us> void f(Us... pargs) {}
template<class... Ts> void g(Ts... args)
{
    f(&args...); // “&args...” 是包展开
                 // “&args” 是它的模式
}
g(1, 0.2, "a"); // Ts... args 会展开成 int E1, double E2, const char* E3
                // &args... 会展开成 &E1, &E2, &E3
                // Us... 会展开成 int* E1, double* E2, const char** E3

如果两个形参包在同一模式中出现，那么它们同时展开而且长度必须相同：

template<typename...> struct Tuple {};
template<typename T1, typename T2> struct Pair {};

template<class... Args1> struct zip
{
    template<class... Args2> struct with
    {
        typedef Tuple<Pair<Args1, Args2>...> type;
        // Pair<Args1, Args2>... 是包展开
        // Pair<Args1, Args2> 是模式
    };
};

typedef zip<short, int>::with<unsigned short, unsigned>::type T1;
// Pair<Args1, Args2>... 会展开成
// Pair<short, unsigned short>, Pair<int, unsigned int>
// T1 是 Tuple<Pair<short, unsigned short>, Pair<int, unsigned>>

typedef zip<short>::with<unsigned short, unsigned>::type T2;
// 错误：包展开中的形参包包含不同长度

如果包展开内嵌于另一个包展开中，那么它所展开的是在最内层包展开出现的形参包，并且在外围（而非最内层）的包展开中必须提及其它形参包：

template<class... Args>
void g(Args... args)
{
    f(const_cast<const Args*>(&args)...);
    // const_cast<const Args*>(&args) 是模式，它同时展开两个包（Args 与 args）

    f(h(args...) + args...); // 嵌套包展开：
    // 内层包展开是 “args...”，它首先展开
    // 外层包展开是 h(E1, E2, E3) + args 它其次被展开
    // （成为 h(E1, E2, E3) + E1, h(E1, E2, E3) + E2, h(E1, E2, E3) + E3）
}

展开场所

展开所产生的逗号分隔列表按发生展开的各个场所可以是不同种类的列表：函数形参列表，成员初始化器列表，属性列表，等等。以下列出了所有允许的语境。

函数实参列表

包展开可以在函数调用运算符的括号内出现，此时省略号左侧的最大表达式或花括号初始化器列表是被展开的模式：

f(&args...);             // 展开成 f(&E1, &E2, &E3)
f(n, ++args...);         // 展开成 f(n, ++E1, ++E2, ++E3);
f(++args..., n);         // 展开成 f(++E1, ++E2, ++E3, n);
f(const_cast<const Args*>(&args)...);
// f(const_cast<const E1*>(&X1), const_cast<const E2*>(&X2), const_cast<const E3*>(&X3))
f(h(args...) + args...); // 展开成
// f(h(E1, E2, E3) + E1, h(E1, E2, E3) + E2, h(E1, E2, E3) + E3)

正式而言，函数调用表达式中的表达式列表被归类为初始化器列表，它的模式是初始化器子句，它是赋值表达式和花括号初始化器列表其中之一。

有括号初始化器

包展开可以在直接初始化器，函数式转型及其他语境（成员初始化器，new 表达式等）的括号内出现，这种情况下的规则与适用于上述函数调用表达式的规则相同：

Class c1(&args...);             // 调用 Class::Class(&E1, &E2, &E3)
Class c2 = Class(n, ++args...); // 调用 Class::Class(n, ++E1, ++E2, ++E3);
::new((void *)p) U(std::forward<Args>(args)...) // std::allocator::allocate

花括号包围的初始化器

在花括号初始化器列表（花括号包围的初始化器和其他花括号初始化器列表的列表，用于列表初始化和其他一些语境中）中，也可以出现包展开：

template<typename... Ts> void func(Ts... args)
{
    const int size = sizeof...(args) + 2;
    int res[size] = {1, args..., 2};
    // 因为初始化器列表保证顺序，所以这可以用来对包的每个元素按顺序调用函数：
    int dummy[sizeof...(Ts)] = {(std::cout << args, 0)...};
}

模板实参列表

包展开可以在模板实参列表的任何位置使用，前提是模板拥有与该展开相匹配的形参：

template<class A, class B, class... C> void func(A arg1, B arg2, C...arg3)
{
    container<A, B, C...> t1; // 展开成 container<A, B, E1, E2, E3>
    container<C..., A, B> t2; // 展开成 container<E1, E2, E3, A, B>
    container<A, C..., B> t3; // 展开成 container<A, E1, E2, E3, B>
}

函数形参列表

在函数形参列表中，如果省略号在某个形参声明中（无论它是否指名函数形参包（例如在 Args ... args中））出现，那么该形参声明是模式：

template<typename... Ts> void f(Ts...) {}
f('a', 1); // Ts... 会展开成 void f(char, int)
f(0.1);    // Ts... 会展开成 void f(double)

template<typename... Ts, int... N> void g(Ts (&...arr)[N]) {}
int n[1];
g<const char, int>("a", n); // Ts (&...arr)[N] 会展开成
                            // const char (&)[2], int(&)[1]

注意：在模式 Ts (&...arr)[N] 中，省略号是最内层的元素，而不是像所有其他包展开中一样是最后的元素。

注意：不能用 Ts (&...)[N]，因为 C++11 语法要求带括号的省略号形参拥有名字：CWG #1488。

模板形参列表

包展开可以在模板形参列表中出现：

template<typename... T> struct value_holder
{
    template<T... Values> // 会展开成非类型模板形参列表，
    struct apply {};      // 例如 <int, char, int(&)[5]>
};

基类说明符与成员初始化器列表

包展开可以用于指定类声明中的基类列表。通常这也意味着它的构造函数也需要在成员初始化器列表中使用包展开，以调用这些基类的构造函数：

template<class... Mixins>
class X : public Mixins...
{
public:
    X(const Mixins&... mixins) : Mixins(mixins)... {}
};

Lambda 捕获

包展开可以在 lambda 表达式的捕获子句中出现：

template<class... Args>
void f(Args... args)
{
    auto lm = [&, args...] { return g(args...); };
    lm();
}

sizeof... 运算符

sizeof... 也被归类为包展开：

template<class... Types>
struct count
{
    static const std::size_t value = sizeof...(Types);
};

动态异常说明

动态异常说明中的异常列表也可以是包展开：

template<class...X> void func(int arg) throw(X...)
{
    // ... 在不同情形下抛出不同的 X
}
 (C++17 前)

对齐说明符

包展开可以在关键词 alignas 所用的类型列表和表达式列表中使用。

属性列表

包展开可以在属性列表中使用，如 [[attributes...]]。例如：void [[attributes...]] function()

折叠表达式

在折叠表达式中，模式是不包含未展开的形参包的整个子表达式。

using 声明

在 using 声明中，省略号可以在声明器列表内出现，这对于从一个形参包进行派生时有用：

template <typename... bases>
struct X : bases...
{
    using bases::g...;
};
X<B, D> x; // OK：引入 B::g 与 D::g
 (C++17 起)

注解

本节未完成
原因：关于部分特化和其他访问单独元素方式的一些话？提及递归 vs 对数 vs 短路，例如折叠表达式

示例

下面的例子定义了类似 std::printf 的函数，并以一个值替换格式字符串中字符 % 的每次出现。

首个重载在仅传递格式字符串且无形参展开时调用。

第二个重载中分别包含针对实参头的一个模板形参和一个形参包，这样就可以在递归调用中只传递形参的尾部，直到它变为空。

Targs 是模板形参包而 Fargs 是函数形参包。

#include <iostream>

void tprintf(const char* format) // 基础函数
{
    std::cout << format;
}

template<typename T, typename... Targs>
void tprintf(const char* format, T value, Targs... Fargs) // 递归变参函数
{
    for (; *format != '\0'; format++)
    {
        if ( *format == '%' )
        {
            std::cout << value;
            tprintf(format + 1, Fargs...); // 递归调用
            return;
        }
        std::cout << *format;
    }
}

int main()
{
    tprintf("% world% %\n", "Hello", '!', 123);
    return 0;
}

输出：

Hello world! 123

参阅

函数模板
类模板
sizeof... | 查询形参包中的元素数量。
C 风格的变参函数
预处理器宏 | 也可以是变参的
折叠表达式


部分模板特化

< cpp‎ | language

允许为给定的模板实参的类别定制类模板或变量模板 (C++14 起)。

语法

template < 形参列表 > 类关键词 类头名 < 实参列表 > 声明 | (1) |
template < 形参列表 > 声明说明符序列 声明符 < 实参列表 > 初始化器(可选) | (2) | (C++14 起)

其中 类头名 标识先前声明的类模板 ，而 声明符 标识先前声明的变量模板 (C++14 起)。此声明必须与它所特化的主模板定义处于相同的命名空间中，或对于成员模板，处于相同的类作用域中。

例如，

template<class T1, class T2, int I>
class A {};             // 主模板

template<class T, int I>
class A<T, T*, I> {};   // #1：部分特化，其中 T2 是指向 T1 的指针

template<class T, class T2, int I>
class A<T*, T2, I> {};  // #2：部分特化，其中 T1 是指针

template<class T>
class A<int, T*, 5> {}; // #3：部分特化，其中 T1 是 int，I 是 5，T2 是指针

template<class X, class T, int I>
class A<X, T*, I> {};   // #4：部分特化，其中 T2 是指针

标准库中的部分特化的例子包括 std::unique_ptr，它对数组类型有部分特化。

实参列表

下列限制会应用到部分模板特化的 实参列表：

1) 实参列表不能与非特化的实参列表相同（它必须有所特化）：
template<class T1, class T2, int I> class B {};        // 主模板
template<class X, class Y, int N> class B<X, Y, N> {}; // 错误

此外，特化必须比主模板更特殊：

template<int N, typename T1, typename... Ts> struct B;
template<typename... Ts> struct B<0, Ts...> {}; // 错误：没有更特殊
 (C++11 起)
2) 实参列表中不能出现默认实参
3) 如果有实参是包展开，那么它必须是列表中最后的实参
4) 非类型实参表达式可以使用模板形参，只要形参在不推导语境之外至少出现一次（注意当前只有 clang 支持此特性）
template<int I, int J> struct A {};
template<int I> struct A<I+5, I*2> {};  // 错误：I 不可推导

template<int I, int J, int K> struct B {};
template<int I> struct B<I, I*2, 2> {}; // OK：首个形参可以推导
5) 非类型模板实参不能特化类型【依赖该特化的形参】的模板形参：
template<class T, T t> struct C {}; // 主模板
template<class T> struct C<T, 1>;   // 错误：1 的类型是 T，它依赖形参 T

template<int X, int (*array_ptr)[X]> class B {}; // 主模板
int array[5];
template<int X> class B<X,&array> {}; // 错误：实参类型 &array 是 int(*)[X]，依赖形参 X

名字查找

名字查找不会找到部分模板特化。只有在主模板被名字查找所找到时才会考虑它的部分特化。特别是使得主模板可见的 using 声明，也会使得部分特化可见：

namespace N
{
    template<class T1, class T2> class Z {}; // 部分特化
}
using N::Z; // 指代主模板

namespace N
{
    template<class T> class Z<T, T*> {};     // 部分特化
}
Z<int, int*> z; // 名字查找找到 N::Z（主模板），然后使用带 T = int 的部分特化

偏序

当实例化类模板或变量模板 (C++14 起)，且有部分特化可用时，编译器必须决定是继续使用主模板还是使用其中一个部分特化。

1) 如果只有一个特化与模板实参匹配，那么使用该特化
2) 如果有多于一个特化匹配，那么就用偏序规则确定哪个特化更加特殊。然后使用其中最特殊的特化（如果它不唯一，那么程序无法编译）
3) 如果没有匹配的特化，那么使用主模板
// 给定上面定义的模板 A
A<int, int, 1> a1;   // 没有匹配的特化，使用主模板
A<int, int*, 1> a2;  // 用部分特化 #1，(T=int, I=1)
A<int, char*, 5> a3; // 用部分特化 #3，(T=char)
A<int, char*, 1> a4; // 用部分特化 #4，(X=int, T=char, I=1)
A<int*, int*, 2> a5; // 错误：匹配 #2 (T=int, T2=int*, I=2) 和
                     //      匹配 #4 (X=int*, T=int, I=2) 都不比对方更特殊

非正式而言，“A 比 B 更特殊”的意思是“A 接受 B 所接受类型的子集”。

正式而言，为在部分特化之间建立“更特殊”关系，首先将其中每一个都转换成下列的虚设函数模板：

  • 第一个函数模板拥有与第一个部分特化相同的模板形参，且只有一个函数形参，它的类型是带有所有来自第一个部分特化的模板实参的类模板特化
  • 第二个函数模板拥有与第二个部分特化相同的模板形参，且只有一个函数形参，它的类型是带有所有来自第二个部分特化的模板实参的类模板特化。

然后，如同为函数模板重载所做的一样，对函数模板排行。

template<int I, int J, class T> struct X { }; // 主模板
template<int I, int J>          struct X<I, J, int>
{
    static const int s = 1;
}; // 部分特化 #1
// #1 的虚设函数模板是
// template<int I, int J> void f(X<I, J, int>); #A

template<int I>                 struct X<I, I, int>
{
    static const int s = 2;
}; // 部分特化 #2
// #2 的虚设函数模板是
// template<int I>        void f(X<I, I, int>); #B

int main()
{
    X<2, 2, int> x; // #1 和 #2 都匹配
// 函数模板的偏序处理：
// 从 #B 到 #A：从 void(X<U1, U1, int>) 到 void(X<I,J,int>)：推导 OK
// 从 #A 到 #B：从 void(X<U1, U2, int>) 到 void(X<I,I,int>)：推导失败
// #B 更特殊
// #2 是被实例化的特化
    std::cout << x.s << '\n'; // 打印 2
}

部分特化的成员

部分特化的成员的模板形参列表和模板实参列表必须与部分特化的形参列表和实参列表相匹配。

正如主模板的成员一样，它们只有在程序中使用时才需要定义。

部分特化的成员与主模板的成员无关。

部分特化的成员的显式（全）特化以与主模板的显式特化相同的方式声明。

template<class T, int I> // 主模板
struct A
{
    void f(); // 成员声明
};

template<class T, int I>
void A<T, I>::f() {}      // 主模板成员定义

// 部分特化
template<class T>
struct A<T, 2>
{
    void f();
    void g();
    void h();
};

// 部分特化的成员
template<class T>
void A<T, 2>::g() {}

// 部分特化的成员的显式（全）特化
template<>
void A<char, 2>::h() {}

int main()
{
    A<char, 0> a0;
    A<char, 2> a2;
    a0.f(); // OK，用主模板的成员定义
    a2.g(); // OK，用部分特化的成员定义
    a2.h(); // OK，用部分特化的成员的全特化定义
    a2.f(); // 错误：部分特化 A<T, 2> 中没有 f() 的定义（没有使用主模板）
}

如果主模板是另一个类模板的成员，那么它的部分特化也是外围类模板的成员。如果外围类模板被实例化，那么每个成员部分特化的声明也会被实例化（模板的所有其他成员的声明（但非其定义）也是以相同方式实例化的）

如果针对外围类模板的给定（隐式）特化进行主成员模板的显式（全）特化，那么对外围类模板的这个特化忽略该成员模板的部分特化。

如果针对外围类模板的给定（隐式）特化进行成员模板的某个部分特化的显式特化，那么对外围类模板的这个特化仍然考虑主成员模板及它的其他部分特化。

template<class T> struct A // 外围类模板
{
    template<class T2>
    struct B {};      // 主成员模板
    template<class T2>
    struct B<T2*> {}; // 成员模板的部分特化
};

template<>
template<class T2>
struct A<short>::B {}; // 主成员模板的全特化（忽略部分特化）

A<char>::B<int*> abcip;  // 使用部分特化 T2=int
A<short>::B<int*> absip; // 使用主模板的全特化（忽略部分特化）
A<char>::B<int> abci;    // 使用主模板

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1315 | C++98 | 不能在除标识表达式之外的非类型模板实参中使用模板形参 | 只要能推导，表达式就 OK
CWG 1495 | C++11 | 涉及形参包时规范不明确 | 特化必须更为特殊


PImpl

< cpp‎ | language

“指向实现的指针”或“pImpl”是一种 C++ 编程技巧[1]，它将类的实现细节从对象表示中移除，放到一个分离的类中，并以一个不透明的指针进行访问：

// widget.h（接口）
class widget {
    // 公开成员
private:
    struct impl;  // 实现类的前置声明
    // 一种实现示例：见下文中的其他设计选项和权衡
    std::experimental::propagate_const< // 转发 const 的指针包装器
        std::unique_ptr<                // 唯一所有权的不透明指针
            impl>> pImpl;               // 指向前置声明的实现类
};

// widget.cpp（实现）
struct widget::impl {
   // 实现细节
};

此技巧用于构造拥有稳定 ABI 的 C++ 库接口，及减少编译时依赖。

解释

因为类的私有数据成员参与其对象表示，影响大小和布局，也因为类的私有成员函数参与重载决议（这发生于成员访问检查之前），故对实现细节的任何更改都要求该类的所有用户重编译。

pImpl 打破了这种编译依赖；实现的改动不会导致重编译。结果是，若某个库在其 ABI 中使用 pImpl，则这个库的新版本可以更改实现，并且与旧版本保持 ABI 兼容。

得失权衡

pImpl 技法的替代方案是

  • 内联实现：私有成员和公开成员是同一类的成员
  • 纯虚类（OOP 工厂）：用户获得到某个轻量级或纯虚的基类的唯一指针，实现细节则处于覆盖其虚成员函数的派生类中。

编译防火墙

简单情况下，pImpl 和工厂方法都会打破实现和类接口的用户之间的编译时依赖。工厂方法创建对虚表的一次隐藏依赖，故而对虚函数进行重排序、添加或移除都会打破 ABI。pImpl 方法则没有隐藏的依赖，然而若实现类是类模板特化，则会丧失编译防火墙的优势：接口的用户必须观测到整个模板定义，以实例化正确的特化。这种情况下的一种常见的设计方案是，以避免参数化的方式对实现进行重构，这是《C++ 核心指南》的 T.61 勿过分参数化成员 和 T.84 使用非模板核心实现以提供 ABI 稳定的接口 的另一种使用情况。

举例来说，以下的类模板在其私有成员或 push_back 函数体内并未使用类型 T

template<class T>
class ptr_vector {
    void **beg, **end, **cap;
public:
    void push_back(T* p) {
        if (end == cap) reallocate(end - beg + 1);
        *end++ = p;
    }
};

因此，能按原样把私有成员传递给实现，而且 push_back 可以转发到同样未在接口使用 T 的实现：

// 头文件（ptr_vector.h）
class ptr_vector_base {
    struct impl; // 不依赖 T
    std::unique_ptr<impl> pImpl;
 protected:
    void push_back_fwd(void*);
    ... // 见特殊成员函数的实现部分
};
template<class T>
class ptr_vector : private ptr_vector_base {
public:
    void push_back(T* p) { push_back_fwd(p); }
};

// 源文件（ptr_vector.cpp）
struct ptr_vector_base::impl {
    void **beg, **end, **cap;
    void push_back(void* p) {
        if (end == cap) reallocate(end - beg + 1);
        *end++ = p;
    }
    void reallocate(size_t sz) { ... }
};
void ptr_vector_base::push_back_fwd(void* p) { pImpl->push_back(p); }
ptr_vector_base::ptr_vector_base() : pImpl(std::make_unique<impl>()) {}

运行时开销

  • 访问开销：pImpl 中，每次对私有成员函数的调用都通过一个指针间接进行。私有成员对公开成员的每次访问也都通过另一个指针间接进行。两个访问都跨翻译单元边界，从而只能被连接时优化优化掉。注意 OO 工厂对公开数据和实现细节的访问都要求跨翻译单元间接进行，而且由于虚派发而给予连接时优化器更少的机会。
  • 空间开销：pImpl 添加一个指针到公开组分，并且若有任何私有成员需要访问公开成员，则要么添加另一个指针到实现组分，要么每次调用要求它的私有成员时作为参数传递。若支持有状态自定义分配器，则必须一同存储分配器实例。
  • 生存期管理开销：pImpl（还有 OO 工厂）将实现对象放在堆上，这在构造与销毁时强加了显著的运行时开销。这可以部分地由自定义分配器所弥补，因为 pImpl（但非 OO 工厂）的大小在编译时是已知的。

另一方面，pImpl 类是对移动友好的；把大型的类重构为可移动 pImpl，可以提升对保有这些对象的容器进行操作的算法性能，即便可移动 pImpl 也具有额外的运行时开销：任何在被移动对象上容许使用并需要访问私有实现的公开成员函数必须进行空指针检查。

本节未完成
原因：微基准测试？)

维护开销

pImpl 的使用要求专用的翻译单元（只有头文件的库无法使用 pImpl），引入一个额外类，一组转发函数，且当使用分配器时，会暴露公开接口所使用的分配器的细节。

因为虚成员是 pImpl 的接口组分的一部分，故模拟 pImpl 意味着单独模拟接口组分。可测试的 pImpl 典型地被设计为允许通过可用接口达成完整的测试覆盖。

实现

由于接口类型的对象控制实现类型对象的生存期，指向实现的指针通常是 std::unique_ptr。

因为 std::unique_ptr 要求被指向类型在任何实例化删除器的语境中均为完整类型，故特殊成员函数必须为用户声明，且在实现类为完整的实现文件中类外定义。

因为当 const 成员通过非 const 成员指针调用函数时会调用实现函数的非 const 重载，故该指针必须包装于 std::experimental::propagate_const 或等价物中。

将所有私有数据成员和所有私有非虚成员函数置于实现类中。将所有公开、受保护和虚成员留于接口类中（对替代方案的讨论见 GOTW #100）。

若任何私有成员需要访问公开或受保护成员，则可以将指向接口的引用或指针作为参数传递给私有函数。另外，也可以将回溯引用作为实现类的一部分维持。

若有意使用非默认分配器以支持实现对象的分配，则可以利用任何常用的具分配器模式，包括缺省为 std::allocator 的分配器模板形参，以及类型为 std::pmr::memory_resource* 的构造函数实参。

示例

演示带有 const_propagation 的 pImpl，带有作为参数传递的回溯引用，不具分配器，并启用不带运行时检查的移动

#include <iostream>
#include <memory>
#include <experimental/propagate_const>

// 接口（widget.h）
class widget {
    class impl;
    std::experimental::propagate_const<std::unique_ptr<impl>> pImpl;
 public:
    void draw() const; // 公开 API，将被转发给实现
    void draw();
    bool shown() const { return true; } // 公开 API，实现必须调用之
    widget(int);
    ~widget(); // 定义于实现文件，其中 impl 是完整类型
    widget(widget&&); // 定义于实现文件
                      // 注意：在被移动的对象上调用 draw() 是 UB
    widget(const widget&) = delete;
    widget& operator=(widget&&); // 定义于实现文件
    widget& operator=(const widget&) = delete;
};

// 实现（widget.cpp）
class widget::impl {
    int n; // 私有数据
 public:
    void draw(const widget& w) const {
        if(w.shown()) // 对公开成员函数的此调用要求回溯引用
            std::cout << "drawing a const widget " << n << '\n';
    }
    void draw(const widget& w) {
        if(w.shown())
            std::cout << "drawing a non-const widget " << n << '\n';
    }
    impl(int n) : n(n) {}
};
void widget::draw() const { pImpl->draw(*this); }
void widget::draw() { pImpl->draw(*this); }
widget::widget(int n) : pImpl{std::make_unique<impl>(n)} {}
widget::widget(widget&&) = default;
widget::~widget() = default;
widget& widget::operator=(widget&&) = default;

// 用户（main.cpp）
int main()
{
    widget w(7);
    const widget w2(8);
    w.draw();
    w2.draw();
}

输出：

drawing a non-const widget 7
drawing a const widget 8

注解

本节未完成
原因：注意连接到值语义多态

引用

  1. ↑ GotW #100：编译防火墙


指针声明

< cpp‎ | language

声明指针或指向成员指针类型的变量。

语法

指针的声明是简单声明，其声明符拥有下列形式

* 属性(可选) cv限定符(可选) 声明符 | (1)
嵌套名说明符 * 属性(可选) cv限定符(可选) 声明符 | (2)
1) 指针声明符：声明 S* D; 将 D 声明为指向 嵌套名说明符 S 所确定类型的指针。
2) 成员指针声明符：声明 S C::* D; 将 D 声明为指向 C 的 嵌套名说明符 S 所确定类型的非静态数据成员的指针。
嵌套名说明符 | - | 名字和作用域解析运算符 :: 的序列
属性 | - | (C++11 起) 可选的属性列表
cv限定符 | - | 应用到被声明指针的 const/volatile 限定（而并非被指向类型，其限定是 声明说明符序列 的一部分）
声明符 | - | 除引用声明符之外的任意声明符（无指向引用的指针）。它可以是另一指针声明符（允许指向指针的指针）

不存在指向引用的指针和指向位域的指针。 当没有详述地提及“指针”时，通常不包含指向（非静态）成员的指针。

指针

指针类型的值是下列之一：

  • 指向对象或函数的指针（此时我们说该指针指向函数或对象），或
  • 对象末尾后指针，或
  • 该类型的空指针值，或
  • 无效指针值。

指向对象的指针表示该对象所占用的内存的首字节的地址。对象的末尾后指针表示，内存中该对象所占用的存储之后的首个字节的地址。

注意，两个表示同一地址的指针也可能拥有不同的值。

struct C {
   int x, y;
} c;

int* px = &c.x;   // px 的值为“指向 c.x 的指针”
int* pxe= px + 1; // pxe 的值为“ c.x 的尾后指针”
int* py = &c.y;   // py 的值为“指向 c.y 的指针”

assert(pxe == py); // == 测试两个指针是否表示相同地址
                   // 可能或可能不引发断言

*pxe = 1; // 即使未引发断言也是未定义行为

通过无效指针值间接寻址，和将无效指针值传递给解分配函数均拥有未定义行为。无效指针值的任何其他用法拥有由实现定义的行为。部分实现会将复制无效指针值的行为定义为造成由系统生成的运行时错误。

对象指针

对象指针能以应用于任何对象类型（包含另一指针类型）的表达式的取址运算符的返回值初始化：

int n;
int* np = &n; // 指向 int 的指针
int* const* npp = &np; // 指向【指向非 const int 的 const 指针】的非 const 指针

int a[2];
int (*ap)[2] = &a; // 指向含有 int 的数组的指针

struct S { int n; };
S s = {1};
int* sp = &s.n; // 指向作为 s 的成员的 int 的指针

对象指针可作为内建间接寻址运算符（一元 operator*）的操作数，并返回指代被指向对象的左值表达式：

int n;
int* p = &n;     // 指向 n 的指针
int& r = *p;     // 绑定到指代 n 的左值表达式的引用
r = 7;           // 在 n 存储 int 7
std::cout << *p; // 左值到右值隐式转换从 n 读取值

指向类对象的指针也能作为成员访问运算符 operator-> 和 operator->* 的左侧操作数。

由于存在数组到指针的隐式转换，可以以数组类型的表达式初始化指向数组首元素的指针：

int a[2];
int* p1 = a; // 指向数组 a 首元素 a[0]（一个 int）的指针

int b[6][3][8];
int (*p2)[3][8] = b; // 指向数组 b 首元素 b[0] 的指针，
                     // 被指者为含有 3 个【含有 8 个 int 元素的数组】元素的数组

由于存在指针的派生类到基类的隐式转换，可以以派生类的地址初始化指向基类的指针：

struct Base {};
struct Derived : Base {};

Derived d;
Base* p = &d;

如果 Derived 是多态的，那么这种指针可用于进行虚函数调用。

某些加法、减法、自增和自减运算符对于指向数组元素的指针有定义：这种指针满足老式随机访问迭代器 (LegacyRandomAccessIterator) 要求，并使得 C++ 库算法可以用于原始数组。

某些情况下，比较运算符对指针有定义：两个表示相同地址的指针比较相等，两个空指针值比较相等，指向同一数组中的元素的指针的比较与各元素的数组下标的比较方式相同，而指向拥有相同成员访问的非静态数据成员的指针以各成员的声明顺序进行比较。

多数实现也为随机来源的指针提供严格全序，例如将它们实现为连续虚拟地址空间中的地址。未能做到的实现（例如，其中并非指针的所有位都是内存地址的一部分因而在比较时必须忽略之，或者要求附带的计算，或者指针与整数并非一对一关系），为指针提供了具有此项保证的 std::less 特化。这使得可在关联容器（如 std::set 或 std::map）中使用所有随机来源的指针。

指向 void 的指针

指向任意类型对象的指针都可以被隐式转换成指向 void 的指针（可有 cv 限定）；不改变其值。逆向的转换要求 static_cast 或显式转型，并生成其原指针值：

int n = 1;
int* p1 = &n;
void* pv = p1;
int* p2 = static_cast<int*>(pv);
std::cout << *p2 << '\n'; // 打印 1

如果原指针指向某多态类型对象中的基类子对象，则可用 dynamic_cast 获得指向最终派生类型的完整对象的 void*。

指向 void 的指针与指向 char 的指针拥有相同的大小、表示及对齐。

void 指针被用来传递未知类型的对象，这在 C 接口中常见：std::malloc 返回 void*，std::qsort 期待接受两个 const void* 参数的用户提供回调。pthread_create 期待接受并返回 void* 的用户提供的回调。所有情况下，调用方负责在使用前将指针转型到正确类型。

函数指针

函数指针能以非成员函数或静态成员函数的地址初始化。由于存在函数到指针的隐式转换，取址运算符可以忽略：

void f(int);
void (*p1)(int) = &f;
void (*p2)(int) = f; // 与 &f 相同

不同于函数或函数的引用，函数指针是对象，从而能存储于数组、被复制、被赋值等。

语法 | 含义
int (* f)() | f 是一个指向一个【原型为 int func() 的函数】的指针。
int (* f())() | f 是一个无参且返回一个【指向一个原型为 int func() 的函数的指针】的函数。
int * f() | f 是一个无参且返回一个【指向 int 的指针】的函数。
int (* a[])() | a 是一个含有【指向原型为 int func() 的函数的指针】元素的数组。
int (* f())[] | f 是一个无参且返回一个【指向一个含有 int 元素的数组】的函数。
int (f[])() | 非法。函数无法作为数组元素。
int * const *(*g)(float) | g 是一个指向一个【原型为 int * const * func(float) 的函数】的指针， 该函数的返回值 int * const * 是一个指向一个【指向 int 的只读指针】的指针。

要了解更多关于函数，指针和函数指针的声明的信息，可参考声明。

函数指针可用作函数调用运算符的左侧操作数，这会调用被指向的函数：

int f(int n)
{
    std::cout << n << '\n';
    return n * n;
}

int main()
{
    int (*p)(int) = f;
    int x = p(7);
}

解引用函数指针生成标识被指向函数的左值：

int f();
int (*p)() = f;  // 指针 p 指向 f
int (&r)() = *p; // 将标识 f 的左值绑定到引用
r();             // 通过左值引用调用函数 f
(*p)();          // 通过函数左值调用函数 f
p();             // 直接通过指针调用函数 f

如果只有一个重载匹配指针类型，那么函数指针可以从可包含函数、函数模板特化及函数模板的一个重载集进行初始化（细节见重载函数的地址）：

template<typename T> T f(T n) { return n; }
double f(double n) { return n; }

int main()
{
    int (*p)(int) = f; // 实例化并选择 f<int>
}

相等比较运算符对于函数指针有定义（如果指向同一函数，那么它们比较相等）。

成员指针

数据成员指针

指向作为类 C 的成员的非静态数据成员 m 的指针，能准确地以表达式 &C::m 初始化。在 C 的成员函数中，如 &(C::m) 或 &m 这样的表达式不构成指向成员指针。

这种指针能用作成员指针访问运算符 operator.* 与 operator->* 的右侧操作数：

struct C { int m; };

int main()
{
    int C::* p = &C::m;          // 指向类 C 的数据成员 m
    C c = {7};
    std::cout << c.*p << '\n';   // 打印 7
    C* cp = &c;
    cp->m = 10;
    std::cout << cp->*p << '\n'; // 打印 10
}

指向一个可访问且无歧义的非虚基类的数据成员的指针，可以隐式转换成指向派生类的同一数据成员的指针：

struct Base { int m; };
struct Derived : Base {};

int main()
{
    int Base::* bp = &Base::m;
    int Derived::* dp = bp;
    Derived d;
    d.m = 1;
    std::cout << d.*dp << ' ' << d.*bp << '\n'; // 打印 1 1
}

相反方向的转换，即从指向派生类的数据成员的指针到指向无歧义非虚基类的数据成员的指针，允许由 static_cast 和显式转型来进行，即使基类并无该成员（但当用该指针访问时，最终派生类中有）：

struct Base {};
struct Derived : Base { int m; };

int main()
{
    int Derived::* dp = &Derived::m;
    int Base::* bp = static_cast<int Base::*>(dp);

    Derived d;
    d.m = 7;
    std::cout << d.*bp << '\n'; // OK：打印 7

    Base b;
    std::cout << b.*bp << '\n'; // 未定义行为
}

成员指针的被指向类型也可以是成员指针自身：成员指针可为多级，而且在每级可以有不同的 cv 限定。指针和成员指针的混合也可以多级组合：

struct A
{
    int m;
    // 指向非 const 成员的 const 指针
    int A::* const p;
};

int main()
{
    // 指向（A 的）数据成员的非 const 指针
    // 该成员是一个指向【（A 的）非 const 成员】的 const 指针
    int A::* const A::* p1 = &A::p;

    const A a = {1, &A::m};
    std::cout << a.*(a.*p1) << '\n'; // 打印 1

    // 指向一个【指向（A 的）非 const 成员的 const 指针】的常规非 const 指针
    int A::* const* p2 = &a.p;
    std::cout << a.**p2 << '\n'; // 打印 1
}

成员函数指针

指向作为类 C 的成员的非静态成员函数 f 的指针，能准确地以表达式 &C::f 初始化。在 C 的成员函数内，如 &(C::f) 或 &f，这样的表达式不构成成员函数指针。

这种指针可以用作成员指针访问运算符 operator.* 与 operator->* 的右操作数。其结果表达式只能用作函数调用运算符的左侧操作数：

struct C
{
    void f(int n) { std::cout << n << '\n'; }
};

int main()
{
    void (C::* p)(int) = &C::f; // 指向类 C 的成员函数 f 的指针
    C c;
    (c.*p)(1);                  // 打印 1
    C* cp = &c;
    (cp->*p)(2);                // 打印 2
}

指向基类的成员函数的指针可以隐式转换成指向派生类的同一成员函数的指针：

struct Base
{
    void f(int n) { std::cout << n << '\n'; }
};
struct Derived : Base {};

int main()
{
    void (Base::* bp)(int) = &Base::f;
    void (Derived::* dp)(int) = bp;
    Derived d;
    (d.*dp)(1);
    (d.*bp)(2);
}

相反方向的转换，即从指向派生类的成员函数的指针到指向无歧义非虚基类的成员函数的指针，允许由 static_cast 与显式转型来进行，即使基类没有该成员函数（但在用该指针进行访问时，最终派生类有）：

struct Base {};
struct Derived : Base
{
    void f(int n) { std::cout << n << '\n'; }
};

int main()
{
    void (Derived::* dp)(int) = &Derived::f;
    void (Base::* bp)(int) = static_cast<void (Base::*)(int)>(dp);

    Derived d;
    (d.*bp)(1); // OK：打印 1

    Base b;
    (b.*bp)(2); // 未定义行为
}

成员函数指针可用作回调或函数对象，通常在应用 std::mem_fn 或 std::bind 之后：

#include <iostream>
#include <string>
#include <algorithm>
#include <functional>

int main()
{
    std::vector<std::string> v = {"a", "ab", "abc"};
    std::vector<std::size_t> l;
    transform(v.begin(), v.end(), std::back_inserter(l),
              std::mem_fn(&std::string::size));
    for(std::size_t n : l)
        std::cout << n << ' ';
}

输出：

1 2 3

空指针

每个类型的指针都拥有一个特殊值，称为该类型的空指针值（null pointer value）。值为空的指针不指向对象或函数（解引用空指针是未定义行为），并与所有值同样为空的同类型指针比较相等。

为将指针初始化为空或赋空值给既存指针，可以使用空指针字面量 nullptr、空指针常量 NULL 或从整数值 ​0​ 的隐式转换。

零初始化和值初始化也初始化指针为其空值。

空指针可用于指示对象不存在（例如 function::target()），或作为其他错误条件的指示器（例如 dynamic_cast）。通常，接受指针实参的函数始终需要检查值是否为空，并以不同方式处理该情况（例如，delete 表达式在传递空指针时不做任何事）。

常量性

  • 如果指针声明中 限定符 在 * 之前出现，则它是 声明说明符序列 的一部分，并应用到被指向的对象。
  • 若指针声明中 限定符 在 * 之后出现，则它是 声明符 的一部分，并应用到所声明的指针。
语法 | 含义
const T* | 指向 const 对象的指针
T const* | 指向 const 对象的指针
T* const | 指向对象的 const 指针
const T* const | 指向 const 对象的 const 指针
T const* const | 指向 const 对象的 const 指针
// pc 是一个指向 const int 的非 const 指针
// cpc 是一个指向 const int 的 const 指针
// ppc 是一个指向【一个指向 const int 的非 const 指针】的非 const 指针
const int ci = 10, *pc = &ci, *const cpc = pc, **ppc;
// p 是一个指向非 const int 的非 const 指针
// cp 是一个指向非 const int 的 const 指针
int i, *p, *const cp = &i;

i = ci;    // OK：复制 const int 值到非 const int
*cp = ci;  // OK：能（通过 const 指针）修改非 const int
pc++;      // OK：能修改非 const 指针（指向 const int）
pc = cpc;  // OK：能修改非 const 指针（指向 const int）
pc = p;    // OK：能修改非 const 指针（指向 const int）
ppc = &pc; // OK：const int 的指针的地址是 const int 的指针的指针

ci = 1;    // 错误：不能修改 const int
ci++;      // 错误：不能修改 const int
*pc = 2;   // 错误：不能修改被指向的 const int
cp = &ci;  // 错误：不能修改 const 指针（指向非 const int）
cpc++;     // 错误：不能修改 const 指针（指向 const int）
p = pc;    // 错误：非 const int 的指针不能指向 const int
ppc = &p;  // 错误：const int 的指针的指针不能指向非 const int 的指针

通常，从一个多级指针到另一个的隐式转换遵循限定转换和指针比较运算符中所描述的规则。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 73 | C++98 | 指向对象的指针与指向数组尾后的指针无法比较相等（即使地址相同） | 对非空非函数指针比较它们表示的地址

参阅


标点

< cpp‎ | language

{ }

  • 在 class/struct 或 union 定义中分隔成员说明。
  • 在 enum 定义中分隔枚举项列表。
  • 分隔复合语句。复合语句可能是下列构造的一部分
  • 函数定义
  • try 块或 catch 子句
  • 函数 try 块
  • lambda 表达式 (C++11 起)
  • 在初始化中分隔初始化器。这种初始化被称为列表初始化。 (C++11 起)
  • 在命名空间定义中分隔命名空间体。
  • 在语言链接说明中分隔声明。
  • 在 requires 表达式中分隔要求。(C++20 起)
  • 在复合要求中分隔表达式。(C++20 起)
  • 在导出声明中分隔声明。(C++20 起)

[ ]

  • 下标运算符；运算符重载中 operator[] 的一部分。
  • 声明或类型标识（例如在 new 表达式中）中数组声明符的一部分。
  • 运算符重载（分配函数）中 new[] 运算符的一部分。
  • delete 表达式及运算符重载（解分配函数）中 delete[] 运算符的一部分。
  • 在 lambda 表达式中分隔捕获。(C++11 起)
  • 在属性说明符中分隔属性。(C++11 起)
  • 在结构化绑定声明中分隔标识符列表。(C++17 起)

#

  • 引入预处理指令。
  • 字符串化的预处理运算符。

##

  • 粘贴记号的预处理运算符。

( )

  • 在表达式中指示分组。
  • 函数调用运算符；运算符重载中 operator() 的一部分。
  • 在函数风格转型中分隔表达式/初始化器。
  • 在 static_cast、 const_cast、 reinterpret_cast 或 dynamic_cast 中分隔表达式。
  • 在 typeid、 sizeof 、 sizeof...、 alignof 或 noexcept (C++11 起) 表达式中分隔操作数。
  • 在布置 new 表达式中分隔布置实参。
  • 在 new 表达式中可选地分隔类型标识。
  • 在 new 表达式中分隔初始化器。
  • 在 C 风格转型中分隔类型标识。
  • 在声明或类型标识中指示分组。
  • 在下列构造中分隔形参列表
  • 函数声明符（在声明或类型标识）中
  • lambda 表达式 (C++11 起)
  • 用户定义推导指引 (C++17 起)
  • requires 表达式 (C++20 起)
  • 在直接初始化中分隔初始化器。
  • 在 asm 声明中分隔字符串字面量。
  • 在成员初始化器列表中分隔属于基类或成员的初始化器。
  • 在 if （包括 constexpr if） (C++17 起)、 switch、 while、 do-while 或 for （包括基于范围的 for） (C++11 起)语句中分隔控制子句。
  • 在 catch 子句中分隔形参声明。
  • 在仿函数宏定义中分隔宏形参。
  • defined、 __has_include (C++17 起)、 __has_cpp_attribute (C++20 起) 预处理运算符的一部分。
  • 在 static_assert 声明中分隔操作数。(C++11 起)
  • 在 decltype 说明符、 noexcept 说明符、 alignas 说明符、 条件性 explicit 说明符 (C++20 起) 中分隔操作数。(C++11 起)
  • 在属性中分隔属性实参。(C++11 起)
  • decltype(auto) 说明符的一部分。(C++14 起)
  • 分隔折叠表达式。(C++17 起)
  • 变参数宏定义中 __VA_OPT__ 替换的一部分。(C++20 起)

;

  • 指示以下构造的末尾
  • 语句（包括 for 语句的初始化语句）
  • 声明或成员声明
  • 模块声明、导入声明、全局模块片段器引入或私有模块片段引入器(C++20 起)
  • 要求 (C++20 起)
  • 分隔 for 语句的第二与第三子句。

:

  • 条件运算符的一部分。
  • 标签声明的一部分。
  • 在类定义的类头中引入基子句。
  • 成员说明中访问说明符的一部分。
  • 位域成员声明中引入宽度。
  • 构造函数定义中引入成员初始化器列表。
  • 基于范围的 for 语句中分隔范围声明与范围初始化器。(C++11 起)
  • 引入枚举基，它指定枚举的底层类型。(C++11 起)
  • 在属性说明符中分隔属性 using 前缀与属性列表。(C++17 起)
  • 在模块声明或模块划分的导入声明中引入模块划分名。(C++20 起)
  • 私有模块片段引入器（module :private;）的一部分。(C++20 起)

...

  • 函数声明符或 lambda 表达式 (C++11 起)或用户定义推导指引 (C++17 起)中形参列表的一部分，标识变参数函数.
  • 在 catch 子句中标识万应处理。
  • 在宏定义中标识变参数宏。(C++11 起)
  • 指示包声明与展开。(C++11 起)

?

  • 条件运算符的一部分。

::

  • 下列构造中的作用域解析运算符
  • 有限定名
  • 成员指针声明
  • new 或 delete 表达式，指示仅查找全局分配或解分配函数
  • 在属性中指示属性作用域。(C++11 起)
  • 嵌套命名空间定义的一部分。(C++17 起)

.

  • 成员访问运算符。
  • 在聚合初始化中引入指派符。(C++20 起)
  • 模块名或模块划分名的一部分。(C++20 起)

.*

  • 成员指针访问运算符。

->

  • 成员访问运算符；运算符重载中 operator-> 的一部分。
  • 在函数声明符或 lambda 表达式中引入尾随返回类型。(C++11 起)
  • 在用户定义推导指引中引入结果类型。(C++17 起)
  • 在复合要求中引入返回类型要求。(C++20 起)

->*

  • 成员指针访问运算符；运算符重载中 operator->* 的一部分。

~

  • 一元补运算符（又称逐位非运算符）；运算符重载中 operator~ 的一部分。
  • 指名析构函数或伪析构函数的标识符的一部分。

!

  • 逻辑非运算符；运算符重载中 operator! 的一部分。
  • consteval if 语句的反向变体的一部分。(C++23 起)

+

  • 一元加运算符；运算符重载中 operator+ 的一部分。
  • 二元加运算符；运算符重载中 operator+ 的一部分。

-

  • 一元减运算符；运算符重载中 operator- 的一部分。
  • 二元减运算符；运算符重载中 operator- 的一部分。

*

  • 间接运算符；运算符重载中 operator* 的一部分。
  • 乘运算符；运算符重载中 operator* 的一部分。
  • 声明符中或类型标识中的指针运算符或成员指针运算符
  • Lambda 捕获列表中 *this 的一部分，以按复制捕获当前对象。(C++17 起)

/

  • 除运算符；运算符重载中 operator/ 的一部分。

%

  • 模运算符；运算符重载中 operator% 的一部分.

^

  • 逐位异或运算符；运算符重载中 operator^ 。

&

  • 取地址运算符；运算符重载中 operator& 的一部分。
  • 逐位与运算符；运算符重载中 operator& 的一部分。
  • 声明符中或类型标识中的左值引用运算符。
  • 在 lambda 捕获中指示按引用捕获。(C++11 起)
  • 成员函数声明中的引用限定符。(C++11 起)

|

  • 逐位或运算符；运算符重载中 operator| 的一部分。

=

  • 简单赋值运算符；运算符重载中 operator= 的一部分，它可能是特殊成员函数（复制赋值运算符 或移动赋值运算符 (C++11 起)）。
  • 在初始化中指示复制初始化 或复制列表初始化 (C++11 起)。
  • 在函数声明中引入默认实参。
  • 在模板形参列表中引入默认模板实参。
  • 在命名空间别名定义中分隔别名与别名指代的命名空间。
  • 在枚举定义中引入枚举项的值。
  • 纯虚函数声明中纯说明符的一部分。
  • lambda 捕获中的捕获预置符，指示按复制捕获。(C++11 起)
  • 函数定义中的预置定义（=default;）或被删除定义（=delete;）。(C++11 起)
  • 在类型别名声明中分隔别名与别名指代的类型。(C++11 起)
  • 在概念定义中分隔概念名与约束表达式。(C++20 起)

+=

  • 复合赋值运算符；运算符重载中 operator+= 的一部分。

-=

  • 复合赋值运算符；运算符重载中 operator-= 的一部分。

*=

  • 复合赋值运算符；运算符重载中 operator*= 的一部分。

/=

  • 复合赋值运算符；运算符重载中 operator/= 的一部分。

%=

  • 复合赋值运算符；运算符重载中 operator%= 的一部分。

^=

  • 复合赋值运算符；运算符重载中 operator^= 的一部分。

&=

  • 复合赋值运算符；运算符重载中 operator&= 的一部分。

|=

  • 复合赋值运算符；运算符重载中 operator|= 的一部分。

==

  • 相等运算符；运算符重载中 operator== 的一部分。

!=

  • 不相等运算符；运算符重载中 operator!= 的一部分。

<

  • 小于运算符；运算符重载中 operator< 的一部分。
  • 在 static_cast、 const_cast、 reinterpret_cast 或 dynamic_cast 中引入类型标识。
  • 引入模板实参列表。
  • 在以下构造中引入模板形参列表
  • 模板声明
  • 部分特化
  • lambda 表达式 (C++20 起)
  • 模板特化声明中 template<> 的一部分。
  • 指示下列构造中的头文件名
  • #include 指令
  • __has_include 预处理表达式 (C++17 起)
  • import 声明 (C++20 起)

>

  • 大于运算符；运算符重载中 operator> 的一部分。
  • 在 static_cast、 const_cast、 reinterpret_cast 或 dynamic_cast 中指示类型标识的末尾。
  • 指示模板实参列表的末尾。
  • 在以下构造中指示模板形参列表的末尾
  • 模板声明
  • 部分特化
  • lambda 表达式 (C++20 起)
  • 模板特化声明中 template<> 的一部分。
  • 指示下列构造中头文件名的末尾
  • #include 指令
  • __has_include 预处理表达式 (C++17 起)
  • import 声明 (C++20 起)

<=

  • 小于或等于运算符；运算符重载中 operator<= 的一部分。

>=

  • 大于或等于运算符；运算符重载中 operator>= 的一部分。

<=> (C++20 起)

  • 三路比较（飞船）运算符；运算符重载中 operator<=> 的一部分。

&&

  • 逻辑与运算符；运算符重载中 operator&& 的一部分。
  • 声明符中或类型标识中的右值引用运算符。(C++11 起)
  • 成员函数声明中的引用限定符。(C++11 起)

||

  • 逻辑或运算符；运算符重载中 operator|| 的一部分。

<<

  • 移位运算符；运算符重载（诸位运算符或流插入运算符）中 operator<< 的一部分。

>>

  • 移位运算符；运算符重载（诸位运算符或流提取运算符）中 operator>> 的一部分。
  • 在 static_cast、 const_cast、 reinterpret_cast 或 dynamic_cast、模板实参列表或模板形参列表中能被重新分析成两个 > 。(C++11 起)

<<=

  • 复合赋值运算符；运算符重载中 operator<<= 的一部分。

>>=

  • 复合赋值运算符；运算符重载中 operator>>= 的一部分。

++

  • 自增运算符；运算符重载中 operator++ 的一部分。

--

  • 自减运算符；运算符重载中 operator-- 的一部分。

,

  • 逗号运算符；运算符重载中 operator, 的一部分。
  • 下列构造中的列表分隔符
  • 声明中的声明符列表
  • 初始化中的初始化器列表
  • 布置 new 中的布置实参列表
  • 函数调用表达式中的实参列表
  • 多实参下标表达式中的实参列表(C++23 起)
  • 枚举声明中的枚举项列表
  • 类声明中的基类列表
  • 构造函数定义中的成员初始化器列表
  • 函数形参列表
  • 模板形参列表
  • 模板实参列表
  • 仿函数宏定义中的宏形参列表
  • lambda 捕获列表(C++11 起)
  • 属性列表(C++11 起)
  • using 声明 中的声明符列表(C++17 起)
  • 结构化绑定声明中的标识符列表(C++17 起)
  • 在 static_assert 声明中分隔参数。(C++11 起)

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 5.12 Operators and punctuators [lex.operators]
  • C++17 标准（ISO/IEC 14882:2017）：
  • 5.12 Operators and punctuators [lex.operators]
  • C++14 标准（ISO/IEC 14882:2014）：
  • 2.13 Operators and punctuators [lex.operators]
  • C++11 标准（ISO/IEC 14882:2011）：
  • 2.13 Operators and punctuators [lex.operators]
  • C++03 标准（ISO/IEC 14882:2003）：
  • 2.12 Operators and punctuators [lex.operators]
  • C++98 标准（ISO/IEC 14882:1998）：
  • 2.12 Operators and punctuators [lex.operators]

参阅

替用表示 某些运算符的替用拼写


有限定的名字查找

< cpp‎ | language

出现在作用域解析操作符 :: 右边的名字是限定名（参阅有限定的标识符）。 限定名可能代表的是：

  • 类的成员（包括静态和非静态函数、类型和模板等）
  • 命名空间的成员（包括其它的命名空间）
  • 枚举项

若 :: 左边为空，则查找过程仅会考虑全局命名空间作用域中作出（或通过 using 声明引入到全局命名空间中）的声明。这使得即使被局部声明隐藏的名字也能够被访问：

#include <iostream>
int main() {
  struct std{};
  std::cout << "fail\n"; // 错误：对 'std' 的无限定查找找到 struct
  ::std::cout << "ok\n"; // 正确： ::std 找到命名空间 std
}

只有完成对 :: 左边的名字的查找（除非左边所用的是 decltype 表达式或左边为空），才能对其右边的名字进行名字查找。该左侧查找可以是有限定或无限定的，取决于这个名字左边是否有另一个 ::，但其仅考虑命名空间、类类型、枚举和能特化为类型的模板：

struct A {
  static int n;
};
int main() {
  int A;
  A::n = 42;    // 正确：对 :: 左边的 A 的无限定查找忽略变量
  A b;          // 错误：对 A 的无限定查找找到了变量 A
}

当限定名为声明符时，对同一声明符中随该限定名之后，而非其之前的名字的无限定查找，是在成员的所在类或命名空间的作用域中进行的：

class X { };
constexpr int number = 100;
struct C {
  class X { };
  static const int number = 50;
  static X arr[number];
};
X C::arr[number], brr[number];    // 错误：对 X 的查找找到 ::X 而不是 C::X
C::X C::arr[number], brr[number]; // OK ： arr 的大小是 50 ， brr 的大小是 100

若 :: 后跟字符 ~ 再跟着一个标识符（也就是说指定了析构函数或伪析构函数），那么该标识符将在与 :: 左边的名字相同的作用域中查找。

struct C { typedef int I; };
typedef int I1, I2;
extern int *p, *q;
struct A { ~A(); };
typedef A AB;
int main() {
  p->C::I::~I(); // ~ 之后的名字 I 在 :: 前面的 I 的同一个作用域中查找
                 //（也就是说，在 C 的作用域中查找，因此查找结果是 C::I ）
  q->I1::~I2();  // 名字 I2 在 I1 的同一个作用域中查找，
                 // 也就是说从当前的作用域中查找，因此查找结果是 ::I2
  AB x;
  x.AB::~AB(); // ~ 之后的名字 AB 在 :: 前面的 AB 的同一个作用域中查找
               // 也就是说从当前的作用域中查找，因此查找结果是 ::AB
}

枚举项

若对左边的名字的查找结果是枚举（无论是有作用域还是无作用域），右边名字的查找结果必须是属于该枚举的一个枚举项，否则程序非良构。

 (C++11 起)

类成员

若对左边的名字的查找结果是某个类、结构体或联合体的名字，则 :: 右边的名字在该类、结构体或联合体的作用域中进行查找（因此可能找到该类或其基类的成员的声明），但有以下例外情况：

  • 析构函数按如上所述进行查找（即在 :: 左边的名字的作用域中查找）
  • 用户定义转换函数名中的转换类型标识首先在该类类型的作用域中查找。若未找到，则在当前作用域中查找该名字。
  • 模板实参中使用的名字，在当前作用域中查找（而非在模板名的作用域中查找）
  • using 声明中的名字，还考虑在当前作用域中声明的变量、数据成员、函数或枚举项所隐藏的类或枚举名
本节未完成
原因：上述内容的小示例

若 :: 右边所指名的是和其左边相同的类，则右边的名字表示的是该类的构造函数。这种限定名仅能用在构造函数的声明以及引入继承构造函数的 using 声明中。在所有忽略函数名的查找过程中（即在查找 :: 左边的名字，或查找详述类型说明符或基类说明符中的名字时），则将同样的语法解释成注入类名：

struct A { A(); };
struct B : A { B(); };
A::A() { } // A::A 指定的是构造函数，用于声明
B::B() { } // B::B 指定的是构造函数，用于声明
B::A ba;   // B::A（在 B 的作用域中查找）指定的是类型 A
A::A a;    // 错误：A::A 不是类型

struct A::A a2; // 正确：详述类型说明符中的查找是忽略函数的，
                // 因此 A::A 在 A 的作用域中查找，于是指定的是类 A
                // （亦即其注入类名）

有限定名字查找可用来访问被嵌套声明或被派生类隐藏了的类成员。对有限定的成员函数的调用将不得是虚调用：

struct B { virtual void foo(); };
struct D : B { void foo() override; };
int main()
{
    D x;
    B& b = x;
    b.foo(); // 调用 D::foo（虚调用派发）
    b.B::foo(); // 调用 B::foo（静态调用派发）
}

命名空间的成员

若 :: 左边的名字代表的是命名空间，或者 :: 左边为空（这种情况代表全局命名空间），那么 :: 右边的名字就在这个命名空间的作用域中进行查找，但有以下例外：

  • 在模板实参中使用的名字在当前作用域中查找
namespace N {
   template<typename T> struct foo {};
   struct X {};
}
N::foo<X> x; // 错误：X 查找结果为 ::X 而不是 N::X

在命名空间 N 中进行有限定查找时，首先要考虑处于 N 之中的所有声明，以及处于 N 的内联命名空间成员（并且传递性地包括它们的内联命名空间成员）之中的所有声明。如果这个集合中没有找到任何声明，则再考虑在 N 和 N 的所有传递性的内联命名空间成员中发现的所有using 指令所指名的命名空间之中的声明。这条规则是递归实施的：

int x;
namespace Y {
  void f(float);
  void h(int);
}
namespace Z {
  void h(double);
}
namespace A {
  using namespace Y;
  void f(int);
  void g(int);
  int i;
}
namespace B {
  using namespace Z;
  void f(char);
  int i;
}
namespace AB {
  using namespace A;
  using namespace B;
  void g();
}
void h()
{
  AB::g();  // 在 AB 中查找，找到了 AB::g 并且选择了 AB::g(void)
            // （并未在 A 和 B 中查找）
  AB::f(1); // 首先在 AB 中查找，未能找到 f
            // 然后再在 A 和 B 中查找
            // 找到了 A::f 和 B::f（但并未在 Y 中查找，因而不考虑 Y::f）
            // 重载决议选中 A::f(int)
  AB::x++;    // 首先在 AB 中查找，未能找到 x
              // 然后再在 A 和 B 中查找。未能找到 x
              // 然后再在 Y 和 Z 中查找。还是没有 x：这是一个错误
  AB::i++;  // 在 AB 中查找，未能找到 i
            // 然后再在 A 和 B 中查找。找到了 A::i 和 B::i：这是一个错误
  AB::h(16.8);  // 首先在 AB 中查找：未能找到 h
                // 然后再在 A 和 B 中查找。未能找到 h
                // 然后再在 Y 和 Z 中查找。
                // 找到了 Y::h 和 Z::h。重载决议选中 Z::h(double)
}

同一个声明允许被多次找到：

namespace A { int a; }
namespace B { using namespace A; }
namespace D { using A::a; }
namespace BD {
  using namespace B;
  using namespace D;
}
void g()
{
  BD::a++; // OK ： 通过 B 和 D 找到同一个 A::a
}
本节未完成
原因：N4861 6.5.3.2[namespace.qual] 中的剩余内容，尝试缩短其示例

参阅

  • 无限定名字查找
  • 作用域
  • 实参依赖查找
  • 模板实参推导
  • 重载决议


基于范围的 for 循环 (C++11 起)

< cpp‎ | language

在一个范围上执行 for 循环。

用作对范围中的各个值（如容器中的所有元素）进行操作的传统 for 循环的更加可读的等价版本。

语法

属性(可选) for ( 初始化语句(可选)范围变量声明 : 范围表达式 ) 循环语句
属性 - 任意数量的属性
初始化语句 - (C++20 起) 以下之一：
  • 表达式语句（可以是空语句“;”）
  • 简单声明，典型地为带初始化器的变量声明，但它可以声明任意多个变量，或者是结构化绑定声明
  • 别名声明
 (C++23 起)
注意，所有 初始化语句 必然以分号 ; 结尾，因此它经常被非正式地描述为后随分号的表达式或声明。
范围变量声明 - 一个具名变量的声明，它的类型是由 范围表达式 所表示的序列的元素的类型，或该类型的引用。通常用 auto 说明符进行自动类型推导。
范围表达式 - 可以表示一个合适的序列（数组，或定义了 begin 和 end 成员函数或自由函数的对象，见下文）的任意表达式，或一个花括号初始化器列表。
循环语句 - 任意语句，通常是一条复合语句，它是循环体

范围变量声明 可以是结构化绑定声明：

for (auto&& [first,second] : mymap) {
    // 使用 first 和 second
}
 (C++17 起)

解释

上述语法产生的代码等价于下列代码（__range、__begin 和 __end 仅用于阐释）：

{

auto && __range = 范围表达式 ;
for (auto __begin = 首表达式, __end = 尾表达式 ; __begin != __end; ++__begin) {
范围变量声明 = *__begin;
循环语句
}

}

 (C++17 前)

{

auto && __range = 范围表达式 ;
auto __begin = 首表达式 ;
auto __end = 尾表达式 ;
for ( ; __begin != __end; ++__begin) {
范围变量声明 = *__begin;
循环语句
}

}

 (C++17 起)
(C++20 前)

{

初始化语句
auto && __range = 范围表达式 ;
auto __begin = 首表达式 ;
auto __end = 尾表达式 ;
for ( ; __begin != __end; ++__begin) {
范围变量声明 = *__begin;
循环语句
}

}

 (C++20 起)

要迭代的序列或范围通过对 范围表达式 求值以确定。依次对序列的每个元素进行解引用，并赋值给具有 范围变量声明 中所给定的类型和名字的变量。

首表达式 和 尾表达式 定义如下：

  • 如果 范围表达式 是数组类型的表达式，那么 首表达式 是 __range 而 尾表达式 是 (__range + __bound)，其中 __bound 是数组的元素数目（如果数组大小未知或拥有不完整类型，那么程序非良构）
  • 如果 范围表达式 是同时拥有名为 begin 以及名为 end 的成员的类类型 C 的表达式（不管这些成员的类型或可见性），那么 首表达式 是 __range.begin() 而 尾表达式 是 __range.end()；
  • 否则，首表达式 是 begin(__range) 而 尾表达式 是 end(__range)，通过实参依赖查找进行查找（不进行非实参依赖查找）。

正如传统循环一样，break 语句可用于提早退出循环，且 continue 语句能用于以下个元素重新开始循环。

临时范围表达式

如果 范围表达式 返回临时量，那么它的生存期延续到循环结尾，如绑定到转发引用 __range 所示，但要注意 范围表达式 中任何临时量生存期都不会延长。

for (auto& x : foo().items()) { /* .. */ } // 如果 foo() 返回右值则为未定义行为

此问题可用 初始化语句 变通解决：

for (T thing = foo(); auto& x : thing.items()) { /* ... */ } // OK
 (C++20 起)

注解

如果初始化器（范围表达式）是花括号初始化器列表，那么 __range 被推导为 std::initializer_list<>&&。

在泛型代码中，使用推导的转发引用，如 for (auto&& var : sequence)，是安全且受推荐的做法。

如果范围类型拥有名为 begin 的成员和名为 end 的成员，那么使用成员解释方案。其中无视成员是类型、数据成员、函数还是枚举项及其可访问性。从而像 class meow { enum { begin = 1, end = 2}; /* 类的剩余部分 */ }; 的类不能用于基于范围的 for 循环，即使有命名空间作用域的 begin/end 函数存在。

虽然通常在 循环语句 中使用声明于 范围变量声明 的变量，但并不要求这么做。

从 C++17 开始，首表达式 和 尾表达式 的类型不必相同，而且实际上 尾表达式 的类型不必是迭代器：它只需要能与一个迭代器比较是否不等。这允许以一个谓词（例如“迭代器指向空字符”）对范围进行分界。

 (C++17 起)

当基于范围的 for 循环被用于一个具有写时复制语义的（非 const）对象时，它可能会通过（隐式）调用非 const 的 begin() 成员函数触发深层复制。

如果想要避免这种行为（比如循环实际上不会修改这个对象），可以使用 std::as_const：

struct cow_string { /* ... */ }; // 写时复制的字符串
cow_string str = /* ... */;

// for(auto x : str) { /* ... */ } // 可能会导致深层复制

for(auto x : std::as_const(str)) { /* ... */ }
 (C++17 起)

关键词

for

示例

#include <iostream>
#include <vector>

int main() {
    std::vector<int> v = {0, 1, 2, 3, 4, 5};

    for (const int& i : v) // 以 const 引用访问
        std::cout << i << ' ';
    std::cout << '\n';

    for (auto i : v) // 以值访问，i 的类型是 int
        std::cout << i << ' ';
    std::cout << '\n';

    for (auto&& i : v) // 以转发引用访问，i 的类型是 int&
        std::cout << i << ' ';
    std::cout << '\n';

    const auto& cv = v;

    for (auto&& i : cv) // 以转发引用访问，i 的类型是 const int&
        std::cout << i << ' ';
    std::cout << '\n';

    for (int n : {0, 1, 2, 3, 4, 5}) // 初始化器可以是花括号初始化器列表
        std::cout << n << ' ';
    std::cout << '\n';

    int a[] = {0, 1, 2, 3, 4, 5};
    for (int n : a) // 初始化器可以是数组
        std::cout << n << ' ';
    std::cout << '\n';

    for ([[maybe_unused]] int n : a)
        std::cout << 1 << ' '; // 不必使用循环变量
    std::cout << '\n';

    for (auto n = v.size(); auto i : v) // 初始化语句（C++20）
        std::cout << --n + i << ' ';
    std::cout << '\n';

    for (typedef decltype(v)::value_type elem_t; elem_t i : v)
    // typedef 声明作为初始化语句（C++20）
        std::cout << i << ' ';
    std::cout << '\n';

    for (using elem_t = decltype(v)::value_type; elem_t i : v)
    // 别名声明作为初始化语句，同上（C++23）
        std::cout << i << ' ';
    std::cout << '\n';
}

输出：

0 1 2 3 4 5
0 1 2 3 4 5
0 1 2 3 4 5
0 1 2 3 4 5
0 1 2 3 4 5
0 1 2 3 4 5
1 1 1 1 1 1
5 5 5 5 5 5
0 1 2 3 4 5
0 1 2 3 4 5

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0962R1 | C++11 | 只要 begin 和 end 之一存在就使用成员解释方案 | 只有在两者都存在时才使用

参阅

for_each
 应用函数到范围中的元素
(函数模板)


引用声明

< cpp‎ | language

声明具名变量为引用，即既存对象或函数的别名。

语法

引用变量声明是声明符拥有下列形式的简单声明：

& 属性(可选) 声明符 | (1) |
&& 属性(可选) 声明符 | (2) | (C++11 起)
1) 左值引用声明符：声明 S& D; 将 D 声明为到 声明说明符序列 所确定的类型 S 的左值引用。
2) 右值引用声明符：声明 S&& D; 将 D 声明为到 声明说明符序列 所确定的类型 S 的右值引用。
声明符 | - | 除引用声明符之外的任何其他声明符（不存在引用的引用）
属性 | - | (C++11 起) 可选的属性列表

引用必须被初始化为指代一个有效的对象或函数：见引用初始化。

不存在 void 的引用，也不存在引用的引用。

引用类型无法在顶层被 cv 限定；声明中没有为此而设的语法，而如果添加限定性到 typedef 名、 decltype 说明符或类型模板形参，则忽略它。

引用不是对象；它们不必占用存储，尽管编译器会在需要实现所需语义（例如，引用类型的非静态数据成员通常会增加类的大小，量为存储内存地址所需）的情况下分配存储。

因为引用不是对象，所以不存在引用的数组，不存在指向引用的指针，不存在引用的引用：

int& a[3]; // 错误
int&* p;   // 错误
int& &r;   // 错误
引用折叠

通过模板或 typedef 中的类型操作可以构成引用的引用，此时适用引用折叠（reference collapsing）规则：右值引用的右值引用折叠成右值引用，所有其他组合均折叠成左值引用：

typedef int&  lref;
typedef int&& rref;
int n;
lref&  r1 = n; // r1 的类型是 int&
lref&& r2 = n; // r2 的类型是 int&
rref&  r3 = n; // r3 的类型是 int&
rref&& r4 = 1; // r4 的类型是 int&&

（这条规则，和将 T&& 用于函数模板时的模板实参推导的特殊规则一起，组成了使得 std::forward 可行的规则。）

 (C++11 起)

左值引用

左值引用可用于建立既存对象的别名（可拥有不同的 cv 限定）：

#include <iostream>
#include <string>

int main() {
    std::string s = "Ex";
    std::string& r1 = s;
    const std::string& r2 = s;

    r1 += "ample";           // 修改 s
//  r2 += "!";               // 错误：不能通过到 const 的引用修改
    std::cout << r2 << '\n'; // 打印 s，它现在保有 "Example"
}

它们也能用于在函数调用中实现按引用传递语义：

#include <iostream>
#include <string>

void double_string(std::string& s) {
    s += s; // 's' 与 main() 的 'str' 是同一对象
}

int main() {
    std::string str = "Test";
    double_string(str);
    std::cout << str << '\n';
}

当函数的返回值是左值引用时，函数调用表达式成为左值表达式：

#include <iostream>
#include <string>

char& char_number(std::string& s, std::size_t n) {
    return s.at(n); // string::at() 返回 char 的引用
}

int main() {
    std::string str = "Test";
    char_number(str, 1) = 'a'; // 函数调用是左值，可被赋值
    std::cout << str << '\n';
}

右值引用

右值引用可用于为临时对象延长生存期（注意，到 const 的左值引用也能延长临时对象生存期，但这些对象无法因此被修改）：

#include <iostream>
#include <string>

int main()
{
    std::string s1 = "Test";
//  std::string&& r1 = s1;           // 错误：不能绑定到左值

    const std::string& r2 = s1 + s1; // okay：到 const 的左值引用延长生存期
//  r2 += "Test";                    // 错误：不能通过到 const 的引用修改

    std::string&& r3 = s1 + s1;      // okay：右值引用延长生存期
    r3 += "Test";                    // okay：能通过到非 const 的引用修改
    std::cout << r3 << '\n';
}

更重要的是，当函数同时具有右值引用和左值引用的重载时，右值引用重载绑定到右值（包含纯右值和亡值），而左值引用重载绑定到左值：

#include <iostream>
#include <utility>

void f(int& x) {
    std::cout << "左值引用重载 f(" << x << ")\n";
}

void f(const int& x) {
    std::cout << "到 const 的左值引用重载 f(" << x << ")\n";
}

void f(int&& x) {
    std::cout << "右值引用重载 f(" << x << ")\n";
}

int main() {
    int i = 1;
    const int ci = 2;
    f(i);  // 调用 f(int&)
    f(ci); // 调用 f(const int&)
    f(3);  // 调用 f(int&&)，如果没有 f(int&&) 重载则会调用 f(const int&)
    f(std::move(i)); // 调用 f(int&&)

    // 右值引用变量在用于表达式时是左值
    int&& x = 1;
    f(x);            // 调用 f(int& x)
    f(std::move(x)); // 调用 f(int&& x)
}

这允许在适当时机自动选择移动构造函数、移动赋值运算符和其他具有移动能力的函数（例如 std::vector::push_back()）。

因为右值引用能绑定到亡值，所以它们能指代非临时对象：

int i2 = 42;
int&& rri = std::move(i2); // 直接绑定到 i2

这使得作用域中不再需要的对象可以被移动出去：

std::vector<int> v{1,2,3,4,5};
std::vector<int> v2(std::move(v)); // 绑定右值引用到 v
assert(v.empty());
 (C++11 起)

转发引用

转发引用是一种特殊的引用，它保持函数实参的值类别，使得 std::forward 能用来转发实参。转发引用是下列之一：

1) 函数模板的函数形参，其被声明为同一函数模板的类型模板形参的无 cv 限定的右值引用：
template<class T>
int f(T&& x) {                    // x 是转发引用
    return g(std::forward<T>(x)); // 从而能被转发
}
int main() {
    int i;
    f(i); // 实参是左值，调用 f<int&>(int&), std::forward<int&>(x) 是左值
    f(0); // 实参是右值，调用 f<int>(int&&), std::forward<int>(x) 是右值
}

template<class T>
int g(const T&& x); // x 不是转发引用：const T 不是无 cv 限定的

template<class T> struct A {
    template<class U>
    A(T&& x, U&& y, int* p); // x 不是转发引用：T 不是构造函数的类型模板形参
                             // 但 y 是转发引用
};
2) auto&&，但当其从花括号包围的初始化器列表推导时除外：
auto&& vec = foo();       // foo() 可以是左值或右值，vec 是转发引用
auto i = std::begin(vec); // 也可以
(*i)++;                   // 也可以
g(std::forward<decltype(vec)>(vec)); // 转发，保持值类别

for (auto&& x: f()) {
  // x 是转发引用；这是使用范围 for 循环最安全的方式
}

auto&& z = {1, 2, 3}; // *不是*转发引用（初始化器列表的特殊情形）

参阅模板实参推导和 std::forward。

 (C++11 起)

悬垂引用

尽管引用一旦初始化就始终指代一个有效的对象或函数，但有可能创建一个程序，其中被指代对象的生存期结束而引用仍保持可访问（悬垂（dangling））。访问这种引用是未定义行为。 一个常见例子是返回自动变量的引用的函数：

std::string& f()
{
    std::string s = "Example";
    return s; // 退出 s 的作用域：调用其析构函数并解分配其存储
}

std::string& r = f(); // 悬垂引用
std::cout << r;       // 未定义行为：从悬垂引用读取
std::string s = f();  // 未定义行为：从悬垂引用复制初始化

注意，右值引用和到 const 的左值引用能延长临时对象的生存期（参阅引用初始化中的规则和例外情况）。

如果被指代对象被销毁（例如通过显式的析构函数调用），但存储尚未被解分配，则到生存期外的对象的引用仍能以有限的方式使用，且当在同一存储中重新创建对象时也可以变为有效（细节见在生存期之外进行访问）。


引用初始化

< cpp‎ | language

将一个引用绑定到一个对象。

语法

T & 引用 = 目标 ; T & 引用 = { 实参1, 实参2, ... }; T & 引用 ( 目标 ) ; T & 引用 { 实参1, 实参2, ... } ; | (1) |
T && 引用 = 目标 ; T && 引用 = { 实参1, 实参2, ... }; T && 引用 ( 目标 ) ; T && 引用 { 实参1, 实参2, ... } ; | (2) | (C++11 起)
给定 R 函数 ( T & 实参 ); 或 R 函数 ( T && 实参 ); (C++11 起) 函数 ( 目标 ) 函数 ( { 实参1, 实参2, ... } ) | (3) |
T & 函数 () 或 T && 函数 () (C++11 起) 内 return 目标 ; | (4) |
给定 类 内的 T & 引用 ; 或 T && 引用 ; (C++11 起) 类::类(...) : 引用( 目标) {...} | (5) |

解释

到 T 的引用能以 T 类型的对象、T 类型的函数或可隐式转换到 T 的对象初始化。引用一旦初始化，便无法引用另一对象。

引用在下列情形初始化：

1) 以初始化器声明具名左值引用变量时
2) 以初始化器声明具名右值引用变量时
3) 在函数调用表达式中且有函数形参拥有引用类型时
4) 在函数的 return 语句中且函数返回引用类型时
5) 以成员初始化器初始化引用类型的非静态数据成员时

引用初始化的效果是：

  • 如果初始化器是花括号初始化器列表 { 实参1, 实参2, ... } ，那么遵循列表初始化。
  • 否则，如果引用是左值引用：
  • 如果 目标 是左值表达式，且其类型为 T 或派生于 T，而且有相等或更少的 cv 限定，那么引用被绑定到左值表达式所标识的对象或其基类子对象。
double d = 2.0;
double& rd = d;        // rd 引用 d
const double& rcd = d; // rcd 引用 d
struct A {};
struct B : A {} b;
A& ra = b;             // ra 引用 b 中的 A 子对象
const A& rca = b;      // rca 引用 b 中的 A 子对象
  • 否则，如果 目标 的类型与 T 不相同且不从它派生，且 目标 拥有到类型为 T 或派生于 T 并有相等或更少的 cv 限定的左值的转换函数，那么绑定引用到转换函数所返回的左值所标识的对象（或到其基类子对象）。
struct A {};
struct B : A { operator int&(); };
int& ir = B(); // ir 指代 B::operator int& 的结果
  • 否则，如果引用是到非 volatile 的 const 限定类型的左值引用或右值引用 (C++11 起)：
  • 如果 目标 是非位域右值或函数左值，且其类型是 T 或派生于 T ，并拥有相等或更少 cv 限定，那么绑定引用到初始化器表达式的值或其基类子对象（如果需要，先进行临时量实质化） (C++17 起)。
struct A {};
struct B : A {};
extern B f();
const A& rca2 = f(); // 到 B 右值的 A 子对象。
A&& rra = f();       // 同上

int i2 = 42;
int&& rri = static_cast<int&&>(i2); // 直接绑定到 i2
  • 否则，如果 目标 的类型与 T 不相同且不从它派生，且 目标 拥有到类型为 T 或派生于 T 并有相等或更少的 cv 限定的右值或函数左值的转换函数，那么绑定引用到转换函数的结果或到其基类子对象（如果需要，先进行临时量实质化） (C++17 起)。
struct A {};
struct B : A {};
struct X { operator B(); } x;
const A& r = x; // 绑定到转换结果的 A 子对象
B&& rrb = x;    // 直接绑定到转换的结果
  • 否则，将 目标 隐式转换为 T。绑定引用到转换（在实质化临时量后，即使 T 是标量类型也保持其 cv 限定） (C++17 起)的结果。如果 目标（或如果由用户定义转换函数进行转换，则为转换函数的结果）类型为 T 或派生于 T，那么它必须拥有等于或少于 T 的 cv 限定，且如果引用为右值引用，那么它必须不是左值 (C++11 起)。
const std::string& rs = "abc"; // rs 指代从字符数组复制初始化的临时量
const double& rcd2 = 2;        // rcd2 指代值为 2.0 的临时量
int i3 = 2;
double&& rrd3 = i3;            // rrd3 指代值为 2.0 的临时量

临时量生存期

一旦引用被绑定到临时对象或其子对象，临时对象的生存期就被延续以匹配引用的生存期（检查临时对象生存期的例外），其中临时对象或其子对象由下列表达式之一代表：

  • 对象类型的纯右值表达式、
 (C++17 前)
  • 临时量实质化转换、
 (C++17 起)
  • 有括号表达式 (e)，其中 e 是这些表达式之一、
  • 形式为 a[n] 或 n[a] 的内建的下标表达式，其中 a 是数组且为这些表达式之一、
  • 形式为 e.m 的成员访问表达式，其中 e 是这些表达式之一而 m 指代对象类型的非静态数据成员、
  • 形式为 e.*mp 的成员指针操作，其中 e 是这些表达式之一而 mp 是指向数据成员的指针、
  • 无用户定义转换的 const_cast、 static_cast、 dynamic_cast 或 reinterpret_cast 转换，它将这些表达式之一转换成指代操作数所指代的对象，其完整对象，或完整对象的子对象的泛左值（显式转型表达式被转译成这些基础转型的序列）、
  • 形式为 cond ? e1 : e2 并为泛左值的条件表达式，其中 e1 或 e2 为这些表达式之一，或
  • 形式为 x, e 并为泛左值的内建的逗号表达式，其中 e 是这些表达式之一。

此生存期规则有下列例外：

  • return 语句中绑定到函数返回值的临时量不被延续：它在返回表达式的末尾立即销毁。这种 return 语句始终返回悬垂引用。
  • 在函数调用中绑定到函数形参的临时量，存在到含这次函数调用的全表达式结尾为止：如果函数返回一个生命长于全表达式的引用，那么它将成为悬垂引用。
  • 绑定到 new 表达式中所用的初始化器中的引用的临时量，存在到含有该 new 表达式的全表达式结尾为止，而非被初始化对象的存在期间。如果被初始化对象的声明长于全表达式，那么它的引用成员将成为悬垂引用。
 (C++11 起)
  • 绑定到用直接初始化语法（圆括号），而非列表初始化语法（花括号）初始化的聚合体的引用元素中的引用的临时量，存在直至含该初始化器的全表达式末尾为止。
struct A {
  int&& r;
};
A a1{7}; // OK：延续生存期
A a2(7); // 良构，但有悬垂引用
 (C++20 起)

总而言之，临时量的生存期不能以进一步“传递”来延续：从绑定了该临时量的引用或数据成员初始化的第二引用不影响临时量的生存期。

注解

仅在函数形参声明，函数返回类型声明，类成员声明，以及带 extern 说明符时，引用可以不与初始化器一同出现。

在 CWG 问题 1696 的解决方案前，容许在构造函数初始化器列表中绑定临时量到引用成员，而临时量只持续到构造函数退出前，而非对象存在期间。这种初始化从 CWG 1696 开始非良构，不过许多编译器仍然支持它（值得注意的例外是 clang）。

示例

#include <utility>
#include <sstream>
struct S {
    int mi;
    const std::pair<int,int>& mp; // 引用成员
};

void foo(int) {}

struct A {};
struct B : A {
    int n;
    operator int&() { return n; };
};

B bar() { return B(); }

//int& bad_r;      // 错误：没有初始化器
extern int& ext_r; // OK

int main() {
//  左值
    int n = 1;
    int& r1 = n;                    // 到对象 n 的左值引用
    const int& cr(n);               // 引用可以有更多 cv 限定
    volatile int& cv{n};            // 可使用任何初始化器语法
    int& r2 = r1;                   // 另一到对象 n 的左值引用
//  int& bad = cr;                  // 错误：更少 cv 限定
    int& r3 = const_cast<int&>(cr); // 需要 const_cast

    void (&rf)(int) = foo;  // 到函数的左值引用
    int ar[3];
    int (&ra)[3] = ar;      // 到数组的左值引用

    B b;
    A& base_ref = b;        // 到基类子对象的左值引用
    int& converted_ref = b; // 到转换结果的左值引用

//  右值
//  int& bad = 1;        // 错误：不能绑定左值引用到右值
    const int& cref = 1; // 绑定到右值
    int&& rref = 1;      // 绑定到右值

    const A& cref2 = bar(); // 到 B 临时量的 A 子对象的引用
    A&& rref2 = bar();      // 相同

    int&& xref = static_cast<int&&>(n); // 直接绑定到 n
//  int&& copy_ref = n;                 // 错误：不能绑定到左值
    double&& copy_ref = n;              // 绑定到值为 1.0 的右值临时量

// 临时量生存期上的限制
    std::ostream& buf_ref = std::ostringstream() << 'a'; // ostringstream 临时量
                      // 被绑定到 operator<< 的左运算数，但是它的生存期在分号结束，
                      // 所以 buf_ref 是悬垂引用。

    S a { 1, {2, 3} };         // 绑定临时量 pair {2,3} 到引用成员 a.mp 并延长其生存期以匹配 a
    S* p = new S{ 1, {2, 3} }; // 绑定临时量 pair {2,3} 到引用成员 p->mp ，
                               // 但是它的生存期在分号结束
                               // p->mp 是悬垂引用
    delete p;
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1299 | C++98 | 临时量的定义不明确 | 使之明确

参阅

  • 构造函数
  • 转换构造函数
  • 复制赋值
  • 复制构造函数
  • explicit
  • 初始化
    • 常量初始化
    • 复制初始化
    • 直接初始化
    • 列表初始化
  • 移动赋值
  • 移动构造函数
  • new


reinterpret_cast 转换

< cpp‎ | language

通过重新解释底层位模式在类型间转换。

语法

reinterpret_cast < 新类型 > ( 表达式 )

返回 新类型 类型的值。

解释

与 static_cast 不同，但与 const_cast 类似，reinterpret_cast 表达式不会编译成任何 CPU 指令（除非在整数和指针间转换，或在指针表示依赖其类型的不明架构上）。它纯粹是一个编译时指令，指示编译器将 表达式 视为如同具有 新类型 类型一样处理。

只有下列转换在不去除常量性或易变性的场合才能用 reinterpret_cast 执行。

1) 整型、枚举、指针或成员指针类型的表达式可转换到其自身的类型。产生的值与 表达式 的相同。(C++11 起)
2) 指针能转换成大小足以保有其类型所有值的任何整型类型（例如转换成 std::uintptr_t）
3) 任何整型或枚举类型的值可转换到指针类型。指针转换到有足够大小的整数再转换回同一指针类型后，保证拥有其原值，否则结果指针无法安全地解引用（不保证相反方向的往返转换；相同指针可拥有多种整数表示）。不保证空指针常量 NULL 或整数零生成目标类型的空指针值；此时应该用 static_cast 或隐式转换。
4) 任何 std::nullptr_t 类型的值，包含 nullptr，可转换成任何整型类型，如同它是 (void*)0 一样。但没有值能转换成 std::nullptr_t，甚至 nullptr 也不行：此时应该用 static_cast。(C++11 起)
5) 任何对象指针类型 T1* 可转换成指向对象指针类型 cv T2* 。这严格等价于 static_cast<cv T2*>(static_cast<cv void*>(表达式))（这意味着，若 T2 的对齐要求不比 T1 的更严格，则指针值不改变，且将结果指针转换回原类型将生成其原值）。任何情况下，只有类型别名化（type aliasing）规则允许（见下文）时，结果指针才可以安全地解引用。
6) T1 类型的左值表达式可转换成到另一个类型 T2 的引用。结果是与原左值指代同一对象，但有不同类型的左值或亡值。不创建临时量，不进行复制，不调用构造函数或转换函数。只有类型别名化（type aliasing）规则允许（见下文）时，结果引用才可以安全访问。
7) 任何函数指针可转换成指向不同函数类型的指针。通过指向不同函数类型的指针调用函数是未定义的，但将这种指针转换回指向原函数类型的指针将生成指向原函数的指针值。
8) 一些实现上（特别是在任何 POSIX 兼容的系统上，即基于 dlsym 的要求），函数指针可以转换成 void* 或任何其他对象指针，反之亦然。若实现支持双向的转换，则转换回原类型将生成原值，否则结果指针不能安全地解引用或调用。
9) 任何指针类型的空指针值可转换成任何其他指针类型，产生该类型的空指针值。注意不能用 reinterpret_cast 将空指针常量 nullptr 或任何其他 std::nullptr_t 类型的值转换为指针：此时应该使用隐式转换或 static_cast。
10) 成员函数指针可转换成指向不同类型的不同成员函数的指针。转换回原类型将生成原值，否则结果指针不能安全使用。
11) 指向某类 T1 的成员对象的指针可转换成指向另一个类 T2 的另一个成员对象的指针。若 T2 的对齐不比 T1 更严格，则转换回原类型 T1 将生成原值，否则不能安全地使用结果指针。

同所有转型表达式，结果是：

  • 左值，如果 新类型 是左值引用或到函数类型的右值引用；
  • 亡值，如果 新类型 是到对象类型的右值引用；
  • 否则为纯右值。

关键词

reinterpret_cast

类型别名化

如果下列条件均不满足，每当试图通过 别名类型 类型的泛左值读或修改类型为 动态类型 的对象的值时，行为未定义：

  • 别名类型 与 动态类型 相似。
  • 别名类型 是 动态类型 的（可有 cv 限定的）有符号或无符号变体。
  • 别名类型 为 std::byte、 (C++17 起)char 或 unsigned char：这容许将任何对象的对象表示作为一个字节数组加以检验。

非正式地说，忽略顶层 cv 限定性，若两个类型符合下列条件，则它们相似：

  • 它们是同一类型；或
  • 它们都是指针，且被指向的类型相似；或
  • 它们都是指向相同类的成员指针，且被指向的成员类型相似；或
  • 它们都是大小相同的数组或都是未知边界数组，且数组元素类型相似。
 (C++20 前)
  • 它们都是数组，大小相同或至少一个是未知边界数组，且数组元素类型相似。
 (C++20 起)

例如：

  • const int * volatile * 与 int * * const 相似；
  • const int (* volatile S::* const)[20] 与 int (* const S::* volatile)[20] 相似；
  • int (* const *)(int *) 与 int (* volatile *)(int *) 相似；
  • int (S::*)() const 与 int (S::*)() 不相似；
  • int (*)(int *) 与 int (*)(const int *) 不相似；
  • const int (*)(int *) 与 int (*)(int *) 不相似；
  • int (*)(int * const) 与 int (*)(int *) 相似（它们是同一类型）；
  • std::pair <int, int> 与 std::pair <const int, int> 不相似。

此规则允许进行基于类型的别名分析，即编译器假设通过一个类型的泛左值读取的值，不会被通过不同类型的泛左值的写入所修改（依据上述例外情况）。

注意，许多 C++ 编译器作为非标准语言扩展放松此规则，以允许通过 union 的不活跃成员的进行类型错误的访问（这种访问在 C 中并不是未定义的）。

注解

标准中定义严格别名化规则的段落含有两条额外条例，部分从 C 继承而来：

  • 别名类型 为聚合类型或 union 类型，它保有前述各类型之一作为其元素或非静态成员（递归地包含子聚合体的元素和被包含的联合体的非静态数据成员）。
  • 别名类型 为 动态类型 的（可有 cv 限定的）基类。

这些条例所描述的情况不可能出现于 C++，从而从上面的讨论中省略。在 C 中，聚合复制和赋值将聚合体对象作为整体访问。但 C++ 中始终通过成员函数调用进行这种行动，这会访问单独的子对象而非整个对象（或在联合体的情况下，复制对象表示，即经由 unsigned char）。见核心问题 2051。

假设符合对齐要求，则 reinterpret_cast 在处理指针可互转换对象的少数受限情况外，不更改指针的值：

struct S1 { int a; } s1;
struct S2 { int a; private: int b; } s2; // 非标准布局
union U { int a; double b; } u = {0};
int arr[2];

int* p1 = reinterpret_cast<int*>(&s1); // p1 的值为“指向 s1.a 的指针”
                                       // 因为 s1.a 与 s1 为指针可互转换

int* p2 = reinterpret_cast<int*>(&s2); // reinterpret_cast 不更改 p2 的值为“指向 s2 的指针”。

int* p3 = reinterpret_cast<int*>(&u);  // p3 的值为“指向 u.a 的指针”：u.a 与 u 指针可互转换

double* p4 = reinterpret_cast<double*>(p3); // p4 的指针为“指向 u.b 的指针”：u.a 与 u.b
                                            // 指针可互转换，因为都与 u 指针可互转换

int* p5 = reinterpret_cast<int*>(&arr); // reinterpret_cast 不更改 p5 的值为“指向 arr 的指针”

在不实际代表适当类型的对象的泛左值（例如通过 reinterpret_cast 所获得）上，进行代表非静态数据成员或非静态成员函数的成员访问，将导致未定义行为：

struct S { int x; };
struct T { int x; int f(); };
struct S1 : S {}; // 标准布局
struct ST : S, T {}; // 非标准布局

S s = {};
auto p = reinterpret_cast<T*>(&s); // p 的值为“指向 s 的指针”
auto i = p->x; // 类成员访问表达式为未定义行为：s 不是 T 对象
p->x = 1; // 未定义行为
p->f();   // 未定义行为

S1 s1 = {};
auto p1 = reinterpret_cast<S*>(&s1); // p1 的值为“指向 S 的 s1 子对象的指针”
auto i = p1->x; // OK
p1->x = 1; // OK

ST st = {};
auto p2 = reinterpret_cast<S*>(&st); // p2 的值为“指向 st 的指针”
auto i = p2->x; // 未定义行为
p2->x = 1; // 未定义行为

许多编译器在这种情况下发布“严格别名化”警告，即使在技术上这种构造所违背的并非称为“严格别名化规则”段落的规则。

严格别名化及其相关规则的目的，是启用基于类型的别名分析，若程序能合法地创建一种情形，使得两个指向无关类型的指针（例如一个 int* 和一个 float*）能同时存在并可一同用于加载或存储同一内存（见此 SG12 reflector 上的邮件），则别名分析会普遍无效。故任何看起来能够创建这种情形的技巧都必然导致未定义行为。

当需要将对象的字节解释为不同类型的值时，可以使用 std::memcpy 或 std::bit_cast (C++20 起)：

double d = 0.1;
std::int64_t n;
static_assert(sizeof n == sizeof d);
// n = *reinterpret_cast<std::int64_t*>(&d); // 未定义行为
std::memcpy(&n, &d, sizeof d); // OK
n = std::bit_cast<std::int64_t>(d); // 亦 OK

若实现提供 std::intptr_t 与/或 std::uintptr_t，则从指向对象类型或 cv void 的指针到这些类型的转型始终为良定义。然而这对于函数指针并不保证。

 (C++11 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 195 | C++98 | 不允许函数指针和对象指针间的转换 | 改为条件性支持

示例

演示 reinterpret_cast 的一些用法：

#include <cstdint>
#include <cassert>
#include <iostream>
int f() { return 42; }
int main()
{
    int i = 7;

    // 指针到整数并转回
    std::uintptr_t v1 = reinterpret_cast<std::uintptr_t>(&i); // 不能误用 static_cast
    std::cout << "&i 的值是 0x" << std::hex << v1 << '\n';
    int* p1 = reinterpret_cast<int*>(v1);
    assert(p1 == &i);

    // 到另一函数指针并转回
    void(*fp1)() = reinterpret_cast<void(*)()>(f);
    // fp1(); 未定义行为
    int(*fp2)() = reinterpret_cast<int(*)()>(fp1);
    std::cout << std::dec << fp2() << '\n'; // 安全

    // 通过指针的类型别名化
    char* p2 = reinterpret_cast<char*>(&i);
    if(p2[0] == '\x7')
        std::cout << "本系统是小端的\n";
    else
        std::cout << "本系统是大端的\n";

    // 通过引用的类型别名化
    reinterpret_cast<unsigned int&>(i) = 42;
    std::cout << i << '\n';

    [[maybe_unused]] const int &const_iref = i;
    // int &iref = reinterpret_cast<int&>(const_iref); // 编译错误——不能去除 const
    // 必须用 const_cast 代替：int &iref = const_cast<int&>(const_iref);
}

可能的输出：

&i 的值是 0x7fff352c3580
42
本系统是小端的
42

参阅

const_cast 转换 | 添加或移除 const
static_cast 转换 | 进行基本转换
dynamic_cast 转换 | 进行有检查的多态转换
显式转型 | 在类型间自由转换
标准转换 | 从一个类型到另一类型的隐式转换


return 语句

< cpp‎ | language

终止当前函数并返回指定值（如果存在）给调用方函数。

语法

属性(可选) return 表达式(可选) ; | (1) |
属性(可选) return 花括号初始化器列表 ; | (2) | (C++11 起)
属性(可选) co_return 表达式(可选) ; | (3) | (C++20 起)
属性(可选) co_return 花括号初始化器列表 ; | (4) | (C++20 起)
属性 | - | (C++11 起) 任意个属性组成的可选序列
表达式 | - | 可以转换到函数返回类型的表达式
花括号初始化器列表 | - | 初始化器的花括号环绕列表，及其他花括号初始化器列表

解释

1) 对 表达式 求值，终止当前函数，并将 表达式 隐式转换到函数返回类型后的结果返回给调用方。表达式 在返回类型是（可有 cv 限定的）void 的函数中可以不出现，在构造函数中和析构函数中不能出现。
2) 使用复制列表初始化对函数的返回值进行构造。
3,4) 在协程中，对于最终暂停点，必须用关键字 co_return 取代 return（细节见协程）。

注解

如果控制流抵达返回（可有 cv 限定的） void 的函数结尾、构造函数结尾、析构函数结尾或返回（可有 cv 限定的） void 的函数的函数 try 块结尾，且没有 return 语句，那么执行 return;。

如果控制流抵达 main 函数的结尾，那么执行 return 0;。

如果控制流抵达有返回值的函数（除了 main）的结尾却没有 return 语句是未定义行为。

在返回（可有 cv 限定的）void 的函数中，当表达式类型是（可有 cv 限定的）void 时，可以使用带 表达式 的 return 语句。

函数返回类型如果是 占位类型，那么会根据返回值自动推导它的具体类型。

对函数调用结果的复制初始化按顺序早于在 表达式 结尾处对所有临时量的销毁，后者按顺序早于该 return 的外围块的局部变量的销毁。

 (C++14 起)

以值返回可能会涉及临时对象的构造和复制/移动，除非使用复制消除。具体而言，复制/移动的条件如下：

自动从局部变量和形参移动

如果 表达式 是（可有括号的）标识表达式并且指名类型如下的变量：

  • 非 volatile 对象类型
  • 或到对象类型的非 volatile 右值引用类型
 (C++20 起)

，而该变量声明于最内层外围函数或 lambda 表达式

  • 的体内，或
  • 为其形参

那么进行两次 重载决议，以选择用于初始化返回值的构造函数，或对于 co_return 为选择 promise.return_value() 的重载 (C++20 起)：

  • 首先如同假设 表达式 是右值表达式（从而它可以选择移动构造函数），然后
  • 如果第一次重载决议失败
  • 或如果它成功，但不选择移动构造函数（正式而言，选择的构造函数的首参数不是到 表达式 类型的（可有 cv 限定）的右值引用，
 (C++20 前)
  • 那么照常进行重载决议，把 表达式 当做左值（从而它可以选择复制构造函数）。
 (C++11 起)

受保证的复制消除

如果 表达式 是纯右值，那么直接以该表达式初始化结果对象。其中在类型相匹配时并不涉及复制或移动构造函数（见复制消除）。

 (C++17 起)

关键词

return, co_return

示例

#include <iostream>
#include <string>
#include <utility>

void fa(int i)
{
    if (i == 2)
         return;
    std::cout << i << '\n';
} // 隐含的 return;

int fb(int i)
{
    if (i > 4)
        return 4;
    std::cout << i << '\n';
    return 2;
}

std::pair<std::string, int> fc(const char* p, int x)
{
    return {p, x};
}

void fd()
{
    return fa(10); // fa(10) 是 void 表达式
}

int main()
{
    fa(2); // 返回，当 i==2 时无动作
    fa(1); // 打印其实参，然后返回
    int i = fb(5); // 返回 4
    i = fb(i); // 打印其实参，返回 2
    std::cout << i << '\n'
              << fc("Hello", 7).second << '\n';
    fd();
}

输出：

1
4
2
7
10

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1579 | C++11 | 不允许经由转换移动构造函数返回 | 启用对转换移动构造函数的查找
CWG 1885 | C++14 | 自动变量的销毁顺序不明确 | 添加了定序规则

参阅

  • 复制消除


三/五/零之法则

< cpp‎ | language

三之法则

若某个类需要用户定义的析构函数、用户定义的复制构造函数或用户定义的复制赋值运算符，则它几乎肯定三者全部都需要。

因为 C++ 在各种场合（按值传递/返回、操纵容器等）对对象进行复制和复制赋值，若可访问，这些特殊成员函数就会被调用，而且若用户不定义他们，则编译器会隐式定义。

如果类对某种资源进行管理，而资源句柄是非类类型的对象（裸指针、POSIX 文件描述符等），则这些隐式定义的成员函数通常都不正确，其析构函数不做任何事，而复制构造函数/复制赋值运算符则进行“浅复制”（复制句柄的值，而不复制底层资源）。

class rule_of_three
{
    char* cstring; // 以裸指针为动态分配内存的句柄

    void init(const char* s)
    {
        std::size_t n = std::strlen(s) + 1;
        cstring = new char[n];
        std::memcpy(cstring, s, n); // 填充
    }
 public:
    rule_of_three(const char* s = "") { init(s); }

    ~rule_of_three()
    {
        delete[] cstring;  // 解分配
    }

    rule_of_three(const rule_of_three& other) // 复制构造函数
    {
        init(other.cstring);
    }

    rule_of_three& operator=(const rule_of_three& other) // 复制赋值
    {
        if(this != &other) {
            delete[] cstring;  // 解分配
            init(other.cstring);
        }
        return *this;
    }
};

通过可复制句柄来管理不可复制资源的类，可能必须将其复制赋值和复制构造函数声明为私有的并且不提供其定义，或将它们定义为弃置的。这是三之法则的另一种应用：删除其中之一而遗留其他被隐式定义很可能会导致错误。

五之法则

因为用户定义析构函数、复制构造函数或复制赋值运算符的存在阻止移动构造函数和移动赋值运算符的隐式定义，所以任何想要移动语义的类必须声明全部五个特殊成员函数：

class rule_of_five
{
    char* cstring; // 以裸指针为动态分配内存的句柄
 public:
    rule_of_five(const char* s = "")
    : cstring(nullptr)
    {
        if (s) {
            std::size_t n = std::strlen(s) + 1;
            cstring = new char[n];      // 分配
            std::memcpy(cstring, s, n); // 填充
        }
    }

    ~rule_of_five()
    {
        delete[] cstring;  // 解分配
    }

    rule_of_five(const rule_of_five& other) // 复制构造函数
    : rule_of_five(other.cstring)
    {}

    rule_of_five(rule_of_five&& other) noexcept // 移动构造函数
    : cstring(std::exchange(other.cstring, nullptr))
    {}

    rule_of_five& operator=(const rule_of_five& other) // 复制赋值
    {
         return *this = rule_of_five(other);
    }

    rule_of_five& operator=(rule_of_five&& other) noexcept // 移动赋值
    {
        std::swap(cstring, other.cstring);
        return *this;
    }

// 另一种方法是用以下函数替代两个赋值运算符
//  rule_of_five& operator=(rule_of_five other) noexcept
//  {
//      std::swap(cstring, other.cstring);
//      return *this;
//  }
};

与三之法则不同的是，不提供移动构造函数和移动赋值运算符通常不是错误，但会导致失去优化机会。

零之法则

有自定义析构函数、复制/移动构造函数或复制/移动赋值运算符的类应该专门处理所有权（这遵循单一责任原则）。其他类都不应该拥有自定义的析构函数、复制/移动构造函数或复制/移动赋值运算符[1]

这条法则也在 C++ 核心指南（C++ Core Guidelines）中出现，为 C.20：一旦可以避免定义默认操作就应当施行。

class rule_of_zero
{
    std::string cppstring;
 public:
    rule_of_zero(const std::string& arg) : cppstring(arg) {}
};

当有意将某个基类用于多态用途时，可能必须将其析构函数声明为公开的虚函数。由于这会阻拦隐式移动（并弃用隐式复制）的生成，因而必须将各特殊成员函数声明为预置的[2]

class base_of_five_defaults
{
 public:
    base_of_five_defaults(const base_of_five_defaults&) = default;
    base_of_five_defaults(base_of_five_defaults&&) = default;
    base_of_five_defaults& operator=(const base_of_five_defaults&) = default;
    base_of_five_defaults& operator=(base_of_five_defaults&&) = default;
    virtual ~base_of_five_defaults() = default;
};

然而这使得类有可能被切片，这是多态类经常把复制定义为弃置的原因（见 C++ 核心指南中的 C.67：多态类应该抑制复制操作），这带来了下列的五之法则的通用说法：

C.21：若有任何默认操作被定义或 =delete，则应当对它们全部进行定义或 =delete

引用

  1. ↑ “零之法则”，R. Martinho Fernandes 8/15/2012
  2. ↑ “关于零之法则的考虑”，Scott Meyers, 3/13/2014


作用域

< cpp‎ | language

C++ 程序中出现的每个名字，只在某些可能不连续的源码部分中有效，这些部分被称为其作用域。

在作用域内，能用无限定名字查找将名字与其声明关联起来。

块作用域

块（复合语句）中的声明所引入的变量的潜在作用域，开始于其声明点并终止于该块末尾。实际作用域与潜在作用域相同，除非有内嵌块带有引入了相同名字的声明（这种情况下，从外层声明的作用域中排除掉嵌套声明的整个潜在作用域）。

int main()
{
    int a = 0; // 第一个 'a' 的作用域开始
    ++a; // 名字 'a' 在作用域中并指代第一个 'a'
    {
        int a = 1; // 第二个 'a' 的作用域开始
                   // 第一个 'a' 的作用域间断
        a = 42;    // 'a' 在作用域中并指代第二个 'a'
    } // 块结束，第二个 'a' 的作用域结束
      //        第一个 'a' 的作用域恢复
} // 块结束，第一个 'a' 的作用域结束
int b = a; // 错误：名字 'a' 不在作用域中

声明于异常处理块中的名字的潜在作用域开始于其声明点，并在该异常处理块结束时结束，其他异常处理块和外围块在作用域以外。

try {
    f();
} catch(const std::runtime_error& re) { // re 的作用域开始
    int n = 1; // n 的作用开始
    std::cout << re.what(); // re 在作用域中
} // re 的作用域结束， n 的作用域结束
 catch(std::exception& e) {
    std::cout << re.what(); // 错误： re 不在作用域中
    ++n; // 错误： n 不在作用域中
}

声明于 for 循环的初始化语句，for 循环的条件，范围 for 循环的范围声明，if 语句或 switch 语句的初始化语句， (C++17 起) if 语句、while 循环或 switch 语句的条件中的名字的潜在作用域开始于其声明点，并结束于相应控制语句的末尾。

Base* bp = new Derived;
if(Derived* dp = dynamic_cast<Derived*>(bp))
{
    dp->f(); // dp 在作用域中
} // dp 的作用域结束

for(int n = 0; // n 的作用域开始
    n < 10;    // n 在作用域中
    ++n)       // n 在作用域中
{
    std::cout << n << ' '; // n 在作用域中
} // n 的作用域结束

函数形参作用域

函数形参（包括 lambda 表达式的形参）或函数局部预定义变量的潜在作用域开始于其声明点。

  • 若最内层的外围函数声明符不是函数定义的声明符，则其潜在作用域终止于该函数声明符的结尾。
  • 否则，其潜在作用域终止于函数 try 块的最后异常处理块的末尾，若不使用函数 try 块则为函数体的末尾。
const int n = 3;

int f1(int n,     // 全局 'n' 的作用域间断
                  // 形参 'n' 的作用域开始
       int y = n); // 错误：默认实参涉指了形参

int (*(*f2)(int n))[n]; // OK ：函数形参 'n' 的作用域终止于其函数声明符的末尾
                        // 在数组声明符中，全局 n 在作用域中
// （这声明了一个返回（含有 3 个 int 元素的数组的指针）的函数的指针）

// 相反
auto (*f3)(int n)->int (*)[n]; // 错误：以形参 'n' 为数组边界

int f(int n = 2)  // 'n' 的作用域开始
try // 函数 try 块
{         // 函数体开始
   ++n;   // 'n' 在作用域中并指代函数形参
   {
      int n = 2; // 局部变量 'n' 的作用域开始
                 // 函数形参 'n' 的作用域中断
      ++n; // 'n' 在此块中指代局部变量
    }            // 局部变量 'n' 的作用域结束
                 // 函数形参 'n' 的作用域恢复
} catch(...) {
   ++n; // n 在作用域中并指代函数形参
   throw;
} // 最后异常处理块结束，函数形参 'n' 的作用域结束
int a = n; // OK ：全局 'n' 在作用域中

函数作用域

如果一个标号（且只有标号）在一个函数内声明，则在该函数和其所有内嵌代码块的任何位置，无论在其自身声明的前后，该标号都在作用域中。

void f()
{
   {
       goto label; // label 在作用域中，尽管之后才声明
label:;
   }
   goto label; // label 忽略块作用域
}

void g()
{
    goto label; // 错误： g() 中 label 不在作用域中
}

命名空间作用域

命名空间中声明的任何实体的潜在作用域均开始于其声明，并由其后的同一命名空间名的所有命名空间定义拼合起来，再加上对于将这个名字或其整个命名空间引入到其他作用域的每个 using 指令来说，包括这个作用域的剩余部分。

翻译单元的顶层作用域（“文件作用域”或“全局作用域”）亦为命名空间，且被正式称作“全局命名空间作用域”。任何声明于全局命名空间作用域的实体的潜在作用域均开始于其声明，并持续到翻译单元的结尾。

声明于无名命名空间或内联命名空间的实体的作用域包括外围命名空间；

namespace N { // N 的作用域开始（作为全局命名空间的成员）
    int i; // i 的作用域开始
    int g(int a) { return a; } // g 的作用域开始
    int j(); // j 的作用域开始
    void q(); // q 的作用域开始
    namespace {
        int x; // x 的作用域开始
    } // x 的作用域不结束
    inline namespace inl { // inl 的作用域开始
      int y; // y 的作用域开始
    } // y 的作用域不结束
} // i、g、j、q、inl、x、y 的作用域间断

namespace {
    int l=1; // l 的作用域开始
} // l 的作用域不结束（它是无名命名空间的成员）

namespace N { // i、g、j、q、inl、x、y 的作用域继续
    int g(char a) {  // 重载 N::g(int)
        return l+a;  // 来自无名命名空间的 l 在作用域中
    }
    // int i; // 错误：重复定义（ i 已在作用域中）
    int j(); // OK ：允许重复的函数声明
    int j() { // OK ：定义先前声明的 N::j()
        return g(i); // 调用 N::g(int)
    }
    int q(); // 错误： q 已在作用域中并有不同的返回类型
} // i、g、j、q、inl、x、y 的作用域间断

int main() {
    using namespace N; // i、g、j、q、inl、x、y 的作用域恢复
    i = 1; // N::i 在作用域中
    x = 1; // N::(匿名)::x 在作用域中
    y = 1; // N::inl::y 在作用域中
    inl::y = 2; // N::inl 也在作用域中
} // i、g、j、q、inl、x、y 的作用域间断

类作用域

类中声明的名字的潜在作用域开始于其声明点，并包含类体的剩余部分和所有函数体（无论是否定义于类定义外或在该名字的声明之前）、默认实参、异常规定、类内花括号或等号初始化器，还递归地包括嵌套类中的所有这些内容。

class X {
    int f(int a = n) { // 默认实参内的 X::n 在作用域中
         return a*n;   // 函数体内的   X::n 在作用域中
    }
    using r = int;
    r g();
    int i = n*2;   // 初始化器内的 X::n 在作用域中

//  int x[n];      // 错误：类体内的 X::n 不在作用域中
    static const int n = 1;
    int x[n];      // OK ： 类体内的 X::n 现在在作用域中
};

//r X::g() {       // 错误：类外成员函数内的 r 不在作用域中
auto X::g()->r {   // OK ：尾随返回类型内的 X::r 在作用域中
    return n;      // 类外成员函数体内的   X::n 在作用域中
}

如果一个名字在被声明前已经在类体中被使用，而该名字的另一声明在作用域中，则程序非良构，不要求诊断。

typedef int c; // ::c
enum { i = 1 }; // ::i
class X {
    char v[i]; // 错误：此处 i 指代 ::i，但 X::i 也存在
    int f() {
         return sizeof(c); // OK ：成员函数体内在作用域中的是 X::c 而非 ::c
    }
    char c; // X::c
    enum { i = 2 }; // X::i
};

typedef char* T;
struct Y {
    T a; // 错误：此处，T 指代 ::T，但 Y::T 也存在
    typedef long T;
    T b;
};

任何类成员名只能用于四种语境中：

  • 在其自身的类作用域或在派生类的类作用域之中
  • 在对其类或其派生类的类型的表达式运用 . 运算符之后
  • 在对其类或其派生的类的指针类型的表达式运用 -> 运算符之后
  • 在对其类或其派生类的名字运用 :: 运算符之后

枚举作用域

有作用域枚举中引入的枚举项的名字的作用域开始于其声明点，并终止于 enum 说明符的末尾（与之相反，无作用域枚举项在 enum 说明符的结束后仍在作用域中）：

enum e1_t { // 无作用域枚举
  A,
  B = A*2
}; // A 与 B 的作用域不结束

enum class e2_t { // 有作用域枚举
    SA,
    SB = SA*2 // SA 在作用域中
}; // SA 与 SB 的作用域结束

e1_t e1 = B; // OK ： B 在作用域中
// e2_t e2 = SB; // 错误： SB 不在作用域中
e2_t e2 = e2_t::SB; // OK

模板形参作用域

模板形参名的潜在作用域直接开始于其声明点，并持续到于其中引入了它的最小模板声明的末尾。具体而言，模板形参能用于其后的模板形参的声明及基类的指定，但不能用于其前的模板形参的声明。

template< typename T, // T 的作用域开始
          T* p,       // T 能用于非类型形参
          class U = T // T 能用作默认类型
        >
class X : public Array<T> // T 能用于基类名
{
   // T 还能在体内使用
}; // T 与 U 的作用域结束， X 的作用域持续

模板模板形参的形参名的潜在作用域，是该名字出现于其中的最小模板形参列表

template< template< // 模板模板形参
                    typename Y,     // Y 的作用域开始
                    typename G = Y // Y 在作用域中
                  > // Y 与 G 的作用域结束
          class T,
//          typename U = Y // 错误： Y 不在作用域中
          typename U
        >
class X
{
}; // T 与 U 的作用域结束

与其他嵌套作用域类似，模板形参名在其自身的持续期间隐藏来自外层作用域的相同名字：

typedef int N;
template< N X, // int 类型的非类型模板形参
          typename N, // 此 N 的作用域开始，::N 的作用域中断
          template<N Y> class T // 此处的 N 是模板形参，非 int
         > struct A;

声明点

作用域始于声明点，它定位如下：

对于简单声明所引入的变量和其他名字，声明点紧随该名字的声明符之后，且在其初始化器之前（若其存在）：

unsigned char x = 32; // 第一个 'x' 的作用域开始
{
    unsigned char x = x; // 第二个 'x' 的作用域在初始化器（= x）前开始
                         // 这导致第二个 'x' 不以值 32 初始化，
                         // 而是以其自身的不确定值初始化
}
std::function<int(int)> f = [&](int n){return n>1 ? n*f(n-1) : n;};
           // lambda 内的函数对象名 'f' 在作用域中，
           // 而且能正确地被按引用俘获，给出递归函数
const int x = 2; // 第一个 'x' 的作用域开始
{
    int x[x] = {}; // 第二个 x 的作用域在初始化器（= {}）前，但在声明器（x[x]）后开始。
                   // 在声明器内，外层 'x' 仍在作用域中，这声明了一个含有 2 个 int 元素的数组。
}

类或类模板的声明点紧随其类头中所出现的命名该类的标识符（或命名该模板特化的 模板标识）之后，并且在基类列表内已处于作用域中：

// 名称 'S' 在其出现后立即处于作用域中，
// 故它能用于基类列表
struct S: std::enable_shared_from_this<S>
{
};

枚举的声明点紧随 enum 说明符或笼统枚举声明（取决于先使用者）中所出现的命名它的标识符之后：

enum E : int { // E 已在作用域中
    A = sizeof(E)
};

类型别名或别名模板的声明点紧随该别名所代表的类型标识之后：

using T = int; // T 的声明点在分号处
using T = T;   // 同 T = int

枚举项的声明点紧随其定义之后（而非在初始化器之前，这点不同于变量）：

const int x = 12;
{
    enum {
        x = x + 1, // 声明点在逗号处，x 初始化为 13
        y = x + 1  // 枚举项 x 在作用域中，y 初始化为 14
    };
}

不指名构造函数的using 声明内的声明符的声明点紧随该声明符之后：

template<int N>
class base {
protected:
    static const int next = N + 1;
    static const int value = N;
};

struct derived : base<0>, base<1>, base<2> {
    using base<0>::next, // next 现在在作用域中
          base<next>::value; // derived::value 为 1
};

注入类名 的声明点紧随其类（或类模板）定义的开花括号之后

template<typename T>
struct Array
// : std::enable_shared_from_this<Array> // 错误：注入类名不在作用域中
   : std::enable_shared_from_this< Array<T> > // OK ：模板名 Array 在作用域中
{ // 注入类名 Array 现在在作用域中，如同为公开成员名
    Array* p; // 指向 Array<T> 的指针
};

函数局部预定义变量 __func__ 的声明点紧接函数定义的函数体之前。

 (C++11 起)

结构化绑定的声明点紧随该结构化绑定声明的标识符列表之后，但结构化绑定的初始化器禁止提及其所引入的任何名字。

 (C++17 起)

声明于基于范围的 for 语句的范围声明的变量或结构化绑定 (C++17 起)的声明点紧随相应的范围表达式之后：

std::vector<int> x;

for (auto x : x) { // OK ：第二个 x 指代 std::vector<int>
// 循环体内 x 指代循环变量
}
 (C++11 起)

模板形参的声明点紧随其完整模板形参（包括可选的默认实参）之后：

typedef unsigned char T;
template<class T
  = T               // 查找找到 unsigned char 的 typedef 名
  , T               // 查找找到模板形参
    N = 0> struct A { };
本节未完成
原因：[basic.scope.pdecl] 的剩余内容

引用

  • C++17 标准（ISO/IEC 14882:2017）：
  • 6.3 Scope [basic.scope]
  • C++14 标准（ISO/IEC 14882:2014）：
  • 3.3 Scope [basic.scope]
  • C++11 标准（ISO/IEC 14882:2011）：
  • 3.3 Scope [basic.scope]
  • C++98 标准（ISO/IEC 14882:1998）：
  • 3.3 Declarative regions and scopes [basic.scope]

参阅


SFINAE

< cpp‎ | language

“替换失败不是错误” (Substitution Failure Is Not An Error)

在函数模板的重载决议中会应用此规则：当模板形参在替换成显式指定的类型或推导出的类型失败时，从重载集中丢弃这个特化，而非导致编译失败。

此特性被用于模板元编程。

解释

对函数模板形参进行两次替换（由模板实参所替代）：

  • 显式指定的模板实参在模板实参推导前替换
  • 推导出的实参和从默认项获得的实参在模板实参推导后替换

替换发生于

  • 函数类型中使用的所有类型（包括返回类型和所有形参的类型）
  • 各个模板形参声明中使用的所有类型
  • 函数类型中使用的所有表达式
  • 各个模板形参声明中使用的所有表达式
 (C++11 起)
  • explicit 说明符中使用的所有表达式
 (C++20 起)

以上类型或表达式在以用来替换的实参写出时谬构（并带有必要的诊断）的场合是替换失败。

只有在函数类型或其模板形参类型或其 explicit 说明符 (C++20 起)的立即语境中的类型与表达式中的失败是 SFINAE 错误。如果对替换后的类型/表达式的求值导致副作用，例如实例化某模板特化、生成某隐式定义的成员函数等，那么这些副作用中的错误被当做硬错误。lambda 表达式不被当作是立即语境的一部分。 (C++20 起)

本节未完成
原因：含有此类影响的小示例

替换以词法序进行，并在遇到失败时终止。

如果多个声明具有不同的词法顺序（例如，某个函数模板声明为具有尾随返回类型，它在某个形参之后替换，然后被重声明为具有常规返回类型，它则在该形参之前替换），而这会导致模板实例化以不同顺序出现或完全不出现，那么程序谬构；不要求诊断。

 (C++11 起)
template<typename A>
struct B { using type = typename A::type; };

template<
    class T,
    class U = typename T::type,    // 如果 T 没有成员 type 那么就是 SFINAE 失败
    class V = typename B<T>::type> // 如果 T 没有成员 type 那么就是硬错误
                                   // （经由 CWG 1227 保证不出现，
                                   // 因为到 U 的默认模板实参中的替换会首先失败）
void foo (int);

template<class T>
typename T::type h(typename B<T>::type);

template<class T>
auto h(typename B<T>::type) -> typename T::type; // 重声明

template<class T>
void h(...) {}

using R = decltype(h<int>(0));     // 谬构，不要求诊断

类型 SFINAE

下列类型的错误是 SFINAE 错误：

  • 试图实例化含有多个不同长度的包的包展开
 (C++11 起)
  • 试图创建 void 的数组，引用的数组，函数的数组，负大小的数组，非整型大小的数组，或者零大小的数组：
template<int I>
void div(char(*)[I % 2 == 0] = 0)
{
    // 当 I 是偶数时选择这个重载
}

template<int I>
void div(char(*)[I % 2 == 1] = 0)
{
    // 当 I 是奇数时选择这个重载
}
  • 试图在作用域解析运算符 :: 左侧使用类和枚举以外的类型：
template<class T>
int f(typename T::B*);

template<class T>
int f(T);

int i = f<int>(0); // 使用第二个重载
  • 试图使用类型的成员，其中
  • 类型不包含指定成员
  • 在要求类型的地方，指定成员不是类型
  • 在要求模板的地方，指定成员不是模板
  • 在要求非类型的地方，指定成员不是非类型
templat <int I>
struct X {};

template<template<class T> class>
struct Z {};

template<class T>
void f(typename T::Y*) {}

template<class T>
void g(X<T::N>*) {}

template<class T>
void h(Z<T::template TT>*) {}

struct A {};
struct B { int Y; };
struct C { typedef int N; };
struct D { typedef int TT; };
struct B1 { typedef int Y; };
struct C1 { static const int N = 0; };
struct D1
{
    template<typename T>
    struct TT {};
};

int main()
{
    // 下列各个情况推导失败：
    f<A>(0); // 不含成员 Y
    f<B>(0); // B 的 Y 成员不是类型
    g<C>(0); // C 的 N 成员不是非类型
    h<D>(0); // D 的 TT 成员不是模板

    // 下列各个情况推导成功：
    f<B1>(0);
    g<C1>(0);
    h<D1>(0);
}
// 未完成：需要演示重载决议，而不只是失败
  • 试图创建指向引用的指针
  • 试图创建到 void 的引用
  • 试图创建指向 T 的成员的指针，其中 T 不是类类型：
template<typename T>
class is_class
{
    typedef char yes[1];
    typedef char no[2];

    template<typename C>
    static yes& test(int C::*); // 如果 C 是类类型就选择它

    template<typename C>
    static no& test(...);       // 否则选择它
public:
    static bool const value = sizeof(test<T>(0)) == sizeof(yes);
};
  • 试图将非法类型给予非类型模板形参：
template<class T, T>
struct S {};

template<class T>
int f(S<T, T()>*);

struct X {};
int i0 = f<X>(0);
// 未完成：需要演示重载决议，而不只是失败
  • 试图在以下语境中进行非法转换：
  • 模板实参表达式
  • 函数声明中使用的表达式：
template<class T, T*>
int f(int);

int i2 = f<int,1>(0); // 不能将 1 转换为 int*
// 未完成：需要演示重载决议，而非仅是失败
  • 试图创建形参类型为 void 的函数类型
  • 试图创建返回数组类型或函数类型的函数类型

表达式 SFINAE

C++11 前，只有在类型中使用的常量表达式（例如数组边界）才要求被当做 SFINAE（而非硬错误）。

 (C++11 前)

下列表达式错误是 SFINAE 错误：

  • 模板形参类型中使用的谬构表达式
  • 函数类型中使用的谬构表达式
struct X {};
struct Y { Y(X){} }; // X 可以转换到 Y

template<class T>
auto f(T t1, T t2) -> decltype(t1 + t2); // 重载 #1

X f(Y, Y);                               // 重载 #2

X x1, x2;
X x3 = f(x1, x2);  // 推导在 #1 上失败（表达式 x1+x2 为谬构）
                   // 重载集中只有 #2，调用它
 (C++11 起)

部分特化中的 SFINAE

在确定一个类或变量 (C++14 起)模板的特化是由部分特化还是主模板生成的时候也会出现推导与替换。在这种确定期间，编译器不会把替换失败当作硬错误，反而像涉及函数模板的重载决议中一样忽略对应的部分特化声明。

// 主模板处理无法引用的类型：
template<class T, class = void>
struct reference_traits
{
    using add_lref = T;
    using add_rref = T;
};

// 特化识别可以引用的类型：
template<class T>
struct reference_traits<T, std::void_t<T&>>
{
    using add_lref = T&;
    using add_rref = T&&;
};

template<class T>
using add_lvalue_reference_t = typename reference_traits<T>::add_lref;

template<class T>
using add_rvalue_reference_t = typename reference_traits<T>::add_rref;

注：当前部分特化 SFINAE 未被标准正式支持（参阅 CWG 问题 2054），然而标准库扩展 TS 自版本 2 起要求它能起效（参阅检测手法）。

库支持

标准库组件 std::enable_if 允许创建替换失败，以基于某个在编译时求值的条件来启用或禁用特定的重载。

另外，许多类型特性在适合的编译器扩展不可用时必须以 SFINAE 实现。

 (C++11 起)

标准库组件 std::void_t 是另一个简化部分特化 SFINAE 的应用的工具元函数。

 (C++17 起)

替代方案

只要可用，标签派发 、if constexpr (C++17 起)以及概念 (C++20 起)通常都比直接使用 SFINAE 更好。

如果只想要条件性的编译时错误，static_assert 通常比 SFINAE 更适合。

 (C++11 起)

示例

一种常见手法，是在返回类型上使用表达式 SFINAE，其中表达式使用逗号运算符，其左子表达式是所检验的（转型到 void 以确保不会选择返回类型上的用户定义逗号运算符），而右子表达式具有期望函数返回的类型。

#include <iostream>

// 此重载始终在重载集中
// 省略号形参对于重载决议具有最低等级
void test(...)
{
    std::cout << "调用了保底重载\n";
}

// 如果 C 是类的引用类型且 F 是指向 C 的成员函数的指针，
// 那么这个重载会被添加到重载集
template<class C, class F>
auto test(C c, F f) -> decltype((void)(c.*f)(), void())
{
    std::cout << "调用了引用重载\n";
}

// 如果 C 是类的指针类型且 F 是指向 C 的成员函数的指针，
// 那么这个重载会被添加到重载集
template<class C, class F>
auto test(C c, F f) -> decltype((void)((c->*f)()), void())
{
    std::cout << "调用了指针重载\n";
}

struct X { void f() {} };

int main()
{
    X x;
    test(x, &X::f);
    test(&x, &X::f);
    test(42, 1337);
}

输出：

调用了引用重载
调用了指针重载
调用了保底重载

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 295 | C++98 | 创建 cv 限定的函数类型可能会导致替换失败 | 使之不是失败，舍弃 cv 限定
CWG 1227 | C++98 | 替换顺序未指明 | 与词法顺序相同
CWG 2322 | C++11 | 不同词法顺序的声明会导致模板实例化以不同顺序或完全不出现 | 这种情况为谬构，不要求诊断


sizeof... 运算符 (C++11 起)

< cpp‎ | language

查询形参包中的元素数量。

语法

sizeof...( 形参包 )

返回 std::size_t 类型的常量。

解释

返回形参包中的元素数量。

关键词

sizeof

示例

#include <array>
#include <iostream>
#include <type_traits>

template<typename... Ts>
constexpr auto make_array(Ts&&... ts)
{
    using CT = std::common_type_t<Ts...>;
    return std::array<CT, sizeof...(Ts)>{std::forward<CT>(ts)...};
}

int main()
{
    std::array<double, 4ul> arr = make_array(1, 2.71f, 3.14, '*');
    std::cout << "arr = { ";
    for (auto s{arr.size()}; double elem : arr)
        std::cout << elem << (--s ? ", " : " ");
    std::cout << "}\n";
}

输出：

arr = { 1, 2.71, 3.14, 42 }

参阅

  • sizeof


sizeof 运算符

< cpp‎ | language

查询对象或类型的大小。

在需要知道对象的实际大小时使用。

语法

sizeof( 类型 ) | (1)
sizeof 表达式 | (2)

两个版本都是 std::size_t 类型的常量表达式。

解释

1) 产生类型 的对象表示的字节数。
2) 产生表达式 的类型的对象表示的字节数，假如该表达式被求值。

注解

取决于计算机架构，字节可能具有8或更多位，精确的位数记录于 CHAR_BIT。

下列 sizeof 表达式总是求值为 1：

  • sizeof(char)
  • sizeof(signed char)
  • sizeof(unsigned char)
  • sizeof(std::byte)
 (C++17 起)
  • sizeof(char8_t)
 (C++20 起)

不能对函数类型、不完整类型或位域泛左值使用 sizeof。

当应用于引用类型时，结果是被引用类型的大小。

当应用于类类型时，结果是该类的完整对象所占据的字节数，包括这种对象放入数组时所需的任何额外填充。潜在重叠的子对象所占据的字节数可以小于该对象的大小。

sizeof 的结果始终非零，即使应用于空类。

当应用于某个表达式时，sizeof 并不对表达式进行求值，并且即便表达式代表多态对象，其结果也是该表达式的静态类型的大小。不进行左值向右值、数组向指针和函数向指针转换。不过，它在形式上对纯右值实参进行临时量实质化：若实参不可析构则程序非良构。 (C++17 起)

关键词

sizeof

示例

本示例的输出对应于具有 64 位指针和 32 位 int 的系统。

#include <iostream>

struct Empty {};
struct Base { int a; };
struct Derived : Base { int b; };
struct Bit { unsigned bit: 1; };

int main()
{
    Empty e;
    Derived d;
    Base& b = d;
    [[maybe_unused]] Bit bit;
    int a[10];
    std::cout << "空类的大小：                   " << sizeof e        << "\n"
              << "指针的大小：                   " << sizeof &e       << "\n"
//            << "函数的大小：                  "  << sizeof(void())  << "\n" // 错误
//            << "不完整类型的大小：             "  << sizeof(int[])   << "\n" // 错误
//            << "位域的大小：                  "  << sizeof bit.bit  << "\n" // 错误
              << "Bit 类的大小：                " << sizeof(Bit)     << '\n'
              << "含有10个 int 的数组的大小：    "  << sizeof(int[10]) << "\n"
              << "含有10个 int 的数组的大小 (2)："  << sizeof a        << "\n"
              << "含有10个 int 的数组的长度：    "  << ((sizeof a) / (sizeof *a)) << "\n"
              << "含有10个 int 的数组的长度 (2)："  << ((sizeof a) / (sizeof a[0])) << "\n"
              << "Derived 的大小:               " << sizeof d        << "\n"
              << "通过 Base 获取 Derived 的大小：" << sizeof b        << "\n";

}

可能的输出：

空类的大小：                   1
指针的大小：                   8
Bit 类的大小：                4
含有10个 int 的数组的大小：    40
含有10个 int 的数组的大小 (2)：40
含有10个 int 的数组的长度：    10
含有10个 int 的数组的长度 (2)：10
Derived 的大小:               8
通过 Base 获取 Derived 的大小：4

参阅

alignof 运算符 (C++11) | 查询类型的对齐要求
sizeof... operator (C++11) | 查询形参包中的元素数


语句

< cpp‎ | language

语句（statement）是依序执行的 C++ 程序片段。任何函数体都是语句的序列。例如：

int main()
{
    int n = 1;                        // 声明语句
    n = n + 1;                        // 表达式语句
    std::cout << "n = " << n << '\n'; // 表达式语句
    return 0;                         // return 语句
}

C++ 包含下列类型的语句：

1) 表达式语句（expression statement）；
2) 复合语句（compound statement）；
3) 选择语句（selection statement）；
4) 循环语句（iteration statement）；
5) 跳转语句（jump statement）；
6) 声明语句（declaration statement）；
7) try 块；
8) atomic 与 synchronized 块(TM TS)。

标签

通过在语句自身之前提供后随冒号的标签，任何语句都可带有标签。

属性(可选) 标识符 : 语句 | (1)
属性(可选) case 常量表达式 : 语句 | (2)
属性(可选) default : 语句 | (3)
1) goto 的目标；
2) switch 语句中的 case 标签；
3) switch 语句中的 default 标签。

一条语句可以带有多个标签。

属性序列 属性 可以紧接标签之前出现（这种情况下它应用到标签），或紧跟在语句自身之后出现，这种情况下它应用到整条语句。

 (C++11 起)

声明于函数内并带标识符的标签（且仅有标签）在该函数内、所有内嵌块、其自身声明的前后每处都在作用域内。

一个函数中的两个标签不得拥有同一标识符。

无限定查找找不到标签：标签能与程序中任何其他实体拥有相同的名字。

void f()
{
   {
       goto label; // label 在作用域内，尽管它在后面才声明
label:;
   }
   goto label; // label 忽略块作用域
}

void g()
{
    goto label; // 错误： label 不在 g() 的作用域内
}

表达式语句

表达式后跟一个分号是一条语句。

属性(可选) 表达式(可选) ; (1)
属性 | - | (C++11 起) 可选的任意数量属性的序列
表达式 | - | 一个表达式

典型 C++ 程序的大部分语句都是表达式语句，例如赋值和函数调用。

没有表达式的表达式语句被称作空语句（null statement）。它通常用来为 for 或 while 循环提供空体。它也可用于在复合语句的末尾引入标签。

复合语句

复合语句或（代码）块是花括号环绕的语句序列。

属性(可选) { 语句...(可选) } (1)

当需要一条语句，但要按顺序执行多条语句时（例如在 if 语句或循环中），可以使用复合语句：

if (x > 5)          // if 语句的开始
{                   // 块的开始
    int n = 1;      // 声明语句
    std::cout << n; // 表达式语句
}                   // 块的结束，if 语句的结束

每个复合语句都引入其自身的块作用域；在块中声明的变量在闭花括号处以逆序销毁：

int main()
{
    {                                // 块的开始
        std::ofstream f("test.txt"); // 声明语句
        f << "abc\n";                // 表达式语句
    }                                // 块结束，刷新并关闭 f
    std::ifstream f("test.txt");
    std::string str;
    f >> str;
}

选择语句

选择语句在数个控制流中选择一个。

}}
属性(可选) if constexpr(可选) ( 初始化语句(可选) 条件 ) true分支语句 | (1) |
属性(可选) if constexpr(可选) ( 初始化语句(可选) 条件 ) true分支语句 else false分支语句 | (2) |
属性(可选) switch ( 初始化语句(可选) 条件 ) 语句 | (3) |
属性(可选) if !(可选) consteval 复合语句 | (4) | (C++23 起)
属性(可选) if !(可选) consteval 复合语句 else 语句 | (5) | (C++23 起)
1) if 语句；
2) 带 else 子句的 if 语句；
3) switch 语句；
4) consteval if 语句；
5) 带 else 子句的 consteval if 语句。

循环语句

循环语句重复执行一些代码。

属性(可选) while ( 条件 ) 语句 | (1) |
属性(可选) do 语句 while ( 表达式 ) ; | (2) |
属性(可选) for ( 初始化语句 条件(可选) ; 表达式(可选) ) 语句 | (3) |
属性(可选) for ( for-范围声明 : for-范围初始化器 ) 语句 | (4) | (C++11 起)
1) while 循环；
2) do-while 循环；
3) for 循环；
4) 范围 for 循环。

跳转语句

跳转语句无条件地转移控制流。

属性(可选) break ; | (1) |
属性(可选) continue ; | (2) |
属性(可选) return 表达式(可选) ; | (3) |
属性(可选) return 花括号初始化器列表 ; | (4) | (C++11 起)
属性(可选) goto 标识符 ; | (5) |
1) break 语句；
2) continue 语句；
3) 可带表达式的 return 语句；
4) 使用列表初始化的 return 语句；
5) goto 语句。

注意：对于所有跳转语句，转移出循环、出块或回到被初始化且具有自动存储期的变量之前，会牵涉到对“ 转移发起点在作用域中而目标点不在，且具有自动存储期 ”的对象的销毁。如果有多个对象被初始化，那么销毁顺序与初始化顺序相反。

声明语句

声明语句在块中引入一个或多个标识符。

块声明 (1)
1) 细节见声明及初始化。

try 块

try 块提供当执行其他语句时捕获其所抛出的异常的能力。

属性(可选) try 复合语句 处理块序列 (1)
1) 细节见 try/catch。

atomic 与 synchronized 块

atomic 与 synchronized 块用来实现事务性内存。

synchronized 复合语句 | (1) | (TM TS)
atomic_noexcept 复合语句 | (2) | (TM TS)
atomic_cancel 复合语句 | (3) | (TM TS)
atomic_commit 复合语句 | (4) | (TM TS)
1) synchronized 块，与所有 synchronized 块在一个全序中执行；
2) 在发生异常时中止的 atomic 块；
3) 在发生异常时回滚的 atomic 块；
4) 在发生异常时提交的 atomic 块。
 (TM TS)

参阅


静态成员

< cpp‎ | language

在类定义中，关键词 static 声明不绑定到类实例的成员。

在类定义之外，它有不同含义：见存储期。

语法

static 数据成员 | (1)
static 成员函数 | (2)
1) 声明静态数据成员。
2) 声明静态成员函数。

解释

类的静态成员不与类的对象关联：它们是具有静态或线程 (C++11 起)存储期的独立变量，或者常规函数。

static 关键词只会用于静态成员在类定义中的声明，而不用于该静态成员的定义：

class X { static int n; }; // 声明（用 'static'）
int X::n = 1;              // 定义（不用 'static'）

类体内的声明不是定义，且可以将成员声明为（除 void 之外的）不完整类型，包括该成员的声明所在的类型：

struct Foo;
struct S
{
   static int a[]; // 声明，不完整类型
   static Foo x;   // 声明，不完整类型
   static S s;     // 声明，不完整类型（在其自身定义中）
};

int S::a[10]; // 定义，完整类型
struct Foo {};
Foo S::x;     // 定义，完整类型
S S::s;       // 定义，完整类型

然而如果声明使用了 constexpr 或 inline (C++17 起) 说明符，那么该成员必须声明为拥有完整类型。

 (C++11 起)

指代类 T 的静态成员 m 有两种可用的形式：限定名 T::m以及成员访问表达式 E.m 或 E->m，其中 E 分别是求值为 T 或 T* 的表达式。在同一类作用域中时，不需要限定：

struct X
{
    static void f(); // 声明
    static int n;    // 声明
};

X g() { return X(); } // 某个返回 X 的函数

void f()
{
    X::f();  // X::f 是静态成员函数的限定名
    g().f(); // g().f 是指代静态成员函数的成员访问表达式
}

int X::n = 7; // 定义

void X::f() // 定义
{
    n = 1; // X::n 在此作用域可以只要以 n 的形式进行访问
}

静态成员遵循类成员访问规则（私有、受保护、公开）。

静态成员函数

静态成员函数不关联到任何对象。调用时，它们没有 this 指针。

静态成员函数不能是 virtual、const 或 volatile 的。

静态成员函数的地址可以存储在常规的函数指针中，但不能存储在成员函数指针中。

静态数据成员

静态数据成员不关联到任何对象。即使不定义类的任何对象它们也存在。整个程序中只有一个拥有静态存储期的静态数据成员实例，除非使用关键词 thread_local，此时每个线程都有一个具有线程存储期的该对象 (C++11 起)。

静态数据成员不能是 mutable 的。

在命名空间作用域中，如果类自身具有外部连接（即不是无名命名空间的成员），那么类的静态数据成员也具有外部连接。局部类（定义于函数内部的类）和无名类，包括无名类的成员类，不能拥有静态数据成员。

静态数据成员可以声明为 inline。 inline 静态数据成员可以在类定义中定义，而且可以指定初始化器。它不需要类外定义：

struct X
{
    inline static int n = 1;
};
 (C++17 起)

常量静态成员

如果整型或枚举类型的静态数据成员被声明为 const（且非 volatile），那么它能以其中的每个表达式均为常量表达式的初始化器直接在类定义内初始化：

struct X
{
    const static int n = 1;
    const static int m{2}; // C++11 起
    const static int k;
};
const int X::k = 3;

如果声明字面类型 (LiteralType) 的静态数据成员为 constexpr，那么它必须以其中的每个表达式均为常量表达式的初始化器直接在类定义内初始化：

struct X {
    constexpr static int arr[] = { 1, 2, 3 };        // OK
    constexpr static std::complex<double> n = {1,2}; // OK
    constexpr static int k; // 错误：constexpr static 要求初始化器
};
 (C++11 起)

如果 const 非 inline (C++17 起)静态数据成员或 constexpr 静态数据成员 (C++11 起)
(C++17 前)被 ODR 式使用，那么仍然需要命名空间作用域的定义，但它不能有初始化器。可以提供定义，尽管这是冗余的 (C++17 起)。

struct X {
    static const int n = 1;
    static constexpr int m = 4;
};
const int *p = &X::n, *q = &X::m; // 因为X::n 与 X::m 被 ODR 式使用
const int X::n;             // ……所以需要定义
constexpr int X::m;         // ……（但 C++17 中的 X::m 不需要）

如果静态数据成员被声明为 constexpr，那么它隐含为 inline 且不必在命名空间作用域重声明。这种无初始化器的重声明（之前则需要，如上所示）仍然得到容许，但已被弃用。

 (C++17 起)

引用

  • C++11 标准（ISO/IEC 14882:2011）：
  • 9.4 Static members [class.static]
  • C++98 标准（ISO/IEC 14882:1998）：
  • 9.4 Static members [class.static]

参阅

  • static 存储说明符


static_assert 声明

< cpp‎ | language

进行编译时断言检查。

语法

static_assert ( 布尔常量表达式 , 消息 ) | (C++11 起)
static_assert ( 布尔常量表达式 ) | (C++17 起)

解释

布尔常量表达式 -
按语境转换成 bool 类型的常量表达式 | (C++23 前)
按语境转换成 bool 的表达式，其中转换为常量表达式 | (C++23 起)
消息 - 当 布尔常量表达式 为 false 时将出现的可选的 (C++17 起)字符串字面量

static_assert 声明可以出现在命名空间和块作用域中（作为块声明），也可以在类体中（作为成员声明）。

如果 布尔常量表达式 返回 true，那么该声明没有效果。否则将发布编译时错误，且当存在 消息时诊断消息中会包含其文本。

消息 可以省略。

 (C++17 起)

除了到 bool 的非窄化 整型转换以外，不允许内建转换。

 (C++23 前)

注解

因为 消息 必须是字符串字面量，所以它不能容纳动态信息，乃至自身并非字符串字面量的常量表达式。特别是它不能容纳模板类型实参的名字。

示例

#include <type_traits>

template <class T>
void swap(T& a, T& b) noexcept
{
    static_assert(std::is_copy_constructible<T>::value,
                  "交换需要可复制");
    static_assert(std::is_nothrow_copy_constructible<T>::value
               && std::is_nothrow_copy_assignable<T>::value,
                  "交换需要可复制及可赋值，且无异常抛出");
    auto c = b;
    b = a;
    a = c;
}

template <class T>
struct data_structure
{
    static_assert(std::is_default_constructible<T>::value,
                  "数据结构要求元素可默认构造");
};

struct no_copy
{
    no_copy ( const no_copy& ) = delete;
    no_copy () = default;
};

struct no_default
{
    no_default () = delete;
};

int main()
{
    int a, b;
    swap(a, b);

    no_copy nc_a, nc_b;
    swap(nc_a, nc_b); // 1

    data_structure<int> ds_ok;
    data_structure<no_default> ds_error; // 2
}

可能的输出：

1：错误：静态断言失败：交换需要可复制
2：错误：静态断言失败：数据结构要求元素可默认构造

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 2039 | C++11 | 只要求转换前的表达式是常量 | 转换本身必须也在常量表达式中合法

参阅

error | 显示给定的错误信息并使程序非良构
assert | 若用户指定的条件非 true 则中断程序。可以在发行构建中禁用 (宏函数)
abort | 导致非正常的程序终止（不进行清理） (函数)
exit | 导致正常的程序终止并进行清理 (函数)
enable_if (C++11) | 条件性地从重载决议移除函数重载或模板特化 (类模板)
类型特征 (C++11) | 定义了一个编译期基于模板的用来查询或修改类型性质的接口


static_cast 转换

< cpp‎ | language

用隐式和用户定义转换的组合在类型间转换。

语法

static_cast < 新类型 > ( 表达式 )

返回 新类型 类型的值。

解释

只有下列转换在不去除常量性或易变性的场合才能用 static_cast 执行。

1) 如果存在从 表达式 到 新类型 的隐式转换序列，或者如果针对以 表达式 对 新类型 类型的对象或引用所进行的直接初始化的重载决议找到至少一个可行函数，则 static_cast<新类型>(表达式) 返回如同以 新类型 Temp(表达式); 所初始化的一个虚构变量 Temp，它可能涉及隐式转换，对 新类型 的构造函数的调用，或对用户定义转换运算符的调用。对于非引用的 新类型，static_cast 纯右值表达式的结果对象是其直接初始化的对象。 (C++17 起)
2) 如果 新类型 是指向某类类型 D 的指针或引用，且 表达式 的类型是其非虚基类 B 的左值或指向它的指针纯右值，则 static_cast 进行向下转型（downcast）。如果 B 是 D 的有歧义的，不可访问的或虚的基类（或虚基类的基类），则此向下转型非良构。这种 static_cast 并不在运行时检查该对象的运行时类型确实为 D，因此它只能在该前提条件通过其他方法保证时，例如在实现静多态时，才能安全使用。安全的向下转型可以用 dynamic_cast 执行。
struct B { };
struct D : B { };
D d;
B& br = d;
static_cast<D&>(br); // 该左值指代原来的 d 对象
3) 如果 新类型 是右值引用类型，则 static_cast 将泛左值、类纯右值或数组纯右值 (C++17 前)任何左值 (C++17 起) 表达式 的值转换为与该表达式指代相同对象，或指代其基类子对象（取决于 新类型）的亡值。如果目标类型是表达式的不可访问或有歧义基类，则程序非良构。如果表达式是位域左值，则它首先被转换成底层类型的纯右值。这种 static_cast 用于在 std::move 中实现移动语义。
 (C++11 起)
4) 如果 新类型 是（可为 cv 限定的）void 类型，则 static_cast 在求值 表达式 后舍弃其值。
5) 如果存在从 新类型 到 表达式 类型的标准转换序列，且它不包含左值到右值、数组到指针、函数到指针、空指针、空成员指针、函数指针 (C++17 起)或布尔转换，则 static_cast 能进行该隐式转换的逆转换。
6) 如果从 表达式 到 新类型 的转换涉及左值到右值、数组到指针或函数到指针转换，则 static_cast 可以显式执行该转换。
7) 有作用域枚举类型(C++11)能转换成整数或浮点类型。
当目标类型为（可为 cv 限定的）bool 类型时，如果原值为零则结果为 false，而对所有其他值结果为 true。对于其余整型类型，若该枚举的值能以目标类型表示，则结果为其值，否则结果未指明。 | (C++20 前)
其结果与从枚举的底层类型隐式转换成目标类型的结果相同。 | (C++20 起)
8) 整数或枚举类型值可转换为任何完整枚举类型。
  • 如果底层类型不固定，则当 表达式 的值落在范围（范围是大到足以保有目标枚举的所有枚举项的最小位域的所有可能值）外时，则行为未定义。
  • 如果底层类型固定，则其结果与转换原值到枚举的底层类型再到该枚举类型的结果相同。
浮点类型的值也可转换为任何完整枚举类型。
  • 其结果与转换原值到枚举的底层类型再到该枚举类型的结果相同。
9) 指向某类 D 的成员的指针可以向上转型（upcast）为指向其无歧义、可访问的基类 B 的成员。这种 static_cast 不检查所指向对象的运行时类型是否包含该成员。
10) 指向（可为 cv 限定的）void 的指针类型的纯右值可转换到指向任何对象的指针类型。如果原指针值所表示的内存中字节地址不满足目标类型的对齐要求，则结果指针值未指明。否则，如果原指针值指向对象 a，且存在与 a 指针可互转换（定义于下文）的目标类型（忽略 cv 限定）的对象 b，则结果为指向 b 的指针。否则指针值不改变。任何指针转换到 void 指针再转换回原（或更为 cv 限定的）类型的指针，都保持其原值。

同所有转型表达式，结果是：

  • 左值，如果 新类型 是左值引用或到函数类型的右值引用；
  • 亡值，如果 新类型 是到对象类型的右值引用；
  • 否则为纯右值。

满足以下条件时，两个对象 a 与 b 指针可互转换（pointer-interconvertible）：

  • 它们是同一个对象，或
  • 一个是 union 对象而另一个是该对象的非静态数据成员，或
  • 一个是标准布局的类对象，而另一个是该对象的首个非静态数据成员，或如果该对象没有非静态数据成员，则为该对象的任何基类子对象，或
  • 存在对象 c 使得 a 与 c 指针可互转换，而 c 与 b 指针可互转换。
union U { int a; double b; } u;
void* x = &u;                        // x 的值为“指向 u 的指针”
double* y = static_cast<double*>(x); // y 的值为“指向 u.b 的指针”
char* z = static_cast<char*>(x);     // z 的值为“指向 u 的指针”

注解

static_cast 也能用于通过进行到指定类型的函数到指针转换，来消解函数重载的歧义，如

std::for_each(files.begin(), files.end(),
              static_cast<std::ostream&(*)(std::ostream&)>(std::flush));

关键词

static_cast

示例

#include <vector>
#include <iostream>

struct B {
    int m = 0;
    void hello() const {
        std::cout << "Hello world，这里是 B！\n";
    }
};
struct D : B {
    void hello() const {
        std::cout << "Hello world，这里是 D！\n";
    }
};

enum class E { ONE = 1, TWO, THREE };
enum EU { ONE = 1, TWO, THREE };

int main()
{
    // 1: 初始化转换
    int n = static_cast<int>(3.14);
    std::cout << "n = " << n << '\n';
    std::vector<int> v = static_cast<std::vector<int>>(10);
    std::cout << "v.size() = " << v.size() << '\n';

    // 2: 静态向下转型
    D d;
    B& br = d; // 通过隐式转换向上转型
    br.hello();
    D& another_d = static_cast<D&>(br); // 向下转型
    another_d.hello();

    // 3: 左值到右值
    std::vector<int> v2 = static_cast<std::vector<int>&&>(v);
    std::cout << "移动后，v.size() = " << v.size() << '\n';

    // 4: 弃值表达式
    static_cast<void>(v2.size());

    // 5. 隐式转换的逆
    void* nv = &n;
    int* ni = static_cast<int*>(nv);
    std::cout << "*ni = " << *ni << '\n';

    // 6. 数组到指针后随向上转型
    D a[10];
    B* dp = static_cast<B*>(a);

    // 7. 有作用域枚举到 int 或 float
    E e = E::ONE;
    int one = static_cast<int>(e);
    std::cout << one << '\n';

    // 8. int 到枚举，枚举到另一枚举
    E e2 = static_cast<E>(one);
    EU eu = static_cast<EU>(e2);

    // 9. 指向成员指针向上转型
    int D::*pm = &D::m;
    std::cout << br.*static_cast<int B::*>(pm) << '\n';

    // 10. void* 到任何类型
    void* voidp = &e;
    std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}

输出：

n = 3
v.size() = 10
Hello world，这里是 B！
Hello world，这里是 D！
移动后，v.size() = 0
*ni = 3
1
0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 2254 | C++11 | 无数据成员的标准布局类对象可指针间转换到其首个基类 | 可指针间转换到其任何基类

参阅

  • const_cast
  • dynamic_cast
  • reinterpret_cast
  • 显式转型
  • 隐式转换


字符串字面量

< cpp‎ | language

语法

"s字符序列(可选)" | (1) |
L"s字符序列(可选)" | (2) |
u8"s字符序列(可选)" | (3) | (C++11 起)
u"s字符序列(可选)" | (4) | (C++11 起)
U"s字符序列(可选)" | (5) | (C++11 起)
前缀(可选) R"d字符序列(可选)(r字符序列(可选))d字符序列(可选)" | (6) | (C++11 起)

解释

s字符序列 - 一个或多个s字符
s字符 - 下列之一：
  • 一个基础s字符
  • 一个转义序列，定义见转义序列
  • 一个通用字符名，定义见转义序列
基础s字符 - 来自源字符集 (C++23 前)翻译字符集 (C++23 起)去掉双引号（"）、反斜杠（\）和换行符后的字符
前缀 - L、u8、u、U 之一
d字符序列 - 一个或多个d字符，最多十六个
d字符 - 来自基础源字符集 (C++23 前)基础字符集 (C++23 起)去掉括号、反斜杠和空格后的字符
r字符序列 - 一个或多个r字符，不得包含闭序列 )d字符序列"
r字符 - 来自源字符集 (C++23 前)翻译字符集 (C++23 起)的字符

1) 通常字符串字面量。无前缀字符串字面量的类型是 const char[N]，其中 N 是以执行窄编码 (C++23 前)通常字面量编码 (C++23 起)的编码单元计的字符串的大小，包含空终止符。
2) 宽字符串字面量。L"..." 字符串字面量的类型是 const wchar_t[N]，其中 N 是以执行宽编码 (C++23 前)宽字面量编码 (C++23 起)的编码单元计的字符串的大小，包含空终止符。
3) UTF-8 字符串字面量。u8"..." 字符串字面量的类型是 const char[N] (C++20 前)const char8_t[N] (C++20 起)，其中 N 是以 UTF-8 编码单元计的字符串的大小，包含空终止符。
4) UTF-16 字符串字面量。u"..." 字符串字面量的类型是 const char16_t[N]，其中 N 是以 UTF-16 编码单元计的字符串的大小，包含空终止符。
5) UTF-32 字符串字面量。U"..." 字符串字面量的类型是 const char32_t[N]，其中 N 是以 UTF-32 编码单元计的字符串的大小，包含空终止符。
6) 原始字符串字面量。用于避免转义任何字符。分隔符间的任何内容都成为字符串的一部分。如果存在 前缀 则具有与上述相同的含义。结尾的 d字符序列需要和开头的 d字符序列一致。

每个（来自非原始字符串字面量的）s字符 或（来自原始字符串字面量的）r字符 (C++11 起)均初始化字符串字面量对象中的对应元素。一个 s字符 或 r字符 (C++11 起)当且仅当它被字符串字面量的关联字符编码中多于一个编码单元的序列表示时对应多于一个元素。

如果字符缺少在关联字符编码中的表示，

  • 如果字符串字面量为通常字符串字面量或宽字符串字面量，则它是条件性支持且编码的是实现定义的编码单元序列；
  • 否则（字符串字面量为 UTF 编码），该字符串字面量非良构。
 (C++23 起)

每个数值转义序列对应单个元素。如果转义序列所指定的值适合元素类型的无符号版本，则元素拥有（可能在转换到元素类型后的）指定值；否则（即指定值在范围外）该字符串字面量非良构。 (C++23 起)

拼接

在翻译阶段 6（预处理器之后），毗邻的字符串字面量会被拼接起来。即 "Hello," " world!" 生成（单个）字符串 "Hello, world!"。如果两个字符串的编码前缀相同（或者都没有编码前缀），则产生的字符串将拥有相同的编码前缀（或无前缀）。

如果一个字符串有编码前缀而另一个没有，则无编码前缀者被认为拥有与另一者相同的编码前缀。

L"Δx = %" PRId16 // 在阶段 4，PRId16 展开成 "d"
                 // 在阶段 6，L"Δx = %" 与 "d" 组成 L"Δx = %d"

如果 UTF-8 字符串字面量与宽字符串字面量毗邻，则程序非良构。

 (C++11 起)
实现可能支持或不支持任何其他编码前缀组合。这种拼接的结果是实现定义的。 | (C++11 起) (C++23 前)
任何其他编码前缀组合为非良构。 | (C++23 起)

注解

字符串字面量始终要追加空字符（'\0'、L'\0'、char16_t() 等）：因此，字符串字面量 "Hello" 是 const char[6]，并保有字符 'H'、'e'、'l'、'l'、'o' 及 '\0'。

通常字符串字面量 (1) 和宽字符串字面量 (2) 的编码是实现定义的。例如，gcc 用命令行选项 -fexec-charset 与 -fwide-exec-charset 选择它们。

字符串字面量拥有静态存储期，从而在程序生存期间存在于内存中。

字符串字面量可用于初始化字符数组。如果数组初始化类似 char str[] = "foo";，那么 str 将含有字符串 "foo" 的副本。

字符串字面量能否重叠以及同一字符串字面量的相继求值是否产生同一对象是未指明的。这意味着以指针比较时，相同的字符串字面量比较时可能相等或不相等。

bool b = "bar" == 3+"foobar" // 可为 true 或 false，由实现定义

试图修改字符串字面量导致未定义行为：它们可以存储于只读存储（例如 .rodata）或与其他字符串字面量合并：

const char* pc = "Hello";
char* p = const_cast<char*>(pc);
p[0] = 'M'; // 未定义行为
字符串字面量可转换为且可赋值给非 const 的 char* 或 wchar_t* 以与 C 兼容， C 中字符串字面量类型为 char[N] 与 wchar_t[N]。 这种隐式转换被弃用。 | (C++11 前)
字符串字面量不可转换为或赋值给非 const 的 CharT*。若想要这种转换则必须用显式转型（例如 const_cast）。 | (C++11 起)

字符串字面量不需要是一个空终止字符序列：如果字符串字面量包含内嵌的空字符，那么它表示含有多于一条字符串的数组。

const char* p = "abc\0def"; // std::strlen(p) == 3 ，但数组大小为 8

如果字符串字面量中一个十六进制转义后随一个合法十六进制数位，则可能因非法转义序列而编译失败。此时可以拼接字符串：

//const char* p = "\xfff"; // 错误：十六进制转义序列在范围外
const char* p = "\xff""f"; // OK ：此字面量是保有 {'\xff','f','\0'} 的 const char[3]

尽管 C++11 中允许混合的宽字符串字面量连接，所有已知的 C++ 编译器都拒绝这种连接，而其使用经验是未知的。结果 C++23 中移除了对混合宽字符串字面量连接的允许。

示例

#include <iostream>

char array1[] = "Foo" "bar";
// 同
char array2[] = { 'F', 'o', 'o', 'b', 'a', 'r', '\0' };

const char* s1 = R"foo(
Hello
  World
)foo";
// 同
const char* s2 = "\nHello\n  World\n";
// 同
const char* s3 = "\n"
                 "Hello\n"
                 "  World\n";
int main()
{
    std::cout << array1 << '\n';
    std::cout << array2 << '\n';
    std::cout << s1 << s2 << s3;
}

输出：

Foobar
Foobar

Hello
  World

Hello
  World

Hello
  World

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1823 | C++98 | 字符串字面量是否有别是实现定义的 | 区别性未指明，相同字符串字面量能产生不同对象

参阅

用户定义字面量 (C++11) 拥有用户定义后缀的字面量


结构化绑定声明 (C++17 起)

< cpp‎ | language

绑定指定名称到初始化器的子对象或元素。

类似引用，结构化绑定是既存对象的别名。不同于引用的是，结构化绑定的类型不必为引用类型。

属性(可选) cv-auto 引用运算符(可选) [ 标识符列表 ] = 表达式 ; | (1)
属性(可选) cv-auto 引用运算符(可选) [ 标识符列表 ] { 表达式 } ; | (2)
属性(可选) cv-auto 引用运算符(可选) [ 标识符列表 ] ( 表达式 ) ; | (3)
属性 | - | 任意数量的属性的序列
cv-auto | - | 可有 cv 限定的 auto 类型说明符，也可以包含存储类说明符 static 或 thread_local ；在 cv 限定符中包含 volatile 是被弃用的 (C++20 起)
引用运算符 | - | & 或 && 之一
标识符列表 | - | 此声明所引入的各标识符的逗号分隔的列表
表达式 | - | 顶层没有逗号运算符的表达式（文法上为赋值表达式），且具有数组或非联合类之一的类型。如果 表达式 涉及任何来自 标识符列表 的名字，则声明非良构。

结构化绑定声明将 标识符列表 中的所有标识符引入作为其外围作用域中的名字，并将它们绑定到 表达式 所指代的对象的各个子对象或元素。以此方式引入的绑定被称作结构化绑定。

结构化绑定声明首先引入一个唯一命名的变量（此处以 e 指代）来保有其初始化器的值，方式如下：

  • 如果 表达式 具有数组类型 A 且不存在 引用运算符，则 e 具有类型 cv A，其中 cv 是 cv-auto 序列中的 cv 限定符，且 e 中的各个元素从 表达式 的对应元素进行复制（对于 (1)）或直接（对于 (2,3)）初始化。
  • 否则 e 如同于声明中以其名取代 [ 标识符列表 ] 一般定义。

我们用 E 代表表达式 e 的类型。（换言之，E 等价于 std::remove_reference_t <decltype((e))>）。

然后，结构化绑定可以以下三种方式之一进行绑定，取决于 E：

  • 情况 1：如果 E 是数组类型，则绑定各个名字到各个数组元素。
  • 情况 2：如果 E 是非联合类类型且 std::tuple_size <E> 是完整类型并拥有名为 value 的成员（无关乎这种成员的类型或可访问性），则使用“元组式”绑定协议。
  • 情况 3：如果 E 是非联合类类型但 std::tuple_size <E> 不是完整类型，则绑定各个名字到 E 的各个可访问数据成员。

下文对每种情况都有更详细的描述。

每个结构化绑定都有一个被引用类型，它会在后文的描述中被定义。此类型是对无括号的结构化绑定应用 decltype 所返回的类型。

情况 1：绑定数组

标识符列表 中的每个标识符均成为指代数组的对应元素的左值。标识符的数量必须等于数组的元素数量。

每个标识符的被引用类型都是数组的元素类型。数组类型 E 的 cv 限定性与其元素的相同。

int a[2] = {1,2};

auto [x,y] = a; // 创建 e[2]，复制 a 到 e，然后 x 指代 e[0]，y 指代 e[1]
auto& [xr, yr] = a; // xr 指代 a[0]，yr 指代 a[1]

情况 2：绑定元组式类型

表达式 std::tuple_size <E>::value 必须是良构的整数常量表达式，且标识符的数量必须等于 std::tuple_size <E>::value。

对于每个标识符，引入一个类型为“std::tuple_element <i, E>::type 的引用”的变量：如果它对应的初始化器是左值，那么它是左值引用，否则它是右值引用。第 i 个变量的初始化器

  • 如果在 E 的作用域中对标识符 get 按类成员访问进行的查找中，至少找到一个声明是首个模板形参为非类型形参的函数模板，则为 e.get<i>()
  • 否则为 get<i>(e)，其中 get 只进行实参依赖查找，忽略其他查找。

这些初始化器表达式中，如果实体 e 的类型是左值引用（只会在 引用运算符 是 &，或它是 && 且初始化器是左值时发生），那么 e 为左值，否则它是亡值（这实际上进行了一种完美转发），i 是 std::size_t 的纯右值，而且始终将 <i> 解释为模板形参列表。

该变量拥有与 e 相同的存储期。

然后该标识符变成指代与上述变量绑定的对象的左值。

第 i 个标识符的被引用类型是 std::tuple_element <i, E>::type。

float x{};
char  y{};
int   z{};

std::tuple<float&,char&&,int> tpl(x,std::move(y),z);
const auto& [a,b,c] = tpl;
// a 指名指代 x 的结构化绑定；decltype(a) 为 float&
// b 指名指代 y 的结构化绑定；decltype(b) 为 char&&
// c 指名指代 tpl 的第 3 元素的结构化绑定；decltype(c) 为 const int

情况 3：绑定到数据成员

E 的所有非静态数据成员必须都是 E 或 E 的同一基类的直接成员，必须在指名为 e.name 时于结构化绑定的语境中是良构的。E 不能有匿名联合体成员。标识符的数量必须等于非静态数据成员的数量。

标识符列表 中的各个标识符，按声明顺序依次成为指代 e 的各个成员的左值的名字（支持位域）；该左值的类型是 e.m_i 的类型，其中 m_i 指代第 i 个成员。

第 i 个标识符的被引用类型是 e.m_i ，如果它不是引用类型；否则是 m_i 的声明类型。

struct S {
    mutable int x1 : 2;
    volatile double y1;
};
S f();

const auto [x, y] = f(); // x 是标识 2 位位域的 int 左值
                         // y 是 const volatile double 左值

注解

对成员 get 的查找照常忽略可访问性，同时也忽略非类型模板形参的确切类型。出现私有的 template<char*> void get(); 成员将导致使用成员解释方案，即使这会导致程序非良构。

声明中 [ 之前的部分应用于隐藏变量 e，而非引入的各个标识符。

int a = 1, b = 2;
const auto& [x, y] = std::tie(a, b); // x 与 y 类型为 int&
auto [z, w] = std::tie(a, b);        // z 与 w 类型仍为 int&
assert(&z == &a);                    // 通过

如果 std::tuple_size <E> 是完整类型，那么始终使用元组式解释方案，即使这会导致程序非良构：

struct A { int x; };
namespace std {
    template<> struct tuple_size<::A> {};
}

auto [x] = A{}; // 错误；不考虑“数据成员”解释方案。

如果存在 引用运算符 且 表达式 为纯右值，则应用将引用绑定到临时量的通常规则（包括生存期延续）。这些情况下，隐藏变量 e 是绑定到从纯右值表达式实质化的临时变量，并延长其生存期的一个引用。与之前一样，如果 e 是非 const 左值引用，则绑定失败：

int a = 1;
const auto& [x] = std::make_tuple(a); // OK，非悬垂引用
auto&       [y] = std::make_tuple(a); // 错误，不能绑定 auto& 到右值 std::tuple
auto&&      [z] = std::make_tuple(a); // 同样 OK

decltype(x) 指名结构化绑定的被引用类型，其中 x 代表一个结构化绑定。在元组式的情况下，它是 std::tuple_element 所返回的类型，它可以不是引用，即使在此情况下始终会引入隐藏的引用。这相当于模拟了绑定到其各个非静态数据成员具有 tuple_element 所返回的类型的结构体的行为，而绑定自身的引用性质则只是实现细节。

std::tuple<int, int&> f();

auto [x, y] = f();       // decltype(x) 为 int
                         // decltype(y) 为 int&

const auto [z, w] = f(); // decltype(z) 为 const int
                         // decltype(w) 为 int&

Lambda 表达式不能捕获结构化绑定。

 (C++20 前)

示例

#include <set>
#include <string>
#include <iomanip>
#include <iostream>

int main() {
    std::set<std::string> myset{"hello"};
    for (int i{2}; i; --i) {
        if (auto [iter, success] = myset.insert("Hello"); success)
            std::cout << "插入成功。值为 " << std::quoted(*iter) << "。\n";
        else
            std::cout << "集合中已存在值 " << std::quoted(*iter) << "。\n";
    }
    struct BitFields {
        int b : 4 {1}, d : 4 {2}, p : 4 {3}, q : 4 {4};
        // C++20 ：位域的默认成员初始化器
    };
    {
        const auto [b, d, p, q] = BitFields{};
        std::cout << b << ' ' << d << ' ' << p << ' ' << q << '\n';
    }{
        const auto [b, d, p, q] = []{ return BitFields{4, 3, 2, 1}; }();
        std::cout << b << ' ' << d << ' ' << p << ' ' << q << '\n';
    }
}

输出：

插入成功。值为 "Hello"。
集合中已存在值 "Hello"。
1 2 3 4
4 3 2 1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0961R1 | C++17 | 元组式情况中，如果查找找到任何类型的 get 则使用成员 get | 仅当查找找到拥有非类型模板形参的函数模板才使用
P0969R0 | C++17 | 绑定到成员情况中，要求这些成员公开 | 只需要在声明的语境中可访问
CWG 2312 | C++17 | mutable 的含义在绑定到成员情况中丢失 | 保持其含义
CWG 2386 | C++17 | 总是在 tuple_size<E> 为完整类型时使用“元组式”绑定协议 | 只会在 tuple_size<E> 拥有成员 value 时才使用

参阅

tie
 创建左值引用的 tuple，或将 tuple 解包为独立对象
(函数模板)


switch 语句

< cpp‎ | language

根据条件的值，将控制流转移到若干语句之一。

语法

属性(可选) switch ( 初始化语句(可选) 条件 ) 语句
属性 - (C++11 起) 任意数量的属性
初始化语句 - (C++17 起) 下列之一：
  • 一条表达式语句（可以是空语句“;”）
  • 一条简单声明，典型地为带初始化器的变量声明，但它可以声明任意多个变量或结构化绑定 (C++17 起)
  • 一条别名声明
 (C++23 起)
注意任何 初始化语句 必须以分号 ; 结尾，这就是为什么它常被非正式描述为后随分号的表达式或声明。
条件 - 任何整型或枚举类型，或可按语境隐式转换到整型或枚举类型的类类型的表达式，或单个这种类型的非数组变量的，带花括号或等号初始化器的声明。
语句 - 任何语句（典型地为复合语句）。在 语句 中允许使用 case: 和 default: 标号，且 break; 语句具有特殊含义。
属性(可选) case 常量表达式 : 语句 | (1)
属性(可选) default : 语句 | (2)
常量表达式 - 与 条件 经过转换和整型提升后的类型相同的常量表达式

解释

switch 语句的体可拥有任意数量的 case: 标号，只要所有 常量表达式 的值（在转换/提升后）均为唯一。最多可以存在一个 default: 标号。（尽管嵌套的 switch 语句可以使用其自身的 default: 标号，或拥有和外部 switch 使用完全相同的常量的 case: 标号）

如果 条件 求值为等于 常量表达式 之一的值，那么控制被转移到用该 常量表达式 标号标记的语句。

如果 条件 求值为不匹配任何 case: 标号的值，且存在 default: 标号，那么控制被转移到带有 default: 标号的语句。

当 语句 中遇到 break 语句时退出 switch 语句：

switch(1) {
    case 1 : cout << '1'; // 打印 "1",
    case 2 : cout << '2'; // 然后打印 "2"
}
switch(1) {
    case 1 : cout << '1'; // 打印 "1"
             break;       // 然后退出 switch
    case 2 : cout << '2';
             break;
}

编译器可能在发生直落（抵达下个 case 标号而没有无 break）时发布警告，除非属性 [[fallthrough]] 紧接该标号之前出现以指示该直落是有意的。

如果使用 初始化语句，那么 switch 语句等价于

{
初始化语句
switch ( 条件 ) 语句

}

但 初始化语句 所声明的名字（如果 初始化语句 是声明）和 条件 所声明的名字（如果条件是声明）处于同一作用域中，该作用域也是 语句 的作用域。

 (C++17 起)

因为控制转移时不允许进入变量的作用域，所以如果在 语句 中遇到声明语句，那么它的作用域必须被限制在它自身的复合语句之内：

switch(1) {
    case 1: int x = 0; // 初始化
            std::cout << x << '\n';
            break;
    default: // 编译错误：跳到 default: 会在尚未初始化 'x' 的情况下进入它的作用域
             std::cout << "default\n";
             break;
}
switch(1) {
    case 1: {  int x = 0;
               std::cout << x << '\n';
               break;
            } // 'x' 的作用域在此结束
    default: std::cout << "default\n"; // 无错误
             break;
}

关键词

switch, case, default

示例

下列代码展示 switch 语句的几种用法：

#include <iostream>

int main()
{
    int i = 2;
    switch (i) {
        case 1: std::cout << "1";
        case 2: std::cout << "2";   // 执行从这个标号开始
        case 3: std::cout << "3";
        case 4:
        case 5: std::cout << "45";
                break;              // 终止后继语句的执行
        case 6: std::cout << "6";
    }

    std::cout << '\n';

    switch (i) {
        case 4: std::cout << "a";
        default: std::cout << "d"; // 没有适用的常量表达式
                                   // 因此执行 default
    }

    std::cout << '\n';

    switch (i) {
        case 4: std::cout << "a";  // 未执行任何语句
    }

    // 当在 switch 语句中使用枚举时，如果有一个枚举项没有处理，许多编译器都会发布警告
    enum color {RED, GREEN, BLUE};
    switch(RED) {
        case RED:   std::cout << "红\n"; break;
        case GREEN: std::cout << "绿\n"; break;
        case BLUE:  std::cout << "蓝\n"; break;
    }

    // C++17 的 初始化语句 语法在不存在到整型或枚举类型的隐式转换时很有用
    switch (Device dev = get_device(); dev.state())
    {
       case SLEEP: /*...*/ break;
       case READY: /*...*/ break;
       case BAD: /*...*/ break;
    }

    // 有问题的示例

    // 语句不必是复合语句
    switch(0)
        std::cout << "什么也不会发生\n";

    // 标号也不要求复合语句
    switch(int n = 1)
        case 0:
        case 1: std::cout << n << '\n';
}

输出：

2345
d
红
1

参阅

达夫设备
C/C++ 可以使用达夫设备实现协程


模板实参推导

< cpp‎ | language

为了实例化一个函数模板，需要知晓但不需要指定每个模板实参。编译器会尽可能从函数实参推导缺失的模板实参。这在尝试调用函数、取函数模板地址时，和某些其他语境中发生：

template<typename To, typename From> To convert(From f);

void g(double d)
{
    int i = convert<int>(d);    // 调用 convert<int, double>(double)
    char c = convert<char>(d);  // 调用 convert<char, double>(double)
    int(*ptr)(float) = convert; // 实例化 convert<int, float>(float)
                                // 并将它的地址储存在 ptr
}

模板运算符依赖此机制运行，因为除了将其重写为函数调用表达式之外，不存在为运算符指定模板实参的语法：

#include <iostream>

int main()
{
    std::cout << "Hello, world" << std::endl;
    // operator<< 通过 ADL 查找为 std::operator<< ，
    // 然后两次都推导为 operator<<<char, std::char_traits<char>>
    // std::endl 被推导为 &std::endl<char, std::char_traits<char>>
}

模板实参推导在函数模板名字查找（可能涉及实参依赖查找）之后，在模板实参替换（可能涉及 SFINAE）和重载决议之前进行。

当将类模板名用作正在构造的对象的类型时，也会进行模板实参推导：

std::pair p(2, 4.5);
std::tuple t(4, 3, 2.5);
std::copy_n(vi1, 3, std::back_insert_iterator(vi2));
std::for_each(vi.begin(), vi.end(), Foo([&](int i) {...}));
auto lck = std::lock_guard(foo.mtx);
std::lock_guard lck2(foo.mtx, ul);

类模板的模板实参推导在声明和显式转型表达式中发生；细节见类模板实参推导。

 (C++17 起)

从函数调用推导

模板实参推导试图确定模板实参（类型模板形参 Ti 的类型，模板模板形参 TTi 的模板，和非类型模板形参 Ii 的值），它们在经过以下列出的调整之后可以替换到每个函数形参 P 中，以产生推导的类型 A，它与函数实参 A 类型相同。

如果有多个形参，那么分别推导每一对 P/A，然后合并模板实参。如果任何一对 P/A 的推导失败或有歧义，或如果不同对推导出的模板实参不同，或如果还有任何模板实参保留还是没有被推导且没有被显式指定，那么编译失败。

如果 P 在移除引用和 cv 限定符后得到 std::initializer_list <P'> 且 A 是花括号初始化器列表，那么对该初始化器列表中的每个元素进行推导，以 P' 为形参，并以列表元素 A' 为实参：

template<class T> void f(std::initializer_list<T>);
f({1, 2, 3});  // P = std::initializer_list<T>, A = {1, 2, 3}
               // P'1 = T，A'1 = 1：推导出 T = int
               // P'2 = T，A'2 = 2：推导出 T = int
               // P'3 = T，A'3 = 3：推导出 T = int
               // OK：推导出 T = int
f({1, "abc"}); // P = std::initializer_list<T>，A = {1, "abc"}
               // P'1 = T，A'1 = 1：推导出 T = int
               // P'2 = T，A'2 = "abc"：推导出 T = const char*
               // 错误：推导失败，T 有歧义

如果 P 在移除引用和 cv 限定符后得到 P'[N] 且 A 是非空花括号初始化器列表，那么按上述方法进行推导，但如果 N 是非类型模板形参，那么它会从初始化器列表的长度被推导：

template<class T, int N> void h(T const(&)[N]);
h({1, 2, 3}); // 推导出 T = int 以及 N = 3

template<class T> void j(T const(&)[3]);
j({42}); // 推导出 T = int，数组边界不是形参，不考虑

struct Aggr { int i; int j; };
template<int N> void k(Aggr const(&)[N]);
k({1, 2, 3});       // 错误：推导失败，没有从 int 到 Aggr 的转换
k({{1}, {2}, {3}}); // OK：推导出 N = 3

template<int M, int N> void m(int const(&)[M][N]);
m({{1, 2}, {3, 4}}); // 推导出 M = 2 以及 N = 2

template<class T, int N> void n(T const(&)[N], T);
n({{1}, {2}, {3}}, Aggr()); // 推导出 T = Aggr 以及 N = 3

如果形参包作为最后的 P 出现，那么对调用的每个剩余实参类型 A 与类型 P 匹配。每个匹配为包展开中的下个位置推导模板实参：

template<class... Types> void f(Types&...);

void h(int x, float& y)
{
    const int z = x;
    f(x, y, z); // P = Types&..., A1 = x：推导出 Types... 的第一成员 = int
                // P = Types&..., A2 = y：推导出 Types... 的第二成员 = float
                // P = Types&..., A3 = z：推导出 Types... 的第三成员 = const int
                // 调用 f<int, float, const int>
}
 (C++11 起)

如果 P 是函数类型、函数指针类型或成员函数指针类型且 A 是不含函数模板的重载函数集，那么尝试以每个重载推导各模板实参。如果只有一个成功，那么使用成功的推导。如果没有或有多个成功，那么模板形参是不推导语境（见下文）：

template<class T> int f(T(*p)(T));
int g(int);
int g(char);
f(g); // P = T(*)(T)，A = 重载集
      // P = T(*)(T)，A1 = int(int)：推导出 T = int
      // P = T(*)(T)，A2 = int(char)：无法推导出 T
      // 只有一个重载有效，推导成功

推导开始前，对 P 和 A 进行下列调整：

1) 如果 P 不是引用类型，
a) 如果 A 是数组类型，那么以从数组到指针转换获得的指针类型替换 A；
b) 否则，如果 A 是函数类型，那么以从函数到指针转换获得的指针类型替换 A；
c) 否则，如果 A 是有 cv 限定的类型，那么推导时会忽略顶层 cv 限定符：
template<class T> void f(T);
int a[3];
f(a); // P = T，A = int[3]，调整为 int*：推导出 T = int*
void b(int);
f(b); // P = T，A = void(int)，调整为 void(*)(int)：推导出 T = void(*)(int)
const int c = 13;
f(c); // P = T，A = const int，调整为 int：推导出 T = int
2) 如果 P 是有 cv 限定的类型，那么推导时会忽略顶层 cv 限定符。
3) 如果 P 是引用类型，那么用 P 所引用的类型推导。
4) 如果 P 是到无 cv 限定模板形参的右值引用（也就是转发引用）且对应函数的调用实参是左值，那么将到 A 的左值引用类型用于 A 的位置进行推导（注意：这是 std::forward 的行动基础；注意：类模板实参推导中，类模板的模板形参不可能是转发引用 (C++17 起)。）：
template<class T>
int f(T&&);       // P 是到无 cv 限定类型 T 的右值引用（转发引用）
template<class T>
int g(const T&&); // P 是到有 cv 限定 T 的右值引用（非特殊）

int main()
{
    int i;
    int n1 = f(i); // 实参是左值：  调用 f<int&>(int&) （特殊情况）
    int n2 = f(0); // 实参不是左值：调用 f<int>(int&&)

//  int n3 = g(i); // 错误：推导出 g<int>(const int&&)，它不能绑定右值引用到左值
}

在进行这些变换之后，按以下步骤进行推导处理（参阅“从类型推导”一节）并试图找到能让推导的 A（即在上面列出的调整和推导的模板形参替换后的 P）等同于变换后的 A（即上面列出的调整后的 A）的模板实参。

如果来自 P 和 A 的通常推导失败，那么额外考虑下列替用者：

1) 如果 P 是引用类型，那么推导的 A（即引用所指涉的类型）能比变换的 A 有更多的 cv 限定：
template<typename T> void f(const T& t);
bool a = false;
f(a); // P = const T&，调整为 const T，A = bool：
      // 推导出 T = bool 以及 A = const bool
      // 推导出的 A 比（原来的）A 有更多的 cv 限定
2) 变换后的 A 可以具有另一指针或成员指针类型，并可以通过限定转换 或函数指针转换 (C++17 起)转换到推导出的 A：
template<typename T> void f(const T*);
int* p;
f(p); // P = const T*，A = int*：
      // 推导 T = int 以及 A = const int*
      // 应用限定转换（从 int* 到 const int*）
3) 如果 P 是类且 P 的形式为 简单模板标识，那么变换后的 A 可以是推导出的 A 的派生类。类似地，如果 P 是指向 简单模板标识 形式的类的指针，那么变换后的 A 可以是推导出的 A 所指向的派生类的指针：
template<class T> struct B { };
template<class T> struct D : public B<T> { };
template<class T> void f(B<T>&) { }

void f()
{
    D<int> d;
    f(d); // P = B<T>&，调整为 P = B<T>（简单模板标识），A = D<int>：
          // 推导出 T = int 以及 A = B<int>
          // （原来的）A 派生自推导出的 A
}

不推导语境

下列情况下，用来组成 P 的类型、模板和非类型值不会参与模板实参推导，而改为使用可以在别处推导出或显式指定的模板实参。如果模板形参只在不推导语境使用且没有被显式指定，那么模板实参推导失败。

1) 用有限定标识指定的类型的 嵌套名说明符（作用域解析运算符 :: 左侧的所有内容）：
// 恒等模板，常用于从推导中排除特定实参
// （即 C++20 中新增的 std::type_identity ）
template<typename T> struct identity { typedef T type; };
template<typename T> void bad(std::vector<T> x, T value = 1);
template<typename T> void good(std::vector<T> x, typename identity<T>::type value = 1);
std::vector<std::complex<double>> x;
bad(x, 1.2);  // P1 = std::vector<T>，A1 = std::vector<std::complex<double>>
              // P1/A1：推导出 T = std::complex<double>
              // P2 = T，A2 = double
              // P2/A2：推导出 T = double
              // 错误：推导失败，T 有歧义
good(x, 1.2); // P1 = std::vector<T>，A1 = std::vector<std::complex<double>>
              // P1/A1：推导出 T = std::complex<double>
              // P2 = identity<T>::type，A2 = double
              // P2/A2：使用 P1/A1 推导出的 T，因为 T 在 P2 中的 :: 的左侧
              // OK：T = std::complex<double>
2) decltype 说明符的表达式：
template<typename T> void f(decltype(*std::declval<T>()) arg);
int n;
f<int*>(n); // P = decltype(*declval<T>())，A = int：T 处于不推导语境
 (C++11 起)
3) 非类型模板实参或数组边界，其中子表达式引用一个模板形参：
template<std::size_t N> void f(std::array<int, 2 * N> a);
std::array<int, 10> a;
f(a); // P = std::array<int, 2 * N>，A = std::array<int, 10>：
      // 2 * N 处于不推导语境，无法推导出 N
      // 注意：f(std::array<int, N> a) 可以推导出 N
4) 用于函数形参的形参类型中拥有默认实参的模板形参，且该函数形参在正在进行实参推导的调用中：
template<typename T, typename F>
void f(const std::vector<T>& v, const F& comp = std::less<T>());
std::vector<std::string> v(3);
f(v); // P1 = const std::vector<T>&，A1 = std::vector<std::string> 左值
      // P1/A1 推导出 T = std::string
      // P2 = const F&，A2 = std::less<std::string> 右值
      // P2 在用于函数形参 comp 的形参类型（const F&）的 F（模板形参）的不推导语境，
      // 该函数形参拥有调用 f(v) 中正在使用的默认实参
5) 形参 P，其实参 A 是一个函数，没有函数或有多个函数与 P 匹配的重载集，或包含一个或多个函数模板的重载集：
template<typename T> void out(const T& value) { std::cout << value; }
out("123");     // P = const T&，A = const char[4] 左值：推导出 T = char[4]
out(std::endl); // P = const T&，A = 函数模板：T 处于不推导语境
6) 形参 P，其实参 A 是花括号初始化器列表，但 P 非 std::initializer_list、到它的引用（可以有 cv 限定），或者 (C++17 起)到数组的引用：
template<class T> void g1(std::vector<T>);
template<class T> void g2(std::vector<T>, T x);
g1({1, 2, 3});     // P = std::vector<T>，A = {1, 2, 3}：T 在不推导语境中
                   // 错误：T 没有被显式指定或从另一对 P/A 推导出
g2({1, 2, 3}, 10); // P1 = std::vector<T>，A1 = {1, 2, 3}：T 在不推导语境中
                   // P2 = T，A2 = int：推导出 T = int
7) 作为形参包且没有在形参列表尾部出现的形参 P：
template<class... Ts, class T> void f1(T n, Ts... args);
template<class... Ts, class T> void f2(Ts... args, T n);
f1(1, 2, 3, 4); // P1 = T，A1 = 1：推导出 T = int
                // P2 = Ts...，A2 = 2，A3 = 3，A4 = 4：推导出 Ts = [int, int, int]
f2(1, 2, 3, 4); // P1 = Ts...：Ts 在不推导语境
8) 在形参 P 中出现且包含不在模板形参列表最尾端的包展开的模板形参列表：
template<int...> struct T { };

template<int... Ts1, int N, int... Ts2>
void good(const T<N, Ts1...>& arg1, const T<N, Ts2...>&);

template<int... Ts1, int N, int... Ts2>
void bad(const T<Ts1..., N>& arg1, const T<Ts2..., N>&);

T<1, 2> t1;
T<1, -1, 0> t2;
good(t1, t2); // P1 = const T<N, Ts1...>&，A1 = T<1, 2>：
              // 推导出 N = 1 以及 Ts1 = [2]
              // P2 = const T<N, Ts2...>&，A2 = T<1, -1, 0>：
              // 推导出 N = 1 以及 Ts2 = [-1, 0]
bad(t1, t2);  // P1 = const T<Ts1..., N>&，A1 = T<1, 2>：
              // <Ts1..., N> 处于不推导语境
              // P2 = const T<Ts2..., N>&，A2 = T<1, -1, 0>：
              // <Ts2..., N> 处于不推导语境
 (C++11 起)
9) 数组（不考虑到数组的引用或数组的指针）类型 P 中的第一维数组边界：
template<int i> void f1(int a[10][i]);
template<int i> void f2(int a[i][20]);    // P = int[i][20]，数组类型
template<int i> void f3(int (&a)[i][20]); // P = int(&)[i][20]，到数组的引用

void g()
{
    int a[10][20];
    f1(a);     // OK：推导出 i = 20
    f1<20>(a); // OK
    f2(a);     // 错误：i 处于不推导语境
    f2<10>(a); // OK
    f3(a);     // OK：推导出 i = 10
    f3<10>(a); // OK
}

在任何情况下，如果类型名的任何部分不会被推导，那么整个类型处于不推导语境。然而复合类型可以同时包含推导和不推导的类型名。例如在 A<T>::B<T2> 中，T 因为规则 #1（嵌套类型说明符）而不会被推导，且 T2 因为它是同一类型名的一部分也不会被推导，但在 void(*f)(typename A<T>::B, A<T>) 中，在 A<T> 中的 T 会被推导时 A<T>::B 中的 T 也（因为相同规则）不会被推导。

从类型推导

给定依赖一或多个类型模板形参 Ti、模板模板形参 TTi 或非类型模板形参 Ii 的模板形参 P 及其对应实参 A，若 P 拥有下列形式之一则进行推导：

本节未完成
原因：尽可能列出带微示例的表格
  • T;
  • cv-list T;
  • T*;
  • T&;
  • T&&;
  • T[整数常量];
  • 类模板名<T>;
  • 类型(T);
  • T();
  • T(T);
  • T 类型::*;
  • 类型 T::*;
  • T T::*;
  • T(类型::*)();
  • 类型(T::*)();
  • 类型(类型::*)(T);
  • 类型(T::*)(T);
  • T (类型::*)(T);
  • T (T::*)();
  • T (T::*)(T);
  • 类型[i];
  • 类模板名<I>;
  • TT<T>;
  • TT<I>;
  • TT<>;

其中

  • (T) 是其中至少有一个形参类型含有 T 的函数形参列表；
  • () 是其中没有含有 T 的形参的函数形参列表；
  • <T> 是至少一个实参含有 T 的模板实参列表；
  • <I> 是其中至少一个实参含有 I 的模板实参列表；
  • <> 其中没有含有 T 或 I 的实参的模板实参列表。

如果 P 具有包含模板形参列表 <T> 或 <I> 的形式之一，那么将该模板形参列表的每个元素 Pi 与其 A 的对应模板实参 Ai 进行匹配。如果最后一个 Pi 是包展开，那么将其模式与 A 的模板实参列表中的每个剩余实参进行比较。其他情况下不推导的尾随参数包会被推导为空形参包。

如果 P 具有包含函数形参列表 (T) 的形式，那么将来自该列表的每个形参 Pi 与来自 A 的函数形参列表的对应实参 Ai 进行比较。如果最后一个 Pi 是包展开，那么将其声明符和 A 的形参类型列表中的每个剩余的 Ai 进行比较。

这些形式可以嵌套并递归处理：X<int>(*)(char[6]) 是一个 类型(*)(T) 的例子，其中 类型 是 类模板名<T> 而 T 是 类型[i]。

不能从非类型模板实参推导类型模板实参：

template<typename T, T i> void f(double a[10][i]);
double v[10][20];
f(v); // P = double[10][i] ， A = double[10][20]:
      // i 能被推导为等于 20
      // 但不能从 i 的类型推导 T
 (C++17 前)

当从表达式推导对应于某个以待决类型声明的非类型模板形参 P 的实参的值时，从该值的类型推导 P 的类型中的模板形参。

template <long n> struct A { };
template <class T> struct C;
template <class T, T n> struct C<A<n>> { using Q = T; };
typedef long R;

typedef C<A<2>>::Q R; // OK：从类型 A<2> 中的模板实参值推导出 T = long

template <auto X> class bar{};
template <class T, T n> void f(bar<n> x);
f(bar<3>{}); // OK：从类型 bar<3> 中的模板实参值推导出 T = int（以及 n = 3）

类型 t[N] 中 N 的类型是 std::size_t。

template<class T, T i> void f(int (&a)[i]);
int v[10];
f(v); // OK：T 是 std::size_t
 (C++17 起)

如果在形参列表中使用某个非类型模板形参并推导了它对应的模板实参，那么推导出的模板实参类型（如同在它的外围模板形参列表中指定，这表示引用被保留）必须与该非类型模板形参的类型严格匹配，但 cv 限定符被丢弃，且不包括从数组边界推导的模板实参——此时允许任何包括 bool 在内（虽然它总是变为 true 值）的整数类型：

template<int i> class A { };
template<short s> void f(A<s>); // 非类型模板形参的类型是 short

void k1()
{
    A<1> a;  // a 的非类型模板形参的类型是 int
    f(a);    // P = A<(short)s>, A = A<(int)1>
             // 错误：推导出的非类型模板形参拥有与对应模板实参不同的类型
    f<1>(a); // OK：不推导模板实参，这会调用 f<(short)1>(A<(short)1>)
}

template<int&> struct X;
template<int& R> void k2(X<R>&);
int n;
void g(X<n> &x) {
    k2(x); // P = X<R>，A = X<n>
           // struct X 的声明中形参类型是 int&
           // 实参类型是 int&
           // OK（因 CWG 2091）：推导出 R 以指代 n
}

类型模板形参不能从函数默认实参的类型推导：

template<typename T> void f(T = 5, T = 7);

void g()
{
    f(1);     // OK：调用 f<int>(1, 7)
    f();      // 错误：无法推导出 T
    f<int>(); // OK：调用 f<int>(5, 7)
}

模板模板形参的推导可以使用函数调用中所用的模板特化中所使用的类型：

template<template<typename> class X> struct A { }; // A 是一个拥有模板模板形参的模板
template<template<typename> class TT> void f(A<TT>) { }
template<class T> struct B { };
A<B> ab;
f(ab); // P = A<TT>，A = A<B>：推导出 TT = B，调用 f(A<B>)

注解：由于 noexcept 说明从 C++17 起成为类型的一部分，有些编译器（例如 GCC、 Clang 与 ICC，但不含 MSVC）能在 C++17 或更新的模式从类型推导 noexcept 说明符中的值。这种特性还没有被标准接受。这就是 CWG 问题 2355 。

其他语境

除了函数调用和运算符表达式以外，以下场合也使用模板实参推导：

auto 类型推导

当变量声明需要从变量的初始化器推导 auto 说明符的含义时会用到模板实参推导。

通过以下方式获得形参 P：在变量的被声明类型 T（包含 auto）中，auto 的每次出现都被替换成一个虚构的类型模板形参 U，或在它的初始化是复制列表初始化时替换成 std::initializer_list<U>。实参 A 是初始化器表达式。按上文所述的规则从 P 和 A 推导出 U 后，将推导出的 U 替换到 P 中以获取实际的变量类型：

const auto& x = 1 + 2; // P = const U&，A = 1 + 2：
                       // 与调用 f(1 + 2) 的规则相同，其中 f 是
                       // template<class U> void f(const U& u)
                       // 推导出 U = int，x 的类型是 const int&
auto l = {13}; // P = std::initializer_list<U>，A = {13}：
               // 推导出 U = int，l 的类型是 std::initializer_list<int>

在直接列表初始化（但不是复制列表初始化）中，当从花括号初始化器列表推导 auto 的含义时，花括号初始化器列表必须只含一个元素，而 auto 的类型将是该元素的类型：

auto x1 = {3}; // x1 是 std::initializer_list<int>
auto x2{1, 2}; // 错误：不止单个元素
auto x3{3};    // x3 是 int
               //（N3922 之前，x2 和 x3 都是 std::initializer_list<int>）
 (C++11 起)

返回 auto 的函数

当从 return 语句推导函数返回类型中的 auto 说明符的含义时，将模板实参推导用于函数的声明。

对于返回 auto 的函数，通过以下方式获得形参 P：在被声明函数的返回类型 T（包含 auto）中，auto 的每次出现都会被替换成一个虚构的类型模板实参 U。实参 A 是 return 语句的表达式，而如果 return 语句没有操作数，那么 A 是 void()。按上文所述的规则从 P 和 A 推导出 U 后，将推导出的 U 替换到 T 中以获取实际的返回类型：

auto f() { return 42; } // P = auto，A = 42：
                        // 推导出 U = int，f 的返回类型是 int

如果这种函数拥有多个 return 语句，那么就会对每个 return 语句进行推导。所有结果类型必须相同，并成为该函数的实际返回类型。

如果这种函数没有 return 语句，那么推导时 A 是 void()。

注意：变量和函数声明中的 decltype(auto) 占位符的含义不使用模板实参推导。

 (C++14 起)

重载决议

从候选模板函数生成特化时，在重载决议期间使用模板实参推导： 其 P 和 A 和常规函数调用相同。

std::string s;
std::getline(std::cin, s); // "std::getline" 指名 4 个函数模板，
// 其中 2 个是候选函数（形参数正确）

// 第 1 候选模板：
// P1 = std::basic_istream<CharT, Traits>&，A1 = std::cin
// P2 = std::basic_string<CharT, Traits, Allocator>&，A2 = s
// 推导确定类型模板实参 CharT、Traits 和 Allocator
// 特化 std::getline<char, std::char_traits<char>, std::allocator<char>>

// 第 2 候选模板：
// P1 = std::basic_istream<CharT, Traits>&&，A1 = std::cin
// P2 = std::basic_string<CharT, Traits, Allocator>&，A2 = s
// 推导确定类型模板形参 CharT、Traits 和 Allocator
// 特化 std::getline<char, std::char_traits<char>, std::allocator<char>>

// 重载决议将从左值 std::cin 绑定的引用排在高位
// 并选取两个候选特化的第一个

如果推导失败，或推导成功但产生的特化无效（例如形参既既不是类类型也不是枚举类型的重载运算符），那么重载集不会包含该特化，这类似于 SFINAE。

重载集的地址

取包含函数模板在内的重载集的地址时，使用模板实参推导。

函数模板的函数类型为 P。目标类型是 A 的类型：

std::cout << std::endl; // std::endl 指名函数模板
// endl 的类型 P =
// std::basic_ostream<CharT, Traits>& (std::basic_ostream<CharT, Traits>&)
// operator<< 的形参 A =
// std::basic_ostream<char, std::char_traits<char>>& (*)(
//     std::basic_ostream<char, std::char_traits<char>>&
// )
// （其他 operator<< 的重载不可行）
// 推导确定类型模板实参 CharT 和 Traits

这种情况下的推导适用一条额外的规则：当比较函数形参 Pi 和 Ai 时，如果有任何 Pi 是到无 cv 限定模板形参的右值引用（“转发引用”）且对应的 Ai 是左值引用，那么会将 Pi 调整为模板形参类型（T&& 成为 T）。

如果函数模板的返回类型是占位符（auto 或 decltype(auto)），那么返回类型处于不推导语境，并由实例化决定。

 (C++14 起)

偏序

在重载的函数模板的偏序过程中使用模板实参推导。

本节未完成
原因：小示例

转换函数模板

选择用户定义转换函数模板实参时使用模板实参推导。

A 是要求作为转换结果的类型。 P 是转换函数模板的返回类型，除了

a) 如果返回类型是引用类型，那么 P 是被引用类型；
b) 如果返回类型是数组类型且 A 不是引用类型，那么 P 是从数组到指针转换获得的指针类型；
c) 如果返回类型是函数类型且 A 不是引用类型，那么 P 是从函数到指针转换获得的函数指针类型；
d) 如果 P 有 cv 限定，那么忽略顶层 cv 限定符。

如果 A 有 cv 限定，那么忽略顶层 cv 限定符。如果 A 是引用类型，那么推导使用被引用的类型。

如果从 P 和 A 进行的常规推导（如上文所述）失败，那么考虑下列替代方式：

a) 如果 A 是引用类型，那么 A 可以比推导出的 A 有更多的 cv 限定；
b) 如果 A 是指针或成员指针类型，那么推导出的 A 可以是任意能以限定转换转换到 A 的指针：
struct A { template<class T> operator T***(); };
A a;
const int* const* const* p1 = a; // P = T***，A = const int* const* const*
// 对 template<class T> void f(T*** p) 的常规函数调用推导
// （如同以 const int* const* const* 类型的实参进行调用）失败
// 转换函数的额外推导确定 T = int
// （推导出的 A 是 int***，可以转换成 const int* const* const*）
c) 如果 A 是函数指针类型，那么推导出的 A 可以是指向 noexcept 函数的指针，并可以通过函数指针转换转换成 A；
d) 如果 A 是成员函数指针，那么推导出的 A 可以是指向 noexcept 成员函数的指针，并可以通过函数指针转换转换成 A。
 (C++17 起)

关于转换函数模板的其他规则，见成员模板。

显式实例化

显式实例化、显式特化 以及声明符标识恰好指代某个函数模板特化的友元声明（例如 friend ostream& operator<< <> (...)）在还有模板实参没有被显式指定且没有默认值时会用模板实参推导来确定指代哪个模板特化。

P 是被认为是潜在匹配的函数模板的类型，而 A 是声明中的函数类型。如果（偏序后）没有匹配或多于一个匹配，那么函数声明为谬构：

template<class X> void f(X a);  // 第 1 个模板 f
template<class X> void f(X* a); // 第 2 个模板 f
template<> void f<>(int* a) { } // f 的显式特化
// P1 = void(X)， A1 = void(int*)：推导出 X = int*，f<int*>(int*)
// P2 = void(X*)，A2 = void(int*)：推导出 X = int， f<int>(int*)
// 向偏序提交 f<int*>(int*) 与 f<int>(int*)
// 它选择 f<int>(int*) 为更特殊的模板

这种情况下的推导适用一条额外的规则：当比较函数形参 Pi 和 Ai 时，如果有任何 Pi 是到无 cv 限定模板形参的右值引用（“转发引用”）且对应的 Ai 是左值引用，那么将 Pi 调整为模板形参类型（T&& 成为 T）。

解分配函数模板

确定解分配函数模板特化是否与给定的 operator new 布置形式相匹配时使用模板实参推导。

P 是被认为是潜在匹配的函数模板的类型，而 A 是应当与考虑中的布置 operator new 相匹配的解分配函数的函数类型。如果（在重载决议后）没有匹配或多于一个匹配，那么不调用布置解分配函数（可能发生内存泄漏）：

struct X
{
    X() { throw std::runtime_error(""); }
    static void* operator new(std::size_t sz, bool b) { return ::operator new(sz); }
    static void* operator new(std::size_t sz, double f) { return ::operator new(sz); }
    template<typename T> static void operator delete(void* ptr, T arg)
    {
        ::operator delete(ptr);
    }
};

int main()
{
    try
    {
        X* p1 = new (true) X; // 当 X() 抛出异常时，查找 operator delete
                              // P1 = void(void*, T)，A1 = void(void*, bool)：
                              // 推导出 T = bool
                              // P2 = void(void*, T)，A2 = void(void*, double)：
                              // 推导出 T = double
                              // 重载决议挑选 operator delete<bool>
    } catch(const std::exception&) { }
    try
    {
        X* p1 = new (13.2) X; // 同样的查找，挑选 operator delete<double>
    } catch(const std::exception&) { }
}

别名模版

别名模版始终不会进行推导：

template<class T> struct Alloc { };
template<class T> using Vec = vector<T, Alloc<T>>;
Vec<int> v;

template<template<class, class> class TT> void g(TT<int, Alloc<int>>);
g(v); // OK：推导出 TT = vector

template<template<class> class TT> void f(TT<int>);
f(v); // 错误： TT 无法被推导为 "Vec"，因为 Vec 是别名模版

隐式转换

类型推导不会考虑（除了以上列出的类型调整之外的）隐式转换：这是其后进行的重载决议的工作。然而，如果对所有参与模板实参推导的形参进行的推导均成功，并且所有不推导的模板实参均被显式指定或有默认值，那么将剩余的各函数形参与对应的函数实参比较。对于具有在替换任何显式指定的模板实参之前未待决的类型的每个剩余形参 P，如果对应的实参 A 无法隐式转换成 P，那么推导失败。

其中没有模板形参会参与模板实参推导的具有待决类型的形参，以及由于替换显式指定的模板实参而成为非待决的形参，将在重载决议期间检查：

template<class T> struct Z { typedef typename T::x xx; };
template<class T> typename Z<T>::xx f(void*, T); // #1
template<class T> void f(int, T);                // #2
struct A { } a;

int main()
{
    f(1, a); // 对于 #1，推导确定 T = struct A，但剩余实参 1
             // 不能隐式转换成其形参 void*：推导失败
             // 不要求返回类型的实例化
             // 对于 #2，推导确定 T = struct A，且剩余实参 1
             // 能隐式转换成其形参 int：推导成功
             // 函数调用编译为到 #2 的调用（推导失败是 SFINAE）
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 70 | C++98 | 未指明数组边界是否会被推导 | 指定为不推导
CWG 1391 | C++98 | 未指明推导所不涉及的实参隐式转换的效果 | 指定为如上文所述
CWG 1591 | C++11 | 不能从 花括号初始化器列表 推导数组边界和元素类型 | 允许推导
CWG 2052 | C++98 | 以非类非枚举实参推导运算符是硬错误 | 若有其他重载则为软错误
CWG 2091 | C++98 | 推导引用非类型形参不可用，因为类型不能匹配实参 | 避免类型不匹配
N3922 | C++11 | auto 的直接列表初始化推导出 std::initializer_list | 对多于一个元素为谬构，对单个元素推导出元素类型


模板形参与模板实参

< cpp‎ | language

模板形参

每个模板都会由一个或多个模板形参参数化，它们在模板声明语法中的 形参列表 中指定：

template < 形参列表 > 声明

形参列表 中的每个形参可以是：

  • 非类型模板形参；
  • 类型模板形参；
  • 模板模板形参。

非类型模板形参

类型 名字(可选) | (1) |
类型 名字(可选) = 默认值 | (2) |
类型 ... 名字(可选) | (3) | (C++11 起)
占位符 名字 | (4) | (C++17 起)
1) 可以有名字的非类型模板形参。
2) 可以有名字和默认值的非类型模板形参。
3) 可以有名字的非类型模板形参包。
4) 带占位符类型的非类型模板形参。占位符 可以是包含占位符 auto 的任何类型（例如单纯的 auto、auto ** 或 auto &），被推导类类型的占位符 (C++20 起)，或者 decltype(auto)。

非类型模板形参必须拥有结构化类型，它是下列类型之一（可以有 cv 限定，忽略限定符）：

  • （到对象或函数的）左值引用类型；
  • 整数类型；
  • （指向对象或函数的）指针类型；
  • （指向成员对象或成员函数的）成员指针类型；
  • 枚举类型；
  • std::nullptr_t ；
 (C++11 起)
  • 浮点类型；
  • 拥有下列属性的字面类类型：
  • 所有基类与非静态数据成员为公开且非 mutable 且
  • 所有基类与非静态数据成员的类型均为结构化类型或其（可能多维的）数组。
 (C++20 起)

数组与函数类型可以写在模板声明中，但它们会被自动替换为适合的对象指针和函数指针。

在类模板体内使用的非类型模板形参的名字是不可修改的纯右值，除非它的类型是左值引用类型或类类型 (C++20 起)。

形式为 class Foo 的模板形参不是类型为 Foo 的无名非类型模板形参，虽然 class Foo 还能是详述类型说明符且 class Foo x; 声明 x 为 Foo 类型的对象。

如果非类型模板形参的类型包含占位符类型 auto，被推导类型的占位符 (C++20 起)，或 decltype(auto)，那么它可以被推导。推导会如同在虚设的声明 T x = 模板实参; 中推导变量 x 的类型一样进行，其中 T 是模板形参的声明类型。如果被推导的类型不能用于非类型模板形参，那么程序非良构。

template<auto n> struct B { /* ... */ };
B<5> b1;   // OK：非类型模板形参的类型是 int
B<'a'> b2; // OK：非类型模板形参的类型是 char
B<2.5> b3; // 错误（C++20 前）：非类型模板形参的类型不能是 double

对于类型中使用了占位符类型的非类型模板形参包，每个模板实参的类型会独立进行推导，而且不需要互相匹配：

template<auto...> struct C {};
C<'C', 0, 2L, nullptr> x; // OK
 (C++17 起)

指名类类型 T 的某个非类型模板形参的标识符代表一个 const T 类型的静态存储期对象，该对象被称为模板形参对象，它的值是对应模板实参转换到模板形参的类型之后的值。程序中所有具有相同类型和值的这种模板形参都代表同一模板形参对象。模板形参对象应当拥有常量析构。

struct A { friend bool operator==(const A&, const A&) = default; };
template<A a> void f() {
    &a;                       // OK
    const A& ra = a, &rb = a; // 都绑定到同一个模板形参对象
    assert(&ra == &rb);       // 通过
}
 (C++20 起)

类型模板形参

类型形参关键词 名字(可选) | (1) |
类型形参关键词 名字(可选) = 默认值 | (2) |
类型形参关键词 ... 名字(可选) | (3) | (C++11 起)
类型约束 名字(可选) | (4) | (C++20 起)
类型约束 名字(可选) = 默认值 | (5) | (C++20 起)
类型约束 ... 名字(可选) | (6) | (C++20 起)
类型形参关键词 | - | typename 或 class 之一。这两个关键词在类型模板形参声明中没有区别
类型约束 | - | 概念的名字或概念名后随模板实参列表（在角括号中）。概念名均对于两者都可以有限定
1) 没有默认类型的类型模板形参。
template<class T>
class My_vector { /* ... */ };
2) 有默认类型的类型模板形参。
template<class T = void>
struct My_op_functor { /* ... */ };
3) 类型模板形参包。
template<typename... Ts>
class My_tuple { /* ... */ };
4) 没有默认实参的受约束类型模板形参。
template <My_concept T>
class My_constrained_vector { /* ... */ };
5) 有默认实参的受约束类型模板形参。
template <My_concept T = void>
class My_constrained_op_functor { /* ... */ };
6) 受约束的类型模板形参包。
template <My_concept... Ts>
class My_constrained_tuple { /* ... */ };

形参的名字是可选的：

// 对上面所示模板的声明：
template<class> class My_vector;
template<class = void> struct My_op_functor;
template<typename...> class My_tuple;

在模板声明体内，类型形参的名字是 typedef 名字，它是当模板被实例化时所提供的类型的别名。

对于每个受约束形参 P，它的 类型约束 Q 指定了概念 C，那么根据以下规则引入一个约束表达式 E：

  • 如果 Q 是 C（没有实参列表），
  • 如果 P 不是形参包，那么 E 是 C<P>
  • 否则，P 是形参包，那么 E 是折叠表达式 (C<P> && ...)
  • 如果 Q 是 C<A1,A2...,AN>，那么 E 分别是 C<P,A1,A2,...AN> 或 (C<P,A1,A2,...AN> && ...)。
template<typename T> concept C1 = true;
template<typename... Ts> concept C2 = true; // 变参概念
template<typename T, typename U> concept C3 = true;

template<C1 T> struct s1;         // 约束表达式为 C1<T>
template<C1... T> struct s2;      // 约束表达式为 (C1<T> && ...)
template<C2... T> struct s3;      // 约束表达式为 (C2<T> && ...)
template<C3<int> T> struct s4;    // 约束表达式为 C3<T, int>
template<C3<int>... T> struct s5; // 约束表达式为 (C3<T, int> && ...)
 (C++20 起)

模板模板形参

template < 形参列表 > typename(C++17)|class 名字(可选) | (1) |
template < 形参列表 > typename(C++17)|class 名字(可选) = default | (2) |
template < 形参列表 > typename(C++17)|class ... 名字(可选) | (3) | (C++11 起)
类型形参关键词 - class 或 typename 之一 (C++17 起)
1) 可以有名字的模板模板形参。
2) 有默认模板且可以有名字的模板模板形参。
3) 可以有名字的模板模板形参包。

在模板声明体内，此形参的名字是一个模板名（且需要实参以实例化）。

template<typename T> class my_array {};

// 两个类型模板形参和一个模板模板形参：
template<typename K, typename V, template<typename> typename C = my_array>
class Map
{
    C<K> key;
    C<V> value;
};

模板形参的名字决议

模板形参的名字不能在它的作用域（包括内嵌作用域）内重声明。模板形参的名字不能与模板的名字相同。

template<class T, int N>
class Y {
    int T;      // 错误：重声明模板形参
    void f()
    {
        char T; // 错误：重声明模板形参
    }
};

template<class X> class X; // 错误：重声明模板形参

在出现于类模板定义外的类模板成员定义中，类模板成员名会隐藏任何外围类模板的模板形参名，但如果该成员是类或函数模板则不隐藏该成员的模板形参。

template<class T>
struct A {
    struct B {};
    typedef void C;
    void f();
    template<class U> void g(U);
};

template<class B>
void A<B>::f()
{
    B b; // A 的 B ，不是模板形参
}

template<class B>
template<class C>
void A<B>::g(C)
{
    B b; // A 的 B ，不是模板形参
    C c; // 模板形参 C ，不是 A 的 C
}

在出现于含该类模板定义的命名空间外的类模板成员定义中，模板形参名隐藏此命名空间的成员名。

namespace N {
    class C {};
    template<class T>
    class B {
        void f(T);
    };
}
template<class C>
void N::B<C>::f(C)
{
    C b; // C 是模板形参，不是 N::C
}

在类模板定义中，或出现于模板定义外的这种成员的定义中，对于每个非待决基类，如果基类名或基类成员名与模板形参名相同，那么该基类名或成员名隐藏模板形参名。

struct A {
    struct B {};
    int C;
    int Y;
};

template<class B, class C>
struct X : A {
    B b; // A 的 B
    C b; // 错误： A 的 C 不是类型名
};

模板实参

为使模板被实例化，它的每个模板形参（类型、非类型或模板）都必须被一个对应的模板实参替换。对于类模板，实参可以被显式提供，或从初始化器推导， (C++17 起)或为默认。对于函数模板，实参可以被显式提供，或从语境推导，或为默认。

如果实参可以同时被解释为类型标识和表达式，那么它始终会被解释为类型标识，即使它对应的是非类型模板形参：

template<class T> void f(); // #1
template<int I> void f();   // #2
void g() {
    f<int()>(); // "int()" 既是类型又是表达式，
                // 因为它被解释成类型，所以调用 #1
}

模板非类型实参

在实例化拥有非类型模板形参的模板时应用下列限制：

  • 对于整型和算术类型，实例化时所提供的模板实参必须是模板形参类型的经转换常量表达式（因此适用某些隐式转换）。
  • 对于对象指针，模板实参必须指定某个具有静态存储期和（内部或外部）连接的完整对象的地址，或者是求值为适当的空指针或 std::nullptr_t 值的常量表达式。
  • 对于函数指针，合法的实参是指向具有连接的函数的指针（或求值为空指针值的常量表达式）。
  • 对于左值引用形参，实例化时所提供的实参不能是临时量、无名左值或无连接的具名左值（换言之，实参必须具有连接）。
  • 对于成员指针，实参必须是表示成 &Class::Member 的成员指针，或求值为空指针值或 std::nullptr_t 值的常量表达式。

特别是，这意味着字符串字面量、数组元素的地址和非静态成员的地址，不能被用作模板实参，来实例化其对应非类型模板形参是对象指针的模板形参的模板。

 (C++17 前)

非类型模板形参可以使用的模板实参，可以是该模板形参类型的任何经转换常量表达式。

template<const int* pci> struct X {};
int ai[10];
X<ai> xi; // OK：数组到指针转换和 cv 限定转换

struct Y {};
template<const Y& b> struct Z {};
Y y;
Z<y> z;   // OK：没有转换

template<int (&pa)[5]> struct W {};
int b[5];
W<b> w;   // OK：没有转换

void f(char);
void f(int);
template<void (*pf)(int)> struct A {};
A<&f> a;  // OK：重载决议选择 f(int)

仅有的例外是引用或指针类型的非类型模板形参以及类类型的非类型模板形参及其子对象之中的引用或指针类型的非静态数据成员 (C++20 起)，它们不能指代下列对象或者是下列对象的地址：

  • 临时对象（包括在引用初始化期间创建的对象）；
  • 字符串字面量；
  • typeid 的结果；
  • 预定义变量 __func__；
  • 或以上之一的 (C++20 起)子对象（包括非静态类成员、基类子对象或数组元素）。
template<class T, const char* p> class X {};
X<int, "Studebaker"> x1; // 错误：将字符串字面量用作模板实参

template<int* p> class X {};
int a[10];
struct S
{
    int m;
    static int s;
} s;
X<&a[2]> x3; // 错误（C++20 前）：数组元素的地址
X<&s.m> x4;  // 错误（C++20 前）：非静态成员的地址
X<&s.s> x5;  // OK：静态成员的地址
X<&S::s> x6; // OK：静态成员的地址

template<const int& CRI> struct B {};
B<1> b2;     // 错误：模板实参要求临时量
int c = 1;
B<c> b1;     // OK
 (C++17 起)

模板类型实参

类型模板形参的模板实参必须是类型标识，它可以指名不完整类型：

template<typename T> class X {}; // 类模板

struct A; // 不完整类型
typedef struct {} B; // 无名类型的类型别名

int main()
{
    X<A> x1; // ok：'A' 指名类型
    X<A*> x2; // ok：'A*' 指名类型
    X<B> x3; // ok：'B' 指名类型
}

模板模板实参

模板模板形参的模板实参是必须是一个 标识表达式，它指名一个类模板或模板别名。

当实参是类模板时，进行形参匹配时只考虑其主模板。部分特化若存在，也仅在基于此模板模板形参的特化恰好要被实例化时才予以考虑。

template<typename T> class A { int x; }; // 主模板
template<typename T> class A<T*> { long x; }; // 部分特化

// 带有模板模板形参 V 的类模板
template<template<typename> class V> class C
{
    V<int> y; // 使用主模板
    V<int*> z; // 使用部分特化
};

C<A> c; // c.y.x 类型为 int，c.z.x 类型为 long

为匹配模板模板实参 A 与模板模板形参 P，A 的每个模板形参必须与 P 的对应模板形参严格匹配 (C++17 前)P 必须至少与 A 一样特殊 (C++17 起)。若 P 的形参列表包含一个形参包，则来自 A 的模板形参列表中的零或更多模板形参（或形参包）与之匹配。

template<typename T> struct eval; // 主模板

template<template<typename, typename...> class TT, typename T1, typename... Rest>
struct eval<TT<T1, Rest...>> {}; // eval 的部分特化

template<typename T1> struct A;
template<typename T1, typename T2> struct B;
template<int N> struct C;
template<typename T1, int N> struct D;
template<typename T1, typename T2, int N = 17> struct E;

eval<A<int>> eA; // ok：匹配 eval 的部分特化
eval<B<int, float>> eB; // ok：匹配 eval 的部分特化
eval<C<17>> eC; // 错误：C 在部分特化中不匹配 TT，因为 TT 的首个形参是类型模板形参
                // 而 17 不指名类型
eval<D<int, 17>> eD; // 错误：D 在部分特化中不匹配 TT，
                     // 因为 TT 的第二形参是类型形参包，而 17 不指名类型
eval<E<int, float>> eE; // 错误：E 在部分特化中不匹配 TT
                        // 因为 E 的第三（默认）形参是非类型形参
template<class T> class A { /* ... */ };
template<class T, class U = T> class B { /* ... */ };
template <class ...Types> class C { /* ... */ };

template<template<class> class P> class X { /* ... */ };
X<A> xa; // OK
X<B> xb; // C++17 在 CWG 150 后 OK
         // 更早时为错误：非严格匹配
X<C> xc; // C++17 在 CWG 150 后 OK
         // 更早时为错误：非严格匹配

template<template<class ...> class Q> class Y { /* ... */ };
Y<A> ya; // OK
Y<B> yb; // OK
Y<C> yc; // OK

template<auto n> class D { /* ... */ }; // 注意：C++17
template<template<int> class R> class Z { /* ... */ };
Z<D> zd; // OK

template <int> struct SI { /* ... */ };
template <template <auto> class> void FA();  // 注意：C++17
FA<SI>();  // 错误

正式来说，给定以下对两个函数模板的重写，根据函数模板的偏序规则，如果对应于模板模板形参 P 的函数模板，至少与对应于模板模板实参 A 的函数模板同样特殊，则 P 至少与 A 同样特殊。给定一个虚设的类模板 X，它拥有 A 的模板形参列表（包含默认实参）：

  • 两个函数模板各自分别拥有与 P 或 A 相同的各个模板形参。
  • 每个函数模板均拥有单个函数形参，其类型是以对应于各自函数模板的模板形参的模板实参对 X 的特化，其中对于函数模板的模板形参列表中的每个模板形参 PP，构成一个对应的模板实参 AA。若 PP 声明参数包，则 AA 是包展开 PP...；否则，AA 是标识表达式 PP。

若重写生成了非法类型，则 P 并非至少与 A 同样特殊。

 (C++17 起)

默认模板实参

默认模板实参在形参列表中于 = 号之后指定。可以为任何种类的模板形参（类型、非类型或模板）指定默认实参，但不能对形参包指定。

若为主类模板、主变量模板 (C++14 起)或别名模版的模板形参指定默认实参，则其每个后继模板形参都必须有默认实参，但最后一个可以是模板形参包。在函数模板中，对跟在默认实参之后的形参没有限制，而仅当类型形参具有默认实参，或可从函数实参推导时，才可跟在形参包之后。

以下情况不允许默认形参

  • 在类模板的成员的类外定义中（必须在类体内的声明中提供它们）。注意非模板类的成员模板可以在其类外定义中使用默认形参（见 GCC 漏洞 53856）
  • 在友元类模板声明中
  • 在任何函数模板声明或定义中
 (C++11 前)

在友元函数模板的声明上，仅当声明是定义，且此翻译单元不出现此函数的其他声明时，才允许默认模板实参。

 (C++11 起)

各个声明和定义中所出现的默认模板实参，以类似默认函数实参的方式合并：

template<typename T1, typename T2 = int> class A;
template<typename T1 = int, typename T2> class A;
// 如上与如下相同：
template<typename T1 = int, typename T2 = int> class A;

但在同一作用域中不能两次为同一形参指定默认实参

template<typename T = int> class X;
template<typename T = int> class X {}; // 错误

模板模板形参的模板形参列表可拥有其自己的默认实参，它仅在模板模板实参自身处于作用域中时有效：

// 类模板，带有默认实参的类型模板形参
template<typename T = float> struct B {};

// 模板模板形参 T 有形参列表，
// 它由一个带默认实参的类型模板形参组成
template<template<typename = float> typename T> struct A
{
    void f();
    void g();
};

// 类体外的成员函数模板定义
template<template<typename TT> class T>
void A<T>::f()
{
    T<> t; // 错误：TT 在作用域中无默认实参
}
template<template<typename TT = char> class T>
void A<T>::g()
{
    T<> t; // ok：t 为 T<char>
}

默认模板形参中所用的名字的成员访问，在声明中，而非在使用点检查：

class B {};

template<typename T> class C
{
    protected:
        typedef T TT;
};

template<typename U, typename V = typename U::TT> class D: public U {};

D<C<B>>* d; // 错误：C::TT 为受保护

默认模板实参在需要该默认实参的值时被隐式实例化，除非模板用于指名函数：

template<typename T, typename U = int> struct S { };
S<bool>* p; // 默认模板实参 U 在此点实例化
            // p 的类型是 S<bool, int>*
 (C++14 起)

模板实参等价性

模板实参等价性用于确定二个模板标识是否相同。

二个值为模板实参等价，若它们拥有相同类型且

  • 它们拥有整数或枚举类型且其值相同
  • 或它们拥有指针类型且它们拥有同一指针值
  • 或它们拥有成员指针类型且它们指代同一类成员或均为空成员指针值
  • 或它们拥有左值引用类型且它们指代同一对象或函数
  • 或它们拥有 std::nullptr_t 类型
 (C++11 起)
  • 或它们拥有浮点类型且其值等同
  • 或它们拥有数组类型（此情况下数组必须是某类/联合体的成员对象）且其对应元素模板实参等价
  • 或它们拥有联合体类型且它们均无活跃成员，或它们拥有相同的活跃成员且其活跃成员模板实参等价
  • 或若它们拥有非联合类类型且其对应直接子对象和引用成员模板实参等价
 (C++20 起)

示例

#include <iostream>

// 简单的非类型模板形参
template<int N>
struct S { int a[N]; };

template<const char*>
struct S2 {};

// 复杂的非类型形参的例子
template
<
    char c, // 整型类型
    int (&ra)[5], // 到（数组类型）对象的左值引用
    int (*pf)(int), // 函数指针
    int (S<10>::*a)[10] // 指向（int[10] 类型的）成员对象的指针
> struct Complicated
{
    // 调用编译时所选择的函数
    // 并在编译时将其结果存储于数组中
    void foo(char base)
    {
        ra[4] = pf(c - base);
    }
};

S2<"fail"> s2; // 错误：不能用字符串字面量
char okay[] = "okay"; // 有连接的静态对象
S2< &okay[0] > s2; // 错误：数组元素无连接
S2<okay> s2; // 能用

int a[5];
int f(int n) { return n; }

int main()
{
    S<10> s; // s.a 是 10 个 int 的数组
    s.a[9] = 4;

    Complicated<'2', a, f, &S<10>::a> c;
    c.foo('0');

    std::cout << s.a[9] << a[4] << '\n';
}

输出：

42
本节未完成
原因：更多示例


显式（全）模板特化

< cpp‎ | language

允许对给定的模板实参集定制模板代码。

语法

template <> 声明

以下任何一项均可以完全特化：

  1. 函数模板
  2. 类模板
  3. 变量模板 (C++14 起)
  4. 类模板的成员函数
  5. 类模板的静态数据成员
  6. 类模板的成员类
  7. 类模板的成员枚举
  8. 类或类模板的成员类模板
  9. 类或类模板的成员函数模板

例如，

#include <iostream>
template<typename T> // 主模板
struct is_void : std::false_type {};
template<>           // 对 T = void 的显式特化
struct is_void<void> : std::true_type {};

int main()
{
    // 对于任何非 void 的类型 T，该类均派生自 false_type
    std::cout << is_void<char>::value << '\n';
    // 但当 T 为 void 时类派生自 true_type
    std::cout << is_void<void>::value << '\n';
}

细节

显式特化可以在任何可以定义其主模板的作用域中声明（可以与定义其主模板的作用域不同；例如同成员模板的类外特化）。显式特化必须在非特化模板声明后出现。

namespace N
{
    template<class T> class X { /*...*/ }; // 主模板
    template<> class X<int> { /*...*/ };   // 同命名空间中的特化

    template<class T> class Y { /*...*/ }; // 主模板
    template<> class Y<double>;            // 对 double 特化的前置声明
}

template<>
class N::Y<double> { /*...*/ }; // OK：相同命名空间中的特化

特化必须在导致隐式实例化的首次使用之前，在每个发生这种使用的翻译单元中声明：

class String {};
template<class T> class Array { /*...*/ };
template<class T> void sort(Array<T>& v) { /*...*/ } // 主模板

void f(Array<String>& v)
{
    sort(v); // 使用初等模板 sort() 隐式实例化 sort(Array<String>&)
}

template<> // 错误：sort(Array<String>) 的显式特化在隐式实例化之后出现
void sort<String>(Array<String>& v);

只有声明没有定义的模板特化可以像其他不完整类型一样使用（例如可以使用到它的指针和引用）：

template<class T> class X; // 主模板
template<> class X<int>;   // 特化（声明，不定义）

X<int>* p; // OK：指向不完整类型的指针
X<int> x;  // 错误：不完整类型的对象

函数模板的显式特化

当特化函数模板时，如果模板实参推导能通过函数实参提供，那么就可以忽略它的模板实参：

template<class T> class Array { /*...*/ };
template<class T> void sort(Array<T>& v); // 主模板
template<> void sort(Array<int>&);        // 对 T = int 的特化
// 不需要写成 template<> void sort<int>(Array<int>&);

与某个特化带有相同名字和相同形参列表的函数不是特化（见函数模板中的模板重载）

函数模板的显式特化只有在声明为带 inline 说明符（或定义为弃置）时才是内联函数，主模板是否为内联对它没有影响。

不能在函数模板，成员函数模板，以及隐式实例化类时的类模板的成员函数的显式特化中指定默认函数实参。

显式特化不能是友元声明。

本节未完成
原因：重新确认不同C++版本对异常说明的要求

特化的成员

在类体外定义显式特化的类模板的成员时，不使用 template <> 语法，除非它是某个被特化为类模板的显式特化的成员类模板的成员，因为其他情况下，语法会要求这种定义以嵌套模板所要求的 template<形参> 开始

template< typename T>
struct A
{
    struct B {};                   // 成员类
    template<class U> struct C {}; // 成员类模板
};

template<> // 特化
struct A<int>
{
    void f(int); // 特化的成员函数
};
// template<> 不会用于特化的成员
void A<int>::f(int) { /* ... */ }

template<> // 成员类的特化
struct A<char>::B
{
    void f();
};
// template<> 也不会用于特化的成员类的成员
void A<char>::B::f() { /* ... */ }

template<> // 成员类模板的特化
template<class U> struct A<char>::C
{
    void f();
};

// template<> 会用于定义被特化为类模板的显式特化的成员类模板的成员
template<>
template<class U> void A<char>::C<U>::f() { /* ... */ }

模板的静态数据成员的显式特化在它的声明包含初始化器时是定义；否则它是声明。这些定义必须用花括号进行默认初始化：

template<> X Q<int>::x;   // 静态成员的声明
template<> X Q<int>::x(); // 错误：函数声明
template<> X Q<int>::x{}; // 静态成员的默认初始化定义

类模板的成员或成员模板可对于类模板的隐式实例化显式特化，即使成员或成员模板定义于类模板定义中。

template<typename T>
struct A
{
    void f(T);   // 成员，声明于主模板中
    void h(T) {} // 成员，定义于主模板中
    template<class X1> void g1(T, X1); // 成员模板
    template<class X2> void g2(T, X2); // 成员模板
};

// 成员的特化
template<> void A<int>::f(int);
// 成员特化 OK，即使在类中定义
template<> void A<int>::h(int) {}

// 类外成员模板定义
template<class T>
template<class X1> void A<T>::g1(T, X1) {}

// 成员模板特化
template<>
template<class X1> void A<int>::g1(int, X1);

// 成员模板特化
template<>
template<> void A<int>::g2<char>(int, char); // 对于 X2 = char

// 同上，用模板实参推导 (X1 = char)
template<>
template<> void A<int>::g1(int, char);

成员或成员模板可以在多个外围类模板内嵌套。在这种成员的显式特化中，对每个显式特化的外围类模板都有一个 template<>。

template<class T1> struct A
{
    template<class T2> struct B
    {
        template<class T3>
        void mf();
    };
};

template<> struct A<int>;
template<> template<> struct A<char>::B<double>;
template<> template<> template<> void A<char>::B<char>::mf<double>();

在这种嵌套声明中，某些层次可保留不特化（但如果它的外围类没有被特化，那么就不能特化类成员模板）。这种层次的每个声明都需要 template<实参>，因为这种特化自身也是模板：

template <class T1> class A
{
    template<class T2> class B
    {
        template<class T3> void mf1(T3); // 成员模板
        void mf2();                      // 非模板成员
    };
};

// 特化
template<> // 对于特化的 A
template<class X> // 对于未特化的 B
class A<int>::B
{
    template <class T> void mf1(T);
};

// 特化
template<> // 对于特化的 A
template<> // 对于特化的 B
template<class T> // 对于未特化的 mf1
void A<int>::B<double>::mf1(T t) {}

// 错误：B<double> 被特化而且是成员模板，所以它外围的 A 也必须特化
template<class Y>
template<> void A<Y>::B<double>::mf2() {}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 727 | C++98 | 不允许在类作用域的全特化，即使允许部分特化 | 允许在任何作用域的全特化

参阅

  • 模板
  • 类模板
  • 函数模板
  • 部分特化


模板

< cpp‎ | language

模板是一个 C++ 实体，它定义以下其一：

  • 一族类（类模板），可以是嵌套类
  • 一族函数（函数模板），可以是成员函数
  • 一族类型的别名（别名模板）
 (C++11 起)
  • 一族变量（变量模板）
 (C++14 起)
  • 概念（约束与概念）
 (C++20 起)

模板以一个或多个模板形参参数化，形参有三种：类型模板形参、非类型模板形参和模板模板形参。

当提供了模板实参，或当函数模板或类 (C++17 起)模板的模板实参被推导出时，它们替换各模板形参，以获得模板的一个特化（specialization），即一个特定类型或一个特定函数左值。特化也可以显式提供：对类、变量 (C++14 起)和函数模板都允许全特化，只允许对类模板和变量模板 (C++14 起) 部分特化。

在要求完整对象类型的语境中引用某个类模板特化时，或在要求函数定义存在的语境中引用某个函数模板特化时，除非模板已经被显式特化或显式实例化，否则模板即被实例化（instantiate）（它的代码被实际编译）。类模板的实例化不会实例化其任何成员函数，除非它们也被使用。在连接时，不同翻译单元生成的相同实例被合并。

模板的定义必须在隐式实例化点可见，这就是模板库通常都在头文件中提供所有模板定义的原因（例如大多数 boost 库只有头文件）

语法

template < 形参列表 > requires子句(可选) 声明 | (1) |
export template < 形参列表 > 声明 | (2) | (C++11 前)
template < 形参列表 > concept 概念名 = 约束表达式 ; | (3) | (C++20 起)
形参列表 | - | 非空的模板形参的逗号分隔列表，其中每项是非类型形参、类型形参、模板形参或任何这些的形参包之一。
requires子句 | - | (C++20 起) 指定了各模板实参上的约束的 requires子句。
声明 | - | 类（包括 struct 和 union），成员类或成员枚举类型，函数或成员函数，命名空间作用域的静态数据成员，变量或类作用域的静态数据成员， (C++14 起)或别名模板 (C++11 起)的声明。它也可以定义模板特化。
概念名 约束表达式 | - | 见约束与概念

export 是一个可选的修饰符，声明模板被导出（用于类模板时，它声明该类的所有成员也被导出）。对被导出模板进行实例化的文件不需要包含其定义：有声明就足够了。export 的实现稀少而且在细节上互不一致。

 (C++11 前)
本节未完成
原因：核心语法，模板形参，以及实例化，带出 class_template 和 function_template 间的公共内容

模板标识

模板名 < 形参列表 >
模板名 - 指名模板的标识符（这种情况下称之为 "简单模板标识"），或重载运算符模板或用户定义字面量模板的名字。

指名类模板特化的 简单模板标识 指名一个类。

指名别名模版特化的 模板标识 指名一个类型。

指名函数模板特化的 模板标识 指名一个函数。

模板标识 只有在符合下列条件时才合法：

  • 实参数量不多于形参，或有一个形参是模板形参包，
  • 每个没有默认模板实参的不可推导的非包形参都有一个实参，
  • 每个模板实参都与对应的模板形参相匹配，
  • 替换每个模板实参到其后续模板形参（如果存在）中均成功，而且
  • 如果 模板标识 非待决，那么它关联得约束需要按下述要求得以满足。
 (C++20 起)

无效的 简单模板标识 是编译时错误，除非它指名的是函数模板特化（此时适用 SFINAE）。

template<class T, T::type n = 0>
class X;

struct S
{
  using type = int;
};

using T1 = X<S, int, int>; // 错误：实参过多
using T2 = X<>;            // 错误：第一个模板形参没有默认实参
using T3 = X<1>;           // 错误：值 1 不匹配类型形参
using T4 = X<int>;         // 错误：第二个模板形参替换失败
using T5 = X<S>;           // OK

如果在 简单模板标识 的模板名指名受约束的非函数模板或受约束的模板模板形参，但不是作为未知特化的成员的成员模板，而且 简单模板标识 中的所有模板实参均非待决，那么必须满足受约束模板的各项关联约束：

template<typename T>
concept C1 = sizeof(T) != sizeof(int);

template<C1 T> struct S1 {};
template<C1 T> using Ptr = T*;

S1<int>* p;                      // 错误：不满足约束
Ptr<int> p;                      // 错误：不满足约束

template<typename T>
struct S2 { Ptr<int> x; };       // 错误，不要求诊断

template<typename T>
struct S3 { Ptr<T> x; };         // OK：不要求满足

S3<int> x;                       // 错误：不满足约束

template<template<C1 T> class X>
struct S4
{
    X<int> x;                    // 错误，不要求诊断
};

template<typename T>
concept C2 = sizeof(T) == 1;

template<C2 T>
struct S {};

template struct S<char[2]>;      // 错误：不满足约束
template<> struct S<char[2]> {}; // 错误：不满足约束
 (C++20 起)

两个 模板标识 在满足下列条件时相同：

  • 它们的 模板名 指代同一模板，且
  • 它们对应的类型模板实参是同一类型，且
  • 它们对应的非类型模板实参在转换到模板形参的类型后模板实参等价，且
  • 它们对应的模板模板实参指代同一模板。

相同的两个 模板标识 指代同一个变量、 (C++14 起)类或函数。

模板化实体

模板化实体（某些资料称之为 "temploid"）是在模板定义内定义（或对于 lambda-表达式 为创建）的实体。下列所有实体都是模板化实体：

  • 类/函数/变量 (C++14 起)模板
  • 概念
 (C++20 起)
  • 模板化实体的成员（例如类模板的非模板成员函数）
  • 作为模板化实体的枚举的枚举项
  • 任何模板化实体中定义或创建的实体：局部类，局部变量，友元函数，等等
  • 模板化实体的声明中出现的 lambda 表达式的闭包类型

例如，在以下模板中：

template<typename T>
struct A
{
    void f() {}
};

函数 A::f 不是函数模板，但它仍然会被当做是模板化的。


this 指针

< cpp‎ | language

语法

this

关键词 this 是一个纯右值 表达式，它的值是隐式对象形参（在其上调用非静态成员函数的对象）的地址。它能出现于下列语境：

1) 在任意非静态成员函数体内，包括成员初始化器列表
2) 在非静态成员函数的声明中，（可能存在的）cv 限定符序列之后的任何位置，包括
  • 动态异常说明、
 (C++17 前)
  • noexcept 说明以及
  • 尾随返回类型
 (C++11 起)
3) 在默认成员初始化器中
 (C++11 起)

在类 X 的成员函数中，this 的类型是 X*（指向 X 的指针）。如果成员函数有 cv 限定，那么 this 的类型是 cv X*（指向有相同 cv 限定的 X 的指针）。因为构造函数与析构函数不能有 cv 限定，所以它们中 this 的类型始终是 X*，即使在构造或销毁 const 对象时也是如此。

当在任何允许 this 关键词的语境（非静态成员函数体、成员初始化器列表、默认成员初始化器）中使用非静态数据成员时，它的名字前会自动添加隐含的 this->，产生一个成员访问表达式（如果该成员是虚成员函数，那么产生虚函数调用）。

在类模板中，this 是一个待决表达式，而且显式的 this-> 可以用于强行使另一表达式变为待决的。

template<typename T>
struct B
{
    int var;
};

template<typename T>
struct D : B<T>
{
    D()
    {
        // var = 1;    // 错误： 'var' 未在此作用域中声明
        this->var = 1; // OK
    }
};

在对象的构造期间，如果通过并非直接或间接从构造函数的 this 指针获得的泛左值访问对象或其任何子对象的值，那么如此获得的对象或子对象的值是未指明的。换言之，构造函数中 this 指针不能被别名化：

extern struct D d;
struct D
{
    D(int a) : a(a), b(d.a) {} // b(a) 或 b(this->a) 是正确的
    int a, b;
};
D d = D(1);   // 因为 b(d.a) 未通过 this 访问，所以 d.b 现在是未指明的

如果程序能保证对象由 new 分配，那么可以执行 delete this;，然而这会令指向被解分配对象的所有指针失效，包括 this 指针自身：在 delete this; 返回后，这种成员函数不能引用类的成员（因为这牵涉到 this 的隐式解引用），且不可再调用其他成员函数。

例如，这被用于 std::shared_ptr 的控制块的负责减少引用数的成员函数中，在最后一个到被管理对象的引用离开作用域时。

 (C++11 起)
class ref
{
    // ...
    void incRef() { ++mnRef; }
    void decRef() { if (--mnRef == 0) delete this; }
};

示例

class T
{
    int x;

    void foo()
    {
        x = 6;       // 等同于 this->x = 6;
        this->x = 5; // 显式使用 this->
    }

    void foo() const
    {
//        x = 7; // 错误：*this 是常量
    }

    void foo(int x) // 形参 x 遮蔽拥有相同名字的成员
    {
        this->x = x; // 无限定的 x 代表形参
                     // 需要用‘this->’消歧义
    }

    int y;
    T(int x) : x(x), // 用形参 x 初始化成员 x
               y(this->x) // 用成员 x 初始化成员 y
    {}

    T& operator= ( const T& b )
    {
        x = b.x;
        return *this; // 许多重载运算符都返回 *this
    }
};

class Outer {
    int a[sizeof(*this)]; // 错误：不在成员函数中
    unsigned int sz = sizeof(*this); // OK：在默认成员初始化器中
    void f() {
        int b[sizeof(*this)]; // OK
        struct Inner {
            int c[sizeof(*this)]; // 错误：不在 Inner 的成员函数中
        };
    }
}


throw 表达式

< cpp‎ | language

对错误条件发信号，并执行错误处理代码。

语法

throw 表达式 | (1)
throw | (2)

解释

更多关于 try 与 catch（异常处理）块的信息见 try-catch 块
1) 首先，从 表达式 复制初始化 异常对象：
  • 这可能调用右值表达式的移动构造函数
  • 这也可能会通过如 return 语句中一般的二步重载决议调用左值表达式的移动构造函数，如果它们指名局部变量或是函数或 catch 子句的形参，且它的作用域不会超出最内层的外围 try 块（如果存在）
 (C++17 起)
  • 复制/移动可能会被复制消除处理
  • 即使复制初始化选择了移动构造函数，从左值复制初始化仍必须为良式，且析构函数必须可访问
 (C++14 起)
然后转移控制给拥有匹配类型，所在的复合语句或成员初始化器列表是最近进入，且未由此执行线程退出的异常处理块。
2) 重抛当前处理的异常。中止当前 catch 块的执行并将控制转移到下一个匹配的异常处理块（但不是到同一个 try 块的下个 catch 子句：它所在的复合语句被认为已经‘退出’），并重用既存的异常对象：不会生成新对象。此形式只能在异常处理过程中使用（其他情况中使用时将调用 std::terminate）。对于构造函数，关联到函数 try 块 的 catch 子句必须通过重抛出退出。

关于在异常处理期间引发错误，见 std::terminate 与 std::unexpected (C++17 前)。

异常对象

异常对象是由 throw 表达式在未指明的存储中构造的临时对象。

异常对象的类型是除去顶层 cv 限定符的 表达式 的静态类型。数组与函数类型分别调整到指针和函数指针类型。如果异常对象的类型是不完整类型或除了指向（可有 cv 限定的）void 的指针以外的不完整类型的指针，那么该 throw 表达式会导致编译时错误。如果 表达式 的类型是类类型，那么它的复制/移动构造函数和析构函数必须可以访问，纵使发生复制消除也是如此。

与其他临时对象不同，异常对象在初始化 catch 子句形参时被认为是左值，所以它可以用左值引用捕获、修改及重抛。

异常对象持续到最后一条不以重抛而退出的 catch 子句（如果不以重抛而退出，那么它紧跟 catch 子句的形参销毁之后被销毁），或持续到引用此对象的最后一个 std::exception_ptr 被销毁（此时异常对象正好在 std::exception_ptr 的析构函数返回前被销毁）。

栈回溯

异常对象构造完成时，控制流立即反向（沿调用栈向上）直到它抵达一个 try 块的起点，在该点按出现顺序将它每个关联的 catch 块的形参和异常对象的类型进行比较，以找到一个匹配（此过程的细节见 try-catch）。如果找不到匹配，那么控制流继续回溯栈直到下个 try 块，以此类推。如果找到匹配，那么控制流跳到匹配的 catch 块。

因为控制流沿调用栈向上移动，所以它会为自进入相应 try 块之后的所有具有自动存储期的已构造但尚未销毁的对象，以其构造函数完成的逆序调用析构函数。当从 return 语句所使用的局部变量或临时量的构造函数中抛出异常时，从函数返回的对象的析构函数也会被调用。 (C++14 起)

如果异常从某个对象的构造函数或（罕见地）从析构函数抛出（不管该对象的存储期），那么就会对所有已经完整构造的非静态非变体 (C++14 前)成员和基类以构造函数完成的逆序调用析构函数。联合体式的类的变体成员只会在从构造函数中回溯的情况中销毁，且如果初始化与销毁之间改变了活动成员，那么行为未定义。 (C++14 起)

如果委托构造函数在非委托构造函数成功完成前以异常退出，那么调用此对象的析构函数。

 (C++11 起)

如果从 new 表达式所调用的构造函数抛出异常，那么调用匹配的解分配函数，如果它可用。

此过程被称为栈回溯（stack unwinding）。

如果由栈回溯机制所直接调用的函数在异常对象初始化后且在异常处理块开始执行前以异常退出，那么就会调用 std::terminate。这种函数包括退出作用域的具有自动存储期的对象的析构函数，和为初始化以值捕获的实参而调用（如果没有被消除）的异常对象的复制构造函数。

如果异常被抛出但未被捕获，包括从 std::thread 的启动函数，main 函数，及任何静态或线程局部对象的构造函数或析构函数中脱离的异常，那么就会调用 std::terminate。是否对未捕获的异常进行任何栈回溯是由实现定义的。

注解

在重抛异常时，必须使用第二个形式，以避免异常对象使用继承的（典型）情况中发生对象切片：

try {
    std::string("abc").substr(10); // 抛出 std::length_error
} catch(const std::exception& e) {
    std::cout << e.what() << '\n';
//  throw e; // 复制初始化一个 std::exception 类型的新异常对象
    throw;   // 重抛 std::length_error 类型的异常对象
}

throw 表达式被归类为 void 类型的纯右值表达式。与任何其他表达式一样，它可以是另一表达式中的子表达式，在条件运算符中最常见：

double f(double d)
{
    return d > 1e7 ? throw std::overflow_error("too big") : d;
}

int main()
{
    try {
        std::cout << f(1e10) << '\n';
    } catch (const std::overflow_error& e) {
        std::cout << e.what() << '\n';
    }
}

关键词

throw

示例

#include <iostream>
#include <stdexcept>

struct A
{
    int n;
    A(int n = 0): n(n) { std::cout << "A(" << n << ") 已成功构造\n"; }
    ~A() { std::cout << "A(" << n << ") 已摧毁\n"; }
};

int foo()
{
    throw std::runtime_error("错误");
}

struct B
{
    A a1, a2, a3;
    B() try : a1(1), a2(foo()), a3(3) {
        std::cout << "B 已成功构造\n";
    } catch(...) {
        std::cout << "B::B() 因异常退出\n";
    }
    ~B() { std::cout << "B 已摧毁\n"; }
};

struct C : A, B
{
    C() try {
        std::cout << "C::C() 已成功完成\n";
    } catch(...) {
        std::cout << "C::C() 因异常退出\n";
    }
    ~C() { std::cout << "C 已摧毁\n"; }
};

int main () try
{
    // 创建 A 基类子对象
    // 创建 B 的成员 a1
    // 创建 B 的成员 a2 失败
    // 回溯销毁 B 的 a1 成员
    // 回溯销毁 A 基类子对象
    C c;
} catch (const std::exception& e) {
    std::cout << "main() 创建 C 失败，原因：" << e.what();
}

输出：

A(0) 已成功构造
A(1) 已成功构造
A(1) 已摧毁
B::B() 因异常退出
A(0) 已摧毁
C::C() 因异常退出
main() 创建 C 失败，原因：错误

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1863 | C++14 | 在抛出时对仅移动异常对象不要求复制构造函数，但允许之后复制 | 要求复制构造函数
CWG 1866 | C++14 | 从构造函数栈回溯时会泄露变体成员 | 变体成员被销毁
CWG 2176 | C++14 | 从局部变量的析构函数抛出时会跳过返回值的析构函数 | 添加函数返回值到回溯过程

参阅

  • try-catch 块
  • noexcept 说明符
  • 异常说明


事务性内存

< cpp‎ | language

事务性内存（transactional memory）是在事务中结合语句组的并发同步机制，事务具有

  • 原子性（atomic）（要么语句全部发生，要么全部不发生）
  • 隔离性（isolated）（事务中的语句不会观察到另一事务写入一半，即使它们并行执行）

典型实现在受支持的平台上将硬件事务性内存使用到极致（例如，直至变更集饱和），再退回到软件事务性内存，后者常以乐观并发（optimistic concurrency）来实现：如果另一事务更新了事务所用的某些变量，那么该事务会安静地重试。由于这个原因，可重试事务（“原子块”）只能调用事务安全的函数。

注意，在没有其他的外部同步的情况下在事务内和事务外访问变量是数据竞争。

如果支持功能特性测试，那么本页所描述的功能特性由具有大于或等于 201505 的值的宏常量 __cpp_transactional_memory 标明。

同步块

synchronized 复合语句

如同在一个全局锁下执行复合语句：程序中的所有最外层同步块都以一个单独的全序执行。在该顺序中，每个同步块的结尾同步于（synchronize with）下个同步块的开始。内嵌于其他同步块的同步块没有特殊语义。

同步块不是事务（不同于后面的原子块），并可以调用事务不安全的函数。

#include <iostream>
#include <vector>
#include <thread>
int f()
{
    static int i = 0;
    synchronized { // 开始同步块
        std::cout << i << " -> ";
        ++i;       // 每次调用 f() 都获得唯一的 i 值
        std::cout << i << '\n';
        return i; // 结束同步块
    }
}
int main()
{
    std::vector<std::thread> v(10);
    for(auto& t: v)
        t = std::thread([]{ for(int n = 0; n < 10; ++n) f(); });
    for(auto& t: v)
        t.join();
}

输出：

0 -> 1
1 -> 2
2 -> 3
...
99 -> 100

以任何方式（抵达结尾，执行 goto、break、continue 或 return，或抛出异常）离开同步块都会退出该块，而如果退出的块是外层块，那么这在单一全序中同步于下个同步块。如果使用 std::longjmp 退出同步块则行为未定义。

不允许用 goto 或 switch 进入同步块。

尽管同步块如同在一个全局锁下执行，我们仍然期待各实现检验每个块内的代码，并为事务安全代码使用乐观并发（在可用时以硬件事务性内存为后盾），为非事务安全代码使用最小锁定。当同步块调用非内联函数时，除非该函数声明为 transaction_safe（见下文）或使用 [[optimize_for_synchronized]] 属性（见下文），否则编译器可能必须放弃推测执行（spculative execution），并在整个调用周围持有一个锁。

原子块

本节未完成

atomic_noexcept 复合语句

atomic_cancel 复合语句

atomic_commit 复合语句

1) 如果抛出异常，那么调用 std::abort
2) 如果抛出异常，那么调用 std::abort，除非该异常是用于事务取消的异常之一（见后述），这种情况下事务被取消（cancel）：程序中所有由该原子块的各操作的副作用所修改的内存位置的值，被还原到该原子块的执行开始时它们曾拥有的值，而异常照常持续栈回溯。
3) 如果抛出异常，那么正常提交事务。

用于 atomic_cancel 块中的事务取消的异常有 std::bad_alloc、std::bad_array_new_length、std::bad_cast、std::bad_typeid、std::bad_exception、std::exception 和所有从它派生的标准库异常，以及特殊异常类型 std::tx_exception<T>。

不允许原子块中的 复合语句 执行任何非 transaction_safe 的表达式或语句，或调用非 transaction_safe 的函数（这是编译时错误）。

// 每次调用 f() 都取得唯一的 i 值，即使以并行进行
int f()
{
   static int i = 0;
   atomic_noexcept { // 开始事务
//   printf("before %d\n", i); // 错误：不能调用非事务安全的函数
      ++i;
      return i; // 提交事务
   }
}

以除异常之外的任何方式（抵达结尾、goto、break、continue、return）离开原子块时，将提交事务。如果用 std::longjmp 退出原子块则行为未定义。

事务安全的函数

本节未完成

可在函数声明中用关键词 transaction_safe 将其显式声明为事务安全。

本节未完成
Lambda 表达式声明中，它可以紧跟俘获列表之后，或紧跟关键词 mutable 之后（如果使用它）出现。
本节未完成

extern volatile int * p = 0;
struct S {
  virtual ~S();
};
int f() transaction_safe {
  int x = 0; // OK：非 volatile
  p = &x; // OK：指针非 volatile
  int i = *p; // 错误：通过 volatile 泛左值读取
  S s; // 错误：调用不安全的析构函数
}
int f(int x) { // 隐式事务安全
  if (x <= 0)
    return 0;
  return x + f(x-1);
}

如果通过指向事务安全函数的引用或指针调用非事务安全的函数，那么行为未定义。

指向事务安全函数的指针和指向事务安全成员函数的指针分别可隐式转换为函数指针和成员函数指针。结果指针和原指针是否比较相等是未指明的。

事务安全的虚函数

本节未完成

如果 transaction_safe_dynamic 函数的最终覆盖函数未被声明为 transaction_safe，那么在原子块中调用它是未定义行为。

标准库

除了引入新的异常模板 std::tx_exception 之外，事务性内存技术规范还对标准库做出下列更改：

  • 令下列函数为显式 transaction_safe：
  • std::forward、std::move、std::move_if_noexcept、std::align、std::abort、全局默认 operator new、全局默认 operator delete、std::allocator::construct（如果调用的构造函数是事务安全的）、std::allocator::destroy（如果调用的析构函数是事务安全的）、std::get_temporary_buffer、std::return_temporary_buffer、std::addressof、std::pointer_traits::pointer_to、所有支持事务取消的异常类型（见上文的 atomic_cancel）的每个非虚成员函数
    本节未完成
    原因：还有更多
  • 令下列函数为显式 transaction_safe_dynamic：
  • 所有支持事务取消的异常类型（见上文的 atomic_cancel）的每个虚函数
  • 要求分配器 (Allocator) X 上所有事务安全的操作在 X::rebind<>::other 上也是事务安全的

属性

[[optimize_for_synchronized]] 属性可以应用到函数声明中的声明符中，而且必须在函数的首个声明上出现。

如果某函数在一个翻译单元中被声明为 [[optimize_for_synchronized]]，而同一个函数在另一翻译单元中的声明不带 [[optimize_for_synchronized]]，那么程序非良构；不要求诊断。

它指示函数定义应该针对从 synchronized 语句中调用而优化。具体而言，如果函数对大多数的调用但非全部调用为事务安全（例如可能必须重算散列的哈希表插入、可能必须请求新内存块的分配器、可能罕有记录日志的简单函数），那么该属性避免对调用该函数的同步块进行串行化。

std::atomic<bool> rehash{false};

// 维护线程运行此循环
void maintenance_thread(void*) {
    while (!shutdown) {
        synchronized {
            if (rehash) {
                hash.rehash();
                rehash = false;
            }
        }
    }
}

// 工作线程每秒执行数十万次对此函数的调用。
// 从另一翻译单元中的同步块调用 insert_key() 将导致这些块被串行化，
// 除非标记 insert_key() 为 [[optimize_for_synchronized]]
[[optimize_for_synchronized]] void insert_key(char* key, char* value) {
  bool concern = hash.insert(key, value);
  if (concern) rehash = true;
}

无该属性的 GCC 汇编：串行化整个函数

insert_key(char*, char*):
        subq    $8, %rsp
        movq    %rsi, %rdx
        movq    %rdi, %rsi
        movl    $hash, %edi
        call    Hash::insert(char*, char*)
        testb   %al, %al
        je      .L20
        movb    $1, rehash(%rip)
        mfence
.L20:
        addq    $8, %rsp
        ret

有该属性的 GCC 汇编：

transaction clone for insert_key(char*, char*):
        subq    $8, %rsp
        movq    %rsi, %rdx
        movq    %rdi, %rsi
        movl    $hash, %edi
        call    transaction clone for Hash::insert(char*, char*)
        testb   %al, %al
        je      .L27
        xorl    %edi, %edi
        call    _ITM_changeTransactionMode # 注意：这是串行化点
        movb    $1, rehash(%rip)
        mfence
.L27:
        addq    $8, %rsp
        ret
本节未完成
原因：检查带主干的汇编，也显示调用方的更改

注解

本节未完成
原因：来自 Wyatt 提案/讨论的体验笔记

编译器支持

GCC 从版本 6.1 起支持此技术规范（要求启用 -fgnu-tm）。GCC 4.7 时曾支持此规范的一个旧版变体。


try 块

< cpp‎ | language

将一或多个异常处理块（catch 子句）与复合语句关联。

语法

try 复合语句 处理块序列

其中 处理块序列 是一或多个 处理块 的序列，它有下列语法：

catch ( 属性(可选) 类型说明符序列 声明符 ) 复合语句 | (1)
catch ( 属性(可选) 类型说明符序列 抽象声明符(可选) ) 复合语句 | (2)
catch ( ... ) 复合语句 | (3)
复合语句 | - | 花括号环绕的语句序列
属性 | - | (C++11 起) 任意数量的属性，应用于形参
类型说明符序列 | - | 形参声明的一部分，与在函数形参列表中相同
声明符 | - | 形参声明的一部分，与在函数形参列表中相同
抽象声明符 | - | 无名形参声明的一部分，与在函数形参列表中相同
1) 声明一个具名形参的 catch 子句
try { /* */ } catch (const std::exception& e) { /* */ }
2) 声明一个无名形参的 catch 子句
try { /* */ } catch (const std::exception&) { /* */ }
3) catch-all 处理块，可被任何异常激活
try { /* */ } catch (...) { /* */ }

解释

更多关于 throw 表达式的信息见抛出异常

try 块是一条语句，从而能出现于任何语句所能出现处（即作为复合语句中的语句之一，包含函数体复合语句）。有关围绕函数体的 try 块，见函数 try 块。下列描述同时适用于 try 块和函数 try 块。

catch 子句的形参（类型说明符序列 与 声明符，或者 类型说明符序列 与 抽象声明符）决定何种类型的异常导致进入此 catch 子句。它不能是右值引用类型、抽象类、不完整类型或指向不完整类型的指针（但允许指向（可有 cv 限定的）void 的指针）。若形参的类型是数组类型或函数类型，则它被处理成对应的指针类型（类似于函数声明）。

当 复合语句 中的任何语句抛出了类型 E 的异常时，以之对 处理块序列 中的每个 catch 子句的形参类型 T，按 catch 子句的列出顺序进行匹配。若下列任一为真则异常得到匹配：

  • E 与 T 是同一类型（忽略 T 上的顶层 cv 限定符）
  • T 是到（可为 cv 限定的）E 的左值引用
  • T 是 E 的无歧义公开基类
  • T 是到 E 的无歧义公开基类的引用
  • T 是（可为 cv 限定的）U 或 const U& (C++14 起)，且 U 是指针或成员指针 (C++17 起)类型，且 E 亦为能通过下列转换中的一或多个转换成 U 的指针或成员指针 (C++17 起)类型
  • 并非到指向私有、受保护或有歧义基类指针的指针转换
  • 限定性转换
  • 函数指针转换
 (C++17 起)
  • T 是指针或成员指针，或 const 指针的引用 (C++14 起)，而 E 是 std::nullptr_t.
try {
    f();
} catch (const std::overflow_error& e) {
    // 若 f() 抛出 std::overflow_error 则执行之（“相同类型”规则）
} catch (const std::runtime_error& e) {
    // 若 f() 抛出 std::underflow_error 则执行之（“基类”规则）
} catch (const std::exception& e) {
    // 若 f() 抛出 std::logic_error 则执行之（“基类”规则）
} catch (...) {
    // 若 f() 抛出 std::string 或 int 或任何其他无关类型则执行之
}

全捕获（catch-all）子句 catch (...) 匹配任何类型的异常。若存在，则它必须是 处理块序列 中的最后一个 catch 子句。Catch-all 块可用于确保不可能有未捕获异常从提供不抛出异常保证的函数逃逸。

若检测所有 catch 子句后仍无匹配，则到外围的 try 块继续异常的传播，如 throw 表达式中所述。若没有剩下的外围 try 块，则执行 std::terminate（此情况下，由实现定义是否完全进行栈回溯：容许抛出未捕获异常导致程序终止而不调用任何析构函数）。

当进入一个 catch 子句时，若其形参是异常类型的基类，则它从异常对象的基类子对象进行复制初始化。否则，它从异常对象复制初始化（这个复制服从复制消除规则）。

try {
   std::string("abc").substr(10); // 抛出 std::length_error
// } catch (std::exception e) { // 从 std::exception 基类复制初始化
//     std::cout << e.what(); // 丢失来自 length_error 的信息
// }
} catch (const std::exception& e) { // 多态对象基类的引用
     std::cout << e.what(); // 打印来自 length_error 的信息
}

若 catch 子句的形参是引用类型，则对它所做的任何更改都会反映到异常对象之中，且若以 throw; 重抛这个异常，则可为另一处理块所观测到。若形参不是引用，则任何对它的更改都是局域的，且其生存期在处理块退出时结束。

在 catch 子句内，可以使用 std::current_exception 把异常捕获到一个 std::exception_ptr 之中，而且可以使用 std::throw_with_nested 来构建嵌套的异常。

 (C++11 起)

goto 和 switch 语句不能用来转移控制进入 try 块以及处理块。

除了抛出或重抛异常以外，普通的 try 块（非函数 try 块）之后的 catch 子句还可以通过 return、continue、break、goto，或通过抵达其 复合语句 尾而退出。任何这些情况，都会销毁异常对象（除非存在指代它的 std::exception_ptr 实例）。

注解

不保证捕捉指针的 catch 子句能够匹配 throw 表达式 throw NULL ;，因为异常对象类型可以是整数类型，但可以确保任何指针或成员指针的 catch 子句能够匹配 throw nullptr;。

若派生类的 catch 子句被置于基类的 catch 子句后，则永远不会执行派生类 catch 子句。

try {
    f();
} catch (const std::exception& e) {
    // 若 f() 抛 std::runtime_error 则执行
} catch (const std::runtime_error& e) {
    // 死代码！
}

若用 goto 退出 try 块，且若这个 goto 所执行的任何块作用域自动变量的析构函数由于抛异常而退出，则那些异常被该变量定义于其中的 try 块所捕捉：

label:
    try {
        T1 t1;
        try {
            T2 t2;
            if(condition)
                goto label; // 销毁 t2，然后销毁 t1，再跳到 label
        } catch (...) {  } // 捕捉来自 t2 析构函数的异常
    } catch (...) {  } // 捕捉来自 t1 析构函数的异常

关键词

try, catch, throw

示例

下列代码演示 try-catch 块的数种用法

#include <iostream>
#include <vector>

int main() {
    try {
        std::cout << "Throwing an integer exception...\n";
        throw 42;
    } catch (int i) {
        std::cout << " the integer exception was caught, with value: " << i << '\n';
    }

    try {
        std::cout << "Creating a vector of size 5... \n";
        std::vector<int> v(5);
        std::cout << "Accessing the 11th element of the vector...\n";
        std::cout << v.at(10); // vector::at() 抛出 std::out_of_range
    } catch (const std::exception& e) { // 按基类的引用捕获
        std::cout << " a standard exception was caught, with message '"
                  << e.what() << "'\n";
    }

}

可能的输出：

Throwing an integer exception...
 the integer exception was caught, with value: 42
Creating a vector of size 5...
Accessing the 11th element of the vector...
 a standard exception was caught, with message 'out_of_range'

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 98 | C++98 | switch 语句可以转移控制进入 try 块以及处理块 | 已禁止


翻译单元局部实体 (C++20 起)

< cpp‎ | language

翻译单元局部（ TU 局部）实体是为阻止假定为局部（不用于任何其他翻译单元）的实体暴露且用于其他翻译单元而引入的。

来自了解 C++ 模块：部分 2 的例子描绘了不约束暴露的问题：

// 无 TU 局部约束的模块单元
export module Foo;

import <iostream>;

namespace {
   class LolWatchThis {        // 内部链接，不能导出
       static void say_hello() {
           std::cout << "Hello, everyone!\n";
       }
   };
}

export LolWatchThis lolwut() { // LolWatchThis 被暴露为返回类型
    return LolWatchThis();
}
// main.cpp
import Foo;

int main() {
    auto evil = lolwut();        // 'evil' 拥有 'LolWatchThis' 类型
    decltype(evil)::say_hello(); // 'LolWatchThis' 的定义不再为内部
}

TU 局部实体

一个实体为 TU 局部，若它为

  1. 类型、函数、变量或模板，且
    1. 拥有带内部链接的名字，或
    2. 无拥有内部链接的名字，且在 TU 局部实体之内声明或由 lambda 表达式引入、
  2. 定义在类说明符、函数体或初始化器外，或由用于声明仅 TU 局部实体的定义类型说明符（类型说明符、类说明符或枚举说明符）引入、
  3. TU 局部模板的特化、
  4. 有任何 TU 局部模板实参的模板特化，或
  5. 其声明为暴露（定义后述）的（可能实例化的）模板特化。
// 拥有内部链接的 TU 局部实体
namespace { // 声明于无名命名空间的所有名字均拥有内部链接
    int tul_var = 1;                          // TU 局部变量
    int tul_func() { return 1; }              // TU 局部函数
    struct tul_type { int mem; };             // TU 局部（类）类型
}
template<typename T>
static int tul_func_temp() { return 1; }      // TU 局部模板

// TU 局部模板特化
template<>
static int tul_func_temp<int>() { return 3; } // TU 局部特化

// 有 TU 局部模板实参的模板特化
template <> struct std::hash<tul_type> {      // TU 局部特化
    std::size_t operator()(const tul_type& t) const { return 4u; }
};
本节未完成
原因：缺少规则 #1.2、 #2 及 #5 的示例

值或对象为 TU 局部，若它

  1. 是 TU 局部的函数或与 TU 局部变量关联的对象，或是指向它的指针，或者
  2. 是类或数组类型对象，而其任一子对象，或其引用类型非静态数据成员所引用的对象或函数，为 TU 局部并且可用于常量表达式。
static int tul_var = 1;             // TU 局部变量
static int tul_func() { return 1; } // TU 局部函数

int* tul_var_ptr = &tul_var;        // TU 局部：指向 TU 局部变量的指针
int (* tul_func_ptr)() = &tul_func; // TU 局部：指向 TU 局部函数的指针

constexpr static int tul_const = 1; // TU 局部变量可用于常量表达式
int tul_arr[] = { tul_const };      // TU 局部： constexpr TU 局部对象的数组
struct tul_class { int mem; };
tul_class tul_obj{tul_const};       // TU 局部：拥有成员 constexpr TU 局部对象

暴露

声明 D 指名实体 E ，若

  1. D 含有闭包类型为 E 的 lambda 表达式、
  2. E 不是函数或函数模板且 D 含有指代 E 的标识表达式、类型说明符、嵌套类型说明符、模板名或概念名，或
  3. E 是函数或函数模板且 D 含有指名 E 的表达式或指代含有 E 的重载集的标识表达式。
// lambda 指名
auto x = [] {}; // 指名 decltype(x)

// 非函数（模板）指名
int y1 = 1;                      // 指名 y1 （标识表达式）
struct y2 { int mem; };
y2 y2_obj{1};                    // 指名 y2 （类型说明符）
struct y3 { int mem_func(); };
int y3::mem_func() { return 0; } // 指名 y3 （嵌套类型说明符）
template<typename T> int y4 = 1;
int var = y4<y2>;                // 指名 y4 （模板名）
template<typename T> concept y5 = true;
template<typename T> void func(T&&) requires y5<T>; // 指名 y5 （概念名）

// 函数（模板）指名
int z1(int arg)      { std::cout << "no overload"; return 0; }
int z2(int arg)      { std::cout << "overload 1";  return 1; }
int z2(double arg)   { std::cout << "overload 2";  return 2; }

int val1 = z1(0); // 指名 z1
int val2 = z2(0); // 指名 z2 （int z2(int)）

一个声明是暴露，若它要么指名一个 TU 局部实体，不过忽略

  1. 非 inline 函数或函数模板的函数体（但非用占位符类型声明返回类型的函数的（可能实例化的）定义的推导返回类型），
  2. 变量或变量模板的初始化器（但非变量类型），
  3. 类定义中的友元声明，及
  4. 任何到拥有内部链接或无链接的、以非 odr 使用的常量表达式初始化的非 volatile 的 const 对象或引用的引用，

这些情况，要么定义以 TU 局部值初始化的 constexpr 变量。

本节未完成
原因：缺少暴露的示例

TU 局部约束

若模块接口单元（在可能有的私有模块片段外）或模块划分中的非 TU 局部实体的（可能实例化的）声明或推导指引为暴露，则程序非良构。这种声明在在任何其他语境中被弃用。

若出现于一个翻译单元中的声明指名在另一非头文件单元的翻译单元中声明的 TU 局部实体，则程序非良构。为模板特化实例化的声明出现在特化的实例化点。

本节未完成
原因：缺少约束的示例

示例

翻译单元 #1：

export module A;
static void f() {}
inline void it() { f(); }         // 错误：为 f 的暴露
static inline void its() { f(); } // OK
template<int> void g() { its(); } // OK
template void g<0>();

decltype(f) *fp;                             // 错误： f （尽管不是其类型）为 TU 局部
auto &fr = f;                                // OK
constexpr auto &fr2 = fr;                    // 错误：为 f 的暴露
constexpr static auto fp2 = fr;              // OK
struct S { void (&ref)(); } s{f};            // OK： value 为 TU 局部
constexpr extern struct W { S &s; } wrap{s}; // OK： value 非 TU 局部 TU-local

static auto x = []{f();}; // OK
auto x2 = x;              // 错误：闭包类型为 TU 局部
int y = ([]{f();}(),0);   // 错误：闭包类型非 TU 局部
int y2 = (x,0);           // OK

namespace N {
    struct A {};
    void adl(A);
    static void adl(int);
}
void adl(double);

inline void h(auto x) { adl(x); } // OK ，但特化可能为暴露

翻译单元 #2：

module A;
void other() {
    g<0>();                  // OK：显式实例化特化
    g<1>();                  // 错误：实例化使用其 TU 局部实体
    h(N::A{});               // 错误：重载集含 TU 局部的 N::adl(int)
    h(0);                    // OK：调用 adl(double)
    adl(N::A{});             // OK：找不到 N::adl(int) ，调用 N::adl(N::A)
    fr();                    // OK：调用 f
    constexpr auto ptr = fr; // 错误：此处 fr 不可用于常量表达式
}
本节未完成
原因：示例太复杂，需要更好的安排


类型别名，别名模版 (C++11 起)

< cpp‎ | language

类型别名是指代【先前定义的类型】的名字（与 typedef 类似）。

别名模版是指代一族类型的名字。

语法

别名声明是具有下列语法的声明：

using 标识符 属性(可选) = 类型标识 ; | (1)
template < 模板形参列表 > using 标识符 属性(可选) = 类型标识 ; | (2)
属性(C++11) | - | 可选的任意数量属性的序列
标识符 | - | 此声明引入的名字，它成为一个类型名 (1) 或一个模板名 (2)
模板形参列表 | - | 模板形参列表，同模板声明
类型标识 | - | 抽象声明符或其他任何合法的 类型标识（可以引入新类型，如 类型标识 中所注明）。类型标识 不能直接或间接涉指 标识符。注意，标识符的声明点处于跟在 类型标识 之后的分号处。

解释

1) 类型别名声明引入一个名字，可用做 类型标识 所指代的类型的同义词。它不引入新类型，且不能更改既存类型名的含义。类型别名声明和 typedef 声明之间没有区别。此类声明可出现于块作用域、类作用域或命名空间作用域。
2) 别名模板是一种模板，当其特化时等价于以别名模板的模板实参来替换 类型标识 中的模板形参的结果。
template<class T>
struct Alloc { };
template<class T>
using Vec = vector<T, Alloc<T>>; // 类型标识为 vector<T, Alloc<T>>
Vec<int> v; // Vec<int> 等同于 vector<int, Alloc<int>>

当特化别名模板的结果是一个待决的模板标识时，对这个模板标识应用后继的替换：

template<typename...>
using void_t = void;
template<typename T>
void_t<typename T::foo> f();
f<int>(); // 错误，int 没有嵌套类型 foo

特化别名模版时所生成的类型不允许直接或间接使用它自己的类型：

template<class T>
struct A;
template<class T>
using B = typename A<T>::U; // 类型标识为 A<T>::U
template<class T>
struct A { typedef B<T> U; };
B<short> b; // 错误：B<short> 通过 A<short>::U 使用其自身类型

在推导模板模板形参时，模板实参推导始终不推导别名模板。

不能部分特化或显式特化别名模板。

与任何模板声明相似，别名模版只能在类作用域或命名空间作用域被声明。

出现于别名模版声明中的lambda 表达式的类型在该模板的不同实例化间不同，即使该 lambda 表达式非待决。

template <class T>
using A = decltype([] { }); // A<int> 与 A<char> 指代不同的闭包类型
 (C++20 起)

示例

#include <string>
#include <ios>
#include <type_traits>

// 类型别名，等同于
// typedef std::ios_base::fmtflags flags;
using flags = std::ios_base::fmtflags;
// 名字 'flags' 现在指代类型：
flags fl = std::ios_base::dec;

// 类型别名，等同于
// typedef void (*func)(int, int);
using func = void (*) (int, int);
// 名字 'func' 现在指代函数指针：
void example(int, int) {}
func f = example;

// 别名模板
template<class T>
using ptr = T*;
// 名字 'ptr<T>' 现在是指向 T 的指针的别名
ptr<int> x;

// 用于隐藏模板形参的别名模版
template<class CharT>
using mystring = std::basic_string<CharT, std::char_traits<CharT>>;
mystring<char> str;

// 别名模板可引入成员 typedef 名
template<typename T>
struct Container { using value_type = T; };
// 可用于泛型编程
template<typename ContainerType>
void g(const ContainerType& c) { typename ContainerType::value_type n; }

// 用于简化 std::enable_if 语法的类型别名
template<typename T>
using Invoke = typename T::type;
template<typename Condition>
using EnableIf = Invoke<std::enable_if<Condition::value>>;
template<typename T, typename = EnableIf<std::is_polymorphic<T>>>
int fpoly_only(T t) { return 1; }

struct S { virtual ~S() {} };

int main()
{
    Container<int> c;
    g(c); // Container::value_type 将在此函数中是 int
//  fpoly_only(c); // 错误：被 enable_if 禁止
    S s;
    fpoly_only(s); // OK：被 enable_if 允许
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1558 | C++11 | 别名模板特化中的未使用实参是否参与替换是未指明的 | 进行替换

参阅

typedef 声明 | 为类型创建同义词
命名空间别名 | 为既存命名空间创建一个别名


typedef 说明符

< cpp‎ | language
  • typedef - 创建能在任何位置替代（可能复杂的）类型名的别名。

解释

当在声明的 声明说明符序列 中使用 typedef 说明符时，指定该声明为 typedef 声明，而非变量或函数声明。 typedef 常在声明的起始处出现，尽管它也可以出现在类型说明符后或两个类型说明符之间。

typedef 声明可以在同一行声明一个或多个标识符（例如 int 和指向 int 的指针），它可以声明数组和函数类型、指针和引用、类类型等。此声明中引入的每个标识符都成为 typedef 名，它是假如关键词 typedef 被移除时标识符本应成为的对象或函数的类型的同义词。

除类型说明符外，typedef 说明符不能与其他说明符组合。

typedef 名是既存类型的别名，而非对新类型的声明。typedef 不能用于更改既存类型名（包含 typedef 名）的含义。一旦声明，则 typedef 名只可重声明为再次指代同一类型。typedef 名只会在它为可见的作用域有效：不同函数或类声明中可以定义具有不同含义的同名类型。

typedef 说明符不可出现于不含声明符的声明中。

typedef struct X {}; // 非良构
 (C++17 起)

链接目的的 typedef 名

正式而言，如果 typedef 声明定义了一个无名类或枚举，那么只有该声明声明的首个作为该类类型或枚举类型的 typedef 名用于代表类类型或枚举类型。例如在 typedef struct { /* ... */ } S; 中， S 是链接目的的 typedef 名。以此方式定义的类或枚举名拥有外部链接（除非它在无名命名空间中）。

以此方式定义的无名类应当仅含与 C 兼容的构造。具体而言，它必须不

  • 声明除了非静态数据成员、成员枚举或成员类以外的任何成员，
  • 拥有任何基类或默认成员初始化器，或
  • 含有 lambda 表达式，

而所有成员类也必须（递归地）满足这些要求。

 (C++20 起)

关键词

typedef

注解

类型别名通过不同的语法提供与 typedef 相同的功能，而且也可以用于模板名。

示例

// 简单 typedef
typedef unsigned long ulong;

// 下面两个对象拥有同一类型
unsigned long l1;
ulong l2;

// 更复杂的 typedef
typedef int int_t, *intp_t, (&fp)(int, ulong), arr_t[10];

// 下面两个对象拥有同一类型
int a1[10];
arr_t a2;

// 避免必须写 "struct S" 的常见 C 手法
typedef struct {int a; int b;} S, *pS;

// 下面两个对象拥有相同类型
pS ps1;
S* ps2;

// 错误：存储类说明符不能出现于 typedef 声明中
// typedef static unsigned int uint;

// typedef 可用在 声明说明符序列 中的任何位置
long unsigned typedef int long ullong;
// 写作 "typedef unsigned long long int ullong;" 更符合惯例

// std::add_const，与许多其他元函数相似，使用了成员 typedef
template< class T>
struct add_const {
    typedef const T type;
};

typedef struct Node {
    struct listNode* next; // 声明名为 listNode 的新的（不完整）结构体类型
} listNode; // 错误：与先前声明的结构体名冲突

参阅


typeid 运算符

< cpp‎ | language

查询类型的信息。

用于必须知晓多态对象的动态类型的场合以及静态类型鉴别。

语法

typeid ( 类型 ) | (1)
typeid ( 表达式 ) | (2)

在使用 typeid 前必须包含头文件 <typeinfo>（如果不包含该头文件，则每次使用关键词 typeid 都令程序为谬构。）

typeid 表达式为左值表达式，指代一个具有静态存储期的，多态类型 std::type_info 或某个其派生类型的 const 限定版本类型的对象。

解释

1) 指代一个表示 类型 类型的 std::type_info 对象。若 类型 为引用类型，则结果所指代的 std::type_info 对象表示被引用的类型。
2) 检验表达式 表达式
a) 若 表达式 为标识某个多态类型（即声明或继承至少一个虚函数的类）对象的泛左值表达式，则 typeid 表达式对该表达式求值，然后指代表示该表达式动态类型的 std::type_info 对象。若该泛左值表达式为通过对一个指针应用一元 * 运算符所得，且该指针为空指针值，则抛出 std::bad_typeid 类型或从 std::bad_typeid 派生的类型的异常。
b) 若 表达式 不是多态类型的泛左值表达式，则 typeid 不对该表达式求值，而它所指代的 std::type_info 对象表示该表达式的静态类型。不进行左值到右值、数组到指针或函数到指针转换。然而对于纯右值参数，（形式上）要进行临时量实质化：参数必须在 typeid 表达式所出现的语境中可析构。 (C++17 起)

在所有情况下，typeid 都忽略顶层的 cv 限定符（即 typeid(T) == typeid(const T)）。

若 typeid 的操作数为类类型或到类类型的引用，则该类类型不得为不完整类型。

若对处于构造和销毁过程中的对象（在构造函数或析构函数之内，包括构造函数的初始化器列表或默认成员初始化器）使用 typeid，则此 typeid 所指代的 std::type_info 对象表示正在构造或销毁的类，即便它不是最终派生类。

关键词

typeid

注解

当应用于多态类型的表达式时，typeid 表达式的求值可能涉及运行时开销（虚表查找），其他情况下 typeid 表达式都在编译时解决。

typeid 所指代的对象的析构函数是否在程序结束时执行是未指明的。

不保证同一类型上的 typeid 表达式的所有求值都指代同一个 std::type_info 实例，不过这些 type_info 对象的 std::type_info::hash_code 相同，其 std::type_index 也相同。

const std::type_info& ti1 = typeid(A);
const std::type_info& ti2 = typeid(A);

assert(&ti1 == &ti2); // 不保证
assert(ti1.hash_code() == ti2.hash_code()); // 保证
assert(std::type_index(ti1) == std::type_index(ti2)); // 保证

示例

该示例展示使用一种实现时的输出，其中 type_info::name 返回完整类型名；若使用 gcc 或相似者则须通过 c++filt -t 过滤。

#include <iostream>
#include <string>
#include <typeinfo>

struct Base {}; // 非多态
struct Derived : Base {};

struct Base2 { virtual void foo() {} }; // 多态
struct Derived2 : Base2 {};

int main() {
    int myint = 50;
    std::string mystr = "string";
    double *mydoubleptr = nullptr;

    std::cout << "myint 的类型：" << typeid(myint).name() << '\n'
              << "mystr 的类型：" << typeid(mystr).name() << '\n'
              << "mydoubleptr 的类型：" << typeid(mydoubleptr).name() << '\n';

    // std::cout << myint 为多态类型的泛左值表达式；求值
    const std::type_info& r1 = typeid(std::cout << myint);
    std::cout << '\n' << "std::cout<<myint 的类型：" << r1.name() << '\n';

    // std::printf() 不是多态类型的泛左值表达式；不求值
    const std::type_info& r2 = typeid(std::printf("%d\n", myint));
    std::cout << "printf(\"%d\\n\",myint) 的类型：" << r2.name() << '\n';

    // 非多态左值时为静态类型
    Derived d1;
    Base& b1 = d1;
    std::cout << "非多态基类的引用：" << typeid(b1).name() << '\n';

    Derived2 d2;
    Base2& b2 = d2;
    std::cout << "多态基类的引用：" << typeid(b2).name() << '\n';

    try {
        // 解引用空指针：对于非多态表达式 OK
        std::cout << "mydoubleptr 指向 " << typeid(*mydoubleptr).name() << '\n';
        // 解引用空指针：对多态左值则不行
        Derived2* bad_ptr = nullptr;
        std::cout << "bad_ptr 指向...";
        std::cout << typeid(*bad_ptr).name() << '\n';
    } catch (const std::bad_typeid& e) {
         std::cout << " 捕获 " << e.what() << '\n';
    }
}

可能的输出：

myint 的类型：int
mystr 的类型：std::basic_string<char, std::char_traits<char>, std::allocator<char> >
mydoubleptr 的类型：double*
50
std::cout<<myint 的类型：std::basic_ostream<char, std::char_traits<char> >
printf("%d\n",myint) 的类型：int
非多态基类的引用：Base
多态基类的引用：Derived2
mydoubleptr 指向 double
bad_ptr 指向... 捕获 std::bad_typeid


基础类型

< cpp‎ | language

（类型系统概览见类型，以及参阅 C++ 库提供的类型相关的工具列表）

void 类型

void - 值为空集的类型。它是无法变为完整的不完整类型（从而不允许存在 void 类型的对象）。不存在含有 void 的数组以及到 void 的引用。然而 指向 void 的指针和返回 void 类型的函数是允许存在的（其他语言中的过程）。

std::nullptr_t

定义于头文件 <cstddef> |
typedef decltype(nullptr) nullptr_t; | (C++11 起)

std::nullptr_t 是空指针字面量 nullptr 的类型。它是独立类型，既非指针类型，亦非成员指针类型。

布尔类型

bool - 足以存放两个值 true 或 false 之一的类型。 sizeof(bool) 的值由实现定义，而且可以不为 1 。

数据模型

每个实现关于基础类型大小所做的选择被统称为数据模型。有四个数据模型广为接受：

32 位系统：

  • LP32 或 2/4/4 （ int 为 16 位， long 和指针为 32 位）
  • Win16 API
  • ILP32 或 4/4/4 （ int 、 long 和指针为 32 位）
  • Win32 API
  • Unix 和类 Unix 系统（ Linux 、 macOS ）

64 位系统：

  • LLP64 或 4/4/8 （ int 和 long 为 32 位，指针为 64 位）
  • Win64 API
  • LP64 或 4/8/8 （ int 为 32 位， long 和指针为 64 位）
  • Unix 和类 Unix 系统（ Linux 、 macOS ）

其他数据模型很罕见。例如， ILP64 （ 8/8/8 ： int 、 long 和指针为 64 位）只出现于某些早期 64 位 Unix 系统（例如 UNICOS on Cray ）。

整数类型

int - 基本整数类型。若使用了下列任何修饰符则可省略关键词 int 。若无长度修饰符，则它保证拥有至少 16 位宽度。然而在 32/64 位系统上，几乎专门保证它拥有至少 32 位宽度（见后述）。

修饰符

修饰整数类型。能以任何顺序混合使用。类型名中每组只能有一个。

符号性

signed - 目标类型将拥有有符号表示（若省略则此为默认）
unsigned - 目标类型将拥有无符号表示

大小

short - 目标类型将为空间优化，且将有至少 16 位的宽度。
long - 目标类型将有至少 32 位的宽度。
long long - 目标类型将有至少 64 位的宽度。
 (C++11 起)

注意：与所有类型说明符相同，容许采用任何顺序： unsigned long long int 与 long int unsigned long 指名同一类型。

性质

下表总结了所有可用的整数类型及其在各种常用数据模型中的性质：

类型说明符 | 等价类型 | 按数据模型的位宽
 |  | C++ 标准 | LP32 | ILP32 | LLP64 | LP64
short | short int | 至少 16 | 16 | 16 | 16 | 16
short int
signed short
signed short int
unsigned short | unsigned short int
unsigned short int
int | int | 至少 16 | 16 | 32 | 32 | 32
signed
signed int
unsigned | unsigned int
unsigned int
long | long int | 至少 32 | 32 | 32 | 32 | 64
long int
signed long
signed long int
unsigned long | unsigned long int
unsigned long int
long long | long long int (C++11) | 至少 64 | 64 | 64 | 64 | 64
long long int
signed long long
signed long long int
unsigned long long | unsigned long long int (C++11)
unsigned long long int

注意：整数算术对有符号和无符号整数类型的定义是不同的。见算术运算符，特别是整数溢出。

std::size_t 是 sizeof 运算符还有 sizeof... 运算符及 alignof 运算符 (C++11 起)的结果的无符号整数类型。

另参阅定宽整数类型。

 (C++11 起)

字符类型

signed char - 有符号字符表示的类型。
unsigned char - 无符号字符表示的类型。亦用于审查对象表示（无修饰内存）。
char - 能在目标系统上最有效地处理的字符表示的类型（拥有与 signed char 或 unsigned char 之一相同的表示和对齐，但始终是独立的类型）。多字节字符串用此类型表示编码单元。对于每个范围 [0, 255] 中的 unsigned char 类型值，将该值转换成 char 再转换回 unsigned char 产生原值。 (C++11 起) char 的符号性取决于编译器和目标平台： ARM 和 PowerPC 的默认设置常为无符号，而 x86 与 x64 的默认设置常为有符号。
wchar_t - 宽字符表示的类型（见宽字符串）。要求大到足以表示任何受支持的字符编码位点（支持 Unicode 的系统上为 32 位。值得注意的例外是 Windows，其中 wchar_t 为 16 位并保有 UTF-16 编码单元）。它与上述整数类型之一具有相同的大小、符号性和对齐，但它是独立的类型。
char16_t - UTF-16 字符表示的类型，要求大到足以表示任何 UTF-16 编码单元（ 16 位）。它与 std::uint_least16_t 具有相同的大小、符号性和对齐，但它是独立的类型。
char32_t - UTF-32 字符表示的类型，要求大到足以表示任何 UTF-32 编码单元（ 32 位）。它与 std::uint_least32_t 具有相同的大小、符号性和对齐，但它是独立的类型。
 (C++11 起)
char8_t - UTF-8 字符表示的类型，要求大到足以表示任何 UTF-8 编码单元（ 8 位）。它与 unsigned char 具有相同的大小、符号性和对齐（从而与 char 和 signed char 具有相同的大小和对齐），但它是独立的类型。
 (C++20 起)

除了最小位数， C++ 标准还保证

1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long) 。

注意：这允许一种极端情况，其中字节有 64 位大小，所有类型（包括 char ）都有 64 位宽，而 sizeof 对每个类型均返回 1。

浮点类型

下列三种类型及其 cv 限定版本统称为浮点类型。

float - 单精度浮点类型。若支持则匹配 IEEE-754 binary32 格式。
double - 双精度浮点类型。若支持则匹配 IEEE-754 binary64 格式。
long double - 扩展精度浮点类型。若支持则匹配 IEEE-754 binary128 格式，否则若支持则匹配 IEEE-754 binary64 扩展格式，否则匹配某种精度优于 binary64 而值域至少和 binary64 一样好的非 IEEE-754 扩展浮点格式，否则匹配 IEEE-754 binary64 格式。
  • 一些 HP-UX、 SPARC、 MIPS、 ARM64 和 z/OS 实现使用 binary128 格式。
  • 最知名的 IEEE-754 binary64 扩展格式是 80 位 x87 扩展精度格式。许多 x86 和 x86-64 实现使用它（一个典型的例外是 MSVC ，它将 long double 实现为与 double 相同的格式，即 binary 64）。

性质

浮点类型可以支持一些特殊值：

  • 无穷（正和负），见 INFINITY
  • 负零，-0.0。它与正零比较相等，但在某些算术运算中有意义，例如 1.0/0.0 == INFINITY ，但 1.0/-0.0 == - INFINITY)，而且对某些数学函数有意义，例如 sqrt(std::complex)
  • 非数 (NaN) ，它与任何值（包括自身）比较都不相等。多个位模式都表示 NaN，见 std::nan、NAN 。注意 C++ 并不对发信 NaN 进行特殊对待，把所有 NaN 均当做静默 NaN，但提供了 std::numeric_limits::has_signaling_NaN 用以检测它们的支持情况。

实浮点数可用于算术运算符 + - / * 和各种来自 <cmath> 的数学函数。内建运算符和库函数都可能引发浮点异常，并按 math_errhandling 中的描述设置 errno。

浮点表达式可拥有大于其类型所指定的值域和精度，见 FLT_EVAL_METHOD。浮点表达式亦可收缩，即在计算时将所有中间值视为拥有无限范围和精度，见 #pragma STDC FP_CONTRACT。

浮点数上的某些运算受浮点环境的状态影响，并可对其进行修改（最值得注意的是舍入方向）。

在实浮点类型和整数类型间定义了隐式转换。

浮点类型的其他细节、界限和性质见浮点类型的界限和 std::numeric_limits。

取值范围

下表提供常用数值表示的界限的参考。

C++20 之前，C++ 标准曾允许任意的有符号整数表示，而 N 位有符号整数的最小保证范围为从 \(\scriptsize -(2^{N-1}-1)\)-(2N-1
-1) 到 \(\scriptsize +2^{N-1}-1\)+2N-1
-1 （例如有符号 8 位类型为 -127 到 127 ），这对应于反码或原码的界限。

然而，所有 C++ 编译器均使用补码表示，而从 C++20 起，这是标准所允许的唯一表示，所保证的范围为从 \(\scriptsize -2^{N-1}\)-2N-1
 到 \(\scriptsize +2^{N-1}-1\)+2N-1
-1 （例如有符号 8 位类型为 -128 到 127 ）。

C++11 起（经由 CWG 1759 ）已不允许 char 的 8 位反码与原码表示，因为用于 UTF-8 字符串字面量的值为 0x80 的 UTF-8 编码单元必须可存储于 char 元素对象。

类型 | 位数 | 格式 | 取值范围
近似 | 精确
字符 | 8 | 有符号 | -128 到 127
无符号 | 0 到 255
16 | UTF-16 | 0 到 65535
32 | UTF-32 | 0 到 1114111 (0x10ffff)
整数 | 16 | 有符号 | ± 3.27 · 104 | -32768 到 32767
无符号 | 0 到 6.55 · 104 | 0 到 65535
32 | 有符号 | ± 2.14 · 109 | -2,147,483,648 到 2,147,483,647
无符号 | 0 到 4.29 · 109 | 0 到 4,294,967,295
64 | 有符号 | ± 9.22 · 1018 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
无符号 | 0 到 1.84 · 1019 | 0 到 18,446,744,073,709,551,615
二进制浮点 32 IEEE-754
  • 最小非正规：
    ± 1.401,298,4 · 10-45
  • 最小正规：
    ± 1.175,494,3 · 10-38
  • 最大：
    ± 3.402,823,4 · 1038
  • 最小非正规：
    ±0x1p-149
  • 最小正规：
    ±0x1p-126
  • 最大：
    ±0x1.fffffep+127
64 IEEE-754
  • 最小非正规：
    ± 4.940,656,458,412 · 10-324
  • 最小正规：
    ± 2.225,073,858,507,201,4 · 10-﻿308
  • 最大：
    ± 1.797,693,134,862,315,7 · 10308
  • 最小非正规：
    ±0x1p-1074
  • 最小正规：
    ±0x1p-1022
  • 最大：
    ±0x1.fffffffffffffp+1023
80[注 1] x86
  • 最小非正规：
    ± 3.645,199,531,882,474,602,528
    · 10-4951
  • 最小正规：
    ± 3.362,103,143,112,093,506,263
    · 10-4932
  • 最大：
    ± 1.189,731,495,357,231,765,021
    · 104932
  • 最小非正规：
    ±0x1p-16446
  • 最小正规：
    ±0x1p-16382
  • 最大：
    ±0x1.fffffffffffffffep+16383
128 IEEE-754
  • 最小非正规：
    ± 6.475,175,119,438,025,110,924,
    438,958,227,646,552,5 · 10-4966
  • 最小正规：
    ± 3.362,103,143,112,093,506,262,
    677,817,321,752,602,6 · 10-4932
  • 最大：
    ± 1.189,731,495,357,231,765,085,
    759,326,628,007,016,2 · 104932
  • 最小非正规：
    ±0x1p-16494
  • 最小正规：
    ±0x1p-16382
  • 最大：
    ±0x1.ffffffffffffffffffffffffffff
    p+16383
  1. ↑ 在 32/64 位平台上对象表示通常占用 96/128 位。

注意：这些类型可表示的值的实际界限（与保证的最小界限相对）可通过 C 数值界限接口及 std::numeric_limits 获知。

关键词

void, bool, true, false, char, wchar_t, char8_t, char16_t, char32_t, int, short, long, signed, unsigned, float, double

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1759 | C++11 | 不保证 char 能表示 UTF-8 编码单元 0x80 | 已保证

参阅

  • C++ 类型系统概览
  • const-volatile (cv) 说明符与限定符
  • 存储期说明符


未定义行为

< cpp‎ | language

若违反某些规则，则令整个程序失去意义。

解释

C++ 标准为不被归入下列分类之一的每个程序都精确定义了其可观察行为：

  • 非良构（ill-formed）——程序拥有语法错误或可诊断的语义错误。遵从标准的 C++ 编译器必须为此给出诊断，即使它定义了为这种代码赋予了含义的语言扩展（例如用非常量长度数组）也应如此。标准文本用 shall（应当）、 shall not（不应当）和 ill-formed（非良构）给出了这些要求。
  • 非良构而不要求诊断（ill-formed, no diagnostic required）——程序拥有通常情况下可能无法诊断的语义错误（例如 ODR 的违规或者其他只能在链接时检测的错误）。若执行这种程序则行为未定义。
  • 由实现定义的行为（implementation-defined behavior）——程序的行为随实现而变动，遵从标准的实现必须为每个这样的行为的效果提供文档。例如 std::size_t 的类型或每个字节的位数，或者 std::bad_alloc::what 的文本。由实现定义的行为的一个子集是本地环境特定行为（locale-specific behavior），它取决于实现所提供的本地环境。
  • 未指明的行为（ unspecified behavior ）——程序的行为随实现而变动，且遵从标准的实现不需要为每个行为的效果提供文档。例如求值顺序，等同的字符串字面量是否为不同的对象，数组分配的开销，等等。每个未指明行为均产生合法结果集合中的一个结果。
  • 未定义行为（undefined behavior，UB）——对程序的行为无任何限制。未定义行为的例子是数组边界外的内存访问，有符号整数溢出，空指针的解引用，在一个表达式中对同一标量多于一次的中间无序列点 (C++11 前)无序 (C++11 起)的修改，通过不同类型的指针访问对象，等等。编译器不需要诊断未定义行为（尽管许多简单情形确实会得到诊断），而且所编译的程序不需要做任何有意义的事。

UB 与优化

因为正确的 C++ 程序不含未定义行为，所以在启用优化选项时编译确实含有 UB 的程序时，编译器可能产生意料之外的结果：

例如，

有符号溢出

int foo(int x) {
    return x+1 > x; // 要么为 true，要么因为有符号溢出导致 UB
}

可能编译为（演示）

foo(int):
        movl    $1, %eax
        ret

边界外访问

int table[4] = {};
bool exists_in_table(int v)
{
    // 可能在头 4 次迭代中返回 true，或者因为边界外访问导致 UB
    for (int i = 0; i <= 4; i++) {
        if (table[i] == v) return true;
    }
    return false;
}

可能编译为（演示）

exists_in_table(int):
        movl    $1, %eax
        ret

未初始化的标量

std::size_t f(int x)
{
    std::size_t a;
    if(x) // x 为零时会有 UB
        a = 42;
    return a;
}

可能编译为（演示）

f(int):
        mov     eax, 42
        ret

以下给出的输出曾在旧版本 gcc 上观察到

bool p; // 未初始化的局部变量
if(p) // UB ：访问未初始化的标量
    std::puts("p is true");
if(!p) // UB ：访问未初始化的标量
    std::puts("p is false");

可能的输出：

p is true
p is false

非法标量

int f() {
  bool b = true;
  unsigned char* p = reinterpret_cast<unsigned char*>(&b);
  *p = 10;
  // 从 b 读取现在是 UB
  return b == 0;
}

可能编译为（演示）

f():
        movl    $11, %eax
        ret

空指针解引用

int foo(int* p) {
    int x = *p;
    if(!p) return x; // 要么如上产生 UB，要么不可能采用此分支
    else return 0;
}
int bar() {
    int* p = nullptr;
    return *p;        // 无条件 UB
}

可能编译为（ foo 用 gcc 、 bar 用 clang ）

foo(int*):
        xorl    %eax, %eax
        ret
bar():
        retq

访问已传递给 realloc 的指针

选择 clang 以观察所示输出

#include <iostream>
#include <cstdlib>
int main() {
    int *p = (int*)std::malloc(sizeof(int));
    int *q = (int*)std::realloc(p, sizeof(int));
    *p = 1; // UB ：访问已传递给 realloc 的指针
    *q = 2;
    if (p == q) // UB ：访问已传递给 realloc 的指针
        std::cout << *p << *q << '\n';
}

可能的输出：

12

无副作用的无限循环

选择 clang 以观察所示输出

#include <iostream>

int fermat() {
  const int MAX = 1000;
  int a=1,b=1,c=1;
  // 无副作用的无限循环是 UB
  while (1) {
    if (((a*a*a) == ((b*b*b)+(c*c*c)))) return 1;
    a++;
    if (a>MAX) { a=1; b++; }
    if (b>MAX) { b=1; c++; }
    if (c>MAX) { c=1;}
  }
  return 0;
}

int main() {
  if (fermat())
    std::cout << "Fermat's Last Theorem has been disproved.\n";
  else
    std::cout << "Fermat's Last Theorem has not been disproved.\n";
}

可能的输出：

Fermat's Last Theorem has been disproved.

外部链接

  • 每个 C 程序员都应该知道的关于未定义行为的事 #1/3
  • 每个 C 程序员都应该知道的关于未定义行为的事 #2/3
  • 每个 C 程序员都应该知道的关于未定义行为的事 #3/3
  • 未定义行为能导致时间旅行（在所有事项中，时间旅行可是最惊人的）
  • 了解 C/C++ 中的整数溢出
  • 未定义行为与费马大定理
  • 空指针的趣事，第一部分 （ Linux 2.6.30 中空指针解引用所致的未定义行为所引发的局部滥用）

参阅


联合体声明

< cpp‎ | language

联合体是特殊的类类型，它在一个时刻只能保有其一个非静态数据成员。

联合体声明的类说明符与类或结构体的声明相似：

union 属性 类头名 { 成员说明 }
属性 | - | (C++11 起) 任意数量属性的可选序列
类头名 | - | 被定义的联合体的名字。可以前附 嵌套名说明符（名字与作用域解析运算符的序列，以作用域解析运算符结尾）。可以忽略名字，此时联合体是无名的
成员说明 | - | 访问说明符、成员对象和成员函数的声明与定义的列表。

联合体可以拥有成员函数（包含构造函数和析构函数），但不能有虚函数。

联合体不能有基类且不能用作基类。

联合体不能拥有引用类型的非静态数据成员。

联合体不能含有带非平凡特殊成员函数（复制构造函数、复制赋值运算符或析构函数）的非静态数据成员。 | (C++11 前)
如果联合体含有带非平凡特殊成员函数（复制/移动构造函数，复制/移动赋值，或析构函数）的非静态数据成员，那么该联合体中的那些函数默认被弃置，且需要程序员显式定义。 如果联合体含有带非平凡默认构造函数的非静态数据成员，那么该联合体的默认构造函数默认被弃置，除非该联合体的变体成员拥有一个默认成员初始化器。 最多只有一个变体成员可以拥有默认成员初始化器。 | (C++11 起)

正如结构体的声明中一般，联合体的默认成员访问是 public。

解释

联合体的大小仅足以保有其最大的数据成员。其他数据成员在该最大成员的一部分相同的字节分配。分配的细节是实现定义的，且读取并非最近写入的联合体成员是未定义行为。许多编译器以非标准语言扩展实现读取联合体的不活跃成员的能力。

#include <iostream>
#include <cstdint>
union S
{
    std::int32_t n;     // 占用 4 字节
    std::uint16_t s[2]; // 占用 4 字节
    std::uint8_t c;     // 占用 1 字节
};                      // 整个联合体占用 4 字节

int main()
{
    S s = {0x12345678}; // 初始化首个成员，s.n 现在是活跃成员
    // 于此点，从 s.s 或 s.c 读取是未定义行为
    std::cout << std::hex << "s.n = " << s.n << '\n';
    s.s[0] = 0x0011; // s.s 现在是活跃成员
    // 在此点，从 n 或 c 读取是 UB 但大多数编译器都对其有定义
    std::cout << "s.c 现在是 " << +s.c << '\n' // 11 或 00，取决于平台
              << "s.n 现在是 " << s.n << '\n'; // 12340011 或 00115678
}

可能的输出：

s.n = 12345678
s.c 现在是 0
s.n 现在是 115678

每个成员的分配都如同它是类的唯一成员一样。

如果联合体的成员是拥有用户定义的构造函数和析构函数的类，那么切换其活跃成员通常需要显式析构函数和布置 new：

#include <iostream>
#include <string>
#include <vector>

union S
{
    std::string str;
    std::vector<int> vec;
    ~S() {} // 需要知道哪个成员活跃，只能在联合体式的类中做到
};          // 整个联合体占有 max(sizeof(string), sizeof(vector<int>)) 的内存

int main()
{
    S s = {"Hello, world"};
    // 在此点，从 s.vec 读取是未定义行为
    std::cout << "s.str = " << s.str << '\n';
    s.str.~basic_string();
    new (&s.vec) std::vector<int>;
    // 现在，s.vec 是联合体的活跃成员
    s.vec.push_back(10);
    std::cout << s.vec.size() << '\n';
    s.vec.~vector();
}

输出：

s.str = Hello, world
1
 (C++11 起)

如果两个联合体成员都是标准布局类型，那么在任何编译器上检验其公共子序列都有良好定义。

成员生存期

联合体成员的生存期从该成员被设为活跃（active）时开始。如果之前已经有另一成员活跃，那么它的生存期终止。

当联合体的活跃成员通过形式为 E1 = E2 的复制表达式（使用内建赋值运算符或平凡的赋值运算符）切换时，对于 E1 中的各个成员访问和数组下标子表达式中出现的，其类型并非拥有非平凡或弃置的默认构造函数的类的每个联合体成员 X，如果 X 的修改在类型别名使用规则下会具有未定义行为，那么在所指名的存储中隐式创建一个 X 类型的对象；不进行初始化，且其生存期的开始按顺序晚于其左右的操作数的值计算，而早于赋值。

union A { int x; int y[4]; };
struct B { A a; };
union C { B b; int k; };
int f() {
  C c;               // 不开始任何联合体成员的生存期
  c.b.a.y[3] = 4;    // OK："c.b.a.y[3]" 指名联合体成员 c.b 与 c.b.a.y;
                     // 这创建对象以保有联合体成员 c.b 和 c.b.a.y
  return c.b.a.y[3]; // OK：c.b.a.y 指代新创建的对象
}

struct X { const int a; int b; };
union Y { X x; int k; };
void g() {
  Y y = { { 1, 2 } }; // OK，y.x 是联合体的活跃成员
  int n = y.x.a;
  y.k = 4;   // OK：结束 y.x 的生存期，y.k 是联合体的活跃成员
  y.x.b = n; // 未定义行为：y.x.b 在其生存期外被修改，
             // "y.x.b" 指名 y.x，但 X 的默认构造函数被弃置，
             // 所以联合体成员 y.x 的生存期不会隐式开始
}

联合体类型的平凡移动构造函数、移动赋值运算符、 (C++11 起)复制构造函数和复制赋值运算符复制对象表示。如果源与目标不是同一对象，那么这些特殊成员函数在复制前开始每个内嵌于目标的并对应内嵌于源的对象（除了既非目标的子对象亦不拥有隐式生存期类型的对象）的生存期。否则，它们不做任何事。在经由平凡特殊成员函数构造或赋值后，两个联合体对象拥有相同的对应活跃成员（如果存在）。

匿名联合体

匿名联合体是不同时定义任何变量（包括联合体类型的对象、引用或指向联合体的指针）的无名的联合体定义。

union { 成员说明 } ;

匿名联合体有更多限制：它们不能有成员函数，不能有静态数据成员，且所有数据成员必须公开。只能声明非静态数据成员，外加static_assert 声明 (C++11 起)。

匿名联合体的成员被注入到它的外围作用域中（而且不得与其中声明的其他名字冲突）。

int main()
{
    union
    {
        int a;
        const char* p;
    };
    a = 1;
    p = "Jennifer";
}

命名空间作用域的匿名联合体必须声明为 static，除非它们在无名命名空间出现。

联合体式的类

联合体式的类（union-like class）是联合体，或是至少拥有一个匿名联合体成员的（非联合）类。联合体式的类拥有一组变体成员（variant member）：

  • 其成员匿名联合体的非静态数据成员；
  • 另外，如果联合体式的类是联合体，则为其并非匿名联合体的非静态数据成员。

联合体式的类可用于实现带标签联合体（tagged union）。

#include <iostream>

// S 拥有一个非静态数据成员（tag），三个枚举项成员（CHAR、INT、DOUBLE），
// 和三个变体成员（c、i、d）
struct S
{
    enum{CHAR, INT, DOUBLE} tag;
    union
    {
        char c;
        int i;
        double d;
    };
};

void print_s(const S& s)
{
    switch(s.tag)
    {
        case S::CHAR: std::cout << s.c << '\n'; break;
        case S::INT: std::cout << s.i << '\n'; break;
        case S::DOUBLE: std::cout << s.d << '\n'; break;
    }
}

int main()
{
    S s = {S::CHAR, 'a'};
    print_s(s);
    s.tag = S::INT;
    s.i = 123;
    print_s(s);
}

输出：

a
123

C++ 标准库包含 std::variant，它可以取代联合体和联合体式的类的大多数用途。上例可重写为

#include <variant>
#include <iostream>

int main()
{
    std::variant<char, int, double> s = 'a';
    std::visit([](auto x){ std::cout << x << '\n';}, s);
    s = 123;
    std::visit([](auto x){ std::cout << x << '\n';}, s);
}

输出：

a
123
 (C++17 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1940 | C++11 | 匿名联合体只允许非静态数据成员 | 也允许 static_assert

参阅


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

< cpp‎ | language

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

语法

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

十进制字面量 用户定义后缀 | (1)
八进制字面量 用户定义后缀 | (2)
十六进制字面量 用户定义后缀 | (3)
二进制字面量 用户定义后缀 | (4)
分数常量 指数部分(可选) 用户定义后缀 | (5)
数字序列 指数部分 用户定义后缀 | (6)
字符字面量 用户定义后缀 | (7)
字符串字面量 用户定义后缀 | (8)
1-4) 用户定义整数字面量，例如 12_km
5-6) 用户定义浮点字面量，例如 0.5_Pa
7) 用户定义字符字面量，例如 'c'_X
8) 用户定义字符串字面量，例如 "abd"_L 或 u"xyz"_M
十进制字面量 | - | 与整数字面量中相同，非零的十进制数位后随零或多个十进制数位
八进制字面量 | - | 与整数字面量中相同，零后随零或多个八进制数位
十六进制字面量 | - | 与整数字面量中相同，0x 或 0X 后随一个或多个十六进制数位
二进制字面量 | - | 与整数字面量中相同，0b 或 0B 后随一或多个二进制数位
数字序列 | - | 与浮点字面量中相同，一个十进制数字序列
分数常量 | - | 与浮点字面量中相同，要么是一个后随小数点的 数字序列（123.），要么是一个可选的 数字序列 后随小数点和另一个 数字序列（1.0 或 .12）
指数部分 | - | 与浮点字面量中相同，字母 e 或字母 E 后随可选的正负号，后随 数字序列
字符字面量 | - | 与字符字面量中相同
字符串字面量 | - | 与字符串字面量中相同，包括原始字符串字面量
用户定义后缀 | - | 标识符，由字面量运算符或字面量运算符模板声明引入（见下文）。所有程序引入的 用户定义后缀 必须以下划线字符 _ 开始。标准库的 用户定义后缀 不以下划线开始。

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

 (C++14 起)

如果一个记号同时匹配用户定义字面量的语法和常规字面量的语法，则它被假定为常规字面量（即不可能重载 123LL 中的 LL）

当编译器遇到一个带有 用户定义后缀 X 的用户定义字面量时，它进行无限定名字查找，寻找名为 operator "" X 的函数。-如果该查找找不到任何声明，则程序非良构。否则，

1) 对于用户定义整数字面量
a) 如果重载集包含带有形参类型 unsigned long long 的字面量运算符，则用户定义字面量表达式被当做函数调用 operator "" X(nULL)，其中 n 是无 用户定义后缀 的该字面量
b) 否则，重载集必须包含以下之一，但不是二者：原始字面量运算符或数值字面量运算符模板。如果重载集包含原始字面量运算符，则用户定义字面量表达式被当做函数调用 operator "" X("n")
c) 否则，如果重载集包含数值字面量运算符模板，则用户定义字面量表达式被当做函数调用 operator "" X<'c1', 'c2', 'c3'..., 'ck'>()，其中 c1..ck 是 n 中的各个字符且它们都来自基础源字符集 (C++23 前)基础字符集 (C++23 起)
2) 对于用户定义浮点字面量，
a) 如果重载集包含带有形参类型 long double 的字面量运算符，则用户定义字面量表达式被当做函数调用 operator "" X(fL)，其中 f 是无 用户定义后缀 的该字面量
b) 否则，重载集必须包含下列之一，但不是二者：原始字面量运算符或数值字面量运算符模板。如果重载集包含原始字面量运算符，则用户定义字面量表达式被当做函数调用 operator "" X("f")
c) 否则，如果重载集包含数值字面量运算符模板，则用户定义字面量表达式被当做函数调用 operator "" X<'c1', 'c2', 'c3'..., 'ck'>()，其中 c1..ck 是 f 中的各个字符且它们都来自基础源字符集 (C++23 前)基础字符集 (C++23 起)。
3) 对于用户定义字符串字面量，令 str 为无 用户定义后缀 的字面量：
a) 如果重载集包含带非类型模板形参的字符串字面量运算符模板，且 str 对它是良构的模板实参，则用户定义字面量表达式被当作函数调用 operator "" X<str>()，
 (C++20 起)
b) 否则，用户定义字面量表达式被当做函数调用 operator "" X (str, len)，其中 len 是字符串字面量的长度，不包含终止空字符
4) 对于用户定义字符字面量，用户定义字面量表达式被当做函数调用 operator "" X (ch)，其中 ch 是无 用户定义后缀 的该字面量。
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 中发生字符串字面量的拼接时，用户定义字符串字面量也被拼接，且其 用户定义后缀 在拼接时被忽略，但所有被拼接的字面量中只可以出现一个后缀：

int main() {
    L"A" "B" "C"_x; // OK：同 L"ABC"_x
    "P"_x "Q" "R"_y;// 错误：两个不同的用户定义后缀（_x 与 _y）
}

字面量运算符

用户定义字面量所调用的函数被称为字面量运算符（如果它是模板，则被称为字面量运算符模板）。它的声明恰如任何其他命名空间作用域的函数或函数模板一样（它可以是友元函数、函数模板的显式实例化或特化，或通过 using 声明引入），但有下列限制：

此函数的名称可拥有两种形式之一：

operator "" 标识符
operator 用户定义字符串字面量
标识符 | - | 作为用户定义字面量所用的 用户定义后缀 的标识符，其将调用此函数。必须以下划线 _ 开始：不以下划线开始的后缀为标准库提供的字面量运算符所保留。
用户定义字符串字面量 | - | 字符序列 "" 后不带空格，后随将作为 用户定义后缀 的字符序列。这种特殊语法使得将语言关键词和保留标识符用作 用户定义后缀 成为可能，并由来自头文件 <complex> 的 operator ""if 的声明所用。注意，使用此形式不改变用户定义字面量必须以下划线开始的规则：类似 operator ""if 的声明只可出现作标准库头文件的一部分。然而，它允许下划线后随大写字母的用法（其他情况下这是保留标识符）。

如果字面量运算符是模板，则它必须有空形参列表，而且只能有一个模板形参，模板形参必须是元素类型为 char 的非类型模板形参包（此时称之为数值字面量运算符模板）

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

或类类型的非类型模板形参（此时称之为字符串字面量运算符模板）

struct A { constexpr A(const char *); };

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) |
1) 拥有此形参列表的字面量运算符是原始字面量运算符，用于整数和浮点用户定义字面量的后备方式（见上文）
2) 拥有这些形参列表的字面量运算符是用户定义整数字面量的首选字面量运算符
3) 拥有这些形参列表的字面量运算符是用于定义浮点字面量的首选字面量运算符
4-8) 拥有这些形参列表的字面量运算符由用户定义的字符字面量所调用
9-13) 拥有这些形参列表的字面量运算符由用户定义的字符串字面量所调用

不允许默认实参。

不允许 C 语言连接。

除了上述限制外，字面量运算符和字面量运算符模板都是普通的函数（和函数模板），它们可声明为 inline 或 constexpr，它们可拥有内部或外部连接，它们可显式调用，可被取地址，等等。

#include <string>
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
double operator ""_Z(const char* args); // OK：能重载字面量运算符

int main() {}

注解

自从引入用户定义字面量之后，使用定宽整数类型格式化宏常量且未在前导字符串字面量后加空格的情况变为非法：std::printf ("%" PRId64 "\n",INT64_MIN ); 必须替换成 std::printf ("%" PRId64 "\n",INT64_MIN );

由于最大吞噬规则，以 p、P、 (C++17 起)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 <cstddef>
#include <algorithm>
#include <iostream>
#include <numbers>
#include <string>

// 用作从度（输入参数）转换为弧度（返回输出）
constexpr long double operator"" _deg_to_rad ( long double deg )
{
    long double radians = deg * std::numbers::pi_v<long double> / 180;
    return radians;
}

// 用作自定义类型
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 << '\n';
}

#if __cpp_nontype_template_args < 201911

std::string operator"" _x2 ( const char* str, std::size_t )
{
    return std::string{str} + str;
}

#else // C++20 字符串字面量运算符模板

template<std::size_t N>
struct DoubleString
{
    char p[N*2-1]{};

    constexpr DoubleString ( char const(&pp)[N] )
    {
        std::ranges::copy(pp, p);
        std::ranges::copy(pp, p + N - 1);
    };
};

template<DoubleString A>
constexpr auto operator"" _x2()
{
    return A.p;
}

#endif // C++20

int main()
{
    double x_rad = 90.0_deg_to_rad;
    std::cout << std::fixed << x_rad << '\n';

    mytype y = 123_mytype;
    std::cout << y.m << '\n';

    0x123ABC_print;
    std::cout << "abc"_x2 << '\n';
}

输出：

1.570796
123
0x123ABC
abcabc

标准库

标准库中定义了下列字面量运算符

定义于内联命名空间 std::literals::complex_literals
operator""ifoperator""ioperator""il (C++14) | 表示纯虚数的 std::complex 字面量 (函数)
定义于内联命名空间 std::literals::chrono_literals
operator""h (C++14) | 表示小时的 std::chrono::duration 字面量 (函数)
operator""min (C++14) | 表示分钟的 std::chrono::duration 字面量 (函数)
operator""s (C++14) | 表示秒的 std::chrono::duration 字面量 (函数)
operator""ms (C++14) | 表示毫秒的 std::chrono::duration 字面量 (函数)
operator""us (C++14) | 表示微秒的 std::chrono::duration 字面量 (函数)
operator""ns (C++14) | 表示纳秒的 std::chrono::duration 字面量 (函数)
operator""y (C++20) | 表示特定年的 std::chrono::year 字面量 (函数)
operator""d (C++20) | 表示月内日期的 std::chrono::day 字面量 (函数)
定义于内联命名空间 std::literals::string_literals
operator""s (C++14) | 转换字符数组字面量为 basic_string (函数)
定义于内联命名空间 std::literals::string_view_literals
operator""sv (C++17) | 创建一个字符数组字面量的字符串视图 (函数)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1473 | C++11 | 字面量运算符声明中曾要求 "" 与 用户定义后缀 间的空格 | 不再强制要求


using 声明

< cpp‎ | language

将别处定义的名字引入到此 using 声明所出现的声明区中。

using typename(可选) 嵌套名说明符 无限定标识 ; | (C++17 前)
using 声明符列表 ; | (C++17 起)
typename | - | 在 using 声明从基类向类模板中引入成员类型时，可能需要用关键词 typename 解决待决名
嵌套名说明符 | - | 名字与作用域解析运算符 :: 的序列，以作用域解析运算符结尾。单个 :: 指代全局命名空间。
无限定标识 | - | 标识表达式
声明符列表 | - | 一个或多个形式为 typename(可选) 嵌套名说明符 无限定标识 的声明符的逗号分隔列表。某些或所有声明符都可以后随省略号 ... 以指示包展开

解释

using 声明可以用于将命名空间成员引入到另一命名空间与块作用域，或将基类成员引入到派生类定义中，或将枚举项引入命名空间、块或类作用域中 (C++20 起)。

包含多于一个 using 声明符的 using 声明等价于一个对应个数的包含单个 using 声明符的 using 声明序列。

 (C++17 起)

在命名空间和块作用域中

using 声明将另一命名空间的成员引入到当前命名空间或块作用域中。

#include <iostream>
#include <string>
using std::string;
int main()
{
    string str = "举例";
    using std::cout;
    cout << str;
}

细节见命名空间。

在类定义中

using 声明可以将基类成员引入到派生类的定义中，例如将基类的受保护成员暴露为派生类的公开成员。此时 嵌套名说明符 必须指名所定义的类的某个基类。如果这个名字是该基类的某个重载的成员函数的名字，那么具有该名字的所有基类成员函数均被引入。如果派生类已包含具有相同名字、形参列表和限定的成员，那么派生类成员隐藏或覆盖从基类引入的成员（不与之冲突）。

#include <iostream>
struct B {
    virtual void f(int) { std::cout << "B::f\n"; }
    void g(char)        { std::cout << "B::g\n"; }
    void h(int)         { std::cout << "B::h\n"; }
 protected:
    int m; // B::m 是受保护的
    typedef int value_type;
};

struct D : B {
    using B::m; // D::m 是公开的
    using B::value_type; // D::value_type 是公开的

    using B::f;
    void f(int) { std::cout << "D::f\n"; } // D::f(int) 覆盖 B::f(int)
    using B::g;
    void g(int) { std::cout << "D::g\n"; } // g(int) 与 g(char) 均作为 D 成员可见
    using B::h;
    void h(int) { std::cout << "D::h\n"; } // D::h(int) 隐藏 B::h(int)
};

int main()
{
    D d;
    B& b = d;

//    b.m = 2; // 错误，B::m 受保护
    d.m = 1; // 受保护的 B::m 可作为公开的 D::m 访问
    b.f(1); // 调用派生类 f()
    d.f(1); // 调用派生类 f()
    d.g(1); // 调用派生类 g(int)
    d.g('a'); // 调用基类 g(char)
    b.h(1); // 调用基类 h()
    d.h(1); // 调用派生类 h()
}

输出：

D::f
D::f
D::g
B::g
B::h
D::h

继承构造函数

如果 using 声明指代了正在定义的类的某个直接基类的构造函数（例如 using Base::Base;），那么在初始化派生类时，该基类的所有构造函数（忽略成员访问）均对重载决议可见。

如果重载决议选择了继承的构造函数，那么如果它被用于构造相应基类的对象时可访问，它也是可访问的：引入它的 using 声明的可访问性被忽略。

如果在初始化这种派生类对象时重载决议选择了继承的构造函数之一，那么用这个继承的构造函数对从之继承该构造函数的 Base 子对象进行初始化，而 Derived 的所有其他基类和成员，都如同以预置的默认构造函数一样进行初始化（如果提供默认成员初始化器则使用，否则进行默认初始化）。整个初始化被视作单个函数调用：继承的构造函数的各形参的初始化，按顺序早于派生类对象的任何基类或成员的初始化。

struct B1 {  B1(int, ...) { } };
struct B2 {  B2(double)   { } };

int get();

struct D1 : B1 {
  using B1::B1;  // 继承 B1(int, ...)
  int x;
  int y = get();
};

void test() {
  D1 d(2, 3, 4); // OK：B1 通过调用 B1(2, 3, 4) 初始化，
                 // 然后 d.x 被默认初始化（不进行初始化），
                 // 然后 d.y 通过调用 get() 初始化
  D1 e;          // 错误：D1 没有默认构造函数
}

struct D2 : B2 {
  using B2::B2; // 继承 B2(double)
  B1 b;
};

D2 f(1.0);       // 错误：B1 没有默认构造函数
struct W { W(int); };
struct X : virtual W {
 using W::W;   // 继承 W(int)
 X() = delete;
};
struct Y : X {
 using X::X;
};
struct Z : Y, virtual W {
  using Y::Y;
};
Z z(0); // OK：Y 的初始化不调用 X 的默认构造函数

如果构造函数从 B 类型的多个基类子对象继承，那么程序非良构，这与多继承的非静态成员函数相似：

struct A { A(int); };
struct B : A { using A::A; };
struct C1 : B { using B::B; };
struct C2 : B { using B::B; };

struct D1 : C1, C2 {
  using C1::C1;
  using C2::C2;
};
D1 d1(0); // 非良构：从不同的 B 基类子对象继承的构造函数

struct V1 : virtual B { using B::B; };
struct V2 : virtual B { using B::B; };

struct D2 : V1, V2 {
  using V1::V1;
  using V2::V2;
};
D2 d2(0); // OK：只有一个 B 子对象。
          // 这初始化虚 B 基类，它初始化 A 基类
          // 然后如同用预置的默认构造函数
          // 初始化 V1 与 V2 基类

与任何其他非静态成员函数的 using 声明相同，如果继承的构造函数的签名与 Derived 的构造函数之一匹配，那么它被 Derived 中找到的版本从查找中隐藏。如果 Base 的继承构造函数恰好有与 Derived 的复制/移动构造函数匹配的签名，那么它不妨碍 Derived 复制/移动构造函数的隐式生成（然后继承的版本被其隐藏，这与 using operator= 类似）。

struct B1 {   B1(int); };
struct B2 {   B2(int); };

struct D2 : B1, B2 {
  using B1::B1;
  using B2::B2;
  D2(int);   // OK：D2::D2(int) 隐藏 B1::B1(int) 和 B2::B2(int)
};
D2 d2(0);    // 调用 D2::D2(int)

在模板化类中，如果 using 声明指代待决名，而 嵌套名说明符 拥有与该 无限定标识 相同的终止名，那么认为它指名构造函数。

template<class T>
struct A : T {
    using T::T; // OK ：继承 T 的构造函数
};

template<class T, class U>
struct B : T, A<U> {
    using A<U>::A; // OK ：继承 A<U> 的构造函数
    using T::A;    // 不继承 T 的构造函数尽管 T 可以是 A<> 的特化
};
 (C++11 起)

引入有作用域枚举项

除了另一命名空间的成员和基类的成员， using 声明也能将枚举的枚举项引入命名空间、块和类作用域。

using 声明也能用于无作用域枚举项。

enum class button { up, down };
struct S {
    using button::up;
    button b = up; // OK
};

using button::down;
constexpr button non_up = down; // OK

constexpr auto get_button(bool is_up)
{
    using button::up, button::down;
    return is_up ? up : down; // OK
}

enum unscoped { val };
using unscoped::val; // OK ，尽管不需要
 (C++20 起)

注解

只有在 using 声明中明确提及的名字才被传送到声明区中：特别是，using 声明枚举类型名时，并不传送其枚举项。

using 声明不能指代命名空间，有作用域枚举项 (C++20 前)，基类的析构函数，或用户定义转换函数的成员模板的特化。

using 声明不能指名成员模板的特化（语法不容许模板标识）：

struct B { template<class T> void f(); };
struct D : B {
      using B::f;      // OK：指名模板
//    using B::f<int>; // 错误：指名模板特化
      void g() { f<int>(); }
};

using 声明也不能引入待决的成员模板的名字作为模板名（不容许待决名的 template 消歧义符）：

template<class X> struct B { template<class T> void f(T); };
template<class Y> struct D : B<Y> {
//  using B<Y>::template f; // 错误：不允许消歧义符
  using B<Y>::f;            // 能编译，但 f 不是模板名
  void g() {
//    f<int>(0);            // 错误：已知 f 不是目标名，
                            // 因此 < 不开始模板实参列表
      f(0);                 // OK
  }
};

如果 using 声明引入基类的赋值运算符到派生类，而其签名恰好与派生类的复制赋值或移动赋值运算符匹配，那么该运算符被派生类的隐式声明的复制/移动赋值运算符隐藏。相同的规则适用于继承恰好与派生类的移动/复制构造函数匹配的基类构造函数的 using 声明。 (C++11 起)

一项针对 C++11 的缺陷报告追溯地更改了继承构造函数的语义。以前，继承构造函数的声明导致将一组合成的构造函数声明注入到派生类中，这导致冗余的实参复制/移动，并与某些形式的 SFINAE 的交互有问题，而且某些情况下在主流 ABI 上无法实现。旧编译器可能仍然实现先前的语义。

旧的继承构造函数语义

如果 using 声明指代被定义类的某个直接基类的构造函数（例如 using Base::Base;），那么按照下列规则继承该基类的构造函数：

1) 继承构造函数候选的集合由以下组成：
a) 基类的所有非模板构造函数（在忽略省略号形参后，若它存在） (C++14 起)
b) 对于每个有默认实参或省略号形参的构造函数，所有构造函数签名通过丢弃省略号及逐个忽略来自形参列表尾的默认实参组成
c) 基类的所有构造函数模板（在忽略省略号形参数后，若它存在） (C++14 起)
d) 对于每个有默认实参或省略号形参的构造函数模板，所有构造函数签名通过丢弃省略号者及逐个忽略来自形参列表尾的默认实参组成
2) 所有并非默认构造函数或复制/移动构造函数，且其签名不与派生类中的用户定义的构造函数相匹配的继承构造函数候选，在派生类中隐式声明。不继承默认实参：
struct B1 {
    B1(int);
};
struct D1 : B1 {
    using B1::B1;
// 继承构造函数候选集是
// 1. B1(const B1&)
// 2. B1(B1&&)
// 3. B1(int)

// D1 有下列构造函数：
// 1. D1() = delete
// 2. D1(const D1&)
// 3. D1(D1&&)
// 4. D1(int) <- 继承的
};

struct B2 {
    B2(int = 13, int = 42);
};
struct D2 : B2 {
    using B2::B2;
// 继承构造函数候选集是
// 1. B2(const B2&)
// 2. B2(B2&&)
// 3. B2(int = 13, int = 42)
// 4. B2(int = 13)
// 5. B2()

// D2 有下列构造函数：
// 1. D2()
// 2. D2(const D2&)
// 3. D2(D2&&)
// 4. D2(int, int) <- 继承的
// 5. D2(int) <- 继承的
};

继承的构造函数等价于有空函数体和由单个 嵌套名说明符 组成的成员初始化器列表的用户定义构造函数，它将其所有实参转发给基类构造函数。

它与对应的基类构造函数有同样的访问。如果用户定义构造函数可满足 constexpr 构造函数的要求，那么它也是 constexpr 的。如果基类构造函数被弃置，或若预置的默认构造会被弃置，那么它也会被弃置（但不计构造函数要被继承的基类的构造）。继承的构造函数不能被显式实例化或显式特化。

如果两条 using 声明（分别从两个直接基类）继承了有相同签名的构造函数，那么程序非良构。
(C++11 起)

在 using 声明中使用包展开可以替代递归来组成暴露变长基类的重载成员的类：

template <typename... Ts>
struct Overloader : Ts... {
    using Ts::operator()...; // 从每个基类暴露 operator()
};

template <typename... T>
Overloader(T...) -> Overloader<T...>; // C++17 推导指引，C++20 起不再需要

int main() {
    auto o = Overloader{ [] (auto const& a) {std::cout << a;},
                         [] (float f) {std::cout << std::setprecision(3) << f;} };
}
 (C++17 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0136R1 | C++11 | 继承构造函数声明会将额外的构造函数注入派生类 | 导致名字查找能找到基类构造函数


值初始化(C++03 起)

< cpp‎ | language

这是在以空初始化器构造对象时进行的初始化。

语法

T() | (1) |
new T () | (2) |
类::类(...) : 成员() { ... } | (3) |
T 对象 {}; | (4) | (C++11 起)
T{} | (5) | (C++11 起)
new T {} | (6) | (C++11 起)
类::类(...) : 成员{} { ... } | (7) | (C++11 起)

解释

以下场合进行值初始化：

1,5) 当以空的括号或花括号 (C++11 起)对组成的初始化器创建无名临时对象时；
2,6) 当 new 表达式以空的括号或花括号 (C++11 起)对组成的初始化器创建具有动态存储期的对象时；
3,7) 当使用以空的括号或花括号 (C++11 起)对组成的成员初始化器初始化非静态数据成员或基类时；
4) 当以由空花括号对组成的初始化器声明具名对象（自动、静态或线程局部）时。
 (C++11 起)

所有情况下，如果使用空花括号对 {} 且 T 是聚合类型，则进行聚合初始化而非值初始化。

如果 T 是没有默认构造函数但带有接受 std::initializer_list 的构造函数的类类型，则进行列表初始化。

 (C++11 起)

值初始化的效果是：

1) 如果 T 是拥有至少一个用户提供的任意种类的构造函数的类类型，则调用默认构造函数； 2) 如果 T 是没有任何用户提供的构造函数的非联合体类类型，则值初始化 T 的每个非静态数据成员与基类组分； | (C++11 前)
1) 如果 T 是没有默认构造函数，或拥有用户提供的或被删除的默认构造函数的类类型，则对象被默认初始化； 2) 如果 T 是拥有默认构造函数的类类型，而默认构造函数既没有被用户提供也没有被删除（即它可以是拥有隐式定义的或默认化的默认构造函数的类），则零初始化对象，然后如果它拥有非平凡的默认构造函数，则默认初始化它； 然而在重载决议选择未被删除的默认化的默认构造函数时，所有已知编译器都进入情况 (2)，即使有用户提供的默认构造函数，见注解； | (C++11 起)
3) 如果 T 是数组类型，则值初始化数组的每个元素；
4) 否则，零初始化对象。

注解

如果构造函数是用户声明的，且未在其首个声明上显式默认化，则它是用户提供的。

语法 T object(); 不初始化对象；它声明一个不接受参数并返回 T 的函数。在 C++11 前值初始化一个具名变量的方式是 T object = T();，它值初始化一个临时量然后复制初始化该对象：多数编译器在此情况下能优化掉复制。

在 C++03（引入了值初始化）之前的 C++98 中，表达式 new T() 被归类为默认初始化并指定进行零初始化。

引用不能被值初始化。

如函数式转型中所述，数组禁止语法 T() (1) ，但允许 T{} (5)。

所有标准容器（std::vector、std::list 等）在以单个 size_type 实参进行构造或由对 resize() 的调用而增长时值初始化其各个元素，除非其分配器定制 construct 的行为。

从 C++11 起，对没有用户提供的构造函数而拥有类类型成员的类进行值初始化，其中成员的类拥有用户提供的构造函数，会在调用成员的构造函数前对成员清零：

struct A
{
    int i;
    A() { } // 用户提供的默认构造函数，不初始化 i
};

struct B { A a; }; // 隐式定义的默认构造函数

std::cout << B().a.i << '\n'; // 值初始化 B 临时量
                              // C++03 中令 b.a.i 为未初始化
                              // C++11 中设 b.a.i 为零
// （注意 C++11 中 B{}.a.i 保留 b.a.i 为未初始化，但因为不同原因：
// 在 DR1301 后的 C++11 中，B{} 是聚合初始化，它值初始化拥有用户提供构造函数的 A）

标准指定在类拥有用户提供的或被删除的默认构造函数时不进行零初始化，即使重载决议不选择该默认构造函数。所有已知编译器都在选择未被删除的默认化的默认构造函数时进行额外的零初始化。

struct A {
    A() = default;
    template<class = void>
    A(int = 0) {} // A 拥有用户提供的默认构造函数，它没有被选择
    int x;
};

constexpr int test(A a) {
    return a.x; // 如果 a 的值不确定则行为未定义
}

constexpr int zero = test(A());
// 谬构：按照标准不会零初始化形参，这导致未定义行为，并在要求常量求值的语境中使程序谬构。
// 然而所有已知编译器都接受这种代码。

void f() {
    A a = A(); // 按照标准不被零初始化
               // 但实现还是会生成零初始化的代码
}

示例

#include <string>
#include <vector>
#include <iostream>

struct T1
{
    int mem1;
    std::string mem2;
}; // 隐式默认构造函数

struct T2
{
    int mem1;
    std::string mem2;
    T2(const T2&) { } // 用户提供的复制构造函数
};                    // 无默认构造函数

struct T3
{
    int mem1;
    std::string mem2;
    T3() { } // 用户提供的默认构造函数
};

std::string s{}; // 类 => 默认初始化，值为 ""

int main()
{
    int n{};                // 标量 => 零初始化，值为 0
    double f = double();    // 标量 => 零初始化，值为 0.0
    int* a = new int[10](); // 数组 => 每个元素的值初始化
                            //          每个元素的值为 0
    T1 t1{};                // 有隐式默认构造函数的类 =>
                            //     t1.mem1 被零初始化，值为 0
                            //     t1.mem2 被默认初始化，值为 ""
//  T2 t2{};                // 错误：类无默认构造函数
    T3 t3{};                // 有用户提供默认构造函数的类 =>
                            //     t3.mem1 被默认初始化为不确定值
                            //     t3.mem2 被默认初始化，值为 ""
    std::vector<int> v(3);  // 值初始化每个元素
                            // 每个元素的值为 0
    std::cout << s.size() << ' ' << n << ' ' << f << ' ' << a[9] << ' ' << v[2] << '\n';
    std::cout << t1.mem1 << ' ' << t3.mem1 << '\n';
    delete[] a;
}

可能的输出：

0 0 0 0 0
0 4199376

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1301 | C++11 | 默认化的默认构造函数跳过构造前的零初始化 | 进行零初始化

参阅

  • 默认构造函数
  • explicit
  • 聚合初始化
  • 列表初始化


变量模板(C++14 起)

< cpp‎ | language

变量模板定义一族变量或静态数据成员。

语法

template < 形参列表 > 变量声明

解释

变量声明 | - | 变量的声明。声明的变量名成为模板名。
形参列表 | - | 非空的模板形参的逗号分隔列表，每项是非类型形参、类型形参、模板形参，或任何上述的形参包之一。

变量模板可以通过处于命名空间作用域中的模板声明引入，其中 声明 声明一个变量。

template<class T>
constexpr T pi = T(3.1415926535897932385L);  // 变量模板

template<class T>
T circular_area(T r) // 函数模板
{
    return pi<T> * r * r; // pi<T> 是变量模板实例化
}

在类作用域中使用时，变量模板声明一个静态数据成员模板。

using namespace std::literals;
struct matrix_constants
{
    template<class T>
    using pauli = hermitian_matrix<T, 2>; // 别名模版

    template<class T> // 静态数据成员模板
    static constexpr pauli<T> sigmaX = { { 0, 1 }, { 1, 0 } };

    template<class T>
    static constexpr pauli<T> sigmaY = { { 0, -1i }, { 1i, 0 } };

    template<class T>
    static constexpr pauli<T> sigmaZ = { { 1, 0 }, { 0, -1 } };
};

与其他静态成员一样，静态数据成员模板的需要一个定义。这种定义可以在类定义外提供。处于命名空间作用域的静态数据成员的模板声明也可以是类模板的非模板数据成员的定义：

struct limits {
    template<typename T>
    static const T min; // 静态数据成员模板的声明
};
template<typename T>
const T limits::min = { }; // 静态数据成员模板的定义

template<class T>
class X {
   static T s; // 类模板的非模板静态数据成员的声明
};
template<class T>
T X<T>::s = 0; // 类模板的非模板静态数据成员的定义

除非变量模板被显式特化或显式实例化，否则在变量模板的特化在要求变量定义存在的语境中被引用，或定义存在与否影响程序语义时，即表达式（可能不使用定义）对常量求值需要该变量时，隐式实例化它。

如果有表达式需要某变量进行常量求值，那么变量定义存在与否会影响程序语义，即使不要求常量求值表达式，或常量表达式求值不使用该定义。

注解

在 C++14 引入变量模板前，参数化变量通常实现为类模板的静态数据成员，或返回所需值的 constexpr 函数模板。

变量模板不能用作模板模板实参。


变长实参

< cpp‎ | language

允许函数接受任意数量的额外实参。

由跟在函数声明的 形参列表 之后的（并非引入包展开的） (C++11 起)尾随 ... 指定。

形参列表 非空时，指示变参函数的 ... 之前可以出现逗号。这是为了兼容 C（从 C++ 采纳函数原型时，C 向其添加了逗号的要求）。

// 函数声明如下
int printx(const char* fmt, ...);
// 能以一个或多个实参调用：
printx("hello world");
printx("a=%d b=%d", a, b);

int printx(const char* fmt...); // 同上（为兼容 C 而允许额外的逗号）
int printy(..., const char* fmt); // 错误：... 不能作为形参出现
int printz(...); // 合法，但无法可移植地访问参数

注意：这与函数形参包展开不同，形参包展开是由作为形参声明符一部分的省略号指定的，而非由出现在所有形参声明之后的省略号。形参包展开和“变参”省略号都能出现在函数模板声明中，如 std::is_function 的情况。

 (C++11 起)

默认转换

调用变参函数时，进行左值到右值、数组到指针及函数到指针的转换后，可变实参列表中的每个实参都要经过称为默认实参提升的额外转换：

  • 转换 std::nullptr_t 到 void*
 (C++11 起)
  • 转换 float 到 double，如同浮点提升
  • 转换 bool、char、short 及无作用域枚举到 int 或更宽的整数类型，如同整型提升

只能有算术、枚举、指针、成员指针及类类型的（转换后的）额外实参。然而，非 POD 类类型 (C++11 前)拥有合格的非平凡复制构造函数、合格的非平凡移动构造函数或非平凡析构函数的类类型，以及有作用域枚举类型 (C++11 起)在潜在求值的调用中是以实现定义的语义条件性支持的（这些类型在不求值调用中始终支持）。

因为变长形参对于重载决议而言具有最低的优先级，所以它们常被用作 SFINAE 中的万应后备（catch-all fallback）。

在使用变长实参的函数体内，可以用一些 <cstdarg> 库设施访问这些实参的值：

定义于头文件 <cstdarg>
va_start | 启用对可变函数实参的访问 (宏函数)
va_arg | 访问下一个可变函数实参 (宏函数)
va_copy (C++11) | 制造可变函数实参的副本 (宏函数)
va_end | 结束对可变函数实参的遍历 (宏函数)
va_list | 保有 va_start、va_arg、va_end 和 va_copy 所需的信息 (typedef)

如果省略号前的最后一个形参具有引用类型，或其类型与默认实参提升所产生的各种类型不兼容，那么 va_start 宏的行为未定义。

如果在 va_start 中以包展开或源自 lambda 捕获的实体为最后的形参，那么程序非良构，不要求诊断。

 (C++11 起)

替代方案

  • 变参模板也可以用来创建接受可变数量实参的函数。它们通常是更好的选择，因为它们对实参类型不施加任何制约，不进行整型和浮点提升，且类型安全。
  • 当所有变长实参均为相同类型时，std::initializer_list 提供了一种访问变长实参的便利机制。不过这种情况下不能修改各个实参，因为 std::initializer_list 仅提供指向其各元素的 const 指针。
 (C++11 起)

注解

因为在 C 编程语言中，省略号前必须至少出现一个具名形参，所以 printz(...); 非法。C++ 中允许这种形式，尽管无法访问传递给这种函数的实参，此形式常用作 SFINAE 的后备重载，它利用了重载决议中省略号转换的最低优先级。

变长实参的语法在 1983 年引入 C++，省略号前没有逗号。C89 从 C++ 接受函数原型时，它以要求逗号的语法替换了该语法。为了兼容，C++98 一并接受 C++ 风格 f(int n...) 和 C 风格 f(int n, ...)。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 506 | C++98 | 传递非 POD 类实参给省略号导致未定义行为 | 使之为条件性支持
CWG 634 | C++98 | 条件性支持的类类型使某些 SFINAE 手法无法起效 | 如果不求值则始终支持
CWG 2247 | C++11 | 不限制传递形参包或 lambda 捕获给 va_start | 改为非良构，不要求诊断
CWG 2347 | C++11 | 不明确如何传递有作用域枚举给省略号 | 改为条件性支持

参阅


virtual 函数说明符

< cpp‎ | language

virtual 说明符指定非静态成员函数为虚函数并支持动态调用派发。它只能在非静态成员函数的首个声明（即当它在类定义中声明时）的 声明说明符序列 中出现。

解释

虚函数是其行为可以在派生类中覆盖的成员函数。与非虚函数相反，即使没有关于该类实际类型的编译时信息，进行覆盖的行为仍然保留。当使用到基类的指针或引用来处理派生类时，对被覆盖的虚函数的调用，将会调用定义于派生类中的行为。这种函数调用被称为虚函数调用或虚调用。虚函数调用在使用有限定名字查找（即函数名出现在作用域解析运算符 :: 的右侧）时被抑制。

#include <iostream>
struct Base {
   virtual void f() {
       std::cout << "基\n";
   }
};
struct Derived : Base {
    void f() override { // 'override' 可选
        std::cout << "派生\n";
    }
};
int main()
{
    Base b;
    Derived d;

    // 通过引用调用虚函数
    Base& br = b; // br 的类型是 Base&
    Base& dr = d; // dr 的类型也是 Base&
    br.f(); // 打印 "基"
    dr.f(); // 打印 "派生"

    // 通过指针调用虚函数
    Base* bp = &b; // bp 的类型是 Base*
    Base* dp = &d; // dp 的类型也是 Base*
    bp->f(); // 打印 "基"
    dp->f(); // 打印 "派生"

    // 非虚函数调用
    br.Base::f(); // 打印 "基"
    dr.Base::f(); // 打印 "基"
}

细节

如果某个成员函数 vf 在类 Base 中被声明为 virtual，且某个直接或间接派生于 Base 的类 Derived 拥有一个下列几项与之相同的成员函数声明：

  • 名字
  • 形参列表（但非返回类型）
  • cv 限定符
  • 引用限定符

那么 vf 在类 Derived 中也是虚函数（无论其声明中是否使用关键词 virtual）并覆盖 Base::vf（无论其声明中是否使用单词 override）。

要覆盖的 Base::vf 不需要可访问或可见。（Base::vf 能声明为私有或者私有继承 Base。 Derived 的基类中的任何同名成员不妨碍覆盖确定，即使在名字查找时它们会隐藏 Base::vf。）

class B {
    virtual void do_f(); // 私有成员
 public:
    void f() { do_f(); } // 公开接口
};
struct D : public B {
    void do_f() override; // 覆盖 B::do_f
};

int main()
{
    D d;
    B* bp = &d;
    bp->f(); // 内部调用 D::do_f();
}

每个虚函数都有最终覆盖函数，它是进行虚函数调用时所执行的函数。基类 Base 的虚成员函数 vf 是最终覆盖函数，除非派生类声明或（通过多重继承）继承了覆盖 vf 的另一个函数。

struct A { virtual void f(); };     // A::f 是虚函数
struct B : A { void f(); };         // B 中的 B::f 覆盖 A::f
struct C : virtual B { void f(); }; // C 中的 C::f 覆盖 A::f
struct D : virtual B {}; // D 不引入覆盖函数，最终覆盖函数是 B::f
struct E : C, D  {       // E 不引入覆盖函数，最终覆盖函数是 C::f
    using A::f; // 非函数声明，只为了能让 A::f 被查找到
};
int main() {
   E e;
   e.f();    // 虚调用 e 中的最终覆盖函数 C::f
   e.E::f(); // 非虚调用调用在 E 中可见的 A::f
}

如果一个函数拥有多于一个最终覆盖函数，那么程序非良构：

struct A {
    virtual void f();
};
struct VB1 : virtual A {
    void f(); // 覆盖 A::f
};
struct VB2 : virtual A {
    void f(); // 覆盖 A::f
};
// struct Error : VB1, VB2 {
//     // 错误：A::f 在 Error 中拥有两个最终覆盖函数
// };
struct Okay : VB1, VB2 {
    void f(); // OK：这是 A::f 的最终覆盖函数
};
struct VB1a : virtual A {}; // 不声明覆盖函数
struct Da : VB1a, VB2 {
    // 在 Da 中，A::f 的最终覆盖函数是 VB2::f
};

名字相同但形参列表不同的函数并不覆盖同名的基类函数，但会隐藏它：在无限定名字查找检查派生类的作用域时，查找找到该声明就不会再检查基类。

struct B {
    virtual void f();
};
struct D : B {
    void f(int); // D::f 隐藏 B::f（错误的形参列表）
};
struct D2 : D {
    void f(); // D2::f 覆盖 B::f（不管它是否可见）
};

int main()
{
    B b;   B& b_as_b   = b;
    D d;   B& d_as_b   = d;    D& d_as_d = d;
    D2 d2; B& d2_as_b  = d2;   D& d2_as_d = d2;

    b_as_b.f(); // 调用 B::f()
    d_as_b.f(); // 调用 B::f()
    d2_as_b.f(); // 调用 D2::f()

    d_as_d.f(); // 错误：D 中的查找只找到 f(int)
    d2_as_d.f(); // 错误：D 中的查找只找到 f(int)
}

如果函数以说明符 override 声明，但不覆盖任何虚函数，那么程序非良构：

struct B {
    virtual void f(int);
};
struct D : B {
    virtual void f(int) override; // OK，D::f(int) 覆盖 B::f(int)
    virtual void f(long) override; // 错误：f(long) 不覆盖 B::f(int)
};

如果函数以说明符 final 声明，而被另一函数试图覆盖，那么程序非良构：

struct B {
    virtual void f() const final;
};
struct D : B {
    void f() const; // 错误：D::f 试图覆盖 final B::f
};
 (C++11 起)

非成员函数和静态成员函数不能是虚函数。

函数模板不能被声明为 virtual。这只适用于自身是模板的函数——类模板的常规成员函数可以被声明为虚函数。

虚函数（无论是声明为 virtual 者还是覆盖函数）不能有任何关联制约。

struct A {
    virtual void f() requires true; // 错误：受制约的虚函数
};

consteval 虚函数不能覆盖非 consteval 虚函数或被它覆盖。

 (C++20 起)

在编译时替换虚函数的默认实参。

协变返回类型

如果函数 Derived::f 覆盖 Base::f，那么它的返回类型必须要么相同，要么为协变（covariant）。当满足以下所有要求时，两个类型为协变：

  • 两个类型都是到类的指针或引用（左值或右值）。不允许多级指针或引用。
  • Base::f() 的返回类型中被引用/指向的类，必须是 Derived::f() 的返回类型中被引用/指向的类的无歧义且可访问的直接或间接基类。
  • Derived::f() 的返回类型必须有相对于 Base::f() 的返回类型的相等或较少的 cv 限定。

Derived::f 的返回类型中的类必须要么是 Derived 自身，要么必须是在 Derived::f 声明点的某个完整类型。

进行虚函数调用时，最终覆盖函数的返回类型被隐式转换成所调用的被覆盖函数的返回类型：

class B {};

struct Base {
    virtual void vf1();
    virtual void vf2();
    virtual void vf3();
    virtual B* vf4();
    virtual B* vf5();
};

class D : private B {
    friend struct Derived; // 在 Derived 中，B 是 D 的可访问基类
};

class A; // 前置声明的类是不完整类型

struct Derived : public Base {
    void vf1();    // 虚函数，覆盖 Base::vf1()
    void vf2(int); // 非虚函数，隐藏 Base::vf2()
//  char vf3();    // 错误：覆盖 Base::vf3，但具有不同且非协变的返回类型
    D* vf4();      // 覆盖 Base::vf4() 并具有协变的返回类型
//  A* vf5();      // 错误：A 是不完整类型
};

int main()
{
    Derived d;
    Base& br = d;
    Derived& dr = d;

    br.vf1(); // 调用 Derived::vf1()
    br.vf2(); // 调用 Base::vf2()
//  dr.vf2(); // 错误：vf2(int) 隐藏 vf2()

    B* p = br.vf4(); // 调用 Derived::vf4() 并将结果转换为 B*
    D* q = dr.vf4(); // 调用 Derived::vf4() 而不将结果转换为 B*

}

虚析构函数

虽然析构函数不会继承，但是如果基类将其析构函数声明为 virtual，那么派生的析构函数始终覆盖它。这样就可以通过指向基类的指针 delete 动态分配的多态类型对象。

class Base {
 public:
    virtual ~Base() { /* 释放 Base 的资源 */ }
};

class Derived : public Base {
    ~Derived() { /* 释放 Derived 的资源 */ }
};

int main()
{
    Base* b = new Derived;
    delete b; // 进行对 Base::~Base() 的虚函数调用
              // 由于它是虚函数，因此它调用的是 Derived::~Derived()，
              // 这就能释放派生类的资源，然后遵循通常的析构顺序
              // 调用 Base::~Base()
}

此外，如果基类的析构函数非虚，则通过指向该基类的指针删除派生类对象是未定义行为，无论不调用派生的析构函数时是否会导致资源泄漏，除非选择的解分配函数是销毁的 operator delete (C++20 起)。

一条有用的方针是，凡是当涉及 delete 表达式，例如在 std::unique_ptr 中隐式使用 (C++11 起)时，任何基类的析构函数必须为公开且虚，或受保护且非虚。

在构造和析构期间

当从构造函数或从析构函数中直接或间接调用虚函数（包括在类的非静态数据成员的构造或析构期间，例如在成员初始化器列表中），且对其实施调用的对象是正在构造或析构中的对象时，所调用的函数是构造函数或析构函数的类中的最终覆盖函数，而非进一步的派生类中的覆盖函数。 换言之，在构造和析构期间，进一步的派生类并不存在。

当构建具有多个分支的复杂类时，在属于一个分支的构造函数内，多态被限制到该类及其基类：如果它获得了指向这个子层级之外的某个基类子对象的指针或引用并试图进行虚函数调用（例如通过显式成员访问），那么行为未定义：

struct V {
    virtual void f();
    virtual void g();
};

struct A : virtual V {
    virtual void f(); // 在 A 中，V::f 的最终覆盖函数是 A::f
};
struct B : virtual V {
    virtual void g(); // 在 B 中，V::g 的最终覆盖函数是 B::g
    B(V*, A*);
};
struct D : A, B {
    virtual void f(); // 在 D 中，V::f 的最终覆盖函数是 D::f
    virtual void g(); // 在 D 中，V::g 的最终覆盖函数是 D::g

    // 注意：A 在 B 之前初始化
    D() : B((A*)this, this)
    {
    }
};

// B 的构造函数，从 D 的构造函数调用
B::B(V* v, A* a)
{
    f(); // 对 V::f 的虚调用（尽管 D 拥有最终覆盖函数，D 也不存在）
    g(); // 对 B::g 的虚调用，在 B 中是最终覆盖函数

    v->g(); // v 的类型 V 是 B 的基类，虚调用像之前一样调用 B::g

    a->f(); // a 的类型 A 不是 B 的基类，它属于层级中的不同分支。
            // 尝试通过这个分支进行虚调用导致未定义行为，
            // 即使此时 A 已完成构造
            // （它在 B 之前构造，因为它在 D 的基类列表中在 B 前面出现）
            // 实践中，对 A::f 的虚调用会试图使用 B 的虚成员函数表，
            // 因为它在 B 的构造期间是活跃的
}

参阅

派生类与继承模式
override 说明符 (C++11) | 显式说明方法覆盖另一方法
final 说明符 (C++11) | 声明不能被覆盖的方法


while 循环

< cpp‎ | language

重复执行 语句，直到 条件 的值变成 false。每次重复之前都进行检测。

语法

属性(可选) while ( 条件 ) 语句
属性 | - | (C++11 起) 任意数量的属性
条件 | - | 能按语境转换为 bool 的任意表达式，或带花括号或等号初始化器的单个变量的声明。每次重复之前求值此表达式，且在它产出 false 时退出循环。如果条件同时是声明，那么每次重复之前求值其初始化器，且在被声明变量的值转换为 false 时退出循环。
语句 | - | 任意语句，典型地为复合语句，它是循环体。

解释

无论 语句 是否为复合语句，它始终都会引入一个块作用域。换言之在其中声明的变量仅在循环体内可见。

while (--x >= 0)
    int i;
// i 离开作用域

与下面的相同

while (--x >= 0) {
    int i;
} // i 离开作用域

如果 条件 是像 T t = x 这样的声明，那么被声明的变量仅在循环体内处于作用域中，而且在每次重复中销毁并重新创建，换言之，这种 while 循环等价于：

label:
{ // 循环作用域的开始
    T t = x;
    if (t) {
        语句
        goto label; // 调用 t 的析构函数
    }
}

如果循环的执行必须在某点终止，那么可以使用 break 语句作为终止语句。

如果循环需要在循环体结尾继续，那么可以使用 continue 语句作为快捷方式。

注解

作为 C++ 向前进展保证的一部分，如果没有可观察行为（不调用 I/O 函数，访问 volatile 对象，或进行原子或同步操作）的循环不会终止，那么它的行为未定义。编译器可以移除这种循环。

关键词

while

示例

#include <iostream>

int main() {
    // 带单语句的 while 循环
    int i = 0;
    while (i < 10)
         i++;
    std::cout << i << '\n';

    // 带复合语句的 while 循环
    int j = 2;
    while (j < 9) {
        std::cout << j << ' ';
        j += 2;
    }
    std::cout << '\n';

   // 带声明条件的 while 循环
   char cstr[] = "Hello";
   int k = 0;
   while (char c = cstr[k++])
       std::cout << c;
   std::cout << '\n';
}

输出：

10
2 4 6 8
Hello

参阅


零初始化

< cpp‎ | language

将一个对象的初始值设为零。

语法

注意零初始化在语言中没有专用语法，因此下列语法不是零初始化语法。这些是可能会进行零初始化的其他初始化的例子。

static T 对象 ; | (1)
T () ;

T t = {} ;
T {} ;

 (2)

(C++11 起)
CharT 数组 [ n ] = ""; | (3)

解释

在下列情形进行零初始化：

1) 在所有其他初始化前，对每个具有静态或线程局部 (C++11 起) 存储期的，不进行常量初始化的具名变量。
2) 作为非类类型变量，和被值初始化的无构造函数的类类型的成员的值初始化序列的一部分，包括未提供初始化器的聚合体元素的值初始化。
3) 以不够长的字符串字面量初始化任何字符类型数组时，零初始化数组的剩余部分。

零初始化的效果是：

  • 如果 T 是标量类型，那么对象初值是显式转换到 T 的整型常量零。
  • 如果 T 是非联合体类类型，那么零初始化它的所有基类和非静态数据成员，并初始化所有填充位为零位。忽略可能存在的构造函数。
  • 如果 T 是联合体类型，那么零初始化首个非静态的具名数据成员，并零初始化所有填充位为零位。
  • 如果 T 是数组类型，那么零初始化每个元素。
  • 如果 T 是引用类型，那么不做任何事。

注解

如非局部初始化中所述，在进行任何其他初始化前，零初始化所有未被常量初始化的静态和线程局部 (C++11 起)变量。如果非类类型非局部变量的定义没有初始化器，那么默认初始化不做任何事，不修改先前零初始化的结果。

零初始化的指针是其类型的空指针值，即使空指针的值并非整型的零。

示例

#include <string>
#include <iostream>

struct A {
    int a,b,c;
};

double f[3]; // 零初始化为三个 0.0
int* p;   // 零初始化为空指针值（即使该值可能不是整型 0）
std::string s; // 零初始化为不确定值
               // 再通过 std::string 的默认构造函数默认初始化为 ""
int main(int argc, char* argv[])
{
    delete p; // 可以安全删除空指针
    static int n = argc; // 零初始化为 0
                         // 然后复制初始化为 argc
    std::cout << "n = " << n << '\n';
    A a = A(); // 效果等同于 A a{}; 或 A a = {};
    std::cout << "a = {" << a.a << ' ' << a.b << ' ' << a.c << "}\n";
}

输出：

n = 1
a = {0 0 0}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 2026 | C++98 | 曾指定始终首先进行零初始化，甚至先于常量初始化 | 如果适用常量初始化则不进行零初始化

参阅

  • 构造函数
  • 复制赋值
  • 默认构造函数
  • 初始化
    • 聚合初始化
    • 常量初始化
    • 复制初始化
    • 默认初始化
    • 直接初始化
    • 列表初始化
    • 值初始化
  • 移动赋值
  • new


有用的资源

< cpp
  • 标准 C++ 基金会 - C++ 新闻、专题及事件的非盈利中心

C++ FAQ

  • isocpp.org C++ FAQ - 标准 C++ 基金会的统一 FAQ 。
  • Bjarne Stroustrup FAQ - 语言创建者的对常提问题的解答
  • Bjarne Stroustrup C++11 FAQ - 考虑 C++ 语言标准近期更改的额外 FAQ
  • StackOverflow.com C++ FAQ - 程序员 Q&A 网站 StackOverflow.com 上频繁提问的 C++ 问题的最佳答案

C++ 语言及库参考

  • JTC1/SC22/WG21 - C++ 标准委员会，包含 C++ 标准草案、提案和缺陷报告
    • N3337 (PDF, HTML) - C++11 首个出版后草案
    • N4140 (PDF, HTML) - C++14 最终工作草案
    • N4659 (PDF, HTML) - C++17 最终工作草案
    • N4861 (PDF, HTML) - C++20 最终工作草案
    • N4868 (PDF, HTML) - C++20 首个出版后草案（仅含对 C++20 的编辑修正）
    • N4892 (PDF) - C++23 最新工作草案
  • eel.is/c++draft - 当前草案的 HTML 版本
  • ansi.org 付费的官方 C++ ISO/IEC 14882:2017
  • Apache - C++ 标准库的 Apache 实现的参考手册
  • IBM AIX 13.1.3 IBM zOS 2.3.0 C 与 C++ 核心语言的 IBM 实现的参考手册
  • IBM AIX 13.1.3 C++ 的 IBM 实现的参考手册
  • MSDN - C++ 核心语言的 Microsoft 实现的参考手册
  • MSDN - C++ 库的 Microsoft 实现的参考手册
    • dinkumware - Microsoft Visual C++ 所主导的 C++ 标准库实现
  • GNU libstdc++ - C++ 库 GNU 实现的参考手册
  • HP - C++ 库 Dinkumware 实现的的参考手册（ HP 拥有许可）
  • cplusplus.com - 非官方 C++ 标准库参考
  • C++17 in Tony Tables C++17 中的新特性及其示例。
  • SGI STL (hosted on rrsd.com) - 1994 年的 STL 库的参考手册，它引入了 C++ 标准库所接纳的许多概念。

C++ ABI

  • Itanium C++ ABI 事实的 C++ ABI 标准，为
  • System V ABI 及
  • ARM C++ ABI 采纳

模式、手法、提示和技巧

  • C++ 核心方针 Bjarne Stroustrup 与 Herb Sutter 著
  • C++ 样本 共同体所创建的现代 C++ 示例
  • 更多 C++ 手法于 wikibooks.org
  • CeePlusPlusIdioms 于 c2.com
  • 欢迎回到 C++ - 学习现代 C++ （ MSDN ）

相关标准

  • JTC1/SC22/WG14 - C 标准委员会，包含草案 C 标准、提案和缺陷报告
  • POSIX.1-2017/IEEE Std 1003.1-2017 - Unix 兼容系统的操作系统 API
  • Unicode 12.1 (2019-05-07) - 用于书写字符的通用编码

可能也有用

  • C++ 库列表

参阅


开源 C++ 库列表

< cpp‎ | links

此页面的目的是构建开源 C++ 库的比较列表，使得人们在需要特定功能的实现时，不必浪费时间在网上（ DuckDuckGo 、谷歌、必应等）搜索。

若你知道可能对其他人有用的库，请在此添加到它的链接。能包含进来的库没有限制，但是必须能便捷地下载库的源码。

以“原态”提供此页面——希望这有用，但不提供任何担保。过时、误导或错误的链接可能出现于此。若你注意到这些错误，则改正它会很有意义。

包管理器

包管理器 | 简述
build2 | 一个开源的 (MIT)、跨平台的构建工具链，旨在为开发和打包 C/C++ 项目时提供如 Rust Cargo 一样的便利性。
cget | Cmake 包检索工具，可用于下载并安装 Cmake 包。
cmodule | 非侵入式 CMake 依赖管理。
conan | 去中心化、开源 (MIT) 的 C/C++ 包管理器。
CPM.cmake | 一段可以为 CMake 加入依赖管理功能的 CMake 脚本。它是作为 CMake 的 FetchContent 模块的一个简单包装构建的。该模块加入了版本控制、缓存、简单 API 等功能。
hunter | 一个 CMake 驱动的跨平台包管理器，服务于 C/C++ 项目。
spack | 一个超级计算机、Linux、macOS 平台的包管理器。它使得安装科学软件变得简单。非绑定于某一特定语言。
teaport | 一个受 cocoapods 启发的依赖管理器。
vcpkg | 一个 Windows、Linux、macOS 平台的 C++ 包管理器。

库

音频

库名 | 简述 | 协议 | 配置手段
Aquila | Aquila 是一个开源、跨平台的 C++11 DSP 库。 | MIT 许可 | CMake
Essentia | 开源库，音频和音乐分析、描述和合成工具 (MIR) (源码) | Affero GPLv3 |
FFTW | 离散傅里叶变换 (DFT) 计算库 (SSE/SSE2/AVX/Altivec/ARM Neon)。 (源码) | GPL-2.0 | CMake
KFR | 快速、现代、C++17、开源并且跨平台的 DSP/DFT 框架。支持音频重采样、 FIR/IIR 滤波器、二阶滤波器, (SSE, AVX, AVX-512, ARM NEON)。 (源码) | GPL-2.0 | CMake
soundtouch | SoundTouch 是一个开源、跨平台的音频处理库，用于更改音频流或音频文件的速度、音调和播放速率。 (源码) | LGPL-2.1 | Makefile
CD
库名 | 简述 | 协议 | 配置手段
libkcompactdisc | CD 接口库 | GPL v2.0 | CMake
音频指纹
库名 | 简述 | 协议 | 配置手段
chromaprint | (源码) | MIT 许可, LGPL 2.1 | CMake
libmusicbrainz | (源码) | LGPL-2.1 | CMake
libofa | MusicIP 开源音频指纹库 | APL | makefile
格式
库名 | 简述 | 协议 | 配置手段
audiofile |  | LGPL-2.1 | makefile
flac |  | Open Source, BSD 许可, GPL 许可 |
libsndfile |  | LGPL v2.0 or v3.0 |
标签
库名 | 简述 | 协议 | 配置手段
id3lib |  | LGPL v2 |
taglib | (源码) | LGPL 和 MPL v1.1 |

性能测试

库名 | 简述 | 协议 | 配置手段
benchmark |  | Apache2.0 许可 | CMake
Celero |  | Apache 许可 | CMake
gperftools | “谷歌性能工具”包含高性能、多线程的 malloc 实现加上评测堆分配和 CPU 利用的工具。 | BSD 3-Clause "New" or "Revised" License | configure
plf::nanotimer | 用于性能评测的最低开销、跨平台的简单定时器类。 | zlib 许可 |

通信

库名 | 简述 | 协议 | 配置手段
ACE | 异步网络、多路分离、报文发送 |  |
Apache Thrift | Apache Thrift 软件框架，用于规模可变的跨语言服务开发，将软件栈与代码生成引擎结合，构建有效而无缝地在 C++ 、 Java 、 Python 、 PHP 、 Ruby 、 Erlang 、 Perl 、 Haskell 、 C# 、 Cocoa 、 JavaScript 、 Node.js 、 Smalltalk 、 Ocaml 、 Delphi 及其他语言间工作的服务。 |  |
Boost.Asio | 异步及同步网络、定时器、序列 I/O | BSL-1.0 |
Boost.Beast | 建立于 Boost.Asio 顶上的 HTTP 及 WebSocket 库 | BSL-1.0 |
Breep | 基于事件、高层、点对点库，允许用户直接发送和接收对象。 | European Union Public License 1.1 | CMake
C++ REST SDK | 异步 HTTP 客户端及监听器、异步 Stream 、 URI 、 JSON | MIT 许可 | CMake
cpp-netlib | cpp-netlib ： C++ 网络库 | BSL-1.0 | CMake
cpr | 现代 C++ HTTP 请求库 | MIT 许可 | CMake
Crow |  | BSD-3-Clause | CMake
curlpp | CURL 库的 C++ 包装 |  |
DumaisLib |  | MIT 许可 | Makefile
EasyHttp | 跨平台的 HTTP 客户端库，专注于可用性和速度，支持 http 响应缓存及更多 | MIT 许可 | CMake
eCAL | 高性能进程间通信 | Apache2.0 许可 | CMake
fineftp-server |  | MIT 许可 | CMake
gRPC |  |  |
gsoap | XML 数据绑定、快速 WSDL/SOAP/XML 网络服务、 WS 安全、 JSON/XML-RPC RESTful 服务的 C/C++ 开发工具套 |  |
HTTPP | 简单、生产就绪的构建在 Boost 上的 HTTP 服务器，及构建在 libcurl 上的客户端。 | BSD 2-Clause "Simplified" License | CMake, Makefile
IXWebSocket | 无依赖的开源 WebSocket + HTTP 库，支持 SSL 和逐条消息 deflate 的 WebSocket 扩展。 | BSD 3-Clause "New" or "Revised" License | CMake, Makefile
KCP | 快速可靠的 ARQ 协议，帮助应用减少网络延迟。 | MIT 许可 | CMake
libashttp | 异步 HTTP 客户端库 | GNU Lesser General Public License v3.0 |
libnavajo |  | CeCILL-C FREE SOFTWARE LICENSE AGREEMENT | CMake
libtins | 网络包装制作及嗅探库 |  |
nanomsg |  |  |
netif |  | BSD 3-Clause "New" or "Revised" License | CMake
nghttp2 | HTTP/2 C 库及工具（服务器、客户端、代理和评测工具） | MIT 许可 | CMake, configure
ngrest | 快速而简易的利用 JSON 的 RESTful 网络服务框架 | Apache2.0 许可 | CMake
nng |  |  |
omniORB | 最快速、完整而可移植的 CORBA ORB 在 C++ 中的实现 |  |
OpenDDS | DDS 实现 |  |
Paho MQTT |  |  | CMake
PcapPlusPlus | 多平台 C++ 网络嗅探和包装分析及制作框架 |  |
POCO | 网络：加密、 HTTP ； ZIP 文件 |  |
rest_rpc | 现代、简单、易用的 rpc 框架 |  | CMake
restbed | 设计以嵌入到宽范围的应用中的 C++ 为框架。 | 许可协议 | CMake
restc-cpp | 将痛苦从自 C++ 访问 JSON API 带走。 HTTP 客户端，原生 C++ 类到/自 JSON 的序列化，通过 boost::asio coroutines 携程的异步 IO 。 C++14 。 | MIT 许可 | CMake
restful_mapper | 于 C++ 中消费 RESTful JSON API 的 ORM |  | CMake, Makefile
seastar | 用C++11实现的高性能异步编程框架。 | Apache2.0 许可 | CMake, etc.
Silicon | 快速而稳健的 Web APIs | MIT 许可 | CMake
sockpp | 简单的现代 C++ 套接库 | BSD 3-Clause "New" or "Revised" License | CMake
Simple C++ REST library | 在你的 C++ 应用中创建 REST API 的非常简单且自成文档的库 |  |
stream-client | 轻量、唯头文件的、基于 Boost 的客户端 socket/connector/socket pool/resolver | Apache2.0 许可 | CMake
tacopie | C++11 TCP 库 | MIT 许可 | CMake
TAO | CORBA |  |
taox11 | 基于 C++11 的 CORBA 实现 | MIT 许可 |
Unicomm | 异步网络、高层 TCP 交互框架 |  |
uvw | 现代 C++ 书写的 libuv | MIT 许可 | CMake
wvstreams |  | GPL 许可 |
zeromq | 快速消息队列 |  |

并发

库名 | 简述 | 协议 | 配置手段
BlockingCollection | C++11 线程安全汇集类，模仿 .Net BlockingCollection。 |  |
Boost.Atomic |  | BSL-1.0 |
Boost.Compute | （非官方） OpenCL 的仿 STL 算法及数据结构 | BSL-1.0 |
Boost.Context |  | BSL-1.0 |
Boost.Interprocess |  | BSL-1.0 |
Boost.Lockfree |  | BSL-1.0 |
Boost.MPI |  | BSL-1.0 |
Boost.Thread |  | BSL-1.0 |
Cpp-Taskflow | 带任务依赖的快速 C++ 并行编程 |  |
hipSYCL |  | BSD-2-Clause License | CMake
HPX | 任何规模的并行和分布式应用的通用 C++ 运行时系统 |  |
Intel TBB |  |  |
KOKKOS | C++ 中的编程模型，用于书写高性能的便携 HPC 应用 |  |
libopenmpi |  |  |
libsimdpp |  |  |
MutexGear |  | The MutexGear Library License | configure, MSVC
OpenMP |  |  |
RaftLib | 类似并发行动者的 C++ 流 |  |
SObjectizer | 通过行动者和出版订阅模型，简化开发并发和事件驱动应用的 C++ 中的小型框架。 |  |
subprocess |  |  |
Taskflow |  |  |
Thrust | CUDA 的仿 STL 算法及数据结构 |  |
VexCL | OpenCL 和 CUDA 的 C++ 表达式模板库 |  |
ViennaCL | 带 OpenMP 、 CUDA 及 OpenCL 后端的线性代数及算法 |  |
Xenium |  |  |

配置

库名 | 简述 | 协议 | 配置手段
Boost.Program_options |  | BSL-1.0 |
gconfmm |  |  |
libconfig |  |  |
libconfini | INI 分析器 |  |
CSS
库名 | 简述 | 协议 | 配置手段
mycss | CSS 解析器 |  |
HOCON
库名 | 简述 | 协议 | 配置手段
cpp-hocon | Pupplet 开发的 HOCON 格式的 C++ 实现。 |  |
JSON
库名 | 简述 | 协议 | 配置手段
ArduinoJson | ArduinoJson |  |
CAJUN |  |  |
jansson | Jansson 是编码、解码及操纵 JSON 数据的 C 库。 |  |
jeayeson | 非常健全的（唯头文件） C++14 JSON 库 |  |
jios | JSON 输入输出流 (JSON Input Output Streams) | MIT 许可 | CMake
JOST |  |  |
JSON Voorhees | C++ 的杀手 JSON |  |
json | Niels Lohmann JSON | MIT 许可 | 仅头文件库
JSON++ |  |  |
json-cpp |  |  |
json11 | json11 是 C++11 的轻量 JSON 库，提供 JSON 分析及序列化。 |  |
JsonBox |  |  |
jsoncons | JSON 与类 JSON 数据结构的唯头文件库，含 JSON Pointer 、 JSON Patch 、 JSONPath 、 CSV 、 MessagePack 、 CBOR 、 BSON 、 UBJSON。 |  |
jsoncpp |  |  |
jsonme-- |  |  |
libjson |  |  |
minijson | C++ 无 DOM 且免分配的 JSON 分析及序列化 |  |
nosjob |  |  |
qjson |  |  |
rapidjson |  |  |
simdjson | 每秒解析 GB 级别的 JSON |  |
struct_mapping |  |  |
ThorsSerializer | JSON/YAML Input Output Streams | MIT 许可 | Makefile
ujson | µjson 是小型的 C++11、UTF-8 JSON 库 |  |
zoolib |  |  |
TOML
库名 | 简述 | 协议 | 配置手段
toml++ |  |  |
toml11 | 基于 C++11 的 TOML 解析库 |  |
XML
库名 | 简述 | 协议 | 配置手段
ai-xml |  |  |
GPDS |  |  |
gSOAP | XML 数据绑定 |  |
libxml++ |  |  |
pugixml |  |  |
tinyxml |  |  |
tinyxml2 | 另一 TinyXML ，建设中。 |  |
Xerces |  |  |
YAML
库名 | 简述 | 协议 | 配置手段
yaml-cpp |  |  |

容器

库名 | 简述 | 协议 | 配置手段
Boost.Bimap |  | BSL-1.0 |
Boost.Container |  | BSL-1.0 |
Boost.Fusion |  | BSL-1.0 |
Boost.Heap |  | BSL-1.0 |
Boost.Pointer Container |  | BSL-1.0 |
Boost.Tuple |  | BSL-1.0 |
Boost.Variant |  | BSL-1.0 |
cpp-btree | btree_map 、 btree_set 、 btree_multimap 、 btree_multiset 。 |  |
DataFrame | C++ DataFrame —— 现代 C++ 中使用原生类型、连续内存存储，且无虚函数的 R 与 Pandas 数据框架。 |  |
eggs::variant | Eggs.Variant 是 C++11/14 的泛型、线程安全、有区别的联合体。值得注意的是它有很好的 constexpr 支持。 |  |
Frozen | constexpr 完美基于哈希的冻结集合与映射（ Apache 2.0 ）。 |  |
Immer |  | Boost License | CMake
plf::colony | 无序的“类背包”容器，在高度修改场景中性能优于 std:: 容器，同时维护指向未被擦除元素的合法指针，无关乎插入或擦除。 |  |
plf::list | std::list 实现，为缓存友好牺牲范围切割，导致更快的插入、擦除和迭代。 |  |
plf::stack | std::stack 容器适配器的随意访问替换容器，在栈环境中有优于 std::vector 和 std::deque 的性能。 |  |
ring_span | Guy Davidson 与 Arthur O'Dwyer 的 ring_span ——即环状缓冲区视图的简化实现。 |  |
strict_variant | 快速而决不空的 variant ，目标 C++11 。阻止许多不想要的隐式转换。 |  |
TdhLists |  |  |
Ygg | 高性能容器和数据结构，例如红黑树、区间数和区间映射的侵入式 C++11 实现。 |  |

密码学

库名 | 简述 | 协议 | 配置手段
Botan |  |  |
crypto++ |  |  |
gnutls |  |  |
openssl |  |  |
TomCrypt |  |  |

数据库

库名 | 简述 | 协议 | 配置手段
cpp-redis | C++11 轻量的 Redis 客户端：异步、线程安全、无依赖、管道化、多平台。 |  |
DTL |  |  |
EasyQtSql | 轻量唯头文件 C++11 库，用 QtSql 快速便捷地进行 SQL 查询 |  |
LevelDB | 谷歌开发的、能够处理十亿级别规模 Key-Value 型数据持久性存储的C++ 程序库。 |  |
libpqxx |  |  |
lmdb++ | LMDB 嵌入式 B+ 树数据库的 C++11 包装。 |  |
mongocxx | MongoDB 的 C++11 驱动库 |  |
mysql++ |  |  |
ODB | C++ Object-Relational Mapping (ORM) |  |
OTL |  |  |
Pgfe | PostGres FrontEnd现代 C++ 客户端 API 到 PostgreSQL | Zlib License | CMake
QTL | A friendly and lightweight C++ database library for MySQL, SQLite and ODBC. |  |
QUINCE | QUeries IN C++ Expressions (ORM+EDSL) | Boost License |
QxOrm | Object Relational Mapping (ORM) database library for C++/Qt, supports most common databases, serialization (JSON, binary, XML); standalone multi-threaded HTTP web server | GPLv3 or Proprietary license |
redis-cpp | C++17 Lightweight C++ client header-only library for executing Redis commands. |  |
redis-plus-plus | 用C++ 11编写的Redis客户端, 支持Redis Sentinel，Redis Cluster，管道，事务，发布订阅，连接池以及类似于STL的接口 |  |
SOCI |  |  |
SQLAPI++ |  |  |
SQLiteCPP |  |  |
sqlpp11 |  |  |
taoPQ | Lightweight C++17 PostgreSQL client library | MIT License | CMake

嵌入语言绑定

库名 | 简述 | 协议 | 配置手段
AngelScript | 类似 C++ 的脚本语言。 |  |
ChaiScript |  |  |
ExprTk |  |  |
Jinx | Scripting language designed for videogames. |  |
lua |  |  |
mozjs |  |  |
muparser |  |  |
PythonQt |  |  |
ScriptCaller | 允许程序员调用 Ruby 脚本的唯头文件库。 |  |
sol2 |  |  |
v8pp | 将 C++ 函数和类绑定到 V8 JavaScript引擎中。 |  |

嵌入式/实时系统

库名 | 简述 | 协议 | 配置手段
distortos | 微控制器的面向对象 C++ RTOS |  |
ETL | Embedded Template Library - C++03 ，为少资源平台裁剪的可移植模板库 |  |
QP/C++ | RTOS 内核，双重 GPL |  |
µcuREST | 微控制器的 C++11 REST/JSON 服务器框架 |  |

文件元数据

库名 | 简述 | 协议 | 配置手段
exempi |  |  |
exiv2 |  |  |
libkexiv2 |  |  |
rarian |  |  |

金融计算

库名 | 简述 | 协议 | 配置手段
DataFrame | C++ DataFrame —— 现代 C++ 中使用原生类型、连续内存存储，且无虚函数的 R 与 Pandas 数据框架。 |  |
QuantLib | Quantitative finance library |  |

游戏引擎架构

库名 | 简述 | 协议 | 配置手段
Anax |  |  |
BOX2D | 物理引擎 |  |
EntityPlus |  |  |
EntityX |  |  |
EnTT |  |  |

通用多媒体

库名 | 简述 | 协议 | 配置手段
Cinder |  |  |
Kigs-framework | Modular Multi-purpose Cross Platform Framework | MIT license |
openFrameworks |  | MIT license |
SDL | (Simple DirectMedia Layer): 对音频、键盘、鼠标、操纵杆及图形硬件，经由平台上图形 API （通常为 OpenGL 或 Direct3D ）的跨平台低层访问（ zlib 许可） |  |
SFML | Simple and Fast Multimedia Library |  |
SIGIL | Sound, Input, and Graphics Integration Library; 文本、形状、输入、音频及 2D 图像的难以置信地简单的跨平台极简库 |  |

通用

库名 | 简述 | 协议 | 配置手段
Abseil | Google 设计以补足 C++ 标准库的开源 C++ 库代码汇集。 |  |
Abstract Intrusive Containers | 比 boost::intrusive 更灵活，但非 STL 兼容。 |  |
BDE | 来自 Bloomberg L.P. 的 Bloomberg Development Environment 核心库 | Apache 许可 |
Better Enums | 反射性枚举（枚举到字符、迭代等），带 constexpr 支持。 | BSD |
bitfield.h | 位域结构设施，比基础语言设施更可移植/灵活。 |  |
Boost | 大量通用库的汇集 | Boost 许可 |
CAF | C++ Actor Framework (CAF) 是开源的 C++11 行动者模型实现，特性为轻量而快速的行动者实现、消息的模式匹配、网络不可见消息传递及更多 | BSD 许可 |
Cinder | A community-developed, free and open source library for professional-quality creative coding in C++. (Doc) (Src) | Modified BSD License | CMake
CommonPP | 多用途库，强调在项目中得出度规。 | BSD |
composite_op.h | 基础类数据成员自省，繁琐且常常不可重入，但有时有用。 |  |
cpp-mmf | 对 POSIX 或 Windows 封装映射到内存文件的 C++98 库 |  |
cxxomfort | C++ 特性逆向移植（ C++11 到 C++03 及 C++1y 提案到 C++11/C++03 ）。 |  |
Dlib | 网络、线程、图形用户界面、数据结构、线性代数、机器学习、 XML 及文本分析、数值优化、贝叶斯网络和大量其他任务 | Boost 许可 |
fcppt | Freundlich 的 C++ 工具套 (fcppt) 是聚焦于通过提供更好的类型和函数式编程改进 C++ 代码的库汇集。 |  |
Folly | Facebook 开源库。设计带有构思中的实践性和效率设计的 C++11 组件库。 |  |
GSL | Guideline Support Library 实现，为 Bjarne Stroustrup, Herb Sutter 和 Co 在《 C++ 核心方针》中推荐 |  |
gsl-lite | C++98 、 C++11 及后续版本的 ISO C++ Guideline 支持库 (GSL) 的单文件唯头文件版本。 |  |
History | Modern C++17 Undo/Redo Framework | Unlicense |
IP-DOS (tm) | IdeaFarm (tm) Piggyback Distributed Operating System: A general purpose programming environment for the C++ language. | Proprietary Open Source | Open Watcom 2.0
JUCE | 扩展性的成熟跨平台 C++ 工具套 | GPL 许可 |
Kangaru | C++11 与 C++14 的依赖注入容器 | MIT 许可 |
libsourcey | 高速网络化和多媒体编码的跨平台 C++11 库。 HTTP 、 WebSockets 、 TURN 、 STUN 、 Symple 及更多…… |  |
LLNL/units | A run-time C++ library for working with units of measurement and conversions between them and with string representations of units and measurements | BSD 3-Clause "New" or "Revised" License | CMake
Loki | 设计模式 |  |
nonstd-lite | *-lite 仓库的亲属，将 C++11 后特性移植到古代 C++ 环境的迁移路径。 |  |
nytl | 通用的 C++17 唯头文件模板库。 | Boost 许可 |
OnPosix | 在 POSIX 平台上提供各种抽象（例如线程、网络化、日志、 IPC 等）的 C++ 库。 |  |
Reason | xml 、 xpath 、正则表达式、线程、接头、 http 、 sql 、日期时间、流、编码与解码、文件系统、压缩 | GPL 许可 |
SaferCPlusPlus | SaferCPlusPlus - 不安全的 C++ 原始工具的安全兼容替换品，包括指针、 int 和 std::vector。 | Boost 许可 |
Smart Enum | 给你的枚举 "to_string" 、 "from_string" 和更多。 | Boost 许可 |
units | 编译时唯头文件的量纲分析及单位转换库，建立于 C++14 而无依赖。 |  |
yaal | 算法、汇集、任意精度计算、泛型 DSL 文法驱动分析器及更多 | CC BY-ND-NC 4.0 | CMake
Yato | 现代 C++ (14/17) 的跨平台 STL 风格及 STL 兼容库，实现容器、范围、迭代器、类型特性和其他工具；行动者系统；类型安全配置接口 | Apache-2.0 |
yomm2 | C++17 的开放式多方法 | Boost 许可 |

GPS

库名 | 简述 | 协议 | 配置手段
gpsd |  |  |

图形用户界面

库名 | 简述 | 协议 | 配置手段
Dear ImGui | 高度优化的不膨胀的图形用户界面库。 |  |
FLTK |  |  |
nana | 用现代 C++ 风格的 GUI 编程（ Boost 许可） |  |
nanogui | 最小化的跨平台器件库，适用于 OpenGL 3.x 或更高版本 |  |
OWLNext | 对 OWL 的，用于在 Windows 上以标准 C++ 书写 GUI 应用的现代更新 |  |
tiny file dialogs | 单个 C C++ 跨平台文件（无初始化、无 main 循环、 6 种形态的函数调用） |  |
WxWidgets |  |  |
xtd | Modern C++17/20 framework to create console, GUI and unit tests applications on Windows, macOS, Linux, iOS and android. (Website) (Doc) | MIT License | CMake
CopperSpice
库名 | 简述 | 协议 | 配置手段
CopperSpice | CopperSpice 是用于开发跨平台软件应用的 C++ 库集合。它在 LGPL V2.1 许可下发布。它使用现代理念的 C++ 并与 STL 无缝结合。 CopperSpice 派生自 Qt 框架。 |  |
CsSignal | 独立的 C++ 具线程信号/槽库 |  |
CsString | 独立的 C++ 具 Unicode 字符串库 |  |
libGuarded | 独立的 C++ 多线程库，用于管理对共享数据的访问 |  |
GTK+
库名 | 简述 | 协议 | 配置手段
evince |  |  |
flowcanvas |  |  |
glibmm |  |  |
goocanvasmm |  |  |
gtkmm |  |  |
libglademm |  |  |
libgnomecanvasmm |  |  |
webkitgtk |  |  |
Qt
库名 | 简述 | 协议 | 配置手段
libdbusmenu-qt |  |  |
Qt |  |  |
QuickQanava | 直接在 Qt/QML 应用中画图的 C++14 库；项目主页： http://www.qanava.org |  |
qwt5 | 技术应用到 Qt Widgets |  |
qwtplot3d |  |  |
QuickProperties | QObject/QtObject 属性编辑的 C++/QML 库；项目主页： http://www.qanava.org |  |
Ultimate++
库名 | 简述 | 协议 | 配置手段
Ultimate++ | 跨平台的迅速应用开发框架 |  |
upp-components | A collection of 3rd party packages for Ultimate++ like TerminalCtrl, MessageCtrl etc.. | BSD-3-Clause |

图形

库名 | 简述 | 协议 | 配置手段
bgfx | 非常强大的跨平台图形渲染库，支持平台包括 Windows Mac Linux iOS Android Web，渲染后端包括 DX, opengl, metal webgl等。 |  |
cairomm |  |  |
dfpsr | 2D, 3D and isometric software renderer with desktop GUI toolkit, minimalistic dependency, designed for long time maintenance and can run without any 3D accelerated drivers | zlib license |
gegl | GEGL (Generic Graphics Library) is a data flow based image processing framework, providing floating point processing and non-destructive image processing capabilities. (Src) | LGPL |
io2d | Reference Implementations of P0267, the proposed 2D graphics API for ISO C++ | Boost License | CMake
nanovg | 基于openGL/DX/metal的2d绘图库。 |  |
nux |  |  |
pangomm |  |  |
Skia | is an open-source 2D-graphics library written in C++. Skia is used in Google Chrome, Chrome OS, Mozilla Firefox, Android, LibreOffice, Flutter, etc. Skia has several back-ends: software rasterization, (PDF) output, OpenGL, SVG, etc. | New BSD License |
TXLib | TX Library is a tiny 2D graphics library for Win32 written in C++. |  |
ULIS | Cross-Platform C++14 Library, Generic digital image processing, 2D Software rasterizer, Unlimited image formats (u8, u16, u32, float, double), Custom bit-ordered memory layout, All Photoshop pixel blending modes + 11 additional modes, Color models (RGB, HSL, HSV, CMYK, ...), Color-managed pipelines, Color Space support (icm profiles and device-independant), Optimized algorithms with multithreading, Optimized algorithms with SIMD Extensions (SSE2), Image pools and caches for optimisations, Memory storage of animated image sequences | Custom (free-of-charge for non-commercial purposes only) | CMake

3D 图形

库名 | 简述 | 协议 | 配置手段
assimp | 3D 模型加载 |  |
bgfx | 跨平台、不知图形 API 、“带来你自己的引擎/框架”风格的制图库。 |  |
Diligent Engine | 现代跨平台低层 3D 图形库。 |  |
Epoxy | GLEM 的现代后继者。在 GL 环境的一些种类间抽象，这使得有时比使用 GLEW 更加单。自 2015 起为 GTK+ 项目所用。 |  |
G3D | The G3D Innovation Engine is a fully featured, open source, cross platform (Windows, Linus, Mac OS) 3D game engine written in C/C++. G3D is used in commercial games, research papers, simulators, and university courses. It supports real-time and offline hardware rendering, ray tracing, model loading, linear algebra, and GP-computation on GPUs. Supports 3DS, OBJ, MP4, PNG, JPG, MD3 and many other formats, includes a native OpenGL skinnable GUI. (Src) (Doc) | BSD-2 license |
GLAD | 可定制的轻量库，用于加载 OpenGL 功能 |  |
GLEW | OpenGL 功能加载 |  |
GLFW | OpenGL 窗口管理器 |  |
GLM | 制图用的唯头文件 C++ 数学库 |  |
hlsl++ | 使用 hlsl 语法的唯头文件 C++ 渲染库。支持 SSE 和 NEON |  |
Horde3D |  |  |
Irrlicht |  |  |
klein | C++11/14/17 SSE-optimized Projective Geometric Algebra library for graphics and animation |  |
Magnum | 游戏和数据可视化的轻量模块化的 C++11/C++14 图形中间件 |  |
O3DE | Open-source 3D Engine (former Amazon's Lumberyard) is a C++ multi-platform 3D engine to build AAA games, cinema-quality 3D worlds, and high-fidelity simulations. Includes physics simulation, script engine, networking, and more. (Doc) | Apache 2.0 | CMake
Ogre3D |  |  |
Open CASCADE | 3D CAD/CAM/CAE 应用的 SDK |  |
OpenGL |  |  |
OpenSceneGraph |  |  |
Visionaray | C++ 光束追踪模板库 |  |
VTK |  |  |
Vulkan |  |  |

图像

库名 | 简述 | 协议 | 配置手段
Adobe/boost GIL | 高层通用库，聚焦于 2D 图像上操作的算法。非常有限定 I/O 选项。 |  |
agge | Anti-Grain Evolution. 2D graphics engine for Speed and Quality in C++ | MIT License | CMake
Anti-Grain Evolution | 跨平台 2D 光栅化及绘图引擎 |  |
FreeImage | An Open-Source library project for developers who would like to support popular graphics image formats like PNG, BMP, JPEG, TIFF and others | GPLv2, GPLv3, FIPL |
gegl |  |  |
GraphicsMagick | 读、写、操纵 88 种主要格式的图像。于 2002 年分化自 ImageMagick |  |
SAIL | Reading and writing static, animated, multi-paged images along with their meta data and ICC profiles. No manipulating capabilities. Targets simplicity and speed. | MIT | CMake
Skia Graphics Engine | Google 从 2005 年起的图形库，用于 Chrome 、 Chrome OS 、 Android 还有 Firefox 和 Sublime Text enwiki:Skia_Graphics_Engine |  |
stb.image |  |  |
格式
库名 | 简述 | 协议 | 配置手段
djvulibre |  |  |
imagemagick |  |  |
Kaitai Struct C++ runtime |  |  |
libraw |  |  |
openexr |  |  |
poppler |  |  |
qimageblitz |  |  |
SVG++ |  |  |
打点
库名 | 简述 | 协议 | 配置手段
Matplot++ | A gnuplot based C++ Graphics Library for Data Visualization. Matplot++ can take advantage of the following libs: OpenCV, OpenGL, LAPACK, BLAS, FFTW, JPEG, TIFF, ZLIB, PNG, GLAD, GLFW3. (Doc) | MIT License | CMake
plotutils |  |  |

图像处理

库名 | 简述 | 协议 | 配置手段
dlib |  |  |
Halide | A C++-embedded DSL for high-performance processing of images and tensors. | MIT | CMake, vcpkg
ITK |  |  |
opencv |  |  |
OTB |  |  |

国际化

库名 | 简述 | 协议 | 配置手段
gettext |  |  |
IBM ICU |  |  |
spirit-po | 快速的唯头文件库，分析 po 文件，并提供类似 GNU libintl 的接口。基于 boost::spirit 。 |  |

日志

库名 | 简述 | 协议 | 配置手段
Backward | 打印漂亮的 Python 风格栈追踪，带颜色和源代码片段，特别是在崩溃时（ MIT 许可）。 |  |
Boost.Log |  |  |
glog | Google 日志库 |  |
Log4cplus | 日志 API ，提供日志管理及配置上的线程安全、灵活且有任意粒度的控制。 |  |
Log4cpp | 用于灵活地记录到文件、系统日志、 IDSA 或其他目标的 C++ 类库 (LGPL) |  |
log4cxx | Apache log4cxx 是 Apache log4j 后的 C++ 模式化记录框架 |  |
Pantheios | 诊断日志 API 库，提供类型安全、效率、泛型和可扩展性的结合 |  |
plog | C++ 的可移植且简单的日志，少于 1000 行代码 (MPL2) |  |
Quill | C++14 Asynchronous Low Latency Logging Library |  |
spdlog | 超快的唯头文件 C++ 日志库 |  |

错误处理

库名 | 简述 | 协议 | 配置手段
Boost.LEAF | Lightweight error-handling library for C++11: single-header format, no dependencies, no dynamic memory allocations, can be used with or without exception handling, multi-threading ready. | BSL-1.0 |

数学

库名 | 简述 | 协议 | 配置手段
alglib |  |  |
ArrayFire High Performance Computation Library |  |  |
BigNumber | 创建和计算任意长度整数的 C++ 类 |  |
Boost.Math.Special Functions and Statistical Distributions |  |  |
Boost.Multiprecision |  |  |
Boost.Random |  |  |
Boost.SafeNumerics | C++14, header only, Guaranteed Correct Integer Arithmetic, a drop-in replacement for the built-in integer types. | BSL-1.0 |
C++ Matrix | 高性能且精确（例如极端情况）的矩阵数学库，带表达式模板算术运算符 |  |
CasADi | Symbolic framework for nonlinear optimization and algorithmic differentiation. Supports C++ code generation for symbolic expressions and dynamic connection of compiled generated code. |  |
cpp-measures | 处理物理度量的唯头文件 C++11 库 |  |
Exact floating-point arithmetic library |  |  |
G+Smo | 等几何分析的跨平台库 |  |
GNU MP bignum C++ interface |  |  |
libmpdec++ | Cross-platform library for correctly-rounded arbitrary precision decimal floating point arithmetic. | BSD-2-Clause | Autoconf, Visual Studio build scripts
PCGrand | PCG is a family of simple fast space-efficient statistically good algorithms for random number generation. Unlike many general-purpose RNGs, they are also hard to predict. | Apache License |
NTL - A Library for doing Number Theory |  |  |
RPNX Uniform Smooth Noise | N 维均匀分布的平滑噪声函数，以 C++ 实现。 |  |
SEMT | Compile time symbolic differentiation |  |
stats++ | 先进、广泛的统计软件：数据收集及预处理、统计、机器学习及优化，拥有开放的 C++ 源码。 |  |
StatsLib | 统计分布函数的模板化唯头文件库。 |  |
自动化理论
库名 | 简述 | 协议 | 配置手段
State Diagram | An easy to use C++20 library for hierarchical finite state machines (Doc) | Apache 2.0 License |
yasmine - C++11 UML state machine framework |  |  |
UML_StateMachine | UML State Machine is a pure C++20 library for defining state charts statically and executing them. (Doc) | GPLv3 License | CMake
数的类库
库名 | 简述 | 协议 | 配置手段
cln |  |  |
CNL | Compositional Numeric Library - fixed-precision numeric types | BSL-1.0 | CMake, Conan
Universal Numbers | 通用数算术的 C++ 模板库，取代 IEEE 浮点（ MIT 许可） |  |
计算几何
库名 | 简述 | 协议 | 配置手段
CGAL | 计算几何算法库 |  |
PCL | 点云库 |  |
pmp-library | Polygon Mesh Processing Library |  |
Wykobi | 计算几何库 |  |
图论
库名 | 简述 | 协议 | 配置手段
Boost.Graph |  |  |
CXXGraph | A C++17 Header-Only Library for Graph Representation, Manipulation, Partitioning and Algorithms | AGPL-3.0 | CMake
GTpo | C++14 泛型图拓扑库，带 Protocol Buffer 序列化；项目主页： http://www.qanava.org |  |
LEMON |  |  |
NGraph | a simple (Network) Graph library in C++ |  |
OGDF | Open Graph Drawing Framework |  |
线性代数
库名 | 简述 | 协议 | 配置手段
Armadillo |  |  |
Blaze |  |  |
Blitz++ |  |  |
Boost.uBLAS |  |  |
DecompLib | 唯头文件的 C++11 库，分解向量为正定加权基向量的集合。 |  |
Dlib - linear algebra tools |  |  |
Eigen |  |  |
ETL |  |  |
IT++ |  |  |
Matrix | Easy-to-use Scientific Computing library in/for C++ available for Linux and Windows. | MIT License | CMake
PETSc | A suite of data structures and routines for the parallel solution of scientific applications modeled by partial differential equations. It supports MPI, and GPUs through CUDA or OpenCL, as well as hybrid MPI-GPU. |  |
xtensor | A C++ library meant for numerical analysis with multi-dimensional array expressions. | BSD |
机器学习
库名 | 简述 | 协议 | 配置手段
ANNetGPGPU | 基于GPU（CUDA）的人工神经网络库。 |  |
btsk | 游戏行为树入门套件。 |  |
CNTK | 微软认知工具包（CNTK），一种开源的深度学习工具包。 |  |
Dlib | 机器学习工具 |  |
DLDT | OpenVINO™工具包-深度学习部署工具包 |  |
Evolving Objects | 基于模板的 C++ 演化计算库，可帮助您快速随意地编写自己的随机优化算法。 |  |
FANN | 快速人工神经网络库 |  |
frugally-deep | 仅头文件的库，用于在 C++ 中使用Keras模型。 |  |
Genann | 简单神经网络库。 |  |
Kaldi | 语音识别工具包。 |  |
liblinear |  |  |
libtorch | C++ frontend to the popular PyTorch Python library (backend is written in C++) | BSD-style license | CMake
MLPACK | 机器学习包 |  |
NCNN | 腾讯开发的、针对移动平台进行了优化的高性能神经网络推理框架 |  |
OpenPose | 实时多人关键点检测库，用于身体，面部，手和脚的检测 |  |
Paddle | 并行化分布式深度学习库 |  |
Recast/Detour | 导航网格生成器和浏览器，主要用于游戏。 |  |
stats++ |  |  |
Shogun | 大规模机器学习工具箱 |  |
tensorflow | 面向所有人的开源机器学习框架 |  |
TensorRT | 用于在 NVIDIA GPU 和深度学习加速器上进行高性能推理的 C++ 库 |  |
tiny-dnn | 基于 C++11 的唯头文件、无依赖的深度学习框架。 |  |
Veles | 用于快速深度学习应用程序开发的分布式平台。 |  |
数值计算
库名 | 简述 | 协议 | 配置手段
LibBF | 由 Bellard 开发的任意精度数值计算库，拥有一个将圆周率计算到数十亿位的示例程序 |  |
优化
库名 | 简述 | 协议 | 配置手段
ceres-solver | Open-source C++ library for modeling and solving large, complicated optimization problems. It is a feature rich, mature and performant library which has been used in production at Google since 2010. | Apache License | CMake, Conan
OptimLib | 非线性函数数值优化方法的 C++11 库。 |  |

元编程

库名 | 简述 | 协议 | 配置手段
Boost.CallableTraits |  |  |
Boost.Hana | 类型与值的新元编程库 |  |
Boost.Metaparse | 编译时分析器库，从编译时字符串产生类型、值和元函数 |  |
Boost.Mp11 |  |  |
Boost.MPL | 原初元编程库，目标为 C++03 ，慢 |  |
Boost.PFR | A header only C++14 library for basic reflection (without macros): visiting members of a user defined type by index, IO streaming. | BSL-1.0 |
Boost.Proto | 构建基于表达式模板的 EDSLs 的库 |  |
Brigand | 使用饿元函数，为最佳性能优化 |  |
CoMeta | 轻量、唯头文件的 C++14 元编程库 |  |
Meta | 使用饿元函数，在 metal 和 brigand 之间，相对于性能妥协 |  |
Metal | 使用饿元函数， 100% SFINAE 友好 |  |
refl-cpp | A modern compile-time reflection library for C++ with support for overloads, templates, attributes and proxies |  |
Refureku | C++17 runtime reflection and code generation library | MIT License | CMake
visit_struct | 小规模反射库，提供 C++11 的结构体观察器。自容纳， 100-200 行代码，取决于如何计算。 |  |

PDF

库名 | 简述 | 协议 | 配置手段
HARU |  |  |
JagPDF |  |  |
PoDoFo |  |  |

物理与模拟

库名 | 简述 | 协议 | 配置手段
Bullet | 游戏、视觉效果、机器人及加固学习的物理模拟 |  |
HELICS | Co-simulation framework for synchronizing time and exchanging data between different types of simulators | BSD 3-Clause "New" or "Revised" License | CMake
ProjectCHRONO | 开源多物理模拟引擎 |  |
ReactPhysics3D | 进行 3D 模拟与游戏的 C++ 物理引擎 |  |

序列化

库名 | 简述 | 协议 | 配置手段
ai-xml | 通过添加单个最小的函数到类，在 XML 间序列化及反序列化。在底层使用 libxml++ 。 |  |
Boost.Serialization |  |  |
C++ XML objects |  |  |
cereal | C++11 序列化 |  |
cppcodec | 唯头文件库，编码/解码 base64 、 base32 和十六进制，有一致而灵活的 API （ MIT 许可） |  |
GPDS | General purpose data serializer to serialize objects to and from XML. Uses TinyXML under the hood. |  |
gSOAP | 准确的 XML 序列化 |  |
iguana | universal serialization engine |  |
jios | JSON 序列化 |  |
libs11n |  |  |
protobuf |  |  |
rpnx-serial | 能（反）序列化如 std::map 、 std::vector 等类型的库 |  |
sweet_persist |  |  |
ThorsSerializer | JSON/YAML Input Output Streams |  |
yaml-cpp |  |  |
YAS | Yet Another Serialization |  |
二进制序列化
库名 | 简述 | 协议 | 配置手段
binn | 旨在紧凑，快速且易于使用的二进制序列化库，自身是同名格式的实现。 |  |
blobify | C++17 header-only, infers the serialized layout from the structure definition alone. | Boost License | CMake
bson-cxx | BSON 格式的 C++ 实现。 |  |
fast_ber | High-performance serialization using BER/DER encoding rules. Encoding layout is defined by ASN.1 schemas. Follows modern C++ practices, written in C++11. |  |
UBjsonCpp | 基于 C++14 的高性能 UBJson 读写库 |  |

排序

库名 | 简述 | 协议 | 配置手段
Cpp-sort | A collection of various sorting algorithms in a simple package. | MIT license |
Indiesort | Templated sort-wrapper function which allows use of std::sort (and other random-access sort methods) with non-random-access containers. It also increases the performance of sorting large types in random-access containers and arrays | zlib license |
Timsort | 模板化的稳定排序函数，对于逆序或半排序的数据，性能优于基于快速排序的算法，包括 std::sort 。 (MIT) |  |

系统

库名 | 简述 | 协议 | 配置手段
Infoware | C++ Library for pulling system and hardware information, without hitting the command line. | Creative Commons v1.0 License | CMake

终端

库名 | 简述 | 协议 | 配置手段
cli | A cross-platform header-only library for interactive command line interfaces in modern C++. | BSL-1.0 | make, cmake, nmake, vcpkg
cwidget |  |  |
replxx | readline 和 libedit 的替换品，支持 UTF-8 、语法高亮和提示。 |  |

测试

库名 | 简述 | 协议 | 配置手段
bandit | C++11 的对人类友好单元测试 |  |
Boost.Test |  |  |
Catch2 |  |  |
cppunit |  |  |
CUTE | C++ Unit Testing Easier (no reliance on static initialization for registration), integrated into Cevelop for TDD | MIT License |
doctest | 单元测试和 TDD 使用的最轻量的特性丰富的 C++ 单头文件测试框架 |  |
ELFspy | 杜绝假象和间谍的测试 - 仅 Linux |  |
Google Test |  |  |
lest | 现代的 C++11 原生的单文件唯头文件的轻量单元测试、 TDD 和 BDD 框架（包含 C++98 变体）。 |  |
liblittletest | 可移植，单个唯头文件的测试框架 |  |
xtd.tunit | Windows 、 macOS 、 Linux 、 iOS 和 Android 上的现代 C++17 单元测试库。官方网站 |  |

文本

编码
库名 | 简述 | 协议 | 配置手段
strsuite | A C++20 library to manage strings with different encodings | LGPL3.0 | CMake
uchardet | 实现猜字符串编码的功能,和python里的uchardet功能基本一样。 |  |
win-iconv | Linux 和 Mac 上的字符集编码转换库 iconv 的 Windows 实现，基于 Win32 字符集转换 API 实现。 |  |
Diff/Patch
库名 | 简述 | 协议 | 配置手段
diff_match_patch | Create and apply patches for strings (requires Qt) | Apache 2.0 License |
格式化
库名 | 简述 | 协议 | 配置手段
fmt | printf 不好用，ostream 也不好用，format 好用 |  |
语法分析
库名 | 简述 | 协议 | 配置手段
BNFlite | 仅单个头文件的轻量文法分析器库 |  |
PEGTL | 分析表达式文法的模板库 |  |
搜索
库名 | 简述 | 协议 | 配置手段
clucene |  |  |
Step | Ukkonen 的构建后缀树在线算法， Manber 的构建后缀数组算法。 |  |
xapian |  |  |
模板引擎
库名 | 简述 | 协议 | 配置手段
inja | 现代 C++ 的模板引擎 |  |
Jinja2C++ | Modern C++ implementation of Jinja2 templates |  |

版本控制

库名 | 简述 | 协议 | 配置手段
cpp-semver | 语义化版本号的 C++ 操作库。 |  |
LibGit2 | 版本控制系统 Git 的核心库。 |  |

视频

库名 | 简述 | 协议 | 配置手段
crystalhd |  |  |
gstreamermm |  |  |
libmatroska |  |  |
libVLC |  |  |
mjpegtools |  |  |

Web

库名 | 简述 | 协议 | 配置手段
Chromium Embedded |  |  |
cpp-jwt |  |  |
Drogon | A C++14/17 based HTTP web application framework running on Linux/macOS/Unix/Windows. |  |
libhttpserver |  |  |
libkcddb |  |  |
liblastfm |  |  |
libmusicbrainz5 |  |  |
libnavajo |  |  |
oatpp | 用于创建高性能网络服务的轻量零依赖框架 |  |
QtWebApp | Java Servlets 所启发的 HTTP(s) Server ，以 C++ 实现 |  |
Tufão |  |  |
uri-template | URI Templates expansion and reverse-matching for C++ | Apache License 2.0 | CMake
Wt |  |  |

参阅


本地化库

< cpp

本地环境设施包含字符分类和字符串校对、数值、货币及日期/时间格式化和分析，以及消息取得的国际化支持。本地环境设置控制流 I/O 、正则表达式库和 C++ 标准库的其他组件的行为。

本地环境

定义于头文件 <locale>
本地环境与平台
locale
 用以封装文化差异的多态刻面的集合
(类)
use_facet
 从本地环境获得一个刻面
(函数模板)
has_facet
 检查本地环境是否实现特定的刻面
(函数模板)
字符分类
isspace(std::locale)
 检查字符是否被本地环境分类为空白
(函数模板)
isblank(std::locale)
(C++11)
 检查字符是否被本地环境分类为空格字符
(函数模板)
iscntrl(std::locale)
 检查字符是否被本地环境分类为控制字符
(函数模板)
isupper(std::locale)
 检查字符是否被本地环境分类为大写
(函数模板)
islower(std::locale)
 检查字符是否被本地环境分类为小写
(函数模板)
isalpha(std::locale)
 检查字符是否被本地环境分类为字母
(函数模板)
isdigit(std::locale)
 检查字符是否被本地环境分类为数字
(函数模板)
ispunct(std::locale)
 检查字符是否被本地环境分类为标点
(函数模板)
isxdigit(std::locale)
 检查字符是否被本地环境分类为十六进制数字
(函数模板)
isalnum(std::locale)
 检查字符是否被本地环境分类为字母或数字
(函数模板)
isprint(std::locale)
 检查字符是否被本地环境分类为可打印字符
(函数模板)
isgraph(std::locale)
 检查字符是否被本地环境分类为图形字符
(函数模板)
字符转换
toupper(std::locale)
 用本地环境的 ctype 刻面将字符转换为大写
(函数模板)
tolower(std::locale)
 用本地环境的 ctype 刻面将字符转换为小写
(函数模板)
字符串与流转换
wstring_convert
(C++11)(C++17 中弃用)
 进行宽字符串和字节字符串之间的转换
(类模板)
wbuffer_convert
(C++11)(C++17 中弃用)
 进行字节流缓冲区和宽流缓冲区间的转换
(类模板)
平台类别基类
ctype_base
 定义字符分类类别
(类)
codecvt_base
 定义字符转换错误
(类)
messages_base
 定义消息目录类型
(类)
time_base
 定义日期格式常量
(类)
money_base
 定义货币格式化模式
(类)
平台类别
ctype
 定义字符分类表
(类模板)
ctype<char>
 std::ctype 对于 char 类型的特化
(类模板特化)
codecvt
 在字符编码间转换，包括 UTF-8、UTF-16、UTF-32
(类模板)
collate
 定义字典序比较和字符串的散列
(类模板)
messages
 实现从消息目录获取字符串
(类模板)
time_get
 从输入字符序列中解析时间/日期值到 std::tm 中
(类模板)
time_put
 格式化 std::tm 内容为字符序列以输出
(类模板)
num_get
 从输入字符序列中解析数字值
(类模板)
num_put
 格式化数值为字符序列以输出
(类模板)
numpunct
 定义数值标点规则
(类模板)
money_get
 从输入字符序列中解析并构造货币值
(类模板)
money_put
 格式化货币值为字符序列以输出
(类模板)
moneypunct
 定义 std::money_get 与 std::money_put 所用的货币格式解析器的参数
(类模板)
本地环境限定平台类别
ctype_byname
 表示系统提供的具名本地环境的 std::ctype
(类模板)
codecvt_byname
 表示系统提供的具名本地环境的 std::codecvt
(类模板)
messages_byname
 表示系统提供的具名本地环境的 std::messages
(类模板)
collate_byname
 表示系统提供的具名本地环境的 std::collate
(类模板)
time_get_byname
 表示系统提供的具名本地环境的 std::time_get
(类模板)
time_put_byname
 表示系统提供的具名本地环境的 std::time_put
(类模板)
numpunct_byname
 表示系统提供的具名本地环境的 std::numpunct
(类模板)
moneypunct_byname
 表示系统提供的具名本地环境的 std::moneypunct
(类模板)

独立于本地环境的 Unicode 转换平台

定义于头文件 <codecvt>
codecvt_utf8 (C++11)(C++17 中弃用) | 在 UTF-8 与 UCS2/UCS4 间转换 (类模板)
codecvt_utf16 (C++11)(C++17 中弃用) | 在 UTF-16 与 UCS2/UCS4 间转换 (类模板)
codecvt_utf8_utf16 (C++11)(C++17 中弃用) | 在 UTF-8 与 UTF-16 间转换 (类模板)
codecvt_mode (C++11)(C++17 中弃用) | 用于改变标准 codecvt 刻面行为的标签 (枚举)

C 库本地环境

定义于头文件 <clocale>
setlocale | 获取和设置当前 C 本地环境 (函数)
LC_ALLLC_COLLATELC_CTYPELC_MONETARYLC_NUMERICLC_TIME | std::setlocale 所用的本地环境类别 (宏常量)
localeconv | 查询当前本地环境的数值和货币格式化细节 (函数)
lconv | std::localeconv 所返回的格式化细节 (类)

参阅


LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME

< cpp‎ | locale
定义于头文件 <clocale>
#define LC_ALL /*implementation defined*/
#define LC_COLLATE /*implementation defined*/
#define LC_CTYPE /*implementation defined*/
#define LC_MONETARY /*implementation defined*/
#define LC_NUMERIC /*implementation defined*/
#define LC_TIME /*implementation defined*/

上面每个宏常量都展开成拥有相异值的整数常量表达式，适合用作 std::setlocale 的首个参数。

常量 | 解释
LC_ALL | 选择整个 C 本地环境
LC_COLLATE | 选择 C 本地环境的对照类别
LC_CTYPE | 选择 C 本地环境中的字符分类类别
LC_MONETARY | 选择 C 本地环境中的货币格式化类别
LC_NUMERIC | 选择 C 本地环境中的数值格式化类别
LC_TIME | 选择 C 本地环境中的时间格式化类别

<clocale> 中可以定义附加宏常量，名称以 LC_ 后随至少一个大写字母开始。例如， POSIX 规范要求 LC_MESSAGES （控制 std::perror 和 std::strerror ）， ISO/IEC 30112:2014 （ 2014 方案）额外定义 LC_IDENTIFICATION 、 LC_XLITERATE 、 LC_NAME 、 LC_ADDRESS 、 LC_TELEPHONE 、 LC_PAPER 、 LC_MEASUREMENT 和 LC_KEYBOARD ，它们均为 GNU C 库所支持（除了 LC_XLITERATE ）。

示例

#include <cstdio>
#include <clocale>
#include <ctime>
#include <cwchar>

int main()
{
    std::setlocale(LC_ALL, "en_US.UTF-8"); // C 本地环境将为启用 UTF-8 的英文
    std::setlocale(LC_NUMERIC, "de_DE.UTF-8");   // 小数点将为德文
    std::setlocale(LC_TIME, "ja_JP.UTF-8");      // 日期/时间格式化将为日文
    wchar_t str[100];
    std::time_t t = std::time(nullptr);
    std::wcsftime(str, 100, L"%A %c", std::localtime(&t));
    std::wprintf(L"Number: %.2f\nDate: %Ls\n", 3.14, str);
}

输出：

Number: 3,14
Date: 月曜日 2011年12月19日 18時04分40秒

参阅

setlocale | 获取和设置当前 C 本地环境 (函数)
locale | 用以封装文化差异的多态刻面的集合 (类)


std::codecvt

< cpp‎ | locale
定义于头文件 <locale>
template<

class InternT,
class ExternT,
class State

> class codecvt;

类模板 std::codecvt 封装字符串的转换，包括宽和多字节，从一种编码到另一种。通过 std::basic_fstream <CharT> 进行的所有 I/O 操作都使用流中感染的 std::codecvt<CharT, char, std::mbstate_t > 本地环境平面。

cpp/locale/codecvt base cpp/locale/locale/facet

继承图

标准库提供以下独立（本地环境无关）特化：

定义于头文件 <locale>
std::codecvt<char, char, std::mbstate_t > | 恒等转换
std::codecvt<char16_t, char, std::mbstate_t > | 在 UTF-16 和 UTF-8 间转换 (C++11 起)(C++20 中弃用)
std::codecvt<char16_t, char8_t, std::mbstate_t > | 在 UTF-16 和 UTF-8 间转换 (C++20 起)
std::codecvt<char32_t, char, std::mbstate_t > | 在 UTF-32 和 UTF-8 间转换 (C++11 起)(C++20 中弃用)
std::codecvt<char32_t, char8_t, std::mbstate_t > | 在 UTF-32 和 UTF-8 间转换 (C++20 起)
std::codecvt<wchar_t, char, std::mbstate_t > | 在系统原生宽和单字节窄字符集间转换

另外， C++ 程序中构造每个的 locale 对象实装上述特化其自身的（本地环境特定）版本。

成员类型

成员类型 | 定义
intern_type | InternT
extern_type | ExternT
state_type | State

成员函数

(构造函数) | 构造新的 codecvt 平面 (公开成员函数)
(析构函数) | 销毁 codecvt 平面 (受保护成员函数)
out | 调用 do_out (公开成员函数)
in | 调用 do_in (公开成员函数)
unshift | 调用 do_unshift (公开成员函数)
encoding | 调用 do_encoding (公开成员函数)
always_noconv | 调用 do_always_noconv (公开成员函数)
length | 调用 do_length (公开成员函数)
max_length | 调用 do_max_length (公开成员函数)

成员对象

成员名 | 类型
id [静态] | std::locale::id

受保护成员函数

do_out [虚] | 从 internT 转换字符串为 externT 转换字符串，如在写入文件时 (虚受保护成员函数)
do_in [虚] | 从 externT 转换字符串为 internT ，如在从文件读取时 (虚受保护成员函数)
do_unshift [虚] | 为不完整转换生成 externT 字符的终止字符序列 (虚受保护成员函数)
do_encoding [虚] | 返回产生一个 internT 字符所需的 externT 字符数，若此值为常数 (虚受保护成员函数)
do_always_noconv [虚] | 测试平面编码是否对所有合法值为恒等转换 (虚受保护成员函数)
do_length [虚] | 计算转换成给定的 internT 缓冲区会消耗的 externT 字符串长度 (虚受保护成员函数)
do_max_length [虚] | 返回能转换成单个 internT 字符的最大 externT 字符数 (虚受保护成员函数)

继承自 std::codecvt_base

成员类型 | 定义
enum result { ok, partial, error, noconv }; | 无作用域枚举类型
枚举常量 | 定义
ok | 完成转换而无错误
partial | 未转换所有源字符
error | 遇到非法字符
noconv | 不要求转换，输入与输出类型相同

示例

下例示例用在 codecvt<wchar_t, char, mbstate_t> 实现 UTF-8 转换的本地环境读取 UTF-8 环境，并用 std::codecvt 的标准特化转换 UTF-8 字符串为 UTF-16

#include <iostream>
#include <fstream>
#include <string>
#include <locale>
#include <iomanip>
#include <codecvt>

// 工具包装器，用于为 wstring/wbuffer 适配绑定到 locale 的平面
template<class Facet>
struct deletable_facet : Facet
{
    template<class ...Args>
    deletable_facet(Args&& ...args) : Facet(std::forward<Args>(args)...) {}
    ~deletable_facet() {}
};

int main()
{
    // UTF-8 窄多字节编码
    std::string data = reinterpret_cast<const char*>(+u8"z\u00df\u6c34\U0001f34c");
                       // 或 reinterpret_cast<const char*>(+u8"zß水🍌")
                       // 或 "\x7a\xc3\x9f\xe6\xb0\xb4\xf0\x9f\x8d\x8c"

    std::ofstream("text.txt") << data;

    // 使用系统提供的本地环境的 codecvt 平面
    std::wifstream fin("text.txt");
    // 从 wifstream 的读取将使用 codecvt<wchar_t, char, mbstate_t>
    // 此 locale 的 codecvt 从 UTF-8 转换到 UCS4 （在如 Linux 的系统上）
    fin.imbue(std::locale("en_US.UTF-8"));
    std::cout << "The UTF-8 file contains the following UCS4 code points: \n";
    for (wchar_t c; fin >> c; )
        std::cout << "U+" << std::hex << std::setw(4) << std::setfill('0') << c << '\n';

    // 使用标准（本地环境无关） codecvt 平面
    std::wstring_convert<
        deletable_facet<std::codecvt<char16_t, char, std::mbstate_t>>, char16_t> conv16;
    std::u16string str16 = conv16.from_bytes(data);

    std::cout << "The UTF-8 file contains the following UTF-16 code points: \n";
    for (char16_t c : str16)
        std::cout << "U+" << std::hex << std::setw(4) << std::setfill('0') << c << '\n';
}

输出：

The UTF-8 file contains the following UCS4 code points:
U+007a
U+00df
U+6c34
U+1f34c
The UTF-8 file contains the following UTF-16 code points:
U+007a
U+00df
U+6c34
U+d83c
U+df4c

参阅

字符转换 | 本地环境定义多字节 (UTF-8, GB18030) | UTF-8 | UTF-16
UTF-16 | mbrtoc16 / c16rtomb (有 C11 的 DR488) | codecvt<char16_t, char, mbstate_t> codecvt_utf8_utf16<char16_t> codecvt_utf8_utf16<char32_t> codecvt_utf8_utf16<wchar_t> | N/A
UCS2 | c16rtomb (无 C11 的 DR488) | codecvt_utf8<char16_t> codecvt_utf8<wchar_t>(Windows) | codecvt_utf16<char16_t> codecvt_utf16<wchar_t>(Windows)
UTF-32 | mbrtoc32 / c32rtomb | codecvt<char32_t, char, mbstate_t> codecvt_utf8<char32_t> codecvt_utf8<wchar_t>(非 Windows) | codecvt_utf16<char32_t> codecvt_utf16<wchar_t>(非 Windows)
系统宽 UTF-32(非 Windows) UCS2(Windows) | mbsrtowcs / wcsrtombs use_facet<codecvt <wchar_t, char, mbstate_t>>(locale) | 无 | 无
codecvt_base | 定义字符转换错误 (类模板)
codecvt_byname | 为具名本地环境构造 codecvt 平面 (类模板)
codecvt_utf8 (C++11)(C++17 中弃用) | 在 UTF-8 与 UCS2/UCS4 间转换 (类模板)
codecvt_utf16 (C++11)(C++17 中弃用) | 在 UTF-16 与 UCS2/UCS4 间转换 (类模板)
codecvt_utf8_utf16 (C++11)(C++17 中弃用) | 在 UTF-8 与 UTF-16 间转换 (类模板)


std::codecvt<InternT,ExternT,State>::always_noconv, do_always_noconv

< cpp‎ | locale‎ | codecvt
定义于头文件 <locale> |
 | (1)
public: bool always_noconv() const throw(); |  | (C++11 前)
public: bool always_noconv() const noexcept; |  | (C++11 起)
 | (2)
protected: virtual bool do_always_noconv() const throw(); |  | (C++11 前)
protected: virtual bool do_always_noconv() const noexcept; |  | (C++11 起)
1) 公开成员函数，调用最终导出类的成员函数 do_always_noconv 。
2) 若 do_in() 和 do_out() 对于所有合法输入都返回 std::codecvt_base::noconv 则返回 true 。

返回值

若此转换平面不进行转换则为 true ，否则为 false 。

不转换特化 std::codecvt <char, char, std::mbstate_t > 返回 true 。

注意

此函数可用于例如 std::basic_filebuf::underflow 和 std::basic_filebuf::overflow 的实现，以使用大量元素复制取代调用 std::codecvt::in 或 std::codecvt::out ，若已知 std::basic_filebuf 中感染的本地环境不进行任何转换。

示例

#include <locale>
#include <iostream>

int main()
{
    std::cout << "The non-converting char<->char codecvt::always_noconv() returns "
              << std::boolalpha
              << std::use_facet<std::codecvt<char, char, std::mbstate_t>>(
                    std::locale()
                 ).always_noconv() << "\n"
              << "while wchar_t<->char codecvt::always_noconv() returns "
              << std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(
                    std::locale()
                 ).always_noconv() << "\n";

}

输出：

The non-converting char<->char codecvt::always_noconv() returns true
while wchar_t<->char codecvt::always_noconv() returns false


std::codecvt<InternT,ExternT,State>::codecvt

< cpp‎ | locale‎ | codecvt

定义于头文件 <locale>
explicit codecvt( std::size_t refs = 0 );

创建 std::codecvt 平面并转发引用计数 refs 到基类构造函数 locale::facet::facet() 。

参数

refs - 开始的引用计数


std::codecvt<InternT,ExternT,State>::encoding, do_encoding

< cpp‎ | locale‎ | codecvt
定义于头文件 <locale> |
 | (1)
public: int encoding() const throw(); |  | (C++11 前)
public: int encoding() const noexcept; |  | (C++11 起)
 | (2)
protected: virtual int do_encoding() const throw(); |  | (C++11 前)
protected: virtual int do_encoding() const noexcept; |  | (C++11 起)
1) 公开成员函数，调用最终导出类的成员函数 do_encoding 。
2) 若此 codecvt 平面所表示的编码映射每个内部字符为相同的常数个外部字符，则返回该常数。若编码为变长（如 UTF-8 或 UTF-16 ），则返回 ​0​ 。若编码依赖平台，则返回 -1 。

返回值

对应一个 internT 字符的准确 externT 字符数。若该数变化则为 ​0​ ，若编码依赖平台则为 -1 。

不转换特化 std::codecvt <char, char, std::mbstate_t > 返回 1 。

示例

#include <locale>
#include <iostream>

int main()
{
    std::cout << "en_US.utf8 is a variable-length encoding, encoding() returns "
              << std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(
                    std::locale("en_US.utf8")
              ).encoding() << '\n';

    std::cout << "zh_CN.gb18030 is also variable-length, encoding() == "
              << std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(
                    std::locale("zh_CN.gb18030")
              ).encoding() << '\n';

    std::cout << "ru_RU.koi8r is a single-byte encoding encoding() == "
              << std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(
                    std::locale("ru_RU.koi8r")
              ).encoding() << '\n';
}

输出：

en_US.utf8 is a variable-length encoding, encoding() returns 0
zh_CN.gb18030 is also variable-length, encoding() == 0
ru_RU.koi8r is a single-byte encoding encoding() == 1

参阅

MB_CUR_MAX | 当前 C 本地环境中多字节字符的最大字节数 (宏变量)
do_max_length [虚] | 返回能转换成单个 internT 字符的最大 externT 字符数 (虚受保护成员函数)


std::codecvt<InternT,ExternT,State>::in, std::codecvt<InternT,ExternT,State>::do_in

< cpp‎ | locale‎ | codecvt
定义于头文件 <locale> |
public: result in( StateT& state, const ExternT* from, const ExternT* from_end, const ExternT*& from_next, InternT* to, InternT* to_end, InternT*& to_next ) const; | (1)
protected: virtual result do_in( StateT& state, const ExternT* from, const ExternT* from_end, const ExternT*& from_next, InternT* to, InternT* to_end, InternT*& to_next ) const; | (2)
1) 公开成员函数，调用最终导出类的成员函数 do_in 。
2) 若此 codecvt 平面定义一个转换，则翻译来自源范围 [from, from_end) 的外部字符为内部字符，将结果置始于 to 的后继位置。不转换多于 from_end - from 个外部字符，不写入多于 to_end - to 个内部字符。令 from_next 和 to_next 指向最后成功转换元素的后一位置。

若此 codecvt 平面不定义转换，则不转换字符。设置 to_next 等于 to ，不更改 state ，并返回 std::codecvt_base::noconv 。

返回值

std::codecvt_base::result 类型值，按以下方式指示成功状况：

ok | 转换完成
partial | 输出缓冲区的中空间不足，或源缓冲的未期待结尾
error | 遇到无法转换的字符
noconv | 此平面为非转换，不写入输出

非转换特化 std::codecvt <char, char, std::mbstate_t > 始终返回 std::codecvt_base::noconv 。

注意

要求 from <= from_end && to <= to_end 且 state 要么表示初始迁移状态，要么以转换序列中前趋的字符获得。

state 上的效果是有意未指定的。标准平面中，它用于维护像是调用 std::mbsrtowcs 时的状态，从而被更新为反映最后被处理外部字符后的转换状态，但是用户定义平面可以自由地用它维护任何其他状态，例如计量遇到的特殊字符数。

示例

#include <iostream>
#include <string>
#include <locale>

int main()
{
    std::locale::global(std::locale("en_US.utf8"));
    auto& f = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(std::locale());
    std::string external = u8"z\u00df\u6c34\U0001d10b"; // 或 u8"zß水𝄋"
                          // 或 "\x7a\xc3\x9f\xe6\xb0\xb4\xf0\x9d\x84\x8b";

    // 注意 wstring_convert 能进行下列内容
    std::mbstate_t mb = std::mbstate_t(); // 初始迁移状态
    std::wstring internal(external.size(), '\0');
    const char* from_next;
    wchar_t* to_next;
    f.in(mb, &external[0], &external[external.size()], from_next,
             &internal[0], &internal[internal.size()], to_next);
    // 为简略跳过错误检查
    internal.resize(to_next - &internal[0]);

    std::wcout << L"The string in wide encoding: " << internal << '\n';
}

输出：

The string in wide encoding: zß水𝄋

参阅

underflow [虚] | 从关联文件读取 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)
from_bytes | 转换字节字符串为宽字符串 (std::wstring_convert<Codecvt,Elem,Wide_alloc,Byte_alloc> 的公开成员函数)
mbsrtowcs | 给定状态，转换窄多字节字符串到宽字符串 (函数)
do_out [虚] | 从 internT 转换字符串为 externT 转换字符串，如在写入文件时 (虚受保护成员函数)


std::codecvt<InternT,ExternT,State>::length, do_length

< cpp‎ | locale‎ | codecvt
定义于头文件 <locale> |
public: int length( StateT& state, const ExternT* from, const ExternT* from_end, std::size_t max ) const; | (1)
protected: virtual int do_length( StateT& state, const ExternT* from, const ExternT* from_end, std::size_t max ) const; | (2)
1) 公开成员函数，调用最终导出类的成员函数 do_length 。
2) 给定初始转换状态 state ，试图转换来自 [from, from_end) 所定义的字符数组的 externT 字符，为至多 max 个 internT 字符，并返回这种转换会消耗的 externT 字符数。如同以对某虚构的 [to, to+max) 输出缓冲区执行 do_in(state, from, from_end, from, to, to+max, to) 一般修改 state 。

返回值

假如以 do_in() 转换直至消耗所有 from_end-from 个字符，或产生 max 个 internT 字符，或出现转换错误，则会消耗的 externT 字符数。

非转换特化 std::codecvt <char, char, std::mbstate_t > 返回 std::min (max, from_end-from) 。

示例

#include <locale>
#include <string>
#include <iostream>

int main()
{
    // 窄多字节编码
    std::string s = "z\u00df\u6c34\U0001d10b"; // 或 u8"zß水𝄋"
                      // 或 "\x7a\xc3\x9f\xe6\xb0\xb4\xf0\x9d\x84\x8b";
    std::mbstate_t mb = std::mbstate_t();
    std::cout << "Only the first " <<
              std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(
                    std::locale("en_US.utf8")
              ).length(mb, &s[0], &s[s.size()], 2)
              << " bytes out of " << s.size() << " would be consumed "
                 " to produce the first 2 characters\n";
}

输出：

Only the first 3 bytes out of 10 would be consumed to produce the first 2 characters

参阅

do_in
[虚]
 从 externT 转换字符串为 internT ，如在从文件读取时
(虚受保护成员函数)


std::codecvt<InternT,ExternT,State>::max_length, do_max_length

< cpp‎ | locale‎ | codecvt
定义于头文件 <locale> |
 | (1)
public: int max_length() const throw(); |  | (C++11 前)
public: int max_length() const noexcept; |  | (C++11 起)
 | (2)
protected: virtual int do_max_length() const throw(); |  | (C++11 前)
protected: virtual int do_max_length() const noexcept; |  | (C++11 起)
1) 公开成员函数，调用最终派生类的成员函数 do_max_length 。
2) 返回对于任何合法范围 [from, from_end) 和任何 state 合法 ， do_length(state, from, from_end, 1) 所能返回的最大值。

返回值

若以 in() 转换生成一个 InternT 字符，能消耗的最大 ExternT 字符数。

不转换特化 std::codecvt <char, char, std::mbstate_t > 返回 1 。

注意

若编码依赖状态（ encoding() == -1 ），则可能消耗多于 max_length() 个外部字符生成一个内部字符。

示例

#include <locale>
#include <iostream>
#include <codecvt>

int main()
{
    std::cout << "In codecvt_utf8, the longest multibyte character is "
              << std::codecvt_utf8<wchar_t>().max_length() << " bytes long\n";

    std::cout << "In header-consuming codecvt_utf8, the longest multibyte character is "
              << std::codecvt_utf8<wchar_t,
                                   0x10ffff,
                                   std::consume_header>().max_length() << " bytes long\n";

    std::cout << "In this system's en_US.utf8, the longest multibyte character is "
              << std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(
                    std::locale("en_US.utf8")
              ).max_length() << " bytes long\n";

    std::cout << "In this system's zh_CN.gb18030, the longest multibyte character is "
              << std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(
                    std::locale("zh_CN.gb18030")
              ).max_length() << " bytes long\n";
}

输出：

In codecvt_utf8, the longest multibyte character is 4 bytes long
In header-consuming codecvt_utf8, the longest multibyte character is 7 bytes long
In this system's en_US.utf8, the longest multibyte character is 6 bytes long
In this system's zh_CN.gb18030, the longest multibyte character is 4 bytes long

参阅

MB_CUR_MAX | 当前 C 本地环境中多字节字符的最大字节数 (宏变量)
do_encoding [虚] | 返回产生一个 internT 字符所需的 externT 字符数，若此值为常数 (虚受保护成员函数)


std::codecvt<InternT,ExternT,State>::out, std::codecvt<InternT,ExternT,State>::do_out

< cpp‎ | locale‎ | codecvt
定义于头文件 <locale> |
public: result out( StateT& state, const InternT* from, const InternT* from_end, const InternT*& from_next, ExternT* to, ExternT* to_end, ExternT*& to_next ) const; | (1)
protected: virtual result do_out( StateT& state, const InternT* from, const InternT* from_end, const InternT*& from_next, ExternT* to, ExternT* to_end, ExternT*& to_next ) const; | (2)
1) 公开成员函数，调用最终导出类的成员函数 do_out 。
2) 若此 codecvt 平面定义一个转换，则翻译来自源范围 [from, from_end) 的内部字符为外部字符，并将结果置于始于 to 的相继位置。不转换多于 from_end - from 个内部字符，不写入多于 to_end - to 个外部字符。令 from_next 和 to_next 指向最后成功转换元素的后一位置。

若此 codecvt 平面不定义转换，则不转换字符。设置 to_next 等于 to ，不更改 state ，并返回 std::codecvt_base::noconv 。

返回值

std::codecvt_base::result 类型值，按以下方式指示成功状况：

ok | 转换完成
partial | 输出缓冲区的中空间不足，或源缓冲的未期待结尾
error | 遇到无法转换的字符
noconv | 此平面为非转换，不写入输出

非转换特化 std::codecvt <char, char, std::mbstate_t > 始终返回 std::codecvt_base::noconv 。

注意

要求 from <= from_end && to <= to_end 且 state 要么表示初始迁移状态，要么以转换序列中前趋的字符获得。

尽管 codecvt 支持 N:M 转换（例如 UTF-16 到 UTF-8 ，其中可能需要二个初始字符决定输出的外部字符）， std::basic_filebuf 只能使用定义 1:N codecvt 转换的平面，即它在写入文件时必须能够一次处理一个内部字符。

进行 N:M 转换时，此函数可能在消耗所有源字符后（ from_next == from_end ）返回 std::codecvt_base::partial 。这表示需要其他内部字符完成转换（例如在转换 UTF-16 到 UTF-8 时，若源缓冲区中的末字符是高位代理）。

state 上的效果是有意未指定的。标准平面中，它用于维护像是调用 std::wcsrtombs 时的状态，从而被更新为反映最后被处理外部字符后的转换状态，但是用户定义平面可以自由地用它维护任何其他状态，例如计量遇到的特殊字符数。

示例

#include <iostream>
#include <string>
#include <locale>

int main()
{
    std::locale::global(std::locale("en_US.utf8"));
    auto& f = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(std::locale());
    std::wstring internal = L"z\u00df\u6c34\U0001f34c"; // L"zß水🍌"

    // 注意 wstring_convert 能做下列内容
    std::mbstate_t mb{}; // 初始迁移状态
    std::string external(internal.size() * f.max_length(), '\0');
    const wchar_t* from_next;
    char* to_next;
    f.out(mb, &internal[0], &internal[internal.size()], from_next,
              &external[0], &external[external.size()], to_next);
    // 为简洁起见跳过错误检查
    external.resize(to_next - &external[0]);

    std::cout << "The string in narrow multibyte encoding: " << external << '\n';
}

输出：

The string in narrow multibyte encoding: zß水🍌

参阅

overflow [虚] | 从放置区写字符到关联的文件 (std::basic_filebuf<CharT,Traits> 的虚受保护成员函数)
to_bytes | 转换宽字符串为字符串 (std::wstring_convert<Codecvt,Elem,Wide_alloc,Byte_alloc> 的公开成员函数)
wcsrtombs | 给定状态，转换宽字符串为窄多字节字符串 (函数)
do_in [虚] | 从 externT 转换字符串为 internT ，如在从文件读取时 (虚受保护成员函数)


std::codecvt<InternT,ExternT,State>::unshift, do_unshift

< cpp‎ | locale‎ | codecvt
定义于头文件 <locale> |
public: result unshift( StateT& state, ExternT* to, ExternT* to_end, ExternT*& to_next) const; | (1)
protected: virtual result do_unshift( StateT& state, ExternT* to, ExternT* to_end, ExternT*& to_next) const; | (2)
1) 公开成员函数，调用最终导出类的成员函数 do_unshift 。
2) 若此 codecvt 所表示的编码依赖状态，而 state 表示的转换状态不是初始迁移状态，则写入返回初始迁移状态所需的字符。字符被写入首元素为 to 所指向的字符数组。不写入多于 to_end-to 个字符。更新参数 to_next 以指向最后写入字符的后一位置。

返回值

std::codecvt_base::result 类型值，指示成功状况如下：

ok | 已写入所有所需字符。 state 现在表示初始迁移状态
partial | 输出缓冲区中空间不足。 to_next == to_end
error | 出现未指明的错误
noconv | 编码不依赖状态，不需要终止序列

非转换特化 std::codecvt <char, char, std::mbstate_t > 始终返回 std::codecvt_base::noconv 。

注意

此函数为 std::basic_filebuf::close() 所调用，并在终止化依赖状态的多字节序列的情形中被调用。

示例

本节未完成
原因：暂无示例

参阅

wcrtomb | 给定状态，转换宽字符到其多字节表示 (函数)
do_out [虚] | 从 internT 转换字符串为 externT 转换字符串，如在写入文件时 (虚受保护成员函数)


std::codecvt<InternT,ExternT,State>::~codecvt

< cpp‎ | locale‎ | codecvt

定义于头文件 <locale>
protected: ~codecvt();

析构 std::codecvt 平面。此析构函数为受保护且为虚（由于基类析构函数为虚）。 std::codecvt 类型对象，同大多数平面，只能在最后一个实装此平面的 std::locale 离开作用域时，或若用户定义导出自 std::codecvt 并实现公开构造函数，才会被销毁。

示例

#include <iostream>
#include <locale>
struct Destructible_codecvt : public std::codecvt<wchar_t, char, std::mbstate_t>
{
    Destructible_codecvt(std::size_t refs = 0) : codecvt(refs) {}
    // 注意：隐式析构函数为公开
};
int main()
{
    Destructible_codecvt dc;
    // std::codecvt<wchar_t> c;  // 编译错误：受保护析构函数
}


std::codecvt_base

< cpp‎ | locale
定义于头文件 <locale>
class codecvt_base;

类 std::codecvt_base 提供 std::codecvt 平面所继承并使用的转换状态常量。

成员类型

成员类型 | 定义
enum result { ok, partial, error, noconv }; | 无作用域枚举类型
枚举常量 | 定义
ok | 完成转换而无错误
partial | 未转换所有源字符
error | 遇到非法字符
noconv | 不要求转换，输入与输出类型相同

注意

值 std::codecvt_base::partial 用于指示目标范围太短，无以接受转换结果，或输入在可为合法多字节字符的中部被截断。

参阅

codecvt
 在字符编码间转换，包括 UTF-8、UTF-16、UTF-32
(类模板)


std::codecvt_byname

< cpp‎ | locale
定义于头文件 <locale>
template< class InternT, class ExternT, class State >
class codecvt_byname : public std::codecvt <InternT, ExternT, State>;

std::codecvt_byname 是 std::codecvt 平面，封装于构造时指定的 locale 的多字节/宽字符转换规则。

标准库提供以下独立特化：

定义于头文件 <locale>
std::codecvt_byname<char, char, std::mbstate_t > | 恒等转换
std::codecvt_byname<char16_t, char, std::mbstate_t > | 在 UTF-16 和 UTF-8 间转换 (C++11 起)(C++20 中弃用)
std::codecvt_byname<char16_t, char8_t, std::mbstate_t > | 在 UTF-16 和 UTF-8 间转换 (C++20 起)
std::codecvt_byname<char32_t, char, std::mbstate_t > | 在 UTF-32 和 UTF-8 间转换 (C++11 起)(C++20 中弃用)
std::codecvt_byname<char32_t, char8_t, std::mbstate_t > | 在 UTF-32 和 UTF-8 间转换 (C++20 起)
std::codecvt_byname<wchar_t, char, std::mbstate_t > | 在系统原生宽和单字节窄字符集间转换

成员函数

(构造函数) | 构造新的 codecvt_byname 平面 (公开成员函数)
(析构函数) | 析构 codecvt_byname 平面 (受保护成员函数)

std::codecvt_byname::codecvt_byname

explicit codecvt_byname( const char* name, std::size_t refs = 0 ); |
explicit codecvt_byname( const std::string & name, std::size_t refs = 0 ); | (C++11 起)

为名为 name 的本地环境构造新的 std::codecvt_byname 平面。

refs 用于资源管理：在销毁最后一个保有平面的 std::locale 对象时，若 refs == 0 ，则实现销毁平面对象。否则，不销毁对象。

参数

name | - | 本地环境的名称
refs | - | 链接到该平面的引用数

std::codecvt_byname::~codecvt_byname

protected:
~codecvt_byname();

销毁平面。

继承自 std::codecvt

成员类型

成员类型 | 定义
intern_type | internT
extern_type | externT
state_type | stateT

成员对象

成员名 | 类型
id [静态] | std::locale::id

成员函数

out | 调用 do_out (std::codecvt<InternT,ExternT,State> 的公开成员函数)
in | 调用 do_in (std::codecvt<InternT,ExternT,State> 的公开成员函数)
unshift | 调用 do_unshift (std::codecvt<InternT,ExternT,State> 的公开成员函数)
encoding | 调用 do_encoding (std::codecvt<InternT,ExternT,State> 的公开成员函数)
always_noconv | 调用 do_always_noconv (std::codecvt<InternT,ExternT,State> 的公开成员函数)
length | 调用 do_length (std::codecvt<InternT,ExternT,State> 的公开成员函数)
max_length | 调用 do_max_length (std::codecvt<InternT,ExternT,State> 的公开成员函数)

受保护成员函数

do_out [虚] | 从 internT 转换字符串为 externT 转换字符串，如在写入文件时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_in [虚] | 从 externT 转换字符串为 internT ，如在从文件读取时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_unshift [虚] | 为不完整转换生成 externT 字符的终止字符序列 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_encoding [虚] | 返回产生一个 internT 字符所需的 externT 字符数，若此值为常数 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_always_noconv [虚] | 测试平面编码是否对所有合法值为恒等转换 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_length [虚] | 计算转换成给定的 internT 缓冲区会消耗的 externT 字符串长度 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_max_length [虚] | 返回能转换成单个 internT 字符的最大 externT 字符数 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)

继承自 std::codecvt_base

成员类型 | 定义
enum result { ok, partial, error, noconv }; | 无作用域枚举类型
枚举常量 | 定义
ok | 完成转换而无错误
partial | 未转换所有源字符
error | 遇到非法字符
noconv | 不要求转换，输入与输出类型相同

示例

此示例演示用来自具备 GB18030 的 locale 的本地环境读取 GB18030 编码的文件

#include <iostream>
#include <fstream>
#include <string>
#include <locale>

int main()
{
    // GB18030 窄多字节编码
    std::ofstream("text.txt") << "\x7a"              // 字母 'z' ， U+007a
                                 "\x81\x30\x89\x38"  // 字母 'ß' ， U+00df
                                 "\xcb\xae"          // CJK 表意字符 '水' ， U+6c34
                                 "\x94\x32\xbc\x35"; // 音符 '𝄋' (segno) ， U+1d10b
    std::wifstream fin("text.txt");
    fin.imbue(std::locale(fin.getloc(),
              new std::codecvt_byname<wchar_t, char, std::mbstate_t>("zh_CN.gb18030")));
    for (wchar_t c; fin.get(c); )
        std::cout << std::hex << std::showbase << c << '\n';
}

输出：

0x7a
0xdf
0x6c34
0x1d10b

参阅

codecvt
 在字符编码间转换，包括 UTF-8、UTF-16、UTF-32
(类模板)


std::codecvt_mode

< cpp‎ | locale
定义于头文件 <codecvt> |
enum codecvt_mode { consume_header = 4, generate_header = 2, little_endian = 1 }; | (C++11 起) (C++17 中弃用)

平面 std::codecvt_utf8 、 std::codecvt_utf16 和 std::codecvt_utf8_utf16 接受可选的 std::codecvt_mode 类型值为模板实参，这会指定 unicode 字符串转换的可选特性。

常量

定义于头文件 <locale>
值 | 含义
little_endian | 假设输入是小端序（仅应用于 UTF-16 ，默认为大端序）
consume_header | 若输入序列的开始存在字节序标记，则消耗它，而且（在 UTF-16 的情况下）依赖于为解码剩下输入而指定的字节序
generate_header | 在输出序列的开始输出字节序标记

受到辨认的字节序标记为：

0xfe 0xff | UTF-16 大端
0xff 0xfe | UTF-16 小端
0xef 0xbb 0xbf | UTF-8 （端序无影响）

若在读以字节序标记开始的文件时未指定 std::consume_header ，则将 Unicode 字符 U+FEFF （零宽无中断空格）读作字符串内容的首字符。

示例

下列示例演示消耗 UTF-8 BOM

#include <fstream>
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>

int main()
{
    // 带 BOM 的 UTF-8 数据
    std::ofstream("text.txt") << u8"\ufeffz\u6c34\U0001d10b";
    // 读 UTF8 文件，跳过 BOM
    std::wifstream fin("text.txt");
    fin.imbue(std::locale(fin.getloc(),
                          new std::codecvt_utf8<wchar_t, 0x10ffff, std::consume_header>));
    for (wchar_t c; fin.get(c); )
        std::cout << std::hex << std::showbase << c << '\n';
}

输出：

0x7a
0x6c34
0x1d10b

参阅

codecvt | 在字符编码间转换，包括 UTF-8、UTF-16、UTF-32 (类模板)
codecvt_utf8 (C++11)(C++17 中弃用) | 在 UTF-8 与 UCS2/UCS4 间转换 (类模板)
codecvt_utf16 (C++11)(C++17 中弃用) | 在 UTF-16 与 UCS2/UCS4 间转换 (类模板)
codecvt_utf8_utf16 (C++11)(C++17 中弃用) | 在 UTF-8 与 UTF-16 间转换 (类模板)


std::codecvt_utf16

< cpp‎ | locale
定义于头文件 <codecvt> |
template< class Elem, unsigned long Maxcode = 0x10ffff, std::codecvt_mode Mode = ( std::codecvt_mode )0 > class codecvt_utf16 : public std::codecvt <Elem, char, std::mbstate_t >; | (C++11 起) (C++17 中弃用)

std::codecvt_utf16 是一个 std::codecvt 平面，封装 UTF-16 编码字节串和 UCS2 或 UTF-32 字符串（取决于 Elem 的类型）之间的转换。此 codecvt 平面能用于以二进制模式读或写 UTF-16 文件。

模板形参

Elem | - | char16_t 、 char32_t 或 wchar_t 之一
Maxcode | - | 此平面将读或写而不出错的 Elem 最大值
Mode | - | std::codecvt_mode 类型常量

成员函数

(构造函数) | 构造新的 codecvt_utf16 平面 (公开成员函数)
(析构函数) | 销毁 codecvt_utf16 平面 (公开成员函数)

std::codecvt_utf16::codecvt_utf16

explicit codecvt_utf16( std::size_t refs = 0 );

构造新的 std::codecvt_utf16 平面，传递初始引用计数 refs 到基类。

参数

refs - 链接到该平面的引用数

std::codecvt_utf16::~codecvt_utf16

~codecvt_utf16();

销毁平面。不同于本地环境所管理的平面，此平面的析构函数为公开。

继承自 std::codecvt

成员类型

成员类型 | 定义
intern_type | internT
extern_type | externT
state_type | stateT

成员对象

成员名 | 类型
id [静态] | std::locale::id

成员函数

out | 调用 do_out (std::codecvt<InternT,ExternT,State> 的公开成员函数)
in | 调用 do_in (std::codecvt<InternT,ExternT,State> 的公开成员函数)
unshift | 调用 do_unshift (std::codecvt<InternT,ExternT,State> 的公开成员函数)
encoding | 调用 do_encoding (std::codecvt<InternT,ExternT,State> 的公开成员函数)
always_noconv | 调用 do_always_noconv (std::codecvt<InternT,ExternT,State> 的公开成员函数)
length | 调用 do_length (std::codecvt<InternT,ExternT,State> 的公开成员函数)
max_length | 调用 do_max_length (std::codecvt<InternT,ExternT,State> 的公开成员函数)

受保护成员函数

do_out [虚] | 从 internT 转换字符串为 externT 转换字符串，如在写入文件时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_in [虚] | 从 externT 转换字符串为 internT ，如在从文件读取时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_unshift [虚] | 为不完整转换生成 externT 字符的终止字符序列 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_encoding [虚] | 返回产生一个 internT 字符所需的 externT 字符数，若此值为常数 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_always_noconv [虚] | 测试平面编码是否对所有合法值为恒等转换 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_length [虚] | 计算转换成给定的 internT 缓冲区会消耗的 externT 字符串长度 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_max_length [虚] | 返回能转换成单个 internT 字符的最大 externT 字符数 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)

继承自 std::codecvt_base

成员类型 | 定义
enum result { ok, partial, error, noconv }; | 无作用域枚举类型
枚举常量 | 定义
ok | 完成转换而无错误
partial | 未转换所有源字符
error | 遇到非法字符
noconv | 不要求转换，输入与输出类型相同

注意

尽管标准要求此版面在 Elem 为 16 位时用 UCS2 工作，某些实现用 UTF-16 代替，使得它成为非转换平面。用语 "UCS2" 已被弃用并被移除 Unicode 标准。

示例

下列示例演示拥有 32 位 wchar_t 系统上的 UTF-16le 文件解码。在有 16 位 wchar_t 的系统上，解码第三字符将失败，因为 std::codecvt_utf16<char16_t> 产生 UCS2 而非 UTF-16 。

#include <fstream>
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>

void prepare_file()
{
    // UTF-16le 数据（若宿主系统为小端）
    char16_t utf16le[4] ={0x007a,          // 拉丁小写字母 'z' U+007a
                          0x6c34,          // CJK 表意符号 '水' U+6c34
                          0xd834, 0xdd0b}; // 音符 segno U+1d10b
    // 存储于文件
    std::ofstream fout("text.txt");
    fout.write( reinterpret_cast<char*>(utf16le), sizeof utf16le);
}

int main()
{
    prepare_file();
    // 作为字节流打开
    std::wifstream fin("text.txt", std::ios::binary);
    // 应用平面
    fin.imbue(std::locale(fin.getloc(),
       new std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>));

    for (wchar_t c; fin.get(c); )
            std::cout << std::showbase << std::hex << c << '\n';
}

输出：

0x7a
0x6c34
0x1d10b

参阅

字符转换 | 本地环境定义多字节 (UTF-8, GB18030) | UTF-8 | UTF-16
UTF-16 | mbrtoc16 / c16rtomb (有 C11 的 DR488) | codecvt<char16_t, char, mbstate_t> codecvt_utf8_utf16<char16_t> codecvt_utf8_utf16<char32_t> codecvt_utf8_utf16<wchar_t> | N/A
UCS2 | c16rtomb (无 C11 的 DR488) | codecvt_utf8<char16_t> codecvt_utf8<wchar_t>(Windows) | codecvt_utf16<char16_t> codecvt_utf16<wchar_t>(Windows)
UTF-32 | mbrtoc32 / c32rtomb | codecvt<char32_t, char, mbstate_t> codecvt_utf8<char32_t> codecvt_utf8<wchar_t>(非 Windows) | codecvt_utf16<char32_t> codecvt_utf16<wchar_t>(非 Windows)
系统宽 UTF-32(非 Windows) UCS2(Windows) | mbsrtowcs / wcsrtombs use_facet<codecvt <wchar_t, char, mbstate_t>>(locale) | 无 | 无
codecvt | 在字符编码间转换，包括 UTF-8、UTF-16、UTF-32 (类模板)
codecvt_mode (C++11)(C++17 中弃用) | 用于改变标准 codecvt 刻面行为的标签 (枚举)
codecvt_utf8 (C++11)(C++17 中弃用) | 在 UTF-8 与 UCS2/UCS4 间转换 (类模板)
codecvt_utf8_utf16 (C++11)(C++17 中弃用) | 在 UTF-8 与 UTF-16 间转换 (类模板)


std::codecvt_utf8

< cpp‎ | locale
定义于头文件 <codecvt> |
template< class Elem, unsigned long Maxcode = 0x10ffff, std::codecvt_mode Mode = ( std::codecvt_mode )0 > class codecvt_utf8 : public std::codecvt <Elem, char, std::mbstate_t >; | (C++11 起) (C++17 中弃用)

std::codecvt_utf8 是封装 UTF-8 编码字符串和 UCS2 或 UTF-32 字符串（取决于 Elem 类型）间转换的 std::codecvt 平面。此 codecvt 能用于读写文本和二进制的 UTF-8 文件。

模板形参

Elem | - | char16_t 、 char32_t 或 wchar_t 之一
Maxcode | - | 此平面将读写而无错误的最大 Elem 值
Mode | - | std::codecvt_mode 类型常量

成员函数

(构造函数) | 构造新的 codecvt_utf8 平面 (公开成员函数)
(析构函数) | 销毁 codecvt_utf8 平面 (公开成员函数)

std::codecvt_utf8::codecvt_utf8

explicit codecvt_utf8( std::size_t refs = 0 );

构造新的 std::codecvt_utf8 平面，传递初始引用计数 refs 给基类。

参数

refs - 链接到该平面的引用数

std::codecvt_utf8::~codecvt_utf8

~codecvt_utf8();

销毁平面。不同于 locale 管理的平面，此平面的析构函数是公开的。

继承自 std::codecvt

成员类型

成员类型 | 定义
intern_type | internT
extern_type | externT
state_type | stateT

成员对象

成员名 | 类型
id [静态] | std::locale::id

成员函数

out | 调用 do_out (std::codecvt<InternT,ExternT,State> 的公开成员函数)
in | 调用 do_in (std::codecvt<InternT,ExternT,State> 的公开成员函数)
unshift | 调用 do_unshift (std::codecvt<InternT,ExternT,State> 的公开成员函数)
encoding | 调用 do_encoding (std::codecvt<InternT,ExternT,State> 的公开成员函数)
always_noconv | 调用 do_always_noconv (std::codecvt<InternT,ExternT,State> 的公开成员函数)
length | 调用 do_length (std::codecvt<InternT,ExternT,State> 的公开成员函数)
max_length | 调用 do_max_length (std::codecvt<InternT,ExternT,State> 的公开成员函数)

受保护成员函数

do_out [虚] | 从 internT 转换字符串为 externT 转换字符串，如在写入文件时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_in [虚] | 从 externT 转换字符串为 internT ，如在从文件读取时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_unshift [虚] | 为不完整转换生成 externT 字符的终止字符序列 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_encoding [虚] | 返回产生一个 internT 字符所需的 externT 字符数，若此值为常数 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_always_noconv [虚] | 测试平面编码是否对所有合法值为恒等转换 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_length [虚] | 计算转换成给定的 internT 缓冲区会消耗的 externT 字符串长度 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_max_length [虚] | 返回能转换成单个 internT 字符的最大 externT 字符数 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)

继承自 std::codecvt_base

成员类型 | 定义
enum result { ok, partial, error, noconv }; | 无作用域枚举类型
枚举常量 | 定义
ok | 完成转换而无错误
partial | 未转换所有源字符
error | 遇到非法字符
noconv | 不要求转换，输入与输出类型相同

注意

尽管标准要求此版面在 Elem 为 16 位时用 UCS2 工作，某些实现用 UTF-16 代替。用语 "UCS2" 已被弃用并被移除 Unicode 标准。

示例

下例示例演示 UCS2/UTF-8 间和 UTF-16/UTF-8 间转换的差异：字符串中的字符不是合法的 UCS2 字符。

#include <iostream>
#include <string>
#include <locale>
#include <codecvt>

int main()
{
    // UTF-8 数据。字符 U+1d10b ，音符 segno ，不在 UCS2 中
    std::string utf8 = u8"z\u6c34\U0001d10b";

    // UTF-8 / UTF-16 标标准转换平面
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> utf16conv;
    std::u16string utf16 = utf16conv.from_bytes(utf8);
    std::cout << "UTF16 conversion produced " << utf16.size() << " code units:\n";
    for (char16_t c : utf16)
        std::cout << std::hex << std::showbase << c << '\n';

    // UTF-8 / UCS2 标准转换平面
    std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> ucs2conv;
    try {
        std::u16string ucs2 = ucs2conv.from_bytes(utf8);
    } catch(const std::range_error& e) {
        std::u16string ucs2 = ucs2conv.from_bytes(utf8.substr(0, ucs2conv.converted()));
        std::cout << "UCS2 failed after producing " << std::dec << ucs2.size()<<" characters:\n";
        for (char16_t c : ucs2)
            std::cout << std::hex << std::showbase << c << '\n';
    }
}

输出：

UTF16 conversion produced 4 code units:
0x7a
0x6c34
0xd834
0xdd0b
UCS2 failed after producing 2 characters:
0x7a
0x6c34

参阅

字符转换 | 本地环境定义多字节 (UTF-8, GB18030) | UTF-8 | UTF-16
UTF-16 | mbrtoc16 / c16rtomb (有 C11 的 DR488) | codecvt<char16_t, char, mbstate_t> codecvt_utf8_utf16<char16_t> codecvt_utf8_utf16<char32_t> codecvt_utf8_utf16<wchar_t> | N/A
UCS2 | c16rtomb (无 C11 的 DR488) | codecvt_utf8<char16_t> codecvt_utf8<wchar_t>(Windows) | codecvt_utf16<char16_t> codecvt_utf16<wchar_t>(Windows)
UTF-32 | mbrtoc32 / c32rtomb | codecvt<char32_t, char, mbstate_t> codecvt_utf8<char32_t> codecvt_utf8<wchar_t>(非 Windows) | codecvt_utf16<char32_t> codecvt_utf16<wchar_t>(非 Windows)
系统宽 UTF-32(非 Windows) UCS2(Windows) | mbsrtowcs / wcsrtombs use_facet<codecvt <wchar_t, char, mbstate_t>>(locale) | 无 | 无
codecvt | 在字符编码间转换，包括 UTF-8、UTF-16、UTF-32 (类模板)
codecvt_mode (C++11)(C++17 中弃用) | 用于改变标准 codecvt 刻面行为的标签 (枚举)
codecvt_utf16 (C++11)(C++17 中弃用) | 在 UTF-16 与 UCS2/UCS4 间转换 (类模板)
codecvt_utf8_utf16 (C++11)(C++17 中弃用) | 在 UTF-8 与 UTF-16 间转换 (类模板)


std::codecvt_utf8_utf16

< cpp‎ | locale
定义于头文件 <codecvt> |
template< class Elem, unsigned long Maxcode = 0x10ffff, std::codecvt_mode Mode = ( std::codecvt_mode )0 > class codecvt_utf8_utf16 : public std::codecvt <Elem, char, std::mbstate_t >; | (C++11 起) (C++17 中弃用)

std::codecvt_utf8_utf16 是一个 std::codecvt 平面，封装 UTF-8 编码字节串和 UTF-16 编码字符串间的转换。若 Elem 为 32 位类型，则输出序列的每个 32 位字符中将存储一个 UTF-16 编码单元。

这是 N:M 转换平面，而且不能为 std::basic_filebuf 所用（它只容许内部和外部编码间的 1:N 转换，例如 UTF-32/UTF-8 ）。此平面不能为 std::wstring_convert 所用。

模板形参

Elem | - | char16_t 、 char32_t 或 wchar_t 之一
Maxcode | - | 此平面将读或写而不出错的 Elem 最大值
Mode | - | std::codecvt_mode 类型常量

成员函数

(构造函数) | 构造新的 codecvt_utf8_utf16 平面 (公开成员函数)
(析构函数) | 销毁 codecvt_utf8_utf16 平面 (公开成员函数)

std::codecvt_utf8_utf16::codecvt_utf8_utf16

explicit codecvt_utf8_utf16( std::size_t refs = 0 );

构造新的 std::codecvt_utf8_utf16 平面，传递初始引用计数 refs 给基类。

参数

refs - 链接到平面的引用数

std::codecvt_utf8_utf16::~codecvt_utf8_utf16

~codecvt_utf8_utf16();

销毁平面。不同于本地环境所管理的平面，此平面的析构函数为公开。

继承自 std::codecvt

成员类型

成员类型 | 定义
intern_type | internT
extern_type | externT
state_type | stateT

成员对象

成员名 | 类型
id [静态] | std::locale::id

成员函数

out | 调用 do_out (std::codecvt<InternT,ExternT,State> 的公开成员函数)
in | 调用 do_in (std::codecvt<InternT,ExternT,State> 的公开成员函数)
unshift | 调用 do_unshift (std::codecvt<InternT,ExternT,State> 的公开成员函数)
encoding | 调用 do_encoding (std::codecvt<InternT,ExternT,State> 的公开成员函数)
always_noconv | 调用 do_always_noconv (std::codecvt<InternT,ExternT,State> 的公开成员函数)
length | 调用 do_length (std::codecvt<InternT,ExternT,State> 的公开成员函数)
max_length | 调用 do_max_length (std::codecvt<InternT,ExternT,State> 的公开成员函数)

受保护成员函数

do_out [虚] | 从 internT 转换字符串为 externT 转换字符串，如在写入文件时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_in [虚] | 从 externT 转换字符串为 internT ，如在从文件读取时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_unshift [虚] | 为不完整转换生成 externT 字符的终止字符序列 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_encoding [虚] | 返回产生一个 internT 字符所需的 externT 字符数，若此值为常数 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_always_noconv [虚] | 测试平面编码是否对所有合法值为恒等转换 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_length [虚] | 计算转换成给定的 internT 缓冲区会消耗的 externT 字符串长度 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)
do_max_length [虚] | 返回能转换成单个 internT 字符的最大 externT 字符数 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)

继承自 std::codecvt_base

成员类型 | 定义
enum result { ok, partial, error, noconv }; | 无作用域枚举类型
枚举常量 | 定义
ok | 完成转换而无错误
partial | 未转换所有源字符
error | 遇到非法字符
noconv | 不要求转换，输入与输出类型相同

示例

#include <iostream>
#include <string>
#include <codecvt>
#include <cassert>
#include <locale>

int main()
{
    std::string u8 = u8"z\u00df\u6c34\U0001f34c";
    std::u16string u16 = u"z\u00df\u6c34\U0001f34c";

    // UTF-8 到 UTF-16/char16_t
    std::u16string u16_conv = std::wstring_convert<
        std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(u8);
    assert(u16 == u16_conv);
    std::cout << "UTF-8 to UTF-16 conversion produced "
              << u16_conv.size() << " code units:\n";
    for (char16_t c : u16_conv)
        std::cout << std::hex << std::showbase << c << ' ';

    // UTF-16/char16_t 到 UTF-8
    std::string u8_conv = std::wstring_convert<
        std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(u16);
    assert(u8 == u8_conv);
    std::cout << "\nUTF-16 to UTF-8 conversion produced "
              << std::dec << u8_conv.size() << " bytes:\n" << std::hex;
    for (char c : u8_conv)
        std::cout << +(unsigned char)c << ' ';
}

输出：

UTF-8 to UTF-16 conversion produced 5 code units:
0x7a 0xdf 0x6c34 0xd83c 0xdf4c
UTF-16 to UTF-8 conversion produced 10 bytes:
0x7a 0xc3 0x9f 0xe6 0xb0 0xb4 0xf0 0x9f 0x8d 0x8c

参阅

字符转换 | 本地环境定义多字节 (UTF-8, GB18030) | UTF-8 | UTF-16
UTF-16 | mbrtoc16 / c16rtomb (有 C11 的 DR488) | codecvt<char16_t, char, mbstate_t> codecvt_utf8_utf16<char16_t> codecvt_utf8_utf16<char32_t> codecvt_utf8_utf16<wchar_t> | N/A
UCS2 | c16rtomb (无 C11 的 DR488) | codecvt_utf8<char16_t> codecvt_utf8<wchar_t>(Windows) | codecvt_utf16<char16_t> codecvt_utf16<wchar_t>(Windows)
UTF-32 | mbrtoc32 / c32rtomb | codecvt<char32_t, char, mbstate_t> codecvt_utf8<char32_t> codecvt_utf8<wchar_t>(非 Windows) | codecvt_utf16<char32_t> codecvt_utf16<wchar_t>(非 Windows)
系统宽 UTF-32(非 Windows) UCS2(Windows) | mbsrtowcs / wcsrtombs use_facet<codecvt <wchar_t, char, mbstate_t>>(locale) | 无 | 无
codecvt | 在字符编码间转换，包括 UTF-8、UTF-16、UTF-32 (类模板)
codecvt_mode (C++11)(C++17 中弃用) | 用于改变标准 codecvt 刻面行为的标签 (枚举)
codecvt_utf8 (C++11)(C++17 中弃用) | 在 UTF-8 与 UCS2/UCS4 间转换 (类模板)
codecvt_utf16 (C++11)(C++17 中弃用) | 在 UTF-16 与 UCS2/UCS4 间转换 (类模板)


std::collate

< cpp‎ | locale
定义于头文件 <locale>
template< class CharT >
class collate;

类 std::collate 封装字符串的本地环境限定对照（比较）和哈希。此平面为 std::basic_regex 所用，并能以 std::locale::operator() 直接应用到所有期待 string 比较谓词的标准算法。

cpp/locale/locale/facet

继承图

标准库提供二个孤立（不依赖本地环境）的特化：

定义于头文件 <locale>
std::collate<char> | 实现字节字符串的字典序定序
std::collate<wchar_t> | 实现宽字符串的字典序定序

另外， C++ 程序中构造的每个 locale 对象都实装这些特化的其自身（本地环境限定）版本。

成员类型

成员类型 | 定义
char_type | CharT
string_type | std::basic_string<CharT>

成员函数

(构造函数) | 构造新的 collate 平面 (公开成员函数)
(析构函数) | 销毁 collate 平面 (受保护成员函数)
compare | 调用 do_compare (公开成员函数)
transform | 调用 do_transform (公开成员函数)
hash | 调用 do_hash (公开成员函数)

成员对象

static std::locale::id id
 locale 的 id
(公开成员对象)

受保护成员函数

do_compare [虚] | 用此平面的对照规则比较二个字符串 (虚受保护成员函数)
do_transform [虚] | 变换字符串，使得能用比较替换对照 (虚受保护成员函数)
do_hash [虚] | 生成使用此平面对照规则的整数哈希值 (虚受保护成员函数)

示例

#include <locale>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

int main()
{
    std::wcout.imbue(std::locale(""));
    std::vector<std::wstring> v = {L"ar", L"zebra", L"\u00f6grupp", L"Zebra", L"\u00e4ngel",
                                   L"\u00e5r", L"f\u00f6rnamn"};

    std::wcout << "Default locale collation order: ";
    std::sort(v.begin(), v.end());
    for (auto s : v) std::wcout << s << ' '; std::wcout << '\n';

    std::wcout << "English locale collation order: ";
    std::sort(v.begin(), v.end(), std::locale("en_US.UTF-8"));
    for (auto s : v) std::wcout << s << ' '; std::wcout << '\n';

    std::wcout << "Swedish locale collation order: ";
    std::sort(v.begin(), v.end(), std::locale("sv_SE.UTF-8"));
    for (auto s : v) std::wcout << s << ' '; std::wcout << '\n';
}

输出：

Default locale collation order: Zebra ar förnamn zebra ängel år ögrupp
English locale collation order: ängel ar år förnamn ögrupp zebra Zebra
Swedish locale collation order: ar förnamn zebra Zebra år ängel ögrupp

参阅

operator() | 用此 locale 的 collate 刻面以字典序比较两个字符串 (std::locale 的公开成员函数)
collate_byname | 为具名 locale 创建 collate 平面 (类模板)


std::collate<CharT>::collate

< cpp‎ | locale‎ | collate

定义于头文件 <locale>
explicit collate( std::size_t refs = 0 );

创建 std::collate 平面并转发引用计数 refs 到基类构造函数 locale::facet::facet() 。

参数

refs - 开始的引用计数


std::collate<CharT>::compare, std::collate<CharT>::do_compare

< cpp‎ | locale‎ | collate
定义于头文件 <locale> |
public: int compare( const CharT* low1, const CharT* high1, const CharT* low2, const CharT* high2 ) const; | (1)
protected: virtual int do_compare( const CharT* low1, const CharT* high1, const CharT* low2, const CharT* high2 ) const; | (2)
1) 公开成员函数，调用最终导出类的受保护虚成员函数 do_compare 。
2) 以此本地环境的对照规则，比较字符序列 [low1, high1) 与字符序列 [low2, high2) ，而若第一字符串后随第二个则返回 1 ，若第一字符串前趋第二个则返回 -1 ，若二个字符串等价则返回零。

参数

low1 | - | 指向第一字符串首字符的指针
high1 | - | 第一字符串的尾后一位置指针
low2 | - | 指向第二字符串首字符的指针
high2 | - | 第二字符串的尾后一位置指针

返回值

若第一字符串大于第二个（即以对照顺序后随第二个）则为 1 ，若第一字符串小于第二个（以对照顺序前趋第二个）则为 -1 ，若二个字符串等价则为零。

注意

不要求三路比较时（例如在提供 Compare 参数给如 std::sort 的标准算法时）， std::locale::operator() 可能更适合。

对照顺序为字典顺序：国家字母表（其等价类）中字母的位置拥有高于其大小写或变体的优先级。在等价类内，小写字符先于其大写等价物对照，而且本地环境限定的顺序可能应用到有发音符号的字符。一些本地环境中，字符组作为单个对照单元比较。例如， "ch" 在捷克语中后随 "h" 而前趋 "i" ， "dzs" 在匈牙利语中后随 "dz" 而前趋 "g" 。

示例

#include <iostream>
#include <string>
#include <locale>

template<typename CharT>
void try_compare(const std::locale& l, const CharT* p1, const CharT* p2)
{
    auto& f = std::use_facet<std::collate<CharT>>(l);

    std::basic_string<CharT> s1(p1), s2(p2);
    if(f.compare(&s1[0], &s1[0] + s1.size(),
                 &s2[0], &s2[0] + s2.size() ) < 0)
         std::wcout << p1 << " before " << p2 << '\n';
    else
         std::wcout << p2 << " before " << p1 << '\n';
}

int main()
{
    std::locale::global(std::locale("en_US.utf8"));
    std::wcout.imbue(std::locale());

    std::wcout << "In the American locale: ";
    try_compare(std::locale(), "hrnec", "chrt");
    std::wcout << "In the Czech locale: ";
    try_compare(std::locale("cs_CZ.utf8"), "hrnec", "chrt");

    std::wcout << "In the American locale: ";
    try_compare(std::locale(), L"år", L"ängel");
    std::wcout << "In the Swedish locale: ";
    try_compare(std::locale("sv_SE.utf8"), L"år", L"ängel");
}

输出：

In the American locale: chrt before hrnec
In the Czech locale: hrnec before chrt
In the American locale: ängel before år
In the Swedish locale: år before ängel

参阅

strcoll | 按照当前本地环境比较两个字符串 (函数)
wcscoll | 按照当前本地环境比较两个宽字符串 (函数)
operator() | 用此 locale 的 collate 刻面以字典序比较两个字符串 (std::locale 的公开成员函数)


std::collate<CharT>::hash, std::collate<CharT>::do_hash

< cpp‎ | locale‎ | collate
定义于头文件 <locale> |
public: long hash( const CharT* beg, const CharT* end ) const; | (1)
protected: virtual long do_hash( const CharT* beg, const CharT* end ) const; | (2)
1) 公开成员函数，调用最终导出类的受保护虚成员函数 do_hash 。
2) 转换字符序列 [beg, end) 为整数值，该值对所有此本地环境中对照等价（ compare() 返回 ​0​ ）的字符串相同。对于二个不对照等价的字符串，其哈希相等的概率要非常小，近似 1.0/ std::numeric_limits <unsigned long>::max() 。

参数

beg | - | 指向要哈希的序列中首字符的指针
end | - | 要哈西的序列的尾后一位置指针

返回值

相对于对照顺序的哈希值。

注意

若 basic_string::operator== 返回 false ，则系统提供的本地环正常地不对照二个字符串为等价（ compare() 不返回 ​0​ ），但用户安装的 std::collate 平面可提供不同的对照规则，例如，它可以若字符串拥有相同的 Unicode 正常化形式，则对待字符串为等价。

示例

演示具本地环境的无序容器

#include <iostream>
#include <string>
#include <locale>
#include <unordered_set>

struct CollateHash {
    template<typename CharT>
    std::size_t operator()(const std::basic_string<CharT>& s) const
    {
        return std::use_facet<std::collate<CharT>>(std::locale()).hash(
                   &s[0], &s[0] + s.size()
               );
    }
};
struct CollateEq {
    template<typename CharT>
    bool operator()(const std::basic_string<CharT>& s1,
                    const std::basic_string<CharT>& s2) const
    {
        return std::use_facet<std::collate<CharT>>(std::locale()).compare(
                     &s1[0], &s1[0] + s1.size(),
                     &s2[0], &s2[0] + s2.size()
               ) == 0;
    }
};

int main()
{
    std::locale::global(std::locale("en_US.utf8"));
    std::wcout.imbue(std::locale());

    std::unordered_set<std::wstring, CollateHash, CollateEq> s2 = {L"Foo", L"Bar"};
    for(auto& str: s2)
        std::wcout << str << ' ';
    std::cout << '\n';
}

可能的输出：

Bar Foo

参阅

std::hash<std::string>std::hash<std::u8string>std::hash<std::u16string>std::hash<std::u32string>std::hash<std::wstring>std::hash<std::pmr::string>std::hash<std::pmr::u8string>std::hash<std::pmr::u16string>std::hash<std::pmr::u32string>std::hash<std::pmr::wstring>
(C++11)(C++20)(C++11)(C++11)(C++11)(C++17)(C++20)(C++17)(C++17)(C++17)
 string 的散列支持
(类模板特化)


std::collate<CharT>::transform, do_transform

< cpp‎ | locale‎ | collate
定义于头文件 <locale> |
public: string_type transform( const CharT* low, const CharT* high ) const; | (1)
protected: virtual string_type do_transform( const CharT* low, const CharT* high ) const; | (2)
1) 公开成员函数，调用最终导出类的受保护虚成员函数 do_transform 。
2) 转换字符序列 [low, high) 为 string ，使得它与在另一字符串上调用 transform() 的结果以字典序比较，会产生在二个相同字符串上调用 do_compare() 的相同结果。

参数

low | - | 指向要变换的字符序列中首字符的指针
high | - | 要变换的序列的尾后一位置指针

返回值

变换后的字符串，它使得被变换字符串的字典序比较能用于取代原字符串的对照。 "C" 本地环境中，返回的字符串为 [low, high) 的准确副本。其他本地环境中，返回字符串的内容是实现定义的，而且可考虑到大小可能更长。

注意

在对照中的使用外，被变换字符串的本地环境限定格式还为 std::regex_traits::transform_primary 所知，它能释出等价类信息。

示例

#include <iostream>
#include <iomanip>
#include <locale>

int main()
{
    std::locale::global(std::locale("sv_SE.utf8"));
    auto& f = std::use_facet<std::collate<wchar_t>>(std::locale());

    std::wstring in1 = L"\u00e4ngel";
    std::wstring in2 = L"\u00e5r";

    std::wstring out1 = f.transform(&in1[0], &in1[0] + in1.size());
    std::wstring out2 = f.transform(&in2[0], &in2[0] + in2.size());

    std::wcout << "In the Swedish locale: ";
    if(out1 < out2)
         std::wcout << in1 << " before " << in2 << '\n';
    else
         std::wcout << in2 << " before " << in1 << '\n';

    std::wcout << "In lexicographic comparison: ";
    if(in1 < in2)
         std::wcout << in1 << " before " << in2 << '\n';
    else
         std::wcout << in2 << " before " << in1 << '\n';

}

输出：

In the Swedish locale: år before ängel
In lexicographic comparison: ängel before år

参阅

strxfrm | 变换字符串，使得 strcmp 会返回与 strcoll 相同的结果 (函数)
wcsxfrm | 变换宽字符串，使得 wcscmp 会产生与 wsccoll 相同的结果 (函数)


std::collate<CharT>::~collate

< cpp‎ | locale‎ | collate

定义于头文件 <locale>
protected: ~collate();

析构 std::collate 平面。此析构函数为受保护且为虚（由于基类析构函数为虚）。 std::collate 类型对象，同大多数平面，只能在最后一个实装此平面的 std::locale 离开作用域时，或若用户定义导出自 std::collate 并实现公开构造函数，才会被销毁。

示例

#include <iostream>
#include <locale>
struct Destructible_collate : public std::collate<wchar_t>
{
    Destructible_collate(std::size_t refs = 0) : collate(refs) {}
    // 注意：隐式析构函数为公开
};
int main()
{
    Destructible_collate dc;
    // std::collate<wchar_t> c;  // 编译错误：受保护析构函数
}


std::collate_byname

< cpp‎ | locale
定义于头文件 <locale>
template< class CharT >
class collate_byname : public std::collate <CharT>;

std::collate_byname 是封装本地环境限定对照（比较）和字符串哈希的 std::collate 平面。正如同 std::collate ，它可以感染于 std::regex ，并以 std::locale::operator() 直接应用到所有期待 string 比较谓词的标准算法。

标准库提供二个特化

定义于头文件 <locale>
std::collate_byname<char> | 多字节字符串的本地环境限定对照
std::collate_byname<wchar_t> | 宽字符串的本地环境限定对照

成员函数

(构造函数) | 构造新的 collate_byname 平面 (公开成员函数)
(析构函数) | 析构 collate_byname 平面 (受保护成员函数)

std::collate_byname::collate_byname

explicit collate_byname( const char* name, std::size_t refs = 0 ); |
explicit collate_byname( const std::string & name, std::size_t refs = 0 ); | (C++11 起)

为名为 name 的本地环境构造新的 std::collate_byname 平面。

refs 用于资源管理：在销毁最后一个保有平面的 std::locale 对象时，若 refs == 0 ，则实现销毁平面对象。否则，不销毁对象。

参数

name | - | 本地环境的名称
refs | - | 链接到该平面的引用数

std::collate_byname::~collate_byname

protected:
~collate_byname();

销毁平面。

继承自 std::collate

成员类型

成员类型 | 定义
char_type | charT
string_type | std::basic_string<charT>

成员函数

compare | 调用 do_compare (std::collate<CharT> 的公开成员函数)
transform | 调用 do_transform (std::collate<CharT> 的公开成员函数)
hash | 调用 do_hash (std::collate<CharT> 的公开成员函数)

受保护成员函数

do_compare [虚] | 用此平面的对照规则比较二个字符串 (std::collate<CharT> 的虚受保护成员函数)
do_transform [虚] | 变换字符串，使得能用比较替换对照 (std::collate<CharT> 的虚受保护成员函数)
do_hash [虚] | 生成使用此平面对照规则的整数哈希值 (std::collate<CharT> 的虚受保护成员函数)

注意

对照顺序为字典顺序：国家字母表（其等价类）中字母的位置拥有高于其大小写或变体的优先级。在等价类内，小写字符先于其大写等价物对照，而且本地环境限定的顺序可能应用到有发音符号的字符。一些本地环境中，字符组作为单个对照单元比较。例如， "ch" 在捷克语中后随 "h" 而前趋 "i" ， "dzs" 在匈牙利语中后随 "dz" 而前趋 "g" 。

示例

本节未完成
原因：暂无示例

参阅

collate | 定义字典序比较和字符串的散列 (类模板)
strcoll | 按照当前本地环境比较两个字符串 (函数)
wcscoll | 按照当前本地环境比较两个宽字符串 (函数)
operator() | 用此 locale 的 collate 刻面以字典序比较两个字符串 (std::locale 的公开成员函数)


std::ctype

< cpp‎ | locale
定义于头文件 <locale>
template< class CharT >
class ctype;

类 ctype 封装字符分类特征。所有通过 std::basic_istream <charT> 进行的流输入操作用感染于流中的 std::ctype<charT> 鉴别空白符以将输入记号化。流输出操作在输出前应用 std::ctype<charT>::widen() 到窄字符参数。

cpp/locale/ctype base cpp/locale/locale/facet

继承图

标准库提供二个孤立（独立于本地环境）的特化：

定义于头文件 <locale>
std::ctype<char> | 提供最小 "C" 本地环境分类的窄字符等价版本。此特化用表查找字符分类
std::ctype<wchar_t> | 提供适合于原生字符集的宽字符分类

另外， C++ 程序中构造的每个 locale 对象实现其自身（本地环境限定）的这些版本。

成员类型

成员类型 | 定义
char_type | CharT

成员函数

(构造函数) | 构造新的 ctype 平面 (公开成员函数)
(析构函数) | 析构 ctype 平面 (受保护成员函数)
is | 调用 do_is (公开成员函数)
scan_is | 调用 do_scan_is (公开成员函数)
scan_not | 调用 do_scan_not (公开成员函数)
toupper | 调用 do_toupper (公开成员函数)
tolower | 调用 do_tolower (公开成员函数)
widen | 调用 do_widen (公开成员函数)
narrow | 调用 do_narrow (公开成员函数)

成员对象

static std::locale::id id
 locale 的 id
(公开成员对象)

受保护成员函数

do_is [虚] | 分类字符或字符序列 (虚受保护成员函数)
do_scan_is [虚] | 定位序列中首个符合给定分类的字符 (虚受保护成员函数)
do_scan_not [虚] | 定位序列中首个不符合给定分类的字符 (虚受保护成员函数)
do_toupper [虚] | 转换一个或多个字符为大写 (虚受保护成员函数)
do_tolower [虚] | 转换一个或多个字符为小写 (虚受保护成员函数)
do_widen [虚] | 将一或多个字符从 char 转换为 charT (虚受保护成员函数)
do_narrow [虚] | 将一个或多个字符从 charT 转换为 char (虚受保护成员函数)

继承自 std::ctype_base

成员类型

类型 | 定义
mask | 未指定的位掩码类型（枚举、整数类型或 bitset ）

成员常量

space [静态] | 鉴别空白字符分类的 mask 值 (公开静态成员常量)
print [静态] | 鉴别可打印字符分类的 mask 值 (公开静态成员常量)
cntrl [静态] | 鉴别控制字符分类的 mask 值 (公开静态成员常量)
upper [静态] | 鉴别大写字符分类的 mask 值 (公开静态成员常量)
lower [静态] | 鉴别小写字符分类的 mask 值 (公开静态成员常量)
alpha [静态] | 鉴别字母字符分类的 mask 值 (公开静态成员常量)
digit [静态] | 鉴别数字字符分类的 mask 值 (公开静态成员常量)
punct [静态] | 鉴别标点字符分类的 mask 值 (公开静态成员常量)
xdigit [静态] | 鉴别十六进制数字字符分类的 mask 值 (公开静态成员常量)
blank [静态] (C++11) | 鉴别空格字符分类的 mask 值 (公开静态成员常量)
alnum [静态] | alpha | digit (公开静态成员常量)
graph [静态] | alnum | punct (公开静态成员常量)

示例

下列代码演示 ctype 异于 ctype<char> 的修改，以记号化 CSV 文件

#include <iostream>
#include <locale>
#include <sstream>

struct csv_whitespace : std::ctype<wchar_t>
{
    bool do_is(mask m, char_type c) const
    {
        if ((m & space) && c == L' ') {
            return false; // 空格将不被分类为空白符
        }
        if ((m & space) && c == L',') {
            return true; // 逗号将被分类为空白符
        }
        return ctype::do_is(m, c); // 将剩下的留给亲类
    }
};

int main()
{
    std::wstring in = L"Column 1,Column 2,Column 3\n123,456,789";
    std::wstring token;

    std::wcout << "default locale:\n";
    std::wistringstream s1(in);
    while (s1 >> token) {
        std::wcout << "  " << token << '\n';
    }

    std::wcout << "locale with modified ctype:\n";
    std::wistringstream s2(in);
    csv_whitespace* my_ws = new csv_whitespace; // 注意：此分配不泄露
    s2.imbue(std::locale(s2.getloc(), my_ws));
    while (s2 >> token) {
        std::wcout << "  " << token<< '\n';
    }
}

输出：

default locale:
  Column
  1,Column
  2,Column
  3
  123,456,789
locale with modified ctype:
  Column 1
  Column 2
  Column 3
  123
  456
  789

参阅

ctype<char> | std::ctype 对类型 char 的特化 (类模板特化)
ctype_base | 定义字符分类类别 (类模板)
ctype_byname | 创建具名本地环境的 ctype 平面 (类模板)


std::ctype<CharT>::ctype

< cpp‎ | locale‎ | ctype

定义于头文件 <locale>
explicit ctype( std::size_t refs = 0 );

创建 std::ctype 平面并转发引用计数 refs 到基类构造函数 locale::facet::facet() 。

参数

refs - 开始的引用计数


std::ctype<CharT>::is, std::ctype<CharT>::do_is

< cpp‎ | locale‎ | ctype
定义于头文件 <locale> |
public: bool is(mask m, CharT c) const; | (1)
public: const CharT* is(const CharT* low, const CharT* high, mask* vec) const; | (2)
protected: virtual bool do_is(mask m, CharT c) const; | (3)
protected: virtual const CharT* do_is(const CharT* low, const CharT* high, mask* vec) const; | (4)
1,2) 公开成员函数，调用最终导出类的受保护虚成员函数 do_is 。
3) 检查字符 c 是否以掩码 m 分类。
4) 对字符数组 [low, high) 中的每个字符，鉴别完整分类掩码（例如默认本地环境中对于数字 '0' 为 digit|xdigit|alnum|print|graph ），并存储掩码于 vec 所指向数组的对应元素。

参数

c | - | 要分类的字符
m | - | 用于分类单个字符的掩码
low | - | 指向要分类的字符数组中首字符的指针
high | - | 要分类的字符数组的尾后一位置指针
vec | - | 指向要填充的掩码数组首元素的指针

返回值

1,3) 若 c 以 m 分类则为 true
2,4) high

示例

#include <locale>
#include <utility>
#include <vector>
#include <iostream>

// 使绑定到 locale 的 facet 可析构的工具包装器
template<class Facet>
struct deletable_facet : Facet
{
    template<class ...Args>
    deletable_facet(Args&& ...args) : Facet(std::forward<Args>(args)...) {}
    ~deletable_facet() {}
};

int main()
{
    // 用默认 locale 分类单个字符
    auto& f = std::use_facet<std::ctype<char>>(std::locale());
    char c = '0';
    if (f.is(std::ctype_base::digit, c)) // 或 isdigit(c, locale());
    {
        std::cout << "'" << c << "' is a digit\n";
    }

    // 用具名 locale 分类每个字符串中的字符
    deletable_facet<std::ctype_byname<wchar_t>> f2("en_US.utf8");
    std::wstring str = L"z\u00df\u6c34\U0001d10b";
    std::vector<std::ctype_base::mask> vec(str.size());
    f2.is(&str[0], &str[0] + str.size(), &vec[0]);

    for (std::size_t n = 0; n < str.size(); ++n) {
       std::cout << std::hex << "U+" << str[n] << " is: ";
       if (vec[n] & std::ctype_base::alnum)
          std::cout << " alnum ";
       if (vec[n] & std::ctype_base::punct)
          std::cout << " punct ";
       std::cout << '\n';
    }
}

输出：

'0' is a digit
U+7a is:  alnum
U+df is:  alnum
U+6c34 is:  alnum
U+1d10b is:  punct

参阅

is | 用分类表分类字符或字符序列 (std::ctype<char> 的公开成员函数)
iswctype | 按照指定的 LC_TYPE 类别分类宽字符 (函数)


std::ctype<CharT>::narrow, do_narrow

< cpp‎ | locale‎ | ctype
定义于头文件 <locale> |
public: char narrow( CharT c, char dflt ) const; | (1)
public: const CharT* narrow( const CharT* beg, const CharT* end, char dflt, char* dst ) const; | (2)
protected: virtual char do_narrow( CharT c, char dflt ) const; | (3)
protected: virtual const CharT* do_narrow( const CharT* beg, const CharT* end, char dflt, char* dst ) const; | (4)
1,2) 公开成员函数，调用最终派生类的受保护虚成员函数 do_narrow 。
3) 如果（可能为宽）的字符 c 能以单字节表示（例如 UTF-8 编码中的 ASCII 字符是单字节），那么转换它为多字节表示。如果这种转换不存在则返回 dflt。
4) 对于字符数组 [beg, end) 中的每个字符，写入窄化字符（或在窄化失败时写入 dflt）到 dst 所指向的字符数组中的相继位置。

对于来自基础源字符集 (C++23 前)基础字符集 (C++23 前)的字符，窄化始终成功且始终可逆（通过调用 widen()）。

如果窄化成功，那么它保持所有 is() 所知的字符分类类别。

窄化任何数字字符保证从结果减去字符字面量 '0' 的差等于原字符的数位值。

参数

c | - | 要转换的字符
dflt | - | 转换失败时产生的默认值
beg | - | 指向要转换的字符数组中首字符的指针
end | - | 指向要转换的字符数组的尾后一位置的指针
dst | - | 指向要填充的字符数组首元素的指针

返回值

1,3) 窄化的字符，或窄化失败时为 dflt
2,4) end

示例

#include <locale>
#include <iostream>

void try_narrow(const std::ctype<wchar_t>& f, wchar_t c)
{
    char n = f.narrow(c, 0);
    if (n) {
        std::wcout << '\'' << c << "' 窄化为 " << +(unsigned char)n << '\n';
    } else {
        std::wcout << '\'' << c << "' 无法被窄化\n";
    }
}

int main()
{
    std::locale::global(std::locale("en_US.utf8"));
    std::wcout.imbue(std::locale());
    std::wcout << std::hex << std::showbase << "在 US English UTF-8 区域设置下：\n";
    auto& f = std::use_facet<std::ctype<wchar_t>>(std::locale());
    try_narrow(f, L'A');
    try_narrow(f, L'Ａ');
    try_narrow(f, L'ě');

    std::locale::global(std::locale("cs_CZ.iso88592"));
    auto& f2 = std::use_facet<std::ctype<wchar_t>>(std::locale());
    std::wcout << "在 Czech ISO-8859-2 区域设置下：\n";
    try_narrow(f2, L'A');
    try_narrow(f2, L'Ａ');
    try_narrow(f2, L'ě');
}

输出：

在 US English UTF-8 区域设置下：
'A' 窄化为 0x41
'Ａ' 无法被窄化
'ě' 无法被窄化
在 Czech ISO-8859-2 区域设置下：
'A' 窄化为 0x41
'Ａ' 无法被窄化
'ě' 窄化为 0xec

参阅

widen | 调用 do_widen (公开成员函数)
narrow | 窄化字符 (std::basic_ios<CharT,Traits> 的公开成员函数)
wctob | 若可能，则窄化宽字符为单字节窄字符 (函数)


std::ctype<CharT>::scan_is, std::ctype<CharT>::do_scan_is

< cpp‎ | locale‎ | ctype
定义于头文件 <locale> |
public: const CharT* scan_is( mask m, const CharT* beg, const CharT* end ) const; | (1)
protected: virtual const CharT* do_scan_is( mask m, const CharT* beg, const CharT* end) const; | (2)
1) 公开成员函数，调用最终导出类的受保护虚成员函数 do_scan_is 。
2) 定位字符数组 [beg, end) 中满足分类掩码 m 的首个字符，即首个使得 is(m, c) 会返回 true 的字符 c 。

参数

m | - | 要搜索的掩码
beg | - | 指向要搜索的数组中首字符的指针
end | - | 指向要搜索的数组尾后一位置的指针

返回值

指向 [beg, end) 中首个满足掩码的字符，或若找不到这种字符则为 end 。

示例

#include <locale>
#include <clocale>
#include <iostream>
#include <iterator>

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout.imbue(std::locale("en_US.utf8"));
    auto& f = std::use_facet<std::ctype<wchar_t>>(std::wcout.getloc());

    // 跳过首个字母之前
    wchar_t s1[] = L"      \t\t\n  Кошка";
    const wchar_t* p1 = f.scan_is(std::ctype_base::alpha, std::begin(s1), std::end(s1));
    std::wcout << "'" << p1 << "'\n";

    // 跳过首个字母之前
    wchar_t s2[] = L"123456789ネプネプ";
    const wchar_t* p2 = f.scan_is(std::ctype_base::alpha, std::begin(s2), std::end(s2));
    std::wcout << "'" << p2 << "'\n";
}

输出：

'Кошка'
'ネプネプ'

参阅

scan_is | 用分类表定位序列中首个符合给定分类的字符 (std::ctype<char> 的公开成员函数)
do_scan_not [虚] | 定位序列中首个不符合给定分类的字符 (虚受保护成员函数)


std::ctype<CharT>::scan_not, std::ctype<CharT>::do_scan_not

< cpp‎ | locale‎ | ctype
定义于头文件 <locale> |
public: const CharT* scan_not( mask m, const CharT* beg, const CharT* end ) const; | (1)
protected: virtual const CharT* do_scan_not( mask m, const CharT* beg, const CharT* end) const; | (2)
1) 公开成员函数，调用最终导出类的受保护虚成员函数 do_scan_not 。
2) 定位字符数组 [beg, end) 中不满足分类掩码 m 的首个字符，即首个使得 is(m, c) 会返回 false 的字符 c 。

参数

m | - | 要搜索的掩码
beg | - | 指向要搜索的数组中首字符的指针
end | - | 指向要搜索的数组尾后一位置的指针

返回值

指向 [beg, end) 中首个不满足掩码的字符，或若找不到这种字符则为 end 。

示例

#include <locale>
#include <clocale>
#include <iostream>
#include <iterator>

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout.imbue(std::locale("en_US.utf8"));
    auto& f = std::use_facet<std::ctype<wchar_t>>(std::wcout.getloc());

    // 跳过前导空白
    wchar_t s1[] = L"      \t\t\n  Кошка";
    const wchar_t* p1 = f.scan_not(std::ctype_base::space, std::begin(s1), std::end(s1));
    std::wcout << "'" << p1 << "'\n";

    // 跳过前导数字
    wchar_t s2[] = L"123456789ネプネプ";
    const wchar_t* p2 = f.scan_not(std::ctype_base::digit, std::begin(s2), std::end(s2));
    std::wcout << "'" << p2 << "'\n";
}

输出：

'Кошка'
'ネプネプ'

See also

scan_not | 用分类表定位序列中首个不符合给定分类的字符 (std::ctype<char> 的公开成员函数)
do_scan_is [虚] | 定位序列中首个符合给定分类的字符 (虚受保护成员函数)


std::ctype<CharT>::tolower, std::ctype<CharT>::do_tolower

< cpp‎ | locale‎ | ctype
定义于头文件 <locale> |
public: CharT tolower( CharT c ) const; | (1)
public: const CharT* tolower( CharT* beg, const CharT* end ) const; | (2)
protected: virtual CharT do_tolower( CharT c ) const; | (3)
protected: virtual const CharT* do_tolower( CharT* beg, const CharT* end ) const; | (4)
1,2) 公开成员函数，调用最终导出类上的受保护虚成员函数 do_tolower 。
3) 若此 locale 定义 c 的小写形式，则转换它为小写形式。
4) 对字符数组 [beg, end) 中每个存在小写形式的字符，以其小写形式替换该字符。

参数

c | - | 要转换的字符
beg | - | 指向要转换的数组中首字符的指针
end | - | 指向要转换的数组尾后一位置的指针

返回值

1,3) 小写字符，或若无列于此 loacale 的小写形式则为 c 。
2,4) end 。

注意

此函数只能进行 1:1 字符映射，例如希腊文大写字母 'Σ' 拥有二个小写形式，取决于在词中的位置： 'σ' 与 'ς' 。此情况下对 do_tolower 的调用不能获得正确的小写形式。

示例

#include <locale>
#include <iostream>

void try_lower(const std::ctype<wchar_t>& f, wchar_t c)
{
    wchar_t up = f.tolower(c);
    if (up != c) {
        std::wcout << "Lower case form of \'" << c << "' is " << up << '\n';
    } else {
        std::wcout << '\'' << c << "' has no lower case form\n";
    }
}

int main()
{
    std::locale::global(std::locale("en_US.utf8"));
    std::wcout.imbue(std::locale());
    std::wcout << "In US English UTF-8 locale:\n";
    auto& f = std::use_facet<std::ctype<wchar_t>>(std::locale());
    try_lower(f, L'Σ');
    try_lower(f, L'Ɛ');
    try_lower(f, L'Ａ');

    std::wstring str = L"HELLo, wORLD!";
    std::wcout << "Lowercase form of the string '" << str << "' is ";
    f.tolower(&str[0], &str[0] + str.size());
    std::wcout << "'" << str << "'\n";
}

输出：

In US English UTF-8 locale:
Lower case form of 'Σ' is σ
Lower case form of 'Ɛ' is ɛ
Lower case form of 'Ａ' is ａ
Lowercase form of the string 'HELLo, wORLD!' is 'hello, world!'

参阅

toupper | 调用 do_toupper (公开成员函数)
tolower | 转换字符为小写 (函数)
towlower | 转换宽字符为小写 (函数)


std::ctype<CharT>::toupper, std::ctype<CharT>::do_toupper

< cpp‎ | locale‎ | ctype
定义于头文件 <locale> |
public: CharT toupper( CharT c ) const; | (1)
public: const CharT* toupper( CharT* beg, const CharT* end ) const; | (2)
protected: virtual CharT do_toupper( CharT c ) const; | (3)
protected: virtual const CharT* do_toupper( CharT* beg, const CharT* end ) const; | (4)
1,2) 公开成员函数，调用最终导出类上的受保护虚成员函数 do_toupper 。
3) 若此 locale 定义 c 的大写形式，则转换它为大写形式。
4) 对字符数组 [beg, end) 中每个存在大写形式的字符，以其大写形式替换该字符。

参数

c | - | 要转换的字符
beg | - | 指向要转换的数组中首字符的指针
end | - | 指向要转换的数组尾后一位置的指针

返回值

1,3) 大写字符，或若无列于此 loacale 的大写形式则为 c 。
2,4) end 。

注意

此函数只能进行 1:1 字符映射，例如 'ß' 的大写形式（有一些例外）是双字符字符串 "SS" ，它无法以 do_toupper 获得。

示例

#include <locale>
#include <iostream>

void try_upper(const std::ctype<wchar_t>& f, wchar_t c)
{
    wchar_t up = f.toupper(c);
    if (up != c) {
        std::wcout << "Upper case form of \'" << c << "' is " << up << '\n';
    } else {
        std::wcout << '\'' << c << "' has no upper case form\n";
    }
}

int main()
{
    std::locale::global(std::locale("en_US.utf8"));
    std::wcout.imbue(std::locale());
    std::wcout << "In US English UTF-8 locale:\n";
    auto& f = std::use_facet<std::ctype<wchar_t>>(std::locale());
    try_upper(f, L's');
    try_upper(f, L'ſ');
    try_upper(f, L'ß');

    std::wstring str = L"Hello, World!";
    std::wcout << "Uppercase form of the string '" << str << "' is ";
    f.toupper(&str[0], &str[0] + str.size());
    std::wcout << "'" << str << "'\n";
}

输出：

In US English UTF-8 locale:
Upper case form of 's' is S
Upper case form of 'ſ' is S
'ß' has no upper case form
Uppercase form of the string 'Hello, World!' is 'HELLO, WORLD!'

参阅

tolower | 调用 do_tolower (公开成员函数)
toupper | 转换字符为大写 (函数)
towupper | 转换宽字符为大写 (函数)


std::ctype<CharT>::widen, do_widen

< cpp‎ | locale‎ | ctype
定义于头文件 <locale> |
public: CharT widen( char c ) const; | (1)
public: const char* widen( const char* beg, const char* end, CharT* dst ) const; | (2)
protected: virtual CharT do_widen( char c ) const; | (3)
protected: virtual const char* do_widen( const char* beg, const char* end, CharT* dst ) const; | (4)
1,2) 公开成员函数，调用最终派生类的受保护虚成员函数 do_widen 。
3) 用最简单的合理变换，转换单字节字符 c 为对应的宽字符。这典型地仅应用于多字节编码为单字节的字符（例如 UTF-8 中的 U+0000-U+007F）。
4) 对字符数组 [beg, end) 中每个字符，写入对应的加宽字符到 dst 所指向的字符数组中的相继位置。

加宽始终返回宽字符，但只保证来自基础源字符集 (C++23 前)基础字符集 (C++23 前)的字符拥有唯一良好定义的加宽变换，它也保证是可逆的（通过 narrow()）。实践中，所有多字节表示为单字节的字符通常都被加宽为其宽字符对应，而剩下的可能单字节值通常被映射为同一占位值，典型地为 CharT(-1) 。

如果加宽有意义，那么保持 is() 所知的所有字符分类类别。

参数

c | - | 要转换的字符
dflt | - | 转换失败时产生的默认值
beg | - | 指向要转换的字符数组中首字符的指针
end | - | 指向要转换的字符数组的尾后一位置的指针
dst | - | 指向要填充的字符数组首元素的指针

返回值

1,3) 加宽的字符
2,4) end

示例

#include <locale>
#include <iostream>

void try_widen(const std::ctype<wchar_t>& f, char c)
{
    wchar_t w = f.widen(c);
    std::cout << "单字节字符 " << +(unsigned char)c
              << " 加宽为 " << +w << '\n';
}

int main()
{
    std::locale::global(std::locale("cs_CZ.iso88592"));
    auto& f = std::use_facet<std::ctype<wchar_t>>(std::locale());
    std::cout << std::hex << std::showbase << "在 Czech ISO-8859-2 区域设置下：\n";
    try_widen(f, 'a');
    try_widen(f, '\xdf'); // ISO-8859-2 中的德文字母 ß (U+00df)
    try_widen(f, '\xec'); // ISO-8859-2 中的捷克文字母 ě (U+011b)

    std::locale::global(std::locale("cs_CZ.utf8"));
    auto& f2 = std::use_facet<std::ctype<wchar_t>>(std::locale());
    std::cout << "在 Czech UTF-8 区域设置下：\n";
    try_widen(f2, 'a');
    try_widen(f2, '\xdf');
    try_widen(f2, '\xec');
}

输出：

在 Czech ISO-8859-2 区域设置下：
单字节字符 0x61 加宽为 to 0x61
单字节字符 0xdf 加宽为 to 0xdf
单字节字符 0xec 加宽为 to 0x11b
在 Czech UTF-8 区域设置下：
单字节字符 0x61 加宽为 to 0x61
单字节字符 0xdf 加宽为 to 0xffffffff
单字节字符 0xec 加宽为 to 0xffffffff

参阅

narrow | 调用 do_narrow (公开成员函数)
widen | 拓宽字符 (std::basic_ios<CharT,Traits> 的公开成员函数)
btowc | 若可能，则加宽单字节窄字符为宽字符 (函数)


std::ctype<CharT>::~ctype

< cpp‎ | locale‎ | ctype

定义于头文件 <locale>
protected: ~ctype();

析构 std::ctype 平面。此析构函数为受保护且为虚（由于基类析构函数为虚）。 std::ctype 类型对象，同大多数平面，只能在最后一个实装此平面的 std::locale 离开作用域时，或若用户定义导出自 std::ctype 并实现公开构造函数，才会被销毁。

示例

#include <iostream>
#include <locale>
struct Destructible_ctype : public std::ctype<wchar_t>
{
    Destructible_ctype(std::size_t refs = 0) : ctype(refs) {}
    // 注意：隐式析构函数为公开
};
int main()
{
    Destructible_ctype dc;
    // std::ctype<wchar_t> c;  // 编译错误：受保护析构函数
}


std::ctype_base

< cpp‎ | locale
定义于头文件 <locale>
class ctype_base;

类 std::ctype_base 列出 std::ctype 平面所继承的字符分类类别。

成员类型

mask
 未指定的位掩码类型 (BitmaskType) （枚举、整数类型或 bitset ）
(typedef)

成员常量

space [静态] | 鉴别空白字符分类的 mask 值 (公开静态成员常量)
print [静态] | 鉴别可打印字符分类的 mask 值 (公开静态成员常量)
cntrl [静态] | 鉴别控制字符分类的 mask 值 (公开静态成员常量)
upper [静态] | 鉴别大写字符分类的 mask 值 (公开静态成员常量)
lower [静态] | 鉴别小写字符分类的 mask 值 (公开静态成员常量)
alpha [静态] | 鉴别字母字符分类的 mask 值 (公开静态成员常量)
digit [静态] | 鉴别数字字符分类的 mask 值 (公开静态成员常量)
punct [静态] | 鉴别标点字符分类的 mask 值 (公开静态成员常量)
xdigit [静态] | 鉴别十六进制数字字符分类的 mask 值 (公开静态成员常量)
blank [静态] (C++11) | 鉴别空格字符分类的 mask 值 (公开静态成员常量)
alnum [静态] | alpha | digit (公开静态成员常量)
graph [静态] | alnum | punct (公开静态成员常量)

参阅

ctype | 定义字符分类表 (类模板)
ctype<char> | std::ctype 对于 char 类型的特化 (类模板特化)
ctype_byname | 表示系统提供的具名本地环境的 std::ctype (类模板)


std::ctype_byname

< cpp‎ | locale
定义于头文件 <locale>
template< class CharT >
class ctype_byname : public std::ctype <CharT>;

std::ctype_byname 是封装指定于其构造的本地环境的字符分类规则的 std::ctype 平面。

标准库提供二个特化

定义于头文件 <locale>
std::ctype_byname<char> | 提供窄字符分类。此分类用表格查找字符分类
std::ctype_byname<wchar_t> | 提供宽字符分类

成员类型

成员类型 | 定义
mask | ctype<CharT>::mask

成员函数

(构造函数) | 构造新的 ctype_byname 平面 (公开成员函数)
(析构函数) | 析构 ctype_byname 平面 (受保护成员函数)

std::ctype_byname::ctype_byname

explicit ctype_byname( const char* name, std::size_t refs = 0 ); |
explicit ctype_byname( const std::string & name, std::size_t refs = 0 ); | (C++11 起)

为名为 name 的本地环境构造新的 std::ctype_byname 平面。

refs 用于资源管理：在销毁最后一个保有平面的 std::locale 对象时，若 refs == 0 ，则实现销毁平面对象。否则，不销毁对象。

参数

name | - | 本地环境的名称
refs | - | 链接到该平面的引用数

std::ctype_byname::~ctype_byname

protected:
~ctype_byname();

销毁平面。

继承自 std::ctype<CharT>

成员类型

成员类型 | 定义
char_type | CharT

成员对象

成员名 类型
static std::locale::id id
[静态]
 本地环境的 id
(公开静态成员常量)
若 CharT 为 char ，则继承 std::ctype<char> 的下列成员
static const std::size_t table_size
[静态]
 分类表的大小，至少为 256
(公开静态成员常量)

成员函数

is
 调用 do_is
(std::ctype<CharT> 的公开成员函数)
scan_is
 调用 do_scan_is
(std::ctype<CharT> 的公开成员函数)
scan_not
 调用 do_scan_not
(std::ctype<CharT> 的公开成员函数)
toupper
 调用 do_toupper
(std::ctype<CharT> 的公开成员函数)
tolower
 调用 do_tolower
(std::ctype<CharT> 的公开成员函数)
widen
 调用 do_widen
(std::ctype<CharT> 的公开成员函数)
narrow
 调用 do_narrow
(std::ctype<CharT> 的公开成员函数)
若 CharT 为 char ，则继承 std::ctype<char> 的下列成员
table
 获得字符分类表
(std::ctype<char> 的公开成员函数)
classic_table
[静态]
 获得 "C" 本地环境字符分类表
(std::ctype<char> 的公开静态成员函数)

受保护成员函数

do_toupper
[虚]
 转换一个或多个字符为大写
(std::ctype<CharT> 的虚受保护成员函数)
do_tolower
[虚]
 转换一个或多个字符为小写
(std::ctype<CharT> 的虚受保护成员函数)
do_widen
[虚]
 将一或多个字符从 char 转换为 charT
(std::ctype<CharT> 的虚受保护成员函数)
do_narrow
[虚]
 将一个或多个字符从 charT 转换为 char
(std::ctype<CharT> 的虚受保护成员函数)
若 CharT 为 char ，则不继承 std::ctype 的下列成员
do_is
[虚]
 分类字符或字符序列
(std::ctype<CharT> 的虚受保护成员函数)
do_scan_is
[虚]
 定位序列中首个符合给定分类的字符
(std::ctype<CharT> 的虚受保护成员函数)
do_scan_not
[虚]
 定位序列中首个不符合给定分类的字符
(std::ctype<CharT> 的虚受保护成员函数)

继承自 std::ctype_base

成员类型

类型 | 定义
mask | 未指定的位掩码类型（枚举、整数类型或 bitset ）

成员常量

space [静态] | 鉴别空白字符分类的 mask 值 (公开静态成员常量)
print [静态] | 鉴别可打印字符分类的 mask 值 (公开静态成员常量)
cntrl [静态] | 鉴别控制字符分类的 mask 值 (公开静态成员常量)
upper [静态] | 鉴别大写字符分类的 mask 值 (公开静态成员常量)
lower [静态] | 鉴别小写字符分类的 mask 值 (公开静态成员常量)
alpha [静态] | 鉴别字母字符分类的 mask 值 (公开静态成员常量)
digit [静态] | 鉴别数字字符分类的 mask 值 (公开静态成员常量)
punct [静态] | 鉴别标点字符分类的 mask 值 (公开静态成员常量)
xdigit [静态] | 鉴别十六进制数字字符分类的 mask 值 (公开静态成员常量)
blank [静态] (C++11) | 鉴别空格字符分类的 mask 值 (公开静态成员常量)
alnum [静态] | alpha | digit (公开静态成员常量)
graph [静态] | alnum | punct (公开静态成员常量)

注意

C++11 前显式特化 std::ctype_byname<char> 作为单独入口列于头文件 <locale> 。 C++11 中因为缺陷 #1298 被移除，但它仍是被要求的特化，只是像 std::ctype_byname<wchar_t> 一般。

示例

#include <iostream>
#include <locale>

int main()
{
    wchar_t c = L'\u00de'; // 大写字母 thorn

    std::locale loc("C");

    std::cout << "isupper('Þ', C locale) returned "
               << std::boolalpha << std::isupper(c, loc) << '\n';

    loc = std::locale(loc, new std::ctype_byname<wchar_t>("en_US.utf8"));

    std::cout << "isupper('Þ', C locale with Unicode ctype) returned "
              << std::boolalpha << std::isupper(c, loc) << '\n';
}

输出：

isupper('Þ', C locale) returned false
isupper('Þ', C locale with Unicode ctype) returned true

参阅

ctype | 定义字符分类表 (类模板)
ctype<char> | std::ctype 对于 char 类型的特化 (类模板特化)


std::ctype_byname<char>

< cpp‎ | locale
定义于头文件 <locale>
template<>
class ctype_byname : public std::ctype <char>;

此 std::ctype_byname 的特化封装 char 类型的字符分类特性。同其基类 std::ctype<char> 而不同于通用的 std::ctype_byname ，它用表格查找分类字符。

成员类型

成员类型 | 定义
mask | ctype<char>::mask

成员函数

(构造函数) | 构造新的 ctype_byname<char> 平面 (公开成员函数)
(析构函数) | 析构 ctype_byname<char> 平面 (受保护成员函数)

继承自 std::ctype<char>

成员类型

成员类型 | 定义
char_type | char

成员对象

成员名 | 类型
id (static) | std::locale::id
table_size (static const) | std::size_t 分类表的大小，至少为 256

成员函数

table | 获得字符分类表 (std::ctype<char> 的公开成员函数)
classic_table [静态] | 获得 "C" 本地环境字符分类表 (std::ctype<char> 的公开静态成员函数)
is | 用分类表分类字符或字符序列 (std::ctype<char> 的公开成员函数)
scan_is | 用分类表定位序列中首个符合给定分类的字符 (std::ctype<char> 的公开成员函数)
scan_not | 用分类表定位序列中首个不符合给定分类的字符 (std::ctype<char> 的公开成员函数)
toupper | 调用 do_toupper (std::ctype<CharT> 的公开成员函数)
tolower | 调用 do_tolower (std::ctype<CharT> 的公开成员函数)
widen | 调用 do_widen (std::ctype<CharT> 的公开成员函数)
narrow | 调用 do_narrow (std::ctype<CharT> 的公开成员函数)

受保护成员函数

do_toupper [虚] | 转换一个或多个字符为大写 (std::ctype<CharT> 的虚受保护成员函数)
do_tolower [虚] | 转换一个或多个字符为小写 (std::ctype<CharT> 的虚受保护成员函数)
do_widen [虚] | 将一或多个字符从 char 转换为 charT (std::ctype<CharT> 的虚受保护成员函数)
do_narrow [虚] | 将一个或多个字符从 charT 转换为 char (std::ctype<CharT> 的虚受保护成员函数)

继承自 std::ctype_base

成员类型

类型 | 定义
mask | 未指定的位掩码类型（枚举、整数类型或 bitset ）

成员常量

space [静态] | 鉴别空白字符分类的 mask 值 (公开静态成员常量)
print [静态] | 鉴别可打印字符分类的 mask 值 (公开静态成员常量)
cntrl [静态] | 鉴别控制字符分类的 mask 值 (公开静态成员常量)
upper [静态] | 鉴别大写字符分类的 mask 值 (公开静态成员常量)
lower [静态] | 鉴别小写字符分类的 mask 值 (公开静态成员常量)
alpha [静态] | 鉴别字母字符分类的 mask 值 (公开静态成员常量)
digit [静态] | 鉴别数字字符分类的 mask 值 (公开静态成员常量)
punct [静态] | 鉴别标点字符分类的 mask 值 (公开静态成员常量)
xdigit [静态] | 鉴别十六进制数字字符分类的 mask 值 (公开静态成员常量)
blank [静态] (C++11) | 鉴别空格字符分类的 mask 值 (公开静态成员常量)
alnum [静态] | alpha | digit (公开静态成员常量)
graph [静态] | alnum | punct (公开静态成员常量)

示例

#include <iostream>
#include <locale>

int main()
{
    char c = '\xde'; // 大写字母 thorn

    std::locale loc("C");

    std::cout << "isupper('Þ', C locale) returned "
               << std::boolalpha << std::isupper(c, loc) << '\n';

    loc = std::locale(loc, new std::ctype_byname<char>("en_US.utf8"));

    std::cout << "isupper('Þ', C locale with Unicode ctype<char>) returned "
              << std::boolalpha << std::isupper(c, loc) << '\n';

    loc = std::locale(loc, new std::ctype_byname<char>("is_IS.iso88591"));

    std::cout << "isupper('Þ', C locale with Islandic ctype<char>) returned "
              << std::boolalpha << std::isupper(c, loc) << '\n';
}

输出：

isupper('Þ', C locale) returned false
isupper('Þ', C locale with Unicode ctype<char>) returned false
isupper('Þ', C locale with Islandic ctype<char>) returned true

参阅

ctype | 定义字符分类表 (类模板)
ctype<char> | std::ctype 对于 char 类型的特化 (类模板特化)


std::ctype<char>

< cpp‎ | locale
定义于头文件 <locale>
template<>
class ctype<char>;

此 std::ctype 的特化为类型 char 封装字符分类特性。不同于使用虚函数的通用 std::ctype ，此特化用表查找分类字符（通常会更快）。

基类 std::ctype <char> 实现等价于最小 "C" 本地环境的字符分类。若用非默认的分类表参数，构造为 std::ctype_byname <char> 或用户定义的导出平面，则能扩展或修改分类规则。所有 std::istream 的有格式输入函数都要求在输入分析中将 std::ctype <char> 用于字符分类。

cpp/locale/ctype base cpp/locale/locale/facet

继承图

成员类型

成员类型 | 定义
char_type | char

成员函数

(构造函数) | 构造新的 std::ctype <char> 平面 (公开成员函数)
(析构函数) | 析构 std::ctype <char> 平面 (受保护成员函数)
table | 获得字符分类表 (公开成员函数)
classic_table [静态] | 获得 "C" 本地环境字符分类表 (公开静态成员函数)
is | 用分类表分类字符或字符序列 (公开成员函数)
scan_is | 用分类表定位序列中首个符合给定分类的字符 (公开成员函数)
scan_not | 用分类表定位序列中首个不符合给定分类的字符 (公开成员函数)
toupper | 调用 do_toupper (std::ctype<CharT> 的公开成员函数)
tolower | 调用 do_tolower (std::ctype<CharT> 的公开成员函数)
widen | 调用 do_widen (std::ctype<CharT> 的公开成员函数)
narrow | 调用 do_narrow (std::ctype<CharT> 的公开成员函数)

受保护成员函数

do_toupper [虚] | 转换一个或多个字符为大写 (std::ctype<CharT> 的虚受保护成员函数)
do_tolower [虚] | 转换一个或多个字符为小写 (std::ctype<CharT> 的虚受保护成员函数)
do_widen [虚] | 将一或多个字符从 char 转换为 charT (std::ctype<CharT> 的虚受保护成员函数)
do_narrow [虚] | 将一个或多个字符从 charT 转换为 char (std::ctype<CharT> 的虚受保护成员函数)

成员对象

static std::locale::id id [静态] | locale 的 id (公开静态成员常量)
static const std::size_t table_size [静态] | 分类表的大小，至少 256 (公开静态成员常量)

继承自 std::ctype_base

成员类型

类型 | 定义
mask | 未指定的位掩码类型（枚举、整数类型或 bitset ）

成员常量

space [静态] | 鉴别空白字符分类的 mask 值 (公开静态成员常量)
print [静态] | 鉴别可打印字符分类的 mask 值 (公开静态成员常量)
cntrl [静态] | 鉴别控制字符分类的 mask 值 (公开静态成员常量)
upper [静态] | 鉴别大写字符分类的 mask 值 (公开静态成员常量)
lower [静态] | 鉴别小写字符分类的 mask 值 (公开静态成员常量)
alpha [静态] | 鉴别字母字符分类的 mask 值 (公开静态成员常量)
digit [静态] | 鉴别数字字符分类的 mask 值 (公开静态成员常量)
punct [静态] | 鉴别标点字符分类的 mask 值 (公开静态成员常量)
xdigit [静态] | 鉴别十六进制数字字符分类的 mask 值 (公开静态成员常量)
blank [静态] (C++11) | 鉴别空格字符分类的 mask 值 (公开静态成员常量)
alnum [静态] | alpha | digit (公开静态成员常量)
graph [静态] | alnum | punct (公开静态成员常量)

示例

下列示例演示修改 ctype<char> 以记号化逗号分隔值

#include <iostream>
#include <vector>
#include <locale>
#include <sstream>

// 此 ctype 平面分类逗号和换行符为空白符
struct csv_whitespace : std::ctype<char> {
    static const mask* make_table()
    {
        // 复制 "C" 本地环境表
        static std::vector<mask> v(classic_table(), classic_table() + table_size);
        v[','] |=  space;  // 逗号将被分类为空白符
        v[' '] &= ~space;      // 空格将不被分类为空白符
        return &v[0];
    }
    csv_whitespace(std::size_t refs = 0) : ctype(make_table(), false, refs) {}
};

int main()
{
    std::string in = "Column 1,Column 2,Column 3\n123,456,789";
    std::string token;

    std::cout << "default locale:\n";
    std::istringstream s1(in);
    while(s1 >> token)
            std::cout << "  " << token << '\n';

    std::cout << "locale with modified ctype:\n";
    std::istringstream s2(in);
    s2.imbue(std::locale(s2.getloc(), new csv_whitespace));
    while(s2 >> token)
            std::cout << "  " << token<< '\n';
}

输出：

default locale:
  Column
  1,Column
  2,Column
  3
  123,456,789
locale with modified ctype:
  Column 1
  Column 2
  Column 3
  123
  456
  789

参阅

ctype | 定义字符分类表 (类模板)
ctype_base | 定义字符分类类别 (类模板)
ctype_byname | 为具名本地环境创建 ctype 平面 (类模板)


std::ctype<char>::classic_table

< cpp‎ | locale‎ | ctype char
定义于头文件 <locale> |
static const mask* classic_table() throw(); | (C++11 前)
static const mask* classic_table() noexcept; | (C++11 起)

返回匹配最小 "C" 本地环境所用分类的分类表。

参数

（无）

返回值

指向分类表（大小为 std::ctype<char>::table_size 的数组）中首元素的指针。

注意

默认构造的 std::ctype <char> 平面用此表分类。

示例

本节未完成
原因：暂无示例


std::ctype<char>::ctype

< cpp‎ | locale‎ | ctype char
定义于头文件 <locale>
explicit ctype( const mask* tbl = 0, bool del = false, std::size_t refs = 0);

创建 std::ctype <char> 平面并转发起始引用计数 refs 给基类构造函数 locale::facet::facet() 。

若 tbl 为空，则所有分类函数使用 classic_table() 。否则， tbl 必须是指向大小至少为 std::ctype <char>::table_size 的掩码数组首元素的指针，而此平面的所有分类成员函数使用该数组。

若 del 为 true ，则假设该数组以 new[] 分配，而此平面的析构函数将调用 delete[] tbl 。

参数

tbl | - | 使用的分类表或空指针
del | - | 指示是否需要删除表的指示器。
refs | - | 起始引用计数

示例

本节未完成
原因：暂无示例


std::ctype<char>::is

< cpp‎ | locale‎ | ctype char
定义于头文件 <locale> |
bool is(mask m, char c) const; | (1)
const char* is(const char* low, const char* high, mask* vec) const; | (2)
1) 检查字符 c 是否按照成员函数 table() 所返回的分类表，以掩码 m 分类。等效地计算 table()[(unsigned char)c] & m 。
2) 对字符数组 [low, high) 中每个字符，从成员函数 table() 所返回的分类表读取其完整分类掩码（即计算 table()[ (unsigned char)*p] ），并存储它于 vec 所指向数组的对应元素。

若 (unsigned char)c >= std::ctype <char>::table_size ，则以实现定义值取代 table()[(unsigned char)c] ，可能对于 c 的不同值不同。

参数

c | - | 要分类的字符
m | - | 用于分类单个字符的掩码
low | - | 指向要分类的字符数组中首字符的指针
high | - | 要分类的字符数组的尾后一位置指针
vec | - | 指向要填充的掩码数组首元素的指针

返回值

1) 若 c 在 table() 中以 m 分类则为 true
2) high

注意

不同于初等模板 std::ctype ，此特化在分类字符时不进行虚函数调用。为定制行为，导出类可提供非默认分类表给基类构造函数。

示例

本节未完成
原因：暂无示例

参阅

do_is
[虚]
 分类字符或字符序列
(std::ctype<CharT> 的虚受保护成员函数)


std::ctype<char>::scan_is

< cpp‎ | locale‎ | ctype char
定义于头文件 <locale> |
const char* scan_is (mask m, const char* beg, const char* end) const; | (1)

在字符数组 [beg, end) 中定位满足分类掩码 m 的首个字符，即满足 table()[(unsigned char) c] & m 会返回 true 的首个 c 。

若 (unsigned char)c >= std::ctype <char>::table_size ，则以实现定义值取代 table()[(unsigned char)c] ，可能对于 c 的不同值不同。

参数

m | - | 要搜索的掩码
beg | - | 指向要搜索的字符数组中首字符的指针
end | - | 要搜索的字符数组的尾后一位置指针

返回值

指向 [beg, end) 中首个满足掩码的字符的指针，或若找不到这种字符则为 end 。

注意

不同于初等模板 std::ctype ，此特化在分类字符时不进行虚函数调用。为定制行为，导出类可提供非默认分类表给基类构造函数。

示例

#include <locale>
#include <iostream>
#include <iterator>

int main()
{
    std::locale loc("");
    auto& f = std::use_facet<std::ctype<char>>(loc);

    // 跳过直至首个字母
    char s1[] = "      \t\t\n  Test";
    const char* p1 = f.scan_is(std::ctype_base::alpha, std::begin(s1), std::end(s1));
    std::cout << "'" << p1 << "'\n";

    // 跳过直至首个字符
    char s2[] = "123456789abcd";
    const char* p2 = f.scan_is(std::ctype_base::alpha, std::begin(s2), std::end(s2));
    std::cout << "'" << p2 << "'\n";
}

输出：

'Test'
'abcd'

参阅

do_scan_is [虚] | 定位序列中首个符合给定分类的字符 (std::ctype<CharT> 的虚受保护成员函数)
scan_not | 用分类表定位序列中首个不符合给定分类的字符 (公开成员函数)


std::ctype<char>::scan_not

< cpp‎ | locale‎ | ctype char
定义于头文件 <locale> |
const char* scan_not (mask m, const char* beg, const char* end) const; | (1)

在字符数组 [beg, end) 中定位不满足分类掩码 m 的首个字符，即满足 table()[(unsigned char) c] & m 会返回 false 的首个 c 。

若 (unsigned char)c >= std::ctype <char>::table_size ，则以实现定义值取代 table()[(unsigned char)c] ，可能对于 c 的不同值不同。

参数

m | - | 要搜索的掩码
beg | - | 指向要搜索的字符数组中首字符的指针
end | - | 要搜索的字符数组的尾后一位置指针

返回值

指向 [beg, end) 中首个不满足掩码的字符的指针，或若找不到这种字符则为 end 。

注意

不同于初等模板 std::ctype ，此特化在分类字符时不进行虚函数调用。为定制行为，导出类可提供非默认分类表给基类构造函数。

示例

#include <locale>
#include <iostream>
#include <iterator>

int main()
{
    auto& f = std::use_facet<std::ctype<char>>(std::locale());

    // 跳过前导空白符
    char s1[] = "      \t\t\n  Test";
    const char* p1 = f.scan_not(std::ctype_base::space, std::begin(s1), std::end(s1));
    std::cout << "'" << p1 << "'\n";

    // 跳过前导数位
    char s2[] = "123456789abcd";
    const char* p2 = f.scan_not(std::ctype_base::digit, std::begin(s2), std::end(s2));
    std::cout << "'" << p2 << "'\n";
}

输出：

'Test'
'abcd'

参阅

do_scan_not [虚] | 定位序列中首个不符合给定分类的字符 (std::ctype<CharT> 的虚受保护成员函数)
scan_is | 用分类表定位序列中首个符合给定分类的字符 (公开成员函数)


std::ctype<char>::table

< cpp‎ | locale‎ | ctype char
定义于头文件 <locale> |
const mask* table() const throw(); | (C++11 前)
const mask* table() const noexcept; | (C++11 起)

返回此 std::ctype <char> 实例的构造函数中提供的分类表，或若未提供分类表，则返回 classic_table() 的副本。

参数

（无）

返回值

指向分类表（大小为 std::ctype<char>::table_size 的数组）中首元素的指针。

示例

本节未完成
原因：暂无示例


std::ctype<char>::~ctype

< cpp‎ | locale‎ | ctype char
定义于头文件 <locale>
protected: ~ctype();

析构 std::ctype <char> 平面。此析构函数受保护且为虚（由于基类析构函数为虚）。，类似大多数平面，只能在实装此平面的最后的 std::locale 对象离开作用域时，或若用户定义类派生自 std::ctype <char> 并实现公开析构函数， std::ctype <char> 类型对象才被析构。

若在构造此 std::ctype <char> 的实例时，提供了定制的分类表而构造函数的第二参数（布尔 del ）为 true ，则此析构函数执行 delete[] table() 。


std::has_facet

< cpp‎ | locale
定义于头文件 <locale> |
template< class Facet > bool has_facet( const locale& loc ) throw(); | (C++11 前)
template< class Facet > bool has_facet( const locale& loc ) noexcept; | (C++11 起)

检查 locale loc 是否实装平面 Facet 。

参数

loc - 要查询的 locale 对象

返回值

若当前 locale loc 中安装了平面 Facet 则返回 true ，否则返回 false 。

示例

#include <iostream>
#include <locale>

// 最小定制平面
struct myfacet : public std::locale::facet {
    static std::locale::id id;
};

std::locale::id myfacet::id;

int main()
{
    // loc 是加上 myfacet 的 "C" 本地环境
    std::locale loc(std::locale::classic(), new myfacet);
    std::cout << std::boolalpha
              << "Can loc classify chars? "
              << std::has_facet<std::ctype<char>>(loc) << '\n'
              << "Can loc classify char32_t? "
              << std::has_facet<std::ctype<char32_t>>(loc) << '\n'
              << "Does loc implement myfacet? "
              << std::has_facet<myfacet>(loc) << '\n';
}

输出：

Can loc classify chars? true
Can loc classify char32_t? false
Does loc implement myfacet? true

参阅

locale | 用以封装文化差异的多态刻面的集合 (类)
use_facet | 从本地环境获得一个刻面 (函数模板)


std::isalnum(std::locale)

< cpp‎ | locale
定义于头文件 <locale>
template< class charT >
bool isalnum( charT ch, const locale& loc );

检查给定字符是否为给定 locale 的 std::ctype 平面分类为字母数字字符。

参数

ch | - | 字符
loc | - | 本地环境

返回值

若字符被分类为字母数字则返回 true ，否则返回 false 。

可能的实现

template< class charT >
bool isalnum( charT ch, const std::locale& loc ) {
    return std::use_facet<std::ctype<charT>>(loc).is(std::ctype_base::alnum, ch);
}

示例

演示以不同本地环境使用 isalnum() （ OS 特定）

#include <iostream>
#include <locale>
int main()
{
    const wchar_t c = L'\u2135'; // 数学符号 aleph

    std::locale loc1("C");
    std::cout << "isalnum('ℵ', C locale) returned "
               << std::boolalpha << std::isalnum(c, loc1) << '\n';

    std::locale loc2("en_US.UTF-8");
    std::cout << "isalnum('ℵ', Unicode locale) returned "
              << std::boolalpha << std::isalnum(c, loc2) << '\n';
}

输出：

isalnum('ℵ', C locale) returned false
isalnum('ℵ', Unicode locale) returned true

参阅

isalnum | 检查字符是否为字母或数字 (函数)
iswalnum | 检查宽字符是否为字母数字 (函数)


std::isalpha(std::locale)

< cpp‎ | locale
定义于头文件 <locale>
template< class charT >
bool isalpha( charT ch, const locale& loc );

检查给定的字符是否为给定 locale 的 std::ctype 平面分类为字母字符。

参数

ch | - | 字符
loc | - | 本地环境

返回值

若字符被分类为字母则返回 true ，否则返回 false 。

可能的实现

template< class charT >
bool isalpha( charT ch, const std::locale& loc ) {
    return std::use_facet<std::ctype<charT>>(loc).is(std::ctype_base::alpha, ch);
}

示例

演示以不同本地环境使用 isalpha() （ OS 特定）。

#include <iostream>
#include <locale>
int main()
{
    const wchar_t c = L'\u042f'; // 西里尔大写字母 ya

    std::locale loc1("C");
    std::cout << "isalpha('Я', C locale) returned "
               << std::boolalpha << std::isalpha(c, loc1) << '\n';

    std::locale loc2("en_US.UTF8");
    std::cout << "isalpha('Я', Unicode locale) returned "
              << std::boolalpha << std::isalpha(c, loc2) << '\n';
}

输出：

isalpha('Я', C locale) returned false
isalpha('Я', Unicode locale) returned true

参阅

isalpha | 检查字符是否为字母 (函数)
iswalpha | 检查宽字符是否为字母 (函数)


std::isblank(std::locale)

< cpp‎ | locale
定义于头文件 <locale> |
template< class charT > bool isblank( charT ch, const locale& loc ); | (C++11 起)

检查给定字符是否为给定 locale 的 ctype 平面分类为空格字符。

参数

ch | - | 字符
loc | - | 本地环境

返回值

若字符被分类为空格字符则返回 true ，否则返回 false 。

可能的实现

template< class charT >
bool isblank( charT ch, const std::locale& loc ) {
    return std::use_facet<std::ctype<charT>>(loc).is(std::ctype_base::blank, ch);
}

示例

演示以不同本地环境使用 isblank() （ OS 限定）

#include <iostream>
#include <locale>

void try_with(wchar_t c, const char* loc)
{
    std::wcout << "isblank('" << c << "', locale(\"" << loc << "\")) returned " << std::boolalpha
               << std::isblank(c, std::locale(loc)) << '\n';
}
int main()
{
    const wchar_t IDEO_SPACE = L'\u3000'; // Unicode 字符‘象形字间隔’
    try_with(IDEO_SPACE, "C");
    try_with(IDEO_SPACE, "en_US.UTF-8");
}

输出：

isblank(' ', locale("C")) returned false
isblank(' ', locale("en_US.UTF-8")) returned true

参阅

isblank (C++11) | 检查字符是否为空白字符 (函数)
iswblank (C++11) | 检查宽字符是否为空白字符 (函数)


std::iscntrl(std::locale)

< cpp‎ | locale
定义于头文件 <locale>
template< class charT >
bool iscntrl( charT ch, const locale& loc );

检查给定字符是否为给定 locale 的 std::ctype 平面分类为控制字符。

参数

ch | - | 字符
loc | - | 本地环境

返回值

若字符被分类为控制字符则返回 true ，否则返回 false 。

可能的实现

template< class charT >
bool iscntrl( charT ch, const std::locale& loc ) {
    return std::use_facet<std::ctype<charT>>(loc).is(std::ctype_base::cntrl, ch);
}

示例

演示以不同本地环境使用 iscntrl() （ OS 限定）。

#include <iostream>
#include <locale>
int main()
{
    const wchar_t CCH = L'\u0094'; // Unicode 中的破坏性退格

    std::locale loc1("C");
    std::cout << "iscntrl(CCH, C locale) returned "
              << std::boolalpha << std::iscntrl(CCH, loc1) << '\n';

    std::locale loc2("en_US.UTF8");
    std::cout << "iscntrl(CCH, Unicode locale) returned "
              << std::boolalpha << std::iscntrl(CCH, loc2) << '\n';
}

输出：

iscntrl(CCH, C locale) returned false
iscntrl(CCH, Unicode locale) returned true

参阅

iscntrl | 检查字符是否为控制字符 (函数)
iswcntrl | 检查宽字符是否为控制字符 (函数)


std::isdigit(std::locale)

< cpp‎ | locale
定义于头文件 <locale>
template< class charT >
bool isdigit( charT ch, const locale& loc );

检查给定字符是否为给定 locale 的 std::ctype 平面分类为数字。

参数

ch | - | 字符
loc | - | 本地环境

返回值

若字符被分类为数字则返回 true ，否则返回 false 。

可能的实现

template< class charT >
bool isdigit( charT ch, const std::locale& loc ) {
    return std::use_facet<std::ctype<charT>>(loc).is(std::ctype_base::digit, ch);
}

示例

#include <iostream>
#include <locale>
#include <string>
#include <set>

struct jdigit_ctype : std::ctype<wchar_t>
{
    std::set<wchar_t> jdigits{L'一',L'二',L'三',L'四',L'五',L'六',L'七',L'八',L'九',L'十'};
    bool do_is(mask m, char_type c) const {
        if ((m & digit) && jdigits.count(c))
            return true; // 中文数字将被分类为数字
        return ctype::do_is(m, c); // 将剩下的留给亲类
    }
};

int main()
{

    std::wstring text = L"123一二三１２３";
    std::locale loc(std::locale(""), new jdigit_ctype);

    std::locale::global(std::locale(""));
    std::wcout.imbue(std::locale());

    for(wchar_t c : text)
        if(std::isdigit(c, loc))
            std::wcout << c << " is a digit\n";
        else
            std::wcout << c << " is NOT a digit\n";
}

输出：

1 is a digit
2 is a digit
3 is a digit
一 is a digit
二 is a digit
三 is a digit
１ is NOT a digit
２ is NOT a digit
３ is NOT a digit

参阅

isdigit | 检查字符是否为数字 (函数)
iswdigit | 检查宽字符是否为数字 (函数)


std::isgraph(std::locale)

< cpp‎ | locale
定义于头文件 <locale>
template< class charT >
bool isgraph( charT ch, const locale& loc );

检查给定字符是否为给定 locale 的 std::ctype 平面分类为图形字符（即可打印字符，除了空格）。

参数

ch | - | 字符
loc | - | 本地环境

返回值

若字符被分类为图形字符则返回 true ，否则返回 false 。

可能的实现

template< class charT >
bool isgraph( charT ch, const std::locale& loc ) {
    return std::use_facet<std::ctype<charT>>(loc).is(std::ctype_base::graph, ch);
}

示例

演示以不同本地环境使用 isgraph() （ OS 限定）。

#include <iostream>
#include <locale>
int main()
{
    const wchar_t c = L'\u2a0c'; // 四重积分

    std::locale loc1("C");
    std::cout << "isgraph('⨌', C locale) returned "
               << std::boolalpha << std::isgraph(c, loc1) << '\n';

    std::locale loc2("en_US.UTF-8");
    std::cout << "isgraph('⨌', Unicode locale) returned "
              << std::boolalpha << std::isgraph(c, loc2) << '\n';
}

输出：

isgraph('⨌', C locale) returned false
isgraph('⨌', Unicode locale) returned true

参阅

isgraph | 检查字符是否为图形字符 (函数)
iswgraph | 检查宽字符是否为图形字符 (函数)


std::islower(std::locale)

< cpp‎ | locale
定义于头文件 <locale>
template< class charT >
bool islower( charT ch, const locale& loc );

检查给定字符是否为给定 locale 的 std::ctype 平面分类为小写字母字符。

参数

ch | - | 字符
loc | - | 本地环境

返回值

若给定字符被分类为小写则返回 true ，否则返回 false 。

可能的实现

template< class charT >
bool islower( charT ch, const std::locale& loc ) {
    return std::use_facet<std::ctype<charT>>(loc).is(std::ctype_base::lower, ch);
}

示例

演示用不同本地环境使用 islower() （ OS 特定）。

#include <iostream>
#include <locale>
int main()
{
    const wchar_t c = L'\u03c0'; // 希腊文小写字母 pi

    std::locale loc1("C");
    std::cout << "islower('π', C locale) returned "
               << std::boolalpha << std::islower(c, loc1) << '\n';

    std::locale loc2("en_US.UTF8");
    std::cout << "islower('π', Unicode locale) returned "
              << std::boolalpha << std::islower(c, loc2) << '\n';
}

可能的输出：

islower('π', C locale) returned false
islower('π', Unicode locale) returned true

参阅

islower | 检查字符是否为小写 (函数)
iswlower | 检查宽字符是否为小写 (函数)


std::isprint(std::locale)

< cpp‎ | locale
定义于头文件 <locale>
template< class charT >
bool isprint( charT ch, const locale& loc );

检查给定字符是否为给定 locale 的 std::ctype 平面分类为可打印字符（包含空格）。

参数

ch | - | 字符
loc | - | 本地环境

返回值

若字符被分类为可打印则返回 true ，否则返回 false 。

可能的实现

template< class charT >
bool isprint( charT ch, const std::locale& loc ) {
    return std::use_facet<std::ctype<charT>>(loc).is(std::ctype_base::print, ch);
}

示例

演示以不同本地环境使用 isprint() （ OS 限定）。

#include <iostream>
#include <locale>
int main()
{
    const wchar_t c = L'\u2122'; // 商标标记

    std::locale loc1("C");
    std::cout << "isprint('™', C locale) returned "
               << std::boolalpha << std::isprint(c, loc1) << '\n';

    std::locale loc2("en_US.UTF-8");
    std::cout << "isprint('™', Unicode locale) returned "
              << std::boolalpha << std::isprint(c, loc2) << '\n';
}

输出：

isprint('™', C locale) returned false
isprint('™', Unicode locale) returned true

参阅

isprint | 检查字符是否为打印字符 (函数)
iswprint | 检查宽字符是否为打印字符 (函数)


std::ispunct(std::locale)

< cpp‎ | locale
定义于头文件 <locale>
template< class charT >
bool ispunct( charT ch, const locale& loc );

检查给定字符是否被给定 locale 的 std::ctype 平面分类为标点字符。

参数

ch | - | 字符
loc | - | 本地环境

返回值

若字符被分类为标点则返回 true ，否则返回 false 。

可能的实现

template< class charT >
bool ispunct( charT ch, const std::locale& loc ) {
    return std::use_facet<std::ctype<charT>>(loc).is(std::ctype_base::punct, ch);
}

示例

演示以不同本地环境使用 ispunct() （ OS 限定）。

#include <iostream>
#include <locale>
int main()
{
    const wchar_t c = L'\u214b'; // 倒转的和号

    std::locale loc1("C");
    std::cout << "ispunct('⅋', C locale) returned "
               << std::boolalpha << std::ispunct(c, loc1) << '\n';

    std::locale loc2("en_US.UTF-8");
    std::cout << "ispunct('⅋', Unicode locale) returned "
              << std::boolalpha << std::ispunct(c, loc2) << '\n';
}

输出：

isalpha('⅋', C locale) returned false
isalpha('⅋', Unicode locale) returned true

参阅

ispunct | 检查字符是否为标点符 (函数)
iswpunct | 检查宽字符是否为标点字符 (函数)


std::isspace(std::locale)

< cpp‎ | locale
定义于头文件 <locale>
template< class charT >
bool isspace( charT ch, const locale& loc );

检查给定字符是否为给定 locale 的 ctype 平面分类为空白字符。

参数

ch | - | 字符
loc | - | 本地环境

返回值

若字符被分类为空白字符则返回 true ，否则返回 false 。

可能的实现

template< class charT >
bool isspace( charT ch, const std::locale& loc ) {
    return std::use_facet<std::ctype<charT>>(loc).is(std::ctype_base::space, ch);
}

示例

演示以不同本地环境使用 isspace() （ OS 限定）。

#include <iostream>
#include <locale>

void try_with(wchar_t c, const char* loc)
{
    std::wcout << "isspace('" << c << "', locale(\"" << loc << "\")) returned "
               << std::boolalpha << std::isspace(c, std::locale(loc)) << '\n';
}

int main()
{
    const wchar_t EM_SPACE = L'\u2003'; // Unicode 字符 'EM SPACE'
    try_with(EM_SPACE, "C");
    try_with(EM_SPACE, "en_US.UTF8");
}

输出：

isspace(' ', locale("C")) returned false
isspace(' ', locale("en_US.UTF8")) returned true

参阅

isspace | 检查字符是否为空白间隔字符 (函数)
iswspace | 检查宽字符是否为空白间隔字符 (函数)


std::isupper(std::locale)

< cpp‎ | locale
定义于头文件 <locale>
template< class charT >
bool isupper( charT ch, const locale& loc );

检查给定字符是否为给定 locale 的 std::ctype 平面分类为大写字母字符。

参数

ch | - | 字符
loc | - | 本地环境

返回值

若给定字符被分类为大写则返回 true ，否则返回 false 。

可能的实现

template< class charT >
bool isupper( charT ch, const std::locale& loc ) {
    return std::use_facet<std::ctype<charT>>(loc).is(std::ctype_base::upper, ch);
}

示例

演示以不同的本地环境使用 isupper() （ OS 限定）。

#include <iostream>
#include <locale>
int main()
{
    const wchar_t c = L'\u00de'; // 大写字母 thorn

    std::locale loc1("C");
    std::cout << "isupper('Þ', C locale) returned "
               << std::boolalpha << std::isupper(c, loc1) << '\n';

    std::locale loc2("en_US.UTF8");
    std::cout << "isupper('Þ', Unicode locale) returned "
              << std::boolalpha << std::isupper(c, loc2) << '\n';
}

输出：

isupper('Þ', C locale) returned false
isupper('Þ', Unicode locale) returned true

参阅

isupper | 检查字符是否为大写字符 (函数)
iswupper | 检查宽字符是否为大写 (函数)


std::isxdigit(std::locale)

< cpp‎ | locale
定义于头文件 <locale>
template< class charT >
bool isxdigit( charT ch, const locale& loc );

检查给定字符是否为给定 locale 的 std::ctype 平面分类为十六进制数位。

参数

ch | - | 字符
loc | - | 本地环境

返回值

若字符被分类为十六进制数位则返回 true ，否则返回 false 。

可能的实现

template< class charT >
bool isxdigit( charT ch, const std::locale& loc ) {
    return std::use_facet<std::ctype<charT>>(loc).is(std::ctype_base::xdigit, ch);
}

示例

本节未完成
原因：暂无示例

参阅

isxdigit | 检查字符是为十六进制字符 (函数)
iswxdigit | 检查宽字符是否为十六进制字符 (函数)


std::lconv

< cpp‎ | locale
定义于头文件 <clocale>
struct lconv;

类 std::lconv 含有 C 本地环境定义的数值和货币格式化规则。此结构体的对象可由 std::localeconv 获得。 std::lconv 的成员为 char 类型和 char* 类型值。除了 decimal_point ，每个 char* 成员都可以指向空字符（即为空 C 字符串）。 char 类型成员均为非负数，而且若任一者在当前 C 本地环境中不可用，则为 CHAR_MAX 。

成员对象

非货币数值格式化参数

char* decimal_point | 用作小数点的字符 (公开成员对象)
char* thousands_sep | 用于在小数点前分隔数位组的字符 (公开成员对象)
char* grouping | 字符串，其元素指示数位组的大小 (公开成员对象)

货币数值格式化参数

char* mon_decimal_point | 用作小数点的字符 (公开成员对象)
char* mon_thousands_sep | 用于在小数点前分隔数位组的字符 (公开成员对象)
char* mon_grouping | 字符串，其元素指示数位组的大小 (公开成员对象)
char* positive_sign | 用于指示非负货币量的字符串 (公开成员对象)
char* negative_sign | 用于指示负货币量的字符串 (公开成员对象)

本地货币数值格式化参数

char* currency_symbol | 当前 C 本地环境中用于通货的符号 (公开成员对象)
char frac_digits | 货币量中小数点后显示的位数 (公开成员对象)
char p_cs_precedes | 若 currency_symbol 置于非负值前则为 1 ，于其后则为 ​0​ (公开成员对象)
char n_cs_precedes | 若 currency_symbol 置于负值前则为 1 ，于其后则为 ​0​ (公开成员对象)
char p_sep_by_space | 指示 currency_symbol 、 positive_sign 及非负货币值的分隔 (公开成员对象)
char n_sep_by_space | 指示 currency_symbol 、 positive_sign 及负货币值的分隔 (公开成员对象)
char p_sign_posn | 指示非负货币值中 positive_sign 的位置 (公开成员对象)
char n_sign_posn | 指示负货币值中 negative_sign 的位置 (公开成员对象)

国际货币数值格式化参数

char* int_curr_symbol | 当前 C 本地环境中用作国际通货名的字符串 (公开成员对象)
char int_frac_digits | 国际货币量中小数点后显示的位数 (公开成员对象)
char int_p_cs_precedes (C++11) | 若 int_curr_symbol 置于非负值前则为 1 ，于其后则为 ​0​ (公开成员对象)
char int_n_cs_precedes (C++11) | 若 int_curr_symbol 置于负值前则为 1 ，于其后则为 ​0​ (公开成员对象)
char int_p_sep_by_space (C++11) | 指示 int_curr_symbol 、 positive_sign 及非负国际货币值的分隔 (公开成员对象)
char int_n_sep_by_space (C++11) | 指示 int_curr_symbol 、 positive_sign 及负国际货币值的分隔 (公开成员对象)
char int_p_sign_posn (C++11) | 指示非负国际货币值中 positive_sign 的位置 (公开成员对象)
char int_n_sign_posn (C++11) | 指示负国际货币值中 positive_sign 的位置 (公开成员对象)

按照数值转译 grouping 和 mon_grouping 所指向的 C 字符串。遇到终止 '\0' 时，假设最后见到的值为剩下的数位重复。若遇到 CHAR_MAX ，则不再将数位分组。典型的每次三位分组是 "\003" 。

p_sep_by_space 、 n_sep_by_space 、 int_p_sep_by_space 、 int_n_sep_by_space 的值转译如下：

0 | 通货符号和值间无空格分隔
1 | 符号紧贴通货符号，值为空格所分隔
2 | 符号紧贴值，通货符号为空格所分隔

p_sign_posn 、 n_sign_posn 、 int_p_sign_posn 、 int_n_sign_posn 的值转译如下：

0 | 括号围绕值，并用通货符号表示符号
1 | 符号在值与通货符号前
2 | 符号在值与通货符号后
3 | 符号在通货符号前
4 | 符号在通货符号后

示例

#include <clocale>
#include <iostream>

int main()
{
    std::setlocale(LC_ALL, "ja_JP.UTF-8");
    std::lconv* lc = std::localeconv();
    std::cout << "Japanese currency symbol: " << lc->currency_symbol
              << '(' << lc->int_curr_symbol << ")\n";
}

输出：

Japanese currency symbol: ￥(JPY )

参阅

localeconv | 查询当前本地环境的数值和货币格式化细节 (函数)
numpunct | 定义数值标点规则 (类模板)
moneypunct | 定义 std::money_get 与 std::money_put 所用的货币格式解析器的参数 (类模板)


std::locale

< cpp‎ | locale
定义于头文件 <locale>
class locale;

std::locale 类型对象是不可变平面的不可变索引集。 C++ 输入/输出库的每个流对象与一个 std::locale 对象关联，并用其平面分析及格式化所有数据。另外， locale 对象与每个 std::basic_regex 对象关联。 locale 对象亦可在标准容器和算法中用作进行字符串对照的谓词，而且能被直接访问，以获得或修改其所保有的平面。

C++ 程序中构造的每个 locale 至少保有下列标准平面，但程序可以定义额外特化，或全新的平面，并将它们添加到任何既存的 locale 对象。

受支持平面
std::collate <char> | std::collate <wchar_t>
std::ctype <char> | std::ctype <wchar_t>
std::codecvt <char,char,mbstate_t>
std::codecvt <char16_t,char,mbstate_t> 		std::codecvt <char32_t,char,mbstate_t>
std::codecvt <wchar_t,char,mbstate_t>
std::moneypunct <char>
std::moneypunct <char,true> 		std::moneypunct <wchar_t>
std::moneypunct <wchar_t,true>
std::money_get <char> | std::money_get <wchar_t>
std::money_put <char> | std::money_put <wchar_t>
std::numpunct <char> | std::numpunct <wchar_t>
std::num_get <char> | std::num_get <wchar_t>
std::num_put <char> | std::num_put <wchar_t>
std::time_get <char> | std::time_get <wchar_t>
std::time_put <char> | std::time_put <wchar_t>
std::messages <char> | std::messages <wchar_t>

在内部， locale 对象实现为如同它是一个指向（以 std::locale::id 索引的）的数组的引用计数指针，数组元素为指向平面的引用计数指针：复制 locale 只复制一个指针，并增加几个引用计数。为维护标准 C++ 库线程安全保证（不同对象上的操作始终为线程安全）， locale 引用计数和每个平面的引用计数都以线程安全方式更新，类似 std::shared_ptr 。

成员类型

id | 平面索引类型：每个平面类必须声明或继承此类型的公开静态成员 (类)
facet | 所有平面分类的分类：任何分类的每个 facet 都从此类型导出 (类)
category | int (typedef)

成员对象

none [静态] | 指示无平面类别的 category 类型零值 (公开静态成员常量)
collate [静态] | category 类型位掩码值 (公开静态成员常量)
ctype [静态] | category 类型位掩码值 (公开静态成员常量)
monetary [静态] | category 类型位掩码值 (公开静态成员常量)
numeric [静态] | category 类型位掩码值 (公开静态成员常量)
time [静态] | category 类型位掩码值 (公开静态成员常量)
messages [静态] | category 类型位掩码值 (公开静态成员常量)
all [静态] | collate | ctype | monetary | numeric | time | messages (公开静态成员常量)

成员函数

(构造函数) | 构造新的 locale (公开成员函数)
(析构函数) | 析构 locale 和其引用计数变为零的平面 (公开成员函数)
operator= | 替换 locale (公开成员函数)
combine | 以复制自另一 locale 的编译时鉴别的平面构造 locale (公开成员函数)
name | 返回 locale 的名称，或若它无名则为 "*" (公开成员函数)
operator==operator!= (C++20 中移除) | locale 对象之间的相等性比较 (公开成员函数)
operator() | 用此 locale 的 collate 刻面以字典序比较两个字符串 (公开成员函数)
global [静态] | 更改全局本地环境 (公开静态成员函数)
classic [静态] | 获得到 "C" 本地环境的引用 (公开静态成员函数)

示例

演示本地环境影响的程序（跨平台）的典型前文

#include <iostream>
#include <locale>

int main()
{
    std::wcout << "User-preferred locale setting is " << std::locale("").name().c_str() << '\n';
    // 在启动时，全局本地环境是 "C" 本地环境
    std::wcout << 1000.01 << '\n';
    // 以用户偏好的本地环境替换 C++ 本地环境和 C 本地环境
    std::locale::global(std::locale(""));
    // 将来的宽字符输出使用新的全局本地环境
    std::wcout.imbue(std::locale());
    // 再次输出同一数字
    std::wcout << 1000.01 << '\n';
}

可能的输出：

User-preferred locale setting is en_US.UTF8
1000.01
1,000.01

参阅

use_facet | 从本地环境获得一个刻面 (函数模板)
has_facet | 检查本地环境是否实现特定的刻面 (函数模板)
imbue | 设置本地环境 (std::ios_base 的公开成员函数)
getloc | 返回当前本地环境 (std::ios_base 的公开成员函数)


std::locale::classic

< cpp‎ | locale‎ | locale
定义于头文件 <locale>
static const locale& classic();

获得到实现经典 "C" 本地环境语义的 C++ 本地环境的引用。此本地环境不同于全局本地环境，不能改变。

参数

（无）

返回值

返回到 "C" 本地环境的引用。

注意

一些标准要求的平面，如 UTF-8/UTF-32 转换平面 std::codecvt <char32_t, char, std::mbstate_t > ，无 "C" 本地环境中的等价版本，然而它们存在于 std::locale::classic() 返回的 locale 中，同任何其他构造于 C++ 程序中的 locale 。

示例

本节未完成
原因：暂无示例

参阅

global
[静态]
 更改全局本地环境
(公开静态成员函数)


std::locale::combine

< cpp‎ | locale‎ | locale
定义于头文件 <locale>
template< class Facet >
locale combine( const locale& other ) const;

构造 locale 对象，结果为 *this 的副本，除了 Facet 类型平面复制自 other 。

返回值

新的无名 locale 。

异常

若 other 不实装 Facet 则为 std::runtime_error 。

示例

#include <iostream>
#include <locale>

int main()
{
    const double number = 1000.25;
    std::cout << "\"C\" locale: " << number << '\n';
    std::locale loc = std::locale().combine<std::numpunct<char>>(std::locale("en_US.UTF8"));
    std::cout.imbue(loc);
    std::cout << "\"C\" locale with en_US numpunct: " << number << '\n';
}

输出：

"C" locale: 1000.25
"C" locale with en_US numpunct: 1,000.25

参阅

(构造函数)
 构造新的 locale
(公开成员函数)


std::locale::facet

< cpp‎ | locale‎ | locale
定义于头文件 <locale>
class locale::facet;

std::locale::facet 是平面的基类。它提供共用基类，使得 locale 能存储指向其所实装的平面的指针于单个有下标容器中，而且它抽象对于平面引用计数的支持。添加平面到 locale 时， locale 自增平面中的引用计数（通过实现特定的机制）。凡在析构或修改 locale 时，它自减每个它不再实装的平面中的引用计数。平面的引用计数变为零时， locale 进行 delete static_cast<std::locale::facet*>(f) ，其中 f 是指向平面的指针。

成员函数

(构造函数) | 构造带指定引用计数的新 facet (受保护成员函数)
operator= | 复制赋值运算符被删除 (受保护成员函数)
(析构函数) [虚] | 析构函数为受保护虚函数 (虚受保护成员函数)

示例

本节未完成
原因：暂无示例

参阅

id
 平面索引类型：每个平面类必须声明或继承此类型的公开静态成员
(类)


std::locale::facet::facet

< cpp‎ | locale‎ | locale‎ | facet
定义于头文件 <locale> |
explicit facet( std::size_t refs = 0 ); | (1)
facet(const facet&) = delete; | (2)

1) 创建拥有起始引用计数 refs 的平面。若 refs 非零，则在最后引用它的 locale 离开作用域时不删除该 facet 。拥有静态或动态存储期的平面应始终以非零 refs 构造。

2) 复制构造函数被； std::locale::facet 不可复制。


std::locale::global

< cpp‎ | locale‎ | locale
定义于头文件 <locale>
static locale global( const locale& loc );

以 loc 替换全局 C++ 本地环境，这表示将来所有对 std::locale 的默认构造函数的调用将返回 loc 的副本。若 loc 拥有名称，则亦如同用 std::setlocale ( LC_ALL, loc.name().c_str()); 替换 C 本地环境。此函数是修改全局 C++ 本地环境的唯一方式，否则全局 C++ 本地环境等价于程序启动时的 std::locale::classic() 。

参阅

loc - 新的全局 C++ locale

返回值

全局 C++ locale 的先前值。

示例

本节未完成
原因：暂无示例

参阅

(构造函数) | 构造新的 locale (公开成员函数)
classic [静态] | 获得到 "C" 本地环境的引用 (公开静态成员函数)
setlocale | 获取和设置当前 C 本地环境 (函数)


std::locale::id

< cpp‎ | locale‎ | locale
定义于头文件 <locale>
class locale::id;

类 std::locale::id 提供本地环境片面的实现限定标识。每个导出自 std::locale::facet 的类都必须拥有名为 id 的 std::locale::id 类型公开静态成员，而每个 std::locale 对象维护其所实装的 facet 列表，以其 id 索引。

拥有相同 id 的 facet 属于同一平面类别，并且在添加到 locale 对象时彼此替换。

成员函数

(构造函数) | 构造新的 id (公开成员函数)
operator= | 复制赋值运算符被删除 (公开成员函数)

示例

下列代码展示如何构造最小的定制 facet 。

#include <iostream>
#include <locale>

struct myfacet : std::locale::facet
{
    myfacet(std::size_t refs = 0) : facet(refs) {}
    static std::locale::id id;
};

std::locale::id myfacet::id;

int main()
{
    std::locale myloc(std::locale(), new myfacet);
    std::cout << "has_facet<myfacet>(myloc) returns " << std::boolalpha
              << std::has_facet<myfacet>(myloc) << '\n';
}

输出：

has_facet<myfacet>(myloc) returns true

参阅

facet
 所有平面分类的分类：任何分类的每个 facet 都从此类型导出
(类)


std::locale::id::id

< cpp‎ | locale‎ | locale‎ | id
定义于头文件 <locale> |
id(); | (1)
id(const id&) = delete; | (2)

1) 默认构造函数：创建拥有实现指定内容的 std::locale::id 类型对象。

2) 复制构造函数被删除； std::locale::id 不可复制。

注意

因为 locale 和 facet 必须对拥有静态存储期的 IO 流对象如 std::cout 可用，典型的实现在静态初始化期间（在构造函数为静态对象运行之前），让隐式的默认构造函数零初始化 std::locale::id 的内容，而在首次添加 facet 到任何 locale 时， locale 完成 facet 的 id 的初始化。


std::locale::locale

< cpp‎ | locale‎ | locale
定义于头文件 <locale> |  |
 | (1) |
locale() throw(); |  |  | (C++11 前)
locale() noexcept; |  |  | (C++11 起)
 | (2) |
locale( const locale& other ) throw(); |  |  | (C++11 前)
locale( const locale& other ) noexcept; |  |  | (C++11 起)
explicit locale( const char* std_name ); | (3) |
explicit locale( const std::string & std_name ); | (4) | (C++11 起)
locale( const locale& other, const char* std_name, category cat ); | (5) |
locale( const locale& other, const std::string & std_name, category cat ); | (6) | (C++11 起)
template< class Facet > locale( const locale& other, Facet* f ); | (7) |
locale( const locale& other, const locale& one, category cat ); | (8) |

构造新的 locale 对象。

1) 默认构造函数。构造全局 C++ 本地环境的副本，它是最近用作 std::locale::global 的参数的 locale ，或若未曾调用 std::locale::global 则为 std::locale::classic 的副本。
2) 复制构造函数。构造 other 的副本。
3-4) 构造拥有特定 std_name 的系统本地环境（如 "C" 或 "POSIX" 或 "en_US.UTF-8" 或 "English_US.1251" ）的副本，若操作系统支持这种本地环境。以此方式构造的 locale 拥有名称。
5-6) 构造 other 的副本，除了 cat 参数所鉴别的所有平面，这些平面从其 std_name 所标识的系统本地环境复制。以此方式构造的 locale 拥有名称，当且仅当 other 拥有名称。
7) 构造 other 的副本，除了 Facet 类型平面（典型地从实参类型推导），该平面从参数 facet 安装。若 facet 为空指针，则构造的 locale 为 other 的完整副本。以此方式构造的 locale 无名称。
8) 构造 other 的副本，除了 cat 参数所鉴别的所有平面，这些平面从 one 复制。若 other 与 one 都拥有名称，则产生的 locale 拥有名称。

参数

other | - | 要复制的另一 locale
std_name | - | 要使用的系统本地环境名称
f | - | 指向要与 other 合并的平面的指针
cat | - | 用于鉴别要与 other 合并的平面的 locale::category
one | - | 接收平面来源的另一 locale

异常

3,5) 若操作系统无名为 std_name 的本地环境，或若 std_name 为空指针则为 std::runtime_error 。
4,6) 若操作系统无名为 std_name 的本地环境则为 std::runtime_error 。
7,8) 可能抛出实现定义的异常。

注解

典型地以直接获得自 new 表达式的参数 f 为第二参数调用重载 7 ： locale 负责从其自身的析构函数调用匹配的 delete 。

示例

#include <codecvt>
#include <iostream>
#include <locale>

std::ostream& operator<< (std::ostream& os, std::locale const& loc)
{
    if (loc.name().length() <= 80) { return os << loc.name() << '\n'; }

    for (const auto c : loc.name())
    {
        c != ';' ? os << c : os << "\n    ";
    }
    return os << '\n';
}

int main()
{
    std::locale l1;
        // l1 为经典 "C" 本地环境副本
    std::locale l2("en_US.UTF-8");
        // l2 为 Unicode 本地环境
    std::locale l3(l1, l2, std::locale::ctype);
        // l3 为 "C" ，除了 ctype 为 Unicode
    std::locale l4(l1, new std::codecvt_utf8<wchar_t>);
        // l4 为 "C" ，除了 codecvt
    std::cout
        << "Locale names:\n"
        << "l1: " << l1 << "l2: " << l2
        << "l3: " << l3 << "l4: " << l4;
}

可能的输出：

Locale names:
l1: C
l2: en_US.UTF-8
l3: LC_CTYPE=en_US.UTF-8
    LC_NUMERIC=C
    LC_TIME=C
    LC_COLLATE=C
    LC_MONETARY=C
    LC_MESSAGES=C
    LC_PAPER=C
    LC_NAME=C
    LC_ADDRESS=C
    LC_TELEPHONE=C
    LC_MEASUREMENT=C
    LC_IDENTIFICATION=C
l4: *

参阅

(析构函数)
 析构 locale 和其引用计数变为零的平面
(公开成员函数)


std::locale::name

< cpp‎ | locale‎ | locale
定义于头文件 <locale>
std::string name() const;

返回操作系统所知的 locale 名称，例如 "POSIX" 或 "en_US.UTF8" 或 "English_United States.1252" 。若该 locale 不是系统提供的本地环境，则返回字符串 "*" 。

返回值

locale 的名称，或若无名则为 "*" 。

示例

#include <locale>
#include <iostream>
#include <string>

int main()
{
    std::locale loc(std::locale(), new std::ctype<char>);
    std::cout << "The default locale is " << std::locale().name() << '\n'
              << "The user's locale is " << std::locale("").name() << '\n'
              << "A nameless locale is " << loc.name() << '\n';
}

输出：

The default locale is C
The user's locale is en_US.UTF8
A nameless locale is *

参阅

(构造函数)
 构造新的 locale
(公开成员函数)


std::locale::operator()

< cpp‎ | locale‎ | locale
template< class CharT, class Traits, class Alloc >

bool operator()( const basic_string<CharT,Traits,Alloc>& s1,

const basic_string<CharT,Traits,Alloc>& s2) const;

按照此 locale 的 std::collate <charT> 平面所定义的比较规则，比较二个 string 参数 s1 与 s2 。此运算符允许以任何拥有 collate 平面的 locale 对象为标准算法（如 std::sort ）和有序容器（ std::set ）中的二元谓词。

参数

s1 | - | 要比较的第一字符串
s2 | - | 要比较的第二字符串

返回值

若 s1 按字典序小于 s2 则为 true ，否则为 false 。

可能的实现

template<class CharT, class Traits, class Alloc >
bool operator()(const std::basic_string<CharT,Traits,Alloc>& s1,
                const std::basic_string<CharT,Traits,Alloc>& s2) const;
{
    return std::use_facet<std::collate<CharT>>(*this).compare(
                                         s1.data(), s1.data() + s1.size(),
                                         s2.data(), s2.data() + s2.size()   ) < 0;
}

示例

string 的 vector 能以 locale 对象为比较器，按照非默认的本地环境排序：

#include <locale>
#include <algorithm>
#include <vector>
#include <string>
#include <cassert>

int main()
{
    std::vector<std::wstring> v = {L"жил", L"был", L"кот"};
    std::sort(v.begin(), v.end(), std::locale("ru_RU.UTF8"));
    assert(v[0] == L"был");
    assert(v[1] == L"жил");
    assert(v[2] == L"кот");
}

参阅

collate
 定义字典序比较和字符串的散列
(类模板)


std::locale::operator=

< cpp‎ | locale‎ | locale
定义于头文件 <locale> |
const locale& operator=( const locale& other ) throw(); | (C++11 前)
const locale& operator=( const locale& other ) noexcept; | (C++11 起)

创建 other 的副本，替换 *this 的内容。增加 other 所保有的所有平面的引用计数。减少 *this 先前所保有的所有平面的引用计数，并删除引用计数成为零的平面。

返回值

返回 *this ，它现在是 other 的副本。

示例

本节未完成
原因：暂无示例

参阅

(构造函数)
 构造新的 locale
(公开成员函数)


std::locale::operator==, operator!=

< cpp‎ | locale‎ | locale
定义于头文件 <locale> |  |
bool operator==( const locale& other ) const; | (1) |
bool operator!=( const locale& other ) const; | (2) | (C++20 前)

测试二个本地环境的相等性。若具名 locale 的名称相等则认为它们相等。若无名 locale 互为彼此的副本则认为它们相等。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

other - 要比较的 std::locale 对象

返回值

1) 若 other 为 *this 的副本或拥有等同名称则为 true ，否则为 false 。
2) 若 other 为 *this 的副本或拥有等同名称则为 false ，否则为 true 。

示例

本节未完成
原因：暂无示例

参阅

(构造函数) | 构造新的 locale (公开成员函数)
name | 返回 locale 的名称，或若它无名则为 "*" (公开成员函数)


std::locale::~locale

< cpp‎ | locale‎ | locale
定义于头文件 <locale>
~locale();

非虚析构函数，减少 *this 所保有的所有刻面的引用计数。删除引用计数变为零的刻面。

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

(构造函数)
 构造新的 locale
(公开成员函数)


std::localeconv

< cpp‎ | locale
定义于头文件 <clocale>
std::lconv * localeconv();

localeconv 函数获得指向 std::lconv 类型静态对象的指针，该对象表示当前 C 本地环境的数值和货币格式化规则。

参数

（无）

返回值

指向当前 std::lconv 对象的指针。

注意

通过返回的指针修改对象是未定义行为。

std::localeconv 修改静态对象，从不同线程调用它而不同步是未定义行为。

示例

#include <clocale>
#include <iostream>

int main()
{
    std::setlocale(LC_ALL, "ja_JP.UTF-8");
    std::lconv* lc = std::localeconv();
    std::cout << "Japanese currency symbol: " << lc->currency_symbol
              << '(' << lc->int_curr_symbol << ")\n";
}

输出：

Japanese currency symbol: ￥(JPY )

参阅

setlocale | 获取和设置当前 C 本地环境 (函数)
lconv | std::localeconv 所返回的格式化细节 (类)


std::messages

< cpp‎ | locale
定义于头文件 <locale>
template< class CharT >
class messages;

类模板 std::messages 是标准 locale 平面，它封装从消息目录取得字符串，例如 GNU gettext 或 POSIX catgets 所提供者。

消息源是实现定义的。

cpp/locale/messages base cpp/locale/locale/facet

继承图

标准库提供二个孤立（独立于本地环境）的特化：

定义于头文件 <locale>
std::messages<char> | 访问窄字符串消息目录
std::messages<wchar_t> | 访问宽字符串消息目录

另外， C++ 程序中的每个 locale 对象还实装这些特化的其自身（本地环境限定）版本。

成员类型

成员类型 | 定义
char_type | CharT
string_type | std::basic_string<CharT>

成员函数

(构造函数) | 构造新的 messages 平面 (公开成员函数)
(析构函数) | 析构 messages 平面 (受保护成员函数)
open | 调用 do_open (公开成员函数)
get | 调用 do_get (公开成员函数)
close | 调用 do_close (公开成员函数)

成员对象

static std::locale::id id
 locale 的 id
(公开成员对象)

受保护成员函数

do_open [虚] | 打开具名消息目录 (虚受保护成员函数)
do_get [虚] | 从打开的消息目录获取消息 (虚受保护成员函数)
do_close [虚] | 关闭消息目录 (虚受保护成员函数)

继承自 std::messages_base

类型 | 定义
catalog | /* 未指定的有符号整数类型 */

参阅

messages_base | 定义消息目录类型 (类模板)
messages_byname | 为具名本地环境创建 massages 平面 (类模板)


std::messages<CharT>::close, std::messages<CharT>::do_close

< cpp‎ | locale‎ | messages
定义于头文件 <locale> |
public: void close( catalog c ) const; | (1)
protected: virtual void do_close( catalog c ) const; | (2)

1) 公开成员函数，调用最终导出类的受保护虚成员函数 do_close 。

2) 释放与从 open() 获得的 catalog 类型（继承自 std::messages_base ）值 c 所指代的打开目录关联的实现定义资源。

参数

c - 合法的打开的目录标识符，仍未在其上调用 close()

返回值

（无）

注意

POSIX 系统上，此函数调用通常翻译为调用 catclose() 。 GNU libstdc++ 中，它以 GNU gettext() 实现，并不做任何事。

示例

下列代码演示消息取得：典型的 GNU/Linux 上，它从 /usr/share/locale/de/LC_MESSAGES/sed.mo 读取

#include <iostream>
#include <locale>

int main()
{
    std::locale loc("de_DE.utf8");
    std::cout.imbue(loc);
    auto& facet = std::use_facet<std::messages<char>>(loc);
    auto cat = facet.open("sed", loc);
    if(cat < 0 )
        std::cout << "Could not open german \"sed\" message catalog\n";
    else
        std::cout << "\"No match\" in German: "
                  << facet.get(cat, 0, 0, "No match") << '\n'
                  << "\"Memory exhausted\" in German: "
                  << facet.get(cat, 0, 0, "Memory exhausted") << '\n';
    facet.close(cat);
}

可能的输出：

"No match" in German: Keine Übereinstimmung
"Memory exhausted" in German: Speicher erschöpft

参阅


std::messages<CharT>::get, std::messages<CharT>::do_get

< cpp‎ | locale‎ | messages
定义于头文件 <locale> |
public: string_type get( catalog cat, int set, int msgid, const string_type& dfault ) const; | (1)
protected: virtual string_type do_get( catalog cat, int set, int msgid, const string_type& dfault ) const; | (2)

1) 公开成员函数，调用最终导出类的受保护虚成员函数 do_get 。

2) 用值 set 、 msgid 和 dfault ，以实现定义方式从打开的消息目录 cat 获得消息。若目录中找不到期待 消息，则返回 dfault 的副本。

参数

cat | - | 从 open() 获得且仍未传递给 close() 的标识符
set | - | 实现定义参数， POSIX 中为消息集
msgid | - | 实现定义参数， POSIX 中为消息标识
dfault | - | 要在目录中查找的字符串（若目录使用字符串查找），亦为失败情况下返回的字符串

返回值

来自目录的消息，或若找不到消息则为 dfault 的副本。

注意

POSIX 系统上，此函数调用通常被翻译为对 catgets() 的调用，并原态传递参数 set 、 msgid 和 dfault 给 catgets() 。 GNU libstdc++ 中，此函数忽略 set 和 msgid ，并简单地在要求的本地环境中调用 GNU gettext(dfault) 。

示例

下列代码演示消息取得：典型的 GNU/Linux 上，它从 /usr/share/locale/de/LC_MESSAGES/sed.mo 读取

#include <iostream>
#include <locale>

int main()
{
    std::locale loc("de_DE.utf8");
    std::cout.imbue(loc);
    auto& facet = std::use_facet<std::messages<char>>(loc);
    auto cat = facet.open("sed", loc);
    if(cat < 0 )
        std::cout << "Could not open german \"sed\" message catalog\n";
    else
        std::cout << "\"No match\" in German: "
                  << facet.get(cat, 0, 0, "No match") << '\n'
                  << "\"Memory exhausted\" in German: "
                  << facet.get(cat, 0, 0, "Memory exhausted") << '\n';
    facet.close(cat);
}

可能的输出：

"No match" in German: Keine Übereinstimmung
"Memory exhausted" in German: Speicher erschöpft

参阅


std::messages<CharT>::messages

< cpp‎ | locale‎ | messages

定义于头文件 <locale>
explicit messages( std::size_t refs = 0 );

创建 std::messages 平面并转发引用计数 refs 到基类构造函数 locale::facet::facet() 。

参数

refs - 开始的引用计数


std::messages<CharT>::open, std::messages<CharT>::do_open

< cpp‎ | locale‎ | messages
定义于头文件 <locale> |
public: catalog open( const std::basic_string <char>& name, const std::locale & loc ) const; | (1)
protected: virtual catalog do_open( const std::basic_string <char>& name, const std::locale & loc ) const; | (2)

1) 公开成员函数，调用最终导出类的受保护虚成员函数 do_open 。

2) 获得 catalog 类型（继承自 std::messages_base ）值，能将它传递给 get() 以从 name 所指名的消息目录取得消息。此值可使用直至传递给 close() 为止。

参数

name | - | 要打开的消息目录名称
loc | - | 提供可能为从目录读取消息所要求的额外平面，例如用以进行宽/多字节转换的 std::codecvt 的 locale 对象

返回值

能传递给 get() 和 close() 的非负 catalog 类型值。若无法打开目录则返回负值。

注意

POSIX 系统上，此函数调用通常翻译为调用 catopen() 。 GNU libstdc++ 中，它调用 textdomain 。

实际目录位置是实现定义的：例如对于德文本地环境中的目录 "sed" （以 Unix 工具 'sed' 安装的消息目录），此函数调用所打开的文件可能为 /usr/lib/nls/msg/de_DE/sed.cat, /usr/lib/locale/de_DE/LC_MESSAGES/sed.cat 或 /usr/share/locale/de/LC_MESSAGES/sed.mo 。

示例

下列代码演示消息取得：典型的 GNU/Linux 上，它从 /usr/share/locale/de/LC_MESSAGES/sed.mo 读取

#include <iostream>
#include <locale>

int main()
{
    std::locale loc("de_DE.utf8");
    std::cout.imbue(loc);
    auto& facet = std::use_facet<std::messages<char>>(loc);
    auto cat = facet.open("sed", loc);
    if(cat < 0 )
        std::cout << "Could not open german \"sed\" message catalog\n";
    else
        std::cout << "\"No match\" in German: "
                  << facet.get(cat, 0, 0, "No match") << '\n'
                  << "\"Memory exhausted\" in German: "
                  << facet.get(cat, 0, 0, "Memory exhausted") << '\n';
    facet.close(cat);
}

可能的输出：

"No match" in German: Keine Übereinstimmung
"Memory exhausted" in German: Speicher erschöpft

参阅


std::messages<CharT>::~messages

< cpp‎ | locale‎ | messages

定义于头文件 <locale>
protected: ~messages();

析构 std::messages 平面。此析构函数为受保护且为虚（由于基类析构函数为虚）。 std::messages 类型对象，同大多数平面，只能在最后一个实装此平面的 std::locale 离开作用域时，或若用户定义导出自 std::messages 并实现公开构造函数，才会被销毁。

示例

#include <iostream>
#include <locale>
struct Destructible_messages : public std::messages<wchar_t>
{
    Destructible_messages(std::size_t refs = 0) : messages(refs) {}
    // 注意：隐式析构函数为公开
};
int main()
{
    Destructible_messages dc;
    // std::messages<wchar_t> c;  // 编译错误：受保护析构函数
}


std::messages_base

< cpp‎ | locale
定义于头文件 <locale>
class messages_base;

类 std::messages_base 提供为 std::messages 平面所继承和使用的类型定义。

成员类型

成员类型 | 定义
catalog | /* 未指定的有符号整数类型 */

注意

catalog 在 C++11 中被错误指定为 int ，这于 LWG 问题 #2028 更正，并包含于 C++14 。

参阅

messages
 实现从消息目录获取字符串
(类模板)


std::messages_byname

< cpp‎ | locale
定义于头文件 <locale>
template< class CharT >
class messages_byname : public std::messages <CharT>;

std::messages_byname 是 std::messages 平面，它封装从在其构造时指定的 locale 的消息目录取得字符串。

标准库提供二个特化

定义于头文件 <locale>
std::messages_byname<char> | 窄/多字节字符串消息目录访问
std::messages_byname<wchar_t> | 宽字符串消息目录访问

成员类型

成员类型 | 定义
catalog | std::messages_base<CharT>::catalog
string_type | std::basic_string<CharT>

成员函数

(构造函数) | 构造新的 messages_byname 平面 (公开成员函数)
(析构函数) | 析构 messages_byname 平面 (受保护成员函数)

std::messages_byname::messages_byname

explicit messages_byname( const char* name, std::size_t refs = 0 ); |
explicit messages_byname( const std::string & name, std::size_t refs = 0 ); | (C++11 起)

为名为 name 的本地环境构造新的 std::messages_byname 平面。

refs 用于资源管理：在销毁最后一个保有平面的 std::locale 对象时，若 refs == 0 ，则实现销毁平面对象。否则，不销毁对象。

参数

name | - | 本地环境的名称
refs | - | 链接到该平面的引用数

std::messages_byname::~messages_byname

protected:
~messages_byname();

销毁平面。

继承自 std::messages

成员类型

成员类型 | 定义
char_type | charT
string_type | std::basic_string<charT>

成员对象

成员名 | 类型
id [静态] | std::locale::id

成员函数

open | 调用 do_open (std::messages<CharT> 的公开成员函数)
get | 调用 do_get (std::messages<CharT> 的公开成员函数)
close | 调用 do_close (std::messages<CharT> 的公开成员函数)

受保护成员函数

do_open [虚] | 打开具名消息目录 (std::messages<CharT> 的虚受保护成员函数)
do_get [虚] | 从打开的消息目录获取消息 (std::messages<CharT> 的虚受保护成员函数)
do_close [虚] | 关闭消息目录 (std::messages<CharT> 的虚受保护成员函数)

示例

#include <iostream>
#include <locale>

void try_with(const std::locale& loc)
{
    const std::messages<char>& facet = std::use_facet<std::messages<char> >(loc)
;
    std::messages<char>::catalog cat = facet.open("sed", std::cout.getloc());
    if(cat < 0 )
        std::cout << "Could not open \"sed\" message catalog\n";
    else
        std::cout << "\"No match\" "
                  << facet.get(cat, 0, 0, "No match") << '\n'
                  << "\"Memory exhausted\" "
                  << facet.get(cat, 0, 0, "Memory exhausted") << '\n';
    facet.close(cat);
}
int main()
{
    std::locale loc("en_US.utf8");
    std::cout.imbue(loc);

    try_with(std::locale(loc, new std::messages_byname<char>("de_DE.utf8")));
    try_with(std::locale(loc, new std::messages_byname<char>("fr_FR.utf8")));
    try_with(std::locale(loc, new std::messages_byname<char>("ja_JP.utf8")));
}

可能的输出：

"No match" Keine Übereinstimmung
"Memory exhausted" Speicher erschöpft
"No match" Pas de concordance
"Memory exhausted" Mémoire épuisée
"No match" 照合しません
"Memory exhausted" メモリーが足りません

参阅

messages
 实现从消息目录获取字符串
(类模板)


std::money_base

< cpp‎ | locale
定义于头文件 <locale>
class money_base;

类 std::money_base 提供为 std::moneypunct 、 std::money_get 和 std::money_put 平面所继承并使用的常量。

成员类型

成员类型 | 定义
enum part { none, space, symbol, sign, value }; | 无作用域枚举类型
struct pattern { char field[4]; }; | 货币格式类型
枚举常量 | 解释
none | 容许但不要求空白符，除了在末位置不容许空白符
space | 要求一或多个空白字符
symbol | 要求 moneypunct::curr_symbol 所返回的字符序列
sign | 要求 moneypunct::positive_sign 或 moneypunct::negative_sign 所返回的首个字符
value | 要求绝对数值货币值

注意

货币格式是四个可转换为 std::money_base::part 的 char 的数组。该序列中， symbol 、 sign 和 value 的每一个准确出现一次，而 space 或 none 出现于剩余位置。 none 的值若存在，则不在首位； space 的值若存在，则不在首位或末位。

std::moneypunct 的标准特化所返回的默认格式为 {symbol, sign, none, value} 。

参阅

moneypunct | 定义 std::money_get 与 std::money_put 所用的货币格式解析器的参数 (类模板)
money_get | 从输入字符序列中解析并构造货币值 (类模板)
money_put | 格式化货币值为字符序列以输出 (类模板)


std::money_get

< cpp‎ | locale
定义于头文件 <locale>
template<

class CharT,
class InputIt = std::istreambuf_iterator <CharT>

> class money_get;

类模板 std::money_get 封装从字符流剖析货币值的规则。标准 I/O 操纵符 std::get_money 使用 I/O 流的 locale 的 std::money_get 平面。

cpp/locale/locale/facet

继承图

类型要求

-
InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

特化

标准库提供二个孤立（独立于本地环境）的全特化和二个部分特化：

定义于头文件 <locale>
std::money_get<char> | 分析货币值的窄字符串表示
std::money_get<wchar_t> | 分析货币值的宽字符串表示
std::money_get<char, InputIt> | 用定制输入迭代器分析货币值的窄字符串表示
std::money_get<wchar_t, InputIt> | 用定制输入迭代器分析货币值的宽字符串表示

另外， C++ 程序中构造的每个 locale 对象都实装这些特化的其自身（本地环境限定）版本。

成员类型

成员类型 | 定义
char_type | CharT
string_type | std::basic_string<CharT>
iter_type | InputIt

成员函数

(构造函数) | 构造新的 money_get 平面 (公开成员函数)
(析构函数) | 销毁 money_get 平面 (受保护成员函数)
get | 调用 do_get (公开成员函数)

受保护成员函数

do_get
[虚]
 分析来自输入流的货币值
(虚受保护成员函数)

成员对象

static std::locale::id id
 locale 的 id
(公开成员对象)

示例

#include <iostream>
#include <sstream>
#include <locale>
#include <iomanip>
#include <iterator>
int main()
{
    std::string str = "$1.11 $2.22 $3.33";
    std::cout << std::fixed << std::setprecision(2);

    std::cout << '"' << str << "\" parsed with the I/O manipulator: ";
    std::istringstream s1(str);
    s1.imbue(std::locale("en_US.UTF-8"));
    long double val;
    while(s1 >> std::get_money(val))
        std::cout << val/100 << ' ';
    std::cout << '\n';

    str = "USD  1,234.56";
    std::cout << '"' << str << "\" parsed with the facet directly: ";
    std::istringstream s2(str);
    s2.imbue(std::locale("en_US.UTF-8"));
    auto& f = std::use_facet<std::money_get<char>>(s2.getloc());
    std::ios_base::iostate err;
    std::istreambuf_iterator<char> beg(s2), end;
    f.get(beg, end, true, s2, err, val);
    std::cout << val/100 << '\n';
}

输出：

"$1.11 $2.22 $3.33" parsed with the I/O manipulator: 1.11 2.22 3.33
"USD  1,234.56" parsed with the facet directly: 1234.56

参阅

moneypunct | 定义 std::money_get 与 std::money_put 所用的货币格式解析器的参数 (类模板)
money_put | 格式化货币值为字符序列以输出 (类模板)
get_money (C++11) | 剖析货币值 (函数模板)


std::money_get<CharT,InputIt>::get, do_get

< cpp‎ | locale‎ | money get
定义于头文件 <locale>
public:

iter_type get(iter_type beg, iter_type end, bool intl, std::ios_base & str,

std::ios_base::iostate & err, long double& units) const;
 (1)
iter_type get(iter_type beg, iter_type end, bool intl, std::ios_base & str,
std::ios_base::iostate & err, string_type& digits) const;
 (2)
protected:

virtual iter_type do_get(iter_type beg, iter_type end, bool intl, std::ios_base & str,

std::ios_base::iostate & err, long double& units) const;
 (3)
virtual iter_type do_get(iter_type beg, iter_type end, bool intl, std::ios_base & str,
std::ios_base::iostate & err, string_type& digits) const;
 (4)

剖析来自输入迭代器的货币值，并写结果到 long double 或 string 。

1-2) 公开成员函数，调用最终导出类的成员函数 do_get 。
3-4) 从输入迭代器 beg 读取字符，期待找到按照 str.getloc() 中感染的 std::ctype 平面（下称 ct ）、 str.getloc() 中感染的 std::moneypunct <CharT, intl> 平面（下称 mp ）及获得自 str.flags() 的流格式化标志所指定的规则格式化的货币值。

若输入迭代器 beg 在分析完成前变得等于 end ，则在 err 中一同设置 failbit 和 eofbit 。若分析因另一原因失败，则在 err 中设置 failbit 。无论如何，都不在错误时修改输出参数（ units 或 digits ）。

若分析成功，则不更改 err ，并存储结果于 units 或 digits 。

此函数所用的格式化 pattern 始终为 mp.neg_format() 。

若 mp.grouping() 不容许千分隔符，则将首个遇到的分隔符当做错误，否则将它们当做可选的。

若 money_base::space 或 money_base::none 是 pattern 中的最后元素，则分析器不尝试在分析货币值的其他组分后消耗任何空白符。否则在 money_base::space 出现处消耗一或多个空白字符。

若 str.flags() 中设置了 showbase 标志，则要求通货符号或通货字符串，若未设置，则通货符号可选。

若在格式化模式的 money_base::sign 位置找到 mp.positive_sign() 或 mp.negative_sign() 所返回的字符串的首字符，则消耗之，而在货币值的所有其他组分后期待并消耗剩余字符。若 mp.positive_sign() 与 mp.negative_sign() 均为非空，则要求有符号并匹配这些字符串的首字符之一。若这些字符串之一为空，则符号为可选（而若符号不存在，则结果的符号对应空的字符串的符号）。若两个字符均为空，或拥有相同首字符，则将正号给予结果。若输出参数为 string （ digits ）而结果为负，则存储值 ct.widen('-') 为结果的首字符。

如同按 digits 中出现的顺序释出并放置来自输入的数位，或将它们置于临时缓冲区 buf1 中（若需要则以 ct.widen() 加宽），再用下方式从该缓冲区构造 units 的值：

static const char src[] = "0123456789-";
CharT atoms[sizeof(src)];
ct.widen(src, src + sizeof(src) - 1, atoms);
for (int i = 0; i < n; ++i)
buf2[i] = src[find(atoms, atoms+sizeof(src), buf1[i]) - atoms];
buf2[n] = 0;
sscanf(buf2, "%Lf", &units);

（其中 n 是从输入释出并存储 buf1 的字符数，而 buf2 是另一充分大的字符缓冲区）

返回值

指向辨识为货币字符串输入的合法部分的末字符立即后一位置的迭代器。

注意

假定通货单位为通货的最小非小数单位：美国中为美分，日本中为日元。从而美国本地环境中的输入序列 "$1,056.23" 会令 units 为数字 105623.0 或令 digits 为字符串 "105623" 。

因为若 showbase 关闭则通货符号为可选，但要求整个多字符 negative_sign() ，故给定格式化模式 {sign, value, space, symbol} 、关闭的 showbase 和 "-" 的 negative_sign ，字符串 "-1.23 €" 会分析为 -123 ，而令 "€" 在输入流上留待未消耗，但若 negative_sign 为 "()" ， 则完全消耗字符串 "(1.23 €)" 。

I/O 操纵符 std::get_money 提供到此函数的简化接口。

示例

#include <iostream>
#include <sstream>
#include <locale>

void demo_money_get(std::locale loc, const std::string& input)
{
    std::istringstream str(input);
    str.imbue(loc);
    long double units;
// 注意：下列代码能简单地写成 std::get_money(units)
    std::ios_base::iostate err = std::ios_base::goodbit;
    std::istreambuf_iterator<char> ret =
        std::use_facet<std::money_get<char>>(loc).get(
                 std::istreambuf_iterator<char>(str),
                 std::istreambuf_iterator<char>(),
                 false, str, err, units);
    str.setstate(err);
    std::istreambuf_iterator<char> last{};
    if(str) {
        std::cout << "Successfully parsed '" << str.str() << "' as "
                  << units/100 << " units\n";
        if(ret != last) {
            std::cout << "Remaining content: '";
            std::copy(ret, last, std::ostreambuf_iterator<char>(std::cout));
            std::cout << "'\n";
        } else {
            std::cout << "The input was fully consumed\n";
        }
    } else {
            std::cout << "Parse failed. Unparsed string: '";
            std::copy(ret, last, std::ostreambuf_iterator<char>(std::cout));
            std::cout << "'\n";
    }
}

int main()
{
    demo_money_get(std::locale("en_US.utf8"), "-$5.12 abc");
    demo_money_get(std::locale("ms_MY.utf8"), "(RM5.12) def");
}

输出：

Successfully parsed '-$5.12 abc' as -5.12 units
Remaining content: ' abc'
Successfully parsed '(RM5.12) def' as -5.12 units
Remaining content: ' def'

参阅

moneypunct | 定义 std::money_get 与 std::money_put 所用的货币格式解析器的参数 (类模板)
money_get | 从输入字符序列中解析并构造货币值 (类模板)
get_money (C++11) | 剖析货币值 (函数模板)


std::money_get<CharT,InputIt>::money_get

< cpp‎ | locale‎ | money get

定义于头文件 <locale>
explicit money_get( std::size_t refs = 0 );

创建 std::money_get 平面并转发引用计数 refs 到基类构造函数 locale::facet::facet() 。

参数

refs - 开始的引用计数


std::money_get<CharT,InputIt>::~money_get

< cpp‎ | locale‎ | money get

定义于头文件 <locale>
protected: ~money_get();

析构 std::money_get 平面。此析构函数为受保护且为虚（由于基类析构函数为虚）。 std::money_get 类型对象，同大多数平面，只能在最后一个实装此平面的 std::locale 离开作用域时，或若用户定义导出自 std::money_get 并实现公开构造函数，才会被销毁。

示例

#include <iostream>
#include <locale>
struct Destructible_money_get : public std::money_get<wchar_t>
{
    Destructible_money_get(std::size_t refs = 0) : money_get(refs) {}
    // 注意：隐式析构函数为公开
};
int main()
{
    Destructible_money_get dc;
    // std::money_get<wchar_t> c;  // 编译错误：受保护析构函数
}


std::money_put

< cpp‎ | locale
定义于头文件 <locale>
template<

class CharT,
class OutputIt = std::ostreambuf_iterator <CharT>

> class money_put;

类 std::money_put 封装格式化货币值为字符串所用的规则。标准 I/O 操纵符 std::put_money 使用 I/O 流的 locale 的 std::money_put 平面。

cpp/locale/locale/facet

继承图

类型要求

-
OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。

特化

标准库提供二个孤立（独立于本地环境）的全特化和二个部分特化：

定义于头文件 <locale>
std::money_put<char> | 创建货币值的窄字符串表示
std::money_put<wchar_t> | 创建货币值的宽窄字符串表示
std::money_put<char, OutputIt> | 用定制输入迭代器创建货币值的窄字符串表示
std::money_put<wchar_t, OutputIt> | 用定制输入迭代器创建货币值的宽字符串表示

另外， C++ 程序中构造的每个 locale 对象都实装这些特化的其自身（本地环境限定）版本。

成员类型

成员类型 | 定义
char_type | CharT
string_type | std::basic_string<CharT>
iter_type | OutputIt

成员函数

(构造函数) | 构造新的 money_put 平面 (公开成员函数)
(析构函数) | 销毁 money_put 平面 (受保护成员函数)
put | 调用 do_put (公开成员函数)

受保护成员函数

do_put
[虚]
 格式化货币值并写入到输出流
(虚受保护成员函数)

成员对象

static std::locale::id id
 locale 的 id
(公开成员对象)

示例

#include <iostream>
#include <locale>
#include <iomanip>
#include <iterator>
int main()
{
    // 使用 I/O 操纵符
    std::cout.imbue(std::locale("en_US.UTF-8"));
    std::cout << "american locale: "
               << std::showbase << std::put_money(12345678.9)<< '\n';

    // 直接使用平面
    std::cout.imbue(std::locale("de_DE.UTF-8"));
    std::cout << "german locale: " ;
    auto& f = std::use_facet<std::money_put<char>>(std::cout.getloc());
    f.put({std::cout}, true, std::cout, std::cout.fill(), 12345678.9 );
    std::cout << '\n';
}

输出：

american locale: $123,456.79
german locale: 123.456,79 EUR

参阅

moneypunct | 定义 std::money_get 与 std::money_put 所用的货币格式解析器的参数 (类模板)
money_get | 从输入字符序列中解析并构造货币值 (类模板)
put_money (C++11) | 格式化并输出货币值 (函数模板)


std::money_put<CharT,OutputIt>::money_put

< cpp‎ | locale‎ | money put

定义于头文件 <locale>
explicit money_put( std::size_t refs = 0 );

创建 std::money_put 平面并转发引用计数 refs 到基类构造函数 locale::facet::facet() 。

参数

refs - 开始的引用计数


std::money_put<CharT,OutputIt>::put, do_put

< cpp‎ | locale‎ | money put
定义于头文件 <locale>
public:

iter_type put(iter_type out, bool intl, std::ios_base & f,

char_type fill, long double quant) const;
 (1)
iter_type put(iter_type out, bool intl, std::ios_base & f,
char_type fill, const string_type& quant) const;
 (2)
protected:

virtual iter_type do_put(iter_type out, bool intl, std::ios_base & str,

char_type fill, long double units) const;
 (3)
virtual iter_type do_put(iter_type out, bool intl, std::ios_base & str,
char_type fill, const string_type& digits) const;
 (4)

格式化货币值并写结果到输出流。

1-2) 公开成员函数，调用最终导出类的成员函数 do_put 。
3) 如同用 ct.widen(buf1, buf1 + std::sprintf (buf1, "%.0Lf", units), buf2) 转换数值参数 units 为宽字符串，其中 ct 为 str.getloc() 中感染的 std::ctype 平面，而 buf1 和 buf2 是充分大的字符缓冲区。按后述方式处理、格式化结果字符串 buf2 并输出到 out 。
4) 从字符串参数 digits 采取仅有的可选前导负号（以与 ct.widen('-') 比较确定，其中 ct 为 str.getloc() 中感染的 std::ctype 平面）和立即后随的数位字符（以 ct 分类）为字符序列，按后述方式处理、格式化，并输出到 out 。

给定来自先前步骤的字符序列，若首字符等于 ct.widen('-') ，则调用 mp.neg_format() 获得格式化 pattern ，否则调用 mp.pos_format() ，其中 mp 为 str.getloc() 中感染的 std::moneypunct <CharT, intl> 平面。

依 mp.grouping() 、 mp.frac_digits() 、 mp.decimal_point() 和 mp.thousands_sep() 所要求插入千分隔符和小数点，而将结果字符串置于输出序列中的 value 出现于格式化模式中的位置。

若 str.flags() & str.showbase 非零（使用了 std::showbase 操纵符），则通过调用 mp.curr_symbol() 生成通货符号或字符串，并将它置于输出序列中的 symbol 出现于格式化模式中的位置。

若 mp.positive_sign() （使用正格式模式的情况下）或 mp.negative_sign() （使用负格式模式的情况下）返回带有多于一个字符的字符串，则将首字符置于输出序列中的 sign 出现于格式化模式中的位置，而将剩余字符置于所有其他字符之后，例如格式化模式 {sign, value, space, symbol} 用 123 单位和 "-" 的 negative_sign 会导致 "-1.23 €" ，而 "()" 的 negative_sign 会生成 "(1.23 €)" 。

若为指定格式生成的字符数小于 str.width() 的返回值，则以如下方式，插入 fill 的副本以令输出序列的总长度准确达到 str.width() ：

  • 若 str.flags() & str.adjustfield 等于 str.internal ，则插入填充字符到 none 或 space 出现于格式化模式中的位置。
  • 否则，若 str.flags() & str.adjustfield 等于 str.left ，则后附 fill 的副本到所有其他字符后
  • 否则，将填充字符置于所有其他字符前characters.

最后，调用 str.width(0) 取消任何 std::setw 的效果。

返回值

指向最后产生字符立即后方的迭代器。

注意

假设通货单位为货币的最小非小数单位：美国中为美分，日本中为日元。

示例

#include <iostream>
#include <iomanip>
#include <locale>

struct my_punct : std::moneypunct_byname<char, false> {
    my_punct(const char* name) : moneypunct_byname(name) {}
    string_type do_negative_sign() const { return "()"; }
};

int main()
{
    std::locale loc("ru_RU.utf8");
    std::cout.imbue(loc);
    long double units = -123.45;
    std::cout << "In Russian locale, " << units << " prints as "
              << std::showbase;
// 注意：以下等价于简单的 std::put_money(units)
    std::use_facet<std::money_put<char>>(loc).put(
             {std::cout}, false, std::cout, std::cout.fill(), units);
    std::cout << '\n';

    std::cout.imbue(std::locale(std::cout.getloc(), new my_punct("ru_RU.utf8")));
    std::cout << "With negative_sign set to \"()\", it prints  as ";
    std::use_facet<std::money_put<char>>(loc).put(
             {std::cout}, false, std::cout, std::cout.fill(), units);
    std::cout << '\n';
}

输出：

In Russian locale, -123,45 prints as -1.23 руб
With negative_sign set to "()", it prints  as (1.23 руб)

参阅

moneypunct | 定义 std::money_get 与 std::money_put 所用的货币格式解析器的参数 (类模板)
money_get | 从输入字符序列中解析并构造货币值 (类模板)
put_money (C++11) | 格式化并输出货币值 (函数模板)


std::money_put<CharT,OutputIt>::~money_put

< cpp‎ | locale‎ | money put

定义于头文件 <locale>
protected: ~money_put();

析构 std::money_put 平面。此析构函数为受保护且为虚（由于基类析构函数为虚）。 std::money_put 类型对象，同大多数平面，只能在最后一个实装此平面的 std::locale 离开作用域时，或若用户定义导出自 std::money_put 并实现公开构造函数，才会被销毁。

示例

#include <iostream>
#include <locale>
struct Destructible_money_put : public std::money_put<wchar_t>
{
    Destructible_money_put(std::size_t refs = 0) : money_put(refs) {}
    // 注意：隐式析构函数为公开
};
int main()
{
    Destructible_money_put dc;
    // std::money_put<wchar_t> c;  // 编译错误：受保护析构函数
}


std::moneypunct

< cpp‎ | locale
定义于头文件 <locale>
template< class CharT, bool International = false >
class moneypunct;

平面 std::moneypunct 封装货币值格式化偏好。流 I/O 操纵符 std::get_money 和 std::put_money 通过 std::money_get 和 std::money_put 用 std::moneypunct 分析货币值输入及格式化货币值输出。

cpp/locale/money base cpp/locale/locale/facet

继承图

标准库提供四个孤立（独立于本地环境）的特化：

定义于头文件 <locale>
std::moneypunct<char> | 提供 "C" 本地环境偏好的等价版本
std::moneypunct<wchar_t> | 提供 "C" 本地环境偏好的宽字符等价版本
std::moneypunct<char, true> | 提供 "C" 本地环境偏好的等价版本，带国际通货符号
std::moneypunct<wchar_t, true> | 提供 "C" 本地环境偏好的宽字符等价版本，带国际通货符号

另外， C++ 程序中构造的每个 locale 对象都实装这些特化的其自身（本地环境限定）版本。

成员类型

成员类型 | 定义
char_type | CharT
string_type | std::basic_string <CharT>

成员函数

(构造函数) | 构造新的 moneypunct 平面 (公开成员函数)
(析构函数) | 销毁 moneypunct 平面 (受保护成员函数)
decimal_point | 调用 do_decimal_point (公开成员函数)
thousands_sep | 调用 do_thousands_sep (公开成员函数)
grouping | 调用 do_grouping (公开成员函数)
curr_symbol | 调用 do_curr_symbol (公开成员函数)
positive_signnegative_sign | 调用 do_positive_sign 或 do_negative_sign (公开成员函数)
frac_digits | 调用 do_frac_digits (公开成员函数)
pos_formatneg_format | 调用 do_pos_format/do_neg_format (公开成员函数)

受保护成员函数

do_decimal_point [虚] | 提供用作小数点的字符 (虚受保护成员函数)
do_thousands_sep [虚] | 提供用作千分隔符的字符 (虚受保护成员函数)
do_grouping [虚] | 提供二个千分隔符间的位数 (虚受保护成员函数)
do_curr_symbol [虚] | 提供用作通货标识符的字符串 (虚受保护成员函数)
do_positive_signdo_negative_sign [虚] | 提供指示正或负值的字符串 (虚受保护成员函数)
do_frac_digits [虚] | 提供小数点后要显示的位数 (虚受保护成员函数)
do_pos_formatdo_neg_format [虚] | 提供通货值的格式化模式 (虚受保护成员函数)

成员常量

成员 | 定义
const bool intl [静态] | International

成员对象

static std::locale::id id
 locale 的 id
(公开成员对象)

继承自 std::money_base

成员类型 | 定义
enum part { none, space, symbol, sign, value }; | 无作用域枚举类型
struct pattern { char field[4]; }; | 货币格式类型
枚举常量 | 解释
none | 容许但不要求空白符，除了在末位置不容许空白符
space | 要求一或多个空白字符
symbol | 要求 moneypunct::curr_symbol 所返回的字符序列
sign | 要求 moneypunct::positive_sign 或 moneypunct::negative_sign 所返回的首个字符
value | 要求绝对数值货币值

参阅

money_base | 定义货币格式化模式 (类)
moneypunct_byname | 表示系统提供的具名本地环境的 std::moneypunct (类模板)
money_get | 从输入字符序列中解析并构造货币值 (类模板)
money_put | 格式化货币值为字符序列以输出 (类模板)


std::moneypunct<CharT,International>::curr_symbol, do_curr_symbol

< cpp‎ | locale‎ | moneypunct
定义于头文件 <locale> |
public: string_type curr_symbol() const; | (1)
protected: virtual string_type do_curr_symbol() const; | (2)
1) 公开成员函数，调用最终导出类的成员函数 do_curr_symbol 。
2) 返回此本地环境用作通货标识符的字符串。若 International （ std::moneypunct 的第二模板形参）为 false ，则此标识符通常为单个（宽）字符，例如 "￥" 或 "$" 。若 International 为 true ，则标识符通常为保有三个 ISO 4217 通货代码，后随空格的四字符字符串（ "JPY " 或 "USD " ）。

返回值

保有通货符号或代码的 string_type 类型对象。

示例

#include <iostream>
#include <locale>
void show_ccy(const char* locname)
{
    std::locale loc(locname);
    std::cout << locname << " currency symbol is "
              << std::use_facet<std::moneypunct<char, true>>(loc).curr_symbol()
              << "or " << std::use_facet<std::moneypunct<char>>(loc).curr_symbol()
              << " for short\n";
}
int main()
{
    show_ccy("en_US.utf8");
    show_ccy("ja_JP.utf8");
    show_ccy("sv_SE.utf8");
    show_ccy("ru_RU.utf8");
    show_ccy("vi_VN.utf8");
}

输出：

en_US.utf8 currency symbol is USD or $ for short
ja_JP.utf8 currency symbol is JPY or ￥ for short
sv_SE.utf8 currency symbol is SEK or kr for short
ru_RU.utf8 currency symbol is RUB or руб for short
vi_VN.utf8 currency symbol is VND or ₫ for short

参阅

do_pos_formatdo_neg_format
[虚]
 提供通货值的格式化模式
(虚受保护成员函数)


std::moneypunct<CharT,International>::decimal_point, do_decimal_point

< cpp‎ | locale‎ | moneypunct
定义于头文件 <locale> |
public: CharT decimal_point() const; | (1)
protected: virtual CharT do_decimal_point() const; | (2)
1) 公开成员函数，调用最终导出类的成员函数 do_decimal_point 。
2) 返回用作货币 I/O 中小数点的字符，若格式使用小数（即若 do_frac_digits() 大于零）。对于典型的美国本地环境，其为字符 '.' （或 L'.' ）。

返回值

保有小数点的 CharT 类型值。

示例

#include <iostream>
#include <iomanip>
#include <locale>

void show_dpt(const char* locname)
{
    std::locale loc(locname);
    std::cout.imbue(loc);
    std::cout << locname << " decimal point is '"
              << std::use_facet<std::moneypunct<char>>(loc).decimal_point()
              << "' for example: " << std::showbase << std::put_money(123);
    if (std::use_facet<std::moneypunct<char>>(loc).frac_digits() == 0)
        std::cout << " (does not use frac digits) ";

    std::cout << '\n';
}

int main()
{
    show_dpt("en_US.utf8");
    show_dpt("ja_JP.utf8");
    show_dpt("sv_SE.utf8");
    show_dpt("de_DE.utf8");

}

输出：

en_US.utf8 decimal point is '.' for example: $1.23
ja_JP.utf8 decimal point is '.' for example: ￥123 (does not use frac digits)
sv_SE.utf8 decimal point is ',' for example: 1,23 kr
de_DE.utf8 decimal point is ',' for example: 1,23 €

参阅

do_frac_digits
[虚]
 提供小数点后要显示的位数
(虚受保护成员函数)


std::moneypunct<CharT,International>::frac_digits, do_frac_digits

< cpp‎ | locale‎ | moneypunct
定义于头文件 <locale> |
public: int frac_digits() const; | (1)
protected: virtual int do_frac_digits() const; | (2)
1) 公开成员函数，调用最终导出类的成员函数 do_frac_digits 。
2) 返回打印货币值时出现在小数点后的位数。

返回值

要显示于小数点后的位数。在常用的美国本地环境中，此为值 2 。

示例

#include <locale>
#include <iostream>
#include <iomanip>
#include <iterator>
struct space_out : std::moneypunct<char> {
    pattern do_pos_format()      const { return { {value, none, none, none} };}
    int do_frac_digits()         const { return 0; }
    char_type do_thousands_sep() const { return ' ';}
    string_type do_grouping()    const { return "\002";}
};
int main()
{
    std::cout.imbue(std::locale("en_US.UTF-8"));
    std::cout << "american locale: " << std::showbase
              << std::put_money(12345678.0)<< '\n';

    std::cout.imbue(std::locale(std::cout.getloc(), new space_out));
    std::cout << "locale with modified moneypunct: "
              << std::put_money(12345678.0)<< '\n';
}

输出：

american locale: $123,456.78
locale with modified moneypunct: 12 34 56 78

参阅

do_thousands_sep [虚] | 提供用作千分隔符的字符 (虚受保护成员函数)
do_decimal_point [虚] | 提供用作小数点的字符 (虚受保护成员函数)


std::moneypunct<CharT,International>::grouping, do_grouping

< cpp‎ | locale‎ | moneypunct
定义于头文件 <locale> |
public: std::string grouping() const; | (1)
protected: virtual std::string do_grouping() const; | (2)
1) 公开成员函数，调用最终导出类的成员函数 do_grouping 。
2) 返回确定货币输出中数位分组的模式，含义与 std::numpunct::do_grouping 准确相同。

返回值

保有分组的 std::string 类型对象。 std::moneypunct 的标准特化返回空字符串，指示不分组。典型的分组（例如 en_US 本地环境）返回 "\003" 。

示例

#include <locale>
#include <iostream>
#include <iomanip>
#include <iterator>
struct space_out : std::moneypunct<char> {
    pattern do_pos_format()      const { return { {value, none, none, none} };}
    int do_frac_digits()         const { return 0; }
    char_type do_thousands_sep() const { return ' ';}
    string_type do_grouping()    const { return "\002";}
};
int main()
{
    std::cout.imbue(std::locale("en_US.UTF-8"));
    std::cout << "american locale: " << std::showbase
              << std::put_money(12345678.0)<< '\n';

    std::cout.imbue(std::locale(std::cout.getloc(), new space_out));
    std::cout << "locale with modified moneypunct: "
              << std::put_money(12345678.0)<< '\n';
}

输出：

american locale: $123,456.78
locale with modified moneypunct: 12 34 56 78

参阅

do_thousands_sep [虚] | 提供用作千分隔符的字符 (虚受保护成员函数)
do_decimal_point [虚] | 提供用作小数点的字符 (虚受保护成员函数)


std::moneypunct<CharT,International>::moneypunct

< cpp‎ | locale‎ | moneypunct

定义于头文件 <locale>
explicit moneypunct( std::size_t refs = 0 );

创建 std::moneypunct 平面并转发引用计数 refs 到基类构造函数 locale::facet::facet() 。

参数

refs - 开始的引用计数


std::moneypunct<CharT,International>::pos_format, do_pos_format, neg_format, do_neg_format

< cpp‎ | locale‎ | moneypunct
定义于头文件 <locale> |
public: pattern pos_format() const; | (1)
public: pattern neg_format() const; | (2)
protected: virtual pattern do_pos_format() const; | (3)
protected: virtual pattern do_neg_format() const; | (4)
1) 公开成员函数，调用最终导出类的成员函数 do_pos_format 。
2) 公开成员函数，调用最终导出类的成员函数 do_neg_format 。
3) 返回（ std::money_base::format 类型）描述正货币值格式化的格式结构。
4) 返回（ std::money_base::format 类型）描述负货币值格式化的格式结构。

std::moneypunct 的标准特化返回模式 {symbol, sign, none, value} 。

返回值

描述此 locale 所用的格式化的 std::money_base::format 类型对象。

注意

std::money_put 用 pos_format 格式化正值，用 neg_format 格式化负值，然而 std::money_get 用 neg_format 分析所有货币值：它假定 neg_format 与 pos_format 兼容。

示例

#include <locale>
#include <iostream>
#include <iomanip>

struct my_punct : std::moneypunct_byname<char, false> {
    my_punct(const char* name) : moneypunct_byname(name) {}
    pattern do_pos_format() const { return { {value, space, symbol, sign} };}
    pattern do_neg_format() const { return { {value, space, symbol, sign} };}
};
int main()
{
    std::cout.imbue(std::locale("en_US.utf8"));
    std::cout << "american locale: " << std::showbase
              << std::put_money(12345678.0) << '\n';

    std::cout.imbue(std::locale(std::cout.getloc(), new my_punct("en_US.utf8")));
    std::cout << "locale with modified moneypunct:\n"
              << std::put_money(12345678.0)  << '\n'
              << std::put_money(-12345678.0) << '\n';
}

输出：

american locale: $123,456.78
locale with modified moneypunct:
123,456.78 $
123,456.78 $-

参阅

do_curr_symbol [虚] | 提供用作通货标识符的字符串 (虚受保护成员函数)
do_positive_signdo_negative_sign [虚] | 提供指示正或负值的字符串 (虚受保护成员函数)
do_get [虚] | 分析来自输入流的货币值 (std::money_get<CharT,InputIt> 的虚受保护成员函数)
do_put [虚] | 格式化货币值并写入到输出流 (std::money_put<CharT,OutputIt> 的虚受保护成员函数)


std::moneypunct<CharT,International>::positive_sign, do_positive_sign, negative_sign, do_negative_sign

< cpp‎ | locale‎ | moneypunct
定义于头文件 <locale> |
public: string_type positive_sign() const; | (1)
public: string_type negative_sign() const; | (2)
protected: virtual string_type do_positive_sign() const; | (3)
protected: virtual string_type do_negative_sign() const; | (4)
1) 公开成员函数，调用最终导出类的成员函数 do_positive_sign 。
2) 公开成员函数，调用最终导出类的成员函数 do_negative_sign 。
3) 返回用作正货币值格式化的字符串。
3) 返回用作负货币值格式化的字符串。

只有返回字符串的首字符是出现于值 sign 所指示的 pos_format()/neg_format() 位置前的字符。剩下的字符出现在货币字符串的剩余部分之后'。

具体而言，对于 "-" 的 negative_sign ，格式化可作为 "-1.23 €" 出现，而对于 "()" 的 negative_sign ，它会作为 "(1.23 €)" 出现。

返回值

保有要用作正或负号的字符的 string_type 类型字符串。

示例

#include <iostream>
#include <iomanip>
#include <locale>

struct my_punct : std::moneypunct_byname<char, false> {
    my_punct(const char* name) : moneypunct_byname(name) {}
    string_type do_negative_sign() const { return "()"; }
};

int main()
{
    std::locale loc("de_DE.utf8");
    std::cout.imbue(loc);
    std::cout << loc.name() << " negative sign is '"
              << std::use_facet<std::moneypunct<char>>(loc).negative_sign()
              << "' for example: " << std::showbase << std::put_money(-1234) << '\n';

    std::locale loc2("ms_MY.utf8");
    std::cout.imbue(loc2);
    std::cout << loc2.name() << " negative sign is '"
              << std::use_facet<std::moneypunct<char>>(loc2).negative_sign()
              << "' for example: " << std::put_money(-1234) << '\n';

    std::cout.imbue(std::locale(std::cout.getloc(), new my_punct("de_DE.utf8")));
    std::cout << "de_DE.utf8 with negative_sign set to \"()\": "
              << std::put_money(-1234) << '\n';

}

输出：

de_DE.utf8 negative sign is '-' for example: -12,34 €
ms_MY.utf8 negative sign is '()' for example: (RM12.34)
de_DE.utf8 with negative_sign set to "()": (12,34 €)

参阅

do_pos_formatdo_neg_format
[虚]
 提供通货值的格式化模式
(虚受保护成员函数)


std::moneypunct<CharT,International>::thousands_sep, do_thousands_sep

< cpp‎ | locale‎ | moneypunct
定义于头文件 <locale> |
public: char_type thousands_sep() const; | (1)
protected: virtual char_type do_thousands_sep() const; | (2)
1) 公开成员函数，调用最终导出类的成员函数 do_thousands_sep 。
2) 返回在分析或格式化货币值整数部分时用作分隔符的字符。

返回值

用作千分隔符的 char_type 类型对象。在常用美国本地环境中，此为 ',' 或 L',' 。

示例

#include <locale>
#include <iostream>
#include <iomanip>
#include <iterator>
struct space_out : std::moneypunct<char> {
    pattern do_pos_format()      const { return { {value, none, none, none} };}
    int do_frac_digits()         const { return 0; }
    char_type do_thousands_sep() const { return ' ';}
    string_type do_grouping()    const { return "\002";}
};
int main()
{
    std::cout.imbue(std::locale("en_US.UTF-8"));
    std::cout << "american locale: " << std::showbase
              << std::put_money(12345678.0)<< '\n';

    std::cout.imbue(std::locale(std::cout.getloc(), new space_out));
    std::cout << "locale with modified moneypunct: "
              << std::put_money(12345678.0)<< '\n';
}

输出：

american locale: $123,456.78
locale with modified moneypunct: 12 34 56 78

参阅

do_grouping
[虚]
 提供二个千分隔符间的位数
(虚受保护成员函数)


std::moneypunct<CharT,International>::~moneypunct

< cpp‎ | locale‎ | moneypunct

定义于头文件 <locale>
protected: ~moneypunct();

析构 std::moneypunct 平面。此析构函数为受保护且为虚（由于基类析构函数为虚）。 std::moneypunct 类型对象，同大多数平面，只能在最后一个实装此平面的 std::locale 离开作用域时，或若用户定义导出自 std::moneypunct 并实现公开构造函数，才会被销毁。

示例

#include <iostream>
#include <locale>
struct Destructible_moneypunct : public std::moneypunct<wchar_t>
{
    Destructible_moneypunct(std::size_t refs = 0) : moneypunct(refs) {}
    // 注意：隐式析构函数为公开
};
int main()
{
    Destructible_moneypunct dc;
    // std::moneypunct<wchar_t> c;  // 编译错误：受保护析构函数
}


std::moneypunct_byname

< cpp‎ | locale
定义于头文件 <locale>
template< class CharT, bool Intl = false >
class moneypunct_byname : public std::moneypunct <CharT, Intl>;

std::moneypunct_byname 是 std::moneypunct 平面，封装在其构造时指定的 locale 的货币格式化偏好。

标准库提供二个特化

定义于头文件 <locale>
std::moneypunct_byname<char, Intl> | 窄字符 I/O 的本地环境限定 std::moneypunct 平面
std::moneypunct_byname<wchar_t, Intl> | 宽字符 I/O 的本地环境限定 std::moneypunct 平面

成员类型

成员类型 | 定义
pattern | std::money_base::pattern
string_type | std::basic_string <CharT>

成员函数

(构造函数) | 构造新的 moneypunct_byname 平面 (公开成员函数)
(析构函数) | 析构 moneypunct_byname 平面 (受保护成员函数)

std::moneypunct_byname::moneypunct_byname

explicit moneypunct_byname( const char* name, std::size_t refs = 0 ); |
explicit moneypunct_byname( const std::string & name, std::size_t refs = 0 ); | (C++11 起)

为名为 name 的本地环境构造新的 std::moneypunct_byname 平面。

refs 用于资源管理：在销毁最后一个保有平面的 std::locale 对象时，若 refs == 0 ，则实现销毁平面对象。否则，不销毁对象。

参数

name | - | 本地环境的名称
refs | - | 链接到该平面的引用数

std::moneypunct_byname::~moneypunct_byname

protected:
~moneypunct_byname();

销毁平面。

继承自 std::moneypunct

成员类型

成员类型 | 定义
char_type | CharT
string_type | std::basic_string <CharT>

成员函数

decimal_point | 调用 do_decimal_point (std::moneypunct<CharT,International> 的公开成员函数)
thousands_sep | 调用 do_thousands_sep (std::moneypunct<CharT,International> 的公开成员函数)
grouping | 调用 do_grouping (std::moneypunct<CharT,International> 的公开成员函数)
curr_symbol | 调用 do_curr_symbol (std::moneypunct<CharT,International> 的公开成员函数)
positive_signnegative_sign | 调用 do_positive_sign 或 do_negative_sign (std::moneypunct<CharT,International> 的公开成员函数)
frac_digits | 调用 do_frac_digits (std::moneypunct<CharT,International> 的公开成员函数)
pos_formatneg_format | 调用 do_pos_format/do_neg_format (std::moneypunct<CharT,International> 的公开成员函数)

受保护成员函数

do_decimal_point [虚] | 提供用作小数点的字符 (std::moneypunct<CharT,International> 的虚受保护成员函数)
do_thousands_sep [虚] | 提供用作千分隔符的字符 (std::moneypunct<CharT,International> 的虚受保护成员函数)
do_grouping [虚] | 提供二个千分隔符间的位数 (std::moneypunct<CharT,International> 的虚受保护成员函数)
do_curr_symbol [虚] | 提供用作通货标识符的字符串 (std::moneypunct<CharT,International> 的虚受保护成员函数)
do_positive_signdo_negative_sign [虚] | 提供指示正或负值的字符串 (std::moneypunct<CharT,International> 的虚受保护成员函数)
do_frac_digits [虚] | 提供小数点后要显示的位数 (std::moneypunct<CharT,International> 的虚受保护成员函数)
do_pos_formatdo_neg_format [虚] | 提供通货值的格式化模式 (std::moneypunct<CharT,International> 的虚受保护成员函数)

成员常量

成员 | 定义
const bool intl [静态] | International

成员对象

static std::locale::id id
 locale 的 id
(公开成员对象)

继承自 std::money_base

成员类型 | 定义
enum part { none, space, symbol, sign, value }; | 无作用域枚举类型
struct pattern { char field[4]; }; | 货币格式类型
枚举常量 | 解释
none | 容许但不要求空白符，除了在末位置不容许空白符
space | 要求一或多个空白字符
symbol | 要求 moneypunct::curr_symbol 所返回的字符序列
sign | 要求 moneypunct::positive_sign 或 moneypunct::negative_sign 所返回的首个字符
value | 要求绝对数值货币值

示例

此示例演示如何应用另一语言的货币格式化规则而不更改 locale 的剩余部分。

#include <iostream>
#include <iomanip>
#include <locale>
int main()
{
    long double mon = 1234567;
    std::locale::global(std::locale("en_US.utf8"));
    std::wcout.imbue(std::locale());
    std::wcout << L"american locale : " << std::showbase
               << std::put_money(mon) << '\n';
    std::wcout.imbue(std::locale(std::wcout.getloc(),
                                 new std::moneypunct_byname<wchar_t>("ru_RU.utf8")));
    std::wcout << L"american locale with russian moneypunct: "
               << std::put_money(mon) << '\n';
}

输出：

american locale : $12,345.67
american locale with russian moneypunct: 12 345.67 руб

参阅

moneypunct
 定义 std::money_get 与 std::money_put 所用的货币格式解析器的参数
(类模板)


std::num_get

< cpp‎ | locale
定义于头文件 <locale>
template<

class CharT,
class InputIt = std::istreambuf_iterator <CharT>

> class num_get;

类 std::num_get 封装分析数值的字符串表示的规则。特别是支持类型 bool 、 unsigned short 、 unsigned int 、 long 、 unsigned long 、 long long 、 unsigned long long 、 float 、 double 、 long double 及 void* 。标准格式化输入运算符（如 cin >> n; ）用 I/O 流的 locale 的 std::num_get 平面分析数字的文本表示。

cpp/locale/locale/facet

继承图

类型要求

-
InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

特化

标准库提供二个独立（不依赖本地环境）的全特化和二个部分特化：

定义于头文件 <locale>
std::num_get<char> | 创建数字的窄字符串分析
std::num_get<wchar_t> | 创建数字的宽字符串分析
std::num_get<char, InputIt> | 创建数字的使用定制输入迭代器的窄字符串分析
std::num_get<wchar_t, InputIt> | 创建数字的使用定制输入迭代器的宽字符串分析

另外， C++ 程序中构造的每个 locale 对象都实装这些特化的其自身（本地环境限定）版本。

成员类型

成员类型 | 定义
char_type | CharT
iter_type | InputIt

成员函数

(构造函数) | 构造新的 num_get 平面 (公开成员函数)
(析构函数) | 析构 num_get 平面 (受保护成员函数)
get | 调用 do_get (公开成员函数)

成员对象

static std::locale::id id
 locale 的 id
(公开成员对象)

受保护成员函数

do_get
[虚]
 从输入流分析数字
(虚受保护成员函数)

示例

#include <iostream>
#include <locale>
#include <string>
#include <sstream>
#include <iterator>

int main()
{
    std::string de_double = "1.234.567,89";
    std::string us_double = "1,234,567.89";

    // 流使用分析
    std::istringstream de_in(de_double);
    de_in.imbue(std::locale("de_DE"));
    double f1;
    de_in >> f1;

    std::istringstream us_in(de_double);
    us_in.imbue(std::locale("en_US.UTF-8"));
    double f2;
    us_in >> f2;

    std::cout << "Parsing " << de_double << " as double gives " << std::fixed
              << f1 << " in de_DE locale and " << f2 << " in en_US\n";

    // 直接使用平面
    std::istringstream s3(us_double);
    s3.imbue(std::locale("en_US.UTF-8"));
    auto& f = std::use_facet<std::num_get<char>>(s3.getloc());
    std::istreambuf_iterator<char> beg(s3), end;
    double f3;
    std::ios::iostate err;
    f.get(beg, end, s3, err, f3);
    std::cout << "parsing " << us_double
              << " as double using raw en_US facet gives " << f3 << '\n';
}

输出：

Parsing 1.234.567,89 as double gives 1234567.890000 in de_DE locale and 1.234000 in en_US
parsing 1,234,567.89 as double using raw en_US facet gives 1234567.890000

参阅

numpunct | 定义数值标点规则 (类模板)
num_put | 格式化数值为字符序列以输出 (类模板)
operator>> | 提取带格式数据 (std::basic_istream<CharT,Traits> 的公开成员函数)


std::num_get<CharT,InputIt>::get, std::num_get<CharT,InputIt>::do_get

< cpp‎ | locale‎ | num get
(1)
public:

iter_type get( iter_type in, iter_type end, std::ios_base & str,

std::ios_base::iostate & err, bool& v ) const;
iter_type get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, long& v ) const;
iter_type get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, long long& v ) const;
 (C++11 起)
iter_type get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, unsigned short& v ) const;
iter_type get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, unsigned int& v ) const;
iter_type get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, unsigned long& v ) const;
iter_type get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, unsigned long long& v ) const;
 (C++11 起)
iter_type get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, float& v ) const;
iter_type get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, double& v ) const;
iter_type get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, long double& v ) const;
iter_type get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, void*& v ) const;
(2)
protected:

virtual iter_type do_get( iter_type in, iter_type end, std::ios_base & str,

std::ios_base::iostate & err, bool& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, long& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, long long& v ) const;
 (C++11 起)
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, unsigned short& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, unsigned int& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, unsigned long& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, unsigned long long& v ) const;
 (C++11 起)
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, float& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, double& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, long double& v ) const;
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, void*& v ) const;
1) 公开成员函数，调用最终导出类的成员函数 do_get 。
2) 从输入迭代器 in 读取字符，并生成 v 的类型的值，考虑来自 IO 流 str.flags() 的格式化标志，来自 std::use_facet < std::ctype <charT>>(str.getloc()) 的字符分类规则，和来自 std::use_facet < std::numpunct <charT>>(str.getloc()) 的数值标点字符。此函数为所有有格式输入流运算符，如 std::cin >> n; 所调用。

转换出现三个阶段

阶段 1 ：转换说明符选择

  • 获得 I/O 格式化标志，如同以
fmtflags basefield = (str.flags() & std::ios_base::basefield );
fmtflags boolalpha = (str.flags() & std::ios_base::boolalpha );
  • 若 v 的类型为整数类型，则选择下列五个选项的首个可应用者：
若 basefield == oct ，则将使用转换说明符 %o
若 basefield == hex ，则将使用转换说明符 %X
若 basefield == 0 ，则将使用转换说明符 %i
若 v 的类型有符号，则将使用转换说明符 %d
若 v 的类型无符号，则将使用转换说明符 %u
  • 对于整数类型，若需要则添加长度说明符到转换说明：对于 short 和 unsigned short 为 h ，对于 long 和 unsigned long 为 l ，对于 long long 和 unsigned long long 为 ll
  • 若 v 的类型为 float ，则将使用转换说明符 %g
  • 若 v 的类型为 double ，则将使用转换说明符 %lg
  • 若 v 的类型为 long double ，则将使用转换说明符 %Lg
  • 若 v 的类型为 void* ，则将使用转换说明符 %p
  • 若 v 的类型为 bool 且 boolalpha==0 ，则如同按 v 的类型为 long 一般处理，除了在阶段 3 存储于 v 的值。
  • 若 v 的类型为 bool 且 boolalpha!=0 ，则下列规则替换阶段 2 和 3 ：
    • 从输入迭代器 in 获得匹配获得自 std::use_facet < std::numpunct <charT>>(str.getloc()).falsename() 和 std::use_facet < std::numpunct <charT> >(str.getloc()).truename() 的相继字符，而且仅按需要匹配鉴别唯一匹配。仅在需要获得字符时，将输入迭代器 in 与 end 比较。
    • 若目标序列为唯一匹配，则设置 v 为对应的 bool 值。否则存储 false 于 v 并赋值 std::ios_base::failbit 给 err 。若在输入结束（ in==end ）前无法找到唯一匹配，则执行 err|= std::ios_base::eofbit 。

阶段 2 ：字符提取

  • 若 in==end ，则立即终止阶段 2 ，则不再提取更多字符
  • 如同以 char_type ct = *in; 从 in 提取下个字符
    • 若字符匹配如同用 std::use_facet < std::ctype <charT>>(str.getloc()).widen() 加宽到 locale 的 char_type 的 "0123456789abcdefxABCDEFX+-" 字符之一，则将它转换为对应的 char 。
    • 若字符匹配小数点（ std::use_facet < std::numpunct <charT>>(str.getloc()).decimal_point()) ），则以 '.' 替换之。
    • 若字符匹配千分隔符（ std::use_facet < std::numpunct <charT>>(str.getloc()).thousands_sep() ）且在所有 std::use_facet < std::numpunct <charT>>(str.getloc()).grouping().length() != 0 中使用千分隔，则若尚未积累小数点 '.' ，则记忆该字符的位置，但其他情况下忽略该字符。若已基类小数点，则舍弃该字符并终止阶段 2 。
    • 任何情况下，检查从前一步骤获得的 char 是否在会为 std::scanf 给定阶段 1 中选择的转换指定符的输入域中得到允许。若它受允许，则将它积累到临时缓冲区并重复阶段 2 。若它不受允许，则阶段 2 终止。

阶段 3 ：转换与存储

  • 转换阶段 2 中积累的 char 序列为数值
如同以对有符号整数 v 的 std::strtoll 、对无符号整数 v 的 std::strtoull 、对 float v 的 std::strtof 、对 double v 的 std::strtod 或对 long double v 的 std::strtold 分析输入
  • 若转换函数无法转换整个域，则存储值 ​0​ 于 v 。
  • 若转换函数产生过大而无法适合作为有符号整数类型的 v 类型的正值或负值，则分别存储可表示的最正值或最负值于 v 。
  • 若转换函数产生不适合作为无符号整数类型的 v 类型的值，则存储可表示的最正值于 v 。
  • 任何情况下，若转换函数失败，则赋值 std::ios_base::failbit 为 err
  • 否则，存储转换的数值结果于 v
    • 若 v 的类型为 bool 且未设置 boolalpha ，则若要存储的值为 ​0​ 则存储 false ，若要存储的值为 1 则存储 true ，对于任何其他值，赋值 std::ios_base::failbit 为 err 并存储 true 。
  • 之后，检查数位分组。若阶段 2 中舍弃的任何千分隔符的位置不匹配 std::use_facet < std::numpunct <charT>>(str.getloc()).grouping() 所提供的分组，则赋值 std::ios_base::failbit 为 err 。
  • 若因测试 in==end 终止阶段 2 ，则执行 err|= std::ios_base::eofbit 设置 eof 位。

返回值

in

注解

C++98/C++03 指定若出现错误则保留 v 不更改。这种行为被并入 C++11 的 LWG23 及 LWG696 更正。

转换负整数字符串为无符号整数时，某些实现产生零（因为字符串所表示的值小于目标类型所能表示的）。这种行为曾被 C++11/14 标准指定，但被 LWG1169 更正。

因为阶段 2 滤出如 'p' 、 'N' 或 'i' 的字符，如 "0x1.23p-10" 的十六进制浮点数和字符串 "NaN" 或 "inf" 可能为 do_get(double) 所拒绝，即使它们它们是对 strtod 的合法输入：此为 LWG 问题 2381 。

示例

用户定义类型的 operator>> 实现。

#include <iostream>
#include <iterator>
#include <locale>

struct base { long x; };

template <class CharT, class Traits>
std::basic_istream<CharT, Traits>&
    operator >>(std::basic_istream<CharT, Traits>& is,
                base& b)
{
    std::ios_base::iostate err = std::ios_base::goodbit;
    try // 设置 err 为能抛出
    {
        typename std::basic_istream<CharT, Traits>::sentry s(is);

        if (s) // 若流已为输入就绪
        {
            std::use_facet<std::num_get<CharT>>(is.getloc()).get(is, {}, is, err, b.x);
        }
    } catch(std::ios_base::failure& error)
    {
        // 处理异常
    }
    return is;
}

int main()
{
    base b;

    std::cin >> b;
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 23 | C++98 | 溢出的输入导致未定义行为 | 处理溢出
LWG 696 | C++98 | 转换失败时不更改结果 | 设为零
LWG 1169 | C++98 | 溢出处理在不同浮点类型间不一致 | 使得与 strtof/strtod 一致

参阅

operator>>
 提取带格式数据
(std::basic_istream<CharT,Traits> 的公开成员函数)


std::num_get<CharT,InputIt>::num_get

< cpp‎ | locale‎ | num get

定义于头文件 <locale>
explicit num_get( std::size_t refs = 0 );

创建 std::num_get 平面并转发引用计数 refs 到基类构造函数 locale::facet::facet() 。

参数

refs - 开始的引用计数


std::num_get<CharT,InputIt>::~num_get

< cpp‎ | locale‎ | num get

定义于头文件 <locale>
protected: ~num_get();

析构 std::num_get 平面。此析构函数为受保护且为虚（由于基类析构函数为虚）。 std::num_get 类型对象，同大多数平面，只能在最后一个实装此平面的 std::locale 离开作用域时，或若用户定义导出自 std::num_get 并实现公开构造函数，才会被销毁。

示例

#include <iostream>
#include <locale>
struct Destructible_num_get : public std::num_get<wchar_t>
{
    Destructible_num_get(std::size_t refs = 0) : num_get(refs) {}
    // 注意：隐式析构函数为公开
};
int main()
{
    Destructible_num_get dc;
    // std::num_get<wchar_t> c;  // 编译错误：受保护析构函数
}


std::num_put

< cpp‎ | locale
定义于头文件 <locale>
template<

class CharT,
class OutputIt = std::ostreambuf_iterator <CharT>

> class num_put;

类 std::num_put 封装格式化数值为字符串的规则。具体而言支持 bool 、 long 、 unsigned long 、 long long 、 unsigned long long 、 double 、 long double 、 void* 类型和所有能隐式转换到它们的类型（例如 int 或 float ）。标准格式化输出运算符（如 cout << n; ）用 I/O 流的 locale 的 std::num_put 平面生成数字的文本表示。

cpp/locale/locale/facet

继承图

类型要求

-
OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。

特化

标准库提供二个孤立（独立于本地环境）的全特化和二个部分特化：

定义于头文件 <locale>
std::num_put<char> | 创建数的窄字符串表示
std::num_put<wchar_t> | 创建数的宽字符串表示
std::num_put<char, OutputIt> | 用定制输出迭代器创建数的窄字符串表示
std::num_put<wchar_t, OutputIt> | 用定制输出迭代器创建数的宽字符串表示

另外， C++ 程序中构造的每个 locale 对象都实装这些特化的其自身（本地环境限定）版本。

成员类型

成员类型 | 定义
char_type | CharT
iter_type | OutputIt

成员函数

(构造函数) | 构造新的 num_put 平面 (公开成员函数)
(析构函数) | 销毁 num_put 平面 (受保护成员函数)
put | 调用 do_put (公开成员函数)

受保护成员函数

do_put
[虚]
 格式化数字并写入到输出流
(虚受保护成员函数)

成员对象

static std::locale::id id
 locale 的 id
(公开成员对象)

示例

#include <iostream>
#include <locale>
#include <string>
#include <iterator>

int main()
{
    double n = 1234567.89;
    std::cout.imbue(std::locale("de_DE"));
    std::cout << "Direct conversion to string:\n"
              << std::to_string(n) << '\n'
              << "Output using a german locale:\n"
              << std::fixed << n << '\n'
              << "Output using an american locale:\n";
    // 直接使用平面
    std::cout.imbue(std::locale("en_US.UTF-8"));
    auto& f = std::use_facet<std::num_put<char>>(std::cout.getloc());
    f.put(std::ostreambuf_iterator<char>(std::cout), std::cout, ' ', n);
    std::cout << '\n';
}

输出：

Direct conversion to string:
1234567.890000
Output using a german locale:
1.234.567,890000
Output using an american locale:
1,234,567.890000

参阅

numpunct | 定义数值标点规则 (类模板)
num_get | 从输入字符序列中解析数字值 (类模板)
to_string (C++11) | 转换整数或浮点值为 string (函数)
to_wstring (C++11) | 转换整数或浮点值为 wstring (函数)


std::num_put<CharT,OutputIt>::num_put

< cpp‎ | locale‎ | num put

定义于头文件 <locale>
explicit num_put( std::size_t refs = 0 );

创建 std::num_put 平面并转发引用计数 refs 到基类构造函数 locale::facet::facet() 。

参数

refs - 开始的引用计数


std::num_put<CharT,OutputIt>::put, std::num_put<CharT,OutputIt>::do_put

< cpp‎ | locale‎ | num put
定义于头文件 <locale> |
 | (1)
public: iter_type put( iter_type out, std::ios_base & str, char_type fill, bool v ) const; |  |
iter_type put( iter_type out, std::ios_base & str, char_type fill, long v ) const; |  |
iter_type put( iter_type out, std::ios_base & str, char_type fill, long long v ) const; |  | (C++11 起)
iter_type put( iter_type out, std::ios_base & str, char_type fill, unsigned long v ) const; |  |
iter_type put( iter_type out, std::ios_base & str, char_type fill, unsigned long long v ) const; |  | (C++11 起)
iter_type put( iter_type out, std::ios_base & str, char_type fill, double v ) const; |  |
iter_type put( iter_type out, std::ios_base & str, char_type fill, long double v ) const; |  |
iter_type put( iter_type out, std::ios_base & str, char_type fill, const void* v ) const; |  |
 | (2)
protected: virtual iter_type do_put( iter_type out, std::ios_base & str, char_type fill, bool v ) const; |  |
virtual iter_type do_put( iter_type out, std::ios_base & str, char_type fill, long v ) const; |  |
virtual iter_type do_put( iter_type out, std::ios_base & str, char_type fill, long long v ) const; |  | (C++11 起)
virtual iter_type do_put( iter_type out, std::ios_base & str, char_type fill, unsigned long v ) const; |  |
virtual iter_type do_put( iter_type out, std::ios_base & str, char_type fill, unsigned long long v ) const; |  | (C++11 起)
virtual iter_type do_put( iter_type out, std::ios_base & str, char_type fill, double v ) const; |  |
virtual iter_type do_put( iter_type out, std::ios_base & str, char_type fill, long double v ) const; |  |
virtual iter_type do_put( iter_type out, std::ios_base & str, char_type fill, const void* v ) const; |  |
1) 公开成员函数，调用最终导出类的受保护虚成员函数 do_put 。
2) 写字符到输出序列 out ，这些字符表示 v 的值，按格式化标志 str.flags() 和流 str 中感染的 locale 的 std::numpunct 和 std::ctype 平面所要求者格式化。此函数为所有有格式输出流运算符，如 std::cout << n; 所调用。

转换以四个阶段出现

阶段 1 ：转换说明符选择

  • 获得 I/O 格式标志，如同以
fmtflags basefield = (str.flags() & std::ios_base::basefield );
fmtflags uppercase = (str.flags() & std::ios_base::uppercase );
fmtflags floatfield = (str.flags() & std::ios_base::floatfield );
fmtflags showpos = (str.flags() & std::ios_base::showpos );
fmtflags showbase = (str.flags() & std::ios_base::showbase );
fmtflags showpoint = (str.flags() & std::ios_base::showpoint );
  • 若 v 的类型为 bool
    • 若 boolalpha == 0 ，则转换 v 为 int 类型并进行整数输出。
    • 若 boolalpha != 0 ，则若 v == true 则获得std::use_facet < std::numpunct <charT>>(str.getloc()).truename() ，或若 v == false 则获得 std::use_facet < std::numpunct <charT>>(str.getloc()).falsename() ，并以 *out++ = c 输出该字符串的每个相继字符 c 到 out 。此情况下不进行进一步的操作，函数返回 out 。
  • 若 v 的类型为整数类型，则选择下列首个可应用选项：
若 basefield == oct ，则将使用转换说明符 %o
若 basefield == hex && !uppercase ，则将使用转换说明符 %x
若 basefield == hex ，则将使用转换说明符 %X
若 v 的类型有符号，则将使用转换说明符 %d
若 v 的类型无符号，则将使用转换说明符 %u
  • 对于整数类型，若需要则添加长度修饰符到转换说明：对于 long 和 unsigned long 为 l ，对于 long long 和 unsigned long long 为 ll 。
  • 若 v 为浮点类型，则选择首个可应用选项：
若 floatfield == std::ios_base::fixed ，则将使用转换说明符 %f
若 floatfield == std::ios_base::scientific && !uppercase ，则将使用转换说明符 %e
若 floatfield == std::ios_base::scientific ，则将使用转换说明符 %E
若 floatfield == ( std::ios_base::fixed | std::ios_base::scientific ) && !uppercase ，则将使用转换说明符 %a
若 floatfield == ( std::ios_base::fixed | std::ios_base::scientific ) ，则将使用转换说明符 %A
 (C++11 起)
若 !uppercase ，则将使用转换说明符 %g
否则，将使用转换说明符 %G
  • 若 v 的类型为 long double ，则添加长度修饰符 L 到转换说明符。
  • 另外若 floatfield != (ios_base::fixed | ios_base::scientific) 则 (C++11 起)添加设为 str.precision() 的精度说明符
  • 对于整数和浮点类型，若设置了 showpos ，则前附修饰符 + 。
  • 对于整数类型，若设置了 showbase ，则前附修饰符 # 。
  • 对于浮点类型，若设置了 showpoint ，则前附修饰符 # 。
  • 若 v 的类型为 void* ，则将使用格式说明符 %p 。
  • 如同以在 "C" 本地环境中调用 std::printf (spec, v) 创建窄字符串，其中 spec 是所选的格式说明符。

阶段 2 ：本地环境限定转换

  • 调用 std::use_facet < std::ctype <CharT>>(str.getloc()).widen(c) ，将阶段 1 中获得的每个异于小数点 '.' 的字符 c 转换为 CharT 。
  • 对于算术类型，按照 std::use_facet < std::numpunct <CharT>>(str.getloc()).grouping() 所提供的分组规则，插入从 std::use_facet < std::numpunct <CharT>>(str.getloc()).thousands_sep() 获得的千分隔字符到序列中。
  • 以 std::use_facet < std::numpunct <CharT>>(str.getloc()).decimal_point() 替换小数点字符（ '.' ）。

阶段 3 ：填充

  • 如同以 std::fmtflags adjustfield = (flags & ( std::ios_base::adjustfield )) 获得调整标志，并以如下方式检验它以鉴别填充位置
若 adjustfield == std::ios_base::left ，则将在后方填充
若 adjustfield == std::ios_base::right ，则将在前方填充
若 adjustfield == std::ios_base::internal 且表示中出现符号字符，则将在符号后填充
若 adjustfield == std::ios_base::internal 而阶段 1 表示以 0x 或 0X 开始，则将在 x 或 X 后填充
否则，将在前方填充
  • 若 str.width() 非零（例如刚使用了 std::setw ）且阶段 2 后的 CharT 数小于 str.width() ，则插入 fill 字符的副本于填充所指示的位置，令序列长度达到 str.width() 。

任何情况下，都调用 str.width(0) 以取消 std::setw 的效果。

阶段 4 ：输出

如同用 *out++ = c 输出来自阶段 3 的 CharT 序列的每个相继字符 c 。

参数

out | - | 指向首个要写入字符的迭代器
str | - | 取得格式化信息来源的流
fill | - | 需要填充结果到域宽时使用的填充字符
v | - | 转换为字符串并输出的值

返回值

out

注解

转换说明 #o （例如产生自 std::showbase 和 std::oct 的组合）不计为填充字符。

格式化浮点值为 hexfloat 时（即 floatfield == ( std::ios_base::fixed | std::ios_base::scientific ) 时），不使用流的精度；而是始终以足以准确表示值的精度打印该数。

 (C++11 起)

示例

用平面直接输出数，并演示用户定义的平面

#include <iostream>
#include <locale>

// 此定制 num_put 平面输出所有整数类型的平方（除了 long long ）
struct squaring_num_put : std::num_put<char> {
    iter_type do_put(iter_type s, std::ios_base& f,
                     char_type fill, long v) const
    {
        return std::num_put<char>::do_put(s, f, fill, v*v );
    }

    iter_type do_put(iter_type s, std::ios_base& f,
                     char_type fill, unsigned long v) const
    {
        return std::num_put<char>::do_put(s, f, fill, v*v);
    }
};

int main()
{
    auto& facet = std::use_facet<std::num_put<char>>(std::locale());
    facet.put(std::cout, std::cout, '0', 2.71);
    std::cout << '\n';

    std::cout.imbue(std::locale(std::cout.getloc(), new squaring_num_put));
    std::cout << 6 << ' ' << -12 << '\n';
}

输出：

2.71
36 144

用户定义类型的 operator<< 的实现。

#include <iostream>
#include <iterator>
#include <locale>

struct base { long x = 10; };

template <class CharT, class Traits>
std::basic_ostream<CharT, Traits>&
    operator<< (std::basic_ostream<CharT, Traits>& os, base const& b)
{
    try {
        typename std::basic_ostream<CharT, Traits>::sentry s(os);
        if (s)
        {
            std::ostreambuf_iterator<CharT, Traits> it(os);
            std::use_facet<std::num_put<CharT>>(os.getloc())
                .put(it, os, os.fill(), b.x);
        }
    } catch (...) {
        // 设置 os 上的 badbit ，而且若要求则重抛出
    }
    return os;
}

int main()
{
    base b;

    std::cout << b;
}

输出：

10

参阅

operator<<
 插入带格式数据
(std::basic_ostream<CharT,Traits> 的公开成员函数)


std::num_put<CharT,OutputIt>::~num_put

< cpp‎ | locale‎ | num put

定义于头文件 <locale>
protected: ~num_put();

析构 std::num_put 平面。此析构函数为受保护且为虚（由于基类析构函数为虚）。 std::num_put 类型对象，同大多数平面，只能在最后一个实装此平面的 std::locale 离开作用域时，或若用户定义导出自 std::num_put 并实现公开构造函数，才会被销毁。

示例

#include <iostream>
#include <locale>
struct Destructible_num_put : public std::num_put<wchar_t>
{
    Destructible_num_put(std::size_t refs = 0) : num_put(refs) {}
    // 注意：隐式析构函数为公开
};
int main()
{
    Destructible_num_put dc;
    // std::num_put<wchar_t> c;  // 编译错误：受保护析构函数
}


std::numpunct

< cpp‎ | locale
定义于头文件 <locale>
template< class CharT >
class numpunct;

平面 std::numpunct 封装数值标点偏好。流 I/O 操作通过 std::num_get 和 std::num_put ，将用 std::numpunct 用于剖析数值输入，和格式化数值输出。

std::numpunct 所支持的数字拥有后述格式。此处 digit 表示 fmtflags 参数值所指定的基底集， thousands-sep 和 decimal-point 分别为 thousands_sep() 和 decimal_point() 函数的结果。整数值格式如下：

integer     ::= [sign] units
sign        ::= plusminus
plusminus   ::= '+' | '-'
units       ::= digits [thousands-sep units]
digits      ::= digit [digits]

thousand-sep 之间的数位（ digits 的最大大小）由 grouping() 的结果指定。

浮点值格式如下：

floatval    ::= [sign] units [decimal-point [digits]] [e [sign] digits] |
                [sign]        decimal-point  digits   [e [sign] digits]
e           ::= 'e' | 'E'
cpp/locale/locale/facet

继承图

标准库提供二个孤立（独立于本地环境）的特化：

定义于头文件 <locale>
std::numpunct<char> | 提供 "C" 本地环境偏好的等价版本
std::numpunct<wchar_t> | 提供 "C" 本地环境偏好的宽字符等价版本

另外， C++ 程序中构造的每个 locale 对象实现这些特化的其自身（本地环境限定）版本。

成员类型

成员类型 | 定义
char_type | charT
string_type | std::basic_string <charT>

成员函数

(构造函数)
 构造新的 numpunct 平面
(公开成员函数)
(析构函数)
 析构 numpunct 平面
(受保护成员函数)
decimal_point
 调用 do_decimal_point
(公开成员函数)
thousands_sep
 调用 do_thousands_sep
(公开成员函数)
grouping
 调用 do_grouping
(公开成员函数)
truenamefalsename
 调用 do_truename 或 do_falsename
(公开成员函数)

受保护成员函数

do_decimal_point [虚] | 提供用作小数点的字符 (虚受保护成员函数)
do_thousands_sep [虚] | 提供用作千分隔符的字符 (虚受保护成员函数)
do_grouping [虚] | 提供一对千分隔符之间的位数 (虚受保护成员函数)
do_truenamedo_falsename [虚] | 提供用作布尔 true 和 false 名称的字符串 (虚受保护成员函数)

成员对象

static std::locale::id id
 locale 的 id
(公开成员对象)

示例

下列代码更改 true 和 false 的字符串表示

#include <iostream>
#include <locale>

struct french_bool : std::numpunct<char> {
    string_type do_truename() const { return "oui"; }
    string_type do_falsename() const { return "non"; }
};

int main()
{
    std::cout << "default locale: "
              << std::boolalpha << true << ", " << false << '\n';
    std::cout.imbue(std::locale(std::cout.getloc(), new french_bool));
    std::cout << "locale with modified numpunct: "
              << std::boolalpha << true << ", " << false << '\n';
}

输出：

default locale: true, false
locale with modified numpunct: oui, non

参阅

numpunct_byname
 为具名 locale 创建 numpunct 平面
(类模板)


std::numpunct<CharT>::decimal_point, do_decimal_point

< cpp‎ | locale‎ | numpunct
定义于头文件 <locale> |
public: char_type decimal_point() const; | (1)
protected: virtual char_type do_decimal_point() const; | (2)
1) 公开成员函数，调用最终导出类的成员函数 do_decimal_point 。
2) 返回要用作整数和小数部分间的小数分隔符的字符。

返回值

用作小数分隔符的 char_type 类型值。 std::numpunct 的标准特化返回 '.' 和 L'.' 。

示例

#include <iostream>
#include <locale>

struct slash : std::numpunct<char> {
    char do_decimal_point()   const { return '/'; }  // 以斜杠分隔
};

int main()
{
    std::cout.precision(10);
    std::cout << "default locale: " << 1234.5678 << '\n';
    std::cout.imbue(std::locale(std::cout.getloc(), new slash));
    std::cout << "locale with modified numpunct: " << 1234.5678 << '\n';
}

输出：

default locale: 1234.5678
locale with modified numpunct: 1234/5678


std::numpunct<CharT>::grouping, std::numpunct<CharT>::do_grouping

< cpp‎ | locale‎ | numpunct
定义于头文件 <locale> |
public: std::string grouping() const; | (1)
protected: virtual std::string do_grouping() const; | (2)
1) 公开成员函数，调用最终导出类的成员函数 do_grouping 。
2) 返回 std::string ，其每个 char 元素中保有 num_put::put() （从而还有 basic_ostream::operator<< ）所格式化的数值输出的每组位数。

组以二进制值存储：三位组为 '\3' ，而 51 位组为 '3' 。返回的字符串的位于零下标的字符，保有最右组中的位数。位于 1 下标的字符保有第二右的组中的位数，等等。返回字符串中的最后字符所指示的分组被复用于数（的左部分）中所有剩余数位的分组。

返回值

保有分组的 std::string 类型对象。 std::numpunct 的标准特化返回空字符串，指示无分组。典型分组（例如 en_US 本地环境）返回 "\003" 。

示例

#include <iostream>
#include <limits>
#include <locale>

struct space_out : std::numpunct<char>
{
    char do_thousands_sep()   const { return ' ';  } // 以空格分隔
    std::string do_grouping() const { return "\1"; } // 1 位组
};

struct g123 : std::numpunct<char>
{
    std::string do_grouping() const { return "\1\2\3"; }
};

int main()
{
    std::cout << "default locale: " << 12345678 << '\n';
    std::cout.imbue(std::locale(std::cout.getloc(), new space_out));
    std::cout << "locale with modified numpunct: " << 12345678 << '\n';
    std::cout.imbue(std::locale(std::cout.getloc(), new g123));
    std::cout << "Locale with \\1\\2\\3 grouping: " <<
              std::numeric_limits<unsigned long long>::max() << '\n';
}

输出：

default locale: 12345678
locale with modified numpunct: 1 2 3 4 5 6 7 8
Locale with \1\2\3 grouping: 18,446,744,073,709,551,61,5

参阅

do_thousands_sep
[虚]
 提供用作千分隔符的字符
(虚受保护成员函数)


std::numpunct<CharT>::numpunct

< cpp‎ | locale‎ | numpunct

定义于头文件 <locale>
explicit numpunct( std::size_t refs = 0 );

创建 std::numpunct 平面并转发引用计数 refs 到基类构造函数 locale::facet::facet() 。

参数

refs - 开始的引用计数


std::numpunct<CharT>::thousands_sep, do_thousands_sep

< cpp‎ | locale‎ | numpunct
定义于头文件 <locale> |
public: char_type thousands_sep() const; | (1)
protected: virtual char_type do_thousands_sep() const; | (2)
1) 公开成员函数，调用最终导出类的成员函数 do_thousands_sep 。
2) 返回在分析或格式化整数和浮点值整数部分时用作数位组间分隔符的字符。

返回值

用作千分隔符的 char_type 类型值。 std::numpunct 的标准特化返回 ',' 和 L',' 。

示例

#include <iostream>
#include <locale>

struct space_out : std::numpunct<char> {
    char do_thousands_sep()   const { return ' '; }  // 以空格分隔
    std::string do_grouping() const { return "\1"; } // 1 位组
};

int main()
{
    std::cout << "default locale: " << 12345678 << '\n';
    std::cout.imbue(std::locale(std::cout.getloc(), new space_out));
    std::cout << "locale with modified numpunct: " << 12345678 << '\n';
}

输出：

default locale: 12345678
locale with modified numpunct: 1 2 3 4 5 6 7 8

参阅

do_grouping
[虚]
 提供一对千分隔符之间的位数
(虚受保护成员函数)


std::numpunct<CharT>::truename, do_truename, falsename, do_falsename

< cpp‎ | locale‎ | numpunct
定义于头文件 <locale> |
public: string_type truename() const; | (1)
public: string_type falsename() const; | (2)
protected: virtual string_type do_truename() const; | (3)
protected: virtual string_type do_falsename() const; | (4)
1-2) 公开成员函数，分别调用最终导出类的成员函数 do_truename 和 do_falsename 。
3) 返回拥有表示布尔值 true 的字符串。
4) 返回拥有表示布尔值 false 的字符串。

返回值

1,3) 用作 true 表示的 string_type 类型对象。 std::numpunct 的标准特化返回 "true" 和 L"true" 。
2,4) 用作 false 表示的 string_type 类型对象。 std::numpunct 的标准特化返回 "false" 和 L"false" 。

示例

#include <iostream>
#include <locale>
#include <iomanip>

struct custom_tf : std::numpunct<char> {
    std::string do_truename()  const { return "t"; }
    std::string do_falsename() const { return "f"; }
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << "default locale: " << true << true << false << false << '\n';
    std::cout.imbue(std::locale(std::cout.getloc(), new custom_tf));
    std::cout << "locale with modified numpunct: "
              << true << true << false << false << '\n';
}

输出：

default locale: truetruefalsefalse
locale with modified numpunct: ttff


std::numpunct<CharT>::~numpunct

< cpp‎ | locale‎ | numpunct

定义于头文件 <locale>
protected: ~numpunct();

析构 std::numpunct 平面。此析构函数为受保护且为虚（由于基类析构函数为虚）。 std::numpunct 类型对象，同大多数平面，只能在最后一个实装此平面的 std::locale 离开作用域时，或若用户定义导出自 std::numpunct 并实现公开构造函数，才会被销毁。

示例

#include <iostream>
#include <locale>
struct Destructible_numpunct : public std::numpunct<wchar_t>
{
    Destructible_numpunct(std::size_t refs = 0) : numpunct(refs) {}
    // 注意：隐式析构函数为公开
};
int main()
{
    Destructible_numpunct dc;
    // std::numpunct<wchar_t> c;  // 编译错误：受保护析构函数
}


std::numpunct_byname

< cpp‎ | locale
定义于头文件 <locale>
template< class CharT >
class numpunct_byname : public std::numpunct <CharT>;

std::numpunct_byname 是 std::numpunct 平面，它封装在其构造时指定的 locale 的数值标点偏好。

标准库提供二个特化

定义于头文件 <locale>
std::numpunct_byname<char> | 窄字符 I/O 的本地环境限定 std::numpunct 平面
std::numpunct_byname<wchar_t> | 宽字符 I/O 的本地环境限定 std::numpunct 平面

成员类型

成员类型 | 定义
char_type | CharT
string_type | std::basic_string <CharT>

成员函数

(构造函数) | 构造新的 numpunct_byname 平面 (公开成员函数)
(析构函数) | 析构 numpunct_byname 平面 (受保护成员函数)

std::numpunct_byname::numpunct_byname

explicit numpunct_byname( const char* name, std::size_t refs = 0 ); |
explicit numpunct_byname( const std::string & name, std::size_t refs = 0 ); | (C++11 起)

为名为 name 的本地环境构造新的 std::numpunct_byname 平面。

refs 用于资源管理：在销毁最后一个保有平面的 std::locale 对象时，若 refs == 0 ，则实现销毁平面对象。否则，不销毁对象。

参数

name | - | 本地环境的名称
refs | - | 链接到该平面的引用数

std::numpunct_byname::~numpunct_byname

protected:
~numpunct_byname();

销毁平面。

继承自 std::numpunct

成员类型

成员类型 | 定义
char_type | charT
string_type | std::basic_string <charT>

成员函数

decimal_point | 调用 do_decimal_point (std::numpunct<CharT> 的公开成员函数)
thousands_sep | 调用 do_thousands_sep (std::numpunct<CharT> 的公开成员函数)
grouping | 调用 do_grouping (std::numpunct<CharT> 的公开成员函数)
truenamefalsename | 调用 do_truename 或 do_falsename (std::numpunct<CharT> 的公开成员函数)

受保护成员函数

do_decimal_point [虚] | 提供用作小数点的字符 (std::numpunct<CharT> 的虚受保护成员函数)
do_thousands_sep [虚] | 提供用作千分隔符的字符 (std::numpunct<CharT> 的虚受保护成员函数)
do_grouping [虚] | 提供一对千分隔符之间的位数 (std::numpunct<CharT> 的虚受保护成员函数)
do_truenamedo_falsename [虚] | 提供用作布尔 true 和 false 名称的字符串 (std::numpunct<CharT> 的虚受保护成员函数)

成员对象

static std::locale::id id
 locale 的 id
(公开成员对象)

示例

此示例演示如何应用另一语言的数值标点规则而不更改 locale 的剩余部分。

#include <iostream>
#include <locale>
int main()
{
    const double number = 1000.25;
    std::wcout << L"default locale: " << number << L'\n';
    std::wcout.imbue(std::locale(std::wcout.getloc(),
                                 new std::numpunct_byname<wchar_t>("ru_RU.UTF8")));
    std::wcout << L"default locale with russian numpunct: " << number << L'\n';
}

输出：

default locale: 1000.25
default locale with russian numpunct: 1 000,25

参阅

numpunct
 定义数值标点规则
(类模板)


std::setlocale

< cpp‎ | locale
定义于头文件 <clocale>
char* setlocale( int category, const char* locale);

setlocale 函数安装指定的系统本地环境或其一部分，作为新的 C 本地环境。修改保持效果，并影响所有关乎本地环境的 C 库函数执行，到下次调用 setlocale 为止。若 locale 为空指针，则 setlocale 查询当前 C 本地环境而不修改它。

参数

category | - | 本地环境类别标识符， LC_xxx 宏之一。可为 0 。
locale | - | 系统限定的本地环境标识符。对于用户偏好的本地环境为 "" ，对于最小本地环境为 "C" 。

返回值

指向窄空终止字符串的指针，它表示应用更改后的 C 本地环境，若存在。或在失败时为空指针。

返回字符串的副本和到 std::setlocale 的此调用中所用的类别，可在程序的后面用来恢复本地环境到此调用结束时的状态。

注意

程序启动过程中，运行任何用户代码前会执行 std::setlocale( LC_ALL, "C"); 的等价代码。

尽管返回类型为 char* ，修改被指向的字符是未定义行为。

setlocale 修改影响本地环境依赖函数的全局状态，故从一个线程调用它，而另一线程同时执行任何下列函数是未定义行为： std::fprintf 、 std::isprint 、 std::iswdigit 、 std::localeconv 、 std::tolower 、 std::fscanf 、 std::ispunct 、 std::iswgraph 、 std::mblen 、 std::toupper 、 std::isalnum 、 std::isspace 、 std::iswlower 、 std::mbstowcs 、 std::towlower 、 std::isalpha 、 std::isupper 、 std::iswprint 、 std::mbtowc 、 std::towupper 、 std::isblank 、 std::iswalnum 、 std::iswpunct 、 std::setlocale 、 std::wcscoll 、 std::iscntrl 、 std::iswalpha 、 std::iswspace 、 std::strcoll 、 std::wcstod 、 std::isdigit 、 std::iswblank 、 std::iswupper 、 std::strerror 、 std::wcstombs 、 std::isgraph 、 std::iswcntrl 、 std::iswxdigit 、 std::strtod 、 std::wcsxfrm 、 std::islower 、 std::iswctype 、 std::isxdigit 。

POSIX 亦定义名为 "POSIX" 的本地环境，它始终可访问，并准确等于默认的最小 "C" 本地环境。

POSIX 亦指定后继的 setlocale 调用可以非法化返回的指针，而不仅是被指向的字符串内容。

示例

#include <cstdio>
#include <clocale>
#include <ctime>
#include <cwchar>

int main()
{
    // C 本地环境将为启用 UTF-8 的英文；
    // 小数点将为德文
    // 日期和时间格式将为日文
    std::setlocale(LC_ALL, "en_US.UTF-8");
    std::setlocale(LC_NUMERIC, "de_DE.UTF-8");
    std::setlocale(LC_TIME, "ja_JP.UTF-8");

    wchar_t str[100];
    std::time_t t = std::time(NULL);
    std::wcsftime(str, 100, L"%A %c", std::localtime(&t));
    std::wprintf(L"Number: %.2f\nDate: %Ls\n", 3.14, str);
}

输出：

Number: 3,14
Date: 月曜日 2011年12月19日 18時04分40秒

参阅

LC_ALLLC_COLLATELC_CTYPELC_MONETARYLC_NUMERICLC_TIME | std::setlocale 所用的本地环境类别 (宏常量)
locale | 用以封装文化差异的多态刻面的集合 (类)


std::time_base

< cpp‎ | locale
定义于头文件 <locale>
class time_base;

类 std::time_base 提供日期顺序常量，它为 std::time_get 平面所继承。

成员类型

成员类型 | 定义
enum dateorder { no_order, dmy, mdy, ymd, ydm }; | 无作用域枚举类型
枚举常量 | 定义
no_order | 未指定的顺序
dmy | 日、月、年（欧洲）顺序
mdy | 月、日、年（美国）顺序
ymd | 年、月、日
ydm | 年、日、月

参阅

do_date_order [虚] | 获得偏好的日、月、年顺序 (std::time_get<CharT,InputIt> 的虚受保护成员函数)
do_get_date [虚] | 从输入流输出月、日以及年 (std::time_get<CharT,InputIt> 的虚受保护成员函数)


std::time_get

< cpp‎ | locale
定义于头文件 <locale>
template<

class CharT,
class InputIt = std::istreambuf_iterator <CharT>

> class time_get;

类模板 std::time_get 封装日期和时间分析规则。 I/O 操纵符 std::get_time 用 I/O 流的 locale 的 std::time_get 平面转换文本输入为 std::tm 对象。

cpp/locale/time base cpp/locale/locale/facet

继承图

类型要求

-
InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

特化

标准库提供二个孤立（独立于本地环境的）全特化和二个部分特化：

定义于头文件 <locale>
std::time_get<char> | 分析日期和时间的窄字符串表示
std::time_get<wchar_t> | 分析日期和时间的宽字符串表示
std::time_get<char, InputIt> | 用定制输入迭代器分析日期和时间的窄字符串表示
std::time_get<wchar_t, InputIt> | 用定制输入迭代器分析日期和时间的宽字符串表示

另外， C++ 程序中构造的每个 locale 对象都实装这些特化的其自身（本地环境限定）版本。

成员类型

成员类型 | 定义
char_type | CharT
iter_type | InputIt

成员函数

(构造函数) | 构造新的 time_get 平面 (公开成员函数)
(析构函数) | 销毁 time_get 平面 (受保护成员函数)
date_order | 调用 do_date_order (公开成员函数)
get_time | 调用 do_get_time (公开成员函数)
get_date | 调用 do_get_date (公开成员函数)
get_weekday | 调用 do_get_weekday (公开成员函数)
get_monthname | 调用 do_get_monthname (公开成员函数)
get_year | 调用 do_get_year (公开成员函数)
get (C++11) | 调用 do_get (公开成员函数)

成员对象

static std::locale::id id
 locale 的 id
(公开成员对象)

受保护成员函数

do_date_order [虚] | 获得偏好的日、月、年顺序 (虚受保护成员函数)
do_get_time [虚] | 从输入流释出时、分、秒 (虚受保护成员函数)
do_get_date [虚] | 从输入流输出月、日以及年 (虚受保护成员函数)
do_get_weekday [虚] | 从输入流释出星期的日名 (虚受保护成员函数)
do_get_monthname [虚] | 从输入流释出月名 (虚受保护成员函数)
do_get_year [虚] | 从输入流释出年份 (虚受保护成员函数)
do_get [虚] (C++11) | 从输入流释出日期/时间组分，按照指定格式 (虚受保护成员函数)

继承自 std::time_base

类型 | 定义
dateorder | 日期顺序枚举类型，定义值 no_order 、 dmy 、 mdy 、 ymd 及 ydm

示例

注意：选择 clang 观察输出。 libstdc++ 当前未实现 %b 说明符：漏洞 78714

#include <iostream>
#include <sstream>
#include <locale>
#include <iomanip>

int main()
{
    std::tm t = {};
    std::istringstream ss("2011-Februar-18 23:12:34");
    ss.imbue(std::locale("de_DE.utf-8"));
    ss >> std::get_time(&t, "%Y-%b-%d %H:%M:%S");
    if (ss.fail()) {
        std::cout << "Parse failed\n";
    } else {
        std::cout << std::put_time(&t, "%c") << '\n';
    }
}

可能的输出：

Sun Feb 18 23:12:34 2011

参阅

time_put | 格式化 std::tm 内容为字符序列以输出 (类模板)
get_time (C++11) | 剖析指定格式的日期/时间值 (函数模板)


std::time_get<CharT,InputIt>::date_order, std::time_get<CharT,InputIt>::do_date_order

< cpp‎ | locale‎ | time get
定义于头文件 <locale> |
public: dateorder date_order() const; | (1)
protected: virtual dateorder do_date_order() const; | (2)
1) 公开成员函数，调用最终导出类的所保有虚成员函数 do_date_order 。
2) 返回 std::time_base::dateorder 类型值，它描述此 locale 所用的默认日期格式（为 get_date() 所期待并为 std::strftime() 用格式指定符 '%x' 所产生）。

合法值（继承自 std::time_base ）：

no_order | 含有可变项目（星期之日、尤里乌斯日等），或未实现此函数
dmy | 日、月、年（欧洲本地环境）
mdy | 月、日、年（美洲本地环境）
ymd | 年、月、日（亚洲本地环境）
ydm | 年、日、月（罕见）

参数

（无）

返回值

dateorder 类型值。

注意

此函数为可选，它可在每种情况下都返回 no_order 。

示例

#include <iostream>
#include <locale>

void show_date_order()
{
    std::time_base::dateorder d = std::use_facet<std::time_get<char>>(
                                           std::locale()
                                  ).date_order();
    switch (d)
    {
        case std::time_base::no_order: std::cout << "no_order\n"; break;
        case std::time_base::dmy: std::cout << "day, month, year\n"; break;
        case std::time_base::mdy: std::cout << "month, day, year\n"; break;
        case std::time_base::ymd: std::cout << "year, month, day\n"; break;
        case std::time_base::ydm: std::cout << "year, day, month\n"; break;
    }
}

int main()
{
    std::locale::global(std::locale("en_US.utf8"));
    std::cout << "In U.S. locale, the default date order is: ";
    show_date_order();

    std::locale::global(std::locale("ja_JP.utf8"));
    std::cout << "In Japanese locale, the default date order is: ";
    show_date_order();

    std::locale::global(std::locale("de_DE.utf8"));
    std::cout << "In German locale, the default date order is: ";
    show_date_order();
}

输出：

In U.S. locale, the default date order is: month, day, year
In Japanese locale, the default date order is: year, month, day
In German locale, the default date order is: day, month, year

参阅

do_get_date [虚] | 从输入流输出月、日以及年 (虚受保护成员函数)
time_base | 定义日期格式常量 (类)


std::time_get<CharT,InputIt>::get, std::time_get<CharT,InputIt>::do_get

< cpp‎ | locale‎ | time get
定义于头文件 <locale>
public:

iter_type get(iter_type beg, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, std::tm * t,

const char_type* fmtbeg, const char_type* fmtend) const;
 (1) (C++11 起)
protected:

virtual iter_type do_get(iter_type beg, iter_type end, std::ios_base & str,
std::ios_base::iostate & err, std::tm *t,

char format, char modifier) const;
 (2) (C++11 起)
1) 按照字符序列 [fmtbeg, fmtend) 中提供的格式，从输入字符序列 [beg, end) 分析日期和时间。期待格式遵循描述于下的格式，尽管能通过覆写 do_get 定制每个格式指定符的实际处理。 get 函数进行下列内容： 首先，通过执行 err = std::ios_base::goodbit 清除 err 中的错误位。然后进入循环，凡在任何下列条件变为真时循环终止（以此顺序检查）：
a) 已从格式字符串读取全部字符（ fmtbeg == fmtend ）
b) 有分析错误（ err != std::ios_base::goodbit ）
c) 已从输入序列读取全部字符（ beg == end ）。若此条件终止循环，则函数于 err 中一同设置 eofbit 和 failbit 。
循环体中，发生下列步骤：
a) 若格式字符串中的下个字符为 '%' ，后随一或二个组成合法 std::get_time 转换指定符的字符（见下方），则将这些字符用于调用 do_get(beg, end, str, err, t, format, modifier) ，其中 format 为初等转换指定符字符，而 modifier 为可选的修饰符（若存在，则出现于 % 和格式字符间）。若无修饰符，则使用值 '\0' 。若格式字符串有歧义，或过早结束而无以确定 '%' 后的转换指定符，则在 err 中设置 eofbit 并终止循环。若调用 do_get 后 err 中未设置错误位，则函数增加 fmtbeg 到正好指向转换指定符之后，并持续循环。
b) 若下个字符为流 str 中提供的 locale 所指示的空白符（即 std::isspace(*fmtbeg, str.getloc()) == true ），则函数保持自增 fmtbeg 直至它变为等于 fmtend 或指向非空白字符。
c) 若格式字符串中的下个字符按照大小写无关比较，等价于输入流中的下个字符，则函数令二个序列一同前进一个字符 ++fmtbeg, ++beg; 并持续循环。否则它设置 err 中的 failbit 。
2) 从输入序列 [beg, end) 分析一个格式指定符并按照它更新 t 所指向的 std::tm 结构体。
首先，通过执行 err = std::ios_base::goodbit 清除 err 中所有错误位。然后从 [beg, end) 读取 '%' 、 modifier （若非 '\0' ）及 format 所组成的 std::time_get 格式指定符所期待的字符。若字符不组成合法转换指定符，则设置 err 中的 failbit 。若读取一个字符后抵达输入流尾，则设置 err 中的 eofbit 。若成功分析输入字符串，则更新 *t 的对应域。
对于复合转换指定符，如 '%x' 或 '%c' ，或使用修饰符 'E' 和 'O' 的指令，函数可能无法确定存储于 *t 的某些值。该情况下设置 err 中的 eofbit ，并将这些域留在未指定状态。

参数

beg - 指代要分析的序列起始的迭代器
end - 要分析的序列的尾后一位置迭代器
str - 此函数在需要时用以获得 locale 平面的流对象，例如用 std::ctype 跳过空白符或用 std::collate 比较字符串
err - 此函数所修改以指示错误的流错误标志对象
t - 指向 std::tm 对象的指针，该对象将保有此函数调用结果
fmtbeg - 指向指定转换格式的 char_type 字符序列首字符的指针

格式字符串由零或更多转换说明符、空白符和通常字符（除了 % ）组成。期待每个通常字符以大小无关比较匹配输入流中的一个字符。每个空白符匹配输入字符串中的任意空白符。每个转换说明始于 % 字符，可选地后随 E 或 O 修饰符（若本地环境不支持则忽略），后随确定说明符转换行为的字符。格式说明符匹配 POSIX 函数 strptime() ：

转﻿换指﻿定﻿符 | 解释 | 写入域
% | 匹配字面 % 。完整转换说明必须是 %% 。 | （无）
t | 匹配任何空白符。 | （无）
n | 匹配任何空白符。 | （无）
年
Y | 分析完整年为四位十进制数，容许但不要求前导零 | tm_year
EY | 以替用表示分析年，例如 平成23年 在 ja_JP 本地环境中写 2011 到 tm_year | tm_year
y | 分析年的后二位为十进制数。范围 [69,99] 生成 1969 至 1999 的值，范围 [00,68] 生成 2000-2068 | tm_year
Oy | 以替用数值系统分析年的后二位数字，例如 十一 在 ja_JP 本地环境中被分析为 11 | tm_year
Ey | 分析年为从本地环境的替用日历周期 %EC 的偏移 | tm_year
C | 分析年的首 2 位数字为十进制数（范围 [00,99] ） | tm_year
EC | 分析本地环境的替用表示中，年基底（周期）的名称，例如 ja_JP 中的 平成 | tm_year
月
b | 分析月份名，完整或缩写，例如 Oct | tm_mon
h | b 的同义词 | tm_mon
B | b 的同义词 | tm_mon
m | 分析月为十进制数（范围 [01,12] ），容许但不要求前导零 | tm_mon
Om | 用替代数值系统分析月，例如 ja_JP 本地环境中 十二 分析为 12 | tm_mon
星期
U | 分析年之星期为十进制数（星期日是星期的首日）（范围 [00,53] ），容许但不要求前导零 | tm_year, tm_wday, tm_yday
OU | 用替用数值系统，如以 %U 一般分析年之星期，例如 ja_JP 本地环境中 五十二 分析为 52 | tm_year, tm_wday, tm_yday
W | 分析年之星期为十进制数（星期一是星期的首日）（范围 [00,53] ），容许但不要求前导零 | tm_year, tm_wday, tm_yday
OW | 用替用数值系统，如以 %W 一般分析年之星期，例如 ja_JP 本地环境中 五十二 分析为 52 | tm_year, tm_wday, tm_yday
年/月之日
j | 分析年之日为十进制数（范围 [001,366] ），容许但不要求前导零 | tm_yday
d | 分析月之日为十进制数（范围 [01,31] ），容许但不要求前导零 | tm_mday
Od | 用替用数值系统分析月之日，例如 ja_JP 本地环境中 二十七 分析为 27 ，容许但不要求前导零 | tm_mday
e | d 的同义词 | tm_mday
Oe | Od 的同义词 | tm_mday
星期之日
a | 分析星期的日名，完整或缩写版，例如 Fri | tm_wday
A | a 的同义词 | tm_wday
w | 分析星期之日为十进制数，其中星期日为 0 （范围 [0-6] ） | tm_wday
Ow | 用替用数值系统分析星期之日为十进制数，其中星期日为 0 ，例如 ja_JP 本地环境中 二 分析为 2 | tm_wday
时、分、秒
H | 分析时为十进制数，以 24 小时时钟（范围 [00,23] ） ，容许但不要求前导零 | tm_hour
OH | 用替用数值系统分析来自 24 小时时钟的时，例如 ja_JP 本地环境中 十八 分析为 18 | tm_hour
I | 分析时为十进制数，以 12 小时时钟（范围 [01,12] ） ，容许但不要求前导零 | tm_hour
OI | 用替用数值系统分析时，例如 ja_JP 本地环境中 六 分析为 6 | tm_hour
M | 分析分为十进制数（范围 [00,59] ），容许但不要求前导零 | tm_min
OM | 用替用数值系统分析分，例如 ja_JP 本地环境中 二十五 分析为 25 | tm_min
S | 分析秒为十进制数（范围 [00,60] ），容许但不要求前导零 | tm_sec
OS | 用替用数值系统分析秒，例如 ja_JP 本地环境中 二十四 分析为 24 | tm_sec
其他
c | 分析本地环境的标准日期和时间字符串格式，例如 Sun Oct 17 04:41:13 2010 （本地环境依赖） | 所有
Ec | 分析本地环境的替用时期和时间字符串格式，例如期待在 ja_JP 本地环境中以 平成23年 取代 2011年 | 所有
x | 分析本地环境的标准日期表示 | 所有
Ex | 分析本地环境的替用日期表示，例如期待在 ja_JP 本地环境中以 平成23年 取代 2011年 | 所有
X | 分析本地环境的标准时间表示 | 所有
EX | 分析本地环境的替用时间表示 | 所有
D | 等价于 "%m / %d / %y " | tm_mon, tm_mday, tm_year
r | 等价于本地环境的标准 12 小时时钟时间（ POSIX 中为 "%I : %M : %S %p" ） | tm_hour, tm_min, tm_sec
R | 等价于 "%H : %M" | tm_hour, tm_min
T | 等价于 "%H : %M : %S" | tm_hour, tm_min, tm_sec
p | 分析 a.m. 或 p.m. 的本地环境等价版本 | tm_hour

注意：不写入 tm_isdst ，需要用如 mktime 的函数显式设置它。
fmtend - 指定转换格式的 char_type 字符序列的末字符后一位置指针
format - 指名转换指定符的字符
modifier - 可出现于 % 和转换指定符间的可选修饰符

返回值

指向 [beg, end) 中成功分析的末字符后一位置的迭代器。

注意

格式字符串中非空白非 '%' 字符的大小写无关比较，不要求，但典型地使用 str 所提供的 locale 的 std::collate 平面。

若遇到分析错误，则此函数的多数实现完全不接触 *t 。

这些函数是否清零 *t 中其所不直接设置的域是实现定义的：可移植程序应在调用 get() 前初始化每个域为零。

示例

#include <iostream>
#include <sstream>
#include <locale>
#include <iomanip>

int main()
{
    std::istringstream ss("2011-Februar-18 23:12:34");
    ss.imbue(std::locale("de_DE.utf8"));

    auto& f = std::use_facet<std::time_get<char>>(std::locale("de_DE.utf8"));
    std::tm t{};
    std::string s = "%Y-%b-%d %H:%M:%S";
    std::ios_base::iostate err = std::ios_base::goodbit;
    auto ret = f.get({ss}, {}, ss, err, &t, &s[0], &s[0] + s.size());
    ss.setstate(err);
    std::istreambuf_iterator<char> last{};
    if(ss) {
        std::cout << "Successfully parsed as " << std::put_time(&t, "%c");
        if(ret != last) {
            std::cout << " Remaining content: ";
            std::copy(ret, last, std::ostreambuf_iterator<char>(std::cout));
        } else {
                std::cout << " The input was fully consumed";
        }
    } else {
            std::cout << "Parse failed. Unparsed string: ";
            std::copy(ret, last, std::ostreambuf_iterator<char>(std::cout));
    }
    std::cout << '\n';
}

输出：

Successfully parsed, as Sun Feb 18 23:12:34 2011 The input was fully consumed

参阅

get_time
(C++11)
 剖析指定格式的日期/时间值
(函数模板)


std::time_get<CharT,InputIt>::get_date, std::time_get<CharT,InputIt>::do_get_date

< cpp‎ | locale‎ | time get
定义于头文件 <locale>
public:

iter_type get_date( iter_type beg, iter_type end, std::ios_base & str,

std::ios_base::iostate & err, std::tm * t ) const;
 (1)
protected:

virtual iter_type do_get_date( iter_type beg, iter_type end, std::ios_base & str,

std::ios_base::iostate & err, std::tm * t ) const;
 (2)
1) 公开成员函数，调用最终导出类的受保护虚成员函数 do_get_date 。
2) 从序列 [beg, end) 读取相继字符，并用此 locale 所期待的默认格式分析出日历时间值，其格式与以下相同
"%x" | (C++11 前)
"%d/%m/%y" 、 "%m/%d/%y" 、 "%y/%m/%d" 和 "%y/%d/%m" ，取决于 date_order() | (C++11 起)
格式指定符为函数 std::get_time 、 time_get::get 和 POSIX 函数 strptime() 所用。
存储分析的时间到参数 t 所指向的 std::tm 结构体的对应域中。
若在读到合法值前抵达尾迭代器，则函数设置 err 中的 std::ios_base::eofbit 。若遇到分析错误，则函数设置 err 中的 std::ios_base::failbit 。

参数

beg | - | 指代要分析的序列起始的迭代器
end | - | 要分析的序列的尾后一位置迭代器
str | - | 此函数在需要时用以获得 locale 平面的流对象，例如用 std::ctype 跳过空白符或用 std::collate 比较字符串
err | - | 此函数所修改以指示错误的流错误标志对象
t | - | 指向 std::tm 对象的指针，该对象将保有此函数调用结果

返回值

指向 [beg, end) 中辨识为合法日期一部分的末字符后一位置的迭代器。

注意

对于默认时间格式的字母组分（若存在），此函数通常不区别大小写。

若遇到分析错误，则此函数的大多数实现保留 *t 不修改。

实现可以支持标准所要求之外的其他日期格式。

示例

#include <iostream>
#include <locale>
#include <sstream>
#include <iterator>
#include <ctime>

void try_get_date(const std::string& s)
{
    std::cout << "Parsing the date out of '" << s <<
                 "' in the locale " << std::locale().name() << '\n';
    std::istringstream str(s);
    std::ios_base::iostate err = std::ios_base::goodbit;

    std::tm t;
    std::istreambuf_iterator<char> ret =
        std::use_facet<std::time_get<char>>(str.getloc()).get_date(
            {str}, {}, str, err, &t
        );
    str.setstate(err);
    if(str) {
        std::cout << "Day: "   << t.tm_mday << ' '
                  << "Month: " << t.tm_mon + 1 << ' '
                  << "Year: "  << t.tm_year + 1900 << '\n';
    } else {
        std::cout << "Parse failed. Unparsed string: ";
        std::copy(ret, {}, std::ostreambuf_iterator<char>(std::cout));
        std::cout << '\n';
    }
}
int main()
{
    std::locale::global(std::locale("en_US.utf8"));
    try_get_date("02/01/2013");
    try_get_date("02-01-2013");

    std::locale::global(std::locale("ja_JP.utf8"));
    try_get_date("2013年02月01日");
}

输出：

Parsing the date out of '02/01/2013' in the locale en_US.utf8
Day: 1 Month: 2 Year: 2013
Parsing the date out of '02-01-2013' in the locale en_US.utf8
Parse failed. Unparsed string: -01-2013
Parsing the date out of '2013年02月01日' in the locale ja_JP.utf8
Day: 1 Month: 2 Year: 2013

参阅

get_time
(C++11)
 剖析指定格式的日期/时间值
(函数模板)


std::time_get<CharT,InputIt>::get_monthname, std::time_get<CharT,InputIt>::do_get_monthname

< cpp‎ | locale‎ | time get
定义于头文件 <locale>
public:

iter_type get_monthname( iter_type beg, iter_type end, std::ios_base & str,

std::ios_base::iostate & err, std::tm * t) const;
 (1)
protected:

virtual iter_type do_get_monthname( iter_type beg, iter_type end, std::ios_base & str,

std::ios_base::iostate & err, std::tm * t) const;
 (2)
1) 公开成员函数，调用最终导出类的受保护虚成员函数 do_get_monthname 。
2) 从字符序列 [beg, end) 读取出相继字符，用此 locale 所期待的月名默认格式，同函数 std::get_time 、 time_get::get 和 POSIX 函数 strptime() 所用的 "%b" ，分析出月名（可能为缩写）。

若它找到缩写名，则它持续读取，直至消耗尽完整名的字符，或找到不为期待的字符，后一情况下即使首段字符为合法缩写也分析失败。

存储分析而得的月名于 std::tm 域 t->tm_mon 。

若在读到合法月名之前抵达尾迭代器，则函数设置 err 中的 std::ios_base::eofbit 。若遇到分析错误，则函数设置 err 中的 std::ios_base::failbit 。

参数

beg | - | 指代要分析的序列起始的迭代器
end | - | 要分析的序列的尾后一位置迭代器
str | - | 此函数在需要时用以获得 locale 平面的流对象，例如用 std::ctype 跳过空白符或用 std::collate 比较字符串
err | - | 此函数所修改以指示错误的流错误标志对象
t | - | 指向 std::tm 对象的指针，该对象将保有此函数调用结果

返回值

指向 [beg, end) 中辨识为合法月名部分的末字符后一位置的迭代器。

注意

此函数通常不区别大小写

若遇到分析错误，则此函数的大多数实现保留 *t 不修改。

示例

#include <iostream>
#include <locale>
#include <sstream>
#include <iterator>
#include <ctime>

void try_get_mon(const std::string& s)
{
    std::cout << "Parsing the month out of '" << s <<
                 "' in the locale " << std::locale().name() << '\n';
    std::istringstream str(s);
    std::ios_base::iostate err = std::ios_base::goodbit;

    std::tm t;
    std::istreambuf_iterator<char> ret =
        std::use_facet<std::time_get<char>>(str.getloc()).get_monthname(
            {str}, {}, str, err, &t
        );
    str.setstate(err);
    std::istreambuf_iterator<char> last{};
    if(str) {
        std::cout << "Successfully parsed, month number is " << t.tm_mon;
        if(ret != last) {
            std::cout << ". Remaining content: ";
            std::copy(ret, last, std::ostreambuf_iterator<char>(std::cout));
        } else {
            std::cout << ". The input was fully consumed";
        }
    } else {
        std::cout << "Parse failed. Unparsed string: ";
        std::copy(ret, last, std::ostreambuf_iterator<char>(std::cout));
    }
    std::cout << '\n';
}
int main()
{
    std::locale::global(std::locale("ja_JP.utf8"));
    try_get_mon("2月");
    std::locale::global(std::locale("th_TH.utf8"));
    try_get_mon("กุมภาพันธ์");
    std::locale::global(std::locale("el_GR.utf8"));
    try_get_mon("Φεβ");
    try_get_mon("Φεβρουάριος");
    std::locale::global(std::locale("en_US.utf8"));
    try_get_mon("Febrile");
}

输出：

Parsing the month out of '2月' in the locale ja_JP.utf8
Successfully parsed, month number is 1. The input was fully consumed
Parsing the month out of 'กุมภาพันธ์' in the locale th_TH.utf8
Successfully parsed, month number is 1. The input was fully consumed
Parsing the month out of 'Φεβ' in the locale el_GR.utf8
Successfully parsed, month number is 1. The input was fully consumed
Parsing the month out of 'Φεβρουάριος' in the locale el_GR.utf8
Successfully parsed, month number is 1. The input was fully consumed
Parsing the month out of 'Febrile' in the locale en_US.utf8
Parse failed. Unparsed string: ile

参阅

get_time
(C++11)
 剖析指定格式的日期/时间值
(函数模板)


std::time_get<CharT,InputIt>::get_time, std::time_get<CharT,InputIt>::do_get_time

< cpp‎ | locale‎ | time get
定义于头文件 <locale>
public:

iter_type get_time( iter_type beg, iter_type end, std::ios_base & str,

std::ios_base::iostate & err, std::tm * t) const;
 (1)
protected:

virtual iter_type get_time( iter_type beg, iter_type end, std::ios_base & str,

std::ios_base::iostate & err, std::tm * t) const;
 (2)
1) 公开成员函数，调用最终导出类的受保护虚成员函数 do_get_time 。
2) 从字符序列 [beg, end) 读取相继的字符，并分析出遵循与下列格式指定符相同规则的时间值
'%X' | (C++11 前)
"%H:%M:%S" | (C++11 起)
格式指定符为函数 std::get_time 、 time_get::get 和 POSIX 函数 strptime() 所用。
存储分析的时间到参数 t 所指向的 std::tm 结构体的对应域中。
若在读到合法值前抵达尾迭代器，则函数设置 err 中的 std::ios_base::eofbit 。若遇到分析错误，则函数设置 err 中的 std::ios_base::failbit 。

参数

beg | - | 指代要分析的序列起始的迭代器
end | - | 要分析的序列的尾后一位置迭代器
str | - | 此函数在需要时用以获得 locale 平面的流对象，例如用 std::ctype 跳过空白符
err | - | 此函数所修改以指示错误的流错误标志对象
t | - | 指向 std::tm 对象的指针，该对象将保有此函数调用结果

返回值

指向 [beg, end) 中辨识为合法日期一部分的末字符后一位置的迭代器。

注意

对于默认时间格式的字母组分（若存在），此函数通常不区别大小写。

若遇到分析错误，则此函数的大多数实现保留 *t 不修改。

示例

#include <iostream>
#include <locale>
#include <sstream>
#include <iterator>

void try_get_time(const std::string& s)
{
    std::cout << "Parsing the time out of '" << s <<
                 "' in the locale " << std::locale().name() << '\n';
    std::istringstream str(s);
    std::ios_base::iostate err = std::ios_base::goodbit;

    std::tm t;
    std::istreambuf_iterator<char> ret =
        std::use_facet<std::time_get<char>>(str.getloc()).get_time(
            {str}, {}, str, err, &t
        );
    str.setstate(err);
    if(str) {
        std::cout << "Hours: "   << t.tm_hour << ' '
                  << "Minutes: " << t.tm_min  << ' '
                  << "Seconds: " << t.tm_sec  << '\n';
    } else {
        std::cout << "Parse failed. Unparsed string: ";
        std::copy(ret, {}, std::ostreambuf_iterator<char>(std::cout));
        std::cout << '\n';
    }
}
int main()
{
    std::locale::global(std::locale("ru_RU.utf8"));
    try_get_time("21:40:11");
    try_get_time("21-40-11");

    std::locale::global(std::locale("ja_JP.utf8"));
    try_get_time("21時37分58秒");
}

输出：

Parsing the time out of '21:40:11' in the locale ru_RU.utf8
Hours: 21 Minutes: 40 Seconds: 11
Parsing the time out of '21-40-11' in the locale ru_RU.utf8
Parse failed. Unparsed string: -40-11
Parsing the time out of '21時37分58秒' in the locale ja_JP.utf8
Hours: 21 Minutes: 37 Seconds: 58

参阅

get_time
(C++11)
 剖析指定格式的日期/时间值
(函数模板)


std::time_get<CharT,InputIt>::get_weekday, std::time_get<CharT,InputIt>::do_get_weekday

< cpp‎ | locale‎ | time get
定义于头文件 <locale>
public:

iter_type get_weekday( iter_type beg, iter_type end, std::ios_base & str,

std::ios_base::iostate & err, std::tm * t) const;
 (1)
protected:

virtual iter_type do_get_weekday( iter_type beg, iter_type end, std::ios_base & str,

std::ios_base::iostate & err, std::tm * t) const;
 (2)
1) 公开成员函数，调用最终导出类的受保护虚成员函数 do_get_weekday 。
2) 从字符序列 [beg, end) 读取出相继字符，用此 locale 所期待的星期默认格式，同函数 std::get_time 、 time_get::get 和 POSIX 函数 strptime() 所用的 "%a" ，分析出星期名（可能为缩写）。

若它找到缩写名，则它持续读取，直至消耗尽完整名的字符，或找到不为期待的字符，后一情况下即使首段字符为合法缩写也分析失败。

存储分析得到的星期于 std::tm 域 t->tm_wday 。

若在读到合法星期名前抵达尾迭代器，则函数设置 err 中的 std::ios_base::eofbit 。若遇到分析错误，则函数设置 err 中的 std::ios_base::failbit 。

参数

beg | - | 指代要分析的序列起始的迭代器
end | - | 要分析的序列的尾后一位置迭代器
str | - | 此函数在需要时用以获得 locale 平面的流对象，例如用 std::ctype 跳过空白符或用 std::collate 比较字符串
err | - | 此函数所修改以指示错误的流错误标志对象
t | - | 指向 std::tm 对象的指针，该对象将保有此函数调用结果

返回值

指向 [beg, end) 中辨识为合法星期名一部分的末字符后一位置的迭代器。

注意

此函数通常不区别大小写

若遇到分析错误，则此函数的大多数实现保留 *t 不修改。

示例

#include <iostream>
#include <locale>
#include <sstream>
#include <iterator>

void try_get_wday(const std::string& s)
{
    std::cout << "Parsing the weekday out of '" << s <<
                 "' in the locale " << std::locale().name() << '\n';
    std::istringstream str(s);
    std::ios_base::iostate err = std::ios_base::goodbit;

    std::tm t;
    std::istreambuf_iterator<char> ret =
        std::use_facet<std::time_get<char>>(str.getloc()).get_weekday(
            {str}, {}, str, err, &t
        );
    str.setstate(err);
    std::istreambuf_iterator<char> last{};
    if(str) {
        std::cout << "Successfully parsed, weekday number is " << t.tm_wday;
        if(ret != last) {
            std::cout << " Remaining content: ";
            std::copy(ret, last, std::ostreambuf_iterator<char>(std::cout));
        } else {
            std::cout << " the input was fully consumed";
        }
    } else {
        std::cout << "Parse failed. Unparsed string: ";
        std::copy(ret, last, std::ostreambuf_iterator<char>(std::cout));
    }
    std::cout << '\n';
}
int main()
{
    std::locale::global(std::locale("lt_LT.utf8"));
    try_get_wday("Št");
    try_get_wday("Šeštadienis");

    std::locale::global(std::locale("en_US.utf8"));
    try_get_wday("SATELLITE");

    std::locale::global(std::locale("ja_JP.utf8"));
    try_get_wday("土曜日");
}

输出：

Parsing the weekday out of 'Št' in the locale lt_LT.utf8
Successfully parsed, weekday number is 6 the input was fully consumed
Parsing the weekday out of 'Šeštadienis' in the locale lt_LT.utf8
Successfully parsed, weekday number is 6 the input was fully consumed
Parsing the weekday out of 'SATELLITE' in the locale en_US.utf8
Successfully parsed, weekday number is 6 Remaining content: ELLITE
Parsing the weekday out of '土曜日' in the locale ja_JP.utf8
Successfully parsed, weekday number is 6 the input was fully consumed

参阅

get_time
(C++11)
 剖析指定格式的日期/时间值
(函数模板)


std::time_get<CharT,InputIt>::get_year, std::time_get<CharT,InputIt>::do_get_year

< cpp‎ | locale‎ | time get
定义于头文件 <locale>
public:

iter_type do_get_year( iter_type s, iter_type end, std::ios_base & str,

std::ios_base::iostate & err, std::tm * t) const;
 (1)
protected:

virtual iter_type do_get_year( iter_type s, iter_type end, std::ios_base & str,

std::ios_base::iostate & err, std::tm * t) const;
 (2)
1) 公开成员函数，调用最终导出类的受保护虚成员函数 do_get_year 。
2) 读取来自序列 [beg, end) 的相继字符，用某实现定义格式分析出年。取决于 locale ，可能接受二位的年，而它们属于哪个世纪是实现定义的。

存储分析而得的年于 std::tm 结构体域 t->tm_year 。

若在读到合法日期前抵达尾迭代器，则函数设置 err 中的 std::ios_base::eofbit 。若遇到分析错误，则函数设置 err 中的 std::ios_base::failbit 。

参数

beg | - | 指代要分析的序列起始的迭代器
end | - | 要分析的序列的尾后一位置迭代器
str | - | 此函数在需要时用以获得 locale 平面的流对象，例如用 std::ctype 跳过空白符或用 std::collate 比较字符串
err | - | 此函数所修改以指示错误的流错误标志对象
t | - | 指向 std::tm 对象的指针，该对象将保有此函数调用结果

返回值

指向 [beg, end) 中辨识为合法年一部分的末字符后一位置的迭代器。

注意

对于二位输入值，许多实现使用同 std::get_time 、 std::time_get::get() 和 POSIX 函数 strptime() 所用的转换指定符 '%y' 的分析规则：期待二位整数，范围 [69,99] 中的值导致值 1969 到 1999 ，范围 [00,68] 导致 2000-2068 。四位输入典型地保持原状接受。

若遇到分析错误，则此函数的大多数实现保留 *t 不修改。

示例

#include <iostream>
#include <locale>
#include <sstream>
#include <iterator>

void try_get_year(const std::string& s)
{
    std::cout << "Parsing the year out of '" << s <<
                 "' in the locale " << std::locale().name() << '\n';
    std::istringstream str(s);
    std::ios_base::iostate err = std::ios_base::goodbit;

    std::tm t;
    std::istreambuf_iterator<char> ret =
        std::use_facet<std::time_get<char>>(str.getloc()).get_year(
            {str}, {}, str, err, &t
        );
    str.setstate(err);
    std::istreambuf_iterator<char> last{};
    if (str) {
        std::cout << "Successfully parsed, year is " << 1900 + t.tm_year;
        if (ret != last) {
            std::cout << " Remaining content: ";
            std::copy(ret, last, std::ostreambuf_iterator<char>(std::cout));
        } else {
            std::cout << " the input was fully consumed";
        }
    } else {
        std::cout << "Parse failed. Unparsed string: ";
        std::copy(ret, last, std::ostreambuf_iterator<char>(std::cout));
    }
    std::cout << '\n';
}

int main()
{
    std::locale::global(std::locale("en_US.utf8"));
    try_get_year("13");
    try_get_year("2013");

    std::locale::global(std::locale("ja_JP.utf8"));
    try_get_year("2013年");
}

可能的输出：

Parsing the year out of '13' in the locale en_US.utf8
Successfully parsed, year is 2013 the input was fully consumed
Parsing the year out of '2013' in the locale en_US.utf8
Successfully parsed, year is 2013 the input was fully consumed
Parsing the year out of '2013年' in the locale ja_JP.utf8
Successfully parsed, year is 2013 Remaining content: 年

参阅

get_time
(C++11)
 剖析指定格式的日期/时间值
(函数模板)


std::time_get<CharT,InputIt>::time_get

< cpp‎ | locale‎ | time get

定义于头文件 <locale>
explicit time_get( std::size_t refs = 0 );

创建 std::time_get 平面并转发引用计数 refs 到基类构造函数 locale::facet::facet() 。

参数

refs - 开始的引用计数


std::time_get<CharT,InputIt>::~time_get

< cpp‎ | locale‎ | time get

定义于头文件 <locale>
protected: ~time_get();

析构 std::time_get 平面。此析构函数为受保护且为虚（由于基类析构函数为虚）。 std::time_get 类型对象，同大多数平面，只能在最后一个实装此平面的 std::locale 离开作用域时，或若用户定义导出自 std::time_get 并实现公开构造函数，才会被销毁。

示例

#include <iostream>
#include <locale>
struct Destructible_time_get : public std::time_get<wchar_t>
{
    Destructible_time_get(std::size_t refs = 0) : time_get(refs) {}
    // 注意：隐式析构函数为公开
};
int main()
{
    Destructible_time_get dc;
    // std::time_get<wchar_t> c;  // 编译错误：受保护析构函数
}


std::time_get_byname

< cpp‎ | locale
定义于头文件 <locale>
template<

class CharT,
class InputIterator = std::istreambuf_iterator <CharT>

> class time_get_byname : public std::time_get <CharT, InputIterator>

std::time_get_byname 是 std::time_get 平面，封装在其构造时指定的 locale 的日期和时间分析规则。

标准库提供二个特化

定义于头文件 <locale>
std::time_get_byname<char, InputIterator> | 窄/多字节时间分析
std::time_get_byname<wchar_t, InputIterator> | 宽字符串时间分析

成员类型

成员类型 | 定义
char_type | CharT
iter_type | OutputIterator

成员函数

(构造函数) | 构造新的 time_get_byname 平面 (公开成员函数)
(析构函数) | 析构 time_get_byname 平面 (受保护成员函数)

std::time_get_byname::time_get_byname

explicit time_get_byname( const char* name, std::size_t refs = 0 ); |
explicit time_get_byname( const std::string & name, std::size_t refs = 0 ); | (C++11 起)

为名为 name 的本地环境构造新的 std::time_get_byname 平面。

refs 用于资源管理：在销毁最后一个保有平面的 std::locale 对象时，若 refs == 0 ，则实现销毁平面对象。否则，不销毁对象。

参数

name | - | 本地环境的名称
refs | - | 链接到该平面的引用数

std::time_get_byname::~time_get_byname

protected:
~time_get_byname();

销毁平面。

继承自 std::time_get

成员类型 | 定义
char_type | CharT
iter_type | InputIt

成员对象

成员名 | 类型
id [静态] | std::locale::id

成员函数

date_order | 调用 do_date_order (std::time_get<CharT,InputIt> 的公开成员函数)
get_time | 调用 do_get_time (std::time_get<CharT,InputIt> 的公开成员函数)
get_date | 调用 do_get_date (std::time_get<CharT,InputIt> 的公开成员函数)
get_weekday | 调用 do_get_weekday (std::time_get<CharT,InputIt> 的公开成员函数)
get_monthname | 调用 do_get_monthname (std::time_get<CharT,InputIt> 的公开成员函数)
get_year | 调用 do_get_year (std::time_get<CharT,InputIt> 的公开成员函数)
get (C++11) | 调用 do_get (std::time_get<CharT,InputIt> 的公开成员函数)

受保护成员函数

do_date_order [虚] | 获得偏好的日、月、年顺序 (std::time_get<CharT,InputIt> 的虚受保护成员函数)
do_get_time [虚] | 从输入流释出时、分、秒 (std::time_get<CharT,InputIt> 的虚受保护成员函数)
do_get_date [虚] | 从输入流输出月、日以及年 (std::time_get<CharT,InputIt> 的虚受保护成员函数)
do_get_weekday [虚] | 从输入流释出星期的日名 (std::time_get<CharT,InputIt> 的虚受保护成员函数)
do_get_monthname [虚] | 从输入流释出月名 (std::time_get<CharT,InputIt> 的虚受保护成员函数)
do_get_year [虚] | 从输入流释出年份 (std::time_get<CharT,InputIt> 的虚受保护成员函数)
do_get [虚] (C++11) | 从输入流释出日期/时间组分，按照指定格式 (std::time_get<CharT,InputIt> 的虚受保护成员函数)

继承自 std::time_base

类型 | 定义
dateorder | 日期顺序枚举类型，定义值 no_order 、 dmy 、 mdy 、 ymd 及 ydm

示例

本节未完成
原因：暂无示例

参阅

time_get | 从输入字符序列中解析时间/日期值到 std::tm 中 (类模板)
get_time (C++11) | 剖析指定格式的日期/时间值 (函数模板)


std::time_put

< cpp‎ | locale
定义于头文件 <locale>
template<

class CharT,
class OutputIt = std::ostreambuf_iterator <CharT>

> class time_put;

类模板 std::time_put 封装日期和时间格式化规则。 I/O 操纵符 std::put_time 用 I/O 流的 locale 的 std::time_put 平面生成 std::tm 对象的文本表示。

cpp/locale/time base cpp/locale/locale/facet

继承图

类型要求

-
OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。

特化

标准库提供二个（独立于本地环境）的全特化和二个部分特化：

定义于头文件 <locale>
std::time_put<char> | 创建日期和时间的窄字符串表示
std::time_put<wchar_t> | 创建日期和时间的宽字符串表示
std::time_put<char, OutputIt> | 用定制输出迭代器创建日期和时间的窄字符串表示
std::time_put<wchar_t, OutputIt> | 用定制输出迭代器创建日期和时间的宽字符串表示

另外， C++ 程序中构造的每个 locale 对象都实装这些特化的其自身（本地环境限定）版本。

成员类型

成员类型 | 定义
char_type | CharT
iter_type | OutputIt

成员函数

(构造函数) | 构造新的 time_put 平面 (公开成员函数)
(析构函数) | 析构 time_put 平面 (受保护成员函数)
put | 调用 do_put (公开成员函数)

成员对象

static std::locale::id id
 locale 的 id
(公开成员对象)

受保护成员函数

do_put
[虚]
 格式化日期/时间并写入输出流
(虚受保护成员函数)

示例

#include <iostream>
#include <ctime>
#include <iomanip>
#include <codecvt>

int main()
{
    std::time_t t = std::time(NULL);
    std::wbuffer_convert<std::codecvt_utf8<wchar_t>> conv(std::cout.rdbuf());
    std::wostream out(&conv);
    out.imbue(std::locale("ja_JP.utf8"));
    // 此 I/O 操纵符 std::put_time 使用 std::time_put<wchar_t>
    out << std::put_time(std::localtime(&t), L"%A %c") << '\n';
}

输出：

水曜日 2011年11月09日 12時32分05秒

参阅

time_put_byname | 表示系统提供的具名本地环境的 std::time_put (类模板)
time_get | 从输入字符序列中解析时间/日期值到 std::tm 中 (类模板)
put_time (C++11) | 按照指定格式格式化并输出日期/时间值 (函数模板)


std::time_put<CharT,OutputIt>::put, std::time_put<CharT,OutputIt>::do_put

< cpp‎ | locale‎ | time put
定义于头文件 <locale>
public:

iter_type put( iter_type out, std::ios_base & str,
char_type fill, const std::tm * t,

const CharT* fmtbeg, const CharT* fmtend ) const;
 (1)
public:

iter_type put( iter_type out, std::ios_base & str,
char_type fill, const std::tm * t,

char format, char modifier = 0 ) const;
 (2)
protected:

virtual iter_type do_put( iter_type out, std::ios_base & str,
char_type fill, const std::tm * t,

char format, char modifier ) const;
 (3)

按照格式字符串 [fmtbeg, fmtend) ，转换存储于 t 所指向的 std::tm 对象中的日历日期和时间为字符串。格式字符串同 std::strftime 所用者，但用对 do_put() 的单独调用处理每个格式指定符，这可以通过扩展此刻面定制。

1) 逐步通过字符序列 [fmtbeg, fmtend) ，检验字符。每个不是格式序列的字符都被立即写入输出迭代器 out 。为鉴别格式序列，此函数如同用 std::ctype <char_type>(str.getloc()).narrow(c,0) 窄化 [fmtbeg, fmtend) 中的下个字符 c ，而若它等于 '%' ，则将下一或二个字符与 std::strftime 所辨识的格式序列列表，加此 locale 所支持的任何额外实现定义格式比较。对每个合法格式序列进行调用 do_put(out, str, fill, t, format, modifier) ，其中 format 为格式序列字符，而 modifier 是可选的格式序列修饰符（ 'E' 或 'O' ）。若修饰符不存在则使用值 '\0' 。
2) 调用最终导出类的 do_put 成员函数。
3) 按照由连接 '%' 、若 modifier 非 '\0' 则有其值，和 format 的值组成的格式转换序列，转换存储于 t 所指向的 std::tm 对象中的日历日期和时间为字符串。格式转译方式同函数 std::strftime ，除了描述为本地环境依赖的格式由此 locale 定义，而且可以支持另外的格式指定符（为这些要使用的实现定义格式指定符提供 fill 参数）。将字符串写入输出迭代器 out 。

参数

out - 输出迭代器，其中写入转换结果
str - 此函数在需要时用以获得本地环境刻面的流对象，例如用 std::ctype 窄化字符
t - 指向 std::tm 对象的指针，从该对象获得日期/时间值
fmtbeg - 指向指定转换格式的 char_type 字符序列首字符的指针

格式字符串由零或更多个说明符和通常字符（除 % ）构成。所有通常字符，包括空终止字符，都会被复制到输出字符串而不加修改。每个转换说明符都始于 % 字符，可选地跟随 E 或 O 修饰符（若本地环境不支持则忽略），后随决定修饰符行为的字符。下列修饰符格式可用：

转换
说明符 		解释 使用的域
% 写字面的 % 。完整转换说明必须是 %% 。
n
(C++11) 		写换行符
t
(C++11) 		写水平制表符
年
Y | 以 4 位十进制数写年。 | tm_year
EY
(C++11) 		以替用方式写年。例如在 ja_JP 本地环境中，以“平成23年”取代“2011年”。 tm_year
y | 写年的末 2 位十进制数（范围[00,99]）。 | tm_year
Oy
(C++11) 		以替用数字系统写年的末 2 位数字。例如在 ja_JP 本地环境中以“十一”取代“11”。 tm_year
Ey
(C++11) 		将年写作从本地环境的替用时期 %EC 的偏移（本地环境依赖）。 tm_year
C
(C++11) 		写年的首 2 位十进制数（范围 [00,99] ）。 tm_year
EC
(C++11) 		以本地环境的替用表示写年份基底（时期），例如 ja_JP 中的“平成”。 tm_year
G
(C++11) 		写基于 ISO 8601 的年，即是包含指定星期的年份。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
g
(C++11) 		写基于 ISO 8601 的年，即是包含指定星期年份，的后 2 位数（范围 [00,99] ）。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
月
b | 写缩略月名，例如 Oct （本地环境依赖）。 | tm_mon
h
(C++11) 		与 b 同意。 tm_mon
B | 写完整月名，例如 October （本地环境依赖）。 | tm_mon
m | 将月写作十进制数（范围 [01,12] ）。 | tm_mon
Om
(C++11) 		以替用数字系统写月。例如 ja_JP 本地环境中“十二”取代“12”。 tm_mon
星期
U | 以十进制数写年的星期（星期日是星期的首日）（范围 [00,53] ）。 | tm_year, tm_wday, tm_yday
OU
(C++11) 		以替用数值系统写如同用 %U 的年的星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
W | 以十进制数写年的星期（星期一是星期的首日）（范围 [00,53] ）。 | tm_year, tm_wday, tm_yday
OW
(C++11) 		以替用数值系统写如同用 %W 的年的第星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
V
(C++11) 		写 ISO 8601 的年的星期（范围[00,53]）。

IS0 8601 中星期以星期一开始，而且一年的首星期必须满足下列要求：

  • 包含 1 月 4 日
  • 包含一年的首个星期四
 tm_year, tm_wday, tm_yday
OV
(C++11) 		以替用数值系统写如同用 %V 的年的星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 tm_year, tm_wday, tm_yday
年/月之日
j | 以十进制数写年的第几日（范围 [001,366] ）。 | tm_yday
d | 以十进制数写月的第几日（范围 [01,31] ）。 | tm_mday
Od
(C++11) 		以替用数字系统写零基的月的第几日。例如 ja_JP 本地环境中“二十七”取代“ 27 ”。

单字符前加空格。

 tm_mday
e
(C++11) 		以十进制数写月的第几日（范围[01,31]）。

单数字前加空格。

 tm_mday
Oe
(C++11) 		以替用数字系统写一基的月的第几日。例如 ja_JP 本地环境中“二十七”取代“27”。

单字符前加空格。

 tm_mday
星期之日
a | 写缩略的星期日期名，例如 Fri （本地环境依赖）。 | tm_wday
A | 写完整的星期日期名，例如 Friday （本地环境依赖）。 | tm_wday
w | 以十进制数写星期日期，其中星期日是 0 （范围 [0-6] ）。 | tm_wday
Ow
(C++11) 		用替用数字系统写星期日期，其中星期日是 0 。例如 ja_JP 本地环境中“二”取代“2”。 tm_wday
u
(C++11) 		十进制数写星期日期，其中星期一是 1 （ ISO 8601 格式）（范围 [1-7] ）。 tm_wday
Ou
(C++11) 		用替用数字系统写星期日期，其中星期一是 1 。例如 ja_JP 本地环境中“二”取代“2”。 tm_wday
时、分、秒
H | 以十进制数写时， 24 小时制（范围 [00-23] ）。 | tm_hour
OH
(C++11) 		以替用数字系统写 24 小时制的时。例如 ja_JP 本地环境中“十八”取代“18”。 tm_hour
I | 以十进制数写时， 12 小时制（范围 [01,12] ）。 | tm_hour
OI
(C++11) 		以替用数字系统写 12 小时制的时。例如 ja_JP 本地环境中“六”取代“6”。 tm_hour
M | 以十进制数写分（范围 [00,59] ）。 | tm_min
OM
(C++11) 		以替用数字系统写分。例如 ja_JP 本地环境中“二十五”取代“25”。 tm_min
S | 以十进制数写秒（范围 [00,60] ）。 | tm_sec
OS
(C++11) 		以替用数字系统写秒。例如 ja_JP 本地环境中“二十四”取代“24”。 tm_sec
其他
c | 写标准日期时间字符串。例如 Sun Oct 17 04:41:13 2010 （本地环境依赖）。 | 全部
Ec
(C++11) 		写替用日期时间字符串。例如 ja_JP 本地环境中“平成23年”取代“2011年”。 全部
x | 写本地化的日期表示（本地环境依赖）。 | 全部
Ex
(C++11) 		写替用日期表示。例如 ja_JP 本地环境中“平成23年”取代“2011年”。 全部
X | 写本地化的时间表示，例如 18:40:20 或 6:40:20 PM （本地环境依赖）。 | 全部
EX
(C++11) 		写替用时间表示（本地环境依赖）。 全部
D
(C++11) 		等价于"%m/%d/%y"。 tm_mon, tm_mday, tm_year
F
(C++11) 		等价于"%Y-%m-%d"（ ISO 8601 日期格式）。 tm_mon, tm_mday, tm_year
r
(C++11) 		写本地化的 12 小时制时间（本地环境依赖）。 tm_hour, tm_min, tm_sec
R
(C++11) 		等价于"%H:%M"。 tm_hour, tm_min
T
(C++11) 		等价于"%H:%M:%S"（ ISO 8601 时间格式）。 tm_hour, tm_min, tm_sec
p | 写本地化的 a.m. 或 p.m. （本地环境依赖）。 | tm_hour
z
(C++11) 		以 ISO 8601 格式（例如 -0430 ）写距 UTC 的偏移，或者倘若时区信息不可用则不写字符。 tm_isdst
Z | 写依赖本地环境的时区名或缩写，或者若时区信息不可用则不写字符。 | tm_isdst

fmtend - 指向指定转换格式的 char_type 字符序列的末字符后一位置的指针
fill - 填充字符（通常为空格）
format - 指名转换指定符的字符
modifier - 可出现于 % 和转换指定符间的可选修饰符

返回值

指向最后产生字符后一位置的迭代器。

注解

不提供错误处理。

为实现定义的格式指定符，和使用填充和填满逻辑的用户定义的 do_put() 覆写提供 fill 字符。这种实现典型地利用来自 str 的格式化标志。

示例

#include <iostream>
#include <sstream>
#include <iomanip>
#include <ctime>

void try_time_put(const std::tm* t, const std::string& fmt)
{
        std::cout.imbue(std::locale());
        std::cout << "In the locale '" << std::cout.getloc().name() << "' : '";

        std::use_facet<std::time_put<char>>(std::cout.getloc()).put(
                    {std::cout}, std::cout, ' ', t, &fmt[0], &fmt[0] + fmt.size());

        std::cout << "'\n";
}

int main()
{
    std::time_t t = std::time(NULL);
    std::tm tm = *std::localtime(&t);

    std::string fmt = "%c";
    std::cout << "Using the format string '" << fmt
              << "' to format the time: " << std::ctime(&t) << '\n';

    std::locale::global(std::locale("de_DE.utf8"));
    try_time_put(&tm, fmt);

    std::locale::global(std::locale("el_GR.utf8"));
    try_time_put(&tm, fmt);

    std::locale::global(std::locale("ja_JP.utf8"));
    try_time_put(&tm, fmt);
}

输出：

Using the format string '%c' to format the time: Mon Feb 11 22:58:50 2013

In the locale 'de_DE.utf8' : 'Mo 11 Feb 2013 23:02:38 EST'
In the locale 'el_GR.utf8' : 'Δευ 11 Φεβ 2013 11:02:38 μμ EST'
In the locale 'ja_JP.utf8' : '2013年02月11日 23時02分38秒'

参阅

put_time (C++11) | 按照指定格式格式化并输出日期/时间值 (函数模板)
do_get [虚] (C++11) | 从输入流释出日期/时间组分，按照指定格式 (std::time_get<CharT,InputIt> 的虚受保护成员函数)


std::time_put<CharT,OutputIt>::time_put

< cpp‎ | locale‎ | time put

定义于头文件 <locale>
explicit time_put( std::size_t refs = 0 );

创建 std::time_put 平面并转发引用计数 refs 到基类构造函数 locale::facet::facet() 。

参数

refs - 开始的引用计数


std::time_put<CharT,OutputIt>::~time_put

< cpp‎ | locale‎ | time put

定义于头文件 <locale>
protected: ~time_put();

析构 std::time_put 平面。此析构函数为受保护且为虚（由于基类析构函数为虚）。 std::time_put 类型对象，同大多数平面，只能在最后一个实装此平面的 std::locale 离开作用域时，或若用户定义导出自 std::time_put 并实现公开构造函数，才会被销毁。

示例

#include <iostream>
#include <locale>
struct Destructible_time_put : public std::time_put<wchar_t>
{
    Destructible_time_put(std::size_t refs = 0) : time_put(refs) {}
    // 注意：隐式析构函数为公开
};
int main()
{
    Destructible_time_put dc;
    // std::time_put<wchar_t> c;  // 编译错误：受保护析构函数
}


std::time_put_byname

< cpp‎ | locale
定义于头文件 <locale>
template< class CharT, class OutputIterator = std::ostreambuf_iterator <CharT> >
class time_put_byname : public std::time_put <CharT, OutputIterator>;

std::time_put_byname 是 std::time_put 平面，封装在其构造时指定的 locale 的日期和时间格式化规则。

标准库提供二个特化

定义于头文件 <locale>
std::time_put_byname<char, OutputIterator> | 窄/多字节时间格式化
std::time_put_byname<wchar_t, OutputIterator> | 宽字符串时间格式化

成员类型

成员类型 | 定义
char_type | CharT
iter_type | OutputIterator

成员函数

(构造函数) | 构造新的 time_put_byname 平面 (公开成员函数)
(析构函数) | 析构 time_put_byname 平面 (受保护成员函数)

std::time_put_byname::time_put_byname

explicit time_put_byname( const char* name, std::size_t refs = 0 ); |
explicit time_put_byname( const std::string & name, std::size_t refs = 0 ); | (C++11 起)

为名为 name 的本地环境构造新的 std::time_put_byname 平面。

refs 用于资源管理：在销毁最后一个保有平面的 std::locale 对象时，若 refs == 0 ，则实现销毁平面对象。否则，不销毁对象。

参数

name | - | 本地环境的名称
refs | - | 链接到该平面的引用数

std::time_put_byname::~time_put_byname

protected:
~time_put_byname();

销毁平面。

继承自 std::time_put

成员对象

成员名 | 类型
id [静态] | std::locale::id

成员函数

put
 调用 do_put
(std::time_put<CharT,OutputIt> 的公开成员函数)

受保护成员函数

do_put
[虚]
 格式化日期/时间并写入输出流
(std::time_put<CharT,OutputIt> 的虚受保护成员函数)

示例

此示例用被各种 time_put_byname 平面替换了 time_put 平面的 "C" 本地环境打印当前时间

#include <iostream>
#include <ctime>
#include <iomanip>
#include <codecvt>

int main()
{
    std::time_t t = std::time(NULL);
    std::wbuffer_convert<std::codecvt_utf8<wchar_t>> conv(std::cout.rdbuf());
    std::wostream out(&conv);

    out.imbue(std::locale(out.getloc(),
                          new std::time_put_byname<wchar_t>("ja_JP")));
    out << std::put_time(std::localtime(&t), L"%A %c") << '\n';

    out.imbue(std::locale(out.getloc(),
                         new std::time_put_byname<wchar_t>("ru_RU.utf8")));
    out << std::put_time(std::localtime(&t), L"%A %c") << '\n';

    out.imbue(std::locale(out.getloc(),
                         new std::time_put_byname<wchar_t>("sv_SE.utf8")));
    out << std::put_time(std::localtime(&t), L"%A %c") << '\n';
}

可能的输出：

木曜日 2012年08月09日 21時41分02秒
Четверг Чт. 09 авг. 2012 21:41:02
torsdag tor  9 aug 2012 21:41:02

参阅

time_put
 格式化 std::tm 内容为字符序列以输出
(类模板)


std::tolower(std::locale)

< cpp‎ | locale
定义于头文件 <locale>
template< class charT >
charT tolower( charT ch, const locale& loc );

用给定 loacale 的 std::ctype 平面所指定的转换规则，若可能则转换字符 ch 为小写。

参数

ch | - | 字符
loc | - | 本地环境

返回值

若 ch 的小写形式列于 locale 则返回它，否则返回不更改的 ch 。

注意

此函数只能进行 1:1 字符映射。例如希腊文大写字母 'Σ' 拥有两个小写形式： 'σ' 与 'ς'，使用哪一个取决于其在词中的位置 。此情况下对 do_tolower 的调用不能获得正确的小写形式。

可能的实现

template< class charT >
charT tolower( charT ch, const std::locale& loc ) {
    return std::use_facet<std::ctype<charT>>(loc).tolower(ch);
}

示例

#include <iostream>
#include <cwctype>
#include <locale>

int main()
{
    wchar_t c = L'\u0190'; // 拉丁文大写开 E ('Ɛ')

    std::cout << std::hex << std::showbase;

    std::cout << "in the default locale, tolower(" << (std::wint_t)c << ") = "
              << std::tolower(c, std::locale()) << '\n';

    std::cout << "in Unicode locale, tolower(" << (std::wint_t)c << ") = "
              << std::tolower(c, std::locale("en_US.utf8")) << '\n';
}

输出：

in the default locale, tolower(0x190) = 0x190
in Unicode locale, tolower(0x190) = 0x25b

参阅

toupper(std::locale) | 用本地环境的 ctype 刻面将字符转换为大写 (函数模板)
tolower | 转换字符为小写 (函数)
towlower | 转换宽字符为小写 (函数)


std::toupper(std::locale)

< cpp‎ | locale
定义于头文件 <locale>
template< class charT >
charT toupper( charT ch, const locale& loc );

用给定 loacale 的 std::ctype 平面所指定的转换规则，若可能则转换字符 ch 为大写。

参数

ch | - | 字符
loc | - | 本地环境

返回值

若 ch 的大写形式列于 locale 则返回它，否则返回不更改的 ch 。

注意

此函数只能进行 1:1 字符映射，例如 'ß' 的大写形式（有一些例外）是双字符字符串 "SS" ，它无法以 do_toupper 获得。

可能的实现

template< class charT >
charT toupper( charT ch, const std::locale& loc ) {
    return std::use_facet<std::ctype<charT>>(loc).toupper(ch);
}

示例

#include <iostream>
#include <cwctype>
#include <locale>

int main()
{
    wchar_t c = L'\u017f'; // 拉丁文小写字母长 S ('ſ')

    std::cout << std::hex << std::showbase;

    std::cout << "in the default locale, toupper(" << (std::wint_t)c << ") = "
              << std::toupper(c, std::locale()) << '\n';

    std::cout << "in Unicode locale, toupper(" << (std::wint_t)c << ") = "
              << std::toupper(c, std::locale("en_US.utf8")) << '\n';
}

输出：

in the default locale, toupper(0x17f) = 0x17f
in Unicode locale, toupper(0x17f) = 0x53

参阅

tolower(std::locale) | 用本地环境的 ctype 刻面将字符转换为小写 (函数模板)
toupper | 转换字符为大写 (函数)
towupper | 转换宽字符为大写 (函数)


std::use_facet

< cpp‎ | locale
定义于头文件 <locale>
template< class Facet >
const Facet& use_facet( const std::locale & loc );

获得到 loc 所实装的平面的引用。

参数

loc - 要查询的 locale 对象

返回值

返回到平面的引用，只要存在任何 std::locale 对象实装 Facet ，则此函数所返回的引用就合法。

异常

若 std::has_facet <Facet>(loc) == false 则为 std::bad_cast 。

示例

显示用户偏好的本地环境所用的 3 字母金额名

#include <iostream>
#include <locale>

int main()
{
    std::locale loc = std::locale(""); // 用户偏好的本地环境
    std::cout << "Your currency string is "
              << std::use_facet<std::moneypunct<char, true>>(loc).curr_symbol() << '\n';
}

输出：

Your currency string is USD

参阅

locale | 用以封装文化差异的多态刻面的集合 (类)
has_facet | 检查本地环境是否实现特定的刻面 (函数模板)


std::wbuffer_convert

< cpp‎ | locale
定义于头文件 <locale> |
template<class Codecvt, class Elem = wchar_t, class Tr = std::char_traits <Elem> > class wbuffer_convert : public std::basic_streambuf <Elem, Tr> | (C++11 起) (C++17 中弃用)

std::wbuffer_convert 是 std::basic_streambuf <char> 类型流缓冲上的包装器，并给予它 std::basic_streambuf <Elem> 的外观。所有通过 std::wbuffer_convert 进行的 I/O 都会经历平面 Codecvt 所定义的字符转换。 std::wbuffer_convert 假设拥有转换平面的所有权，而不能使用 locale 所管理的转换平面。适用于 std::wbuffer_convert 的标准平面对于 UTF-8/UCS2 和 UTF-8/UCS4 转换是 std::codecvt_utf8 ，而对于 UTF-8/UTF-16 转换是 std::codecvt_utf8_utf16 。

此类模板令 std::basic_filebuf 的隐式字符转换功能对任何 std::basic_streambuf 可用。

成员类型

成员类型 | 定义
state_type | Codecvt::state_type

成员函数

(构造函数) | 构造新的 wbuffer_convert (公开成员函数)
operator= | 复制赋值运算符被删除 (公开成员函数)
(析构函数) | 析构 wbuffer_convert 及其转换平面 (公开成员函数)
rdbuf | 返回或替换底层窄流缓冲 (公开成员函数)
state | 返回当前转换状态 (公开成员函数)

参阅

字符转换 | 本地环境定义多字节 (UTF-8, GB18030) | UTF-8 | UTF-16
UTF-16 | mbrtoc16 / c16rtomb (有 C11 的 DR488) | codecvt<char16_t, char, mbstate_t> codecvt_utf8_utf16<char16_t> codecvt_utf8_utf16<char32_t> codecvt_utf8_utf16<wchar_t> | N/A
UCS2 | c16rtomb (无 C11 的 DR488) | codecvt_utf8<char16_t> codecvt_utf8<wchar_t>(Windows) | codecvt_utf16<char16_t> codecvt_utf16<wchar_t>(Windows)
UTF-32 | mbrtoc32 / c32rtomb | codecvt<char32_t, char, mbstate_t> codecvt_utf8<char32_t> codecvt_utf8<wchar_t>(非 Windows) | codecvt_utf16<char32_t> codecvt_utf16<wchar_t>(非 Windows)
系统宽 UTF-32(非 Windows) UCS2(Windows) | mbsrtowcs / wcsrtombs use_facet<codecvt <wchar_t, char, mbstate_t>>(locale) | 无 | 无
wstring_convert (C++11)(C++17 中弃用) | 进行宽字符串和字节字符串之间的转换 (类模板)
codecvt_utf8 (C++11)(C++17 中弃用) | 在 UTF-8 与 UCS2/UCS4 间转换 (类模板)
codecvt_utf8_utf16 (C++11)(C++17 中弃用) | 在 UTF-8 与 UTF-16 间转换 (类模板)


std::wbuffer_convert<Codecvt,Elem,Tr>::rdbuf

< cpp‎ | locale‎ | wbuffer convert
定义于头文件 <locale> |
std::streambuf * rdbuf() const; | (1)
std::streambuf * rdbuf( std::streambuf * bytebuf ); | (2)

1) 返回指向底层字节流的指针。

2) 以 bytebuf 替换关联字节流。

返回值

1) 当前的底层字节流

2) 先前的字节流

示例

#include <iostream>
#include <sstream>
#include <locale>
#include <codecvt>
int main()
{
    // 转换 UTF-8 到 UCS4
    std::stringbuf utf8buf(u8"z\u00df\u6c34\U0001d10b");  // 或 u8"zß水𝄋"
                       // 或 "\x7a\xc3\x9f\xe6\xb0\xb4\xf0\x9d\x84\x8b";
    std::wbuffer_convert<std::codecvt_utf8<wchar_t>> conv(&utf8buf);
    std::wistream ucsbuf(&conv);
    std::cout << "Reading from a UTF-8 stringbuf via wbuffer_convert:\n";
    for(wchar_t c; ucsbuf.get(c); )
        std::cout << std::hex << std::showbase << c << '\n';

    // 复用同一 wbuffer_convert ，以处理 UCS4 到 UTF-8 的输出
    conv.rdbuf(std::cout.rdbuf());
    std::wostream out(&conv);
    std::cout << "Sending UCS4 data to std::cout via wbuffer_convert:\n";
    out << L"z\u00df\u6c34\U0001d10b\n";
}

输出：

Reading from a UTF-8 stringbuf via wbuffer_convert:
0x7a
0xdf
0x6c34
0x1d10b
Sending UCS4 data to std::cout via wbuffer_convert:
zß水𝄋

参阅

(构造函数)
 构造新的 wbuffer_convert
(公开成员函数)


std::wbuffer_convert<Codecvt,Elem,Tr>::state

< cpp‎ | locale‎ | wbuffer convert
定义于头文件 <locale>
state_type state() const;

返回存储于 wbuffer_convert 对象的转换状态的当前值。转换状态可在构造函数中显式设置，并为所有转换操作所更新。

返回值

当前转换状态。

示例

本节未完成
原因：暂无示例

参阅

state | 返回当前转换状态 (std::wstring_convert<Codecvt,Elem,Wide_alloc,Byte_alloc> 的公开成员函数)
mbsinit | 检查 mbstate_t 对象是否表示初始迁移状态 (函数)


std::wbuffer_convert<Codecvt,Elem,Tr>::wbuffer_convert

< cpp‎ | locale‎ | wbuffer convert
wbuffer_convert() : wbuffer_convert(nullptr) { }
 (1)
explicit wbuffer_convert( std::streambuf * bytebuf,

Codecvt* pcvt = new Codecvt,

state_type state = state_type() );
 (2)
wbuffer_convert(const std::wbuffer_convert &) = delete;
 (3) (C++14 起)
1) 默认构造函数。
2) 以指定的底层字节流、指定的 codecvt 平面和指定的初始转换状态构造 wbuffer_convert 对象（所有参数均为可选）。
3) 复制构造函数被删除。 wbuffer_convert 非可复制构造 (CopyConstructible) 。

参数

bytebuf | - | 指向作为底层窄字符流作用的 std::streambuf 的指针
pcvt | - | 指向独立（不为 locale 所管理）的 std::codecvt 平面的指针。若此指针为空则行为未定义。
state | - | 字符转换状态的初始值

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式

示例

#include <iostream>
#include <sstream>
#include <locale>
#include <codecvt>
int main()
{
    // 包装 UTF-8 字符串流于 UCS4 wbuffer_convert 中
    std::stringbuf utf8buf(u8"z\u00df\u6c34\U0001f34c");  // 或 u8"zß水🍌"
                       // 或 "\x7a\xc3\x9f\xe6\xb0\xb4\xf0\x9f\x8d\x8c";
    std::wbuffer_convert<std::codecvt_utf8<wchar_t>> conv_in(&utf8buf);
    std::wistream ucsbuf(&conv_in);
    std::cout << "Reading from a UTF-8 stringbuf via wbuffer_convert:\n";
    for(wchar_t c; ucsbuf.get(c); )
        std::cout << std::hex << std::showbase << c << '\n';

    // 包装具 UTF-8 的 std::cout 于 UCS4 wbuffer_convert 中以输出 UCS4
    std::wbuffer_convert<std::codecvt_utf8<wchar_t>> conv_out(std::cout.rdbuf());
    std::wostream out(&conv_out);
    std::cout << "Sending UCS4 data to std::cout via wbuffer_convert:\n";
    out << L"z\u00df\u6c34\U0001f34c\n";
}

输出：

Reading from a UTF-8 stringbuf via wbuffer_convert produces
0x7a
0xdf
0x6c34
0x1f34c
Sending UCS4 data to std::cout via wbuffer_convert:
zß水🍌


std::wbuffer_convert<Codecvt,Elem,Tr>::~wbuffer_convert

< cpp‎ | locale‎ | wbuffer convert
定义于头文件 <locale>
~wbuffer_convert();

销毁 wbuffer_convert 对象并删除指向转换平面的指针。

注意

一些实现能删除任何平面，包含拥有受保护析构函书的本地环境限定平面。其他实现要求平面拥有公开析构函数，类似来自 <codecvt> 的本地环境独立平面。

示例

#include <locale>
#include <utility>
#include <iostream>
#include <codecvt>

// 包装 wstring/wbuffer_convert 所用的绑定本地环境平面的工具
template<class Facet>
struct deletable_facet : Facet
{
    template<class ...Args>
    deletable_facet(Args&& ...args) : Facet(std::forward<Args>(args)...) {}
    ~deletable_facet() {}
};

int main()
{
    // GB18030 / UCS4 转换，直接使用基于本地环境的平面
    // typedef std::codecvt_byname<char32_t, char, std::mbstate_t> gbfacet_t;
    // 编译错误： "calling a protected destructor of codecvt_byname<> in ~wbuffer_convert"
    // std::wbuffer_convert<gbfacet_t, char32_t> gbto32(std::cout.rdbuf(),
    //                                        new gbfacet_t("zh_CN.gb18030"));

    // GB18030 / UCS4 转换平面使用拥有公开析构函数的平面
    typedef deletable_facet<std::codecvt_byname<char32_t, char, std::mbstate_t>> gbfacet_t;
    std::wbuffer_convert<gbfacet_t, char32_t> gbto32(std::cout.rdbuf(),
                                           new gbfacet_t("zh_CN.gb18030"));
} // 析构函数调用于此

参阅

(析构函数)
 析构 wstring_convert 及其转换平面
(std::wstring_convert<Codecvt,Elem,Wide_alloc,Byte_alloc> 的公开成员函数)


std::wstring_convert

< cpp‎ | locale
定义于头文件 <locale>
template< class Codecvt,

class Elem = wchar_t,
class Wide_alloc = std::allocator <Elem>,
class Byte_alloc = std::allocator <char> >

class wstring_convert;
 (C++11 起)
(C++17 中弃用)

类模板 std::wstring_convert 用单独的编码转换平面 Codecvt ，进行字节字符串 std::string 和宽字符串 std::basic_string <Elem> 间的转换。 std::wstring_convert 假定拥有转换平面的所有权，而不能使用 locale 所管理的平面。适用于 std::wstring_convert 的标准平面对于 UTF-8/UCS2 和 UTF-8/UCS4 转换是 std::codecvt_utf8 ，而对于 UTF-8/UTF-16 转换是 std::codecvt_utf8_utf16 。

成员类型

成员类型 | 定义
byte_string | std::basic_string<char, char_traits<char>, Byte_alloc>
wide_string | std::basic_string<Elem, char_traits<Elem>, Wide_alloc>
state_type | Codecvt::state_type
int_type | wide_string::traits_type::int_type

成员函数

(构造函数) | 构造新的 wstring_convert (公开成员函数)
operator= | 复制赋值运算符被删除 (公开成员函数)
(析构函数) | 析构 wstring_convert 及其转换平面 (公开成员函数)
from_bytes | 转换字节字符串为宽字符串 (公开成员函数)
to_bytes | 转换宽字符串为字符串 (公开成员函数)
converted | 返回成功转换的字符数 (公开成员函数)
state | 返回当前转换状态 (公开成员函数)

参阅

字符转换 | 本地环境定义多字节 (UTF-8, GB18030) | UTF-8 | UTF-16
UTF-16 | mbrtoc16 / c16rtomb (有 C11 的 DR488) | codecvt<char16_t, char, mbstate_t> codecvt_utf8_utf16<char16_t> codecvt_utf8_utf16<char32_t> codecvt_utf8_utf16<wchar_t> | N/A
UCS2 | c16rtomb (无 C11 的 DR488) | codecvt_utf8<char16_t> codecvt_utf8<wchar_t>(Windows) | codecvt_utf16<char16_t> codecvt_utf16<wchar_t>(Windows)
UTF-32 | mbrtoc32 / c32rtomb | codecvt<char32_t, char, mbstate_t> codecvt_utf8<char32_t> codecvt_utf8<wchar_t>(非 Windows) | codecvt_utf16<char32_t> codecvt_utf16<wchar_t>(非 Windows)
系统宽 UTF-32(非 Windows) UCS2(Windows) | mbsrtowcs / wcsrtombs use_facet<codecvt <wchar_t, char, mbstate_t>>(locale) | 无 | 无
wbuffer_convert (C++11)(C++17 中弃用) | 进行字节流缓冲区和宽流缓冲区间的转换 (类模板)
codecvt_utf8 (C++11)(C++17 中弃用) | 在 UTF-8 与 UCS2/UCS4 间转换 (类模板)
codecvt_utf8_utf16 (C++11)(C++17 中弃用) | 在 UTF-8 与 UTF-16 间转换 (类模板)


std::wstring_convert<Codecvt,Elem,Wide_alloc,Byte_alloc>::converted

< cpp‎ | locale‎ | wstring convert
定义于头文件 <locale>
std::size_t converted() const noexcept;

返回最近的 from_bytes() 或 to_bytes() 所处理的源字符数。

返回值

最近的转换操作所消耗的字符数。

示例

#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
int main()
{
    std::string utf8 =  u8"z\u00df\u6c34\U0001d10b"; // 或 u8"zß水𝄋"
                        // 或 "\x7a\xc3\x9f\xe6\xb0\xb4\xf0\x9d\x84\x8b";
    std::cout << "original UTF-8 string size: " << utf8.size() << '\n';

    // UTF-8 - UTF-32 标准转换平面
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> cvt;

    // UTF-8 到 UTF-32
    std::u32string utf32 = cvt.from_bytes(utf8);
    std::cout << "UTF-32 string size: " << utf32.size() << '\n';
    std::cout << "converted() == " << cvt.converted() << '\n';
    // UTF-32 到 UTF-8
    utf8 = cvt.to_bytes(utf32);
    std::cout << "new UTF-8 string size: " << utf8.size() << '\n';
    std::cout << "converted() == " << cvt.converted() << '\n';
}

输出：

original UTF-8 string size: 10
UTF-32 string size: 4
converted() == 10
new UTF-8 string size: 10
converted() == 4

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2174 | C++11 | 未要求 wstring_convert::converted 为 noexcept | 已要求

参阅

to_bytes | 转换宽字符串为字符串 (公开成员函数)
from_bytes | 转换字节字符串为宽字符串 (公开成员函数)


std::wstring_convert<Codecvt,Elem,Wide_alloc,Byte_alloc>::from_bytes

< cpp‎ | locale‎ | wstring convert
定义于头文件 <locale> |
wide_string from_bytes( char byte ); | (1)
wide_string from_bytes( const char* ptr ); | (2)
wide_string from_bytes( const byte_string& str ); | (3)
wide_string from_bytes( const char* first, const char* last); | (4)

用构造中时提供的 codecvt 平面，进行多字节到宽转换。

1) 转换 byte 为 wide_string ，如同它是长为 1 的字符串。

2) 转换始于 ptr 所指向字符的空终止多字节字符序列为 wide_string 。

3) 转换窄字符串 str 为 wide_string 。

4) 转换窄多字节字符序列 [first, last) 为 wide_string 。

所有情况下，转换以初始迁移状态起始，除非提供了非初始起始状态给此 wstring_convert 的构造函数。记忆转换的字符数和转换状态的终值，并且能以 state() 和 converted() 访问它们。

返回值

含有多字节到宽转换结果的 wide_string 对象。若转换失败，且有用户提供的宽错误字符串提供给此 wstring_convert 的构造函数，则返回该宽错误字符串。

异常

若此 wstring_convert 不以用户提供的宽错误字符串构造，则在转换失败时抛出 std::range_error 。

示例

#include <iostream>
#include <string>
#include <locale>
#include <codecvt>

int main()
{
    std::string utf8 =  u8"z\u00df\u6c34\U0001d10b"; // 或 u8"zß水𝄋"
                        // 或 "\x7a\xc3\x9f\xe6\xb0\xb4\xf0\x9d\x84\x8b";

    // UTF-8 / UTF-16 标准转换平面
    std::u16string utf16 = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(utf8.data());
    std::cout << "UTF16 conversion produced " << utf16.size() << " code units:\n";
    for (char16_t c : utf16)
        std::cout << std::hex << std::showbase << c << '\n';

    // UTF-8 / UTF-32 标准转换平面
    std::u32string utf32 = std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t>{}.from_bytes(utf8);
    std::cout << "UTF32 conversion produced " << std::dec << utf32.size() << " code units:\n";
    for (char32_t c : utf32)
        std::cout << std::hex << std::showbase << c << '\n';
}

输出：

UTF16 conversion produced 5 code units:
0x7a
0xdf
0x6c34
0xd834
0xdd0b
UTF32 conversion produced 4 code units:
0x7a
0xdf
0x6c34
0x1d10b

参阅

to_bytes | 转换宽字符串为字符串 (公开成员函数)
mbsrtowcs | 给定状态，转换窄多字节字符串到宽字符串 (函数)
do_in [虚] | 从 externT 转换字符串为 internT ，如在从文件读取时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


std::wstring_convert<Codecvt,Elem,Wide_alloc,Byte_alloc>::state

< cpp‎ | locale‎ | wstring convert
定义于头文件 <locale>
state_type state() const;

返回存储于此 wstring_convert 对象的转换状态的当前值。转换状态可在构造函数中显式设置，并为所有转换操作所更新。

返回值

当前转换状态。

示例

本节未完成
原因：暂无示例

参阅

to_bytes | 转换宽字符串为字符串 (公开成员函数)
from_bytes | 转换字节字符串为宽字符串 (公开成员函数)
mbsinit | 检查 mbstate_t 对象是否表示初始迁移状态 (函数)


std::wstring_convert<Codecvt,Elem,Wide_alloc,Byte_alloc>::to_bytes

< cpp‎ | locale‎ | wstring convert
定义于头文件 <locale> |
byte_string to_bytes( Elem wchar ); | (1)
byte_string to_bytes( const Elem* wptr ); | (2)
byte_string to_bytes( const wide_string& wstr ); | (3)
byte_string to_bytes( const Elem* first, const Elem* last); | (4)

用构造时提供的 codecvt 平面进行宽到多字节转换。

1) 转换 wchar 为 byte_string ，如同它是长为 1 的字符串。
2) 转换始于 wptr 所指向宽字符的空终止宽字符序列为 byte_string 。
3) 转换宽字符串 str 为 byte_string 。
4) 转换宽字符序列 [first, last) 为 byte_string 。

所有情况下，转换始于初始迁移状态，除非提供给此 wstring_convert 的构造函数非初始起始状态。记忆转换的字符数和转换状态的终止，并且能以 state() 和 converted() 访问它们。

返回值

含有宽到多字节转换结果的 byte_string 对象。若转换失败，且有用户提供的字节错误字符串提供给此 wstring_convert 的构造函数，则返回该字节错误字符串。

异常

若此 wstring_convert 不以用户提供的字节错误字符串构造，则在转换失败时抛出 std::range_error 。

示例

#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
#include <iomanip>

// 输出用的工具函数
void hex_print(const std::string& s)
{
    std::cout << std::hex << std::setfill('0');
    for(unsigned char c : s)
        std::cout << std::setw(2) << static_cast<int>(c) << ' ';
    std::cout << std::dec << '\n';
}

int main()
{
    // 宽字符数据
    std::wstring wstr =  L"z\u00df\u6c34\U0001f34c"; // 或 L"zß水🍌"

    // 宽到 UTF-8
    std::wstring_convert<std::codecvt_utf8<wchar_t>> conv1;
    std::string u8str = conv1.to_bytes(wstr);
    std::cout << "UTF-8 conversion produced " << u8str.size() << " bytes:\n";
    hex_print(u8str);

    // 宽到 UTF-16le
    std::wstring_convert<std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>> conv2;
    std::string u16str = conv2.to_bytes(wstr);
    std::cout << "UTF-16le conversion produced " << u16str.size() << " bytes:\n";
    hex_print(u16str);
}

输出：

UTF-8 conversion produced 10 bytes:
7a c3 9f e6 b0 b4 f0 9f 8d 8c
UTF-16le conversion produced 10 bytes:
7a 00 df 00 34 6c 3c d8 4c df

参阅

from_bytes | 转换字节字符串为宽字符串 (公开成员函数)
wcsrtombs | 给定状态，转换宽字符串为窄多字节字符串 (函数)
do_out [虚] | 从 internT 转换字符串为 externT 转换字符串，如在写入文件时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


std::wstring_convert<Codecvt,Elem,Wide_alloc,Byte_alloc>::wstring_convert

< cpp‎ | locale‎ | wstring convert
wstring_convert() : wstring_convert( new Codecvt ) { } | (1) |
explicit wstring_convert( Codecvt* pcvt ); | (2) |
wstring_convert( Codecvt* pcvt, state_type state); | (3) |
explicit wstring_convert( const byte_string& byte_err, const wide_string& wide_err = wide_string() ); | (4) |
wstring_convert(const std::wstring_convert &) = delete; | (5) | (C++14 起)
1) 默认构造函数。
2) 以指定的转换平面，用初始迁移状态和错误字符串的默认构造值构造 wstring_convert 对象。
3) 以指定的转换平面和指定的初始迁移状态，用默认构造的错误字符串值构造 wstring_convert 对象。
4) 以指定的错误字符串，以 new Codecvt 为转换平面并以 state_type 的默认构造值为初始状态构造 wstring_convert 对象。
5) 复制构造函数被删除， wstring_convert 非可复制构造 (CopyConstructible) 。

参数

pcvt | - | 指向 Codecvt 类型转换平面的指针（若此指针为空则行为未定义）
state | - | 转换迁移状态的初始值
byte_err | - | 错误时显示的窄字符串
wide_err | - | 错误时显示的宽字符串

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式

示例

#include <locale>
#include <utility>
#include <codecvt>

// 为 wstring/wbuffer convert 适配绑定本地环境的平面的工具包装器
template<class Facet>
struct deletable_facet : Facet
{
    using Facet::Facet; // 继承构造函数
    ~deletable_facet() {}
};

int main()
{
    // UTF-16le / UCS4 转换
    std::wstring_convert<
         std::codecvt_utf16<char32_t, 0x10ffff, std::little_endian>
    > u16to32;

    // UTF-8 / 宽字符串转换，带定制消息
    std::wstring_convert<std::codecvt_utf8<wchar_t>> u8towide("Error!", L"Error!");

    // GB18030 / 宽字符串转换平面
    typedef deletable_facet<std::codecvt_byname<wchar_t, char, std::mbstate_t>> F;
    std::wstring_convert<F> gbtowide(new F("zh_CN.gb18030"));
}


std::wstring_convert<Codecvt,Elem,Wide_alloc,Byte_alloc>:: ~wstring_convert

< cpp‎ | locale‎ | wstring convert
~wstring_convert();

销毁 wstring_convert 对象并删除指向转换平面的指针。

注意

一些实现能删除任何平面，包含拥有受保护析构函数的本地环境限定平面。其他实现要求平面拥有公开析构函数，类似来自 <codecvt> 的本地环境独立平面。此为 LWG 问题 721 。

示例

#include <locale>
#include <utility>
#include <codecvt>

// 包装 wstring/wbuffer_convert 所用的绑定本地环境平面的工具
template<class Facet>
struct deletable_facet : Facet
{
    template<class ...Args>
    deletable_facet(Args&& ...args) : Facet(std::forward<Args>(args)...) {}
    ~deletable_facet() {}
};

int main()
{
    // GB18030 / UCS4 转换，直接使用基于本地环境的平面
    // typedef std::codecvt_byname<char32_t, char, std::mbstate_t> gbfacet_t;
    // 编译错误： "calling a protected destructor of codecvt_byname<> in ~wstring_convert"
    // std::wstring_convert<gbfacet_t> gbto32(new gbfacet_t("zh_CN.gb18030"));

    // GB18030 / UCS4 转换平面使用拥有公开析构函数的平面
    typedef deletable_facet<std::codecvt_byname<char32_t, char, std::mbstate_t>> gbfacet_t;
    std::wstring_convert<gbfacet_t> gbto32(new gbfacet_t("zh_CN.gb18030"));
} // 析构函数调用于此


动态内存管理

< cpp

智能指针

智能指针使得自动、异常安全的对象生存期管理可行。

定义于头文件 <memory>
指针类别
unique_ptr
(C++11)
 拥有独有对象所有权语义的智能指针
(类模板)
shared_ptr
(C++11)
 拥有共享对象所有权语义的智能指针
(类模板)
weak_ptr
(C++11)
 到 std::shared_ptr 所管理对象的弱引用
(类模板)
auto_ptr
(C++17 中移除)
 拥有严格对象所有权语义的智能指针
(类模板)
辅助类
owner_less
(C++11)
 提供基于所有者的，共享指针和弱指针的混合类型的排序
(类模板)
enable_shared_from_this
(C++11)
 允许对象创建指代自身的 shared_ptr
(类模板)
bad_weak_ptr
(C++11)
 访问指向已销毁对象的 weak_ptr 时抛出的异常
(类)
default_delete
(C++11)
 unique_ptr 的默认删除器
(类模板)
智能指针适配器
out_ptr_t
(C++23)
 与外来指针设置器交互，并在析构时重设智能指针
(类模板)
out_ptr
(C++23)
 以关联的智能指针和重设参数创建 out_ptr_t
(函数模板)
inout_ptr_t
(C++23)
 与外来指针设置器交互，从智能指针获得初始指针值，并在析构时重设它
(类模板)
inout_ptr
(C++23)
 以关联的智能指针和重设参数创建 inout_ptr_t
(函数模板)

分配器

分配器是封装内存分配策略的类模板。这允许泛型容器从数据自身将内存管理解耦合。

定义于头文件 <memory>
allocator | 默认的分配器 (类模板)
allocator_traits (C++11) | 提供关于分配器类型的信息 (类模板)
allocation_result (C++23) | 记录由 allocate_at_least 分配的存储的地址与实际大小 (类模板)
allocate_at_least (C++23) | 经由分配器分配至少与请求的大小一样大的存储 (函数模板)
allocator_arg_t (C++11) | 标签类型，用于选择具分配器的构造函数重载 (类)
allocator_arg (C++11) | 用于选择具分配器的构造函数的 std::allocator_arg_t 对象 (常量)
uses_allocator (C++11) | 检查指定的类型是否支持使用分配器的构造 (类模板)
uses_allocator_construction_args (C++20) | 准备匹配给定类型所要求的使用分配器构造的口味的参数列表 (函数模板)
make_obj_using_allocator (C++20) | 以使用分配器构造的手段创建给类型的对象 (函数模板)
uninitialized_construct_using_allocator (C++20) | 以使用分配器构造的手段在指定的内存位置创建给定类型的对象 (函数模板)
定义于头文件 <scoped_allocator>
scoped_allocator_adaptor (C++11) | 为多级容器实现的多级分配器 (类模板)
定义于头文件 <memory_resource>
定义于命名空间 std::pmr
polymorphic_allocator (C++17) | 以 std::memory_resource 构造，支持基于它的运行时多态的分配器 (类模板)

内存资源

内存资源实现可为 std::pmr::polymorphic_allocator 所用的内存分配策略

定义于头文件 <memory_resource>
定义于命名空间 std::pmr
memory_resource (C++17) | 一个抽象接口，用于各种封装内存资源的类 (类)
new_delete_resource (C++17) | 返回一个静态的程序范围 std::pmr::memory_resource，它使用全局 operator new 与 operator delete 分配和解分配内存 (函数)
null_memory_resource (C++17) | 返回一个不进行任何分配的静态 std::pmr::memory_resource (函数)
get_default_resource (C++17) | 获取缺省 std::pmr::memory_resource (函数)
set_default_resource (C++17) | 设置缺省 std::pmr::memory_resource (函数)
pool_options (C++17) | 一组池资源的构造函数选项 (类)
synchronized_pool_resource (C++17) | 线程安全的 std::pmr::memory_resource，用于管理具有不同块大小的池中的分配 (类)
unsynchronized_pool_resource (C++17) | 线程不安全的 std::pmr::memory_resource，用于管理具有不同块大小的池中的分配 (类)
monotonic_buffer_resource (C++17) | 一种特殊用途的 std::pmr::memory_resource，仅在资源被销毁时才释放所分配内存 (类)

未初始化存储

提供数个工具以创建并访问未初始化存储。

定义于头文件 <memory>
raw_storage_iterator (C++17 中弃用)(C++20 中移除) | 允许标准算法存储结果于未初始化内存的迭代器 (类模板)
get_temporary_buffer (C++17 中弃用)(C++20 中移除) | 获得未初始化存储 (函数模板)
return_temporary_buffer (C++17 中弃用)(C++20 中移除) | 释放未初始化存储 (函数模板)

未初始化内存算法

定义于头文件 <memory>
uninitialized_copy | 将范围内的对象复制到未初始化的内存区域 (函数模板)
uninitialized_copy_n (C++11) | 将指定数量的对象复制到未初始化的内存区域 (函数模板)
uninitialized_fill | 复制一个对象到以范围定义的未初始化内存区域 (函数模板)
uninitialized_fill_n | 复制一个对象到以起点和计数定义的未初始化内存区域 (函数模板)
uninitialized_move (C++17) | 移动一个范围的对象到未初始化的内存区域 (函数模板)
uninitialized_move_n (C++17) | 移动一定数量对象到未初始化内存区域 (函数模板)
uninitialized_default_construct (C++17) | 在范围所定义的未初始化的内存区域以默认初始化构造对象 (函数模板)
uninitialized_default_construct_n (C++17) | 在起始和计数所定义的未初始化内存区域用默认初始化构造对象 (函数模板)
uninitialized_value_construct (C++17) | 在范围所定义的未初始化内存中用值初始化构造对象 (函数模板)
uninitialized_value_construct_n (C++17) | 在起始和计数所定义的未初始化内存区域以值初始化构造对象 (函数模板)
destroy_at (C++17) | 销毁在给定地址的对象 (函数模板)
destroy (C++17) | 销毁一个范围中的对象 (函数模板)
destroy_n (C++17) | 销毁范围中一定数量的对象 (函数模板)
construct_at (C++20) | 在给定地址创建对象 (函数模板)

受约束的未初始化内存算法 (C++20)

C++20 提供受约束的未初始化内存算法，它们接受范围参数或迭代器-哨位对。

定义于头文件 <memory>
定义于命名空间 std::ranges
no-throw-input-iteratorno-throw-forward-iteratorno-throw-sentinel-forno-throw-input-rangeno-throw-forward-range (C++20) | 指定迭代器、哨位和范围上的某些操作不抛出 (仅用于阐释的概念)
ranges::uninitialized_copy (C++20) | 复制元素范围到未初始化的内存区域 (niebloid)
ranges::uninitialized_copy_n (C++20) | 复制一定量元素到未初始化的内存区域 (niebloid)
ranges::uninitialized_fill (C++20) | 复制一个对象到范围所定义的未初始化的内存区域 (niebloid)
ranges::uninitialized_fill_n (C++20) | 复制一个对象到起始与计数所定义的未初始化的内存区域 (niebloid)
ranges::uninitialized_move (C++20) | 移动对象范围到未初始化的内存区域 (niebloid)
ranges::uninitialized_move_n (C++20) | 移动一定量对象到未初始化的内存区域 (niebloid)
ranges::uninitialized_default_construct (C++20) | 在范围所定义的未初始化的内存区域以默认初始化构造对象 (niebloid)
ranges::uninitialized_default_construct_n (C++20) | 在起始与计数所定义的未初始化的内存区域以默认初始化构造对象 (niebloid)
ranges::uninitialized_value_construct (C++20) | 在范围所定义的未初始化的内存区域以值初始化构造对象 (niebloid)
ranges::uninitialized_value_construct_n (C++20) | 在起始与计数所定义的未初始化的内存区域以值初始化构造对象 (niebloid)
ranges::destroy_at (C++20) | 销毁位于给定地址的元素 (niebloid)
ranges::destroy (C++20) | 销毁范围中的元素 (niebloid)
ranges::destroy_n (C++20) | 销毁范围中一定量的元素 (niebloid)
ranges::construct_at (C++20) | 在给定地址创建对象 (niebloid)

垃圾收集器支持

定义于头文件 <memory>
declare_reachable (C++11)(C++23 中移除) | 声明一个对象不能被回收 (函数)
undeclare_reachable (C++11)(C++23 中移除) | 声明一个对象可以被回收 (函数模板)
declare_no_pointers (C++11)(C++23 中移除) | 声明该内存区域不含可追踪指针 (函数)
undeclare_no_pointers (C++11)(C++23 中移除) | 取消 std::declare_no_pointers 的效果 (函数)
pointer_safety (C++11)(C++23 中移除) | 列出指针安全模式 (枚举)
get_pointer_safety (C++11)(C++23 中移除) | 返回当前的指针安全模式 (函数)

杂项

定义于头文件 <memory>
pointer_traits (C++11) | 提供关于指针式类型的信息 (类模板)
to_address (C++20) | 从指针式类型获得裸指针 (函数模板)
addressof (C++11) | 获得对象的实际地址，即使其重载了 & 运算符 (函数模板)
align (C++11) | 对齐缓冲区中的指针 (函数)
assume_aligned (C++20) | 告知编译器指针已对齐 (函数模板)

C 风格内存管理

包含如 std::malloc 、 std::free

低层内存管理

包含如 operator new 、 operator delete 、 std::set_new_handler


std::addressof

< cpp‎ | memory
定义于头文件 <memory> |  |
 | (1) |
template< class T > T* addressof(T& arg) noexcept; |  |  | (C++11 起) (C++17 前)
template< class T > constexpr T* addressof(T& arg) noexcept; |  |  | (C++17 起)
template <class T> const T* addressof(const T&&) = delete; | (2) | (C++17 起)
1) 获得对象或函数 arg 的实际地址，即使存在 operator& 的重载
2) 右值重载被删除，以避免取 const 右值的地址。

表达式 std::addressof(E) 是一个常量表达式，若 E 是左值常量子表达式。

 (C++17 起)

参数

arg - 左值对象或函数

返回值

指向 arg 的指针。

可能的实现

template<class T>
typename std::enable_if<std::is_object<T>::value, T*>::type  addressof(T& arg) noexcept
{
    return reinterpret_cast<T*>(
               &const_cast<char&>(
                   reinterpret_cast<const volatile char&>(arg)));
}

template<class T>
typename std::enable_if<!std::is_object<T>::value, T*>::type addressof(T& arg) noexcept
{
    return &arg;
}

注：上述实现不是 constexpr （这要求编译器支持）。

示例

operator& 可以为指针封装器类重载，以获得指向指针的指针：

#include <iostream>
#include <memory>

template<class T>
struct Ptr {
    T* pad; // 增加填充以显示‘ this ’和‘ data ’的区别
    T* data;
    Ptr(T* arg) : pad(nullptr), data(arg)
    {
        std::cout << "Ctor this = " << this << std::endl;
    }

    ~Ptr() { delete data; }
    T** operator&() { return &data; }
};

template<class T>
void f(Ptr<T>* p)
{
    std::cout << "Ptr   overload called with p = " << p << '\n';
}

void f(int** p)
{
    std::cout << "int** overload called with p = " << p << '\n';
}

int main()
{
    Ptr<int> p(new int(42));
    f(&p);                 // 调用 int** 重载
    f(std::addressof(p));  // 调用 Ptr<int>* 重载，（ = this ）
}

可能的输出：

Ctor this = 0x7fff59ae6e88
int** overload called with p = 0x7fff59ae6e90
Ptr   overload called with p = 0x7fff59ae6e88

参阅

allocator | 默认的分配器 (类模板)
pointer_to [静态] | 获得指向其参数的可解引用指针 (std::pointer_traits<Ptr> 的公开静态成员函数)


std::align

< cpp‎ | memory
定义于头文件 <memory>
void* align( std::size_t alignment,

std::size_t size,
void*& ptr,

std::size_t & space );
 (C++11 起)

给定指针 ptr 指定大小为 space 的缓冲区，返回按指定 alignment 为 size 字节数对齐的指针，并减小 space 参数对齐所用的字节数。返回首个对齐的地址。

仅以给定对齐量对齐入缓冲区的所需字节数合适，函数才会修改指针。若缓冲区太小，则函数不做任何事并返回 nullptr 。

若 alignment 不是二的幂，则行为未定义。

参数

alignment | - | 欲求的对齐量
size | - | 要被对齐的存储的大小
ptr | - | 指向至少有 space 字节的连续存储的指针
space | - | 要在其中操作的缓冲区的大小

返回值

ptr 的调整值，或若提供空间太小则为空指针值。

示例

演示使用 std::align 在内存中放置不同类型的对象

#include <iostream>
#include <memory>

template <std::size_t N>
struct MyAllocator
{
    char data[N];
    void* p;
    std::size_t sz;
    MyAllocator() : p(data), sz(N) {}
    template <typename T>
    T* aligned_alloc(std::size_t a = alignof(T))
    {
        if (std::align(a, sizeof(T), p, sz))
        {
            T* result = reinterpret_cast<T*>(p);
            p = (char*)p + sizeof(T);
            sz -= sizeof(T);
            return result;
        }
        return nullptr;
    }
};

int main()
{
    MyAllocator<64> a;

    // 分配一个 char
    char* p1 = a.aligned_alloc<char>();
    if (p1)
        *p1 = 'a';
    std::cout << "allocated a char at " << (void*)p1 << '\n';

    // 分配一个 int
    int* p2 = a.aligned_alloc<int>();
    if (p2)
        *p2 = 1;
    std::cout << "allocated an int at " << (void*)p2 << '\n';

    // 分配一个 int ，对齐于 32 字节边界
    int* p3 = a.aligned_alloc<int>(32);
    if (p3)
        *p3 = 2;
    std::cout << "allocated an int at " << (void*)p3 << " (32 byte alignment)\n";
}

可能的输出：

allocated a char at 0x2ff21a08
allocated an int at 0x2ff21a0c
allocated an int at 0x2ff21a20 (32 byte alignment)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2377 | C++11 | 要求 alignment 为基础或受支持的扩展对齐值 | 仅需要为二的幂

参阅

alignof 运算符 (C++11) | 查询类型的对齐要求
alignas 说明符 (C++11) | 指定该变量的存储应该按指定量对齐
aligned_storage (C++11) | 定义适于用作给定大小的类型的未初始化存储的类型 (类模板)


std::allocate_at_least

< cpp‎ | memory
定义于头文件 <memory>
template< class Alloc >

[[nodiscard]] constexpr std::allocation_result<
typename std::allocator_traits <Alloc>::pointer>

allocate_at_least( Alloc& a, std::size_t n );
 (C++23 起)

std::allocate_at_least 调用 a.allocate_at_least(n) 并返回其结果，若该调用为良构，否则它等价于 return {a.allocate(n), n}; 。

对于分配器 (Allocator) a ， std::allocator_at_least 尝试分配至少 n 个 Alloc::value_type 对象的存储，并提供准确 n 个对象的存储的后备机制（类似 std::allocator_traits 所提供者）。

参数

a | - | 用于分配存储的分配器
n | - | 要分配存储的对象数的下界

返回值

a.allocate_at_least(n) 若它为良构，否则为 {a.allocate(n), n} 。

异常

在选择的分配函数抛出时抛出其所抛的异常。

注解

分配器 (Allocator) 类型的 allocate_at_least 成员函数主要为连续容器，例如 std::vector 与 std::basic_string 提供，以通过使得其容量在可能时匹配实际分配的大小减少重分配。由于 std::allocate_at_least 提供后备机制，故能在适合处直接使用它。

给定 Alloc 类型的分配器对象 a ，令 result 代表从 std::allocate_at_least(a, n) 返回的值，应该由 a.deallocate(result.ptr, m) （常经由 std::allocator_traits <Alloc>::deallocate(a, result.ptr, m) 调用）解分配存储以避免内存泄漏。

用于解分配的参数 m 必须不小于 n 且不大于 result.count ，否则行为未定义。注意若分配器不支持 allocate_at_least 则 n 始终等于 result.count ，这表示要求 m 等于 n 。

示例

本节未完成
原因：暂无示例

参阅

allocate_at_least (C++23) | 分配与请求的大小至少一样大的未初始化存储 (std::allocator<T> 的公开成员函数)
allocator_traits (C++11) | 提供关于分配器类型的信息 (类模板)


std::allocation_result

< cpp‎ | memory
定义于头文件 <memory>
template< class Pointer >

struct allocation_result {
Pointer ptr;
std::size_t count;

};
 (C++23 起)

allocation_result 特化是适合的分配器 (Allocator) 类型的 allocate_at_least 成员函数（例如 std::allocator::allocate_at_least ）及 std::allocate_at_least 的返回类型。

allocation_result 的每个特化均无基类或 ptr 与 count 之外的声明成员，从而它适合聚合初始化及结构化绑定。

模板形参

Pointer - 常为 std::allocator_traits <Alloc>::pointer ，其中 Alloc 为分配器 (Allocator) 类型

成员对象

ptr (C++23) | 常用于 allocate_at_least 所分配的存储中首元素的地址 (公开成员对象)
count (C++23) | 常用于 allocate_at_least 所分配的存储中的实际元素数 (公开成员对象)

示例

本节未完成
原因：暂无示例

参阅

allocate_at_least (C++23) | 分配与请求的大小至少一样大的未初始化存储 (std::allocator<T> 的公开成员函数)
allocate_at_least (C++23) | 经由分配器分配至少与请求的大小一样大的存储 (函数模板)


std::allocator

< cpp‎ | memory
定义于头文件 <memory> |  |
template< class T > struct allocator; | (1) |
template<> struct allocator<void>; | (2) | (C++17 中弃用) (C++20 中移除)

std::allocator 类模板是所有标准库容器所用的默认分配器 (Allocator) ，若不提供用户指定的分配器。默认分配器无状态，即任何给定的 allocator 实例可交换、比较相等，且能解分配同一 allocator 类型的任何其他实例所分配的内存。

对 void 的显式特化缺少成员 typedef reference 、 const_reference 、 size_type 和 difference_type 。此特化不声明成员函数。

 (C++20 前)

默认分配器满足分配器完整性要求。

 (C++17 起)

成员类型

类型 | 定义
value_type | T
pointer (C++17 中弃用)(C++20 中移除) | T*
const_pointer (C++17 中弃用)(C++20 中移除) | const T*
reference (C++17 中弃用)(C++20 中移除) | T&
const_reference (C++17 中弃用)(C++20 中移除) | const T&
size_type | std::size_t
difference_type | std::ptrdiff_t
propagate_on_container_move_assignment(C++14) | std::true_type
rebind (C++17 中弃用)(C++20 中移除) template< class U > struct rebind {

typedef allocator<U> other;
};
is_always_equal(C++17)(C++20 中弃用) | std::true_type

成员函数

(构造函数) | 创建新的 allocator 实例 (公开成员函数)
(析构函数) | 析构 allocator 实例 (公开成员函数)
address (C++17 中弃用)(C++20 中移除) | 获得对象的地址，即使重载了 operator& (公开成员函数)
allocate | 分配未初始化的存储 (公开成员函数)
allocate_at_least (C++23) | 分配与请求的大小至少一样大的未初始化存储 (公开成员函数)
deallocate | 解分配存储 (公开成员函数)
max_size (C++17 中弃用)(C++20 中移除) | 返回最大的受支持分配大小 (公开成员函数)
construct (C++17 中弃用)(C++20 中移除) | 在分配的存储构造对象 (公开成员函数)
destroy (C++17 中弃用)(C++20 中移除) | 析构在已分配存储中的对象 (公开成员函数)

非成员函数

operator==operator!=
(C++20 中移除)
 比较两个分配器实例
(公开成员函数)

注解

成员模板 rebind 提供获得不同类型的分配器的方式。例如，std::list<T, A> 用分配器A::rebind<Node<T>>::other (C++11 前)std::allocator_traits <A>::rebind_alloc<Node<T>> ，若 A 为 std::allocator 则实现自 A::rebind<Node<T>>::other (C++11 起) 分配某个某个内部类型 Node<T> 结点。

成员类型 is_always_equal 由 LWG 问题 3170 弃用，因为它使得派生自 std::allocator 的定制分配器默认被当作始终相等。 std::allocator_traits <std::allocator<T>>::is_always_equal 未被弃用，而其成员常量 value 对任何 T 均为 true 。

示例

#include <memory>
#include <iostream>
#include <string>

int main()
{
    {
        // int 的默认分配器
        std::allocator<int> alloc;

        // 演示少见的直接使用成员
        static_assert(std::is_same_v<int, decltype(alloc)::value_type>);
        int* p = alloc.allocate(1);  // 一个 int 的空间
        alloc.deallocate(p, 1);      // 而它没了

        // 即使可以通过特征使用这些，从而无直接使用的必要
        using traits_t = std::allocator_traits<decltype(alloc)>; // 匹配的特征
        p = traits_t::allocate(alloc, 1);
        traits_t::construct(alloc, p, 7);       // 构造 int
        std::cout << *p << '\n';
        traits_t::deallocate(alloc, p, 1);      // 解分配 int 的空间
    }

    {
        // string 的默认分配器
        std::allocator<std::string> alloc;
        // 匹配的特征
        using traits_t = std::allocator_traits<decltype(alloc)>;

        // 用 string 的特征重绑定产生同一类型
        traits_t::rebind_alloc<std::string> alloc_ = alloc;

        std::string* p = traits_t::allocate(alloc, 2); // 2 个 string 的空间

        traits_t::construct(alloc, p, "foo");
        traits_t::construct(alloc, p + 1, "bar");

        std::cout << p[0] << ' ' << p[1] << '\n';

        traits_t::destroy(alloc, p + 1);
        traits_t::destroy(alloc, p);
        traits_t::deallocate(alloc, p, 2);
    }
}

输出：

7
foo bar

参阅

allocator_traits (C++11) | 提供关于分配器类型的信息 (类模板)
scoped_allocator_adaptor (C++11) | 为多级容器实现的多级分配器 (类模板)
uses_allocator (C++11) | 检查指定的类型是否支持使用分配器的构造 (类模板)


std::allocator<T>::address

< cpp‎ | memory‎ | allocator
pointer address( reference x ) const; | (C++11 前)
pointer address( reference x ) const noexcept; | (C++11 起) (C++17 中弃用) (C++20 中移除)
const_pointer address( const_reference x ) const; | (C++11 前)
const_pointer address( const_reference x ) const noexcept; | (C++11 起) (C++17 中弃用) (C++20 中移除)

返回 x 的实际地址，即使存在重载的 operator& 。

参数

x - 要获取地址的对象

返回值

x 的实际地址。


std::allocator<T>::allocate

< cpp‎ | memory‎ | allocator
 | (1)
pointer allocate( size_type n, const void * hint = 0 ); |  | (C++17 前)
T* allocate( std::size_t n, const void * hint); |  | (C++17 起) (弃用) (C++20 中移除)
 | (2)
T* allocate( std::size_t n ); |  | (C++17 起) (C++20 前)
[[nodiscard]] constexpr T* allocate( std::size_t n ); |  | (C++20 起)

调用 :: operator new ( std::size_t ) 或 :: operator new ( std::size_t, std::align_val_t ) (C++17 起)分配 n * sizeof(T) 字节的未初始化存储，但何时及如何调用此函数是未指定的。指针 hint 可用于提供引用的局部性：若实现支持，则 allocator 会试图分配尽可能接近 hint 的新内存块。

然后，此函数在该存储中创建一个 T[n] 数组并开始其生存期，但不开始其任何元素的生存期。

若 T 为不完整类型则此函数的使用为非良构。

为了在常量表达式中使用此函数，必须在同一表达式的求值内解分配其所分配的存储。

 (C++20 起)

参数

n | - | 要分配存储的对象数
hint | - | 指向临近内存位置的指针

返回值

指向 T 类型的 n 个对象的数组首元素的指针，数组元素尚未构造。

异常

若 std::numeric_limits < std::size_t >::max() / sizeof(T) < n 则抛出 std::bad_array_new_length 。

 (C++11 起)

若分配失败则抛出 std::bad_alloc 。

注解

遣词“未指定何时及如何”令标准库容器可以组合或优化掉堆分配，即使对直接调用 ::operator new 禁止这种优化。例如 libc++ 实现了它（ [1] 与 [2] ）

在调用 allocate 后、构造元素前， T* 的指针算术在分配的数组内是良定义的，但若访问元素则行为未定义。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3190 | C++11 | allocate 可能分配大小错误的存储 | 替而抛出 bad_array_new_length

参阅

allocate
[静态]
 用分配器分配未初始化的存储
(std::allocator_traits<Alloc> 的公开静态成员函数)


std::allocator<T>::allocate_at_least

< cpp‎ | memory‎ | allocator
[[nodiscard]] constexpr std::allocation_result<T*>
allocate_at_least( std::size_t n );
 (C++23 起)

调用 :: operator new （可能提供额外的 std::align_val_t 参数）分配 count * sizeof(T) 字节的未初始化存储，其中 count 是未指定的不小于 n 的整数值，但未指定何时及如何调用此函数。

然后，此函数在该存储中创建一个 T[count] 数组并开始其生存期，但不开始其任何元素的生存期。

为在常量表达式中使用此函数，必须在同一表达式的求值内解分配其所分配的存储。

若 T 为不完整类型则此函数的使用为非良构。

参数

n - 要分配存储的对象数的下界

返回值

std::allocation_result<T*>{p, count} ，其中 p 指向 T 类型的 n 个对象的数组首元素的指针，数组元素尚未构造。

异常

若 std::numeric_limits < std::size_t >::max() / sizeof(T) < n 则抛出 std::bad_array_new_length ，或若分配失败则抛出 std::bad_alloc 。

注解

allocate_at_least 主要为连续容器，例如 std::vector 与 std::basic_string 提供，以通过使得其容量在可能时匹配实际分配的大小减少重分配。

遣词“未指定何时及如何”令标准库容器可以组合或优化掉堆分配，即使对直接调用 ::operator new 禁止这种优化。例如 libc++ 实现了它（ [1] 与 [2] ）

在调用 allocate_at_least 后、构造元素前， T* 的指针算术在分配的数组内是良定义的，但若访问元素则行为未定义。

参阅

allocate_at_least
(C++23)
 经由分配器分配至少与请求的大小一样大的存储
(函数模板)


std::allocator<T>::allocator

< cpp‎ | memory‎ | allocator
 | (1)
allocator() throw(); |  | (C++11 前)
allocator() noexcept; |  | (C++11 起) (C++20 前)
constexpr allocator() noexcept; |  | (C++20 起)
 | (2)
allocator( const allocator& other ) throw(); |  | (C++11 前)
allocator( const allocator& other ) noexcept; |  | (C++11 起) (C++20 前)
constexpr allocator( const allocator& other ) noexcept; |  | (C++20 起)
 | (3)
template< class U > allocator( const allocator<U>& other ) throw(); |  | (C++11 前)
template< class U > allocator( const allocator<U>& other ) noexcept; |  | (C++11 起) (C++20 前)
template< class U > constexpr allocator( const allocator<U>& other ) noexcept; |  | (C++20 起)

构造默认分配器。因为默认分配器是无状态的，故构造函数无可见效应。

参数

other - 用以构造的另一 allocator


std::allocator<T>::construct

< cpp‎ | memory‎ | allocator
定义于头文件 <memory> |  |
void construct( pointer p, const_reference val ); | (1) | (C++11 前)
template< class U, class... Args > void construct( U* p, Args&&... args ); | (2) | (C++11 起) (C++17 中弃用) (C++20 中移除)

用布置 new ，在 p 所指的未初始化存储中构造 T 类型对象。

1) 调用 new((void *)p) T(val)
2) 调用 ::new((void *)p) U( std::forward <Args>(args)...)

参数

p | - | 指向未初始化存储的指针
val | - | 用作复制构造函数参数的值
args... | - | 所用的构造函数参数

返回值

（无）

参阅

construct [静态] | 在分配的存储构造对象 (函数模板)
operator newoperator new[] | 分配函数 (函数)


std::allocator<T>::deallocate

< cpp‎ | memory‎ | allocator
void deallocate( T* p, std::size_t n ); | (C++20 前)
constexpr void deallocate( T* p, std::size_t n ); | (C++20 起)

从指针 p 所引用的存储解分配，指针必须是通过先前调用 allocate() 或 allocate_at_least() (C++23 起) 获得的指针。

参数 n 必须等于对原先生成 p 的 allocate() 调用的首参数，或若 p 由返回 {p, count} 的调用 allocate_at_least(m) 获得，则在范围 [m, count] 中 (C++23 起)；否则行为未定义。

调用 :: operator delete (void*) 或 :: operator delete (void*, std::align_val_t ) (C++17 起)，但何时及如何调用是未指定的。

在常量表达式的求值中，此函数必须解分配在同一表达式的求值内分配的存储。

 (C++20 起)

参数

p | - | 从 allocate() 或 allocate_at_least() (C++23 起) 获得的指针
n | - | 先前传递给 allocate() 的对象数，或在经由 allocate_at_least() 请求和实际分配的对象数之间的数（可以等于任一边界） (C++23 起)

返回值

（无）

示例

#include <algorithm>
#include <cstddef>
#include <iostream>
#include <memory>
#include <string>

class S {
    inline static int n{1};
    int m{};
    void pre() const { std::cout << "#" << m << std::string(m, ' '); }
public:
    S(int x) : m{n++} { pre(); std::cout << "S::S(" << x << ");\n"; }
    ~S() { pre(); std::cout << "S::~S();\n"; }
    void id() const { pre(); std::cout << "S::id();\n"; }
};

int main() {
    constexpr std::size_t n{4};
    std::allocator<S> allocator;
    try {
        S* s = allocator.allocate(n); // 可能抛出
        for (std::size_t i{}; i != n; ++i) {
        //  allocator.construct(&s[i], i+42); // C++20 中移除
            std::construct_at(&s[i], i+42); // C++20 起
        }
        std::for_each_n(s, n, [](const auto& e) { e.id(); });
        std::destroy_n(s, n);
        allocator.deallocate(s, n);
    }
    catch(std::bad_array_new_length const& ex) { std::cout << ex.what() << '\n'; }
    catch(std::bad_alloc const& ex) { std::cout << ex.what() << '\n'; }
}

输出：

#1 S::S(42);
#2  S::S(43);
#3   S::S(44);
#4    S::S(45);
#1 S::id();
#2  S::id();
#3   S::id();
#4    S::id();
#1 S::~S();
#2  S::~S();
#3   S::~S();
#4    S::~S();

参阅

allocate | 分配未初始化的存储 (公开成员函数)
allocate_at_least (C++23) | 分配与请求的大小至少一样大的未初始化存储 (公开成员函数)
deallocate [静态] | 用分配器解分配存储 (std::allocator_traits<Alloc> 的公开静态成员函数)


std::allocator<T>::destroy

< cpp‎ | memory‎ | allocator
定义于头文件 <memory> |
void destroy( pointer p ); | (C++11 前)
template< class U > void destroy( U* p ); | (C++11 起) (C++17 中弃用) (C++20 中移除)

调用 p 所指的对象的析构函数

1) 调用 ((T*)p)->~T()
2) 调用 p->~U()

参数

p - 指向要被销毁的对象的指针

返回值

（无）

参阅

destroy
[静态]
 析构存储于已分配存储的对象
(函数模板)


std::allocator<T>::max_size

< cpp‎ | memory‎ | allocator
size_type max_size() const throw(); | (C++11 前)
size_type max_size() const noexcept; | (C++11 起) (C++17 中弃用) (C++20 中移除)

返回理论上可行的 n 最大值，对于它 allocate(n, 0) 调用可能成功。

大部分实现中，它返回 std::numeric_limits <size_type>::max() / sizeof(value_type) 。

参数

（无）

返回值

受支持的最大分配大小

参阅

max_size
[静态]
 返回分配器所支持的最大对象大小
(std::allocator_traits<Alloc> 的公开静态成员函数)


operator==,!=(std::allocator)

< cpp‎ | memory‎ | allocator
 | (1)
template< class T1, class T2 > bool operator==( const allocator<T1>& lhs, const allocator<T2>& rhs ) throw(); |  | (C++11 前)
template< class T1, class T2 > bool operator==( const allocator<T1>& lhs, const allocator<T2>& rhs ) noexcept; |  | (C++11 起) (C++20 前)
template< class T1, class T2 > constexpr bool operator==( const allocator<T1>& lhs, const allocator<T2>& rhs ) noexcept; |  | (C++20 起)
 | (2)
template< class T1, class T2 > bool operator!=( const allocator<T1>& lhs, const allocator<T2>& rhs ) throw(); |  | (C++11 前)
template< class T1, class T2 > bool operator!=( const allocator<T1>& lhs, const allocator<T2>& rhs ) noexcept; |  | (C++11 起) (C++20 前)

比较二个默认分配器。因为默认分配器无状态，故二个默认分配器始终相等。

1) 返回 true
2) 返回 false

参数

lhs, rhs - 要比较的默认分配器

返回值

1) true
2) false


std::allocator<T>::~allocator

< cpp‎ | memory‎ | allocator
~allocator(); | (C++20 前)
constexpr ~allocator(); | (C++20 起)

销毁默认分配器。


std::allocator_arg

< cpp‎ | memory
定义于头文件 <memory> |
constexpr std::allocator_arg_t allocator_arg = std::allocator_arg_t (); | (C++11 起) (C++17 前)
inline constexpr std::allocator_arg_t allocator_arg = std::allocator_arg_t (); | (C++17 起)

std::allocator_arg 是 std::allocator_arg_t 类型常量，用于在调用点消歧义具分配器对象，例如 std::tuple 、 std::function 、 std::promise 与 std::packaged_task 的构造函数及成员函数的重载。

参阅

allocator_arg_t (C++11) | 标签类型，用于选择具分配器的构造函数重载 (类)
uses_allocator (C++11) | 检查指定的类型是否支持使用分配器的构造 (类模板)


std::allocator_arg_t

< cpp‎ | memory
定义于头文件 <memory> |
struct allocator_arg_t { explicit allocator_arg_t() = default; }; | (C++11 起)

std::allocator_arg_t 是用于消歧义具分配器对象，包括 std::tuple 、 std::function 、 std::packaged_task (C++17 前)与 std::promise 的构造函数和成员函数的空类类型。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2510 | C++11 | 默认构造函数为非 explicit ，能导致歧义 | 使之为 explicit

参阅

allocator_arg (C++11) | 用于选择具分配器的构造函数的 std::allocator_arg_t 对象 (常量)
uses_allocator (C++11) | 检查指定的类型是否支持使用分配器的构造 (类模板)


std::allocator_traits

< cpp‎ | memory
定义于头文件 <memory> |
template< class Alloc > struct allocator_traits; | (C++11 起)

allocator_traits 类模板提供访问分配器 (Allocator) 各种属性的标准化方式。标准容器和其他标准库组件通过此模板访问分配器，这使得能以任何类类型为分配器，只要用户提供的 allocator_traits 特化实现所有要求的功能。

默认的非特化 allocator_traits 含有下列成员：

成员类型

类型 | 定义
allocator_type | Alloc
value_type | Alloc::value_type
pointer | 若存在则为 Alloc::pointer ，否则为 value_type*
const_pointer | 若存在则为 Alloc::const_pointer ，否则为 std::pointer_traits <pointer>::rebind<const value_type>
void_pointer | 若存在则为 Alloc::void_pointer ，否则为 std::pointer_traits <pointer>::rebind<void>
const_void_pointer | 若存在则为 Alloc::const_void_pointer ，否则为 std::pointer_traits <pointer>::rebind<const void>
difference_type | 若存在则为 Alloc::difference_type ，否则为 std::pointer_traits <pointer>::difference_type
size_type | 若存在则为 Alloc::size_type ，否则为 std::make_unsigned <difference_type>::type
propagate_on_container_copy_assignment | 若存在则为 Alloc::propagate_on_container_copy_assignment ，否则为 std::false_type
propagate_on_container_move_assignment | 若存在则为 Alloc::propagate_on_container_move_assignment ，否则为 std::false_type
propagate_on_container_swap | 若存在则为 Alloc::propagate_on_container_swap ，否则为 std::false_type
is_always_equal(C++17 起) | 若存在则为 Alloc::is_always_equal ，否则为 std::is_empty <Alloc>::type

成员别名模版

类型 | 定义
rebind_alloc<T> | 若存在则为 Alloc::rebind<T>::other ，否则若 Alloc<T, Args> 则为 Alloc<U, Args>
rebind_traits<T> | std::allocator_traits<rebind_alloc<T>>

成员函数

allocate [静态] | 用分配器分配未初始化的存储 (公开静态成员函数)
deallocate [静态] | 用分配器解分配存储 (公开静态成员函数)
construct [静态] | 在分配的存储构造对象 (函数模板)
destroy [静态] | 析构存储于已分配存储的对象 (函数模板)
max_size [静态] | 返回分配器所支持的最大对象大小 (公开静态成员函数)
select_on_container_copy_construction [静态] | 获得复制标准容器后使用的分配器 (公开静态成员函数)

参阅

allocator | 默认的分配器 (类模板)
scoped_allocator_adaptor (C++11) | 为多级容器实现的多级分配器 (类模板)
pointer_traits (C++11) | 提供关于指针式类型的信息 (类模板)


std::allocator_traits<Alloc>::allocate

< cpp‎ | memory‎ | allocator traits
定义于头文件 <memory> |
 | (1)
static pointer allocate( Alloc& a, size_type n ); |  | (C++11 起) (C++20 前)
[[nodiscard]] static constexpr pointer allocate( Alloc& a, size_type n ); |  | (C++20 起)
 | (2)
static pointer allocate( Alloc& a, size_type n, const_void_pointer hint ); |  | (C++11 起) (C++20 前)
[[nodiscard]] static constexpr pointer allocate( Alloc& a, size_type n, const_void_pointer hint ); |  | (C++20 起)

用分配器 a 分配 n*sizeof(Alloc::value_type) 字节的未初始化存储。于该存储创建 Alloc::value_type[n] 类型数组，但不构造其任何元素。

1) 调用 a.allocate(n)
2) 附带地传递内存位置提示 hint 。若可能则调用 a.allocate(n, hint) 。若不可能（例如无双参数成员函数 allocate() ），则调用 a.allocate(n)

参数

a | - | 使用的分配器
n | - | 要分配存储的对象数
hint | - | 指向临近内存位置的指针

返回值

调用 a.allocate(n) 所返回的指针。

注解

在 P0593R6 前不保证 Alloc::allocate 创建数组对象，这使得按照核心语言规范，对 std::vector 及某些其他容器使用非默认分配器并非实际良定义。

在调用 allocate 后、构造元素前， Alloc::value_type* 的指针算术在分配的数组内是良定义的，但若访问元素则行为未定义。

参阅

allocate
 分配未初始化的存储
(std::allocator<T> 的公开成员函数)


std::allocator_traits<Alloc>::construct

< cpp‎ | memory‎ | allocator traits
定义于头文件 <memory> |
template< class T, class... Args > static void construct( Alloc& a, T* p, Args&&... args ); | (C++11 起) (C++20 前)
template< class T, class... Args > static constexpr void construct( Alloc& a, T* p, Args&&... args ); | (C++20 起)

若可能，则在 p 所指向的分配的未初始化存储构造 T 类型对象，通过调用

a.construct(p, std::forward <Args>(args)...)

若以上不可行（例如 Alloc 无 construct() 成员函数），则调用

::new (static_cast<void*>(p)) T( std::forward <Args>(args)...) | (C++20 前)
std::construct_at(p, std::forward <Args>(args)...) | (C++20 起)

参数

a | - | 用于构造的分配器
p | - | 指向未初始化存储的指针，将在其上构造 T 对象
args... | - | 传递给 a.construct() 或布置 new (C++20 前) std::construct_at() (C++20 起) 的参数

返回值

（无）

注解

此函数为标准库容器在插入、复制或移动元素时所用。

因为此函数提供到布置 new 的自动回落，故 C++11 起成员函数 construct() 是分配器 (Allocator) 的可选要求。

参阅

operator newoperator new[] | 分配函数 (函数)
construct (C++17 中弃用)(C++20 中移除) | 在分配的存储构造对象 (std::allocator<T> 的公开成员函数)


std::allocator_traits<Alloc>::deallocate

< cpp‎ | memory‎ | allocator traits
定义于头文件 <memory> |
static void deallocate( Alloc& a, pointer p, size_type n ); | (C++11 起) (C++20 前)
static constexpr void deallocate( Alloc& a, pointer p, size_type n ); | (C++20 起)

用分配器 a 解分配 p 所引用的存储，通过调用 a.deallocate(p, n)

参数

a | - | 使用的分配器
p | - | 指向先前分配存储的指针
n | - | 分配存储的对象数

返回值

（无）

参阅

allocate [静态] | 用分配器分配未初始化的存储 (公开静态成员函数)
deallocate | 解分配存储 (std::allocator<T> 的公开成员函数)


std::allocator_traits<Alloc>::destroy

< cpp‎ | memory‎ | allocator traits
定义于头文件 <memory> |
template< class T > static void destroy( Alloc& a, T* p ); | (C++11 起) (C++20 前)
template< class T > static constexpr void destroy( Alloc& a, T* p ); | (C++20 起)

调用 p 所指向对象的析构函数。若可能，则通过调用 a.destroy(p) 这么做。若不可能（例如 Alloc 无成员函数 destroy() ），则直接调用 *p 的析构函数，同 p->~T() (C++20 前) std::destroy_at (p) (C++20 起) 。

参数

a | - | 用于析构的分配器
p | - | 指向要被销毁的对象的指针

返回值

（无）

注解

因为此函数提供到析构函数的自动回落，故 C++11 起成员函数 destroy() 是分配器 (Allocator) 的可选要求。

参阅

destroy
(C++17 中弃用)(C++20 中移除)
 析构在已分配存储中的对象
(std::allocator<T> 的公开成员函数)


std::allocator_traits<Alloc>::max_size

< cpp‎ | memory‎ | allocator traits
定义于头文件 <memory> |
static size_type max_size( const Alloc& a ) noexcept; | (C++11 起) (C++20 前)
static constexpr size_type max_size( const Alloc& a ) noexcept; | (C++20 起)

若可能，则通过调用 a.max_size() ，从 a 获得最大理论可行的分配大小。

若上述行为不可行（例如 Alloc 无成员函数 max_size() ），则返回 std::numeric_limits <size_type>::max() / sizeof(value_type) 。

参数

a - 要检测的分配器

返回值

理论最大分配大小。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2162 | C++11 | 不要求 max_size 为 noexcept | 已要求
LWG 2466 | C++11 | 后备情况下返回按字节计的理论最大分配大小 | 返回按元素计的大小

参阅

max_size
(C++17 中弃用)(C++20 中移除)
 返回最大的受支持分配大小
(std::allocator<T> 的公开成员函数)


std::allocator_traits<Alloc>::select_on_container_copy_construction

< cpp‎ | memory‎ | allocator traits
定义于头文件 <memory> |
static Alloc select_on_container_copy_construction( const Alloc& a ); | (C++11 起) (C++20 前)
static constexpr Alloc select_on_container_copy_construction( const Alloc& a ); | (C++20 起)

若可能，则获得分配器 a 的赋值构造函数版本，通过调用 a.select_on_container_copy_construction() 。若上述不可行（例如 Alloc 无成员函数 select_on_container_copy_construction() ），则返回不修改的 a 。

此函数为所有标准库容器的复制构造函数所调用。它允许构造函数参数所用的分配器为正在复制的容器所具备，并在需要的情况下修改状态。

参数

a - 标准容器用以传递给容器复制构造函数的分配器

返回值

复制构造的标准容器所用的分配器。

参阅

select_on_container_copy_construction
 复制 scoped_allocator_adaptor 与其所有分配器的状态
(std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...> 的公开成员函数)


std::assume_aligned

< cpp‎ | memory
定义于头文件 <memory>
template< std::size_t N, class T >
[[nodiscard]] constexpr T* assume_aligned(T* ptr);
 (C++20 起)

告知编译器 ptr 所指向的对象至少对齐到 N 。实现可用此信息生成更高效的代码，但仅会对通过 assume_aligned 的返回值进行的访问做此假设。

若 N 不是 2 的幂则程序非良构。若 ptr 不指向 T 类型对象（忽略每层的 cv 限定）或对象的对齐不至少为 N ，则行为未定义。

返回值

ptr 。

异常

不抛出。

注解

为确保程序能从以 assume_aligned 启用的优化受益，最好通过其返回值访问对象：

void f(int* p) {
   int* p1 = std::assume_aligned<256>(p);
   // 用 p1 而非 p ，以确保从对齐假设受益。
   // 然而，若 p 未对齐则程序有未定义行为，无关乎是否使用 p1 。
}

交给程序员确保对齐假设确实成立。调用 assume_aligned 不导致编译器检查或强制这点。

参阅

alignof 运算符 (C++11) | 查询类型的对齐要求
alignas 说明符 (C++11) | 指定该变量的存储应该按指定量对齐
aligned_storage (C++11) | 定义适于用作给定大小的类型的未初始化存储的类型 (类模板)
align (C++11) | 对齐缓冲区中的指针 (函数)


std::auto_ptr

< cpp‎ | memory
定义于头文件 <memory> |  |
template< class T > class auto_ptr; | (1) | (C++11 中弃用) (C++17 中移除)
template<> class auto_ptr<void>; | (2) | (C++11 中弃用) (C++17 中移除)

auto_ptr 是通过由 new 表达式获得的对象，并在 auto_ptr 自身被销毁时删除该对象的智能指针。它可用于为动态分配的对象提供异常安全、传递动态分配对象的所有权给函数和从函数返回动态分配的对象。

复制 auto_ptr ，会复制指针并转移所有权给目标： auto_ptr 的复制构造和复制赋值都会修改其右侧参数，而且“副本”不等于原值。因为这些不常见的复制语义，不可将 auto_ptr 置于标准容器中。此用途及其他使用更适合用 std::unique_ptr 。 (C++11 起)

2) 提供对类型 void 的特化，它声明 typedef element_type ，但无成员函数。

文档中到处使用附加的类模板 auto_ptr_ref 。它是保有到 auto_ptr 引用的实现定义类型。允许实现提供拥有不同名称的模板，或以其他方式实现返回它或接受它为参数的函数。

成员类型

成员类型 | 定义
element_type | T

成员函数

(构造函数)
 创建新的 auto_ptr
(公开成员函数)
(析构函数)
 销毁 auto_ptr 和被管理对象
(公开成员函数)
operator=
 从另一 auto_ptr 转移所有权
(公开成员函数)
operator auto_ptr<Y>operator auto_ptr_ref<Y>
 转换被管理指针到指向另一类型的指针
(公开成员函数)
观察器
get
 返回指向被管理对象的指针
(公开成员函数)
operator*operator->
 访问被管理对象
(公开成员函数)
修改器
reset
 替换被管理对象
(公开成员函数)
release
 释放被管理对象的所有权
(公开成员函数)


std::auto_ptr<T>::auto_ptr

< cpp‎ | memory‎ | auto ptr
explicit auto_ptr( X* p = 0 ) throw(); | (1) | (C++11 中弃用) (C++17 中移除)
auto_ptr( auto_ptr& r ) throw(); | (2) | (C++11 中弃用) (C++17 中移除)
template< class Y > auto_ptr( auto_ptr<Y>& r ) throw(); | (3) | (C++11 中弃用) (C++17 中移除)
auto_ptr( auto_ptr_ref<X> m ) throw(); | (4) | (C++11 中弃用) (C++17 中移除)

从指代待管理对象的指针构造 auto_ptr 。

1) 以指针 p 构造 auto_ptr 。
2) 以 r 所保有的指针构造 auto_ptr 。调用 r.release() 获取该对象的所有权。
3) 同 (2) 。 Y* 必须可隐式转换为 T* 。
4) 以 m 所指代的 auto_ptr 实例中保有的指针构造 auto_ptr 。对 m 所保有的 auto_ptr p 调用 p.release() 以获取该对象的所有权。
auto_ptr_ref 是保有到 auto_ptr 引用的实现定义类型。 std::auto_ptr 可隐式转换成此类型并可从它赋值。允许实现以不同的名称提供该模板，或以其他方式实现等价的功能。

参数

p | - | 指向待管理对象的指针
r | - | 另一 auto_ptr ，从它传递所有权
m | - | 保有到 auto_ptr 的引用的实现定义类型对象

注意

源自 auto_ptr_ref 的构造函数和复制赋值运算符允许从无名临时量复制构造和赋值 std::auto_ptr 。因为其复制构造函数与复制赋值运算符以非 const 引用接收参数，它们不能直接绑定右值。然而能执行用户定义转换（释放原 auto_ptr ），之后再调用以值接收 auto_ptr_ref 的构造函数或复制赋值运算符。这是移动语义的早期实现。


std::auto_ptr<T>::get

< cpp‎ | memory‎ | auto ptr
T* get() const throw(); | (C++11 中弃用) (C++17 中移除)

返回 *this 所保有的指针。

参数

（无）

返回值

*this 所保有的指针。

参阅

operator*operator->
 访问被管理对象
(公开成员函数)


std::auto_ptr<T>::operator*, std::auto_ptr<T>::operator->

< cpp‎ | memory‎ | auto ptr
T& operator*() const throw(); | (1) | (C++11 中弃用) (C++17 中移除)
T* operator->() const throw(); | (2) | (C++11 中弃用) (C++17 中移除)

解引用指向被管理对象的指针。第一版本要求 get() != 0 。

参数

（无）

返回值

1) *get() 。
2) get() 。

参阅

get
 返回指向被管理对象的指针
(公开成员函数)


std::auto_ptr<T>::operator=

< cpp‎ | memory‎ | auto ptr
auto_ptr& operator=( auto_ptr& r ) throw(); | (1) | (C++11 中弃用) (C++17 中移除)
template< class Y > auto_ptr& operator=( auto_ptr<Y>& r ) throw(); | (2) | (C++11 中弃用) (C++17 中移除)
auto_ptr& operator=( auto_ptr_ref m ) throw(); | (3) | (C++11 中弃用) (C++17 中移除)

以 r 所管理的对象替换被管理对象。

1) 等效于调用 reset(r.release()) 。
2) 等效于调用 reset(r.release()) 。 Y* 必须可隐式转换为 T* 。
3) 等效于调用 reset(m.release()) 。 auto_ptr_ref 是保有到 auto_ptr 引用的实现定义类型。 std::auto_ptr 可隐式转换到及转换自此类型。允许实现以不同的名称提供该模板，或以其他方式实现等价的功能。

参数

r | - | 另一 auto_ptr ，从它转移对象的所有权
m | - | 保有到 auto_ptr 引用的实现定义类型对象

返回值

*this 。

注意

源自 auto_ptr_ref 的构造函数和复制赋值运算符允许从无名临时量复制构造和赋值 std::auto_ptr 。因为其复制构造函数与复制赋值运算符以非 const 引用接收参数，它们不能直接绑定右值。然而能执行用户定义转换（释放原 auto_ptr ），之后再调用以值接收 auto_ptr_ref 的构造函数或复制赋值运算符。这是移动语义的早期实现。


std::auto_ptr<T>::operator auto_ptr<Y>

< cpp‎ | memory‎ | auto ptr
template< class Y > operator auto_ptr_ref<Y>() throw(); | (1) | (C++11 中弃用) (C++17 中移除)
template< class Y > operator auto_ptr<Y>() throw(); | (2) | (C++11 中弃用) (C++17 中移除)

转换 *this 为对于相异类型 Y 的 auto_ptr 。

1) 返回保有到 *this 引用的实现定义类型对象。 std::auto_ptr 可转换并且可赋值自此模板。允许实现以不同的名称提供该模板，或以其他方式实现等价的功能。
2) 以调用 release() 获得的指针构造新的 auto_ptr 。

参数

（无）

返回值

1) 保有到 *this 的引用的实现定义类型对象。
2) 拥有由调用 release() 获得的指针的 auto_ptr 。

注意

源自 auto_ptr_ref 的构造函数和复制赋值运算符允许从无名临时量复制构造和赋值 std::auto_ptr 。因为其复制构造函数与复制赋值运算符以非 const 引用接收参数，它们不能直接绑定右值。然而能执行用户定义转换（释放原 auto_ptr ），之后再调用以值接收 auto_ptr_ref 的构造函数或复制赋值运算符。这是移动语义的早期实现。


std::auto_ptr<T>::release

< cpp‎ | memory‎ | auto ptr
T* release() throw(); | (C++11 中弃用) (C++17 中移除)

返回保有的指针。调用后 *this 保有空指针。

参数

（无）

返回值

get() 。

参阅

reset
 替换被管理对象
(公开成员函数)


std::auto_ptr<T>::reset

< cpp‎ | memory‎ | auto ptr
void reset( T* p = 0 ) throw(); | (C++11 中弃用) (C++17 中移除)

替换 p 为保有的指针。若当前实现保有的指针不是空指针，则调用 delete get() 。

参数

p - 指向待管理对象的指针

返回值

（无）

参阅

release
 释放被管理对象的所有权
(公开成员函数)


std::auto_ptr<T>::~auto_ptr

< cpp‎ | memory‎ | auto ptr
~auto_ptr() throw(); | (C++11 中弃用) (C++17 中移除)

销毁管理的对象。调用 delete get() 。


std::bad_weak_ptr

< cpp‎ | memory
定义于头文件 <memory> |
class bad_weak_ptr; | (C++11 起)

std::bad_weak_ptr 是 std::shared_ptr 以 std::weak_ptr 为参数的构造函数，在 std::weak_ptr 指代已被删除的对象时，作为异常抛出的对象类型。

cpp/error/exception std-bad weak ptr-inheritance.svg

继承图

成员函数

(构造函数) | 构造新的 bad_weak_ptr 对象 (公开成员函数)
operator= | 替换 bad_weak_ptr 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::bad_weak_ptr::bad_weak_ptr

bad_weak_ptr() noexcept; | (1) | (C++11 起)
bad_weak_ptr( const bad_weak_ptr& other ) noexcept; | (2) | (C++11 起)

构造新的拥有实现定义的空终止字节字符串的 bad_weak_ptr 对象，字符串能通过 what() 访问。

1) 默认构造函数。
2) 复制构造函数。若 *this 与 other 均拥有动态类型 std::bad_weak_ptr 则 std::strcmp (what(), other.what()) == 0 。

参数

other - 要复制的另一异常对象

std::bad_weak_ptr::operator=

bad_weak_ptr& operator=( const bad_weak_ptr& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::bad_weak_ptr 则赋值后 std::strcmp (what(), other.what()) == 0 。

参数

other - 用以赋值的另一异常对象

返回值

*this

std::bad_weak_ptr::what

virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

示例

#include <memory>
#include <iostream>
int main()
{
    std::shared_ptr<int> p1(new int(42));
    std::weak_ptr<int> wp(p1);
    p1.reset();
    try {
        std::shared_ptr<int> p2(wp);
    } catch(const std::bad_weak_ptr& e) {
        std::cout << e.what() << '\n';
    }
}

可能的输出：

std::bad_weak_ptr

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2376 | C++11 | 要求在默认构造的 bad_weak_ptr 上调用 what 返回 "bad_weak_ptr" | 返回值为实现定义

参阅

shared_ptr (C++11) | 拥有共享对象所有权语义的智能指针 (类模板)
weak_ptr (C++11) | 到 std::shared_ptr 所管理对象的弱引用 (类模板)


C 内存管理库

< cpp‎ | memory

函数

定义于头文件 <cstdlib>
malloc | 分配内存 (函数)
aligned_alloc (C++17) | 分配对齐的内存 (函数)
calloc | 分配并清零内存 (函数)
realloc | 扩张或收缩之前分配的内存块 (函数)
free | 解分配之前分配的内存 (函数)

参阅


std::aligned_alloc

< cpp‎ | memory‎ | c
定义于头文件 <cstdlib> |
void* aligned_alloc( std::size_t alignment, std::size_t size ); | (C++17 起)

分配 size 字节的未初始化存储，由 alignment 指定其对齐。 size 参数必须是 alignment 的整数倍。

要求下列函数是线程安全的：

  • operator new 及 operator delete 的库版本
  • 全局 operator new 与 operator delete 的用户替换版本
  • std::calloc 、 std::malloc 、 std::realloc 、 std::aligned_alloc (C++17 起) 、 std::free

对这些分配或解分配特定存储单元的函数调用以单独全序出现，并且在此顺序中，每个解分配调用先发生于下个分配（若存在）。

 (C++11 起)

参数

alignment | - | 指定对齐。必须是实现支持的合法对齐。
size | - | 分配的字节数。 alignment 的整数倍。

返回值

成功时，返回指向新分配内存起始的指针。为避免内存泄漏，返回的指针必须由 std::free 或 std::realloc 解分配。

失败时，返回空指针。

注意

传递不是 alignment 整数倍的 size 或不受实现支持或非法的 alignment 导致函数失败并返回空指针（ C11 刚发布时，曾指定此情况为未定义行为，这为 DR 460 所纠正）。

作为“实现支持”要求的例子， POSIX 函数 posix_memalign 接受任何是二的幂且为 sizeof(void*) 倍数的 alignment ，而基于 POSIX 的 aligned_alloc 实现继承此要求。

常规的 std::malloc 分配适用于任何对象的大小的内存（实际上，意味着内存对齐到 alignof( std::max_align_t ) ）。此函数适用于过对齐分配，例如对 SSE 、缓存线或 VM 页边界。

示例

#include <cstdio>
#include <cstdlib>

int main()
{
    int* p1 = static_cast<int*>(std::malloc(10*sizeof *p1));
    std::printf("default-aligned address:   %p\n", static_cast<void*>(p1));
    std::free(p1);

    int* p2 = static_cast<int*>(std::aligned_alloc(1024, 10*sizeof *p2));
    std::printf("1024-byte aligned address: %p\n", static_cast<void*>(p2));
    std::free(p2);
}

可能的输出：

default-aligned address:   0x2221c20
1024-byte aligned address: 0x2222400

参阅

aligned_storage
(C++11)
 定义适于用作给定大小的类型的未初始化存储的类型
(类模板)


std::calloc

< cpp‎ | memory‎ | c
定义于头文件 <cstdlib>
void* calloc( std::size_t num, std::size_t size );

分配 num 个大小为 size 的对象的数组，并初始化所有位为零。

若分配成功，则返回指向为任何对象类型适当对齐的，被分配内存块最低（首）字节的指针。

若 size 为零，则行为是实现定义的（可以返回空指针，亦可返回某个不可用于访问存储的非空指针）

要求下列函数是线程安全的：

  • operator new 及 operator delete 的库版本
  • 全局 operator new 与 operator delete 的用户替换版本
  • std::calloc 、 std::malloc 、 std::realloc 、 std::aligned_alloc (C++17 起) 、 std::free

对这些分配或解分配特定存储单元的函数调用以单独全序出现，并且在此顺序中，每个解分配调用先发生于下个分配（若存在）。

 (C++11 起)

参数

num | - | 对象数量
size | - | 每个对象的大小

返回值

成功时，返回指向新分配内存起始的指针。返回的指针必须以 std::free() 或 std::realloc() 解分配。

失败时，返回空指针。

注意

因为对齐要求，分配的字节数不需要等于 num*size 。

将所有位初始化为零不保证浮点数或指针各被初始化到 0.0 与空指针值（尽管大多数平台上这为 true ）

最初（ C89 中），添加对零大小的支持是为了接纳下面这种代码

OBJ *p = calloc(0, sizeof(OBJ)); // “零长度”占位
...
while(1) {
    p = realloc(p, c * sizeof(OBJ)); // 重分配直至大小稳定
    ... // 可能更改 c 或打破循环的代码
}

示例

#include <iostream>
#include <cstdlib>

int main()
{
    int* p1 = (int*)std::calloc(4, sizeof(int)); // 分配并清零 4 个 int 的数组
    int* p2 = (int*)std::calloc(1, sizeof(int[4])); // 同上，直接指名数组类型
    int* p3 = (int*)std::calloc(4, sizeof *p3);   // 同上，不重复类型名

    if(p2)
        for(int n=0; n<4; ++n) // 打印数组
            std::cout << "p2[" << n << "] == " << p2[n] << '\n';

    std::free(p1);
    std::free(p2);
    std::free(p3);
}

输出：

p2[0] == 0
p2[1] == 0
p2[2] == 0
p2[3] == 0

参阅


std::free

< cpp‎ | memory‎ | c
定义于头文件 <cstdlib>
void free( void* ptr );

解分配先前由 std::malloc() 、 std::calloc() 、 std::aligned_alloc (C++17 起) 或 std::realloc() 分配的内存空间。

若 ptr 是空指针，则函数不做任何事。

若 ptr 的值不等于先前 std::malloc() 、 std::calloc() 、 std::aligned_alloc (C++17 起) 或 std::realloc() 返回的值，则行为未定义。

若 ptr 所指代的内存区域已被解分配，即已以 ptr 为参数掉调用 std::free() 或 std::realloc() ，且无对 std::malloc() 、 std::calloc() 、 std::aligned_alloc (C++17 起) 或 std::realloc() 产生等于之前 ptr 的指针，则行为未定义。

若在 std::free() 返回后，通过指针 ptr 访问（除非另一分配函数恰好产生等于 ptr 的指针值），则行为未定义。

要求下列函数是线程安全的：

  • operator new 及 operator delete 的库版本
  • 全局 operator new 与 operator delete 的用户替换版本
  • std::calloc 、 std::malloc 、 std::realloc 、 std::aligned_alloc (C++17 起) 、 std::free

对这些分配或解分配特定存储单元的函数调用以单独全序出现，并且在此顺序中，每个解分配调用先发生于下个分配（若存在）。

 (C++11 起)

参数

ptr - 指向要解分配的内存的指针

返回值

（无）

注意

此函数接受空指针（不做任何事）以减少特殊情况的总数。无论分配是否成功，分配函数返回的指针都能传递给 free() 。

示例

#include <cstdlib>

int main()
{
    int* p1 = (int*)std::malloc(10*sizeof *p1);
    std::free(p1); // 每个分配的指针都必须释放

    int* p2 = (int*)std::calloc(10, sizeof *p2);
    int* p3 = (int*)std::realloc(p2, 1000*sizeof *p3);
    if(p3) // p3 非空表示 p2 为 std::realloc 所释放
       std::free(p3);
    else // p3 空表示 p2 未被释放
       std::free(p2);
}

参阅


std::malloc

< cpp‎ | memory‎ | c
定义于头文件 <cstdlib>
void* malloc( std::size_t size );

分配 size 字节的未初始化存储。

若分配成功，则返回指向分配的适合对任何标量类型对齐的内存块中，最低（首）字节的指针。

若 size 为零，则行为是实现定义的（可以返回空指针，或某个不可用于访问存储，但必须传递给 std::free 的非空指针）。

要求下列函数是线程安全的：

  • operator new 及 operator delete 的库版本
  • 全局 operator new 与 operator delete 的用户替换版本
  • std::calloc 、 std::malloc 、 std::realloc 、 std::aligned_alloc (C++17 起) 、 std::free

对这些分配或解分配特定存储单元的函数调用以单独全序出现，并且在此顺序中，每个解分配调用先发生于下个分配（若存在）。

 (C++11 起)

参数

size - 要分配的字节数

返回值

成功时，返回指向新分配内存起始的指针。返回的指针必须用 std::free() 或 std::realloc() 解分配。

失败时，返回空指针。

注解

任何情况下，此函数不调用构造函数或初始化内存。无能保证调用匹配的解分配函数的预备使用的智能指针。 C++ 中偏好的内存分配方法是用 RAII 预备函数 std::make_unique 、 std::make_shared 、容器构造函数等，而在低层代码中为 new 表达式。

对于加载大文件，经由如 POSIX 上的 mmap 或 Windows 上的 CreateFileMapping(A/W) 伴随 MapViewOfFile 的操作系统特定函数进行文件映射，比为文件读取分配缓冲区更适合。

示例

#include <iostream>
#include <cstdlib>
#include <string>

int main()
{
    // 为 4 个 string 的数组分配足够空间
    if(auto p = (std::string*)std::malloc(4 * sizeof(std::string)))
    {
        int i = 0;
        try
        {
            for(; i != 4; ++i) // 填充数组
                new(p + i) std::string(5, 'a' + i);

            for(int j = 0; j != 4; ++j) // 打印出来
                std::cout << "p[" << j << "] == " << p[j] << '\n';
        }
        catch(...) {}

        for(; i != 0; --i) // 清理
            p[i - 1].~basic_string();

        std::free(p);
    }
}

输出：

p[0] == aaaaa
p[1] == bbbbb
p[2] == ccccc
p[3] == ddddd

参阅

operator newoperator new[] | 分配函数 (函数)
get_temporary_buffer (C++17 中弃用)(C++20 中移除) | 获得未初始化存储 (函数模板)


std::realloc

< cpp‎ | memory‎ | c
定义于头文件 <cstdlib>
void* realloc( void* ptr, std::size_t new_size );

重分配给定的内存区域。它必须是 std::malloc() 、 std::calloc() 或 std::realloc() 先前分配的，且仍未被 std::free() 释放，否则行为未定义。

重分配按以下之一进行：

a) 若可能则扩张或收缩 ptr 所指向的既存内存区域。区域的内容直到新旧大小的较小者都保留为更改。若区域扩张，则数组新部分的内容是未定义的。
b) 分配大小为 new_size 字节的新内存块，复制大小等于新旧大小较小者的内存区域，并释放旧块。

若无足够内存，则不释放旧块并返回空指针。

若 ptr 是空指针，则行为同调用 std::malloc(new_size) 。

若 new_size 为零，则行为是实现定义的：可以返回空指针（该情况下可能或可能不释放旧内存块），或可能返回某个不可用于访问存储的非空指针。这种用法被弃用（经由 C DR 400 ）。 (C++20 起)

要求下列函数是线程安全的：

  • operator new 及 operator delete 的库版本
  • 全局 operator new 与 operator delete 的用户替换版本
  • std::calloc 、 std::malloc 、 std::realloc 、 std::aligned_alloc (C++17 起) 、 std::free

对这些分配或解分配特定存储单元的函数调用以单独全序出现，并且在此顺序中，每个解分配调用先发生于下个分配（若存在）。

 (C++11 起)

参数

ptr | - | 指向要被重分配的内存区域的指针
new_size | - | 数组的新大小

返回值

成功时，返回指向新分配内存起始的指针。为避免内存泄漏，返回的必须以 std::free() 解分配指针。原指针 ptr 被非法化，且任何对它的访问是未定义行为（即使重分配是原位的）。

失败时，返回空指针。原指针 ptr 保持合法且可能需要以 std::free() 解分配。

注解

因为重分配可能涉及逐位复制（无论是扩展还是压缩），调用 realloc 后，只有可平凡复制 (TriviallyCopyable) 类型才能安全地于内存块的保留位置访问。

一些非标准库定义类型特性“可逐位移动 (BitwiseMovable) ”或“可重定位 (Relocatable) ”，这描述不拥有下列内容的类型：

  • 外部引用（例如链表或树的保有另一元素引用的结点），和
  • 内部引用（例如，可能保有另一成员地址的成员指针）。

重分配其存储后，能访问这种类型的对象，即使其复制构造函数非平凡。

示例

#include <cstdlib>
#include <new>
#include <cassert>

class MallocDynamicBuffer
{
    char* p;
public:
    explicit MallocDynamicBuffer(std::size_t initial = 0) : p(nullptr) {
       resize(initial);
    }
    ~MallocDynamicBuffer() { std::free(p); }
    void resize(std::size_t newSize) {
        if(newSize == 0) { // 此检查并非严格需要，但零大小 realloc 于 C 中弃用
            std::free(p);
            p = nullptr;
        } else {
            if(void* mem = std::realloc(p, newSize))
                p = static_cast<char*>(mem);
            else
                throw std::bad_alloc();
        }
    }
    char& operator[](size_t n) { return p[n]; }
    char operator[](size_t n) const { return p[n]; }
};

int main()
{
    MallocDynamicBuffer buf1(1024);
    buf1[5] = 'f';
    buf1.resize(10); // 收缩
    assert(buf1[5] == 'f');
    buf1.resize(1024); // 增长
    assert(buf1[5] == 'f');
}

参阅


std::construct_at

< cpp‎ | memory
定义于头文件 <memory> |
template<class T, class... Args> constexpr T* construct_at( T* p, Args&&... args ); | (C++20 起)

在给定地址 p 创建以参数 args... 初始化的 T 对象。此函数模板的特化仅若 ::new( std::declval <void*>()) T( std::declval <Args>()...) 在不求值语境中为良构才参与重载决议。

等价于

return ::new (const_cast<void*>(static_cast<const volatile void*>(p)))
    T(std::forward<Args>(args)...);

除了 construct_at 可用于常量表达式的求值。

在某常量表达式 e 的求值中调用 construct_at 时，参数 p 必须指向用 std::allocator <T>::allocate 获得的存储或生存期始于 e 的求值内的对象。

参数

p | - | 指向将在其上构造 T 对象的未初始化存储的指针
args... | - | 用于初始化的参数

返回值

p

示例

#include <iostream>
#include <memory>

struct S {
    int x;
    float y;
    double z;

    S(int x, float y, double z) : x{x}, y{y}, z{z} { std::cout << "S::S();\n"; }

    ~S() { std::cout << "S::~S();\n"; }

    void print() const {
        std::cout << "S { x=" << x << "; y=" << y << "; z=" << z << "; };\n";
    }
};

int main()
{
    alignas(S) unsigned char storage[sizeof(S)];

    S* ptr = std::construct_at(reinterpret_cast<S*>(storage), 42, 2.71828f, 3.1415);
    ptr->print();

    std::destroy_at(ptr);
}

输出：

S::S();
S { x=42; y=2.71828; z=3.1415; };
S::~S();

参阅

allocate | 分配未初始化的存储 (std::allocator<T> 的公开成员函数)
construct [静态] | 在分配的存储构造对象 (函数模板)
destroy_at (C++17) | 销毁在给定地址的对象 (函数模板)
ranges::construct_at (C++20) | 在给定地址创建对象 (niebloid)


std::default_delete

< cpp‎ | memory
定义于头文件 <memory> |  |
template< class T > struct default_delete; | (1) | (C++11 起)
template< class T > struct default_delete<T[]>; | (2) | (C++11 起)

std::default_delete 是不指定删除器时 std::unique_ptr 所用的默认删除策略。 default_delete 的特化在典型实现上为空类，并且用于空基类优化。

1) 非特化的 default_delete 用 delete 解分配单个对象的内存。
2) 亦为提供数组类型的使用 delete[] 的部分特化。

成员函数

(构造函数) | 构造 default_delete 对象 (公开成员函数)
operator() | 删除对象或数组 (公开成员函数)

std::default_delete::default_delete

constexpr default_delete() noexcept = default; | (1) |
template <class U> default_delete( const default_delete<U>& d ) noexcept; | (2) | (仅为初等 default_delete 模板的成员)
template<class U> default_delete( const default_delete<U[]>& d ) noexcept; | (3) | (仅为 default_delete<T[]> 模板特化的成员)
1) 构造 std::default_delete 对象。
2) 从另一 std::default_delete 构造 std::default_delete 对象。此构造函数仅若 U* 可隐式转换为 T* 才参与重载决议。
3) 从另一 std::default_delete<U[]> 对象构造 std::default_delete<T[]> 对象。此构造函数仅若 U(*)[] 可隐式转换为 T(*)[] 才参与重载决议。

参数

d - 复制来源的删除器

注解

std::default_delete 的转换构造函数模板令从 std::unique_ptr <Derived> 到 std::unique_ptr <Base> 的隐式转换可行。

std::default_delete::operator()

void operator()(T* ptr) const; | (1) | (仅为初等 default_delete 模板的成员)
template <class U> void operator()(U* ptr) const; | (2) | (仅为 default_delete<T[]> 模板特化的成员)
1) 在 ptr 上调用 delete 。
2) 在 ptr 上调用 delete[] 。此函数仅若 U(*)[] 能隐式转换为 T(*)[] 才参与重载决议。

任何情况下，若 U 是不完整类型，则程序为谬构。

参数

ptr - 要删除的对象或数组

异常

无异常保证。

在不完整类型上调用

于代码中调用 operator() 点，类型必须完整。一些实现中用 static_assert 确保如此。此要求的原因，是 C++ 中若完整类类型拥有非平凡析构函数或解分配函数，则在不完整类型上调用 delete 是未定义行为，因为编译器无法得知这种函数是否存在且必须被调用。

示例

#include <memory>
#include <vector>
#include <algorithm>

int main()
{
//    {
//        std::shared_ptr<int> shared_bad(new int[10]);
//    } // 析构函数调用 delete ，未定义行为

    {
        std::shared_ptr<int> shared_good(new int[10], std::default_delete<int[]>
());
    } // 析构函数调用 delete[] ， ok

    {
        std::unique_ptr<int> ptr(new int(5));
    } // unique_ptr<int> 使用 default_delete<int>

    {
        std::unique_ptr<int[]> ptr(new int[10]);
    } // unique_ptr<int[]> 使用 default_delete<int[]>

    // default_delete 能用于需要删除用函数对象的任何场所
    std::vector<int*> v;
    for(int n = 0; n < 100; ++n)
        v.push_back(new int(n));
    std::for_each(v.begin(), v.end(), std::default_delete<int>());
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2118 | C++11 | default_delete<T[]> 的成员函数拒绝限定转换 | 接受

参阅

unique_ptr
(C++11)
 拥有独有对象所有权语义的智能指针
(类模板)


std::destroy

< cpp‎ | memory
定义于头文件 <memory> |  |
 | (1) |
template< class ForwardIt > void destroy( ForwardIt first, ForwardIt last ); |  |  | (C++17 起) (C++20 前)
template< class ForwardIt > constexpr void destroy( ForwardIt first, ForwardIt last ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt > void destroy( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last ); | (2) | (C++17 起)
1) 销毁范围 [first, last) 中的对象，如同用
for (; first != last; ++first)
  std::destroy_at(std::addressof(*first));
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要销毁的元素的范围
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 通过合法 ForwardIt 实例的自增、赋值、比较或间接均不抛出异常。

返回值

（无）

复杂度

与 first 和 last 间的距离成线性。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template< class ForwardIt >
constexpr // C++20 起
void destroy( ForwardIt first, ForwardIt last )
{
  for (; first != last; ++first)
    std::destroy_at(std::addressof(*first));
}

示例

下列示例演示如何用 destroy 销毁元素的相接序列。

#include <memory>
#include <new>
#include <iostream>

struct Tracer {
    int value;
    ~Tracer() { std::cout << value << " destructed\n"; }
};

int main()
{
    alignas(Tracer) unsigned char buffer[sizeof(Tracer) * 8];

    for (int i = 0; i < 8; ++i)
        new(buffer + sizeof(Tracer) * i) Tracer{i}; // 手工构造对象

    auto ptr = std::launder(reinterpret_cast<Tracer*>(buffer));

    std::destroy(ptr, ptr + 8);
}

输出：

0 destructed
1 destructed
2 destructed
3 destructed
4 destructed
5 destructed
6 destructed
7 destructed

参阅

destroy_n (C++17) | 销毁范围中一定数量的对象 (函数模板)
destroy_at (C++17) | 销毁在给定地址的对象 (函数模板)


std::destroy_at

< cpp‎ | memory
定义于头文件 <memory> |
template< class T > void destroy_at( T* p ); | (C++17 起) (C++20 前)
template< class T > constexpr void destroy_at( T* p ); | (C++20 起)

若 T 不是数组类型，则调用 p 所指向对象的析构函数，如同用 p->~T() 。

若 T 是数组类型，则程序非良构 (C++20 前)按顺序递归地销毁 *p 的元素，如同通过调用 std::destroy ( std::begin (*p), std::end (*p)) (C++20 起)。

参数

p - 指向要被销毁的对象的指针

返回值

（无）

可能的实现

template<class T>
constexpr void destroy_at(T* p)
{
    if constexpr (std::is_array_v<T>)
        for (auto &elem : *p)
            (destroy_at)(std::addressof(elem));
    else
        p->~T();
}
// C++17 版本：
// template<class T> void destroy_at(T* p) { p->~T(); }

注解

destroy_at 推导要销毁的对象类型，从而避免在析构函数调用中显式写出它。

在某常量表达式 e 的求值中调用 destroy_at 时，参数 p 必须指向生存期始于 e 的求值内的对象。

 (C++20 起)

示例

下列示例演示如何用 destroy_at 销毁元素的相接序列。

#include <memory>
#include <new>
#include <iostream>

struct Tracer {
    int value;
    ~Tracer() { std::cout << value << " destructed\n"; }
};

int main()
{
    alignas(Tracer) unsigned char buffer[sizeof(Tracer) * 8];

    for (int i = 0; i < 8; ++i)
        new(buffer + sizeof(Tracer) * i) Tracer{i}; // 手工构造对象

    auto ptr = std::launder(reinterpret_cast<Tracer*>(buffer));

    for (int i = 0; i < 8; ++i)
        std::destroy_at(ptr + i);
}

输出：

0 destructed
1 destructed
2 destructed
3 destructed
4 destructed
5 destructed
6 destructed
7 destructed

参阅

destroy (C++17) | 销毁一个范围中的对象 (函数模板)
destroy_n (C++17) | 销毁范围中一定数量的对象 (函数模板)
construct_at (C++20) | 在给定地址创建对象 (函数模板)
ranges::destroy_at (C++20) | 销毁位于给定地址的元素 (niebloid)


std::destroy_n

< cpp‎ | memory
定义于头文件 <memory> |  |
 | (1) |
template< class ForwardIt, class Size > ForwardIt destroy_n( ForwardIt first, Size n ); |  |  | (C++17 起) (C++20 前)
template< class ForwardIt, class Size > constexpr ForwardIt destroy_n( ForwardIt first, Size n ); |  |  | (C++20 起)
template< class ExecutionPolicy, class ForwardIt, class Size > ForwardIt destroy_n( ExecutionPolicy&& policy, ForwardIt first, Size n ); | (2) | (C++17 起)
1) 销毁从 first 开始的范围中的 n 个对象，如同用
for (; n > 0; (void) ++first, --n)
  std::destroy_at(std::addressof(*first));
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first | - | 要销毁的元素范围的起始
n | - | 要销毁的元素数目
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 通过 ForwardIt 合法实例的自增、赋值、比较或间接均不抛出异常。

返回值

已被销毁的元素的范围结尾（即 std::next (first, n) ）。

复杂度

与 n 成线性。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class ForwardIt, class Size>
constexpr // C++20 起
ForwardIt destroy_n( ForwardIt first, Size n )
{
  for (; n > 0; (void) ++first, --n)
    std::destroy_at(std::addressof(*first));
  return first;
}

示例

下列示例演示如何用 destroy_n 销毁元素的相接序列。

#include <memory>
#include <new>
#include <iostream>

struct Tracer {
    int value;
    ~Tracer() { std::cout << value << " destructed\n"; }
};

int main()
{
    alignas(Tracer) unsigned char buffer[sizeof(Tracer) * 8];

    for (int i = 0; i < 8; ++i)
        new(buffer + sizeof(Tracer) * i) Tracer{i}; // 手工构造对象

    auto ptr = std::launder(reinterpret_cast<Tracer*>(buffer));

    std::destroy_n(ptr, 8);
}

输出：

0 destructed
1 destructed
2 destructed
3 destructed
4 destructed
5 destructed
6 destructed
7 destructed

参阅

destroy (C++17) | 销毁一个范围中的对象 (函数模板)
destroy_at (C++17) | 销毁在给定地址的对象 (函数模板)


std::enable_shared_from_this

< cpp‎ | memory
定义于头文件 <memory> |
template< class T > class enable_shared_from_this; | (C++11 起)

std::enable_shared_from_this 能让其一个对象（假设其名为 t ，且已被一个 std::shared_ptr 对象 pt 管理）安全地生成其他额外的 std::shared_ptr 实例（假设名为 pt1, pt2, ... ） ，它们与 pt 共享对象 t 的所有权。

若一个类 T 继承 std::enable_shared_from_this<T> ，则会为该类 T 提供成员函数： shared_from_this 。 当 T 类型对象 t 被一个为名为 pt 的 std::shared_ptr <T> 类对象管理时，调用 T::shared_from_this 成员函数，将会返回一个新的 std::shared_ptr <T> 对象，它与 pt 共享 t 的所有权。

成员函数

(构造函数) | 构造 enable_shared_from_this 对象 (受保护成员函数)
(析构函数) | 销毁 enable_shared_from_this 对象 (受保护成员函数)
operator= | 返回到 this 的引用 (受保护成员函数)
shared_from_this | 返回共享 *this 所有权的 shared_ptr (公开成员函数)
weak_from_this (C++17) | 返回共享 *this 所有权的 weak_ptr (公开成员函数)

成员对象

成员名 | 定义
weak_this (私有成员对象)(C++17) | 追踪 *this 的首个共享占有者的控制块的 std::weak_ptr 对象。仅为说明。

注意

enable_shared_from_this 的常见实现为：其内部保存着一个对 this 的弱引用（例如 std::weak_ptr )。 std::shared_ptr 的构造函数检测无歧义且可访问的 (C++17 起) enable_shared_from_this 基类，并且若内部存储的弱引用未为生存的 std::shared_ptr 占有，则 (C++17 起)赋值新建的 std::shared_ptr 为内部存储的弱引用。为已为另一 std::shared_ptr 所管理的对象构造一个 std::shared_ptr ，将不会考虑内部存储的弱引用，从而将导致未定义行为。

只允许在先前已被std::shared_ptr 管理的对象上调用 shared_from_this 。否则调用行为未定义 (C++17 前)抛出 std::bad_weak_ptr 异常（通过 shared_ptr 从默认构造的 weak_this 的构造函数） (C++17 起)。

enable_shared_from_this 提供安全的替用方案，以替代 std::shared_ptr <T>(this) 这样的表达式（这种不安全的表达式可能会导致 this 被多个互不知晓的所有者析构，见下方示例）。

示例

#include <memory>
#include <iostream>

struct Good: std::enable_shared_from_this<Good> // 注意：继承
{
    std::shared_ptr<Good> getptr() {
        return shared_from_this();
    }
};

struct Bad
{
    // 错误写法：用不安全的表达式试图获得 this 的 shared_ptr 对象
    std::shared_ptr<Bad> getptr() {
        return std::shared_ptr<Bad>(this);
    }
    ~Bad() { std::cout << "Bad::~Bad() called\n"; }
};

int main()
{
    // 正确的示例：两个 shared_ptr 对象将会共享同一对象
    std::shared_ptr<Good> gp1 = std::make_shared<Good>();
    std::shared_ptr<Good> gp2 = gp1->getptr();
    std::cout << "gp2.use_count() = " << gp2.use_count() << '\n';

    // 错误的使用示例：调用 shared_from_this 但其没有被 std::shared_ptr 占有
    try {
        Good not_so_good;
        std::shared_ptr<Good> gp1 = not_so_good.getptr();
    } catch(std::bad_weak_ptr& e) {
        // C++17 前为未定义行为； C++17 起抛出 std::bad_weak_ptr 异常
        std::cout << e.what() << '\n';
    }

    // 错误的示例，每个 shared_ptr 都认为自己是对象仅有的所有者
    std::shared_ptr<Bad> bp1 = std::make_shared<Bad>();
    std::shared_ptr<Bad> bp2 = bp1->getptr();
    std::cout << "bp2.use_count() = " << bp2.use_count() << '\n';
} // UB ： Bad 对象将会被删除两次

可能的输出：

gp2.use_count() = 2
bad_weak_ptr
bp2.use_count() = 1
Bad::~Bad() called
Bad::~Bad() called
*** glibc detected *** ./test: double free or corruption

参阅

shared_ptr
(C++11)
 拥有共享对象所有权语义的智能指针
(类模板)


std::enable_shared_from_this<T>::enable_shared_from_this

< cpp‎ | memory‎ | enable shared from this
constexpr enable_shared_from_this() noexcept; | (1) | (C++11 起)
enable_shared_from_this( const enable_shared_from_this<T>&obj ) noexcept; | (2) | (C++11 起)

构造新的 enable_shared_from_this 对象。值初始化私有 std::weak_ptr<T> 成员。

参数

obj - 要复制的 enable_shared_from_this

注意

无移动构造函数：从导出自 shared_from_this 的对象移动不转移其共享身份。

示例

#include <memory>

struct Foo : public std::enable_shared_from_this<Foo> {
    Foo() {}  // 隐式调用 enable_shared_from_this 构造函数
    std::shared_ptr<Foo> getFoo() { return shared_from_this(); }
};

int main() {
    std::shared_ptr<Foo> pf1(new Foo);
    auto pf2 = pf1->getFoo();  // 与 pf1 共享对象所有权
}

参阅

shared_ptr
(C++11)
 拥有共享对象所有权语义的智能指针
(类模板)


std::enable_shared_from_this<T>::operator=

< cpp‎ | memory‎ | enable shared from this
enable_shared_from_this<T>& operator=( const enable_shared_from_this<T> &obj ) noexcept; | (C++11 起)

不做任何事；返回 *this 。

参数

obj - 赋值给 *this 的 enable_shared_from_this

返回值

*this

注意

私有的 std::weak_ptr<T> 成员不受此赋值运算符影响。

示例

注意：定义 enable_shared_from_this::operator= 为受保护以避免意外切片，但允许导出类拥有默认的赋值运算符。

#include <memory>
#include <iostream>

class SharedInt : public std::enable_shared_from_this<SharedInt>
{
public:
    explicit SharedInt(int n) : mNumber(n) {}
    SharedInt(const SharedInt&) = default;
    SharedInt(SharedInt&&) = default;
    ~SharedInt() = default;

    // 两个赋值运算符都使用 enable_shared_from_this::operator=
    SharedInt& operator=(const SharedInt&) = default;
    SharedInt& operator=(SharedInt&&) = default;

    int number() const { return mNumber; }

private:
    int mNumber;
};

int main() {
    std::shared_ptr<SharedInt> a = std::make_shared<SharedInt>(2);
    std::shared_ptr<SharedInt> b = std::make_shared<SharedInt>(4);
    *a = *b;

    std::cout << a->number() << std::endl;
}

输出：

4

参阅

shared_ptr
(C++11)
 拥有共享对象所有权语义的智能指针
(类模板)


std::enable_shared_from_this<T>::shared_from_this

< cpp‎ | memory‎ | enable shared from this
std::shared_ptr <T> shared_from_this(); | (1)
std::shared_ptr <T const> shared_from_this() const; | (2)

返回与所有指代 *this 的 std::shared_ptr 共享 *this 所有权的 std::shared_ptr <T> 。

等效地执行 std::shared_ptr <T>(weak_this) ，其中 weak_this 是 enable_shared_from_this 的私有 mutable std::weak_ptr <T> 成员。

注解

只容许在先前共享的对象，即 std::shared_ptr 所管理的对象上调用 shared_from_this 。（特别是不能在构造 *this 期间 shared_from_this 。）

否则行为未定义 (C++17 前)抛出 std::bad_weak_ptr （由参数为默认构造的 weak_this 的 shared_ptr 构造函数） (C++17 起)。

返回值

与之前存在的 std::shared_ptr 共享 *this 所有权的 std::shared_ptr <T> 。

示例

#include <iostream>
#include <memory>

struct Foo : public std::enable_shared_from_this<Foo> {
    Foo() { std::cout << "Foo::Foo\n"; }
    ~Foo() { std::cout << "Foo::~Foo\n"; }
    std::shared_ptr<Foo> getFoo() { return shared_from_this(); }
};

int main() {
    Foo *f = new Foo;
    std::shared_ptr<Foo> pf1;

    {
        std::shared_ptr<Foo> pf2(f);
        pf1 = pf2->getFoo();  // 与 pf2 的对象共享所有权
    }

    std::cout << "pf2 is gone\n";
}

输出：

Foo::Foo
pf2 is gone
Foo::~Foo

参阅

shared_ptr
(C++11)
 拥有共享对象所有权语义的智能指针
(类模板)


std::enable_shared_from_this<T>::weak_from_this

< cpp‎ | memory‎ | enable shared from this
std::weak_ptr <T> weak_from_this() noexcept; | (1) | (C++17 起)
std::weak_ptr <T const> weak_from_this() const noexcept; | (2) | (C++17 起)

返回 std::weak_ptr <T> ，跟踪所有既存的指代 *this 的 std::shared_ptr 所拥有的 *this 的所有权。

注意

这是作为 enable_shared_from_this 一部分的私有 mutable weak_ptr 成员的副本。

返回值

与既存的 std::shared_ptr 共享 *this 所有权的 std::weak_ptr <T> 。

示例

本节未完成
原因：暂无示例

参阅

shared_ptr
(C++11)
 拥有共享对象所有权语义的智能指针
(类模板)


std::enable_shared_from_this<T>::~enable_shared_from_this

< cpp‎ | memory‎ | enable shared from this
~enable_shared_from_this();

销毁 *this 。

参阅

shared_ptr
(C++11)
 拥有共享对象所有权语义的智能指针
(类模板)


std::declare_no_pointers

< cpp‎ | memory
定义于头文件 <memory> |
void declare_no_pointers( char *p, std::size_t n ); | (C++11 起) (C++23 中移除)

告诉垃圾收集器或泄漏检测器，指定的内存区域（从 p 所指向的字节开始的 n 个字节）不含可追踪指针。若区域的任何部分在分配的对象内，则同一对象中必须含有整个区域。

参数

p | - | 指向范围起始的指针
n | - | 范围中的字节数

返回值

（无）

异常

不抛出。

示例

本节未完成
原因：暂无示例

参阅

undeclare_no_pointers
(C++11)(C++23 中移除)
 取消 std::declare_no_pointers 的效果
(函数)


std::declare_reachable

< cpp‎ | memory
定义于头文件 <memory> |
void declare_reachable( void* p ); | (C++11 起) (C++23 中移除)

声明 p 所引用的对象可抵达。可抵达对象将不为垃圾收集器删除，或不被泄漏检测器认为是泄露，即使所有指向它的指针都被销毁。对象可以声明为多次可抵达，该情况下会需要多次调用 std::undeclare_reachable 以移除此属性。例如，若实现拥有启用的垃圾收集，则异或链表需要声明其结点为可抵达。

参数

p - 安全派生的指针或空指针

返回值

（无）

异常

若系统不能分配追踪可抵达对象所要求的内存，则可能抛出 std::bad_alloc 。

示例

本节未完成
原因：暂无示例

参阅

undeclare_reachable
(C++11)(C++23 中移除)
 声明一个对象可以被回收
(函数模板)


std::get_pointer_safety

< cpp‎ | memory
定义于头文件 <memory> |
std::pointer_safety get_pointer_safety() noexcept; | (C++11 起) (C++23 中移除)

获得实现定义的指针安全模式，它是 std::pointer_safety 类型的值。

参数

（无）

返回值

此实现所用的 pointer_safety 。

示例

#include <iostream>
#include <memory>

int main()
{
    std::cout << "Pointer safety: ";
    switch (std::get_pointer_safety()) {
        case std::pointer_safety::strict:    std::cout << "strict\n"; break;
        case std::pointer_safety::preferred: std::cout << "preferred\n"; break;
        case std::pointer_safety::relaxed:   std::cout << "relaxed\n"; break;
    }
}

可能的输出：

Pointer safety: relaxed

参阅

pointer_safety
(C++11)(C++23 中移除)
 列出指针安全模式
(枚举)


std::pointer_safety

< cpp‎ | memory
定义于头文件 <memory> |
enum class pointer_safety { relaxed, preferred, strict }; | (C++11 起) (C++23 中移除)

有作用域枚举类型 pointer_safety 列出 C++ 所支持的指针安全模式。

枚举常量

pointer_safety::strict | 只有安全派生的指针（指向以 new 分配对象或其子对象的指针）可解引用或解分配。垃圾收集器可能活跃。
pointer_safety::preferred | 认为所有指针均合法且可以解引用或解分配。基于可达性的泄露检测器可能活跃。
pointer_safety::relaxed | 认为所有指针均合法且可以解引用或解分配。

参阅

get_pointer_safety
(C++11)(C++23 中移除)
 返回当前的指针安全模式
(函数)


std::undeclare_no_pointers

< cpp‎ | memory
定义于头文件 <memory> |
void undeclare_no_pointers( char *p, std::size_t n ); | (C++11 起) (C++23 中移除)

解除注册先前以 std::declare_no_pointers () 注册的范围。

参数

p | - | 指向先前以 std::declare_no_pointers 注册的范围起始的指针
n | - | 范围的字节数，与先前用于 std::declare_no_pointers 的值相同

返回值

（无）

异常

不抛出。

示例

本节未完成
原因：暂无示例

参阅

declare_no_pointers
(C++11)(C++23 中移除)
 声明该内存区域不含可追踪指针
(函数)


std::undeclare_reachable

< cpp‎ | memory
定义于头文件 <memory> |
template< class T > T* undeclare_reachable( T* p ); | (C++11 起) (C++23 中移除)

移除指针 p 所引用对象的可抵达状态，若先前为 std::declare_reachable 所设。若多次声明对象为可抵达，则需要相等次数的到 undeclare_reachable 的调用移除此属性。一旦对象不再声明为可抵达，且没有指针引用它，则它可能为垃圾收集器所回收，或被泄露检测器报告为泄露。

参数

p - 指向先前声明为可抵达且之后未被析构的对象的指针

返回值

p 的安全派生副本。

异常

不抛出。

示例

本节未完成
原因：暂无示例

参阅

declare_reachable
(C++11)(C++23 中移除)
 声明一个对象不能被回收
(函数)


std::pmr::get_default_resource

< cpp‎ | memory
定义于头文件 <memory_resource> |
std::pmr::memory_resource * get_default_resource() noexcept; | (C++17 起)

获取默认的 memory_resource 指针。

默认 memory_resource 指针为某些设施在未显式提供 memory_resource 使所用。初始的默认 memory_resource 指针是 std::pmr::new_delete_resource 的返回值。

此函数是线程安全的。先前对 std::pmr::set_default_resource 的调用同步于（见 std::memory_order ） 后继的 std::pmr::get_default_resource 调用。

返回值

返回默认 memory_resource 指针的值。

参阅

set_default_resource (C++17) | 设置缺省 std::pmr::memory_resource (函数)
new_delete_resource (C++17) | 返回一个静态的程序范围 std::pmr::memory_resource，它使用全局 operator new 与 operator delete 分配和解分配内存 (函数)


std::get_temporary_buffer

< cpp‎ | memory
定义于头文件 <memory>
template< class T >

std::pair <T*, std::ptrdiff_t >

get_temporary_buffer( std::ptrdiff_t count );
 (C++11 前)
template< class T >

std::pair <T*, std::ptrdiff_t >

get_temporary_buffer( std::ptrdiff_t count ) noexcept;
 (C++11 起)
(C++17 中弃用)
(C++20 中移除)

分配未初始化的相接存储，它应足以存储至多 count 个 T 类型的相邻对象。要求是非绑定的，且实现可以分配少于或多于存储 count 个相邻对象所需的内存。

参数

count - 所需的对象数量

返回值

一个 std::pair ，保有指向被分配存储起始的指针，和适合在实际分配的存储中的对象数。

若无法分配内存，或若分配的存储不足以存储单个 T 类型元素，则结果的 first 元素为空指针且 second 元素为零。

示例

#include <algorithm>
#include <iostream>
#include <memory>
#include <string>
#include <iterator>

int main()
{
    const std::string s[] = {"string", "1", "test", "..."};
    const auto p = std::get_temporary_buffer<std::string>(4);
    // 要求将 p.first 传递给 return_temporary_buffer
    // （当心提前退出和异常）

    std::copy(s, s + p.second,
              std::raw_storage_iterator<std::string*, std::string>(p.first));
    // 要求单独销毁每个 p 中的 string
    // （当心提前退出和异常）

    std::copy(p.first, p.first + p.second,
              std::ostream_iterator<std::string>{std::cout, "\n"});

    std::for_each(p.first, p.first + p.second, [](std::string& e) {
        e.~basic_string<char>();
    });

    std::return_temporary_buffer(p.first);
}

输出：

string
1
test
...

参阅

return_temporary_buffer
(C++17 中弃用)(C++20 中移除)
 释放未初始化存储
(函数模板)


std::inout_ptr_t

< cpp‎ | memory
定义于头文件 <memory> |
template< class Smart, class Pointer, class... Args > class inout_ptr_t; | (C++23 起)

inout_ptr_t 用于对通过 Pointer* （通常为某对象类型 T 的 T** ）或 void** 参数重设所有权的外来函数，适配智能指针之类的类型。

inout_ptr_t 在构造时捕获额外的实参，为前述的这种外来函数访问的结果提供存储，释放适配的 Smart 对象所保有的所有权，而最终在销毁时以该结果和捕获的实参重设适配的 Smart 对象。

inout_ptr_t 表现如同它拥有下列非静态数据成员：

  • 一个 Smart& 引用，在构造时绑定到被适配的对象，
  • 对 Args... 中的每个 T 有一个 T 类型成员，它是在构造时捕获并在析构时用于重设的实参，以及
  • 适合在其内存储 Pointer 以及提供 void* 对象的成员子对象，其中 Pointer 或 void* 对象通常会暴露给用于重初始化的外来函数。

若 Smart 不是指针类型，则在适配的对象上至多调用一次 release() 。实现可以在构造函数内或调用 release() ，或在析构函数内若 Pointer 值非空则在重设前调用。

用户能通过在 Args... 中分别指定对象类型或引用类型，控制每个参数是按复制还是按引用捕获。

模板形参

Smart | - | 要适配的对象（常为智能指针）的类型
Pointer | - | 外来函数写入其结果所用的对象（常为裸指针）的类型
Args... | - | 用于重设适配的对象的捕获实参的类型
类型要求
- Pointer 必须满足可空指针 (NullablePointer) 的要求。
- 若 Smart 为 std::shared_ptr 特化则程序非良构。

特化

不同于标准库中的大多数类模板，依赖于至少一个程序定义类型的 inout_ptr_t 程序定义特化不需要符合对主模板的要求。

此许可允许程序定义特化将存储于非标准智能指针内的裸指针暴露给外来函数。

成员函数

(构造函数) (C++23) | 构造 inout_ptr_t (公开成员函数)
operator= [被删除](C++23) | inout_ptr_t 不可赋值 (公开成员函数)
(析构函数) (C++23) | 重设适配的智能指针 (公开成员函数)
operator Pointer*operator void** (C++23) | 转换 inout_ptr_t 为用于输出的存储的地址 (公开成员函数)

非成员函数

inout_ptr
(C++23)
 以关联的智能指针和重设参数创建 inout_ptr_t
(函数模板)

注解

inout_ptr_t 期待外来函数释放被指向的 Pointer 的值所表示的所有权，然后重初始化它。禁止带 std::shared_ptr 的用法，因为这种操作要求独占所有权。

inout_ptr_t 的典型用法是由 std::inout_ptr 创建其临时对象，这会立即重设智能指针。例如，给定设置器函数和智能指针，分别以 int foreign_resetter(T**); 与 std::unique_ptr <T, D> up; 声明，

if (int ec = foreign_resetter(std::inout_ptr(up)) {
    return ec;
}

粗略地等价于

T *raw_p = up.get();
up.release();
int ec = foreign_resetter(&raw_p);
up.reset(raw_p);
if (ec != 0) {
    return ec;
}

不推荐创建拥有自动存储期以外的存储期的 inout_ptr_t 对象，因为这种代码较可能产生悬垂引用并在析构时导致未定义行为。

捕获的参数常被打包到 std::tuple <Args...> 中。实现可能用不同的机制提供他们需要保有的 Pointer 或 void* 对象。

示例

本节未完成
原因：暂无示例

参阅

out_ptr_t (C++23) | 与外来指针设置器交互，并在析构时重设智能指针 (类模板)
unique_ptr (C++11) | 拥有独有对象所有权语义的智能指针 (类模板)
shared_ptr (C++11) | 拥有共享对象所有权语义的智能指针 (类模板)


std::inout_ptr

< cpp‎ | memory‎ | inout ptr t
定义于头文件 <memory> |
template< class Pointer = void, class Smart, class... Args > auto inout_ptr( Smart& s, Args&&... args ); | (C++23 起)

返回拥有被推导模板实参的 inout_ptr_t ，按引用绑定重设用的实参。

若返回值（见后述）的构造非良构则程序非良构。

参数

s | - | 要适配的对象（常为智能指针）
args... | - | 要捕获的用于重设的实参

返回值

std::inout_ptr_t<Smart, P, Args&&>(s, std::forward <Args>(args)...) ，其中 P 为

  • Pointer ，若 Pointer 与 void 不同，
  • 否则为 Smart::pointer ，若它合法并指代类型，
  • 否则为 Smart::element_type* ，若 Smart::element_type 合法并指代类型，
  • 否则为 std::pointer_traits <Smart>::element_type* 。

注解

用户可对模板形参 Pointer 指定模板实参，以与接收 Pointer* 的外来函数交互。

由于所有实参都按引用捕获，返回的 inout_ptr_t 应为在含有外来函数调用的全表达式结尾销毁的临时对象，以避免悬垂引用。

示例

本节未完成
原因：暂无示例

参阅

out_ptr (C++23) | 以关联的智能指针和重设参数创建 out_ptr_t (函数模板)
make_uniquemake_unique_for_overwrite (C++14)(C++20) | 创建管理一个新对象的独占指针 (函数模板)
make_sharedmake_shared_for_overwrite (C++20) | 创建管理一个新对象的共享指针 (函数模板)


std::inout_ptr_t<Smart,Pointer,Args...>::inout_ptr_t

< cpp‎ | memory‎ | inout ptr t
explicit inout_ptr_t( Smart &sp, Args... args ); | (1) | (C++23 起)
inout_ptr_t( const inout_ptr_t& ) = delete; | (2) | (C++23 起)
1) 创建 inout_ptr_t 。如同将 sp 绑定到 Smart& 成员一般适配它，如同用 std::forward <T>(t) 初始化对应的 Args... 中类型 T 的成员一般捕获 args... 中的实参 t ，然后若 Smart 为指针类型则以 sp 初始化存储的 Pointer ，否则以 sp.get() 初始化它。若 Smart 不是指针类型则可能调用 sp.release() ，该情况下不会再于析构函数内调用它。
2) 复制构造函数被显示删除。 inout_ptr_t 既不可复制又不可移动。

参数

sp | - | 要适配的对象（常为智能指针）
args... | - | 要捕获的用于重设的实参

返回值

（无）

异常

可能抛出实现定义的异常。

注解

若 Smart 不是指针类型且构造函数不调用 sp.release() ，则析构函数在重设前可能调用它。

args... 中的每个参数若拥有对象类型则被移动到创建的 inout_ptr_t 中，而若拥有引用类型则保持原状转移到创建的 inout_ptr_t 中。

允许 inout_ptr_t 抛出异常。例如当 sp 为带有控制块的侵入式指针时，新的控制块的分配可以在构造函数而非析构函数内进行。

示例

本节未完成
原因：暂无示例


std::inout_ptr_t<Smart,Pointer,Args...>::operator Pointer*, std::inout_ptr_t<Smart,Pointer,Args...>::operator void**

< cpp‎ | memory‎ | inout ptr t
operator Pointer*() const noexcept; | (1) | (C++23 起)
operator void**() const noexcept; | (2) | (C++23 起)

暴露 Pointer 或 void* 对象的地址给一般会释放其值所表示的所有权然后重初始化它的外来函数。

1) 转换 *this 为存储的 Pointer 对象的地址。
2) 转换 *this 为 void* 对象的地址。此转换函数仅若 Pointer 与 void* 不同才参与重载决议，而若 Pointer 不是指针类型则程序非良构。
void* 对象的初值等于存储的 Pointer 对象的值转换到 void* ，而任何对它的修改影响用于析构函数的 Pointer 值。在 *this 的生存期外访问该 void* 拥有未定义行为。

一旦在一个 inout_ptr_t 对象上调用了此二转换函数之一，则不应当调用另一个，否则行为未定义。

参数

（无）

返回值

1) 存储的 Pointer 对象的地址。
2) 满足前述要求的 void* 对象的地址。

注解

若返回值所指向的对象未被写入，则它等于适配的 Smart 对象在构造前持有的值。

常见实现上，每个作为指针类型的 Pointer 对象表示均与 void* 的兼容，从而这些实现常在 Pointer 对象的存储内存储该 void* 对象，不需要额外存储：

  • 若实现启用基于类型的别名分析（依赖严格别名化规则），则可以使用正确对齐的 std::byte[sizeof(void*)] 成员子对象，而两个转换函数都返回在该数组内隐式创建的对象的地址。
  • 否则，可将 Pointer 成员子对象用于两个转换函数，而 (2) 可以直接返回 reinterpret_cast 成 void** 的其地址。

若 Pointer 是对象表示与 void* 的不兼容的指针类型，则可能需要额外的 bool 标志记录是否调用了 (1) （或 (2) ）。

示例

本节未完成
原因：暂无示例


std::inout_ptr_t<Smart,Pointer,Args...>::~inout_ptr_t

< cpp‎ | memory‎ | inout ptr t
~inout_ptr_t(); | (C++23 起)

以修改的 Pointer 对象（或若调用了 operator void**() 则为 void* 对象）的值捕获的实参重设适配的 Smart 对象。可能在适配的 Smart 对象上调用 release() ，若构造函数未调用它。

令

  • s 代表适配的 Smart 对象，
  • args... 代表捕获的实参，
  • p 代表存储的 Pointer 的值，或若调用了 operator void** 则为 static_cast<Pointer>(*operator void**()) ，
  • SP 为
    • Smart::pointer ，若它合法并代表类型，否则为
    • Smart::element_type* ，若 Smart::element_type 并代表类型，否则为
    • std::pointer_traits <Smart>::element_type* ，若 std::pointer_traits <Smart>::element_type 合法并代表类型，否则为
    • Pointer
  • /*do-release*/ 代表 s.release() ，若构造函数不调用 release() ，否则为空。

若 Smart 为指针类型，则析构函数进行

if (p) s = static_cast<Smart>(p); ，而若 sizeof...(Args) > 0 则程序非良构，

否则，若 s.reset(static_cast<SP>(p), std::forward <Args>(args)...) 为良构，则析构函数进行

if (p) { /*do-release*/; s.reset(static_cast<SP>(p), std::forward <Args>(args)...); } ，

否则，若 std::is_constructible_v <Smart, SP, Args...> 为 true ，则析构函数进行

if (p) { /*do-release*/; s = Smart(static_cast<SP>(p), std::forward <Args>(args)...); } ，

否则程序非良构。

注解

实现可能在构造时分配 Smart 所需的数据结构（例如控制块）的存储，以将不抛出的工作留给析构函数。

在重设后销毁按值捕获的实参。


std::make_obj_using_allocator

< cpp‎ | memory
定义于头文件 <memory> |
template< class T, class Alloc, class... Args > constexpr T make_obj_using_allocator( const Alloc& alloc, Args&&... args ); | (C++20 起)

以使用分配器构造的手段创建给定的 T 类型对象。

等价于

return std::make_from_tuple<T>(
    std::uses_allocator_construction_args<T>(alloc, std::forward<Args>(args)...)
);

参数

alloc | - | 要使用的分配器。
args | - | 传递给 T 构造函数的参数

返回值

新创建的 T 类型对象。

异常

可能抛出 T 的构造函数所抛的任何异常，常包括 std::bad_alloc 。

示例

本节未完成
原因：暂无示例

参阅

uses_allocator_construction_args (C++20) | 准备匹配给定类型所要求的使用分配器构造的口味的参数列表 (函数模板)
uninitialized_construct_using_allocator (C++20) | 以使用分配器构造的手段在指定的内存位置创建给定类型的对象 (函数模板)


std::pmr::memory_resource

< cpp‎ | memory
定义于头文件 <memory_resource> |
class memory_resource; | (C++17 起)

类 std::pmr::memory_resource 是抽象接口，针对封装内存资源类的无界集。

成员函数

(构造函数)
(隐式声明)
 构造新的 memory_resource
(公开成员函数)
(析构函数)
[虚]
 析构 memory_resource
(虚公开成员函数)
operator=
(隐式声明)
 隐式声明的复制赋值运算符
(公开成员函数)
公开成员函数
allocate
 分配内存
(公开成员函数)
deallocate
 解分配内存
(公开成员函数)
is_equal
 与另一 memory_resource 比较相等
(公开成员函数)
私有成员函数
do_allocate
[虚]
 分配内存
(虚私有成员函数)
do_deallocate
[虚]
 解分配内存
(虚私有成员函数)
do_is_equal
[虚]
 与另一 memory_resource 比较相等
(虚私有成员函数)

非成员函数

operator==operator!=
(C++20 中移除)
 比较二个 memory_resource
(函数)


std::pmr::memory_resource::allocate

< cpp‎ | memory‎ | memory resource
void* allocate( std::size_t bytes,
std::size_t alignment = alignof( std::max_align_t ));
 (C++17 起)
(C++20 前)
[[nodiscard]] void* allocate( std::size_t bytes,
std::size_t alignment = alignof( std::max_align_t ));
 (C++20 起)

分配至少有 bytes 字节的存储。若支持这种对齐，则返回的存储对齐到指定的 alignment ，否则对齐到 alignof( std::max_align_t ) 。

等价于 return do_allocate(bytes, alignment); 。

异常

若不能取得拥有要求的大小和对齐的存储，则抛出异常。

参阅

do_allocate
[虚]
 分配内存
(虚私有成员函数)


std::pmr::memory_resource::deallocate

< cpp‎ | memory‎ | memory resource
void deallocate(void* p,

std::size_t bytes,

std::size_t alignment = alignof( std::max_align_t ));
 (C++17 起)

解分配 p 所指向的存储。 p 应当是先前在比较等于 *this 的 memory_resource 上对 allocate(bytes, alignment) 的调用所返回的值，且它指向的存储应当未被解分配。

等价于 do_deallocate(p, bytes, alignment); 。

异常

不抛出任何异常。

参阅

do_deallocate
[虚]
 解分配内存
(虚私有成员函数)


std::pmr::memory_resource::do_allocate

< cpp‎ | memory‎ | memory resource
virtual void* do_allocate( std::size_t bytes, std::size_t alignment) = 0; | (C++17 起)

分配至少有 bytes 字节的存储，对齐到指定的 alignment 。

alignment 应当是二的幂。

异常

若不能取得拥有请求的大小和对齐的存储，则抛出异常。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2843 | C++17 | 处理不支持的对齐有矛盾 | 抛出异常

参阅

allocate
 分配内存
(公开成员函数)


std::pmr::memory_resource::do_deallocate

< cpp‎ | memory‎ | memory resource
virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) = 0; | (C++17 起)

解分配 p 所指向的存储。

p 必须是先前在比较等于 *this 的 memory_resource 上对 allocate(bytes, alignment) 的调用所返回的值，且它指向的存储必须未被解分配，否则行为未定义。

异常

不抛出任何异常。

参阅

deallocate
 解分配内存
(公开成员函数)


std::pmr::memory_resource::do_is_equal

< cpp‎ | memory‎ | memory resource
virtual bool do_is_equal(const std::pmr::memory_resource & other) const noexcept = 0; | (C++17 起)

比较 *this 与 other 的相等性。

二个 memory_resource 比较相等，当且仅当从一个 memory_resource 分配的内存能从另一个解分配，反之亦然。

注解

other 的最终派生类型可能不匹配 *this 的最终派生类型。典型的派生类实现必须用 dynamic_cast 检查 *this 与 other 的最终派生类型是否匹配，而若转型失败则立即返回 false 。

参阅

is_equal
 与另一 memory_resource 比较相等
(公开成员函数)


std::pmr::memory_resource::is_equal

< cpp‎ | memory‎ | memory resource
bool is_equal(const memory_resource& other) const noexcept; | (C++17 起)

比较 *this 与 other 的相等性。二个 memory_resource 比较相等，当且仅当从一个 memory_resource 分配的内存能从另一个解分配，反之亦然。

等价于 return do_is_equal(other); 。

参阅

do_is_equal
[虚]
 与另一 memory_resource 比较相等
(虚私有成员函数)


std::pmr::memory_resource::memory_resource

< cpp‎ | memory‎ | memory resource
memory_resource() = default; | (1) | (C++17 起) (隐式声明)
memory_resource(const memory_resource&) = default; | (2) | (C++17 起) (隐式声明)
1) 隐式声明的默认构造函数。
2) 隐式声明的复制构造函数。


std::pmr::operator==, std::pmr::operator!=

< cpp‎ | memory‎ | memory resource
定义于头文件 <memory_resource>
bool operator==( const std::pmr::memory_resource & a,
const std::pmr::memory_resource & b ) noexcept;
 (1) (C++17 起)
bool operator!=( const std::pmr::memory_resource & a,
const std::pmr::memory_resource & b ) noexcept;
 (2) (C++17 起)
(C++20 前)

比较 memory_resource a 与 b 的相等性。二个 memory_resource 比较相等，当且仅当从一个 memory_resource 分配的内存能从另一个解分配，反之亦然。

!= 运算符从 operator== 合成。

 (C++20 起)

返回值

1) &a == &b || a.is_equal(b)
2) !(a == b)

参阅

is_equal
 与另一 memory_resource 比较相等
(公开成员函数)


std::pmr::monotonic_buffer_resource

< cpp‎ | memory
定义于头文件 <memory_resource> |
class monotonic_buffer_resource : public std::pmr::memory_resource ; | (C++17 起)

类 std::pmr::monotonic_buffer_resource 是特定目的的内存资源类，它仅在销毁资源时释放分配的内存。它的意图是提供非常快速的内存分配，在内存用于分配少量对象，并于之后一次释放的情况下。

monotonic_buffer_resource 能以初始缓冲区构造，若无初始缓冲，或缓冲用尽，则从构造时提供的上游分配器分配缓冲区。缓冲区的大小以几何级数增长。

monotonic_buffer_resource 不是线程安全的。

成员函数

(构造函数)
 构造一个 monotonic_buffer_resource
(公开成员函数)
(析构函数)
[虚]
 销毁一个 monotonic_buffer_resource ，释放所有分配的内存
(虚公开成员函数)
operator=
[被删除]
 复制赋值运算符被删除。 monotonic_buffer_resource 不可复制赋值
(公开成员函数)
公开成员函数
release
 释放所有分配的内存
(公开成员函数)
upstream_resource
 返回指向上游 memory_resource 的指针
(公开成员函数)
受保护成员函数
do_allocate
[虚]
 分配内存
(虚受保护成员函数)
do_deallocate
[虚]
 无操作
(虚受保护成员函数)
do_is_equal
[虚]
 与另一 std::pmr::memory_resource 比较相等性
(虚受保护成员函数)


std::pmr::monotonic_buffer_resource::do_allocate

< cpp‎ | memory‎ | monotonic buffer resource
virtual void* do_allocate( std::size_t bytes, std::size_t alignment); | (C++17 起)

分配存储

若当前缓冲区足以不使用空间以适合一个拥有指定大小和对齐的块，则从当前缓冲区分配返回的块。

否则，此函数通过调用 upstream_resource()->allocate(n, m) 分配新缓冲区，其中 n 不小于bytes 与下个缓冲区大小的较大者，且 m 不小于 alignment 。它设置新缓冲区为当前缓冲区，以实现定义的增长因子（不必是整数）增加下个缓冲区大小，然后从新分配的缓冲区分配返回块。

返回值

指向至少 bytes 字节大小的指针，若支持该对齐则对齐到指定的 alignment ，否则对齐到 alignof( std::max_align_t ) 。

异常

不抛出任何异常，除非上游 memory_resource 的 allocate() 抛出。

参阅

allocate | 分配内存 (std::pmr::memory_resource 的公开成员函数)
do_allocate [虚] | 分配内存 (std::pmr::memory_resource 的虚私有成员函数)


std::pmr::monotonic_buffer_resource::do_deallocate

< cpp‎ | memory‎ | monotonic buffer resource
virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment); | (C++17 起)

此函数无效应。 monotonic_buffer_resource 所用的内存，如其名所指示单调地增加，直到销毁资源为止。

异常

不抛出任何异常。

参阅

deallocate | 解分配内存 (std::pmr::memory_resource 的公开成员函数)
do_deallocate [虚] | 解分配内存 (std::pmr::memory_resource 的虚私有成员函数)


std::pmr::monotonic_buffer_resource::do_is_equal

< cpp‎ | memory‎ | monotonic buffer resource
virtual bool do_is_equal(const std::pmr::memory_resource & other) const noexcept; | (C++17 起)

比较 *this 与 other 的相等性——用 monotonic_buffer_resource 分配的内存只能用相同资源解分配。

返回值

this == &other

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3000 | C++17 | 进行了不必要的 dynamic_cast | 已移除

参阅

do_is_equal
[虚]
 与另一 memory_resource 比较相等
(std::pmr::memory_resource 的虚私有成员函数)


std::pmr::monotonic_buffer_resource::monotonic_buffer_resource

< cpp‎ | memory‎ | monotonic buffer resource
monotonic_buffer_resource();
 (1) (C++17 起)
explicit monotonic_buffer_resource( std::pmr::memory_resource * upstream);
 (2) (C++17 起)
explicit monotonic_buffer_resource( std::size_t initial_size);
 (3) (C++17 起)
monotonic_buffer_resource( std::size_t initial_size,
std::pmr::memory_resource * upstream);
 (4) (C++17 起)
monotonic_buffer_resource(void* buffer, std::size_t buffer_size);
 (5) (C++17 起)
monotonic_buffer_resource(void* buffer, std::size_t buffer_size,
std::pmr::memory_resource * upstream);
 (6) (C++17 起)
monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
 (7) (C++17 起)

构造 monotonic_buffer_resource 。不接收上游 memory_resource 指针的构造函数以 std::pmr::get_default_resource 为 memory_resource 。

1-2) 设置当前缓冲区为空，下个缓冲区大小为实现定义大小。
3-4) 设置当前缓冲区为空，下个缓冲区大小为不小于 initial_size 的值。
5-6) 设置当前缓冲区为 buffer ，下个缓冲区大小为 buffer_size （但不小于 1 ）。然后以实现定义的增长因子（不必是整数）增加下个缓冲区大小。
7) 复制构造函数被删除。

参数

upstream | - | 要使用的上游内存资源；必须指向合法的 memory_resource
initial_size | - | 要分配的首个缓冲区的最小大小；必须大于零
buffer | - | 使用的初始缓冲区
buffer_size | - | 初始缓冲区的大小；不能大于 buffer 的字节数


std::pmr::monotonic_buffer_resource::release

< cpp‎ | memory‎ | monotonic buffer resource
void release(); | (C++17 起)

通过上游 memory_resource 的 ddeallocate 函数，按需要释放所有分配的内存。重设当前缓冲区及下个缓冲区大小为其构造时的初始值。

内存被释放回上游资源，即使未对某些被分配块调用 deallocate 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3120 | C++17 | release 可以不使得初始缓冲区可用，若提供它 | 要求这么做

参阅

deallocate
 解分配内存
(std::pmr::memory_resource 的公开成员函数)


std::pmr::monotonic_buffer_resource::upstream_resource

< cpp‎ | memory‎ | monotonic buffer resource
std::pmr::memory_resource * upstream_resource() const; | (C++17 起)

返回指向上游 memory_resource 的指针。该值与传递给此对象的构造函数的 upstream 参数相同。

参阅

(构造函数)
 构造一个 monotonic_buffer_resource
(公开成员函数)


std::pmr::monotonic_buffer_resource::~monotonic_buffer_resource

< cpp‎ | memory‎ | monotonic buffer resource
virtual ~monotonic_buffer_resource(); | (C++17 起)

销毁 monotonic_buffer_resource.

通过调用 this->release() 解分配此资源拥有的所有内存。

参阅

release
 释放所有分配的内存
(公开成员函数)


低层内存管理

< cpp‎ | memory

new 表达式是创建拥有动态存储期对象或对象数组的仅有方式，即它们拥有不受制于创建所它们在的作用域的生存期。 new 表达式通过调用分配函数获得存储。 delete 表达式销毁最终导出对象或通过 new 表达式创造的数组，然后调用解分配函数。默认分配函数和默认解分配函数，及与之关联的函数、类型及对象声明于头文件 <new> 。

定义于头文件 <new>
函数
operator newoperator new[]
 分配函数
(函数)
operator deleteoperator delete[]
 解分配函数
(函数)
get_new_handler
(C++11)
 获得当前的 new 处理函数
(函数)
set_new_handler
 注册一个 new 处理函数
(函数)
类
bad_alloc
 内存分配失败时抛出的异常
(类)
bad_array_new_length
(C++11)
 在分配有非法长度的数组时抛出的异常
(类)
nothrow_t
 用于选择不抛出分配函数的标签类型
(类)
align_val_t
(C++17)
 用于向带对齐分配及解分配函数传递对齐值的类型
(枚举)
destroying_delete_t
(C++20)
 用于鉴别 operator delete 的销毁删除重载的标签类型
(类)
类型
new_handler
 new 处理函数的函数指针类型
(typedef)
对象
nothrow
 用于选择不抛出分配函数的 nothrow_t 类型对象
(常量)


std::align_val_t

< cpp‎ | memory‎ | new
定义于头文件 <new> |
enum class align_val_t : std::size_t {}; | (C++17 起)

在将 new 表达式和 delete 表达式用于对齐要求大于 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 的对象时，该对齐要求作为 std::align_val_t 类型的参数传递给分配/解分配函数。

注解

对齐（以 alignof 取得者）拥有 std::size_t 类型，但采用 std::size_t 作为附加参数的布置形式分配和删除函数已经被使用了，故使用此类型以代替。

参阅

operator newoperator new[] | 分配函数 (函数)
operator deleteoperator delete[] | 解分配函数 (函数)


std::bad_alloc

< cpp‎ | memory‎ | new
定义于头文件 <new>
class bad_alloc;

std::bad_alloc 是分配函数作为异常抛出的对象类型，以报告存储分配失败。

cpp/error/exception

继承图

成员函数

(构造函数) | 构造新的 bad_alloc 对象 (公开成员函数)
operator= | 替换 bad_alloc 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::bad_alloc::bad_alloc

 | (1)
bad_alloc() throw(); |  | (C++11 前)
bad_alloc() noexcept; |  | (C++11 起)
 | (2)
bad_alloc( const bad_alloc& other ) throw(); |  | (C++11 前)
bad_alloc( const bad_alloc& other ) noexcept; |  | (C++11 起)

构造新的拥有实现定义的空终止字节字符串的 bad_alloc 对象，字符串能通过 what() 访问。

1) 默认构造函数。
2) 复制构造函数。若 *this 与 other 均拥有动态类型 std::bad_alloc 则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 要复制的另一异常对象

std::bad_alloc::operator=

bad_alloc& operator=( const bad_alloc& other ) throw(); | (C++11 前)
bad_alloc& operator=( const bad_alloc& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::bad_alloc 则赋值后 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 用以赋值的另一异常对象

返回值

*this

std::bad_alloc::what

virtual const char* what() const throw(); | (C++11 前)
virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

示例

#include <iostream>
#include <new>

int main()
{
    try {
        while (true) {
            new int[100000000ul];
        }
    } catch (const std::bad_alloc& e) {
        std::cout << "Allocation failed: " << e.what() << '\n';
    }
}

可能的输出：

Allocation failed: std::bad_alloc

参阅

operator newoperator new[]
 分配函数
(函数)


std::bad_array_new_length

< cpp‎ | memory‎ | new
定义于头文件 <new> |
class bad_array_new_length; | (C++11 起)

std::bad_array_new_length 是new 表达式作为异常抛出以报告非法数组长度的对象类型，若

1) 数组长度为负

2) 新数组的总大小将超过实现定义最大值

3) 初始化器子句的数量超出要初始化的元素数量

仅数组第一维可生成此异常；第一维外的维数是常量表达式，在编译时得到检查。

cpp/error/exception cpp/memory/new/bad alloc std-bad array new length-inheritance.svg

继承图

成员函数

(构造函数) | 构造新的 bad_array_new_length 对象 (公开成员函数)
operator= | 替换 bad_array_new_length 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::bad_array_new_length::bad_array_new_length

bad_array_new_length() noexcept; | (1) | (C++11 起)
bad_array_new_length( const bad_array_new_length& other ) noexcept; | (2) | (C++11 起)

构造新的拥有实现定义的空终止字节字符串的 bad_array_new_length 对象，字符串能通过 what() 访问。

1) 默认构造函数。
2) 复制构造函数。若 *this 与 other 均拥有动态类型 std::bad_array_new_length 则 std::strcmp (what(), other.what()) == 0 。

参数

other - 要复制的另一异常对象

std::bad_array_new_length::operator=

bad_array_new_length& operator=( const bad_array_new_length& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::bad_array_new_length 则赋值后 std::strcmp (what(), other.what()) == 0 。

参数

other - 用以赋值的另一异常对象

返回值

*this

std::bad_array_new_length::what

virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::bad_alloc

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

示例

应抛出 std::bad_array_new_length 的三种条件：

#include <iostream>
#include <new>
#include <climits>

int main()
{
    int negative = -1;
    int small = 1;
    int large = INT_MAX;
    try {
        new int[negative];           // 负大小： bad_array_new_length
        new int[small]{1,2,3};       // 过多初始化器： bad_array_new_length
        new int[large][1000000];     // 过大： bad_alloc 或 bad_array_new_length
    } catch(const std::bad_array_new_length &e) {
        std::cout << e.what() << '\n';
    } catch(const std::bad_alloc &e) {
        std::cout << e.what() << '\n';
    }
}

可能的输出：

std::bad_array_new_length

参阅

operator newoperator new[] | 分配函数 (函数)
bad_alloc | 内存分配失败时抛出的异常 (类)


std::destroying_delete_t, std::destroying_delete

< cpp‎ | memory‎ | new
定义于头文件 <new> |
struct destroying_delete_t { explicit destroying_delete_t() = default; }; | (C++20 起)
inline constexpr destroying_delete_t destroying_delete{}; | (C++20 起)

用于鉴别 operator delete 的销毁删除形式的标签类型。

参阅

operator deleteoperator delete[]
 解分配函数
(函数)


std::get_new_handler

< cpp‎ | memory‎ | new
定义于头文件 <new> |
std::new_handler get_new_handler() noexcept; | (C++11 起)

返回当前安装的 new 处理函数，它可以是空指针值。

此函数是线程安全的。先前对 std::set_new_handler 的调用同步于（见 std::memory_order ）对 std::get_new_handler 的后继调用。

参数

（无）

返回值

当前安装的 new 处理函数，它可以是空指针值。

参阅

operator newoperator new[] | 分配函数 (函数)
set_new_handler | 注册一个 new 处理函数 (函数)
new_handler | new 处理函数的函数指针类型 (typedef)


std::new_handler

< cpp‎ | memory‎ | new
定义于头文件 <new>
typedef void (*new_handler)();

std::new_handler 是函数指针类型（指向不接收参数并返回 void 的指针），它为函数 std::set_new_handler 与 std::get_new_handler 所用。

参阅

operator newoperator new[] | 分配函数 (函数)
set_new_handler | 注册一个 new 处理函数 (函数)
get_new_handler (C++11) | 获得当前的 new 处理函数 (函数)


std::nothrow

< cpp‎ | memory‎ | new
定义于头文件 <new>
extern const std::nothrow_t nothrow;

std::nothrow 是 std::nothrow_t 类型的常量，用于区分抛出与不抛出分配函数的重载。

示例

#include <iostream>
#include <new>

int main()
{
    try {
        while (true) {
            new int[100000000ul];   // 抛出重载
        }
    } catch (const std::bad_alloc& e) {
        std::cout << e.what() << '\n';
    }

    while (true) {
        int* p = new(std::nothrow) int[100000000ul]; // 不抛出重载
        if (p == nullptr) {
            std::cout << "Allocation returned nullptr\n";
            break;
        }
    }
}

输出：

std::bad_alloc
Allocation returned nullptr

参阅

nothrow_t | 用于选择不抛出分配函数的标签类型 (类)
operator newoperator new[] | 分配函数 (函数)


std::nothrow_t

< cpp‎ | memory‎ | new
定义于头文件 <new> |
struct nothrow_t {}; | (C++11 前)
struct nothrow_t { explicit nothrow_t() = default; }; | (C++11 起)

std::nothrow_t 是用于区分抛出与不抛出分配函数重载的空类类型。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2510 | C++11 | 默认构造函数为非 explicit ，能导致歧义 | 使之为 explicit

参阅

nothrow | 用于选择不抛出分配函数的 nothrow_t 类型对象 (常量)
operator newoperator new[] | 分配函数 (函数)


operator delete, operator delete[]

< cpp‎ | memory‎ | new
定义于头文件 <new>
可替换通常解分配函数
(1)
void operator delete ( void* ptr ) throw();
 (C++11 前)
void operator delete ( void* ptr ) noexcept;
 (C++11 起)
(2)
void operator delete[]( void* ptr ) throw();
 (C++11 前)
void operator delete[]( void* ptr ) noexcept;
 (C++11 起)
void operator delete ( void* ptr, std::align_val_t al ) noexcept;
 (3) (C++17 起)
void operator delete[]( void* ptr, std::align_val_t al ) noexcept;
 (4) (C++17 起)
void operator delete ( void* ptr, std::size_t sz ) noexcept;
 (5) (C++14 起)
void operator delete[]( void* ptr, std::size_t sz ) noexcept;
 (6) (C++14 起)
void operator delete ( void* ptr, std::size_t sz,
std::align_val_t al ) noexcept;
 (7) (C++17 起)
void operator delete[]( void* ptr, std::size_t sz,
std::align_val_t al ) noexcept;
 (8) (C++17 起)
可替换布置解分配函数
(9)
void operator delete ( void* ptr, const std::nothrow_t & tag ) throw();
 (C++11 前)
void operator delete ( void* ptr, const std::nothrow_t & tag ) noexcept;
 (C++11 起)
(10)
void operator delete[]( void* ptr, const std::nothrow_t & tag ) throw();
 (C++11 前)
void operator delete[]( void* ptr, const std::nothrow_t & tag ) noexcept;
 (C++11 起)
void operator delete ( void* ptr, std::align_val_t al,
const std::nothrow_t & tag ) noexcept;
 (11) (C++17 起)
void operator delete[]( void* ptr, std::align_val_t al,
const std::nothrow_t & tag ) noexcept;
 (12) (C++17 起)
不分配布置解分配函数
(13)
void operator delete ( void* ptr, void* place ) throw();
 (C++11 前)
void operator delete ( void* ptr, void* place ) noexcept;
 (C++11 起)
(14)
void operator delete[]( void* ptr, void* place ) throw();
 (C++11 前)
void operator delete[]( void* ptr, void* place ) noexcept;
 (C++11 起)
用户定义的布置解分配函数
void operator delete ( void* ptr, args... );
 (15)
void operator delete[]( void* ptr, args... );
 (16)
类特定通常解分配函数
void T::operator delete ( void* ptr );
 (17)
void T::operator delete[]( void* ptr );
 (18)
void T::operator delete ( void* ptr, std::align_val_t al );
 (19) (C++17 起)
void T::operator delete[]( void* ptr, std::align_val_t al );
 (20) (C++17 起)
void T::operator delete ( void* ptr, std::size_t sz );
 (21)
void T::operator delete[]( void* ptr, std::size_t sz );
 (22)
void T::operator delete ( void* ptr, std::size_t sz, std::align_val_t al );
 (23) (C++17 起)
void T::operator delete[]( void* ptr, std::size_t sz, std::align_val_t al );
 (24) (C++17 起)
类特定布置解分配函数
void T::operator delete ( void* ptr, args... );
 (25)
void T::operator delete[]( void* ptr, args... );
 (26)
类特定销毁解分配函数
void T::operator delete(T* ptr, std::destroying_delete_t);
 (27) (C++20 起)
void T::operator delete(T* ptr, std::destroying_delete_t,
std::align_val_t al);
 (28) (C++20 起)
void T::operator delete(T* ptr, std::destroying_delete_t, std::size_t sz);
 (29) (C++20 起)
void T::operator delete(T* ptr, std::destroying_delete_t,
std::size_t sz, std::align_val_t al);
 (30) (C++20 起)

解分配先前由匹配的 operator new 所分配的存储。这些解分配函数为 delete 表达式与 new 表达式所调用，以在析构（或构造失败）拥有动态存储期的对象后解分配内存。它们亦可用常规函数调用语法调用。

1) 为 delete 表达式所调用，以解分配先前为单对象分配的存储。此函数的标准库实现的行为未定义，除非 ptr 是空指针或是先前从 operator new (size_t) 或 operator new (size_t, std::nothrow_t ) 的标准库实现获得的指针。
2) 为 delete[] 表达式所调用，以解分配先前为对象数组分配的存储。此函数的标准库实现的行为未定义，除非 ptr 是空指针或是先前从 operator new [](size_t) 或 operator new [](size_t, std::nothrow_t ) 的标准库实现获得的指针。
3,4) 同 (1,2) ，除了若对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 才被调用
5,6) 若提供用户定义重载，则取代 (1-2) 得到调用，除了在删除不完整类型的对象、非类类型的数组和可平凡析构类类型的数组时，调用 (1-2) 还是 (5-6) 是未指定的。内存分配器可用给定的大小变得更高效。标准库实现等同于 (1-2) 。
7,8) 同 (5-6) ，除了若对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 才被调用
9) 若对象的构造函数抛出异常，则为不抛出的单对象 new 表达式所调用。标准库实现表现同 (1)
10) 若任何对象的构造函数抛出异常，则（在执行数组中已成功构造的所有对象的析构函数后）为不抛出的数组 new[] 表达式所调用。标准库实现表现同 (2)
11,12) 同 (9,10) ，除了若对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 才被调用
13) 若对象的构造函数抛出异常，则为标准单对象布置 new 表达式所调用。此函数的标准库实现不做任何事。
14) 若任何对象的构造函数抛出异常，则为布置 new[] 表达式的数组形式（在执行数组中已成功构造的所有对象的析构函数后）所调用。此函数的标准库实现不做任何事。
15) 若定义，则为拥有匹配签名的自定义单对象布置 new 表达式调用，若对象构造函数抛出异常。若定义类特定版本 (25) ，则类特定版本优先于 (9) 调用。若用户既不提供 (25) 又不提供 (15) ，则不调用解分配函数。
16) 若定义，则为拥有匹配签名的布置 new[] 表达式自定义数组形式（在执行数组中已成功构造的所有对象的析构函数后）调用，若任何对象的构造函数抛出异常。若定义类特定版本 (16) ，则类特定版本优先于 (10) 调用。若用户既不提供 (26) 又不提供 (16) ，则不调用解分配函数。
17) 若定义，则为通常单对象 delete 表达式调用，若在解分配一个 T 类型对象。
18) 若定义，则为通常数组 delete[] 表达式调用，若在解分配 T 类型对象的数组。
19,20) 若定义，则优先于 (17,18) 调用，若对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 。
21) 若定义，且若未定义 (17) ，则为通常单对象 delete 表达式调用，若在解分配一个 T 类型对象。
22) 若定义，且若未定义 (18) ，则为通常数组 delete[] 表达式调用，若在解分配 T 类型对象的数组。
23,24) 若定义，且若未定义 (19,20) ，则优先于无对齐成员调用，若对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__.
25) 若定义，则为拥有匹配签名的自定义单对象布置 new 表达式调用，若对象构造函数抛出异常。若不提供此函数，亦不提供匹配的 (15) ，则不调用解分配函数。
26) 若定义，则为拥有匹配签名的自定义布置 new[] 表达式的数组形式（在执行数组中已成功构造的所有对象的析构函数后）调用，若任何对象的构造函数抛出异常。若不提供此函数，亦不提供匹配的 (16) ，则不调用析构函数。
27-30) 若定义，则 delete 表达式在调用 operator delete 前不对 *p 执行析构函数。取而代之地，变为由此用户定义的 operator delete 负责直接调用析构函数，例如用 p->~T(); 。

通常（非布置）解分配函数的具对齐和不具对齐重载之间的重载决议准确细节见 delete 表达式。

 (C++17 起)

所有情况下，若 ptr 是空指针，则标准库解分配函数不做任何事。若传递给标准库解分配函数的指针不是从对应的标准库分配函数取得者，则行为未定义。

在标准库解分配函数返回后，所有引用到被解分配存储的任何部分的指针都变为非法。

通过已因此方式变为非法的指针解引用，以及将它传递给解分配函数（双重 delete ）是未定义行为。任何其他使用是实现定义的。

参数

ptr | - | 指向要解分配的内存块的指针或空指针
sz | - | 传递给匹配的分配函数的 size
place | - | 用作匹配的布置 new 中布置参数的指针
tag | - | 匹配不抛出 operator new 所用标签的重载消歧义标签
al | - | 被分配的对象或数组元素的对齐
args | - | 匹配布置分配函数的任意参数（可包含 std::size_t 与 std::align_val_t ）

返回值

（无）

异常

15-30) 容许用户定义的解分配函数抛异常。 | (C++11 前)
15-30) 所有解分配函数均为 noexcept(true) ，除非在声明中另外说明。若解分配函数以抛异常终止，则行为未定义，即使以 noexcept(false) 声明它。 | (C++11 起)

全局替换

可替换解分配函数 (1-12) 在每个翻译单元隐式声明，即使不包含 <new> 头文件。这些函数是可替换的：定义于程序任何位置、任何头文件的用户提供的拥有相同签名的非成员函数，会为整个程序替换对应的隐式版本。其声明不必可见。

若程序中提供多于一个替换，或若替换声明有 inline 说明符，则程序非良构，不要求诊断。若替换声明于异于全局命名空间的命名空间，或若它定义为在全局作用域的 static 非成员函数，则程序为非良构。

nothrow 版本 (9,10) 的标准库实现直接调用抛出版本 (1,2) 。具大小解分配函数 (5-8) 的标准库实现直接调用对应的不具大小解分配函数 (1-4) 。不具大小的抛出数组形式 (2,4) 的标准库实现直接调用对应的单对象形式 (1,3) 。

故而，替换抛出的单对象解分配函数 (1,3) 足以处理所有解分配。

 (C++11 起)
#include <cstdio>
#include <cstdlib>
#include <new>
// 最小函数集的替换：
void* operator new(std::size_t sz) // 无 inline ，由 [replacement.functions]/3 要求
{
    std::printf("global op new called, size = %zu\n", sz);
    if (sz == 0)
        ++sz; // 避免可能在成功时返回 nullptr 的 std::malloc(0)

    if (void *ptr = std::malloc(sz))
        return ptr;

    throw std::bad_alloc{}; // 由 [new.delete.single]/3 要求
}
void operator delete(void* ptr) noexcept
{
    std::puts("global op delete called");
    std::free(ptr);
}
int main()
{
    int* p1 = new int;
    delete p1;

    int* p2 = new int[10]; // C++11 中保证调用替换
    delete[] p2;
}

可能的输出：

global op new called, size = 4
global op delete called
global op new called, size = 40
global op delete called

operator delete 与 operator delete[] 带额外用户定义参数的重载（“布置形式”， (15,16) ）可照常声明于全局作用域，而且为匹配的布置形式 new 表达式 所调用，若正在分配的对象的构造函数抛出异常。

operator delete 的标准库布置形式 (13,14) 不能替换，而且仅若布置 new 表达式不使用 ::new 语法才能被自定义，通过提供拥有匹配签名的类特定布置 delete (25,26) ： void T::operator delete(void*, void*) 或 void T::operator delete[](void*, void*) 。

类特定重载

解分配函数 (17-24) 可定义为类的静态成员函数。若提供这些解分配函数，则它们为 delete 表达式在删除此类的对象 (17,19,21) 和数组 (18,20,22) 时调用，除非 delete 表达式使用跳过类作用域查找的形式 ::delete 。关键词 static 对这些函数声明是可选的：不管是否使用该关键词，解分配函数都始终是静态成员函数。

delete 表达式从类作用域开始查找适当的解分配函数名（数组形式在数组元素类的作用域查找），然后若找不到成员再继而照常寻找全局作用域。注意，同每个名称查找规则，任何声明于类作用域的解分配函数隐藏所有全局解分配函数。

若正在删除的对象的静态类型异于其动态类型（例如通过指向基类的指针删除一个多态对象），且若静态类型中的析构函数是虚的，则 delete 的单对象形式从其虚析构函数的最终覆盖者的定义点开始查找解分配函数的名称。无关乎运行时会执行哪个析构函数，为了能够编译， operator delete 的静态可见版本必须可访问。其他情况下，当通过指向基类的指针删除数组，或通过带非虚析构函数的指针删除时，行为未定义。

若未提供单参数重载 (17,18) ，但提供接收 std::size_t 为第二参数的具大小重载 (21,22) ，则正常解分配调用具大小形式，且 C++ 运行时传递要被解分配的对象大小为第二参数。若定义两种形式，则调用不具大小的版本。

#include <iostream>
// 具大小的类特定解分配函数
struct X {
    static void operator delete(void* ptr, std::size_t sz)
    {
        std::cout << "custom delete for size " << sz << '\n';
        ::operator delete(ptr);
    }
    static void operator delete[](void* ptr, std::size_t sz)
    {
        std::cout << "custom delete for size " << sz << '\n';
        ::operator delete(ptr);
    }
};
int main() {
     X* p1 = new X;
     delete p1;
     X* p2 = new X[10];
     delete[] p2;
}

可能的输出：

custom delete for size 1
custom delete for size 18

带额外用户定义参数的 operator delete 与 operator delete[] （“布置形式”， (25,26) ）亦可定义为类成员。在失败的布置 new 表达式查找将调用的对应布置 delete 函数时，它首次从类作用域开始，在全局作用域之前查找，并且查找匹配布置 new 签名的函数：

#include <stdexcept>
#include <iostream>
struct X {
    X() { throw std::runtime_error(""); }
    // 自定义布置 new
    static void* operator new(std::size_t sz, bool b) {
        std::cout << "custom placement new called, b = " << b << '\n';
        return ::operator new(sz);
    }
    // 自定义布置 delete
    static void operator delete(void* ptr, bool b)
    {
        std::cout << "custom placement delete called, b = " << b << '\n';
        ::operator delete(ptr);
    }
};
int main() {
   try {
     X* p1 = new (true) X;
   } catch(const std::exception&) { }
}

输出：

custom placement new called, b = 1
custom placement delete called, b = 1

若类级别的 operator delete 是模板函数，则它必须拥有 void 返回类型，首参数 void* ，而且必须拥有二个或更多参数。换言之，只有布置形式能是模板。模板 operator delete 的特化为模板参数推导所选择。

注解

在多态类上调用类特定的 T::operator delete 是仅有的通过动态派发调用静态成员函数的情况。

要求下列函数是线程安全的：

  • operator new 及 operator delete 的库版本
  • 全局 operator new 与 operator delete 的用户替换版本
  • std::calloc 、 std::malloc 、 std::realloc 、 std::aligned_alloc (C++17 起) 、 std::free

对这些分配或解分配特定存储单元的函数调用以单独全序出现，并且在此顺序中，每个解分配调用先发生于下个分配（若存在）。

 (C++11 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1438 | C++98 | 任何非法指针值的使用均为未定义行为 | 只有间接和解分配是
LWG 2458 | C++14 | 曾指定了接受 (void*,size_t,const nothrow_t&) 的重载，但它无法被调用 | 移除虚假重载

参阅

operator newoperator new[] | 分配函数 (函数)
return_temporary_buffer (C++17 中弃用)(C++20 中移除) | 释放未初始化存储 (函数模板)
free | 解分配之前分配的内存 (函数)


operator new, operator new[]

< cpp‎ | memory‎ | new
定义于头文件 <new>
可替换分配函数

[[nodiscard]]

 (C++20 起)
void* operator new ( std::size_t count );
 (1)
void* operator new[]( std::size_t count );
 (2)
void* operator new ( std::size_t count, std::align_val_t al);
 (3) (C++17 起)
void* operator new[]( std::size_t count, std::align_val_t al);
 (4) (C++17 起)
可替换不抛出分配函数

noexcept

 (C++11 起)

[[nodiscard]]

 (C++20 起)
void* operator new ( std::size_t count, const std::nothrow_t & tag);
 (5)
void* operator new[]( std::size_t count, const std::nothrow_t & tag);
 (6)
void* operator new ( std::size_t count,
std::align_val_t al, const std::nothrow_t &);
 (7) (C++17 起)
void* operator new[]( std::size_t count,
std::align_val_t al, const std::nothrow_t &);
 (8) (C++17 起)
不分配布置分配函数

noexcept

 (C++11 起)

[[nodiscard]]

 (C++20 起)
void* operator new ( std::size_t count, void* ptr );
 (9)
void* operator new[]( std::size_t count, void* ptr );
 (10)
用户定义布置分配函数
void* operator new ( std::size_t count, user-defined-args... );
 (11)
void* operator new[]( std::size_t count, user-defined-args... );
 (12)
void* operator new ( std::size_t count,
std::align_val_t al, user-defined-args... );
 (13) (C++17 起)
void* operator new[]( std::size_t count,
std::align_val_t al, user-defined-args... );
 (14) (C++17 起)
类特定分配函数
void* T::operator new ( std::size_t count );
 (15)
void* T::operator new[]( std::size_t count );
 (16)
void* T::operator new ( std::size_t count, std::align_val_t al );
 (17) (C++17 起)
void* T::operator new[]( std::size_t count, std::align_val_t al );
 (18) (C++17 起)
类特定布置分配函数
void* T::operator new ( std::size_t count, user-defined-args... );
 (19)
void* T::operator new[]( std::size_t count, user-defined-args... );
 (20)
void* T::operator new ( std::size_t count,
std::align_val_t al, user-defined-args... );
 (21) (C++17 起)
void* T::operator new[]( std::size_t count,
std::align_val_t al, user-defined-args... );
 (22) (C++17 起)

分配请求数量的字节。这些分配函数为 new 表达式所调用，以分配将被初始化的对象所在的内存。亦可用常规函数调用语法调用它们。

1) 为非数组 new 表达式所调用，以分配为单个对象请求的存储。标准库实现从自由存储分配 count 字节。失败情况下，标准库实现调用 std::get_new_handler 所返回的函数指针，并重复尝试分配，直到 new 处理函数不返回或成为空指针，在该时刻抛出 std::bad_alloc 。要求此函数返回指向拥有请求大小的对象的适当对齐的指针。
2) 为 new[] 表达式的数组形式所调用，以分配为数组请求的所有存储（包含可能的 new 表达式开销）。标准库实现调用版本 (1)
3) 为非数组 new 表达式调用，以分配对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 的单个对象所要求的存储
4) 为 new[] 表达式的数组形式调用，以分配对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 的对象数组要求的所有存储
5) 为不抛出非数组 new 表达式所调用。标准库实现调用版本 (1) 并在失败时不传播异常而抛出空指针。
6) 为 new[] 表达式的不抛出数组形式所调用。标准库实现调用版本 (2) 并在失败时不传播异常而抛出空指针。
7) 在对象对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 时为不抛出非数组 new 表达式所调用。标准库实现调用版本 (3) 并在失败时不传播异常而抛出空指针。
8) 在数组元素的对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 时为 new[] 表达式的不抛出数组形式所调用。标准库实现调用版本 (4) 并在失败时不传播异常而抛出空指针。
9) 为标准单对象布置 new 表达式所调用，标准库实现不进行任何动作并返回不修改的 ptr 。若通过布置 new 表达式调用此函数而 ptr 为空指针则行为未定义。
10) 为标准数组形式布置 new 表达式所调用。标准库实现不进行任何动作并返回不修改的 ptr 。若通过布置 new 表达式调用此函数而 ptr 为空指针则行为未定义。
11) 若定义，则为拥有匹配签名的自定义单对象布置 new 表达式所调用。若定义类特定版本 (19) ，则优先于 (11) 调用类特定版本。若用户既不提供 (11) 又不提供 (19) ，则布置 new 表达式为病式。
12) 若定义，则为拥有匹配签名的自定义数组形式布置 new 表达式所调用。若定义类特定版本 (20) ，则优先于 (12) 调用类特定版本。若用户既不提供 (12) 又不提供 (20) ，则布置 new 表达式为病式。
13) 若定义，则为拥有匹配签名的自定义单对象布置 new 表达式所调用，若对象的对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 。若定义类特定版本（ (15) 或 (17) ），则调用之。若既不提供类特定版本又不提供具对齐布置形式（此形式），则替而查找无对齐布置形式 (11) 。
14) 若定义，则为拥有匹配签名的自定义数组形式布置 new 表达式所调用，若元素的对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 。若定义类特定版本（(16) 或 (18) ），则调用之。若既不提供类特定版本又不提供具对齐布置形式（此形式），则替而查找无对齐布置形式 (12) 。
15) 若定义，则为通常的单对象 new 表达式所调用，若在分配 T 类型对象。
16) 若定义，则为通常的数组 new[] 表达式所调用，若在分配 T 类型对象的数组。
17) 若定义，则为通常的单对象 new 表达式所调用，若在分配 T 类型对象，且其对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 。若不提供此重载，但提供了无对齐成员形式 (15) ，则调用无对齐成员重载。
18) 若定义，通常的数组 new[] 表达式所调用，若在分配 T 类型的对象数组，且其对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 。若不提供此重载，但提供了无对齐成员形式 (16) ，则调用无对齐成员重载。
19) 若定义，则为拥有匹配签名的自定义单对象布置 new 表达式所调用，若在分配 T 类型对象。
20) 若定义，则为拥有匹配签名的自定义数组形式布置 new 表达式所调用，若在分配 T 类型对象的数组。
21) 若定义，则为拥有匹配签名的自定义单对象布置 new 表达式所调用，若在分配 T 类型对象，且其对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 。若不提供此重载，但提供了无对齐成员形式 (19) ，则调用无对齐成员重载。
22) 若定义，则为拥有匹配签名的自定义数组形式布置 new 表达式所调用，若在分配 T 类型的对象数组，且其对齐要求超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 。若不提供此重载，但提供了无对齐成员形式 (20) ，则调用无对齐成员重载。

参数

count | - | 要分配的字节数
ptr | - | 指向要初始化的对象所在的内存区域的指针
tag | - | 用于选择不抛出重载的消歧义标签
al | - | 使用的对齐。若此非有效对齐值，则行为未定义

返回值

1-4) 非空指针，指向拥有至少 size 大小的适当对齐的内存
5-8) 非空指针，指向拥有至少 size 大小的适当对齐的内存，或在失败时为空指针
9-10) ptr
11-22) 若函数在分配失败时不返回则同 (1-4) ，否则同 (5-8)

异常

1-4) 在分配内存失败时抛出 std::bad_alloc 或任何从 std::bad_alloc 派生的异常 (C++11 起)
11-22) 若函数在分配失败时不返回则同 (1-4) ，否则同 (5-8)

全局替换

版本 (1-4) 在每个翻译单元隐式声明，即使不包含 <new> 头文件。版本 (1-8) 是可替换的：定义于程序任何位置，在任何源文件的用户提供的拥有相同签名的非成员函数，会替换默认版本。其声明不必可见。

若程序中为任何可替换分配函数提供多于一个替换版本，或若替换声明带 inline 说明符，则程序非良构，不要求诊断。若替换定义于异于全局命名空间的命名空间中，或它定义为在全局作用域的 static 函数，则程序为非良构。

nothrow 版本的标准库实现 (5-8) 直接调用对应的抛出版本 (1-4) 。抛出的数组版本的标准库实现 (2,4) 直接调用对应的单对象版本 (1,3) 。故而，替换抛出单对象分配函数足以处理所有分配。

 (C++11 起)
#include <cstdio>
#include <cstdlib>
#include <new>
// 最小函数集的替换：
void* operator new(std::size_t sz) // 无 inline ，由 [replacement.functions]/3 要求
{
    std::printf("global op new called, size = %zu\n", sz);
    if (sz == 0)
        ++sz; // 避免可能在成功时返回 nullptr 的 std::malloc(0)

    if (void *ptr = std::malloc(sz))
        return ptr;

    throw std::bad_alloc{}; // 由 [new.delete.single]/3 要求
}
void operator delete(void* ptr) noexcept
{
    std::puts("global op delete called");
    std::free(ptr);
}
int main()
{
    int* p1 = new int;
    delete p1;

    int* p2 = new int[10]; // C++11 中保证调用替换
    delete[] p2;
}

可能的输出：

global op new called, size = 4
global op delete called
global op new called, size = 40
global op delete called

operator new 与 operator new[] 带额外用户定义参数的重载（“布置形式”，版本 (11-14) ）可以照常声明于全局作用域，而且为匹配的 new 表达式的布置形式所调用。

标准库的 operator new 的不分配布置形式 (9-10) 不能被替换，而且只若布置 new 表达式不使用 ::new 语法才能自定义，通过提供类特定的带匹配签名的布置 new (19,20) ： void* T::operator new(size_t, void*) 或 void* T::operator new[](size_t, void*) 。

布置形式 void* operator new(std::size_t, std::size_t) 不被允许，因为对应的解分配函数的匹配签名 void operator delete(void*, std::size_t) 是通常（非布置）的解分配函数。

 (C++14 起)

类特定重载

单对象和数组分配函数都可以定义为类的公开静态成员函数（版本 (15-18) 。若定义，则 new 表达式调用这些函数，以分配此类单个对象或数组的内存，除非 new 表达式使用 ::new 形式，这跳过类作用域查找。关键词 static 对这些函数可选：不管是否使用，分配函数都是静态成员函数。

new 表达式首先在类作用域中查找适当的函数名，然后在全局作用域查找。注意，同每个名称查找规则，就试图分配此类对象的 new 表达式而言，任何声明于类作用域的分配函数隐藏所有全局分配函数。

在分配对齐超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 的对象或对象数组时，进行二次重载决议：首先，针对具对齐的函数签名，然后，针对无对齐的函数签名。这表示若拥有扩展对齐的类拥有无对齐量的类特定分配函数，则将被调用者是该函数，而非全局的具对齐分配函数。这是有意的：期待类成员对如何处理该类的理解是最好的。

 (C++17 起)
#include <iostream>
// 类特定分配函数
struct X {
    static void* operator new(std::size_t sz)
    {
        std::cout << "custom new for size " << sz << '\n';
        return ::operator new(sz);
    }
    static void* operator new[](std::size_t sz)
    {
        std::cout << "custom new[] for size " << sz << '\n';
        return ::operator new(sz);
    }
};
int main() {
     X* p1 = new X;
     delete p1;
     X* p2 = new X[10];
     delete[] p2;
}

可能的输出：

custom new for size 1
custom new[] for size 10

operator new 与 operator new[] 带额外用户定义参数（“布置形式”）的重载，亦可定义为类成员 (19-22) 。在拥有匹配签名的布置 new 表达式查找要调用的对应分配函数时，查找在检验全局作用域前，从类作用域开始，而若提供了类特定的布置 new 则调用它。

在分配对齐超出 __STDCPP_DEFAULT_NEW_ALIGNMENT__ 的对象或对象数组时，布置形式的重载决议如常规形式一样执行二次：首先，对有对齐量的函数签名，然后，对无对齐量的函数签名。

 (C++17 起)
#include <stdexcept>
#include <iostream>
struct X {
    X() { throw std::runtime_error(""); }
    // 自定义布置 new
    static void* operator new(std::size_t sz, bool b) {
        std::cout << "custom placement new called, b = " << b << '\n';
        return ::operator new(sz);
    }
    // 自定义布置 delete
    static void operator delete(void* ptr, bool b)
    {
        std::cout << "custom placement delete called, b = " << b << '\n';
        ::operator delete(ptr);
    }
};
int main() {
   try {
     X* p1 = new (true) X;
   } catch(const std::exception&) { }
}

输出：

custom placement new called, b = 1
custom placement delete called, b = 1

若类级别的 operator new 是模板函数，则它必须拥有返回类型 void* ，第一参数类型 std::size_t ，且它必须拥有二个或更多参数。换言之，仅布置形式能是模板。

注解

尽管不分配布置 new (9,10) 不能被替换，亦可在上面描述的类作用域定义拥有相同签名的函数。而且，像是布置 new 但接受非 void 指针类型作为第二参数的全局重载是的受到允许的，故意图确保调用真的布置 new 的代码（例如 std::allocator::construct ）必须使用 ::new 并将指针转型到 void* 。

要求下列函数是线程安全的：

  • operator new 及 operator delete 的库版本
  • 全局 operator new 与 operator delete 的用户替换版本
  • std::calloc 、 std::malloc 、 std::realloc 、 std::aligned_alloc (C++17 起) 、 std::free

对这些分配或解分配特定存储单元的函数调用以单独全序出现，并且在此顺序中，每个解分配调用先发生于下个分配（若存在）。

 (C++11 起)

operator new 的库版本是否产生任何对 std::malloc 或 std::aligned_alloc (C++17 起) 的调用是未指定的。

对于加载大文件，经由如 POSIX 上的 mmap 或 Windows 上的 CreateFileMapping(A/W) 伴随 MapViewOfFile 的操作系统特定函数进行文件映射，比为文件读取分配缓冲区更适合。

示例

本节未完成
原因：暂无示例

参阅

operator deleteoperator delete[] | 解分配函数 (函数)
get_new_handler (C++11) | 获得当前的 new 处理函数 (函数)
set_new_handler | 注册一个 new 处理函数 (函数)
get_temporary_buffer (C++17 中弃用)(C++20 中移除) | 获得未初始化存储 (函数模板)
malloc | 分配内存 (函数)
aligned_alloc (C++17) | 分配对齐的内存 (函数)

引用

  • C++11 标准（ISO/IEC 14882:2011）：
  • 18.6 Dynamic memory management [support.dynamic]


std::set_new_handler

< cpp‎ | memory‎ | new
定义于头文件 <new> |
std::new_handler set_new_handler( std::new_handler new_p ) throw(); | (C++11 前)
std::new_handler set_new_handler( std::new_handler new_p ) noexcept; | (C++11 起)

令 new_p 成为新的全局 new 处理函数并返回先前安装的 new 处理函数。

new 处理函数是为分配函数在凡是内存分配尝试失败时调用的函数。其目的是三件事之一：

1) 令更多内存可用
2) 终止程序（例如通过调用 std::terminate
3) 抛出 std::bad_alloc 或自 std::bad_alloc 导出的类型的异常。

默认实现抛 std::bad_alloc 。用户可以安装自己的 new 处理函数，并可以提供异于默认者的行为。

若 new 处理函数返回，则分配函数重复先前失败的分配，并若分配再次失败则调用 new 处理函数。为终止循环， new 处理函数可调用 std::set_new_handler(nullptr) ：若在失败的分配尝试后，分配函数发现 std::get_new_handler 返回空指针值，则它会试图抛出 std::bad_alloc 。

在程序启动时， new 处理函数是空指针。

此函数是线程安全的。每个对 std::set_new_handler 的调用同步于（见 std::memory_order ）后继的 std::set_new_handler 和 std::get_new_handler 调用。

 (C++11 起)

参数

new_p - std::new_handler 类型的指向函数指针，或空指针

返回值

先前安装的 new 处理函数，或若无安装者则返回空指针。

示例

#include <iostream>
#include <new>

void handler()
{
    std::cout << "Memory allocation failed, terminating\n";
    std::set_new_handler(nullptr);
}

int main()
{
    std::set_new_handler(handler);
    try {
        while (true) {
            new int[100000000ul];
        }
    } catch (const std::bad_alloc& e) {
        std::cout << e.what() << '\n';
    }
}

输出：

Memory allocation failed, terminating
std::bad_alloc

参阅

operator newoperator new[] | 分配函数 (函数)
get_new_handler (C++11) | 获得当前的 new 处理函数 (函数)
new_handler | new 处理函数的函数指针类型 (typedef)
bad_alloc | 内存分配失败时抛出的异常 (类)


std::pmr::new_delete_resource

< cpp‎ | memory
定义于头文件 <memory_resource> |
std::pmr::memory_resource * new_delete_resource() noexcept; | (C++17 起)

返回指向使用全局 operator new 与 operator delete 分配内存的 memory_resource 的指针。

返回值

返回指针 p ，指向导出自 std::pmr::memory_resource 类型的静态存储期对象，它拥有下列属性：

  • 其 allocate() 函数用 ::operator new 分配内存；
  • 其 deallocate() 函数用 ::operator delete 解分配内存；
  • 对于任何 memory_resource r ， p->is_equal(r) 返回 &r == p.

每次调用此函数时返回相同值。


std::pmr::null_memory_resource

< cpp‎ | memory
定义于头文件 <memory_resource> |
std::pmr::memory_resource * null_memory_resource() noexcept; | (C++17 起)

返回指向不进行任何分配的 memory_resource 的指针。

返回值

返回指针 p ，指向导出自 std::pmr::memory_resource 类型的静态存储期对象，它拥有下列属性：

  • 其 allocate() 函数始终抛出 std::bad_alloc ；
  • 其 deallocate() 函数无效果；
  • 对于任何 memory_resource r ， p->is_equal(r) 返回 &r == p 。

每次调用此函数都返回相同值。


std::out_ptr_t

< cpp‎ | memory
定义于头文件 <memory> |
template< class Smart, class Pointer, class... Args > class out_ptr_t; | (C++23 起)

out_ptr_t 用于对通过 Pointer* （通常为某对象类型 T 的 T** ）或 void** 参数输出其结果的外来函数，适配智能指针之类的类型。

out_ptr_t 在构造时捕获额外的实参，为前述的这种外来函数写入的结果提供存储，而最终在销毁时以该结果和捕获的实参重设适配的 Smart 对象。

out_ptr_t 表现如同它拥有下列非静态数据成员：

  • 一个 Smart& 引用，在构造时绑定到被适配的对象，
  • 对 Args... 中的每个 T 有一个 T 类型成员，它是在构造时捕获并在析构时用于重设的实参，以及
  • 适合在其内存储 Pointer 以及提供 void* 对象的成员子对象，其中 Pointer 或 void* 对象通常会暴露给用于重初始化的外来函数。

用户能通过在 Args... 中分别指定对象类型或引用类型，控制每个参数是按复制还是按引用捕获。

模板形参

Smart | - | 要适配的对象（常为智能指针）的类型
Pointer | - | 外来函数写入其结果所用的对象（常为裸指针）的类型
Args... | - | 用于重设适配的对象的捕获实参的类型
类型要求
- Pointer 必须满足可空指针 (NullablePointer) 的要求。
- 若 Smart 为 std::shared_ptr 特化且 sizeof...(Args) == 0 则程序非良构。

特化

不同于标准库中的大多数类模板，依赖于至少一个程序定义类型的 out_ptr_t 程序定义特化不需要符合对主模板的要求。

此许可允许程序定义特化将存储于非标准智能指针内的裸指针暴露给外来函数。

成员函数

(构造函数) (C++23) | 构造 out_ptr_t (公开成员函数)
operator= [被删除](C++23) | out_ptr_t 不可赋值 (公开成员函数)
(析构函数) (C++23) | 重设适配的智能指针 (公开成员函数)
operator Pointer*operator void** (C++23) | 转换 out_ptr_t 为用于输出的存储的地址 (公开成员函数)

非成员函数

out_ptr
(C++23)
 以关联的智能指针和重设参数创建 out_ptr_t
(函数模板)

注解

out_ptr_t 期待外来函数不使用被指向的 Pointer 的值并且只重新初始化它。不使用智能指针在适配前的值。

out_ptr_t 的典型用法是由 std::out_ptr 创建其临时对象，这会立即重设智能指针。例如，给定设置器函数和智能指针，分别以 int foreign_setter(T**); 与 std::unique_ptr <T, D> up; 声明，

if (int ec = foreign_setter(std::out_ptr(up)) {
    return ec;
}

粗略地等价于

T *raw_p{};
int ec = foreign_setter(&raw_p);
up.reset(raw_p);
if (ec != 0) {
    return ec;
}

不推荐创建拥有自动存储期以外的存储期的 out_ptr_t 对象，因为这种代码较可能产生悬垂引用并在析构时导致未定义行为。

out_ptr_t 禁止会不经指定删除器就重设 std::shared_ptr 的用法，因为之后它会调用 std::shared_ptr::reset 并替换定制的删除器。

捕获的参数常被打包到 std::tuple <Args...> 中。实现可能用不同的机制提供他们需要保有的 Pointer 或 void* 对象。

示例

本节未完成
原因：暂无示例

参阅

inout_ptr_t (C++23) | 与外来指针设置器交互，从智能指针获得初始指针值，并在析构时重设它 (类模板)
unique_ptr (C++11) | 拥有独有对象所有权语义的智能指针 (类模板)
shared_ptr (C++11) | 拥有共享对象所有权语义的智能指针 (类模板)


std::out_ptr_t<Smart,Pointer,Args...>::operator Pointer*, std::out_ptr_t<Smart,Pointer,Args...>::operator void**

< cpp‎ | memory‎ | out ptr t
operator Pointer*() const noexcept; | (1) | (C++23 起)
operator void**() const noexcept; | (2) | (C++23 起)

暴露 Pointer 或 void* 对象的地址给一般会重初始化它的外来函数。

1) 转换 *this 为存储的 Pointer 对象的地址。
2) 转换 *this 为 void* 对象的地址。此转换函数仅若 Pointer 与 void* 不同才参与重载决议，而若 Pointer 不是指针类型则程序非良构。
void* 对象的初值等于存储的 Pointer 对象的值转换到 void* ，而任何对它的修改影响用于析构函数的 Pointer 值。在 *this 的生存期外访问该 void* 拥有未定义行为。

一旦在一个 out_ptr_t 对象上调用了此二转换函数之一，则不应当调用另一个，否则行为未定义。

参数

（无）

返回值

1) 存储的 Pointer 对象的地址。
2) 满足前述要求的 void* 对象的地址。

注解

若返回值所指向的对象未被写入，则它等于 nullptr 。

常见实现上，每个作为指针类型的 Pointer 对象表示均与 void* 的兼容，从而这些实现常在 Pointer 对象的存储内存储该 void* 对象，不需要额外存储：

  • 若实现启用基于类型的别名分析（依赖严格别名化规则），则可以使用正确对齐的 std::byte[sizeof(void*)] 成员子对象，而两个转换函数都返回在该数组内隐式创建的对象的地址。
  • 否则，可将 Pointer 成员子对象用于两个转换函数，而 (2) 可以直接返回 reinterpret_cast 成 void** 的其地址。

若 Pointer 是对象表示与 void* 的不兼容的指针类型，则可能需要额外的 bool 标志记录是否调用了 (1) （或 (2) ）。

示例

本节未完成
原因：暂无示例


std::out_ptr

< cpp‎ | memory‎ | out ptr t
定义于头文件 <memory> |
template< class Pointer = void, class Smart, class... Args > auto out_ptr( Smart& s, Args&&... args ); | (C++23 起)

返回拥有被推导模板实参的 out_ptr_t ，按引用绑定重设用的实参。

若返回值（见后述）的构造非良构则程序非良构。

参数

s | - | 要适配的对象（常为智能指针）
args... | - | 要捕获的用于重设的实参

返回值

std::out_ptr_t<Smart, P, Args&&>(s, std::forward <Args>(args)...) ，其中 P 为

  • Pointer ，若 Pointer 与 void 不同，
  • 否则为 Smart::pointer ，若它合法并指代类型，
  • 否则为 Smart::element_type* ，若 Smart::element_type 合法并指代类型，
  • 否则为 std::pointer_traits <Smart>::element_type* 。

注解

用户可对模板形参 Pointer 指定模板实参，以与接收 Pointer* 的外来函数交互。

由于所有实参都按引用捕获，返回的 out_ptr_t 应为在含有外来函数调用的全表达式结尾销毁的临时对象，以避免悬垂引用。

示例

本节未完成
原因：暂无示例

参阅

inout_ptr (C++23) | 以关联的智能指针和重设参数创建 inout_ptr_t (函数模板)
make_uniquemake_unique_for_overwrite (C++14)(C++20) | 创建管理一个新对象的独占指针 (函数模板)
make_sharedmake_shared_for_overwrite (C++20) | 创建管理一个新对象的共享指针 (函数模板)


std::out_ptr_t<Smart,Pointer,Args...>::out_ptr_t

< cpp‎ | memory‎ | out ptr t
explicit out_ptr_t( Smart &sp, Args... args ); | (1) | (C++23 起)
out_ptr_t( const out_ptr_t& ) = delete; | (2) | (C++23 起)
1) 创建 out_ptr_t 。如同将 sp 绑定到 Smart& 成员一般适配它，如同用 std::forward <T>(t) 初始化对应的 Args... 中类型 T 的成员一般捕获 args... 中的实参 t ，然后值初始化存储的 Pointer 。
2) 复制构造函数被显示删除。 out_ptr_t 既不可复制又不可移动。

参数

sp | - | 要适配的对象（常为智能指针）
args... | - | 要捕获的用于重设的实参

返回值

（无）

异常

可能抛出实现定义的异常。

注解

构造后，任一转换函数的返回值所指向的 Pointer 或 void* 对象等于 nullptr 。

args... 中的每个参数若拥有对象类型则被移动到创建的 out_ptr_t 中，而若拥有引用类型则保持原状转移到创建的 out_ptr_t 中。

允许 out_ptr_t 抛出异常。例如当 sp 为 std::shared_ptr 时，新的控制块的分配可以在构造函数而非析构函数内进行。

示例

本节未完成
原因：暂无示例


std::out_ptr_t<Smart,Pointer,Args...>::~out_ptr_t

< cpp‎ | memory‎ | out ptr t
~out_ptr_t(); | (C++23 起)

以修改的 Pointer 对象（或若调用了 operator void**() 则为 void* 对象）的值捕获的实参重设适配的 Smart 对象。

令

  • s 代表适配的 Smart 对象，
  • args... 代表捕获的实参，
  • p 代表存储的 Pointer 的值，或若调用了 operator void** 则为 static_cast<Pointer>(*operator void**()) ，
  • SP 为
    • Smart::pointer ，若它合法并代表类型，否则为
    • Smart::element_type* ，若 Smart::element_type 并代表类型，否则为
    • std::pointer_traits <Smart>::element_type* ，若 std::pointer_traits <Smart>::element_type 合法并代表类型，否则为
    • Pointer 。

若 s.reset(static_cast<SP>(p), std::forward <Args>(args)...) 为良构，则析构函数进行

if (p) s.reset(static_cast<SP>(p), std::forward <Args>(args)...); ，

否则，若 std::is_constructible_v <Smart, SP, Args...> 为 true ，则析构函数进行

if (p) s = Smart(static_cast<SP>(p), std::forward <Args>(args)...); ，

否则程序非良构。

注解

若 Smart 是 std::shared_ptr 的特化，则实现可以在构造时分配重设新的控制块的存储，以将不抛出的工作留给析构函数。

在重设后销毁按值捕获的实参。


std::owner_less

< cpp‎ | memory
定义于头文件 <memory> |  |
 | (1) |
template< class T > struct owner_less; /* undefined */ |  |  | (C++11 起) (C++17 前)
template< class T = void > struct owner_less; /* undefined */ |  |  | (C++17 起)
template< class T > struct owner_less< std::shared_ptr <T>>; | (2) | (C++11 起)
template< class T > struct owner_less< std::weak_ptr <T>>; | (3) | (C++11 起)
template<> struct owner_less<void>; | (4) | (C++17 起)

此函数对象提供基于拥有者（不同于基于值）的， std::weak_ptr 和 std::shared_ptr 两者的混合类型序。顺序满足二个智能指针比较相等，若且唯若它们均为空或共享所有权，即使由 get() 获得的裸指针值相异（例如因为它们指向同一对象中的不同子对象）。

在以 std::shared_ptr 或 std::weak_ptr 为关键建立关联容器，即

std::map < std::shared_ptr <T>, U, std::owner_less< std::shared_ptr <T>>>

或

std::map < std::weak_ptr <T>, U, std::owner_less< std::weak_ptr <T>>> 时，最好使用此类模板。

默认的 operator< 不为弱指针定义，并且可能错误地认为同一对象的二个共享指针不等价（见 shared_ptr::owner_before ）。

特化

标准库提供 std::owner_less 在不指定 T 时的特化。此情况下，从实参类型推导形参类型（每个实参都必须是 std::shared_ptr 或 std::weak_ptr ）。

owner_less<void>
 为共享指针和弱指针提供混合类型的、基于拥有者的顺序的函数对象，无关乎被指向的类型
(类模板特化)
(C++17 起)

成员类型

成员类型 | 定义
result_type(C++17 中弃用) | 2-3) bool
first_argument_type(C++17 中弃用) 2) std::shared_ptr <T>
3) std::weak_ptr <T>
second_argument_type(C++17 中弃用) 2) std::shared_ptr <T>
3) std::weak_ptr <T>
(C++20 前)

成员函数

operator()
 用基于拥有者的语义比较其参数
(函数)

std::owner_less::operator()

所有模板特化的成员
bool operator()( const std::shared_ptr <T>& lhs,
const std::weak_ptr <T>& rhs ) const noexcept;
 (C++11 起)
bool operator()( const std::weak_ptr <T>& lhs,
const std::shared_ptr <T>& rhs ) const noexcept;
 (C++11 起)
仅为 owner_less<shared_ptr<T>> 模板特化的成员
bool operator()( const std::shared_ptr <T>& lhs,
const std::shared_ptr <T>& rhs ) const noexcept;
 (C++11 起)
仅为 owner_less<weak_ptr<T>> 模板特化的成员
bool operator()( const std::weak_ptr <T>& lhs,
const std::weak_ptr <T>& rhs ) const noexcept;
 (C++11 起)

用基于拥有者的语义比较 lhs 与 rhs 。等效于调用 lhs.owner_before(rhs) 。

顺序是严格弱序关系。

lhs 与 rhs 相等，当且仅当它们均为空或共享所有权。

参数

lhs, rhs - 要比较的共享所有权指针

返回值

若按基于拥有者的顺序确定 lhs 小于 rhs ，则为 true 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2873 | C++11 | operator() 可以不声明为 noexcept | 声明为 noexcept

参阅

owner_before | 提供基于拥有者的共享指针排序 (std::shared_ptr<T> 的公开成员函数)
owner_before | 提供弱指针的基于拥有者顺序 (std::weak_ptr<T> 的公开成员函数)


std::owner_less

< cpp‎ | memory
定义于头文件 <memory> |
template<> struct owner_less<void>; | (C++17 起)

std::owner_less <> 是拥有待推导形参类型的 std::owner_less 特化。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

成员函数

operator()
 用基于占有者的语义比较其参数
(函数)

std::owner_less<void>::operator()

template<class T, class U>

bool operator()( const std::shared_ptr <T>& lhs,

const std::shared_ptr <U>& rhs ) const noexcept;
 (C++17 起)
template<class T, class U>

bool operator()( const std::shared_ptr <T>& lhs,

const std::weak_ptr <U>& rhs ) const noexcept;
 (C++17 起)
template<class T, class U>

bool operator()( const std::weak_ptr <T>& lhs,

const std::shared_ptr <U>& rhs ) const noexcept;
 (C++17 起)
template<class T, class U>

bool operator()( const std::weak_ptr <T>& lhs,

const std::weak_ptr <U>& rhs ) const noexcept;
 (C++17 起)

用基于占有者的语义比较 lhs 与 rhs 。等效地调用 lhs.owner_before(rhs) 。

顺序是严格弱序关系。

lhs 与 rhs 仅若均为空或共享所有权才等价。

参数

lhs, rhs - 要比较的共享所有权指针

返回值

若以基于占有者的顺序确定 lhs 小于 rhs 则为 true 。

参阅

owner_before | 提供基于拥有者的共享指针排序 (std::shared_ptr<T> 的公开成员函数)
owner_before | 提供弱指针的基于拥有者顺序 (std::weak_ptr<T> 的公开成员函数)


std::pointer_traits

< cpp‎ | memory
定义于头文件 <memory> |  |
template< class Ptr > struct pointer_traits; | (1) | (C++11 起)
template< class T > struct pointer_traits<T*>; | (2) | (C++11 起)

pointer_traits 类模板提供标准化方法，访问类指针类型（缀饰指针，如 boost::interprocess::offset_ptr ）的某些属性。标准模板 std::allocator_traits 依靠 pointer_traits 确定多种分配器 (Allocator) 所要求的 typedef 的默认行为。

1) 非特化 pointer_traits 声明下列类型：

成员类型

类型 | 定义
pointer | Ptr
element_type | 若存在则为 Ptr::element_type 。否则若 Ptr 是模板特化 Template<T, Args...> 则为 T 。否则该 pointer_traits 特化为谬构
difference_type | 若存在则为 Ptr::difference_type ，否则为 std::ptrdiff_t

成员别名模板

模板 | 定义
template <class U> using rebind | 若存在则为 Ptr::rebind<U> ，否则若 Ptr 是模板特化 Template<T, Args...> 则为 Template<U, Args...>

成员函数

pointer_to
[静态]
 获得指向其参数的可解引用指针
(公开静态成员函数)
程序定义特化的可选成员函数
to_address
[静态] (C++20)(可选)
 从缀饰指针获得裸指针（ pointer_to 的反函数）
(公开静态成员函数)
2) 为指针类型 T* 提供的特化，它声明下列类型：

成员类型

类型 | 定义
pointer | T*
element_type | T
difference_type | std::ptrdiff_t

成员别名模版

模板 | 定义
template <class U> using rebind | U*

成员函数

pointer_to
[静态]
 获得指向其参数的可解引用指针
(公开静态成员函数)

注解

重绑定成员模板别名，使得可以由指向 T 的类指针类型，获取指向 U 的相同类指针类型。例如，

typedef std::pointer_traits<std::shared_ptr<int>>::rebind<double> another_pointer;
static_assert(std::is_same<another_pointer, std::shared_ptr<double>>::value);

对用户定义指针类型的特化可提供额外的静态成员函数 to_address 以定制 std::to_address 的行为。

 (C++20 起)

示例

#include <memory>
#include <iostream>

template <class Ptr>
struct BlockList
{
   // 预定义内存块
   struct block;

   // 从指针类别 Ptr 定义指向内存块的指针
   // 若 Ptr 是任何 T* 类型，则 block_ptr_t 为 block*
   // 若 Ptr 是 smart_ptr<T> ，则 block_ptr_t 为 smart_ptr<block>
   using block_ptr_t = typename std::pointer_traits<Ptr>::template rebind<block>;

   struct block
   {
      std::size_t size{};
      block_ptr_t next_block{};
   };

   block_ptr_t free_blocks;
};

int main()
{
    [[maybe_unused]] BlockList<int*> bl1;
    // bl1.free_blocks 的类型是 BlockList<int*>::block*

    BlockList<std::shared_ptr<char>> bl2;
    // bl2.free_blocks 的类型是 std::shared_ptr< BlockList<std::shared_ptr<char> >::block>
    std::cout << bl2.free_blocks.use_count() << '\n';
}

输出：

​0​

参阅

allocator_traits (C++11) | 提供关于分配器类型的信息 (类模板)
addressof (C++11) | 获得对象的实际地址，即使其重载了 & 运算符 (函数模板)


std::pointer_traits<Ptr>::pointer_to

< cpp‎ | memory‎ | pointer traits
定义于头文件 <memory> |  |
static pointer pointer_to( element_type& r ); | (1) | (C++11 起) (pointer_traits<Ptr> 特化的成员)
 | (2) |
static pointer pointer_to( element_type& r ) noexcept; |  |  | (C++11 起) (C++20 前) (pointer_traits<T*> 特化的成员)
static constexpr pointer pointer_to( element_type& r ) noexcept; |  |  | (C++20 起) (pointer_traits<T*> 特化的成员)

构造一个指向其参数的可解引用指针或类指针对象（“缀饰指针”）。

1) 此函数于非特化 std::pointer_traits 模板的版本简单地调用 Ptr::pointer_to(r) ，且若 Ptr 不提供静态成员函数 pointer_to ，则此函数的实例化为编译时错误。
2) 此函数于 std::pointer_traits 为指针类型特化的版本返回 std::addressof (r)

参数

r - element_type& 类型的到对象引用，除非 element_type 为 void ，此情况下 r 的类型未指定

返回值

指向 r 的可解引用指针，拥有 pointer_traits<>::pointer 类型。

异常

1) 未指定（通常同 Ptr::pointer_to ）

注意

若 Ptr::pointer_to 不存在，则此函数的 Boost.Intrusive 库版本 返回 pointer( std::addressof (r)) 。

参阅

addressof (C++11) | 获得对象的实际地址，即使其重载了 & 运算符 (函数模板)
address (C++17 中弃用)(C++20 中移除) | 获得对象的地址，即使重载了 operator& (std::allocator<T> 的公开成员函数)
to_address [静态] (C++20)(可选) | 从缀饰指针获得裸指针（ pointer_to 的反函数） (公开静态成员函数)
to_address (C++20) | 从指针式类型获得裸指针 (函数模板)


std::pointer_traits<Ptr>::to_address

< cpp‎ | memory‎ | pointer traits
定义于头文件 <memory> |
static element_type* to_address(pointer p) noexcept; | (C++20 起) (程序定义特化的可选成员)

构造裸指针，结果引用的对象与其仿指针（“缀饰指针”）参数相同。

若定义此函数，则它是 pointer_to 的反函数，它作为定制点存在并为 std::to_address 所调用。

参数

p - 缀饰值指针/仿指针对象

返回值

element_type* 类型的裸指针，其所引用的内存位置与参数 p 相同。

参阅

pointer_to [静态] | 获得指向其参数的可解引用指针 (公开静态成员函数)
to_address (C++20) | 从指针式类型获得裸指针 (函数模板)


std::pmr::polymorphic_allocator

< cpp‎ | memory
定义于头文件 <memory_resource>
template< class T >
class polymorphic_allocator;
 (C++17 起)
(C++20 前)
template< class T = std::byte >
class polymorphic_allocator;
 (C++20 起)

类模板 std::pmr::polymorphic_allocator 是一个分配器 (Allocator) ，展现出取决于其构造所用的 std::pmr::memory_resource 的不同的分配行为。因为 memory_resource 使用运行时多态管理分配器，不同的以 polymorphic_allocator 为其静态分配器类型的分配器可互操作，但能表现为如同它们拥有不同的分配器类型。

polymorphic_allocator 的所有特化均满足分配器完整性要求。

成员类型

成员类型 | 定义
value_type | T

成员函数

(构造函数)
 构造一个 polymorphic_allocator
(公开成员函数)
(析构函数)
(隐式声明)
 隐式声明的析构函数
(公开成员函数)
operator=
[被删除]
 复制赋值运算符被删除
(公开成员函数)
公开成员函数
allocate
 分配内存
(公开成员函数)
deallocate
 解分配内存
(公开成员函数)
construct
 在分配的存储上构造一个对象
(公开成员函数)
destroy
(C++20 中弃用)
 销毁处于分配的内存的对象
(公开成员函数)
allocate_bytes
(C++20)
 从底层资源分配未处理的对齐内存
(公开成员函数)
deallocate_bytes
(C++20)
 释放从 allocate_bytes 获得的未处理内存
(公开成员函数)
allocate_object
(C++20)
 分配适合单个对象或数组的未处理内存
(公开成员函数)
deallocate_object
(C++20)
 释放由 allocate_object 获得的未处理内存
(公开成员函数)
new_object
(C++20)
 分配并创建对象
(公开成员函数)
delete_object
(C++20)
 销毁并解分配对象
(公开成员函数)
select_on_container_copy_construction
 为容器的复制构造函数的使用创建一个新的 polymorphic_allocator
(公开成员函数)
resource
 返回指向底层 memory_resource 的指针
(公开成员函数)

非成员函数

operator==operator!=
(C++20 中移除)
 比较二个 polymorphic_allocator
(函数)

注解

polymorphic_allocator 在容器复制赋值、移动赋值或交换时不传播。结果是，使用 polymorphic_allocator 的容器的移动赋值可能抛出，且交换二个使用 polymorphic_allocator ，而所用分配器比较不相等的容器导致未定义行为。

参阅

memory_resource
(C++17)
 一个抽象接口，用于各种封装内存资源的类
(类)


std::pmr::polymorphic_allocator<T>::allocate

< cpp‎ | memory‎ | polymorphic allocator
T* allocate( std::size_t n ); | (C++17 起) (C++20 前)
[[nodiscard]] T* allocate( std::size_t n ); | (C++20 起)

用底层的 memory_resource 分配 n 个 T 类型对象的存储。等价于 return static_cast<T*>(resource()->allocate(n * sizeof(T), alignof(T))); 。

参数

n - 要分配存储的对象数

返回值

指向被分配存储的指针。

异常

若 n > std::numeric_limits < std::size_t >::max() / sizeof(T) 则抛出 std::bad_array_new_length ；亦可抛出调用 resource()->allocate 所抛的任何异常。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3038 | C++17 | allocate 可能分配大小错误的存储 | 替而抛出 length_error
LWG 3237 | C++17 | allocate 所抛的异常与 std::allocator::allocate 不一致 | 使之一致

参阅

allocate [静态] | 用分配器分配未初始化的存储 (std::allocator_traits<Alloc> 的公开静态成员函数)
allocate | 分配内存 (std::pmr::memory_resource 的公开成员函数)


std::pmr::polymorphic_allocator<T>::allocate_bytes

< cpp‎ | memory‎ | polymorphic allocator
[[nodiscard]] void* allocate_bytes( std::size_t nbytes,
std::size_t alignment = alignof( std::max_align_t ) );
 (C++20 起)

分配按指定 alignment 对齐的 nbytes 字节存储。等价于 return resource()->allocate(nbytes, alignment); 。

参数

nbytes | - | 要分配的字节数
alignment | - | 使用的对齐

返回

指向分配的存储的指针。

注解

引入此函数是为了用于全特化分配器 std::polymorphic_allocator<> ，但它可能在任何特化中都有用。

返回类型为 void* （而非 std::byte* 之类），以支持通过 static_cast<U*> 转换到任意指针类型 U* 。

异常

可能抛出任何调用 resource()->allocate 所抛的异常。

参阅

allocate_object (C++20) | 分配适合单个对象或数组的未处理内存 (公开成员函数)
new_object (C++20) | 分配并创建对象 (公开成员函数)
allocate | 分配内存 (公开成员函数)
allocate [静态] | 用分配器分配未初始化的存储 (std::allocator_traits<Alloc> 的公开静态成员函数)
allocate | 分配内存 (std::pmr::memory_resource 的公开成员函数)


std::pmr::polymorphic_allocator<T>::allocate_object

< cpp‎ | memory‎ | polymorphic allocator
template< class U > [[nodiscard]] U* allocate_object( std::size_t n = 1 ); | (C++20 起)

用底层内存资源分配 n 个 U 类型对象的存储。

若 std::numeric_limits < std::size_t >::max() / sizeof(U) < n ，则抛出 std::bad_array_new_length ，否则等价于 return static_cast<U*>(allocate_bytes(n * sizeof(U), alignof(U)) ); 。

参数

n - 要分配存储的对象数

返回值

指向分配的存储的指针。

注解

引入此函数是为了用于全特化分配器 std::polymorphic_allocator<> ，但它可能在任何特化中都有用，作为避免从 std::polymorphic_allocator<T> 重绑定到 std::polymorphic_allocator<U> 的快捷方式。

因为不推导 U ，调用此函数时必须提供它为模板实参。

异常

若 n > std::numeric_limits < std::size_t >::max() / sizeof(U) 则抛出 std::bad_array_new_length ；亦可能抛出任何调用 resource()->allocate 所抛的异常。

参阅

allocate_bytes (C++20) | 从底层资源分配未处理的对齐内存 (公开成员函数)
new_object (C++20) | 分配并创建对象 (公开成员函数)
allocate | 分配内存 (公开成员函数)
allocate [静态] | 用分配器分配未初始化的存储 (std::allocator_traits<Alloc> 的公开静态成员函数)
allocate | 分配内存 (std::pmr::memory_resource 的公开成员函数)


std::pmr::polymorphic_allocator<T>::construct

< cpp‎ | memory‎ | polymorphic allocator
template < class U, class... Args >
void construct( U* p, Args&&... args );
 (1) (C++17 起)
template< class T1, class T2, class... Args1, class... Args2 >

void construct( std::pair <T1, T2>* p,
std::piecewise_construct_t,
std::tuple <Args1...> x,

std::tuple <Args2...> y );
 (2) (C++17 起)
(C++20 前)
template< class T1, class T2 >
void construct( std::pair <T1, T2>* p );
 (3) (C++17 起)
(C++20 前)
template< class T1, class T2, class U, class V >
void construct( std::pair <T1, T2>* p, U&& x, V&& y );
 (4) (C++17 起)
(C++20 前)
template< class T1, class T2, class U, class V >
void construct( std::pair <T1, T2>* p, const std::pair <U, V>& xy );
 (5) (C++17 起)
(C++20 前)
template< class T1, class T2, class U, class V >
void construct( std::pair <T1, T2>* p, std::pair <U, V>&& xy );
 (6) (C++17 起)
(C++20 前)

在 p 所指的，分配但未初始化的存储上，以提供的构造函数参数构造一个对象。若对象自身拥有使用分配器的类型，或它是 std::pair ，则传递 this->resource() 给被构造的对象。

1) 以使用分配器构造的手段在 p 所指示的未初始化内存位置，以 *this 为分配器创建给定类型 U 的对象。此重载仅若 U 不是 std::pair 的特化才参与重载决议。 (C++20 前)
2) 首先，若 T1 或 T2 之一具分配器，则修改 x 与 y 的 tuple 以包含 this->resource() ，产生二个新 tuple xprime 与 yprime ，按照下列规则：
2a) 若 T1 不具分配器（ std::uses_allocator <T1, polymorphic_allocator>::value==false ）且 std::is_constructible <T1, Args1...>::value==true ，则 xprime 是未修改的 x 。
2b) 若 T1 具分配器（ std::uses_allocator <T1, polymorphic_allocator>::value==true ），且其构造函数使用分配器标签（ std::is_constructible <T1, std::allocator_arg_t, polymorphic_allocator, Args1...>::value==true ），则 xprime 是 std::tuple_cat ( std::make_tuple ( std::allocator_arg, *this), std::move(x))
2c) 若 T1 具分配器（ std::uses_allocator <T1, polymorphic_allocator>::value==true ），且其构造函数接受分配器为最后参数（ std::is_constructible <T1, Args1..., polymorphic_allocator>::value==true ），则 xprime 是 std::tuple_cat (std::move(x), std::make_tuple (*this)) 。
2d) 否则程序为病式。
同样的规则应用于 T2 及以 yprime 替换 y 的情况。
一旦构造了 xprime 和 yprime ，就如同以用 ::new((void *) p) pair<T1, T2>( std::piecewise_construct, std::move(xprime), std::move(yprime)); 于分配的存储构造 pair p 。
3) 等价于 construct(p, std::piecewise_construct, std::tuple <>(), std::tuple <>()) ，即传递memory_resouce 到 pair 的成员类型上，若它接受它们。
4) 等价于
    construct(p, std::piecewise_construct, std::forward_as_tuple(std::forward<U>(x)),
                                       std::forward_as_tuple(std::forward<V>(y)))
5) 等价于
    construct(p, std::piecewise_construct, std::forward_as_tuple(xy.first),
                                       std::forward_as_tuple(xy.second))
6) 等价于
    construct(p, std::piecewise_construct, std::forward_as_tuple(std::forward<U>(xy.first)),
                                       std::forward_as_tuple(std::forward<V>(xy.second)))
 (C++20 前)

参数

p | - | 指向分配而未初始化存储的指针
args... | - | 传递给 T 构造函数的构造函数参数
x | - | 传递给 T1 构造函数的构造函数参数
y | - | 传递给 T2 构造函数的构造函数参数
xy | - | 成员是 T1 与 T2 构造函数参数的 pair

返回值

（无）

注意

此函数为任何具分配器对象调用（通过 std::allocator_traits ），例如 std::pmr::vector （或另一个给定了 std::std::polymorphic_allocator 作为所用分配器的 std::vector ）。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2969 | C++17 | uses-allocator 构造传递 resource() | 传递 *this
LWG 2975 | C++17 | 某些情况下 pair 构造错误地使用第一重载 | 制约为不接受 pair

参阅

construct [静态] | 在分配的存储构造对象 (函数模板)
construct (C++17 中弃用)(C++20 中移除) | 在分配的存储构造对象 (std::allocator<T> 的公开成员函数)


std::pmr::polymorphic_allocator<T>::deallocate

< cpp‎ | memory‎ | polymorphic allocator
void deallocate(T* p, std::size_t n ); | (C++17 起)

解分配 p 所指向的存储，它必须由从比较等于 *resource() 的 std::pmr::memory_resource x 用 x.allocate(n * sizeof(T), alignof(T)) 分配。

等价于 this->resource()->deallocate(p, n * sizeof(T), alignof(T));

参数

p | - | 指向要解分配的内存
n | - | 原先分配的对象数目

异常

不抛出任何异常。

参阅

deallocate [静态] | 用分配器解分配存储 (std::allocator_traits<Alloc> 的公开静态成员函数)
deallocate | 解分配内存 (std::pmr::memory_resource 的公开成员函数)


std::pmr::polymorphic_allocator<T>::deallocate_bytes

< cpp‎ | memory‎ | polymorphic allocator
void deallocate_bytes( void* p,

std::size_t nbytes,

std::size_t alignment = alignof( std::max_align_t ) );
 (C++20 起)

解分配 p 所指向的存储，它必须从比较等于 *resource() 的 std::pmr::memory_resource x 以 x.allocate(nbytes, alignment) 分配，通常通过调用 allocate_bytes(nbytes, alignment 。

等价于 resource()->deallocate(p, nbytes, alignment); 。

参数

p | - | 指向要解分配的内存的指针
nbytes | - | 原先分配的字节数
alignment | - | 原先分配的对齐

异常

不抛出。

注解

引入此函数是为了用于全特化分配器 std::polymorphic_allocator<> ，但它可能在任何特化中都有用。

参阅

deallocate_object (C++20) | 释放由 allocate_object 获得的未处理内存 (公开成员函数)
delete_object (C++20) | 销毁并解分配对象 (公开成员函数)
deallocate [静态] | 用分配器解分配存储 (std::allocator_traits<Alloc> 的公开静态成员函数)
deallocate | 解分配内存 (std::pmr::memory_resource 的公开成员函数)


std::pmr::polymorphic_allocator<T>::deallocate_object

< cpp‎ | memory‎ | polymorphic allocator
template <class U> void deallocate_object( U* p, std::size_t n = 1 ); | (C++20 起)

解分配 p 所指向的存储，它必须从比较等于 *resource() 的 std::pmr::memory_resource x 用 x.allocate(n*sizeof(U), alignof(U)) 分配，通常通过调用 allocate_object<U>(n) 。

等价于 deallocate_bytes(p, n*sizeof(U), alignof(U)); 。

参数

p | - | 指向要解分配的内存的指针
n | - | 内存所用于的 U 类型对象数

异常

不抛出。

注意

引入此函数是为了用于全特化分配器 std::polymorphic_allocator<> ，但它可能在任何特化中都有用。

参阅

deallocate_bytes (C++20) | 释放从 allocate_bytes 获得的未处理内存 (公开成员函数)
delete_object (C++20) | 销毁并解分配对象 (公开成员函数)
deallocate [静态] | 用分配器解分配存储 (std::allocator_traits<Alloc> 的公开静态成员函数)
deallocate | 解分配内存 (std::pmr::memory_resource 的公开成员函数)


std::pmr::polymorphic_allocator<T>::deallocate_object

< cpp‎ | memory‎ | polymorphic allocator
template <class U> void delete_object( U* p ); | (C++20 起)

销毁 U 类型对象并解分配为它分配的存储。

等价于

std::allocator_traits<polymorphic_allocator>::destroy(*this, p);
deallocate_object(p);

参数

p - 指向要销毁并解分配的对象的指针

异常

不抛出。

注解

引入此函数是为了用于全特化分配器 std::polymorphic_allocator<> ，但它可能在任何特化中都有用。

参阅

deallocate_bytes (C++20) | 释放从 allocate_bytes 获得的未处理内存 (公开成员函数)
deallocate_object (C++20) | 释放由 allocate_object 获得的未处理内存 (公开成员函数)
deallocate [静态] | 用分配器解分配存储 (std::allocator_traits<Alloc> 的公开静态成员函数)
deallocate | 解分配内存 (std::pmr::memory_resource 的公开成员函数)


std::pmr::polymorphic_allocator<T>::destroy

< cpp‎ | memory‎ | polymorphic allocator
template<class U> void destroy(U* p); | (C++17 起) (C++20 中弃用)

销毁 p 所指向的对象，如同以调用 p->~U() 。

参数

p - 指向被销毁对象的指针

注解

此函数由 LWG 问题 3036 弃用，因为其功能能由 std::allocator_traits::destroy 的默认实现提供，从而是多余的。

参阅

destroy
[静态]
 析构存储于已分配存储的对象
(函数模板)


std::pmr::polymorphic_allocator<T>::new_object

< cpp‎ | memory‎ | polymorphic allocator
template< class U, class CtorArgs... > [[nodiscard]] U* new_object( CtorArgs&&... ctor_args ); | (C++20 起)

分配并构造 U 类型对象。

等价于

U* p = allocate_object<U>();
try {
  construct(p, std::forward<CtorArgs>(ctor_args)...);
} catch (...) {
  deallocate_object(p);
  throw;
}
return p;

参数

ctor_args - 转发给 U 的构造函数的参数

返回值

指向分配并构造的对象的指针。

注解

引入此函数是为了用于全特化分配器 std::polymorphic_allocator<> ，但它可能在任何特化中都有用，作为避免从 std::polymorphic_allocator<T> 重绑定到 std::polymorphic_allocator<U> 和必须单独调用 allocate 、 construct 及 deallocate 的快捷方式。

因为不推导 U ，调用此函数时必须提供它为模板实参。

异常

可能抛出任何调用 allocate_object 或 U 的构造函数所抛的异常。

参阅

allocate_bytes (C++20) | 从底层资源分配未处理的对齐内存 (公开成员函数)
allocate_object (C++20) | 分配适合单个对象或数组的未处理内存 (公开成员函数)
allocate | 分配内存 (公开成员函数)
allocate [静态] | 用分配器分配未初始化的存储 (std::allocator_traits<Alloc> 的公开静态成员函数)
allocate | 分配内存 (std::pmr::memory_resource 的公开成员函数)


std::pmr::operator==, std::pmr::operator!=

< cpp‎ | memory‎ | polymorphic allocator
定义于头文件 <memory_resource>
template< class T1, class T2 >

bool operator==( const std::pmr::polymorphic_allocator <T1>& lhs,

const std::pmr::polymorphic_allocator <T2>& rhs ) noexcept;
 (1) (C++17 起)
template< class T1, class T2 >

bool operator!=( const std::pmr::polymorphic_allocator <T1>& lhs,

const std::pmr::polymorphic_allocator <T2>& rhs ) noexcept;
 (2) (C++17 起)
(C++20 前)

比较二个 polymorphic_allocator 。若二个 polymorphic_allocator 的底层 memory_resource 比较相等，则它们比较相等。

1) 返回 *lhs.resource() == *rhs.resource()
2) 返回 !(lhs == rhs)

参数

lhs, rhs - 要比较的 polymorphic_allocator

返回值

1) *lhs.resource() == *rhs.resource()
2) !(lhs == rhs)


std::pmr::polymorphic_allocator<T>::polymorphic_allocator

< cpp‎ | memory‎ | polymorphic allocator
polymorphic_allocator() noexcept; | (1)
polymorphic_allocator( const polymorphic_allocator& other ) = default; | (2)
template< class U > polymorphic_allocator( const polymorphic_allocator<U>& other ) noexcept; | (3)
polymorphic_allocator( memory_resource* r); | (4)

构造新的 polymorphic_allocator 。

1) 以 std::pmr::get_default_resource () 的返回值为底层 memory_resource 构造一个 polymorphic_allocator 。
2-3) 以 other.resource() 为底层 memory_resource 构造 polymorphic_allocator 。
4) 以 r 为底层 memory_resouce 构造 polymorphic_allocator 。此构造函数提供从 memory_resource* 的隐式转换。

参数

other | - | 要复制的另一 polymorphic_allocator
r | - | 指向要使用的 memory_resource 的指针。不可为空。

异常

4) 不抛出任何异常。

注意

复制使用 polymorphic_allocator 的容器不会调用分配器的复制构造函数。新容器会替代地以 select_on_container_copy_construction 的返回值（默认构造的 polymorphic_allocator ）为其分配器。

参阅

select_on_container_copy_construction
 为容器的复制构造函数的使用创建一个新的 polymorphic_allocator
(公开成员函数)


std::pmr::polymorphic_allocator<T>::resource

< cpp‎ | memory‎ | polymorphic allocator
memory_resource* resource() const; | (C++17 起)

返回此 polymorohic_allocator 所用的 memory_resource 指针。

参数

（无）

返回值

此 polymorohic_allocator 所用的 memory_resource 指针。


std::pmr::polymorphic_allocator<T>:: select_on_container_copy_construction

< cpp‎ | memory‎ | polymorphic allocator
polymorphic_allocator select_on_container_copy_construction() const; | (C++17 起)

返回默认构造的 polymorphic_allocator 对象。

参数

（无）

返回值

默认构造的 polymorphic_allocator 对象。

注意

polymorphic_allocator 不在容器复制构造时传播。

参阅

select_on_container_copy_construction
[静态]
 获得复制标准容器后使用的分配器
(std::allocator_traits<Alloc> 的公开静态成员函数)


std::pmr::pool_options

< cpp‎ | memory
定义于头文件 <memory_resource> |
struct pool_options; | (C++17 起)

std::pmr::pool_options 是一组池资源构造函数选项的集合，池资源包含 std::pmr::synchronized_pool_resource 和 std::pmr::unsynchronized_pool_resource 。

数据成员

成员 含义
std::size_t max_blocks_per_chunk;
要一次从上游 std::pmr::memory_resource 分配以充满池的块数量最大值。若 max_blocks_per_chunk 的值为零或大于一个实现定义极限，则使用极限代替。实现可以选择使用小于指定于此域的值，并可对不同池使用不同值。
std::size_t largest_required_pool_block;
要求使用分池机制实现的最大分配大小。分配大于此门槛的单个块的尝试会直接从上游 std::pmr::memory_resource 分配。若 largest_required_pool_block 为零或大于实现定义的极限，则使用极限代替。实现可选择大于指定于此域的值的通过门槛。

参阅

synchronized_pool_resource (C++17) | 线程安全的 std::pmr::memory_resource，用于管理具有不同块大小的池中的分配 (类)
unsynchronized_pool_resource (C++17) | 线程不安全的 std::pmr::memory_resource，用于管理具有不同块大小的池中的分配 (类)


std::ranges::construct_at

< cpp‎ | memory
定义于头文件 <memory> |
调用签名 |
template< class T, class... Args > constexpr T* construct_at( T* p, Args&&... args ); | (C++20 起)

在给定地址 p 创建以参数 args... 初始化的 T 对象。 construct_at 仅若 ::new( std::declval <void*>()) T( std::declval <Args>()...) 在不求值语境中为良构才参与重载决议。

等价于

return ::new (const_cast<void*>(static_cast<const volatile void*>(p)))
    T(std::forward<Args>(args)...);

除了 construct_at 可用于常量表达式的求值。

在某常量表达式 e 的求值中调用 construct_at 时，参数 p 必须指向用 std::allocator <T>::allocate 获得的存储或生存期始于 e 的求值内的对象。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

p | - | 指向将在其上构造 T 对象的未初始化存储的指针
args... | - | 用于初始化的参数

返回值

p

可能的实现

struct construct_at_fn {
  template<class T, class...Args>
    requires
      requires (void* vp, Args&&... args) { ::new (vp) T(static_cast<Args&&>(args)...); }
  constexpr T* operator()(T* p, Args&&... args) const
  {
    return std::construct_at(p, static_cast<Args&&>(args)...);
  }
};

inline constexpr construct_at_fn construct_at{};

注解

std::ranges::construct_at 与 std::construct_at 表现准确相同，除了它对实参依赖查找不可见。

示例

#include <iostream>
#include <memory>

struct S {
    int x;
    float y;
    double z;

    S(int x, float y, double z) : x{x}, y{y}, z{z} { std::cout << "S::S();\n"; }

    ~S() { std::cout << "S::~S();\n"; }

    void print() const {
        std::cout << "S { x=" << x << "; y=" << y << "; z=" << z << "; };\n";
    }
};

int main()
{
    alignas(S) unsigned char buf[sizeof(S)];

    S* ptr = std::ranges::construct_at(reinterpret_cast<S*>(buf), 42, 2.71828f, 3.1415);
    ptr->print();

    std::ranges::destroy_at(ptr);
}

输出：

S::S();
S { x=42; y=2.71828; z=3.1415; };
S::~S();

参阅

ranges::destroy_at (C++20) | 销毁位于给定地址的元素 (niebloid)
construct_at (C++20) | 在给定地址创建对象 (函数模板)


std::ranges::destroy

< cpp‎ | memory
定义于头文件 <memory>
调用签名
template< no-throw-input-iterator I, no-throw-sentinel-for<I> S >

requires std::destructible<std::iter_value_t<I>>

constexpr I destroy( I first, S last ) noexcept;
 (1) (C++20 起)
template< no-throw-input-range R >

requires std::destructible<ranges::range_value_t<R>>

constexpr ranges::borrowed_iterator_t<R> destroy( R&& r ) noexcept;
 (2) (C++20 起)
1) 销毁范围 [first, last) 中的对象，如同用
for (; first != last; ++first)
    std::ranges::destroy_at(std::addressof(*first));
return first;
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 代表要销毁的范围的迭代器-哨位对
r | - | 要销毁的范围

返回值

比较等于 last 的迭代器。

复杂度

与 first 和 last 间的距离成线性。

可能的实现

struct destroy_fn {
  template<no-throw-input-iterator I, no-throw-sentinel-for<I> S>
    requires std::destructible<std::iter_value_t<I>>
  constexpr I operator()(I first, S last) const noexcept
  {
    for (; first != last; ++first)
      std::ranges::destroy_at(std::addressof(*first));
    return first;
  }

  template<no-throw-input-range R>
    requires std::destructible<std::ranges::range_value_t<R>>
  constexpr std::ranges::borrowed_iterator_t<R> operator()(R&& r) const noexcept
  {
    return operator()(std::ranges::begin(r), std::ranges::end(r));
  }
};

inline constexpr destroy_fn destroy{};

示例

下列示例演示如何用 ranges::destroy 销毁元素的相接序列。

#include <memory>
#include <new>
#include <iostream>

struct Tracer {
    int value;
    ~Tracer() { std::cout << value << " destructed\n"; }
};

int main()
{
    alignas(Tracer) unsigned char buffer[sizeof(Tracer) * 8];

    for (int i = 0; i < 8; ++i)
        new(buffer + sizeof(Tracer) * i) Tracer{i}; // 手工构造对象

    auto ptr = std::launder(reinterpret_cast<Tracer*>(buffer));

    std::destroy_n(ptr, 8);
}

输出：

0 destructed
1 destructed
2 destructed
3 destructed
4 destructed
5 destructed
6 destructed
7 destructed

参阅

ranges::destroy_n (C++20) | 销毁范围中一定量的元素 (niebloid)
ranges::destroy_at (C++20) | 销毁位于给定地址的元素 (niebloid)
destroy (C++17) | 销毁一个范围中的对象 (函数模板)


std::ranges::destroy_at

< cpp‎ | memory
定义于头文件 <memory>
调用签名
template< std::destructible T >
constexpr void destroy_at( T* p ) noexcept;
 (C++20 起)

若 T 不是数组类型，则在 p 所指向的对象上调用析构函数，如同通过 p->~T() 。否则，按顺序递归地销毁 *p 的元素，如同通过调用 std::destroy ( std::begin (*p), std::end (*p)) 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

p - 指向要被销毁的对象的指针

返回值

（无）

可能的实现

struct destroy_at_fn {
  template<std::destructible T>
  constexpr void operator()(T *p) const noexcept
  {
    if constexpr (std::is_array_v<T>)
      for (auto &elem : *p)
        operator()(std::addressof(elem));
    else
      p->~T();
  }
};

inline constexpr destroy_at_fn destroy_at{};

注解

destroy_at 推导要被销毁的对象的类型，从而避免在析构函数调用中显式写出它。

在某常量表达式 e 的求值中调用 destroy_at 时，参数 p 必须指向生存期始于 e 的求值内的对象。

示例

下列示例演示如何用 ranges::destroy_at 销毁元素的相接序列。

#include <memory>
#include <new>
#include <iostream>

struct Tracer {
    int value;
    ~Tracer() { std::cout << value << " destructed\n"; }
};

int main()
{
    alignas(Tracer) unsigned char buffer[sizeof(Tracer) * 8];

    for (int i = 0; i < 8; ++i)
        new(buffer + sizeof(Tracer) * i) Tracer{i}; // 手工构造对象

    auto ptr = std::launder(reinterpret_cast<Tracer*>(buffer));

    std::destroy_n(ptr, 8);
}

输出：

0 destructed
1 destructed
2 destructed
3 destructed
4 destructed
5 destructed
6 destructed
7 destructed

参阅

ranges::destroy (C++20) | 销毁范围中的元素 (niebloid)
ranges::destroy_n (C++20) | 销毁范围中一定量的元素 (niebloid)
ranges::construct_at (C++20) | 在给定地址创建对象 (niebloid)
destroy_at (C++17) | 销毁在给定地址的对象 (函数模板)


std::ranges::destroy_n

< cpp‎ | memory
定义于头文件 <memory>
调用签名
template< no-throw-input-iterator I >

requires std::destructible<std::iter_value_t<I>>

constexpr I destroy_n( I first, std::iter_difference_t<I> n ) noexcept;
 (C++20 起)

销毁始于 first 的范围中的 n 个对象，等价于

return std::ranges::destroy(std::counted_iterator(first, n), std::default_sentinel).base();

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first | - | 要销毁的元素范围的起始
n | - | 要销毁的元素数

返回值

被销毁的元素的范围的末尾。

复杂度

与 n 成线性。

可能的实现

struct destroy_n_fn {
  template<no-throw-input-iterator I>
    requires std::destructible<std::iter_value_t<I>>
  constexpr I operator()(I first, std::iter_difference_t<I> n) const noexcept
  {
    for (; n != 0; (void)++first, --n)
      std::ranges::destroy_at(std::addressof(*first));
    return first;
  }
};

inline constexpr destroy_n_fn destroy_n{};

示例

下列示例演示如何用 ranges::destroy_n 销毁元素的相接序列。

#include <memory>
#include <new>
#include <iostream>

struct Tracer {
    int value;
    ~Tracer() { std::cout << value << " destructed\n"; }
};

int main()
{
    alignas(Tracer) unsigned char buffer[sizeof(Tracer) * 8];

    for (int i = 0; i < 8; ++i)
        new(buffer + sizeof(Tracer) * i) Tracer{i}; // 手工构造对象

    auto ptr = std::launder(reinterpret_cast<Tracer*>(buffer));

    std::destroy_n(ptr, 8);
}

输出：

0 destructed
1 destructed
2 destructed
3 destructed
4 destructed
5 destructed
6 destructed
7 destructed

参阅

ranges::destroy_at (C++20) | 销毁位于给定地址的元素 (niebloid)
ranges::destroy (C++20) | 销毁范围中的元素 (niebloid)
destroy_n (C++17) | 销毁范围中一定数量的对象 (函数模板)


no-throw-input-iterator, no-throw-forward-iterator, no-throw-sentinel-for, no-throw-input-range, no-throw-forward-range

< cpp‎ | memory
template<class I>

concept no-throw-input-iterator = // 仅用于阐释
std::input_iterator<I> &&
std::is_lvalue_reference_v <std::iter_reference_t<I>> &&

std::same_as<std::remove_cvref_t<std::iter_reference_t<I>>, std::iter_value_t<I>>;
 (1) (C++20 起)
template<class I>

concept no-throw-forward-iterator = // 仅用于阐释
no-throw-input-iterator<I> &&
std::forward_iterator<I> &&

no-throw-sentinel-for<I, I>;
 (2) (C++20 起)
template<class S, class I>
concept no-throw-sentinel-for = std::sentinel_for<S, I>; // 仅用于阐释
 (3) (C++20 起)
template<class R>

concept no-throw-input-range = // 仅用于阐释
ranges::range<R> &&
no-throw-input-iterator<ranges::iterator_t<R>> &&

no-throw-sentinel-for<ranges::sentinel_t<R>, ranges::iterator_t<R>>;
 (4) (C++20 起)
template<class R>

concept no-throw-forward-range = // 仅用于阐释
no-throw-input-range<R> &&

no-throw-forward-iterator<ranges::iterator_t<R>>;
 (5) (C++20 起)

这些仅用于阐释的概念指定迭代器、哨位和范围上算法所要求的操作均不抛异常。

1) no-throw-input-iterator 概念要求解引用迭代器产生左值，类似 contiguous_iterator 与老式向前迭代器 (LegacyForwardIterator) 。

语义要求

类似所有标准概念，此处列出的每个概念得以实现，仅若其所蕴含的所有概念均被实现。

1) 类型 I 实现 no-throw-input-iterator ，仅若自增、复制构造、移动构造、复制赋值、移动赋值或通过合法迭代器的间接不抛出异常。
3) 类型 S 与 I 实现 no-throw-sentinel-for ，仅若复制构造、移动构造、复制赋值、移动赋值或类型 I 与 S 的合法值间的比较不抛异常。
4) 类型 R 实现 no-throw-input-range ，仅若在 R 类型对象上调用 ranges::begin 与 ranges::end 不抛异常。

注解

这些概念允许迭代器和哨位上的某些操作抛出异常，例如非法值上的操作。

参阅

input_iterator (C++20) | 指定类型为输入迭代器，即可读取其所引用的值，且可前/后自增 (概念)
forward_iterator (C++20) | 指定 input_iterator 为向前迭代器，支持相等比较与多趟操作 (概念)
sentinel_for (C++20) | 指定类型为某个 input_or_output_iterator 类型的哨位类型 (概念)
ranges::input_range (C++20) | 指定范围的迭代器类型满足 input_iterator (概念)
ranges::forward_range (C++20) | 指定范围的迭代器类型满足 forward_iterator (概念)


std::ranges::uninitialized_copy, std::ranges::uninitialized_copy_result

< cpp‎ | memory
定义于头文件 <memory>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S1,

no-throw-forward-iterator O, no-throw-sentinel-for<O> S2 >
requires std::constructible_from<std::iter_value_t<O>, std::iter_reference_t<I>>
uninitialized_copy_result<I, O>

uninitialized_copy( I ifirst, S1 ilast, O ofirst, S2 olast );
 (1) (C++20 起)
template< ranges::input_range IR, no-throw-forward-range OR >

requires std::constructible_from<ranges::range_value_t<OR>,
ranges::range_reference_t<IR>>
uninitialized_copy_result<ranges::borrowed_iterator_t<IR>,
ranges::borrowed_iterator_t<OR>>

uninitialized_copy( IR&& in_range, OR&& out_range );
 (2) (C++20 起)
辅助类型
template<class I, class O>
using uninitialized_copy_result = ranges::in_out_result<I, O>;
 (3) (C++20 起)
1) 令 \(\scriptsize N\)N 为 ranges::min(ranges::distance(ifirst, ilast), ranges::distance(ofirst, olast)) ，在作为未初始化内存区域的输出范围 [ofirst, olast) 中，以输入范围 [ifirst, ilast) 中的元素为来源构造 \(\scriptsize N\)N 个元素。
输入与输出范围必须不重叠。
若在初始化时抛异常，则以未指定顺序销毁已构造的元素。
函数拥有的效果等价于：
for (; !(ifirst == ilast || ofirst == olast); ++ofirst, ++ifirst) {
    ::new (const_cast<void*>(static_cast<const volatile void*>(std::addressof(*ofirst))))
        std::remove_reference_t<std::iter_reference_t<O>>(*ifirst);
}
2) 同 (1) ，但以 in_range 为第一范围并以 out_range 为第二范围，如同以 ranges::begin(in_range) 为 ifirst ，以 ranges::end(in_range) 为 ilast ，以 ranges::begin(out_range) 为 ofirst ，并以 ranges::end(out_range) 为 olast 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

ifirst, ilast | - | 要复制的元素范围
in_range | - | 要复制的元素范围
ofirst, olast | - | 目标范围
out_range | - | 目标范围

返回值

{ifirst + N, ofirst + N} 。

复杂度

O(N)𝓞(N) 。

异常

构造目标范围中的元素时抛出的异常，若存在。

注解

若输出范围的值类型为平凡类型 (TrivialType) ，则实现可能提升 ranges::uninitialized_copy 的效率。

可能的实现

struct uninitialized_copy_fn {
    template <std::input_iterator I, std::sentinel_for<I> S1,
             no-throw-forward-iterator O, no-throw-sentinel-for<O> S2>
    requires std::constructible_from<std::iter_value_t<O>, std::iter_reference_t<I>>
    ranges::uninitialized_copy_result<I, O>
    operator()( I ifirst, S1 ilast, O ofirst, S2 olast ) const {
        O current {ofirst};
        try {
            for (; !(ifirst == ilast or current == olast); ++ifirst, ++current)
                ranges::construct_at(std::addressof(*current), *ifirst);
            return {std::move(ifirst), std::move(current)};
        } catch (...) { // 回滚：销毁构造的元素
            for (; ofirst != current; ++ofirst)
                ranges::destroy_at(std::addressof(*ofirst));
            throw;
        }
    }

    template <ranges::input_range IR, no-throw-forward-range OR>
    requires std::constructible_from<ranges::range_value_t<OR>,
             ranges::range_reference_t<IR>>
    ranges::uninitialized_copy_result<ranges::borrowed_iterator_t<IR>,
             ranges::borrowed_iterator_t<OR>>
    operator()( IR&& in_range, OR&& out_range ) const {
        return (*this)(ranges::begin(in_range), ranges::end(in_range),
                       ranges::begin(out_range), ranges::end(out_range));
    }
};

inline constexpr uninitialized_copy_fn uninitialized_copy{};

示例

#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <memory>
#include <string>

int main()
{
    const char* v[] { "This", "is", "an", "example", };

    if (const auto sz{std::size(v)};
        void* pbuf = std::aligned_alloc(alignof(std::string), sizeof(std::string) * sz))
    {
        try
        {
            auto first {static_cast<std::string*>(pbuf)};
            auto last {first + sz};
            std::ranges::uninitialized_copy(std::begin(v), std::end(v), first, last);

            std::cout << "{ ";
            for (auto it {first}; it != last; ++it)
                std::cout << std::quoted(*it) << ", ";
            std::cout << "};\n";

            std::ranges::destroy(first, last);
        }
        catch(...)
        {
            std::cout << "uninitialized_copy exception\n";
        }
        std::free(pbuf);
    }
}

输出：

{ "This", "is", "an", "example", };

参阅

ranges::uninitialized_copy_n (C++20) | 复制一定量元素到未初始化的内存区域 (niebloid)
uninitialized_copy | 将范围内的对象复制到未初始化的内存区域 (函数模板)


std::ranges::uninitialized_copy_n, std::ranges::uninitialized_copy_n_result

< cpp‎ | memory
定义于头文件 <memory>
调用签名
template< std::input_iterator I, no-throw-input-iterator O, no-throw-sentinel-for<O> S >

requires std::constructible_from<std::iter_value_t<O>, std::iter_reference_t<I>>
uninitialized_copy_n_result<I, O>
uninitialized_copy_n( I ifirst, std::iter_difference_t<I> count,

O ofirst, S olast );
 (1) (C++20 起)
辅助类型
template<class I, class O>
using uninitialized_copy_n_result = ranges::in_out_result<I, O>;
 (2) (C++20 起)

令 \(\scriptsize N\)N 为 ranges::min(count, ranges::distance(ofirst, olast)) ，以始于 ifirst 的输入范围的元素为来源，在作为未初始化内存区域的输出范围 [ofirst, olast) 中构造 \(\scriptsize N\)N 个元素。

输入范围 [ifirst, ifirst + count) 必须不与输出范围 [ofirst, olast) 重叠。

若在初始化期间抛异常，则以未指定顺序销毁已构造的元素。

函数所拥有的效果等价于：

auto ret = ranges::uninitialized_copy(std::counted_iterator(ifirst, count),
                                      std::default_sentinel, ofirst, olast);
return {std::move(ret.in).base(), ret.out};

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

ifirst | - | 要复制的元素范围的起始
count | - | 要复制的元素数
ofirst, olast | - | 目标范围

返回值

{ifirst + N, ofirst + N} 。

复杂度

\(\scriptsize\mathcal{O}(N)\)𝓞(N) 。

异常

构造目标范围中的元素时抛出的异常，若存在。

注解

若输出范围的值类型为平凡类型 (TrivialType) ，则实现可能提升 ranges::uninitialized_copy_n 的效率，例如用 ranges::copy_n 。

可能的实现

struct uninitialized_copy_n_fn {
    template <std::input_iterator I, no-throw-input-iterator O, no-throw-sentinel-for<O> S>
    requires std::constructible_from<std::iter_value_t<O>, std::iter_reference_t<I>>
    ranges::uninitialized_copy_n_result<I, O>
    operator()( I ifirst, std::iter_difference_t<I> count, O ofirst, S olast ) const {
        O current {ofirst};
        try {
            for (; count > 0 && current != olast; ++ifirst, ++current, --count)
                ranges::construct_at(std::addressof(*current), *ifirst);
            return {std::move(ifirst), std::move(current)};
        } catch (...) { // 回滚：销毁构造的元素
            for (; ofirst != current; ++ofirst)
                ranges::destroy_at(std::addressof(*ofirst));
            throw;
        }
    }
};

inline constexpr uninitialized_copy_n_fn uninitialized_copy_n{};

示例

#include <iomanip>
#include <iostream>
#include <memory>
#include <string>

int main()
{
    const char* stars[] { "Procyon", "Spica", "Pollux", "Deneb", "Polaris", };

    constexpr int n {4};
    alignas(alignof(std::string)) char out[n * sizeof(std::string)];

    try
    {
        auto first {reinterpret_cast<std::string*>(out)};
        auto last {first + n};
        auto ret {std::ranges::uninitialized_copy_n(std::begin(stars), n, first, last)};

        std::cout << "{ ";
        for (auto it {first}; it != ret.out; ++it)
            std::cout << std::quoted(*it) << ", ";
        std::cout << "};\n";

        std::ranges::destroy(first, last);
    }
    catch(...)
    {
        std::cout << "uninitialized_copy_n exception\n";
    }
}

输出：

{ "Procyon", "Spica", "Pollux", "Deneb", };

参阅

ranges::uninitialized_copy (C++20) | 复制元素范围到未初始化的内存区域 (niebloid)
uninitialized_copy_n (C++11) | 将指定数量的对象复制到未初始化的内存区域 (函数模板)


std::ranges::uninitialized_default_construct

< cpp‎ | memory
定义于头文件 <memory>
调用签名
template <no-throw-forward-iterator I, no-throw-sentinel-for<I> S>

requires std::default_initializable<std::iter_value_t<I>>

I uninitialized_default_construct( I first, S last );
 (1) (C++20 起)
template <no-throw-forward-range R>

requires std::default_initializable<ranges::range_value_t<R>>
ranges::borrowed_iterator_t<R>

uninitialized_default_construct( R&& r );
 (2) (C++20 起)
1) 在 [first, last) 所指代的未初始化范围中构造以默认初始化构造 std::iter_value_t<I> 类型对象，如同用
for (; first != last; ++first)
    ::new (
        const_cast<void*>(static_cast<const volatile void*>(std::addressof(*first)))
        ) std::remove_reference_t<std::iter_reference_t<I>>;
若在初始化期间抛出异常，则以未指定顺序销毁已构造的对象。
2) 同 (1) ，但以 r 为范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要初始化的元素范围
r | - | 要初始化的元素范围

返回值

等于 last 的迭代器。

复杂度

与 first 和 last 间的距离成线性。

异常

构造目标范围中的元素时抛出的异常，若存在。

注解

若默认初始化 std::iter_value_t<I> 对象时不调用非平凡的默认构造函数，则实现可以跳过对象构造（而不更改可观察作用），这能由 std::is_trivially_default_constructible_v 检测。

可能的实现

struct uninitialized_default_construct_fn {
    template <no-throw-forward-iterator I, no-throw-sentinel-for<I> S>
    requires std::default_initializable<std::iter_value_t<I>>
    I operator()( I first, S last ) const {
        using ValueType = std::remove_reference_t<std::iter_reference_t<I>>;
        if constexpr (std::is_trivially_default_constructible_v<ValueType>)
            return ranges::next(first, last); // 跳过初始化
        I rollback {first};
        try {
            for (; !(first == last); ++first)
                ::new (const_cast<void*>(static_cast<const volatile void*>
                        (std::addressof(*first)))) ValueType;
            return first;
        } catch (...) { // 回滚：销毁构造的元素
            for (; rollback != first; ++rollback)
                ranges::destroy_at(std::addressof(*rollback));
            throw;
        }
    }

    template <no-throw-forward-range R>
    requires std::default_initializable<ranges::range_value_t<R>>
    ranges::borrowed_iterator_t<R>
    operator()( R&& r ) const {
        return (*this)(ranges::begin(r), ranges::end(r));
    }
};

inline constexpr uninitialized_default_construct_fn uninitialized_default_construct{};

示例

#include <cstring>
#include <iostream>
#include <memory>
#include <string>

int main()
{
    struct S { std::string m{ "▄▀▄▀▄▀▄▀" }; };

    constexpr int n {4};
    alignas(alignof(S)) char out[n * sizeof(S)];

    try
    {
        auto first {reinterpret_cast<S*>(out)};
        auto last {first + n};

        std::ranges::uninitialized_default_construct(first, last);

        auto count {1};
        for (auto it {first}; it != last; ++it) {
            std::cout << count++ << ' ' << it->m << '\n';
        }

        std::ranges::destroy(first, last);
    }
    catch(...) { std::cout << "Exception!\n"; }

    // 注意对于“平凡类型” uninitialized_default_construct 通常不以零填充给定的未初始化内存区域。
    constexpr char etalon[] { 'A', 'B', 'C', 'D', '\n' };
    char v[] { 'A', 'B', 'C', 'D', '\n' };
    std::ranges::uninitialized_default_construct(std::begin(v), std::end(v));
    if (std::memcmp(v, etalon, sizeof(v)) == 0) {
        std::cout << "  ";
        // 可能为未定义行为，待定的 CWG 1997 ：
        // for (const char c : v) { std::cout << c << ' '; }
        for (const char c : etalon) { std::cout << c << ' '; }
    } else {
        std::cout << "Unspecified\n";
    }
}

可能的输出：

1 ▄▀▄▀▄▀▄▀
2 ▄▀▄▀▄▀▄▀
3 ▄▀▄▀▄▀▄▀
4 ▄▀▄▀▄▀▄▀
  A B C D

参阅

ranges::uninitialized_default_construct_n (C++20) | 在起始与计数所定义的未初始化的内存区域以默认初始化构造对象 (niebloid)
ranges::uninitialized_value_construct (C++20) | 在范围所定义的未初始化的内存区域以值初始化构造对象 (niebloid)
ranges::uninitialized_value_construct_n (C++20) | 在起始与计数所定义的未初始化的内存区域以值初始化构造对象 (niebloid)
uninitialized_default_construct (C++17) | 在范围所定义的未初始化的内存区域以默认初始化构造对象 (函数模板)


std::ranges::uninitialized_default_construct_n

< cpp‎ | memory
定义于头文件 <memory>
调用签名
template <no-throw-forward-iterator I>

requires std::default_initializable<std::iter_value_t<I>>

I uninitialized_default_construct_n( I first, std::iter_difference_t<I> n );
 (C++20 起)

以默认初始化在始于 first 的未初始化存储中构造 n 个 std::iter_value_t<I> 类型对象，如同用

for (; n-- > 0; ++first)
  ::new (const_cast<void*>(static_cast<const volatile void*>(std::addressof(*first))))
      std::remove_reference_t<std::iter_reference_t<I>>;

若初始化期间抛出异常，则按未指定顺序销毁已构造的对象。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要初始化的元素范围
n | - | 要构造的元素数

返回值

对象范围的末尾（即 ranges::next(first, n) ）。

复杂度

与 n 成线性。

异常

构造目标范围中的元素时抛出的异常，若存在。

注解

若默认初始化 std::iter_value_t<I> 对象时不调用非平凡的默认构造函数，则实现可以跳过对象构造（而不更改可观察作用），这能由 std::is_trivially_default_constructible_v 检测。

可能的实现

struct uninitialized_default_construct_n_fn {
    template <no-throw-forward-iterator I>
    requires std::default_initializable<std::iter_value_t<I>>
    I operator()( I first, std::iter_difference_t<I> n ) const {
        using ValueType = std::remove_reference_t<std::iter_reference_t<I>>;
        if constexpr (std::is_trivially_default_constructible_v<ValueType>)
            return ranges::next(first, n); // 跳过初始化
        I rollback {first};
        try {
            for (; n-- > 0; ++first)
                ::new (const_cast<void*>(static_cast<const volatile void*>
                        (std::addressof(*first)))) ValueType;
            return first;
        } catch (...) { // 回滚：销毁已构造的元素
            for (; rollback != first; ++rollback)
                ranges::destroy_at(std::addressof(*rollback));
            throw;
        }
    }
};

inline constexpr uninitialized_default_construct_n_fn uninitialized_default_construct_n{};

示例

#include <cstring>
#include <iostream>
#include <memory>
#include <string>

int main()
{
    struct S { std::string m{ "█▓▒░ █▓▒░ " }; };

    constexpr int n {4};
    alignas(alignof(S)) char out[n * sizeof(S)];

    try
    {
        auto first {reinterpret_cast<S*>(out)};
        auto last = std::ranges::uninitialized_default_construct_n(first, n);

        auto count {1};
        for (auto it {first}; it != last; ++it) {
            std::cout << count++ << ' ' << it->m << '\n';
        }

        std::ranges::destroy(first, last);
    }
    catch(...) { std::cout << "Exception!\n"; }

    // 注意 uninitialized_default_construct_n 对“平凡类型”
    // 通常不会以零填充给定的未初始化内存区域。
    constexpr int etalon[] { 1, 2, 3, 4, 5, 6 };
    int v[] { 1, 2, 3, 4, 5, 6 };
    std::ranges::uninitialized_default_construct_n(std::begin(v), std::size(v));
    if (std::memcmp(v, etalon, sizeof(v)) == 0) {
        // 可能为未定义行为，待决的 CWG 1997 ：
        // for (const int i : v) { std::cout << i << ' '; }
        for (const int i : etalon) { std::cout << i << ' '; }
    } else {
        std::cout << "Unspecified!";
    }
    std::cout << '\n';
}

可能的输出：

1 █▓▒░ █▓▒░
2 █▓▒░ █▓▒░
3 █▓▒░ █▓▒░
4 █▓▒░ █▓▒░
1 2 3 4 5 6

参阅

ranges::uninitialized_default_construct (C++20) | 在范围所定义的未初始化的内存区域以默认初始化构造对象 (niebloid)
ranges::uninitialized_value_construct (C++20) | 在范围所定义的未初始化的内存区域以值初始化构造对象 (niebloid)
ranges::uninitialized_value_construct_n (C++20) | 在起始与计数所定义的未初始化的内存区域以值初始化构造对象 (niebloid)
uninitialized_default_construct_n (C++17) | 在起始和计数所定义的未初始化内存区域用默认初始化构造对象 (函数模板)


std::ranges::uninitialized_fill

< cpp‎ | memory
定义于头文件 <memory>
调用签名
template< no-throw-forward-iterator I, no-throw-sentinel-for<I> S, class T >

requires std::constructible_from<std::iter_value_t<I>, const T&>

I uninitialized_fill( I first, S last, const T& x );
 (1) (C++20 起)
template< no-throw-forward-range R, class T >

requires std::constructible_from<ranges::range_value_t<R>, const T&>
ranges::borrowed_iterator_t<R>

uninitialized_fill( R&& r, const T& x );
 (2) (C++20 起)
1) 在范围 [first, last) 所指代的未初始化内存区域构造给定值 x 的 \(\scriptsize N\)N 个副本，其中 \(\scriptsize N\)N 为 ranges::distance(first, last) 。
函数所拥有的效果等价于：
for (; first != last; ++first) {
    ::new (
        const_cast<void*>(static_cast<const volatile void*>(std::addressof(*first)))
        ) std::remove_reference_t<std::iter_reference_t<I>>(x);
}
return first;
若在初始化期间抛异常，则以未指定顺序销毁已构造的对象。
2) 同 (1) ，但以 r 为源范围，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要初始化的元素范围
r | - | 要初始化的元素范围
value | - | 用以构造元素的值

返回值

等于 last 的迭代器。

复杂度

\(\scriptsize\mathcal{O}(N)\)𝓞(N) 。

异常

构造目标范围中的元素时抛出的异常，若存在。

注解

若输出范围的值类型为 平凡类型 (TrivialType) ，则实现可以提升 ranges::uninitialized_fill 的效率，例如用 ranges::fill 。

可能的实现

struct uninitialized_fill_fn {
    template <no-throw-forward-iterator I, no-throw-sentinel-for<I> S, class T>
    requires std::constructible_from<std::iter_value_t<I>, const T&>
    I operator()( I first, S last, const T& x ) const {
        I rollback {first};
        try {
            for (; !(first == last); ++first)
                ranges::construct_at(std::addressof(*first), x);
            return first;
        } catch (...) { // 回滚：销毁已构造的元素
            for (; rollback != first; ++rollback)
                ranges::destroy_at(std::addressof(*rollback));
            throw;
        }
    }

    template <no-throw-forward-range R, class T>
    requires std::constructible_from<ranges::range_value_t<R>, const T&>
    ranges::borrowed_iterator_t<R>
    operator()( R&& r, const T& x ) const {
        return (*this)(ranges::begin(r), ranges::end(r), x);
    }
};

inline constexpr uninitialized_fill_fn uninitialized_fill{};

示例

#include <iostream>
#include <memory>
#include <string>

int main()
{
    constexpr int n {4};
    alignas(alignof(std::string)) char out[n * sizeof(std::string)];

    try
    {
        auto first {reinterpret_cast<std::string*>(out)};
        auto last {first + n};
        std::ranges::uninitialized_fill(first, last, "▄▀▄▀▄▀▄▀");

        int count {1};
        for (auto it {first}; it != last; ++it) {
            std::cout << count++ << ' ' << *it << '\n';
        }

        std::ranges::destroy(first, last);
    }
    catch(...)
    {
        std::cout << "Exception!\n";
    }
}

输出：

1 ▄▀▄▀▄▀▄▀
2 ▄▀▄▀▄▀▄▀
3 ▄▀▄▀▄▀▄▀
4 ▄▀▄▀▄▀▄▀

参阅

ranges::uninitialized_fill_n (C++20) | 复制一个对象到起始与计数所定义的未初始化的内存区域 (niebloid)
uninitialized_fill | 复制一个对象到以范围定义的未初始化内存区域 (函数模板)


std::ranges::uninitialized_fill_n

< cpp‎ | memory
定义于头文件 <memory>
调用签名
template <no-throw-forward-range I, class T>

requires std::constructible_from<std::iter_value_t<I>, const T&>

I uninitialized_fill_n( I first, std::iter_difference_t<I> n, const T& x );
 (C++20 起)

在范围 [first, first + n) 所指代的未初始化内存区域构造给定值 x 的 n 个副本，如同用

for (; n--; ++first) {
    ::new (
        const_cast<void*>(static_cast<const volatile void*>(std::addressof(*first)))
        ) std::remove_reference_t<std::iter_reference_t<I>>(x);
}

若初始化期间抛出异常，则以未指定顺序销毁已构造的对象。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first | - | 要初始化的元素范围的起始
n | - | 构造的元素数
x | - | 用以构造元素的值

返回值

等于 first + n 的迭代器。

复杂度

与 n 成线性。

异常

构造目标范围中的元素时抛出的异常，若存在。

注解

若输出范围的值类型为平凡类型 (TrivialType) ，则实现可能提升 ranges::uninitialized_fill_n 的效率，例如用 ranges::fill_n 。

可能的实现

struct uninitialized_fill_n_fn {
    template <no-throw-forward-range I, class T>
    requires std::constructible_from<std::iter_value_t<I>, const T&>
    I operator()( I first, std::iter_difference_t<I> n, const T& x ) const {
        I rollback {first};
        try {
            for (; n-- > 0; ++first)
                ranges::construct_at(std::addressof(*first), x);
            return first;
        } catch (...) { // 回滚：销毁已构造的元素
            for (; rollback != first; ++rollback)
                ranges::destroy_at(std::addressof(*rollback));
            throw;
        }
    }
};

inline constexpr uninitialized_fill_n_fn uninitialized_fill_n{};

示例

#include <iostream>
#include <memory>
#include <string>

int main()
{
    constexpr int n {3};
    alignas(alignof(std::string)) char out[n * sizeof(std::string)];

    try
    {
        auto first {reinterpret_cast<std::string*>(out)};
        auto last = std::ranges::uninitialized_fill_n(first, n, "cppreference");

        for (auto it {first}; it != last; ++it) {
            std::cout << *it << '\n';
        }

        std::ranges::destroy(first, last);
    }
    catch(...)
    {
        std::cout << "Exception!\n";
    }
}

输出：

cppreference
cppreference
cppreference

参阅

ranges::uninitialized_fill (C++20) | 复制一个对象到范围所定义的未初始化的内存区域 (niebloid)
uninitialized_fill_n | 复制一个对象到以起点和计数定义的未初始化内存区域 (函数模板)


std::ranges::uninitialized_move, std::ranges::uninitialized_move_result

< cpp‎ | memory
定义于头文件 <memory>
调用签名
template< std::input_iterator I, std::sentinel_for<I> S1,

no-throw-forward-iterator O, no-throw-sentinel-for<O> S2 >
requires std::constructible_from<std::iter_value_t<O>,
std::iter_rvalue_reference_t<I>>
uninitialized_move_result<I, O>

uninitialized_move( I ifirst, S1 ilast, O ofirst, S2 olast );
 (1) (C++20 起)
template< ranges::input_range IR, no-throw-forward-range OR >

requires std::constructible_from<ranges::range_value_t<OR>,
ranges::range_rvalue_reference_t<IR>>
uninitialized_move_result<ranges::borrowed_iterator_t<IR>,
ranges::borrowed_iterator_t<OR>>

uninitialized_move( IR&& in_range, OR&& out_range );
 (2) (C++20 起)
辅助类型
template<class I, class O>
using uninitialized_move_result = ranges::in_out_result<I, O>;
 (3) (C++20 起)
1) 从输入范围 [ifirst, ilast) 移动 N 元素到输出范围 [ofirst, olast) （为未初始化内存区域），其中 N 为 min(ranges::distance(ifirst, ilast), ranges::distance(ofirst, olast)) 。
效果等价于：
for (; ifirst != ilast && ofirst != olast; ++ofirst, ++ifirst)
    ::new (const_cast<void*>(static_cast<const volatile void*>(std::addressof(*first))))
        std::remove_reference_t<std::iter_reference_t<O>>(ranges::iter_move(ifirst));
若在初始化期间抛出异常，则以未指定顺序销毁 [ofirst, olast) 中已构造的元素。而且 [ifirst, ilast) 中已被移动的元素被置于合法但未指定的状态。
2) 同 (1) ，但以 in_range 为第一范围并以 out_range 为第二范围，如同以 ranges::begin(in_range) 为 ifirst ，以 ranges::end(in_range) 为 ilast ，以 ranges::begin(out_range) 为 ofirst ，并以 ranges::end(out_range) 为 olast 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参阅

ifirst, ilast | - | 要移动的输入元素范围
ofirst, olast | - | 要初始化的输出范围
in_range | - | 要移动的输入元素范围
out_range | - | 要初始化的输出范围

返回值

{ifirst + N, ofirst + N} 。

复杂度

与 N 成线性。

异常

构造目标范围中的元素时抛出的异常，若存在。

注解

若输出范围的值类型为平凡类型 (TrivialType) ，则实现可能提升 ranges::uninitialized_move 的效率，例如用 ranges::copy_n 。

可能的实现

struct uninitialized_move_fn {
    template <std::input_iterator I, std::sentinel_for<I> S1,
             no-throw-forward-iterator O, no-throw-sentinel-for<O> S2>
    requires std::constructible_from<std::iter_value_t<O>,
             std::iter_rvalue_reference_t<I>>
    ranges::uninitialized_move_result<I, O>
    operator()( I ifirst, S1 ilast, O ofirst, S2 olast ) const {
        O current {ofirst};
        try {
            for (; !(ifirst == ilast or current == olast); ++ifirst, ++current)
                ::new (const_cast<void*>(static_cast<const volatile void*>
                    (std::addressof(*current)))) std::remove_reference_t<
                        std::iter_reference_t<O>>(ranges::iter_move(ifirst));
            return {std::move(ifirst), std::move(current)};
        } catch (...) { // 回滚：析构已构造的元素
            for (; ofirst != current; ++ofirst)
                ranges::destroy_at(std::addressof(*ofirst));
            throw;
        }
    }

    template <ranges::input_range IR, no-throw-forward-range OR>
    requires std::constructible_from<ranges::range_value_t<OR>,
             ranges::range_rvalue_reference_t<IR>>
    ranges::uninitialized_move_result<ranges::borrowed_iterator_t<IR>,
             ranges::borrowed_iterator_t<OR>>
    operator()( IR&& in_range, OR&& out_range ) const {
        return (*this)(ranges::begin(in_range), ranges::end(in_range),
                       ranges::begin(out_range), ranges::end(out_range));
    }
};

inline constexpr uninitialized_move_fn uninitialized_move{};

示例

#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <memory>
#include <string>

void print(auto rem, auto first, auto last) {
    for (std::cout << rem; first != last; ++first)
        std::cout << std::quoted(*first) << ' ';
    std::cout << '\n';
}

int main() {
    std::string in[] { "Home", "World" };
    print("initially, in: ", std::begin(in), std::end(in));

    if (
        constexpr auto sz = std::size(in);
        void* out = std::aligned_alloc(alignof(std::string), sizeof(std::string) * sz)
    ) {
        try {
            auto first {static_cast<std::string*>(out)};
            auto last {first + sz};
            std::ranges::uninitialized_move(std::begin(in), std::end(in), first, last);

            print("after move, in: ", std::begin(in), std::end(in));
            print("after move, out: ", first, last);

            std::ranges::destroy(first, last);
        }
        catch (...) {
            std::cout << "Exception!\n";
        }
        std::free(out);
    }
}

可能的输出：

initially, in: "Home" "World"
after move, in: "" ""
after move, out: "Home" "World"

参阅

ranges::uninitialized_move_n (C++20) | 移动一定量对象到未初始化的内存区域 (niebloid)
uninitialized_move (C++17) | 移动一个范围的对象到未初始化的内存区域 (函数模板)


std::ranges::uninitialized_move_n, std::ranges::uninitialized_move_n_result

< cpp‎ | memory
定义于头文件 <memory>
调用签名
template <std::input_iterator I, no-throw-forward-iterator O,

no-throw-sentinel-for<O> S>
requires std::constructible_from<std::iter_value_t<O>,
std::iter_rvalue_reference_t<I>>
uninitialized_move_n_result<I, O>

uninitialized_move_n( I ifirst, std::iter_difference_t<I> n, O ofirst, S olast );
 (1) (C++20 起)
辅助类型
template<class I, class O>
using uninitialized_move_n_result = ranges::in_out_result<I, O>;
 (2) (C++20 起)

从始于 ifirst 的输入范围移动 N 个元素到范围 [ofirst, olast) 所指代的未初始化存储，其中 N 为 min(n, ranges::distance(ofirst, olast)) 。

效果等价于：

for (; n-- > 0 && ofirst != olast; ++ifirst, ++ofirst)
    ::new (const_cast<void*>(static_cast<const volatile void*>(std::addressof(*first))))
        std::remove_reference_t<std::iter_reference_t<O>>(ranges::iter_move(ifirst));

若在初始化期间抛出异常，则以未指定顺序析构 [ofirst, olast) 中已构造的读写。另外，在始于 ifirst 的范围中的已被移动的对象被置于合法但未指定的状态。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

ifirst | - | 要移动的输入范围的起始
ofirst, olast | - | 要初始化的输入范围
n | - | 要移动的元素数

返回值

{ifirst + N, ofirst + N} 。

复杂度

与 N 成线性。

异常

构造目标范围中的元素时抛出的异常，若存在。

注解

若输出范围的值类型为平凡类型 (TrivialType) ，则实现可能提升 ranges::uninitialized_move_n 的效率，例如用 ranges::copy_n 。

可能的实现

struct uninitialized_move_n_fn {
    template <std::input_iterator I, no-throw-forward-iterator O,
             no-throw-sentinel-for<O> S>
    requires std::constructible_from<std::iter_value_t<O>,
             std::iter_rvalue_reference_t<I>>
    ranges::uninitialized_move_n_result<I, O>
    operator()( I ifirst, std::iter_difference_t<I> n, O ofirst, S olast ) const {
        O current {ofirst};
        try {
            for (; n-- > 0 && current != olast; ++ifirst, ++current)
                ::new (const_cast<void*>(static_cast<const volatile void*>
                    (std::addressof(*current)))) std::remove_reference_t<
                        std::iter_reference_t<O>>(ranges::iter_move(ifirst));
            return {std::move(ifirst), std::move(current)};
        } catch (...) { // 回滚：析构已构造的元素
            for (; ofirst != current; ++ofirst)
                ranges::destroy_at(std::addressof(*ofirst));
            throw;
        }
    }
};

inline constexpr uninitialized_move_n_fn uninitialized_move_n{};

示例

#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <memory>
#include <string>

void print(auto rem, auto first, auto last) {
    for (std::cout << rem; first != last; ++first)
        std::cout << std::quoted(*first) << ' ';
    std::cout << '\n';
}

int main() {
    std::string in[] { "No", "Diagnostic", "Required", };
    print("initially, in: ", std::begin(in), std::end(in));

    if (
        constexpr auto sz = std::size(in);
        void* out = std::aligned_alloc(alignof(std::string), sizeof(std::string) * sz)
    ) {
        try {
            auto first {static_cast<std::string*>(out)};
            auto last {first + sz};
            std::ranges::uninitialized_move_n(std::begin(in), sz, first, last);

            print("after move, in: ", std::begin(in), std::end(in));
            print("after move, out: ", first, last);

            std::ranges::destroy(first, last);
        }
        catch (...) {
            std::cout << "Exception!\n";
        }
        std::free(out);
    }
}

可能的输出：

initially, in: "No" "Diagnostic" "Required"
after move, in: "" "" ""
after move, out: "No" "Diagnostic" "Required"

参阅

ranges::uninitialized_move (C++20) | 移动对象范围到未初始化的内存区域 (niebloid)
uninitialized_move_n (C++17) | 移动一定数量对象到未初始化内存区域 (函数模板)


std::ranges::uninitialized_value_construct

< cpp‎ | memory
定义于头文件 <memory>
调用签名
template <no-throw-forward-iterator I, no-throw-sentinel-for<I> S>

requires std::default_initializable<std::iter_value_t<I>>

I uninitialized_value_construct( I first, S last );
 (1) (C++20 起)
template <no-throw-forward-range R>

requires std::default_initializable<ranges::range_value_t<R>>
ranges::borrowed_iterator_t<R>

uninitialized_value_construct( R&& r );
 (2) (C++20 起)
1) 以值初始化在范围 [first, last) 所指代的未初始化存储中构造 std::iter_value_t<I> 类型对象，如同用
for (; first != last; ++first)
  ::new (const_cast<void*>(static_cast<const volatile void*>(std::addressof(*first))))
    std::remove_reference_t<std::iter_reference_t<I>>();
若初始化期间抛出异常，则按未指定顺序销毁已构造的对象。
2) 同 (1) ，但以 r 为迭代器，如同以 ranges::begin(r) 为 first 并以 ranges::end(r) 为 last 。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要值初始化的元素范围
r | - | 要值初始化的元素范围

返回值

等于 last 的迭代器。

复杂度

与 first 和 last 间的距离成线性。

异常

构造目标范围中的元素时抛出的异常，若存在。

注解

若范围的值类型为平凡类型 (TrivialType) 及 可复制赋值 (CopyAssignable) ，则实现可以提升 ranges::uninitialized_value_construct 的效率，例如用 ranges::fill 。

可能的实现

struct uninitialized_value_construct_fn {
    template <no-throw-forward-iterator I, no-throw-sentinel-for<I> S>
    requires std::default_initializable<std::iter_value_t<I>>
    I operator()( I first, S last ) const {
        using T = std::remove_reference_t<std::iter_reference_t<I>>;
        if constexpr (std::is_trivial_v<T> && std::is_copy_assignable_v<T>)
            return ranges::fill(first, last, T());
        I rollback {first};
        try {
            for (; !(first == last); ++first)
                ::new (const_cast<void*>(static_cast<const volatile void*>
                        (std::addressof(*first)))) T();
            return first;
        } catch (...) { // 回滚：销毁已构造的元素
            for (; rollback != first; ++rollback)
                ranges::destroy_at(std::addressof(*rollback));
            throw;
        }
    }

    template <no-throw-forward-range R>
    requires std::default_initializable<ranges::range_value_t<R>>
    ranges::borrowed_iterator_t<R>
    operator()( R&& r ) const {
        return (*this)(ranges::begin(r), ranges::end(r));
    }
};

inline constexpr uninitialized_value_construct_fn uninitialized_value_construct{};

示例

#include <iostream>
#include <memory>
#include <string>

int main()
{
    struct S { std::string m{ "▄▀▄▀▄▀▄▀" }; };

    constexpr int n {4};
    alignas(alignof(S)) char out[n * sizeof(S)];

    try
    {
        auto first {reinterpret_cast<S*>(out)};
        auto last {first + n};

        std::ranges::uninitialized_value_construct(first, last);

        auto count {1};
        for (auto it {first}; it != last; ++it) {
            std::cout << count++ << ' ' << it->m << '\n';
        }

        std::ranges::destroy(first, last);
    }
    catch(...)
    {
        std::cout << "Exception!\n";
    }

    // Notice that for "trivial types" the uninitialized_value_construct
    // zero-fills the given uninitialized memory area.
    int v[] { 0, 1, 2, 3 };
    std::cout << ' ';
    for (const int i : v) { std::cout << ' ' << static_cast<char>(i + 'A'); }
    std::cout << "\n ";
    std::ranges::uninitialized_value_construct(std::begin(v), std::end(v));
    for (const int i : v) { std::cout << ' ' << static_cast<char>(i + 'A'); }
    std::cout << '\n';
}

输出：

1 ▄▀▄▀▄▀▄▀
2 ▄▀▄▀▄▀▄▀
3 ▄▀▄▀▄▀▄▀
4 ▄▀▄▀▄▀▄▀
  A B C D
  A A A A

参阅

ranges::uninitialized_value_construct_n (C++20) | 在起始与计数所定义的未初始化的内存区域以值初始化构造对象 (niebloid)
ranges::uninitialized_default_construct (C++20) | 在范围所定义的未初始化的内存区域以默认初始化构造对象 (niebloid)
ranges::uninitialized_default_construct_n (C++20) | 在起始与计数所定义的未初始化的内存区域以默认初始化构造对象 (niebloid)
uninitialized_value_construct (C++17) | 在范围所定义的未初始化内存中用值初始化构造对象 (函数模板)


std::ranges::uninitialized_value_construct_n

< cpp‎ | memory
定义于头文件 <memory>
调用签名
template <no-throw-forward-iterator I>

requires std::default_initializable<std::iter_value_t<I>>

I uninitialized_value_construct_n( I first, std::iter_difference_t<I> n );
 (C++20 起)

以值初始化在始于 first 的未初始化存储中构造 n 个 std::iter_value_t<I> 类型对象，如同用

for (; n-- > 0; ++first)
  ::new (const_cast<void*>(static_cast<const volatile void*>(std::addressof(*first))))
      std::remove_reference_t<std::iter_reference_t<I>>();

若初始化期间抛出异常，则按未指定顺序销毁已构造的对象。

此页面上描述的仿函数实体是 niebloid ，即：

  • 调用它们中的任何一者时不可指定显式模板实参。
  • 它们无一对实参依赖查找可见。
  • 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

参数

first, last | - | 要初始化的元素范围
n | - | 要构造的元素数

返回值

对象范围的末尾（即 ranges::next(first, n) ）。

复杂度

与 n 成线性。

异常

构造目标范围中的元素时抛出的异常，若存在。

注解

若范围的值类型为平凡类型 (TrivialType) 及 可复制赋值 (CopyAssignable) ，则实现可以提升 ranges::uninitialized_value_construct_n 的效率，例如用 ranges::fill 。

可能的实现

struct uninitialized_value_construct_n_fn {
    template <no-throw-forward-iterator I>
    requires std::default_initializable<std::iter_value_t<I>>
    I operator()( I first, std::iter_difference_t<I> n ) const {
        using T = std::remove_reference_t<std::iter_reference_t<I>>;
        if constexpr (std::is_trivial_v<T> && std::is_copy_assignable_v<T>)
            return ranges::fill_n(first, n, T());
        I rollback {first};
        try {
            for (; n-- > 0; ++first)
                ::new (const_cast<void*>(static_cast<const volatile void*>
                        (std::addressof(*first)))) T();
            return first;
        } catch (...) { // 回滚：销毁已构造的元素
            for (; rollback != first; ++rollback)
                ranges::destroy_at(std::addressof(*rollback));
            throw;
        }
    }
};

inline constexpr uninitialized_value_construct_n_fn uninitialized_value_construct_n{};

示例

#include <iostream>
#include <memory>
#include <string>

int main()
{
    struct S { std::string m{ "█▓▒░ █▓▒░ █▓▒░ " }; };

    constexpr int n {4};
    alignas(alignof(S)) char out[n * sizeof(S)];

    try
    {
        auto first {reinterpret_cast<S*>(out)};
        auto last = std::ranges::uninitialized_value_construct_n(first, n);

        auto count {1};
        for (auto it {first}; it != last; ++it) {
            std::cout << count++ << ' ' << it->m << '\n';
        }

        std::ranges::destroy(first, last);
    }
    catch(...)
    {
        std::cout << "Exception!\n";
    }

    // 注意对于“平凡类型” the uninitialized_value_construct_n 零初始化给定的未初始化内存区域。
    int v[] { 1, 2, 3, 4, 5, 6, 7, 8 };
    std::cout << ' ';
    for (const int i : v) { std::cout << i << ' '; }
    std::cout << "\n ";
    std::ranges::uninitialized_value_construct_n(std::begin(v), std::size(v));
    for (const int i : v) { std::cout << i << ' '; }
    std::cout << '\n';
}

输出：

1 █▓▒░ █▓▒░ █▓▒░
2 █▓▒░ █▓▒░ █▓▒░
3 █▓▒░ █▓▒░ █▓▒░
4 █▓▒░ █▓▒░ █▓▒░
1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0

参阅

ranges::uninitialized_value_construct (C++20) | 在范围所定义的未初始化的内存区域以值初始化构造对象 (niebloid)
ranges::uninitialized_default_construct (C++20) | 在范围所定义的未初始化的内存区域以默认初始化构造对象 (niebloid)
ranges::uninitialized_default_construct_n (C++20) | 在起始与计数所定义的未初始化的内存区域以默认初始化构造对象 (niebloid)
uninitialized_value_construct_n (C++17) | 在起始和计数所定义的未初始化内存区域以值初始化构造对象 (函数模板)


std::raw_storage_iterator

< cpp‎ | memory
定义于头文件 <memory> |
template< class OutputIt, class T > class raw_storage_iterator : public std::iterator < std::output_iterator_tag, void, void, void, void>; | (C++17 前)
template< class OutputIt, class T > class raw_storage_iterator; | (C++17 起) (弃用) (C++20 中移除)

输出迭代器 std::raw_storage_iterator 使得标准算法能存储结果于未初始化内存。凡在算法写 T 类型对象到解引用后的迭代器时，对象被复制构造到该迭代器所指向的未初始化存储中的位置。模板形参 OutputIt 是任何满足老式输出迭代器 (LegacyOutputIterator) 要求的类型，并拥有定义为返回对象的 operator* ， operator& 对该对象返回 T* 类型值。通常，以类型 T* 为 OutputIt 。

类型要求

-
OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。

成员函数

(构造函数) | 创建新的 raw_storage_iterator (公开成员函数)
operator= | 在缓冲区中的被指向位置构造对象 (公开成员函数)
operator* | 解引用迭代器 (公开成员函数)
operator++operator++(int) | 推进迭代器 (公开成员函数)
base (C++17 起) | 提供到被包装迭代器的访问 (公开成员函数)

成员类型

成员类型 | 定义
iterator_category | std::output_iterator_tag
value_type | void
difference_type
void | (C++20 前)
std::ptrdiff_t | (C++20 起)
pointer | void
reference | void

要求通过从 std::iterator < std::output_iterator_tag, void, void, void, void> 继承获得成员类型 iterator_category、 value_type、 difference_type、 pointer 及 reference 。

 (C++17 前)

示例

#include <iostream>
#include <string>
#include <memory>
#include <algorithm>

int main()
{
    const std::string s[] = {"This", "is", "a", "test", "."};
    std::string* p = std::allocator<std::string>().allocate(5);

    std::copy(std::begin(s), std::end(s),
              std::raw_storage_iterator<std::string*, std::string>(p));

    for(std::string* i = p; i!=p+5; ++i) {
        std::cout << *i << '\n';
        i->~basic_string<char>();
    }
    std::allocator<std::string>().deallocate(p, 5);
}

输出：

This
is
a
test
.

参阅

allocator_traits (C++11) | 提供关于分配器类型的信息 (类模板)
scoped_allocator_adaptor (C++11) | 为多级容器实现的多级分配器 (类模板)
uses_allocator (C++11) | 检查指定的类型是否支持使用分配器的构造 (类模板)


std::raw_storage_iterator<OutputIt,T>::base

< cpp‎ | memory‎ | raw storage iterator
OutputIt base() const; | (C++17 起)

提供到传入此 raw_storage_iterator 构造函数的迭代器的访问。

参数

（无）

返回值

与 *this 指向同一对象的迭代器。


std::raw_storage_iterator<OutputIt,T>::operator*

< cpp‎ | memory‎ | raw storage iterator
raw_storage_iterator& operator*();

解引用迭代器。

参数

（无）

返回值

*this


std::raw_storage_iterator<OutputIt,T>::operator=

< cpp‎ | memory‎ | raw storage iterator
raw_storage_iterator& operator=( const T& el ); | (1) |
raw_storage_iterator& operator=( T&& el ); | (2) | (C++17 起)
1) 从 el 构造位于迭代器所指向位置的值。
2) 从 std::move(el) 构造位于迭代器所指向位置的值。

参数

el - 复制或移动来源的值

返回值

*this


std::raw_storage_iterator<OutputIt,T>::operator++, operator++(int)

< cpp‎ | memory‎ | raw storage iterator
raw_storage_iterator& operator++();
raw_storage_iterator operator++(int);

推进迭代器。

1) 前自增。返回更新后的迭代器。
2) 后自增。返回迭代器的旧值。

参数

（无）

返回值

1) *this
2) 迭代器的旧值。


std::raw_storage_iterator<OutputIt,T>::raw_storage_iterator

< cpp‎ | memory‎ | raw storage iterator
explicit raw_storage_iterator( OutputIt it );

初始化迭代器为指向与 it 所指向的相同值。

参数

it - 要指向的位置


std::return_temporary_buffer

< cpp‎ | memory
定义于头文件 <memory> |
template< class T > void return_temporary_buffer( T* p ); | (C++17 中弃用) (C++20 中移除)

解分配先前以 std::get_temporary_buffer 分配的存储。

参数

p - 指向先前由 std::get_temporary_buffer 分配的存储，且未被之前到 return_temporary_buffer 的调用非法化的指针

返回值

（无）

异常

不抛出。

示例

#include <algorithm>
#include <iostream>
#include <memory>
#include <string>
#include <iterator>

int main()
{
    const std::string s[] = {"string", "1", "test", "..."};
    const auto p = std::get_temporary_buffer<std::string>(4);
    // 要求将 p.first 传递给 return_temporary_buffer
    // （当心提前退出和异常）

    std::copy(s, s + p.second,
              std::raw_storage_iterator<std::string*, std::string>(p.first));
    // 要求单独销毁每个 p 中的 string
    // （当心提前退出和异常）

    std::copy(p.first, p.first + p.second,
              std::ostream_iterator<std::string>{std::cout, "\n"});

    std::for_each(p.first, p.first + p.second, [](std::string& e) {
        e.~basic_string<char>();
    });

    std::return_temporary_buffer(p.first);
}

输出：

string
1
test
...

参阅

get_temporary_buffer
(C++17 中弃用)(C++20 中移除)
 获得未初始化存储
(函数模板)


std::scoped_allocator_adaptor

< cpp‎ | memory
定义于头文件 <scoped_allocator> |
template< class OuterAlloc, class... InnerAlloc > class scoped_allocator_adaptor : public OuterAlloc; | (C++11 起)

std::scoped_allocator_adaptor 类模板是可用于多层容器（ map 的 list 的 set 的 vector 等等）的分配器。它以外层分配器类型 OuterAlloc 与零或更多个内层分配器类型 InnerAlloc... 实例化。直接以 scoped_allocator_adaptor 构造的容器用 OuterAlloc 分配其元素，但若元素自身是容器，则它使用首个内存分配器。该容器的元素，若其自身是容器，则使用第二个内存分配器，以此类推。若容器的层级多于内层分配器的数量，则最内层分配器为所有进一步内嵌的容器再度使用。

此适配器的目的是在内嵌容器中正确初始化有状态分配器，例如在所有层次的嵌套容器都必须置于同一共享内存段时。适配器的构造函数接收列表中所有分配器的参数，而每个内嵌容器从适配器按需获得其分配器的状态。

为了 scoped_allocator_adaptor 的目的，若下个内层分配器是 A ，则任何满足 std::uses_allocator <T,A>::value == true 的类 T 参与递归，如同它是容器，另外， std::pair 被当做这种容器，通过 scoped_allocator_adaptor::construct 的指定重载。

典型实现保有一个 std::scoped_allocator_adaptor<InnerAllocs...> 作为成员对象。

成员类型

类型 | 定义
outer_allocator_type | OuterAlloc
inner_allocator_type | scoped_allocator_adaptor<InnerAllocs...> ，或若 sizeof...(InnerAllocs) == 0 则为 scoped_allocator_adaptor<OuterAlloc>
value_type | std::allocator_traits <OuterAlloc>::value_type
size_type | std::allocator_traits <OuterAlloc>::size_type
difference_type | std::allocator_traits <OuterAlloc>::difference_type
pointer | std::allocator_traits <OuterAlloc>::pointer
const_pointer | std::allocator_traits <OuterAlloc>::const_pointer
void_pointer | std::allocator_traits <OuterAlloc>::void_pointer
const_void_pointer | std::allocator_traits <OuterAlloc>::const_void_pointer
propagate_on_container_copy_assignment
若 std::allocator_traits <A>::propagate_on_container_copy_assignment::value 对于 OuterAlloc 与 InnerAlloc... 之中至少一个分配器为 true 则为 std::true_type
propagate_on_container_move_assignment
若 {std::allocator_traits <A>::propagate_on_container_move_assignment::value 对于 OuterAlloc 与 InnerAlloc... 之中至少一个分配器为 true 则为 std::true_type
propagate_on_container_swap
若 std::allocator_traits <A>::propagate_on_container_swap::value 对于 OuterAlloc 与 InnerAlloc... 之中至少一个分配器为 true 则为 std::true_type
is_always_equal(C++17)
若 std::allocator_traits <A>::is_always_equal::value 对于 OuterAlloc 与 InnerAlloc... 中每个分配器为 true 则为 std::true_type
rebind
template< class T >
struct rebind {
    typedef scoped_allocator_adaptor<
        std::allocator_traits<OuterAlloc>::template rebind_alloc<T>,
        InnerAllocs...
    > other;
};

成员函数

(构造函数) | 创建新的 scoped_allocator_adaptor 实例 (公开成员函数)
(析构函数) | 析构 scoped_allocator_adaptor 实例 (公开成员函数)
operator= | 赋值一个 scoped_allocator_adaptor (公开成员函数)
inner_allocator | 获得一个 inner_allocator 引用 (公开成员函数)
outer_allocator | 获得一个 outer_allocator 引用 (公开成员函数)
allocate | 用外层分配器分配未初始化存储 (公开成员函数)
deallocate | 用外层分配器解分配存储 (公开成员函数)
max_size | 返回外层分配器所支持的最大分配大小 (公开成员函数)
construct | 在分配的存储上构造一个对象，若适合则传递内存分配器至其构造函数 (公开成员函数)
destroy | 析构处于分配的存储的对象 (公开成员函数)
select_on_container_copy_construction | 复制 scoped_allocator_adaptor 与其所有分配器的状态 (公开成员函数)

非成员函数

operator==operator!=
(C++20 中移除)
 比较两个 scoped_allocator_adaptor 实例
(公开成员函数)

推导指引 (C++17 起)

示例

#include <vector>
#include <scoped_allocator>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/adaptive_pool.hpp>
namespace bi = boost::interprocess;
template<class T> using alloc = bi::adaptive_pool<T,
                                    bi::managed_shared_memory::segment_manager>;
using ipc_row = std::vector<int, alloc<int>>;
using ipc_matrix = std::vector<ipc_row, std::scoped_allocator_adaptor<alloc<ipc_row>>>;
int main ()
{
   bi::managed_shared_memory s(bi::create_only, "Demo", 65536);

   // 在共享内存中创建 vector 的 vector
   ipc_matrix v(s.get_segment_manager());

   // 对于所有这些附加项，内层 vector 从外层 vector 的 scoped_allocator_adaptor
   // 获得其分配器参数
   v.resize(1); v[0].push_back(1);
   v.emplace_back(2);
   std::vector<int> local_row = {1,2,3};
   v.emplace_back(local_row.begin(), local_row.end());

   bi::shared_memory_object::remove("Demo");
}

参阅

allocator_traits (C++11) | 提供关于分配器类型的信息 (类模板)
uses_allocator (C++11) | 检查指定的类型是否支持使用分配器的构造 (类模板)
allocator | 默认的分配器 (类模板)


std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...>::allocate

< cpp‎ | memory‎ | scoped allocator adaptor
定义于头文件 <scoped_allocator> |
 | (1)
pointer allocate( size_type n ); |  | (C++11 起) (C++20 前)
[[nodiscard]] pointer allocate( size_type n ); |  | (C++20 起)
 | (2)
pointer allocate( size_type n, const_void_pointer hint ); |  | (C++11 起) (C++20 前)
[[nodiscard]] pointer allocate( size_type n, const_void_pointer hint ); |  | (C++20 起)

用外层分配器分配未初始化存储。

1) 调用 std::allocator_traits <OuterAlloc>::allocate(outer_allocator(), n)
2) 附带提供内存位置提示，通过调用 std::allocator_traits <OuterAlloc>::allocate(outer_allocator(), n, hint)

参数

n | - | 要分配存储的对象数
hint | - | 指向临近内存位置的指针

返回值

指向分配存储的指针

参阅

allocate | 分配未初始化的存储 (std::allocator<T> 的公开成员函数)
allocate [静态] | 用分配器分配未初始化的存储 (std::allocator_traits<Alloc> 的公开静态成员函数)


std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...>::construct

< cpp‎ | memory‎ | scoped allocator adaptor
定义于头文件 <scoped_allocator>
template < class T, class... Args >
void construct( T* p, Args&&... args );
 (1)
template< class T1, class T2, class... Args1, class... Args2 >

void construct( std::pair <T1, T2>* p,
std::piecewise_construct_t,
std::tuple <Args1...> x,

std::tuple <Args2...> y );
 (2) (C++20 前)
template< class T1, class T2 >
void construct( std::pair <T1, T2>* p );
 (3) (C++20 前)
template< class T1, class T2, class U, class V >
void construct( std::pair <T1, T2>* p, U&& x, V&& y );
 (4) (C++20 前)
template< class T1, class T2, class U, class V >
void construct( std::pair <T1, T2>* p, const std::pair <U, V>& xy );
 (5) (C++20 前)
template< class T1, class T2, class U, class V >
void construct( std::pair <T1, T2>* p, std::pair <U, V>&& xy );
 (6) (C++20 前)

用 OuterAllocator 与提供的构造函数参数在 p 所指向的分配但未初始化的存储构造对象。若对象是自身使用分配器的类型，或若它是 std::pair ，则下传 InnerAllocator 给构造的对象。

首先，调用 this->outer_allocator() 获得最外层分配器 OUTERMOST ，然后在此调用的结果上递归调用 outer_allocator() 成员函数直至抵达无这种成员函数的分配器。

定义 OUTERMOST_ALLOC_TRAITS(x) 为 std::allocator_traits < std::remove_reference_t <decltype(OUTERMOST(x))>>

1) 以使用分配器构造的手段在 p 所指示的未初始化内存位置，以 OUTERMOST 为分配器创建给定类型 T 的对象。在为 T 的构造函数所期待的使用分配器约定调整后，调用 OUTERMOST_ALLOC_TRAITS(*this)::construct 。
此重载仅若 U 不是 std::pair 的特化才参与重载决议。
 (C++20 前)
等价于
std::apply(
    [p,this](auto&&... newargs) {
        OUTERMOST_ALLOC_TRAITS(*this)::construct(
            OUTERMOST(*this), p, std::forward<decltype(newargs)>(newargs)...);
    },
    std::uses_allocator_construction_args(
        inner_allocator(),
        std::forward<Args>(args)...
    )
);
 (C++20 起)
2) 首先，若 T1 或 T2 具分配器，则修改 tuple x 与 y 以包含适合的内层分配其，按照下列三条规则产生二个新的 tuple xprime 与 yprime ：
2a) 若 T1 不具分配器 (std::uses_allocator <T1, inner_allocator_type>::value==false ，则 xprime 是 std::tuple <Args1&&...>(std::move(x)) 。（亦要求 std::is_constructible <T1, Args1...>::value==true ）
2b) 若 T1 具分配器 (std::uses_allocator <T1, inner_allocator_type>::value==true) ，而其构造函数接收 allocator_tag (std::is_constructible <T1, std::allocator_arg_t, inner_allocator_type&, Args1...>::value==true) ，则 xprime 为
std::tuple_cat(std::tuple<std::allocator_arg_t, inner_allocator_type&>(
                    std::allocator_arg, inner_allocator()
               ),
               std::tuple<Args1&&...>(std::move(x)))
2c) 若 T1 具分配器 (std::uses_allocator <T1, inner_allocator_type>::value==true) ，且其构造函数接收分配器为尾参数 (std::is_constructible <T1, Args1..., inner_allocator_type&>::value==true) ，则 xprime 为 std::tuple_cat ( std::tuple <Args1&&...>(std::move(x)), std::tuple <inner_allocator_type&>(inner_allocator())) 。
应用相同规则到 T2 并以 yprime 替换 y 。
一旦构造了 xprime 与 yprime ，则在分配器的存储构造 pair p ，通过调用
std::allocator_traits<O>::construct( OUTERMOST,
                                     p,
                                     std::piecewise_construct,
                                     std::move(xprime),
                                     std::move(yprime));
3) 等价于 construct(p, std::piecewise_construct, std::tuple <>(), std::tuple <>()) ，即传递 pair 的成员类型上的内层分配器，若它们接受。
4) 等价于
construct(p, std::piecewise_construct, std::forward_as_tuple(std::forward<U>(x)),
                                       std::forward_as_tuple(std::forward<V>(y)))
5) 等价于
construct(p, std::piecewise_construct, std::forward_as_tuple(xy.first),
                                       std::forward_as_tuple(xy.second))
6) 等价于
construct(p, std::piecewise_construct,
             std::forward_as_tuple(std::forward<U>(xy.first)),
             std::forward_as_tuple(std::forward<V>(xy.second)))
 (C++20 前)

参数

p | - | 指向被分配但未初始化的存储的指针
args... | - | 传递给 T 的构造函数的构造函数参数
x | - | 传递给 T1 的构造函数的构造函数参数
y | - | 传递给 T2 的构造函数的构造函数参数
xy | - | 成员分别为 T1 与 T2 构造函数实参的 pair

返回值

（无）

注意

此函数为任何给予了 std::scoped_allocator_adaptor 作为分配器使用的具分配器对象，例如 std::vector 所调用（通过 std::allocator_traits ）。因为 inner_allocator 自身是 std::scoped_allocator_adaptor 的实例，此函数亦在具分配器对象通过此函数开始构造其自身成员时得到调用。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2975 | C++11 | 某些情况下 pair 构造错误地使用第一重载 | 制约为不接受 pair
P0475R1 | C++11 | pair 逐片构造可能复制参数 | 变换到引用的 tuple 以避免复制

参阅

construct [静态] | 在分配的存储构造对象 (函数模板)
construct (C++17 中弃用)(C++20 中移除) | 在分配的存储构造对象 (std::allocator<T> 的公开成员函数)


std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...>::deallocate

< cpp‎ | memory‎ | scoped allocator adaptor
定义于头文件 <scoped_allocator> |
void deallocate( pointer p, size_type n ) noexcept; | (C++11 起)

用外层分配器解分配 p 所引用的存储，通过调用 std::allocator_traits <OuterAlloc>::deallocate(outer_allocator(), p, n)

参数

p | - | 指向先前分配的内存的指针
n | - | 分配内存所用的对象数

返回值

（无）

参阅

deallocate | 解分配存储 (std::allocator<T> 的公开成员函数)
deallocate [静态] | 用分配器解分配存储 (std::allocator_traits<Alloc> 的公开静态成员函数)


std::scoped_allocator_adaptor 的推导指引

< cpp‎ | memory‎ | scoped allocator adaptor
定义于头文件 <scoped_allocator>
template<class OuterAlloc, class... InnerAllocs>

scoped_allocator_adaptor(OuterAlloc, InnerAllocs...)

-> scoped_allocator_adaptor<OuterAlloc, InnerAllocs...>;
 (C++17 起)

为 std::scoped_allocator_adaptor 提供推导指引使之能推导其外层分配器。

示例

本节未完成
原因：暂无示例


std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...>::destroy

< cpp‎ | memory‎ | scoped allocator adaptor
定义于头文件 <scoped_allocator> |
template< class T > void destroy( T* p ); | (C++11 起)

用外层分配器调用 p 所指向对象的析构函数，通过调用

std::allocator_traits <OUTERMOST>::destroy(OUTERMOST(*this), p)

其中 OUTERMOST 是调用 this->outer_allocator() ，之后在此调用的结果上递归调用 outer_allocator() 成员函数直至抵达无该成员函数的类型的返回类型。

参数

p - 指向将被销毁的对象的指针

返回值

（无）

参阅

destroy [静态] | 析构存储于已分配存储的对象 (函数模板)
destroy (C++17 中弃用)(C++20 中移除) | 析构在已分配存储中的对象 (std::allocator<T> 的公开成员函数)


std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...>::inner_allocator

< cpp‎ | memory‎ | scoped allocator adaptor
定义于头文件 <scoped_allocator> |  |
inner_allocator_type& inner_allocator() noexcept; | (1) | (C++11 起)
const inner_allocator_type& inner_allocator() const noexcept; | (2) | (C++11 起)

获得到用于声明此 scoped_allocator_adaptor 的内层分配器的引用。

若 sizeof...(InnerAllocs) == 0 ，即未声明内层分配器，则返回 *this 。否则返回到 std::scoped_allocator_adaptor <InnerAllocs...> 的一个引用，即由 *this 的所有内层分配器组成的有作用域分配器，其首个内层分配器变为外层分配器。

参数

（无）

返回值

到内层分配器的引用，它自身是 std::scoped_allocator_adaptor 。

参阅

outer_allocator
 获得一个 outer_allocator 引用
(公开成员函数)


std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...>::max_size

< cpp‎ | memory‎ | scoped allocator adaptor
定义于头文件 <scoped_allocator> |
size_type max_size() const; | (C++11 起)

报告外层分配器支持的最大分配大小，通过调用 std::allocator_traits <OuterAlloc>::max_size(outer_allocator())

参数

（无）

返回值

OuterAlloc 的最大分配大小。

参阅

max_size (C++17 中弃用)(C++20 中移除) | 返回最大的受支持分配大小 (std::allocator<T> 的公开成员函数)
max_size [静态] | 返回分配器所支持的最大对象大小 (std::allocator_traits<Alloc> 的公开静态成员函数)


std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...>::operator=

< cpp‎ | memory‎ | scoped allocator adaptor
定义于头文件 <scoped_allocator> |
scoped_allocator_adaptor& operator=(const scoped_allocator_adaptor& other) = default; | (1)
scoped_allocator_adaptor& operator=(scoped_allocator_adaptor&& other) = default; | (2)

1) 显式设为默认的复制赋值运算符，它复制赋值基类（外层分配器 OuterAlloc ）和所有内层分配器。

2) 显式设为默认的移动赋值运算符，它移动赋值基类（外层分配器 OuterAlloc ）和所有内层分配器。

参数

other - 另一 std::scoped_allocator_adaptor


operator==,!=(std::scoped_allocator_adaptor)

< cpp‎ | memory‎ | scoped allocator adaptor
定义于头文件 <scoped_allocator> |
template< class OuterAlloc1, class OuterAlloc2, class... InnerAllocs > bool operator==( const scoped_allocator_adaptor<OuterAlloc1, InnerAllocs...>& lhs, const scoped_allocator_adaptor<OuterAlloc2, InnerAllocs...>& rhs ) noexcept; | (C++11 起)
template< class OuterAlloc1, class OuterAlloc2, class... InnerAllocs > bool operator!=( const scoped_allocator_adaptor<OuterAlloc1, InnerAllocs...>& lhs, const scoped_allocator_adaptor<OuterAlloc2, InnerAllocs...>& rhs ) noexcept; | (C++11 起) (C++20 前)

比较二个有作用域分配器适配器。若满足下列条件则二个这种分配器相等：

  • lhs.outer_allocator() == rhs.outer_allocator() ，且
  • 若 sizeof...(InnerAllocs) > 0 ，则 lhs.inner_allocator() == rhs.inner_allocator() 。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的有作用域分配器适配器

返回值

1) 若 lhs 与 rhs 相等，则返回 true ，否则返回 false 。
2) 若 lhs 与 rhs 不相等，则返回 true ，否则返回 false 。


std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...>::outer_allocator

< cpp‎ | memory‎ | scoped allocator adaptor
定义于头文件 <scoped_allocator> |  |
outer_allocator_type& outer_allocator() noexcept; | (1) | (C++11 起)
const outer_allocator_type& outer_allocator() const noexcept; | (2) | (C++11 起)

获得到用于声明此类的外层分配器的引用。

1) 返回 static_cast<OuterAlloc&>(*this)

2) 返回 static_cast<const OuterAlloc&>(*this)

参数

（无）

返回值

到 OuterAlloc 的引用

参阅

inner_allocator
 获得一个 inner_allocator 引用
(公开成员函数)


std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...>:: scoped_allocator_adaptor

< cpp‎ | memory‎ | scoped allocator adaptor
定义于头文件 <scoped_allocator> |  |
scoped_allocator_adaptor(); | (1) | (C++11 起)
template< class OuterA2 > scoped_allocator_adaptor( OuterA2&& outerAlloc, const InnerAllocs&... innerAllocs) noexcept; | (2) | (C++11 起)
scoped_allocator_adaptor( const scoped_allocator_adaptor& other ) noexcept; | (3) | (C++11 起)
scoped_allocator_adaptor( scoped_allocator_adaptor&& other ) noexcept; | (4) | (C++11 起)
template< class OuterA2 > scoped_allocator_adaptor( const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& other ) noexcept; | (5) | (C++11 起)
template< class OuterA2 > scoped_allocator_adaptor( scoped_allocator_adaptor<OuterA2, InnerAllocs...>&& other ) noexcept; | (6) | (C++11 起)
1) 默认构造函数：值初始化 OuterAlloc 基类及内层分配器成员对象，若为实现所使用。
2) 从 std::forward <OuterA2>(outerAlloc) 构造基类 OuterAlloc ，并用 innerAllocs... 构造内层分配器。此重载仅若 std::is_constructible <OuterAlloc, OuterA2>::value 为 true才参与重载决议。
3) 复制构造函数：从 other 的对应分配器初始化每个分配器
4) 移动构造函数：从 other 的对应分配器移动每个分配器到 *this 内
5) 从 other 的对应分配器初始化每个分配器。此重载仅若 std::is_constructible <OuterAlloc, const OuterA2&>::value 为 true 才参与重载决议。
6) 用移动语义，从 other 的对应分配器初始化每个分配器。此重载仅若 std::is_constructible <OuterAlloc, OuterA2>::value 为 true 才参与重载决议。

参数

outerAlloc | - | 外层分配器的构造函数参数
innerAllocs... | - | 内层分配其的构造函数参数
other | - | 另一 std::scoped_allocator_adaptor

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2782 | C++11 | 接收 OuterA2 的构造函数未受制约，干扰到元编程 | 添加了制约

参阅

allocate | 用外层分配器分配未初始化存储 (公开成员函数)
construct | 在分配的存储上构造一个对象，若适合则传递内存分配器至其构造函数 (公开成员函数)


std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...>:: select_on_container_copy_construction

< cpp‎ | memory‎ | scoped allocator adaptor
定义于头文件 <scoped_allocator> |
scoped_allocator_adaptor select_on_container_copy_construction() const; | (C++11 起)

创建 std::scoped_allocator_adaptor 的新实例，其中外层分配器基类和每个内层分配器子对象通过调用 std::allocator_traits <A>::select_on_container_copy_construction() 获得。

参数

（无）

返回值

新的 std::scoped_allocator_adaptor 对象，构造自正确复制的分配器。

参阅

select_on_container_copy_construction
[静态]
 获得复制标准容器后使用的分配器
(std::allocator_traits<Alloc> 的公开静态成员函数)


std::scoped_allocator_adaptor<OuterAlloc,InnerAlloc...>:: ~scoped_allocator_adaptor

< cpp‎ | memory‎ | scoped allocator adaptor
~scoped_allocator_adaptor(); | (C++11 起)

销毁 scoped_allocator_adaptor 。


std::pmr::set_default_resource

< cpp‎ | memory
定义于头文件 <memory_resource> |
std::pmr::memory_resource * set_default_resource( std::pmr::memory_resource * r) noexcept; | (C++17 起)

若 r 非空，则设置默认 memory_resource 指针为 r ；否则，设置默认 memory_resource 指针为 std::pmr::new_delete_resource () 。

默认 memory_resource 指针为某些设施在未显式提供 memory_resource 使所用。初始的默认 memory_resource 指针是 std::pmr::new_delete_resource 的返回值。

此函数是线程安全的。每个对 std::pmr::set_default_resource 的调用同步于（见 std::memory_order ） 后继的 std::pmr::set_default_resource 及 std::pmr::get_default_resource 调用。

返回值

返回先前默认 memory_resource 指针的值。

参阅

get_default_resource (C++17) | 获取缺省 std::pmr::memory_resource (函数)
new_delete_resource (C++17) | 返回一个静态的程序范围 std::pmr::memory_resource，它使用全局 operator new 与 operator delete 分配和解分配内存 (函数)


std::shared_ptr

< cpp‎ | memory
定义于头文件 <memory> |
template< class T > class shared_ptr; | (C++11 起)

std::shared_ptr 是通过指针保持对象共享所有权的智能指针。多个 shared_ptr 对象可占有同一对象。下列情况之一出现时销毁对象并解分配其内存：

  • 最后剩下的占有对象的 shared_ptr 被销毁；
  • 最后剩下的占有对象的 shared_ptr 被通过 operator= 或 reset() 赋值为另一指针。

用 delete 表达式或在构造期间提供给 shared_ptr 的定制删除器销毁对象。

shared_ptr 能在存储指向一个对象的指针时共享另一对象的所有权。此特性能用于在占有其所属对象时，指向成员对象。存储的指针为 get() 、解引用及比较运算符所访问。被管理指针是在 use_count 抵达零时传递给删除器者。

shared_ptr 亦可不占有对象，该情况下称它为空 (empty) （空 shared_ptr 可拥有非空存储指针，若以别名使用构造函数创建它）。

shared_ptr 的所有特化满足可复制构造 (CopyConstructible) 、可复制赋值 (CopyAssignable) 和可小于比较 (LessThanComparable) 的要求并可按语境转换为 bool 。

多个线程能在 shared_ptr 的不同实例上调用所有成员函数（包含复制构造函数与复制赋值）而不附加同步，即使这些实例是副本，且共享同一对象的所有权。若多个执行线程访问同一 shared_ptr 而不同步，且任一线程使用 shared_ptr 的非 const 成员函数，则将出现数据竞争；原子函数的 shared_ptr 特化能用于避免数据竞争。

成员类型

成员类型 | 定义
element_type
T | (C++17 前)
std::remove_extent_t <T> | (C++17 起)
weak_type (C++17 起) | std::weak_ptr <T>

成员函数

(构造函数)
 构造新的 shared_ptr
(公开成员函数)
(析构函数)
 如果没有更多 shared_ptr 指向持有的对象，则析构对象
(公开成员函数)
operator=
 对 shared_ptr 赋值
(公开成员函数)
修改器
reset
 替换所管理的对象
(公开成员函数)
swap
 交换所管理的对象
(公开成员函数)
观察器
get
 返回存储的指针
(公开成员函数)
operator*operator->
 解引用存储的指针
(公开成员函数)
operator[]
(C++17)
 提供到被存储数组的带下标访问
(公开成员函数)
use_count
 返回 shared_ptr 所指对象的引用计数
(公开成员函数)
unique
(C++20 前)
 检查所管理对象是否仅由当前 shared_ptr 的实例管理
(公开成员函数)
operator bool
 检查是否有关联的管理对象
(公开成员函数)
owner_before
 提供基于拥有者的共享指针排序
(公开成员函数)

非成员函数

make_sharedmake_shared_for_overwrite (C++20) | 创建管理一个新对象的共享指针 (函数模板)
allocate_sharedallocate_shared_for_overwrite (C++20) | 创建管理一个用分配器分配的新对象的共享指针 (函数模板)
static_pointer_castdynamic_pointer_castconst_pointer_castreinterpret_pointer_cast (C++17) | 应用 static_cast、dynamic_cast、const_cast 或 reinterpret_cast 到被存储指针 (函数模板)
get_deleter | 返回指定类型中的删除器，若其拥有 (函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 与另一个 shared_ptr 或 nullptr 进行比较 (函数模板)
operator<< | 将存储的指针的值输出到输出流 (函数模板)
std::swap(std::shared_ptr) (C++11) | 特化 std::swap 算法 (函数模板)
std::atomic_is_lock_free(std::shared_ptr)std::atomic_load(std::shared_ptr)std::atomic_load_explicit(std::shared_ptr)std::atomic_store(std::shared_ptr)std::atomic_store_explicit(std::shared_ptr)std::atomic_exchange(std::shared_ptr)std::atomic_exchange_explicit(std::shared_ptr)std::atomic_compare_exchange_weak(std::shared_ptr)std::atomic_compare_exchange_strong(std::shared_ptr)std::atomic_compare_exchange_weak_explicit(std::shared_ptr)std::atomic_compare_exchange_strong_explicit(std::shared_ptr)
(C++20 中弃用)
 特化的原子操作
(函数模板)

辅助类

std::hash<std::shared_ptr> (C++11) | std::shared_ptr 的散列支持 (类模板特化)
std::atomic<std::shared_ptr> (C++20) | 原子共享指针 (类模板特化)

推导指引 (C++17 起)

注意

只能通过复制构造或复制赋值其值给另一 shared_ptr ，将对象所有权与另一 shared_ptr 共享。用另一 shared_ptr 所占有的底层指针创建新的 shared_ptr 导致未定义行为。

std::shared_ptr 可以用于不完整类型 T 。然而，参数为裸指针的构造函数（ template<class Y> shared_ptr(Y*) ）和 template<class Y> void reset(Y*) 成员函数只可以用指向完整类型的指针调用（注意 std::unique_ptr 可以从指向不完整类型的裸指针构造）。

实现说明

在典型的实现中， std::shared_ptr 只保有二个指针：

  • get() 所返回的指针
  • 指向控制块的指针

控制块是一个动态分配的对象，其中包含：

  • 指向被管理对象的指针或被管理对象本身
  • 删除器（类型擦除）
  • 分配器（类型擦除）
  • 占有被管理对象的 shared_ptr 的数量
  • 涉及被管理对象的 weak_ptr 的数量

以调用 std::make_shared 或 std::allocate_shared 创建 shared_ptr 时，以单次分配创建控制块和被管理对象。被管理对象在控制块的数据成员中原位构造。通过 shared_ptr 构造函数之一创建 shared_ptr 时，被管理对象和控制块必须分离分配。此情况中，控制块存储指向被管理对象的指针。

shared_ptr 持有的指针是通过 get() 返回的；而控制块所持有的指针/对象则是最终引用计数归零时会被删除的那个。两者并不一定相等。

shared_ptr 的析构函数会将控制块中的 shared_ptr 计数器减一，如果减至零，控制块就会调用被管理对象的析构函数。但控制块本身直到 std::weak_ptr 计数器同样归零时才会释放。

既存实现中，若有共享指针指向同一控制块，则自增弱指针计数 ([1], [2]) 。

为满足线程安全要求，引用计数器典型地用等价于用 std::memory_order_relaxed 的 std::atomic::fetch_add 自增（自减要求更强的顺序，以安全销毁控制块）。

示例

#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>

struct Base
{
    Base() { std::cout << "  Base::Base()\n"; }
    // 注意：此处非虚析构函数 OK
    ~Base() { std::cout << "  Base::~Base()\n"; }
};

struct Derived: public Base
{
    Derived() { std::cout << "  Derived::Derived()\n"; }
    ~Derived() { std::cout << "  Derived::~Derived()\n"; }
};

void thr(std::shared_ptr<Base> p)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::shared_ptr<Base> lp = p; // 线程安全，虽然自增共享的 use_count
    {
        static std::mutex io_mutex;
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << "local pointer in a thread:\n"
                  << "  lp.get() = " << lp.get()
                  << ", lp.use_count() = " << lp.use_count() << '\n';
    }
}

int main()
{
    std::shared_ptr<Base> p = std::make_shared<Derived>();

    std::cout << "Created a shared Derived (as a pointer to Base)\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    std::thread t1(thr, p), t2(thr, p), t3(thr, p);
    p.reset(); // 从 main 释放所有权
    std::cout << "Shared ownership between 3 threads and released\n"
              << "ownership from main:\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    t1.join(); t2.join(); t3.join();
    std::cout << "All threads completed, the last one deleted Derived\n";
}

可能的输出：

Base::Base()
  Derived::Derived()
Created a shared Derived (as a pointer to Base)
  p.get() = 0x2299b30, p.use_count() = 1
Shared ownership between 3 threads and released
ownership from main:
  p.get() = 0, p.use_count() = 0
local pointer in a thread:
  lp.get() = 0x2299b30, lp.use_count() = 5
local pointer in a thread:
  lp.get() = 0x2299b30, lp.use_count() = 3
local pointer in a thread:
  lp.get() = 0x2299b30, lp.use_count() = 2
  Derived::~Derived()
  Base::~Base()
All threads completed, the last one deleted Derived


std::allocate_shared, std::allocate_shared_for_overwrite

< cpp‎ | memory‎ | shared ptr
定义于头文件 <memory>
template< class T, class Alloc, class... Args >
shared_ptr<T> allocate_shared( const Alloc& alloc, Args&&... args );
 (1) (C++11 起)
(T 非数组)
template< class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc, std::size_t N );
 (2) (C++20 起)
(T 为 U[])
template< class T, class Alloc >
shared_ptr<T> allocate_shared( const Alloc& alloc );
 (3) (C++20 起)
(T 为 U[N])
template< class T, class Alloc >

shared_ptr<T> allocate_shared( const Alloc& alloc, std::size_t N,

const std::remove_extent_t <T>& u );
 (4) (C++20 起)
(T 为 U[])
template< class T, class Alloc >

shared_ptr<T> allocate_shared( const Alloc& alloc,

const std::remove_extent_t <T>& u );
 (5) (C++20 起)
(T 为 U[N])
template< class T, class Alloc >
shared_ptr<T> allocate_shared_for_overwrite( const Alloc& alloc );
 (6) (C++20 起)
(T 非 U[])
template< class T, class Alloc >
shared_ptr<T> allocate_shared_for_overwrite( const Alloc& alloc, std::size_t N );
 (7) (C++20 起)
(T 为 U[])
1) 以 args 为 T 的构造函数参数列表，构造 T 类型对象并将它包装于 std::shared_ptr 。对象如同以表达式 ::new (pv) T(v) (C++20 前)std::allocator_traits <A2>::construct(a, pv, v) (C++20 起) 构造，其中 pv 是内部指向适合保有 T 类型对象的存储的 void* 指针，而 a 是重绑定到 std::remove_cv_t <T> 的分配器副本。存储通常大于 sizeof(T) ，以对共享指针的控制块和 T 对象使用一次分配。此函数所调用的 std::shared_ptr 构造函数以指向新构造的 T 类型对象指针启用 shared_from_this 。所有内存分配用 alloc 的副本执行，而它必须满足分配器 (Allocator) 要求。此重载仅若 T 不是数组类型才参与重载决议。
2,3) 同 (1) ，但构造的元素是可能多维的数组，其每个非数组元素如同以表达式 std::allocator_traits <A2>::construct(a2, pv) 初始化，其中 A2 类型的 a2 是重绑定为管理 std::remove_cv_t < std::remove_all_extents_t <T>> 类型对象的分配器副本。重载 (2) 创建第一维上大小为 N 的数组。数组元素以其地址递增顺序初始化，而当其生存期结束时，以原本构造顺序的逆序销毁。
4,5) 同 (2,3) ，但每个元素从默认值 u 初始化。若 U 不是数组类型，则这如同以与 (1) 中相同的分配器表达式进行，除了把分配器重绑定到 std::remove_cv_t < std::remove_all_extents_t <T>> 。否则，这如同以如同 (1) 中的分配器表达式，从来自 u 的对应元素初始化（可能多维的）数组的每个非数组元素，除了重绑定分配器到 std::remove_cv_t < std::remove_all_extents_t <T>> 类型。重载 (4)创建第一维上大小为 N 的数组。数组元素以其地址递增顺序初始化，而当其生存期结束时，以原本构造顺序的逆序销毁。
6) 若 T 非数组类型则同 (1) 而若 T 为 U[N] 则同 (3) ，除了默认初始化创建的元素。
7) 同 (2) ，除了默认初始化单独的数组元素。

对于 allocate_shared ，通过表达式 std::allocator_traits <A2>::destroy(a, p) 销毁对象{{rev inl|since=c++20|（或对于 (2-5) 为单独的数组元素），其中 p 是指向对象的指针而 a 是传递给 allocate_shared 的分配器副本，重绑定到正在销毁的对象类型。

对于 allocate_shared_for_overwrite ，对象（或若 T 为数组类型则为单独的数组元素）将会被 p->~X() 销毁，其中 p 是指向对象的指针而 X 是对象的类型。

 (C++20 起)

参数

alloc | - | 使用的分配器 (Allocator) 。
args... | - | 构造 T 示例将要用到的参数列表。
N | - | 所用的数组大小
u | - | 初始化数组每个元素的初值

返回值

T 类型实例的的 std::shared_ptr 。

异常

能抛出从 Alloc::allocate() 抛出的异常，或从 T 构造函数抛出的异常。若抛出异常，则 (1) 无效果。若异常在数组的构造中抛出，则已初始化元素以逆序销毁。 (C++20 起)

注解

类似 std::make_shared ，此函数通常只进行一次分配，并将 T 对象与控制块置于分配的内存块中（标准推荐但不要求如此，所有已知实现均如此）。 alloc 的副本作为控制块的一部分存储，从而它能用于解分配之，若所有共享及若引用计数抵达零。

不同于 std::shared_ptr 构造函数， std::allocate_shared 不接受另外的自定义删除器：用提供的分配器析构控制块和 T 对象，及解分配其共享内存块。

std::shared_ptr 支持数组类型（从 C++17 起），但 std::allocate_shared 不支持。 boost::allocate_shared 支持此功能。

 (C++20 前)

构造函数以 U* 类型指针 ptr 启用 shared_from_this ，表示它确定 U 是否拥有作为 std::enable_shared_from_this 特化的无歧义且可访问 (C++17 起)基类，而若如此，则构造函数求值该语句：

if (ptr != nullptr && ptr->weak_this.expired())
  ptr->weak_this = std::shared_ptr<std::remove_cv_t<U>>(*this,
                                  const_cast<std::remove_cv_t<U>*>(ptr));

其中 weak_this 是 std::shared_from_this 的隐藏 mutable std::weak_ptr 成员。对 weak_this 成员的赋值不是原子的，且与任何到同一对象的潜在并发访问冲突。这确保将来对 shared_from_this() 调用，将与此裸指针构造函数所创建的 shared_ptr 共享所有权。

上述解释代码中，测试 ptr->weak_this.expired() 是为确保若 weak_this 指示已有占有者则重赋值它。从 C++17 起要求此测试。

参阅

(构造函数) | 构造新的 shared_ptr (公开成员函数)
make_sharedmake_shared_for_overwrite (C++20) | 创建管理一个新对象的共享指针 (函数模板)


std::atomic_...<std::shared_ptr>

< cpp‎ | memory‎ | shared ptr
template< class T >
bool atomic_is_lock_free( const std::shared_ptr <T>* p );
 (1) (C++11 起)
(C++20 中弃用)
template< class T >
std::shared_ptr <T> atomic_load( const std::shared_ptr <T>* p );
 (2) (C++11 起)
(C++20 中弃用)
template< class T >

std::shared_ptr <T> atomic_load_explicit( const std::shared_ptr <T>* p,

std::memory_order mo );
 (3) (C++11 起)
(C++20 中弃用)
template< class T >

void atomic_store( std::shared_ptr <T>* p,

std::shared_ptr <T> r );
 (4) (C++11 起)
(C++20 中弃用)
template< class T >

void atomic_store_explicit( std::shared_ptr <T>* p,
std::shared_ptr <T> r,

std::memory_order mo);
 (5) (C++11 起)
(C++20 中弃用)
template< class T >

std::shared_ptr <T> atomic_exchange( std::shared_ptr <T>* p,

std::shared_ptr <T> r);
 (6) (C++11 起)
(C++20 中弃用)
template<class T>

std::shared_ptr <T> atomic_exchange_explicit( std::shared_ptr <T>* p,
std::shared_ptr <T> r,

std::memory_order mo);
 (7) (C++11 起)
(C++20 中弃用)
template< class T >

bool atomic_compare_exchange_weak( std::shared_ptr <T>* p,
std::shared_ptr <T>* expected,

std::shared_ptr <T> desired);
 (8) (C++11 起)
(C++20 中弃用)
template<class T>

bool atomic_compare_exchange_strong( std::shared_ptr <T>* p,
std::shared_ptr <T>* expected,

std::shared_ptr <T> desired);
 (9) (C++11 起)
(C++20 中弃用)
template< class T >

bool atomic_compare_exchange_strong_explicit( std::shared_ptr <T>* p,
std::shared_ptr <T>* expected,
std::shared_ptr <T> desired,
std::memory_order success,

std::memory_order failure);
 (10) (C++11 起)
(C++20 中弃用)
template< class T >

bool atomic_compare_exchange_weak_explicit( std::shared_ptr <T>* p,
std::shared_ptr <T>* expected,
std::shared_ptr <T> desired,
std::memory_order success,

std::memory_order failure);
 (11) (C++11 起)
(C++20 中弃用)

若多个执行线程访问同一 std::shared_ptr 对象而无同步，且这些访问中任一者使用 shared_ptr 的非 const 成员函数，则发生数据竞争，除非所有这种访问都通过这些作为对应原子访问函数（ std::atomic_load 、 std::atomic_store 等）重载的函数进行。

注意 shared_ptr 的控制块是线程安全的：多个线程能同时用可改操作访问不同的 std::shared_ptr 对象，如 operator= 或 reset ，即使这些实例是副本，并内部共享同一控制块。

1) 确定到 p 所指向共享指针的原子访问是否无锁。
2) 等价于 atomic_load_explicit(p, std::memory_order_seq_cst ) 。
3) 返回 p 所指向的共享指针。同非特化的 std::atomic_load_explicit ， mo 不能是 std::memory_order_release 或 std::memory_order_acq_rel 。
4) 等价于 atomic_store_explicit(p, r, memory_order_seq_cst) 。
5) 原子地存储共享指针 r 于 p 所指向的共享指针，等效地执行 p->swap(r) 。同非特化的 std::atomic_store_explicit 、 mo 不能是 std::memory_order_acquire 或 std::memory_order_acq_rel 。
6) 等价于 atomic_exchange_explicit(p, r, memory_order_seq_cst) 。
7) 原子地存储共享指针 r 于 p 所指向的共享指针，并返回 p 先前指向的值。等效地执行 p->swap(r) 并返回交换后 r 的副本。
8) 等价于 atomic_compare_exchange_weak_explicit(p, expected, desired, std::memory_order_seq_cst, std::memory_order_seq_cst ) 。
9) 等价于 atomic_compare_exchange_strong_explicit(p, expected, desired, std::memory_order_seq_cst, std::memory_order_seq_cst ) 。
10) 比较 p 所指向的共享指针和 expected 。若它们等价（存储同一指针值，并且共享同一对象的所有权或均为空），则用 success 所指定的内存定序制约赋值 desired 给 *p 并返回 true 。若它们不等价，则用 failure 所指定的内存定序制约赋值 *p 给 *expected 并返回 false 。
11) 同 10) ，但可能虚假地失败。

若 p 为空指针，则这些函数都会引发未定义行为。

参数

p, expected | - | 指向 std::shared_ptr 的指针
r, desired | - | 一个 std::shared_ptr
mo, success, failure | - | std::memory_order 类型的内存定序选择器

异常

这些函数不抛异常。

返回值

1) 若原子访问使用无锁指令则为 true
2,3) 被指向的共享指针的副本。
4,5) （无）
6,7) 先前被指向共享指针的副本
8,9,10,11) 若共享指针等价并进行交换则为 true ，否则为 false 。

注意

这些函数典型地以互斥实现，互斥存储于全局哈希表中，其中以指针值为关键。

为避免数据竞争，一旦把共享指针传递给这些函数，就不能非原子地使用它。特别是，若你没有首先把这种 shared_ptr 加载到另一 shared_ptr 对象中，再通过第二对象解引用，就不能解引用它。

并发 TS 提供原子智能指针类 atomic_shared_ptr 和 atomic_weak_ptr ，以替换这些函数的使用。

这些函数被弃用，取代者是 std::atomic 模板的特化： std::atomic < std::shared_ptr > 和 std::atomic < std::weak_ptr > 。

 (C++20 起)

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2980 | C++11 | 空的 shared_ptr 决不等价 | 若它们存储同一指针值则等价

参阅

atomic_is_lock_free (C++11) | 检查对该原子类型的操作是否是无锁的 (函数模板)
atomic_storeatomic_store_explicit (C++11)(C++11) | 原子地以非原子实参替换原子对象的值 (函数模板)
atomic_loadatomic_load_explicit (C++11)(C++11) | 原子地获得存储于原子对象的值 (函数模板)
atomic_exchangeatomic_exchange_explicit (C++11)(C++11) | 原子地以非原子实参的值替换原子对象的值，并返回该原子对象的旧值 (函数模板)
atomic_compare_exchange_weakatomic_compare_exchange_weak_explicitatomic_compare_exchange_strongatomic_compare_exchange_strong_explicit (C++11)(C++11)(C++11)(C++11) | 原子地比较原子对象和非原子实参的值，若相等则进行 atomic_exchange，若不相等则进行 atomic_load (函数模板)


std::atomic(std::shared_ptr)

< cpp‎ | memory‎ | shared ptr
定义于头文件 <memory> |
template <class T> struct std::atomic < std::shared_ptr <T>>; | (C++20 起)

std::atomic 对 std::shared_ptr <T> 的部分模板特化允许用户原子地操纵 shared_ptr 。

若多个执行线程同时访问同一 std::shared_ptr 对象而不同步，且任何这些访问使用了 shared_ptr 的非 const 成员函数，则将出现数据竞争，除非通过 std::atomic<std::shared_ptr>> 的实例进行所有访问（或通过从 C++20 起弃用的孤立函数对 std::shared_ptr 进行原子访问）。

关联 use_count 的自增保证是原子操作的一部分。关联 use_count 的自减后序于原子操作，但不要求是原子操作的一部分，除非在覆写失败的 CAS 中的 expected 时， use_count 更改。任何关联删除和解分配后序于原子更新步骤，且不是原子操作的一部分。

注意 shared_ptr 的控制块是线程安全的：多个线程能同时用可变操作，例如 operator= 或 reset ，访问不同的非原子 std::shared_ptr 对象，即使这些实例互为副本，于内部共享同一控制块。

类型 T 可为不完整类型。

成员类型

成员类型 | 定义
value_type | std::shared_ptr <T>

成员函数

此特化提供所有非特化的 std::atomic 的成员函数，不提供附加成员函数。

atomic<shared_ptr<T>>::atomic

constexpr atomic() noexcept = default; | (1)
atomic( std::shared_ptr <T> desired) noexcept; | (2)
atomic(const atomic&) = delete; | (3)
1) 初始化底层 shared_ptr<T> 为默认构造值
2) 初始化底层 shared_ptr<T> 为 desired 的副本。同任何 std::atomic 类型，初始化不是原子操作。
3) 原子类型不可复制/移动构造。

atomic<shared_ptr<T>>::operator=

void operator=(const atomic&) = delete; | (1)
void operator=( std::shared_ptr <T> desired) noexcept; | (2)
1) 原子类型不可复制/移动构造
2) 值赋值，等价于 store(desired)

atomic<shared_ptr<T>>::is_lock_free

bool is_lock_free() const noexcept;

若此类型所有对象上的原子操作为免锁则返回 true ，否则返回 false 。

atomic<shared_ptr<T>>::store

void store( std::shared_ptr <T> desired,
std::memory_order order = std::memory_order_seq_cst ) noexcept;

如同用 p.swap(desired) ，原子地以 desired 的值替换 *this 的值，其中 p 是底层的 std::shared_ptr<T> 。按照 order 排序内存。若 order 非 std::memory_order_consume 、 std::memory_order_acquire 或 std::memory_order_acq_rel 则行为未定义。

atomic<shared_ptr<T>>::load

std::shared_ptr <T> load( std::memory_order order = std::memory_order_seq_cst ) const noexcept;

原子地返回底层共享指针的副本。按照 order 排序内存。若 order 不是 std::memory_order_release 或 std::memory_order_acq_rel 则行为未定义。

atomic<shared_ptr<T>>::operator std::shared_ptr<T>

operator std::shared_ptr <T>() const noexcept;

等价于 return load(); 。

atomic<shared_ptr<T>>::exchange

std::shared_ptr <T> exchange( std::shared_ptr <T> desired,
std::memory_order order = std::memory_order_seq_cst ) noexcept;

如同用 p.swap(desired) ，原子地以 desired 替换底层 std::shared_ptr <T> ，其中 p 为底层 std::shared_ptr<T> ，并返回该 p 的值的副本。按照 order 排序内存。这是原子读修改写操作。

atomic<shared_ptr<T>>::compare_exchange_weak, compare_exchange_strong

bool compare_exchange_strong( std::shared_ptr <T>& expected, std::shared_ptr <T> desired,
std::memory_order success, std::memory_order failure) noexcept;
 (1)
bool compare_exchange_weak( std::shared_ptr <T>& expected, std::shared_ptr <T> desired,
std::memory_order success, std::memory_order failure) noexcept;
 (2)
bool compare_exchange_strong( std::shared_ptr <T>& expected, std::shared_ptr <T> desired,
std::memory_order order = std::memory_order_seq_cst ) noexcept;
 (3)
bool compare_exchange_weak( std::shared_ptr <T>& expected, std::shared_ptr <T> desired,
std::memory_order order = std::memory_order_seq_cst ) noexcept;
 (4)
1) 若底层 std::shared_ptr <T> 存储同 expected 的 T* 并与之共享所有权，或若底层指针和 expected 均为空，则从 desired 赋值给底层 std::shared_ptr <T> 并返回 true ，按照 success 排序内存；否则从底层 std::shared_ptr <T> 赋值给 expected 并返回 false ，按照 failure 排序内存。若 failure 为 std::memory_order_release 或 std::memory_order_acq_rel 则行为未定义。成功时，操作为 *this 上的读修改写操作，而且在原子更新后不访问 expected 。失败时，操作为 *this 上的原子加载操作，并更新 expected 为从原子对象读取的既存值。这个对 expected 的 use_count 的更新是原子操作的一部分，尽管不要求写入自身（以及任何后继的解分配/析构）是其一部分。
2) 同 (1) ，但允许虚假地失败。
3) 等价于： return compare_exchange_strong(expected, desired, order, fail_order); ，其中 fail_order 与 order 相同，除了 std:memory_order_acq_rel 被替换为 std::memory_order_acquire ，而 std::memory_order_release 被替换为 std::memory_order_relaxed 。
4) 等价于： return compare_exchange_weak(expected, desired, order, fail_order); ，其中 fail_order 与 order 相同，除了 std::memory_order_acq_rel 被替换为 std::memory_order_acquire 而 std::memory_order_release 被替换为 std::memory_order_relaxed 。

atomic<shared_ptr<T>>::wait

void wait( std::shared_ptr <T> old
std::memory_order order = std::memory_order_seq_cst ) const noexcept;

进行原子等待操作。

比较 load(order) 与 old ，而若它们等价则阻塞直至 *this 被 notify_one() 或 notify_all() 提醒。重复此操作直至 load(order) 更改。此函数保证仅若值更改才返回，即使底层实现虚假地除阻。

按照 order 排序内存。若 order 为 std::memory_order_release 或 std::memory_order_acq_rel 则行为未定义。

注解：若二个 shared_ptr 存储同一指针，且要么共享所有权要么都为空，则它们等价。

atomic<shared_ptr<T>>::notify_one

void notify_one() noexcept;

进行原子提醒操作。

若有一个线程在 *this 上的原子等待操作（即 wait() ）中阻塞，则除阻至少一个这种线程，否则不做任何事。

atomic<shared_ptr<T>>::notify_all

void notify_all() noexcept;

进行原子提醒操作。

除阻所有在 *this 上的原子等待操作（即 wait() ）中阻塞的线程，若存在；否则不做任何事。

成员常量

此特化亦提供标准 std::atomic 仅有的成员常量 is_always_lock_free 。

atomic<shared_ptr<T>>::is_always_lock_free

static constexpr bool is_always_lock_free = /*implementation-defined*/;

示例

本节未完成
原因：暂无示例

参阅

atomic
(C++11)
 atomic 类模板及其针对布尔、整型和指针类型的特化
(类模板)


std::shared_ptr 的推导指引

< cpp‎ | memory‎ | shared ptr
定义于头文件 <memory> |  |
template <class T> shared_ptr( std::weak_ptr <T>) -> shared_ptr<T>; | (1) | (C++17 起)
template <class T, class D> shared_ptr( std::unique_ptr <T, D>) -> shared_ptr<T>; | (2) | (C++17 起)

为 std::shared_ptr 提供此推导指引，以囊括隐式推导指引所错失的极端情况。

注意没有从指针类型的类模板实参推导，因为不可能辨别获得自 new 的数组和非数组形式的指针。

示例

#include <memory>

int main()
{
    auto p = std::make_shared<int>(42);
    std::weak_ptr w{p};    // 用于此情况的显式推导指引
    std::shared_ptr p2{w}; // 用于此情况的显式推导指引
}


std::shared_ptr<T>::get

< cpp‎ | memory‎ | shared ptr
T* get() const noexcept; | (C++17 前)
element_type* get() const noexcept; | (C++17 起)

返回存储的指针。

参数

（无）

返回值

存储的指针。

注意

shared_ptr 可能在存储指向一个对象的指针时共享另一对象的所有权。 get() 返回存储的指针，而非被管理指针。

示例

#include <iostream>
#include <memory>
#include <string_view>

void output(std::string_view msg, int const* pInt)
{
    std::cout << msg << *pInt << "\n";
}

int main()
{
    int* pInt = new int(42);
    std::shared_ptr<int> pShared = std::make_shared<int>(42);

    output("Naked pointer ", pInt);
    // output("Shared pointer ", pShared); // 编译错误
    output("Shared pointer with get() ", pShared.get());

    delete pInt;
}

输出：

Naked pointer 42
Shared pointer with get() 42

参阅

operator*operator->
 解引用存储的指针
(公开成员函数)


std::get_deleter

< cpp‎ | memory‎ | shared ptr
定义于头文件 <memory> |
template< class Deleter, class T > Deleter* get_deleter( const std::shared_ptr <T>& p ) noexcept; | (C++11 起)

访问 p 的删除器。若共享指针 p 占有无 cv 限定 Deleter 类型的删除器（例如，若以接收删除器为参数的构造函数之一创建它），则返回指向删除器的指针。否则，返回空指针。

参数

p - 需要访问其删除器的共享指针

返回值

指向被占有删除器的指针或 nullptr 。只要至少还有一个 shared_ptr 实例占有返回的指针，它就合法。

注解

返回的指针可能比最后一个 shared_ptr 的生存期更持久，例如，还剩下 std::weak_ptr 时且实现在销毁整个控制块前不销毁删除器。

示例

演示 shared_ptr 删除器独立于 shared_ptr 的类型

#include <iostream>
#include <memory>

struct Foo { int i; };
void foo_deleter(Foo * p)
{
    std::cout << "foo_deleter called!\n";
    delete p;
}

int main()
{
    std::shared_ptr<int> aptr;

    {
        // 创建拥有一个 Foo 和删除器的 shared_ptr
        auto foo_p = new Foo;
        std::shared_ptr<Foo> r(foo_p, foo_deleter);
        aptr = std::shared_ptr<int>(r, &r->i); // 别名使用构造函数
        // aptr 现在指向 int ，但管理整个 Foo
    } // r 被销毁（不调用删除器）

    // 获得指向删除器的指针：
    if(auto del_p = std::get_deleter<void(*)(Foo*)>(aptr))
    {
        std::cout << "shared_ptr<int> owns a deleter\n";
        if(*del_p == foo_deleter)
            std::cout << "...and it equals &foo_deleter\n";
    } else
        std::cout << "The deleter of shared_ptr<int> is null!\n";
} // 于此调用删除器

输出：

shared_ptr<int> owns a deleter
...and it equals &foo_deleter
foo_deleter called!

参阅

(构造函数)
 std::shared_ptr 构造函数
(公开成员函数)


std::hash(std::shared_ptr)

< cpp‎ | memory‎ | shared ptr
template<class T> struct hash<shared_ptr<T>>; | (C++11 起)

std::hash 对 std::shared_ptr <T> 的模板特化允许用户获得 std::shared_ptr <T> 类型对象的哈希。

对于给定的 std::shared_ptr <T> p ，此特化确保

std::hash < std::shared_ptr <T>>()(p) == std::hash <T*>()(p.get()). | (C++17 前)
std::hash < std::shared_ptr <T>>()(p) == std::hash <typename std::shared_ptr <T>::element_type*>()(p.get()). | (C++17 起)

示例

本节未完成
原因：暂无示例

参阅

hash
(C++11)
 散列函数对象
(类模板)


std::make_shared, std::make_shared_for_overwrite

< cpp‎ | memory‎ | shared ptr
定义于头文件 <memory> |  |
template< class T, class... Args > shared_ptr<T> make_shared( Args&&... args ); | (1) | (C++11 起) (T 非数组)
template<class T> shared_ptr<T> make_shared( std::size_t N ); | (2) | (C++20 起) (T 为 U[])
template<class T> shared_ptr<T> make_shared(); | (3) | (C++20 起) (T 为 U[N])
template<class T> shared_ptr<T> make_shared( std::size_t N, const std::remove_extent_t <T>& u ); | (4) | (C++20 起) (T 为 U[])
template<class T> shared_ptr<T> make_shared( const std::remove_extent_t <T>& u ); | (5) | (C++20 起) (T 为 U[N])
template<class T> shared_ptr<T> make_shared_for_overwrite(); | (6) | (C++20 起) (T 非 U[])
template<class T> shared_ptr<T> make_shared_for_overwrite( std::size_t N ); | (7) | (C++20 起) (T 为 U[])
1) 以 args 为 T 的构造函数参数列表，构造 T 类型对象并将它包装于 std::shared_ptr 。对象如同用表达式 ::new (pv) T( std::forward <Args>(args)...) 构造，其中 pv 是内部指向适合保有 T 类型对象的存储的 void* 指针。存储典型地大于 sizeof(T) ，以对共享指针控制块和 T 对象使用一次分配。此函数所调用的 std::shared_ptr 构造函数以指向新构造的 T 类型对象指针启用 shared_from_this 。此重载仅若 T 不是数组类型才参与重载决议。
2,3) 同 (1) ，但构造的对象是可能多维的数组，其 std::remove_all_extents_t<T> 类型的非数组元素如同以布置 new 表达式 ::new(pv) std::remove_all_extents_t <T>() 值初始化。重载 (2) 创建第一维上大小为 N 的数组。数组元素以其地址递增顺序初始化，而当其生存期结束时，以原本构造顺序的逆序销毁。
4,5) 同 (2,3) ，但每个元素从默认值 u 初始化。若 U 不是数组类型，则这如同以如 (1) 中的布置 new 表达式进行；否则，这如同以如同 (1) 中的布置 new 表达式，从来自 u 的对应元素初始化（可能多维的）数组的每个非数组元素。重载 (4) 创建第一维上大小为 N 的数组。数组元素以其地址递增顺序初始化，而当其生存期结束时，以原本构造顺序的逆序销毁。
6) 若 T 不是数组类型则同 (1) ，而若 (3) 是 U[N] 则同 if T ，除了默认初始化创建的对象。
7) 同 (2) ，除了默认初始化单独的数组元素。

每种情况下，均将用 p->~X() 销毁对象（或若 T 为数组类型则为单独的元素） (C++20 起)，其中 p 是指向对象的指针，而 X 是该对象的类型。

参数

args | - | 将用以构造 T 实例的参数列表。
N | - | 要使用的数组
u | - | 初始化数组每个元素的初值

返回值

类型 T 实例的 std::shared_ptr 。

异常

可能抛出 std::bad_alloc 或任何 T 构造函数所抛的异常。若抛出异常，则函数无效果。若异常在数组的构造中抛出，则已初始化元素以逆序销毁。 (C++20 起)

注解

此函数可用作 std::shared_ptr <T>(new T(args...)) 的替代品。得失是：

  • std::shared_ptr <T>(new T(args...)) 进行至少二次分配（一次为 T 而另一次为共享指针的控制块），而 std::make_shared<T> 典型地仅进行一次分配（标准推荐但不要求如此，所有已知实现均如此）。
  • 若任何 std::weak_ptr 在所有共享拥有者的生存期结束后引用 std::make_shared 所创建的控制块，则 T 所占有的内存维持着，直至所有弱拥有者亦被销毁，若 sizeof(T) 较大则这可能是不想要的。
  • std::shared_ptr <T>(new T(args...)) 可能调用 T 的非公开构造函数，若在它可访问的语境中执行，而 std::make_shared 要求对被选择构造函数的公开访问。
  • 不同于 std::shared_ptr 构造函数， std::make_shared 不允许自定义删除器。
  • std::make_shared 使用 ::new ，故若用类特定的 operator new 设置了任何特殊行为，则它将异于 std::shared_ptr <T>(new T(args...)) 。
  • std::shared_ptr 支持数组类型（从 C++17 起），但 std::make_shared 不支持。 boost::make_shared 支持此功能。
 (C++20 前)
  • 如 f( std::shared_ptr <int>(new int(42)), g()) 的代码可能导致内存泄漏，若 g 在 new int(42) 后得到调用且抛出异常，而 f(std::make_shared<int>(42), g()) 是安全的，因为二个函数调用决不会穿插。
 (C++17 前)

构造函数以 U* 类型指针 ptr 启用 shared_from_this ，表示它确定 U 是否拥有作为 std::enable_shared_from_this 特化的无歧义且可访问 (C++17 起)基类，而若如此，则构造函数求值该语句：

if (ptr != nullptr && ptr->weak_this.expired())
  ptr->weak_this = std::shared_ptr<std::remove_cv_t<U>>(*this,
                                  const_cast<std::remove_cv_t<U>*>(ptr));

其中 weak_this 是 std::shared_from_this 的隐藏 mutable std::weak_ptr 成员。对 weak_this 成员的赋值不是原子的，且与任何到同一对象的潜在并发访问冲突。这确保将来对 shared_from_this() 调用，将与此裸指针构造函数所创建的 shared_ptr 共享所有权。

上述解释代码中，测试 ptr->weak_this.expired() 是为确保若 weak_this 指示已有占有者则重赋值它。从 C++17 起要求此测试。

示例

#include <iostream>
#include <memory>
#include <type_traits>

struct C
{
  C(int i) : i(i) {} // < 需要构造函数 (C++20 前)
  int i;
};

int main()
{
    auto sp = std::make_shared<C>(12);

    static_assert(std::is_same_v<decltype(sp), std::shared_ptr<C>>);

    std::cout << sp->i << '\n';
}

输出：

12

参阅

(构造函数) | 构造新的 shared_ptr (公开成员函数)
allocate_sharedallocate_shared_for_overwrite (C++20) | 创建管理一个用分配器分配的新对象的共享指针 (函数模板)
make_uniquemake_unique_for_overwrite (C++14)(C++20) | 创建管理一个新对象的独占指针 (函数模板)
operator newoperator new[] | 分配函数 (函数)


std::shared_ptr<T>::operator*, std::shared_ptr<T>::operator->

< cpp‎ | memory‎ | shared ptr
T& operator*() const noexcept; | (1)
T* operator->() const noexcept; | (2)

解引用所存储的指针。若存储的指针为空，则行为未定义。

参数

（无）

返回值

1) 解引用存储的指针所得的结果，即 *get()

2) 存储的指针，即 get()

注意

T 是（可有 cv 限定的） void 类型时，是否声明函数 (1) 是未指定的。

T 是数组类型时，是否声明这两个函数是未指定的。

 (C++17 起)

以上情况下，若声明函数，则其返回类型是未指定的，但保证函数声明合法，函数定义未必合法。这使得 std::shared_ptr <void> 可以实例化。

示例

#include <iostream>
#include <memory>

struct Foo
{
   Foo(int in) : a(in) {}
   void print() const
   {
      std::cout << "a = " << a << '\n';
   }
   int a;
};

int main()
{
   auto ptr = std::make_shared<Foo>(10);
   ptr->print();
   (*ptr).print();
}

输出：

a = 10
a = 10

参阅

get
 返回存储的指针
(公开成员函数)


std::shared_ptr<T>::operator=

< cpp‎ | memory‎ | shared ptr
shared_ptr& operator=( const shared_ptr& r ) noexcept; | (1) |
template< class Y > shared_ptr& operator=( const shared_ptr<Y>& r ) noexcept; | (1) |
shared_ptr& operator=( shared_ptr&& r ) noexcept; | (2) |
template< class Y > shared_ptr& operator=( shared_ptr<Y>&& r ) noexcept; | (2) |
template< class Y > shared_ptr& operator=( std::auto_ptr <Y>&& r ); | (3) | (C++11 中弃用) (C++17 中移除)
template< class Y, class Deleter > shared_ptr& operator=( std::unique_ptr <Y,Deleter>&& r ); | (4) |

以 r 所管理者替换被管理对象。

若 *this 已占有对象且它是最后一个占有该对象的 shared_ptr ，且 r 与 *this 不相同，则通过占有的删除器销毁对象。

1) 共享 r 所管理对象的所有权。若 r 不管理对象，则 *this 亦不管理对象。等价于 shared_ptr<T>(r).swap(*this) 。
2) 从 r 移动赋值 shared_ptr 。赋值后， *this 含有先前 r 状态的副本，而 r 为空，等价于 shared_ptr<T>(std::move(r)).swap(*this) 。
3) 转移 r 所管理对象的所有权给 *this 。若 r 不管理对象，则 *this 亦不管理对象。赋值后， *this 含有先前 r 所保有的对象，且 use_count()==1 ；而 r 为空。等价于 shared_ptr<T>(r).swap(*this) 。
4) 转移 r 所管理对象的所有权给 *this 。为将来删除被管理对象，存储关联到 r 的删除器。调用后 r 不管理对象。等价于 shared_ptr<T>(std::move(r)).swap(*this) 。

参数

r - 要获得所有权或共享所有权的另一智能指针

返回值

*this

注解

实现可以满足要求而无需创建临时的 shared_ptr 对象。

异常

3,4) 可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

reset
 替换所管理的对象
(公开成员函数)


std::shared_ptr<T>::operator[]

< cpp‎ | memory‎ | shared ptr
element_type& operator[]( std::ptrdiff_t idx ) const; | (C++17 起)

到存储的指针所指向的数组内的下标。

若存储的指针为空或 idx 为负则行为未定义。

若 T （ shared_ptr 的模板形参）是数组类型 U[N] ，则 idx 必须小于 N ，否则行为未定义。

参数

idx - 数组下标

返回值

到数组第 idx 元素的引用，即 get()[idx] 。

异常

不抛出。

提醒

T 不是数组类型时，是否声明此函数是未指定的。若声明此函数，则其返回类型是未指定的，但函数声明保证合法，函数定义未必合法。

示例

#include <cstddef>
#include <memory>
#include <iostream>
int main() {
    const std::size_t arr_size = 10;
    std::shared_ptr<int[]> pis(new int[10]{0,1,2,3,4,5,6,7,8,9});
    for (std::size_t i = 0; i < arr_size; i++){
        std::cout << pis[i] << ' ';
    }
}

输出：

0 1 2 3 4 5 6 7 8 9

参阅

get
 返回存储的指针
(公开成员函数)


std::shared_ptr<T>::operator bool

< cpp‎ | memory‎ | shared ptr
explicit operator bool() const noexcept;

检查 *this 是否存储非空指针，即是否有 get() != nullptr 。

参数

（无）

返回值

若 *this 存储非空指针则为 true ，否则为 false 。

注意

空 shared_ptr （其中 use_count() == 0 ）可能存储能以 get() 访问的非空指针，例如若它以别名使用构造函数创建。

示例

#include <iostream>
#include <memory>

void report(std::shared_ptr<int> ptr)
{
    if (ptr) {
        std::cout << "*ptr=" << *ptr << "\n";
    } else {
        std::cout << "ptr is not a valid pointer.\n";
    }
}

int main()
{
    std::shared_ptr<int> ptr;
    report(ptr);

    ptr = std::make_shared<int>(7);
    report(ptr);
}

输出：

ptr is not a valid pointer.
*ptr=7

参阅

get
 返回存储的指针
(公开成员函数)


operator==, !=, <, <=, >, >=, <=> (std::shared_ptr)

< cpp‎ | memory‎ | shared ptr
定义于头文件 <memory>
比较二个 shared_ptr 对象
template < class T, class U >

bool operator==( const std::shared_ptr <T>& lhs,

const std::shared_ptr <U>& rhs ) noexcept;
 (1) (C++11 起)
template< class T, class U >

bool operator!=( const std::shared_ptr <T>& lhs,

const std::shared_ptr <U>& rhs ) noexcept;
 (2) (C++11 起)
(C++20 前)
template< class T, class U >

bool operator<( const std::shared_ptr <T>& lhs,

const std::shared_ptr <U>& rhs ) noexcept;
 (3) (C++11 起)
(C++20 前)
template< class T, class U >

bool operator>( const std::shared_ptr <T>& lhs,

const std::shared_ptr <U>& rhs ) noexcept;
 (4) (C++11 起)
(C++20 前)
template< class T, class U >

bool operator<=( const std::shared_ptr <T>& lhs,

const std::shared_ptr <U>& rhs ) noexcept;
 (5) (C++11 起)
(C++20 前)
template< class T, class U >

bool operator>=( const std::shared_ptr <T>& lhs,

const std::shared_ptr <U>& rhs ) noexcept;
 (6) (C++11 起)
(C++20 前)
template< class T, class U >

std::strong_ordering operator<=>( const std::shared_ptr <T>& lhs,

const std::shared_ptr <U>& rhs ) noexcept;
 (7) (C++20 起)
比较 shared_ptr 与空指针
template< class T >
bool operator==( const std::shared_ptr <T>& lhs, std::nullptr_t ) noexcept;
 (8) (C++11 起)
template< class T >
bool operator==( std::nullptr_t, const std::shared_ptr <T>& rhs ) noexcept;
 (9) (C++11 起)
(C++20 前)
template< class T >
bool operator!=( const std::shared_ptr <T>& lhs, std::nullptr_t ) noexcept;
 (10) (C++11 起)
(C++20 前)
template< class T >
bool operator!=( std::nullptr_t, const std::shared_ptr <T>& rhs ) noexcept;
 (11) (C++11 起)
(C++20 前)
template< class T >
bool operator<( const std::shared_ptr <T>& lhs, std::nullptr_t ) noexcept;
 (12) (C++11 起)
(C++20 前)
template< class T >
bool operator<( std::nullptr_t, const std::shared_ptr <T>& rhs ) noexcept;
 (13) (C++11 起)
(C++20 前)
template< class T >
bool operator>( const std::shared_ptr <T>& lhs, std::nullptr_t ) noexcept;
 (14) (C++11 起)
(C++20 前)
template< class T >
bool operator>( std::nullptr_t, const std::shared_ptr <T>& rhs ) noexcept;
 (15) (C++11 起)
(C++20 前)
template< class T >
bool operator<=( const std::shared_ptr <T>& lhs, std::nullptr_t ) noexcept;
 (16) (C++11 起)
(C++20 前)
template< class T >
bool operator<=( std::nullptr_t, const std::shared_ptr <T>& rhs ) noexcept;
 (17) (C++11 起)
(C++20 前)
template< class T >
bool operator>=( const std::shared_ptr <T>& lhs, std::nullptr_t ) noexcept;
 (18) (C++11 起)
(C++20 前)
template< class T >
bool operator>=( std::nullptr_t, const std::shared_ptr <T>& rhs ) noexcept;
 (19) (C++11 起)
(C++20 前)
template< class T >

std::strong_ordering operator<=>( const std::shared_ptr <T>& lhs,

std::nullptr_t ) noexcept;
 (20) (C++20 起)

比较二个 shared_ptr<T> 对象或将 shared_ptr<T> 与空指针比较。

注意 shared_ptr 的比较运算符简单地比较指针值；不比较所指向的实际对象。对 shared_ptr 定义 operator< 允许将 shared_ptr 用作关联容器，如 std::map 与 std::set 中的键。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs | - | 要比较的左侧 shared_ptr
rhs | - | 要比较的右侧 shared_ptr

返回值

1) lhs.get() == rhs.get()
2) !(lhs == rhs)
3) std::less <V>()(lhs.get(), rhs.get()) ，其中 V 是 std::shared_ptr <T>::element_type* 与 std::shared_ptr <U>::element_type* 的合成指针类型
4) rhs < lhs
5) !(rhs < lhs)
6) !(lhs < rhs)
7) std::compare_three_way{}(x.get(), y.get())
8) !lhs
9) !rhs
10) (bool)lhs
11) (bool)rhs
12) std::less < std::shared_ptr <T>::element_type*>()(lhs.get(), nullptr)
13) std::less < std::shared_ptr <T>::element_type*>()(nullptr, rhs.get())
14) nullptr < lhs
15) rhs < nullptr
16) !(nullptr < lhs)
17) !(rhs < nullptr)
18) !(lhs < nullptr)
19) !(nullptr < rhs)
20) std::compare_three_way{}(x.get(), static_cast< std::shared_ptr <T>::element_type*>(nullptr))

注解

所有情况下，被比较者是存储的指针（ get() 所返回者）而非被管理指针（ uses_count 达到零时传递给删除器者）。二个指针可能在用别名使用构造函数创建的 shared_ptr 中有别。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3427 | C++20 | operator<=>(shared_ptr, nullptr_t) 非良构 | 修正定义

参阅

get
 返回存储的指针
(公开成员函数)


std::shared_ptr<T>::operator<<

< cpp‎ | memory‎ | shared ptr
template <class T, class U, class V>
std::basic_ostream <U, V>& operator<<( std::basic_ostream <U, V>& os, const std::shared_ptr <T>& ptr);

插入存储于 ptr 的指针值到输出流 os 中。

等价于 os << ptr.get() 。

参数

os | - | 要插入 ptr 到的 std::basic_ostream
ptr | - | 被插入到 os 的数据

返回值

os

示例

#include <iostream>
#include <memory>

class Foo {};

int main()
{
    auto sp = std::make_shared<Foo>();
    std::cout << sp << std::endl;
    std::cout << sp.get() << std::endl;
}

可能的输出：

0x6d9028
0x6d9028

参阅

get
 返回存储的指针
(公开成员函数)


std::shared_ptr<T>::owner_before

< cpp‎ | memory‎ | shared ptr

template< class Y >
bool owner_before( const shared_ptr<Y>& other) const noexcept;
template< class Y >
bool owner_before( const std::weak_ptr <Y>& other) const noexcept;

以实现定义的基于拥有者（与基于值相反）顺序，检查此 shared_ptr 是否先于 other 。二个智能指针仅若都占有同一对象或均为空才比较相等，即使由 get() 获得的指针不同（例如因为它们指向同一对象中的不同子对象）。

此顺序用于令共享和弱指针可用作关联容器中的关键，通常经由 std::owner_less 。

参数

other - 要比较的 std::shared_ptr 或 std::weak_ptr

返回值

若 *this 前于 other 则为 true ，否则为 false 。常见实现比较控制块的地址。

示例

#include <iostream>
#include <memory>

struct Foo {
    int n1;
    int n2;
    Foo(int a, int b) : n1(a), n2(b) {}
};
int main()
{
    auto p1 = std::make_shared<Foo>(1, 2);
    std::shared_ptr<int> p2(p1, &p1->n1);
    std::shared_ptr<int> p3(p1, &p1->n2);

    std::cout << std::boolalpha
              << "p2 < p3 " << (p2 < p3) << '\n'
              << "p3 < p2 " << (p3 < p2) << '\n'
              << "p2.owner_before(p3) " << p2.owner_before(p3) << '\n'
              << "p3.owner_before(p2) " << p3.owner_before(p2) << '\n';

    std::weak_ptr<int> w2(p2);
    std::weak_ptr<int> w3(p3);
    std::cout
//              << "w2 < w3 " << (w2 < w3) << '\n'  // won't compile
//              << "w3 < w2 " << (w3 < w2) << '\n'  // won't compile
              << "w2.owner_before(w3) " << w2.owner_before(w3) << '\n'
              << "w3.owner_before(w2) " << w3.owner_before(w2) << '\n';

}

输出：

p2 < p3 true
p3 < p2 false
p2.owner_before(p3) false
p3.owner_before(p2) false
w2.owner_before(w3) false
w3.owner_before(w2) false

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2873 | C++11 | owner_before 可以不声明为 noexcept | 声明为 noexcept

参阅

owner_less
(C++11)
 提供基于所有者的，共享指针和弱指针的混合类型的排序
(类模板)


std::static_pointer_cast, std::dynamic_pointer_cast, std::const_pointer_cast, std::reinterpret_pointer_cast

< cpp‎ | memory‎ | shared ptr
定义于头文件 <memory> |  |
template< class T, class U > std::shared_ptr <T> static_pointer_cast( const std::shared_ptr <U>& r ) noexcept; | (1) | (C++11 起)
template< class T, class U > std::shared_ptr <T> static_pointer_cast( std::shared_ptr <U>&& r ) noexcept; | (2) | (C++20 起)
template< class T, class U > std::shared_ptr <T> dynamic_pointer_cast( const std::shared_ptr <U>& r ) noexcept; | (3) | (C++11 起)
template< class T, class U > std::shared_ptr <T> dynamic_pointer_cast( std::shared_ptr <U>&& r ) noexcept; | (4) | (C++20 起)
template< class T, class U > std::shared_ptr <T> const_pointer_cast( const std::shared_ptr <U>& r ) noexcept; | (5) | (C++11 起)
template< class T, class U > std::shared_ptr <T> const_pointer_cast( std::shared_ptr <U>&& r ) noexcept; | (6) | (C++20 起)
template< class T, class U > std::shared_ptr <T> reinterpret_pointer_cast( const std::shared_ptr <U>& r ) noexcept; | (7) | (C++17 起)
template< class T, class U > std::shared_ptr <T> reinterpret_pointer_cast( std::shared_ptr <U>&& r ) noexcept; | (8) | (C++20 起)

创建 std::shared_ptr 的新实例，其存储指针从 r 的存储指针用转型表达式获得。

若 r 为空，则新的 shared_ptr 亦然（但其存储指针不必为空）。否则，新的 shared_ptr 将与 r 的初始值共享所有权，除了若 dynamic_pointer_cast 所进行的 dynamic_cast 返回空指针，则为它空。

令 Y 为 typename std::shared_ptr <T>::element_type ，则将分别通过求值下列表达式，获得生成 std::shared_ptr 的存储指针：

1-2) static_cast<Y*>(r.get()) 。
3-4) dynamic_cast<Y*>(r.get()) （若 dynamic_cast 的结果是空指针值，则返回的 shared_ptr 将为空）。
5-6) const_cast<Y*>(r.get()) 。
7-8) reinterpret_cast<Y*>(r.get()) 。

这些函数的行为未定义，除非从 U* 到 T* 的对应转型为良式：

1-2) 行为未定义，除非 static_cast<T*>((U*)nullptr) 为良式。
3-4) 行为未定义，除非 dynamic_cast<T*>((U*)nullptr) 为良式。
5-6) 行为未定义，除非 const_cast<T*>((U*)nullptr) 为良式。
7-8) 行为未定义，除非 reinterpret_cast<T*>((U*)nullptr) 为良式。

调用右值重载 (2,4,6,8) 后， r 为空且 r.get() == nullptr ，除了对于 dynamic_pointer_cast (4) ，若 dynamic_cast 失败则不修改 r 。

 (C++20 起)

参数

r - 要转换的指针

注意

表达式 std::shared_ptr <T>(static_cast<T*>(r.get())) 、 std::shared_ptr <T>(dynamic_cast<T*>(r.get())) 及 std::shared_ptr <T>(const_cast<T*>(r.get())) 看起来可能拥有相同效果，但它们全都很可能导致未定义行为，试图删除同一对象二次！

可能的实现

版本一
template< class T, class U >
std::shared_ptr<T> static_pointer_cast( const std::shared_ptr<U>& r ) noexcept
{
    auto p = static_cast<typename std::shared_ptr<T>::element_type*>(r.get());
    return std::shared_ptr<T>(r, p);
}
版本二
template< class T, class U >
std::shared_ptr<T> dynamic_pointer_cast( const std::shared_ptr<U>& r ) noexcept
{
    if (auto p = dynamic_cast<typename std::shared_ptr<T>::element_type*>(r.get())) {
        return std::shared_ptr<T>(r, p);
    } else {
        return std::shared_ptr<T>();
    }
}
版本三
template< class T, class U >
std::shared_ptr<T> const_pointer_cast( const std::shared_ptr<U>& r ) noexcept
{
    auto p = const_cast<typename std::shared_ptr<T>::element_type*>(r.get());
    return std::shared_ptr<T>(r, p);
}

示例

#include <iostream>
#include <memory>

struct BaseClass {};

struct DerivedClass : BaseClass
{
    void f() const
    {
        std::cout << "Hello World!\n";
    }
    ~DerivedClass(){ // 注意：它不是虚的
        std::cout << "~DerivedClass\n";
    }
};

int main()
{
    std::shared_ptr<BaseClass> ptr_to_base(std::make_shared<DerivedClass>());

    // ptr_to_base->f(); // 错误不会编译： BaseClass 无名为 'f' 的成员

    std::static_pointer_cast<DerivedClass>(ptr_to_base)->f(); // OK
    // （构造临时 shared_ptr ，然后调用 operator-> ）

    static_cast<DerivedClass*>(ptr_to_base.get())->f(); // 亦 OK
    // （直接转型，不构造临时 shared_ptr ）
}

输出：

Hello World!
Hello World!
~DerivedClass

参阅

(构造函数)
 构造新的 shared_ptr
(公开成员函数)


std::shared_ptr<T>::reset

< cpp‎ | memory‎ | shared ptr
void reset() noexcept; | (1) | (C++11 起)
template< class Y > void reset( Y* ptr ); | (2) | (C++11 起)
template< class Y, class Deleter > void reset( Y* ptr, Deleter d ); | (3) | (C++11 起)
template< class Y, class Deleter, class Alloc > void reset( Y* ptr, Deleter d, Alloc alloc ); | (4) | (C++11 起)

以 ptr 所指向的对象替换被管理对象。能可选地提供删除器 d ，之后在无 shared_ptr 对象占有该对象时以之销毁新对象。默认以 delete 表达式为删除器。始终选择对应提供类型的 delete 表达式，这是函数以使用分离的形参 Y 的模板实现的理由。

若 *this 已占有对象，且它是最后一个占有该对象的 shared_ptr ，则通过所占有的删除器销毁对象。

若 ptr 所指向的对象已被占有，则函数通常会导致未定义行为。

1) 释放被管理对象的所有权，若存在。调用后， *this 不管理对象。等价于 shared_ptr().swap(*this); 。
2-4) 以 ptr 所指向对象替换被管理对象。 Y 必须是完整类型且可隐式转换为 T 。另外：
2) 以 delete 表达式为删除器。合法的 delete 表达式必须可用，即 delete ptr 必须为良式，拥有良好定义行为且不抛任何异常。等价于 shared_ptr<T>(ptr).swap(*this); 。
3) 以指定的删除器 d 为删除器。 Deleter 必须对 T 类型可调用，即 d(ptr)必须为良构，拥有良好定义行为且不抛任何异常。 Deleter 必须可复制构造 (CopyConstructible) ，且其复制构造函数和析构函数必须不抛异常。等价于 shared_ptr<T>(ptr, d).swap(*this); 。
4) 同 (3) ，但额外地用 alloc 的副本分配内部使用的数据。 Alloc 必须是分配器 (Allocator) 。复制构造函数和析构函数必须不抛异常。等价于 shared_ptr<T>(ptr, d, alloc).swap(*this); 。

参数

ptr | - | 指向要取得所有权的对象的指针
d | - | 为删除对象而存储的删除器
alloc | - | 内部存储所用的分配器

返回值

（无）

异常

2) 若无法获得要求的额外内存则为 std::bad_alloc 。可能因其他错误抛出实现定义的异常。若出现异常则调用 delete ptr 。
3-4) 若无法获得要求的额外内存则为 std::bad_alloc 。可能因其他错误抛出实现定义的异常。若出现异常则调用 d(ptr) 。

示例

#include <memory>
#include <iostream>

struct Foo {
    Foo(int n = 0) noexcept : bar(n) {
        std::cout << "Foo: constructor, bar = " << bar << '\n';
    }
    ~Foo() {
         std::cout << "Foo: destructor, bar = " << bar << '\n';
    }
    int getBar() const noexcept { return bar; }
private:
    int bar;
};

int main()
{
    std::shared_ptr<Foo> sptr = std::make_shared<Foo>(1);
    std::cout << "The first Foo's bar is " << sptr->getBar() << "\n";

    // 重置，交与新的 Foo 实例
    // （此调用后将销毁旧实例）
    sptr.reset(new Foo);
    std::cout << "The second Foo's bar is " << sptr->getBar() << "\n";
}

输出：

Foo: constructor, bar = 1
The first Foo's bar is 1
Foo: constructor, bar = 0
Foo: destructor, bar = 1
The second Foo's bar is 0
Foo: destructor, bar = 0

参阅

(构造函数)
 构造新的 shared_ptr
(公开成员函数)


std::shared_ptr<T>::shared_ptr

< cpp‎ | memory‎ | shared ptr
constexpr shared_ptr() noexcept; | (1) |
constexpr shared_ptr( std::nullptr_t ) noexcept; | (2) |
template< class Y > explicit shared_ptr( Y* ptr ); | (3) |
template< class Y, class Deleter > shared_ptr( Y* ptr, Deleter d ); | (4) |
template< class Deleter > shared_ptr( std::nullptr_t ptr, Deleter d ); | (5) |
template< class Y, class Deleter, class Alloc > shared_ptr( Y* ptr, Deleter d, Alloc alloc ); | (6) |
template< class Deleter, class Alloc > shared_ptr( std::nullptr_t ptr, Deleter d, Alloc alloc ); | (7) |
template< class Y > shared_ptr( const shared_ptr<Y>& r, element_type* ptr ) noexcept; | (8) |
template< class Y > shared_ptr( shared_ptr<Y>&& r, element_type* ptr ) noexcept; | (8) | (C++20 起)
shared_ptr( const shared_ptr& r ) noexcept; | (9) |
template< class Y > shared_ptr( const shared_ptr<Y>& r ) noexcept; | (9) |
shared_ptr( shared_ptr&& r ) noexcept; | (10) |
template< class Y > shared_ptr( shared_ptr<Y>&& r ) noexcept; | (10) |
template< class Y > explicit shared_ptr( const std::weak_ptr <Y>& r ); | (11) |
template< class Y > shared_ptr( std::auto_ptr <Y>&& r ); | (12) | (C++17 中移除)
template< class Y, class Deleter > shared_ptr( std::unique_ptr <Y,Deleter>&& r ); | (13) |

从指代要管理的对象的各种指针类型构造新的 shared_ptr 。

为以下描述的目的，若指针类型 Y* 可转换为指针类型 T* ，或 Y 是 U[N] 类型数组而 T 是 U cv [] （其中 cv 是某个 cv 限定符集合），则说 Y* 兼容 T* 。

 (C++17 起)
1-2) 构造无被管理对象的 shared_ptr ，即空 shared_ptr 。
3-7) 构造 shared_ptr ，管理 ptr 所指向的对象。
对于 (3-4,6) ， Y* 必须可转换为 T* 。 | (C++17 前)
若 T 是数组类型 U[N] ，则若 Y(*)[N] 不可转换为 T* 则 (3-4,6) 不参与重载决议。若 T 是数组类型 U[] ，则若 Y(*)[] 不可转换为 T* 则 (3-4,6) 不参与重载决议。否则，若 Y* 不可转换为 T* 则 (3-4,6) 不参与重载决议。 | (C++17 起)
另外：
3) 以 delete 表达式 delete ptr 为删除器，若 T 不是数组类型；以 delete[] ptr 为删除器，若 T 是数组类型 (C++17 起)。 Y 必须是完整类型。 delete 表达式必须为良构，拥有良好定义行为且不抛异常。若 delete 表达式不为良构，则此构造函数不参与重载决议。 (C++17 起)
4-5) 以指定的删除器 d 为删除器。表达式 d(ptr) 表达式必须为良构，拥有良好定义行为且不抛异常。 d 的构造和从 d 构造存储的删除器必须不抛异常。
Deleter 必须可复制构造 (CopyConstructible) 。 | (C++17 前)
若表达式 d(ptr) 非良构，或若 std::is_move_constructible <D>::value 为 false ，则这些构造函数不额外参与重载决议。 | (C++17 起)
6-7) 同 (4-5) ，但额外地用 alloc 的副本分配内部使用的数据。 Alloc 必须是分配器 (Allocator) 。
8) 别名使用构造函数：构造 shared_ptr ，与 r 的初始值共享所有权信息，但保有无关且不管理的指针 ptr 。若此 shared_ptr 是离开作用域的组中的最后者，则它将调用最初 r 所管理对象的析构函数。然而，在此 shared_ptr 上调用 get() 将始终返回 ptr 的副本。程序员负责确保只要此 shared_ptr 存在，此 ptr 就保持合法，例如在典型使用情况中，其中 ptr 是 r 所管理对象的成员，或是 r.get() 的别名（例如向下转型）。对于接收右值的第二重载，调用后 r 为空且 r.get() == nullptr 。 (C++20 起)
9) 构造 shared_ptr ，共享 r 所管理对象的所有权。若 r 不管理对象，则 *this 亦不管理对象。若 Y* 不可隐式转换为 (C++17 前)兼容 (C++17 起) T* ，则模板重载不参与重载决议。
10) 从 r 移动构造 shared_ptr 。构造后， *this 含 r 先前状态的副本，而 r 为空且其存储的指针为空。若 Y* 不可隐式转换为 (C++17 前)兼容 (C++17 起) T* ，则模板重载不参与重载决议。
11) 构造 shared_ptr ，共享 r 所管理对象的所有权。 Y* 必须可隐式转换为 T* 。 (C++17 前)此重载仅若 Y* 兼容 T* 才参与重载决议。 (C++17 起)注意可为相同目的用 r.lock() ：区别是若参数为空则此构造函数抛异常，而 std::weak_ptr <T>::lock() 在该情况下构造空的 std::shared_ptr 。
12) 构造 shared_ptr ，存储并占有 r 先前占有的对象。 Y* 必须可转换为 T* 。构造后， r 为空。
13) 构造 shared_ptr ，管理当前为 r 所管理的对象。存储与 r 关联的删除器以在未来删除被管理对象。调用后 r 不管理对象。
若 std::unique_ptr<Y, Deleter>::pointer 不兼容 T* 则此重载不参与重载决议。若 r.get() 是空指针，则此重载等价于默认构造函数 (1) 。 (C++17 起)
若 Deleter 是引用类型，则等价于 shared_ptr(r.release(), std::ref (r.get_deleter()) 。否则，等价于 shared_ptr(r.release(), std::move(r.get_deleter())) 。

T 不是数组类型时，重载 (3) 、 (4) 及 (6) 以 ptr 启用 shared_from_this ，而重载 (13) 以 r.release() 所返回的指针启用 shared_from_this 。

注解

T 不是数组类型是，重载 (3) 、 (4) 及 (6) 以 ptr 启用 shared_from_this ，而重载 (13) 以 r.release() 所返回的指针启用 shared_from_this 。

构造函数以 U* 类型指针 ptr 启用 shared_from_this ，表示它确定 U 是否拥有作为 std::enable_shared_from_this 特化的无歧义且可访问 (C++17 起)基类，而若如此，则构造函数求值该语句：

if (ptr != nullptr && ptr->weak_this.expired())
  ptr->weak_this = std::shared_ptr<std::remove_cv_t<U>>(*this,
                                  const_cast<std::remove_cv_t<U>*>(ptr));

其中 weak_this 是 std::shared_from_this 的隐藏 mutable std::weak_ptr 成员。对 weak_this 成员的赋值不是原子的，且与任何到同一对象的潜在并发访问冲突。这确保将来对 shared_from_this() 调用，将与此裸指针构造函数所创建的 shared_ptr 共享所有权。

上述解释代码中，测试 ptr->weak_this.expired() 是为确保若 weak_this 指示已有占有者则重赋值它。从 C++17 起要求此测试。

裸指针重载认定被指向对象的所有权。从而，用裸指针重载为已经为 shared_ptr 所管理对象构造 shared_ptr ，例如以 shared_ptr(ptr.get()) 很可能导致未定义行为，即使对象有导出自 std::enable_shared_from_this 的类型。

因为默认构造函数是 constexpr ，静态 shared_ptrs 作为静态非局部初始化的一部分初始化，在任何动态初始化开始前。这使得在任何静态对象的构造函数中使用 shared_ptr 是安全的。

C++11 和 C++14 中，从 std::unique_ptr <T[]> 构造 std::shared_ptr <T> 是合法的：

std::unique_ptr<int[]> arr(new int[1]);
std::shared_ptr<int> ptr(std::move(arr));

因为 shared_ptr 从 unique_ptr 获得其删除器（ std::default_delete <T[]> 对象），故能正确解分配数组。

C++17 中这不再受允许。应当使用替代的数组形式 std::shared_ptr <T[]> 。

参数

ptr | - | 指向要管理的对象的指针
d | - | 用于销毁对象的删除器
alloc | - | 用于分配内部使用的数据的分配器
r | - | 要共享所有权或从它获得所有权的另一智能指针

异常

3) 若无法获得要求的附加内存则为 std::bad_alloc 。可能因其他错误抛出实现定义的异常。若异常出现，则调用 delete ptr，若 T 非数组类型，否则调用 delete[] ptr (C++17 起) 。
4-7) 若无法获得要求的附加内存则为 std::bad_alloc 。可能因其他错误抛出实现定义的异常。若异常出现，则调用 d(ptr) 。
11) 若 r.expired() == true 则为 std::bad_weak_ptr 。若异常出现，则此构造函数无效果。
12) 若无法获得要求的附加内存则为 std::bad_alloc 。可能因其他错误抛出实现定义的异常。若异常出现，则此构造函数无效果。
13) 若抛异常，则构造函数无效果。

示例

#include <memory>
#include <iostream>

struct Foo {
    Foo() { std::cout << "Foo...\n"; }
    ~Foo() { std::cout << "~Foo...\n"; }
};

struct D {
    void operator()(Foo* p) const {
        std::cout << "Call delete from function object...\n";
        delete p;
    }
};

int main()
{
    {
        std::cout << "constructor with no managed object\n";
        std::shared_ptr<Foo> sh1;
    }

    {
        std::cout << "constructor with object\n";
        std::shared_ptr<Foo> sh2(new Foo);
        std::shared_ptr<Foo> sh3(sh2);
        std::cout << sh2.use_count() << '\n';
        std::cout << sh3.use_count() << '\n';
    }

    {
        std::cout << "constructor with object and deleter\n";
        std::shared_ptr<Foo> sh4(new Foo, D());
        std::shared_ptr<Foo> sh5(new Foo, [](auto p) {
           std::cout << "Call delete from lambda...\n";
           delete p;
        });
    }
}

输出：

constructor with no managed object
constructor with object
Foo...
2
2
~Foo...
constructor with object and deleter
Foo...
Foo...
Call delete from lambda...
~Foo...
Call delete from function object...
~Foo..

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3548 | C++11 | 源自 unique_ptr 的构造函数复制构造删除器 | 改为移动构造

参阅

make_sharedmake_shared_for_overwrite (C++20) | 创建管理一个新对象的共享指针 (函数模板)
allocate_sharedallocate_shared_for_overwrite (C++20) | 创建管理一个用分配器分配的新对象的共享指针 (函数模板)
enable_shared_from_this (C++11) | 允许对象创建指代自身的 shared_ptr (类模板)


std::shared_ptr<T>::swap

< cpp‎ | memory‎ | shared ptr
void swap( shared_ptr& r ) noexcept; | (C++11 起)

交换 *this 与 r 的存储指针值与所有权。不调整引用计数，若它们存在。

参数

r - 要与之交换内容的智能指针

返回值

（无）


std::swap(std::shared_ptr)

< cpp‎ | memory‎ | shared ptr

定义于头文件 <memory> |
template< class T > void swap( std::shared_ptr <T>& lhs, std::shared_ptr <T>& rhs ) noexcept; | (C++11 起)

对 std::shared_ptr 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的智能指针

返回值

（无）

复杂度

常数

参阅

swap | 交换两个对象的值 (函数模板)
swap | 交换内容 (公开成员函数)


std::shared_ptr<T>::unique

< cpp‎ | memory‎ | shared ptr
bool unique() const noexcept; | (C++17 中弃用) (C++20 中移除)

检查 *this 是否管理当前对象的仅有 shared_ptr 实例，即是否 use_count() == 1 。

参数

（无）

返回值

若 *this 否管理当前对象的仅有 shared_ptr 实例则为 true ，否则为 false 。

注意

此函数于 C++17 中被弃用并于 C++20 中移除，因为 use_count 在多线程环境中只是估计（见 use_count 中的“注意”）。

示例

#include <memory>
#include <iostream>

int main()
{
    auto sp1 = std::make_shared<int>(5);
    std::cout << std::boolalpha;
    std::cout << "sp1.unique() == " << sp1.unique() << '\n';

    std::shared_ptr<int> sp2 = sp1;
    std::cout << "sp1.unique() == " << sp1.unique() << '\n';
}

输出：

sp1.unique() == true
sp1.unique() == false

参阅

use_count
 返回 shared_ptr 所指对象的引用计数
(公开成员函数)


std::shared_ptr<T>::use_count

< cpp‎ | memory‎ | shared ptr
long use_count() const noexcept;

返回管理当前对象的不同 shared_ptr 实例（包含 this ）数量。若无管理对象，则返回 ​0​ 。

多线程环境下， use_count 返回的值是近似的（典型实现使用 memory_order_relaxed 加载）

参数

（无）

返回值

管理当前对象的 shared_ptr 实例数量，或若无被管理对象则为 ​0​ 。

注意

常用使用包括

  • 与 ​0​ 比较。若 use_count 返回零，则智能指针为空且不管理对象（无论被存储指针是否为空）。多线程环境下，这不隐含被管理对象的析构函数已完成。
  • 与 1 比较。若 use_count 返回 1 ，则无其他拥有者。（被弃用成员函数 unique() 为此使用情况提供。）多线程环境中，这不隐含对象可以安全修改，因为先前拥有者对被管理对象的访问可能未完成，而因为新的共享拥有者可以同时引入，例如用 std::weak_ptr::lock 。

示例

#include <memory>
#include <iostream>

void fun(std::shared_ptr<int> sp)
{
    std::cout << "fun: sp.use_count() == " << sp.use_count() << '\n';
}

int main()
{
    auto sp1 = std::make_shared<int>(5);
    std::cout << "sp1.use_count() == " << sp1.use_count() << '\n';

    fun(sp1);
}

输出：

sp1.use_count() == 1
fun: sp.use_count() == 2

参阅

unique
(C++20 前)
 检查所管理对象是否仅由当前 shared_ptr 的实例管理
(公开成员函数)


std::shared_ptr<T>::~shared_ptr

< cpp‎ | memory‎ | shared ptr
~shared_ptr();

若 *this 占有对象且它是最后一个占有该对象的 shared_ptr ，则通过占有的删除器销毁对象。

析构后，与 *this 共享所有权的智能指针若存在，则报告比先前值少一的 use_count() 。

注解

不同于 std::unique_ptr ，即使被管理指针为空也调用 std::shared_ptr 的删除器。

示例

本节未完成
原因：暂无示例

参阅

(析构函数)
 销毁 weak_ptr
(std::weak_ptr<T> 的公开成员函数)


std::pmr::synchronized_pool_resource

< cpp‎ | memory
定义于头文件 <memory_resource> |
class synchronized_pool_resource : public std::pmr::memory_resource ; | (C++17 起)

类 std::pmr::synchronized_pool_resource 是带下列属性的通用内存资源类：

  • 它占有被分配内存并在析构时释放它，即使 deallocate 未被对于某些被分配块调用。
  • 它由供应不同块大小请求的池的汇集组成。每个池管理之后被分入一致大小的大块的汇集。
  • 对 do_allocate 的调用被派发到供应适应请求大小的最小块的池。
  • 在池中耗尽内存，会导致该池从上游分配器分配额外的内存大块，以填满池。获取的大块大小以几何级数增加。
  • 请求超出最大的块大小的分配，由上游分配器直接供应。
  • 最大的块大小和大块大小的最大值可通过传递 std::pmr::pool_options 结构体给其构造函数调节。

synchronized_pool_resource 可以从多个线程不经同步地访问，并可拥有线程指定的池以减少同步成本。若内存资源只从单个线程访问，则 unsynchronized_pool_resource 更有效率。

成员函数

(构造函数)
 构造 synchronized_pool_resource
(公开成员函数)
(析构函数)
[虚]
 销毁 synchronized_pool_resource ，释放所有分配的资源
(虚公开成员函数)
operator=
[被删除]
 复制赋值运算符被删除。 synchronized_pool_resource 不可复制赋值
(公开成员函数)
公开成员函数
release
 释放所有分配的内存
(公开成员函数)
upstream_resource
 返回指向上游 memory_resource 的指针
(公开成员函数)
options
 返回控制此资源分池行为的选项
(公开成员函数)
受保护成员函数
do_allocate
[虚]
 分配内存
(虚受保护成员函数)
do_deallocate
[虚]
 返还内存到池
(虚受保护成员函数)
do_is_equal
[虚]
 与另一 memory_resource 比较相等
(虚受保护成员函数)


std::pmr::synchronized_pool_resource::do_allocate

< cpp‎ | memory‎ | synchronized pool resource
virtual void* do_allocate( std::size_t bytes, std::size_t alignment); | (C++17 起)

分配存储。

若为块大小 bytes 选择的池无以满足来自其内部数据结构的请求，则调用上游 memory_resource 上的 allocate() 获得内存。

若请求的大小大于最大的池所能处理者，则通过调用上游 memory_resources 上的 allocate() 分配内存。

返回值

指向至少有 bytes 字节大小，若支持该对齐则对齐到指定的 alignment ，否则对齐到 alignof( std::max_align_t ) 的存储的指针。

异常

不抛出，除非上游 memory_resources 上 allocate() 的调用抛出异常。

参阅

allocate | 分配内存 (std::pmr::memory_resource 的公开成员函数)
do_allocate [虚] | 分配内存 (std::pmr::memory_resource 的虚私有成员函数)


std::pmr::synchronized_pool_resource::do_deallocate

< cpp‎ | memory‎ | synchronized pool resource
virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment); | (C++17 起)

返回位于 p 的内存到池。此操作是否或在何种情况下导致上游 memory_resource 上对 deallocate() 的调用是未指定的。

异常

不抛出任何异常。

参阅

deallocate | 解分配内存 (std::pmr::memory_resource 的公开成员函数)
do_deallocate [虚] | 解分配内存 (std::pmr::memory_resource 的虚私有成员函数)


std::pmr::synchronized_pool_resource::do_is_equal

< cpp‎ | memory‎ | synchronized pool resource
virtual bool do_is_equal(const std::pmr::memory_resource & other) const noexcept; | (C++17 起)

比较 *this 与 other 的相等性——用 synchronized_pool_resource 分配的内存只能用同一资源解分配。

返回值

this == &other

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3000 | C++17 | 进行了不必要的 dynamic_cast | 已移除

参阅

do_is_equal
[虚]
 与另一 memory_resource 比较相等
(std::pmr::memory_resource 的虚私有成员函数)


std::pmr::synchronized_pool_resource::options

< cpp‎ | memory‎ | synchronized pool resource
std::pmr::pool_options options() const; | (C++17 起)

返回控制此资源分池行为的选项。

返回的结构体中的值，可以以下方式异于供应给构造函数的值：

  • 零值将被替换成实现指定的默认值；
  • 大小可能被取整到未指定的粒度。

参阅

(构造函数)
 构造 synchronized_pool_resource
(公开成员函数)


std::pmr::synchronized_pool_resource::release

< cpp‎ | memory‎ | synchronized pool resource
void release(); | (C++17 起)

在需要时，通过调用上游 memory_resource 上的 deallocate 函数，释放此资源占有的所有内存。

内存被释放回上游 memory_resource ，即使未对某些被分配块调用 deallocate 。

参阅

deallocate
 解分配内存
(std::pmr::memory_resource 的公开成员函数)


std::pmr::synchronized_pool_resource::synchronized_pool_resource

< cpp‎ | memory‎ | synchronized pool resource
synchronized_pool_resource();
 (1) (C++17 起)
explicit synchronized_pool_resource( std::pmr::memory_resource * upstream);
 (2) (C++17 起)
explicit synchronized_pool_resource(const std::pmr::pool_options & opts);
 (3) (C++17 起)
synchronized_pool_resource(const std::pmr::pool_options & opts,
std::pmr::memory_resource * upstream);
 (4) (C++17 起)
synchronized_pool_resource(const synchronized_pool_resource&) = delete;
 (5) (C++17 起)

构造一个 synchronized_pool_resource.

1-4) 用指定的上游 memory_resource 构造一个 synchronized_pool_resource 并根据指定的选项调节。结果对象保有 upstream 的副本但不占有 upstream 所指向的资源。
不将 opts 接收为参数的重载以默认构造的 pool_options 实例为选项。不将 upstream 作为参数接收的重载以 std::pmr::get_default_resource () 的返回值为上游 memory_resource 。
5) 复制构造函数被删除。

参数

opts | - | 含有构造函数选项的 std::pmr::pool_options 结构体
upstream | - | 所用的上游 memory_resource

异常

1-4) 仅若对上游资源的 allocate() 函数调用抛出异常才抛出。是否或在何种条件下发生这种调用是未指定的。


std::pmr::synchronized_pool_resource::upstream_resource

< cpp‎ | memory‎ | synchronized pool resource
std::pmr::memory_resource * upstream_resource() const; | (C++17 起)

返回指向上游 memory_resource 的指针。该值与传递给此对象构造函数的 upstream 参数相同。

参阅

(构造函数)
 构造 synchronized_pool_resource
(公开成员函数)


std::pmr::synchronized_pool_resource::~synchronized_pool_resource

< cpp‎ | memory‎ | synchronized pool resource
virtual ~synchronized_pool_resource(); | (C++17 起)

销毁 synchronized_pool_resource 。

通过调用 this->release() 解分配此资源拥有的所有内存。

参阅

release
 释放所有分配的内存
(公开成员函数)


std::to_address

< cpp‎ | memory
定义于头文件 <memory> |  |
template< class Ptr > constexpr auto to_address(const Ptr& p) noexcept; | (1) | (C++20 起)
template< class T > constexpr T* to_address(T* p) noexcept; | (2) | (C++20 起)

获得 p 所指向的地址，而不形成到被指向者的引用：

1) 缀饰指针重载：若表达式 std::pointer_traits <Ptr>::to_address(p) 为良构，则返回该表达式的结果。否则，返回 std::to_address(p.operator->()) 。
2) 裸指针重载：若 T 为函数类型，则程序为谬构，否则返回不修改的 p 。

参数

p - 缀饰或裸指针

返回值

表示与 p 所表示者相同地址的裸指针。

可能的实现

template<class T>
constexpr T* to_address(T* p) noexcept
{
    static_assert(!std::is_function_v<T>);
    return p;
}

template<class T>
constexpr auto to_address(const T& p) noexcept
{
    if constexpr (requires{ std::pointer_traits<T>::to_address(p); }) {
        return std::pointer_traits<T>::to_address(p);
    } else {
        return std::to_address(p.operator->());
    }
}

注解

即使在 p 引用的存储中无已构造的对象时，也能使用 std::to_address ，该情况下不能用 std::addressof (*p) ，因为无可绑定 std::addressof 参数的合法对象。

to_address 的缀饰指针重载审查 std::pointer_traits <Ptr> 特化。若实例化该特化自身为谬构（往往是因为无法定义 element_type ），则导致立即语境外的硬错误并使得程序为谬构。

示例

#include <memory>

template<class A>
auto allocator_new(A& a)
{
    auto p = a.allocate(1);
    try {
        std::allocator_traits<A>::construct(a, std::to_address(p));
    } catch (...) {
        a.deallocate(p, 1);
        throw;
    }
    return p;
}

template<class A>
void allocator_delete(A& a, typename std::allocator_traits<A>::pointer p)
{
    std::allocator_traits<A>::destroy(a, std::to_address(p));
    a.deallocate(p, 1);
}

int main()
{
    std::allocator<int> a;
    auto p = allocator_new(a);
    allocator_delete(a, p);
}

参阅

pointer_traits (C++11) | 提供关于指针式类型的信息 (类模板)
to_address [静态] (C++20)(可选) | 从缀饰指针获得裸指针（ pointer_to 的反函数） (std::pointer_traits<Ptr> 的公开静态成员函数)


std::uninitialized_construct_using_allocator

< cpp‎ | memory
定义于头文件 <memory> |
template< class T, class Alloc, class... Args > constexpr T* uninitialized_construct_using_allocator( T* p, const Alloc& alloc, Args&&... args ); | (C++20 起)

以使用分配器构造的手段在 p 所指示的未初始化内存位置创建给定类型 T 的对象。

等价于

return std::apply([&]<class... Xs>(Xs&&...xs) {
        return std::construct_at(p, std::forward<Xs>(xs)...);
    }, std::uses_allocator_construction_args<T>(alloc, std::forward<Args>(args)...));

参数

p | - | 将要放置对象的内存位置。
alloc | - | 要使用的分配器。
args | - | 传递给 T 构造函数的参数。

返回值

指向新创建的 T 类型对象的指针。

异常

可能抛出 T 的构造函数所抛的任何异常，常包括 std::bad_alloc 。

示例

本节未完成
原因：暂无示例

参阅

uses_allocator (C++11) | 检查指定的类型是否支持使用分配器的构造 (类模板)
make_obj_using_allocator (C++20) | 以使用分配器构造的手段创建给类型的对象 (函数模板)


std::uninitialized_copy

< cpp‎ | memory
定义于头文件 <memory> |  |
template< class InputIt, class NoThrowForwardIt > NoThrowForwardIt uninitialized_copy( InputIt first, InputIt last, NoThrowForwardIt d_first ); | (1) |
template< class ExecutionPolicy, class ForwardIt, class NoThrowForwardIt > NoThrowForwardIt uninitialized_copy( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, NoThrowForwardIt d_first ); | (2) | (C++17 起)
1) 复制来自范围 [first, last) 的元素到始于 d_first 的未初始化内存，如同用
for (; first != last; ++d_first, (void) ++first)
   ::new (/*VOIDIFY*/(*d_first))
      typename std::iterator_traits<ForwardIt>::value_type(*first);

其中 /*VOIDIFY*/(e) 为：

static_cast<void*>(&e)
 (C++11 前)
static_cast<void*>( std::addressof (e))
 (C++11 起)
(C++20 前)
const_cast<void*>(static_cast<const volatile void*>( std::addressof (e)))
 (C++20 起)
若初始化中抛异常，则以未指定顺序销毁已构造的对象。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要复制的元素范围
d_first | - | 目标范围的起始
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- NoThrowForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 通过 NoThrowForwardIt 合法实例的自增、赋值、比较或间接均不可抛异常。作用 &* 到 NoThrowForwardIt 值必须产生指向其值类型的指针。 (C++11 前)

返回值

指向最后复制的元素后一元素的迭代器。

复杂度

与 first 和 last 间的距离成线性

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class InputIt, class NoThrowForwardIt>
NoThrowForwardIt uninitialized_copy(InputIt first, InputIt last, NoThrowForwardIt d_first)
{
    using T = typename std::iterator_traits<NoThrowForwardIt>::value_type;
    NoThrowForwardIt current = d_first;
    try {
        for (; first != last; ++first, (void) ++current) {
            ::new (const_cast<void*>(static_cast<const volatile void*>(
                std::addressof(*current)))) T(*first);
        }
        return current;
    } catch (...) {
        for (; d_first != current; ++d_first) {
            d_first->~T();
        }
        throw;
    }
}

示例

#include <iostream>
#include <memory>
#include <cstdlib>
#include <string>

int main()
{
    const char *v[] = {"This", "is", "an", "example"};

    auto sz = std::size(v);

    if(void *pbuf = std::aligned_alloc(alignof(std::string), sizeof(std::string) * sz))
    {
        try
        {
            auto first = static_cast<std::string*>(pbuf);
            auto last = std::uninitialized_copy(std::begin(v), std::end(v), first);

            for (auto it = first; it != last; ++it)
                std::cout << *it << '_';
            std::cout << '\n';

            std::destroy(first, last);
        }
        catch(...) {}
        std::free(pbuf);
    }
}

输出：

This_is_an_example_

参阅

uninitialized_copy_n (C++11) | 将指定数量的对象复制到未初始化的内存区域 (函数模板)
ranges::uninitialized_copy (C++20) | 复制元素范围到未初始化的内存区域 (niebloid)


std::uninitialized_copy_n

< cpp‎ | memory
定义于头文件 <memory>
template< class InputIt, class Size, class NoThrowForwardIt >
NoThrowForwardIt uninitialized_copy_n( InputIt first, Size count, NoThrowForwardIt d_first );
 (1) (C++11 起)
template< class ExecutionPolicy, class ForwardIt, class Size, class NoThrowForwardIt >

NoThrowForwardIt uninitialized_copy_n( ExecutionPolicy&& policy, ForwardIt first, Size count,

NoThrowForwardIt d_first );
 (2) (C++17 起)
1) 从始于 first 的范围复制 count 个元素到始于 d_first 的未初始化内存区域，如同以
for ( ; n > 0; ++d_first, (void) ++first, --n)
   ::new (/*VOIDIFY*/(*d_first))
      typename std::iterator_traits<ForwardIt>::value_type(*first);

其中 /*VOIDIFY*/(e) 为：

static_cast<void*>( std::addressof (e))
 (C++20 前)
const_cast<void*>(static_cast<const volatile void*>( std::addressof (e)))
 (C++20 起)
若初始化期间抛异常，则以未指定顺序销毁已构造的对象。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first | - | 要复制的元素范围起始
d_first | - | 目标范围起始
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- NoThrowForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 通过 NoThrowForwardIt 合法实例的自增、赋值、比较或间接均不可抛异常。

返回值

指向最后复制的元素后一元素的迭代器。

复杂度

与 count 成线性。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class InputIt, class Size, class NoThrowForwardIt>
NoThrowForwardIt uninitialized_copy_n(InputIt first, Size count, NoThrowForwardIt d_first)
{
    using T = typename std::iterator_traits<NoThrowForwardIt>::value_type;
    NoThrowForwardIt current = d_first;
    try {
        for (; count > 0; ++first, (void) ++current, --count) {
            ::new (const_cast<void*>(static_cast<const volatile void*>(
                std::addressof(*current)))) T(*first);
        }
    } catch (...) {
        for (; d_first != current; ++d_first) {
            d_first->~T();
        }
        throw;
    }
    return current;
}

示例

#include <algorithm>
#include <iostream>
#include <memory>
#include <string>
#include <tuple>
#include <vector>

int main()
{
    std::vector<std::string> v = {"This", "is", "an", "example"};

    std::string* p;
    std::size_t sz;
    std::tie(p, sz) = std::get_temporary_buffer<std::string>(v.size());
    sz = std::min(sz, v.size());

    std::uninitialized_copy_n(v.begin(), sz, p);

    for (std::string* i = p; i != p+sz; ++i) {
        std::cout << *i << ' ';
        i->~basic_string<char>();
    }
    std::return_temporary_buffer(p);
}

输出：

This is an example

参阅

uninitialized_copy | 将范围内的对象复制到未初始化的内存区域 (函数模板)
ranges::uninitialized_copy_n (C++20) | 复制一定量元素到未初始化的内存区域 (niebloid)


std::uninitialized_default_construct

< cpp‎ | memory
定义于头文件 <memory> |  |
template< class ForwardIt > void uninitialized_default_construct( ForwardIt first, ForwardIt last); | (1) | (C++17 起)
template< class ExecutionPolicy, class ForwardIt > void uninitialized_default_construct( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last ); | (2) | (C++17 起)
1) 以默认初始化在范围 [first, last) 所指代的未初始化存储上构造 typename iterator_traits<ForwardIt>::value_type 类型对象，如同用
for (; first != last; ++first)
  ::new (/*VOIDIFY*/(*first))
      typename std::iterator_traits<ForwardIt>::value_type;

其中 /*VOIDIFY*/(e) 为：

static_cast<void*>( std::addressof (e))
 (C++20 前)
const_cast<void*>(static_cast<const volatile void*>( std::addressof (e)))
 (C++20 起)
若初始化期间抛出异常，则以未指定顺序销毁已构造的对象。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要初始化的元素范围
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 通过 ForwardIt 合法实例的自增、复制、比较或间接均不抛出异常。

返回值

（无）

复杂度

与 first 与 last 间的距离成线性

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class ForwardIt>
void uninitialized_default_construct(ForwardIt first, ForwardIt last)
{
    using Value = typename std::iterator_traits<ForwardIt>::value_type;
    ForwardIt current = first;
    try {
        for (; current != last; ++current) {
            ::new (const_cast<void*>(static_cast<const volatile void*>(
                std::addressof(*current)))) Value;
        }
    }  catch (...) {
        std::destroy(first, current);
        throw;
    }
}

示例

#include <iostream>
#include <memory>
#include <string>
#include <cstring>

int main()
{
    struct S { std::string m{ "Default value" }; };

    constexpr int n {3};
    alignas(alignof(S)) unsigned char mem[n * sizeof(S)];

    try
    {
        auto first {reinterpret_cast<S*>(mem)};
        auto last {first + n};

        std::uninitialized_default_construct(first, last);

        for (auto it {first}; it != last; ++it) {
            std::cout << it->m << '\n';
        }

        std::destroy(first, last);
    }
    catch(...)
    {
        std::cout << "Exception!\n";
    }

    // 注意对于“平凡类型” uninitialized_default_construct 通常不会以零填充未初始化的内存区域。
    int v[] { 1, 2, 3, 4 };
    const int original[] { 1, 2, 3, 4 };
    std::uninitialized_default_construct(std::begin(v), std::end(v));
    // for (const int i : v) { std::cout << i << ' '; }
    // 可能为未定义行为，待定的 CWG 1997 。
    std::cout <<
        (std::memcmp(v, original, sizeof(v)) == 0 ? "Unmodified\n" : "Modified\n");
    // 结果未指定。
}

可能的输出：

Default value
Default value
Default value
Unmodified

参阅

uninitialized_default_construct_n (C++17) | 在起始和计数所定义的未初始化内存区域用默认初始化构造对象 (函数模板)
uninitialized_value_construct (C++17) | 在范围所定义的未初始化内存中用值初始化构造对象 (函数模板)
ranges::uninitialized_default_construct (C++20) | 在范围所定义的未初始化的内存区域以默认初始化构造对象 (niebloid)


std::uninitialized_default_construct_n

< cpp‎ | memory
定义于头文件 <memory> |  |
template< class ForwardIt, class Size > ForwardIt uninitialized_default_construct_n( ForwardIt first, Size n ); | (1) | (C++17 起)
template< class ExecutionPolicy, class ForwardIt, class Size > ForwardIt uninitialized_default_construct_n( ExecutionPolicy&& policy, ForwardIt first, Size n ); | (2) | (C++17 起)
1) 在 first 起始的存储中以默认初始化构造 n 个 typename iterator_traits<ForwardIt>::value_type 类型对象，如同用
for (; n > 0; (void) ++first, --n)
  ::new (/*VOIDIFY*/(*first))
      typename std::iterator_traits<ForwardIt>::value_type;

其中 /*VOIDIFY*/(e) 为：

static_cast<void*>( std::addressof (e))
 (C++20 前)
const_cast<void*>(static_cast<const volatile void*>( std::addressof (e)))
 (C++20 起)
若初始化期间抛出异常，则以未指定顺序销毁已构造的对象。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first | - | 要初始化的元素范围的起始
n | - | 要初始化的元素数量
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 通过 ForwardIt 合法实例的自增、赋值、比较或间接均不抛出异常。

返回值

对象范围的结尾（即 std::next (first, n) ）。

复杂度

与 n 成线性。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class ForwardIt, class Size>
ForwardIt uninitialized_default_construct_n( ForwardIt first, Size n )
{
    using T = typename std::iterator_traits<ForwardIt>::value_type;
    ForwardIt current = first;
    try {
        for (; n > 0 ; (void) ++current, --n) {
            ::new (const_cast<void*>(static_cast<const volatile void*>(
                std::addressof(*current)))) T;
        }
        return current;
    }  catch (...) {
        std::destroy(first, current);
        throw;
    }
}

示例

#include <iostream>
#include <memory>
#include <string>
#include <cstring>

int main()
{
    struct S { std::string m{ "Default value" }; };

    constexpr int n {3};
    alignas(alignof(S)) unsigned char mem[n * sizeof(S)];

    try
    {
        auto first {reinterpret_cast<S*>(mem)};
        auto last = std::uninitialized_default_construct_n(first, n);

        for (auto it {first}; it != last; ++it) {
            std::cout << it->m << '\n';
        }

        std::destroy(first, last);
    }
    catch(...)
    {
        std::cout << "Exception!\n";
    }

    // 注意对于“平凡类型” uninitialized_default_construct_n 通常不会以零填充未初始化的内存区域。
    int v[] { 1, 2, 3, 4 };
    const int original[] { 1, 2, 3, 4 };
    std::uninitialized_default_construct_n(std::begin(v), std::size(v));
    // for (const int i : v) { std::cout << i << ' '; }
    // 可能为未定义行为，待定的 CWG 1997 。
    std::cout <<
        (std::memcmp(v, original, sizeof(v)) == 0 ? "Unmodified\n" : "Modified\n");
    // 结果未指定。
}

可能的输出：

Default value
Default value
Default value
Unmodified

参阅

uninitialized_default_construct (C++17) | 在范围所定义的未初始化的内存区域以默认初始化构造对象 (函数模板)
uninitialized_value_construct_n (C++17) | 在起始和计数所定义的未初始化内存区域以值初始化构造对象 (函数模板)
ranges::uninitialized_default_construct_n (C++20) | 在起始与计数所定义的未初始化的内存区域以默认初始化构造对象 (niebloid)


std::uninitialized_fill

< cpp‎ | memory
定义于头文件 <memory> |  |
template< class ForwardIt, class T > void uninitialized_fill( ForwardIt first, ForwardIt last, const T& value ); | (1) |
template< class ExecutionPolicy, class ForwardIt, class T > void uninitialized_fill( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, const T& value ); | (2) | (C++17 起)
1) 复制给定的 value 到以 [first, last) 定义的未初始化内存区域，如同用
for (; first != last; ++first)
    ::new (/*VOIDIFY*/(*first))
        typename std::iterator_traits<ForwardIt>::value_type(value);

其中 /*VOIDIFY*/(e) 为：

static_cast<void*>(&e)
 (C++11 前)
static_cast<void*>( std::addressof (e))
 (C++11 起)
(C++20 前)
const_cast<void*>(static_cast<const volatile void*>( std::addressof (e)))
 (C++20 起)
若初始化期间抛异常，则以未指定顺序销毁已构造的对象。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要初始化的元素的范围
value | - | 构造元素所用的值
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 通过 ForwardIt 合法实例的自增、赋值、比较或间接均不可抛异常。作用 &* 到 ForwardIt 值必须产生指向其值类型的指针。 (C++11 前)

返回值

（无）

复杂度

与 first 和 last 间的距离成线性

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class ForwardIt, class T>
void uninitialized_fill(ForwardIt first, ForwardIt last, const T& value)
{
    using V = typename std::iterator_traits<ForwardIt>::value_type;
    ForwardIt current = first;
    try {
        for (; current != last; ++current) {
            ::new (const_cast<void*>(static_cast<const volatile void*>(
                std::addressof(*current)))) V(value);
        }
    }  catch (...) {
        for (; first != current; ++first) {
            first->~V();
        }
        throw;
    }
}

示例

#include <algorithm>
#include <iostream>
#include <memory>
#include <string>
#include <tuple>

int main()
{
    std::string* p;
    std::size_t sz;
    std::tie(p, sz) = std::get_temporary_buffer<std::string>(4);

    std::uninitialized_fill(p, p+sz, "Example");

    for (std::string* i = p; i != p+sz; ++i) {
        std::cout << *i << '\n';
        i->~basic_string<char>();
    }
    std::return_temporary_buffer(p);
}

输出：

Example
Example
Example
Example

参阅

uninitialized_fill_n | 复制一个对象到以起点和计数定义的未初始化内存区域 (函数模板)
ranges::uninitialized_fill (C++20) | 复制一个对象到范围所定义的未初始化的内存区域 (niebloid)


std::uninitialized_fill_n

< cpp‎ | memory
定义于头文件 <memory> |  |
 | (1) |
template< class ForwardIt, class Size, class T > void uninitialized_fill_n( ForwardIt first, Size count, const T& value ); |  |  | (C++11 前)
template< class ForwardIt, class Size, class T > ForwardIt uninitialized_fill_n( ForwardIt first, Size count, const T& value ); |  |  | (C++11 起)
template< class ExecutionPolicy, class ForwardIt, class Size, class T > ForwardIt uninitialized_fill_n( ExecutionPolicy&& policy, ForwardIt first, Size count, const T& value ); | (2) | (C++17 起)
1) 复制给定值 value 到始于 first 的未初始化内存区域的首 count 个元素，如同以
for (; n--; ++first)
    ::new (/*VOIDIFY*/(*first))
        typename std::iterator_traits<ForwardIt>::value_type(value);

其中 /*VOIDIFY*/(e) 为：

static_cast<void*>(&e)
 (C++11 前)
static_cast<void*>( std::addressof (e))
 (C++11 起)
(C++20 前)
const_cast<void*>(static_cast<const volatile void*>( std::addressof (e)))
 (C++20 起)
若初始化期间抛异常，则以未指定顺序销毁已构造的对象。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first | - | 要初始化的元素范围起始
count | - | 要构造的元素数量
value | - | 构造元素所用的值
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 通过 ForwardIt 合法实例的自增、赋值、比较或间接均不可抛异常。作用 &* 到 ForwardIt 值必须产生指向其值类型的指针。 (C++11 前)

返回值

（无） | (C++11 前)
指向最后复制的元素后一位置元素的迭代器。 | (C++11 起)

复杂度

与 count 成线性。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template< class ForwardIt, class Size, class T >
ForwardIt uninitialized_fill_n(ForwardIt first, Size count, const T& value)
{
    using V = typename std::iterator_traits<ForwardIt>::value_type;
    ForwardIt current = first;
    try {
        for (; count > 0; ++current, (void) --count) {
            ::new (const_cast<void*>(static_cast<const volatile void*>(
                std::addressof(*current)))) V(value);
        }
        return current;
    } catch (...) {
        for (; first != current; ++first) {
            first->~V();
        }
        throw;
    }
}

示例

#include <algorithm>
#include <iostream>
#include <memory>
#include <string>
#include <tuple>

int main()
{
    std::string* p;
    std::size_t sz;
    std::tie(p, sz) = std::get_temporary_buffer<std::string>(4);
    std::uninitialized_fill_n(p, sz, "Example");

    for (std::string* i = p; i != p+sz; ++i) {
        std::cout << *i << '\n';
        i->~basic_string<char>();
    }
    std::return_temporary_buffer(p);
}

输出：

Example
Example
Example
Example

参阅

uninitialized_fill | 复制一个对象到以范围定义的未初始化内存区域 (函数模板)
ranges::uninitialized_fill_n (C++20) | 复制一个对象到起始与计数所定义的未初始化的内存区域 (niebloid)


std::uninitialized_move

< cpp‎ | memory
定义于头文件 <memory> |  |
template< class InputIt, class ForwardIt > ForwardIt uninitialized_move( InputIt first, InputIt last, ForwardIt d_first ); | (1) | (C++17 起)
template< class ExecutionPolicy, class InputIt, class ForwardIt > ForwardIt uninitialized_move( ExecutionPolicy&& policy, InputIt first, InputIt last, ForwardIt d_first ); | (2) | (C++17 起)
1) 从范围 [first, last) 移动元素到始于 d_first 的未初始化内存区域，如同用
for (; first != last; ++d_first, (void) ++first)
   ::new (/*VOIDIFY*/(*d_first))
      typename std::iterator_traits<ForwardIt>::value_type(std::move(*first));

其中 /*VOIDIFY*/(e) 为：

static_cast<void*>( std::addressof (e))
 (C++20 前)
const_cast<void*>(static_cast<const volatile void*>( std::addressof (e)))
 (C++20 起)
若此初始化抛出异常，则 [first, last) 中的某些对象留在合法但未指定的状态，并以未指定顺序销毁已构造的对象。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要移动的元素范围
d_first | - | 目标范围的起始
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 通过 ForwardIt 合法实例的自增、赋值、比较或间接不可抛出异常。

返回值

指向最后被移动元素的后一元素的迭代器。

复杂度

与 first 和 last 的距离成线性

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class InputIt, class ForwardIt>
ForwardIt uninitialized_move(InputIt first, InputIt last, ForwardIt d_first)
{
    using Value = typename std::iterator_traits<ForwardIt>::value_type;
    ForwardIt current = d_first;
    try {
        for (; first != last; ++first, (void) ++current) {
            ::new (const_cast<void*>(static_cast<const volatile void*>(
                std::addressof(*current)))) Value(std::move(*first));
        }
        return current;
    } catch (...) {
        std::destroy(d_first, current);
        throw;
    }
}

示例

#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <memory>
#include <string>

void print(auto rem, auto first, auto last) {
    for (std::cout << rem; first != last; ++first)
        std::cout << std::quoted(*first) << ' ';
    std::cout << '\n';
}

int main() {
    std::string in[] { "Home", "Work!" };
    print("initially, in: ", std::begin(in), std::end(in));

    if (
        constexpr auto sz = std::size(in);
        void* out = std::aligned_alloc(alignof(std::string), sizeof(std::string) * sz)
    ) {
        try {
            auto first {static_cast<std::string*>(out)};
            auto last {first + sz};
            std::uninitialized_move(std::begin(in), std::end(in), first);

            print("after move, in: ", std::begin(in), std::end(in));
            print("after move, out: ", first, last);

            std::destroy(first, last);
        }
        catch (...) {
            std::cout << "Exception!\n";
        }
        std::free(out);
    }
}

可能的输出：

initially, in: "Home" "Work!"
after move, in: "" ""
after move, out: "Home" "Work!"

参阅

uninitialized_copy | 将范围内的对象复制到未初始化的内存区域 (函数模板)
uninitialized_move_n (C++17) | 移动一定数量对象到未初始化内存区域 (函数模板)
ranges::uninitialized_move (C++20) | 移动对象范围到未初始化的内存区域 (niebloid)


std::uninitialized_move_n

< cpp‎ | memory
定义于头文件 <memory>
template< class InputIt, class Size, class NoThrowForwardIt >

std::pair <InputIt, NoThrowForwardIt>

uninitialized_move_n( InputIt first, Size count, NoThrowForwardIt d_first );
 (1) (C++17 起)
template< class ExecutionPolicy, class ForwardIt, class Size, class NoThrowForwardIt >

std::pair <ForwardIt, NoThrowForwardIt>
uninitialized_move_n( ExecutionPolicy&& policy, ForwardIt first, Size count,

NoThrowForwardIt d_first );
 (2) (C++17 起)
1) 从始于 first 的范围移动 count 到始于 d_first 的未初始化内存区域，如同用
for ( ; n > 0; ++d_first, (void) ++first, --n)
   ::new (/*VOIDIFY*/(*d_first))
      typename std::iterator_traits<ForwardIt>::value_type(std::move(*first));

其中 /*VOIDIFY*/(e) 为：

static_cast<void*>( std::addressof (e))
 (C++20 前)
const_cast<void*>(static_cast<const volatile void*>( std::addressof (e)))
 (C++20 起)
若此初始化抛出异常，则 [first, last) 中的某些对象留在合法但未指定的状态，并以未指定顺序销毁已构造的对象。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first | - | 要移动的元素范围起始
count | - | 要移动的元素数目
d_first | - | 目标范围的起始
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- NoThrowForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 通过 NoThrowForwardIt 合法实例的自增、赋值、比较或间接不可抛出异常。

返回值

一对迭代器，其首元素是指向源范围中最后被移动的元素后一元素的迭代器，第二元素是指向目标范围中最后移动到的元素后一元素的迭代器。

复杂度

与 count 成线性。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class InputIt, class Size, class ForwardIt>
std::pair<InputIt, ForwardIt>
    uninitialized_move_n(InputIt first, Size count, ForwardIt d_first)
{
    using Value = typename std::iterator_traits<ForwardIt>::value_type;
    ForwardIt current = d_first;
    try {
        for (; count > 0; ++first, (void) ++current, --count) {
            ::new (const_cast<void*>(static_cast<const volatile void*>(
                std::addressof(*current)))) Value(std::move(*first));
        }
    } catch (...) {
        std::destroy(d_first, current);
        throw;
    }
    return {first, current};
}

示例

#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <memory>
#include <string>

void print(auto rem, auto first, auto last) {
    for (std::cout << rem; first != last; ++first)
        std::cout << std::quoted(*first) << ' ';
    std::cout << '\n';
}

int main() {
    std::string in[] { "One", "Definition", "Rule" };
    print("initially, in: ", std::begin(in), std::end(in));

    if (
        constexpr auto sz = std::size(in);
        void* out = std::aligned_alloc(alignof(std::string), sizeof(std::string) * sz)
    ) {
        try {
            auto first {static_cast<std::string*>(out)};
            auto last {first + sz};
            std::uninitialized_move_n(std::begin(in), sz, first);

            print("after move, in: ", std::begin(in), std::end(in));
            print("after move, out: ", first, last);

            std::destroy(first, last);
        }
        catch (...) {
            std::cout << "Exception!\n";
        }
        std::free(out);
    }
}

可能的输出：

initially, in: "One" "Definition" "Rule"
after move, in: "" "" ""
after move, out: "One" "Definition" "Rule"

参阅

uninitialized_move (C++17) | 移动一个范围的对象到未初始化的内存区域 (函数模板)
uninitialized_copy_n (C++11) | 将指定数量的对象复制到未初始化的内存区域 (函数模板)
ranges::uninitialized_move_n (C++20) | 移动一定量对象到未初始化的内存区域 (niebloid)


std::uninitialized_value_construct

< cpp‎ | memory
定义于头文件 <memory> |  |
template< class ForwardIt > void uninitialized_value_construct( ForwardIt first, ForwardIt last); | (1) | (C++17 起)
template< class ExecutionPolicy, class ForwardIt > void uninitialized_value_construct( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last ); | (2) | (C++17 起)
1) 在 [first, last) 范围所指代的未初始化存储中以值初始化构造 typename iterator_traits<ForwardIt>::value_type 类型的对象，如同用
for (; first != last; ++first)
  ::new (/*VOIDIFY*/(*first))
      typename std::iterator_traits<ForwardIt>::value_type();

其中 /*VOIDIFY*/(e) 为：

static_cast<void*>( std::addressof (e))
 (C++20 前)
const_cast<void*>(static_cast<const volatile void*>( std::addressof (e)))
 (C++20 起)
若初始化过程中抛出异常，则以未指定顺序销毁已构造的对象。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。

参数

first, last | - | 要初始化的元素范围
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 通过 ForwardIt 合法实例的自增、赋值、比较或间接均不抛出异常。

返回值

（无）

复杂度

与 first 和 last 间的距离成线性

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class ForwardIt>
void uninitialized_value_construct(ForwardIt first, ForwardIt last)
{
    using Value = typename std::iterator_traits<ForwardIt>::value_type;
    ForwardIt current = first;
    try {
        for (; current != last; ++current) {
            ::new (const_cast<void*>(static_cast<const volatile void*>(
                std::addressof(*current)))) Value();
        }
    } catch (...) {
        std::destroy(first, current);
        throw;
    }
}

示例

#include <iostream>
#include <memory>
#include <string>

int main()
{
    struct S { std::string m{ "Default value" }; };

    constexpr int n {3};
    alignas(alignof(S)) unsigned char mem[n * sizeof(S)];

    try
    {
        auto first {reinterpret_cast<S*>(mem)};
        auto last {first + n};

        std::uninitialized_value_construct(first, last);

        for (auto it {first}; it != last; ++it) {
            std::cout << it->m << '\n';
        }

        std::destroy(first, last);
    }
    catch(...)
    {
        std::cout << "Exception!\n";
    }

    // 注意对于“平凡类型” uninitialized_value_construct 会以零填充给定的未初始化内存区域。
    int v[] { 1, 2, 3, 4 };
    for (const int i : v) { std::cout << i << ' '; }
    std::cout << '\n';
    std::uninitialized_value_construct(std::begin(v), std::end(v));
    for (const int i : v) { std::cout << i << ' '; }
    std::cout << '\n';
}

输出：

Default value
Default value
Default value
1 2 3 4
0 0 0 0

参阅

uninitialized_value_construct_n (C++17) | 在起始和计数所定义的未初始化内存区域以值初始化构造对象 (函数模板)
uninitialized_default_construct (C++17) | 在范围所定义的未初始化的内存区域以默认初始化构造对象 (函数模板)
ranges::uninitialized_value_construct (C++20) | 在范围所定义的未初始化的内存区域以值初始化构造对象 (niebloid)


std::uninitialized_value_construct_n

< cpp‎ | memory
定义于头文件 <memory> |  |
template< class ForwardIt, class Size > ForwardIt uninitialized_value_construct_n( ForwardIt first, Size n ); | (1) | (C++17 起)
template< class ExecutionPolicy, class ForwardIt, class Size > ForwardIt uninitialized_value_construct_n( ExecutionPolicy&& policy, ForwardIt first, Size n ); | (2) | (C++17 起)
1) 在始于 first 的未初始化存储中以值初始化构造 n 个 typename iterator_traits<ForwardIt>::value_type 类型的对象，如同用
for (; n > 0; (void) ++first, --n)
  ::new (/*VOIDIFY*/(*first))
      typename std::iterator_traits<ForwardIt>::value_type();

其中 /*VOIDIFY*/(e) 为：

static_cast<void*>( std::addressof (e))
 (C++20 前)
const_cast<void*>(static_cast<const volatile void*>( std::addressof (e)))
 (C++20 起)
若初始化当中抛出异常，则以未指定顺序销毁已构造的对象。
2) 同 (1) ，但按照 policy 执行。此重载仅若 std::is_execution_policy_v < std::decay_t <ExecutionPolicy>> (C++20 前)std::is_execution_policy_v <std::remove_cvref_t<ExecutionPolicy>> (C++20 起) 为 true 才参与重载决议。。

参数

first | - | 要初始化的元素范围的起始
n | - | 要初始化的元素数量
policy | - | 所用的执行策略。细节见执行策略。
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。
- 通过 ForwardIt 合法实例的自增、复制、比较或间接均不抛出异常。

返回值

对象范围的结尾（即 std::next (first, n) ）。

复杂度

与 n 成线性。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误：

  • 若作为算法一部分调用的函数的执行抛出异常，且 ExecutionPolicy 为标准策略之一，则调用 std::terminate 。对于任何其他 ExecutionPolicy ，行为是实现定义的。
  • 若算法无法分配内存，则抛出 std::bad_alloc 。

可能的实现

template<class ForwardIt, class Size>
ForwardIt uninitialized_value_construct_n( ForwardIt first, Size n )
{
    using T = typename std::iterator_traits<ForwardIt>::value_type;
    ForwardIt current = first;
    try {
        for (; n > 0 ; (void) ++current, --n) {
            ::new (const_cast<void*>(static_cast<const volatile void*>(
                std::addressof(*current)))) T();
        }
        return current;
    }  catch (...) {
        std::destroy(first, current);
        throw;
    }
}

示例

#include <iostream>
#include <memory>
#include <string>

int main()
{
    struct S { std::string m{ "Default value" }; };

    constexpr int n {3};
    alignas(alignof(S)) unsigned char mem[n * sizeof(S)];

    try
    {
        auto first {reinterpret_cast<S*>(mem)};
        auto last = std::uninitialized_value_construct_n(first, n);

        for (auto it {first}; it != last; ++it) {
            std::cout << it->m << '\n';
        }

        std::destroy(first, last);
    }
    catch(...)
    {
        std::cout << "Exception!\n";
    }

    // 注意对于“平凡类型” uninitialized_value_construct_n 会以零填充给定的未初始化内存区域。
    int v[] { 1, 2, 3, 4 };
    for (const int i : v) { std::cout << i << ' '; }
    std::cout << '\n';
    std::uninitialized_value_construct_n(std::begin(v), std::size(v));
    for (const int i : v) { std::cout << i << ' '; }
    std::cout << '\n';
}

输出：

Default value
Default value
Default value
1 2 3 4
0 0 0 0

参阅

uninitialized_value_construct (C++17) | 在范围所定义的未初始化内存中用值初始化构造对象 (函数模板)
uninitialized_default_construct_n (C++17) | 在起始和计数所定义的未初始化内存区域用默认初始化构造对象 (函数模板)
ranges::uninitialized_value_construct_n (C++20) | 在起始与计数所定义的未初始化的内存区域以值初始化构造对象 (niebloid)


std::unique_ptr

< cpp‎ | memory
定义于头文件 <memory> |  |
template< class T, class Deleter = std::default_delete <T> > class unique_ptr; | (1) | (C++11 起)
template < class T, class Deleter > class unique_ptr<T[], Deleter>; | (2) | (C++11 起)

std::unique_ptr 是通过指针占有并管理另一对象，并在 unique_ptr 离开作用域时释放该对象的智能指针。

在下列两者之一发生时用关联的删除器释放对象：

  • 销毁了管理的 unique_ptr 对象
  • 通过 operator= 或 reset() 赋值另一指针给管理的 unique_ptr 对象。

通过调用 get_deleter()(ptr) ，用潜在为用户提供的删除器释放对象。默认删除器用 delete 运算符，它销毁对象并解分配内存。

unique_ptr 亦可以不占有对象，该情况下称它为空 (empty)。

std::unique_ptr 有两个版本：

1) 管理单个对象（例如以 new 分配）
2) 管理动态分配的对象数组（例如以 new[] 分配）

类满足可移动构造 (MoveConstructible) 和可移动赋值 (MoveAssignable) 的要求，但不满足可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 的要求。

类型要求
-
Deleter 必须是函数对象 (FunctionObject) 或到函数对象 (FunctionObject) 的左值引用或到函数的左值引用，可以 unique_ptr<T, Deleter>::pointer 类型参数调用

注解

只有非 const 的 unique_ptr 能转移被管理对象的所有权给另一 unique_ptr 。若对象的生存期为 const std::unique_ptr 所管理，则它被限定在创建指针的作用域中。

std::unique_ptr 常用于管理对象的生存期，包含：

  • 通过正常退出和经由异常退出两者上的受保证删除，提供异常安全，给处理拥有动态生存期的对象的类和函数
  • 传递独占的拥有动态生存期的对象的所有权到函数
  • 从函数获得独占的拥有动态生存期对象的所有权
  • 作为具移动容器的元素类型，例如保有指向动态分配对象的指针的 std::vector （例如，若想要多态行为）

std::unique_ptr 可为不完整类型 T 构造，例如用于改善用作 pImpl 手法中柄的用途。若使用默认删除器，则 T 必须在代码中调用删除器点处完整，这发生于析构函数、移动赋值运算符和 std::unique_ptr 的 reset 成员函数中。（相反地， std::shared_ptr 不能从指向不完整类型的裸指针构造，但可于 T 不完整处销毁）。注意若 T 是类模板特化，则以 unique_ptr 为运算数的使用，如 !p ，因 ADL 而要求 T 的形参完整。

若 T 是某基类 B 的派生类，则 std::unique_ptr<T> 可隐式转换为 std::unique_ptr<B>。产生的 std::unique_ptr<B> 的默认删除器将使用 B 的 operator delete ，这导致未定义行为，除非 B 的析构函数为虚。注意 std::shared_ptr 表现有别： std::shared_ptr <B> 将使用类型 T 的 operator delete ，而且即使 B 的析构函数非虚，也会正确删除被占有对象。

不同于 std::shared_ptr ， std::unique_ptr 可通过任何满足可空指针 (NullablePointer) 的定制柄类型管理对象。例如，这允许管理位于共享内存，但提供定义 typedef boost::offset_ptr pointer; 或其他缀饰指针的 Deleter 的对象。

成员类型

成员类型 | 定义
pointer | 若该类型存在则为 std::remove_reference <Deleter>::type::pointer ，否则为 T* 。必须满足可空指针 (NullablePointer) 。
element_type | T ，此 unique_ptr 所管理的对象类型
deleter_type | Deleter ，函数对象或到函数或到函数对象的左值引用，会从析构函数调用

成员函数

(构造函数)
 构造新的unique_ptr
(公开成员函数)
(析构函数)
 析构所管理的对象，如果存在的话
(公开成员函数)
operator=
 为unique_ptr赋值
(公开成员函数)
修改器
release
 返回一个指向被管理对象的指针，并释放所有权
(公开成员函数)
reset
 替换被管理对象
(公开成员函数)
swap
 交换被管理对象
(公开成员函数)
观察器
get
 返回指向被管理对象的指针
(公开成员函数)
get_deleter
 返回用于析构被管理对象的删除器
(公开成员函数)
operator bool
 检查是否有关联的被管理对象
(公开成员函数)
单对象版本， unique_ptr<T>
operator*operator->
 解引用指向被管理对象的指针
(公开成员函数)
数组版本， unique_ptr<T[]>
operator[]
 提供到被管理数组的有索引访问
(公开成员函数)

非成员函数

make_uniquemake_unique_for_overwrite (C++14)(C++20) | 创建管理一个新对象的独占指针 (函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20) | 与另一个 unique_ptr 或 nullptr 进行比较 (函数模板)
operator<< (C++20) | 输出被管理指针的值到输出流 (函数模板)
std::swap(std::unique_ptr) (C++11) | 特化 std::swap 算法 (函数模板)

辅助类

std::hash<std::unique_ptr>
(C++11)
 std::unique_ptr 的散列支持
(类模板特化)

示例

#include <iostream>
#include <vector>
#include <memory>
#include <cstdio>
#include <fstream>
#include <cassert>
#include <functional>

struct B {
  virtual void bar() { std::cout << "B::bar\n"; }
  virtual ~B() = default;
};
struct D : B
{
    D() { std::cout << "D::D\n";  }
    ~D() { std::cout << "D::~D\n";  }
    void bar() override { std::cout << "D::bar\n";  }
};

// 消费 unique_ptr 的函数能以值或以右值引用接收它
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
    p->bar();
    return p;
}

void close_file(std::FILE* fp) { std::fclose(fp); }

int main()
{
  std::cout << "unique ownership semantics demo\n";
  {
      auto p = std::make_unique<D>(); // p 是占有 D 的 unique_ptr
      auto q = pass_through(std::move(p));
      assert(!p); // 现在 p 不占有任何内容并保有空指针
      q->bar();   // 而 q 占有 D 对象
  } // ~D 调用于此

  std::cout << "Runtime polymorphism demo\n";
  {
    std::unique_ptr<B> p = std::make_unique<D>(); // p 是占有 D 的 unique_ptr
                                                  // 作为指向基类的指针
    p->bar(); // 虚派发

    std::vector<std::unique_ptr<B>> v;  // unique_ptr 能存储于容器
    v.push_back(std::make_unique<D>());
    v.push_back(std::move(p));
    v.emplace_back(new D);
    for(auto& p: v) p->bar(); // 虚派发
  } // ~D called 3 times

  std::cout << "Custom deleter demo\n";
  std::ofstream("demo.txt") << 'x'; // 准备要读的文件
  {
      std::unique_ptr<std::FILE, void (*)(std::FILE*) > fp(std::fopen("demo.txt", "r"),
                                                           close_file);
      if(fp) // fopen 可以打开失败；该情况下 fp 保有空指针
        std::cout << (char)std::fgetc(fp.get()) << '\n';
  } // fclose() 调用于此，但仅若 FILE* 不是空指针
    // （即 fopen 成功）

  std::cout << "Custom lambda-expression deleter demo\n";
  {
    std::unique_ptr<D, std::function<void(D*)>> p(new D, [](D* ptr)
        {
            std::cout << "destroying from a custom deleter...\n";
            delete ptr;
        });  // p 占有 D
    p->bar();
  } // 调用上述 lambda 并销毁 D

  std::cout << "Array form of unique_ptr demo\n";
  {
      std::unique_ptr<D[]> p{new D[3]};
  } // 调用 ~D 3 次
}

输出：

unique ownership semantics demo
D::D
D::bar
D::bar
D::~D
Runtime polymorphism demo
D::D
D::bar
D::D
D::D
D::bar
D::bar
D::bar
D::~D
D::~D
D::~D
Custom deleter demo
x
Custom lambda-expression deleter demo
D::D
D::bar
destroying from a custom deleter...
D::~D
Array form of unique_ptr demo
D::D
D::D
D::D
D::~D
D::~D
D::~D


std::unique_ptr<T,Deleter>::get

< cpp‎ | memory‎ | unique ptr
pointer get() const noexcept; | (C++11 起)

返回指向被管理对象的指针，如果无被管理对象，则为 nullptr 。

参数

（无）

返回值

指向被管理对象的指针，无被管理对象，则为 nullptr 。

示例

#include <iostream>
#include <string>
#include <memory>

int main()
{
    std::unique_ptr<std::string> s_p(new std::string("Hello, world!"));
    std::string *s = s_p.get();
    std::cout << *s << '\n';
}

输出：

Hello, world!

参阅

release
 返回一个指向被管理对象的指针，并释放所有权
(公开成员函数)


std::unique_ptr<T,Deleter>::get_deleter

< cpp‎ | memory‎ | unique ptr
Deleter& get_deleter() noexcept; | (C++11 起)
const Deleter& get_deleter() const noexcept; | (C++11 起)

返回会用于析构被管理对象的删除器对象。

参数

（无）

返回值

存储的删除器对象。

示例

#include <iostream>
#include <memory>

struct Foo
{
    Foo() { std::cout << "Foo...\n"; }
    ~Foo() { std::cout << "~Foo...\n"; }
};

struct D
{
    void bar() { std::cout << "Call deleter D::bar()...\n"; }
    void operator()(Foo* p) const
    {
        std::cout << "Call delete for Foo object...\n";
        delete p;
    }
};

int main()
{
    std::unique_ptr<Foo, D> up(new Foo(), D());
    D& del = up.get_deleter();
    del.bar();
}

输出：

Foo...
Call deleter D::bar()...
Call delete for Foo object...
~Foo...


std::hash<std::unique_ptr>

< cpp‎ | memory‎ | unique ptr
template<class T, class Deleter> struct hash<unique_ptr<T, Deleter>>; | (C++11 起)

std::hash 对 std::unique_ptr <T, Deleter> 的模板特化允许用户获得 std::unique_ptr <T, Deleter> 类型对象的散列值。

若启用 std::hash<typename std::unique_ptr<T,D>::pointer> ，则启用特化 std::hash<std::unique_ptr<T,D>> （见 std::hash ），否则禁用它。

启用时，对于给定的 std::unique_ptr <T, D> p ，此特化确保 std::hash < std::unique_ptr <T, D>>()(p) == std::hash <typename std::unique_ptr <T, D>::pointer>()(p.get()) 。

此特化的成员函数不保证为 noexcept ，因为指针可能是缀饰指针且其散列函数可能抛出。

示例

#include <iostream>
#include <memory>
#include <functional>

struct Foo {
    Foo() { std::cout << "Foo...\n"; }
    ~Foo() { std::cout << "~Foo...\n\n"; }
};

int main()
{
    Foo* foo = new Foo();
    std::unique_ptr<Foo> up(foo);

    std::cout << "hash(up):  " << std::hash<std::unique_ptr<Foo>>()(up) << '\n';
    std::cout << "hash(foo): " << std::hash<Foo*>()(foo) << '\n';
}

输出：

Foo...
hash(up):  3686401041
hash(foo): 3686401041
~Foo...

参阅

hash
(C++11)
 散列函数对象
(类模板)


std::make_unique, std::make_unique_for_overwrite

< cpp‎ | memory‎ | unique ptr
定义于头文件 <memory> |  |
template< class T, class... Args > unique_ptr<T> make_unique( Args&&... args ); | (1) | (C++14 起) (仅对非数组类型)
template< class T > unique_ptr<T> make_unique( std::size_t size ); | (2) | (C++14 起) (仅对未知边界数组)
template< class T, class... Args > /* unspecified */ make_unique( Args&&... args ) = delete; | (3) | (C++14 起) (仅对已知边界数组)
template< class T > unique_ptr<T> make_unique_for_overwrite( ); | (4) | (C++20 起) (仅对非数组类型)
template< class T > unique_ptr<T> make_unique_for_overwrite( std::size_t size ); | (5) | (C++20 起) (仅对未知边界数组)
template< class T, class... Args > /* unspecified */ make_unique_for_overwrite( Args&&... args ) = delete; | (6) | (C++20 起) (仅对已知边界数组)

构造 T 类型对象并将其包装进 std::unique_ptr 。

1) 构造非数组类型 T 对象。传递参数 args 给 T 的构造函数。此重载仅若 T 不是数组类型才参与重载决议。函数等价于：
unique_ptr<T>(new T(std::forward<Args>(args)...))
2) 构造拥有动态大小的数组。值初始化数组元素。此重载仅若 T 是未知边界数组才参与重载决议。函数等价于：
unique_ptr<T>(new std::remove_extent_t<T>[size]())
3,6) 不允许构造已知边界的数组。
4) 同 (1) ，除了默认初始化对象。此重载仅若 T 不是数组类型才参与重载决议。函数等价于：
unique_ptr<T>(new T)
5) 同 (2) ，除了默认初始化数组。此重载仅若 T 是未知边界数组才参与重载决议。函数等价于：
unique_ptr<T>(new std::remove_extent_t<T>[size])

参数

args | - | 将要构造的 T 实例所用的参数列表。
size | - | 要构造的数组大小

返回值

类型 T 实例的 std::unique_ptr 。

异常

可能抛出 std::bad_alloc 或任何 T 的构造函数所抛的异常。若抛出异常，则此函数无效果。

可能的实现

版本一
// C++14 make_unique
namespace detail {
template<class>
constexpr bool is_unbounded_array_v = false;
template<class T>
constexpr bool is_unbounded_array_v<T[]> = true;

template<class>
constexpr bool is_bounded_array_v = false;
template<class T, std::size_t N>
constexpr bool is_bounded_array_v<T[N]> = true;
} // namespace detail

template<class T, class... Args>
std::enable_if_t<!std::is_array<T>::value, std::unique_ptr<T>>
make_unique(Args&&... args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

template<class T>
std::enable_if_t<detail::is_unbounded_array_v<T>, std::unique_ptr<T>>
make_unique(std::size_t n)
{
    return std::unique_ptr<T>(new std::remove_extent_t<T>[n]());
}

template<class T, class... Args>
std::enable_if_t<detail::is_bounded_array_v<T>> make_unique(Args&&...) = delete;
版本二
// C++20 make_unique_for_overwrite
template<class T>
    requires !std::is_array_v<T>
std::unique_ptr<T> make_unique_for_overwrite()
{
    return std::unique_ptr<T>(new T);
}

template<class T>
    requires std::is_unbounded_array_v<T>
std::unique_ptr<T> make_unique_for_overwrite(std::size_t n)
{
    return std::unique_ptr<T>(new std::remove_extent_t<T>[n]);
}

template<class T, class... Args>
    requires std::is_bounded_array_v<T>
void make_unique_for_overwrite(Args&&...) = delete;

注解

不同于 std::make_shared （它拥有 std::allocate_shared ）， std::make_unique 没有具分配器的对应物。 P0211 中提案的 allocate_unique 会要求为其返回的 unique_ptr<T,D> 创作删除器类型 D ，返回类型可能含有分配器对象，并在其 operator() 调用 destroy 和 deallocate 。

示例

#include <iostream>
#include <memory>

struct Vec3
{
    int x, y, z;
    // C++20 起不再需要以下构造函数
    Vec3(int x = 0, int y = 0, int z = 0) noexcept : x(x), y(y), z(z) { }
    friend std::ostream& operator<<(std::ostream& os, const Vec3& v)
    {
        return os << '{' << "x:" << v.x << " y:" << v.y << " z:" << v.z  << '}';
    }
};

int main()
{
    // 使用默认构造函数。
    std::unique_ptr<Vec3> v1 = std::make_unique<Vec3>();
    // 使用匹配这些参数的构造函数
    std::unique_ptr<Vec3> v2 = std::make_unique<Vec3>(0, 1, 2);
    // 创建指向 5 个元素数组的 unique_ptr
    std::unique_ptr<Vec3[]> v3 = std::make_unique<Vec3[]>(5);

    std::cout << "make_unique<Vec3>():      " << *v1 << '\n'
              << "make_unique<Vec3>(0,1,2): " << *v2 << '\n'
              << "make_unique<Vec3[]>(5):   " << '\n';
    for (int i = 0; i < 5; i++) {
        std::cout << "     " << v3[i] << '\n';
    }
}

输出：

make_unique<Vec3>():      {x:0 y:0 z:0}
make_unique<Vec3>(0,1,2): {x:0 y:1 z:2}
make_unique<Vec3[]>(5):
     {x:0 y:0 z:0}
     {x:0 y:0 z:0}
     {x:0 y:0 z:0}
     {x:0 y:0 z:0}
     {x:0 y:0 z:0}

参阅

(构造函数) | 构造新的unique_ptr (公开成员函数)
make_sharedmake_shared_for_overwrite (C++20) | 创建管理一个新对象的共享指针 (函数模板)


std::unique_ptr<T,Deleter>::operator*, std::unique_ptr<T,Deleter>::operator->

< cpp‎ | memory‎ | unique ptr
typename std::add_lvalue_reference <T>::type operator*() const
noexcept(noexcept(* std::declval <pointer>()));
 (1) (C++11 起)
pointer operator->() const noexcept;
 (2) (C++11 起)

operator* 与 operator-> 提供到 *this 所占有的对象的访问。

若 get() == nullptr 则行为未定义。

仅为单独对象的 unique_ptr ，即主模板提供这些成员函数。

参数

（无）

返回值

1) 返回 *this 所占有的对象，等价于 *get() 。
2) 返回指向 *this 所占有对象的指针，即 get() 。

异常

1) 若 pointer 拥有抛出的 operator* 则可能抛出。

示例

#include <iostream>
#include <memory>

struct Foo {
    void bar() { std::cout << "Foo::bar\n"; }
};

void f(const Foo& foo)
{
    std::cout << "f(const Foo&)\n";
}

int main()
{
    std::unique_ptr<Foo> ptr(new Foo);

    ptr->bar();
    f(*ptr);
}

输出：

Foo::bar
f(const Foo&)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2762 | C++11 | 即使底层表达式为 noexcept ， operator* 仍可为潜在抛出 | 添加了条件性异常说明

参阅

get
 返回指向被管理对象的指针
(公开成员函数)


std::unique_ptr<T,Deleter>::operator=

< cpp‎ | memory‎ | unique ptr
主模板 unique_ptr<T> 的成员 |
unique_ptr& operator=( unique_ptr&& r ) noexcept; | (1)
template< class U, class E > unique_ptr& operator=( unique_ptr<U,E>&& r ) noexcept; | (2)
unique_ptr& operator=( std::nullptr_t ) noexcept; | (3)
数组特化 unique_ptr<T[]> 的成员 |
unique_ptr& operator=( unique_ptr&& r ) noexcept; | (1)
template< class U, class E > unique_ptr& operator=( unique_ptr<U,E>&& r ) noexcept; | (2)
unique_ptr& operator=( std::nullptr_t ) noexcept; | (3)
1) 移动赋值运算符。从 r 转移所有权到 *this ，如同以调用 reset(r.release()) 后随从 get_deleter() 到 std::forward <Deleter>(r.get_deleter()) 的赋值。

若 Deleter 不是引用类型，则要求它为不抛出可移动赋值 (MoveAssignable) 。
若 Deleter 是引用类型，则要求 std::remove_reference<Deleter>::type 为不抛出可复制赋值 (CopyAssignable) 。

移动赋值运算符仅若 std::is_move_assignable <Deleter>::value 为 true 才参与重载决议。
2) 转换赋值运算符。行为同 (1) ，除了
  • 主模板的此赋值运算符仅若 U 非数组类型且 unique_ptr<U,E>::pointer 可隐式转换为 pointer 且 std::is_assignable <Deleter&, E&&>::value 为 true 才参与重载决议。
  • 数组特化 std::unique_ptr<T[]> 的此赋值运算符的表现与主模板中的相同，除了仅若下列皆为真才参与重载决议：
  • U 是数组类型
  • pointer 与 element_type* 是同一类型
  • unique_ptr<U,E>::pointer 与 unique_ptr<U,E>::element_type* 是同一类型
  • unique_ptr<U,E>::element_type(*)[] 可转换为 element_type(*)[]
  • std::is_assignable <Deleter&, E&&>::value 为 true
3) 与调用 reset() 等效。

注意 unique_ptr 的赋值运算符只接受典型地由 std::move 生成的右值。（ unique_ptr 类显式删除其左值复制构造函数和左值赋值运算符。）

参数

r - 所有权将被转移的智能指针

返回值

*this

示例

#include <iostream>
#include <memory>

struct Foo {
    Foo() { std::cout << "Foo\n"; }
    ~Foo() { std::cout << "~Foo\n"; }
};

int main()
{
    std::unique_ptr<Foo> p1;

    {
        std::cout << "Creating new Foo...\n";
        std::unique_ptr<Foo> p2( std::make_unique<Foo>() );
        // p1 = p2; // 错误！不能复制 unique_ptr
        p1 = std::move(p2);
        std::cout << "About to leave inner block...\n";

        // Foo 实例将继续生存，尽管 p2 离开作用域
    }

    std::cout << "About to leave program...\n";
}

输出：

Creating new Foo...
Foo
About to leave inner block...
About to leave program...
~Foo

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2118 | C++11 | unique_ptr<T[]>::operator= 拒绝限定转换 | 接受
LWG 2228 | C++11 | 转换赋值运算符未受约束 | 已约束
LWG 2899 | C++11 | 移动赋值运算符未受约束 | 已约束


std::unique_ptr<T,Deleter>::operator[]

< cpp‎ | memory‎ | unique ptr
T& operator[]( std::size_t i ) const; | (C++11 起)

operator[] 提供对 unique_ptr 所管理的数组元素的访问。

参数 i 必须小于数组中的元素数；否则行为未定义。

仅为对于数组类型的特化提供此成员函数。

参数

i - 要返回的元素的索引

返回值

返回在索引 i 的元素，即 get()[i] 。

示例

#include <iostream>
#include <memory>

int main()
{
    const int size = 10;
    std::unique_ptr<int[]> fact(new int[size]);

    for (int i = 0; i < size; ++i) {
        fact[i] = (i == 0) ? 1 : i * fact[i-1];
    }

    for (int i = 0; i < size; ++i) {
        std::cout << i << ": " << fact[i] << '\n';
    }
}

输出：

0: 1
1: 1
2: 2
3: 6
4: 24
5: 120
6: 720
7: 5040
8: 40320
9: 362880

参阅

get
 返回指向被管理对象的指针
(公开成员函数)


std::unique_ptr<T,Deleter>::operator bool

< cpp‎ | memory‎ | unique ptr
explicit operator bool() const noexcept; | (C++11 起)

检查 *this 是否占有对象，即是否有 get() != nullptr 。

参数

（无）

返回值

若 *this 占有对象则为 true ，否则为 false 。

示例

#include <iostream>
#include <memory>

int main()
{
    std::unique_ptr<int> ptr(new int(42));

    if (ptr) std::cout << "before reset, ptr is: " << *ptr << '\n';
    ptr.reset();
    if (ptr) std::cout << "after reset, ptr is: " << *ptr << '\n';
}

输出：

before reset, ptr is: 42

参阅

get
 返回指向被管理对象的指针
(公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::unique_ptr)

< cpp‎ | memory‎ | unique ptr
定义于头文件 <memory>
template<class T1, class D1, class T2, class D2>
bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
 (1) (C++11 起)
template<class T1, class D1, class T2, class D2>
bool operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
 (2) (C++11 起)
(C++20 前)
template<class T1, class D1, class T2, class D2>
bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
 (3) (C++11 起)
template<class T1, class D1, class T2, class D2>
bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
 (4) (C++11 起)
template<class T1, class D1, class T2, class D2>
bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
 (5) (C++11 起)
template<class T1, class D1, class T2, class D2>
bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
 (6) (C++11 起)
template<class T1, class D1, class T2, class D2>

requires std::three_way_comparable_with<
typename unique_ptr<T1, D1>::pointer,
typename unique_ptr<T2, D2>::pointer>
std::compare_three_way_result_t<typename unique_ptr<T1, D1>::pointer,
typename unique_ptr<T2, D2>::pointer>

operator<=>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
 (7) (C++20 起)
template <class T, class D>
bool operator==(const unique_ptr<T, D>& x, std::nullptr_t ) noexcept;
 (8) (C++11 起)
template <class T, class D>
bool operator==( std::nullptr_t, const unique_ptr<T, D>& x) noexcept;
 (9) (C++11 起)
(C++20 前)
template <class T, class D>
bool operator!=(const unique_ptr<T, D>& x, std::nullptr_t ) noexcept;
 (10) (C++11 起)
(C++20 前)
template <class T, class D>
bool operator!=( std::nullptr_t, const unique_ptr<T, D>& x) noexcept;
 (11) (C++11 起)
(C++20 前)
template <class T, class D>
bool operator<(const unique_ptr<T, D>& x, std::nullptr_t );
 (12) (C++11 起)
template <class T, class D>
bool operator<( std::nullptr_t, const unique_ptr<T, D>& y);
 (13) (C++11 起)
template <class T, class D>
bool operator<=(const unique_ptr<T, D>& x, std::nullptr_t );
 (14) (C++11 起)
template <class T, class D>
bool operator<=( std::nullptr_t, const unique_ptr<T, D>& y);
 (15) (C++11 起)
template <class T, class D>
bool operator>(const unique_ptr<T, D>& x, std::nullptr_t );
 (16) (C++11 起)
template <class T, class D>
bool operator>( std::nullptr_t, const unique_ptr<T, D>& y);
 (17) (C++11 起)
template <class T, class D>
bool operator>=(const unique_ptr<T, D>& x, std::nullptr_t );
 (18) (C++11 起)
template <class T, class D>
bool operator>=( std::nullptr_t, const unique_ptr<T, D>& y);
 (19) (C++11 起)
template<class T, class D>

requires std::three_way_comparable<typename unique_ptr<T, D>::pointer>
std::compare_three_way_result_t<typename unique_ptr<T, D>::pointer>

operator<=>(const unique_ptr<T, D>& x, std::nullptr_t );
 (20) (C++20 起)

比较二个 unique_ptr 或 unique_ptr 与 nullptr 的指针值。

1-7) 比较二个 unique_ptr 。
8-20) 比较 unique_ptr 与 nullptr 。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

x, y - 要比较的 unique_ptr

返回值

1) x.get() == y.get()
2) x.get() != y.get()
3) std::less <CT>()(x.get(), y.get()) ，其中 CT 是 std::common_type <unique_ptr<T1, D1>::pointer, unique_ptr<T2, D2>::pointer>::type
4) !(y < x)
5) y < x
6) !(x < y)
7) std::compare_three_way{}(x.get(), y.get())
8-9) !x
10-11) (bool)x
12) std::less <unique_ptr<T,D>::pointer>()(x.get(), nullptr)
13) std::less <unique_ptr<T,D>::pointer>()(nullptr, y.get())
14) !(nullptr < x)
15) !(y < nullptr)
16) nullptr < x
17) y < nullptr
18) !(x < nullptr)
19) !(nullptr < y)
20) std::compare_three_way{}(x.get(), static_cast<typename unique_ptr<T, D>::pointer>(nullptr))

示例

#include <iostream>
#include <memory>

int main()
{
    std::unique_ptr<int> p1(new int(42));
    std::unique_ptr<int> p2(new int(42));

    std::cout << "p1 == p1: " << (p1 == p1) << '\n';

    // p1 与 p2 指向不同内存位置，故 p1 != p2
    std::cout << "p1 == p2: " << (p1 == p2) << '\n';
}

输出：

p1 == p1: 1
p1 == p2: 0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3426 | C++20 | operator<=>(unique_ptr, nullptr_t) 为谬构 | 修正约束与定义

参阅

get
 返回指向被管理对象的指针
(公开成员函数)


std::unique_ptr<T,Deleter>::operator<<

< cpp‎ | memory‎ | unique ptr
template <class CharT, class Traits, class Y, class D>

std::basic_ostream <CharT, Traits>& operator<<( std::basic_ostream <CharT, Traits>& os,

const std::unique_ptr <Y, D>& p);
 (C++20 起)

插入 p 所管理的指针的值到输出流 os 中。

等价于 os << p.get() 。

此重载仅若 os << p.get() 为合法表达式才参与重载决议。

参数

os | - | 要插入 p 到的 std::basic_ostream
p | - | 要插入到 os 的指针

返回值

os

注意

若 std::unique_ptr <Y, D>::pointer 为指向字符类型的指针（例如当 Y 为 char 或 char[] 或 CharT 时），这可能最终调用 operator<< 对空终止字符串的重载（若该指针实际上不指向这种字符串，则导致未定义行为），而非打印指针值自身的重载。

示例

#include <iostream>
#include <memory>

class Foo {};

int main()
{
    auto p = std::make_unique<Foo>();
    std::cout << p << '\n';
    std::cout << p.get() << '\n';
}

可能的输出：

0x6d9028
0x6d9028

参阅

get
 返回指向被管理对象的指针
(公开成员函数)


std::unique_ptr<T,Deleter>::release

< cpp‎ | memory‎ | unique ptr
pointer release() noexcept; | (C++11 起)

若存在，则释放被管理对象的所有权。调用后 get() 返回 nullptr 。

调用方负责删除该对象。

参数

（无）

返回值

指向被管理对象的指针，或若无被管理对象则为 nullptr ，即调用前 get() 会返回的值。

示例

#include <memory>
#include <iostream>
#include <cassert>

struct Foo {
    Foo() { std::cout << "Foo\n"; }
    ~Foo() { std::cout << "~Foo\n"; }
};

int main()
{
    std::cout << "Creating new Foo...\n";
    std::unique_ptr<Foo> up(new Foo());

    std::cout << "About to release Foo...\n";
    Foo* fp = up.release();

    assert (up.get() == nullptr);
    std::cout << "Foo is no longer owned by unique_ptr...\n";

    delete fp;
}

输出：

Creating new Foo...
Foo
About to release Foo...
Foo is no longer owned by unique_ptr...
~Foo

参阅

get | 返回指向被管理对象的指针 (公开成员函数)
reset | 替换被管理对象 (公开成员函数)


std::unique_ptr<T,Deleter>::reset

< cpp‎ | memory‎ | unique ptr
主模板 unique_ptr<T> 的成员 |
void reset( pointer ptr = pointer() ) noexcept; | (1)
特化 unique_ptr<T[]> 的成员 |
template< class U > void reset( U ) noexcept; | (2)
void reset( std::nullptr_t p = nullptr ) noexcept; | (3)

替换被管理对象。

1) 给定指向 *this 所管理对象的指针 current_ptr ，进行下列行动，以此顺序：
  1. 保存当前指针的副本 old_ptr = current_ptr
  2. 以参数重写当前指针 current_ptr = ptr
  3. 若旧指针非空，则删除先前管理的对象 if(old_ptr != nullptr) get_deleter()(old_ptr) 。
2) 表现同主模板的 reset 成员，除了它仅若满足下列任意条件才参与重载决议
  1. U 与 pointer 是同一类型，或
  2. pointer 与 element_type* 是同一类型，且 U 为指针类型 V* ，并满足 V(*)[] 可隐式转换为 element_type(*)[] 。
3) 等价于 reset(pointer()) 。

参数

ptr - 指向要管理的新对象的指针

返回值

（无）

注解

为在提供新删除器时替换被管理对象，可用移动赋值运算符。

不进行自 reset 测试，即 ptr 是否指向已为 *this 管理的对象，除非作为编译器扩展，或调试断言提供。注意如 p.reset(p.release()) 的代码不涉及自重置，只有类似 p.reset(p.get()) 的代码会。

示例

#include <iostream>
#include <memory>

struct Foo {
    Foo() { std::cout << "Foo...\n"; }
    ~Foo() { std::cout << "~Foo...\n"; }
};

struct D {
    void operator() (Foo* p) {
        std::cout << "Calling delete for Foo object... \n";
        delete p;
    }
};

int main()
{
    std::cout << "Creating new Foo...\n";
    std::unique_ptr<Foo, D> up(new Foo(), D());  // up 占有 Foo 指针（删除器 D ）

    std::cout << "Replace owned Foo with a new Foo...\n";
    up.reset(new Foo());  // 调用旧者的删除器

    std::cout << "Release and delete the owned Foo...\n";
    up.reset(nullptr);
}

输出：

Creating new Foo...
Foo...
Replace owned Foo with a new Foo...
Foo...
Calling delete for Foo object...
~Foo...
Release and delete the owned Foo...
Calling delete for Foo object...
~Foo...

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2118 | C++11 | unique_ptr<T[]>::reset 拒绝限定转换 | 接受

参阅

release
 返回一个指向被管理对象的指针，并释放所有权
(公开成员函数)


std::unique_ptr<T,Deleter>::swap

< cpp‎ | memory‎ | unique ptr
void swap(unique_ptr& other) noexcept; | (C++11 起)

交换 *this 和另一 unique_ptr 对象 other 的被管理对象和关联的删除器。

参数

other - 要与之交换被管理对象和删除器的另一 unique_ptr 对象

返回值

（无）

示例

#include <iostream>
#include <memory>

struct Foo {
    Foo(int _val) : val(_val) { std::cout << "Foo...\n"; }
    ~Foo() { std::cout << "~Foo...\n"; }
    int val;
};

int main()
{
    std::unique_ptr<Foo> up1(new Foo(1));
    std::unique_ptr<Foo> up2(new Foo(2));

    up1.swap(up2);

    std::cout << "up1->val:" << up1->val << std::endl;
    std::cout << "up2->val:" << up2->val << std::endl;
}

输出：

Foo...
Foo...
up1->val:2
up2->val:1
~Foo...
~Foo...


std::swap(std::unique_ptr)

< cpp‎ | memory‎ | unique ptr

定义于头文件 <memory> |
template< class T, class D > void swap( std::unique_ptr <T, D>& lhs, std::unique_ptr <T, D>& rhs ) noexcept; | (C++11 起)

对 std::unique_ptr 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

此重载仅若 std::is_swappable_v <D>::value 为 true 才参与重载决议。

 (C++17 起)

参数

lhs, rhs - 要交换内容的智能指针

返回值

（无）

复杂度

常数

参阅

swap | 交换两个对象的值 (函数模板)
swap | 交换内容 (公开成员函数)


std::unique_ptr<T,Deleter>::unique_ptr

< cpp‎ | memory‎ | unique ptr
主模板 unique_ptr<T> 的成员
constexpr unique_ptr() noexcept;
constexpr unique_ptr( std::nullptr_t ) noexcept;
 (1)
explicit unique_ptr( pointer p ) noexcept;
 (2)
unique_ptr( pointer p, /* see below */ d1 ) noexcept;
 (3)
unique_ptr( pointer p, /* see below */ d2 ) noexcept;
 (4)
unique_ptr( unique_ptr&& u ) noexcept;
 (5)
template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept;
 (6)
template< class U >
unique_ptr( std::auto_ptr <U>&& u ) noexcept;
 (7) (C++17 中移除)
数组特化 unique_ptr<T[]> 的成员
constexpr unique_ptr() noexcept;
constexpr unique_ptr( std::nullptr_t ) noexcept;
 (1)
template<class U> explicit unique_ptr( U p ) noexcept;
 (2)
template<class U> unique_ptr( U p, /* see below */ d1 ) noexcept;
 (3)
template<class U> unique_ptr( U p, /* see below */ d2 ) noexcept;
 (4)
unique_ptr( unique_ptr&& u ) noexcept;
 (5)
template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept;
 (6)
1) 构造不占有对象的 std::unique_ptr 。值初始化存储的指针和存储的删除器。要求 Deleter 可默认构造 (DefaultConstructible) 且构造不抛异常。这些重载仅若 std::is_default_constructible <Deleter>::value 为 true 且 Deleter 不是指针类型才参与重载决议。
2) 构造占有 p 的 std::unique_ptr ，以 p 初始化存储的指针，并值初始化存储的删除器。要求 Deleter 可默认构造 (DefaultConstructible) 且构造不抛异常。这些重载仅若 std::is_default_constructible <Deleter>::value 为 true 且 Deleter 不是指针类型才参与重载决议。

若类模板实参推导选择此构造函数，则程序为谬构。

 (C++17 起)
3-4) 构造占有 p 的 std::unique_ptr 对象，以 p 初始化存储的指针，并按下列方式初始化删除器 D （依赖于 D 是否为引用类型）
a) 若 D 是非引用类型 A ，则签名是：
unique_ptr(pointer p, const A& d) noexcept; | (1) | （要求 Deleter 为不抛出可复制构造 (CopyConstructible) ）
unique_ptr(pointer p, A&& d) noexcept; | (2) | （要求 Deleter 为不抛出可移动构造 (MoveConstructible) ）
b) 若 D 是左值引用类型 A& ，则签名是：
unique_ptr(pointer p, A& d) noexcept; | (1)
unique_ptr(pointer p, A&& d) = delete; | (2)
c) 若 D 是左值引用类型 const A& ，则签名是：
unique_ptr(pointer p, const A& d) noexcept; | (1)
unique_ptr(pointer p, const A&& d) = delete; | (2)
所有情况下中删除器从 std::forward <decltype(d)>(d) 初始化。这些重载仅若 std::is_constructible <D, decltype(d)>::value 为 true 才参与重载决议。

若类模板实参推导选择二个构造函数之一，则程序为谬构。

 (C++17 起)
2-4) 数组特化中表现同初等模板中接收一个指针参数的构造函数，除了它们不另外参与重载决议，除非下列之一为真：
  • U 与 pointer 为同一类型，或
  • U 为 std::nullptr_t ，或
  • pointer 与 element_type* 为同一类型且 U 为指针类型 V* ，满足 V(*)[] 可隐式转换为 element_type(*)[] 。
5) 通过从 u 转移所有权给 *this 构造 unique_ptr 并存储空指针于 u 。此构造函数仅若 std::is_move_constructible <Deleter>::value 为 true 才参与重载决议。若 Deleter 不是引用类型，则要求它为不抛出可移动构造 (MoveConstructible) （若 Deleter 是引用，则 get_deleter() 和 u.get_deleter() 在移动构造后引用相同值）。
6) 通过从 u 转移所有权给 *this 构造 unique_ptr ，其中 u 以指定的删除器（ E ）构造。它依赖于 E 是否引用类型，如下：
a) 若 E 是引用类型，则从 u 的删除器复制构造此删除器（要求此构造不抛出）
b) 若 E 不是引用类型，则从 u 的删除器移动构造此删除器（要求此构造不抛出）
此构造函数仅若下列皆为真才参与重载决议：
a) unique_ptr<U, E>::pointer 可隐式转换为 pointer
b) U 不是数组类型
c) Deleter 是引用类型且 E 与 D 为同一类型，或 Deleter 不是引用类型且 E 可隐式转换为 D
6) 数组特化中，表现同在初等模板中的版本，除了它仅若下列皆为真才会参与重载决议
  • U 是数组类型
  • pointer 与 element_type* 是同一类型
  • unique_ptr<U,E>::pointer 与 unique_ptr<U,E>::element_type* 是同一类型
  • unique_ptr<U,E>::element_type(*)[] 可转换为 element_type(*)[]
  • Deleter 是引用类型且 E 与 Deleter 是同一类型，或 Deleter 非引用类型且 E 可隐式转换为 Deleter 。
7) 构造 unique_ptr ，其中以 u.release() 初始化存储的指针，并值初始化存储的删除器。此构造函数仅若 U* 可隐式转换为 T* 且 Deleter 与 std::default_delete<T> 为同一类型才参与重载决议。

参数

p | - | 指向要管理的对象的指针
d1,d2 | - | 用于销毁对象的删除器
u | - | 获取所有权来源的智能指针

注解

使用 std::make_unique<T> 是更好的做法，可取代与 new 一起的重载 (2) 。

 (C++14 起)

std::unique_ptr <Derived> 通过重载 (6) 可隐式转换为 std::unique_ptr <Base> （因为被管理指针和 std::default_delete 都可隐式转换）。

因为默认构造函数是 constexpr ，故静态的 unique_ptr 作为静态非局部初始化的一部分初始化，在任何动态初始化之前。这使得在任何静态对象的构造函数中使用 unique_ptr 是安全的。

无源自指针类型的类模板实参推导，因为不可能辨别来自 new 的数组和非数组形式的指针。

 (C++17 起)

示例

#include <iostream>
#include <memory>

struct Foo { // 要管理的对象
    Foo() { std::cout << "Foo ctor\n"; }
    Foo(const Foo&) { std::cout << "Foo copy ctor\n"; }
    Foo(Foo&&) { std::cout << "Foo move ctor\n"; }
    ~Foo() { std::cout << "~Foo dtor\n"; }
};

struct D { // 删除器
    D() {};
    D(const D&) { std::cout << "D copy ctor\n"; }
    D(D&) { std::cout << "D non-const copy ctor\n";}
    D(D&&) { std::cout << "D move ctor \n"; }
    void operator()(Foo* p) const {
        std::cout << "D is deleting a Foo\n";
        delete p;
    };
};

int main()
{
    std::cout << "Example constructor(1)...\n";
    std::unique_ptr<Foo> up1;  // up1 为空
    std::unique_ptr<Foo> up1b(nullptr);  // up1b 为空

    std::cout << "Example constructor(2)...\n";
    {
        std::unique_ptr<Foo> up2(new Foo); // up2 现在占有 Foo
    } // Foo 被删除

    std::cout << "Example constructor(3)...\n";
    D d;
    {  // 删除器类型不是引用
       std::unique_ptr<Foo, D> up3(new Foo, d); // 复制删除器
    }
    {  // 删除器类型是引用
       std::unique_ptr<Foo, D&> up3b(new Foo, d); // up3b 保有到 d 的引用
    }

    std::cout << "Example constructor(4)...\n";
    {  // 删除器不是引用
       std::unique_ptr<Foo, D> up4(new Foo, D()); // 移动删除器
    }

    std::cout << "Example constructor(5)...\n";
    {
       std::unique_ptr<Foo> up5a(new Foo);
       std::unique_ptr<Foo> up5b(std::move(up5a)); // 所有权转移
    }

    std::cout << "Example constructor(6)...\n";
    {
        std::unique_ptr<Foo, D> up6a(new Foo, d); // 复制 D
        std::unique_ptr<Foo, D> up6b(std::move(up6a)); // 移动 D

        std::unique_ptr<Foo, D&> up6c(new Foo, d); // D 是引用
        std::unique_ptr<Foo, D> up6d(std::move(up6c)); // 复制 D
    }

#if (__cplusplus < 201703L)
    std::cout << "Example constructor(7)...\n";
    {
        std::auto_ptr<Foo> up7a(new Foo);
        std::unique_ptr<Foo> up7b(std::move(up7a)); // 所有权转移
    }
#endif

    std::cout << "Example array constructor...\n";
    {
        std::unique_ptr<Foo[]> up(new Foo[3]);
    } // 删除三个 Foo 对象
}

输出：

Example constructor(1)...
Example constructor(2)...
Foo ctor
~Foo dtor
Example constructor(3)...
Foo ctor
D copy ctor
D is deleting a Foo
~Foo dtor
Foo ctor
D is deleting a Foo
~Foo dtor
Example constructor(4)...
Foo ctor
D move ctor
D is deleting a Foo
~Foo dtor
Example constructor(5)...
Foo ctor
~Foo dtor
Example constructor(6)...
Foo ctor
D copy ctor
D move ctor
Foo ctor
D non-const copy ctor
D is deleting a Foo
~Foo dtor
D is deleting a Foo
~Foo dtor
Example constructor(7)...
Foo ctor
~Foo dtor
Example array constructor...
Foo ctor
Foo ctor
Foo ctor
~Foo dtor
~Foo dtor
~Foo dtor

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2118 | C++11 | unique_ptr<T[]> 的构造函数拒绝限定转换 | 接受
LWG 2520 | C++11 | unique_ptr<T[]> 被意外地设为不可从 nullptr_t 构造 | 使之可构造
LWG 2801 | C++11 | 默认构造函数未受约束 | 已约束
LWG 2899 | C++11 | 移动构造函数未受约束 | 已约束
LWG 2905 | C++11 | 来自指针和删除器的构造函数上的约束错误 | 更正
LWG 2944 | C++11 | 某些前条件被 LWG 2905 意外丢弃 | 恢复


std::unique_ptr<T,Deleter>::~unique_ptr

< cpp‎ | memory‎ | unique ptr
~unique_ptr(); | (C++11 起)

若 get() == nullptr 则无效果。否则，通过 get_deleter() (get()) 销毁占有的对象。

要求 get_deleter()(get()) 不抛异常。

注意

即使拥有默认删除器的 std::unique_ptr<T> 能以不完整类型 T 构造，在调用析构函数的代码位置， T 必须完整。

示例

下列程序演示定制删除器的用法。

#include <iostream>
#include <memory>

int main ()
{
    auto deleter = [](int* ptr){
        std::cout << "[deleter called]\n";
        delete ptr;
    };

    std::unique_ptr<int,decltype(deleter)> uniq(new int, deleter);
    std::cout << (uniq ? "not empty\n" : "empty\n");
    uniq.reset();
    std::cout << (uniq ? "not empty\n" : "empty\n");
}

输出：

not empty
[deleter called]
empty


std::pmr::unsynchronized_pool_resource

< cpp‎ | memory
定义于头文件 <memory_resource> |
class unsynchronized_pool_resource : public std::pmr::memory_resource ; | (C++17 起)

类 std::pmr::unsynchronized_pool_resource 是带下列属性的通用内存资源类：

  • 它占有被分配内存并在析构时释放它，即使 deallocate 未被对于某些被分配块调用。
  • 它由供应不同块大小请求的池的汇集组成。每个池管理之后被分入一致大小的大块的汇集。
  • 对 do_allocate 的调用被派发到供应适应请求大小的最小块的池。
  • 在池中耗尽内存，会导致该池从上游分配器分配额外的内存大块，以填满池。获取的大块大小以几何级数增加。
  • 请求超出最大的块大小的分配，由上游分配器直接供应。
  • 最大的块大小和大块大小的最大值可通过传递 std::pmr::pool_options 结构体给其构造函数调节。

unsynchronized_pool_resource 不是线程安全的，而且不能从多个线程同时访问；若要求从多个线程访问则应使用 synchronized_pool_resource 。

成员函数

(构造函数)
 构造 unsynchronized_pool_resource
(公开成员函数)
(析构函数)
[虚]
 销毁 unsynchronized_pool_resource ，释放所有分配的内存
(虚公开成员函数)
operator=
[被删除]
 复制赋值运算符被删除， unsynchronized_pool_resource 不可复制赋值
(公开成员函数)
公开成员函数
release
 释放所有分配的内存
(公开成员函数)
upstream_resource
 返回指向上游 memory_resource 的指针
(公开成员函数)
options
 返回控制此资源分池行为的选项
(公开成员函数)
受保护成员函数
do_allocate
[虚]
 分配内存
(虚受保护成员函数)
do_deallocate
[虚]
 返还内存到池
(虚受保护成员函数)
do_is_equal
[虚]
 与另一 std::pmr::memory_resource 比较相等
(虚受保护成员函数)


std::pmr::unsynchronized_pool_resource::do_allocate

< cpp‎ | memory‎ | unsynchronized pool resource
virtual void* do_allocate( std::size_t bytes, std::size_t alignment); | (C++17 起)

分配存储。

若为 bytes 大小的块所选的池不足以满足来自其内部数据结构的请求，则调用上游 memory_resources 上的 allocate() 以获得内存。

若请求的大小大于最大的池所能处理者，则通过调用上游 memory_resources 上的 allocate() 分配内存。

返回值

指向至少有 bytes 字节大小，若支持这种对齐则对齐到指定的 alignment ，否则对齐到 alignof( std::max_align_t ) 的被分配存储。

异常

除非上游内存资源上的 allocate() 调用抛出异常，否则不抛出。

参阅

allocate | 分配内存 (std::pmr::memory_resource 的公开成员函数)
do_allocate [虚] | 分配内存 (std::pmr::memory_resource 的虚私有成员函数)


std::pmr::unsynchronized_pool_resource::do_deallocate

< cpp‎ | memory‎ | unsynchronized pool resource
virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment); | (C++17 起)

将在 p 的内存返还到池。此操作是否或在何种场合下导致对上游 memory_resource 上的 deallocate() 调用是未指定的。

异常

不抛出。

参阅

deallocate | 解分配内存 (std::pmr::memory_resource 的公开成员函数)
do_deallocate [虚] | 解分配内存 (std::pmr::memory_resource 的虚私有成员函数)


std::pmr::unsynchronized_pool_resource::do_is_equal

< cpp‎ | memory‎ | unsynchronized pool resource
virtual bool do_is_equal(const std::pmr::memory_resource & other) const noexcept; | (C++17 起)

比较 *this 与 other 的相等性——用 unsynchronized_pool_resource 分配的内存只能用同一资源解分配。

返回值

this == &other

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3000 | C++17 | 进行了不必要的 dynamic_cast | 已移除

参阅

do_is_equal
[虚]
 与另一 memory_resource 比较相等
(std::pmr::memory_resource 的虚私有成员函数)


std::pmr::unsynchronized_pool_resource::options

< cpp‎ | memory‎ | unsynchronized pool resource
std::pmr::pool_options options() const; | (C++17 起)

返回控制此资源行为的选项。

返回的结构体中的值可以以下列方式，异于提供给构造函数的值：

  • 零值将被替换成实现指定的默认值；
  • 大小可被取整到未指定的粒度。

参阅

(构造函数)
 构造 unsynchronized_pool_resource
(公开成员函数)


std::pmr::unsynchronized_pool_resource::release

< cpp‎ | memory‎ | unsynchronized pool resource
void release(); | (C++17 起)

需要时，通过调用上游 memory_resource 的 deallocate 函数，释放所有此资源所占有的内存。

即使未对某些被分配块调用 deallocate ，资源也被返还给上游 memory_resource 。

参阅

deallocate
 解分配内存
(std::pmr::memory_resource 的公开成员函数)


std::pmr::unsynchronized_pool_resource::unsynchronized_pool_resource

< cpp‎ | memory‎ | unsynchronized pool resource
unsynchronized_pool_resource();
 (1) (C++17 起)
explicit unsynchronized_pool_resource( std::pmr::memory_resource * upstream);
 (2) (C++17 起)
explicit unsynchronized_pool_resource(const std::pmr::pool_options & opts);
 (3) (C++17 起)
unsynchronized_pool_resource(const std::pmr::pool_options & opts,
std::pmr::memory_resource * upstream);
 (4) (C++17 起)
unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete;
 (5) (C++17 起)

构造一个 unsynchronized_pool_resource 。

1-4) 用指定的上游 memory_resource 构造一个 unsynchronized_pool_resource 并根据指定的选项调节。结果对象保有 upstream 的副本但不占有 upstream 所指向的资源。
不将 opts 接收为参数的重载以默认构造的 pool_options 实例为选项。不将 upstream 作为参数接收的重载以 std::pmr::get_default_resource () 的返回值为上游 memory_resource 。
5) 复制构造函数被删除。

参数

opts | - | 含有构造函数选项的 std::pmr::pool_options 结构体
upstream | - | 所用的上游 memory_resource

异常

1-4) 仅若上游资源的 allocate() 函数抛出异常才抛出。这种调用在何种条件下发生或是否发生是未指定的。


std::pmr::unsynchronized_pool_resource::upstream_resource

< cpp‎ | memory‎ | unsynchronized pool resource
std::pmr::memory_resource * upstream_resource() const; | (C++17 起)

返回指向上游 memory_resource 的指针。其值与传递给此对象构造函数的 upstream 参数相同。

参阅

(构造函数)
 构造 unsynchronized_pool_resource
(公开成员函数)


std::pmr::unsynchronized_pool_resource::~unsynchronized_pool_resource

< cpp‎ | memory‎ | unsynchronized pool resource
virtual ~unsynchronized_pool_resource(); | (C++17 起)

销毁 unsynchronized_pool_resource 。

通过调用 this->release() 释放此资源所拥有的所有内存。

参阅

release
 释放所有分配的内存
(公开成员函数)


std::uses_allocator

< cpp‎ | memory
定义于头文件 <memory> |
template< class T, class Alloc > struct uses_allocator; | (C++11 起)

若 T 拥有：1）内嵌定义类型 allocator_type ，并且该类型能从 Alloc 转换，2）或者该类型是 std::experimental::erased_type 的别名 (库基础 TS)，则成员常量 value 为 true 。否则 value 为 false 。

辅助变量模板

template< class T, class Alloc > inline constexpr bool uses_allocator_v = uses_allocator<T, Alloc>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 使用分配器 Alloc则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

使用分配器构造

传递分配器 alloc 给某类型 T 的构造函数有三种约定：

  • 若 T 不使用兼容的分配器（ std::uses_allocator_v<T, Alloc> 为 false ），则忽略 alloc 。
  • 否则 std::uses_allocator_v<T, Alloc> 为 true ，而
  • 若 T 使用前导分配器约定（可用 T( std::allocator_arg, alloc, args...) 调用），则使用分配器构造使用此形式
  • 若 T 使用尾随分配器约定（可用 T(args..., alloc) 调用），则使用分配器构造使用此形式
  • 否则，程序为谬构（这表示 std::uses_allocator_v<T, Alloc> 为 true ，但类型不遵守二种允许的约定之一）
  • 作为特例， std::pair 被当做使用分配器类型，即使 std::uses_allocator 对 pair 为 false （不同于 std::tuple 等）；见 std::polymoprhic_allocator::construct 与 std::scoped_allocator_adaptor::construct (C++20 前)std::uses_allocator_construction_args (C++20 起) 的 pair 特定重载。

工具函数 std::make_obj_using_allocator 及 std::uninitialized_construct_using_allocator 可用于显式创建遵循上述协议的对象，而 std::uses_allocator_construction_args 能用于准备匹配类型所期待的使用分配器构造的口味的实参列表。

 (C++20 起)

特化

类型特性 std::uses_allocator 的自定义特化对无成员 typedef allocator_type 的类型允许，但必须满足下列二个要求之一：

1) T 拥有接收 std::allocator_arg_t 为首参数， Alloc 为第二参数的构造函数。
2) T 拥有接收 Alloc 为最后参数的构造函数。

上述情况中， Alloc 是满足分配器 (Allocator) 要求的类型，或是可转换到 std::experimental::pmr::memory_resource* 的指针类型 (库基础 TS)。

标准库已提供下列特化：

std::uses_allocator<std::tuple> (C++11) | 特化 std::uses_allocator 类型特征 (类模板特化)
std::uses_allocator<std::queue> (C++11) | 特化 std::uses_allocator 类型特征 (类模板特化)
std::uses_allocator<std::priority_queue> (C++11) | 特化 std::uses_allocator 类型特征 (类模板特化)
std::uses_allocator<std::stack> (C++11) | 特化 std::uses_allocator 类型特征 (类模板特化)
std::uses_allocator<std::function> (C++11) (C++17 前) | 特化 std::uses_allocator 类型特性 (类模板特化)
std::uses_allocator<std::promise> (C++11) | 特化 std::uses_allocator 类型特征 (类模板特化)
std::uses_allocator<std::packaged_task> (C++11)(C++17 前) | 特化 std::uses_allocator 类型特征 (类模板特化)

注解

std::scoped_allocator_adaptor 、 std::tuple 及 std::pmr::polymorphic_allocator 使用此类型特性。自定义分配器或封装类型亦可使用之，以确定要构造的对象或成员是否足以使用分配器（例如是容器的情况），该情况下应传递分配器给其构造函数。

参阅

allocator_arg (C++11) | 用于选择具分配器的构造函数的 std::allocator_arg_t 对象 (常量)
allocator_arg_t (C++11) | 标签类型，用于选择具分配器的构造函数重载 (类)
uses_allocator_construction_args (C++20) | 准备匹配给定类型所要求的使用分配器构造的口味的参数列表 (函数模板)
make_obj_using_allocator (C++20) | 以使用分配器构造的手段创建给类型的对象 (函数模板)
uninitialized_construct_using_allocator (C++20) | 以使用分配器构造的手段在指定的内存位置创建给定类型的对象 (函数模板)
scoped_allocator_adaptor (C++11) | 为多级容器实现的多级分配器 (类模板)


std::uses_allocator_construction_args

< cpp‎ | memory
定义于头文件 <memory> |  |
T 不是 std::pair 的特化 |  |
template< class T, class Alloc, class... Args > constexpr auto uses_allocator_construction_args( const Alloc& alloc, Args&&... args) noexcept; | (1) | (C++20 起)
T 是 std::pair 的特化 |  |
template< class T, class Alloc, class Tuple1, class Tuple2 > constexpr auto uses_allocator_construction_args( const Alloc& alloc, std::piecewise_construct_t, Tuple1&& x, Tuple2&& y) noexcept; | (2) | (C++20 起)
template< class T, class Alloc > constexpr auto uses_allocator_construction_args( const Alloc& alloc ) noexcept; | (3) | (C++20 起)
template< class T, class Alloc, class U, class V > constexpr auto uses_allocator_construction_args( const Alloc& alloc, U&& u, V&& v) noexcept; | (4) | (C++20 起)
template< class T, class Alloc, class U, class V > constexpr auto uses_allocator_construction_args( const Alloc& alloc, const std::pair <U, V>& pr ) noexcept; | (5) | (C++20 起)
template< class T, class Alloc, class U, class V > constexpr auto uses_allocator_construction_args( const Alloc& alloc, std::pair <U, V>&& pr) noexcept; | (6) | (C++20 起)

准备以使用分配器构造的手段创建给定类型 T 对象所需的参数列表。

1) 此重载仅若 T 不是 std::pair 的特化才参与重载决议。返回按下列方式确定的 std::tuple ：
  • 若 std::uses_allocator_v <T, Alloc> 为 false 而 std::is_constructible_v <T, Args...> 为 true ，则返回 std::forward_as_tuple ( std::forward <Args>(args)...)
  • 否则，若 std::uses_allocator_v <T, Alloc> 为 true 而 std::is_constructible_v <T, std::allocator_arg_t, const Alloc&, Args...> 为 true ，则返回 std::tuple < std::allocator_arg_t, const Alloc&, Args&&...>( std::allocator_arg, alloc, std::forward <Args>(args)...)
  • 否则，若 std::uses_allocator_v <T, Alloc> 为 true 而 std::is_constructible_v <T, Args..., const Alloc&> 为 true ，则返回 std::forward_as_tuple ( std::forward <Args>(args)..., alloc)
  • 否则，程序非良构
2) 此重载仅若 T 是 std::pair 的特化才参与重载决议。对作为 std::pair <T1, T2> 的 T 等价于
return std::make_tuple( std::piecewise_construct,
    std::apply( [&alloc](auto&&... args1) {
            return std::uses_allocator_construction_args<T1>( alloc,
                       std::forward<decltype(args1)>(args1)...);
        }, std::forward<Tuple1>(x)),
    std::apply( [&alloc](auto&&... args2) {
            return std::uses_allocator_construction_args<T2>( alloc,
                    std::forward<decltype(args2)>(args2)...);
        }, std::forward<Tuple2>(y))
    );
3) 此重载仅若 T 是 std::pair 的特化才参与重载决议。等价于
return std::uses_allocator_construction_args<T>(alloc,
    std::piecewise_construct, std::tuple<>{}, std::tuple<>{}
);
4) 此重载仅若 T 是 std::pair 的特化才参与重载决议。等价于
return std::uses_allocator_construction_args<T>( alloc,
    std::piecewise_construct,
    std::forward_as_tuple(std::forward<U>(u)),
    std::forward_as_tuple(std::forward<V>(v))
);
5) 此重载仅若 T 是 std::pair 的特化才参与重载决议。等价于
return std::uses_allocator_construction_args<T>( alloc,
    std::piecewise_construct,
    std::forward_as_tuple(pr.first),
    std::forward_as_tuple(pr.second)
);
6) 此重载仅若 T 是 std::pair 的特化才参与重载决议。等价于
return std::uses_allocator_construction_args<T>( alloc,
    std::piecewise_construct,
    std::forward_as_tuple(std::get<0>(std::move(pr))),
    std::forward_as_tuple(std::get<1>(std::move(pr)));

参数

alloc | - | 使用的分配器。
args | - | 传递给 T 构造函数的参数。
x | - | 传递给 T 的 .first 的构造函数的参数 tuple 。
y | - | 传递给 T 的 .second 的构造函数的参数 tuple 。
u | - | 传递给 T 的 .first 的构造函数的单个参数。
v | - | 传递给 T 的 .second 的构造函数的单个参数。
pr | - | pair ，将其 .first 传递给 T 的 .first 的构造函数，并将其 .second 传递给 T 的 .second 的构造函数的

返回值

适合于传递给 T 构造函数的参数的 std::tuple 。

示例

本节未完成
原因：暂无示例

注解

重载 (2-6) 提供传入 std::pair 的分配器传播，它们不支持前导分配器或尾随分配器约定（不同于如使用前导分配器约定的 std::tuple ）。

参阅

uses_allocator (C++11) | 检查指定的类型是否支持使用分配器的构造 (类模板)
make_obj_using_allocator (C++20) | 以使用分配器构造的手段创建给类型的对象 (函数模板)
uninitialized_construct_using_allocator (C++20) | 以使用分配器构造的手段在指定的内存位置创建给定类型的对象 (函数模板)


std::weak_ptr

< cpp‎ | memory
定义于头文件 <memory> |
template< class T > class weak_ptr; | (C++11 起)

std::weak_ptr 是一种智能指针，它对被 std::shared_ptr 管理的对象存在非拥有性（「弱」）引用。在访问所引用的对象前必须先转换为 std::shared_ptr。

std::weak_ptr 用来表达临时所有权的概念：当某个对象只有存在时才需要被访问，而且随时可能被他人删除时，可以使用 std::weak_ptr 来跟踪该对象。需要获得临时所有权时，则将其转换为 std::shared_ptr，此时如果原来的 std::shared_ptr 被销毁，则该对象的生命期将被延长至这个临时的 std::shared_ptr 同样被销毁为止。

std::weak_ptr 的另一用法是打断 std::shared_ptr 所管理的对象组成的环状引用。若这种环被孤立（例如无指向环中的外部共享指针），则 shared_ptr 引用计数无法抵达零，而内存被泄露。能令环中的指针之一为弱指针以避免此情况。

成员类型

成员类型 定义
element_type
T | (C++17 前)
std::remove_extent_t <T> | (C++17 起)

成员函数

(构造函数)
 构造新的weak_ptr
(公开成员函数)
(析构函数)
 销毁 weak_ptr
(公开成员函数)
operator=
 为weak_ptr赋值
(公开成员函数)
修改器
reset
 释放被管理对象的所有权
(公开成员函数)
swap
 交换被管理对象
(公开成员函数)
观察器
use_count
 返回管理该对象的 shared_ptr 对象数量
(公开成员函数)
expired
 检查被引用的对象是否已删除
(公开成员函数)
lock
 创建管理被引用的对象的shared_ptr
(公开成员函数)
owner_before
 提供弱指针的基于拥有者顺序
(公开成员函数)

非成员函数

std::swap(std::weak_ptr)
(C++11)
 特化 std::swap 算法
(函数模板)

辅助类

std::atomic<std::weak_ptr>
(C++20)
 原子弱指针
(类模板特化)

推导指引 (C++17 起)

注解

同 std::shared_ptr ， weak_ptr 的典型实现存储二个指针：

  • 指向控制块的指针；和
  • 作为构造来源的 shared_ptr 的存储指针。

需要用分离的存储指针确保 shared_ptr 和 weak_ptr 间的来回转化正确进行，即使对于别名使用的 shared_ptr 。不可能不经将 weak_ptr 中的存储指针锁入 shared_ptr 就访问它。

示例

演示如何通过锁来保证指针的有效性

#include <iostream>
#include <memory>

std::weak_ptr<int> gw;

void observe()
{
    std::cout << "use_count == " << gw.use_count() << ": ";
    if (auto spt = gw.lock()) { // 使用之前必须复制到 shared_ptr
        std::cout << *spt << "\n";
    }
    else {
        std::cout << "gw is expired\n";
    }
}

int main()
{
    {
        auto sp = std::make_shared<int>(42);
        gw = sp;

        observe();
    }

    observe();
}

输出：

use_count == 1: 42
use_count == 0: gw is expired

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3001 | C++17 | 未为数组支持更新 element_type | 已更新


std::atomic(std::weak_ptr)

< cpp‎ | memory‎ | weak ptr
定义于头文件 <memory> |
template <class T> struct std::atomic < std::weak_ptr <T>>; | (C++20 起)

std::atomic 对 std::weak_ptr <T> 的部分模板特化允许用户原子地操纵 weak_ptr 。

若多个执行线程访问同一 std::weak_ptr 对象而不同步，而任何这些访问使用 weak_ptr 的非 const 成员函数，则将出现数据竞争，除非所有这种访问都通过 std::atomic<std::weak_ptr>> 的实例进行。

保证关联 use_count 的自增是原子操作的一部分。要求关联 use_count 的自减在原子操作之后，但不要求是其一部分，除非在覆写失败的 CAS 中的 expected 时 use_count 更改。任何关联删除和解分配后序于原子更新步骤，且不是原子操作的一部分。

注意 std::weak_ptr 和 std::shared_ptr 所用的控制块是线程安全的：多个线程能同时用可变操作，例如 operator= 或 reset ，访问不同的非原子 std::weak_ptr 对象，即使在这些实例互为副本，或因其他原因于内部共享同一控制块时。

类型 T 可为不完整类型。

成员类型

成员类型 | 定义
value_type | std::weak_ptr <T>

成员函数

此特化亦提供所有非特化 std::atomic 的成员函数，且不提供额外成员函数。

atomic<weak_ptr<T>>::atomic

constexpr atomic() noexcept = default; | (1)
atomic( std::weak_ptr <T> desired) noexcept; | (2)
atomic(const atomic&) = delete; | (3)
1) 初始化底层 weak_ptr<T> 为默认构造值。
2) 初始化底层 weak_ptr<T> 为 desired 的副本。同任何 std::atomic ，初始化不是原子操作。
3) 原子类型不可复制/移动构造。

atomic<weak_ptr<T>>::operator=

void operator=(const atomic&) = delete; | (1)
void operator=( std::weak_ptr <T> desired) noexcept; | (2)
1) 原子类型不可复制/移动赋值。
2) 值赋值，等价于 store(desired)

atomic<weak_ptr<T>>::is_lock_free

bool is_lock_free() const noexcept;

若此类型所有对象上的原子操作为无锁则返回 true ，否则返回 false 。

atomic<weak_ptr<T>>::store

void store( std::weak_ptr <T> desired,
std::memory_order order = std::memory_order_seq_cst ) noexcept;

如同用 p.swap(desired) ，原子地以 desired 的值替换 *this 的值，其中 p 为底层的 std::weak_ptr<T> 。按照 order 排序内存。若 order 非 std::memory_order_consume 、 std::memory_order_acquire 或 std::memory_order_acq_rel 则行为未定义。

atomic<weak_ptr<T>>::load

std::weak_ptr <T> load( std::memory_order order = std::memory_order_seq_cst ) const noexcept;

原子地返回底层 std::weak_ptr<T> 的副本。按照 order 排序内存。若 order 非 std::memory_order_release 或 std::memory_order_acq_rel 则行为未定义。

atomic<weak_ptr<T>>::operator std::weak_ptr<T>

operator std::weak_ptr <T>() const noexcept;

等价于 return load(); 。

atomic<weak_ptr<T>>::exchange

std::weak_ptr <T> exchange( std::weak_ptr <T> desired,
std::memory_order order = std::memory_order_seq_cst ) noexcept;

如同用 p.swap(desired) ，原子地以 desired 替换底层 std::weak_ptr <T> ，其中 p 为底层 std::weak_ptr<T> ，并返回 p 立即在交换前所拥有的值的副本。按照 order 排序内存。操作是原子读修改写操作。

atomic<weak_ptr<T>>::compare_exchange_weak, compare_exchange_strong

bool compare_exchange_strong( std::weak_ptr <T>& expected, std::weak_ptr <T> desired,
std::memory_order success, std::memory_order failure) noexcept;
 (1)
bool compare_exchange_weak( std::weak_ptr <T>& expected, std::weak_ptr <T> desired,
std::memory_order success, std::memory_order failure) noexcept;
 (2)
bool compare_exchange_strong( std::weak_ptr <T>& expected, std::weak_ptr <T> desired,
std::memory_order order = std::memory_order_seq_cst ) noexcept;
 (3)
bool compare_exchange_weak( std::weak_ptr <T>& expected, std::weak_ptr <T> desired,
std::memory_order order = std::memory_order_seq_cst ) noexcept;
 (4)
1) 若底层 std::weak_ptr <T> 存储值与 expected 相同的指针，并与之共享所有权，或若底层指针和 expected 均为空，则从 desired 赋值给底层 std::weak_ptr <T> 并返回 true ，按照 success 排序内存；否则从底层 std::weak_ptr <T> 赋值给 expected 并返回 false ，按照 failure 排序内存。若 failure 为 std::memory_order_release 或 std::memory_order_acq_rel 则行为未定义。成功时，操作为 *this 上的原子读修改写操作，而在原子更新后不访问 expected 。失败时，操作是 *this 上的原子加载操作，并以读取自原子对象的既存值更新 expected 。这个对 expected 的 use_count 的更新是原子操作，尽管不要求写入自身（和任何后继的解分配/析构）是。
2) 同 (1) ，但可能虚假地失败。
3) 等价于： return compare_exchange_strong(expected, desired, order, fail_order); ，其中 fail_order 与 order 相同，除了 std:memory_order_acq_rel 被替换为 std::memory_order_acquire ，而 std::memory_order_release 被替换为 std::memory_order_relaxed 。
4) 等价于： return compare_exchange_weak(expected, desired, order, fail_order); ，其中 fail_order 与 order 相同，除了 std::memory_order_acq_rel 被替换为 std::memory_order_acquire ，而 std::memory_order_release 被替换为 std::memory_order_relaxed 。

atomic<weak_ptr<T>>::wait

void wait( std::weak_ptr <T> old
std::memory_order order = std::memory_order_seq_cst ) const noexcept;

进行原子等待操作。

比较 load(order) 与 old ，而若它们等价则阻塞直至 *this 被 notify_one() 或 notify_all() 提醒。重复此操作直至 load(order) 更改。此函数保证仅若值更改才返回，即使底层实现虚假地除阻。

按照 order 排序内存。若 order 为 std::memory_order_release 或 std::memory_order_acq_rel 则行为未定义。

注解：若二个 weak_ptr 存储同一指针，且要么共享所有权要么都为空，则它们等价。

atomic<weak_ptr<T>>::notify_one

void notify_one() noexcept;

进行原子提醒操作。

若有一个线程在 *this 上的原子等待操作（即 wait() ）中阻塞，则除阻至少一个这种线程，否则不做任何事。

atomic<weak_ptr<T>>::notify_all

void notify_all() noexcept;

进行原子提醒操作。

除阻所有在 *this 上的原子等待操作（即 wait() ）中阻塞的线程，若存在；否则不做任何事。

成员常量

此特化亦提供唯一的标准 std::atomic 成员常量 is_always_lock_free 。

atomic<weak_ptr<T>>::is_always_lock_free

static constexpr bool is_always_lock_free = /*implementation-defined*/;

示例

本节未完成
原因：暂无示例

参阅

atomic
(C++11)
 atomic 类模板及其针对布尔、整型和指针类型的特化
(类模板)


std::weak_ptr 的推导指引

< cpp‎ | memory‎ | weak ptr
定义于头文件 <memory> |
template<class T> weak_ptr( std::shared_ptr <T>) -> weak_ptr<T>; | (C++17 起)

为 std::weak_ptr 提供一个推导指引以处理隐式推导指引所遗漏的特殊情况。

示例

#include <memory>

int main()
{
    auto p = std::make_shared<int>(42);
    std::weak_ptr w{p};    // 用于此情况的显式推导指引
}


std::weak_ptr<T>::expired

< cpp‎ | memory‎ | weak ptr
bool expired() const noexcept; | (C++11 起)

等价于 use_count() == 0 。可能仍未对被管理对象调用析构函数，但此对象的析构已经临近（或可能已发生）。

参数

（无）

返回值

若被管理对象已被删除则为 true ，否则为 false 。

注意

若被管理对象在线程间共享，则此函数内在地不可靠，通常 false 结果可能在能用之前就变得过时。 true 结果可靠。

示例

演示如何用 expired 检查指针的合法性。

#include <iostream>
#include <memory>

std::weak_ptr<int> gw;

void f()
{
    if (!gw.expired()) {
        std::cout << "gw is valid\n";
    }
    else {
        std::cout << "gw is expired\n";
    }
}

int main()
{
    {
        auto sp = std::make_shared<int>(42);
        gw = sp;

        f();
    }

    f();
}

输出：

gw is valid
gw is expired

参阅

lock | 创建管理被引用的对象的shared_ptr (公开成员函数)
use_count | 返回管理该对象的 shared_ptr 对象数量 (公开成员函数)


std::weak_ptr<T>::lock

< cpp‎ | memory‎ | weak ptr
std::shared_ptr <T> lock() const noexcept; | (C++11 起)

创建新的 std::shared_ptr 对象，它共享被管理对象的所有权。若无被管理对象，即 *this 为空，则返回亦为空的 shared_ptr 。

等效地返回 expired() ? shared_ptr<T>() : shared_ptr<T>(*this) ，原子地执行。

参数

（无）

返回值

若 std::weak_ptr::expired 返回 false 则为共享被占有对象所有权的 shared_ptr 。否则返回默认构造的 T 类型的 shared_ptr 。

注意

此函数和 std::shared_ptr 的构造函数可能获得 std::weak_ptr 所指向的被管理对象的临时所有权。区别是 std::shared_ptr 的构造函数在其 std::weak_ptr 为空时抛异常，而 std::weak_ptr<T>::lock() 构造空的 std::shared_ptr<T> 。

示例

#include <iostream>
#include <memory>

void observe(std::weak_ptr<int> weak)
{
    if (auto observe = weak.lock()) {
        std::cout << "\tobserve() able to lock weak_ptr<>, value=" << *observe << "\n";
    } else {
        std::cout << "\tobserve() unable to lock weak_ptr<>\n";
    }
}

int main()
{
    std::weak_ptr<int> weak;
    std::cout << "weak_ptr<> not yet initialized\n";
    observe(weak);

    {
        auto shared = std::make_shared<int>(42);
        weak = shared;
        std::cout << "weak_ptr<> initialized with shared_ptr.\n";
        observe(weak);
    }

    std::cout << "shared_ptr<> has been destructed due to scope exit.\n";
    observe(weak);
}

输出：

weak_ptr<> not yet initialized
        observe() unable to lock weak_ptr<>
weak_ptr<> initialized with shared_ptr.
        observe() able to lock weak_ptr<>, value=42
shared_ptr<> has been destructed due to scope exit.
        observe() unable to lock weak_ptr<>

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2316 | C++11 | 不要求 lock() 是原子的，但要求为 noexcept ，这导致矛盾 | 指定为原子的

参阅

expired
 检查被引用的对象是否已删除
(公开成员函数)


std::weak_ptr<T>::operator=

< cpp‎ | memory‎ | weak ptr
weak_ptr& operator=( const weak_ptr& r ) noexcept; | (1) | (C++11 起)
template< class Y > weak_ptr& operator=( const weak_ptr<Y>& r ) noexcept; | (2) | (C++11 起)
template< class Y > weak_ptr& operator=( const shared_ptr<Y>& r ) noexcept; | (3) | (C++11 起)
weak_ptr& operator=( weak_ptr&& r ) noexcept; | (4) | (C++11 起)
template< class Y > weak_ptr& operator=( weak_ptr<Y>&& r ) noexcept; | (5) | (C++11 起)

以 r 所管理者替换被管理对象。与 r 共享该对象。若 r 不管理对象，则 *this 亦不管理对象。

1-3) 等价于 std::weak_ptr <T>(r).swap(*this) 。
4,5) 等价于 std::weak_ptr <T>(std::move(r)).swap(*this) 。

参数

r - 与之共享对象的智能指针

返回值

*this

注解

实现可以满足要求而无需创建临时的 weak_ptr 对象。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2315 | C++11 | 移动语义未对 weak_ptr 启用 | 已启用

参阅

(构造函数) | 构造新的weak_ptr (公开成员函数)
swap | 交换被管理对象 (公开成员函数)


std::weak_ptr<T>::owner_before

< cpp‎ | memory‎ | weak ptr

template< class Y >
bool owner_before( const weak_ptr<Y>& other) const noexcept;
template< class Y >
bool owner_before( const std::shared_ptr <Y>& other) const noexcept;

以实现定义的基于拥有者（与基于值相反）顺序，检查此 weak_ptr 是否先于 other 。二个智能指针仅若都占有同一对象或均为空才比较相等，即使由 get() 获得的指针不同（例如因为它们指向同一对象中的不同子对象）。

此顺序用于令共享和弱指针可用作关联容器中的关键，通常经由 std::owner_less 。

参数

other - 要比较的 std::shared_ptr 或 std::weak_ptr

返回值

若 *this 前于 other 则为 true ，否则为 false 。常见实现比较控制块的地址。

示例

#include <iostream>
#include <memory>

struct Foo {
    int n1;
    int n2;
    Foo(int a, int b) : n1(a), n2(b) {}
};
int main()
{
    auto p1 = std::make_shared<Foo>(1, 2);
    std::shared_ptr<int> p2(p1, &p1->n1);
    std::shared_ptr<int> p3(p1, &p1->n2);

    std::cout << std::boolalpha
              << "p2 < p3 " << (p2 < p3) << '\n'
              << "p3 < p2 " << (p3 < p2) << '\n'
              << "p2.owner_before(p3) " << p2.owner_before(p3) << '\n'
              << "p3.owner_before(p2) " << p3.owner_before(p2) << '\n';

    std::weak_ptr<int> w2(p2);
    std::weak_ptr<int> w3(p3);
    std::cout
//              << "w2 < w3 " << (w2 < w3) << '\n'  // won't compile
//              << "w3 < w2 " << (w3 < w2) << '\n'  // won't compile
              << "w2.owner_before(w3) " << w2.owner_before(w3) << '\n'
              << "w3.owner_before(w2) " << w3.owner_before(w2) << '\n';

}

输出：

p2 < p3 true
p3 < p2 false
p2.owner_before(p3) false
p3.owner_before(p2) false
w2.owner_before(w3) false
w3.owner_before(w2) false

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2873 | C++11 | owner_before 可以不声明为 noexcept | 声明为 noexcept
LWG 2942 | C++11 | weak_ptr::owner_before 在 LWG 2873 的解决方案中缺少 noexcept | 令之为 noexcept

参阅

owner_less
(C++11)
 提供基于所有者的，共享指针和弱指针的混合类型的排序
(类模板)


std::weak_ptr<T>::reset

< cpp‎ | memory‎ | weak ptr
void reset() noexcept; | (C++11 起)

释放被管理对象的所有权。调用后 *this 不管理对象。

参数

（无）

返回值

（无）


std::weak_ptr<T>::swap

< cpp‎ | memory‎ | weak ptr
void swap( weak_ptr& r ) noexcept; | (C++11 起)

交换 *this 与 r 的存储指针值与所有权。不调整引用计数，若它们存在。

参数

r - 要与之交换内容的智能指针

返回值

（无）


std::swap(std::weak_ptr)

< cpp‎ | memory‎ | weak ptr

定义于头文件 <memory> |
template< class T > void swap( std::weak_ptr <T>& lhs, std::weak_ptr <T>& rhs ) noexcept; | (C++11 起)

对 std::weak_ptr 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的智能指针

返回值

（无）

复杂度

常数

参阅

swap | 交换两个对象的值 (函数模板)
swap | 交换内容 (公开成员函数)


std::weak_ptr<T>::use_count

< cpp‎ | memory‎ | weak ptr
long use_count() const noexcept; | (C++11 起)

返回共享被管理对象所有权的 shared_ptr 实例数量，或 ​0​ ，若被管理对象已被删除，即 *this 为空。

参数

（无）

返回值

在调用的瞬间共享被管理对象所有权的 shared_ptr 实例数量。

注意

expired() 可能快于 use_count() 。此函数固有地有不稳，若被管理对象在可能创建并销毁 shared_ptr 副本的线程间共享：则结果仅若匹配调用方线程所独占的副本数或零才可靠；任何其他值可能在能使用前就变得过时了。

示例

#include <iostream>
#include <memory>

std::weak_ptr<int> gwp;

void observe_gwp() {
    std::cout << "use_count(): " << gwp.use_count() << "\t id: ";
    if (auto sp = gwp.lock())
        std::cout << *sp << '\n';
    else
        std::cout << "??\n";
}

void share_recursively(std::shared_ptr<int> sp, int depth) {
    observe_gwp(); // : 2 3 4
    if (1 < depth)
        share_recursively(sp, depth - 1);
    observe_gwp(); // : 4 3 2
}

int main() {
    observe_gwp();
    {
        auto sp = std::make_shared<int>(42);
        gwp = sp;
        observe_gwp(); // : 1
        share_recursively(sp, 3); // : 2 3 4 4 3 2
        observe_gwp(); // : 1
    }
    observe_gwp(); // : 0
}

输出：

use_count(): 0   id: ??
use_count(): 1   id: 42
use_count(): 2   id: 42
use_count(): 3   id: 42
use_count(): 4   id: 42
use_count(): 4   id: 42
use_count(): 3   id: 42
use_count(): 2   id: 42
use_count(): 1   id: 42
use_count(): 0   id: ??

参阅

expired
 检查被引用的对象是否已删除
(公开成员函数)


std::weak_ptr<T>::weak_ptr

< cpp‎ | memory‎ | weak ptr
constexpr weak_ptr() noexcept; | (1) | (C++11 起)
weak_ptr( const weak_ptr& r ) noexcept; | (2) | (C++11 起)
template< class Y > weak_ptr( const weak_ptr<Y>& r ) noexcept; | (2) | (C++11 起)
template< class Y > weak_ptr( const std::shared_ptr <Y>& r ) noexcept; | (2) | (C++11 起)
weak_ptr( weak_ptr&& r ) noexcept; | (3) | (C++11 起)
template< class Y > weak_ptr( weak_ptr<Y>&& r ) noexcept; | (3) | (C++11 起)

构造新的 weak_ptr ，潜在地与 r 共享对象的。

1) 默认构造函数。构造空 weak_ptr 。
2) 构造新的 weak_ptr ，它共享 r 所管理的对象。若 r 不管理对象，则 *this 亦不管理对象。模板重载不参与重载决议，除非 Y* 可隐式转换为 T* ，或 Y 是某类型 U 和某数 N 的“ N 个 U 的数组”类型，而 T 是“（可有 cv 限定的） U 的未知边界数组”类型 (C++17 起)。
3) 移动构造函数。从 r 移动 weak_ptr 实例到 *this 。之后， r 为空且 r.use_count()==0 。模板重载不参与重载决议，除非 Y* 可隐式转换为 T* 。

参数

r - 将为此 std::weak_ptr 所查看的 std::shared_ptr 或 std::weak_ptr

注解

因为默认构造函数是 constexpr ，静态 weak_ptr 会在任何动态非局部初始化之前，作为静态非局部初始化的一部分初始化。这使得在任何静态对象的构造函数中使用 weak_ptr 是安全的。

示例

#include <memory>
#include <iostream>

struct Foo {};

int main()
{
   std::weak_ptr<Foo> w_ptr;

   {
      auto ptr = std::make_shared<Foo>();
      w_ptr = ptr;
      std::cout << "w_ptr.use_count() inside scope: " << w_ptr.use_count() << '\n';
   }

   std::cout << "w_ptr.use_count() out of scope: " << w_ptr.use_count() << '\n';
   std::cout << "w_ptr.expired() out of scope: " << std::boolalpha << w_ptr.expired() << '\n';
}

输出：

w_ptr.use_count() inside scope: 1
w_ptr.use_count() out of scope: 0
w_ptr.expired() out of scope: true

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2315 | C++11 | 移动语义未对 weak_ptr 启用 | 已启用

参阅

operator=
 为weak_ptr赋值
(公开成员函数)


std::weak_ptr<T>::~weak_ptr

< cpp‎ | memory‎ | weak ptr
~weak_ptr(); | (C++11 起)

销毁 weak_ptr 对象。对被管理对象不产生影响。


具名要求

< cpp

此页面中列出的具名要求，是 C++ 标准的规范性文本中使用的具名要求，用于定义标准库的期待。

某些具名要求在 C++20 中正在以概念语言特性进行形式化。在那之前，确保以满足这些要求的模板实参实例化标准库模板是程序员的重担。若不这么做，则可能导致非常复杂的编译器诊断。

基本概念
DefaultConstructible可默认构造
 指定该类型对象可以默认构造
(具名要求)
MoveConstructible可移动构造
(C++11)
 指定该类型对象可以从右值构造
(具名要求)
CopyConstructible可复制构造
 指定该类型对象可以从左值构造
(具名要求)
MoveAssignable可移动赋值
(C++11)
 指定该类型对象可以从右值赋值
(具名要求)
CopyAssignable可复制赋值
 指定该类型对象可以从左值赋值
(具名要求)
Destructible可析构
 指定该对象可以析构
(具名要求)

类型属性
注意，标准并未定义这个子类别中指定的各名字的具名要求。
它们是由核心语言定义的类型分类。将它们作为具名要求于此处包含只是为了一致性。
TriviallyCopyable可平凡复制
(C++11)
 拥有平凡的复制、赋值及析构函数的类
(具名要求)
TrivialType平凡类型
(C++11)
 拥有平凡的构造函数、赋值及析构函数的类
(具名要求)
StandardLayoutType标准布局类型
(C++11)
 非虚类，仅包含其他标准布局 (standard layout) 成员，且其全部具有相同的访问控制
(具名要求)
PODType简旧数据类型
 POD（简旧数据）结构体，与 C 的 struct 兼容
(具名要求)

全库范围的概念
EqualityComparable可相等比较
 operator== 是一种等价关系
(具名要求)
LessThanComparable可小于比较
 operator< 是一种严格弱序关系
(具名要求)
Swappable可交换
(C++11)
 可用无限定的非成员函数调用 swap() 进行交换的类型
(具名要求)
ValueSwappable值可交换
(C++11)
 解引用为某种可交换 (Swappable) 类型的老式迭代器 (LegacyIterator)
(具名要求)
NullablePointer可空指针
(C++11)
 支持空值的指针式类型
(具名要求)
Hash散列
(C++11)
 函数对象 (FunctionObject) ，对于不同输入值产生相同输出具有很低概率
(具名要求)
Allocator分配器
 包含分配信息的类类型
(具名要求)
FunctionObject函数对象
 能以函数调用语法进行调用的对象
(具名要求)
Callable可调用
 定义了调用操作的类型
(具名要求)
Predicate谓词
 函数对象 (FunctionObject) ，对于一个实参，返回一个可转换为 bool 的值而不改动实参
(具名要求)
BinaryPredicate二元谓词
 函数对象 (FunctionObject) ，对于两个实参，返回一个可转换为 bool 的值而不改动各实参
(具名要求)
Compare比较
 建立一种顺序关系的二元谓词 (BinaryPredicate)
(具名要求)

容器
Container容器
 允许通过迭代器访问元素的数据结构
(具名要求)
ReversibleContainer可逆容器
 使用双向迭代器的容器
(具名要求)
AllocatorAwareContainer知分配器容器
(C++11)
 使用分配器的容器
(具名要求)
SequenceContainer序列容器
 线性存储各元素的容器
(具名要求)
ContiguousContainer连续容器
(C++17)
 在相邻内存地址中存储各元素的容器
(具名要求)
AssociativeContainer关联容器
 将元素与键相关联而存储它们的容器
(具名要求)
UnorderedAssociativeContainer无序关联容器
(C++11)
 将元素与键关联并将它们存储于桶中的容器
(具名要求)
容器元素
DefaultInsertable可默认插入
(C++11)
 可在未初始化存储中默认构造的元素
(具名要求)
CopyInsertable可复制插入
(C++11)
 可在未初始化存储中复制构造的元素
(具名要求)
MoveInsertable可移动插入
(C++11)
 可在未初始化存储中移动构造的函数
(具名要求)
EmplaceConstructible可就位构造
(C++11)
 可在未初始化存储中构造的元素
(具名要求)
Erasable可擦除
(C++11)
 可用分配器销毁的元素
(具名要求)

迭代器
LegacyIterator老式迭代器
 在一些数据结构内访问数据的通用概念
(具名要求)
LegacyInputIterator老式输入迭代器
 可用于读数据的迭代器
(具名要求)
LegacyOutputIterator老式输出迭代器
 可用于写数据的迭代器
(具名要求)
LegacyForwardIterator老式向前迭代器
 可用于多次读数据的迭代器
(具名要求)
LegacyBidirectionalIterator老式双向迭代器
 可增可减的迭代器
(具名要求)
LegacyRandomAccessIterator老式随机访问迭代器
 可在常数时间内增加的迭代器
(具名要求)
LegacyContiguousIterator老式连续迭代器
(C++17)
 指向连续分配元素的迭代器
(具名要求)
ConstexprIterator常量表达式迭代器
(C++20)
 能在常量表达式求值中使用的迭代器
(具名要求)

流 I/O 函数
UnformattedInputFunction无格式输入函数
 不跳过前导空格并对处理字符计数的流输入函数
(具名要求)
FormattedInputFunction有格式输入函数
 跳过前导空格的流输入函数
(具名要求)
UnformattedOutputFunction无格式输出函数
 基本流输出函数
(具名要求)
FormattedOutputFunction有格式输出函数
 出错时设置失败位并返回流引用的流输出函数
(具名要求)

随机数生成
SeedSequence种子序列
(C++11)
 消耗一个整数序列，产出一个 32 位无符号值的序列
(具名要求)
UniformRandomBitGenerator均匀随机位生成器
(C++11)
 返回均匀分布的随机无符号整数
(具名要求)
RandomNumberEngine随机数引擎
(C++11)
 由种子定义的确定性均匀随机位生成器 (UniformRandomBitGenerator)
(具名要求)
RandomNumberEngineAdaptor随机数引擎适配器
(C++11)
 对另一个随机数引擎 (RandomNumberEngine) 的输出进行变换的随机数引擎 (RandomNumberEngine)
(具名要求)
RandomNumberDistribution随机数分布
(C++11)
 返回服从给定数学概率密度函数分布的随机数
(具名要求)

并发
BasicLockable基本可锁定
(C++11)
 为执行代理（即线程）提供排他所有权语义
(具名要求)
Lockable可锁定
(C++11)
 支持尝试进行锁获取基本可锁定 (BasicLockable)
(具名要求)
TimedLockable可定时锁定
(C++11)
 支持定时锁获取的可锁定 (Lockable)
(具名要求)
SharedLockable可共享锁定
(C++14)
 为执行代理（即线程）提供共享所有权语义
(具名要求)
SharedTimedLockable可共享定时锁定
(C++14)
 支持定时锁获取的可共享锁定 (SharedLockable)
(具名要求)
Mutex互斥体
(C++11)
 提供免受数据竞争的保护和顺序一致同步操作的可锁定 (Lockable)
(具名要求)
TimedMutex定时互斥体
(C++11)
 提供免受数据竞争的保护和顺序一致同步操作的可定时锁定 (TimedLockable)
(具名要求)
SharedMutex共享互斥体
(C++17)
 支持共享所有权语义的互斥体 (Mutex)
(具名要求)
SharedTimedMutex共享定时互斥体
(C++14)
 支持共享所有权语义的定时互斥体 (TimedMutex)
(具名要求)

其他
UnaryTypeTrait一元类型特征
(C++11)
 描述一个类型的一项性质
(具名要求)
BinaryTypeTrait二元类型特征
(C++11)
 描述两个类型间的一种关系
(具名要求)
TransformationTrait变换特征
(C++11)
 修改一个类型的一项性质
(具名要求)
Clock时钟
(C++11)
 聚合一种时长，一种时间点，和一个获取当前时间点的函数
(具名要求)
TrivialClock平凡时钟
(C++11)
 不抛异常的时钟 (Clock)
(具名要求)
CharTraits字符特征
 为字符类型定义一些类型和函数
(具名要求)
BitmaskType位掩码类型
 位集合、整数或枚举
(具名要求)
NumericType数值类型
 初始化效率相当于赋值的类型
(具名要求)
RegexTraits正则表达式特征
(C++11)
 定义正则表达式库所使用的各个类型和函数
(具名要求)
LiteralType字面类型
(C++11)
 拥有 constexpr 构造函数的类型
(具名要求)
Formatter格式化器
(C++20)
 定义用于格式化库的函数
(具名要求)
本节未完成
原因：任何其他遗漏的具名要求？


C++ 具名要求：分配器 (Allocator)

< cpp‎ | named req

封装访问/寻址，分配/解分配，以及对象的构造/析构的策略。

可能需要分配或释放内存的每个标准库组件，从 std::string、std::vector 和除 std::array 以外的所有容器，到 std::shared_ptr 和 std::function，都通过分配器 (Allocator) 进行这些操作：分配器是满足下列要求的类类型对象。

许多分配器要求的实现是可选的，因为所有知分配器类，包括标准库容器，都通过 std::allocator_traits 访问分配器，而 std::allocator_traits 提供这些要求的默认实现。

要求

给定

  • T ，无 cv 限定的对象类型
  • A ， T 类型的分配器 (Allocator) 类型
  • a ， A 类型对象
  • B ，某无 cv 限定的对象类型 U 的对应分配器 (Allocator) 类型（由重绑定 A 获得）
  • b ， B 类型对象
  • p ， allocator_traits<A>::pointer 类型值，由调用 allocator_traits<A>::allocate() 获得
  • cp ， allocator_traits<A>::const_pointer 类型值，由从 p 转换获得
  • vp ， allocator_traits<A>::void_pointer 类型值，由从 p 转换获得
  • cvp ， allocator_traits<A>::const_void_pointer 类型值，由从 cp 或从 vp 转换获得
  • xp ，指向某无 cv 限定类型 X 的可解引用的指针
  • r ，由表达式 *p 获得的 T 类型左值
  • n ， allocator_traits<A>::size_type 类型值
内部类型
类型标识 | 别名使用的类型 | 要求
A::pointer (可选) （未指明）[1]
  • 满足可空指针 (NullablePointer) 、老式随机访问迭代器 (LegacyRandomAccessIterator) 及老式连续迭代器 (LegacyContiguousIterator) 。
A::const_pointer (可选) （未指明）
  • 满足可空指针 (NullablePointer) 、老式随机访问迭代器 (LegacyRandomAccessIterator) 及老式连续迭代器 (LegacyContiguousIterator) 。
  • A::pointer 可转换为 A::const_pointer 。
A::void_pointer (可选) （未指明）
  • 满足可空指针 (NullablePointer) 。
  • A::pointer 可转换为 A::void_pointer 。
  • B::void_pointer 与 A::void_pointer 为同一类型。
A::const_void_pointer (可选) （未指明）
  • 满足可空指针 (NullablePointer) 。
  • A::pointer 、 A::const_pointer 与 A::void_pointer 可转换为 A::const_void_pointer 。
  • B::const_void_pointer 与 A::const_void_pointer 为同一类型。
A::value_type | T
A::size_type (可选) （未指明）
  • 无符号整数类型。
  • 能表示 A 所能分配的最大对象的大小。
A::difference_type (可选) （未指明）
  • 有符号整数类型。
  • 能表示任何二个指向 A 所分配的对象的指针的差
A::template rebind<U>::other
(可选)[2] 		B
  • 对于任何 U ， B::template rebind<T>::other 为 A 。

指针上的操作
表达式 | 返回类型 | 要求
*p | T& |
*cp | const T& | *cp 与 *p 标识同一对象。
p->m | （原状） | 同 (*p).m ，若 (*p).m 良定义。
cp->m | （原状） | 同 (*cp).m ，若 (*cp).m 良定义
static_cast<A::pointer>(vp) | （原状） | static_cast<A::pointer>(vp) == p
static_cast<A::const_pointer>(cvp) | （原状） | static_cast<A::const_pointer>(cvp) == cp
std::pointer_traits <A::pointer>::pointer_to(r) | （原状） |
存储与生存期操作
表达式 | 返回类型 | 要求
a.allocate(n) | A::pointer | 分配适合一个 T[n] 类型数组对象的存储并创建该数组，但不构造数组元素。可以抛异常。
a.allocate(n, cvp) (可选) | 同 a.allocate(n) ，但可能以未指定的方式使用 cvp （ nullptr 或从 a.allocate() 获得的指针）以辅助局部性。
a.allocate_at_least(n) (可选) (C++23 起) std::allocation_result<

A::pointer>

 分配适合一个 T[cnt] 类型数组对象的存储并创建该数组，但不构造数组元素，然后返回 {p, cnt} ，其中 p 指向存储而 cnt 不小于 n 。可以抛异常。
a.deallocate(p, n) | （不使用） | 解分配 p 所指向的存储，该值必须由之前调用 allocate 或 allocate_at_least (C++23 起) 返回且未被中间对 deallocate 的调用非法化。 n 必须匹配先前传给 allocate 的值或在经由 allocate_at_last 请求和返回的元素数之间（可以等于任一边界） (C++23 起)。不抛异常。
a.max_size() (可选) | A::size_type | 能传递给 A::allocate() 的最大值。
a.construct(xp, args) (可选) | （不使用） | 于先前分配的 xp 所指向的存储构造 X 类型对象，以 args 为构造函数参数。
a.destroy(xp) (可选) | （不使用） | 销毁 xp 所指向的 X 类型对象，但不解分配存储。
实例间的关系
表达式 | 返回类型 | 要求
a1 == a2 bool
  • 仅若由分配器 a1 分配的存储能通过 a2 解分配才为 true 。
  • 建立自反、对称和传递关系。
  • 不抛异常。
a1 != a2
  • 同 !(a1==a2) 。
声明 | 效果 | 要求
A a1(a) 复制构造 a1 使得 a1 == a 。
（注：每个分配器 (Allocator) 亦满足可复制构造 (CopyConstructible) 。）
  • 不抛异常。
A a1 = a
A a(b) 构造 a 使得 B(a)==b 且 A(b)==a 。
（这隐含所有由 rebind 联系的分配器均维护彼此的资源，例如内存池。）
  • 不抛异常。
A a1(std::move(a)) 构造 a1 使得它等于先前 a 的值。
  • 不抛异常。
  • 不更改 a 的值且 a1 == a 。
A a1 = std::move(a)
A a(std::move(b)) 构造 a 使得它等于先前 A(b) 的值。
  • 不抛异常。
类型标识 | 别名使用的类型 | 要求
A::is_always_equal
(可选) (C++17 起) 		std::true_type 或 std::false_type 或从它们派生。
  • 若二个 A 类型分配器始终比较相等则为 true 。
  • （若不提供，则 std::allocator_traits 默认它为 std::is_empty <A>::type 。）
容器操作上的影响
表达式 | 返回类型 | 描述
a.select_on_container_copy_construction()
(可选) 		A
  • 提供从当前使用 a 的容器复制构造容器所用的 A 的实例。
  • （通常返回 a 的副本或默认构造的 A 。）
类型标识 | 别名使用的类型 | 描述
A::propagate_on_container_copy_assignment
(可选) 		std::true_type 或 std::false_type 或从它们派生。
  • 若复制赋值使用 A 类型分配器的容器时需要复制它则为 std::true_type 或其派生类。
  • 若此成员为 std::true_type 或从它派生，则 A 必须满足可复制赋值 (CopyAssignable) 且复制操作必须不抛异常。
  • 注意若源与目标容器的分配器不比较相等，则复制赋值必须用旧分配器解分配目标的内存，然后在复制元素（和分配器）前用新分配器分配内存。
A::propagate_on_container_move_assignment
(可选)
  • 若移动赋值使用 A 类型分配器的容器时需要移动它则为 std::true_type 或其派生类。
  • 若此成员为 std::true_type 或从它派生，则 A 必须满足可移动赋值 (MoveAssignable) 且移动操作必须不抛异常。
  • 若不提供此成员或它从 std::false_type 派生，而源与目标容器的分配器不比较相等，则移动赋值不能取得源内存的所有权，并且必须单独地复制赋值或复制构造元素，按需重置其自身内存的大小。
A::propagate_on_container_swap
(可选)
  • 若交换二个使用 A 类型分配器的容器时需要移动它们则为 std::true_type 或其派生类。
  • 若此成员为 std::true_type 或从它派生，则 A 的左值必须为可交换 (Swappable) 且交换操作必须不抛异常。
  • 若不提供此成员或它从 std::false_type 派生，且二个容器的分配器不比较相等，则容器交换的行为未定义。

注：

  1. ↑ 参阅后述缀饰指针。
  2. ↑ rebind 仅若分配器是形式为 SomeAllocator<T, Args> 的模板，其中 Args 是零或更多个额外的类型模板形参才为可选（由 std::allocator_traits 提供）。

给定

  • x1 与 x2 ，（可能不同）类型 X::void_pointer 、 X::const_void_pointer 、 X::pointer 或 X::const_pointer 的对象。

则 x1 与 x2 为等价值的指针值，当且仅当 x1 与 x2 能用 static_cast ，仅使用这四个类型的序列显式转换成二个对应的 X::const_pointer 类型对象 px1 与 px2 ，而表达式 px1 == px2 求值为 true 。

给定

  • w1 与 w2 ， X::void_pointer 类型对象。

则对于表达式 w1 == w2 与 w1 != w2 ，可将一个或两个对象替换成等价值的 X::const_void_pointer 类型对象而无语义更改。

给定

  • p1 与 p2 ， X::pointer 类型对象

则对于表达式 p1 == p2 、 p1 != p2 、 p1 < p2 、 p1 <= p2 、 p1 >= p2 、 p1 > p2 、 p1 - p2 ，可将一个或两个对象替换成等价值的 X::const_pointer 类型对象而无语义更改。

以上要求使得能比较容器 (Container) 的 iterator 与 const_iterator 。

分配器完整性要求

若无论 T 是否为完整类型下列二者皆为真，则针对类型 T 的分配器类型 X 还额外满足分配器完整性要求：

  • X 是完整类型
  • 除 value_type 之外，所有 std::allocator_traits <X> 的成员都是完整类型。
 (C++17 起)

有状态与无状态分配器

每个分配器 (Allocator) 类型要么是有状态要么是无状态。通常来说，有状态分配器类型能拥有代表有别的内存资源的不相等值，而无状态分配器类型代表单一内存资源。

尽管不要求自定义分配器为无状态，标准库中是否及如何支持分配器是实现定义的。若实现不支持使用不相等的分配器值，则这种使用可能导致实现定义的运行时错误或未定义行为。 | (C++11 前)
定制分配器可含有状态。每个容器或另一知分配器对象存储提供的分配器的实例并通过 std::allocator_traits 控制分配器替换。 | (C++11 起)

无状态分配器类型的实例始终比较相等。无状态分配器类型常实现为空类并适合空基类优化。

std::allocator_traits 的成员类型 is_always_equal 有意用于确定分配器类型是否为无状态。

 (C++17 起)

缀饰指针

当成员类型 pointer 不是原生指针时，它通常被称为“缀饰指针（fancy pointer）”。这种指针曾为支持分段内存架构而引入，并在当今用于访问在某些不同于原生指针所访问的同质虚拟地址空间的地址空间中所分配的对象。缀饰指针的一个实例是映射的不依赖地址指针 boost::interprocess::offset_ptr，它使得在共享内存和在每个进程中映射到不同地址的映射到内存文件中，分配 std::set 一类的基于结点的数据结构可行。通过类模板 std::pointer_traits ， (C++11 起)可以独立于提供缀饰指针的分配器而使用它们。能用函数 std::to_address 从缀饰指针获得裸指针。 (C++20 起)

在标准库中使用缀饰指针和定制的大小/差类型是条件性支持的。实现可以要求成员类型 pointer 、 const_pointer 、 size_type 和 difference_type 分别为 value_type* 、 const value_type* 、 std::size_t 和 std::ptrdiff_t 。

 (C++11 前)

标准库

下列标准库组件满足分配器 (Allocator) 要求：

allocator | 默认的分配器 (类模板)
scoped_allocator_adaptor (C++11) | 为多级容器实现的多级分配器 (类模板)
polymorphic_allocator (C++17) | 以 std::memory_resource 构造，支持基于它的运行时多态的分配器 (类模板)

示例

一个 C++11 分配器，但添加了 [[nodiscard]] 以符合 C++20 风格。

#include <cstdlib>
#include <new>
#include <limits>
#include <iostream>
#include <vector>

template <class T>
struct Mallocator
{
  typedef T value_type;

  Mallocator () = default;
  template <class U> constexpr Mallocator (const Mallocator <U>&) noexcept {}

  [[nodiscard]] T* allocate(std::size_t n) {
    if (n > std::numeric_limits<std::size_t>::max() / sizeof(T))
      throw std::bad_array_new_length{};

    if (auto p = static_cast<T*>(std::malloc(n*sizeof(T)))) {
      report(p, n);
      return p;
    }

    throw std::bad_alloc{};
  }

  void deallocate(T* p, std::size_t n) noexcept {
    report(p, n, 0);
    std::free(p);
  }

private:
  void report(T* p, std::size_t n, bool alloc = true) const {
    std::cout << (alloc ? "Alloc: " : "Dealloc: ") << sizeof(T)*n
      << " bytes at " << std::hex << std::showbase
      << reinterpret_cast<void*>(p) << std::dec << '\n';
  }
};

template <class T, class U>
bool operator==(const Mallocator <T>&, const Mallocator <U>&) { return true; }
template <class T, class U>
bool operator!=(const Mallocator <T>&, const Mallocator <U>&) { return false; }

int main()
{
  std::vector<int, Mallocator<int>> v(8);
  v.push_back(42);
}

可能的输出：

Alloc: 32 bytes at 0x2020c20
Alloc: 64 bytes at 0x2023c60
Dealloc: 32 bytes at 0x2020c20
Dealloc: 64 bytes at 0x2023c60

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 179 | C++98 | 未要求 pointer 与 const_pointer 可相互比较 | 已要求
P0593R6 | C++98 | 未要求 allocate 在其所分配的存储中创建数组 | 已要求
LWG 2016 | C++11 | 分配器的复制、移动与交换操作在使用时可能抛出 | 要求不抛出
LWG 2263 | C++11 | LWG179 的解决方案在 C++11 中意外丢失 且未被推广到 void_pointer 与 const_void_pointer | 恢复并推广
LWG 2593 | C++11 | 从分配器移动可能修改其值 | 禁止修改


C++ 具名要求：知分配器容器 (AllocatorAwareContainer)

< cpp‎ | named req

知分配器容器 (AllocatorAwareContainer) 是容器 (Container) ，其保有一个分配器 (Allocator) 实例，并于其所有成员函数中用该实例来分配及解分配内存，并于这个内存中构造及销毁对象的（这种对象可以是容器元素，结点，或对于无序容器为桶数组），除了 std::basic_string 特化不用分配器构造/析构其元素 (C++23 起)。

下列规则适用于容器的构造

  • 知分配器容器 (AllocatorAwareContainer) 的复制构造函数，通过在正在复制的容器的分配器上调用 std::allocator_traits <allocator_type>::select_on_container_copy_construction 获得自己的分配器实例。
  • 移动构造函数通过从属于旧容器的分配器进行移动构造，获得其自己的分配器实例。
  • 所有其他构造函数均接收一个 const allocator_type& 形参。

仅有的替换分配器的方式是进行移动赋值、复制赋值及交换：

  • 仅当 std::allocator_traits <allocator_type>::propagate_on_container_copy_assignment::value 为 true 时，复制赋值才会替换分配器
  • 仅当 std::allocator_traits <allocator_type>::propagate_on_container_move_assignment::value 为 true 时，移动赋值才会替换分配器
  • 仅当 std::allocator_traits <allocator_type>::propagate_on_container_swap::value 为 true 时，交换才会替换分配器。特别是它将通过对非成员函数 swap 的无限定的调用来交换分配器实例，见可交换 (Swappable) 。

注：若 propagate_on_container_swap 为 false，则交换两个拥有不相等分配器的容器是未定义行为。

  • 访问器 get_allocator() 获得构造容器时所用的，或为最近的分配器替换操作所安装的分配器的一个副本。

要求

凡例

X | 容器类型
T | 元素类型
A | T 的分配器
a, b | X 类型的对象（非 const 左值）
t | X 类型的对象（左值或 const 右值）
rv | X 类型的对象（非 const 右值）
m | A 类型的对象
Q | 分配器类型
表达式 | 返回类型 | 前提/要求 | 后置/效应 | 复杂度
allocator_type | A | allocator_type::value_type 必须与 X::value_type 相同 |  | 编译时
get_allocator() | A |  |  | 常数
X u; |  | A 可默认构造 (DefaultConstructible) | u.empty() == true && u.get_allocator() == A() | 常数
X u(m); |  |  | u.empty() == true && u.get_allocator() == m | 常数
X u(t,m); |  | T 可复制插入 (CopyInsertable) 到 X | u == t && u.get_allocator() == m | 线性
X u(rv); |  | A 的移动构造函数必须不抛异常 | u 拥有与 rv 构造前相同的元素和相等的分配器 | 常数
X u(rv,m); |  | T 可移动插入 (MoveInsertable) 到 X | u 的元素与 rv 的相同或是其副本，且 u.get_allocator() == m | 若 m == rv.get_allocator() 则为常数，否则为线性
a = t | X& | T 可复制插入 (CopyInsertable) 到 X 且可复制赋值 (CopyAssignable) | a == t | 线性
a = rv | X& | 若分配器将不被移动赋值所替换（见上文），则 T 可移动插入 (MoveInsertable) 到 X 并可移动赋值 (MoveAssignable) | a 的所有既存元素被移动赋值或销毁；若 a 与 rv 不指代同一对象则 a 等于 rv 赋值前所拥有的值 | 线性
a.swap(b) | void |  | 交换 a 与 b 的内容 | 常数

注解

具分配器容器始终调用 std::allocator_traits <A>::construct(m, p, args) 在 p 中用 args 来构造一个 A 类型的对象，其中 m == get_allocator()。std::allocator 中默认的 construct 调用 ::new((void*)p) T(args) (C++20 前)std::allocator 无 construct 成员，而在构造元素时 std::construct_at(p, args) 得到调用 (C++20 起)，但特化的分配器可以选择不同的定义。

标准库

所有标准库容器，除了 std::array，都是知分配器容器 (AllocatorAwareContainer) ：

  • std::basic_string
  • std::deque
  • std::forward_list
  • std::list
  • std::vector
  • std::map
  • std::multimap
  • std::set
  • std::multiset
  • std::unordered_map
  • std::unordered_multimap
  • std::unordered_set
  • std::unordered_multiset

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2839 | C++11 | 不允许标准容器的自移动赋值 | 容许但结果未指定


C++ 具名要求：关联容器 (AssociativeContainer)

< cpp‎ | named req

关联容器 (AssociativeContainer) 是提供基于键的快速对象查找的容器 (Container) 。

要求

凡例
X | 容器类型
a | X 类型的值
a2 | 其结点句柄与 X 兼容的 Y 类型的值
b | X 类型的可能为 const 的值
u | 任意变量名
a_uniq | （当 X 支持唯一键时）X 类型的值
a_eq | （当 X 支持多重键时）X 类型的值
a_tran | （当 X::key_compare::is_transparent 存在时）X 类型的可能为 const 的值
i, j | 老式输入迭代器 (LegacyInputIterator) ，指代有效范围并指向可隐式转换到 X::value_type 的元素
p | 指向 a 的有效常迭代器
q | 指向 a 的有效可解引用常量迭代器
r | 指向 a 的可解引用迭代器
q1, q2 | 指代 a 中的有效范围的常迭代器
il | std::initializer_list<X::value_type> 类型的对象
t | X::value_type 类型的值
k | X::key_type 类型的值
c | X::key_compare 类型的可以为 const 的值
kl | 一个值，使得 a 依据 c(r,kl) 已划分，其中 r 是 e 的键且 e 在 a 中
ku | 一个值，使得 a 依据 !c(ku, r) 已划分
ke | 一个值，使得 a 依据 c(r, ke) 与 !c(ke, r) 已划分，其中 c(r, ke) 隐含 !c(ke, r)
A | X 所用的存储分配器，或 std::allocator_type<X::value_type>
m | 分配器，其类型可转换为 A
nh | X::node_type 类型的非 const 右值
表达式 | 返回类型 | 前条件/要求 | 后条件/效果 | 复杂度
X::key_type | Key | Key 可析构 (Destructible) | 编译时
X::key_compare | Compare | 编译时
X::value_compare 满足二元谓词 (BinaryPredicate) 的类型 对于 std::set 和 std::multiset 为 key_compare；
对于 std::map 和 std::multimap 为 Key 上的顺序关系 		编译时
X(c), X a(c); | key_compare 可复制构造 (CopyConstructible) | 以 c 的副本为 key_comp 构造空容器 | 常数
X(), X a; | key_compare 可复制构造 (CopyConstructible) | 以 Compare() 为 key_comp 构造空容器 | 常数
X(i, j, c), X a(i, j, c); | key_compare 可复制构造 (CopyConstructible) 且 value_type 从 *i 可就位构造 (EmplaceConstructible) 到 X | 以 c 的副本为 key_comp 构造空容器并插入来自范围 [i; j) 的所有元素 | 通常为 N log N，或若 [i, j) 已排序则为 N（其中 N 是 std::distance (i, j)）
X(i, j), X a(i, j); | key_compare 可复制构造 (CopyConstructible) 且 value_type 从 *i 可就位构造 (EmplaceConstructible) 到 X | 以 Compare() 为 key_comp 构造空容器并插入来自范围 [i; j) 的所有元素 | 通常为 N log N，或若 [i, j) 已按照 value_comp() 排序则为 N（其中 N 是 std::distance (i, j)）
X(il); | 等价于 X(il.begin(), il.end()); | 等价于 X(il.begin(), il.end());
a = il | X& | T 可复制插入 (CopyInsertable) 到 X 而且亦可复制赋值 (CopyAssignable) | 将范围 [il.begin(), il.end()) 赋值到 a。 a 的未被赋值元素均被销毁 | 通常为 N log N，或若 [il.begin(), il.end()) 已按照 value_comp() 排序则为 N（其中 N 是 il.size() + a.size()）
a.key_comp() | X::key_compare | 返回构造 a 所用的比较对象。 | 常数
a.value_comp() | X::value_compare | 返回在比较对象外构造的 X::value_compare 类型的对象。 | 常数

作为 std::map 或 std::multimap 的关联容器 X 额外支持表达式 X::mapped_type，它以 T 为返回的类型（但要求 T 可析构 (Destructible) ），及编译时复杂度。

本节未完成
原因：完成要求。

标准库中的关联容器

set | 唯一键的集合，按照键排序 (类模板)
multiset | 键的集合，按照键排序 (类模板)
map | 键值对的集合，按照键排序，键是唯一的 (类模板)
multimap | 键值对的集合，按照键排序 (类模板)


C++ 具名要求：基本可锁定 (BasicLockable)

< cpp‎ | named req

基本可锁定 (BasicLockable) 要求描述提供为执行代理（即线程）提供排他性阻塞语义的类型的最小特征。

要求

对于要为基本可锁定 (BasicLockable) 的类型 L ， L 类型对象 m 必须满足下列条件：

表达式 | 前条件 | 效果
m.lock() |  | 阻塞到能为当前执行代理（线程、进程、任务）取得锁为止。若抛异常，则不取得锁。
m.unlock() | 当前执行代理在 m 上保有非共享锁。 | 释放执行代理曾保有的非共享锁。不抛异常。

非共享锁

若对象上的一个锁由调用 lock、 try_lock、 try_lock_for 或 try_lock_until 成员函数取得，则称之为非共享锁。

参阅

  • 线程支持库
  • 互斥体 (Mutex)
  • 可锁定 (Lockable)
  • 可定时锁定 (TimedLockable)


C++ 具名要求：老式双向迭代器 (LegacyBidirectionalIterator)

< cpp‎ | named req

老式双向迭代器 (LegacyBidirectionalIterator) 是能双向移动（即自增与自减）的老式向前迭代器 (LegacyForwardIterator) 。

要求

以下情况下，类型 It 满足 老式双向迭代器 (LegacyBidirectionalIterator)

  • 类型 It 满足老式向前迭代器 (LegacyForwardIterator)

且，给定

  • a 与 b，为类型 It 的迭代器
  • reference，为 std::iterator_traits<It>::reference 所指代的类型

则下列表达式必须合法并拥有其效果

表达式 | 返回 | 等价表达式 | 注意
--a It& 前提条件：
  • a 可自减（存在满足 a == ++b 的 b）

后条件：

  • a 可解引用
  • --(++a) == a
  • 若 --a == --b 则 a == b
  • a 与 --a 指代同一迭代器对象
a-- 可转换到 const It& It temp = a;

--a;

return temp;
*a-- | reference

可变（mutable）老式双向迭代器 (LegacyBidirectionalIterator) 是还额外满足老式输出迭代器 (LegacyOutputIterator) 要求的老式双向迭代器 (LegacyBidirectionalIterator) 。

注解

起始迭代器不可自减。且若求值 --container.begin() 则行为未定义。

双向迭代器不必可解引用、可自减（尤其是尾迭代器不可解引用但可自减）。

概念

为了定义 std::iterator_traits，定义了以下仅用于阐释的概念：

template<class I>

concept __LegacyBidirectionalIterator =
__LegacyForwardIterator<I> && requires(I i) {
{ --i } -> std::same_as<I&>;
{ i-- } -> std::convertible_to<const I&>;
{ *i-- } -> std::same_as<std::iter_reference_t<I>>;

};

其中仅用于阐释的概念 __LegacyForwardIterator 描述于 LegacyForwardIterator#概念。

 (C++20 起)

参阅

bidirectional_iterator (C++20) | 指定 forward_iterator 为双向迭代器，支持向后移动 (概念)
迭代器库 | 提供迭代器的定义、迭代器表征、适配器及工具函数


C++ 具名要求：二元谓词 (BinaryPredicate)

< cpp‎ | named req

二元谓词 (BinaryPredicate) 是一些标准库设施针对用户提供的实参所期待的一组要求。

给定二元谓词 (BinaryPredicate) bin_pred 和一对迭代器 iter1 与 iter2 或一个迭代器 iter 与值 value，表达式 bin_pred(*iter1, *iter2) 或 bin_pred(*iter, value) 必须可按语境转换为 bool。

另外，不允许表达式的求值调用解引用迭代器的非 const 成员函数。

要求

  • 谓词 (Predicate)
  • 可复制构造 (CopyConstructible) （除非另行指明）

标准库

下列标准库设施期待并非比较 (Compare) 类型的二元谓词 (BinaryPredicate) 。

unique (C++11) | 删除连续的重复元素 (std::forward_list<T,Allocator> 的公开成员函数)
unique | 删除连续的重复元素 (std::list<T,Allocator> 的公开成员函数)
find_end | 在特定范围中寻找最后出现的元素序列 (函数模板)
find_first_of | 搜索元素集合中的任意元素 (函数模板)
adjacent_find | 查找首对相邻的相同（或满足给定谓词的）元素 (函数模板)
mismatch | 寻找两个范围出现不同的首个位置 (函数模板)
equal | 确定两个元素集合是否是相同的 (函数模板)
is_permutation (C++11) | 判断一个序列是否为另一个序列的排列 (函数模板)
search | 搜索一个元素范围 (函数模板)
search_n | 在范围中搜索一定量的某个元素的连续副本 (函数模板)
unique | 移除范围内的连续重复元素 (函数模板)
unique_copy | 创建某范围的不含连续重复元素的副本 (函数模板)
not2 (C++17 中弃用)(C++20 中移除) | 构造定制的 std::binary_negate 对象 (函数模板)
unordered_set (C++11 起) | 唯一键的集合，按照键生成散列 (类模板)
unordered_map (C++11 起) | 键值对的集合，按照键生成散列，键是唯一的 (类模板)
unordered_multiset (C++11 起) | 键的集合，按照键生成散列 (类模板)
unordered_multimap (C++11 起) | 键值对的集合，按照键生成散列 (类模板)


C++ 具名要求：二元类型特征 (BinaryTypeTrait)

< cpp‎ | named req

二元类型特征 (BinaryTypeTrait) 是类模板，以一个 intergral_constant （典型地为 bool_constant ） 特化描述其二个模板类型形参间的关系。

要求

  • 可默认构造 (DefaultConstructible) 并可复制构造 (CopyConstructible)
  • 接收二个模板类型形参（允许可选的额外模板形参）
  • 公开且无歧义地从被称为其基特征（ base characteristic ）的 intergral_constant 特化派生
  • 基特征的成员名未被隐藏，且无歧义地可用

标准库

下列标准库类模板满足二元类型特征 (BinaryTypeTrait) 。

is_same (C++11) | 检查两个类型是否相同 (类模板)
is_base_of (C++11) | 检查一个类型是否派生自另一个类型 (类模板)
is_convertibleis_nothrow_convertible (C++11)(C++20) | 检查是否能转换一个类型为另一类型 (类模板)
is_invocableis_invocable_ris_nothrow_invocableis_nothrow_invocable_r (C++17) | 检查类型能否以给定的实参类型调用（如同以 std::invoke） (类模板)
uses_allocator (C++11) | 检查指定的类型是否支持使用分配器的构造 (类模板)


C++ 具名要求：位掩码类型 (BitmaskType)

< cpp‎ | named req

定义能用来表示一组常量值或这些值的任何组合的类型。此类型常以整数类型、 std::bitset 、或带附加运算符重载的枚举（有作用域和无作用域）实现。

要求

位掩码类型支持有限数量的位掩码元素，它们拥有各不相同的位掩码类型的非零值，满足对于任意对 Ci 与 Cj ， Ci & Ci 非零而 Ci & Cj 为零。另外，值 0 用于表示空位掩码，而无值集合。

逐位运算符 operator& 、 operator| 、 operator^ 、 operator~ 、 operator&= 、 operator|= 及 operator^= 对位掩码类型的值定义，且拥有无符号整数上会有的对应内建运算符的相同语义，若位掩码元素为相异的二的幂。

对任何位掩码类型 (BitmaskType) ，下列表达式为良构且拥有下列含义

X |= Y | 在对象 X 中设置值 Y
X &= ~Y | 在对象 X 中清除值 Y
X & Y | 非零结果指示已于对象 X 设置值 Y

每个可表示的位掩码元素定义为位掩码类型的 inline (C++17 起)constexpr 值。

用法

下列标准库类型满足位掩码类型 (BitmaskType) ：

  • std::ctype_base::mask
  • std::ios_base::fmtflags
  • std::ios_base::iostate
  • std::ios_base::openmode
  • std::regex_traits::char_class_type (C++11 起)
  • std::regex_constants::syntax_option_type (C++11 起)
  • std::regex_constants::match_flag_type (C++11 起)
  • std::launch (C++11 起)
  • std::filesystem::perms (C++17 起)
  • std::filesystem::copy_options (C++17 起)
  • std::filesystem::directory_options (C++17 起)

依赖某些特定实现选项的代码（例如 int n = std::ios_base::hex ）是不可移植的，因为 std::ios_base::fmtflags 不需要可隐式转换为 int 。


C++ 具名要求：可调用 (Callable)

< cpp‎ | named req

可调用 (Callable) 类型是可应用 INVOKE 操作（例如用于 std::function、std::bind 和 std::thread::thread）的类型。可以用库函数 std::invoke 显式进行此操作。 (C++17 起)

要求

若满足下列条件，则类型 T 满足可调用 (Callable)

给定

  • T 类型的对象 f
  • 适合的实参类型列表 ArgTypes
  • 适合的返回类型 R

则下列表达式必须合法：

表达式 | 要求
INVOKE<R>(f, std::declval <ArgTypes>()...) | 该表达式在不求值语境中良构

其中 INVOKE<R>(f, t1, t2, ..., tN)，若 R 是可有 cv 限定的 void，则定义为 static_cast<void>(INVOKE(f, t1, t2, ..., tN))，否则为 INVOKE(f, t1, t2, ..., tN)，隐式转换成 R

其中 INVOKE(f, t1, t2, ..., tN) 定义如下：

  • 若 f 是类 T 的成员函数指针：
  • 若 std::is_base_of <T, std::remove_reference_t <decltype(t1)>>::value 为 true，则 INVOKE(f, t1, t2, ..., tN) 等价于 (t1.*f)(t2, ..., tN)
  • 否则，若 std::remove_cvref_t<decltype(t1)> 为 std::reference_wrapper 的特化，则 INVOKE(f, t1, t2, ..., tN) 等价于 (t1.get().*f)(t2, ..., tN)
  • 否则，若 t1 不满足前述条件，则 INVOKE(f, t1, t2, ..., tN) 等价于 ((*t1).*f)(t2, ..., tN)。
  • 否则，若 N == 1 且 f 是类 T 的数据成员指针：
  • 若 std::is_base_of <T, std::remove_reference_t <decltype(t1)>>::value 为 true，则 INVOKE(f, t1) 等价于 t1.*f
  • 否则，若 std::remove_cvref_t<decltype(t1)> 是 std::reference_wrapper 的特化，则 INVOKE(f, t1) 等价于 t1.get().*f
  • 否则，若 t1 不满足前述条件，则 INVOKE(f, t1) 等价于 (*t1).*f
  • 否则，INVOKE(f, t1, t2, ..., tN) 等价于 f(t1, t2, ..., tN)（即 f 是一个函数对象 (FunctionObject) ）

注解

对于成员函数指针和数据成员指针，t1 可以是一个常规指针或一个重载了 operator* 的类的对象，例如 std::unique_ptr 或 std::shared_ptr。

数据成员指针为可调用 (Callable) ，尽管并不发生函数调用。

标准库

此外，下列标准库设施接受任何可调用 (Callable) 类型（不仅是函数对象 (FunctionObject) ）

function (C++11) | 包装具有指定函数调用签名的任意可复制构造类型的可调用对象 (类模板)
move_only_function (C++23) | 包装具有指定函数调用签名的任意类型的可调用对象 (类模板)
bind (C++11) | 绑定一或多个实参到函数对象 (函数模板)
bind_front (C++20) | 按顺序绑定一定数量的参数到函数对象 (函数模板)
reference_wrapper (C++11) | 可复制构造 (CopyConstructible) 且可复制赋值 (CopyAssignable) 的引用包装器 (类模板)
result_ofinvoke_result (C++11)(C++20 中移除)(C++17) | 推导以一组实参调用一个可调用对象的结果类型 (类模板)
thread (C++11) | 管理单独的线程 (类)
jthread (C++20) | 有自动合并和取消支持的 std::thread (类)
call_once (C++11) | 仅调用函数一次，即使从多个线程调用 (函数模板)
async (C++11) | 异步运行一个函数（有可能在新线程中执行），并返回保有其结果的 std::future (函数模板)
packaged_task (C++11) | 打包一个函数，存储其返回值以进行异步获取 (类模板)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2219 | C++11 | 不可能以 reference_wrapper 为对象表达式 INVOKE 成员指针 | 检测并处理 reference_wrapper
LWG 2420 | C++11 | 当 R 为 void 时，要求从结果到 void 的不可能的隐式转换 | 当 R 为 cv void 时结果可显式转换为 void

参阅

is_invocableis_invocable_ris_nothrow_invocableis_nothrow_invocable_r (C++17) | 检查类型能否以给定的实参类型调用（如同以 std::invoke） (类模板)
invocableregular_invocable (C++20) | 指定能以给定的一组实参类型调用的可调用类型 (概念)


C++ 具名要求：字符特征 (CharTraits)

< cpp‎ | named req

字符特征 (CharTraits) 是特征类，它抽象给定字符类型的基本字符和字符串操作。大多数标准库字符串类和输入/输出类要求伴随对应字符模板类型形参的字符特征 (CharTraits) 模板类型。

要求

字符特征 (CharTraits) 上的下列操作均不可抛出异常。

给定

  • CharT ，字符类型
  • X ， CharT 的字符特征 (CharTraits) 类型
  • c, d ， CharT 类型值
  • p, q ， const CharT* 类型值
  • s ， CharT* 类型值
  • n, i, j ， std::size_t 类型值
  • e, f ， X::int_type 类型值
  • pos ， X::pos_type 类型值
  • state ， X::state_type 类型值
  • r ， CharT 类型左值
表达式 | 返回类型 | 语义 | 复﻿杂﻿度
X::char_type | CharT | 用于指代字符类型 | 编译时
X::int_type | 能保有 X::char_type 的所有合法值加 X::eof() 的类型 | 编译时
X::off_type | 以 X 为输入/输出类中的特性模板形参时，若此类型非 std::streamoff 则引起实现定义行为。 | 编译时
X::pos_type
  • 输入/输出类中的函数返回此类型，以 X::pos_type(X::off_type(-1)) 为提示错误的非法值
  • 以此类型的非法值为任何接收此类型值的 std::istream 、 std::ostream 或 std::streambuf 成员的实参是未定义行为
  • 在以 X 为输入/输出类中的特性模板形参时，若此类型非 std::streampos 则引起实现定义行为
 编译时
X::state_type | 可析构 (Destructible) 、可复制赋值 (CopyAssignable) 、可复制构造 (CopyConstructible) 、可默认构造 (DefaultConstructible) | 编译时
X::eq(c,d) | bool | 返回：是否把 c 当做等于 d | 常数
X::lt(c,d) | bool | 返回：是否把 c 当做小于 d | 常数
X::compare(p,q,n) int 返回：
  • 0 ，若对 [0,n) 中的每个 i ， X::eq(p[i], q[i]) 为 true
  • 否则为负值，若
    • 对 [0,n) 中的某个 j ， X::lt(p[j], q[j]) 为 true ，且
    • 对 [0,j) 中的每个 i ， X::eq(p[i], q[i]) 为 true
  • 否则为正值
 线性
X::length(p) | std::size_t | 返回：使得 X::eq(p[i], CharT()) 为 true 的最小 i | 线性
X::find(p,n,c) const X::char_type* 返回：
  • [p, p+n) 中的最小 q ，使得 X::eq(*q, c) 为 true
  • 否则为零
 线性
X::move(s,p,n) X::char_type*
  • 对 [0,n) 中的每个 i 进行 X::assign(s[i], p[i])
  • 即使范围 [p,p+n) 与 [s,s+n) 重叠也能正确复制
  • 返回： s
 线性
X::copy(s,p,n) X::char_type*
  • 要求： p 不在 [s,s+n) 中
  • 返回： s
  • 对 [0,n) 中每个 i 进行 X::assign(s[i], p[i])
 线性
X::assign(r,d) | （不使用） | 赋值 r = d | 常数
X::assign(s,n,c) X::char_type*
  • 对 [0,n) 中每个 i 进行 X::assign(s[i], c) 。
  • 返回： s
 线性
X::not_eof(e) X::int_type 返回：
  • e ，若 X::eq_int_type(e, X::eof()) 为 false
  • 否则为使得 X::eq_int_type(f, X::eof()) 为 false 的值 f
 常数
X::to_char_type(e) X::char_type 返回：
  • 若 X::eq_int_type(e, X::to_int_type(c)) 对某个 c 为 true 则为 c
  • 否则为某未指定值
 常数
X::to_int_type(c) | X::int_type | 返回： X::to_char_type 和 X::eq_int_type 的定义所制约的某值 e | 常数
X::eq_int_type(e,f) bool
  • 对于所有 c 和 d ， X::eq(c,d) 等于 X::eq_int_type(X::to_int_type(c), X::to_int_type(d))
  • 返回：
    • X::eq(c,d) ，若对于某 c 和 d ， e == X::to_int_type(c) 且 f == X::to_int_type(d)
    • 否则为 true ，若 e 与 f 都是 X::eof() 的副本
    • 否则为 false ，若 e 与 f 之一为 X::eof() 的副本而另一者不是
    • 否则值未指定
 常数
X::eof() | X::int_type | 返回：使得 X::eq_int_type(e, X::to_int_type(c)) 对于所有值 c 为 false 的值 e | 常数

标准库

下列标准库类模板要求字符特征 (CharTraits) 作为模板类型形参：

字符串
basic_string
 存储并操作字符序列
(类模板)
basic_string_view
(C++17)
 只读的字符串视图
(类模板)
流
basic_ios
 管理任意流缓冲
(类模板)
basic_istream
 包装给定的抽象设备（std::basic_streambuf）
并提供高层输入接口
(类模板)
basic_ifstream
 实现高层文件流输入操作
(类模板)
basic_istringstream
 实现高层字符串流输入操作
(类模板)
basic_ispanstream
(C++23)
 实现固定字符缓冲区输入操作
(类模板)
basic_ostream
 包装给定的抽象设备（std::basic_streambuf）
并提供高层输出接口
(类模板)
basic_ofstream
 实现高层文件流输出操作
(类模板)
basic_ostringstream
 实现高层字符串流输出操作
(类模板)
basic_osyncstream
(C++20)
 同步输出流的包装
(类模板)
basic_ospanstream
(C++23)
 实现固定字符缓冲区输出操作
(类模板)
basic_iostream
 包装给定的抽象设备（std::basic_streambuf）
并提供高层输入/输出接口
(类模板)
basic_fstream
 实现高层文件流输入/输出操作
(类模板)
basic_stringstream
 实现高层字符串流输入/输出操作
(类模板)
basic_spanstream
(C++23)
 实现固定字符缓冲区输入/输出操作
(类模板)
流迭代器
istream_iterator
 从 std::basic_istream 读取的输入迭代器
(类模板)
ostream_iterator
 写入 std::basic_ostream 的输出迭代器
(类模板)
流缓冲
basic_streambuf
 抽象原生设备
(类模板)
basic_filebuf
 抽象原生文件设备
(类模板)
basic_stringbuf
 实现原生字符串设备
(类模板)
basic_syncbuf
(C++20)
 同步输出设备的包装
(类模板)
basic_spanbuf
(C++23)
 实现原始固定字符缓冲区设备
(类模板)
流缓冲迭代器
istreambuf_iterator
 从 std::basic_streambuf 读取的输入迭代器
(类模板)
ostreambuf_iterator
 写入 std::basic_streambuf 的输出迭代器
(类模板)

下列标准库类满足字符特征 (CharTraits) ：

template<> class char_traits<char>;

template<> class char_traits<wchar_t>;
template<> class char_traits<char8_t>;
template<> class char_traits<char16_t>;

template<> class char_traits<char32_t>;

(C++20 起)
(C++11 起)
(C++11 起)


C++ 具名要求：时钟 (Clock)

< cpp‎ | named req

时钟 (Clock) 要求描述由 std::chrono::duration 、 std::chrono::time_point 和获取当前 time_point 的函数 now() 组成的一束内容。时钟的纪元指代时钟的 time_point 的原点。

要求

C1 与 C2 表示时钟类型。 t1 与 t2 是 C1::now() 返回的值，其中返回 t1 的调用先发生于返回 t2 的调用，且两者都先发生于 C1::time_point::max() 。

表达式 | 返回类型 | 操作语义
C1::rep | 算术类型或模拟算术类型的类 | C1::duration 的表示类型。
C1::period | std::ratio 的特化 | 时钟的每秒计次周期。
C1::duration | std::chrono::duration <C1::rep, C1::period> | 时钟的时期类型。
C1::time_point | std::chrono::time_point <C1> 或 std::chrono::time_point <C2, C1::duration> | 时钟的 std::chrono::time_point 类型。 C1 与 C2 应指同一纪元。
C1::is_steady | const bool | 若 t1 <= t2 始终为 true 且时钟计次之间的时间间隔为常量，则为 true ，否则为 false
C1::now() | C1::time_point | 返回表示时间中当前点的 time_point 对象。

参阅

is_clockis_clock_v
(C++20)
 确定类型是否为时钟 (Clock)
(类模板) (变量模板)


C++ 具名要求：比较 (Compare)

< cpp‎ | named req

比较 (Compare) 是一些标准库设施针对用户提供的函数对象类型所期待的一组要求。

对满足比较 (Compare) 的类型的对象运用函数调用操作的返回值，当按语境转换成 bool 时，若此类型所引入的严格弱序关系中，该调用的第一实参先于第二实参，则生成 true，否则生成 false。

与任何二元谓词 (BinaryPredicate) 相同，不允许该表达式的求值通过解引用的迭代器调用非 const 函数。

要求

以下情况下，类型 T 满足比较 (Compare)

  • 类型 T 满足二元谓词 (BinaryPredicate) ，且

给定

  • T 类型的对象 comp
  • equiv(a, b)，为等价于 !comp(a, b) && !comp(b, a) 的表达式

下列表达是必须合法且拥有其指定的效果

表达式 返回类型 要求
comp(a, b) 可隐式转换为 bool 建立具有下列性质的严格弱序关系
  • 对于所有 a，comp(a,a)==false
  • 若 comp(a,b)==true 则 comp(b,a)==false
  • 若 comp(a,b)==true 且 comp(b,c)==true 则 comp(a,c)==true
equiv(a, b) bool 建立具有下列性质的等价关系
  • 对于所有 a，equiv(a,a)==true
  • 若 equiv(a,b)==true 则 equiv(b,a)==true
  • 若 equiv(a,b)==true 且 equiv(b,c)==true 则 equiv(a,c)==true

注：comp 在 equiv 所确定的等价类上引入了一种严格全序。

标准库

下列标准库设施期待比较 (Compare) 类型。

set | 唯一键的集合，按照键排序 (类模板)
map | 键值对的集合，按照键排序，键是唯一的 (类模板)
multiset | 键的集合，按照键排序 (类模板)
multimap | 键值对的集合，按照键排序 (类模板)
priority_queue | 适配一个容器以提供优先级队列 (类模板)
sort | 将范围按升序排序 (函数模板)
sort (C++11) | 对元素进行排序 (std::forward_list<T,Allocator> 的公开成员函数)
sort | 对元素进行排序 (std::list<T,Allocator> 的公开成员函数)
stable_sort | 将范围内的元素排序，同时保持相等的元素之间的顺序 (函数模板)
partial_sort | 排序一个范围的前 N 个元素 (函数模板)
partial_sort_copy | 对范围内的元素进行复制并部分排序 (函数模板)
is_sorted (C++11) | 检查范围是否已按升序排列 (函数模板)
is_sorted_until (C++11) | 找出最大的已排序子范围 (函数模板)
nth_element | 将给定的范围部分排序，确保其按给定元素划分 (函数模板)
lower_bound | 返回指向第一个不小于给定值的元素的迭代器 (函数模板)
upper_bound | 返回指向第一个大于给定值的元素的迭代器 (函数模板)
binary_search | 确定元素是否存在于某范围中 (函数模板)
equal_range | 返回匹配特定键值的元素范围 (函数模板)
merge | 归并两个已排序的范围 (函数模板)
merge (C++11) | 合并二个已排序列表 (std::forward_list<T,Allocator> 的公开成员函数)
merge | 合并二个已排序列表 (std::list<T,Allocator> 的公开成员函数)
inplace_merge | 就地归并两个有序范围 (函数模板)
includes | 若一个序列是另一个的子列则返回 true (函数模板)
set_difference | 计算两个集合的差集 (函数模板)
set_intersection | 计算两个集合的交集 (函数模板)
set_symmetric_difference | 计算两个集合的对称差 (函数模板)
set_union | 计算两个集合的并集 (函数模板)
push_heap | 将一个元素加入到一个最大堆 (函数模板)
pop_heap | 从最大堆中移除最大元素 (函数模板)
make_heap | 从一个元素范围创建出一个最大堆 (函数模板)
sort_heap | 将一个最大堆变成一个按升序排序的元素范围 (函数模板)
is_heap | 检查给定范围是否为一个最大堆 (函数模板)
is_heap_until (C++11) | 查找能成为最大堆的最大子范围 (函数模板)
max | 返回各给定值中的较大者 (函数模板)
max_element | 返回范围内的最大元素 (函数模板)
min | 返回各给定值中的较小者 (函数模板)
min_element | 返回范围内的最小元素 (函数模板)
minmax (C++11) | 返回两个元素的较小和较大者 (函数模板)
minmax_element (C++11) | 返回范围内的最小元素和最大元素 (函数模板)
lexicographical_compare | 当一个范围按字典顺序小于另一个范围时，返回 true (函数模板)
next_permutation | 产生某个元素范围的按字典顺序的下一个较大的排列 (函数模板)
prev_permutation | 产生某个元素范围的按字典顺序的下一个较小的排列 (函数模板)

参阅

strict_weak_order
(C++20)
 指定一个 relation 所强加的是严格弱序
(概念)


C++ 具名要求：常量表达式迭代器 (ConstexprIterator)

< cpp‎ | named req

常量表达式迭代器 (ConstexprIterator) 是能在常量表达式求值中使用的老式迭代器 (LegacyIterator) 。

要求

若符合下列条件，则类型 It 满足常量表达式迭代器 (ConstexprIterator)

  • 类型 It 满足某个迭代器具名要求 MeowIterator

而对于每个

  • purr，为 MeowIterator 在 It 上要求支持的操作，
  • kittens...，为一组 purr 的实参，满足该操作的要求，

则

  • 若 kittens... 可用于常量表达式，则 purr(kittens...) 亦然

标准库

下列标准库类型是常量表达式迭代器 (ConstexprIterator) ：

  • array::iterator 及 array::const_iterator。
  • basic_string_view::iterator。
  • span::iterator。
  • vector::iterator 及 vector::const_iterator。

参阅

  • 迭代器库


C++ 具名要求：容器 (Container)

< cpp‎ | named req

容器 (Container) 是用于存储其他对象并照顾管理其所容纳的对象所用的内存的对象。

要求

  • 容器类型 C；
  • 元素类型 T；
  • C 类型的对象 a、b。
  • rv ， C 类型右值表达式。

类型

名称 | 类型 | 注解
value_type | T | 可擦除 (Erasable)
reference | T& |
const_reference | const T& |
iterator | 指向 T 的迭代器 | 老式向前迭代器 (LegacyForwardIterator) 可转换为 const_iterator
const_iterator | 指向 T 的常迭代器 | 老式向前迭代器 (LegacyForwardIterator)
difference_type | 有符号整数 | 必须与 iterator 和 const_iterator 的 iterator_traits::difference_type 相同
size_type | 无符号整数 | 足够大以表示 difference_type 的所有正值

方法与运算符

表达式 | 返回类型 | 语义 | 条件 | 复杂度
C() | C | 创建空容器 | 后：C().empty() == true | 常数
C(a) C 创建 a 的副本 前：T 必须为可复制插入 (CopyInsertable)
后：a == C(a) 		线性
C(rv)(C++11 起) | C | 移动 rv | 后：等于 rv 在此构造前的值 | 常数[1]
a = b | C& | 销毁或从 b 的元素复制赋值 a 的所有元素 | 后：a == b | 线性
a = rv | C& | 销毁或从 rv 的元素移动赋值 a 的所有元素 | 后：若 a 与 rv 不指代同一对象则 a 等于 rv 在此赋值前拥有的值 | 线性
a.~C() | void | 销毁 a 的所有元素并释放所有内存 | 线性
a.begin() | (const_)iterator | 指向 a 首元素的迭代器 | 常数
a.end() | (const_)iterator | 指向 a 尾元素后一位的元素 | 常数
a.cbegin()(C++11 起) | const_iterator | const_cast<const C&>(a).begin() | 常数
a.cend()(C++11 起) | const_iterator | const_cast<const C&>(a).end() | 常数
a == b 可转换为 bool a.size() == b.size() &&
std::equal (a.begin(), a.end(), b.begin())
 (C++14 前)std::equal (a.begin(), a.end(), b.begin(), b.end())
 (C++14 起) 		前：T 必须可相等比较 (EqualityComparable) 若 a.size() != b.size() 则为常数[2]，否则为线性
a != b | 可转换为 bool | !(a == b) | 线性
a.swap(b) | void | 交换 a 与 b 的值 | 常数[1][3]
swap(a, b) | void | a.swap(b) | 常数[1]
a.size() | size_type | std::distance (a.begin(), a.end()) | 常数[3]
a.max_size() | size_type | b.size() ，其中 b 是最大的可能容器 | 常数[3]
a.empty() | 可转换为 bool | a.begin() == a.end() | 常数
注
  1. ↑ 1.0 1.1 1.2 对 std::array 为线性
  2. ↑ 对于 std::forward_list 始终为线性
  3. ↑ 3.0 3.1 3.2 (C++11 前) 非严格常数

给定

  • 容器的 iterator 类型的对象 i 与 j，

表达式 i == j、i != j、i < j、i <= j、i >= j、i > j、i - j 中，任一或二者都可以用指代相同元素的一个该容器的 const_iterator 类型的对象替换，而不更改其语义。

容器数据竞争

见容器线程安全

其他要求

C
  • 可默认构造 (DefaultConstructible)
  • 可复制构造 (CopyConstructible)
  • 可相等比较 (EqualityComparable)
  • 可交换 (Swappable)
T
  • 可复制插入 (CopyInsertable)
  • 可相等比较 (EqualityComparable)
  • 可析构 (Destructible)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 179 | C++98 | iterator 与 const_iterator 类型可能不可比较 | 要求可比较
LWG 2263 | C++11 | LWG179 的解决方案在 C++11 中被意外丢弃 | 已恢复
LWG 2839 | C++11 | 不允许标准容器的自移动赋值 | 容许但结果未指定

参阅


C++ 具名要求：连续容器 (ContiguousContainer)

< cpp‎ | named req

连续容器 (ContiguousContainer) 是在连续的内存位置中存储对象的容器 (Container) 。

要求

以下情况下，类型 X 满足连续容器 (ContiguousContainer) ：

  • 类型 X 满足容器 (Container)
  • 类型 X 支持老式随机访问迭代器 (LegacyRandomAccessIterator)
  • 成员类型 X::iterator 与 X::const_iterator 是老式连续迭代器 (LegacyContiguousIterator) (C++20 前) contiguous_iterator (C++20 起)

标准库中的连续容器

basic_string | 存储并操作字符序列 (类模板)
array (C++11) | 静态的连续数组 (类模板)
vector | 动态的连续数组 (类模板)


C++ 具名要求：老式连续迭代器 (LegacyContiguousIterator)

< cpp‎ | named req

老式连续迭代器 (LegacyContiguousIterator) 是老式迭代器 (LegacyIterator) ，其所指向的逻辑相邻元素也在内存中物理上相邻。

指向数组元素的指针满足老式连续迭代器 (LegacyContiguousIterator) 的所有要求。

要求

以下情况下，类型 It 满足老式连续迭代器 (LegacyContiguousIterator)

  • 类型 It 满足老式迭代器 (LegacyIterator)

并且，对于每个

  • a，为 It 类型的可解引用迭代器
  • n，为整型值

使得

  • a + n 为有效的可解引用迭代器值

则

  • *(a + n) 等价于 *( std::addressof (*a) + n)。

标准库

下列标准库类型是老式连续迭代器 (LegacyContiguousIterator) 。

  • array::iterator。
  • basic_string_view::iterator。
  • basic_string::iterator。
  • vector::iterator，对于除 bool 以外的 value_type。
  • begin(valarray) 和 end(valarray) 的返回类型。

注解

亦要求指向对象类型的缀饰指针满足老式连续迭代器 (LegacyContiguousIterator) 。

老式连续迭代器 (LegacyContiguousIterator) 被 contiguous_iterator 概念代替：标准库中在 C++17 中被要求满足老式连续迭代器 (LegacyContiguousIterator) 的迭代器类型在 C++20 中亦被要求实现 contiguous_iterator 。

 (C++20 起)

参阅

contiguous_iterator (C++20) | 指定 random_access_iterator 为连续迭代器，指代内存中连续相接的元素 (概念)
迭代器库 | 提供迭代器的定义、迭代器表征、适配器及工具函数


C++ 具名要求：可复制赋值 (CopyAssignable)

< cpp‎ | named req

指定该类型的实例可从左值表达式复制赋值。

要求

若满足下列条件，则类型 T 满足可复制赋值 (CopyAssignable) ：

  • 类型 T 满足可移动赋值 (MoveAssignable) ，且

给定

  • T 类型的可修改左值表达式 t
  • v，为 T 或 const T 类型的左值表达式或 const T 类型的右值表达式

下列表达式必须合法且拥有其指定的效果

表达式 | 返回类型 | 返回值 | 后条件
t = v | T& | t | t 的值等价于 v 的值。 v 的值不更改。

参阅

is_copy_assignableis_trivially_copy_assignableis_nothrow_copy_assignable (C++11)(C++11)(C++11) | 检查类型是否拥有复制赋值运算符 (类模板)
assignable_from (C++20) | 指定一个类型能从另一类型赋值 (概念)


C++ 具名要求：可复制构造 (CopyConstructible)

< cpp‎ | named req

指定该类型的实例可以从左值表达式进行复制构造。

要求

以下情况下，类型 T 满足可复制构造 (CopyConstructible) ：

  • 类型 T 满足可移动构造 (MoveConstructible) ，且

给定

  • v，为 T 或 const T 类型的左值表达式或 const T 类型的右值表达式
  • 任意标识符 u

下列表达式必须合法且拥有其指定的效果

表达式 | 后条件
T u = v; | u 的值等价于 v 的值。不更改 v 的值。
T(v) | T(v) 的值等价于 v 的值。不更改 v 的值。

表达式 v.~T() 亦必须合法，且对于左值 v，表达式 &v 必须具有 T* 或 const T* 类型，且必须求值为 v 的地址。

 (C++11 前)

注解

C++11 前，重载了 operator& 的类并非可复制构造 (CopyConstructible) ，从而不可用于标准库容器。C++11 开始，标准库在凡是需要对象地址时都使用 std::addressof。

参阅

is_copy_constructibleis_trivially_copy_constructibleis_nothrow_copy_constructible (C++11)(C++11)(C++11) | 检查类型是否拥有复制构造函数 (类模板)
copy_constructible (C++20) | 指定能复制构造和移动构造一个类型的对象 (概念)


C++ 具名要求：可复制插入 (CopyInsertable)

< cpp‎ | named req

指定该类型的实例能以给定分配器原位复制构造。

要求

以下情况下，类型 T 可复制插入 (CopyInsertable) 进容器 X（其 value_type 等同于 T）：若 T 可移动插入 (MoveInsertable) 进 X ，且给定

A | 分配器类型
m | A 类型的左值
p | 容器所准备的 T* 类型的指针
v | （可为 const 的）T 类型的表达式

其中 X::allocator_type 等同于 std::allocator_traits <A>::rebind_alloc<T>，

下列表达式良构：

std::allocator_traits<A>::construct(m, p, v);

并且在求值后，*p 的值等价于 v 的值。而 v 的值不更改。

若 X 非知分配器或为 std::basic_string 特化，则如同 A 就是 std::allocator<T> 一样进行定义，但并不需要创建分配器对象，且不会实例化用户定义的 std::allocator 的特化。

注解

若 A 是 std::allocator <T>，则这将调用布置 new，如同用 ::new((void*)p) T(v) (C++20 前)std::construct_at(p, v) (C++20 起)。

尽管 C++23 前要求在构造 std::basic_string 的元素时使用定制的 construct，所有实现都使用默认机制。P1072R10 更正了该要求以匹配既存实现。


C++ 具名要求：可默认构造 (DefaultConstructible)

< cpp‎ | named req

指定该类型的对象可以默认构造 。

要求

以下情况下，类型 T 满足可默认构造 (DefaultConstructible) ：

给定

  • 任意标识符 u，

下列表达式必须合法且拥有其指定的效果

表达式 | 后条件
T u | 对象 u 被默认初始化。
T u{} | 对象 u 被值初始化或聚合初始化。
T() T{} | 一个 T 类型的临时对象被值初始化或聚合初始化。

注解

对于非聚合类类型的对象，必须定义公开的默认构造函数（用户定义或隐式定义），以满足可默认构造 (DefaultConstructible) 。

非类对象类型的非 const 对象始终为可默认构造 (DefaultConstructible) 。

const 的非类类型非可默认构造 (DefaultConstructible) 。

const 的聚合类型，若其任何成员是非类类型对象，则非可默认构造 (DefaultConstructible) 。

非对象类型（函数类型，引用类型，以及（可能 cv 限定的）void 类型）和 const 的非对象类型始终非可默认构造 (DefaultConstructible) 。

参阅

is_default_constructibleis_trivially_default_constructibleis_nothrow_default_constructible (C++11)(C++11)(C++11) | 检查类型是否有默认构造函数 (类模板)
default_initializable (C++20) | 指定能默认构造一个类型的对象 (概念)


C++ 具名要求：可默认插入 (DefaultInsertable)

< cpp‎ | named req

指定该类型的实例能以给定的分配器原位默认构造。

要求

以下情况下，类型 T 可默认插入 (DefaultInsertable) 进容器 (Container) X（其 value_type 等同于 T）：给定

A | 分配器类型
m | A 类型的左值
p | 容器所准备的 T* 类型的指针

其中 X::allocator_type 等同于 std::allocator_traits <A>::rebind_alloc<T>，

下列表达式良构：

std::allocator_traits<A>::construct(m, p);

若 X 非知分配器或为 std::basic_string 特化，则如同 A 就是 std::allocator<T> 一样进行定义，但并不需要创建分配器对象，且不会实例化用户定义的 std::allocator 的特化。

注解

默认情况下，这会调用布置 new，如用 ::new((void*)p) T() (C++20 前)std::construct_at(p) (C++20 起) 一样（即值初始化 p 所指向的对象）。若不欲值初始化，例如当对象是非类类型且不需要清零时，则可通过提供定制的 Allocator::construct 予以避免。

尽管 C++23 前要求在构造 std::basic_string 的元素时使用定制的 construct，所有实现都使用默认机制。P1072R10 更正了该要求以匹配既存实现。

参阅

可默认构造 (DefaultConstructible)
可复制插入 (CopyInsertable)
可移动插入 (MoveInsertable)
可就位构造 (EmplaceConstructible)
可擦除 (Erasable)


C++ 具名要求：可析构 (Destructible)

< cpp‎ | named req

指定该类型的实例可被析构。

要求

以下情况下，类型 T 满足可析构 (Destructible) ：

给定

  • T 类型的表达式 u

则下列表达式必须合法且拥有其指定的效果

表达式 | 后条件
u.~T() | u 所拥有的全部资源都得到回收，不抛异常。

注解

在对象生存期结束（例如在离开作用域时或由于 delete 表达式）时隐式调用析构函数。如类型要求表中所示的显式析构函数调用是罕见的。

拜伪析构函数调用所赐，所有标量类型都满足可析构 (Destructible) 的要求，而数组类型和引用类型则不满足。注意 std::is_destructible 允许数组与引用类型。

参阅

is_destructibleis_trivially_destructibleis_nothrow_destructible (C++11)(C++11)(C++11) | 检查类型是否拥有未被弃置的析构函数 (类模板)
destructible (C++20) | 指定能销毁该类型的对象 (概念)


C++ 具名要求：可就位构造 (EmplaceConstructible) (C++11 起)

< cpp‎ | named req

指定该类型的对象能以给定的分配器从给定的一组实参构造到未初始化存储之中。

要求

以下情况下，类型 T 为从实参 args 可就位构造 (EmplaceConstructible) 进容器 (Container) X（其 value_type 等同于 T）：给定

A | 具分配器类型
m | A 类型的左值
p | 容器所准备的 T* 类型的指针
args | 零或更多实参

其中 X::allocator_type 等同于 std::allocator_traits <A>::rebind_alloc<T>，

下列表达式良构：

std::allocator_traits<A>::construct(m, p, args);

若 X 非知分配器或为 std::basic_string 特化，则如同 A 就是 std::allocator<T> 一样进行定义，但并不需要创建分配器对象，且不会实例化用户定义的 std::allocator 的特化。

注解

尽管 C++23 前要求在构造 std::basic_string 的元素时使用定制的 construct，所有实现都使用默认机制。P1072R10 更正了该要求以匹配既存实现。

参阅

可复制插入 (CopyInsertable)
可移动插入 (MoveInsertable)


C++ 具名要求：可相等比较 (EqualityComparable)

< cpp‎ | named req

类型必须能使用 == 运算符且结果应当具有标准语义。

要求

以下情况下，类型 T 满足可相等比较 (EqualityComparable) ：

给定

  • T 或 const T 类型的表达式 a、b 与 c

下列表达式必须合法且拥有其指定的效果

表达式 返回类型 要求
a == b 可隐式转换为 bool 建立一种等价关系，即满足下列性质：
  • 对于 a 的所有值，a == a 产生 true；
  • 若 a == b，则 b == a；
  • 若 a == b 且 b == c，则 a == c。

注解

为满足此要求，没有内建比较运算符的类型必须提供用户定义的 operator==。

对于既为可相等比较 (EqualityComparable) 亦为可小于比较 (LessThanComparable) 的类型， C++ 标准库对相等（即表达式 a == b 的值）和等价（即表达式 !(a < b) && !(b < a) 的值）间做出区别。

参阅

equality_comparableequality_comparable_with
(C++20)
 指定运算符 == 为等价关系
(概念)


C++ 具名要求：可擦除 (Erasable)

< cpp‎ | named req

指定该类型的对象能以给定的分配器 (Allocator) 销毁。

要求

以下情况下，类型 T 从容器 (Container) X（其 value_type 等同于 T）可擦除 (Erasable) ：给定

A | 分配器类型
m | A 类型的左值
p | 容器所准备的 T* 类型的指针

其中 X::allocator_type 等同于 std::allocator_traits <A>::rebind_alloc<T>，

下列表达式良构：

std::allocator_traits<A>::destroy(m, p);

若 X 非知分配器或为 std::basic_string 特化，则如同 A 就是 std::allocator <T> 一样进行定义，但并不需要创建分配器对象，且不会实例化用户定义的 std::allocator 的特化。

注解

所有标准库容器均要求其元素满足可擦除 (Erasable) 。

对于默认分配器，此要求等价于 p->~T() 的合法性，它接受拥有可访问的析构函数的类类型和所有标量类型，但拒绝数组类型、函数类型、引用类型和 void。 | (C++20 前)
对于默认分配器，此要求等价于 std::destroy_at (p) 的合法性，它接受拥有可访问的析构函数的类类型和所有标量类型，还有其数组。 | (C++20 起)

尽管 C++23 前要求在销毁 std::basic_string 的元素时使用定制的 destroy，所有实现都使用默认机制。P1072R10 更正了该要求以匹配既存实现。

参阅

可复制插入 (CopyInsertable)
可移动插入 (MoveInsertable)
可就位构造 (EmplaceConstructible)
可析构 (Destructible)


C++ 具名要求：有格式输入函数 (FormattedInputFunction)

< cpp‎ | named req

要求

有格式输入函数 (FormattedInputFunction) 是进行下列操作的流输入函数：

  • 构造一个具有自动存储期的 basic_istream::sentry 类型的对象，并将 noskipws 实参设为 false，这导致进行下列操作
  • 若输入流上设置了 eofbit 或 badbit，则一同设置 failbit，且若此输入流的异常掩码中启用了 failbit 上的异常，则抛出 ios_base::failure。
  • 冲洗其所 tie() 的输出流，若适用
  • 若此输入流上设置了 ios_base::skipws 标志，则提取并舍弃来自输入流的字符，直至下列之一为真：
  • 输入流上的下个可用字符不是空白字符（以此输入流中当前浸染的本地环境的 std::ctype 刻面进行测试）。不提取非空白字符。
  • 抵达流尾，该情况下设置 failbit 和 eofbit，而且若该流开启了这些位之一上的异常，则抛出 ios_base::failure。
  • 通过调用 sentry::operator bool() 检查 sentry 的状态，这等价于 basic_ios::good。
  • 若 sentry 返回 false 或 sentry 的构造函数抛异常，则不发生输入。
  • 若 sentry 返回 true，则如同通过调用 rdbuf()->sbumpc() 或 rdbuf()->sgetc() 一样进行输入。
  • 若抵达流尾（对 rdbuf()->sbumpc() 或 rdbuf()->sgetc() 的调用返回 Traits::eof()），则设置 eofbit。若此流的异常掩码中启用了 eofbit 上的异常，则抛出 ios_base::failure。
  • 若在输入期间抛出了异常，则在输入流中设置 badbit。若此流的异常掩码中启用了 badbit 上的异常，则重抛这个异常。
  • 若未抛出任何异常，则返回 *this。
  • 任何事件中，无论是因异常终止还是返回，离开此函数前都会调用 sentry 的析构函数。

标准库

下列标准库函数是有格式输入函数 (FormattedInputFunction) 。

  • basic_istream::operator>>(int, long, double, void*, bool)
  • operator>>(std::basic_istream, char&)
  • operator>>(std::basic_istream, char*)
  • operator>>(std::basic_istream, std::bitset)
  • operator>>(std::basic_istream, std::string)
  • operator>>，在 std::get_money 的返回值上调用时。


C++ 具名要求：有格式输出函数 (FormattedOutputFunction)

< cpp‎ | named req

要求

有格式输出函数 (FormattedOutputFunction) 是进行下列操作的流输出函数：

  • 构造一个拥有自动存储期的 basic_ostream::sentry类型的对象，这进行下列操作
  • 若输出流上设置了 eofbit 或 badbit，则一并设置 failbit，而若此输出流的异常掩码中启用了 failbit 上的异常，则抛出 ios_base::failure。
  • 冲洗其所 tie() 的输出流，若适用。
  • 通过调用 sentry::operator bool() 检查 sentry 的状态，等价于 basic_ios::good。
  • 若 sentry 返回 false，或 sentry 的构造函数抛出了异常，则不发生输出
  • 若 sentry 返回 true，则如同以调用 rdbuf()->sputc() 或 rdbuf()->xsputn()，试图通过插入字符到输出流进行所欲的输出。另外，可能调用 rdbuf()->overflow() 或 rdbuf()->sync()，但不会调用 std::basic_streambuf 的其他虚成员函数。
  • 若无法生成输出，则设置 failbit。若此流的异常掩码中启用了 failbit 上的异常，则抛出 ios_base::failure。
  • 若输出中抛出了异常，则设置输出流中的 badbit。若此流的异常掩码中启用了 badbit 上的异常，则亦会重抛该异常。
  • 若未抛出异常，则返回 *this。
  • 任何事件中，无论是因异常终止还是返回，都会在离开此函数前调用 sentry 的析构函数。

标准库

下列标准库函数是有格式输出函数 (FormattedOutputFunction) 。

  • basic_ostream::operator<<(int, long, double, void*, bool)
  • operator<<(std::basic_ostream, char)
  • operator<<(std::basic_ostream, char*)
  • operator<<(std::basic_ostream, std::bitset)
  • operator<<(std::basic_ostream, std::string)
  • operator<< ，在 std::put_money 的返回值上调用时。


C++ 具名要求：格式化器 (Formatter)

< cpp‎ | named req

格式化器 (Formatter) 是对给定的格式化实参类型与字符类型抽象化格式化操作的类型。要求 std::formatter 的特化实现格式化器 (Formatter) 。

要求

一个类型满足格式化器 (Formatter) ，若它为半正则，意思是它满足：

  • 可默认构造 (DefaultConstructible)
  • 可复制构造 (CopyConstructible)
  • 可复制赋值 (CopyAssignable)
  • 可析构 (Destructible)
  • 可交换 (Swappable)

而且给定

  • Arg ，格式化实参类型
  • CharT ，字符类型
  • Formatter ，对于类型 Arg 与 CharT 的格式化器 (Formatter) 类型
  • OutputIt ，老式输出迭代器 (LegacyOutputIterator) 类型
  • formatter ， Formatter 类型值
  • arg ， Arg 类型左值
  • t ，可转换到（可能为 const ）的 Arg
  • ParseContext ， std::basic_format_parse_context<CharT> 的别名
  • FormatContext ， std::basic_format_context<OutputIt, CharT> 的别名
  • parse_context ， ParseContext 类型左值
  • format_context ， FormatContext 类型左值
表达式 返回类型 语义
formatter.parse(parse_context) ParseContext::iterator
  • 对类型 Arg 分析 格式说明 [parse_context.begin(), parse_context.end()) ，直至首个未匹配的字符。
  • 抛出 std::format_error ，除非可分析整个范围或首个未匹配字符是 } 。[注 1]
  • 存储分析的格式说明符到 formatter 中并返回已分析范围的尾迭代器。
formatter.format(t, format_context) FormatContext::​iterator
  • 按存储于 formatter 的格式说明符分析 t ，写输出到 format_context.out() 并返回输出范围的尾迭代器。
  • 输出应当仅依赖
    • t、
    • format_context.locale()、
    • 来自前一次调用的范围 [parse_context.begin(), parse_context.end()) ，以及
    • 对于任何 std::size_t 类型值 n 的 format_context.arg(n) 。
formatter.format(arg, format_context) FormatContext::​iterator

同上，但不修改 arg 。
  1. ↑ 这允许格式化器放出有意义的错误消息。


C++ 具名要求：老式向前迭代器 (LegacyForwardIterator)

< cpp‎ | named req

老式向前迭代器 (LegacyForwardIterator) 是能从所指向的元素读取数据的老式迭代器 (LegacyIterator) 。

不同于老式输入迭代器 (LegacyInputIterator) 和老式输出迭代器 (LegacyOutputIterator) ，它可被用于多趟算法。

要求

若达成下列条件，则类型 It 满足老式向前迭代器 (LegacyForwardIterator)

  • 类型 It 满足老式输入迭代器 (LegacyInputIterator)
  • 类型 It 满足可默认构造 (DefaultConstructible)
  • 类型 It 的对象提供下文所述的多趟保证
  • 类型 std::iterator_traits<It>::reference 必须恰为
  • 若 It 满足老式输出迭代器 (LegacyOutputIterator) （It 可变）则为 T&
  • 否则（It 为常量），为 const T&，
（其中 T 是 std::iterator_traits <It>::value_type 所指代的类型）
  • 在同一底层序列上的所有迭代器和值初始化迭代器 (C++14 起)中定义等于和不等于比较。

而且，给定

  • i，为 It 类型的可解引用迭代器
  • reference，为 std::iterator_traits<It>::reference 所指代的类型

则下列表达式必须合法且拥有其指定的效果

表达式 | 返回类型 | 等价表达式 | 注意
i++ | It | It ip=i; ++i; return ip; |
*i++ | reference |  |

可变的（mutable）老式向前迭代器 (LegacyForwardIterator) 是还额外满足老式输出迭代器 (LegacyOutputIterator) 要求的老式向前迭代器 (LegacyForwardIterator) 。

多趟保证

给定 It 类型的可解引用迭代器 a 和 b

  • 若 a 与 b 比较相等（a == b 可按语境转换为 true），则要么都不可解引用，要么 *a 与 *b 是绑定到同一对象的引用
  • 若 *a 与 *b 指代相同的对象，则 。
  • 通过可变ForwardIterator进行赋值不会使迭代器失效（隐含地因为 reference 定义为真引用）
  • 自增 a 的副本不改变从 a 读取的值（正式而言，要么 It 是原生指针类型，要么表达式 (void)++It(a), *a 等价于表达式 *a）
  • a == b 蕴含 ++a == ++b

孤立迭代器

值初始化的老式向前迭代器 (LegacyForwardIterator) 表现类似某个未指定空容器的末尾后迭代器：它与所有值初始化的同类型老式向前迭代器 (LegacyForwardIterator) 比较为相等。

 (C++14 起)

概念

为了定义 std::iterator_traits，定义了以下仅用于阐释的概念：

template<class I>

concept __LegacyForwardIterator =
__LegacyInputIterator<I> && std::constructible_from<I> &&
std::is_lvalue_reference_v <std::iter_reference_t<I>> &&
std::same_as<
std::remove_cvref_t<std::iter_reference_t<I>>,
typename std::readable_traits<I>::value_type> &&
requires(I i) {
{ i++ } -> std::convertible_to<const I&>;
{ *i++ } -> std::same_as<std::iter_reference_t<I>>;

};

其中仅用于阐释的概念 __LegacyInputIterator<T> 描述于 LegacyInputIterator#概念。

 (C++20 起)

参阅

forward_iterator (C++20) | 指定 input_iterator 为向前迭代器，支持相等比较与多趟操作 (概念)
迭代器库 | 提供迭代器的定义、迭代器表征、适配器及工具函数


C++ 具名要求：函数对象 (FunctionObject)

< cpp‎ | named req

函数对象 (FunctionObject) 类型是可用在函数调用运算符左侧的对象的类型。

要求

若满足下列条件，则类型 T 满足 函数对象 (FunctionObject)

  • 类型 T 满足 std::is_object，且

给定

  • T 或 const T 类型的值 f
  • args，为适合的实参列表，可以为空

则下列表达式必须合法：

表达式 | 要求
f(args) | 进行函数调用

注解

函数和到函数的引用不是函数对象类型，但因为函数到指针隐式转换，它们能用在期待函数对象类型的地方。

标准库

  • 所有函数指针都满足此要求。
  • 所有定义于 <functional> 的函数对象。
  • 某些 <functional> 的函数的返回类型。


C++ 具名要求：散列 (Hash)

< cpp‎ | named req

散列 (Hash) 是函数对象，其输出仅依赖于输入，且当给定不同输入值时，有非常低的概率生成相同输出。

要求

以下情况下，类型 T 满足散列 (Hash) ：

  • 类型 T 满足函数对象 (FunctionObject) 、可复制构造 (CopyConstructible) 、可析构 (Destructible) ，且

给定

  • T 或 const T 类型的值 h，其实参类型是 Key
  • 可转换为 Key 或 const Key 的值 k
  • Key 类型的左值表达式 u

下列表达是必须合法且拥有其指定的效果

表达式 | 返回类型 | 要求
h(k) | std::size_t | 返回值在程序执行期间仅依赖于 k 的值。所有在程序执行内执行的 h(k) 的求值对 k 的相同值生成相同结果。 a!=b 的情况下 h(a)==h(b) 的概率应当趋近于 1.0/ std::numeric_limits < std::size_t >::max()。
h(u) | std::size_t | 不修改 u

标准库

hash
(C++11)
 散列函数对象
(类模板)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2291 | C++11 | 在所有情况下要求对相同参数的相同结果 | 仅在单次执行内要求


C++ 具名要求：老式输入迭代器 (LegacyInputIterator)

< cpp‎ | named req

老式输入迭代器 (LegacyInputIterator) 是能从所指向元素进行读取的老式迭代器 (LegacyIterator) 。老式输入迭代器 (LegacyInputIterator) 仅保证单趟算法的有效性：一旦自增老式输入迭代器 (LegacyInputIterator) i，则所有其先前值的副本都可能失效。

要求

若满足下列条件，则类型 It 满足老式输入迭代器 (LegacyInputIterator)

  • 类型 It 满足老式迭代器 (LegacyIterator)
  • 类型 It 满足可相等比较 (EqualityComparable)

并且，给定

  • i 和 j，为 It 或 const It 类型的值
  • reference，为 std::iterator_traits <It>::reference 所代表的类型
  • value_type，为 std::iterator_traits <It>::value_type 所代表的类型

则下列表达式必须合法且拥有其指定的效果

表达式 | 返回 | 等价表达式 | 注解
i != j | 可按语境转换到 bool | !(i == j) | 前条件：(i, j) 在 == 的定义域中。
*i reference，可转换到 value_type 若 i == j 与 (i, j) 在 == 的定义域中，则这等价于 *j。

前条件：i 可解引用。

表达式 (void)*i, *i 等价于 *i。
i->m | (*i).m | 前条件：i 可解引用。
++i It&

前条件：i 可解引用

后条件：i 可解引用或 i 为末尾后迭代器。

后条件：不再要求任何 i 的先前值的副本是可解引用的，或在 == 的定义域内。
(void)i++ | (void)++i
*i++ 可转换到 value_type value_type x = *i;

++i;

return x;

注解

“在 == 的定义域内”的意思是，两个迭代器值之间定义了相等比较。对于输入迭代器，相等比较不需要对所有值定义，且 == 的定义域中的值的集合可能随时间而改变。

对于并非同时为老式向前迭代器 (LegacyForwardIterator) 的输入迭代器，其 reference 类型不必是引用类型：解引用输入迭代器可以返回一个代理对象，或以值返回 value_type 本身（如 std::istreambuf_iterator 的情况）。

概念

为了定义 std::iterator_traits，定义了以下仅用于阐释的概念：

template<class I>

concept __LegacyInputIterator =
__LegacyIterator<I> && std::equality_comparable<I> && requires(I i) {
typename std::incrementable_traits<I>::difference_type;
typename std::readable_traits<I>::value_type;
typename std::common_reference_t<std::iter_reference_t<I>&&,
typename std::readable_traits<I>::value_type&>;
*i++;
typename std::common_reference_t<decltype(*i++)&&,
typename std::readable_traits<I>::value_type&>;
requires std::signed_integral<typename std::incrementable_traits<I>::difference_type>;

};

其中仅用于阐释的概念 __LegacyIterator 描述于 LegacyIterator#概念。

 (C++20 起)

参阅

input_iterator (C++20) | 指定类型为输入迭代器，即可读取其所引用的值，且可前/后自增 (概念)
迭代器库 | 提供迭代器的定义、迭代器表征、适配器及工具函数


C++ 具名要求：老式迭代器 (LegacyIterator)

< cpp‎ | named req

老式迭代器 (LegacyIterator) 要求描述可以用来标识和遍历容器中的元素的类型。

老式迭代器 (LegacyIterator) 是用于其他迭代器类型的基础集合：老式输入迭代器 (LegacyInputIterator) 、老式输出迭代器 (LegacyOutputIterator) 、老式向前迭代器 (LegacyForwardIterator) 、老式双向迭代器 (LegacyBidirectionalIterator) 及老式随机访问迭代器 (LegacyRandomAccessIterator) 。可以把迭代器想象成指针的抽象。

要求

若下列条件成立，则类型 It 满足老式迭代器 (LegacyIterator)

  • 类型 It 满足可复制构造 (CopyConstructible) ，且
  • 类型 It 满足可复制赋值 (CopyAssignable) ，且
  • 类型 It 满足可析构 (Destructible)
  • 类型 It 的左值满足可交换 (Swappable) ，且
  • std::iterator_traits <It> 拥有成员 typedef value_type、difference_type、reference、pointer 和 iterator_category 且

给定

  • 类型 It 的左值 r，

下列表达式必须合法，且拥有其指定的效果：

表达式 | 返回类型 | 前条件
*r | 未指明 | r 可解引用（见下文）
++r | It& | r 可增（表达式 ++r 的行为有定义）

可解引用的迭代器

表达式 *i 的行为得到定义的迭代器被称作可解引用（dereferenceable）。

下列情况下的迭代器不可解引用

  • 它们是末尾后迭代器（包括数组末尾后面一个位置的指针）或起始前迭代器。在特定实现中这些迭代器可能可解引用，但库从不假设它们能。
  • 它们是孤立迭代器，即是说，没有关联到任何序列的迭代器。空指针，以及默认构造的指针（保有不确定的值）是孤立的。
  • 在它们所指代的序列上，它们已经因使迭代器失效的操作之一而失效了。

概念

为了定义 std::iterator_traits，定义了以下仅用于阐释的概念。

template<class I>

concept __LegacyIterator =
requires(I i) {
{ *i } -> __Referenceable;
{ ++i } -> std::same_as<I&>;
{ *i++ } -> __Referenceable;

} && std::copyable<I>;

其中仅用于阐释的概念 __Referenceable<T> 当且仅当 T& 是合法类型时得到满足（特别是 T 必须不是 void）。

 (C++20 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3420 | C++20 | 仅用于阐释的概念首先检查 copyable | 仅若 requires 表达式返回 true 才检查 copyable

参阅

input_or_output_iterator (C++20) | 指定该类型对象可以自增且可以解引用 (概念)
迭代器库 | 提供迭代器的定义、迭代器表征、适配器及工具函数


C++ 具名要求：可小于比较 (LessThanComparable)

< cpp‎ | named req

类型必须能使用 < 运算符且结果应当具有标准语义。

要求

以下情况下，类型 T 满足可小于比较 (LessThanComparable) ：

给定

  • T 或 const T 类型的表达式 a、b 与 c

下列表达式必须合法并拥有其指定的效果

表达式 返回值 要求
a < b 可隐式转换为 bool 建立严格弱序关系，即具有下列属性：
  • 对于所有 a，!(a < a)
  • 若 a < b 则 !(b < a)
  • 若 a < b 且 b < c 则 a < c
  • 定义 equiv(a, b) 为 !(a < b) && !(b < a)，若 equiv(a, b) 且 equiv(b, c)，则 equiv(a, c)

注解

为满足此要求，没有内建比较运算符的类型必须提供用户定义的 operator<。

对于既可相等比较 (EqualityComparable) 又可小于比较 (LessThanComparable) 的类型，C++ 标准库在相等（即表达式 a == b 的值）和等价（即表达式 !(a < b) && !(b < a) 的值）间做出区别。

参阅

Compare比较
 建立顺序关系的二元谓词 (BinaryPredicate)
(具名要求)


C++ 具名要求：字面类型 (LiteralType)

< cpp‎ | named req

指明一个类型为字面类型。字面类型是 constexpr 变量所拥有的类型，且能通过 constexpr 函数构造、操作及返回它们。

注意：标准中并没有定义具有这个名字的具名要求。这是核心语言所定义的一种类型类别。将它作为具名要求包含于此只是为了保持一致性。

要求

字面类型是下列之一：

  • 可为 cv 限定的 void （从而 constexpr 函数能返回 void ）；
 (C++14 起)
  • 标量类型；
  • 引用类型；
  • 字面类型的数组；
  • 可有 cv 限定的类类型，并拥有下列全部属性：
  • 拥有平凡 (C++20 前) constexpr (C++20 起)析构函数，
  • 是以下之一
  • 聚合类型，
  • 或拥有至少一个 constexpr 构造函数（可为模板）且非复制或移动构造函数，
  • 或为闭包类型
 (C++17 起)
  • 对于联合体，至少有一个非静态数据成员是非 volatile 字面类型，
  • 对于非联合体，所有非静态数据成员和基类是非 volatile 字面类型。
 (C++17 起)
  • 所有非静态数据成员和基类是非 volatile 字面类型。
 (C++17 前)

参数

扩展字符串字面量的字面类型：

#include <iostream>
#include <stdexcept>

class conststr
{
    const char* p;
    std::size_t sz;
public:
    template<std::size_t N>
    constexpr conststr(const char(&a)[N]) : p(a), sz(N - 1) {}

    constexpr char operator[](std::size_t n) const
    {
        return n < sz ? p[n] : throw std::out_of_range("");
    }
    constexpr std::size_t size() const { return sz; }
};

constexpr std::size_t countlower(conststr s, std::size_t n = 0,
                                             std::size_t c = 0)
{
    return n == s.size() ? c :
           s[n] >= 'a' && s[n] <= 'z' ? countlower(s, n + 1, c + 1) :
                                        countlower(s, n + 1, c);
}

// 要求编译时常量的输出函数，为测试用
template<int n>
struct constN
{
    constN() { std::cout << n << '\n'; }
};

int main()
{
    std::cout << "the number of lowercase letters in \"Hello, world!\" is ";
    constN<countlower("Hello, world!")>(); // 隐式转换成 conststr
}

输出：

the number of lowercase letters in "Hello, world!" is 9

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1951 | C++11 (类类型) C++14 (void) | 仍不明确 cv 限定的 void 及类类型是否字面类型 | 它们是

参阅

is_literal_type
(C++11)(C++17 中弃用)(C++20 中移除)
 检查类型是否为字面类型
(类模板)


C++ 具名要求：可锁定 (Lockable)

< cpp‎ | named req

可锁定 (Lockable) 要求扩展基本可锁定 (BasicLockable) 要求，以包含有意图的锁定。

要求

  • 基本可锁定 (BasicLockable)

对于要为可锁定 (Lockable) 的类型 L ，它必须满足以上还有以下的条件：

表达式 | 效果 | 返回值
m.try_lock() | 试图为当前执行代理（线程、进程、任务）取得锁，而不阻塞。若抛异常，则不取得锁。 | 若取得锁则为 true ，否则为 false

注解

try_lock 成员函数在成功时在 m 上获得非共享锁。

参阅

  • 线程支持库
  • 互斥体 (Mutex)
  • 基本可锁定 (BasicLockable)
  • 可定时锁定 (TimedLockable)


C++ 具名要求：可移动赋值 (MoveAssignable) (C++11 起)

< cpp‎ | named req

指定该类型的实例可以从右值实参赋值。

要求

若满足下列条件，则类型 T 满足可移动赋值 (MoveAssignable) ：

给定

  • T 类型的可修改左值表达式 t
  • T 类型的右值表达式 rv

下列表达式必须合法并拥有其指定的效果

表达式 | 返回类型 | 返回值 | 后条件
t = rv | T& | t | 若 t 与 rv 不指代同一对象，则 t 的值等价于 rv 在赋值前的值。 rv 的新值未指定

注解

类型不必为满足此类型要求而实现移动赋值运算符：按值或按 const Type& 接收其参数的复制赋值运算符会绑定到右值实参。

若可移动赋值 (MoveAssignable) 类实现了移动赋值运算符，则它亦可实现移动语义，以获得“rv 在赋值后的值未指定”这一事实的优势。

参阅

is_move_assignableis_trivially_move_assignableis_nothrow_move_assignable (C++11)(C++11)(C++11) | 检查类型是否有拥有移动赋值运算符 (类模板)
assignable_from (C++20) | 指定一个类型能从另一类型赋值 (概念)


C++ 具名要求：可移动构造 (MoveConstructible) (C++11 起)

< cpp‎ | named req

指定该类型的实例可以从一个右值实参构造。

要求

以下情况下，类型 T 满足可移动构造 (MoveConstructible) ：

给定

  • T 类型的右值表达式 rv
  • 任意标识符 u

下列表达式必须合法且拥有其指定的效果

表达式 | 后条件
T u = rv; | u 的值等于 rv 在初始化前的值。rv 的新值未指明。
T(rv) | T(rv) 的值等于 rv 在初始化前的值。rv 的新值未指明。

注解

类不必为满足此要求而实现移动构造函数：接收 const T& 实参的复制构造函数也能绑定右值表达式。

若可移动构造 (MoveConstructible) 类实现了移动构造函数，则它亦可实现移动语义，以从“构造后 rv 的值未指明”的事实中获利。

参阅

is_move_constructibleis_trivially_move_constructibleis_nothrow_move_constructible (C++11)(C++11)(C++11) | 检查类型是否能从右值引用构造 (类模板)
move_constructible (C++20) | 指定能移动构造一个类型的对象 (概念)


C++ 具名要求：可移动插入 (MoveInsertable) (C++11 起)

< cpp‎ | named req

指定该类型的对象能以给定的分配器，从一个该类型的右值构造到未初始化存储之中。

要求

以下情况下，类型 T 可移动插入 (MoveInsertable) 进容器 X（其 value_type 等同于 T）：给定

A | 分配器类型
m | A 类型的左值
p | 容器所准备的 T* 类型的指针
rv | T 类型的右值表达式

其中 X::allocator_type 等同于 std::allocator_traits <A>::rebind_alloc<T>，

下列表达式为良构：

std::allocator_traits<A>::construct(m, p, rv);

并且求值后，*p 的值等价于 rv 先前保有的值（rv 保持有效，但处于未指明的状态）。

若 X 非知分配器或为 std::basic_string 特化，则如同 A 就是 std::allocator<T> 一样进行定义，但并不需要创建分配器对象，且不会实例化用户定义的 std::allocator 的特化。

注解

若 A 为 std::allocator <T>，则这将调用布置 new，如同用 ::new((void*)p) T(rv) (C++20 前)std::construct_at(p, rv) (C++20 起)。

若使用了 std::allocator <T> 或类似的分配器，则该类不必为满足此类型要求而实现移动构造函数：接收 const T& 实参的复制构造函数能绑定右值表达式。若可移动插入 (MoveInsertable) 的类实现了移动构造函数，则它可能亦实现移动语义以利用“构造后 rv 的值未指明”的事实。

尽管 C++23 前要求在构造 std::basic_string 的元素时使用定制的 construct，所有实现都使用默认机制。P1072R10 更正了该要求以匹配既存实现。

参阅

可复制插入 (CopyInsertable)


C++ 具名要求：互斥体 (Mutex)

< cpp‎ | named req

互斥体 (Mutex) 要求扩展可锁定 (Lockable) 要求以包含线程间同步。

要求

  • 可锁定 (Lockable)
  • 可默认构造 (DefaultConstructible)
  • 可析构 (Destructible)
  • 不可复制
  • 不可移动

对于互斥 (互斥体 (Mutex) ) 类型的对象 m ：

  • 表达式 m.lock() 有下列属性
  • 表现原子操作。
  • 阻塞调用方线程，直到能获得互斥的排他性所有权为止。
  • 先于同一互斥上的 m.unlock() 的操作同步于此锁操作（等价于释放获得 std::memory_order ）
  • 若调用方线程已占有互斥，则行为未定义（除非 m 是 std::recursive_mutex 或 std::recursive_timed_mutex ）
  • 错误时可能抛出 std::system_error 类型的异常，拥有下例错误码：
  • 若调用方线程无要求的权限，则为 std::errc::operation_not_permitted
  • 若实现检测出此线程将导致死锁，则为 std::errc::resource_deadlock_would_occur
  • 若互斥已被锁，则为 std::errc::device_or_resource_busy
 (C++17 前)
  • 表达式 m.try_lock() 拥有下列属性
  • 表现为原子操作。
  • 试图为调用方线程获得互斥的排他性所有权，而不阻塞。若未获得所有权，则立即返回。允许此函数虚假地失败并返回，即使互斥当前未为另一线程所占有。
  • 若 try_lock() 成功，则先于同一对象上 unlock() 的操作同步于此操作（等价于释放获得 std::memory_order ）。 lock() 不与失败的 try_lock() 同步。
  • 不抛异常。
  • 表达式 m.unlock() 拥有下列属性
  • 表现为原子操作。
  • 释放调用方线程的互斥所有权，并同步于同一对象上的后继的成功锁操作。
  • 若调用方线程不占有互斥，则行为未定义。
  • 不抛异常。
  • 单个互斥上的所有锁和解锁操作以能视为一个原子变量的修改顺序的单独全序发生：顺序对此单独互斥是特定的。

库类型

下列标准库类型满足互斥体 (Mutex) ：

  • std::mutex
  • std::recursive_mutex
  • std::timed_mutex
  • std::recursive_timed_mutex
  • std::shared_mutex

参阅

  • 线程支持库
  • 可锁定 (Lockable)
  • 定时互斥体 (TimedMutex)


C++ 具名要求：可空指针 (NullablePointer) (C++11 起)

< cpp‎ | named req

指定该类型是能与 std::nullptr_t 对象进行比较的指针式类型。

要求

类型必须满足所有下列要求：

  • 可相等比较 (EqualityComparable)
  • 可默认构造 (DefaultConstructible)
  • 可复制构造 (CopyConstructible)
  • 可复制赋值 (CopyAssignable)
  • 可析构 (Destructible)

此外，此类型的一个值初始化的对象必须产生该类型的空值（null）。空值必须仅与自身等价。该类型的默认初始化可拥有不确定值。

此类型必须可按语境转换成 bool。若其值等价于其空值则此转换的效果为 false，否则为 true。

此类型进行的操作均不可抛异常。

此类型必须满足下列额外的表达式，给定该类型的两个值 p 与 q，以及 np 是 std::nullptr_t 类型的值（可有 const 限定）：

表达式 | 效果
Type p(np); Type p = np; | 之后 p 等价于 nullptr。
Type(np) | 等价于 nullptr 的临时对象。
p = np | 必须返回 Type&，而且之后 p 等价于 nullptr。
p != q | 必须返回能按语境转换成 bool 的值。效果为 !(p == q)。
p == np np == p | 必须返回能按语境转换成 bool 的值。效果为 (p == Type())。
p != np np != p | 必须返回能按语境转换成 bool 的值。效果为 !(p == np)。

注解

注意，对可空指针 (NullablePointer) 类型不要求解引用（operator* 或 operator->）。满足这些要求的最小化类型是

class handle {
    int id = 0;
public:
    handle() = default;
    handle(std::nullptr_t) { }
    explicit operator bool() const { return id != 0; }
    friend bool operator==(handle l, handle r) { return l.id == r.id; }
    friend bool operator!=(handle l, handle r) { return !(l == r); }
    // 或仅一个预置的 operator== (C++20 起)
};

标准库

下列类型必须满足可空指针 (NullablePointer) ：

  • 每个分配器 (Allocator) 类型 X 的成员类型 X::pointer、X::const_pointer、X::void_pointer 及 X::const_void_pointer
  • std::unique_ptr 的成员类型 X::pointer
  • 类型 std::exception_ptr


C++ 具名要求：数值类型 (NumericType)

< cpp‎ | named req

指定能用于 std::valarray 模板参数的类型。

要求

对于作为数值类型 (NumericType) 的类型 T ，它必须是无 cv 限定的对象类型且：

  • 满足可默认构造 (DefaultConstructible) 、可复制构造 (CopyConstructible) 、可复制赋值 (CopyAssignable) 及可析构 (Destructible) 要求。
  • T 上的操作均不抛出异常


C++ 具名要求：老式输出迭代器 (LegacyOutputIterator)

< cpp‎ | named req

老式输出迭代器 (LegacyOutputIterator) 是能写入所指向元素的老式迭代器 (LegacyIterator) 。

一个实现老式输出迭代器 (LegacyOutputIterator) 的类型的例子是 std::ostream_iterator。

当老式向前迭代器 (LegacyForwardIterator) 、老式双向迭代器 (LegacyBidirectionalIterator) 或老式随机访问迭代器 (LegacyRandomAccessIterator) 在自身的要求之外还满足老式输出迭代器 (LegacyOutputIterator) 的要求时，它即被描述为可变的（mutable）。

要求

以下情况下，类型 X 满足老式输出迭代器 (LegacyOutputIterator)

  • 类型 X 满足老式迭代器 (LegacyIterator)
  • X 是类类型或指针类型

且，给定

  • o，是输出迭代器对应的可写入类型的值（可以有多种可写入的类型，例如 operator= 是模板的情况。并没有像输入迭代器的 value_type 那种记号）
  • r，为 X 类型的左值，

则下列表达式必须合法且拥有其指定的效果

表达式 | 返回 | 等价表达式 | 前条件 | 后条件 | 注解
*r = o | （不使用） | r 可解引用 | r 可自增 | 在此操作后不要求 r 可解引用，且不再要求任何 r 的先前值的副本可解引用或可自增。
++r | X& | r 可自增 | r 与 ++r 指代同一迭代器对象，r 可解引用或为末尾后迭代器 | 在此操作后不要求 r 可自增，且不再要求任何 r 的先前值的副本可解引用或可自增。
r++ 可转换到 const X& X temp = r;

++r;
return temp;
*r++ = o （不使用） *r = o;

++r;

注解

operator* 对于输出迭代器的仅有的合法用法是在赋值的左侧：operator* 可以返回一个代理对象，它定义了成员 operator=（可以是模板）

可以不对输出迭代器定义相等和不相等。即使定义了 operator==，x == y 也不需要隐含 ++x == ++y。

通过输出迭代器的同一值进行的赋值只会发生一次：输出迭代器上的算法必须是单趟算法。

预期通过输出迭代器的赋值与自增交替进行。双重自增是未定义行为（C++ 标准当前声称双重自增得到支持，这与 STL 文档相反；此为 LWG2035）

允许纯粹仅支持输出的迭代器声明其 iterator_traits<X>::value_type、iterator_traits<X>::difference_type、iterator_traits<X>::pointer 与 iterator_traits<X>::reference 为 void（如 std::back_insert_iterator 这样的迭代器正如此）。

标准库

下列的标准库迭代器是输出迭代器而非向前迭代器：

  • std::ostream_iterator
  • std::ostreambuf_iterator
  • std::insert_iterator
  • std::back_insert_iterator
  • std::front_insert_iterator

参阅

output_iterator (C++20) | 指定类型为给定的值类型的输出迭代器，即可向其写入该类型的值，且可前/后自增 (概念)
迭代器库 | 提供迭代器的定义、迭代器表征、适配器及工具函数


C++ 具名要求：简旧数据类型 (PODType)

< cpp‎ | named req

指定类型为 POD（Plain Old Data，简旧数据）类型。这表示该类型与用于 C 程序语言的类型兼容，即能直接以其二进制形式与 C 库交互。

注意：标准中并没有定义具有这个名字的具名要求。这是核心语言所定义的一种类型类别。将它作为具名要求包含于此只是为了保持一致性。

此类型要求在 C++ 标准中已弃用。其所有使用都已被替换成更为斟酌过的类型要求，例如平凡类型 (TrivialType) 。

 (C++20 起)

要求

以下之一：

  • 标量类型；
  • 满足下列要求的类类型（class 或 struct 或 union）：
  • 聚合类型；
  • 没有非 POD 的非静态成员；
  • 没有引用类型的成员；
  • 没有用户定义的复制构造函数；
  • 没有用户定义的析构函数
 (C++11 前)
  • 为平凡类型；
  • 为标准布局类型；
  • 没有非 POD 的非静态成员；
 (C++11 起)
  • 这种类型的数组。

参阅

is_pod
(C++11)(C++20 中弃用)
 检查类型是否为简旧数据（POD）类型
(类模板)


C++ 具名要求：谓词 (Predicate)

< cpp‎ | named req

谓词 (Predicate) 要求描述了返回可作为 bool 测试的值的可调用 (Callable) 体。

谓词 (Predicate) 常与接收输入数据（单独的对象/容器）和谓词的算法一起使用，它会针对输入数据进行调用以决定进一步的动作。C++ 标准库中的一些使用谓词的例子有：

  • std::all_of、std::any_of、std::none_of 接收一组元素和一个谓词为其输入。在每个单独的输入元素上调用谓词，并且当谓词分别对全部/任一/无元素返回 true 时返回 true。
  • std::find_if 接受元素的序列和一个谓词。返回序列中首个谓词对其返回 true 的元素。

上面给出的算法设施描述是简陋的，并且有意地简要解释谓词 (Predicate) 。对于详细信息可查阅各自的页面。

换言之，若算法接收一个谓词 (Predicate) pred 和一个迭代器 first，则它应该能经由类似 if(pred(*first)) {...} 的构造，测试迭代器 first 所指向的类型。

函数对象 pred 不应当通过解引用的迭代器运用任何非 const 函数。此函数对象可以是函数指针，或者拥有适合的函数调用运算符的类型的对象。

要求

  • 函数对象 (FunctionObject)
本节未完成
原因：更好地描述实际要求


C++ 具名要求：老式随机访问迭代器 (LegacyRandomAccessIterator)

< cpp‎ | named req

老式随机访问迭代器 (LegacyRandomAccessIterator) 是能在常数时间内移动到指向任何元素的老式双向迭代器 (LegacyBidirectionalIterator) 。

指向数组元素的指针满足所有老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。

要求

类型 It 满足老式随机访问迭代器 (LegacyRandomAccessIterator) ，若

  • 类型 It 满足老式双向迭代器 (LegacyBidirectionalIterator)

且给定

  • value_type，为 std::iterator_traits <It>::value_type 所指代的类型
  • difference_type，为 std::iterator_traits <It>::difference_type 所指代的类型
  • reference，为 std::iterator_traits <It>::reference 所指代的类型
  • i、a、b，为 It 或 const It 类型的对象
  • r，为 It& 类型的值
  • n，为 difference_type 类型的整数

则下列表达式必须合法且拥有其指定的效果

表达式 | 返回类型 | 操作语义 | 注意
r += n It& difference_type m = n;

if (m >= 0) while (m--) ++r;
else while (m++) --r;
return r;
  • n 可为正或负
  • 复杂度为常数（即实现不能按操作语义所示实际执行循环）
a + n

n + a

 It It temp = a;

return temp += n;
  • n 可为正或负
  • a + n == n + a
r -= n | It& | return r += -n; | n 的绝对值必须在 difference_type 的可表示值范围内。
i - n It It temp = i;

return temp -= n;
b - a difference_type return n;

前条件：

  • 存在 difference_type 类型的值 n 满足 a+n==b

后条件：

  • b == a + (b - a)
i[n] | 可转换到 reference | *(i + n)
a < b 可按语境转换到 bool 等价于 return b - a > 0; 前条件：
  • 同 b - a

严格全序关系：

  • !(a < a)
  • 若 a < b 则 !(b < a)
  • 若 a < b 且 b < c 则 a < c
  • a < b 或 b < a 或 a == b
    （表达式恰有一者为 true）
a > b | 可按语境转换到 bool | b < a | 与 a < b 相反的全序关系
a >= b | 可按语境转换到 bool | !(a < b)
a <= b | 可按语境转换到 bool | !(a > b)

上述规则隐含了老式随机访问迭代器 (LegacyRandomAccessIterator) 亦实现可小于比较 (LessThanComparable) 。

可变（mutable）老式随机访问迭代器 (LegacyRandomAccessIterator) 是还额外满足老式输出迭代器 (LegacyOutputIterator) 要求的老式随机访问迭代器 (LegacyRandomAccessIterator) 。

概念

为了定义 std::iterator_traits，定义了以下仅用于阐释的概念：

template<class I>

concept __LegacyRandomAccessIterator =
__LegacyBidirectionalIterator<I> && std::totally_ordered<I> &&
requires(I i, typename std::incrementable_traits<I>::difference_type n) {
{ i += n } -> std::same_as<I&>;
{ i -= n } -> std::same_as<I&>;
{ i + n } -> std::same_as<I>;
{ n + i } -> std::same_as<I>;
{ i - n } -> std::same_as<I>;
{ i - i } -> std::same_as<decltype(n)>;
{ i[n] } -> std::convertible_to<std::iter_reference_t<I>>;

};

其中仅用于阐释的概念 __LegacyBidirectionalIterator 描述于 LegacyBidirectionalIterator#概念。

 (C++20 起)

参阅

random_access_iterator (C++20) | 指定 bidirectional_iterator 为随机访问迭代器，支持常数时间内的前进和下标访问 (概念)
迭代器库 | 提供迭代器的定义、迭代器表征、适配器及工具函数


C++ 具名要求：随机数分布 (RandomNumberDistribution)

< cpp‎ | named req

随机数分布 (RandomNumberDistribution) 是返回服从概率密度函数 p(x) 或离散概率分布 P(x
i) 的随机数的函数对象。

要求

类型 D 满足随机数分布 (随机数分布 (RandomNumberDistribution) ) ，若

  • D 满足可复制构造 (CopyConstructible)
  • D 满足可复制赋值 (CopyAssignable)

给定

  • T ， D::result_type 所指名的类型
  • P ， D::param_type 所指名的类型，它
  • 满足可复制构造 (CopyConstructible)
  • 满足可复制赋值 (CopyAssignable)
  • 满足可相等比较 (EqualityComparable)
  • 拥有一个构造函数，接收的参数与 D 的接收与分布参数相对应的参数的构造函数等同。
  • 拥有成员函数，其名称、类型、语义与 D 的每个返回分布参数的成员函数等同。
  • 声明成员 typedef using distribution_type = D;
  • d ， D 类型的值
  • x 与 y ， D 类型的（可能 const 的）值。
  • p ， P 类型的（可能 const 的）值
  • g 、 g1 、 g2 ，满足均匀随机位生成器 (UniformRandomBitGenerator) 的类型左值
  • os ， std::basic_ostream 特化的左值
  • is ， std::basic_istream 特化的左值

下列表达式必须合法且拥有其指定的效应

表达式 | 类型 | 注意 | 复﻿杂﻿度
D::result_type | T | 算术类型 | 编译时
D::param_type | P |  | 编译时
D() |  | 创建与其他默认构造的 D 不可区别的分布 | 常数
D(p) |  | 创建与从用以构造 p 的值直接构造的 D 不可区别的分布 | 同 p 的构造
d.reset() | void | 重置分布的初始状态。 d 上的下次到 operator() 的调用将不依赖任何引擎的先于 reset() 的产生的值。 | 常数
x.param() | P | 返回 p ，满足 D(p).param() == p | 不劣于 D(p)
d.param(p) | void | 后置条件： d.param() == p | 不劣于 D(p)
d(g) | T | 以同一 g 调用之的相继调用，所返回的数列随机分布，服从 d.param() 所参数化的分布 | 均摊常数次 g 的调用
d(g,p) | T | 以同一 g 调用之的相继调用，所返回的数列随机分布，服从 p 所参数化的分布 | 均摊常数次 g 的调用
x.min() | T | x 的 operator() 潜在返回值上的最大下界，由 x 的参数的当前值确定 | 常数
x.max() | T | x 的 operator() 潜在返回值上的最小上界，由 x 的参数的当前值确定 | 常数
x == y | bool | 建立等价关系。若 x.param() == y.param() ，且只要 g1 == g2 ，将来重复调用 x(g1) 与 y(g2) 所生成的无限数列就相等，则返回 true 。 | 常数
x != y | bool | !(x == y) | 常数
os << x | 到 os 类型的引用 | 写分布参数和内部状态的文本表示到 os 。不更改 os 的格式化标志和填充字符。 |
is >> d | 到 is 类型的引用 | 从读取自 is 的数据还原分布参数和内部状态。不更改 is 的格式化标志。数据必须用带相同本地环境、 CharT 和 Traits 流模板形参的流写入，否则行为未定义。若遇到坏的输入，则调用 is.setstate(std::ios::failbit) ，它可以抛出 std::ios_base::failure 。该情况下不更改 d 。 |

注意

分布对象的参数可用 d.param(p) 永久更改，或用 d(g,p) 只在单次 operator() 调用期间更改。

调用分布的 const 成员函数和 os << d 不影响重复 d(g) 所产生的数列。

标准库

下列标准库组件满足随机数分布 (RandomNumberDistribution)

uniform_int_distribution (C++11) | 产生在一个范围上均匀分布的整数值 (类模板)
uniform_real_distribution (C++11) | 产生在一个范围上均匀分布的实数值 (类模板)
bernoulli_distribution (C++11) | 产生伯努利分布上的 bool 值。 (类)
binomial_distribution (C++11) | 产生二项分布上的整数值。 (类模板)
negative_binomial_distribution (C++11) | 产生负二项分布上的整数值。 (类模板)
geometric_distribution (C++11) | 产生几何分布上的整数值。 (类模板)
poisson_distribution (C++11) | 产生泊松分布上的整数值。 (类模板)
exponential_distribution (C++11) | 产生指数分布上的实数值。 (类模板)
gamma_distribution (C++11) | 产生 Γ 分布上的实数值 (类模板)
weibull_distribution (C++11) | 产生威布尔分布上的实数值。 (类模板)
extreme_value_distribution (C++11) | 产生极值分布上的实数值。 (类模板)
normal_distribution (C++11) | 产生标准正态（高斯）分布上的实数值。 (类模板)
lognormal_distribution (C++11) | 产生对数正态分布上的实数值。 (类模板)
chi_squared_distribution (C++11) | 产生 χ2 分布上上的实数值。 (类模板)
cauchy_distribution (C++11) | 产生柯西分布上的实数值。 (类模板)
fisher_f_distribution (C++11) | 产生费舍尔 F 分布上的实数值。 (类模板)
student_t_distribution (C++11) | 产生学生 t 分布上的实数值。 (类模板)
discrete_distribution (C++11) | 产生离散分布上的随机整数。 (类模板)
piecewise_constant_distribution (C++11) | 产生分布在常子区间上的实数值。 (类模板)
piecewise_linear_distribution (C++11) | 产生分布在定义的子区间上的实数值。 (类模板)


C++ 具名要求：随机数引擎 (RandomNumberEngine)

< cpp‎ | named req

随机数引擎是函数对象，返回无符号整数值，它使得可能结果范围中的每个值拥有（理想的）相等概率。

任何随机数引擎亦为均匀随机位生成器 (UniformRandomBitGenerator) ，从而可能插入任何随机数分布，以获得随机数（正式而言是随机变量）。

要求

满足均匀随机位生成器 (UniformRandomBitGenerator) 的类型 E 会另外满足随机数引擎 (随机数引擎 (RandomNumberEngine) ) ，若给定

  • T ， E::result_type 所指名的类型
  • s ， T 类型值
  • e ， E 类型的非 const 值
  • v ， E 类型左值
  • x 与 y ， E 类型的可能为 const 的值
  • q ，某满足种子序列 (SeedSequence) 的类型的左值
  • z ， unsigned long long 类型值
  • os ，输出流
  • is ，输入流

而下列表达式合法并拥有其指定的效果：

表达式 | 返回类型 | 要求
E() |  | 创建引擎，其状态与所有其他默认构造的 E 类型引擎相同。
E(x) |  | 创建引擎，其状态与 x 的相同。
E(s) |  | 创建引擎，其初始状态为 s 所确定。
E(q) |  | 创建引擎，其初始状态以单次调用 q.generate 确定。
e.seed() | void | 设置 e == E() 。
e.seed(s) | void | 设置 e == E(s) 。
e.seed(q) | void | 设置 e == E(q) 。
e() | T | 返回闭区间 [E::min(), E::max()] 中的值。拥有均摊常数复杂度。
e.discard(z) | void | 令 e 的状态前进，如同通过 z 次连续调用 e() 。
x == y | bool | 若 x 与 y 在相同状态（满足将来对 x() 和 y() 的重复调用将产生等同的数列）则为 true 。否则为 false 。
x != y | bool | !(x == y)
os << x | decltype(os)& | 将 x 当前状态的文本表示写入 os 。输出中，相邻的数以一或多个空格字符分隔。若 os 的 fmtflags 未设为 ios_base::dec|ios_base::left ，则行为可能未定义。
is >> v | decltype(is)& | 从 is 读取 v 当前状态的文本表示，满足若先前通过 os << x 写入该状态，则 x == v 。若 is 的 fmtflags 未设为 ios_base::dec ，则行为可能未定义。

标准库

下列标准库设施满足随机数引擎 (随机数引擎 (RandomNumberEngine) ) ：

linear_congruential_engine (C++11) | 实现线性同余算法 (类模板)
mersenne_twister_engine (C++11) | 实现梅森缠绕器算法 (类模板)
subtract_with_carry_engine (C++11) | 实现带进位减（一种延迟斐波那契）算法 (类模板)
discard_block_engine (C++11) | 舍弃随机数引擎的某些输出 (类模板)
independent_bits_engine (C++11) | 将一个随机数引擎的输出打包为指定位数的块 (类模板)
shuffle_order_engine (C++11) | 以不同顺序发送一个随机数引擎的输出 (类模板)

下列标准库设施满足均匀随机位生成器 (UniformRandomBitGenerator) 但不满足随机数引擎 (随机数引擎 (RandomNumberEngine) ) ：

random_device
(C++11)
 使用硬件熵源的非确定随机数生成器
(类)


C++ 具名要求：随机数引擎适配器 (RandomNumberEngineAdaptor)

< cpp‎ | named req

随机数引擎适配器 (RandomNumberEngineAdaptor) 是变换另一随机数引擎 (RandomNumberEngine) 输出的随机数引擎 (RandomNumberEngine) ，前者被称为基引擎。

要求

给定

  • B ，随机数引擎 (RandomNumberEngine)
  • b ， B 类型对象
  • A ，适配 B 为基引擎的随机数引擎适配器 (RandomNumberEngineAdaptor)
  • a ， A 类型对象
函数 | 语义
A::A(); | 如同以其默认构造函数初始化基引擎。
bool operator==(const A& lhs, const A& rhs); | 返回 lhs 的基引擎是否等于 rhs 的基引擎
A::A(result_type s); | 以 s 初始化基引擎。
template<class Sseq> A::A(Sseq& q); | 以 q 初始化基引擎。
void seed(); | 调用 b.seed() 。
void seed(result_type s); | 调用 b.seed(s) 。
template<class Sseq> void seed(Sseq& q); | 调用 b.seed(q) 。

还有

  • A 的每个函数的复杂度不超出 B 的对应函数的复杂度
  • A 的状态包含 B 的状态
  • A 的状态大小不小于 b 的大小
  • 复制 A 的状态包含复制 B 的状态
  • A 的文本表示包含 B 的文本表示

标准库

下列标准库设施满足随机数引擎适配器 (RandomNumberEngineAdaptor) ：

discard_block_engine (C++11) | 舍弃随机数引擎的某些输出 (类模板)
independent_bits_engine (C++11) | 将一个随机数引擎的输出打包为指定位数的块 (类模板)
shuffle_order_engine (C++11) | 以不同顺序发送一个随机数引擎的输出 (类模板)


C++ 具名要求：正则表达式特征 (RegexTraits)

< cpp‎ | named req

正则表达式特征 (RegexTraits) 是特性类，它在用作 std::basic_regex 的模板类型形参时，对给定字符类型抽象所需的操作。

要求

给定

  • CharT ，字符类型
  • X ， CharT 类型的正则表达式特性 (正则表达式特征 (RegexTraits) ) 类型
  • u ， X 类型对象
  • v ， const X 类型对象
  • p ， const CharT* 类型值
  • I1, I2 ，输入迭代器
  • F1, F2 ，向前迭代器
  • c ， const CharT 类型值
  • s ， X::string_type 类型对象
  • cs ， const X::string_type 类型对象
  • b ， bool 类型值
  • I ， int 类型值
  • cl ， X::char_class_type 类型对象
  • loc ， X::locale_type 类型对象

表达式 | 返回类型 | 语义
X::char_type | CharT | 用于指代字符类型
X::string_type | std::basic_string <CharT>
X::locale_type | 表示特性类所用本地环境的可复制构造 (CopyConstructible) 类型。
X::char_class_type | 表示特定字符分类的位掩码类型 (BitmaskType) 。
X::length(p) | std::size_t | 返回满足 p[i] == 0 的最小 i 。复杂度与 i 成线性。
v.translate(c) | X::char_type | 返回一个字符，使得对于任何被认为等价于 c 的字符 d ，有 v.translate(c) == v.translate(d) 。
v.translate_nocase(c) | X::char_type | 返回一个字符，使得对于任何被认为忽略大小写就等价于 c 的字符 C ，有 v.translate_nocase(c) == v.translate_nocase(C) 。
v.transform(F1, F2) | X::string_type | 返回：迭代器范围 [F1, F2) 所指代的字符序列的排序关键，使得若字符序列 [G1, G2) 排序于字符序列 [H1, H2) 前，则 v.transform(G1, G2) < v.transform(H1, H2) 。
v.transform_primary(F1, F2) | X::string_type | 返回迭代器范围 [F1, F2) 所指代的排序关键，使得若字符序列 [G1, G2) 在忽略大小写的情况下排序于字符序列 [H1, H2) 前，则 v.transform_primary(G1, G2) < v.transform_primary(H1, H2) 。
v.lookup_collatename(F1, F2) X::string_type 返回：
  • 空字符串，若字符序列不是合法的对照元素
  • 否则为字符序列，表示由迭代器范围 [F1, F2) 所指带的字符序列组成的对照元素
v.lookup_classname(F1, F2, b) X::char_class_type
  • 转换迭代器范围所指代的字符序列 [F1, F2) 为之后能传递给 isctype 的位掩码类型 (BitmaskType) 值
  • 能将从 lookup_classname 返回的值相互逐位或；结果值表示任一对应字符类中的成员关系
  • 若 b 为 true ，则返回的位掩码适于匹配字符而不考虑其大小写。
  • 若字符序列不是 X 所辨识的字符类名，则返回 ​0​ 。
  • 返回值应当独立于序列中字符的大小写。
v.isctype(c, cl) | bool | 返回： c 是否为 cl 所指代的字符类的成员。
v.value(c, I) int Returns:
  • 数位 c 在 I 中表示的值，若字符 c 为底 I 中合法的数位
  • 否则为 -1
u.imbue(loc) X::locale_type
  • 以 locale loc 感染 u
  • 返回 v 先前使用的 locale ，若存在。
v.getloc() | X::locale_type | 返回 v 先前使用的 locale ，若存在。

标准库

下列标准库满足正则表达式特性 (正则表达式特征 (RegexTraits) ) ：

template<> class regex_traits<char>;
template<> class regex_traits<wchar_t>;
 (C++11 起)
(C++11 起)


C++ 具名要求：可逆容器 (ReversibleContainer)

< cpp‎ | named req

可逆容器 (ReversibleContainer) 是拥有满足老式双向迭代器 (LegacyBidirectionalIterator) 或老式随机访问迭代器 (LegacyRandomAccessIterator) 要求的迭代器的容器 (Container) 。这些迭代器允许对可逆容器 (ReversibleContainer) 进行逆序迭代。

要求

X | 容器类型
T | 元素类型
a | X 类型对象

类型

表达式 | 返回类型 | 条件 | 复杂度
X::reverse_iterator | 值类型为 T 的迭代器类型 | reverse_iterator<iterator> | 编译时
X::const_reverse_iterator | 值类型为 T 的常迭代器类型 | reverse_iterator<const_iterator> | 编译时

方法

表达式 | 返回类型 | 条件 | 复杂度
a.rbegin() | reverse_iterator； 对常数 a 为 const_reverse_iterator | reverse_iterator(end()) | 常数
a.rend() | reverse_iterator ； 对常数 a 为 const_reverse_iterator | reverse_iterator(begin()) | 常数
a.crbegin() | const_reverse_iterator | const_cast<X const&>(a).rbegin() | 常数
a.crend() | const_reverse_iterator | const_cast<X const&>(a).rend() | 常数

示例

下列示例在（拥有随机访问迭代器的）vector 上逆序迭代。

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> v = {3, 1, 4, 1, 5, 9};

    for(std::vector<int>::reverse_iterator i = v.rbegin(); i != v.rend(); ++i) {
        std::cout << *i << '\n';
    }
}

输出：

9
5
1
4
1
3

标准库

  • std::array
  • std::deque
  • std::list
  • std::vector
  • std::map
  • std::multimap
  • std::set
  • std::multiset


C++ 具名要求：种子序列 (SeedSequence)

< cpp‎ | named req

种子序列 (SeedSequence) 是基于消费的整数数据范围，产生 0 ≤ i < 232
 范围中的无符号整数值 i 的对象。

要求

  • S 是种子序列 (种子序列 (SeedSequence) ) 。
  • q 是 S 的对象且 r 是 S 的潜在常对象。
  • T 为 result_type 。
  • ib 、 ie 是老式输入迭代器 (LegacyInputIterator) ，其 value_type 为至少 32 位的无符号整数值。
  • il 是一个 std::initializer_list <T> 。
  • rb 、 re 是可变 老式随机访问迭代器 (LegacyRandomAccessIterator) ，其 value_type 为至少 32 位的无符号整数值。
  • ob 是老式输出迭代器 (LegacyOutputIterator) 。
表达式 | 类型 | 注意 | 复杂度
S::result_type | T | 至少 32 位的无符号整数 | 编译时
S() |  | 创建拥有同 S 类型其他对象的默认值的种子序列 | 常数
S(ib,ie) |  | 创建基于 [ib,ie) 所提供输入位的种子序列 | O(ie-ib)
S(il) |  | 同 S(il.begin(), il.end()) |
q.generate(rb,re) | void | 以依赖初始提供值和潜在的到 generate 的先前调用的 32 位数量填充 [rb,re) 。若 rb == re 则不做任何事。 | O(re-rb)
r.size() | size_t | param 所复制的 32 位整数的量。 | 常数
r.param(ob) | void | 复制 32 位值，到若传递给 S 的构造函数则会重生成对象当前状态的 ob 。 | O(r.size())

参阅

  • std::seed_seq


C++ 具名要求：序列容器 (SequenceContainer)

< cpp‎ | named req

序列容器 (SequenceContainer) 是在线性排列中存储相同类型对象的容器 (Container) 。

要求

以下情况下，类型 X 满足序列容器 (SequenceContainer)

  • 类型 X 满足容器 (Container) ，且

给定

  • T，为 X 的元素类型
  • A，为 X 的分配器类型：若存在则为 X::allocator_type，否则为 std::allocator <T>
  • a，为 X 类型的左值表达式
  • p，a 中的有效常量迭代器
  • q，a 中的有效可解引用常量迭代器
  • q1 与 q2，为 a 中的两个有效常量迭代器，并使得 [q1, q2) 是有效范围
  • i 与 j，为老式输入迭代器 (LegacyInputIterator) ，使得 [i, j) 是有效范围，且各迭代器指代能隐式转换成 value_type 的对象
  • il，为 std::initializer_list <value_type> 类型的对象
  • n，为 X::size_type 类型的值
  • t，为 X::value_type 类型的左值或 const 右值
  • rv，为 X::value_type 类型的非 const 右值
  • Args：模板形参包
  • args：拥有模式 Arg&& 的函数形参包

下列表达式必须合法，且对除 std::array 之外的所有顺序容器均具有所指定的效果：

表达式 | 返回类型 | 效果 | 前条件 | 后条件
X(n, t)

X a(n, t)

 构造保有 n 个 t 的副本的容器 T 可复制插入 (CopyInsertable) 到 X std::distance (begin(),end()) == n
X(i, j)

X a(i, j)

 构造与范围 [i,j) 逐元素相等的顺序容器 T 从 *i 可就位构造 (EmplaceConstructible) 到 X 中

(仅对 std::vector)若各迭代器不是老式向前迭代器 (LegacyForwardIterator) ，则 T 必须可复制插入 (CopyInsertable)

 std::distance (begin(),end()) == std::distance (i,j)
X(il) | X(il.begin(), il.end())
a = il | X& | 将 il 所表示的范围赋值到 a 中[1] | T 可复制插入 (CopyInsertable) 且可复制赋值 (CopyAssignable) | a 的既存元素被销毁或被赋值
a.emplace(p,args) iterator 在 p 前插入以 std::forward <Args>(args) 构造的 T 类型的对象 T 可复制插入 (CopyInsertable)

(对 std::vector 与 std::deque) T 可移动赋值 (MoveAssignable) 且可移动插入 (MoveInsertable)

 返回指向由 args 构造到 a 中的元素的迭代器
a.insert(p,t) iterator 在 p 前插入 t 的副本 T 可复制插入 (CopyInsertable)

(对 std::vector 与 std::deque) T 可复制赋值 (CopyAssignable) 或可移动赋值 (MoveAssignable)

 返回指向插入到 a 中的 t 的副本的迭代器
a.insert(p,rv) iterator 在 p 前插入 rv 的副本，可能用移动语义 T 可移动插入 (MoveInsertable)

(对 std::vector 与 std::deque) T 可移动赋值 (MoveAssignable)

 返回指向插入到 a 中的 rv 的副本的迭代器
a.insert(p,n,t) | iterator | 插入 n 个 t 的副本到 p 之前 | T 可复制插入 (CopyInsertable) 且可复制赋值 (CopyAssignable) | 返回指向插入到 a 中的首元素的副本的迭代器，或当 n==0 时为 p
a.insert(p,i,j) iterator 插入 [i, j) 中元素的副本到 p 之前 T 可就位构造 (EmplaceConstructible) 且 i 与 j 不在 a 中

(仅对 std::vector)若迭代器不是老式向前迭代器 (LegacyForwardIterator) ，则 T 必须可移动插入 (MoveInsertable) 且可移动赋值 (MoveAssignable)

 [i,j) 中的每个迭代器被解引用一次。返回指向插入到 a 的首元素的副本的迭代器，或当 i==j 时为 p
a.insert(p, il) | iterator | a.insert(p,il.begin(),il.end()) | 返回指向插入到 a 中的首元素的副本的迭代器，或若 il 为空则为 p。
a.erase(q) | iterator | 擦除 q 所指向的元素 | (std::deque, std::vector) T 可移动赋值 (MoveAssignable) | 返回指向擦除前紧跟 q 之后的元素的迭代器，或若此种元素不存在则返回 a.end()。
a.erase(q1,q2) | iterator | 擦除 [q1,q2) 中的元素 | (std::deque, std::vector) T 可移动赋值 (MoveAssignable) | 返回指向在任何擦除前 q2 曾指向的元素的迭代器，或若不存在此种元素则返回 a.end()。
a.clear() void 销毁 a 中所有元素

所有引用、指针及迭代器均失效，包含尾迭代器。a.empty() == true。
a.assign(i,j) void 以 [i, j) 的副本替换 a 中的元素 T 可就位构造 (EmplaceConstructible) ，且 i、j 不在 a 中

(std::vector)，若非老式向前迭代器 (LegacyForwardIterator) ，则 T 可移动插入 (MoveInsertable)

 [i,j) 中的每个迭代器被解引用一次
a.assign(il) | void | a.assign(il.begin(),il.end())
a.assign(n,t) | void | 用 t 的 n 个副本替换 a 中的元素 | T 可复制插入 (CopyInsertable) 并可复制赋值 (CopyAssignable)
注
  1. ↑ std::array 支持从花括号初始化器列表复制，但不支持从 std::initializer_list 赋值

下列表达式必须合法，且对于所指名的顺序容器拥有所指定的效果：

表达式 | 返回类型 | 效果 | 前条件 | 容器
a.front() | reference 对于 const a 为 const_reference | 等价于 *a.begin() |  | （全部）
a.back() | reference 对于 const a 为 const_reference | 等价于 { auto tmp = a.end(); --tmp; return *tmp; } |  | std::basic_string std::array std::deque std::list std::vector
a.emplace_front(args) | void | 前附一个以 std::forward <Args>(args)... 构造的 T | T 从 args 可就位构造 (EmplaceConstructible) 到 X 中 | std::deque std::forward_list std::list
a.emplace_back(args) | void | 后附一个以 std::forward <Args>(args)... 构造的 T | T 从 args 可就位构造 (EmplaceConstructible) 到 X 中 (仅 std::vector) T 可移动插入 (MoveInsertable) 到 X 中 | std::deque std::list std::vector
a.push_front(t) | void | 前附 t 的一个副本 | T 可复制插入 (CopyInsertable) 到 X 中 | std::deque std::forward_list std::list
a.push_front(rv) | void | 前附 rv 的一个副本，可能用移动语义 | T 可移动插入 (MoveInsertable) 到 X 中 | std::deque std::forward_list std::list
a.push_back(t) | void | 后附 t 的一个副本 | T 可复制插入 (CopyInsertable) 到 X 中 | std::basic_string std::deque std::list std::vector
a.push_back(rv) | void | 后附 rv 的一个副本，可能用移动语义 | T 可移动插入 (MoveInsertable) 到 X 中 | std::basic_string std::deque std::list std::vector
a.pop_front() | void | 销毁首元素 | a.empty() == false | std::deque std::forward_list std::list
a.pop_back() | void | 销毁最末元素 | a.empty() == false | std::basic_string std::deque std::list std::vector
a[n] | reference 对于 const a 为 const_reference | 等价于 *(n + a.begin()) |  | std::basic_string std::array std::deque std::vector
a.at(n) | reference 对于 const a 为 const_reference | 等价于 *(n + a.begin())，但若 n>=size() 则抛出 out_of_range |  | std::basic_string std::array std::deque std::vector

另外，对于每个顺序容器，接收两个输入迭代器的构造函数模板和成员函数 insert()、append()、assign()、replace() 的模板重载，若相应的模板实参不满足老式输入迭代器 (LegacyInputIterator) ，则它们不参与重载决议。

标准库中的顺序容器

basic_string | 存储并操作字符序列 (类模板)
array (C++11) | 静态的连续数组 (类模板)
vector | 动态的连续数组 (类模板)
deque | 双端队列 (类模板)
forward_list (C++11 起) | 单链表 (类模板)
list | 双链表 (类模板)

权衡/使用备注

std::array | 快速访问但元素数量固定
std::vector | 快速访问但大多情况在插入/删除低效
std::list
std::forward_list 		在序列中部高效地插入/删除
std::deque | 在序列首尾高效地插入/删除


C++ 具名要求：可共享锁定 (SharedLockable)

< cpp‎ | named req

可共享锁定 (SharedLockable) 要求描述对执行代理（即线程）提供共享阻塞语义的类型的最小特征。

要求

对于要为可共享锁定 (SharedLockable) 的类型 L ，必须对 L 类型的对象 m 满足下列条件：

表达式 | 前条件 | 效果 | 返回值
m.lock_shared() |  | 阻塞直至能对当前执行代理（线程、进程、任务）获得锁。若抛异常则不获得锁。 |
m.try_lock_shared() |  | 尝试获得对当前执行代理（线程、进程、任务）获得锁。若抛异常则不获得锁。 | 若获得锁则为 true ，否则为 false
m.unlock_shared() | 当前执行代理保有 m 上的共享锁。 | 释放执行代理曾保有的共享锁。 不抛异常。 |

共享锁

若对象上的一个锁由调用 lock_shared、 try_lock_shared、 try_lock_shared_for 或 try_lock_shared_until 成员函数取得，则称之为共享锁。

参阅

  • 线程支持库
  • 可共享定时锁定 (SharedTimedLockable)
  • 共享互斥体 (SharedMutex)


C++ 具名要求：共享互斥体 (SharedMutex)

< cpp‎ | named req

共享互斥体 (SharedMutex) 要求扩展互斥体 (Mutex) 要求，以包括共享的锁所有权模式。

要求

  • 互斥体 (Mutex)

另外，共享互斥 (共享互斥体 (SharedMutex) ) 类型的对象 m 支持另一所有权模式：共享。多个线程（或更通用地，执行代理）能同时以共享模式占有此互斥，但若有线程以排他性模式占有，则无线程可获得共享所有权，而若有线程以共享模式占有，则无线程可获得排他性所有权。若多于实现定义数量（不少于 10000 ）的线程数保有一个共享锁，则另一对获得共享锁的尝试会阻塞直至共享所有者的数量跌到该阈值以下。

  • 表达式 m.lock_shared() 拥有下列属性
  • 表现为原子操作。
  • 阻塞调用方线程，直到能获得互斥的共享所有权。
  • 同一互斥上的先前 m.unlock() 操作同步于此操作（等价于释放获得内存顺序 (std::memory_order) ）。
  • 若调用方线程已以任何模式占有互斥，则行为未定义。
  • 若抛出异常，则不获得共享锁。
  • 表达式 m.try_lock_shared() 拥有下列属性
  • 表现为原子操作。
  • 试图为调用方线程获得互斥的共享所有权，而不阻塞。若未得到所有权，则立即返回。允许此函数虚假地失败并返回，即使互斥当前未为任何线程以任何模式占有。
  • 若 try_lock_shared() 成功，则同一对象上的先前 unlock() 操作同步于此操作（等价于释放获得内存顺序 (std::memory_order) ） 。
  • 若调用方线程已以任何模式占有互斥，则行为未定义。
  • 表达式 m.unlock_shared() 拥有下列属性
  • 表现为原子操作。
  • 释放调用方线程的互斥所有权，且同步于同一对象上后继的成功锁操作。
  • 若调用方线程不占有互斥，则行为未定义。
  • 单个互斥上的所有锁和解锁操作以单独全序出现。

库类型

下列标准库类型满足共享互斥体 (SharedMutex) ：

  • std::shared_mutex(C++17 起)
  • std::shared_timed_mutex(C++14 起)

参阅

  • 线程支持库
  • 互斥体 (Mutex)
  • 定时互斥体 (TimedMutex)
  • 共享定时互斥体 (SharedTimedMutex)


C++ 具名要求：可共享定时锁定 (SharedTimedLockable)

< cpp‎ | named req

可共享定时锁定 (SharedTimedLockable) 要求描述为执行代理（线程、进程、任务）提供定时排他性阻塞语义的类型特征。

要求

  • 可共享锁定 (SharedLockable)

对于要为可共享定时锁定 (SharedTimedLockable) 的类型 L ，给定

  • rel_time ， std::chrono::duration 的特化的值，及
  • abs_time ， std::chrono::time_point 的特化的值，

对 L 类型对象 m 必须满足下列条件：

表达式 | 要求 | 返回值
m.try_lock_shared_for(rel_time) | 阻塞提供的时长 rel_time ，或直至取得 m 上的锁。 | 若取得锁则为 true ，否则为 false 。
m.try_lock_shared_until(abs_time) | 阻塞直至提供的时间点 abs_time ，或直至取得 m 上的锁。 | 若取得锁则为 true ，否则为 false 。

注解

try_lock_shared_for 与 try_lock_shared_until 成员函数在成功时在 m 上获得共享锁。

参阅

  • 线程支持库
  • 共享定时互斥体 (SharedTimedMutex)
  • 可共享锁定 (SharedLockable)


C++ 具名要求：共享定时互斥体 (SharedTimedMutex)

< cpp‎ | named req

共享定时互斥体 (SharedTimedMutex) 要求扩展定时互斥体 (TimedMutex) 要求以包含共享锁所有权模式。

要求

  • 定时互斥体 (TimedMutex)
  • 共享互斥体 (SharedMutex)

另外，对于支持定时共享操作的共享定时互斥体 (SharedTimedMutex) 类型对象 m ：

  • 表达式 m.try_lock_shared_for(duration) 拥有下列属性
  • 表现为原子操作。
  • 试图在 duration 所指定的时常内获得互斥的共享所有权。若 duration 小于或等于 duration.zero() ，则试图获得所有权而不阻塞（如同用 try_lock() ）。否则，此函数将阻塞直至得到互斥，或直至经过 duration 所指定的时长。它仅若成功才在 duration 内返回，但允许获得互斥失败，即使在 duration 期间的某点，互斥不为另一线程所占有。任何情况下，若得到互斥则返回 true ，否则返回 false 。
  • 若 try_lock_shared_for(duration) 成功，则同一对象上先前的 unlock() 操作同步于此操作（等价于释放获得内存顺序 (std::memory_order) ）。
  • 若调用方线程已以任何模式占有互斥，则行为未定义。
  • 执行期间时钟、时间点或时长可能抛出异常（标准库提供的时钟、时间点及时长决不抛出）。
  • 若抛出异常，则不获得共享锁。
  • 表达式 m.try_lock_shared_until(time_point) 拥有下列属性
  • 表现为原子操作。
  • 试图在 time_point 前剩余的时间内获得互斥的共享所有权。若已经过 time_point ，则试图获得所有权而不阻塞（如同用 try_lock() ）。否则，此函数将阻塞直至得到互斥，或直至经过 time_point 所制定的时间点。它仅若成功才在 time_point 前返回，但允许获得互斥失败，即使在 time_point 前的某点，互斥不为另一线程所占有。任何情况下，若得到互斥则返回 true ，否则返回 false 。
  • 若 try_lock_shared_until(time_point) 成功，则同一对象上先前的 unlock() 操作同步于此操作（等价于释放获得内存顺序 (std::memory_order) ）。
  • 若调用方线程已以任何模式占有互斥，则行为未定义。
  • 执行期间时钟、时间点或时长可能抛出异常（标准库提供的时钟、时间点及时长决不抛出）。
  • 若抛出异常，则不获得共享锁。

库类型

下列标准库类型满足共享定时互斥体 (SharedTimedMutex) ：

  • std::shared_timed_mutex

参阅

  • 线程支持库
  • 互斥体 (Mutex)
  • 定时互斥体 (TimedMutex)
  • 共享互斥体 (SharedMutex)


C++ 具名要求：可交换 (Swappable)

< cpp‎ | named req

在 std::swap 与用户定义 swap() 均可见的语境中，此类型的任何左值或右值能与某个其他类型的任何左值或右值，可以用非限定函数调用 swap() 来进行交换。

要求

若对于任意 U 类型的对象 u 和任意 T 类型的对象 t，满足以下情况，则类型 U 与类型 T 可交换：

表达式 要求 语义
#include <utility>

using std::swap ;
swap(u, t);

 调用后，t 的值是 u 在调用前保有的值，而 u 的值是 t 在调用前保有的值。 调用名为 swap() 的函数，它是在由实参依赖查找所找到的所有具有这个名字的函数，和定义于头文件 <utility> 中的两个 std::swap 模板中，由重载决议所找到的函数。
#include <utility>

using std::swap ;
swap(t, u);

 同上 同上

许多标准库函数（例如许多算法）期待其实参满足可交换 (Swappable) ，这意味着每当标准库进行交换时，都使用等价于 using std::swap ; swap(t, u); 的写法。

典型的实现进行二者之一

1) 在外围命名空间中定义非成员 swap，若要求访问非公开数据成员，则它可转发到成员 swap
2) 于类中定义友元函数（此方法对于除 ADL 之外的名字查找隐藏了类特有的 swap）

注解

标准库进行交换时是否实际包含 <utility> 是未指明的，因此用户提供的 swap() 不应当期待它已被包含。

示例

#include <iostream>
#include <vector>

class IntVector {
    std::vector<int> v;
    IntVector& operator=(IntVector) = delete; // 不可赋值
 public:
    void swap(IntVector& other) {
        v.swap(other.v);
    }
};
void swap(IntVector& v1, IntVector& v2) {
    v1.swap(v2);
}

int main()
{
    IntVector v1, v2;
//  std::swap(v1, v2); // 编译器错误！std::swap 要求可移动赋值 (MoveAssignable)
    std::iter_swap(&v1, &v2); // OK：标准库调用无限定的 swap()
}

参阅

is_swappable_withis_swappableis_nothrow_swappable_withis_nothrow_swappable (C++17)(C++17)(C++17)(C++17) | 检查一个类型的对象是否能与同类型或不同类型的对象交换 (类模板)
swappableswappable_with (C++20) | 指定一个类型能进行交换，或两个类型能彼此交换 (概念)


C++ 具名要求：可定时锁定 (TimedLockable)

< cpp‎ | named req

可定时锁定 (TimedLockable) 要求描述为执行代理（线程、进程、任务）提供定时排他性阻塞语义的类型特征。

要求

  • 可锁定 (Lockable)

对于要为可定时锁定 (TimedLockable) 的类型 L ，给定

  • rel_time ， std::chrono::duration 的特化的值，及
  • abs_time ， std::chrono::time_point 的特化的值，

对 L 类型对象 m 必须满足下列条件：

表达式 | 效果 | 返回值
m.try_lock_for(rel_time) | 阻塞提供的时长 rel_time ，或直至取得 m 上的锁。 | 若取得锁则为 true ，否则为 false 。
m.try_lock_until(abs_time) | 阻塞直至提供的时间点 abs_time ，或直至取得 m 上的锁。 | 若取得锁则为 true ，否则为 false 。

注解

try_lock_for 与 try_lock_until 成员函数在成功时在 m 上获得非共享锁。

参阅

  • 线程支持库
  • 定时互斥体 (TimedMutex)
  • 可锁定 (Lockable)
  • 基本可锁定 (BasicLockable)


C++ 具名要求：定时互斥体 (TimedMutex)

< cpp‎ | named req

定时互斥体 (TimedMutex) 要求扩展可定时锁定 (TimedLockable) 要求，以包含线程间同步。

要求

  • 可定时锁定 (TimedLockable)
  • 互斥体 (Mutex)

另外，对于定时互斥体 (TimedMutex) 类型对象 m 。

  • 表达式 m.try_lock_for(duration) 拥有下列属性
  • 表现为原子操作。
  • 试图在 duration 所指定的时长内获得互斥的排他性所有权。若 duration 小于或等于 duration.zero() ，则试图获得所有权而不阻塞（如同用 try_lock() ）。否则，此函数将阻塞直至得到互斥，或直至经过 duration 所指定的时长。它仅若成功才在 duration 内返回，但允许获得互斥失败，即使在 duration 期间的某点，互斥不为另一线程所占有。任何情况下，若得到互斥则返回 true ，否则返回 false 。
  • 若 try_lock_for(duration) 成功，则同一对象上先前的 unlock() 操作同步于此操作（等价于释放获得内存顺序 (std::memory_order) ）。
  • 若调用方线程已占有互斥，则行为未定义（除非 m 是 std::recursive_timed_mutex ）。
  • 执行期间时钟、时间点或时长可能抛出异常（标准库提供的时钟、时间点及时长决不抛出）。
  • 表达式 m.try_lock_until(time_point) 拥有下列属性
  • 表现为原子操作。
  • 试图在到 time_point 为止的剩余时间内获得互斥的排他性所有权。若已经过 time_point ，则试图获得所有权而不阻塞（如同用 try_lock() ）。否则，此函数将阻塞直至得到互斥，或直至经过 time_point 所指定的时间点。它仅若成功才在 time_point 前返回，但允许获得互斥失败，即使在 time_point 前的某点，互斥不为另一线程所占有。任何情况下，若得到互斥则返回 true ，否则返回 false 。
  • 若 try_lock_until(time_point) 成功，则同一对象上先前的 unlock() 操作同步于此操作（等价于释放获得内存顺序 (std::memory_order) ）。
  • 若调用方线程已占有互斥，则行为未定义（除非 m 是 std::recursive_timed_mutex ）。
  • 执行期间时钟、时间点或时长可能抛出异常（标准库提供的时钟、时间点及时长决不抛出）。

库类型

下列标准库类型满足定时互斥体 (TimedMutex) ：

  • std::timed_mutex
  • std::recursive_timed_mutex
  • std::shared_timed_mutex

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2093 | C++11 | 规范中缺失超时相关异常 | 已提及

参阅

  • 线程支持库
  • 可定时锁定 (TimedLockable)
  • 互斥体 (Mutex)


C++ 具名要求：变换特征 (TransformationTrait)

< cpp‎ | named req

变换特征 (TransformationTrait) 是类模板，提供其模板类型形参的变换。

要求

  • 接收一个模板类型形参（允许可选的额外模板形参）
  • 变换后类型为可公开访问的，名为 type 的嵌套类型

标准库

类型修改与变换全都满足变换特征 (TransformationTrait) 。

下列标准库类模板亦满足变换特征 (TransformationTrait) 。

std::tuple_element<std::tuple> (C++11) | 获得指定元素的类型 (类模板特化)
std::tuple_element<std::pair> (C++11) | 获得 pair 中元素的类型 (类模板特化)
std::tuple_element<std::array> (C++11) | 获得 array 元素的类型 (类模板特化)
variant_alternativevariant_alternative_t (C++17) | 在编译时获得以其下标指定的可选项的类型 (类模板) (别名模板)


C++ 具名要求：平凡时钟 (TrivialClock)

< cpp‎ | named req

平凡时钟 (TrivialClock) 要求描述所有时间库中数个时钟所满足的要求。

要求

对于类型 TC:

  • 该类型必须满足时钟 (Clock) 要求。
  • 类型 TC::rep 、 TC::duration 及 TC::time_point 满足 可相等比较 (EqualityComparable) 、可小于比较 (LessThanComparable) 、可默认构造 (DefaultConstructible) 、可复制构造 (CopyConstructible) 、可复制赋值 (CopyAssignable) 、可析构 (Destructible) 及数值类型 (NumericType) 的要求。
  • TC::rep 、 TC::duration 及 TC::time_point类型的左值 可交换 (Swappable) 。
  • 函数 TC::now() 不抛出异常。
  • 类型 TC::time_point::clock 满足平凡时钟 (平凡时钟 (TrivialClock) ) 的要求，依此递归。

使用

标准库中下列类型满足此概念：

  • std::chrono::system_clock
  • std::chrono::steady_clock
  • std::chrono::high_resolution_clock
  • std::filesystem::file_time_type::clock
  • std::chrono::file_clock


C++ 具名要求：平凡类型 (TrivialType)

< cpp‎ | named req

指定类型为平凡类型。

注意：标准中并没有定义具有这个名字的具名要求。这是核心语言所定义的一种类型类别。将它作为具名要求包含于此只是为了保持一致性。

要求

  • 可平凡复制 (TriviallyCopyable)
  • 若该类型是类类型或其数组，则该类拥有一个或多个合格的默认构造函数，均为平凡的。

注解

一个默认构造函数为合格当且仅当它不是弃置的。

 (C++20 前)

参阅

is_trivial
(C++11)
 检查类型是否平凡
(类模板)


C++ 具名要求：可平凡复制 (TriviallyCopyable)

< cpp‎ | named req

注意：标准中并没有定义具有这个名字的具名要求。这是核心语言所定义的一种类型类别。将它作为具名要求包含于此只是为了保持一致性。

要求

下列类型统称为可平凡复制类型：

  • 标量类型
  • 可平凡复制类类型，即满足下列条件的类类型：
    • 至少一个复制构造函数、移动构造函数、复制赋值运算符或移动赋值运算符是合格的
    • 每个合格的复制构造函数（若存在）均为平凡的
    • 每个合格的移动构造函数（若存在）均为平凡的
    • 每个合格的复制赋值运算符（若存在）均为平凡的
    • 每个合格的移动赋值运算符（若存在）均为平凡的
    • 拥有一个平凡而未弃置的析构函数
  • 可平凡复制 (TriviallyCopyable) 对象的数组

这意味着可平凡复制类没有虚函数或虚基类。

注解

一个复制构造函数、移动构造函数、复制赋值运算符或移动赋值运算符是合格的当且仅当它不是弃置的。

 (C++20 前)

一般来说，对于任何可平凡复制类型 T 及 T 对象 obj1 ，能复制 obj1 的底层字节到 char 或 unsigned char 或 std::byte (C++17 起) 的数组中，或到 T 的另一不同对象 obj2 中。 obj1 与 obj2 均不可为潜在重叠的子对象。

若复制 obj1 的底层字节到这种数组中，然后复制结果内容回 obj1 中，则 obj1 将保有其原值。若复制 obj1 的底层字节到 obj2 中，则 obj2 将保有 obj1 的值。

底层字节能由 std::memcpy 或 std::memmove 复制，只要不访问存活的 volatile 对象。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1734 | C++11 | 拥有弃置的非平凡赋值的 C++03 POD 不是平凡的 | 允许弃置的构造函数/运算符
CWG 2094 | C++11 | volatile 标量类型非可平凡复制（ CWG 1746 ） | 使之为可平凡复制

参阅

is_trivially_copyable
(C++11)
 检查类型是否可平凡复制
(类模板)


C++ 具名要求：一元类型特征 (UnaryTypeTrait)

< cpp‎ | named req

一元类型特征 (UnaryTypeTrait) 是类模板，以一个 integral_constant （常为 bool_constant ）特化描述其模板类型形参的属性。

要求

  • 可默认构造 (DefaultConstructible) 且可复制构造 (CopyConstructible)
  • 接收一个模板类型形参（允许可选的额外模板形参）
  • 公开且无歧义地从称为其基特征（ base characteristic ）的 intergral_constant 特化派生
  • 基特征的成员名不被隐藏，且无歧义地可用

标准库

下列类型特征全都满足一元类型特征 (UnaryTypeTrait) ：

  • 基础类型类别
  • 合成类型类别
  • 类型属性
  • 受支持操作
  • 属性查询

下列标准库类模板亦满足一元类型特征 (UnaryTypeTrait) ：

negation (C++17) | 逻辑非元函数 (类模板)
std::tuple_size<std::tuple> (C++11) | 在编译时获得 tuple 的大小 (类模板特化)
std::tuple_size<std::array> (C++11) | 获得 array 的大小 (类模板特化)
std::tuple_size<std::pair> (C++11) | 获得 pair 的大小 (类模板特化)
variant_sizevariant_size_v (C++17) | 在编译时获得 variant 可选项列表的大小 (类模板) (变量模板)
is_bind_expression (C++11) | 指示对象为 std::bind 表达式，或能被用作这种表达式 (类模板)
is_placeholder (C++11) | 表明一个对象是标准占位符，或者可以用作标准占位符 (类模板)
is_execution_policy (C++17) | 测试一个类是否表示某种执行策略 (类模板)


C++ 具名要求：无格式输入函数 (UnformattedInputFunction)

< cpp‎ | named req

要求

无格式输入函数 (UnformattedInputFunction) 是进行下列操作的流输入函数：

  • 构造具有自动存储期的 basic_istream::sentry 类型的对象，并将 noskipws 实参设为 true，这会进行下列操作
  • 若 eofbit 或 badbit 在输入流上被设置，则一并设置 failbit，且若此输入流的异常掩码中启用了 failbit 上的异常，则抛出 ios_base::failure。
  • 冲洗其所 tie() 的输出流，若适用
  • 通过调用 sentry::operator bool() 检查 sentry 的状态，这等价于 basic_ios::good。
  • 若 sentry 返回 false 或 sentry 的构造函数抛异常，则：
  • 设置输入流中的已提取字符数 (gcount) 为零
  • 若是为写入某个 CharT 的数组而进行函数调用，则向该数组的首个位置写入 CharT()（空字符）
  • 若 sentry 返回 true，则如同以调用 rdbuf()->sbumpc() 或 rdbuf()->sgetc() 来实施输入。
  • 若抵达了流尾（对 rdbuf()->sbumpc() 或 rdbuf()->sgetc() 的调用返回 Traits::eof()），则设置 eofbit。若此流的异常掩码中启用了 eofbit 上的异常，则抛出 ios_base::failure。
  • 若输入过程中抛出了异常，则设置输入流中的 badbit。若此流的异常掩码中启用了 badbit 上的异常，则还要重抛这个异常。
  • 若输入过程中未抛出异常，则设置输入流中的已提取字符数 (gcount)。
  • 任何事件中，无论是异常终止还是返回，离开此函数前都会调用 sentry 的析构函数。

标准库

下列标准库函数是无格式输入函数 (UnformattedInputFunction) 。

  • std::getline，但它不修改 gcount。
  • basic_istream::operator>>(basic_streambuf*)
  • basic_istream::get
  • basic_istream::getline
  • basic_istream::ignore
  • basic_istream::peek
  • basic_istream::read
  • basic_istream::readsome
  • basic_istream::putback，除了首先清除 eofbit
  • basic_istream::unget，除了首先清除 eofbit
  • basic_istream::sync，除了不修改 gcount
  • basic_istream::tellg，除了不修改 gcount
  • basic_istream::seekg，除了首先清除 eofbit 且不修改 gcount
  • std::ws ，除了不修改 gcount 。


C++ 具名要求：无格式输出函数 (UnformattedOutputFunction)

< cpp‎ | named req

要求

无格式输出函数 (UnformattedOutputFunction) 是进行下列操作的流输入函数：

  • 构造一个具有自动存储期的 basic_ostream::sentry 类型的对象，它进行下列操作
  • 若输出流上设置了 eofbit 或 badbit，则一同设置 failbit，且若此输出流的异常掩码中启用了 failbit 上的异常，则抛出 ios_base::failure。
  • 冲洗其所 tie() 的输出流，若适用。
  • 通过调用 sentry::operator bool() 检查 sentry 的状态，等价于 basic_ios::good。
  • 若 sentry 返回 false，或 sentry 的构造函数抛出了异常，则不发生输出
  • 若 sentry 返回 true，则试图通过插入字符到输出流，如同以调用 rdbuf()->sputc() 或 rdbuf()->xsputn()，进行所欲的输出。另外，可能调用 rdbuf()->overflow() 或 rdbuf()->sync()，但不会调用 std::basic_streambuf 的其他虚函数。
  • 若输出中抛出了异常，则设置输出流中的 badbit。若此流的异常掩码中启用了 badbit 上的异常，则亦会重抛这个异常。
  • 若不抛异常，则返回该函数所指定的值。
  • 任何事件中，无论是因异常终止还是返回，离开此函数前都会调用 sentry 的析构函数。

标准库

下列标准库函数是无格式输出函数 (UnformattedOutputFunction) 。

  • basic_ostream::operator<<(basic_streambuf*)
  • basic_ostream::put
  • basic_ostream::write
  • basic_ostream::flush
  • basic_ostream::tellp （但其调用 pubseekoff 而非进行输出）
  • basic_ostream::seekp （但其调用 pubseekoff 或 pubseekpos 而非进行输出）
 (C++11 起)


C++ 具名要求：均匀随机位生成器 (UniformRandomBitGenerator)

< cpp‎ | named req

均匀随机位生成器是返回无符号整数值的函数对象，可能结果范围中的每个值都（理想情况）拥有等概率。

均匀随机位生成器不是有意用做随机数生成器的：它们被用作随机位的源（为效率大量生成）。任何均匀随机位生成器均可被插入任何随机数分布，以获得随机数（正式而言是随机变量）。

要求

类型 G 满足均匀随机位生成器 (UniformRandomBitGenerator) ，若

给定

  • T ， G::result_type 所指名的类型
  • g ， G 类型的值

下列表达式必须合法且拥有其指定的效应

表达式 | 返回类型 | 要求
G::result_type | T | T 是无符号整数类型
G::min() | T | 返回 G 的 operator() 可返回的最小值。值严格小于 G::max() 。函数必须是 constexpr 。
G::max() | T | 返回 G 的 operator() 可返回的最大值。值严格大于 G::min() 。函数必须是 constexpr 。
g() | T | 返回闭区间 [G::min(), G::max()] 中的值。拥有均摊常数复杂度。

注解

所有随机数引擎 (RandomNumberEngine) 均满足此要求。

标准库

下列标准库设施期待均匀随机位生成器 (UniformRandomBitGenerator) 类型。

random_shuffleshuffle (C++17 前)(C++11) | 随机重排范围中的元素 (函数模板)
generate_canonical (C++11) | 给定精度的均匀分布在 [0, 1) 上的实数值 (函数模板)
uniform_int_distribution (C++11) | 产生在一个范围上均匀分布的整数值 (类模板)
uniform_real_distribution (C++11) | 产生在一个范围上均匀分布的实数值 (类模板)
所有其他随机数分布

下列标准库设施满足均匀随机位生成器 (UniformRandomBitGenerator) 而不另外满足随机数引擎 (RandomNumberEngine) ：

random_device
(C++11)
 使用硬件熵源的非确定随机数生成器
(类)

参阅

uniform_random_bit_generator
(C++20)
 指定类型具备作为均匀随机位生成器的资格
(概念)


C++ 具名要求：无序关联容器 (UnorderedAssociativeContainer)

< cpp‎ | named req

无序关联容器是提供基于键的快速对象查找的容器 (Container) 。最坏情况的复杂度为线性，但平均而言大多数操作则快得多。

无序关联容器基于以下各项参数化：Key；Hash，表现为 Key 上散列函数的散列 (Hash) 函数对象；Pred，评估 Key 间的等价性的二元谓词 (BinaryPredicate) 。std::unordered_map 与 std::unordered_multimap 也拥有与 Key 关联的被映射类型 T。

若两个 Key 按照 Pred 比较为相等，则 Hash 必须对两个键返回相同值。

若 Hash::is_transparent 与 Pred::is_transparent 均存在且各指名类型，则成员函数 find 、 contains 、 count 与 equal_range 接受异于 Key 的实参类型并期待 Hash 能以那些类型调用，而 Pred 是如 std::equal_to<> 的通透比较函数。

 (C++20 起)

std::unordered_map 与 std::unordered_set 能容纳至多一个带给定键的元素，而 std::unordered_multiset 与 std::unordered_multimap 能拥有带同一键的多个元素（它们在迭代时必然相邻）。

对于 std::unordered_set 和 std::unordered_multiset，其值类型与键类型相同，而 iterator 和 const_iterator 都是常量迭代器。对于 std::unordered_map 与 std::unordered_multimap，值类型是 std::pair <const Key, T>。

无序关联容器中的元素被组织到桶（bucket）中，拥有相同散列值的键将归于相同的桶中。桶数在容器大小增加时增加，以保持每个桶中的平均元素数在某个确定值之下。

重散列会使迭代器失效，并可能导致元素被重排到不同的桶中，但它不使元素的引用失效。

无序关联容器满足知分配器容器 (AllocatorAwareContainer) 的要求。对于 std::unordered_map 与 std::unordered_multimap，知分配器容器 (AllocatorAwareContainer) 中 value_type 的要求应用到 key_type 和 mapped_type（而非到 value_type）。

要求

凡例
X | 容器类型
a | X 类型的对象
b | X 类型的 const 对象
a_uniq | （当 X 支持唯一键时）X 中的对象
a_eq | （当 X 支持多重键时）X 中的对象
i, j | 指代有效范围的老式输入迭代器 (LegacyInputIterator)
p, q2 | 指向 a 的有效 const_iterator
q, q1 | 指向 a 的指代有效范围的可解引用 const_iterator
il | std::initializer_list <X::value_type> 类型的对象
t | X::value_type 类型的对象
k | X::key_type 类型的对象
hf | X::hasher 类型的 const 对象
eq | X::key_equal 类型的 const 对象
n | X::size_type 类型的值
z | float 类型的值

表达式 | 返回类型 | 前条件/要求 | 后条件/效果 | 复杂度
X::key_type | Key |  |  | 编译时
X::mapped_type | T | 仅 std::unordered_map 与 std::unordered_multimap |  | 编译时
X::value_type | Key | 仅 std::unordered_set 与 std::unordered_multiset。于 X 可擦除 (Erasable) |  | 编译时
X::value_type | std::pair <const Key, T> | 仅 std::unordered_map 与 std::unordered_multimap。于 X 可擦除 (Erasable) |  | 编译时
X::hasher | Hash | 散列 (Hash) |  | 编译时
X::key_equal | Pred | 接收两个 Key 类型的实参并表达等价关系的二元谓词 (BinaryPredicate) 。 |  | 编译时
X::local_iterator | 类别和类型与 X::iterator 相同的老式迭代器 (LegacyIterator) |  | 可用于在单个桶上迭代 | 编译时
X::const_local_iterator | 类别和类型与 X::const_iterator 相同的老式迭代器 (LegacyIterator) |  | 可用于在单个桶上迭代 | 编译时
X(n,hf,eq) | X | hasher 与 key_equal 可复制构造 (CopyConstructible) | 用给定的散列函数和相等谓词，构造至少有 n 个桶的空容器 | 与 n 成线性
X(n,hf) | X | hasher 可复制构造 (CopyConstructible) ， key_equal 可默认构造 (DefaultConstructible) | 用给定的散列函数并以 key_equal() 为相等谓词，构造至少有 n 个桶的空容器 | 与 n 成线性
X(n) | X | hasher 与 key_equal 可默认构造 (DefaultConstructible) | 以 hasher() 为散列函数并以 key_equal() 为相等谓词，构造至少有 n 个桶的空容器 | 与 n 成线性
X() | X | hasher 与 key_equal 可默认构造 (DefaultConstructible) | 以 hasher() 为散列函数并以 key_equal() 为相等谓词，构造有未指定桶数的空容器 | 常数
X(i,j,n,hf,eq) | X | hasher 与 key_equal 可复制构造 (CopyConstructible) ，value_type 从 *i 可就位构造 (EmplaceConstructible) 到 X | 用给定的散列函数和相等谓词，构造至少有 n 个桶的空容器，并插入来自 [i,j) 的元素到它。 | 平均为线性，最坏为（对 i 与 j 间的的距离的）平方
X(i,j,n,hf) | X | key_equal 可默认构造 (DefaultConstructible) | 如上，有 eq=key_equal() | 同上
X(i,j,n) | X | hasher 可默认构造 (DefaultConstructible) | 如上，有 hf=hasher() | 同上
X(i,j) | X |  | 如上，拥有未指定的桶数 | 同上
X(il) | X |  | X(il.begin(),il.end() | 同上
X(il,n) | X |  | X(il.begin(),il.end(),n | 同上
X(il,n,hf) | X |  | X(il.begin(),il.end(),n,hf | 同上
X(il,n,hf,eq) | X |  | X(il.begin(),il.end(),n,hf,eq | 同上
X(b) | X |  | 复制构造函数，亦复制散列函数、谓词和最大加载因子 | 平均为线性，最坏为（对 b.size() 的）平方
a = b | X& |  | 复制赋值，亦复制散列函数、谓词和最大加载因子 | 平均为线性，最坏为（对 b.size() 的）平方
a = il | X& | value_type 可复制赋值 (CopyAssignable) 且可复制插入 (CopyInsertable) 到 X | a = X(il) | 同上
本节未完成
原因：考虑成员函数的要求

标准库中的无序关联容器

unordered_set (C++11 起) | 唯一键的集合，按照键生成散列 (类模板)
unordered_multiset (C++11 起) | 键的集合，按照键生成散列 (类模板)
unordered_map (C++11 起) | 键值对的集合，按照键生成散列，键是唯一的 (类模板)
unordered_multimap (C++11 起) | 键值对的集合，按照键生成散列 (类模板)


C++ 具名要求：值可交换 (ValueSwappable)

< cpp‎ | named req

此类型的两个对象可以解引用，且在 std::swap 和用户定义 swap() 均可见的语境中，其结果值可以用无限定的函数调用 swap() 进行交换。

要求

以下情况下，类型 T 为值可交换 (ValueSwappable) :

  1. 类型 T 满足老式迭代器 (LegacyIterator) 要求
  2. 对任何 T 类型的可解引用对象 x（即并非尾迭代器的值），*x 满足可交换 (Swappable) 要求。

许多标准库函数均期待其实参满足值可交换 (ValueSwappable) ，这意味着凡在标准库进行交换时，它都使用 using std::swap ; swap(*iter1, *iter2); 的等价物。

示例

#include <iostream>
#include <vector>

class IntVector {
    std::vector<int> v;
    IntVector& operator=(IntVector); // 不可赋值
 public:
    void swap(IntVector& other) {
        v.swap(other.v);
    }
};
void swap(IntVector& v1, IntVector& v2) {
    v1.swap(v2);
}

int main()
{
    IntVector v1, v2;    // IntVector 为可交换 (Swappable)，但非可移动赋值 (MoveAssignable)
    IntVector* p1 = &v1;
    IntVector* p2 = &v2; // IntVector* 为值可交换 (ValueSwappable)
    std::iter_swap(p1, p2); // OK：iter_swap 要求值可交换 (ValueSwappable)
//  std::swap(v1, v2); // 编译器错误！std::swap 要求可移动赋值 (MoveAssignable)
}

参阅

indirectly_swappable
(C++20)
 指定能交换两个 indirectly_readable 类型所引用的值
(概念)


数值库

< cpp

C++ 数值库包含常用数学函数及类型，以及优化的数值数组及对随机数生成的支持。

数学函数与类型

常用数学函数

头文件 <cmath> 提供标准 C 库数学函数，例如 std::fabs 、 std::sqrt 及 std::sin 。

数学特殊函数 (C++17 起)

头文件 <cmath> 亦提供数个特殊数学函数，例如 std::beta 、 std::hermite 及 std::cyl_bessel_i 。

数学常数 (C++20 起)

头文件 <numbers> 提供数个数学常数，例如 std::numbers::pi 或 std::numbers::sqrt2 。

复数算术

定义于头文件 <complex>
complex
 复数类型
(类模板)

数值数组

定义于头文件 <valarray>
valarray
 数值数组、数组掩码及数组切片
(类模板)

数值算法

头文件 <numeric> 提供下列数值算法：

因数运算

定义于头文件 <numeric>
gcd (C++17) | 返回二个整数最大公约数的 constexpr 函数模板 (函数模板)
lcm (C++17) | 返回二个整数最小公倍数的 constexpr 函数模板 (函数模板)

插值运算

定义于头文件 <numeric>
midpoint (C++20) | 两个数值或指针间的中点 (函数模板)
定义于头文件 <cmath>
lerp (C++20) | 线性插值函数 (函数)

数值运算

定义于头文件 <numeric>
iota (C++11) | 用从起始值开始连续递增的值填充一个范围 (函数模板)
accumulate | 对一个范围内的元素求和 (函数模板)
reduce (C++17) | 类似 std::accumulate，但不依序执行 (函数模板)
transform_reduce (C++17) | 应用一个函数对象，然后以乱序规约 (函数模板)
inner_product | 计算两个范围的元素的内积 (函数模板)
adjacent_difference | 计算范围内各相邻元素之间的差 (函数模板)
partial_sum | 计算范围内元素的部分和 (函数模板)
inclusive_scan (C++17) | 类似 std::partial_sum，第 i 个和中包含第 i 个输入 (函数模板)
exclusive_scan (C++17) | 类似 std::partial_sum，第 i 个和中排除第 i 个输入 (函数模板)
transform_inclusive_scan (C++17) | 应用一个函数对象，然后进行包含扫描 (函数模板)
transform_exclusive_scan (C++17) | 应用一个函数对象，然后进行排除扫描 (函数模板)

杂项

伪随机数生成

头文件 <random> 定义为随机数生成器与数值分布。头文件 cstdlib 亦包含 C 风格随机数生成，通过 std::srand 和 std::rand 。

编译时有理数算术 (C++11 起)

头文件 <ratio> 提供操作和存储编译时比例的类型和函数。

浮点环境 (C++11 起)

头文件 <cfenv> 定义关系到异常浮点状态的标志和函数，例如上溢和除以零。

位操纵 (C++20 起)

头文件 <bit> 提供数个访问、操纵及处理单独位和位序列的函数模板。

定义于头文件 <bit>
定义于命名空间 std
bit_cast (C++20) | 将一个类型的对象表示重解释为另一类型的对象表示 (函数模板)
byteswap (C++23) | 反转给定整数值中的字节 (函数模板)
has_single_bit (C++20) | 检查一个数是否为二的整数次幂 (函数模板)
bit_ceil (C++20) | 寻找不小于给定值的最小的二的整数次幂 (函数模板)
bit_floor (C++20) | 寻找不大于给定值的最大的二的整数次幂 (函数模板)
bit_width (C++20) | 寻找表示给定值所需的最小位数 (函数模板)
rotl (C++20) | 计算逐位左旋转的结果 (函数模板)
rotr (C++20) | 计算逐位右旋转的结果 (函数模板)
countl_zero (C++20) | 从最高位起计量连续的 0 位的数量 (函数模板)
countl_one (C++20) | 从最高位起计量连续的 1 位的数量 (函数模板)
countr_zero (C++20) | 从最低位起计量连续的 0 位的数量 (函数模板)
countr_one (C++20) | 从最低位起计量连续的 1 位的数量 (函数模板)
popcount (C++20) | 计量无符号整数中为 1 的位的数量 (函数模板)
endian (C++20) | 指示标量类型的端序 (枚举)

参阅


std::bit_cast

< cpp‎ | numeric
定义于头文件 <bit> |
template< class To, class From > constexpr To bit_cast( const From& from ) noexcept; | (C++20 起)

通过转译 from 的对象表示获得 To 类型值。返回的 To 对象值表示中的每位都等于 from 的对象表示中的对应位。返回的 To 对象中的填充位的值未指定。

若无 To 类型值对应产生的值表示，则行为未定义。若有多个这种值，则产生哪个值是未指定的。

结果的值表示中的一个位为不确定，若它

  • 不对应 From 的值表示中的位（即它对应填充位），或
  • 对应一个不在其生存期内的对象的位，或
  • 拥有不确定值。

对于每个结果的值表示中的不确定位，含该位的最小对象拥有不确定值；若该对象不拥有 unsigned char 或 std::byte 类型则行为未定义。其他情况下结果不含不确定值。

此重载仅若 sizeof(To) == sizeof(From) 且 To 和 From 两者都是可平凡复制 (TriviallyCopyable) 类型才参与重载决议。

此函数模板为 constexpr ，若且唯若 To、 From 和 To 及 From 的所有子对象的类型都：

  • 不是联合体类型；
  • 不是指针类型；
  • 不是指向成员指针类型；
  • 不是 volatile 限定类型；且
  • 无引用类型的非静态数据成员。

返回值

值表示描述如上的 To 类型对象。

注解

大多数情况下不应该用指针或引用类型间的 reinterpret_cast （或等价的显式转型）转译对象表示，因为类型别名使用规则。

在 std::bit_cast 前，需要翻译对象表示为另一类型的对象表示时，能使用 std::memcpy ：

template <class To, class From>
typename std::enable_if_t<
    sizeof(To) == sizeof(From) &&
    std::is_trivially_copyable_v<From> &&
    std::is_trivially_copyable_v<To>,
    To>
// constexpr 支持需要编译器魔法
bit_cast(const From& src) noexcept
{
    // 此实现要求 To 可平凡默认构造
    static_assert(std::is_trivially_constructible_v<To>,
        "This implementation additionally requires destination type to be trivially constructible");

    To dst;
    std::memcpy(&dst, &src, sizeof(To));
    return dst;
}

示例

#include <cstdint>
#include <bit>
#include <iostream>

constexpr double f64v = 19880124.0;
constexpr auto u64v = std::bit_cast<std::uint64_t>(f64v);

constexpr std::uint64_t u64v2 = 0x3fe9000000000000ull;
constexpr auto f64v2 = std::bit_cast<double>(u64v2);

int main()
{
    std::cout
        << std::fixed <<f64v << "f64.to_bits() == 0x"
        << std::hex << u64v << "u64\n";

    std::cout
        << "f64::from_bits(0x" << std::hex << u64v2 << "u64) == "
        << std::fixed << f64v2 << "f64\n";
}

可能的输出：

19880124.000000f64.to_bits() == 0x4172f58bc0000000u64
f64::from_bits(0x3fe9000000000000u64) == 0.781250f64

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 2482 | C++20 | 在涉及不确定位时未指定 UB 是否会出现 | 已指定


std::bit_ceil

< cpp‎ | numeric
定义于头文件 <bit> |
template< class T > constexpr T bit_ceil(T x); | (C++20 起)

不小于 x 的最小的二的整数次幂。

若值不能以 T 表示，则行为未定义。仅若不出现未定义行为才容许在常量求值中调用此函数。

此重载仅若 T 为无符号整数类型（即 unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 、 unsigned long long 或扩展无符号整数类型）才参与重载决议。

参数

x - 无符号整数类型的值

返回值

不小于 x 的最小的二的整数次幂。

异常

不抛出。

可能的实现

见 libstdc++ (gcc) 与 libc++ (clang) 中的可能实现。

template <std::unsigned_integral T>
    requires !std::same_as<T, bool> && !std::same_as<T, char> &&
             !std::same_as<T, char8_t> && !std::same_as<T, char16_t> &&
             !std::same_as<T, char32_t> && !std::same_as<T, wchar_t>
constexpr T bit_ceil(T x) noexcept
{
    if (x <= 1u)
        return T(1);
    if constexpr (std::same_as<T, decltype(+x)>)
        return T(1) << std::bit_width(T(x - 1));
    else { // 对于要经受整数提升的类型
        constexpr int offset_for_ub =
            std::numeric_limits<unsigned>::digits - std::numeric_limits<T>::digits;
        return T(1u << (std::bit_width(T(x - 1)) + offset_for_ub) >> offset_for_ub);
    }
}

示例

#include <bit>
#include <bitset>
#include <iostream>

auto main() -> int
{
    using bin = std::bitset<8>;

    for (unsigned x{0}; x != 10; ++x)
    {
        auto const z = std::bit_ceil(x); // P1956R1 前为 `ceil2`

        std::cout << "bit_ceil(" << bin(x) << ") = " << bin(z) << '\n';
    }
}

输出：

bit_ceil(00000000) = 00000001
bit_ceil(00000001) = 00000001
bit_ceil(00000010) = 00000010
bit_ceil(00000011) = 00000100
bit_ceil(00000100) = 00000100
bit_ceil(00000101) = 00001000
bit_ceil(00000110) = 00001000
bit_ceil(00000111) = 00001000
bit_ceil(00001000) = 00001000
bit_ceil(00001001) = 00010000

参阅

bit_floor
(C++20)
 寻找不大于给定值的最大的二的整数次幂
(函数模板)


std::bit_floor

< cpp‎ | numeric
定义于头文件 <bit> |
template< class T > constexpr T bit_floor(T x) noexcept; | (C++20 起)

若 x 非零，则计算不大于 x 的最大的二的整数次幂。若 x 为零，则返回零。

此重载仅若 T 为无符号整数类型（即 unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 、 unsigned long long 或扩展无符号整数类型）才参与重载决议。

返回值

若 x 为零则为零；否则为不大于 x 的最大的二的整数次幂。

可能的实现

template <std::unsigned_integral T>
    requires !std::same_as<T, bool> && !std::same_as<T, char> &&
             !std::same_as<T, char8_t> && !std::same_as<T, char16_t> &&
             !std::same_as<T, char32_t> && !std::same_as<T, wchar_t>
constexpr T bit_floor(T x) noexcept
{
    if (x != 0)
        return T{1} << (std::bit_width(x) - 1);
    return 0;
}

示例

#include <bit>
#include <bitset>
#include <iostream>

auto main() -> int
{
    using bin = std::bitset<8>;

    for (unsigned x = 0; x != 10; ++x)
    {
        auto const z = std::bit_floor(x); // P1956R1 前为 `floor2`

        std::cout << "bit_floor(" << bin(x) << ") = " << bin(z) << '\n';
    }
}

输出：

bit_floor(00000000) = 00000000
bit_floor(00000001) = 00000001
bit_floor(00000010) = 00000010
bit_floor(00000011) = 00000010
bit_floor(00000100) = 00000100
bit_floor(00000101) = 00000100
bit_floor(00000110) = 00000100
bit_floor(00000111) = 00000100
bit_floor(00001000) = 00001000
bit_floor(00001001) = 00001000

参阅

bit_ceil (C++20) | 寻找不小于给定值的最小的二的整数次幂 (函数模板)
rotr (C++20) | 计算逐位右旋转的结果 (函数模板)
bit_width (C++20) | 寻找表示给定值所需的最小位数 (函数模板)
has_single_bit (C++20) | 检查一个数是否为二的整数次幂 (函数模板)


std::bit_width

< cpp‎ | numeric
定义于头文件 <bit> |
template< class T > constexpr T bit_width(T x) noexcept; | (C++20 起)

若 x 非零，则计算存储值 x 所需的位数，即 \(1 + \lfloor \log_2(x) \rfloor\)1 + floor(log
2(x)) 。若 x 为零，则返回零。

此重载仅若 T 为无符号整数类型（即 unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 、 unsigned long long 或扩展无符号整数类型）才参与重载决议。

返回值

若 x 为零则为零；否则为一加 x 的 2 为底的对数，舍弃任何小数部分。

注解

此函数等价于 return std::numeric_limits <T>::digits - std::countl_zero(x); 。

示例

#include <bit>
#include <bitset>
#include <iostream>

auto main() -> int
{
    for (unsigned x{0u}; x != 8u; ++x)
    {
        std::cout
            << "bit_width( "
            << std::bitset<4>{x} << " ) = "
            << std::bit_width(x) << '\n';
    }
}

输出：

bit_width( 0000 ) = 0
bit_width( 0001 ) = 1
bit_width( 0010 ) = 2
bit_width( 0011 ) = 2
bit_width( 0100 ) = 3
bit_width( 0101 ) = 3
bit_width( 0110 ) = 3
bit_width( 0111 ) = 3

参阅

countl_zero
(C++20)
 从最高位起计量连续的 0 位的数量
(函数模板)


std::byteswap

< cpp‎ | numeric
定义于头文件 <bit> |
template< class T > constexpr T byteswap( T n ) noexcept; | (C++23 起)

逆转给定整数值 n 中的字节。

std::byteswap 仅若 T 满足 integral ，即 T 为整数类型才参与重载决议。若 T 拥有填充位则程序非良构。

参数

n - 整数值

返回值

T 类型整数值，其对象表示由 n 的对象表示的字节按逆序组成。

注解

此函数对处理有不同端序的数据有用。

示例

#include <bit>
#include <cstdint>
#include <concepts>
#include <iostream>
#include <iomanip>

template <std::integral T>
void dump(T v, char term = '\n') {
    std::cout << std::hex << std::uppercase << std::setfill('0')
              << std::setw(sizeof(T) * 2) << v << " : ";
    for (std::size_t i{}; i != sizeof(T); ++i, v >>= 8) {
        std::cout << std::setw(2) << static_cast<unsigned>(T(0xFF) & v) << ' ';
    }
    std::cout << std::dec << term;
}

int main()
{
    static_assert(std::byteswap('a') == 'a');

    std::cout << "byteswap for U16:\n";
    constexpr auto x = std::uint16_t(0xCAFE);
    dump(x);
    dump(std::byteswap(x));

    std::cout << "\nbyteswap for U32:\n";
    constexpr auto y = std::uint32_t(0xDEADBEEFu);
    dump(y);
    dump(std::byteswap(y));

    std::cout << "\nbyteswap for U64:\n";
    constexpr auto z = std::uint64_t{0x0123456789ABCDEFull};
    dump(z);
    dump(std::byteswap(z));
}

可能的输出：

byteswap for U16:
CAFE : FE CA
FECA : CA FE

byteswap for U32:
DEADBEEF : EF BE AD DE
EFBEADDE : DE AD BE EF

byteswap for U64:
0123456789ABCDEF : EF CD AB 89 67 45 23 01
EFCDAB8967452301 : 01 23 45 67 89 AB CD EF

参阅

endian (C++20) | 指示标量类型的端序 (枚举)
rotl (C++20) | 计算逐位左旋转的结果 (函数模板)
rotr (C++20) | 计算逐位右旋转的结果 (函数模板)


std::complex

< cpp‎ | numeric
定义于头文件 <complex> |
template< class T > class complex; | (1)
template<> class complex<float>; | (2)
template<> class complex<double>; | (3)
template<> class complex<long double>; | (4)

模板特化 std::complex<float>、 std::complex<double> 及 std::complex<long double> 是表示并计算复数的字面类型 (LiteralType) 。

对任何其他类型，实例化模板 complex 的效果是不确定的。实现可以禁止这种特化的实例化。

成员类型

成员类型 | 定义
value_type | T

成员函数

(构造函数) | 构造一个复数 (公开成员函数)
operator= | 赋值内容 (公开成员函数)
real | 访问复数的实部 (公开成员函数)
imag | 访问复数的虚部 (公开成员函数)
operator+=operator-=operator*=operator/= | 两个复数，或一个复数与一个标量的复合赋值 (公开成员函数)

非成员函数

operator+operator-
 对复数运用一元运算符
(函数模板)
operator+operator-operator*operator/
 在两个复数，或一个复数与一个标量上进行复数算术运算
(函数模板)
operator==operator!=
(C++20 中移除)
 比较两个复数，或一个复数与一个标量
(函数模板)
operator<<operator>>
 复数的序列化和反序列化
(函数模板)
real
 返回实部
(函数模板)
imag
 返回虚部
(函数模板)
abs(std::complex)
 返回复数的模
(函数模板)
arg
 返回辐角
(函数模板)
norm
 返回模(范数)的平方
(函数模板)
conj
 返回复共轭
(函数模板)
proj
(C++11)
 返回到黎曼球上的投影
(函数模板)
polar
 从模和辐角构造复数
(函数模板)
指数函数
exp(std::complex)
 以 e 为底复数的指数
(函数模板)
log(std::complex)
 沿负实轴切割的复自然对数
(函数模板)
log10(std::complex)
 沿负实轴分割的复常用对数
(函数模板)
幂函数
pow(std::complex)
 复数幂，一或两个参数可为复数
(函数模板)
sqrt(std::complex)
 右半平面范围中的复平方根
(函数模板)
三角函数
sin(std::complex)
 计算复数的正弦（ \({\small\sin{z} }\)sin(z) ）
(函数模板)
cos(std::complex)
 计算复数的余弦（ \({\small\cos{z} }\)cos(z) ）
(函数模板)
tan(std::complex)
 计算复数的正切（ \({\small\tan{z} }\)tan(z) ）
(函数模板)
asin(std::complex)
(C++11)
 计算复数的反正弦（ \({\small\arcsin{z} }\)arcsin(z) ）
(函数模板)
acos(std::complex)
(C++11)
 计算复数的反余弦（ \({\small\arccos{z} }\)arccos(z) ）
(函数模板)
atan(std::complex)
(C++11)
 计算复数的反正切（ \({\small\arctan{z} }\)arctan(z) ）
(函数模板)
双曲函数
sinh(std::complex)
 计算复数的双曲正弦（ \({\small\sinh{z} }\)sinh(z) ）
(函数模板)
cosh(std::complex)
 计算复数的双曲余弦（ \({\small\cosh{z} }\)cosh(z) ）
(函数模板)
tanh(std::complex)
 计算复数的双曲正切（ \({\small\tanh{z} }\)tanh(z) ）
(函数模板)
asinh(std::complex)
(C++11)
 计算复数的反双曲正弦（ \({\small\operatorname{arsinh}{z} }\)arsinh(z) ）
(函数模板)
acosh(std::complex)
(C++11)
 计算复数的反双曲余弦（ \({\small\operatorname{arcosh}{z} }\)arcosh(z) ）
(函数模板)
atanh(std::complex)
(C++11)
 计算复数的反双曲正切（ \({\small\operatorname{artanh}{z} }\)artanh(z) ）
(函数模板)

通过数组访问

对于任何 complex<T> 类型的对象 z ， reinterpret_cast<T(&)[2]>(z)[0] 为 z 的实部且 reinterpret_cast<T(&)[2]>(z)[1] 为 z 的虚部。

对于任何名为 p 指向 complex<T> 数组元素的指针，及任何合法下标 i ， reinterpret_cast<T*>(p)[2*i] 等于复数 p[i] 的实部，而 reinterpret_cast<T*>(p)[2*i + 1] 等于复数 p[i] 的虚部

此要求的目的是 C++ 复数类型与 C 语言复数类型（及其数组）的二进制兼容性，其中要求相同的对象表示。

 (C++11 起)

实现注解

为满足数组访问的要求，实现需满足在单独且相邻的内存位置存储 std::complex 特化的实部和虚部。其非静态数据成员的可能声明包括：

  • 数组类型 value_type[2] ，其首元素存有实部而第二元素存有虚部（例如 Microsoft Visual Studio ）；
  • 单个 value_type _Complex 类型成员（封装对应的 C 语言复数类型）（例如 GNU libstdc++ ）；
  • 两个拥有相同访问权限的 value_type 类型成员，分别存有实部和虚部（例如 LLVM libc++ ）。

实现不能添加会占用与实部和虚部冲突的存储的非静态数据成员，而且必须确保类模板特化不含任何填充。实现也必须确保对数组访问的优化问题，其中要考虑到指向 value_type 的指针可能为 std::complex 特化的别名，对应的数组亦然。

 (C++11 起)

字面量

定义于内联命名空间 std::literals::complex_literals
operator""ifoperator""ioperator""il
(C++14)
 表示纯虚数的 std::complex 字面量
(函数)

示例

#include <iostream>
#include <iomanip>
#include <complex>
#include <cmath>

int main()
{
    using namespace std::complex_literals;
    std::cout << std::fixed << std::setprecision(1);

    std::complex<double> z1 = 1i * 1i;     // 虚数单位平方
    std::cout << "i * i = " << z1 << '\n';

    std::complex<double> z2 = std::pow(1i, 2); // 虚数单位平方
    std::cout << "pow(i, 2) = " << z2 << '\n';

    double PI = std::acos(-1);
    std::complex<double> z3 = std::exp(1i * PI); // 欧拉方程
    std::cout << "exp(i * pi) = " << z3 << '\n';

    std::complex<double> z4 = 1. + 2i, z5 = 1. - 2i; // 共轭
    std::cout << "(1+2i)*(1-2i) = " << z4 * z5 << '\n';
}

输出：

i * i = (-1.0,0.0)
pow(i, 2) = (-1.0,0.0)
exp(i * pi) = (-1.0,0.0)
(1+2i)*(1-2i) = (5.0,0.0)

参阅


std::abs(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
template< class T >
T abs( const complex<T>& z );

返回复数 z 的绝对值。

参数

z - 复数值

返回值

若不出现错误，则返回 z 的绝对值（又称为范数、模或幅度）。

错误和特殊情形按照此函数实现成 std::hypot (std::real(z), std::imag(z)) 一般处理

示例

#include <iostream>
#include <complex>

int main()
{
    std::complex<double> z(1, 1);
    std::cout << z << " cartesian is rho = " << std::abs(z)
              << " theta = " << std::arg(z) << " polar\n";
}

输出：

(1,1) cartesian is rho = 1.41421 theta = 0.785398 polar

参阅

arg | 返回辐角 (函数模板)
polar | 从模和辐角构造复数 (函数模板)
abs(int)labsllabs (C++11) | 计算整数值的绝对值（ \(\small{|x|}\)|x| ） (函数)
abs(float)fabsfabsffabsl (C++11)(C++11) | 浮点值的绝对值（ \(\small{|x|}\)|x| ） (函数)
hypothypotfhypotl (C++11)(C++11)(C++11) | 计算两个给定数的平方和的平方根（ \(\scriptsize{\sqrt{x^2+y^2} }\)√x2 +y2 ） (函数)
abs(std::valarray) | 应用函数 std::abs 到 valarray 的每个元素 (函数模板)


std::acos(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex> |
template< class T > complex<T> acos( const complex<T>& z ); | (C++11 起)

计算复数值 z 的复弧（反）余弦。分支切割在沿实轴的区间 [−1,+1] 外。

参数

z - 复数值

返回值

若不出现错误，则返回 z 的复弧（反）余弦，于沿实轴的范围 [0 ; ∞) 且于沿虚轴的范围 [−iπ ; iπ] 中。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • std::acos (std::conj(z)) == std::conj( std::acos (z))
  • 若 z 为 (±0,+0) ，则结果为 (π/2,-0)
  • 若 z 为 (±0,NaN) ，则结果为 (π/2,NaN)
  • 若 z 为 (x,+∞) （对于任何有限 x ），则结果为 (π/2,-∞)
  • 若 z 为 (x,NaN) （对于任何有限非零 x ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID 。
  • 若 z 为 (-∞,y) （对于任何有限正 y ），则结果为 (π,-∞)
  • 若 z 为 (+∞,y) （对于任何有限正 y ），则结果为 (+0,-∞)
  • 若 z 为 (-∞,+∞) ，则结果为 (3π/4,-∞)
  • 若 z 为 (+∞,+∞) ，则结果为 (π/4,-∞)
  • 若 z 为 (±∞,NaN) ，则结果为 (NaN,±∞) （虚部符号未指定）
  • 若 z 为 (NaN,y) （对于任何有限 y ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID 。
  • 若 z 为 (NaN,+∞) ，则结果为 (NaN,-∞)
  • 若 z 为 (NaN,NaN) ，则结果为 (NaN,NaN)

注意

反余弦（或弧余弦）是多值函数，要求复平面上的分支切割。约定将分支切割置于实轴的线段 (-∞,-1) 和 (1,∞) 上。

弧（反）余弦主值的数学定义是 acos z =
1
2
π + iln(iz + √1-z2
) 。

对于任何 z ， acos(z) = π - acos(-z) 。

示例

#include <iostream>
#include <cmath>
#include <complex>

int main()
{
    std::cout << std::fixed;
    std::complex<double> z1(-2, 0);
    std::cout << "acos" << z1 << " = " << std::acos(z1) << '\n';

    std::complex<double> z2(-2, -0.0);
    std::cout << "acos" << z2 << " (the other side of the cut) = "
              << std::acos(z2) << '\n';

    // 对于任何 z ， acos(z) = pi - acos(-z)
    const double pi = std::acos(-1);
    std::complex<double> z3 = pi - std::acos(z2);
    std::cout << "cos(pi - acos" << z2 << ") = " << std::cos(z3) << '\n';
}

输出：

acos(-2.000000,0.000000) = (3.141593,-1.316958)
acos(-2.000000,-0.000000) (the other side of the cut) = (3.141593,1.316958)
cos(pi - acos(-2.000000,-0.000000)) = (2.000000,0.000000)

参阅

asin(std::complex) (C++11) | 计算复数的反正弦（ \({\small\arcsin{z} }\)arcsin(z) ） (函数模板)
atan(std::complex) (C++11) | 计算复数的反正切（ \({\small\arctan{z} }\)arctan(z) ） (函数模板)
cos(std::complex) | 计算复数的余弦（ \({\small\cos{z} }\)cos(z) ） (函数模板)
acosacosfacosl (C++11)(C++11) | 计算反余弦（ \({\small\arccos{x} }\)arccos(x) ） (函数)
acos(std::valarray) | 应用函数 std::acos 到 valarray 的每个元素 (函数模板)


std::acosh(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex> |
template< class T > complex<T> acosh( const complex<T>& z ); | (C++11 起)

计算复数值 z 的复反双曲余弦，分支切割在沿实轴小于 1 的值上。

参数

z - 复数值

返回值

若不出现错误，则返回 z 的复反双曲余弦，沿实轴在区间 [0; ∞) 中，而沿虚轴在区间 [−iπ; +iπ] 中。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • std::acosh (std::conj(z)) == std::conj( std::acosh (z))
  • 若 z 为 (±0,+0) ，则结果为 (+0,π/2)
  • 若 z 为 (x,+∞) （对于任何有限 x ），则结果为 (+∞,π/2)
  • 若 z 为 (x,NaN) （对于任何[1]有限 x ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID 。
  • 若 z 为 (-∞,y) （对于任何有限正 y ），则结果为 (+∞,π)
  • 若 z 为 (+∞,y) （对于任何有限正 y ），则结果为 (+∞,+0)
  • 若 z 为 (-∞,+∞) ，则结果为 (+∞,3π/4)
  • 若 z 为 (±∞,NaN) ，则结果为 (+∞,NaN)
  • 若 z 为 (NaN,y) （对于任何有限 y ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID 。
  • 若 z 为 (NaN,+∞) ，则结果为 (+∞,NaN)
  • 若 z 为 (NaN,NaN) ，则结果为 (NaN,NaN)
  1. ↑ 由 C11 DR471 ，这只对非零 x 成立。若 z 为 (0,NaN) ，则结果应为 (NaN,π/2)

注意

尽管 C++ 标准命名此函数为“复弧双曲余弦”，双曲函数的反函数是面积函数。其参数为双曲扇形的面积，而非弧长。正确名称是“复反双曲余弦”，和更少见的“复面积双曲余弦”。

反双曲余弦是多值函数，在复平面上要求分支切割。约定将分支切割置于实轴的线段 (-∞,+1) 上。

复反双曲余弦主值的数学定义是 acosh z = ln(z + √z+1 √z-1) 。

对于任何 z ， acosh(z) =
√z-1
√1-z
acos(z) ，或在复平面上半部简单地为 i acos(z) 。

示例

#include <iostream>
#include <complex>

int main()
{
    std::cout << std::fixed;
    std::complex<double> z1(0.5, 0);
    std::cout << "acosh" << z1 << " = " << std::acosh(z1) << '\n';

    std::complex<double> z2(0.5, -0.0);
    std::cout << "acosh" << z2 << " (the other side of the cut) = "
              << std::acosh(z2) << '\n';

    // 在上半平面， acosh = i acos
    std::complex<double> z3(1, 1), i(0, 1);
    std::cout << "acosh" << z3 << " = " << std::acosh(z3) << '\n'
              << "i*acos" << z3 << " = " << i*std::acos(z3) << '\n';
}

输出：

acosh(0.500000,0.000000) = (0.000000,-1.047198)
acosh(0.500000,-0.000000) (the other side of the cut) = (0.000000,1.047198)
acosh(1.000000,1.000000) = (1.061275,0.904557)
i*acos(1.000000,1.000000) = (1.061275,0.904557)

参阅

acos(std::complex) (C++11) | 计算复数的反余弦（ \({\small\arccos{z} }\)arccos(z) ） (函数模板)
asinh(std::complex) (C++11) | 计算复数的反双曲正弦（ \({\small\operatorname{arsinh}{z} }\)arsinh(z) ） (函数模板)
atanh(std::complex) (C++11) | 计算复数的反双曲正切（ \({\small\operatorname{artanh}{z} }\)artanh(z) ） (函数模板)
cosh(std::complex) | 计算复数的双曲余弦（ \({\small\cosh{z} }\)cosh(z) ） (函数模板)
acoshacoshfacoshl (C++11)(C++11)(C++11) | 计算反双曲余弦（ \({\small\operatorname{arcosh}{x} }\)arcosh(x) ） (函数)


std::arg(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex> |  |
template< class T > T arg( const complex<T>& z ); | (1) |
long double arg( long double z ); | (2) | (C++11 起)
template< class DoubleOrInteger > double arg( DoubleOrInteger z ); | (3) | (C++11 起)
float arg( float z ); | (4) | (C++11 起)

计算复数 z 的辐角（以弧度表示）

(C++11 起)为 float 、 double 、 long double 及所有整数类型提供重载，它们被当做有零虚部的复数

参数

z - 复数值

返回值

若无错误发生，则返回 z 在区间 (−π; π) 内的辐角。

错误和特殊情况按照函数宛如以 std::atan2 (std::imag(z), std::real(z)) 实现来处理。

示例

#include <iostream>
#include <complex>

int main()
{
    std::complex<double> z1(1, 0);
    std::cout << "phase angle of " << z1 << " is " << std::arg(z1) << '\n';

    std::complex<double> z2(0, 1);
    std::cout << "phase angle of " << z2 << " is " << std::arg(z2) << '\n';

    std::complex<double> z3(-1, 0);
    std::cout << "phase angle of " << z3 << " is " << std::arg(z3) << '\n';

    std::complex<double> z4(-1, -0.0);
    std::cout << "phase angle of " << z4 << " (the other side of the cut) is "
              << std::arg(z4) << '\n';
}

输出：

phase angle of (1,0) is 0
phase angle of (0,1) is 1.5708
phase angle of (-1,0) is 3.14159
phase angle of (-1,-0) (the other side of the cut) is -3.14159

参阅

abs(std::complex) | 返回复数的模 (函数模板)
polar | 从模和辐角构造复数 (函数模板)
atan2atan2fatan2l (C++11)(C++11) | 反正切，用符号确定象限 (函数)
atan2(std::valarray) | 应用函数 std::atan2 到一个 valarray 和一个值 (函数模板)


std::asin(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex> |
template< class T > complex<T> asin( const complex<T>& z ); | (C++11 起)

计算 z 的复弧（反）正弦。分支切割存在于沿实轴的 [−1,+1] 区间外。

参数

z - 复数值

返回值

若不出现错误，则返回 z 的复弧正弦，在沿虚轴无界，沿实轴在区间 [−π/2; +π/2] 中的条状范围中。

如同运算以 -i * std::asinh(i*z) 实现一般处理错误和特殊情况，其中 i 是虚数单位。

注意

反正弦（或弧正弦）是多值函数，且在复平面上要求分支切割。约定将分支切割置于实轴上的线段 (-∞,-1) 和 (1,∞) 上。

弧（反）正弦主值的数学定义是 asin z = -iln(iz + √1-z2
) 。

对于任何 z ， asin(z) = acos(-z) -
π
2
。

示例

#include <iostream>
#include <cmath>
#include <complex>

int main()
{
    std::cout << std::fixed;
    std::complex<double> z1(-2, 0);
    std::cout << "acos" << z1 << " = " << std::acos(z1) << '\n';

    std::complex<double> z2(-2, -0.0);
    std::cout << "acos" << z2 << " (the other side of the cut) = "
              << std::acos(z2) << '\n';

    // 对于任何 z ， acos(z) = pi - acos(-z)
    const double pi = std::acos(-1);
    std::complex<double> z3 = pi - std::acos(z2);
    std::cout << "cos(pi - acos" << z2 << ") = " << std::cos(z3) << '\n';
}

输出：

asin(-2.000000,0.000000) = (-1.570796,1.316958)
asin(-2.000000,-0.000000) (the other side of the cut) = (-1.570796,-1.316958)
sin(acos(-2.000000,-0.000000) - pi/2) = (-2.000000,-0.000000)

参阅

acos(std::complex) (C++11) | 计算复数的反余弦（ \({\small\arccos{z} }\)arccos(z) ） (函数模板)
atan(std::complex) (C++11) | 计算复数的反正切（ \({\small\arctan{z} }\)arctan(z) ） (函数模板)
sin(std::complex) | 计算复数的正弦（ \({\small\sin{z} }\)sin(z) ） (函数模板)
asinasinfasinl (C++11)(C++11) | 计算反正弦（ \({\small\arcsin{x} }\)arcsin(x) ） (函数)
asin(std::valarray) | 应用函数 std::asin 到 valarray 的每个元素 (函数模板)


std::asinh(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex> |
template< class T > complex<T> asinh( const complex<T>& z ); | (C++11 起)

计算 z 的复反双曲正弦，分支切割在沿虚轴的 [−i; +i] 区间外。

参数

z - 复数值

返回值

若不出现错误，则返回 z 的复反双曲正弦，在沿实轴数学上无界，沿虚轴在区间 [−iπ/2; +iπ/2] 中的条状范围中。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • std::asinh (std::conj(z)) == std::conj( std::asinh (z))
  • std::asinh (-z) == - std::asinh (z)
  • 若 z 为 (+0,+0) ，则结果为 (+0,+0)
  • 若 z 为 (x,+∞) （对于任何有限正 x ），则结果为 (+∞,π/2)
  • 若 z 为 (x,NaN) （对于任何有限 x ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID
  • 若 z 为 (+∞,y) （对于任何有限正 y ），则结果为 (+∞,+0)
  • 若 z 为 (+∞,+∞) ，则结果为 (+∞,π/4)
  • 若 z 为 (+∞,NaN) ，则结果为 (+∞,NaN)
  • 若 z 为 (NaN,+0) ，则结果为 (NaN,+0)
  • 若 z 为 (NaN,y) （对于任何有限非零 y ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID
  • 若 z 为 (NaN,+∞) ，则结果为 (±∞,NaN) （实部符号未指定）
  • 若 z 为 (NaN,NaN) ，则结果为 (NaN,NaN)

注意

尽管 C++ 标准命名此函数为“复弧双曲正弦”函数，双曲函数的反函数仍是面积函数。其参数是双曲扇形的面积，而非弧长。正确的名称是“复反双曲正弦”或较不常用的“复面积双曲正弦”。

反双曲正弦是多值函数，而在复平面上要求分支切割。约定将分支置于虚轴的线段 (-i∞,-i) 和 (i,i∞) 上。

反双曲正弦主值的数学定义是 asinh z = ln(z + √1+z2
) 。

对于任何 z ， asinh(z) =
asin(iz)
i
。

示例

#include <iostream>
#include <complex>

int main()
{
    std::cout << std::fixed;
    std::complex<double> z1(0, -2);
    std::cout << "asinh" << z1 << " = " << std::asinh(z1) << '\n';

    std::complex<double> z2(-0.0, -2);
    std::cout << "asinh" << z2 << " (the other side of the cut) = "
              << std::asinh(z2) << '\n';

    // 对于任何 z ， asinh(z) = asin(iz)/i
    std::complex<double> z3(1,2);
    std::complex<double> i(0,1);
    std::cout << "asinh" << z3 << " = " << std::asinh(z3) << '\n'
              << "asin" << z3*i << "/i = " << std::asin(z3*i)/i << '\n';
}

输出：

asinh(0.000000,-2.000000) = (1.316958,-1.570796)
asinh(-0.000000,-2.000000) (the other side of the cut) = (-1.316958,-1.570796)
asinh(1.000000,2.000000) = (1.469352,1.063440)
asin(-2.000000,1.000000)/i = (1.469352,1.063440)

参阅

acosh(std::complex) (C++11) | 计算复数的反双曲余弦（ \({\small\operatorname{arcosh}{z} }\)arcosh(z) ） (函数模板)
atanh(std::complex) (C++11) | 计算复数的反双曲正切（ \({\small\operatorname{artanh}{z} }\)artanh(z) ） (函数模板)
sinh(std::complex) | 计算复数的双曲正弦（ \({\small\sinh{z} }\)sinh(z) ） (函数模板)
asinhasinhfasinhl (C++11)(C++11)(C++11) | 计算反双曲正弦（ \({\small\operatorname{arsinh}{x} }\)arsinh(x) ） (函数)


std::atan(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex> |
template< class T > complex<T> atan( const complex<T>& z ); | (C++11 起)

计算复数值 z 的复弧（反）正切。分支切割存在于虚轴上的 [−i ; +i] 区间之外。

参数

z - 复数值

返回值

若不发生错误，则返回 z 的复弧（反）正切，在沿虚轴无界，沿实轴在区间 [−π/2; +π/2] 内的条状范围中。

按照如同以 -i * std::atanh(i*z) 实现运算一般处理错误和特殊情况，其中 i 为虚数单位。

注意

反正切（或弧正切）是多值函数而要求复平面上的分支切割。约定分支切割置于虚轴的线段 (-∞i,-i) 和 (+i,+∞i) 上。

反正切主值的数学定义是 atan z = -
1
2
i [ln(1 - iz) - ln (1 + iz)] 。

示例

#include <iostream>
#include <complex>
#include <cmath>
int main()
{
    std::cout << std::fixed;
    std::complex<double> z1(0, 2);
    std::cout << "atan" << z1 << " = " << std::atan(z1) << '\n';

    std::complex<double> z2(-0.0, 2);
    std::cout << "atan" << z2 << " (the other side of the cut) = "
              << std::atan(z2) << '\n';

    std::complex<double> z3(0, INFINITY);
    std::cout << "2*atan" << z3 << " = " << 2.0*std::atan(z3) << '\n';
}

输出：

atan(0.000000,2.000000) = (1.570796,0.549306)
atan(-0.000000,2.000000) (the other side of the cut) = (-1.570796,0.549306)
2*atan(0.000000,inf) = (3.141593,0.000000)

参阅

asin(std::complex) (C++11) | 计算复数的反正弦（ \({\small\arcsin{z} }\)arcsin(z) ） (函数模板)
acos(std::complex) (C++11) | 计算复数的反余弦（ \({\small\arccos{z} }\)arccos(z) ） (函数模板)
tan(std::complex) | 计算复数的正切（ \({\small\tan{z} }\)tan(z) ） (函数模板)
atanatanfatanl (C++11)(C++11) | 计算反正切（ \({\small\arctan{x} }\)arctan(x) ） (函数)
atan(std::valarray) | 应用函数 std::atan 到 valarray 的每个元素 (函数模板)


std::atanh(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex> |
template< class T > complex<T> atanh( const complex<T>& z ); | (C++11 起)

计算 z 的复反双曲正切，其分支切割为沿实轴的 [−1; +1] 区间外部。

参数

z - 复数值

返回值

若不发生错误，则返回 z 的复反双曲正切，范围在数学上为沿着实轴无界的半条，沿着虚轴为区间 [−iπ/2; +iπ/2] 。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • std::atanh (std::conj(z)) == std::conj( std::atanh (z))
  • std::atanh (-z) == - std::atanh (z)
  • 若 z 为 (+0,+0) ，则结果为 (+0,+0)
  • 若 z 为 (+0,NaN) ，则结果为 (+0,NaN)
  • 若 z 为 (+1,+0) ，则结果为 (+∞,+0) 并引发 FE_DIVBYZERO
  • 若 z 为 (x,+∞) （对于任何有限正 x ），则结果为 (+0,π/2)
  • 若 z 为 (x,NaN) （对于任何有限非零 x ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID
  • 若 z 为 (+∞,y) （对于任何有限正 y ），结果为 (+0,π/2)
  • 若 z 为 (+∞,+∞) ，则结果为 (+0,π/2)
  • 若 z 为 (+∞,NaN) ，则结果为 (+0,NaN)
  • 若 z 为 (NaN,y) （对于任何有限的 y ） ，则结果为 (NaN,NaN) 并可能引发 FE_INVALID
  • 若 z 为 (NaN,+∞) ，则结果为 (±0,π/2) （实部的符号未指定）
  • 若 z 为 (NaN,NaN) ，则结果为 (NaN,NaN)

注意

尽管 C++ 标准命名此函数为“复弧双曲正切”，双曲函数的反函数却是面积函数。其参数是双曲扇形的面积，而非弧长。正确的名称是“复反双曲正切”，和较少见的“复面积双曲正切”。

反双曲正切是多值函数，并要求复平面上的分支切割。我们约定将分支切割置于实轴的划分线 (-∞,-1] 和 [+1,+∞) 。

反双曲正切的主值的数学定义是 atanh z =
ln(1+z)-ln(z-1)
2
。

对于任何 z ， atanh(z) =
atan(iz)
i
。

示例

#include <iostream>
#include <complex>

int main()
{
    std::cout << std::fixed;
    std::complex<double> z1(2, 0);
    std::cout << "atanh" << z1 << " = " << std::atanh(z1) << '\n';

    std::complex<double> z2(2, -0.0);
    std::cout << "atanh" << z2 << " (the other side of the cut) = "
              << std::atanh(z2) << '\n';

    // 对于任何 z ， atanh(z) = atanh(iz)/i
    std::complex<double> z3(1,2);
    std::complex<double> i(0,1);
    std::cout << "atanh" << z3 << " = " << std::atanh(z3) << '\n'
              << "atan" << z3*i << "/i = " << std::atan(z3*i)/i << '\n';
}

输出：

atanh(2.000000,0.000000) = (0.549306,1.570796)
atanh(2.000000,-0.000000) (the other side of the cut) = (0.549306,-1.570796)
atanh(1.000000,2.000000) = (0.173287,1.178097)
atan(-2.000000,1.000000)/i = (0.173287,1.178097)

参阅

asinh(std::complex) (C++11) | 计算复数的反双曲正弦（ \({\small\operatorname{arsinh}{z} }\)arsinh(z) ） (函数模板)
acosh(std::complex) (C++11) | 计算复数的反双曲余弦（ \({\small\operatorname{arcosh}{z} }\)arcosh(z) ） (函数模板)
tanh(std::complex) | 计算复数的双曲正切（ \({\small\tanh{z} }\)tanh(z) ） (函数模板)
atanhatanhfatanhl (C++11)(C++11)(C++11) | 计算反双曲正切（ \({\small\operatorname{artanh}{x} }\)artanh(x) ） (函数)


std::complex<T>::complex

< cpp‎ | numeric‎ | complex
初等模板 complex<T>
complex( const T& re = T(), const T& im = T() );
 (1) (C++14 前)
constexpr complex( const T& re = T(), const T& im = T() );
 (1) (C++14 起)
complex( const complex& other );
 (2) (C++14 前)
constexpr complex( const complex& other );
 (2) (C++14 起)
template< class X >
complex( const complex<X>& other);
 (3) (C++14 前)
template< class X >
constexpr complex( const complex<X>& other);
 (3) (C++14 起)
特化 complex<float>
complex(float re = 0.0f, float im = 0.0f);
 (1) (C++11 前)
constexpr complex(float re = 0.0f, float im = 0.0f);
 (1) (C++11 起)
explicit complex(const complex<double>& other);
explicit complex(const complex<long double>& other);
 (3) (C++11 前)
explicit constexpr complex(const complex<double>& other);
explicit constexpr complex(const complex<long double>& other);
 (3) (C++11 起)
特化 complex<double>
complex(double re = 0.0, double im = 0.0);
 (1) (C++11 前)
constexpr complex(double re = 0.0, double im = 0.0);
 (1) (C++11 起)
complex(const complex<float>& other);
explicit complex(const complex<long double>& other);
 (3) (C++11 前)
constexpr complex(const complex<float>& other);
explicit constexpr complex(const complex<long double>& other);
 (3) (C++11 起)
特化 complex<long double>
complex(long double re = 0.0L, long double im = 0.0L);
 (1) (C++11 前)
constexpr complex(long double re = 0.0L, long double im = 0.0L);
 (1) (C++11 起)
complex(const complex<float>& other);
complex(const complex<double>& other);
 (3) (C++11 前)
constexpr complex(const complex<float>& other);
constexpr complex(const complex<double>& other);
 (3) (C++11 起)

构造 std::complex 对象。

1) 从实部和虚部构造复数。
2) 复制构造函数。以 other 内容的副本构造复数。复制构造函数在标准特化中为隐式。
3) 转化构造函数。从不同类型的复数构造对象。

参数

re | - | 实部
im | - | 虚部
other | - | 用作源的另一复数

参阅

operator= | 赋值内容 (公开成员函数)
operator""ifoperator""ioperator""il (C++14) | 表示纯虚数的 std::complex 字面量 (函数)


std::conj(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
(1)
template< class T >
std::complex <T> conj( const std::complex <T>& z );
 (C++20 前)
template< class T >
constexpr std::complex <T> conj( const std::complex <T>& z );
 (C++20 起)
(2)
std::complex <float> conj( float z );

template< class DoubleOrInteger >
std::complex <double> conj( DoubleOrInteger z );

std::complex <long double> conj( long double z );
 (C++11 起)
(C++20 前)
constexpr std::complex <float> conj( float z );

template< class DoubleOrInteger >
constexpr std::complex <double> conj( DoubleOrInteger z );

constexpr std::complex <long double> conj( long double z );
 (C++20 起)
1) 通过反转虚部符号计算 z 的复共轭。
2) 为 float 、 double 、 long double 和所有整数类型添加额外重载，它们将参数当做虚部为零的复数。
 (C++11 起)

参数

z - 复数值

返回值

z 的复共轭

示例

#include <iostream>
#include <complex>

int main()
{
    std::complex<double> z(1,2);
    std::cout << "The conjugate of " << z << " is " << std::conj(z) << '\n'
              << "Their product is " << z*std::conj(z) << '\n';
}

输出：

The conjugate of (1,2) is (1,-2)
Their product is (5,0)

参阅

abs(std::complex) | 返回复数的模 (函数模板)
norm | 返回模(范数)的平方 (函数模板)
polar | 从模和辐角构造复数 (函数模板)


std::cos(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
template< class T >
complex<T> cos( const complex<T>& z );

计算复数值 z 的复余弦。

参数

z - 复数值

返回值

若不出现错误，则返回 z 的复余弦。

如同以 std::cosh(i*z) 实现运算一般处理错误和特殊情况，其中 i 为虚数单位。

注意

余弦在复平面上是整函数，而且无分支切割。

余弦的数学定义是 cos z =
eiz
+e-iz
2
。

示例

#include <iostream>
#include <cmath>
#include <complex>

int main()
{
    std::cout << std::fixed;
    std::complex<double> z(1, 0); // 表现类似沿实轴的实余弦
    std::cout << "cos" << z << " = " << std::cos(z)
              << " ( cos(1) = " << std::cos(1) << ")\n";

    std::complex<double> z2(0, 1); // 表现类似沿虚轴的实 cosh
    std::cout << "cos" << z2 << " = " << std::cos(z2)
              << " (cosh(1) = " << std::cosh(1) << ")\n";
}

输出：

cos(1.000000,0.000000) = (0.540302,-0.000000) ( cos(1) = 0.540302)
cos(0.000000,1.000000) = (1.543081,-0.000000) (cosh(1) = 1.543081)

参阅

sin(std::complex) | 计算复数的正弦（ \({\small\sin{z} }\)sin(z) ） (函数模板)
tan(std::complex) | 计算复数的正切（ \({\small\tan{z} }\)tan(z) ） (函数模板)
acos(std::complex) (C++11) | 计算复数的反余弦（ \({\small\arccos{z} }\)arccos(z) ） (函数模板)
coscosfcosl (C++11)(C++11) | 计算余弦（ \({\small\cos{x} }\)cos(x) ） (函数)
cos(std::valarray) | 应用函数 std::cos 到 valarray 的每个元素 (函数模板)


std::cosh(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex> |
template< class T > complex<T> cosh( const complex<T>& z ); | (C++11 起)

计算 z 的复双曲余弦。

参数

z - 复数值

返回值

若不发生错误，则返回 z 的复双曲余弦。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则，

  • std::cosh (std::conj(z)) == std::conj( std::cosh (z))
  • std::cosh (z) == std::cosh (-z)
  • 若 z 为 (+0,+0) ，则结果为 (1,+0)
  • 若 z 为 (+0,+∞) ，则结果为 (NaN,±0) （虚部符号未指定）并引发 FE_INVALID
  • 若 z 为 (+0,NaN) ，则结果为 (NaN,±0) (（虚部符号未指定）
  • 若 z 为 (x,+∞) （对于任何有限非零 x ），则结果为 (NaN,NaN) 并引发 FE_INVALID
  • 若 z 为 (x,NaN) （对于任何有限非零 x ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID
  • 若 z 为 (+∞,+0)，则结果为 (+∞,+0)
  • 若 z 为 (+∞,y) （对于任何有限非零 y ），则结果为 +∞cis(y)
  • 若 z 为 (+∞,+∞)，则结果为 (±∞,NaN) （实部符号未指定）并引发 FE_INVALID
  • 若 z 为 (+∞,NaN)，则结果为 (+∞,NaN)
  • 若 z 为 (NaN,+0)，则结果为 (NaN,±0) （虚部符号未指定）
  • 若 z 为 (NaN,+y) （对于任何有限非零 y ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID
  • 若 z 为 (NaN,NaN)，则结果为 (NaN,NaN)

其中 cis(y) 为 cos(y) + i sin(y) 。

注意

双曲余弦的数学定义是 cosh z =
ez
+e-z
2
。

双曲余弦在复平面上是整函数，而无分支切割。它相对于虚部是周期的，周期为 2πi 。

示例

#include <iostream>
#include <cmath>
#include <complex>

int main()
{
    std::cout << std::fixed;
    std::complex<double> z(1, 0); // 表现如沿实轴的实 cosh
    std::cout << "cosh" << z << " = " << std::cosh(z)
              << " (cosh(1) = " << std::cosh(1) << ")\n";

    std::complex<double> z2(0, 1); // 表现如沿虚轴的实余弦
    std::cout << "cosh" << z2 << " = " << std::cosh(z2)
              << " ( cos(1) = " << std::cos(1) << ")\n";
}

输出：

cosh(1.000000,0.000000) = (1.543081,0.000000) (cosh(1) = 1.543081)
cosh(0.000000,1.000000) = (0.540302,0.000000) ( cos(1) = 0.540302)

参阅

sinh(std::complex) | 计算复数的双曲正弦（ \({\small\sinh{z} }\)sinh(z) ） (函数模板)
tanh(std::complex) | 计算复数的双曲正切（ \({\small\tanh{z} }\)tanh(z) ） (函数模板)
acosh(std::complex) (C++11) | 计算复数的反双曲余弦（ \({\small\operatorname{arcosh}{z} }\)arcosh(z) ） (函数模板)
coshcoshfcoshl (C++11)(C++11) | 计算双曲余弦（ \({\small\cosh{x} }\)cosh(x) ） (函数)
cosh(std::valarray) | 在 valarray 的每个元素上调用 std::cosh 函数 (函数模板)


std::exp(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
template< class T >
complex<T> exp( const complex<T>& z );

计算 z 的底 e 指数，即 e （欧拉数， 2.7182818 ）的 z 次幂。

参数

z - 复数值

返回值

若不出现错误，则返回 e 的 z 次幂， ez
 。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • std::exp (std::conj(z)) == std::conj( std::exp (z))
  • 若 z 为 (±0,+0) ，则结果为 (1,+0) 。
  • 若 z 为 (x,+∞) （对于任何有限 x ），则结果为 (NaN,NaN) 并引发 FE_INVALID 。
  • 若 z 为 (x,NaN) （对于任何有限 x ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID 。
  • 若 z 为 (+∞,+0) ，则结果为 (+∞,+0) 。
  • 若 z 为 (-∞,y) （对于任何有限 y ），则结果为 +0cis(y) 。
  • 若 z 为 (+∞,y) （对于任何有限非零 y ），则结果为 +∞cis(y) 。
  • 若 z 为 (-∞,+∞) ，则结果为 (±0,±0) （符号未指定）。
  • 若 z 为 (+∞,+∞) ，则结果为 (±∞,NaN) 并引发 FE_INVALID （实部符号未指定）
  • 若 z 为 (-∞,NaN) ，则结果为 (±0,±0) （符号未指定）
  • 若 z 为 (+∞,NaN) ，则结果为 (±∞,NaN) （实部符号未指定）
  • 若 z 为 (NaN,+0) ，则结果为 (NaN,+0)
  • 若 z 为 (NaN,y) （对于任何非零 y ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID 。
  • 若 z 为 (NaN,NaN) ，则结果为 (NaN,NaN) 。

其中 cis(y) 为 cos(y) + i sin(y) 。

注意

复指数函数 ez
 对于自变量 z = x+iy 的值等于 ex
 cis(y) ，或 ex
 (cos(y) + i sin(y)) 。

指数函数在复平面上是整函数且无分支切割。

示例

#include <complex>
#include <iostream>

int main()
{
   const double pi = std::acos(-1);
   const std::complex<double> i(0, 1);

   std::cout << std::fixed << " exp(i*pi) = " << std::exp(i * pi) << '\n';
}

输出：

exp(i*pi) = (-1.000000,0.000000)

参阅

log(std::complex) | 沿负实轴切割的复自然对数 (函数模板)
expexpfexpl (C++11)(C++11) | 返回 e 的给定次幂（ \({\small e^x}\)ex ） (函数)
exp(std::valarray) | 应用函数 std::exp 到 valarray 的每个元素 (函数模板)


std::complex<T>::imag

< cpp‎ | numeric‎ | complex
初等模板 complex<T> |
 | (1)
T imag() const; |  | (C++14 前)
constexpr T imag() const; |  | (C++14 起)
 | (2)
void imag( T value ); |  | (C++20 前)
constexpr void imag( T value ); |  | (C++20 起)
特化 complex<float> |
 | (1)
float imag() const; |  | (C++11 前)
constexpr float imag(); |  | (C++11 起) (C++14 前)
constexpr float imag() const; |  | (C++14 起)
 | (2)
void imag( float value ); |  | (C++20 前)
constexpr void imag( float value ); |  | (C++20 起)
特化 complex<double> |
 | (1)
double imag() const; |  | (C++11 前)
constexpr double imag(); |  | (C++11 起) (C++14 前)
constexpr double imag() const; |  | (C++14 起)
 | (2)
void imag( double value ); |  | (C++20 前)
constexpr void imag( double value ); |  | (C++20 起)
特化 complex<long double> |
 | (1)
long double imag() const; |  | (C++11 前)
constexpr long double imag(); |  | (C++11 起) (C++14 前)
constexpr long double imag() const; |  | (C++14 起)
 | (2)
void imag( long double value ); |  | (C++20 前)
constexpr void imag( long double value ); |  | (C++20 起)

访问复数的虚部。

1) 返回虚部。
2) 设置虚部为 value 。

参数

value - 设置虚部到的值

参阅

imag | 返回虚部 (函数模板)
real | 访问复数的实部 (公开成员函数)


std::imag(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
(1)
template< class T >
T imag( const std::complex <T>& z );
 (C++14 前)
template< class T >
constexpr T imag( const std::complex <T>& z );
 (C++14 起)
(2)
float imag( float z );

template< class DoubleOrInteger >
double imag( DoubleOrInteger z );

long double imag( long double z );
 (C++11 起)
(C++14 前)
constexpr float imag( float z );

template< class DoubleOrInteger >
constexpr double imag( DoubleOrInteger z );

constexpr long double imag( long double z );
 (C++14 起)
1) 返回复数 z 的虚部，即 z.imag() 。
2) 为 float 、 double 、 long double 和所有整数类型提供额外重载，将它们当做拥有零虚部的复数。
 (C++11 起)

参数

z - 复数值

返回值

z 的虚部

参阅

imag | 访问复数的虚部 (公开成员函数)
real | 返回实部 (函数模板)


std::log(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
template< class T >
complex<T> log( const complex<T>& z );

计算 z 的复自然（底 e ）对数，分支切割沿负实轴。

参数

z - 复数值

返回值

若不发生错误，则返回 z 的复自然对数，在沿虚轴为区间 [−iπ, +iπ] ，沿实轴为数学上无界的条状范围中。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • 考虑虚部符号，函数连续到分支切割上
  • std::log (std::conj(z)) == std::conj( std::log (z))
  • 若 z 为 (-0,+0) ，则结果为 (-∞,π) 并引发 FE_DIVBYZERO
  • 若 z 为 (+0,+0) ，则结果为 (-∞,+0) 并引发 FE_DIVBYZERO
  • 若 z 为 (x,+∞) （对于任何有限 x ），则结果为 (+∞,π/2)
  • 若 z 为 (x,NaN) （对于任何有限 x ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID
  • 若 z 为 (-∞,y) （对于任何有限正 y ），则结果为 (+∞,π)
  • 若 z 为 (+∞,y) （对于任何有限正 y ），则结果为 (+∞,+0)
  • 若 z 为 (-∞,+∞) ，则结果为 (+∞,3π/4)
  • 若 z 为 (+∞,+∞) ，则结果为 (+∞,π/4)
  • 若 z 为 (±∞,NaN)，则结果为 (+∞,NaN)
  • 若 z 为 (NaN,y) （对于任何有限 y ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID
  • 若 z 为 (NaN,+∞) ，则结果为 (+∞,NaN)
  • 若 z 为 (NaN,NaN) ，则结果为 (NaN,NaN)

注意

拥有极坐标表示 (r,θ) 的复数 z 的自然对数等于 ln r + i(θ+2nπ) ，其主值为 ln r + iθ 。

此函数语义的目的是与 C 函数 clog 一致。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2597 | C++98 | 规定错误地处理了有符号零虚部 | 移除错误的要求

示例

#include <iostream>
#include <cmath>
#include <complex>

int main()
{
    std::complex<double> z(0, 1); // // r = 1, θ = pi/2
    std::cout << "2*log" << z << " = " << 2.*std::log(z) << '\n';

    std::complex<double> z2(sqrt(2)/2, sqrt(2)/2); // r = 1, θ = pi/4
    std::cout << "4*log" << z2 << " = " << 4.*std::log(z2) << '\n';

    std::complex<double> z3(-1, 0); // r = 1, θ = pi
    std::cout << "log" << z3 << " = " << std::log(z3) << '\n';
    std::complex<double> z4(-1, -0.0); // 分支的另一侧
    std::cout << "log" << z4 << " (the other side of the cut) = " << std::log(z4) << '\n';
}

输出：

2*log(0,1) = (0,3.14159)
4*log(0.707107,0.707107) = (0,3.14159)
log(-1,0) = (0,3.14159)
log(-1,-0) (the other side of the cut) = (0,-3.14159)

参阅

log10(std::complex) | 沿负实轴分割的复常用对数 (函数模板)
exp(std::complex) | 以 e 为底复数的指数 (函数模板)
loglogflogl (C++11)(C++11) | 计算自然（以 e 为底）对数（ \({\small \ln{x} }\)ln(x) ） (函数)
log(std::valarray) | 应用函数 std::log 到 valarray 的每个元素 (函数模板)


std::log10(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
template< class T >
complex<T> log10( const complex<T>& z );

计算复数值 z 的复常用（底 10 ）对数，分支切割沿负实轴。

此函数的行为等价于 std::log(z)/std::log(T(10)) 。

参数

z - 复数值

返回值

z 的复常用对数

示例

#include <iostream>
#include <cmath>
#include <complex>

int main()
{
    std::complex<double> z(0, 1); // // r = 0, θ = pi/2
    std::cout << "2*log10" << z << " = " << 2.*std::log10(z) << '\n';

    std::complex<double> z2(sqrt(2)/2, sqrt(2)/2); // r = 1, θ = pi/4
    std::cout << "4*log10" << z2 << " = " << 4.*std::log10(z2) << '\n';

    std::complex<double> z3(-100, 0); // r = 100, θ = pi
    std::cout << "log10" << z3 << " = " << std::log10(z3) << '\n';
    std::complex<double> z4(-100, -0.0); // 切割的另一侧
    std::cout << "log10" << z4 << " (the other side of the cut) = "
              << std::log10(z4) << '\n'
              << "(note: pi/log(10) = " << acos(-1)/log(10) << ")\n";
}

输出：

2*log10(0,1) = (0,1.36438)
4*log10(0.707107,0.707107) = (0,1.36438)
log10(-100,0) = (2,1.36438)
log10(-100,-0) (the other side of the cut) = (2,-1.36438)
(note: pi/log(10) = 1.36438)

参阅

log(std::complex) | 沿负实轴切割的复自然对数 (函数模板)
log10log10flog10l (C++11)(C++11) | 计算常用（以 10 为底）对数（ \({\small \log_{10}{x} }\)log10(x) ） (函数)
log10(std::valarray) | 应用函数 std::log10 到 valarray 的每个元素 (函数模板)


std::norm(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
(1)
template< class T >
T norm( const std::complex <T>& z );
 (C++20 前)
template< class T >
constexpr T norm( const std::complex <T>& z );
 (C++20 起)
(2)
float norm( float z );

template< class DoubleOrInteger >
double norm( DoubleOrInteger z );

long double norm( long double z );
 (C++11 起)
(C++20 前)
constexpr float norm( float z );

template< class DoubleOrInteger >
constexpr double norm( DoubleOrInteger z );

constexpr long double norm( long double z );
 (C++20 起)
1) 返回复数 z 模的平方。
2) 为 float 、 double 、 long double 和所有整数类型提供附加重载，把参数当做拥有零虚部的复数。
 (C++11 起)

参数

z - 复数值

返回值

z 的模的平方。

注意

此函数所计算的范数亦被称为域范数或绝对平方。

std::abs 提供复数的欧几里得范数，其计算成本更高。某些情形中，可用 std::norm 替换它，例如若 abs(z1) > abs(z2) 则 norm(z1) > norm(z2) 。

参阅

abs(std::complex) | 返回复数的模 (函数模板)
conj | 返回复共轭 (函数模板)
polar | 从模和辐角构造复数 (函数模板)


std::literals::complex_literals::operator""i, operator""if, operator""il

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
constexpr complex<double> operator""i(long double arg);
constexpr complex<double> operator""i(unsigned long long arg);
 (1) (C++14 起)
constexpr complex<float> operator""if(long double arg);
constexpr complex<float> operator""if(unsigned long long arg);
 (2) (C++14 起)
constexpr complex<long double> operator""il(long double arg);
constexpr complex<long double> operator""il(unsigned long long arg);
 (3) (C++14 起)

构成表示虚数的 std::complex 字面量。

1) 构成实部为零而虚部为 arg 的 std::complex <double> 字面量
2) 构成实部为零而虚部为 arg 的 std::complex <float> 字面量
3) 构成实部为零而虚部为 arg 的 std::complex <long double> 字面量

参数

arg - 虚数的值

返回值

实部为零而虚部为 arg 的 std::complex 字面量

注解

这些运算符声明于命名空间 std::literals::complex_literals ，其中 literals 和 complex_literals 都是内联命名空间。可以由 using namespace std::literals 、 using namespace std::complex_literals 和 using namespace std::literals::complex_literals 获取对这些运算符的访问。

尽管 if 在 C++ 中是关键词，它亦为 operator ""if 形式的字面量运算符 的 ud-suffix ，并在如 1if 或 1.0if 的字面量表达式中，因为它不被空白符分隔而且它不是独立记号。

可能的实现

版本一
constexpr std::complex<double> operator""i(unsigned long long d)
{
    return std::complex<double>{0.0, static_cast<double>(d)};
}
constexpr std::complex<double> operator""i(long double d)
{
    return std::complex<double>{0.0, static_cast<double>(d)};
}
版本二
constexpr std::complex<float> operator""if(unsigned long long d)
{
    return std::complex<float>{0.0f, static_cast<float>(d)};
}
constexpr std::complex<float> operator""if(long double d)
{
    return std::complex<float>{0.0f, static_cast<float>(d)};
}
版本三
constexpr std::complex<long double> operator""il(unsigned long long d)
{
    return std::complex<long double>{0.0L, static_cast<long double>(d)};
}
constexpr std::complex<long double> operator""il(long double d)
{
    return std::complex<long double>{0.0L, d};
}

示例

#include <iostream>
#include <complex>

int main()
{
    using namespace std::complex_literals;
    std::complex<double> c = 1.0 + 1i;
    std::cout << "abs" << c << " = " << std::abs(c) << '\n';
    std::complex<float> z = 3.0f + 4.0if;
    std::cout << "abs" << z << " = " << std::abs(z) << '\n';
}

输出：

abs(1,1) = 1.41421
abs(3,4) = 5

参阅

(构造函数) | 构造一个复数 (公开成员函数)
operator= | 赋值内容 (公开成员函数)


std::complex<T>::operator=

< cpp‎ | numeric‎ | complex
初等模板 complex<T> |
 | (1)
complex& operator=(const T& x); |  | (C++20 前)
constexpr complex& operator=(const T& x); |  | (C++20 起)
特化 complex<float> |
 | (1)
complex& operator=(float x); |  | (C++20 前)
constexpr complex& operator=(float x); |  | (C++20 起)
特化 complex<double> |
 | (1)
complex& operator=(double x); |  | (C++20 前)
constexpr complex& operator=(double x); |  | (C++20 起)
特化 complex<long double> |
 | (1)
complex& operator=(long double x); |  | (C++20 前)
constexpr complex& operator=(long double x); |  | (C++20 起)
所有特化 |
 | (2)
complex& operator=(const complex& cx); |  | (C++20 前)
constexpr complex& operator=(const complex& cx); |  | (C++20 起)
 | (3)
template<class X> complex& operator=(const std::complex <X>& cx); |  | (C++20 前)
template<class X> constexpr complex& operator=(const std::complex <X>& cx); |  | (C++20 起)

赋新值给内容。

1) 赋值 x 给复数的实部。虚部设为零。
2,3) 分别把赋值 cx.real() 和 cx.imag() 给复数的实部和虚部。

参数

x | - | 要赋值的值
cx | - | 要赋值的复数值

返回值

*this

参阅

(构造函数) | 构造一个复数 (公开成员函数)
operator""ifoperator""ioperator""il (C++14) | 表示纯虚数的 std::complex 字面量 (函数)


std::complex<T>::operator+=,-=,*=,/=

< cpp‎ | numeric‎ | complex
初等模板 complex<T> |
 | (1)
complex& operator+=(const T& other); |  | (C++20 前)
constexpr complex& operator+=(const T& other); |  | (C++20 起)
 | (2)
complex& operator-=(const T& other); |  | (C++20 前)
constexpr complex& operator-=(const T& other); |  | (C++20 起)
 | (3)
complex& operator*=(const T& other); |  | (C++20 前)
constexpr complex& operator*=(const T& other); |  | (C++20 起)
 | (4)
complex& operator/=(const T& other); |  | (C++20 前)
constexpr complex& operator/=(const T& other); |  | (C++20 起)
特化 complex<float> |
 | (1)
complex& operator+=(float other); |  | (C++20 前)
constexpr complex& operator+=(float other); |  | (C++20 起)
 | (2)
complex& operator-=(float other); |  | (C++20 前)
constexpr complex& operator-=(float other); |  | (C++20 起)
 | (3)
complex& operator*=(float other); |  | (C++20 前)
constexpr complex& operator*=(float other); |  | (C++20 起)
 | (4)
complex& operator/=(float other); |  | (C++20 前)
constexpr complex& operator/=(float other); |  | (C++20 起)
特化 complex<double> |
 | (1)
complex& operator+=(double other); |  | (C++20 前)
constexpr complex& operator+=(double other); |  | (C++20 起)
 | (2)
complex& operator-=(double other); |  | (C++20 前)
constexpr complex& operator-=(double other); |  | (C++20 起)
 | (3)
complex& operator*=(double other); |  | (C++20 前)
constexpr complex& operator*=(double other); |  | (C++20 起)
 | (4)
complex& operator/=(double other); |  | (C++20 前)
constexpr complex& operator/=(double other); |  | (C++20 起)
特化 complex<long double> |
 | (1)
complex& operator+=(long double other); |  | (C++20 前)
constexpr complex& operator+=(long double other); |  | (C++20 起)
 | (2)
complex& operator-=(long double other); |  | (C++20 前)
constexpr complex& operator-=(long double other); |  | (C++20 起)
 | (3)
complex& operator*=(long double other); |  | (C++20 前)
constexpr complex& operator*=(long double other); |  | (C++20 起)
 | (4)
complex& operator/=(long double other); |  | (C++20 前)
constexpr complex& operator/=(long double other); |  | (C++20 起)
所有特化 |
 | (5)
template<class X> complex& operator+=(const std::complex <X>& other); |  | (C++20 前)
template<class X> constexpr complex& operator+=(const std::complex <X>& other); |  | (C++20 起)
 | (6)
template<class X> complex& operator-=(const std::complex <X>& other); |  | (C++20 前)
template<class X> constexpr complex& operator-=(const std::complex <X>& other); |  | (C++20 起)
 | (7)
template<class X> complex& operator*=(const std::complex <X>& other); |  | (C++20 前)
template<class X> constexpr complex& operator*=(const std::complex <X>& other); |  | (C++20 起)
 | (8)
template<class X> complex& operator/=(const std::complex <X>& other); |  | (C++20 前)
template<class X> constexpr complex& operator/=(const std::complex <X>& other); |  | (C++20 起)

为复数算术和复数/标量混合算术实现复合赋值运算符。把标量参数当做复数，它拥有等于参数的实部和设为零的虚部。

1,5) 将 other 加到 *this 。
2,6) 从 *this 减去 other 。
3,7) 将 *this 乘上 other 。
4,8) 以 other 除 *this 。

参数

other - 匹配类型（ float 、 double 、 long double ）的复数或标量值

返回值

*this

参阅

operator+operator- | 对复数运用一元运算符 (函数模板)
operator+operator-operator*operator/ | 在两个复数，或一个复数与一个标量上进行复数算术运算 (函数模板)


std::complex<T>::operator+(unary), operator-(unary)

< cpp‎ | numeric‎ | complex
 | (1)
template< class T > std::complex <T> operator+( const std::complex <T>& val ); |  | (C++20 前)
template< class T > constexpr std::complex <T> operator+( const std::complex <T>& val ); |  | (C++20 起)
 | (2)
template< class T > std::complex <T> operator-( const std::complex <T>& val ); |  | (C++20 前)
template< class T > constexpr std::complex <T> operator-( const std::complex <T>& val ); |  | (C++20 起)

为复数实现一元算术运算符的类似物。

1) 返回其参数的值
2) 求参数的相反数

参数

val - 复数参数

返回值

1) 参数的副本， std::complex <T>(val)
2) 参数的相反数， std::complex <T>(-val.real(), -val.imag())

参阅

operator+operator-operator*operator/
 在两个复数，或一个复数与一个标量上进行复数算术运算
(函数模板)


operator+,-,*,/ (std::complex)

< cpp‎ | numeric‎ | complex
 | (1)
template< class T > std::complex <T> operator+( const std::complex <T>& lhs, const std::complex <T>& rhs); |  | (C++20 前)
template< class T > constexpr std::complex <T> operator+( const std::complex <T>& lhs, const std::complex <T>& rhs); |  | (C++20 起)
 | (2)
template< class T > std::complex <T> operator+( const std::complex <T>& lhs, const T& rhs); |  | (C++20 前)
template< class T > constexpr std::complex <T> operator+( const std::complex <T>& lhs, const T& rhs); |  | (C++20 起)
 | (3)
template< class T > std::complex <T> operator+( const T& lhs, const std::complex <T>& rhs); |  | (C++20 前)
template< class T > constexpr std::complex <T> operator+( const T& lhs, const std::complex <T>& rhs); |  | (C++20 起)
 | (4)
template< class T > std::complex <T> operator-( const std::complex <T>& lhs, const std::complex <T>& rhs); |  | (C++20 前)
template< class T > constexpr std::complex <T> operator-( const std::complex <T>& lhs, const std::complex <T>& rhs); |  | (C++20 起)
 | (5)
template< class T > std::complex <T> operator-( const std::complex <T>& lhs, const T& rhs); |  | (C++20 前)
template< class T > constexpr std::complex <T> operator-( const std::complex <T>& lhs, const T& rhs); |  | (C++20 起)
 | (6)
template< class T > std::complex <T> operator-( const T& lhs, const std::complex <T>& rhs); |  | (C++20 前)
template< class T > constexpr std::complex <T> operator-( const T& lhs, const std::complex <T>& rhs); |  | (C++20 起)
 | (7)
template< class T > std::complex <T> operator*( const std::complex <T>& lhs, const std::complex <T>& rhs); |  | (C++20 前)
template< class T > constexpr std::complex <T> operator*( const std::complex <T>& lhs, const std::complex <T>& rhs); |  | (C++20 起)
 | (8)
template< class T > std::complex <T> operator*( const std::complex <T>& lhs, const T& rhs); |  | (C++20 前)
template< class T > constexpr std::complex <T> operator*( const std::complex <T>& lhs, const T& rhs); |  | (C++20 起)
 | (9)
template< class T > std::complex <T> operator*( const T& lhs, const std::complex <T>& rhs); |  | (C++20 前)
template< class T > constexpr std::complex <T> operator*( const T& lhs, const std::complex <T>& rhs); |  | (C++20 起)
 | (10)
template< class T > std::complex <T> operator/( const std::complex <T>& lhs, const std::complex <T>& rhs); |  | (C++20 前)
template< class T > constexpr std::complex <T> operator/( const std::complex <T>& lhs, const std::complex <T>& rhs); |  | (C++20 起)
 | (11)
template< class T > std::complex <T> operator/( const std::complex <T>& lhs, const T& rhs); |  | (C++20 前)
template< class T > constexpr std::complex <T> operator/( const std::complex <T>& lhs, const T& rhs); |  | (C++20 起)
 | (12)
template< class T > std::complex <T> operator/( const T& lhs, const std::complex <T>& rhs); |  | (C++20 前)
template< class T > constexpr std::complex <T> operator/( const T& lhs, const std::complex <T>& rhs); |  | (C++20 起)

为复数运算和混合复数/标量运算实现二元运算符。将标量当做拥有等于参数的实部和设为零的虚部的复数。

1-3) 返回其参数的和
4-6) 返回从 lhs 减去 rhs 的结果
7-9) 将参数相乘
10-12) lhs 除以 rhs

参数

lhs, rhs - 参数：两个复数，或一个复数与一个拥有匹配类型的标量（ float 、 double 、 long double ）

返回值

1-3) std::complex <T>(lhs) += rhs
4-6) std::complex <T>(lhs) -= rhs
7-9) std::complex <T>(lhs) *= rhs
10-12) std::complex <T>(lhs) /= rhs

注意

模板实参推导不考虑隐式转换，故这些运算符不能用于整数/复数混合运算。所有情况下，标量必须与复数的底层类型拥有相同类型。

GCC 标志 "-fcx-limited-range" （包含于 "-ffast-math" ）更改复数乘/除的行为，移除浮点极端情况的检查。这会影响向量化。

示例

#include <iostream>
#include <complex>
int main()
{
    std::complex<double> c2(2, 0);
    std::complex<double> ci(0, 1);

    std::cout << ci << " + " << c2 << " = " << ci+c2 << '\n'
              << ci << " * " << ci << " = " << ci*ci << '\n'
              << ci << " + " << c2 << " / " << ci << " = " << ci+c2/ci << '\n'
              << 1  << " / " << ci << " = " << 1./ci << '\n';

//    std::cout << 1.f/ci; // 编译错误
//    std::cout << 1/ci; // 编译错误
}

输出：

(0,1) + (2,0) = (2,1)
(0,1) * (0,1) = (-1,0)
(0,1) + (2,0) / (0,1) = (0,-1)
1 / (0,1) = (0,-1)

参阅

operator+=operator-=operator*=operator/= | 两个复数，或一个复数与一个标量的复合赋值 (公开成员函数)
operator+operator- | 对复数运用一元运算符 (函数模板)


operator==,!=(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex> |
 | (1)
template< class T > bool operator==( const complex<T>& lhs, const complex<T>& rhs); |  | (C++14 前)
template< class T > constexpr bool operator==( const complex<T>& lhs, const complex<T>& rhs); |  | (C++14 起)
 | (2)
template< class T > bool operator==( const complex<T>& lhs, const T& rhs); |  | (C++14 前)
template< class T > constexpr bool operator==( const complex<T>& lhs, const T& rhs); |  | (C++14 起)
 | (3)
template< class T > bool operator==( const T& lhs, const complex<T>& rhs); |  | (C++14 前)
template< class T > constexpr bool operator==( const T& lhs, const complex<T>& rhs); |  | (C++14 起) (C++20 前)
 | (4)
template< class T > bool operator!=( const complex<T>& lhs, const complex<T>& rhs); |  | (C++14 前)
template< class T > constexpr bool operator!=( const complex<T>& lhs, const complex<T>& rhs); |  | (C++14 起) (C++20 前)
 | (5)
template< class T > bool operator!=( const complex<T>& lhs, const T& rhs); |  | (C++14 前)
template< class T > constexpr bool operator!=( const complex<T>& lhs, const T& rhs); |  | (C++14 起) (C++20 前)
 | (6)
template< class T > bool operator!=( const T& lhs, const complex<T>& rhs); |  | (C++14 前)
template< class T > constexpr bool operator!=( const T& lhs, const complex<T>& rhs); |  | (C++14 起) (C++20 前)

比较而二个复数。标量参数被当做拥有等于参数的实部和设为零的虚部的复数。

1-3) 比较 lhs 与 rhs 的相等性。
4-6) 比较 lhs 与 rhs 的不等性。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的参数：要么都是复数，要么是一个复数和另一个匹配类型（ float 、 double 、 long double ）的标量

返回值

1-3) 若 lhs 两部分别等于 rhs ，则为 true ，否则为 false 。
4-6) !(lhs == rhs)

示例

本节未完成
原因：暂无示例
ry:cpp/numeric/complex/operator cmp


operator<<,>>(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
template <class T, class CharT, class Traits>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::complex <T>& x);
 (1)
template <class T, class CharT, class Traits>

std::basic_istream <CharT, Traits>&
operator>>( std::basic_istream <CharT, Traits>& is,

std::complex <T>& x);
 (2)
1) 以 (real,imaginary) 格式写入复数到 os 。
2) 从 is 读取复数。受支持格式为
  • real
  • (real)
  • (real,imaginary)

其中 real 与 imaginary 的输入必须可转换为 T 。

若错误发生则调用 is.setstate(ios_base::failbit)

异常

流错误时可能抛 std::ios_base::failure 。

参数

os | - | 字符输出流
is | - | 字符输入流
x | - | 要被插入或释出的复数

返回值

1) os
2) is

注意

1) 因为逗号可能被当前本地环境用作小数点，故输出可能有歧义。这可用强制显示小数点的 std::showpoint 解决。
2) 输入以简单格式化的释出进行。空白符的跳过对于它们每一项都相同。

可能的实现

template<class T, class charT, class traits>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& o, const complex<T>& x) {
    basic_ostringstream<charT, traits> s;
    s.flags(o.flags());
    s.imbue(o.getloc());
    s.precision(o.precision());
    s << '(' << x.real() << "," << x.imag() << ')';
    return o << s.str();
}


std::polar(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
template< class T >
complex<T> polar( const T& r, const T& theta = T());

返回拥有绝对值 r 和辐角 theta 的复数。

若 r 为负数或 NaN ，或若 theta 为无穷大，则行为未定义。

参数

r | - | 模
theta | - | 辐角

返回值

以 r 和 theta 确定的复数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2459 | C++98 | 某些输入的行为不明 | 使之为未定义
LWG 2870 | C++98 | 参数 theta 的默认值不依赖于类型 | 使之为依赖

参阅

abs(std::complex) | 返回复数的模 (函数模板)
arg | 返回辐角 (函数模板)


std::pow(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex> |  |
template< class T > complex<T> pow( const complex<T>& x, const complex<T>& y); | (1) |
template< class T > complex<T> pow( const complex<T>& x, const T& y); | (2) |
template< class T > complex<T> pow( const T& x, const complex<T>& y); | (3) |
template< class T, class U > complex</*Promoted*/> pow( const complex<T>& x, const complex<U>& y); | (4) | (C++11 起)
template< class T, class U > complex</*Promoted*/> pow( const complex<T>& x, const U& y); | (5) | (C++11 起)
template< class T, class U > complex</*Promoted*/> pow( const T& x, const complex<U>& y); | (6) | (C++11 起)

计算复数 x 的 y 次复数幂，首参数的分支切割沿负实轴。

4-6) 为所有算术类型提供额外重载，使得
1. 若任一参数为 long double 或 std::complex <long double> ，则转型两个参数为 std::complex <long double>
2. 否则，若任一参数为 double 、 std::complex <double> 或整数类型，则转型两个参数为 std::complex <double>
3. 否则，若任一参数为 float 或 std::complex <float> ，则转型两个参数为 std::complex <float>
 (C++11 起)

参数

x | - | 作为底数的复数值
y | - | 作为指数的复数值

返回值

若不出现错误，则返回复幂 xy
 。

错误和特殊情况按照如同以 std::exp (y* std::log (x)) 实现运算一般处理，

std::pow (0, 0) 的结果是实现定义的。

示例

#include <iostream>
#include <complex>

int main()
{
    std::cout << std::fixed;

    std::complex<double> z(1, 2);
    std::cout << "(1,2)^2 = " << std::pow(z, 2) << '\n';

    std::complex<double> z2(-1, 0);  // -1 的平方根
    std::cout << "-1^0.5 = " << std::pow(z2, 0.5) << '\n';

    std::complex<double> z3(-1, -0.0);  // 切割的另一侧
    std::cout << "(-1, -0)^0.5 = " << std::pow(z3, 0.5) << '\n';

    std::complex<double> i(0, 1); // i^i = exp(-pi/2)
    std::cout << "i^i = " << std::pow(i, i) << '\n';
}

输出：

(1,2)^2 = (-3.000000,4.000000)
-1^0.5 = (0.000000,1.000000)
(-1, -0)^0.5 = (0.000000,-1.000000)
i^i = (0.207880,0.000000)

参阅

sqrt(std::complex) | 右半平面范围中的复平方根 (函数模板)
powpowfpowl (C++11)(C++11) | 求某数的给定次幂（ \(\small{x^y}\)xy ） (函数)
pow(std::valarray) | 应用函数 std::pow 到二个 valarray 或一个 valarray 与一个值 (函数模板)


std::proj(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex> |  |
template< class T > std::complex <T> proj( const std::complex <T>& z ); | (1) | (C++11 起)
std::complex <long double> proj( long double z ); | (2) | (C++11 起)
template< class DoubleOrInteger > std::complex <double> proj( DoubleOrInteger z ); | (3) | (C++11 起)
std::complex <float> proj( float z ); | (4) | (C++11 起)

返回复数 z 在黎曼球面上的投影。

对于绝大多数 z ， std::proj(z)==z ，但所有复无穷大，即使是一部为无穷大而另一部为 NaN 者，都变成实正无穷大 ( INFINITY, 0.0) 或 ( INFINITY, -0.0) 。虚部（零）的符号是 std::imag(z) 的符号。

为 float 、 double 、 long double 和所有整数类型提供额外重载，将它们当做拥有正零虚部的复数。

参数

z - 复数值

返回值

z 在黎曼球面上的投影

注意

proj 函数以映射所有无穷大到一（给出或接收虚数零的符号），帮助模拟黎曼球面，而且应该在任何操作，特别是比较浅使用，比较可能对任何其他无穷大给出虚假结果。

示例

#include <iostream>
#include <complex>

int main()
{
    std::complex<double> c1(1, 2);
    std::cout << "proj" << c1 << " = " << std::proj(c1) << '\n';

    std::complex<double> c2(INFINITY, -1);
    std::cout << "proj" << c2 << " = " << std::proj(c2) << '\n';

    std::complex<double> c3(0, -INFINITY);
    std::cout << "proj" << c3 << " = " << std::proj(c3) << '\n';
}

输出：

proj(1,2) = (1,2)
proj(inf,-1) = (inf,-0)
proj(0,-inf) = (inf,-0)

参阅

abs(std::complex) | 返回复数的模 (函数模板)
norm | 返回模(范数)的平方 (函数模板)
polar | 从模和辐角构造复数 (函数模板)


std::complex<T>::real

< cpp‎ | numeric‎ | complex
初等模板 complex<T> |
 | (1)
T real() const; |  | (C++14 前)
constexpr T real() const; |  | (C++14 起)
 | (2)
void real( T value ); |  | (C++20 前)
constexpr void real( T value ); |  | (C++20 起)
特化 complex<float> |
 | (1)
float real() const; |  | (C++11 前)
constexpr float real(); |  | (C++11 起) (C++14 前)
constexpr float real() const; |  | (C++14 起)
 | (2)
void real( float value ); |  | (C++20 前)
constexpr void real( float value ); |  | (C++20 起)
特化 complex<double> |
 | (1)
double real() const; |  | (C++11 前)
constexpr double real(); |  | (C++11 起) (C++14 前)
constexpr double real() const; |  | (C++14 起)
 | (2)
void real( double value ); |  | (C++20 前)
constexpr void real( double value ); |  | (C++20 起)
特化 complex<long double> |
 | (1)
long double real() const; |  | (C++11 前)
constexpr long double real(); |  | (C++11 起) (C++14 前)
constexpr long double real() const; |  | (C++14 起)
 | (2)
void real( long double value ); |  | (C++20 前)
constexpr void real( long double value ); |  | (C++20 起)

访问复数的实部。

1) 返回实部。
2) 设置实部为 value 。

参数

value - 设置实部到的值

返回值

1) 实部。
2) （无）

参阅

real | 返回实部 (函数模板)
imag | 访问复数的虚部 (公开成员函数)


std::real(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
(1)
template< class T >
T real( const std::complex <T>& z );
 (C++14 前)
template< class T >
constexpr T real( const std::complex <T>& z );
 (C++14 起)
(2)
float real( float z );

template< class DoubleOrInteger >
double real( DoubleOrInteger z );

long double real( long double z );
 (C++11 起)
(C++14 前)
constexpr float real( float z );

template< class DoubleOrInteger >
constexpr double real( DoubleOrInteger z );

constexpr long double real( long double z );
 (C++14 起)
1) 返回复数 z 的实部，即 z.real() 。
2) 为 float 、 double 、 long double 和所有整数类型提供额外重载，它们被处理为拥有零虚部的复数。
 (C++11 起)

参数

z - 复数值

返回值

z 的实部

参阅

real | 访问复数的实部 (公开成员函数)
imag | 返回虚部 (函数模板)


std::sin(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
template< class T >
complex<T> sin( const complex<T>& z );

计算 complex 值 z 的复正弦。

参数

z - complex 值

返回值

若无错误发生，则返回 z 的复正弦。

错误和特殊情况处理成如同运算以 -i * std::sinh(i*z) 实现，其中 i 是虚数单位。

注意

正弦是复平面上的整函数，而没有分支。

正弦的数学定义是 sin z =
eiz
-e-iz
2i

示例

#include <iostream>
#include <cmath>
#include <complex>

int main()
{
    std::cout << std::fixed;
    std::complex<double> z(1, 0); // 表现同沿着实轴的实正弦
    std::cout << "sin" << z << " = " << std::sin(z)
              << " ( sin(1) = " << std::sin(1) << ")\n";

    std::complex<double> z2(0, 1); // 表现同沿着虚轴的 sinh
    std::cout << "sin" << z2 << " = " << std::sin(z2)
              << " (sinh(1) = " << std::sinh(1) << ")\n";
}

输出：

sin(1.000000,0.000000) = (0.841471,0.000000) ( sin(1) = 0.841471)
sin(0.000000,1.000000) = (0.000000,1.175201) (sinh(1) = 1.175201)

参阅

cos(std::complex) | 计算复数的余弦（ \({\small\cos{z} }\)cos(z) ） (函数模板)
tan(std::complex) | 计算复数的正切（ \({\small\tan{z} }\)tan(z) ） (函数模板)
asin(std::complex) (C++11) | 计算复数的反正弦（ \({\small\arcsin{z} }\)arcsin(z) ） (函数模板)
sinsinfsinl (C++11)(C++11) | 计算正弦（ \({\small\sin{x} }\)sin(x) ） (函数)
sin(std::valarray) | 对 valarray 的每个元素应用std::sin函数 (函数模板)


std::sinh(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex> |
template< class T > complex<T> sinh( const complex<T>& z ); | (C++11 起)

计算复数值 z 的复双曲正弦。

参数

z - 复数值

返回值

若不出现错误，则返回 z 的复双曲正弦。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • std::sinh (std::conj(z)) == std::conj( std::sinh (z))
  • std::sinh (z) == - std::sinh (-z)
  • 若 z 为 (+0,+0) ，则结果为 (+0,+0)
  • 若 z 为 (+0,+∞) ，则结果为 (±0,NaN) （实部符号未指定）并引发 FE_INVALID
  • 若 z 为 (+0,NaN) ，则结果为 (±0,NaN)
  • 若 z 为 (x,+∞) （对于任何有限正 x ），则结果为 (NaN,NaN) 并引发 FE_INVALID
  • 若 z 为 (x,NaN) （对于任何有限正 x ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID
  • 若 z 为 (+∞,+0) ，则结果为 (+∞,+0)
  • 若 z 为 (+∞,y) （对于任何有限正 y ），则结果为 +∞cis(y)
  • 若 z 为 (+∞,+∞) ，则结果为 (±∞,NaN) （实部符号未指定）并引发 FE_INVALID
  • 若 z 为 (+∞,NaN) ，则结果为 (±∞,NaN) （实部符号未指定）
  • 若 z 为 (NaN,+0) ，则结果为 (NaN,+0)
  • 若 z 为 (NaN,y) （对于任何有限非零 y ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID
  • 若 z 为 (NaN,NaN) ，则结果为 (NaN,NaN)

其中 cis(y) 为 cos(y) + i sin(y) 。

注意

双曲正弦的数学定义是 sinh z =
ez
-e-z
2
。

双曲正弦在复平面上是整函数而无分支切割。它相对于虚部是周期的，周期为 2πi 。

示例

#include <iostream>
#include <cmath>
#include <complex>

int main()
{
    std::cout << std::fixed;
    std::complex<double> z(1, 0); // 表现类似沿实轴的 sinh
    std::cout << "sinh" << z << " = " << std::sinh(z)
              << " (sinh(1) = " << std::sinh(1) << ")\n";

    std::complex<double> z2(0, 1); // 表现类似沿虚轴的正弦
    std::cout << "sinh" << z2 << " = " << std::sinh(z2)
              << " ( sin(1) = " << std::sin(1) << ")\n";
}

输出：

sinh(1.000000,0.000000) = (1.175201,0.000000) (sinh(1) = 1.175201)
sinh(0.000000,1.000000) = (0.000000,0.841471) ( sin(1) = 0.841471)

参阅

cosh(std::complex) | 计算复数的双曲余弦（ \({\small\cosh{z} }\)cosh(z) ） (函数模板)
tanh(std::complex) | 计算复数的双曲正切（ \({\small\tanh{z} }\)tanh(z) ） (函数模板)
asinh(std::complex) (C++11) | 计算复数的反双曲正弦（ \({\small\operatorname{arsinh}{z} }\)arsinh(z) ） (函数模板)
sinhsinhfsinhl (C++11)(C++11) | 计算双曲正弦（ \({\small\sinh{x} }\)sinh(x) ） (函数)
sinh(std::valarray) | 在 valarray 的每个元素上调用 std::sinh 函数 (函数模板)


std::sqrt(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
template< class T >
complex<T> sqrt( const complex<T>& z );

计算复数 z 的平方根，分支切割沿负实轴。

参数

z - 要取平方根的复数

返回值

若不出现错误，则返回 z 的平方根，在包含虚轴的右半平面中（沿实轴为 [0; +∞) ，而沿虚轴为 (−∞; +∞) ）。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • 考虑虚部符号，函数连续到分支切割上
  • std::sqrt (std::conj(z)) == std::conj( std::sqrt (z))
  • 若 z 为 (±0,+0) ，则结果为 (+0,+0)
  • 若 z 为 (x,+∞) ，则结果为 (+∞,+∞) ，即使 x 为 NaN
  • 若 z 为 (x,NaN) ，则结果为 (NaN,NaN) （除非 x 为 ±∞ ）并可能引发 FE_INVALID
  • 若 z 为 (-∞,y) ，则对于有限正 y 结果为 (+0,+∞)
  • 若 z 为 (+∞,y) ，则对于有限正 y 结果为 (+∞,+0)
  • 若 z 为 (-∞,NaN) ，则结果为 (NaN,∞) （虚部符号未指定）
  • 若 z 为 (+∞,NaN) ，则结果为 (+∞,NaN)
  • 若 z 为 (NaN,y) ，则结果为 (NaN,NaN) 并可能引发 FE_INVALID
  • 若 z 为 (NaN,NaN) ，则结果为 (NaN,NaN)

注解

此函数的语义有意与 C 函数 csqrt 一致。

示例

#include <iostream>
#include <complex>

int main()
{
    std::cout << "Square root of -4 is "
              << std::sqrt(std::complex<double>(-4, 0)) << '\n'
              << "Square root of (-4,-0), the other side of the cut, is "
              << std::sqrt(std::complex<double>(-4, -0.0)) << '\n';
}

输出：

Square root of -4 is (0,2)
Square root of (-4,-0), the other side of the cut, is (0,-2)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2597 | C++98 | 规定错处理有符号零虚部有误 | 移除了错误的要求

参阅

pow(std::complex) | 复数幂，一或两个参数可为复数 (函数模板)
sqrtsqrtfsqrtl (C++11)(C++11) | 计算平方根（ \(\small{\sqrt{x} }\)√x ） (函数)
sqrt(std::valarray) | 应用函数 std::sqrt 到 valarray 的每个元素 (函数模板)


std::tan(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex>
template< class T >
complex<T> tan( const complex<T>& z );

计算复数值 z 的复正切。

参数

z - 复数值

返回值

若无错误发生，则返回 z 的复正切。

错误和特殊情况如同运算实现为 -i * std::tanh(i*z) 一般处理，其中 i 是虚数单位。

注意

正切是复平面上的解析函数，而无分支切割。它对于实部是周期的，周期为 πi ，而且沿实轴有一阶极点，位于坐标 (π(1/2 + n), 0) 。然而无常用浮点表示能准确表示 π/2 ，故而没有值使得极点错误出现。

正切的数学定义是 tan z =
i(e-iz
-eiz
)
e-iz
+eiz
。

示例

#include <iostream>
#include <cmath>
#include <complex>

int main()
{
    std::cout << std::fixed;
    std::complex<double> z(1, 0); // 表现类似沿实轴的实正切
    std::cout << "tan" << z << " = " << std::tan(z)
              << " ( tan(1) = " << std::tan(1) << ")\n";

    std::complex<double> z2(0, 1); // 表现类似沿虚轴的 tanh
    std::cout << "tan" << z2 << " = " << std::tan(z2)
              << " (tanh(1) = " << std::tanh(1) << ")\n";
}

输出：

tan(1.000000,0.000000) = (1.557408,0.000000) ( tan(1) = 1.557408)
tan(0.000000,1.000000) = (0.000000,0.761594) (tanh(1) = 0.761594)

参阅

sin(std::complex) | 计算复数的正弦（ \({\small\sin{z} }\)sin(z) ） (函数模板)
cos(std::complex) | 计算复数的余弦（ \({\small\cos{z} }\)cos(z) ） (函数模板)
atan(std::complex) (C++11) | 计算复数的反正切（ \({\small\arctan{z} }\)arctan(z) ） (函数模板)
tantanftanl (C++11)(C++11) | 计算正切（ \({\small\tan{x} }\)tan(x) ） (函数)
tan(std::valarray) | 应用函数 std::tan 到 valarray 的每个元素 (函数模板)


std::tanh(std::complex)

< cpp‎ | numeric‎ | complex
定义于头文件 <complex> |
template< class T > complex<T> tanh( const complex<T>& z ); | (C++11 起)

计算复数值 z 的复双曲正切。

参数

z - 复数值

返回值

若不发生错误，则返回 z 的复双曲正切。

错误处理及特殊值

报告的错误与 math_errhandling 一致。

若实现支持 IEEE 浮点算术，则

  • std::tanh (std::conj(z)) == std::conj( std::tanh (z))
  • std::tanh (-z) == - std::tanh (z)
  • 若 z 为 (+0,+0) ，则结果为 (+0,+0) 。
  • 若 z 为 (x,+∞) （对于任何[1]有限 x ），结果为 (NaN,NaN) 并引发 FE_INVALID 。
  • 若 z 为 (x,NaN) （对于任何[2]有限 x ），结果为 (NaN,NaN) 并可能引发 FE_INVALID 。
  • 若 z 为 (+∞,y) （对于任何有限正 y ），结果为 (1,+0) 。
  • 若 z 为 (+∞,+∞) ，则结果为 (1,±0) （虚部符号未指定）。
  • 若 z 为 (+∞,NaN) ，则结果为 (1,±0) （虚部符号未指定）。
  • 若 z 为 (NaN,+0) ，则结果为 (NaN,+0) 。
  • 若 z 为 (NaN,y) （对于任何非零 y ），则结果为 (NaN,NaN) 并可能引发 FE_INVALID 。
  • 若 z 为 (NaN,NaN) ，则结果为 (NaN,NaN) 。
  1. ↑ 由 C11 DR471 ，这只对非零 x 成立。若 z 为 (0,∞) ，则结果应为 (0,NaN) 。
  2. ↑ 由 C11 DR471 ，这只对非零 x 成立。若 z 为 (0,NaN) ，则结果应为 (0,NaN) 。

注意

双曲正切的数学定义是 tanh z =
ez
-e-z
ez
+e-z
。

双曲正切是复平面上的解析函数且无分支切割。它对于虚部是周期的，周期为 πi ，而且沿虚轴有一阶极点，位于坐标 (0, π(1/2 + n)) 。然而无常用浮点表示能准确表示 π/2 ，故没有参数值能导致极点错误。

示例

#include <iostream>
#include <cmath>
#include <complex>

int main()
{
    std::cout << std::fixed;
    std::complex<double> z(1, 0); // 表现类似沿实轴的 tanh
    std::cout << "tanh" << z << " = " << std::tanh(z)
              << " (tanh(1) = " << std::tanh(1) << ")\n";

    std::complex<double> z2(0, 1); // 表现类似沿虚轴的正切
    std::cout << "tanh" << z2 << " = " << std::tanh(z2)
              << " ( tan(1) = " << std::tan(1) << ")\n";
}

输出：

tanh(1.000000,0.000000) = (0.761594,0.000000) (tanh(1) = 0.761594)
tanh(0.000000,1.000000) = (0.000000,1.557408) ( tan(1) = 1.557408)

参阅

sinh(std::complex) | 计算复数的双曲正弦（ \({\small\sinh{z} }\)sinh(z) ） (函数模板)
cosh(std::complex) | 计算复数的双曲余弦（ \({\small\cosh{z} }\)cosh(z) ） (函数模板)
atanh(std::complex) (C++11) | 计算复数的反双曲正切（ \({\small\operatorname{artanh}{z} }\)artanh(z) ） (函数模板)
tanhtanhftanhl (C++11)(C++11) | 计算双曲正切（ \({\small\tanh{x} }\)tanh(x) ） (函数)
tanh(std::valarray) | 在 valarray 的每个元素上调用 std::tanh 函数 (函数模板)


数学常数

< cpp‎ | numeric

常数 (C++20 起)

定义于头文件 <numbers>
定义于命名空间 std::numbers
e_v
 数学常数 \(\small e\)e
(变量模板)
log2e_v
 \(\log_{2}e\)log
2e
(变量模板)
log10e_v
 \(\log_{10}e\)log
10e
(变量模板)
pi_v
 \(\pi\)π
(变量模板)
inv_pi_v
 \(\frac1\pi\)
1
π

(变量模板)
inv_sqrtpi_v
 \(\frac1{\sqrt\pi}\)
1
√π

(变量模板)
ln2_v
 \(\ln{2}\)ln 2
(变量模板)
ln10_v
 \(\ln{10}\)ln 10
(变量模板)
sqrt2_v
 \(\sqrt2\)√2
(变量模板)
sqrt3_v
 \(\sqrt3\)√3
(变量模板)
inv_sqrt3_v
 \(\frac1{\sqrt3}\)
1
√3

(变量模板)
egamma_v
 欧拉-马歇罗尼常数
(变量模板)
phi_v
 黄金比 Φ 常数 (\(\frac{1+\sqrt5}2\)
1 + √5
2
)
(变量模板)
inline constexpr double e
 e_v<double>
(常量)
inline constexpr double log2e
 log2e_v<double>
(常量)
inline constexpr double log10e
 log10e_v<double>
(常量)
inline constexpr double pi
 pi_v<double>
(常量)
inline constexpr double inv_pi
 inv_pi_v<double>
(常量)
inline constexpr double inv_sqrtpi
 inv_sqrtpi_v<double>
(常量)
inline constexpr double ln2
 ln2_v<double>
(常量)
inline constexpr double ln10
 ln10_v<double>
(常量)
inline constexpr double sqrt2
 sqrt2_v<double>
(常量)
inline constexpr double sqrt3
 sqrt3_v<double>
(常量)
inline constexpr double inv_sqrt3
 inv_sqrt3_v<double>
(常量)
inline constexpr double egamma
 egamma_v<double>
(常量)
inline constexpr double phi
 phi_v<double>
(常量)

注解

实例化数学常数变量模板的初等模板的程序为谬构。

标准库对所有浮点类型（即 float 、 double 与 long double ）特化数学常数变量模板。

程序可以部分或显式特化数学常数变量模板，只要该特化依赖程序定义的类型。

示例

#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <numbers>
#include <string_view>

int main()
{
    using namespace std::numbers;

    std::cout
        << std::pow(e, ln2) / 2 << ' '
        << std::pow(std::cosh(pi), 2) - std::pow(std::sinh(pi), 2) << ' '
        << std::sqrt(pi) * inv_sqrtpi << ' '
        << std::pow(sqrt2 * sqrt3, 2) / 6 << ' '
        << sqrt3 * inv_sqrt3 << ' '
        << log2e * ln2 << ' '
        << log10e * ln10 << ' '
        << pi * inv_pi << ' '
        << phi * phi - phi << '\n';

    auto egamma_aprox = [] {
        long double s = 0, m = 2.0;
        for (unsigned c = 2; c != 1'000'000; ++c, ++m) {
            const long double t = std::riemann_zeta(m) / m;
            (c & 1) == 0 ? s += t : s -= t;
        }
        return s;
    };

    std::cout << std::fixed << (egamma_v<long double> - egamma_aprox()) << '\n';

    constexpr std::string_view γ {"0.577215664901532860606512090082402"};

    std::cout
        << "γ as egamma_v<float>       = "
        << std::setprecision(std::numeric_limits<float>::digits10 + 1)
        << egamma_v<float> << '\n'
        << "γ as egamma_v<double>      = "
        << std::setprecision(std::numeric_limits<double>::digits10 + 1)
        << egamma_v<double> << '\n'
        << "γ as egamma_v<long double> = "
        << std::setprecision(std::numeric_limits<long double>::digits10 + 1)
        << egamma_v<long double> << '\n'
        << "γ with " << γ.length() - 1 << " digits precision = " << γ << '\n';
}

可能的输出：

1 1 1 1 1 1 1 1 1
0.000001
γ as egamma_v<float>       = 0.5772157
γ as egamma_v<double>      = 0.5772156649015329
γ as egamma_v<long double> = 0.5772156649015328606
γ with 34 digits precision = 0.577215664901532860606512090082402


std::countl_one

< cpp‎ | numeric
定义于头文件 <bit> |
template<class T> constexpr int countl_one(T x) noexcept; | (C++20 起)

返回 x 的值中从最高位（“左”）起连续的为 1 （“一”）的位的数量。

此重载仅若 T 为无符号整数类型（即 unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 、 unsigned long long 或扩展无符号整数类型）才参与重载决议。

参数

x - 无符号整数类型的值

返回值

x 的值中从最高位起连续的为 1 的位的数量。

示例

#include <bit>
#include <bitset>
#include <cstdint>
#include <initializer_list>
#include <iostream>

int main()
{
    for (std::uint8_t i : { 0, 0b11111111, 0b11100011 }) {
        std::cout << "countl_one(0b" << std::bitset<8>(i) << ") = "
                  << std::countl_one(i) << '\n';
    }
}

输出：

countl_one(0b00000000) = 0
countl_one(0b11111111) = 8
countl_one(0b11100011) = 3

参阅

countl_zero (C++20) | 从最高位起计量连续的 0 位的数量 (函数模板)
countr_zero (C++20) | 从最低位起计量连续的 0 位的数量 (函数模板)
countr_one (C++20) | 从最低位起计量连续的 1 位的数量 (函数模板)
popcount (C++20) | 计量无符号整数中为 1 的位的数量 (函数模板)


std::countl_zero

< cpp‎ | numeric
定义于头文件 <bit> |
template<class T> constexpr int countl_zero(T x) noexcept; | (C++20 起)

返回 x 的值中从最高位（“左”）起连续的为 0 的位的数量。

此重载仅若 T 为无符号整数类型（即 unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 、 unsigned long long 或扩展无符号整数类型）才参与重载决议。

参数

x - 无符号整数类型的值

返回值

x 的值中从最高位起连续的为 0 的位的数量。

示例

#include <bit>
#include <bitset>
#include <cstdint>
#include <initializer_list>
#include <iostream>

int main()
{
    for (std::uint8_t i : { 0, 0b11111111, 0b00011100 }) {
        std::cout << "countl_zero(0b" << std::bitset<8>(i) << ") = "
                  << std::countl_zero(i) << '\n';
    }
}

输出：

countl_zero(0b00000000) = 8
countl_zero(0b11111111) = 0
countl_zero(0b00011100) = 3

参阅

countl_one (C++20) | 从最高位起计量连续的 1 位的数量 (函数模板)
countr_zero (C++20) | 从最低位起计量连续的 0 位的数量 (函数模板)
countr_one (C++20) | 从最低位起计量连续的 1 位的数量 (函数模板)
popcount (C++20) | 计量无符号整数中为 1 的位的数量 (函数模板)


std::countr_one

< cpp‎ | numeric
定义于头文件 <bit> |
template<class T> constexpr int countr_one(T x) noexcept; | (C++20 起)

返回 x 的值中从最低位（“右”）起连续的为 1 的位的数量。

此重载仅若 T 为无符号整数类型（即 unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 、 unsigned long long 或扩展无符号整数类型）才参与重载决议。

参数

x - 无符号整数类型的值

返回值

x 的值中从最低位起连续的为 1 的位的数量。

示例

#include <bit>
#include <bitset>
#include <cstdint>
#include <initializer_list>
#include <iostream>

int main()
{
    for (std::uint8_t i : { 0, 0b11111111, 0b11100011 }) {
        std::cout << "countr_one(0b" << std::bitset<8>(i) << ") = "
                  << std::countr_one(i) << '\n';
    }
}

输出：

countr_one(0b00000000) = 0
countr_one(0b11111111) = 8
countr_one(0b11100011) = 2

参阅

countl_zero (C++20) | 从最高位起计量连续的 0 位的数量 (函数模板)
countl_one (C++20) | 从最高位起计量连续的 1 位的数量 (函数模板)
countr_zero (C++20) | 从最低位起计量连续的 0 位的数量 (函数模板)
popcount (C++20) | 计量无符号整数中为 1 的位的数量 (函数模板)


std::countr_zero

< cpp‎ | numeric
定义于头文件 <bit> |
template<class T> constexpr int countr_zero(T x) noexcept; | (C++20 起)

返回 x 的值中从最低位（“右”）起连续的为 0 的位的数量。

此重载仅若 T 为无符号整数类型（即 unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 、 unsigned long long 或扩展无符号整数类型）才参与重载决议。

参数

x - 无符号整数类型的值

返回值

x 的值中从最低位起连续的为 0 的位的数量。

示例

#include <bit>
#include <bitset>
#include <cstdint>
#include <initializer_list>
#include <iostream>

int main()
{
    for (std::uint8_t i : { 0, 0b11111111, 0b00011100 }) {
        std::cout << "countr_zero(0b" << std::bitset<8>(i) << ") = "
                  << std::countr_zero(i) << '\n';
    }
}

输出：

countr_zero(0b00000000) = 8
countr_zero(0b11111111) = 0
countr_zero(0b00011100) = 2

参阅

countl_zero (C++20) | 从最高位起计量连续的 0 位的数量 (函数模板)
countl_one (C++20) | 从最高位起计量连续的 1 位的数量 (函数模板)
countr_one (C++20) | 从最低位起计量连续的 1 位的数量 (函数模板)
popcount (C++20) | 计量无符号整数中为 1 的位的数量 (函数模板)


浮点环境

< cpp‎ | numeric

浮点环境是实现所支持的浮点状态标志集合及控制模式。它是线程局域的，每个线程从亲线程继承其浮点环境的初始状态。浮点运算修改浮点状态标志，以指示异常结果或辅助信息。浮点控制模式的状态影响一些浮点运算的产出。

浮点环境访问和修改仅在 #pragma STDC FENV_ACCESS 得到支持并被设为 ON 时有意义。否则实现有假设浮点控制模式始终是默认者，且浮点状态标志决不被测试或被修改的自由。实践中，少数当前编译器，例如 HP aCC 、 Oracle Studio 或 IBM XL 显式支持 #pragma ，但无论如何，大多数编译器允许有意义地访问浮点环境。

类型

定义于头文件 <cfenv>
fenv_t | 表示整个浮点环境的类型
fexcept_t | 汇集地表示所有浮点状态标志的类型

函数

feclearexcept (C++11) | 清除指定的浮点状态标志 (函数)
fetestexcept (C++11) | 确定设置了哪个指定的浮点状态标志 (函数)
feraiseexcept (C++11) | 引发指定的浮点异常 (函数)
fegetexceptflagfesetexceptflag (C++11)(C++11) | 从浮点环境（或向其中）复制指定的浮点状态标志 (函数)
fegetroundfesetround (C++11)(C++11) | 获取或设置舍入方向 (函数)
fegetenvfesetenv (C++11) | 保存或恢复当前浮点环境 (函数)
feholdexcept (C++11) | 保存环境，清除所有状态标志，并忽略所有将来的错误 (函数)
feupdateenv (C++11) | 恢复浮点环境并引发之前引发的异常 (函数)

宏

FE_ALL_EXCEPTFE_DIVBYZEROFE_INEXACTFE_INVALIDFE_OVERFLOWFE_UNDERFLOW (C++11) | 浮点异常 (宏常量)
FE_DOWNWARDFE_TONEARESTFE_TOWARDZEROFE_UPWARD (C++11) | 浮点舍入方向 (宏常量)
FE_DFL_ENV (C++11) | 默认浮点环境 (宏常量)

注意

浮点异常与 C++ 异常无关。浮点运算引发浮点异常时，浮点环境的状态改变，这能用 std::fetestexcept 测试，但绝大多数实现上 C++ 程序执行持续而不中断。

有编译器扩展，可用于凡在引发浮点异常时自动生成 C++ 异常：

  • GNU libc 函数 feenableexcept() 启用浮点异常的陷阱，它生成信号 SIGFPE 。若使用编译器选项 -fnon-call-exceptions ，则该信号的处理函数可抛出用户定义的 C++ 异常。
  • MSVC 函数 _control87() 启用浮点异常的陷阱，它生成硬件异常，这能用 _set_se_translator 转换成 C++ 异常。

参阅


FE_DFL_ENV

< cpp‎ | numeric‎ | fenv
定义于头文件 <cfenv> |
#define FE_DFL_ENV /*implementation defined*/ | (C++11 起)

宏常量 FE_DFL_ENV 展开成 const std::fenv_t* 类型表达式，它指向默认浮点环境，即在程序加载时的浮点环境的完整副本。

实现亦可支持附加的以 FE_ 后随大写字母，并拥有 const std::fenv_t* 类型的宏。

示例

#include <iostream>
#include <cfenv>

#pragma STDC FENV_ACCESS ON

void show_env()
{
    int e = std::fetestexcept(FE_ALL_EXCEPT);
    if(e & FE_DIVBYZERO) std::cout << "division by zero is raised\n";
    if(e & FE_INEXACT)   std::cout << "inexact is raised\n";
    if(e & FE_INVALID)   std::cout << "invalid is raised\n";
    if(e & FE_UNDERFLOW) std::cout << "underflow is raised\n";
    if(e & FE_OVERFLOW)  std::cout << "overflow is raised\n";
    int r = std::fegetround();
    switch(r)
    {
        case FE_DOWNWARD: std::cout << "rounding down\n"; break;
        case FE_TONEAREST: std::cout << "rounding to nearest\n"; break;
        case FE_TOWARDZERO: std::cout << "rounding to zero\n"; break;
        case FE_UPWARD: std::cout << "rounding up\n"; break;
    }
}

int main()
{
    std::cout << "On startup: \n";
    show_env();

    std::feraiseexcept(FE_UNDERFLOW | FE_OVERFLOW);
    std::fesetround(FE_UPWARD);

    std::cout << "\nBefore restoration: \n";
    show_env();

    std::fesetenv(FE_DFL_ENV);

    std::cout << "\nAfter reset to default: \n";
    show_env();
}

输出：

On startup:
rounding to nearest

Before restoration:
underflow is raised
overflow is raised
rounding up

After reset to default:
rounding to nearest

参阅

fegetenvfesetenv (C++11) | 保存或恢复当前浮点环境 (函数)
feupdateenv (C++11) | 恢复浮点环境并引发之前引发的异常 (函数)


FE_DIVBYZERO, FE_INEXACT, FE_INVALID, FE_OVERFLOW, FE_UNDERFLOW, FE_ALL_EXCEPT

< cpp‎ | numeric‎ | fenv
定义于头文件 <cfenv> |
#define FE_DIVBYZERO /*implementation defined power of 2*/ | (C++11 起)
#define FE_INEXACT /*implementation defined power of 2*/ | (C++11 起)
#define FE_INVALID /*implementation defined power of 2*/ | (C++11 起)
#define FE_OVERFLOW /*implementation defined power of 2*/ | (C++11 起)
#define FE_UNDERFLOW /*implementation defined power of 2*/ | (C++11 起)
#define FE_ALL_EXCEPT FE_DIVBYZERO | FE_INEXACT | \ FE_INVALID | FE_OVERFLOW | \ FE_UNDERFLOW | (C++11 起)

所有这些宏常量（除了 FE_ALL_EXCEPT ）都展开成值为 2 的相异次幂整数常量表达式，唯一地鉴别所有受支持浮点异常。每个宏仅若受支持才得到定义。

宏常量 FE_ALL_EXCEPT 展开成所有其他 FE_* 的逐位或，且始终有定义，若实现不支持浮点异常，则为零。

常量 | 定义
FE_DIVBYZERO | 出现于之前浮点运算的极点错误
FE_INEXACT | 不准确结果：必须舍入以存储之前浮点运算的结果
FE_INVALID | 出现于之前浮点运算的定义域错误
FE_OVERFLOW | 之前浮点运算的结果过大而无法表示
FE_UNDERFLOW | 之前浮点运算的结果为有精度损失的非正规值
FE_ALL_EXCEPT | 所有受支持浮点异常的逐位或

实现可于 <cfenv> 定义附加宏常量以鉴别附加浮点异常。所有这种常量都以 FE_ 后随至少一个大写字母开始。

进一步的细节见 math_errhandling 。

示例

#include <iostream>
#include <cfenv>
#include <cmath>

#pragma STDC FENV_ACCESS ON

volatile double zero = 0.0; // 支持 FENV_ACCESS 处不需要 volatile
volatile double one = 1.0;  // 支持 FENV_ACCESS 处不需要 volatile

int main()
{
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout <<  "1.0/0.0 = " << 1.0 / zero << '\n';
    if(std::fetestexcept(FE_DIVBYZERO)) {
        std::cout << "division by zero reported\n";
    } else {
        std::cout << "divsion by zero not reported\n";
    }

    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "1.0/10 = " << one/10 << '\n';
    if(std::fetestexcept(FE_INEXACT)) {
        std::cout << "inexact result reported\n";
    } else {
        std::cout << "inexact result not reported\n";
    }

    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "sqrt(-1) = " << std::sqrt(-1) << '\n';
    if(std::fetestexcept(FE_INVALID)) {
        std::cout << "invalid result reported\n";
    } else {
        std::cout << "invalid result not reported\n";
    }
}

输出：

1.0/0.0 = inf
division by zero reported
1.0/10 = 0.1
inexact result reported
sqrt(-1) = -nan
invalid result reported

参阅

math_errhandlingMATH_ERRNOMATH_ERREXCEPT
(C++11)(C++11)(C++11)
 定义常用数学函数所用的错误处理机制
(宏常量)


FE_DOWNWARD, FE_TONEAREST, FE_TOWARDZERO, FE_UPWARD

< cpp‎ | numeric‎ | fenv
定义于头文件 <cfenv> |
#define FE_DOWNWARD /*implementation defined*/ | (C++11 起)
#define FE_TONEAREST /*implementation defined*/ | (C++11 起)
#define FE_TOWARDZERO /*implementation defined*/ | (C++11 起)
#define FE_UPWARD /*implementation defined*/ | (C++11 起)

每个这种宏展开成非负常量表达式，可被 std::fesetround 或 std::fegetround 用于指示受支持的浮点舍入模式之一。实现可于 <cfenv> 定义另外的舍入模式常量，它应以 FE_ 后随至少一个大写字母开始。每个宏仅若受支持才得到定义。

大多数实现中，这些宏常量展开成的值等于 FLT_ROUNDS 和 std::float_round_style 的值。

常量 | 解释
FE_DOWNWARD | 向负无穷大舍入
FE_TONEAREST | 向最接近可表示值舍入
FE_TOWARDZERO | 向零舍入
FE_UPWARD | 向正无穷大舍入

实现可支持另外的舍入模式。

当前舍入模式影响下列内容：

  • 常量表达式外浮点算术运算符的结果
double x = 1;
x/10; // 0.09999999999999999167332731531132594682276248931884765625
   // or 0.1000000000000000055511151231257827021181583404541015625
  • 标准库数学函数的结果
std::sqrt(2); // 1.41421356237309492343001693370752036571502685546875
           // or 1.4142135623730951454746218587388284504413604736328125
  • 浮点到浮点隐式转换或转型
double d = 1 + std::numeric_limits<double>::epsilon();
float f = d; //  1.00000000000000000000000
           // or 1.00000011920928955078125
  • 例如 std::strtod 或 std::printf 的字符串转换
std::stof("0.1"); // 0.0999999940395355224609375
               // or 0.100000001490116119384765625
  • 库舍入函数 std::nearbyint 、 std::rint 、 std::lrint
std::lrint(2.1); // 2 或 3

当前舍入模式不影响：

  • 浮点到整数的隐式转换或转型（始终向零）
  • 编译时执行的常量表达式中浮点算术运算符的结果（始终向最接近）
  • 库函数 std::round 、 std::lround 、 std::llround 、 std::ceil 、 std::floor 、 std::trunc

同任何浮点环境功能，仅若设置了 #pragma STDC FENV_ACCESS ON 才保证舍入。

示例

#include <iostream>
#include <iomanip>
#include <string>
#include <cfenv>
#include <cmath>
int main()
{
#pragma STDC FENV_ACCESS ON
    std::fesetround(FE_DOWNWARD);
    std::cout << "rounding down: \n" << std::setprecision(50)
              << "         pi = " << std::acos(-1.f) << '\n'
              << "stof(\"1.1\") = " << std::stof("1.1") << '\n'
              << "  rint(2.1) = " << std::rint(2.3) << "\n\n";
    std::fesetround(FE_UPWARD);
    std::cout << "rounding up: \n"
              << "         pi = " << std::acos(-1.f) << '\n'
              << "stof(\"1.1\") = " << std::stof("1.1") << '\n'
              << "  rint(2.1) = " << std::rint(2.3) << '\n';
}

输出：

rounding down:
         pi = 3.141592502593994140625
stof("1.1") = 1.099999904632568359375
  rint(2.1) = 2

rounding up:
         pi = 3.1415927410125732421875
stof("1.1") = 1.10000002384185791015625
  rint(2.1) = 3

参阅

float_round_style | 指示浮点舍入模式 (枚举)
fegetroundfesetround (C++11)(C++11) | 获取或设置舍入方向 (函数)


std::feclearexcept

< cpp‎ | numeric‎ | fenv
定义于头文件 <cfenv> |
int feclearexcept( int excepts ); | (C++11 起)

试图清除列于位掩码参数 excepts 的浮点异常，异常为浮点异常宏的逐位或。

参数

excepts - 列出要清理的异常标志的位掩码

返回值

若成功清除所有指示的异常则或若 excepts 为零则为 ​0​ 。错误时返回非零值。

示例

#include <iostream>
#include <cfenv>
#include <cmath>

#pragma STDC FENV_ACCESS ON

volatile double zero = 0.0; // 支持 FENV_ACCESS 处不需要 volatile
volatile double one = 1.0;  // 支持 FENV_ACCESS 处不需要 volatile

int main()
{
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout <<  "1.0/0.0 = " << 1.0 / zero << '\n';
    if(std::fetestexcept(FE_DIVBYZERO)) {
        std::cout << "division by zero reported\n";
    } else {
        std::cout << "divsion by zero not reported\n";
    }

    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "1.0/10 = " << one/10 << '\n';
    if(std::fetestexcept(FE_INEXACT)) {
        std::cout << "inexact result reported\n";
    } else {
        std::cout << "inexact result not reported\n";
    }

    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "sqrt(-1) = " << std::sqrt(-1) << '\n';
    if(std::fetestexcept(FE_INVALID)) {
        std::cout << "invalid result reported\n";
    } else {
        std::cout << "invalid result not reported\n";
    }
}

输出：

1.0/0.0 = inf
division by zero reported
1.0/10 = 0.1
inexact result reported
sqrt(-1) = -nan
invalid result reported

参阅

fetestexcept
(C++11)
 确定设置了哪个指定的浮点状态标志
(函数)


std::fegetenv, std::fesetenv

< cpp‎ | numeric‎ | fenv
定义于头文件 <cfenv> |  |
int fegetenv( std::fenv_t* envp ) | (1) | (C++11 起)
int fesetenv( const std::fenv_t* envp ); | (2) | (C++11 起)

管理浮点环境的状态。

1) 试图存储浮点环境的状态于 envp 所指向的对象。
2) 试图从 envp 所指向的对象建立浮点环境状态。对象的值必须是以先前调用 std::feholdexcept 或 std::fegetenv 获得值或是浮点宏常量。若 envp 中设置了任何浮点状态标志，则环境中标志变为被设置（然后可用 std::fetestexcept 测试），但不引发对应的浮点异常（执行持续而不中断）。

参数

envp - 指向 std::fenv_t 类型对象的指针，该对象保有浮点环境的状态

返回值

成功时为 ​0​ ，否则为非零。

参阅

feholdexcept (C++11) | 保存环境，清除所有状态标志，并忽略所有将来的错误 (函数)
feupdateenv (C++11) | 恢复浮点环境并引发之前引发的异常 (函数)
FE_DFL_ENV (C++11) | 默认浮点环境 (宏常量)


std::fegetexceptflag, std::fesetexceptflag

< cpp‎ | numeric‎ | fenv
定义于头文件 <cfenv> |  |
int fegetexceptflag( std::fexcept_t* flagp, int excepts ); | (1) | (C++11 起)
int fesetexceptflag( const std::fexcept_t* flagp, int excepts ); | (2) | (C++11 起)

1) 试图获得列于位掩码参数 excepts 的浮点异常标志的完整内容，它是浮点异常宏的逐位或。

2) 试图从 flagp 复制列于 excepts 的浮点异常标志到浮点环境。不引发任何异常，只修改标志。

浮点异常标志的完整内容不必是指示是否引发或清除异常的布尔值。例如，它可以是结构体，包含布尔状态和触发了异常的代码地址。这些函数获得所有这种内容，并以实现定义格式于 flagp 获得/存储它。

参数

flagp | - | 指向将要存储或读取标志位置的 std::fexcept_t 对象的指针
excepts | - | 列出要获取/设置的异常的位掩码

返回值

成功时为 ​0​ ，否则为非零。

参阅


std::feholdexcept

< cpp‎ | numeric‎ | fenv
定义于头文件 <cfenv> |
int feholdexcept( std::fenv_t* envp ) | (C++11 起)

首先，保存当前浮点环境到 envp 所指向的对象（类似 std::fegetenv ），然后清除所有浮点状态标志，再安装不停止模式：未来的浮点异常将不中断执行（不会陷落），直至以 std::feupdateenv 或 std::fesetenv 还原浮点状态。

此函数可用于必须从调用方隐藏它可能引发的浮点异常的子程序的起始。若只是必须抑制某些异常，而其他必须报告，则通常在清除不想要的异常后通过调用 std::feupdateenv 结束不停止模式。

参数

envp - 指向 std::fenv_t 类型对象的指针，其中将存储浮点环境

返回值

成功时为 ​0​ ，否则为非零。

参阅

feupdateenv (C++11) | 恢复浮点环境并引发之前引发的异常 (函数)
fegetenvfesetenv (C++11) | 保存或恢复当前浮点环境 (函数)
FE_DFL_ENV (C++11) | 默认浮点环境 (宏常量)


std::feraiseexcept

< cpp‎ | numeric‎ | fenv
定义于头文件 <cfenv> |
int feraiseexcept( int excepts ); | (C++11 起)

试图引发所有列于 excepts （浮点异常宏的逐位或）的浮点异常。若异常之一是 FE_OVERFLOW 或 FE_UNDERFLOW ，则此函数还会再引发 FE_INEXACT 。引发异常所用的顺序是未指定的，除了 FE_OVERFLOW 和 FE_UNDERFLOW 始终先于 FE_INEXACT 引发。

参数

excepts - 列出要引发的异常标志的位掩码

返回值

若已引发所有列出的异常则为 ​0​ ，否则为非零值。

示例

#include <iostream>
#include <cfenv>

#pragma STDC FENV_ACCESS ON

int main()
{
    std::feclearexcept(FE_ALL_EXCEPT);
    int r = std::feraiseexcept(FE_UNDERFLOW | FE_DIVBYZERO);
    std::cout <<  "Raising divbyzero and underflow simultaneously "
              << (r?"fails":"succeeds") << " and results in\n";
    int e = std::fetestexcept(FE_ALL_EXCEPT);
    if (e & FE_DIVBYZERO) {
        std::cout << "division by zero\n";
    }
    if (e & FE_INEXACT) {
        std::cout << "inexact\n";
    }
    if (e & FE_INVALID) {
        std::cout << "invalid\n";
    }
    if (e & FE_UNDERFLOW) {
        std::cout << "underflow\n";
    }
    if (e & FE_OVERFLOW) {
        std::cout << "overflow\n";
    }
}

输出：

Raising divbyzero and underflow simultaneously succeeds and results in
division by zero
underflow

参阅

feclearexcept (C++11) | 清除指定的浮点状态标志 (函数)
fetestexcept (C++11) | 确定设置了哪个指定的浮点状态标志 (函数)


std::fegetround, std::fesetround

< cpp‎ | numeric‎ | fenv
定义于头文件 <cfenv> |  |
int fesetround( int round ) | (1) | (C++11 起)
int fegetround() | (2) | (C++11 起)

管理浮点舍入方向。

1) 试图建立等于参数 round 的浮点舍入方向，期待参数为浮点舍入宏之一。
2) 返回对应当前舍入方向的浮点舍入宏。

参数

round - 舍入方向，浮点舍入宏之一

返回值

1) 成功时为 ​0​ ，否则为非零。

2) 描述当前舍入方向的浮点舍入宏，或若不能确定方向则为负值

注意

当前舍入方向反映最近的 fesetround 的效果，亦能以 FLT_ROUNDS 查询。

舍入的效果见浮点舍入宏。

示例

#include <cmath>
#include <cfenv>
#include <iostream>

int main()
{
    #pragma STDC FENV_ACCESS ON
    std::fesetround(FE_DOWNWARD);
    std::cout << "rounding using FE_DOWNWARD: \n" << std::fixed
              << " 12.0 ->  " << std::nearbyint(12.0) << '\n'
              << " 12.1 ->  " << std::nearbyint(12.1) << '\n'
              << "-12.1 -> " << std::nearbyint(-12.1) << '\n'
              << " 12.5 ->  " << std::nearbyint(12.5) << '\n'
              << " 12.9 ->  " << std::nearbyint(12.9) << '\n'
              << "-12.9 -> " << std::nearbyint(-12.9) << '\n'
              << " 13.0 ->  " << std::nearbyint(13.0) << '\n';
    std::fesetround(FE_TONEAREST);
    std::cout << "rounding using FE_TONEAREST: \n"
              << " 12.0 ->  " << std::nearbyint(12.0) << '\n'
              << " 12.1 ->  " << std::nearbyint(12.1) << '\n'
              << "-12.1 -> " << std::nearbyint(-12.1) << '\n'
              << " 12.5 ->  " << std::nearbyint(12.5) << '\n'
              << " 12.9 ->  " << std::nearbyint(12.9) << '\n'
              << "-12.9 -> " << std::nearbyint(-12.9) << '\n'
              << " 13.0 ->  " << std::nearbyint(13.0) << '\n';
}

输出：

rounding using FE_DOWNWARD:
 12.0 ->  12.000000
 12.1 ->  12.000000
-12.1 -> -13.000000
 12.5 ->  12.000000
 12.9 ->  12.000000
-12.9 -> -13.000000
 13.0 ->  13.000000
rounding using FE_TONEAREST:
 12.0 ->  12.000000
 12.1 ->  12.000000
-12.1 -> -12.000000
 12.5 ->  12.000000
 12.9 ->  13.000000
-12.9 -> -13.000000
 13.0 ->  13.000000

参阅

nearbyintnearbyintfnearbyintl (C++11)(C++11)(C++11) | 使用当前舍入模式的最接近整数 (函数)
rintrintfrintllrintlrintflrintlllrintllrintfllrintl (C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11) | 使用当前舍入模式的最接近整数 若结果有别则有异常 (函数)


std::fetestexcept

< cpp‎ | numeric‎ | fenv
定义于头文件 <cfenv> |
int fetestexcept( int excepts ); | (C++11 起)

确定当前设定了哪个浮点异常的指定子集。参数 excepts 是浮点异常宏的逐位或。

参数

excepts - 列出要测试的异常标志的位掩码

返回值

包含于 excepts 而且对应于当前设置的浮点异常中的浮点异常宏的逐位或。

示例

#include <iostream>
#include <cfenv>
#include <cmath>

#pragma STDC FENV_ACCESS ON

volatile double zero = 0.0; // 支持 FENV_ACCESS 处不需要 volatile
volatile double one = 1.0;  // 支持 FENV_ACCESS 处不需要 volatile

int main()
{
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout <<  "1.0/0.0 = " << 1.0 / zero << '\n';
    if(std::fetestexcept(FE_DIVBYZERO)) {
        std::cout << "division by zero reported\n";
    } else {
        std::cout << "divsion by zero not reported\n";
    }

    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "1.0/10 = " << one/10 << '\n';
    if(std::fetestexcept(FE_INEXACT)) {
        std::cout << "inexact result reported\n";
    } else {
        std::cout << "inexact result not reported\n";
    }

    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "sqrt(-1) = " << std::sqrt(-1) << '\n';
    if(std::fetestexcept(FE_INVALID)) {
        std::cout << "invalid result reported\n";
    } else {
        std::cout << "invalid result not reported\n";
    }
}

输出：

1.0/0.0 = inf
division by zero reported
1.0/10 = 0.1
inexact result reported
sqrt(-1) = -nan
invalid result reported

参阅

feclearexcept
(C++11)
 清除指定的浮点状态标志
(函数)


std::feupdateenv

< cpp‎ | numeric‎ | fenv
定义于头文件 <cfenv> |
int feupdateenv( const std::fenv_t* envp ) | (C++11 起)

首先，回忆当前引发的浮点异常，然后从 envp 所指向的对象恢复浮点环境（类似 std::fesetenv ），再引发保存的浮点异常。

此函数可用于结束先前调用 std::feholdexcept 所建立的不停止模式。

参数

envp - 指向 std::fenv_t 类型对象的指针，对象为之前到 std::feholdexcept 或 std::fegetenv 的调用所设，或等于 FE_DFL_ENV

返回值

成功时为 ​0​ ，否则为非零。

参阅

feholdexcept (C++11) | 保存环境，清除所有状态标志，并忽略所有将来的错误 (函数)
fegetenvfesetenv (C++11) | 保存或恢复当前浮点环境 (函数)
FE_DFL_ENV (C++11) | 默认浮点环境 (宏常量)


std::gcd

< cpp‎ | numeric
定义于头文件 <numeric> |
template< class M, class N> constexpr std::common_type_t <M, N> gcd(M m, N n); | (C++17 起)

计算整数 m 与 n 的最大公约数。

参数

m, n - 整数值

返回值

若 m 与 n 均为零则返回零。否则返回 |m| 与 |n| 的最大公约数。

注意

若 M 或 N 不是整数类型，或者若其中之一是（可有 cv 限定的） bool ，则程序为病式。

若 |m| 或 |n| 不能表示为 std::common_type_t <M, N> 类型的值，则行为未定义。

异常

不抛异常。

示例

#include <numeric>
int main() {
    constexpr int p {2 * 2 * 3};
    constexpr int q {2 * 3 * 3};
    static_assert(2 * 3 == std::gcd(p, q));
}

参阅

lcm
(C++17)
 返回二个整数最小公倍数的 constexpr 函数模板
(函数模板)


std::has_single_bit

< cpp‎ | numeric
定义于头文件 <bit> |
template< class T > constexpr bool has_single_bit(T x) noexcept; | (C++20 起)

检查 x 是否为二的整数次幂。

此重载仅若 T 为无符号整数类型（即 unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 、 unsigned long long 或扩展无符号整数类型）才参与重载决议。

返回值

若 x 为二的整数次幂则为 true ；否则为 false 。

可能的实现

版本一
template <std::unsigned_integral T>
    requires !std::same_as<T, bool> && !std::same_as<T, char> &&
             !std::same_as<T, char8_t> && !std::same_as<T, char16_t> &&
             !std::same_as<T, char32_t> && !std::same_as<T, wchar_t>
constexpr bool has_single_bit(T x) noexcept
{
    return x != 0 && (x & (x - 1)) == 0;
}
版本二
template <std::unsigned_integral T>
    requires !std::same_as<T, bool> && !std::same_as<T, char> &&
             !std::same_as<T, char8_t> && !std::same_as<T, char16_t> &&
             !std::same_as<T, char32_t> && !std::same_as<T, wchar_t>
constexpr bool has_single_bit(T x) noexcept
{
    return std::popcount(x) == 1;
}

示例

#include <bit>
#include <bitset>
#include <iostream>

int main()
{
    std::cout << std::boolalpha;
    for (auto i = 0u; i < 10u; ++i) {
        std::cout << "has_single_bit( " << std::bitset<4>(i) << " ) = "
                  << std::has_single_bit(i) // P1956R1 前为 `ispow2`
                  << '\n';
    }
}

输出：

has_single_bit( 0000 ) = false
has_single_bit( 0001 ) = true
has_single_bit( 0010 ) = true
has_single_bit( 0011 ) = false
has_single_bit( 0100 ) = true
has_single_bit( 0101 ) = false
has_single_bit( 0110 ) = false
has_single_bit( 0111 ) = false
has_single_bit( 1000 ) = true
has_single_bit( 1001 ) = false

参阅

popcount (C++20) | 计量无符号整数中为 1 的位的数量 (函数模板)
count | 返回设置为 true 的位的数量 (std::bitset<N> 的公开成员函数)
test | 访问特定位 (std::bitset<N> 的公开成员函数)


std::lcm

< cpp‎ | numeric
定义于头文件 <numeric> |
template< class M, class N> constexpr std::common_type_t <M, N> lcm(M m, N n); | (C++17 起)

计算整数 m 与 n 的最小公倍数。

参数

m, n - 整数值

返回值

若 m 或 n 为零，则返回零。否则，返回 |m| 与 |n| 的最小公倍数。

注意

若 M 或 N 不是整数类型，或其中有（可为 cv 限定的） bool ，则程序为病式。

若 |m| 、 |n| 或 |m| 和 |n| 的最小公倍数不能表示为 std::common_type_t <M, N> 类型的值，则行为未定义。

异常

不抛异常。

参阅

gcd
(C++17)
 返回二个整数最大公约数的 constexpr 函数模板
(函数模板)


std::lerp

< cpp‎ | numeric
定义于头文件 <cmath> |  |
constexpr float lerp( float a, float b, float t ) noexcept; | (1) | (C++20 起)
constexpr double lerp( double a, double b, double t ) noexcept; | (2) | (C++20 起)
constexpr long double lerp( long double a, long double b, long double t ) noexcept; | (3) | (C++20 起)
constexpr Promoted lerp( Arithmetic1 a, Arithmetic2 b, Arithmetic3 t ) noexcept; | (4) | (C++20 起)
1-3) 计算 \(a+t(b−a)\)a+t(b−a) ，即 a 与 b 间参数为 t 的线性内插（或为外插，当 t 落在范围 [0,1] 外时）。
4) 所有 1-3) 所不覆盖的算术类型参数的重载集或模板。。若任何参数拥有整数类型，则将它转型为 double 。若任何其他参数为 long double ，则返回类型为 long double ，否则为 double 。

参数

a, b, t - 浮点或整数类型值

返回值

\(a+t(b−a)\)a+t(b−a)

isfinite(a) && isfinite(b) 时，保证下列属性：

  • 若 t == 0 ，则结果等于 a ；
  • 若 t == 1 ，则结果等于 b ；
  • 若 t >= 0 && t <= 1 ，则结果有限；
  • 若 isfinite(t) && a == b ，则结果等于 a ；
  • 若 isfinite(t) || (!isnan(t) && b-a != 0) ，则结果非 NaN 。

令 CMP(x,y) 为若 x > y 则为 1 ，若 x < y 则为 -1 ，否则为 0 。对于任何 t1 与 t2 ， CMP(lerp(a, b, t2), lerp(a, b, t1)) 、 CMP(t2, t1) 与 CMP(b, a) 的积非负。（即 lerp 单调。）

注解

包含 <math.h> 时 lerp 在全局命名空间可用，即使它不是 C 的一部分。

示例

#include <iostream>
#include <cmath>

int main()
{
    float a=10.0f, b=20.0f;

    std::cout << "a=" << a << ", " << "b=" << b << '\n'
              << "mid point=" << std::lerp(a,b,0.5f) << '\n'
              << std::boolalpha << (a == std::lerp(a,b,0.0f)) << ' '
              << std::boolalpha << (b == std::lerp(a,b,1.0f)) << '\n';
}

输出：

a=10, b=20
mid point=15
true true

参阅

midpoint
(C++20)
 两个数值或指针间的中点
(函数模板)


常用数学函数

< cpp‎ | numeric

函数

定义于头文件 <cstdlib>
abs(int)labsllabs
(C++11)
 计算整数值的绝对值（ \(\small{|x|}\)|x| ）
(函数)
div(int)ldivlldiv
(C++11)
 计算整数除法的商和余数
(函数)
定义于头文件 <cinttypes>
abs(std::intmax_t)imaxabs
(C++11)(C++11)
 计算整数值的绝对值（ \(\small{|x|}\)|x| ）
(函数)
div(std::intmax_t)imaxdiv
(C++11)(C++11)
 计算整数除法的商和余数
(函数)
定义于头文件 <cmath>
基础运算
abs(float)fabsfabsffabsl
(C++11)(C++11)
 浮点值的绝对值（ \(\small{|x|}\)|x| ）
(函数)
fmodfmodffmodl
(C++11)(C++11)
 浮点除法运算的余数
(函数)
remainderremainderfremainderl
(C++11)(C++11)(C++11)
 除法运算的有符号余数
(函数)
remquoremquofremquol
(C++11)(C++11)(C++11)
 除法运算的有符号余数和最后三个二进制位
(函数)
fmafmaffmal
(C++11)(C++11)(C++11)
 混合的乘加运算
(函数)
fmaxfmaxffmaxl
(C++11)(C++11)(C++11)
 两个浮点值的较大者
(函数)
fminfminffminl
(C++11)(C++11)(C++11)
 两个浮点值的较小者
(函数)
fdimfdimffdiml
(C++11)(C++11)(C++11)
 两个浮点值的正数差（ \({\small\max{(0, x-y)} }\)max(0, x-y) ）
(函数)
nannanfnanl
(C++11)(C++11)(C++11)
 非数（NaN）
(函数)
指数函数
expexpfexpl
(C++11)(C++11)
 返回 e 的给定次幂（ \({\small e^x}\)ex ）
(函数)
exp2exp2fexp2l
(C++11)(C++11)(C++11)
 返回 2 的给定次幂（ \({\small 2^x}\)2x ）
(函数)
expm1expm1fexpm1l
(C++11)(C++11)(C++11)
 返回 e 的给定次幂减一（ \({\small e^x-1}\)ex-1 ）
(函数)
loglogflogl
(C++11)(C++11)
 计算自然（以 e 为底）对数（ \({\small \ln{x} }\)ln(x) ）
(函数)
log10log10flog10l
(C++11)(C++11)
 计算常用（以 10 为底）对数（ \({\small \log_{10}{x} }\)log10(x) ）
(函数)
log2log2flog2l
(C++11)(C++11)(C++11)
 给定数值的以 2 为底的对数（ \({\small \log_{2}{x} }\)log2(x) ）
(函数)
log1plog1pflog1pl
(C++11)(C++11)(C++11)
 1 加上给定数值的自然（以 e 为底）对数（ \({\small \ln{(1+x)} }\)ln(1+x) ）
(函数)
幂函数
powpowfpowl
(C++11)(C++11)
 求某数的给定次幂（ \(\small{x^y}\)xy ）
(函数)
sqrtsqrtfsqrtl
(C++11)(C++11)
 计算平方根（ \(\small{\sqrt{x} }\)√x ）
(函数)
cbrtcbrtfcbrtl
(C++11)(C++11)(C++11)
 计算立方根（ \(\small{\sqrt[3]{x} }\)3√x ）
(函数)
hypothypotfhypotl
(C++11)(C++11)(C++11)
 计算两个给定数的平方和的平方根（ \(\scriptsize{\sqrt{x^2+y^2} }\)√x2
+y2
 ）
(函数)
三角函数
sinsinfsinl
(C++11)(C++11)
 计算正弦（ \({\small\sin{x} }\)sin(x) ）
(函数)
coscosfcosl
(C++11)(C++11)
 计算余弦（ \({\small\cos{x} }\)cos(x) ）
(函数)
tantanftanl
(C++11)(C++11)
 计算正切（ \({\small\tan{x} }\)tan(x) ）
(函数)
asinasinfasinl
(C++11)(C++11)
 计算反正弦（ \({\small\arcsin{x} }\)arcsin(x) ）
(函数)
acosacosfacosl
(C++11)(C++11)
 计算反余弦（ \({\small\arccos{x} }\)arccos(x) ）
(函数)
atanatanfatanl
(C++11)(C++11)
 计算反正切（ \({\small\arctan{x} }\)arctan(x) ）
(函数)
atan2atan2fatan2l
(C++11)(C++11)
 反正切，用符号确定象限
(函数)
双曲函数
sinhsinhfsinhl
(C++11)(C++11)
 计算双曲正弦（ \({\small\sinh{x} }\)sinh(x) ）
(函数)
coshcoshfcoshl
(C++11)(C++11)
 计算双曲余弦（ \({\small\cosh{x} }\)cosh(x) ）
(函数)
tanhtanhftanhl
(C++11)(C++11)
 计算双曲正切（ \({\small\tanh{x} }\)tanh(x) ）
(函数)
asinhasinhfasinhl
(C++11)(C++11)(C++11)
 计算反双曲正弦（ \({\small\operatorname{arsinh}{x} }\)arsinh(x) ）
(函数)
acoshacoshfacoshl
(C++11)(C++11)(C++11)
 计算反双曲余弦（ \({\small\operatorname{arcosh}{x} }\)arcosh(x) ）
(函数)
atanhatanhfatanhl
(C++11)(C++11)(C++11)
 计算反双曲正切（ \({\small\operatorname{artanh}{x} }\)artanh(x) ）
(函数)
误差与伽马函数
erferfferfl
(C++11)(C++11)(C++11)
 误差函数
(函数)
erfcerfcferfcl
(C++11)(C++11)(C++11)
 补误差函数
(函数)
tgammatgammaftgammal
(C++11)(C++11)(C++11)
 gamma 函数
(函数)
lgammalgammaflgammal
(C++11)(C++11)(C++11)
 gamma 函数的自然对数
(函数)
最接近整数的浮点运算
ceilceilfceill
(C++11)(C++11)
 不小于给定值的最接近整数值
(函数)
floorfloorffloorl
(C++11)(C++11)
 不大于给定值的最接近整数
(函数)
trunctruncftruncl
(C++11)(C++11)(C++11)
 绝对值不大于给定值的最接近整数
(函数)
roundroundfroundllroundlroundflroundlllroundllroundfllroundl
(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)
 最接近整数，中间情况下向远离零舍入
(函数)
nearbyintnearbyintfnearbyintl
(C++11)(C++11)(C++11)
 使用当前舍入模式的最接近整数
(函数)
rintrintfrintllrintlrintflrintlllrintllrintfllrintl
(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)
 使用当前舍入模式的最接近整数
若结果有别则有异常
(函数)
浮点操作函数
frexpfrexpffrexpl
(C++11)(C++11)
 将数分解为有效数字和 2 的幂次
(函数)
ldexpldexpfldexpl
(C++11)(C++11)
 将数乘以 2 的幂次
(函数)
modfmodffmodfl
(C++11)(C++11)
 分解数为整数和小数部分
(函数)
scalbnscalbnfscalbnlscalblnscalblnfscalblnl
(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)
 将数乘以 FLT_RADIX 的幂次
(函数)
ilogbilogbfilogbl
(C++11)(C++11)(C++11)
 提取数的指数
(函数)
logblogbflogbl
(C++11)(C++11)(C++11)
 提取数的指数
(函数)
nextafternextafterfnextafterlnexttowardnexttowardfnexttowardl
(C++11)(C++11) (C++11)(C++11)(C++11)(C++11)
 趋向给定值的下个可表示浮点值
(函数)
copysigncopysignfcopysignl
(C++11)(C++11)(C++11)
 复制浮点值的符号
(函数)
分类与比较
fpclassify
(C++11)
 归类给定的浮点值
(函数)
isfinite
(C++11)
 检查给定数是否拥有有限值
(函数)
isinf
(C++11)
 检查给定数是否为无限
(函数)
isnan
(C++11)
 检查给定的数是否 NaN
(函数)
isnormal
(C++11)
 检查给定数是否正规
(函数)
signbit
(C++11)
 检查给定数是否为负
(函数)
isgreater
(C++11)
 检查第一个浮点实参是否大于第二个
(函数)
isgreaterequal
(C++11)
 检查第一个浮点实参是否大于或等于第二个
(函数)
isless
(C++11)
 检查第一个浮点实参是否小于第二个
(函数)
islessequal
(C++11)
 检查第一个浮点实参是否小于或等于第二个
(函数)
islessgreater
(C++11)
 检查第一个浮点实参是否小于或大于第二个
(函数)
isunordered
(C++11)
 检查两个浮点值是否无顺序
(函数)

类型

定义于头文件 <cstdlib>
div_t | 结构体类型，std::div 函数的返回值 (typedef)
ldiv_t | 结构体类型，std::ldiv 函数的返回值 (typedef)
lldiv_t (C++11) | 结构体类型，std::lldiv 函数的返回值 (typedef)
定义于头文件 <cinttypes>
imaxdiv_t (C++11) | 结构体类型，由 std::imaxdiv 函数返回 (typedef)
定义于头文件 <cmath>
float_t (C++11) | 至少和 float 一样宽的最高效浮点类型 (typedef)
double_t (C++11) | 至少和 double 一样宽的最高效浮点类型 (typedef)

宏常量

定义于头文件 <cmath>
HUGE_VALFHUGE_VALHUGE_VALL
(C++11)(C++11)
 分别指出 float、double 和 long double 的上溢值
(宏常量)
INFINITY
(C++11)
 求值为正无穷大或保证使 float 上溢的值
(宏常量)
NAN
(C++11)
 求值为 float 类型的静默 NAN
(宏常量)
math_errhandlingMATH_ERRNOMATH_ERREXCEPT
(C++11)(C++11)(C++11)
 定义常用数学函数所用的错误处理机制
(宏常量)
分类
FP_NORMALFP_SUBNORMALFP_ZEROFP_INFINITEFP_NAN
(C++11)(C++11)(C++11)(C++11)(C++11)
 指示浮点类别
(宏常量)

参阅

数学特殊函数


FP_NORMAL, FP_SUBNORMAL, FP_ZERO, FP_INFINITE, FP_NAN

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |
#define FP_NORMAL /*implementation defined*/ | (C++11 起)
#define FP_SUBNORMAL /*implementation defined*/ | (C++11 起)
#define FP_ZERO /*implementation defined*/ | (C++11 起)
#define FP_INFINITE /*implementation defined*/ | (C++11 起)
#define FP_NAN /*implementation defined*/ | (C++11 起)

FP_NORMAL 、 FP_SUBNORMAL 、 FP_ZERO 、 FP_INFINITE 、 FP_NAN 宏各代表一个独自的浮点数类别。它们都展开成整数常量表达式。

常量 | 解释
FP_NORMAL | 指示值为正规，即不是无穷大、非正规、非数或零
FP_SUBNORMAL | 指示值为非正规
FP_ZERO | 指示值为正或负零
FP_INFINITE | 指示值无法以底层类型表示（正或负无穷大）
FP_NAN | 指示值是非数（ NaN ）

示例

#include <iostream>
#include <cmath>
#include <cfloat>

const char* show_classification(double x) {
    switch(std::fpclassify(x)) {
        case FP_INFINITE:  return "Inf";
        case FP_NAN:       return "NaN";
        case FP_NORMAL:    return "normal";
        case FP_SUBNORMAL: return "subnormal";
        case FP_ZERO:      return "zero";
        default:           return "unknown";
    }
}
int main()
{
    std::cout << "1.0/0.0 is " << show_classification(1/0.0) << '\n'
              << "0.0/0.0 is " << show_classification(0.0/0.0) << '\n'
              << "DBL_MIN/2 is " << show_classification(DBL_MIN/2) << '\n'
              << "-0.0 is " << show_classification(-0.0) << '\n'
              << "1.0 is " << show_classification(1.0) << '\n';
}

输出：

1.0/0.0 is Inf
0.0/0.0 is NaN
DBL_MIN/2 is subnormal
-0.0 is zero
1.0 is normal

参阅

fpclassify
(C++11)
 归类给定的浮点值
(函数)


HUGE_VALF, HUGE_VAL, HUGE_VALL

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |
#define HUGE_VALF /*implementation defined*/ | (C++11 起)
#define HUGE_VAL /*implementation defined*/ |
#define HUGE_VALL /*implementation defined*/ | (C++11 起)

HUGE_VALF 、 HUGE_VAL 和 HUGE_VALL 宏展开成正浮点常量表达式，它们比较等于上溢情况中浮点函数和运算符的返回值（见 math_errhandling ）。

常量 | 解释
HUGE_VALF | 展开成指示上溢的正 float 表达式
HUGE_VAL | 展开成指示上溢的正 double 表达式，不必可表示为 float
HUGE_VALL | 展开成指示上溢的正 long double 表达式，不必可表示为 float 或 double

在支持浮点无穷大的平台上，这些宏始终分别展开成 float 、 double 和 long double 的正无穷大。

参阅

INFINITY
(C++11)
 求值为正无穷大或保证使 float 上溢的值
(宏常量)


INFINITY

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |
#define INFINITY /*implementation defined*/ | (C++11 起)

若实现支持浮点无穷大，则宏 INFINITY 展开成求值为正或无符号无穷大的 float 类型常量表达式。

若实现不支持浮点无穷大，则宏 INFINITY 展开成保证在编译时上溢 float 的正值，而此宏的使用生成编译器警告。

参阅

isinf (C++11) | 检查给定数是否为无限 (函数)
HUGE_VALFHUGE_VALHUGE_VALL (C++11)(C++11) | 分别指出 float、double 和 long double 的上溢值 (宏常量)
has_infinity [静态] | 鉴别能表示特殊值“正无穷大”的浮点类型 (std::numeric_limits<T> 的公开静态成员常量)
infinity [静态] | 返回给定类型的正无穷大值 (std::numeric_limits<T> 的公开静态成员函数)


NAN

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |
#define NAN /*implementation defined*/ | (C++11 起)

宏 NAN 展开成求值为安静非数（ QNaN ）的 float 类型常量表达式。若实现不支持 QNaN ，则不定义此宏。

注意

有许多不同的 NaN 值，区别于其载荷与其符号位。宏 NAN 所生成的 NaN 的载荷与符号位的内容是实现定义的。

参阅

nannanfnanl (C++11)(C++11)(C++11) | 非数（NaN） (函数)
isnan (C++11) | 检查给定的数是否 NaN (函数)
has_quiet_NaN [静态] | 鉴别能表示特殊值“安静的非数”（ NaN ）的浮点类型 (std::numeric_limits<T> 的公开静态成员常量)
has_signaling_NaN [静态] | 鉴别能表示特殊值“发信的非数”（ NaN ）的浮点类型 (std::numeric_limits<T> 的公开静态成员常量)
quiet_NaN [静态] | 返回给定浮点类型的安静 NaN 值 (std::numeric_limits<T> 的公开静态成员函数)
signaling_NaN [静态] | 返回给定浮点类型的发信的 NaN (std::numeric_limits<T> 的公开静态成员函数)


std::abs(int), std::labs, std::llabs, std::imaxabs

< cpp‎ | numeric‎ | math
定义于头文件 <cstdlib> |
定义于头文件 <cmath> |
int abs( int n ); |
long abs( long n ); |
long long abs( long long n ); | (C++11 起)
定义于头文件 <cstdlib> |
long labs( long n ); |
long long llabs( long long n ); | (C++11 起)
定义于头文件 <cinttypes> |
std::intmax_t abs( std::intmax_t n ); | (C++11 起)
std::intmax_t imaxabs( std::intmax_t n ); | (C++11 起)

计算整数的绝对值。若结果不能以返回类型表示则行为未定义。

若以不能由整型提升转换成 int 的无符号整型参数调用 std::abs ，则程序为谬构。

<cinttypes> 中提供 std::abs 对 std::intmax_t 的重载，当且仅当 std::intmax_t 为扩展整数类型。

 (C++11 起)

参数

n - 整数值

返回值

若可表示，则为 n 的绝对值（即 |n| ）。

注解

补码系统中，最负值的绝对值在范围外，例如对于 32 位补码类型 int ， INT_MIN 是 -2147483648 ，但本应有的结果 2147483648 大于 INT_MAX ，即 2147483647 。

示例

#include <iostream>
#include <cstdlib>
#include <climits>

int main()
{
    std::cout << "abs(+3) = " << std::abs(3) << '\n'
              << "abs(-3) = " << std::abs(-3) << '\n';

//  std::cout << abs(INT_MIN); // 补码系统上是未定义行为
}

输出：

abs(+3) = 3
abs(-3) = 3

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2192 | C++98 | std::abs 的重载不一致地声明于二个头文件 | 在两个头文件中都声明这些重载

参阅

abs(float)fabsfabsffabsl (C++11)(C++11) | 浮点值的绝对值（ \(\small{|x|}\)|x| ） (函数)
abs(std::complex) | 返回复数的模 (函数模板)
abs(std::valarray) | 应用函数 std::abs 到 valarray 的每个元素 (函数模板)


std::acos, std::acosf, std::acosl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float acos ( float arg ); |  |  |
float acosf( float arg ); |  |  | (C++11 起)
double acos ( double arg ); | (2) |
 | (3) |
long double acos ( long double arg ); |  |  |
long double acosl( long double arg ); |  |  | (C++11 起)
double acos ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算 arg 的弧（反）余弦主值。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 于范围 [0 ; π] 中的弧（反）余弦（ arccos(arg) ）。

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 在范围 [-1.0; 1.0] 外则出现定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 +1 ，则返回值 +0 。
  • 若 |arg| > 1 ，则返回定义域错误并返回 NaN 。
  • 若参数为 NaN ，则返回 NaN 。rror occurs and NaN is returned.
  • if the argument is NaN, NaN is returned

示例

#include <cmath>
#include <iostream>
#include <cerrno>
#include <cfenv>
#include <cstring>

#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "acos(-1) = " << acos(-1) << '\n'
              << "acos(0.0) = " << acos(0.0) << " 2*acos(0.0) = " << 2*acos(0) << '\n'
              << "acos(0.5) = " << acos(0.5) << " 3*acos(0.5) = " << 3*acos(0.5) << '\n'
              << "acos(1) = " << acos(1) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "acos(1.1) = " << acos(1.1) << '\n';
    if (errno == EDOM)
        std::cout << "    errno == EDOM: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_INVALID))
        std::cout << "    FE_INVALID raised" << '\n';
}

输出：

acos(-1) = 3.14159
acos(0.0) = 1.5708 2*acos(0.0) = 3.14159
acos(0.5) = 1.0472 3*acos(0.5) = 3.14159
acos(1) = 0
acos(1.1) = nan
    errno == EDOM: Numerical argument out of domain
    FE_INVALID raised

参阅

asinasinfasinl (C++11)(C++11) | 计算反正弦（ \({\small\arcsin{x} }\)arcsin(x) ） (函数)
atanatanfatanl (C++11)(C++11) | 计算反正切（ \({\small\arctan{x} }\)arctan(x) ） (函数)
atan2atan2fatan2l (C++11)(C++11) | 反正切，用符号确定象限 (函数)
coscosfcosl (C++11)(C++11) | 计算余弦（ \({\small\cos{x} }\)cos(x) ） (函数)
acos(std::complex) (C++11) | 计算复数的反余弦（ \({\small\arccos{z} }\)arccos(z) ） (函数模板)
acos(std::valarray) | 应用函数 std::acos 到 valarray 的每个元素 (函数模板)


std::acosh, std::acoshf, std::acoshl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float acosh ( float arg );
float acoshf( float arg );
 (1) (C++11 起)
double acosh ( double arg );
 (2) (C++11 起)
long double acosh ( long double arg );
long double acoshl( long double arg );
 (3) (C++11 起)
double acosh ( IntegralType arg );
 (4) (C++11 起)
1-3) 计算 arg 的反双曲余弦。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型到 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 在区间 [0, +∞] 上的反双曲余弦（ cosh-1
(arg) 或 arcosh(arg) ）。

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

错误处理

报告 math_errhandling 中指定的错误。

若参数小于 1 ，则出现定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数小于 1 ，则引发 FE_INVALID 并返回 NaN
  • 若参数为 1 ，则返回 +0
  • 若参数为 +∞ ，则返回 +∞
  • 若参数为 NaN ，则返回 NaN

注意

尽管（ C++ 对此函数引用的） C 标准命名此函数为“弧双曲余弦”，双曲函数的反函数仍是面积函数。其参数是双曲扇形的面积，而非弧长。正确的名称是“反双曲余弦”（ POSIX 所用）或“面积双曲余弦”。

示例

#include <iostream>
#include <cmath>
#include <cfloat>
#include <cerrno>
#include <cfenv>
#include <cstring>
#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "acosh(1) = " << std::acosh(1) << '\n'
              << "acosh(10) = " << std::acosh(10) << '\n'
              << "acosh(DBL_MAX) = " << std::acosh(DBL_MAX) << '\n'
              << "acosh(Inf) = " <<  std::acosh(INFINITY) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "acosh(0.5) = " << std::acosh(0.5) << '\n';
    if (errno == EDOM)
        std::cout << "    errno == EDOM: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_INVALID))
        std::cout << "    FE_INVALID raised\n";
}

可能的输出：

acosh(1) = 0
acosh(10) = 2.99322
acosh(DBL_MAX) = 710.476
acosh(Inf) = inf
acosh(0.5) = -nan
    errno == EDOM: Numerical argument out of domain
    FE_INVALID raised

参阅

asinhasinhfasinhl (C++11)(C++11)(C++11) | 计算反双曲正弦（ \({\small\operatorname{arsinh}{x} }\)arsinh(x) ） (函数)
atanhatanhfatanhl (C++11)(C++11)(C++11) | 计算反双曲正切（ \({\small\operatorname{artanh}{x} }\)artanh(x) ） (函数)
coshcoshfcoshl (C++11)(C++11) | 计算双曲余弦（ \({\small\cosh{x} }\)cosh(x) ） (函数)
acosh(std::complex) (C++11) | 计算复数的反双曲余弦（ \({\small\operatorname{arcosh}{z} }\)arcosh(z) ） (函数模板)

外部链接

Weisstein, Eric W. “反双曲余弦”来自 MathWorld--A Wolfram Web Resource 。


std::asin, std::asinf, std::asinl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float asin ( float arg ); |  |  |
float asinf( float arg ); |  |  | (C++11 起)
double asin ( double arg ); | (2) |
 | (3) |
long double asin ( long double arg ); |  |  |
long double asinl( long double arg ); |  |  | (C++11 起)
double asin ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算 arg 的弧（反）正弦主值。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 在范围 [-
π
2
; +
π
2
] 中的弧（反）正弦（ arcsin(arg) ）。

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 在范围 [-1.0; 1.0] 外则出现定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回不修改的参数。
  • 若 |arg| > 1 ，则出现定义域错误并返回 NaN 。
  • 若参数为 NaN ，则返回 NaN 。

示例

#include <cmath>
#include <iostream>
#include <cerrno>
#include <cfenv>
#include <cstring>

#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "asin(1.0) = " << asin(1) << '\n'
              << "2*asin(1.0) = " << 2*asin(1) << '\n'
              << "asin(-0.5) = " << asin(-0.5) << '\n'
              << "6*asin(-0.5) =" << 6*asin(-0.5) << '\n';
    // 特殊值
    std::cout << "asin(0.0) = " << asin(0) << " asin(-0.0)=" << asin(-0.0) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "asin(1.1) = " << asin(1.1) << '\n';
    if (errno == EDOM)
        std::cout << "    errno == EDOM: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_INVALID))
        std::cout << "    FE_INVALID raised" << '\n';
}

可能的输出：

asin(1.0) = 1.5708
2*asin(1.0) = 3.14159
asin(-0.5) = -0.523599
6*asin(-0.5) = -3.14159
asin(0.0) = 0 asin(-0.0)=-0
asin(1.1) = nan
    errno == EDOM: Numerical argument out of domain
    FE_INVALID raised

参阅

acosacosfacosl (C++11)(C++11) | 计算反余弦（ \({\small\arccos{x} }\)arccos(x) ） (函数)
atanatanfatanl (C++11)(C++11) | 计算反正切（ \({\small\arctan{x} }\)arctan(x) ） (函数)
atan2atan2fatan2l (C++11)(C++11) | 反正切，用符号确定象限 (函数)
sinsinfsinl (C++11)(C++11) | 计算正弦（ \({\small\sin{x} }\)sin(x) ） (函数)
asin(std::complex) (C++11) | 计算复数的反正弦（ \({\small\arcsin{z} }\)arcsin(z) ） (函数模板)
asin(std::valarray) | 应用函数 std::asin 到 valarray 的每个元素 (函数模板)


std::asinh, std::asinhf, std::asinhl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float asinh ( float arg );
float asinhf( float arg );
 (1) (C++11 起)
double asinh ( double arg );
 (2) (C++11 起)
long double asinh ( long double arg );
long double asinhl( long double arg );
 (3) (C++11 起)
double asinh ( IntegralType arg );
 (4) (C++11 起)
1-3) 计算 arg 的反双曲正弦。
4) 接受任何整数类型参数的重载集或函数模板，等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不发生错误，则返回 arg 的反双曲正弦（ sinh-1
(arg) 或 arsinh(arg) ）。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 或 ±∞ ，则返回不修改的参数
  • 若参数为 NaN ，则返回 NaN

注意

尽管（ C++ 对此函数引用的） C 标准命名此函数为“弧双曲正弦”，双曲函数的反函数仍是面积函数。其参数为双曲扇形的面积，而非弧长。正确的名称是“反双曲正弦”（ POSIX 所用）或“面积双曲正弦”。

示例

#include <iostream>
#include <cmath>

int main()
{
    std::cout << "asinh(1) = " << std::asinh(1) << '\n'
              << "asinh(-1) = " << std::asinh(-1) << '\n';
    // 特殊值
    std::cout << "asinh(+0) = " << std::asinh(+0.0) << '\n'
              << "asinh(-0) = " <<  std::asinh(-0.0) << '\n';
}

输出：

asinh(1) = 0.881374
asinh(-1) = -0.881374
asinh(+0) = 0
asinh(-0) = -0

参阅

acoshacoshfacoshl (C++11)(C++11)(C++11) | 计算反双曲余弦（ \({\small\operatorname{arcosh}{x} }\)arcosh(x) ） (函数)
atanhatanhfatanhl (C++11)(C++11)(C++11) | 计算反双曲正切（ \({\small\operatorname{artanh}{x} }\)artanh(x) ） (函数)
sinhsinhfsinhl (C++11)(C++11) | 计算双曲正弦（ \({\small\sinh{x} }\)sinh(x) ） (函数)
asinh(std::complex) (C++11) | 计算复数的反双曲正弦（ \({\small\operatorname{arsinh}{z} }\)arsinh(z) ） (函数模板)

外部链接

Weisstein, Eric W. “反双曲正弦”来自 MathWorld--A Wolfram Web Resource 。


std::atan, std::atanf, std::atanl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float atan ( float arg ); |  |  |
float atanf( float arg ); |  |  | (C++11 起)
double atan ( double arg ); | (2) |
 | (3) |
long double atan ( long double arg ); |  |  |
long double atanl( long double arg ); |  |  | (C++11 起)
double atan ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算 arg 的弧（反）正切主值。
4) 接受任何整数类型参数的重载集或函数模板，等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 在 [-
π
2
; +
π
2
] 弧度范围中的弧（反）正切（ arctan(arg) ）。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回不修改的参数
  • 若参数为 +∞ ，则返回 +π/2
  • 若参数为 -∞ ，则返回 -π/2
  • 若参数为 NaN ，则返回 NaN

注意

POSIX 指定在下溢情况下，返回不修改的 arg ，而若不支持如此，则返回不大于 DBL_MIN 、 FLT_MIN 和 LDBL_MIN 的实现定义值。

示例

#include <iostream>
#include <cmath>

int main()
{
    std::cout << "atan(1) = " << atan(1) << " 4*atan(1) = " << 4*atan(1) << '\n';
    // 特殊值
    std::cout << "atan(Inf) = " << atan(INFINITY)
              << " 2*atan(Inf) = " << 2*atan(INFINITY) << '\n'
              << "atan(-0.0) = " << atan(-0.0) << '\n'
              << "atan(+0.0) = " << atan(0) << '\n';
}

输出：

atan(1) = 0.785398 4*atan(1) = 3.14159
atan(Inf) = 1.5708 2*atan(Inf) = 3.14159
atan(-0.0) = -0
atan(+0.0) = 0

参阅

asinasinfasinl (C++11)(C++11) | 计算反正弦（ \({\small\arcsin{x} }\)arcsin(x) ） (函数)
acosacosfacosl (C++11)(C++11) | 计算反余弦（ \({\small\arccos{x} }\)arccos(x) ） (函数)
atan2atan2fatan2l (C++11)(C++11) | 反正切，用符号确定象限 (函数)
tantanftanl (C++11)(C++11) | 计算正切（ \({\small\tan{x} }\)tan(x) ） (函数)
atan(std::complex) (C++11) | 计算复数的反正切（ \({\small\arctan{z} }\)arctan(z) ） (函数模板)
atan(std::valarray) | 应用函数 std::atan 到 valarray 的每个元素 (函数模板)


std::atan2, std::atan2f, std::atan2l

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float atan2 ( float y, float x ); |  |  |
float atan2f( float y, float x ); |  |  | (C++11 起)
double atan2 ( double y, double x ); | (2) |
 | (3) |
long double atan2 ( long double y, long double x ); |  |  |
long double atan2l( long double y, long double x ); |  |  | (C++11 起)
Promoted atan2 ( Arithmetic1 y, Arithmetic2 x ); | (4) | (C++11 起)
1-3) 计算 y/x 的弧（反）正切，以参数符号确定正确的象限。
4) 所有 1-3) 所不覆盖的算术类型的重载集或函数模板。若任何参数拥有整数类型，则将它转型为 double 。若任何参数为 long double ，则返回类型 Promoted 亦为 long double ，否则返回类型始终为 double 。

参数

x, y - 浮点或整数类型值

返回值

若不出现错误，则返回 y/x 在 [-π ; +π] 弧度范围中的弧（反）正切（ arctan(
y
x
) ）。
Y 参数
返回值
X 参数

若出现定义域错误，则返回实现定义值。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若 x 与 y 均为零则可能出现定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若 x 与 y 均为零，则定义域错误不出现
  • 若 x 与 y 均为零，则也不出现值域错误
  • 若 y 为零，则不出现极点错误
  • 若 y 为 ±0 且 x 为负或 -0 ，则返回 ±π
  • 若 y 为 ±0 且 x 为正或 +0 ，则返回 ±0
  • 若 y 为 ±∞ 且 x 有限，则返回 ±π/2
  • 若 y 为 ±∞ 且 x 为 -∞ ，则返回 ±3π/4
  • 若 y 为 ±∞ 且 x 为 +∞ ，则返回 ±π/4
  • 若 x 为 ±0 且 y 为负，则返回 -π/2
  • 若 x 为 ±0 且 y 为正，则返回 +π/2
  • 若 x 为 -∞ 且 y 为正有限，则返回 +π
  • 若 x 为 -∞ 且 y 为负有限，则返回 -π
  • 若 x 为 +∞ 且 y 为正有限，则返回 +0
  • 若 x 为 +∞ 且 y 为负有限，则返回 -0
  • 若 x 为 NaN 或 y 为 NaN ，则返回 NaN

注解

std::atan2(y, x) 等价于 std::arg( std::complex <double>(x,y)) 。

POSIX 指定在下溢情况下，返回不修改的 arg ，而若不支持如此，则返回不大于 DBL_MIN 、 FLT_MIN 和 LDBL_MIN 的实现定义值。

示例

#include <iostream>
#include <cmath>

int main()
{
    // 正常用法：二个参数的符号确定象限
    std::cout << "(+1,+1) cartesian is (" << hypot(1,1)
              << ',' << atan2(1,1) << ") polar\n"  // atan2(1,1) = +pi/4 ，第 I 象限
              << "(+1,-1) cartesian is (" << hypot(1,-1)
              << ',' << atan2(1,-1) << ") polar\n" // atan2(1, -1) = +3pi/4 ，第 II 象限
              << "(-1,-1) cartesian is (" << hypot(-1,-1)
              << ',' << atan2(-1,-1) << ") polar\n" // atan2(-1,-1) = -3pi/4 ，第 III 象限
              << "(-1,+1) cartesian is (" << hypot(-1,1)
              << ',' << atan2(-1,1) << ") polar\n"; // atan2(-1,1) = -pi/4 ，第 IV 象限
    // 特殊值
    std::cout << "atan2(0, 0) = " << atan2(0,0)
              << " atan2(0,-0) = " << atan2(0,-0.0) << '\n'
              << "atan2(7, 0) = " << atan2(7,0)
              << " atan2(7,-0) = " << atan2(7,-0.0) << '\n';
}

输出：

(+1,+1) cartesian is (1.41421,0.785398) polar
(+1,-1) cartesian is (1.41421,2.35619) polar
(-1,-1) cartesian is (1.41421,-2.35619) polar
(-1,+1) cartesian is (1.41421,-0.785398) polar
atan2(0, 0) = 0 atan2(0,-0) = 3.14159
atan2(7, 0) = 1.5708 atan2(7,-0) = 1.5708

参阅

asinasinfasinl (C++11)(C++11) | 计算反正弦（ \({\small\arcsin{x} }\)arcsin(x) ） (函数)
acosacosfacosl (C++11)(C++11) | 计算反余弦（ \({\small\arccos{x} }\)arccos(x) ） (函数)
atanatanfatanl (C++11)(C++11) | 计算反正切（ \({\small\arctan{x} }\)arctan(x) ） (函数)
arg | 返回辐角 (函数模板)
atan2(std::valarray) | 应用函数 std::atan2 到一个 valarray 和一个值 (函数模板)


std::atanh, std::atanh, std::atanhl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float atanh ( float arg );
float atanhf( float arg );
 (1) (C++11 起)
double atanh ( double arg );
 (2) (C++11 起)
long double atanh ( long double arg );
long double atanhl( long double arg );
 (3) (C++11 起)
double atanh ( IntegralType arg );
 (4) (C++11 起)
1-3) 计算 arg 的反正切。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型到 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 的反双曲正切（ tanh-1
(arg) 或 artanh(arg) ）。

若出现定义域错误，则返回实现定义值（若支持则为 NaN ）。

若出现极点错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL （带正确符号）。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若参数不在区间 [-1, +1] 中，则出现值域错误。

若参数为 ±1 ，则出现极点错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回不修改的参数。
  • 若参数为 ±1 ，则返回 ±∞ 并引发 FE_DIVBYZERO 。
  • 若 |arg|>1 ，则返回 NaN 并引发 FE_INVALID 。
  • 若参数为 NaN ，则返回 NaN 。

注意

尽管（ C++ 对此函数引用的） C 标准命名此函数为“弧双曲正切”，双曲函数的反函数是面积函数。其参数为双曲扇形的面积，而非弧。正确的名称为“反双曲正切”（ POSIX 所用）或“面积双曲正切”。

POSIX 指定在下溢的情况下，返回不修改的 arg ，而且若不支持，则返回不大于 DBL_MIN 、 FLT_MIN 和 LDBL_MIN 的值。

示例

#include <iostream>
#include <cmath>
#include <cfloat>
#include <cerrno>
#include <cfenv>
#include <cstring>
#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "atanh(0) = " << std::atanh(0) << '\n'
              << "atanh(-0) = " << std::atanh(-0.0) << '\n'
              << "atanh(0.9) = " << std::atanh(0.9) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "atanh(-1) = " << std::atanh(-1) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_DIVBYZERO))
        std::cout << "    FE_DIVBYZERO raised\n";
}

可能的输出：

atanh(0) = 0
atanh(-0) = -0
atanh(0.9) = 1.47222
atanh(-1) = -inf
    errno == ERANGE: Numerical result out of range
    FE_DIVBYZERO raised

参阅

asinhasinhfasinhl (C++11)(C++11)(C++11) | 计算反双曲正弦（ \({\small\operatorname{arsinh}{x} }\)arsinh(x) ） (函数)
acoshacoshfacoshl (C++11)(C++11)(C++11) | 计算反双曲余弦（ \({\small\operatorname{arcosh}{x} }\)arcosh(x) ） (函数)
tanhtanhftanhl (C++11)(C++11) | 计算双曲正切（ \({\small\tanh{x} }\)tanh(x) ） (函数)
atanh(std::complex) (C++11) | 计算复数的反双曲正切（ \({\small\operatorname{artanh}{z} }\)artanh(z) ） (函数模板)

外部链接

Weisstein, Eric W. “反双曲正切。”来自 MathWorld--A Wolfram Web Resource 。


std::cbrt, std::cbrtf, std::cbrtl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float cbrt ( float arg );
float cbrtf( float arg );
 (1) (C++11 起)
double cbrt ( double arg );
 (2) (C++11 起)
long double cbrt ( long double arg );
long double cbrtl( long double arg );
 (3) (C++11 起)
double cbrt ( IntegralType arg );
 (4) (C++11 起)
1-3) 计算 arg 的立方根。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 的立方根（ \(\small{\sqrt[3]{arg} }\)3√arg ）。

若出现下溢所致的错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 或 ±∞ ，则返回不更改的参数
  • 若参数为 NaN ，则返回 NaN 。

注解

std::cbrt(arg) 不等价于 std::pow (arg, 1.0/3) ，因为有理数 \(\small{\frac1{3} }\)
1
3
通常不等于 1.0/3 并且 std::pow 不能求负底数的小数次幂。另外 std::cbrt(arg) 常给出比 std::pow (arg, 1.0/3) 更精确的结果（见示例）。

示例

#include <iostream>
#include <cmath>

int main()
{
    // 正常使用
    std::cout << "cbrt(729) = " << std::cbrt(729) << '\n'
              << "cbrt(-0.125) = " << std::cbrt(-0.125) << '\n';
    // 特殊值
    std::cout << "cbrt(-0) = " << std::cbrt(-0.0) << '\n'
              << "cbrt(+inf) = " << std::cbrt(INFINITY) << '\n';
    // 精度
    std::cout.precision(std::numeric_limits<double>::max_digits10);
    std::cout << "cbrt(343)      = " << std::cbrt(343) << '\n';
    std::cout << "pow(343,1.0/3) = " << std::pow(343, 1.0/3) << '\n';
}

输出：

cbrt(729) = 9
cbrt(-0.125) = -0.5
cbrt(-0) = -0
cbrt(+inf) = inf
cbrt(343)      = 7
pow(343,1.0/3) = 6.9999999999999991

参阅

powpowfpowl (C++11)(C++11) | 求某数的给定次幂（ \(\small{x^y}\)xy ） (函数)
sqrtsqrtfsqrtl (C++11)(C++11) | 计算平方根（ \(\small{\sqrt{x} }\)√x ） (函数)
hypothypotfhypotl (C++11)(C++11)(C++11) | 计算两个给定数的平方和的平方根（ \(\scriptsize{\sqrt{x^2+y^2} }\)√x2 +y2 ） (函数)


std::ceil, std::ceilf, std::ceill

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float ceil ( float arg ); |  |  |
float ceilf( float arg ); |  |  | (C++11 起)
double ceil ( double arg ); | (2) |
 | (3) |
long double ceil ( long double arg ); |  |  |
long double ceill( float arg ); |  |  | (C++11 起)
double ceil ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算不小于 arg 的最小整数值。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点值

返回值

若不出现错误，则返回不小于 arg 的最小整数值，即 ⌈arg⌉ 。

返回值
参数

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 当前舍入模式无效。
  • 若 arg 为 ±∞ ，则返回不修改的参数
  • 若 arg 为 ±0 ，则返回不修改的参数
  • 若 arg 为 NaN ，则返回 NaN

注意

舍入非整数有限值时，可以（但不要求）引发 FE_INEXACT 。

所有标准浮点格式中的最大可表示浮点值都是准确的整数，故此函数自身决不上溢；然而存储于整数对象时，结果可以溢出任何整数类型（包括 std::intmax_t ）。

（ double 参数的）此函数表现如同（除了不引发 FE_INEXACT 的自由）以下列代码实现

#include <cmath>
#include <cfenv>
#pragma STDC FENV_ACCESS ON
double ceil(double x)
{
    double result;
    int save_round = std::fegetround();
    std::fesetround(FE_UPWARD);
    result = std::rint(x); // 或 std::nearbyint
    std::fesetround(save_round);
    return result;
}

示例

#include <cmath>
#include <iostream>
int main()
{
    std::cout << std::fixed
              << "ceil(+2.4) = " << std::ceil(+2.4) << '\n'
              << "ceil(-2.4) = " << std::ceil(-2.4) << '\n'
              << "ceil(-0.0) = " << std::ceil(-0.0) << '\n'
              << "ceil(-Inf) = " << std::ceil(-INFINITY) << '\n';
}

输出：

ceil(+2.4) = 3.000000
ceil(-2.4) = -2.000000
ceil(-0.0) = -0.000000
ceil(-Inf) = -INF

参阅

floorfloorffloorl (C++11)(C++11) | 不大于给定值的最接近整数 (函数)
trunctruncftruncl (C++11)(C++11)(C++11) | 绝对值不大于给定值的最接近整数 (函数)
roundroundfroundllroundlroundflroundlllroundllroundfllroundl (C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11) | 最接近整数，中间情况下向远离零舍入 (函数)
nearbyintnearbyintfnearbyintl (C++11)(C++11)(C++11) | 使用当前舍入模式的最接近整数 (函数)
rintrintfrintllrintlrintflrintlllrintllrintfllrintl (C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11) | 使用当前舍入模式的最接近整数 若结果有别则有异常 (函数)


std::copysign, std::copysignf, std::copysignl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float copysign ( float x, float y );
float copysignf( float x, float y );
 (1) (C++11 起)
double copysign ( double x, double y );
 (2) (C++11 起)
long double copysign ( long double x, long double y );
long double copysignl( long double x, long double y );
 (3) (C++11 起)
Promoted copysign ( Arithmetic1 x, Arithmetic2 y );
 (4) (C++11 起)
1-3) 以 x 的模和 y 的符号组成浮点值。
4) 重载集或函数模板，用于所有 (1-3) 所不覆盖的算术类型参数组合。若任何参数拥有整数类型，则将它转型到 double 。若任何参数为 long double ，则返回类型 Promoted 亦为 long double ， 否则返回类型始终是 double 。

参数

x, y - 浮点值

返回值

若无错误发生，则返回以 x 的模与 y 的符号组成的浮点值。

若 x 为 NaN ，则返回带 y 符号的 NaN 。

若 y 为 -0 ，则仅若实现支持与算术运算一致的有符号零，结果才为负。

错误处理

此函数不受制于任何指定于 math_errhandling 的错误

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 返回值是准确的（决不引发 FE_INEXACT ）且独立于当前舍入模式。

注意

std::copysign 是操作 NaN 值符号的唯一可移植方式（ signbit 亦可用于检验 NaN 的符号）

示例

#include <iostream>
#include <cmath>

int main(void)
{
    std::cout << "copysign(1.0,+2.0) = " << std::copysign(1.0,+2.0) << '\n'
              << "copysign(1.0,-2.0) = " << std::copysign(1.0,-2.0) << '\n'
              << "copysign(inf,-2.0) = " << std::copysign(INFINITY,-2.0) << '\n'
              << "copysign(NaN,-2.0) = " << std::copysign(NAN,-2.0) << '\n';
}

输出：

copysign(1.0,+2.0) = 1
copysign(1.0,-2.0) = -1
copysign(inf,-2.0) = -inf
copysign(NaN,-2.0) = -nan

参阅

abs(float)fabsfabsffabsl (C++11)(C++11) | 浮点值的绝对值（ \(\small{|x|}\)|x| ） (函数)
signbit (C++11) | 检查给定数是否为负 (函数)


std::cos, std::cosf, std::cosl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float cos ( float arg ); |  |  |
float cosf( float arg ); |  |  | (C++11 起)
double cos ( double arg ); | (2) |
 | (3) |
long double cos ( long double arg ); |  |  |
long double cosl( long double arg ); |  |  | (C++11 起)
double cos ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算 arg （以弧度计量）的余弦。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 以弧度表示角的浮点或整数类型值

返回值

若不出现错误，则返回 arg 的余弦（ cos(arg) ），在范围 [-1 , +1] 中。

若 arg 的绝对值很大，则结果可能拥有少量或无有效数字。

 (C++11 前)

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

若出现下溢所致的值域错误，则返回（舍入后的）正确的结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），

  • 则若参数为 ±0 ，则结果为 1.0
  • 若参数为 ±∞ ，则返回 NaN 并引发 FE_INVALID
  • 若参数为 NaN ，则返回 NaN

注意

参数为无穷大的情况不被指定为 C 中的定义域错误，但被定义为 POSIX 中的定义域错误。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cfenv>

#pragma STDC FENV_ACCESS ON
const double pi = std::acos(-1);
int main()
{
    // 典型用法
    std::cout << "cos(pi/3) = " << std::cos(pi/3) << '\n'
              << "cos(pi/2) = " << std::cos(pi/2) << '\n'
              << "cos(-3*pi/4) = " << std::cos(-3*pi/4) << '\n';
    // 特殊值
    std::cout << "cos(+0) = " << std::cos(0.0) << '\n'
              << "cos(-0) = " << std::cos(-0.0) << '\n';
    // 错误处理
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "cos(INFINITY) = " << std::cos(INFINITY) << '\n';
    if (std::fetestexcept(FE_INVALID))
        std::cout << "    FE_INVALID raised\n";
}

可能的输出：

cos(pi/3) = 0.5
cos(pi/2) = 6.12323e-17
cos(-3*pi/4) = -0.707107
cos(+0) = 1
cos(-0) = 1
cos(INFINITY) = -nan
    FE_INVALID raised

参阅

sinsinfsinl (C++11)(C++11) | 计算正弦（ \({\small\sin{x} }\)sin(x) ） (函数)
tantanftanl (C++11)(C++11) | 计算正切（ \({\small\tan{x} }\)tan(x) ） (函数)
acosacosfacosl (C++11)(C++11) | 计算反余弦（ \({\small\arccos{x} }\)arccos(x) ） (函数)
cos(std::complex) | 计算复数的余弦（ \({\small\cos{z} }\)cos(z) ） (函数模板)
cos(std::valarray) | 应用函数 std::cos 到 valarray 的每个元素 (函数模板)


std::cosh, std::coshf, std::coshl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float cosh ( float arg ); |  |  |
float coshf( float arg ); |  |  | (C++11 起)
double cosh ( double arg ); | (2) |
 | (3) |
long double cosh ( long double arg ); |  |  |
long double coshl( long double arg ); |  |  | (C++11 起)
double cosh ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算 arg 的双曲余弦。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 的双曲余弦（ cosh(arg) 或
earg
+e-arg
2
）。

若出现上溢所致的值域错误，则返回 +HUGE_VAL 、 +HUGE_VALF 或 +HUGE_VALL 。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 1
  • 若参数为 ±∞ ，则返回 +∞
  • 若参数为 NaN ，则返回 NaN

注解

对于 IEEE 兼容的 double 类型，若 |arg| > 710.5 ，则 cosh(arg) 上溢。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <cfenv>

#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "cosh(1) = " << std::cosh(1) << '\n'
              << "cosh(-1) = " << std::cosh(-1) << '\n'
              << "log(sinh(1)+cosh(1)=" << std::log(std::sinh(1)+std::cosh(1)) << '\n';
    // 特殊值
    std::cout << "cosh(+0) = " << std::cosh(0.0) << '\n'
              << "cosh(-0) = " << std::cosh(-0.0) << '\n';
    // 错误处理
    errno=0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "cosh(710.5) = " << std::cosh(710.5) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_OVERFLOW))
        std::cout << "    FE_OVERFLOW raised\n";
}

可能的输出：

cosh(1) = 1.54308
cosh(-1) = 1.54308
log(sinh(1)+cosh(1)=1
cosh(+0) = 1
cosh(-0) = 1
cosh(710.5) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

参阅

sinhsinhfsinhl (C++11)(C++11) | 计算双曲正弦（ \({\small\sinh{x} }\)sinh(x) ） (函数)
tanhtanhftanhl (C++11)(C++11) | 计算双曲正切（ \({\small\tanh{x} }\)tanh(x) ） (函数)
acoshacoshfacoshl (C++11)(C++11)(C++11) | 计算反双曲余弦（ \({\small\operatorname{arcosh}{x} }\)arcosh(x) ） (函数)
cosh(std::complex) | 计算复数的双曲余弦（ \({\small\cosh{z} }\)cosh(z) ） (函数模板)
cosh(std::valarray) | 在 valarray 的每个元素上调用 std::cosh 函数 (函数模板)


std::div, std::ldiv, std::lldiv

< cpp‎ | numeric‎ | math
定义于头文件 <cstdlib> |  |
std::div_t div( int x, int y ); | (1) |
std::ldiv_t div( long x, long y ); | (2) |
std::lldiv_t div( long long x, long long y ); | (3) | (C++11 起)
std::ldiv_t ldiv( long x, long y ); | (4) |
std::lldiv_t lldiv( long long x, long long y ); | (5) | (C++11 起)
定义于头文件 <cinttypes> |  |
std::imaxdiv_t div( std::intmax_t x, std::intmax_t y ); | (6) | (C++11 起)
std::imaxdiv_t imaxdiv( std::intmax_t x, std::intmax_t y ); | (7) | (C++11 起)

计算分子 x 除以分母 y 的商和余数。

<cinttypes> 中提供 std::div 对 std::intmax_t 的重载，当且仅当 std::intmax_t 为扩展整数类型。

 (C++11 起)
商是舍弃任何小数部分（向零截断）的代数商。余数满足 quot * y + rem == x 。 | (C++11 前)
商是表达式 x/y 的结果。余数是表达式 x%y 的结果。 | (C++11 起)

参数

x, y - 整数值

返回值

若余数与上皆能表示成对应类型（分别为 int 、 long 、 long long 、 std::imaxdiv_t ）的对象，则返回作为定义于下的 std::div_t 、 std::ldiv_t 、 std::lldiv_t 、 std::imaxdiv_t 类型对象的二者：

std::div_t

struct div_t { int quot; int rem; };

或

struct div_t { int rem; int quot; };

std::ldiv_t

struct ldiv_t { long quot; long rem; };

或

struct ldiv_t { long rem; long quot; };

std::lldiv_t

struct lldiv_t { long long quot; long long rem; };

或

struct lldiv_t { long long rem; long long quot; };

std::imaxdiv_t

struct imaxdiv_t { std::intmax_t quot; std::intmax_t rem; };

或

struct imaxdiv_t { std::intmax_t rem; std::intmax_t quot; };

若余数或商之一无法表示，则行为未定义。

注解

C++11 前，若运算数之一为负，则内建除法与取余运算符中商的舍入方向和余数的符号是实现定义的，但在 std::div 中已为良定义。

多数平台上，单条 CPU 指令一同获得商与余数，而此函数可以活用这点，尽管编译器通常能够在适合处合并邻近的 / 与 % 。

示例

#include <string>
#include <cmath>
#include <cstdlib>
#include <iostream>

std::string itoa(int n, int base)
{
    std::string buf;
    std::div_t dv{}; dv.quot = n;
    do {
        dv = std::div(dv.quot, base);
        buf += "0123456789abcdef"[std::abs(dv.rem)];  // 字符串字面量是数组
    } while(dv.quot);
    if(n<0) buf += '-';
    return {buf.rbegin(), buf.rend()};
}

int main()
{
    std::cout << itoa(12345, 10) << '\n'
              << itoa(-12345, 10) << '\n'
              << itoa(65535, 16) << '\n';
}

输出：

12345
-12345
ffff

参阅

fmodfmodffmodl (C++11)(C++11) | 浮点除法运算的余数 (函数)
remainderremainderfremainderl (C++11)(C++11)(C++11) | 除法运算的有符号余数 (函数)
remquoremquofremquol (C++11)(C++11)(C++11) | 除法运算的有符号余数和最后三个二进制位 (函数)


std::erf, std::erff, std::erfl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float erf ( float arg );
float erff( float arg );
 (1) (C++11 起)
double erf ( double arg );
 (2) (C++11 起)
long double erf ( long double arg );
long double erfl( long double arg );
 (3) (C++11 起)
double erf ( IntegralType arg );
 (4) (C++11 起)
1-3) 计算 arg 的误差函数。
4) 接受任何整数类型参数的重载集或函数模板，等价于 (2) （参数被转型到 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 的误差函数的值，即 \(\frac{2}{\sqrt{\pi} }\int_{0}^{arg}{e^{-{t^2} }\mathsf{d}t}\)
2
√π
∫arg
0 e-t2
dt 。 若因下溢出现值域错误，则返回（舍入后的）正确结果，即 \(\frac{2\cdot arg}{\sqrt{\pi} }\)
2*arg
√π
。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 ±0
  • 若参数为 ±∞ ，则返回 ±1
  • 若参数为 NaN ，则返回 NaN

注解

若 |arg| < DBL_MIN *(sqrt(π)/2) 则保证下溢。

\(\operatorname{erf}(\frac{x}{\sigma \sqrt{2} })\)erf(
x
σ√2
) 是测量结果小于与平均数相差 \(x\)x 的值的概率，其误差服从标准差为 \(\sigma\)σ 的正态分布。

示例

以下示例计算正态分布随机变量在区间 (x1, x2) 上的概率

#include <iostream>
#include <cmath>
#include <iomanip>
double phi(double x1, double x2)
{
    return (std::erf(x2/std::sqrt(2)) - std::erf(x1/std::sqrt(2)))/2;
}
int main()
{
    std::cout << "normal variate probabilities:\n"
              << std::fixed << std::setprecision(2);
    for(int n=-4; n<4; ++n)
        std::cout << "[" << std::setw(2) << n << ":" << std::setw(2) << n+1 << "]: "
                  << std::setw(5) << 100*phi(n, n+1) << "%\n";

    std::cout << "special values:\n"
              << "erf(-0) = " << std::erf(-0.0) << '\n'
              << "erf(Inf) = " << std::erf(INFINITY) << '\n';
}

输出：

normal variate probabilities:
[-4:-3]:  0.13%
[-3:-2]:  2.14%
[-2:-1]: 13.59%
[-1: 0]: 34.13%
[ 0: 1]: 34.13%
[ 1: 2]: 13.59%
[ 2: 3]:  2.14%
[ 3: 4]:  0.13%
special values:
erf(-0) = -0.00
erf(Inf) = 1.00

参阅

erfcerfcferfcl
(C++11)(C++11)(C++11)
 补误差函数
(函数)

外部链接

Weisstein, Eric W. "Erf." 来自 MathWorld--A Wolfram Web Resource 。


std::erfc, std::erfcf, std::erfcl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float erfc ( float arg );
float erfcf( float arg );
 (1) (C++11 起)
double erfc ( double arg );
 (2) (C++11 起)
long double erfc ( long double arg );
long double erfcl( long double arg );
 (3) (C++11 起)
double erfc ( IntegralType arg );
 (4) (C++11 起)
1-3) 计算 arg 的补误差函数，即 1.0-erf(arg) ，但对于大的 arg 无精度损失。
4) 接受任何整数类型参数的重载集或函数模板。等价于 (2) （参数被转型到 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 的补误差函数的值，即 \(\frac{2}{\sqrt{\pi} }\int_{arg}^{\infty}{e^{-{t^2} }\mathsf{d}t}\)
2
√π
∫∞
arg e-t2
dt 或 \({\small 1-\operatorname{erf}(arg)}\)1-erf(arg) 。

若出现源于下溢的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 +∞ ，则返回 +0
  • 若参数为 -∞ ，则返回 2
  • 若参数为 NaN ，则返回 NaN

注解

对于 IEEE 兼容的 double 类型，若 arg > 26.55 则保证下溢。

示例

#include <iostream>
#include <cmath>
#include <iomanip>
double normalCDF(double x) // Phi(-∞, x) 又称为 N(x)
{
    return std::erfc(-x/std::sqrt(2))/2;
}
int main()
{
    std::cout << "normal cumulative distribution function:\n"
              << std::fixed << std::setprecision(2);
    for(double n=0; n<1; n+=0.1)
        std::cout << "normalCDF(" << n << ") " << 100*normalCDF(n) << "%\n";

    std::cout << "special values:\n"
              << "erfc(-Inf) = " << std::erfc(-INFINITY) << '\n'
              << "erfc(Inf) = " << std::erfc(INFINITY) << '\n';
}

输出：

normal cumulative distribution function:
normalCDF(0.00) 50.00%
normalCDF(0.10) 53.98%
normalCDF(0.20) 57.93%
normalCDF(0.30) 61.79%
normalCDF(0.40) 65.54%
normalCDF(0.50) 69.15%
normalCDF(0.60) 72.57%
normalCDF(0.70) 75.80%
normalCDF(0.80) 78.81%
normalCDF(0.90) 81.59%
normalCDF(1.00) 84.13%
special values:
erfc(-Inf) = 2.00
erfc(Inf) = 0.00

参阅

erferfferfl
(C++11)(C++11)(C++11)
 误差函数
(函数)

外部链接

Weisstein, Eric W. "Erfc." 来自 MathWorld--A Wolfram Web Resource 。


std::exp, std::expf, std::expl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float exp ( float arg ); |  |  |
float expf( float arg ); |  |  | (C++11 起)
double exp ( double arg ); | (2) |
 | (3) |
long double exp ( long double arg ); |  |  |
long double expl( long double arg ); |  |  | (C++11 起)
double exp ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算 e （欧拉数， 2.7182818 ）的 arg 次幂。
4) 接受任何整数类型参数的重载集或函数模板。等价于(2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 的底 e 指数（ earg
 ）。

若出现上溢所致的值域错误，则返回 +HUGE_VAL 、 +HUGE_VALF 或 +HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 1
  • 若参数为 -∞ ，则返回 +0
  • 若参数为 +∞ ，则返回 +∞
  • 若参数为 NaN ，则返回 NaN

注解

对于 IEEE 兼容的 double 类型，若 709.8 < arg 则保证上溢，而若 arg < -708.4 则保证下溢。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <cfenv>
#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "exp(1) = " << std::exp(1) << '\n'
              << "FV of $100, continuously compounded at 3% for 1 year = "
              << 100*std::exp(0.03) << '\n';
    // 特殊值
    std::cout << "exp(-0) = " << std::exp(-0.0) << '\n'
              << "exp(-Inf) = " << std::exp(-INFINITY) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "exp(710) = " << std::exp(710) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_OVERFLOW))
        std::cout << "    FE_OVERFLOW raised\n";
}

可能的输出：

exp(1) = 2.71828
FV of $100, continuously compounded at 3% for 1 year = 103.045
exp(-0) = 1
exp(-Inf) = 0
exp(710) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

参阅

exp2exp2fexp2l (C++11)(C++11)(C++11) | 返回 2 的给定次幂（ \({\small 2^x}\)2x ） (函数)
expm1expm1fexpm1l (C++11)(C++11)(C++11) | 返回 e 的给定次幂减一（ \({\small e^x-1}\)ex-1 ） (函数)
loglogflogl (C++11)(C++11) | 计算自然（以 e 为底）对数（ \({\small \ln{x} }\)ln(x) ） (函数)
exp(std::complex) | 以 e 为底复数的指数 (函数模板)
exp(std::valarray) | 应用函数 std::exp 到 valarray 的每个元素 (函数模板)


std::exp2, std::exp2f, std::exp2l

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float exp2 ( float n );
float exp2f( float n );
 (1) (C++11 起)
double exp2 ( double n );
 (2) (C++11 起)
long double exp2 ( long double n );
long double exp2l( long double n );
 (3) (C++11 起)
double exp2 ( IntegralType n );
 (4) (C++11 起)
1-3) 计算 2 的给定 n 次幂。
4) 接收任何整数类型参数的重载集或函数模板。等价于 (2) （将参数转型为 double ）。

参数

n - 浮点或整数类型值

返回值

若不出现错误，则返回 n 的底 2 指数（ 2n
 ）。

若出现上溢所致的值域错误，则返回 +HUGE_VAL 、 +HUGE_VALF 或 +HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 1
  • 若参数为 -∞ ，则返回 +0
  • 若参数为 +∞ ，则返回 +∞
  • 若参数为 NaN ，则返回 NaN

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <cfenv>
#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "exp2(4) = " << std::exp2(4) << '\n'
              << "exp2(0.5) = " << std::exp2(0.5) << '\n'
              << "exp2(-4) = " << std::exp2(-4) << '\n';
    // 特殊值
    std::cout << "exp2(-0) = " << std::exp2(-0.0) << '\n'
              << "exp2(-Inf) = " << std::exp2(-INFINITY) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "exp2(1024) = " << std::exp2(1024) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_OVERFLOW))
        std::cout << "    FE_OVERFLOW raised\n";
}

可能的输出：

exp2(4) = 16
exp2(0.5) = 1.41421
exp2(-4) = 0.0625
exp2(-0) = 1
exp2(-Inf) = 0
exp2(1024) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

参阅

expexpfexpl (C++11)(C++11) | 返回 e 的给定次幂（ \({\small e^x}\)ex ） (函数)
expm1expm1fexpm1l (C++11)(C++11)(C++11) | 返回 e 的给定次幂减一（ \({\small e^x-1}\)ex-1 ） (函数)
log2log2flog2l (C++11)(C++11)(C++11) | 给定数值的以 2 为底的对数（ \({\small \log_{2}{x} }\)log2(x) ） (函数)


std::expm1, std::expm1f, std::expm1l

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float expm1 ( float arg );
float expm1f( float arg );
 (1) (C++11 起)
double expm1 ( double arg );
 (2) (C++11 起)
long double expm1 ( long double arg );
long double expm1l( long double arg );
 (3) (C++11 起)
double expm1 ( IntegralType arg );
 (4) (C++11 起)
1-3) 计算 e （欧拉数， 2.7182818 ）的给定 arg 次幂减 1.0 。若 arg 接近零，则此函数比表达式 std::exp (arg)-1.0 更精确。
4) 接受任何整数类型参数的重载集或函数模板，等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误则返回 earg
-1 。

若出现上溢所致的值域错误，则返回 +HUGE_VAL 、 +HUGE_VALF 或 +HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回不修改的参数
  • 若参数为 -∞ ，则返回 -1
  • 若参数为 +∞ ，则返回 +∞
  • 若参数为 NaN ，则返回 NaN

注意

函数 std::expm1 和 std::log1p 对于金融计算有用：例如在计算小的日利率时： (1+x)n
-1 能表示为 std::expm1(n * std::log1p (x)) 。这些函数亦简化书写精确的反双曲函数。

对于 IEEE 兼容的 double 类型，若 709.8 < arg 则保证上溢。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <cfenv>
#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "expm1(1) = " << std::expm1(1) << '\n'
              << "Interest earned in 2 days on on $100, compounded daily at 1%\n"
              << " on a 30/360 calendar = "
              << 100*std::expm1(2*std::log1p(0.01/360)) << '\n'
              << "exp(1e-16)-1 = " << std::exp(1e-16)-1
              << ", but expm1(1e-16) = " << std::expm1(1e-16) << '\n';
    // 特殊值
    std::cout << "expm1(-0) = " << std::expm1(-0.0) << '\n'
              << "expm1(-Inf) = " << std::expm1(-INFINITY) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "expm1(710) = " << std::expm1(710) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_OVERFLOW))
        std::cout << "    FE_OVERFLOW raised\n";
}

可能的输出：

expm1(1) = 1.71828
Interest earned in 2 days on on $100, compounded daily at 1%
 on a 30/360 calendar = 0.00555563
exp(1e-16)-1 = 0 expm1(1e-16) = 1e-16
expm1(-0) = -0
expm1(-Inf) = -1
expm1(710) = inf
    errno == ERANGE: Result too large
    FE_OVERFLOW raised

参阅

expexpfexpl (C++11)(C++11) | 返回 e 的给定次幂（ \({\small e^x}\)ex ） (函数)
exp2exp2fexp2l (C++11)(C++11)(C++11) | 返回 2 的给定次幂（ \({\small 2^x}\)2x ） (函数)
log1plog1pflog1pl (C++11)(C++11)(C++11) | 1 加上给定数值的自然（以 e 为底）对数（ \({\small \ln{(1+x)} }\)ln(1+x) ） (函数)


std::abs(float), std::fabs, std::fabsf, std::fabsl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
定义于头文件 <cstdlib> |  |
float abs( float arg ); | (1) |
double abs( double arg ); | (2) |
long double abs( long double arg ); | (3) |
定义于头文件 <cmath> |  |
 | (4) |
float fabs ( float arg ); |  |  |
float fabsf( float arg ); |  |  | (C++11 起)
double fabs ( double arg ); | (5) |
 | (6) |
long double fabs ( long double arg ); |  |  |
long double fabsl( long double arg ); |  |  | (C++11 起)
double fabs ( IntegralType arg ); | (7) | (C++11 起)
1-6) 计算浮点值 arg 的绝对值。
7) 接受任何整数类型参数的重载集或函数模板。等价于 (5) （将参数转型为 double ）。

对于整数参数， std::abs 的整数重载更可能是较好的匹配。若以不能由整型提升转换成 int 的无符号整型参数调用 std::abs ，则程序为谬构。

参数

arg - 浮点或整数类型值

返回值

若成功，则返回 arg 的绝对值（ |arg| ）。值是准确的，且不依赖任何舍入模式。

错误处理

此函数不受制于任何指定于 math_errhandling 的错误条件。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 +0
  • 若参数为 ±∞ ，则返回 +∞
  • 若参数为 NaN ，则返回 NaN

示例

#include <iostream>
#include <cmath>

int main()
{
    std::cout << "abs(+3.0) = " << std::abs(+3.0) << '\n'
              << "abs(-3.0) = " << std::abs(-3.0) << '\n';
    // 特殊值
    std::cout << "abs(-0.0) = " << std::abs(-0.0) << '\n'
              << "abs(-Inf) = " << std::abs(-INFINITY) << '\n'
              << "abs(-NaN) = " << std::abs(-NAN) << '\n';
}

可能的输出：

abs(+3.0) = 3
abs(-3.0) = 3
abs(-0.0) = 0
abs(-Inf) = inf
abs(-NaN) = nan

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2192 | C++98 | std::abs 的重载不一致地声明于二个头文件 | 在两个头文件中都声明这些重载
LWG 2735 | C++11 | 错误地要求了 std::abs 的对整数类型返回 double 的重载 | 移除该要求

参阅

abs(int)labsllabs (C++11) | 计算整数值的绝对值（ \(\small{|x|}\)|x| ） (函数)
copysigncopysignfcopysignl (C++11)(C++11)(C++11) | 复制浮点值的符号 (函数)
signbit (C++11) | 检查给定数是否为负 (函数)
abs(std::complex) | 返回复数的模 (函数模板)
abs(std::valarray) | 应用函数 std::abs 到 valarray 的每个元素 (函数模板)


std::fdim, std::fdimf, std::fdiml

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float fdim ( float x, float y );
float fdimf( float x, float y );
 (1) (C++11 起)
double fdim ( double x, double y );
 (2) (C++11 起)
long double fdim ( long double x, long double y );
long double fdiml( long double x, long double y );
 (3) (C++11 起)
Promoted fdim ( Arithmetic1 x, Arithmetic2 y );
 (4) (C++11 起)
1-3) 返回 x 与 y 间的正差，即若 x>y 则返回 x-y ，否则（若 x≤y ）返回 +0 。
4) 任何 1-3) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则将它转型为 double 。若任何参数为 long double ，则返回类型 Promoted 亦为 long double ，否则返回类型始终为 double 。

参数

x, y - 浮点或整数类型值

返回值

若成功，则返回 x 与 y 间的正差。

若出现上溢所致的值域错误，则返回 +HUGE_VAL 、 +HUGE_VALF 或 +HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若任一参数为 NaN ，则返回 NaN

注意

等价于 std::fmax (x-y, 0) ，除了 NaN 处理要求。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <cfenv>
#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "fdim(4, 1) = " << std::fdim(4, 1)
              << " fdim(1, 4) = " << std::fdim(1, 4) << '\n'
              << "fdim(4,-1) = " << std::fdim(4, -1)
              << " fdim(1,-4) = " << std::fdim(1, -4) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "fdim(1e308, -1e308) = " << std::fdim(1e308, -1e308) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_OVERFLOW))
        std::cout << "    FE_OVERFLOW raised\n";
}

输出：

fdim(4, 1) = 3 fdim(1, 4) = 0
fdim(4,-1) = 5 fdim(1,-4) = 5
fdim(1e308, -1e308) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

参阅

abs(int)labsllabs (C++11) | 计算整数值的绝对值（ \(\small{|x|}\)|x| ） (函数)
fmaxfmaxffmaxl (C++11)(C++11)(C++11) | 两个浮点值的较大者 (函数)


std::floor, std::floorf, std::floorl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float floor ( float arg ); |  |  |
float floorf( float arg ); |  |  | (C++11 起)
double floor ( double arg ); | (2) |
 | (3) |
long double floor ( long double arg ); |  |  |
long double floorl( long double arg ); |  |  | (C++11 起)
double floor ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算不大于 arg 的最大整数值。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点值

返回值

若不出现错误，则返回不大于 arg 的最大整数值，即 ⌊arg⌋ 。

返回值
参数

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 当前舍入方式无效。
  • 若 arg 为 ±∞ ，则返回不修改的参数
  • 若 arg 为 ±0 ，则返回不修改的参数
  • 若 arg 为 NaN ，则返回 NaN

注意

在舍入非整数有限值时可以（但不要求）引发 FE_INEXACT 。

所有标准浮点格式中，最大可表示浮点值准确地为整数，故此函数自身决不上溢；然而存储于整数对象时，结果可能溢出任何整数类型（包含 std::intmax_t ）。

示例

#include <cmath>
#include <iostream>
int main()
{
    std::cout << std::fixed
              << "floor(+2.7) = " << std::floor(+2.7) << '\n'
              << "floor(-2.7) = " << std::floor(-2.7) << '\n'
              << "floor(-0.0) = " << std::floor(-0.0) << '\n'
              << "floor(-Inf) = " << std::floor(-INFINITY) << '\n';
}

输出：

floor(+2.7) = 2.000000
floor(-2.7) = -3.000000
floor(-0.0) = -0.000000
floor(-Inf) = -inf

参阅

ceilceilfceill (C++11)(C++11) | 不小于给定值的最接近整数值 (函数)
trunctruncftruncl (C++11)(C++11)(C++11) | 绝对值不大于给定值的最接近整数 (函数)
roundroundfroundllroundlroundflroundlllroundllroundfllroundl (C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11) | 最接近整数，中间情况下向远离零舍入 (函数)


std::fma, std::fmaf, std::fmal

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float fma ( float x, float y, float z );
float fmaf( float x, float y, float z );
 (1) (C++11 起)
double fma ( double x, double y, double z );
 (2) (C++11 起)
long double fma ( long double x, long double y, long double z );
long double fmal( long double x, long double y, long double z );
 (3) (C++11 起)
Promoted fma ( Arithmetic1 x, Arithmetic2 y, Arithmetic3 z );
 (4) (C++11 起)
#define FP_FAST_FMA /* implementation-defined */
 (5) (C++11 起)
#define FP_FAST_FMAF /* implementation-defined */
 (6) (C++11 起)
#define FP_FAST_FMAL /* implementation-defined */
 (7) (C++11 起)
1-3) 计算 (x*y) + z ，如同用无限精度，而仅舍入一次到结果类型。
4) 所有 1-3) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则将它转型为 double 。若任何其他参数为 long double ，则返回类型为 long double ，否则为 double 。
5-7) 若定义宏常量 FP_FAST_FMAF 、 FP_FAST_FMA 或 FP_FAST_FMAL ，则函数 std::fma 分别求值快于（并且精度高于） float 、 double 和 long double 参数的表达式 x*y+z 。若定义，则这些宏求值为整数 1 。

参数

x, y, z - 浮点或整数类型值

返回值

若成功，则返回 (x*y) + z 的值，如同计算为无限精度再舍入一次以适合目标类型（或者说是作为单次三元浮点运算计算）。

若出现上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若 x 为零而 y 为无穷大或 x 为无穷大而 y 为零，且 z 非 NaN ，则返回 NaN 并引发 FE_INVALID
  • 若 x 为零而 y 为无穷大或 x 为无穷大而 y 为零，且 z 为 NaN ，则返回 NaN 并可能引发 FE_INVALID
  • 若 x*y 为准确的无穷大且 z 为带相反符号的无穷大，则返回 NaN 并引发 FE_INVALID
  • 若 x 或 y 为 NaN ，则返回 NaN
  • 若 z 为 NaN ，且 x*y 不是 0*Inf 或 Inf*0 ，则返回 NaN （而无 FE_INVALID ）

注意

此运算经常在硬件中实现为融合乘加 CPU 指令。若硬件支持，则期待定义相应的 FP_FAST_FMA* 宏，但多数实现即使在不定义这些宏时也利用该 CPU 指令。

POSIX 另外指定被指定为返回 FE_INVALID 的情形是定义域错误。

由于其无限的中间精度， fma 是其他正确舍入数学运算，如 std::sqrt 或甚至除法（在 CPU 不支持的平台上，例如 Itanium ）的常用构建块。

同所有浮点表达式，表达式 (x*y) + z 可编译为融合乘加，除非 #pragma STDC FP_CONTRACT 为关闭。

示例

#include <iostream>
#include <iomanip>
#include <cmath>
#include <cfenv>
#pragma STDC FENV_ACCESS ON
int main()
{
    // 演示 fma 与内建运算符间的差别
    double in = 0.1;
    std::cout << "0.1 double is " << std::setprecision(23) << in
              << " (" << std::hexfloat << in << std::defaultfloat << ")\n"
              << "0.1*10 is 1.0000000000000000555112 (0x8.0000000000002p-3), "
              << "or 1.0 if rounded to double\n";
    double expr_result = 0.1 * 10 - 1;
    double fma_result = fma(0.1, 10, -1);
    std::cout << "0.1 * 10 - 1 = " << expr_result
              << " : 1 subtracted after intermediate rounding\n"
              << "fma(0.1, 10, -1) = " << std::setprecision(6) << fma_result << " ("
              << std::hexfloat << fma_result << std::defaultfloat << ")\n\n";

    // fma 用于 double-double 算术
    double high = 0.1 * 10;
    double low = fma(0.1, 10, -high);
    std::cout << "in double-double arithmetic, 0.1 * 10 is representable as "
              << high << " + " << low << "\n\n";

    // 错误处理
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "fma(+Inf, 10, -Inf) = " << std::fma(INFINITY, 10, -INFINITY) << '\n';
    if(std::fetestexcept(FE_INVALID))
        std::cout << "    FE_INVALID raised\n";
}

可能的输出：

0.1 double is 0.10000000000000000555112 (0x1.999999999999ap-4)
0.1*10 is 1.0000000000000000555112 (0x8.0000000000002p-3), or 1.0 if rounded to double
0.1 * 10 - 1 = 0 : 1 subtracted after intermediate rounding
fma(0.1, 10, -1) = 5.55112e-17 (0x1p-54)

in double-double arithmetic, 0.1 * 10 is representable as 1 + 5.55112e-17

fma(+Inf, 10, -Inf) = -nan
    FE_INVALID raised

参阅

remainderremainderfremainderl (C++11)(C++11)(C++11) | 除法运算的有符号余数 (函数)
remquoremquofremquol (C++11)(C++11)(C++11) | 除法运算的有符号余数和最后三个二进制位 (函数)


std::fmax, std::fmaxf, std::fmaxl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float fmax ( float x, float y );
float fmaxf( float x, float y );
 (1) (C++11 起)
double fmax ( double x, double y );
 (2) (C++11 起)
long double fmax ( long double x, long double y );
long double fmaxl( long double x, long double y );
 (3) (C++11 起)
Promoted fmax ( Arithmetic1 x, Arithmetic2 y );
 (4) (C++11 起)
1-3) 返回二个浮点数的较大者，把 NaNs 当做缺失数据（在 NaN 和数值间选择数值）
4) 所有 1-3) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则将它转型为 double 。若任何其他参数为 long double ，则返回类型为 long double ，否则为 double 。

参数

x, y - 浮点或整数类型值

返回值

若成功，则返回二个浮点值的较大者。返回值准确且不依赖任何舍入模式。

错误处理

此函数不受制于 math_errhandling 中指定的任何错误条件。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若二个参数之一为 NaN ，则返回另一参数的值
  • 仅若二个参数均为 NaN ，才返回 NaN

注意

不要求此函数对零的符号敏感，尽管某些实现额外强制若一个参数是 +0 而另一个是 -0 ，则返回 +0 。

示例

#include <iostream>
#include <cmath>

int main()
{
    std::cout << "fmax(2,1)    = " << std::fmax(2,1) << '\n'
              << "fmax(-Inf,0) = " << std::fmax(-INFINITY,0) << '\n'
              << "fmax(NaN,-1) = " << std::fmax(NAN,-1) << '\n';
}

输出：

fmax(2,1)    = 2
fmax(-Inf,0) = 0
fmax(NaN,-1) = -1

参阅

isgreater (C++11) | 检查第一个浮点实参是否大于第二个 (函数)
fminfminffminl (C++11)(C++11)(C++11) | 两个浮点值的较小者 (函数)
max | 返回各给定值中的较大者 (函数模板)
max_element | 返回范围内的最大元素 (函数模板)
minmax (C++11) | 返回两个元素的较小和较大者 (函数模板)
minmax_element (C++11) | 返回范围内的最小元素和最大元素 (函数模板)


std::fmin, std::fminf, std::fminl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float fmin ( float x, float y );
float fminf( float x, float y );
 (1) (C++11 起)
double fmin ( double x, double y );
 (2) (C++11 起)
long double fmin ( long double x, long double y );
long double fminl( long double x, long double y );
 (3) (C++11 起)
Promoted fmin ( Arithmetic x, Arithmetic y );
 (4) (C++11 起)
1-3) 返回二个浮点数的较小者，把 NaNs 当做缺失数据（在 NaN 和数值间选择数值）
4) 所有 1-3) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则将它转型为 double 。若任何其他参数为 long double ，则返回类型为 long double ，否则为 double 。

参数

x, y - 浮点或整数类型值

返回值

若成功，则返回二个浮点值的较小者。返回值准确且不依赖任何舍入模式。

错误处理

此函数不受制于 math_errhandling 中指定的任何错误条件。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若二个参数之一为 NaN ，则返回另一参数的值
  • 仅若二个参数均为 NaN ，才返回 NaN

注意

不要求此函数对零的符号敏感，尽管某些实现额外强制若一个参数是 +0 而另一个是 -0 ，则返回 -0 。

示例

#include <iostream>
#include <cmath>

int main()
{
    std::cout << "fmin(2,1)    = " << std::fmin(2,1) << '\n'
              << "fmin(-Inf,0) = " << std::fmin(-INFINITY,0) << '\n'
              << "fmin(NaN,-1) = " << std::fmin(NAN,-1) << '\n';
}

可能的输出：

fmin(2,1)    = 1
fmin(-Inf,0) = -inf
fmin(NaN,-1) = -1

参阅

isless (C++11) | 检查第一个浮点实参是否小于第二个 (函数)
fmaxfmaxffmaxl (C++11)(C++11)(C++11) | 两个浮点值的较大者 (函数)
min | 返回各给定值中的较小者 (函数模板)
min_element | 返回范围内的最小元素 (函数模板)
minmax (C++11) | 返回两个元素的较小和较大者 (函数模板)
minmax_element (C++11) | 返回范围内的最小元素和最大元素 (函数模板)


std::fmod, std::fmodf, std::fmodl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float fmod ( float x, float y ); |  |  |
float fmodf( float x, float y ); |  |  | (C++11 起)
double fmod ( double x, double y ); | (2) |
 | (3) |
long double fmod ( long double x, long double y ); |  |  |
long double fmodl( long double x, long double y ); |  |  | (C++11 起)
Promoted fmod ( Arithmetic1 x, Arithmetic2 y ); | (4) | (C++11 起)
1-3) 计算除法运算 x/y 的浮点余数。
4) 所有 1-3 不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则将它转型到 double 。若任何其他参数为 long double ，则返回类型是 long double ，否则是 double 。

此函数计算的除法 x/y 的浮点余数是 x - n*y 的准确值，其中 n 是截断小数部分的 x/y 。

返回值与 x 拥有相同符号，且绝对值小于 y 。

参数

x, y - 浮点值

返回值

若成功，则返回定义于上的除法 x/y 的浮点余数。

若出现定义域错误，则返回实现定义值（受支持的平台上为 NaN ）。

若出现下溢所指定值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若 y 为零则可能发生定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），

  • 若 x 为 ±0 且 y 非零，则返回 ±0
  • 若 x 为 ±∞ 且 y 非 NaN ，则返回 NaN 并引发 FE_INVALID
  • 若 y 为 ±0 且 x 非 NaN ，则返回 NaN 并引发 FE_INVALID
  • 若 y 为 ±∞ 且 x 有限，则返回 x 。
  • 若任一参数为 NaN ，则返回 NaN 。

注意

POSIX 要求若 x 为无穷大或 y 为零则出现定义域错误。

std::fmod ，但不是 std::remainder ，适于安静地包装浮点类型到无符号整数类型： (0.0 <= (y = std::fmod( std::rint (x), 65536.0 )) ? y : 65536.0 + y) 在范围 [-0.0 .. 65535.0] 内，它对应 unsigned short ，但 std::remainder ( std::rint (x), 65536.0 在范围 [-32767.0, +32768.0] 内，它在 signed short 的范围外。

fmod 的 double 版本表现为如同实现如下：

double fmod(double x, double y)
{
#pragma STDC FENV_ACCESS ON
    double result = std::remainder(std::fabs(x), (y = std::fabs(y)));
    if (std::signbit(result)) result += y;
    return std::copysign(result, x);
}

舍入 x/y 到 trunc 的参数损失过多精度时，表达式 x - trunc(x/y)*y 可以不等于 fmod(x,y) （例如： x = 30.508474576271183309, y = 6.1016949152542370172 ）。

示例

#include <iostream>
#include <cmath>
#include <cfenv>

#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "fmod(+5.1, +3.0) = " << std::fmod(5.1,3) << '\n'
              << "fmod(-5.1, +3.0) = " << std::fmod(-5.1,3) << '\n'
              << "fmod(+5.1, -3.0) = " << std::fmod(5.1,-3) << '\n'
              << "fmod(-5.1, -3.0) = " << std::fmod(-5.1,-3) << '\n';

    // 特殊值
    std::cout << "fmod(+0.0, 1.0) = " << std::fmod(0, 1) << '\n'
              << "fmod(-0.0, 1.0) = " << std::fmod(-0.0, 1) << '\n'
              << "fmod(5.1, Inf) = " << std::fmod(5.1, INFINITY) << '\n';

    // 错误处理
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "fmod(+5.1, 0) = " << std::fmod(5.1, 0) << '\n';
    if(std::fetestexcept(FE_INVALID))
        std::cout << "    FE_INVALID raised\n";
}

可能的输出：

fmod(+5.1, +3.0) = 2.1
fmod(-5.1, +3.0) = -2.1
fmod(+5.1, -3.0) = 2.1
fmod(-5.1, -3.0) = -2.1
fmod(+0.0, 1.0) = 0
fmod(-0.0, 1.0) = -0
fmod(5.1, Inf) = 5.1
fmod(+5.1, 0) = -nan
    FE_INVALID raised

参阅

div(int)ldivlldiv (C++11) | 计算整数除法的商和余数 (函数)
remainderremainderfremainderl (C++11)(C++11)(C++11) | 除法运算的有符号余数 (函数)
remquoremquofremquol (C++11)(C++11)(C++11) | 除法运算的有符号余数和最后三个二进制位 (函数)


std::fpclassify

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
int fpclassify( float arg ); | (1) | (C++11 起)
int fpclassify( double arg ); | (2) | (C++11 起)
int fpclassify( long double arg ); | (3) | (C++11 起)
int fpclassify( IntegralType arg ); | (4) | (C++11 起)
1-3) 归类浮点值 arg 到下列类别中：零、非正规、正规、无穷大、 NaN 或实现定义类别。
4) 接受任何整数类型 from 参数的重载集或函数模板。等价于 (2) （将参数转型为 double ）。

参数

arg - 浮点值

返回值

指明 arg 类别的 FP_INFINITE 、 FP_NAN 、 FP_NORMAL 、 FP_SUBNORMAL 、 FP_ZERO 或实现定义类型之一。

示例

#include <iostream>
#include <cmath>
#include <cfloat>

const char* show_classification(double x) {
    switch(std::fpclassify(x)) {
        case FP_INFINITE:  return "Inf";
        case FP_NAN:       return "NaN";
        case FP_NORMAL:    return "normal";
        case FP_SUBNORMAL: return "subnormal";
        case FP_ZERO:      return "zero";
        default:           return "unknown";
    }
}
int main()
{
    std::cout << "1.0/0.0 is " << show_classification(1/0.0) << '\n'
              << "0.0/0.0 is " << show_classification(0.0/0.0) << '\n'
              << "DBL_MIN/2 is " << show_classification(DBL_MIN/2) << '\n'
              << "-0.0 is " << show_classification(-0.0) << '\n'
              << "1.0 is " << show_classification(1.0) << '\n';
}

输出：

1.0/0.0 is Inf
0.0/0.0 is NaN
DBL_MIN/2 is subnormal
-0.0 is zero
1.0 is normal

参阅

isfinite (C++11) | 检查给定数是否拥有有限值 (函数)
isinf (C++11) | 检查给定数是否为无限 (函数)
isnan (C++11) | 检查给定的数是否 NaN (函数)
isnormal (C++11) | 检查给定数是否正规 (函数)
numeric_limits | 提供查询所有基础数值类型的性质的接口。 (类模板)


std::frexp, std::frexpf, std::frexpl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float frexp ( float arg, int* exp ); |  |  |
float frexpf( float arg, int* exp ); |  |  | (C++11 起)
double frexp ( double arg, int* exp ); | (2) |
 | (3) |
long double frexp ( long double arg, int* exp ); |  |  |
long double frexpl( long double arg, int* exp ); |  |  | (C++11 起)
double frexp ( IntegralType arg, int* exp ); | (4) | (C++11 起)
1-3) 分解给定的浮点值 x 为正规化小数和二的整数幂。
4) 接受任何整数类型参数的重载集或函数模板。等价于 (2) （将参数转型为 double ）。

参数

arg | - | 浮点值
exp | - | 指向要存储指数到的整数的指针

返回值

若 arg 为零，则返回零并存储零于 *exp 。

否则（若 arg 非零），若不出现错误，则返回范围 (-1;-0.5], [0.5; 1) 中的值 x ，并存储整数值为 *exp ，满足 x×2(*exp)
=arg 。

若存储于 *exp 的值在 int 范围外，则行为未指定。

若 arg 不是浮点数，则行为未指定。

错误处理

此函数不受制于任何指定于 math_errhandling 的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若 arg 为 ±0 ，则返回不修改的参数，并存储 0 于 *exp 。
  • 若 arg 为 ±∞ ，则返回它，并存储未指定值于 *exp 。
  • 若 arg 为 NaN ，则返回 NaN ，并存储未指定值于 *exp 。
  • 不引发浮点异常。
  • 若 FLT_RADIX 为 2 （或 2 的幂），则返回值准确，忽略当前舍入模式。

注意

二进制系统（其中 FLT_RADIX 为 2 ）上， frexp 可实现为

{
    *exp = (value == 0) ? 0 : (int)(1 + std::logb(value));
    return std::scalbn(value, -(*exp));
}

函数 std::frexp 与其对偶 std::ldexp 能一起用于操纵浮点数的表示，而无需直接的位操作。

示例

比较不同的浮点分解函数

#include <iostream>
#include <cmath>
#include <limits>

int main()
{
    double f = 123.45;
    std::cout << "Given the number " << f << " or " << std::hexfloat
              << f << std::defaultfloat << " in hex,\n";

    double f3;
    double f2 = std::modf(f, &f3);
    std::cout << "modf() makes " << f3 << " + " << f2 << '\n';

    int i;
    f2 = std::frexp(f, &i);
    std::cout << "frexp() makes " << f2 << " * 2^" << i << '\n';

    i = std::ilogb(f);
    std::cout << "logb()/ilogb() make " << f/std::scalbn(1.0, i) << " * "
              << std::numeric_limits<double>::radix
              << "^" << std::ilogb(f) << '\n';
}

可能的输出：

Given the number 123.45 or 0x1.edccccccccccdp+6 in hex,
modf() makes 123 + 0.45
frexp() makes 0.964453 * 2^7
logb()/ilogb() make 1.92891 * 2^6

参阅

ldexpldexpfldexpl (C++11)(C++11) | 将数乘以 2 的幂次 (函数)
logblogbflogbl (C++11)(C++11)(C++11) | 提取数的指数 (函数)
ilogbilogbfilogbl (C++11)(C++11)(C++11) | 提取数的指数 (函数)
modfmodffmodfl (C++11)(C++11) | 分解数为整数和小数部分 (函数)


std::hypot, std::hypotf, std::hypotl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float hypot ( float x, float y );
float hypotf( float x, float y );
 (1) (C++11 起)
double hypot ( double x, double y );
 (2) (C++11 起)
long double hypot ( long double x, long double y );
long double hypotl( long double x, long double y );
 (3) (C++11 起)
Promoted hypot ( Arithmetic1 x, Arithmetic2 y );
 (4) (C++11 起)
float hypot ( float x, float y, float z );
 (5) (C++17 起)
double hypot ( double x, double y, double z );
 (6) (C++17 起)
long double hypot ( long double x, long double y, long double z );
 (7) (C++17 起)
Promoted hypot ( Arithmetic1 x, Arithmetic2 y, Arithmetic3 z );
 (8) (C++17 起)
1-3) 计算 x 与 y 平方和的平方根，而不会在计算的中间阶段有过度的上溢或下溢。
4) 所有 (1-3) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则它被转型为 double 。若任何其他参数为 long double ，则返回类型为 long double ，否则为 double 。
5-7) 计算 x 、 y 和 z 平方和的平方根，而不会在计算的中间阶段有过度的上溢或下溢。
8) 所有 (5-7) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则它被转型为 double 。若任何其他参数为 long double ，则返回类型为 long double ，否则为 double 。

此函数的双参数版本所计算的是直角边长度为 x 和 y 的直角三角形的斜边长，或点 (x,y) 距原点 (0,0) 的距离，或复数 x+iy 的绝对值。

此函数的三参数版本所计算的值是点 (x,y,z) 到原点 (0,0,0) 的距离。

参数

x, y, z - 浮点或整数类型值

返回值

1-4) 若不出现错误，则返回直角三角形的斜边， \(\scriptsize{\sqrt{x^2+y^2} }\)√x2
+y2
 。
5-8) 若不出现错误，则返回三维空间中到原点的距离， \(\scriptsize{\sqrt{x^2+y^2+z^2} }\)√x2
+y2
+z2
 。

若出现上溢所致的值域错误，则返回 +HUGE_VAL 、 +HUGE_VALF 或 +HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • hypot(x, y) 、 hypot(y, x) 及 hypot(x, -y) 等价
  • 若参数之一为 ±0 ，则 hypot 等价于以非零参数调用 fabs
  • 若参数之一为 ±∞ ，则 hypot 返回 +∞ ，即使另一参数为 NaN
  • 否则，若任何参数为 NaN ，则返回 NaN

注意

实现通常保证小于 1 ulp （最后位置单位）的精度： GNU 、 BSD 、 Open64 。

std::hypot(x, y) 等价于 std::abs( std::complex <double>(x,y)) 。

POSIX 指定仅若二个参数均为非正规且正确结果亦为非正规才可以出现下溢（这禁止朴素实现）。

能以 std::hypot(x2-x1, y2-y1, z2-z1) 计算二个点 (x1,y1,z1) 和 (x2,y2,z2) 在三维空间中的距离。

 (C++17 起)

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cfenv>
#include <cfloat>
#include <cstring>

#pragma STDC FENV_ACCESS ON
int main()
{
    // 通常用法
    std::cout << "(1,1) cartesian is (" << std::hypot(1,1)
              << ',' << std::atan2(1,1) << ") polar\n";
    // 特殊值
    std::cout << "hypot(NAN,INFINITY) = " << std::hypot(NAN,INFINITY) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "hypot(DBL_MAX,DBL_MAX) = " << std::hypot(DBL_MAX,DBL_MAX) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno = ERANGE " << std::strerror(errno) << '\n';
    if (fetestexcept(FE_OVERFLOW))
        std::cout << "    FE_OVERFLOW raised\n";
}

输出：

(1,1) cartesian is (1.41421,0.785398) polar
hypot(NAN,INFINITY) = inf
hypot(DBL_MAX,DBL_MAX) = inf
    errno = ERANGE Numerical result out of range
    FE_OVERFLOW raised

参阅

powpowfpowl (C++11)(C++11) | 求某数的给定次幂（ \(\small{x^y}\)xy ） (函数)
sqrtsqrtfsqrtl (C++11)(C++11) | 计算平方根（ \(\small{\sqrt{x} }\)√x ） (函数)
cbrtcbrtfcbrtl (C++11)(C++11)(C++11) | 计算立方根（ \(\small{\sqrt[3]{x} }\)3√x ） (函数)
abs(std::complex) | 返回复数的模 (函数模板)


std::ilogb, std::ilogbf, std::ilogbl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
int ilogb ( float arg );
int ilogbf( float arg );
 (1) (C++11 起)
int ilogb ( double arg );
 (2) (C++11 起)
int ilogb ( long double arg );
int ilogbl( long double arg );
 (3) (C++11 起)
int ilogb ( IntegralType arg );
 (4) (C++11 起)
#define FP_ILOGB0 /*implementation-defined*/
 (5) (C++11 起)
#define FP_ILOGBNAN /*implementation-defined*/
 (6) (C++11 起)
1-3) 从浮点参数 arg 提取独立于基底的无偏指数，并将它作为有符号整数值返回。
4) 接受任何整数类型参数的重载集或函数模板。等价于 (2) （将参数转型为 double ）。
5) 展开成整数常量表达式，值为 INT_MIN 或 - INT_MAX 。
6) 展开成整数常量表达式，值为 INT_MIN 或 + INT_MAX 。

正式而言，无偏指数是非零 arg 的 log
r|arg| 的整数部分，作为有符号整数值，其中 r 是 std::numeric_limits <T>::radix ，而 T 是 arg 的浮点类型。

参数

arg - 浮点值

返回值

若不出现错误，则返回作为 int 值的 arg 的无偏指数。

若 arg 为零，则返回 FP_ILOGB0 。

若 arg 为无穷大，则返回 INT_MAX 。

若 arg 为 NaN ，则返回 FP_ILOGBNAN 。

若正确结果大于 INT_MAX 或小于 INT_MIN ，则返回值未指定，且可能出现定义域或值域错误。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 为零、无穷大或 NaN ，则可能出现定义域错误或值域错误。

若正确结果大于 INT_MAX 或小于 INT_MIN ，则可能出现定义域错误或值域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若正确结果大于 INT_MAX 或小于 INT_MIN ，则引发 FE_INVALID 。
  • 若 arg 为 ±0 、 ±∞ 或 NaN ，则引发 FE_INVALID 。
  • 所有其他情况下，结果是准确的（决不引发 FE_INEXACT ）并且忽略当前舍入模式。

注意

若 arg 不是零、无穷大或 NaN ，则返回的值准确等价于 (int) std::logb (arg) 。

POSIX 要求若 arg 为零、无穷大、 NaN 或若正确结果在 int 的范围外则出现定义域错误。

POSIX 亦要求在符合 XSI 的系统上，正确结果大于 INT_MAX 时返回值为 INT_MAX ，而正确结果小于 INT_MIN 时返回值为 INT_MIN 。

在所有已知平台上正确结果都能表示成 int 。对于要出现溢出的情况， INT_MAX 必须小于 LDBL_MAX_EXP *log2( FLT_RADIX ) 或 INT_MIN 必须大于 LDBL_MIN_EXP- LDBL_MANT_DIG )*log2( FLT_RADIX ) 。

std::ilogb 所返回的指数值始终比 std::frexp 所返回的小 1 ，因为不同的正规化要求：对于 ilogb 返回的指数 e ， |arg*r-e
| 在 1 与 r 之间（典型地在 1 与 2 之间），但 std::frexp 返回的指数 e ， |arg*2-e
| 在 0.5 与 1 之间。

示例

比较不同的浮点分解函数

#include <iostream>
#include <cmath>
#include <limits>
#include <cfenv>

#pragma STDC FENV_ACCESS ON
int main()
{
    double f = 123.45;
    std::cout << "Given the number " << f << " or " << std::hexfloat
              << f << std::defaultfloat << " in hex,\n";

    double f3;
    double f2 = std::modf(f, &f3);
    std::cout << "modf() makes " << f3 << " + " << f2 << '\n';

    int i;
    f2 = std::frexp(f, &i);
    std::cout << "frexp() makes " << f2 << " * 2^" << i << '\n';

    i = std::ilogb(f);
    std::cout << "logb()/ilogb() make " << f/std::scalbn(1.0, i) << " * "
              << std::numeric_limits<double>::radix
              << "^" << std::ilogb(f) << '\n';

    // 错误处理
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "ilogb(0) = " << std::ilogb(0) << '\n';
    if (std::fetestexcept(FE_INVALID))
        std::cout << "    FE_INVALID raised\n";
}

可能的输出：

Given the number 123.45 or 0x1.edccccccccccdp+6 in hex,
modf() makes 123 + 0.45
frexp() makes 0.964453 * 2^7
logb()/ilogb() make 1.92891 * 2^6
ilogb(0) = -2147483648
    FE_INVALID raised

参阅

frexpfrexpffrexpl (C++11)(C++11) | 将数分解为有效数字和 2 的幂次 (函数)
logblogbflogbl (C++11)(C++11)(C++11) | 提取数的指数 (函数)
scalbnscalbnfscalbnlscalblnscalblnfscalblnl (C++11)(C++11)(C++11)(C++11)(C++11)(C++11) | 将数乘以 FLT_RADIX 的幂次 (函数)


std::isfinite

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
bool isfinite( float arg ); | (1) | (C++11 起)
bool isfinite( double arg ); | (2) | (C++11 起)
bool isfinite( long double arg ); | (3) | (C++11 起)
bool isfinite( IntegralType arg ); | (4) | (C++11 起)
1-3) 确定给定的浮点数 arg 是否拥有有限值，即它是正规、非正规或零，但不是无穷大或 NaN 。
4) 接受任何整数类型 arg 参数的重载集或函数模板。等价于 (2) （将参数转型为 double ）。

参数

arg - 浮点值

返回值

若 arg 拥有有限值则为 true ，否则为 false 。

示例

#include <iostream>
#include <cmath>
#include <cfloat>

int main()
{
    std::cout << std::boolalpha
              << "isfinite(NaN) = " << std::isfinite(NAN) << '\n'
              << "isfinite(Inf) = " << std::isfinite(INFINITY) << '\n'
              << "isfinite(0.0) = " << std::isfinite(0.0) << '\n'
              << "isfinite(exp(800)) = " << std::isfinite(std::exp(800)) << '\n'
              << "isfinite(DBL_MIN/2.0) = " << std::isfinite(DBL_MIN/2.0) << '\n';
}

输出：

isfinite(NaN) = false
isfinite(Inf) = false
isfinite(0.0) = true
isfinite(exp(800)) = false
isfinite(DBL_MIN/2.0) = true

参阅

fpclassify (C++11) | 归类给定的浮点值 (函数)
isinf (C++11) | 检查给定数是否为无限 (函数)
isnan (C++11) | 检查给定的数是否 NaN (函数)
isnormal (C++11) | 检查给定数是否正规 (函数)


std::isgreater

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
bool isgreater( float x, float y ); | (1) | (C++11 起)
bool isgreater( double x, double y ); | (2) | (C++11 起)
bool isgreater( long double x, long double y ); | (3) | (C++11 起)
bool isgreater( Arithmetic x, Arithmetic y ); | (4) | (C++11 起)
1-3) 确定浮点数 x 是否大于浮点数 y ，而不设置浮点异常。
4) 所有 (1-3) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则将它转型为 double 。

参数

x | - | 浮点值
y | - | 浮点值

返回值

若 x > y 则为 true ，否则为 false 。

注意

若一或两个参数为 NaN ，则浮点数的内建 operator> 可能引发 FE_INVALID 。此函数是 operator> 的“安静”版本。

参阅

greater | 实现 x > y 的函数对象 (类模板)
isless (C++11) | 检查第一个浮点实参是否小于第二个 (函数)


std::isgreaterequal

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
bool isgreaterequal( float x, float y ); | (1) | (C++11 起)
bool isgreaterequal( double x, double y ); | (2) | (C++11 起)
bool isgreaterequal( long double x, long double y ); | (3) | (C++11 起)
bool isgreaterequal( Arithmetic x, Arithmetic y ); | (4) | (C++11 起)
1-3) 确定浮点数 x 是否大于或等于浮点数 y ，而不设置浮点异常。
4) 所有 (1-3) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则将它转型为 double 。

参数

x | - | 浮点值
y | - | 浮点值

返回值

若 x >= y 则为 true ，否则为 false 。

注意

若一或两个参数为 NaN ，则浮点数的内建 operator>= 可能引发 FE_INVALID 。此函数是 operator>= 的“安静”版本。

参阅

greater_equal | 实现 x >= y 的函数对象 (类模板)
islessequal (C++11) | 检查第一个浮点实参是否小于或等于第二个 (函数)


std::isinf

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
bool isinf( float arg ); | (1) | (C++11 起)
bool isinf( double arg ); | (2) | (C++11 起)
bool isinf( long double arg ); | (3) | (C++11 起)
bool isinf( IntegralType arg ); | (4) | (C++11 起)
1-3) 确定给定浮点数 arg 是否为正或负无穷大。
4) 接受任何整数类型 arg 参数的重载集或函数模板。等价于 (2) （将参数转型为 double ）。

参数

arg - 浮点值

返回值

若 arg 为无穷大则为 true ，否则为 false 。

示例

#include <iostream>
#include <cmath>
#include <cfloat>

int main()
{
    std::cout << std::boolalpha
              << "isinf(NaN) = " << std::isinf(NAN) << '\n'
              << "isinf(Inf) = " << std::isinf(INFINITY) << '\n'
              << "isinf(0.0) = " << std::isinf(0.0) << '\n'
              << "isinf(exp(800)) = " << std::isinf(std::exp(800)) << '\n'
              << "isinf(DBL_MIN/2.0) = " << std::isinf(DBL_MIN/2.0) << '\n';
}

输出：

isinf(NaN) = false
isinf(Inf) = true
isinf(0.0) = false
isinf(exp(800)) = true
isinf(DBL_MIN/2.0) = false

参阅

fpclassify (C++11) | 归类给定的浮点值 (函数)
isfinite (C++11) | 检查给定数是否拥有有限值 (函数)
isnan (C++11) | 检查给定的数是否 NaN (函数)
isnormal (C++11) | 检查给定数是否正规 (函数)


std::isless

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
bool isless( float x, float y ); | (1) | (C++11 起)
bool isless( double x, double y ); | (2) | (C++11 起)
bool isless( long double x, long double y ); | (3) | (C++11 起)
bool isless( Arithmetic x, Arithmetic y ); | (4) | (C++11 起)
1-3) 确定浮点数 x 是否小于浮点数 y ，而不设置浮点异常。
4) 所有 (1-3) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则将它转型为 double 。

参数

x | - | 浮点值
y | - | 浮点值

返回值

若 x < y 则为 true ，否则为 false 。

注意

若一或两个参数为 NaN ，则浮点数的内建 operator< 可能引发 FE_INVALID 。此函数是 operator< 的“安静”版本。

参阅

less | 实现 x < y 的函数对象 (类模板)
isgreater (C++11) | 检查第一个浮点实参是否大于第二个 (函数)


std::islessequal

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
bool islessequal( float x, float y ); | (1) | (C++11 起)
bool islessequal( double x, double y ); | (2) | (C++11 起)
bool islessequal( long double x, long double y ); | (3) | (C++11 起)
bool islessequal( Arithmetic x, Arithmetic y ); | (4) | (C++11 起)
1-3) 确定浮点数 x 是否小于或等于浮点数 y ，而不设置浮点异常。
4) 所有 (1-3) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则将它转型为 double 。

参数

x | - | 浮点值
y | - | 浮点值

返回值

若 x <= y 则为 true ，否则为 false 。

注意

若一或两个参数为 NaN ，则浮点数的内建 operator<= 可能引发 FE_INVALID 。此函数是 operator<= 的“安静”版本。

参阅

less_equal | 实现 x <= y 的函数对象 (类模板)
isgreaterequal (C++11) | 检查第一个浮点实参是否大于或等于第二个 (函数)


std::islessgreater

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
bool islessgreater( float x, float y ); | (1) | (C++11 起)
bool islessgreater( double x, double y ); | (2) | (C++11 起)
bool islessgreater( long double x, long double y ); | (3) | (C++11 起)
bool islessgreater( Arithmetic x, Arithmetic y ); | (4) | (C++11 起)
1-3) 确定浮点数 x 是否小于或大于浮点数 y ，而不设置浮点异常。
4) 所有 (1-3) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则将它转型为 double 。

参数

x | - | 浮点值
y | - | 浮点值

返回值

若 x < y || x > y 则为 true ，否则为 false 。

注意

若一或两个参数为 NaN ，则浮点数的内建 operator< 和 operator> 可能引发 FE_INVALID 。此函数是表达式 x < y || x > y 的“安静”版本。

参阅

isless (C++11) | 检查第一个浮点实参是否小于第二个 (函数)
isgreater (C++11) | 检查第一个浮点实参是否大于第二个 (函数)


std::isnan

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
bool isnan( float arg ); | (1) | (C++11 起)
bool isnan( double arg ); | (2) | (C++11 起)
bool isnan( long double arg ); | (3) | (C++11 起)
bool isnan( IntegralType arg ); | (4) | (C++11 起)
1-3) 确定给定的浮点数 arg 是否为非数（ NaN ）值。
4) 接受任何整数类型 arg 参数的重载集或函数模板。等价于 (2) （将参数转型为 double ）。

参数

arg - 浮点值

返回值

若 arg 为 NaN 则为 true ，否则为 false 。

注意

有多个拥有不同符号位和载荷的不同 NaN 值，参阅 std::nan 及 std::numeric_limits::quiet_NaN 。

NaN 值决不与自身或其他 NaN 值比较相等。 IEEE-754 不要求复制 NaN 保留其位表示（符号与载荷），尽管大多数实现保留。

另一种测试浮点值是否 NaN 的方式是与自身比较： bool is_nan(double x) { return x != x; }

示例

#include <iostream>
#include <cmath>
#include <cfloat>

int main()
{
    std::cout << std::boolalpha
              << "isnan(NaN) = " << std::isnan(NAN) << '\n'
              << "isnan(Inf) = " << std::isnan(INFINITY) << '\n'
              << "isnan(0.0) = " << std::isnan(0.0) << '\n'
              << "isnan(DBL_MIN/2.0) = " << std::isnan(DBL_MIN/2.0) << '\n'
              << "isnan(0.0 / 0.0)   = " << std::isnan(0.0/0.0) << '\n'
              << "isnan(Inf - Inf)   = " << std::isnan(INFINITY - INFINITY) << '\n';
}

输出：

isnan(NaN) = true
isnan(Inf) = false
isnan(0.0) = false
isnan(DBL_MIN/2.0) = false
isnan(0.0 / 0.0)   = true
isnan(Inf - Inf)   = true

参阅

nannanfnanl (C++11)(C++11)(C++11) | 非数（NaN） (函数)
fpclassify (C++11) | 归类给定的浮点值 (函数)
isfinite (C++11) | 检查给定数是否拥有有限值 (函数)
isinf (C++11) | 检查给定数是否为无限 (函数)
isnormal (C++11) | 检查给定数是否正规 (函数)
isunordered (C++11) | 检查两个浮点值是否无顺序 (函数)


std::isnormal

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
bool isnormal( float arg ); | (1) | (C++11 起)
bool isnormal( double arg ); | (2) | (C++11 起)
bool isnormal( long double arg ); | (3) | (C++11 起)
bool isnormal( IntegralType arg ); | (4) | (C++11 起)
1-3) 确定给定的浮点数 arg 是否为正规值，即不是零、非正规、无穷大或 NaN 。
4) 接受任何整数类型 arg 参数的重载集或函数模板。等价于 (2) （将参数转型为 double ）。

参数

arg - 浮点值

返回值

若 arg 正规则为 true ，否则为 false 。

示例

#include <iostream>
#include <cmath>
#include <cfloat>

int main()
{
    std::cout << std::boolalpha
              << "isnormal(NaN) = " << std::isnormal(NAN) << '\n'
              << "isnormal(Inf) = " << std::isnormal(INFINITY) << '\n'
              << "isnormal(0.0) = " << std::isnormal(0.0) << '\n'
              << "isnormal(DBL_MIN/2.0) = " << std::isnormal(DBL_MIN/2.0) << '\n'
              << "isnormal(1.0) = " << std::isnormal(1.0) << '\n';
}

输出：

isnormal(NaN) = false
isnormal(Inf) = false
isnormal(0.0) = false
isnormal(DBL_MIN/2.0) = false
isnormal(1.0) = true

参阅

fpclassify (C++11) | 归类给定的浮点值 (函数)
isfinite (C++11) | 检查给定数是否拥有有限值 (函数)
isinf (C++11) | 检查给定数是否为无限 (函数)
isnan (C++11) | 检查给定的数是否 NaN (函数)


std::isunordered

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
bool isunordered( float x, float y ); | (1) | (C++11 起)
bool isunordered( double x, double y ); | (2) | (C++11 起)
bool isunordered( long double x, long double y ); | (3) | (C++11 起)
bool isunordered( Arithmetic x, Arithmetic y ); | (4) | (C++11 起)
1-3) 确定二个浮点数 x 与 y 是否无序，即一或两者为 NaN ，从而无法有意义地彼此比较。
4) 所有 (1-3) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则将它转型为 double 。

参数

x | - | 浮点值
y | - | 浮点值

返回值

若 x 或 y 为 NaN 则为 true ，否则为 false 。

参阅

fpclassify (C++11) | 归类给定的浮点值 (函数)
isnan (C++11) | 检查给定的数是否 NaN (函数)


std::ldexp, std::ldexpf, std::ldexpl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float ldexp ( float x, int exp ); |  |  |
float ldexpf( float x, int exp ); |  |  | (C++11 起)
double ldexp ( double x, int exp ); | (2) |
 | (3) |
long double ldexp ( long double x, int exp ); |  |  |
long double ldexpl( long double x, int exp ); |  |  | (C++11 起)
double ldexp ( IntegralType x, int exp ); | (4) | (C++11 起)
1-3) 将浮点值 arg 乘以 2 的 exp 次幂。
4) 接受任何整数类型参数的重载集或函数模板。等价于 (2) （将参数转型为 double ）。

参数

arg | - | 浮点值
exp | - | 整数值

返回值

若不出现错误，则返回 arg 乘 2 的 exp 次幂（ arg×2exp
 ）。

若出现上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 决不引发 FE_INEXACT ，除非出现值域错误（结果准确）
  • 忽略当前舍入模式，除非出现值域错误
  • 若 arg 为 ±0 ，则返回不修改的参数
  • 若 arg 为 ±∞ ，则返回不修改的参数
  • 若 exp 为 0 ，则返回不修改的 arg
  • 若 arg 为 NaN ，则返回 NaN

注意

二进制系统上（其中 FLT_RADIX 为 2 ）， std::ldexp 等价于 std::scalbn 。

函数 std::ldexp （“加载指数”）与其对偶 std::frexp 能一同用于操纵浮点数的表示，而无需直接的位操作。

多数实现上， std::ldexp 效率低于用通常算术运算符乘或除以二的幂。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <cfenv>

#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "ldexp(7, -4) = " << std::ldexp(7, -4) << '\n'
              << "ldexp(1, -1074) = " << std::ldexp(1, -1074)
              << " (minimum positive subnormal double)\n"
              << "ldexp(nextafter(1,0), 1024) = "
              << std::ldexp(std::nextafter(1,0), 1024)
              << " (largest finite double)\n";
    // 特殊值
    std::cout << "ldexp(-0, 10) = " << std::ldexp(-0.0, 10) << '\n'
              << "ldexp(-Inf, -1) = " << std::ldexp(-INFINITY, -1) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "ldexp(1, 1024) = " << std::ldexp(1, 1024) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_OVERFLOW))
        std::cout << "    FE_OVERFLOW raised\n";
}

输出：

ldexp(7, -4) = 0.4375
ldexp(1, -1074) = 4.94066e-324 (minimum positive subnormal double)
ldexp(nextafter(1,0), 1024) = 1.79769e+308 (largest finite double)
ldexp(-0, 10) = -0
ldexp(-Inf, -1) = -inf
ldexp(1, 1024) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

参阅

frexpfrexpffrexpl (C++11)(C++11) | 将数分解为有效数字和 2 的幂次 (函数)
scalbnscalbnfscalbnlscalblnscalblnfscalblnl (C++11)(C++11)(C++11)(C++11)(C++11)(C++11) | 将数乘以 FLT_RADIX 的幂次 (函数)


std::lgamma, std::lgammaf, std::lgammal

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float lgamma ( float arg );
float lgammaf( float arg );
 (1) (C++11 起)
double lgamma ( double arg );
 (2) (C++11 起)
long double lgamma ( long double arg );
long double lgammal( long double arg );
 (3) (C++11 起)
double lgamma ( IntegralType arg );
 (4) (C++11 起)
1-3) 计算 arg 的 gamma 函数绝对值的自然对数。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 的 gamma 函数的自然对数，即 \(\log_{e}|{\int_0^\infty t^{arg-1} e^{-t} \mathsf{d}t}|\)log
e|∫∞
0 t arg-1
 e-t dt| 。

若出现极点错误，则返回 +HUGE_VAL 、 +HUGE_VALF 或 +HUGE_VALL 。

若出现上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 为零或为小于零的整数，则可能出现极点错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 1 ，则返回 +0 。
  • 若参数为 2 ，则返回 +0 。
  • 若参数为 ±0 ，则返回 +∞ 并引发 FE_DIVBYZERO 。
  • 若参数为负整数，则返回 +∞ 并引发 FE_DIVBYZERO 。
  • 若参数为 ±∞ ，则返回 +∞ 。
  • 若参数为 NaN ，则返回 NaN 。

注意

若 arg 为自然数，则 std::lgamma(arg) 是 arg-1 阶乘的自然对数。

lgamma 的 POSIX 版本不是线程安全的：每次执行函数都会存储 arg 的伽马函数的符号于静态外部变量 signgam 。一些实现提供 lgamma_r ，它接收指向 singgam 的用户提供存储的指针为第二参数，而且是线程安全的。

多数实现中有名为 gamma 的非标准函数，但其定义不一致。例如， gamma 的 glibc 和 4.2BSD 版本执行 lgamma ，但 gamma 的 4.4BSD 版本执行 tgamma 。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <cfenv>
#pragma STDC FENV_ACCESS ON
const double pi = std::acos(-1);
int main()
{
    std::cout << "lgamma(10) = " << std::lgamma(10)
              << ",  log(9!) = " << std::log(2*3*4*5*6*7*8*9) << '\n'
              << "lgamma(0.5) = " << std::lgamma(0.5)
              << " , log(sqrt(pi)) = " << std::log(std::sqrt(pi)) << '\n';
    // 特殊值
    std::cout << "lgamma(1) = " << std::lgamma(1) << '\n'
              << "lgamma(+Inf) = " << std::lgamma(INFINITY) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "lgamma(0) = " << std::lgamma(0) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_DIVBYZERO))
        std::cout << "    FE_DIVBYZERO raised\n";
}

输出：

lgamma(10) = 12.8018,  log(9!) = 12.8018
lgamma(0.5) = 0.572365 , log(sqrt(pi)) = 0.572365
lgamma(1) = 0
lgamma(+Inf) = inf
lgamma(0) = inf
    errno == ERANGE: Numerical result out of range
    FE_DIVBYZERO raised

参阅

tgammatgammaftgammal
(C++11)(C++11)(C++11)
 gamma 函数
(函数)

外部链接

Weisstein, Eric W. “对数伽马函数”来自 MathWorld--A Wolfram Web Resource 。


std::log, std::logf, std::logl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float log ( float arg ); |  |  |
float logf( float arg ); |  |  | (C++11 起)
double log ( double arg ); | (2) |
 | (3) |
long double log ( long double arg ); |  |  |
long double logl( long double arg ); |  |  | (C++11 起)
double log ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算 arg 的自然（底 e ）对数。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 的自然（底 e ）对数（ ln(arg) 或log
e(arg) ）。

若出现定义域错误，则返回实现定义值（支持的平台上为 NaN ）。

若出现极点错误，则返回 -HUGE_VAL 、 -HUGE_VALF 或 -HUGE_VALL 。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 小于零则出现定义域错误。

若 arg 为零则可能出现极点错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 -∞ 并引发 FE_DIVBYZERO 。
  • 若参数为 1 ，则返回 +0 。
  • 若参数为负数，则返回 NaN 并引发 FE_INVALID 。
  • 若参数为 +∞ ，则返回 +∞ 。
  • 若参数为 NaN ，则返回 NaN 。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <cfenv>
#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "log(1) = " << std::log(1) << '\n'
              << "base-5 logarithm of 125 = " << std::log(125)/std::log(5) << '\n';
    // 特殊值
    std::cout << "log(1) = " << std::log(1) << '\n'
              << "log(+Inf) = " << std::log(INFINITY) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "log(0) = " << std::log(0) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_DIVBYZERO))
        std::cout << "    FE_DIVBYZERO raised\n";
}

可能的输出：

log(1) = 0
base-5 logarithm of 125 = 3
log(1) = 0
log(+Inf) = inf
log(0) = -inf
    errno == ERANGE: Numerical result out of range
    FE_DIVBYZERO raised

参阅

log10log10flog10l (C++11)(C++11) | 计算常用（以 10 为底）对数（ \({\small \log_{10}{x} }\)log10(x) ） (函数)
log2log2flog2l (C++11)(C++11)(C++11) | 给定数值的以 2 为底的对数（ \({\small \log_{2}{x} }\)log2(x) ） (函数)
log1plog1pflog1pl (C++11)(C++11)(C++11) | 1 加上给定数值的自然（以 e 为底）对数（ \({\small \ln{(1+x)} }\)ln(1+x) ） (函数)
expexpfexpl (C++11)(C++11) | 返回 e 的给定次幂（ \({\small e^x}\)ex ） (函数)
log(std::complex) | 沿负实轴切割的复自然对数 (函数模板)
log(std::valarray) | 应用函数 std::log 到 valarray 的每个元素 (函数模板)


std::log10, std::log10f, std::log10l

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float log10 ( float arg ); |  |  |
float log10f( float arg ); |  |  | (C++11 起)
double log10 ( double arg ); | (2) |
 | (3) |
long double log10 ( long double arg ); |  |  |
long double log10l( long double arg ); |  |  | (C++11 起)
double log10 ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算 arg 的常用（底 10 ）对数。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 的常用（底 10 ）对数（ log
10(arg) 或 lg(arg) ）。

若出现定义域错误，则返回实现定义值（支持的平台上为 NaN ）。

若出现极点错误，则返回 -HUGE_VAL 、 -HUGE_VALF 或 -HUGE_VALL 。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 小于零则出现定义域错误。

若 arg 为零则可能出现极点错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 -∞ 并引发 FE_DIVBYZERO 。
  • 若参数为 1 ，则返回 +0 。
  • 若参数为负数，则返回 NaN 并引发 FE_INVALID 。
  • 若参数为 +∞ ，则返回 +∞ 。
  • 若参数为 NaN ，则返回 NaN 。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <cfenv>
#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "log10(1000) = " << std::log10(1000) << '\n'
              << "log10(0.001) = " << std::log10(0.001) << '\n'
              << "base-5 logarithm of 125 = " << std::log10(125)/std::log10(5) << '\n';
    // 特殊值
    std::cout << "log10(1) = " << std::log10(1) << '\n'
              << "log10(+Inf) = " << std::log10(INFINITY) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "log10(0) = " << std::log10(0) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_DIVBYZERO))
        std::cout << "    FE_DIVBYZERO raised\n";
}

可能的输出：

log10(1000) = 3
log10(0.001) = -3
base-5 logarithm of 125 = 3
log10(1) = 0
log10(+Inf) = inf
log10(0) = -inf
    errno == ERANGE: Numerical result out of range
    FE_DIVBYZERO raised

参阅

loglogflogl (C++11)(C++11) | 计算自然（以 e 为底）对数（ \({\small \ln{x} }\)ln(x) ） (函数)
log2log2flog2l (C++11)(C++11)(C++11) | 给定数值的以 2 为底的对数（ \({\small \log_{2}{x} }\)log2(x) ） (函数)
log1plog1pflog1pl (C++11)(C++11)(C++11) | 1 加上给定数值的自然（以 e 为底）对数（ \({\small \ln{(1+x)} }\)ln(1+x) ） (函数)
log10(std::complex) | 沿负实轴分割的复常用对数 (函数模板)
log10(std::valarray) | 应用函数 std::log10 到 valarray 的每个元素 (函数模板)


std::log1p, std::log1pf, std::log1pl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float log1p ( float arg );
float log1pf( float arg );
 (1) (C++11 起)
double log1p ( double arg );
 (2) (C++11 起)
long double log1p ( long double arg );
long double log1pl( long double arg );
 (3) (C++11 起)
double log1p ( IntegralType arg );
 (4) (C++11 起)
1-3) 计算 1+arg 的自然（底 e ）对数。若 arg 接近零，则此函数比表达式 std::log (1+arg) 更精确。
4) 接受任何整数类型参数的重载集或函数模板，等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误则返回 ln(1+arg) 。

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

若出现极点错误，则返回 -HUGE_VAL 、 -HUGE_VALF 或 -HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 小于 -1 则出现定义域错误。

若 arg 为 -1 则可能出现极点错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回不修改的参数。
  • 若参数为 -1 ，则返回 -∞ 并引发 FE_DIVBYZERO 。
  • 若参数小于 -1 ，则返回 NaN 并引发 FE_INVALID 。
  • 若参数为 +∞ ，则返回 +∞ 。
  • 若参数为 NaN ，则返回 NaN 。

注意

函数 std::expm1 和 std::log1p 对于金融计算有用：例如在计算小的日利率时： (1+x)n
-1 能表示为 std::expm1 (n * std::log1p(x)) 。这些函数亦简化书写精确的反双曲函数。

示例

#include <iostream>
#include <cfenv>
#include <cmath>
#include <cerrno>
#include <cstring>
#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "log1p(0) = " << log1p(0) << '\n'
              << "Interest earned in 2 days on on $100, compounded daily at 1%\n"
              << " on a 30/360 calendar = "
              << 100*expm1(2*log1p(0.01/360)) << '\n'
              << "log(1+1e-16) = " << std::log(1+1e-16)
              << " log1p(1e-16) = " << std::log1p(1e-16) << '\n';
    // 特殊值
    std::cout << "log1p(-0) = " << std::log1p(-0.0) << '\n'
              << "log1p(+Inf) = " << std::log1p(INFINITY) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "log1p(-1) = " << std::log1p(-1) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_DIVBYZERO))
        std::cout << "    FE_DIVBYZERO raised\n";
}

可能的输出：

log1p(0) = 0
Interest earned in 2 days on on $100, compounded daily at 1%
 on a 30/360 calendar = 0.00555563
log(1+1e-16) = 0 log1p(1e-16) = 1e-16
log1p(-0) = -0
log1p(+Inf) = inf
log1p(-1) = -inf
    errno == ERANGE: Result too large
    FE_DIVBYZERO raised

参阅

loglogflogl (C++11)(C++11) | 计算自然（以 e 为底）对数（ \({\small \ln{x} }\)ln(x) ） (函数)
log10log10flog10l (C++11)(C++11) | 计算常用（以 10 为底）对数（ \({\small \log_{10}{x} }\)log10(x) ） (函数)
log2log2flog2l (C++11)(C++11)(C++11) | 给定数值的以 2 为底的对数（ \({\small \log_{2}{x} }\)log2(x) ） (函数)
expm1expm1fexpm1l (C++11)(C++11)(C++11) | 返回 e 的给定次幂减一（ \({\small e^x-1}\)ex-1 ） (函数)


std::log2, std::log2f, std::log2l

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float log2 ( float arg );
float log2f( float arg );
 (1) (C++11 起)
double log2 ( double arg );
 (2) (C++11 起)
long double log2 ( long double arg );
long double log2l( long double arg );
 (3) (C++11 起)
double log2 ( IntegralType arg );
 (4) (C++11 起)
1-3) 计算 arg 的底 2 对数。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 的底 2 对数（ log
2(arg) 或 lb(arg) ）。

若出现定义域错误，则返回实现定义值（支持的平台上为 NaN ）。

若出现极点错误，则返回 -HUGE_VAL 、 -HUGE_VALF 或 -HUGE_VALL 。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 小于零则出现定义域错误。

若 arg 为零则可能出现极点错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 -∞ 并引发 FE_DIVBYZERO 。
  • 若参数为 1 ，则返回 +0 。
  • 若参数为负数，则返回 NaN 并引发 FE_INVALID 。
  • 若参数为 +∞ ，则返回 +∞ 。
  • 若参数为 NaN ，则返回 NaN 。

注意

对于整数 arg ，二进制对数能转译成输入中最高位 1 的零底下标。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <cfenv>
#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "log2(65536) = " << std::log2(65536) << '\n'
              << "log2(0.125) = " << std::log2(0.125) << '\n'
              << "log2(0x020f) = " << std::log2(0x020f)
              << " (highest set bit is in position 9)\n"
              << "base-5 logarithm of 125 = " << std::log2(125)/std::log2(5) << '\n';
    // 特殊值
    std::cout << "log2(1) = " << std::log2(1) << '\n'
              << "log2(+Inf) = " << std::log2(INFINITY) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "log2(0) = " << std::log2(0) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_DIVBYZERO))
        std::cout << "    FE_DIVBYZERO raised\n";
}

可能的输出：

log2(65536) = 16
log2(0.125) = -3
log2(0x020f) = 9.04166 (highest set bit is in position 9)
base-5 logarithm of 125 = 3
log2(1) = 0
log2(+Inf) = inf
log2(0) = -inf
    errno == ERANGE: Numerical result out of range
    FE_DIVBYZERO raised

参阅

loglogflogl (C++11)(C++11) | 计算自然（以 e 为底）对数（ \({\small \ln{x} }\)ln(x) ） (函数)
log10log10flog10l (C++11)(C++11) | 计算常用（以 10 为底）对数（ \({\small \log_{10}{x} }\)log10(x) ） (函数)
log1plog1pflog1pl (C++11)(C++11)(C++11) | 1 加上给定数值的自然（以 e 为底）对数（ \({\small \ln{(1+x)} }\)ln(1+x) ） (函数)
exp2exp2fexp2l (C++11)(C++11)(C++11) | 返回 2 的给定次幂（ \({\small 2^x}\)2x ） (函数)


std::logb, std::logbf, std::logbl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float logb ( float arg );
float logbf( float arg );
 (1) (C++11 起)
double logb ( double arg );
 (2) (C++11 起)
long double logb ( long double arg );
long double logbl( long double arg );
 (3) (C++11 起)
double logb ( IntegralType arg );
 (4) (C++11 起)
1-3) 从浮点参数 arg 提取独立于基底的无偏指数，并将它作为浮点值返回。
4) 接收任何整数类型参数的重载集或函数模板。等价于 (2) （将参数转型为 double ）。

正式而言，无偏指数是非零 arg 的 log
r|arg| 的有符号整数部分（此函数作为浮点值返回），其中 r 是 FLT_RADIX 。若 arg 为非正规，则当做它如同已正规化。

参数

arg - 浮点值

返回值

若不出现错误，则返回作为有符号浮点值的 arg 的无偏指数。

若出现定义域错误，则返回实现定义值。

若出现极点错误，则返回 -HUGE_VAL 、 -HUGE_VALF 或 -HUGE_VALL 。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 为零则可能出现定义域或值域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若 arg 为 ±0 ，则返回 -∞ 并引发 FE_DIVBYZERO 。
  • 若 arg 为 ±∞ ，则返回 +∞ 。
  • 若 arg 为 NaN ，则返回 NaN 。
  • 所有其他情况下，结果是准确的（决不引发 FE_INEXACT ）且忽略当前舍入模式。

注意

POSIX 要求若 arg 为 ±0 则出现极点错误。

std::logb 所返回的指数值始终比 std::frexp 所返回的小 1 ，因为不同的正规化要求：对于 logb 返回的指数 e ， |arg*r-e
| 在 1 与 r 之间（典型地在 1 与 2 之间），但 frexp 返回的指数 e ， |arg*2-e
| 在 0.5 与 1 之间。

示例

比较不同的浮点分解函数

#include <iostream>
#include <cmath>
#include <limits>
#include <cfenv>
#pragma STDC FENV_ACCESS ON
int main()
{
    double f = 123.45;
    std::cout << "Given the number " << f << " or " << std::hexfloat
              << f << std::defaultfloat << " in hex,\n";

    double f3;
    double f2 = std::modf(f, &f3);
    std::cout << "modf() makes " << f3 << " + " << f2 << '\n';

    int i;
    f2 = std::frexp(f, &i);
    std::cout << "frexp() makes " << f2 << " * 2^" << i << '\n';

    i = std::ilogb(f);
    std::cout << "logb()/ilogb() make " << f/std::scalbn(1.0, i) << " * "
              << std::numeric_limits<double>::radix
              << "^" << std::ilogb(f) << '\n';

    // 错误处理
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "logb(0) = " << std::logb(0) << '\n';
    if (std::fetestexcept(FE_DIVBYZERO))
        std::cout << "    FE_DIVBYZERO raised\n";
}

可能的输出：

Given the number 123.45 or 0x1.edccccccccccdp+6 in hex,
modf() makes 123 + 0.45
frexp() makes 0.964453 * 2^7
logb()/ilogb() make 1.92891 * 2^6
logb(0) = -Inf
    FE_DIVBYZERO raised

参阅

frexpfrexpffrexpl (C++11)(C++11) | 将数分解为有效数字和 2 的幂次 (函数)
ilogbilogbfilogbl (C++11)(C++11)(C++11) | 提取数的指数 (函数)
scalbnscalbnfscalbnlscalblnscalblnfscalblnl (C++11)(C++11)(C++11)(C++11)(C++11)(C++11) | 将数乘以 FLT_RADIX 的幂次 (函数)


MATH_ERRNO, MATH_ERREXCEPT, math_errhandling

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |
#define MATH_ERRNO 1 | (C++11 起)
#define MATH_ERREXCEPT 2 | (C++11 起)
#define math_errhandling /*implementation defined*/ | (C++11 起)

宏常量 math_errhandling 展开成 int 类型的表达式，要么等于 MATH_ERRNO ，要么等于 MATH_ERREXCEPT ，要么等于其逐位或（ MATH_ERRNO | MATH_ERREXCEPT ）。

math_errhandling 的值指示浮点运算符和函数所进行的错误处理：

常量 | 解释
MATH_ERREXCEPT | 指示使用浮点异常： <cfenv> 中至少定义了 FE_DIVBYZERO 、 FE_INVALID 及 FE_OVERFLOW 。
MATH_ERRNO | 指明浮点运算使用变量 errno 报告错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则要求 math_errhandling & MATH_ERREXCEPT 非零。

识别下列浮点错误条件：

条件 | 解释 | errno | 浮点异常 | 示例
定义域错误 | 参数在该运算的数学上的定义域之外（每个函数的描述列出了要求的定义域错误） | EDOM | FE_INVALID | std::acos (2)
极点错误 | 函数的数学结果恰是无限大或未定义 | ERANGE | FE_DIVBYZERO | std::log (0.0) 、 1.0/0.0
上溢所致的值域错误 | 数学结果有限，但舍入后变为无限，或在向下舍入后变成最大可表示有限值 | ERANGE | FE_OVERFLOW | std::pow ( DBL_MAX,2)
下溢所致的域错误 | 结果非零，但因为舍入变为零，或变成非正规并有精度损失 | ERANGE 或不改变（实现定义） | FE_UNDERFLOW 或无（实现定义） | DBL_TRUE_MIN /2
结果不准确 | 结果必须被舍入到目标类型 | 不改变 | FE_INEXACT 或无（未指定） | std::sqrt (2)、 1.0/10.0

注意

通常， FE_INEXACT 是否为数学库函数所引发是未指定的，但这可以显式指定于函数的描述（例如 std::rint vs std::nearbyint ）。

C++11 前，浮点异常是未指定的，要求对于任何定义域错误有 EDOM ，要求对上溢和实现定义的下溢有 ERANGE 。

示例

#include <iostream>
#include <cfenv>
#include <cmath>
#include <cerrno>
#include <cstring>
#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "MATH_ERRNO is "
              << (math_errhandling & MATH_ERRNO ? "set" : "not set") << '\n'
              << "MATH_ERREXCEPT is "
              << (math_errhandling & MATH_ERREXCEPT ? "set" : "not set") << '\n';
    std::feclearexcept(FE_ALL_EXCEPT);
    errno = 0;
    std::cout <<  "log(0) = " << std::log(0) << '\n';
    if(errno == ERANGE)
            std::cout << "errno = ERANGE (" << std::strerror(errno) << ")\n";
    if(std::fetestexcept(FE_DIVBYZERO))
        std::cout << "FE_DIVBYZERO (pole error) reported\n";
}

可能的输出：

MATH_ERRNO is set
MATH_ERREXCEPT is set
log(0) = -inf
errno = ERANGE (Numerical result out of range)
FE_DIVBYZERO (pole error) reported

参阅

FE_ALL_EXCEPTFE_DIVBYZEROFE_INEXACTFE_INVALIDFE_OVERFLOWFE_UNDERFLOW (C++11) | 浮点异常 (宏常量)
errno | 展开成 POSIX 兼容的线程局域错误号变量的宏 (宏变量)


std::modf, std::modff, std::modfl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |
 | (1)
float modf ( float x, float* iptr ); |  |
float modff( float x, float* iptr ); |  | (C++11 起)
double modf ( double x, double* iptr ); | (2)
 | (3)
long double modf ( long double x, long double* iptr ); |  |
long double modfl( long double x, long double* iptr ); |  | (C++11 起)
1-3) 分解给定的浮点值 arg 为整数和分数部分，每个都拥有与 arg 相同的类型和符号。（以浮点格式）存储整数部分于 iptr 所指向的对象。

参数

arg | - | 浮点值
iptr | - | 指向要存储整数部分的目标的浮点值的指针

返回值

若不出现错误，则返回与 x 相同符号的 x 小数部分。将整数部分放进 iptr 所指向的值。

返回值和存储于 *iptr 的值的和给出 arg （允许舍入）。

错误处理

此函数不受制于任何指定于 math_errhandling 的错误。

若实现支持 IEE 浮点算术（ IEC 60559 ），则

  • 若 arg 为 ±0 ，则返回 ±0 ，并存储 ±0 于 *iptr 。
  • 若 arg 为 ±∞ ，则返回 ±0 ，并存储 ±∞ 于 *iptr 。
  • 若 arg 为 NaN ，则返回 NaN ，并存储 NaN 于 *iptr 。
  • 返回值是准确的，忽略当前舍入模式。

注意

此函数表现为如同实现如下：

double modf(double x, double* iptr)
{
#pragma STDC FENV_ACCESS ON
    int save_round = std::fegetround();
    std::fesetround(FE_TOWARDZERO);
    *iptr = std::nearbyint(x);
    std::fesetround(save_round);
    return std::copysign(std::isinf(x) ? 0.0 : x - (*iptr), x);
}

示例

比较不同的浮点分解函数

#include <iostream>
#include <cmath>
#include <limits>

int main()
{
    double f = 123.45;
    std::cout << "Given the number " << f << " or " << std::hexfloat
              << f << std::defaultfloat << " in hex,\n";

    double f3;
    double f2 = std::modf(f, &f3);
    std::cout << "modf() makes " << f3 << " + " << f2 << '\n';

    int i;
    f2 = std::frexp(f, &i);
    std::cout << "frexp() makes " << f2 << " * 2^" << i << '\n';

    i = std::ilogb(f);
    std::cout << "logb()/ilogb() make " << f/std::scalbn(1.0, i) << " * "
              << std::numeric_limits<double>::radix
              << "^" << std::ilogb(f) << '\n';

    // 特殊值
    f2 = std::modf(-0.0, &f3);
    std::cout << "modf(-0) makes " << f3 << " + " << f2 << '\n';
    f2 = std::modf(-INFINITY, &f3);
    std::cout << "modf(-Inf) makes " << f3 << " + " << f2 << '\n';

}

可能的输出：

Given the number 123.45 or 0x1.edccccccccccdp+6 in hex,
modf() makes 123 + 0.45
frexp() makes 0.964453 * 2^7
logb()/ilogb() make 1.92891 * 2^6
modf(-0) makes -0 + -0
modf(-Inf) makes -INF + -0

参阅

trunctruncftruncl
(C++11)(C++11)(C++11)
 绝对值不大于给定值的最接近整数
(函数)


std::nearbyint, std::nearbyintf, std::nearbyintl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float nearbyint ( float arg );
float nearbyintf( float arg );
 (1) (C++11 起)
double nearbyint ( double arg );
 (2) (C++11 起)
long double nearbyint ( long double arg );
long double nearbyintl( long double arg );
 (3) (C++11 起)
double nearbyint ( IntegralType arg );
 (4) (C++11 起)
1-3) 以当前舍入模式，舍入浮点参数 arg 到浮点格式的整数值。
4) 接受任何整数类型参数的重载集或函数模板。等价于 (2) （将参数转型为 double ）。

参数

arg - 浮点值

返回值

返回 arg 按照当前舍入模式的最接近整数值。

错误处理

此函数不受制于任何指定于 math_errhandling 的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 决不引发 FE_INEXACT
  • 若 arg 为 ±∞ ，则返回不修改的参数
  • 若 arg 为 ±0 ，则返回不修改的参数
  • 若 arg 为 NaN ，则返回 NaN

注意

std::nearbyint 和 rint 之间仅有的区别是 std::nearbyint 决不引发 FE_INEXACT 。

所有标准浮点格式中，最大可表示浮点值都是整数，故 std::nearbyint 自身决不溢出；然而存储结果于整数对象时，结果可能溢出任何整数类型（包含 std::intmax_t ）。

若当前舍入模式为 FE_TONEAREST ，则此函数在中点情况向偶数舍入（同 rint ，但不同于 round ）。

示例

#include <iostream>
#include <cmath>
#include <cfenv>

int main()
{
#pragma STDC FENV_ACCESS ON
    std::fesetround(FE_TONEAREST);
    std::cout << "rounding to nearest: \n"
              << "nearbyint(+2.3) = " << std::nearbyint(2.3)
              << "  nearbyint(+2.5) = " << std::nearbyint(2.5)
              << "  nearbyint(+3.5) = " << std::nearbyint(3.5) << '\n'
              << "nearbyint(-2.3) = " << std::nearbyint(-2.3)
              << "  nearbyint(-2.5) = " << std::nearbyint(-2.5)
              << "  nearbyint(-3.5) = " << std::nearbyint(-3.5) << '\n';

    std::fesetround(FE_DOWNWARD);
    std::cout << "rounding down:\n"
              << "nearbyint(+2.3) = " << std::nearbyint(2.3)
              << "  nearbyint(+2.5) = " << std::nearbyint(2.5)
              << "  nearbyint(+3.5) = " << std::nearbyint(3.5) << '\n'
              << "nearbyint(-2.3) = " << std::nearbyint(-2.3)
              << "  nearbyint(-2.5) = " << std::nearbyint(-2.5)
              << "  nearbyint(-3.5) = " << std::nearbyint(-3.5) << '\n';

    std::cout << "nearbyint(-0.0) = " << std::nearbyint(-0.0)  << '\n'
              << "nearbyint(-Inf) = " << std::nearbyint(-INFINITY) << '\n';
}

输出：

rounding to nearest:
nearbyint(+2.3) = 2  nearbyint(+2.5) = 2  nearbyint(+3.5) = 4
nearbyint(-2.3) = -2  nearbyint(-2.5) = -2  nearbyint(-3.5) = -4
rounding down:
nearbyint(+2.3) = 2  nearbyint(+2.5) = 2  nearbyint(+3.5) = 3
nearbyint(-2.3) = -3  nearbyint(-2.5) = -3  nearbyint(-3.5) = -4
nearbyint(-0.0) = -0
nearbyint(-Inf) = -inf

参阅

rintrintfrintllrintlrintflrintlllrintllrintfllrintl (C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11) | 使用当前舍入模式的最接近整数 若结果有别则有异常 (函数)
roundroundfroundllroundlroundflroundlllroundllroundfllroundl (C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11) | 最接近整数，中间情况下向远离零舍入 (函数)
fegetroundfesetround (C++11)(C++11) | 获取或设置舍入方向 (函数)


std::nextafter, std::nextafterf, std::nextafterl, std::nexttoward, std::nexttowardf, std::nexttowardl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float nextafter ( float from, float to );
float nextafterf( float from, float to );
 (1) (C++11 起)
double nextafter ( double from, double to );
 (2) (C++11 起)
long double nextafter ( long double from, long double to );
long double nextafterl( long double from, long double to );
 (3) (C++11 起)
Promoted nextafter ( Arithmetic1 from, Arithmetic2 to );
 (4) (C++11 起)
float nexttoward ( float from, long double to );
float nexttowardf( float from, long double to );
 (5) (C++11 起)
double nexttoward ( double from, long double to );
 (6) (C++11 起)
long double nexttoward ( long double from, long double to );
long double nexttowardl( long double from, long double to );
 (7) (C++11 起)
double nexttoward ( IntegralType from, long double to );
 (8) (C++11 起)

返回 from 于 to 方向的下个可表示值。

1-3) 若 from 等于 to ，则返回 to 。
5-7) 若 from 等于 to ，则返回从 long double 转换到函数返回类型的 to ，而不带范围或精度的损失。
4) 所有 (1-3) 所不覆盖的算术类型参数的重载集或函数模板。若任何参数拥有整数类型，则将它转型为 double 。若任何参数为 long double ，则返回类型 Promoted 亦为 long double ，否则返回类型始终为 double 。
8) 接受任何整数类型 from 参数的重载集或函数模板。等价于 (6) （将参数转型为 double ）。

参数

from, to - 浮点值

返回值

若不出现错误，则返回 from 于 to 的方向的下个可表示值。若 from 等于 to ，则返回 to ，转换到函数的类型。

若出现上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL （所带符号同 from ）。

若出现下溢所致的值域错误，则返回正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若 from 有限，但期待的结果无限，则引发 FE_INEXACT 和 FE_OVERFLOW 。
  • 若 from 不等于 to 且结果为非正规或零，则引发 FE_INEXACT 和 FE_UNDERFLOW 。
  • 任何情况下，返回值独立于当前舍入模式。
  • 若 from 或 to 为 NaN ，则返回 NaN

注解

POSIX 指定上溢和下溢条件是值域错误（可以设置 errno ）。

IEC 60559 推荐凡在 from==to 时返回 from 。这些函数替而返回 to ，这使得围绕零的行为一致： std::nextafter(-0.0, +0.0) 返回 +0.0 而 std::nextafter(+0.0, -0.0) 返回 -0.0 。

nextafter 常通过操纵 IEEE 表示实现（ glibc ）（ musl ）。

示例

#include <cmath>
#include <iomanip>
#include <iostream>
#include <cfloat>
#include <cfenv>

int main()
{
    float from1 = 0, to1 = std::nextafter(from1, 1.f);
    std::cout << "The next representable float after " << std::setprecision(20) << from1
              << " is " << to1
              << std::hexfloat << " (" << to1 << ")\n" << std::defaultfloat;

    float from2 = 1, to2 = std::nextafter(from2, 2.f);
    std::cout << "The next representable float after " << from2 << " is " << to2
              << std::hexfloat << " (" << to2 << ")\n" << std::defaultfloat;

    double from3 = std::nextafter(0.1, 0), to3 = 0.1;
    std::cout << "The number 0.1 lies between two valid doubles:\n"
              << std::setprecision(56) << "    " << from3
              << std::hexfloat << " (" << from3 << ')' << std::defaultfloat
              << "\nand " << to3 << std::hexfloat << " (" << to3 << ")\n"
              << std::defaultfloat << std::setprecision(20);

    // nextafter 和 nexttoward 间的差异：
    long double dir = std::nextafter(from1, 1.0L); // 首个非正规 long double
    float x = nextafter(from1, dir); // 首先转换 dir 为 float ，给出 0
    std::cout << "With nextafter, next float after " << from1 << " is " << x << '\n';
    x = std::nexttoward(from1, dir);
    std::cout << "With nexttoward, next float after " << from1 << " is " << x << '\n';

    // 特殊值
    {
        #pragma STDC FENV_ACCESS ON
        std::feclearexcept(FE_ALL_EXCEPT);
        double from4 = DBL_MAX, to4 = std::nextafter(from4, INFINITY);
        std::cout << "The next representable double after " << std::setprecision(6)
                  << from4 << std::hexfloat << " (" << from4 << ')'
                  << std::defaultfloat << " is " << to4
                  << std::hexfloat << " (" << to4 << ")\n" << std::defaultfloat;
        if(std::fetestexcept(FE_OVERFLOW)) std::cout << "   raised FE_OVERFLOW\n";
        if(std::fetestexcept(FE_INEXACT)) std::cout << "   raised FE_INEXACT\n";
    } // 结束 FENV_ACCESS 块

    float from5 = 0.0, to5 = std::nextafter(from5, -0.0);
    std::cout << "std::nextafter(+0.0, -0.0) gives " << std::fixed << to5 << '\n';
}

输出：

The next representable float after 0 is 1.4012984643248170709e-45 (0x1p-149)
The next representable float after 1 is 1.0000001192092895508 (0x1.000002p+0)
The number 0.1 lies between two valid doubles:
    0.09999999999999999167332731531132594682276248931884765625 (0x1.9999999999999p-4)
and 0.1000000000000000055511151231257827021181583404541015625 (0x1.999999999999ap-4)
With nextafter, next float after 0 is 0
With nexttoward, next float after 0 is 1.4012984643248170709e-45
The next representable double after 1.79769e+308 (0x1.fffffffffffffp+1023) is inf (inf)
   raised FE_OVERFLOW
   raised FE_INEXACT
std::nextafter(+0.0, -0.0) gives -0.000000

参阅


std::pow, std::powf, std::powl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float pow ( float base, float exp ); |  |  |
float powf( float base, float exp ); |  |  | (C++11 起)
double pow ( double base, double exp ); | (2) |
 | (3) |
long double pow ( long double base, long double exp ); |  |  |
long double powl( long double base, long double exp ); |  |  | (C++11 起)
float pow ( float base, int iexp ); | (4) | (C++11 前)
double pow ( double base, int iexp ); | (5) | (C++11 前)
long double pow ( long double base, int iexp ); | (6) | (C++11 前)
Promoted pow ( Arithmetic1 base, Arithmetic2 exp ); | (7) | (C++11 起)
1-6) 计算 base 的 exp 或 iexp 次幂。
7) 1-3) 所不覆盖的所有算术类型组合的重载集或函数模板。若任何参数拥有整数类型，则将它转型为 double 。若任何参数为 long double ，则返回类型 Promoted 亦为 long double ，否则返回类型始终为 double 。

参数

base | - | 作为底数的浮点或整数类型值
exp | - | 作为指数的浮点或整数类型值
iexp | - | 整数值指数

返回值

若不出现错误，则返回 base 的 exp 次幂（ baseexp
 ）。

若出现定义域错误，则返回实现定义值（支持的平台上为 NaN ）。

若出现极点错误或上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若 base 有限且为负，且 exp 有限且为非整数，则出现定义域错误，并可能出现值域错误。

若 base 为零且 exp 为零，则可能出现定义域错误。

若 base 为零且 exp 为负，则可能出现定义域错误或极点错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • pow(+0, exp) ，其中 exp 为负奇数，返回 +∞ 并引发 FE_DIVBYZERO
  • pow(-0, exp) ，其中 exp 为负奇数，返回 -∞ 并引发 FE_DIVBYZERO
  • pow(±0, exp) ，其中 exp 为有限负数，且为偶数或非整数，则返回 +∞ 并引发 FE_DIVBYZERO
  • pow(±0, -∞) 返回 +∞ 并可能引发 FE_DIVBYZERO
  • pow(+0, exp) ，其中 exp 为正奇数，返回 +0
  • pow(-0, exp) ，其中 exp 为正奇数，返回 -0
  • pow(±0, exp) ，其中 exp 为正非整数或正偶数，返回 +0
  • pow(-1, ±∞) 返回 1
  • pow(+1, exp) 对于任何 exp 返回 1 ，即使 exp 为 NaN
  • pow(base, ±0) 对于任何 base 返回 1 ，即使 base 为 NaN
  • pow(base, exp) 返回 NaN 并引发 FE_INVALID ，若 base 为有限负数且 exp 为有限非整数。
  • pow(base, -∞) 对任何 |base|<1 返回 +∞
  • pow(base, -∞) 对任何 |base|>1 返回 +0
  • pow(base, +∞) 对任何 |base|<1 返回 +0
  • pow(base, +∞) 对任何 |base|>1 返回 +∞
  • pow(-∞, exp) 返回 -0 ，若 exp 为负奇整数
  • pow(-∞, exp) 返回 +0 ，若 exp 为负非整数或负偶数
  • pow(-∞, exp) 返回 -∞ ，若 exp 为正奇整数
  • pow(-∞, exp) 返回 +∞ ，若 exp 为正非整数或正偶数
  • pow(+∞, exp) 对任何 exp 返回 +0
  • pow(+∞, exp) 对任何 exp 返回 +∞
  • 除了指定于上处，若任何参数为 NaN ，则返回 NaN

注意

pow(float, int) 在 C++11 前返回 float （由重载 4 ）但从 C++11 起返回 double （由重载 7 ）。

尽管 std::pow 不能获得负数的开方根， exp 为 1/3 的常用情况还提供了 std::cbrt 。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cfenv>
#include <cstring>

#pragma STDC FENV_ACCESS ON
int main()
{
    // 通常用法
    std::cout << "pow(2, 10) = " << std::pow(2,10) << '\n'
              << "pow(2, 0.5) = " << std::pow(2,0.5) << '\n'
              << "pow(-2, -3) = " << std::pow(-2,-3) << '\n';
    // 特殊值
    std::cout << "pow(-1, NAN) = " << std::pow(-1,NAN) << '\n'
              << "pow(+1, NAN) = " << std::pow(+1,NAN) << '\n'
              << "pow(INFINITY, 2) = " << std::pow(INFINITY, 2) << '\n'
              << "pow(INFINITY, -1) = " << std::pow(INFINITY, -1) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "pow(-1, 1/3) = " << std::pow(-1, 1.0/3) << '\n';
    if (errno == EDOM)
        std::cout << "    errno == EDOM " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_INVALID))
        std::cout << "    FE_INVALID raised\n";

    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "pow(-0, -3) = " << std::pow(-0.0, -3) << '\n';
    if (std::fetestexcept(FE_DIVBYZERO))
        std::cout << "    FE_DIVBYZERO raised\n";
}

可能的输出：

pow(2, 10) = 1024
pow(2, 0.5) = 1.41421
pow(-2, -3) = -0.125
pow(-1, NAN) = nan
pow(+1, NAN) = 1
pow(INFINITY, 2) = inf
pow(INFINITY, -1) = 0
pow(-1, 1/3) = -nan
    errno == EDOM Numerical argument out of domain
    FE_INVALID raised
pow(-0, -3) = -inf
    FE_DIVBYZERO raised

参阅

sqrtsqrtfsqrtl (C++11)(C++11) | 计算平方根（ \(\small{\sqrt{x} }\)√x ） (函数)
cbrtcbrtfcbrtl (C++11)(C++11)(C++11) | 计算立方根（ \(\small{\sqrt[3]{x} }\)3√x ） (函数)
hypothypotfhypotl (C++11)(C++11)(C++11) | 计算两个给定数的平方和的平方根（ \(\scriptsize{\sqrt{x^2+y^2} }\)√x2 +y2 ） (函数)
pow(std::complex) | 复数幂，一或两个参数可为复数 (函数模板)
pow(std::valarray) | 应用函数 std::pow 到二个 valarray 或一个 valarray 与一个值 (函数模板)


std::remainder, std::remainderf, std::remainderl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float remainder ( float x, float y );
float remainderf( float x, float y );
 (1) (C++11 起)
double remainder ( double x, double y );
 (2) (C++11 起)
long double remainder ( long double x, long double y );
long double remainderl( long double x, long double y );
 (3) (C++11 起)
Promoted remainder ( Arithmetic1 x, Arithmetic2 y );
 (4) (C++11 起)
1-3) 计算浮点除法运算 x/y 的 IEEE 余数。
4) 所有 (1-3) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则将它转型到 double 。若任何其他参数为 long double ，则返回类型为 long double ，否则为 double 。

此函数所计算的除法运算 x/y 的 IEEE 浮点余数，准确地为值 x - n*y ，其中值 n 是最接近 x/y 准确值的整数值。 |n-x/y| = ½ 时，选择作为偶数的 n 。

与 std::fmod() 相反，不保证返回值拥有与 x 相同的符号。

若返回值是 0 ，则它拥有与 x 相同的符号。

参数

x, y - 浮点或整数类型值

返回值

若成功，则返回定义如上的除法 x/y 浮点余数。

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

若出现下溢所致的值域错误，则返回正确结果。

若 y 为零但不出现定义域错误，则返回零。

错误处理

报告 math_errhandling 中指定的错误。

若 y 为零则可能出现定义域错误。

若实现支持 IEEE 浮点算术 （ IEC 60559 ），

  • 当前舍入模式无效。
  • 决不引发 FE_INEXACT ，结果始终准确。
  • 若 x 为 ±∞ 且 y 非 NaN ，则返回 NaN 并引发 FE_INVALID 。
  • 若 y 为 ±0 且 x 非 NaN ，则返回 NaN 并引发 FE_INVALID 。
  • 若任一参数为 NaN ，则返回 NaN 。

注意

POSIX 要求若 x 为无穷大或 y 为零则出现定义域错误。

std::fmod ，但不是 std::remainder ，适于安静地包装浮点类型到无符号整数类型： (0.0 <= (y = std::fmod ( std::rint (x), 65536.0 )) ? y : 65536.0 + y) 在范围 [-0.0 .. 65535.0] 内，它对应 unsigned short ，但 std::remainder( std::rint (x), 65536.0 在范围 [-32767.0, +32768.0] 内，它在 signed short 的范围外。

示例

#include <iostream>
#include <cmath>
#include <cfenv>

#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "remainder(+5.1, +3.0) = " << std::remainder(5.1,3) << '\n'
              << "remainder(-5.1, +3.0) = " << std::remainder(-5.1,3) << '\n'
              << "remainder(+5.1, -3.0) = " << std::remainder(5.1,-3) << '\n'
              << "remainder(-5.1, -3.0) = " << std::remainder(-5.1,-3) << '\n';

    // 特殊值
    std::cout << "remainder(-0.0, 1.0) = " << std::remainder(-0.0, 1) << '\n'
              << "remainder(5.1, Inf) = " << std::remainder(5.1, INFINITY) << '\n';

    // 错误处理
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "remainder(+5.1, 0) = " << std::remainder(5.1, 0) << '\n';
    if(fetestexcept(FE_INVALID))
        std::cout << "    FE_INVALID raised\n";
}

可能的输出：

remainder(+5.1, +3.0) = -0.9
remainder(-5.1, +3.0) = 0.9
remainder(+5.1, -3.0) = -0.9
remainder(-5.1, -3.0) = 0.9
remainder(-0.0, 1.0) = -0
remainder(5.1, Inf) = 5.1
remainder(+5.1, 0) = -nan
    FE_INVALID raised

参阅

div(int)ldivlldiv (C++11) | 计算整数除法的商和余数 (函数)
fmodfmodffmodl (C++11)(C++11) | 浮点除法运算的余数 (函数)
remquoremquofremquol (C++11)(C++11)(C++11) | 除法运算的有符号余数和最后三个二进制位 (函数)


std::remquo, std::remquof, std::remquol

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float remquo ( float x, float y, int* quo );
float remquof( float x, float y, int* quo );
 (1) (C++11 起)
double remquo ( double x, double y, int* quo );
 (2) (C++11 起)
long double remquo ( long double x, long double y, int* quo );
long double remquol( long double x, long double y, int* quo );
 (3) (C++11 起)
Promoted remquo ( Arithmetic1 x, Arithmetic2 y, int* quo );
 (4) (C++11 起)
1-3) 计算除法运算 x/y 的浮点余数，如 std::remainder() 函数所为。另外，将存储 x/y 的至少最低三位及符号于 quo ，这足以确定结果在周期中的八分位。
4) 1-3 所不覆盖的所有算术类型参数组合的重载集或函数模板。若任何非指针参数拥有整数类型，则将它转型为 double 。若任何非指针参数为 long double ，则返回类型为 long double ，否则为 double 。

参数

x, y | - | 浮点值
quo | - | 指向存储 x/y 的符号和某些位的整数的指针

返回值

若成功，则返回定义于 std::remainder 的 x/y 的余数，并存储 x/y 的符号和至少后三位有效数字于 *quo （正式而言，存储的值的符号是 x/y 的符号，而绝对值与 x/y 的整数商的绝对值对于 modulo 2n
 同余，其中 n 是实现定义的大于或等于 3 的整数）。

若 y 为零，则存储于 *quo 的值未指定。

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

若出现下溢所致的值域错误，则若支持非正规值则返回正确结果。

若 y 为零，但不出现定义域错误，则返回零。

错误处理

报告 math_errhandling 中指定的错误。

若 y 为零则可能出现定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 当前舍入模式无效。
  • 决不引发 FE_INEXACT 。
  • 若 x 为 ±∞ 且 y 非 NaN ，则返回 NaN 并引发 FE_INVALID 。
  • 若 y 为 ±0 且 x 非 NaN ，则返回 NaN 并引发 FE_INVALID 。
  • 若 x 或 y 为 NaN ，则返回 NaN 。

注意

POSIX 要求若 x 为无穷大或 y 为零则出现定义域错误。

此函数在实现周期可准确表示为浮点值的周期函数时有用：对非常大的 x 计算 sin(πx) 时，直接调用 std::sin 可能导致巨大误差，但若首先以 std::remquo 减小参数，则商的低位可用来确定结果在周期中的八分位，同时余数可用来计算拥有高精度的值。

某些平台上硬件支持此运算（而例如在 Intel CPU 上， FPREM1 在完成时于商中准确保留 3 位精度）。

示例

#include <iostream>
#include <cmath>
#include <cfenv>

#pragma STDC FENV_ACCESS ON
const double pi = std::acos(-1);
double cos_pi_x_naive(double x) { return std::cos(pi * x); }
// 周期为 2 ，值为 (0;0.5) 正， (0.5;1.5) 负， (1.5,2) 正
double cos_pi_x_smart(double x)
{
    int quadrant;
    double rem = std::remquo(x, 1, &quadrant);
    quadrant = (unsigned)quadrant % 2;  // 周期为 2 。
    switch(quadrant) {
        case 0: return std::cos(pi * rem);
        case 1: return -std::cos(pi * rem);
    };
}
int main()
{
    std::cout << "cos(pi * 0.25) = " << cos_pi_x_naive(0.25) << '\n'
              << "cos(pi * 1.25) = " << cos_pi_x_naive(1.25) << '\n'
              << "cos(pi * 2.25) = " << cos_pi_x_naive(2.25) << '\n'
              << "cos(pi * 0.25) = " << cos_pi_x_smart(0.25) << '\n'
              << "cos(pi * 1.25) = " << cos_pi_x_smart(1.25) << '\n'
              << "cos(pi * 2.25) = " << cos_pi_x_smart(2.25) << '\n'
              << "cos(pi * 1000000000000.25) = "
              << cos_pi_x_naive(1000000000000.25) << '\n'
              << "cos(pi * 1000000000001.25) = "
              << cos_pi_x_naive(1000000000001.25) << '\n'
              << "cos(pi * 1000000000000.25) = "
              << cos_pi_x_smart(1000000000000.25) << '\n'
              << "cos(pi * 1000000000001.25) = "
              << cos_pi_x_smart(1000000000001.25) << '\n';
    // 错误处理
    std::feclearexcept(FE_ALL_EXCEPT);
    int quo;
    std::cout << "remquo(+Inf, 1) = " << std::remquo(INFINITY, 1, &quo) << '\n';
    if(fetestexcept(FE_INVALID)) std::cout << "    FE_INVALID raised\n";
}

可能的输出：

cos(pi * 0.25) = 0.707107
cos(pi * 1.25) = -0.707107
cos(pi * 2.25) = 0.707107
cos(pi * 0.25) = 0.707107
cos(pi * 1.25) = -0.707107
cos(pi * 2.25) = 0.707107
cos(pi * 1000000000000.25) = 0.707123
cos(pi * 1000000000001.25) = -0.707117
cos(pi * 1000000000000.25) = 0.707107
cos(pi * 1000000000001.25) = -0.707107
remquo(+Inf, 1) = -nan
    FE_INVALID raised

参阅

div(int)ldivlldiv (C++11) | 计算整数除法的商和余数 (函数)
fmodfmodffmodl (C++11)(C++11) | 浮点除法运算的余数 (函数)
remainderremainderfremainderl (C++11)(C++11)(C++11) | 除法运算的有符号余数 (函数)


std::rint, std::rintf, std::rintl, std::lrint, std::lrintf, std::lrintl, std::llrint, std::llrintf

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float rint ( float arg );
float rintf( float arg );
 (1) (C++11 起)
double rint ( double arg );
 (2) (C++11 起)
long double rint ( long double arg );
long double rintl( long double arg );
 (3) (C++11 起)
double rint ( IntegralType arg );
 (4) (C++11 起)
long lrint ( float arg );
long lrintf( float arg );
 (5) (C++11 起)
long lrint ( double arg );
 (6) (C++11 起)
long lrint ( long double arg );
long lrintl( long double arg );
 (7) (C++11 起)
long lrint ( IntegralType arg );
 (8) (C++11 起)
long long llrint ( float arg );
long long llrintf( float arg );
 (9) (C++11 起)
long long llrint ( double arg );
 (10) (C++11 起)
long long llrint ( long double arg );
long long llrintl( long double arg );
 (11) (C++11 起)
long long llrint ( IntegralType arg );
 (12) (C++11 起)
1-3) 用当前舍入模式，舍入浮点参数 arg 为整数值（以浮点格式）。
5-7, 9-11) 用当前舍入模式，舍入浮点参数 arg 为整数值。
4,8,12) 接受任何整数类型参数的重载集或函数模板。分别等价于 (2,6,10) （将参数转型为 double ）。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 按照当前舍入模式的最接近整数值。

错误处理

报告 math_errhandling 中指定的错误。

若 std::lrint 或 std::llrint 的结果在返回类型的可表示范围外，则可能出现定义域错误或值域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

对于 std::rint 函数：
  • 若 arg 为 ±∞ ，则返回不修改的参数
  • 若 arg 为 ±0 ，则返回不修改的参数
  • 若 arg 为 NaN ，则返回 NaN
对于 std::lrint 和 std::llrint 函数：
  • 若 arg 为 ±∞ ，则引发 FE_INVALID 并返回实现定义值
  • 若舍入结果在返回类型范围外，则引发 FE_INVALID 并返回实现定义值
  • 若 arg 为 NaN ，则引发 FE_INVALID 并返回实现定义值

注意

POSIX 指定 std::lrint 或 std::llrint 引发 FE_INEXACT 的所有情况都是定义域错误。

如 math_errhandling 中指定， std::rint 在舍入非整数有限值时可以（但不在非 IEEE 浮点平台上要求）引发 FE_INEXACT 。

std::rint 和 std::nearbyint 间仅有的区别是 std::nearbyint 决不引发 FE_INEXACT 。

所有标准浮点格式中，最大可表示浮点值都是准确的整数，故 std::rint 自身决不上溢；然而在存储结果于整数对象时，结果可能溢出任何整数类型（包含 std::intmax_t ）。

若当前舍入模式为……

  • FE_DOWNWARD ，则 std::rint 等价于 std::floor 。
  • FE_UPWARD ，则 std::rint 等价于 std::ceil 。
  • FE_TOWARDZERO ，则 std::rint 等价于 std::trunc 。
  • FE_TONEAREST ，则 std::rint 在中点情况和 std::round 的区别是前者始终舍入到偶数，而非远离零。

示例

#include <iostream>
#include <cmath>
#include <cfenv>
#include <climits>

int main()
{
#pragma STDC FENV_ACCESS ON
    std::fesetround(FE_TONEAREST);
    std::cout << "rounding to nearest (halfway cases to even):\n"
              << "rint(+2.3) = " << std::rint(2.3)
              << "  rint(+2.5) = " << std::rint(2.5)
              << "  rint(+3.5) = " << std::rint(3.5) << '\n'
              << "rint(-2.3) = " << std::rint(-2.3)
              << "  rint(-2.5) = " << std::rint(-2.5)
              << "  rint(-3.5) = " << std::rint(-3.5) << '\n';

    std::fesetround(FE_DOWNWARD);
    std::cout << "rounding down:\n"
              << "rint(+2.3) = " << std::rint(2.3)
              << "  rint(+2.5) = " << std::rint(2.5)
              << "  rint(+3.5) = " << std::rint(3.5) << '\n'
              << "rint(-2.3) = " << std::rint(-2.3)
              << "  rint(-2.5) = " << std::rint(-2.5)
              << "  rint(-3.5) = " << std::rint(-3.5) << '\n'
              << "rounding down with lrint\n"
              << "lrint(+2.3) = " << std::lrint(2.3)
              << "  lrint(+2.5) = " << std::lrint(2.5)
              << "  lrint(+3.5) = " << std::lrint(3.5) << '\n'
              << "lrint(-2.3) = " << std::lrint(-2.3)
              << "  lrint(-2.5) = " << std::lrint(-2.5)
              << "  lrint(-3.5) = " << std::lrint(-3.5) << '\n';

    std::cout << "lrint(-0.0) = " << std::lrint(-0.0)  << '\n'
              << "lrint(-Inf) = " << std::lrint(-INFINITY) << '\n';

    // 错误处理
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "std::rint(0.1) = " << std::rint(.1) << '\n';
    if (std::fetestexcept(FE_INEXACT))
              std::cout << "    FE_INEXACT was raised\n";

    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "std::lrint(LONG_MIN-2048.0) = "
              << std::lrint(LONG_MIN-2048.0) << '\n';
    if (std::fetestexcept(FE_INVALID))
              std::cout << "    FE_INVALID was raised\n";
}

可能的输出：

rounding to nearest (halfway cases to even):
rint(+2.3) = 2  rint(+2.5) = 2  rint(+3.5) = 4
rint(-2.3) = -2  rint(-2.5) = -2  rint(-3.5) = -4
rounding down:
rint(+2.3) = 2  rint(+2.5) = 2  rint(+3.5) = 3
rint(-2.3) = -3  rint(-2.5) = -3  rint(-3.5) = -4
rounding down with lrint
lrint(+2.3) = 2  lrint(+2.5) = 2  lrint(+3.5) = 3
lrint(-2.3) = -3  lrint(-2.5) = -3  lrint(-3.5) = -4
lrint(-0.0) = 0
lrint(-Inf) = -9223372036854775808
std::rint(0.1) = 0
    FE_INEXACT was raised
std::lrint(LONG_MIN-2048.0) = -9223372036854775808
    FE_INVALID was raised

参阅

trunctruncftruncl (C++11)(C++11)(C++11) | 绝对值不大于给定值的最接近整数 (函数)
nearbyintnearbyintfnearbyintl (C++11)(C++11)(C++11) | 使用当前舍入模式的最接近整数 (函数)
fegetroundfesetround (C++11)(C++11) | 获取或设置舍入方向 (函数)


std::round, std::roundf, std::roundl, std::lround, std::lroundf, std::lroundl, std::llround, std::llroundf

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float round ( float arg );
float roundf( float arg );
 (1) (C++11 起)
double round ( double arg );
 (2) (C++11 起)
long double round ( long double arg );
long double roundl( long double arg );
 (3) (C++11 起)
double round ( IntegralType arg );
 (4) (C++11 起)
long lround ( float arg );
long lroundf( float arg );
 (5) (C++11 起)
long lround ( double arg );
 (6) (C++11 起)
long lround ( long double arg );
long lroundl( long double arg );
 (7) (C++11 起)
long lround ( IntegralType arg );
 (8) (C++11 起)
long long llround ( float arg );
long long llroundf( float arg );
 (9) (C++11 起)
long long llround ( double arg );
 (10) (C++11 起)
long long llround ( long double arg );
long long llroundl( long double arg );
 (11) (C++11 起)
long long llround ( IntegralType arg );
 (12) (C++11 起)
1-3) 计算 arg 的最接近整数值（以浮点格式），中点情况舍入为远离零，无关乎当前舍入模式。
5-7, 9-11) 计算 arg 的最接近整数值（以整数格式），中点情况舍入为远离零，无关乎当前舍入模式。
4,8,12) 接受任何整数类型参数的重载集或函数模板。分别等价于 2) 、 6) 或 10) （将参数转型为 double ）。

参数

arg - 浮点值

返回值

若不出现错误，则返回 arg 的最接近整数值，中点情况为远离零者。

返回值
math-round away zero.svg
参数

若出现定义域错误，则返回实现定义值。

错误处理

报告 math_errhandling 中指定的错误。

若 std::lround 或 std::llround 的结果在返回类型的可表示范围外，则可能出现定义域错误或值域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

对于 std::round 函数：
  • 当前舍入模式无效。
  • 若 arg 为 ±∞ ，则返回不修改的参数。
  • 若 arg 为 ±0 ，则返回不修改的参数。
  • 若 arg 为 NaN ，则返回 NaN 。
对于 std::lround 和 std::llround 函数：
  • 决不引发 FE_INEXACT 。
  • 当前舍入模式无效。
  • 若 arg 为 ±∞ ，则引发 FE_INVALID 并返回实现定义值。
  • 若舍入结果在返回类型范围外，则引发 FE_INVALID 并返回实现定义值。
  • 若 arg 为 NaN ，则引发 FE_INVALID 并返回实现定义值。

注意

舍入非整数有限值时 std::round 可以（但不要求）引发 FE_INEXACT 。

所有标准浮点格式中，最大可表示浮点值均为准确的整数，故 std::round 自身决不上溢；然而在存储于整数对象时，结果可能溢出任何整数类型（包含 std::intmax_t ）。

POSIX 指定 std::lround 或 std::llround 引发 FE_INEXACT 的所有情况都是定义域错误。

std::round 的 double 版本表现为如同实现如下：

#include <cmath>
#include <cfenv>
#pragma STDC FENV_ACCESS ON
double round(double x)
{
    std::fenv_t save_env;
    std::feholdexcept(&save_env);
    double result = std::rint(x);
    if (std::fetestexcept(FE_INEXACT)) {
        auto const save_round = std::fegetround();
        std::fesetround(FE_TOWARDZERO);
        result = std::rint(std::copysign(0.5 + std::fabs(x), x));
        std::fesetround(save_round);
    }
    std::feupdateenv(&save_env);
    return result;
}

示例

#include <iostream>
#include <cmath>
#include <cfenv>
#include <climits>

#pragma STDC FENV_ACCESS ON

int main()
{
    // round
    std::cout << "round(+2.3) = " << std::round(2.3)
              << "  round(+2.5) = " << std::round(2.5)
              << "  round(+2.7) = " << std::round(2.7) << '\n'
              << "round(-2.3) = " << std::round(-2.3)
              << "  round(-2.5) = " << std::round(-2.5)
              << "  round(-2.7) = " << std::round(-2.7) << '\n';

    std::cout << "round(-0.0) = " << std::round(-0.0)  << '\n'
              << "round(-Inf) = " << std::round(-INFINITY) << '\n';

    // lround
    std::cout << "lround(+2.3) = " << std::lround(2.3)
              << "  lround(+2.5) = " << std::lround(2.5)
              << "  lround(+2.7) = " << std::lround(2.7) << '\n'
              << "lround(-2.3) = " << std::lround(-2.3)
              << "  lround(-2.5) = " << std::lround(-2.5)
              << "  lround(-2.7) = " << std::lround(-2.7) << '\n';

    std::cout << "lround(-0.0) = " << std::lround(-0.0)  << '\n'
              << "lround(-Inf) = " << std::lround(-INFINITY) << '\n';

    // 错误处理
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "std::lround(LONG_MAX+1.5) = "
              << std::lround(LONG_MAX+1.5) << '\n';
    if (std::fetestexcept(FE_INVALID))
              std::cout << "    FE_INVALID was raised\n";
}

可能的输出：

round(+2.3) = 2  round(+2.5) = 3  round(+2.7) = 3
round(-2.3) = -2  round(-2.5) = -3  round(-2.7) = -3
round(-0.0) = -0
round(-Inf) = -inf
lround(+2.3) = 2  lround(+2.5) = 3  lround(+2.7) = 3
lround(-2.3) = -2  lround(-2.5) = -3  lround(-2.7) = -3
lround(-0.0) = 0
lround(-Inf) = -9223372036854775808
std::lround(LONG_MAX+1.5) = -9223372036854775808
    FE_INVALID was raised

参阅

floorfloorffloorl (C++11)(C++11) | 不大于给定值的最接近整数 (函数)
ceilceilfceill (C++11)(C++11) | 不小于给定值的最接近整数值 (函数)
trunctruncftruncl (C++11)(C++11)(C++11) | 绝对值不大于给定值的最接近整数 (函数)


std::scalbn, std::scalbnf, std::scalbnl, std::scalbln, std::scalblnf, std::scalblnl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float scalbn ( float x, int exp );
float scalbnf( float x, int exp );
 (1) (C++11 起)
double scalbn ( double x, int exp );
 (2) (C++11 起)
long double scalbn ( long double x, int exp );
long double scalbnl( long double x, int exp );
 (3) (C++11 起)
double scalbn ( IntegralType x, int exp );
 (4) (C++11 起)
float scalbln ( float x, long exp );
float scalblnf( float x, long exp );
 (5) (C++11 起)
double scalbln ( double x, long exp );
 (6) (C++11 起)
long double scalbln ( long double x, long exp );
long double scalblnl( long double x, long exp );
 (7) (C++11 起)
double scalbln ( IntegralType x, long exp );
 (8) (C++11 起)
1-3,5-7) 将浮点值 arg 乘以 FLT_RADIX 的 exp 次幂。
4,8) 接受任何整数类型参数的重载集或函数模板。等价于 (2) 或 (6) （将参数转型为 double ）。

参数

arg | - | 浮点值
exp | - | 整数值

返回值

若不出现错误，则返回 arg 乘 FLT_RADIX 的 exp 次幂（ arg×FLT_RADIXexp
 ）。

若出现上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 决不引发 FE_INEXACT ，除非出现值域错误（结果准确）
  • 忽略当前舍入模式，除非出现值域错误
  • 若 arg 为 ±0 ，则返回不修改的参数
  • 若 arg 为 ±∞ ，则返回不修改的参数
  • 若 exp 为 0 ，则返回不修改的 arg
  • 若 arg 为 NaN ，则返回 NaN

注意

二进制系统上（其中 FLT_RADIX 为 2 ）， std::scalbn 等价于 std::ldexp 。

尽管指定 std::scalbn 和 std::scalbln 高效进行运算，多数实现上它们的效率低于用算术运算符乘或除以二的幂。

函数名代表“新 scalb ”，其中 scalb 是旧的非标准函数名，其第二参数拥有浮点类型。

提供 scalbln 函数，因为从最小正浮点值放大到最大正有限值的因子可能大于标准保证的 INT_MAX 32767 。特别是对于 80 位 long double ，因子是 32828 。

GNU 实现不设置 errno ，无关乎 math_errhandling 。

注意

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <cfenv>

#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "scalbn(7, -4) = " << std::scalbn(7, -4) << '\n'
              << "scalbn(1, -1074) = " << std::scalbn(1, -1074)
              << " (minimum positive subnormal double)\n"
              << "scalbn(nextafter(1,0), 1024) = "
              << std::scalbn(std::nextafter(1,0), 1024)
              << " (largest finite double)\n";
    // 特殊值
    std::cout << "scalbn(-0, 10) = " << std::scalbn(-0.0, 10) << '\n'
              << "scalbn(-Inf, -1) = " << std::scalbn(-INFINITY, -1) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "scalbn(1, 1024) = " << std::scalbn(1, 1024) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_OVERFLOW))
        std::cout << "    FE_OVERFLOW raised\n";
}

可能的输出：

scalbn(7, -4) = 0.4375
scalbn(1, -1074) = 4.94066e-324 (minimum positive subnormal double)
scalbn(nextafter(1,0), 1024) = 1.79769e+308 (largest finite double)
scalbn(-0, 10) = -0
scalbn(-Inf, -1) = -inf
scalbn(1, 1024) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

参阅

frexpfrexpffrexpl (C++11)(C++11) | 将数分解为有效数字和 2 的幂次 (函数)
ldexpldexpfldexpl (C++11)(C++11) | 将数乘以 2 的幂次 (函数)


std::signbit

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
bool signbit( float arg ); | (1) | (C++11 起)
bool signbit( double arg ); | (2) | (C++11 起)
bool signbit( long double arg ); | (3) | (C++11 起)
bool signbit( IntegralType arg ); | (4) | (C++11 起)
1-3) 确定给定的浮点数 arg 是否为负。
4) 接受任何整数类型 arg 参数的重载集或函数模板。等价于 (2) （将参数转型为 double ）。

参数

arg - 浮点值

返回值

若 arg 为负则为 true ，否则为 false 。

注意

此函数检测零、无穷大和 NaN 的符号。 std::signbit 是检验 NaN 符号的唯二可移植方式，另一方式是 std::copysign 。

示例

#include <iostream>
#include <cmath>

int main()
{
    std::cout << std::boolalpha
              << "signbit(+0.0) = " << std::signbit(+0.0) << '\n'
              << "signbit(-0.0) = " << std::signbit(-0.0) << '\n';
}

输出：

signbit(+0.0) = false
signbit(-0.0) = true

参阅

abs(float)fabsfabsffabsl (C++11)(C++11) | 浮点值的绝对值（ \(\small{|x|}\)|x| ） (函数)
copysigncopysignfcopysignl (C++11)(C++11)(C++11) | 复制浮点值的符号 (函数)


std::sin, std::sinf, std::sinl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float sin ( float arg ); |  |  |
float sinf( float arg ); |  |  | (C++11 起)
double sin ( double arg ); | (2) |
 | (3) |
long double sin ( long double arg ); |  |  |
long double sinl( long double arg ); |  |  | (C++11 起)
double sin ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算 arg （以弧度度量）的正弦。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 以弧度表示角的浮点或整数类型值

返回值

若不发生错误，则返回 arg 的正弦（ sin(arg) ），于范围 [-1 ; +1] 中。

若 arg 的绝对值很大，结果可能拥有少量或无有效数字。

 (C++11 前)

若发生定义域错误，则返回实现定义的值（受支持的平台上为 NaN ）。

若发生下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数是 ±0 ，则返回不修改的参数
  • 若参数是 ±∞ ，则返回 NaN 并引发 FE_INVALID
  • 若参数是 NaN ，则返回 NaN

注意

参数为无穷大的情况不被指定为（ C++ 所委派的） C 中的定义域错误，但被指定为 POSIX 中的定义域错误。

POSIX 亦指定在溢出的情况下，返回不修改的 arg ，而且若不支持如此，则返回实现定义的不大于 DBL_MIN 、 FLT_MIN 及 LDBL_MIN 的值。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cfenv>

#pragma STDC FENV_ACCESS ON
const double pi = std::acos(-1);
int main()
{
    // 典型用法
    std::cout << "sin(pi/6) = " << std::sin(pi/6) << '\n'
              << "sin(pi/2) = " << std::sin(pi/2) << '\n'
              << "sin(-3*pi/4) = " << std::sin(-3*pi/4) << '\n';
    // 特殊值
    std::cout << "sin(+0) = " << std::sin(0.0) << '\n'
              << "sin(-0) = " << std::sin(-0.0) << '\n';
    // 错误处理
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "sin(INFINITY) = " << std::sin(INFINITY) << '\n';
    if (std::fetestexcept(FE_INVALID))
        std::cout << "    FE_INVALID raised\n";
}

可能的输出：

sin(pi/6) = 0.5
sin(pi/2) = 1
sin(-3*pi/4) = -0.707107
sin(+0) = 0
sin(-0) = -0
sin(INFINITY) = -nan
    FE_INVALID raised

参阅

coscosfcosl (C++11)(C++11) | 计算余弦（ \({\small\cos{x} }\)cos(x) ） (函数)
tantanftanl (C++11)(C++11) | 计算正切（ \({\small\tan{x} }\)tan(x) ） (函数)
asinasinfasinl (C++11)(C++11) | 计算反正弦（ \({\small\arcsin{x} }\)arcsin(x) ） (函数)
sin(std::complex) | 计算复数的正弦（ \({\small\sin{z} }\)sin(z) ） (函数模板)
sin(std::valarray) | 对 valarray 的每个元素应用std::sin函数 (函数模板)


std::sinh, std::sinhf, std::sinhl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float sinh ( float arg ); |  |  |
float sinhf( float arg ); |  |  | (C++11 起)
double sinh ( double arg ); | (2) |
 | (3) |
long double sinh ( long double arg ); |  |  |
long double sinhl( long double arg ); |  |  | (C++11 起)
double sinh ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算 arg 的双曲正弦。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 的双曲正弦（ sinh(arg) 或
earg
-e-arg
2
）。

若出现上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 或 ±∞ ，则返回不修改的参数
  • 若参数为 NaN ，则返回 NaN

注意

POSIX 指定在下溢情况下，返回不修改的 arg ，而若不支持如此，则返回不大于 DBL_MIN 、 FLT_MIN 和 LDBL_MIN 的实现定义值。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <cfenv>

#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "sinh(1) = " << std::sinh(1) << '\n'
              << "sinh(-1) = " << std::sinh(-1) << '\n'
              << "log(sinh(1)+cosh(1)) = "
              << std::log(std::sinh(1)+std::cosh(1)) << '\n';
    // 特殊值
    std::cout << "sinh(+0) = " << std::sinh(0.0) << '\n'
              << "sinh(-0) = " << std::sinh(-0.0) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "sinh(710.5) = " << std::sinh(710.5) << '\n';
    if (errno == ERANGE)
        std::cout << "    errno == ERANGE: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_OVERFLOW))
        std::cout << "    FE_OVERFLOW raised\n";
}

输出：

sinh(1) = 1.1752
sinh(-1) = -1.1752
log(sinh(1)+cosh(1)) = 1
sinh(+0) = 0
sinh(-0) = -0
sinh(710.5) = inf
    errno == ERANGE: Numerical result out of range
    FE_OVERFLOW raised

参阅

coshcoshfcoshl (C++11)(C++11) | 计算双曲余弦（ \({\small\cosh{x} }\)cosh(x) ） (函数)
tanhtanhftanhl (C++11)(C++11) | 计算双曲正切（ \({\small\tanh{x} }\)tanh(x) ） (函数)
asinhasinhfasinhl (C++11)(C++11)(C++11) | 计算反双曲正弦（ \({\small\operatorname{arsinh}{x} }\)arsinh(x) ） (函数)
sinh(std::complex) | 计算复数的双曲正弦（ \({\small\sinh{z} }\)sinh(z) ） (函数模板)
sinh(std::valarray) | 在 valarray 的每个元素上调用 std::sinh 函数 (函数模板)


std::sqrt, std::sqrtf, std::sqrtl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float sqrt ( float arg ); |  |  |
float sqrtf( float arg ); |  |  | (C++11 起)
double sqrt ( double arg ); | (2) |
 | (3) |
long double sqrt ( long double arg ); |  |  |
long double sqrtl( long double arg ); |  |  | (C++11 起)
double sqrt ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算 arg 的平方根。
4) 接受任何整数类型参数的重载集或函数模模板。等价于 (2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 的平方根（ \({\small \sqrt{arg} }\)√arg ）。

若出现定义域错误，则返回实现定义值（支持的平台上为 NaN ）。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若 arg 小于零则出现定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数小于 -0 ，则引发 FE_INVALID 并返回 NaN 。
  • 若参数为 +∞ 或 ±0 ，则返回不修改的参数。
  • 若参数为 NaN ，则返回 NaN 。

注解

IEEE 标准要求 std::sqrt 为准确。其他要求为准确的运算只有算术运算符和函数 std::fma 。舍入到返回类型后（用默认舍入模式）， std::sqrt 的结果与无限精度结果不可辨别。换言之，误差小于 0.5 ulp 。其他函数，含 std::pow ，不受这种制约。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cfenv>
#include <cstring>

#pragma STDC FENV_ACCESS ON

int main()
{
    // 正常使用
    std::cout << "sqrt(100) = " << std::sqrt(100) << '\n'
              << "sqrt(2) = " << std::sqrt(2) << '\n'
              << "golden ratio = " << (1+std::sqrt(5))/2 << '\n';
    // 特殊值
    std::cout << "sqrt(-0) = " << std::sqrt(-0.0) << '\n';
    // 错误处理
    errno = 0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "sqrt(-1.0) = " << std::sqrt(-1) << '\n';
    if(errno == EDOM)
        std::cout << "    errno = EDOM " << std::strerror(errno) << '\n';
    if(std::fetestexcept(FE_INVALID))
        std::cout << "    FE_INVALID raised\n";
}

可能的输出：

sqrt(100) = 10
sqrt(2) = 1.41421
golden ratio = 1.61803
sqrt(-0) = -0
sqrt(-1.0) = -nan
    errno = EDOM Numerical argument out of domain
    FE_INVALID raised

参阅

powpowfpowl (C++11)(C++11) | 求某数的给定次幂（ \(\small{x^y}\)xy ） (函数)
cbrtcbrtfcbrtl (C++11)(C++11)(C++11) | 计算立方根（ \(\small{\sqrt[3]{x} }\)3√x ） (函数)
hypothypotfhypotl (C++11)(C++11)(C++11) | 计算两个给定数的平方和的平方根（ \(\scriptsize{\sqrt{x^2+y^2} }\)√x2 +y2 ） (函数)
sqrt(std::complex) | 右半平面范围中的复平方根 (函数模板)
sqrt(std::valarray) | 应用函数 std::sqrt 到 valarray 的每个元素 (函数模板)


std::tan, std::tanf, std::tanl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float tan ( float arg ); |  |  |
float tanf( float arg ); |  |  | (C++11 起)
double tan ( double arg ); | (2) |
 | (3) |
long double tan ( long double arg ); |  |  |
long double tanl( long double arg ); |  |  | (C++11 起)
double tan ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算 arg （以弧度度量）的正切。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型的，以弧度表示角的值

返回值

若不出现错误，则返回 arg 的正切（ tan(arg) ）。

若 arg 的绝对值很大，则结果可能有较少或无有效数字。

 (C++11 前)

若出现定义域错误，则返回实现定义值（受支持平台为 NaN ）。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算数（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回不修改的参数
  • 若参数为 ±∞ ，则返回 NaN 并引发 FE_INVALID
  • 若参数为 NaN ，则返回 NaN

注意

（C++ 委派到的） C 中参数为无限大的情况未被指定为定义域错误，但它被定义为 POSIX 中的定义域错误。

函数在 π(1/2 + n) 有数学上的极点；然而无常用浮点表示能准确表示 π/2 ，故而没有值使得极点错误出现。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cfenv>

#pragma STDC FENV_ACCESS ON
const double pi = std::acos(-1);
int main()
{
    // 典型用法
    std::cout << "tan  (pi/4) = " << std::tan(  pi/4) << '\n' // 45°
              << "tan(3*pi/4) = " << std::tan(3*pi/4) << '\n' // 135°
              << "tan(5*pi/4) = " << std::tan(5*pi/4) << '\n' // -135°
              << "tan(7*pi/4) = " << std::tan(7*pi/4) << '\n'; // -45°
    // 特殊值
    std::cout << "tan(+0) = " << std::tan(0.0) << '\n'
              << "tan(-0) = " << std::tan(-0.0) << '\n';
    // 错误处理
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "tan(INFINITY) = " << std::tan(INFINITY) << '\n';
    if (std::fetestexcept(FE_INVALID))
        std::cout << "    FE_INVALID raised\n";
}

可能的输出：

tan  (pi/4) = 1
tan(3*pi/4) = -1
tan(5*pi/4) = 1
tan(7*pi/4) = -1
tan(+0) = 0
tan(-0) = -0
tan(INFINITY) = -nan
    FE_INVALID raised

参阅

sinsinfsinl (C++11)(C++11) | 计算正弦（ \({\small\sin{x} }\)sin(x) ） (函数)
coscosfcosl (C++11)(C++11) | 计算余弦（ \({\small\cos{x} }\)cos(x) ） (函数)
atanatanfatanl (C++11)(C++11) | 计算反正切（ \({\small\arctan{x} }\)arctan(x) ） (函数)
tan(std::complex) | 计算复数的正切（ \({\small\tan{z} }\)tan(z) ） (函数模板)
tan(std::valarray) | 应用函数 std::tan 到 valarray 的每个元素 (函数模板)


std::tanh, std::tanhf, std::tanhl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath> |  |
 | (1) |
float tanh ( float arg ); |  |  |
float tanhf( float arg ); |  |  | (C++11 起)
double tanh ( double arg ); | (2) |
 | (3) |
long double tanh ( long double arg ); |  |  |
long double tanhl( long double arg ); |  |  | (C++11 起)
double tanh ( IntegralType arg ); | (4) | (C++11 起)
1-3) 计算 arg 的双曲正切。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 的双曲正切（ tanh(arg) 或
earg
-e-arg
earg
+e-arg
）。

若发生下溢所致的错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 ±0
  • 若参数为 ±∞ ，则返回 ±1
  • 若参数为 NaN ，则返回 NaN

注意

POSIX 指定在下溢的情况中，返回不修改的 arg ，而且若不支持这么做，则返回不大于 DBL_MIN 、 FLT_MIN 和 LDBL_MIN 的实现定义值。

示例

#include <iostream>
#include <cmath>

int main()
{
    std::cout << "tanh(1) = " << std::tanh(1) << '\n'
              << "tanh(-1) = " << std::tanh(-1) << '\n'
              << "tanh(0.1)*sinh(0.2)-cosh(0.2) = "
              << std::tanh(0.1) * std::sinh(0.2) - std::cosh(0.2) << '\n';
    // 特殊值
    std::cout << "tanh(+0) = " << std::tanh(+0.0) << '\n'
              << "tanh(-0) = " <<  std::tanh(-0.0) << '\n';
}

输出：

tanh(1) = 0.761594
tanh(-1) = -0.761594
tanh(0.1)*sinh(0.2)-cosh(0.2) = -1
tanh(+0) = 0
tanh(-0) = -0

参阅

sinhsinhfsinhl (C++11)(C++11) | 计算双曲正弦（ \({\small\sinh{x} }\)sinh(x) ） (函数)
coshcoshfcoshl (C++11)(C++11) | 计算双曲余弦（ \({\small\cosh{x} }\)cosh(x) ） (函数)
atanhatanhfatanhl (C++11)(C++11)(C++11) | 计算反双曲正切（ \({\small\operatorname{artanh}{x} }\)artanh(x) ） (函数)
tanh(std::complex) | 计算复数的双曲正切（ \({\small\tanh{z} }\)tanh(z) ） (函数模板)
tanh(std::valarray) | 在 valarray 的每个元素上调用 std::tanh 函数 (函数模板)


std::tgamma, std::tgammaf, std::tgammal

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float tgamma ( float arg );
float tgammaf( float arg );
 (1) (C++11 起)
double tgamma ( double arg );
 (2) (C++11 起)
long double tgamma ( long double arg );
long double tgammal( long double arg );
 (3) (C++11 起)
double tgamma ( IntegralType arg );
 (4) (C++11 起)
1-3) 计算 arg 的 gamma 函数。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点或整数类型值

返回值

若不出现错误，则返回 arg 的 Γ 函数值，即 \(\Gamma(\mathtt{arg}) = \displaystyle\int_0^\infty\!\! t^{\mathtt{arg}-1} e^{-t}\, dt\)∫∞
0 t arg-1
 e-t dt 。

若出现定义域错误，则返回实现定义值（受支持平台上为 NaN ）。

若出现极点错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

若出现上溢所致的值域错误，则返回 ±HUGE_VAL 、 ±HUGE_VALF 或 ±HUGE_VALL 。

若出现下溢所致的值域错误，则返回（舍入后的）正确结果。

错误处理

报告 math_errhandling 中指定的错误

若 arg 为零或为小于零的整数，则可能出现极点或定义域错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 若参数为 ±0 ，则返回 ±∞ 并引发 FE_DIVBYZERO
  • 若参数为负整数，则返回 NaN 并引发 FE_INVALID
  • 若参数为 -∞ ，则返回 NaN 并引发 FE_INVALID
  • 若参数为 +∞ ，则返回 +∞
  • 若参数为 NaN ，则返回 NaN

注解

若 arg 为自然数，则 std::tgamma(arg) 为 arg-1 的阶乘。许多实现若参数是足够小的整数，则计算准确的整数域阶乘。

对于 IEEE 兼容的 double 类型，若 0 < x < 1/DBL_MAX 或 x > 171.7 则发生上溢。

POSIX 要求若参数为零则出现极点错误，但在参数为负整数时出现定义域错误。它亦指定在将来，对于负整数，可能替换定义域错误为浮点错误（这些情况下返回值将从 NaN 更改为 ±∞ ）。

多数实现中有名为 gamma 的非标准函数，但其定义不一致。例如， gamma 的 glibc 和 4.2BSD 版本执行 lgamma ，但 gamma 的 4.4BSD 版本执行 tgamma 。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <cfenv>
#pragma STDC FENV_ACCESS ON
int main()
{
    std::cout << "tgamma(10) = " << std::tgamma(10)
              << ", 9! = " << 2*3*4*5*6*7*8*9 << '\n'
              << "tgamma(0.5) = " << std::tgamma(0.5)
              << ", sqrt(pi) = " << std::sqrt(std::acos(-1)) << '\n';
    // 特殊值
    std::cout << "tgamma(1) = " << std::tgamma(1) << '\n'
              << "tgamma(+Inf) = " << std::tgamma(INFINITY) << '\n';
    // 错误处理
    errno=0;
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "tgamma(-1) = " << std::tgamma(-1) << '\n';
    if (errno == EDOM)
        std::cout << "    errno == EDOM: " << std::strerror(errno) << '\n';
    if (std::fetestexcept(FE_INVALID))
        std::cout << "    FE_INVALID raised\n";
}

可能的输出：

tgamma(10) = 362880, 9! = 362880
tgamma(0.5) = 1.77245, sqrt(pi) = 1.77245
tgamma(1) = 1
tgamma(+Inf) = inf
tgamma(-1) = nan
    errno == EDOM: Numerical argument out of domain
    FE_INVALID raised

参阅

lgammalgammaflgammal (C++11)(C++11)(C++11) | gamma 函数的自然对数 (函数)
betabetafbetal (C++17)(C++17)(C++17) | beta 函数 (函数)

外部链接

Weisstein, Eric W. “伽马函数”来自 MathWorld--A Wolfram Web Resource 。


std::trunc, std::truncf, std::truncl

< cpp‎ | numeric‎ | math
定义于头文件 <cmath>
float trunc ( float arg );
float truncf( float arg );
 (1) (C++11 起)
double trunc ( double arg );
 (2) (C++11 起)
long double trunc ( long double arg );
long double truncl( long double arg );
 (3) (C++11 起)
double trunc ( IntegralType arg );
 (4) (C++11 起)
1-3) 计算绝对值不大于 arg 的最接近整数。
4) 接受任何整数类型参数的重载集或函数模板。等价于 2) （将参数转型为 double ）。

参数

arg - 浮点值

返回值

若不发生错误，则返回绝对值不大于 arg 的最接近整数值（换言之，将 arg 向零舍入）。

返回值
参数

错误处理

报告 math_errhandling 中指定的错误。

若实现支持 IEEE 浮点算术（ IEC 60559 ），则

  • 当前舍入模式无效。
  • 若 arg 为 ±∞ ，则返回不修改的参数。
  • 若 arg 为 ±0 ，则返回不修改的参数。
  • 若 arg 为 NaN ，则返回 NaN

注意

截断非整数有限值时可以（但不要求）引发 FE_INEXACT 。

所有标准浮点格式中，最大可表示浮点值均为准确的整数，故此函数自身决不上溢；然而存储结果于整数对象时，结果可以溢出任何整数类型（包含 std::intmax_t ）。

从浮点到整数类型的隐式转换始终向零舍入，但它被限制于能表示成目标类型的值。

示例

#include <cmath>
#include <iostream>
int main()
{
    std::cout << std::fixed
              << "trunc(+2.7) = " << std::trunc(+2.7) << '\n'
              << "trunc(-2.9) = " << std::trunc(-2.9) << '\n'
              << "trunc(-0.0) = " << std::trunc(-0.0) << '\n'
              << "trunc(-Inf) = " << std::trunc(-INFINITY) << '\n';
}

可能的输出：

trunc(+2.7) = 2.000000
trunc(-2.9) = -2.000000
trunc(-0.0) = -0.000000
trunc(-Inf) = -inf

参阅

floorfloorffloorl (C++11)(C++11) | 不大于给定值的最接近整数 (函数)
ceilceilfceill (C++11)(C++11) | 不小于给定值的最接近整数值 (函数)
roundroundfroundllroundlroundflroundlllroundllroundfllroundl (C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11)(C++11) | 最接近整数，中间情况下向远离零舍入 (函数)


std::midpoint

< cpp‎ | numeric
定义于头文件 <numeric> |  |
template< class T > constexpr T midpoint(T a, T b) noexcept; | (1) | (C++20 起)
template< class T > constexpr T* midpoint(T* a, T* b); | (2) | (C++20 起)

计算整数、浮点或指针 a 与 b 的中点。

1) 此重载仅若 T 为 bool 以外的算术类型才参与重载决议。
2) 此重载仅若 T 为对象类型才参与重载决议。若 T 为不完整类型则此重载的使用为谬构。

参数

a, b - 整数、浮点或指针值

返回值

1) a 与 b 和的一半。不出现上溢。若 a 与 b 拥有整数类型而和为奇数，则向 a 取整结果。若 a 与 b 拥有浮点类型，则至多出现一次不准确运算。
2) 若 a 与 b 分别指向（就指针算术目的而言的）同一数组对象 x 的 x[i] 与 x[j] ，则返回指向 x[i+(j-i)/2] （或等价地为 x[std::midpoint(i, j)] ）的指针，其中除法向零取整。若 a 与 b 不指向同一数组对象，则行为未定义。

异常

不抛异常。

注解

重载 (2) 在常见平台上能简单地实现为 return a + (b - a) / 2; 。然而不保证这种实现是可移植的，因为可以有一些平台上，可在其上创建元素数大于 PTRDIFF_MAX 的数组，从而即使 b 与 a 均指向同一数组的元素 b - a 亦可导致未定义行为。

示例

#include <cstdint>
#include <limits>
#include <numeric>
#include <iostream>

int main()
{
    std::uint32_t a = std::numeric_limits<std::uint32_t>::max();
    std::uint32_t b = std::numeric_limits<std::uint32_t>::max() - 2;

    std::cout << "a: " << a << '\n'
              << "b: " << b << '\n'
              << "Incorrect (overflow and wrapping): " << (a + b) / 2 << '\n'
              << "Correct: " << std::midpoint(a, b) << "\n\n";

    auto on_pointers = [](int i, int j) {
        char const* text = "0123456789";
        char const* p = text + i;
        char const* q = text + j;
        std::cout << "std::midpoint('" << *p << "', '" << *q << "'): '"
                  << *std::midpoint(p, q) << "'\n";
    };

    on_pointers(2, 4);
    on_pointers(2, 5);
    on_pointers(5, 2);
    on_pointers(2, 6);
}

输出：

a: 4294967295
b: 4294967293
Incorrect (overflow and wrapping): 2147483646
Correct: 4294967294

std::midpoint('2', '4'): '3'
std::midpoint('2', '5'): '3'
std::midpoint('5', '2'): '4'
std::midpoint('2', '6'): '4'

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 25.10.15 Midpoint [numeric.ops.midpoint]

参阅

lerp
(C++20)
 线性插值函数
(函数)


std::popcount

< cpp‎ | numeric
定义于头文件 <bit> |
template<class T> constexpr int popcount(T x) noexcept; | (C++20 起)

返回 x 的值中为 1 的位的数量。

此重载仅若 T 为无符号整数类型（即 unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 、 unsigned long long 或扩展无符号整数类型）才参与重载决议。

参数

x - 无符号整数类型的值

返回值

x 的值中为 1 的位的数量。

示例

#include <bit>
#include <bitset>
#include <cstdint>
#include <initializer_list>
#include <iostream>

int main()
{
    for (std::uint8_t i : { 0, 0b11111111, 0b00011101 }) {
        std::cout << "popcount(0b" << std::bitset<8>(i) << ") = "
                  << std::popcount(i) << '\n';
    }
}

输出：

popcount(0b00000000) = 0
popcount(0b11111111) = 8
popcount(0b00011101) = 4

参阅

countl_zero (C++20) | 从最高位起计量连续的 0 位的数量 (函数模板)
countl_one (C++20) | 从最高位起计量连续的 1 位的数量 (函数模板)
countr_zero (C++20) | 从最低位起计量连续的 0 位的数量 (函数模板)
countr_one (C++20) | 从最低位起计量连续的 1 位的数量 (函数模板)
has_single_bit (C++20) | 检查一个数是否为二的整数次幂 (函数模板)
count | 返回设置为 true 的位的数量 (std::bitset<N> 的公开成员函数)
allanynone (C++11) | 检查是否所有、任一或无位被设为 true (std::bitset<N> 的公开成员函数)


伪随机数生成

< cpp‎ | numeric

随机数库提供生成随机和伪随机数的类。这些类包括：

  • 均匀随机位生成器 (URBG) ，包含随机数引擎，它们是伪随机数生成器，生成拥有均匀分布整数序列的伪随机数生成器，以及真随机数生成器，若可用。
  • 随机数分布（例如均匀、正态或泊松分布），它们将 URBG 的输出转换为各种统计分布。

URBG 和分布被设计为相互使用以生成随机值。所有随机数引擎都可以指定地播种、序列化和反序列化，以用于可重复的模拟器。

均匀随机位生成器

均匀随机位生成器是函数对象，它返回无符号整数值，并使得每个值在可能结果的范围中拥有（理想上）相等的被返回概率。

所有均匀随机位生成器都满足均匀随机位生成器 (UniformRandomBitGenerator) 要求。 C++20 亦定义 uniform_random_bit_generator 概念。

定义于头文件 <random>
uniform_random_bit_generator
(C++20)
 指定类型具备作为均匀随机位生成器的资格
(概念)

随机数引擎

随机数引擎以种子数据为熵源生成伪随机数。数种不同类的伪随机数生成算法实现为能定制的模板。

选择使用何种引擎涉及到多次权衡：线性同余引擎一般地快，并对状态的存储要求非常小。延迟斐波那契生成器在无先进算术指令集的处理器上非常快，但状态存储较为庞大，有时有不太想要的谱特性。梅森缠绕器较慢且拥有较大的状态存储要求，但只要有正确的参数，就会有最长的的不可重复序列，且拥有最想要的谱特性（对于给定的想要的定义）。

定义于头文件 <random>
linear_congruential_engine (C++11) | 实现线性同余算法 (类模板)
mersenne_twister_engine (C++11) | 实现梅森缠绕器算法 (类模板)
subtract_with_carry_engine (C++11) | 实现带进位减（一种延迟斐波那契）算法 (类模板)

随机数引擎适配器

随机数引擎适配器生成以另一随机数引擎为熵源的伪随机数。它们通常用于改换底层引擎的谱特性。

定义于头文件 <random>
discard_block_engine (C++11) | 舍弃随机数引擎的某些输出 (类模板)
independent_bits_engine (C++11) | 将一个随机数引擎的输出打包为指定位数的块 (类模板)
shuffle_order_engine (C++11) | 以不同顺序发送一个随机数引擎的输出 (类模板)

预定义随机数生成器

定义了数个特别的流行算法。

定义于头文件 <random>
类型 | 定义
minstd_rand0(C++11) | std::linear_congruential_engine < std::uint_fast32_t, 16807, 0, 2147483647> 由 Lewis、Goodman 及 Miller 发现于 1969，由 Park 与 Miller 于 1988 采纳为“最小标准”
minstd_rand(C++11) | std::linear_congruential_engine < std::uint_fast32_t, 48271, 0, 2147483647> 较新的“最小标准”，为 Park、 Miller 及 Stockmeyer 于 1993 推荐
mt19937(C++11) | std::mersenne_twister_engine < std::uint_fast32_t, 32, 624, 397, 31, 0x9908b0df, 11, 0xffffffff, 7, 0x9d2c5680, 15, 0xefc60000, 18, 1812433253> 32 位梅森缠绕器，由松本与西村设计于 1998
mt19937_64(C++11) | std::mersenne_twister_engine < std::uint_fast64_t, 64, 312, 156, 31, 0xb5026f5aa96619e9, 29, 0x5555555555555555, 17, 0x71d67fffeda60000, 37, 0xfff7eee000000000, 43, 6364136223846793005> 64 位梅森缠绕器，由松本与西村设计于 2000
ranlux24_base(C++11) | std::subtract_with_carry_engine < std::uint_fast32_t, 24, 10, 24>
ranlux48_base(C++11) | std::subtract_with_carry_engine < std::uint_fast64_t, 48, 5, 12>
ranlux24(C++11) | std::discard_block_engine < std::ranlux24_base, 223, 23> 24 位 RANLUX 生成器，由 Martin Lüscher 与 Fred James 设计于 1994
ranlux48(C++11) | std::discard_block_engine < std::ranlux48_base, 389, 11> 48 位 RANLUX 生成器，由 Martin Lüscher 与 Fred James 设计于 1994
knuth_b(C++11) | std::shuffle_order_engine < std::minstd_rand0, 256>
default_random_engine(C++11) | 实现定义

非确定随机数

std::random_device 是非确定的均匀随机位生成器，尽管若不支持非确定随机数生成，则允许实现用伪随机数引擎实现 std::random_device 。

random_device
(C++11)
 使用硬件熵源的非确定随机数生成器
(类)

随机数分布

随机数分布后处理 URBG 的输出，以使得输出结果按照定义的统计概率密度函数分布。

随机数分布满足随机数分布 (RandomNumberDistribution) 。

定义于头文件 <random>
均匀分布
uniform_int_distribution
(C++11)
 产生在一个范围上均匀分布的整数值
(类模板)
uniform_real_distribution
(C++11)
 产生在一个范围上均匀分布的实数值
(类模板)
伯努利分布
bernoulli_distribution
(C++11)
 产生伯努利分布上的 bool 值。
(类)
binomial_distribution
(C++11)
 产生二项分布上的整数值。
(类模板)
negative_binomial_distribution
(C++11)
 产生负二项分布上的整数值。
(类模板)
geometric_distribution
(C++11)
 产生几何分布上的整数值。
(类模板)
泊松分布
poisson_distribution
(C++11)
 产生泊松分布上的整数值。
(类模板)
exponential_distribution
(C++11)
 产生指数分布上的实数值。
(类模板)
gamma_distribution
(C++11)
 产生 Γ 分布上的实数值
(类模板)
weibull_distribution
(C++11)
 产生威布尔分布上的实数值。
(类模板)
extreme_value_distribution
(C++11)
 产生极值分布上的实数值。
(类模板)
正态分布
normal_distribution
(C++11)
 产生标准正态（高斯）分布上的实数值。
(类模板)
lognormal_distribution
(C++11)
 产生对数正态分布上的实数值。
(类模板)
chi_squared_distribution
(C++11)
 产生 χ2 分布上的实数值。
(类模板)
cauchy_distribution
(C++11)
 产生柯西分布上的实数值。
(类模板)
fisher_f_distribution
(C++11)
 产生费舍尔 F 分布上的实数值。
(类模板)
student_t_distribution
(C++11)
 产生学生 t 分布上的实数值。
(类模板)
采样分布
discrete_distribution
(C++11)
 产生离散分布上的随机整数。
(类模板)
piecewise_constant_distribution
(C++11)
 产生分布在常子区间上的实数值。
(类模板)
piecewise_linear_distribution
(C++11)
 产生分布在定义的子区间上的实数值。
(类模板)

工具

定义于头文件 <random>
generate_canonical (C++11) | 给定精度的均匀分布在 [0, 1) 上的实数值 (函数模板)
seed_seq (C++11) | 通用的偏差消除的混淆种子序列生成器 (类)

C 随机库

除了上述的引擎和分布，来自 C 随机库的函数和常量亦可用，尽管不推荐：

定义于头文件 <cstdlib>
rand | 生成伪随机数 (函数)
srand | 初始化伪随机数生成器 (函数)
RAND_MAX | std::rand 生成的最大可能值 (宏常量)

示例

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <cmath>

int main()
{
    // 以随机值播种，若可能
    std::random_device r;

    // 选择 1 与 6 间的随机数
    std::default_random_engine e1(r());
    std::uniform_int_distribution<int> uniform_dist(1, 6);
    int mean = uniform_dist(e1);
    std::cout << "Randomly-chosen mean: " << mean << '\n';

    // 生成围绕平均值的正态分布
    std::seed_seq seed2{r(), r(), r(), r(), r(), r(), r(), r()};
    std::mt19937 e2(seed2);
    std::normal_distribution<> normal_dist(mean, 2);

    std::map<int, int> hist;
    for (int n = 0; n < 10000; ++n) {
        ++hist[std::round(normal_dist(e2))];
    }
    std::cout << "Normal distribution around " << mean << ":\n";
    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

可能的输出：

Randomly-chosen mean: 4
Normal distribution around 4:
-4
-3
-2
-1
 0 *
 1 ***
 2 ******
 3 ********
 4 *********
 5 ********
 6 ******
 7 ***
 8 *
 9
10
11
12

参阅


RAND_MAX

< cpp‎ | numeric‎ | random
定义于头文件 <cstdlib>
#define RAND_MAX /*implementation defined*/

展开成等于函数 std::rand 返回的最大值的整数常量表达式。此值依赖实现。保证此值至少为 32767 。

参阅

rand | 生成伪随机数 (函数)
srand | 初始化伪随机数生成器 (函数)


std::bernoulli_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
class bernoulli_distribution; | (C++11 起)

根据离散概率函数产生随机布尔值。 true 的概率为

P(b|p) =⎧
⎨
⎩p if b == true
1 − p if b == false

std::bernoulli_distribution 满足随机数分布 (RandomNumberDistribution) 。

成员类型

成员类型 | 定义
result_type | bool
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
p
 返回 p 分布参数（生成 true 的概率）
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    // 1/4 时间给出 "true"
    // 3/4 时间给出 "false"
    std::bernoulli_distribution d(0.25);

    std::map<bool, int> hist;
    for(int n=0; n<10000; ++n) {
        ++hist[d(gen)];
    }
    for(auto p : hist) {
        std::cout << std::boolalpha << std::setw(5) << p.first
                  << ' ' << std::string(p.second/500, '*') << '\n';
    }
}

可能的输出：

false ***************
 true ****

外部链接

Weisstein, Eric W. “伯努利分布。”来自 MathWorld--A Wolfram Web Resource 。


std::bernoulli_distribution::bernoulli_distribution

< cpp‎ | numeric‎ | random‎ | bernoulli distribution
bernoulli_distribution() : bernoulli_distribution(0.5) { } | (1) | (C++11 起)
explicit bernoulli_distribution( double p ); | (2) | (C++11 起)
explicit bernoulli_distribution( const param_type& params ); | (3) | (C++11 起)

构造新对象。 (2) 以 p 为分布参数， (3) 以 params 为分布参数。

参数

p | - | p 分布参数（生成 true 的概率）
params | - | 分布参数集

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::bernoulli_distribution::max

< cpp‎ | numeric‎ | random‎ | bernoulli distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::bernoulli_distribution::min

< cpp‎ | numeric‎ | random‎ | bernoulli distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::bernoulli_distribution::operator()

< cpp‎ | numeric‎ | random‎ | bernoulli distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::bernoulli_distribution)

< cpp‎ | numeric‎ | random‎ | bernoulli distribution

friend bool operator==( const bernoulli_distribution& lhs, const bernoulli_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const bernoulli_distribution& lhs, const bernoulli_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::bernoulli_distribution 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::bernoulli_distribution)

< cpp‎ | numeric‎ | random‎ | bernoulli distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const bernoulli_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

bernoulli_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::bernoulli_distribution 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::bernoulli_distribution::p

< cpp‎ | numeric‎ | random‎ | bernoulli distribution
double p() const; | (C++11 起)

返回构造分布所用的 p 参数。它定义生成 true 的概率。默认值为 0.5 。

参数

（无）

返回值

标识 p 分布参数的浮点值。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::bernoulli_distribution::param

< cpp‎ | numeric‎ | random‎ | bernoulli distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::bernoulli_distribution::reset

< cpp‎ | numeric‎ | random‎ | bernoulli distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::binomial_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class IntType = int > class binomial_distribution; | (C++11 起)

生产随机非负整数值 i ，分布依照离散概率函数：

\(P(i|t,p) = \binom{t}{i} \cdot p^i \cdot (1-p)^{t-i}\)P(i|t,p) =⎛
⎜
⎝t
i⎞
⎟
⎠ · pi
 · (1 − p)t−i

获得的值是 t 次是/否实验序列中的成功次数，每次成功的概率为 p 。

std::binomial_distribution 满足随机数分布 (RandomNumberDistribution) 。

模板形参

IntType - 生成器所生成的结果类型。若它不是 short 、 int 、 long 、 long long 、 unsigned short 、 unsigned int 、 unsigned long 或 unsigned long long 之一则效果未定义。

模板类型

成员类型 | 定义
result_type | IntType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
pt
 返回分布参数
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

每次试验成功概率准确为 0.5 的二项分布的点图，描绘与贾宪三角的关系（此情况下无、 1 、 2 、 3 或全部 4 次试验成功的概率为 1:4:6:4:1 ）

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    // 进行 4 次试验，平均 2 次中成功 1 次
    std::binomial_distribution<> d(4, 0.5);

    std::map<int, int> hist;
    for (int n = 0; n < 10000; ++n) {
        ++hist[d(gen)];
    }
    for (auto p : hist) {
        std::cout << p.first << ' '
                  << std::string(p.second/100, '*') << '\n';
    }
}

可能的输出：

0 ******
1 ************************
2 *************************************
3 *************************
4 ******

外部链接

Weisstein, Eric W. “二项分布。”来自 MathWorld--A Wolfram Web Resource 。


std::binomial_distribution<IntType>::binomial_distribution

< cpp‎ | numeric‎ | random‎ | binomial distribution
binomial_distribution() : binomial_distribution(1) {} | (1) | (C++11 起)
explicit binomial_distribution( IntType t, double p = 0.5 ); | (2) | (C++11 起)
explicit binomial_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。 (2) 以 t 和 p 为分布参数， (3) 以 params 为分布参数。

参数

t | - | t 分布参数（试验次数）
p | - | p 分布参数（试验生成 true 的概率）、
params | - | 分布参数集

注意

要求 0 ≤ p ≤ 1 且 0 ≤ t 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::binomial_distribution<IntType>::max

< cpp‎ | numeric‎ | random‎ | binomial distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::binomial_distribution<IntType>::min

< cpp‎ | numeric‎ | random‎ | binomial distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::binomial_distribution<IntType>::operator()

< cpp‎ | numeric‎ | random‎ | binomial distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::binomial_distribution)

< cpp‎ | numeric‎ | random‎ | binomial distribution

friend bool operator==( const binomial_distribution& lhs, const binomial_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const binomial_distribution& lhs, const binomial_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::binomial_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::binomial_distribution)

< cpp‎ | numeric‎ | random‎ | binomial distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const binomial_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

binomial_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::binomial_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::binomial_distribution<IntType>::param

< cpp‎ | numeric‎ | random‎ | binomial distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::binomial_distribution<IntType>::p, t

< cpp‎ | numeric‎ | random‎ | binomial distribution
double p() const; | (1) | (C++11 起)
IntType t() const; | (2) | (C++11 起)

返回构造分布所用的参数。

1) 返回 p 分布参数。它定义试验生成 true 的概率。默认值为 0.5 。
2) 返回 t 分布参数。它定义试验次数。默认值为 1 。

参数

（无）

返回值

1) p 分布参数。
2) t 分布参数。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::binomial_distribution<IntType>::reset

< cpp‎ | numeric‎ | random‎ | binomial distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::cauchy_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class RealType = double > class cauchy_distribution; | (C++11 起)

产生随机数，服从柯西分布（又称洛伦兹分布）：

\({\small f(x;a,b)={(b\pi{[1+{(\frac{x-a}{b})}^{2}]} })}^{-1}\)f(x; a,b) = ⎛
⎜
⎝bπ ⎡
⎢
⎣1 + ⎛
⎜
⎝
x - a
b
⎞
⎟
⎠2
⎤
⎥
⎦⎞
⎟
⎠-1

std::cauchy_distribution 满足随机数分布 (RandomNumberDistribution) 的所有要求。

模板形参

RealType - 生成器所生成的结果类型。若它不是 float 、 double 或 long double 之一则效果未定义。

成员类型

成员类型 | 定义
result_type(C++11) | RealType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
ab
 返回分布参数
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <random>
#include <vector>

template <int Height = 5, int BarWidth = 1, int Padding = 1, int Offset = 0,
          bool DrawMinMax = true, class Sample>
void draw_vbars(Sample const& s) {
    static_assert((Height > 0) && (BarWidth > 0) && (Padding >= 0) && (Offset >= 0));
    auto cout_n = [](auto const& v, int n) { while (n-- > 0) std::cout << v; };
    const auto [min, max] = std::minmax_element(std::cbegin(s), std::cend(s));
    std::vector<std::div_t> qr;
    for (float e : s) {
        qr.push_back(std::div(std::lerp(0.f, Height*8, (e - *min)/(*max - *min)), 8));
    }
    for (auto h{Height}; h-- > 0 ;) {
        cout_n(' ', Offset);
        for (auto [q, r] : qr) {
            char d[] = "█"; // == { 0xe2, 0x96, 0x88, 0 }
            q < h ? d[0] = ' ', d[1] = '\0' : q == h ? d[2] -= (7 - r) : 0;
            cout_n(d, BarWidth);
            cout_n(' ', Padding);
        }
        if (DrawMinMax && Height > 1)
            h == Height - 1 ? std::cout << "┬ " << *max:
                     h != 0 ? std::cout << "│"
                            : std::cout << "┴ " << *min;
        cout_n('\n', 1);
    }
}

int main() {
    std::random_device rd{};
    std::mt19937 gen{rd()};

    auto cauchy = [&gen](const float x₀, const float 𝛾) {
        std::cauchy_distribution<float> d{ x₀ /* a */, 𝛾 /* b */};

        const int norm = 1'00'00;
        const float cutoff = 0.005f;

        std::map<int, int> hist{};
        for (int n=0; n!=norm; ++n) { ++hist[std::round(d(gen))]; }

        std::vector<float> bars;
        std::vector<int> indices;
        for (const auto [n, p] : hist) {
            if (float x = p * (1.0/norm); cutoff < x) {
                bars.push_back(x);
                indices.push_back(n);
            }
        }

        std::cout << "x₀ = " << x₀ << ", 𝛾 = " << 𝛾 << ":\n";
        draw_vbars<4,3>(bars);
        for (int n : indices) { std::cout << "" << std::setw(2) << n << "  "; }
        std::cout << "\n\n";
    };

    cauchy(/* x₀ = */ -2.0f, /* 𝛾 = */ 0.50f);
    cauchy(/* x₀ = */ +0.0f, /* 𝛾 = */ 1.25f);
}

可能的输出：

x₀ = -2, 𝛾 = 0.5:
                    ███                     ┬ 0.5006
                    ███                     │
                ▂▂▂ ███ ▁▁▁                 │
▁▁▁ ▁▁▁ ▁▁▁ ▃▃▃ ███ ███ ███ ▂▂▂ ▁▁▁ ▁▁▁ ▁▁▁ ┴ 0.0076
-7  -6  -5  -4  -3  -2  -1   0   1   2   3

x₀ = 0, 𝛾 = 1.25:
                                ███                                 ┬ 0.2539
                            ▅▅▅ ███ ▃▃▃                             │
                        ▁▁▁ ███ ███ ███ ▁▁▁                         │
▁▁▁ ▁▁▁ ▁▁▁ ▁▁▁ ▃▃▃ ▅▅▅ ███ ███ ███ ███ ███ ▅▅▅ ▃▃▃ ▂▂▂ ▁▁▁ ▁▁▁ ▁▁▁ ┴ 0.0058
-8  -7  -6  -5  -4  -3  -2  -1   0   1   2   3   4   5   6   7   9

外部链接

Weisstein, Eric W. “柯西分布”来自 MathWorld--A Wolfram Web Resource 。


std::cauchy_distribution<RealType>::cauchy_distribution

< cpp‎ | numeric‎ | random‎ | cauchy distribution
cauchy_distribution() : cauchy_distribution(0.0) {} | (1) | (C++11 起)
explicit cauchy_distribution( RealType a, RealType b = 1.0 ); | (2) | (C++11 起)
explicit cauchy_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。 (2) 以 a 和 b 为分布参数。 (3) 以 params 为分布参数。

参数

a | - | a 分布参数（位置）
b | - | b 分布参数（尺度）
params | - | 分布参数集

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::cauchy_distribution<RealType>::max

< cpp‎ | numeric‎ | random‎ | cauchy distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::cauchy_distribution<RealType>::min

< cpp‎ | numeric‎ | random‎ | cauchy distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::cauchy_distribution<RealType>::operator()

< cpp‎ | numeric‎ | random‎ | cauchy distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::cauchy_distribution)

< cpp‎ | numeric‎ | random‎ | cauchy distribution

friend bool operator==( const cauchy_distribution& lhs, const cauchy_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const cauchy_distribution& lhs, const cauchy_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::cauchy_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::cauchy_distribution)

< cpp‎ | numeric‎ | random‎ | cauchy distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const cauchy_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

cauchy_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::cauchy_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::cauchy_distribution<RealType>::param

< cpp‎ | numeric‎ | random‎ | cauchy distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::cauchy_distribution<RealType>::a, b

< cpp‎ | numeric‎ | random‎ | cauchy distribution
RealType a() const; | (1) | (C++11 起)
RealType b() const; | (2) | (C++11 起)

返回构造分布所用的分布参数。

1) 返回 a 参数。它指定峰的位置，又被称为位置参数。默认值为 0.0 。
2) 返回 b 参数。它指定半最大位置半宽（ HWHM ），又被称为尺度参数，默认值为 1.0 。

参数

（无）

返回值

1) a 参数的值。
2) b 参数的值。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)

外部链接

  • 尺度参数来自维基百科。
  • 位置参数来自维基百科。


std::cauchy_distribution<RealType>::reset

< cpp‎ | numeric‎ | random‎ | cauchy distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::chi_squared_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class RealType = double > class chi_squared_distribution; | (C++11 起)

chi_squared_distribution 产生随机数 \(\small x>0\)x>0 ，服从 χ2 分布：

\({\small f(x;n) = }\frac{x^{(n/2)-1}\exp{(-x/2)} }{\Gamma{(n/2)}2^{n/2} }\)f(x;n) =
x(n/2)-1
 e-x/2
Γ(n/2) 2n/2

\(\small\Gamma\)Γ 为 Γ 函数（参阅 std::tgamma ）而 \(\small n\)n 为自由度（默认为 1 ）。

std::chi_squared_distribution 满足随机数分布 (RandomNumberDistribution) 的所有要求。

模板形参

RealType - 生成器所生成的结果类型。若它不是 float 、 double 或 long double 之一则效果未定义。

成员类型

成员类型 | 定义
result_type(C++11) | RealType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
n
(C++11)
 返回自由度（ \(\small n\)n ）分布参数
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <random>
#include <vector>

template <int Height = 5, int BarWidth = 1, int Padding = 1, int Offset = 0,
          bool DrawMinMax = true, class Sample>
void draw_vbars(Sample const& s) {
    static_assert((Height > 0) && (BarWidth > 0) && (Padding >= 0) && (Offset >= 0));
    auto cout_n = [](auto const& v, int n) { while (n-- > 0) std::cout << v; };
    const auto [min, max] = std::minmax_element(std::cbegin(s), std::cend(s));
    std::vector<std::div_t> qr;
    for (float e : s) {
        qr.push_back(std::div(std::lerp(0.f, Height*8, (e - *min)/(*max - *min)), 8));
    }
    for (auto h{Height}; h-- > 0 ;) {
        cout_n(' ', Offset);
        for (auto [q, r] : qr) {
            char d[] = "█"; // == { 0xe2, 0x96, 0x88, 0 }
            q < h ? d[0] = ' ', d[1] = '\0' : q == h ? d[2] -= (7 - r) : 0;
            cout_n(d, BarWidth);
            cout_n(' ', Padding);
        }
        if (DrawMinMax && Height > 1)
            h == Height - 1 ? std::cout << "┬ " << *max:
                     h != 0 ? std::cout << "│"
                            : std::cout << "┴ " << *min;
        cout_n('\n', 1);
    }
}

int main() {
    std::random_device rd{};
    std::mt19937 gen{rd()};

    auto χ² = [&gen](const float dof) {
        std::chi_squared_distribution<float> d{ dof /* n */ };

        const int norm = 1'00'00;
        const float cutoff = 0.002f;

        std::map<int, int> hist{};
        for (int n=0; n!=norm; ++n) { ++hist[std::round(d(gen))]; }

        std::vector<float> bars;
        std::vector<int> indices;
        for (const auto [n, p] : hist) {
            if (float x = p * (1.0/norm); cutoff < x) {
                bars.push_back(x);
                indices.push_back(n);
            }
        }

        std::cout << "dof = " << dof << ":\n";
        draw_vbars<4,3>(bars);
        for (int n : indices) { std::cout << "" << std::setw(2) << n << "  "; }
        std::cout << "\n\n";
    };

    for (float dof : {1.f, 2.f, 3.f, 4.f, 6.f, 9.f}) χ²(dof);
}

可能的输出：

dof = 1:
███                                 ┬ 0.5271
███                                 │
███ ███                             │
███ ███ ▇▇▇ ▃▃▃ ▂▂▂ ▁▁▁ ▁▁▁ ▁▁▁ ▁▁▁ ┴ 0.003
 0   1   2   3   4   5   6   7   8

dof = 2:
    ███                                     ┬ 0.3169
▆▆▆ ███ ▃▃▃                                 │
███ ███ ███ ▄▄▄                             │
███ ███ ███ ███ ▇▇▇ ▄▄▄ ▃▃▃ ▂▂▂ ▁▁▁ ▁▁▁ ▁▁▁ ┴ 0.004
 0   1   2   3   4   5   6   7   8   9  10

dof = 3:
    ███ ▃▃▃                                         ┬ 0.2439
    ███ ███ ▄▄▄                                     │
▃▃▃ ███ ███ ███ ▇▇▇ ▁▁▁                             │
███ ███ ███ ███ ███ ███ ▆▆▆ ▄▄▄ ▃▃▃ ▂▂▂ ▁▁▁ ▁▁▁ ▁▁▁ ┴ 0.0033
 0   1   2   3   4   5   6   7   8   9  10  11  12

dof = 4:
    ▂▂▂ ███ ▃▃▃                                                 ┬ 0.1864
    ███ ███ ███ ███ ▂▂▂                                         │
    ███ ███ ███ ███ ███ ▅▅▅ ▁▁▁                                 │
▅▅▅ ███ ███ ███ ███ ███ ███ ███ ▆▆▆ ▄▄▄ ▃▃▃ ▂▂▂ ▂▂▂ ▁▁▁ ▁▁▁ ▁▁▁ ┴ 0.0026
 0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15

dof = 6:
            ▅▅▅ ▇▇▇ ███ ▂▂▂                                                 ┬ 0.1351
        ▅▅▅ ███ ███ ███ ███ ▇▇▇ ▁▁▁                                         │
    ▁▁▁ ███ ███ ███ ███ ███ ███ ███ ▅▅▅ ▂▂▂                                 │
▁▁▁ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ▅▅▅ ▄▄▄ ▃▃▃ ▂▂▂ ▁▁▁ ▁▁▁ ▁▁▁ ┴ 0.0031
 0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18

dof = 9:
            ▅▅▅ ▇▇▇ ███ ███ ▄▄▄ ▂▂▂                                                 ┬ 0.1044
        ▃▃▃ ███ ███ ███ ███ ███ ███ ▅▅▅ ▁▁▁                                         │
    ▄▄▄ ███ ███ ███ ███ ███ ███ ███ ███ ███ ▆▆▆ ▃▃▃                                 │
▄▄▄ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ▆▆▆ ▄▄▄ ▃▃▃ ▂▂▂ ▁▁▁ ▁▁▁ ▁▁▁ ┴ 0.0034
 2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22

外部链接

  • Weisstein, Eric W. “ Χ2 分布”来自 MathWorld--A Wolfram Web Resource 。
  • χ2 分布来自维基百科。


std::chi_squared_distribution<RealType>::chi_squared_distribution

< cpp‎ | numeric‎ | random‎ | chi squared distribution
chi_squared_distribution() : chi_squared_distribution(1.0) {} | (1) | (C++11 起)
explicit chi_squared_distribution( RealType n ); | (2) | (C++11 起)
explicit chi_squared_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。 (2) 以 n 为分布参数， (3) 以 params 为分布参数。

参数

n | - | n 分布参数（自由度）
params | - | 分布参数集

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::chi_squared_distribution<RealType>::max

< cpp‎ | numeric‎ | random‎ | chi squared distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::chi_squared_distribution<RealType>::min

< cpp‎ | numeric‎ | random‎ | chi squared distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::chi_squared_distribution<RealType>::n

< cpp‎ | numeric‎ | random‎ | chi squared distribution
RealType n() const; | (C++11 起)

返回构造对象所用的 n 参数。它指定分布的自由度。默认值为 1.0 。

参数

（无）

返回值

n 分布参数。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::chi_squared_distribution<RealType>::operator()

< cpp‎ | numeric‎ | random‎ | chi squared distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::chi_squared_distribution)

< cpp‎ | numeric‎ | random‎ | chi squared distribution

friend bool operator==( const chi_squared_distribution& lhs, const chi_squared_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const chi_squared_distribution& lhs, const chi_squared_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::chi_squared_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::chi_squared_distribution)

< cpp‎ | numeric‎ | random‎ | chi squared distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const chi_squared_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

chi_squared_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::chi_squared_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::chi_squared_distribution<RealType>::param

< cpp‎ | numeric‎ | random‎ | chi squared distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::chi_squared_distribution<RealType>::reset

< cpp‎ | numeric‎ | random‎ | chi squared distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::discard_block_engine

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class Engine, std::size_t P, std::size_t R > class discard_block_engine; | (C++11 起)

discard_block_engine 是伪随机数引擎适配器，它忽略基础引擎所产生的一定量数据。生成器只从基础引擎生成的每个 P 大小的块保留 R 个数，舍弃剩余的数。

模板形参

Engine | - | 包装的引擎类型
P | - | 块大小。期待 \(\small{P>0}\)P > 0 。
R | - | 每块的使用数的数量。期待 \(\small{0<R\le P}\)0 < R ≤ P 。
类型要求
- Engine 必须满足随机数引擎 (RandomNumberEngine) 的要求。

成员类型

成员类型 | 定义
result_type(C++11) | Engine::result_type

成员函数

(构造函数)
(C++11)
 构造引擎适配器
(公开成员函数)
seed
(C++11)
 设置底层引擎的状态
(公开成员函数)
base
(C++11)
 返回底层引擎
(公开成员函数)
生成
operator()
(C++11)
 令底层引擎的状态前进并返回生成的值
(公开成员函数)
discard
(C++11)
 令适配器状态前进指定量
(公开成员函数)
特征
min
[静态] (C++11)
 获取底层引擎输出范围中的最小可能值。
(公开静态成员函数)
max
[静态] (C++11)
 获取底层引擎输出范围中最大的可能值。
(公开静态成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较适配器和底层引擎的内部状态 (函数)
operator<<operator>> (C++11) | 在伪随机数引擎适配器上进行流输入和输出 (函数)

成员常量

constexpr size_t block_size [静态] (C++11) | 块大小 P (公开静态成员常量)
constexpr size_t used_block [静态] (C++11) | 每块用的数字数 R (公开静态成员常量)


std::discard_block_engine<Engine,P,R>::base

< cpp‎ | numeric‎ | random‎ | discard block engine

const Engine& base() const noexcept; | (C++11 起)

返回底层引擎

参数

（无）

返回值

底层引擎。


std::discard_block_engine<Engine,P,R>::discard

< cpp‎ | numeric‎ | random‎ | discard block engine

void discard( unsigned long long z ); | (C++11 起)

令内部状态前进 z 次。等价于调用 operator() z 次并舍弃结果。可能令底层引擎的状态前进多于 z 次。

参数

z - 指定令引擎前进次数的整数值

返回值

（无）

异常

不抛出。

参阅

operator()
(C++11)
 令底层引擎的状态前进并返回生成的值
(公开成员函数)


std::discard_block_engine<Engine,P,R>::discard_block_engine

< cpp‎ | numeric‎ | random‎ | discard block engine

discard_block_engine(); | (1) | (C++11 起)
explicit discard_block_engine( result_type s ); | (2) | (C++11 起)
template< class Sseq > explicit discard_block_engine( Sseq& seq ); | (3) | (C++11 起)
explicit discard_block_engine( const Engine& e ); | (4) | (C++11 起)
explicit discard_block_engine( Engine&& e ); | (5) | (C++11 起)

构造新的伪随机数引擎适配器。

1) 默认构造函数。亦默认构造底层引擎。
2) 以 s 构造底层引擎
3) 以种子序列 seq 构造底层引擎。此构造函数仅若 Sseq 满足种子序列 (SeedSequence) 才参与重载决议。特别是若 Sseq 可隐式转换为 result_type 则此构造函数不参与重载决议。
4) 以 e 的副本构造底层引擎。
5) 以 e 移动构造底层引擎。之后 e 保有未指定但合法的状态。

参数

s | - | 用以构造底层引擎的整数值
seq | - | 用以构造底层引擎的种子序列
e | - | 用以初始化的伪随机数引擎


std::discard_block_engine<Engine,P,R>::max

< cpp‎ | numeric‎ | random‎ | discard block engine

static constexpr result_type max(); | (C++11 起)

返回引擎适配器潜在生成的最大值。此值等于 e.max() ，其中 e 是底层引擎。

参数

（无）

返回值

最大的潜在生成值。

复杂度

常数

参阅

min
[静态]
 获取输出范围中的最小可能值
(公开静态成员函数)


std::discard_block_engine<Engine,P,R>::min

< cpp‎ | numeric‎ | random‎ | discard block engine

static constexpr result_type min(); | (C++11 起)

返回引擎适配器潜在生成的最小值。此值等于 e.min() ，其中 e 是底层引擎。

参数

（无）

返回值

最小的潜在生成值。

复杂度

常数

参阅

max
[静态]
 获取输出范围中的最大可能值
(公开静态成员函数)


std::discard_block_engine<Engine,P,R>::operator()

< cpp‎ | numeric‎ | random‎ | discard block engine

result_type operator()(); | (C++11 起)

生成随机值。令底层引擎状态前进一或多次。

参数

（无）

返回值

[min(), max()] 中的伪随机数。

异常

不抛出。

参阅

discard
(C++11)
 令适配器状态前进指定量
(公开成员函数)


operator==,!=(std::discard_block_engine)

< cpp‎ | numeric‎ | random‎ | discard block engine

friend bool operator==( const discard_block_engine& lhs, const discard_block_engine& rhs ); | (1) | (C++11 起)
friend bool operator!=( const discard_block_engine& lhs, const discard_block_engine& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个随机数引擎适配器。若二个适配器的底层引擎相等，且其内部状态（若存在）相等，即若它们会对任何数量的 operator() 调用产生等价的值，则它们相等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::discard_block_engine<Engine,p,r> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的引擎适配器

返回值

1) 若引擎适配器等价则为 true ，否则为 false 。
2) 若引擎适配器不等价则为 true ，否则为 false 。

异常

不抛出。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::discard_block_engine)

< cpp‎ | numeric‎ | random‎ | discard block engine

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

discard_block_engine<>& e );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

discard_block_engine& e );
 (2) (C++11 起)
1) 序列化伪随机数引擎适配器的内部状态为一或多个空格所分隔的十进制数序列，并将它插入流 ost 。忽略且不影响填充字符和格式化标签。
2) 从序列化表示恢复伪随机数引擎适配器 e 的内部状态，该表示由先前对 operator<< ，以拥有相同的感染本地环境、相同的 CharT 和 Traits 的流调用创建。若不能反序列化输入，则保留 e 不更改并引发 ist 上的 failbit 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::discard_block_engine<Engine,p,r> 为参数的关联类时由实参依赖查找找到。

若用 os << x 写入文本表示并用 is >> y 将它恢复到同一类型的相同或不同对象 y ，则 x==y 。

本节未完成
原因：标准还定义了文本表示的组成内容

参数

ost | - | 要插入数据的输出流
ist | - | 要提取数据的输入流
e | - | 要序列化或恢复的引擎适配器

返回值

1) ost
2) ist

复杂度

本节未完成

异常

1) 可能抛出实现定义的异常。
2) 设置了 failbit 时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::discard_block_engine<Engine,P,R>::seed

< cpp‎ | numeric‎ | random‎ | discard block engine

void seed(); | (1) | (C++11 起)
void seed( result_type value ); | (2) | (C++11 起)
template< class Sseq > void seed( Sseq& seq ); | (3) | (C++11 起)

用新的种子值重初始化底层引擎的内部状态。

1) 以默认种子值播种底层引擎。等效地调用 e.seed() ，其中 e 是底层引擎。
2) 以种子值 s 播种底层引擎。等效地调用 e.seed(value) ，其中 e 是底层引擎。
3) 以种子序列 seq 播种底层引擎。等效地调用 e.seed(seq) ，其中 e 是底层引擎。此模板仅若 Sseq 符合种子序列 (SeedSequence) 才参与重载决议。特别是若 Sseq 可隐式转换为 result_type 则此模板不参与重载决议。

参数

value | - | 用于初始化底层引擎内部状态的种子值
seq | - | 用于初始化底层引擎内部状态的种子序列

返回值

（无）

异常

不抛出。


std::discrete_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class IntType = int > class discrete_distribution; | (C++11 起)

std::discrete_distribution 产生区间 [0, n) 上的随机整数，其中每个单独整数 i 的概率定义为 w
i/S ，即第 i 个整数的权重除以所有 n 个权重的和。

std::discrete_distribution 满足随机数分布 (RandomNumberDistribution) 的所有要求。

模板形参

IntType - 生成器所生成的结果类型。若它不是 short 、 int 、 long 、 long long 、 unsigned short 、 unsigned int 、 unsigned long 或 unsigned long long 之一则效果未定义。

成员类型

成员类型 | 定义
result_type | IntType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
probabilities
 获得概率列表
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <iostream>
#include <map>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::discrete_distribution<> d({40, 10, 10, 40});
    std::map<int, int> m;
    for(int n=0; n<10000; ++n) {
        ++m[d(gen)];
    }
    for(auto p : m) {
        std::cout << p.first << " generated " << p.second << " times\n";
    }
}

输出：

0 generated 4028 times
1 generated 978 times
2 generated 1012 times
3 generated 3982 times


std::discrete_distribution<IntType>::discrete_distribution

< cpp‎ | numeric‎ | random‎ | discrete distribution
discrete_distribution();
 (1) (C++11 起)
template< class InputIt >
discrete_distribution( InputIt first, InputIt last );
 (2) (C++11 起)
discrete_distribution( std::initializer_list <double> weights );
 (3) (C++11 起)
template< class UnaryOperation >

discrete_distribution( std::size_t count, double xmin, double xmax,

UnaryOperation unary_op );
 (4) (C++11 起)
explicit discrete_distribution( const param_type& params );
 (5) (C++11 起)

构造新的分布对象。

1) 默认分布函数。构造拥有单个权重 p={1} 的分布。此分布始终生成 ​0​ 。

2) 构造拥有范围 [first, last) 中权重的分布。若 first == last ，则效果同默认构造函数。

3) 构造拥有 weights 中权重的分布。等效地调用 discrete_distribution(weights.begin(), weights.end()) 。

4) 构造拥有以函数 unary_op 生成的 count 个权重的分布。每个权重等于 w
i = unary_op(xmin + δ/2 + i · δ) ，其中 δ =
(xmax − xmin)
count
而 i ∈ {0, ..., count−1} 。 xmin 与 xmax 必须使得 δ > 0 。若 count == 0 ，则效果同默认构造函数。

5) 以 params 为分布参数构造分布。

参数

first, last | - | 定义用作权重的数的元素范围。 InputIterator 所指的元素类型必须可转换为 double
weights | - | 含权重的 initializer_list
unary_op | - | 将要应用的一元算符函数。 函数签名应等价于如下者： Ret fun(const Type &a); 签名不必有 const & 。 类型 Type 必须使得 double 类型对象能在解引用后隐式转换到 Type 。 类型 Ret 必须使得 double 类型对象能被解引用并能被赋 Ret 类型值。 ​
params | - | 分布参数集
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。


std::discrete_distribution<IntType>::max

< cpp‎ | numeric‎ | random‎ | discrete distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::discrete_distribution<IntType>::min

< cpp‎ | numeric‎ | random‎ | discrete distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::discrete_distribution<IntType>::operator()

< cpp‎ | numeric‎ | random‎ | discrete distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::discrete_distribution)

< cpp‎ | numeric‎ | random‎ | discrete distribution

friend bool operator==( const discrete_distribution& lhs, const discrete_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const discrete_distribution& lhs, const discrete_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::discrete_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::discrete_distribution)

< cpp‎ | numeric‎ | random‎ | discrete distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const discrete_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

discrete_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::discrete_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::discrete_distribution<IntType>::param

< cpp‎ | numeric‎ | random‎ | discrete distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::discrete_distribution<IntType>::probabilities

< cpp‎ | numeric‎ | random‎ | discrete distribution
std::vector <double> probabilities() const; | (C++11 起)

获得含此分布所生成的每个整数的单独概率的 std::vector <double> 。

参数

（无）

返回值

std::vector <double> 类型对象。

示例

#include <iostream>
#include <vector>
#include <random>
int main()
{
    std::discrete_distribution<> d({40, 10, 10, 40});
    std::vector<double> p = d.probabilities();
    for(auto n : p)
        std::cout << n << ' ';
    std::cout << '\n';
}

输出：

0.4 0.1 0.1 0.4


std::discrete_distribution<IntType>::reset

< cpp‎ | numeric‎ | random‎ | discrete distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::exponential_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class RealType = double > class exponential_distribution; | (C++11 起)

产生随机浮点值 \(\small x\)x ，分布服从概率密度函数：

\(\small P(x|\lambda) = \lambda e^{-\lambda x}\)P(x|λ) = λe-λx

若随机事件以常数频率 \(\small\lambda\)λ 于每个时间/距离单位发生，则获得的值为直至下次随机事件的时间/距离。例如，此分布描述盖革计数器的点击间的时间，或 DNA 链中变异点间的距离。

这是 std::geometric_distribution 的连续对应。

std::exponential_distribution 满足随机数分布 (RandomNumberDistribution) 。

模板形参

RealType - 生成器所生成的结果类型。若它不是 float 、 double 或 long double 之一则效果未定义。

成员类型

成员类型 | 定义
result_type(C++11) | RealType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
lambda
 返回 lambda 分布参数（事件频率）
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

注解

若 RealType 为 float ，则一些实现有时会返回无穷大。此为 LWG 问题 2524 。

示例

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());

    // 若粒子平均每秒衰变一次，
    // 则到下个衰变前要多少秒的时间？
    std::exponential_distribution<> d(1);

    std::map<int, int> hist;
    for(int n=0; n<10000; ++n) {
        ++hist[2*d(gen)];
    }
    for(auto p : hist) {
        std::cout << std::fixed << std::setprecision(1)
                  << p.first/2.0 << '-' << (p.first+1)/2.0 <<
                ' ' << std::string(p.second/200, '*') << '\n';
    }
}

可能的输出：

0.0-0.5 *******************
0.5-1.0 ***********
1.0-1.5 *******
1.5-2.0 ****
2.0-2.5 **
2.5-3.0 *
3.0-3.5
3.5-4.0

外部链接

Weisstein, Eric W. “指数分布。”来自 MathWorld--A Wolfram Web Resource 。


std::exponential_distribution<RealType>::exponential_distribution

< cpp‎ | numeric‎ | random‎ | exponential distribution
exponential_distribution() : exponential_distribution(1.0) {} | (1) | (C++11 起)
explicit exponential_distribution( RealType lambda ); | (2) | (C++11 起)
explicit exponential_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。 (2) 以 lambda 为分布参数。 (3) 以 params 为分布参数。

参数

lambda | - | λ 分布参数（频率参数）
params | - | 分布参数集

注意

要求 0 < lambda 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::exponential_distribution<RealType>::lambda

< cpp‎ | numeric‎ | random‎ | exponential distribution
RealType lambda() const; | (C++11 起)

返回构造分布所用的 λ 分布参数。该参数定义每单位事件发生率。默认值为 1.0 。

参数

（无）

返回值

标识每单位事件发生率的浮点值。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::exponential_distribution<RealType>::max

< cpp‎ | numeric‎ | random‎ | exponential distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::exponential_distribution<RealType>::min

< cpp‎ | numeric‎ | random‎ | exponential distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::exponential_distribution<RealType>::operator()

< cpp‎ | numeric‎ | random‎ | exponential distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::exponential_distribution)

< cpp‎ | numeric‎ | random‎ | exponential distribution

friend bool operator==( const exponential_distribution& lhs, const exponential_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const exponential_distribution& lhs, const exponential_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::exponential_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::exponential_distribution)

< cpp‎ | numeric‎ | random‎ | exponential distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const exponential_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

exponential_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::exponential_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::exponential_distribution<RealType>::param

< cpp‎ | numeric‎ | random‎ | exponential distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::exponential_distribution<RealType>::reset

< cpp‎ | numeric‎ | random‎ | exponential distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::extreme_value_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class RealType = double > class extreme_value_distribution; | (C++11 起)

生成服从极值分布（又称为耿贝尔 I 型、对数威布尔、费舍尔蒂皮特 II 型）的随机数：

\({\small p(x;a,b) = \frac{1}{b} \exp{(\frac{a-x}{b}-\exp{(\frac{a-x}{b})})} }\)p(x;a,b) =
1
b
exp⎛
⎜
⎝
a-x
b
- exp⎛
⎜
⎝
a-x
b
⎞
⎟
⎠⎞
⎟
⎠

std::extreme_value_distribution满足随机数分布 (RandomNumberDistribution) 的所有要求。

模板形参

RealType - 生成器所生成的结果类型。若它不是 float 、 double 或 long double 之一则效果未定义。

成员类型

成员类型 | 定义
result_type | RealType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
ab
 返回分布参数
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <random>
#include <vector>

template<int Height = 5, int BarWidth = 1, int Padding = 1, int Offset = 0,
         bool MinMax = true, class S>
void draw_vbars(S const& s)
{
    static_assert((Height > 0) && (BarWidth > 0) && (Padding >= 0) && (Offset >= 0));

    const auto repeat_cout = [](auto const& v, int n)
    {
        while (n-- > 0)
            std::cout << v;
    };

    const auto [min, max] = std::minmax_element(std::cbegin(s), std::cend(s));
    std::vector<std::div_t> qr;
    for (float e : s) {
        qr.push_back(std::div(std::lerp(0.f, Height * 8 , (e - *min) / (*max - *min)), 8));
    }
    for (auto h{Height}; h-- > 0 ;) {
        repeat_cout(' ', Offset);
        for (auto [q, r] : qr) {
            char d[] = "█"; // == { 0xe2, 0x96, 0x88, 0 }
            if (q < h) {
                repeat_cout(' ', BarWidth);
            } else {
                if (q == h) {
                    d[2] -= (7 - r);
                }
                repeat_cout(d, BarWidth);
            }
            repeat_cout(' ', Padding);
        }
        if (MinMax && Height > 1) {
            std::cout << "│";
            if (h == Height - 1) std::cout << " " << *max;
            else if (h == 0) std::cout << " " << *min;
        }
        std::cout << '\n';
    }
}

int main()
{
    std::random_device rd{};
    std::mt19937 gen{rd()};

    std::extreme_value_distribution<> d{-1.618f, 1.618f};

    const int norm = 10'000;
    const float cutoff = 0.000'3f;

    std::map<int, int> hist{};
    for(int n=0; n<norm; ++n) {
        ++hist[std::round(d(gen))];
    }

    std::vector<float> bars;
    std::vector<int> indices;
    for(const auto [n,p] : hist) {
        float x = p*(1.0f/norm);
        if (x > cutoff) {
            bars.push_back(x);
            indices.push_back(n);
        }
    }

    draw_vbars<8,4>(bars);

    for (int n : indices) {
        std::cout << " " << std::setw(2) << n << "  ";
    }
    std::cout << '\n';
}

可能的输出：

               ████ ▂▂▂▂                                                        │ 0.2227
               ████ ████                                                        │
               ████ ████ ▆▆▆▆                                                   │
          ████ ████ ████ ████                                                   │
          ████ ████ ████ ████ ▅▅▅▅                                              │
          ████ ████ ████ ████ ████ ▂▂▂▂                                         │
     ▄▄▄▄ ████ ████ ████ ████ ████ ████ ▂▂▂▂                                    │
▁▁▁▁ ████ ████ ████ ████ ████ ████ ████ ████ ▆▆▆▆ ▃▃▃▃ ▂▂▂▂ ▁▁▁▁ ▁▁▁▁ ▁▁▁▁ ▁▁▁▁ │ 0.0006

 -5   -4   -3   -2   -1    0    1    2    3    4    5    6    7    8    9   10

外部链接

Weisstein, Eric W. “极值分布”来自 MathWorld--A Wolfram Web Resource 。


std::extreme_value_distribution<RealType>::extreme_value_distribution

< cpp‎ | numeric‎ | random‎ | extreme value distribution
extreme_value_distribution() : extreme_value_distribution(0.0) {} | (1) | (C++11 起)
explicit extreme_value_distribution( RealType a, RealType b = 1.0 ); | (2) | (C++11 起)
explicit extreme_value_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。 (2) 以 a 和 b 为分布参数。 (3) 以 params 为分布参数。

参数

a | - | a 分布参数（位置）
b | - | b 分布参数（尺度）
params | - | 分布参数集

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::extreme_value_distribution<RealType>::max

< cpp‎ | numeric‎ | random‎ | extreme value distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::extreme_value_distribution<RealType>::min

< cpp‎ | numeric‎ | random‎ | extreme value distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::extreme_value_distribution<RealType>::operator()

< cpp‎ | numeric‎ | random‎ | extreme value distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::extreme_value_distribution)

< cpp‎ | numeric‎ | random‎ | extreme value distribution

friend bool operator==( const extreme_value_distribution& lhs, const extreme_value_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const extreme_value_distribution& lhs, const extreme_value_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::extreme_value_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::extreme_value_distribution)

< cpp‎ | numeric‎ | random‎ | extreme value distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const extreme_value_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

extreme_value_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::extreme_value_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::extreme_value_distribution<RealType>::param

< cpp‎ | numeric‎ | random‎ | extreme value distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::extreme_value_distribution<RealType>::a, b

< cpp‎ | numeric‎ | random‎ | extreme value distribution
RealType a() const; | (1) | (C++11 起)
RealType b() const; | (2) | (C++11 起)

返回构造分布所用的参数。

1) 返回 a 分布参数（位置）。默认值为 1.0 。
2) 返回 b 分布参数（尺度）。默认值为 0.0 。

参数

（无）

返回值

1) a 分布参数（位置）。
2) b 分布参数（尺度）。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::extreme_value_distribution<RealType>::reset

< cpp‎ | numeric‎ | random‎ | extreme value distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::fisher_f_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class RealType = double > class fisher_f_distribution; | (C++11 起)

产生随机数，服从 F 分布：

\(P(x;m,n)=\frac{\Gamma{(\frac{m+n}{2})} }{\Gamma{(\frac{m}{2})}\Gamma{(\frac{n}{2})} }{(\frac{m}{n})}^{\frac{m}{2} }x^{\frac{m}{2}-1}{(1+\frac{m}{n}x)}^{-\frac{m+n}{2} }\)P(x;m,n) =
Γ((m+n)/2)
Γ(m/2) Γ(n/2)
(m/n)m/2
 x(m/2)-1
 (1+
mx
n
)-(m+n)/2

\(\small m\)m 和 \(\small n\)n 是自由度。

std::fisher_f_distribution 满足随机数分布 (RandomNumberDistribution) 的所有要求。

模板形参

RealType - 生成器所生成的结果类型。若它不是 float 、 double 或 long double 之一则效果未定义。

成员类型

成员类型 | 定义
result_type(C++11) | RealType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
mn
 返回分布参数
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <random>
#include <vector>

template <int Height = 5, int BarWidth = 1, int Padding = 1, int Offset = 0,
          bool DrawMinMax = true, class Sample>
void draw_vbars(Sample const& s) {
    static_assert((Height > 0) && (BarWidth > 0) && (Padding >= 0) && (Offset >= 0));
    auto cout_n = [](auto const& v, int n) { while (n-- > 0) std::cout << v; };
    const auto [min, max] = std::minmax_element(std::cbegin(s), std::cend(s));
    std::vector<std::div_t> qr;
    for (float e : s) {
        qr.push_back(std::div(std::lerp(0.f, Height*8, (e - *min)/(*max - *min)), 8));
    }
    for (auto h{Height}; h-- > 0 ;) {
        cout_n(' ', Offset);
        for (auto [q, r] : qr) {
            char d[] = "█"; // == { 0xe2, 0x96, 0x88, 0 }
            q < h ? d[0] = ' ', d[1] = '\0' : q == h ? d[2] -= (7 - r) : 0;
            cout_n(d, BarWidth);
            cout_n(' ', Padding);
        }
        if (DrawMinMax && Height > 1)
            h == Height - 1 ? std::cout << "┬ " << *max:
                     h != 0 ? std::cout << "│"
                            : std::cout << "┴ " << *min;
        cout_n('\n', 1);
    }
}

int main() {
    std::random_device rd{};
    std::mt19937 gen{rd()};

    auto fisher = [&gen](const float d₁, const float d₂) {
        std::fisher_f_distribution<float> d{ d₁ /* m */, d₂ /* n */};

        const int norm = 1'00'00;
        const float cutoff = 0.002f;

        std::map<int, int> hist{};
        for (int n=0; n!=norm; ++n) { ++hist[std::round(d(gen))]; }

        std::vector<float> bars;
        std::vector<int> indices;
        for (const auto [n, p] : hist) {
            if (float x = p * (1.0/norm); cutoff < x) {
                bars.push_back(x);
                indices.push_back(n);
            }
        }

        std::cout << "d₁ = " << d₁ << ", d₂ = " << d₂ << ":\n";
        draw_vbars<4,3>(bars);
        for (int n : indices) { std::cout << "" << std::setw(2) << n << "  "; }
        std::cout << "\n\n";
    };

    fisher(/* d₁ = */ 1.0f, /* d₂ = */ 5.0f);
    fisher(/* d₁ = */ 15.0f, /* d₂ = */ 10.f);
    fisher(/* d₁ = */ 100.0f, /* d₂ = */ 3.0f);
}

可能的输出：

d₁ = 1, d₂ = 5:
███                                                     ┬ 0.4956
███                                                     │
███ ▇▇▇                                                 │
███ ███ ▇▇▇ ▄▄▄ ▂▂▂ ▂▂▂ ▁▁▁ ▁▁▁ ▁▁▁ ▁▁▁ ▁▁▁ ▁▁▁ ▁▁▁ ▁▁▁ ┴ 0.0021
 0   1   2   3   4   5   6   7   8   9  10  11  12  14

d₁ = 15, d₂ = 10:
    ███                     ┬ 0.6252
    ███                     │
    ███ ▂▂▂                 │
▆▆▆ ███ ███ ▃▃▃ ▁▁▁ ▁▁▁ ▁▁▁ ┴ 0.0023
 0   1   2   3   4   5   6

d₁ = 100, d₂ = 3:
    ███                                                             ┬ 0.4589
    ███                                                             │
▁▁▁ ███ ▅▅▅                                                         │
███ ███ ███ ▆▆▆ ▃▃▃ ▂▂▂ ▂▂▂ ▁▁▁ ▁▁▁ ▁▁▁ ▁▁▁ ▁▁▁ ▁▁▁ ▁▁▁ ▁▁▁ ▁▁▁ ▁▁▁ ┴ 0.0021
 0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16

外部链接

Weisstein, Eric W. “ F 分布”来自 MathWorld--A Wolfram Web Resource 。


std::fisher_f_distribution<RealType>::fisher_f_distribution

< cpp‎ | numeric‎ | random‎ | fisher f distribution
fisher_f_distribution() : fisher_f_distribution(1.0) {} | (1) | (C++11 起)
explicit fisher_f_distribution( RealType m, RealType n = 1.0 ); | (2) | (C++11 起)
explicit fisher_f_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。 (2) 以 m 和 n 为分布参数， (3) 以 params 为分布参数。

参数

m | - | m 分布参数（自由度）
n | - | n 分布参数（自由度）
params | - | 分布参数集

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::fisher_f_distribution<RealType>::max

< cpp‎ | numeric‎ | random‎ | fisher f distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::fisher_f_distribution<RealType>::min

< cpp‎ | numeric‎ | random‎ | fisher f distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::fisher_f_distribution<RealType>::operator()

< cpp‎ | numeric‎ | random‎ | fisher f distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::fisher_f_distribution)

< cpp‎ | numeric‎ | random‎ | fisher f distribution

friend bool operator==( const fisher_f_distribution& lhs, const fisher_f_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const fisher_f_distribution& lhs, const fisher_f_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::fisher_f_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::fisher_f_distribution)

< cpp‎ | numeric‎ | random‎ | fisher f distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const fisher_f_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

fisher_f_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::fisher_f_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::fisher_f_distribution<RealType>::param

< cpp‎ | numeric‎ | random‎ | fisher f distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::fisher_f_distribution<RealType>::m, n

< cpp‎ | numeric‎ | random‎ | fisher f distribution
RealType m() const; | (1) | (C++11 起)
RealType n() const; | (2) | (C++11 起)

返回构造分布所用的参数。

1) 返回 m （第一自由度）分布参数。默认值为 1.0 。
2) 返回 n （第二自由度）分布参数。默认值为 1.0 。

参数

（无）

返回值

1) m （第一自由度）分布参数。
2) n （第二自由度）分布参数。

复杂度

常数。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::fisher_f_distribution<RealType>::reset

< cpp‎ | numeric‎ | random‎ | fisher f distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::gamma_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class RealType = double > class gamma_distribution; | (C++11 起)

产生随机正浮点数 x ，分布服从概率密度函数：

\(\mathsf{p}(x\mid\alpha,\beta) = \frac{e^{-x/\beta} }{\beta^\alpha\cdot\Gamma(\alpha)}\cdot x^{\alpha-1} \)P(x|α,β) =
e-x/β
βα
 · Γ(α)
· xα-1

其中 α 被称为形状参数而 β 被称为尺度参数。形状参数有时以字母 k 表示，而尺度参数有时以字母 θ 表示。

对于浮点 α ，获得的值是 α 个独立指数分布的随机变量的和，每个的平均值均为 β 。

std::gamma_distribution 满足随机数分布 (RandomNumberDistribution) 。

模板形参

RealType - 生成器所生成的结果类型。若它不是 float 、 double 或 long double 之一则效果未定义。

成员类型

成员类型 | 定义
result_type | RealType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
alphabeta
 返回分布参数
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());

    // alpha=1 ， beta=2 的 gamma 分布近似于指数分布。
    std::gamma_distribution<> d(1,2);

    std::map<int, int> hist;
    for(int n=0; n<10000; ++n) {
        ++hist[2*d(gen)];
    }
    for(auto p : hist) {
        std::cout << std::fixed << std::setprecision(1)
                  << p.first/2.0 << '-' << (p.first+1)/2.0 <<
                ' ' << std::string(p.second/200, '*') << '\n';
    }
}

可能的输出：

0.0-0.5 **********
0.5-1.0 ********
1.0-1.5 ******
1.5-2.0 *****
2.0-2.5 ****
2.5-3.0 ***
3.0-3.5 **
3.5-4.0 *
4.0-4.5 *
4.5-5.0 *
5.0-5.5 *
5.5-6.0
6.0-6.5
6.5-7.0
7.0-7.5
7.5-8.0
8.0-8.5
8.5-9.0
9.0-9.5
9.5-10.0
10.0-10.5
10.5-11.0
11.0-11.5
11.5-12.0
12.0-12.5
12.5-13.0
13.0-13.5
13.5-14.0
14.0-14.5
15.0-15.5
15.5-16.0
18.0-18.5
18.5-19.0

外部链接

Weisstein, Eric W. “ Γ 分布。”来自 MathWorld--A Wolfram Web Resource 。


std::gamma_distribution<RealType>::gamma_distribution

< cpp‎ | numeric‎ | random‎ | gamma distribution
gamma_distribution() : gamma_distribution(1.0) {} | (1) | (C++11 起)
explicit gamma_distribution( RealType alpha, RealType beta = 1.0 ); | (2) | (C++11 起)
explicit gamma_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。 (2) 以 alpha 和 beta 为分布参数。 (3) 以 params 为分布参数。

参数

alpha | - | α 分布参数（形状）
beta | - | β 分布参数（尺度）
params | - | 分布参数集

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::gamma_distribution<RealType>::max

< cpp‎ | numeric‎ | random‎ | gamma distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::gamma_distribution<RealType>::min

< cpp‎ | numeric‎ | random‎ | gamma distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::gamma_distribution<RealType>::operator()

< cpp‎ | numeric‎ | random‎ | gamma distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::gamma_distribution)

< cpp‎ | numeric‎ | random‎ | gamma distribution

friend bool operator==( const gamma_distribution& lhs, const gamma_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const gamma_distribution& lhs, const gamma_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::gamma_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::gamma_distribution)

< cpp‎ | numeric‎ | random‎ | gamma distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const gamma_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

gamma_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::gamma_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::gamma_distribution<RealType>::param

< cpp‎ | numeric‎ | random‎ | gamma distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::gamma_distribution<RealType>::alpha, beta

< cpp‎ | numeric‎ | random‎ | gamma distribution
RealType alpha() const; | (1) | (C++11 起)
RealType beta() const; | (2) | (C++11 起)

返回构造分布所用的分布参数。

1) 返回 α 分布参数。它又称为形状参数。默认值为 1.0 。
2) 返回 β 分布参数。它又称为尺度参数。默认值为 1.0 。

参数

（无）

返回值

1) 标识 α 参数的浮点值。
2) 标识 β 参数的浮点值。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::gamma_distribution<RealType>::reset

< cpp‎ | numeric‎ | random‎ | gamma distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::generate_canonical

< cpp‎ | numeric‎ | random
定义于头文件 <random>
template< class RealType, std::size_t Bits, class Generator >
RealType generate_canonical( Generator& g );
 (C++11 起)

生成范围 \(\small [0,1)\)[0, 1) 中的随机浮点值。

为生成足够的熵， generate_canonical() 将准确调用 g() \(\small k\)k 次，其中 \(\small k = \max(1, \lceil \frac{b}{\log_2 R} \rceil)\)k = max(1, ⌈ b / log
2 R ⌉) 且

  • b = std::min (Bits, std::size_t { std::numeric_limits <RealType>::digits}) ，
  • R = g.max() - g.min() + 1 。

参数

g - 用于取得熵的生成器

返回值

范围 \(\small [0,1)\)[0, 1) 中的浮点值。

异常

无，除了 g 所抛者。

注解

一些既存实现拥有漏洞，若 RealType 为 float ，则它们有时可以返回 1.0 GCC #63176 LLVM #18767 MSVC STL #1074 。此为 LWG 问题 2524 。

示例

产生有 10 位随机性的随机数：这仅可能产生 k*R 个相异值

#include <random>
#include <iostream>

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    for(int n = 0; n < 10; ++n) {
        std::cout << std::generate_canonical<double, 10>(gen) << ' ';
    }
}

可能的输出：

0.208143 0.824147 0.0278604 0.343183 0.0173263 0.864057 0.647037 0.539467 0.0583497 0.609219

参阅

uniform_real_distribution
(C++11)
 产生在一个范围上均匀分布的实数值
(类模板)


std::geometric_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class IntType = int > class geometric_distribution; | (C++11 起)

生成随机非负整数值 i ，分布按照离散概率函数：

\(P(i|p) = p \cdot (1-p)^i\)P(i|p) = p · (1 − p)i

该值表示获得单次成功所需的是/否试验（每次以 p 概率成功）次数。

std::geometric_distribution<>(p) 准确等价于 std::negative_binomial_distribution <>(1, p) 。它亦为 std::exponential_distribution 的离散对应版本。

std::geometric_distribution 满足随机数分布 (RandomNumberDistribution) 。

模板形参

IntType - 生成器所生成的结果类型。若它不是 short 、 int 、 long 、 long long 、 unsigned short 、 unsigned int 、 unsigned long 或 unsigned long long 之一则效果未定义。

成员类型

成员类型 | 定义
result_type | IntType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
p
 返回 p 分布参数（试验生成 true 的概率）
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

geometric_distribution<>(0.5) 为默认，并表示获取正面所要求的硬币投掷次数

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());

    std::geometric_distribution<> d; // 同 std::negative_binomial_distribution<> d(1, 0.5);

    std::map<int, int> hist;
    for(int n=0; n<10000; ++n) {
        ++hist[d(gen)];
    }
    for(auto p : hist) {
        std::cout << p.first <<
                ' ' << std::string(p.second/100, '*') << '\n';
    }
}

输出：

0 *************************************************
1 *************************
2 ************
3 ******
4 **
5 *
6
7
8
9
10
11

外部链接

Weisstein, Eric W. “几何分布。”来自 MathWorld--A Wolfram Web Resource 。


std::geometric_distribution<IntType>::geometric_distribution

< cpp‎ | numeric‎ | random‎ | geometric distribution
geometric_distribution() : geometric_distribution(0.5) {} | (1) | (C++11 起)
explicit geometric_distribution( double p ); | (2) | (C++11 起)
explicit geometric_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。 (2) 以 p 为分布参数。 (3) 以 params 为分布参数。

参数

p | - | p 分布参数（试验生成 true 的概率）
params | - | 分布参数集

注意

要求 0 < p < 1 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::geometric_distribution<IntType>::max

< cpp‎ | numeric‎ | random‎ | geometric distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::geometric_distribution<IntType>::min

< cpp‎ | numeric‎ | random‎ | geometric distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::geometric_distribution<IntType>::operator()

< cpp‎ | numeric‎ | random‎ | geometric distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::geometric_distribution)

< cpp‎ | numeric‎ | random‎ | geometric distribution

friend bool operator==( const geometric_distribution& lhs, const geometric_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const geometric_distribution& lhs, const geometric_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::geometric_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::geometric_distribution)

< cpp‎ | numeric‎ | random‎ | geometric distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const geometric_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

geometric_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::geometric_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::geometric_distribution<IntType>::p

< cpp‎ | numeric‎ | random‎ | geometric distribution
double p() const; | (C++11 起)

返回构造分布所用的 p 分布参数。该参数定义试验生成 true 的概率。默认值为 0.5 。

参数

（无）

返回值

标识 p 分布参数的浮点值。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::geometric_distribution<IntType>::param

< cpp‎ | numeric‎ | random‎ | geometric distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::geometric_distribution<IntType>::reset

< cpp‎ | numeric‎ | random‎ | geometric distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::independent_bits_engine

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class Engine, std::size_t W, class UIntType > class independent_bits_engine; | (C++11 起)

independent_bits_engine 是随机数引擎适配器，它产生位数与被包装引擎所产生者不同的随机数。

模板形参

Engine | - | 包装的引擎类型
W | - | 生成数字应有的位数
UIntType | - | 生成的随机数类型。行为未定义，除非形参是无 cv 限定的 unsigned short、 unsigned int、 unsigned long 或 unsigned long long 之一。
类型要求
- Engine 必须满足随机数引擎 (RandomNumberEngine) 的要求。
- W 必须大于零，且不大于 std::numeric_limits <UIntType>::digits 。

成员类型

成员类型 | 定义
result_type | UIntType

成员函数

(构造函数)
(C++11)
 构造引擎适配器
(公开成员函数)
seed
(C++11)
 设置底层引擎的状态
(公开成员函数)
base
(C++11)
 返回底层引擎
(公开成员函数)
生成
operator()
(C++11)
 令底层引擎的状态前进并返回生成的值
(公开成员函数)
discard
(C++11)
 令适配器状态前进指定量
(公开成员函数)
特征
min
[静态] (C++11)
 获取输出范围中的最小可能值（始终为零）。
(公开静态成员函数)
max
[静态] (C++11)
 获取输出范围中最大的可能值（始终为 2w
-1 ）。
(公开静态成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较适配器和底层引擎的内部状态 (函数)
operator<<operator>> (C++11) | 在伪随机数引擎适配器上进行流输入和输出 (函数)


std::independent_bits_engine<Engine,W,UIntType>::base

< cpp‎ | numeric‎ | random‎ | independent bits engine

const Engine& base() const noexcept; | (C++11 起)

返回底层引擎

参数

（无）

返回值

底层引擎。


std::independent_bits_engine<Engine,W,UIntType>::discard

< cpp‎ | numeric‎ | random‎ | independent bits engine

void discard( unsigned long long z ); | (C++11 起)

令内部状态前进 z 次。等价于调用 operator() z 次并舍弃结果。可能令底层引擎的状态前进多于 z 次。

参数

z - 指定令引擎前进次数的整数值

返回值

（无）

异常

不抛出。

参阅

operator()
(C++11)
 令底层引擎的状态前进并返回生成的值
(公开成员函数)


std::independent_bits_engine<Engine,W,UIntType>::independent_bits_engine

< cpp‎ | numeric‎ | random‎ | independent bits engine

independent_bits_engine(); | (1) | (C++11 起)
explicit independent_bits_engine( result_type s ); | (2) | (C++11 起)
template< class Sseq > explicit independent_bits_engine( Sseq& seq ); | (3) | (C++11 起)
explicit independent_bits_engine( const Engine& e ); | (4) | (C++11 起)
explicit independent_bits_engine( Engine&& e ); | (5) | (C++11 起)

构造新的伪随机数引擎适配器。

1) 默认构造函数。亦默认构造底层引擎。
2) 以 s 构造底层引擎
3) 以种子序列 seq 构造底层引擎。此构造函数仅若 Sseq 满足种子序列 (SeedSequence) 才参与重载决议。特别是若 Sseq 可隐式转换为 result_type 则此构造函数不参与重载决议。
4) 以 e 的副本构造底层引擎。
5) 以 e 移动构造底层引擎。之后 e 保有未指定但合法的状态。

参数

s | - | 用以构造底层引擎的整数值
seq | - | 用以构造底层引擎的种子序列
e | - | 用以初始化的伪随机数引擎


std::independent_bits_engine<Engine,W,UIntType>::max

< cpp‎ | numeric‎ | random‎ | independent bits engine

static constexpr result_type max(); | (C++11 起)

返回引擎适配器潜在生成的最大值。此值等于 2w
-1 。

参数

（无）

返回值

最大的潜在生成值。

复杂度

常数

参阅

min
[静态]
 获取输出范围中的最小可能值
(公开静态成员函数)


std::independent_bits_engine<Engine,W,UIntType>::min

< cpp‎ | numeric‎ | random‎ | independent bits engine

static constexpr result_type min(); | (C++11 起)

返回引擎适配器潜在生成的最小值。此值等于 0u 。

参数

（无）

返回值

最小的潜在生成值。

复杂度

常数

参阅

max
[静态]
 获取输出范围中的最大可能值
(公开静态成员函数)


std::independent_bits_engine<Engine,W,UIntType>::operator()

< cpp‎ | numeric‎ | random‎ | independent bits engine

result_type operator()(); | (C++11 起)

生成随机值。令底层引擎状态前进一或多次。

参数

（无）

返回值

[min(), max()] 中的伪随机数。

异常

不抛出。

参阅

discard
(C++11)
 令适配器状态前进指定量
(公开成员函数)


operator==,!=(std::independent_bits_engine)

< cpp‎ | numeric‎ | random‎ | independent bits engine

friend bool operator==( const independent_bits_engine& lhs, const independent_bits_engine& rhs ); | (1) | (C++11 起)
friend bool operator!=( const independent_bits_engine& lhs, const independent_bits_engine& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个随机数引擎适配器。若二个适配器的底层引擎相等，且其内部状态（若存在）相等，即若它们会对任何数量的 operator() 调用产生等价的值，则它们相等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::independent_bits_engine<Engine,w,UIntType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的引擎适配器

返回值

1) 若引擎适配器等价则为 true ，否则为 false 。
2) 若引擎适配器不等价则为 true ，否则为 false 。

异常

不抛出。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::independent_bits_engine)

< cpp‎ | numeric‎ | random‎ | independent bits engine

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

independent_bits_engine<>& e );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

independent_bits_engine& e );
 (2) (C++11 起)
1) 序列化伪随机数引擎适配器的内部状态为一或多个空格所分隔的十进制数序列，并将它插入流 ost 。忽略且不影响填充字符和格式化标签。
2) 从序列化表示恢复伪随机数引擎适配器 e 的内部状态，该表示由先前对 operator<< ，以拥有相同的感染本地环境、相同的 CharT 和 Traits 的流调用创建。若不能反序列化输入，则保留 e 不更改并引发 ist 上的 failbit 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::independent_bits_engine<Engine,w,UIntType> 为参数的关联类时由实参依赖查找找到。

若用 os << x 写入文本表示并用 is >> y 将它恢复到同一类型的相同或不同对象 y ，则 x==y 。

本节未完成
原因：标准还定义了文本表示的组成内容

参数

ost | - | 要插入数据的输出流
ist | - | 要提取数据的输入流
e | - | 要序列化或恢复的引擎适配器

返回值

1) ost
2) ist

复杂度

本节未完成

异常

1) 可能抛出实现定义的异常。
2) 设置了 failbit 时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::independent_bits_engine<Engine,W,UIntType>::seed

< cpp‎ | numeric‎ | random‎ | independent bits engine

void seed(); | (1) | (C++11 起)
void seed( result_type value ); | (2) | (C++11 起)
template< class Sseq > void seed( Sseq& seq ); | (3) | (C++11 起)

用新的种子值重初始化底层引擎的内部状态。

1) 以默认种子值播种底层引擎。等效地调用 e.seed() ，其中 e 是底层引擎。
2) 以种子值 s 播种底层引擎。等效地调用 e.seed(value) ，其中 e 是底层引擎。
3) 以种子序列 seq 播种底层引擎。等效地调用 e.seed(seq) ，其中 e 是底层引擎。此模板仅若 Sseq 符合种子序列 (SeedSequence) 才参与重载决议。特别是若 Sseq 可隐式转换为 result_type 则此模板不参与重载决议。

参数

value | - | 用于初始化底层引擎内部状态的种子值
seq | - | 用于初始化底层引擎内部状态的种子序列

返回值

（无）

异常

不抛出。


std::linear_congruential_engine

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class UIntType, UIntType a, UIntType c, UIntType m > class linear_congruential_engine; | (C++11 起)

linear_congruential_engine 是基于线性同余生成器 (LCG) 的随机数引擎。 LCG 拥有以单个整数构成的状态。

LCG 函数的变换算法是 \(\small{x_{i+1}\leftarrow(a x_i + c)\mod m}\)x
i+1 ← (ax
i+c) mod m 。

下列 typedef 定义有二种常用参数集的随机数引擎：

定义于头文件 <random>
类型 | 定义
minstd_rand0(C++11) | std::linear_congruential_engine< std::uint_fast32_t, 16807, 0, 2147483647> 由 Lewis、Goodman 及 Miller 发现于 1969，由 Park 与 Miller 于 1988 采纳为“最小标准”
minstd_rand(C++11) | std::linear_congruential_engine< std::uint_fast32_t, 48271, 0, 2147483647> 较新的“最小标准”，为 Park、 Miller 及 Stockmeyer 于 1993 推荐

成员类型

成员类型 | 定义
result_type(C++11) | 引擎所生成的整数类型。若此非无符号整数类型则结果未定义。

成员函数

构造与播种
(构造函数)
(C++11)
 构造引擎
(公开成员函数)
seed
(C++11)
 设置引擎的当前状态
(公开成员函数)
生成
operator()
(C++11)
 推进引擎状态并返回生成的值
(公开成员函数)
discard
(C++11)
 令引擎状态前进指定量
(公开成员函数)
特征
min
[静态]
 获取输出范围中的最小可能值
(公开静态成员函数)
max
[静态]
 获取输出范围中的最大可能值
(公开静态成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个伪随机数引擎的内部状态 (函数)
operator<<operator>> (C++11) | 执行伪随机数引擎的流输入和输出 (函数)

成员常量

constexpr UIntType multiplier [静态] (C++11) | 乘数项 (a) 。 (公开静态成员常量)
constexpr UIntType increment [静态] (C++11) | 增量项 (c) 。 (公开静态成员常量)
constexpr UIntType modulus [静态] (C++11) | 模项 (m) 。 (公开静态成员常量)
constexpr UIntType default_seed [静态] (C++11) | 默认种子 (1) 。 (公开静态成员常量)


std::linear_congruential_engine<UIntType,a,c,m>::discard

< cpp‎ | numeric‎ | random‎ | linear congruential engine

void discard( unsigned long long z ); | (C++11 起)

令内部状态前进 z 次。等价于调用 operator() z 次并舍弃结果。

参数

z - 指定状态前进次数的整数值

返回值

（无）

复杂度

本节未完成

注意

对于某些引擎，“快速跳转”算法已知，它们能令状态前进许多步（以百万计）而无需计算中间状态迁移，尽管不需要在常数时间内。

参阅

operator()
(C++11)
 推进引擎状态并返回生成的值
(公开成员函数)


std::linear_congruential_engine<UIntType,a,c,m>::linear_congruential_engine

< cpp‎ | numeric‎ | random‎ | linear congruential engine

linear_congruential_engine() : linear_congruential_engine(default_seed) {} | (1) | (C++11 起)
explicit linear_congruential_engine( result_type value ); | (2) | (C++11 起)
template< class Sseq > explicit linear_congruential_engine( Sseq& s ); | (3) | (C++11 起)
linear_congruential_engine( const linear_congruential_engine& ); | (4) | (C++11 起) (隐式声明)

构造伪随机数引擎。

1) 默认构造函数。以 default_seed 播种引擎。
本节未完成

仅若 Sseq 符合重载种子序列 (SeedSequence) ， (3) 才参与重载决议。尤其是若 Sseq 可转换为 result_type ，则从候选函数集中排除该重载。

参数

value | - | 用于内部状态初始化的种子值
s | - | 用于内部状态初始化的种子序列

复杂度

本节未完成

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式

参阅

seed
(C++11)
 设置引擎的当前状态
(公开成员函数)


std::linear_congruential_engine<UIntType,a,c,m>::max

< cpp‎ | numeric‎ | random‎ | linear congruential engine

static constexpr result_type max(); | (C++11 起)

返回随机数引擎潜在生成的最大值。此值比 modulus 小一。

参数

（无）

返回值

最大潜在生成值。

复杂度

常数

参阅

min
[静态]
 获取输出范围中的最小可能值
(公开静态成员函数)


std::linear_congruential_engine<UIntType,a,c,m>::min

< cpp‎ | numeric‎ | random‎ | linear congruential engine

static constexpr result_type min(); | (C++11 起)

返回随机数引擎潜在生成的最小值。若 increment 为 0u 则此值等于 1u ，否则等于 0u 。

参数

（无）

返回值

最小的潜在生成值。

复杂度

常数

参阅

max
[静态]
 获取输出范围中的最大可能值
(公开静态成员函数)


std::linear_congruential_engine<UIntType,a,c,m>::operator()

< cpp‎ | numeric‎ | random‎ | linear congruential engine

result_type operator()(); | (C++11 起)

生成伪随机数。令引擎状态前进一个位置。

本节未完成

参数

（无）

返回值

[min(), max()] 中的伪随机数。

复杂度

均摊常数。

参阅

discard
(C++11)
 令引擎状态前进指定量
(公开成员函数)


operator==,!=(std::linear_congruential_engine)

< cpp‎ | numeric‎ | random‎ | linear congruential engine

friend bool operator==( const linear_congruential_engine& lhs, const linear_congruential_engine& rhs ); | (1) | (C++11 起)
friend bool operator!=( const linear_congruential_engine& lhs, const linear_congruential_engine& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个伪随机数引擎。若其内部状态等价，即对任何数量的 operator() 调用都会生成相等的值，则二个引擎相等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::linear_congruential_engine<UIntType,a,c,m> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的引擎

返回值

1) 若引擎等价则为 true ，否则为 false 。
2) 若引擎不等价则为 true ，否则为 false 。

异常

不抛出。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::linear_congruential_engine)

< cpp‎ | numeric‎ | random‎ | linear congruential engine

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const linear_congruential_engine& e );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

linear_congruential_engine& e );
 (2) (C++11 起)
1) 序列化伪随机数引擎 e 的内部状态为一或多个空格分隔的十进制数序列，并插入之到流 ost 。填充字符和格式化标志被忽略且无效。
2) 从先前用拥有相同感染的本地环境，和相同 CharT 与 Traits 的流调用 operator<< ，生成的序列化表示还原伪随机数引擎 e 的内部状态。若不能反序列化输入，则保留 e 不改变并在 ist 上引发 failbit 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::linear_congruential_engine<UIntType,a,c,m> 为参数的关联类时由实参依赖查找找到。

若用 os << x 写的文本表示，用 is >> y 还原到同类型的同一或不同对象 y ，则 x==y 。

以设置 os.fmtflags 为 ios_base::dec|ios_base::left 并设置填充字符为空格符写文本表示。引擎内部状态的文本表示是一组空格分隔的十进制数。

参数

ost | - | 要插入数据的输出流
ist | - | 要提取数据的输入流
e | - | 伪随机数引擎

返回值

1) ost
2) ist

复杂度

本节未完成

异常

1) 可能抛出实现定义的异常。
2) 设置了 failbit 时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::linear_congruential_engine<UIntType,a,c,m>::seed

< cpp‎ | numeric‎ | random‎ | linear congruential engine

void seed( result_type value = default_seed ); | (1) | (C++11 起)
template< class Sseq > void seed( Sseq& seq ); | (2) | (C++11 起)

用新种子值重初始化随机数引擎的内部状态。

本节未完成

参数

value | - | 用于内部状态初始化的种子值
seq | - | 用于内部状态初始化的种子序列

异常

不抛出。

复杂度

本节未完成


std::lognormal_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class RealType = double > class lognormal_distribution; | (C++11 起)

lognormal_distribution 随机数分布生成随机数 x > 0 ，服从对数正态分布。

\({\small f(x;m,s) = \frac{1}{sx\sqrt{2\pi} } \exp{(-\frac{ {(\ln{x} - m)}^{2} }{2{s}^{2} })} }\)f(x; m,s) =
1
sx√2 π
exp⎛
⎜
⎝-
(ln x - m)2
2s2
⎞
⎟
⎠

参数 m 和 s 分别为 x 的自然对数的平均数和标准差。

std::lognormal_distribution 满足随机数分布 (RandomNumberDistribution) 的所有要求。

模板形参

RealType - 生成器所生成的结果类型。若它不是 float 、 double 或 long double 之一则效果未定义。

成员类型

成员类型 | 定义
result_type | RealType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
ms
 返回分布参数
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <cmath>
int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());

    std::lognormal_distribution<> d(1.6, 0.25);

    std::map<int, int> hist;
    for(int n=0; n<10000; ++n) {
        ++hist[std::round(d(gen))];
    }
    for(auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

可能的输出：

 2
 3 ***
 4 *************
 5 ***************
 6 *********
 7 ****
 8 *
 9
10
11
12

外部链接

  • Weisstein, Eric W. “对数正态分布”来自 MathWorld--A Wolfram Web Resource 。


std::lognormal_distribution<RealType>::lognormal_distribution

< cpp‎ | numeric‎ | random‎ | lognormal distribution
lognormal_distribution() : lognormal_distribution(0.0) {} | (1) | (C++11 起)
explicit lognormal_distribution( RealType m, RealType s = 1.0 ); | (2) | (C++11 起)
explicit lognormal_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。 (2) 以 m 和 s 为分布参数。 (3) 以 params 为分布参数。

参数

m | - | m 分布参数（对数尺度）
s | - | s 分布参数（形状）
params | - | 分布参数集

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::lognormal_distribution<RealType>::max

< cpp‎ | numeric‎ | random‎ | lognormal distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::lognormal_distribution<RealType>::min

< cpp‎ | numeric‎ | random‎ | lognormal distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::lognormal_distribution<RealType>::operator()

< cpp‎ | numeric‎ | random‎ | lognormal distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::lognormal_distribution)

< cpp‎ | numeric‎ | random‎ | lognormal distribution

friend bool operator==( const lognormal_distribution& lhs, const lognormal_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const lognormal_distribution& lhs, const lognormal_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::lognormal_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::lognormal_distribution)

< cpp‎ | numeric‎ | random‎ | lognormal distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const lognormal_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

lognormal_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::lognormal_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::lognormal_distribution<RealType>::param

< cpp‎ | numeric‎ | random‎ | lognormal distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::lognormal_distribution<RealType>::m, s

< cpp‎ | numeric‎ | random‎ | lognormal distribution
RealType m() const; | (1) | (C++11 起)
RealType s() const; | (2) | (C++11 起)

返回构造分布所用的参数。

1) 返回对数平均 m 分布参数。它定义峰的位置。默认值为 0.0 。
2) 返回对数标准差 s 分布参数。默认值为 1.0 。

参数

（无）

返回值

1) 对数平均 m 分布参数。
2) 对数标准差 s 分布参数。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::lognormal_distribution<RealType>::reset

< cpp‎ | numeric‎ | random‎ | lognormal distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::mersenne_twister_engine

< cpp‎ | numeric‎ | random
定义于头文件 <random>
template<

class UIntType,
std::size_t w, std::size_t n, std::size_t m, std::size_t r,
UIntType a, std::size_t u, UIntType d, std::size_t s,
UIntType b, std::size_t t,
UIntType c, std::size_t l, UIntType f

> class mersenne_twister_engine;
 (C++11 起)

mersenne_twister_engine 是基于梅森缠绕器算法的随机数生成器。它产生高质量 UIntType 类型的区间 \(\small{[0,2^w-1)}\)[0, 2w
-1] 上的无符号整数随机数。

下列类型别名定义拥有二个常用参数集的随机数引擎：

定义于头文件 <random>
类型 | 定义
mt19937(C++11) | std::mersenne_twister_engine< std::uint_fast32_t, 32, 624, 397, 31, 0x9908b0df, 11, 0xffffffff, 7, 0x9d2c5680, 15, 0xefc60000, 18, 1812433253> 32 位梅森缠绕器，由松本与西村设计于 1998
mt19937_64(C++11) | std::mersenne_twister_engine< std::uint_fast64_t, 64, 312, 156, 31, 0xb5026f5aa96619e9, 29, 0x5555555555555555, 17, 0x71d67fffeda60000, 37, 0xfff7eee000000000, 43, 6364136223846793005> 64 位梅森缠绕器，由松本与西村设计于 2000

成员类型

成员类型 | 定义
result_type(C++11) | 引擎所生成的整数类型。若此非无符号整数类型则结果未定义。

成员函数

构造与播种
(构造函数)
(C++11)
 构造引擎
(公开成员函数)
seed
(C++11)
 设置引擎的当前状态
(公开成员函数)
生成
operator()
(C++11)
 推进引擎状态并返回生成的值
(公开成员函数)
discard
(C++11)
 令引擎状态前进指定量
(公开成员函数)
特征
min
[静态]
 获取输出范围中的最小可能值
(公开静态成员函数)
max
[静态]
 获取输出范围中的最大可能值
(公开静态成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个伪随机数引擎的内部状态 (函数)
operator<<operator>> (C++11) | 执行伪随机数引擎的流输入和输出 (函数)

成员常量

constexpr size_t word_size [静态] (C++11) | 模板形参 w ，确定引擎所生成的值范围。 (公开静态成员常量)
constexpr size_t state_size [静态] (C++11) | 模板形参 n 。引擎状态是 n 个 UIntType 值 (公开静态成员常量)
constexpr size_t shift_size [静态] (C++11) | 模板形参 m (公开静态成员常量)
constexpr size_t mask_bits [静态] (C++11) | 模板形参 r ，亦称为缠绕值。 (公开静态成员常量)
constexpr UIntType xor_mask [静态] (C++11) | 模板形参 a ，条件性异或掩码。 (公开静态成员常量)
constexpr size_t tempering_u [静态] (C++11) | 模板形参 u ，位扰乱（均化）矩阵的第一组分 (公开静态成员常量)
constexpr UIntType tempering_d [静态] (C++11) | 模板形参 d ，位扰乱（均化）矩阵的第二组分 (公开静态成员常量)
constexpr size_t tempering_s [静态] (C++11) | 模板形参 s ，位扰乱（均化）矩阵的第三组分 (公开静态成员常量)
constexpr UIntType tempering_b [静态] (C++11) | 模板形参 b ，位扰乱（均化）矩阵的第四组分 (公开静态成员常量)
constexpr size_t tempering_t [静态] (C++11) | 模板形参 t ，位扰乱（均化）矩阵的第五组分 (公开静态成员常量)
constexpr UIntType tempering_c [静态] (C++11) | 模板形参 c ，位扰乱（均化）矩阵的第六组分 (公开静态成员常量)
constexpr size_t tempering_l [静态] (C++11) | 模板形参 l ，位扰乱（均化）矩阵的第七组分 (公开静态成员常量)
constexpr UIntType initialization_multiplier [静态] (C++11) | 模板形参 f (公开静态成员常量)
constexpr UIntType default_seed [静态] (C++11) | 常数值 5489u (公开静态成员常量)

注解

第 10000 次连续调用默认构造的 std::mt19937 应生成值 4123659995 。

第 10000 次连续调用默认构造的 std::mt19937_64 应生成值 9981545732273789042 。


std::mersenne_twister_engine<UIntType,w,n,m,r,a,u,d,s,b,t,c,l,f>::discard

< cpp‎ | numeric‎ | random‎ | mersenne twister engine

void discard( unsigned long long z ); | (C++11 起)

令内部状态前进 z 次。等价于调用 operator() z 次并舍弃结果。

参数

z - 指定状态前进次数的整数值

返回值

（无）

复杂度

本节未完成

注意

对于某些引擎，“快速跳转”算法已知，它们能令状态前进许多步（以百万计）而无需计算中间状态迁移，尽管不需要在常数时间内。

参阅

operator()
(C++11)
 推进引擎状态并返回生成的值
(公开成员函数)


std::mersenne_twister_engine<UIntType,w,n,m,r,a,u,d,s,b,t,c,l,f>::max

< cpp‎ | numeric‎ | random‎ | mersenne twister engine

static constexpr result_type max(); | (C++11 起)

返回随机数引擎潜在生成的最大值。此值等于 2w
 - 1 ，其中 w 是模板形参，它亦可作为静态成员 word_size 访问。

参数

（无）

返回值

最大潜在生成值。

复杂度

常数

参阅

min
[静态]
 获取输出范围中的最小可能值
(公开静态成员函数)


std::mersenne_twister_engine<UIntType,w,n,m,r,a,u,d,s,b,t,c,l,f>::mersenne_twister_engine

< cpp‎ | numeric‎ | random‎ | mersenne twister engine

mersenne_twister_engine() : mersenne_twister_engine(default_seed) {} | (1) | (C++11 起)
explicit mersenne_twister_engine( result_type value ); | (2) | (C++11 起)
template< class Sseq > explicit mersenne_twister_engine( Sseq& s ); | (3) | (C++11 起)
mersenne_twister_engine( const mersenne_twister_engine& ); | (4) | (C++11 起) (隐式声明)

构造伪随机数引擎。

1) 默认构造函数。以 default_seed 播种引擎。
2) 构造引擎并初始化状态（ result_type 类型的 n 个值 X
i ）如下：用 value mod 2w
 初始化 X
0 ，并递推初始化其余内容，对于 i=1-n,...,-1 ，初始化每个 X
i 为 [f·(X
i-1xor(X
i-1rshift(w-2)))+i mod n] mod 2w
 。
3) 构造引擎并通过调用 s.generate(a, a+n*k) 初始化状态，其中 a 是长为 n*k 的数组，而 k 为 ceil(w/32) ，然后，对于每个 i=-n,...,-1 ，递推地设置引擎状态的元素 X
i 为 (Σk-1
j=0a
k(i+n)+j}·232j
) mod 2w
 ，最后若 X
0 的最高 w-r 位为零，且若所有其他 X
i 均为零，则以 2w-1
 替换 X
0 。

注意：初始化要求基于梅森缠绕器的 2002 版本， mt19937ar.c

仅若 Sseq 符合重载种子序列 (SeedSequence) ， (3) 才参与重载决议。尤其是若 Sseq 可转换为 result_type ，则从候选函数集中排除该重载。

参数

value | - | 用于内部状态初始化的种子值
s | - | 用于内部状态初始化的种子序列

复杂度

与 n （状态大小）成线性

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式

参阅

seed
(C++11)
 设置引擎的当前状态
(公开成员函数)


std::mersenne_twister_engine<UIntType,w,n,m,r,a,u,d,s,b,t,c,l,f>::min

< cpp‎ | numeric‎ | random‎ | mersenne twister engine

static constexpr result_type min(); | (C++11 起)

返回随机数引擎潜在生成的最小值。此值等于 0u 。

参数

（无）

返回值

最小的潜在生成值。

复杂度

常数

参阅

max
[静态]
 获取输出范围中的最大可能值
(公开静态成员函数)


std::mersenne_twister_engine<UIntType,w,n,m,r,a,u,d,s,b,t,c,l,f>::operator()

< cpp‎ | numeric‎ | random‎ | mersenne twister engine

result_type operator()(); | (C++11 起)

生成伪随机数。令引擎状态前进一个位置。

本节未完成

参数

（无）

返回值

[min(), max()] 中的伪随机数。

复杂度

均摊常数。

参阅

discard
(C++11)
 令引擎状态前进指定量
(公开成员函数)


operator==,!=(std::mersenne_twister_engine)

< cpp‎ | numeric‎ | random‎ | mersenne twister engine

friend bool operator==( const mersenne_twister_engine& lhs, const mersenne_twister_engine& rhs ); | (1) | (C++11 起)
friend bool operator!=( const mersenne_twister_engine& lhs, const mersenne_twister_engine& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个伪随机数引擎。若其内部状态等价，即对任何数量的 operator() 调用都会生成相等的值，则二个引擎相等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::mersenne_twister_engine<UIntType,w,n,m,r,a,u,d,s,b,t,c,l,f> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的引擎

返回值

1) 若引擎等价则为 true ，否则为 false 。
2) 若引擎不等价则为 true ，否则为 false 。

异常

不抛出。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::mersenne_twister_engine)

< cpp‎ | numeric‎ | random‎ | mersenne twister engine

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const mersenne_twister_engine& e );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

mersenne_twister_engine& e );
 (2) (C++11 起)
1) 序列化伪随机数引擎 e 的内部状态为一或多个空格分隔的十进制数序列，并插入之到流 ost 。填充字符和格式化标志被忽略且无效。
2) 从先前用拥有相同感染的本地环境，和相同 CharT 与 Traits 的流调用 operator<< ，生成的序列化表示还原伪随机数引擎 e 的内部状态。若不能反序列化输入，则保留 e 不改变并在 ist 上引发 failbit 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::mersenne_twister_engine<UIntType,w,n,m,r,a,u,d,s,b,t,c,l,f> 为参数的关联类时由实参依赖查找找到。

若用 os << x 写的文本表示，用 is >> y 还原到同类型的同一或不同对象 y ，则 x==y 。

以设置 os.fmtflags 为 ios_base::dec|ios_base::left 并设置填充字符为空格符写文本表示。引擎内部状态的文本表示是一组空格分隔的十进制数。

参数

ost | - | 要插入数据的输出流
ist | - | 要提取数据的输入流
e | - | 伪随机数引擎

返回值

1) ost
2) ist

复杂度

本节未完成

异常

1) 可能抛出实现定义的异常。
2) 设置了 failbit 时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::mersenne_twister_engine<UIntType,w,n,m,r,a,u,d,s,b,t,c,l,f>::seed

< cpp‎ | numeric‎ | random‎ | mersenne twister engine

void seed( result_type value = default_seed ); | (1) | (C++11 起)
template< class Sseq > void seed( Sseq& seq ); | (2) | (C++11 起)

用新种子值重初始化随机数引擎的内部状态。

本节未完成

参数

value | - | 用于内部状态初始化的种子值
seq | - | 用于内部状态初始化的种子序列

异常

不抛出。

复杂度

本节未完成


std::negative_binomial_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class IntType = int > class negative_binomial_distribution; | (C++11 起)

产生随机非负整数值 i ，其分布按照离散概率函数：

\(P(i|k, p) = \binom{k + i - 1}{i} \cdot p^k \cdot (1 - p)^i\)P(i|k,p) =⎛
⎜
⎝k + i − 1
i⎞
⎟
⎠ · pk
 · (1 − p)i

该值表示一系列独立的是/否试验在准确出现 k 次成功前的失败次数（每次成功概率为 p ）。

std::negative_binomial_distribution 满足随机数分布 (RandomNumberDistribution) 。

模板形参

IntType - 生成器所生成的结果类型。若它不是 short 、 int 、 long 、 long long 、 unsigned short 、 unsigned int 、 unsigned long 或 unsigned long long 之一则效果未定义。

成员类型

成员类型 | 定义
result_type | IntType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
pk
 返回分布参数
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    // Pat 挨家挨户卖饼干
    // 在每家，有 75% 的几率卖出一盒
    // 试问她在卖出 5 盒前要卖多少次？
    std::negative_binomial_distribution<> d(5, 0.75);

    std::map<int, int> hist;
    for(int n=0; n<10000; ++n) {
        ++hist[d(gen)];
    }
    for(auto p : hist) {
        std::cout  << p.first << ' ' << std::string(p.second/100, '*') << '\n';
    }
}

输出：

0 ***********************
1 *****************************
2 **********************
3 *************
4 ******
5 ***
6 *
7
8
9
10
11

外部链接

Weisstein, Eric W. “负二项分布。”来自 MathWorld--A Wolfram Web Resource 。


std::negative_binomial_distribution<IntType>::max

< cpp‎ | numeric‎ | random‎ | negative binomial distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::negative_binomial_distribution<IntType>::min

< cpp‎ | numeric‎ | random‎ | negative binomial distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::negative_binomial_distribution<IntType>::negative_binomial_distribution

< cpp‎ | numeric‎ | random‎ | negative binomial distribution
negative_binomial_distribution() : negative_binomial_distribution(1) {} | (1) | (C++11 起)
explicit negative_binomial_distribution( IntType k, double p = 0.5 ); | (2) | (C++11 起)
explicit negative_binomial_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。 (2) 以 k 和 p 为分布参数， (3) 以 params 为分布参数。

参数

k | - | k 分布参数（试验成功次数）
p | - | p 分布参数（试验生成 true 的概率）
params | - | 分布参数集

注意

要求 0 < p ≤ 1 和 0 < k 。

若 p == 1 ，则调用不接受 param_type 参数的 operator() 的重载将导致未定义行为。

默认构造的 std::negative_binomial_distribution 等价于默认构造的 std::geometric_distribution 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::negative_binomial_distribution<IntType>::operator()

< cpp‎ | numeric‎ | random‎ | negative binomial distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::negative_binomial_distribution)

< cpp‎ | numeric‎ | random‎ | negative binomial distribution

friend bool operator==( const negative_binomial_distribution& lhs, const negative_binomial_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const negative_binomial_distribution& lhs, const negative_binomial_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::negative_binomial_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::negative_binomial_distribution)

< cpp‎ | numeric‎ | random‎ | negative binomial distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const negative_binomial_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

negative_binomial_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::negative_binomial_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::negative_binomial_distribution<IntType>::param

< cpp‎ | numeric‎ | random‎ | negative binomial distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::negative_binomial_distribution<IntType>::p, k

< cpp‎ | numeric‎ | random‎ | negative binomial distribution
double p() const; | (1) | (C++11 起)
IntType k() const; | (2) | (C++11 起)

返回构造分布所用的参数。

1) 返回 p 分布参数。它定义试验生成 true 的概率。默认值为 0.5 。
2) 返回 k 分布参数。它定义盼望的结果数。默认值为 1 。

参数

（无）

返回值

1) p 分布参数。
2) k 分布参数。。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::negative_binomial_distribution<IntType>::reset

< cpp‎ | numeric‎ | random‎ | negative binomial distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::normal_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class RealType = double > class normal_distribution; | (C++11 起)

生成服从正态（高斯）随机数分布的随机数。它定义为：

\(\small{f(x;\mu,\sigma)}=\frac{1}{\sigma\sqrt{2\pi} }\exp{(-\frac{1}{2}{(\frac{x-\mu}{\sigma})}^2)}\)f(x; μ,σ) =
1
σ√2π
exp⎛
⎜
⎝
-1
2
⎛
⎜
⎝
x-μ
σ
⎞
⎟
⎠2
⎞
⎟
⎠

此处 \(\small\mu\)μ 为平均数 (mean) 而 \(\small\sigma\)σ 为标准差 (stddev) 。

std::normal_distribution 满足随机数分布 (RandomNumberDistribution) 的所有要求。

模板形参

RealType - 生成器所生成的结果类型。若它不是 float 、 double 或 long double 之一则效果未定义。

成员类型

成员类型 | 定义
result_type(C++11) | RealType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
meanstddev
 返回分布参数
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <cmath>
int main()
{
    std::random_device rd{};
    std::mt19937 gen{rd()};

    // 值最可能接近平均
    // 标准差影响生成的值距离平均数的分散
    std::normal_distribution<> d{5,2};

    std::map<int, int> hist{};
    for(int n=0; n<10000; ++n) {
        ++hist[std::round(d(gen))];
    }
    for(auto p : hist) {
        std::cout << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

可能的输出：

-2
-1
 0
 1 *
 2 ***
 3 ******
 4 ********
 5 **********
 6 ********
 7 *****
 8 ***
 9 *
10
11
12

外部链接

  • Weisstein, Eric W. “正态分布”来自 MathWorld--A Wolfram Web Resource 。
  • 正态分布来自维基百科。


std::normal_distribution<RealType>::max

< cpp‎ | numeric‎ | random‎ | normal distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::normal_distribution<RealType>::min

< cpp‎ | numeric‎ | random‎ | normal distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::normal_distribution<RealType>::normal_distribution

< cpp‎ | numeric‎ | random‎ | normal distribution
normal_distribution() : normal_distribution(0.0) {} | (1) | (C++11 起)
explicit normal_distribution( RealType mean, RealType stddev = 1.0 ); | (2) | (C++11 起)
explicit normal_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。 (2) 以 mean 和 stddev 为分布参数。 (3) 以 params 为分布参数。

若 stddev 不大于零则行为未定义。

参数

mean | - | μ 分布参数（平均数）
stddev | - | σ 分布参数（标准差）
params | - | 分布参数集

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::normal_distribution<RealType>::operator()

< cpp‎ | numeric‎ | random‎ | normal distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::normal_distribution)

< cpp‎ | numeric‎ | random‎ | normal distribution

friend bool operator==( const normal_distribution& lhs, const normal_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const normal_distribution& lhs, const normal_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::normal_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::normal_distribution)

< cpp‎ | numeric‎ | random‎ | normal distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const normal_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

normal_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::normal_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::normal_distribution<RealType>::param

< cpp‎ | numeric‎ | random‎ | normal distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::normal_distribution<RealType>::mean, stddev

< cpp‎ | numeric‎ | random‎ | normal distribution
RealType mean() const; | (1) | (C++11 起)
RealType stddev() const; | (2) | (C++11 起)

返回构造分布所用的参数。

1) 返回平均数 μ 分布参数。平均数指定峰的位置。默认值为 0.0 。
2) 返回标准差 σ 分布参数。默认值为 1.0 。

参数

（无）

返回值

1) 平均数 μ 分布参数。
2) 标准差 σ 分布参数。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::normal_distribution<RealType>::reset

< cpp‎ | numeric‎ | random‎ | normal distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::piecewise_constant_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class RealType = double > class piecewise_constant_distribution; | (C++11 起)

std::piecewise_constant_distribution 产生随机浮点数，在分别带有自身权重的 w
i 的数个子区间 [b
i, b
i+1) 中的每一个上均匀分布。区间边界集合与权重集合为此分布的参数。

任何 b
i≤x<b
i+1 上的概率密度为
w
i
S (b
i+1 - b
i)
，其中 S 为所有权重之和。

std::piecewise_constant_distribution 满足随机数分布 (RandomNumberDistribution) 的所有要求。

模板形参

RealType - 生成器所生成的结果类型。若它不是 float 、 double 或 long double 之一则效果未定义。

成员类型

成员类型 | 定义
result_type | RealType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
intervalsdensities
 返回分布参数
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <iostream>
#include <string>
#include <map>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    // 50% 时间生成 0 与 1 间的随机数
    // 50% 时间生成 10 与 15 间的随机数
    std::vector<double> i{0,  1, 10, 15};
    std::vector<double> w{  1,  0,  1};
    std::piecewise_constant_distribution<> d(i.begin(), i.end(), w.begin());

    std::map<int, int> hist;
    for(int n=0; n<10000; ++n) {
        ++hist[d(gen)];
    }
    for(auto p : hist) {
        std::cout << p.first << ' ' << std::string(p.second/100, '*') << '\n';
    }
}

输出：

0 **************************************************
10 **********
11 *********
12 *********
13 **********
14 *********


std::piecewise_constant_distribution<RealType>::max

< cpp‎ | numeric‎ | random‎ | piecewise constant distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::piecewise_constant_distribution<RealType>::min

< cpp‎ | numeric‎ | random‎ | piecewise constant distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::piecewise_constant_distribution<RealType>::operator()

< cpp‎ | numeric‎ | random‎ | piecewise constant distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::piecewise_constant_distribution)

< cpp‎ | numeric‎ | random‎ | piecewise constant distribution

friend bool operator==( const piecewise_constant_distribution& lhs, const piecewise_constant_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const piecewise_constant_distribution& lhs, const piecewise_constant_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::piecewise_constant_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::piecewise_constant_distribution)

< cpp‎ | numeric‎ | random‎ | piecewise constant distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const piecewise_constant_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

piecewise_constant_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::piecewise_constant_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::piecewise_constant_distribution<RealType>::param

< cpp‎ | numeric‎ | random‎ | piecewise constant distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::piecewise_constant_distribution<RealType>::intervals, densities

< cpp‎ | numeric‎ | random‎ | piecewise constant distribution
std::vector <RealType> intervals() const; | (1) | (C++11 起)
std::vector <RealType> densities() const; | (2) | (C++11 起)

返回分布参数。

1) 返回区间边界列表。
2) 返回区间概率密度列表。

参数

（无）

返回值

分布参数：

1) 区间边界列表。
2) 区间概率密度列表。

复杂度

常数。


std::piecewise_constant_distribution<RealType>::piecewise_constant_distribution

< cpp‎ | numeric‎ | random‎ | piecewise constant distribution
piecewise_constant_distribution();
 (1) (C++11 起)
template< class InputIt1, class InputIt2 >

piecewise_constant_distribution( InputIt1 first_i, InputIt1 last_i,

InputIt2 first_w );
 (2) (C++11 起)
template< class UnaryOperation >

piecewise_constant_distribution( std::initializer_list <RealType> bl,

UnaryOperation fw );
 (3) (C++11 起)
template< class UnaryOperation >

piecewise_constant_distribution( std::size_t nw,
RealType xmin, RealType xmax,

UnaryOperation fw );
 (4) (C++11 起)
explicit piecewise_constant_distribution( const param_type& parm );
 (5) (C++11 起)

构造新的 piecewise_constant_distribution 对象。

1) 构造 n = 1 、 ρ0 = 1 、 b0 = 0 且 b1 = 1 的分布对象。
2) 从区间序列 [first_i, last_i) 上的迭代器和始于 first_w 的匹配权重序列构造分布对象。
3) 构造分布对象，其中区间取自 initializer_list bl 而权重以函数 fw 生成。
4) 构造分布对象，拥有 nw 个均匀分布的区间 [xmin, xmax] ，而权重以函数 fw 生成。
5) 构造以参数 param 初始化的分布对象。

参数

first_i | - | 初始化为指向区间序列起始的迭代器
last_i | - | 初始化为指向区间序列末尾尾后一位置的迭代器
first_w | - | 初始化为指向密度（权重）序列起始的迭代器
ilist_i | - | 产出区间序列的 initializer_list
fw | - | 产出密度的 double(double) 函数
nw | - | 密度数量
xmin | - | 区间序列下界
xmax | - | 区间序列上界
parm | - | 分布参数集


std::piecewise_constant_distribution<RealType>::reset

< cpp‎ | numeric‎ | random‎ | piecewise constant distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::piecewise_linear_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class RealType = double > class piecewise_linear_distribution; | (C++11 起)

std::piecewise_linear_distribution 产生随机浮点数，分布服在数个子区间 \(\small{[b_i, b_{i+1})}\)[b
i, b
i+1) 的每一者上的线性概率密度函数。分布满足在每个区间边界上的概率密度恰为预定义值 \(\small{p_i}\)p
i 。

任何 \(\small{ b_i \le x < b_{i+1} }\)b
i≤x<b
i+1 中的概率密度为 \(\small{p_i\frac{b_{i+1}-x}{b_{i+1}-b_i} + p_{i+1}\frac{x-b_i}{b_{i+1}-b_i} }\)p
i
b
i+1-x
b
i+1-b
i
+ p
i+1
x-b
i
b
i+1-b
i
，其中在区间边界 \(\small{p_k}\)p
k 上的概率密度计算为 \(\small{w_k/S}\)w
k/S ，其中 \(\small{S}\)S 为所有 \(\small{\frac{1}{2}(w_k + w_{k+1})(b_{k+1} - b_k)}\)
1
2
(w
k+w
k+1)(b
k+1−b
k) 之和。

区间边界 \(\small{b_i}\)b
i 的集合和边界上权重 \(\small{w_i}\)w
i 的集合是此分布的参数。

std::piecewise_linear_distribution 满足随机数分布 (RandomNumberDistribution) 的所有要求。

模板形参

RealType - 生成器所生成的结果类型。若它不是 float 、 double 或 long double 之一则效果未定义。

模板类型

成员类型 | 定义
result_type(C++11) | RealType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
intervalsdensities
 返回分布参数
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    // 从 0 到 5 增加概率
    // 从 5 到 10 保持水平
    // 从 10 到 15 以相同速率下降
    std::vector<double> i{0, 5, 10, 15};
    std::vector<double> w{0, 1,   1, 0};
    std::piecewise_linear_distribution<> d(i.begin(), i.end(), w.begin());

    std::map<int, int> hist;
    for(int n=0; n<10000; ++n) {
        ++hist[d(gen)];
    }
    for(auto p : hist) {
        std::cout << std::setw(2) << std::setfill('0') << p.first << ' '
            << std::string(p.second/100,'*') << '\n';
    }
}

可能的输出：

00 *
01 ***
02 ****
03 ******
04 *********
05 *********
06 *********
07 **********
08 *********
09 **********
10 *********
11 *******
12 ****
13 ***
14 *


std::piecewise_linear_distribution<RealType>::max

< cpp‎ | numeric‎ | random‎ | piecewise linear distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::piecewise_linear_distribution<RealType>::min

< cpp‎ | numeric‎ | random‎ | piecewise linear distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::piecewise_linear_distribution<RealType>::operator()

< cpp‎ | numeric‎ | random‎ | piecewise linear distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::piecewise_linear_distribution)

< cpp‎ | numeric‎ | random‎ | piecewise linear distribution

friend bool operator==( const piecewise_linear_distribution& lhs, const piecewise_linear_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const piecewise_linear_distribution& lhs, const piecewise_linear_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::piecewise_linear_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::piecewise_linear_distribution)

< cpp‎ | numeric‎ | random‎ | piecewise linear distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const piecewise_linear_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

piecewise_linear_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::piecewise_linear_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::piecewise_linear_distribution<RealType>::param

< cpp‎ | numeric‎ | random‎ | piecewise linear distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::piecewise_linear_distribution<RealType>::intervals, densities

< cpp‎ | numeric‎ | random‎ | piecewise linear distribution
std::vector <RealType> intervals() const; | (1) | (C++11 起)
std::vector <RealType> densities() const; | (2) | (C++11 起)

返回分布参数。

1) 返回区间边界列表。
2) 返回区间边界上的概率密度列表。

参数

（无）

返回值

分布参数：

1) 区间边界列表。
2) 区间边界上的概率密度列表。

复杂度

常数。


std::piecewise_linear_distribution<RealType>::piecewise_linear_distribution

< cpp‎ | numeric‎ | random‎ | piecewise linear distribution
piecewise_linear_distribution();
 (1) (C++11 起)
template< class InputIt1, class InputIt2 >

piecewise_linear_distribution( InputIt1 first_i, InputIt1 last_i,

InputIt2 first_w );
 (2) (C++11 起)
template< class UnaryOperation >

piecewise_linear_distribution( std::initializer_list <RealType> ilist,

UnaryOperation fw );
 (3) (C++11 起)
template< class UnaryOperation >

piecewise_linear_distribution( std::size_t nw,
RealType xmin, RealType xmax,

UnaryOperation fw );
 (4) (C++11 起)
explicit piecewise_linear_distribution( const param_type& parm );
 (5) (C++11 起)

构造新的 piecewise_linear_distribution 对象。

1) 构造分布对象，有 n = 1 、 ρ0 = 1 、 b0 = 0 且 b1 = 1 。
2) 从区间序列 [first_i, last_i) 上的迭代器和始于 first_w 的匹配权重序列构造分布对象。
3) 构造分布对象，其中区间取自 initializer_list ilist ，而权重以函数 fw 计算。
4) 构造分布对象，拥有在 [xmin, xmax] 上均匀分布的 nw 个区间。
5) 构造以参数 param 初始化的对象。

参数

first_i | - | 初始化为指向区间序列起始的迭代器
last_i | - | 初始化为指向区间序列末尾尾后一位置的迭代器
first_w | - | 初始化为指向密度（权重）序列起始的迭代器
ilist_i | - | 产出区间序列的 initializer_list
fw | - | 产出密度的 double(double) 函数
nw | - | 密度数量
xmin | - | 区间序列下界
xmax | - | 区间序列上界
parm | - | 分布参数集


std::piecewise_linear_distribution<RealType>::reset

< cpp‎ | numeric‎ | random‎ | piecewise linear distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::poisson_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class IntType = int > class poisson_distribution; | (C++11 起)

产生随机非负整数值 i ，分布服从离散概率函数：

\(P(i | \mu) = \frac{e^{-\mu}\mu^i}{i!}\)P(i|μ) =
e-μ
·μi
i!

若同一条件下（相同的时间/空间区间上）随机事件的期望平均发生次数为 μ ，则获得的值是其准确发生 i 次的概率。

std::poisson_distribution 满足随机数分布 (RandomNumberDistribution) 。

模板形参

IntType - 生成器所生成的结果类型。若它不是 short 、 int 、 long 、 long long 、 unsigned short 、 unsigned int 、 unsigned long 或 unsigned long long 之一则效果未定义。

成员类型

成员类型 | 定义
result_type | IntType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
mean
 返回 mean 分布参数（事件出现次数的平均数）
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());

    // 若平均一分钟出现 4 次事件
    // 则在一分钟内出现 n 次的频率如何？
    std::poisson_distribution<> d(4);

    std::map<int, int> hist;
    for(int n=0; n<10000; ++n) {
        ++hist[d(gen)];
    }
    for(auto p : hist) {
        std::cout << p.first <<
                ' ' << std::string(p.second/100, '*') << '\n';
    }
}

输出：

0 *
1 *******
2 **************
3 *******************
4 *******************
5 ***************
6 **********
7 *****
8 **
9 *
10
11
12
13

外部链接

Weisstein, Eric W. “泊松分布。”来自 MathWorld--A Wolfram Web Resource 。


std::poisson_distribution<IntType>::max

< cpp‎ | numeric‎ | random‎ | poisson distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::poisson_distribution<IntType>::mean

< cpp‎ | numeric‎ | random‎ | poisson distribution
double mean() const; | (C++11 起)

返回构造分布所用的 μ 参数。参数定义事件发生次数的平均数。默认值为 1.0 。

参数

（无）

返回值

标识 μ 分布参数的浮点值。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::poisson_distribution<IntType>::min

< cpp‎ | numeric‎ | random‎ | poisson distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::poisson_distribution<IntType>::operator()

< cpp‎ | numeric‎ | random‎ | poisson distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::poisson_distribution)

< cpp‎ | numeric‎ | random‎ | poisson distribution

friend bool operator==( const poisson_distribution& lhs, const poisson_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const poisson_distribution& lhs, const poisson_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::poisson_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::poisson_distribution)

< cpp‎ | numeric‎ | random‎ | poisson distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const poisson_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

poisson_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::poisson_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::poisson_distribution<IntType>::param

< cpp‎ | numeric‎ | random‎ | poisson distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::poisson_distribution<IntType>::poisson_distribution

< cpp‎ | numeric‎ | random‎ | poisson distribution
poisson_distribution() : poisson_distribution(1.0) {} | (1) | (C++11 起)
explicit poisson_distribution( double mean ); | (2) | (C++11 起)
explicit poisson_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。第一版本以 mean 为分布参数，第二版本以 params 为分布参数。

参数

mean | - | μ 分布参数（分布的平均数）
params | - | 分布参数集

注意

要求 0 < mean 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::poisson_distribution<IntType>::reset

< cpp‎ | numeric‎ | random‎ | poisson distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::rand

< cpp‎ | numeric‎ | random
定义于头文件 <cstdlib>
int rand();

返回 ​0​ 到 RAND_MAX （包含 0 与 RAND_MAX ）的随机数。

std::srand() 播种 rand() 所用的伪随机数生成器。若在任何到 srand() 的调用前使用 rand() ，则 rand() 表现如同它以 srand(1) 播种。

每次以 srand() 播种 rand() ，它必须在后续调用上产生相同的值数列。

标准库中的其他函数可调用 rand 。哪个函数这么做是实现定义的。

rand() 是否线程安全是实现定义的。

参数

（无）

返回值

​0​ 与 RAND_MAX 间的随机整数值。

注解

不保证生成的随机数列质量。过去，一些 rand() 在随机性、分布和产生的序列周期上有严重缺陷（在一个众所周知的例子中，调用之间最低位简单地在 1 与 0 间切换）。

对于严肃的随机数生成需求不推荐 rand() 。推荐用 C++11 的随机数生成设施替换 rand() 。 (C++11 起)

示例

#include <cstdlib>
#include <iostream>
#include <ctime>

int main()
{
    std::srand(std::time(nullptr)); // 以当前时间为随机生成器的种子
    int random_variable = std::rand();
    std::cout << "Random value on [0 " << RAND_MAX << "]: "
              << random_variable << '\n';

    // 扔 6 面色子 20 次
    for (int n = 0; n != 20; ++n) {
        int x = 7;
        while(x > 6)
            x = 1 + std::rand() / ((RAND_MAX + 1u) / 6);  // 注意： 1 + rand() % 6 有偏差！
        std::cout << x << ' ';
    }
}

可能的输出：

Random value on [0 2147483647]: 726295113
6 3 6 2 6 5 6 3 1 1 1 6 6 6 4 1 3 6 4 2

参阅

uniform_int_distribution (C++11) | 产生在一个范围上均匀分布的整数值 (类模板)
srand | 初始化伪随机数生成器 (函数)
RAND_MAX | std::rand 生成的最大可能值 (宏常量)
randint | 生成指定范围中的随机整数 (函数模板)


std::random_device

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
class random_device; | (C++11 起)

std::random_device 是生成非确定随机数的均匀分布整数随机数生成器。

std::random_device 可以以实现定义的伪随机数引擎实现，若非确定源（例如硬件设备）对实现不可用。此情况下每个 std::random_device 对象可生成同一数值序列。

成员类型

成员类型 | 定义
result_type | unsigned int

成员函数

构造
(构造函数)
(C++11)
 构造引擎
(公开成员函数)
operator=
(被删除)
 赋值运算符被删除
(公开成员函数)
生成
operator()
(C++11)
 推进引擎状态并返回生成的值
(公开成员函数)
特征
entropy
 获得非确定随机数生成器的熵估计
(公开成员函数)
min
[静态]
 获取输出范围中的最小可能值
(公开静态成员函数)
max
[静态]
 获取输出范围中的最大可能值
(公开静态成员函数)

注解

值得注意的 std::random_device 为确定性的实现是 MinGW 的旧版本（漏洞 338 ， GCC 9.2 起修复）。最新的 MinGW 版本可从 GCC with the MCF thread model 下载。

示例

#include <iostream>
#include <string>
#include <map>
#include <random>

int main()
{
    std::random_device rd;
    std::map<int, int> hist;
    std::uniform_int_distribution<int> dist(0, 9);
    for (int n = 0; n < 20000; ++n) {
        ++hist[dist(rd)]; // 注意：仅用于演示：一旦熵池耗尽，
                          // 许多 random_device 实现的性能就急剧下滑
                          // 对于实践使用， random_device 通常仅用于
                          // 播种类似 mt19937 的伪随机数生成器
    }
    for (auto p : hist) {
        std::cout << p.first << " : " << std::string(p.second/100, '*') << '\n';
    }
}

可能的输出：

0 : ********************
1 : *******************
2 : ********************
3 : ********************
4 : ********************
5 : *******************
6 : ********************
7 : ********************
8 : *******************
9 : ********************


std::random_device::entropy

< cpp‎ | numeric‎ | random‎ | random device
double entropy() const noexcept; | (C++11 起)

获得随机数设备熵的估计，它是 0 与 log
2(max()+1) （等于 std::numeric_limits <unsigned int>::digits ）之间的浮点数。若设备拥有 n 个状态，而其概率各为 P
0,...,P
n-1 ，则设备熵 S 定义为

S = -Σn-1
i=0P
ilog(P
i)

确定的随机数生成器（例如伪随机数生成器）拥有零熵。

返回值

设备熵的值，或若不可应用则为零。

注解

此函数在一些标准库中未完全实现。例如，版本 12 前的 LLVM libc++ 始终返回零，即使设备是非确定的（对于 libstdc++ ，见 bug 67578 ）。与之相比， Microsoft Visual C++ 实现始终返回 32 ，且 boost.random 返回 10 。

Linux 内核设备 /dev/urandom 的熵可用 ioctl RNDGETENTCNT 获得—— GNU libstdc++ 从版本 8.1 起将它用于 std::random_device::entropy() 。

示例

实现之一上的示例输出

#include <iostream>
#include <random>

int main()
{
    std::random_device rd;
    std::cout << rd.entropy() << '\n';
}

可能的输出：

32


std::random_device::max

< cpp‎ | numeric‎ | random‎ | random device

static constexpr result_type max(); | (C++11 起)

返回随机数引擎潜在生成的最大值。此值等于 std::numeric_limits <unsigned int>::max() 。

参数

（无）

返回值

最大潜在生成值。

复杂度

常数

参阅

min
[静态]
 获取输出范围中的最小可能值
(公开静态成员函数)


std::random_device::min

< cpp‎ | numeric‎ | random‎ | random device

static constexpr result_type min(); | (C++11 起)

返回随机数引擎潜在生成的最小值。此值等于 0u 。

参数

（无）

返回值

最小的潜在生成值。

复杂度

常数

参阅

max
[静态]
 获取输出范围中的最大可能值
(公开静态成员函数)


std::random_device::operator()

< cpp‎ | numeric‎ | random‎ | random device
result_type operator()(); | (C++11 起)

生成均匀分布的非确定随机值。

参数

（无）

返回值

均匀分布于 [min(), max()] 的随机数。

异常

若不能生成随机数则抛出导出自 std::exception 的实现定义异常。

参阅

min [静态] | 获取输出范围中的最小可能值 (公开静态成员函数)
max [静态] | 获取输出范围中的最大可能值 (公开静态成员函数)


std::random_device::random_device

< cpp‎ | numeric‎ | random‎ | random device
random_device() : random_device(/*implementation-defined*/) {} | (1) | (C++11 起)
explicit random_device(const std::string & token); | (2) | (C++11 起)
random_device(const random_device& ) = delete; | (3) | (C++11 起)
1) 以实现定义的 token 默认构造新的 std::random_device 对象。
2) 构造新的 std::random_device 对象，若提供则以实现定义行为利用参数 token 。
3) 复制构造函数被删除： std::random_device 不可复制。

异常

失败时抛出从 std::exception 派生的实现定义异常。

注解

libstdc++ 中的实现期待 token 指名随机字节的源。可能的记号值包括 "default" 、 "rand_s" 、 "rdseed" 、 "rdrand" 、 "rdrnd" 、 "/dev/urandom" 、 "/dev/random" 、 "mt19937" 和指定 mt19937 引擎的整数字符串。（除了 "default" 的记号仅在某些目标上可用。）

libc++ 中的实现在配置以字符设备为源时，期待 token 为在从它读取时产生随机数的字符设备的名字；否则它期待 token 为 "/dev/urandom" 。

若提供不支持的记号则 libstdc++ 与 libc++ 均抛出异常。 Microsoft STL 完全忽略记号。

示例

演示 Linux 上 std::random_device 二种常见的可用类型

#include <iostream>
#include <random>

int main()
{

    std::uniform_int_distribution<int> d(0, 10);

    std::random_device rd1; // 使用 RDRND 或 /dev/urandom
    for(int n = 0; n < 10; ++n)
        std::cout << d(rd1) << ' ';
    std::cout << '\n';

    std::random_device rd2("/dev/random"); // Linux 上更慢
    for(int n = 0; n < 10; ++n)
        std::cout << d(rd2) << ' ';
    std::cout << '\n';
}

可能的输出：

7 10 7 0 4 4 6 9 4 7
2 4 10 6 3 2 0 6 3 7

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数为 explicit | 使之为隐式


std::seed_seq

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
class seed_seq; | (C++11 起)

std::seed_seq 消耗整数值数列，并基于消耗的数据生成请求数量的无符号整数值 i ， 0 ≤ i < 232
 。产生的值分布在整个 32 位范围上，即使消耗的值接近。

它提供手段，以给定小种子或分布凄惨的初始种子序列，播种大量随机数引擎或播种要求大量熵的随机数。

std::seed_seq 满足种子序列 (SeedSequence) 的要求。

成员类型

成员类型 | 定义
result_type(C++11) | std::uint_least32_t

成员函数

(构造函数) (C++11) | 构造并播种 std::seed_seq 对象 (公开成员函数)
operator= [被删除](C++11) | seed_seq 不可赋值 (公开成员函数)
generate (C++11) | 计算偏差消除的均匀分布的 32 位值 (公开成员函数)
size (C++11) | 获得存储于 std::seed_seq 的 32 位值的数量 (公开成员函数)
param (C++11) | 获得存储于 std::seed_seq 的 32 位值 (公开成员函数)

示例

#include <random>
#include <cstdint>
#include <iostream>

int main()
{
    std::seed_seq seq{1,2,3,4,5};
    std::vector<std::uint32_t> seeds(10);
    seq.generate(seeds.begin(), seeds.end());
    for (std::uint32_t n : seeds) {
        std::cout << n << '\n';
    }
}

输出：

4204997637
4246533866
1856049002
1129615051
690460811
1075771511
46783058
3904109078
1534123438
1495905678


std::seed_seq::generate

< cpp‎ | numeric‎ | random‎ | seed seq
template< class RandomIt > void generate( RandomIt begin, RandomIt end ); | (C++11 起)

以基于最初提供于此 seed_seq 构造函数的无符号整数值 i ， 0 ≤ i < 232
 填充范围 [begin, end) 。产生的值分布在整个 32 位范围，即使初值有强偏差。

使用下列算法（改编自松本真与西村拓士发明的梅森缠绕器生成器，加以斋藤睦夫于 2007 的改进工作）。

  • 若 begin == end 则不做任何事。否则，
  • 首先，设置输出范围的每个元素为值 0x8b8b8b8b 。
  • 按照下列算法变换输出范围的元素：

对于 k = 0,..., m-1

其中 m=max(s+1, n)
而 n=end-begin
而 s=v.size()
而 v 是保有最初为此 seed_seq 对象的构造函数所提供的值的私有容器，

  1. begin[k+p] += r1
  2. begin[k+q] += r2
  3. begin[k] = r2 ，

其中 p=(n-t)/2
而 q=p+t
而 t=(n >= 623) ? 11 : (n >= 68) ? 7 : (n >= 39) ? 5 : (n >= 7) ? 3 : (n - 1) / 2
而 r1=1664525 * T(begin[k]^begin[k+p]^begin[k−1])
而 T(x) = x ^ (x >> 27)
而若 k==0 则 r2=r1+s ，若 0<k<=s 则 r2=r1 + k%n + v[k-1] ，若 k>s 则 r2=r1 + k%n 。

对于 k = m,..., m+n-1 ，

  1. begin[k+p] ^= r3
  2. begin[k+q] ^= r4
  3. begin[k]=r4

其中 r3 = 1566083941 * T(begin[k]+begin[k+p]+begin[k-1])
而 r4=r3 - k%n

其中，所有计算以 modulo 232
 进行，并且以 modulo n 取输出范围的下标（ begin[x] ）。

参数

begin, end - 可变随机访问迭代器，其 std::iterator_traits <>::value_type 为适合存储 32 位值的无符号整数类型
类型要求
-
RandomIt 必须满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。

返回值

无，写入结果到 [begin, end) 范围。

异常

仅若 begin 和 end 上的操作抛出才抛异常。

示例

#include <random>
#include <iostream>

int main()
{
    std::seed_seq seq({1,2,3,4,5});
    std::vector<std::uint32_t> seeds(10);
    seq.generate(seeds.begin(), seeds.end());
// 步骤 1 ：以 0x8b8b8b8b 填充
// seeds = {2341178251, 2341178251, 2341178251, 2341178251, 2341178251,
//          2341178251, 2341178251, 2341178251, 2341178251, 2341178251 }
//
// 步骤 2 ：
// n = 10, s = 5, t = 3, p = 3, q = 6, m = 10
//
// 首次迭代， k = 0 ； r1 = 1371501266 ， r2 = 1371501271
//
// seeds = {1371501271, 2341178251, 2341178251, 3712679517, 2341178251,
//          2341178251, 3712679522, 2341178251, 2341178251, 2341178251 }
//
// 从 k = 1 到 k = 5 迭代（ r2 = r1 + k%n + v[k-1] ）
//
// r1 = 2786190137, 3204727651, 4173325571, 1979226628, 401983366
// r2 = 2786190139, 3204727655, 4173325577, 1979226636, 401983376
//
// seeds = {3350727907, 3188173515, 3204727655, 4173325577, 1979226636,
//           401983376, 3591037797, 2811627722, 1652921976, 2219536532 }
//
// 从 k = 6 到 k = 9 迭代（ r2 = r1 + k%n ）
//
// r1 = 2718637909, 1378394210, 2297813071, 1608643617
// r2 = 2718637915, 1378394217, 2297813079, 1608643626
//
// seeds = { 434154821, 1191019290, 3237041891, 1256752498, 4277039715,
//          2010627002, 2718637915, 1378394217, 2297813079, 1608643626 }
//
// 步骤 3
// 从 k = 10 到 k = 19 迭代，用 ^= 修改输出
//
// r1 = 1615303485, 3210438310, 893477041, 2884072672, 1918321961,
// r2 = 1615303485, 3210438309, 893477039, 2884072669, 1918321957
//
// seeds = { 303093272, 3210438309,  893477039, 2884072669, 1918321957,
//          1117182731, 1772877958, 2669970405, 3182737656, 4094066935 }
//
// r1 =  423054846, 46783064, 3904109085, 1534123446, 1495905687
// r2 =  423054841, 46783058, 3904109078, 1534123438, 1495905678
//
// seeds = { 4204997637, 4246533866, 1856049002, 1129615051, 690460811,
//           1075771511,   46783058, 3904109078, 1534123438, 1495905678 }

    for(std::uint32_t n : seeds)
        std::cout << n << '\n';
}

输出：

4204997637
4246533866
1856049002
1129615051
690460811
1075771511
46783058
3904109078
1534123438
1495905678


std::seed_seq::param

< cpp‎ | numeric‎ | random‎ | seed seq
template< class OutputIt > void param( OutputIt dest ) const; | (C++11 起)

输出存储于 std::seed_seq 对象的初始种子序列。

参数

dest - 输出迭代器，满足 *dest=rt 对 result_type 的值 rt 合法
类型要求
-
OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。

返回值

（无）

异常

仅若 dest 上的操作抛出才抛出。

示例

#include <random>
#include <iostream>
#include <iterator>
int main()
{
    std::seed_seq s1 = {-1, 0, 1};
    s1.param(std::ostream_iterator<int>(std::cout, " "));
}

输出：

-1 0 1


std::seed_seq::seed_seq

< cpp‎ | numeric‎ | random‎ | seed seq
seed_seq() noexcept; | (1) | (C++11 起)
seed_seq( const seed_seq& ) = delete; | (2) | (C++11 起)
template< class InputIt > seed_seq( InputIt begin, InputIt end ); | (3) | (C++11 起)
template< class T > seed_seq( std::initializer_list <T> il ); | (4) | (C++11 起)
1) 默认构造函数创建拥有零长度初始种子序列的 std::seed_seq 对象。
2) 复制构造函数被删除： std::seed_seq 不可复制。
3) 构造 std::seed_seq ，以拥有从范围 [begin, end) 上迭代并以解引用迭代器复制值获得的值 modulo 232
 （即复制低 32 位）为初始种子序列。
4) 等价于 seed_seq(il.begin(), il.end()) 。此构造函数启用源自种子值列表的列表初始化。此重载仅若 T 为整数类型才参与重载决议。

参数

begin, end | - | 初始种子序列，表示为一对 std::iterator_traits <>::value_type 为整数类型的输入迭代器
il | - | 整数类型对象的 std::initializer_list ，提供初始种子序列
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

异常

3-4) 在分配失败时抛出 std::bad_alloc 。

示例

#include <random>
#include <sstream>
#include <iterator>
int main()
{
    std::seed_seq s1; // 可默认构造
    std::seed_seq s2{1, 2, 3}; // 能用列表初始化
    std::seed_seq s3 = {-1, 0, 1}; // 列表初始化的另一种形式
    int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::seed_seq s4(a, a + 10); // 能用迭代器
    std::istringstream buf("1 2 3 4 5");
    std::istream_iterator<int> beg(buf), end;
    std::seed_seq s5(beg, end); // 即使是流输入迭代器
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3422 | C++11 | 默认构造函数决不失败但可以不是 noexcept ； 初始化器列表构造函数禁用源自迭代器对的列表初始化 | 使之为 noexcept ； 已约束


std::seed_seq::size

< cpp‎ | numeric‎ | random‎ | seed seq
std::size_t size() const noexcept; | (C++11 起)

返回存储的初始种子序列的大小。

参数

（无）

返回值

在构造时填充的私有容器的大小。

复杂度

常数时间。

示例

#include <random>
#include <iostream>
int main()
{
    std::seed_seq s1 = {-1, 0, 1};
    std::cout << s1.size() << '\n';
}

输出：

3

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2440 | C++11 | 未要求 seed_seq::size 为 noexcept | 已要求


std::shuffle_order_engine

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class Engine, std::size_t K > class shuffle_order_engine; | (C++11 起)

shuffle_order_engine 是随机数引擎适配器，它打乱基础引擎生成的随机数。它维护一个大小为 K 的表，并在请求时随机地从该表派送被选择数，将它替换为基础引擎生成的数。

下列 typedef 定义拥有常用参数集的随机数引擎：

定义于头文件 <random>
类型 | 定义
knuth_b(C++11) | std::shuffle_order_engine< std::minstd_rand0, 256>

模板形参

Engine | - | 包装的引擎类型
K | - | 内部表大小。必须大于 0
类型要求
- Engine 必须满足随机数引擎 (RandomNumberEngine) 的要求。

成员类型

成员类型 | 特征
result_type | Engine::result_type

成员函数

(构造函数)
(C++11)
 构造引擎适配器
(公开成员函数)
seed
(C++11)
 设置底层引擎的状态
(公开成员函数)
base
(C++11)
 返回底层引擎
(公开成员函数)
生成
operator()
(C++11)
 令底层引擎的状态前进并返回生成的值
(公开成员函数)
discard
(C++11)
 令适配器状态前进指定量
(公开成员函数)
特征
min
[静态] (C++11)
 获取底层引擎输出范围中的最小可能值。
(公开静态成员函数)
max
[静态] (C++11)
 获取底层引擎输出范围中最大的可能值。
(公开静态成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较适配器和底层引擎的内部状态 (函数)
operator<<operator>> (C++11) | 在伪随机数引擎适配器上进行流输入和输出 (函数)

成员对象

constexpr size_t table_size
[静态]
 内部表大小 K
(公开静态成员常量)


std::shuffle_order_engine<Engine,K>::base

< cpp‎ | numeric‎ | random‎ | shuffle order engine

const Engine& base() const noexcept; | (C++11 起)

返回底层引擎

参数

（无）

返回值

底层引擎。


std::shuffle_order_engine<Engine,K>::discard

< cpp‎ | numeric‎ | random‎ | shuffle order engine

void discard( unsigned long long z ); | (C++11 起)

令内部状态前进 z 次。等价于调用 operator() z 次并舍弃结果。可能令底层引擎的状态前进多于 z 次。

参数

z - 指定令引擎前进次数的整数值

返回值

（无）

异常

不抛出。

参阅

operator()
(C++11)
 令底层引擎的状态前进并返回生成的值
(公开成员函数)


std::shuffle_order_engine<Engine,K>::max

< cpp‎ | numeric‎ | random‎ | shuffle order engine

static constexpr result_type max(); | (C++11 起)

返回引擎适配器潜在生成的最大值。此值等于 e.max() ，其中 e 是底层引擎。

参数

（无）

返回值

最大的潜在生成值。

复杂度

常数

参阅

min
[静态]
 获取输出范围中的最小可能值
(公开静态成员函数)


std::shuffle_order_engine<Engine,K>::min

< cpp‎ | numeric‎ | random‎ | shuffle order engine

static constexpr result_type min(); | (C++11 起)

返回引擎适配器潜在生成的最小值。此值等于 e.min() ，其中 e 是底层引擎。

参数

（无）

返回值

最小的潜在生成值。

复杂度

常数

参阅

max
[静态]
 获取输出范围中的最大可能值
(公开静态成员函数)


std::shuffle_order_engine<Engine,K>::operator()

< cpp‎ | numeric‎ | random‎ | shuffle order engine

result_type operator()(); | (C++11 起)

生成随机值。令底层引擎状态前进一或多次。

参数

（无）

返回值

[min(), max()] 中的伪随机数。

异常

不抛出。

参阅

discard
(C++11)
 令适配器状态前进指定量
(公开成员函数)


operator==,!=(std::shuffle_order_engine)

< cpp‎ | numeric‎ | random‎ | shuffle order engine

friend bool operator==( const shuffle_order_engine& lhs, const shuffle_order_engine& rhs ); | (1) | (C++11 起)
friend bool operator!=( const shuffle_order_engine& lhs, const shuffle_order_engine& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个随机数引擎适配器。若二个适配器的底层引擎相等，且其内部状态（若存在）相等，即若它们会对任何数量的 operator() 调用产生等价的值，则它们相等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::shuffle_order_engine<Engine,p,r> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的引擎适配器

返回值

1) 若引擎适配器等价则为 true ，否则为 false 。
2) 若引擎适配器不等价则为 true ，否则为 false 。

异常

不抛出。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::shuffle_order_engine)

< cpp‎ | numeric‎ | random‎ | shuffle order engine

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

shuffle_order_engine<>& e );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

shuffle_order_engine& e );
 (2) (C++11 起)
1) 序列化伪随机数引擎适配器的内部状态为一或多个空格所分隔的十进制数序列，并将它插入流 ost 。忽略且不影响填充字符和格式化标签。
2) 从序列化表示恢复伪随机数引擎适配器 e 的内部状态，该表示由先前对 operator<< ，以拥有相同的感染本地环境、相同的 CharT 和 Traits 的流调用创建。若不能反序列化输入，则保留 e 不更改并引发 ist 上的 failbit 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::shuffle_order_engine<Engine,p,r> 为参数的关联类时由实参依赖查找找到。

若用 os << x 写入文本表示并用 is >> y 将它恢复到同一类型的相同或不同对象 y ，则 x==y 。

本节未完成
原因：标准还定义了文本表示的组成内容

参数

ost | - | 要插入数据的输出流
ist | - | 要提取数据的输入流
e | - | 要序列化或恢复的引擎适配器

返回值

1) ost
2) ist

复杂度

本节未完成

异常

1) 可能抛出实现定义的异常。
2) 设置了 failbit 时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::shuffle_order_engine<Engine,K>::seed

< cpp‎ | numeric‎ | random‎ | shuffle order engine

void seed(); | (1) | (C++11 起)
void seed( result_type value ); | (2) | (C++11 起)
template< class Sseq > void seed( Sseq& seq ); | (3) | (C++11 起)

用新的种子值重初始化底层引擎的内部状态。

1) 以默认种子值播种底层引擎。等效地调用 e.seed() ，其中 e 是底层引擎。
2) 以种子值 s 播种底层引擎。等效地调用 e.seed(value) ，其中 e 是底层引擎。
3) 以种子序列 seq 播种底层引擎。等效地调用 e.seed(seq) ，其中 e 是底层引擎。此模板仅若 Sseq 符合种子序列 (SeedSequence) 才参与重载决议。特别是若 Sseq 可隐式转换为 result_type 则此模板不参与重载决议。

参数

value | - | 用于初始化底层引擎内部状态的种子值
seq | - | 用于初始化底层引擎内部状态的种子序列

返回值

（无）

异常

不抛出。


std::shuffle_order_engine<Engine,K>::shuffle_order_engine

< cpp‎ | numeric‎ | random‎ | shuffle order engine

shuffle_order_engine(); | (1) | (C++11 起)
explicit shuffle_order_engine( result_type s ); | (2) | (C++11 起)
template< class Sseq > explicit shuffle_order_engine( Sseq& seq ); | (3) | (C++11 起)
explicit shuffle_order_engine( const Engine& e ); | (4) | (C++11 起)
explicit shuffle_order_engine( Engine&& e ); | (5) | (C++11 起)

构造新的伪随机数引擎适配器。

1) 默认构造函数。亦默认构造底层引擎。
2) 以 s 构造底层引擎
3) 以种子序列 seq 构造底层引擎。此构造函数仅若 Sseq 满足种子序列 (SeedSequence) 才参与重载决议。特别是若 Sseq 可隐式转换为 result_type 则此构造函数不参与重载决议。
4) 以 e 的副本构造底层引擎。
5) 以 e 移动构造底层引擎。之后 e 保有未指定但合法的状态。

参数

s | - | 用以构造底层引擎的整数值
seq | - | 用以构造底层引擎的种子序列
e | - | 用以初始化的伪随机数引擎


std::srand

< cpp‎ | numeric‎ | random
定义于头文件 <cstdlib>
void srand( unsigned seed );

以值 seed 播种 std::rand() 所用的随机数生成器。

若在任何到 srand() 的调用前使用 rand() ，则 rand() 表现为如同它被以 srand(1) 播种。

每次以同一 seed 播种 rand() 时，它必须产生相同的值数列。

srand() 不保证为线程安全。

参数

seed - 种子值

返回值

（无）

注意

通常来说，应该只播种一次随机数生成器，在程序开始出，任何到 rand() 的调用前。不应重复播种，或每次冀愿生成新一批随机数时重播种。

标准实践是使用以 time(0) 为种子调用的结果。然而 time() 返回 time_t 值，而不保证 time_t 是整数类型。尽管实践中，主流实现都定义 time_t 为整数类型，且此亦为 POSIX 所要求。

示例

#include <cstdlib>
#include <iostream>
#include <ctime>

int main()
{
    std::srand(std::time(0)); // 以当前时间为随机数生成器的种子
    int random_variable = std::rand();
    std::cout << "Random value on [0 " << RAND_MAX << "]: "
              << random_variable << '\n';
}

可能的输出：

Random value on [0 2147483647]: 1373858591

参阅

rand | 生成伪随机数 (函数)
RAND_MAX | std::rand 生成的最大可能值 (宏常量)
reseed | 重播种单个线程的随机引擎 (函数)


std::student_t_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class RealType = double > class student_t_distribution; | (C++11 起)

生成随机浮点值 x ，分布服从概率密度函数：

\(p(x|n) = \frac{1}{\sqrt{n\pi} } \cdot \frac{\Gamma(\frac{n+1}{2})}{\Gamma(\frac{n}{2})} \cdot (1+\frac{x^2}{n})^{-\frac{n+1}{2} } \)p(x|n) =
1
√nπ
·
Γ(
n+1
2
)
Γ(
n
2
)
· ⎛
⎜
⎝1+
x2
n
⎞
⎟
⎠ -
n+1
2

其中 n 为自由度数。在给定 n+1 个独立测量，每个都带标准差未知的加性误差，如在物理测量中估计未知正态分布值的平均数时使用此分布。或者，在给定 n+1 个样本，估计拥有未知标准差的正态分布的未知平均值时，使用此分布。

std::student_t_distribution 满足随机数分布 (RandomNumberDistribution) 的所有要求。

模板形参

RealType - 生成器所生成的结果类型。若它不是 float 、 double 或 long double 之一则效果未定义。

成员类型

成员类型 | 定义
result_type | RealType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
n
 返回 n 分布参数（自由度）
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <random>
#include <vector>

template <int Height = 5, int BarWidth = 1, int Padding = 1, int Offset = 0,
          bool DrawMinMax = true, class Sample>
void draw_vbars(Sample const& s) {
    static_assert((Height > 0) && (BarWidth > 0) && (Padding >= 0) && (Offset >= 0));
    auto cout_n = [](auto const& v, int n) { while (n-- > 0) { std::cout << v; } };
    const auto [min, max] = std::minmax_element(std::cbegin(s), std::cend(s));
    std::vector<std::div_t> qr;
    for (float e : s) {
        qr.push_back(std::div(std::lerp(0.f, Height*8, (e - *min)/(*max - *min)), 8));
    }
    for (auto h{Height}; h-- > 0 ;) {
        cout_n(' ', Offset);
        for (auto [q, r] : qr) {
            char d[] = "█"; // == { 0xe2, 0x96, 0x88, 0 }
            q < h ? d[0] = ' ', d[1] = '\0' : q == h ? d[2] -= (7 - r) : 0;
            cout_n(d, BarWidth);
            cout_n(' ', Padding);
        }
        if (DrawMinMax && Height > 1)
            h == Height - 1 ? std::cout << "┬ " << *max:
                     h != 0 ? std::cout << "│"
                            : std::cout << "┴ " << *min;
        cout_n('\n', 1);
    }
}

int main() {
    std::random_device rd{};
    std::mt19937 gen{rd()};

    std::student_t_distribution<> d{10.0f};

    const int norm = 10'000;
    const float cutoff = 0.000'3f;

    std::map<int, int> hist{};
    for(int n=0; n<norm; ++n) { ++hist[std::round(d(gen))]; }

    std::vector<float> bars;
    std::vector<int> indices;
    for (const auto [n, p] : hist) {
        if (float x = p * (1.0f / norm); cutoff < x) {
            bars.push_back(x);
            indices.push_back(n);
        }
    }

    draw_vbars<8,5>(bars);
    for (int n : indices) { std::cout << " " << std::setw(2) << n << "   "; }
    std::cout << '\n';
}

可能的输出：

                        █████                               ┬ 0.3753
                        █████                               │
                  ▁▁▁▁▁ █████                               │
                  █████ █████ ▆▆▆▆▆                         │
                  █████ █████ █████                         │
                  █████ █████ █████                         │
            ▄▄▄▄▄ █████ █████ █████ ▄▄▄▄▄                   │
▁▁▁▁▁ ▃▃▃▃▃ █████ █████ █████ █████ █████ ▃▃▃▃▃ ▁▁▁▁▁ ▁▁▁▁▁ ┴ 0.0049
 -4    -3    -2    -1     0     1     2     3     4     5

外部链接

Weisstein, Eric W. “学生 t 分布”来自 MathWorld--A Wolfram Web Resource 。


std::student_t_distribution<RealType>::max

< cpp‎ | numeric‎ | random‎ | student t distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::student_t_distribution<RealType>::min

< cpp‎ | numeric‎ | random‎ | student t distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::student_t_distribution<RealType>::n

< cpp‎ | numeric‎ | random‎ | student t distribution
RealType n() const; | (C++11 起)

返回构造分布所用的 n 分布参数（自由度数）。默认值为 1.0 。

参数

（无）

返回值

标识分布自由度的浮点值。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::student_t_distribution<RealType>::operator()

< cpp‎ | numeric‎ | random‎ | student t distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::student_t_distribution)

< cpp‎ | numeric‎ | random‎ | student t distribution

friend bool operator==( const student_t_distribution& lhs, const student_t_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const student_t_distribution& lhs, const student_t_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::student_t_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::student_t_distribution)

< cpp‎ | numeric‎ | random‎ | student t distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const student_t_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

student_t_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::student_t_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::student_t_distribution<RealType>::param

< cpp‎ | numeric‎ | random‎ | student t distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::student_t_distribution<RealType>::reset

< cpp‎ | numeric‎ | random‎ | student t distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::student_t_distribution<RealType>::student_t_distribution

< cpp‎ | numeric‎ | random‎ | student t distribution
student_t_distribution() : student_t_distribution(1) {} | (1) | (C++11 起)
explicit student_t_distribution( RealType n ); | (2) | (C++11 起)
explicit student_t_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。 (2) 以 n 为分布参数， (3) 以 params 为分布参数。

参数

n | - | n 分布参数（自由度）
params | - | 分布参数集

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::subtract_with_carry_engine

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class UIntType, std::size_t w, std::size_t s, std::size_t r > class subtract_with_carry_engine; | (C++11 起)

subtract_with_carry_engine 是使用带进位减法算法的随机数引擎。

subtract_with_carry_engine 的状态由序列 \(\small{\{ X_i\}(0 \le i <r)}\){X
i} (0 ≤ i <r) 组成，每个 \(\small{X_i}\)X
i 均在区间 \(\small{[0, 2^w)}\)[0, 2w
) 中。

令所有应用到序列的下标都对 r 取余， c 为进位值 0 或 1 。状态迁移按下列方式进行：

  • 令 \(\small{Y=X_{i-s}-X_{i-r}-c}\)Y=X
    i-s    -X
    i-r    -c     ，
  • 设置 \(\small{X_i}\)X
    i     为 \(\small{Y \mod 2^w}\)Y mod 2w
     ，若 \(\small{Y<0}\)Y<0 则设置 c 为 1 ，否则设置为 0 。

下列 typedef 定义拥有二个常用参数集的随机数引擎：

定义于头文件 <random>
类型 | 定义
ranlux24_base(C++11) | std::subtract_with_carry_engine< std::uint_fast32_t, 24, 10, 24>
ranlux48_base(C++11) | std::subtract_with_carry_engine< std::uint_fast64_t, 48, 5, 12>

模板形参

UIntType | - | 生成器所生成的结果类型。若它不是 unsigned short 、 unsigned int 、 unsigned long 或 unsigned long long 之一则效果未定义。
w | - | 状态序列按位计的字大小， 0 < w <= std::numeric_limits <UIntType>::digits
s | - | 短延迟
r | - | 长延迟，其中 0 < s < r

成员类型

成员类型 | 定义
result_type(C++11) | 引擎生成的整数类型。若此非无符号整数类型则结果未定义。

成员函数

构造与播种
(构造函数)
(C++11)
 构造引擎
(公开成员函数)
seed
(C++11)
 设置引擎的当前状态
(公开成员函数)
生成
operator()
(C++11)
 推进引擎状态并返回生成的值
(公开成员函数)
discard
(C++11)
 令引擎状态前进指定量
(公开成员函数)
特征
min
[静态]
 获取输出范围中的最小可能值
(公开静态成员函数)
max
[静态]
 获取输出范围中的最大可能值
(公开静态成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个伪随机数引擎的内部状态 (函数)
operator<<operator>> (C++11) | 执行伪随机数引擎的流输入和输出 (函数)

成员常量

constexpr size_t word_size [静态] (C++11) | 模板形参 w ，字大小 (公开静态成员常量)
constexpr size_t short_lag [静态] (C++11) | 模板形参 s ，短延迟 (公开静态成员常量)
constexpr size_t long_lag [静态] (C++11) | 模板形参 r ，长延迟 (公开静态成员常量)
constexpr UIntType default_seed [静态] (C++11) | 常数值 19780503u (公开静态成员常量)


std::subtract_with_carry_engine<UIntType,w,s,r>::discard

< cpp‎ | numeric‎ | random‎ | subtract with carry engine

void discard( unsigned long long z ); | (C++11 起)

令内部状态前进 z 次。等价于调用 operator() z 次并舍弃结果。

参数

z - 指定状态前进次数的整数值

返回值

（无）

复杂度

本节未完成

注意

对于某些引擎，“快速跳转”算法已知，它们能令状态前进许多步（以百万计）而无需计算中间状态迁移，尽管不需要在常数时间内。

参阅

operator()
(C++11)
 推进引擎状态并返回生成的值
(公开成员函数)


std::subtract_with_carry_engine<UIntType,w,s,r>::max

< cpp‎ | numeric‎ | random‎ | subtract with carry engine

static constexpr result_type max(); | (C++11 起)

返回随机数引擎潜在生成的最大值。此值等于 2w
 - 1 ，其中 w 是模板形参，它亦可作为静态成员 word_size 访问。

参数

（无）

返回值

最大潜在生成值。

复杂度

常数

参阅

min
[静态]
 获取输出范围中的最小可能值
(公开静态成员函数)


std::subtract_with_carry_engine<UIntType,w,s,r>::min

< cpp‎ | numeric‎ | random‎ | subtract with carry engine

static constexpr result_type min(); | (C++11 起)

返回随机数引擎潜在生成的最小值。此值等于 0u 。

参数

（无）

返回值

最小的潜在生成值。

复杂度

常数

参阅

max
[静态]
 获取输出范围中的最大可能值
(公开静态成员函数)


std::subtract_with_carry_engine<UIntType,w,s,r>::operator()

< cpp‎ | numeric‎ | random‎ | subtract with carry engine

result_type operator()(); | (C++11 起)

生成伪随机数。令引擎状态前进一个位置。

本节未完成

参数

（无）

返回值

[min(), max()] 中的伪随机数。

复杂度

均摊常数。

参阅

discard
(C++11)
 令引擎状态前进指定量
(公开成员函数)


operator==,!=(std::subtract_with_carry_engine)

< cpp‎ | numeric‎ | random‎ | subtract with carry engine

friend bool operator==( const subtract_with_carry_engine& lhs, const subtract_with_carry_engine& rhs ); | (1) | (C++11 起)
friend bool operator!=( const subtract_with_carry_engine& lhs, const subtract_with_carry_engine& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个伪随机数引擎。若其内部状态等价，即对任何数量的 operator() 调用都会生成相等的值，则二个引擎相等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::subtract_with_carry_engine<UIntType,w,s,r> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的引擎

返回值

1) 若引擎等价则为 true ，否则为 false 。
2) 若引擎不等价则为 true ，否则为 false 。

异常

不抛出。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::subtract_with_carry_engine)

< cpp‎ | numeric‎ | random‎ | subtract with carry engine

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const subtract_with_carry_engine& e );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

subtract_with_carry_engine& e );
 (2) (C++11 起)
1) 序列化伪随机数引擎 e 的内部状态为一或多个空格分隔的十进制数序列，并插入之到流 ost 。填充字符和格式化标志被忽略且无效。
2) 从先前用拥有相同感染的本地环境，和相同 CharT 与 Traits 的流调用 operator<< ，生成的序列化表示还原伪随机数引擎 e 的内部状态。若不能反序列化输入，则保留 e 不改变并在 ist 上引发 failbit 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::subtract_with_carry_engine<UIntType,w,s,r> 为参数的关联类时由实参依赖查找找到。

若用 os << x 写的文本表示，用 is >> y 还原到同类型的同一或不同对象 y ，则 x==y 。

以设置 os.fmtflags 为 ios_base::dec|ios_base::left 并设置填充字符为空格符写文本表示。引擎内部状态的文本表示是一组空格分隔的十进制数。

参数

ost | - | 要插入数据的输出流
ist | - | 要提取数据的输入流
e | - | 伪随机数引擎

返回值

1) ost
2) ist

复杂度

本节未完成

异常

1) 可能抛出实现定义的异常。
2) 设置了 failbit 时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::subtract_with_carry_engine<UIntType,w,s,r>::seed

< cpp‎ | numeric‎ | random‎ | subtract with carry engine

void seed( result_type value = default_seed ); | (1) | (C++11 起)
template< class Sseq > void seed( Sseq& seq ); | (2) | (C++11 起)

用新种子值重初始化随机数引擎的内部状态。

本节未完成

参数

value | - | 用于内部状态初始化的种子值
seq | - | 用于内部状态初始化的种子序列

异常

不抛出。

复杂度

本节未完成


std::subtract_with_carry_engine<UIntType,w,s,r>::subtract_with_carry_engine

< cpp‎ | numeric‎ | random‎ | subtract with carry engine

subtract_with_carry_engine() : subtract_with_carry_engine(default_seed) {} | (1) | (C++11 起)
explicit subtract_with_carry_engine( result_type value ); | (2) | (C++11 起)
template< class Sseq > explicit subtract_with_carry_engine( Sseq& s ); | (3) | (C++11 起)
subtract_with_carry_engine( const subtract_with_carry_engine& ); | (4) | (C++11 起) (隐式声明)

构造伪随机数引擎。

1) 默认构造函数。以 default_seed 播种引擎。
本节未完成

仅若 Sseq 符合重载种子序列 (SeedSequence) ， (3) 才参与重载决议。尤其是若 Sseq 可转换为 result_type ，则从候选函数集中排除该重载。

参数

value | - | 用于内部状态初始化的种子值
s | - | 用于内部状态初始化的种子序列

复杂度

本节未完成

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式

参阅

seed
(C++11)
 设置引擎的当前状态
(公开成员函数)


std::uniform_int_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class IntType = int > class uniform_int_distribution; | (C++11 起)

生成随机整数值 \(\small i\)i ，均匀分布于闭区间 \(\small[a, b]\)[a, b] ，即按照以下离散概率函数分布

\({\small P(i|a,b) =}\frac{1}{b - a + 1}\)P(i|a,b) =
1
b − a + 1
。

std::uniform_int_distribution 满足随机数分布 (RandomNumberDistribution) 的所有要求。

模板形参

IntType - 生成器所生成的结果类型。若它不是 short 、 int 、 long 、 long long 、 unsigned short 、 unsigned int 、 unsigned long 或 unsigned long long 之一则效果未定义。

成员类型

成员类型 | 定义
result_type(C++11) | IntType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
ab
 返回分布参数
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

此程序模拟 6 面骰子。

#include <random>
#include <iostream>

int main()
{
    std::random_device rd;  // 将用于为随机数引擎获得种子
    std::mt19937 gen(rd()); // 以播种标准 mersenne_twister_engine
    std::uniform_int_distribution<> dis(1, 6);

    for (int n=0; n<10; ++n)
        // 用 dis 变换 gen 所生成的随机 unsigned int 到 [1, 6] 中的 int
        std::cout << dis(gen) << ' ';
    std::cout << '\n';
}

可能的输出：

1 1 6 5 2 2 5 5 6 2


std::uniform_int_distribution<IntType>::max

< cpp‎ | numeric‎ | random‎ | uniform int distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::uniform_int_distribution<IntType>::min

< cpp‎ | numeric‎ | random‎ | uniform int distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::uniform_int_distribution<IntType>::operator()

< cpp‎ | numeric‎ | random‎ | uniform int distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::uniform_int_distribution)

< cpp‎ | numeric‎ | random‎ | uniform int distribution

friend bool operator==( const uniform_int_distribution& lhs, const uniform_int_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const uniform_int_distribution& lhs, const uniform_int_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::uniform_int_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::uniform_int_distribution)

< cpp‎ | numeric‎ | random‎ | uniform int distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const uniform_int_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

uniform_int_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::uniform_int_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::uniform_int_distribution<IntType>::param

< cpp‎ | numeric‎ | random‎ | uniform int distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::uniform_int_distribution<IntType>::a, b

< cpp‎ | numeric‎ | random‎ | uniform int distribution
result_type a() const; | (1) | (C++11 起)
result_type b() const; | (2) | (C++11 起)

返回构造分布所用的参数集。

1) 返回 a 分布参数。它定义最小的可能生成值。默认值是 ​0​ 。
2) 返回 b 分布参数。它定义最大的可能生成值。默认值是 std::numeric_limits <IntType>::max() 。

参数

（无）

返回值

1) a 分布参数。
2) b 分布参数。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::uniform_int_distribution<IntType>::reset

< cpp‎ | numeric‎ | random‎ | uniform int distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::uniform_int_distribution<IntType>::uniform_int_distribution

< cpp‎ | numeric‎ | random‎ | uniform int distribution
uniform_int_distribution() : uniform_int_distribution(0) { } | (1) | (C++11 起)
explicit uniform_int_distribution( IntType a, IntType b = std::numeric_limits <IntType>::max() ); | (2) | (C++11 起)
explicit uniform_int_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。第一版本以 a 和 b 为分布参数，第二版本以 params 为分布参数。

若 a>b 则行为未定义。

参数

a | - | a 分布参数（最小值）
b | - | b 分布参数（最大值）
params | - | 分布参数集

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::uniform_random_bit_generator

< cpp‎ | numeric‎ | random
定义于头文件 <random>
template <class G>

concept uniform_random_bit_generator =
std::invocable<G&> && std::unsigned_integral<std::invoke_result_t<G&>> &&
requires {
{ G::min() } -> std::same_as<std::invoke_result_t<G&>>;
{ G::max() } -> std::same_as<std::invoke_result_t<G&>>;
requires std::bool_constant <(G::min() < G::max())>::value;

};
 (C++20 起)

概念 uniform_random_bit_generator<G> 指定 G 为均匀随机位生成器的类型，即 G 类型对象是函数对象，返回无符号整数值，并使得可能结果范围中的每个值（理论上）拥有相等的被返回概率。

语义要求

uniform_random_bit_generator<G> 仅若符合下列条件才得到实现。给定 G 类型对象 g ：

  • g() 在范围 [G::min(), G::max()] 中
  • g() 拥有均摊常数复杂度

注解

requires std::bool_constant <(G::min() < G::max())>::value; 要求仅若 G::min() 与 G::max() 均为常量表达式，且比较结果为 true 才得到满足。


std::uniform_real_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class RealType = double > class uniform_real_distribution; | (C++11 起)

产生均匀分布在区间 \(\small [a, b)\)[a, b) 上的随机浮点值 \(\small x\)x ，分布按照概率密度函数：

\({\small P(x|a,b) =} \frac{1}{b-a}\)P(x|a,b) =
1
b − a
。

std::uniform_real_distribution 满足随机数分布 (RandomNumberDistribution) 的所有要求。

模板形参

RealType - 生成器所生成的结果类型。若它不是 float 、 double 或 long double 之一则效果未定义。

成员类型

成员类型 | 定义
result_type(C++11) | RealType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
ab
 返回分布参数
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

注解

为创建闭区间 \(\small[a, b]\)[a, b] 上的分布，可以 std::nextafter (b, std::numeric_limits <RealType>::max()) 为第二参数。

某些既存实现拥有漏洞，若 RealType 为 float 则它们有时返回 \(\small b\)b GCC #63176 LLVM #18767 MSVC STL #1074 。此为 LWG 问题 2524 所导致。

示例

打印 10 个 1 与 2 间的随机数

#include <random>
#include <iostream>

int main()
{
    std::random_device rd;  // 将用于获得随机数引擎的种子
    std::mt19937 gen(rd()); // 以 rd() 播种的标准 mersenne_twister_engine
    std::uniform_real_distribution<> dis(1, 2);
    for (int n = 0; n < 10; ++n) {
        // 用 dis 变换 gen 生成的随机 unsigned int 为 [1, 2) 中的 double
        std::cout << dis(gen) << ' '; // 每次调用 dis(gen) 都生成新的随机 double
    }
    std::cout << '\n';
}

可能的输出：

1.80829 1.15391 1.18483 1.38969 1.36094 1.0648 1.97798 1.27984 1.68261 1.57326


std::uniform_real_distribution<RealType>::max

< cpp‎ | numeric‎ | random‎ | uniform real distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::uniform_real_distribution<RealType>::min

< cpp‎ | numeric‎ | random‎ | uniform real distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::uniform_real_distribution<RealType>::operator()

< cpp‎ | numeric‎ | random‎ | uniform real distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::uniform_real_distribution)

< cpp‎ | numeric‎ | random‎ | uniform real distribution

friend bool operator==( const uniform_real_distribution& lhs, const uniform_real_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const uniform_real_distribution& lhs, const uniform_real_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::uniform_real_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::uniform_real_distribution)

< cpp‎ | numeric‎ | random‎ | uniform real distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const uniform_real_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

uniform_real_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::uniform_real_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::uniform_real_distribution<RealType>::param

< cpp‎ | numeric‎ | random‎ | uniform real distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::uniform_real_distribution<RealType>::a, b

< cpp‎ | numeric‎ | random‎ | uniform real distribution
result_type a() const; | (1) | (C++11 起)
result_type b() const; | (2) | (C++11 起)

返回创建分布所用的参数。

1) 返回 a 分布参数。它定义可能生成的最小值。默认值为 0.0 。
2) 返回 b 分布参数。它定义可能生成的最大值。默认值为 1.0 。

参数

（无）

返回值

1) a 分布参数。
2) b 分布参数。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::uniform_real_distribution<RealType>::reset

< cpp‎ | numeric‎ | random‎ | uniform real distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::uniform_real_distribution<RealType>::uniform_real_distribution

< cpp‎ | numeric‎ | random‎ | uniform real distribution
uniform_real_distribution() : uniform_real_distribution(0.0) { } | (1) | (C++11 起)
explicit uniform_real_distribution( RealType a, RealType b = 1.0 ); | (1) | (C++11 起)
explicit uniform_real_distribution( const param_type& params ); | (2) | (C++11 起)

构造新的分布对象。第一版本以 a 和 b 为分布参数，第二版本以 params 为分布参数。

参数

a | - | a 分布参数（最小值）
b | - | b 分布参数（最大值）
params | - | 分布参数集

注意

要求 a ≤ b 且 b-a ≤ std::numeric_limits<RealType>::max() 。

若 a == b ，则后继调用 operator() 的不接受 param_type 对象的重载将导致未定义行为。

为创建闭区间 [a,b] 上的分布，可以 std::nextafter (b, std::numeric_limits <RealType>::max()) 为第二参数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::weibull_distribution

< cpp‎ | numeric‎ | random
定义于头文件 <random> |
template< class RealType = double > class weibull_distribution; | (C++11 起)

weibull_distribution 满足随机数分布 (RandomNumberDistribution) 并产生服从威布尔分布的随机数。

\(\small{f(x;a,b)=\frac{a}{b}{(\frac{x}{b})}^{a-1}\exp{(-{(\frac{x}{b})}^{a})} }\)f(x;a,b) =
a
b
⎛
⎜
⎝
x
b
⎞
⎟
⎠a-1
 exp⎛
⎜
⎝-⎛
⎜
⎝
x
b
⎞
⎟
⎠a
⎞
⎟
⎠

a 为形状参数而 b 为尺度参数。

模板形参

RealType - 生成器所生成的结果类型。若它不是 float 、 double 或 long double 之一则效果未定义。

成员类型

成员类型 | 定义
result_type | RealType
param_type(C++11) | 参数集的类型，见随机数分布 (RandomNumberDistribution) 。

成员函数

(构造函数)
(C++11)
 构造新分布
(公开成员函数)
reset
(C++11)
 重置分布的内部状态
(公开成员函数)
生成
operator()
(C++11)
 生成分布中的下个随机数
(公开成员函数)
特征
ab
 返回分布参数
(公开成员函数)
param
(C++11)
 获取或设置随机参数对象
(公开成员函数)
min
(C++11)
 返回最小的潜在生成值
(公开成员函数)
max
(C++11)
 返回最大的潜在生成值
(公开成员函数)

非成员函数

operator==operator!= (C++11)(C++11)(C++20 中移除) | 比较两个分布对象 (函数)
operator<<operator>> (C++11) | 执行伪随机数分布的流输入和输出 (函数模板)

示例

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <cmath>
int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());

    std::weibull_distribution<> d;

    std::map<int, int> hist;
    for(int n=0; n<10000; ++n) {
        ++hist[std::round(d(gen))];
    }
    for(auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

可能的输出：

 0 *******************
 1 *******************
 2 ******
 3 **
 4
 5
 6
 7
 8

外部链接

  • Weisstein, Eric W. “威布尔分布”来自 MathWorld--A Wolfram Web Resource 。
  • 威布尔分布来自维基百科。


std::weibull_distribution<RealType>::max

< cpp‎ | numeric‎ | random‎ | weibull distribution

result_type max() const; | (C++11 起)

返回分布潜在生成的最大值。

参数

（无）

返回值

分布潜在生成的最大值。

复杂度

常数。

参阅

min
(C++11)
 返回最小的潜在生成值
(公开成员函数)


std::weibull_distribution<RealType>::min

< cpp‎ | numeric‎ | random‎ | weibull distribution

result_type min() const; | (C++11 起)

返回分布潜在生成的最小值。

参数

（无）

返回值

分布潜在生成的最小值

复杂度

常数。

参阅

max
(C++11)
 返回最大的潜在生成值
(公开成员函数)


std::weibull_distribution<RealType>::operator()

< cpp‎ | numeric‎ | random‎ | weibull distribution

template< class Generator > result_type operator()( Generator& g ); | (1) | (C++11 起)
template< class Generator > result_type operator()( Generator& g, const param_type& params ); | (2) | (C++11 起)

根据关联的概率分布函数生成随机数。由调用 g.operator() 获得熵。

第一版本使用关联的参数集，第二版本用 params 。不修改关联参数集。

参数

g | - | 均匀随机位生成器对象
params | - | 用于替代被关联者的分布参数集
类型要求
- Generator 必须满足均匀随机位生成器 (UniformRandomBitGenerator) 的要求。

返回值

生成的随机数。

复杂度

均摊常数次调用 g.operator() 。


operator==,!=(std::weibull_distribution)

< cpp‎ | numeric‎ | random‎ | weibull distribution

friend bool operator==( const weibull_distribution& lhs, const weibull_distribution& rhs ); | (1) | (C++11 起)
friend bool operator!=( const weibull_distribution& lhs, const weibull_distribution& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个分布对象。参数值和内部状态相同时二个分布对象相等。

1) 比较二个分布对象是否相等。
2) 比较二个分布对象是否不等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::weibull_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的分布对象

返回值

1) 若分布对象相等则为 true ，否则为 false 。
2) 若分布对象不相等则为 true ，否则为 false 。

复杂度

常数。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 相等运算符的形式未指定 | 指定为隐藏友元


operator<<,>>(std::weibull_distribution)

< cpp‎ | numeric‎ | random‎ | weibull distribution

template< class CharT, class Traits >

friend std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& ost,

const weibull_distribution& d );
 (1) (C++11 起)
template< class CharT, class Traits >

friend std::basic_istream <CharT,Traits>&
operator>>( std::basic_istream <CharT,Traits>& ist,

weibull_distribution& d );
 (2) (C++11 起)

在伪随机数分布 d 上进行流输入与输出。

1) 将分布参数和内部状态作为文本表示写入 ost 。不更改 ost 的格式化标志和填充字符。
2) 以读取自 ist 的数据恢复分布参数和内部状态。不更改 ist 的格式化标志。数据必须用拥有相同本地环境、 CharT 和 Traits 模板形参的流写入，否则行为未定义。若遇到坏输入，则调用 ist.setstate(std::ios::failbit) ，它可能抛出 std::ios_base::failure 。该情况下不更改 d 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::weibull_distribution<ResultType> 为参数的关联类时由实参依赖查找找到。

参数

ost | - | 插入数据到的输出流
ist | - | 提取数据来源的输入流
d | - | 伪随机数分布

返回值

1) ost
2) ist

异常

1) 可能抛出实现定义的异常。
2) 输入错误时可能抛出 std::ios_base::failure 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3519 | C++11 | 插入与提取运算符的形式未指定 | 指定为隐藏友元


std::weibull_distribution<RealType>::param

< cpp‎ | numeric‎ | random‎ | weibull distribution

param_type param() const; | (1) | (C++11 起)
void param( const param_type& params ); | (2) | (C++11 起)

管理关联的参数集。

1) 返回关联的参数集。

2) 设置关联的参数集为 params 。

参数

params - 关联参数集的新内容

返回值

1) 关联参数集

2) （无）

复杂度

常数。


std::weibull_distribution<RealType>::a, b

< cpp‎ | numeric‎ | random‎ | weibull distribution
RealType a() const; | (1) | (C++11 起)
RealType b() const; | (2) | (C++11 起)

返回构造分布所用的参数。

1) 返回 a 参数。它定义分布的形状。默认值为 1.0 。
2) 返回 b 参数。它定义分布的尺度。默认值为 1.0 。

参数

（无）

返回值

1) a 参数的值。
2) b 参数的值。

复杂度

常数。

参阅

param
(C++11)
 获取或设置随机参数对象
(公开成员函数)


std::weibull_distribution<RealType>::reset

< cpp‎ | numeric‎ | random‎ | weibull distribution

void reset(); | (C++11 起)

重置分布对象的内部状态。调用此函数后，下次在分布对象上到 operator() 的调用将不依赖于先前到 operator() 的调用。

参数

（无）

返回值

（无）

复杂度

常数。


std::weibull_distribution<RealType>::weibull_distribution

< cpp‎ | numeric‎ | random‎ | weibull distribution
weibull_distribution() : weibull_distribution(1.0) {} | (1) | (C++11 起)
explicit weibull_distribution( RealType a, RealType b = 1.0 ); | (2) | (C++11 起)
explicit weibull_distribution( const param_type& params ); | (3) | (C++11 起)

构造新的分布对象。 (2) 以 a 和 b 为分布参数。 (3) 以 params 为分布参数。

参数

a | - | a 分布参数（形状）
b | - | b 分布参数（尺度）
params | - | 分布参数集

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


编译时有理数算术

< cpp‎ | numeric

类模板 std::ratio 及相关的模板提供编译时有理数算术支持。此模板的每个实例化都准确表示任一有限有理数。

编译时分数

定义于头文件 <ratio>
ratio
 表示准确的分数
(类模板)

标准库为提供数种对应 SI 比例的便利 typedef ：

定义于头文件 <ratio>
类型 | 定义
yocto | std::ratio <1, 1000000000000000000000000> ，若 std::intmax_t 能表示分母
zepto | std::ratio <1, 1000000000000000000000> ，若 std::intmax_t 能表示分母
atto | std::ratio <1, 1000000000000000000>
femto | std::ratio <1, 1000000000000000>
pico | std::ratio <1, 1000000000000>
nano | std::ratio <1, 1000000000>
micro | std::ratio <1, 1000000>
milli | std::ratio <1, 1000>
centi | std::ratio <1, 100>
deci | std::ratio <1, 10>
deca | std::ratio <10, 1>
hecto | std::ratio <100, 1>
kilo | std::ratio <1000, 1>
mega | std::ratio <1000000, 1>
giga | std::ratio <1000000000, 1>
tera | std::ratio <1000000000000, 1>
peta | std::ratio <1000000000000000, 1>
exa | std::ratio <1000000000000000000, 1>
zetta | std::ratio <1000000000000000000000, 1> ，若 std::intmax_t 能表示分子
yotta | std::ratio <1000000000000000000000000, 1> ，若 std::intmax_t 能表示分子

编译时有理数算术

提供数个别名模板，它们在编译时进行 ratio 实例上的算术。

定义于头文件 <ratio>
ratio_add (C++11) | 在编译时相加两个 ratio 对象 (别名模板)
ratio_subtract (C++11) | 在编译时相减两个 ratio 对象 (别名模板)
ratio_multiply (C++11) | 在编译时相乘两个 ratio 对象 (别名模板)
ratio_divide (C++11) | 在编译时相除两个 ratio 对象 (别名模板)

编译时有理数比较

提供数个类模板，它们在编译时进行 ratio 实例上的比较运算。

定义于头文件 <ratio>
ratio_equal (C++11) | 在编译时比较两个 ratio 对象的相等性 (类模板)
ratio_not_equal (C++11) | 在编译时比较两个 ratio 对象的不相等性 (类模板)
ratio_less (C++11) | 在编译时比较两个 ratio 对象的小于关系 (类模板)
ratio_less_equal (C++11) | 在编译时比较两个 ratio 对象的小于或等于关系 (类模板)
ratio_greater (C++11) | 在编译时比较两个 ratio 对象的大于关系 (类模板)
ratio_greater_equal (C++11) | 在编译时比较两个 ratio 对象的大于或等于关系 (类模板)


std::ratio

< cpp‎ | numeric‎ | ratio
定义于头文件 <ratio>
template<

std::intmax_t Num,
std::intmax_t Denom = 1

> class ratio;
 (C++11 起)

类模板 std::ratio 及相关的模板提供编译时有理数算术支持。此模板的每个实例化都准确表示任一确定有理数，只要分子 Num 与分母 Denom 能表示为 std::intmax_t 类型的编译时常量。另外， Denom 不可为零且不可等于最负的值。约分分子和分母到最简。

静态数据成员 num 与 den 表示由将 Num 与 Denom 除以其最大公约数的分子与分母。然而，二个有相异的 Num 或 Denom 的 std::ratio 是不同的类型，即使它们表示同一有理数（在约分后）。能经由其 type 成员约分 ratio 类型到最简分数： std::ratio<3, 6>::type 为 std::ratio<1, 2> 。

标准库提供数个对应 SI 比例的便利 typedef ：

定义于头文件 <ratio>
类型 | 定义
yocto | std::ratio<1, 1000000000000000000000000> ，若 std::intmax_t 能表示分母
zepto | std::ratio<1, 1000000000000000000000> ，若 std::intmax_t 能表示分母
atto | std::ratio<1, 1000000000000000000>
femto | std::ratio<1, 1000000000000000>
pico | std::ratio<1, 1000000000000>
nano | std::ratio<1, 1000000000>
micro | std::ratio<1, 1000000>
milli | std::ratio<1, 1000>
centi | std::ratio<1, 100>
deci | std::ratio<1, 10>
deca | std::ratio<10, 1>
hecto | std::ratio<100, 1>
kilo | std::ratio<1000, 1>
mega | std::ratio<1000000, 1>
giga | std::ratio<1000000000, 1>
tera | std::ratio<1000000000000, 1>
peta | std::ratio<1000000000000000, 1>
exa | std::ratio<1000000000000000000, 1>
zetta | std::ratio<1000000000000000000000, 1> ，若 std::intmax_t 能表示分子
yotta | std::ratio<1000000000000000000000000, 1> ，若 std::intmax_t 能表示分子

成员类型

成员类型 | 定义
type | std::ratio<num, den>

成员对象

constexpr intmax_t num [静态] | std::intmax_t 类型的 constexpr 值，等于 sign(Num) * sign(Denom) * abs(Num) / gcd(Num, Denom) (公开静态成员常量)
constexpr intmax_t den [静态] | std::intmax_t 类型的 constexpr 值，等于 abs(Denom) / gcd(Num, Denom) (公开静态成员常量)


std::ratio_add

< cpp‎ | numeric‎ | ratio
定义于头文件 <ratio> |
template< class R1, class R2 > using ratio_add = /* see below */; | (C++11 起)

别名模版 std::ratio_add 指代 std::ratio 的特化 R1 和 R2 所表示的二个准确有理分数的相加结果。

结果是 std::ratio 特化 std::ratio <U, V> ，满足给定 Num == R1::num * R2::den + R2::num * R1::den 与 Denom == R1::den * R2::den （计算无算术溢出）， U 为 std::ratio <Num, Denom>::num 而 V 为 std::ratio <Num, Denom>::den 。

注意

若 U 或 V 不能以 std::intmax_t 表示，则程序为病式。若 Num 或 Denom 不能以 std::intmax_t 表示，则程序为病式，除非实现生成 U 与 V 的正确值。

上述定义要求 std::ratio_add<R1, R2> 的结果已被约分到最简分数；例如， std::ratio_add< std::ratio <1, 3>, std::ratio <1, 6>> 与 std::ratio <1, 2> 是同一类型。

示例

#include <iostream>
#include <ratio>

int main()
{
    using two_third = std::ratio<2, 3>;
    using one_sixth = std::ratio<1, 6>;

    using sum = std::ratio_add<two_third, one_sixth>;
    std::cout << "2/3 + 1/6 = " << sum::num << '/' << sum::den << '\n';
}

输出：

2/3 + 1/6 = 5/6


std::ratio_divide

< cpp‎ | numeric‎ | ratio
定义于头文件 <ratio> |
template< class R1, class R2 > using ratio_divide = /* see below */; | (C++11 起)

别名模板 std::ratio_divide 指代由 std::ratio 特化 R1 和 R2 表示的二个准确有理分数相除的结果。

结果是 std::ratio 特化 std::ratio <U, V> ，给定 Num == R1::num * R2::den 及 Denom == R1::den * R2::num （计算无算术溢出），则 U 为 std::ratio <Num, Denom>::num 且 V 为 std::ratio <Num, Denom>::den 。

注意

若 U 或 V 不能以 std::intmax_t 表示，则程序为病式。若 Num 或 Denom 不能表示为 std::intmax_t ，则程序为病式，除非实现生成 U 与 V 的正确值。

上述定义要求 std::ratio_divide<R1, R2> 的结果已约分到最简；例如， std::ratio_divide< std::ratio <1, 12>, std::ratio <1, 6>> 与 std::ratio <1, 2> 是同一类型。

示例

#include <iostream>
#include <ratio>

int main()
{
    using two_third = std::ratio<2, 3>;
    using one_sixth = std::ratio<1, 6>;
    using quotient = std::ratio_divide<two_third, one_sixth>;
    std::cout << "(2/3) / (1/6) = " << quotient::num << '/' << quotient::den << '\n';
}

输出：

(2/3) / (1/6) = 4/1


std::ratio_equal

< cpp‎ | numeric‎ | ratio
定义于头文件 <ratio> |
template< class R1, class R2 > struct ratio_equal : std::integral_constant <bool, /* see below */> { }; | (C++11 起)

若比例 R1 与 R2 相等，则提供等于 true 的成员常量 value 。否则 value 等于 false 。

辅助变量模板

template< class R1, class R2 > inline constexpr bool ratio_equal_v = ratio_equal<R1, R2>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 R1::num == R2::num && R1::den == R2::den 则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template< class R1, class R2 >
struct ratio_equal : public std::integral_constant <
                                 bool,
                                 R1::num == R2::num && R1::den == R2::den
                            > {};

示例

#include <iostream>
#include <ratio>

int main()
{
    if(std::ratio_equal<std::ratio<2,3>, std::ratio<4,6>>::value) {
        std::cout << "2/3 == 4/6\n";
    } else {
        std::cout << "2/3 != 4/6\n";
    }
}

输出：

2/3 == 4/6

参阅


std::ratio_greater

< cpp‎ | numeric‎ | ratio
定义于头文件 <ratio> |
template< class R1, class R2 > struct ratio_greater : std::integral_constant <bool, /* see below */> { }; | (C++11 起)

若比例 R1 大于比例 R2 ，则提供等于 true 的成员常量 value 。否则 value 等于 false 。

辅助变量模板

template< class R1, class R2 > inline constexpr bool ratio_greater_v = ratio_greater<R1, R2>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 R1::num * R2::den > R2::num * R1::den 或避免溢出的等价表达式，则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <ratio>
#include <iostream>

auto main() -> int
{
    static_assert(std::ratio_greater<std::ratio<3, 4>, std::ratio<1, 2>>::value,
                  "3/4 > 1/2");

    if (std::ratio_greater<std::ratio<11, 12>, std::ratio<10, 11>>::value) {
        std::cout << "11/12 > 10/11" "\n";
    }

    // Since C++17
    static_assert(std::ratio_greater_v<std::ratio<12, 13>, std::ratio<11, 12>> );

    if constexpr (std::ratio_greater_v<std::ratio<12, 13>, std::ratio<11, 12>>) {
        std::cout << "12/13 > 11/12" "\n";
    }
}

输出：

11/12 > 10/11
12/13 > 11/12

参阅


std::ratio_greater_equal

< cpp‎ | numeric‎ | ratio
定义于头文件 <ratio> |
template< class R1, class R2 > struct ratio_greater_equal : std::integral_constant <bool, /* see below */> { }; | (C++11 起)

若比例 R1 大于或等于比例 R2 ，则提供等于 true 的成员常量 value 。否则 value 等于 false 。

辅助变量模板

template< class R1, class R2 > inline constexpr bool ratio_greater_equal_v = ratio_greater_equal<R1, R2>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 R1::num * R2::den >= R2::num * R1::den 或避免溢出的等价表达式成立，则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <ratio>
#include <iostream>

auto main() -> int
{
    static_assert(std::ratio_greater_equal<
        std::ratio<2, 3>,
        std::ratio<2, 3>>::value, "2/3 >= 2/3");

    if (std::ratio_greater_equal<
        std::ratio<2,1>, std::ratio<1, 2>>::value) {
        std::cout << "2/1 >= 1/2" "\n";
    }

    if (std::ratio_greater_equal<
        std::ratio<1,2>, std::ratio<1, 2>>::value) {
        std::cout << "1/2 >= 1/2" "\n";
    }

    // C++17 起
    static_assert(std::ratio_greater_equal_v<
        std::ratio<999'999, 1'000'000>,
        std::ratio<999'998, 999'999>> );

    if constexpr (std::ratio_greater_equal_v<
        std::ratio<999'999, 1'000'000>,
        std::ratio<999'998, 999'999>>) {
        std::cout << "999'999/1'000'000 >= 999'998/999'999" "\n";
    }
    if constexpr (std::ratio_greater_equal_v<
        std::ratio<999'999, 1'000'000>,
        std::ratio<999'999, 1'000'000>>) {
        std::cout << "999'999/1'000'000 >= 999'999/1'000'000" "\n";
    }
}

输出：

2/1 >= 1/2
1/2 >= 1/2
999'999/1'000'000 >= 999'998/999'999
999'999/1'000'000 >= 999'999/1'000'000

参阅


std::ratio_less

< cpp‎ | numeric‎ | ratio
定义于头文件 <ratio> |
template< class R1, class R2 > struct ratio_less : std::integral_constant <bool, /* see below */> { }; | (C++11 起)

若比例 R1 小于比例 R2 ，则提供等于 true 的成员常量 value 。否则 value 等于 false 。

辅助变量模板

template< class R1, class R2 > inline constexpr bool ratio_less_v = ratio_less<R1, R2>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 R1::num * R2::den < R2::num * R1::den 或避免溢出的等价表达式，则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <iostream>
#include <ratio>

int main()
{
    if (std::ratio_less<std::ratio<23,37>, std::ratio<57,90>>::value) {
        std::cout << "23/37 < 57/90\n";
    }
}

输出：

23/37 < 57/90

参阅


std::ratio_less_equal

< cpp‎ | numeric‎ | ratio
定义于头文件 <ratio> |
template< class R1, class R2 > struct ratio_less_equal : std::integral_constant <bool, /* see below */> { }; | (C++11 起)

若比例 R1 小于或等于比例 R2 ，则提供等于 true 的成员常量 value 。否则 value 等于 false 。

辅助变量模板

template< class R1, class R2 > inline constexpr bool ratio_less_equal_v = ratio_less_equal<R1, R2>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 R1::num * R2::den <= R2::num * R1::den 或避免溢出的等价表达式，则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <ratio>
#include <iostream>

auto main() -> int
{
    static_assert(std::ratio_less_equal<std::ratio<1, 2>, std::ratio<3, 4>>::value,
                  "1/2 <= 3/4");

    if (std::ratio_less_equal<std::ratio<10,11>, std::ratio<11,12>>::value) {
        std::cout << "10/11 <= 11/12" "\n";
    }

    // C++17 起
    static_assert(std::ratio_less_equal_v<std::ratio<10, 11>, std::ratio<11, 12>> );

    if constexpr (std::ratio_less_equal_v<std::ratio<10, 11>, std::ratio<11, 12>>) {
        std::cout << "11/12 <= 12/13" "\n";
    }
}

输出：

10/11 <= 11/12
11/12 <= 12/13

参阅


std::ratio_multiply

< cpp‎ | numeric‎ | ratio
定义于头文件 <ratio> |
template< class R1, class R2 > using ratio_multiply = /* see below */; | (C++11 起)

别名模版 std::ratio_multiply 指代二个由 std::ratio 的特化 R1 和 R2 所表示的准确有理分数的相乘结果。

结果是一个 std::ratio 特化 std::ratio <U, V> ，给出 Num == R1::num * R2::num 与 Denom == R1::den * R2::den （计算无算术溢出），则 U 为 std::ratio <Num, Denom>::num 且 V 为 std::ratio <Num, Denom>::den.

注意

若 U 或 V 不能以 std::intmax_t 表示，则程序为病式。若 Num 或 Denom 不能以 std::intmax_t 表示，则程序为病式，除非实现生成 U 与 V 的正确值。

上述定义要求 std::ratio_multiply<R1, R2> 的结果已约分到最简；例如， std::ratio_multiply< std::ratio <1, 6>, std::ratio <4, 5>> 与 std::ratio <2, 15> 是同一类型。

示例

#include <iostream>
#include <ratio>

int main()
{
    using two_third = std::ratio<2, 3>;
    using one_sixth = std::ratio<1, 6>;
    using product = std::ratio_multiply<two_third, one_sixth>;
    std::cout << "2/3 * 1/6 = " << product::num << '/' << product::den << '\n';
}

输出：

2/3 * 1/6 = 1/9


std::ratio_not_equal

< cpp‎ | numeric‎ | ratio
定义于头文件 <ratio> |
template< class R1, class R2 > struct ratio_not_equal : std::integral_constant <bool, /* see below */> { }; | (C++11 起)

若比例 R1 与 R2 不相等，则提供等于 true 的成员常量 value 。否则 value 等于 false 。

辅助变量模板

template< class R1, class R2 > inline constexpr bool ratio_not_equal_v = ratio_not_equal<R1, R2>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 R1::num != R2::num || R1::den != R2::den 则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template< class R1, class R2 >
struct ratio_not_equal : std::integral_constant <
                              bool,
                              !std::ratio_equal<R1, R2>
                         > {};

示例

#include <iostream>
#include <ratio>

int main()
{
    if(std::ratio_not_equal<std::ratio<2,3>, std::ratio<1,3>>::value) {
        std::cout << "2/3 != 1/3\n";
    } else {
        std::cout << "2/3 == 1/3\n";
    }
}

输出：

2/3 != 1/3

参阅


std::ratio_subtract

< cpp‎ | numeric‎ | ratio
定义于头文件 <ratio> |
template< class R1, class R2 > using ratio_subtract = /* see below */; | (C++11 起)

别名模板 std::ratio_subtract 指代二个 std::ratio 特化 R1 和 R2 所表示的准确有理分数相减的结果。

结果是一个 std::ratio 特化 std::ratio <U, V> ，给定 Num == R1::num * R2::den - R2::num * R1::den 和 Denom == R1::den * R2::den （计算无算术溢出）， U 为 std::ratio <Num, Denom>::num 而 V 为 std::ratio <Num, Denom>::den 。

注意

若 U 或 V 不能以 std::intmax_t 表示，则程序为病式。若 Num 或 Denom 不能以 std::intmax_t 表示，则程序为病式，除非实现生成了 U 和 V 的正确值。

上述定义要求 std::ratio_subtract<R1, R2> 的结果已经被约分到最简；例如 std::ratio_subtract< std::ratio <1, 2>, std::ratio <1, 6>> 与 std::ratio <1, 3> 是同一类型。

示例

#include <iostream>
#include <ratio>

int main()
{
    using two_third = std::ratio<2, 3>;
    using one_sixth = std::ratio<1, 6>;

    using diff = std::ratio_subtract<two_third, one_sixth>;
    std::cout << "2/3 - 1/6 = " << diff::num << '/' << diff::den << '\n';
}

输出：

2/3 - 1/6 = 1/2


std::rotl

< cpp‎ | numeric
定义于头文件 <bit> |
template<class T> [[nodiscard]] constexpr T rotl(T x, int s) noexcept; | (C++20 起)

计算将 x 左旋转 s 位的结果。此运算被称为循环移位。

正式而言，令 N 为 std::numeric_limits <T>::digits ， r 为 s % N 。

  • 若 r 为 0 ，则返回 x ；
  • 若 r 为正，则返回 (x << r) | (x >> (N - r)) ；
  • 若 r 为负，则返回 std::rotr(x, -r) 。

此重载仅若 T 为无符号整数类型（即 unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 、 unsigned long long 或扩展无符号整数类型）才参与重载决议。

参数

x - 无符号整数类型的值

返回值

将 x 左旋转 s 位的结果。

示例

#include <bit>
#include <bitset>
#include <cstdint>
#include <iostream>

int main()
{
    std::uint8_t i = 0b00011101;
    std::cout << "i          = " << std::bitset<8>(i) << '\n';
    std::cout << "rotl(i,0)  = " << std::bitset<8>(std::rotl(i,0)) << '\n';
    std::cout << "rotl(i,1)  = " << std::bitset<8>(std::rotl(i,1)) << '\n';
    std::cout << "rotl(i,4)  = " << std::bitset<8>(std::rotl(i,4)) << '\n';
    std::cout << "rotl(i,9)  = " << std::bitset<8>(std::rotl(i,9)) << '\n';
    std::cout << "rotl(i,-1) = " << std::bitset<8>(std::rotl(i,-1)) << '\n';
}

输出：

i          = 00011101
rotl(i,0)  = 00011101
rotl(i,1)  = 00111010
rotl(i,4)  = 11010001
rotl(i,9)  = 00111010
rotl(i,-1) = 10001110

参阅

rotr (C++20) | 计算逐位右旋转的结果 (函数模板)
operator<<=operator>>=operator<<operator>> | 进行二进制左移和右移 (std::bitset<N> 的公开成员函数)


std::rotr

< cpp‎ | numeric
定义于头文件 <bit> |
template<class T> [[nodiscard]] constexpr T rotr(T x, int s) noexcept; | (C++20 起)

计算将 x 右旋转 s 位的结果。此运算被称为循环移位。

正式而言，令 N 为 std::numeric_limits <T>::digits ， r 为 s % N 。

  • 若 r 为 0 ，则返回 x ；
  • 若 r 为正，则返回 (x >> r) | (x << (N - r)) ；
  • 若 r 为负，则返回 std::rotl(x, -r) 。

此重载仅若 T 为无符号整数类型（即 unsigned char 、 unsigned short 、 unsigned int 、 unsigned long 、 unsigned long long 或扩展无符号整数类型）才参与重载决议。

参数

x - 无符号整数类型的值

返回值

将 x 右旋转 s 位的结果。

示例

#include <bit>
#include <bitset>
#include <cstdint>
#include <iostream>

int main()
{
    std::uint8_t i = 0b00011101;
    std::cout << "i          = " << std::bitset<8>(i) << '\n';
    std::cout << "rotr(i,0)  = " << std::bitset<8>(std::rotr(i,0)) << '\n';
    std::cout << "rotr(i,1)  = " << std::bitset<8>(std::rotr(i,1)) << '\n';
    std::cout << "rotr(i,9)  = " << std::bitset<8>(std::rotr(i,9)) << '\n';
    std::cout << "rotr(i,-1) = " << std::bitset<8>(std::rotr(i,-1)) << '\n';
}

输出：

i          = 00011101
rotr(i,0)  = 00011101
rotr(i,1)  = 10001110
rotr(i,9)  = 10001110
rotr(i,-1) = 00111010

参阅

rotl (C++20) | 计算逐位左旋转的结果 (函数模板)
operator<<=operator>>=operator<<operator>> | 进行二进制左移和右移 (std::bitset<N> 的公开成员函数)


数学特殊函数

< cpp‎ | numeric

数学特殊函数库原是库 TR1 ISO/IEC TR 19768:2007 的一部分，后作为独立 ISO 标准， ISO/IEC 29124:2010 出版，最终从 C++17 起并入 ISO C++ 。

此库的 ISO/IEC 29124:2010 版本可参阅数学特殊函数。

函数

定义于头文件 <cmath>
assoc_laguerreassoc_laguerrefassoc_laguerrel (C++17)(C++17)(C++17) | 连带拉盖尔多项式 (函数)
assoc_legendreassoc_legendrefassoc_legendrel (C++17)(C++17)(C++17) | 连带勒让德多项式 (函数)
betabetafbetal (C++17)(C++17)(C++17) | beta 函数 (函数)
comp_ellint_1comp_ellint_1fcomp_ellint_1l (C++17)(C++17)(C++17) | 第一类（完全）椭圆积分 (函数)
comp_ellint_2comp_ellint_2fcomp_ellint_2l (C++17)(C++17)(C++17) | 第二类（完全）椭圆积分 (函数)
comp_ellint_3comp_ellint_3fcomp_ellint_3l (C++17)(C++17)(C++17) | 第三类（完全）椭圆积分 (函数)
cyl_bessel_icyl_bessel_ifcyl_bessel_il (C++17)(C++17)(C++17) | 规则变形圆柱贝塞尔函数 (函数)
cyl_bessel_jcyl_bessel_jfcyl_bessel_jl (C++17)(C++17)(C++17) | （第一类）圆柱贝塞尔函数 (函数)
cyl_bessel_kcyl_bessel_kfcyl_bessel_kl (C++17)(C++17)(C++17) | 不规则变形圆柱贝塞尔函数 (函数)
cyl_neumanncyl_neumannfcyl_neumannl (C++17)(C++17)(C++17) | 圆柱诺依曼函数 (函数)
ellint_1ellint_1fellint_1l (C++17)(C++17)(C++17) | 第一类（不完全）椭圆积分 (函数)
ellint_2ellint_2fellint_2l (C++17)(C++17)(C++17) | 第二类（不完全）椭圆积分 (函数)
ellint_3ellint_3fellint_3l (C++17)(C++17)(C++17) | 第三类（不完全）椭圆积分 (函数)
expintexpintfexpintl (C++17)(C++17)(C++17) | 指数积分 (函数)
hermitehermitefhermitel (C++17)(C++17)(C++17) | 埃尔米特多项式 (函数)
legendrelegendreflegendrel (C++17)(C++17)(C++17) | 勒让德多项式 (函数)
laguerrelaguerreflaguerrel (C++17)(C++17)(C++17) | 拉盖尔多项式 (函数)
riemann_zetariemann_zetafriemann_zetal (C++17)(C++17)(C++17) | 黎曼 zeta 函数 (函数)
sph_besselsph_besselfsph_bessell (C++17)(C++17)(C++17) | （第一类）球面贝塞尔函数 (函数)
sph_legendresph_legendrefsph_legendrel (C++17)(C++17)(C++17) | 球面连带勒让德函数 (函数)
sph_neumannsph_neumannfsph_neumannl (C++17)(C++17)(C++17) | 球面诺依曼函数 (函数)

注解

数学特殊函数的重载在 ISO/IEC 29124:2010 的最终草案（ N3060 ）中存在，但在 C++17/20 中缺失。有些实现不提供这些重载。我们有意认为这些重载的缺失是 C++17/20 中的缺陷。参阅 LWG 问题 3234 。

这些函数与类类型的特殊成员函数无关。

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 26.8.6 Mathematical special functions [sf.cmath]
  • C++17 标准（ISO/IEC 14882:2017）：
  • 29.9.5 Mathematical special functions [sf.cmath]


std::assoc_laguerre, std::assoc_laguerref, std::assoc_laguerrel

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double assoc_laguerre( unsigned int n, unsigned int m, double x );

float assoc_laguerre( unsigned int n, unsigned int m, float x );
long double assoc_laguerre( unsigned int n, unsigned int m, long double x );
float assoc_laguerref( unsigned int n, unsigned int m, float x );

long double assoc_laguerrel( unsigned int n, unsigned int m, long double x );
 (1) (C++17 起)
double assoc_laguerre( unsigned int n, unsigned int m, IntegralType x );
 (2) (C++17 起)
1) 以参数 x 计算 n 次 m 阶关联拉盖尔多项式
2) 接受任意整数类型参数的重载集或函数模板。等价于将参数转型到 double 后的 (1) 。

参数

n | - | 多项式的次数，无符号整数类型值
m | - | 多项式的阶数，无符号整数类型值
x | - | 参数，浮点或整数类型值

返回值

若无错误发生，则返回 x 的关联拉盖尔多项式的值，即 \((-1)^m \: \frac{ \mathsf{d} ^ m}{ \mathsf{d}x ^ m} \, \mathsf{L}_{n+m}(x)\)(-1)m
dm
dxm
L
n+m(x) （其中 \(\mathsf{L}_{n+m}(x)\)L
n+m(x) 是非关联拉盖尔多项式， std::laguerre (n+m, x) ）。

错误处理

可能报告 math_errhandling 中指定的错误。

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 x 为负，则可能出现定义域错误
  • 若 n 或 m 大于或等于 128 ，则行为是实现定义的。

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

关联拉盖尔多项式是方程 \(x\ddot{y} + (m+1-x)\dot{y} + ny = 0\)xy,,
+(m+1-x)y,
+ny = 0 的多项式解

前几个解是：

  • assoc_laguerre(0, m, x) = 1
  • assoc_laguerre(1, m, x) = -x + m + 1
  • assoc_laguerre(2, m, x) =
    1
    2
    [x2
    -2(m+2)x+(m+1)(m+2)]
  • assoc_laguerre(3, m, x) =
    1
    6
    [-x3
    -3(m+3)x2
    -3(m+2)(m+3)x+(m+1)(m+2)(m+3)]

示例

#include <cmath>
#include <iostream>
double L1(unsigned m, double x) { return -x + m + 1; }
double L2(unsigned m, double x) { return 0.5*(x*x-2*(m+2)*x+(m+1)*(m+2)); }
int main()
{
    // 点检查
    std::cout << std::assoc_laguerre(1, 10, 0.5) << '=' << L1(10, 0.5) << '\n'
              << std::assoc_laguerre(2, 10, 0.5) << '=' << L2(10, 0.5) << '\n';
}

输出：

10.5=10.5
60.125=60.125

参阅

laguerrelaguerreflaguerrel
(C++17)(C++17)(C++17)
 拉盖尔多项式
(函数)

外部链接

Weisstein, Eric W. “关联拉盖尔多项式”来自 MathWorld--A Wolfram Web Resource 。


std::assoc_legendre, std::assoc_legendref, std::assoc_legendrel

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double assoc_legendre( unsigned int n, unsigned int m, double x );

float assoc_legendre( unsigned int n, unsigned int m, float x );
long double assoc_legendre( unsigned int n, unsigned int m, long double x );
float assoc_legendref( unsigned int n, unsigned int m, float x );

long double assoc_legendrel( unsigned int n, unsigned int m, long double x );
 (1) (C++17 起)
double assoc_legendre( unsigned int n, unsigned int m, IntegralType x );
 (2) (C++17 起)
1) 以参数 x 计算 n 次 m 阶关联勒让德多项式
2) 接受任何整数类型参数的重载集或函数模板。等价于将参数转型到 double 后的 (1) 。

参数

n | - | 多项式的次数，无符号整数值
m | - | 多项式的阶数，无符号整数值
x | - | 参数，浮点或整数类型值

返回值

若无错误发生，则返回 x 的关联勒让德多项式 \(\mathsf{P}_n^m\)Pm
n 的值，即 \((1 - x^2) ^ {m/2} \: \frac{ \mathsf{d} ^ m}{ \mathsf{d}x ^ m} \, \mathsf{P}_n(x)\)(1-x2
)m/2
dm
dxm
P
n(x) （其中 \(\mathsf{P}_n(x)\)P
n(x) 是非关勒让德多项式 std::legendre (n, x) ）。

注意此定义忽略 Condon-Shortley 相位项 \((-1)^m\)(-1)m
 。

错误处理

可能报告 math_errhandling 中指定的错误。

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 |x| > 1 ，则可能出现定义域错误
  • 若 n 大于或等于 128 ，则行为是实现定义的。

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦作为 boost::math::legendre_p 可用于 boost.math ，除了 boost.math 定义包含 Condon-Shortley 相位项。

前几个关联勒让德多项式是：

  • assoc_legendre(0, 0, x) = 1
  • assoc_legendre(1, 0, x) = x
  • assoc_legendre(1, 1, x) = (1-x2
    )1/2
  • assoc_legendre(2, 0, x) =
    1
    2
    (3x2
    -1)
  • assoc_legendre(2, 1, x) = 3x(1-x2
    )1/2
  • assoc_legendre(2, 2, x) = 3(1-x2
    )

示例

#include <cmath>
#include <iostream>
double P20(double x) { return 0.5*(3*x*x-1); }
double P21(double x) { return -3.0*x*std::sqrt(1-x*x); }
double P22(double x) { return 3*(1-x*x); }
int main()
{
    // 点检查
    std::cout << std::assoc_legendre(2, 0, 0.5) << '=' << P20(0.5) << '\n'
              << std::assoc_legendre(2, 1, 0.5) << '=' << P21(0.5) << '\n'
              << std::assoc_legendre(2, 2, 0.5) << '=' << P22(0.5) << '\n';
}

输出：

-0.125=-0.125
1.29904=1.29904
2.25=2.25

参阅

legendrelegendreflegendrel
(C++17)(C++17)(C++17)
 勒让德多项式
(函数)

外部链接

Weisstein, Eric W. “关联勒让德多项式”来自 MathWorld--A Wolfram Web Resource 。


std::comp_ellint_1, std::comp_ellint_1f, std::comp_ellint_1l

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double comp_ellint_1( double k );

float comp_ellint_1( float k );
long double comp_ellint_1( long double k );
float comp_ellint_1f( float k );

long double comp_ellint_1l( long double k );
 (1) (C++17 起)
double comp_ellint_1( IntegralType k );
 (2) (C++17 起)
1) 计算 k 的第一类完全椭圆积分。
2) 接受任意整数类型参数的重载集或函数模板。等价于将参数转型到 double 后的 (1) 。

参数

k - 椭圆模或离心率（浮点或整数类型值）

返回值

若无错误发生，则返回 k 的第一类完全椭圆积的值，即 ellint_1(k,π/2) 。

错误处理

可能报告 math_errhandling 中指定的错误。

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 |k|>1 ，则可能发生定义域错误

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

给定重力加速度 g ，及初始角 θ ，则长度为 l 的钟摆周期等于 4√l/gK(sin2
(θ/2)) ，其中 K 是 std::comp_ellint_1 。

示例

#include <cmath>
#include <iostream>
int main()
{
    double hpi = std::acos(-1)/2;
    std::cout << "K(0) = " << std::comp_ellint_1(0) << '\n'
              << "π/2 = " << hpi << '\n'
              << "K(0.5) = " << std::comp_ellint_1(0.5) << '\n'
              << "F(0.5, π/2) = " << std::ellint_1(0.5, hpi) << '\n';
    std::cout << "Period of a pendulum length 1 m at 90 degree initial angle is "
              << 4*std::sqrt(1/9.80665)*
                 std::comp_ellint_1(std::pow(std::sin(hpi/2),2)) << " s\n";
}

输出：

K(0) = 1.5708
π/2 = 1.5708
K(0.5) = 1.68575
F(0.5, π/2) = 1.68575
Period of a pendulum length 1 m at 90 degree initial angle is 2.15324 s

外部链接

Weisstein, Eric W. “第一类完全椭圆积分”来自 MathWorld--A Wolfram Web Resource 。

参阅

ellint_1ellint_1fellint_1l
(C++17)(C++17)(C++17)
 第一类（不完全）椭圆积分
(函数)


std::comp_ellint_2, std::comp_ellint_2f, std::comp_ellint_2l

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double comp_ellint_2( double k);

float comp_ellint_2( float k );
long double comp_ellint_2( long double k );
float comp_ellint_2f( float k );

long double comp_ellint_2l( long double k );
 (1) (C++17 起)
double comp_ellint_2( IntegralType k );
 (2) (C++17 起)
1) 计算 k 的第二类完全椭圆积分。
2) 接受任意整数类型参数的重载集或函数模板。等价于将参数转型到 double 后的 (1) 。

参数

k - 椭圆模或离心率（浮点或整数类型值）

返回值

若无错误发生，则返回 k 的第二类完全椭圆积的值，即 ellint_2(k,π/2) 。

错误处理

可能报告 math_errhandling 中指定的错误。

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 |k|>1 ，则可能发生定义域错误

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

离心率为 k 半长轴为 a 的椭圆的周长等于 4aE(k) ，其中 E 为 std::comp_ellint_2 。离心率等于 0 时，椭圆退化为半径为 a 的圆，而周长等于 2πa ，故 E(0) = π/2 。离心率等于 1 时，椭圆退化成长度为 2a 的线段，其周长为 4a ，故 E(1) = 1 。

示例

#include <cmath>
#include <iostream>
int main()
{
    double hpi = std::acos(-1)/2;
    std::cout << "E(0) = " << std::comp_ellint_2(0) << '\n'
              << "π/2 = " << hpi << '\n'
              << "E(1) = " << std::comp_ellint_2(1) << '\n'
              << "E(1, π/2) = " << std::ellint_2(1, hpi) << '\n';
}

输出：

E(0) = 1.5708
π/2 = 1.5708
E(1) = 1
E(1, π/2) = 1

外部链接

Weisstein, Eric W. “第二类完全椭圆积分”来自 MathWorld--A Wolfram Web Resource 。

参阅

ellint_2ellint_2fellint_2l
(C++17)(C++17)(C++17)
 第二类（不完全）椭圆积分
(函数)


std::comp_ellint_3, std::comp_ellint_3f, std::comp_ellint_3l

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double comp_ellint_3( double k, double n );

float comp_ellint_3f( float k, float n );

long double comp_ellint_3l( long double k, long double n );
 (1) (C++17 起)
Promoted comp_ellint_3( Arithmetic k, Arithmetic n );
 (2) (C++17 起)
1) 计算参数 k 与 n 的第三类完全椭圆积分。
2) 对于所有 (1) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则它被转型到 double 。若任何参数为 long double ，则返回类型 Promoted 亦为 long double ，否则返回类型始终是 double

参数

k | - | 椭圆模或离心率（浮点或整数类型值）
n | - | 椭圆特征（浮点或整数类型值）

返回值

若无错误发生，则返回 k 与 n 的第三类完全椭圆积分的值，即 std::ellint_3(k,n,π/2) 。

错误处理

可能报告 math_errhandling 中指定的错误。

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 |k|>1 ，则可能发生定义域错误

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

示例

#include <cmath>
#include <iostream>
int main()
{
    double hpi = std::acos(-1)/2;
    std::cout << "Π(0.5,0) = " << std::comp_ellint_3(0.5, 0) << '\n'
              << "K(0.5) = " << std::comp_ellint_1(0.5) << '\n'
              << "Π(0,0) = " << std::comp_ellint_3(0, 0) << '\n'
              << "π/2 = " << hpi << '\n'
              << "Π(0.5,1) = " << std::comp_ellint_3(0.5, 1) << '\n';
}

输出：

Π(0.5,0) = 1.68575
K(0.5) = 1.68575
Π(0,0) = 1.5708
π/2 = 1.5708
Π(0.5,1) = inf

外部链接

Weisstein, Eric W. “第三类椭圆积分”来自 MathWorld--A Wolfram Web Resource 。

参阅

ellint_3ellint_3fellint_3l
(C++17)(C++17)(C++17)
 第三类（不完全）椭圆积分
(函数)


std::cyl_bessel_j, std::cyl_bessel_jf, std::cyl_bessel_jl

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double cyl_bessel_j( double n, double x );

float cyl_bessel_jf( float n, float x );

long double cyl_bessel_jl( long double n, long double x );
 (1) (C++17 起)
Promoted cyl_bessel_j( Arithmetic n, Arithmetic x );
 (2) (C++17 起)
1) 计算 n 和 x 的第一类柱贝塞尔函数。
2) 对于所有 (1) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则它被转型到 double 。若任何参数为 long double ，则返回类型 Promoted 亦为 long double ，否则返回类型始终是 double 。

参数

n | - | 函数的阶数
x | - | 函数的参数

返回值

若无错误发生，则返回 n 和 x 的第一类柱贝塞尔函数的值，即 J
n(x) = Σ∞
k=0
(-1)k
(x/2)n+2k
k!Γ(n+k+1)
（对于 x≥0 ）。

错误处理

可能报告 math_errhandling 中指定的错误

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 n>=128 ，则行为是实现定义的

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

示例

#include <cmath>
#include <iostream>
int main()
{
    // 对 n == 0 点检查
    double x = 1.2345;
    std::cout << "J_0(" << x << ") = " << std::cyl_bessel_j(0, x) << '\n';

    // 对 J_0 展开级数
    double fct = 1;
    double sum = 0;
    for(int k = 0; k < 6; fct*=++k) {
        sum += std::pow(-1, k)*std::pow((x/2),2*k) / std::pow(fct,2);
        std::cout << "sum = " << sum << '\n';
    }
}

输出：

J_0(1.2345) = 0.653792
sum = 1
sum = 0.619002
sum = 0.655292
sum = 0.653756
sum = 0.653793
sum = 0.653792

外部链接

Weisstein, Eric W. “第一类贝塞尔函数。”来自 MathWorld--A Wolfram Web Resource 。

参阅

cyl_bessel_icyl_bessel_ifcyl_bessel_il
(C++17)(C++17)(C++17)
 规则变形圆柱贝塞尔函数
(函数)


std::cyl_bessel_k, std::cyl_bessel_kf, std::cyl_bessel_kl

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double cyl_bessel_k( double n, double x );

float cyl_bessel_kf( float n, float x );

long double cyl_bessel_kl( long double n, long double x );
 (1) (C++17 起)
Promoted cyl_bessel_k( Arithmetic n, Arithmetic x );
 (2) (C++17 起)
1) 计算 n 和 x 的非常规修正柱贝塞尔函数（亦称为第二类修正贝塞尔函数）。
2) 对于所有 (1) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则它被转型到 double 。若任何参数为 long double ，则返回类型 Promoted 亦为 long double ，否则返回类型始终是 double 。

参数

n | - | 函数的阶数
x | - | 函数的参数

返回值

若无错误发生，则返回 n 与 x 的非常规修正柱贝塞尔函数（第二类修正贝塞尔函数）的值，即对于 x≥0 及非整数 n 的 K
n(x) =
π
2
I
-n(x)-I
n(x)
sin(nπ)
（其中 I
n(x) 为 std::cyl_bessel_i(n,x)）；对整数 n 使用极限。

错误处理

可能报告 math_errhandling 中指定的错误

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 n>=128 ，则行为是实现定义的

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

示例

#include <cmath>
#include <iostream>
int main()
{
    double pi = std::acos(-1);
    double x = 1.2345;

    // 对 n == 0.5 点检查
    std::cout << "K_.5(" << x << ") = " << std::cyl_bessel_k( .5, x) << '\n'
              << "calculated via I = " <<
              (pi/2)*(std::cyl_bessel_i(-.5,x)
                     -std::cyl_bessel_i(.5,x))/std::sin(.5*pi) << '\n';
}

输出：

K_.5(1.2345) = 0.32823
calculated via I = 0.32823

外部链接

Weisstein, Eric W. “第二类修正贝塞尔函数”来自 MathWorld--A Wolfram Web Resource 。

参阅

cyl_bessel_icyl_bessel_ifcyl_bessel_il (C++17)(C++17)(C++17) | 规则变形圆柱贝塞尔函数 (函数)
cyl_bessel_jcyl_bessel_jfcyl_bessel_jl (C++17)(C++17)(C++17) | （第一类）圆柱贝塞尔函数 (函数)


std::cyl_neumann, std::cyl_neumannf, std::cyl_neumannl

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double cyl_neumann( double n, double x );

float cyl_neumannf( float n, float x );

long double cyl_neumannl( long double n, long double x );
 (1) (C++17 起)
Promoted cyl_neumann( Arithmetic n, Arithmetic x );
 (2) (C++17 起)
1) 计算 n 和 x 的柱诺依曼函数（亦称为第二类贝塞尔函数或 Weber 函数）。
2) 对于所有 (1) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则它被转型到 double 。若任何参数为 long double ，则返回类型 Promoted 亦为 long double ，否则返回类型始终是 double 。

参数

n | - | 函数的阶数
x | - | 函数的参数

返回值

若无错误发生，则返回 n 和 x 的柱诺依曼函数（第二类贝塞尔函数）的值，即对于 x≥0 和非整数 n 的 N
n(x) =
J
n(x)cos(nπ)-J
-n(x)
sin(nπ)
（其中 J
n(x) 是 std::cyl_bessel_j(n,x) ）；对整数 n 使用极限。

错误处理

可能报告 math_errhandling 中指定的错误

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 n>=128 ，则行为是实现定义的

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

示例

#include <cmath>
#include <iostream>
int main()
{
    double pi = std::acos(-1);
    double x = 1.2345;

    // 对 n == 0.5 点检查
    std::cout << "N_.5(" << x << ") = " << std::cyl_neumann(.5, x) << '\n'
              << "calculated via J = " <<
              (std::cyl_bessel_j(.5,x)*std::cos(.5*pi)
             - std::cyl_bessel_j(-.5,x))/std::sin(.5*pi) << '\n';
}

输出：

N_.5(1.2345) = -0.236973
calculated via J = -0.236973

外部链接

Weisstein, Eric W. “第二类贝塞尔函数”来自 MathWorld--A Wolfram Web Resource 。

参阅

cyl_bessel_icyl_bessel_ifcyl_bessel_il (C++17)(C++17)(C++17) | 规则变形圆柱贝塞尔函数 (函数)
cyl_bessel_jcyl_bessel_jfcyl_bessel_jl (C++17)(C++17)(C++17) | （第一类）圆柱贝塞尔函数 (函数)
cyl_bessel_kcyl_bessel_kfcyl_bessel_kl (C++17)(C++17)(C++17) | 不规则变形圆柱贝塞尔函数 (函数)


std::ellint_1, std::ellint_1f, std::ellint_1l

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double ellint_1( double k, double phi );

float ellint_1f( float k, float phi );

long double ellint_1l( long double k, long double phi );
 (1) (C++17 起)
Promoted ellint_1( Arithmetic k, Arithmetic phi );
 (2) (C++17 起)
1) 计算 k 和 phi 的第一类不完全椭圆积分。
2) 对于所有 (1) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则它被转型到 double 。若任何参数为 long double ，则返回类型 Promoted 亦为 long double ，否则返回类型始终是 double 。

参数

k | - | 椭圆模或离心率（浮点或整数类型值）
phi | - | 雅可比振幅（浮点或整数类型值，以弧度计量）

返回值

若无错误发生，则返回 k 与 phi 的第一类完全椭圆积分，即 ∫phi
0
dθ
√1-k2
sin2
θ
。

错误处理

可能报告 math_errhandling 中指定的错误

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 |k|>1 ，则可能发生定义域错误

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

示例

#include <cmath>
#include <iostream>
int main()
{
    double hpi = std::acos(-1)/2;
    std::cout << "F(0,π/2) = " << std::ellint_1(0, hpi) << '\n'
              << "F(0,-π/2) = " << std::ellint_1(0, -hpi) << '\n'
              << "π/2 = " << hpi << '\n'
              << "F(0.7,0) = " << std::ellint_1(0.7, 0) << '\n';
}

输出：

F(0,π/2) = 1.5708
F(0,-π/2) = -1.5708
π/2 = 1.5708
F(0.7,0) = 0

外部链接

Weisstein, Eric W. “第一类椭圆积分”来自 MathWorld--A Wolfram Web Resource 。

参阅

comp_ellint_1comp_ellint_1fcomp_ellint_1l
(C++17)(C++17)(C++17)
 第一类（完全）椭圆积分
(函数)


std::ellint_2, std::ellint_2f, std::ellint_2l

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double ellint_2( double k, double phi );

float ellint_2f( float k, float phi );

long double ellint_2l( long double k, long double phi );
 (1) (C++17 起)
Promoted ellint_2( Arithmetic k, Arithmetic phi );
 (2) (C++17 起)
1) 计算 k 和 phi 的第二类不完全椭圆积分。
2) 对于所有 (1) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则它被转型到 double 。若任何参数为 long double ，则返回类型 Promoted 亦为 long double ，否则返回类型始终是 double 。

参数

k | - | 椭圆模或离心率（浮点或整数类型值）
phi | - | 雅可比振幅（浮点或整数类型值，以弧度度量）

返回值

若无错误发生，则返回 k 与 phi 的第二类不完全椭圆积分的值，即 ∫phi
0√1-k2
sin2
θdθ 。

错误处理

可能报告 math_errhandling 中指定的错误

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 |k|>1 ，则可能发生定义域错误

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

示例

#include <cmath>
#include <iostream>
int main()
{
    double hpi = std::acos(-1)/2;
    std::cout << "E(0,π/2) = " << std::ellint_2(0, hpi) << '\n'
              << "E(0,-π/2) = " << std::ellint_2(0, -hpi) << '\n'
              << "π/2 = " << hpi << '\n'
              << "E(0.7,0) = " << std::ellint_2(0.7, 0) << '\n'
              << "E(1,π/2) = " << std::ellint_2(1, hpi) << '\n';
}

输出：

F(0,π/2) = 1.5708
F(0,-π/2) = -1.5708
π/2 = 1.5708
F(0.7,0) = 0
E(1,π/2) = 1

外部链接

Weisstein, Eric W. “第二类椭圆积分”来自 MathWorld--A Wolfram Web Resource 。

参阅

comp_ellint_2comp_ellint_2fcomp_ellint_2l
(C++17)(C++17)(C++17)
 第二类（完全）椭圆积分
(函数)


std::ellint_3, std::ellint_3f, std::ellint_3l

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double ellint_3( double k, double n, double phi );

float ellint_3f( float k, float n, float phi );

long double ellint_3l( long double k, long double n, long double phi );
 (1) (C++17 起)
Promoted ellint_3( Arithmetic k, Arithmetic n, Arithmetic phi );
 (2) (C++17 起)
1) 计算 k 、 n 和 phi 的第三类不完全椭圆积分。
2) 对于所有 (1) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则它被转型到 double 。若任何参数为 long double ，则返回类型 Promoted 亦为 long double ，否则返回类型始终是 double 。

参数

k | - | 椭圆模或离心率（浮点或整数类型值）
n | - | 椭圆特征（浮点或整数类型值）
phi | - | 雅可比振幅（浮点或整数类型值，以弧度计量）

返回值

若无错误发生，则返回 k 、 n 和 phi 的第三类椭圆积分的值，即 ∫phi
0
dθ
(1-nsin2
θ)√1-k2
sin2
θ
。

错误处理

可能报告 math_errhandling 中指定的错误

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 |k|>1 ，则可能出现定义域错误

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

示例

#include <cmath>
#include <iostream>
int main()
{
    double hpi = std::acos(-1)/2;
    std::cout << "Π(0,0,π/2) = " << std::ellint_3(0, 0, hpi) << '\n'
              << "π/2 = " << hpi << '\n';
}

输出：

Π(0,0,π/2) = 1.5708
π/2 = 1.5708
本节未完成
原因：这个和其他椭圆积分需要更好的示例……或许应该计算椭圆弧长？

外部链接

Weisstein, Eric W. “第三类椭圆积分”来自 MathWorld--A Wolfram Web Resource 。

参阅

comp_ellint_3comp_ellint_3fcomp_ellint_3l
(C++17)(C++17)(C++17)
 第三类（完全）椭圆积分
(函数)


std::expint, std::expintf, std::expintl

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double expint( double arg );

float expint( float arg );
long double expint( long double arg );
float expintf( float arg );

long double expintl( long double arg );
 (1) (C++17 起)
double expint( IntegralType arg );
 (2) (C++17 起)
1) 计算 arg 的指数积分。
2) 接受任意整数类型参数的重载集或函数模板。等价于将参数转型到 double 后的 (1) 。

参数

arg - 浮点或整数类型的值

返回值

若不发生错误，则返回 arg 的指数积分的值，即 -∫∞
-arg
e-t
t
dt 。

错误处理

可能报告 math_errhandling 中指定的错误。

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若参数是 ±0 ，则返回 -∞

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

示例

#include <cmath>
#include <iostream>
int main()
{
    std::cout << "Ei(0) = " << std::expint(0) << '\n'
              << "Ei(1) = " << std::expint(1) << '\n'
              << "Gompetz constant = " << -std::exp(1)*std::expint(-1) << '\n';
}

输出：

Ei(0) = -inf
Ei(1) = 1.89512
Gompetz constant = 0.596347

外部链接

Weisstein, Eric W. “指数积分”来自 MathWorld--A Wolfram Web Resource 。


std::laguerre, std::laguerref, std::laguerrel

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double laguerre( unsigned int n, double x );

float laguerre( unsigned int n, float x );
long double laguerre( unsigned int n, long double x );
float laguerref( unsigned int n, float x );

long double laguerrel( unsigned int n, long double x );
 (1) (C++17 起)
double laguerre( unsigned int n, IntegralType x );
 (2) (C++17 起)
1) 以参数 x 计算 n 次非关联拉盖尔多项式
2) 接受任何整数类型参数的重载集或函数模板。等价于将参数转型到 double 后的 (1) 。

参数

n | - | 多项式的次数，无符号整数类型的值
x | - | 参数，浮点或整数类型的值

返回值

若无错误发生，则返回 x 的 n 阶非关联拉盖尔多项式的值，即
ex
n!
dn
dxn
(xn
e-x) 。

错误处理

可能报告 math_errhandling 中指定的错误

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 x 为负，则可能发生定义域错误
  • 若 n 大于或等于 128 ，则行为是实现定义的

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

拉盖尔多项式是方程 xy,,
+(1-x)y,
+ny = 0 的多项式解

前几个解是：

  • laguerre(0, x) = 1
  • laguerre(1, x) = -x + 1
  • laguerre(2, x) =
    1
    2
    [x2
    -4x+2]
  • laguerre(3, x) =
    1
    6
    [-x3
    -9x2
    -18x+6]

示例

#define __STDCPP_WANT_MATH_SPEC_FUNCS__ 1
#include <cmath>
#include <iostream>
double L1(double x) { return -x + 1; }
double L2(double x) { return 0.5*(x*x-4*x+2); }
int main()
{
    // 点检查
    std::cout << std::laguerre(1, 0.5) << '=' << L1(0.5) << '\n'
              << std::laguerre(2, 0.5) << '=' << L2(0.5) << '\n';
}

输出：

0.5=0.5
0.125=0.125

参阅

assoc_laguerreassoc_laguerrefassoc_laguerrel
(C++17)(C++17)(C++17)
 连带拉盖尔多项式
(函数)

外部链接

Weisstein, Eric W. “拉盖尔多项式”来自 MathWorld--A Wolfram Web Resource 。


std::legendre, std::legendref, std::legendrel

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double legendre( unsigned int n, double x );

float legendre( unsigned int n, float x );
long double legendre( unsigned int n, long double x );
float legendref( unsigned int n, float x );

long double legendrel( unsigned int n, long double x );
 (1) (C++17 起)
double legendre( unsigned int n, IntegralType x );
 (2) (C++17 起)
1) 以参数 x 计算 n 次非关联勒让德多项式
2) 接受任意整数类型参数的重载集或函数模板。等价于将参数转型到 double 后的 (1) 。

参数

n | - | 多项式的次数
x | - | 参数，浮点或整数类型的值

返回值

若无错误发生，则返回 x 的 n 阶非关联勒让德多项式的值，即 \(\mathsf{P}_n(x) = \frac{1}{2^n n!} \frac{\mathsf{d}^n}{\mathsf{d}x^n} (x^2-1)^n \)
1
2n
n!
dn
dxn
(x2
-1)n
 。

错误处理

可能报告 math_errhandling 中指定的错误

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 不要求函数对 |x|>1 有定义
  • 若 n 大于或等于 128 ，则行为是实现定义的

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

前几个勒让德多项式是：

  • legendre(0, x) = 1
  • legendre(1, x) = x
  • legendre(2, x) =
    1
    2
    (3x2
    -1)
  • legendre(3, x) =
    1
    2
    (5x3
    -3x)
  • legendre(4, x) =
    1
    8
    (35x4
    -30x2
    +3)

示例

#include <cmath>
#include <iostream>
double P3(double x) { return 0.5*(5*std::pow(x,3) - 3*x); }
double P4(double x) { return 0.125*(35*std::pow(x,4)-30*x*x+3); }
int main()
{
    // 点检查
    std::cout << std::legendre(3, 0.25) << '=' << P3(0.25) << '\n'
              << std::legendre(4, 0.25) << '=' << P4(0.25) << '\n';
}

输出：

-0.335938=-0.335938
0.157715=0.157715

参阅

laguerrelaguerreflaguerrel (C++17)(C++17)(C++17) | 拉盖尔多项式 (函数)
hermitehermitefhermitel (C++17)(C++17)(C++17) | 埃尔米特多项式 (函数)

外部链接

Weisstein, Eric W. “勒让德多项式”来自 MathWorld--A Wolfram Web Resource 。


std::riemann_zeta, std::riemann_zetaf, std::riemann_zetal

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double riemann_zeta( double arg );

float riemann_zeta( float arg );
long double riemann_zeta( long double arg );
float riemann_zetaf( float arg );

long double riemann_zetal( long double arg );
 (1) (C++17 起)
double riemann_zeta( IntegralType arg );
 (2) (C++17 起)
1) 计算 arg 的黎曼 zeta 函数。
2) 接受任何整数类型实参的重载集或函数模板。等价于 (1) ，在将参数转型为 double 后。

参数

arg - 浮点或整数类型的值

返回值

若无错误发生，则为 arg 的黎曼 Zeta 函数值， ζ(arg) ，定义于整个实轴：

  • 对于 arg>1 ，为 Σ∞
    n=1    n-arg
  • 对于 0≤arg≤1 ，为
    1
    1-21-arg
    Σ∞
    n=1    (-1)n-1
    n-arg
  • 对于 arg<0 ，为 2arg
    πarg-1
    sin(
    πarg
    2
    )Γ(1−arg)ζ(1−arg)

错误处理

可能报告 math_errhandling 中指定的错误

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

示例

#include <cmath>
#include <iostream>
int main()
{
    // 广为人知的值的点检查
    std::cout << "ζ(-1) = " << std::riemann_zeta(-1) << '\n'
              << "ζ(0) = " << std::riemann_zeta(0) << '\n'
              << "ζ(1) = " << std::riemann_zeta(1) << '\n'
              << "ζ(0.5) = " << std::riemann_zeta(0.5) << '\n'
              << "ζ(2) = " << std::riemann_zeta(2) << ' '
              << "(π²/6 = " << std::pow(std::acos(-1),2)/6 << ")\n";
}

输出：

ζ(-1) = -0.0833333
ζ(0) = -0.5
ζ(1) = inf
ζ(0.5) = -1.46035
ζ(2) = 1.64493 (π²/6 = 1.64493)

外部链接

Weisstein, Eric W. “黎曼 Zeta 函数”来自 MathWorld--A Wolfram Web Resource 。


std::sph_bessel, std::sph_besself, std::sph_bessell

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double sph_bessel ( unsigned n, double x );

float sph_bessel ( unsigned n, float x );
long double sph_bessel ( unsigned n, long double x );
float sph_besself( unsigned n, float x );

long double sph_bessell( unsigned n, long double x );
 (1) (C++17 起)
double sph_bessel( unsigned n, IntegralType x );
 (2) (C++17 起)
1) 计算 n 和 x 的第一类球贝塞尔函数。
2) 接受任意整数类型参数的重载集或函数模板。等价于将参数转型到 double 后的 (1) 。

参数

n | - | 函数的阶数
x | - | 函数的参数

返回值

若无错误发生，则返回 n 和 x 的第一类球贝塞尔函数，即 j
n(x) = (π/2x)1/2
J
n+1/2(x) ，其中 J
n(x) 为 std::cyl_bessel_j (n,x) 且 x≥0

错误处理

可能报告 math_errhandling 中指定的错误

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 n>=128 ，则行为是实现定义的

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

参阅

#include <cmath>
#include <iostream>
int main()
{
    // 对 n == 1 的点检查
    double x = 1.2345;
    std::cout << "j_1(" << x << ") = " << std::sph_bessel(1, x) << '\n';

    // 对 j_1 的准确解
    std::cout << "(sin x)/x^2 - (cos x)/x = " << std::sin(x)/(x*x) - std::cos(x)/x << '\n';
}

输出：

j_1(1.2345) = 0.352106
(sin x)/x^2 - (cos x)/x = 0.352106

外部链接

Weisstein, Eric W. “第一类球贝塞尔函数”来自 MathWorld--A Wolfram Web Resource 。

参阅

cyl_bessel_jcyl_bessel_jfcyl_bessel_jl (C++17)(C++17)(C++17) | （第一类）圆柱贝塞尔函数 (函数)
sph_neumannsph_neumannfsph_neumannl (C++17)(C++17)(C++17) | 球面诺依曼函数 (函数)


std::sph_legendre, std::sph_legendref, std::sph_legendrel

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double sph_legendre ( unsigned l, unsigned m, double t );

float sph_legendre ( unsigned l, unsigned m, float t );
long double sph_legendre ( unsigned l, unsigned m, long double t );
float sph_legendref( unsigned l, unsigned m, float t );

long double sph_legendrel( unsigned l, unsigned m, long double t );
 (1) (C++17 起)
double sph_legendre ( unsigned l, unsigned m, IntegralType t );
 (2) (C++17 起)
1) 计算 l 次、 m 阶和极角 t 的球关联勒让德函数。
2) 接受任意整数类型参数的重载集或函数模板。等价于将参数转型到 double 后的 (1) 。

参数

l | - | 次数
m | - | 阶数
t | - | 极角，以弧度度量

返回值

若无错误发生，则返回 l 、 m 和 t 的球关联勒让德函数（即 ϕ = 0 下的球谐函数）的值，其中球谐函数定义为 Ym
l(t,ϕ) = (-1)m
[
(2l+1)(l-m)!
4π(l+m)!
]1/2
Pm
l(cost)eimϕ
 ，其中 Pm
l(x) 为 std::assoc_legendre (l,m,x)) 且 |m|≤l

注意此函数定义包含 Condon-Shortley 相位项 (-1)m
 ，因为以 std::assoc_legendre 定义的 Pm
l 忽略了它。

错误处理

可能报告 math_errhandling 中指定的错误。

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 l≥128 ，则行为是实现定义的

注意

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

球谐函数的一种实现 可用于 boost.math ，且它在以设为零的参数 phi 调用时规约到此函数。

示例

#include <cmath>
#include <iostream>
int main()
{
    // 对于 l=3, m=0 的点检查
    double x = 1.2345;
    std::cout << "Y_3^0(" << x << ") = " << std::sph_legendre(3, 0, x) << '\n';

    // 准确解
    double pi = std::acos(-1);
    std::cout << "exact solution = "
              << 0.25*std::sqrt(7/pi)*(5*std::pow(std::cos(x),3)-3*std::cos(x))
              << '\n';
}

输出：

Y_3^0(1.2345) = -0.302387
exact solution = -0.302387

外部链接

Weisstein, Eric W. “球谐”来自 MathWorld--A Wolfram Web Resource 。

参阅

assoc_legendreassoc_legendrefassoc_legendrel
(C++17)(C++17)(C++17)
 连带勒让德多项式
(函数)


std::sph_neumann, std::sph_neumannf, std::sph_neumannl

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double sph_neumann ( unsigned n, double x );

float sph_neumann ( unsigned n, float x );
long double sph_neumann ( unsigned n, long double x );
float sph_neumannf( unsigned n, float x );

long double sph_neumannl( unsigned n, long double x );
 (1) (C++17 起)
double sph_neumann( unsigned n, IntegralType x );
 (2) (C++17 起)
1) 计算 n 和 x 的第二类球贝塞尔函数，又称球诺依曼函数。
2) 接受任意整数类型参数的重载集或函数模板。等价于将参数转型到 double 后的 (1) 。

参数

n | - | 函数的阶数
x | - | 函数的参数

返回值

若无错误发生，则返回 n 和 x 的第二类球贝塞尔函数（球诺依曼函数），即 n
n(x) = (π/2x)1/2
N
n+1/2(x) ，其中 N
n(x) 为 std::cyl_neumann (n,x) 且 x≥0

错误处理

可能报告 math_errhandling 中指定的错误

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 n>=128 ，则行为是实现定义的

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

示例

#include <cmath>
#include <iostream>
int main()
{
    // 对 n == 1 的点检查
    double x = 1.2345;
    std::cout << "n_1(" << x << ") = " << std::sph_neumann(1, x) << '\n';

    // 对 n_1 的准确解
    std::cout << "-(cos x)/x^2 - (sin x)/x = "
              << -std::cos(x)/(x*x) - std::sin(x)/x << '\n';
}

输出：

n_1(1.2345) = -0.981201
-(cos x)/x^2 - (sin x)/x = -0.981201

外部链接

Weisstein, Eric W. “第二类球贝塞尔函数”来自 MathWorld--A Wolfram Web Resource 。

参阅

cyl_neumanncyl_neumannfcyl_neumannl (C++17)(C++17)(C++17) | 圆柱诺依曼函数 (函数)
sph_besselsph_besselfsph_bessell (C++17)(C++17)(C++17) | （第一类）球面贝塞尔函数 (函数)


std::beta, std::betaf, std::betal

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double beta( double x, double y );

float betaf( float x, float y );

long double betal( long double x, long double y );
 (1) (C++17 起)
Promoted beta( Arithmetic x, Arithmetic y );
 (2) (C++17 起)
1) 计算 x 与 y 的 Β 函数。
2) 所有 (1) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则它被转型到 double 。若任何参数为 long double ，则返回类型 Promoted 亦为 long double ，否则返回类型始终是 double 。

参数

x, y - 浮点或整数类型值

返回值

若无错误发生，则返回 x 与 y 的 beta 函数值，即 \(\int_{0}^{1}{ {t}^{x-1}{(1-t)}^{y-1}\mathsf{d}t}\)∫1
0tx-1
(1-t)(y-1)
dt ，或等价地为 \(\frac{\Gamma(x)\Gamma(y)}{\Gamma(x+y)}\)
Γ(x)Γ(y)
Γ(x+y)
。

错误处理

可能报告 math_errhandling 中指定的错误。

  • 若任一参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 仅要求函数在 x 与 y 均大于零的情况有定义，并且允许其他情况下报告定义域错误。

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

beta(x, y) 等于 beta(y, x)

当 x 与 y 为正整数时， beta(x,y) 等于 \(\frac{(x-1)!(y-1)!}{(x+y-1)!}\)
(x-1)!(y-1)!
(x+y-1)!
。

二项式系数可用 Β 函数表示： \(\binom{n}{k} = \frac{1}{(n+1)B(n-k+1,k+1)}\)⎛
⎜
⎝n
k⎞
⎟
⎠=
1
(n+1)Β(n-k+1,k+1)
。

示例

#include <cmath>
#include <string>
#include <iostream>
#include <iomanip>
double binom(int n, int k) { return 1/((n+1)*std::beta(n-k+1,k+1)); }
int main()
{
    std::cout << "Pascal's triangle:\n";
    for(int n = 1; n < 10; ++n) {
        std::cout << std::string(20-n*2, ' ');
        for(int k = 1; k < n; ++k)
            std::cout << std::setw(3) << binom(n,k) << ' ';
        std::cout << '\n';
    }
}

输出：

Pascal's triangle:

                  2
                3   3
              4   6   4
            5  10  10   5
          6  15  20  15   6
        7  21  35  35  21   7
      8  28  56  70  56  28   8
    9  36  84 126 126  84  36   9

参阅

tgammatgammaftgammal
(C++11)(C++11)(C++11)
 gamma 函数
(函数)

外部链接

Weisstein, Eric W. “ Β 函数。” 来自 MathWorld--A Wolfram Web Resource 。


std::cyl_bessel_i, std::cyl_bessel_if, std::cyl_bessel_il

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double cyl_bessel_i( double n, double x );

float cyl_bessel_if( float n, float x );

long double cyl_bessel_il( long double n, long double x );
 (1) (C++17 起)
Promoted cyl_bessel_i( Arithmetic n, Arithmetic x );
 (2) (C++17 起)
1) 计算 n 与 x 的常规修正贝塞尔函数。
2) 对于所有 (1) 所不覆盖的算术类型参数组合的重载集或函数模板。若任何参数拥有整数类型，则它被转型到 double 。若任何参数为 long double ，则返回类型 Promoted 亦为 long double ，否则返回类型始终是 double 。

参数

n | - | 函数的阶数
x | - | 函数的参数

返回值

若无错误发生，则返回 n 和 x, 的常规修正柱贝塞尔函数，即 I
n(x) = Σ∞
k=0
(x/2)n+2k
k!Γ(n+k+1)
（对于 x≥0 ）。

错误处理

可能报告 math_errhandling 中指定的错误

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 n>=128 ，则行为是实现定义的

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

示例

#include <cmath>
#include <iostream>
int main()
{
    // 对 n == 0 点检查
    double x = 1.2345;
    std::cout << "I_0(" << x << ") = " << std::cyl_bessel_i(0, x) << '\n';

    // 对 I_0 的级数展开
    double fct = 1;
    double sum = 0;
    for(int k = 0; k < 5; fct*=++k) {
        sum += std::pow((x/2),2*k) / std::pow(fct,2);
        std::cout << "sum = " << sum << '\n';
    }
}

输出：

I_0(1.2345) = 1.41886
sum = 1
sum = 1.381
sum = 1.41729
sum = 1.41882
sum = 1.41886

外部链接

Weisstein, Eric W. “第一类修正贝塞尔函数”来自 MathWorld--A Wolfram Web Resource 。

参阅

cyl_bessel_jcyl_bessel_jfcyl_bessel_jl
(C++17)(C++17)(C++17)
 （第一类）圆柱贝塞尔函数
(函数)


std::hermite, std::hermitef, std::hermitel

< cpp‎ | numeric‎ | special functions
定义于头文件 <cmath>
double hermite( unsigned int n, double x );

float hermite( unsigned int n, float x );
long double hermite( unsigned int n, long double x );
float hermitef( unsigned int n, float x );

long double hermitel( unsigned int n, long double x );
 (1) (C++17 起)
double hermite( unsigned int n, IntegralType x );
 (2) (C++17 起)
1) 以参数 x 计算 n 次（物理学家）埃尔米特多项式
2) 接受任何整数类型参数的重载集或函数模板。等价于将参数转型到 double 后的 (1) 。

参数

n | - | 多项式的次数
x | - | 参数，浮点或整数类型的值

返回值

若无错误发生，则返回 x 的 n 阶埃尔米特多项式的值，即 (-1)n
ex2
dn
dxn
e-x2
 。

错误处理

可能报告 math_errhandling 中指定的错误

  • 若参数是 NaN ，则返回 NaN 且不报告定义域错误
  • 若 n 大于或等于 128 ，则行为是实现定义的

注解

不支持 C++17 ，但支持 ISO 29124:2010 的实现会提供此函数，若实现定义了 __STDCPP_MATH_SPEC_FUNCS__ 为至少 201003L 的值，且用户在包含任何标准库头文件前定义了 __STDCPP_WANT_MATH_SPEC_FUNCS__ 。

不支持 ISO 29124:2010 但支持 TR 19768:2007 (TR1) 的实现，在头文件 tr1/cmath 及命名空间 std::tr1 中提供此函数。

此函数的一种实现亦可用于 boost.math

埃尔米特多项式是方程 u,,
-2xu,
 = -2nu 的多项式解

前几个解是：

  • hermite(0, x) = 1
  • hermite(1, x) = 2x
  • hermite(2, x) = 4x2
    -2
  • hermite(3, x) = 8x3
    -12x
  • hermite(4, x) = 16x4
    -48x2
    +12

示例

#include <cmath>
#include <iostream>
double H3(double x) { return 8*std::pow(x,3) - 12*x; }
double H4(double x) { return 16*std::pow(x,4)-48*x*x+12; }
int main()
{
    // 点检查
    std::cout << std::hermite(3, 10) << '=' << H3(10) << '\n'
              << std::hermite(4, 10) << '=' << H4(10) << '\n';
}

输出：

7880=7880
155212=155212

参阅

laguerrelaguerreflaguerrel (C++17)(C++17)(C++17) | 拉盖尔多项式 (函数)
legendrelegendreflegendrel (C++17)(C++17)(C++17) | 勒让德多项式 (函数)

外部链接

Weisstein, Eric W. “埃尔米特多项式”来自 MathWorld--A Wolfram Web Resource 。


std::valarray

< cpp‎ | numeric
定义于头文件 <valarray>
template< class T >
class valarray;

std::valarray 是表示并操作值数组的类。它支持对元素逐个进行数学运算，并且支持多种形式的广义下标运算符、切片及间接访问。

注意

std::valarray 及帮助类定义为免除某些形式的别名使用，从而允许这些类上的操作被优化得类似 C 程序语言中关键词 restrict 的效果。而且，接收 valarray 参数的函数和运算符允许返回代理对象，以使得编译器将诸如 v1 = a*v2 + v3; 的表达式优化成执行 v1[i] = a*v2[i] + v3[i]; 的单个循环，避免任何临时量或多趟运算。然而，表达式模板使得同样的优化技巧对任何 C++ 容器可用，而数值库的主流因灵活性偏好表达式模板甚于 valarray 。某些 C++ 标准库实现使用表达式模板以实现 std::valarray 上的高效运算（例如 GNU libstdc++ 与 LLVM libc++ ）。只有少数库进一步优化 valarray ，例如 Intel Integrated Performance Primitives 。

模板形参

T - 元素的类型。类型必须满足数值类型 (NumericType) 要求

成员类型

成员类型 | 定义
value_type | T

成员函数

(构造函数) | 构造新的数值数组 (公开成员函数)
(析构函数) | 析构数值数组 (公开成员函数)
operator= | 为内容赋值 (公开成员函数)
operator[] | 获取/设置 valarray 数组元素、切片或掩码 (公开成员函数)
operator+operator-operator~operator! | 对 valarray 的每个元素运用一元算术运算符 (公开成员函数)
operator+=operator-=operator*=operator/=operator%=operator&=operator|=operator^=operator<<=operator>>= | 对 valarray 的每个元素应用复合赋值运算符 (公开成员函数)
swap | 与另一 valarray 交换 (公开成员函数)
size | 返回valarray的大小 (公开成员函数)
resize | 更改 valarray 的大小 (公开成员函数)
sum | 计算所有元素的和 (公开成员函数)
min | 返回最小元素 (公开成员函数)
max | 返回最大的元素 (公开成员函数)
shift | 以填入零的方式移动 valarray 的元素 (公开成员函数)
cshift | 循环移动 valarray 的元素 (公开成员函数)
apply | 对 valarray 的每个元素应用函数 (公开成员函数)

非成员函数

std::swap(std::valarray)
(C++11)
 特化 std::swap() 算法
(函数模板)
std::begin(std::valarray)
(C++11)
 特化的 std::begin
(函数模板)
std::end(std::valarray)
(C++11)
 特化的 std::end
(函数模板)
operator+operator-operator*operator/operator%operator&operator|operator^operator<<operator>>operator&&operator||
 对两个 valarray 的每个元素，或一个 valarray 的每个元素和一个值运用二元运算符
(函数模板)
operator==operator!=operator<operator<=operator>operator>=
 比较两个 valarrays，或比较一个 valarray 和一个值
(函数模板)
abs(std::valarray)
 应用函数 std::abs 到 valarray 的每个元素
(函数模板)
指数函数
exp(std::valarray)
 应用函数 std::exp 到 valarray 的每个元素
(函数模板)
log(std::valarray)
 应用函数 std::log 到 valarray 的每个元素
(函数模板)
log10(std::valarray)
 应用函数 std::log10 到 valarray 的每个元素
(函数模板)
幂函数
pow(std::valarray)
 应用函数 std::pow 到二个 valarray 或一个 valarray 与一个值
(函数模板)
sqrt(std::valarray)
 应用函数 std::sqrt 到 valarray 的每个元素
(函数模板)
三角函数
sin(std::valarray)
 对 valarray 的每个元素应用std::sin函数
(函数模板)
cos(std::valarray)
 应用函数 std::cos 到 valarray 的每个元素
(函数模板)
tan(std::valarray)
 应用函数 std::tan 到 valarray 的每个元素
(函数模板)
asin(std::valarray)
 应用函数 std::asin 到 valarray 的每个元素
(函数模板)
acos(std::valarray)
 应用函数 std::acos 到 valarray 的每个元素
(函数模板)
atan(std::valarray)
 应用函数 std::atan 到 valarray 的每个元素
(函数模板)
atan2(std::valarray)
 应用函数 std::atan2 到一个 valarray 和一个值
(函数模板)
双曲函数
sinh(std::valarray)
 在 valarray 的每个元素上调用 std::sinh 函数
(函数模板)
cosh(std::valarray)
 在 valarray 的每个元素上调用 std::cosh 函数
(函数模板)
tanh(std::valarray)
 在 valarray 的每个元素上调用 std::tanh 函数
(函数模板)

辅助类

slice | valarray 的 BLAS 式切片：起始下标、长度、跨度 (类)
slice_array | 到 valarray 应用 slice 后的子集的代理 (类模板)
gslice | valarray 的通用切片：起始下标、长度集、步幅集 (类)
gslice_array | valarray 应用 gslice 后的子集的代理 (类模板)
mask_array | 到应用布尔掩码 operator[] 后的 valarray 子集的代理 (类模板)
indirect_array | 到应用间接 operator[] 后的 valarray 子集的代理。 (类模板)

推导指引 (C++17 起)


std::abs(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
valarray<T> abs( const valarray<T>& va );

计算值数组中每个元素的绝对值。

参数

va - 要应用操作到的值数组

返回值

含 va 中值的绝对值的值数组。

注意

用无限定函数 (abs) 进行计算。若该函数不可用，则因参数依赖查找使用 std::abs 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

可能的实现

template< class T >
valarray<T> abs( const valarray<T>& va )
{
    valarray<T> other = va;
    for (T &i : other) {
        i = abs(i);
    }
    return other; // 可返回代理对象
}

示例

#include <valarray>
#include <iostream>

int main()
{
    std::valarray<int> v{1, -2, 3, -4, 5, -6, 7, -8};
    std::valarray<int> v2 = std::abs(v);
    for(auto n : v2) {
        std::cout << n << ' ';
    }
    std::cout << '\n';
}

输出：

1 2 3 4 5 6 7 8

参阅

abs(int)labsllabs (C++11) | 计算整数值的绝对值（ \(\small{|x|}\)|x| ） (函数)
abs(float)fabsfabsffabsl (C++11)(C++11) | 浮点值的绝对值（ \(\small{|x|}\)|x| ） (函数)
abs(std::complex) | 返回复数的模 (函数模板)


std::acos(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
valarray<T> acos( const valarray<T>& va );

对 va 中的每个元素，计算元素值的反余弦。

参数

va - 要应用运算到的值数组

返回值

含有 va 中值的反余弦的值数组。

注意

用无限定函数 (acos) 进行计算。若该函数不可用，则因参数依赖查找使用 std::acos 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

可能的实现

template<class T>
valarray<T> acos(const valarray<T>& va)
{
    valarray<T> other = va;
    for (T &i : other) {
        i = acos(i);
    }
    return other;
}

示例

本节未完成
原因：暂无示例

参阅

asin(std::valarray) | 应用函数 std::asin 到 valarray 的每个元素 (函数模板)
atan(std::valarray) | 应用函数 std::atan 到 valarray 的每个元素 (函数模板)
atan2(std::valarray) | 应用函数 std::atan2 到一个 valarray 和一个值 (函数模板)
cos(std::valarray) | 应用函数 std::cos 到 valarray 的每个元素 (函数模板)
acosacosfacosl (C++11)(C++11) | 计算反余弦（ \({\small\arccos{x} }\)arccos(x) ） (函数)
acos(std::complex) (C++11) | 计算复数的反余弦（ \({\small\arccos{z} }\)arccos(z) ） (函数模板)


std::valarray<T>::apply

< cpp‎ | numeric‎ | valarray
valarray<T> apply( T func(T) ) const;
valarray<T> apply( T func(const T&) ) const;

返回同大小的新 valarray ，拥有通过应用 func 函数到元素先前值取得的值。

参数

func - 应用到值的函数

返回值

作为结果的 valarray ，拥有通过应用 func 取得的值

注意

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

示例

计算并打印前 10 个正整数的阶乘

#include <iostream>
#include <valarray>
#include <cmath>

int main()
{
    std::valarray<int> v = {1,2,3,4,5,6,7,8,9,10};
    v = v.apply([](int n)->int {
                    return std::round(std::tgamma(n+1));
                });
    for(auto n : v) {
        std::cout << n << ' ';
    }
    std::cout << '\n';
}

输出：

1 2 6 24 120 720 5040 40320 362880 3628800

See also

for_each
 应用函数到范围中的元素
(函数模板)


std::asin(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
valarray<T> asin( const valarray<T>& va );

对每个 va 中元素计算元素值的反正弦。

参数

va - 要应用运算的 value_array

返回值

含有 va 中值反正弦的 value_array 。

注意

用无限定函数 (asin) 进行计算。若该函数不可用，则因参数依赖查找使用 std::asin 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

可能的实现

template<class T>
valarray<T> asin(const valarray<T>& va)
{
    valarray<T> other = va;
    for (T &i : other) {
        i = asin(i);
    }
    return other;
}

示例

本节未完成
原因：暂无示例

参阅

acos(std::valarray) | 应用函数 std::acos 到 valarray 的每个元素 (函数模板)
atan(std::valarray) | 应用函数 std::atan 到 valarray 的每个元素 (函数模板)
atan2(std::valarray) | 应用函数 std::atan2 到一个 valarray 和一个值 (函数模板)
sin(std::valarray) | 对 valarray 的每个元素应用std::sin函数 (函数模板)
asinasinfasinl (C++11)(C++11) | 计算反正弦（ \({\small\arcsin{x} }\)arcsin(x) ） (函数)
asin(std::complex) (C++11) | 计算复数的反正弦（ \({\small\arcsin{z} }\)arcsin(z) ） (函数模板)


std::atan(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
valarray<T> atan( const valarray<T>& va );

对于每个 va 中的元素，计算元素值的弧（反）正切。

参数

va - 要应用操作到的值数组

返回值

含有 va 中值的反正切的值数组。

注意

用无限定函数 (atan) 进行计算。若该函数不可用，则因参数依赖查找使用 std::atan 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

可能的实现

template<class T>
valarray<T> atan(const valarray<T>& va)
{
    valarray<T> other = va;
    for (T &i : other) {
        i = atan(i);
    }
    return other;
}

示例

#include <algorithm>
#include <cmath>
#include <iostream>
#include <valarray>

auto show = [](char const* title, const std::valarray<float>& va) {
    std::cout << title << " :";
    std::for_each(std::begin(va), std::end(va),
        [](const float x) { std::cout << "  " << std::fixed << x; });
    std::cout << '\n';
};

int main()
{
    const std::valarray<float> x = {.1f, .3f, .6f, .9f};
    const std::valarray<float> f = std::atan(x);
    const std::valarray<float> g = std::tan(f);

    show("x          ", x);
    show("f = atan(x)", f);
    show("g = tan(f) ", g);
}

输出：

x           :  0.100000  0.300000  0.600000  0.900000
f = atan(x) :  0.099669  0.291457  0.540420  0.732815
g = tan(f)  :  0.100000  0.300000  0.600000  0.900000

参阅

asin(std::valarray) | 应用函数 std::asin 到 valarray 的每个元素 (函数模板)
acos(std::valarray) | 应用函数 std::acos 到 valarray 的每个元素 (函数模板)
atan2(std::valarray) | 应用函数 std::atan2 到一个 valarray 和一个值 (函数模板)
tan(std::valarray) | 应用函数 std::tan 到 valarray 的每个元素 (函数模板)
atanatanfatanl (C++11)(C++11) | 计算反正切（ \({\small\arctan{x} }\)arctan(x) ） (函数)
atan(std::complex) (C++11) | 计算复数的反正切（ \({\small\arctan{z} }\)arctan(z) ） (函数模板)


std::atan2(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
std::valarray <T> atan2( const std::valarray <T>& y, const std::valarray <T>& x );
 (1)
template< class T >

std::valarray <T> atan2( const std::valarray <T>& y,

const typename std::valarray <T>::value_type& vx );
 (2)
template< class T >

std::valarray <T> atan2( const typename std::valarray <T>::value_type& vy,

const std::valarray <T>& x );
 (3)

计算 y/x 的反正切，用参数符号正确地确定象限。

1) 计算每对来自 y 与 x 的对应值的反正切。

若 x.size() != y.size() 则行为未定义。

2) 计算 vx 与数值数组 y 中每个值的反正切。
3) 计算 vy 与数值数组 x 中每个值的反正切。

参数

x, y | - | 要计算反正切的数值数组
vy, vx | - | 要计算反正切的值

返回值

含反正切计算结果的数值数组。

注解

用无限定函数 (atan2) 进行计算。若该函数不可用，则因参数依赖查找使用 std::atan2 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

示例

#include <algorithm>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <valarray>

void show(char const* title, const std::valarray<double>& va) {
    std::cout << title << " ";
    std::for_each(std::begin(va), std::end(va), [](const double x) {
        std::cout << " " << std::right << std::setw(4) << x << "°";
    });
    std::cout << '\n';
}

const double pi = std::acos(-1.0); // C++20: std::numbers::pi

int main()
{
    auto degrees_to_radians = [](double const& x) { return (pi * x / 180); };
    auto radians_to_degrees = [](double const& x) { return (180 * x / pi); };

    const std::valarray<double> degrees{-90, -60, -45, -30, 0, 30, 45, 60, 90};
    const std::valarray<double> radians = degrees.apply(degrees_to_radians);

    const auto sin = std::sin(radians);
    const auto cos = std::cos(radians);

    show("(1)", std::atan2(sin, cos).apply(radians_to_degrees));
    show("(2)", std::atan2(sin/cos, 1.0).apply(radians_to_degrees));
    show("(3)", std::atan2(1.0, cos/sin).apply(radians_to_degrees));
}

输出：

(1)   -90°  -60°  -45°  -30°    0°   30°   45°   60°   90°
(2)   -90°  -60°  -45°  -30°    0°   30°   45°   60°   90°
(3)    90°  120°  135°  150°    0°   30°   45°   60°   90°

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3074 | C++98 | (2-3) 从标量和 valarray 两者推导 T ，禁止混合类型的调用 | 仅从 valarray 推导 T

参阅

asin(std::valarray) | 应用函数 std::asin 到 valarray 的每个元素 (函数模板)
acos(std::valarray) | 应用函数 std::acos 到 valarray 的每个元素 (函数模板)
atan(std::valarray) | 应用函数 std::atan 到 valarray 的每个元素 (函数模板)
atan2atan2fatan2l (C++11)(C++11) | 反正切，用符号确定象限 (函数)
arg | 返回辐角 (函数模板)


std::begin(std::valarray)

< cpp‎ | numeric‎ | valarray
template< class T > /*unspecified1*/ begin( valarray<T>& v ); | (1) | (C++11 起)
template< class T > /*unspecified2*/ begin( const valarray<T>& v ); | (2) | (C++11 起)

std::begin 对 valarray 的重载返回指代数值数组中首元素的未指定类型迭代器。

1) 返回类型满足可变老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。
2) 返回类型满足常老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。

在数组 v 上调用成员函数 resize() ，或在 v 的生存期结束，两者之一到来时，从此函数获得的迭代器被非法化。

参数

v - 数值数组

返回值

指向数值数组中首个值的迭代器。

异常

可能抛出实现定义的异常。

注解

不同于其他接收 std::valarray 参数的函数， begin() 不能接受可从涉及 valarray 的表达式返回的替换类型（例如表达式模板所产生的类型）： std::begin (v1 + v2) 不可移植，必须用 std::begin ( std::valarray <T>(v1 + v2)) 代替。

此函数的意图是允许范围 for 循环能作用于 valarray ，而非提供容器语义。

示例

#include <iostream>
#include <valarray>
#include <algorithm>

auto show = [](std::valarray<int> const& v) {
    std::for_each(std::begin(v), std::end(v), [](int c) {
        std::cout << c << ' ';
    });
    std::cout << '\n';
};

int main()
{
    const std::valarray<int> x { 47, 70, 37, 52, 90, 23, 17, 33, 22, 16, 21, 4 };
    const std::valarray<int> y { 25, 31, 71, 56, 21, 21, 15, 34, 21, 27, 12, 6 };

    show(x);
    show(y);

    const std::valarray<int> z { x + y };

    std::for_each(std::begin(z), std::end(z), [](char c) { std::cout << c; });
}

输出：

47 70 37 52 90 23 17 33 22 16 21 4
25 31 71 56 21 21 15 34 21 27 12 6
Hello, C++!

参阅

std::end(std::valarray)
(C++11)
 特化的 std::end
(函数模板)


std::cos(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
valarray<T> cos( const valarray<T>& va );

对 va 中每个元素计算元素值的余弦。

参数

va - 要应用操作到的值数组

返回值

含有 va 中值的余弦的值数组。

注解

用无限定函数 (cos) 进行计算。若该函数不可用，则因参数依赖查找使用 std::cos 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

可能的实现

template<class T>
valarray<T> cos(const valarray<T>& va)
{
    valarray<T> other = va;
    for (T &i : other) {
        i = cos(i);
    }
    return other;
}

示例

#include <cmath>
#include <iomanip>
#include <iostream>
#include <valarray>

void show(const char* title, const std::valarray<float>& data)
{
    const int w { 9 };
    std::cout << std::setw(w) << title << " | ";
    for (float x : data)
        std::cout << std::setw(w) << x << " | ";
    std::cout << '\n';
}

int main()
{
    const std::valarray<float> x { .1, .2, .3, .4 };
    const auto sin = std::sin(x);
    const auto cos = std::cos(x);
    const auto z = (sin * sin) + (cos * cos);

    show("x"     , x  );
    show("sin(x)", sin);
    show("cos(x)", cos);
    show("z"     , z  );
}

输出：

        x |       0.1 |       0.2 |       0.3 |       0.4 |
   sin(x) | 0.0998334 |  0.198669 |   0.29552 |  0.389418 |
   cos(x) |  0.995004 |  0.980067 |  0.955337 |  0.921061 |
        z |         1 |         1 |         1 |         1 |

参阅

sin(std::valarray) | 对 valarray 的每个元素应用std::sin函数 (函数模板)
tan(std::valarray) | 应用函数 std::tan 到 valarray 的每个元素 (函数模板)
acos(std::valarray) | 应用函数 std::acos 到 valarray 的每个元素 (函数模板)
coscosfcosl (C++11)(C++11) | 计算余弦（ \({\small\cos{x} }\)cos(x) ） (函数)
cos(std::complex) | 计算复数的余弦（ \({\small\cos{z} }\)cos(z) ） (函数模板)


std::cosh(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
valarray<T> cosh( const valarray<T>& va );

对 va 中每个元素计算元素值的双曲余弦。

参数

va - 应用操作到的值数组

返回值

含有 va 中值的双曲余弦的值数组。

注解

用无限定函数 (cosh) 进行计算。若该函数不可用，则因参数依赖查找使用 std::cosh 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

可能的实现

template<class T>
valarray<T> cosh(const valarray<T>& va)
{
    valarray<T> other = va;
    for (T &i : other) {
        i = cosh(i);
    }
    return other;
}

示例

#include <cmath>
#include <iomanip>
#include <iostream>
#include <valarray>

void show(const char* title, const std::valarray<float>& data)
{
    const int w { 9 };
    std::cout << std::setw(w) << title << " | ";
    for (float x : data)
        std::cout << std::setw(w) << x << " | ";
    std::cout << '\n';
}

int main()
{
    const std::valarray<float> x { .1, .2, .3, .4 };
    const auto sinh = std::sinh(x);
    const auto cosh = std::cosh(x);
    const auto z = (cosh * cosh) - (sinh * sinh);

    show("x"      , x   );
    show("sinh(x)", sinh);
    show("cosh(x)", cosh);
    show("z"      , z   );
}

输出：

        x |       0.1 |       0.2 |       0.3 |       0.4 |
  sinh(x) |  0.100167 |  0.201336 |   0.30452 |  0.410752 |
  cosh(x) |     1.005 |   1.02007 |   1.04534 |   1.08107 |
        z |         1 |         1 |         1 |         1 |

参阅

sinh(std::valarray) | 在 valarray 的每个元素上调用 std::sinh 函数 (函数模板)
tanh(std::valarray) | 在 valarray 的每个元素上调用 std::tanh 函数 (函数模板)
coshcoshfcoshl (C++11)(C++11) | 计算双曲余弦（ \({\small\cosh{x} }\)cosh(x) ） (函数)
cosh(std::complex) | 计算复数的双曲余弦（ \({\small\cosh{z} }\)cosh(z) ） (函数模板)


std::valarray<T>::cshift

< cpp‎ | numeric‎ | valarray
valarray<T> cshift( int count ) const;

返回同大小的新 valarray ，其每个元素的位置被循环迁移 count 个元素。每个元素的新位置是 (i−count) mod s ，其中 i 为先前位置，而 s 为 size() 。

参数

count - 元素迁移的位置数

返回值

作为结果的 valarray ，拥有循环迁移的元素。

注意

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

示例

#include <iostream>
#include <valarray>

int main() {
    std::valarray<int> v{1, 2, 3, 4, 5, 6, 7, 8};

    for (auto const& val : v) {
        std::cout << val << " ";
    }
    std::cout << "\n";

    std::valarray<int> v2 = v.cshift(2);

    for (auto const& val : v2) {
        std::cout << val << " ";
    }
    std::cout << "\n";
}

输出：

1 2 3 4 5 6 7 8
3 4 5 6 7 8 1 2

参阅

shift
 以填入零的方式移动 valarray 的元素
(公开成员函数)


std::valarray 的推导指引

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template<typename T, std::size_t cnt>
valarray(const T(&)[cnt], std::size_t ) -> valarray<T>;
 (C++17 起)

为 std::valarray 提供此推导指引以允许从数组和大小推导（注意从指针和大小推导已为隐式指引所涵盖）

示例

#include <valarray>
int main() {
  int a[] = {1, 2, 3};
  std::valarray va(a, 3); // 使用显示推导指引
}


std::end(std::valarray)

< cpp‎ | numeric‎ | valarray
template< class T > /*unspecified1*/ end( valarray<T>& v ); | (1) | (C++11 起)
template< class T > /*unspecified2*/ end( const valarray<T>& v ); | (2) | (C++11 起)

std::end 对 valarray 的重载返回指代数值数组中末元素后一位置的未指定类型的迭代器。

1) 返回类型满足可变老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。
2) 返回类型满足常老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。

在数组 v 上调用成员函数 resize() ，或在 v 的生存期结束，两者之一到来时，从此函数获得的迭代器被非法化。

参数

v - 数值数组

参数

v - 数值数组

返回值

指向数值数组中最后的值后一位置的迭代器。

异常

可能抛出实现定义的异常。

注解

不同于其他接收 std::valarray 参数的函数， end() 不能接受可从涉及 valarray 的表达式返回的替换类型（例如表达式模板所产生的类型）： std::end (v1 + v2) 不可移植，必须用 std::end ( std::valarray <T>(v1 + v2)) 代替。

此函数的意图是允许范围 for 循环能作用于 valarray ，而非提供容器语义。

示例

#include <iostream>
#include <valarray>
#include <algorithm>

int main()
{
    const std::valarray<char> va {
        'H', 'e', 'l', 'l', 'o',
        ',', ' ',
        'C', '+', '+', '!', '\n'
    };

    std::for_each(
        std::begin(va),
        std::end(va),
        [](char c) {
            std::cout << c;
        });
}

可能的输出：

Hello, C++!

参阅

std::begin(std::valarray)
(C++11)
 特化的 std::begin
(函数模板)


std::exp(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
valarray<T> exp( const valarray<T>& va );

对 va 中每个元素，计算 e 的元素值次幂。

参数

va - 要应用操作到的值数组

返回值

含有 e 的 va 中值次幂的值数组。

注解

用无限定函数 (exp) 进行计算。若该函数不可用，则因参数依赖查找使用 std::exp 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

可能的实现

template< class T >
valarray<T> exp( const valarray<T>& va )
{
    valarray<T> other = va;
    for (T &i : other) {
        i = exp(i);
    }
    return other; // 亦可返回代理对象
}

示例

此示例演示欧拉恒等式 eiπ
 = -1 和相关的指数。

#include <iostream>
#include <complex>
#include <valarray>

int main()
{
    const double pi = std::acos(-1);
    std::valarray<std::complex<double>> v = {
        {0, 0}, {0, pi/2}, {0, pi}, {0, 3*pi/2}, {0, 2*pi}
    };
    std::valarray<std::complex<double>> v2 = std::exp(v);
    for(auto n : v2) {
        std::cout << std::showpos << std::fixed << n << '\n';
    }
}

输出：

(+1.000000,+0.000000)
(+0.000000,+1.000000)
(-1.000000,+0.000000)
(-0.000000,-1.000000)
(+1.000000,-0.000000)

参阅

log(std::valarray) | 应用函数 std::log 到 valarray 的每个元素 (函数模板)
expexpfexpl (C++11)(C++11) | 返回 e 的给定次幂（ \({\small e^x}\)ex ） (函数)
exp(std::complex) | 以 e 为底复数的指数 (函数模板)


std::gslice

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
class gslice;

std::gslice 是标识 std::valarray 下标子集的选择器，以跨度和大小的多层集定义。 std::gslice 类型对象可用作 valarray 的 operator[] 所选择的下标，例如，表示为 valarray 的多维数组的列。

给定起始值 s 、跨度列表 i
j 及大小列表 d
j ，从这些值构造的 std::gslice 选择下标集 k
j=s+Σ
j(i
jd
j).

例如拥有始于下标 3 ，跨度为 {19,4,1} 长度为 {2,4,3} 的 gslice 生成下列坐标集：

3 + 0*19 + 0*4 + 0*1 = 3,
3 + 0*19 + 0*4 + 1*1 = 4,
3 + 0*19 + 0*4 + 2*1 = 5,
3 + 0*19 + 1*4 + 0*1 = 7,
3 + 0*19 + 1*4 + 1*1 = 8,
...
3 + 1*19 + 3*4 + 2*1 = 36

可以构造选择某些下标多于一次的 std::gslice 对象：若上述示例使用跨度 {1,1,1} ，则下标将是 {3, 4, 5, 4, 5, 6, ...} 。这种 gslice 只可用于 std::valarray::operator[] 的 const 版本的参数，否则行为未定义。

成员函数

(构造函数) | 构造通用切片 (公开成员函数)
startsizestride | 返回切片的参数 (公开成员函数)

std::gslice::gslice

gslice()
gslice( std::size_t start, const std::valarray < std::size_t >& sizes,
const std::valarray < std::size_t >& strides );
gslice( const gslice& other );

构造新的通用切片。

1) 默认构造函数。等价于 gslice(0, std::valarray < std::size_t >(), std::valarray < std::size_t >()) 。此构造函数的存在只为允许构造数组切片。
2) 以参数 start 、 sizes 、 strides 构造新切片。
3) 构造 other 的副本。

参数

start | - | 首元素的位置
sizes | - | 定义每个维度元素数量的数组
strides | - | 定义每个维度中前后元素间的位置差数的数组
other | - | 要复制的另一切片

std::slice::start, size, stride

std::size_t start() const; | (1)
std::valarray < std::size_t > size() const; | (2)
std::valarray < std::size_t > stride() const; | (3)

返回构造时传递给切片的参数——分别为起点、大小和跨度。

参数

（无）

返回值

切片的参数——分别为起点、大小及跨度。

复杂度

常数。

示例

演示使用 gslice 定位 3D 数组的列

#include <iostream>
#include <valarray>
void test_print(std::valarray<int>& v, int rows, int cols, int planes)
{
    for(int r=0; r<rows; ++r) {
        for(int c=0; c<cols; ++c) {
            for(int z=0; z<planes; ++z)
                std::cout << v[r*cols*planes + c*planes + z] << ' ';
            std::cout << '\n';
        }
        std::cout << '\n';
    }
}
int main()
{
    std::valarray<int> v = // 3d 数组： 2 x 4 x 3 元素
    { 111,112,113 , 121,122,123 , 131,132,133 , 141,142,143,
      211,212,213 , 221,222,223 , 231,232,233 , 241,242,243};
    // int ar3d[2][4][3]
    std::cout << "Initial 2x4x3 array:\n";
    test_print(v, 2, 4, 3);

    // 更新两个平面第一列的每个值
    v[std::gslice(0, {2, 4}, {4*3, 3})] = 1; // 二层的一个 12 元素跨度
                                             // 然后是四层的二个 3 元素跨度

    // 从第一平面的第二列减去第三列的值
    v[std::gslice(1, {1, 4}, {4*3, 3})] -= v[std::gslice(2, {1, 4}, {4*3, 3})];

    std::cout << "After column operations: \n";
    test_print(v, 2, 4, 3);
}

输出：

Initial 2x4x3 array:
111 112 113
121 122 123
131 132 133
141 142 143

211 212 213
221 222 223
231 232 233
241 242 243

After column operations:
1 -1 113
1 -1 123
1 -1 133
1 -1 143

1 212 213
1 222 223
1 232 233
1 242 243

参阅

operator[] | 获取/设置 valarray 数组元素、切片或掩码 (公开成员函数)
slice | valarray 的 BLAS 式切片：起始下标、长度、跨度 (类)
gslice_array | valarray 应用 gslice 后的子集的代理 (类模板)


std::gslice_array

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T > class gslice_array;

std::gslice_array 是 std::gslice 的下标运算符所用的帮助模板。它拥有到 std::gslice 对象所指定的数组子集的引用语义。

成员类型

类型 | 定义
value_type | T

成员函数

(构造函数) | 构造一个 gslice_array (公开成员函数)
(析构函数) | 销毁一个 gslice_array (公开成员函数)
operator= | 赋值内容 (公开成员函数)
operator+=operator-=operator*=operator/=operator%=operator&=operator|=operator^=operator<<=operator>>= | 在通用切片所指代的数组上进行算术运算。 (公开成员函数)

示例

本节未完成
原因：暂无示例

参阅

slice_array
 到 valarray 应用 slice 后的子集的代理
(类模板)


std::gslice_array<T>::gslice_array

< cpp‎ | numeric‎ | valarray‎ | gslice array

gslice_array( const gslice_array& other );
gslice_array() = delete;

从另一 gslice_array other 构造 gslice_array 。

默认构造函数被隐式删除。

参数

other - 用来初始化的 gslice_array


std::gslice_array<T>::operator=

< cpp‎ | numeric‎ | valarray‎ | gslice array

void operator=( const T& value ) const; | (1) |
void operator=( const std::valarray <T>& val_arr ) const; | (2) |
const gslice_array& operator=( const gslice_array& sl_arr) const; | (3) | (C++11 起)

将值赋值给所有被引用元素。

1) 将 value 赋值给所有元素。
2) 将 val_arr 的元素赋值给 *this 所引用的元素。
3) 将自 sl_arr 选择的元素赋值给 *this 所引用的元素。

参数

value | - | 赋值给所有被引用元素的值
val_arr | - | 用以赋值的 std::valarray
sl_arr | - | 用以赋值的 std::gslice_array

返回值

1-2) （无）
3) *this

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例


std::gslice_array<T>::operator+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=

< cpp‎ | numeric‎ | valarray‎ | gslice array

void operator+=( const std::valarray <T>& other ) const;
void operator-=( const std::valarray <T>& other ) const;
void operator*=( const std::valarray <T>& other ) const;
void operator/=( const std::valarray <T>& other ) const;
void operator%=( const std::valarray <T>& other ) const;
void operator&=( const std::valarray <T>& other ) const;
void operator|=( const std::valarray <T>& other ) const;
void operator^=( const std::valarray <T>& other ) const;
void operator<<=( const std::valarray <T>& other ) const;
void operator>>=( const std::valarray <T>& other ) const;

应用给定的运算到所引用元素和 other 的元素。

参数

other - 作为获取值来源的参数数组

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例


std::gslice_array<T>::~gslice_array

< cpp‎ | numeric‎ | valarray‎ | gslice array

~gslice_array();

销毁数组中的下标。不修改对象所引用的元素。


std::indirect_array

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T > class indirect_array;

std::indirect_array 是 std::valarray 对 std::valarray < std::size_t > 的下标运算符所用的帮助模板。它拥有到间接数组（ std::valarray < std::size_t > 对象）所指定的数组子集的引用语义。

成员类型

类型 | 定义
value_type | T

成员函数

(构造函数) | 构造一个 indirect_array (公开成员函数)
(析构函数) | 销毁一个 indirect_array (公开成员函数)
operator= | 赋值内容 (公开成员函数)
operator+=operator-=operator*=operator/=operator%=operator&=operator|=operator^=operator<<=operator>>= | 在间接数组所指代的数组上进行算术运算。 (公开成员函数)

示例

#include <iostream>
#include <valarray>

int main()
{
    std::valarray<int> data = {0,1,2,3,4,5,6,7,8,9};

    std::valarray<std::size_t> idx = {0,2,4,6,8};

    std::cout << "Original valarray: ";
    for(int n: data) std::cout << n << ' ';
    std::cout << '\n';

    data[idx] += data[idx]; // 令在下标 'idx' 的值变为双倍

    // data[idx] 的类型是 std::indirect_array<int>

    std::cout << "After indirect modification: ";
    for(int n: data) std::cout << n << ' ';
    std::cout << '\n';
}

输出：

Original valarray: 0 1 2 3 4 5 6 7 8 9
After indirect modification: 0 1 4 3 8 5 12 7 16 9


std::indirect_array<T>::indirect_array

< cpp‎ | numeric‎ | valarray‎ | indirect array

indirect_array( const indirect_array& other );
indirect_array() = delete;

从另一 indirect_array other 构造 indirect_array 。

默认构造函数被隐式删除。

参数

other - 用来初始化的 indirect_array


std::indirect_array<T>::operator=

< cpp‎ | numeric‎ | valarray‎ | indirect array

void operator=( const T& value ) const; | (1) |
void operator=( const std::valarray <T>& val_arr ) const; | (2) |
const indirect_array& operator=( const indirect_array& sl_arr) const; | (3) | (C++11 起)

将值赋值给所有被引用元素。

1) 将 value 赋值给所有元素。
2) 将 val_arr 的元素赋值给 *this 所引用的元素。
3) 将自 sl_arr 选择的元素赋值给 *this 所引用的元素。

参数

value | - | 赋值给所有被引用元素的值
val_arr | - | 用以赋值的 std::valarray
sl_arr | - | 用以赋值的 std::indirect_array

返回值

1-2) （无）
3) *this

异常

可能抛出实现定义的异常。

示例

#include <iomanip>
#include <iostream>
#include <valarray>
#include <numeric>

void print(int n, std::valarray<int> const& v)
{
    std::cout << n << ':';
    for (int e : v) std::cout << std::setw(3) << e;
    std::cout << '\n';
}

int main()
{
    std::valarray<int> v(8);
    std::iota(std::begin(v), std::end(v), 0);
    print(1, v);

    std::valarray<std::size_t> idx{1, 3, 5, 7};
    const std::indirect_array<int> ia = v[idx];
    // 'ia' 代表 v[1], v[3], v[5], v[7]
    ia = -1; // (1) ，等效地：
             // v[1] = v[3] = v[5] = v[7] = -1;
    print(2, v);

    ia = /*std::valarray<int>*/{-1, -2, -3, -4}; // (2) ，
        // 等效地： v[1]=-1, v[3]=-2, v[5]=-3, v[7]=-4;
    print(3, v);

    std::valarray<std::size_t> idx2{0, 2, 4, 6};
    const std::indirect_array<int> ia2 = v[idx2];
    // 'ia2' refers to v[0], v[2], v[4], v[6]
    ia = ia2; // (3) ，等效地：
              // v[1]=v[0], v[3]=v[2], v[5]=v[4], v[7]=v[6];
    print(4, v);
}

输出：

1:  0  1  2  3  4  5  6  7
2:  0 -1  2 -1  4 -1  6 -1
3:  0 -1  2 -2  4 -3  6 -4
4:  0  0  2  2  4  4  6  6


std::indirect_array<T>::operator+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=

< cpp‎ | numeric‎ | valarray‎ | indirect array

void operator+=( const std::valarray <T>& other ) const;
void operator-=( const std::valarray <T>& other ) const;
void operator*=( const std::valarray <T>& other ) const;
void operator/=( const std::valarray <T>& other ) const;
void operator%=( const std::valarray <T>& other ) const;
void operator&=( const std::valarray <T>& other ) const;
void operator|=( const std::valarray <T>& other ) const;
void operator^=( const std::valarray <T>& other ) const;
void operator<<=( const std::valarray <T>& other ) const;
void operator>>=( const std::valarray <T>& other ) const;

应用给定的运算到所引用元素和 other 的元素。

参数

other - 作为获取值来源的参数数组

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例


std::indirect_array<T>::~indirect_array

< cpp‎ | numeric‎ | valarray‎ | indirect array

~indirect_array();

销毁数组中的下标。不修改对象所引用的元素。


std::log(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
valarray<T> log( const valarray<T>& va );

对 va 中每个元素计算元素值的自然对数。

参数

va - 要应用操作到的值数组

返回值

含有 va 中每个值的自然对数的值数组。

注解

用无限定函数 (log) 进行计算。若该函数不可用，则因参数依赖查找使用 std::log 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

可能的实现

template< class T >
valarray<T> log( const valarray<T>& va )
{
    valarray<T> other = va;
    for (T &i : other) {
        i = log(i);
    }
    return other;
}

示例

#include <iomanip>
#include <iostream>
#include <valarray>

void show(char const* title, const std::valarray<double>& va)
{
    std::cout << title << " :" << std::right << std::fixed;
    for (double x : va) {
        std::cout << std::setw(10) << x;
    }
    std::cout << '\n';
}

int main()
{
    const std::valarray<double> n { 0.0, 1.0, 2.0, 3.0 };
    const std::valarray<double> exp_n { std::exp(n) };
    const std::valarray<double> log_exp_n { std::log(exp_n) };

    show("n      ", n);
    show("eⁿ     ", exp_n);
    show("log(eⁿ)", log_exp_n);
}

输出：

n       :  0.000000  1.000000  2.000000  3.000000
eⁿ      :  1.000000  2.718282  7.389056 20.085537
log(eⁿ) :  0.000000  1.000000  2.000000  3.000000

参阅

log10(std::valarray) | 应用函数 std::log10 到 valarray 的每个元素 (函数模板)
exp(std::valarray) | 应用函数 std::exp 到 valarray 的每个元素 (函数模板)
loglogflogl (C++11)(C++11) | 计算自然（以 e 为底）对数（ \({\small \ln{x} }\)ln(x) ） (函数)
log(std::complex) | 沿负实轴切割的复自然对数 (函数模板)


std::log10(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
valarray<T> log10( const valarray<T>& va );

对 va 中每个元素计算元素值的常用（底 10 ）对数。

参数

va - 要应用操作到的值数组

返回值

含有 va 中值的常用对数的值数组。

注解

用无限定函数 (log10) 进行计算。若该函数不可用，则因参数依赖查找使用 std::log10 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

可能的实现

template< class T >
valarray<T> log10( const valarray<T>& va )
{
    valarray<T> other = va;
    for (T &i : other) {
        i = log10(i);
    }
    return other;
}

示例

#include <cmath>
#include <iomanip>
#include <iostream>
#include <valarray>

void show(char const* title, const std::valarray<float>& va)
{
    std::cout << title << " : " << std::right;
    for (float x : va) {
        std::cout << std::setw(6) << x;
    }
    std::cout << '\n';
}

int main()
{
    const std::valarray<float> n { -2.f, -1.f, 0.f, 1.f, 2.f, 3.f, INFINITY };
    const std::valarray<float> pow10 { std::pow(10.f, n) };
    const std::valarray<float> log10_pow10 { std::log10(pow10) };

    show("n      ", n);
    show("10ⁿ    ", pow10);
    show("lg(10ⁿ)", log10_pow10);
}

输出：

n       :     -2    -1     0     1     2     3   inf
10ⁿ     :   0.01   0.1     1    10   100  1000   inf
lg(10ⁿ) :     -2    -1     0     1     2     3   inf

参阅

log(std::valarray) | 应用函数 std::log 到 valarray 的每个元素 (函数模板)
log10log10flog10l (C++11)(C++11) | 计算常用（以 10 为底）对数（ \({\small \log_{10}{x} }\)log10(x) ） (函数)
log10(std::complex) | 沿负实轴分割的复常用对数 (函数模板)


std::mask_array

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T > class mask_array;

std::mask_array 是以std::valarray<bool> 为参数的 valarray 下标运算符所用的帮助模板。它拥有引用语义，并提供到由下标对应 std::valarray <bool> 掩码的 true 值的元素所组成的 valarray 子集的访问。

成员类型

类型 | 定义
value_type | T

成员函数

(构造函数) | 构造一个 mask_array (公开成员函数)
(析构函数) | 销毁一个 mask_array (公开成员函数)
operator= | 赋值内容 (公开成员函数)
operator+=operator-=operator*=operator/=operator%=operator&=operator|=operator^=operator<<=operator>>= | 在掩码所指代的数组上进行算术运算。 (公开成员函数)

参阅

#include <iostream>
#include <valarray>

int main()
{
    std::valarray<int> data = {0,1,2,3,4,5,6,7,8,9};

    std::cout << "Initial valarray: ";
    for(int n: data) std::cout << n << ' ';
    std::cout << '\n';

    data[data > 5] = -1;
    // data>5 的类型是 std::valarray<bool>
    // data[data>5] 的类型是 std::mask_array<int>

    std::cout << "After v[v>5]=-1:  ";
    for(int n: data) std::cout << n << ' ';
    std::cout << '\n';
}

输出：

Initial valarray: 0 1 2 3 4 5 6 7 8 9
After v[v>5]=-1:  0 1 2 3 4 5 -1 -1 -1 -1


std::mask_array<T>::mask_array

< cpp‎ | numeric‎ | valarray‎ | mask array

mask_array( const mask_array& other );
mask_array() = delete;

从另一 mask_array other 构造 mask_array 。

默认构造函数被隐式删除。

参数

other - 用来初始化的 mask_array


std::mask_array<T>::operator=

< cpp‎ | numeric‎ | valarray‎ | mask array

void operator=( const T& value ) const; | (1) |
void operator=( const std::valarray <T>& val_arr ) const; | (2) |
const mask_array& operator=( const mask_array& sl_arr) const; | (3) | (C++11 起)

将值赋值给所有被引用元素。

1) 将 value 赋值给所有元素。
2) 将 val_arr 的元素赋值给 *this 所引用的元素。
3) 将自 sl_arr 选择的元素赋值给 *this 所引用的元素。

参数

value | - | 赋值给所有被引用元素的值
val_arr | - | 用以赋值的 std::valarray
sl_arr | - | 用以赋值的 std::mask_array

返回值

1-2) （无）
3) *this

异常

可能抛出实现定义的异常。

示例

#include <iomanip>
#include <iostream>
#include <valarray>

void print(std::valarray<int> const& v)
{
    for (int e : v) std::cout << std::setw(2) << e << ' ';
    std::cout << '\n';
}

int main()
{
    const auto init = {1, 2, 3, 4, 5, 6, 7, 8};
    std::valarray<int> v;

    v = init;
    v[(v % 2) == 0] = 0; // (1)
    print(v);

    v = init;
    v[(v % 2) == 1] = std::valarray<int>{-1, -2, -3, -4}; // (2)
    print(v);

    v = init;
    v[(v % 2) == 0] = v[(v % 2) == 1]; // (3)
    print(v);
}

输出：

 1  0  3  0  5  0  7  0
-1  2 -2  4 -3  6 -4  8
 1  1  3  3  5  5  7  7


std::mask_array<T>::operator+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=

< cpp‎ | numeric‎ | valarray‎ | mask array

void operator+=( const std::valarray <T>& other ) const;
void operator-=( const std::valarray <T>& other ) const;
void operator*=( const std::valarray <T>& other ) const;
void operator/=( const std::valarray <T>& other ) const;
void operator%=( const std::valarray <T>& other ) const;
void operator&=( const std::valarray <T>& other ) const;
void operator|=( const std::valarray <T>& other ) const;
void operator^=( const std::valarray <T>& other ) const;
void operator<<=( const std::valarray <T>& other ) const;
void operator>>=( const std::valarray <T>& other ) const;

应用给定的运算到所引用元素和 other 的元素。

参数

other - 作为获取值来源的参数数组

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例


std::mask_array<T>::~mask_array

< cpp‎ | numeric‎ | valarray‎ | mask array

~mask_array();

销毁数组中的下标。不修改对象所引用的元素。


std::valarray<T>::max

< cpp‎ | numeric‎ | valarray
T max() const;

计算元素的最大值。

若无元素，则行为未定义。

仅若 operator< 对类型 T 定义才能使用该函数。

参数

（无）

返回值

元素的最大值。

示例

#include <valarray>
#include <iostream>

int main()
{
    std::valarray<double> a{1, 2, 3, 4, 5, 6, 7, 8};
    std::cout << "Maximum value : " << a.max() << "\n";
}

输出：

Maximum value : 8

参阅

min
 返回最小元素
(公开成员函数)


std::valarray<T>::min

< cpp‎ | numeric‎ | valarray
T min() const;

计算元素的最小值。

若无元素，则行为未定义。

仅若 operator< 对类型 T 定义才能使用该函数。

参数

（无）

返回值

元素的最小值。

示例

#include <valarray>
#include <iostream>

int main()
{
    std::valarray<double> a{1, 2, 3, 4, 5, 6, 7, 8};
    std::cout << "Minimum value : " << a.min() << "\n";
}

输出：

Minimum value : 1

参阅

max
 返回最大的元素
(公开成员函数)


std::valarray<T>::operator=

< cpp‎ | numeric‎ | valarray
valarray<T>& operator=( const valarray<T>& other ); | (1) |
valarray<T>& operator=( valarray<T>&& other ) noexcept; | (2) | (C++11 起)
valarray<T>& operator=( const T& val ); | (3) |
valarray<T>& operator=( const std::slice_array <T>& other); | (4) |
valarray<T>& operator=( const std::gslice_array <T>& other); | (5) |
valarray<T>& operator=( const std::mask_array <T>& other ); | (6) |
valarray<T>& operator=( const std::indirect_array <T>& other ); | (7) |
valarray<T>& operator=( std::initializer_list <T> il ); | (8) | (C++11 起)

替换数值数组的内容。

1) 复制赋值运算符。 *this 的每个元素被赋 other 的值。若 other 的长度不等于 *this 的长度，则行为未定义 (C++11 前)首先如通过 resize(other.size()) 重置大小 (C++11 起)。
2) 移动赋值运算符。以 other 的内容替换 *this 的内容。此操作后 other 的内容未指定。若 T 拥有非平凡构造函数则此操作的复杂度可能为线性，但否则通常为常数。
3) 以f val 的副本替换 *this 中的每个值。
4-7) 以泛型化下标运算的结果替换 *this 的内容。若参数的长度不等于 *this 的长度，或若任何左侧的值依赖右侧的值（例如 v=v[v>2] ），则行为未定义。
8) 赋值 il 的内容。等价于 *this = valarray(il) 。

参数

other | - | 要赋值的另一数值数组（或掩码）
val | - | 用以初始化每个元素的值
il | - | 要赋值的 initializer_list

返回值

*this

异常

1, 3-8) 可能抛出实现定义的异常。

示例

#include <iomanip>
#include <iostream>
#include <valarray>

void print(const char* rem, const std::valarray<int>& v)
{
    std::cout << std::left << std::setw(36) << rem << std::right;
    for (int n: v) std::cout << std::setw(3) << n;
    std::cout << '\n';
}

int main()
{
    std::valarray<int> v1(3);
    v1 = -1; // (3) 从标量
    print("assigned from scalar: ", v1);

    v1 = {1, 2, 3, 4, 5, 6}; // (8) ：从不同大小的初始化器列表
    print("assigned from initializer_list:", v1);

    std::valarray<int> v2(3);
    v2 = v1[std::slice(0,3,2)]; // (4) ：从切片数组
    print("every 2nd element starting at pos 0:", v2);

    v2 = v1[v1 % 2 == 0]; // (6) ：从掩码数组
    print("values that are even:", v2);

    std::valarray<std::size_t> idx = {0,1,2,4}; // 下标数组
    v2.resize(4); // 从生成下标赋值时大小必须匹配
    v2 = v1[idx]; // (7) ：从间接数组
    print("values at positions 0, 1, 2, 4:", v2);
}

输出：

assigned from scalar:                -1 -1 -1
assigned from initializer_list:       1  2  3  4  5  6
every 2nd element starting at pos 0:  1  3  5
values that are even:                 2  4  6
values at positions 0, 1, 2, 4:       1  2  3  5


std::valarray<T>::operator+,-,~,!

< cpp‎ | numeric‎ | valarray
valarray<T> operator+() const; | (1)
valarray<T> operator-() const; | (2)
valarray<T> operator~() const; | (3)
valarray<bool> operator!() const; | (4)

应用一元运算符到数值数组的每个元素。

参数

（无）

返回值

含有元素的数值数组，元素值由应用对应运算符到 *this 中的值获得。

异常

可能抛出实现定义的异常。

注解

仅若满足下列要求，才能实例化每个运算符：

  • 指示的运算符能应用到类型 T
  • 返回值能无歧义地转换为 T (1-3) 或 bool (4) 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

示例

本节未完成
原因：暂无示例


std::valarray<T>::operator+=,-=,*=,/=,%=,&=,|=,<<=,>>=

< cpp‎ | numeric‎ | valarray
valarray<T> operator+=( const valarray<T>& v );

valarray<T> operator-=( const valarray<T>& v );
valarray<T> operator*=( const valarray<T>& v );
valarray<T> operator/=( const valarray<T>& v );
valarray<T> operator%=( const valarray<T>& v );
valarray<T> operator&=( const valarray<T>& v );
valarray<T> operator|=( const valarray<T>& v );
valarray<T> operator^=( const valarray<T>& v );
valarray<T> operator<<=( const valarray<T>& v );

valarray<T> operator>>=( const valarray<T>& v );
 (1)
valarray<T> operator+=( const T& val );

valarray<T> operator-=( const T& val );
valarray<T> operator*=( const T& val );
valarray<T> operator/=( const T& val );
valarray<T> operator%=( const T& val );
valarray<T> operator&=( const T& val );
valarray<T> operator|=( const T& val );
valarray<T> operator^=( const T& val );
valarray<T> operator<<=( const T& val );

valarray<T> operator>>=( const T& val );
 (2)

应用复合赋值运算符到数值数组中的每个元素。

1) 将以应用对应运算符到每个元素先前值和来自 v 的对应元素所获得的值，赋值给每个元素。
若 size() != v.size() 则行为未定义。
若任何 v 中的值在赋值过程中计算并依赖任何 *this 中的值，即赋值右侧的表达式引用到赋值左侧的变量，则行为未定义。
2) 将以应用对应运算符到每个元素先前值和 val 的值所获得的值，赋值给每个元素。

参数

v | - | 另一个数值数组
val | - | 一个值

返回值

*this

异常

可能抛出实现定义的异常。

注解

仅若满足下列条件，才能实例化各个运算符：

  • 所指示的运算符可应用于类型 T
  • 返回值可以无歧义地转换为 T 。

示例

#include <iostream>
#include <string_view>
#include <type_traits>
#include <valarray>

void o(std::string_view rem, auto const& v, bool nl = false) {
    if constexpr (std::is_scalar_v<std::decay_t<decltype(v)>>) {
        std::cout << rem << " : " << v;
    } else {
        for (std::cout << rem << " : { "; auto const e : v)
            std::cout << e << ' ';
        std::cout << "}";
    }
    std::cout << (nl ? "\n" : ";  ");
}

int main()
{
    std::valarray<int> x, y;

    o("x", x = {1, 2, 3, 4}), o("y", y = {4, 3, 2, 1}), o("x += y", x += y, 1);
    o("x", x = {4, 3, 2, 1}), o("y", y = {3, 2, 1, 0}), o("x -= y", x -= y, 1);
    o("x", x = {1, 2, 3, 4}), o("y", y = {5, 4, 3, 2}), o("x *= y", x *= y, 1);
    o("x", x = {1, 3, 4, 7}), o("y", y = {1, 1, 3, 5}), o("x &= y", x &= y, 1);
    o("x", x = {0, 1, 2, 4}), o("y", y = {4, 3, 2, 1}), o("x <<=y", x <<=y, 1);

    o("x", x = {1, 2, 3, 4}), o("x += 5", x += 5, 1);
    o("x", x = {1, 2, 3, 4}), o("x *= 2", x *= 2, 1);
    o("x", x = {8, 6, 4, 2}), o("x /= 2", x /= 2, 1);
    o("x", x = {8, 4, 2, 1}), o("x >>=1", x >>=1, 1);
}

输出：

x : { 1 2 3 4 };  y : { 4 3 2 1 };  x += y : { 5 5 5 5 }
x : { 4 3 2 1 };  y : { 3 2 1 0 };  x -= y : { 1 1 1 1 }
x : { 1 2 3 4 };  y : { 5 4 3 2 };  x *= y : { 5 8 9 8 }
x : { 1 3 4 7 };  y : { 1 1 3 5 };  x &= y : { 1 1 0 5 }
x : { 0 1 2 4 };  y : { 4 3 2 1 };  x <<=y : { 0 8 8 8 }
x : { 1 2 3 4 };  x += 5 : { 6 7 8 9 }
x : { 1 2 3 4 };  x *= 2 : { 2 4 6 8 }
x : { 8 6 4 2 };  x /= 2 : { 4 3 2 1 }
x : { 8 4 2 1 };  x >>=1 : { 4 2 1 0 }


operator+,-,*,/,%,&,|,^,<<,>>,&&,|| (std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template <class T>

std::valarray <T> operator+ (const std::valarray <T>& lhs, const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator- (const std::valarray <T>& lhs, const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator* (const std::valarray <T>& lhs, const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator/ (const std::valarray <T>& lhs, const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator% (const std::valarray <T>& lhs, const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator& (const std::valarray <T>& lhs, const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator| (const std::valarray <T>& lhs, const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator^ (const std::valarray <T>& lhs, const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator<<(const std::valarray <T>& lhs, const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator>>(const std::valarray <T>& lhs, const std::valarray <T>& rhs);
template <class T>
std::valarray <bool> operator&&(const std::valarray <T>& lhs, const std::valarray <T>& rhs);
template <class T>

std::valarray <bool> operator||(const std::valarray <T>& lhs, const std::valarray <T>& rhs);
 (1)
template <class T>

std::valarray <T> operator+ (const typename std::valarray <T>::value_type & val,
const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator- (const typename std::valarray <T>::value_type & val,
const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator* (const typename std::valarray <T>::value_type & val,
const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator/ (const typename std::valarray <T>::value_type & val,
const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator% (const typename std::valarray <T>::value_type & val,
const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator& (const typename std::valarray <T>::value_type & val,
const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator| (const typename std::valarray <T>::value_type & val,
const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator^ (const typename std::valarray <T>::value_type & val,
const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator<<(const typename std::valarray <T>::value_type & val,
const std::valarray <T>& rhs);
template <class T>
std::valarray <T> operator>>(const typename std::valarray <T>::value_type & val,
const std::valarray <T>& rhs);
template <class T>
std::valarray <bool> operator&&(const typename std::valarray <T>::value_type & val,
const std::valarray <T>& rhs);
template <class T>
std::valarray <bool> operator||(const typename std::valarray <T>::value_type & val,

const std::valarray <T>& rhs);
 (2)
template <class T>

std::valarray <T> operator+ (const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & val);
template <class T>
std::valarray <T> operator- (const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & val);
template <class T>
std::valarray <T> operator* (const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & val);
template <class T>
std::valarray <T> operator/ (const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & val);
template <class T>
std::valarray <T> operator% (const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & val);
template <class T>
std::valarray <T> operator& (const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & val);
template <class T>
std::valarray <T> operator| (const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & val);
template <class T>
std::valarray <T> operator^ (const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & val);
template <class T>
std::valarray <T> operator<<(const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & val);
template <class T>
std::valarray <T> operator>>(const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & val);
template <class T>
std::valarray <bool> operator&&(const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & val);
template <class T>
std::valarray <bool> operator||(const std::valarray <T>& lhs,

const typename std::valarray <T>::value_type & val);
 (3)

应用二元运算符到二个 valarray 的对应元素，或一个 valarray 和一个值。

1) 运算符作用于拥有同样大小的 valarray 并返回大小等于参数的 valarray ，将运算应用到二个参数的每个元素。
2,3) 在 valarray 的每个元素和标量间应用运算符。

参数

rhs | - | 数值数组
lhs | - | 数值数组
val | - | 类型 T 的值

返回值

大小等于参数的 valarray 。

注解

若二个参数是不同大小的 valarray 则行为未定义。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

示例

寻找多个二次方程的实根。

#include <cstddef>
#include <valarray>
#include <iostream>

int main()
{
    std::valarray<double> a(1, 8);
    std::valarray<double> b{1, 2, 3, 4, 5, 6, 7, 8};
    std::valarray<double> c = -b;
    // LWG3074 前字面量亦必须拥有 T 类型（此情况下为 double ）
    std::valarray<double> d = std::sqrt(b * b - 4.0 * a * c);
    std::valarray<double> x1 = (-b - d) / (2.0 * a);
    std::valarray<double> x2 = (-b + d) / (2.0 * a);
    std::cout << "quadratic equation    root 1,  root 2" << "\n";
    for (std::size_t i = 0; i < a.size(); ++i) {
        std::cout << a[i] << "x\u00B2 + " << b[i] << "x + " << c[i] << " = 0   ";
        std::cout << std::fixed << x1[i] << ", " << x2[i] << std::defaultfloat << "\n";
    }
}

输出：

quadratic equation    root 1,  root 2
1x² + 1x + -1 = 0   -1.618034, 0.618034
1x² + 2x + -2 = 0   -2.732051, 0.732051
1x² + 3x + -3 = 0   -3.791288, 0.791288
1x² + 4x + -4 = 0   -4.828427, 0.828427
1x² + 5x + -5 = 0   -5.854102, 0.854102
1x² + 6x + -6 = 0   -6.872983, 0.872983
1x² + 7x + -7 = 0   -7.887482, 0.887482
1x² + 8x + -8 = 0   -8.898979, 0.898979

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3074 | C++98 | (2-3) 从标量和 valarray 两者推导 T ，禁止混合类型的调用 | 仅从 valarray 推导 T


std::valarray<T>::operator[]

< cpp‎ | numeric‎ | valarray
 | (1)
T operator[]( std::size_t pos ) const; |  | (C++11 前)
const T& operator[]( std::size_t pos ) const; |  | (C++11 起)
T& operator[]( std::size_t pos ); | (2)
std::valarray <T> operator[]( std::slice slicearr ) const; | (3)
std::slice_array <T> operator[]( std::slice slicearr ); | (4)
std::valarray <T> operator[]( const std::gslice & gslicearr ) const; | (5)
std::gslice_array <T> operator[]( const std::gslice & gslicearr ); | (6)
std::valarray <T> operator[]( const valarray<bool>& boolarr ) const; | (7)
std::mask_array <T> operator[]( const valarray<bool>& boolarr ); | (8)
std::valarray <T> operator[]( const valarray< std::size_t >& indarr ) const; | (9)
std::indirect_array <T> operator[]( const valarray< std::size_t >& indarr ); | (10)

获取数组的单个元素或一部分。

const 重载返回元素序列，并创建新的 std::valarray 对象。 非 const 重载返回持有到数组元素引用的类。

参数

本节未完成
原因：解释参数

返回值

1,2) 到对应元素的引用
3,5,7,9) 含有被选择项副本的 std::valarray 对象
4,6,8,10) 包含到被选择项引用的对应数据结构

异常

可能抛出实现定义的异常。

前条件

被选择元素必须存在。

注解

  • 对于具体的值 i 与 j ，下列属性为 true ：
1) (a[i] = q, a[i]) == q
对于非 const 的 a 。
2) &a[i+j] == &a[i] + j
这表示 valarray 元素在内存中毗邻。
3) &a[i] != &b[j]
这对于每个互不为别称的对象 a 与 b 成立。
这表示元素没有别称，而且此属性可用于进行某些类型的优化。
  • 在 resize 或数组析构时引用变为非法。

对于重载 (3,5,7,9) ，函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

切片/掩码/间接访问不连锁： v[v==n][ std::slice (0,5,2)] = x; 是错误，因为 std::mask_array （ v[v==n] 的类型）无 operator[] 。

示例

#include <iostream>
#include <valarray>

int main()
{
    std::valarray<int> data = {0,1,2,3,4,5,6,7,8,9};

    std::cout << "Initial valarray: ";
    for(int n: data) std::cout << n << ' ';
    std::cout << '\n';

    data[data > 5] = -1; // operator[] 的 valarray<bool> 重载
    // data>5 的类型是 std::valarray<bool>
    // data[data>5] 的类型是 std::mask_array<int>

    std::cout << "After v[v>5]=-1:  ";
    for(std::size_t n = 0; n < data.size(); ++n)
      std::cout << data[n] << ' ';  // 常规 operator[]
    std::cout << '\n';
}

输出：

Initial valarray: 0 1 2 3 4 5 6 7 8 9
After v[v>5]=-1:  0 1 2 3 4 5 -1 -1 -1 -1


operator==,!=,<,<=,>,>=(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >

std::valarray <bool> operator==( const std::valarray <T>& lhs, const std::valarray <T>& rhs );
template< class T >
std::valarray <bool> operator!=( const std::valarray <T>& lhs, const std::valarray <T>& rhs );
template< class T >
std::valarray <bool> operator< ( const std::valarray <T>& lhs, const std::valarray <T>& rhs );
template< class T >
std::valarray <bool> operator<=( const std::valarray <T>& lhs, const std::valarray <T>& rhs );
template< class T >
std::valarray <bool> operator> ( const std::valarray <T>& lhs, const std::valarray <T>& rhs );
template< class T >

std::valarray <bool> operator>=( const std::valarray <T>& lhs, const std::valarray <T>& rhs );
 (1)
template< class T >

std::valarray <bool> operator==( const typename std::valarray <T>::value_type & lhsv,
const std::valarray <T>& rhs );
template< class T >
std::valarray <bool> operator!=( const typename std::valarray <T>::value_type & lhsv,
const std::valarray <T>& rhs );
template< class T >
std::valarray <bool> operator< ( const typename std::valarray <T>::value_type & lhsv,
const std::valarray <T>& rhs );
template< class T >
std::valarray <bool> operator<=( const typename std::valarray <T>::value_type & lhsv,
const std::valarray <T>& rhs );
template< class T >
std::valarray <bool> operator> ( const typename std::valarray <T>::value_type & lhsv,
const std::valarray <T>& rhs );
template< class T >
std::valarray <bool> operator>=( const typename std::valarray <T>::value_type & lhsv,

const std::valarray <T>& rhs );
 (2)
template< class T >

std::valarray <bool> operator==( const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & rhsv );
template< class T >
std::valarray <bool> operator!=( const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & rhsv );
template< class T >
std::valarray <bool> operator< ( const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & rhsv );
template< class T >
std::valarray <bool> operator<=( const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & rhsv );
template< class T >
std::valarray <bool> operator> ( const std::valarray <T>& lhs,
const typename std::valarray <T>::value_type & rhsv );
template< class T >
std::valarray <bool> operator>=( const std::valarray <T>& lhs,

const typename std::valarray <T>::value_type & rhsv );
 (3)

与另一值比较数值数组中的值。

1) 返回 bool 的数值数组，含应用指示的比较运算符到 lhs 与 rhs 的对应元素所获得的每个元素。

若 size() != v.size() 则行为未定义。

2) 返回 bool 的数值数组，含应用指示的比较运算符到 lhsv 与 rhs 的对应值所获得的每个元素。
3) 返回 bool 的数值数组，含应用指示的比较运算符到 lhs 的对应值与 rhsv 所获得的每个元素。

参数

lhs, rhs | - | 要比较的数值数组
lhsv, rhsv | - | 要与数值数组中每个元素比较的值

返回值

含对应元素比较结果的 bool 的数值数组。

异常

可能抛出实现定义的异常。

注解

仅若满足下列要求，每个运算符才能实例化：

  • 指示的运算符能应用于类型 T 。
  • 返回值能无歧义地转换为 bool 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

示例

#include <iostream>
#include <valarray>

int main()
{
    // 清零 valarray 中的所有负值
    std::valarray<int> v = {1, -1, 0, -3, 10, -1, -2};
    std::cout << "Before: ";
    for(auto n: v) {
        std::cout << n << ' ';
    }
    std::cout << '\n';
    v[v < 0] = 0;
    std::cout << "After: ";
    for(auto n: v) {
        std::cout << n << ' ';
    }
    std::cout << '\n';

    // 转换 == 的 valarray<bool> 结果为单个 bool
    std::valarray<int> a = {1,2,3};
    std::valarray<int> b = {2,4,6};

    std::cout << "2*a == b is " << std::boolalpha
              << (2*a == b).min() << '\n';

}

输出：

Before: 1 -1 0 -3 10 -1 -2
After: 1 0 0 0 10 0 0
2*a == b is true

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3074 | C++98 | (2-3) 从标量和 valarray 两者推导 T ，禁止混合类型的调用 | 仅从 valarray 推导 T


std::pow(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
std::valarray <T> pow( const std::valarray <T>& base, const std::valarray <T>& exp );
 (1)
template< class T >

std::valarray <T> pow( const std::valarray <T>& base,

const typename std::valarray <T>::value_type& vexp );
 (2)
template< class T >

std::valarray <T> pow( const typename std::valarray <T>::value_type& vbase,

const std::valarray <T>& exp );
 (3)

计算值的幂。

1) 计算数值数组 base 中的元素的幂，指数由来自数值数组 exp 的对应元素指定。

若 base.size() != exp.size() 则行为未定义。

2) 计算数值数组 base 中每个元素的 vexp 次幂。
3) 计算 vbase 的值以数值数组 exp 中的元素定义次数的幂。

参数

base | - | 含底数值的数值数组
exp | - | 含指数值的数值数组
vbase | - | 定义底数的值
vexp | - | 定义指数的值

返回值

含有指数结果的数值数组。

注解

用无限定函数 (pow) 进行计算。若该函数不可用，则因参数依赖查找使用 std::pow 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

示例

#include <cstddef>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <valarray>

void render(std::valarray<int> const& bases,
            std::valarray<int> const& exponents = {},
            std::valarray<int> const& results   = {})
{
    constexpr char const* sup[] {
        "\u2070", "\u00B9", "\u00B2", "\u00B3", "\u2074",
        "\u2075", "\u2076", "\u2077", "\u2078", "\u2079",
    };

    for (std::size_t n = 0; n != bases.size(); ++n) {
        std::cout << std::left << bases[n] << std::left;
        if (n < exponents.size())
            std::cout << sup[exponents[n] % 10] << " ";
        else
            std::cout << "  ";
    }
    if (results.size() != 0) {
        std::cout << "=";
        for (std::size_t n = 0; n != results.size(); ++n) {
            std::cout << " " << results[n];
        }
    }
    std::cout << '\n';
}

void render(int n) { std::cout << n << '\n'; }

int main()
{
    constexpr int base { 2 };
    constexpr int exponent { 5 };
    const std::valarray<int> bases { 1, 2, 3, 4, 5, 6, 7 };
    const std::valarray<int> exponents { 0, 1, 2, 3, 4, 5, 6 };

    std::cout << "(1) pow( const std::valarray<T>& base, const std::valarray<T>& exp ); \n";
    const std::valarray<int> powers1 = std::pow(bases, exponents);
    std::cout << "base  : "; render(bases);
    std::cout << "exp   : "; render(exponents);
    std::cout << "pow   : "; render(bases, exponents, powers1);

    std::cout << "\n(2) pow( const std::valarray<T>& base, const value_type& vexp ); \n";
    const std::valarray<int> powers2 = std::pow(bases, exponent);
    std::cout << "base  : "; render(bases);
    std::cout << "vexp  : "; render(exponent);
    std::cout << "pow   : "; render(bases, std::valarray<int>(exponent, bases.size()), powers2);

    std::cout << "\n(3) pow( const value_type& vbase, const std::valarray<T>& exp ); \n";
    const std::valarray<int> powers3 = std::pow(base, exponents);
    std::cout << "vbase : "; render(base);
    std::cout << "exp   : "; render(exponents);
    std::cout << "pow   : "; render(std::valarray<int>(base, bases.size()), exponents, powers3);
}

输出：

(1) pow( const std::valarray<T>& base, const std::valarray<T>& exp );
base  : 1  2  3  4  5  6  7
exp   : 0  1  2  3  4  5  6
pow   : 1⁰ 2¹ 3² 4³ 5⁴ 6⁵ 7⁶ = 1 2 9 64 625 7776 117649

(2) pow( const std::valarray<T>& base, const value_type& vexp );
base  : 1  2  3  4  5  6  7
vexp  : 5
pow   : 1⁵ 2⁵ 3⁵ 4⁵ 5⁵ 6⁵ 7⁵ = 1 32 243 1024 3125 7776 16807

(3) pow( const value_type& vbase, const std::valarray<T>& exp );
vbase : 2
exp   : 0  1  2  3  4  5  6
pow   : 2⁰ 2¹ 2² 2³ 2⁴ 2⁵ 2⁶ = 1 2 4 8 16 32 64

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3074 | C++98 | (2-3) 从标量和 valarray 两者推导 T ，禁止混合类型的调用 | 仅从 valarray 推导 T

参阅

sqrt(std::valarray) | 应用函数 std::sqrt 到 valarray 的每个元素 (函数模板)
powpowfpowl (C++11)(C++11) | 求某数的给定次幂（ \(\small{x^y}\)xy ） (函数)
pow(std::complex) | 复数幂，一或两个参数可为复数 (函数模板)


std::valarray<T>::resize

< cpp‎ | numeric‎ | valarray
void resize( std::size_t count, T value = T() );

重设 valarray 的大小以含有 count 个元素，并赋值 value 给每个元素。

此函数非法化指向数组中元素的所有指针和引用。

参数

count | - | 数组的新大小
value | - | 用以初始化新元素的值

返回值

（无）

示例

#include <valarray>
#include <iostream>
int main()
{
    std::valarray<int> v{1,2,3};
    v.resize(10);
    for(int n: v) std::cout << n << ' ';
    std::cout << '\n';
}

输出：

0 0 0 0 0 0 0 0 0 0

参阅

size
 返回valarray的大小
(公开成员函数)


std::valarray<T>::shift

< cpp‎ | numeric‎ | valarray
valarray<T> shift( int count ) const;

返回拥有同样大小的 valarray ，其元素位置被迁移了 count 个元素。每个元素的新位置是 i−count ，其中 i 是先前的位置。迁移进来的元素值是 T() 。

参数

count - 要迁移元素的位置数

返回值

产生的拥有移位后元素的 valarray 。

注意

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

示例

#include <iostream>
#include <valarray>

int main() {
    std::valarray<int> v{1, 2, 3, 4, 5, 6, 7, 8};

    for (auto const& val : v) {
        std::cout << val << " ";
    }
    std::cout << "\n";

    std::valarray<int> v2 = v.shift(2);

    for (auto const& val : v2) {
        std::cout << val << " ";
    }
    std::cout << "\n";
}

输出：

1 2 3 4 5 6 7 8
3 4 5 6 7 8 0 0

参阅

cshift
 循环移动 valarray 的元素
(公开成员函数)


std::sin(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
valarray<T> sin( const valarray<T>& va );

对于每个 va 中的元素，计算元素的正弦值。

参数

va - 要应用运算的值数组

返回值

包含 va 中的值的正弦的值数组。

注意

用无限定函数 (sin) 进行计算。若该函数不可用，则因参数依赖查找使用 std::sin 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

可能的实现

template<class T>
valarray<T> sin(const valarray<T>& va)
{
    valarray<T> other = va;
    for (T &i : other) {
        i = sin(i);
    }
    return other;
}

示例

#include <iostream>
#include <valarray>
#include <cmath>

const double pi = std::acos(-1);
int main()
{
    std::valarray<double> v1 = {0, 0.25, 0.5, 0.75, 1};
    std::valarray<double> v2 = std::sin(v1 * pi);

    for(double n : v2)
        std::cout << std::fixed << n << ' ';
    std::cout << '\n';
}

输出：

0.000000 0.707107 1.000000 0.707107 0.000000

参阅

cos(std::valarray) | 应用函数 std::cos 到 valarray 的每个元素 (函数模板)
tan(std::valarray) | 应用函数 std::tan 到 valarray 的每个元素 (函数模板)
asin(std::valarray) | 应用函数 std::asin 到 valarray 的每个元素 (函数模板)
sinsinfsinl (C++11)(C++11) | 计算正弦（ \({\small\sin{x} }\)sin(x) ） (函数)
sin(std::complex) | 计算复数的正弦（ \({\small\sin{z} }\)sin(z) ） (函数模板)


std::sinh(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
valarray<T> sinh( const valarray<T>& va );

对每个 va 中的元素，计算该元素的双曲正弦。

参数

va - 要应用运算的值数组

返回值

含 va 中每个值双曲正弦的值数组。

注解

用无限定函数 (sinh) 进行计算。若该函数不可用，则因参数依赖查找使用 std::sinh 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

可能的实现

template<class T>
valarray<T> sinh(const valarray<T>& va)
{
    valarray<T> other = va;
    for (T &i : other) {
        i = sinh(i);
    }
    return other;
}

示例

#include <cmath>
#include <iomanip>
#include <iostream>
#include <valarray>
#include <complex>

template<typename T>
void show(char const* title, const std::valarray<T>& va)
{
    std::cout << title << " : " << std::right;
    for (T x : va) {
        std::cout << std::fixed << x << " ";
    }
    std::cout << '\n';
}

template<typename T>
void sinh_for(std::valarray<T> const& z)
{
    // 双曲正弦为 sinh(z) = (eᶻ - e⁻ᶻ) / 2.

    const std::valarray<T> sinh_z { std::sinh(z) };
    const std::valarray<T> e_z { std::exp(z) };
    const std::valarray<T> e_neg_z { std::exp(-z) };
    const std::valarray<T> sinh_def { (e_z - e_neg_z) / 2.0f };

    show("n         ", z);
    show("sinh(n)   ", sinh_z);
    show("(eⁿ-e⁻ⁿ)/2", sinh_def);

    std::cout.put('\n');
}

int main()
{
    sinh_for(std::valarray<float>{ -.2f, -.1f, 0.f, .1f, .2f, INFINITY });
    sinh_for(std::valarray<std::complex<double>>{ {-.2,-.1}, {.2,.1} });
}

输出：

n          : -0.200000 -0.100000 0.000000 0.100000 0.200000 inf
sinh(n)    : -0.201336 -0.100167 0.000000 0.100167 0.201336 inf
(eⁿ-e⁻ⁿ)/2 : -0.201336 -0.100167 0.000000 0.100167 0.201336 inf

n          : (-0.200000,-0.100000) (0.200000,0.100000)
sinh(n)    : (-0.200330,-0.101837) (0.200330,0.101837)
(eⁿ-e⁻ⁿ)/2 : (-0.200330,-0.101837) (0.200330,0.101837)

参阅

cosh(std::valarray) | 在 valarray 的每个元素上调用 std::cosh 函数 (函数模板)
tanh(std::valarray) | 在 valarray 的每个元素上调用 std::tanh 函数 (函数模板)
sinhsinhfsinhl (C++11)(C++11) | 计算双曲正弦（ \({\small\sinh{x} }\)sinh(x) ） (函数)
sinh(std::complex) | 计算复数的双曲正弦（ \({\small\sinh{z} }\)sinh(z) ） (函数模板)


std::valarray<T>::size

< cpp‎ | numeric‎ | valarray
std::size_t size() const;

返回 valarray 中的元素数。

参数

（无）

返回值

valarray 中的元素数。

示例

#include <iostream>
#include <valarray>

int main()
{
    std::valarray<double> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::cout << "Average: " << a.sum()/a.size() << '\n';
}

输出：

Average: 5.5

参阅

resize
 更改 valarray 的大小
(公开成员函数)


std::slice

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
class slice;

std::slice 是选择器类，标识 std::valarray 类似于 BLAS 的子集。一个 std::slice 类型的对象保有三个值：起始下标，跨度，及子集中的值的总数。 std::slice 类型的对象可用作 valarray 的 operator[] 的下标。

成员函数

(构造函数) | 构造一个 slice (公开成员函数)
startsizestride | 返回 slice 的参数 (公开成员函数)

std::slice::slice

slice()
slice( std::size_t start, std::size_t size, std::size_t stride );
slice( const slice& other );

构造一个新切片。

1) 默认构造函数。等价于 slice(0, 0, 0) 。此构造函数的存在只为允许构造数组的切片。
2) 以参数 start 、 size 、 stride 构造新切片。此切片将引用 size 个元素，每个处于位置：
start + 0*stride
start + 1*stride
...
start + (size-1)*stride
3) 构造 other 的副本。

参数

start | - | 首元素的位置
size | - | 切片中的元素数
stride | - | 切片中前后元素的相对位置
other | - | 要复制的另一切片

std::slice::start, size, stride

std::size_t start() const; | (1)
std::size_t size() const; | (2)
std::size_t stride() const; | (3)

返回构造时传递给切片的参数——分别为起点、大小和跨度。

参数

（无）

返回值

切片的参数——分别为起点、大小和跨度。

复杂度

常数。

非成员函数

operator==(std::slice)
(C++20)
 检查二个切片是否相等
(函数)

operator==(std::slice)

friend bool operator==( const slice& lhs, const slice& rhs ); | (C++20 起)

检查 lhs 与 rhs 的参数——起点、大小和跨度是否分别相等。

此函数对通常无限定或有限定查找不可见，而只能在 std::slice 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

参数

lhs, rhs - 要比较的切片

返回值

lhs.start() == rhs.start() && lhs.size() == rhs.size() && lhs.stride() == rhs.stride()

示例

建立于 valarray 的带迹计算函数的极简化矩阵类。

#include <iostream>
#include <valarray>
class Matrix {
    std::valarray<int> data;
    int dim;
 public:
    Matrix(int r, int c) : data(r*c), dim(c) {}
    int& operator()(int r, int c) {return data[r*dim + c];}
    int trace() const {
        return data[std::slice(0, dim, dim+1)].sum();
    }
};
int main()
{
    Matrix m(3,3);
    int n = 0;
    for(int r=0; r<3; ++r)
       for(int c=0; c<3; ++c)
           m(r, c) = ++n;
    std::cout << "Trace of the matrix (1,2,3) (4,5,6) (7,8,9) is " << m.trace() << '\n';
}

输出：

Trace of the matrix (1,2,3) (4,5,6) (7,8,9) is 15

参阅

operator[] | 获取/设置 valarray 数组元素、切片或掩码 (公开成员函数)
gslice | valarray 的通用切片：起始下标、长度集、步幅集 (类)
slice_array | 到 valarray 应用 slice 后的子集的代理 (类模板)


std::slice_array

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T > class slice_array;

std::slice_array 是 std::slice 的下标运算符所用的帮助模板。它拥有到 std::slice 对象所指定的数组子集的引用语义。

成员类型

类型 | 定义
value_type | T

成员函数

(构造函数) | 构造一个 slice_array (公开成员函数)
(析构函数) | 销毁一个 slice_array (公开成员函数)
operator= | 赋值内容 (公开成员函数)
operator+=operator-=operator*=operator/=operator%=operator&=operator|=operator^=operator<<=operator>>= | 在切片所指代的数组上进行算术运算。 (公开成员函数)

示例

#include <iostream>
#include <valarray>

class Matrix {
    int dim;
    std::valarray<int> data;
public:
    explicit Matrix(int dim, int init = 0)
        : dim{dim}, data(init, dim*dim) {}
    void clear(int value = 0) { data = value; }
    void identity() { clear(); diagonal() = 1; }
    int& operator()(int x, int y) { return data[dim * y + x]; }

    std::slice_array<int> diagonal() {
        return data[std::slice(0, dim, dim+1)];
    }
    std::slice_array<int> secondary_diagonal() {
        return data[std::slice(dim-1, dim, dim-1)];
    }
    std::slice_array<int> row(std::size_t row) {
        return data[std::slice(dim*row, dim, 1)];
    }
    std::slice_array<int> column(std::size_t col) {
        return data[std::slice(col, dim, dim)];
    }
    void print(char term = '\n') const {
        for (unsigned i = 0; i != data.size(); ++i)
            std::cout << data[i] << (((i+1) % dim) ? ' ' : '\n');
        std::cout << term;
    }
};

int main()
{
    Matrix m{3};
    m.identity();
    m.print();

    m.clear(1);
    m.secondary_diagonal() = 3;
    m.print();

    m.clear();
    m.row(1) = std::valarray<int>{4, 5, 6};
    m.print();

    m.clear();
    m.column(1) = std::valarray<int>{7, 8, 9};
    m.print();
}

输出：

1 0 0
0 1 0
0 0 1

1 1 3
1 3 1
3 1 1

0 0 0
4 5 6
0 0 0

0 7 0
0 8 0
0 9 0

参阅

gslice_array
 valarray 应用 gslice 后的子集的代理
(类模板)


std::slice_array<T>::operator=

< cpp‎ | numeric‎ | valarray‎ | slice array

void operator=( const T& value ) const; | (1) |
void operator=( const std::valarray <T>& val_arr ) const; | (2) |
const slice_array& operator=( const slice_array& sl_arr) const; | (3) | (C++11 起)

将值赋值给所有被引用元素。

1) 将 value 赋值给所有元素。
2) 将 val_arr 的元素赋值给 *this 所引用的元素。
3) 将自 sl_arr 选择的元素赋值给 *this 所引用的元素。

参数

value | - | 赋值给所有被引用元素的值
val_arr | - | 用以赋值的 std::valarray
sl_arr | - | 用以赋值的 std::slice_array

返回值

1-2) （无）
3) *this

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <valarray>

void print(char const* remark, std::valarray<int> const& v = {})
{
    std::cout << remark;
    if (v.size() != 0) {
        std::cout << ":";
        for (int e : v) std::cout << ' ' << e;
    }
    std::cout << '\n';
}

int main()
{
    std::valarray<int> v1{1,2,3,4,5,6,7,8};
    std::slice_array<int> s1 = v1[std::slice(1, 4, 2)];
    print("v1", v1);
    print("s1", s1);

    print("\n(1) operator=( const T& )");
    print("s1 = 42");
    s1 = 42; // (1)
    print("s1", s1);
    print("v1", v1);

    print("\n(2) operator=( const std::valarray<T>& )");
    std::valarray<int> v2{10,11,12,13,14,15};
    print("v2", v2);
    print("s1 = v2");
    s1 = v2; // (2)
    print("s1", s1);
    print("v1", v1);

    print("\n(3) operator=( const slice_array& )");
    v1 = {1,2,3,4,5,6,7,8};
    std::slice_array<int> s2 = v1[std::slice(0, 4, 1)];
    std::slice_array<int> s3 = v2[std::slice(1, 4, 1)];
    print("v1", v1);
    print("v2", v2);
    print("s2", s2);
    print("s3", s3);
    print("s2 = s3");
    s2 = s3; // (3) 注： LHS 与 RHS 必须拥有相同大小
    print("s2", s2);
    print("v1", v1);
}

输出：

v1: 1 2 3 4 5 6 7 8
s1: 2 4 6 8

(1) operator=( const T& )
s1 = 42
s1: 42 42 42 42
v1: 1 42 3 42 5 42 7 42

(2) operator=( const std::valarray<T>& )
v2: 10 11 12 13 14 15
s1 = v2
s1: 10 11 12 13
v1: 1 10 3 11 5 12 7 13

(3) operator=( const slice_array& )
v1: 1 2 3 4 5 6 7 8
v2: 10 11 12 13 14 15
s2: 1 2 3 4
s3: 11 12 13 14
s2 = s3
s2: 11 12 13 14
v1: 11 12 13 14 5 6 7 8


std::slice_array<T>::operator+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=

< cpp‎ | numeric‎ | valarray‎ | slice array

void operator+=( const std::valarray <T>& other ) const;
void operator-=( const std::valarray <T>& other ) const;
void operator*=( const std::valarray <T>& other ) const;
void operator/=( const std::valarray <T>& other ) const;
void operator%=( const std::valarray <T>& other ) const;
void operator&=( const std::valarray <T>& other ) const;
void operator|=( const std::valarray <T>& other ) const;
void operator^=( const std::valarray <T>& other ) const;
void operator<<=( const std::valarray <T>& other ) const;
void operator>>=( const std::valarray <T>& other ) const;

应用给定的运算到所引用元素和 other 的元素。

参数

other - 作为获取值来源的参数数组

返回值

（无）

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例


std::slice_array<T>::slice_array

< cpp‎ | numeric‎ | valarray‎ | slice array

slice_array( const slice_array& other );
slice_array() = delete;

从另一 slice_array other 构造 slice_array 。

默认构造函数被隐式删除。

参数

other - 用来初始化的 slice_array


std::slice_array<T>::~slice_array

< cpp‎ | numeric‎ | valarray‎ | slice array

~slice_array();

销毁数组中的下标。不修改对象所引用的元素。


std::sqrt(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
valarray<T> sqrt( const valarray<T>& va );

对 va 中每个元素计算元素值的平方根。

参数

va - 要应用操作到的值数组

返回值

含有 va 中值的平方根的值数组。

注解

用无限定函数 (sqrt) 进行计算。若该函数不可用，则因参数依赖查找使用 std::sqrt 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

可能的实现

template<class T>
valarray<T> sqrt(const valarray<T>& va)
{
    valarray<T> other = va;
    for (T &i : other) {
        i = sqrt(i);
    }
    return other;
}

示例

寻找多个二次方程的实根。

#include <cstddef>
#include <valarray>
#include <iostream>

int main()
{
    std::valarray<double> a(1, 8);
    std::valarray<double> b{1, 2, 3, 4, 5, 6, 7, 8};
    std::valarray<double> c = -b;
    // LWG3074 前字面量亦必须拥有 T 类型（此情况下为 double ）
    std::valarray<double> d = std::sqrt(b * b - 4.0 * a * c);
    std::valarray<double> x1 = (-b - d) / (2.0 * a);
    std::valarray<double> x2 = (-b + d) / (2.0 * a);
    std::cout << "quadratic equation    root 1,  root 2" << "\n";
    for (std::size_t i = 0; i < a.size(); ++i) {
        std::cout << a[i] << "x\u00B2 + " << b[i] << "x + " << c[i] << " = 0   ";
        std::cout << std::fixed << x1[i] << ", " << x2[i] << std::defaultfloat << "\n";
    }
}

输出：

quadratic equation    root 1,  root 2
1x² + 1x + -1 = 0   -1.618034, 0.618034
1x² + 2x + -2 = 0   -2.732051, 0.732051
1x² + 3x + -3 = 0   -3.791288, 0.791288
1x² + 4x + -4 = 0   -4.828427, 0.828427
1x² + 5x + -5 = 0   -5.854102, 0.854102
1x² + 6x + -6 = 0   -6.872983, 0.872983
1x² + 7x + -7 = 0   -7.887482, 0.887482
1x² + 8x + -8 = 0   -8.898979, 0.898979

参阅

pow(std::valarray) | 应用函数 std::pow 到二个 valarray 或一个 valarray 与一个值 (函数模板)
sqrtsqrtfsqrtl (C++11)(C++11) | 计算平方根（ \(\small{\sqrt{x} }\)√x ） (函数)
sqrt(std::complex) | 右半平面范围中的复平方根 (函数模板)


std::valarray<T>::sum

< cpp‎ | numeric‎ | valarray
T sum() const;

计算元素的和。

仅若 operator+= 定义于类型 T 才能使用此函数。若 std::valarray 为空，则行为未定义。此函数处理元素的顺序未指定。

参数

（无）

返回值

元素的和。

示例

#include <iostream>
#include <valarray>

int main()
{
    std::valarray<int> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::cout << a.sum() << '\n';
}

输出：

55

参阅

apply | 对 valarray 的每个元素应用函数 (公开成员函数)
accumulate | 对一个范围内的元素求和 (函数模板)


std::valarray<T>::swap

< cpp‎ | numeric‎ | valarray
void swap( valarray& other ); | (C++11 前)
void swap( valarray& other ) noexcept; | (C++11 起)

与 other 交换内容。

参数

other - 要交换内容的另一 valarray

返回值

（无）


std::swap(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray> |
template< class T > void swap( std::valarray <T> &lhs, std::valarray <T> &rhs ) noexcept; | (C++11 起)

为 std::valarray 特化 std::swap 算法。交换 lhs 与 rhs 的内容。调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的 valarray

返回值

（无）

复杂度

常数。

参阅

swap
 与另一 valarray 交换
(公开成员函数)


std::tan(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
valarray<T> tan( const valarray<T>& va );

对 va 中每个元素计算元素值的正切。

参数

va - 要应用操作到的值数组

返回值

含有 va 中值的正切的值数组。

注意

用无限定函数 (tan) 进行计算。若该函数不可用，则因参数依赖查找使用 std::tan 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

可能的实现

template<class T>
valarray<T> tan(const valarray<T>& va)
{
    valarray<T> other = va;
    for (T &i : other) {
        i = tan(i);
    }
    return other;
}

示例

#include <cmath>
#include <iostream>
#include <valarray>

auto show = [](char const* title, const std::valarray<double>& va) {
    std::cout << title << " :";
    for(auto x : va)
        std::cout << "  " << std::fixed << x;
    std::cout << '\n';
};

int main()
{
    const std::valarray<double> x = {.0, .1, .2, .3};
    const std::valarray<double> y = std::tan(x);
    const std::valarray<double> z = std::atan(y);

    show("x          ", x);
    show("y = tan(x) ", y);
    show("z = atan(y)", z);
}

输出：

x           :  0.000000  0.100000  0.200000  0.300000
y = tan(x)  :  0.000000  0.100335  0.202710  0.309336
z = atan(y) :  0.000000  0.100000  0.200000  0.300000

参阅

sin(std::valarray) | 对 valarray 的每个元素应用std::sin函数 (函数模板)
cos(std::valarray) | 应用函数 std::cos 到 valarray 的每个元素 (函数模板)
atan(std::valarray) | 应用函数 std::atan 到 valarray 的每个元素 (函数模板)
tantanftanl (C++11)(C++11) | 计算正切（ \({\small\tan{x} }\)tan(x) ） (函数)
tan(std::complex) | 计算复数的正切（ \({\small\tan{z} }\)tan(z) ） (函数模板)


std::tanh(std::valarray)

< cpp‎ | numeric‎ | valarray
定义于头文件 <valarray>
template< class T >
valarray<T> tanh( const valarray<T>& va );

对 va 中每个元素计算元素值的双曲正切。

参数

va - 要应用操作到的值数组

返回值

含有 va 中值的双曲正切的值数组。

注解

用无限定函数 (tanh) 进行计算。若该函数不可用，则因参数依赖查找使用 std::tanh 。

函数能实现为拥有不同于 std::valarray 的返回类型。此情况下，替换类型拥有下列属性：

  • 提供 std::valarray 的所有 const 成员函数。
  • 能从替换类型构造 std::valarray 、 std::slice_array 、 std::gslice_array 、 std::mask_array 和 std::indirect_array 。
  • 所有接受一个 const std::valarray & 类型参数的函数，除了 begin() 和 end() (C++11 起)也应该接受替换类型。
  • 所有接受二个 const std::valarray & 类型参数的函数都应该接受 const std::valarray & 和替换类型的每种组合。
  • 返回类型添加不多于二层嵌套在最深层嵌套的参数类型上的模板。

可能的实现

template<class T>
valarray<T> tanh(const valarray<T>& va)
{
    valarray<T> other = va;
    for (T &i : other) {
        i = tanh(i);
    }
    return other;
}

示例

#include <cmath>
#include <iostream>
#include <valarray>

auto show = [](char const* title, const std::valarray<double>& va) {
    std::cout << title << " :";
    for(auto x : va)
        std::cout << "  " << std::fixed << x;
    std::cout << '\n';
};

int main()
{
    const std::valarray<double> x = {.0, .1, .2, .3};
    const std::valarray<double> sinh = std::sinh(x);
    const std::valarray<double> cosh = std::cosh(x);
    const std::valarray<double> tanh = std::tanh(x);
    const std::valarray<double> tanh_by_def = sinh / cosh;
    const std::valarray<double> tanh_2x = std::tanh(2.0 * x);
    const std::valarray<double> tanh_2x_by_def =
        (2.0 * tanh) / (1.0 + std::pow(tanh, 2.0));

    show("x              ", x);
    show("tanh(x)        ", tanh);
    show("tanh(x) (def)  ", tanh_by_def);
    show("tanh(2*x)      ", tanh_2x);
    show("tanh(2*x) (def)", tanh_2x_by_def);
}

输出：

x               :  0.000000  0.100000  0.200000  0.300000
tanh(x)         :  0.000000  0.099668  0.197375  0.291313
tanh(x) (def)   :  0.000000  0.099668  0.197375  0.291313
tanh(2*x)       :  0.000000  0.197375  0.379949  0.537050
tanh(2*x) (def) :  0.000000  0.197375  0.379949  0.537050

参阅

sinh(std::valarray) | 在 valarray 的每个元素上调用 std::sinh 函数 (函数模板)
cosh(std::valarray) | 在 valarray 的每个元素上调用 std::cosh 函数 (函数模板)
tanhtanhftanhl (C++11)(C++11) | 计算双曲正切（ \({\small\tanh{x} }\)tanh(x) ） (函数)
tanh(std::complex) | 计算复数的双曲正切（ \({\small\tanh{z} }\)tanh(z) ） (函数模板)


std::valarray<T>::valarray

< cpp‎ | numeric‎ | valarray
valarray(); | (1) |
explicit valarray( std::size_t count ); | (2) |
valarray( const T& val, std::size_t count ); | (3) |
valarray( const T* vals, std::size_t count ); | (4) |
valarray( const valarray& other ); | (5) |
valarray( valarray&& other ) noexcept; | (6) | (C++11 起)
valarray( const std::slice_array <T>& sa ); | (7) |
valarray( const std::gslice_array <T>& gsa ); | (8) |
valarray( const std::mask_array <T>& ma ); | (9) |
valarray( const std::indirect_array <T>& ia ); | (10) |
valarray( std::initializer_list <T> il ); | (11) | (C++11 起)

从各种源构造数值数组。

1) 默认构造函数。构造空数值数组。
2) 以 count 个值初始化的元素副本构造数值数组。
3) 以 count 个 val 副本构造数值数组。
4) 构造拥有从来自 vals 所指向的数组的 count 个值的副本的数值数组。若此数组含少于 count 个值，则行为未定义。
5) 复制构造函数。构造有 other 内容副本的数值数组。
6) 移动构造函数。用移动语义构造有 other 内容的数值数组。
7-10) 转换构造函数。转换对应数据结构为 valarray 。
11) 构造拥有 initializer_list il 内容的数值数组。

参数

count | - | 要构造的元素数
val | - | 用以初始化元素的值
vals | - | 指向用作初始化内容的数组的指针
other | - | 用作源初始化内容的另一数值数组
sa | - | 用以初始化元素的切片数组
gsa | - | 用以初始化元素的通用切片数组
ma | - | 用以初始化元素的掩码数组
ia | - | 用以初始化元素的间接数组
il | - | 用以初始化元素的 initializer_list

异常

1-5, 7-11) 可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例


std::valarray<T>::~valarray

< cpp‎ | numeric‎ | valarray
~valarray()

析构数值数组。调用每个元素的析构函数，并解分配使用的存储。

复杂度

与数值数组的大小成线性。


预处理器

< cpp

预处理器在编译前的翻译阶段 4 执行。预处理的结果是单个文件，接下来它会被传递给实际编译器。

指令

预处理指令控制预处理器的行为。每个指令占据一行并拥有下列格式：

  • # 字符
  • 预处理指令（define、undef、include、if、ifdef、ifndef、else、elif、elifdef、elifndef (C++23 起)、endif、line、error、pragma 之一）[1]
  • 实参（取决于指令）
  • 换行符

允许空指令（即在 # 后直接换行），而它没有效果。

module 与 import 指令同样是预处理指令。

 (C++20 起)

预处理指令不得来自宏展开。

#define EMPTY
EMPTY   #   include <file.h> // 不是预处理指令

能力

预处理器有能力翻译源文件：

  • 有条件编译源文件的某些部分（由 #if、#ifdef、#ifndef、#else、#elif、elifdef、elifndef (C++23 起) 和 #endif 指令控制）。
  • 替换文本宏，同时可能对标识符进行拼接或加引号（由 #define 和 #undef 指令与 # 和 ## 运算符控制）。
  • 包含其他文件（由 #include 指令控制并以 __has_include 检查 (C++17 起)）。
  • 引发错误（由 #error 指令控制）

能控制预处理器的下列方面：

  • 由实现定义的行为（由 #pragma 指令和 _Pragma 运算符 (C++11 起)控制）。
  • 对预处理器可用的文件名和行信息（由 #line 指令控制）

脚注

  1. ↑ 这些指令是标准定义的。标准不定义其他指令的行为：它们可以被忽略、拥有一些有用的含义或导致编译时错误。即使忽略，也会在预处理器完成工作时将它们从源码中移除。一种常用的非标准扩展是 #warning 指令，它在编译期间放出一条用户定义的消息。

参阅


条件包含

< cpp‎ | preprocessor

预处理器支持有条件地编译源文件的某些部分。这一行为由 #if、#else、#elif、#ifdef、#ifndef、#elifdef、#elifndef (C++23 起) 与 #endif 指令所控制。

语法

#if 表达式 |
#ifdef 标识符 |
#ifndef 标识符 |
#elif 表达式 |
#elifdef 标识符 | (C++23 起)
#elifndef 标识符 | (C++23 起)
#else |
#endif |

解释

条件预处理块由 #if、#ifdef 或 #ifndef 指令开始，然后可选地包含任意多个 #elif、#elifdef 或 #elifndef (C++23 起) 指令，接下来是最多一个可选的 #else 指令，并以 #endif 指令结束。嵌套的条件预处理块会被单独处理。

各个 #if、#ifdef、#ifndef、#elif、#elifdef、#elifndef (C++23 起) 和 #else 指令所控制的代码块在第一个不属于内部嵌套的条件预处理块的 #elif、#elifdef、#elifndef (C++23 起)、#else 或 #endif 指令处结束。

#if、#ifdef 和 #ifndef 指令测试其所指定的条件（见下文），如果条件求值为真，则编译其控制的代码块。此时后续的 #else、#elifdef、#elifndef (C++23 起) 和 #elif 指令将被忽略。否则，如果所指定的条件求值为假，则跳过其所控制的代码块，然后处理后续的 #else、#elifdef、#elifndef (C++23 起) 或 #elif 指令（如果存在）。若后续指令为 #else，则 #else 指令所控制的代码块将会无条件地进行编译。否则，#elif、#elifdef 或 #elifndef (C++23 起) 指令按照与 #if 指令相同的方式执行：即测试条件是否满足，并根据其结果决定编译或跳过其所控制的代码块，并在后一种情况下继续处理后续的 #elif、#elifdef、#elifndef (C++23 起) 和 #else 指令。条件预处理块以 #endif 指令结束。

条件的求值

#if, #elif

表达式 是常量表达式。

表达式可含有形如“defined 标识符”或“defined (标识符)”的一元运算符。当此 标识符 已经被定义为宏名 ，或者此 标识符 为 __has_include (C++17 起)时结果为 1，否则结果为 ​0​。

在进行所有宏展开和 defined 及 __has_include (C++17 起) 表达式的求值后，任何非布尔字面量的标识符都被替换成数字 ​0​（这包含词法上为关键字的标识符，但不包括如 and 之类的代用记号）。

当 表达式 求值为非零值时，包含其所控制的代码块，否则跳过该代码块。

预处理器语境中， __has_cpp_attribute 表达式检测给定属性记号是否受支持及其受支持版本。见属性测试。

 (C++20 起)

注： CWG 1955 前，“#if cond1 ... #elif cond2”和“#if cond1 ... #else”后面跟着“#if cond3”是不同的，因为当 cond1 为真时第二个 #if 将被跳过，且 cond3 并不需要是良构的，而 #elif 中的 cond2 则必须是合法的表达式。 CWG 1955 开始，引领跳过的代码块的 #elif 也被跳过。

组合指令

检查标识符是否被定义为宏名。

“#ifdef 标识符”与“#if defined 标识符”实质上等价。

“#ifndef 标识符”与“#if !defined 标识符”实质上等价。

“#elifdef 标识符”与“#elif defined 标识符”实质上等价。

“#elifndef 标识符”与“#elif !defined 标识符”实质上等价。

 (C++23 起)

示例

#define ABCD 2
#include <iostream>

int main()
{

#ifdef ABCD
    std::cout << "1: yes\n";
#else
    std::cout << "1: no\n";
#endif

#ifndef ABCD
    std::cout << "2: no1\n";
#elif ABCD == 2
    std::cout << "2: yes\n";
#else
    std::cout << "2: no2\n";
#endif

#if !defined(DCBA) && (ABCD < 2*4-3)
    std::cout << "3: yes\n";
#endif
}

输出：

1: yes
2: yes
3: yes

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1955 | C++14 | 要求失败的 #elif 中的表达式合法 | 跳过失败的 #elif

参阅


错误指令

< cpp‎ | preprocessor

显示给定的错误消息并使程序非良构。

语法

#error 错误消息

解释

遇到 #error 指令后，实现显示诊断消息 错误消息，并使程序非良构（编译停止）。

错误消息可由多个词组成，不必在引号中。

参阅


实现定义的行为控制

< cpp‎ | preprocessor

实现定义的行为受 #pragma 指令控制。

语法

#pragma 语用形参 | (1) |
_Pragma ( 字符串字面量 ) | (2) | (C++11 起)
1) 具有由实现定义的行为方式
2) 从 字符串字面量 移除 L 前缀（若存在），外层引号，及前导/尾随空白符，将每个 \" 替换为 "、将每个 \\ 替换为 \，然后将结果记号化（如翻译阶段 3 中一样），再如同将结果作为 (1) 中的输入来予以使用。

解释

pragma 指令控制编译器的特定于实现的行为，如禁用编译器警告或更改对齐要求。无法识别的语用会被忽略。

非标准语用

ISO C++ 语言标准并不要求编译器支持任何语用。不过，多种实现都支持几种非标准的语用：

#pragma STDC

ISO C 语言标准要求 C 编译器支持下列三种语用，一些 C++ 编译器供应商在它们的 C++ 前端中以不同的程度支持它们：

#pragma STDC FENV_ACCESS 实参 | (1)
#pragma STDC FP_CONTRACT 实参 | (2)
#pragma STDC CX_LIMITED_RANGE 实参 | (3)

其中 实参 是 ON、OFF 和 DEFAULT 之一。

1) 若设为 ON，则告知编译器，程序将访问或修改浮点环境，这意味着可能推翻标志测试和模式更改（例如，全局共用子表达式删除，代码移动，及常量折叠）的优化将被禁用。默认值由实现定义，通常是 OFF。
2) 允许浮点表达式的缩略（contracting）行为，即一种优化，表达式严格按书面求值时可被观察到的一些舍入错误和浮点异常将被忽略。例如，允许 (x*y) + z 使用单条融合乘加 CPU 指令实现。默认值由实现定义，通常是 ON。
3) 告知编译器，复数的乘法、除法和绝对值可以使用简化的数学公式 (x+iy)×(u+iv) = (xu-yv)+i(yu+xv) (x+iy)/(u+iv) = [(xu+yv)+i(yu-xv)]/(u2
+v2
)，和 |x+iy| = √x2
+y2
，而不考虑中间溢出的可能性。换言之，程序员保证传递给这些函数的值范围是受限的。默认值为 OFF。

如果上述三种语用的任一条并非出现于所有外部声明之外，或所有显式声明或复合语句中的所有语句之前，则程序的行为未定义。

注意：不支持这些 pragma 的编译器可能提供等价的编译时选项，例如 gcc 的 -fcx-limited-range 和 -ffp-contract。

#pragma once

#pragma once 是受到绝大多数现代编译器支持的非标准语用。当某个头文件中包含它时，指示编译器只对其分析一次，即使它在同一源文件中（直接或间接）被包含了多次也是如此。

阻止同一头文件的多次包含的标准方式是使用包含防护：

#ifndef LIBRARY_FILENAME_H
#define LIBRARY_FILENAME_H
// 头文件的内容
#endif /* LIBRARY_FILENAME_H */

从而在任何翻译单元中，该头文件除首次以外被包含时都被排除出编译。所有现代编译器都记录头文件使用了包含防护的事实，只要该防护仍有定义，再遇到该头文件时就不再分析它。（例子见 gcc ）

使用 #pragma once 时，同一个头文件可以变为

#pragma once
// 头文件的内容

不同于头文件防护，这条语用使得错误地在多个文件中使用相同的宏名变得不可能。另一方面，因为带 #pragma once 的文件是基于其文件系统层次的身份所排除的，所以若头文件在项目中有多个位置，则这不能防止包含它两次。

#pragma pack

此 pragma 族控制后继定义的类和联合体的最大对齐。

#pragma pack(实参) | (1)
#pragma pack() | (2)
#pragma pack(push) | (3)
#pragma pack(push, 实参) | (4)
#pragma pack(pop) | (5)

其中 arg 实参是小的 2 的幂，指定以字节计的新对齐。

1) 设置当前对齐为值 实参 。
2) 设置当前对齐为默认值（由命令行选项指定）。
3) 推入当前对齐的值到内部栈。
4) 推入当前对齐的值到内部栈然后设置当前对齐为值 实参 。
5) 从内部栈弹出顶条目然后设置（恢复）当前对齐为该值。

#pragma pack 可以指定类的对齐，然而它不能使类过对齐。

参阅 GCC 与 MSVC 的特定细节。

本节未完成
原因：解释此语用在数据成员的效果还有使用它们的优势与劣势。参考源：
  • Stack Overflow
本节未完成
原因：暂无示例

参阅

外部链接

  • Visual Studio 2019 的 C++ pragma
  • GCC 接受的 Pragma
  • IBM AIX XL C 16.1 的单独 pragma 描述及标准 pragma
  • Sun Studio 11 C++ 用户指南中的 Appendix B. Pragmas
  • Intel C++ compiler pragmas
  • HP aCC A.06.25 的发行注记（包括 pragma）


源文件包含

< cpp‎ | preprocessor

将其他源文件包含到当前源文件中紧随指令之后的一行。

语法

#include < h字符序列 > 换行 | (1) |
#include " q字符序列 " 换行 | (2) |
#include 记号序列 换行 | (3) |
__has_include ( " q字符序列 " ) __has_include ( < h字符序列 > ) | (4) | (C++17 起)
__has_include ( 字符串字面量 ) __has_include ( < h记号序列 > ) | (5) | (C++17 起)
1) 搜索由 h字符序列 唯一识别的头，并将该指令替换为这个头的全部内容。
2) 搜索由 q字符序列 识别的源文件，并将该指令替换为这个源文件的全部内容。可以退回至语法 (1) 并将 q字符序列 视为头标识符。
3) 如果 (1) 和 (2) 都不匹配，记号序列会经历宏替换。该指令在替换后会再次尝试匹配 (1) 和 (2)。
4) 检查一个头或源文件是否可以被包含。
5) 如果 (4) 不匹配，h记号序列会经历宏替换。T该指令在替换后会再次尝试匹配 (4)。
换行 | - | 换行符
h字符序列 | - | 一个或多个 h字符
h字符 | - | 源字符集 (C++23 前)翻译字符集 (C++23 起) 除了换行符和 > 以外的任何成员
q字符序列 | - | 一个或多个 q字符
q字符 | - | 源字符集 (C++23 前)翻译字符集 (C++23 起) 除了换行符和 " 以外的任何成员
记号序列 | - | 一个或多个预处理记号
字符串字面量 | - | 一个字符串字面量
h记号序列 | - | 一个或多个除了 > 以外的预处理记号

说明

1) 在一系列由实现定义的地点中搜索由 h字符序列 唯一识别的头，并将该指令替换为这个头的全部内容。由实现定义如何制指定这些地点和识别头。
2) 将该指令替换为由 q字符序列 识别的源文件的全部内容。命名的源文件通过由实现定义的方式进行搜索。如果不支持这种搜索或者搜索失败，该指令按语法 (1) 重新处理，将原指令中包含的序列（包括大于号，如果存在）作为语法 (1) 中所需的序列。
3) 该指令中 include 后面的预处理记号会按在正常文本中进行处理（即每个目前定义为宏名的标识符都会被替换为它的预处理记号替换列表）如果在所有替换都完成后生成的指令不匹配前面两种语法，那么行为未定义。将在一对预处理记号 < 和 > 之间或一对 " 字符之前的预处理记号序列合并为单个头名预处理记号的方法由实现定义。
4) 搜索由 h字符序列 或 q字符序列 识别的头或源文件，如同通过将该预处理记号序列作为语法 (3) 中的 记号序列 的方法进行搜索，但不会有后续的宏展开会执行。如果刚才的语法 (3) 指令不满足 #include 指令的语法要求，那么程序非良构。如果搜索成功，__has_include 表达式求值为 1，否则（搜索失败时）求值为 0。
5) 只有在不匹配 (4) 才会选择此形式，此时预处理记号会按在正常文本中进行处理。

如果由 头名（即 < h字符序列 > 或 " q字符序列 "）标识的头指明了一个可以导入的头，那么由实现决定要包含这个头的 #include 预处理指令是否要被替换为具有以下形式的导入指令：

import 头名 ; 换行

 (C++20 起)

__has_include 可以在 #if 和 #elif 中的表达式展开。它被 #ifdef， #ifndef ， #elifdef， #elifndef (C++23 起) 和 defined 视为已定义的宏，但不能在其他任何地方使用。

注解

语法 (1) 的意图是搜索由实现所掌控的文件。典型实现仅搜索标准包含目录。这些标准包含目录中隐含地包含标准 C++ 库和标准 C 库。用户通常能通过编译器选项来控制标准包含目录。

语法 (2) 的意图是搜索不被实现所掌控的文件。典型实现首先于当前文件所在的目录搜索，然后退回使用语法 (1)。

包含一个文件时，它将经过翻译阶段 1-4 的处理，这可能递归地包含嵌套 #include 指令的展开，直到一个由实现定义的嵌套限制。为避免（可能传递性地）重复包含相同文件，和由文件包含自身造成的无限递归，通常使用头文件防护：整个头文件被包装在下列结构中

#ifndef FOO_H_INCLUDED /* 任何唯一地映射到文件的名称 */
#define FOO_H_INCLUDED
// 文件内容在此
#endif

许多编译器也会实现有类似效果的非标准 pragma #pragma once：在已经包含相同文件（文件的身份以操作系统指定的方式确定）的时候禁止处理该文件。

结果是 1 的 __has_include 只表明存在有指定名称的头或源文件。它并不意味着包含该头或源文件时不会导致错误，或它会包含任何有意义的内容。例如在同时支持 C++14 和 C++17 模式（并在其 C++14 模式作为一项遵从标准的扩展而提供 __has_include）的 C++ 实现上，__has_include(<optional>) 在 C++14 模式中可以是 1，但实际上 #include <optional> 可能导致错误。

示例

#if __has_include(<optional>)
#  include <optional>
#  define has_optional 1
   template<class T> using optional_t = std::optional<T>;
#elif __has_include(<experimental/optional>)
#  include <experimental/optional>
#  define has_optional -1
   template<class T> using optional_t = std::experimental::optional<T>;
#else
#  define has_optional 0
#  include <utility>
template<class V> class optional_t {
    V v_{}; bool has_{false};
  public:
    optional_t() = default;
    optional_t(V&& v) : v_(v), has_{true} {}
    V value_or(V&& alt) const& { return has_ ? v_ : alt; }
    /*...*/
};
#endif

#include <iostream>

int main()
{
    if (has_optional > 0)
        std::cout << "<optional> 存在\n";
    else if (has_optional < 0)
        std::cout << "<experimental/optional> 存在\n";
    else
        std::cout << "<optional> 不存在\n";

    optional_t<int> op;
    std::cout << "op = " << op.value_or(-1) << '\n';
    op = 42;
    std::cout << "op = " << op.value_or(-1) << '\n';
}

输出：

<optional> 存在
op = -1
op = 42

参阅

C++ 标准库头文件列表


文件名和行信息

< cpp‎ | preprocessor

更改预处理器中当前的行号和文件名。

语法

#line 行号 | (1)
#line 行号 "文件名" | (2)

解释

1) 将当前的预处理器行号更改为 行号。宏 __LINE__ 在该点后的展开将产生 行号 加上自此遇到的实际代码行数。

2) 还将当前的预处理器文件名更改为 文件名。宏 __FILE__ 在该点后的展开将生成 文件名。

任何预处理器记号（宏常量或表达式）都允许作为 #line 的实参，只要它们展开成合法的十进制整数，可选地后随一个合法的字符串即可。

行号 必须是至少有一个十进制位的序列（否则程序非良构），并且始终按十进制解释（即使它以 0 开始也是如此）。

若 行号 为 0 或大于 32767 (C++11 前)2147483647 (C++11 起)，则行为未定义。

注解

一些自动代码生成工具通过以其他语言编写的文件产生 C++ 源文件时，会使用此指令。这种情况下，它们在所生成的 C++ 文件中插入 #line 指令，以指代原（人类编辑的）源文件的行号和文件名。

示例

#include <cassert>
#define FNAME "test.cc"
int main()
{
#line 777 FNAME
        assert(2+2 == 5);
}

输出：

test: test.cc:777: int main(): Assertion `2+2 == 5' failed.

参阅


文本替换宏

< cpp‎ | preprocessor

预处理器支持文本宏替换和仿函数文本宏替换。

语法

#define 标识符 替换列表(可选) | (1) |
#define 标识符( 形参 ) 替换列表(可选) | (2) |
#define 标识符( 形参, ... ) 替换列表(可选) | (3) | (C++11 起)
#define 标识符( ... ) 替换列表(可选) | (4) | (C++11 起)
#undef 标识符 | (5) |

解释

#define 指令

#define 指令将 标识符 定义为宏，即指示编译器以将其后出现的所有 标识符 都替换为 替换列表，而它也可以被进一步处理。如果该标识符已被定义为任何类型的宏，那么除非这些定义都相同，否则程序非良构。

仿对象宏

仿对象宏（object-like）以 替换列表 替换每次出现的被定义 标识符。#define 指令的版本 (1) 准确表现如此。

仿函数宏

仿函数宏（function-like）以 替换列表 替换每次出现的被定义 标识符，可选地接受一定量的实参，它们随即替换掉 替换列表 中出现的任何对应的 形参。

仿函数宏语法类似函数调用语法：每个宏名实例后随一个 ( 作为下个预处理记号，所引入的记号序列将被替换为 替换列表。该序列以匹配的 ) 记号终止，跳过中间的匹配左右括号对。

对于版本 (2)，实参数量必须与宏定义中的形参数量相同。对于版本 (3,4) ，实参数量必须多于 (C++20 前)不少于 (C++20 起)形参数量（不计 ...）。否则程序非良构。如果标识符未使用函数写法，即它自身之后没有括号，那么它完全不被替换。

#define 指令的版本 (2) 定义简单仿函数宏。

#define 指令的版本 (3) 定义有可变数量实参的仿函数宏。额外的实参（是谓可变实参）可用 __VA_ARGS__ 标识符访问，它会被与要被替换的标识符一起提供的实参替换。

#define 指令的版本 (4) 定义有可变数量实参的仿函数宏，但无常规实参。额外的实参（是谓可变实参）只能用 __VA_ARGS__ 标识符访问，它会被与要被替换的标识符一起提供的实参替换。

对于版本 (3,4)，替换列表 可以含有记号序列“__VA_OPT__ ( 内容 )”，如果 __VA_ARGS__ 非空，那么它会被 内容 替换，否则不展开成任何内容。

#define F(...) f(0 __VA_OPT__(,) __VA_ARGS__)
#define G(X, ...) f(0, X __VA_OPT__(,) __VA_ARGS__)
#define SDEF(sname, ...) S sname __VA_OPT__(= { __VA_ARGS__ })
F(a, b, c) // 替换为 f(0, a, b, c)
F()        // 替换为 f(0)
G(a, b, c) // 替换为 f(0, a, b, c)
G(a, )     // 替换为 f(0, a)
G(a)       // 替换为 f(0, a)
SDEF(foo);       // 替换为 S foo;
SDEF(bar, 1, 2); // 替换为 S bar = { 1, 2 };
 (C++20 起)

注意：如果仿函数宏的实参中包含不为匹配的左右括号对所保护的逗号（最常出现于模板实参列表中，如 assert ( std::is_same_v <int, int>); 或 BOOST_FOREACH( std::pair <int,int> p, m)），那么逗号被解释成宏实参分隔符，并造成由于实参数量不匹配所致的编译失败。

保留宏名

包含标准库头文件的翻译单元不可 #define 或 #undef 声明于任何标准库头文件中所声明的名字。

使用标准库任何部分的翻译单元不可 #define 或 #undef 词法上等同于下列内容的名称：

  • 关键字
  • 有特殊含义的标识符
  • 任何标准属性记号
 (C++11 起)

除了可定义 likely 与 unlikely 为仿函数宏。

 (C++20 起)

否则，行为未定义。

# 与 ## 运算符

仿函数宏中，如果替换列表 中一个标识符前有 # 运算符，那么该标识符在运行形参替换的基础上以引号包围，实际上创建一个字符串字面量。另外，预处理器为内嵌的字符串字面量（如果存在）外围的引号添加反斜杠以进行转义，并按需要双写字符串中的反斜杠。移除所有前导和尾随空白符，并将文本中间（除内嵌字符串字面量中间外）的任何空白符序列缩减成单个空格。此操作被称为“字符串化”，如果字符串化的结果不是合法的字符串字面量，那么行为未定义。

# 出现于 __VA_ARGS__ 之前时，展开后的 __VA_ARGS__ 整体被包在引号中：

#define showlist(...) puts(#__VA_ARGS__)
showlist();            // 展开成 puts("")
showlist(1, "x", int); // 展开成 puts("1, \"x\", int")
 (C++11 起)

如果 替换列表 中任何两个相继标识符之间有 ## 运算符，那么这两个标识符（首先未被宏展开）在运行形参替换的基础上将结果进行拼接。此操作被称为“拼接”或“记号粘贴”。只有一同组成合法记号的记号才可以粘贴：如组成更长标识符的标识符、组成数字的数字位，或组成 += 的运算符 + 和 =。不能通过粘贴 / 和 * 来创建注释，这是因为注释在考虑文本宏替换前就已经被移除了。如果结果以一个与通用字符名的语法匹配的序列起始，那么行为未定义。在翻译阶段 3中的通用字符名替换不算在内。 (C++23 起)如果连接的结果不是合法记号，那么行为未定义。

注意：一些编译器提供了一项扩展，允许 ## 出现于逗号后及 __VA_ARGS__ 前，此情况下 ## 在存在可变实参时不做任何事，但在不存在可变实参时移除逗号：这使得可以定义如 fprintf (stderr, format, ##__VA_ARGS__) 这样的宏。

#undef 指令

#undef 指令取消定义 标识符，即取消 #define 指令所作的 标识符 定义。如果标识符未关联到宏，那么忽略该指令。

预定义宏

下列宏名已预定义于每个翻译单元中。

__cplusplus
 代表所用的 C++ 标准版本，展开成值
  • 199711L(C++11 前)
  • 201103L(C++11)
  • 201402L(C++14)
  • 201703L(C++17)，或
  • 202002L(C++20)
    (宏常量)
__STDC_HOSTED__
(C++11)
 如果实现有宿主（在操作系统下运行）则展开成整数常量 1，如果实现自立（不在操作系统下运行）则展开成 ​0​
(宏常量)
__FILE__
 展开成当前文件名，作为字符串字面量，可用 #line 指令更改
(宏常量)
__LINE__
 展开成源文件行号，整数常量，可用 #line 指令更改
(宏常量)
__DATE__
 展开成翻译日期，形式为 "Mmm dd yyyy" 的字符串。如果月中日期数小于 10 则 "dd" 的首字符为空格。月份名如同以 std::asctime () 生成
(宏常量)
__TIME__
 展开成翻译时间，形式为 "hh:mm:ss" 的字符串字面量
(宏常量)
__STDCPP_DEFAULT_NEW_ALIGNMENT__
(C++17)
 展开成 std::size_t 字面量，其值为对不具对齐的 operator new 的调用所保证的对齐（更大的对齐将传递给具对齐重载，如 operator new ( std::size_t, std::align_val_t )）
(宏常量)

实现可能预定义下列其他的宏名。

__STDC__ | 如果存在则为实现定义值，典型地用于指示 C 遵从性 (宏常量)
__STDC_VERSION__ (C++11) | 如果存在则为实现定义值 (宏常量)
__STDC_ISO_10646__ (C++11) | 如果 wchar_t 使用 Unicode ，则展开成 yyyymmL 形式的整数常量，日期指示所支持的 Unicode 的最近版本 (宏常量)
__STDC_MB_MIGHT_NEQ_WC__ (C++11) | 如果对于基本字符集成员 'x' == L'x' 可能为假，则展开成 1，如在基于 EBCDIC 并且为 wchar_t 使用 Unicode 的系统上。 (宏常量)
__STDCPP_THREADS__ (C++11) | 如果程序能拥有多于一个执行线程则展开成 1 (宏常量)
__STDCPP_STRICT_POINTER_SAFETY__
(C++11)(C++23 中移除)
 如果实现支持严格 std::pointer_safety 则展开成 1
(宏常量)

这些宏的值（除了 __FILE__ 和 __LINE__）在整个翻译单元保持为常量。试图重定义或取消定义这些宏会导致未定义行为。

注意：在每个函数体的作用域内部都有一个名为 __func__ 的特殊的函数局域预定义变量，它被定义为一个持有具有实现定义格式的函数名的静态字符数组。它不是预处理器宏，但它与 __FILE__ 和 __LINE__ 一起使用，例如 assert。

 (C++11 起)

语言功能特性测试宏

标准定义一组对应于 C++11 或之后引入的 C++ 语言功能特性的预处理器宏。它们被用来以简单且可移植的方式检测所说的特性是否存在。

详见功能特性测试 。

 (C++20 起)

示例

#include <iostream>

// 制造函数工厂并使用它
#define FUNCTION(name, a) int fun_##name() { return a;}

FUNCTION(abcd, 12)
FUNCTION(fff, 2)
FUNCTION(qqq, 23)

#undef FUNCTION
#define FUNCTION 34
#define OUTPUT(a) std::cout << "output: " #a << '\n'

// 在后面的宏定义中使用之前的宏
#define WORD "Hello "
#define OUTER(...) WORD #__VA_ARGS__

int main()
{
    std::cout << "abcd: " << fun_abcd() << '\n';
    std::cout << "fff: " << fun_fff() << '\n';
    std::cout << "qqq: " << fun_qqq() << '\n';
    std::cout << FUNCTION << '\n';
    OUTPUT(million);               // 注意这里没有引号

    std::cout << OUTER(World) << '\n';
    std::cout << OUTER(WORD World) << '\n';
}

输出：

abcd: 12
fff: 2
qqq: 23
34
output: million
Hello World
Hello WORD World

参阅


范围库 (C++20)

< cpp

范围库提供处理元素范围的组件，包括各种视图适配器。

定义于头文件 <ranges>
namespace std {

namespace views = ranges::views;

}
 (C++20 起)

提供命名空间别名 std::views ，作为 std::ranges::views 的缩写。

定义于命名空间 std::ranges
范围访问
定义于头文件 <ranges>
定义于头文件 <iterator>
ranges::begin
(C++20)
 返回指向范围起始的迭代器
(定制点对象)
ranges::end
(C++20)
 返回指示范围结尾的哨位
(定制点对象)
ranges::cbegin
(C++20)
 返回指向只读范围起始的迭代器
(定制点对象)
ranges::cend
(C++20)
 返回指示只读范围结尾的哨位
(定制点对象)
ranges::rbegin
(C++20)
 返回指向范围的逆向迭代器
(定制点对象)
ranges::rend
(C++20)
 返回指向范围的逆向尾迭代器
(定制点对象)
ranges::crbegin
(C++20)
 返回指向只读范围的逆向迭代器
(定制点对象)
ranges::crend
(C++20)
 返回指向只读范围的逆向尾迭代器
(定制点对象)
ranges::size
(C++20)
 返回等于范围大小的整数
(定制点对象)
ranges::ssize
(C++20)
 返回等于范围大小的有符号整数
(定制点对象)
ranges::empty
(C++20)
 检查范围是否为空
(定制点对象)
ranges::data
(C++20)
 获得指向连续范围的起始的指针
(定制点对象)
ranges::cdata
(C++20)
 获得指向只读连续范围的起始的指针
(定制点对象)
范围原语
定义于头文件 <ranges>
ranges::iterator_tranges::sentinel_tranges::range_difference_tranges::range_size_tranges::range_value_tranges::range_reference_tranges::range_rvalue_reference_t
(C++20)
 获得范围的关联类型
(别名模板)
悬垂迭代器处理
定义于头文件 <ranges>
ranges::dangling
(C++20)
 占位类型，指示不应返回迭代器或子范围，因为它可能悬垂
(类)
ranges::borrowed_iterator_tranges::borrowed_subrange_t
(C++20)
 获得塑造 borrowed_range 的迭代器类型或子范围类型
(别名模板)
范围概念
定义于头文件 <ranges>
ranges::range
(C++20)
 指定类型为范围，即它同时提供 begin 迭代器和 end 哨位
(概念)
ranges::borrowed_range
(C++20)
 指定类型为 range 而且能安全返回从该类型表达式获得的迭代器而无悬垂之虞
(概念)
ranges::sized_range
(C++20)
 指定范围可在常数时间内知晓其大小
(概念)
ranges::view
(C++20)
 指定范围为视图，即它拥有常数时间的复制/移动/赋值
(概念)
ranges::input_range
(C++20)
 指定范围的迭代器类型满足 input_iterator
(概念)
ranges::output_range
(C++20)
 指定范围的迭代器类型满足 output_iterator
(概念)
ranges::forward_range
(C++20)
 指定范围的迭代器类型满足 forward_iterator
(概念)
ranges::bidirectional_range
(C++20)
 指定范围的迭代器类型满足 bidirectional_iterator
(概念)
ranges::random_access_range
(C++20)
 指定范围的迭代器类型满足 random_access_iterator
(概念)
ranges::contiguous_range
(C++20)
 指定范围的迭代器类型满足 contiguous_iterator
(概念)
ranges::common_range
(C++20)
 指定范围拥有相同的迭代器和哨位类型
(概念)
ranges::viewable_range
(C++20)
 指定针对 range 的要求，令其可安全转换为 view
(概念)
视图
定义于头文件 <ranges>
ranges::view_interface
(C++20)
 用于定义 view 的辅助类模板，使用奇异递归模板模式
(类模板)
ranges::subrange
(C++20)
 将迭代器/哨位对结合为一个 view
(类模板)

范围工厂

定义于头文件 <ranges>
定义于命名空间 std::ranges
ranges::empty_viewviews::empty (C++20) | 无元素的空 view (类模板) (变量模板)
ranges::single_viewviews::single (C++20) | 含有具有指定值的单个元素的 view (类模板) (定制点对象)
ranges::iota_viewviews::iota (C++20) | 由通过重复对某个初值自增所生成的序列组成的 view (类模板) (定制点对象)
ranges::basic_istream_viewviews::istream (C++20) | 由在关联的输入流上相继应用 operator>> 获得的元素组成的 view (类模板) (定制点对象)

范围适配器

定义于头文件 <ranges>
定义于命名空间 std::ranges
views::all_tviews::all (C++20) | 包含 range 的所有元素的 view (别名模板) (范围适配器对象)
ranges::ref_view (C++20) | 某个其他 range 的元素的 view (类模板)
ranges::owning_view (C++20) | 拥有某 range 的独占所有权的 view (类模板)
ranges::filter_viewviews::filter (C++20) | 由 range 中满足某个谓词的元素构成的 view (类模板) (范围适配器对象)
ranges::transform_viewviews::transform (C++20) | 对序列的每个元素应用某个变换函数的 view (类模板) (范围适配器对象)
ranges::take_viewviews::take (C++20) | 由另一 view 的前 N 个元素组成的 view (类模板) (范围适配器对象)
ranges::take_while_viewviews::take_while (C++20) | 由另一 view 的到首个谓词返回 false 为止的起始元素组成的 view (类模板) (范围适配器对象)
ranges::drop_viewviews::drop (C++20) | 由另一 view 跳过首 N 个元素组成的 view (类模板) (范围适配器对象)
ranges::drop_while_viewviews::drop_while (C++20) | 由另一 view 跳过元素的起始序列，直至首个谓词返回 false 的元素组成的 view (类模板) (范围适配器对象)
ranges::join_viewviews::join (C++20) | 由拉平 range 的 view 所获得的序列构成的 view (类模板) (范围适配器对象)
ranges::split_viewviews::split (C++20) | 用某个分隔符切割另一 view 所获得的子范围的 view (类模板) (范围适配器对象)
ranges::lazy_split_viewviews::lazy_split (C++20) | 用某个分隔符切割另一 view 所获得的子范围的 view (类模板) (范围适配器对象)
views::counted (C++20) | 从迭代器和计数创建子范围 (定制点对象)
ranges::common_viewviews::common (C++20) | 转换 view 为 common_range (类模板) (范围适配器对象)
ranges::reverse_viewviews::reverse (C++20) | 以逆序迭代另一双向视图上的元素的 view (类模板) (范围适配器对象)
ranges::elements_viewviews::elements (C++20) | 选取元组式值组成的 view 和数值 N ，产生每个 tuple 的第 N 个元素的 view (类模板) (范围适配器对象)
ranges::keys_viewviews::keys (C++20) | 选取 pair 式值组成的 view 并产生每个 pair 的第一元素的 view (类模板) (范围适配器对象)
ranges::values_viewviews::values (C++20) | 选取 pair 式值组成的 view 并产生每个 pair 的第二元素的 view (类模板) (范围适配器对象)
ranges::zip_viewviews::zip (C++23) | 到被适配视图的对应元素的引用元组组成的 view (类模板) (定制点对象)
ranges::zip_transform_viewviews::zip_transform (C++23) | 由应用变换函数到被适配视图的对应元素的结果的元组组成的 view (类模板) (定制点对象)
ranges::adjacent_viewviews::adjacent (C++23) | 由到被适配视图的相邻元素的引用的元组组成的 view (类模板) (范围适配器对象)
ranges::adjacent_transform_viewviews::adjacent_transform (C++23) | 由应用变换函数到被适配视图的相邻元素的结果的元组组成的 view (类模板) (范围适配器对象)

某些范围适配器用可复制包装包装其元素或函数对象。

范围适配器对象

范围适配器对象是接收 viewable_range 作为其首参数并返回 view 的定制点对象。一些范围适配器对象是一元的，即它们接收一个 viewable_range 作为其仅有的参数。其他范围适配器对象接收一个 viewable_range 和其他尾随参数。

若范围适配器接收多于一个参数，则它亦支持部分应用：令

  • a 为范围适配器对象，而
  • args... 为参数（通常适合作为尾随参数），

则表达式 a(args...) 拥有下列属性：

  • 它合法当且仅当对每个 args... 中的 e ，设 E 为 decltype((e)) ， std::is_constructible_v < std::decay_t <E>, E> 为 true ，
  • 当调用合法时，其结果对象对每个 e 中的 args... 存储以 std::forward <E>(e) 直接非列表初始化的 std::decay_t <E> 类型子对象，而且
  • 结果对象是范围适配器闭包对象（见后述）。

类似其他定制点对象，令

  • a 为任何范围适配器类型的 cv 无限定版本的对象，
  • args... 任何满足 a 的 operator() 的约束参数组，

对

  • a(args...)、
  • std::as_const (a)(args...)、
  • std::move(a)(args...) 及
  • std::move( std::as_const (a))(args...)

的调用全部等价。

每个这些表达式的结果对象是一个 view 对象或范围适配器闭包对象。

注：范围适配器类型的 volatile 限定或 const-volatile 限定版本不支持 operator() 。数组和函数在绑定时转换成指针。

范围适配器闭包对象

范围适配器闭包对象是类型同下列对象之一（忽略 cv 限定）的对象：

  • 一元范围适配器对象、
  • 范围适配器对象绑定尾随参数的结果，及
  • operator| 连接两个范围适配器闭包对象的结果。

范围适配器对象接收一个 viewable_range 作为其仅有的参数并返回 view 。它们可通过管道运算符调用：若 C 是范围适配器闭包对象且 R 为 viewable_range ，则下列两个表达式等价（均为良构或非良构）：

C(R)
R | C

此调用将绑定的参数（若存在）转发给关联的范围适配器对象。绑定的参数（若存在）被当作与 C 等同地为左值或右值以及具有 cv 限定。

两个范围适配器闭包对象能由 operator| 连接以产生另一个范围适配器闭包对象：若 C 与 D 为范围适配器闭包对象，则 C | D 亦为范围适配器闭包对象，若它合法。

C | D 的绑定参数确定如下：

  • 对两个操作数中的每个作为绑定参数的子对象，结果对象中有一个同类型子对象（舍弃 cv 限定），
  • 这种绑定的参数以含有它的操作数中的源子对象直接非列表初始化，其中源被当作与操作数等同地为左值或右值以及具有 cv 限定，而且
  • 结果合法当且仅当所有绑定参数的初始化为合法。

结果的 operator() 的效果与合法性确定如下：给定 viewable_range R ，这两个表达式等价（均为合法或非合法）：

R | C | D // (R | C) | D
R | (C | D)

注意：范围适配器闭包类型的 volatile 限定或 const-volatile 限定版本不支持 operator() 。

示例

#include <ranges>
#include <iostream>

int main()
{
    auto const ints = {0,1,2,3,4,5};
    auto even = [](int i) { return 0 == i % 2; };
    auto square = [](int i) { return i * i; };

    // 组合视图的“管道”语法：
    for (int i : ints | std::views::filter(even) | std::views::transform(square)) {
        std::cout << i << ' ';
    }

    std::cout << '\n';

    // 传统的“函数式”组合语法：
    for (int i : std::views::transform(std::views::filter(ints, even), square)) {
        std::cout << i << ' ';
    }
}

输出：

0 4 16

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3509 | C++20 | 不明确范围适配器对象如何绑定尾随参数 | 按值绑定它们


std::ranges::views::all, std::ranges::views::all_t

< cpp‎ | ranges
定义于头文件 <ranges>
inline constexpr /*unspecified*/ all = /*unspecified*/;
 (1) (C++20 起)
template <ranges::viewable_range R>
using all_t = decltype(views::all( std::declval <R>()));
 (2) (C++20 起)
1) 返回包含其 range 参数的所有元素的 view 的范围适配器对象（亦为范围适配器闭包对象）。

表达式 views::all(e) 表达式等价于：

  • 隐式转换 e 为 std::decay_t <decltype((e))> 纯右值，若结果类型实现 view 。
  • 否则为 std::ranges::ref_view{e} ，若该表达式为良构。
  • 否则为 std::ranges::owning_view{e} 。
2) 计算 viewable_range 类型的适合 view 类型。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

示例

#include <ranges>
#include <vector>
#include <iostream>
#include <type_traits>

int main()
{
    std::vector<int> v{0,1,2,3,4,5};
    for(int n : std::views::all(v) | std::views::take(2) ) {
        std::cout << n << ' ';
    }

    static_assert(std::is_same<
        decltype(std::views::single(42)),
        std::ranges::single_view<int>
        >{});

    static_assert(std::is_same<
        decltype(std::views::all(v)),
        std::ranges::ref_view<std::vector<int, std::allocator<int>>>
        >{});

    int a[]{1,2,3,4};
    static_assert(std::is_same<
        decltype(std::views::all(a)),
        std::ranges::ref_view<int [4]>
        >{});

    static_assert(std::is_same<
        decltype(std::ranges::subrange{std::begin(a)+1, std::end(a)-1}),
        std::ranges::subrange<int*, int*, std::ranges::subrange_kind(1)>
        >{});
}

输出：

0 1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2415R2 | C++20 | views::all 对非 view 右值 range 返回 subrange | 对其返回 owning_view

参阅

ranges::empty_viewviews::empty (C++20) | 无元素的空 view (类模板) (变量模板)
ranges::single_viewviews::single (C++20) | 含有具有指定值的单个元素的 view (类模板) (定制点对象)


std::ranges::views::istream, std::ranges::basic_istream_view, std::ranges::istream_view, std::ranges::wistream_view

< cpp‎ | ranges
定义于头文件 <ranges>
template< std::movable Val, class CharT, class Traits = std::char_traits <CharT> >

requires std::default_initializable<Val> &&
/*stream-extractable*/<Val,CharT,Traits>
class basic_istream_view

: public ranges::view_interface<basic_istream_view<Val,CharT,Traits>>
 (1) (C++20 起)
辅助模板
template< class Val >
using istream_view = ranges::basic_istream_view<Val, char>;
 (2) (C++20 起)
template< class Val >
using wistream_view = ranges::basic_istream_view<Val, wchar_t>;
 (3) (C++20 起)
定制点对象
template< class T >
inline constexpr /*unspecified*/ istream = /*unspecified*/;
 (4) (C++20 起)
辅助概念
template< class Val, class CharT, class Traits >

concept /*stream-extractable*/ =
requires( std::basic_istream <CharT,Traits>& is, Val& t) {
is >> t;

};
 (3) (C++20 起)
1) 通过重复调用 operator>> 生成元素序列的范围工厂。
2-3) 字符类型 char 与 wchar_t 的便利别名模板。
4) views::istream<T>(e) 对任何适合的子表达式 e 表达式等价于（拥有相同效果） ranges::basic_istream_view<T, typename U::char_type, typename U::traits_type>(e) ，其中 U 为 std::remove_reference_t <decltype(e)> 。若 U 不公开且无歧义地派生自 std::basic_istream <typename U::char_type, typename U::traits_type> 则程序非良构，这可能导致替换失败。
5) 仅用于阐释的概念 /*stream-extractable*/<Val,CharT,Traits> 在 Val 左值能从 std::basic_istream <CharT,Traits> 左值提取时得到满足。

basic_istream_view 的迭代器类型为仅移动：它不满足老式迭代器 (LegacyIterator) 要求，从而不能为 C++20 前的算法所用。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

成员函数

(构造函数)
(C++20)
 构造 basic_istream_view
(公开成员函数)
begin
(C++20)
 返回迭代器
(公开成员函数)
end
(C++20)
 返回 std::default_sentinel
(公开成员函数)
继承自 std::ranges::view_interface
(无) 尽管 basic_istream_view 派生自 std::ranges::view_interface ，它无法使用继承的成员函数。

std::ranges::basic_istream_view::basic_istream_view

constexpr explicit basic_istream_view( std::basic_istream <CharT, Traits>& stream ); | (C++20 起)

以 std::addressof (stream) 初始化存储的指针，并值初始化存储的 Val 值。

std::ranges::basic_istream_view::begin

constexpr auto begin(); | (C++20 起)

等价于 *stream_ >> value_; return /*iterator*/{*this}; ，其中 stream_ 为存储的指向流的指针，而 value_ 是存储的 Val 的值。

std::ranges::basic_istream_view::end

constexpr std::default_sentinel_t end() const noexcept; | (C++20 起)

等价于 return std::default_sentinel; 。

嵌套类

iterator
(C++20)
 basic_istream_view 的迭代器类型，名字仅用于阐释
(仅用于阐释的成员类)

示例

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <ranges>
#include <sstream>
#include <string>

int main()
{
    auto words = std::istringstream{"today is yesterday’s tomorrow"};
    for (const auto& s: std::ranges::istream_view<std::string>(words)) {
        std::cout << std::quoted(s, '/') << ' ';
    }
    std::cout << '\n';

    auto floats = std::istringstream{"1.1  2.2\t3.3\v4.4\f55\n66\r7.7  8.8"};
    std::ranges::copy(
        std::ranges::istream_view<float>(floats),
        std::ostream_iterator<float>{std::cout, ", "});
    std::cout << '\n';
}

输出：

/today/ /is/ /yesterday’s/ /tomorrow/
1.1, 2.2, 3.3, 4.4, 55, 66, 7.7, 8.8,

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | 因为 view 必须为 default_initializable 提供了默认构造函数 | 与该要求一同移除
LWG 3568 | C++20 | P2325R3 意外地使存储的值默认初始化 | 还原为值初始化
P2432R1 | C++20 | ranges::istream_view 曾为函数模板并且不遵循命名约定 | 使之为别名模板；添加了定制点对象

参阅

istream_iterator
 从 std::basic_istream 读取的输入迭代器
(类模板)


std::ranges::basic_istream_view::iterator

< cpp‎ | ranges‎ | basic istream view
struct /*iterator*/; | (C++20 起)

basic_istream_view::begin 的返回类型。此处展示的名字 /*iterator*/ 仅用于阐释。

/*iterator*/ 为 input_iterator ，但不满足老式输入迭代器 (LegacyInputIterator) ，从而无法用于 C++20 前的算法。

成员类型

成员类型 | 定义
iterator_concept(C++20) | std::input_iterator_tag
difference_type(C++20) | std::ptrdiff_t
value_type(C++20) | Val

成员函数

(构造函数) (C++20) | 构造迭代器 (公开成员函数)
operator= (C++20) | 复制赋值运算符被删除； /*iterator*/ 为仅移动 (公开成员函数)
operator++ (C++20) | 令迭代器前进 (公开成员函数)
operator* (C++20) | 返回当前元素 (公开成员函数)

std::ranges::basic_istream_view::iterator::iterator

constexpr explicit /*iterator*/( basic_istream_view& parent ); | (1) | (C++20 起)
/*iterator*/( const /*iterator*/& ) = delete; | (2) | (C++20 起)
/*iterator*/( /*iterator*/&& ) = default; | (3) | (C++20 起)
1) 从亲 basic_istream_view 构造迭代器。
2) 复制构造函数被删除。迭代器不可复制。
3) 移动构造函数被默认化。迭代器可移动。

std::ranges::basic_istream_view::iterator::operator=

/*iterator*/& operator=( const /*iterator*/& ) = delete; | (1) | (C++20 起)
/*iterator*/& operator=( /*iterator*/&& ) = default; | (2) | (C++20 起)
1) 复制赋值运算符被删除。迭代器不可复制。
2) 移动赋值运算符被默认化。迭代器可移动。

std::ranges::basic_istream_view::iterator::operator++

/*iterator*/& operator++(); | (1) | (C++20 起)
void operator++(int); | (2) | (C++20 起)

从底层流读取值并将它存储于亲 basic_istream_view 。

返回值

1) *this
2) （无）

std::ranges::basic_istream_view::iterator::operator*

Val& operator*() const; | (C++20 起)

返回到存储值的引用。

非成员函数

operator==
(C++20)
 与 std::default_sentinel_t 比较
(公开成员函数)

operator==(std::ranges::basic_istream_view::iterator, std::default_sentinel)

friend bool operator==( const /*iterator*/& x, std::default_sentinel_t ); | (C++20 起)

与 std::default_sentinel_t 比较。

若 *this 无亲 basic_istream_view 或若底层流发生错误则返回 true 。

此函数对通常无限定或有限定查找不可见，而只能在 std::ranges::basic_istream_view::iterator 为参数的关联类时由实参依赖查找找到。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | 因为 C++20 迭代器必须为 default_initializable 提供了默认构造函数 | 与该要求一同移除


std::ranges::begin

< cpp‎ | ranges
定义于头文件 <ranges>
定义于头文件 <iterator>
inline namespace /*unspecified*/ {

inline constexpr /*unspecified*/ begin = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T >

requires /* see below */

constexpr std::input_or_output_iterator auto begin(T&& t);

返回指向参数首元素的迭代器。

令 t 为 T 类型对象。若实参为左值或 ranges::enable_borrowed_range< std::remove_cv_t <T>> 为 true ，则调用 ranges::begin 表达式等价于：

  1. t + 0 ，若 T 为数组类型。
    若 std::remove_all_extents_t <T> 不完整，则调用 ranges::begin( std::forward <T>(t)) 非良构，不要求诊断。
  2. 否则为 std::forward <T>(t).begin() 转换到其衰变类型，若该带转换的表达式合法且其转换后的类型实现 std::input_or_output_iterator 。
  3. 否则为 begin( std::forward <T>(t)) 转换到其衰变类型，若 T 为类或枚举类型，而带转换的前述无限定调用合法，且其转换后的类型实现 std::input_or_output_iterator ，其中以下列候选进行重载决议：
    • void begin(auto&) = delete;
    • void begin(const auto&) = delete;
    • 实参依赖查找所找到的任何 begin 的声明。

所有其他情况下，调用 ranges::begin 非良构，这能在 ranges::begin(t) 出现于模板实例化的立即语境中时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::begin 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __begin_fn 表示其类型的 cv 无限定版本。

__begin_fn 的所有实例均相等。在相同参数上调用类型 __begin_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::begin 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::begin 的参数要求，则 __begin_fn 实现 std::invocable<__begin_fn, Args...>、 std::invocable<const __begin_fn, Args...>、 std::invocable<__begin_fn&, Args...> 及 std::invocable<const __begin_fn&, Args...> 。否则， __begin_fn 的函数调用运算符不参与重载决议。

注解

若实参为右值（即 T 为对象类型）且 ranges::enable_borrowed_range< std::remove_cv_t <T>> 为 false ，则调用 ranges::begin 非良构，这亦能导致替换失败。

所有情况下，返回类型实现 std::input_or_output_iterator 。

C++20 标准要求若底层 begin 函数调用返回纯右值，则从实质化的临时对象移动构造返回值。所有实现均直接返回纯右值。 C++20 后的提案 P0849R8 更正了该要求以匹配实现。

示例

#include <iostream>
#include <vector>
#include <ranges>

int main()
{
    std::vector<int> v = { 3, 1, 4 };
    auto vi = std::ranges::begin(v);
    std::cout << *vi << '\n';
    *vi = 42; // OK

    int a[] = { -5, 10, 15 };
    auto ai = std::ranges::begin(a);
    std::cout << *ai << '\n';
    *ai = 42; // OK
}

输出：

3
-5

参阅

ranges::cbegin (C++20) | 返回指向只读范围起始的迭代器 (定制点对象)
begincbegin (C++11)(C++14) | 返回指向容器或数组起始的迭代器 (函数模板)


std::ranges::bidirectional_range

< cpp‎ | ranges
定义于头文件 <ranges>
template<class T>

concept bidirectional_range =

ranges::forward_range<T> && std::bidirectional_iterator<ranges::iterator_t<T>>;

bidirectional_range 概念是 range 的细化，对于实现的类型， ranges::begin 返回 bidirectional_iterator 的实现。


std::ranges::borrowed_iterator_t, std::ranges::borrowed_subrange_t

< cpp‎ | ranges
定义于头文件 <ranges>
template< ranges::range R >
using borrowed_iterator_t = /* see below */;
 (1) (C++20 起)
template< ranges::range R >
using borrowed_subrange_t = /* see below */;
 (2) (C++20 起)
1) 若 R 实现 borrowed_range 则为 std::ranges::iterator_t<R> ，否则为 std::ranges::dangling 。
2) 若 R 实现 borrowed_range 则为 std::ranges::subrange<std::ranges::iterator_t<R>> ，否则为 std::ranges::dangling 。

某些受约束算法用此二模板别名避免返回潜在悬垂的迭代器或视图。

可能的实现

版本一
template< std::ranges::range R >
using borrowed_iterator_t = std::conditional_t<std::ranges::borrowed_range<R>,
    std::ranges::iterator_t<R>, std::ranges::dangling>;
版本二
template< std::ranges::range R >
using borrowed_subrange_t = std::conditional_t<std::ranges::borrowed_range<R>,
    std::ranges::subrange<std::ranges::iterator_t<R>>, std::ranges::dangling>;

参阅

ranges::dangling
(C++20)
 占位类型，指示不应返回迭代器或子范围，因为它可能悬垂
(类)


std::ranges::borrowed_range, std::ranges::enable_borrowed_range

< cpp‎ | ranges
定义于头文件 <ranges>
template<class R>

concept borrowed_range =
ranges::range<R> &&
( std::is_lvalue_reference_v <R> ||

ranges::enable_borrowed_range<std::remove_cvref_t<R>>);
 (1) (C++20 起)
template<class R>
inline constexpr bool enable_borrowed_range = false;
 (2) (C++20 起)
1) 概念 borrowed_range 定义范围的要求，使得函数能按值接收它，并返回从它获得的迭代器，而无悬垂之虞。
2) enable_borrowed_range 变量模板用于指示一个 range 是否为 borrowed_range 。主模板定义为 false 。

语义要求

若 T 为右值引用类型则令 U 为 std::remove_reference_t <T> ，否则为 T 。给定 U 类型变量 u ， T 实现 borrowed_range 仅若从 u 获得的迭代器的合法性不绑定到该变量的生存期。

特化

enable_borrowed_range 对下列标准模板的所有特化定义为 true ：

  • std::basic_string_view
  • std::span
  • std::ranges::subrange
  • std::ranges::ref_view
  • std::ranges::empty_view
  • std::ranges::iota_view

enable_borrowed_range 对下列标准范围适配器定义为 true 当且仅当 std::ranges::enable_borrowed_range<V> 为 true ，其中 V 是底层视图类型：

  • std::ranges::owning_view
  • std::ranges::take_view
  • std::ranges::drop_view
  • std::ranges::drop_while_view
  • std::ranges::common_view
  • std::ranges::reverse_view
  • std::ranges::elements_view
  • std::ranges::adjacent_view
 (C++23 起)

对 std::ranges::zip_view 的特化定义为 true 当且仅当 (std::ranges::enable_borrowed_range<Vs> && ...) 为 true ，其中 Vs... 为其所适配的所有视图类型。

 (C++23 起)

用户可对要实现 borrowed_range 的无 cv 限定的程序定义类型特化 enable_borrowed_range 为 true ，而对不实现的类型特化为 false 。这些特化应当可用于常量表达式并拥有 const bool 类型。

示例

演示 enable_borrowed_range 对程序定义类型的特化。这种特化防御潜在悬垂的结果。

#include <algorithm>
#include <array>
#include <cstddef>
#include <iostream>
#include <ranges>
#include <span>
#include <type_traits>

template <typename T, std::size_t N>
struct MyRange : std::array<T, N> { };

template <typename T, std::size_t N>
inline constexpr bool std::ranges::enable_borrowed_range<MyRange<T, N>> = false;

template <typename T, std::size_t N>
struct MyBorrowedRange : std::span<T, N> { };

template <typename T, std::size_t N>
inline constexpr bool std::ranges::enable_borrowed_range<MyBorrowedRange<T, N>> = true;

int main()
{
    static_assert(std::ranges::range<MyRange<int, 8>>);
    static_assert(std::ranges::borrowed_range<MyRange<int, 8>> == false);
    static_assert(std::ranges::range<MyBorrowedRange<int, 8>>);
    static_assert(std::ranges::borrowed_range<MyBorrowedRange<int, 8>> == true);

    auto getMyRangeByValue = [] { return MyRange<int, 4>{ {1, 2, 42, 3} }; };
    auto dangling_iter = std::ranges::max_element(getMyRangeByValue());
    static_assert(std::is_same_v<std::ranges::dangling, decltype(dangling_iter)>);
//  *dangling_iter; // 编译错误（即悬垂保护生效。）

    auto my = MyRange<int, 4>{ {1, 2, 42, 3} };
    auto valid_iter = std::ranges::max_element(my);
    std::cout << *valid_iter << ' '; // OK: 42

    auto getMyBorrowedRangeByValue = [] {
        static int sa[4] {1, 2, 42, 3};
        return MyBorrowedRange<int, std::size(sa)>{sa};
    };
    auto valid_iter2 = std::ranges::max_element(getMyBorrowedRangeByValue());
    std::cout << *valid_iter2 << '\n'; // OK ： 42
}

输出：

42 42


std::ranges::cbegin

< cpp‎ | ranges
定义于头文件 <ranges>
inline namespace /*unspecified*/ {

inline constexpr /*unspecified*/ cbegin = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T >

requires /* see below */

constexpr std::input_or_output_iterator auto cbegin(T&& t);

返回指向 const 限定的实参的首元素。

令 CT

  1. 若实参为左值（即 T 为左值引用类型）则为 const std::remove_reference_t <T>& ，
  2. 否则为 const T ，

则调用 ranges::cbegin 表达式等价于 ranges::begin(static_cast<CT&&>(t)) 。

两种情况下返回类型都实现 std::input_or_output_iterator 。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::cbegin 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __cbegin_fn 表示其类型的 cv 无限定版本。

__cbegin_fn 的所有实例均相等。在相同参数上调用类型 __cbegin_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::cbegin 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::cbegin 的参数要求，则 __cbegin_fn 实现 std::invocable<__cbegin_fn, Args...>、 std::invocable<const __cbegin_fn, Args...>、 std::invocable<__cbegin_fn&, Args...> 及 std::invocable<const __cbegin_fn&, Args...> 。否则， __cbegin_fn 的函数调用运算符不参与重载决议。

示例

#include <iostream>
#include <ranges>
#include <vector>

int main()
{
    std::vector<int> v = { 3, 1, 4 };
    auto vi = std::ranges::cbegin(v);
    std::cout << *vi << '\n';
    // *vi = 42; // 错误：只读变量不可赋值

    int a[] = { -5, 10, 15 };
    auto ai = std::ranges::cbegin(a);
    std::cout << *ai << '\n';
    // *ai = 42; // 错误：只读变量不可赋值
}

输出：

3
-5

参阅

ranges::begin (C++20) | 返回指向范围起始的迭代器 (定制点对象)
begincbegin (C++11)(C++14) | 返回指向容器或数组起始的迭代器 (函数模板)


std::ranges::cdata

< cpp‎ | ranges
定义于头文件 <ranges>
inline namespace /*unspecified*/ {

inline constexpr /*unspecified*/ cdata = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T >

requires /* see below */

constexpr std::remove_reference_t <ranges::range_reference_t</*CT*/>>* cdata(T&& t);

返回指向 const 限定实参所代表的连续范围的首元素的指针。

令 CT

  1. 若实参为左值（即 T 为左值引用类型）则为 const std::remove_reference_t <T>& ，
  2. 否则为 const T ，

则调用 ranges::cdata 表达式等价于 ranges::data(static_cast<CT&&>(t)) 。

若 ranges::cdata(t) 合法，则它返回指向对象的指针。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::cdata 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __cdata_fn 表示其类型的 cv 无限定版本。

__cdata_fn 的所有实例均相等。在相同参数上调用类型 __cdata_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::cdata 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::cdata 的参数要求，则 __cdata_fn 实现 std::invocable<__cdata_fn, Args...>、 std::invocable<const __cdata_fn, Args...>、 std::invocable<__cdata_fn&, Args...> 及 std::invocable<const __cdata_fn&, Args...> 。否则， __cdata_fn 的函数调用运算符不参与重载决议。

示例

#include <cstring>
#include <iostream>
#include <ranges>
#include <string>

int main()
{
    std::string s {"Hello world!\n"};

    char a[20]; // C 风格字符串的存储
    std::strcpy(a, std::ranges::cdata(s));
    // [data(s), data(s) + size(s)] 保证为 NTBS

    std::cout << a;
}

输出：

Hello world!

参阅

ranges::data (C++20) | 获得指向连续范围的起始的指针 (定制点对象)
data (C++17) | 获得指向底层数组的指针 (函数模板)


std::ranges::cend

< cpp‎ | ranges
定义于头文件 <ranges>
inline namespace /*unspecified*/ {

inline constexpr /*unspecified*/ cend = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T >

requires /* see below */

constexpr std::sentinel_for<ranges::iterator_t<T>> auto cend(T&& t);

返回指示 const 限定范围的末尾的哨位。

令 CT

  1. 若实参为左值（即 T 为左值引用类型）则为 const std::remove_reference_t <T>& ，
  2. 否则为 const T ，

则调用 ranges::cend 表达式等价于 ranges::end(static_cast<CT&&>(t)) 。

若 ranges::cend(e) 对表达式 e 合法，其中 decltype((e)) 为 T ，则 CT 实现 std::ranges::range ，且所有情况下 std::sentinel_for<S, I> 为 true ，其中 S 为 decltype(ranges::cend(e)) 而 I 为 decltype(ranges::cbegin(e)) 。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::cend 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __cend_fn 表示其类型的 cv 无限定版本。

__cend_fn 的所有实例均相等。在相同参数上调用类型 __cend_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::cend 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::cend 的参数要求，则 __cend_fn 实现 std::invocable<__cend_fn, Args...>、 std::invocable<const __cend_fn, Args...>、 std::invocable<__cend_fn&, Args...> 及 std::invocable<const __cend_fn&, Args...> 。否则， __cend_fn 的函数调用运算符不参与重载决议。

示例

#include <algorithm>
#include <iostream>
#include <ranges>
#include <vector>

int main()
{
    std::vector<int> v = { 3, 1, 4 };
    namespace ranges = std::ranges;
    if (ranges::find(v, 5) != ranges::cend(v)) {
        std::cout << "found a 5 in vector v!\n";
    }

    int a[] = { 5, 10, 15 };
    if (ranges::find(a, 5) != ranges::cend(a)) {
        std::cout << "found a 5 in array a!\n";
    }
}

输出：

found a 5 in array a!

参阅

ranges::end (C++20) | 返回指示范围结尾的哨位 (定制点对象)
endcend (C++11)(C++14) | 返回指向容器或数组结尾的迭代器 (函数模板)


std::ranges::common_range

< cpp‎ | ranges
定义于头文件 <ranges>
template<class T>

concept common_range =

ranges::range<T> && std::same_as<ranges::iterator_t<T>, ranges::sentinel_t<T>>;

common_range 概念是 range 对于 ranges::begin 与 ranges::end 返回相同类型的类型（如所有标准库容器）的细化。


std::ranges::views::common, std::ranges::common_view

< cpp‎ | ranges
定义于头文件 <ranges>
template< ranges::view V >

requires (!ranges::common_range<V> && std::copyable<ranges::iterator_t<V>>)

class common_view : public ranges::view_interface<common_view<V>>
 (1) (C++20 起)
namespace views {

inline constexpr /*unspecified*/ common = /*unspecified*/;

}
 (2) (C++20 起)
1) 将给定的拥有相异迭代器/哨位类型的 view 适配成亦为 common_range 的 view 。 common_view 始终拥有相同的迭代器/哨位类型。
2) 范围适配器对象。令 e 为子表达式。则表达式 views​::​common(e) 表达式等价于：
  • views​::​all(e) ，若它为良构表达式且 decltype((e)) 实现 common_range ；
  • 否则为 common_view{e} 。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

数据成员

common_view 的典型实现仅保有一个非静态数据成员： V 类型的底层视图。

成员函数

(构造函数)
(C++20)
 构造 common_view
(公开成员函数)
base
(C++20)
 返回底层（适配的）视图的副本
(公开成员函数)
begin
(C++20)
 返回指向起始的迭代器
(公开成员函数)
end
(C++20)
 返回指向末尾的迭代器
(公开成员函数)
size
(C++20)
 返回元素数，只要底层（适配的）范围满足 sized_range
(公开成员函数)
继承自 std::ranges::view_interface
empty
(C++20)
 返回视图是否为空。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
data
(C++20)
 返回派生视图的数据的地址。若视图的迭代器类型满足 contiguous_iterator 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator[]
(C++20)
 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

推导指引

辅助模板

template<class T>

inline constexpr bool enable_borrowed_range<std::ranges::common_view<T>> =

std::ranges::enable_borrowed_range<T>;
 (C++20 起)

std::ranges::enable_borrowed_range 的此特化使得 common_view 在底层类型实现 borrowed_range 时实现它。

注解

common_view 对于使用期待迭代器与哨位为相同类型的传统算法有用。

示例

#include <iostream>
#include <iterator>
#include <numeric>
#include <ranges>
#include <list>

int main() {
    auto v1 = { 1, 2, 3, 4, 5 };
    auto i1 = std::counted_iterator{v1.begin(), std::ssize(v1)};
    auto r1 = std::ranges::subrange{i1, std::default_sentinel};
//  auto e1 = std::accumulate(r1.begin(), r1.end(), 0); // 错误：要求“共同范围”
    auto c1 = std::ranges::common_view{r1};
    std::cout << "accumulate: " << std::accumulate(c1.begin(), c1.end(), 0) << '\n';

    // 从 ranges::view_interface 继承：
    std::cout << "c1.front(): " << c1.front() << '\n';
    std::cout << "c1.back(): " << c1.back() << '\n';
    std::cout << "c1.data(): " << c1.data() << '\n';
    std::cout << "c1[0]: " << c1[0] << '\n';

    auto v2 = std::list{ 1, 2, 3, 4, 5 };
    auto i2 = std::counted_iterator{v2.begin(), std::ssize(v2)};
    auto r2 = std::ranges::subrange{i2, std::default_sentinel};
//  auto e2 = std::accumulate(r2.begin(), r2.end(), 0); // 错误：要求“共同范围”
    auto c2 = std::ranges::common_view{r2};
    std::cout << "accumulate: " << std::accumulate(c2.begin(), c2.end(), 0) << '\n';

    // inherited from ranges::view_interface:
    std::cout << "c2.front(): " << c2.front() << '\n';
//  auto e3 = c2.back(); // 错误：要求“连续范围”
//  auto e4 = c2.data(); // 错误：要求“连续范围”
//  auto e5 = c2[0];     // 错误：要求“连续范围”
}

可能的输出：

accumulate: 15
c1.front(): 1
c1.back(): 5
c1.data(): 0x400ec0
c1[0]: 1
accumulate: 15
c2.front(): 1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3494 | C++20 | common_view 始终不是 borrowed_range | 若底层视图是 borrowed_range 则它是

参阅

ranges::common_range (C++20) | 指定范围拥有相同的迭代器和哨位类型 (概念)
common_iterator (C++20) | 适配一个迭代器类型及其哨位为一个公共迭代器类型 (类模板)


std::ranges::common_view<V>::base

< cpp‎ | ranges‎ | common view
constexpr V base() const& requires std::copy_constructible<V>; | (1) | (C++20 起)
constexpr V base() &&; | (2) | (C++20 起)

返回底层视图的副本。

1) 从底层视图复制构造结果。
2) 从底层视图移动构造结果。

参数

（无）

返回值

底层视图的副本。

示例

#include <iostream>
#include <ranges>
#include <string>

int main()
{
    std::string str { "C++20" };
    auto view = std::views::common(str);

    std::string copy_of_str = view.base();
    std::cout << "copy of str: [" << copy_of_str << "]\n";
    std::cout << "view.base(): [" << view.base() << "]\n";

    std::string move_str = std::move(view.base());
    std::cout << "moved str:   [" << move_str << "]\n";
    std::cout << "view.base(): [" << view.base() << "]\n"; // 未指定
}

可能的输出：

copy of str: [C++20]
view.base(): [C++20]
moved str:   [C++20]
view.base(): []


std::ranges::common_view<V>::begin

< cpp‎ | ranges‎ | common view
constexpr auto begin(); | (1) | (C++20 起)
constexpr auto begin() const requires range<const V>; | (2) | (C++20 起)
1) 返回指向 common_view 首元素的迭代器，即：
  • ranges::begin(base_) ，若 ranges::random_access_range<V> 与 ranges::sized_range<V> 均得到满足，
  • 否则为 std::common_iterator<ranges::iterator_t<V>, ranges::sentinel_t<V>>(ranges::begin(base_)) 。
此处 base_ （名称仅用于阐释目的）为底层视图。
2) 同 (1) ，但 V 为 const 限定。

参数

（无）

返回值

指向底层视图起始的迭代器。

示例

#include <iostream>
#include <numeric>
#include <ranges>
#include <string_view>

int main()
{
    constexpr auto common = std::views::iota(1)
                          | std::views::take(3)
                          | std::views::common
                          ;

    for (int i{}; int e : common) { std::cout << (i++ ? " + " : "") << e; }

    std::cout << " = " << std::accumulate(common.begin(), common.end(), 0) << '\n';
}

输出：

1 + 2 + 3 = 6

参阅

end (C++20) | 返回指向末尾的迭代器 (公开成员函数)
ranges::begin (C++20) | 返回指向范围起始的迭代器 (定制点对象)
ranges::end (C++20) | 返回指示范围结尾的哨位 (定制点对象)


std::ranges::common_view<V>::common_view

< cpp‎ | ranges‎ | common view
common_view() = default; | (1) | (C++20 起)
constexpr explicit common_view( V r ); | (2) | (C++20 起)

构造 common_view 。

1) 默认构造函数。值初始化底层视图。构造后 base() 返回 V() 的副本。
2) 以 std::move(r) 初始化底层视图。

参数

r - 要适配到公共范围中的底层视图

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3405 | C++20 | 冗余的转换构造函数可能导致约束递归 | 已移除


std::ranges::common_view 的推导指引

< cpp‎ | ranges‎ | common view
定义于头文件 <ranges> |
template<class R> common_view(R&&) -> common_view<views::all_t<R>>; | (C++20 起)

为 std::ranges::common_view 提供推导指引以允许从 range 推导。

若 R 为 view ，则推导出的类型为 common_view<R> ；否则推导出的类型通常为 common_view<ranges::ref_view<R>> 。

示例

本节未完成
原因：暂无示例


std::ranges::common_view<V>::end

< cpp‎ | ranges‎ | common view
constexpr auto end(); | (1) | (C++20 起)
constexpr auto end() const requires ranges::range<const V>; | (2) | (C++20 起)
1) 返回表示 common_view 末尾的迭代器，即：
  • ranges::begin(base_) + ranges::size(base_)，若 ranges::random_access_range<V> 与 ranges::sized_range<V> 均得到满足，
  • 否则为 std::common_iterator<ranges::iterator_t<V>, ranges::sentinel_t<V>>(ranges::end(base_)) 。
此处 base_ （名称仅用于阐释目的）为底层视图。
2) 同 (1) ，但 V 为 const 限定。

参数

（无）

返回值

表示底层视图末尾的迭代器。

示例

#include <iostream>
#include <numeric>
#include <ranges>

int main()
{
    constexpr int n{4};

    constexpr auto cv1 = std::views::iota(1)
                       | std::views::take(n)
                       | std::views::common
                       ;
    constexpr auto cv2 = std::views::iota(2)
                       | std::views::take(n)
                       ;
    const int product = std::inner_product(cv1.begin(), cv1.end(),
                                           cv2.begin(),
                                           0);
    std::cout << product << '\n';
}

输出：

40

参阅

begin (C++20) | 返回指向起始的迭代器 (公开成员函数)
ranges::begin (C++20) | 返回指向范围起始的迭代器 (定制点对象)
ranges::end (C++20) | 返回指示范围结尾的哨位 (定制点对象)


std::ranges::common_view<V>::size

< cpp‎ | ranges‎ | common view
constexpr auto size() requires ranges::sized_range<V>; | (1) | (C++20 起)
constexpr auto size() const requires ranges::sized_range<const V>; | (2) | (C++20 起)

返回元素数。

等价于 { return ranges::size(base_); } ，其中 base_ 为底层视图。

参数

（无）

返回值

元素数。

示例

#include <ranges>
#include <string_view>

int main()
{
    constexpr static auto v1 = {1, 2, 3, 4, 5};
    constexpr auto common1 { v1 | std::views::common };
    static_assert(common1.size() == 5);

    constexpr auto take3 { v1 | std::views::reverse | std::views::take(3) };
    constexpr auto common2 { take3 | std::views::common };
    static_assert(common2.size() == 3);

    using namespace std::literals;
    constexpr static auto v2 = { "∧"sv, "∨"sv, "∃"sv, "∀"sv };
    static_assert(std::ranges::views::common(v2).size() == 4);
}

参阅

ranges::size (C++20) | 返回等于范围大小的整数 (定制点对象)
ranges::ssize (C++20) | 返回等于范围大小的有符号整数 (定制点对象)


std::ranges::contiguous_range

< cpp‎ | ranges
定义于头文件 <ranges>
template<class T>

concept contiguous_range =
ranges::random_access_range<T> &&
std::contiguous_iterator<ranges::iterator_t<T>> &&
requires(T& t) {
{ ranges::data(t) } ->
std::same_as< std::add_pointer_t <ranges::range_reference_t<T>>>;

};

contiguous_range 概念是 range 的细化，对于实现的类型， ranges::begin 返回 contiguous_iterator 的实现，且定制点 ranges::data 可用。

语义要求

T 实现 contiguous_range ，仅若给定使得 decltype((e)) 为 T& 的表达式 e ， std::to_address(ranges::begin(t)) == ranges::data(t) 。


可复制包装 (C++20)

< cpp‎ | ranges
template<class T>

requires std::copy_constructible<T> && std::is_object_v <T>

class /*copyable-box*/;
 (C++20 起)

ranges::single_view 与存储一个可调用对象的范围适配器通过仅用于阐释的类模板 copyable-box 说明。名称 copyable-box 仅用于阐释目的。

/*copyable-box*/<T> 行为准确同 std::optional <T> ，除了默认构造函数、复制赋值运算符与移动赋值运算符（条件性地）异于 std::optional 的，这使得它始终满足 copyable 。

若 T 已为 copyable ，或 std::is_nothrow_move_constructible_v <T> 与 std::is_nothrow_copy_constructible_v <T> 均为 true ，则 /*copyable-box*/<T> 可以只存储一个 T 对象，因为它始终含值。

模板形参

T - 被含有值的类型，必须为实现 copy_constructible 的对象类型

成员函数

copyable-box::copyable-box

constexpr /*copyable-box*/() noexcept( std::is_nothrow_default_constructible_v <T>)

requires std::default_initializable<T>

: /*copyable-box*/( std::in_place ) { }
 (C++20 起)

当且仅当 T 实现 default_initializable 才提供默认构造函数。

默认构造的 /*copyable-box*/<T> 含有值初始化的 T 对象。

copyable-box::operator=

constexpr /*copyable-box*/& operator=(const /*copyable-box*/& other);
noexcept(/* see below */);
 (1) (C++20 起)
constexpr /*copyable-box*/& operator=(/*copyable-box*/&& other)
noexcept( std::is_nothrow_move_constructible_v <T>);
 (2) (C++20 起)
1) 若 std::copyable<T> 未得到实现，则复制赋值运算符等价地定义为：

constexpr /*copyable-box*/& operator=(const /*copyable-box*/& other)
noexcept( std::is_nothrow_copy_constructible_v <T>)
{
if (this != std::addressof (other)) {
if (other) emplace(*other);
else reset();
}
return *this;
}

否则，它等同于 std::optional 的复制赋值运算符。
2) 若 std::movable<T> 未得到实现，则移动赋值运算符等价地定义为：

constexpr /*copyable-box*/& operator=(/*copyable-box*/&& other)
noexcept( std::is_nothrow_move_constructible_v <T>)
{
if (this != std::addressof (other)) {
if (other) emplace(std::move(*other));
else reset();
}
return *this;
}

否则，它等同于 std::optional 的移动赋值运算符。

等同于 std::optional 的成员

成员函数

(构造函数)
 构造optional对象
(std::optional<T> 的公开成员函数)
(析构函数)
 销毁容纳的值，若存在
(std::optional<T> 的公开成员函数)
operator=
 对内容赋值
(std::optional<T> 的公开成员函数)
观察器
operator->operator*
 访问所含值
(std::optional<T> 的公开成员函数)
operator boolhas_value
 检查对象是否含值
(std::optional<T> 的公开成员函数)
修改器
reset
 销毁任何所含值
(std::optional<T> 的公开成员函数)
emplace
 原位构造所含值
(std::optional<T> 的公开成员函数)

注解

copyable-box 不含值，若

  • T 不实现 movable 或 copyable ，而分别在移动赋值或复制赋值时抛异常，或者
  • 从另一无值的包装初始化/赋值它。

在 P2325R3 前，该包装在标准中被称为 semiregular-box ，并且始终满足 semiregular ，因为始终提供默认构造函数（可能构造无值的包装）。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | 若 T 非 default_initializable 则默认构造函数构造不含值的包装 | 包装亦非 default_initializable
LWG 3572 | C++20 | 条件性有别的赋值运算符不是 constexpr | 使之为 constexpr

参阅

ranges::single_viewviews::single (C++20) | 含有具有指定值的单个元素的 view (类模板) (定制点对象)
ranges::filter_viewviews::filter (C++20) | 由 range 中满足某个谓词的元素构成的 view (类模板) (范围适配器对象)
ranges::transform_viewviews::transform (C++20) | 对序列的每个元素应用某个变换函数的 view (类模板) (范围适配器对象)
ranges::take_while_viewviews::take_while (C++20) | 由另一 view 的到首个谓词返回 false 为止的起始元素组成的 view (类模板) (范围适配器对象)
ranges::drop_while_viewviews::drop_while (C++20) | 由另一 view 跳过元素的起始序列，直至首个谓词返回 false 的元素组成的 view (类模板) (范围适配器对象)
ranges::zip_transform_viewviews::zip_transform (C++23) | 由应用变换函数到被适配视图的对应元素的结果的元组组成的 view (类模板) (定制点对象)
ranges::adjacent_transform_viewviews::adjacent_transform (C++23) | 由应用变换函数到被适配视图的相邻元素的结果的元组组成的 view (类模板) (范围适配器对象)


std::ranges::crbegin

< cpp‎ | ranges
定义于头文件 <ranges>
inline namespace /*unspecified*/ {

inline constexpr /*unspecified*/ crbegin = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T >

requires /* see below */

constexpr std::input_or_output_iterator auto crbegin(T&& t);

返回指向被当作逆向序列的 const 限定实参的首元素的迭代器。

令 CT

  1. 若实参为左值（即 T 为左值引用类型）则为 const std::remove_reference_t <T>& ，
  2. 否则为 const T ，

则调用 ranges::crbegin 表达式等价于 ranges::rbegin(static_cast<CT&&>(t)) 。

两种情况下返回类型都实现 std::input_or_output_iterator 。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::crbegin 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __crbegin_fn 表示其类型的 cv 无限定版本。

__crbegin_fn 的所有实例均相等。在相同参数上调用类型 __crbegin_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::crbegin 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::crbegin 的参数要求，则 __crbegin_fn 实现 std::invocable<__crbegin_fn, Args...>、 std::invocable<const __crbegin_fn, Args...>、 std::invocable<__crbegin_fn&, Args...> 及 std::invocable<const __crbegin_fn&, Args...> 。否则， __crbegin_fn 的函数调用运算符不参与重载决议。

示例

#include <iostream>
#include <vector>
#include <iterator>

int main()
{
    std::vector<int> v = { 3, 1, 4 };
    auto vi = std::ranges::crbegin(v);
    std::cout << *vi << '\n';

    int a[] = { -5, 10, 15 };
    auto ai = std::ranges::crbegin(a);
    std::cout << *ai << '\n';
}

输出：

4
15

参阅

ranges::rbegin (C++20) | 返回指向范围的逆向迭代器 (定制点对象)
rbegincrbegin (C++14) | 返回指向一个容器或数组的逆向迭代器 (函数模板)


std::ranges::crend

< cpp‎ | ranges
定义于头文件 <ranges>
inline namespace /*unspecified*/ {

inline constexpr /*unspecified*/ crend = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T >

requires /* see below */

constexpr std::sentinel_for<ranges::iterator_t<T>> auto crend(T&& t);

返回指示被当作逆向序列的 const 限定范围结尾的哨位。

令 CT

  1. 若实参为左值（即 T 为左值引用类型）则为 const std::remove_reference_t <T>& ，
  2. 否则为 const T ，

则调用 ranges::crbegin 表达式等价于 ranges::rend(static_cast<CT&&>(t)) 。

若 ranges::crend(e) 对于表达式 e 合法，则 std::sentinel_for<S, I> 在所有情况下为 true ，其中 S 为 decltype(ranges::crend(e)) 而 I 为 decltype(ranges::crbegin(e)) 。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::crend 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __crend_fn 表示其类型的 cv 无限定版本。

__crend_fn 的所有实例均相等。在相同参数上调用类型 __crend_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::crend 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::crend 的参数要求，则 __crend_fn 实现 std::invocable<__crend_fn, Args...>、 std::invocable<const __crend_fn, Args...>、 std::invocable<__crend_fn&, Args...> 及 std::invocable<const __crend_fn&, Args...> 。否则， __crend_fn 的函数调用运算符不参与重载决议。

示例

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

int main()
{
    int a[] = {4, 6, -3, 9, 10};
    std::cout << "Array backwards: ";
    namespace ranges = std::ranges;
    ranges::copy(ranges::rbegin(a), ranges::rend(a),
                 std::ostream_iterator<int>(std::cout, " "));

    std::cout << "\nVector backwards: ";
    std::vector<int> v = {4, 6, -3, 9, 10};
    ranges::copy(ranges::rbegin(v), ranges::rend(v),
                 std::ostream_iterator<int>(std::cout, " "));
}

输出：

Array backwards: 10 9 -3 6 4
Vector backwards: 10 9 -3 6 4

参阅

ranges::rend (C++20) | 返回指向范围的逆向尾迭代器 (定制点对象)
rendcrend (C++14) | 返回容器或数组的逆向尾迭代器 (函数模板)


std::ranges::dangling

< cpp‎ | ranges
定义于头文件 <ranges> |
struct dangling; | (C++20 起)

dangling 是占位类型兼空类类型，与模板别名 ranges::borrowed_iterator_t 及 ranges::borrowed_subrange_t 一同使用。

某些通常返回 range 的迭代器或子范围的有制约算法，在接收不实现 borrowed_range 的特定的右值 range 参数时，将取而代之地返回 dangling 以避免潜在返回悬垂的结果。

成员函数

std::ranges::dangling::dangling

constexpr dangling() noexcept = default; | (1)
template<class... Args> constexpr dangling(Args&&...) noexcept { } | (2)
1) dangling 可平凡默认构造。
2) dangling 能从任意数量及任意非 void 类型的参数构造。构造自身无任何副作用。

换言之，在良构的非聚合初始化中以 dangling 替换类型（例如迭代器类型）后，所得的初始化亦为良构。

示例

本节未完成
原因：暂无示例

参阅

ranges::borrowed_iterator_tranges::borrowed_subrange_t
(C++20)
 获得塑造 borrowed_range 的迭代器类型或子范围类型
(别名模板)


std::ranges::data

< cpp‎ | ranges
定义于头文件 <ranges>
定义于头文件 <iterator>
inline namespace /*unspecified*/ {

inline constexpr /*unspecified*/ data = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T >

requires /* see below */

constexpr std::remove_reference_t <ranges::range_reference_t<T>>* data(T&& t);

返回指向连续范围首元素的指针。

令 t 为 T 类型对象。若实参为左值或 ranges::enable_borrowed_range< std::remove_cv_t <T>> 为 true ，则调用 ranges::data 表达式等价于：

  1. std::forward <T>(t).data() 转换到其衰变类型，若转换后的表达式合法且其返回类型为指向对象的指针类型。
  2. 否则为 std::to_address(ranges::begin( std::forward <T>(t))) ，若 ranges::begin( std::forward <T>(t)) 合法且返回的类型实现 std::contiguous_iterator 。
    若 std::remove_all_extents_t < std::remove_reference_t <T>> 不完整，则 ranges::data( std::forward <T>(t)) 非良构，不要求诊断。

所有其他情况下，调用 ranges::data 非良构，这能在 ranges::data(t) 出现于模板实例化的立即语境时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::data 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __data_fn 表示其类型的 cv 无限定版本。

__data_fn 的所有实例均相等。在相同参数上调用类型 __data_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::data 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::data 的参数要求，则 __data_fn 实现 std::invocable<__data_fn, Args...>、 std::invocable<const __data_fn, Args...>、 std::invocable<__data_fn&, Args...> 及 std::invocable<const __data_fn&, Args...> 。否则， __data_fn 的函数调用运算符不参与重载决议。

注解

若实参为右值（即 T 为对象类型）且 ranges::enable_borrowed_range< std::remove_cv_t <T>> 为 false ，则调用 ranges::data 非良构，这亦导致替换失败。

若 ranges::data( std::forward <T>(t)) 合法，则它返回指向对象的指针。

C++20 标准要求若底层 data 函数调用返回纯右值，则从实质化的临时对象移动构造返回值。所有实现均直接返回纯右值。 C++20 后的提案 P0849R8 更正了该要求以匹配实现。

示例

#include <cstring>
#include <iostream>
#include <ranges>
#include <string>

int main()
{
    std::string s {"Hello world!\n"};

    char a[20]; // C 风格字符串的存储
    std::strcpy(a, std::ranges::data(s));
    // [data(s), data(s) + size(s)] 保证为 NTBS

    std::cout << a;
}

输出：

Hello world!

参阅

ranges::cdata (C++20) | 获得指向只读连续范围的起始的指针 (定制点对象)
ranges::begin (C++20) | 返回指向范围起始的迭代器 (定制点对象)
data (C++17) | 获得指向底层数组的指针 (函数模板)


std::ranges::views::drop, std::ranges::drop_view

< cpp‎ | ranges
定义于头文件 <ranges>
template< ranges::view V >
class drop_view : public ranges::view_interface<drop_view<V>>
 (1) (C++20 起)
namespace views {

inline constexpr /*unspecified*/ drop = /*unspecified*/;

}
 (2) (C++20 起)
1) 由跳过首 N 个元素的底层元素序列构成的范围适配器。
2) 范围适配器对象。给定 T 为 std::remove_cvref_t<decltype((e))> 而 D 为 ranges::range_difference_t<decltype((e))>) ，表达式 views::drop(e, f) 表达式等价于：
  • ((void)f, static_cast<T>(e)) ，若 T 为 ranges::empty_view ，除了 e 与 f 的求值为不确定顺序；
  • 否则为 T(ranges::begin(e) + inc, ranges::end(e), /*to-unsigned-like*/(ranges::distance(e) - inc)) ，若 T 是 ranges::subrange 实现 random_access_range 及 sized_range 的特化且 T 需要存储大小（细节见 ranges::subrange::subrange ），其中 inc 为 std::min <D>(ranges::distance(e), f) ；
  • 否则为 U(ranges::begin(e) + std::min <D>(ranges::distance(e), f), ranges::end(e)) ，若 T 为 std::span、 std::basic_string_view、 ranges::iota_view 或 ranges::subrange 的实现 random_access_range 及 sized_range 的特化，其中 U 为
  • std::span<typename T::element_type> ，若 T 为 std::span 的特化；
  • 否则为 T ；
  • 否则为 drop_view(e, f) 。
所有情况下 decltype((f)) 必须实现 std::convertible_to<D> 。

drop_view 在底层范围 V 分别实现概念 contiguous_range、 random_access_range、 bidirectional_range、 forward_range、 input_range、 common_range 及 sized_range 时实现该概念。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

成员函数

(构造函数)
(C++20)
 构造 drop_view
(公开成员函数)
base
(C++20)
 返回底层（适配的）视图的副本
(公开成员函数)
begin
(C++20)
 返回指向起始的迭代器
(公开成员函数)
end
(C++20)
 返回指向末尾的迭代器或哨位
(公开成员函数)
size
(C++20)
 返回元素数，只要底层（适配的）范围满足 sized_range
(公开成员函数)
继承自 std::ranges::view_interface
empty
(C++20)
 返回视图是否为空。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
data
(C++20)
 返回派生视图的数据的地址。若视图的迭代器类型满足 contiguous_iterator 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator[]
(C++20)
 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

推导指引

辅助模板

template<class T>

inline constexpr bool enable_borrowed_range<std::ranges::drop_view<T>> =

std::ranges::enable_borrowed_range<T>;
 (C++20 起)

std::ranges::enable_borrowed_range 的此特化使 drop_view 在底层视图满足 borrowed_range 时满足它。

示例

#include <ranges>
#include <iostream>

int main()
{
    const auto nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    for (int i : nums | std::views::drop(2))
        std::cout << i << ' ';
    std::cout << '\n';

    for (int i : std::views::iota(1, 10) | std::views::drop(2))
        std::cout << i << ' ';
    std::cout << '\n';

    for (int i : std::ranges::drop_view{nums, 2})
        std::cout << i << ' ';
    std::cout << '\n';
}

输出：

3 4 5 6 7 8 9
3 4 5 6 7 8 9
3 4 5 6 7 8 9

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3494 | C++20 | drop_view 决不是 borrowed_range | 若底层范围是 borrowed_range 则它是
LWG 3407 | C++20 | views::drop 有时无法构造具大小随机访问范围 | 调整构造使之始终合法

参阅

ranges::drop_while_viewviews::drop_while
(C++20)
 由另一 view 跳过元素的起始序列，直至首个谓词返回 false 的元素组成的 view
(类模板) (范围适配器对象)


std::ranges::drop_view<V>::base

< cpp‎ | ranges‎ | drop view
constexpr V base() const& requires std::copy_constructible<V>; | (1) | (C++20 起)
constexpr V base() &&; | (2) | (C++20 起)

返回底层视图的副本。

1) 从底层视图复制构造结果。
2) 从底层视图移动构造结果。

参数

（无）

返回值

底层视图的副本。

示例

本节未完成
原因：暂无示例


std::ranges::drop_view<V>::begin

< cpp‎ | ranges‎ | drop view
constexpr auto begin()

requires (!(__SimpleView<V> &&

ranges::random_access_range<const V> && ranges::sized_range<const V>));
 (1) (C++20 起)
constexpr auto begin() const
requires ranges::random_access_range<const V> && ranges::sized_range<const V>;
 (2) (C++20 起)

返回指向 drop_view 的首元素的迭代器，即指向底层视图第 N 元素的迭代器，或若它有少于 N 各元素则为指向底层视图末尾的迭代器。

若 V 不是 random_access_range 或 sized_range ，为提供 range 概念所要求的的均摊常数时间复杂度，重载 (1) 在 drop_view 对象内缓存结果以供后继调用。

参数

（无）

返回值

ranges::next(ranges::begin(base_), count_, ranges::end(base_)) ，其中 base_ 为底层视图，而 count_ 为要跳过的元素数。

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
#include <ranges>

int main()
{
    std::array hi{ 'H','e','l','l','o',',',' ','C','+','+','2','0','!' };

    std::ranges::for_each(hi, [](const char c){ std::cout << c; });
    std::cout << '\n';

    const auto c = std::distance(hi.begin(), std::ranges::find(hi, 'C'));
    auto cxx = std::ranges::drop_view{ hi, c };
    std::cout << "*drop_view::begin() == '" << *cxx.begin() << "'\n";

//  *cxx.begin() = 'c'; // 未定义： 'views' 要用作观察器

    for (char c : cxx) { std::cout << c; }
    std::cout << '\n';
}

输出：

Hello, C++20!
*drop_view::begin() == 'C'
C++20!

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3482 | C++20 | const 重载能以不具大小范围调用 | const 重载要求 sized_range

参阅

end (C++20) | 返回指向末尾的迭代器或哨位 (公开成员函数)
ranges::begin (C++20) | 返回指向范围起始的迭代器 (定制点对象)
ranges::end (C++20) | 返回指示范围结尾的哨位 (定制点对象)


std::ranges::drop_view 的推导指引

< cpp‎ | ranges‎ | drop view
定义于头文件 <ranges> |
template< class R > drop_view( R&&, ranges::range_difference_t<R> ) -> drop_view<views::all_t<R>>; | (C++20 起)

为 std::ranges::drop_view 提供一个推导指引以允许从 range 和元素数推导。

若 R 为 view 则推导的类型为 drop_view<R> ；否则推导的类型通常为 drop_view<ranges::ref_view<R>> 。

示例

本节未完成
原因：暂无示例


std::ranges::drop_view<V>::drop_view

< cpp‎ | ranges‎ | drop view
drop_view() requires std::default_initializable<V> = default; | (1) | (C++20 起)
constexpr drop_view( V base, ranges::range_difference_t<V> count ); | (2) | (C++20 起)

构造 drop_view 。

1) 默认构造函数。值初始化底层视图并初始化计数为 0 。构造后 base() 返回 V() 的副本而 size() 等于底层视图的大小。
2) 以 std::move(base) 初始化底层视图并以 count 初始化计数。构造后 base() 返回 base 的副本而 size() 若 base 的大小不小于 count 则返回 ranges::size(base) - count ，否则返回 ​0​ 。

参数

base | - | 底层视图
count | - | 要跳过的元素数

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
#include <ranges>

int main()
{
    constexpr std::array hi{ 'H','e','l','l','o',',',' ','C','+','+','2','0' };

    std::ranges::for_each(hi, [](const char c){ std::cout << c; });
    std::cout << '\n';

    constexpr auto n = std::distance(hi.cbegin(), std::ranges::find(hi, 'C'));

    auto cxx = std::ranges::drop_view{ hi, n };

    std::ranges::for_each(cxx, [](const char c){ std::cout << c; });
    std::cout << '\n';
}

输出：

Hello, C++20
C++20


std::ranges::drop_view<V>::end

< cpp‎ | ranges‎ | drop view
constexpr auto end() requires (!__SimpleView<V>); | (1) | (C++20 起)
constexpr auto end() const requires ranges::range<const V>; | (2) | (C++20 起)

返回表示 drop_view 末尾的迭代器或哨位。

等效于返回 ranges::end(base_) ，其中 base_ 为底层视图。

参数

（无）

返回值

表示视图末尾的迭代器或哨位。

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <ranges>

int main()
{
    constexpr char url[]{ "https://cppreference.com" };

    const auto p = std::distance(std::ranges::begin(url), std::ranges::find(url, '/'));
    auto site = std::ranges::drop_view{ url, p + 2 }; // 丢弃前缀 "https://"

    for (auto it = site.begin(); it != site.end(); ++it) {
        std::cout << *it; //                ^^^
    }
    std::cout << '\n';
}

输出：

cppreference.com

参阅

begin (C++20) | 返回指向起始的迭代器 (公开成员函数)
ranges::begin (C++20) | 返回指向范围起始的迭代器 (定制点对象)
ranges::end (C++20) | 返回指示范围结尾的哨位 (定制点对象)


std::ranges::drop_view<V>::size

< cpp‎ | ranges‎ | drop view
constexpr auto size() requires ranges::sized_range<V>; | (1) | (C++20 起)
constexpr auto size() const requires ranges::sized_range<const V>; | (2) | (C++20 起)

返回元素数。

令 base_ 为底层视图， count_ 为存储的计数（通常为传递给构造函数的数，或若 *this 为默认构造则为 ​0​ ）。等价于

const auto s = ranges::size(base_);
const auto c = static_cast<decltype(s)>(count_);
return s < c ? 0 : s - c;

参数

（无）

返回值

元素数。

示例

#include <array>
#include <ranges>

int main()
{
    constexpr std::array a{42, 43, 44};
    static_assert(std::ranges::drop_view{std::views::all(a), 0}.size() == 3);
    static_assert(std::ranges::drop_view{std::views::all(a), 1}.size() == 2);
    static_assert(std::ranges::drop_view{std::views::all(a), 2}.size() == 1);
    static_assert(std::ranges::drop_view{std::views::all(a), 3}.size() == 0);
    static_assert(std::ranges::drop_view{std::views::all(a), 4}.size() == 0);
}

参阅

ranges::size (C++20) | 返回等于范围大小的整数 (定制点对象)
ranges::ssize (C++20) | 返回等于范围大小的有符号整数 (定制点对象)


std::ranges::views::drop_while, std::ranges::drop_while_view

< cpp‎ | ranges
定义于头文件 <ranges>
template< ranges::view V, class Pred >

requires ranges::input_range<V> &&
std::is_object_v <Pred> &&
std::indirect_unary_predicate<const Pred, ranges::iterator_t<V>>

class drop_while_view : public ranges::view_interface<drop_while_view<V, Pred>>
 (1) (C++20 起)
namespace views {

inline constexpr /*unspecified*/ drop_while = /*unspecified*/;

}
 (2) (C++20 起)
1) 表示来自底层序列，始于首个谓词对其返回 false 的元素的 view 。
2) 范围适配器对象。表达式 views::drop_while(e, f) 对任何适合的子表达式 e 与 f 表达式等价于 drop_while_view(e, f) 。

drop_while_view 在底层视图 V 实现 contiguous_range、 random_access_range、 bidirectional_range、 forward_range、 input_range 和 common_range 时实现该概念。若 ranges::forward_range<V> 与 std::sized_sentinel_for<ranges::sentinel_t<D>, ranges::iterator_t<D>> 均被实现则它亦实现 sized_range 。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

成员函数

(构造函数)
(C++20)
 构造 drop_while_view
(公开成员函数)
base
(C++20)
 返回底层（适配的）视图的副本
(公开成员函数)
pred
(C++20)
 返回到存储的谓词的引用
(公开成员函数)
begin
(C++20)
 返回指向起始的迭代器
(公开成员函数)
end
(C++20)
 返回指向末尾的迭代器或哨位
(公开成员函数)
继承自 std::ranges::view_interface
empty
(C++20)
 返回视图是否为空。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
data
(C++20)
 返回派生视图的数据的地址。若视图的迭代器类型满足 contiguous_iterator 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
size
(C++20)
 返回派生视图中的元素数。若视图满足 forward_range 且其哨位与迭代器类型满足 sized_sentinel_for 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator[]
(C++20)
 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

推导指引

辅助模板

template<class T, class Pred>

inline constexpr bool enable_borrowed_range<std::ranges::drop_while_view<T, Pred>> =

std::ranges::enable_borrowed_range<T>;
 (C++20 起)

std::ranges::enable_borrowed_range 的此特化使得 drop_while_view 在底层视图满足 borrowed_range 时满足它。

注解

为提供 range 概念所要求的均摊常数时间复杂度， begin 的结果缓存于 drop_while_view 对象内。若在首次调用 begin() 修改底层范围，则 drop_while_view 对象的后继使用可能导致非本意的行为。

示例

#include <cctype>
#include <iomanip>
#include <iostream>
#include <ranges>
#include <string>
#include <string_view>

std::string trim(std::string_view const in)
{
    auto view
        = in
        | std::views::drop_while(isspace)
        | std::views::reverse
        | std::views::drop_while(isspace)
        | std::views::reverse
        ;
    return {view.begin(), view.end()};
}

int main()
{
    const auto s = trim(" \f\n\t\r\vHello, C++20!\f\n\t\r\v ");
    std::cout << std::quoted(s) << '\n';

    static constexpr auto v = {0, 1, 2, 3, 4, 5};
    for (int n : v | std::views::drop_while([](int i) { return i < 3; })) {
        std::cout << n << ' ';
    }
}

输出：

"Hello, C++20!"
3 4 5

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3494 | C++20 | drop_while_view 始终不是 borrowed_range | 若底层视图是 borrowed_range 则它是

参阅

ranges::drop_viewviews::drop
(C++20)
 由另一 view 跳过首 N 个元素组成的 view
(类模板) (范围适配器对象)


std::ranges::drop_while_view<V,Pred>::base

< cpp‎ | ranges‎ | drop while view
constexpr V base() const& requires std::copy_constructible<V>; | (1) | (C++20 起)
constexpr V base() &&; | (2) | (C++20 起)

返回底层视图的副本。

1) 从底层视图复制构造结果。
2) 从底层视图移动构造结果。

参数

（无）

返回值

底层视图的副本。

示例

#include <array>
#include <ranges>
#include <iostream>

void print(auto const& container) {
    for (const auto& elem : container)
        std::cout << elem << ' ';
    std::cout << '\n';
}

int main()
{
    std::array data{ 1, 2, 3, 4 };
    print(data);

    auto stub = [](int x) { return x < 2; };
    auto view = std::ranges::drop_while_view{ data, stub };

    auto base = view.base(); // `base` 指代 `data`

    std::ranges::reverse(base); //< 直接更改 `data`
    print(data);
}

输出：

1 2 3 4
4 3 2 1


std::ranges::drop_while_view<V,Pred>::begin

< cpp‎ | ranges‎ | drop while view
constexpr auto begin(); | (C++20 起)

返回指向视图首元素的迭代器。

等效于返回 ranges::find_if_not(base_, std::cref (pred())) ，其中 base_ 为底层视图。若 *this 不存储谓词则行为未定义。

为提供 range 概念所要求的均摊常数时间复杂度，此函数在 drop_while_view 对象内缓存结果以供后继使用。

参数

（无）

返回值

指向视图首元素的迭代器。

示例

#include <array>
#include <iostream>
#include <ranges>

int main()
{
    constexpr std::array data{ 0, -1, -2, 3, 1, 4, 1, 5 };

    auto view = std::ranges::drop_while_view{
        data, [](int x) { return x <= 0; }
    };

    std::cout << *view.begin() << '\n';
}

输出：

3

参阅

end
(C++20)
 返回指向末尾的迭代器或哨位
(公开成员函数)


std::ranges::drop_while_view 的推导指引

< cpp‎ | ranges‎ | drop while view
定义于头文件 <ranges> |
template< class R, class Pred > drop_while_view( R&&, Pred ) -> drop_while_view<views::all_t<R>, Pred>; | (C++20 起)

为 std::ranges::drop_while_view 提供推导指引以允许从 range 和谓词推导。

若 R 为 view ，则推导出的类型为 drop_while_view<R> ；否则推导出的类型通常为 drop_while_view<ranges::ref_view<R>> 。

示例

本节未完成
原因：暂无示例


std::ranges::drop_while_view<V,Pred>::drop_while_view

< cpp‎ | ranges‎ | drop while view
drop_while_view() requires std::default_initializable<V> &&
std::default_initializable<Pred> = default;
 (1) (C++20 起)
constexpr drop_while_view( V base, Pred pred );
 (2) (C++20 起)

构造 drop_while_view 。

1) 默认构造函数。值初始化底层视图与谓词。
2) 从 base 移动构造底层视图并从 pred 移动构造谓词。

参数

base | - | 底层视图
pred | - | 谓词

示例

#include <array>
#include <iostream>
#include <ranges>

int main()
{
    constexpr std::array data{ 0, -1, -2, 3, 1, 4, 1, 5, };

    auto view = std::ranges::drop_while_view{
        data, [](int x) { return x <= 0; }
    };

    for (int x: view) {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

输出：

3 1 4 1 5

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | 若 Pred 非 default_initializable ， 则默认构造函数构造不含 Pred 的 drop_while_view | drop_while_view 亦非 default_initializable


std::ranges::drop_while_view<V,Pred>::end

< cpp‎ | ranges‎ | drop while view
constexpr auto end(); | (C++20 起)

返回表示 drop_while_view 末尾的迭代器或哨位。

等效于返回 ranges::end(base_) ，其中 base_ 为底层视图。

参数

（无）

返回值

表示 drop_while_view 末尾的迭代器或哨位。

示例

#include <array>
#include <iostream>
#include <ranges>

int main()
{
    constexpr std::array data{ 0, -1, -2, 3, 1, 4, 1, 5 };

    auto view = std::ranges::drop_while_view{
        data, [](int x) { return x <= 0; }
    };

    for (auto it = view.begin(); it != view.end(); ++it) {
        std::cout << *it << ' ';
    }
    std::cout << '\n';
}

输出：

3 1 4 1 5

参阅

begin
(C++20)
 返回指向起始的迭代器
(公开成员函数)


std::ranges::drop_while_view<V,Pred>::pred

< cpp‎ | ranges‎ | drop while view
constexpr const Pred& pred() const; | (C++20 起)

返回到存储的谓词的引用。

若 *this 不存储谓词（例如在复制构造或移动构造 Pred 的对 *this 的赋值时抛出异常），则行为未定义。

参数

（无）

返回值

到存储的谓词的引用。

示例

#include <array>
#include <iostream>
#include <iomanip>
#include <ranges>

int main()
{
    constexpr std::array data{ 0, -1, -2, 3, 1, 4, 1, 5, };

    auto view = std::ranges::drop_while_view{
        data, [](int x) { return x <= 0; }
    };

    std::cout << std::boolalpha;
    for (int x: data) {
        std::cout << "predicate(" << std::setw(2) << x << ") : "
                  << view.pred()(x) << '\n';
    }
}

输出：

predicate( 0) : true
predicate(-1) : true
predicate(-2) : true
predicate( 3) : false
predicate( 1) : false
predicate( 4) : false
predicate( 1) : false
predicate( 5) : false


std::ranges::views::elements, std::ranges::elements_view

< cpp‎ | ranges
定义于头文件 <ranges>
template< ranges::input_range V, std::size_t N >

requires
view<V> &&
__HasTupleElement<ranges::range_value_t<V>, N> &&
__HasTupleElement< std::remove_reference_t <ranges::range_reference_t<V>>, N> &&
__ReturnableElement<<ranges::range_reference_t<V>, N>

class elements_view : public ranges::view_interface<elements_view<V, N>>;
 (1) (C++20 起)
namespace views {

inline constexpr /*unspecified*/ elements = /*unspecified*/;

}
 (2) (C++20 起)
调用签名
template< ranges::viewable_range R >

requires /* see below */

constexpr ranges::view auto elements<N>( R&& r );
辅助概念
template< class T, std::size_t N >

concept __HasTupleElement = // 仅用于阐释
requires(T t) {
typename std::tuple_size <T>::type;
requires N < std::tuple_size_v <T>;
typename std::tuple_element_t <N, T>;
{ std::get<N>(t) } -> std::convertible_to<const std::tuple_element_t <N, T>&>;

};
 (3) (C++20 起)
template< class T, std::size_t N >

concept __ReturnableElement = // 仅用于阐释

std::is_reference_v <T> || std::move_constructible< std::tuple_element_t <N, T>>;
 (4) (C++20 起)
1) 接收元组式值的 view ，并产生值类型为适配视图的值类型的第 N 元素的视图。
2) views::elements 的每个特化均为范围适配器对象。对于任何适合的表达式 e 与常量表达式 M表达式 views​::​elements<M>(e) 表达式等价于 elements_view<views​::​all_t<decltype((e))>, M>{e} 。
3) 确保底层视图的元素是元组式值。
4) 确保不能返回悬垂引用。

elements_view 在底层视图 V 实现 random_access_range、 bidirectional_range、 forward_range、 input_range、 common_range 及 sized_range 时实现对应的概念。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

成员函数

(构造函数)
(C++20)
 构造 elements_view
(公开成员函数)
base
(C++20)
 返回底层（适配的）视图的副本
(公开成员函数)
begin
(C++20)
 返回指向起始的迭代器
(公开成员函数)
end
(C++20)
 返回指向末尾的迭代器或哨位
(公开成员函数)
size
(C++20)
 返回元素数，只要底层（适配的）范围满足 sized_range
(公开成员函数)
继承自 std::ranges::view_interface
empty
(C++20)
 返回视图是否为空。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator[]
(C++20)
 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

嵌套类

iterator (C++20) | 迭代器类型 (仅用于阐释的成员类模板)
sentinel (C++20) | 哨位类型 (仅用于阐释的成员类模板)

辅助模板

template<class T, std::size_t N>

inline constexpr bool enable_borrowed_range<std::ranges::elements_view<T, N>> =

std::ranges::enable_borrowed_range<T>;
 (C++20 起)

std::ranges::enable_borrowed_range 的此特化使得 elements_view 在底层视图满足 borrowed_range 时满足它。

示例

#include <iostream>
#include <ranges>
#include <tuple>
#include <vector>

int main()
{
    const std::vector<std::tuple<int, char, std::string>> vt {
        {1, 'A', "α"},
        {2, 'B', "β"},
        {3, 'C', "γ"},
        {4, 'D', "δ"},
        {5, 'E', "ε"},
    };

    for (int const e: std::views::elements<0>(vt)) { std::cout << e << ' '; }
    std::cout << '\n';
    for (char const e: std::views::elements<1>(vt)) { std::cout << e << ' '; }
    std::cout << '\n';
    for (std::string const& e: std::views::elements<2>(vt)) { std::cout << e << ' '; }
    std::cout << '\n';
}

输出：

1 2 3 4 5
A B C D E
α β γ δ ε

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3494 | C++20 | elements_view 始终不是 borrowed_range | 若底层视图是 borrowed_range 则它是
LWG 3502 | C++20 | 能从 elements_view 获得悬垂引用 | 禁止这种用法

参阅

ranges::keys_viewviews::keys (C++20) | 选取 pair 式值组成的 view 并产生每个 pair 的第一元素的 view (类模板) (范围适配器对象)
ranges::values_viewviews::values (C++20) | 选取 pair 式值组成的 view 并产生每个 pair 的第二元素的 view (类模板) (范围适配器对象)
slice | valarray 的 BLAS 式切片：起始下标、长度、跨度 (类)


std::ranges::elements_view<V,N>::base

< cpp‎ | ranges‎ | elements view
constexpr V base() const& requires std::copy_constructible<V>; | (1) | (C++20 起)
constexpr V base() &&; | (2) | (C++20 起)

返回底层视图的副本。

1) 从底层视图复制构造结果。
2) 从底层视图移动构造结果。

参数

（无）

返回值

底层视图的副本。

示例

本节未完成
原因：暂无示例


std::ranges::elements_view<V,N>::begin

< cpp‎ | ranges‎ | elements view
constexpr auto begin() requires (!__SimpleView<V>); | (1) | (C++20 起)
constexpr auto begin() const requires ranges::range<const V>; | (2) | (C++20 起)

返回指向 elements_view 首元素的迭代器。

令 base_ 为底层视图。

1) 等价于 return /*iterator*/<false>(ranges::begin(base_)); 。
2) 等价于 return /*iterator*/<true>(ranges::begin(base_)); 。

参数

（无）

返回值

指向首元素的迭代器。

示例

本节未完成
原因：暂无示例

参阅

end (C++20) | 返回指向末尾的迭代器或哨位 (公开成员函数)
ranges::begin (C++20) | 返回指向范围起始的迭代器 (定制点对象)


std::ranges::elements_view<V,N>::elements_view

< cpp‎ | ranges‎ | elements view
elements_view() requires std::default_initializable<V> = default; | (1) | (C++20 起)
constexpr elements_view( V base ); | (2) | (C++20 起)

构造 elements_view 。

1) 默认构造函数。值初始化底层视图。构造后 base() 返回 V() 的副本。
2) 以 std::move(r) 初始化底层视图。

参数

base - 底层视图

示例

#include <iostream>
#include <ranges>
#include <tuple>
#include <array>
using namespace std::literals;

int main()
{
    const std::array<std::tuple<int, char, std::string>, 2> vt {
        std::tuple{1, 'A', "α"s},
        std::tuple{2, 'B', "β"s},
    };

    [[maybe_unused]]
    auto empty = std::views::elements<0>;

    auto ev0 = std::views::elements<0>(vt);
    auto ev1 = std::views::elements<1>(vt);
    auto ev2 = std::views::elements<2>(vt);

    for (auto const& e: ev0) { std::cout << e << ' '; }
    std::cout << '\n';
    for (auto const& e: ev1) { std::cout << e << ' '; }
    std::cout << '\n';
    for (auto const& e: ev2) { std::cout << e << ' '; }
    std::cout << '\n';
}

输出：

1 2
A B
α β


std::ranges::elements_view<V,N>::end

< cpp‎ | ranges‎ | elements view
constexpr auto end() requires (!__SimpleView<V> && !ranges::common_range<V>); | (1) | (C++20 起)
constexpr auto end() requires (!__SimpleView<V> && ranges::common_range<V>); | (2) | (C++20 起)
constexpr auto end() const requires ranges::range<const V>; | (3) | (C++20 起)
constexpr auto end() const requires ranges::common_range<const V>; | (4) | (C++20 起)

返回表示 elements_view 末尾的哨位或迭代器。

令 base_ 为底层视图：

1) 等价于 return /*sentinel*/<false>{ranges::end(base_)}; 。
2) 等价于 return /*iterator*/<false>{ranges::end(base_)}; 。
3) 等价于 return /*sentinel*/<true>{ranges::end(base_)}; 。
4) 等价于 return /*iterator*/<true>{ranges::end(base_)}; 。

参数

（无）

返回值

1,3) 比较等于尾迭代器的哨位。
2,4) 指向末元素后一位置的迭代器。

注解

end() 当且仅当底层视图为 common_range 时返回迭代器： elements_view<V,F> 凡在 V 实现 common_range 时实现该概念。

示例

本节未完成
原因：暂无示例

参阅

begin (C++20) | 返回指向起始的迭代器 (公开成员函数)
ranges::end (C++20) | 返回指示范围结尾的哨位 (定制点对象)


std::ranges::elements_view<V,N>::iterator

< cpp‎ | ranges‎ | elements view
template< bool Const > class /*iterator*/; // 仅用于阐释 | (C++20 起)

elements_view::begin 的返回类型，及 elements_view::end 在底层类型为 common_range 时的返回类型。

const 限定重载返回 /*iterator*/<true> 。非 const 限定重载返回 /*iterator*/<false> 。

此类模板的名字（此处示为 iterator ）是未指定的。

成员类型

成员类型 | 定义
Base (私有) | 若 Const 为 true 则为 const V ，否则为 V 。名字仅用于阐释
iterator_concept 若 Base 实现 random_access_range 则为 std::random_access_iterator_tag ，
若 Base 实现 bidirectional_range 则为 std::bidirectional_iterator_tag ，
若 Base 实现 forward_range 则为 std::forward_iterator_tag ，
否则为 std::input_iterator_tag
iterator_category 若 Base 不实现 forward_range 则不定义。
  • 否则若 std​::​get<N>(*current_) 为右值则该类型为 std::input_iterator_tag 。
  • 否则令 C 为类型 std::iterator_traits <std::iterator_t<Base>>​::​iterator_category 。则若 C 实现 std::derived_from< std::random_access_iterator_tag > 则该类型为 std::random_access_iterator_tag 。
  • 否则该类型为 C 。
value_type | std::remove_cvref_t< std::tuple_element_t <N, ranges::range_value_t<Base>>>
difference_type | ranges::range_difference_t<Base>

成员对象

成员名 | 定义
current_ (私有) | ranges::iterator_t<Base> 类型对象，名字仅用于阐释

成员函数

(构造函数) (C++20) | 构造迭代器 (公开成员函数)
base (C++20) | 返回底层迭代器 (公开成员函数)
operator* (C++20) | 访问第 N 元组元素 (公开成员函数)
operator[] (C++20) | 按下标访问元素 (公开成员函数)
operator++operator++(int) operator--operator--(int)operator+=operator-= (C++20) | 推进或减少底层迭代器 (公开成员函数)

非成员函数

operator==operator<operator>operator<=operator>=operator<=> (C++20) | 比较底层迭代器 (函数)
operator+operator- (C++20) | 进行迭代器算术 (函数)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2259R1 | C++20 | 始终定义成员 iterator_category | 仅若 Base 实现 forward_range 才定义
LWG 3555 | C++20 | iterator_concept 的定义忽略 const | 使之考虑

参阅


std::ranges::elements_view<V,N>::iterator<Const>::base

< cpp‎ | ranges‎ | elements view‎ | iterator
constexpr const ranges::iterator_t<Base>& base() const & noexcept; | (1) | (C++20 起)
constexpr ranges::iterator_t<Base> base() &&; | (2) | (C++20 起)

返回底层迭代器。

1) 返回到底层迭代器的引用。
2) 从底层迭代器移动构造结果。

参数

（无）

返回值

1) 到底层迭代器的引用。
1) 从底层迭代器移动构造的迭代器。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3533 | C++20 | base 的 const& 重载返回底层迭代器的副本 | 返回引用
LWG 3593 | C++20 | base 的 const& 重载可以不是 noexcept | 使之为 noexcept


std::ranges::elements_view<V,N>::iterator<Const>::iterator

< cpp‎ | ranges‎ | elements view‎ | iterator
/*iterator*/() requires std::default_initializable<ranges::iterator_t<Base>>
= default;
 (1) (C++20 起)
constexpr explicit /*iterator*/( ranges::iterator_t<Base> current );
 (2) (C++20 起)
constexpr /*iterator*/( /*iterator*/<!Const> i ) requires Const &&
std::convertible_to<ranges::iterator_t<V>, ranges::iterator_t<Base>>;
 (3) (C++20 起)

构造迭代器。

1) 经由其默认成员初始化器（= ranges::iterator_t<Base>()）值初始化底层迭代器 current_ 。
2) 以 std::move(current) 初始化底层迭代器 current_ 。
3) 从 /*iterator*/<false> 转换到 /*iterator*/<true> 。以 std::move(i.current) 初始化底层迭代器 current_ 。

参数

current | - | 指向（可能为 const 限定的） V 中的迭代器
i | - | /*iterator*/<false>

示例

本节未完成
原因：暂无示例


std::ranges::elements_view<V,N>::iterator<Const>::operator*

< cpp‎ | ranges‎ | elements view‎ | iterator
constexpr decltype(auto) operator*() const; | (C++20 起)

返回底层迭代器所指向的 V 中的元素。

等效于返回 /*get-element*/(this->base()) ，其中对于表达式 e ， /*get-element*/(e) 为

  • std::get<N>(*e) ，若 ranges::range_reference_t<Base> 为引用类型，
  • 否则为 static_cast<E>(std::get<N>(*e)) ，其中 E 为 std::remove_cv_t < std::tuple_element_t <N, ranges::range_reference_t<Base>>> 。

参数

（无）

返回值

当前元素。

注解

不提供 operator-> 。

示例

本节未完成
原因：暂无示例


std::ranges::elements_view<V,N>::iterator<Const>::operator++,--,+=,-=

< cpp‎ | ranges‎ | elements view‎ | iterator
constexpr /*iterator*/& operator++();
 (1) (C++20 起)
constexpr void operator++( int );
 (2) (C++20 起)
constexpr /*iterator*/ operator++( int )
requires ranges::forward_range<Base>;
 (3) (C++20 起)
constexpr /*iterator*/& operator--()
requires ranges::bidirectional_range<Base>;
 (4) (C++20 起)
constexpr /*iterator*/ operator--( int )
requires ranges::bidirectional_range<Base>;
 (5) (C++20 起)
constexpr /*iterator*/& operator+=( difference_type n )
requires ranges::random_access_range<Base>;
 (6) (C++20 起)
constexpr /*iterator*/& operator-=( difference_type n )
requires ranges::random_access_range<Base>;
 (7) (C++20 起)

增或减迭代器。

令 current_ 为底层迭代器。

1) 等价于 ++current_; return *this;
2) 等价于 ++current_;
3) 等价于 auto tmp = *this; ++*this; return tmp;
4) 等价于 --current_; return *this;
5) 等价于 auto tmp = *this; --*this; return tmp;
6) 等价于 current_ += n; return *this;
7) 等价于 current_ -= n; return *this;

参数

n - 相对于当前位置的位置

返回值

1,4,6,7) *this
2) （无）
3,5) 更改前的 *this 的副本


operator+,-(ranges::elements_view::iterator)

< cpp‎ | ranges‎ | elements view‎ | iterator
friend constexpr /*iterator*/ operator+( const /*iterator*/& i, difference_type n ) requires ranges::random_access_range<Base>; | (1) | (C++20 起)
friend constexpr /*iterator*/ operator+( difference_type n, const /*iterator*/& i ) requires ranges::random_access_range<Base>; | (2) | (C++20 起)
friend constexpr /*iterator*/ operator-( const /*iterator*/& i, difference_type n ) requires ranges::random_access_range<Base>; | (3) | (C++20 起)
friend constexpr difference_type operator-( const /*iterator*/& x, const /*iterator*/& y ) requires std::sized_sentinel_for<ranges::iterator_t<Base>, ranges::iterator_t<Base>>; | (4) | (C++20 起)
1,2) 返回增加 n 的迭代器 i 。
3) 返回减少 n 的迭代器 i
4) 返回 x 与 y 之间的距离。

这些函数对通常无限定或有限定查找不可见，而只能在 elements_view::iterator<Const> 为参数的关联类时由实参依赖查找找到。

参数

i, x, y | - | 迭代器
n | - | 相对于当前位置的位置

返回值

1-2) [&]{ auto j = i; j += n; return j; }()
3) [&]{ auto j = i; j -= n; return j; }()
4) x.base() - y.base()

示例

本节未完成
原因：暂无示例


std::ranges::elements_view<V,N>::iterator<Const>::operator[]

< cpp‎ | ranges‎ | elements view‎ | iterator
constexpr decltype(auto) operator[]( difference_type n ) const requires ranges::random_access_range<Base>; | (C++20 起)

返回位于指定位置的元素。

等效于返回 /*get-element*/(this->base() + n) ，其中对于表达式 e ， /*get-element*/(e) 为

  • std::get<N>(*e) ，若 ranges::range_reference_t<Base> 为引用类型，
  • 否则为 static_cast<E>(std::get<N>(*e)) ，其中 E 为 std::remove_cv_t < std::tuple_element_t <N, ranges::range_reference_t<Base>>> 。

参数

n - 相对当前位置的位置

返回值

位于相对于当前位置位移为 n 的元素。

示例

本节未完成
原因：暂无示例


operator==,<,>,<=,>=,<=>(ranges::elements_view::iterator)

< cpp‎ | ranges‎ | elements view‎ | iterator
friend constexpr bool operator==( const /*iterator*/& x, const /*iterator*/& y )
requires std::equality_comparable<ranges::iterator_t<Base>>;
 (1) (C++20 起)
friend constexpr bool operator<( const /*iterator*/& x, const /*iterator*/& y )
requires ranges::random_access_range<Base>;
 (2) (C++20 起)
friend constexpr bool operator>( const /*iterator*/& x, const /*iterator*/& y )
requires ranges::random_access_range<Base>;
 (3) (C++20 起)
friend constexpr bool operator<=( const /*iterator*/& x, const /*iterator*/& y )
requires ranges::random_access_range<Base>;
 (4) (C++20 起)
friend constexpr bool operator>=( const /*iterator*/& x, const /*iterator*/& y )
requires ranges::random_access_range<Base>;
 (5) (C++20 起)
friend constexpr auto operator<=>( const /*iterator*/& x, const /*iterator*/& y )

requires ranges::random_access_range<Base> &&

std::three_way_comparable<ranges::iterator_t<Base>>;
 (6) (C++20 起)

比较底层迭代器。

1) 等价于 return x.base() == y.base(); 。
2) 等价于 return x.base() < y.base(); 。
3) 等价于 return y < x; 。
4) 等价于 return !(y < x); 。
5) 等价于 return !(x < y); 。
6) 等价于 return x.base() <=> y.base(); 。

这些函数对通常无限定或有限定查找不可见，而只能在 std::ranges::elements_view::iterator<Const> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

参数

x, y - 要比较的迭代器

返回值

比较结果。


std::ranges::elements_view<V,N>::sentinel

< cpp‎ | ranges‎ | elements view
template< bool Const > class /*sentinel*/; // 仅用于阐释 | (C++20 起)

elements_view::end 在底层类型非 common_range 时的返回类型。

const 限定重载返回 /*sentinel*/<true> 类型。非 const 限定重载返回 /*sentinel*/<false> 类型。

此类模板的名字（此处示为 /*sentinel*/ ）是未指定的。

典型实现仅保有一个数据成员：从（可能为 const 限定的） V 获得的哨位 end_ 。

成员类型

成员类型 | 定义
Base (私有) | 若 Const 为 true 则为 const V ，否则为 V 。名称仅用于阐释

成员函数

(构造函数) (C++20) | 构造哨位 (公开成员函数)
base (C++20) | 返回底层哨位 (公开成员函数)

非成员函数

operator== (C++20) | 比较哨位与从 elements_view::begin 返回的迭代器 (函数)
operator- (C++20) | 计算哨位与从 elements_view::begin 返回的迭代器的距离 (函数)


std::ranges::elements_view<V,N>::sentinel<Const>::base

< cpp‎ | ranges‎ | elements view‎ | sentinel
constexpr ranges::sentinel_t<Base> base() const; | (C++20 起)

返回底层哨位。

参数

（无）

返回值

底层哨位的副本。

示例

本节未完成
原因：暂无示例


operator-(ranges::elements_view::sentinel)

< cpp‎ | ranges‎ | elements view‎ | sentinel
template< bool OtherConst >

requires std::sized_sentinel_for<ranges::sentinel_t<Base>,
ranges::iterator_t</*maybe-const*/<OtherConst, V>>>
friend constexpr ranges::range_difference_t</*maybe-const*/<OtherConst, V>>

operator-( const /*iterator*/<OtherConst>& x, const /*sentinel*/& y );
 (1) (C++20 起)
template< bool OtherConst >

requires std::sized_sentinel_for<ranges::sentinel_t<Base>,
ranges::iterator_t</*maybe-const*/<OtherConst, V>>>
friend constexpr ranges::range_difference_t</*maybe-const*/<OtherConst, V>>

operator-( const /*sentinel*/& y, const /*iterator*/<OtherConst>& x );
 (2) (C++20 起)

计算 x 的底层迭代器与 y 的底层哨位间的距离。

这些函数对通常无限定或有限定查找不可见，而只能在 elements_view::sentinel<Const> 为参数的关联类时由实参依赖查找找到。

参数

x | - | 迭代器
y | - | 哨位

返回值

1) x.base() - y.base()
2) y.base() - x.base()


operator==(ranges::elements_view::sentinel)

< cpp‎ | ranges‎ | elements view‎ | sentinel
template< bool OtherConst >

requires std::sentinel_for<ranges::sentinel_t<Base>,
ranges::iterator_t</*maybe-const*/<OtherConst, V>>>
friend constexpr bool operator==( const /*iterator*/<OtherConst>& x,

const /*sentinel*/& y );
 (C++20 起)

比较 x 的底层迭代器与 y 的底层哨位。

此函数对通常无限定或有限定查找不可见，而只能在 elements_view::sentinel<Const> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

参数

x | - | 要比较的迭代器
y | - | 要比较的哨位

返回值

x.current_ == y.end_ ，其中 current_ 代表底层迭代器， end_ 代表底层哨位。

示例

本节未完成
原因：暂无示例


std::ranges::elements_view<V,N>::sentinel<Const>::sentinel

< cpp‎ | ranges‎ | elements view‎ | sentinel
/*sentinel*/() = default;
 (1) (C++20 起)
constexpr explicit /*sentinel*/( ranges::sentinel_t<Base> end );
 (2) (C++20 起)
constexpr /*sentinel*/( /*sentinel*/<!Const> i )

requires Const && std::convertible_to<ranges::sentinel_t<V>,

ranges::sentinel_t<Base>>;
 (3) (C++20 起)

构造哨位。

1) 默认构造函数。值初始化底层哨位。
2) 以 end 初始化底层哨位。
3) 从 /*sentinel*/<false> 转换到 /*sentinel*/<true> 。移动构造底层哨位。

参数

end | - | 表示（可能为 const 限定的） V 末尾的哨位
i | - | /*sentinel*/<false>

示例

本节未完成
原因：暂无示例


std::ranges::elements_view<V,N>::size

< cpp‎ | ranges‎ | elements view
constexpr auto size() requires ranges::sized_range<V>; | (C++20 起)
constexpr auto size() const requires ranges::sized_range<const V>; | (C++20 起)

返回元素数，即 ranges::size(base_) ，其中 base_ 为底层视图。

参数

（无）

返回值

元素数。

示例

本节未完成
原因：暂无示例

参阅

ranges::size (C++20) | 返回等于范围大小的整数 (定制点对象)
ranges::ssize (C++20) | 返回等于范围大小的有符号整数 (定制点对象)


std::ranges::empty

< cpp‎ | ranges
定义于头文件 <ranges>
inline namespace /*unspecified*/ {

inline constexpr auto empty = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T >

requires /* see below */

constexpr bool empty(T&& t);

确定 t 是否拥有任何元素。

令 t 为 T 类型对象。对 ranges::empty 的调用表达式等价于：

  1. bool( std::forward <T>(t).empty()) ，若该表达式合法。
  2. 否则为 (ranges::size( std::forward <T>(t)) == 0) ，若该表达式合法。
  3. 否则为 bool(ranges::begin(t) == ranges::end(t)) 。

所有其他情况下，对 ranges::empty 的调用非良构，这能在 ranges::empty(t) 出现于模板实例化的立即语境中时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::empty 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __empty_fn 表示其类型的 cv 无限定版本。

__empty_fn 的所有实例均相等。在相同参数上调用类型 __empty_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::empty 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::empty 的参数要求，则 __empty_fn 实现 std::invocable<__empty_fn, Args...>、 std::invocable<const __empty_fn, Args...>、 std::invocable<__empty_fn&, Args...> 及 std::invocable<const __empty_fn&, Args...> 。否则， __empty_fn 的函数调用运算符不参与重载决议。

示例

#include <iostream>
#include <ranges>
#include <vector>

template <std::ranges::input_range R>
void print(R&& r)
{
    if (std::ranges::empty(r)) {
        std::cout << "\tEmpty\n";
        return;
    }

    std::cout << "\tElements:";
    for (const auto& element : r) {
        std::cout << ' ' << element;
    }

    std::cout << '\n';
}

int main()
{
    {
        auto v = std::vector<int>{1, 2, 3};
        std::cout << "1. calling ranges::empty on std::vector:\n";
        print(v);

        v.clear();
        print(v);
    }
    {
        std::cout << "2. calling ranges::empty on std::initializer_list:\n";
        auto il = {7, 8, 9};
        print(il);

        print(std::initializer_list<int>{});
    }
    {
        std::cout << "2. calling ranges::empty on a raw array:\n";
        int array[] = {4, 5, 6}; // 数组拥有已知边界
        print(array);
    }
    {
        struct NoEmptyNorSize : private std::vector<int> {
            auto begin() { return std::vector<int>::begin(); }
            auto end() { return std::vector<int>::end(); }
        };

        std::cout << "3. calling ranges::empty on an object that satisfies only case 3):\n";
        print(NoEmptyNorSize{});
    }
}

输出：

1. calling ranges::empty on std::vector:
        Elements: 1 2 3
        Empty
2. calling ranges::empty on std::initializer_list:
        Elements: 7 8 9
        Empty
2. calling ranges::empty on a raw array:
        Elements: 4 5 6
3. calling ranges::empty on an object that satisfies only case 3):
        Empty

参阅

empty
(C++17)
 检查容器是否为空
(函数模板)


std::ranges::views::empty, std::ranges::empty_view

< cpp‎ | ranges
template<class T>

requires std::is_object_v <T>

class empty_view : public ranges::view_interface<empty_view<T>>
 (1) (C++20 起)
namespace views {

template<class T> inline constexpr empty_view<T> empty{};

}
 (2) (C++20 起)
1) 产生无特定类型元素的 view 的范围工厂。
2) empty_view 的变量模板。

成员函数

begin
[静态] (C++20)
 返回 nullptr
(公开静态成员函数)
end
[静态] (C++20)
 返回 nullptr
(公开静态成员函数)
data
[静态] (C++20)
 返回 nullptr
(公开静态成员函数)
size
[静态] (C++20)
 返回 ​0​ （零）
(公开静态成员函数)
empty
[静态] (C++20)
 返回 true
(公开静态成员函数)
继承自 std::ranges::view_interface
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator[]
(C++20)
 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

std::ranges::empty_view::begin

static constexpr T* begin() noexcept { return nullptr; } | (C++20 起)

empty_view 不引用任何元素。

std::ranges::empty_view::end

static constexpr T* end() noexcept { return nullptr; } | (C++20 起)

empty_view 不引用任何元素。

std::ranges::empty_view::data

static constexpr T* data() noexcept { return nullptr; } | (C++20 起)

empty_view 不引用任何元素。

std::ranges::empty_view::size

static constexpr std::size_t size() noexcept { return 0; } | (C++20 起)

empty_view 始终为空。

std::ranges::empty_view::empty

static constexpr bool empty() noexcept { return true; } | (C++20 起)

empty_view 始终为空。

辅助模板

template<class T> inline constexpr bool enable_borrowed_range<ranges::empty_view<T>> = true; | (C++20 起)

std::ranges::enable_borrowed_range 的此特化使得 empty_view 满足 borrowed_range 。

注解

尽管 empty_view 从 view_interface 获得成员函数 front、 back 及 operator[] ，对它们的调用始终导致未定义行为，因为 empty_view 始终为空。

继承的 operator bool 转换函数始终返回 false 。

示例

#include <ranges>

int main()
{
    std::ranges::empty_view<long> e;
    static_assert(std::ranges::empty(e));
    static_assert(0 == e.size());
    static_assert(nullptr == e.data());
    static_assert(nullptr == e.begin());
    static_assert(nullptr == e.end());
}

参阅

ranges::single_viewviews::single (C++20) | 含有具有指定值的单个元素的 view (类模板) (定制点对象)
views::all_tviews::all (C++20) | 包含 range 的所有元素的 view (别名模板) (范围适配器对象)
ranges::ref_view (C++20) | 某个其他 range 的元素的 view (类模板)


std::ranges::end

< cpp‎ | ranges
定义于头文件 <ranges>
定义于头文件 <iterator>
inline namespace /*unspecified*/ {

inline constexpr /*unspecified*/ end = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T >

requires /* see below */

constexpr std::sentinel_for<ranges::iterator_t<T>> auto end(T&& t);

返回指示范围末尾的哨位。

令 t 为 T 类型对象。若实参为左值或 ranges::enable_borrowed_range< std::remove_cv_t <T>> 为 true ，则调用 ranges::end 表达式等价于：

  1. t + std::extent_v <T> ，若 T 为已知边界数组类型。
    若 std::remove_all_extents_t <T> 不完整，则 ranges::end( std::forward <T>(t)) 非良构，不要求诊断。
  2. 否则为 std::forward <T>(t).end() 转换到其衰变类型，若该带转换表达式合法且其转换后的类型实现 std::sentinel_for<ranges::iterator_t<T>> 。
  3. 否则为 end( std::forward <T>(t)) 转换到其衰变类型，若 T 为类或枚举类型，带转换的前述无限定调用合法，且其转换后的类型实现 std::sentinel_for<ranges::iterator_t<T>> ，其中重载决议以下列候选进行：
    • void end(auto&) = delete;
    • void end(const auto&) = delete;
    • 实参依赖查找所找到的任何 end 声明。

所有其他情况下，调用 ranges::end 非良构，这能在 ranges::end(t) 出现于模板实例化的立即语境时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::end 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __end_fn 表示其类型的 cv 无限定版本。

__end_fn 的所有实例均相等。在相同参数上调用类型 __end_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::end 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::end 的参数要求，则 __end_fn 实现 std::invocable<__end_fn, Args...>、 std::invocable<const __end_fn, Args...>、 std::invocable<__end_fn&, Args...> 及 std::invocable<const __end_fn&, Args...> 。否则， __end_fn 的函数调用运算符不参与重载决议。

注解

若实参为右值（即 T 为对象类型）且 ranges::enable_borrowed_range< std::remove_cv_t <T>> 为 false ，或若它拥有未知边界数组类型，则调用 ranges::end 非良构，这亦导致替换失败。

若 ranges::end( std::forward <T>(t)) 合法，则所有情况下 decltype(ranges::end( std::forward <T>(t))) 与 decltype(ranges::begin( std::forward <T>(t))) 实现 std::sentinel_for ，同时 T 实现 std::ranges::range 。

C++20 标准要求若底层 end 函数调用返回纯右值，则从实质化的临时对象移动构造返回值。所有实现均直接返回纯右值。 C++20 后的提案 P0849R8 更正了该要求以匹配实现。

示例

#include <algorithm>
#include <iostream>
#include <ranges>
#include <vector>

int main()
{
    std::vector<int> v = { 3, 1, 4 };
    namespace ranges = std::ranges;
    if (ranges::find(v, 5) != ranges::end(v)) {
        std::cout << "found a 5 in vector v!\n";
    }

    int a[] = { 5, 10, 15 };
    if (ranges::find(a, 5) != ranges::end(a)) {
        std::cout << "found a 5 in array a!\n";
    }
}

输出：

found a 5 in array a!

参阅

ranges::cend (C++20) | 返回指示只读范围结尾的哨位 (定制点对象)
ranges::begin (C++20) | 返回指向范围起始的迭代器 (定制点对象)
endcend (C++11)(C++14) | 返回指向容器或数组结尾的迭代器 (函数模板)


std::ranges::views::filter, std::ranges::filter_view

< cpp‎ | ranges
定义于头文件 <ranges>
template< ranges::input_range V,

std::indirect_unary_predicate<ranges::iterator_t<V>> Pred >
requires ranges::view<V> && std::is_object_v <Pred>

class filter_view : public ranges::view_interface<filter_view<V, Pred>>
 (1) (C++20 起)
namespace views {

inline constexpr /*unspecified*/ filter = /*unspecified*/;

}
 (2) (C++20 起)
1) 表示排除了不能满足谓词的元素的底层序列的 view 的范围适配器。
2) 范围适配器对象。对任何适合的子表达式 e 与 p ，表达式 views::filter(e, p) 表达式等价于 filter_view(e, p) 。

filter_view 在底层 view V 实现 bidirectional_range、 forward_range、 input_range 及 common_range 时分别实现相应的概念。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

数据成员

filter_view 的典型实现保有二或三个数据成员：

  • V 类型的底层 view （此处示为 base_ ，仅为阐释），
  • /*copyable-box*/<Pred> 类型的包装，包装用于滤出 base_ 的元素的谓词（此处示为 pred_ ，仅为阐释），其中 copyable-box 时始终满足 copyable 的包装类模板，
  • std::optional 式对象（此处示为 begin_ ，仅为阐释），缓存指向 base_ 的首个满足 pred_ 的元素的迭代器。 begin_ 可能仅若 filter_view 实现 forward_range 才存在。

成员函数

(构造函数)
(C++20)
 构造 filter_view
(公开成员函数)
base
(C++20)
 返回底层视图 V
(公开成员函数)
pred
(C++20)
 返回到存储于 filter_view 内的谓词的引用
(公开成员函数)
begin
(C++20)
 返回 filter_view 的起始迭代器
(公开成员函数)
end
(C++20)
 返回 filter_view 的哨位
(公开成员函数)
继承自 std::ranges::view_interface
empty
(C++20)
 返回视图是否为空。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

std::ranges::filter_view::filter_view

filter_view() requires std::default_initializable<V> &&
std::default_initializable<Pred> = default;
 (1) (C++20 起)
constexpr filter_view( V base, Pred pred );
 (2) (C++20 起)
1) 经由其默认成员初始化器（= V()）值初始化 base_ 并默认初始化 pred_ （这值初始化其所含的 Pred ）。
2) 以 std::move(base) 初始化 base_ 并以 std::move(pred) 初始化 pred_ 。

参数

base | - | 要滤的范围
pred | - | 滤出元素的谓词

std::ranges::filter_view::base

constexpr V base() const& requires std::copy_constructible<V>; | (1) | (C++20 起)
constexpr V base() &&; | (2) | (C++20 起)
1) 等价于 return base_; 。
2) 等价于 return std::move(base_); 。

std::ranges::filter_view::pred

constexpr const Pred& pred() const; | (C++20 起)

返回到存储的 Pred 对象的引用。若 pred_ 不含值则行为未定义。

std::ranges::filter_view::begin

constexpr /*iterator*/ begin(); | (C++20 起)

为提供 range 概念所要求的均摊常数时间复杂度，此函数在 filter_view 对象内存储结果以用于后继调用。等价于

if constexpr (!ranges::forward_range<V>) {
    return /*iterator*/{*this, ranges::find_if(base_, std::ref(*pred_))};
} else {
    if (!begin_.has_value())
        begin_ = ranges::find_if(base_, std::ref(*pred_)); // 缓存
    return /*iterator*/{*this, begin_.value())};
}

若 pred_ 不含值则行为未定义。

std::ranges::filter_view::end

constexpr auto end() {

if constexpr (ranges::common_range<V>)
return /*iterator*/{*this, ranges::end(base_)};
else
return /*sentinel*/{*this};

}
 (C++20 起)

推导指引

template< class R, class Pred > filter_view( R&&, Pred ) -> filter_view<views::all_t<R>, Pred>; | (C++20 起)

嵌套类

iterator (C++20) | filter_view 的迭代器类型 (仅用于阐释的成员类)
sentinel (C++20) | 底层视图非 common_range 时的 filter_view 的哨位类型 (仅用于阐释的成员类)

示例

#include <iostream>
#include <ranges>

int main() {
    auto even = [](int i) { return 0 == i % 2; };
    auto square = [](int i) { return i * i; };

    for (int i : std::views::iota(0, 6)
               | std::views::filter(even)
               | std::views::transform(square)) {
        std::cout << i << ' ';
    }
}

输出：

0 4 16

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | 若 Pred 非 default_initializable ， 则默认构造函数构造不含 Pred 的 filter_view | filter_view 亦非 default_initializable

参阅

ranges::take_while_viewviews::take_while
(C++20)
 由另一 view 的到首个谓词返回 false 为止的起始元素组成的 view
(类模板) (范围适配器对象)


std::ranges::filter_view<V,Pred>::iterator

< cpp‎ | ranges‎ | filter view
class /*iterator*/; // 仅用于阐释 | (C++20 起)

filter_view::begin 的返回类型。名称 iterator 仅用于阐释目的。

若 V 实现 bidirectional_range 则这是 bidirectional_iterator ，若 V 实现 forward_range 则这是 forward_iterator ，否则是 input_iterator 。

容许修改此迭代器所指向的元素，但若结果值不满足滤的谓词则导致未定义行为。

成员类型

成员类型 | 定义
iterator_concept
  • 若 V 实现 bidirectional_range 则为 std::bidirectional_iterator_tag ，
  • 若 V 实现 forward_iterator 则为 std::forward_iterator_tag ，
  • 否则为 std::input_iterator_tag 。
iterator_category

当且仅当 V 实现 forward_range 才定义。 令 C 为类型 std::iterator_traits <ranges::iterator_t<V>>​::​iterator_category 。

  • 若 C 实现 std::derived_from< std::bidirectional_iterator_tag > 则为 std::bidirectional_iterator_tag ，
  • 若 C 实现 std::forward_iterator_tag 则为 std::derived_from< std::forward_iterator_tag > ，
  • 否则为 C 。
value_type | ranges::range_value_t<V>
difference_type | ranges::range_difference_t<V>

数据成员

iterator 的典型实现保有二个非静态数据成员：

  • ranges::iterator_t<V> 类型迭代器，指向底层 view 中（此处示为 current_ ，仅为阐释），及
  • ranges::filter_view<V, Pred>* 指针，指向亲 filter_view 对象（此处示为 parent_ ，仅为阐释）。

成员函数

(构造函数) (C++20) | 构造迭代器 (公开成员函数)
base (C++20) | 返回底层迭代器 (公开成员函数)
operator*operator-> (C++20) | 转发到底层迭代器 (公开成员函数)
operator++operator++(int)operator--operator--(int) (C++20) | 推进或自减迭代器 (公开成员函数)

std::ranges::filter_view::iterator::iterator

/*iterator*/()
requires std::default_initializable<ranges::iterator_t<V>> = default;
 (1) (C++20 起)
constexpr /*iterator*/( filter_view& parent,
ranges::iterator_t<V> current );
 (2) (C++20 起)
1) 分别以其默认成员初始化器初始化 current_ 与 parent_ ，它们分别为 = ranges::iterator_t<V>() 与 = nullptr 。
2) 以 std​::​move(current) 初始化 current_ 并以 std::addressof (parent) 初始化 parent_ 。

std::ranges::filter_view::iterator::base

constexpr const ranges::iterator_t<V>& base() const & noexcept; | (1) | (C++20 起)
constexpr ranges::iterator_t<V> base() &&; | (2) | (C++20 起)
1) 等价于 return current_; 。
2) 等价于 return std​::​move(current_); 。

std::ranges::filter_view::iterator::operator*,->

constexpr ranges::range_reference_t<V> operator*() const;
 (1) (C++20 起)
constexpr ranges::iterator_t<V> operator->() const

requires /*has-arrow*/<ranges::iterator_t<V>> &&

std::copyable<ranges::iterator_t<V>>;
 (2) (C++20 起)
1) 等价于 return *current_; 。
2) 等价于 return current_; 。
对于 I ， /*has-arrow*/<I> 得到实现或满足，当且仅当 I 分别实现或满足 input_iterator ，并且 I 为指针类型或 requires(I i){ i.operator->(); } 为 true 。

std::ranges::filter_view::iterator::operator++

constexpr /*iterator*/& operator++(); | (1) | (C++20 起)
constexpr void operator++( int ); | (2) | (C++20 起)
constexpr /*iterator*/ operator++( int ) requires ranges::forward_range<V>; | (3) | (C++20 起)
1) 等价于
current_ = ranges::find_if(std::move(++current_), ranges::end(parent_->base_),

std::ref (*parent_->pred_));

return *this; 。
2) 等价于 ++*this; 。
3) 等价于 auto tmp = *this; ++*this; return tmp; 。

std::ranges::filter_view::iterator::operator--

constexpr /*iterator*/& operator--() requires ranges::bidirectional_range<V>; | (1) | (C++20 起)
constexpr /*iterator*/ operator--( int ) requires ranges::bidirectional_range<V>; | (2) | (C++20 起)
1) 等价于
do

--current_;
while (! std::invoke (*parent_->pred_, *current_));

return *this; 。
2) 等价于 auto tmp = *this; --*this; return tmp; 。

非成员函数

operator== (C++20) | 比较底层迭代器 (函数)
iter_move (C++20) | 将解引用底层迭代器的结果转型到其关联右值引用类型 (函数)
iter_swap (C++20) | 交换二个底层迭代器所指向的对象 (函数)

operator==(std::ranges::filter_view::iterator)

friend constexpr bool operator==( const /*iterator*/& x, const /*iterator*/& y ) requires std::equality_comparable<ranges::iterator_t<V>>; | (C++20 起)

等价于 return x.current_ == y.current_; 。

!= 运算符从 operator== 合成。

此函数对通常无限定或有限定查找不可见，而只能在 std::ranges::filter_view::iterator 为参数的关联类时由实参依赖查找找到。

iter_move(std::ranges::filter_view::iterator)

friend constexpr ranges::range_rvalue_reference_t<V>

iter_move( const /*iterator*/& i )

noexcept(noexcept(ranges::iter_move(i.current_)));
 (C++20 起)

等价于 return ranges​::​iter_move(i.current_);。

此函数对通常无限定或有限定查找不可见，而只能在 std::ranges::filter_view::iterator 为参数的关联类时由实参依赖查找找到。

iter_swap(std::ranges::filter_view::iterator)

friend constexpr void iter_swap( const /*iterator*/& x, const /*iterator*/& y )

noexcept(noexcept(ranges::iter_swap(x.current_, y.current_)))

requires std::indirectly_swappable<ranges::iterator_t<V>>;
 (C++20 起)

等价于 ranges​::​iter_swap(x.current_, y.current_) 。

此函数对通常无限定或有限定查找不可见，而只能在 std::ranges::filter_view::iterator 为参数的关联类时由实参依赖查找找到。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2259R1 | C++20 | 始终定义成员类型 iterator_category | 仅若 V 为 forward_range 才定义
LWG 3533 | C++20 | base 的 const& 重载复制底层迭代器 | 返回到它的引用
LWG 3593 | C++20 | base 的 const& 重载可能不是 noexcept | 使之为 noexcept


std::ranges::filter_view<V,Pred>::sentinel

< cpp‎ | ranges‎ | filter view
class /*sentinel*/; // 仅用于阐释 | (C++20 起)

底层 view 类型（V）不满足 common_range 时 filter_view::end 的返回类型。

名称 sentinel 仅用于阐释目的。

数据成员

sentinel 的典型实现仅保有一个非静态数据成员：底层 view 的哨位（此处示为 end_ ，仅用于阐释）。

成员函数

(构造函数) (C++20) | 构造哨位 (公开成员函数)
base (C++20) | 返回底层哨位 (公开成员函数)

std::ranges::filter_view::sentinel::sentinel

/*sentinel*/() = default; | (1) | (C++20 起)
constexpr explicit /*sentinel*/( filter_view& parent ); | (2) | (C++20 起)
1) 经由其默认成员初始化器（= ranges::sentinel_t<V>()）值初始化 end_ 。
2) 以 ranges​::​end(parent.base_) 初始化 end_ 。

std::ranges::filter_view::sentinel::base

constexpr ranges::sentinel_t<V> base() const; | (C++20 起)

等价于 return end_; 。

非成员函数

operator==
(C++20)
 比较底层迭代器与底层哨位
(函数)

operator==(std::ranges::filter_view::iterator, std::ranges::filter_view::sentinel)

friend constexpr bool operator==( const /*iterator*/& x, const /*sentinel*/& y ); | (C++20 起)

等价于 return x.current_ == y.end_; ，其中 current_ 为包装于 filter_view::iterator 的底层迭代器。

!= 运算符从 operator== 合成。

此函数对通常无限定或有限定查找不可见，而只能在 std::ranges::filter_view::sentinel 为参数的关联类时由实参依赖查找找到。


std::ranges::forward_range

< cpp‎ | ranges
定义于头文件 <ranges>
template<class T>

concept forward_range =

range::input_range<T> && std::forward_iterator<ranges::iterator_t<T>>;

forward_range 概念是 range 的细化，对于实现的类型， ranges::begin 返回 forward_iterator 的实现。


std::ranges::input_range

< cpp‎ | ranges
定义于头文件 <ranges>
template<class T>

concept input_range =

ranges::range<T> && std::input_iterator<ranges::iterator_t<T>>;

input_range 概念是 range 的细化，对于实现的类型， ranges::begin 返回 input_iterator 的实现。


std::ranges::views::iota, std::ranges::iota_view

< cpp‎ | ranges
定义于头文件 <ranges>
template<std::weakly_incrementable W,

std::semiregular Bound = std::unreachable_sentinel_t>
requires __WeaklyEqualityComparableWith<W, Bound> && std::copyable<W>

class iota_view : public ranges::view_interface<iota_view<W, Bound>>
 (1) (C++20 起)
namespace views {

inline constexpr /*unspecified*/ iota = /*unspecified*/;

}
 (2) (C++20 起)
1) 以重复自增初值生成序列的范围工厂。能为有界或无界（无限）。
2) views::iota(e) 与 views::iota(e, f) 对于适合的子表达式 e 和 f 分别表达式等价于 iota_view(e) 与 iota_view(e, f) 。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 views::iota 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __iota_fn 表示其类型的 cv 无限定版本。

__iota_fn 的所有实例均相等。在相同参数上调用类型 __iota_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 views::iota 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 views::iota 的参数要求，则 __iota_fn 实现 std::invocable<__iota_fn, Args...>、 std::invocable<const __iota_fn, Args...>、 std::invocable<__iota_fn&, Args...> 及 std::invocable<const __iota_fn&, Args...> 。否则， __iota_fn 的函数调用运算符不参与重载决议。

数据成员

iota_view 的典型实现保有二个非静态数据成员：类型为 W 的起始值 value_ 及类型为 Bound 的哨位值 bound_ 。此处显示的名字仅用于阐释。

成员函数

(构造函数)
(C++20)
 创建 iota_view
(公开成员函数)
begin
(C++20)
 获得 iota_view 的起始迭代器
(公开成员函数)
end
(C++20)
 获得指代 iota_view 末尾的哨位
(公开成员函数)
size
(C++20)
 若 iota_view 具有大小则获得其大小
(公开成员函数)
继承自 std::ranges::view_interface
empty
(C++20)
 返回视图是否为空。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator[]
(C++20)
 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

std::ranges::iota_view::iota_view

iota_view() requires std::default_initializable<W> = default;
 (1) (C++20 起)
constexpr explicit iota_view( W value );
 (2) (C++20 起)
constexpr iota_view( std::type_identity_t<W> value,
std::type_identity_t<Bound> bound );
 (3) (C++20 起)
constexpr iota_view( /*iterator*/ first, /*see below*/ last );
 (4) (C++20 起)
1) 由其默认成员初始化器（ = W() 与 = Bound() ）值初始化 value_ 与 bound_ 。
2) 以 value 初始化 value_ 。此构造函数用于创建无界 iota_view ，例如 iota(0) 产生数 0、 1、 2 ……无穷大。
3) 以 value 初始化 value_ 并以 bound 初始化 bound_ 。若 std::totally_ordered_with<W, Bound> 得到实现且 bool(value <= bound) 为 false 则行为未定义。此构造函数用于创建有界 iota_view ，例如 iota(10, 20) 产生从 10 到 19 的数。
4) 同 (3) ，除了以存储于 first 的 W 值初始化 value_ ，以及
  • 若 W 与 Bound 为同一类型，则 last 的类型为 /*iterator*/ 并且以存储于 last 的 W 值初始化 bound_ ，
  • 否则，若 iota_view 无界（即 Bound 为 std::unreachable_sentinel_t ），则 last 的类型为 std::unreachable_sentinel_t 并且以 std::unreachable_sentinel 初始化 bound_ 。
  • 否则 last 的类型为 /*sentinel*/ 并且以存储于 last 的 Bound 值初始化 bound_ 。
任何情况下， last 的类型均与 decltype(end()) 相同。

对于 (2)、 (3) 与 (4) ，若 iota_view 有界（即 Bound 不是 std::unreachable_sentinel_t ）且初始化 bound_ 为不可从 value_ 抵达的值，则行为未定义。

参数

value | - | 起始值
bound | - | 边界
first | - | 指代起始值的迭代器
last | - | 指代边界的哨位

std::ranges::iota_view::begin

constexpr /*iterator*/ begin() const; | (C++20 起)

返回以 value_ 初始化的迭代器。

std::ranges::iota_view::end

constexpr auto end() const; | (1) | (C++20 起)
constexpr /*iterator*/ end() const requires std::same_as<W, Bound>; | (2) | (C++20 起)
1) 若视图有界则返回以 bound_ 初始化的特定类型的哨位（此处显示为 /*sentinel*/ ），或若视图无界则返回 std::unreachable_sentinel 。
2) 返回以 bound_ 初始化的迭代器。

std::ranges::iota_view::size

constexpr auto size() const

requires (std::same_as<W, Bound> && /*advanceable*/<W>) ||
(std::integral<W> && std::integral<Bound>) ||
std::sized_sentinel_for<Bound, W>
{
if constexpr (/*is-integer-like*/<W> && /*is-integer-like*/<Bound>)
return (value_ < 0)
? ((bound_ < 0)
? /*to-unsigned-like*/(-value_) - /*to-unsigned-like*/(-bound_)
: /*to-unsigned-like*/(bound_) + /*to-unsigned-like*/(-value_))
: /*to-unsigned-like*/(bound_) - /*to-unsigned-like*/(value_);
else
return /*to-unsigned-like*/(bound_ - value_);

}
 (C++20 起)

若视图有界则返回视图的大小。

仅用于阐释的概念 advanceable 描述于此页面。

仅用于阐释的函数模板 to-unsigned-like 将其参数（必须为整数式）转换为参数类型的对应无符号版本。

推导指引

template<class W, class Bound>

requires (!/*is-integer-like*/<W> || !/*is-integer-like*/<Bound> ||
/*is-signed-integer-like*/<W> == /*is-signed-integer-like*/<Bound>)

iota_view(W, Bound) -> iota_view<W, Bound>;
 (C++20 起)

对于任何类型 T ， /*is-integer-like*/<T> 为 true 当且仅当 T 为整数式，而 /*is-integer-signed-like*/<T> 为 true 当且仅当它为整数式且能够表示负值。

注意推导指引自身抵御有符号/无符号不匹配漏洞，如 views::iota(0, v.size()) ，其中 ​0​ 为（有符号） int 而 v.size() 为（无符号） std::size_t 。

嵌套类

iterator (C++20) | 迭代器类型 (仅用于阐释的成员类)
sentinel (C++20) | 当 iota_view 有界且 Bound 与 W 不是同一类型时使用的哨位类型 (仅用于阐释的成员类)

辅助模板

template<std::weakly_incrementable W, std::semiregular Bound>
inline constexpr bool enable_borrowed_range<ranges::iota_view<W, Bound>> = true;
 (C++20 起)

std::ranges::enable_borrowed_range 的此特化使得 iota_view 满足 borrowed_range 。

示例

#include <ranges>
#include <iostream>

int main()
{
    for (int i : std::iota_view{1, 10})
        std::cout << i << ' ';
    std::cout << '\n';

    for (int i : std::views::iota(1, 10))
        std::cout << i << ' ';
    std::cout << '\n';

    for (int i : std::views::iota(1) | std::views::take(9))
        std::cout << i << ' ';
    std::cout << '\n';
}

输出：

1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3523 | C++20 | 迭代器-哨位对构造函数可能使用错误的哨位类型 | 已更正
P2325R3 | C++20 | iota_view 要求 W 为 semiregular 因为 view 要求 default_initializable | 仅要求 W 为 copyable

参阅

iota
(C++11)
 用从起始值开始连续递增的值填充一个范围
(函数模板)


std::ranges::iota_view<W, Bound>::iterator

< cpp‎ | ranges‎ | iota view
struct /*iterator*/;
 (1) (C++20 起)
辅助别名模板
template< class I >
using /*iota-diff-t*/ = /* see below */; // 仅用于阐释
 (2) (C++20 起)
辅助概念
template< class I >

concept /*decrementable*/ = // 仅用于阐释
std::incrementable<I> && requires(I i) {
{ --i } -> std::same_as<I&>;
{ i-- } -> std::same_as<I>;

};
 (3) (C++20 起)
template< class I >

concept /*advanceable*/ = // 仅用于阐释
/*decrementable*/<I> && std::totally_ordered<I> &&
requires(I i, const I j, const /*iota-diff-t*/<I> n) {
{ i += n } -> std::same_as<I&>;
{ i -= n } -> std::same_as<I&>;
I(j + n);
I(n + j);
I(j - n);
{ j - j } -> std::convertible_to</*iota-diff-t*/<I>>;

};
 (4) (C++20 起)
1) iota_view::begin 的返回类型。此类的名称（此处示为 /*iterator*/ ）是未指明的。
2) 仅用于阐释的别名模板 iota-diff-t 计算迭代器类型和整数式类型的差类型。
  • 若 W 不是整数类型，或若它是整数类型且 sizeof(std::iter_difference_t<I>) 大于 sizeof(I) ，则 /*iota-diff-t*/<I> 为 std::iter_difference_t<I> 。
  • 否则，若 /*iota-diff-t*/<I> 宽度大于 I 的有符号整数类型，若这种类型存在。
  • 否则， I 是最宽的整数类型之一，而 /*iota-diff-t*/<I> 是宽度不小于 I 的未指明的有符号整数式类型。此情况下不指定 /*iota-diff-t*/<I> 是否实现 weakly_incrementable 。
3) 仅用于阐释的概念 decrementable 指定类型为 incrementable ，而且该类型的前与后 operator-- 均拥有通常含义。
4) 仅用于阐释的概念 advanceable 指定类型为 decrementable 及 totally_ordered ，而且该类型与其差类型间的 operator+=、 operator-=、 operator+ 和 operator- 均拥有通常含义。

语义要求

3) 类型 I 实现 decrementable ，仅若 I 满足 decrementable 且所有其所蕴含的概念均得到实现，并且给定相等的 I 类型对象 a 与 b ：
  • 若 a 与 b 在前与后 operator-- 的定义域内（即它们可自减），则以下均为 true ：
    • std::addressof (--a) == std::addressof (a)、
    • bool(a-- == b)、
    • bool(((void)a--, a) == --b)、
    • bool(++(--a) == b) 。
  • 若 a 与 b 在前与后 operator++ 的定义域内（即它们可自增），则 bool(--(++a) == b) 为 true 。
4) 令 D 代表 /*iota-diff-t*/<I> 。类型 I 实现 advanceable 仅若 I 满足 advanceable 且所有其所蕴含均得到实现，并且给定
  • I 类型对象 a 与 b 及
  • D 类型值 n ，

使得 b 可在 n 次应用 ++a 后从 a 可达，下列所有条件都得到满足：

  • (a += n) 等于 b 。
  • std::addressof (a += n) 等于 std::addressof (a) 。
  • I(a + n) 等于 (a += n) 。
  • 对于二个 D 类型正值 x 与 y ，若 I(a + D(x + y)) 为良定义，则 I(a + D(x + y)) 等于 I(I(a + x) + y) 。
  • I(a + D(0)) 等于 a 。
  • 若 I(a + D(n - 1)) 为良定义，则 I(a + n) 等于 [](I c) { return ++c; }(I(a + D(n - 1))) 。
  • (b += -n) 等于 a 。
  • (b -= n) 等于 a 。
  • std::addressof (b -= n) 等于 std::addressof (b) 。
  • I(b - n) 等于 (b -= n) 。
  • D(b - a) 等于 n 。
  • D(a - b) 等于 D(-n) 。
  • bool(a <= b) 为 true 。

成员类型

成员类型 | 定义
iterator_concept 若 W 实现 advanceable 则为 std::random_access_iterator_tag 。
否则若 W 实现 decrementable 则为 std::bidirectional_iterator_tag 。
否则若 W 实现 incrementable 则为 std::forward_iterator_tag 。
否则为 std::input_iterator_tag 。
iterator_category 若 W 实现 incrementable 则为 std::input_iterator_tag 。
否则无成员类型 iterator_category 。
value_type | W
difference_type | /*iota-diff-t*/<W>

注意： /*iterator*/ 是

  • random_access_iterator ，若 W 实现 advanceable ，
  • bidirectional_iterator ，若 W 实现 decrementable ，
  • forward_iterator ，若 W 实现 incrementable ，
  • 否则为 input_iterator 。

然而，若 W 实现 incrementable 则它仅满足老式输入迭代器 (LegacyInputIterator) ，否则不满足老式输入迭代器 (LegacyInputIterator) 。

数据成员

此迭代器类型的典型实现仅保有一个 W 类型的数据成员（此处示为 value_ ）：用于解引用的值。

成员函数

std::ranges::iota_view::iterator::iterator

/*iterator*/() requires std::default_initializable<W> = default; | (1) | (C++20 起)
constexpr explicit /*iterator*/( W value ); | (2) | (C++20 起)
1) 经由其默认成员初始化器（ = W() ）值初始化仅用于阐释的数据成员 value_ 。
2) 以 value 初始化仅用于阐释的数据成员 value_ 。此值将由 operator* 返回，并为 operator++ 所自增。

std::ranges::iota_view::iterator::operator*

constexpr W operator*() const noexcept( std::is_nothrow_copy_constructible_v <W>); | (C++20 起)

按值返回当前值（换言之，这是只读视图）。

std::ranges::iota_view::iterator::operator++

constexpr /*iterator*/& operator++() | (1) | (C++20 起)
constexpr void operator++(int) | (2) | (C++20 起)
constexpr /*iterator*/ operator++(int) requires std::incrementable<W>; | (3) | (C++20 起)
1) 等价于 ++value_; return *this; 。
2) 等价于 ++value_; 。
3) 等价于 auto tmp = *this; ++value_; return tmp; 。

std::ranges::iota_view::iterator::operator--

constexpr /*iterator*/& operator--() requires /*decrementable*/<W>; | (1) | (C++20 起)
constexpr /*iterator*/operator--(int) requires /*decrementable*/<W>; | (2) | (C++20 起)
1) 等价于 --value_; return *this; 。
2) 等价于 auto tmp = *this; --value_; return tmp; 。

std::ranges::iota_view::iterator::operator+=

constexpr /*iterator*/& operator+=( difference_type n )
requires /*advanceable*/<W>;
 (C++20 起)

若 W 为无符号整式，则在 n 非负时进行 value_ += static_cast<W>(n) ，否则进行 value -= static_cast<W>(-n) ，然后返回 *this 。

否则等价于 value_ += n; return *this; 。

std::ranges::iota_view::iterator::operator-=

constexpr /*iterator*/& operator-=( difference_type n )
requires /*advanceable*/<W>;
 (C++20 起)

若 W 为无符号整式，则在 n 非负时进行 value_ -= static_cast<W>(n) ，否则进行 value += static_cast<W>(-n) ，然后返回 *this 。

否则等价于 value_ -= n; return *this; 。

std::ranges::iota_view::iterator::operator[]

constexpr W operator[]( difference_type n ) const requires /*advanceable*/<W>; | (C++20 起)

等价于 return W(value_ + n); 。

非成员函数

operator==, <, >, <=, >=, <=>(std::ranges::iota_view::iterator)

friend constexpr bool operator== (const /*iterator*/& x, const /*iterator*/& y) requires std::equality_comparable<W>; | (1) | (C++20 起)
friend constexpr bool operator< (const /*iterator*/& x, const /*iterator*/& y) requires std::totally_ordered<W>; | (2) | (C++20 起)
friend constexpr bool operator> (const /*iterator*/& x, const /*iterator*/& y) requires std::totally_ordered<W>; | (3) | (C++20 起)
friend constexpr bool operator<= (const /*iterator*/& x, const /*iterator*/& y) requires std::totally_ordered<W>; | (4) | (C++20 起)
friend constexpr bool operator>= (const /*iterator*/& x, const /*iterator*/& y) requires std::totally_ordered<W>; | (5) | (C++20 起)
friend constexpr bool operator<=>(const /*iterator*/& x, const /*iterator*/& y) requires std::totally_ordered<W> && std::three_way_comparable<W>; | (6) | (C++20 起)
1) 等价于 return x.value_ == y.value_; 。
2) 等价于 return x.value_ < y.value_; 。
3) 等价于 return y < x; 。
4) 等价于 return !(y < x); 。
5) 等价于 return !(x < y); 。
6) 等价于 return x.value_ <=> y.value_;。

!= 运算符从 operator== 合成。

这些函数对通常无限定或有限定查找不可见，而只能在 iterator 为参数的关联类时由实参依赖查找找到。

operator+(std::ranges::iota_view::iterator)

friend constexpr /*iterator*/ operator+( /*iterator*/ i, difference_type n ) requires /*advanceable*/<W>; | (1) | (C++20 起)
friend constexpr /*iterator*/ operator+( difference_type n, /*iterator*/ i ) requires /*advanceable*/<W>; | (2) | (C++20 起)

等价于 i += n; return i; 。

这些函数对通常无限定或有限定查找不可见，而只能在 iterator 为参数的关联类时由实参依赖查找找到。

operator-(std::ranges::iota_view::iterator)

friend constexpr /*iterator*/ operator-( /*iterator*/ i, difference_type n ) requires /*advanceable*/<W>; | (1) | (C++20 起)
friend constexpr difference_type operator-( const /*iterator*/& x, const /*iterator*/& y ) requires /*advanceable*/<W>; | (2) | (C++20 起)
1) 等价于 i -= n; return i; 。
2) 令 D 为 difference_type 。
  • 若 W 为有符号整数式，等价于 return D(D(x.value_) - D(y.value_)); 。
  • 否则若 W 为无符号整数式，等价于 return y.value_ > x.value_ ? D(-D(y.value_ - x.value_)) : D(x.value_ - y.value_); 。
  • 否则等价于 return x.value_ - y.value_; 。

这些函数对通常无限定或有限定查找不可见，而只能在 iterator 为参数的关联类时由实参依赖查找找到。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2259R1 | C++20 | 始终定义成员 iterator_category | 仅若 W 满足 incrementable 才定义
LWG 3580 | C++20 | operator+ 与 operator- 复制迭代器 | 使之移动迭代器


std::ranges::iota_view<W, Bound>::sentinel

< cpp‎ | ranges‎ | iota view
struct /*sentinel*/; | (C++20 起)

iota_view::end 的返回类型，在 iota_view 有界（即 Bound 不是 std::unreachable_sentinel_t ）且 Bound 与 W 不是同一类型时使用。

此类的名字（此处示作 /*sentinel*/）是未指定的。

典型实现保有一个 Bound 类型的数据成员（此处示作 bound_），对于有界 iota_view 常为数。

成员函数

std::ranges::iota_view::sentinel::sentinel

/*sentinel*/() = default; | (1) | (C++20 起)
constexpr explicit /*sentinel*/( Bound bound ); | (2) | (C++20 起)
1) 通过其默认成员初始化器（ = Bound() ）值初始化 bound_ 。
2) 以 bound 初始化仅用于阐释的数据成员 bound_ 。

非成员函数

在下列描述中， value_ 是 iterator 的仅用于阐释的数据成员，其 operator* 从该成员复制。

operator==(std::ranges::iota_view::iterator, std::ranges::iota_view::sentinel)

friend constexpr bool operator==( const /*iterator*/& x, const /*sentinel*/& y); | (C++20 起)

等价于 return x.value_ == y.bound_; 。

!= 运算符从 operator== 合成。

此函数对通常无限定或有限定查找不可见，而只能在 sentinel 为参数的关联类时由实参依赖查找找到。

operator-(std::ranges::iota_view::iterator, std::ranges::iota_view::sentinel)

friend constexpr std::iter_difference_t<W>

operator-(const /*iterator*/& x, const /*sentinel*/& y)

requires std::sized_sentinel_for<Bound, W>;
 (1) (C++20 起)
friend constexpr std::iter_difference_t<W>

operator-(const /*sentinel*/& x, const /*iterator*/& y)

requires std::sized_sentinel_for<Bound, W>;
 (2) (C++20 起)
1) 等价于 return x.value_ - y.bound_; 。
2) 等价于 return -(y.value_ - x.bound_); 。

这些函数对通常无限定或有限定查找不可见，而只能在 sentinel 为参数的关联类时由实参依赖查找找到。


std::ranges::iterator_t, std::ranges::sentinel_t, std::ranges::range_size_t, std::ranges::range_difference_t, std::ranges::range_value_t, std::ranges::range_reference_t, std::ranges::range_rvalue_reference_t

< cpp‎ | ranges
定义于头文件 <ranges>
template <class T>
using iterator_t = decltype(ranges::begin( std::declval <T&>()));
 (1) (C++20 起)
template <ranges::range R>
using sentinel_t = decltype(ranges::end( std::declval <R&>()));
 (2) (C++20 起)
template <ranges::sized_range R>
using range_size_t = decltype(ranges::size( std::declval <R&>()));
 (3) (C++20 起)
template <ranges::range R>
using range_difference_t = std::iter_difference_t<ranges::iterator_t<R>>;
 (4) (C++20 起)
template <ranges::range R>
using range_value_t = std::iter_value_t<ranges::iterator_t<R>>;
 (5) (C++20 起)
template <ranges::range R>
using range_reference_t = std::iter_reference_t<ranges::iterator_t<R>>;
 (6) (C++20 起)
template <ranges::range R>

using range_rvalue_reference_t =

std::iter_rvalue_reference_t<ranges::iterator_t<R>>;
 (7) (C++20 起)
1) 用于获得 T 的迭代器类型。
2) 用于获得 range 类型 R 的哨位类型。
3) 用于获得 sized_range 类型 R 的大小类型。
4) 用于获得范围类型 R 的迭代器类型的差类型。
5) 用于获得范围类型 R 的迭代器类型的值类型。
6) 用于获得范围类型 R 的迭代器类型的引用类型。
7) 用于获得范围类型 R 的迭代器类型的右值引用类型。

模板形参

T | - | 能用于 std::ranges::begin 的类型
R | - | range 类型或 sized_range 类型

注解

iterator_t 能应用到非范围类型，例如未知边界数组。

参阅

iter_value_titer_reference_titer_difference_titer_rvalue_reference_titer_common_reference_t
(C++20)(C++20)(C++20)(C++20)(C++20)
 计算迭代器的关联类型
(别名模板)


std::ranges::views::join, std::ranges::join_view

< cpp‎ | ranges
定义于头文件 <ranges>
template< ranges::input_range V >

requires ranges::view<V> && ranges::input_range<ranges::range_reference_t<V>>

class join_view : public ranges::view_interface<join_view<V>>
 (1) (C++20 起)
namespace views {

inline constexpr /* unspecified */ join = /* unspecified */;

}
 (2) (C++20 起)
1) 表示由从拉平范围的视图获得的序列组成的 view 。
2) 范围适配器对象。对于任何适合的子表达式 e 表达式 views::join(e) 表达式等价于 join_view<views::all_t<decltype((e))>>{e} 。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

成员函数

(构造函数)
(C++20)
 构造 join_view
(公开成员函数)
base
(C++20)
 返回底层（适配的）视图的副本
(公开成员函数)
begin
(C++20)
 返回指向起始的迭代器
(公开成员函数)
end
(C++20)
 返回指向末尾的迭代器或哨位
(公开成员函数)
继承自 std::ranges::view_interface
empty
(C++20)
 返回视图是否为空。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

推导指引

嵌套类

iterator (C++20) | 迭代器类型 (仅用于阐释的成员类模板)
sentinel (C++20) | 哨位类型 (仅用于阐释的成员类模板)

注解

在接纳 P2328R1 前，内层范围类型（ ranges::range_reference_t<V> ）不能为容器类型（但能为容器的引用）。例如不允许接合 std::string 纯右值的 transform_view 。

struct Person { int age; std::string name; };
auto f(std::vector<Person>& v) {
 // return v | std::views::transform([](auto& p) { return p.name; })
 //          | std::views::join; // P2328R1 前错误
    return v | std::views::transform([](auto& p) -> std::string& { return p.name; })
             | std::views::join; // OK
}

示例

#include <iostream>
#include <ranges>
#include <string_view>
#include <vector>

int main()
{
    using namespace std::literals;
    const auto bits = { "https:"sv, "//"sv, "cppreference"sv, "."sv, "com"sv };
    for (char const c : bits | std::views::join) std::cout << c;
    std::cout << '\n';

    const std::vector<std::vector<int>> v{ {1,2}, {3,4,5}, {6}, {7,8,9} };
    auto jv = std::ranges::join_view(v);
    for (int const e : jv) std::cout << e << ' ';
    std::cout << '\n';
}

输出：

https://cppreference.com
1 2 3 4 5 6 7 8 9

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3474 | C++20 | views::join(e) 在 e 为 join_view 时返回 e 的副本 | 返回嵌套的 join_view
P2328R1 | C++20 | join_view 无法接合非视图 range 纯右值 | 使得可接合

参阅

ranges::split_viewviews::split (C++20) | 用某个分隔符切割另一 view 所获得的子范围的 view (类模板) (范围适配器对象)
ranges::lazy_split_viewviews::lazy_split (C++20) | 用某个分隔符切割另一 view 所获得的子范围的 view (类模板) (范围适配器对象)


std::ranges::join_view<V>::begin

< cpp‎ | ranges‎ | join view
constexpr auto begin();
 (1) (C++20 起)
constexpr auto begin() const

requires ranges::input_range<const V> &&

std::is_reference_v <ranges::range_reference_t<const V>>;
 (2) (C++20 起)

返回指向 join_view 首元素的迭代器。给定 base_ 为底层视图，

1) 若 __SimpleView<V> 得到满足且 ranges::range_reference_t<V> 为引用类型则等价于 return /*iterator*/<true>{*this, ranges::begin(base_)}; 。否则等价于 return /*iterator*/<false>{*this, ranges::begin(base_)}; 。
2) 等价于 return /*iterator*/<true>{*this, ranges::begin(base_)}; 。

参数

（无）

返回值

到首元素的引用。

注解

在 ranges::range_reference_t<V> 不是引用类型，即解引用 V 的迭代器返回纯右值临时量时， join_view 仅为 input_range ，此情况下仅支持单趟迭代，而重复调用 begin() 可能不给出有意义的结果。

示例

本节未完成
原因：暂无示例

参阅

end (C++20) | 返回指向末尾的迭代器或哨位 (公开成员函数)
ranges::begin (C++20) | 返回指向范围起始的迭代器 (定制点对象)


std::ranges::join_view<V>::join_view

< cpp‎ | ranges‎ | join view
join_view() requires std::default_initializable<V> = default; | (1) | (C++20 起)
constexpr explicit join_view( V base ); | (2) | (C++20 起)

构造 join_view 。

1) 默认构造函数。值初始化底层视图。构造后 base() 返回 V() 的副本。
2) 以 std::move(base) 初始化底层视图。

参数

base - 要打平的范围的视图

示例

本节未完成
原因：暂无示例


std::ranges::views::keys, std::ranges::keys_view

< cpp‎ | ranges
定义于头文件 <ranges>
template<class R>
using keys_view = ranges::elements_view<R, 0>;
 (1) (C++20 起)
namespace views {

inline constexpr auto keys = ranges::elements<0>;

}
 (2) (C++20 起)

接收元组式值（例如 std::tuple 或 std::pair ）的 view ，并产生值类型为被适配的视图的值的第一个元素的视图。

1) ranges::elements_view<R, 0> 的别名。
2) 范围适配器对象。表达式 views​::keys(e) 表达式对任何适合的子表达式 e 表达式等价于 keys_view<views​::​all_t<decltype((e))>>{e} 。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

注解

keys_view 能用于从关联容器提取键，例如 for (auto const& key : std::views::keys(map)) { /*...*/ } 。

示例

#include <iomanip>
#include <iostream>
#include <ranges>
#include <utility>
#include <vector>

int main()
{
    const std::vector<std::pair<std::string, double>> quark_mass{ // MeV/c²
        {"up", 2.3},      {"down", 4.8},
        {"charm", 1275},  {"strange", 95},
        {"top", 173'210}, {"bottom", 4'180},
    };

    std::cout << "quark name:  │ ";
    for (std::string const& name : std::views::keys(quark_mass))
        std::cout << std::setw(9) << name << " │ ";

    std::cout << "\n" "mass MeV/c²: │ ";
    for (const double mass : std::views::values(quark_mass))
        std::cout << std::setw(9) << mass << " │ ";
    std::cout << '\n';
}

输出：

quark name:  │        up │      down │     charm │   strange │       top │    bottom │
mass MeV/c²: │       2.3 │       4.8 │      1275 │        95 │    173210 │      4180 │

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3563 | C++20 | keys_view 由于使用 views::all_t 无法参与 CTAD | 移除 views::all_t

参阅

ranges::values_viewviews::values (C++20) | 选取 pair 式值组成的 view 并产生每个 pair 的第二元素的 view (类模板) (范围适配器对象)
ranges::elements_viewviews::elements (C++20) | 选取元组式值组成的 view 和数值 N ，产生每个 tuple 的第 N 个元素的 view (类模板) (范围适配器对象)
slice | valarray 的 BLAS 式切片：起始下标、长度、跨度 (类)


std::ranges::output_range

< cpp‎ | ranges
定义于头文件 <ranges>
template<class R, class T>

concept output_range =

ranges::range<R> && std::output_iterator<ranges::iterator_t<R>, T>;

output_range 概念是 range 的细化，对于实现的类型， ranges::begin 返回 output_iterator 的实现。


std::ranges::owning_view

< cpp‎ | ranges
定义于头文件 <ranges>
template<ranges::range R>

requires std::movable<R> && (!/*is-initializer-list*/<R>)

class owning_view : public ranges::view_interface<owning_view<R>>
 (C++20 起)

owning_view 是拥有 range 的独占所有权的 view 。它为仅移动并在其内部存储该 range 。

requires 子句中的 /*is-initializer-list*/<R> 为 true 当且仅当 std::remove_cvref_t<R> 为 std::initializer_list 的特化。

数据成员

owning_view 的典型实现仅拥有一个非静态数据成员： R 类型的底层范围。此处显示该成员为 r_ （名字仅用于阐释）。

成员函数

(构造函数)
(C++20)
 通过值初始化或移动构造存储的范围构造 owning_view
(公开成员函数)
operator=
(C++20)
 移动赋值存储的范围
(公开成员函数)
base
(C++20)
 返回到存储的范围的引用
(公开成员函数)
begin
(C++20)
 返回存储的范围的起始迭代器
(公开成员函数)
end
(C++20)
 返回存储的范围的哨位
(公开成员函数)
empty
(C++20)
 检查存储的范围是否为空
(公开成员函数)
size
(C++20)
 返回存储的 sized_range 的大小
(公开成员函数)
data
(C++20)
 返回指向存储的 contiguous_range 起始的指针
(公开成员函数)
继承自 std::ranges::view_interface
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator[]
(C++20)
 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

std::ranges::owning_view::owning_view

owning_view() requires std::default_initializable<R> = default; | (1) | (C++20 起)
owning_view( owning_view&& other ) = default; | (2) | (C++20 起)
constexpr owning_view( R&& t ); | (3) | (C++20 起)
owning_view( const owning_view& ) = delete; | (4) | (C++20 起)
1) 默认构造函数。由其默认成员初始化器（= R()）值初始化存储的范围。
2) 复制构造函数。从 other 的存储范围移动构造存储范围。
3) 从 t 移动构造存储范围。
4) 复制构造函数被删除。 owning_view 为仅移动。

参数

other | - | 要移动的 owning_view
t | - | 要移动的范围

std::ranges::owning_view::operator=

owning_view& opeartor=( owning_view&& other ) = default; | (1) | (C++20 起)
owning_view& operator=( const owning_view& ) = delete; | (2) | (C++20 起)
1) 移动赋值运算符。从 other 的存储范围移动赋值存储范围。
2) 复制赋值运算符被删除。 owning_view 为仅移动。

参数

other - 要移动的另一 owning_view

返回值

*this 。

std::ranges::owning_view::base

constexpr R& base() & noexcept; | (1) | (C++20 起)
constexpr const R& base() const & noexcept; | (2) | (C++20 起)
constexpr R&& base() && noexcept; | (3) | (C++20 起)
constexpr const R&& base() const && noexcept; | (4) | (C++20 起)

返回到存储的范围的引用，保持值类别与 const 限定。

1-2) 等价于 return r_; 。
3-4) 等价于 return std::move(r_); 。

std::ranges::owning_view::begin

constexpr ranges::iterator_t<R> begin(); | (1) | (C++20 起)
constexpr auto begin() const requires ranges::range<const R>; | (2) | (C++20 起)

等价于 return ranges::begin(r_); 。

std::ranges::owning_view::end

constexpr ranges::sentinel_t<R> end(); | (1) | (C++20 起)
constexpr auto end() const requires ranges::range<const R>; | (2) | (C++20 起)

等价于 return ranges::end(r_); 。

std::ranges::owning_view::empty

constexpr bool empty() requires requires { ranges::empty(r_); }; | (1) | (C++20 起)
constexpr bool empty() const requires requires { ranges::empty(r_); }; | (2) | (C++20 起)

等价于 return ranges::empty(r_); 。

std::ranges::owning_view::size

constexpr auto size() requires ranges::sized_range<R>; | (1) | (C++20 起)
constexpr auto size() const requires ranges::sized_range<const R>; | (2) | (C++20 起)

等价于 return ranges::size(r_); 。

std::ranges::owning_view::data

constexpr auto data() requires ranges::contiguous_range<R>; | (1) | (C++20 起)
constexpr auto data() const requires ranges::contiguous_range<const R>; | (2) | (C++20 起)

等价于 return ranges::data(r_); 。

辅助模板

template<class T>

inline constexpr bool enable_borrowed_range<std::ranges::owning_view<T>> =

std::ranges::enable_borrowed_range<T>;
 (C++20 起)

std::ranges::enable_borrowed_range 的此特化使得 owning_view 在底层范围满足 borrowed_range 时满足它。

示例

#include <ranges>
#include <string>
#include <cassert>
#include <iostream>

int main()
{
    using namespace std::literals;
    std::ranges::owning_view ov{ "cosmos"s }; // 推导的 R 类型为 std::string ；
                                              // `ov` 为此字符串的唯一所有者
    std::cout
        << std::boolalpha
        << "call empty() : " << ov.empty() << '\n'
        << "call size()  : " << ov.size() << '\n'
        << "call front() : " << ov.front() << '\n' // 同 *(ov.begin())
        << "call back()  : " << ov.back() << '\n' // 等于 *(ov.end()-1)
        << "call data()  : " << ov.data() << '\n'
        << "call base()  : " << ov.base().size() << '\n' // ~> ov.size()
        << "sizeof(ov)   : " << sizeof(ov) << '\n' // 常等于 sizeof(R)
        << "range-for    : \"";

    for (const char c: ov)
        std::cout << c;
    std::cout << "\"\n";

    std::ranges::owning_view<std::string> ov2;
    assert(ov2.empty());
//  ov2 = ov; // 编译时错误：复制赋值运算符被删除
    ov2 = std::move(ov); // OK
    assert(ov.empty());
    assert(ov2.size() == 6);
}

可能的输出：

call empty() : false
call size()  : 6
call front() : c
call back()  : s
call data()  : cosmos
call base()  : 6
sizeof(ov)   : 32
range-for    : "cosmos"

参阅

ranges::ref_view (C++20) | 某个其他 range 的元素的 view (类模板)
views::all_tviews::all (C++20) | 包含 range 的所有元素的 view (别名模板) (范围适配器对象)


std::ranges::random_access_range

< cpp‎ | ranges
定义于头文件 <ranges>
template<class T>

concept random_access_range =

ranges::bidirectional_range<T> && std::random_access_iterator<ranges::iterator_t<T>>;

random_access_range 概念是 range 的细化，对于实现的类型， ranges::begin 返回 random_access_iterator 的实现。


std::ranges::range

< cpp‎ | ranges
定义于头文件 <ranges>
template< class T >

concept range = requires(T& t) {
ranges::begin(t); // 对向前迭代器保持相等性
ranges::end (t);

};
 (C++20 起)

range 概念定义允许通过指代元素范围的迭代器和哨位，在其元素上迭代的类型。

语义要求

给定满足 decltype((E)) 为 T 的表达式 E ， T 实现 range 仅若：

  • [ranges::begin(E), ranges::end(E)) 代表范围，且
  • ranges::begin(E) 与 ranges::end(E) 均有均摊常量时间复杂度且不会以对于保持相等性的表达式可观察的方式更改 E 的值，且
  • 若 ranges::begin(E) 的类型实现 forward_iterator ，则 ranges::begin(E) 保持相等性（换言之，向前迭代器支持多趟算法）

注意：在上述定义中，要求的表达式 ranges::begin( std::forward <T>(t)) 与 ranges::end( std::forward <T>(t)) 不要求隐式表达式变种。


std::ranges::rbegin

< cpp‎ | ranges
定义于头文件 <ranges>
inline namespace /*unspecified*/ {

inline constexpr /*unspecified*/ rbegin = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T >

requires /* see below */

constexpr std::input_or_output_iterator auto rbegin(T&& t);

返回指向实参末元素的迭代器。

令 t 为 T 类型对象。若实参为左值或 ranges::enable_borrowed_range< std::remove_cv_t <T>> 为 true ，则对 ranges::rbegin 的调用表达式等价于：

  1. std::forward <T>(t).rbegin() 转换到其衰变类型，若该带转换的表达式合法且其转换后的类型实现 std::input_or_output_iterator 。
  2. 否则为 rbegin( std::forward <T>(t)) 转换到其衰变类型，若 T 为类或枚举类型，带转换的前述无限定调用合法，且其转换后的类型实现 std::input_or_output_iterator ，其中以下列候选进行重载决议：
    • void rbegin(auto&) = delete;
    • void rbegin(const auto&) = delete;
    • 实参依赖查找所找到的任何 rbegin 声明。
  3. 否则为 std::make_reverse_iterator (ranges::end( std::forward <T>(t))) ，若 ranges::begin( std::forward <T>(t)) 与 ranges::end( std::forward <T>(t)) 均为合法表达式，拥有同一类型，且该类型实现 std::bidirectional_iterator 。

所有其他情况下，调用 ranges::rbegin 为非良构，这能在 ranges::rbegin(t) 出现于模板实例化的立即语境时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::rbegin 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __rbegin_fn 表示其类型的 cv 无限定版本。

__rbegin_fn 的所有实例均相等。在相同参数上调用类型 __rbegin_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::rbegin 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::rbegin 的参数要求，则 __rbegin_fn 实现 std::invocable<__rbegin_fn, Args...>、 std::invocable<const __rbegin_fn, Args...>、 std::invocable<__rbegin_fn&, Args...> 及 std::invocable<const __rbegin_fn&, Args...> 。否则， __rbegin_fn 的函数调用运算符不参与重载决议。

注解

若实参为右值（即 T 为对象类型）且 ranges::enable_borrowed_range< std::remove_cv_t <T>> 为 false ，则调用 ranges::rbegin 非良构，这亦导致替换失败。

返回类型在所有情况下实现 std::input_or_output_iterator 。

C++20 标准要求若底层 rbegin 函数调用返回纯右值，则从实质化的临时对象移动构造返回值。所有实现均直接返回纯右值。 C++20 后的提案 P0849R8 更正了该要求以匹配实现。

示例

#include <iostream>
#include <vector>
#include <ranges>
#include <span>

int main()
{
    std::vector<int> v = { 3, 1, 4 };
    auto vi = std::ranges::rbegin(v);
    std::cout << *vi << '\n';
    *vi = 42; // OK

    int a[] = { -5, 10, 15 };
    auto ai = std::ranges::rbegin(a);
    std::cout << *ai << '\n';
    *ai = 42; // OK

    // auto x_x = std::ranges::rbegin(std::vector{6,6,6});
    // 非良构：实参为右值（见注解 ↑）

    auto si = std::ranges::rbegin(std::span{a}); // OK ：
    static_assert(std::ranges::enable_borrowed_range<
        std::remove_cv_t<decltype(std::span{a})>>);
    *si = 42; // OK
}

输出：

4
15

参阅

ranges::crbegin (C++20) | 返回指向只读范围的逆向迭代器 (定制点对象)
rbegincrbegin (C++14) | 返回指向一个容器或数组的逆向迭代器 (函数模板)


std::ranges::ref_view

< cpp‎ | ranges
定义于头文件 <ranges>
template<ranges::range R>

requires std::is_object_v <R>

class ref_view : public ranges::view_interface<ref_view<R>>
 (C++20 起)

ref_view 是某个其他 range 的元素的 view 。它包装到该 range 的引用。

数据成员

ref_view 表现如同它仅存储一个指向被引用范围的 R* 成员子对象。此处显示该成员为 r_ （名称仅用于阐释）。

成员函数

(构造函数)
(C++20)
 构造引用给定范围的 ref_view
(公开成员函数)
base
(C++20)
 返回到被引用范围的引用
(公开成员函数)
begin
(C++20)
 返回被引用范围的起始迭代器
(公开成员函数)
end
(C++20)
 返回被引用范围的哨位
(公开成员函数)
empty
(C++20)
 检查被引用范围是否为空
(公开成员函数)
size
(C++20)
 返回被引用 sized_range 的大小
(公开成员函数)
data
(C++20)
 返回指向被引用 contiguous_range 起始的指针
(公开成员函数)
继承自 std::ranges::view_interface
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator[]
(C++20)
 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

std::ranges::ref_view::ref_view

template</*different-from*/<ref_view> T>

requires std::convertible_to<T, R&> && requires { _FUN( std::declval <T>()); }

constexpr ref_view(T&& t);
 (C++20 起)

以 std::addressof (static_cast<R&>( std::forward <T>(t))) 初始化 r_ 。

/*different-from*/<T, U> 当且仅当 std::remove_cvref_t<T> 与 std::remove_cvref_t<U>> 不是同一类型才得到满足，而 _FUN 的重载声明为 void _FUN(R&); void _FUN(R&&) = delete; 。

参数

t - 要引用的范围

std::ranges::rev_view::base

constexpr R& base() const; | (C++20 起)

等价于 return *r_;

std::ranges::ref_view::begin

constexpr ranges::iterator_t<R> begin() const; | (C++20 起)

等价于 return ranges::begin(*r_);

std::ranges::ref_view::end

constexpr ranges::sentinel_t<R> end() const; | (C++20 起)

等价于 return ranges::end(*r_);

std::ranges::ref_view::empty

constexpr bool empty() const
requires requires { ranges::empty(*r_); };
 (C++20 起)

等价于 return ranges::empty(*r_);

std::ranges::ref_view::size

constexpr auto size() const

requires ranges::sized_range<R>

{ return ranges::size(*r_); }
 (C++20 起)

std::ranges::ref_view::data

constexpr auto data() const

requires ranges::contiguous_range<R>

{ return ranges::data(*r_); }
 (C++20 起)

推导指引

template<class R> ref_view(R&) -> ref_view<R>; | (C++20 起)

辅助模板

template<class T> inline constexpr bool enable_borrowed_range<ranges::ref_view<T>> = true; | (C++20 起)

std::ranges::enable_borrowed_range 的此特化使得 ref_view 满足 borrowed_range 。

示例

#include <ranges>
#include <iostream>

int main()
{
    const std::string s{"cosmos"};

    const std::ranges::take_view tv{s, 3};
    const std::ranges::ref_view rv{tv};

    std::cout
        << std::boolalpha
        << "call empty() : " << rv.empty() << '\n'
        << "call size()  : " << rv.size() << '\n'
        << "call begin() : " << *rv.begin() << '\n'
        << "call end()   : " << *(rv.end()-1) << '\n'
        << "call data()  : " << rv.data() << '\n'
        << "call base()  : " << rv.base().size() << '\n' // ~> tv.size()
        << "range-for    : ";

    for (const auto c: rv) { std::cout << c; }
    std::cout << '\n';
}

输出：

call empty() : false
call size()  : 3
call begin() : c
call end()   : s
call data()  : cosmos
call base()  : 3
range-for    : cos

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | 由于 view 必须为 default_initializable 提供了默认构造函数 | 与该要求一同移除

参阅

reference_wrapper (C++11) | 可复制构造 (CopyConstructible) 且可复制赋值 (CopyAssignable) 的引用包装器 (类模板)
ranges::owning_view (C++20) | 拥有某 range 的独占所有权的 view (类模板)
views::all_tviews::all (C++20) | 包含 range 的所有元素的 view (别名模板) (范围适配器对象)


std::ranges::rend

< cpp‎ | ranges
定义于头文件 <ranges>
inline namespace /*unspecified*/ {

inline constexpr /*unspecified*/ rend = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T >

requires /* see below */

constexpr std::sentinel_for<decltype(ranges::rbegin( std::declval <T>()))> auto rend(T&& t);

获得指示逆向范围末尾的迭代器。

令 t 为 T 类型对象。若实参为左值或 ranges::enable_borrowed_range< std::remove_cv_t <T>> 为 true ，则对 ranges::rend 的调用表达式等价于：

  1. std::forward <T>(t).rend() 转换到其衰变类型，若该带转换的表达式合法，且其转换后的类型实现 std::sentinel_for<decltype(ranges::rbegin( std::declval <T>()))> 。
  2. 否则为 rend( std::forward <T>(t)) 转换到其衰变类型，若 T 为类或枚举类型，带转换的前述无限定调用合法，且其转换后的类型实现 std::sentinel_for<decltype(ranges::rbegin( std::declval <T>()))> ，其中以下列候选进行重载决议：
    • void rend(auto&) = delete;
    • void rend(const auto&) = delete;
    • 实参依赖查找所找到的任何 rend 声明。
  3. 否则为 std::make_reverse_iterator (ranges::begin( std::forward <T>(t))) ，若 ranges::begin( std::forward <T>(t)) 与 ranges::end( std::forward <T>(t)) 均为合法表达式，拥有相同类型，且该类型实现 std::bidirectional_iterator 。

所有其他情况下，调用 ranges::rend 为非良构，这能在 ranges::rend(t) 出现于模板实例化的立即语境时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::rend 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __rend_fn 表示其类型的 cv 无限定版本。

__rend_fn 的所有实例均相等。在相同参数上调用类型 __rend_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::rend 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::rend 的参数要求，则 __rend_fn 实现 std::invocable<__rend_fn, Args...>、 std::invocable<const __rend_fn, Args...>、 std::invocable<__rend_fn&, Args...> 及 std::invocable<const __rend_fn&, Args...> 。否则， __rend_fn 的函数调用运算符不参与重载决议。

注解

若实参为右值（即 T 为对象类型）且 ranges::enable_borrowed_range< std::remove_cv_t <T>> 为 false ，则调用 ranges::rend 非良构，这亦导致替换失败。

若 ranges::rend( std::forward <T>(t)) 合法，则 decltype(ranges::rend( std::forward <T>(t))) 与 decltype(ranges::begin( std::forward <T>(t))) 在所有情况下实现 std::sentinel_for ，同时 T 实现 std::ranges::range 。

C++20 标准要求若底层 rend 函数调用返回纯右值，则从实质化的临时对象移动构造返回值。所有实现均直接返回纯右值。 C++20 后的提案 P0849R8 更正了该要求以匹配实现。

示例

#include <algorithm>
#include <iostream>
#include <ranges>
#include <vector>

int main()
{
    std::vector<int> v = { 3, 1, 4 };
    namespace ranges = std::ranges;
    if (ranges::find(ranges::rbegin(v), ranges::rend(v), 5) != ranges::rend(v)) {
        std::cout << "found a 5 in vector 'v'!\n";
    }

    int a[] = { 5, 10, 15 };
    if (ranges::find(ranges::rbegin(a), ranges::rend(a), 5) != ranges::rend(a)) {
        std::cout << "found a 5 in array 'a'!\n";
    }
}

输出：

found a 5 in array 'a'!

参阅

ranges::crend (C++20) | 返回指向只读范围的逆向尾迭代器 (定制点对象)
ranges::rbegin (C++20) | 返回指向范围的逆向迭代器 (定制点对象)
rendcrend (C++14) | 返回容器或数组的逆向尾迭代器 (函数模板)


std::ranges::views::reverse, std::ranges::reverse_view

< cpp‎ | ranges
定义于头文件 <ranges>
template< ranges::view V >

requires ranges::bidirectional_range<V>

class reverse_view : public ranges::view_interface<reverse_view<V>>
 (1) (C++20 起)
namespace views {

inline constexpr /*unspecified*/ reverse = /*unspecified*/;

}
 (2) (C++20 起)
1) 代表有逆序的底层 view 的视图。
2) 范围适配器对象。表达式 views::reverse(e) 表达式等价于下列表达式之一，除了只求值 E 一次：
  • e.base() ，若 e 的类型是（可有 cv 限定的） reverse_view 的特化；
  • 否则，若 e 的类型是（可有 cv 限定的）某迭代器类型 I 和 ranges::subrange_kind 类型值 K 的 ranges::subrange< std::reverse_iterator <I>, std::reverse_iterator <I>, K> ：
  • ranges::subrange<I, I, K>(e.end().base(), e.begin().base(), e.size()) ，若 K 为 ranges::subrange_kind::sized;
  • 否则为 ranges::subrange<I, I, K>(e.end().base(), e.begin().base()) ；
  • 否则为 ranges::reverse_view{e} 。
换言之， views::reverse 尽可能解包逆转的视图。

reverse_view 始终实现 bidirectional_range 与 common_range ，而若底层视图类型 V 实现 borrowed_range、 sized_range 或 random_access_range 则它实现对应的概念。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

数据成员

reverse_view 的典型实现仅保有一或二个成员对象：

  • V 类型的底层视图（此处示为 base_ ，名称仅用于阐释），及
  • std::optional 式的缓存对象，不保有值或保有一个底层视图的尾迭代器/位置，仅若底层视图类型 V 不实现 common_range 才存在。

成员函数

(构造函数)
(C++20)
 构造 reverse_view
(公开成员函数)
base
(C++20)
 返回底层视图 V
(公开成员函数)
begin
(C++20)
 返回 reverse_view 的起始迭代器
(公开成员函数)
end
(C++20)
 返回 reverse_view 的尾迭代器
(公开成员函数)
size
(C++20)
 若底层视图有界则返回其大小
(公开成员函数)
继承自 std::ranges::view_interface
empty
(C++20)
 返回视图是否为空。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator[]
(C++20)
 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

std::ranges::reverse_view::reverse_view

reverse_view() requires std::default_initializable<V> = default; | (1) | (C++20 起)
constexpr reverse_view(V r); | (2) | (C++20 起)
1) 经由其默认成员初始化器（ = V() ）值初始化 base_ 。
2) 以 std::move(r) 初始化 base_ 。

参数

r - 要逆转的范围

std::ranges::reverse_view::base

constexpr V base() const& requires std::copy_constructible<V>; | (1) | (C++20 起)
constexpr V base() &&; | (2) | (C++20 起)

返回底层视图。

1) 从底层视图复制构造结果。等价于 return base_; 。
2) 从底层视图移动构造结果。等价于 return std::move(base_); 。

std::ranges::reverse_view::begin

constexpr std::reverse_iterator <ranges::iterator_t<V>> begin();
 (1) (C++20 起)
constexpr std::reverse_iterator <ranges::iterator_t<V>> begin()
requires ranges::common_range<V>;
 (2) (C++20 起)
constexpr auto begin() const requires ranges::common_range<const V>;
 (3) (C++20 起)
1) 返回 std::make_reverse_iterator (ranges::next(ranges::begin(base_), ranges::end(base_))) 。为提供 range 概念所要求的的均摊常数时间复杂度，此函数在缓存对象内缓存结果，以供后继调用使用。
2-3) 等价于 return std::make_reverse_iterator (ranges::end(base_)); 。

std::ranges::reverse_view::end

constexpr std::reverse_iterator <ranges::iterator_t<V>> end(); | (1) | (C++20 起)
constexpr auto end() const requires ranges::common_range<const V>; | (2) | (C++20 起)

等价于 return std::make_reverse_iterator (ranges::begin(base_)); 。

std::ranges::reverse_view::size

constexpr auto size() requires ranges::sized_range<V> {

return ranges::size(base_);

}
 (1) (C++20 起)
constexpr auto size() const requires ranges::sized_range<const V> {

return ranges::size(base_);

}
 (2) (C++20 起)

若视图有界则返回其大小。

推导指引

template<class R> reverse_view(R&&) -> reverse_view<views::all_t<R>>; | (C++20 起)

辅助模板

template<class T>

inline constexpr bool enable_borrowed_range<std::ranges::reverse_view<T>> =

std::ranges::enable_borrowed_range<T>;
 (C++20 起)

std::ranges::enable_borrowed_range 的此特化使得 reverse_view 在底层视图满足 borrowed_range 时满足它。

示例

#include <ranges>
#include <iostream>

int main()
{
    static constexpr auto il = {3, 1, 4, 1, 5, 9};

    std::ranges::reverse_view rv {il};
    for (int i : rv)
        std::cout << i << ' ';

    std::cout << '\n';

    for(int i : il | std::views::reverse)
        std::cout << i << ' ';
}

输出：

9 5 1 4 1 3
9 5 1 4 1 3

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3494 | C++20 | reverse_view 始终不是 borrowed_range | 若底层视图为 borrowed_range 则它是

参阅

reverse_iterator | 逆序遍历的迭代器适配器 (类模板)
ranges::reverse (C++20) | 逆转范围中的元素顺序 (niebloid)
ranges::revserse_copy (C++20) | 创建一个范围的逆向副本 (niebloid)


std::ranges::views::single, std::ranges::single_view

< cpp‎ | ranges
定义于头文件 <ranges>
template< std::copy_constructible T >

requires std::is_object_v <T>

class single_view : public ranges::view_interface<single_view<T>>
 (1) (C++20 起)
namespace views {

inline constexpr /*unspecified*/ single = /*unspecified*/;

}
 (2) (C++20 起)
1) 产生准确含有一个拥有指定值元素的 view 。
2) 表达式 views::single(e) 对任何适合的子表达式 e 表达式等价于 single_view< std::decay_t <decltype((e))>>(e) 。

single_view 的典型实现存储一个 copyable-box<T> 类型成员。为描述目的，下面称该成员为 value_ 。

元素的生存期绑定到所属的 single_view 。复制 single_view 会进行元素的复制。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 views::single 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __single_fn 表示其类型的 cv 无限定版本。

__single_fn 的所有实例均相等。在相同参数上调用类型 __single_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 views::single 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 views::single 的参数要求，则 __single_fn 实现 std::invocable<__single_fn, Args...>、 std::invocable<const __single_fn, Args...>、 std::invocable<__single_fn&, Args...> 及 std::invocable<const __single_fn&, Args...> 。否则， __single_fn 的函数调用运算符不参与重载决议。

成员函数

(构造函数)
(C++20)
 构造 single_view
(公开成员函数)
begin
(C++20)
 返回指向元素的指针
(公开成员函数)
end
(C++20)
 返回元素后一位置的指针
(公开成员函数)
size
[静态] (C++20)
 返回 1 （一）
(公开静态成员函数)
data
(C++20)
 返回指向元素的指针
(公开成员函数)
继承自 std::ranges::view_interface
empty
(C++20)
 返回视图是否为空。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator[]
(C++20)
 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

std::ranges::single_view::single_view

single_view() requires std::default_initializable<T> = default;
 (1) (C++20 起)
constexpr explicit single_view( const T& t );
 (2) (C++20 起)
constexpr explicit single_view( T&& t );
 (3) (C++20 起)
template< class... Args >

requires std::constructible_from<T, Args...>

constexpr explicit single_view( std::in_place_t, Args&&... args );
 (4) (C++20 起)

构造 single_view 。

1) 默认初始化 value_ ，值初始化其所含的值。
2) 以 t 初始化 value_ 。
3) 以 std::move(t) 初始化 value_ 。
4) 如同以 value_{ std::in_place, std::forward <Args>(args)...} 初始化 value_ 。

std::ranges::single_view::begin

constexpr T* begin() noexcept;
constexpr const T* begin() const noexcept;
 (C++20 起)

等价于 return data(); 。

std::ranges::single_view::end

constexpr T* end() noexcept;
constexpr const T* end() const noexcept;
 (C++20 起)

等价于 return data() + 1; 。

std::ranges::single_view::size

static constexpr std::size_t size() noexcept; | (C++20 起)

等价于 return 1; 。

此为静态函数。这使得 single_view 实现 split_view 所要求的 /*tiny-range*/ 。

std::ranges::single_view::data

constexpr T* data() noexcept;
constexpr const T* data() const noexcept;
 (C++20 起)

返回指向 value_ 的所含值的指针。若 value_ 不含值则行为未定义。

推导指引

template<class T> single_view(T) -> single_view<T>; | (C++20 起)

注解

对于一个 single_view ，继承的 empty 成员函数始终返回 false ，而继承的 operator bool 转换函数始终返回 true 。

示例

#include <iostream>
#include <iomanip>
#include <ranges>
#include <string>
#include <tuple>

int main()
{
    constexpr std::ranges::single_view sv1{3.1415}; // 使用 (const T&) 构造函数
    static_assert(sv1);
    static_assert(not sv1.empty());

    std::cout << "1) *sv1.data(): " << *sv1.data() << '\n'
              << "2) *sv1.begin(): " << *sv1.begin() << '\n'
              << "3)  sv1.size(): " << sv1.size() << '\n'
              << "4)  distance: " << std::distance(sv1.begin(), sv1.end()) << '\n';

    std::string str{"C++20"};
    std::cout << "5)  str = " << std::quoted(str) << '\n';
    std::ranges::single_view sv2{std::move(str)}; // 使用 (T&&) 构造函数
    std::cout << "6) *sv2.data(): " << std::quoted(*sv2.data()) << '\n'
              << "7)  str = " << std::quoted(str) << '\n';

    std::ranges::single_view<std::tuple<int, double, std::string>>
        sv3{std::in_place, 42, 3.14, "😄"}; // uses (std::in_place_t, Args&&... args)

    std::cout << "8)  sv3 holds a tuple: { "
              << std::get<0>(sv3[0]) << ", "
              << std::get<1>(sv3[0]) << ", "
              << std::get<2>(sv3[0]) << " }\n";
}

输出：

1) *sv1.data(): 3.1415
2) *sv1.begin(): 3.1415
3)  sv1.size(): 1
4)  distance: 1
5)  str = "C++20"
6) *sv2.data(): "C++20"
7)  str = ""
8)  sv3 holds a tuple: { 42, 3.14, 😄 }

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3428 | C++20 | single_view 可从 std::in_place_t 转换 | 使该构造函数为 explicit
P2367R0 | C++20 | single_view 的推导指引无法衰变参数； views::single 复制但不包装 single_view | 提供衰变的推导指引； 使之始终包装

参阅

ranges::empty_viewviews::empty (C++20) | 无元素的空 view (类模板) (变量模板)
ranges::split_viewviews::split (C++20) | 用某个分隔符切割另一 view 所获得的子范围的 view (类模板) (范围适配器对象)


std::ranges::size

< cpp‎ | ranges
定义于头文件 <ranges>
inline namespace /*unspecified*/ {

inline constexpr auto size = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T >

requires /* see below */

constexpr auto size( T&& t );
 (C++20 起)

在常量时间内计算 t 的元素数。

令 t 为 T 类型对象。调用 ranges::size 表达式等价于：

  1. std::extent_v <T> ，若 T 为已知边界数组；
  2. 否则为 t.size() 转换到其衰变类型，若 ranges::disable_sized_range< std::remove_cv_t <T>> 为 false 且转换后的表达式合法并拥有整数式类型。
  3. 否则为 size(t) ，转换到其衰变类型，若 ranges::disable_sized_range< std::remove_cv_t <T>> 为 false 且转换后的表达式合法并拥有整数式类型，其中以下列候选进行重载决议：
    • void size(auto&) = delete;
    • void size(const auto&) = delete;
  4. 否则为， /*to-unsigned-like*/(ranges::end(t) - ranges::begin(t)) ，若 T 实现 ranges::forward_range 且 ranges::sentinel_t<T> 实现 std::sized_sentinel_for<ranges::iterator_t<T>> ，
    其中 /*to-unsigned-like*/ 代表到无符号整数式类型的显式转换。

所有其他情况下，调用 ranges::size 为非良构，这能在 ranges::size(t) 出现于模板实例化的立即语境中时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::size 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __size_fn 表示其类型的 cv 无限定版本。

__size_fn 的所有实例均相等。在相同参数上调用类型 __size_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::size 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::size 的参数要求，则 __size_fn 实现 std::invocable<__size_fn, Args...>、 std::invocable<const __size_fn, Args...>、 std::invocable<__size_fn&, Args...> 及 std::invocable<const __size_fn&, Args...> 。否则， __size_fn 的函数调用运算符不参与重载决议。

注解

凡在 ranges::size(e) 对表达式 e 合法时，返回类型均为整数式。

C++20 标准要求若底层 begin 函数调用返回纯右值，则从实质化的临时对象移动构造返回值。所有实现均直接返回纯右值。 C++20 后的提案 P0849R8 更正了该要求以匹配实现。

示例

#include <iostream>
#include <ranges>
#include <type_traits>
#include <vector>

int main()
{
    auto v = std::vector<int>{};
    std::cout << "ranges::size(v) == " << std::ranges::size(v) << '\n';

    auto il = {7};
    std::cout << "ranges::size(il) == " << std::ranges::size(il) << '\n';

    int array[] = {4, 5}; // 数组拥有已知边界
    std::cout << "ranges::size(array) == " << std::ranges::size(array) << '\n';

    std::cout << std::boolalpha << "is_signed: "
              << std::is_signed_v<decltype(std::ranges::size(v))> << '\n';
}

输出：

ranges::size(v) == 0
ranges::size(il) == 1
ranges::size(array) == 2
is_signed: false

参阅

ranges::ssize (C++20) | 返回等于范围大小的有符号整数 (定制点对象)
sizessize (C++17)(C++20) | 返回容器或数组的大小 (函数模板)


std::ranges::sized_range, std::ranges::disable_sized_range

< cpp‎ | ranges
定义于头文件 <ranges>
template< class T >

concept sized_range = ranges::range<T> &&
requires(T& t) {
ranges::size(t);

};
 (1) (C++20 起)
template<class>
inline constexpr bool disable_sized_range = false;
 (2) (C++20 起)
1) sized_range 概念指定在常数时间内以 size 函数知晓其大小的 range 类型。
2) disable_sized_range 为允许使用（成员或非成员）提供 size 函数但不实际实现 sized_range 的范围类型存在。用户可对无 cv 限定的程序定义类型特化 disable_sized_range 。这些特化应当可用于常量表达式并拥有 const bool 类型。

语义要求

1) 给定 std::remove_reference_t <T> 类型左值 t ， T 实现 sized_range 仅若
  • ranges::size(t)
  • 拥有非均摊的常数时间复杂度，
  • 不以对于保持相等性的表达式可观察的方式更改 t 的值，且
  • 等于 ranges::distance(ranges::begin(t), ranges::end(t)) ，而
  • 若 ranges::iterator_t<T> 实现 forward_iterator ，则 ranges::size(t) 为良定义，而无关乎 ranges::begin(t) 的求值（换言之，单趟有大小范围可以只在首次调用 begin 前支持调用 size ，但向前范围必须在所有时间支持）

注解

disable_sized_range 不能用于手动禁用迭代器与哨位满足 sized_sentinel_for 的范围；必须用 disable_sized_sentinel_for 代替。

不能对数组类型或引用类型特化 disable_sized_range 。


std::ranges::ssize

< cpp‎ | ranges
定义于头文件 <ranges>
inline namespace /*unspecified*/ {

inline constexpr /*unspecified*/ ssize = /*unspecified*/;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T >

requires /* see below */

constexpr /*signed-integral-like*/ ssize(T&& t);

返回转换到有符号类型的范围大小。

若 ranges::size( std::forward <T>(t)) 为良构，令 MadeSigned 代表

  • decltype(ranges::size( std::forward <T>(t))) 的对应有符号版本，若它宽于 std::ptrdiff_t ，否则为
  • std::ptrdiff_t ，

则调用 ranges::ssize 表达式等价于 static_cast<MadeSigned>(ranges::size( std::forward <T>(t))) 。

否则，调用 ranges::ssize 为非良构，这能在 ranges::ssize(t) 出现于模板实例化的立即语境时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::ssize 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __ssize_fn 表示其类型的 cv 无限定版本。

__ssize_fn 的所有实例均相等。在相同参数上调用类型 __ssize_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::ssize 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::ssize 的参数要求，则 __ssize_fn 实现 std::invocable<__ssize_fn, Args...>、 std::invocable<const __ssize_fn, Args...>、 std::invocable<__ssize_fn&, Args...> 及 std::invocable<const __ssize_fn&, Args...> 。否则， __ssize_fn 的函数调用运算符不参与重载决议。

注解

若 ranges::ssize(e) 对于表达式 e 合法，则返回类型为有符号整数式类型，即 std::is_signed_v 对其为 true 的整数类型，或有符号整数类类型。

整数式类型的宽度能由 std::numeric_limits::digits 检测。

示例

#include <array>
#include <iostream>
#include <ranges>
#include <type_traits>

int main()
{
    std::array arr{1, 2, 3, 4, 5};
    auto s = std::ranges::ssize(arr);

    std::cout << "ranges::ssize(arr) = " << s << '\n'
              << "ranges::ssize is "
              << (std::is_signed_v<decltype(s)> ? "signed" : "unsigned")
              << '\n';

    std::cout << "reversed arr: ";

    for (--s; s >= 0; --s)
        std::cout << arr[s] << ' ';

    std::cout << "\n" "s = " << s << '\n';
}

输出：

ranges::ssize(arr) = 5
ranges::ssize is signed
reversed arr: 5 4 3 2 1
s = -1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3403 | C++20 | ranges::size 可作用于某些非范围类型但 ranges::ssize 不能 | 使之能

参阅

ranges::size (C++20) | 返回等于范围大小的整数 (定制点对象)
sizessize (C++17)(C++20) | 返回容器或数组的大小 (函数模板)


std::ranges::subrange

< cpp‎ | ranges
定义于头文件 <ranges>
template<

std::input_or_output_iterator I,
std::sentinel_for<I> S = I,
ranges::subrange_kind K = std::sized_sentinel_for<S, I> ?
ranges::subrange_kind::sized : ranges::subrange_kind::unsized
>
requires (K == ranges::subrange_kind::sized || !std::sized_sentinel_for<S, I>)

class subrange : public ranges::view_interface<subrange<I, S, K>>
 (C++20 起)

subrange 类模板组合一个迭代器与一个哨位到单个 view 中。

另外， subrange 凡在最后的模板形参为 subrange_kind​::​sized 时（在 sized_sentinel_for<S, I> 得到满足或显式传递大小为构造函数参数时发生）为 sized_range 。当且仅当 std::sized_sentinel_for<S, I> 为 false 且 K 为 subrange_kind::sized 才需要存储大小记录。

成员函数

(构造函数)
(C++20)
 创建新的 subrange
(公开成员函数)
operator PairLike
(C++20)
 转换 subrange 为 pair 式类型
(公开成员函数)
观察器
begin
(C++20)
 获得迭代器
(公开成员函数)
end
(C++20)
 获得哨位
(公开成员函数)
empty
(C++20)
 检查 subrange 是否为空
(公开成员函数)
size
(C++20)
 获得 subrange 的大小
(公开成员函数)
迭代器操作
advance
(C++20)
 以给定距离前进迭代器
(公开成员函数)
prev
(C++20)
 以给定距离减少迭代器并返回原 subrange
(公开成员函数)
next
(C++20)
 以给定距离前进迭代器并返回原 subrange
(公开成员函数)
继承自 std::ranges::view_interface
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
data
(C++20)
 返回派生视图的数据的地址。若视图的迭代器类型满足 contiguous_iterator 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator[]
(C++20)
 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

推导指引

非成员函数

get(std::ranges::subrange)
(C++20)
 从 std::ranges::subrange 获得迭代器或哨位
(函数模板)

辅助类型

ranges::subrange_kind (C++20) | 指定 std::ranges::subrange 是否实现 std::ranges::sized_range (枚举)
std::tuple_size<std::ranges::subrange> (C++20) | 获得 std::ranges::subrange 的组分数量 (类模板特化)
std::tuple_element<std::ranges::subrange> (C++20) | 获得 std::ranges::subrange 的迭代器或哨位的类型 (类模板特化)

辅助模板

template<class I, class S, ranges::subrange_kind K>
inline constexpr bool enable_borrowed_range<ranges::subrange<I, S, K>> = true;

std::ranges::enable_borrowed_range 的此特化使得 subrange 满足 borrowed_range 。

示例

#include <iostream>
#include <map>
#include <ranges>
#include <string_view>

template <class V> void mutate(V& v) { v += 'A' - 'a'; }

template <class K, class V>
void mutate_map_values(std::multimap<K, V>& m, K k) {
    auto [first, last] = m.equal_range(k);
    for (auto& [_, v] : std::ranges::subrange(first, last)) {
        mutate(v);
    }
}

int main()
{
    auto print = [](std::string_view rem, auto const& mm) {
        std::cout << rem << "{ ";
        for (const auto& [k, v] : mm) std::cout << "{" << k << ",'" << v << "'} ";
        std::cout << "}\n";
    };

    std::multimap<int,char> mm{ {4,'a'}, {3,'-'}, {4,'b'}, {5,'-'}, {4,'c'} };
    print("Before: ", mm);
    mutate_map_values(mm, 4);
    print("After:  ", mm);
}

输出：

Before: { {3,'-'} {4,'a'} {4,'b'} {4,'c'} {5,'-'} }
After:  { {3,'-'} {4,'A'} {4,'B'} {4,'C'} {5,'-'} }

参阅

ranges::view_interface
(C++20)
 用于定义 view 的辅助类模板，使用奇异递归模板模式
(类模板)


std::ranges::subrange<I,S,K>::advance

< cpp‎ | ranges‎ | subrange
constexpr subrange& advance( std::iter_difference_t<I> n ); | (C++20 起)

若 n >= 0 ，则自增 n 次存储的迭代器，或直至它等于存储的哨位，二者之一先到来为止。否则，自减存储的迭代器 -n 次。

存储的大小若存在，则相应地得到调整（若 n < 0 则增加 -n ，否则减少 m ，其中 m 是实际应用到迭代器的自增次数）。

若

  • I 不实现 bidirectional_iterator 且 n < 0 ，或
  • 存储的迭代器在变为不可自减值后被自减，

则行为未定义。

参数

n - 迭代器上的最大自增次数

返回值

*this

复杂度

通常为在 n >= 0 或 n < 0 时分别为迭代器上的 min(n, size()) 次自增或 -n 次自减。

若 I 实现 random_access_iterator ，且 n < 0 或者 std::sized_sentinel_for<S, I> 得到实现则为常数。

注解

存储的大小当且仅当 K == ranges::subrange_kind::sized 但 std::sized_sentinel_for<S, I> 不被满足才存在。

示例

#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
#include <ranges>

void print(auto name, auto const sub) {
    std::cout << name << ".size() == " << sub.size() << "; { ";
    std::ranges::for_each(sub, [](int x) { std::cout << x << ' '; });
    std::cout << "}\n";
};

int main()
{
    std::array arr{1,2,3,4,5,6,7};
    std::ranges::subrange sub{ std::next(arr.begin()), std::prev(arr.end()) };
    print("1) sub", sub);
    print("2) sub", sub.advance(3));
    print("3) sub", sub.advance(-2));
}

输出：

1) sub.size() == 5; { 2 3 4 5 6 }
2) sub.size() == 2; { 5 6 }
3) sub.size() == 4; { 3 4 5 6 }

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3433 | C++20 | 规范错误处理了 n < 0 的情况 | 已更正

参阅

next (C++20) | 以给定距离前进迭代器并返回原 subrange (公开成员函数)
prev (C++20) | 以给定距离减少迭代器并返回原 subrange (公开成员函数)
advance | 令迭代器前进给定的距离 (函数模板)
ranges::advance (C++20) | 令迭代器前进给定的距离或到给定的边界 (niebloid)


std::ranges::subrange<I,S,K>::begin

< cpp‎ | ranges‎ | subrange
constexpr I begin() const requires std::copyable<I>; | (1) | (C++20 起)
[[nodiscard]] constexpr I begin() requires (!std::copyable<I>); | (2) | (C++20 起)

获得指向 subrange 首元素的迭代器，或若视图为空则为尾迭代器。

1) 若迭代器类型可复制，则返回存储的迭代器的副本。
2) 若迭代器类型不可复制，则返回从存储的迭代器移动构造的迭代器。

参数

（无）

返回值

1) 从存储的迭代器复制构造的迭代器。
2) 从存储的迭代器移动构造的迭代器。

注解

调用 (2) 可能将存储的迭代器置于合法但未指定的状态，取决于 I 的构造函数的行为。

示例

本节未完成
原因：暂无示例

参阅

end (C++20) | 获得哨位 (公开成员函数)
begincbegin (C++11)(C++14) | 返回指向容器或数组起始的迭代器 (函数模板)
ranges::begin (C++20) | 返回指向范围起始的迭代器 (定制点对象)


std::ranges::subrange 的推导指引

< cpp‎ | ranges‎ | subrange
定义于头文件 <ranges>
template< std::input_or_output_iterator I, std::sentinel_for<I> S >
subrange(I, S) -> subrange<I, S>;
 (1) (C++20 起)
template< std::input_or_output_iterator I, std::sentinel_for<I> S >

subrange(I, S, /*make-unsigned-like-t*/<std::iter_difference_t<I>>) ->

subrange<I, S, ranges::subrange_kind::sized>;
 (2) (C++20 起)
template< ranges::borrowed_range<R> >

subrange(R&&) ->
subrange<ranges::iterator_t<R>, ranges::sentinel_t<R>,
(ranges::sized_range<R> ||
std::sized_sentinel_for<ranges::iterator_t<R>,
ranges::sentinel_t<R>>) ?

ranges::subrange_kind::sized : ranges::subrange_kind::unsized>;
 (3) (C++20 起)
template< ranges::borrowed_range<R> >

subrange(R&&, /*make-unsigned-like-t*/<ranges::range_difference_t<R>>) ->
subrange<ranges::iterator_t<R>, ranges::sentinel_t<R>,

ranges::subrange_kind::sized>;
 (4) (C++20 起)

为 std::ranges::subrange 提供这些推导指引。

1) 从迭代器与哨位类型推导模板实参。若 std::sized_sentinel_for<S, I> 得以满足则 subrange 为有大小，如默认模板实参所确定。
2) 在指定范围大小时从迭代器与哨位类型推导模板实参。 subrange 始终为有大小。
3) 从范围类型推导模板实参。若能从范围或其迭代器与哨位获得大小则 subrange 有大小。
4) 在指定范围大小时从范围类型推导模板实参。 subrange 始终为有大小。

仅用于阐释的别名模板 make-unsigned-like-t 将每个整数式类型映射到其对应的无符号版本。

注解

在构造 subrange 对象时，

  • 对于 (1,2) ，若迭代器-哨位对不代表合法范围则行为未定义，
  • 对于 (2,4) ，若给定的大小不等于范围大小则行为未定义。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3404 | C++20 | 提供了无意义的来自 pair 式类型的推导指引 | 已移除


std::ranges::subrange<I,S,K>::empty

< cpp‎ | ranges‎ | subrange
constexpr bool empty() const; | (C++20 起)

检查 subrange 是否为空，即存储的迭代器与哨位是否比较相等。

参数

（无）

返回值

若存储的迭代器与哨位比较相等则为 true ，否则为 false 。

示例

本节未完成
原因：暂无示例

参阅

size (C++20) | 获得 subrange 的大小 (公开成员函数)
empty (C++17) | 检查容器是否为空 (函数模板)
ranges::empty (C++20) | 检查范围是否为空 (定制点对象)


std::ranges::subrange<I,S,K>::end

< cpp‎ | ranges‎ | subrange
constexpr S end() const; | (C++20 起)

返回指示 subrange 末尾的哨位

参数

（无）

返回值

从存储的哨位复制构造的哨位。

示例

本节未完成
原因：暂无示例

参阅

begin (C++20) | 获得迭代器 (公开成员函数)
endcend (C++11)(C++14) | 返回指向容器或数组结尾的迭代器 (函数模板)
ranges::end (C++20) | 返回指示范围结尾的哨位 (定制点对象)


std::ranges::get(std::ranges::subrange)

< cpp‎ | ranges‎ | subrange
定义于头文件 <ranges>
template< std::size_t N, class I, class S, ranges::subrange_kind K >

requires (N == 0 && std::copyable<I>) || N == 1)

constexpr auto get( const ranges::subrange<I, S, K>& r );
 (1) (C++20 起)
template< std::size_t N, class I, class S, ranges::subrange_kind K >

requires (N < 2)

constexpr auto get( ranges::subrange<I, S, K>&& r );
 (2) (C++20 起)
namespace std { using ranges::get; }
 (3) (C++20 起)
1) 分别在 N == 0 或 N == 1 时从 subrange 左值（或 const 右值）获得迭代器或哨位。它主要为结构化绑定支持提供。
2) 同 (1) ，除了它接收非 const subrange 右值。
3) 将 (1-2) 导入命名空间 std ，这简化其使用并使得每个拥有可复制迭代器的 subrange 均为 pair 式类型。

参数

r - subrange

返回值

1) 当 N == 0 或 N == 1 时分别为从存储的迭代器或哨位复制构造的迭代器或哨位。
2) 同 (1) ，除了若 N == 0 且 I 不满足 copyable 则移动构造迭代器。

可能的实现

template<std::size_t N, class I, class S, std::ranges::subrange_kind K>
    requires (N == 0 && std::copyable<I>) || N == 1)
constexpr auto get(const std::ranges::subrange<I, S, K>& r)
{
    if constexpr (N == 0)
        return r.begin();
    else
        return r.end();
}

template<std::size_t N, class I, class S, std::ranges::subrange_kind K>
    requires (N < 2)
constexpr auto get(std::ranges::subrange<I, S, K>&& r)
{
    if constexpr (N == 0)
        return r.begin(); // 可能进行移动构造
    else
        return r.end();
}

示例

#include <array>
#include <iostream>
#include <iterator>
#include <ranges>

int main()
{
    std::array a{1, -2, 3, -4};

    std::ranges::subrange sub_a{ std::next(a.begin()), std::prev(a.end()) };

    std::cout << *std::ranges::get<0>(sub_a) << ' '  // == *(begin(a) + 1)
              << *std::get<1>(sub_a) << '\n';        // == *(end(a) - 1)

    *std::get<0>(sub_a) = 42; // OK
//  *std::get<2>(sub_a) = 13; // 硬错误：下标只能为 0 或 1
}

输出：

-2 -4

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3589 | C++20 | 若 N == 0 且 I 不实现 copyable 则 const 左值的重载非良构 | 从重载集移除它

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
std::get(std::tuple) | 元组式访问指定的元素 (函数模板)
std::get(std::pair) (C++11) | 访问 pair 的一个元素 (函数模板)
std::get(std::array) | 访问 array 的一个元素 (函数模板)


std::ranges::subrange<I,S,K>::next

< cpp‎ | ranges‎ | subrange
[[nodiscard]] constexpr subrange next(std::iter_difference_t<I> n = 1) const&
requires std::forward_iterator<I>;
 (1) (C++20 起)
[[nodiscard]] constexpr subrange next(std::iter_difference_t<I> n = 1) &&;
 (2) (C++20 起)
1) 获得在 n >= 0 或 n < 0 时迭代器分别相对 *this 的自增 min(n, size()) 次或自减 -n 次的 subrange 。等价于 auto tmp = *this; tmp.advance(n); return tmp; 。
2) 在 n >= 0 或 n < 0 时分别自增 min(n, size()) 次或自减 -n 次存储的迭代器，然后从 *this 移动构造结果。等价于 advance(n); return std::move(*this); 。

若

  • I 不实现 bidirectional_iterator 且 n < 0 ，或
  • 存储的迭代器在变为不可自减值后被自减，

则行为未定义。

参数

n - 迭代器上的最大自增次数

返回值

在 n >= 0 或 n < 0 时迭代器分别相对 *this 的迭代器的原值自增 min(n, size()) 次或自减 -n 次的 subrange 。

复杂度

通常为在 n >= 0 或 n < 0 时分别为迭代器上的 min(n, size()) 次自增或 -n 次自减。

若 I 实现 random_access_iterator ，且 n < 0 或者 std::sized_sentinel_for<S, I> 得到实现则为常数。

注解

调用 (2) 可能将存储的迭代器置于合法但未指定的状态，取决于 I 与 S 的构造函数的行为。

示例

本节未完成
原因：暂无示例

参阅

prev (C++20) | 以给定距离减少迭代器并返回原 subrange (公开成员函数)
advance (C++20) | 以给定距离前进迭代器 (公开成员函数)
next (C++11) | 令迭代器自增 (函数模板)
ranges::next (C++20) | 自增迭代器给定的距离或到边界 (niebloid)


std::ranges::subrange<I,S,K>::operator PairLike

< cpp‎ | ranges‎ | subrange
template< /*different-from*/<subrange> PairLike >

requires /*pair-like-convertible-from*/<PairLike, const I&, const S&>

constexpr operator PairLike() const;
 (1) (C++20 起)
辅助概念
template< class T >

concept /*pair-like*/ = // 仅用于阐释
! std::is_reference_v <T> && requires(T t) {
typename std::tuple_size <T>::type; // 确保 std::tuple_size<T> 完整
requires std::derived_from< std::tuple_size <T>,
std::integral_constant < std::size_t, 2>>;
typename std::tuple_element_t <0, std::remove_const <T>>;
typename std::tuple_element_t <1, std::remove_const <T>>;
{ std::get<0>(t) } -> std::convertible_to<const std::tuple_element_t <0, T>&>;
{ std::get<1>(t) } -> std::convertible_to<const std::tuple_element_t <1, T>&>;

};
 (2) (C++20 起)
template< class T, class U, class V >

concept /*pair-like-convertible-from*/ = // 仅用于阐释
!ranges::range<T> && /*pair-like*/<T> &&
std::constructible_from<T, U, V> &&
/*convertible-to-non-slicing*/<U, std::tuple_element_t <0, T>> &&

std::convertible_to<V, std::tuple_element_t <1, T>>;
 (3) (C++20 起)
1) 转换 subrange 为 pair 式类型（即实现 pair-like 的类型，见后述）。等价于 return PairLike(i_, s_); ，其中 i_ 与 s_ 分别为存储的迭代器与哨位。此转换函数拥有 pair-like-convertible （见后述）所施加的额外约束。
2) 仅用于阐释的概念 pair-like 指定类型为 pair 式类型。通常而言， pair 式类型的表达式 e 能用于结构化绑定（即 auto const& [x, y] = e; 通常为良构）。同标准概念，此概念得到实现，若它得到满足且其蕴含的所有概念均得到实现。
3) 仅用于阐释的概念 pair-like-convertible-from 细化 pair-like 。它拒绝 range 类型，并要求 U 与 V 分别可转换成 T 的第一与第二元素类型，并且从 U （将被替换成 const I& ）的转换为非切片（见 convertible-to-non-slicing ）。同标准概念，此概念得到实现，若它得到满足且其蕴含的所有概念均得到实现。

仅用于阐释的概念 different-from 为类型 T 与 U 实现，当且仅当 std::decay_t <T> 与 std::decay_t <U> 是不同的类型。

参数

（无）

返回值

从存储的迭代器与哨位直接初始化 PairLike 值。

注解

下列类型为 pair 式：

  • std::pair <T, U>
  • std::tuple <T, U>
  • std::array <T, 2>
  • std::ranges::subrange<I, S, K>

从这些类型之一或 std::variant 特化派生的程序定义类型为 pair 式，若

  • std::tuple_size 与 std::tuple_element 对它正确特化，且
  • 对其值调用 std::get<0> 与 std::get<1> 为良构。

由于 subrange 特化是 range 类型，到它们的转换不经由此转换函数进行。

std::array 特化不能从 subrange 转换而来，因为它们是 range 类型。

示例

#include <iostream>
#include <ranges>
#include <string>
#include <utility>

using legacy_strview = std::pair<
    std::string::const_iterator,
    std::string::const_iterator
>;

void legacy_print(legacy_strview p)
{
    for (; p.first != p.second; ++p.first)
        std::cout << *p.first << ' ';
    std::cout << '\n';
}

int main()
{
    std::string dat{"ABCDE"};
    for (auto v{ std::ranges::subrange{dat} }; v; v = {v.begin(), v.end() - 1}) {
        /*...*/
        legacy_print(legacy_strview{v});
    }
}

输出：

A B C D E
A B C D
A B C
A B
A


std::ranges::subrange<I,S,K>::prev

< cpp‎ | ranges‎ | subrange
[[nodiscard]] constexpr subrange prev( std::iter_difference_t<I> n = 1 ) const
requires std::bidirectional_iterator<I>;
 (C++20 起)

获得在 n >= 0 或 n < 0 时分别为迭代器相对于 *this 的自减 n 次或自增 min(-n, size()) 次的 subrange 。

等价于 auto tmp = *this; tmp.advance(-n); return tmp; 。若迭代器在成为不可自减值后被自减则行为未定义。

参数

n - 迭代器的最小自减次数

返回值

在 n >= 0 或 n < 0 时分别为迭代器相对于 *this 的自减 n 次或自增 min(-n, size()) 次的 subrange 。

复杂度

通常在 n >= 0 为 n < 0 或时分别为迭代器上的 n 次自减或 min(-n, size()) 次自增。

若 I 实现 random_access_iterator ，且 n >= 0 或者 std::sized_sentinel_for<S, I> 得到实现则为常数。

示例

本节未完成
原因：暂无示例

参阅

next (C++20) | 以给定距离前进迭代器并返回原 subrange (公开成员函数)
advance (C++20) | 以给定距离前进迭代器 (公开成员函数)
prev (C++11) | 令迭代器自减 (函数模板)
ranges::prev (C++20) | 自减迭代器给定的距离或到边界 (niebloid)


std::ranges::subrange<I,S,K>::size

< cpp‎ | ranges‎ | subrange
constexpr /* see below */ size() const
requires (K == ranges::subrange_kind::sized);
 (C++20 起)

获得 subrange 中的元素数。

返回类型为 std::iter_difference_t<I> 的对应无符号版本。

参数

（无）

返回值

显式转换到返回类型的 s_ - i_ ，其中 i_ 与 s_ 分别为存储的迭代器与哨位，若不存储大小。

否则为存储的大小。

注解

subrange 中存储大小，当且仅当 K == ranges::subrange_kind::sized 但 std::sized_sentinel_for<S, I> 不被满足。

示例

本节未完成
原因：暂无示例

参阅

empty (C++20) | 检查 subrange 是否为空 (公开成员函数)
sizessize (C++17)(C++20) | 返回容器或数组的大小 (函数模板)
ranges::size (C++20) | 返回等于范围大小的整数 (定制点对象)


std::ranges::subrange<I,S,K>::subrange

< cpp‎ | ranges‎ | subrange
subrange() requires std::default_initializable<I> = default;
 (1) (C++20 起)
constexpr subrange( /*convertible-to-non-slicing*/<I> auto i, S s )
requires (!/*store-size*/);
 (2) (C++20 起)
constexpr subrange( /*convertible-to-non-slicing*/<I> auto i, S s,

/*make-unsigned-like-t*/<std::iter_difference_t<I>> n )

requires (K == ranges::subrange_kind::sized);
 (3) (C++20 起)
template< /*different-from*/<subrange> R >

requires ranges::borrowed_range<R> &&
/*convertible-to-non-slicing*/<ranges::iterator_t<R>, I> &&
std::convertible_to<ranges::sentinel_t<R>, S>

constexpr subrange( R&& r ) requires (!/*store-size*/ || ranges::sized_range<R>);
 (4) (C++20 起)
template< ranges::borrowed_range R>

requires /*convertible-to-non-slicing*/<ranges::iterator_t<R>, I> &&
std::convertible_to<ranges::sentinel_t<R>, S>
constexpr subrange( R&& r, /*make-unsigned-like-t*/<std::iter_difference_t<I>> n )
requires (K == ranges::subrange_kind::sized)
: subrange{ranges::begin(r), ranges::end(r), n}

{}
 (5) (C++20 起)

构造 subrange 。

若 K == ranges::subrange_kind::sized && !std::sized_sentinel_for<S, I> ，则存储范围大小到 subrange 中，如同用 /*make-unsigned-like-t*/<std::iter_difference_t<I>> 类型的成员子对象存储，其中 make-unsigned-like-t 是仅用于阐释的别名模板，将每个整数式类型映射到其对应的无符号版本。否则不存储大小。若存储大小则常量 store-size 为 true ，否则为 false 。

1) 默认构造函数。值初始化存储的迭代器与哨位，如同分别用默认成员初始化器 = I() 与 = S() 。若存储大小，则将它初始化为 ​0​ ，如同通过默认成员初始化器 = 0 。
2) 从迭代器-哨位对构造 subrange 。分别以 std::move(i) 与 s 初始化存储的迭代器与哨位。若 [i, s) 不是合法范围则行为未定义。
3) 从迭代器-哨位对与大小提示构造 subrange 。分别以 std::move(i) 与 s 初始化存储的迭代器与哨位。若存储大小，则以 n 初始化它。若 [i, s) 不是合法范围，或 n 不等于显式转换到其类型的 ranges::distance(i, s) 则行为未定义。
4) 从范围构造 subrange 。若存储大小则等价于 subrange(r, static_cast</*make-unsigned-like-t*/<std::iter_difference_t<I>>>(ranges::size(r))) 。否则等价于 subrange(ranges::begin(r), ranges::end(r)) 。
5) 从范围与大小提示构造 subrange 。若 n 不等于显式转换到其类型的 ranges::distance(ranges::begin(r), ranges::end(r)) 则行为未定义。

仅用于阐释的概念 different-from 为类型 T 与 U 实现，当且仅当 std::decay_t <T> 与 std::decay_t <U> 是不同的类型。

仅用于阐释的概念 convertible-to-non-slicing 为 From 与 To 满足或实现，当且仅当 std::convertible_to<From, To> 得到满足或实现，且任一下列条件得到满足：

  • std::decay_t <From> 或 std::decay_t <To> 不是指针类型、
  • std::remove_pointer_t <From>(*)[] 可隐式转换为 std::remove_pointer_t <To>(*)[] ，即从 From 到 To 的转换至多为限定转换。

参数

i | - | 代表范围起始的迭代器
s | - | 代表范围末尾的哨位
r | - | 范围
n | - | 大小提示，必须等于范围大小

注解

仅用于阐释的概念 convertible-to-non-slicing 禁止从指向派生类的指针到指向基类的指针的转换。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3470 | C++20 | convertible-to-non-slicing 曾拒绝一些合法的限定转换 | 使之接受
P2393R1 | C++20 | 到整数类类型的隐式转换可能非法 | 使之为显式

示例

本节未完成
原因：暂无示例


std::tuple_element<std::ranges::subrange>

< cpp‎ | ranges‎ | subrange
定义于头文件 <ranges>
template< class I, class S, ranges::subrange_kind K >
struct tuple_element<0, ranges::subrange<I, S, K>>;
 (1) (C++20 起)
template< class I, class S, ranges::subrange_kind K >
struct tuple_element<0, const ranges::subrange<I, S, K>>;
 (2) (C++20 起)
template< class I, class S, ranges::subrange_kind K >
struct tuple_element<1, ranges::subrange<I, S, K>>;
 (3) (C++20 起)
template< class I, class S, ranges::subrange_kind K >
struct tuple_element<1, const ranges::subrange<I, S, K>>;
 (4) (C++20 起)

std::tuple_element 对 std::ranges::subrange 的部分特化用元组式语法提供 subrange 的迭代器或哨位类型的编译时访问。它们是为结构化绑定支持提供的。

1-2) 获得迭代器类型，即 I 。
3-4) 获得哨位类型，即 S 。

成员类型

成员类型 | 定义
type | (1-2) I (3-4) S

注解

由于 subrange 的 get 函数按值返回迭代器与哨位，在 为 const 限定（但非 volatile 限定）时不添加 const 限定符到结果类型。

若 subrange 为 volatile 限定，则结果类型亦为 volatile 限定，因为使用了对 volatile 或 const volatile 类型的部分特化。这种使用被弃用。

示例

#include <iterator>
#include <list>
#include <ranges>
#include <type_traits>

int main()
{
    std::list<int> list{3, 1, 4, 1, 5, 9, 2, 6};

    std::ranges::subrange subrange{
        std::counted_iterator(std::begin(list), 4),
        std::default_sentinel
    };

    static_assert(
        std::is_same_v<
            std::tuple_element_t<0, decltype(subrange)>,
            // 实现定义的类型：
            std::counted_iterator<std::_List_iterator<int>>
            >);

    static_assert(
        std::is_same_v<
            std::tuple_element_t<1, decltype(subrange)>,
            std::default_sentinel_t
            >);
}

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
tuple_element (C++11) | 获得元组式类型的元素类型 (类模板)
std::tuple_size<std::ranges::subrange> (C++20) | 获得 std::ranges::subrange 的组分数量 (类模板特化)


std::tuple_size<std:ranges::subrange>

< cpp‎ | ranges‎ | subrange
定义于头文件 <ranges>
template< class I, class S, ranges::subrange_kind K >

struct tuple_size<ranges::subrange<I, S, K>>

: std::integral_constant < std::size_t, 2> {};
 (C++20 起)

std::tuple_size 对 std::ranges::subrange 的部分特化提供编译时获得 subrange 的组分数量的方式，该数始终为 2 。它是为结构化绑定支持提供的。

继承自 std::integral_constant

成员常量

value
[静态]
 常量值 2
(公开静态成员常量)

成员函数

operator std::size_t | 转换对象为 std::size_t ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | std::size_t
type | std::integral_constant < std::size_t, value>

示例

#include <array>
#include <iostream>
#include <iterator>
#include <ranges>

int main()
{
    static_assert(2 == std::tuple_size_v<std::ranges::subrange<int*, int*>>);

    using array5 = std::array<int, 5>;

    static_assert(2 == std::tuple_size<std::ranges::subrange<
        array5::const_iterator, array5::const_iterator>>{});

    constexpr array5 a{ 1, 2, 3, 4, 5 };

    std::ranges::subrange sub_a1{a};

    for (std::cout << "sub_a1: { "; int e : sub_a1) { std::cout << e << ' '; }
    std::cout << "}\n";

    std::ranges::subrange sub_a2{std::next(cbegin(a)), std::prev(cend(a))};

    const auto [first, last] = sub_a2;
    std::cout << "sub_a2 size = " << std::distance(first, last) << '\n';

    for (std::cout << "sub_a2: { "; int e : sub_a2) { std::cout << e << ' '; }
    std::cout << "}\n";
}

输出：

sub_a1: { 1 2 3 4 5 }
sub_a2 size = 3
sub_a2: { 2 3 4 }

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
tuple_size (C++11) | 获得元组式类型的元素数 (类模板)
std::tuple_element<std::ranges::subrange> (C++20) | 获得 std::ranges::subrange 的迭代器或哨位的类型 (类模板特化)


std::ranges::subrange_kind

< cpp‎ | ranges
定义于头文件 <ranges> |
enum class subrange_kind : bool { unsized, sized }; | (C++20 起)

指定 std::ranges::subrange 是否实现 std::ranges::sized_range 。

常量 | 解释
unsized | 指定 subrange 不实现 sized_range
sized | 指定 subrange 实现 sized_range


std::ranges::views::take, std::ranges::take_view

< cpp‎ | ranges
定义于头文件 <ranges>
template< ranges::view V >
class take_view : public ranges::view_interface<take_view<V>>
 (1) (C++20 起)
namespace views {

inline constexpr /*unspecified*/ take = /*unspecified*/;

}
 (2) (C++20 起)
1) 范围适配器，表示来自底层序列的始于开端终于给定边界的元素的 view 。
2) views::take 是一个范围适配器对象。表达式 views::take(e, f) 产生表示来自 e 的首 f 个元素的视图。结果不一定是 take_view 。

它表达式等价于（其中 T 为 std::remove_cvref_t<decltype((e))> 而 D 为 ranges::range_difference_t<decltype((e))> ）：

  • ((void)f, static_cast<T>(e)) ，若 T 为 ranges::empty_view ，除了 e 与 f 的求值具有不确定顺序；
  • U(ranges::begin(e), ranges::begin(e) + std::min <D>(ranges::distance(e), f)) ，若 T 是 std::span、 std::basic_string_view 或 ranges::subrange 的实现 random_access_range 及 sized_range 的特化，其中 U 为
  • std::span<typename T::element_type> ，若 T 为 std::span 的特化；
  • T ，若 T 为 std::basic_string_view 的特化；
  • ranges::subrange<ranges::iterator_t<T>> ，若 T 为 ranges::subrange 的特化；
  • ranges::iota_view(*ranges::begin(e), *(ranges::begin(e) + std::min <D>(ranges::distance(e), f))) ，若 T 为 ranges::iota_view 实现 random_access_range 及 sized_range 的特化；
  • 否则为 take_view(e, f) 。
所有情况下 decltype((f)) 必须实现 std::convertible_to<D> 。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

成员函数

(构造函数)
(C++20)
 构造 take_view
(公开成员函数)
base
(C++20)
 返回底层（适配的）视图的副本
(公开成员函数)
begin
(C++20)
 返回指向起始的迭代器
(公开成员函数)
end
(C++20)
 返回指向末尾的迭代器或哨位
(公开成员函数)
size
(C++20)
 返回元素数，只要底层（适配的）范围满足 sized_range
(公开成员函数)
继承自 std::ranges::view_interface
empty
(C++20)
 返回视图是否为空。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
data
(C++20)
 返回派生视图的数据的地址。若视图的迭代器类型满足 contiguous_iterator 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator[]
(C++20)
 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

推导指引

嵌套类

sentinel
(C++20)
 哨位类型
(仅用于阐释的成员类模板)

辅助模板

template<class T>

inline constexpr bool enable_borrowed_range<std::ranges::take_view<T>> =

std::ranges::enable_borrowed_range<T>;
 (C++20 起)

std::ranges::enable_borrowed_range 的此特化使得 take_view 在底层类型实现 borrowed_range 时实现它。

示例

#include <algorithm>
#include <iostream>
#include <ranges>

auto print = [](char x) { std::cout << x; };

int main()
{
    constexpr char pi[] { '3', '.', '1', '4', '1', '5', '9', '2' };

    std::ranges::for_each(pi | std::ranges::views::take(6), print);
    std::cout << '\n';

    std::ranges::for_each(std::ranges::take_view{pi, 42}, print); // safely takes only 8 chars
    std::cout << '\n';
}

输出：

3.1415
3.141592

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3494 | C++20 | take_view 决不是 borrowed_range | 若底层视图是 borrowed_range 则它是
LWG 3407 | C++20 | views::take 有时无法构造具大小随机访问范围 | 调整结果类型使构造始终合法

参阅

views::counted (C++20) | 从迭代器和计数创建子范围 (定制点对象)
ranges::take_while_viewviews::take_while (C++20) | 由另一 view 的到首个谓词返回 false 为止的起始元素组成的 view (类模板) (范围适配器对象)
ranges::copy_n (C++20) | 将一定数目的元素复制到一个新的位置 (niebloid)


std::ranges::take_view<V>::base

< cpp‎ | ranges‎ | take view
constexpr V base() const& requires std::copy_constructible<V>; | (1) | (C++20 起)
constexpr V base() &&; | (2) | (C++20 起)

返回底层视图的副本。

1) 从底层视图复制构造结果。
2) 从底层视图移动构造结果。

参数

（无）

返回值

底层视图的副本。

示例

本节未完成
原因：暂无示例


std::ranges::take_view<V>::begin

< cpp‎ | ranges‎ | take view
constexpr auto begin() requires (!__SimpleView<V>); | (1) | (C++20 起)
constexpr auto begin() const requires ranges::range<const V>; | (2) | (C++20 起)

返回指向 take_view 首元素的迭代器。

1) 返回 std::counted_iterator 或 ranges::range_iterator_t<V> 。
2) 返回 std::counted_iterator 或 ranges::range_iterator_t<const V> 。

重载 (1) 仅若 V 是简单视图（即若 V 与 const V 均为视图且拥有相同迭代器与哨位类型）才参与重载决议。

参数

（无）

返回值

结果依赖于可能为 const 限定的底层视图类型 _Base ，即 V （对于重载 (1) ）或 const V （对于重载 (2) ）所满足的概念。

令 base_ 为底层视图， count_ 为传递给构造函数的数（若默认初始化则为 ​0​ ）。

底层视图满足…… | random_access_range
是 | 否
sized_range 是 ranges::begin(base_) std::counted_iterator(ranges::begin(base_),

ranges::range_difference_t<Base_>(this->size()))
否 | std::counted_iterator(ranges::begin(base_), count_)

示例

#include <ranges>
#include <iostream>
#include <string_view>
using namespace std::literals;

int main()
{
    static constexpr auto sv = {"∀x"sv, "∃y"sv, "ε"sv, "δ"sv};

    std::cout << *std::ranges::take_view(sv, 8).begin() << '\n';
}

输出：

∀x

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2393R1 | C++20 | 有符号与无符号整数类间的隐式转换可能失败 | 使之为显式

参阅

end (C++20) | 返回指向末尾的迭代器或哨位 (公开成员函数)
counted_iterator (C++20) | 对到范围结尾距离进行跟踪的迭代器适配器 (类模板)
operator== (C++20) | 比较哨位与从 take_view::begin 返回的迭代器 (函数)


std::ranges::take_view 的推导指引

< cpp‎ | ranges‎ | take view
定义于头文件 <ranges> |
template< class R > take_view( R&&, ranges::range_difference_t<R> ) -> take_view<views::all_t<R>>; | (C++20 起)

为 std::ranges::take_view 提供该推导指引以允许从 range 和元素数推导。

若 R 为 view ，则推导的类型为 ranges::take_view<R> ；否则，推导的类型通常为 ranges::take_view<ranges::ref_view<R>> 。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3447 | C++20 | 模板形参 R 以 range 约束 | 不约束 R （但 range_difference_t 要求 range ）


std::ranges::take_view<V>::end

< cpp‎ | ranges‎ | take view
constexpr auto end() requires (!__SimpleView<V>); | (1) | (C++20 起)
constexpr auto begin() const requires ranges::range<const V>; | (2) | (C++20 起)

返回表示 take_view 末尾的迭代器或哨位。 take_view 的末尾是底层范围的第 count 元素的后一位置，或若后者拥有少于 count 个元素则为其末尾。

1) 返回 take_view::/*sentinel*/<false>、 std::default_sentinel_t 或 ranges::range_iterator_t<V> 。
2) 返回 take_view::/*sentinel*/<true>、 std::default_sentinel_t 或 ranges::range_iterator_t<const V> 。

重载 (1) 仅若 V 简单视图（即若 V 与 const V 均为视图且拥有相同迭代器与哨位类型）才参与重载决议。

参数

（无）

返回值

结果依赖于可能为 const 限定的底层视图类型 _Base ，即 V （对于重载 (1) ）或 const V （对于重载 (2) ）所满足的概念。

令 base_ 为底层视图。

底层视图满足…… |  | random_access_range
 |  | 是 | 否
sized_range | 是 | ranges::begin(base_) + ranges::range_difference_t<Base_>(this->size())} | std::default_sentinel
 | 否 | 1) /*sentinel*/<false>{ranges::end(base_)} 2) /*sentinel*/<true>{ranges::end(base_)}

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2393R1 | C++20 | 有符号与无符号整数类间的隐式转换可能失败 | 使之为显式

参阅

begin (C++20) | 返回指向起始的迭代器 (公开成员函数)
counted_iterator (C++20) | 对到范围结尾距离进行跟踪的迭代器适配器 (类模板)
operator== (C++20) | 比较哨位与从 take_view::begin 返回的迭代器 (函数)


std::ranges::take_view<V>::sentinel

< cpp‎ | ranges‎ | take view
template< bool Const > class /*sentinel*/ | (C++20 起)

底层类型不是 sized_range 时 take_view::end 的返回类型。

const 限定重载返回 /*sentinel*/<true> 类型。非 const 限定重载返回 /*sentinel*/<false> 类型。

此类模板的名字（此处展示为 /*sentinel*/ ）是未指明的。

典型实现仅保有一个数据成员：从（可能为 const 限定的） V 获得的哨位。

成员类型

成员类型 | 定义
Base(私有) | 若 Const 为 true 则为 const V ，否则为 V 。名称仅用于阐释

成员函数

(构造函数) (C++20) | 构造哨位 (公开成员函数)
base (C++20) | 返回底层哨位 (公开成员函数)

非成员函数

operator==
(C++20)
 比较哨位与从 take_view::begin 返回的迭代器
(函数)


std::ranges::take_view<V>::sentinel<Const>::base

< cpp‎ | ranges‎ | take view‎ | sentinel
constexpr ranges::sentinel_t<Base> base() const; | (C++20 起)

返回底层哨位。

参数

（无）

返回值

底层哨位的副本

示例

本节未完成
原因：暂无示例


operator==(std::ranges::take_view::sentinel<Const>)

< cpp‎ | ranges‎ | take view‎ | sentinel
friend constexpr bool

operator==( const std::counted_iterator<ranges::iterator_t<Base>>& y,

const /*sentinel*/& x );
 (1) (C++20 起)
template< bool OtherC = !Const >

requires std::sentinel_for<ranges::sentinel_t<Base>,
ranges::iterator_t</*add-const-if*/<OtherC, V>>>
friend constexpr bool operator==( const std::counted_iterator<ranges::iterator_t<
/*add-const-if*/<OtherC, V>>>& y,

const /*sentinel*/& x );
 (2) (C++20 起)

将 take_view::/*sentinel*/ 与 std::counted_iterator （常通过调用 take_view::begin 获得）比较。

若 y 指向第 N 元素（其中 N 为传递给 take_view 的构造函数的数）后一位置，或抵达了底层视图末尾则为 true 。

仅用于阐释的别名模板 add-const-if 定义为 template<bool C, class T> using /*add-const-if*/ = std::conditional_t <C, const T, T>; 。

这些函数对通常无限定或有限定查找不可见，而只能在 std::ranges::take_view::sentinel<Const> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

参数

y | - | 要比较的 std::counted_iterator
x | - | 要比较的哨位

返回值

y.count() == 0 || y.base() == x.end_ ，其中 end_ 代表底层哨位。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3449 | C++20 | 不支持相异 const 限定的 take_view 的迭代器与哨位间的比较 | 使得在可能时支持


std::ranges::take_view<V>::sentinel<Const>::sentinel

< cpp‎ | ranges‎ | take view‎ | sentinel
/*sentinel*/() = default;
 (1) (C++20 起)
constexpr explicit /*sentinel*/( ranges::sentinel_t<Base> end );
 (2) (C++20 起)
constexpr /*sentinel*/( /*sentinel*/<!Const> s )

requires Const &&

std::convertible_to<ranges::sentinel_t<V>, ranges::sentinel_t<Base>>;
 (3) (C++20 起)

构造哨位。

1) 默认构造函数。值初始化底层哨位。
2) 以 end 初始化底层哨位。
3) 从 /*sentinel*/<false> 转换到 /*sentinel*/<true> 。移动构造对应的成员。

参数

end | - | 表示（可能有 const 限定的） V 的末尾的哨位
s | - | /*sentinel*/<false>

示例

本节未完成
原因：暂无示例


std::ranges::take_view<V>::size

< cpp‎ | ranges‎ | take view
constexpr auto size() requires ranges::sized_range<V>; | (1) | (C++20 起)
constexpr auto size() const requires ranges::sized_range<const V>; | (2) | (C++20 起)

返回元素数，它是传递给构造函数的计数与底层视图大小的较小者。

令 base_ 为底层视图， count_ 为传递给构造函数的元素数（若默认构造则为 ​0​ ）。等价于

auto n = ranges::size(base_);
return ranges::min(n, static_cast<decltype(n)>(count_));

参数

（无）

返回值

元素数。

示例

#include <ranges>
#include <iostream>

int main()
{
    constexpr int arr[] {1, 2, 3};

    for (int i = 0; i != 6; ++i) {
        const auto tv = std::ranges::take_view{arr, i};
        std::cout << tv.size() << ' ';
    }
}

输出：

0 1 2 3 3 3


std::ranges::take_view<V>::take_view

< cpp‎ | ranges‎ | take view
take_view() requires std::default_initializable<V> = default; | (1) | (C++20 起)
constexpr take_view( V base, ranges::range_difference_t<V> count ); | (2) | (C++20 起)

构造 take_view 。

1) 默认构造函数。值初始化底层视图并初始化计数为 0 。构造后 base() 返回 V() 的副本而 size() 返回 ​0​ 。
2) 以 std::move(base) 初始化底层视图并以 count 初始化计数。构造后 base() 返回 base 的副本而 size() 返回 count 与 ranges::size(base) 的较小者。

参数

base | - | 底层视图
count | - | 要收取的元素数

示例

打印首 n 个质数，用埃拉托色尼筛法生成起始。

#include <bit>
#include <bitset>
#include <iomanip>
#include <iostream>
#include <limits>
#include <ranges>

constexpr unsigned clog2(auto x) // ~ ⌈ log₂(x) ⌉
{
    return std::numeric_limits<decltype(x)>::digits - std::countl_zero(x);
}

template <unsigned Primes> struct Sieve
{
    bool operator()(int n) {
        if (n < 2) return false;
        if (n == 2) return true;
        if (n % 2 == 0 || bits.test(n / 2))
            return false;
        for (int i{n}, j{3}, k{}; (k = i * j) < size; j += 2)
            bits.set(k / 2);
        return true;
    }

    static constexpr int prime_numbers = Primes;

    // a(n) ~= n*(log(n) + log(log(n)));
    static constexpr int size = Primes*(clog2(Primes) + clog2(clog2(Primes)));

    // 仅保留奇数； 0 意味着它是质数
    private: std::bitset<size / 2 + 1> bits;
};

int main()
{
    Sieve<100> sieve{};
    auto primes_gen = std::views::iota(1)
                    | std::views::filter(sieve);

    auto primes = std::ranges::take_view{ primes_gen, sieve.prime_numbers };

    for (int n{1}; auto prime : primes) {
        std::cout << prime << (n++ % 10 ? ' ' : '\n');
    }

    std::cout
        << "\n" "sieve.prime_numbers: " << sieve.prime_numbers
        << "\n" "sieve.size: " << sieve.size
        << "\n" "sizeof(sieve): " << sizeof sieve << " bytes\n";
}

输出：

2 3 5 7 11 13 17 19 23 29
31 37 41 43 47 53 59 61 67 71
73 79 83 89 97 101 103 107 109 113
127 131 137 139 149 151 157 163 167 173
179 181 191 193 197 199 211 223 227 229
233 239 241 251 257 263 269 271 277 281
283 293 307 311 313 317 331 337 347 349
353 359 367 373 379 383 389 397 401 409
419 421 431 433 439 443 449 457 461 463
467 479 487 491 499 503 509 521 523 541

sieve.prime_numbers: 100
sieve.size: 1000
sizeof(sieve): 64 bytes


std::ranges::views::take_while, std::ranges::take_while_view

< cpp‎ | ranges
定义于头文件 <ranges>
template< ranges::view V, class Pred >

requires ranges::input_range<V> &&
std::is_object_v <Pred> &&
std::indirect_unary_predicate<const Pred, ranges::iterator_t<V>>

class take_while_view : public ranges::view_interface<take_while_view<V, Pred>>
 (1) (C++20 起)
namespace views {

inline constexpr /*unspecified*/ take_while = /*unspecified*/;

}
 (2) (C++20 起)
1) 范围适配器，表示来自底层序列，始于其起始，终于首个谓词对其返回 false 的元素的 view 。
2) 范围适配器对象。表达式 views::take_while(e, f) 对任何适合的子表达式 e 与 f 表达式等价于 take_while_view(e, f) 。

take_while_view 分别在底层视图 V 实现 contiguous_range、 random_access_range、 bidirectional_range、 forward_range 及 input_range 时实现该概念。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

成员函数

(构造函数)
(C++20)
 构造 take_while_view
(公开成员函数)
base
(C++20)
 返回底层（适配的）视图的副本
(公开成员函数)
pred
(C++20)
 返回到存储的谓词的引用
(公开成员函数)
begin
(C++20)
 返回指向起始的迭代器
(公开成员函数)
end
(C++20)
 返回表示末尾的哨位
(公开成员函数)
继承自 std::ranges::view_interface
empty
(C++20)
 返回视图是否为空。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
data
(C++20)
 返回派生视图的数据的地址。若视图的迭代器类型满足 contiguous_iterator 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator[]
(C++20)
 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

推导指引

嵌套类

sentinel
 哨位类型
(仅用于阐释的成员类模板)

示例

#include <ranges>
#include <iostream>

int main()
{
    for (int year : std::views::iota(2017)
                  | std::views::take_while([](int y) { return y <= 2020; })) {
        std::cout << year << ' ';
    }
    std::cout << '\n';

    const char idea[] {"Today is yesterday's tomorrow!.."};
    for (char x : std::ranges::take_while_view(idea, [](char c) { return c != '.'; })) {
        std::cout << x;
    }
    std::cout << '\n';
}

输出：

2017 2018 2019 2020
Today is yesterday's tomorrow!

参阅

ranges::take_viewviews::take (C++20) | 由另一 view 的前 N 个元素组成的 view (类模板) (范围适配器对象)
ranges::drop_while_viewviews::drop_while (C++20) | 由另一 view 跳过元素的起始序列，直至首个谓词返回 false 的元素组成的 view (类模板) (范围适配器对象)


std::ranges::take_while_view<V,Pred>::base

< cpp‎ | ranges‎ | take while view
constexpr V base() const& requires std::copy_constructible<V>; | (1) | (C++20 起)
constexpr V base() &&; | (2) | (C++20 起)

返回底层视图的副本。

1) 从底层视图复制构造结果。
2) 从底层视图移动构造结果。

参数

（无）

返回值

底层范围的副本。

示例

本节未完成
原因：暂无示例


std::ranges::take_while_view<V,Pred>::begin

< cpp‎ | ranges‎ | take while view
constexpr auto begin() requires (!__SimpleView<V>);
 (1) (C++20 起)
constexpr auto begin() const requires

ranges::range<const V> &&

std::indirect_unary_predicate<const Pred, ranges::iterator_t<const V>>;
 (2) (C++20 起)

返回指向视图首元素的迭代器。等效于在底层视图上调用 ranges::begin 。

若 V 为简单视图（即 V 与 const V 是拥有相同迭代器与哨位类型的视图）则重载 (1) 不参与重载决议。

参数

（无）

返回值

ranges::begin(base_) ，其中 base_ 为底层视图。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3450 | C++20 | const 重载可能返回不可与哨位比较的迭代器 | 已约束

参阅

end (C++20) | 返回表示末尾的哨位 (公开成员函数)
operator== (C++20) | 比较哨位与从 take_while_view::begin 返回的迭代器 (函数)


std::ranges::take_while_view 的推导指引

< cpp‎ | ranges‎ | take while view
定义于头文件 <ranges> |
template< class R, class Pred > take_while_view( R&&, Pred ) -> take_while_view<views::all_t<R>, Pred>; | (C++20 起)

为 std::ranges::take_while_view 提供推导指引以允许从 range 与谓词推导。

若 R 为 view ，则推导的类型为 take_while_view<R> ；否则推导的类型常为 take_while_view<ranges::ref_view<R>> 。

示例

本节未完成
原因：暂无示例


std::ranges::take_while_view<V,Pred>::end

< cpp‎ | ranges‎ | take while view
constexpr auto end() requires (!__SimpleView<V>);
 (1) (C++20 起)
constexpr auto end() const requires

ranges::range<const V> &&

std::indirect_unary_predicate<const Pred, ranges::iterator_t<const V>>;
 (2) (C++20 起)

返回表示视图末尾的哨位。

1) 等效于返回 /*sentinel*/<false>(ranges::end(base_), std::addressof (pred())) ，其中 base_ 代表底层视图。
2) 等效于返回 /*sentinel*/<true>(ranges::end(base_), std::addressof (pred())) ，其中 base_ 代表底层视图。

若 V 为简单视图（即 V 与 const V 是拥有相同迭代器与哨位类型的视图）则重载 (1) 不参与重载决议。

参数

（无）

返回值

表示视图末尾的哨位。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3450 | C++20 | const 重载可能返回不可与迭代器比较的哨位 | 已约束

参阅

begin (C++20) | 返回指向起始的迭代器 (公开成员函数)
operator== (C++20) | 比较哨位与从 take_while_view::begin 返回的迭代器 (函数)


std::ranges::take_while_view<V,Pred>::pred

< cpp‎ | ranges‎ | take while view
constexpr const Pred& pred() const; | (C++20 起)

返回到存储的谓词的引用。

若 *this 不存储谓词（例如在复制构造或移动构造 Pred 的对 *this 的赋值时抛出异常），则行为未定义。

参数

（无）

返回值

到存储的谓词的引用。

示例

本节未完成
原因：暂无示例


std::ranges::take_while_view<V,Pred>::sentinel

< cpp‎ | ranges‎ | take while view
template<bool Const> class /*sentinel*/; // 仅用于阐释 | (C++20 起)

take_while_view::end 的返回类型。

const 限定重载返回 /*sentinel*/<true> 类型。非 const 限定重载返回 /*sentinel*/<false> 类型。

此类模板的名称（此处示为 sentinel ）是未指定的。

典型实现保有二个数据成员：表示底层视图末尾的哨位，及指向谓词的指针。

成员类型

成员类型 | 定义
Base(私有) | 若 Const 为 true 则为 const V ，否则为 V 。名字仅用于阐释

成员函数

(构造函数) (C++20) | 构造哨位 (公开成员函数)
base (C++20) | 返回底层哨位 (公开成员函数)

非成员函数

operator==
(C++20)
 比较哨位与从 take_while_view::begin 返回的迭代器
(函数)


std::ranges::take_while_view<V,Pred>::sentinel<Const>::base

< cpp‎ | ranges‎ | take while view‎ | sentinel
constexpr ranges::sentinel_t<Base> base() const; | (C++20 起)

返回底层哨位。

参数

（无）

返回值

底层哨位的副本

示例

本节未完成
原因：暂无示例


operator==(ranges::take_while_view::sentinel)

< cpp‎ | ranges‎ | take while view‎ | sentinel
friend constexpr bool operator==( const ranges::iterator_t<Base>& x,
const /*sentinel*/& y);
 (C++20 起)

比较 take_while_view::/*sentinel*/ 与指向（可能为 const 限定的）视图 V 中的迭代器。迭代器常从调用 take_while_view::begin 获得。

若 x 与 y 的底层哨位（即 y.base() ）比较相等或谓词在应用到 *x 时返回 false 则返回 true 。

此函数对通常无限定或有限定查找不可见，而只能在 take_while_view::sentinel<Const> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

参数

x | - | 要比较的迭代器
y | - | 要比较的哨位

返回值

y.end_ == x || ! std::invoke (*y.pred_, *x) ，其中 end_ 代表存储的哨位而 pred_ 代表存储的指向谓词的指针。

示例

本节未完成
原因：暂无示例


std::ranges::take_while_view<V,Pred>::sentinel<Const>::sentinel

< cpp‎ | ranges‎ | take while view‎ | sentinel
/*sentinel*/() = default;
 (1) (C++20 起)
constexpr explicit /*sentinel*/( ranges::sentinel_t<Base> end, const Pred* pred );
 (2) (C++20 起)
constexpr /*sentinel*/( /*sentinel*/<!Const> s )

requires Const &&

std::convertible_to<ranges::sentinel_t<V>, ranges::sentinel_t<Base>>;
 (3) (C++20 起)

构造哨位。

1) 默认构造函数。值初始化底层哨位和指向谓词的指针。
2) 以 end 初始化底层哨位并以 pred 初始化指向谓词的指针。
3) 从 /*sentinel*/<false> 转换到 /*sentinel*/<true> 。复制构造对应的成员。

参数

end | - | 表示（可能为 const 限定的） V 末尾的哨位
pred | - | 指向谓词的指针
i | - | /*sentinel*/<false>

示例

本节未完成
原因：暂无示例


std::ranges::take_while_view<V,Pred>::take_while_view

< cpp‎ | ranges‎ | take while view
take_while_view() requires std::default_initializable<V> &&
std::default_initializable<Pred> = default;
 (1) (C++20 起)
constexpr take_while_view( V base, Pred pred );
 (2) (C++20 起)

构造 take_while_view 。

1) 默认构造函数。值初始化底层哨位与谓词。
2) 从 base 移动构造底层视图并从 pred 移动构造谓词。

参数

base | - | 底层视图
fun | - | 谓词

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | 若 Pred 非 default_initializable ， 则默认构造函数构造不含 Pred 的 take_while_view | take_while_view 亦非 default_initializable


std::ranges::views::transform, std::ranges::transform_view

< cpp‎ | ranges
定义于头文件 <ranges>
template< ranges::input_range V,

std::copy_constructible F >
requires ranges::view<V> &&
std::is_object_v <F> &&
std::regular_invocable<F&, ranges::range_reference_t<V>> &&
/* invoke_result_t<F&, range_reference_t<V>>& 是合法类型 */

class transform_view : public ranges::view_interface<transform_view<V, F>>
 (1) (C++20 起)
namespace views {

inline constexpr /*unspecified*/ transform = /*unspecified*/;

}
 (2) (C++20 起)
1) 表示底层序列应用变换函数到每个元素后的 view 的范围适配器。
2) 范围适配器对象。对每个适合的表达式 e 与 f ，表达式 views::transform(e, f) 表达式等价于 transform_view(e, f) 。

transform_view 分别在底层视图 V 实现 random_access_range、 bidirectional_range、 forward_range、 input_range、 common_range 与 sized_range 时实现同一概念。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

成员函数

(构造函数)
(C++20)
 构造 transform_view
(公开成员函数)
base
(C++20)
 返回底层（适配的）视图的副本
(公开成员函数)
begin
(C++20)
 返回指向起始的迭代器
(公开成员函数)
end
(C++20)
 返回指向末尾的迭代器或哨位
(公开成员函数)
size
(C++20)
 返回元素数，只要底层（适配的）范围满足 sized_range
(公开成员函数)
继承自 std::ranges::view_interface
empty
(C++20)
 返回视图是否为空。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator bool
(C++20)
 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。
(std::ranges::view_interface<D> 的公开成员函数)
front
(C++20)
 返回派生视图中的首元素。若视图满足 forward_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
back
(C++20)
 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)
operator[]
(C++20)
 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。
(std::ranges::view_interface<D> 的公开成员函数)

推导指引

嵌套类

iterator (C++20) | 迭代器类型 (仅用于阐释的成员类模板)
sentinel (C++20) | 哨位类型 (仅用于阐释的成员类模板)

示例

#include <array>
#include <cstdio>
#include <ranges>
#include <string>

class Transcoder {
    static constexpr std::array r{
        0x02,-0x02,-0x42, 0x05, 0x04, 0x05, 0x04,-0x02,
        0x00,-0x0a, 0x06,-0x04, 0x00, 0x0c, 0x03,-0x06,
    };
    decltype(r.size()) p{}, q{};
public:
    char operator() (int x) {
        ! (p|q)
        ? (99 == x ? x += r[p++]  : x -= r[q++])
        : (0 < p && p < r.size()) ? x += r[p++]
        : (0 < q && q < r.size()) ? x -= r[q++]
        : (0)
        ;
        return x;
    }
};

int main()
{
    auto show = [](const char x) { std::putchar(x); };

    std::string in{ "cppreference.com\n" };
    std::ranges::for_each(in, show);

    std::string out;
    std::ranges::copy(
        std::ranges::views::transform(in, Transcoder{}),
        std::ranges::back_inserter(out));
    std::ranges::for_each(out, show);

    auto view = std::transform_view{ out, Transcoder{} };
    std::ranges::for_each(view, show);
    std::ranges::for_each(view, show);
}

输出：

cppreference.com
en.wikipedia.org
cppreference.com
en.wikipedia.org

参阅

ranges::transform
(C++20)
 将一个函数应用于某一范围的各个元素
(niebloid)


std::ranges::transform_view<V,F>::base

< cpp‎ | ranges‎ | transform view
constexpr V base() const& requires std::copy_constructible<V>; | (1) | (C++20 起)
constexpr V base() &&; | (2) | (C++20 起)

返回底层视图的副本

1) 从底层视图复制构造结果。
2) 从底层视图移动构造结果。

参数

（无）

返回值

底层视图的副本。

示例

本节未完成
原因：暂无示例


std::ranges::transform_view<V,F>::begin

< cpp‎ | ranges‎ | transform view
constexpr /*iterator*/<false> begin();
 (1) (C++20 起)
constexpr /*iterator*/<true> begin() const

requires ranges::range<const V> &&

std::regular_invocable<const F&, ranges::range_reference_t<const V>>;
 (2) (C++20 起)

返回指向 transform_view 首元素的迭代器 。

1) 等价于 return /*iterator*/<false>{*this, ranges::begin(base_)}; ，其中 base_ 是底层视图。
2) 等价于 return /*iterator*/<true>{*this, ranges::begin(base_)}; ，其中 base_ 是底层视图。

参数

（无）

返回值

指向首元素的迭代器。

示例

本节未完成
原因：暂无示例

参阅

end
(C++20)
 返回指向末尾的迭代器或哨位
(公开成员函数)


std::ranges::transform_view 的推导指引

< cpp‎ | ranges‎ | transform view
template< class R, class F > transform_view( R&&, F ) -> transform_view<views::all_t<R>, F>; | (C++20 起)

为 std::ranges::transform_view 提供一个推导指引以允许从 range 和变换函数推导。

若 R 为 view ，则推导的类型是 transform_view<R, F> ；否则推导的类型经常为 transform_view<ranges::ref_view<R>, F> 。

示例

本节未完成
原因：暂无示例


std::ranges::transform_view<V,F>::end

< cpp‎ | ranges‎ | transform view
constexpr /*sentinel*/<false> end();
 (1) (C++20 起)
constexpr /*iterator*/<false> end() requires ranges::common_range<V>;
 (2) (C++20 起)
constexpr /*sentinel*/<true> end() const

requires ranges::range<const V> &&

std::regular_invocable<const F&, ranges::range_reference_t<const V>>;
 (3) (C++20 起)
constexpr /*iterator*/<true> end() const

requires ranges::common_range<const V> &&

std::regular_invocable<const F&, ranges::range_reference_t<const V>>;
 (4) (C++20 起)

返回表示 transform_view 末尾的哨位或迭代器。

令 base_ 表示底层视图：

1) 等价于 return /*sentinel*/<false>{ranges::end(base_)}; 。
2) 等价于 return /*iterator*/<false>{*this, ranges::end(base_)}; 。
3) 等价于 return /*sentinel*/<true>{ranges::end(base_)}; 。
4) 等价于 return /*iterator*/<true>{*this, ranges::end(base_)}; 。

参数

（无）

返回值

1,3) 与尾迭代器比较相等的哨位。
2,4) 指向末元素后一元素的迭代器。

注解

end() 返回迭代器当且仅当底层视图为 common_range ： tranform_view<V,F> 凡在 V 实现 common_range 时亦如此。

示例

本节未完成
原因：暂无示例

参阅

begin
(C++20)
 返回指向起始的迭代器
(公开成员函数)


std::ranges::transform_view<V,F>::iterator

< cpp‎ | ranges‎ | transform view
template< bool Const > class /*iterator*/; | (C++20 起)

transform_view::begin 的返回类型，及底层视图为 common_range 时 transform_view::end 的返回类型。

const 限定重载返回 /*iterator*/<true> 。非 const 限定重载返回 /*iterator*/<false> 。

此类模板的名称（此处示为 iterator ）是未指定的。

典型实现保有二个数据成员：指向（可为 const 限定的） V 中的迭代器与指向亲 transform_view 的指针。

成员类型

成员类型 | 定义
Parent(私有) | 若 Const 为 true 则为 const ranges::transform_view<V, F> ，否则为 ranges::transform_view<V, F> 。名称仅用于阐释
Base(私有) | 若 Const 为 true 则为 const V ，否则为 V 。名称仅用于阐释
iterator_concept 若 Base 实现 random_access_range 则为 std::random_access_iterator_tag ，
若 Base 实现 bidirectional_range 则为 std::bidirectional_iterator_tag ，
若 Base 实现 forward_range 则为 std::forward_iterator_tag ，
否则为 std::input_iterator_tag
iterator_category 若 Base 不实现 forward_range 则不定义。
若 std::invoke_result_t<F&, ranges::range_reference_t<Base>> 不是左值引用则为 std::input_iterator_tag 。
否则，令 C 为 std::iterator_traits <ranges::iterator_t<Base>>::iterator_category ，若 C 为 std::contiguous_iterator_tag 则该类型为 std::random_access_iterator_tag ；否则该类型为 C 。
value_type | std::remove_cvref_t<std::invoke_result_t<F&, ranges::range_reference_t<Base>>>
difference_type | ranges::range_difference_t<Base>

成员函数

(构造函数) (C++20) | 构造迭代器 (公开成员函数)
base (C++20) | 返回底层迭代器 (公开成员函数)
operator* (C++20) | 访问变换的元素 (公开成员函数)
operator[] (C++20) | 按下标访问元素 (公开成员函数)
operator++operator++(int)operator--operator--(int)operator+=operator-= (C++20) | 推进或减少底层迭代器 (公开成员函数)

非成员函数

operator==operator<operator>operator<=operator>=operator<=> (C++20) | 比较底层迭代器 (函数)
operator+operator- (C++20) | 进行迭代器算术 (函数)
iter_move (C++20) | 获得到变换的元素的右值引用 (函数)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2259R1 | C++20 | 始终定义成员类型 iterator_category | 仅若 Base 实现 forward_range 才定义
LWG 3555 | C++20 | iterator_concept 的定义忽略 const | 使之考虑


std::ranges::transform_view<V,F>::iterator<Const>::base

< cpp‎ | ranges‎ | transform view‎ | iterator
constexpr const ranges::iterator_t<Base>& base() const & noexcept; | (1) | (C++20 起)
constexpr ranges::iterator_t<Base> base() &&; | (2) | (C++20 起)

返回底层迭代器。

1) 返回到底层迭代器的引用。
2) 从底层迭代器移动构造结果。

参数

（无）

返回值

1) 到底层迭代器的引用。
2) 从底层迭代器移动构造的迭代器。

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <ranges>

int main()
{
    const auto v = { 0, 1, 2, 3, 4 };
    auto x2 = [](int x) { return x << 1; };
    std::ranges::transform_view tv{ v, x2 };
    std::ostream_iterator<int> ostr{ std::cout, " " };

    std::ranges::copy(v, ostr), std::cout << '\n';
    std::ranges::copy(tv.base(), ostr), std::cout << '\n';
    std::ranges::copy(tv, ostr), std::cout << '\n';
}

输出：

0 1 2 3 4
0 1 2 3 4
0 2 4 6 8

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3533 | C++20 | base 的 const& 重载返回底层迭代器的副本 | 返回引用
LWG 3593 | C++20 | base 的 const& 重载可以不是 noexcept | 使之为 noexcept


iter_move(ranges::transform_view::iterator)

< cpp‎ | ranges‎ | transform view‎ | iterator
friend constexpr decltype(auto) iter_move( const /*iterator*/& i ) noexcept(/* see below */); | (C++20 起)

若 *i 为左值引用则返回 std::move(*i) ，否则返回 *i 。

此函数对通常无限定或有限定查找不可见，而只能在 transform_view::iterator<Const> 为参数的关联类时由实参依赖查找找到。

参数

i - 迭代器

返回值

若 *i 为左值引用则为 std::move(*i) ，否则为 *i 。

异常

noexcept 说明：
noexcept(noexcept( std::invoke (*i.parent_->fun_, *i.current_)))
，其中 *i.parent_->fun_ 代表变换函数， i.current_ 代表底层迭代器。


std::ranges::transform_view<V,F>::iterator<Const>::iterator

< cpp‎ | ranges‎ | transform view‎ | iterator
/*iterator*/() requires std::default_initializable<ranges::iterator_t<Base>> = default;
 (1) (C++20 起)
constexpr /*iterator*/( Parent& parent, ranges::iterator_t<Base> current );
 (2) (C++20 起)
constexpr /*iterator*/( /*iterator*/<!Const> i )

requires Const &&

std::convertible_to<ranges::iterator_t<V>, ranges::iterator_t<Base>>;
 (3) (C++20 起)

构造迭代器。

1) 默认构造函数。值初始化底层迭代器，并以 nullptr 初始化指向亲 transform_view 的指针。
2) 以 std::move(current) 初始底层迭代器，并以 std::addressof (parent) 初始化指向亲的指针。
3) 从 /*iterator*/<false> 转换到 /*iterator*/<true> 。移动构造对应的成员。

参数

parent | - | （可为 const 限定的） std::ranges::transform_view
current | - | 指向（可为 const 限定的） V 中的迭代器
i | - | /*iterator*/<false>

示例

本节未完成
原因：暂无示例


std::ranges::transform_view<V,F>::iterator<Const>::operator*

< cpp‎ | ranges‎ | transform view‎ | iterator
constexpr decltype(auto) operator*() const; | (C++20 起)

返回变换后的元素。

等价地返回 std::invoke (*parent_->fun_, *current_) ，其中 *parent_->fun_ 是存储于亲 transform_view 的变换函数，而 current_ 是指向 V 中的底层迭代器。

参数

（无）

返回值

变换后的元素。

注解

不提供 operator-> 。

若指向亲 transform_view 的指针为空（例如若 *this 为默认构造），或若亲 transform_view 不保有变换函数（例如若亲 transform_view 为默认构造，而变换函数不可默认构造）。

示例

本节未完成
原因：暂无示例


std::ranges::transform_view<V,F>::iterator<Const>::operator++,--,+=,-=

< cpp‎ | ranges‎ | transform view‎ | iterator
constexpr /*iterator*/& operator++();
 (1) (C++20 起)
constexpr void operator++( int );
 (2) (C++20 起)
constexpr /*iterator*/ operator++( int )
requires ranges::forward_range<Base>;
 (3) (C++20 起)
constexpr /*iterator*/& operator--()
requires ranges::bidirectional_range<Base>;
 (4) (C++20 起)
constexpr /*iterator*/ operator--( int )
requires ranges::bidirectional_range<Base>;
 (5) (C++20 起)
constexpr /*iterator*/& operator+=( difference_type n )
requires ranges::random_access_range<Base>;
 (6) (C++20 起)
constexpr /*iterator*/& operator-=( difference_type n )
requires ranges::random_access_range<Base>;
 (7) (C++20 起)

增加或减少迭代器。

令 current_ 为底层迭代器。

1) 等价于 ++current_; return *this;
2) 等价于 ++current_;
3) 等价于 auto tmp = *this; ++*this; return tmp;
4) 等价于 --current_; return *this;
5) 等价于 auto tmp = *this; --*this; return tmp;
6) 等价于 current_ += n; return *this;
7) 等价于 current_ -= n; return *this;

参数

n - 相对于当前位置的位置

返回值

1,4,6,7) *this
3,5) 修改前作出的 *this 的副本


operator+,-(ranges::transform_view::iterator)

< cpp‎ | ranges‎ | transform view‎ | iterator
friend constexpr /*iterator*/ operator+( /*iterator*/ i, difference_type n ) requires ranges::random_access_range<Base>; | (1) | (C++20 起)
friend constexpr /*iterator*/ operator+( difference_type n, /*iterator*/ i ) requires ranges::random_access_range<Base>; | (2) | (C++20 起)
friend constexpr /*iterator*/ operator-( /*iterator*/ i, difference_type n ) requires ranges::random_access_range<Base>; | (3) | (C++20 起)
friend constexpr difference_type operator-( const /*iterator*/& x, const /*iterator*/& y ) requires ranges::random_access_range<Base>; | (4) | (C++20 起)
1,2) 返回增加 n 的 i 。
3) 返回减少 n 的 i 。
4) 返回 x 与 y 间的距离。

这些函数对通常无限定或有限定查找不可见，而只能在 transform_view::iterator<Const> 为参数的关联类时由实参依赖查找找到。

返回值

令 parent_ 代表指向亲 transform_view 的指针， current_ 代表底层迭代器。

1,2) /*iterator*/{*i.parent_, i.current_ + n}
3) /*iterator*/{*i.parent_, i.current_ - n}
4) x.current_ - y.current_

示例

本节未完成
原因：暂无示例


std::ranges::transform_view<V,F>::iterator<Const>::operator[]

< cpp‎ | ranges‎ | transform view‎ | iterator
constexpr decltype(auto) operator[]( difference_type n ) const requires ranges::random_access_range<Base>; | (C++20 起)

返回变换后的位于相对位置的元素。

等效于返回 std::invoke (*parent_->fun_, current_[n]) ，其中 *parent_->fun_ 是存储于亲 transform_view 的变换函数，而 current_ 是指向 V 中的底层迭代器。

参数

n - 相对于当前位置的位置。

返回值

变换后的元素

示例

本节未完成
原因：暂无示例


operator==,<,>,<=,>=,<=>(ranges::transform_view::iterator)

< cpp‎ | ranges‎ | transform view‎ | iterator
friend constexpr bool operator==( const /*iterator*/& x, const /*iterator*/& y )
requires std::equality_comparable<ranges::iterator_t<Base>>;
 (1) (C++20 起)
friend constexpr bool operator<( const /*iterator*/& x, const /*iterator*/& y )
requires ranges::random_access_range<Base>;
 (2) (C++20 起)
friend constexpr bool operator>( const /*iterator*/& x, const /*iterator*/& y )
requires ranges::random_access_range<Base>;
 (3) (C++20 起)
friend constexpr bool operator<=( const /*iterator*/& x, const /*iterator*/& y )
requires ranges::random_access_range<Base>;
 (4) (C++20 起)
friend constexpr bool operator>=( const /*iterator*/& x, const /*iterator*/& y )
requires ranges::random_access_range<Base>;
 (5) (C++20 起)
friend constexpr auto operator<=>( const /*iterator*/& x, const /*iterator*/& y )

requires ranges::random_access_range<Base> &&

std::three_way_comparable<ranges::iterator_t<Base>>;
 (6) (C++20 起)

比较底层迭代器。

1) 等价于 return x.current_ == y.current_; ，其中 current_ 是底层迭代器。
2) 等价于 return x.current_ < y.current_; ，其中 current_ 是底层迭代器。
3) 等价于 return y < x;
4) 等价于 return !(y < x);
5) 等价于 return !(x < y);
6) 等价于 return x.current_ <=> y.current_; ，其中 current_ 是底层迭代器。

这些函数对通常无限定或有限定查找不可见，而只能在 std::ranges::transform_view::iterator<Const> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

参数

x, y - 要比较的迭代器

返回值

比较结果


std::ranges::transform_view<V,F>::sentinel

< cpp‎ | ranges‎ | transform view
template< bool Const > class /*sentinel*/ | (C++20 起)

底层类型非 common_range 时 tranform_view::end 的返回类型。

const 限定重载返回 /*sentinel*/<true> 。非 const 限定重载返回 /*sentinel*/<false> 。

此类模板的名称（此处示为 /*sentinel*/ ）是未指定的。

典型实现仅保有一个数据成员：从（可为 const 限定的） V 获得的哨位。

成员类型

成员类型 | 定义
Parent(私有) | 若 Const 为 true 则为 const transform_view<V, F> ，否则为 transform_view<V, F> 。名称仅用于阐释
Base(私有) | 若 Const 为 true 则为 const V ，否则为 V 。名称仅用于阐释

成员函数

(构造函数) (C++20) | 构造哨位 (公开成员函数)
base (C++20) | 返回底层哨位 (公开成员函数)

非成员函数

operator== (C++20) | 比较哨位与从 transform_view::begin 返回的迭代器 (函数)
operator- (C++20) | 计算哨位与从 transform_view::begin 返回的迭代器的距离 (函数)


std::ranges::transform_view<V,F>::sentinel<Const>::base

< cpp‎ | ranges‎ | transform view‎ | sentinel
constexpr ranges::sentinel_t<Base> base() const; | (C++20 起)

返回底层哨位的副本。

参数

（无）

返回值

底层哨位的副本。

示例

本节未完成
原因：暂无示例


operator-(ranges::transform_view::sentinel)

< cpp‎ | ranges‎ | transform view‎ | sentinel
friend constexpr ranges::range_difference_t<Base>

operator-( const /*iterator*/<Const>& x, const /*sentinel*/& y )

requires std::sized_sentinel_for<ranges::sentinel_t<Base>, ranges::iterator_t<Base>>;
 (1) (C++20 起)
friend constexpr ranges::range_difference_t<Base>

operator-( const /*sentinel*/& y, const /*iterator*/<Const>& x )

requires std::sized_sentinel_for<ranges::sentinel_t<Base>, ranges::iterator_t<Base>>;
 (2) (C++20 起)

计算 x 的底层迭代器与 y 的底层哨位间的距离。

这些函数对通常无限定或有限定查找不可见，而只能在 transform_view::sentinel<Const> 为参数的关联类时由实参依赖查找找到。

参数

x | - | 迭代器
y | - | 哨位

返回值

令 current_ 代表底层迭代器， end_ 代表底层哨位。

1) x.current_ == y.end_
2) y.end_ == x.current_


operator==(ranges::transform_view::sentinel)

< cpp‎ | ranges‎ | transform view‎ | sentinel
friend constexpr bool operator==( const /*iterator*/<Const>& x, const /*sentinel*/& y ); | (C++20 起)

比较 x 的底层迭代器与 y 的底层哨位。

此函数对通常无限定或有限定查找不可见，而只能在 transform_view::sentinel<Const> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

参数

x | - | 要比较的迭代器
y | - | 要比较的哨位

返回值

x.current_ == y.end_ ，其中 current_ 代表底层迭代器， end_ 代表底层哨位。

示例

本节未完成
原因：暂无示例


std::ranges::transform_view<V,F>::sentinel<Const>::sentinel

< cpp‎ | ranges‎ | transform view‎ | sentinel
/*sentinel*/() = default;
 (1) (C++20 起)
constexpr explicit /*sentinel*/( ranges::sentinel_t<Base> end );
 (2) (C++20 起)
constexpr /*sentinel*/( /*sentinel*/<!Const> i )

requires Const &&

std::convertible_to<ranges::sentinel_t<V>, ranges::sentinel_t<Base>>;
 (3) (C++20 起)

构造哨位。

1) 默认构造函数。值初始化底层哨位。
2) 以 end 初始化底层哨位。
3) 从 /*sentinel*/<false> 转换到 /*sentinel*/<true> 。移动构造对应的成员。

参数

end | - | 表示（可为 const 限定的） V 的末尾的哨位
i | - | /*sentinel*/<false>

示例

本节未完成
原因：暂无示例


std::ranges::transform_view<V,F>::size

< cpp‎ | ranges‎ | transform view
constexpr auto size() requires ranges::sized_range<V>; | (C++20 起)
constexpr auto size() const requires ranges::sized_range<const V>; | (C++20 起)

返回元素数。

返回 ranges::size(base_) ，其中 base_ 是底层视图。=

参数

（无）

返回值

元素数。=

注解

若 V 不实现 forward_range ，则 size() 在调用 begin() 后可能非良定义。

示例

本节未完成
原因：暂无示例


std::ranges::transform_view<V,F>::transform_view

< cpp‎ | ranges‎ | transform view
transform_view() requires std::default_initializable<V> &&
std::default_initializable<F> = default;
 (1) (C++20 起)
constexpr transform_view( V base, F fun );
 (2) (C++20 起)

构造 transform_view 。

1) 默认构造函数。值初始化底层视图与变换函数。
2) 从 base 移动构造视图并从 fun 移动构造变换函数。

参数

base | - | 视图
fun | - | 变换函数

示例

演示使用 1 的反正切的级数展开的 π 近似：
atan(1) = π/4 ~ 1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + ...

#include <iomanip>
#include <iostream>
#include <numbers>
#include <ranges>

int main()
{
    std::cout << std::setprecision(15) << std::fixed;
    auto atan1term = std::ranges::views::transform(
        [](int n) { return ((n % 2) ? -1 : 1) * 1.0 / (2 * n + 1); }
    );
    for (const int iterations : {1, 2, 3, 4, 5, 10, 100, 1000, 1'000'000}) {
        double accum{0.0};
        for (double term : std::ranges::views::iota(0, iterations) | atan1term) {
            accum += term;
        }
        std::cout << "π ~ " << 4 * accum << " (iterations: " << iterations << ")\n";
    }
    std::cout << "π ~ " << std::numbers::pi << " (std::numbers::pi)\n";
}

可能的输出：

π ~ 4.000000000000000 (iterations: 1)
π ~ 2.666666666666667 (iterations: 2)
π ~ 3.466666666666667 (iterations: 3)
π ~ 2.895238095238096 (iterations: 4)
π ~ 3.339682539682540 (iterations: 5)
π ~ 3.041839618929403 (iterations: 10)
π ~ 3.131592903558554 (iterations: 100)
π ~ 3.140592653839794 (iterations: 1000)
π ~ 3.141591653589774 (iterations: 1000000)
π ~ 3.141592653589793 (std::numbers::pi)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | 若 F 非 default_initializable ，则默认构造函数构造不含 F 的 transform_view | transform_view 亦非 default_initializable


std::ranges::views::values, std::ranges::values_view

< cpp‎ | ranges
定义于头文件 <ranges>
template<class R>
using values_view = ranges::elements_view<R, 1>;
 (1) (C++20 起)
namespace views {

inline constexpr auto values = ranges::elements<1>;

}
 (2) (C++20 起)

接收元组式值（例如 std::tuple 或 std::pair ）的 view ，并产生值类型为被适配的视图的值的第二个元素的视图。

1) ranges::elements_view<R, 1> 的别名。
2) 范围适配器对象。表达式 views​::values(e) 表达式对任何适合的子表达式 e 表达式等价于 values_view<views​::​all_t<decltype((e))>>{e} 。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

注解

values_view 能用于从关联容器提取值，例如 for (auto const& value : std::views::values(map)) { /*...*/ } 。

示例

#include <iostream>
#include <ranges>
#include <map>

int main()
{
    std::map<char, int> map{ {'A', 1}, {'B', 2}, {'C', 3}, {'D', 4}, {'E', 5} };

    auto odd = [](int x) { return 0 != (x & 1); };

    std::cout << "Odd values in the map: ";
    for (int value : map | std::views::values | std::views::filter(odd))
        std::cout << value << ' ';
}

输出：

Odd values in the map: 1 3 5

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3563 | C++20 | values_view 由于使用 views::all_t 无法参与 CTAD | 移除 views::all_t

参阅

ranges::keys_viewviews::keys (C++20) | 选取 pair 式值组成的 view 并产生每个 pair 的第一元素的 view (类模板) (范围适配器对象)
ranges::elements_viewviews::elements (C++20) | 选取元组式值组成的 view 和数值 N ，产生每个 tuple 的第 N 个元素的 view (类模板) (范围适配器对象)
slice | valarray 的 BLAS 式切片：起始下标、长度、跨度 (类)


std::ranges::view, std::ranges::enable_view, std::ranges::view_base

< cpp‎ | ranges
定义于头文件 <ranges> |  |
template<class T> concept view = ranges::range<T> && std::movable<T> && ranges::enable_view<T>; | (1) | (C++20 起)
template<class T> inline constexpr bool enable_view = std::derived_from<T, view_base> || /*is-derived-from-view-interface*/<T>; | (2) | (C++20 起)
struct view_base { }; | (3) | (C++20 起)
1) view 概念指定拥有适合用于构造范围适配器管道的语义属性的 range 类型（例如一对迭代器或按需创建其元素的生成器 range 。
2) enable_view 变量模板用于指示 range 是否为 view 。 /*is-derived-from-view-interface*/<T> 为 true 当且仅当 T 准确拥有一个对于某类型 U 的公开基类 ranges::view_interface<U> ，且 T 无任何对于其他类型 V 的基类 ranges::view_interface<V> 。
用户可对要实现 view 的无 cv 限定的程序定义类型特化 enable_view 为 true ，而对不实现的类型特化为 false 。这些特化应当可用于常量表达式并拥有 const bool 类型。
3) 从 view_base 派生会允许 range 类型实现 view 。

语义要求

1) T 实现 view ，仅若：
  • T 的移动构造拥有常数时间复杂度，且
  • 若从保有 \(\scriptsize M\)M 个元素的 T 对象作出 \(\scriptsize N\)N 次复制与/或移动，则这 \(\scriptsize N\)N 个对象拥有 \(\scriptsize \mathcal{O}{(N+M)}\)𝓞(N+M) 时间复杂度析构（这蕴含被移动的 view 对象拥有 \(\scriptsize \mathcal{O}{(1)}\)𝓞(1) 析构），且
  • std::copy_constructible<T> 为 false ，或 T 的复制构造拥有常数时间复杂度，且
  • std::copyable<T> 为 false ，或 T 拥有不多于析构后随复制构造的时间复杂度。

注解

view 类型的示例为：

  • 包装一对迭代器的 range 类型，例如 std::ranges::subrange<I> 。
  • 通过 std::shared_ptr 持有其元素并与所有副本共享所有权的 range 类型。
  • 按需生成其元素的 range 类型，例如 std::ranges::iota_view 。

诸如 std::vector < std::string > 的可复制容器通常不符合 view 的语义要求，因为复制容器会复制其所有元素，这无法在常数时间内完成。

视图原先被描述成可廉价复制并且为非占有的范围，不过不要求要实现 view 的类型为可复制或非占有。然而，它必须仍然有廉价的复制（凡在可能时）、移动及析构，以令范围适配器不会拥有不期待的复杂度。

实现 movable 和 range 的类型默认被认为是视图，若它公开且无歧义地派生自 view_base 或恰好一个 ranges::view_interface 的特化。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2325R3 | C++20 | view 要求 default_initializable | 不要求
LWG 3549 | C++20 | enable_view 不检测来自 view_interface 的继承 | 检测
P2415R2 | C++20 | 析构的时间复杂度上的限制过于严格 | 已放松


std::ranges::views::counted

< cpp‎ | ranges
定义于头文件 <ranges> |
inline constexpr /*unspecified*/ counted = /*unspecified*/; | (C++20 起)
调用签名 |
template< class Iterator, class DifferenceType > requires /* see below */ constexpr /*span-or-subrange*/ counted( Iterator&& it, DifferenceType&& count ); |

counted 视图是表示某迭代器 i 与非负整数 n 的计数范围 [i, n) 的元素的 view 。

计数范围 [i, n) 是始于以 i 所指向的元素，到若存在则为应用 n 次 ++i 的结果所指向的元素为止，但不包含该元素的 n 个元素。

若 n == 0 ，则计数范围合法且为空。否则，计数范围仅若 n 为正， i 可解引用，且 [++i, --n) 为合法的计数范围才合法。

正式而言，若 it 与 count 为表达式， T 为 std::decay_t <decltype((it))> ，而 D 为 std::iter_difference_t<T> ，则

若 T 实现 input_or_output_iterator 且 decltype((count)) 实现 std::convertible_to<D> ，
  • 否则，若 T 实现 contiguous_iterator ，则 views::counted(it, count) 表达式等价于 std::span(it, static_cast< std::size_t >(static_cast<D>(count))) ，否则
  • 若 T 实现 random_access_iterator ，则 views::counted(it, count) 表达式等价于 ranges::subrange(it, it + static_cast<D>(count)) ，否则
  • views::counted(it, count) 表达式等价于 ranges::subrange(std::counted_iterator(it, count), std::default_sentinel)
否则 views::counted(it, count) 非良构。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 views::counted 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __counted_fn 表示其类型的 cv 无限定版本。

__counted_fn 的所有实例均相等。在相同参数上调用类型 __counted_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 views::counted 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 views::counted 的参数要求，则 __counted_fn 实现 std::invocable<__counted_fn, Args...>、 std::invocable<const __counted_fn, Args...>、 std::invocable<__counted_fn&, Args...> 及 std::invocable<const __counted_fn&, Args...> 。否则， __counted_fn 的函数调用运算符不参与重载决议。

示例

#include <ranges>
#include <iostream>

int main()
{
    const int a[] = {1, 2, 3, 4, 5, 6, 7};
    for(int i : std::views::counted(a, 3))
        std::cout << i << ' ';
    std::cout << '\n';

    const auto il = {1, 2, 3, 4, 5};
    for (int i : std::views::counted(il.begin() + 1, 3))
        std::cout << i << ' ';
    std::cout << '\n';
}

输出：

1 2 3
2 3 4

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2393R1 | C++20 | 从整数类类型到 size_t 的隐式转换可能非法 | 使之为显式

参阅

ranges::subrange (C++20) | 将迭代器/哨位对结合为一个 view (类模板)
counted_iterator (C++20) | 对到范围结尾距离进行跟踪的迭代器适配器 (类模板)
ranges::countranges::count_if (C++20)(C++20) | 返回满足指定判别标准的元素数 (niebloid)


std::ranges::view_interface

< cpp‎ | ranges
定义于头文件 <ranges>
template<class D>

requires std::is_class_v <D> && std::same_as<D, std::remove_cv_t <D>>

class view_interface;
 (C++20 起)

std::ranges::view_interface 是用于定义范围接口的辅助类模板。

view_interface 常以 CRTP 使用：

class my_view : public std::ranges::view_interface<my_view> {
public:
    auto begin() const { /*...*/ }
    auto end() const { /*...*/ }
    // 若 begin() 返回向前迭代器且 end() 返回其哨位则提供 empty() 。
};

成员函数

empty (C++20) | 返回视图是否为空。若视图满足 forward_range 则提供。 (公开成员函数)
operator bool (C++20) | 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。 (公开成员函数)
data (C++20) | 返回派生视图的数据的地址。若视图的迭代器类型满足 contiguous_iterator 则提供。 (公开成员函数)
size (C++20) | 返回派生视图中的元素数。若视图满足 forward_range 且其哨位与迭代器类型满足 sized_sentinel_for 则提供。 (公开成员函数)
front (C++20) | 返回派生视图中的首元素。若视图满足 forward_range 则提供。 (公开成员函数)
back (C++20) | 返回派生视图中的末元素。若视图满足 bidirectional_range 与 common_range 则提供。 (公开成员函数)
operator[] (C++20) | 返回派生视图中的第 n 个元素。若视图满足 random_access_range 则提供。 (公开成员函数)

示例

#include <ranges>
#include <vector>
#include <iostream>

template <class T, class A>
class VectorView : public std::ranges::view_interface<VectorView<T, A>> {
public:
    VectorView() = default;
    VectorView(const std::vector<T, A>& vec) :
        m_begin(vec.cbegin()), m_end(vec.cend()) {}
    auto begin() const { return m_begin; }
    auto end() const { return m_end; }
private:
    typename std::vector<T, A>::const_iterator m_begin{}, m_end{};
};

int main()
{
    std::vector<int> v = {1, 4, 9, 16};

    VectorView view_over_v{v};

    // 我们能以 begin() 与 end() 迭代。
    for (int n : view_over_v) {
        std::cout << n << ' ';
    }
    std::cout << '\n';

    // 我们能在继承 view_interface 时免费地获得 operator[]
    // 因为我们满足 random_access_range 概念。
    for (std::ptrdiff_t i = 0; i < view_over_v.size(); i++) {
        std::cout << "v[" << i << "] = " << view_over_v[i] << '\n';
    }
}

输出：

1 4 9 16
v[0] = 1
v[1] = 4
v[2] = 9
v[3] = 16

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3549 | C++20 | 要求 view_interface 派生自 view_base ，这有时要求视图中的多个 view_base 子对象 | 移除继承

参阅

ranges::subrange
(C++20)
 将迭代器/哨位对结合为一个 view
(类模板)


std::ranges::view_interface<D>::back

< cpp‎ | ranges‎ | view interface
constexpr decltype(auto) back() requires ranges::bidirectional_range<D> &&
ranges::common_range<D>;
 (1) (C++20 起)
constexpr decltype(auto) back() const
requires ranges::bidirectional_range<const D> && ranges::common_range<const D>;
 (2) (C++20 起)

back 成员函数的默认实现返回派生类型视图中的末元素。元素是按值还是按引用返回取决于迭代器类型的 operator* 。

1) 令 derived 为 static_cast<D&>(*this) 。等价于 return *ranges::prev(ranges::end(derived)); 。若 empty() 为 true （即起始迭代器与哨位比较相等）则行为未定义，即使以相同方式获得的迭代器可解引用。
2) 同 (1) ，除了 derived 为 static_cast<const D&>(*this) 。

参数

（无）

返回值

视图中的末元素。

注解

C++20 中，标准库无派生自 std::ranges::view_interface 的类型提供其自身的 back 成员函数。

然而，下列派生类型不能使用默认实现，因为它们决不一同满足 bidirectional_range 与 common_range ：

  • std::ranges::basic_istream_view
  • std::ranges::common_view
  • std::ranges::split_view
  • std::ranges::take_while_view

继承的 back 成员函数对 std::ranges::empty_view 可用，但对它的调用始终导致未定义行为。

示例

本节未完成
原因：暂无示例

参阅

rbegincrbegin (C++14) | 返回指向一个容器或数组的逆向迭代器 (函数模板)
ranges::rbegin (C++20) | 返回指向范围的逆向迭代器 (定制点对象)
ranges::crbegin (C++20) | 返回指向只读范围的逆向迭代器 (定制点对象)


std::ranges::view_interface<D>::data

< cpp‎ | ranges‎ | view interface
constexpr auto data()
requires std::contiguous_iterator<ranges::iterator_t<D>>;
 (1) (C++20 起)
constexpr bool data() const
requires std::contiguous_iterator<ranges::iterator_t<const D>>;
 (2) (C++20 起)

data 成员函数的默认实现经由 std::to_address 获得起始迭代器所代表的地址，在派生类型的视图非空时，它亦是视图所引用的连续存储（为 contiguous_iterator 所蕴含）的最低地址。

1) 令 derived 为 static_cast<D&>(*this) 。等价于 return std::to_address(ranges::begin(derived)); 。
2) 同 (1) ，除了 derived 为 static_cast<const D&>(*this) 。

参数

（无）

返回值

起始迭代器所代表的地址。

注解

下列派生类型可能使用 data 的默认实现：

  • std::ranges::drop_view
  • std::ranges::drop_while_view
  • std::ranges::ref_view
  • std::ranges::subrange
  • std::ranges::take_view
  • std::ranges::take_while_view

下列类型派生自 std::ranges::view_interface 并且不声明其自身的 data 成员函数，但它们无法使用默认实现，因为其迭代器类型决不满足 contiguous_iterator ：

  • std::ranges::basic_istream_view
  • std::ranges::common_view
  • std::ranges::elements_view
  • std::ranges::filter_view
  • std::ranges::iota_view
  • std::ranges::join_view
  • std::ranges::reverse_view
  • std::ranges::split_view
  • std::ranges::transform_view

示例

#include <array>
#include <iostream>
#include <ranges>
#include <string_view>

int main() {
    constexpr std::string_view str { "Hello, C++20!" };
    std::cout << (str | std::views::drop(7)).data() << '\n';
    constexpr static std::array a { 1,2,3,4,5 };
    constexpr auto v { a | std::views::take(3) };
    static_assert( &a[0] == v.data() );
}

输出：

C++20!

参阅

data (C++17) | 获得指向底层数组的指针 (函数模板)
ranges::data (C++20) | 获得指向连续范围的起始的指针 (定制点对象)
ranges::cdata (C++20) | 获得指向只读连续范围的起始的指针 (定制点对象)
to_address (C++20) | 从指针式类型获得裸指针 (函数模板)


std::ranges::view_interface<D>::empty

< cpp‎ | ranges‎ | view interface
constexpr bool empty() requires ranges::forward_range<D>; | (1) | (C++20 起)
constexpr bool empty() const requires ranges::forward_range<const D>; | (2) | (C++20 起)

empty 成员函数的默认实现检查起始迭代器与哨位是否比较相等。

1) 令 derived 为绑定到 static_cast<D&>(*this) 的引用。等价于 return ranges::begin(derived) == ranges::end(derived); 。
2) 同 (1) ，除了 derived 为 static_cast<const D&>(*this) 。

参数

（无）

返回值

若派生类型对象的起始迭代器与哨位比较相等则为 true ，否则为 false 。

注解

下列派生类型可使用 empty 的默认实现：

  • std::ranges::common_view
  • std::ranges::drop_view
  • std::ranges::drop_while_view
  • std::ranges::elements_view
  • std::ranges::filter_view
  • std::ranges::iota_view
  • std::ranges::join_view
  • std::ranges::reverse_view
  • std::ranges::single_view
  • std::ranges::split_view
  • std::ranges::take_view
  • std::ranges::take_while_view
  • std::ranges::transform_view

尽管 std::ranges::basic_istream_view 继承自 std::ranges::view_interface 并且不声明 empty 成员函数，它仍无法使用默认实现，因为它决不满足 std::ranges::forward_range 。

示例

#include <array>
#include <ranges>

int main() {
    constexpr std::array a {0, 1, 2, 3, 4};
    static_assert( ! std::ranges::single_view(a).empty() );
    static_assert(   (a | std::views::take(0)).empty() );
    static_assert( ! (a | std::views::take(2)).empty() );
    static_assert(   (a | std::views::drop(9)).empty() );
    static_assert( ! (a | std::views::drop(2)).empty() );
    static_assert(   std::views::iota(0,0).empty() );
    static_assert( ! std::views::iota(0).empty() );
}

参阅

empty (C++17) | 检查容器是否为空 (函数模板)
ranges::empty (C++20) | 检查范围是否为空 (定制点对象)


std::ranges::view_interface<D>::front

< cpp‎ | ranges‎ | view interface
constexpr decltype(auto) front() requires ranges::forward_range<D>;
 (1) (C++20 起)
constexpr decltype(auto) front() const
requires ranges::forward_range<const D>;
 (2) (C++20 起)

front 成员函数的默认实现返回派生类型的视图中的首个元素。元素是按值还是按引用返回取决于迭代器类型的 operator* 。

1) 令 derived 为 static_cast<D&>(*this) 。等价于 return *ranges::begin(derived); 。若 empty() 为 true （即起始迭代器比较等于哨位）则行为未定义，即使以同样方式获得的迭代器可解引用。
2) 同 (1) ，除了 derived 为 static_cast<const D&>(*this) 。

参数

（无）

返回值

视图中的首个元素。

注解

C++20 中，标准库无派生自 std::ranges::view_interface 的类型提供其自身的 front 成员函数。几乎所有这些类型都使用默认实现。

一个值得注意的例外是 std::ranges::basic_istream_view 。由于它决不满足 forward_range ，该视图无法使用继承的 front 。

继承的 front 成员函数对 std::ranges::empty_view 可用，但对它的调用始终导致未定义行为。

示例

本节未完成
原因：暂无示例

参阅

begincbegin (C++11)(C++14) | 返回指向容器或数组起始的迭代器 (函数模板)
ranges::begin (C++20) | 返回指向范围起始的迭代器 (定制点对象)
ranges::cbegin (C++20) | 返回指向只读范围起始的迭代器 (定制点对象)


std::ranges::view_interface<D>::operator[]

< cpp‎ | ranges‎ | view interface
template<ranges::random_access_range R = D>
constexpr decltype(auto) operator[]( ranges::range_difference_t<R> n );
 (1) (C++20 起)
template<ranges::random_access_range R = const D>
constexpr decltype(auto) operator[]( ranges::range_difference_t<R> n ) const;
 (2) (C++20 起)

operator[] 成员函数的默认实现获得相对于迭代器在指定偏移的元素，复用迭代器类型的 operator[] 。

1) 令 derived 为 static_cast<D&>(*this) 。等价于 return ranges::begin(derived)[n]; 。
2) 同 (1) ，除了 derived 为 static_cast<const D&>(*this) 。

参数

n - 要返回的元素位置

返回值

相对于起始迭代器偏移为 n 的元素。

注解

C++20 中，标准库无派生自 std::ranges::view_interface 的类型提供其自身的 operator[] 成员函数。

然而，下列派生类型不能使用默认实现，因为它们决不满足 random_access_range ：

  • std::ranges::basic_istream_view
  • std::ranges::common_view
  • std::ranges::filter_view
  • std::ranges::join_view
  • std::ranges::split_view

继承的 operator[] 成员函数对 std::ranges::empty_view 可用，但对它的调用始终导致未定义行为。

示例

本节未完成
原因：暂无示例


std::ranges::view_interface<D>::operator bool

< cpp‎ | ranges‎ | view interface
explicit constexpr operator bool() requires /* see below */; | (1) | (C++20 起)
explicit constexpr operator bool() const requires /* see below */; | (2) | (C++20 起)

operator bool 成员函数的默认实现检查视图是否为非空。它使得派生类型可按语境转换成 bool 。

1) 令 derived 为 static_cast<D&>(*this) 。 requires 子句中的表达式等于 requires { ranges::empty(derived); } ，而函数体等价于 return ranges::empty(derived); 。
2) 同 (1) ，除了 derived 为 static_cast<const D&>(*this) 。

参数

（无）

返回值

若派生类型的值为空（由 std::ranges::empty 确定）则为 false ，否则为 true 。

注解

C++20 中，标准库中无派生自 std::ranges::view_interface 的类型提供其自身的 operator bool 。几乎所有这些类型都使用默认实现。

一个值得注意的例外是 std::ranges::basic_istream_view 。由于其迭代器类型决不满足 forward_iterator ，故视图不能使用继承的 operator bool 。

示例

#include <array>
#include <iostream>
#include <ranges>

int main() {
    const std::array ints {0, 1, 2, 3, 4};
    auto odds = ints | std::views::filter([](int i) { return 0 != i % 2; });
    auto negs = ints | std::views::filter([](int i) { return i < 0; });
    std::cout << std::boolalpha
              << "Has odd numbers: " << (!!odds) << ' ' << '\n'
              << "Has negative numbers: " << (!!negs) << ' ' << '\n';
}

输出：

Has odd numbers: true
Has negative numbers: false

参阅

ranges::empty (C++20) | 检查范围是否为空 (定制点对象)
empty (C++20) | 返回视图是否为空。若视图满足 forward_range 则提供。 (公开成员函数)
empty (C++17) | 检查容器是否为空 (函数模板)


std::ranges::view_interface<D>::size

< cpp‎ | ranges‎ | view interface
constexpr auto size() requires ranges::forward_range<D> &&

std::sized_sentinel_for<ranges::sentinel_t<D>,

ranges::iterator_t<D>>;
 (1) (C++20 起)
constexpr auto size() const requires ranges::forward_range<const D> &&

std::sized_sentinel_for<ranges::iterator_t<const D>,

ranges::sentinel_t<const D>>;
 (2) (C++20 起)

size() 成员函数的默认实现通过计算哨位与起始迭代器间的差获得范围的大小。

1) 令 derived 为 static_cast<D&>(*this) 。等价于 return ranges::end(derived) - ranges::begin(derived); 。
2) 同 (1) ，除了 derived 为 static_cast<const D&>(*this) 。

参数

（无）

返回值

派生类类型值的哨位与起始迭代器间的差。

注解

下列派生类型能使用 size() 的默认实现：

  • std::ranges::drop_while_view

下列类型派生自 std::ranges::view_interface 并且不声明其自身的 size() 成员函数，但它们无法使用默认实现，因为其迭代器与哨位类型决不满足 sized_sentinel_for ：

  • std::ranges::basic_istream_view
  • std::ranges::filter_view
  • std::ranges::join_view
  • std::ranges::split_view
  • std::ranges::lazy_split_view
  • std::ranges::take_while_view

参阅

sizessize (C++17)(C++20) | 返回容器或数组的大小 (函数模板)
ranges::size (C++20) | 返回等于范围大小的整数 (定制点对象)
ranges::ssize (C++20) | 返回等于范围大小的有符号整数 (定制点对象)


std::ranges::viewable_range

< cpp‎ | ranges
定义于头文件 <ranges>
template<class T>

concept viewable_range =
ranges::range<T> &&
((ranges::view<std::remove_cvref_t<T>> &&
std::constructible_from<std::remove_cvref_t<T>, T>) ||
(!ranges::view<std::remove_cvref_t<T>> &&
( std::is_lvalue_reference_v <T> ||

(std::movable< std::remove_reference_t <T>> && !/*is-initializer-list*/<T>))));
 (C++20 起)

viewable_range 概念是 range 的细化，它描述能安全转换成 view 的范围。

常量 /*is-initializer-list*/<T> 为 true 当且仅当 std::remove_cvref_t<T> 为 std::initializer_list 的特化。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3481 | C++20 | viewable_range 曾接受仅移动视图的左值 | 拒绝
P2415R2 | C++20 | viewable_range 仅接受作为 borrowed_range 的非 view 右值 | 接受更多类型


正则表达式库

< cpp

正则表达式库提供表示正则表达式的类，正则表达式是一种用于在字符串中匹配模式的微型语言。下列数种对象上的操作能刻画几乎所有带正则表达式的操作：

  • 目标序列。为模式而搜索到的字符序列。这可以是二个迭代器所指定的范围、空终止字符串或一个 std::string 。
  • 模式。这是正则表达式自身。它确定构成匹配者。它是从带特定语法的字符串构成的 std::basic_regex 类型对象。受支持的语法变体的描述见 syntax_option_type 。
  • 匹配的数组。关于匹配的信息可作为 std::match_results 类型对象获取。
  • 替换字符串。这是确定如何替换匹配的字符串，受支持的语法变体的描述见 match_flag_type 。

主类

这些类封装正则表达式和在字符的目标序列中匹配正则表达式的结果。

basic_regex (C++11) | 正则表达式对象 (类模板)
sub_match (C++11) | 标识子表达式所匹配的字符序列 (类模板)
match_results (C++11) | 标识一个正则表达式匹配，包含所有子表达式匹配 (类模板)

算法

这些算法将封装于 regex 的正则表达式应用到字符的目标序列。

regex_match (C++11) | 尝试匹配一个正则表达式到整个字符序列 (函数模板)
regex_search (C++11) | 尝试匹配一个正则表达式到字符序列的任何部分 (函数模板)
regex_replace (C++11) | 以格式化的替换文本来替换正则表达式匹配的出现位置 (函数模板)

迭代器

regex_iterator 用于遍历在序列中找到的匹配正则表达式的整个集合。

regex_iterator (C++11) | 迭代一个字符序列中的所有正则表达式匹配 (类模板)
regex_token_iterator (C++11) | 迭代给定字符串中的所有正则表达式匹配中的指定子表达式，或迭代未匹配的子字符串 (类模板)

异常

此类定义作为异常抛出以报告来自正则表达式库错误的类型。

regex_error
(C++11)
 报告正则表达式库生成的错误
(类)

特征

regex_traits 类用于封装 regex 的本地化方面。

regex_traits
(C++11)
 提供正则表达式库所需的关于字符类型的元信息
(类模板)

常量

定义于命名空间 std::regex_constants
syntax_option_type (C++11) | 控制正则表达式行为的通用选项 (typedef)
match_flag_type (C++11) | 特定于匹配的选项 (typedef)
error_type (C++11) | 描述不同类型的匹配错误 (typedef)

示例

#include <iostream>
#include <iterator>
#include <string>
#include <regex>

int main()
{
    std::string s = "Some people, when confronted with a problem, think "
        "\"I know, I'll use regular expressions.\" "
        "Now they have two problems.";

    std::regex self_regex("REGULAR EXPRESSIONS",
            std::regex_constants::ECMAScript | std::regex_constants::icase);
    if (std::regex_search(s, self_regex)) {
        std::cout << "Text contains the phrase 'regular expressions'\n";
    }

    std::regex word_regex("(\\w+)");
    auto words_begin =
        std::sregex_iterator(s.begin(), s.end(), word_regex);
    auto words_end = std::sregex_iterator();

    std::cout << "Found "
              << std::distance(words_begin, words_end)
              << " words\n";

    const int N = 6;
    std::cout << "Words longer than " << N << " characters:\n";
    for (std::sregex_iterator i = words_begin; i != words_end; ++i) {
        std::smatch match = *i;
        std::string match_str = match.str();
        if (match_str.size() > N) {
            std::cout << "  " << match_str << '\n';
        }
    }

    std::regex long_word_regex("(\\w{7,})");
    std::string new_s = std::regex_replace(s, long_word_regex, "[$&]");
    std::cout << new_s << '\n';
}

输出：

Text contains the phrase 'regular expressions'
Found 20 words
Words longer than 6 characters:
  confronted
  problem
  regular
  expressions
  problems
Some people, when [confronted] with a [problem], think
"I know, I'll use [regular] [expressions]." Now they have two [problems].


std::basic_regex

< cpp‎ | regex
定义于头文件 <regex> |
template < class CharT, class Traits = std::regex_traits <CharT> > class basic_regex; | (C++11 起)

类模板 basic_regex 提供保有正则表达式的通用框架。

提供对于常见类型的几个特化：

定义于头文件 <regex>
类型 | 定义
regex | basic_regex<char>
wregex | basic_regex<wchar_t>

成员类型

成员类型 | 定义
value_type | CharT
traits_type | Traits
string_type | Traits::string_type
locale_type | Traits::locale_type
flag_type | std::regex_constants::syntax_option_type

成员函数

(构造函数)
 构造 regex 对象
(公开成员函数)
(析构函数)
 析构 regex 对象
(公开成员函数)
operator=
 赋值内容
(公开成员函数)
assign
 赋值内容
(公开成员函数)
观察器
mark_count
 返回正则表达式中有标记的子表达式数量
(公开成员函数)
flags
 返回语法标志
(公开成员函数)
本地环境
getloc
 获取本地环境信息
(公开成员函数)
imbue
 设置本地环境信息
(公开成员函数)
修改器
swap
 交换内容
(公开成员函数)

常量

值 | 效果
icase | 应当以不考虑大小写进行字符匹配。
nosubs | 进行匹配时，将所有被标记的子表达式 (expr) 当做非标记的子表达式 (?:expr) 。不将匹配存储于提供的 std::regex_match 结构中，且 mark_count() 为零
optimize | 指示正则表达式引擎进行更快的匹配，带有令构造变慢的潜在开销。例如这可能表示将非确定 FSA 转换为确定 FSA 。
collate | 形如 "[a-b]" 的字符范围将对本地环境敏感。
multiline (C++17) | 若选择 ECMAScript 引擎，则指定 ^ 应该匹配行首，而 $ 应该匹配行尾。
ECMAScript | 使用改 ECMAScript 正则表达式文法
basic | 使用基本 POSIX 正则表达式文法（文法文档）。
extended | 使用扩展 POSIX 正则表达式文法（文法文档）。
awk | 使用 POSIX 中 awk 工具所用的正则表达式文法（文法文档）。
grep | 使用 POSIX 中 grep 工具所用的正则表达式文法。这等效于 basic 选项附带作为另一种分隔符的换行符 '\n' 。
egrep | 使用 POSIX 中 grep 工具带 -E 选项所用的正则表达式文法。这等效于 extended 附带 '|' 之外的作为另一种分隔符的换行符 '\n' 。

ECMAScript, basic, extended, awk, grep, egrep 必须选取至多一个文法选项。若不选取文法选项，则设定为选取 ECMAScript 。其他选项作为修饰符工作，从而 std::regex("meow", std::regex::icase) 等价于 std::regex("meow", std::regex::ECMAScript|std::regex::icase)

basic_regex 中的成员常量是定义于命名空间 std::regex_constants 的 syntax_option_type 常量的副本。

非成员函数

std::swap(std::basic_regex)
(C++11)
 特化 std::swap 算法
(函数模板)

推导指引 (C++17 起)


std::basic_regex<CharT,Traits>::assign

< cpp‎ | regex‎ | basic regex
basic_regex& assign( const basic_regex& other );
 (1) (C++11 起)
basic_regex& assign( basic_regex&& that ) noexcept;
 (2) (C++11 起)
basic_regex& assign( const CharT* s,
flag_type f = std::regex_constants::ECMAScript );
 (3) (C++11 起)
basic_regex& assign( const CharT* ptr, size_t count,
flag_type f = std::regex_constants::ECMAScript );
 (4) (C++11 起)
template< class ST, class SA >

basic_regex& assign( const std::basic_string <CharT,ST,SA>& str,

flag_type f = std::regex_constants::ECMAScript );
 (5) (C++11 起)
template< class InputIt >

basic_regex& assign( InputIt first, InputIt last,

flag_type f = std::regex_constants::ECMAScript );
 (6) (C++11 起)
basic_regex& assign( std::initializer_list <CharT> ilist,
flag_type f = std::regex_constants::ECMAScript );
 (7) (C++11 起)

赋值内容给正则表达式。

1) 赋值 other 的内容。调用后 flags() 和 mark_count() 等于 other.flags() 和 other.mark_count() 的值。
2) 用移动语义赋值 other 的内容。 flags() 和 mark_count() 等于 other.flags() 和 other.mark_count() 在赋值前的值。调用后， other 在合法但未指定的状态。
3-7) 赋值字符序列给正则表达式。设置语法标志为 f 。调用后 mark_count() 产生的子表达式中的有标记子表达式数。
3) 赋值 s 所指向的空终止字符串。
4) 赋值 s 所指向的 count 个字符序列。
5) 赋值 string str 。
6) 赋值范围 [first, last) 中的字符。
7) 赋值 initializer_list ilist 中的字符。

参数

other | - | 要赋值的另一正则表达式
s | - | 指向要赋值的字符序列的指针
str | - | 要赋值的 string
first, last | - | 要赋值的字符范围
ilist | - | 含要赋值的字符的 initializer_list
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

*this

异常

1) 可能抛出实现定义的异常。
3-7) 若提供的正则表达式非法则为 std::regex_error 。该情况下不修改对象。

示例

本节未完成
原因：暂无示例

参阅

operator=
 赋值内容
(公开成员函数)


std::basic_regex<CharT,Traits>::basic_regex

< cpp‎ | regex‎ | basic regex
basic_regex();
 (1) (C++11 起)
explicit basic_regex( const CharT* s,
flag_type f = std::regex_constants::ECMAScript );
 (2) (C++11 起)
basic_regex( const CharT* s, std::size_t count,
flag_type f = std::regex_constants::ECMAScript );
 (3) (C++11 起)
basic_regex( const basic_regex& other );
 (4) (C++11 起)
basic_regex( basic_regex&& other ) noexcept;
 (5) (C++11 起)
template< class ST, class SA >

explicit basic_regex( const std::basic_string <CharT,ST,SA>& str,

flag_type f = std::regex_constants::ECMAScript );
 (6) (C++11 起)
template< class ForwardIt >

basic_regex( ForwardIt first, ForwardIt last,

flag_type f = std::regex_constants::ECMAScript );
 (7) (C++11 起)
basic_regex( std::initializer_list <CharT> init,
flag_type f = std::regex_constants::ECMAScript );
 (8) (C++11 起)

从按照标志 f 转译的字符序列构造新的正则表达式。

1) 默认构造函数。构造将不匹配内容的空正则表达式。
2) 从空终止字符串 s 构造正则表达式。
3) 从 s 所指向的 count 个的字符序列构造正则表达式。
4) 复制构造函数。通过复制 other 构造正则表达式。
5) 移动构造函数。用移动语义构造拥有 other 内容的正则表达式。
6) 从 string str 构造正则表达式。
7) 范围构造函数。构造拥有范围 [first, last) 内容的正则表达式。
8) initializer_list 构造函数。构造拥有 initializer_list init 内容的正则表达式。

参数

s | - | 指向空终止字符串的指针
count | - | 用于初始化 regex 的字符序列长度
first, last | - | 用于初始化 regex 的字符序列范围
str | - | 用作源初始化 regex 的 basic_string
other | - | 用作源初始化 regex 的另一 regex
init | - | 用于初始化 regex 的 initializer_list
f | - | 用于指引转译字符序列为正则表达式的标志
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

异常

1) 可能抛出实现定义的异常。
2-3) 若提供的正则表达式非法则为 std::regex_error 。
4) 可能抛出实现定义的异常。
6-8) 若提供的正则表达式非法则为 std::regex_error 。

示例

本节未完成
原因：暂无示例


std::basic_regex 常量

< cpp‎ | regex‎ | basic regex
定义于头文件 <regex>
static constexpr std::regex_constants::syntax_option_type icase =

std::regex_constants::icase ;
static constexpr std::regex_constants::syntax_option_type nosubs =
std::regex_constants::nosubs ;
static constexpr std::regex_constants::syntax_option_type optimize =
std::regex_constants::optimize ;
static constexpr std::regex_constants::syntax_option_type collate =
std::regex_constants::collate ;
static constexpr std::regex_constants::syntax_option_type ECMAScript =
std::regex_constants::ECMAScript ;
static constexpr std::regex_constants::syntax_option_type basic =
std::regex_constants::basic ;
static constexpr std::regex_constants::syntax_option_type extended =
std::regex_constants::extended ;
static constexpr std::regex_constants::syntax_option_type awk =
std::regex_constants::awk ;
static constexpr std::regex_constants::syntax_option_type grep =
std::regex_constants::grep ;
static constexpr std::regex_constants::syntax_option_type egrep =

std::regex_constants::egrep ;
static constexpr std::regex_constants::syntax_option_type multiline =
std::regex_constants::multiline;
 (C++17 起)

std::basic_regex 定义数个掌控通用正则表达式语法的常量。

这些常量复制自 std::regex_constants ：

值 | 效果
icase | 应当以不考虑大小写进行字符匹配。
nosubs | 进行匹配时，将所有被标记的子表达式 (expr) 当做非标记的子表达式 (?:expr) 。不将匹配存储于提供的 std::regex_match 结构中，且 mark_count() 为零
optimize | 指示正则表达式引擎进行更快的匹配，带有令构造变慢的潜在开销。例如这可能表示将非确定 FSA 转换为确定 FSA 。
collate | 形如 "[a-b]" 的字符范围将对本地环境敏感。
multiline (C++17) | 若选择 ECMAScript 引擎，则指定 ^ 应该匹配行首，而 $ 应该匹配行尾。
ECMAScript | 使用改 ECMAScript 正则表达式文法
basic | 使用基本 POSIX 正则表达式文法（文法文档）。
extended | 使用扩展 POSIX 正则表达式文法（文法文档）。
awk | 使用 POSIX 中 awk 工具所用的正则表达式文法（文法文档）。
grep | 使用 POSIX 中 grep 工具所用的正则表达式文法。这等效于 basic 选项附带作为另一种分隔符的换行符 '\n' 。
egrep | 使用 POSIX 中 grep 工具带 -E 选项所用的正则表达式文法。这等效于 extended 附带 '|' 之外的作为另一种分隔符的换行符 '\n' 。

ECMAScript, basic, extended, awk, grep, egrep 必须选取至多一个文法选项。若不选取文法选项，则设定为选取 ECMAScript 。其他选项作为修饰符工作，从而 std::regex ("meow", std::regex::icase) 等价于 std::regex ("meow", std::regex::ECMAScript|std::regex::icase)

参阅

syntax_option_type
(C++11)
 控制正则表达式行为的通用选项
(typedef)


std::basic_regex 的推导指引

< cpp‎ | regex‎ | basic regex
定义于头文件 <regex> |
template<class ForwardIt> basic_regex(ForwardIt, ForwardIt, std::regex_constants::syntax_option_type = std::regex_constants::ECMAScript ) -> basic_regex<typename std::iterator_traits <ForwardIt>::value_type>; | (C++17 起)

为 std::basic_regex 提供此推导指引 ，以允许从迭代器范围推导。

示例

#include <regex>
#include <vector>
int main() {
   std::vector<char> v = {'a', 'b', 'c'};
   std::basic_regex re{v.begin(), v.end()}; // 使用显式推导指引
}


std::basic_regex<CharT,Traits>::flags

< cpp‎ | regex‎ | basic regex
flag_type flags() const; | (C++11 起)

返回构造函数或最后一次到 assign() 调用中设置的正则表达式语法标志。

参数

（无）

返回值

当前正则表达式语法标志。

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例


std::basic_regex<CharT,Traits>::getloc

< cpp‎ | regex‎ | basic regex
locale_type getloc() const; | (C++11 起)

返回与正则表达式关联的当前本地环境。

等效地调用 traits_i.getloc() ，其中 traits_i 是存储于正则表达式对象内的 Traits 类型的默认初始化实例。

参数

（无）

返回值

与正则表达式关联的当前本地环境。

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

imbue
 设置本地环境信息
(公开成员函数)


std::basic_regex<CharT,Traits>::imbue

< cpp‎ | regex‎ | basic regex
locale_type imbue( locale_type loc ); | (C++11 起)

以 loc 替换当前本地环境。调用后，正则表达式不匹配任何字符序列。

等效地调用 traits_i.imbue(loc) ，其中 traits_i 是存储于正则表达式对象内的默认初始化的 Traits 类型实例。

参数

loc - 要使用的新本地环境

返回值

此调用前的本地环境。等效地返回表达式 traits_i.imbue(loc) 的结果。

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

参阅

getloc
 获取本地环境信息
(公开成员函数)


std::basic_regex<CharT,Traits>::mark_count

< cpp‎ | regex‎ | basic regex
unsigned mark_count() const; | (C++11 起)

返回正则表达式内有标记的子表达式（又称捕获组）数。

参数

（无）

返回值

正则表达式内有标记的子表达式数。

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <regex>

int main()
{
    std::regex r1{"abcde"};
    std::cout << "r1 has " << r1.mark_count() << " subexpressions" <<  '\n';
    //  期待： 0

    std::regex r2{"ab(c)de"};
    std::cout << "r2 has " << r2.mark_count() << " subexpressions" << '\n';
    //  期待： 1

    std::regex r3{"a(bc)d(e)"};
    std::cout << "r3 has " << r3.mark_count() << " subexpressions" << '\n';
    //  期待： 2

    //  嵌套的子表达式
    std::regex r4{"abc(de(fg))"};
    std::cout << "r4 has " << r4.mark_count() << " subexpressions" << '\n';
    //  期待： 2

    //  转义的括号
    std::regex r5{"a(bc\\(\\)de)"};
    std::cout << "r5 has " << r5.mark_count() << " subexpressions" << '\n';
    //  期待： 1

    //  使用 nosubs 标志
    std::regex r6 {"ab(c)de", std::regex_constants::nosubs};
    std::cout << "r6 has " << r6.mark_count() << " subexpressions" << '\n';
    //  Expected: 0
}

输出：

r1 has 0 subexpressions
r2 has 1 subexpressions
r3 has 2 subexpressions
r4 has 2 subexpressions
r5 has 1 subexpressions
r6 has 0 subexpressions


std::basic_regex<CharT,Traits>::operator=

< cpp‎ | regex‎ | basic regex
定义于头文件 <regex> |  |
basic_regex& operator=( const basic_regex& other ); | (1) | (C++11 起)
basic_regex& operator=( basic_regex&& other ) noexcept; | (2) | (C++11 起)
basic_regex& operator=( const CharT* ptr ); | (3) | (C++11 起)
basic_regex& operator=( std::initializer_list <CharT> il ); | (4) | (C++11 起)
template< class ST, class SA > basic_regex& operator=( const std::basic_string <CharT,ST,SA>& p ); | (5) | (C++11 起)

赋值内容。

1) 复制赋值运算符。赋值 other 的内容。等价于 assign(other); 。
2) 移动赋值运算符。用移动语义赋值 other 的内容。操作后 other 在合法但未指定的状态。等价于 assign(other); 。
3) 赋值 ptr 所指向的空终止字符串。等价于 assign(ptr); 。
4) 赋值 initializer_list il 中含有的字符。等价于 assign(il); 。
5) 赋值 string p 的内容。等价于 assign(p); 。

参数

other | - | 另一 regex 对象
ptr | - | 指向空终止字符串的指针
il | - | 含要赋值的字符的 initializer_list
p | - | 含要赋值的字符的 string

返回值

*this 。

异常

1) 可能抛出实现定义的异常。
3-5) 若提供的正则表达式非法则抛出 std::regex_error 。该情况下不修改对象。

参阅

assign
 赋值内容
(公开成员函数)


std::basic_regex<CharT,Traits>::swap

< cpp‎ | regex‎ | basic regex
void swap( basic_regex& other ) noexcept; | (C++11 起)

交换二个正则表达式的内容。

参数

other - 要交换的正则表达式

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

std::swap(std::basic_regex)
(C++11)
 特化 std::swap 算法
(函数模板)


std::swap(std::basic_regex)

< cpp‎ | regex‎ | basic regex
template< class CharT, class Traits > void swap( basic_regex<CharT,Traits> &lhs, basic_regex<CharT,Traits> &rhs ) noexcept; | (C++11 起)

为 std::basic_regex 特化 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换的正则表达式

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

swap
 交换内容
(公开成员函数)


std::basic_regex<CharT,Traits>::~basic_regex

< cpp‎ | regex‎ | basic regex
~basic_regex(); | (C++11 起)

销毁正则表达式对象。


改 ECMAScript 正则表达式文法

< cpp‎ | regex

此页面描述以设置为 ECMAScript （默认值）的 syntax_option_type 构造 std::basic_regex 时使用的文法。其他受支持正则表达式文法见 syntax_option_type 。

C++ 中的 ECMAScript 3 正则表达式文法是带标记有后述 (仅 C++) 的修改的 ECMA-262 文法。

总览

改正则表达式文法几乎是 ECMAScript RegExp 文法带上类原子 (ClassAtom) 下的本地环境上的 POSIX 类型展开。我们作出了相等检查与数量分析上的一些澄清。对于此处的多数示例，你可以在你的浏览器控制台中尝试此等价版本：

function match(s, re) { return s.match(new RegExp(re)); }

标准中的“正式引用”指定 ECMAScript 3 。我们于此链接到 ECMAScript 5.1 规范，因为其正则表达式文法相比 ECMAScript 3 仅有微小改动，而且它有一个 HTML 版本。方言特性的概览见 MDN Guide on JavaScript RegExp 。

可选项

正则表达式模式是一或多个以析取运算符 | 分隔的可选项可选项 (Alternative) 序列（换言之，析取运算符拥有最低优先级）

Pattern ::

Disjunction

Disjunction ::

Alternative
Alternative | Disjunction

模式首先尝试跳过析取 (Disjunction) 并匹配（析取后的）后随剩余正则表达式的可选项。

若它失败，则试图跳过左侧可选项并匹配右侧析取（后随剩余正则表达式）。

若左侧可选项、右侧析取和剩余正则表达式都拥有选择点，则在尝试移动到左侧可选项中的下个选择前，尝试剩余表达式值中的所有选择。若穷尽了左侧可选项中的所有选择，则取代左侧可选项尝试右侧析取。

跳过的可选项内的任何捕获括号产生空子匹配。

#include <iostream>
#include <regex>

// TODO ：转换到接受宽字符序列
// std::match_results<std::basic_string<_ch>::const_iterator> m; 不行。
void show_matches(const std::string& in, const std::string& re)
{
    std::smatch m;
    std::regex_search(in, m, std::regex(re));
    if(m.empty()) {
        std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n";
    } else {
        std::cout << "input=[" << in << "], regex=[" << re << "]: ";
        std::cout << "prefix=[" << m.prefix() << "] ";
        for(std::size_t n = 0; n < m.size(); ++n)
            std::cout << " m[" << n << "]=[" << m[n] << "] ";
        std::cout << "suffix=[" << m.suffix() << "]\n";
    }
}

int main()
{
    show_matches("abcdef", "abc|def");
    show_matches("abc", "ab|abc"); // 首先匹配左侧可选项

    // 针对后随剩余正则表达式 (c|bc) 左侧可选项 (a) 的匹配成功
    // 它生成 m[1]="a" 及 m[4]="bc" 。
    // 跳过的可选项 (ab) 和 (c) 将其子匹配 m[3] 和 m[5] 置为空。
    show_matches("abc", "((a)|(ab))((c)|(bc))");
}

输出：

input=[abcdef], regex=[abc|def]: prefix=[]  m[0]=[abc] suffix=[def]
input=[abc], regex=[ab|abc]: prefix=[]  m[0]=[ab] suffix=[c]
input=[abc], regex=[((a)|(ab))((c)|(bc))]: prefix=[]  m[0]=[abc]
m[1]=[a]  m[2]=[a]  m[3]=[] m[4]=[bc]  m[5]=[]  m[6]=[bc] suffix=[]

项

每个可选项为空，或为项 (Term) 的序列（项间无分隔符）

Alternative ::

[empty]
Alternative Term

空的可选项始终匹配并且不消耗任何输入。

相继的项尝试同时匹配输入的连续部分。

若左侧可选项、右侧项和剩余正则表达式拥有选择点，则在移动到右侧项中的下个选择前，尝试剩余正则表达式中的所有选择，并在移动到左侧可选项中的下个选择前，尝试右侧项中的所有选择。

#include <iostream>
#include <regex>

// TODO ：转换到接受宽字符序列
// std::match_results<std::basic_string<_ch>::const_iterator> m; 不行。
void show_matches(const std::string& in, const std::string& re)
{
    std::smatch m;
    std::regex_search(in, m, std::regex(re));
    if(m.empty()) {
        std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n";
    } else {
        std::cout << "input=[" << in << "], regex=[" << re << "]: ";
        std::cout << "prefix=[" << m.prefix() << "] ";
        for(std::size_t n = 0; n < m.size(); ++n)
            std::cout << " m[" << n << "]=[" << m[n] << "] ";
        std::cout << "suffix=[" << m.suffix() << "]\n";
    }
}

int main()
{
    show_matches("abcdef", ""); // 空正则表达式是单个空可选项
    show_matches("abc", "abc|"); // 左可选项首先匹配
    show_matches("abc", "|abc"); // 左可选项首先匹配，留待 abc 未匹配
}

输出：

input=[abcdef], regex=[]: prefix=[]  m[0]=[] suffix=[abcdef]
input=[abc], regex=[abc|]: prefix=[]  m[0]=[abc] suffix=[]
input=[abc], regex=[|abc]: prefix=[]  m[0]=[] suffix=[abc]

数量词

  • 每个项 为断言 (Assertion)（见后方）或原子 (Atom) （见后方），或原子立即后随数量词 (Quantifier) 之一

Term ::

Assertion
Atom
Atom Quantifier

每个数量词为贪心 (greedy) 数量词（仅由一个数量词前缀 (QuantifierPrefix) 组成）或非贪心 (non-greedy) 数量词（由一个数量词前缀后随问号掩码 ? 组成）。

Quantifier ::

QuantifierPrefix
QuantifierPrefix ?

每个数量词前缀确定二个数：最小重复数和最大重复数，如下：

数量词前缀 | 最小 | 最大
* | 零 | 无穷大
+ | 一 | 无穷大
? | 零 | 一
{ 十进制数 } | 十进制数的值 | 十进制数的值
{ 十进制数 , } | 十进制数的值 | 无穷大
{ 十进制数 , 十进制数 } | 逗号前的十进制数的值 | 逗号后的十进制数的值

通过在每个数位上调用 std::regex_traits::value(仅 C++)获得单独的十进制数 (DecimalDigits) 的值。

原子后随数量词重复数量词所指定的次数。数量词能为非贪心，该情况下原子模式重复在仍然匹配剩余正则表达式的同时尽可能少的次数，或能为贪心，该情况下原子模式重复在仍然匹配剩余正则表达式的同时尽可能多的次数。

重复的是原子模式，而非其所匹配的输入，故原子的不同重复能匹配不同的输入子串。

若原子和剩余正则表达式都有选择点，则首先将原子匹配尽可能尽可能多（或少，若为非贪心）次。，移动到原子的最后一次重复中的下个选择前，尝试剩余正则表达式中的所有选择。移动到原子的倒数第二（第 n-1 ）次重复中的下个选择前，尝试原子的最后一（第 n ）次重复中的所有选择；在明确现在可能有原子的更多或更少重复时；在移动到原子的第 n-1 次重复中的下个选择前，将这些穷尽（再次以尽可能少或多开始），以此类推。

每次重复原子'时，清除其捕获（见后方 "(z)((a+)?(b+)?(c))*" 的示例）

#include <iostream>
#include <regex>

// TODO ：转换到接受宽字符序列
// std::match_results<std::basic_string<_ch>::const_iterator> m; 不行。
void show_matches(const std::string& in, const std::string& re)
{
    std::smatch m;
    std::regex_search(in, m, std::regex(re));
    if(m.empty()) {
        std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n";
    } else {
        std::cout << "input=[" << in << "], regex=[" << re << "]: ";
        std::cout << "prefix=[" << m.prefix() << "] ";
        for(std::size_t n = 0; n < m.size(); ++n)
            std::cout << " m[" << n << "]=[" << m[n] << "] ";
        std::cout << "suffix=[" << m.suffix() << "]\n";
    }
}

int main()
{
    // 贪心匹配，重复 [a-z] 4 次
    show_matches("abcdefghi", "a[a-z]{2,4}");
    // 非贪心匹配，重复 [a-z] 2 次
    show_matches("abcdefghi", "a[a-z]{2,4}?");

    // 数量词的选择点顺序，生成带二个重复的匹配，
    // 第一个匹配子串 "aa" ，第二个匹配子串 "ba" ，保留 "ac" 匹配
    // （"ba" 出现于 m[1] 的捕获子句中）
    show_matches("aabaac", "(aa|aabaac|ba|b|c)*");

    // 数量词的选择点顺序令此 regex 计算 10 与 15 间的最大公约数
    // （答案是 5 ，并以 "aaaaa" 填充 m[1] ）
    show_matches("aaaaaaaaaa,aaaaaaaaaaaaaaa", "^(a+)\\1*,\\1+$");

    // 子串 "bbb" 不出现于捕获子句 m[4] 中
    // 因为它在原子 (a+)?(b+)?(c) 的第二次重复匹配子串 "ac" 时被声明
    // 注： gcc 理解有误——它没有正确地按 ECMA-262 21.2.2.5.1 清除
    // matches[4] 捕获组，从而错误地对于该组捕获 "bbb" 。
    show_matches("zaacbbbcac", "(z)((a+)?(b+)?(c))*");
}

输出：

input=[abcdefghi], regex=[a[a-z]{2,4}]: prefix=[]  m[0]=[abcde] suffix=[fghi]
input=[abcdefghi], regex=[a[a-z]{2,4}?]: prefix=[]  m[0]=[abc] suffix=[defghi]
input=[aabaac], regex=[(aa|aabaac|ba|b|c)*]:
 prefix=[]  m[0]=[aaba]  m[1]=[ba] suffix=[ac]
input=[aaaaaaaaaa,aaaaaaaaaaaaaaa], regex=[^(a+)\1*,\1+$]:
 prefix=[]  m[0]=[aaaaaaaaaa,aaaaaaaaaaaaaaa]  m[1]=[aaaaa] suffix=[]
input=[zaacbbbcac], regex=[(z)((a+)?(b+)?(c))*]:
prefix=[]  m[0]=[zaacbbbcac]  m[1]=[z]  m[2]=[ac]  m[3]=[a]  m[4]=[]  m[5]=[c] suffix=[]

断言

断言 (Assertion) 匹配条件，而非输入字符串的子串。它们决不消耗任何来自输入的字符。每个断言是下列之一

Assertion ::

^
$
\ b
\ B
( ? = Disjunction )
( ? ! Disjunction )

断言 ^ （行起始）匹配

1) 立即后随行终止符 (LineTerminator) 字符的位置（这可能不受支持） (C++17 前)（这仅若启用 std::regex_constants::multiline (仅 C++) 才得到保证） (C++17 起)
2) 输入的起始（除非启用 std::regex_constants::match_not_bol(仅 C++) ）

断言 $ （行结尾）匹配

1) 行终止符字符的位置（这可能不受支持） (C++17 前)（这仅若启用 std::regex_constants::multiline (仅 C++) 才得到保证） (C++17 起)
2) 输入的结尾（除非启用 std::regex_constants::match_not_bol(仅 C++) ）

上面二个断言和下面的原子 . 中，行终止符是下列四个字符之一： U+000A （ \n 或换行）、 U+000D （ \r 或回车）、 U+2028 （行分隔符）或 U+2029 （段分隔符）

断言 \b （词边界）匹配

1) 词的起始（当前字符为字母、数字或下划线，而前一字符不是）
2) 词的结尾（当前字符不是字母、数字或下划线，而前一字符是这些之一）
3) 输入的起始，若首字符为字母、数字或下划线（除非启用 std::regex_constants::match_not_bow(仅 C++) ）
4) 输入的结尾，若末字符为字母、数字或下划线（除非启用 std::regex_constants::match_not_eow(仅 C++) ）

断言 \B （反词边界）匹配所有字符，除了下列内容

1) 词的起始（当前字符为字母、数字或下划线，而前一字符不是这些之一或不存在）
2) 词的结尾（当前字符不是字母、数字或下划线（或匹配者在输入结尾），前一字符是这些之一）

若析取会匹配在当前位置的输入，则断言 ( ? = 析取 ) （零宽正前瞻）匹配。

若析取不会匹配在当前位置的的输入，则断言 ( ? ! 析取 ) （零宽负前瞻）匹配。

对于两个前瞻断言，在匹配析取时，不在匹配剩余正则表达式之前令位置前进。另外，若析取能以多种方式在当前位置匹配，则只尝试第一个。

ECMAScript 禁止回撤到前瞻析取中，这影响到来自剩余正则表达式的正前瞻中的回溯引用（见下方示例） 。到来自剩余正则表达式的负前瞻中的回溯引用始终没有定义（因为前瞻断言必定无法继续）。

注意：前瞻断言可用于创建多个正则表达式间的逻辑与（见下方示例）。

#include <iostream>
#include <regex>

// TODO ：转换到接受宽字符序列
// std::match_results<std::basic_string<_ch>::const_iterator> m; 不行。
void show_matches(const std::string& in, const std::string& re)
{
    std::smatch m;
    std::regex_search(in, m, std::regex(re));
    if(m.empty()) {
        std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n";
    } else {
        std::cout << "input=[" << in << "], regex=[" << re << "]: ";
        std::cout << "prefix=[" << m.prefix() << "] ";
        for(std::size_t n = 0; n < m.size(); ++n)
            std::cout << " m[" << n << "]=[" << m[n] << "] ";
        std::cout << "suffix=[" << m.suffix() << "]\n";
    }
}

int main()
{
    // 在输入结尾匹配 a
    show_matches("aaa", "a$");

    // 在第一个词结尾匹配 o
    show_matches("moo goo gai pan", "o\\b");

    // 前瞻匹配立即在第一个 b 之后的空字符串
    // 这以 "aaa" 填充 m[1] ，尽管 m[0] 为空
    show_matches("baaabac", "(?=(a+))");

    // 因为禁止回溯引用回撤到前瞻中，
    // 这匹配 aba 而非 aaaba
    show_matches("baaabac", "(?=(a+))a*b\\1");

    // 经由前瞻的逻辑与：此密码匹配，若它含有
    // 至少一个小写字母
    // 与 至少一个大写字母
    // 与 至少一个标点字符
    // 与 至少有 6 个字符长
    show_matches("abcdef", "(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}");
    show_matches("aB,def", "(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}");
}

输出：

input=[aaa], regex=[a$]: prefix=[aa]  m[0]=[a] suffix=[]
input=[moo goo gai pan], regex=[o\b]: prefix=[mo]  m[0]=[o] suffix=[ goo gai pan]
input=[baaabac], regex=[(?=(a+))]: prefix=[b]  m[0]=[]  m[1]=[aaa] suffix=[aaabac]
input=[baaabac], regex=[(?=(a+))a*b\1]: prefix=[baa]  m[0]=[aba]  m[1]=[a] suffix=[c]
input=[abcdef], regex=[(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}]:
 NO MATCH
input=[aB,def], regex=[(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}]:
 prefix=[]  m[0]=[aB,def] suffix=[]

原子

原子能为下列之一：

Atom ::

PatternCharacter
.
\ AtomEscape
CharacterClass
( Disjunction )
( ? : Disjunction )

其中 AtomEscape ::

DecimalEscape
CharacterEscape
CharacterClassEscape

不同种类的原子求值方式不同。

子表达式

原子 ( 析取 ) 是有标记表达式：它执行析取并存储析取所消耗的输入子串于子匹配数组，下标对应在此点已遇到的整个正则表达式中，有标记子表达式的左开括号 ( 次数。

除了在 std::match_results 中返回，捕获的子匹配还可作为回溯引用（ \1 、 \2 ……）访问，并在正则表达式中引用它们。注意 std::regex_replace 以同 String.prototype.replace (ECMA-262, part 15.5.4.11) 的方式，对于回溯引用以 $ 代替 \ （ $1 、 $2 ……）。

原子 ( ? : 析取 ) （非标记子表达式）简单地求值 析取 并不存储其结果于子匹配。这单纯是词法分组。

本节未完成
原因：暂无示例

回溯引用

DecimalEscape ::

DecimalIntegerLiteral [lookahead ∉ DecimalDigit]

若 \ 后随首位非 0 的十进制数 N ，则认为该转义序列为回溯引用 (backreference) 。通过在每个数位上调用 std::regex_traits::value(仅 C++) 并用底 10 算术组合及其结果获得 N 。若 N 大于整个正则表达式中捕获括号的总数，则为错误。

回溯引用 \N 作为原子出现时，它匹配当前存储于子匹配数组中第 N 个元素的子串。

十进制转义 \0 不是回溯引用：它是表示空字符的字符转义。它不能为十进制数所后随。

如上，注意 std::regex_replace 对于回溯引用以 $ 代替 \ （ $1 、 $2 ……）。

本节未完成
原因：暂无示例

单字符匹配

原子 . 匹配并消耗来自输入序列的任一字符，除了行终止符（ U+000A 、 U+000D 、 U+2028 或 U+2029 ）

原子 模式字符 ，其中模式字符 (PatternCharacter) 为任何源字符 (SourceCharacter) ，除了字符 ^ $ \ . * + ? ( ) [ ] { } | ，匹配并消耗一个来自输入的字符，若它等于此模式字符。

这个及所有其他单字符匹配定义如下：

1) 若设置了 std::regex_constants::icase ，则若 std::regex_traits::translate_nocase 的返回值相等则字符相等。(仅 C++)
2) 否则，若设置了 std::regex_constants::collate ，则若 std::regex_traits::translate 的返回值相等则字符相等。(仅 C++)
3) 否则，若 operator== 返回 true 则字符相等。

每个由转义字符 \ 后随字符转义 (CharacterEscape) 的原子，还有特殊十进制转义 \0 ，匹配消耗一个来自输入的字符，若它等于字符转义所表示的字符。辨识下列字符转义序列：

CharacterEscape ::

ControlEscape
c ControlLetter
HexEscapeSequence
UnicodeEscapeSequence
IdentityEscape

此处控制转义 (ControlEscape) 为下列五个字符之一： f n r t v

控制转义 | 编码单元 | 名称
f | U+000C | 换页
n | U+000A | 换行
r | U+000D | 回车
t | U+0009 | 水平制表
v | U+000B | 垂直制表

控制字母 (ControlLetter) 为任何小写或大写 ASCII 字符，而此字符转义所匹配字符的编码单元等于控制字母的编码单元的值除以 32 ，例如 \cD 和 \cd 都匹配编码单元 U+0004 (EOT) ，因为 'D' 是 U+0044 而 0x44 % 32 == 4 并且 'd' 是 U+0064 而 0x64 % 32 == 4 。

十六进制转义序列 (HexEscapeSequence) 是字母 x 后随准确二个十六进制位 (HexDigit) （其中十六进制位是 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F 之一）。此字符转义所匹配字符的编码单元等于二位十六进制数的数值。

Unicode转义序列 (UnicodeEscapeSequence) 是字母 u 后随准确四个十六进制位。此字符转义所匹配字符的编码单元等于此四位十六进制数的数值。若该值不适于此 std::basic_regex 的 CharT ，则抛出 std::regex_error (仅 C++)。

自身转义 (IdentityEscape) 能为任何非字母数字的字符：例如另一反斜杠。它照原样匹配字符。

#include <iostream>
#include <regex>

// TODO ：转换到接受宽字符序列
// std::match_results<std::basic_string<_ch>::const_iterator> m; 不行。
void show_matches(const std::string& in, const std::string& re)
{
    std::smatch m;
    std::regex_search(in, m, std::regex(re));
    if(m.empty()) {
        std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n";
    } else {
        std::cout << "input=[" << in << "], regex=[" << re << "]: ";
        std::cout << "prefix=[" << m.prefix() << "] ";
        for(std::size_t n = 0; n < m.size(); ++n)
            std::cout << " m[" << n << "]=[" << m[n] << "] ";
        std::cout << "suffix=[" << m.suffix() << "]\n";
    }
}

int main()
{
    // 大多数转义类似 C++ ，为元字符保存。你将需要在斜杠情形使用双重转义或未处理字符串。
    show_matches("C++\\", R"(C\+\+\\)");

    // 转义序列与 NUL 。
    std::string s("ab\xff\0cd", 5);
    show_matches(s, "(\\0|\\u00ff)");

    // 没有定义非 BMP Unicode 的匹配，因为 ECMAScript 使用 UTF-16 原子。
    // 此 emoji 香蕉是否匹配能为平台依赖：
    // XXX ：这些需要为宽字符串！
    // show_matches(L"\U0001f34c", L"[\\u0000-\\ufffe]+");
}

字符类

原子能表示字符类，即它会匹配并消耗一个字符，若该字符属于预定义的字符组之一。

字符类能通过字符类转义引入：

Atom ::

\ CharacterClassEscape

或直接为

Atom ::

CharacterClass

字符类转义是一些常用字符类的简洁写法，如下：

字符类转义 | 类名表达式(仅 C++) | 含义
d | [[:digit:]] | 数字
D | [^[:digit:]] | 非数字
s | [[:space:]] | 空白字符
S | [^[:space:]] | 非空白字符
w | [_[:alnum:]] | 字母数字字符及字符 _
W | [^_[:alnum:]] | 异于字母数字或 _ 的字符
C++ 中这些字符类转义的准确含义以依赖 locale 的具名字符类定义，而非通过显式列举同 ECMAScript 中的可接受字符。

字符类 (CharacterClass) 是方括号环绕的类范围 (ClassRanges) 序列，可选地以取反运算符 ^ 开始。若它始于 ^ ，则此原子匹配任何不在所有类范围的并所表示的字符集合中的字符。否则，此原子匹配任何在所有类范围的并所表示的字符集合中的字符。

CharacterClass ::

[ [ lookahead ∉ {^}] ClassRanges ]
[ ^ ClassRanges ]

ClassRanges ::

[empty]
NonemptyClassRanges

NonemptyClassRanges ::

ClassAtom
ClassAtom NonemptyClassRangesNoDash
ClassAtom - ClassAtom ClassRanges

若非空类范围拥有形式 ClassAtom - ClassAtom ，则它匹配来自定义如下的范围的任何字符：(仅 C++)

首个类原子 (ClassAtom) 必须匹配单个对照元素 c1 ，而第二个类原子必须匹配单个对照元素 c2 。采用下列步骤，测试此范围是否匹配输入字符 c ：

1) 若 std::regex_constants::collate 不打开，则通过直接比较编码点匹配字符：若 c1 <= c && c <= c2 则匹配 c
1) 否则（若启用 std::regex_constants::collate ）：
1) 若启用 std::regex_constants::icase ，则传递所有三个字符（ c 、 c1 及 c2 ）给 std::regex_traits::translate_nocase
2) 否则（若未设置 std::regex_constants::icase ），则传递所有三个字符（ c 、 c1 及 c2 ）给 std::regex_traits::translate
2) 用 std::regex_traits::transform 比较结果字符串，而若 transformed c1 <= transformed c && transformed c <= transformed c2 则匹配 c

按字面对待字符 - ，若它是下列之一

  • 类范围的首或末字符
  • 杠分隔范围规定的开始或结尾类原子
  • 立即在杠分隔范围规定之后。
  • 以反斜杠转义为字符转义

NonemptyClassRangesNoDash ::

ClassAtom
ClassAtomNoDash NonemptyClassRangesNoDash
ClassAtomNoDash - ClassAtom ClassRanges

ClassAtom ::

-
ClassAtomNoDash
ClassAtomExClass(仅 C++)
ClassAtomCollatingElement(仅 C++)
ClassAtomEquivalence(仅 C++)

ClassAtomNoDash ::

SourceCharacter but not one of \ or ] or -
\ ClassEscape

每个无杠类原子 (ClassAtomNoDash) 表示单个字符——原状的源字符或转义如下的字符：

ClassEscape ::

DecimalEscape
b
CharacterEscape
CharacterClassEscape

特殊的类转义 (ClassEscape) \b 产生匹配编码单元 U+0008 （退格）的字符集。在字符类外，它是词边界断言。

字符类内， \B 的使用和任何回溯引用（异于零的十进制转义）都是错误。

为将字符 - 和 ] 当做原子，一些情形中需要转义它们。其他拥有在字符类外的特殊含义的字符，例如 * 或 ? ，不需要转义。

本节未完成
原因：暂无示例

基于 POSIX 的字符类

这些字符类是对 ECMAScript 文法的扩展，并等价于 POSIX 正则表达式中找到的字符类。

ClassAtomExClass(仅 C++) ::

[: ClassName :]

表示所有具名字符类类名 (ClassName) 中的成员。仅若 std::regex_traits::lookup_classname 对此名称返回非零字符串，名称才合法。如 std::regex_traits::lookup_classname 中描述，保证辨识下列名称： alnum, alpha, blank, cntrl, digit, graph, lower, print, punct, space, upper, xdigit, d, s, w 。额外的名称（如日文中的 jdigit 或 jkanji ）可为系统提供的 locale 提供，或实现为用户定义的扩展：

ClassAtomCollatingElement(仅 C++) ::

[. ClassName .]

表示具名对照元素，它可表示单个字符，或在感染的 locale 下作为单个单位对照的字符序列，例如 [.tilde.] 或捷克文中的 [.ch.] 。仅若 std::regex_traits::lookup_collatename 不是空字符串名称才合法。

使用 std::regex_constants::collate 时，始终能以对照元素为范围的端点（例如匈牙利文中的 [[.dz.]-g] ）。

ClassAtomEquivalence(仅 C++) ::

[= ClassName =]

表示与具名对照元素相同的等价类的所有成员字符，即其初等对照关键与对照元素类名所拥有者相同的字符。仅若 std::regex_traits::lookup_collatename 对该名称返回非空字符串，且 std::regex_traits::transform_primary 对调用 std::regex_traits::lookup_collatename 的结果的返回值不是空字符串，名称才合法。

初等排序关键是忽略大小写、标音符或本地环境限定裁剪的关键；故例如 [[=a=]] 匹配任何这些字符之一： a, À, Á, Â, Ã, Ä, Å, A, à, á, â, ã, ä 和 å 。

ClassName(仅 C++) ::

ClassNameCharacter
ClassNameCharacter ClassName

ClassNameCharacter(仅 C++) ::

SourceCharacter 但非 . = : 之一
本节未完成
原因：暂无示例


std::regex_constants::error_type

< cpp‎ | regex
定义于头文件 <regex>
typedef /*implementation defined*/ error_type;
 (C++11 起)
constexpr error_type error_collate = /*unspecified*/;

constexpr error_type error_ctype = /*unspecified*/;
constexpr error_type error_escape = /*unspecified*/;
constexpr error_type error_backref = /*unspecified*/;
constexpr error_type error_brack = /*unspecified*/;
constexpr error_type error_paren = /*unspecified*/;
constexpr error_type error_brace = /*unspecified*/;
constexpr error_type error_badbrace = /*unspecified*/;
constexpr error_type error_range = /*unspecified*/;
constexpr error_type error_space = /*unspecified*/;
constexpr error_type error_badrepeat = /*unspecified*/;
constexpr error_type error_complexity = /*unspecified*/;

constexpr error_type error_stack = /*unspecified*/;
 (C++11 起)
(C++17 前)
inline constexpr error_type error_collate = /*unspecified*/;

inline constexpr error_type error_ctype = /*unspecified*/;
inline constexpr error_type error_escape = /*unspecified*/;
inline constexpr error_type error_backref = /*unspecified*/;
inline constexpr error_type error_brack = /*unspecified*/;
inline constexpr error_type error_paren = /*unspecified*/;
inline constexpr error_type error_brace = /*unspecified*/;
inline constexpr error_type error_badbrace = /*unspecified*/;
inline constexpr error_type error_range = /*unspecified*/;
inline constexpr error_type error_space = /*unspecified*/;
inline constexpr error_type error_badrepeat = /*unspecified*/;
inline constexpr error_type error_complexity = /*unspecified*/;

inline constexpr error_type error_stack = /*unspecified*/;
 (C++17 起)

error_type 是描述可能在正则表达式剖析期间发生的错误的类型。

常量

常量 | 解释
error_collate | 表达式含有非法对照字符名
error_ctype | 表达式含有非法字符类名
error_escape | 表达式含有非法转义字符或尾随转义
error_backref | 表达式含有非法回溯引用
error_brack | 表达式含有不匹配的方括号对（ '[' 与 ']' ）
error_paren | 表达式含有不匹配的括号对（ '(' 与 ')' ）
error_brace | 表达式含有不匹配的花括号对（ '{' 与 '}' ）
error_badbrace | 表达式在 {} 表达式中含有非法范围
error_range | 表达式含有非法字符范围（例如 [b-a] ）
error_space | 没有将表达式转换成有限状态机的足够内存
error_badrepeat | *?+{ 之一不后继一个合法正则表达式
error_complexity | 尝试的匹配的复杂度超过了预定义的等级
error_stack | 没有进行匹配的足够内存

注意

C++11 中，这些常量曾被指定带有冗余的关键词 static ，它为 C++14 通过 LWG 问题 2053 移除

参阅

regex_error
(C++11)
 报告正则表达式库生成的错误
(类)


std::regex_constants::match_flag_type

< cpp‎ | regex
定义于头文件 <regex>
typedef /*unspecified*/ match_flag_type;
 (C++11 起)
constexpr match_flag_type match_default = {};

constexpr match_flag_type match_not_bol = /*unspecified*/;
constexpr match_flag_type match_not_eol = /*unspecified*/;
constexpr match_flag_type match_not_bow = /*unspecified*/;
constexpr match_flag_type match_not_eow = /*unspecified*/;
constexpr match_flag_type match_any = /*unspecified*/;
constexpr match_flag_type match_not_null = /*unspecified*/;
constexpr match_flag_type match_continuous = /*unspecified*/;
constexpr match_flag_type match_prev_avail = /*unspecified*/;
constexpr match_flag_type format_default = {};
constexpr match_flag_type format_sed = /*unspecified*/;
constexpr match_flag_type format_no_copy = /*unspecified*/;

constexpr match_flag_type format_first_only = /*unspecified*/;
 (C++11 起)
(C++17 前)
inline constexpr match_flag_type match_default = {};

inline constexpr match_flag_type match_not_bol = /*unspecified*/;
inline constexpr match_flag_type match_not_eol = /*unspecified*/;
inline constexpr match_flag_type match_not_bow = /*unspecified*/;
inline constexpr match_flag_type match_not_eow = /*unspecified*/;
inline constexpr match_flag_type match_any = /*unspecified*/;
inline constexpr match_flag_type match_not_null = /*unspecified*/;
inline constexpr match_flag_type match_continuous = /*unspecified*/;
inline constexpr match_flag_type match_prev_avail = /*unspecified*/;
inline constexpr match_flag_type format_default = {};
inline constexpr match_flag_type format_sed = /*unspecified*/;
inline constexpr match_flag_type format_no_copy = /*unspecified*/;

inline constexpr match_flag_type format_first_only = /*unspecified*/;
 (C++17 起)

match_flag_type 是指定附加正则表达式匹配选项的位掩码类型 (BitmaskType) 。

常量

注意： [first, last) 指代要匹配的字符序列。

常量 | 解释
match_not_bol | [first,last) 中的首个字符将被处理成如同它不在行首（即 ^ 将不匹配 [first,first) ）
match_not_eol | [first,last) 中的最末字符将被处理成如同它不在行尾（即 $ 将不匹配 [last,last) ）
match_not_bow | "\b" 将不匹配 [first,first)
match_not_eow | "\b" 将不匹配 [last,last)
match_any | 若多于一个匹配可行，则任何匹配都是可接受的结果
match_not_null | 不匹配空字符序列
match_continuous | 仅匹配始于 first 的子串
match_prev_avail | --first 是合法的迭代位置。设置时导致 match_not_bol 和 match_not_bow 被忽略
format_default | 使用 ECMAScript 规则于 std::regex_replace 构造字符串（语法文档）
format_sed | 于 std::regex_replace 使用 POSIX sed 工具规则。（语法文档）
format_no_copy | 不复制不匹配的字符串到 std::regex_replace 中的输出
format_first_only | 仅替换 std::regex_replace 中的首个匹配

match_default 及 format_default 以外的所有常量都是位掩码元素。 match_default 与 format_default 常量是空位掩码。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2053 | C++11 | match_flag_type 不能为有作用域枚举，因为要求 match_default 与 format_default 从 ​0​ 初始化 | 使之从空花括号初始化

参阅

regex_match (C++11) | 尝试匹配一个正则表达式到整个字符序列 (函数模板)
syntax_option_type (C++11) | 控制正则表达式行为的通用选项 (typedef)
error_type (C++11) | 描述不同类型的匹配错误 (typedef)


std::match_results

< cpp‎ | regex
定义于头文件 <regex>
template<

class BidirIt,
class Alloc = std::allocator < std::sub_match <BidirIt>>

> class match_results;
 (1) (C++11 起)
namespace pmr {

template <class BidirIt>
using match_results = std::match_results<BidirIt,
std::pmr::polymorphic_allocator <
std::sub_match <BidirIt>>>;

}
 (2) (C++17 起)

类模板 std::match_results 保有表示正则表达式匹配结果的字符序列汇集。

这是特殊的具分配器容器。它只能默认创建、从std::regex_iterator 获得，或通过 std::regex_search 或 std::regex_match 修改。 std::match_results 保有 std::sub_match ，它们每个都是一对指向匹配的原初字符序列中的迭代器，故若原初字符序列被销毁，或指向它的迭代器因另外的原因非法化，则检验 std::match_results 是未定义行为。

match_result 中所含的首个 sub_match （下标 0 ）始终表示 regex 所做的目标序列内的完整匹配，而后继的 sub_match 表示按顺序对应分隔正则表达式中子表达式的左括号的子表达式匹配

std::match_results 满足知分配器容器 (AllocatorAwareContainer) 与序列容器 (SequenceContainer) 的要求，除了仅支持复制赋值、移动赋值和对常容器定义的操作，还有比较函数的语义异于对容器要求的语义。

类型要求

-
BidirIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求。
-
Alloc 必须满足分配器 (Allocator) 的要求。

特化

提供几个对常用字符类型的特化：

定义于头文件 <regex>
类型 | 定义
std::cmatch | std::match_results<const char*>
std::wcmatch | std::match_results<const wchar_t*>
std::smatch | std::match_results<std::string::const_iterator>
std::wsmatch | std::match_results<std::wstring::const_iterator>
std::pmr::cmatch (C++17) | std::pmr::match_results<const char*>
std::pmr::wcmatch (C++17) | std::pmr::match_results<const wchar_t*>
std::pmr::smatch (C++17) | std::pmr::match_results<std::string::const_iterator>
std::pmr::wsmatch (C++17) | std::pmr::match_results<std::wstring::const_iterator>

成员类型

成员类型 | 定义
allocator_type | Allocator
value_type | std::sub_match <BidirIt>
const_reference | const value_type&
reference | value_type&
const_iterator | 实现定义（取决于底层容器）
iterator | const_iterator
difference_type | std::iterator_traits <BidirIt>::difference_type
size_type | std::allocator_traits <Alloc>::size_type
char_type | std::iterator_traits <BidirIt>::value_type
string_type | std::basic_string <char_type>

成员函数

(构造函数)
 构造对象
(公开成员函数)
(析构函数)
 析构对象
(公开成员函数)
operator=
 赋值内容
(公开成员函数)
get_allocator
 返回关联的分配器
(公开成员函数)
状态
ready
 检查结果是否合法
(公开成员函数)
大小
empty
 检查匹配是否成功
(公开成员函数)
size
 返回完全建立的结果状态中的匹配数
(公开成员函数)
max_size
 返回子匹配的最大可能数量
(公开成员函数)
元素访问
length
 返回特定子匹配的长度
(公开成员函数)
position
 返回特定子匹配首字符的位置
(公开成员函数)
str
 返回特定子匹配的字符序列
(公开成员函数)
operator[]
 返回指定的子匹配
(公开成员函数)
prefix
 返回目标序列起始和完整匹配起始之间的子序列。
(公开成员函数)
suffix
 返回完整匹配结尾和目标序列结尾之间的子序列
(公开成员函数)
迭代器
begincbegin
 返回指向子匹配列表起始的迭代器
(公开成员函数)
endcend
 返回指向子匹配列表末尾的迭代器
(公开成员函数)
格式
format
 为输出格式化匹配结果
(公开成员函数)
修改器
swap
 交换内容
(公开成员函数)

非成员函数

operator==operator!= (C++20 中移除) | 以字典序比较两个匹配结果的值 (函数模板)
std::swap(std::match_results) (C++11) | 特化 std::swap 算法 (函数模板)


std::match_results<BidirIt,Alloc>::begin, std::match_results<BidirIt,Alloc>::cbegin

< cpp‎ | regex‎ | match results
iterator begin() noexcept; | (C++11 起)
const_iterator begin() const noexcept; | (C++11 起)
const_iterator cbegin() const noexcept; | (C++11 起)

返回指向子匹配列表开始的迭代器。若匹配成功，则迭代器将指向整个匹配的表达式。

参数

（无）

返回值

指向首个子匹配的迭代器。

复杂度

常数

参阅

endcend
 返回指向子匹配列表末尾的迭代器
(公开成员函数)


std::match_results<BidirIt,Alloc>::empty

< cpp‎ | regex‎ | match results
bool empty() const; | (C++11 起) (C++20 前)
[[nodiscard]] bool empty() const; | (C++20 起)

检查匹配是否成功。

参数

（无）

返回值

若 *this 表示失败匹配则为 true ，否则为 false ，即 size() == 0 。

异常

可能抛出实现定义的异常。

复杂度

常数。

参阅

size
 返回完全建立的结果状态中的匹配数
(公开成员函数)


std::match_results<BidirIt,Alloc>::end, std::match_results<BidirIt,Alloc>::cend

< cpp‎ | regex‎ | match results
iterator end() noexcept; | (C++11 起)
const_iterator end() const noexcept; | (C++11 起)
const_iterator cend() const noexcept; | (C++11 起)

返回指向子匹配列表结尾的迭代器。

参数

（无）

返回值

指向最后子匹配后一元素的迭代器。

复杂度

常数

参阅

begincbegin
 返回指向子匹配列表起始的迭代器
(公开成员函数)


std::match_results<BidirIt,Alloc>::format

< cpp‎ | regex‎ | match results
template< class OutputIt >

OutputIt format( OutputIt out,
const char_type* fmt_first, const char_type* fmt_last,
std::regex_constants::match_flag_type flags =

std::regex_constants::format_default ) const;
 (1) (C++11 起)
template< class OutputIt, class ST, class SA >

OutputIt format( OutputIt out,
const basic_string<char_type,ST,SA>& fmt,
std::regex_constants::match_flag_type flags =

std::regex_constants::format_default ) const;
 (2) (C++11 起)
template< class ST, class SA >

std::basic_string <char_type,ST,SA>
format( const std::basic_string <char_type,ST,SA>& fmt,
std::regex_constants::match_flag_type flags =

std::regex_constants::format_default ) const;
 (3) (C++11 起)
string_type format( const char_type* fmt_s,

std::regex_constants::match_flag_type flags =

std::regex_constants::format_default ) const;
 (4) (C++11 起)

format 输出格式字符串，它将字符串中的任何格式指定符或转义序列替换为来自 *this 的数据。

1) 格式字符序列以范围 [fmt_first, fmt_last) 定义。复制结果字符序列到 out 的副本。
2) 格式字符序列以 fmt 中的字符定义。复制结果字符序列到 out 的副本。
3-4) 格式字符序列分别以 fmt 和 fmt_s 中的字符定义。复制结果字符序列到新构造的 std::basic_string ，并返回它。

flags 位掩码确定辨识哪些格式指定符和转义序列。

若 ready() != true 则 format 的行为未定义。

参数

fmt_begin, fmt_end | - | 指向定义格式字符序列的字符范围的指针
fmt | - | 定义格式字符序列的 std::basic_string
fmt_s | - | 指向定义格式字符序列的空终止字符串的指针
out | - | 要复制结果字符串到的迭代器
flags | - | 指定辨识哪些格式指定符和转义序列的 std::regex_constants::match_flag_type 位掩码
类型要求
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。

返回值

1-2) out
3-4) 含结果字符序列的新构造字符串。

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <string>
#include <regex>

int main()
{
    std::string s = "for a good time, call 867-5309";
    std::regex phone_regex("\\d{3}-\\d{4}");
    std::smatch phone_match;

    if (std::regex_search(s, phone_match, phone_regex)) {
        std::string fmt_s = phone_match.format(
            "$`"    // $` 意味着匹配之前的字符
            "[$&]"  // $& 意味着匹配的字符
            "$'");  // $' 意味着后随匹配的字符
        std::cout << fmt_s << '\n';
    }
}

输出：

for a good time, call [867-5309]

参阅

regex_replace (C++11) | 以格式化的替换文本来替换正则表达式匹配的出现位置 (函数模板)
match_flag_type (C++11) | 特定于匹配的选项 (typedef)


std::match_results<BidirIt,Alloc>::get_allocator

< cpp‎ | regex‎ | match results
allocator_type get_allocator() const; | (C++11 起)

返回与对象关联的分配器。

参数

（无）

返回值

关联的分配器。

复杂度

常数。


std::match_results<BidirIt,Alloc>::length

< cpp‎ | regex‎ | match results
difference_type length( size_type n = 0 ) const; | (C++11 起)

返回指定子匹配的长度。

若 n == 0 ，则返回整个匹配的表达式的长度。

若 n > 0 && n < size() ，则返回第 n 个子匹配的长度。

若 n >= size() ，则返回未匹配的长度。

调用等价于 (*this)[n].length() 。

参数

n - 指定要检验哪个匹配的整数

返回值

指定的匹配或子匹配的长度。

参阅

operator[] | 返回指定的子匹配 (公开成员函数)
length | 若存在则返回匹配的长度 (std::sub_match<BidirIt> 的公开成员函数)


std::match_results<BidirIt,Alloc>::match_results

< cpp‎ | regex‎ | match results
match_results() : match_results(Allocator()) { } | (1) | (C++11 起)
explicit match_results( const Allocator& a ); | (2) | (C++11 起)
match_results( const match_results& rhs ); | (3) | (C++11 起)
match_results( match_results&& rhs ) noexcept; | (4) | (C++11 起)
1) 默认构造函数。构造未建立结果状态（ ready() != true ）的 match_result 。
2) 以 a 的副本分配器，构造未建立结果状态（ ready() != true ）的 match_result 。
3) 复制构造函数。以 rhs 的副本构造 match_result 。
4) 移动构造函数。用移动语义构造拥有 rhs 内容的 match_result 。调用后， rhs 在合法但未指定的状态。

参数

a | - | 用于此容器所有内存分配的分配器
rhs | - | 用作源以初始化 match_result 的另一 match_result

异常

1-2) 可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0935R0 | C++11 | 默认构造函数曾为 explicit | 使之为隐式


std::match_results<BidirIt,Alloc>::max_size

< cpp‎ | regex‎ | match results
size_type max_size() const noexcept; | (C++11 起)

返回 match_results 类型因系统或库实现限制而能保有最大子匹配数，即对于最大子匹配数的 std::distance (begin(), end()) 。

参数

（无）

返回值

最大子匹配数

复杂度

常数。


std::match_results<BidirIt,Alloc>::operator=

< cpp‎ | regex‎ | match results
定义于头文件 <regex> |  |
match_results& operator=( const match_results& other ); | (1) | (C++11 起)
match_results& operator=( match_results&& other ) noexcept; | (2) | (C++11 起)

赋值内容。

1) 复制赋值运算符。赋值 other 的内容。
2) 移动赋值运算符。用移动语义赋值 other 的内容。操作后 other 在合法但未指定的状态。

参数

other - 另一 match_results 对象

返回值

*this 。

异常

1) 可能抛出实现定义的异常。


std::match_results<BidirIt,Alloc>::operator[]

< cpp‎ | regex‎ | match results
const_reference operator[]( size_type n ) const; | (C++11 起)

若 n > 0 且 n < size() ，则返回到 std::sub_match 的引用，它表示第 n 个捕获的有标记子表达式所匹配的目标序列部分。

若 n == 0 ，则返回到 std::sub_match 的引用，它表示返回整个匹配的正则表达式所匹配的目标序列部分。

若 n >= size() ，则返回到 std::sub_match 的引用，它表示不配的子表达式（目标序列的空子范围）。

除非 ready() == true ，否则行为未定义。

参数

n - 指定要返回哪个匹配的整数

返回值

返回到表示目标序列中指定的匹配子范围的 std::sub_match 的引用。

示例

#include <iostream>
#include <regex>
#include <string>

int main()
{
    std::string target("baaaby");
    std::smatch sm;

    std::regex re1("a(a)*b");
    std::regex_search(target, sm, re1);
    std::cout << "entire match: " << sm[0] << '\n'
              << "submatch #1: " << sm[1] << '\n';

    std::regex re2("a(a*)b");
    std::regex_search(target, sm, re2);
    std::cout << "entire match: " << sm[0] << '\n'
              << "submatch #1: " << sm[1] << '\n';

}

输出：

entire match: aaab
submatch #1: a
entire match: aaab
submatch #1: aa

参阅

str
 返回特定子匹配的字符序列
(公开成员函数)


operator==,!=(std::match_results)

< cpp‎ | regex‎ | match results
定义于头文件 <regex> |  |
template< class BidirIt, class Alloc > bool operator==( match_results<BidirIt,Alloc>& lhs, match_results<BidirIt,Alloc>& rhs ); | (1) | (C++11 起)
template< class BidirIt, class Alloc > bool operator!=( match_results<BidirIt,Alloc>& lhs, match_results<BidirIt,Alloc>& rhs ); | (2) | (C++11 起) (C++20 前)

比较二个 match_results 对象。

若满足下列条件则二个 match_results 相等：

  • 无一对象为就绪，或
  • 二个 match_results 均为就绪且满足下列条件：
  • lhs.empty() 且 rhs.empty() ，或
  • !lhs.empty() 且 !rhs.empty() 并满足下列条件：
  • lhs.prefix() == rhs.prefix()
  • lhs.size() == rhs.size() && std::equal (lhs.begin(), lhs.end(), rhs.begin())
  • lhs.suffix() == rhs.suffix()
1) 检查 lhs 与 rhs 是否相等。
2) 检查 lhs 与 rhs 是否不相等。

参数

lhs, rhs - 要比较的 match_results
类型要求
-
BidirIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求。
-
Alloc 必须满足分配器 (Allocator) 的要求。

返回值

1) 若 lhs 与 rhs 相等则为 true ，否则为 false 。
2) 若 lhs 与 rhs 不相等则为 true ，否则为 false 。

异常

可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例


std::match_results<BidirIt,Alloc>::position

< cpp‎ | regex‎ | match results
difference_type position( size_type n = 0 ) const; | (C++11 起)

返回指定的子匹配的首字符位置。

若 n == 0 ，则返回整个匹配表达式的首字符位置。

若 n > 0 && n < size() ，则返回第 n 个子匹配的首字符位置。

若 n >= size() ，则返回不匹配的首字符位置。

参数

n - 指定要检验哪个匹配的整数

返回值

指定的匹配或子匹配的首字符位置。

示例

#include <iostream>
#include <regex>
#include <string>

int main()
{
    std::regex re("a(a)*b");
    std::string target("aaab");
    std::smatch sm;

    std::regex_match(target, sm, re);
    std::cout << sm.position(1) << '\n';
}

输出：

1

参阅

operator[]
 返回指定的子匹配
(公开成员函数)


std::match_results<BidirIt,Alloc>::prefix

< cpp‎ | regex‎ | match results
const_reference prefix() const; | (C++11 起)

获得到 std::sub_match 对象的引用，该对象表示目标序列起始到正则表达式的整个匹配起始之间的目标序列。

除非 ready() == true ，否则行为未定义。

参数

（无）

返回值

到未匹配前缀的引用。

示例

#include <iostream>
#include <regex>
#include <string>

int main()
{
  std::regex re("a(a)*b");
  std::string target("baaaby");
  std::smatch sm;

  std::regex_search(target, sm, re);
  std::cout << sm.prefix().str() << '\n';
}

输出：

b


std::match_results<BidirIt,Alloc>::ready

< cpp‎ | regex‎ | match results
bool ready() const; | (C++11 起)

指示 match_results 是否就绪（合法）。

默认构造的 match_results 无结果状态（未就绪），而且只能由正则表达式算法之一变为就绪。就绪状态隐含已经完整建立了所有匹配结果。

在未就绪的 match_results 对象上调用大多数成员函数的结果未定义。

返回值

若 match_results 就绪则为 true ，否则为 false 。

示例

#include <iostream>
#include <regex>
#include <string>

int main()
{
    std::string target("pattern");
    std::smatch sm;
    std::cout << "default constructed smatch is "
              << (sm.ready() ? " ready\n" : " not ready\n");

    std::regex re1("tte");
    std::regex_search(target, sm, re1);

    std::cout << "after search, smatch is "
              << (sm.ready() ? " ready\n" : " not ready\n");
}

输出：

default constructed smatch is  not ready
after search, smatch is  ready


std::match_results<BidirIt,Alloc>::size

< cpp‎ | regex‎ | match results
size_type size() const noexcept; | (C++11 起)

返回子匹配数，即 std::distance (begin(), end()) 。

若 *this 不表示成功匹配的结果则返回 0 、

参数

（无）

返回值

子匹配数

复杂度

常数

示例

#include <iostream>
#include <regex>
#include <string>

int main()
{
    std::regex re("a(a)*b");
    std::string target("aaab");
    std::smatch sm;

    std::cout << sm.size() << '\n';

    std::regex_match(target, sm, re);
    std::cout << sm.size() << '\n';
}

输出：

0
2

参阅

begincbegin | 返回指向子匹配列表起始的迭代器 (公开成员函数)
endcend | 返回指向子匹配列表末尾的迭代器 (公开成员函数)


std::match_results<BidirIt,Alloc>::str

< cpp‎ | regex‎ | match results
string_type str( size_type n = 0 ) const; | (C++11 起)

返回表示指示的子匹配的字符串。

若 n == 0 ，则返回表示整个匹配的表达式的字符串。

若 n > 0 && n < size() ，则返回表示第 n 个子匹配的字符串。

若 n >= size() ，则返回表示不匹配的匹配的字符串。

调用等价于 string_type((*this)[n]) 。

参数

n - 指定要返回哪个匹配的整数

返回值

返回表示指定匹配或子匹配的字符串。

示例

#include <iostream>
#include <regex>
#include <string>

int main()
{
    std::string target("baaaby");
    std::smatch sm;

    std::regex re1("a(a)*b");
    std::regex_search(target, sm, re1);
    std::cout << "entire match: " << sm.str(0) << '\n'
              << "submatch #1: " << sm.str(1) << '\n';

    std::regex re2("a(a*)b");
    std::regex_search(target, sm, re2);
    std::cout << "entire match: " << sm.str(0) << '\n'
              << "submatch #1: " << sm.str(1) << '\n';

}

输出：

entire match: aaab
submatch #1: a
entire match: aaab
submatch #1: aa

参阅

operator[]
 返回指定的子匹配
(公开成员函数)


std::match_results<BidirIt,Alloc>::suffix

< cpp‎ | regex‎ | match results
const_reference suffix() const; | (C++11 起)

获得到 std::sub_match 对象的引用，该对象表示正则表达式的整个匹配结尾，和目标序列结尾之间的目标序列。

除非 ready() == true ，否则行为未定义。

参数

（无）

返回值

到未匹配后缀的引用。

示例

#include <iostream>
#include <regex>
#include <string>

int main()
{
    std::regex re("a(a)*b");
    std::string target("baaaby");
    std::smatch sm;

    std::regex_search(target, sm, re);
    std::cout << sm.suffix().str() << '\n';
}

输出：

y


std::match_results<BidirIt,Alloc>::swap

< cpp‎ | regex‎ | match results
void swap( match_results& other ) noexcept; | (C++11 起)

交换二个 match_results 对象的共享状态。

参数

other - 要与之交换的 match_results

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

std::swap(std::match_results)
(C++11)
 特化 std::swap 算法
(函数模板)


std::swap(std::match_results)

< cpp‎ | regex‎ | match results
定义于头文件 <regex> |
template< class BidirIt, class Alloc > void swap( match_results<BidirIt,Alloc>& x1, match_results<BidirIt,Alloc>& x2 ) noexcept; | (C++11 起)

为 std::match_results 特化 std::swap 算法。交换 x1 与 x2 的内容。等效地调用 x1.swap(x2) 。

参数

x1, x2 - 要交换内容的 match_results 对象
类型要求
-
BidirIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求。
-
Alloc 必须满足分配器 (Allocator) 的要求。

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

swap
 交换内容
(公开成员函数)


std::match_results<BidirIt,Alloc>::~match_results

< cpp‎ | regex‎ | match results
~match_results(); | (C++11 起)

销毁 match_results 对象和关联的子匹配。

复杂度

与子匹配数成线性。


std::regex_error

< cpp‎ | regex
定义于头文件 <regex> |
class regex_error; | (C++11 起)

定义抛出的异常对象类型，以报告正则表达式库中的错误。

cpp/error/exception cpp/error/runtime error

继承图

成员函数

(构造函数) | 构造 regex_error 对象 (公开成员函数)
operator= | 替换 regex_error 对象 (公开成员函数)
code | 获得 regex_error 的 std::regex_constants::error_type (公开成员函数)

继承自 std::runtime_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

示例

#include <regex>
#include <iostream>

int main()
{
    try {
        std::regex re("[a-b][a");
    }
    catch (const std::regex_error& e) {
        std::cout << "regex_error caught: " << e.what() << '\n';
        if (e.code() == std::regex_constants::error_brack) {
            std::cout << "The code was error_brack\n";
        }
    }
}

可能的输出：

regex_error caught: The expression contained mismatched [ and ].
The code was error_brack


std::regex_error::code

< cpp‎ | regex‎ | regex error
定义于头文件 <regex> |
std::regex_constants::error_type code() const; | (C++11 起)

返回传递给 std::regex_error 构造函数的 std::regex_constants::error_type 。

参阅

error_type (C++11) | 描述不同类型的匹配错误 (typedef)
(构造函数) | 构造 regex_error 对象 (公开成员函数)


std::regex_error::operator=

< cpp‎ | regex‎ | regex error
regex_error& operator=( const regex_error& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::regex_error 则赋值后 std::strcmp (what(), other.what()) == 0 。

参数

other - 用以赋值的另一 system_error 对象

返回值

*this

示例

本节未完成
原因：暂无示例


std::regex_error::regex_error

< cpp‎ | regex‎ | regex error
定义于头文件 <regex> |  |
regex_error( std::regex_constants::error_type ecode ); | (1) | (C++11 起)
regex_error( const regex_error& other ); | (2) | (C++11 起)
1) 以给定 std::regex_constants::error_type 类型的 ecode 构造 regex_error 。
2) 复制构造函数。以 other 的内容初始化内容。若 *this 与 other 均拥有动态类型 std::regex_error 则 std::strcmp (what(), other.what()) == 0 。

参数

ecode | - | 指示正则表达式分析中引发的错误的错误码
other | - | 要复制的另一 regex_error 对象

参阅

error_type
(C++11)
 描述不同类型的匹配错误
(typedef)


std::regex_iterator

< cpp‎ | regex
定义于头文件 <regex> |
template< class BidirIt, class CharT = typename std::iterator_traits <BidirIt>::value_type, class Traits = std::regex_traits <CharT> > class regex_iterator | (C++11 起)

std::regex_iterator 是访问底层字符序列中正则表达式的单独匹配的只读老式向前迭代器 (LegacyForwardIterator) 。

在构造和每次自增时，它调用 std::regex_search 并记忆结果（即保存值 std::match_results <BidirIt> 的副本）。第一个对象可能在构造迭代器或进行首次解引用时读取。其他情况下，解引用只返回最近获得的正则表达式匹配副本。

默认构造的 std::regex_iterator 是序列尾迭代器。在抵达最后匹配（std::regex_search 返回 false ）后自增合法的 std::regex_iterator 时，它变得等于序列尾迭代器。进一步解引用或自增它引发未定义行为。

典型的 std::regex_iterator 实现保有底层序列的开始和结束迭代器（二个 BidirIt 实例）、指向正则表达式的指针（ const regex_type* ）、匹配标志（ std::regex_constants::match_flag_type ）和当前匹配（ std::match_results <BidirIt> ）。

类型要求

-
BidirIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求。

特化

提供对于常用字符序列类型的数个特化：

定义于头文件 <regex>
类型 | 定义
cregex_iterator | regex_iterator<const char*>
wcregex_iterator | regex_iterator<const wchar_t*>
sregex_iterator | regex_iterator<std::string::const_iterator>
wsregex_iterator | regex_iterator<std::wstring::const_iterator>

成员类型

成员类型 | 定义
value_type | std::match_results <BidirIt>
difference_type | std::ptrdiff_t
pointer | const value_type*
reference | const value_type&
iterator_category | std::forward_iterator_tag
regex_type | basic_regex<CharT, Traits>

成员函数

(构造函数) | 构造新的 regex_iterator (公开成员函数)
(析构函数) (隐式声明) | 析构 regex_iterator ，包含缓存的值 (公开成员函数)
operator= | 赋值内容 (公开成员函数)
operator==operator!= (C++20 中移除) | 比较两个 regex_iterator (公开成员函数)
operator*operator-> | 访问当前匹配 (公开成员函数)
operator++operator++(int) | 推进迭代器到下一个匹配 (公开成员函数)

注解

程序员负责确保传递给迭代器构造函数的 std::basic_regex 对象活得长于迭代器。因为迭代器存储指向 regex 的指针，故在销毁 regex 后自增迭代器会访问悬垂指针。

若匹配的正则表达式部分仅是断言（ ^ 、 $ 、 \b 、 \B ），则存储于迭代器的匹配是零长度匹配，即 match[0].first == match[0].second 。

示例

#include <regex>
#include <iterator>
#include <iostream>
#include <string>

int main()
{
    const std::string s = "Quick brown fox.";

    std::regex words_regex("[^\\s]+");
    auto words_begin =
        std::sregex_iterator(s.begin(), s.end(), words_regex);
    auto words_end = std::sregex_iterator();

    std::cout << "Found "
              << std::distance(words_begin, words_end)
              << " words:\n";

    for (std::sregex_iterator i = words_begin; i != words_end; ++i) {
        std::smatch match = *i;
        std::string match_str = match.str();
        std::cout << match_str << '\n';
    }
}

输出：

Found 3 words:
Quick
brown
fox.

参阅

match_results (C++11) | 标识一个正则表达式匹配，包含所有子表达式匹配 (类模板)
regex_search (C++11) | 尝试匹配一个正则表达式到字符序列的任何部分 (函数模板)


std::regex_iterator<BidirIt,CharT,Traits>::operator*,operator->

< cpp‎ | regex‎ | regex iterator
const value_type& operator*() const; | (1) | (C++11 起)
const value_type* operator->() const; | (2) | (C++11 起)

从 regex_iterator 提取当前 std::match_results ：

1) 返回到当前 std::match_results 的引用。
2) 返回指向当前 std::match_results 的指针。

示例

#include <iostream>
#include <string>
#include <regex>

int main()
{
    std::regex expression("[1234]");
    std::string searchStr("1.1a2b3cjk34");

    for (std::regex_iterator<std::string::iterator> it{
        searchStr.begin(), searchStr.end(), expression
    }, last{}; it != last; ++it) {
        std::cout << it->str();
    }
}

输出：

112334


std::regex_iterator<BidirIt,CharT,Traits>::operator=

< cpp‎ | regex‎ | regex iterator
regex_iterator& operator=( const regex_iterator& other ); | (C++11 起)

赋值 other 的内容。

参数

other - 要赋值的 regex_iterator

返回值

*this 。


std::regex_iterator<BidirIt,CharT,Traits>::operator++, operator++(int)

< cpp‎ | regex‎ | regex iterator
regex_iterator& operator++(); | (C++11 起)
regex_iterator operator++(int); | (C++11 起)

推进迭代器到下个匹配。

本节未完成
原因：更好地解释

首先以 match[0].second 的值构造 BidirIt 类型局部变量。

若迭代器保有零长匹配且 start == end ，则设置 *this 为序列尾迭代器，函数返回。

否则，若迭代器保有零长匹配，则运算符调用以下内容：

regex_search(start, end, match, *pregex,
flags | regex_constants::match_not_null |
regex_constants::match_continuous);

若调用返回 true ，则函数返回。

否则运算符自增 start 并持续，如同最近匹配不是零长匹配。

若最近匹配不是零长匹配，则运算符设置 flags 为 flags | regex_constants::match_prev_avail 并调用以下内容：

regex_search(start, end, match, *pregex, flags);

若调用返回 false ，则运算符设置 *this 为序列尾迭代器，函数返回。

调用 regex_search 返回 true 的所有情况下， match.prefix().first 将等于 match[0].second 的先前值，而且对于范围 [0, match.size()) 中满足 match[i].matched 为 true 的的每个 i ， match[i].position() 将返回 distance(begin, match[i].first) 。

这表明 match[i].position() 给出自目标序列起始的偏移，它通常与从传递给 regex_search 调用中的序列偏移不同。

实现如何进行这些调整是未指定的。这表明编译器可以调用实现限定的搜索函数，该情况下将不调用用户定义的 regex_search 特化。

若迭代器是序列尾迭代器则行为未定义。

参数

（无）

返回值

1) *this
2) 迭代器的先前值。


std::regex_iterator<BidirIt,CharT,Traits>::operator==,operator!=

< cpp‎ | regex‎ | regex iterator
bool operator==(const regex_iterator& rhs) const; | (1) | (C++11 起)
bool operator!=(const regex_iterator& rhs) const; | (2) | (C++11 起) (C++20 前)

比较二个 regex_iterator 。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

rhs - 要比较的 regex_iterator

返回值

为说明起见，假设 regex_iterator 含下列成员：

  • BidirIt begin;
  • BidirIt end;
  • const regex_type *pregex;
  • std::regex_constants::match_flag_type flags;
  • std::match_results <BidirIt> match;
1) 若 *this 和 rhs 都是序列尾迭代器，或若下列条件全为 true 则返回 true ：
  • begin == rhs.begin
  • end == rhs.end
  • pregex == rhs.pregex
  • flags == rhs.flags
  • match[0] == rhs.match[0]
2) 返回 !(*this == rhs)

示例

本节未完成
原因：暂无示例


std::regex_iterator<BidirIt,CharT,Traits>::regex_iterator

< cpp‎ | regex‎ | regex iterator
regex_iterator();
 (1) (C++11 起)
regex_iterator(BidirIt a, BidirIt b,

const regex_type& re,
std::regex_constants::match_flag_type m =

std::regex_constants::match_default );
 (2) (C++11 起)
regex_iterator(const regex_iterator&);
 (3) (C++11 起)
regex_iterator(BidirIt, BidirIt,

const regex_type&&,
std::regex_constants::match_flag_type =

std::regex_constants::match_default ) = delete;
 (4) (C++11 起)

构造新的 regex_iterator ：

1) 默认构造函数。构造序列尾迭代器。
2) 从字符序列 [a, b) 、正则表达式 re 和掌管匹配行为的标志 m 构造 regex_iterator 。此构造函数以此数据进行 std::regex_search 的初始调用。若此初始调用结构为 false ，则设置 *this 为序列尾迭代器。
3) 复制 regex_iterator 。
4) 不允许以临时 regex 调用重载 2 ，因为返回的迭代会被立即非法化。

参数

a | - | 指向目标字符序列起始的 BidirIt
b | - | 指向目标字符序列结尾的 BidirIt
re | - | 用于搜索目标字符序列的正则表达式
m | - | 掌管 re 行为的标志

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2332 | C++11 | 从临时 basic_regex 构造的 regex_iterator 会立即变为非法 | 通过被删除的重载禁止这种构造


std::regex_match

< cpp‎ | regex
定义于头文件 <regex>
template< class BidirIt,

class Alloc, class CharT, class Traits >
bool regex_match( BidirIt first, BidirIt last,
std::match_results <BidirIt,Alloc>& m,
const std::basic_regex <CharT,Traits>& e,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (1) (C++11 起)
template< class BidirIt,

class CharT, class Traits >
bool regex_match( BidirIt first, BidirIt last,
const std::basic_regex <CharT,Traits>& e,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (2) (C++11 起)
template< class CharT, class Alloc, class Traits >

bool regex_match( const CharT* str,
std::match_results <const CharT*,Alloc>& m,
const std::basic_regex <CharT,Traits>& e,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (3) (C++11 起)
template< class STraits, class SAlloc,

class Alloc, class CharT, class Traits >
bool regex_match( const std::basic_string <CharT,STraits,SAlloc>& s,
std::match_results <
typename std::basic_string <CharT,STraits,SAlloc>::const_iterator,
Alloc
>& m,
const std::basic_regex <CharT,Traits>& e,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (4) (C++11 起)
template< class CharT, class Traits >

bool regex_match( const CharT* str,
const std::basic_regex <CharT,Traits>& e,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (5) (C++11 起)
template< class STraits, class SAlloc,

class CharT, class Traits >
bool regex_match( const std::basic_string <CharT, STraits, SAlloc>& s,
const std::basic_regex <CharT,Traits>& e,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (6) (C++11 起)
template< class STraits, class SAlloc,

class Alloc, class CharT, class Traits >
bool regex_match( const std::basic_string <CharT,STraits,SAlloc>&&,
std::match_results <
typename std::basic_string <CharT,STraits,SAlloc>::const_iterator,
Alloc
>&,
const std::basic_regex <CharT,Traits>&,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default ) = delete;
 (7) (C++11 起)

确定正则表达式 el 是否匹配整个目标字符序列，它可能以 std::string 、 C 字符串或迭代器对表示。

1) 确定正则表达式 e 和整个目标字符序列 [first,last) 间是否有匹配，不计 flags 的效果。确定是否有匹配时，只考虑匹配整个字符序列的潜在匹配。匹配结果返回于 m 。
2) 表现同上面的 (1) ，省去匹配结果。
3) 返回 std::regex_match(str, str + std::char_traits <charT>::length(str), m, e, flags) 。
4) 返回 std::regex_match(s.begin(), s.end(), m, e, flags) 。
5) 返回 std::regex_match(str, str + std::char_traits <charT>::length(str), e, flags) 。
6) 返回 std::regex_match(s.begin(), s.end(), e, flags) 。
7) 禁止重载 (4) 接受临时 string ，否则此函数会以立即变为非法的 string 迭代器填充 match_results m 。

注意 regex_match 将只成功地匹配正则表达式到整个字符序列，而 std::regex_search 将成功地匹配子序列。

参数

first, last | - | 应用 regex 到的目标字符范围，以迭代器给定
m | - | 匹配结果
str | - | 目标字符串，以空终止 C 风格字符串给出
s | - | 目标字符串，以 std::basic_string 给出
e | - | 正则表达式
flags | - | 用于确定将如何进行匹配的标志
类型要求
- BidirIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求。

返回值

若匹配存在则返回 true ，否则返回 false 。任一情况下，以下列方式更新对象 m ：

若匹配不存在：

m.ready() == true
m.empty() == true
m.size() == 0

若匹配存在：

m.ready() | true
m.empty() | false
m.size() | 有标记子表达式数加 1 ，即 1+e.mark_count()
m.prefix().first | first
m.prefix().second | first
m.prefix().matched | false （匹配前缀为空）
m.suffix().first | last
m.suffix().second | last
m.suffix().matched | false （匹配前缀为空）
m[0].first | first
m[0].second | last
m[0].matched | true （匹配整个序列）
m[n].first | 匹配有标记子表达式 n 的序列起始，或若该子表达式不参与匹配则为 last
m[n].second | 匹配有标记子表达式 n 的序列结尾，或若该子表达式不参与匹配则为 last
m[n].matched | 若表达式 n 参与匹配则为 true ，否则为 false

注解

因为 regex_match 只考虑完全匹配，故同一 regex 可能在 regex_match 和 std::regex_search 间给出不同的匹配：

std::regex re("Get|GetValue");
std::cmatch m;
std::regex_search("GetValue", m, re);  // 返回 true ，且 m[0] 含 "Get"
std::regex_match ("GetValue", m, re);  // 返回 true ，且 m[0] 含 "GetValue"
std::regex_search("GetValues", m, re); // 返回 true ，且 m[0] 含 "Get"
std::regex_match ("GetValues", m, re); // 返回 false

示例

#include <iostream>
#include <string>
#include <regex>

int main()
{
    // 简单正则表达式匹配
    std::string fnames[] = {"foo.txt", "bar.txt", "baz.dat", "zoidberg"};
    std::regex txt_regex("[a-z]+\\.txt");

    for (const auto &fname : fnames) {
        std::cout << fname << ": " << std::regex_match(fname, txt_regex) << '\n';
    }

    // 提取子匹配
    std::regex base_regex("([a-z]+)\\.txt");
    std::smatch base_match;

    for (const auto &fname : fnames) {
        if (std::regex_match(fname, base_match, base_regex)) {
            // 首个 sub_match 是整个字符串；下个
            // sub_match 是首个有括号表达式。
            if (base_match.size() == 2) {
                std::ssub_match base_sub_match = base_match[1];
                std::string base = base_sub_match.str();
                std::cout << fname << " has a base of " << base << '\n';
            }
        }
    }

    // 提取几个子匹配
    std::regex pieces_regex("([a-z]+)\\.([a-z]+)");
    std::smatch pieces_match;

    for (const auto &fname : fnames) {
        if (std::regex_match(fname, pieces_match, pieces_regex)) {
            std::cout << fname << '\n';
            for (size_t i = 0; i < pieces_match.size(); ++i) {
                std::ssub_match sub_match = pieces_match[i];
                std::string piece = sub_match.str();
                std::cout << "  submatch " << i << ": " << piece << '\n';
            }
        }
    }
}

输出：

foo.txt: 1
bar.txt: 1
baz.dat: 0
zoidberg: 0
foo.txt has a base of foo
bar.txt has a base of bar
foo.txt
  submatch 0: foo.txt
  submatch 1: foo
  submatch 2: txt
bar.txt
  submatch 0: bar.txt
  submatch 1: bar
  submatch 2: txt
baz.dat
  submatch 0: baz.dat
  submatch 1: baz
  submatch 2: dat

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2329 | C++11 | 曾接受 basic_string 右值，这较可能导致悬垂迭代器 | 通过被删除的重载拒绝

参阅

basic_regex (C++11) | 正则表达式对象 (类模板)
match_results (C++11) | 标识一个正则表达式匹配，包含所有子表达式匹配 (类模板)
regex_search (C++11) | 尝试匹配一个正则表达式到字符序列的任何部分 (函数模板)


std::regex_replace

< cpp‎ | regex
定义于头文件 <regex>
template< class OutputIt, class BidirIt,

class Traits, class CharT,
class STraits, class SAlloc >
OutputIt regex_replace( OutputIt out, BidirIt first, BidirIt last,
const std::basic_regex <CharT,Traits>& re,
const std::basic_string <CharT,STraits,SAlloc>& fmt,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (1) (C++11 起)
template< class OutputIt, class BidirIt,

class Traits, class CharT >
OutputIt regex_replace( OutputIt out, BidirIt first, BidirIt last,
const std::basic_regex <CharT,Traits>& re,
const CharT* fmt,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (2) (C++11 起)
template< class Traits, class CharT,

class STraits, class SAlloc,
class FTraits, class FAlloc >
std::basic_string <CharT,STraits,SAlloc>
regex_replace( const std::basic_string <CharT,STraits,SAlloc>& s,
const std::basic_regex <CharT,Traits>& re,
const std::basic_string <CharT,FTraits,FAlloc>& fmt,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (3) (C++11 起)
template< class Traits, class CharT,

class STraits, class SAlloc >
std::basic_string <CharT,STraits,SAlloc>
regex_replace( const std::basic_string <CharT,STraits,SAlloc>& s,
const std::basic_regex <CharT,Traits>& re,
const CharT* fmt,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (4) (C++11 起)
template< class Traits, class CharT,

class STraits, class SAlloc >
std::basic_string <CharT>
regex_replace( const CharT* s,
const std::basic_regex <CharT,Traits>& re,
const std::basic_string <CharT,STraits,SAlloc>& fmt,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (5) (C++11 起)
template< class Traits, class CharT >

std::basic_string <CharT>
regex_replace( const CharT* s,
const std::basic_regex <CharT,Traits>& re,
const CharT* fmt,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (6) (C++11 起)

regex_replace 用正则表达式进行字符序列的替换：

1) 复制 [first,last) 中的字符到 out ，以 re 所格式化的字符替换任何匹配 fmt 的序列。换言之：
  • 如同以 std::regex_iterator <BidirIt, CharT, traits> i(first, last, re, flags) 构造 std::regex_iterator 对象 i ，并用它在序列 [first,last) 内前进通过每个 re 的匹配。
  • 对于每个匹配 m ，如同用 out = std::copy (m.prefix().first, m.prefix().second, out) 复制非匹配子序列（ m.prefix() ）到 out ，然后如同通过调用 out = m.format(out, fmt, flags) ，以格式化替换字符串替换匹配的子序列。
  • 找不到更多匹配时，如同用 out = std::copy (last_m.suffix().first, last_m.suffix().second, out) 复制剩余的非匹配字符到 out ，其中 last_m 是找到的最后匹配的副本。
  • 若无匹配，则原态地复制整个序列到 out ，以 out = std::copy (first, last, out) 。
  • 若 flags 含有 std::regex_constants::format_no_copy ，则不复制非匹配的子序列到 out 。
  • 若 flags 含有 std::regex_constants::format_first_only ，则只替换首个匹配。
2) 同 1) ，但如同以调用 out = m.format(out, fmt, fmt + char_traits<charT>::length(fmt), flags) 进行格式化替换。
3-4) 构造 std::basic_string <CharT, ST, SA> 类型空字符串 result ，并调用 std::regex_replace( std::back_inserter (result), s.begin(), s.end(), re, fmt, flags) 。
5-6) 构造 std::basic_string <CharT> 类型空字符串 result 并调用 std::regex_replace( std::back_inserter (result), s, s + std::char_traits <CharT>::length(s), re, fmt, flags) 。

参数

first, last | - | 以一对迭代器表示的输入字符序列
s | - | 以 std::basic_string 或字符数组表示的输入字符序列
re | - | 将与输入序列匹配的 std::basic_regex
flags | - | std::regex_constants::match_flag_type 类型的匹配标志
fmt | - | 正则表达式替换格式字符串，准确语法依赖于 flags 的值
out | - | 存储替换结果的输出迭代器
类型要求
- OutputIt 必须满足老式输出迭代器 (LegacyOutputIterator) 的要求。
- BidirIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求。

返回值

1-2) 返回输出迭代器 out 在所有插入后的副本。
3-6) 返回含有输出的字符串 result 。

异常

可能抛出指示错误条件的 std::regex_error 。

示例

#include <iostream>
#include <iterator>
#include <regex>
#include <string>

int main()
{
   std::string text = "Quick brown fox";
   std::regex vowel_re("a|e|i|o|u");

   // 写结果到输出迭代器
   std::regex_replace(std::ostreambuf_iterator<char>(std::cout),
                      text.begin(), text.end(), vowel_re, "*");

   // 构造保有结果的字符串
   std::cout << '\n' << std::regex_replace(text, vowel_re, "[$&]") << '\n';
}

输出：

Q**ck br*wn f*x
Q[u][i]ck br[o]wn f[o]x

参阅

regex_search (C++11) | 尝试匹配一个正则表达式到字符序列的任何部分 (函数模板)
match_flag_type (C++11) | 特定于匹配的选项 (typedef)


std::regex_search

< cpp‎ | regex
定义于头文件 <regex>
template< class BidirIt,

class Alloc, class CharT, class Traits >
bool regex_search( BidirIt first, BidirIt last,
std::match_results <BidirIt,Alloc>& m,
const std::basic_regex <CharT,Traits>& e,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (1) (C++11 起)
template< class CharT, class Alloc, class Traits >

bool regex_search( const CharT* str,
std::match_results <const CharT*,Alloc>& m,
const std::basic_regex <CharT,Traits>& e,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (2) (C++11 起)
template< class STraits, class SAlloc,

class Alloc, class CharT, class Traits >
bool regex_search( const std::basic_string <CharT,STraits,SAlloc>& s,
std::match_results <
typename std::basic_string <CharT,STraits,SAlloc>::const_iterator,
Alloc
>& m,
const std::basic_regex <CharT, Traits>& e,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (3) (C++11 起)
template< class BidirIt,

class CharT, class Traits >
bool regex_search( BidirIt first, BidirIt last,
const std::basic_regex <CharT,Traits>& e,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (4) (C++11 起)
template< class CharT, class Traits >

bool regex_search( const CharT* str,
const std::basic_regex <CharT,Traits>& e,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (5) (C++11 起)
template< class STraits, class SAlloc,

class CharT, class Traits >
bool regex_search( const std::basic_string <CharT,STraits,SAlloc>& s,
const std::basic_regex <CharT,Traits>& e,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default );
 (6) (C++11 起)
template< class STraits, class SAlloc,

class Alloc, class CharT, class Traits >
bool regex_search( const std::basic_string <CharT,STraits,SAlloc>&&,
std::match_results <
typename std::basic_string <CharT,STraits,SAlloc>::const_iterator,
Alloc
>&,
const std::basic_regex <CharT, Traits>&,
std::regex_constants::match_flag_type flags =

std::regex_constants::match_default ) = delete;
 (7) (C++11 起)

确定正则表达式 e 和目标字符序列中的某个子序列间是否有匹配。

1) 分析泛型范围 [first,last) 。返回匹配结果于 m 。
2) 分析 str 所指向的空终止字符串。返回匹配结果于 m 。
3) 分析 string s 。返回匹配结果于 m 。
4-6) 等价于 (1-3) ，只是省略匹配结果。
7) 禁止重载 (3) 接受临时字符串，否则此函数将以立即变为非法的 string 迭代器填充 match_results m 。

regex_search 将成功地匹配给定序列的任何子序列，相对地 std::regex_match 仅若正则表达式匹配整个序列才返回 true 。

参数

first, last | - | 标识目标字符序列的范围
str | - | 指向空终止字符序列的指针
s | - | 标识目标字符序列的指针
e | - | 应当应用到目标字符序列的 std::regex
m | - | 匹配结果
flags | - | 掌管搜索行为的 std::regex_constants::match_flag_type
类型要求
- BidirIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求。
- Alloc 必须满足分配器 (Allocator) 的要求。

返回值

若匹配存在则返回 true ，否则返回 false 。任一情况下，更新对象 m 如下：

若匹配不存在：

m.ready() == true
m.empty() == true
m.size() == 0

若匹配存在：

m.ready() | true
m.empty() | false
m.size() | 有标记子表达式的数量加 1 ，即 1+e.mark_count()
m.prefix().first | first
m.prefix().second | m[0].first
m.prefix().matched | m.prefix().first != m.prefix().second
m.suffix().first | m[0].second
m.suffix().second | last
m.suffix().matched | m.suffix().first != m.suffix().second
m[0].first | 匹配序列的起始
m[0].second | 匹配数列的结尾
m[0].matched | true
m[n].first | 匹配有标记子表达式 n 的序列的起始，或若子表达式不参与匹配则为 last
m[n].second | 匹配有标记子表达式 n 的序列的结尾，或若子表达式不参与匹配则为 last
m[n].matched | 若子表达式 n 参与匹配则为 true ，否则为 false

注解

为在目标序列内检验所有匹配，可在循环中调用 std::regex_search ，每次从先前调用的 m[0].second 重新开始。 std::regex_iterator 提供对此迭代的简易接口。

示例

#include <iostream>
#include <string>
#include <regex>

int main()
{
    std::string lines[] = {"Roses are #ff0000",
                           "violets are #0000ff",
                           "all of my base are belong to you"};

    std::regex color_regex("#([a-f0-9]{2})"
                            "([a-f0-9]{2})"
                            "([a-f0-9]{2})");

    // 简单匹配
    for (const auto &line : lines) {
        std::cout << line << ": " << std::boolalpha
                  << std::regex_search(line, color_regex) << '\n';
    }
    std::cout << '\n';

    // 展示每个匹配中有标记子表达式的内容
    std::smatch color_match;
    for (const auto& line : lines) {
        if(std::regex_search(line, color_match, color_regex)) {
            std::cout << "matches for '" << line << "'\n";
            std::cout << "Prefix: '" << color_match.prefix() << "'\n";
            for (size_t i = 0; i < color_match.size(); ++i)
                std::cout << i << ": " << color_match[i] << '\n';
            std::cout << "Suffix: '" << color_match.suffix() << "\'\n\n";
        }
    }

    // 重复搜索（参阅 std::regex_iterator ）
    std::string log(R"(
        Speed:  366
        Mass:   35
        Speed:  378
        Mass:   32
        Speed:  400
        Mass:   30)");
    std::regex r(R"(Speed:\t\d*)");
    std::smatch sm;
    while(regex_search(log, sm, r))
    {
        std::cout << sm.str() << '\n';
        log = sm.suffix();
    }

    // C 风格字符串演示
    std::cmatch cm;
    if(std::regex_search("this is a test", cm, std::regex("test")))
        std::cout << "\nFound " << cm[0] << " at position " << cm.prefix().length();
}

输出：

Roses are #ff0000: true
violets are #0000ff: true
all of my base are belong to you: false

matches for 'Roses are #ff0000'
Prefix: 'Roses are '
0: #ff0000
1: ff
2: 00
3: 00
Suffix: ''

matches for 'violets are #0000ff'
Prefix: 'violets are '
0: #0000ff
1: 00
2: 00
3: ff
Suffix: ''

Speed:  366
Speed:  378
Speed:  400

Found test at position 10

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2329 | C++11 | 曾接受 basic_string 右值，这较可能导致悬垂迭代器 | 通过被删除的重载拒绝

参阅

basic_regex (C++11) | 正则表达式对象 (类模板)
match_results (C++11) | 标识一个正则表达式匹配，包含所有子表达式匹配 (类模板)
regex_match (C++11) | 尝试匹配一个正则表达式到整个字符序列 (函数模板)


std::regex_token_iterator

< cpp‎ | regex
定义于头文件 <regex> |
template< class BidirIt, class CharT = typename std::iterator_traits <BidirIt>::value_type, class Traits = std::regex_traits <CharT> > class regex_token_iterator | (C++11 起)

std::regex_token_iterator 是访问底层字符序列内每个正则表达式匹配的单独子匹配的只读老式向前迭代器 (LegacyForwardIterator) 。它亦可用于访问不为给定的正则表达式所匹配的序列部分（例如作为记号化器）。

构造时，它构造一个 std::regex_iterator ，而在每次自增时，它走过请求的来自当前 match_results 的子匹配，并在自增离开上个子匹配时自增底层的 regex_iterator 。

默认构造的 std::regex_token_iterator 是序列尾迭代器。在抵达最后匹配的最后子匹配自增合法的 std::regex_token_iterator 时，它变得等于序列尾迭代器。进一步解引用或自增它引发未定义行为。

在恰好变为序列尾迭代器前，若请求的子匹配下标列表中出现 -1 （非匹配碎片），则 std::regex_token_iterator 可成为后缀迭代器。若解引用这种迭代器，则返回对应最后匹配和序列结尾之间的字符序列的 match_results 。

std::regex_token_iterator 的典型实现保有底层的 std::regex_iterator 、请求的子匹配下标的容器（例如 std::vector <int> ）、等于子匹配下标的内部计数器、指向当前匹配的当前子匹配的指向 std::sub_match 指针和含有最近非匹配字符序列的 std::match_results 对象（用于记号化器模式）。

类型要求

-
BidirIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求。

特化

定义对常用字符序列类型的数个特化：

定义于头文件 <regex>
类型 | 定义
cregex_token_iterator | regex_token_iterator<const char*>
wcregex_token_iterator | regex_token_iterator<const wchar_t*>
sregex_token_iterator | regex_token_iterator<std::string::const_iterator>
wsregex_token_iterator | regex_token_iterator<std::wstring::const_iterator>

成员类型

成员类型 | 定义
value_type | std::sub_match <BidirIt>
difference_type | std::ptrdiff_t
pointer | const value_type*
reference | const value_type&
iterator_category | std::forward_iterator_tag
regex_type | basic_regex<CharT, Traits>

成员函数

(构造函数) | 构造新的 regex_token_iterator (公开成员函数)
(析构函数) (隐式声明) | 析构 regex_token_iterator ，包含缓存值 (公开成员函数)
operator= | 赋值内容 (公开成员函数)
operator==operator!= (C++20 中移除) | 比较两个 regex_token_iterator (公开成员函数)
operator*operator-> | 访问当前子匹配 (公开成员函数)
operator++operator++(int) | 推进迭代器到下一个子匹配 (公开成员函数)

注意

程序员负责确保传递给迭代器构造函数的 std::basic_regex 对象活得久于迭代器。因为迭代器存储 std::regex_iterator ，它存储指向 regex 的指针，故在销毁 regex 后自增迭代器导致未定义行为。

示例

#include <fstream>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <regex>

int main()
{
   std::string text = "Quick brown fox.";
   // 记号化（非匹配碎片）
   // 注意仅匹配二次 regex ：在获得第三值时迭代器为后缀迭代器。
   std::regex ws_re("\\s+"); // 空白符
   std::copy( std::sregex_token_iterator(text.begin(), text.end(), ws_re, -1),
              std::sregex_token_iterator(),
              std::ostream_iterator<std::string>(std::cout, "\n"));

   // 迭代首个子匹配
   std::string html = "<p><a href=\"http://google.com\">google</a> "
                      "< a HREF =\"http://cppreference.com\">cppreference</a>\n</p>";
   std::regex url_re("<\\s*A\\s+[^>]*href\\s*=\\s*\"([^\"]*)\"", std::regex::icase);
   std::copy( std::sregex_token_iterator(html.begin(), html.end(), url_re, 1),
              std::sregex_token_iterator(),
              std::ostream_iterator<std::string>(std::cout, "\n"));
}

输出：

Quick
brown
fox.
http://google.com
http://cppreference.com


std::regex_token_iterator<BidirIt,CharT,Traits>::operator*, operator->

< cpp‎ | regex‎ | regex token iterator
const value_type& operator*() const; | (C++11 起)
const value_type* operator->() const; | (C++11 起)

返回指向当前匹配的指针或引用。

若迭代器是序列尾迭代器，则行为未定义。

返回值

指向当前匹配的指针或引用。


std::regex_token_iterator<BidirIt,CharT,Traits>::operator=

< cpp‎ | regex‎ | regex token iterator
regex_token_iterator& operator=( const regex_token_iterator& other ); | (C++11 起)

赋值 other 的内容。

参数

other - 要赋值的正则表达式迭代器

返回值

*this 。


std::regex_token_iterator<BidirIt,CharT,Traits>::operator++, operator++(int)

< cpp‎ | regex‎ | regex token iterator
regex_token_iterator& operator++(); | (C++11 起)
regex_token_iterator operator++(int); | (C++11 起)

令迭代器前进到下个子匹配。

本节未完成
原因：更好的解释

若 *this 为后缀迭代器，则设置 *this 为序列尾迭代器。

否则，若 N + 1 < subs.size() ，则自增 N 并设置结果为当前匹配的地址。

否则，设置 N 为 ​0​ 并自增 position 。若 position 不是序列尾迭代器，则运算符设置结果为当前匹配的地址。

否则，若存储于 sub 中的任何值等于 -1 且 prev->suffix().length() 非 ​0​ ，则运算符设置 *this 为指向范围 [prev->suffix().first, prev->suffix().second) 的后缀迭代器。

否则，设置 *this 为序列尾迭代器。

若迭代器是序列尾迭代器则行为未定义。

参数

（无）

返回值

1) *this
2) 迭代器的先前值。


std::regex_token_iterator<BidirIt,CharT,Traits>::operator==, operator!=

< cpp‎ | regex‎ | regex token iterator
bool operator==( const regex_token_iterator& other ) const; | (1) | (C++11 起)
bool operator!=( const regex_token_iterator& other ) const; | (2) | (C++11 起) (C++20 前)

检查 *this 与 other 是否等价。

二个 regex_token_iterator 相等，若：

a) 它们都是序列尾迭代器。
b) 它们都是后缀迭代器且后缀相等。
c) 它们都不是序列尾或后缀迭代器且：
  • position == other.position
  • N == other.N
  • subs == other.subs

1) 检查 *this 是否等于 other 。
2) 检查 *this 是否不等于 other 。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

other - 要比较的另一 regex_token_iterator

返回值

1) 若 *this 等于 other 则为 true ，否则为 false 。
2) 若 *this 不等于 other 则为 true ，否则为 false 。


std::regex_token_iterator<BidirIt,CharT,Traits>::regex_token_iterator

< cpp‎ | regex‎ | regex token iterator
regex_token_iterator();
 (1) (C++11 起)
regex_token_iterator( BidirIt a, BidirIt b,

const regex_type& re,
int submatch = 0,
std::regex_constants::match_flag_type m =

std::regex_constants::match_default );
 (2) (C++11 起)
regex_token_iterator( BidirIt a, BidirIt b,

const regex_type& re,
const std::vector <int>& submatches,
std::regex_constants::match_flag_type m =

std::regex_constants::match_default );
 (3) (C++11 起)
regex_token_iterator( BidirIt a, BidirIt b,

const regex_type& re,
std::initializer_list <int> submatches,
std::regex_constants::match_flag_type m =

std::regex_constants::match_default );
 (4) (C++11 起)
template < std::size_t N>

regex_token_iterator( BidirIt a, BidirIt b,
const regex_type& re,
const int (&submatches)[N],
std::regex_constants::match_flag_type m =

std::regex_constants::match_default );
 (5) (C++11 起)
regex_token_iterator( const regex_token_iterator& other );
 (6) (C++11 起)
regex_token_iterator( BidirIt a, BidirIt b,

const regex_type&& re,
int submatch = 0,
std::regex_constants::match_flag_type m =

std::regex_constants::match_default ) = delete;
 (7) (C++11 起)
regex_token_iterator( BidirIt a, BidirIt b,

const regex_type&& re,
const std::vector <int>& submatches,
std::regex_constants::match_flag_type m =

std::regex_constants::match_default ) = delete;
 (8) (C++11 起)
regex_token_iterator( BidirIt a, BidirIt b,

const regex_type&& re,
std::initializer_list <int> submatches,
std::regex_constants::match_flag_type m =

std::regex_constants::match_default ) = delete;
 (9) (C++11 起)
template < std::size_t N>

regex_token_iterator( BidirIt a, BidirIt b,
const regex_type&& re,
const int (&submatches)[N],
std::regex_constants::match_flag_type m =

std::regex_constants::match_default ) = delete;
 (10) (C++11 起)

构造新的 regex_token_iterator ：

1) 默认构造函数。构造序列尾迭代器。
2-5) 首先，复制出 submatches 或 submatch 参数的请求的子匹配列表，到存储于迭代器的成员列表中，再通过传递 a 、 b 、 re 和 m 到其四参数构造函数（该构造函数进行到 std::regex_search 的初始调用）构造成员 std::regex_iterator ，然后设置子匹配的内部计数器为零。
  • 若构造后，成员 regex_iterator 不是序列尾迭代器，则设置成员指针直指向当前 std::sub_match 的地址。
  • 否则（若成员 regex_iterator 是序列尾迭代器），但值 -1 是 submatches/submatch 中的值之一，则将 *this 转变为指向范围 [a,b) 的后缀迭代器（整个字符串是非匹配的后缀）
  • 否则，（若 -1 不在子匹配列表中），转变 *this 为序列尾迭代器。

若 submatches 中任何值小于 -1 则行为未定义。

6) 复制构造函数：进行逐元素赋值（包含复制成员 regex_iterator 和成员指向 sub_match 指针）。
7-10) 禁止以临时 regex 调用重载 (2-5) ，因为否则返回的迭代器会被立即非法化。

参数

a | - | 指向目标字符序列起始的老式双向迭代器 (LegacyBidirectionalIterator)
b | - | 指向目标字符序列结尾的老式双向迭代器 (LegacyBidirectionalIterator)
re | - | 用于在目标字符序列中搜索的正则表达式
submatch | - | 应当返回的子匹配下标。 "0" 表示完整匹配，而 "-1" 表示未匹配的部分（例如匹配间的填塞）。
submatches | - | 应当在每个匹配内迭代的子匹配下标的序列，对于非匹配片段可能包含特殊值 -1
m | - | 掌管 re 行为的标志

参阅

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2332 | C++11 | 从临时 basic_regex 构造的 regex_token_iterator 立即变为非法 | 通过被删除的重载禁止这种构造


std::regex_traits

< cpp‎ | regex
定义于头文件 <regex> |
template< class CharT > class regex_traits; | (C++11 起)

类型特性模板 regex_traits 将类型集合及在类型 CharT 上的操作所需的函数提供给 std::basic_regex 。

因为大多数 regex 操作是对本地环境敏感的（设置 std::regex_constants::collate 标志时），从而 regex_traits 类典型地保有一个作为私有成员的 std::locale 实例。

标准特化

标准库定义 std::regex_traits 的二个特化：

std::regex_traits<char>
std::regex_traits<wchar_t>

这些特化使得 std::basic_regex <char> （别名 std::regex ）和 std::basic_regex <wchar_t> （别名 std::wregex ）可用。为将 std::basic_regex 用于其他字符类型（例如 char32_t ），必须使用用户提供的特性类。

成员类型

类型 | 定义
char_type | CharT
string_type | std::basic_string <CharT>
locale_type | 用于正则表达式中本地化行为的本地环境。必须为可复制构造 (CopyConstructible)
char_class_type | 表示字符分类，并足以保有 lookup_classname 所返回的实现指定集合。必须是位掩码类型 (BitmaskType) 。

成员函数

(构造函数) | 构造 regex_traits 对象 (公开成员函数)
length [静态] | 计算空终止字符串的长度 (公开静态成员函数)
translate | 确定字符的等价关键 (公开成员函数)
translate_nocase | 决定字符的无关大小写的等价关键 (公开成员函数)
transform | 确定给定字符串的搜索关键，用于提供对照顺序 (公开成员函数)
transform_primary | 确定字符序列的初等搜索关键，用于确定等价类 (公开成员函数)
lookup_collatename | 以名获得对照元素 (公开成员函数)
lookup_classname | 以名获得字符类 (公开成员函数)
isctype | 指示本地化字符类的从属关系 (公开成员函数)
value | 把代表数位的序列翻译成整数值 (公开成员函数)
imbue | 设置本地环境 (公开成员函数)
getloc | 获得本地环境 (公开成员函数)


std::regex_traits<CharT>::getloc

< cpp‎ | regex‎ | regex traits
locale_type getloc() const; | (C++11 起)

返回特性对象的当前本地环境。

若仍未对此对象调用 imbue() ，则返回调用时的全局本地环境。否则调用传递给 imbue() 的上次调用的本地环境。

参数

（无）

返回值

特性对象的当前本地环境。

示例

本节未完成
原因：暂无示例

参阅

imbue
 设置本地环境
(公开成员函数)


std::regex_traits<CharT>::imbue

< cpp‎ | regex‎ | regex traits
locale_type imbue( locale_type loc ); | (C++11 起)

以 loc 的副本替换当前的本地环境。若 loc 异于当前本地环境，则所有缓存数据变为非法。

在 getloc() == loc 的调用后。

参数

loc - 要感染的本地环境

返回自

特性对象的本地环境。

若仍未对此对象调用 imbue() ，则在此调用时返回全局本地环境。否则，返回上次传递给 imbue() 的本地环境。

示例

本节未完成
原因：暂无示例

参阅

getloc
 获得本地环境
(公开成员函数)


std::regex_traits<CharT>::isctype

< cpp‎ | regex‎ | regex traits
bool isctype( CharT c, char_class_type f ) const;

确定字符 c 是否属于 f 所标识的字符类，即为 lookup_classname() 所返回的值或几个这种值的逐位或。

std::regex_traits 的标准库特化中提供的此函数版本进行下列动作：

1) 首先以实现定义方式转换 f 为 std::ctype_base::mask 类型临时值 m
2) 然后试图以感染的本地环境分类字符，通过调用 std::use_facet < std::ctype <CharT>>(getloc()).is(m, c) 。若它返回 true ，则 isctype() 返回 true 。
3) 否则，检查 c 是否等于 '_' 且位掩码 f 是否包含对字符类 [:w:] 调用 lookup_classname() 的结果，该情况下返回 true 。
4) 否则，返回 false 。

参数

c | - | 要分类的字符
f | - | 从一或多次调用 lookup_classname() 获得的位掩码

返回值

若 c 以 f 分类则为 true ，否则为 false 。

注意

以上描述摘要 C++14 ； C++11 用语要求此函数在所有情况下对 '_' 返回 true （ LWG 问题 2018 ）。

示例

#include <iostream>
#include <string>
#include <regex>

int main()
{
    std::regex_traits<char> t;
    std::string str_alnum = "alnum";
    auto a = t.lookup_classname(str_alnum.begin(), str_alnum.end());
    std::string str_w = "w"; // [:w:] 为 [:alnum:] 加上 '_'
    auto w = t.lookup_classname(str_w.begin(), str_w.end());
    std::cout << std::boolalpha
              << t.isctype('A', w) << ' ' << t.isctype('A', a) << '\n'
              << t.isctype('_', w) << ' ' << t.isctype('_', a) << '\n'
              << t.isctype(' ', w) << ' ' << t.isctype(' ', a) << '\n';
}

输出：

true true
true false
false false

演示定制 regex_traits 的 lookup_classname/isctype 实现

#include <iostream>
#include <locale>
#include <regex>
#include <cwctype>

// 此定制正则表达式特性以 wctype/iswctype 实现 lookup_classname/isctype
struct wctype_traits : std::regex_traits<wchar_t>
{
    using char_class_type = std::wctype_t;
    template<class It>
    char_class_type lookup_classname(It first, It last, bool=false) const {
        return std::wctype(std::string(first, last).c_str());
    }
    bool isctype(wchar_t c, char_class_type f) const {
        return std::iswctype(c, f);
    }
};

int main()
{
    std::locale::global(std::locale("ja_JP.utf8"));
    std::wcout.sync_with_stdio(false);
    std::wcout.imbue(std::locale());

    std::wsmatch m;
    std::wstring in = L"けものフレンズ";
    // 匹配所有字符（它们被分类为 alnum ）
    std::regex_search(in, m, std::wregex(L"([[:alnum:]]+)"));
    std::wcout << "alnums: " << m[1] << '\n'; // 打印 "けものフレンズ"
    // 只匹配片假名
    std::regex_search(in, m,
                      std::basic_regex<wchar_t, wctype_traits>(L"([[:jkata:]]+)"));
    std::wcout << "katakana: " << m[1] << '\n'; // 打印 "フレンズ"
}

输出：

alnums: けものフレンズ
katakana: フレンズ

参阅

lookup_classname | 以名获得字符类 (公开成员函数)
do_is [虚] | 分类字符或字符序列 (std::ctype<CharT> 的虚受保护成员函数)
iswctype | 按照指定的 LC_TYPE 类别分类宽字符 (函数)


std::regex_traits<CharT>::length

< cpp‎ | regex‎ | regex traits
static std::size_t length(const char_type* p);

计算空终止字符序列的长度，即满足 p[i]==0 的最小 i 。

std::regex_traits 的标准库特化执行 std::char_traits <CharT>::length(p);

参数

p - 指向空终止字符序列首元素的指针

返回值

空终止字符串的长度。

示例

#include <regex>
#include <iostream>

int main()
{
    std::cout << std::regex_traits<char>::length(u8"Кошка") << '\n'
              << std::regex_traits<wchar_t>::length(L"Кошка") << '\n';
}

输出：

10
5


std::regex_traits<CharT>::lookup_classname

< cpp‎ | regex‎ | regex traits
template< class ForwardIt >

char_class_type lookup_classname( ForwardIt first,
ForwardIt last,

bool icase = false ) const;

若字符序列 [first, last) 表示当前感染的 locale 中合法的字符类名称（即正则表达式中 [: 与 :] 之间的字符串），则返回表示此字符类的实现定义值。否则，返回零。

若参数 icase 为 true ，则字符类忽略字符大小写，例如带 std::regex_constants::icase 的正则表达式 [:lower:] 生成以 [first, last) 指示字符串 "lower" ，且 icase == true 的 regex_traits<>::lookup_classname() 调用。此调用返回与带 icase == false 的正则表达式 [:alpha:] 所生成者相同位掩码。

始终以窄和宽字符形式辨认下列字符类，并返回如下的，感染的 locale 的 std::ctype 平面所获得的匹配分类所对应的分类（有 icase == false ）：

字符类 | std::ctype 分类
"alnum" | std::ctype_base::alnum
"alpha" | std::ctype_base::alpha
"blank" | std::ctype_base::blank
"cntrl" | std::ctype_base::cntrl
"digit" | std::ctype_base::digit
"graph" | std::ctype_base::graph
"lower" | std::ctype_base::lower
"print" | std::ctype_base::print
"punct" | std::ctype_base::punct
"space" | std::ctype_base::space
"upper" | std::ctype_base::upper
"xdigit" | std::ctype_base::xdigit
"d" | std::ctype_base::digit
"s" | std::ctype_base::space
"w" | std::ctype_base::alnum 可选地加上带 '_'

对字符串 "w" 返回的分类可以准确地与 "alnum" 相同，该情况下 isctype() 显式加上 '_' 。

系统提供的本地环境可提供额外分类，如 "jdigit" 或 "jkanji" （该情况下它们亦可通过 std::wctype 访问）。

参数

first, last | - | 一对迭代器，确定表示字符类名的字符序列
icase | - | 若为 true ，则忽略字符分类中的大小写区别
类型要求
- ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

以给定的字符类确定的表示字符分类的位掩码，或若类未知则为 char_class_type() 。

示例

演示定制 regex_traits 的 lookup_classname/isctype 实现

#include <iostream>
#include <locale>
#include <regex>
#include <cwctype>

// 此定制正则表达式特性以 wctype/iswctype 实现 lookup_classname/isctype
struct wctype_traits : std::regex_traits<wchar_t>
{
    using char_class_type = std::wctype_t;
    template<class It>
    char_class_type lookup_classname(It first, It last, bool=false) const {
        return std::wctype(std::string(first, last).c_str());
    }
    bool isctype(wchar_t c, char_class_type f) const {
        return std::iswctype(c, f);
    }
};

int main()
{
    std::locale::global(std::locale("ja_JP.utf8"));
    std::wcout.sync_with_stdio(false);
    std::wcout.imbue(std::locale());

    std::wsmatch m;
    std::wstring in = L"けものフレンズ";
    // 匹配所有字符（它们被分类为 alnum ）
    std::regex_search(in, m, std::wregex(L"([[:alnum:]]+)"));
    std::wcout << "alnums: " << m[1] << '\n'; // 打印 "けものフレンズ"
    // 只匹配片假名
    std::regex_search(in, m,
                      std::basic_regex<wchar_t, wctype_traits>(L"([[:jkata:]]+)"));
    std::wcout << "katakana: " << m[1] << '\n'; // 打印 "フレンズ"
}

输出：

alnums: けものフレンズ
katakana: フレンズ

参阅

isctype | 指示字符类中的成员关系指示 (公开成员函数)
wctype | 在当前 C 本地环境中查找字符分类类别 (函数)


std::regex_traits<CharT>::lookup_collatename

< cpp‎ | regex‎ | regex traits
template< class ForwardIt >
string_type lookup_collatename( ForwardIt first, ForwardIt last ) const;

若字符序列 [first, last) 表示当前感染的 locale 中合法对照元素的名称，则返回该对照元素之名。否则，返回空字符串。

对照元素是在 POSIX 正则表达式的 [. 与 .] 之间找到的符号。例如， [.a.] 在 C 本地环境中匹配字符 a 。而 [.tilde.] 在 C 本地环境中匹配 ~ 。 [.ch.] 在捷克语本地环境中匹配双标符 ch ，但在大多数其他本地环境中生成错误码为 std::regex_constants::error_collate 的 std::regex_error 。

参数

first, last - 一对迭代器，确定表示对照元素名的字符序列
类型要求
-
ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

具名对照元素作为字符串的表示。

示例

#include <iostream>
#include <string>
#include <regex>

struct noisy_traits : std::regex_traits<char> {

    template< class Iter >
    string_type lookup_collatename( Iter first, Iter last ) const {
        string_type result = regex_traits::lookup_collatename(first, last);
        std::cout << "regex_traits<>::lookup_collatename(\""
                  << string_type(first, last)
                  << "\") returns \"" << result << "\"\n";
        return result;
    }
};

int main()
{
    std::string str = "z|}a"; // C 本地环境对照顺序： x,y,z,{,|,},~
    std::basic_regex<char, noisy_traits> re("[x-[.tilde.]]*a", std::regex::basic);
    std::cout << std::boolalpha << std::regex_match(str, re) << '\n';
}

输出：

regex_traits<>::lookup_collatename("tilde") returns "~"
true


std::regex_traits<CharT>::regex_traits

< cpp‎ | regex‎ | regex traits
regex_traits();

默认构造 std::regex_traits 对象，包含默认构造私有 std::locale 成员或任何需要的内部状态。

参数

（无）

示例

#include <iostream>
#include <regex>

int main()
{
    std::locale::global(std::locale("en_US.utf8"));
    std::regex_traits<char> r1;
    std::regex_traits<wchar_t> r2;
    std::cout << "The regex locale is " << r1.getloc().name() << '\n';
}

输出：

The regex locale is en_US.utf8


std::regex_traits<CharT>::transform

< cpp‎ | regex‎ | regex traits
template< class ForwardIt >
string_type transform( ForwardIt first, ForwardIt last) const;

获得字符序列 [first, last) 的排序关键，满足若排序关键以 operator< 小于另一排序关键，则在当前感染的 locale 的对照顺序中，产生第一排序关键的字符序列优先于产生第二排序关键的字符序列。

例如，在设置 regex 标志 std::regex_constants::collate 时，若 traits.transform("a") <= traits.transform(c1) <= traits.transform("b") 则序列 [a-b] 会匹配某字符 c1 。注意此函数接收字符序列为参数，以适应定义为如 [[.ae.]-d] 的范围。

std::regex_traits 的标准库特化返回 std::use_facet < std::collate <CharT>>(getloc()).transform(str.data(), str.data() + str.length()) ，对于某个构造为 string_type str(first, last) 的临时字符串 str 。

参数

first, last - 一对老式向前迭代器 (LegacyForwardIterator) ，确定要比较的字符序列
类型要求
-
ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

当前感染的 locale 中字符序列 [first, last) 的对照关键。

示例

本节未完成
原因：暂无示例


std::regex_traits<CharT>::transform_primary

< cpp‎ | regex‎ | regex traits
template< class ForwardIt >
string_type transform_primary( ForwardIt first, ForwardIt last ) const;

获得字符序列 [first, last) 在感染的本地环境的对照顺序中的初等排序关键，即基于国家字母表中，忽略大小写、发音符号、变体等的字母位置和对照单元的排序关键。若初等排序关键以 operator< 比较小于另一排序关键，则产生第一个排序关键的字符序列，在当前感染的本地环境的初等对照序列中，比生成第二个排序关键的字符序列先到来。

正则表达式库用此特性将字符匹配到等价类。例如，正则表达式 [[=a=]] 等价于字符 c1 ，若 traits.transform_primary(c1) 等价于 traits.transform_primary("a") （这在美国英语本地环境中对来自 "AÀÁÂÃÄÅaàáâãäå" 的任何 c1 为真）。注意 transform_primary() 接收字符序列参数，因为等价类可能是多字符，如捷克语中的 [[=ch=]] 或匈牙利语中的 [[=dzs=]] 。

没有以 std::locale 定义初等排序关键的可移植方式，因为从 std::collate::transform() 所返回的对照关键到初等等价关键的转换是本地环境限定的，而且若用户替换 std::collate 平面，则转换就不再是标准库的 std::regex_traits 。 std::regex_traits 的标准库特化返回空字符串，除非当前感染的本 locale 的 std::collate 平面未为用户所替换，并仍然匹配系统提供的 std::collate 平面，该情况下执行 std::collate_byname <charT>::transform(first, last) ，并用本地环境限定转换，转换其所产生的排序关键为初等排序关键。

参数

first, last - 一对迭代器，确定要比较的字符序列
类型要求
-
ForwardIt 必须满足老式向前迭代器 (LegacyForwardIterator) 的要求。

返回值

当前感染的本地环境中字符序列 [first, last) 的初等排序关键，忽略大小写、变体、发音符号等。

示例

演示通过 transform_primary() 工作的正则表达式特性

#include <iostream>
#include <regex>

int main()
{
    std::locale::global(std::locale("en_US.UTF-8"));
    std::wstring str = L"AÀÁÂÃÄÅaàáâãäå";
    std::wregex re(L"[[=a=]]*", std::regex::basic);
    std::cout << std::boolalpha << std::regex_match(str, re) << '\n';
}

输出：

true
本节未完成
原因：可使用带提供用户定义 transform_primary 的用户定义 regex_traits 的示例


std::regex_traits<CharT>::translate

< cpp‎ | regex‎ | regex traits
CharT translate(CharT c) const;

获得字符 c 的等价关键，它满足在感染的 locale 中等价于此字符的所有字符生成相同关键。

正则表达式库需要比较二个字符 c1 和 c2 且标志 std::regex_constants::collate 为 true 时，它执行 regex_traits<>::translate(c1) == regex_traits<>::translate(c2) 。

std::regex_traits 的标准库特化返回未修改的 c 。

参数

c - 需要检验等价性的字符

返回值

当前感染的 locale 中 c 的比较关键。

示例

本节未完成
原因：暂无示例


std::regex_traits<CharT>::translate_nocase

< cpp‎ | regex‎ | regex traits
CharT translate_nocase(CharT c) const;

获得字符 c 的比较关键，使得感染的 locale 中，所有忽略大小写差异（若存在）后等价于此字符的所有字符产生相同关键。

正则表达式库需要匹配二个字符 c1 和 c2 ，且标志 std::regex_constants::icase 为 true 时，它执行 regex_traits<>::translate_nocase(c1) == regex_traits<>::translate_nocase(c2) 。

std::regex_traits 的标准库特化返回 std::use_facet < std::ctype <CharT>>(getloc()).tolower(c) ，即用当前感染的 locale 转换 c 为小写。

参数

c - 需要检验等价性的字符，忽略大小写

返回值

当前感染的本地环境中 c 的无关大小写的比较关键。

示例

本节未完成
原因：暂无示例


std::regex_traits<CharT>::value

< cpp‎ | regex‎ | regex traits
int value( CharT ch, int radix ) const; | (C++11 起)

给定当前感染的本地环境，确定数位 ch 在数值底 radix 中表示的值。 std::regex 在处理如 {1} 或 {2,5} 的数量词、如 \1 的回溯引用和十六进制及 Unicode 字符转义时调用此函数。

参数

ch | - | 可以表示数位的字符
radix | - | 8 、 10 或 16 之一

返回值

若 ch 在当前感染的本地环境中确实表示对于数值底 radix 合法的数位，则为其数值，错误时为 -1 。

示例

#include <iostream>
#include <locale>
#include <regex>
#include <map>

// 此定制正则表达式特性允许日文数字
struct jnum_traits : std::regex_traits<wchar_t>
{
    static std::map<wchar_t, int> data;
    int value(wchar_t ch, int radix ) const {
        wchar_t up = std::toupper(ch, getloc());
        return data.count(up) ? data[up] : regex_traits::value(ch, radix);
    }
};
std::map<wchar_t, int> jnum_traits::data = {{L'〇',0}, {L'一',1}, {L'二',2},
                                            {L'三',3}, {L'四',4}, {L'五',5},
                                            {L'六',6}, {L'七',7}, {L'八',8},
                                            {L'九',9}, {L'Ａ',10}, {L'Ｂ',11},
                                            {L'Ｃ',12}, {L'Ｄ',13}, {L'Ｅ',14},
                                            {L'Ｆ',15}};
int main()
{
    std::locale::global(std::locale("ja_JP.utf8"));
    std::wcout.sync_with_stdio(false);
    std::wcout.imbue(std::locale());

    std::wstring in = L"風";

    if(std::regex_match(in, std::wregex(L"\\u98a8")))
        std::wcout << "\\u98a8 matched " << in << '\n';

    if(std::regex_match(in, std::basic_regex<wchar_t, jnum_traits>(L"\\u九八ａ八")))
        std::wcout << L"\\u九八ａ八 with custom traits matched " << in << '\n';
}

输出：

\u98a8 matched 風
\u九八ａ八 with custom traits matched 風


std::sub_match

< cpp‎ | regex
定义于头文件 <regex> |
template<class BidirIt> class sub_match; | (C++11 起)

正则表达式引擎用类模板 sub_match ，表示有标记子表达式所匹配的字符序列。 匹配是目标范围中匹配正则表达式的 [begin, end) 对，不过拥有附加的观察器函数以增进代码清晰度。

只有默认构造函数是可公开访问的。在处理 regex 算法之一期间， sub_match 的实例作为 std::match_results 容器的一部分正常构造并移居。

成员函数返回定义的默认值，除非 matched 成员为 true 。

sub_match 继承自 std::pair <BidirIt, BidirIt> ，尽管它不能当做 std::pair 对象，因为成员函数，如交换与赋值，不会按期待工作。

类型要求

-
BidirIt 必须满足老式双向迭代器 (LegacyBidirectionalIterator) 的要求。

特化

为常见字符类型提供数个特化：

定义于头文件 <regex>
类型 | 定义
csub_match | sub_match<const char*>
wcsub_match | sub_match<const wchar_t*>
ssub_match | sub_match<std::string::const_iterator>
wssub_match | sub_match<std::wstring::const_iterator>

成员类型

成员类型 | 定义
iterator | BidirIt
value_type | std::iterator_traits <BidirIt>::value_type
difference_type | std::iterator_traits <BidirIt>::difference_type
string_type | std::basic_string <value_type>

成员对象

bool matched
 指示此匹配是否成功
(公开成员对象)

继承自 std::pair

BidirIt first | 匹配序列的开始。 (公开成员对象)
BidirIt second | 匹配序列的结尾后一位置。 (公开成员对象)

成员函数

(构造函数)
 构造匹配对象
(公开成员函数)
观察器
length
 若存在则返回匹配的长度
(公开成员函数)
stroperator string_type
 转换为底层字符串类型
(公开成员函数)
compare
 若存在则比较匹配的子序列
(公开成员函数)

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 比较一个 sub_match 与另一 sub_match 、字符串或字符 (函数模板)
operator<< | 输出匹配的字符子序列 (函数模板)

参阅

regex_token_iterator
(C++11)
 迭代给定字符串中的所有正则表达式匹配中的指定子表达式，或迭代未匹配的子字符串
(类模板)


std::sub_match<BidirIt>::compare

< cpp‎ | regex‎ | sub match
int compare( const sub_match& m ) const; | (1) | (C++11 起)
int compare( const string_type& s ) const; | (2) | (C++11 起)
int compare( const value_type* c ) const; | (3) | (C++11 起)
1) 通过直接比较其底层字符序列比较二个 sub_match 。等价于 str().compare(m.str()) 。
2) 比较 sub_match 与 std::basic_string 。等价于 str().compare(s) 。
3) 比较 sub_match 与 s 所指向的底层字符类型的空终止序列。等价于 str().compare(c) 。

应用代码很少直接使用此函数。它们替而使用非成员比较运算符之一。

参数

m | - | 到另一 sub_match 的引用
s | - | 到要比较的字符串的引用
c | - | 指向要比较的底层 value_type 的空终止序列的指针

返回值

若此 sub_match 小于另一字符序列则小于零的值，若二个底层字符序列相等则为零，若此 sub_match 大于另一字符序列则为大于零的值。

示例

本节未完成
原因：暂无示例

参阅

compare | 比较二个字符串 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
stroperator string_type | 转换为底层字符串类型 (公开成员函数)
operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 比较一个 sub_match 与另一 sub_match 、字符串或字符 (函数模板)


std::sub_match<BidirIt>::length

< cpp‎ | regex‎ | sub match
difference_type length() const;

参数

（无）

返回值

返回匹配中的字符数，即若匹配合法则为 std::distance (first, second) ，否则为 0 。

复杂度

常数


operator==,!=,<,<=,>,>=,<=>(std::sub_match)

< cpp‎ | regex‎ | sub match
定义于头文件 <regex>
直接比较
template< class BidirIt >

bool operator==( const std::sub_match <BidirIt>& lhs,

const std::sub_match <BidirIt>& rhs );
 (1) (C++11 起)
template< class BidirIt >

bool operator!=( const std::sub_match <BidirIt>& lhs,

const std::sub_match <BidirIt>& rhs );
 (2) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator<( const std::sub_match <BidirIt>& lhs,

const std::sub_match <BidirIt>& rhs );
 (3) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator<=( const std::sub_match <BidirIt>& lhs,

const std::sub_match <BidirIt>& rhs );
 (4) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator>( const std::sub_match <BidirIt>& lhs,

const std::sub_match <BidirIt>& rhs );
 (5) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator>=( const std::sub_match <BidirIt>& lhs,

const std::sub_match <BidirIt>& rhs );
 (6) (C++11 起)
(C++20 前)
template< class BidirIt >

/*comp-cat*/ operator<=>( const std::sub_match <BidirIt>& lhs,

const std::sub_match <BidirIt>& rhs );
 (7) (C++20 起)
std::sub_match 与 std::basic_string
template< class BidirIt, class Traits, class Alloc >

bool operator==( const std::sub_match <BidirIt>& sm,
const std::basic_string <
typename std::iterator_traits <BidirIt>::value_type,

Traits,Alloc>& rhs );
 (8) (C++11 起)
template< class BidirIt, class Traits, class Alloc >

bool operator!=( const std::sub_match <BidirIt>& sm,
const std::basic_string <
typename std::iterator_traits <BidirIt>::value_type,

Traits,Alloc>& st );
 (9) (C++11 起)
(C++20 前)
template< class BidirIt, class Traits, class Alloc >

bool operator<( const std::sub_match <BidirIt>& sm,
const std::basic_string <
typename std::iterator_traits <BidirIt>::value_type,

Traits,Alloc>& st );
 (10) (C++11 起)
(C++20 前)
template< class BidirIt, class Traits, class Alloc >

bool operator<=( const std::sub_match <BidirIt>& sm,
const std::basic_string <
typename std::iterator_traits <BidirIt>::value_type,

Traits,Alloc>& st );
 (11) (C++11 起)
(C++20 前)
template< class BidirIt, class Traits, class Alloc >

bool operator>( const std::sub_match <BidirIt>& sm,
const std::basic_string <
typename std::iterator_traits <BidirIt>::value_type,

Traits,Alloc>& st );
 (12) (C++11 起)
(C++20 前)
template< class BidirIt, class Traits, class Alloc >

bool operator>=( const std::sub_match <BidirIt>& sm,
const std::basic_string <
typename std::iterator_traits <BidirIt>::value_type,

Traits,Alloc>& st );
 (13) (C++11 起)
(C++20 前)
template< class BidirIt, class Traits, class Alloc >

/*comp-cat*/ operator<=>( const std::sub_match <BidirIt>& sm,
const std::basic_string <
typename std::iterator_traits <BidirIt>::value_type,

Traits,Alloc>& st );
 (14) (C++20 起)
std::basic_string 与 std::sub_match
template< class BidirIt, class Traits, class Alloc >

bool operator==( const std::basic_string <
typename std::iterator_traits <BidirIt>::value_type,
Traits,Alloc>& st,

const std::sub_match <BidirIt>& sm );
 (15) (C++11 起)
(C++20 前)
template< class BidirIt, class Traits, class Alloc >

bool operator!=( const std::basic_string <
typename std::iterator_traits <BidirIt>::value_type,
Traits,Alloc>& st,

const std::sub_match <BidirIt>& sm );
 (16) (C++11 起)
(C++20 前)
template< class BidirIt, class Traits, class Alloc >

bool operator<( const std::basic_string <
typename std::iterator_traits <BidirIt>::value_type,
Traits,Alloc>& st,

const std::sub_match <BidirIt>& sm );
 (17) (C++11 起)
(C++20 前)
template< class BidirIt, class Traits, class Alloc >

bool operator<=( const std::basic_string <
typename std::iterator_traits <BidirIt>::value_type,
Traits,Alloc>& st,

const std::sub_match <BidirIt>& sm );
 (18) (C++11 起)
(C++20 前)
template< class BidirIt, class Traits, class Alloc >

bool operator>( const std::basic_string <
typename std::iterator_traits <BidirIt>::value_type,
Traits,Alloc>& st,

const std::sub_match <BidirIt>& sm );
 (19) (C++11 起)
(C++20 前)
template< class BidirIt, class Traits, class Alloc >

bool operator>=( const std::basic_string <
typename std::iterator_traits <BidirIt>::value_type,
Traits,Alloc>& st,

const std::sub_match <BidirIt>& sm );
 (20) (C++11 起)
(C++20 前)
std::sub_match 与 std::iterator_traits<BidirIt>::value_type*
template< class BidirIt >

bool operator==( const std::sub_match <BidirIt>& sm,

const typename std::iterator_traits <BidirIt>::value_type* s );
 (21) (C++11 起)
template< class BidirIt >

bool operator!=( const std::sub_match <BidirIt>& sm,

const typename std::iterator_traits <BidirIt>::value_type* s );
 (22) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator<( const std::sub_match <BidirIt>& sm,

const typename std::iterator_traits <BidirIt>::value_type* s );
 (23) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator<=( const std::sub_match <BidirIt>& sm,

const typename std::iterator_traits <BidirIt>::value_type* s );
 (24) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator>( const std::sub_match <BidirIt>& sm,

const typename std::iterator_traits <BidirIt>::value_type* s );
 (25) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator>=( const std::sub_match <BidirIt>& sm,

const typename std::iterator_traits <BidirIt>::value_type* s );
 (26) (C++11 起)
(C++20 前)
template< class BidirIt >

/*comp-cat*/ operator<=>( const std::sub_match <BidirIt>& sm,

const typename std::iterator_traits <BidirIt>::value_type* s );
 (27) (C++20 起)
std::iterator_traits<BidirIt>::value_type* 与 std::sub_match
template< class BidirIt >

bool operator==( const typename std::iterator_traits <BidirIt>::value_type* s,

const std::sub_match <BidirIt>& sm );
 (28) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator!=( const typename std::iterator_traits <BidirIt>::value_type* s,

const std::sub_match <BidirIt>& sm );
 (29) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator<( const typename std::iterator_traits <BidirIt>::value_type* s,

const std::sub_match <BidirIt>& sm );
 (30) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator<=( const typename std::iterator_traits <BidirIt>::value_type* s,

const std::sub_match <BidirIt>& sm );
 (31) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator>( const typename std::iterator_traits <BidirIt>::value_type* s,

const std::sub_match <BidirIt>& sm );
 (32) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator>=( const typename std::iterator_traits <BidirIt>::value_type* s,

const std::sub_match <BidirIt>& sm );
 (33) (C++11 起)
(C++20 前)
std::sub_match 与 std::iterator_traits<BidirIt>::value_type
template< class BidirIt >

bool operator==( const std::sub_match <BidirIt>& sm,

const typename std::iterator_traits <BidirIt>::value_type& ch );
 (34) (C++11 起)
template< class BidirIt >

bool operator!=( const std::sub_match <BidirIt>& sm,

const typename std::iterator_traits <BidirIt>::value_type& ch );
 (35) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator<( const std::sub_match <BidirIt>& sm,

const typename std::iterator_traits <BidirIt>::value_type& ch );
 (36) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator<=( const std::sub_match <BidirIt>& sm,

const typename std::iterator_traits <BidirIt>::value_type& ch );
 (37) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator>( const std::sub_match <BidirIt>& sm,

const typename std::iterator_traits <BidirIt>::value_type& ch );
 (38) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator>=( const std::sub_match <BidirIt>& sm,

const typename std::iterator_traits <BidirIt>::value_type& ch );
 (39) (C++11 起)
(C++20 前)
template< class BidirIt >

/*comp-cat*/ operator<=>( const std::sub_match <BidirIt>& sm,

const typename std::iterator_traits <BidirIt>::value_type& ch );
 (40) (C++20 起)
std::iterator_traits<BidirIt>::value_type 与 std::sub_match
template< class BidirIt >

bool operator==( const typename std::iterator_traits <BidirIt>::value_type& ch,

const std::sub_match <BidirIt>& sm );
 (41) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator!=( const typename std::iterator_traits <BidirIt>::value_type& ch,

const std::sub_match <BidirIt>& sm );
 (42) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator<( const typename std::iterator_traits <BidirIt>::value_type& ch,

const std::sub_match <BidirIt>& sm );
 (43) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator<=( const typename std::iterator_traits <BidirIt>::value_type& ch,

const std::sub_match <BidirIt>& sm );
 (44) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator>( const typename std::iterator_traits <BidirIt>::value_type& ch,

const std::sub_match <BidirIt>& sm );
 (45) (C++11 起)
(C++20 前)
template< class BidirIt >

bool operator>=( const typename std::iterator_traits <BidirIt>::value_type& ch,

const std::sub_match <BidirIt>& sm );
 (46) (C++11 起)
(C++20 前)

比较 sub_match 与另一 sub_match 、 string 、空终止字符序列或字符。

1-7) 通过直接比较其底层序列比较二个 sub_match 。如同以 lhs.compare(rhs) 实现。
8-20) 比较 sub_match 与 std::basic_string 。如同以 sm.compare(typename sub_match<BidirIt>::string_type(st.data(), st.size()) 实现。
21-33) 比较 sub_match 与空终止字符串。如同以 sm.compare(s) 实现。
34-46) 比较 sub_match 与字符。如同以 sm.compare(typename sub_match<BidirIt>::string_type(1, ch)) 实现。

三路比较运算符的结果类型（ /*comp-cat*/ ）是 std::compare_three_way_result_t<typename std::sub_match <BidirIt>::string_type>> ，即 std::char_traits <typename std::iterator_traits <BidirIt>::value_type>::comparison_category ，若该有限定标识合法并指代类型，否则为 std::weak_ordering 。若 /*comp-cat*/ 不是比较类别类型，则程序为非良构。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs, sm | - | 要比较的 sub_match
st | - | 要比较的 basic_string
s | - | 指向要比较空终止字符串的指针
ch | - | 要比较的字符

返回值

对于 operator== ， (C++20 起)若以 std::sub_match::compare() 定义的对应关系成立则为 true ，否则为 false 。

对于 operator<=> 为 static_cast</*comp-cat*/>(/*comp-res*/ <=> 0) ，其中 /*comp-res*/ 是上述 std::sub_match::compare() 的结果。

 (C++20 起)

注解

若 BidirIt 的值类型为 char 、 wchar_t 、 char8_t 、 char16_t 或 char32_t ，则 operator<=> 的返回类型为 std::strong_ordering 。

 (C++20 起)

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3432 | C++20 | 未要求 operator<=> 的返回类型为比较类别类型 | 已要求

参阅

compare
 若存在则比较匹配的子序列
(公开成员函数)


operator<<(std::sub_match)

< cpp‎ | regex‎ | sub match
template< class CharT, class Traits, class BidirIt >

std::basic_ostream <CharT,Traits>&
operator<<( std::basic_ostream <CharT,Traits>& os,

const sub_match<BidirIt>& m );
 (C++11 起)

写入匹配子序列 m 的表示到输出流 os 。

等价于 os << m.str() 。

参数

os | - | 要写入表示到的输出流
m | - | 要输出的自匹配对象

返回值

os 。

示例

本节未完成
原因：暂无示例


std::sub_match<BidirIt>::operator string_type, std::sub_match<BidirIt>::str

< cpp‎ | regex‎ | sub match
operator string_type() const; | (1)
string_type str() const; | (2)

转换为底层 std::basic_string 类型对象。

第一版本为隐式转换，第二版本为显式。

参数

（无）

返回值

返回作为底层 std::basic_string 类型对象的匹配字符序列。若 matched 成员为 false 则返回空字符串。

复杂度

与底层字符序列的长度成线性。

示例

#include <iostream>
#include <regex>
#include <string>
int main()
{
  std::ssub_match sm;
  std::string s = sm;  // 隐式转换
  std::cout << s.length() << '\n';
}

输出：

​0​


std::sub_match<BidirIt>::sub_match

< cpp‎ | regex‎ | sub match
constexpr sub_match(); | (C++11 起)

默认构造 std::sub_match 。设置 matched 成员为 false 并值初始化继承的成员 first 与 second 。

这是仅有的得到定义的可公开访问的构造函数。

参数

（无）


std::regex_constants::syntax_option_type

< cpp‎ | regex
定义于头文件 <regex>
typedef /*unspecified*/ syntax_option_type;
 (C++11 起)
constexpr syntax_option_type icase = /*unspecified*/;

constexpr syntax_option_type nosubs = /*unspecified*/;
constexpr syntax_option_type optimize = /*unspecified*/;
constexpr syntax_option_type collate = /*unspecified*/;
constexpr syntax_option_type ECMAScript = /*unspecified*/;
constexpr syntax_option_type basic = /*unspecified*/;
constexpr syntax_option_type extended = /*unspecified*/;
constexpr syntax_option_type awk = /*unspecified*/;
constexpr syntax_option_type grep = /*unspecified*/;

constexpr syntax_option_type egrep = /*unspecified*/;
 (C++11 起)
(C++17 前)
inline constexpr syntax_option_type icase = /*unspecified*/;

inline constexpr syntax_option_type nosubs = /*unspecified*/;
inline constexpr syntax_option_type optimize = /*unspecified*/;
inline constexpr syntax_option_type collate = /*unspecified*/;
inline constexpr syntax_option_type ECMAScript = /*unspecified*/;
inline constexpr syntax_option_type basic = /*unspecified*/;
inline constexpr syntax_option_type extended = /*unspecified*/;
inline constexpr syntax_option_type awk = /*unspecified*/;
inline constexpr syntax_option_type grep = /*unspecified*/;
inline constexpr syntax_option_type egrep = /*unspecified*/;

inline constexpr syntax_option_type multiline = /*unspecified*/;
 (C++17 起)

syntax_option_type 是含有掌控正则表达式行为方式的选项的位掩码类型 (BitmaskType) 。

此类型的可能值（ icase 、 optimize 等）被复制到 std::basic_regex 中。

常量

值 | 效果
icase | 应当以不考虑大小写进行字符匹配。
nosubs | 进行匹配时，将所有被标记的子表达式 (expr) 当做非标记的子表达式 (?:expr) 。不将匹配存储于提供的 std::regex_match 结构中，且 mark_count() 为零
optimize | 指示正则表达式引擎进行更快的匹配，带有令构造变慢的潜在开销。例如这可能表示将非确定 FSA 转换为确定 FSA 。
collate | 形如 "[a-b]" 的字符范围将对本地环境敏感。
multiline (C++17) | 若选择 ECMAScript 引擎，则指定 ^ 应该匹配行首，而 $ 应该匹配行尾。
ECMAScript | 使用改 ECMAScript 正则表达式文法
basic | 使用基本 POSIX 正则表达式文法（文法文档）。
extended | 使用扩展 POSIX 正则表达式文法（文法文档）。
awk | 使用 POSIX 中 awk 工具所用的正则表达式文法（文法文档）。
grep | 使用 POSIX 中 grep 工具所用的正则表达式文法。这等效于 basic 选项附带作为另一种分隔符的换行符 '\n' 。
egrep | 使用 POSIX 中 grep 工具带 -E 选项所用的正则表达式文法。这等效于 extended 附带 '|' 之外的作为另一种分隔符的换行符 '\n' 。

ECMAScript, basic, extended, awk, grep, egrep 必须选取至多一个文法选项。若不选取文法选项，则设定为选取 ECMAScript 。其他选项作为修饰符工作，从而 std::regex ("meow", std::regex::icase) 等价于 std::regex ("meow", std::regex::ECMAScript|std::regex::icase)

注意

因为 POSIX 使用“最左最长”匹配规则（最长的匹配子序列得到匹配，且若存在数个这种子序列，则匹配最左者），故它不适用的例子之一是剖析标签语言：如 "<tag[^>]*>.*</tag>" 这种 POSIX 正则表达式会匹配从首个 "<tag" 到最末 "</tag>" 的任何内容，包含中间的每个 "</tag>" 和 "<tag>" 。另一方面， ECMAScript 支持非贪心匹配，且 ECMAScript 正则表达式 "<tag[^>]*>.*?</tag>" 会只匹配到首个闭标签。

C++11 中，这些常量曾被指定带有冗余的关键词 static ，它为 C++14 通过 LWG 问题 2053 移除。

示例

描绘匹配算法于 ECMAScript 与 POSIX 正则表达式之间的差异

#include <iostream>
#include <string>
#include <regex>

int main()
{
    std::string str = "zzxayyzz";
    std::regex re1(".*(a|xayy)"); // ECMA
    std::regex re2(".*(a|xayy)", std::regex::extended); // POSIX

    std::cout << "Searching for .*(a|xayy) in zzxayyzz:\n";
    std::smatch m;
    std::regex_search(str, m, re1);
    std::cout << " ECMA (depth first search) match: " << m[0] << '\n';
    std::regex_search(str, m, re2);
    std::cout << " POSIX (leftmost longest)  match: " << m[0] << '\n';
}

输出：

Searching for .*(a|xayy) in zzxayyzz:
 ECMA (depth first search) match: zzxa
 POSIX (leftmost longest)  match: zzxayy

参阅

basic_regex
(C++11)
 正则表达式对象
(类模板)


字符串库

< cpp

C++ 字符串库支持三种通用字符串类型：

  • std::basic_string ——为操作任何字符类型的字符串设计的模板类。
  • std::basic_string_view (C++17) ——对于字符串子序列的轻量无所有权的只读视图。
  • 空终止字符串 - 以特殊的空字符终止的字符数组。

std::basic_string

模板类 std::basic_string 通用化字符序列如何操作及存储。字符串创建、操作及析构全部为便利的类方法集合与相关函数所处理。

标准提供 std::basic_string 对常用类型的数种特化：

定义于头文件 <string>
类型 | 定义
std::string | std::basic_string <char>
std::wstring | std::basic_string <wchar_t>
std::u8string (C++20 起) | std::basic_string <char8_t>
std::u16string (C++11 起) | std::basic_string <char16_t>
std::u32string (C++11 起) | std::basic_string <char32_t>

std::basic_string_view

模板类 std::basic_string_view 提供一个轻量对象，它使用类似 std::basic_string 接口的接口，提供对字符串一部分的只读访问。

标准提供 std::basic_string_view 对常用类型的数种特化：

定义于头文件 <string_view>
类型 | 定义
std::string_view (C++17 起) | std::basic_string_view <char>
std::wstring_view (C++17 起) | std::basic_string_view <wchar_t>
std::u8string_view (C++20 起) | std::basic_string_view <char8_t>
std::u16string_view (C++17 起) | std::basic_string_view <char16_t>
std::u32string_view (C++17 起) | std::basic_string_view <char32_t>
 (C++17 起)

空终止字符串

空终止字符串是以特殊的空字符终止的字符数组。C++提供创建、检查及修改空终止字符串的函数。

空终止字符串有三种类型：

  • 空终止字节字符串
  • 空终止多字节字符串
  • 空终止宽字符串

附加支持

std::char_traits

字符串库亦提供类模板 std::char_traits ，它为 std::basic_string 和 std::basic_string_view (C++17 起)定义类型和函数。标准定义下列特化：

定义于头文件 <string> |
template<> class char_traits<char>; |
template<> class char_traits<wchar_t>; |
template<> class char_traits<char8_t>; | (C++20 起)
template<> class char_traits<char16_t>; | (C++11 起)
template<> class char_traits<char32_t>; | (C++11 起)

转换与分类

本地化库提供对字符串转换的支持（例如 std::wstring_convert 或 std::toupper ），还有分类字符的函数（例如 std::isspace 或 std::isdigit ）。

参阅


std::basic_string

< cpp‎ | string
定义于头文件 <string>
template<

class CharT,
class Traits = std::char_traits <CharT>,
class Allocator = std::allocator <CharT>

> class basic_string;
 (1)
namespace pmr {

template <class CharT, class Traits = std::char_traits <CharT>>
using basic_string = std::basic_string< CharT, Traits,
std::polymorphic_allocator<CharT>>;

}
 (2) (C++17 起)

类模板 basic_string 存储并操纵作为非数组平凡 标准布局类型的仿 char 对象序列。该类既不依赖字符类型，亦不依赖该类型上的原生操作。操作的定义通过 Traits 模板形参—— std::char_traits 的特化或兼容特性类提供。 Traits::char_type 和 CharT 必须指名同一类型；否则程序非良构。

basic_string 是相继存储的，即对于 basic_string s ，对任何 [0, s.size()) 中的 n 有 &*(s.begin() + n) == &*s.begin() + n ，或等价地，指向 s[0] 的指针能传递给期待指向空终止 (C++11 起) CharT[] 数组首元素指针的函数。

std::basic_string 满足知分配器容器 (AllocatorAwareContainer) （除了不用定制的 construct/destroy 构造/析构元素）、序列容器 (SequenceContainer) 及连续容器 (ContiguousContainer) (C++17 起)的要求。

std::basic_string 的成员函数为 constexpr ：可以在常量表达式的求值中创建并使用 std::string 对象。

然而， std::string 对象通常不能为 constexpr ，因为任何动态分配的存储都必须在同一常量表达式求值内释放。

 (C++20 起)

提供数个对于常用字符类型的 typedef ：

定义于头文件 <string>
类型 | 定义
std::string | std::basic_string<char>
std::wstring | std::basic_string<wchar_t>
std::u8string (C++20) | std::basic_string<char8_t>
std::u16string (C++11) | std::basic_string<char16_t>
std::u32string (C++11) | std::basic_string<char32_t>
std::pmr::string (C++17) | std::pmr::basic_string<char>
std::pmr::wstring (C++17) | std::pmr::basic_string<wchar_t>
std::pmr::u8string (C++20) | std::pmr::basic_string<char8_t>
std::pmr::u16string (C++17) | std::pmr::basic_string<char16_t>
std::pmr::u32string (C++17) | std::pmr::basic_string<char32_t>

模板形参

CharT | - | 字符类型
Traits | - | 指定字符类型上操作的特性类
Allocator | - | 用于分配内部存储的分配器 (Allocator) 类型

成员类型

成员类型 | 定义
traits_type | Traits
value_type | CharT
allocator_type | Allocator
size_type
Allocator::size_type | (C++11 前)
std::allocator_traits <Allocator>::size_type | (C++11 起)
difference_type
Allocator::difference_type | (C++11 前)
std::allocator_traits <Allocator>::difference_type | (C++11 起)
reference | value_type&
const_reference | const value_type&
pointer
Allocator::pointer | (C++11 前)
std::allocator_traits <Allocator>::pointer | (C++11 起)
const_pointer
Allocator::const_pointer | (C++11 前)
std::allocator_traits <Allocator>::const_pointer | (C++11 起)
iterator
指向 value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 及老式连续迭代器 (LegacyContiguousIterator) | (C++20 前)
指向 value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 、contiguous_iterator 及常量表达式迭代器 (ConstexprIterator) | (C++20 起)
const_iterator
指向 const value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 及老式连续迭代器 (LegacyContiguousIterator) | (C++20 前)
指向 const value_type 的老式随机访问迭代器 (LegacyRandomAccessIterator) 、contiguous_iterator 及常量表达式迭代器 (ConstexprIterator) | (C++20 起)
reverse_iterator | std::reverse_iterator <iterator>
const_reverse_iterator | std::reverse_iterator <const_iterator>

成员函数

(构造函数)
 构造 basic_string
(公开成员函数)
(析构函数)
 销毁字符串，若使用内部存储则解分配它
(公开成员函数)
operator=
 为字符串赋值
(公开成员函数)
assign
 赋值字符给字符串
(公开成员函数)
get_allocator
 返回关联的分配器
(公开成员函数)
元素访问
at
 访问指定字符，有边界检查
(公开成员函数)
operator[]
 访问指定字符
(公开成员函数)
front
(C++11)
 访问首字符
(公开成员函数)
back
(C++11)
 访问最后的字符
(公开成员函数)
data
 返回指向字符串首字符的指针
(公开成员函数)
c_str
 返回字符串的不可修改的 C 字符数组版本
(公开成员函数)
operator basic_string_view
(C++17)
 返回到整个字符串的不可修改的 basic_string_view
(公开成员函数)
迭代器
begincbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)
end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)
rbegin crbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)
rend crend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)
容量
empty
 检查字符串是否为空
(公开成员函数)
sizelength
 返回字符数
(公开成员函数)
max_size
 返回字符数的最大值
(公开成员函数)
reserve
 保留存储
(公开成员函数)
capacity
 返回当前对象分配的存储空间能保存的字符数量
(公开成员函数)
shrink_to_fit
(C++11)
 通过释放不使用内存减少内存使用
(公开成员函数)
操作
clear
 清除内容
(公开成员函数)
insert
 插入字符
(公开成员函数)
erase
 移除字符
(公开成员函数)
push_back
 后附字符到结尾
(公开成员函数)
pop_back
(C++11)
 移除末尾字符
(公开成员函数)
append
 后附字符到结尾
(公开成员函数)
operator+=
 后附字符到结尾
(公开成员函数)
compare
 比较二个字符串
(公开成员函数)
starts_with
(C++20)
 检查 string 是否始于给定前缀
(公开成员函数)
ends_with
(C++20)
 检查 string 是否终于给定后缀
(公开成员函数)
contains
(C++23)
 检查字符串是否含有给定的子串或字符
(公开成员函数)
replace
 替换字符串的指定部分
(公开成员函数)
substr
 返回子串
(公开成员函数)
copy
 复制字符
(公开成员函数)
resize
 更改存储的字符数
(公开成员函数)
resize_and_overwrite
(C++23)
 更改存储的字符数并可能经由用户提供的操作重写不确定的内容
(公开成员函数)
swap
 交换内容
(公开成员函数)
查找
find
 于字符串中寻找字符
(公开成员函数)
rfind
 寻找子串的最后一次出现
(公开成员函数)
find_first_of
 寻找字符的首次出现
(公开成员函数)
find_first_not_of
 寻找字符的首次缺失
(公开成员函数)
find_last_of
 寻找字符的最后一次出现
(公开成员函数)
find_last_not_of
 寻找字符的最后一次缺失
(公开成员函数)

常量
npos
[静态]
 特殊值。准确含义依赖语境
(公开静态成员常量)

非成员函数

operator+
 连接两个字符串或者一个字符串和一个字符
(函数模板)
operator==operator!=operator<operator>operator<=operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 以字典序比较两个字符串
(函数模板)
std::swap(std::basic_string)
 特化 std::swap 算法
(函数模板)
erase(std::basic_string)erase_if(std::basic_string)
(C++20)
 擦除所有满足特定判别标准的元素
(函数模板)
输入/输出
operator<<operator>>
 执行字符串的流输入与输出
(函数模板)
getline
 从 I/O 流读取数据到字符串
(函数模板)
数值转换
stoistolstoll
(C++11)(C++11)(C++11)
 转换字符串为有符号整数
(函数)
stoulstoull
(C++11)(C++11)
 转换字符串为无符号整数
(函数)
stofstodstold
(C++11)(C++11)(C++11)
 转换字符串为浮点值
(函数)
to_string
(C++11)
 转换整数或浮点值为 string
(函数)
to_wstring
(C++11)
 转换整数或浮点值为 wstring
(函数)

字面量

定义于内联命名空间 std::literals::string_literals
operator""s
(C++14)
 转换字符数组字面量为 basic_string
(函数)

辅助类

std::hash<std::string>std::hash<std::u8string>std::hash<std::u16string>std::hash<std::u32string>std::hash<std::wstring>std::hash<std::pmr::string>std::hash<std::pmr::u8string>std::hash<std::pmr::u16string>std::hash<std::pmr::u32string>std::hash<std::pmr::wstring>
(C++11)(C++20)(C++11)(C++11)(C++11)(C++17)(C++20)(C++17)(C++17)(C++17)
 string 的散列支持
(类模板特化)

推导指引 (C++17 起)

注解

尽管在 C++23 前要求在构造或销毁 std::basic_string 的元素时使用定制的 construct 或 destroy，所有实现都使用默认机制。P1072R10 更正了该要求以匹配既存实现。

示例

#include <iostream>
#include <string>

int main()
{
    using namespace std::literals;

    // 从 const char* 创建 string
    std::string str1 = "hello";

    // 从字符串字面量创建 string
    auto str2 = "world"s;

    // 连接 string
    std::string str3 = str1 + " " + str2;

    // 打印结果
    std::cout << str3 << '\n';

    std::string::size_type pos = str3.find(" ");
    str1 = str3.substr(pos + 1); // the part after the space
    str2 = str3.substr(0, pos);  // the part till the space

    std::cout << str1 << ' ' << str2 << '\n';

    // 用下标运算符 operator[] 访问元素
    std::cout << str1[0] << '\n';
    str1[0] = 'W';
    std::cout << str1 << '\n';
}

输出：

hello world
world hello
w
World


std::basic_string<CharT,Traits,Allocator>::append

< cpp‎ | string‎ | basic string
 | (1)
basic_string& append( size_type count, CharT ch ); |  | (C++20 前)
constexpr basic_string& append( size_type count, CharT ch ); |  | (C++20 起)
 | (2)
basic_string& append( const basic_string& str ); |  | (C++20 前)
constexpr basic_string& append( const basic_string& str ); |  | (C++20 起)
 | (3)
basic_string& append( const basic_string& str, size_type pos, size_type count ); |  | (C++14 前)
basic_string& append( const basic_string& str, size_type pos, size_type count = npos ); |  | (C++14 起) (C++20 前)
constexpr basic_string& append( const basic_string& str, size_type pos, size_type count = npos ); |  | (C++20 起)
 | (4)
basic_string& append( const CharT* s, size_type count ); |  | (C++20 前)
constexpr basic_string& append( const CharT* s, size_type count ); |  | (C++20 起)
 | (5)
basic_string& append( const CharT* s ); |  | (C++20 前)
constexpr basic_string& append( const CharT* s ); |  | (C++20 起)
 | (6)
template< class InputIt > basic_string& append( InputIt first, InputIt last ); |  | (C++20 前)
template< class InputIt > constexpr basic_string& append( InputIt first, InputIt last ); |  | (C++20 起)
 | (7)
basic_string& append( std::initializer_list <CharT> ilist ); |  | (C++11 起) (C++20 前)
constexpr basic_string& append( std::initializer_list <CharT> ilist ); |  | (C++20 起)
 | (8)
template < class T > basic_string& append( const T& t ); |  | (C++17 起) (C++20 前)
template < class T > constexpr basic_string& append( const T& t ); |  | (C++20 起)
 | (9)
template < class T > basic_string& append( const T& t, size_type pos, size_type count = npos ); |  | (C++17 起) (C++20 前)
template < class T > constexpr basic_string& append( const T& t, size_type pos, size_type count = npos ); |  | (C++20 起)

后附额外字符到字符串。

1) 后附 count 个 ch 的副本
2) 后附 string str
3) 后附 str 的子串 [pos, pos+count) 。若请求的子串越过 string 结尾，或若 count == npos ，则后附的子串为 [pos, size()) 。若 pos > str.size() ，则抛出 std::out_of_range 。
4) 后附范围 [s, s + count) 中的字符。此范围能含有空字符。
5) 后附 s 所指向的空终止字符串。由首个空字符用 Traits::length(s) 确定字符串的长度。
6) 后附范围 [first, last) 中的字符。
若 InputIt 为整数类型，则此重载与重载 (1) 拥有相同效果。 | (C++11 前)
此重载仅若 InputIt 满足 老式输入迭代器 (LegacyInputIterator) 的要求才参与重载决议。 | (C++11 起)
7) 后附来自 initializer_list ilist 的字符。
8) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后如同用 append(sv.data(), sv.size()) 后附所有来自 sv 的字符。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。
9) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后后附来自 sv 子视图 [pos, pos+count) 的字符。若请求的子视图越过 sv 的结尾，或若 count == npos ，则后附的子视图为 [pos, sv.size()) 。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。

参数

count | - | 要后附的字符数
pos | - | 要后附的首个字符下标
ch | - | 要后附的字符值
first, last | - | 要后附的字符范围
str | - | 要后附的 string
s | - | 指向要后附的字符串的指针
ilist | - | 拥有要后附的字符的 initializer_list
t | - | 可转换为带要后附的字符的 std::basic_string_view 的对象

返回值

*this

复杂度

无标准复杂度保证，典型实现表现类似 std::vector::insert 。

异常

若因任何原因抛出异常，则此函数无效果（强异常保证）。 (C++11 起)

若操作会导致 size() > max_size() ，则抛出 std::length_error 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2946 | C++17 | string_view 重载在某些情况下导致歧义 | 通过使之为模板来避免

示例

#include <string>
#include <iostream>

int main() {
    std::basic_string<char> str = "string";
    const char* cptr = "C-string";
    const char carr[] = "Two and one";

    std::string output;

    // 1) 后附 char 3 次。
    // 注意，这是仅有的接受 char 的重载。
    output.append(3, '*');
    std::cout << "1) " << output << "\n";

    //  2) 后附整个 string
    output.append(str);
    std::cout << "2) " << output << "\n";

    // 3) 后附字符串的一部分（此情况为最后 3 个字母）case)
    output.append(str, 3, 3);
    std::cout << "3) " << output << "\n";

    // 4) 后附 C 字符串的一部分
    // 注意，因为 `append` 返回 *this ，我们能一同链式调用
    output.append(1, ' ').append(carr, 4);
    std::cout << "4) " << output << "\n";

    // 5) 后附整个 C 字符串
    output.append(cptr);
    std::cout << "5) " << output << "\n";

    // 6) 后附范围
    output.append(std::begin(carr) + 3, std::end(carr));
    std::cout << "6) " << output << "\n";

    // 7) 后附 initializer_list
    output.append({ ' ', 'l', 'i', 's', 't' });
    std::cout << "7) " << output << "\n";
}

输出：

1) ***
2) ***string
3) ***stringing
4) ***stringing Two
5) ***stringing Two C-string
6) ***stringing Two C-string and one
7) ***stringing Two C-string and one list

参阅

operator+= | 后附字符到结尾 (公开成员函数)
strcat | 连接两个字符串 (函数)
strncat | 连接两个字符串的一定量字符 (函数)
wcscat | 后附一个宽字符串的副本到另一个 (函数)
wcsncat | 后附来自一个宽字符串的一定量宽字符到另一个 (函数)


std::basic_string<CharT,Traits,Allocator>::assign

< cpp‎ | string‎ | basic string
 | (1)
basic_string& assign( size_type count, CharT ch ); |  | (C++20 前)
constexpr basic_string& assign( size_type count, CharT ch ); |  | (C++20 起)
 | (2)
basic_string& assign( const basic_string& str ); |  | (C++20 前)
constexpr basic_string& assign( const basic_string& str ); |  | (C++20 起)
 | (3)
basic_string& assign( const basic_string& str, size_type pos, size_type count ); |  | (C++14 前)
basic_string& assign( const basic_string& str, size_type pos, size_type count = npos); |  | (C++14 起) (C++20 前)
constexpr basic_string& assign( const basic_string& str, size_type pos, size_type count = npos); |  | (C++20 起)
 | (4)
basic_string& assign( basic_string&& str ); |  | (C++11 起) (C++17 前)
basic_string& assign( basic_string&& str ) noexcept(/* see below */); |  | (C++17 起) (C++20 前)
constexpr basic_string& assign( basic_string&& str ) noexcept(/* see below */); |  | (C++20 起)
 | (5)
basic_string& assign( const CharT* s, size_type count ); |  | (C++20 前)
constexpr basic_string& assign( const CharT* s, size_type count ); |  | (C++20 起)
 | (6)
basic_string& assign( const CharT* s ); |  | (C++20 前)
constexpr basic_string& assign( const CharT* s ); |  | (C++20 起)
 | (7)
template< class InputIt > basic_string& assign( InputIt first, InputIt last ); |  | (C++20 前)
template< class InputIt > constexpr basic_string& assign( InputIt first, InputIt last ); |  | (C++20 起)
 | (8)
basic_string& assign( std::initializer_list <CharT> ilist ); |  | (C++11 起) (C++20 前)
constexpr basic_string& assign( std::initializer_list <CharT> ilist ); |  | (C++20 起)
 | (9)
template < class T > basic_string& assign( const T& t ); |  | (C++17 起) (C++20 前)
template < class T > constexpr basic_string& assign( const T& t ); |  | (C++20 起)
 | (10)
template < class T > basic_string& assign( const T& t, size_type pos, size_type count = npos); |  | (C++17 起) (C++20 前)
template < class T > constexpr basic_string& assign( const T& t, size_type pos, size_type count = npos); |  | (C++20 起)

替换字符串的内容。

1) 以 count 个 ch 的副本替换内容。
2) 以 str 的副本替换内容。等价于 *this = str; 。特别是可以发生分配器传播。 (C++11 起)
3) 以 str 的子串 [pos, pos+count) 替换内容。若请求的子串越过 string 尾，或若 count == npos ，则产生的子串是 [pos, str.size()) 。若 pos > str.size() ，则抛出 std::out_of_range 。
4) 用移动语义以 str 的内容替换内容。等价于 *this = std::move(str) 。特别是可以发生分配器传播。
5) 以范围 [s, s+count) 中的字符的副本替换内容。此范围能含空字符。
6) 以 s 所指向的空终止字符串的内容替换内容。由首个空字符，用 Traits::length(s) 确定字符串长度。
7) 以范围 [first, last) 中的字符的副本替换内容。若 InputIt 不满足老式输入迭代器 (LegacyInputIterator) ，则此重载不参与重载决议。 (C++11 起)
8) 以 initializer_list ilist 的内容替换内容。
9) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后以字符串视图 sv 的内容替换内容，如同用 assign(sv.data(), sv.size())。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。
10) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后以来自 sv 的子视图 [pos, pos+count) 的字符替换内容。若请求的子视图越过 sv 的结尾，或若 count == npos ，则产生的子视图为 [pos, sv.size()) 。若 pos > sv.size() ，则抛出 std::out_of_range 。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。

参数

count | - | 产生的 string 大小
pos | - | 要取的首字符下标
ch | - | 用以初始化字符串的字符的值
first, last | - | 复制字符来源的范围
str | - | 用作源以初始化字符的 string
s | - | 指向用作源初始化 string 字符串的指针
ilist | - | 用以初始化 string 字符的 std::initializer_list
sv | - | 用以初始化 string 字符的 std::basic_string_view
t | - | 用以初始化 string 字符的对象（可转换为 std::basic_string_view ）
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

*this

复杂度

1) 与 count 成线性
2) 与 str 的大小成线性
3) 与 count 成线性
4) 常数。若给定 alloc 且 alloc != other.get_allocator() ，则为线性。
5) 与 count 成线性
6) 与 s 的大小成线性
7) 与 first 和 last 间的距离成线性
8) 与 ilist 的大小成线性

异常

若因任何原因抛出异常，则此函数无效果（强异常保证）。 (C++11 起)

若操作会导致 size() > max_size() ，则抛出 std::length_error 。

4)
noexcept 规定：
noexcept( std::allocator_traits <Allocator>::propagate_on_container_move_assignment::value
|| std::allocator_traits <Allocator>::is_always_equal::value)
 (C++17 起)

示例

#include <iostream>
#include <iterator>
#include <string>

int main()
{
  std::string s;
  // assign(size_type count, CharT ch)
  s.assign(4, '=');
  std::cout << s << '\n'; // "===="

  std::string const c("Exemplary");
  // assign(basic_string const& str)
  s.assign(c);
  std::cout << c << "==" << s <<'\n'; // "Exemplary == Exemplary"

  // assign(basic_string const& str, size_type pos, size_type count)
  s.assign(c, 0, c.length()-1);
  std::cout << s << '\n'; // "Exemplar";

  // assign(basic_string&& str)
  s.assign(std::string("C++ by ") + "example");
  std::cout << s << '\n'; // "C++ by example"

  // assign(charT const* s, size_type count)
  s.assign("C-style string", 7);
  std::cout << s << '\n'; // "C-style"

  // assign(charT const* s)
  s.assign("C-style\0string");
  std::cout << s << '\n'; // "C-style"

  char mutable_c_str[] = "C-style string";
  // assign(InputIt first, InputIt last)
  s.assign(std::begin(mutable_c_str), std::end(mutable_c_str)-1);
  std::cout << s << '\n'; // "C-style string"

  // assign(std::initializer_list<charT> ilist)
  s.assign({ 'C', '-', 's', 't', 'y', 'l', 'e' });
  std::cout << s << '\n'; // "C-style"
}

输出：

====
Exemplary==Exemplary
Exemplar
C++ by example
C-style
C-style
C-style string
C-style

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2063 | C++11 | 非标准化注释曾说交换是移动赋值的合法实现 | 更正为要求移动赋值
LWG 2579 | C++11 | assign(const basic_string&) 不传播分配器 | 使之为若需要则传播分配器
LWG 2946 | C++17 | string_view 重载在某些情况下导致歧义 | 通过使之为模板避免

参阅

(构造函数) | 构造 basic_string (公开成员函数)
operator= | 为字符串赋值 (公开成员函数)


std::basic_string<CharT,Traits,Allocator>::at

< cpp‎ | string‎ | basic string
reference at( size_type pos ); | (C++20 前)
constexpr reference at( size_type pos ); | (C++20 起)
const_reference at( size_type pos ) const; | (C++20 前)
constexpr const_reference at( size_type pos ) const; | (C++20 起)

返回到位于指定位置 pos 的字符的引用。进行边界检查，非法访问时抛出 std::out_of_range 类型的异常。

参数

pos - 要返回的字符位置

返回值

到请求的字符的引用。

异常

若 pos >= size() 则抛出 std::out_of_range 。

复杂度

常数。

示例

#include <stdexcept>
#include <iostream>
#include <string>

int main()
{
    std::string s("message"); // 为容量

    s = "abc";
    s.at(2) = 'x'; // ok
    std::cout << s << '\n';

    std::cout << "string size = " << s.size() << '\n';
    std::cout << "string capacity = " << s.capacity() << '\n';

    try {
        // 抛出，即使容量允许访问元素
        s.at(3) = 'x';
    }
    catch (std::out_of_range const& exc) {
        std::cout << exc.what() << '\n';
    }
}

可能的输出：

abx
string size = 3
string capacity = 7
basic_string::at

参阅

operator[]
 访问指定字符
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::back

< cpp‎ | string‎ | basic string
CharT& back(); | (C++11 起) (C++20 前)
constexpr CharT& back(); | (C++20 起)
const CharT& back() const; | (C++11 起) (C++20 前)
constexpr const CharT& back() const; | (C++20 起)

返回字符串中的末字符。若 empty() == true 则行为未定义。

参数

（无）

返回值

到末字符的引用，等价于 operator[](size() - 1) 。

复杂度

常数

示例

#include <iostream>
#include <string>

int main()
{
  {
    std::string s("Exemplary");
    char& back = s.back();
    back = 's';
    std::cout << s << '\n'; // "Exemplars"
  }

  {
    std::string const c("Exemplary");
    char const& back = c.back();
    std::cout << back << '\n'; // 'y'
  }
}

输出：

Exemplars
y

参阅

front
(C++11)
 访问首字符
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::basic_string

< cpp‎ | string‎ | basic string
(1)
basic_string();
explicit basic_string( const Allocator& alloc );
 (C++17 前)
basic_string() noexcept(noexcept( Allocator() )) :

basic_string( Allocator() ) {}

explicit basic_string( const Allocator& alloc ) noexcept;
 (C++17 起)
(C++20 前)
constexpr basic_string() noexcept(noexcept( Allocator() )) :

basic_string( Allocator() ) {}

explicit constexpr basic_string( const Allocator& alloc ) noexcept;
 (C++20 起)
(2)
basic_string( size_type count,

CharT ch,

const Allocator& alloc = Allocator() );
 (C++20 前)
constexpr basic_string( size_type count,

CharT ch,

const Allocator& alloc = Allocator() );
 (C++20 起)
(3)
basic_string( const basic_string& other,

size_type pos,
size_type count = std::basic_string::npos,

const Allocator& alloc = Allocator() );
 (C++17 前)
basic_string( const basic_string& other,

size_type pos,

const Allocator& alloc = Allocator() );
 (C++17 起)
(C++20 前)
constexpr basic_string( const basic_string& other,

size_type pos,

const Allocator& alloc = Allocator() );
 (C++20 起)
(3)
basic_string( const basic_string& other,

size_type pos,
size_type count,

const Allocator& alloc = Allocator() );
 (C++17 起)
(C++20 前)
constexpr basic_string( const basic_string& other,

size_type pos,
size_type count,

const Allocator& alloc = Allocator() );
 (C++20 起)
(4)
basic_string( const CharT* s,

size_type count,

const Allocator& alloc = Allocator() );
 (C++20 前)
constexpr basic_string( const CharT* s,

size_type count,

const Allocator& alloc = Allocator() );
 (C++20 起)
(5)
basic_string( const CharT* s,
const Allocator& alloc = Allocator() );
 (C++20 前)
constexpr basic_string( const CharT* s,
const Allocator& alloc = Allocator() );
 (C++20 起)
(6)
template< class InputIt >

basic_string( InputIt first, InputIt last,

const Allocator& alloc = Allocator() );
 (C++20 前)
template< class InputIt >

constexpr basic_string( InputIt first, InputIt last,

const Allocator& alloc = Allocator() );
 (C++20 起)
(7)
basic_string( const basic_string& other );
 (C++20 前)
constexpr basic_string( const basic_string& other );
 (C++20 起)
(7)
basic_string( const basic_string& other, const Allocator& alloc );
 (C++11 起)
(C++20 前)
constexpr basic_string( const basic_string& other, const Allocator& alloc );
 (C++20 起)
(8)
basic_string( basic_string&& other ) noexcept;
 (C++11 起)
(C++20 前)
constexpr basic_string( basic_string&& other ) noexcept;
 (C++20 起)
(8)
basic_string( basic_string&& other, const Allocator& alloc );
 (C++11 起)
(C++20 前)
constexpr basic_string( basic_string&& other, const Allocator& alloc );
 (C++20 起)
(9)
basic_string( std::initializer_list <CharT> ilist,
const Allocator& alloc = Allocator() );
 (C++11 起)
(C++20 前)
constexpr basic_string( std::initializer_list <CharT> ilist,
const Allocator& alloc = Allocator() );
 (C++20 起)
(10)
template < class T >
explicit basic_string( const T& t, const Allocator& alloc = Allocator() );
 (C++17 起)
(C++20 前)
template < class T >

explicit constexpr basic_string( const T& t,

const Allocator& alloc = Allocator() );
 (C++20 起)
(11)
template < class T >

basic_string( const T& t, size_type pos, size_type n,

const Allocator& alloc = Allocator() );
 (C++17 起)
(C++20 前)
template < class T >

constexpr basic_string( const T& t, size_type pos, size_type n,

const Allocator& alloc = Allocator() );
 (C++20 起)
constexpr basic_string( std::nullptr_t ) = delete;
 (12) (C++23 起)

从各种数据源构造新 string ，可选地使用用户提供的分配器 alloc 。

1) 默认构造函数。构造空 string （拥有零大小和未指定的容量）。若不提供分配器，则从默认构造的实例获得分配器。
2) 构造拥有字符 ch 的 count 个副本的 string 。若会推导出不足以作为分配器的 Allocator 类型，则此构造函数不用于类模板实参推导。 (C++17 起)
3) 以 other 的子串 [pos, pos+count) 构造 string 。若 count == npos 或未指定 count ，或若请求的子串越过字符串的结尾，则产生的子串为 [pos, other.size()) 。
4) 以 s 所指向的字符串的首 count 个字符构造 string 。 s 能包含空字符。 string 的长度为 count 。若 [s, s + count) 不是合法范围则行为未定义。
5) 以 s 所指向的空终止字符串的副本所初始化的内容构造 string 。以首个空字符确定字符串的长度。若 [s, s + Traits::length(s)) 不是合法范围（例如若 s 是空指针）则行为未定义。若会推导出不足以作为分配器的 Allocator 类型，则此构造函数不用于类模板实参推导。 (C++17 起)
6) 构造拥有范围 [first, last) 内容的 string 。
若 InputIt 为整数类型，则等价于 basic_string(static_cast<size_type>(first), static_cast<value_type>(last), a) 。 | (C++11 前)
此构造函数仅若 InputIt 满足 老式输入迭代器 (LegacyInputIterator) 才参与重载决议。 | (C++11 起)
7) 复制构造函数。构造拥有 other 内容副本的 string 。
8) 移动构造函数。用移动语义构造拥有 other 内容的 string 。将 other 留在合法但未指定的状态。
9) 构造拥有 initializer_list ilist 内容的 string 。
10) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后如同用 basic_string(sv.data(), sv.size(), alloc) ，以 sv 的内容初始化 string 。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。
11) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后如同用 basic_string(sv.substr(pos, n), a) ，以 sv 的子范围 [pos, pos + n) 初始化 string 。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 才参与重载决议。
12) 不能从 nullptr 构造 basic_string 。

参数

alloc | - | 用于此 string 所有内存分配的分配器
count | - | 产生的 string 大小
ch | - | 初始化 string 所用的值
pos | - | 要包含的首字符位置
first, last | - | 复制字符的来源范围
s | - | 指向用作源初始化 string 的字符数组的指针
other | - | 用作源初始化 string 的另一 string
ilist | - | 初始化 string 所用的 std::initializer_list
t | - | 初始化 string 所用的对象（可转换为 std::basic_string_view ）

复杂度

1) 常数
2-4) 与 count 成线性
5) 与 s 的长度成线性
6) 与 first 和 last 间的距离成线性
7) 与 other 的大小成线性
8) 常数。若给出 alloc 且 alloc != other.get_allocator() 则为线性
9) 与 ilist 的大小成线性

异常

3) 若 pos > other.size() 则为 std::out_of_range
8) 若 alloc == str.get_allocator() 则不抛出
11) 若 pos 在范围外则为 std::out_of_range

若构造的字符串长度会超出 max_size() （例如对于 (2) ，若 count > max_size() ）则抛出 std::length_error 。调用 Allocator::allocate 可能抛出。

注意

以含内嵌 '\0' 字符的字符串字面量初始化 string 会使用重载 (5) ，并在首个空字符停止。这可通过指定不同的构造函数，或通过使用 operator""s 避免：

std::string s1 = "ab\0\0cd";   // s1 含 "ab"
std::string s2{"ab\0\0cd", 6}; // s2 含 "ab\0\0cd"
std::string s3 = "ab\0\0cd"s;  // s3 含 "ab\0\0cd"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2193 | C++11 | 默认构造函数为 explicit | 使之为非 explicit
LWG 2946 | C++17 | string_view 重载在一些情况下导致歧义 | 通过使之为模板来避免
LWG 3076 | C++17 | 二个构造函数可能在类模板实参推导中导致歧义 | 已制约

示例

#include <iostream>
#include <cassert>
#include <iterator>
#include <string>
#include <cctype>

int main()
{
  {
    // string::string()
    std::string s;
    assert(s.empty() && (s.length() == 0) && (s.size() == 0));
  }

  {
    // string::string(size_type count, charT ch)
    std::string s(4, '=');
    std::cout << s << '\n'; // "===="
  }

  {
    std::string const other("Exemplary");
    // string::string(string const& other, size_type pos, size_type count)
    std::string s(other, 0, other.length()-1);
    std::cout << s << '\n'; // "Exemplar"
  }

  {
    // string::string(charT const* s, size_type count)
    std::string s("C-style string", 7);
    std::cout << s << '\n'; // "C-style"
  }

  {
    // string::string(charT const* s)
    std::string s("C-style\0string");
    std::cout << s << '\n'; // "C-style"
  }

  {
    char mutable_c_str[] = "another C-style string";
    // string::string(InputIt first, InputIt last)
    std::string s(std::begin(mutable_c_str)+8, std::end(mutable_c_str)-1);
    std::cout << s << '\n'; // "C-style string"
  }

  {
    std::string const other("Exemplar");
    std::string s(other);
    std::cout << s << '\n'; // "Exemplar"
  }

  {
    // string::string(string&& str)
    std::string s(std::string("C++ by ") + std::string("example"));
    std::cout << s << '\n'; // "C++ by example"
  }

  {
    // string(std::initializer_list<charT> ilist)
    std::string s({ 'C', '-', 's', 't', 'y', 'l', 'e' });
    std::cout << s << '\n'; // "C-style"
  }

  {
    // 重载决议选择 string(InputIt first, InputIt last) [with InputIt = int]
    // 这表现为如同调用 string(size_type count, charT ch)
    std::string s(3, std::toupper('a'));
    std::cout << s << '\n'; // "AAA"
  }
}

输出：

====
Exemplar
C-style
C-style
C-style string
Exemplar
C++ by example
C-style
AAA

参阅

assign | 赋值字符给字符串 (公开成员函数)
operator= | 为字符串赋值 (公开成员函数)
to_string (C++11) | 转换整数或浮点值为 string (函数)
to_wstring (C++11) | 转换整数或浮点值为 wstring (函数)


std::basic_string<CharT,Traits,Allocator>::begin, std::basic_string<CharT,Traits,Allocator>::cbegin

< cpp‎ | string‎ | basic string
 | (1)
iterator begin(); |  | (C++11 前)
iterator begin() noexcept; |  | (C++11 起) (C++20 前)
constexpr iterator begin() noexcept; |  | (C++20 起)
 | (2)
const_iterator begin() const; |  | (C++11 前)
const_iterator begin() const noexcept; |  | (C++11 起) (C++20 前)
constexpr const_iterator begin() const noexcept; |  | (C++20 起)
 | (3)
const_iterator cbegin() const noexcept; |  | (C++11 起) (C++20 前)
constexpr const_iterator cbegin() const noexcept; |  | (C++20 起)

返回指向字符串首字符的迭代器。

begin() 返回可变或常迭代器，取决于 *this 的常性。

cbegin() 始终返回常迭代器。它等价于 const_cast<const basic_string&>(*this).begin() 。

参数

（无）

返回值

指向首字符的迭代器

复杂度

常数

示例

#include <string>
#include <iostream>

int main()
{
    std::string s("Exemplar");
    *s.begin() = 'e';
    std::cout << s <<'\n';

    auto i = s.cbegin();
    std::cout << *i << '\n';
//  *i = 'E'; // 错误： i 是常迭代器
}

输出：

exemplar
e

参阅

end cend
(C++11)
 返回指向末尾的迭代器
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::c_str

< cpp‎ | string‎ | basic string
const CharT* c_str() const; | (C++11 前)
const CharT* c_str() const noexcept; | (C++11 起) (C++20 前)
constexpr const CharT* c_str() const noexcept; | (C++20 起)

返回指向拥有数据等价于存储于字符串中的空终止字符数组的指针。

该指针有范围 [c_str(); c_str() + size()] 为合法，且其中的值对应存储于字符串的值，且在最后位置有个附加的空终止字符。

从 c_str() 获得的指针可能被下列行为非法化：

  • 传递给任何非标准库函数字符串的非 const 引用，或
  • 在字符串上调用非 const 成员函数，包括 operator[] 、 at() 、 front() 、 back() 、 begin() 、 rbegin() 、 end() 及 rend() 。

通过 c_str() 写入字符数组是未定义行为。

c_str() 与 data() 进行同一功能。

 (C++11 起)

参数

（无）

返回值

指向底层字符存储的指针。

对于每个 [0, size()) 中的 i 有 c_str()[i] == operator[](i) 。 | (C++11 前)
对于每个 [0, size()] 中的 i 有 c_str() + i == std::addressof (operator[](i)) 。 | (C++11 起)

复杂度

常数。

注意

从 c_str() 获得的指针可以只当做一个指向空终止字符串的指针，若 string 对象不含其他空字符。

示例

#include <algorithm>
#include <cassert>
#include <cstring>
#include <string>

int main()
{
  std::string const s("Emplary");
  assert(s.size() == std::strlen(s.c_str()));
  assert(std::equal(s.begin(), s.end(), s.c_str()));
  assert(std::equal(s.c_str(), s.c_str() + s.size(), s.begin()));
  assert(0 == *(s.c_str() + s.size()));
}

参阅

front (C++11) | 访问首字符 (公开成员函数)
back (C++11) | 访问最后的字符 (公开成员函数)
data | 返回指向字符串首字符的指针 (公开成员函数)


std::basic_string<CharT,Traits,Allocator>::capacity

< cpp‎ | string‎ | basic string
size_type capacity() const; | (C++11 前)
size_type capacity() const noexcept; | (C++11 起) (C++20 前)
constexpr size_type capacity() const noexcept; | (C++20 起)

返回当前已为字符串分配空间的字符数。

参数

（无）

返回值

当前分配的存储，即可用于存储元素的存储的容量。

复杂度

常数

注解

从分配器获得，但不可用于存储任何元素的内存位置不计入分配的存储。注意空终止符不是 basic_string 的元素。

示例

#include <iostream>
#include <string>

void show_capacity(std::string const& s)
{
    std::cout << "'" << s << "' has capacity " << s.capacity() << ".\n";
}

int main()
{
    std::string s{"Exemplar"};
    show_capacity(s);

    s += " is an example string.";
    show_capacity(s);
}

可能的输出：

'Exemplar' has capacity 15.
'Exemplar is an example string.' has capacity 31.

参阅

sizelength | 返回字符数 (公开成员函数)
reserve | 保留存储 (公开成员函数)


std::basic_string<CharT,Traits,Allocator>::clear

< cpp‎ | string‎ | basic string
void clear(); | (C++11 前)
void clear() noexcept; | (C++11 起) (C++20 前)
constexpr void clear() noexcept; | (C++20 起)

如同通过执行 erase(begin(), end()) 从 string 移除所有字符。

非法化所有指针、引用及迭代器。

参数

（无）

返回值

（无）

注解

不同于 std::vector::clear ， C++ 标准不显式要求此函数不更改 capacity ，但既存实现都不更改容量。这意味着它们不释放分配的内存（参阅 shrink_to_fit ）。

复杂度

与 string 大小成线性，尽管既存实现在常数时间内操作。

示例

#include <cassert>
#include <string>

int main()
{
    std::string s{ "Exemplar" };
    std::string::size_type const capacity = s.capacity();

    s.clear();
    assert(s.capacity() == capacity);
    assert(s.empty());
    assert(s.size() == 0);
}

参阅

erase
 移除字符
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::compare

< cpp‎ | string‎ | basic string
 | (1)
int compare( const basic_string& str ) const; |  | (C++11 前)
int compare( const basic_string& str ) const noexcept; |  | (C++11 起) (C++20 前)
constexpr int compare( const basic_string& str ) const noexcept; |  | (C++20 起)
 | (2)
int compare( size_type pos1, size_type count1, const basic_string& str ) const; |  | (C++20 前)
constexpr int compare( size_type pos1, size_type count1, const basic_string& str ) const; |  | (C++20 起)
 | (3)
int compare( size_type pos1, size_type count1, const basic_string& str, size_type pos2, size_type count2 ) const; |  | (C++14 前)
int compare( size_type pos1, size_type count1, const basic_string& str, size_type pos2, size_type count2 = npos ) const; |  | (C++14 起) (C++20 前)
constexpr int compare( size_type pos1, size_type count1, const basic_string& str, size_type pos2, size_type count2 = npos ) const; |  | (C++20 起)
 | (4)
int compare( const CharT* s ) const; |  | (C++20 前)
constexpr int compare( const CharT* s ) const; |  | (C++20 起)
 | (5)
int compare( size_type pos1, size_type count1, const CharT* s ) const; |  | (C++20 前)
constexpr int compare( size_type pos1, size_type count1, const CharT* s ) const; |  | (C++20 起)
 | (6)
int compare( size_type pos1, size_type count1, const CharT* s, size_type count2 ) const; |  | (C++20 前)
constexpr int compare( size_type pos1, size_type count1, const CharT* s, size_type count2 ) const; |  | (C++20 起)
 | (7)
template < class T > int compare( const T& t ) const noexcept(/* see below */); |  | (C++17 起) (C++20 前)
template < class T > constexpr int compare( const T& t ) const noexcept(/* see below */); |  | (C++20 起)
 | (8)
template < class T > int compare( size_type pos1, size_type count1, const T& t ) const; |  | (C++17 起) (C++20 前)
template < class T > constexpr int compare( size_type pos1, size_type count1, const T& t ) const; |  | (C++20 起)
 | (9)
template < class T > int compare( size_type pos1, size_type count1, const T& t, size_type pos2, size_type count2 = npos) const; |  | (C++17 起) (C++20 前)
template < class T > constexpr int compare( size_type pos1, size_type count1, const T& t, size_type pos2, size_type count2 = npos) const; |  | (C++20 起)

比较二个字符序列。

1) 比较此 string 与 str 。
2) 比较此 string 的 [pos1, pos1+count1) 子串与 str 。若 count1 > size() - pos1 则子串为 [pos1, size()) 。
3) 比较此 string 的 [pos1, pos1+count1) 子串与 str 的子串 [pos2, pos2+count2) 。若 count1 > size() - pos1 则第一子串为 [pos1, size()) 。类似地若 count2 > str.size() - pos2 则第二子串为 [pos2, str.size()) 。
4) 比较此 string 与始于 s 所指向字符的长度为 Traits::length(s) 的空终止字符序列。
5) 比较此 string 的 [pos1, pos1+count1) 子串与始于 s 所指向字符的长度为 Traits::length(s) 的空终止字符序列。若 count1 > size() - pos1 则子串为 [pos1, size()) 。
6) 比较此 string 的 [pos1, pos1+count1) 子串与范围 [s, s + count2) 中的字符。（注意：范围 [s, s + count2) 中的字符可包含空字符。）
7) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后比较此 string 与 sv 。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。
8) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后比较此 string 的 [pos1, pos1+count1) 子串与 sv ，如同用 std::basic_string_view <CharT, Traits>(data(), size()).substr(pos1, count1).compare(sv) 。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。
9) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后比较此 string 的 [pos1, pos1+count1) 子串与 sv 的 [pos2, pos2+count2) 子串，如同用 std::basic_string_view <CharT, Traits>(data(), size()).substr(pos1, count1).compare(sv.substr(pos2, count2)); 。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。

按下列方式比较始于 data1 的 count1 个字符组成的字符序列与始于 data2 的 count2 个字符组成的字符序列。首先，如同用 size_type rlen = std::min (count1, count2) 计算要比较的字符数。然后调用 Traits::compare(data1, data2, rlen) 比较序列。对于标准字符特性，此函数进行逐字符字典序比较。若结果为零（到此为止的字符序列相等），则按下列方式比较其大小：

条件 |  | 结果 | 返回值
Traits::compare(data1, data2, rlen) < 0 |  | data1 小于 data2 | <0
Traits::compare(data1, data2, rlen) == 0 | size1 < size2 | data1 小于 data2 | <0
 | size1 == size2 | data1 等于 data2 | ​0​
 | size1 > size2 | data1 大于 data2 | >0
Traits::compare(data1, data2, rlen) > 0 |  | data1 大于 data2 | >0

参数

str | - | 要比较的另一 string
s | - | 指向要比较的字符串的指针
count1 | - | 此 string 要比较的字符数
pos1 | - | 此 string 中要比较的首字符的位置
count2 | - | 给定字符串要比较的字符数
pos2 | - | 给定字符串的要比较的首字符位置
t | - | 要比较的对象（可转换为 std::basic_string_view ）

返回值

若 *this 在字典序中先出现于参数所指定的字符序列，则为负值。

若两个序列比较等价则为零。

若 *this 在字典序中后出现于参数所指定的字符序列，则为正值。

异常

接收名为 pos1 或 pos2 的参数的重载若参数在范围外则抛出 std::out_of_range 。

7)
noexcept 说明：
noexcept(std::is_nothrow_convertible_v<const T&, std::basic_string_view <CharT, Traits>>)
8-9) 抛出任何到 basic_string_view 的转换所抛的异常。

可能的实现

template<class CharT, class Traits, class Alloc>
int basic_string<CharT, Traits, Alloc>::compare(const std::basic_string& s) const noexcept
{
    size_type lhs_sz = size();
    size_type rhs_sz = s.size();
    if (int result = traits_type::compare(data(), s.data(), std::min(lhs_sz, rhs_sz)))
        return result;
    if (lhs_sz < rhs_sz)
        return -1;
    if (lhs_sz > rhs_sz)
        return 1;
    return 0;
}

注解

对于不要求三路比较的情形， std::basic_string 提供通常关系运算符（ < 、 <= 、 == 、 > 等）。

此函数默认（以默认 std::char_traits ）不会考虑本地环境。具本地环境的三路比较见 std::collate::compare 。

示例

#include <cassert>
#include <string>
#include <iostream>

int main()
{
    // 1) 与另一 string 比较
    {
        int compare_value{
            std::string{"Batman"}.compare(std::string{"Superman"})
        };
        std::cout << (
            compare_value < 0 ? "Batman comes before Superman\n" :
            compare_value > 0 ? "Superman comes before Batman\n" :
            "Superman and Batman are the same.\n"
        );
    }

    // 2) 与另一 string 比较子串
    {
        int compare_value{
            std::string{"Batman"}.compare(3, 3, std::string{"Superman"})
        };
        std::cout << (
            compare_value < 0 ? "man comes before Superman\n" :
            compare_value > 0 ? "Superman comes before man\n" :
            "man and Superman are the same.\n"
        );
    }

    // 3) 与另一子串比较子串
    {
        std::string a{"Batman"};
        std::string b{"Superman"};

        int compare_value{a.compare(3, 3, b, 5, 3)};

        std::cout << (
            compare_value < 0 ? "man comes before man\n" :
            compare_value > 0 ? "man comes before man\n" :
            "man and man are the same.\n"
        );
        // 与另一子串比较子串
        // 默认到为另一 string 的末尾
        assert(compare_value == a.compare(3, 3, b, 5));
    }

    // 4) 与另一 char 指针比较
    {
        int compare_value{std::string{"Batman"}.compare("Superman")};

        std::cout << (
            compare_value < 0 ? "Batman comes before Superman\n" :
            compare_value > 0 ? "Superman comes before Batman\n" :
            "Superman and Batman are the same.\n"
        );
    }

    // 5) 与另一 char 指针比较子串
    {
        int compare_value{std::string{"Batman"}.compare(3, 3, "Superman")};

        std::cout << (
            compare_value < 0 ? "man comes before Superman\n" :
            compare_value > 0 ? "Superman comes before man\n" :
            "man and Superman are the same.\n"
        );
    }

    // 6) 与另一 char 指针子串比较子串
    {
        int compare_value{std::string{"Batman"}.compare(0, 3, "Superman", 5)};

        std::cout << (
            compare_value < 0 ? "Bat comes before Super\n" :
            compare_value > 0 ? "Super comes before Bat\n" :
            "Super and Bat are the same.\n"
        );
    }
}

输出：

Batman comes before Superman
Superman comes before man
man and man are the same.
Batman comes before Superman
Superman comes before man
Bat comes before Super

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2946 | C++17 | string_view 重载在某些情况下导致歧义 | 通过使之为模板来避免
P1148R0 | C++17 | 重载 (7) 的 noexcept 被 LWG2946 意外丢弃 | 恢复

参阅

operator==operator!=operator<operator>operator<=operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 以字典序比较两个字符串 (函数模板)
substr | 返回子串 (公开成员函数)
collate | 定义字典序比较和字符串的散列 (类模板)
strcoll | 按照当前本地环境比较两个字符串 (函数)
lexicographical_compare | 当一个范围按字典顺序小于另一个范围时，返回 true (函数模板)


std::basic_string<CharT,Traits,Allocator>::contains

< cpp‎ | string‎ | basic string
constexpr bool contains( std::basic_string_view <CharT,Traits> sv )
const noexcept;
 (1) (C++23 起)
constexpr bool contains( CharT c ) const noexcept;
 (2) (C++23 起)
constexpr bool contains( const CharT* s ) const;
 (3) (C++23 起)

检查字符串是否含有给定子串。子串可以是下列三种之一：

1) 字符串视图 sv （可能为从另一 std::basic_string 隐式转换的结果）。
2) 单个字符 c 。
3) 空终止字符串 s 。

所有三个重载都等价于 return find(x) != npos; ，其中 x 为参数。

参数

sv | - | 字符串视图，可能为从另一 std::basic_string 隐式转换的结果
c | - | 单个字符
s | - | 空终止字符串

返回值

若字符串含有给定子串则为 true ，否则为 false 。

示例

#include <iostream>
#include <string_view>
#include <string>

template <typename SubstrType>
void test_substring_print(const std::string& str, SubstrType subs)
{
    std::cout << '\'' << str << "' contains '" << subs << "': " <<
        str.contains(subs) << '\n';
}

int main()
{
    std::boolalpha(std::cout);
    auto helloWorld = std::string("hello world");

    test_substring_print(helloWorld, std::string_view("hello"));

    test_substring_print(helloWorld, std::string_view("goodbye"));

    test_substring_print(helloWorld, 'w');

    test_substring_print(helloWorld, 'x');
}

输出：

'hello world' contains 'hello': true
'hello world' contains 'goodbye': false
'hello world' contains 'w': true
'hello world' contains 'x': false

参阅

starts_with (C++20) | 检查 string 是否始于给定前缀 (公开成员函数)
ends_with (C++20) | 检查 string 是否终于给定后缀 (公开成员函数)
find | 于字符串中寻找字符 (公开成员函数)
substr | 返回子串 (公开成员函数)


std::basic_string<CharT,Traits,Allocator>::copy

< cpp‎ | string‎ | basic string
size_type copy( CharT* dest, size_type count, size_type pos = 0 ) const; | (C++20 前)
constexpr size_type copy( CharT* dest, size_type count, size_type pos = 0 ) const; | (C++20 起)

复制子串 [pos, pos+count) 到 dest 所指向的字符串。若请求的子串越过 string 结尾，或若 count == npos ，则复制的子串为 [pos, size()) 。产生的字符串不是空终止的。

若 pos > size() ，则抛出 std::out_of_range 。

参数

dest | - | 指向目标字符串的指针
count | - | 子串长度
pos | - | 包含的首字符位置

返回值

复制的字符数

异常

若 pos > size() 则为 std::out_of_range 。

复杂度

与 count 成线性

示例

#include <string>
#include <iostream>

int main()
{
  std::string foo("quuuux");
  char bar[7]{};
  foo.copy(bar, sizeof bar);
  std::cout << bar << '\n';
}

输出：

quuuux

参阅

substr
 返回子串
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::data

< cpp‎ | string‎ | basic string
 | (1)
const CharT* data() const; |  | (C++11 前)
const CharT* data() const noexcept; |  | (C++11 起) (C++20 前)
constexpr const CharT* data() const noexcept; |  | (C++20 起)
 | (2)
CharT* data() noexcept; |  | (C++17 起) (C++20 前)
constexpr CharT* data() noexcept; |  | (C++20 起)

返回指向作为字符存储工作的底层数组的指针。此指针满足范围 [data(); data() + size()) (C++11 前) [data(); data() + size()] (C++11 起) 为合法，且其中的值对应存储于字符串的值。

不要求返回的数组是空终止的。 若 empty() 返回 true ，则指针指向不应解引用的非空指针。 | (C++11 前)
返回的数组是空终止的，即 data() 与 c_str() 进行同一功能。 若 empty() 返回 true ，则指针指向单个空字符。 | (C++11 起)

指向 data() 的指针可能因以下情况非法：

  • 传递非 const 引用给任何标准库函数，或
  • 在 string 上调用非 const 成员函数，除了 operator[]() 、 at() 、 front() 、 back() 、 begin() 、 end() 、 rbegin() 、 rend() 。
1) 通过 data 的 const 重载修改数组有未定义行为。
2) 修改存储于 data() + size() 的尾后空终止符为任何异于 CharT() 的值有未定义行为。

参数

（无）

返回值

指向底层字符存储的指针。

对 [0, size()) 中每个 i 有 data()[i] == operator[](i) 。 | (C++11 前)
对 [0, size()] 中每个 i 有 data() + i == std::addressof (operator[](i)) 。 | (C++11 起)

复杂度

常数。

示例

#include <algorithm>
#include <cassert>
#include <cstring>
#include <string>

int main()
{
  std::string const s("Emplary");
  assert(s.size() == std::strlen(s.data()));
  assert(std::equal(s.begin(), s.end(), s.data()));
  assert(std::equal(s.data(), s.data() + s.size(), s.begin()));
  assert(0 == *(s.data() + s.size()));
}

参阅

front (C++11) | 访问首字符 (公开成员函数)
back (C++11) | 访问最后的字符 (公开成员函数)
c_str | 返回字符串的不可修改的 C 字符数组版本 (公开成员函数)


std::basic_string 的推导指引

< cpp‎ | string‎ | basic string
定义于头文件 <string>
template<class InputIt, class Alloc = std::allocator <

typename std::iterator_traits <InputIt>::value_type>>
basic_string(InputIt, InputIt, Alloc = Alloc())
-> basic_string<typename std::iterator_traits <InputIt>::value_type,
std::char_traits <typename std::iterator_traits <InputIt>::value_type>,

Alloc>;
 (1) (C++17 起)
template<class CharT,

class Traits,
class Alloc = std::allocator <CharT>>
explicit basic_string( std::basic_string_view <CharT, Traits>, const Alloc& = Alloc())

-> basic_string<CharT, Traits, Alloc>;
 (2) (C++17 起)
template<class CharT,

class Traits,
class Alloc = std::allocator <CharT>>>
basic_string( std::basic_string_view <CharT, Traits>, typename /*see below*/::size_type,
typename /*see below*/::size_type, const Alloc& = Alloc())

-> basic_string<CharT, Traits, Alloc>;
 (3) (C++17 起)
1) 为 std::basic_string 提供此推导指引，以允许从迭代器范围推导。此重载仅若 InputIt 满足老式输入迭代器 (LegacyInputIterator) 且 Alloc 满足分配器 (Allocator) 才参与重载决议。
2-3) 为 std::basic_string 提供这些推导指引以允许从 std::basic_string_view 推导。 (3) 中的size_type 参数指代推导指引所推出类型的 size_type 成员类型。这些重载仅若 Alloc 满足分配器 (Allocator) 才参与重载决议。

注意：库确定类型是否满足老式输入迭代器 (LegacyInputIterator) 的程度是未指定的，除了最低要求是整数类型不具备输入迭代器的条件。类似地，确定类型是否满足分配器 (Allocator) 是未指定的，除了最低要求是成员类型 Alloc::value_type 必须存在，且表达式 std::declval <Alloc&>().allocate( std::size_t {}) 在作为不求值操作数时必须为良构。

注解

需要指引 (2-3) ，因为 std::basic_string 对于 std::basic_string_view 的构造函数被设为模板，以避免既存代码中的歧义，而这些模板不支持类模板实参推导。

示例

#include <string>
#include <vector>
int main() {
   std::vector<char> v = {'a', 'b', 'c'};
   std::basic_string s(v.begin(), v.end()); // 使用显式推导指引
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3075 | C++17 | 不支持从 basic_string_view 推导（为 LWG 问题 2946 所恶化） | 添加推导指引


std::basic_string<CharT,Traits,Allocator>::empty

< cpp‎ | string‎ | basic string
bool empty() const; | (C++11 前)
bool empty() const noexcept; | (C++11 起) (C++20 前)
[[nodiscard]] constexpr bool empty() const noexcept; | (C++20 起)

检查 string 是否无字符，即是否 begin() == end() 。

参数

（无）

返回值

若 string 为空则为 true ，否则为 false 。

复杂度

常数。

示例

#include <iostream>
#include <string>

int main()
{
    std::string s;
    std::boolalpha(std::cout);
    std::cout << "s.empty():" << s.empty() << "\t s:'" << s << "'\n";

    s = "Exemplar";
    std::cout << "s.empty():" << s.empty() << "\t s:'" << s << "'\n";

    s = "";
    std::cout << "s.empty():" << s.empty() << "\t s:'" << s << "'\n";
}

输出：

s.empty():true  s:''
s.empty():false  s:'Exemplar'
s.empty():true   s:''

参阅

sizelength
 返回字符数
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::end, std::basic_string<CharT,Traits,Allocator>::cend

< cpp‎ | string‎ | basic string
 | (1)
iterator end(); |  | (C++11 前)
iterator end() noexcept; |  | (C++11 起) (C++20 前)
constexpr iterator end() noexcept; |  | (C++20 起)
 | (2)
const_iterator end() const; |  | (C++11 前)
const_iterator end() const noexcept; |  | (C++11 起) (C++20 前)
constexpr const_iterator end() const noexcept; |  | (C++20 起)
 | (3)
const_iterator cend() const noexcept; |  | (C++11 起) (C++20 前)
constexpr const_iterator cend() const noexcept; |  | (C++20 起)

返回指向后随字符串末字符的字符的迭代器。此字符表现为占位符，试图访问它导致未定义行为。

参数

（无）

返回值

指向后随尾字符的字符的迭代器

复杂度

常数

示例

#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>

int main()
{
    std::string s("Exemparl");
    std::next_permutation(s.begin(), s.end());

    std::string c;
    std::copy(s.cbegin(), s.cend(), std::back_inserter(c));
    std::cout << c <<'\n'; // "Exemplar"
}

输出：

Exemplar

参阅

begincbegin
(C++11)
 返回指向起始的迭代器
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::ends_with

< cpp‎ | string‎ | basic string
constexpr bool ends_with( std::basic_string_view <CharT,Traits> sv )
const noexcept;
 (1) (C++20 起)
constexpr bool ends_with( CharT c ) const noexcept;
 (2) (C++20 起)
constexpr bool ends_with( const CharT* s ) const;
 (3) (C++20 起)

检查 string 是否终于给定后缀。后缀可为以下之一：

1) string_view sv （可以是从另一 std::basic_string 隐式转换的结果）。
2) 单个字符 c
3) 空终止字符串 s

所有三个重载等效地返回 std::basic_string_view <CharT, Traits>(data(), size()).ends_with(x) ，其中 x 是参数。

参数

sv | - | string_view ，可为从另一 std::basic_string 隐式转换的结果
c | - | 单个字符
s | - | 空终止字符串

返回值

若 string 终于给定后缀则为 true ，否则为 false 。

示例

#include <iostream>
#include <string_view>
#include <string>

template <typename SuffixType>
void test_suffix_print(const std::string& str, SuffixType suffix)
{
    std::cout << '\'' << str << "' ends with '" << suffix << "': " <<
        str.ends_with(suffix) << '\n';
}

int main()
{
    std::boolalpha(std::cout);
    auto helloWorld = std::string("hello world");

    test_suffix_print(helloWorld, std::string_view("world"));

    test_suffix_print(helloWorld, std::string_view("goodby"));

    test_suffix_print(helloWorld, 'd');

    test_suffix_print(helloWorld, 'x');
}

输出：

'hello world' ends with 'world': true
'hello world' ends with 'goodby': false
'hello world' ends with 'd': true
'hello world' ends with 'x': false

参阅

starts_with (C++20) | 检查 string 是否始于给定前缀 (公开成员函数)
starts_with (C++20) | 检查 string_view 是否始于给定前缀 (std::basic_string_view<CharT,Traits> 的公开成员函数)
ends_with (C++20) | 检查 string_view 是否终于给定后缀 (std::basic_string_view<CharT,Traits> 的公开成员函数)
contains (C++23) | 检查字符串是否含有给定的子串或字符 (公开成员函数)
contains (C++23) | 检查字符串视图是否含有给定的子串或字符 (std::basic_string_view<CharT,Traits> 的公开成员函数)
compare | 比较二个字符串 (公开成员函数)
substr | 返回子串 (公开成员函数)


std::basic_string<CharT,Traits,Allocator>::erase

< cpp‎ | string‎ | basic string
 | (1)
basic_string& erase( size_type index = 0, size_type count = npos ); |  | (C++20 前)
constexpr basic_string& erase( size_type index = 0, size_type count = npos ); |  | (C++20 起)
 | (2)
iterator erase( iterator position ); |  | (C++11 前)
iterator erase( const_iterator position ); |  | (C++11 起) (C++20 前)
constexpr iterator erase( const_iterator position ); |  | (C++20 起)
 | (3)
iterator erase( iterator first, iterator last ); |  | (C++11 前)
iterator erase( const_iterator first, const_iterator last ); |  | (C++11 起) (C++20 前)
constexpr iterator erase( const_iterator first, const_iterator last ); |  | (C++20 起)

从 string 移除指定的字符。

1) 移除始于 index 的 min(count, size() - index) 个字符。
2) 移除位于 position 的字符。
3) 移除范围 [first, last) 中的字符。

参数

index | - | 要移除的首个字符
count | - | 要移除的字符数
position | - | 指向要移除的字符的迭代器
first, last | - | 要移除的字符范围

返回值

1) *this
2) 指向立即后随被擦除字符的迭代器，或若不存在这种字符则为 end()
3) 指向擦除前 last 所指向字符的迭代器，或若不存在这种字符则为 end()

异常

1) 若 index > size() 则为 std::out_of_range 。
2-3) 不抛出。

任何情况下，若因任何原因抛出异常，则此函数无效果（强异常保证）。 (C++11 起)

示例

#include <iostream>
#include <algorithm>
#include <string>

int main()
{
    std::string s = "This is an example";
    std::cout << s << '\n';

    s.erase(0, 5); // 擦除 "This "
    std::cout << s << '\n';

    s.erase(std::find(s.begin(), s.end(), ' ')); // 擦除 ' '
    std::cout << s << '\n';

    s.erase(s.find(' ')); // 从 ' ' 到字符串尾裁剪
    std::cout << s << '\n';
}

输出：

This is an example
is an example
isan example
isan

参阅

clear
 清除内容
(公开成员函数)


std::erase, std::erase_if (std::basic_string)

< cpp‎ | string‎ | basic string

定义于头文件 <string>
template< ..., class U >

constexpr typename std::basic_string <...>::size_type

erase( std::basic_string <...>& c, const U& value);
 (1) (C++20 起)
template< ..., class Pred >

constexpr typename std::basic_string <...>::size_type

erase_if( std::basic_string <...>& c, Pred pred);
 (2) (C++20 起)
1) 从容器中擦除所有比较等于 value 的元素。等价于
auto it = std::remove(c.begin(), c.end(), value);
auto r = std::distance(it, c.end());
c.erase(it, c.end());
return r;
2) 从容器中擦除所有满足 pred 的元素。等价于
auto it = std::remove_if(c.begin(), c.end(), pred);
auto r = std::distance(it, c.end());
c.erase(it, c.end());
return r;

参数

c | - | 要从中擦除的容器
value | - | 要擦除的值
pred | - | 若应该擦除元素则返回 ​true 的一元谓词。 对每个（可为 const 的） CharT 类型参数 v ，表达式 pred(v) 必须可转换为 bool ，无关乎值类别，而且必须不修改 v 。从而不允许 CharT& 类型参数，亦不允许 CharT ，除非对 CharT 而言移动等价于复制 (C++11 起)。 ​

返回值

被擦除的元素数。

复杂度

线性。

示例

#include <iostream>
#include <numeric>
#include <string>

void print_container(const std::string& c)
{
    for (auto x : c) {
        std::cout << x << ' ';
    }
    std::cout << '\n';
}

int main()
{
    std::string cnt(10, ' ');
    std::iota(cnt.begin(), cnt.end(), '0');

    std::cout << "Init:\n";
    print_container(cnt);

    auto erased = std::erase(cnt, '3');
    std::cout << "Erase \'3\':\n";
    print_container(cnt);

    std::erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; });
    std::cout << "Erase all even numbers:\n";
    print_container(cnt);
    std::cout << "In all " << erased << " even numbers were erased.\n";
}

输出：

Init:
0 1 2 3 4 5 6 7 8 9
Erase '3':
0 1 2 4 5 6 7 8 9
Erase all even numbers:
1 5 7 9
In all 5 even numbers were erased.

参阅

removeremove_if
 移除满足特定判别标准的元素
(函数模板)


std::basic_string<CharT,Traits,Allocator>::find

< cpp‎ | string‎ | basic string
 | (1)
size_type find( const basic_string& str, size_type pos = 0 ) const; |  | (C++11 前)
size_type find( const basic_string& str, size_type pos = 0 ) const noexcept; |  | (C++11 起) (C++20 前)
constexpr size_type find( const basic_string& str, size_type pos = 0 ) const noexcept; |  | (C++20 起)
 | (2)
size_type find( const CharT* s, size_type pos, size_type count ) const; |  | (C++20 前)
constexpr size_type find( const CharT* s, size_type pos, size_type count ) const; |  | (C++20 起)
 | (3)
size_type find( const CharT* s, size_type pos = 0 ) const; |  | (C++20 前)
constexpr size_type find( const CharT* s, size_type pos = 0 ) const; |  | (C++20 起)
 | (4)
size_type find( CharT ch, size_type pos = 0 ) const; |  | (C++11 前)
size_type find( CharT ch, size_type pos = 0 ) const noexcept; |  | (C++11 起) (C++20 前)
constexpr size_type find( CharT ch, size_type pos = 0 ) const noexcept; |  | (C++20 起)
 | (5)
template < class T > size_type find( const T& t, size_type pos = 0 ) const noexcept(/* see below */); |  | (C++17 起) (C++20 前)
template < class T > constexpr size_type find( const T& t, size_type pos = 0 ) const noexcept(/* see below */); |  | (C++20 起)

寻找首个等于给定字符序列的子串。搜索始于 pos ，即找到的子串必须不始于 pos 之前的位置。

1) 寻找等于 str 的首个子串。
2) 寻找等于范围 [s, s+count) 的首个子串。此范围能含空字符。
3) 寻找等于 s 所指向的字符串的首个子串。由首个空字符，用 Traits::length(s) 确定字符串长度。
4) 寻找首个字符 ch （由后述规则当作单字节子串）。
5) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后寻找等于字符串视图 sv 的首个子串。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。

正式而言，若下列全部为 true ，则说在位置 xpos 找到子串 str ：

  • xpos >= pos
  • xpos + str.size() <= size()
  • 对于 str 中所有位置 n ， Traits::eq(at(xpos+n), str.at(n))

特别是，这隐含

  • 仅若 pos <= size() - str.size() 才能找到子串
  • 在 pos 找到空子串，若且唯若 pos <= size()
  • 对于非空子串，若 pos >= size() ，则函数始终返回 npos 。

参数

str | - | 要搜索的 string
pos | - | 开始搜索的位置
count | - | 要搜索的子串长度
s | - | 指向要搜索的字符串的指针
ch | - | 要搜索的字符
t | - | 要搜索的对象（可转换为 std::basic_string_view ）

返回值

找到的子串的首字符位置，或若找不到这种子串则为 npos 。

异常

1,4) 不抛出。
5)
noexcept 说明：
noexcept(std::is_nothrow_convertible_v<const T&, std::basic_string_view <CharT, Traits>>)

示例

#include <string>
#include <iostream>

void print(std::string::size_type n, std::string const &s)
{
    if (n == std::string::npos) {
        std::cout << "not found\n";
    } else {
        std::cout << "found: " << s.substr(n) << '\n';
    }
}

int main()
{
    std::string::size_type n;
    std::string const s = "This is a string";

    // 从 string 开始搜索
    n = s.find("is");
    print(n, s);

    // 从位置 5 开始搜索
    n = s.find("is", 5);
    print(n, s);

    // 寻找单个字符
    n = s.find('a');
    print(n, s);

    // 寻找单个字符
    n = s.find('q');
    print(n, s);
}

输出：

found: is is a string
found: is a string
found: a string
not found

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2064 | C++11 | 重载 (3) 与 (4) 为 noexcept | 移除
LWG 2946 | C++17 | string_view 重载在某些情况下导致歧义 | 通过使之为模板来避免
P1148R0 | C++11 C++17 | 重载 (4)/(5) 的 noexcept 意外地被 LWG2064/LWG2946 丢弃 | 恢复

参阅

strstr | 寻找字符子串的首次出现 (函数)
wcsstr | 在另一宽字符串中寻找宽字符串的首次出现 (函数)
strchr | 寻找字符的首次出现 (函数)
wcschr | 寻找宽字符串中宽字符的首次出现 (函数)
rfind | 寻找子串的最后一次出现 (公开成员函数)
find_first_of | 寻找字符的首次出现 (公开成员函数)
find_first_not_of | 寻找字符的首次缺失 (公开成员函数)
find_last_of | 寻找字符的最后一次出现 (公开成员函数)
find_last_not_of | 寻找字符的最后一次缺失 (公开成员函数)
search | 搜索一个元素范围 (函数模板)


std::basic_string<CharT,Traits,Allocator>::find_first_not_of

< cpp‎ | string‎ | basic string
 | (1)
size_type find_first_not_of( const basic_string& str, size_type pos = 0 ) const; |  | (C++11 前)
size_type find_first_not_of( const basic_string& str, size_type pos = 0 ) const noexcept; |  | (C++11 起) (C++20 前)
constexpr size_type find_first_not_of( const basic_string& str, size_type pos = 0 ) const noexcept; |  | (C++20 起)
 | (2)
size_type find_first_not_of( const CharT* s, size_type pos, size_type count ) const; |  | (C++20 前)
constexpr size_type find_first_not_of( const CharT* s, size_type pos, size_type count ) const; |  | (C++20 起)
 | (3)
size_type find_first_not_of( const CharT* s, size_type pos = 0 ) const; |  | (C++20 前)
constexpr size_type find_first_not_of( const CharT* s, size_type pos = 0 ) const; |  | (C++20 起)
 | (4)
size_type find_first_not_of( CharT ch, size_type pos = 0 ) const; |  | (C++11 前)
size_type find_first_not_of( CharT ch, size_type pos = 0 ) const noexcept; |  | (C++11 起) (C++20 前)
constexpr size_type find_first_not_of( CharT ch, size_type pos = 0 ) const noexcept; |  | (C++20 起)
 | (5)
template < class T > size_type find_first_not_of( const T& t, size_type pos = 0 ) const noexcept(/* see below */); |  | (C++17 起) (C++20 前)
template < class T > constexpr size_type find_first_not_of( const T& t, size_type pos = 0 ) const noexcept(/* see below */); |  | (C++20 起)

寻找不等于给定字符序列中任何字符的首个字符。搜索只考虑区间 [pos, size()) 。若区间中不存在字符，则将返回 npos 。

1) 寻找不等于 str 中任何字符的首个字符。
2) 寻找不等于范围 [s, s+count) 中任何字符的首个字符。此范围能包含空字符。
3) 寻找不等于 s所指向的字符串中任何字符的首个字符。用 Traits::length(s) ，由首个空终止符确定字符串长度。
4) 寻找不等于 ch 的首个字符。
5) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后寻找不等于 sv 中任何字符的首个字符。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。

所有情况下，均调用 Traits::eq 检查相等性。

参数

str | - | 鉴别要搜索的字符的 string
pos | - | 搜索开始的位置
count | - | 鉴别要搜索的字符的字符串长度
s | - | 指向鉴别要搜索的字符的字符串的指针
ch | - | 鉴别要搜索的字符的字符
t | - | 鉴别要搜索的字符的对象（可转换为 std::basic_string_view ）

返回值

找到的字符的位置，或若找不到这种字符则为 npos 。

异常

5)
noexcept 说明：
noexcept(std::is_nothrow_convertible_v<const T&, std::basic_string_view <CharT, Ttraits>>)

示例

#include <string>
#include <iostream>

int main() {
    std::string to_search = "Some data with %MACROS to substitute";

    std::cout << "Before: " << to_search << '\n';

    auto pos = std::string::npos;
    while ((pos = to_search.find('%')) != std::string::npos) {
        // 宏名中容许大写字母、小写字母和数字
        const auto after = to_search.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                                       "abcdefghijklmnopqrstuvwxyz"
                                                       "0123456789", pos + 1);

        // 现在 to_search[pos] == '%' 而 to_search[after] == ' ' （在 'S' 后）

        if(after != std::string::npos)
            to_search.replace(pos, after - pos, "some very nice macros");
    }

    std::cout << "After: " << to_search << '\n';
}

输出：

Before: Some data with %MACROS to substitute
After: Some data with some very nice macros to substitute

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2064 | C++11 | 重载 (3) 与 (4) 为 noexcept | 移除
LWG 2946 | C++17 | string_view 重载在某些情况下导致歧义 | 通过使之为模板来避免
P1148R0 | C++11 C++17 | 重载 (4)/(5) 的 noexcept 意外地被 LWG2064/LWG2946 丢弃 | 恢复

参阅

find | 于字符串中寻找字符 (公开成员函数)
rfind | 寻找子串的最后一次出现 (公开成员函数)
find_first_of | 寻找字符的首次出现 (公开成员函数)
find_last_of | 寻找字符的最后一次出现 (公开成员函数)
find_last_not_of | 寻找字符的最后一次缺失 (公开成员函数)


std::basic_string<CharT,Traits,Allocator>::find_first_of

< cpp‎ | string‎ | basic string
 | (1)
size_type find_first_of( const basic_string& str, size_type pos = 0 ) const; |  | (C++11 前)
size_type find_first_of( const basic_string& str, size_type pos = 0 ) const noexcept; |  | (C++11 起) (C++20 前)
constexpr size_type find_first_of( const basic_string& str, size_type pos = 0 ) const noexcept; |  | (C++20 起)
 | (2)
size_type find_first_of( const CharT* s, size_type pos, size_type count ) const; |  | (C++20 前)
constexpr size_type find_first_of( const CharT* s, size_type pos, size_type count ) const; |  | (C++20 起)
 | (3)
size_type find_first_of( const CharT* s, size_type pos = 0 ) const; |  | (C++20 前)
constexpr size_type find_first_of( const CharT* s, size_type pos = 0 ) const; |  | (C++20 起)
 | (4)
size_type find_first_of( CharT ch, size_type pos = 0 ) const; |  | (C++11 前)
size_type find_first_of( CharT ch, size_type pos = 0 ) const noexcept; |  | (C++11 起) (C++20 前)
constexpr size_type find_first_of( CharT ch, size_type pos = 0 ) const noexcept; |  | (C++20 起)
 | (5)
template < class T > size_type find_first_of( const T& t, size_type pos = 0 ) const noexcept(/* see below */); |  | (C++17 起) (C++20 前)
template < class T > constexpr size_type find_first_of( const T& t, size_type pos = 0 ) const noexcept(/* see below */); |  | (C++20 起)

寻找等于给定字符序列中字符之一的首个字符。搜索只考虑区间 [pos, size()) 。若区间中不存在字符，则返回 npos 。

1) 寻找等于 str 中字符之一的首个字符。
2) 寻找等于范围 [s, s+count) 中字符中字符之一的首个字符。此范围能包含空字符。
3) 寻找等于 s 所指向的字符串中字符之一的首个字符。由首个空字符，用 Traits::length(s) 确定字符串长度。
4) 寻找等于 ch 的首个字符。
5) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后寻找等于 sv 中字符之一的首个字符。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。

参数

str | - | 鉴别要搜索的字符的 string
pos | - | 搜索开始的位置
count | - | 鉴别要搜索的字符的字符串长度
s | - | 指向鉴别要搜索的字符的字符串的指针
ch | - | 鉴别要搜索的字符的字符
t | - | 鉴别要搜索的字符的对象（可转换为 std::basic_string_view ）

返回值

找到的字符的位置，或若找不到这种字符则为 npos 。

异常

5)
noexcept 说明：
noexcept(std::is_nothrow_convertible_v<const T&, std::basic_string_view <CharT, Traits>>)

注解

用 Traits::eq() 进行比较。

示例

#include <iostream>
#include <string>

int main()
{
    // 被搜索的字符串
    const std::string str = "Hello World!";

    // 要搜索的字符串和字符
    const std::string search_str = "o";
    const char* search_cstr      = "Good Bye!";

    std::cout << str.find_first_of(search_str) << std::endl;
    std::cout << str.find_first_of(search_str, 5) << std::endl;
    std::cout << str.find_first_of(search_cstr) << std::endl;
    std::cout << str.find_first_of(search_cstr, 0, 4) << std::endl;

    // 当 'x' 不在 str 中时它将返回 std::string::npos
    std::cout << str.find_first_of('x') << '\n';
}

可能的输出：

4
7
1
4
18446744073709551615

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2064 | C++11 | 重载 (3) 与 (4) 为 noexcept | 移除
LWG 2946 | C++17 | string_view 重载在某些情况下导致歧义 | 通过使之为模板来避免
P1148R0 | C++11 C++17 | 重载 (4)/(5) 的 noexcept 意外地被 LWG2064/LWG2946 丢弃 | 恢复

参阅

find | 于字符串中寻找字符 (公开成员函数)
rfind | 寻找子串的最后一次出现 (公开成员函数)
find_first_not_of | 寻找字符的首次缺失 (公开成员函数)
find_last_of | 寻找字符的最后一次出现 (公开成员函数)
find_last_not_of | 寻找字符的最后一次缺失 (公开成员函数)
strspn | 返回仅由另一字节字符串中找到的字符组成的最大起始段的长度 (函数)


std::basic_string<CharT,Traits,Allocator>::find_last_not_of

< cpp‎ | string‎ | basic string
 | (1)
size_type find_last_not_of( const basic_string& str, size_type pos = npos ) const; |  | (C++11 前)
size_type find_last_not_of( const basic_string& str, size_type pos = npos ) const noexcept; |  | (C++11 起) (C++20 前)
constexpr size_type find_last_not_of( const basic_string& str, size_type pos = npos ) const noexcept; |  | (C++20 起)
 | (2)
size_type find_last_not_of( const CharT* s, size_type pos, size_type count ) const; |  | (C++20 前)
constexpr size_type find_last_not_of( const CharT* s, size_type pos, size_type count ) const; |  | (C++20 起)
 | (3)
size_type find_last_not_of( const CharT* s, size_type pos = npos ) const; |  | (C++20 前)
constexpr size_type find_last_not_of( const CharT* s, size_type pos = npos ) const; |  | (C++20 起)
 | (4)
size_type find_last_not_of( CharT ch, size_type pos = npos ) const; |  | (C++11 前)
size_type find_last_not_of( CharT ch, size_type pos = npos ) const noexcept; |  | (C++11 起) (C++20 前)
constexpr size_type find_last_not_of( CharT ch, size_type pos = npos ) const noexcept; |  | (C++20 起)
 | (5)
template < class T > size_type find_last_not_of( const T& t, size_type pos = npos ) const noexcept(/* see below */); |  | (C++17 起) (C++20 前)
template < class T > constexpr size_type find_last_not_of( const T& t, size_type pos = npos ) const noexcept(/* see below */); |  | (C++20 起)

寻找不等于给定字符序列中任何字符的最后字符。搜索只考虑区间 [0, pos] 。若区间中不存在这种字符，则返回 npos 。

1) 寻找不等于 str 中任何字符的最后字符。
2) 寻找不等于范围 [s, s+count) 中任何字符的最后字符。此范围能包含空字符。
3) 寻找不等于 s 所指向的字符串中任何字符的最后字符。用 Traits::length(s) 确定字符串长度。
4) 寻找不等于 ch 的最后字符。
5) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后寻找不等于 sv 中任何字符的最后字符。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。

所有情况下均调用 Traits::eq 检查相等性。

参数

str | - | 鉴别要搜索的字符的 string
pos | - | 搜索结束的位置
count | - | 鉴别要搜索的字符的字符串长度
s | - | 指向鉴别要搜索的字符的字符串的指针
ch | - | 鉴别要搜索的字符的字符
t | - | 鉴别要搜索的字符的对象（可转换为 std::basic_string_view ）

返回值

找到的字符位置，或若找不到这种字符则为 npos 。

异常

5)
noexcept 说明：
noexcept(std::is_nothrow_convertible_v<const T&, std::basic_string_view <charT, traits>>)

示例

#include <iostream>
#include <string>

void show_pos(const std::string& str, std::string::size_type found) {
    if (found != std::string::npos) {
        std::cout << "[" << found << "] = \'" << str[found] << "\'\n";
    } else {
        std::cout << "not found" "\n";
    }
}

int main()
{
    std::string str { "abc_123" };
    char const* skip_set { "0123456789" };
    std::string::size_type str_last_pos { std::string::npos };

    show_pos(str, str.find_last_not_of(skip_set)); // [3] = '_'

    str_last_pos = 2;
    show_pos(str, str.find_last_not_of(skip_set, str_last_pos)); // [2] = 'c'

    str_last_pos = 2;
    show_pos(str, str.find_last_not_of('c', str_last_pos)); // [1] = 'b'

    const char arr[] { '3', '4', '5' };
    show_pos(str, str.find_last_not_of(arr)); // [5] = '2'

    str_last_pos = 2;
    std::string::size_type skip_set_size{4};
    show_pos(str, str.find_last_not_of(skip_set,
                                       str_last_pos,
                                       skip_set_size)); // [2] = 'c'

    show_pos(str, str.find_last_not_of("abc")); // [6] = '3'

    str_last_pos = 2;
    show_pos(str, str.find_last_not_of("abc", str_last_pos)); // 找不到
}

输出：

[3] = '_'
[2] = 'c'
[1] = 'b'
[5] = '2'
[2] = 'c'
[6] = '3'
not found

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2064 | C++11 | 重载 (3) 与 (4) 为 noexcept | 移除
LWG 2946 | C++17 | string_view 重载在某些情况下导致歧义 | 通过使之为模板来避免
P1148R0 | C++11 C++17 | 重载 (4)/(5) 的 noexcept 意外地被 LWG2064/LWG2946 丢弃 | 恢复

示例

本节未完成
原因：暂无示例

参阅

find | 于字符串中寻找字符 (公开成员函数)
rfind | 寻找子串的最后一次出现 (公开成员函数)
find_first_of | 寻找字符的首次出现 (公开成员函数)
find_first_not_of | 寻找字符的首次缺失 (公开成员函数)
find_last_of | 寻找字符的最后一次出现 (公开成员函数)


std::basic_string<CharT,Traits,Allocator>::find_last_of

< cpp‎ | string‎ | basic string
 | (1)
size_type find_last_of( const basic_string& str, size_type pos = npos ) const; |  | (C++11 前)
constexpr size_type find_last_of( const basic_string& str, size_type pos = npos ) const noexcept; |  | (C++11 起) (C++20 前)
 | (2)
size_type find_last_of( const CharT* s, size_type pos, size_type count ) const; |  | (C++11 前)
constexpr size_type find_last_of( const CharT* s, size_type pos, size_type count ) const; |  | (C++11 起)
 | (3)
size_type find_last_of( const CharT* s, size_type pos = npos ) const; |  | (C++20 前)
constexpr size_type find_last_of( const CharT* s, size_type pos = npos ) const; |  | (C++20 起)
 | (4)
size_type find_last_of( CharT ch, size_type pos = npos ) const; |  | (C++11 前)
size_type find_last_of( CharT ch, size_type pos = npos ) const noexcept; |  | (C++11 起) (C++20 前)
constexpr size_type find_last_of( CharT ch, size_type pos = npos ) const noexcept; |  | (C++20 起)
 | (5)
template < class T > size_type find_last_of( const T& t, size_type pos = npos ) const noexcept(/* see below */); |  | (C++17 起) (C++20 前)
template < class T > constexpr size_type find_last_of( const T& t, size_type pos = npos ) const noexcept(/* see below */); |  | (C++20 起)

寻找等于给定字符序列中字符之一的最后字符。不指定准确的搜索算法。搜索只考虑区间 [0, pos] 。若区间中不存在这种字符，则返回 npos 。

1) 寻找等于 str 中字符之一的最后字符。
2) 寻找等于范围 [s, s+count) 中字符之一的最后字符。此范围能包含空字符。
3) 寻找等于 s 所指向的字符串中字符之一的最后字符。用 Traits::length(s) ，由首个空字符确定字符串长度。
4) 寻找等于 ch 的最后字符。
5) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后寻找等于 sv 中字符之一的最后字符。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。

所有情况下，均调用 Traits::eq 检查相等性。

参数

str | - | 鉴别要搜索的字符的 string
pos | - | 搜索结束的位置
count | - | 鉴别要搜索的字符的字符串长度
s | - | 指向鉴别要搜索的字符的字符串的指针
ch | - | 要搜索的字符
t | - | 鉴别要搜索的字符的对象（可转换为 std::basic_string_view ）

返回值

找到的字符位置，或若找不到这种字符则为 npos 。

异常

5)
noexcept 说明：
noexcept(std::is_nothrow_convertible_v<const T&, std::basic_string_view <CharT, Traits>>)

示例

#include<string>
#include<iostream>
int main()
{
    const std::string path="/root/config";
    auto const pos=path.find_last_of('/');
    const auto leaf=path.substr(pos+1);

    std::cout << leaf << '\n';
}

输出：

config

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2064 | C++11 | 重载 (3) 与 (4) 为 noexcept | 移除
LWG 2946 | C++17 | string_view 重载在某些情况下导致歧义 | 通过使之为模板来避免
P1148R0 | C++11 C++17 | 重载 (4)/(5) 的 noexcept 意外地被 LWG2064/LWG2946 丢弃 | 恢复

参阅

find | 于字符串中寻找字符 (公开成员函数)
rfind | 寻找子串的最后一次出现 (公开成员函数)
find_first_of | 寻找字符的首次出现 (公开成员函数)
find_first_not_of | 寻找字符的首次缺失 (公开成员函数)
find_last_not_of | 寻找字符的最后一次缺失 (公开成员函数)


std::basic_string<CharT,Traits,Allocator>::front

< cpp‎ | string‎ | basic string
CharT& front(); | (C++11 起) (C++20 前)
constexpr CharT& front(); | (C++20 起)
const CharT& front() const; | (C++11 起) (C++20 前)
constexpr const CharT& front() const; | (C++20 起)

返回到 string 中首字符的引用。若 empty() == true 则行为未定义。

参数

（无）

返回值

到首字符的引用，等价于 operator[](0) 。

复杂度

常数

示例

#include <iostream>
#include <string>

int main()
{
  {
    std::string s("Exemplary");
    char& f = s.front();
    f = 'e';
    std::cout << s << '\n'; // "exemplary"
  }

  {
    std::string const c("Exemplary");
    char const& f = c.front();
    std::cout << &f << '\n'; // "Exemplary"
  }
}

输出：

exemplary
Exemplary

参阅

back
(C++11)
 访问最后的字符
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::get_allocator

< cpp‎ | string‎ | basic string
allocator_type get_allocator() const; | (C++20 前)
constexpr allocator_type get_allocator() const; | (C++20 起)

返回与 string 关联的分配器。

参数

（无）

返回值

关联的分配器

复杂度

常数

参阅

allocator | 默认的分配器 (类模板)
allocator_traits (C++11) | 提供关于分配器类型的信息 (类模板)
uses_allocator (C++11) | 检查指定的类型是否支持使用分配器的构造 (类模板)


std::getline

< cpp‎ | string‎ | basic string
定义于头文件 <string>
template< class CharT, class Traits, class Allocator >

std::basic_istream <CharT,Traits>& getline( std::basic_istream <CharT,Traits>& input,
std::basic_string <CharT,Traits,Allocator>& str,

CharT delim );
 (1)
template< class CharT, class Traits, class Allocator >

std::basic_istream <CharT,Traits>& getline( std::basic_istream <CharT,Traits>&& input,
std::basic_string <CharT,Traits,Allocator>& str,

CharT delim );
 (1) (C++11 起)
template< class CharT, class Traits, class Allocator >

std::basic_istream <CharT,Traits>& getline( std::basic_istream <CharT,Traits>& input,

std::basic_string <CharT,Traits,Allocator>& str );
 (2)
template< class CharT, class Traits, class Allocator >

std::basic_istream <CharT,Traits>& getline( std::basic_istream <CharT,Traits>&& input,

std::basic_string <CharT,Traits,Allocator>& str );
 (2) (C++11 起)

getline 从输入流读取字符并将它们放进 string ：

1) 表现为无格式输入函数 (UnformattedInputFunction) ，除了不影响 input.gcount() 。构造并检查 sentry 对象后，进行下列操作：
1) 调用 str.erase()
2) 从 input 释出字符并后附它们到 str ，直至发生下列条件之一（按顺序检查）：
a) input 上的文件尾条件，该情况下， getline 设置 eofbit 。
b) 下个可用输入字符是 delim ，以 Traits::eq(c, delim) 测试，该情况下从 input 释出分隔字符，但不后附它到 str 。
c) 已经存储 str.max_size() 个字符，该情况下 getline 设置 failbit 并返回。
3) 若因任何原因（不是舍弃的分隔符）没有释出字符，则 getline 设置 failbit 并返回。
2) 同 getline(input, str, input.widen('\n')) ，即默认分隔符是换行符。

参数

input | - | 获取数据来源的流
str | - | 放置数据的目标 string
delim | - | 分隔字符

返回值

input

注解

消耗空白符分隔的输入（例如 int n; std::cin >> n; ）时，任何后随的空白符，包括换行符都会被留在流中。然后当切换到面向行的输入时，以 getline 取得的首行只会是该空白符。多数情况下这是不想要的行为，可能的解法包括：

  • 对 getline 的显式的额外初始调用
  • 以 std::cin >> std::ws 移除额外的空白符
  • 以 std::cin.ignore( std::numeric_limits < std::streamsize >::max(), '\n'); 忽略输入行上剩下的全部字符

示例

下列代码演示如何用 getline 函数读取用户输入以及如何逐行处理文件。

#include <string>
#include <iostream>
#include <sstream>

int main()
{
    // 问候用户
    std::string name;
    std::cout << "What is your name? ";
    std::getline(std::cin, name);
    std::cout << "Hello " << name << ", nice to meet you.\n";

    // 逐行读文件
    std::istringstream input;
    input.str("1\n2\n3\n4\n5\n6\n7\n");
    int sum = 0;
    for (std::string line; std::getline(input, line); ) {
        sum += std::stoi(line);
    }
    std::cout << "\nThe sum is: " << sum << "\n";
}

可能的输出：

What is your name? John Q. Public
Hello John Q. Public, nice to meet you.

The sum is 28

参阅

getline
 一直读并取走字符，直至找到给定字符
(std::basic_istream<CharT,Traits> 的公开成员函数)


std::hash (std::string, std::wstring, std::u16string, std::u32string, std::u8string, std::pmr::string, std::pmr::wstring, std::pmr::u16string, std::pmr::u32string, std::pmr::u8string)

< cpp‎ | string‎ | basic string
定义于头文件 <string>
template<> struct hash< std::string >;

template<> struct hash< std::wstring >;
template<> struct hash< std::u16string >;

template<> struct hash< std::u32string >;
 (C++11 起)
template<> struct hash< std::pmr::string >;

template<> struct hash< std::pmr::wstring >;
template<> struct hash< std::pmr::u16string >;

template<> struct hash< std::pmr::u32string >;
 (C++17 起)
template<> struct hash<std::u8string>;
template<> struct hash<std::pmr::u8string>;
 (C++20 起)

std::hash 对各种字符串类的模板特化允许用户获得字符串的哈希。

这些哈希等于对应 std::basic_string_view 类的哈希：若 S 是这些字符串类型之一， SV 是对应的字符串视图类型，而 s 是 S 类型的对象，则 std::hash <S>()(s) == std::hash <SV>()(SV(s)) 。

 (C++17 起)

示例

下列代码显示 string 上使用的散列函数的一种可能输出：

#include <iostream>
#include <string>
#include <string_view>
#include <functional>
#include <memory_resource>
using namespace std::literals;

int main()
{
    auto sv = "Stand back! I've got jimmies!"sv;
    std::string s(sv);
    std::pmr::string pmrs(sv); // 使用默认分配器

    std::cout << std::hash<std::string_view>{}(sv) << '\n';
    std::cout << std::hash<std::string>{}(s) << '\n';
    std::cout << std::hash<std::pmr::string>{}(pmrs) << '\n';
}

可能的输出：

3544599705012401047
3544599705012401047
3544599705012401047

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2978 | C++17 | 未启用 std::pmr::string 与其类似物的散列支持 | 已启用

参阅

hash (C++11) | 散列函数对象 (类模板)
std::hash<std::string_view>std::hash<std::wstring_view>std::hash<std::u8string_view>std::hash<std::u16string_view>std::hash<std::u32string_view> (C++17)(C++17)(C++20)(C++17)(C++17) | string_view 的散列支持 (类模板特化)


std::basic_string<CharT,Traits,Allocator>::insert

< cpp‎ | string‎ | basic string
 | (1)
basic_string& insert( size_type index, size_type count, CharT ch ); |  | (C++20 前)
constexpr basic_string& insert( size_type index, size_type count, CharT ch ); |  | (C++20 起)
 | (2)
basic_string& insert( size_type index, const CharT* s ); |  | (C++20 前)
constexpr basic_string& insert( size_type index, const CharT* s ); |  | (C++20 起)
 | (3)
basic_string& insert( size_type index, const CharT* s, size_type count ); |  | (C++20 前)
constexpr basic_string& insert( size_type index, const CharT* s, size_type count ); |  | (C++20 起)
 | (4)
basic_string& insert( size_type index, const basic_string& str ); |  | (C++20 前)
constexpr basic_string& insert( size_type index, const basic_string& str ); |  | (C++20 起)
 | (5)
basic_string& insert( size_type index, const basic_string& str, size_type index_str, size_type count ); |  | (C++14 前)
basic_string& insert( size_type index, const basic_string& str, size_type index_str, size_type count = npos); |  | (C++14 起) (C++20 前)
constexpr basic_string& insert( size_type index, const basic_string& str, size_type index_str, size_type count = npos); |  | (C++20 起)
 | (6)
iterator insert( iterator pos, CharT ch ); |  | (C++11 前)
iterator insert( const_iterator pos, CharT ch ); |  | (C++11 起) (C++20 前)
constexpr iterator insert( const_iterator pos, CharT ch ); |  | (C++20 起)
 | (7)
void insert( iterator pos, size_type count, CharT ch ); |  | (C++11 前)
iterator insert( const_iterator pos, size_type count, CharT ch ); |  | (C++11 起) (C++20 前)
constexpr iterator insert( const_iterator pos, size_type count, CharT ch ); |  | (C++20 起)
 | (8)
template< class InputIt > void insert( iterator pos, InputIt first, InputIt last ); |  | (C++11 前)
template< class InputIt > iterator insert( const_iterator pos, InputIt first, InputIt last ); |  | (C++11 起) (C++20 前)
template< class InputIt > constexpr iterator insert( const_iterator pos, InputIt first, InputIt last ); |  | (C++20 起)
 | (9)
iterator insert( const_iterator pos, std::initializer_list <CharT> ilist ); |  | (C++11 起) (C++20 前)
constexpr iterator insert( const_iterator pos, std::initializer_list <CharT> ilist ); |  | (C++20 起)
 | (10)
template < class T > basic_string& insert( size_type pos, const T& t ); |  | (C++17 起) (C++20 前)
template < class T > constexpr basic_string& insert( size_type pos, const T& t ); |  | (C++20 起)
 | (11)
template < class T > basic_string& insert( size_type index, const T& t, size_type index_str, size_type count = npos); |  | (C++17 起) (C++20 前)
template < class T > constexpr basic_string& insert( size_type index, const T& t, size_type index_str, size_type count = npos); |  | (C++20 起)

插入字符到 string 中。

1) 在位置 index 插入 count 个字符 ch 的副本。
2) 在位置 index 插入 s 所指向的空终止字符串。字符串的长度由首个空字符，用 Traits::length(s) 确定。
3) 在位置 index 插入范围 [s, s+count) 中的字符。范围能含有空字符。
4) 在位置 index 插入 string str 。
5) 在位置 index 插入由 str.substr(index_str, count) 获得的 string 。
6) 在 pos 所指向的字符前插入字符 ch 。
7) 在 pos 所指向的元素（若存在）前插入 count 个字符 ch 的副本。
8) 在 pos 所指向的元素（若存在）前插入来自范围 [first, last) 的元素。若 InputIt 不满足老式输入迭代器 (LegacyInputIterator) 则此重载不参与重载决议。 (C++11 起)
9) 在 pos 所指向的元素（若存在）前插入来自 initializer_list ilist 的字符。
10) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后如同用 insert(pos, sv.data(), sv.size()) ，在 pos 所指向的元素（若存在）前插入来自 sv 的元素。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。
11) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后在 pos 所指向的元素（若存在）前插入来自 sv 的子视图 [index_str, index_str+count) 的元素。若请求的子视图越过 sv 的末尾，或若 count == npos ，则作为结果的子视图是 [index_str, sv.size()) 。若 index_str > sv.size() 或若 index > size() ，则抛出 std::out_of_range 。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。

参数

index | - | 插入内容到的位置
pos | - | 将插入字符到其前的迭代器
ch | - | 要插入的字符
count | - | 要插入的字符数
s | - | 指向要插入的字符串的指针
str | - | 要插入的 string
first, last | - | 定义要插入字符的范围
index_str | - | string str 中要插入的首字符位置
ilist | - | 要插入的字符来源的 std::initializer_list
t | - | 要插入的字符来源对象（可转换为 std::basic_string_view ）
类型要求
- InputIt 必须满足老式输入迭代器 (LegacyInputIterator) 的要求。

返回值

1-5,10-11) *this
6-9) 指代首个被插入字符的迭代器，或若未插入字符则为 pos （ count == 0 或 ilist.size() == 0 或 first == last ）

异常

1-4, 10) 若 index > size() 则为 std::out_of_range 。
5) 若 index > size() 或若 index_str > str.size() 则抛出 std::out_of_range 。
11) 若 index > size() 或若 index_str > sv.size() 则抛出 std::out_of_range 。

所有情况下，若 size() + ins_count > max_size() 则抛出 std::length_error ，其中 ins_count 是将要插入的字符数。并且可能抛出 Allocator::allocate 所抛的任何异常。

任何情况下，若因任何原因抛异常，则此函数无效果（强异常保证）。

 (C++11 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2946 | C++17 | string_view 重载在某些情况下导致歧义 | 通过使之为模板来避免

示例

#include <cassert>
#include <iterator>
#include <string>
using namespace std::string_literals;
int main()
{
    std::string s = "xmplr";

    // insert(size_type index, size_type count, char ch)
    s.insert(0, 1, 'E');
    assert("Exmplr" == s);

    // insert(size_type index, const char* s)
    s.insert(2, "e");
    assert("Exemplr" == s);

    // insert(size_type index, string const& str)
    s.insert(6, "a"s);
    assert("Exemplar" == s);

    // insert(size_type index, string const& str,
    //     size_type index_str, size_type count)
    s.insert(8, " is an example string."s, 0, 14);
    assert("Exemplar is an example" == s);

    // insert(const_iterator pos, char ch)
    s.insert(s.cbegin() + s.find_first_of('n') + 1, ':');
    assert("Exemplar is an: example" == s);

    // insert(const_iterator pos, size_type count, char ch)
    s.insert(s.cbegin() + s.find_first_of(':') + 1, 2, '=');
    assert("Exemplar is an:== example" == s);

    // insert(const_iterator pos, InputIt first, InputIt last)
    {
        std::string seq = " string";
        s.insert(s.begin() + s.find_last_of('e') + 1,
            std::begin(seq), std::end(seq));
        assert("Exemplar is an:== example string" == s);
    }

    // insert(const_iterator pos, std::initializer_list<char>)
    s.insert(s.cbegin() + s.find_first_of('g') + 1, { '.' });
    assert("Exemplar is an:== example string." == s);
}

参阅

append | 后附字符到结尾 (公开成员函数)
push_back | 后附字符到结尾 (公开成员函数)


std::basic_string<CharT,Traits,Allocator>::max_size

< cpp‎ | string‎ | basic string
size_type max_size() const; | (C++11 前)
size_type max_size() const noexcept; | (C++11 起) (C++20 前)
constexpr size_type max_size() const noexcept; | (C++20 起)

返回 string 由于保有系统或库实现限制所能保有的最大元素数，即最大 string 的 std::distance (begin(), end()) 。

参数

（无）

返回值

最大字符数

复杂度

常数。

示例

#include <iostream>
#include <string>

int main()
{
    std::string s;
    std::cout << "Maximum size of a string is " << s.max_size() << "\n";
}

可能的输出：

Maximum size of a string is 4294967294

参阅

sizelength
 返回字符数
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::npos

< cpp‎ | string‎ | basic string
static const size_type npos = -1;

这是特殊值，等于 size_type 类型可表示的最大值。准确含义依赖于语境，但通常，期待 string 下标的函数以之为字符串尾指示器，返回 string 下标的函数以之为错误指示器。

注意

虽然定义使用 -1 ，由于有符号到无符号隐式转换，且 size_type 是无符号整数类型， npos 的值是其所能保有的最大正值。这是指定任何无符号类型的最大值的可移植方式。

示例

#include <iostream>
#include <bitset>
#include <string>

int main()
{
    // 若找不到内容则字符串搜索函数返回 npos
    std::string s = "test";
    if(s.find('a') == std::string::npos)
        std::cout << "no 'a' in 'test'\n";

    // 以字符串子集为参数的函数以 npos 为“所有到达终点的方式”指示器
    std::string s2(s, 2, std::string::npos);
    std::cout << s2 << '\n';

    std::bitset<5> b("aaabb", std::string::npos, 'a', 'b');
    std::cout << b << '\n';
}

输出：

no 'a' in 'test'
st
00011


std::literals::string_literals::operator""s

< cpp‎ | string‎ | basic string
定义于头文件 <string> |  |
 | (1) |
std::string operator""s(const char *str, std::size_t len); |  |  | (C++14 起) (C++20 前)
constexpr std::string operator""s(const char *str, std::size_t len); |  |  | (C++20 起)
constexpr std::u8string operator""s(const char8_t *str, std::size_t len); | (2) | (C++20 起)
 | (3) |
std::u16string operator""s(const char16_t *str, std::size_t len); |  |  | (C++14 起) (C++20 前)
constexpr std::u16string operator""s(const char16_t *str, std::size_t len); |  |  | (C++20 起)
 | (4) |
std::u32string operator""s(const char32_t *str, std::size_t len); |  |  | (C++14 起) (C++20 前)
constexpr std::u32string operator""s(const char32_t *str, std::size_t len); |  |  | (C++20 起)
 | (5) |
std::wstring operator""s(const wchar_t *str, std::size_t len); |  |  | (C++14 起) (C++20 前)
constexpr std::wstring operator""s(const wchar_t *str, std::size_t len); |  |  | (C++20 起)

创建所需类型的 string 字面量。

1) 返回 std::string {str, len}
2) 返回 std::u8string{str, len}
3) 返回 std::u16string {str, len}
4) 返回 std::u32string {str, len}
5) 返回 std::wstring {str, len}

参数

str | - | 指向无修饰字符数组字面量起始的指针
len | - | 无修饰字符数组字面量的长度

返回值

string 字面量。

注解

这些运算符定义于命名空间 std::literals::string_literals ，其中 literals 和 string_literals 都是内联命名空间。可通过 using namespace std::literals 、 using namespace std::string_literals 及 using namespace std::literals::string_literals 获取对这些运算符的访问。

std::chrono::duration 亦定义 operator""s ，以表示字面量的秒，但它是算术类型字面量： 10.0s 与 10s 是十秒，但 "10"s 是字符串。

示例

#include <string>
#include <iostream>

int main()
{
    using namespace std::string_literals;

    std::string s1 = "abc\0\0def";
    std::string s2 = "abc\0\0def"s;
    std::cout << "s1: " << s1.size() << " \"" << s1 << "\"\n";
    std::cout << "s2: " << s2.size() << " \"" << s2 << "\"\n";
}

可能的输出：

s1: 3 "abc"
s2: 8 "abcdef"

参阅

(构造函数) | 构造 basic_string (公开成员函数)
operator""sv (C++17) | 创建一个字符数组字面量的字符串视图 (函数)


std::operator+(std::basic_string)

< cpp‎ | string‎ | basic string
定义于头文件 <string>
template< class CharT, class Traits, class Alloc >

std::basic_string <CharT,Traits,Alloc>
operator+( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (1) (C++20 起为 constexpr)
template< class CharT, class Traits, class Alloc >

std::basic_string <CharT,Traits,Alloc>
operator+( const std::basic_string <CharT,Traits,Alloc>& lhs,

const CharT* rhs );
 (2) (C++20 起为 constexpr)
template<class CharT, class Traits, class Alloc>

std::basic_string <CharT,Traits,Alloc>
operator+( const std::basic_string <CharT,Traits,Alloc>& lhs,

CharT rhs );
 (3) (C++20 起为 constexpr)
template< class CharT, class Traits, class Alloc >

std::basic_string <CharT,Traits,Alloc>
operator+( const CharT* lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (4) (C++20 起为 constexpr)
template< class CharT, class Traits, class Alloc >

std::basic_string <CharT,Traits,Alloc>
operator+( CharT lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (5) (C++20 起为 constexpr)
template< class CharT, class Traits, class Alloc >

std::basic_string <CharT,Traits,Alloc>
operator+( std::basic_string <CharT,Traits,Alloc>&& lhs,

std::basic_string <CharT,Traits,Alloc>&& rhs );
 (6) (C++11 起)
(C++20 起为 constexpr)
template< class CharT, class Traits, class Alloc >

std::basic_string <CharT,Traits,Alloc>
operator+( std::basic_string <CharT,Traits,Alloc>&& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (7) (C++11 起)
(C++20 起为 constexpr)
template< class CharT, class Traits, class Alloc >

std::basic_string <CharT,Traits,Alloc>
operator+( std::basic_string <CharT,Traits,Alloc>&& lhs,

const CharT* rhs );
 (8) (C++11 起)
(C++20 起为 constexpr)
template< class CharT, class Traits, class Alloc >

std::basic_string <CharT,Traits,Alloc>
operator+( std::basic_string <CharT,Traits,Alloc>&& lhs,

CharT rhs );
 (9) (C++11 起)
(C++20 起为 constexpr)
template< class CharT, class Traits, class Alloc >

std::basic_string <CharT,Traits,Alloc>
operator+( const std::basic_string <CharT,Traits,Alloc>& lhs,

std::basic_string <CharT,Traits,Alloc>&& rhs );
 (10) (C++11 起)
(C++20 起为 constexpr)
template< class CharT, class Traits, class Alloc >

std::basic_string <CharT,Traits,Alloc>
operator+( const CharT* lhs,

std::basic_string <CharT,Traits,Alloc>&& rhs );
 (11) (C++11 起)
(C++20 起为 constexpr)
template< class CharT, class Traits, class Alloc >

std::basic_string <CharT,Traits,Alloc>
operator+( CharT lhs,

std::basic_string <CharT,Traits,Alloc>&& rhs );
 (12) (C++11 起)
(C++20 起为 constexpr)

返回含有来自 lhs 的字符后随来自 rhs 的字符的字符串。

结果所用的分配器为：

1-3) std::allocator_traits <Alloc>::select_on_container_copy_construction(lhs.get_allocator())
4-5) std::allocator_traits <Alloc>::select_on_container_copy_construction(rhs.get_allocator())
6-9) lhs.get_allocator()
10-12) rhs.get_allocator()

换言之，若运算数之一是 basic_string 右值，则使用其分配器；否则在左值 basic_string 运算数的分配上使用 select_on_container_copy_construction 。每种情况下，当两者是拥有同一值类别的 basic_string 时，偏向左运算数。

(6-12) 将所有右值 basic_string 运算数置于合法但未指定的状态。

 (C++11 起)

参数

lhs | - | string 、字符或指向空终止字符序列首字符的指针
rhs | - | string 、字符或指向空终止字符序列首字符的指针

返回值

含有来自 lhs 的字符后随来自 rhs 的字符的字符串，使用指定如上的分配器 (C++11 起)。

注解

涉及有状态分配器时（例如用 std::pmr::string 时） (C++17 起)，应该谨慎使用 operator+ 。在 P1165R1 前，确定结果所用的分配器是历史事故，而且能在重载间无显著理由地变化。另外，对于 (1-5) ，分配器传播行为在主流标准库实现间各异，且异于标准所描述的行为。

operator+ 的结果所用的分配器对值类别敏感，故 operator+ 相对于分配器传播不满足结合律：

using my_string = std::basic_string<char, std::char_traits<char>, my_allocator<char>>;
my_string cat();
const my_string& dog();

my_string meow = /* ... */, woof = /* ... */;
meow + cat() + /*...*/; // 使用 meow 的分配器上的 select_on_container_copy_construction
woof + dog() + /*...*/; // 转而使用 dog() 的返回值的分配器

meow + woof + meow; // 使用 meow 的分配器上的 SOCCC
meow + (woof + meow); // 转而使用 woof 的分配器上的 select_on_container_copy_construction

对于 operator+ 链的调用，可通过前置拥有所欲分配器的右值 basic_string 控制最终结果所用的分配器：

// 令最终结果使用 my_favorite_allocator
my_string(my_favorite_allocator) + meow + woof + cat() + dog();

为了在分配器上更好且可移植地控制，应该在以所欲分配器构造的结果字符串上，使用 append() 、 insert() 及 operator+=() 之类的成员函数。

 (C++11 起)

示例

#include <iostream>
#include <string>

int main()
{
    std::string s1 = "Hello";
    std::string s2 = "world";
    std::cout << s1 + ' ' + s2 + "!\n";
}

输出：

Hello world!

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P1165R1 | C++11 | 分配器传播混乱且不一致 | 使之更为一致

参阅

operator+= | 后附字符到结尾 (公开成员函数)
append | 后附字符到结尾 (公开成员函数)
insert | 插入字符 (公开成员函数)


std::basic_string<CharT,Traits,Allocator>::operator+=

< cpp‎ | string‎ | basic string
 | (1)
basic_string& operator+=( const basic_string& str ); |  | (C++20 前)
constexpr basic_string& operator+=( const basic_string& str ); |  | (C++20 起)
 | (2)
basic_string& operator+=( CharT ch ); |  | (C++20 前)
constexpr basic_string& operator+=( CharT ch ); |  | (C++20 起)
 | (3)
basic_string& operator+=( const CharT* s ); |  | (C++20 前)
constexpr basic_string& operator+=( const CharT* s ); |  | (C++20 起)
 | (4)
basic_string& operator+=( std::initializer_list <CharT> ilist ); |  | (C++11 起) (C++20 前)
constexpr basic_string& operator+=( std::initializer_list <CharT> ilist ); |  | (C++20 起)
 | (5)
template < class T > basic_string& operator+=( const T& t ); |  | (C++17 起) (C++20 前)
template < class T > constexpr basic_string& operator+=( const T& t ); |  | (C++20 起)

后附额外字符到字符串。

1) 后附 string str 。
2) 后附字符 ch 。
3) 后附 s 所指向的空终止字符串。
4) 后附 initializer_list ilist 中的字符。
5) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后后附字符串视图 sv 中的字符，如同用 append(sv) 。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。

参数

str | - | 要后附的 string
ch | - | 要后附的字符值
s | - | 指向要后附的空终止字符串的指针
ilist | - | 拥有要后附的字符的 std::initializer_list
t | - | 拥有要后附的字符的（可转换为 std::basic_string_view ）的对象

返回值

*this

复杂度

无标准复杂度保证，典型实现表现类似 std::vector::insert 。

异常

若因任何原因抛出异常，则此函数无效果（强异常保证）。 (C++11 起)

若操作会导致 size() > max_size() ，则抛出 std::length_error 。

注解

重载 (2) 能接受任何可隐式转换为 CharT 的类型。对于 CharT 为 char 的 std::string ，可接受类型的集合包含任何算术类型。这可能拥有非意图的效果。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2946 | C++17 | string_view 重载在某些情况下导致歧义 | 通过使之为模板来避免

示例

#include <iostream>
#include <iomanip>
#include <string>

int main()
{
   std::string str;
   str.reserve(50); // 预留足够的存储空间以避免内存分配
   std::cout << std::quoted(str) << '\n'; // 空字符串

   str += "This";
   std::cout << std::quoted(str) << '\n';

   str += std::string(" is ");
   std::cout << std::quoted(str) << '\n';

   str += 'a';
   std::cout << std::quoted(str) << '\n';

   str += {' ','s','t','r','i','n','g','.'};
   std::cout << std::quoted(str) << '\n';

   str += 76.85; // 等价于 str += static_cast<char>(76.85) ，可能不合意图
   std::cout << std::quoted(str) << '\n';
}

输出：

""
"This"
"This is "
"This is a"
"This is a string."
"This is a string.L"

参阅

append
 后附字符到结尾
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::operator=

< cpp‎ | string‎ | basic string
 | (1) |
basic_string& operator=( const basic_string& str ); |  |  | (C++20 前)
constexpr basic_string& operator=( const basic_string& str ); |  |  | (C++20 起)
 | (2) |
basic_string& operator=( basic_string&& str ); |  |  | (C++11 起) (C++17 前)
basic_string& operator=( basic_string&& str ) noexcept(/* see below */); |  |  | (C++17 起) (C++20 前)
constexpr basic_string& operator=( basic_string&& str ) noexcept(/* see below */); |  |  | (C++20 起)
 | (3) |
basic_string& operator=( const CharT* s ); |  |  | (C++20 前)
constexpr basic_string& operator=( const CharT* s ); |  |  | (C++20 起)
 | (4) |
basic_string& operator=( CharT ch ); |  |  | (C++20 前)
constexpr basic_string& operator=( CharT ch ); |  |  | (C++20 起)
 | (5) |
basic_string& operator=( std::initializer_list <CharT> ilist ); |  |  | (C++11 起) (C++20 前)
constexpr basic_string& operator=( std::initializer_list <CharT> ilist ); |  |  | (C++20 起)
 | (6) |
template<class T> basic_string& operator=( const T& t ); |  |  | (C++17 起) (C++20 前)
template<class T> constexpr basic_string& operator=( const T& t ); |  |  | (C++20 起)
constexpr basic_string& operator=( std::nullptr_t ) = delete; | (7) | (C++23 起)

替换字符串的内容。

1) 以 str 的副本替换内容。若 *this 与 str 为同一对象，则此函数无效果。
2) 用移动语义以 str 的内容替换内容。之后 str 在合法但未指定的状态。若 std::allocator_traits <Allocator>::propagate_on_container_move_assignment::value 为 true ，则以 str 的分配器副本替换 *this 的。若它为 false 且 *this 与 str 的分配器不比较相等，则 *this 不能接收 str 所拥有的内存的所有权，而必须逐个字符赋值，用其自身的分配器按需分配额外内存。不同于其他容器移动赋值，指向 str 的引用、指针和迭代器可能被无效化。
3) 以 s 所指向的空终止字符串的内容替换内容，如同用 assign(s, Traits::length(s)) 。
4) 以字符 ch 的内容替换内容，如同用 assign( std::addressof (ch), 1) 。
5) 以 initializer_list ilist 的内容替换内容，如同用 assign(ilist.begin(), ilist.size()) 。
6) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后如同用 assign(sv) ，以 sv 的内容替换内容。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。
7) 不能将 nullptr 赋值给 basic_string 。

参数

ch | - | 用以初始化 string 的字符
str | - | 用作源初始化 string 的 string
s | - | 指向空终止字符串的指针，用作源初始化 string
init | - | 用作源初始化 string 的 std::initializer_list
t | - | 可转换为用以初始化 string 的 std::basic_string_view 的对象

返回值

*this

复杂度

1) 与 str 的大小成线性。
2) 与 *this 的大小成线性（正式而言，必须销毁每个 CharT ）。若分配器比较不相等且不传播，则亦与 str 的大小成线性（必须进行复制）。
3) 与 s 的大小成线性。
4) 常数。
5) 与 init 的大小成线性。

异常

2)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::propagate_on_container_move_assignment::value
|| std::allocator_traits <Allocator>::is_always_equal::value)
 (C++17 起)

若操作将导致 size() > max_size() ，则抛出 std::length_error 。

若因任何原因抛异常，则此函数无效果（强异常保证）。

 (C++11 起)

示例

#include <string>
#include <iostream>
#include <iomanip>

int main()
{
    std::string str1;
    std::string str2 { "alpha" };

    // (1) operator=( const basic_string& );
    str1 = str2;
    std::cout << std::quoted(str1) << ' ' // "alpha"
              << std::quoted(str2) << '\n'; // "alpha"

    // (2) operator=( basic_string&& );
    str1 = std::move(str2);
    std::cout << std::quoted(str1) << ' ' // "alpha"
              << std::quoted(str2) << '\n'; // "" 或 "alpha" （未指定）

    // (3) operator=( const CharT* );
    str1 = "beta";
    std::cout << std::quoted(str1) << '\n'; // "beta"

    // (4) operator=( CharT );
    str1 = '!';
    std::cout << std::quoted(str1) << '\n'; // "!"

    // (5) operator=( std::initializer_list<CharT> );
    str1 = {'g','a','m','m','a'};
    std::cout << std::quoted(str1) << '\n'; // "gamma"

    // (6) operator=( const T& );
    str1 = 35U; // equivalent to str1 = static_cast<char>(35U);
    std::cout << std::quoted(str1) << '\n'; // "#" (ASCII = 35)
}

可能的输出：

"alpha" "alpha"
"alpha" ""
"beta"
"!"
"gamma"
"#"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2063 | C++11 | 非规范性注释曾说交换是移动赋值的合法实现 | 更正以支持分配器
LWG 2946 | C++17 | string_view 重载在某些情况下导致歧义 | 通过使之为模板来避免

参阅

(构造函数) | 构造 basic_string (公开成员函数)
assign | 赋值字符给字符串 (公开成员函数)
operator= | 对视图赋值 (std::basic_string_view<CharT,Traits> 的公开成员函数)


std::basic_string<CharT,Traits,Allocator>::operator[]

< cpp‎ | string‎ | basic string
 | (1)
reference operator[]( size_type pos ); |  | (C++20 前)
constexpr reference operator[]( size_type pos ); |  | (C++20 起)
 | (2)
const_reference operator[]( size_type pos ) const; |  | (C++20 前)
constexpr const_reference operator[]( size_type pos ) const; |  | (C++20 起)

返回到位于指定位置 pos 的字符的引用。不进行边界检查。若 pos > size() ，则行为未定义。

1) 若 pos == size() ，则行为未定义。 2) 若 pos == size() ，则返回到拥有值 CharT() 的字符（空字符）的引用。 | (C++11 前)
若 pos == size() ，则返回到拥有值 CharT() 的字符（空字符）的引用。 对于第一（非 const 版本），若修改此字符为任何异于 CharT() 的值，则行为未定义。 | (C++11 起)

参数

pos - 要返回的字符位置

返回值

到请求字符的引用。

复杂度

常数

示例

#include <iostream>
#include <string>

int main()
{
    std::string const e("Exemplar");
    for (unsigned i = e.length() - 1; i != 0; i /= 2)
        std::cout << e[i];
    std::cout << '\n';

    const char* c = &e[0];
    std::cout << c << '\n'; // 作为 C 字符串打印

    // 更改 s 的最后字符为 'y'
    std::string s("Exemplar ");
    s[s.size()-1] = 'y';
    std::cout << s << '\n';
}

输出：

rmx
Exemplar
Exemplary

参阅

at
 访问指定字符，有边界检查
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::operator basic_string_view

< cpp‎ | string‎ | basic string
operator std::basic_string_view <CharT, Traits>() const noexcept; | (C++17 起) (C++20 前)
constexpr operator std::basic_string_view <CharT, Traits>() const noexcept; | (C++20 起)

返回如同用 std::basic_string_view <CharT, Traits>(data(), size()) 构造的 std::basic_string_view 。

参数

（无）

返回值

表示整个字符串内容的字符串视图。

注解

程序员负责确保返回的字符串视图不会生存超过字符串的生存期。

std::string get_string();
int f(std::string_view sv);

int x = f(get_string()); // OK
std::string_view sv = get_string(); // 坏：保有悬垂指针

示例

#include <iostream>
#include <string>
#include <string_view>

void show_wstring_size(std::wstring_view wcstr_v)
{
  std::cout << wcstr_v.size() << " code points\n";
}

int main()
{
  std::string cppstr = "ラーメン";   // 窄字符串
  std::wstring wcstr = L"ラーメン";  // 宽字符串

  // 从 string 隐式转换到 string_view
  // 经由 std::string::operator string_view ：
  std::string_view cppstr_v = cppstr;

  std::cout << cppstr_v << '\n'
            << cppstr_v.size() << " code units\n";

  // 从 wstring 隐式转换到 wstring_view
  // 经由 std::wstring::operator wstring_view ：
  show_wstring_size(wcstr);
}

输出：

ラーメン
12 code units
4 code points

参阅

(构造函数)
 构造 basic_string_view
(std::basic_string_view<CharT,Traits> 的公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::basic_string)

< cpp‎ | string‎ | basic string
定义于头文件 <string>
比较二个 basic_string 对象
(1)
template< class CharT, class Traits, class Alloc >

bool operator==( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (C++11 前)
template< class CharT, class Traits, class Alloc >

bool operator==( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs ) noexcept;
 (C++11 起)
(C++20 前)
template< class CharT, class Traits, class Alloc >

constexpr bool
operator==( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs ) noexcept;
 (C++20 起)
(2)
template< class CharT, class Traits, class Alloc >

bool operator!=( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (C++11 前)
template< class CharT, class Traits, class Alloc >

bool operator!=( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs ) noexcept;
 (C++11 起)
(C++20 前)
(3)
template< class CharT, class Traits, class Alloc >

bool operator<( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (C++11 前)
template< class CharT, class Traits, class Alloc >

bool operator<( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs ) noexcept;
 (C++11 起)
(C++20 前)
(4)
template< class CharT, class Traits, class Alloc >

bool operator>=( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (C++11 前)
template< class CharT, class Traits, class Alloc >

bool operator>=( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs ) noexcept;
 (C++11 起)
(C++20 前)
(5)
template< class CharT, class Traits, class Alloc >

bool operator>( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (C++11 前)
template< class CharT, class Traits, class Alloc >

bool operator>( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs ) noexcept;
 (C++11 起)
(C++20 前)
(6)
template< class CharT, class Traits, class Alloc >

bool operator>=( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (C++11 前)
template< class CharT, class Traits, class Alloc >

bool operator>=( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs ) noexcept;
 (C++11 起)
(C++20 前)
template< class CharT, class Traits, class Alloc >

constexpr /*comp-cat*/
operator<=>( const std::basic_string <CharT,Traits,Alloc>& lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs ) noexcept;
 (7) (C++20 起)
比较一个 basic_string 与 T 的空终止数组
(8)
template< class CharT, class Traits, class Alloc >

bool operator==( const std::basic_string <CharT,Traits,Alloc>& lhs,

const CharT* rhs );
 (C++20 前)
template< class CharT, class Traits, class Alloc >

constexpr bool operator==( const std::basic_string <CharT,Traits,Alloc>& lhs,

const CharT* rhs );
 (C++20 起)
template< class CharT, class Traits, class Alloc >

bool operator==( const CharT* lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (C++20 前)
(9)
template< class CharT, class Traits, class Alloc >

bool operator!=( const std::basic_string <CharT,Traits,Alloc>& lhs,

const CharT* rhs );
 (C++20 前)
template< class CharT, class Traits, class Alloc >

bool operator!=( const CharT* lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (C++20 前)
(10)
template< class CharT, class Traits, class Alloc >

bool operator<( const std::basic_string <CharT,Traits,Alloc>& lhs,

const CharT* rhs );
 (C++20 前)
template< class CharT, class Traits, class Alloc >

bool operator<( const CharT* lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (C++20 前)
(11)
template< class CharT, class Traits, class Alloc >

bool operator<=( const std::basic_string <CharT,Traits,Alloc>& lhs,

const CharT* rhs );
 (C++20 前)
template< class CharT, class Traits, class Alloc >

bool operator<=( const CharT* lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (C++20 前)
(12)
template< class CharT, class Traits, class Alloc >

bool operator>( const std::basic_string <CharT,Traits,Alloc>& lhs,

const CharT* rhs );
 (C++20 前)
template< class CharT, class Traits, class Alloc >

bool operator>( const CharT* lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (C++20 前)
(13)
template< class CharT, class Traits, class Alloc >

bool operator>=( const std::basic_string <CharT,Traits,Alloc>& lhs,

const CharT* rhs );
 (C++20 前)
template< class CharT, class Traits, class Alloc >

bool operator>=( const CharT* lhs,

const std::basic_string <CharT,Traits,Alloc>& rhs );
 (C++20 前)
template< class CharT, class Traits, class Alloc >

constexpr /*comp-cat*/
operator<=>( const std::basic_string <CharT,Traits,Alloc>& lhs,

const CharT* rhs );
 (14) (C++20 起)

比较 string 与另一 string 或 CharT 的空终止数组的内容。

所有比较通过 compare() 成员函数进行（它自身以 Traits::compare() 定义）：

  • 若 lhs 与 rhs 的大小相等，且 lhs 中的每个字符有在 rhs 中在同一位置的等价字符，则二个字符串相等。
  • 顺序比较按字典序——以等价于 std::lexicographical_compare 或 std::lexicographical_compare_three_way (C++20 起)的函数进行比较。
1-7) 比较二个 basic_string 对象。
8-14) 比较 basic_string 对象和 CharT 的空终止数组。

三路比较运算符的返回类型（ /*comp-cat*/ ）为 Traits::comparison_category ，若该有限定标识合法并指代类型，否则为 std::weak_ordering 。若 /*comp-cat*/ 不是比较类别类型，则程序非良构。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较内容的字符串

返回值

1-6,8-13) 若对应比较关系成立则为 true ，否则为 false 。
7,14) static_cast</*comp-cat*/>(lhs.compare(rhs) <=> 0) 。

复杂度

与字符串大小成线性。

注解

若至少一个参数拥有类型 std::string 、 std::wstring 、 std::u8string 、 std::u16string 或 std::u32string ，则 operator<=> 的返回类型是 std::strong_ordering 。

 (C++20 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2064 | C++11 | 接收二个 basic_string 的重载是否为 noexcept 不一致； 接收一个 CharT* 的重载为 noexcept 但可能引发 UB | 使之一致； 移除 noexcept
LWG 3432 | C++20 | 未要求 operator<=> 的返回类型为比较类别类型 | 已要求


operator<<,>>(std::basic_string)

< cpp‎ | string‎ | basic string
定义于头文件 <string>
template <class CharT, class Traits, class Allocator>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

const std::basic_string <CharT, Traits, Allocator>& str);
 (1)
template <class CharT, class Traits, class Allocator>

std::basic_istream <CharT, Traits>&
operator>>( std::basic_istream <CharT, Traits>& is,

std::basic_string <CharT, Traits, Allocator>& str);
 (2)

1) 表现为有格式输出函数 (FormattedOutputFunction) 。构造并检查 sentry 对象后，以如下方式确定输出格式填充：

a) 若 str.size() 不小于 os.width() ，则原样地使用范围 [str.begin(), str.end())
b) 否则，若 (os.flags() & ios_base::adjustfield) == ios_base::left ，则放置 os.width()-str.size() 个 os.fill() 字符的副本到字符序列后
c) 否则，放置 os.width()-str.size() 个 os.fill() 字符副本到字符序列前

然后存储每个来自结果序列（ str 的内容加上填充）到输出流 os ，如同通过调用 os.rdbuf()->sputn(seq, n) ，其中 n= std::max (os.width(), str.size())

最后，调用 os.width(0) 取消 std::setw 的效果，若存在。

2) 表现为有格式输入函数 (FormattedInputFunction) 。构造并检查 sentry 对象，这可能跳过前导空白符，然后首先以 str.erase() 清除 str ，然后从 is 读取字符并后附它们到 str ，如同用 str.append(1, c) ，直至下列条件之一变为真：

  • 读取了 N 个字符，其中若 is.width() > 0 则 N 为 is.width() ，否则 N 为 str.max_size()
  • 流 is 中出现文件尾条件
  • std::isspace(c,is.getloc()) 对 is 中的下个字符 c 为 true （空白符留在输入流中）。

若未释出字符，则设置 is 上的 std::ios::failbit ，这可能抛出 std::ios_base::failure 。

最后，调用 is.width(0) 取消 std::setw 的效果，若存在。

异常

1) 若输出中抛出异常则可能抛出 std::ios_base::failure 。

2) 若未从 is 释出字符（例如流在文件尾或仅有空白符组成），或若输入中抛出异常则可能抛出 std::ios_base::failure 。

参数

os | - | 字符输出流
is | - | 字符输入流
str | - | 插入或释出的字符串

返回值

1) os

2) is

示例

#include <iostream>
#include <string>
#include <sstream>

int main()
{
    std::string greeting = "Hello, whirled!";
    std::istringstream is(greeting);
    std::string hello_comma;
    is >> hello_comma;
    std::cout << greeting << '\n' << hello_comma << '\n';
}

输出：

Hello, whirled!
Hello,


std::basic_string<CharT,Traits,Allocator>::pop_back

< cpp‎ | string‎ | basic string
void pop_back(); | (C++11 起) (C++20 前)
constexpr void pop_back(); | (C++20 起)

从字符串移除末字符。

等价于 erase(end() - 1, 1) 。若字符串为空则行为未定义。

参数

（无）

返回值

（无）

复杂度

常数。

异常

不抛出。

参阅

push_back | 后附字符到结尾 (公开成员函数)
erase | 移除字符 (公开成员函数)


std::basic_string<CharT,Traits,Allocator>::push_back

< cpp‎ | string‎ | basic string
void push_back( CharT ch ); | (C++20 前)
constexpr void push_back( CharT ch ); | (C++20 起)

后附给定字符 ch 到字符串尾。

参数

ch - 要后附的字符

返回值

（无）

复杂度

均摊常数。

异常

若因任何原因抛出异常，则此函数无效果（强异常保证）。 (C++11 起)

若操作将导致 size() > max_size() ，则抛出 std::length_error 。

参阅

pop_back
(C++11)
 移除末尾字符
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::rbegin, std::basic_string<CharT,Traits,Allocator>::crbegin

< cpp‎ | string‎ | basic string
 | (1)
reverse_iterator rbegin(); |  | (C++11 前)
reverse_iterator rbegin() noexcept; |  | (C++11 起) (C++20 前)
constexpr reverse_iterator rbegin() noexcept; |  | (C++20 起)
 | (2)
const_reverse_iterator rbegin() const; |  | (C++11 前)
const_reverse_iterator rbegin() const noexcept; |  | (C++11 起) (C++20 前)
constexpr const_reverse_iterator rbegin() const noexcept; |  | (C++20 起)
 | (3)
const_reverse_iterator crbegin() const noexcept; |  | (C++11 起) (C++20 前)
constexpr const_reverse_iterator crbegin() const noexcept; |  | (C++20 起)

返回指向逆转字符串首字符的逆向迭代器。它对应非逆向字符串的末字符。

参数

（无）

返回值

指向首字符的逆向迭代器

复杂度

常数

示例

#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>

int main()
{
    std::string s("Exemplar!");
    *s.rbegin() = 'y';
    std::cout << s << '\n'; // "Exemplary"

    std::string c;
    std::copy(s.crbegin(), s.crend(), std::back_inserter(c));
    std::cout << c << '\n'; // "yralpmexE"
}

输出：

Exemplary
yralpmexE

参阅

rend crend
(C++11)
 返回指向末尾的逆向迭代器
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::rend, std::basic_string<CharT,Traits,Allocator>::crend

< cpp‎ | string‎ | basic string
 | (1)
reverse_iterator rend(); |  | (C++11 前)
reverse_iterator rend() noexcept; |  | (C++11 起) (C++20 前)
constexpr reverse_iterator rend() noexcept; |  | (C++20 起)
 | (2)
const_reverse_iterator rend() const; |  | (C++11 前)
const_reverse_iterator rend() const noexcept; |  | (C++11 起) (C++20 前)
constexpr const_reverse_iterator rend() const noexcept; |  | (C++20 起)
 | (3)
const_reverse_iterator crend() const noexcept; |  | (C++11 起) (C++20 前)
constexpr const_reverse_iterator crend() const noexcept; |  | (C++20 起)

返回指向后随逆向字符串末字符的字符的逆向迭代器。它对应前驱非逆向字符串首字符的字符。此字符表现为占位符，试图访问它会导致未定义行为。

参数

（无）

返回值

指向后随末字符的字符的逆向迭代器

复杂度

常数

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>

int main()
{
  std::string s("A man, a plan, a canal: Panama");
  {
    std::string c;
    std::copy(s.rbegin(), s.rend(), std::back_inserter(c));
    std::cout << c <<'\n'; // "amanaP :lanac a ,nalp a ,nam A"
  }

  {
    std::string c;
    std::copy(s.crbegin(), s.crend(), std::back_inserter(c));
    std::cout << c <<'\n'; // "amanaP :lanac a ,nalp a ,nam A"
  }
}

输出：

amanaP :lanac a ,nalp a ,nam A
amanaP :lanac a ,nalp a ,nam A

参阅

rbegin crbegin
(C++11)
 返回指向起始的逆向迭代器
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::replace

< cpp‎ | string‎ | basic string
 | (1)
basic_string& replace( size_type pos, size_type count, const basic_string& str ); |  | (C++20 前)
constexpr basic_string& replace( size_type pos, size_type count, const basic_string& str ); |  | (C++20 起)
 | (1)
basic_string& replace( const_iterator first, const_iterator last, const basic_string& str ); |  | (C++20 前)
constexpr basic_string& replace( const_iterator first, const_iterator last, const basic_string& str ); |  | (C++20 起)
 | (2)
basic_string& replace( size_type pos, size_type count, const basic_string& str, size_type pos2, size_type count2 ); |  | (C++14 前)
basic_string& replace( size_type pos, size_type count, const basic_string& str, size_type pos2, size_type count2 = npos ); |  | (C++14 起) (C++20 前)
constexpr basic_string& replace( size_type pos, size_type count, const basic_string& str, size_type pos2, size_type count2 = npos ); |  | (C++20 起)
 | (3)
template< class InputIt > basic_string& replace( const_iterator first, const_iterator last, InputIt first2, InputIt last2 ); |  | (C++20 前)
template< class InputIt > constexpr basic_string& replace( const_iterator first, const_iterator last, InputIt first2, InputIt last2 ); |  | (C++20 起)
 | (4)
basic_string& replace( size_type pos, size_type count, const CharT* cstr, size_type count2 ); |  | (C++20 前)
constexpr basic_string& replace( size_type pos, size_type count, const CharT* cstr, size_type count2 ); |  | (C++20 起)
 | (4)
basic_string& replace( const_iterator first, const_iterator last, const CharT* cstr, size_type count2 ); |  | (C++20 前)
constexpr basic_string& replace( const_iterator first, const_iterator last, const CharT* cstr, size_type count2 ); |  | (C++20 起)
 | (5)
basic_string& replace( size_type pos, size_type count, const CharT* cstr ); |  | (C++20 前)
constexpr basic_string& replace( size_type pos, size_type count, const CharT* cstr ); |  | (C++20 起)
 | (5)
basic_string& replace( const_iterator first, const_iterator last, const CharT* cstr ); |  | (C++20 前)
constexpr basic_string& replace( const_iterator first, const_iterator last, const CharT* cstr ); |  | (C++20 起)
 | (6)
basic_string& replace( size_type pos, size_type count, size_type count2, CharT ch ); |  | (C++20 前)
constexpr basic_string& replace( size_type pos, size_type count, size_type count2, CharT ch ); |  | (C++20 起)
 | (6)
basic_string& replace( const_iterator first, const_iterator last, size_type count2, CharT ch ); |  | (C++20 前)
constexpr basic_string& replace( const_iterator first, const_iterator last, size_type count2, CharT ch ); |  | (C++20 起)
 | (7)
basic_string& replace( const_iterator first, const_iterator last, std::initializer_list <CharT> ilist ); |  | (C++11 起) (C++20 前)
constexpr basic_string& replace( const_iterator first, const_iterator last, std::initializer_list <CharT> ilist ); |  | (C++20 起)
 | (8)
template < class T > basic_string& replace( size_type pos, size_type count, const T& t ); |  | (C++17 起) (C++20 前)
template < class T > constexpr basic_string& replace( size_type pos, size_type count, const T& t ); |  | (C++20 起)
 | (8)
template < class T > basic_string& replace( const_iterator first, const_iterator last, const T& t ); |  | (C++17 起) (C++20 前)
template < class T > constexpr basic_string& replace( const_iterator first, const_iterator last, const T& t ); |  | (C++20 起)
 | (9)
template < class T > basic_string& replace( size_type pos, size_type count, const T& t, size_type pos2, size_type count2 = npos ); |  | (C++17 起) (C++20 前)
template < class T > constexpr basic_string& replace( size_type pos, size_type count, const T& t, size_type pos2, size_type count2 = npos ); |  | (C++20 起)

以新字符串替换 [pos, pos + count) 或 [first, last) 所指示的 string 部分。

新字符串可以是下列之一：

1) string str ；
2) str 的子串 [pos2, pos2 + count2) ，除了若 count2==npos 或若它可能越过 str.size() ，则使用 [pos2, str.size()) 。
3) 范围 [first2, last2) 中的字符。
若 InputIt 为整数类型则此重载与 (6) 拥有相同效果。 | (C++11 前)
此重载仅若 InputIt 满足 老式输入迭代器 (LegacyInputIterator) 的要求才参与重载决议。 | (C++11 起)
4) 范围 [cstr, cstr + count2) 中的字符；
5) 范围 [cstr, cstr + Traits::length(cstr)) 中的字符；
6) 字符 ch 的 count2 个副本；
7) initializer_list ilist 中的字符；
8) 如同用 std::basic_string_view <CharT, Traits> sv = t; 从 t 转换而来的 string_view sv 的字符。这些重载仅若std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议
9) 如同用 std::basic_string_view <CharT, Traits> sv = t; 从 t 转换而得的字符串视图 sv 的子视图 [pos2, pos2 + count2) ，除了若 count2==npos 或它将越过 sv.size() ，则使用 [pos2, sv.size()) 。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。

参数

pos | - | 将被替换的子串起始位置
count | - | 将被替换的子串长度
first, last | - | 将被替换的字符范围
str | - | 用于替换的 string
pos2 | - | 用于替换的子串起始位置
count2 | - | 用于替换的字符数
cstr | - | 指向用于替换的字符串的指针
ch | - | 用于替换的字符值
first2, last2 | - | 用于替换的字符范围
ilist | - | 拥有用于替换的字符的 initializer_list
t | - | 拥有用于替换的字符的对象（可转换为 std::basic_string_view ）

返回值

*this

异常

若 pos > length() 或 pos2 > str.length() 则为 std::out_of_range

若产生的 string 将超出最大可能 string 长度（ max_size() - 1 ）则为 std::length_error 。

任何情况下，若因任何原因抛出异常，则此函数无效果（强异常保证）。 (C++11 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2946 | C++17 | string_view 重载在某些情况下导致歧义 | 通过使之为模板来避免

示例

#include <iostream>
#include <string>

int main()
{
    std::string str("The quick brown fox jumps over the lazy dog.");

    str.replace(10, 5, "red"); // (5)

    str.replace(str.begin(), str.begin() + 3, 1, 'A'); // (6)

    std::cout << str << '\n';
}

输出：

A quick red fox jumps over the lazy dog.


std::basic_string<CharT,Traits,Allocator>::reserve

< cpp‎ | string‎ | basic string
 | (1) |
void reserve( size_type new_cap = 0 ); |  |  | (C++20 前)
constexpr void reserve( size_type new_cap ); |  |  | (C++20 起)
void reserve(); | (2) | (C++20 起) (弃用)
1) 告诉 std::basic_string 对象大小的有计划更改，使得它能准确地管理存储分配。
  • 若 new_cap 大于当前 capacity() ，则分配新存储，并令 capacity() 大于或等于 new_cap 。
  • 若 new_cap 小于当前 capacity() ，则这是非强制的收缩请求。
  • 若 new_cap 小于当前 size() ，则这是非强制的收缩到适合 (shrink-to-fit) 请求，等价于 shrink_to_fit() (C++11 起)。
 (C++20 前)
  • 若 new_cap 小于或等于当前 capacity() ，则无效果。
 (C++20 起)
若发生容量更改，则非法化所有迭代器与引用，包含尾后迭代器。
2) 以无参数调用 reserve 是非强制的收缩到适合请求。此调用后， capacity() 拥有大于或等于 size() 的未指定值。
 (C++20 起)

参数

new_cap - string 的新容量

返回值

（无）

异常

若 new_cap 大于 max_size() 则抛出 std::length_error

可能抛出任何 std::allocator_traits <Allocator>::allocate() 所抛的异常，如 std::bad_alloc 。

复杂度

至多与 string 的 size() 成线性

示例

#include <cassert>
#include <string>

int main()
{
    std::string s;
    std::string::size_type new_capacity{ 100u };
    assert(new_capacity > s.capacity());

    s.reserve(new_capacity);
    assert(new_capacity <= s.capacity());
}

参阅

capacity
 返回当前对象分配的存储空间能保存的字符数量
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::resize

< cpp‎ | string‎ | basic string
 | (1)
void resize( size_type count ); |  | (C++20 前)
constexpr void resize( size_type count ); |  | (C++20 起)
 | (2)
void resize( size_type count, CharT ch ); |  | (C++20 前)
constexpr void resize( size_type count, CharT ch ); |  | (C++20 起)

重设 string 大小以含 count 个字符。

若当前大小小于 count ，则后附额外的字符。

若当前大小大于 count ，则缩减 string 到为其首 count 个元素。

第一版本初始化新字符为 CharT() ，第二版本初始化新字符为 ch 。

参数

count | - | string 的新大小
ch | - | 用以初始化新字符的字符

返回值

（无）

异常

若 count > max_size() 则为 std::length_error 。对应 Allocator 所抛的任何异常。

若因任何原因抛出异常，则此函数无效果（强异常保证）。 (C++11 起)

示例

#include <iostream>
#include <stdexcept>

int main()
{
    std::cout << "Basic functionality:\n";
    const unsigned  desired_length(8);
    std::string     long_string( "Where is the end?" );
    std::string     short_string( "Ha" );

    // 缩短
    std::cout << "Before: \"" << long_string << "\"\n";
    long_string.resize( desired_length );
    std::cout << "After: \"" << long_string <<  "\"\n";

    // 加长
    std::cout << "Before: \"" << short_string <<  "\"\n";
    short_string.resize( desired_length, 'a' );
    std::cout << "After: \"" << short_string <<  "\"\n";

    std::cout  << "\nErrors:\n";
    {
        std::string s;

        try {
            // 大小 OK ，无 length_error
            // （可能抛 bad_alloc ）
            s.resize(s.max_size() - 1, 'x');
        } catch (const std::bad_alloc&) {
            std::cout << "1. bad alloc\n";
        }

        try {
            // 大小 OK ，无 length_error
            // （可能抛 bad_alloc ）
            s.resize(s.max_size(), 'x');
        } catch (const std::bad_alloc& exc) {
            std::cout << "2. bad alloc\n";
        }

        try {
            // 大小错误，抛出 length_error
            s.resize(s.max_size() + 1, 'x');
        } catch (const std::length_error&) {
            std::cout << "3. length error\n";
        }
     }
}

可能的输出：

Basic functionality:
Before: "Where is the end?"
After: "Where is"
Before: "Ha"
After: "Haaaaaaa"

Errors:
1. bad alloc
2. bad alloc
3. length error

复杂度

与 string 大小成线性。

参阅

sizelength
 返回字符数
(公开成员函数)


std::basic_string<CharT,Traits,Allocator>::resize_and_overwrite

< cpp‎ | string‎ | basic string
template< class Operation > constexpr void resize_and_overwrite( size_type count, Operation op ); | (C++23 起)

重设字符串大小以含有至多 count 个字符，用用户提供的操作 op 修改可能不确定的内容并设置长度。

此函数执行下列步骤：

  1. 获得至少含有 count + 1 个字符的存储，并使其前 k 个字符等于 *this 的前 k 个字符，其中 k 是 count 与调用 resize_and_overwrite 前 this->size() 的结果的较小者。令 p 代表指向该存储中首个字符的指针。
    • 相等性以如同通过检查 this->compare(0, k, p, k) == 0 确定。
    • [p + k, p + count] 中的字符可能拥有不确定值。
  2. 求值 std::move(op)(p, count) 。令 r 为 std::move(op)(p, count) 的返回值。
  3. 以 [p, p + r) 替换 *this 的内容（这会设置 *this 的长度为 r ）。非法化所有指向范围 [p, p + count] 中的指针与引用。

若 r 不具有整数式类型则程序非良构。若 std::move(op)(p, count) 抛出异常或修改 p 或 count、 r 不在范围 [0, count] 中，或范围 [p, p + r) 中的任何字符拥有不确定值，则行为未定义。

推荐实现避免不必要的复制与分配，例如通过使得 p 等于指向调用后为 *this 分配的字符存储的起始指针，若 count 小于或等于 this->capacity() 则该存储能等同于 *this 的既存存储。

参数

count | - | 字符串的最大可能的新大小
op | - | 用于设置字符串新内容的函数对象

返回值

（无）

异常

若 count > max_size() 则为 std::length_error 。任何对应的 Allocator 所抛的异常。

若从 std::move(op)(p, count) 抛出异常，则行为未定义。否则若抛出异常则此函数无效果。

注解

无论重分配是否出现， resize_and_overwrite 都非法化所有指向 *this 中的迭代器、指针及引用。实现可以假设调用 resize_and_overwrite 后字符串的内容不会被别名化。

示例

本节未完成
原因：暂无示例

参阅

resize | 更改存储的字符数 (公开成员函数)
make_uniquemake_unique_for_overwrite (C++14)(C++20) | 创建管理一个新对象的独占指针 (函数模板)
make_sharedmake_shared_for_overwrite (C++20) | 创建管理一个新对象的共享指针 (函数模板)
allocate_sharedallocate_shared_for_overwrite (C++20) | 创建管理一个用分配器分配的新对象的共享指针 (函数模板)


std::basic_string<CharT,Traits,Allocator>::rfind

< cpp‎ | string‎ | basic string
 | (1)
size_type rfind( const basic_string& str, size_type pos = npos ) const; |  | (C++11 前)
size_type rfind( const basic_string& str, size_type pos = npos ) const noexcept; |  | (C++11 起) (C++20 前)
constexpr size_type rfind( const basic_string& str, size_type pos = npos ) const noexcept; |  | (C++20 起)
 | (2)
size_type rfind( const CharT* s, size_type pos, size_type count ) const; |  | (C++20 前)
constexpr size_type rfind( const CharT* s, size_type pos, size_type count ) const; |  | (C++20 起)
 | (3)
size_type rfind( const CharT* s, size_type pos = npos ) const; |  | (C++20 前)
constexpr size_type rfind( const CharT* s, size_type pos = npos ) const; |  | (C++20 起)
 | (4)
size_type rfind( CharT ch, size_type pos = npos ) const; |  | (C++11 前)
size_type rfind( CharT ch, size_type pos = npos ) const noexcept; |  | (C++11 起) (C++20 前)
constexpr size_type rfind( CharT ch, size_type pos = npos ) const noexcept; |  | (C++20 起)
 | (5)
template < class T > size_type rfind( const T& t, size_type pos = npos ) const noexcept(/* see below */); |  | (C++17 起) (C++20 前)
template < class T > constexpr size_type rfind( const T& t, size_type pos = npos ) const noexcept(/* see below */); |  | (C++20 起)

寻找等于给定字符序列的最后子串。搜索始于 pos ，即找到的子串必须不始于 pos 后的位置。若将 npos 或任何不小于 size()-1 的值作为 pos 传递，则在整个字符串中搜索。

1) 寻找等于 str 的最后子串。
2) 寻找等于范围 [s, s+count) 的最后子串。此范围能包含空字符。
3) 寻找等于 s 所指向的字符串的最后子串。由首个空字符，用 Traits::length(s) 确定字符串长度。
4) 寻找等于 ch 的最后字符。
5) 如同用 std::basic_string_view <CharT, Traits> sv = t; 隐式转换 t 为 string_view sv ，然后寻找等于 sv 内容的最后子串。此重载仅若 std::is_convertible_v <const T&, std::basic_string_view <CharT, Traits>> 为 true 且 std::is_convertible_v <const T&, const CharT*> 为 false 才参与重载决议。

所有情况下均调用 Traits::eq 检查相等性。

参数

str | - | 要搜索的 string
pos | - | 开始搜索的位置
count | - | 要搜索的子串长度
s | - | 指向要搜索的字符串的指针
ch | - | 要搜索的字符
t | - | 要搜索的对象（可转换为 std::basic_string_view ）

返回值

找到的子串的首字符位置，或若找不到这种子串则为 npos 。注意这是从字符串开始，而非末尾的偏移。

若搜索任何空字符串（ str.size() 、 count 或 Traits::length(s) 为零），则返回 pos （立即找到空字符串），除非 pos > size() （包括 pos == npos 的情况），该情况下返回 size() 。

否则，若 size() 为零，则始终返回 npos 。

异常

5)
noexcept 说明：
noexcept(std::is_nothrow_convertible_v<const T&, std::basic_string_view <CharT, Traits>>)

示例

#include <string>
#include <iostream>

void print(std::string::size_type n, std::string const &s)
{
    if (n == std::string::npos) {
        std::cout << "not found\n";
    } else {
        std::cout << "found: \"" << s.substr(n) << "\" at " << n << '\n';
    }
}

int main()
{
    std::string::size_type n;
    std::string const s = "This is a string";

    // 从字符串尾反向搜索
    n = s.rfind("is");
    print(n, s);
    // 从位置 4 反向搜索
    n = s.rfind("is", 4);
    print(n, s);
    // 寻找单个字符
    n = s.rfind('s');
    print(n, s);
    // 寻找单个字符
    n = s.rfind('q');
    print(n, s);
}

输出：

found: "is a string" at 5
found: "is is a string" at 2
found: "string" at 10
not found

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2064 | C++11 | 重载 (3) 与 (4) 为 noexcept | 移除
LWG 2946 | C++17 | string_view 重载在某些情况下导致歧义 | 通过使之为模板来避免
P1148R0 | C++11 C++17 | 重载 (4)/(5) 的 noexcept 意外地被 LWG2064/LWG2946 丢弃 | 恢复

参阅

find | 于字符串中寻找字符 (公开成员函数)
find_first_of | 寻找字符的首次出现 (公开成员函数)
find_first_not_of | 寻找字符的首次缺失 (公开成员函数)
find_last_of | 寻找字符的最后一次出现 (公开成员函数)
find_last_not_of | 寻找字符的最后一次缺失 (公开成员函数)


std::basic_string<CharT,Traits,Allocator>::shrink_to_fit

< cpp‎ | string‎ | basic string
void shrink_to_fit(); | (C++11 起) (C++20 前)
constexpr void shrink_to_fit(); | (C++20 起)

请求移除未使用的容量。

这是减少 capacity() 到 size() 的非强制请求。是否满足请求取依赖于实现。

若（且唯若）发生重分配，则非法化所有指针、引用和迭代器。

参数

（无）

返回值

（无）

复杂度

（未指明） | (C++17 前)
与 string 大小成线性 | (C++17 起)

示例

#include <iostream>
#include <string>

int main()
{
    std::string s;
    std::cout << "Default-constructed capacity is " << s.capacity()
        << " and size is " << s.size() << '\n';
    for (int i=0; i<42; i++)
        s.append(" 42 ");
    std::cout << "Capacity after a couple of appends is " << s.capacity()
        << " and size is " << s.size() << '\n';
    s.clear();
    std::cout << "Capacity after clear() is " << s.capacity()
        << " and size is " << s.size() << '\n';
    s.shrink_to_fit();
    std::cout << "Capacity after shrink_to_fit() is " << s.capacity()
        << " and size is " << s.size() << '\n';
}

可能的输出：

Default-constructed capacity is 15 and size 0
Capacity after a couple of appends is 240 and size 168
Capacity after clear() is 240 and size 0
Capacity after shrink_to_fit() is 15 and size 0

参阅

sizelength | 返回字符数 (公开成员函数)
capacity | 返回当前对象分配的存储空间能保存的字符数量 (公开成员函数)


std::basic_string<CharT,Traits,Allocator>::size, std::basic_string<CharT,Traits,Allocator>::length

< cpp‎ | string‎ | basic string
size_type size() const; | (C++11 前)
size_type size() const noexcept; | (C++11 起) (C++20 前)
constexpr size_type size() const noexcept; | (C++20 起)
size_type length() const; | (C++11 前)
size_type length() const noexcept; | (C++11 起) (C++20 前)
constexpr size_type length() const noexcept; | (C++20 起)

返回 string 中的 CharT 元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

string 中的 CharT 元素数。

复杂度

未指定 | (C++11 前)
常数 | (C++11 起)

注解

对于 std::string ，元素是字节（ char 类型对象），若使用如 UTF-8 的多字节编码，则它与字符不同。

示例

#include <cassert>
#include <iterator>
#include <string>

int main()
{
    std::string s("Exemplar");
    assert(8 == s.size());
    assert(s.size() == s.length());
    assert(s.size() == static_cast<std::string::size_type>(
        std::distance(s.begin(), s.end())));

    std::u32string a(U"ハロー・ワールド"); // 8 个码点
    assert(8 == a.size()); // 8 个 UTF-32 的编码单元

    std::u16string b(u"ハロー・ワールド"); // 8 个码点
    assert(8 == b.size()); // 8 个 UTF-16 的编码单元

    std::string c(u8"ハロー・ワールド"); // 8 个码点
    assert(24 == c.size()); // 24 个 UTF-8 的编码单元
}

参阅

empty | 检查字符串是否为空 (公开成员函数)
max_size | 返回字符数的最大值 (公开成员函数)


std::basic_string<CharT,Traits,Allocator>::starts_with

< cpp‎ | string‎ | basic string
constexpr bool starts_with( std::basic_string_view <CharT,Traits> sv )
const noexcept;
 (1) (C++20 起)
constexpr bool starts_with( CharT c ) const noexcept;
 (2) (C++20 起)
constexpr bool starts_with( const CharT* s ) const;
 (3) (C++20 起)

检查 string 是否始于给定前缀。前缀可为以下之一：

1) string_view sv （可以是从另一 std::basic_string 隐式转换的结果）。
2) 单个字符 c
3) 空终止字符串 s

所有三个重载等效地返回 std::basic_string_view <CharT, Traits>(data(), size()).starts_with(x) ，其中 x 是参数。

参数

sv | - | string_view ，可为从另一 std::basic_string 隐式转换的结果
c | - | 单个字符
s | - | 空终止字符串

返回值

若 string 始于前缀起始则为 true ，否则为 false 。

示例

#include <iostream>
#include <string_view>
#include <string>

template <typename PrefixType>
void test_prefix_print(const std::string& str, PrefixType prefix)
{
    std::cout << '\'' << str << "' starts with '" << prefix << "': " <<
        str.starts_with(prefix) << '\n';
}

int main()
{
    std::boolalpha(std::cout);
    auto helloWorld = std::string("hello world");

    test_prefix_print(helloWorld, std::string_view("hello"));

    test_prefix_print(helloWorld, std::string_view("goodbye"));

    test_prefix_print(helloWorld, 'h');

    test_prefix_print(helloWorld, 'x');
}

输出：

'hello world' starts with 'hello': true
'hello world' starts with 'goodby': false
'hello world' starts with 'h': true
'hello world' starts with 'x': false

参阅

ends_with (C++20) | 检查 string 是否终于给定后缀 (公开成员函数)
starts_with (C++20) | 检查 string_view 是否始于给定前缀 (std::basic_string_view<CharT,Traits> 的公开成员函数)
ends_with (C++20) | 检查 string_view 是否终于给定后缀 (std::basic_string_view<CharT,Traits> 的公开成员函数)
contains (C++23) | 检查字符串是否含有给定的子串或字符 (公开成员函数)
contains (C++23) | 检查字符串视图是否含有给定的子串或字符 (std::basic_string_view<CharT,Traits> 的公开成员函数)
compare | 比较二个字符串 (公开成员函数)
substr | 返回子串 (公开成员函数)


std::stof, std::stod, std::stold

< cpp‎ | string‎ | basic string
定义于头文件 <string>
float stof( const std::string & str, std::size_t * pos = 0 );
float stof( const std::wstring & str, std::size_t * pos = 0 );
 (1) (C++11 起)
double stod( const std::string & str, std::size_t * pos = 0 );
double stod( const std::wstring & str, std::size_t * pos = 0 );
 (2) (C++11 起)
long double stold( const std::string & str, std::size_t * pos = 0 );
long double stold( const std::wstring & str, std::size_t * pos = 0 );
 (3) (C++11 起)

转译 string str 中的浮点值。

1) 调用 std::strtof (str.c_str(), &ptr) 或 std::wcstof (str.c_str(), &ptr)
2) 调用 std::strtod (str.c_str(), &ptr) 或 std::wcstod (str.c_str(), &ptr)
3) 调用 std::strtold (str.c_str(), &ptr) 或 std::wcstold (str.c_str(), &ptr)

函数会舍弃任何空白符（由 std::isspace() 确定），直至找到首个非空白符。然后它会取用尽可能多的字符，以构成合法的浮点数表示，并将它们转换成浮点值。合法的浮点值可以为下列之一：

  • 十进制浮点数表达式。它由下列部分组成：
  • (可选) 正或负号
  • 非空的十进制数字序列，可选地包含一个小数点字符（由当前的 C 本地环境确定）（定义有效数字）
  • (可选) e 或 E ，并跟随可选的正或负号，以及非空十进制数字序列（以 10 为底定义指数）
  • 十六进制浮点数表达式。它由下列部分组成：
  • (可选) 正或负号
  • 0x 或 0X
  • 非空的十六进制数字序列，选地包含一个小数点字符（由当前的 C 本地环境确定）（定义有效数字）
  • (可选) p 或 P ，并跟随可选的正或负号，以及非空十进制数字序列（以 2 为底定义指数）
  • 无穷大表达式。它由下列部分组成：
  • (可选) 正或负号
  • INF 或 INFINITY ，忽略大小写
  • 非数（NaN）表达式。它由下列部分组成：
  • (可选) 正或负号
  • NAN 或 NAN(char_sequence) ，忽略 NAN 部分的大小写。 char_sequence 只能由数字、拉丁字母和下划线构成。结果是一个静态的 NaN 浮点值。
  • 任何其他可由当前 C 本地环境接受的表达式

若 pos 不是空指针，则对于转换函数为内部的指针 ptr 将接受 str.c_str() 中首个未转换字符的地址，然后计算该字符的下标并存储之于 *pos ，给出转换处理的字符数。

参数

str | - | 要转换的 string
pos | - | 存储已处理字符数的整数的地址

返回值

转换为指定浮点类型的字符串。

异常

若不能进行转换则为 std::invalid_argument 。

若转换后的值会落在结果类型的范围外，或若底层函数（ strtof 、 strtod 或 strtold ）设置 errno 为 ERANGE 则为 std::out_of_range 。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2403 | C++11 | stof 调用 std::strtod 或 std::wcstod | stof 调用 std::strtof 或 std::wcstof

参阅

stoistolstoll (C++11)(C++11)(C++11) | 转换字符串为有符号整数 (函数)
stoulstoull (C++11)(C++11) | 转换字符串为无符号整数 (函数)
from_chars (C++17) | 转换字符序列到整数或浮点值 (函数)


std::stoi, std::stol, std::stoll

< cpp‎ | string‎ | basic string
定义于头文件 <string>
int stoi( const std::string & str, std::size_t * pos = 0, int base = 10 );
int stoi( const std::wstring & str, std::size_t * pos = 0, int base = 10 );
 (1) (C++11 起)
long stol( const std::string & str, std::size_t * pos = 0, int base = 10 );
long stol( const std::wstring & str, std::size_t * pos = 0, int base = 10 );
 (2) (C++11 起)
long long stoll( const std::string & str, std::size_t * pos = 0, int base = 10 );
long long stoll( const std::wstring & str, std::size_t * pos = 0, int base = 10 );
 (3) (C++11 起)

转译字符串 str 中的有符号整数值。

1) 调用 std::strtol (str.c_str(), &ptr, base) 或 std::wcstol (str.c_str(), &ptr, base)
2) 调用 std::strtol (str.c_str(), &ptr, base) 或 std::wcstol (str.c_str(), &ptr, base)
3) 调用 std::strtoll (str.c_str(), &ptr, base) 或 std::wcstoll (str.c_str(), &ptr, base)

舍弃所有空白符（以调用 isspace() 鉴别），直到找到首个非空白符，然后取尽可能多的字符组成底 n （其中 n=base ）的整数表示，并将它们转换成一个整数值。合法的整数值由下列部分组成：

  • (可选)正或负号
  • (可选)指示八进制底的前缀（ 0 ）（仅当底为 8 或 ​0​ 时应用）
  • (可选)指示十六进制底的前缀（ 0x 或 0X ）（仅当底为 16 或 ​0​ 时应用）
  • 一个数字序列

底的合法集是 {0,2,3,...,36} 。合法数字集对于底 2 整数是 {0,1}，对于底3整数是 {0,1,2} ，以此类推。对于大于 10 的底，合法数字包含字母字符，从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。

当前安装的 C 本地环境可能接受另外的数字格式。

若 base 为 ​0​ ，则自动检测数值进制：若前缀为 0 ，则底为八进制，若前缀为 0x 或 0X ，则底为十六进制，否则底为十进制。

若符号是输入序列的一部分，则对从数字序列计算得来的数字值取反，如同用结果类型的一元减。

若 pos 不是空指针，则指针 ptr ——转换函数内部者——将接收 str.c_str() 中首个未转换字符的地址，将计算该字符的下标并存储之于 *pos ，该对象给出转换所处理的字符数。

参数

str | - | 要转换的字符串
pos | - | 存储已处理字符数的整数的地址
base | - | 数的底

返回值

对应 str 内容的整数值。

异常

  • 若不能进行转换则为 std::invalid_argument
  • 若转换值会落在结果类型的范围外，或若底层函数（ std::strtol 或 std::strtoll ）设置 errno 为 ERANGE 则为 std::out_of_range 。

示例

#include <iostream>
#include <string>

int main()
{
    std::string str1 = "45";
    std::string str2 = "3.14159";
    std::string str3 = "31337 with words";
    std::string str4 = "words and 2";

    int myint1 = std::stoi(str1);
    int myint2 = std::stoi(str2);
    int myint3 = std::stoi(str3);
    // 错误： 'std::invalid_argument'
    // int myint4 = std::stoi(str4);

    std::cout << "std::stoi(\"" << str1 << "\") is " << myint1 << '\n';
    std::cout << "std::stoi(\"" << str2 << "\") is " << myint2 << '\n';
    std::cout << "std::stoi(\"" << str3 << "\") is " << myint3 << '\n';
    //std::cout << "std::stoi(\"" << str4 << "\") is " << myint4 << '\n';
}

输出：

std::stoi("45") is 45
std::stoi("3.14159") is 3
std::stoi("31337 with words") is 31337

参阅

stoulstoull (C++11)(C++11) | 转换字符串为无符号整数 (函数)
stofstodstold (C++11)(C++11)(C++11) | 转换字符串为浮点值 (函数)
strtolstrtoll (C++11) | 转换字节字符串为整数值 (函数)
strtoulstrtoull (C++11) | 转换字节字符串为无符号整数值 (函数)
strtoimaxstrtoumax (C++11)(C++11) | 转换字节字符串为 std::intmax_t 或 std::uintmax_t (函数)
from_chars (C++17) | 转换字符序列到整数或浮点值 (函数)
atoiatolatoll (C++11) | 转换字节字符串为整数值 (函数)
to_string (C++11) | 转换整数或浮点值为 string (函数)
to_wstring (C++11) | 转换整数或浮点值为 wstring (函数)


std::stoul, std::stoull

< cpp‎ | string‎ | basic string
定义于头文件 <string>
unsigned long stoul( const std::string & str, std::size_t * pos = 0, int base = 10 );
unsigned long stoul( const std::wstring & str, std::size_t * pos = 0, int base = 10 );
 (1) (C++11 起)
unsigned long long stoull( const std::string & str, std::size_t * pos = 0, int base = 10 );
unsigned long long stoull( const std::wstring & str, std::size_t * pos = 0, int base = 10 );
 (2) (C++11 起)

转译字符串 str 中的无符号整数值。

1) 调用 std::strtoul (str.c_str(), &ptr, base) 或 std::wcstoul (str.c_str(), &ptr, base)
2) 调用 std::strtoull (str.c_str(), &ptr, base) 或 std::wcstoull (str.c_str(), &ptr, base)

舍弃所有空白符（以调用 isspace() 鉴别），直到找到首个非空白符，然后取尽可能多的字符组成底 n （其中 n=base ）的无符号整数表示，并将它们转换成一个整数值。合法的无符号整数值由下列部分组成：

  • (可选)正或负号
  • (可选)指示八进制底的前缀（ 0 ）（仅当底为 8 或 ​0​ 时应用）
  • (可选)指示十六进制底的前缀（ 0x 或 0X ）（仅当底为 16 或 ​0​ 时应用）
  • 一个数字序列

底的合法集是 {0,2,3,...,36} 。合法数字集对于底 2 整数是 {0,1}，对于底3整数是 {0,1,2} ，以此类推。对于大于 10 的底，合法数字包含字母字符，从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。

当前安装的 C 本地环境可能接受另外的数字格式。

若 base 为 ​0​ ，则自动检测数值进制：若前缀为 0 ，则底为八进制，若前缀为 0x 或 0X ，则底为十六进制，否则底为十进制。

若符号是输入序列的一部分，则对从数字序列计算得来的数字值取反，如同用结果类型的一元减，它对无符号整数应用回卷规则。

若 pos 不是空指针，则转换函数内部的 ptr 指针会接收首个 str.c_str() 中未转换字符的地址，然后该字符的下标在计算后存储于 *pos ，给出转换所处理的字符数。

参数

str | - | 要转换的字符串
pos | - | 存储被处理字符数的整数的地址
base | - | 数字基底

返回值

转换到指定无符号整数类型的字符串。

异常

  • 若不能进行转换则抛出 std::invalid_argument
  • 若转换值会落在转换类型的范围之外，或底层函数（ std::strtoul 或 std::strtoull ）设 errno 为 ERANGE 则抛出 std::out_of_range 。

参阅

stoistolstoll (C++11)(C++11)(C++11) | 转换字符串为有符号整数 (函数)
stofstodstold (C++11)(C++11)(C++11) | 转换字符串为浮点值 (函数)


std::basic_string<CharT,Traits,Allocator>::substr

< cpp‎ | string‎ | basic string
basic_string substr( size_type pos = 0, size_type count = npos ) const; | (C++20 前)
constexpr basic_string substr( size_type pos = 0, size_type count = npos ) const; | (C++20 起)

返回子串 [pos, pos+count) 。若请求的字串越过字符串的结尾，即 count 大于 size() - pos （例如若 count == npos ），则返回的子串为 [pos, size()) 。

参数

pos | - | 要包含的首个字符的位置
count | - | 子串的长度

返回值

含子串 [pos, pos+count) 或 [pos, size()) 的 string 。

异常

若 pos > size() 则为 std::out_of_range 。

复杂度

与 count 成线性。

注解

如同以 basic_string(data()+pos, count) 构造返回的 string ，这隐含将会默认构造返回的 string 的分配器——新分配器将不是 this->get_allocator() 的副本。

示例

#include <string>
#include <iostream>

int main()
{
    std::string a = "0123456789abcdefghij";

    // count 为 npos ，返回 [pos, size())
    std::string sub1 = a.substr(10);
    std::cout << sub1 << '\n';

    // pos 和 pos+count 都在边界内，返回 [pos, pos+count)
    std::string sub2 = a.substr(5, 3);
    std::cout << sub2 << '\n';

    // pos 在边界内， pos+count 不在，返回 [pos, size())
    std::string sub4 = a.substr(a.size()-3, 50);
    // 这等效于
    // std::string sub4 = a.substr(17, 3);
    // 因为 a.size() == 20 ， pos == a.size()-3 == 17 而 a.size()-pos == 3

    std::cout << sub4 << '\n';

    try {
        // pos 在边界外，抛出
        std::string sub5 = a.substr(a.size()+3, 50);
        std::cout << sub5 << '\n';
    } catch(const std::out_of_range& e) {
        std::cout << "pos exceeds string size\n";
    }
}

输出：

abcdefghij
567
hij
pos exceeds string size

参阅

copy | 复制字符 (公开成员函数)
sizelength | 返回字符数 (公开成员函数)
find | 于字符串中寻找字符 (公开成员函数)
npos [静态] | 特殊值。准确含义依赖语境 (公开静态成员常量)


std::basic_string<CharT,Traits,Allocator>::swap

< cpp‎ | string‎ | basic string
void swap( basic_string& other ); | (C++17 前)
void swap( basic_string& other ) noexcept(/* see below */); | (C++17 起) (C++20 前)
constexpr void swap( basic_string& other ) noexcept(/* see below */); | (C++20 起)

交换 string 与 other 的内容。可能非法化所有迭代器和引用。

若 Allocator 不在交换时传播且 *this 与 other 的分配器不相等则行为未定义。

 (C++11 起)

参数

other - 要与之交换内容的 string

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept( std::allocator_traits <Allocator>::propagate_on_container_swap::value
|| std::allocator_traits <Allocator>::is_always_equal::value)
 (C++17 起)

示例

#include <string>
#include <iostream>

int main()
{
    std::string a = "AAA";
    std::string b = "BBB";

    std::cout << "before swap" << '\n';
    std::cout << "a: " << a << '\n';
    std::cout << "b: " << b << '\n';

    a.swap(b);

    std::cout << "after swap" << '\n';
    std::cout << "a: " << a << '\n';
    std::cout << "b: " << b << '\n';
}

输出：

before swap
a: AAA
b: BBB
after swap
a: BBB
b: AAA


std::swap(std::basic_string)

< cpp‎ | string‎ | basic string
定义于头文件 <string>
template< class CharT, class Traits, class Alloc >

void swap( std::basic_string <CharT, Traits, Alloc> &lhs,

std::basic_string <CharT, Traits, Alloc> &rhs );
 (C++17 前)
template< class CharT, class Traits, class Alloc >

void swap( std::basic_string <CharT, Traits, Alloc> &lhs,

std::basic_string <CharT, Traits, Alloc> &rhs ) noexcept(/* see below */);
 (C++17 起)
(C++20 前)
template< class CharT, class Traits, class Alloc >

constexpr void
swap( std::basic_string <CharT, Traits, Alloc> &lhs,

std::basic_string <CharT, Traits, Alloc> &rhs ) noexcept(/* see below */);
 (C++20 起)

对 std::basic_string 特化 std::swap 算法。交换 lhs 与 rhs 的内容。等价于 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换内容的 string

返回值

（无）

复杂度

常数。

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))
 (C++17 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2064 | C++11 | 非成员 swap 为 noexcept 并与成员 swap 不一致 | 移除 noexcept

参阅

swap
 交换内容
(公开成员函数)


std::to_string

< cpp‎ | string‎ | basic string
定义于头文件 <string> |  |
std::string to_string( int value ); | (1) | (C++11 起)
std::string to_string( long value ); | (2) | (C++11 起)
std::string to_string( long long value ); | (3) | (C++11 起)
std::string to_string( unsigned value ); | (4) | (C++11 起)
std::string to_string( unsigned long value ); | (5) | (C++11 起)
std::string to_string( unsigned long long value ); | (6) | (C++11 起)
std::string to_string( float value ); | (7) | (C++11 起)
std::string to_string( double value ); | (8) | (C++11 起)
std::string to_string( long double value ); | (9) | (C++11 起)
1) 把有符号十进制整数转换为字符串，与 std::sprintf (buf, "%d", value) 在有足够大的 buf 时产生的内容相同。
2) 把有符号十进制整数转换为字符串，与 std::sprintf (buf, "%ld", value) 在有足够大的 buf 时产生的内容相同。
3) 把有符号十进制整数转换为字符串，与 std::sprintf (buf, "%lld", value) 在有足够大的 buf 时产生的内容相同。
4) 把无符号十进制整数转换为字符串，与 std::sprintf (buf, "%u", value) 在有足够大的 buf 时产生的内容相同。
5) 把无符号十进制整数转换为字符串，与 std::sprintf (buf, "%lu", value) 在有足够大的 buf 时产生的内容相同。
6) 把无符号十进制整数转换为字符串，与 std::sprintf (buf, "%llu", value) 在有足够大的 buf 时产生的内容相同。
7,8) 把浮点值转换为字符串，与 std::sprintf (buf, "%f", value) 在有足够大的 buf 时产生的内容相同。
9) 把浮点值转换为字符串，与 std::sprintf (buf, "%Lf", value) 在有足够大的 buf 时产生的内容相同。

参数

value - 需要转换的数值

返回值

一个包含转换后值的字符串

异常

可能从 std::string 的构造函数抛出 std::bad_alloc 。

注意

  • 对于浮点类型， std::to_string 可能产生不期待的结果，因为返回的字符串中的有效位数能为零，见示例。
  • 返回值可以明显地有别于 std::cout 所默认打印的结果，见示例。
  • std::to_string 由于格式化目的依赖本地环境，从而从多个线程同时调用 std::to_string 可能会导致调用的部分序列化结果。 C++17 提供高性能、不依赖本地环境的替用品 std::to_chars 。

示例

#include <iostream>
#include <string>

int main()
{
    double f = 23.43;
    double f2 = 1e-9;
    double f3 = 1e40;
    double f4 = 1e-40;
    double f5 = 123456789;
    std::string f_str = std::to_string(f);
    std::string f_str2 = std::to_string(f2); // 注意：返回 "0.000000"
    std::string f_str3 = std::to_string(f3); // 注意：不返回 "1e+40".
    std::string f_str4 = std::to_string(f4); // 注意：返回 "0.000000"
    std::string f_str5 = std::to_string(f5);
    std::cout << "std::cout: " << f << '\n'
              << "to_string: " << f_str  << "\n\n"
              << "std::cout: " << f2 << '\n'
              << "to_string: " << f_str2 << "\n\n"
              << "std::cout: " << f3 << '\n'
              << "to_string: " << f_str3 << "\n\n"
              << "std::cout: " << f4 << '\n'
              << "to_string: " << f_str4 << "\n\n"
              << "std::cout: " << f5 << '\n'
              << "to_string: " << f_str5 << '\n';
}

输出：

std::cout: 23.43
to_string: 23.430000

std::cout: 1e-09
to_string: 0.000000

std::cout: 1e+40
to_string: 10000000000000000303786028427003666890752.000000

std::cout: 1e-40
to_string: 0.000000

std::cout: 1.23457e+08
to_string: 123456789.000000

参阅

to_wstring (C++11) | 转换整数或浮点值为 wstring (函数)
stoulstoull (C++11)(C++11) | 转换字符串为无符号整数 (函数)
stoistolstoll (C++11)(C++11)(C++11) | 转换字符串为有符号整数 (函数)
stofstodstold (C++11)(C++11)(C++11) | 转换字符串为浮点值 (函数)
to_chars (C++17) | 转换整数或浮点值到字符序列 (函数)


std::to_wstring

< cpp‎ | string‎ | basic string
定义于头文件 <string> |  |
std::wstring to_wstring( int value ); | (1) | (C++11 起)
std::wstring to_wstring( long value ); | (2) | (C++11 起)
std::wstring to_wstring( long long value ); | (3) | (C++11 起)
std::wstring to_wstring( unsigned value ); | (4) | (C++11 起)
std::wstring to_wstring( unsigned long value ); | (5) | (C++11 起)
std::wstring to_wstring( unsigned long long value ); | (6) | (C++11 起)
std::wstring to_wstring( float value ); | (7) | (C++11 起)
std::wstring to_wstring( double value ); | (8) | (C++11 起)
std::wstring to_wstring( long double value ); | (9) | (C++11 起)

转换数值为 std::wstring 。

1) 转换有符号十进制整数为宽字符串，其内容与 std::swprintf (buf, sz, L"%d", value) 对于充分大的 buf 将会生成的内容相同。
2) 转换有符号十进制整数为宽字符串，其内容与 std::swprintf (buf, sz, L"%ld", value) 对于充分大的 buf 将会生成的内容相同。
3) 转换有符号十进制整数为宽字符串，其内容与 std::swprintf (buf, sz, L"%lld", value) 对于充分大的 buf 将会生成的内容相同。
4) 转换无符号十进制整数为宽字符串，其内容与 std::swprintf (buf, sz, L"%u", value) 对于充分大的 buf 将会生成的内容相同。
5) 转换无符号十进制整数为宽字符串，其内容与 std::swprintf (buf, sz, L"%lu", value) 对于充分大的 buf 将会生成的内容相同。
6) 转换无符号十进制整数为宽字符串，其内容与 std::swprintf (buf, sz, L"%llu", value) 对于充分大的 buf 将会生成的内容相同。
7,8) 转换浮点值为宽字符串，其内容与 std::swprintf (buf, sz, L"%f", value) 对于充分大的 buf 将会生成的内容相同。
9) 转换浮点值为宽字符串，其内容与 std::swprintf (buf, sz, L"%Lf", value) 对于充分大的 buf 将会生成的内容相同。

参数

value - 要转换的数值

返回值

保有转换后值的宽字符串

异常

可能从 std::wstring 的构造函数抛出 std::bad_alloc 。

示例

#include <string>
#include <iostream>

int main() {
    double f = 23.43;
    std::wstring f_str = std::to_wstring(f);
    std::wcout << f_str;
}

输出：

23.430000

参阅

to_string
(C++11)
 转换整数或浮点值为 string
(函数)


std::basic_string_view

< cpp‎ | string
定义于头文件 <string_view> |
template< class CharT, class Traits = std::char_traits <CharT> > class basic_string_view; | (C++17 起)

类模板 basic_string_view 描述一个能指代常量连续仿 char 对象序列的对象，序列首元素在零位置。

std::basic_string_view 的每个特化均为可平凡复制 (TriviallyCopyable) 类型。

 (C++23 起)

典型的实现仅保有二个成员：指向常 CharT 的指针和大小。

提供数种对常用字符类型的 typedef ：

定义于头文件 <string_view>
类型 | 定义
std::string_view | std::basic_string_view<char>
std::wstring_view | std::basic_string_view<wchar_t>
std::u8string_view (C++20) | std::basic_string_view<char8_t>
std::u16string_view | std::basic_string_view<char16_t>
std::u32string_view | std::basic_string_view<char32_t>

模板形参

CharT | - | 字符类型
Traits | - | 指定字符类型上操作的字符特征 (CharTraits) 类。同 basic_string ， Traits::char_type 必须指名同 CharT 的类型，否则程序为谬构。

成员类型

成员类型 | 定义
traits_type | Traits
value_type | CharT
pointer | CharT*
const_pointer | const CharT*
reference | CharT&
const_reference | const CharT&
const_iterator | 实现定义的常老式随机访问迭代器 (LegacyRandomAccessIterator) 、常量表达式迭代器 (ConstexprIterator) (C++20 起)兼老式连续迭代器 (LegacyContiguousIterator) ，其 value_type 为 CharT
iterator | const_iterator
const_reverse_iterator | std::reverse_iterator <const_iterator>
reverse_iterator | const_reverse_iterator
size_type | std::size_t
difference_type | std::ptrdiff_t

注解： iterator 与 const_iterator 是同一类型，因为 string_view 是到常字符序列中的视图。

容器 (Container) 的迭代器类型上的所有要求亦应用于 basic_string_view 的 iterator 和 const_iterator 类型。

成员函数

(构造函数)
 构造 basic_string_view
(公开成员函数)
operator=
 对视图赋值
(公开成员函数)
迭代器
begincbegin
 返回指向起始位置的迭代器
(公开成员函数)
endcend
 返回指向结尾的迭代器
(公开成员函数)
rbegincrbegin
 返回指向起始的反向迭代器
(公开成员函数)
rendcrend
 返回指向结尾的反向迭代器
(公开成员函数)
元素访问
operator[]
 访问指定字符
(公开成员函数)
at
 访问指定字符，带有边界检查
(公开成员函数)
front
 访问首个字符
(公开成员函数)
back
 访问最末字符
(公开成员函数)
data
 返回指向视图首字符的指针
(公开成员函数)
容量
sizelength
 返回字符数
(公开成员函数)
max_size
 返回最大字符数
(公开成员函数)
empty
 检查视图是否为空
(公开成员函数)
修改器
remove_prefix
 以后移起点收缩视图
(公开成员函数)
remove_suffix
 以前移终点收缩视图
(公开成员函数)
swap
 交换内容
(公开成员函数)
操作
copy
 复制字符
(公开成员函数)
substr
 返回子串
(公开成员函数)
compare
 比较二个视图
(公开成员函数)
starts_with
(C++20)
 检查 string_view 是否始于给定前缀
(公开成员函数)
ends_with
(C++20)
 检查 string_view 是否终于给定后缀
(公开成员函数)
contains
(C++23)
 检查字符串视图是否含有给定的子串或字符
(公开成员函数)
find
 在视图中查找字符
(公开成员函数)
rfind
 寻找子串的最后一次出现
(公开成员函数)
find_first_of
 查找字符的首次出现
(公开成员函数)
find_last_of
 查找字符的最后一次出现
(公开成员函数)
find_first_not_of
 查找字符的首次不出现
(公开成员函数)
find_last_not_of
 查找字符的最后一次不出现
(公开成员函数)

常量
npos
[静态]
 特殊值。准确含义依赖于语境。
(公开静态成员常量)

非成员函数

operator==operator!=operator<operator>operator<=operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 以字典序比较两个字符串视图
(函数模板)
输入/输出
operator<<
 进行字符串视图的流输出
(函数模板)

字面量

定义于内联命名空间 std::literals::string_view_literals
operator""sv
(C++17)
 创建一个字符数组字面量的字符串视图
(函数)

辅助类

std::hash<std::string_view>std::hash<std::wstring_view>std::hash<std::u8string_view>std::hash<std::u16string_view>std::hash<std::u32string_view>
(C++17)(C++17)(C++20)(C++17)(C++17)
 string_view 的散列支持
(类模板特化)

辅助模板

template<class CharT, class Traits> inline constexpr bool ranges::enable_borrowed_range<std::basic_string_view<CharT, Traits>> = true; | (C++20 起)

std::ranges::enable_borrowed_range 的此特化使得 basic_string_view 满足 borrowed_range 。

template<class CharT, class Traits> inline constexpr bool ranges::enable_view<std::basic_string_view<CharT, Traits>> = true; | (C++20 起)

std::ranges::enable_view 的此特化使得 basic_string_view 满足 view 。

推导指引 (C++20 起)

注解

程序员负责确保 std::string_view 不在被指向数组的生存期外继续生存：

std::string_view good("a string literal");   // OK ： "good" 指向静态数组
std::string_view bad("a temporary string"s); // "bad" 保有悬垂指针

即使在 C++23 中引入的正式要求前，所有既存实现中 std::basic_string_view 的特化已经为可平凡复制类型。

示例

#include <iostream>
#include <string_view>

int main() {
    constexpr std::string_view unicode[] {
        "▀▄─", "▄▀─", "▀─▄", "▄─▀"
    };

    for (int y{}, p{}; y != 6; ++y, p = ((p + 1) % 4)) {
        for (int x{}; x != 16; ++x)
            std::cout << unicode[p];
        std::cout << '\n';
    }
}

可能的输出：

▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─
▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─
▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄
▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀
▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─▀▄─
▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─▄▀─


std::basic_string_view<CharT,Traits>::at

< cpp‎ | string‎ | basic string view
constexpr const_reference at(size_type pos) const; | (C++17 起)

返回到在指定位置 pos 的字符的引用。进行边界检查，非法访问时将抛出 std::out_of_range 类型异常。

参数

pos - 要返回的字符的位置

返回值

到请求字符的引用。

异常

若 pos >= size() 则抛出 std::out_of_range 。

复杂度

常数。

示例

#include <iostream>
#include <stdexcept>
#include <string_view>

int main()
{
    std::string_view str_view("abcdef");

    try {
        for (std::size_t i = 0; true; ++i)
            std::cout << i << ": " << str_view.at(i) << '\n';
    }
    catch (const std::out_of_range& e) {
        std::cout << "Whooops. Index is out of range.\n";
        std::cout << e.what() << '\n';
    }
}

可能的输出：

0: a
1: b
2: c
3: d
4: e
5: f
6: Whooops. Index is out of range.
basic_string_view::at: __pos (which is 6) >= this->size() (which is 6)

参阅

operator[]
 访问指定字符
(公开成员函数)


std::basic_string_view<CharT,Traits>::back

< cpp‎ | string‎ | basic string view
constexpr const_reference back() const; | (C++17 起)

返回到视图末字符的引用，若 empty() == true 则行为未定义。

参数

（无）

返回值

到末字符的引用，等价于 operator[](size() - 1) 。

复杂度

常数。

参阅

front | 访问首个字符 (公开成员函数)
empty | 检查视图是否为空 (公开成员函数)


std::basic_string_view<CharT,Traits>::basic_string_view

< cpp‎ | string‎ | basic string view
constexpr basic_string_view() noexcept; | (1) | (C++17 起)
constexpr basic_string_view(const basic_string_view& other) noexcept = default; | (2) | (C++17 起)
constexpr basic_string_view(const CharT* s, size_type count); | (3) | (C++17 起)
constexpr basic_string_view(const CharT* s); | (4) | (C++17 起)
template<class It, class End> constexpr basic_string_view(It first, End last); | (5) | (C++20 起)
template<class R> constexpr basic_string_view(R&& r); | (6) | (C++23 起)
constexpr basic_string_view( std::nullptr_t ) = delete; | (7) | (C++23 起)
1) 默认构造函数。构造空的 basic_string_view 。构造后， data() 等于 nullptr ，而 size() 等于 0 。
2) 复制构造函数。构造内容同 other 的视图。构造后， data() 等于 other.data() ，而 size() 等于 other.size() 。
3) 构造始于 s 所指向元素的字符数组的首 count 个字符的视图。 s 可包含空字符。若 [s, s+count) 不是合法范围，则行为未定义（尽管构造函数可能不访问此范围的任何元素）。构造后， data() 等于 s ，而 size() 等于 count 。
4) 构造一个 s 所指向的空终止字符串的视图，不包含终止空字符。视图的长度如同以 Traits::length(s) 确定。若 [s, s+Traits::length(s)) 不是合法范围，则行为未定义。构造后， data() 等于 s ，而 size() 等于 Traits::length(s) 。
5) 构造范围 [first, last) 上的 basic_string_view 。若 [first, last) 不是合法范围、若 It 不实际实现 contiguous_iterator 或若 End 不实际实现 It 的 sized_sentinel_for 则行为未定义。构造后 data() 等于 std::to_address(first) 而 size() 等于 last - first 。

此重载仅若

  • It 满足 contiguous_iterator ，
  • End 满足 It 的 sized_sentinel_for ，
  • std::iter_value_t<It> 与 CharT 为同一类型且
  • End 不可转换到 std::size_t
才参与重载决议。
6) 构造范围 r 上的 basic_string_view 。构造后 data() 等于 ranges::data(r) 而 size() 等于 ranges::size(r) 。

此重载仅若

  • std::remove_cvref_t<R> 与 basic_string_view 不是同一类型，
  • R 实现 contiguous_range 与 sized_range ，
  • ranges::range_value_t<R> 与 CharT 为同一类型，
  • R 不可转换成 const CharT* ，
  • 令 d 为 std::remove_cvref_t<R> 类型左值， d.operator :: std::basic_string_view <CharT, Traits>() 不是合法的表达式，且
  • 若有限定标识 R::traits_type 合法并代表理性，则它与 Traits 相同才参与重载决议。
7) 不能从 nullptr 构造 basic_string_view 。

参数

other | - | 用以初始化视图的另一视图
s | - | 用以初始化视图的指向字符数组或 C 字符串的指针
count | - | 要包含于视图的字符数
first | - | 指向序列首字符的迭代器
last | - | 指向序列尾字符后一位置的迭代器或另一哨位
r | - | 含有序列的连续范围

复杂度

1-3,5-6) 常数
4) 与 s 的长度成线性

示例

#include <array>
#include <iostream>
#include <string>
#include <string_view>
int main()
{
    constexpr std::wstring_view wcstr_v = L"xyzzy";

    char array[3] = {'B', 'a', 'r'};
    std::string_view array_v(array, std::size(array));

    std::string cppstr = "Foo";
    std::string_view cppstr_v(cppstr);

    std::array ar = {'P', 'u', 'b'};
    std::string_view ar_v(ar.begin(), ar.end()); // C++20

    std::cout << cppstr_v << ' '
              << array_v << ' '
              << ar_v << ' '
              << wcstr_v.size() << '\n';
}

输出：

Foo Bar Pub 5

参阅

operator= | 对视图赋值 (公开成员函数)
(构造函数) | 构造 basic_string (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)


std::basic_string_view<CharT,Traits>::begin, std::basic_string_view<CharT,Traits>::cbegin

< cpp‎ | string‎ | basic string view
constexpr const_iterator begin() const noexcept; | (C++17 起)
constexpr const_iterator cbegin() const noexcept; | (C++17 起)

返回指向视图首字符的迭代器。

参数

（无）

返回值

指向首字符的 const_iterator

复杂度

常数

示例

#include <iostream>
#include <string_view>

int main()
{
    std::string_view str_view("abcd");

    auto begin = str_view.begin();
    auto cbegin = str_view.cbegin();

    std::cout << *begin << '\n';
    std::cout << *cbegin << '\n';

    std::cout << std::boolalpha << (begin == cbegin) << '\n';
    std::cout << std::boolalpha << (*begin == *cbegin) << '\n';
}

输出：

a
a
true
true

参阅

endcend
 返回指向结尾的迭代器
(公开成员函数)


std::basic_string_view<CharT,Traits>::compare

< cpp‎ | string‎ | basic string view
constexpr int compare(basic_string_view v) const noexcept; | (1) | (C++17 起)
constexpr int compare(size_type pos1, size_type count1, basic_string_view v) const; | (2) | (C++17 起)
constexpr int compare(size_type pos1, size_type count1, basic_string_view v, size_type pos2, size_type count2) const; | (3) | (C++17 起)
constexpr int compare(const CharT* s) const; | (4) | (C++17 起)
constexpr int compare(size_type pos1, size_type count1, const CharT* s) const; | (5) | (C++17 起)
constexpr int compare(size_type pos1, size_type count1, const CharT* s, size_type count2) const; | (6) | (C++17 起)

比较二个字符序列。

1) 要比较的序列长度 rlen 是 size() 与 v.size() 的较小者。该函数通过调用 traits::compare(data(), v.data(), rlen) 比较二个视图，并根据下表返回一个值：
条件 |  | 结果 | 返回值
Traits::compare(data(), v.data(), rlen) < 0 |  | *this 小于 v | <0
Traits::compare(data(), v.data(), rlen) == 0 | size() < v.size() | *this 小于 v | <0
 | size() == v.size() | *this 等于 v | ​0​
 | size() > v.size() | *this 大于 v | >0
Traits::compare(data(), v.data(), rlen) > 0 |  | *this 大于 v | >0
2) 等价于 substr(pos1, count1).compare(v) 。
3) 等价于 substr(pos1, count1).compare(v.substr(pos2, count2)) 。
4) 等价于 compare(basic_string_view(s)) 。
5) 等价于 substr(pos1, count1).compare(basic_string_view(s)) 。
6) 等价于 substr(pos1, count1).compare(basic_string_view(s, count2)) 。

参数

v | - | 要比较的视图
s | - | 指向要比较的字符串的指针
count1 | - | 此视图的要比较的字符数
pos1 | - | 此视图中要比较的首字符位置
count2 | - | 给定视图的要比较的字符数
pos2 | - | 给定视图的要比较的首字符位置

返回值

若此视图小于另一字符序列则为负值，若二个字符序列相等则为零，若此视图大于另一字符序列则为正值。

复杂度

1) 与比较的字符数成线性。

参阅

operator==operator!=operator<operator>operator<=operator>=operator<=>
(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)
 以字典序比较两个字符串视图
(函数模板)


std::basic_string_view<CharT,Traits>::contains

< cpp‎ | string‎ | basic string view
constexpr bool contains( basic_string_view sv ) const noexcept; | (1) | (C++23 起)
constexpr bool contains( CharT c ) const noexcept; | (2) | (C++23 起)
constexpr bool contains( const CharT* s ) const; | (3) | (C++23 起)

检查字符串视图是否含有给定的子串，其中

1) 子串为字符串视图。
2) 子串为单个字符。
3) 字串为空终止字符串。

所有三个重载都等价于 return find(x) != npos; ，其中 x 为参数。

参数

sv | - | 字符串视图
c | - | 单个字符
s | - | 空终止字符串

返回值

若字符串视图含有给定的子串则为 true ，否则为 false 。

示例

#include <iostream>
#include <string_view>

auto main() -> int
{
    using namespace std::literals;

    std::cout
        << std::boolalpha

        // bool contains(basic_string_view x) const noexcept;
        << "https://cppreference.com"sv.contains("cpp"sv)  << ' ' // true
        << "https://cppreference.com"sv.contains("java"sv) << ' ' // false

        // bool contains(CharT x) const noexcept;
        << "C++23"sv.contains('+') << ' ' // true
        << "C++23"sv.contains('-') << ' ' // false

        // bool contains(const CharT* x) const;
        << std::string_view("basic_string_view").contains("string") << ' ' // true
        << std::string_view("basic_string_view").contains("String") << ' ' // false
        << '\n';
}

输出：

true false true false true false

参阅

starts_with (C++20) | 检查 string_view 是否始于给定前缀 (公开成员函数)
ends_with (C++20) | 检查 string_view 是否终于给定后缀 (公开成员函数)
find | 在视图中查找字符 (公开成员函数)
substr | 返回子串 (公开成员函数)


std::basic_string_view<CharT,Traits>::copy

< cpp‎ | string‎ | basic string view
size_type copy( CharT* dest, size_type count, size_type pos = 0 ) const; | (C++17 起) (C++20 前)
constexpr size_type copy( CharT* dest, size_type count, size_type pos = 0 ) const; | (C++20 起)

复制子串 [pos, pos + rcount) 到 dest 所指向的字符序列，其中 rcount 是 count 与 size() - pos 中较小者。

等价于 Traits::copy(dest, data() + pos, rcount) 。

参数

dest | - | 指向目标字符串的指针
pos | - | 首字符的位置
count | - | 请求的字符串长度

返回值

复制的字符数

异常

若 pos > size() 则抛出 std::out_of_range 。

复杂度

与 rcount 成线性。

参阅

substr
 返回子串
(公开成员函数)


std::basic_string_view<CharT,Traits>::data

< cpp‎ | string‎ | basic string view
constexpr const_pointer data() const noexcept; | (C++17 起)

返回指向底层字符数组的指针。该指针满足范围 [data(); data() + size()) 合法，且其中的值与视图的值对应。

参数

（无）

返回值

指向底层字符数组的指针。

复杂度

常数。

注解

不同于 std::basic_string::data() 和字符串字面量， data() 可以返回指向非空终止的缓冲区的指针。从而将 data() 传递给一个仅接收 const CharT* 并期待空终止字符串的子程序是一个典型错误。

示例

#include <iostream>
#include <cstring>
#include <cwchar>
#include <string>
#include <string_view>
int main()
{
    std::wstring_view wcstr_v = L"xyzzy";
    std::cout << std::wcslen(wcstr_v.data()) << '\n';
    // OK ：底层字符数组为空终止

    char array[3] = {'B', 'a', 'r'};
    std::string_view array_v(array, sizeof array);
    // std::cout << std::strlen(array_v.data()) << '\n';
    // 错误：底层字符数组非空终止

    std::string str(array_v.data(), array_v.size()); // OK
    std::cout << std::strlen(str.data()) << '\n';
    // OK ： std::string 的底层字符数组始终为空终止
}

输出：

5
3

参阅

front | 访问首个字符 (公开成员函数)
back | 访问最末字符 (公开成员函数)


std::basic_string_view 的推导指引

< cpp‎ | string‎ | basic string view
定义于头文件 <string_view> |  |
template<class It, class End> basic_string_view(It, End) -> basic_string_view<std::iter_value_t<It>>; | (1) | (C++20 起)
template<class R> basic_string_view(R&&) -> basic_string_view<ranges::range_value_t<R>>; | (2) | (C++23 起)

为 std::basic_string_view 提供这些推导指引。

1) 此推导指引允许从迭代器-哨位对推导字符类型。此重载仅若 It 满足 contiguous_iterator 且 End 满足 It 的 sized_sentinel_for 才参与重载决议。
2) 此推导指引允许从范围推导字符类型。此重载仅若 R 满足 contiguous_range 才参与重载决议。

示例

#include <array>
#include <iostream>
#include <string_view>

int main()
{
    std::array a1 {'n', 'u', 'c', 'l', 'e', 'o', 'n', 's', ':', '\n'};
    std::basic_string_view s1(a1.cbegin(), a1.cend()); // 推导： CharT -> char
    static_assert(std::is_same_v<decltype(s1)::value_type, char>);
    std::cout << s1;

    std::array a2 {L'p', L'r', L'o', L't', L'o', L'n', L's', L'\n'};
    std::basic_string_view s2(a2.cbegin(), a2.cend()); // 推导： CharT -> wchar_t
    static_assert(std::is_same_v<decltype(s2)::value_type, wchar_t>);
    std::wcout << s2;

    std::array<long, 9> a3 {'n', 'e', 'u', 't', 'r', 'o', 'n', 's', '\n'};
    std::basic_string_view s3(a3.cbegin(), a3.cend()); // 推导： CharT -> long
    static_assert(std::is_same_v<decltype(s3)::value_type, long>);
    for (const auto e : s3) { std::cout << static_cast<char>(e); }
}

输出：

nucleons:
protons
neutrons


std::basic_string_view<CharT,Traits>::empty

< cpp‎ | string‎ | basic string view
constexpr bool empty() const noexcept; | (C++17 起) (C++20 前)
[[nodiscard]] constexpr bool empty() const noexcept; | (C++20 起)

检查视图是否无字符，即是否 size() == 0 。

参数

（无）

返回值

若视图为空则为 true ，否则为 false 。

复杂度

常量。

示例

#include <string_view>
#include <iostream>

void check_string(std::string_view ref)
{
        // 打印以单引号环绕的字符串、它的长度及其是否为空。
        std::cout << std::boolalpha
                  << "'" << ref << "' has " << ref.size()
                  << " character(s); emptiness: " << ref.empty() << '\n';
}

int main(int argc, char **argv)
{
        // 空字符串
        check_string("");

        // 几乎始终非空： argv[0]
        if (argc > 0)
                check_string(argv[0]);
}

可能的输出：

'' has 0 character(s); emptiness: true
'./a.out' has 7 character(s); emptiness: false

参阅

sizelength | 返回字符数 (公开成员函数)
max_size | 返回最大字符数 (公开成员函数)


std::basic_string_view<CharT,Traits>::end, std::basic_string_view<CharT,Traits>::cend

< cpp‎ | string‎ | basic string view
constexpr const_iterator end() const noexcept; | (C++17 起)
constexpr const_iterator cend() const noexcept; | (C++17 起)

返回指向视图末字符后一字符的迭代器。此字符表现为占位符，试图访问它会导致未定义行为。

参数

（无）

返回值

指向末字符后一字符的 const_iterator 。

复杂度

常数

示例

#include <iostream>
#include <iterator>
#include <string_view>

int main()
{
    std::string_view str_view("abcd");

    auto end = str_view.end();
    auto cend = str_view.cend();

    std::cout << *std::prev(end) << '\n';
    std::cout << *std::prev(cend) << '\n';

    std::cout << std::boolalpha << (end == cend) << '\n';
}

输出：

d
d
true

参阅

begincbegin
 返回指向起始位置的迭代器
(公开成员函数)


std::basic_string_view<CharT,Traits>::ends_with

< cpp‎ | string‎ | basic string view
constexpr bool ends_with( basic_string_view sv ) const noexcept; | (1) | (C++20 起)
constexpr bool ends_with( CharT c ) const noexcept; | (2) | (C++20 起)
constexpr bool ends_with( const CharT* s ) const; | (3) | (C++20 起)

检查 string_view 是否终于给定后缀，其中

1) 后缀为 string_view 。等效地返回 size() >= sv.size() && compare(size() - sv.size(), npos, sv) == 0
2) 后缀为单个字符。等效地返回 !empty() && Traits::eq(back(), c)
3) 后缀为空终止字符串。等效地返回 ends_with(basic_string_view(s))

参数

sv | - | 可能为来自 std::basic_string 转换结果的字符串视图
c | - | 单个字符
s | - | 空终止字符串

返回值

若 string_view 终于给定后缀则为 true ，否则为 false 。

示例

#include <iostream>
#include <string_view>

auto main() -> int
{
    using namespace std::literals;

    std::cout
        << std::boolalpha

        // (1) bool ends_with( basic_string_view sv ) const noexcept;
        << std::string_view("https://cppreference.com").ends_with(".com"sv) << ' ' // true
        << std::string_view("https://cppreference.com").ends_with(".org"sv) << ' ' // false

        // (2) bool ends_with( CharT c ) const noexcept;
        << std::string_view("C++20").ends_with('0') << ' ' // true
        << std::string_view("C++20").ends_with('3') << ' ' // false

        // (3) bool ends_with( const CharT* s ) const;
        << std::string_view("string_view").ends_with("view") << ' ' // true
        << std::string_view("string_view").ends_with("View") << ' ' // false
        << '\n';
}

输出：

true false true false true false

参阅

starts_with (C++20) | 检查 string_view 是否始于给定前缀 (公开成员函数)
starts_with (C++20) | 检查 string 是否始于给定前缀 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
ends_with (C++20) | 检查 string 是否终于给定后缀 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
contains (C++23) | 检查字符串是否含有给定的子串或字符 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
contains (C++23) | 检查字符串视图是否含有给定的子串或字符 (公开成员函数)
compare | 比较二个视图 (公开成员函数)


std::basic_string_view<CharT,Traits>::find

< cpp‎ | string‎ | basic string view
constexpr size_type find(basic_string_view v, size_type pos = 0) const noexcept; | (1) | (C++17 起)
constexpr size_type find(CharT ch, size_type pos = 0) const noexcept; | (2) | (C++17 起)
constexpr size_type find(const CharT* s, size_type pos, size_type count) const; | (3) | (C++17 起)
constexpr size_type find(const CharT* s, size_type pos = 0) const; | (4) | (C++17 起)

寻找首个等于给定字符序列的子串。

1) 在此视图中寻找 v 的首次出现，从位置 pos 开始。
2) 等价于 find(basic_string_view( std::addressof (ch), 1), pos) 。
3) 等价于 find(basic_string_view(s, count), pos) 。
4) 等价于 find(basic_string_view(s), pos) 。

参数

v | - | 要搜索的子串
pos | - | 要开始搜索的位置
count | - | 要搜索的子串长度
s | - | 指向要搜索的字符串的指针
ch | - | 要搜索的字符

返回值

找到的子串的首字符位置，或者若找不到子串则为 npos 。

复杂度

最坏情况为 O(size() * v.size()) 。

参阅

rfind | 寻找子串的最后一次出现 (公开成员函数)
find_first_of | 查找字符的首次出现 (公开成员函数)
find_last_of | 查找字符的最后一次出现 (公开成员函数)
find_first_not_of | 查找字符的首次不出现 (公开成员函数)
find_last_not_of | 查找字符的最后一次不出现 (公开成员函数)


std::basic_string_view<CharT,Traits>::find_first_not_of

< cpp‎ | string‎ | basic string view
constexpr size_type find_first_not_of(basic_string_view v, size_type pos = 0) const noexcept; | (1) | (C++17 起)
constexpr size_type find_first_not_of(CharT c, size_type pos = 0) const noexcept; | (2) | (C++17 起)
constexpr size_type find_first_not_of(const CharT* s, size_type pos, size_type count) const; | (3) | (C++17 起)
constexpr size_type find_first_not_of(const CharT* s, size_type pos = 0) const; | (4) | (C++17 起)

寻找首个不等于给定字符序列中任何字符的字符。

1) 在此视图中寻找首个不等于 v 中任意字符的字符，从位置 pos 开始。
2) 等价于 find_first_not_of(basic_string_view( std::addressof (c), 1), pos) 。
3) 等价于 find_first_not_of(basic_string_view(s, count), pos) 。
4) 等价于 find_first_not_of(basic_string_view(s), pos) 。

参数

v | - | 要搜索的视图
pos | - | 要开始搜索的位置
count | - | 要比较的字符串的长度
s | - | 指向要比较的字符串的指针
ch | - | 要比较的字符

返回值

首个不等于给定字符串中任意字符的字符位置，或若找不到这些字符则为 npos 。

复杂度

最坏情况为 O(size() * v.size()) 。

参阅

find | 在视图中查找字符 (公开成员函数)
rfind | 寻找子串的最后一次出现 (公开成员函数)
find_first_of | 查找字符的首次出现 (公开成员函数)
find_last_of | 查找字符的最后一次出现 (公开成员函数)
find_last_not_of | 查找字符的最后一次不出现 (公开成员函数)


std::basic_string_view<CharT,Traits>::find_first_of

< cpp‎ | string‎ | basic string view
constexpr size_type find_first_of(basic_string_view v, size_type pos = 0) const noexcept; | (1) | (C++17 起)
constexpr size_type find_first_of(CharT c, size_type pos = 0) const noexcept; | (2) | (C++17 起)
constexpr size_type find_first_of(const CharT* s, size_type pos, size_type count) const; | (3) | (C++17 起)
constexpr size_type find_first_of(const CharT* s, size_type pos = 0) const; | (4) | (C++17 起)

寻找首个等于给定字符序列中任意字符的字符。

1) 寻找 v 的任意字符在此视图中的首次出现，从位置 pos 开始。
2) 等价于 find_first_of(basic_string_view( std::addressof (c), 1), pos) 。
3) 等价于 find_first_of(basic_string_view(s, count), pos) 。
4) 等价于 find_first_of(basic_string_view(s), pos) 。

参数

v | - | 要搜索的视图
pos | - | 要开始搜索的位置
count | - | 要搜索的字符串的长度
s | - | 指向要搜索的字符串的指针
c | - | 要搜索的字符

返回值

子串的任意字符的首次出现位置，或者若找不到这些字符则为 npos 。

复杂度

最坏情况为 O(size() * v.size()) 。

参阅

find | 在视图中查找字符 (公开成员函数)
rfind | 寻找子串的最后一次出现 (公开成员函数)
find_last_of | 查找字符的最后一次出现 (公开成员函数)
find_first_not_of | 查找字符的首次不出现 (公开成员函数)
find_last_not_of | 查找字符的最后一次不出现 (公开成员函数)


std::basic_string_view<CharT,Traits>::find_last_not_of

< cpp‎ | string‎ | basic string view
constexpr size_type find_last_not_of(basic_string_view v, size_type pos = npos) const noexcept; | (1) | (C++17 起)
constexpr size_type find_last_not_of(CharT c, size_type pos = npos) const noexcept; | (2) | (C++17 起)
constexpr size_type find_last_not_of(const CharT* s, size_type pos, size_type count) const; | (3) | (C++17 起)
constexpr size_type find_last_not_of(const CharT* s, size_type pos = npos) const; | (4) | (C++17 起)

寻找不等于给定字符序列的任意字符的最后一个字符。

1) 在此视图中寻找不等于 v 的任意字符的最后一个字符，从位置 pos 开始。
2) 等价于 find_last_not_of(basic_string_view( std::addressof (c), 1), pos) 。
3) 等价于 find_last_not_of(basic_string_view(s, count), pos) 。
4) 等价于 find_last_not_of(basic_string_view(s), pos) 。

参数

v | - | 要搜索的视图
pos | - | 要开始搜索的位置
count | - | 要比较的字符串长度
s | - | 指向要比较的字符串的指针
ch | - | 要比较的字符

返回值

最后一个不等于给定字符串中任意字符的字符位置，或若找不到这些字符则为 npos 。

复杂度

最坏情况为 O(size() * v.size()) 。

参阅

find | 在视图中查找字符 (公开成员函数)
rfind | 寻找子串的最后一次出现 (公开成员函数)
find_first_of | 查找字符的首次出现 (公开成员函数)
find_last_of | 查找字符的最后一次出现 (公开成员函数)
find_first_not_of | 查找字符的首次不出现 (公开成员函数)


std::basic_string_view<CharT,Traits>::find_last_of

< cpp‎ | string‎ | basic string view
constexpr size_type find_last_of(basic_string_view v, size_type pos = npos) const noexcept; | (1) | (C++17 起)
constexpr size_type find_last_of(CharT c, size_type pos = npos) const noexcept; | (2) | (C++17 起)
constexpr size_type find_last_of(const CharT* s, size_type pos, size_type count) const; | (3) | (C++17 起)
constexpr size_type find_last_of(const CharT* s, size_type pos = npos) const; | (4) | (C++17 起)

寻找最后一个给定字符序列中字符之一相等的字符。不指定准确的搜索算法。搜索只考虑区间 [0; pos] 。若区间中不存在字符，则将返回 npos 。

1) 寻找此视图中 v 的任意字符的最后一次出现，到位置 pos 结束。
2) 等价于 find_last_of(basic_string_view( std::addressof (c), 1), pos) 。
3) 等价于 find_last_of(basic_string_view(s, count), pos) 。
4) 等价于 find_last_of(basic_string_view(s), pos) 。

参数

v | - | 要搜索的视图
pos | - | 要开始搜索的位置
count | - | 要搜索的字符串的长度
s | - | 指向要搜索的字符串的指针
ch | - | 要搜索的字符

返回值

子串的任意字符的最后一次出现位置，或者若找不到这些字符则为 npos 。

复杂度

最坏情况为 O(size() * v.size()) 。

参阅

find | 在视图中查找字符 (公开成员函数)
rfind | 寻找子串的最后一次出现 (公开成员函数)
find_first_of | 查找字符的首次出现 (公开成员函数)
find_first_not_of | 查找字符的首次不出现 (公开成员函数)
find_last_not_of | 查找字符的最后一次不出现 (公开成员函数)


std::basic_string_view<CharT,Traits>::front

< cpp‎ | string‎ | basic string view
constexpr const_reference front() const; | (C++17 起)

返回到视图首字符的引用。若 empty() == true 则行为未定义。

参数

（无）

返回值

到首字符的引用，等价于 operator[](0) 。

复杂度

常数。

参阅

back | 访问最末字符 (公开成员函数)
empty | 检查视图是否为空 (公开成员函数)


std::hash (std::string_view, std::wstring_view, std::u16string_view, std::u32string_view)

< cpp‎ | string‎ | basic string view
定义于头文件 <string_view> |
template<> struct hash< std::string_view >; | (C++17 起)
template<> struct hash< std::wstring_view >; | (C++17 起)
template<> struct hash<std::u8string_view>; | (C++20 起)
template<> struct hash< std::u16string_view >; | (C++17 起)
template<> struct hash< std::u32string_view >; | (C++17 起)

std::hash 对各种视图类的模板特化，目的是对视图哈希。

这些哈希等于对应的 std::basic_string 类的哈希：若 S 是标准 basic_string 类型，而 SV 是对应的 string_view 类型，且 s 是 S 类型对象，则 std::hash <S>()(s) == std::hash <SV>()(SV(s)) 。

参阅

hash
(C++11)
 散列函数对象
(类模板)


std::basic_string_view<CharT,Traits>::max_size

< cpp‎ | string‎ | basic string view
constexpr size_type max_size() const noexcept; | (C++17 起)

basic_string_view 所能引用的类 char 对象的最大数目。

参数

（无）

返回值

字符数的最大值。

复杂度

常数。

参阅

sizelength | 返回字符数 (公开成员函数)
empty | 检查视图是否为空 (公开成员函数)


std::basic_string_view<CharT,Traits>::npos

< cpp‎ | string‎ | basic string view
static constexpr size_type npos = size_type(-1); | (C++17 起)

这是等于 size_type 类型所能表示最大值的特殊值。准确的含义依赖于语境，不过通常期待视图下标的函数以之为视图尾指示器，而返回视图下标的函数以之为错误指示器。


std::literals::string_view_literals::operator""sv

< cpp‎ | string‎ | basic string view
定义于头文件 <string_view>
constexpr std::string_view
operator "" sv(const char* str, std::size_t len) noexcept;
 (1) (C++17 起)
constexpr std::u8string_view
operator "" sv(const char8_t* str, std::size_t len) noexcept;
 (2) (C++20 起)
constexpr std::u16string_view
operator "" sv(const char16_t* str, std::size_t len) noexcept;
 (3) (C++17 起)
constexpr std::u32string_view
operator "" sv(const char32_t* str, std::size_t len) noexcept;
 (4) (C++17 起)
constexpr std::wstring_view
operator "" sv(const wchar_t* str, std::size_t len) noexcept;
 (5) (C++17 起)

从字符数组字面量组成 string_view 。

1) 返回 std::string_view {str, len}
2) 返回 std::u8string_view{str, len}
3) 返回 std::u16string_view {str, len}
4) 返回 std::u32string_view {str, len}
5) 返回 std::wstring_view {str, len}

参数

str | - | 指向无修饰字符数组字面量起始的指针
len | - | 无修饰字符数组字面量的长度

返回值

string_view 字面量。

注解

这些运算符声明于命名空间 std::literals::string_view_literals ， literals 和 string_view_literals 均为内联命名空间。能以 using namespace std::literals 、 using namespace std::string_view_literals 及 using namespace std::literals::string_view_literals 取得对这些运算符的访问。

示例

#include <string_view>
#include <iostream>

int main()
{
    using namespace std::literals;

    std::string_view s1 = "abc\0\0def";
    std::string_view s2 = "abc\0\0def"sv;
    std::cout << "s1: " << s1.size() << " \"" << s1 << "\"\n";
    std::cout << "s2: " << s2.size() << " \"" << s2 << "\"\n";

    std::cout
        << "narrow string literal"sv.size() << '\n'
        << L"wide string literal"sv.size() << '\n'
        << R"(raw string literal)"sv.size() << '\n';
}

可能的输出：

s1: 3 "abc"
s2: 8 "abc^@^@def"
21
19
18

参阅

(构造函数)
 构造 basic_string_view
(公开成员函数)


std::basic_string_view<CharT,Traits>::operator=

< cpp‎ | string‎ | basic string view
constexpr basic_string_view& operator=( const basic_string_view& view ) noexcept = default; | (C++17 起)

以 view 的内容替换视图。

参数

view - 要复制的视图

返回值

*this

复杂度

常数。

示例

#include <iostream>
#include <string_view>
int main()
{
    std::string_view v = "Hello, world";
    v = v.substr(7);
    std::cout << v << '\n';
}

输出：

world

参阅

(构造函数)
 构造 basic_string_view
(公开成员函数)


std::basic_string_view<CharT,Traits>::operator[]

< cpp‎ | string‎ | basic string view
constexpr const_reference operator[](size_type pos) const; | (C++17 起)

返回到位于指定位置 pos 的字符的 const 引用。

不进行边界检查：若 pos >= size() 则行为未定义。

参数

pos - 要返回的字符位置

返回值

到所请求字符的 const 引用。

异常

不抛出。

复杂度

常数。

注解

不同于 std::basic_string::operator[] ， std::basic_string_view::operator[](size()) 拥有未定义行为，而非返回 CharT() 。

示例

#include <iostream>
#include <string_view>
int main()
{
    std::string str = "Exemplar";
    std::string_view v = str;
    std::cout << v[2] << '\n';
//  v[2] = 'y'; // 错误：不能通过字符串视图修改
    str[2] = 'y';
    std::cout << v[2] << '\n';
}

输出：

e
y

参阅

at
 访问指定字符，带有边界检查
(公开成员函数)


operator==,!=,<,<=,>,>=,<=>(std::basic_string_view)

< cpp‎ | string‎ | basic string view
定义于头文件 <string_view>
template< class CharT, class Traits >

constexpr bool operator==( std::basic_string_view <CharT,Traits> lhs,

std::basic_string_view <CharT,Traits> rhs ) noexcept;
 (1) (C++17 起)
template< class CharT, class Traits >

constexpr bool operator!=( std::basic_string_view <CharT,Traits> lhs,

std::basic_string_view <CharT,Traits> rhs ) noexcept;
 (2) (C++17 起)
(C++20 前)
template< class CharT, class Traits >

constexpr bool operator<( std::basic_string_view <CharT,Traits> lhs,

std::basic_string_view <CharT,Traits> rhs ) noexcept;
 (3) (C++17 起)
(C++20 前)
template< class CharT, class Traits >

constexpr bool operator<=( std::basic_string_view <CharT,Traits> lhs,

std::basic_string_view <CharT,Traits> rhs ) noexcept;
 (4) (C++17 起)
(C++20 前)
template< class CharT, class Traits >

constexpr bool operator>( std::basic_string_view <CharT,Traits> lhs,

std::basic_string_view <CharT,Traits> rhs ) noexcept;
 (5) (C++17 起)
(C++20 前)
template< class CharT, class Traits >

constexpr bool operator>=( std::basic_string_view <CharT,Traits> lhs,

std::basic_string_view <CharT,Traits> rhs ) noexcept;
 (6) (C++17 起)
(C++20 前)
template< class CharT, class Traits >

constexpr /*comp-cat*/
operator<=>( std::basic_string_view <CharT,Traits> lhs,

std::basic_string_view <CharT,Traits> rhs ) noexcept;
 (7) (C++20 起)

比较二个视图。

通过 compare() 成员函数进行所有比较（其自身以 Traits::compare() 定义）：

  • 若 lhs 与 rhs 的大小相等且 lhs 中每个字符等于 rhs 在同一位置的字符，则二个视图相等。
  • 比较顺序按字典序进行——由等价于 std::lexicographical_compare 的函数进行比较。

三路比较运算符的返回类型（ /*comp-cat*/ ）为 Traits::comparison_category ，若该有限定标识合法并指代类型，否则为 std::weak_ordering 。若 /*comp-cat*/ 不是比较类别类型，则程序非良构。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

实现应对这些函数提供充足的额外 constexpr 及 noexcept 重载，以令 basic_string_view<CharT,Traits> 对象 sv 可以与另一带隐式转换成 basic_string_view<CharT,Traits> 的对象 t 比较，而且语义上与比较 sv 和 basic_string_view<CharT,Traits>(t) 相同。

参数

lhs, rhs - 要比较的视图

返回值

1-6) 若对应比较关系成立则为 true ，否则为 false 。
7) static_cast</*comp-cat*/>(lhs.compare(rhs) <=> 0) 。

复杂度

与视图大小成线性。

注解

充足的额外重载可通过一个参数类型中的非推导语境实现。

std::string_view 、 std::wstring_view 、 std::u8string_view 、 std::u16string_view 与 std::u32string_view 的三路比较结果类型为 std::strong_ordering 。

 (C++20 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3432 | C++20 | 未要求 operator<=> 的返回类型为比较类别类型 | 已要求


operator<<(std::basic_string_view)

< cpp‎ | string‎ | basic string view
定义于头文件 <string_view>
template <class CharT, class Traits>

std::basic_ostream <CharT, Traits>&
operator<<( std::basic_ostream <CharT, Traits>& os,

std::basic_string_view <CharT, Traits> v);
 (C++17 起)

表现为有格式输出函数 (FormattedOutputFunction) 。构造并检查 sentry 对象后，以下列方式确定输出格式填充：

a) 若 v.size() 不小于 os.width() ，则原态使用 [v.begin(), v.end()) ；
b) 否则，若 (os.flags() & ios_base::adjustfield) == ios_base::left ，则将 os.fill() 字符的 os.width()-v.size() 份副本置于字符序列前；
c) 否则，将 os.fill() 字符的 os.width()-v.size() 份副本置于字符序列后。

然后如同通过调用 os.rdbuf()->sputn(seq, n) ，存储每个来自结果序列（ v 的内容加上填充）于输出流 os ，其中 n= std::max (os.width(), str.size()) 。

最后，调用 os.width(0) 以取消 std::setw 的效果，若存在。

异常

若输出时抛异常，则可能抛出 std::ios_base::failure 。

参数

os | - | 字符输出流
v | - | 要插入的视图

返回值

os

参阅

operator<<operator>>
 执行字符串的流输入与输出
(函数模板)


std::basic_string_view<CharT,Traits>::rbegin, std::basic_string_view<CharT,Traits>::crbegin

< cpp‎ | string‎ | basic string view
constexpr const_reverse_iterator rbegin() const noexcept; | (C++17 起)
constexpr const_reverse_iterator crbegin() const noexcept; | (C++17 起)

返回指向逆向视图首字符的逆向迭代器。它对应非逆向视图的末字符。

参数

（无）

返回值

指向逆向视图首字符的 const_reverse_iterator

复杂度

常数

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string_view>

int main()
{
    std::ostream_iterator<char> out_it(std::cout);
    std::string_view str_view("abcdef");

    std::copy(str_view.rbegin(), std::next(str_view.rbegin(), 3), out_it);
    *out_it = '\n';

    std::copy(str_view.crbegin(), std::next(str_view.crbegin(), 3), out_it);
    *out_it = '\n';
}

输出：

fed
fed

参阅

rendcrend
 返回指向结尾的反向迭代器
(公开成员函数)


std::basic_string_view<CharT,Traits>::remove_prefix

< cpp‎ | string‎ | basic string view
constexpr void remove_prefix(size_type n); | (C++17 起)

前向移动视图起点 n 个字符。

若 n > size() 则行为未定义。

参数

n - 要从视图起始移除的字符数

返回值

（无）

复杂度

常数。

示例

#include <iostream>
#include <algorithm>
#include <string_view>
int main()
{
    std::string str = "   trim me";
    std::string_view v = str;
    v.remove_prefix(std::min(v.find_first_not_of(" "), v.size()));
    std::cout << "String: '" << str << "'\n"
              << "View  : '" << v << "'\n";
}

输出：

String: '   trim me'
View  : 'trim me'

参阅

remove_suffix
 以前移终点收缩视图
(公开成员函数)


std::basic_string_view<CharT,Traits>::remove_suffix

< cpp‎ | string‎ | basic string view
constexpr void remove_suffix(size_type n); | (C++17 起)

反向移动视图终点 n 个字符。

若 n > size() 则行为未定义。

参数

n - 要从视图终点移除的字符数

返回值

（无）

复杂度

常数。

示例

#include <iostream>
#include <string_view>
int main()
{
    char arr[] = {'a', 'b', 'c', 'd', '\0', '\0', '\0'};
    std::string_view v(arr, sizeof arr);
    auto trim_pos = v.find('\0');
    if(trim_pos != v.npos)
        v.remove_suffix(v.size() - trim_pos);
    std::cout << "Array: '" << arr << "', size=" << sizeof arr << '\n'
              << "View : '" << v << "', size=" << v.size() << '\n';
}

输出：

Array: 'abcd', size=7
View : 'abcd', size=4

参阅

remove_prefix
 以后移起点收缩视图
(公开成员函数)


std::basic_string_view<CharT,Traits>::rend, std::basic_string_view<CharT,Traits>::crend

< cpp‎ | string‎ | basic string view
constexpr const_reverse_iterator rend() const noexcept; | (C++17 起)
constexpr const_reverse_iterator crend() const noexcept; | (C++17 起)

返回指向逆向视图末字符的后一字符的逆向迭代器。它对应非逆向视图的首字符的前趋字符。此字符表现作占位符，试图访问它会导致未定义行为。

参数

（无）

返回值

指向逆向视图末字符后继字符的 const_reverse_iterator

复杂度

常数

示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string_view>

int main()
{
    std::ostream_iterator<char> out_it(std::cout);
    std::string_view str_view("abcdef");

    std::copy(str_view.rbegin(), str_view.rend(), out_it);
    *out_it = '\n';

    std::copy(str_view.crbegin(), str_view.crend(), out_it);
    *out_it = '\n';
}

输出：

fedcba
fedcba

参阅

rbegincrbegin
 返回指向起始的反向迭代器
(公开成员函数)


std::basic_string_view<CharT,Traits>::rfind

< cpp‎ | string‎ | basic string view
constexpr size_type rfind(basic_string_view v, size_type pos = npos) const noexcept; | (1) | (C++17 起)
constexpr size_type rfind(CharT c, size_type pos = npos) const noexcept; | (2) | (C++17 起)
constexpr size_type rfind(const CharT* s, size_type pos, size_type count) const; | (3) | (C++17 起)
constexpr size_type rfind(const CharT* s, size_type pos = npos) const; | (4) | (C++17 起)

寻找等于给定字符序列的最末子串。

1) 在此视图中寻找 v 的最后一次出现，从位置 pos 开始。
2) 等价于 rfind(basic_string_view( std::addressof (c), 1), pos) 。
3) 等价于 rfind(basic_string_view(s, count), pos) 。
4) 等价于 rfind(basic_string_view(s), pos) 。

参数

v | - | 要搜索的视图
pos | - | 要开始搜索的位置
count | - | 要搜索的子串长度
s | - | 指向要搜索的字符串的指针
ch | - | 要搜索的字符

返回值

找到子串的首个字符位置，或者若未找到该子串则为 npos 。

复杂度

最坏情况为 O(size() * v.size()) 。

参阅

find | 在视图中查找字符 (公开成员函数)
find_first_of | 查找字符的首次出现 (公开成员函数)
find_last_of | 查找字符的最后一次出现 (公开成员函数)
find_first_not_of | 查找字符的首次不出现 (公开成员函数)
find_last_not_of | 查找字符的最后一次不出现 (公开成员函数)


std::basic_string_view<CharT,Traits>::size, std::basic_string_view<CharT,Traits>::length

< cpp‎ | string‎ | basic string view
constexpr size_type size() const noexcept; | (C++17 起)
constexpr size_type length() const noexcept; | (C++17 起)

返回视图中的 CharT 元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

视图中的 CharT 元素数。

复杂度

常数。

示例

#include <string_view>
#include <iostream>

void check_string(std::string_view ref)
{
        // 打印以单引号环绕的字符串、它的长度及其是否为空。
        std::cout << std::boolalpha
                  << "'" << ref << "' has " << ref.size()
                  << " character(s); emptiness: " << ref.empty() << '\n';
}

int main(int argc, char **argv)
{
        // 空字符串
        check_string("");

        // 几乎始终非空： argv[0]
        if (argc > 0)
                check_string(argv[0]);
}

可能的输出：

'' has 0 character(s); emptiness: true
'./a.out' has 7 character(s); emptiness: false

参阅

empty | 检查视图是否为空 (公开成员函数)
max_size | 返回最大字符数 (公开成员函数)


std::basic_string_view<CharT,Traits>::starts_with

< cpp‎ | string‎ | basic string view
constexpr bool starts_with( std::basic_string_view sv) const noexcept; | (1) | (C++20 起)
constexpr bool starts_with(CharT c) const noexcept; | (2) | (C++20 起)
constexpr bool starts_with(const CharT* s) const; | (3) | (C++20 起)

检查 string_view 是否始于给定前缀，其中

1) 前缀为 string_view 。等效地返回 substr(0, sv.size()) == sv
2) 前缀为单个字符。等效地返回 !empty() && Traits::eq(front(), c)
3) 前缀为空终止字符串。等效地返回 starts_with(basic_string_view(s))

参数

sv | - | 可能为来自 std::basic_string 转换结果的字符串视图
c | - | 单个字符
s | - | 空终止字符串

返回值

若 string_view 始于给定前缀则为 true ，否则为 false 。

示例

#include <iostream>
#include <string_view>

auto main() -> int
{
    using namespace std::literals;

    std::cout
        << std::boolalpha

        // bool starts_with(basic_string_view x) const noexcept;
        << "https://cppreference.com"sv.starts_with("http"sv) << ' ' // true
        << "https://cppreference.com"sv.starts_with("ftp"sv) << ' '  // false

        // bool starts_with(CharT x) const noexcept;
        << "C++20"sv.starts_with('C') << ' ' // true
        << "C++20"sv.starts_with('J') << ' ' // false

        // bool starts_with(const CharT* x) const;
        << std::string_view("string_view").starts_with("string") << ' ' // true
        << std::string_view("string_view").starts_with("String") << ' ' // false
        << '\n';
}

输出：

true false true false true false

参阅

ends_with (C++20) | 检查 string_view 是否终于给定后缀 (公开成员函数)
starts_with (C++20) | 检查 string 是否始于给定前缀 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
ends_with (C++20) | 检查 string 是否终于给定后缀 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
contains (C++23) | 检查字符串是否含有给定的子串或字符 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
contains (C++23) | 检查字符串视图是否含有给定的子串或字符 (公开成员函数)
compare | 比较二个视图 (公开成员函数)


std::basic_string_view<CharT,Traits>::substr

< cpp‎ | string‎ | basic string view
constexpr basic_string_view substr(size_type pos = 0, size_type count = npos ) const; | (C++17 起)

返回子串 [pos, pos + rcount) 的视图，其中 rcount 是 count 与 size() - pos 中较小者。

参数

pos | - | 首字符的位置
count | - | 请求的长度

返回值

子串 [pos, pos + rcount) 的视图。

异常

若 pos > size() 则抛出 std::out_of_range 。

复杂度

常数。

参阅

copy | 复制字符 (公开成员函数)
find | 在视图中查找字符 (公开成员函数)


std::basic_string_view<CharT,Traits>::swap

< cpp‎ | string‎ | basic string view
constexpr void swap( basic_string_view& v ) noexcept; | (C++17 起)

将视图与 v 的内容交换。

参数

v - 要与之交换的视图

返回值

（无）

复杂度

常数。

示例

#include <string_view>
#include <iostream>

int main() {
    auto s1{ std::string_view{"⏺⏺⏺⏺⏺"} };
    auto s2{ std::string_view{"⏹⏹⏹⏹⏹"} };

    std::cout << "Before : " << s1 << ' ' << s2 << "\n";
    s1.swap(s2);
    std::cout << "After  : " << s1 << ' ' << s2 << "\n";
}

输出：

Before : ⏺⏺⏺⏺⏺ ⏹⏹⏹⏹⏹
After  : ⏹⏹⏹⏹⏹ ⏺⏺⏺⏺⏺

参阅

swap | 交换两个对象的值 (函数模板)
swap_ranges | 交换两个范围的元素 (函数模板)
swap | 交换内容 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)


空终止字节字符串

< cpp‎ | string

空终止字节字符串（ null-terminated byte string, NTBS ）是后随拥有零值的字节（空终止字符）的非零字节序列。字节字符串的每个字节编码某字符集的一个字符。例如，字符数组 {'\x63', '\x61', '\x74', '\0'} 是持有以 ASCII 编码的字符串 "cat" 的 NTBS 。

函数

字符分类
定义于头文件 <cctype>
isalnum
 检查字符是否为字母或数字
(函数)
isalpha
 检查字符是否为字母
(函数)
islower
 检查字符是否为小写
(函数)
isupper
 检查字符是否为大写字符
(函数)
isdigit
 检查字符是否为数字
(函数)
isxdigit
 检查字符是为十六进制字符
(函数)
iscntrl
 检查字符是否为控制字符
(函数)
isgraph
 检查字符是否为图形字符
(函数)
isspace
 检查字符是否为空白间隔字符
(函数)
isblank
(C++11)
 检查字符是否为空白字符
(函数)
isprint
 检查字符是否为打印字符
(函数)
ispunct
 检查字符是否为标点符
(函数)
字符操作
tolower
 转换字符为小写
(函数)
toupper
 转换字符为大写
(函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
转换为数值格式
定义于头文件 <cstdlib>
atof
 转换字节字符串为浮点值
(函数)
atoiatolatoll
(C++11)
 转换字节字符串为整数值
(函数)
strtolstrtoll
(C++11)
 转换字节字符串为整数值
(函数)
strtoulstrtoull
(C++11)
 转换字节字符串为无符号整数值
(函数)
strtofstrtodstrtold
 转换字节字符串为浮点值
(函数)
定义于头文件 <cinttypes>
strtoimaxstrtoumax
(C++11)(C++11)
 转换字节字符串为 std::intmax_t 或 std::uintmax_t
(函数)
字符串操作
定义于头文件 <cstring>
strcpy
 复制一个字符串给另一个
(函数)
strncpy
 复制来自一个字符串的一定量字符给另一个
(函数)
strcat
 连接两个字符串
(函数)
strncat
 连接两个字符串的一定量字符
(函数)
strxfrm
 变换字符串，使得 strcmp 会返回与 strcoll 相同的结果
(函数)
字符串检验
定义于头文件 <cstring>
strlen
 返回给定字符串的长度
(函数)
strcmp
 比较两个字符串
(函数)
strncmp
 比较两个字符串的一定量字符
(函数)
strcoll
 按照当前本地环境比较两个字符串
(函数)
strchr
 寻找字符的首次出现
(函数)
strrchr
 寻找字符的最后出现
(函数)
strspn
 返回仅由另一字节字符串中找到的字符组成的最大起始段的长度
(函数)
strcspn
 返回仅由另一字节字符串中找不到的字符组成的最大起始段的长度
(函数)
strpbrk
 寻找任何来自分隔符集合的字符的首个位置
(函数)
strstr
 寻找字符子串的首次出现
(函数)
strtok
 寻找字节字符串中的下个记号
(函数)
字符数组操作
定义于头文件 <cstring>
memchr
 在数组中搜索字符的首次出现
(函数)
memcmp
 比较两个缓冲区
(函数)
memset
 以一个字符填充缓冲区
(函数)
memcpy
 复制一个缓冲区到另一个
(函数)
memmove
 移动一个缓冲区到另一个
(函数)
杂项
定义于头文件 <cstring>
strerror
 返回给定错误码的文本版本
(函数)

参阅


std::atof

< cpp‎ | string‎ | byte
定义于头文件 <cstdlib>
double atof( const char *str );

转译 str 所指向的字节字符串中的浮点值。

函数会舍弃任何空白符（由 std::isspace() 确定），直至找到首个非空白符。然后它会取用尽可能多的字符，以构成合法的浮点数表示，并将它们转换成浮点值。合法的浮点值可以为下列之一：

  • 十进制浮点数表达式。它由下列部分组成：
  • (可选) 正或负号
  • 非空的十进制数字序列，可选地包含一个小数点字符（由当前的 C 本地环境确定）（定义有效数字）
  • (可选) e 或 E ，并跟随可选的正或负号，以及非空十进制数字序列（以 10 为底定义指数）
  • 十六进制浮点数表达式。它由下列部分组成：
  • (可选) 正或负号
  • 0x 或 0X
  • 非空的十六进制数字序列，选地包含一个小数点字符（由当前的 C 本地环境确定）（定义有效数字）
  • (可选) p 或 P ，并跟随可选的正或负号，以及非空十进制数字序列（以 2 为底定义指数）
  • 无穷大表达式。它由下列部分组成：
  • (可选) 正或负号
  • INF 或 INFINITY ，忽略大小写
  • 非数（NaN）表达式。它由下列部分组成：
  • (可选) 正或负号
  • NAN 或 NAN(char_sequence) ，忽略 NAN 部分的大小写。 char_sequence 只能由数字、拉丁字母和下划线构成。结果是一个静态的 NaN 浮点值。
 (C++11 起)
  • 任何其他可由当前 C 本地环境接受的表达式

参数

str - 指向要被转译的空终止字节字符串的指针

返回值

成功时为对应 str 内容的 double 值。若转换值落在返回类型范围外，则返回值未定义。若不能进行转换，则返回 0.0 。

示例

#include <cstdlib>
#include <iostream>

int main()
{
    std::cout << std::atof("0.0000000123") << '\n'
              << std::atof("0.012")        << '\n'
              << std::atof("15e16")        << '\n'
              << std::atof("-0x1afp-2")    << '\n'
              << std::atof("inF")          << '\n'
              << std::atof("Nan")          << '\n'
              << std::atof("invalid")      << '\n';
}

输出：

1.23e-08
0.012
1.5e+17
-107.75
inf
nan
0

参阅

stofstodstold (C++11)(C++11)(C++11) | 转换字符串为浮点值 (函数)
strtofstrtodstrtold | 转换字节字符串为浮点值 (函数)
from_chars (C++17) | 转换字符序列到整数或浮点值 (函数)
atoiatolatoll (C++11) | 转换字节字符串为整数值 (函数)


std::atoi, std::atol, std::atoll

< cpp‎ | string‎ | byte
定义于头文件 <cstdlib> |
int atoi( const char *str ); |
long atol( const char *str ); |
long long atoll( const char *str ); | (C++11 起)

转译 str 所指向的字节字符串中的整数值。

舍弃任何空白符，直至找到首个非空白符，然后接收尽可能多的字符以组成合法的整数表示，并转换之为整数值。合法的整数值含下列部分：

  • (可选) 正或负号
  • 数位

参数

str - 指向要转译的空终止字节字符串的指针

返回值

成功时为对应 str 内容的整数值。若转换出的值落在对应返回类型的范围外，则返回值未定义。若不能进行转换，则返回 ​0​ 。

示例

#include <iostream>
#include <cstdlib>

int main()
{
    const char *str1 = "42";
    const char *str2 = "3.14159";
    const char *str3 = "31337 with words";
    const char *str4 = "words and 2";

    int num1 = std::atoi(str1);
    int num2 = std::atoi(str2);
    int num3 = std::atoi(str3);
    int num4 = std::atoi(str4);

    std::cout << "std::atoi(\"" << str1 << "\") is " << num1 << '\n';
    std::cout << "std::atoi(\"" << str2 << "\") is " << num2 << '\n';
    std::cout << "std::atoi(\"" << str3 << "\") is " << num3 << '\n';
    std::cout << "std::atoi(\"" << str4 << "\") is " << num4 << '\n';
}

输出：

std::atoi("42") is 42
std::atoi("3.14159") is 3
std::atoi("31337 with words") is 31337
std::atoi("words and 2") is 0

参阅

stoistolstoll (C++11)(C++11)(C++11) | 转换字符串为有符号整数 (函数)
stoulstoull (C++11)(C++11) | 转换字符串为无符号整数 (函数)
strtolstrtoll (C++11) | 转换字节字符串为整数值 (函数)
strtoulstrtoull (C++11) | 转换字节字符串为无符号整数值 (函数)
strtoimaxstrtoumax (C++11)(C++11) | 转换字节字符串为 std::intmax_t 或 std::uintmax_t (函数)
from_chars (C++17) | 转换字符序列到整数或浮点值 (函数)


std::isalnum

< cpp‎ | string‎ | byte
定义于头文件 <cctype>
int isalnum( int ch );

检查给定字符是否为当前 C 本地环境分类为字母数字字符。默认本地环境中，下列字符为字母数字：

  • 数字（ 0123456789 ）
  • 大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）
  • 小写字母（ abcdefghijklmnopqrstuvwxyz ）

若 ch 的值不能表示为 unsigned char 且不等于 EOF 则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为字母数字字符，则为非零值，否则为 0 。

注意

同所有其他来自 <cctype> 的函数，若参数值既不能表示为 unsigned char 又不等于 EOF 则 std::isalnum 的行为未定义。为了以简单的 char （或 signed char ）安全使用此函数，首先要将参数转换为 unsigned char ：

bool my_isalnum(char ch)
{
    return std::isalnum(static_cast<unsigned char>(ch));
}

类似地，迭代器的值类型为 char 或 signed char 时，不应直接将它们用于标准算法。而是要首先转换值为 unsigned char ：

int count_alnums(const std::string& s)
{
    return std::count_if(s.begin(), s.end(),
                      // static_cast<int(*)(int)>(std::isalnum)         // 错误
                      // [](int c){ return std::isalnum(c); }           // 错误
                      // [](char c){ return std::isalnum(c); }          // 错误
                         [](unsigned char c){ return std::isalnum(c); } // 正确
                        );
}

示例

演示以不同本地环境（ OS 限定）使用 isalnum() 。

#include <iostream>
#include <cctype>
#include <clocale>

int main()
{
    unsigned char c = '\xdf'; // ISO-8859-1 中的德文字母 ß

    std::cout << "isalnum(\'\\xdf\', default C locale) returned "
               << std::boolalpha << (bool)std::isalnum(c) << '\n';

    if(std::setlocale(LC_ALL, "de_DE.iso88591"))
        std::cout << "isalnum(\'\\xdf\', ISO-8859-1 locale) returned "
                  << std::boolalpha << (bool)std::isalnum(c) << '\n';

}

可能的输出：

isalnum('\xdf', default C locale) returned false
isalnum('\xdf', ISO-8859-1 locale) returned true

参阅

isalnum(std::locale) | 检查字符是否被本地环境分类为字母或数字 (函数模板)
iswalnum | 检查宽字符是否为字母数字 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::isalpha

< cpp‎ | string‎ | byte
定义于头文件 <cctype>
int isalpha( int ch );

检查给定字符是否为当前安装的 C 本地环境分类为字母字符。默认本地环境中，下列字符为字母：

  • uppercase letters ABCDEFGHIJKLMNOPQRSTUVWXYZ
  • lowercase letters abcdefghijklmnopqrstuvwxyz

在异于 "C" 的本地环境中，字母字符是 std::isupper() 或 std::islower() 对它返回非零的字符，或本地环境认为是字母的任何其他字符。任何情况下， std::iscntrl() 、 std::isdigit() 、 std::ispunct() 和 std::isspace() 将对此字符返回零。

若 ch 的值不可表示为 unsigned char 且不等于 EOF 则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为字母字符则为非零值，否则为零。

注意

同所有其他来自 <cctype> 的函数，若参数值既不能表示为 unsigned char 又不等于 EOF 则 std::isalpha 的行为未定义。为了以简单的 char （或 signed char ）安全使用此函数，首先要将参数转换为 unsigned char ：

bool my_isalpha(char ch)
{
    return std::isalpha(static_cast<unsigned char>(ch));
}

类似地，迭代器的值类型为 char 或 signed char 时，不应直接将它们用于标准算法。而是要首先转换值为 unsigned char ：

int count_alphas(const std::string& s)
{
    return std::count_if(s.begin(), s.end(),
                      // static_cast<int(*)(int)>(std::isalpha)         // 错误
                      // [](int c){ return std::isalpha(c); }           // 错误
                      // [](char c){ return std::isalpha(c); }          // 错误
                         [](unsigned char c){ return std::isalpha(c); } // 正确
                        );
}

示例

演示以不同的本地环境（ OS 限定）使用 isalpha() 。

#include <iostream>
#include <cctype>
#include <clocale>

int main()
{
    unsigned char c = '\xdf'; // ISO-8859-1 中的德文字母 ß

    std::cout << "isalpha(\'\\xdf\', default C locale) returned "
               << std::boolalpha << (bool)std::isalpha(c) << '\n';

    std::setlocale(LC_ALL, "de_DE.iso88591");
    std::cout << "isalpha(\'\\xdf\', ISO-8859-1 locale) returned "
              << std::boolalpha << (bool)std::isalpha(c) << '\n';

}

输出：

isalpha('\xdf', default C locale) returned false
isalpha('\xdf', ISO-8859-1 locale) returned true

参阅

isalpha(std::locale) | 检查字符是否被本地环境分类为字母 (函数模板)
iswalpha | 检查宽字符是否为字母 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::isblank

< cpp‎ | string‎ | byte
定义于头文件 <cctype> |
int isblank( int ch ); | (C++11 起)

检查给定字符是否为当前安装的 C 本地环境分类为空格符。空格符是在句内分词的空白符。默认 C 本地环境中，只有空格（ 0x20 ）和水平制表符（ 0x09 ）是空格符。

若 ch 的值不能表示为 unsigned char 且不等于 EOF 则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为空格符则为非零值，否则为零。

注意

同所有其他来自 <cctype> 的函数，若参数值既不能表示为 unsigned char 又不等于 EOF 则 std::isblank 的行为未定义。为了以简单的 char （或 signed char ）安全使用此函数，首先要将参数转换为 unsigned char ：

bool my_isblank(char ch)
{
    return std::isblank(static_cast<unsigned char>(ch));
}

类似地，迭代器的值类型为 char 或 signed char 时，不应直接将它们用于标准算法。而是要首先转换值为 unsigned char ：

int count_blanks(const std::string& s)
{
    return std::count_if(s.begin(), s.end(),
                      // static_cast<int(*)(int)>(std::isblank)         // 错误
                      // [](int c){ return std::isblank(c); }           // 错误
                      // [](char c){ return std::isblank(c); }          // 错误
                         [](unsigned char c){ return std::isblank(c); } // 正确
                        );
}

参阅

isblank(std::locale) (C++11) | 检查字符是否被本地环境分类为空格字符 (函数模板)
iswblank (C++11) | 检查宽字符是否为空白字符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::iscntrl

< cpp‎ | string‎ | byte
定义于头文件 <cctype>
int iscntrl( int ch );

检查给定的字符是否为当前安装的 C 本地环境分类为控制字符。默认的 "C" 本地环境中。控制字符是拥有编码 0x00-0x1F 和 0x7F 的字符。

若 ch 的值不可表示为 unsigned char 且不等于 EOF 则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为控制字符则为非零值，否则为零。

注意

同所有其他来自 <cctype> 的函数，若参数值既不能表示为 unsigned char 又不等于 EOF 则 std::iscntrl 的行为未定义。为了以简单的 char （或 signed char ）安全使用此函数，首先要将参数转换为 unsigned char ：

bool my_iscntrl(char ch)
{
    return std::iscntrl(static_cast<unsigned char>(ch));
}

类似地，迭代器的值类型为 char 或 signed char 时，不应直接将它们用于标准算法。而是要首先转换值为 unsigned char ：

int count_cntrls(const std::string& s)
{
    return std::count_if(s.begin(), s.end(),
                      // static_cast<int(*)(int)>(std::iscntrl)         // 错误
                      // [](int c){ return std::iscntrl(c); }           // 错误
                      // [](char c){ return std::iscntrl(c); }          // 错误
                         [](unsigned char c){ return std::iscntrl(c); } // 正确
                        );
}

示例

#include <iostream>
#include <cctype>
#include <clocale>

int main()
{
    unsigned char c = '\x94'; // ISO-8859-1 中的控制码 CCH

    std::cout << "iscntrl(\'\\x94\', default C locale) returned "
               << std::boolalpha << (bool)std::iscntrl(c) << '\n';

    std::setlocale(LC_ALL, "en_GB.iso88591");
    std::cout << "iscntrl(\'\\x94\', ISO-8859-1 locale) returned "
              << std::boolalpha << (bool)std::iscntrl(c) << '\n';

}

输出：

iscntrl('\x94', default C locale) returned false
iscntrl('\x94', ISO-8859-1 locale) returned true

参阅

iscntrl(std::locale) | 检查字符是否被本地环境分类为控制字符 (函数模板)
iswcntrl | 检查宽字符是否为控制字符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::isdigit

< cpp‎ | string‎ | byte
定义于头文件 <cctype>
int isdigit( int ch );

检查给定的字符是否 10 个十进制数位： 0123456789 之一。

若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为数字字符则为非零值，否则为零。

注意

isdigit 和 isxdigit 是仅有的不受当前安装的 C 本地环境影响的标准窄字符分类函数。尽管某些实现（例如 Microsoft 在 1252 代码页）可能分类另外的单字节字符为数字。

同所有其他来自 <cctype> 的函数，若参数值既不能表示为 unsigned char 又不等于 EOF 则 std::isdigit 的行为未定义。为了以简单的 char （或 signed char ）安全使用此函数，首先要将参数转换为 unsigned char ：

bool my_isdigit(char ch)
{
    return std::isdigit(static_cast<unsigned char>(ch));
}

类似地，迭代器的值类型为 char 或 signed char 时，不应直接将它们用于标准算法。而是要首先转换值为 unsigned char ：

int count_digits(const std::string& s)
{
    return std::count_if(s.begin(), s.end(),
                      // static_cast<int(*)(int)>(std::isdigit)         // 错误
                      // [](int c){ return std::isdigit(c); }           // 错误
                      // [](char c){ return std::isdigit(c); }          // 错误
                         [](unsigned char c){ return std::isdigit(c); } // 正确
                        );
}

参阅

isdigit(std::locale) | 检查字符是否被本地环境分类为数字 (函数模板)
iswdigit | 检查宽字符是否为数字 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::isgraph

< cpp‎ | string‎ | byte
定义于头文件 <cctype>
int isgraph( int ch );

检查给定的字符是否为当前安装的 C 本地环境分类为图形符（拥有图形表示）。默认 C 本地环境中，下列字符是图形符：

  • 数字（ 0123456789 ） ()
  • 大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）
  • 小写字母（ abcdefghijklmnopqrstuvwxyz ）
  • 标点字符（ !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ）

若 ch 的值不能表示为 unsigned char 且不等于 EOF 则行为未定义。

参数

ch - 要分类的字符

返回值

若字符拥有图形表示，则为非零值，否则为零。

注意

同所有其他来自 <cctype> 的函数，若参数值既不能表示为 unsigned char 又不等于 EOF 则 std::isgraph 的行为未定义。为了以简单的 char （或 signed char ）安全使用此函数，首先要将参数转换为 unsigned char ：

bool my_isgraph(char ch)
{
    return std::isgraph(static_cast<unsigned char>(ch));
}

类似地，迭代器的值类型为 char 或 signed char 时，不应直接将它们用于标准算法。而是要首先转换值为 unsigned char ：

int count_graphs(const std::string& s)
{
    return std::count_if(s.begin(), s.end(),
                      // static_cast<int(*)(int)>(std::isgraph)         // 错误
                      // [](int c){ return std::isgraph(c); }           // 错误
                      // [](char c){ return std::isgraph(c); }          // 错误
                         [](unsigned char c){ return std::isgraph(c); } // 正确
                        );
}

示例

#include <iostream>
#include <cctype>
#include <clocale>

int main()
{
    unsigned char c = '\xb6'; // ISO-8559-1 中的字符 ¶

    std::cout << "isgraph(\'\\xb6\', default C locale) returned "
               << std::boolalpha << (bool)std::isgraph(c) << '\n';

    std::setlocale(LC_ALL, "en_GB.iso88591");
    std::cout << "isgraph(\'\\xb6\', ISO-8859-1 locale) returned "
              << std::boolalpha << (bool)std::isgraph(c) << '\n';
}

输出：

isgraph('\xb6', default C locale) returned false
isgraph('\xb6', ISO-8859-1 locale) returned true

参阅

isgraph(std::locale) | 检查字符是否被本地环境分类为图形字符 (函数模板)
iswgraph | 检查宽字符是否为图形字符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::islower

< cpp‎ | string‎ | byte
定义于头文件 <cctype>
int islower( int ch );

检查给定字符是否按照当前 C 本地环境分类为小写字符。默认 "C" 本地环境中， islower 仅对小写字母（ abcdefghijklmnopqrstuvwxyz ）返回非零值。

若 islower 返回非零值，则保证同一 C 本地环境中 std::iscntrl 、 std::isdigit 、 std::ispunct 和 std::isspace 对同一字符返回零。

若 ch 不可表示为 unsigned char 且不等于 EOF 则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为小写字母则为非零值，否则为零。

注意

同所有其他来自 <cctype> 的函数，若参数值既不能表示为 unsigned char 又不等于 EOF 则 std::islower 的行为未定义。为了以简单的 char （或 signed char ）安全使用此函数，首先要将参数转换为 unsigned char ：

bool my_islower(char ch)
{
    return std::islower(static_cast<unsigned char>(ch));
}

类似地，迭代器的值类型为 char 或 signed char 时，不应直接将它们用于标准算法。而是要首先转换值为 unsigned char ：

int count_lowers(const std::string& s)
{
    return std::count_if(s.begin(), s.end(),
                      // static_cast<int(*)(int)>(std::islower)         // 错误
                      // [](int c){ return std::islower(c); }           // 错误
                      // [](char c){ return std::islower(c); }          // 错误
                         [](unsigned char c){ return std::islower(c); } // 正确
                        );
}

示例

#include <iostream>
#include <cctype>
#include <clocale>

int main()
{
    unsigned char c = '\xe5'; // ISO-8859-1 中的字母 å

    std::cout << "islower(\'\\xe5\', default C locale) returned "
               << std::boolalpha << (bool)std::islower(c) << '\n';

    std::setlocale(LC_ALL, "en_GB.iso88591");
    std::cout << "islower(\'\\xe5\', ISO-8859-1 locale) returned "
              << std::boolalpha << (bool)std::islower(c) << '\n';

}

输出：

islower('\xe5', default C locale) returned false
islower('\xe5', ISO-8859-1 locale) returned true

参阅

islower(std::locale) | 检查字符是否被本地环境分类为小写 (函数模板)
iswlower | 检查宽字符是否为小写 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::isprint

< cpp‎ | string‎ | byte
定义于头文件 <cctype>
int isprint( int ch );

检查 ch 是否为当前安装的 C 本地环境分类为可打印字符。默认的 "C" 本地环境中，下列字符可打印：

  • 数字（ 0123456789 ）
  • 大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）
  • 小写字母（ abcdefghijklmnopqrstuvwxyz ）
  • 标点字符（ !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ）
  • 空格（ ）

若 ch 的值不可表示为 unsigned char 且不等于 EOF 则行为未定义。

参数

ch - 要分类的字符

返回值

若能打印字符则为非零值，否则为零。

注意

同所有其他来自 <cctype> 的函数，若参数值既不能表示为 unsigned char 又不等于 EOF 则 std::isprint 的行为未定义。为了以简单的 char （或 signed char ）安全使用此函数，首先要将参数转换为 unsigned char ：

bool my_isprint(char ch)
{
    return std::isprint(static_cast<unsigned char>(ch));
}

类似地，迭代器的值类型为 char 或 signed char 时，不应直接将它们用于标准算法。而是要首先转换值为 unsigned char ：

int count_prints(const std::string& s)
{
    return std::count_if(s.begin(), s.end(),
                      // static_cast<int(*)(int)>(std::isprint)         // 错误
                      // [](int c){ return std::isprint(c); }           // 错误
                      // [](char c){ return std::isprint(c); }          // 错误
                         [](unsigned char c){ return std::isprint(c); } // 正确
                        );
}

示例

#include <iostream>
#include <cctype>
#include <clocale>

int main()
{
    unsigned char c = '\xa0'; // ISO-8859-1 中的无中断空格

    std::cout << "isprint(\'\\xa0\', default C locale) returned "
               << std::boolalpha << (bool)std::isprint(c) << '\n';

    std::setlocale(LC_ALL, "en_GB.iso88591");
    std::cout << "isprint(\'\\xa0\', ISO-8859-1 locale) returned "
              << std::boolalpha << (bool)std::isprint(c) << '\n';
}

输出：

isprint('\xa0', default C locale) returned false
isprint('\xa0', ISO-8859-1 locale) returned true

参阅

isprint(std::locale) | 检查字符是否被本地环境分类为可打印字符 (函数模板)
iswprint | 检查宽字符是否为打印字符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::ispunct

< cpp‎ | string‎ | byte
定义于头文件 <cctype>
int ispunct( int ch );

检查给定的字符是否为当前 C 本地环境分类为标点字符。默认 C 本地环境分类字符 !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ 为标点。

若 ch 的值不能表示为 unsigned char 且不等于 EOF 则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为标点字符则为非零值，否则为零。

注意

同所有其他来自 <cctype> 的函数，若参数值既不能表示为 unsigned char 又不等于 EOF 则 std::ispunct 的行为未定义。为了以简单的 char （或 signed char ）安全使用此函数，首先要将参数转换为 unsigned char ：

bool my_ispunct(char ch)
{
    return std::ispunct(static_cast<unsigned char>(ch));
}

类似地，迭代器的值类型为 char 或 signed char 时，不应直接将它们用于标准算法。而是要首先转换值为 unsigned char ：

int count_puncts(const std::string& s)
{
    return std::count_if(s.begin(), s.end(),
                      // static_cast<int(*)(int)>(std::ispunct)         // 错误
                      // [](int c){ return std::ispunct(c); }           // 错误
                      // [](char c){ return std::ispunct(c); }          // 错误
                         [](unsigned char c){ return std::ispunct(c); } // 正确
                        );
}

示例

#include <iostream>
#include <cctype>
#include <clocale>

int main()
{
    unsigned char c = '\xd7'; // ISO-8859-1 中的字符 × （乘号）

    std::cout << "ispunct(\'\\xd7\', default C locale) returned "
               << std::boolalpha << (bool)std::ispunct(c) << '\n';

    std::setlocale(LC_ALL, "en_GB.iso88591");
    std::cout << "ispunct(\'\\xd7\', ISO-8859-1 locale) returned "
              << std::boolalpha << (bool)std::ispunct(c) << '\n';
}

输出：

ispunct('\xd7', default C locale) returned false
ispunct('\xd7', ISO-8859-1 locale) returned true

参阅

ispunct(std::locale) | 检查字符是否被本地环境分类为标点 (函数模板)
iswpunct | 检查宽字符是否为标点字符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::isspace

< cpp‎ | string‎ | byte
定义于头文件 <cctype>
int isspace( int ch );

检查给定的字符在当前的 C 本地环境中是否是空白字符。在默认的本地环境中，空白字符是:

  • 空格 (0x20, ' ')
  • 换页 (0x0c, '\f')
  • 换行 (0x0a, '\n')
  • 回车 (0x0d, '\r')
  • 水平制表符 (0x09, '\t')
  • 垂直制表符 (0x0b, '\v')

如果 ch 的值不能表示为 unsigned char ，并且不等于 EOF ，则函数行为未定义。

参数

ch - 要检查的字符字符

返回值

如果字符是空白字符，返回非零值，否则返回零。

注意

同所有其他来自 <cctype> 的函数，若参数值既不能表示为 unsigned char 又不等于 EOF 则 std::isspace 的行为未定义。为了以简单的 char （或 signed char ）安全使用此函数，首先要将参数转换为 unsigned char ：

bool my_isspace(char ch)
{
    return std::isspace(static_cast<unsigned char>(ch));
}

类似地，迭代器的值类型为 char 或 signed char 时，不应直接将它们用于标准算法。而是要首先转换值为 unsigned char ：

int count_spaces(const std::string& s)
{
    return std::count_if(s.begin(), s.end(),
                      // static_cast<int(*)(int)>(std::isspace)         // 错误
                      // [](int c){ return std::isspace(c); }           // 错误
                      // [](char c){ return std::isspace(c); }          // 错误
                         [](unsigned char c){ return std::isspace(c); } // 正确
                        );
}

参阅

isspace(std::locale) | 检查字符是否被本地环境分类为空白 (函数模板)
iswspace | 检查宽字符是否为空白间隔字符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::isupper

< cpp‎ | string‎ | byte
定义于头文件 <cctype>
int isupper( int ch );

检查给定的字符是否为当前安装的 C 本地环境分类为大写字符。默认 "C" 本地环境中， isupper 仅对大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）返回非零值。

若 isupper 返回非零值，则保证同一 C 本地环境中 iscntrl 、 isdigit 、 ispunct 和 isspace 对同一字符返回零。

若 ch 的值不能表示为 unsigned char 且不等于 EOF 则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为大写字母则为非零值，否则为零。

注意

同所有其他来自 <cctype> 的函数，若参数值既不能表示为 unsigned char 又不等于 EOF 则 std::isupper 的行为未定义。为了以简单的 char （或 signed char ）安全使用此函数，首先要将参数转换为 unsigned char ：

bool my_isupper(char ch)
{
    return std::isupper(static_cast<unsigned char>(ch));
}

类似地，迭代器的值类型为 char 或 signed char 时，不应直接将它们用于标准算法。而是要首先转换值为 unsigned char ：

int count_uppers(const std::string& s)
{
    return std::count_if(s.begin(), s.end(),
                      // static_cast<int(*)(int)>(std::isupper)         // 错误
                      // [](int c){ return std::isupper(c); }           // 错误
                      // [](char c){ return std::isupper(c); }          // 错误
                         [](unsigned char c){ return std::isupper(c); } // 正确
                        );
}

示例

#include <iostream>
#include <cctype>
#include <clocale>

int main()
{
    unsigned char c = '\xc6'; // ISO-8859-1 中的字母 Æ

    std::cout << "isupper(\'\\xc6\', default C locale) returned "
               << std::boolalpha << (bool)std::isupper(c) << '\n';

    std::setlocale(LC_ALL, "en_GB.iso88591");
    std::cout << "isupper(\'\\xc6\', ISO-8859-1 locale) returned "
              << std::boolalpha << (bool)std::isupper(c) << '\n';

}

输出：

isupper('\xc6', default C locale) returned false
isupper('\xc6', ISO-8859-1 locale) returned true

参阅

isupper(std::locale) | 检查字符是否被本地环境分类为大写 (函数模板)
iswupper | 检查宽字符是否为大写 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::isxdigit

< cpp‎ | string‎ | byte
定义于头文件 <cctype>
int isxdigit( int ch );

检查给定字符是否为十六进制数字字符（ 0123456789abcdefABCDEF ）。

若 ch 的值不能表示为 unsigned char 且不等于 EOF 则行为未定义。

参数

ch - 要分类的字符

返回值

若字符为十六进制数字字符则为非零值，否则为零。

注意

isdigit 和 isxdigit 是仅有的不受当前安装的 C 本地环境影响的标准窄字符分类函数。尽管某些实现（例如 Microsoft 在 1252 代码页）可能分类另外的单字节字符为数字。

同所有其他来自 <cctype> 的函数，若参数值既不能表示为 unsigned char 又不等于 EOF 则 std::isxdigit 的行为未定义。为了以简单的 char （或 signed char ）安全使用此函数，首先要将参数转换为 unsigned char ：

bool my_isxdigit(char ch)
{
    return std::isxdigit(static_cast<unsigned char>(ch));
}

类似地，迭代器的值类型为 char 或 signed char 时，不应直接将它们用于标准算法。而是要首先转换值为 unsigned char ：

int count_xdigits(const std::string& s)
{
    return std::count_if(s.begin(), s.end(),
                      // static_cast<int(*)(int)>(std::isxdigit)         // 错误
                      // [](int c){ return std::isxdigit(c); }           // 错误
                      // [](char c){ return std::isxdigit(c); }          // 错误
                         [](unsigned char c){ return std::isxdigit(c); } // 正确
                        );
}

参阅

isxdigit(std::locale) | 检查字符是否被本地环境分类为十六进制数字 (函数模板)
iswxdigit | 检查宽字符是否为十六进制字符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::memchr

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
const void* memchr( const void* ptr, int ch, std::size_t count );
void* memchr( void* ptr, int ch, std::size_t count );

转换 ch 为 unsigned char 并在 ptr 所指向的对象的起始 count （每个都转译为 unsigned char ）个字符中定位该值的首次出现。

此函数表现如同它按顺序读取字符，并立即于找到匹配的字符时停止：若 ptr 所指向的字符数组小于 count ，但在数组中找到匹配，则行为良好定义。

 (C++17 起)

参数

ptr | - | 指向要检验的对象的指针
ch | - | 要搜索的字符
count | - | 要检验的最大字符数

返回值

指向字符位置的指针，或若找不到这种字符则为空指针。

示例

搜索字符数组。

#include <iostream>
#include <cstring>

int main()
{
    char arr[] = {'a','\0','a','A','a','a','A','a'};
    char *pc = (char*)std::memchr(arr,'A',sizeof arr);
    if (pc != NULL)
       std::cout << "search character found\n";
    else
       std::cout << "search character not found\n";
}

输出：

search character found

参阅

strchr | 寻找字符的首次出现 (函数)
findfind_iffind_if_not (C++11) | 寻找首个满足特定判别标准的元素 (函数模板)


std::memcmp

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
int memcmp( const void* lhs, const void* rhs, std::size_t count );

转译 lhs 和 rhs 所指向的对象为 unsigned char 数组，并比较这些数组的首 count 个字符。按字典序比较。

结果的符号是在被比较对象中相异的首对字节的值（都转译成 unsigned char ）的差。

参数

lhs, rhs | - | 指向要比较的内存缓冲区的指针
count | - | 要检验的字节数

返回值

若 lhs 中首个相异字节（转译为 unsigned char ）小于 rhs 中的对应字节则为负值。

若 lhs 和 rhs 的所有 count 个字节相等则为 ​0​ 。

若 lhs 中首个相异字节大于 rhs 中的对应字节则为正值。

注意

此函数读取对象表示，而非对象值，而且典型地只对无填充的可平凡复制对象有意义。例如二个 std::string 或 std::vector 类型对象间的 memcmp() 将不比较其内容，而二个 struct{char c; int n;} 类型对象间的 memcmp() 将比较填充字节，其值在 c 和 n 相同时可以相异。

示例

#include <iostream>
#include <cstring>

void demo(const char* lhs, const char* rhs, std::size_t sz)
{
    std::cout << std::string(lhs, sz);
    int rc = std::memcmp(lhs, rhs, sz);
    if(rc == 0)
        std::cout << " compares equal to ";
    else if(rc < 0)
        std::cout << " precedes ";
    else if(rc > 0)
        std::cout << " follows ";
    std::cout << std::string(rhs, sz) << " in lexicographical order\n";
}

int main()
{
    char a1[] = {'a','b','c'};
    char a2[sizeof a1] = {'a','b','d'};

    demo(a1, a2, sizeof a1);
    demo(a2, a1, sizeof a1);
    demo(a1, a1, sizeof a1);
}

输出：

abc precedes abd in lexicographical order
abd follows abc in lexicographical order
abc compares equal to abc in lexicographical order

参阅

strcmp | 比较两个字符串 (函数)
strncmp | 比较两个字符串的一定量字符 (函数)


std::memcpy

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
void* memcpy( void* dest, const void* src, std::size_t count );

从 src 所指向的对象复制 count 个字符到 dest 所指向的对象。两个对象都被转译成 unsigned char 的数组。

若对象重叠，则行为未定义。

若 dest 或 src 为非法或空指针则行为未定义，纵使 count 为零。

若对象潜在重叠或不可平凡复制 (TriviallyCopyable) ，则 memcpy 的行为未指定而且可能未定义。

参数

dest | - | 指向要复制的对象的指针
src | - | 指向复制来源对象的指针
count | - | 复制的字节数

返回值

dest

注解

std::memcpy 可用于在目标缓冲区中隐式创建对象。

std::memcpy 理应是最快的内存到内存复制子程序。它通常比必须扫描其所复制数据的 std::strcpy ，或必须预防以处理重叠输入的 std::memmove 更高效。

许多 C++ 编译器将适合的内存复制循环变换为 std::memcpy 调用。

在严格别名使用禁止检验同一内存为二个不同类型的值处，可用 std::memcpy 转换值。

示例

#include <iostream>
#include <cstdint>
#include <cstring>

int main()
{
    // 简单用法
    char source[] = "once upon a midnight dreary...", dest[4];
    std::memcpy(dest, source, sizeof dest);
    for (char c : dest)
        std::cout << c << '\n';

    // 转译
    double d = 0.1;
//  std::int64_t n = *reinterpret_cast<std::int64_t*>(&d); // 别名违规
    std::int64_t n;
    std::memcpy(&n, &d, sizeof d); // OK

    std::cout << std::hexfloat << d << " is " << std::hex << n
              << " as an std::int64_t\n";
}

输出：

o
n
c
e
0x1.999999999999ap-4 is 3fb999999999999a as an std::int64_t

参阅

memmove | 移动一个缓冲区到另一个 (函数)
memset | 以一个字符填充缓冲区 (函数)
wmemcpy | 在两个不重叠数组间复制一定量宽字符 (函数)
copycopy_if (C++11) | 将某一范围的元素复制到一个新的位置 (函数模板)
copy_backward | 按从后往前的顺序复制一个范围内的元素 (函数模板)
is_trivially_copyable (C++11) | 检查类型是否可平凡复制 (类模板)


std::memmove

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
void* memmove( void* dest, const void* src, std::size_t count );

从 src 所指向的对象复制 count 个字节到 dest 所指向的对象。两个对象都被转译成 unsigned char 的数组。

如同复制字符到临时数组，再从该数组到 dest 一般发生复制。

若 dest 或 src 为非法或空指针则行为未定义，即使 count 为零。

若对象潜在重叠或非可平凡复制 (TriviallyCopyable) ，则 memmove 的行为未指定，且可能未定义。

参数

dest | - | 指向复制目的的内存位置的指针
src | - | 指向复制来源的内存位置的指针
count | - | 要复制的字节数

返回值

dest

注解

std::memmove 可用于在目标缓冲区中隐式创建对象。

尽管说明了“如同”使用临时缓冲区，此函数的实际实现不会带来二次复制或额外内存的开销。常用方法（ glibc 和 bsd libc ）是若目标在源之前开始，则从缓冲区开始正向复制，否则从末尾反向复制，完全无重叠时回落到更高效的 std::memcpy 。

在严格别名使用禁止检验同一内存为二个不同类型的值处，可用 std::memmove 转换值。

示例

#include <iostream>
#include <cstring>

int main()
{
    char str[] = "1234567890";
    std::cout << str << '\n';
    std::memmove(str + 4, str + 3, 3); // 从 [4, 5, 6] 复制到 [5, 6, 7]
    std::cout << str << '\n';
}

输出：

1234567890
1234456890

参阅

memcpy | 复制一个缓冲区到另一个 (函数)
memset | 以一个字符填充缓冲区 (函数)
wmemmove | 在两个可能重叠的数组间复制一定量宽字符 (函数)
copycopy_if (C++11) | 将某一范围的元素复制到一个新的位置 (函数模板)
copy_backward | 按从后往前的顺序复制一个范围内的元素 (函数模板)
is_trivially_copyable (C++11) | 检查类型是否可平凡复制 (类模板)


std::memset

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
void* memset( void* dest, int ch, std::size_t count );

转换值 ch 为 unsigned char 并复制它到 dest 所指向对象的首 count 个字节。若该对象是潜在重叠的子对象或非 可平凡复制 (TriviallyCopyable) （例如标量、 C 兼容的结构体或可平凡复制类型的数组），则行为未定义。若 count 大于 dest 所指向的对象大小，则行为未定义。

参数

dest | - | 指向要填充的对象的指针
ch | - | 填充字节
count | - | 要填充的字节数

返回值

dest

注意

若 std::memset 所修改的对象在其生存期的剩余部分不再被访问，则此函数可以被优化掉（在如同规则下）（例如 gcc 漏洞 8537 ）。为此，此函数不能用于擦洗内存（例如以令填充存储密码的数组）。该问题的解决方案包含 C11 memset_s 、 FreeBSD explicit_bzero 或 Microsoft SecureZeroMemory 。

示例

#include <iostream>
#include <cstring>

int main()
{
    int a[20];
    std::memset(a, 0, sizeof a);
    for (int ai : a) std::cout << ai;
}

输出：

00000000000000000000

参阅

memcpy | 复制一个缓冲区到另一个 (函数)
memmove | 移动一个缓冲区到另一个 (函数)
wmemset | 复制给定宽字符到宽字符数组的每个位置 (函数)
fill | 将一个给定值复制赋值给一个范围内的每个元素 (函数模板)
fill_n | 将一个给定值复制赋值给一个范围内的 N 个元素 (函数模板)
is_trivially_copyable (C++11) | 检查类型是否可平凡复制 (类模板)


std::strcat

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
char *strcat( char *dest, const char *src );

后附 src 所指向的空终止字节字符串的副本到 dest 所指向的空终止字节字符串的结尾。字符 src[0] 替换 dest 末尾的空终止符。产生的字节字符串是空终止的。

若目标数组对于 src 和 dest 的内容以及空终止符不够大，则行为未定义。

若字符串重叠，则行为未定义。

参数

dest | - | 指向要后附到的空终止字节字符串的指针
src | - | 指向作为复制来源的空终止字节字符串的指针

返回值

dest

注解

因为 strcat 需要在每次调用时找到 dest 的结尾，故用 strcat 将多个字符串连接成一体是低效的。

示例

#include <cstring>
#include <cstdio>

int main()
{
    char str[50] = "Hello ";
    char str2[50] = "World!";
    std::strcat(str, str2);
    std::strcat(str, " Goodbye World!");
    std::puts(str);
}

输出：

Hello World! Goodbye World!

参阅

strncat | 连接两个字符串的一定量字符 (函数)
strcpy | 复制一个字符串给另一个 (函数)


std::strchr

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
const char* strchr( const char* str, int ch );
char* strchr( char* str, int ch );

在 str 所指向的字节字符串中寻找字符 static_cast<char>(ch) 的首次出现。

认为终止空字符是字符串的一部分，而且若搜索 '\0' 则能找到它。

参数

str | - | 指向待分析的空终止字节字符串的指针
ch | - | 要搜索的字符

返回值

指向 str 找到的字符的指针，若未找到该字符则为空指针。

示例

#include <iostream>
#include <cstring>

int main()
{
  const char *str = "Try not. Do, or do not. There is no try.";
  char target = 'T';
  const char *result = str;

  while ((result = std::strchr(result, target)) != NULL) {
    std::cout << "Found '" << target
              << "' starting at '" << result << "'\n";

    // 自增 result，否则我们将找到相同位置的目标
    ++result;
  }
}

输出：

Found 'T' starting at 'Try not. Do, or do not. There is no try.'
Found 'T' starting at 'There is no try.'

参阅

memchr | 在数组中搜索字符的首次出现 (函数)
find | 于字符串中寻找字符 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
wcschr | 寻找宽字符串中宽字符的首次出现 (函数)
strrchr | 寻找字符的最后出现 (函数)
strpbrk | 寻找任何来自分隔符集合的字符的首个位置 (函数)


std::strcmp

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
int strcmp( const char *lhs, const char *rhs );

以字典序比较二个空终止字节字符串。

结果的符号是被比较的字符串中首对不同字符（都转译成 unsigned char ）的值间的差值符号。

若 lhs 或 rhs 不是指向空终止字节字符串的指针，则行为未定义。

参数

lhs, rhs - 指向待比较的空终止字节字符串的指针

返回值

若字典序中 lhs 先出现于 rhs 则为负值。

若 lhs 与 rhs 比较相等则为零。

若字典序中 lhs 后出现于 rhs 则为正值。

示例

#include <vector>
#include <cstring>
#include <algorithm>
#include <iostream>

int main()
{
    std::vector<const char*> cats {"Heathcliff", "Snagglepuss", "Hobbes", "Garfield"};
    std::sort(cats.begin(), cats.end(), [](const char *strA, const char *strB) {
        return std::strcmp(strA, strB) < 0;
    });

    for (const char *cat : cats) {
        std::cout << cat << '\n';
    }
}

输出：

Garfield
Heathcliff
Hobbes
Snagglepuss

参阅

strncmp | 比较两个字符串的一定量字符 (函数)
wcscmp | 比较两个宽字符串 (函数)
memcmp | 比较两个缓冲区 (函数)
strcoll | 按照当前本地环境比较两个字符串 (函数)


std::strcoll

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
int strcoll( const char* lhs, const char* rhs );

按照 LC_COLLATE 类别所定义的当前本地环境，比较二个空终止字节字符串。

参数

lhs, rhs - 指向要比较的空终止字节字符串的指针

返回值

若 lhs 小于（前趋） rhs 则为负值。

若 lhs 等于 rhs 则为 ​0​ 。

若 lhs 大于（后随） rhs 则为负值。

注意

对照顺序为字典顺序：国家字母表（其等价类）中字母的位置拥有高于其大小写或变体的优先级。在等价类内，小写字符先于其大写等价物对照，而且本地环境限定的顺序可能应用到有发音符号的字符。一些本地环境中，字符组作为单个对照单元比较。例如， "ch" 在捷克语中后随 "h" 而前趋 "i" ， "dzs" 在匈牙利语中后随 "dz" 而前趋 "g" 。

示例

#include <iostream>
#include <cstring>
#include <clocale>

int main()
{
    std::setlocale(LC_COLLATE, "cs_CZ.iso88592");

    const char* s1 = "hrnec";
    const char* s2 = "chrt";

    std::cout << "In the Czech locale: ";
    if(std::strcoll(s1, s2) < 0)
         std::cout << s1 << " before " << s2 << '\n';
    else
         std::cout << s2 << " before " << s1 << '\n';

    std::cout << "In lexicographical comparison: ";
    if(std::strcmp(s1, s2) < 0)
         std::cout << s1 << " before " << s2 << '\n';
    else
         std::cout << s2 << " before " << s1 << '\n';
}

输出：

In the Czech locale: hrnec before chrt
In lexicographical comparison: chrt before hrnec

参阅

wcscoll | 按照当前本地环境比较两个宽字符串 (函数)
do_compare [虚] | 用此平面的对照规则比较二个字符串 (std::collate<CharT> 的虚受保护成员函数)
strxfrm | 变换字符串，使得 strcmp 会返回与 strcoll 相同的结果 (函数)


std::strcpy

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
char* strcpy( char* dest, const char* src );

复制 src 所指向的字符串，包含空终止符，到首元素为 dest 所指向的字符数组。

若 dest 数组不够大则行为未定义。若字符串重叠则行为未定义。

参数

dest | - | 指向要写入的字符数组的指针
src | - | 指向复制来源的空终止字节字符串的指针

返回值

dest

示例

#include <iostream>
#include <cstring>
#include <memory>

int main()
{
    const char* src = "Take the test.";
//  src[0] = 'M'; // 不能修改字符串字面量
    auto dst = std::make_unique<char[]>(std::strlen(src)+1); // 为空终止符 +1
    std::strcpy(dst.get(), src);
    dst[0] = 'M';
    std::cout << src << '\n' << dst.get() << '\n';
}

输出：

Take the test.
Make the test.

参阅

strncpy | 复制来自一个字符串的一定量字符给另一个 (函数)
memcpy | 复制一个缓冲区到另一个 (函数)


std::strcspn

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
size_t strcspn( const char *dest, const char *src );

返回 dest 所指向的空终止字节字符串的最大起始段长度，该段只由 src 所指向的空终止字节字符串中找不到的字符组成。

函数名代表“补集段 (complementary span) ”。

参数

dest | - | 指向要分析的空终止字节字符串的指针
src | - | 指向含有要搜索字符的空终止字节字符串的指针

返回值

仅由 src 所指向的空终止字节字符串中找不到的字符组成的最大起始段长度。

示例

#include <string>
#include <cstring>
#include <iostream>

const char* invalid = "*$#";
int main()
{
    std::string s = "abcde312$#@";

    size_t valid_len = std::strcspn(s.c_str(), invalid);
    if(valid_len != s.size())
       std::cout << "'" << s << "' contains invalid chars starting at position "
                 << valid_len << '\n';
}

输出：

'abcde312$#@' contains invalid chars starting at position 8

参阅

strspn | 返回仅由另一字节字符串中找到的字符组成的最大起始段的长度 (函数)
wcscspn | 返回仅由另一宽字符串中找不到的宽字符组成的最大起始段的长度 (函数)
strpbrk | 寻找任何来自分隔符集合的字符的首个位置 (函数)
find_first_of | 寻找字符的首次出现 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)


std::strerror

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
char* strerror( int errnum );

返回指向系统错误码 errnum 的文本表示的指针，它等同于 std::perror() 会打印的描述。

通常从 errno 对象获得 errnum ，不过函数接受任何 int 类型值。字符串的内容是本地环境限定的。

程序必须不修改返回的字符串，但对 strerror 函数的后继调用可能重写该字符串。不要求 strerror 为线程安全。实现可以返回指向静态只读字符串字面量的不同指针，或反复返回指向静态缓冲区的同一指针而 strerror 于该缓冲区中放置字符串。

参数

errnum - 指代错误码的整数值

返回值

指向对应 errno 错误码 errnum 的空终止字节串的指针。

注意

POSIX 允许对 strerror 的后继调用非法化先前调用所返回的指针值。它亦指定控制这些消息的 LC_MESSAGES 本地环境平面。

示例

#include <iostream>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <clocale>

int main()
{
    double not_a_number = std::log(-1.0);
    if (errno == EDOM) {
        std::cout << "log(-1) failed: " << std::strerror(errno) << '\n';
        std::setlocale(LC_MESSAGES, "de_DE.utf8");
        std::cout << "Or, in German, " << std::strerror(errno) << '\n';
    }
}

可能的输出：

log(-1) failed: Numerical argument out of domain
Or, in German, Das numerische Argument ist ausserhalb des Definitionsbereiches

参阅

perror | 显示对应当前错误的字符串于 stderr (函数)
E2BIG, EACCES, ..., EXDEV | 兼容标准 POSIX 的错误条件的宏 (宏常量)


std::strlen

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
std::size_t strlen( const char* str );

返回给定字节字符串的长度，即首元素为 str 所指向的字符数组直到而不包含首个空字符的字符数。若 str 所指向的字符数组中无空字符，则行为未定义。

参数

str - 指向要检验的空终止字节字符串的指针

返回值

空终止字符串 str 的长度。

示例

#include <cstring>
#include <iostream>

int main()
{
   const char str[] = "How many characters does this string contain?";

   std::cout << "without null character: " << std::strlen(str) << '\n'
             << "with null character: " << sizeof str << '\n';
}

输出：

without null character: 45
with null character: 46

参阅

wcslen | 返回宽字符串长度 (函数)
mblen | 返回下一个多字节字符中的字节数 (函数)


std::strncat

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
char *strncat( char *dest, const char *src, std::size_t count );

后附 src 所指向的字节字符串到 dest 所指向的字节字符串。至多复制 count 个字符。产生的字节字符串是空终止的。

目标字节字符串必须拥有足够的空间用于连接 dest 和 src 的内容加上终止空字符，但 src 的大小被限制到 count 。

若字符串重叠则行为未定义。

参数

dest | - | 指向要后附到的空终止字节字符串的指针
src | - | 指向作为复制来源的字符数组的指针
count | - | 要复制的最大字符数

返回值

dest

注解

因为 strncat 需要在每次调用时找到 dest 的结尾，故用 strncat 将多个字符串连接成一体是低效的。

示例

#include <cstring>
#include <cstdio>

int main()
{
    char str[50] = "Hello ";
    char str2[50] = "World!";
    std::strcat(str, str2);
    std::strncat(str, " Goodbye World!", 3);
    std::puts(str);
}

输出：

Hello World! Go

参阅

strcat | 连接两个字符串 (函数)
strcpy | 复制一个字符串给另一个 (函数)


std::strncmp

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
int strncmp( const char* lhs, const char* rhs, std::size_t count );

比较二个可能空终止的数组的至多 count 个字符。按字典序进行比较。不比较后随空字符的字符。

结果的符号是被比较的数组中首对字符（都转译成 unsigned char ）的值间的差的符号。

若出现越过 lhs 或 rhs 结尾的访问，则行为未定义。若 lhs 或 rhs 为空指针，则行为未定义。

参数

lhs, rhs | - | 指向要比较的可能空终止的数组的指针
count | - | 要比较的最大字符数

返回值

若字典序中 lhs 先出现于 rhs 则为负值。

若 lhs 与 rhs 比较相等，或若 count 为零，则为零。

若字典序中 lhs 后出现于 rhs 则为正值。

注解

不同于 std::strcoll 和 std::strxfrm ，此函数不考虑本地环境。

示例

#include <cstring>
#include <iostream>

void demo(const char* lhs, const char* rhs, int sz)
{
    int rc = std::strncmp(lhs, rhs, sz);
    if(rc == 0)
        std::cout << "First " << sz << " chars of ["
                  << lhs << "] equal [" << rhs << "]\n";
    else if(rc < 0)
        std::cout << "First " << sz << " chars of ["
                  << lhs << "] precede [" << rhs << "]\n";
    else if(rc > 0)
        std::cout << "First " << sz << " chars of ["
                  << lhs << "] follow [" << rhs << "]\n";
}
int main()
{
    demo("Hello, world!", "Hello, everybody!", 13);
    demo("Hello, everybody!", "Hello, world!", 13);
    demo("Hello, everybody!", "Hello, world!", 7);
    demo("Hello, everybody!" + 12, "Hello, somebody!" + 11, 5);
}

输出：

First 13 chars of [Hello, world!] follow [Hello, everybody!]
First 13 chars of [Hello, everybody!] precede [Hello, world!]
First 7 chars of [Hello, everybody!] equal [Hello, world!]
First 5 chars of [body!] equal [body!]

参阅

strcmp | 比较两个字符串 (函数)
wcsncmp | 比较来自两个宽字符串的一定量宽字符 (函数)
memcmp | 比较两个缓冲区 (函数)
strcoll | 按照当前本地环境比较两个字符串 (函数)


std::strncpy

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
char *strncpy( char *dest, const char *src, std::size_t count );

复制 src 所指向的字节字符串的至多 count 个字符（包含终止空字符）到 dest 所指向的字符数组。

若在复制整个字符串 src 前抵达 count ，则产生的字符数组不是空终止的。

若在复制来自 src 的终止空字符后未抵达 count ，则写入额外的空字符到 dest ，直至写入总共 count 个字符。

若字符串重叠，则行为未定义。

参数

dest | - | 指向要复制到的字符数组的指针
src | - | 指向作为复制来源的字节字符串的指针
count | - | 要复制的最大字符数

返回值

dest

示例

#include <iostream>
#include <cstring>

int main()
{
    const char* src = "hi";
    char dest[6] = {'a', 'b', 'c', 'd', 'e', 'f'};
    std::strncpy(dest, src, 5);

    std::cout << "The contents of dest are: ";
    for (char c : dest) {
        if (c) {
            std::cout << c << ' ';
        } else {
            std::cout << "\\0" << ' ';
        }
    }
    std::cout << '\n';
}

输出：

The contents of dest are: h i \0 \0 \0 f

参阅

strcpy | 复制一个字符串给另一个 (函数)
memcpy | 复制一个缓冲区到另一个 (函数)


std::strpbrk

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
const char* strpbrk( const char* dest, const char* breakset );
char* strpbrk( char* dest, const char* breakset );

在 dest 所指向的空终止字节串中，扫描来自 breakset 所指向的空终止字节串的任何字符，并返回指向该字符的指针。

参数

dest | - | 指向要分析的空终止字节字符串的指针
breakset | - | 指向含要搜索的字符的空终止字节字符串的指针

返回值

指向 dest 中首个亦在 breakset 中的字符的指针，或若这种字符不存在则为空指针。

注解

名称代表“字符串指针打断 (string pointer break) ”，因为它返回指向首个分隔符（“打断”）的指针。

示例

#include <iostream>
#include <iomanip>
#include <cstring>

int main()
{
    const char* str = "hello world, friend of mine!";
    const char* sep = " ,!";

    unsigned int cnt = 0;
    do {
       str = std::strpbrk(str, sep); // 寻找分隔符
       std::cout << std::quoted(str) << '\n';
       if(str) str += std::strspn(str, sep); // 跳过分隔符
       ++cnt; // 增加词计数
    } while(str && *str);

    std::cout << "There are " << cnt << " words\n";
}

输出：

" world, friend of mine!"
", friend of mine!"
" of mine!"
" mine!"
"!"
There are 5 words

参阅

strcspn | 返回仅由另一字节字符串中找不到的字符组成的最大起始段的长度 (函数)
strtok | 寻找字节字符串中的下个记号 (函数)
strchr | 寻找字符的首次出现 (函数)
wcspbrk | 在一个宽字符串中，寻找另一宽字符串中任何字符的首个位置 (函数)


std::strrchr

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
const char* strrchr( const char* str, int ch );
char* strrchr( char* str, int ch );

寻找 ch （转换到 char 后）在 str 所指向的空终止字节串中的最后出现。若搜索 '\0' ，则认为终止空字符为字符串的一部分，而且能找到。

参数

str | - | 指向要分析的空终止字节字符串的指针
ch | - | 要搜索的字符

返回值

指向 str 中找到的字符的指针，或若找不到这种字符则为空指针。

示例

#include <iostream>
#include <cstring>

int main()
{
    char input[] = "/home/user/hello.c";
    char* output = std::strrchr(input, '/');
    if(output)
        std::cout << output+1 << '\n';
}

输出：

hello.c

参阅

strchr | 寻找字符的首次出现 (函数)
wcsrchr | 在宽字符串中寻找宽字符的最后一次出现 (函数)
rfind | 寻找子串的最后一次出现 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)


std::strspn

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
size_t strspn( const char* dest, const char* src );

返回 dest 所指向的空终止字节串的最大起始段（ span ）长度，段仅由 src 所指向的空终止字节字符串中找到的字符组成。

参数

dest | - | 指向要分析的空终止字节字符串的指针
src | - | 指向含有要搜索的字符的空终止字节字符串的指针

返回值

仅由来自 src 所指向的空终止字节字符串的字符组成的最大起始段长度。

示例

#include <cstring>
#include <string>
#include <iostream>

const char *low_alpha = "qwertyuiopasdfghjklzxcvbnm";
int main()
{
    std::string s = "abcde312$#@";

    std::size_t spnsz = std::strspn(s.c_str(), low_alpha);
    std::cout << "After skipping initial lowercase letters from '" << s
              << "'\nThe remainder is '" << s.substr(spnsz) << "'\n";
}

输出：

After skipping initial lowercase letters from 'abcde312$#@'
The remainder is '312$#@'

参阅

strcspn | 返回仅由另一字节字符串中找不到的字符组成的最大起始段的长度 (函数)
wcsspn | 返回仅由另一宽字符串中找到的宽字符组成的最大起始段的长度 (函数)
strpbrk | 寻找任何来自分隔符集合的字符的首个位置 (函数)


std::strstr

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
const char* strstr( const char* str, const char* target );
char* strstr( char* str, const char* target );

在 str 所指的字节字符串中寻找字节字符串 target 的首次出现。不比较空终止字符。

参数

str | - | 指向要检验的空终止字节字符串的指针
target | - | 指向要查找的空终止字节字符串的指针

返回值

指向 str 中寻获子串的首个字符的指针，或若找不到该字符则为空指针。若 target 指向空字符串，则返回 str 。

示例

#include <iostream>
#include <cstring>

int main()
{
    const char *str = "Try not. Do, or do not. There is no try.";
    const char *target = "not";
    const char *result = str;

    while ((result = std::strstr(result, target)) != NULL) {
        std::cout << "Found '" << target
                  << "' starting at '" << result << "'\n";

        // 自增 result ，否则会找到同一位置的目标
        ++result;
    }
}

输出：

Found 'not' starting at 'not. Do, or do not. There is no try.'
Found 'not' starting at 'not. There is no try.'

参阅

find | 于字符串中寻找字符 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
wcsstr | 在另一宽字符串中寻找宽字符串的首次出现 (函数)
strchr | 寻找字符的首次出现 (函数)
strrchr | 寻找字符的最后出现 (函数)


std::strtof, std::strtod, std::strtold

< cpp‎ | string‎ | byte
定义于头文件 <cstdlib> |
float strtof( const char* str, char** str_end ); | (C++11 起)
double strtod( const char* str, char** str_end ); |
long double strtold( const char* str, char** str_end ); | (C++11 起)

转译 str 所指向的字节字符串中的浮点值。

函数会舍弃任何空白符（由 std::isspace() 确定），直至找到首个非空白符。然后它会取用尽可能多的字符，以构成合法的浮点数表示，并将它们转换成浮点值。合法的浮点值可以为下列之一：

  • 十进制浮点数表达式。它由下列部分组成：
  • (可选) 正或负号
  • 非空的十进制数字序列，可选地包含一个小数点字符（由当前的 C 本地环境确定）（定义有效数字）
  • (可选) e 或 E ，并跟随可选的正或负号，以及非空十进制数字序列（以 10 为底定义指数）
  • 十六进制浮点数表达式。它由下列部分组成：
  • (可选) 正或负号
  • 0x 或 0X
  • 非空的十六进制数字序列，选地包含一个小数点字符（由当前的 C 本地环境确定）（定义有效数字）
  • (可选) p 或 P ，并跟随可选的正或负号，以及非空十进制数字序列（以 2 为底定义指数）
  • 无穷大表达式。它由下列部分组成：
  • (可选) 正或负号
  • INF 或 INFINITY ，忽略大小写
  • 非数（NaN）表达式。它由下列部分组成：
  • (可选) 正或负号
  • NAN 或 NAN(char_sequence) ，忽略 NAN 部分的大小写。 char_sequence 只能由数字、拉丁字母和下划线构成。结果是一个静态的 NaN 浮点值。
 (C++11 起)
  • 任何其他可由当前 C 本地环境接受的表达式

函数设置 str_end 所指向的指针指向最后被转译字符的后一字符，若 str_end 为空指针，则忽略它。

参数

str | - | 指向要转译的空终止字节字符串的指针
str_end | - | 指向指向字符指针的指针。

返回值

成功时为对应 str 内容的浮点值。若转换出的值落在对应返回类型的范围外，则发生值域错误并返回 HUGE_VAL 、 HUGE_VALF 或 HUGE_VALL 。若无法进行转换，则返回 ​0​ 并将 *str_end 设为 str 。

示例

#include <iostream>
#include <string>
#include <cerrno>
#include <cstdlib>

int main()
{
    const char* p = "111.11 -2.22 0X1.BC70A3D70A3D7P+6  1.18973e+4932zzz";
    char* end;
    std::cout << "Parsing \"" << p << "\":\n";
    for (double f = std::strtod(p, &end); p != end; f = std::strtod(p, &end))
    {
        std::cout << "'" << std::string(p, end-p) << "' -> ";
        p = end;
        if (errno == ERANGE){
            std::cout << "range error, got ";
            errno = 0;
        }
        std::cout << f << '\n';
    }
}

输出：

Parsing "111.11 -2.22 0X1.BC70A3D70A3D7P+6  1.18973e+4932zzz":
'111.11' -> 111.11
' -2.22' -> -2.22
' 0X1.BC70A3D70A3D7P+6' -> 111.11
'  1.18973e+4932' -> range error, got inf

参阅

atof | 转换字节字符串为浮点值 (函数)
wcstofwcstodwcstold | 转换宽字符串为浮点值 (函数)
from_chars (C++17) | 转换字符序列到整数或浮点值 (函数)


std::strtoimax, std::strtoumax

< cpp‎ | string‎ | byte
定义于头文件 <cinttypes> |
std::intmax_t strtoimax( const char* nptr, char** endptr, int base ); | (C++11 起)
std::uintmax_t strtoumax( const char* nptr, char** endptr, int base ); | (C++11 起)

转译 nptr 所指向的字节字符串中的整数值。

舍弃所有空白符（以调用 isspace() 鉴别），直到找到首个非空白符，然后取尽可能多的字符组成底 n （其中 n=base ）的整数表示，并将它们转换成一个整数值。合法的整数值由下列部分组成：

  • (可选)正或负号
  • (可选)指示八进制底的前缀（ 0 ）（仅当底为 8 或 ​0​ 时应用）
  • (可选)指示十六进制底的前缀（ 0x 或 0X ）（仅当底为 16 或 ​0​ 时应用）
  • 一个数字序列

底的合法集是 {0,2,3,...,36} 。合法数字集对于底 2 整数是 {0,1}，对于底3整数是 {0,1,2} ，以此类推。对于大于 10 的底，合法数字包含字母字符，从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。

当前安装的 C 本地环境可能接受另外的数字格式。

若 base 为 ​0​ ，则自动检测数值进制：若前缀为 0 ，则底为八进制，若前缀为 0x 或 0X ，则底为十六进制，否则底为十进制。

若符号是输入序列的一部分，则对从数字序列计算得来的数字值取反，如同用结果类型的一元减。

函数设置 endptr 所指向的指针指向最后被转译字符的后一字符。若 endptr 为空指针，则忽略之。

若 nptr 为空或无期待形式，则不进行转换，并（若 enptr 非空指针）将 nptr 存储于 endptr 所指向的对象。

参数

nptr | - | 指向要转译的空终止字节字符串的指针
endptr | - | 指向指向字符指针的指针。
base | - | 被转译整数值的底

返回值

  • 若成功，则返回对应 str 内容的整数值。
  • 若转换出的值落在对应返回类型的范围外，则发生值域错误（设置 errno 为 ERANGE ）并返回 INTMAX_MAX 、 INTMAX_MIN 、 UINTMAX_MAX 及 ​0​ 中的接近者。
  • 若不能进行转换，则返回 ​0​ 。

示例

#include <iostream>
#include <string>
#include <cinttypes>

int main()
{
    std::string str = "helloworld";
    std::intmax_t val = std::strtoimax(str.c_str(), nullptr, 36);
    std::cout << str << " in base 36 is " << val << " in base 10\n";

    char* nptr;
    val = std::strtoimax(str.c_str(), &nptr, 30);
    if(nptr != &str[0] + str.size())
        std::cout << str << " in base 30 is invalid."
                  << " The first invalid digit is '" << *nptr << "'\n";
}

输出：

helloworld in base 36 is 1767707668033969 in base 10
helloworld in base 30 is invalid. The first invalid digit is 'w'

参阅

stoistolstoll (C++11)(C++11)(C++11) | 转换字符串为有符号整数 (函数)
stoulstoull (C++11)(C++11) | 转换字符串为无符号整数 (函数)
strtolstrtoll (C++11) | 转换字节字符串为整数值 (函数)
strtoulstrtoull (C++11) | 转换字节字符串为无符号整数值 (函数)
wcstoimaxwcstoumax (C++11)(C++11) | 转换宽字符串为 std::intmax_t 或 std::uintmax_t (函数)
strtofstrtodstrtold | 转换字节字符串为浮点值 (函数)
from_chars (C++17) | 转换字符序列到整数或浮点值 (函数)
atoiatolatoll (C++11) | 转换字节字符串为整数值 (函数)


std::strtok

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
char* strtok( char* str, const char* delim );

寻找 str 所指向的空终止字节字符串中的下个记号。由 delim 所指向的空终止字节字符串鉴别分隔字符。

此函数被设计为调用多次，以从同一字符串获得相继的记号。

  • 若 str 不是空指针，则调用被当做 strtok 对此特定字符串的首次调用。函数搜索首个不含于 delim 的字符。
  • 若找不到这种字符，则 str 中完全没有记号，而函数返回空指针。
  • 若找到这种字符，则它是记号的起始。然后函数从 delim 所含的首个字符的该点搜索。
  • 若找不到这种字符，则 str 只有一个记号，而将来对 strtok 的调用将返回空指针
  • 若找到这种字符，则用空字符 '\0' 替换它，并将指向下个字符的指针存储于静态位置，以为后继调用所用。
  • 然后函数返回指向记号起始的指针
  • 若 str 为空指针，则将调用当做对 strtok 的后继调用，函数从先前调用中它剩下的位置开始。行为如同将先前存储的指针作为 str 传递。

参数

str | - | 指向要记号化的空终止字节字符串的指针
delim | - | 指向标识分隔符的空终止字节字符串的指针

返回值

指向下个记号起始的指针，或若无更多记号则为空指针。

注解

此函数是破坏性的：它写入 '\0' 字符于字符串 str 的元素。特别是，字符串字面量不能用作 strtok 的首参数。

每次对 strtok 的调用都会修改静态对象：它不是线程安全的。

不同于大多数其他记号化器， strtok 中的分隔符能对于后继记号不同，而且甚至能依赖于先前记号的内容。

示例

#include <cstring>
#include <iostream>

int main()
{
    char input[100] = "A bird came down the walk";
    char *token = std::strtok(input, " ");
    while (token != NULL) {
        std::cout << token << '\n';
        token = std::strtok(NULL, " ");
    }
}

输出：

A
bird
came
down
the
walk

参阅

strpbrk | 寻找任何来自分隔符集合的字符的首个位置 (函数)
strcspn | 返回仅由另一字节字符串中找不到的字符组成的最大起始段的长度 (函数)
strspn | 返回仅由另一字节字符串中找到的字符组成的最大起始段的长度 (函数)


std::strtol, std::strtoll

< cpp‎ | string‎ | byte
定义于头文件 <cstdlib> |
long strtol( const char *str, char **str_end, int base ); |
long long strtoll( const char *str, char **str_end, int base ); | (C++11 起)

转译 str 所指向的字节字符串中的整数值。

舍弃所有空白符（以调用 isspace() 鉴别），直到找到首个非空白符，然后取尽可能多的字符组成底 n （其中 n=base ）的整数表示，并将它们转换成一个整数值。合法的整数值由下列部分组成：

  • (可选)正或负号
  • (可选)指示八进制底的前缀（ 0 ）（仅当底为 8 或 ​0​ 时应用）
  • (可选)指示十六进制底的前缀（ 0x 或 0X ）（仅当底为 16 或 ​0​ 时应用）
  • 一个数字序列

底的合法集是 {0,2,3,...,36} 。合法数字集对于底 2 整数是 {0,1}，对于底3整数是 {0,1,2} ，以此类推。对于大于 10 的底，合法数字包含字母字符，从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。

当前安装的 C 本地环境可能接受另外的数字格式。

若 base 为 ​0​ ，则自动检测数值进制：若前缀为 0 ，则底为八进制，若前缀为 0x 或 0X ，则底为十六进制，否则底为十进制。

若符号是输入序列的一部分，则对从数字序列计算得来的数字值取反，如同用结果类型的一元减。

函数设置 str_end 所指向的指针指向最后被转译字符的后一字符。若 str_end 为空指针，则忽略它。

若 str 为空或无期待的形式，则不进行转换，并（若 str_end 非空指针）将 str 的值存储于 str_end 所指向的对象。

参数

str | - | 指向要转译的空终止字符串的指针
str_end | - | 指向指向字符指针的指针。
base | - | 被转译整数值的底

返回值

  • 若成功，则返回对应 str 内容的整数值。
  • 若转换出的值落在对应类型的范围外，则发生值域错误（设置 errno 为 ERANGE ）并返回 LONG_MAX 、 LONG_MIN 、 LLONG_MAX 或 LLONG_MIN 。
  • 若不能进行转换，则返回 ​0​ 。

示例

#include <cerrno>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <string>

int main()
{
    const char* p = "10 200000000000000000000000000000 30 -40";
    std::cout << "Parsing " << std::quoted(p) << ":\n";

    for (;;)
    {
        // 库函数调用能设置 errno 为任何非零值，无关乎是否有错误，
        // 故为检查 strtol 设置的错误，需要清除它
        errno = 0;
        char* p_end;
        const long i = std::strtol(p, &p_end, 10);
        if (p == p_end)
            break;

        const bool range_error = errno == ERANGE;
        const std::string extracted(p, p_end - p);
        p = p_end;

        std::cout << "Extracted " << std::quoted(extracted)
                  << ", strtol returned " << i << '.';
        if (range_error)
            std::cout << " Range error occurred.";

        std::cout << '\n';
    }
}

可能的输出：

Parsing "10 200000000000000000000000000000 30 -40":
Extracted "10", strtol returned 10.
Extracted " 200000000000000000000000000000", strtol returned 9223372036854775807. Range error occurred.
Extracted " 30", strtol returned 30.
Extracted " -40", strtol returned -40.

参阅

stoistolstoll (C++11)(C++11)(C++11) | 转换字符串为有符号整数 (函数)
strtoulstrtoull (C++11) | 转换字节字符串为无符号整数值 (函数)
strtoimaxstrtoumax (C++11)(C++11) | 转换字节字符串为 std::intmax_t 或 std::uintmax_t (函数)
wcstolwcstoll | 转换宽字符串为整数值 (函数)
strtofstrtodstrtold | 转换字节字符串为浮点值 (函数)
from_chars (C++17) | 转换字符序列到整数或浮点值 (函数)
atoiatolatoll (C++11) | 转换字节字符串为整数值 (函数)


std::strtoul, std::strtoull

< cpp‎ | string‎ | byte
定义于头文件 <cstdlib> |
unsigned long strtoul( const char *str, char **str_end, int base ); |
unsigned long long strtoull( const char *str, char **str_end, int base ); | (C++11 起)

转译 str 所指的字符串中的无符号整数值。

舍弃所有空白符（以调用 isspace() 鉴别），直到找到首个非空白符，然后取尽可能多的字符组成底 n （其中 n=base ）的无符号整数表示，并将它们转换成一个整数值。合法的无符号整数值由下列部分组成：

  • (可选)正或负号
  • (可选)指示八进制底的前缀（ 0 ）（仅当底为 8 或 ​0​ 时应用）
  • (可选)指示十六进制底的前缀（ 0x 或 0X ）（仅当底为 16 或 ​0​ 时应用）
  • 一个数字序列

底的合法集是 {0,2,3,...,36} 。合法数字集对于底 2 整数是 {0,1}，对于底3整数是 {0,1,2} ，以此类推。对于大于 10 的底，合法数字包含字母字符，从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。

当前安装的 C 本地环境可能接受另外的数字格式。

若 base 为 ​0​ ，则自动检测数值进制：若前缀为 0 ，则底为八进制，若前缀为 0x 或 0X ，则底为十六进制，否则底为十进制。

若符号是输入序列的一部分，则对从数字序列计算得来的数字值取反，如同用结果类型的一元减，它对无符号整数应用回卷规则。

函数设置 str_end 所指向的指针指向最后一个被转译字符的后一字符。若 str_end 为空指针，则忽略它。

参数

str | - | 指向要被转译的空终止字符串的指针
str_end | - | 指向指向字符的指针的指针。
base | - | 被转译整数值的底

返回值

成功时为对应 str 内容的整数值。若被转换值落在对应返回类型的范围外，则发生值域错误（ errno 被设为 ERANGE ）并返回 ULONG_MAX 或 ULLONG_MAX 。若无转换可进行，则返回 ​0​ 。

示例

#include <iostream>
#include <string>
#include <errno.h>
#include <cstdlib>

int main()
{
    const char* p = "10 200000000000000000000000000000 30 -40";
    char *end;
    std::cout << "Parsing '" << p << "':\n";
    for (unsigned long i = std::strtoul(p, &end, 10);
         p != end;
         i = std::strtoul(p, &end, 10))
    {
        std::cout << "'" << std::string(p, end-p) << "' -> ";
        p = end;
        if (errno == ERANGE){
            std::cout << "range error, got ";
            errno = 0;
        }
        std::cout << i << '\n';
    }
}

可能的输出：

Parsing '10 200000000000000000000000000000 30 -40':
'10' -> 10
' 200000000000000000000000000000' -> range error, got 18446744073709551615
' 30' -> 30
' -40' -> 18446744073709551576

参阅

stoulstoull (C++11)(C++11) | 转换字符串为无符号整数 (函数)
strtolstrtoll (C++11) | 转换字节字符串为整数值 (函数)
strtoimaxstrtoumax (C++11)(C++11) | 转换字节字符串为 std::intmax_t 或 std::uintmax_t (函数)
wcstoulwcstoull | 转换宽字符串为无符号整数值 (函数)
strtofstrtodstrtold | 转换字节字符串为浮点值 (函数)
from_chars (C++17) | 转换字符序列到整数或浮点值 (函数)
atoiatolatoll (C++11) | 转换字节字符串为整数值 (函数)


std::strxfrm

< cpp‎ | string‎ | byte
定义于头文件 <cstring>
std::size_t strxfrm( char* dest, const char* src, std::size_t count );

变换 src 所指向的空终止字节字符串为实现定义形式，满足当前 C 本地环境中，以 std::strcmp 比较二个变换后字符串给出与用 std::strcoll 比较源字符串相同的结果。

将变换后字符串的首 count 个字符写入目标，包含空终止字符，并返回排除空终止字符的完整转换后字符串的长度。

若 dest 数组不够大则行为未定义。若 dest 与 src 重叠则行为未定义。

若 count 为 ​0​ ，则允许 dest 为空指针。

注意

能接收整个变换后字符串的正确缓冲区长度为 1+std::strxfrm( NULL, src, 0) 。

在以同一字符串或字符串集合进行多个本地环境依赖的比较时，使用此函数，因为仅用 std::strxfrm 变换所有字符串一次，而以 std::strcmp 进行后继比较更为高效。

参数

dest | - | 指向将写入变换后的字符串的数组首元素的指针
src | - | 指向要变换的空终止字节字符串首元素的指针
count | - | 要写入的最大字符数

返回值

变换后的字符串长度，不包含空终止字符。

示例

#include <iostream>
#include <iomanip>
#include <cstring>
#include <string>
#include <cassert>

int main()
{
    char* loc = std::setlocale(LC_COLLATE, "cs_CZ.iso88592");
    assert(loc);

    std::string in1 = "hrnec";
    std::string out1(1+std::strxfrm(nullptr, in1.c_str(), 0), ' ');
    std::string in2 = "chrt";
    std::string out2(1+std::strxfrm(nullptr, in2.c_str(), 0), ' ');

    std::strxfrm(&out1[0], in1.c_str(), out1.size());
    std::strxfrm(&out2[0], in2.c_str(), out2.size());

    std::cout << "In the Czech locale: ";
    if(out1 < out2)
         std::cout << in1 << " before " << in2 << '\n';
    else
         std::cout << in2 << " before " << in1 << '\n';

    std::cout << "In lexicographical comparison: ";
    if(in1 < in2)
         std::cout << in1 << " before " << in2 << '\n';
    else
         std::cout << in2 << " before " << in1 << '\n';

}

输出：

In the Czech locale: hrnec before chrt
In lexicographical comparison: chrt before hrnec

参阅

wcsxfrm | 变换宽字符串，使得 wcscmp 会产生与 wsccoll 相同的结果 (函数)
do_transform [虚] | 变换字符串，使得能用比较替换对照 (std::collate<CharT> 的虚受保护成员函数)
strcoll | 按照当前本地环境比较两个字符串 (函数)


std::tolower

< cpp‎ | string‎ | byte
定义于头文件 <cctype>
int tolower( int ch );

按照当前安装的 C 本地环境所定义的规则，转换给定字符为小写。

默认 "C" 本地环境中，分别以小写字母 abcdefghijklmnopqrstuvwxyz 替换大写字母 ABCDEFGHIJKLMNOPQRSTUVWXYZ 。

参数

ch - 要转换的字符。若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义

返回值

ch 的小写版本，或若无列于当前 C 本地环境的小写版本，则为不修改的 ch 。

注意

同所有其他来自 <cctype> 的函数，若参数值既不能表示为 unsigned char 又不等于 EOF 则 std::tolower 的行为未定义。为了以简单的 char （或 signed char ）安全使用此函数，首先要将参数转换为 unsigned char ：

char my_tolower(char ch)
{
    return static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
}

类似地，迭代器的值类型为 char 或 signed char 时，不应直接将它们用于标准算法。而是要首先转换值为 unsigned char ：

std::string str_tolower(std::string s) {
    std::transform(s.begin(), s.end(), s.begin(),
                // static_cast<int(*)(int)>(std::tolower)         // 错误
                // [](int c){ return std::tolower(c); }           // 错误
                // [](char c){ return std::tolower(c); }          // 错误
                   [](unsigned char c){ return std::tolower(c); } // 正确
                  );
    return s;
}

示例

#include <iostream>
#include <cctype>
#include <clocale>

int main()
{
    unsigned char c = '\xb4'; // ISO-8859-15 中的字符 Ž
                              // 但在 ISO-8859-1 中为 ´ （锐音符）

    std::setlocale(LC_ALL, "en_US.iso88591");
    std::cout << std::hex << std::showbase;
    std::cout << "in iso8859-1, tolower('0xb4') gives "
              << std::tolower(c) << '\n';
    std::setlocale(LC_ALL, "en_US.iso885915");
    std::cout << "in iso8859-15, tolower('0xb4') gives "
              << std::tolower(c) << '\n';
}

输出：

in iso8859-1, tolower('0xb4') gives 0xb4
in iso8859-15, tolower('0xb4') gives 0xb8

参阅

toupper | 转换字符为大写 (函数)
tolower(std::locale) | 用本地环境的 ctype 刻面将字符转换为小写 (函数模板)
towlower | 转换宽字符为小写 (函数)


std::toupper

< cpp‎ | string‎ | byte
定义于头文件 <cctype>
int toupper( int ch );

按照当前安装的 C 本地环境所定义的字符转换规则，转换给定字符为大写。

默认 "C" 本地环境中，分别以大写字母 ABCDEFGHIJKLMNOPQRSTUVWXYZ 替换下列小写字母 abcdefghijklmnopqrstuvwxyz 。

参数

ch - 要转化的字符。若 ch 的值不能表示为 unsigned char 且不等于 EOF ，则行为未定义。

返回值

被转换的字符，或若当前 C 本地环境不定义大写版本则为 ch 。

注意

同所有其他来自 <cctype> 的函数，若参数值既不能表示为 unsigned char 又不等于 EOF 则 std::toupper 的行为未定义。为了以简单的 char （或 signed char ）安全使用此函数，首先要将参数转换为 unsigned char ：

char my_toupper(char ch)
{
    return static_cast<char>(std::toupper(static_cast<unsigned char>(ch)));
}

类似地，迭代器的值类型为 char 或 signed char 时，不应直接将它们用于标准算法。而是要首先转换值为 unsigned char ：

std::string str_toupper(std::string s) {
    std::transform(s.begin(), s.end(), s.begin(),
                // static_cast<int(*)(int)>(std::toupper)         // 错误
                // [](int c){ return std::toupper(c); }           // 错误
                // [](char c){ return std::toupper(c); }          // 错误
                   [](unsigned char c){ return std::toupper(c); } // 正确
                  );
    return s;
}

示例

#include <iostream>
#include <cctype>
#include <clocale>

int main()
{
    unsigned char c = '\xb8'; // ISO-8859-15 中的字符 ž
                              // 但在 ISO-8859-1 中为 ¸ （下加符）

    std::setlocale(LC_ALL, "en_US.iso88591");
    std::cout << std::hex << std::showbase;
    std::cout << "in iso8859-1, toupper('0xb8') gives " << std::toupper(c) << '\n';
    std::setlocale(LC_ALL, "en_US.iso885915");
    std::cout << "in iso8859-15, toupper('0xb8') gives " << std::toupper(c) << '\n';
}

输出：

in iso8859-1, toupper('0xb8') gives 0xb8
in iso8859-15, toupper('0xb8') gives 0xb4

参阅

tolower | 转换字符为小写 (函数)
toupper(std::locale) | 用本地环境的 ctype 刻面将字符转换为大写 (函数模板)
towupper | 转换宽字符为大写 (函数)


std::char_traits

< cpp‎ | string
定义于头文件 <string>
template<

class CharT

> class char_traits;

char_traits 类是一种特性类模板，对给定的字符类型抽象基础字符和字符串比较操作。有定义操作集是几乎始终可实现于其项的通用算法。从而可以将这些算法用于几乎任何可能的字符或字符串类型，只需提供自定义的 char_traits 类。

char_traits 类模板表现为显式实例化的基础。用户可以对任何自定义字符类型提供特化。标准字符类型上已定义了数种特化。

标准特化

标准特化的成员 typedef 定义如下。

特化 | char_type | int_type | pos_type
std::char_traits<char> | char | int | std::streampos
std::char_traits<wchar_t> | wchar_t | std::wint_t | std::wstreampos
std::char_traits<char16_t> (C++11) | char16_t | std::uint_least16_t | std::u16streampos
std::char_traits<char32_t> (C++11) | char32_t | std::uint_least32_t | std::u32streampos
std::char_traits<char8_t> (C++20) | char8_t | unsigned int | std::u8streampos
成员类型 | 定义（对所有标准特化相同）
off_type | std::streamoff
state_type | std::mbstate_t
comparison_category (C++20) | std::strong_ordering

标准特化的成员函数的语义定义如下：

特化 | assign | eq | lt | eof
std::char_traits<char> | = | unsigned char 的 == | unsigned char 的 < | EOF
std::char_traits<wchar_t> | = | == | < | WEOF
std::char_traits<char16_t> (C++11) | = | == | < | 非法 UTF-16 编码单元
std::char_traits<char32_t> (C++11) | = | == | < | 非法 UTF-32 编码单元
std::char_traits<char8_t> (C++20) | = | == | < | 非法 UTF-8 编码单元

char_traits 类模板的标准特化满足字符特征 (CharTraits) 的要求。

成员类型

类型 | 定义
char_type | CharT
int_type | 能保有所有 char_type 值加 EOF 的整数类型
off_type | 实现定义
pos_type | 实现定义
state_type | 实现定义

成员函数

assign [静态] | 赋值一个字符 (公开静态成员函数)
eqlt [静态] | 比较二个字符 (公开静态成员函数)
move [静态] | 移动一个字符序列到另一个上 (公开静态成员函数)
copy [静态] | 复制一个字符序列 (公开静态成员函数)
compare [静态] | 以字典序比较二个字符序列 (公开静态成员函数)
length [静态] | 返回一个字符序列的长度 (公开静态成员函数)
find [静态] | 在字符序列中查找一个字符 (公开静态成员函数)
to_char_type [静态] | 转换 int_type 到等效的 char_type (公开静态成员函数)
to_int_type [静态] | 转换 char_type 到等效的 int_type (公开静态成员函数)
eq_int_type [静态] | 比较二个 int_type 值 (公开静态成员函数)
eof [静态] | 返回一个 eof 值 (公开静态成员函数)
not_eof [静态] | 检查字符是否为 eof 值 (公开静态成员函数)

示例

用户定义的字符特性可以用于提供无关大小写的比较

#include <string>
#include <string_view>
#include <iostream>
#include <cctype>

struct ci_char_traits : public std::char_traits<char> {
    static char to_upper(char ch) {
        return std::toupper((unsigned char) ch);
    }
    static bool eq(char c1, char c2) {
         return to_upper(c1) == to_upper(c2);
     }
    static bool lt(char c1, char c2) {
         return to_upper(c1) <  to_upper(c2);
    }
    static int compare(const char* s1, const char* s2, std::size_t n) {
        while ( n-- != 0 ) {
            if ( to_upper(*s1) < to_upper(*s2) ) return -1;
            if ( to_upper(*s1) > to_upper(*s2) ) return 1;
            ++s1; ++s2;
        }
        return 0;
    }
    static const char* find(const char* s, std::size_t n, char a) {
        auto const ua (to_upper(a));
        while ( n-- != 0 )
        {
            if (to_upper(*s) == ua)
                return s;
            s++;
        }
        return nullptr;
    }
};

template<class DstTraits, class CharT, class SrcTraits>
constexpr std::basic_string_view<CharT, DstTraits>
    traits_cast(const std::basic_string_view<CharT, SrcTraits> src) noexcept
{
    return {src.data(), src.size()};
}

int main()
{
    using namespace std::literals;

    constexpr auto s1 = "Hello"sv;
    constexpr auto s2 = "heLLo"sv;

    if (traits_cast<ci_char_traits>(s1) == traits_cast<ci_char_traits>(s2))
        std::cout << s1 << " and " << s2 << " are equal\n";
}

输出：

Hello and heLLo are equal

参阅

basic_string
 存储并操作字符序列
(类模板)


std::char_traits<CharT>::assign

< cpp‎ | string‎ | char traits
 | (1)
static void assign( char_type& r, const char_type& a ); |  | (C++11 前)
static void assign( char_type& r, const char_type& a ) noexcept; |  | (C++11 起) (C++17 前)
static constexpr void assign( char_type& r, const char_type& a ) noexcept; |  | (C++17 起)
 | (2)
static char_type* assign( char_type* p, std::size_t count, char_type a ); |  | (C++20 前)
static constexpr char_type* assign( char_type* p, std::size_t count, char_type a ); |  | (C++20 起)

赋值一个字符。

1) 赋值字符 a 给字符 r 。
2) 赋值字符 a 给 p 所指的字符序列中的 count 个字符的每一个。

参数

a | - | 要赋值的字符值
r | - | 被赋值的字符
p | - | 指向被赋值字符序列的指针
count | - | 字符序列的长度

返回值

1) （无）
2) p

复杂度

1) 常数。
2) 与 count 成线性


std::char_traits<CharT>::eq, std::char_traits<CharT>::lt

< cpp‎ | string‎ | char traits
 | (1)
static bool eq( char_type a, char_type b ); |  | (C++11 前)
static constexpr bool eq( char_type a, char_type b ) noexcept; |  | (C++11 起)
 | (2)
static bool lt( char_type a, char_type b ); |  | (C++11 前)
static constexpr bool lt( char_type a, char_type b ) noexcept; |  | (C++11 起)

比较二个字符。

1) 比较 a 与 b 的相等性。
2) 以全序的方式比较 a 与 b 。

对于 char 特化， eq 与 lt 定义成等同于类型 unsigned char 的内建运算符 == 与 < （不是 char 的）。

 (C++11 起)

参数

a, b - 要比较的字符值

返回值

1) 若 a 等于 b 则为 true ， 否则为 false 。
2) 若 a 小于 b 则为 true ， 否则为 false 。

复杂度

常数。


std::char_traits<CharT>::compare

< cpp‎ | string‎ | char traits
static int compare( const char_type* s1, const char_type* s2, std::size_t count ); | (C++17 前)
static constexpr int compare( const char_type* s1, const char_type* s2, std::size_t count ); | (C++17 起)

比较字符串 s1 与 s2 的首 count 个字节，比较按字典序进行。

若 count 为零，则认为字符串相等。

参数

s1, s2 | - | 指向要比较的字符串的指针
count | - | 要比较来自每个字符串的字符数

返回值

若 s1 小于 s2 则为负值。

若 s1 等于 s2 则为 ​0​ 。

若 s1 大于 s2 则为正值。

异常

不抛出。

复杂度

与 count 成线性。


std::char_traits<CharT>::copy

< cpp‎ | string‎ | char traits
static char_type* copy( char_type* dest, const char_type* src, std::size_t count ); | (C++20 前)
static constexpr char_type* copy( char_type* dest, const char_type* src, std::size_t count ); | (C++20 起)

从 src 所指的字符串复制 count 个字符到 dest 所指向的字符序列。

正式而言，对 [0, count) 中每个 i 进行 assign(src[i], dest[i]) 。

若复制的字符范围重叠，即 src 在 [dest, dest + count) 之中，则行为未定义。

参数

dest | - | 指向要复制的字符串的指针
src | - | 指向复制来源的字符串的指针
count | - | 要复制的字符数

返回值

dest

异常

不抛出。

复杂度

线性。


std::char_traits<CharT>::eof

< cpp‎ | string‎ | char traits
static int_type eof(); | (C++11 前)
static constexpr int_type eof() noexcept; | (C++11 起)

返回不等价于任何 char_type 合法值的值。

正式而言，返回的值 e 满足 X::eq_int_type(e, X::to_int_type(c)) 对于所有 c 为 false 。

参数

（无）

返回值

不等于任何 char_type 合法值的值。

复杂度

常数。

参阅

not_eof
[静态]
 检查字符是否为 eof 值
(公开静态成员函数)


std::char_traits<CharT>::eq_int_type

< cpp‎ | string‎ | char traits
static bool eq_int_type( int_type c1, int_type c2 ); | (C++11 前)
static constexpr bool eq_int_type( int_type c1, int_type c2 ) noexcept; | (C++11 起)

检查二个 int_type 的值是否相等。

正式而言，

  • 若存在满足 c1 == X::to_int_type(a) 及 c2 == X::to_int_type(b) 的值 a 与 b ，则结果等于 X::eq(a,b)
  • 否则，若 c1 与 c2 均为 X::eof() 的副本，则结果为 true
  • 否则，若 c1 与 c2 之一为 X::eof() 的副本， 而另一者不是，则结果为 false
  • 否则，结果未指定

参数

c1, c2 - 要比较的值

返回值

若 c1 在上述规则下等于 c2 则为 true ，否则为 false 。

复杂度

常数。


std::char_traits<CharT>::find

< cpp‎ | string‎ | char traits
static const char_type* find( const char_type* p, std::size_t count, const char_type& ch ); | (C++17 前)
static constexpr const char_type* find( const char_type* p, std::size_t count, const char_type& ch ); | (C++17 起)

在 p 所指字符序列的前 count 个字符中查找字符 ch 。

参数

p | - | 指向要查找的字符串的指针
count | - | 要分析的字符数量
ch | - | 要查找的字符

返回值

指向 [p, p + count) 所指定范围中首个比较等于 ch 的字符的指针，或若未找到则为空指针。

异常

不抛出。

复杂度

与 count 成线性。


std::char_traits<CharT>::length

< cpp‎ | string‎ | char traits
static std::size_t length( const char_type* s ); | (C++17 前)
static constexpr std::size_t length( const char_type* s ); | (C++17 起)

返回 s 所指的字符序列长度，即空终止字符（ CharT() ）的位置。

参数

s - 指向要返回长度的字符序列的指针

返回值

s 所指向字符序列的长度。

异常

不抛出。

复杂度

线性。

示例

#include <iostream>

void print(const char* str)
{
  std::cout << "string '" << str << "' ";
  std::cout << "length = " << std::char_traits<char>::length(str) << '\n';
}

int main()
{
  print("foo");

  std::string s("booo");
  print(s.c_str());
}

输出：

string 'foo' length = 3
string 'booo' length = 4


std::char_traits<CharT>::move

< cpp‎ | string‎ | char traits
static char_type* move( char_type* dest, const char_type* src, std::size_t count ); | (C++20 前)
static constexpr char_type* move( char_type* dest, const char_type* src, std::size_t count ); | (C++20 起)

从 src 所指的字符串复制 count 个字符到 dest 所指的字符串。

即使字符范围重叠，即 src 在 [dest, dest + count) 之中，也正确进行。

参数

dest | - | 指向要复制的字符串的指针
src | - | 指向复制来源的字符串的指针
count | - | 要复制的字符数

返回值

dest

异常

不抛出。

复杂度

线性。


std::char_traits<CharT>::not_eof

< cpp‎ | string‎ | char traits
static int_type not_eof( int_type e ); | (C++11 前)
static constexpr int_type not_eof( int_type e ) noexcept; | (C++11 起)

检查 e 是否不等价于 eof 值。

正式而言

  • 若 X::eq_int_type(e, X::eof()) 为 true ，则返回 e
  • 否则，返回满足 X::eq_int_type(f, X::eof()) 为 false 的 f

参数

e - 要分析的值

返回值

若 e 与 eof 不等价则返回 e ，否则返回某些其他非 eof 值。

复杂度

常数。

参阅

eof
[静态]
 返回一个 eof 值
(公开静态成员函数)


std::char_traits<CharT>::to_char_type

< cpp‎ | string‎ | char traits
static char_type to_char_type( int_type c ); | (C++11 前)
static constexpr char_type to_char_type( int_type c ) noexcept; | (C++11 起)

转换 int_type 的值到 char_type 。若无等价值（例如 c 是 eof() 值的副本时），结果未指定。

正式而言，返回满足 X::eq_int_type(c, X::to_int_type(x)) 为 true 的值 x ，且若这种 x 不存在在返回未指定值。

参数

c - 要转换的值

返回值

等于 c 的值。

复杂度

常数。


std::char_traits<CharT>::to_int_type

< cpp‎ | string‎ | char traits
static int_type to_int_type( char_type c ); | (C++11 前)
static constexpr int_type to_int_type( char_type c ) noexcept; | (C++11 起)

转换 char_type 的值到 int_type 。

参数

c - 要转换的值

返回值

等价于 c 的值。

复杂度

常数。

注意

对于每个 char_type 的合法值，都有一个不同于 eof 的 int_type 值。


空终止多字节字符串

< cpp‎ | string

空终止多字节字符串（ null-terminated multibyte string, NTMBS ），或“多字节字符串”，是后随拥有零值的字节（空终止字符）的非零字节序列。

存储于该字符串中的每个字符可能占用多于一个字节。用于表示字符的编码是本地环境限定的：它可以是 UTF-8 、 GB18030 、 EUC-JP 、 Shift-JIS 等。例如，字符数组 {'\xe4','\xbd','\xa0','\xe5','\xa5','\xbd','\0'} 是一个以UTF8编码包含 "你好" 的 NTMBS ：首三个字节编码字符 "你" ，接下来三个字节编码字符 "好" 。编码于 GB18030 的相同字符串是字符数组 {'\xc4', '\xe3', '\xba', '\xc3', '\0'} ，其中二个字符各编码为双字节序列。

一些多字节编码中，任何给定的多字节字符序列可以根据之前的字节序列，称之为“迁移序列”，表示不同的字符。这种编码被称为状态依赖的：要求知晓当前迁移状态以转译每个字符。 NTMBS 仅若以初始迁移状态开始及结束才合法：若使用迁移序列，则对应的无迁移序列必须在空终止字符前存在。这种编码的例子是 7-bit JIS 、 BOCU-1 及 SCSU 。

多字节字符串与空终止字节字符串（ NTBS ）布局兼容，即能用相同的设施存储、复制并检验，除了计算字符数。若当前本地环境生效，则 I/O 函数亦处理多字节字符串。多字节字符串可用 std::codecvt 成员函数、 std::wstring_convert 或下列依赖本地环境的转换函数与宽字符串相互转换：

多字节/宽字符串转换

定义于头文件 <cstdlib>
mblen | 返回下一个多字节字符中的字节数 (函数)
mbtowc | 将下一个多字节字符转换成宽字符 (函数)
wctomb | 转换宽字符为其多字节表示 (函数)
mbstowcs | 转换窄多字节字符串为宽字符串 (函数)
wcstombs | 转换宽字符串为窄多字节字符串 (函数)
定义于头文件 <cwchar>
mbsinit | 检查 mbstate_t 对象是否表示初始迁移状态 (函数)
btowc | 若可能，则加宽单字节窄字符为宽字符 (函数)
wctob | 若可能，则窄化宽字符为单字节窄字符 (函数)
mbrlen | 给定状态，返回下一个多字节字符中的字节数 (函数)
mbrtowc | 给定状态，转换下个多字节字符为宽字符 (函数)
wcrtomb | 给定状态，转换宽字符到其多字节表示 (函数)
mbsrtowcs | 给定状态，转换窄多字节字符串到宽字符串 (函数)
wcsrtombs | 给定状态，转换宽字符串为窄多字节字符串 (函数)
定义于头文件 <cuchar>
mbrtoc8 (C++20) | 转换窄多字节字符为 UTF-8 编码 (函数)
c8rtomb (C++20) | 转换 UTF-8 字符串为窄多字节编码 (函数)
mbrtoc16 (C++11) | 转换窄多字节字符为 UTF-16 编码 (函数)
c16rtomb (C++11) | 转换 16 位宽字符为窄多字节字符串 (函数)
mbrtoc32 (C++11) | 转换窄多字节字符为 UTF-32 编码 (函数)
c32rtomb (C++11) | 转换 32 位宽字符为窄多字节字符串 (函数)

类型

定义于头文件 <cwchar>
mbstate_t
 迭代多字节字符串所需的转换状态信息
(类)

宏

定义于头文件 <climits>
MB_LEN_MAX | 多字节字符中的最大字节数 (宏常量)
定义于头文件 <cstdlib>
MB_CUR_MAX | 当前 C 本地环境中多字节字符的最大字节数 (宏变量)
定义于头文件 <cuchar>
__STDC_UTF_16__ (C++11) | 指示 mbrtoc16 与 c16rtomb 使用 UTF-16 编码 (宏常量)
__STDC_UTF_32__ (C++11) | 指示 mbrtoc32 与 c32rtomb 使用 UTF-32 编码 (宏常量)

参阅


std::btowc

< cpp‎ | string‎ | multibyte
定义于头文件 <cwchar>
std::wint_t btowc( int c );

加宽单字节字符 c 为其宽字符等价物。

大多数多字节字符编码用单字节码表示来自 ASCII 字符集的字符。此函数可用于转换这种字符为 wchar_t 。

参数

c - 要加宽的单字节字符

返回值

若 c 为 EOF 则为 WEOF 。

若 (unsigned char)c 在初始迁移状态为合法单字节字符，则为 c 的宽字符表示，否则为 WEOF 。

示例

#include <iostream>
#include <cwchar>
#include <clocale>

void try_widen(char c)
{
    std::wint_t w = std::btowc(c);
    if(w != WEOF)
        std::cout << "The single-byte character " << +(unsigned char)c
                  << " widens to " << +w << '\n';
    else
        std::cout << "The single-byte character " << +(unsigned char)c
                  << " failed to widen\n";
}

int main()
{
    std::setlocale(LC_ALL, "lt_LT.iso88594");
    std::cout << std::hex << std::showbase << "In Lithuanian ISO-8859-4 locale:\n";
    try_widen('A');
    try_widen('\xdf'); // ISO-8859-4 中的德文字母 ß (U+00df)
    try_widen('\xf9'); // ISO-8859-4 中的立陶宛字母 ų (U+0173)

    std::setlocale(LC_ALL, "lt_LT.utf8");
    std::cout << "In Lithuanian UTF-8 locale:\n";
    try_widen('A');
    try_widen('\xdf');
    try_widen('\xf9');
}

输出：

In Lithuanian ISO-8859-4 locale:
The single-byte character 0x41 widens to 0x41
The single-byte character 0xdf widens to 0xdf
The single-byte character 0xf9 widens to 0x173
In Lithuanian UTF-8 locale:
The single-byte character 0x41 widens to 0x41
The single-byte character 0xdf failed to widen
The single-byte character 0xf9 failed to widen

参阅

wctob | 若可能，则窄化宽字符为单字节窄字符 (函数)
do_widen [虚] | 将一或多个字符从 char 转换为 charT (std::ctype<CharT> 的虚受保护成员函数)


std::c16rtomb

< cpp‎ | string‎ | multibyte
定义于头文件 <cuchar> |
std::size_t c16rtomb( char* s, char16_t c16, std::mbstate_t * ps ); | (C++11 起)

从变长 16 位宽字符表示（典型地为 UTF-16 ）转换单个编码点到其窄多字节字符表示。

若 s 不是空指针且 c16 是合法的编码点变长编码中的最后一个 16 位编码单元，则函数确定存储该编码点所需的字节数（包含任何迁移序列，并考虑当前多字节转换状态 *ps ），并存储多字节表示于首元素为 s 所指向的字符数组，若必要则更新 *ps 。此函数最能写入 MB_CUR_MAX 个字节。

若 s 是空指针，则调用等价于对于某内部缓冲区 buf 的 std::c16rtomb(buf, u'\0', ps) 。

若 c16 是空宽字符 u'\0' ，则存储空字节，前附恢复到初始迁移状态所需的任何迁移序列，并更新 *ps 以表示初始迁移状态。

若 c16 不是宽字符的 16 位表示中最终编码单元，则不写入 s 所指向的数组，只更新 *ps 。

此函数所用的宽字符编码为当前活跃的 C 本地环境所指定。

参数

s | - | 指向将存储多字节字符的窄字符数组的指针
c16 | - | 要转换的 16 位宽字符
ps | - | 指向转译多字节字符串时所用转换状态对象的指针

返回值

成功时，返回写入首元素为 s 所指向的字符数组的字节数（包含任何迁移序列）。此值可以是 ​0​ ，例如在处理多 char16_t 单元序列的前导 char16_t 单元时（在处理 UTF-16 代理对中的前导代理时出现）。

失败时（若 c16 不是合法的 16 位编码单元），则返回 -1 ，并存储 EILSEQ 于 errno ，把 *ps 置于未指定状态。

注意

C++ 标准将此函数的语义委派到 C 标准。在 C11 刚发布时，不同于转换变宽多字节（如 UTF-8 ）到变宽 16 位（如 UTF-16 ）编码的 std::mbrtoc16 ，此函数只能转换单个单元的 16 位编码，这表示尽管此函数的原目的如此，它仍不能转换 UTF-16 到 UTF-8 。这为 C11 后的缺陷报告 DR488 所更正。

示例

注意：此示例假设应用缺陷报告 488 的修复

#include <iostream>
#include <iomanip>
#include <string_view>
#include <clocale>
#include <cuchar>
#include <climits>

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    std::u16string_view strv = u"zß水🍌"; // 或 z\u00df\u6c34\U0001F34C
    std::cout << "Processing " << strv.size() << " UTF-16 code units: [ ";
    for(char16_t c : strv)
        std::cout << std::showbase << std::hex << c << ' ';
    std::cout << "]\n";

    std::mbstate_t state{};
    char out[MB_LEN_MAX]{};
    for(char16_t c : strv)
    {
        std::size_t rc = std::c16rtomb(out, c, &state);
        std::cout << c << " converted to [ ";
        if(rc != (std::size_t)-1)
            for(unsigned char c8 : std::string_view{out, rc})
                std::cout << +c8 << ' ';
        std::cout << "]\n";
    }
}

输出：

Processing 5 UTF-16 code units: [ 0x7a 0xdf 0x6c34 0xd83c 0xdf4c ]
0x7a converted to [ 0x7a ]
0xdf converted to [ 0xc3 0x9f ]
0x6c34 converted to [ 0xe6 0xb0 0xb4 ]
0xd83c converted to [ ]
0xdf4c converted to [ 0xf0 0x9f 0x8d 0x8c ]

参阅

mbrtoc16 (C++11) | 转换窄多字节字符为 UTF-16 编码 (函数)
do_out [虚] | 从 internT 转换字符串为 externT 转换字符串，如在写入文件时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


std::c32rtomb

< cpp‎ | string‎ | multibyte
定义于头文件 <cuchar> |
std::size_t c32rtomb( char* s, char32_t c32, std::mbstate_t * ps ); | (C++11 起)

转换 UTF-32 字符到其窄多字节表示。

若 s 不是空指针，则函数确定存储 c32 的多字节字符表示所需的字节数（包含任何迁移序列，并考虑当前的多字节转换状态 *ps ），并存储多字节字符表示于首元素为 s 所指向的字符数组，按需更新 *ps 。此函数至多能写 MB_CUR_MAX 个字符。

若 s 是空指针，则调用等价于对某内部存储 buf 的 std::c32rtomb(buf, U'\0', ps) 。

若 c32 是空宽字符 U'\0' ，则存储空字节，前附恢复到初始迁移状态所需的任何迁移序列，并更新转换状态参数 *ps 以表示初始迁移状态。

此函数所用的多字节字符编码为当前活跃的 C 本地环境所指定。

参数

s | - | 指向将存储多字节字符的窄字符数组的指针
c32 | - | 要转换的 32 位宽字符
ps | - | 指向转译多字节字符串所用的转换状态对象的指针

返回值

成功时，返回写入首元素为 s 所指向的字符数组的字节数（包含任何迁移序列）。此值可为 ​0​ ，例如在处理多 char32_t 单元序列中的前导 char32_t 单元时（ UTF-32 中不出现）。

失败时（若 c32 不是合法的 32 位宽字符），返回 -1 ，存储 EILSEQ 于 errno ，并置 *ps 于未指定状态。

示例

#include <iostream>
#include <iostream>
#include <iomanip>
#include <string_view>
#include <clocale>
#include <cuchar>
#include <climits>

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    std::u32string_view strv = U"zß水🍌"; // 或 z\u00df\u6c34\U0001F34C
    std::cout << "Processing " << strv.size() << " UTF-32 code units: [ ";
    for(char32_t c : strv)
        std::cout << std::showbase << std::hex << c << ' ';
    std::cout << "]\n";

    std::mbstate_t state{};
    char out[MB_LEN_MAX]{};
    for(char32_t c : strv)
    {
        std::size_t rc = std::c32rtomb(out, c, &state);
        std::cout << c << " converted to [ ";
        if(rc != (std::size_t)-1)
            for(unsigned char c8 : std::string_view{out, rc})
                std::cout << +c8 << ' ';
        std::cout << "]\n";
    }
}

输出：

Processing 4 UTF-32 code units: [ 0x7a 0xdf 0x6c34 0x1f34c ]
0x7a converted to [ 0x7a ]
0xdf converted to [ 0xc3 0x9f ]
0x6c34 converted to [ 0xe6 0xb0 0xb4 ]
0x1f34c converted to [ 0xf0 0x9f 0x8d 0x8c ]

参阅

mbrtoc32 (C++11) | 转换窄多字节字符为 UTF-32 编码 (函数)
do_out [虚] | 从 internT 转换字符串为 externT 转换字符串，如在写入文件时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


std::c8rtomb

< cpp‎ | string‎ | multibyte
定义于头文件 <cuchar> |
std::size_t c8rtomb( char* s, char8_t c8, std::mbstate_t * ps ); | (C++20 起)

转换来自 UTF-8 的单个编码点为窄多字节字符表示。

若 s 不是空指针且 c8 是编码点的合法 UTF-8 编码中的最后编码单元，则函数确定存储该编码点的多字节字符表示所需的字符数（包含任何迁移序列，并且考虑到当前多字节转换状态 *ps ），并存储多字节字符表示于首元素为 s 所指向的字符数组，按需更新 *ps 。此函数至多能写入 MB_CUR_MAX 个字节。

若 c8 不是编码点表示中的最终 UTF-8 编码单元，则函数不写入 s 所指向的数组，只更新 *ps 。

若 s 为空指针，则调用等价于对某内部缓冲区 buf 的 std::c8rtomb(buf, u8'\0', ps) 。

若 c8 为空字符 u8'\0' ，则存储空字节，前附任何恢复初始迁移状态所需的迁移序列，并更新转换状态参数 *ps ，使之代表初始迁移状态。

此函数所用的多字节编码由当前活跃的 C 本地环境指定。

参数

s | - | 指向将要存储多字节字符的通常字符数组的指针
c8 | - | 要转换的 UTF-8 编码单元
ps | - | 指向转译多字节字符串时使用的转换状态的指针

返回值

存储于数组中的的字节数（包含任何迁移序列）。 c8 不是编码点的 UTF-8 表示中的最终编码单元时，可以为零。

若 c8 非法（不贡献到对应合法多字节字符的 char8_t 序列），则存储宏 EILSEQ 的值于 errno ，返回 size_t(-1) ，而转换状态未指定。

注意

以空指针参数 s 调用 c8rtomb ，可能会与其他以空指针参数 s 对 c8rtomb 的调用造成数据竞争。

示例

本节未完成
原因：暂无示例

参阅

mbrtoc8
(C++20)
 转换窄多字节字符为 UTF-8 编码
(函数)


std::mblen

< cpp‎ | string‎ | multibyte
定义于头文件 <cstdlib>
int mblen( const char* s, std::size_t n );

确定多字节字符的字节大小，其首字节为 s 所指向。

若 s 是空指针，则重置全局转换状态并确定是否使用迁移序列。

此函数等价于调用 std::mbtowc ((wchar_t*)0, s, n) ，除了不影响 std::mbtowc 的转换状态。

注解

每次对 mblen 的调用更新内部全局转换状态（ std::mbstate_t 类型的静态对象，只为此函数所知）。若多字节编码使用迁移状态，则必须留意以避免回撤或多次扫描。任何情况下，多线程不应无同步地调用 mblen ：可用 std::mbrlen 代替。

参数

s | - | 指向多字节字符的指针
n | - | s中能被检验的字节数限制

返回值

若 s 不是空指针，则返回多字节字符所含的字节数，或若 s 所指的首字节不组成合法多字节字符则返回 -1 ，或若 s 指向空字符 '\0' 则返回 ​0​ 。

若 s 是空指针，则重置内部转换状态为初始迁移状态，并若当前多字节编码非状态依赖（不使用迁移序列）则返回 ​0​ ，或者若当前多字节编码为状态依赖（使用迁移序列）则返回非零。

示例

#include <clocale>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <string_view>

// 多字节字符串中的字符数是 mblen() 的和
// 注意：更简单的手段是 std::mbstowcs(NULL, s.c_str(), s.size())
std::size_t strlen_mb(const std::string_view s)
{
    std::size_t result = 0;
    const char* ptr = s.data();
    const char* end = ptr + s.size();
    std::mblen(NULL, 0); // 重置转换状态
    while (ptr < end) {
        int next = std::mblen(ptr, end-ptr);
        if (next == -1) {
            throw std::runtime_error("strlen_mb(): conversion error");
        }
        ptr += next;
        ++result;
    }
    return result;
}

void dump_bytes(const std::string_view str)
{
    std::cout << std::hex << std::uppercase << std::setfill('0');
    for (unsigned char c : str)
        std::cout << std::setw(2) << static_cast<int>(c) << ' ';
    std::cout << std::dec << '\n';
}

int main()
{
    // 允许 mblen() 以 UTF-8 多字节编码工作
    std::setlocale(LC_ALL, "en_US.utf8");
    // UTF-8 窄多字节编码
    const std::string_view str = "z\u00df\u6c34\U0001f34c"; // 或 u8"zß水🍌"
    std::cout << std::quoted(str) << " is " << strlen_mb(str)
              << " characters, but as much as " << str.size() << " bytes: ";
    dump_bytes(str);
}

可能的输出：

zß水🍌 is 10 bytes, but only 4 characters

参阅

mbtowc | 将下一个多字节字符转换成宽字符 (函数)
mbrlen | 给定状态，返回下一个多字节字符中的字节数 (函数)


std::mbrlen

< cpp‎ | string‎ | multibyte
定义于头文件 <cwchar>
std::size_t mbrlen( const char* s, std::size_t n, std::mbstate_t * ps);

给定当前转换状态 s ，确定首字节为 ps 所指向的多字节字符的剩余字节大小。

此函数等价于对于某 std::mbstate_t 类型的隐藏对象 internal 的调用 std::mbrtowc (nullptr, s, n, ps?ps:&internal) ，除了只求值表达式 ps 一次。

参数

s | - | 指向多字节字符串元素的指针
n | - | s 中能检验的字节数限制
ps | - | 指向保有转换状态的对象的指针

返回值

若下 n 个或更少字节完成空字符则为 ​0​ 。

完成合法多字节字符的字节数（ 1 与 n 之间）。

若发生编码错误则为 (size_t)-1 。

若下 n 个字节为可能合法，而在检验全部 n 个字节后仍不完整的多字节字符的一部分，则为 (size_t)-2 。

示例

#include <clocale>
#include <string>
#include <iostream>
#include <cwchar>

int main()
{
    // 允许 mbrlen() 以 UTF-8 多字节编码工作
    std::setlocale(LC_ALL, "en_US.utf8");
    // UTF-8 窄多字节编码
    std::string str = u8"水"; // 或 u8"\u6c34" 或 "\xe6\xb0\xb4"
    std::mbstate_t mb = std::mbstate_t();
    int len1 = std::mbrlen(&str[0], 1, &mb);
    if(len1 == -2) {
        std::cout << "The first 1 byte of " << str
                  << " is an incomplete multibyte char (mbrlen returns -2)\n";
    }
    int len2 = std::mbrlen(&str[1], str.size()-1, &mb);
    std::cout << "The remaining " << str.size()-1 << " bytes of " << str
              << " hold " << len2 << " bytes of the multibyte character\n";
    std::cout << "Attempting to call mbrlen() in the middle of " << str
              << " while in initial shift state returns "
              << (int)mbrlen(&str[1], str.size(), &mb) << '\n';

}

输出：

The first 1 byte of 水 is an incomplete multibyte char (mbrlen returns -2)
The remaining 2 bytes of 水 hold 2 bytes of the multibyte character
Attempting to call mbrlen() in the middle of 水 while in initial shift state returns -1

参阅

mbrtowc | 给定状态，转换下个多字节字符为宽字符 (函数)
mblen | 返回下一个多字节字符中的字节数 (函数)
do_length [虚] | 计算转换成给定的 internT 缓冲区会消耗的 externT 字符串长度 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


std::mbrtoc16

< cpp‎ | string‎ | multibyte
定义于头文件 <cuchar>
std::size_t mbrtoc16( char16_t* pc16,

const char* s,
std::size_t n,

std::mbstate_t * ps );
 (C++11 起)

转换窄多字节字符到其 UTF-16 字符表示。

若 s 不是空指针，则审查从 s 所指的字节开始的多字节字符串的至多 n 个字节，以检查完成下个多字节字符的字节数（包含任何迁移序列）。若函数确定 s 中下个多字节字符完整且合法，则将它转换到对应的 16 位宽字符，并将它存储于 *pc16 （若 pc16 非空）。

若 *s 中的宽字符对应多 char16_t 序列（例如 UTF-16 中的代理对），则在首次调用此函数后更新 *ps ，以令下次到 mbrtoc16 的调用将写出额外的 char16_t ，而不考虑 *s 。

若 s 是空指针，则忽略 n 与 pc16 的值，而调用等价于 std::mbrtoc16( NULL, "", 1, ps) 。

若产生的宽字符是空字符，则转换状态 *ps 表示初始迁移状态。

此函数所用的多字节字符编码为当前活跃的 C 本地环境所指定。

参数

pc16 | - | 指向将写入产生的 16-bit 宽字符的位置的指针
s | - | 指向用作输入的多字节字符串的指针
n | - | 能检验的字节数上的限制
ps | - | 指向转译多字节字符串时所用转换状态对象的指针

返回值

下列首个能应用者：

  • 若从 s 转换的字符是空字符（并存储于 *pc16 ，若它非空），则为 ​0​ 。
  • 成功从 s 转换的多字节字符的字节数 [1...n] 。
  • 若下个 char16_t 组成多 char16_t 字符，并已写入 *pc16 ，则为 -3 。此情况下不从输入处理字节。
  • 若接下来 n 个字符组成不完整，但到此还合法的多字节字符，则为 -2 。不写入 *pc16 。
  • 若出现编码错误则为 -1 。不写入 *pc16 ，存储值 EILSEQ 于 errno ，且 *ps 状态未指定。

示例

#include <iostream>
#include <iomanip>
#include <clocale>
#include <cstring>
#include <cwchar>
#include <cuchar>

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");

    std::string str = u8"z\u00df\u6c34\U0001F34C"; // 或 u8"zß水🍌"

    std::cout << "Processing " << str.size() << " bytes: [ " << std::showbase;
    for(unsigned char c: str) std::cout << std::hex << +c << ' ';
    std::cout << "]\n";

    std::mbstate_t state{}; // 零初始化到初始状态
    char16_t c16;
    const char *ptr = &str[0], *end = &str[0] + str.size();

    while(std::size_t rc = std::mbrtoc16(&c16, ptr, end - ptr + 1, &state))
    {
        std::cout << "Next UTF-16 char: " << std::hex << c16 << " obtained from ";
        if(rc == (std::size_t)-3)
            std::cout << "earlier surrogate pair\n";
        else if(rc <= ((std::size_t)-1) / 2) {
            std::cout << std::dec << rc << " bytes [ ";
            for(std::size_t n = 0; n < rc; ++n)
                std::cout << std::hex << +(unsigned char)ptr[n] << ' ';
            std::cout << "]\n";
            ptr += rc;
        } else break;
    }
}

输出：

Processing 10 bytes: [ 0x7a 0xc3 0x9f 0xe6 0xb0 0xb4 0xf0 0x9f 0x8d 0x8c ]
Next UTF-16 char: 0x7a obtained from 1 bytes [ 0x7a ]
Next UTF-16 char: 0xdf obtained from 2 bytes [ 0xc3 0x9f ]
Next UTF-16 char: 0x6c34 obtained from 3 bytes [ 0xe6 0xb0 0xb4 ]
Next UTF-16 char: 0xd83c obtained from 4 bytes [ 0xf0 0x9f 0x8d 0x8c ]
Next UTF-16 char: 0xdf4c obtained from earlier surrogate pair

参阅

c16rtomb (C++11) | 转换 16 位宽字符为窄多字节字符串 (函数)
do_in [虚] | 从 externT 转换字符串为 internT ，如在从文件读取时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


std::mbrtoc32

< cpp‎ | string‎ | multibyte
定义于头文件 <cuchar>
std::size_t mbrtoc32( char32_t* pc32,

const char* s,
std::size_t n,

std::mbstate_t * ps );
 (C++11 起)

从窄多字符编码转换编码点到其 UTF-32 字符表示。

若 s 不是空指针，则审查以 s 所指向的字节开始的多字节字符串的至多 n 个字节，以确定完成下个多字节字符所需的字节数（包含任何迁移序列）。若函数确定 s 中下个多字节字符完整且合法，则将它转换成对应的 32 位宽字符并存储于 *pc32 （若 pc32 非空）。

若 *s 中下个多字节字符对应多 char32_t 序列（对于 UTF-32 不可能），则在首次调用此函数后更新 *ps ，以满足下次到 mbrtoc32 的调用将写出附加的 char32_t ，而不考虑 *s 。

若 s 是空指针，则忽略 n 与 pc32 的值，而调用等价于 std::mbrtoc32( NULL, "", 1, ps) 。

若产生的宽字符是空字符，则转换状态 *ps 表示初始迁移状态。

此函数所用的多字节编码为当前活跃的 C 本地环境所指定。

参数

pc32 | - | 指向将写入产生的 32 位宽字符的位置的指针
s | - | 指向用作输入的多字节字符串的指针
n | - | s 中能检验的字节数上的限制
ps | - | 指向转译多字节字符串时所用的转换状态对象的指针

返回值

下列首个应用者：

  • 若从 s 转换的字符为空字符（并存储于 *pc32 中，若它非空）则为 ​0​ 。
  • 成功从 s 转换的多字节字符的字节数 [1...n] 。
  • 若现已将来自多 char32_t 字符的下个 char32_t 写入 *pc32 ，则为 -3 。此情况下不从输入处理字节。
  • 若接下来 n 个字节组成不完整，但到此仍合法的多字节字符则为 -2 。不写入内容到 *pc32 。
  • 若出现编码错误则为 -1 。不写入内容到 *pc32 ，存储 EILSEQ 于 errno 且 *ps 的值未指定。

示例

#include <iostream>
#include <iomanip>
#include <clocale>
#include <cstring>
#include <cwchar>
#include <cuchar>
#include <cassert>

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");

    std::string str = u8"z\u00df\u6c34\U0001F34C"; // 或 u8"zß水🍌"

    std::cout << "Processing " << str.size() << " bytes: [ " << std::showbase;
    for(unsigned char c: str) std::cout << std::hex << +c << ' ';
    std::cout << "]\n";

    std::mbstate_t state{}; // 零初始化为初始状态
    char32_t c32;
    const char *ptr = str.c_str(), *end = str.c_str() + str.size() + 1;

    while(std::size_t rc = std::mbrtoc32(&c32, ptr, end - ptr, &state))
    {
        std::cout << "Next UTF-32 char: " << std::hex << c32 << " obtained from ";
        assert(rc != (std::size_t)-3); // no surrogates in UTF-32
        if(rc <= ((std::size_t)-1) / 2) {
            std::cout << std::dec << rc << " bytes [ ";
            for(std::size_t n = 0; n < rc; ++n)
                std::cout << std::hex << +(unsigned char)ptr[n] << ' ';
            std::cout << "]\n";
            ptr += rc;
        } else break;
    }
}

输出：

Processing 10 bytes: [ 0x7a 0xc3 0x9f 0xe6 0xb0 0xb4 0xf0 0x9f 0x8d 0x8c ]
Next UTF-32 char: 0x7a obtained from 1 bytes [ 0x7a ]
Next UTF-32 char: 0xdf obtained from 2 bytes [ 0xc3 0x9f ]
Next UTF-32 char: 0x6c34 obtained from 3 bytes [ 0xe6 0xb0 0xb4 ]
Next UTF-32 char: 0x1f34c obtained from 4 bytes [ 0xf0 0x9f 0x8d 0x8c ]

参阅

c32rtomb (C++11) | 转换 32 位宽字符为窄多字节字符串 (函数)
do_in [虚] | 从 externT 转换字符串为 internT ，如在从文件读取时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


std::mbrtoc8

< cpp‎ | string‎ | multibyte
定义于头文件 <cuchar>
std::size_t mbrtoc8( char8_t* pc8,

const char* s,
std::size_t n,

std::mbstate_t * ps );
 (C++20 起)

转换窄多字节字符为 UTF-8 编码。

若 s 不是空指针，则审视始于 s 所指向字符的多字节字符串的至多 n 个字节，以确定完成下个多字节字符所需的字节数（包含任何迁移序列）。若函数确定 s 中的下个多字节字符完整且合法，则将它转换成 UTF-8 并存储首个 UTF-8 编码单元于 *pc8 （若 pc8 非空）。

若 *s 中的多字节字符的 UTF-8 编码由多于一个 UTF-8 编码单元组成，则在首次调用此函数后更新 *ps ，以使得下次调用 mbrtoc8 会写出另外的 UTF-8 编码单元，而不考虑 *s 。

若 s 为空指针，则忽略 n 与 pc8 的值，而调用等价于 std::mbrtoc8( NULL, "", 1, ps) 。

若产生的 UTF-8 编码单元为 u8'\0' ，则转换状态 *ps 代表初始迁移状态。

此函数所用的多字节编码由当前活跃的 C 本地环境指定。

参数

pc8 | - | 指向将写入生成的 UTF-8 编码单元的位置的指针
s | - | 指向用作输入的多字节字符串的指针
n | - | s 中能检验的字节数上的限制
ps | - | 指向转译多字节字符串时使用的转换状态对象的指针

返回值

下列的首个成立者：

  • ​0​ ，若从 s 转换（而若 pc8 非空则存储于 *pc8 ）的字符是空字符。
  • [1...n] ，从 s 成功转换的多字节字符的字节数。
  • -3 ，若现在已将来自由多个编码单元组成的字符的下个 UTF-8 编码单元写入 *pc8 。此情况下不处理来自输入的字节。
  • -2 ，若下 n 个字节组成不完整但到此仍合法的多字节字符。不写入任何内容到 *pc8 。
  • -1 ，若编码错误出现。不写入任何内容到 *pc8 ，存储值 EILSEQ 于 errno ，而 *ps 的值未指定。

示例

本节未完成
原因：暂无示例

参阅

c8rtomb
(C++20)
 转换 UTF-8 字符串为窄多字节编码
(函数)


std::mbrtowc

< cpp‎ | string‎ | multibyte
定义于头文件 <cwchar>
std::size_t mbrtowc( wchar_t* pwc,

const char* s,
std::size_t n,

std::mbstate_t * ps );

转换窄多字节字符为宽字符。

若 s 不是空指针，则从 s 所指向的字节起，审查多字节字符串的至多 n 个字节，以确定完成下个多字节字符（包含任何迁移序列）的字节数。若该函数确定 s 的下个多字节字符完整且合法，则将它转换为对应的宽字符，并存储之于 *pwc （若 pwc 非空）。

若 s 是空指针，则忽略 n 和 pwc 的值，而调用等价于 std::mbrtowc( NULL, "", 1, ps) 。

若产生的宽字符是空字符，则存储于 *ps 的转换状态为初始迁移状态。

参数

pwc | - | 指向要写入结果宽字符位置的指针
s | - | 指向用作输入的多字节字符串的指针
n | - | s 中能被检验的字节数限制
ps | - | 指向转译多字节字符串时的转换状态的指针

返回值

下列首个可应用者：

  • 若转换自 s 的字符为空字符，则为 ​0​ （若 pwc 非空则存储于 *pwc ）
  • 成功地 s 从转换的多字节字符 [1...n] 的字节数
  • 若接下来的 n 字节组成不完整，但该部分合法的宽字符，则为 static_cast< std::size_t >(-2) 。不写入 *pwc 。
  • 若出现编码错误则为 static_cast< std::size_t >(-1) 。不写入 *pwc ，存储值 EILSEQ 于 errno ，并且置 *ps 的值为未指定。

示例

#include <iostream>
#include <clocale>
#include <cstring>
#include <cwchar>

void print_mb(const char* ptr)
{
    std::mbstate_t state = std::mbstate_t(); // 初始状态
    const char* end = ptr + std::strlen(ptr);
    int len;
    wchar_t wc;
    while((len = std::mbrtowc(&wc, ptr, end-ptr, &state)) > 0) {
        std::wcout << "Next " << len << " bytes are the character " << wc << '\n';
        ptr += len;
    }
}

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    // UTF-8 窄多字节编码
    const char* str = u8"z\u00df\u6c34\U0001d10b"; // 或 u8"zß水𝄋"
                      // 或 "\x7a\xc3\x9f\xe6\xb0\xb4\xf0\x9d\x84\x8b";
    print_mb(str);
}

输出：

Next 1 bytes are the character z
Next 2 bytes are the character ß
Next 3 bytes are the character 水
Next 4 bytes are the character 𝄋

参阅

mbtowc | 将下一个多字节字符转换成宽字符 (函数)
wcrtomb | 给定状态，转换宽字符到其多字节表示 (函数)
do_in [虚] | 从 externT 转换字符串为 internT ，如在从文件读取时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


std::mbsinit

< cpp‎ | string‎ | multibyte
定义于头文件 <cwchar>
int mbsinit( const std::mbstate_t * ps);

若 ps 不是空指针，则 mbsinit 函数确定被指向的 std::mbstate_t 对象是否描述初始迁移状态。

注意

尽管零初始化的 std::mbstate_t 始终表示初始转换状态，亦可能有其他 std::mbstate_t 值表示初始转换状态。

参数

ps - 指向要检验的 std::mbstate_t 对象的指针

返回值

若 ps 不是空指针且不表示初始迁移状态则为 ​0​ ，否则为非零值。

示例

#include <clocale>
#include <string>
#include <iostream>
#include <cwchar>

int main()
{
    // 允许 mbrlen() 以 UTF-8 多字节编码工作
    std::setlocale(LC_ALL, "en_US.utf8");
    // UTF-8 窄多字节编码
    std::string str = u8"水"; // 或 u8"\u6c34" 或 "\xe6\xb0\xb4"
    std::mbstate_t mb = std::mbstate_t();
    (void)std::mbrlen(&str[0], 1, &mb);
    if (!std::mbsinit(&mb)) {
        std::cout << "After processing the first 1 byte of " << str
                  << " the conversion state is not initial\n";
    }

    (void)std::mbrlen(&str[1], str.size()-1, &mb);
    if (std::mbsinit(&mb)) {
        std::cout << "After processing the remaining 2 bytes of " << str
                  << ", the conversion state is initial conversion state\n";
    }
}

输出：

After processing the first 1 byte of 水 the conversion state is not initial
After processing the remaining 2 bytes of 水, the conversion state is initial conversion state

参阅

mbstate_t
 迭代多字节字符串所需的转换状态信息
(类)


std::mbsrtowcs

< cpp‎ | string‎ | multibyte
定义于头文件 <cwchar>
std::size_t mbsrtowcs( wchar_t* dst,

const char** src,
std::size_t len,

std::mbstate_t * ps );

转换始于 *ps 所描述的转换状态，来自首元素为 *src 所指向的数组的空终止多字节字符序列，到其宽字符表示。若 dst 非空，则存储转换后的字符于 dst 所指向的 wchar_t 数组的相继元素。不写入多于 len 个宽字符到目标数组。

如同以调用 std::mbrtowc 转换每个多字节字符。若满足下列条件则转换终止：

  • 转换并存储了多字节空字符。设置 *src 为空指针并令 *ps 表示初始迁移状态。
  • 遇到任何非法多字节字符（按照当前 C 本地环境）。设置 *src 指向首个未转换的多字节字符的起始。
  • 将存储的下个宽字符将超出 len 。设置 *src 指向首个未转换的多字节字符的起始。若 dst 为空指针则不检查此条件。

参数

dst | - | 指向将存储结果的宽字符数组的指针
src | - | 指向空终止多字节字符串首元素的指针
len | - | dst 所指向的字符数组中可用的宽字符数
ps | - | 指向转换状态对象的指针

返回值

成功时返回写入字符数组的宽字符数，排除终止的 L'\0' 。若 dst 为空指针，则返回给定无限定长度则本会写入的宽字符数。

转换错误时（若遇到非法多字节字符）返回 static_cast< std::size_t >(-1) ，存储 EILSEQ 于 errno ，并令 *ps 留在未指定状态。

注解

此函数移动 src 指针指向被转换的多字节字符串结尾。若 dst 为空指针则这不发生。

示例

#include <iostream>
#include <vector>
#include <clocale>
#include <cwchar>

void print_as_wide(const char* mbstr)
{
    std::mbstate_t state = std::mbstate_t();
    std::size_t len = 1 + std::mbsrtowcs(NULL, &mbstr, 0, &state);
    std::vector<wchar_t> wstr(len);
    std::mbsrtowcs(&wstr[0], &mbstr, wstr.size(), &state);
    std::wcout << "Wide string: " << &wstr[0] << '\n'
               << "The length, including '\\0': " << wstr.size() << '\n';
}

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    const char* mbstr = u8"z\u00df\u6c34\U0001f34c"; // 或 u8"zß水🍌"
    print_as_wide(mbstr);
}

输出：

Wide string: zß水🍌
The length, including '\0': 5

参阅

mbrtowc | 给定状态，转换下个多字节字符为宽字符 (函数)
wcsrtombs | 给定状态，转换宽字符串为窄多字节字符串 (函数)
do_in [虚] | 从 externT 转换字符串为 internT ，如在从文件读取时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


std::mbstate_t

< cpp‎ | string‎ | multibyte
定义于头文件 <cuchar> | (C++17 起)
定义于头文件 <cwchar> |
struct mbstate_t; |

类型 mbstate_t 是平凡非数组类型，能表示任何能出现于实现定义的受支持多字节编码规则集合的转换状态。 mbstate_t 的零初始化值表示初始转换状态，尽管亦可能存在 mbstate_t 的其他值表示初始转换状态。

mbstate_t 的可行实现是一个结构体类型，保有表示不完整多字节字符的数组、指示数组中已处理字节数和当前迁移状态的表示。

由于可能的数据竞争，不应从多个线程以空指针为 std::mbstate_t* 参数调用下列函数而不同步： std::mbrlen 、 std::mbrtowc 、 std::mbsrtowcs 、 std::mbtowc 、 std::wcrtomb 、 std::wcsrtombs 、 std::wctomb 。

参阅

mbsinit
 检查 mbstate_t 对象是否表示初始迁移状态
(函数)


std::mbstowcs

< cpp‎ | string‎ | multibyte
定义于头文件 <cstdlib>
std::size_t mbstowcs( wchar_t* dst, const char* src, std::size_t len);

转换来自首元素为 src 所指向的数组的多字节字符串到其宽字符表示。被转换的字符存储于 dst 所指向数组的相继元素。写入目标数组的宽字符数不多于 len 。

如同以调用 std::mbtowc 转换每个字符，除了 mbtowc 转换状态不受影响。若满足下列条件则转换停止：

* 转换并存储了多字节空字符。
* 遇到（当前 C 本地环境中的）非法多字节字符。
* 本要存储的下个宽字符会超出 len 。

注意

大多数实现中， 此函数在处理过字符串时更新 std::mbstate_t 类型的全局静态对象，而且不能为二个线程所同时调用，这种情况应该用 std::mbsrtowcs 。

POSIX 指定一个常见扩展：若 dst 是空指针，则此函数返回假设转换则写入 dst 的宽字符数。类似行为对于 std::mbsrtowcs 是标准。

参数

dst | - | 指向将存储宽字符串的宽字符数组的指针
src | - | 指向要转换的空终止多字节字符串的首元素的指针
len | - | dst 所指向的数组中的可用宽字符数

返回值

成功时，返回目标数组的宽字符数，不含终止符 L'\0' 。

转换错误时（若遇到非法多字节字符），返回 static_cast< std::size_t >(-1) 。

示例

#include <iostream>
#include <clocale>
#include <cstdlib>
int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout.imbue(std::locale("en_US.utf8"));
    const char* mbstr = u8"z\u00df\u6c34\U0001f34c"; // 或 u8"zß水🍌"
                        // 或 "\x7a\xc3\x9f\xe6\xb0\xb4\xf0\x9f\x8d\x8c";
    wchar_t wstr[5];
    std::mbstowcs(wstr, mbstr, 5);
    std::wcout << "wide string: " << wstr << '\n';
}

输出：

wide string: zß水🍌

参阅

mbsrtowcs | 给定状态，转换窄多字节字符串到宽字符串 (函数)
wcstombs | 转换宽字符串为窄多字节字符串 (函数)
do_in [虚] | 从 externT 转换字符串为 internT ，如在从文件读取时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


std::mbtowc

< cpp‎ | string‎ | multibyte
定义于头文件 <cstdlib>
int mbtowc( wchar_t* pwc, const char* s, std::size_t n );

将 s 指向其首字节的多字节字符转换成宽字符，若 pwc 非空则写入 *pwc 。

若 s 为空指针，则重置全局转换状态并确定是否使用迁移序列。

参数

s | - | 指向多字节字符的指针
n | - | s 中能被检验的字节数的限制
pwc | - | 指向输出用宽字符的指针

返回值

若 s 不是空指针，则返回多字节字符所含的字节数，或若 s 所指的首字节不组成合法多字节字符则返回 -1 ，或若 s 指向空字符 '\0' 则返回 ​0​ 。

若 s 是空指针，则重置内部转换状态为初始迁移状态，并若当前多字节编码非状态依赖（不使用迁移序列）则返回 ​0​ ，或若当前多字节编码为状态依赖（使用迁移序列）则返回非零值。

注意

每次对 mbtowc 的调用更新内部全局转换状态（ std::mbstate_t 类型的静态对象，只为此函数所知）。若多字节编码使用迁移状态，则必须留意以避免回撤或多次扫描。任何情况下，多线程不应调用 mbtowc 而不同步：可用 std::mbrtowc 代替。

示例

#include <iostream>
#include <clocale>
#include <cstring>
#include <cstdlib>

int print_mb(const char* ptr)
{
    std::mbtowc(NULL, 0, 0); // 重置转换状态
    const char* end = ptr + std::strlen(ptr);
    int ret;
    for (wchar_t wc; (ret = std::mbtowc(&wc, ptr, end-ptr)) > 0; ptr+=ret) {
        std::wcout << wc;
    }
    std::wcout << '\n';
    return ret;
}

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    // UTF-8 窄多字节编码
    const char* str = u8"z\u00df\u6c34\U0001d10b"; // 或 u8"zß水🍌"
                      // 或 "\x7a\xc3\x9f\xe6\xb0\xb4\xf0\x9d\x84\x8b";
    print_mb(str);
}

输出：

zß水🍌

参阅

mbrtowc | 给定状态，转换下个多字节字符为宽字符 (函数)
mblen | 返回下一个多字节字符中的字节数 (函数)
do_in [虚] | 从 externT 转换字符串为 internT ，如在从文件读取时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


std::wcrtomb

< cpp‎ | string‎ | multibyte
定义于头文件 <cwchar>
std::size_t wcrtomb( char* s, wchar_t wc, std::mbstate_t * ps );

转换宽字符为其窄多字节表示。

若 s 不是空指针，则函数检测存储 wc 的多字节字符表示所需的字节数（包含任何迁移序列，并考虑当前多字节转换状态 *ps ，并存储多字节字符表示于首元素为 s 所指向的字符数组，按需更新 *ps 。此函数至多能写入 MB_CUR_MAX 字节。

若 s 为空指针，则调用等价于对某内部缓冲区 buf 的 wcrtomb(buf, L'\0', ps) 。

若 wc 是空宽字符 L'\0' ，则存储空字节，前接任何恢复到初始迁移状态所需的迁移序列，并更新转换状态参数 *ps 以表示初始迁移状态。

参数

s | - | 指向窄字符数组的指针，其中将存储多字节字符串
wc | - | 要转换的宽字符
ps | - | 指向转译多字节字符串时所用的转换状态对象的指针

返回值

成功时，返回写入首元素为 s 所指向的字符数组的字节数（包含任何迁移序列）。

失败时（若 wc 不是合法宽字符），返回 static_cast< std::size_t >(-1) ，存储 EILSEQ 于 errno ，并使 *ps 留在未指定状态。

示例

#include <iostream>
#include <clocale>
#include <string>
#include <cwchar>

void print_wide(const std::wstring& wstr)
{
    std::mbstate_t state {};
    for(wchar_t wc : wstr) {
        std::string mb(MB_CUR_MAX, '\0');
        std::size_t ret = std::wcrtomb(&mb[0], wc, &state);
        std::cout << "multibyte char " << mb << " is " << ret << " bytes\n";
    }
}

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    std::wstring wstr = L"z\u00df\u6c34\U0001f34c"; // 或 L"zß水🍌"
    print_wide(wstr);
}

输出：

multibyte char z is 1 bytes
multibyte char ß is 2 bytes
multibyte char 水 is 3 bytes
multibyte char 🍌 is 4 bytes

参阅

wctomb | 转换宽字符为其多字节表示 (函数)
mbrtowc | 给定状态，转换下个多字节字符为宽字符 (函数)
do_out [虚] | 从 internT 转换字符串为 externT 转换字符串，如在写入文件时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


std::wcsrtombs

< cpp‎ | string‎ | multibyte
定义于头文件 <cwchar>
std::size_t wcsrtombs( char* dst,

const wchar_t** src,
std::size_t len,

std::mbstate_t * ps );

转换来自元素为 *src 所指向的宽字符序列为其窄多字节表示，始于 *ps 所描述的转换状态。若 dst 非空，则存储转换后的字符于 dst 所指向的字符数组的相接元素。不写入多于 len 个字节到目标数组。

如同以调用 std::wcrtomb 转换每个字符。若遇到下列条件则停止转换：

  • 转换并存储了空字符 L'\0' 。此情况下存储的字节是反迁移序列（若需要）后随 '\0' ，设置 *src 为空指针并令 *ps 表示初始迁移状态。
  • 找到当前 C 本地环境中不对应合法字符的 wchar_t 。设置 *src 指向首个未转换的宽字符。
  • 下个多字节字符将超出 len 。设置 *src 指向首个未转换的宽字符。若 dst 为空指针则不检查此条件。

参数

dst | - | 指向窄字符数组的指针，其中将存储多字节字符
src | - | 指向指向空终止宽字符串首元素的指针的指针
len | - | dst 所指向的数组中可用的字节数
ps | - | 指向转换状态对象的指针

返回值

成功时，返回写入首元素为 dst 所指向的字符数组的字节数（包含任何迁移序列，但不包含终止 '\0' ）。若 dst 为空指针，则返回本会写入的字节数。

转换错误时（若遇到非法宽字符），返回 static_cast< std::size_t >(-1) ，存储 EILSEQ 于 errno ，并令 *ps 留在未指定状态。

示例

#include <iostream>
#include <vector>
#include <clocale>
#include <string>
#include <cwchar>

void print_wide(const wchar_t* wstr)
{
    std::mbstate_t state = std::mbstate_t();
    std::size_t len = 1 + std::wcsrtombs(nullptr, &wstr, 0, &state);
    std::vector<char> mbstr(len);
    std::wcsrtombs(&mbstr[0], &wstr, mbstr.size(), &state);
    std::cout << "multibyte string: " << &mbstr[0] << '\n'
              << "Length, including '\\0': " << mbstr.size() << '\n';
}

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    // UTF-8 窄多字节编码
    const wchar_t* wstr = L"z\u00df\u6c34\U0001d10b"; // 或 L"zß水𝄋"
    print_wide(wstr);
}

输出：

multibyte string: zß水𝄋
Length, including '\0': 11

参阅

wcrtomb | 给定状态，转换宽字符到其多字节表示 (函数)
mbsrtowcs | 给定状态，转换窄多字节字符串到宽字符串 (函数)
do_out [虚] | 从 internT 转换字符串为 externT 转换字符串，如在写入文件时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


std::wcstombs

< cpp‎ | string‎ | multibyte
定义于头文件 <cstdlib>
std::size_t wcstombs( char* dst, const wchar_t* src, std::size_t len);

转换来自首元素为 src 所指向的数组到其始于初始迁移状态的多字节表示。转换出的字符被存储于 dst 所指向的数组的相继元素。写入目标数组的字节数不多于 len 。

如同以调用 std::wctomb 每个字符，除了 wctomb 的转换状态不受影响。若满足下列条件则转换停止：

  • 转换并存储空字符。
  • 找到当前 C 本地环境中不对应合法字符的 wchar_t 。
  • 下个要存储的多字节字符会超出 len 。

注意

大多数实现中，此函数在处理过字符串时更新 std::mbstate_t 类型的全局静态对象，而且不能为二个线程同时调用，这种情况下应使用 std::wcsrtombs 。

POSIX 指定一个常见扩展：若 dst 是空指针，则此函数返回假设转换则会写入 dst 的字节数。类似行为对于 std::wcsrtombs 是标准。

参数

dst | - | 指向窄字符数组的指针，其中将存储多字节字符
src | - | 指向要转换的空终止宽字符串首字符的指针
len | - | dst 所指向数组中的可用字节数

返回值

成功时，返回写入首元素为 dst 所指向的字符数组的字节数（包含任何迁移序列，但不含终止的 '\0' ）。

转换错误时（若遇到非法宽字符），返回 static_cast< std::size_t >(-1) 。

示例

#include <iostream>
#include <clocale>
#include <cstdlib>

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    // UTF-8 窄多字节编码
    const wchar_t* wstr = L"z\u00df\u6c34\U0001d10b"; // 或 L"zß水𝄋"
    char mbstr[11];
    std::wcstombs(mbstr, wstr, 11);
    std::cout << "multibyte string: " << mbstr << '\n';
}

输出：

multibyte string: zß水𝄋

参阅

wcsrtombs | 给定状态，转换宽字符串为窄多字节字符串 (函数)
mbstowcs | 转换窄多字节字符串为宽字符串 (函数)
do_out [虚] | 从 internT 转换字符串为 externT 转换字符串，如在写入文件时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


std::wctob

< cpp‎ | string‎ | multibyte
定义于头文件 <cwchar>
int wctob( std::wint_t c );

窄化宽字符 c ，若其多字节字符等价版本在初始迁移状态为单字节。

这典型地对来自 ASCII 字符集的字符可行，因为大多数多字节编码（例如 UTF-8 ）用单字节编码那些字符。

参数

c - 要窄化的宽字符

返回值

若 c 在初始迁移状态不表示长度为 1 的多字节字符则为 EOF 。

否则，为作为 unsigned char 的 c 的单字节表示，转换为 int 。

示例

#include <clocale>
#include <cwchar>
#include <iostream>

void try_narrowing(wchar_t c)
{
    int cn = std::wctob(c);
    if(cn != EOF)
        std::cout << '\'' << c << "' narrowed to " << +cn << '\n';
    else
        std::cout << '\'' << c << "' could not be narrowed\n";
}

int main()
{
    std::setlocale(LC_ALL, "th_TH.utf8");
    std::cout << std::hex << std::showbase << "In Thai UTF-8 locale:\n";
    try_narrowing(L'a');
    try_narrowing(L'๛');

    std::setlocale(LC_ALL, "th_TH.tis620");
    std::cout << "In Thai TIS-620 locale:\n";
    try_narrowing(L'a');
    try_narrowing(L'๛');
}

输出：

In Thai UTF-8 locale:
'0x61' narrowed to 0x61
'0xe5b' could not be narrowed
In Thai TIS-620 locale:
'0x61' narrowed to 0x61
'0xe5b' narrowed to 0xfb

参阅

btowc | 若可能，则加宽单字节窄字符为宽字符 (函数)
narrow | 窄化字符 (std::basic_ios<CharT,Traits> 的公开成员函数)
narrow | 调用 do_narrow (std::ctype<CharT> 的公开成员函数)


std::wctomb

< cpp‎ | string‎ | multibyte
定义于头文件 <cstdlib>
int wctomb( char *s, wchar_t wc );

转换宽字符 wc 为多字节编码并存储之（包含任何迁移序列）于首元素为 s 所指向的字符数组。不存储多于 MB_CUR_MAX 个字符。

若 wc 是空字符，则将空字节写入 s ，前附任何需要恢复到初始迁移状态的迁移序列。

若 s 是空指针，则重置全局转换状态并确定是否使用迁移序列。

参数

s | - | 指向输出的字符数组的指针
wc | - | 要转换的宽字符

返回值

若 s 不是空指针，则返回 wc 的多字节表示中的字节数，或若 wc 不是合法字符则为 -1 。

若 s 是空指针，则重置其内部转换状态为表示初始迁移状态，且若当前多字节编码不依赖状态（不使用迁移序列）则返回 ​0​ ，或若当前多字节编码以来状态（使用迁移序列）则返回非零值。

注意

每次到 wctomb 的调用更新全局转换状态（ std::mbstate_t 类型静态对象，仅为此函数所知）。若多字节编码使用迁移状态，则此函数不可重入。任何情况下，多个线程不应调用 wctomb 而不同步：可用 std::wcrtomb 替代。

示例

#include <iostream>
#include <clocale>
#include <string>
#include <cstdlib>

void print_wide(const std::wstring& wstr)
{
    bool shifts = std::wctomb(nullptr, 0); // 重置转换状态
    std::cout << "shift sequences " << (shifts ? "are" : "not" ) << " used\n";
    for (wchar_t wc : wstr) {
        std::string mb(MB_CUR_MAX, '\0');
        int ret = std::wctomb(&mb[0], wc);
        std::cout << "multibyte char " << mb << " is " << ret << " bytes\n";
    }
}

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    // UTF-8 窄多字节编码
    std::wstring wstr = L"z\u00df\u6c34\U0001d10b"; // 或 L"zß水𝄋"
    print_wide(wstr);
}

输出：

shift sequences not used
multibyte char z is 1 bytes
multibyte char ß is 2 bytes
multibyte char 水 is 3 bytes
multibyte char 𝄋 is 4 bytes

参阅

mbtowc | 将下一个多字节字符转换成宽字符 (函数)
wcrtomb | 给定状态，转换宽字符到其多字节表示 (函数)
do_out [虚] | 从 internT 转换字符串为 externT 转换字符串，如在写入文件时 (std::codecvt<InternT,ExternT,State> 的虚受保护成员函数)


空终止宽字符串

< cpp‎ | string

空终止宽字符串是以空字符结束的合法宽字符序列。

函数

字符分类
定义于头文件 <cwctype>
iswalnum
 检查宽字符是否为字母数字
(函数)
iswalpha
 检查宽字符是否为字母
(函数)
iswlower
 检查宽字符是否为小写
(函数)
iswupper
 检查宽字符是否为大写
(函数)
iswdigit
 检查宽字符是否为数字
(函数)
iswxdigit
 检查宽字符是否为十六进制字符
(函数)
iswcntrl
 检查宽字符是否为控制字符
(函数)
iswgraph
 检查宽字符是否为图形字符
(函数)
iswspace
 检查宽字符是否为空白间隔字符
(函数)
iswblank
(C++11)
 检查宽字符是否为空白字符
(函数)
iswprint
 检查宽字符是否为打印字符
(函数)
iswpunct
 检查宽字符是否为标点字符
(函数)
iswctype
 按照指定的 LC_TYPE 类别分类宽字符
(函数)
wctype
 在当前 C 本地环境中查找字符分类类别
(函数)
字符操作
定义于头文件 <cwctype>
towlower
 转换宽字符为小写
(函数)
towupper
 转换宽字符为大写
(函数)
towctrans
 按照指定的 LC_TYPE 映射类别进行字符映射
(函数)
wctrans
 在当前 C 本地环境中查找字符映射类别
(函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
转换到数值格式
定义于头文件 <cwchar>
wcstolwcstoll
 转换宽字符串为整数值
(函数)
wcstoulwcstoull
 转换宽字符串为无符号整数值
(函数)
wcstofwcstodwcstold
 转换宽字符串为浮点值
(函数)
定义于头文件 <cinttypes>
wcstoimaxwcstoumax
(C++11)(C++11)
 转换宽字符串为 std::intmax_t 或 std::uintmax_t
(函数)
字符串操作
定义于头文件 <cwchar>
wcscpy
 复制一个宽字符串到另一个
(函数)
wcsncpy
 复制来自一个宽字符串的一定量宽字符到另一个
(函数)
wcscat
 后附一个宽字符串的副本到另一个
(函数)
wcsncat
 后附来自一个宽字符串的一定量宽字符到另一个
(函数)
wcsxfrm
 变换宽字符串，使得 wcscmp 会产生与 wsccoll 相同的结果
(函数)
字符串检验
定义于头文件 <cwchar>
wcslen
 返回宽字符串长度
(函数)
wcscmp
 比较两个宽字符串
(函数)
wcsncmp
 比较来自两个宽字符串的一定量宽字符
(函数)
wcscoll
 按照当前本地环境比较两个宽字符串
(函数)
wcschr
 寻找宽字符串中宽字符的首次出现
(函数)
wcsrchr
 在宽字符串中寻找宽字符的最后一次出现
(函数)
wcsspn
 返回仅由另一宽字符串中找到的宽字符组成的最大起始段的长度
(函数)
wcscspn
 返回仅由另一宽字符串中找不到的宽字符组成的最大起始段的长度
(函数)
wcspbrk
 在一个宽字符串中，寻找另一宽字符串中任何字符的首个位置
(函数)
wcsstr
 在另一宽字符串中寻找宽字符串的首次出现
(函数)
wcstok
 寻找宽字符串中的下一个记号
(函数)
宽字符数组操作
定义于头文件 <cwchar>
wmemcpy
 在两个不重叠数组间复制一定量宽字符
(函数)
wmemmove
 在两个可能重叠的数组间复制一定量宽字符
(函数)
wmemcmp
 比较来自两个数组的一定量宽字符
(函数)
wmemchr
 寻找宽字符数组中宽字符的首次出现
(函数)
wmemset
 复制给定宽字符到宽字符数组的每个位置
(函数)

类型

定义于头文件 <cwctype>
wctrans_t | 保有本地环境限定的字符映射的标量类型 (typedef)
wctype_t | 保有本地环境特定的字符分类的标量类型 (typedef)
定义于头文件 <cwctype>
定义于头文件 <cwchar>
wint_t | 能保有任何合法宽字符和至少多一个值的整数类型 (typedef)

宏

定义于头文件 <cwchar>
WEOF | 用于指示错误的 wint_t 类型非字符值 (宏常量)
WCHAR_MIN | wchar_t 的最小合法值 (宏常量)
WCHAR_MAX | wchar_t 的最大合法值 (宏常量)

参阅


std::iswalnum

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
int iswalnum( std::wint_t ch );

检查给定宽字符是否字母数字，即数字（ 0123456789 ）、大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）、小写字母（ abcdefghijklmnopqrstuvwxyz ）或任何限定于当前本地环境的字母数字字符。

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch - 宽字符

返回值

若宽字符是字母数字字符则为非零值，否则为零。

注意

ISO 30112 指定哪些 Unicode 字符包含于 POSIX 字母数字类别。

示例

#include <iostream>
#include <cwctype>
#include <clocale>

int main()
{
    wchar_t c = L'\u13ad'; // 切罗基字母 HA ('Ꭽ')

    std::cout << std::hex << std::showbase << std::boolalpha;
    std::cout << "in the default locale, iswalnum(" << (std::wint_t)c << ") = "
              << (bool)std::iswalnum(c) << '\n';
    std::setlocale(LC_ALL, "en_US.utf8");
    std::cout << "in Unicode locale, iswalnum(" << (std::wint_t)c << ") = "
              << (bool)std::iswalnum(c) << '\n';
}

输出：

in the default locale, iswalnum(0x13ad) = false
in Unicode locale, iswalnum(0x13ad) = true

参阅

isalnum(std::locale) | 检查字符是否被本地环境分类为字母或数字 (函数模板)
isalnum | 检查字符是否为字母或数字 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::iswalpha

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
int iswalpha( std::wint_t ch );

检查给定字符是否字母字符，即大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）、小写字母（ abcdefghijklmnopqrstuvwxyz ）或任何限定于当前本地环境的字母字符。

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch - 宽字符

返回值

若宽字符为字母字符则为非零值，否则为 0 。

注意

ISO 30112 指定哪些 Unicode 字符包含于 POSIX 字母类别。

示例

#include <iostream>
#include <cwctype>
#include <clocale>

int main()
{
    wchar_t c = L'\u0b83'; // 泰米尔符号 Visarga ('ஃ')

    std::cout << std::hex << std::showbase << std::boolalpha;
    std::cout << "in the default locale, iswalpha(" << (std::wint_t)c << ") = "
              << (bool)std::iswalpha(c) << '\n';
    std::setlocale(LC_ALL, "en_US.utf8");
    std::cout << "in Unicode locale, iswalpha(" << (std::wint_t)c << ") = "
              << (bool)std::iswalpha(c) << '\n';
}

输出：

in the default locale, iswalpha(0xb83) = false
in Unicode locale, iswalpha(0xb83) = true

参阅

isalpha(std::locale) | 检查字符是否被本地环境分类为字母 (函数模板)
isalpha | 检查字符是否为字母 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::iswblank

< cpp‎ | string‎ | wide
定义于头文件 <cwctype> |
int iswblank( std::wint_t ch ); | (C++11 起)

检查给定的宽字符是否被当前 C 本地环境分类为空格符（即用于在句中分隔单词的空白符）。默认 C 本地环境中，只有空格（ 0x20 ）和水平制表符（ 0x09 ）是空格符。

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch - 宽字符

返回值

若宽字符是空格符则为非零值，否则为零。

注意

ISO 30112 定义 POSIX 空格字符为 Unicode 字符 U+0009 、 U+0020 、 U+1680 、 U+180E 、 U+2000..U+2006 、 U+2008 、 U+200A 、 U+205F 及 U+3000 。

示例

#include <iostream>
#include <cwctype>
#include <clocale>

int main()
{
    wchar_t c = L'\u3000'; // 表意空格 ('　')

    std::cout << std::hex << std::showbase << std::boolalpha;
    std::cout << "in the default locale, iswblank(" << (std::wint_t)c << ") = "
              << (bool)std::iswblank(c) << '\n';
    std::setlocale(LC_ALL, "en_US.utf8");
    std::cout << "in Unicode locale, iswblank(" << (std::wint_t)c << ") = "
              << (bool)std::iswblank(c) << '\n';
}

输出：

in the default locale, iswblank(0x3000) = false
in Unicode locale, iswblank(0x3000) = true

参阅

isblank(std::locale) (C++11) | 检查字符是否被本地环境分类为空格字符 (函数模板)
isblank (C++11) | 检查字符是否为空白字符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::iswcntrl

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
int iswcntrl( std::wint_t ch );

检查给定的宽字符是否为控制字符，即控制码 0x00-0x1F 和 0x7F 及任何限定于当前本地环境的控制字符。

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch - 宽字符

返回值

若宽字符为控制字符则为非零值，否则为零。

注意

ISO 30112 定义 POSIX 控制字符为 Unicode 字符 U+0000..U+001F 、 U+007F..U+009F 、 U+2028 及 U+2029 （ Unicode 类 Cc 、 Zl 及 Zp ）。

示例

#include <iostream>
#include <cwctype>
#include <clocale>

int main()
{
    wchar_t c = L'\u2028'; // Unicode 字符“行分隔符”

    std::cout << std::hex << std::showbase << std::boolalpha;
    std::cout << "in the default locale, iswcntrl(" << (std::wint_t)c << ") = "
              << (bool)std::iswcntrl(c) << '\n';
    std::setlocale(LC_ALL, "en_US.utf8");
    std::cout << "in Unicode locale, iswcntrl(" << (std::wint_t)c << ") = "
              << (bool)std::iswcntrl(c) << '\n';
}

输出：

in the default locale, iswcntrl(0x2028) = false
in Unicode locale, iswcntrl(0x2028) = true

参阅

iscntrl(std::locale) | 检查字符是否被本地环境分类为控制字符 (函数模板)
iscntrl | 检查字符是否为控制字符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::iswctype

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
int iswctype( std::wint_t wc, std::wctype_t desc );

用 desc 所标识的当前 C 本地环境的 LC_TYPE 类别分类宽字符 wc 。

若 wc 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

wc | - | 要分类的宽字符
desc | - | 从调用 std::wctype 获得的 LC_CTYPE 类别

返回值

若字符 ch 拥有当前 C 本地环境的 LC_CTYPE 平面 desc 所标识的属性则为非零值，否则为零。

示例

#include <clocale>
#include <cwctype>
#include <iostream>
bool classify(wchar_t wc, const std::string& cat)
{
    return std::iswctype(wc, std::wctype(cat.c_str()));
}
int main()
{
    std::setlocale(LC_ALL, "ja_JP.UTF-8");
    std::cout << "The character \u6c34 is...\n";
    for(std::string s : {"digit", "alpha", "space", "cntrl", "jkanji"})
        std::cout << s << "? " << std::boolalpha << classify(L'\u6c34', s) << '\n';
}

输出：

The character 水 is...
digit? false
alpha? true
space? false
cntrl? false
jkanji? true

参阅

wctype
 在当前 C 本地环境中查找字符分类类别
(函数)


std::iswdigit

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
int iswdigit( wint_t ch );

检查给定的宽字符（若窄化）是否对应十个十进制数字字符 0123456789 之一。

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch - 宽字符

返回值

若宽字符为数字字符则为非零值，否则为零。

注意

std::iswdigit 和 std::iswxdigit 是仅有的不受当前安装的 C 本地环境影响的标准宽字符分类函数。

示例

一些本地环境提供检测非 ASCII 数字的额外字符类

#include <iostream>
#include <cwctype>
#include <clocale>
void test(wchar_t a3, wchar_t u3, wchar_t j3)
{
    std::wcout << std::boolalpha
               << "          '" << a3 << "'   '" << u3 << "'  '" << j3  << "'\n"
               << "iswdigit "
               << (bool)std::iswdigit(a3) << "  "
               << (bool)std::iswdigit(u3) << " "
               << (bool)std::iswdigit(j3) << '\n'
               << "jdigit:  "
               << (bool)std::iswctype(a3, std::wctype("jdigit")) << ' '
               << (bool)std::iswctype(u3, std::wctype("jdigit")) << ' '
               << (bool)std::iswctype(j3, std::wctype("jdigit")) << '\n';
}
int main()
{
    wchar_t a3 = L'3';  // ASCII 数字 3
    wchar_t u3 = L'三'; // CJK 数字 3
    wchar_t j3 = L'３'; // 全角数字 3

    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout << "In american locale:\n";
    test(a3, u3, j3);

    std::wcout << "\nIn japanese locale:\n";
    std::setlocale(LC_ALL, "ja_JP.utf8");
    test(a3, u3, j3);
}

输出：

In american locale:
          '3'   '三'  '３'
iswdigit true  false false
jdigit:  false false false

In japanese locale:
          '3'   '三'  '３'
iswdigit true  false false
jdigit:  false false true

参阅

isdigit(std::locale) | 检查字符是否被本地环境分类为数字 (函数模板)
isdigit | 检查字符是否为数字 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::iswgraph

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
int iswgraph( std::wint_t ch );

检查给定的宽字符是否拥有图形表示，即是数字（ 0123456789 ）、大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）、小写字母（ abcdefghijklmnopqrstuvwxyz ）、标点字符（ !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ）之一或任何限定于当前 C 本地环境的图形字符。

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch - 宽字符

返回值

若宽字符拥有图形表示字符则为非零值，否则为零。

注意

ISO 30112 指定哪些 Unicode 字符包含于 POSIX 图像类别。

示例

#include <iostream>
#include <cwctype>
#include <clocale>

int main()
{
    wchar_t c = L'\u2602'; // Unicode 字符伞 ('☂')

    std::cout << std::hex << std::showbase << std::boolalpha;
    std::cout << "in the default locale, iswgraph(" << (std::wint_t)c << ") = "
              << (bool)std::iswgraph(c) << '\n';
    std::setlocale(LC_ALL, "en_US.utf8");
    std::cout << "in Unicode locale, iswgraph(" << (std::wint_t)c << ") = "
              << (bool)std::iswgraph(c) << '\n';
}

输出：

in the default locale, iswgraph(0x2602) = false
in Unicode locale, iswgraph(0x2602) = true

参阅

isgraph(std::locale) | 检查字符是否被本地环境分类为图形字符 (函数模板)
isgraph | 检查字符是否为图形字符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::iswlower

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
int iswlower( std::wint_t ch );

检查给定宽字符是否小写字母，即 abcdefghijklmnopqrstuvwxyz 之一或任何限定于当前本地环境的小写字母。

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch - 宽字符

返回值

若宽字符为小写字母则为非零值，否则为零。

注意

ISO 30112 指定哪些 Unicode 字符包含于 POSIX 小写类别。

示例

#include <iostream>
#include <cwctype>
#include <clocale>

int main()
{
    wchar_t c = L'\u0444'; // 西里尔小写字母 ef ('ф')

    std::cout << std::hex << std::showbase << std::boolalpha;
    std::cout << "in the default locale, iswlower(" << (std::wint_t)c << ") = "
              << (bool)std::iswlower(c) << '\n';
    std::setlocale(LC_ALL, "en_US.utf8");
    std::cout << "in Unicode locale, iswlower(" << (std::wint_t)c << ") = "
              << (bool)std::iswlower(c) << '\n';
}

输出：

in the default locale, iswlower(0x444) = false
in Unicode locale, iswlower(0x444) = true

参阅

islower(std::locale) | 检查字符是否被本地环境分类为小写 (函数模板)
islower | 检查字符是否为小写 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::iswprint

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
int iswprint( std::wint_t ch );

检查是否能打印给定的宽字符，即宽字符是否为数字（ 0123456789 ）、大写字母（ ABCDEFGHIJKLMNOPQRSTUVWXYZ ）、小写字母（ abcdefghijklmnopqrstuvwxyz ）、标点字符（ !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ）、空格或限定于当前 C 本地环境的任何可打印字符之一。

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch - 宽字符

返回值

若能打印宽字符则为非零值，否则为零。

注意

ISO 30112 指定哪些 Unicode 字符包含于 POSIX 打印类别。

示例

#include <iostream>
#include <cwctype>
#include <clocale>

int main()
{
    wchar_t c = L'\u2002'; // en-space
    std::setlocale(LC_ALL, "en_US.utf8");
    std::cout << std::boolalpha << std::hex << std::showbase
              << "in Unicode locale,\n"
              << "iswprint('" << c << "') = "
              << (bool)std::iswprint(c) << '\n';

    c = L'\u0082'; // break permitted
    std::cout << "iswprint('" << c << "') = "
              << (bool)std::iswprint(c) << '\n';
}

输出：

in Unicode locale,
iswprint('0x2002') = true
iswprint('0x82') = false

参阅

isprint(std::locale) | 检查字符是否被本地环境分类为可打印字符 (函数模板)
isprint | 检查字符是否为打印字符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::iswpunct

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
int iswpunct( std::wint_t ch );

检查给定的宽字符是否为标点，即 !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ 之一或任何限定于当前 C 本地环境的字符。

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch - 宽字符

返回值

若宽字符为标点字符则为非零值，否则为零。

注意

ISO 30112 指定哪些 Unicode 字符包含于 POSIX 标点类别。

示例

#include <iostream>
#include <cwctype>
#include <clocale>

int main()
{
    wchar_t c = L'\u2051'; // 双星号 ('⁑')

    std::cout << std::hex << std::showbase << std::boolalpha;
    std::cout << "in the default locale, iswpunct(" << (std::wint_t)c << ") = "
              << (bool)std::iswpunct(c) << '\n';
    std::setlocale(LC_ALL, "en_US.utf8");
    std::cout << "in Unicode locale, iswpunct(" << (std::wint_t)c << ") = "
              << (bool)std::iswpunct(c) << '\n';
}

输出：

in the default locale, iswpunct(0x2051) = false
in Unicode locale, iswpunct(0x2051) = true

参数

ispunct(std::locale) | 检查字符是否被本地环境分类为标点 (函数模板)
ispunct | 检查字符是否为标点符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::iswspace

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
int iswspace( wint_t ch );

检查给定宽字符是否为当前安装的 C 本地环境分类为宽空白字符。在默认本地环境中，下列字符是空白符：

  • 空格（ 0x20 、 ' ' ）
  • 换页符（ 0x0c 、 '\f' ）
  • 换行符（ 0x0a 、 '\n' ）
  • 回车（ 0x0d 、 '\r' ）
  • 水平制表符（ 0x09 、 '\t' ）
  • 垂直制表符（ 0x0b 、 '\v' ）

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch - 宽字符

返回值

若宽字符为空白符则为非零值，否则为零。

注意

ISO 30112 定义 POSIX 空白符为 Unicode 字符 U+0009..U+000D 、 U+0020 、 U+1680 、 U+180E 、 U+2000..U+2006 、 U+2008..U+200A 、 U+2028 、 U+2029 、 U+205F 及 U+3000 。

示例

演示以不同本地环境使用 iswspace()

#include <iostream>
#include <clocale>
#include <cwctype>
void try_with(wchar_t c, const char* loc)
{
    std::setlocale(LC_ALL, loc);
    std::wcout << "isspace('" << c << "') in " << loc << " locale returned "
               << std::boolalpha << (bool)std::iswspace(c) << '\n';
}
int main()
{
    wchar_t EM_SPACE = L'\u2003'; // Unicode 字符 'EM SPACE'
    try_with(EM_SPACE, "C");
    try_with(EM_SPACE, "en_US.UTF8");
}

输出：

isspace(' ') in C locale returned false
isspace(' ') in en_US.UTF8 locale returned true

参阅

isspace(std::locale) | 检查字符是否被本地环境分类为空白 (函数模板)
isspace | 检查字符是否为空白间隔字符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::iswupper

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
int iswupper( std::wint_t ch );

检查给定的宽字符是否大写字符，即 ABCDEFGHIJKLMNOPQRSTUVWXYZ 之一或任何限定于当前本地环境的大写字符。

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch - 宽字符

返回值

若宽字符为大写字符则为非零值，否则为零。

注意

ISO 30112 指定哪些 Unicode 字符包含于 POSIX 大写类别。

示例

#include <iostream>
#include <cwctype>
#include <clocale>

int main()
{
    wchar_t c = L'\u053d'; // 亚美尼亚文大写字母 xeh ('Խ')

    std::cout << std::hex << std::showbase << std::boolalpha;
    std::cout << "in the default locale, iswupper(" << (std::wint_t)c << ") = "
              << (bool)std::iswupper(c) << '\n';
    std::setlocale(LC_ALL, "en_US.utf8");
    std::cout << "in Unicode locale, iswupper(" << (std::wint_t)c << ") = "
              << (bool)std::iswupper(c) << '\n';
}

输出：

in the default locale, iswupper(0x53d) = false
in Unicode locale, iswupper(0x53d) = true

参阅

isupper(std::locale) | 检查字符是否被本地环境分类为大写 (函数模板)
isupper | 检查字符是否为大写字符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::iswxdigit

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
int iswxdigit( wint_t ch );

检查给定的宽字符（若窄化）是否对应十六进制数字字符，即 0123456789abcdefABCDEF 之一。

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch - 宽字符

返回值

若宽字符为十六进制数字字符则为非零值，否则为零。

注意

std::iswdigit 和 std::iswxdigit 是仅有的不受当前安装的 C 本地环境影响的标准宽字符分类函数。

参阅

isxdigit(std::locale) | 检查字符是否被本地环境分类为十六进制数字 (函数模板)
isxdigit | 检查字符是为十六进制字符 (函数)
ASCII 值 |  |  | 字符 | iscntrl iswcntrl | isprint iswprint | isspace iswspace | isblank iswblank | isgraph iswgraph | ispunct iswpunct | isalnum iswalnum | isalpha iswalpha | isupper iswupper | islower iswlower | isdigit iswdigit | isxdigit iswxdigit
十进制 | 十六进制 | 八进制
0–8 | \x0–\x8 | \0–\10 | 控制码 (NUL 等) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
9 | \x9 | \11 | 制表 (\t) | ≠0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
10–13 | \xA–\xD | \12–\15 | 空白符 (\n, \v, \f, \r) | ≠0 | 0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
14–31 | \xE–\x1F | \16–\37 | 控制码 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
32 | \x20 | \40 | space | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
33–47 | \x21–\x2F | \41–\57 | !"#$%&'()*+,-./ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
48–57 | \x30–\x39 | \60–\71 | 0123456789 | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | 0 | 0 | 0 | ≠0 | ≠0
58–64 | \x3A–\x40 | \72–\100 | :;<=>?@ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
65–70 | \x41–\x46 | \101–\106 | ABCDEF | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | ≠0
71–90 | \x47–\x5A | \107–\132 | GHIJKLMNOP QRSTUVWXYZ | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | ≠0 | 0 | 0 | 0
91–96 | \x5B–\x60 | \133–\140 | [\]^_` | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
97–102 | \x61–\x66 | \141–\146 | abcdef | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | ≠0
103–122 | \x67–\x7A | \147–\172 | ghijklmnop qrstuvwxyz | 0 | ≠0 | 0 | 0 | ≠0 | 0 | ≠0 | ≠0 | 0 | ≠0 | 0 | 0
123–126 | \x7B–\x7E | \172–\176 | {|}~ | 0 | ≠0 | 0 | 0 | ≠0 | ≠0 | 0 | 0 | 0 | 0 | 0 | 0
127 | \x7F | \177 | 退格字符 (DEL) | ≠0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0


std::towctrans

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
std::wint_t towctrans( std::wint_t wc, std::wctrans_t desc );

用 desc 所标识的当前 C 本地环境的 LC_TYPE 映射宽字符 wc 。

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch | - | 要映射的宽字符
desc | - | 从调用 std::wctrans 获得的 LC_CTYPE 映射

返回值

ch 的被映射值，使用当前 C 本地环境的 LC_TYPE 中的 desc 标识的映射。

示例

下列代码演示片假名到平假名的字符映射

#include <clocale>
#include <cwctype>
#include <iostream>
#include <algorithm>

std::wstring tohira(std::wstring str)
{
    std::transform(str.begin(), str.end(), str.begin(), [](wchar_t c) {
         return std::towctrans(c, std::wctrans("tojhira"));
    });
    return str;
}

int main()
{
    std::setlocale(LC_ALL, "ja_JP.UTF-8");
    std::wstring kana = L"ヒラガナ";
    std::wcout << "katakana characters " << kana
               << " are " << tohira(kana) << " in hiragana\n";
}

输出：

katakana characters ヒラガナ are ひらがな in hiragana

参阅

wctrans
 在当前 C 本地环境中查找字符映射类别
(函数)


std::towlower

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
std::wint_t towlower( std::wint_t ch );

若可能，则转换给定宽字符为小写。

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch - 要转换的宽字符

返回值

ch 的小写版本，或若无小写版本列于当前 C 本地环境则为不修改的 ch 。

注意

此函数只能进行 1:1 字符映射，例如希腊大写字母 'Σ' 拥有二个小写形式，依赖在词中的位置： 'σ' 与 'ς' 。此情况下，不能用对 std::towlower 的调用获得正确的小写形式。

ISO 30112 指定此映射包含哪些 Unicode 字符对。

示例

#include <iostream>
#include <cwctype>
#include <clocale>

int main()
{
    wchar_t c = L'\u0190'; // 拉丁文大写字母开 E ('Ɛ')

    std::cout << std::hex << std::showbase;
    std::cout << "in the default locale, towlower(" << (std::wint_t)c << ") = "
              << std::towlower(c) << '\n';
    std::setlocale(LC_ALL, "en_US.utf8");
    std::cout << "in Unicode locale, towlower(" << (std::wint_t)c << ") = "
              << std::towlower(c) << '\n';
}

输出：

in the default locale, towlower(0x190) = 0x190
in Unicode locale, towlower(0x190) = 0x25b

参阅

towupper | 转换宽字符为大写 (函数)
tolower(std::locale) | 用本地环境的 ctype 刻面将字符转换为小写 (函数模板)
tolower | 转换字符为小写 (函数)


std::towupper

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
std::wint_t towupper( std::wint_t ch );

若可能则转换给定的宽字符为大写。

若 ch 的值既不能表示为 wchar_t 又不等于宏 WEOF ，则行为未定义。

参数

ch - 要转换的宽字符

返回值

ch 的大写版本，或若无大写版本列于当前 C 本地环境，则为不修改的 ch 。

注意

此函数只能进行 1:1 映射，例如 'ß' 的大写形式（有一些例外）是双字符字符串 "SS" ，它无法通过 std::towupper 获得。

ISO 30112 指定此映射包含哪些 Unicode 字符对。

示例

拉丁字母 'ſ' (U+017F) 是 'S' (U+0053) 的替用小写形式。

#include <iostream>
#include <cwctype>
#include <clocale>

int main()
{
    wchar_t c = L'\u017f'; // 拉丁文小写字母长 S ('ſ')

    std::cout << std::hex << std::showbase;
    std::cout << "in the default locale, towupper(" << (std::wint_t)c << ") = "
              << std::towupper(c) << '\n';
    std::setlocale(LC_ALL, "en_US.utf8");
    std::cout << "in Unicode locale, towupper(" << (std::wint_t)c << ") = "
              << std::towupper(c) << '\n';
}

输出：

in the default locale, towupper(0x17f) = 0x17f
in Unicode locale, towupper(0x17f) = 0x53

参阅

towlower | 转换宽字符为小写 (函数)
toupper(std::locale) | 用本地环境的 ctype 刻面将字符转换为大写 (函数模板)
toupper | 转换字符为大写 (函数)


std::wcscat

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
wchar_t *wcscat( wchar_t *dest, const wchar_t *src );

后附 src 所指向的空终止宽字符串的副本到 dest 所指向的空终止宽字符串的结尾。宽字符 src[0] 替换 dest 末尾的空终止符。产生的宽字符串是空终止的。

若目标数组对于 src 和 dest 的内容以及终止空宽字符不够大，则行为未定义。

若字符串重叠，则行为未定义。

参数

dest | - | 指向要后附到的空终止宽字符串的指针
src | - | 指向作为复制来源的空终止宽字符串的指针

返回值

返回 dest 的副本。

示例

#include <iostream>
#include <cwchar>
#include <clocale>

int main(void)
{
    wchar_t str[50] = L"Земля, прощай.";
    std::wcscat(str, L" ");
    std::wcscat(str, L"В добрый путь.");

    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout.imbue(std::locale("en_US.utf8"));
    std::wcout << str << '\n';
}

可能的输出：

Земля, прощай. В добрый путь.

参阅

wcsncat | 后附来自一个宽字符串的一定量宽字符到另一个 (函数)
strcat | 连接两个字符串 (函数)
wcscpy | 复制一个宽字符串到另一个 (函数)


std::wcschr

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
const wchar_t* wcschr( const wchar_t* str, wchar_t ch );
wchar_t* wcschr( wchar_t* str, wchar_t ch );

寻找宽字符 ch 在 str 所指向的宽字符串中的首次出现。

参数

str | - | 指向待分析的空终止宽字符的指针
ch | - | 要搜索的宽字符

返回值

指向 str 中找到的字符的指针，或若找不到这种字符则为空指针。

示例

#include <iostream>
#include <cwchar>
#include <locale>

int main()
{
    wchar_t arr[] = L"招き猫 кошка";
    const wchar_t* cat = std::wcschr(arr, L'猫');
    const wchar_t* dog = std::wcschr(arr, L'犬');

    std::cout.imbue(std::locale("en_US.utf8"));

    if(cat)
        std::cout << "The character 猫 found at position " << cat - arr << '\n';
    else
        std::cout << "The character 猫 not found\n";

    if(dog)
        std::cout << "The character 犬 found at position " << dog - arr << '\n';
    else
        std::cout << "The character 犬 not found\n";
}

输出：

The character 猫 found at position 2
The character 犬 not found

参阅

find | 于字符串中寻找字符 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
strchr | 寻找字符的首次出现 (函数)
wcsrchr | 在宽字符串中寻找宽字符的最后一次出现 (函数)
wcspbrk | 在一个宽字符串中，寻找另一宽字符串中任何字符的首个位置 (函数)


std::wcscmp

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
int wcscmp( const wchar_t* lhs, const wchar_t* rhs );

以字典序比较二个空终止宽字符串。

结果的符号是被比较的字符串中，首对相异宽字符间的差值符号。

若 lhs 或 rhs 不是指向空终止宽字符串的指针，则行为未定义。

参数

lhs, rhs - 指向待比较的空终止宽字符串的指针

返回值

若字典序中 lhs 先出现于 rhs 则为负值。

若 lhs 与 rhs 比较相等则为零。

若字典序中 lhs 后出现于 rhs 则为负值。

注意

不同于 std::wcscoll ，此函数不考虑本地环境。而且在一同使用来自不同的 Unicode 块的字符时，或编码单元不匹配任何对照顺序时，顺序可能无意义。

示例

#include <vector>
#include <cwchar>
#include <algorithm>
#include <iostream>

int main()
{
    std::vector<const wchar_t*> leaders{L"Ленин", L"Сталин", L"Маленков",
        L"Хрущёв", L"Брежнев", L"Андропов", L"Черненко", L"Горбачёв"};

    std::sort(leaders.begin(), leaders.end(), [](auto strA, auto strB) {
        return std::wcscmp(strA, strB) < 0;
    });

    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout.imbue(std::locale("en_US.utf8"));
    for (auto leader : leaders)
        std::wcout << leader << '\n';
}

可能的输出：

Андропов
Брежнев
Горбачёв
Ленин
Маленков
Сталин
Хрущёв
Черненко

参阅

wcsncmp | 比较来自两个宽字符串的一定量宽字符 (函数)
wmemcmp | 比较来自两个数组的一定量宽字符 (函数)
strcmp | 比较两个字符串 (函数)
wcscoll | 按照当前本地环境比较两个宽字符串 (函数)


std::wcscoll

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
int wcscoll( const wchar_t* lhs, const wchar_t* rhs );

按照最近通过 std::setlocale 安装的， LC_COLLATE 类别所定义的本地环境比较二个空终止宽字符串。

参数

lhs, rhs - 指向要比较的空终止宽字符串的指针

返回值

若 lhs 小于（前趋） rhs 则为负值。

若 lhs 等于 rhs 则为 ​0​ 。

若 lhs 大于（后随） rhs 则为负值。

注意

对照顺序为字典顺序：国家字母表（其等价类）中字母的位置拥有高于其大小写或变体的优先级。在等价类内，小写字符先于其大写等价物对照，而且本地环境限定的顺序可能应用到有发音符号的字符。一些本地环境中，字符组作为单个对照单元比较。例如， "ch" 在捷克语中后随 "h" 而前趋 "i" ， "dzs" 在匈牙利语中后随 "dz" 而前趋 "g" 。

示例

#include <iostream>
#include <clocale>

void try_compare(const wchar_t* p1, const wchar_t* p2)
{
    if(std::wcscoll(p1, p2) < 0)
         std::wcout << p1 << " before " << p2 << '\n';
    else
         std::wcout << p2 << " before " << p1 << '\n';
}

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout << "In the American locale: ";
    try_compare(L"hrnec", L"chrt");

    std::setlocale(LC_COLLATE, "cs_CZ.utf8");
    std::wcout << "In the Czech locale: ";
    try_compare(L"hrnec", L"chrt");

    std::setlocale(LC_COLLATE, "en_US.utf8");
    std::wcout << "In the American locale: ";
    try_compare(L"år", L"ängel");

    std::setlocale(LC_COLLATE, "sv_SE.utf8");
    std::wcout << "In the Swedish locale: ";
    try_compare(L"år", L"ängel");
}

输出：

In the American locale: chrt before hrnec
In the Czech locale: hrnec before chrt
In the American locale: ängel before år
In the Swedish locale: år before ängel

参阅

strcoll | 按照当前本地环境比较两个字符串 (函数)
do_compare [虚] | 用此平面的对照规则比较二个字符串 (std::collate<CharT> 的虚受保护成员函数)
wcsxfrm | 变换宽字符串，使得 wcscmp 会产生与 wsccoll 相同的结果 (函数)


std::wcscpy

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
wchar_t *wcscpy( wchar_t *dest, const wchar_t *src );

复制 src 所指向的宽字符串（包含空终止宽字符）到 dest 所指向的宽字符数组。

若字符串重叠，则行为未定义。

参数

dest | - | 指向复制来源的宽字符数组的指针
src | - | 指向复制来源的空终止宽字符串的指针

返回值

dest

示例

#include <iostream>
#include <cwchar>
#include <memory>
#include <clocale>

int main()
{
    const wchar_t* src = L"犬 means dog";
//  src[0] = L'狗'; // 不能修改字符串字面量
    auto dst = std::make_unique<wchar_t[]>(std::wcslen(src)+1); // 为空宽字符 +1
    std::wcscpy(dst.get(), src);
    dst[0] = L'狗';
    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout.imbue(std::locale(""));
    std::wcout << src << '\n' << dst.get() << '\n';
}

输出：

犬 means dog
狗 means dog

参阅

wcsncpy | 复制来自一个宽字符串的一定量宽字符到另一个 (函数)
wmemcpy | 在两个不重叠数组间复制一定量宽字符 (函数)
strcpy | 复制一个字符串给另一个 (函数)


std::wcscspn

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
std::size_t wcscspn( const wchar_t* dest, const wchar_t* src );

返回 dest 所指向的宽字符串的，仅由 src 所指向的宽字符串中找不到的字符组成的最大起始段的长度。

参数

dest | - | 指向要分析的空终止宽字符串的指针
src | - | 指向含待搜索字符的空终止宽字符串的指针

返回值

仅由 src 所指向的宽字符串中找不到的字符组成的最大起始段长度。

示例

本节未完成
原因：暂无示例

参阅

wcsspn | 返回仅由另一宽字符串中找到的宽字符组成的最大起始段的长度 (函数)
wcspbrk | 在一个宽字符串中，寻找另一宽字符串中任何字符的首个位置 (函数)


std::wcslen

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
std::size_t wcslen( const wchar_t* str );

返回宽字符串的长度，即空终止宽字符之前的非空宽字符数。

若 str 所指向的宽字符数组中无空字符则行为未定义。

参数

str - 指向要检验的空终止宽字符串的指针

返回值

空终止宽字符串 str 的长度。

示例

#include <iostream>
#include <cwchar>
#include <clocale>

int main()
{
    const wchar_t* str = L"歡迎來到加帕里公園";

    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout.imbue(std::locale("en_US.utf8"));
    std::wcout << "The length of \"" << str << "\" is " << std::wcslen(str) << '\n';
}

输出：

The length of "歡迎來到加帕里公園" is 9

参阅

strlen | 返回给定字符串的长度 (函数)
mblen | 返回下一个多字节字符中的字节数 (函数)


std::wcsncat

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
wchar_t *wcsncat( wchar_t *dest, const wchar_t *src, std::size_t count );

后附来自 src 所指向的宽字符串的至多 count 个宽字符，到 dest 所指向的字符串末尾，若找到空字符则停止。宽字符 src[0] 替换位于 dest 末尾的空终止符。始终后附终止空字符到末尾（故函数可写入的最大宽字符数是 count+1 ）。

若目标数组没有对于 dest 和 src 的内容加上终止空宽字符足够的空间，则行为未定义。

若字符串重叠则行为未定义。

参数

dest | - | 指向要后附到的空终止宽字符串的指针
src | - | 指向作为复制来源的宽字符数组的指针
count | - | 要复制的最大宽字符数

返回值

dest

示例

#include <cwchar>
#include <iostream>
#include <clocale>

int main(void)
{
    wchar_t str[50] = L"Земля, прощай.";
    std::wcsncat(str, L" ", 1);
    std::wcsncat(str, L"В добрый путь.", 8); // 只后附首 8 个宽字符

    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout.imbue(std::locale("en_US.utf8"));
    std::wcout << str << '\n';
}

可能的输出：

Земля, прощай. В добрый

参阅

wcscat | 后附一个宽字符串的副本到另一个 (函数)
strncat | 连接两个字符串的一定量字符 (函数)
wcscpy | 复制一个宽字符串到另一个 (函数)


std::wcsncmp

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
int wcsncmp( const wchar_t* lhs, const wchar_t* rhs, std::size_t count );

比较二个空终止宽字符串的至多 count 个字符。按字典序进行比较。

结果的符号是被比较的字符串中首对宽字符的值间的差的符号。

若 lhs 或 rhs 不是指向空终止字符串的指针则行为未定义。

参数

lhs, rhs | - | 指向要比较的空终止宽字符串的指针
count | - | 要比较的最大字符数

返回值

若字典序中 lhs 先出现于 rhs 则为负值。

若 lhs 与 rhs 比较相等，或若 count 为零，则为零。

若字典序中 lhs 后出现于 rhs 则为负值。

示例

#include <iostream>
#include <cwchar>
#include <clocale>
#include <locale>

void demo(const wchar_t* lhs, const wchar_t* rhs, int sz)
{
    int rc = std::wcsncmp(lhs, rhs, sz);
    if(rc == 0)
        std::wcout << "First " << sz << " characters of ["
                  << lhs << "] equal [" << rhs << "]\n";
    else if(rc < 0)
        std::wcout << "First " << sz << " characters of ["
                  << lhs << "] precede [" << rhs << "]\n";
    else if(rc > 0)
        std::wcout << "First " << sz << " characters of ["
                  << lhs << "] follow [" << rhs << "]\n";
}

int main()
{
    const wchar_t str1[] = L"안녕하세요";
    const wchar_t str2[] = L"안녕히 가십시오";

    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout.imbue(std::locale("en_US.utf8"));
    demo(str1, str2, 5);
    demo(str2, str1, 8);
    demo(str1, str2, 2);
}

输出：

First 5 characters of [안녕하세요] precede [안녕히 가십시오]
First 8 characters of [안녕히 가십시오] follow [안녕하세요]
First 2 characters of [안녕하세요] equal [안녕히 가십시오]

参阅

strncmp | 比较两个字符串的一定量字符 (函数)
wcscmp | 比较两个宽字符串 (函数)
wmemcmp | 比较来自两个数组的一定量宽字符 (函数)
wcscoll | 按照当前本地环境比较两个宽字符串 (函数)


std::wcsncpy

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
wchar_t *wcsncpy( wchar_t *dest, const wchar_t *src, std::size_t count );

复制 src 所指向的宽字符串的至多 count 个字符（包含终止空宽字符）到 dest 所指向的宽字符数组。

若在完全复制整个 src 数组前抵达 count ，则产生的宽字符数组不是空终止的。

若在复制来自 src 的终止空宽字符后未抵达 count ，则写入额外的空宽字符到 dest ，直至写入总共 count 个字符。

若字符串重叠，则行为未定义。

参数

dest | - | 指向要复制到的宽字符数组的指针
src | - | 指向复制来源的宽字符串的指针
count | - | 要复制的最大宽字符数

返回值

dest

注意

典型用法中， count 是目标数组的大小。

示例

#include <iostream>
#include <cwchar>

int main()
{
    wchar_t src[] = L"hi";
    wchar_t dest[6] = {L'a', L'b', L'c', L'd', L'e', L'f'};

    std::wcsncpy(dest, src, 5); // 这将复制 hi 并重复 \0 三次

    std::wcout << "The contents of dest are: ";
    for(wchar_t c : dest) {
        if(c)
            std::wcout << c << ' ';
        else
            std::wcout << "\\0" << ' ';
    }
    std::wcout << '\n';
}

输出：

The contents of dest are: h i \0 \0 \0 f

参阅

wcscpy | 复制一个宽字符串到另一个 (函数)
wmemcpy | 在两个不重叠数组间复制一定量宽字符 (函数)
strncpy | 复制来自一个字符串的一定量字符给另一个 (函数)


std::wcspbrk

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
const wchar_t* wcspbrk( const wchar_t* dest, const wchar_t* str );
wchar_t* wcspbrk( wchar_t* dest, const wchar_t* str );

在 dest 所指向的宽字符串中，寻找首个亦在 str 所指向的宽字符串中的字符。

参数

dest | - | 指向要分析的空终止宽字符串的指针
src | - | 指向含有待搜索字符的空终止宽字符串的指针

返回值

指向 dest 中首个亦在 str 中的首个字符的指针，或若这种字符不存在则为空指针。

注解

名字代表“宽字符串指针打断 (wide character string pointer break) ”，因为它返回指向首个分隔符（“打断”）的指针。

示例

#include <iostream>
#include <cwchar>
#include <iomanip>

int main()
{
    const wchar_t* str = L"Hello world, friend of mine!";
    const wchar_t* sep = L" ,!";

    unsigned int cnt = 0;
    do {
       str = std::wcspbrk(str, sep); // 寻找分隔符
       std::wcout << std::quoted(str) << L'\n';
       if (str) str += std::wcsspn(str, sep); // 跳过分隔符
       ++cnt; // 增加词计数
    } while (str && *str);

    std::wcout << L"There are " << cnt << L" words\n";
}

输出：

" world, friend of mine!"
", friend of mine!"
" of mine!"
" mine!"
"!"
There are 5 words

参阅

wcscspn | 返回仅由另一宽字符串中找不到的宽字符组成的最大起始段的长度 (函数)
wcschr | 寻找宽字符串中宽字符的首次出现 (函数)
strpbrk | 寻找任何来自分隔符集合的字符的首个位置 (函数)


std::wcsrchr

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
const wchar_t* wcsrchr( const wchar_t* str, wchar_t ch );
wchar_t* wcsrchr( wchar_t* str, wchar_t ch );

寻找宽字符 ch 在 str 所指向的空终止宽字符串中的最后一次出现。

参数

str | - | 指向要分析的空终止宽字符串的指针
ch | - | 要搜索的宽字符

返回值

指向 str 中找到的字符的指针，或若找不到这种字符则为空指针。

示例

本节未完成
原因：暂无示例

参阅

wcschr | 寻找宽字符串中宽字符的首次出现 (函数)
strrchr | 寻找字符的最后出现 (函数)
rfind | 寻找子串的最后一次出现 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)


std::wcsspn

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
size_t wcsspn( const wchar_t* dest, const wchar_t* src );

返回 dest 所指向的空终止宽字符串的，仅由在 src 所指向的宽字符串中找到的字符组成的最大起始段的长度。

参数

dest | - | 指向要分析的空终止宽字符串的指针
src | - | 指向含有要搜索的字符的空终止宽字符串的指针

返回值

仅由来自 src 所指向的宽字符串的字符组成的最大起始段长度。

示例

本节未完成
原因：暂无示例

参阅

wcscspn | 返回仅由另一宽字符串中找不到的宽字符组成的最大起始段的长度 (函数)
wcspbrk | 在一个宽字符串中，寻找另一宽字符串中任何字符的首个位置 (函数)


std::wcsstr

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
const wchar_t* wcsstr( const wchar_t* dest, const wchar_t* src );
wchar_t* wcsstr( wchar_t* dest, const wchar_t* src );

寻找 dest 所指的空终止宽字符串在 src 所指的空终止宽字符串中的首次出现。不比较空终止字符。

若 src 或 dest 不是指向空终止字节字符串的指针，则行为未定义。

参数

dest | - | 指向要检验的空终止字节字符串的指针
src | - | 指向要搜索的空终止宽字符串的指针

返回值

指向于 dest 中找到的子串首字符的指针，或若找不到该子串则为空指针。若 src 指向空字符串，则返回 dest 。

示例

#include <iostream>
#include <cwchar>
#include <clocale>

int main()
{
    wchar_t const* origin = L"アルファ, ベータ, ガンマ, アルファ, ベータ, ガンマ.";
    wchar_t const* target = L"ベータ";
    wchar_t const* result = origin;

    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout << L"Substring to find: \"" << target << L"\"\n"
               << L"String to search: " << origin << L"\n\n";

    for (; (result = std::wcsstr(result, target)) != NULL; ++result)
        std::wcout << L"found: " << result << '\n';
}

可能的输出：

Substring to find: "ベータ"
String to search: アルファ, ベータ, ガンマ, アルファ, ベータ, ガンマ.

found: ベータ, ガンマ, アルファ, ベータ, ガンマ.
found: ベータ, ガンマ.

参阅

find | 于字符串中寻找字符 (std::basic_string<CharT,Traits,Allocator> 的公开成员函数)
strstr | 寻找字符子串的首次出现 (函数)
wcschr | 寻找宽字符串中宽字符的首次出现 (函数)
wcsrchr | 在宽字符串中寻找宽字符的最后一次出现 (函数)


std::wcstof, std::wcstod, std::wcstold

< cpp‎ | string‎ | wide
定义于头文件 <cwchar> |
float wcstof( const wchar_t* str, wchar_t** str_end ); | (C++11 起)
double wcstod( const wchar_t* str, wchar_t** str_end ); |
long double wcstold( const wchar_t* str, wchar_t** str_end ); | (C++11 起)

转译 str 所指向的宽字符串中的浮点值。

函数会舍弃任何空白符（由 std::iswspace () 确定），直至找到首个非空白符。然后它会取用尽可能多的字符，以构成合法的浮点数表示，并将它们转换成浮点值。合法的浮点值可以为下列之一：

  • 十进制浮点数表达式。它由下列部分组成：
  • (可选) 正或负号
  • 非空的十进制数字序列，可选地包含一个小数点字符（由当前的 C 本地环境确定）（定义有效数字）
  • (可选) e 或 E ，并跟随可选的正或负号，以及非空十进制数字序列（以 10 为底定义指数）
  • 十六进制浮点数表达式。它由下列部分组成：
  • (可选) 正或负号
  • 0x 或 0X
  • 非空的十六进制数字序列，选地包含一个小数点字符（由当前的 C 本地环境确定）（定义有效数字）
  • (可选) p 或 P ，并跟随可选的正或负号，以及非空十进制数字序列（以 2 为底定义指数）
  • 无穷大表达式。它由下列部分组成：
  • (可选) 正或负号
  • INF 或 INFINITY ，忽略大小写
  • 非数（NaN）表达式。它由下列部分组成：
  • (可选) 正或负号
  • NAN 或 NAN(char_sequence) ，忽略 NAN 部分的大小写。 char_sequence 只能由数字、拉丁字母和下划线构成。结果是一个静态的 NaN 浮点值。
 (C++11 起)
  • 任何其他可由当前 C 本地环境接受的表达式

函数设置 str_end 所指向的指针为指向最后被转译宽字符的后一字符。若 str_end 为空指针，则忽略它。

参数

str | - | 指向要转译的空终止宽字符串的指针
str_end | - | 指向指向宽字符指针的指针。

返回值

成功时为对应 str 内容的浮点值。若转换得到的值落在对应返回类型的范围外，则发生值域错误并返回 HUGE_VAL 、 HUGE_VALF 或 HUGE_VALL 。若不能进行转换，则返回 ​0​ 。

示例

#include <iostream>
#include <string>
#include <cerrno>
#include <cwchar>

int main()
{
    const wchar_t* p = L"111.11 -2.22 0X1.BC70A3D70A3D7P+6  1.18973e+4932zzz";
    wchar_t* end;
    std::wcout << "Parsing L\"" << p << "\":\n";
    for (double f = std::wcstod(p, &end); p != end; f = std::wcstod(p, &end))
    {
        std::wcout << "'" << std::wstring(p, end-p) << "' -> ";
        p = end;
        if (errno == ERANGE){
            std::wcout << "range error, got ";
            errno = 0;
        }
        std::wcout << f << '\n';
    }
}

输出：

Parsing L"111.11 -2.22 0X1.BC70A3D70A3D7P+6  1.18973e+4932zzz":
'111.11' -> 111.11
' -2.22' -> -2.22
' 0X1.BC70A3D70A3D7P+6' -> 111.11
'  1.18973e+4932' -> range error, got inf

参阅

strtofstrtodstrtold
 转换字节字符串为浮点值
(函数)


std::wcstoimax, std::wcstoumax

< cpp‎ | string‎ | wide
定义于头文件 <cinttypes> |
std::intmax_t wcstoimax( const wchar_t* nptr, wchar_t** endptr, int base ); | (C++11 起)
std::uintmax_t wcstoumax( const wchar_t* nptr, wchar_t** endptr, int base ); | (C++11 起)

转译 nptr 所指向的宽字符串中的整数值。

舍弃所有空白符（以调用 isspace() 鉴别），直到找到首个非空白符，然后取尽可能多的字符组成底 n （其中 n=base ）的无符号整数表示，并将它们转换成一个整数值。合法的无符号整数值由下列部分组成：

  • (可选)正或负号
  • (可选)指示八进制底的前缀（ 0 ）（仅当底为 8 或 ​0​ 时应用）
  • (可选)指示十六进制底的前缀（ 0x 或 0X ）（仅当底为 16 或 ​0​ 时应用）
  • 一个数字序列

底的合法集是 {0,2,3,...,36} 。合法数字集对于底 2 整数是 {0,1}，对于底3整数是 {0,1,2} ，以此类推。对于大于 10 的底，合法数字包含字母字符，从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。

当前安装的 C 本地环境可能接受另外的数字格式。

若 base 为 ​0​ ，则自动检测数值进制：若前缀为 0 ，则底为八进制，若前缀为 0x 或 0X ，则底为十六进制，否则底为十进制。

若符号是输入序列的一部分，则对从数字序列计算得来的数字值取反，如同用结果类型的一元减，它对无符号整数应用回卷规则。

函数设置 endptr 所指向的指针指向最后被转译宽字符的后一宽字符。若 endptr 为空指针，则忽略它。

参数

nptr | - | 指向要转译的空终止宽字符串的指针
endptr | - | 指向指向宽字符指针的指针。
base | - | 被转译整数值的底

返回值

成功时为对应 str 内容的整数值。若被转换值落在对应返回类型。若转换出的值落在对应返回类型范围外，则发生值域错误并返回 INTMAX_MAX 、 INTMAX_MIN 、 UINTMAX_MAX 或 ​0​ 中的接近者。若不能进行转换，则返回 ​0​ 。

示例

#include <iostream>
#include <string>
#include <cinttypes>

int main()
{
    std::wstring str = L"helloworld";
    std::intmax_t val = std::wcstoimax(str.c_str(), nullptr, 36);
    std::wcout << str << " in base 36 is " << val << " in base 10\n";

    wchar_t* nptr;
    val = std::wcstoimax(str.c_str(), &nptr, 30);
    if(nptr != &str[0] + str.size())
        std::wcout << str << " in base 30 is invalid."
                  << " The first invalid digit is " << *nptr << '\n';
}

输出：

helloworld in base 36 is 1767707668033969 in base 10
helloworld in base 30 is invalid. The first invalid digit is w

参阅

strtoimaxstrtoumax (C++11)(C++11) | 转换字节字符串为 std::intmax_t 或 std::uintmax_t (函数)
wcstolwcstoll | 转换宽字符串为整数值 (函数)
wcstoulwcstoull | 转换宽字符串为无符号整数值 (函数)


std::wcstok

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
wchar_t* wcstok( wchar_t* str, const wchar_t* delim, wchar_t ** ptr);

寻找 str 所指向的空终止宽字符串中的下个记号。以 delim 所指向的空终止宽字符串鉴别分隔符。

此函数被设计为调用多次以从同一字符串获得相继的记号。
  • 若 str != NULL ，则调用被当做 std::wcstok 首次对此具体宽字符的调用。函数搜索首个不含于 delim 的字符。
  • 若找不到这种宽字符，则 str 中完全无记号，而函数返回空指针。
  • 若找到这种宽字符，则它是记号起始。然后函数从该点搜索首个含于 delim 的宽字符。
  • 若找不到这种宽字符，则 str 只有一个记号，而对 std::wcstok 的将来调用将返回空指针
  • 若找到这种宽字符，则以空宽字符 L'\0' 替换它，并存储分析状态（典型地为指向后一宽字符的指针）于用户提供位置 *ptr 。
  • 然后函数返回指向记号起始的指针
  • 若 str == NULL ，则调用被当作对 std::wcstok 的后继调用：函数从带同一 *ptr 的先前调用所留下的位置开始持续。行为与如同将指向后随上次检测的记号的宽字符的指针作为 str 传递相同。

参数

str | - | 指向要记号化的空终止宽字符串的指针
delim | - | 指向标识分隔符的空终止宽字符串的指针
ptr | - | 指向 wchar_t* 类型对象的指针， wcstok 以之存储分析器的内部状态

返回值

返回指向下个记号起始的指针，或若无更多记号则为空指针。

注意

此函数是破坏性的：它写入 L'\0' 字符于字符串 str 的元素。特别是，宽字符串字面量不能用作 std::wcstok 的首参数。

不同于 std::strtok ，此函数不更新静态存储：它存储分析状态于用户提供的位置。

不同于大多数其他记号化器， std::wcstok 中的分隔符能对于后继记号不同，而且甚至能依赖于先前记号的内容。

示例

#include <cwchar>
#include <iostream>

int main()
{
    wchar_t input[100] = L"A bird came down the walk";
    wchar_t* buffer;
    wchar_t* token = std::wcstok(input, L" ", &buffer);
    while (token) {
        std::wcout << token << '\n';
        token = std::wcstok(nullptr, L" ", &buffer);
    }
}

输出：

A
bird
came
down
the
walk

参阅

strtok
 寻找字节字符串中的下个记号
(函数)


std::wcstol, std::wcstoll

< cpp‎ | string‎ | wide
定义于头文件 <cwchar> |
long wcstol( const wchar_t* str, wchar_t** str_end, int base ); |
long long wcstoll( const wchar_t* str, wchar_t** str_end, int base ); | (C++11 起)

转译 str 所指向的宽字符串中的整数值。

舍弃所有空白符（以调用 isspace() 鉴别），直到找到首个非空白符，然后取尽可能多的字符组成底 n （其中 n=base ）的整数表示，并将它们转换成一个整数值。合法的整数值由下列部分组成：

  • (可选)正或负号
  • (可选)指示八进制底的前缀（ 0 ）（仅当底为 8 或 ​0​ 时应用）
  • (可选)指示十六进制底的前缀（ 0x 或 0X ）（仅当底为 16 或 ​0​ 时应用）
  • 一个数字序列

底的合法集是 {0,2,3,...,36} 。合法数字集对于底 2 整数是 {0,1}，对于底3整数是 {0,1,2} ，以此类推。对于大于 10 的底，合法数字包含字母字符，从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。

当前安装的 C 本地环境可能接受另外的数字格式。

若 base 为 ​0​ ，则自动检测数值进制：若前缀为 0 ，则底为八进制，若前缀为 0x 或 0X ，则底为十六进制，否则底为十进制。

若符号是输入序列的一部分，则对从数字序列计算得来的数字值取反，如同用结果类型的一元减。

函数设置 str_end 所指向的指针指向最后一个被转译字符的后一宽字符。若 str_end 为空指针，则忽略之。

参数

str | - | 指向要转译的空终止宽字符串的指针
str_end | - | 指向指向宽字符的指针的指针
base | - | 被转译整数值的底

返回值

成功时为对应 str 内容的整数值。若转换得到的值落在对应类型的范围外，则发生值域错误并返回 LONG_MAX 、 LONG_MIN 、 LLONG_MAX 或 LLONG_MIN 。若不能进行转换，则返回 ​0​ 。

示例

#include <iostream>
#include <string>
#include <errno.h>
#include <cwchar>

int main()
{
    const wchar_t* p = L"10 200000000000000000000000000000 30 -40";
    wchar_t *end;
    std::wcout << "Parsing L'" << p << "':\n";
    for (long i = std::wcstol(p, &end, 10);
         p != end;
         i = std::wcstol(p, &end, 10))
    {
        std::wcout << "'" << std::wstring(p, end-p) << "' -> ";
        p = end;
        if (errno == ERANGE){
            std::wcout << "range error, got ";
            errno = 0;
        }
        std::wcout << i << '\n';
    }
}

可能的输出：

Parsing L'10 200000000000000000000000000000 30 -40':
'10' -> 10
' 200000000000000000000000000000' -> range error, got 9223372036854775807
' 30' -> 30
' -40' -> -40

参阅

strtolstrtoll (C++11) | 转换字节字符串为整数值 (函数)
wcstoulwcstoull | 转换宽字符串为无符号整数值 (函数)


std::wcstoul, std::wcstoull

< cpp‎ | string‎ | wide
定义于头文件 <cwchar> |
unsigned long wcstoul( const wchar_t* str, wchar_t** str_end, int base ); |
unsigned long long wcstoull( const wchar_t* str, wchar_t** str_end, int base ); | (C++11 起)

转译 str 所指向的宽字符串中的无符号整数值。

舍弃所有空白符（以调用 isspace() 鉴别），直到找到首个非空白符，然后取尽可能多的字符组成底 n （其中 n=base ）的无符号整数表示，并将它们转换成一个整数值。合法的无符号整数值由下列部分组成：

  • (可选)正或负号
  • (可选)指示八进制底的前缀（ 0 ）（仅当底为 8 或 ​0​ 时应用）
  • (可选)指示十六进制底的前缀（ 0x 或 0X ）（仅当底为 16 或 ​0​ 时应用）
  • 一个数字序列

底的合法集是 {0,2,3,...,36} 。合法数字集对于底 2 整数是 {0,1}，对于底3整数是 {0,1,2} ，以此类推。对于大于 10 的底，合法数字包含字母字符，从对于底 11 整数的 Aa 到对于底36整数的 Zz 。忽略字符大小写。

当前安装的 C 本地环境可能接受另外的数字格式。

若 base 为 ​0​ ，则自动检测数值进制：若前缀为 0 ，则底为八进制，若前缀为 0x 或 0X ，则底为十六进制，否则底为十进制。

若符号是输入序列的一部分，则对从数字序列计算得来的数字值取反，如同用结果类型的一元减，它对无符号整数应用回卷规则。

函数设置 str_end 所指向的指针指向最后被转译字符的后一宽字符。若 str_end 为空指针，则忽略它。

参数

str | - | 指向要转译的空终止宽字符串的指针
str_end | - | 指向指向宽字符的指针的指针
base | - | 被转译整数值的底

返回值

成功时为对应 str 内容的整数值。若转换后的值落在对应返回类型的范围外，则出现值域错误并返回 ULONG_MAX 和 ULLONG_MAX 。若不能进行转换，则返回 ​0​ 。

示例

#include <iostream>
#include <string>
#include <errno.h>
#include <cwchar>

int main()
{
    const wchar_t* p = L"10 200000000000000000000000000000 30 40";
    wchar_t *end;
    std::wcout << "Parsing L'" << p << "':\n";
    for (unsigned long i = std::wcstoul(p, &end, 10);
         p != end;
         i = std::wcstoul(p, &end, 10))
    {
        std::wcout << "'" << std::wstring(p, end-p) << "' -> ";
        p = end;
        if (errno == ERANGE){
            std::wcout << "range error, got ";
            errno = 0;
        }
        std::wcout << i << '\n';
    }
}

可能的输出：

Parsing L'10 200000000000000000000000000000 30 40':
'10' -> 10
' 200000000000000000000000000000' -> range error, got 18446744073709551615
' 30' -> 30
' 40' -> 40

参阅

strtoulstrtoull (C++11) | 转换字节字符串为无符号整数值 (函数)
wcstolwcstoll | 转换宽字符串为整数值 (函数)


std::wcsxfrm

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
std::size_t wcsxfrm( wchar_t* dest, const wchar_t* src, std::size_t count );

变换 src 所指向的空终止宽字符串为实现定义形式，满足在当前 C 本地环境中，用 std::wcscmp 比较二个变换后的字符串给出的结果与用 std::wcscoll 比较源字符串者相同。

将变换后字符串的首 count 个字符写入目标，包含空终止符，并返回完整的变换后字符串长度，排除空终止符。

若 count 为 ​0​ ，则允许 dest 为空指针。

注意

能接收整个变换后字符串的正确缓冲区长度是 1+std::wcsxfrm( NULL, src, 0) 。

在以同一宽字符串或宽字符串集进行本地环境依赖比较时使用此函数，因为只用 std::wcsxfrm 变换所有字符串一次，再以 std::wcscmp 进行后续比较更为高效。

参数

dest | - | 指向要写入变换后字符串到的空终止宽字符数组首元素的指针
src | - | 指向要变换的空终止宽字符串的指针
count | - | 要输出的最大字符数

返回值

变换后的空终止宽字符串的长度，不包含空终止字符。

示例

#include <iostream>
#include <cwchar>

int main()
{
    std::setlocale(LC_ALL, "sv_SE.utf8");

    std::wstring in1 = L"\u00e5r";
    std::wstring out1(1+std::wcsxfrm(nullptr, in1.c_str(), 0), L' ');
    std::wstring in2 = L"\u00e4ngel";
    std::wstring out2(1+std::wcsxfrm(nullptr, in2.c_str(), 0), L' ');

    std::wcsxfrm(&out1[0], in1.c_str(), out1.size());
    std::wcsxfrm(&out2[0], in2.c_str(), out2.size());

    std::wcout << "In the Swedish locale: ";
    if(out1 < out2)
         std::wcout << in1 << " before " << in2 << '\n';
    else
         std::wcout << in2 << " before " << in1 << '\n';

    std::wcout << "In lexicographical comparison: ";
    if(in1 < in2)
         std::wcout << in1 << " before " << in2 << '\n';
    else
         std::wcout << in2 << " before " << in1 << '\n';

}

输出：

In the Swedish locale: år before ängel
In lexicographical comparison: ängel before år

参阅

strxfrm | 变换字符串，使得 strcmp 会返回与 strcoll 相同的结果 (函数)
do_transform [虚] | 变换字符串，使得能用比较替换对照 (std::collate<CharT> 的虚受保护成员函数)
wcscoll | 按照当前本地环境比较两个宽字符串 (函数)


std::wctrans

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
std::wctrans_t wctrans( const char* str );

构造 std::wctrans_t 类型值，描述宽字符映射的 LC_CTYPE 类别。它可以是标准映射，或如 "tojhira" 或 "tojkata" 的本地环境限定映射之一。

参数

str - 保有所欲映射名的 C 字符串。

下列 str 的值在所有 C 本地环境中受到支持：

str 的值 | 效果
"toupper" | 标识 towupper 所用的映射
"tolower" | 标识 towlower 所用的映射

返回值

std::wctrans_t 对象，适合由 std::towctrans 用来根据当前 C 本地环境的具名映射映射宽字符，或若 str 不指名当前 C 本地环境所支持的映射则为零。

参阅

towctrans
 按照指定的 LC_TYPE 映射类别进行字符映射
(函数)


std::wctype

< cpp‎ | string‎ | wide
定义于头文件 <cwctype>
std::wctype_t wctype( const char* str );

构造 std::wctype_t 类型值，它描述宽字符分类的 LC_CTYPE 类别。它可以是标准分类类别之一，或本地环境限定的类别，例如 "jkanji" 。

参数

str - 保有所欲类别名称的 C 字符串

str 的下列值在所有 C 本地环境中得到支持：

str 的值 | 效果
"alnum" | 标识 std::iswalnum 所用的类别
"alpha" | 标识 std::iswalpha 所用的类别
"blank" | 标识 std::iswblank 所用的类别(C++11)
"cntrl" | 标识 std::iswcntrl 所用的类别
"digit" | 标识 std::iswdigit 所用的类别
"graph" | 标识 std::iswgraph 所用的类别
"lower" | 标识 std::iswlower 所用的类别
"print" | 标识 std::iswprint 所用的类别
"space" | 标识 std::iswspace 所用的类别
"upper" | 标识 std::iswupper 所用的类别
"xdigit" | 标识 std::iswxdigit 所用的类别

返回值

std::wctype_t 对象，适合由 std::iswctype 用以按照当前 C 本地环境的具名类别分类宽字符，或若str 不指名当前 C 本地环境支持的类别则为零。

参阅

iswctype
 按照指定的 LC_TYPE 类别分类宽字符
(函数)


std::wmemchr

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
const wchar_t* wmemchr( const wchar_t* ptr, wchar_t ch, std::size_t count );
wchar_t* wmemchr( wchar_t* ptr, wchar_t ch, std::size_t count );

于 ptr 所指向的宽字符数组的首 count 个宽字符中，定位宽字符 ch 的首次出现。

若 count 为零，则函数返回空指针。

参数

ptr | - | 指向要检验的宽字符数组的指针
ch | - | 要搜索的宽字符
count | - | 要检验的宽字符数

返回值

指向宽字符位置的指针，或若找不到这种字符则为空指针。

示例

#include <iostream>
#include <cwchar>
#include <clocale>
#include <locale>

int main()
{
    const wchar_t str[] = L"诺不轻信，故人不负我\0诺不轻许，故我不负人。";
    wchar_t target = L'许';
    const std::size_t sz = sizeof str / sizeof *str;
    if (const wchar_t* result = std::wmemchr(str, target, sz)) {
        std::setlocale(LC_ALL, "en_US.utf8");
        std::wcout.imbue(std::locale("en_US.utf8"));
        std::wcout << "Found '" << target
                   << "' at position " << result - str << "\n";
    }
}

可能的输出：

Found '许' at position 14

参阅

memchr | 在数组中搜索字符的首次出现 (函数)
strchr | 寻找字符的首次出现 (函数)
wcschr | 寻找宽字符串中宽字符的首次出现 (函数)
findfind_iffind_if_not (C++11) | 寻找首个满足特定判别标准的元素 (函数模板)


std::wmemcmp

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
int wmemcmp( const wchar_t* lhs, const wchar_t* rhs, std::size_t count );

比较 lhs 和 rhs 所指向的宽字符数组的首 count 个宽字符。按字典序比较。

结果的符号是在被比较数组中相异的首对宽字符值的差。

若 count 为零，则不做任何事。

参数

lhs, rhs | - | 指向要比较的宽字符数组的指针
count | - | 要检验的宽字符数

返回值

若 lhs 中首个相异的宽字符小于 rhs 中对应的宽字符则为负值：字典序中 lhs 先于 rhs 。

若 lhs 和 rhs 的全部 count 个宽字符相等则为 ​0​ 。

若 lhs 中首个相异的宽字符大于 rhs 中对应的宽字符则为正值：字典序中 rhs 先于 lhs 。

注意

此函数不考虑本地环境，且不注意其所检验的 wchar_t 对象的值：亦会比较空字符和非法宽字符。

示例

#include <iostream>
#include <string>
#include <cwchar>
#include <locale>
#include <clocale>

void demo(const wchar_t* lhs, const wchar_t* rhs, std::size_t sz)
{
    std::wcout << std::wstring(lhs, sz);
    int rc = std::wmemcmp(lhs, rhs, sz);
    if(rc == 0)
        std::wcout << " compares equal to ";
    else if(rc < 0)
        std::wcout << " precedes ";
    else if(rc > 0)
        std::wcout << " follows ";
    std::wcout << std::wstring(rhs, sz) << " in lexicographical order\n";
}

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout.imbue(std::locale("en_US.utf8"));

    wchar_t a1[] = {L'α',L'β',L'γ'};
    constexpr std::size_t sz = sizeof a1 / sizeof *a1;
    wchar_t a2[sz] = {L'α',L'β',L'δ'};

    demo(a1, a2, sz);
    demo(a2, a1, sz);
    demo(a1, a1, sz);
}

可能的输出：

αβγ precedes αβδ in lexicographical order
αβδ follows αβγ in lexicographical order
αβγ compares equal to αβγ in lexicographical order

参阅

wcscmp | 比较两个宽字符串 (函数)
memcmp | 比较两个缓冲区 (函数)
wcsncmp | 比较来自两个宽字符串的一定量宽字符 (函数)


std::wmemcpy

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
wchar_t* wmemcpy( wchar_t* dest, const wchar_t* src, std::size_t count );

从 src 所指向的宽字符数组准确复制 count 个相继的宽字符到 dest 所指向的宽字符数组。若对象重叠，则行为未定义。若 count 为零，则函数不做任何事。

参数

dest | - | 指向复制目标宽字符数组的指针
src | - | 指向复制来源宽字符数组的指针
count | - | 要复制的宽字符数

返回值

dest

注意

此函数对字节字符串的类似版本是 std::strncpy ，而非 std::strcpy。

此函数不考虑本地环境，而且不关心其所复制的 wchar_t 对象的值：亦复制空字符还有非法字符。

示例

#include <iostream>
#include <cwchar>
#include <clocale>
#include <locale>

int main(void)
{
    wchar_t from1[] = L"नमस्ते";
    const size_t sz1 = sizeof from1 / sizeof *from1;
    wchar_t from2[] = L"Բարև";
    const size_t sz2 = sizeof from2 / sizeof *from2;
    wchar_t to[sz1 + sz2];

    std::wmemcpy(to, from1, sz1); // 复制 from1 ，沿着其空终止符
    std::wmemcpy(to + sz1, from2, sz2); // 后附 from2 ，沿着其空终止符

    std::setlocale(LC_ALL, "en_US.utf8");
    std::cout.imbue(std::locale("en_US.utf8"));
    std::wcout << "Wide array contains: ";
    for(size_t n = 0; n < sizeof to / sizeof *to; ++n)
        if(to[n])
            std::wcout << to[n];
        else
            std::wcout << "\\0";
    std::wcout << '\n';
}

可能的输出：

Wide array contains: नमस्ते\0Բարև\0

参阅

strncpy | 复制来自一个字符串的一定量字符给另一个 (函数)
wmemmove | 在两个可能重叠的数组间复制一定量宽字符 (函数)


std::wmemmove

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
wchar_t* wmemmove( wchar_t* dest, const wchar_t* src, std::size_t count );

准确地从 src 所指向的宽字符数组复制 count 个相继的宽字符到 dest 所指向的宽字符数组。

若 count 为零，则函数不做任何事。

数组可以重叠：如同复制宽字符到临时宽字符数组，再从临时数组到 dest 一般发生复制。

参数

dest | - | 指向复制目标宽字符数组的指针
src | - | 指向复制来源宽字符数组的指针
count | - | 要复制的宽字符数

返回值

返回 dest 的副本。

注意

此函数不考虑本地环境，并且不注意其所复制的 wchar_t 对象的值：亦会复制空字符和非法字符。

示例

#include <iostream>
#include <cwchar>
#include <locale>
#include <clocale>

int main()
{
    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout.imbue(std::locale("en_US.utf8"));

    wchar_t str[] = L"αβγδεζηθικλμνξοπρστυφχψω";
    std::wcout << str << '\n';
    std::wmemmove(str+4, str+3, 3); // 从 [δεζ] 复制到 [εζη]
    std::wcout << str << '\n';
}

可能的输出：

αβγδεζηθικλμνξοπρστυφχψω
αβγδδεζθικλμνξοπρστυφχψω

参阅

wmemcpy | 在两个不重叠数组间复制一定量宽字符 (函数)
memmove | 移动一个缓冲区到另一个 (函数)
copycopy_if (C++11) | 将某一范围的元素复制到一个新的位置 (函数模板)
copy_backward | 按从后往前的顺序复制一个范围内的元素 (函数模板)


std::wmemset

< cpp‎ | string‎ | wide
定义于头文件 <cwchar>
wchar_t* wmemset( wchar_t* dest, wchar_t ch, std::size_t count );

复制宽字符 ch 到 dest 所指向的宽字符数组的首 count 个宽字符。

若出现溢出，则行为未定义。

若 count 为零，则函数不做任何事。

参数

dest | - | 指向要填充的宽字符数组的指针
ch | - | 填充的宽字符
count | - | 要填充的宽字符数

返回值

返回 dest 的副本

注意

此函数不受本地环境影响，且不注意其写入的 wchar_t 对象的值：亦写入空字符还有非法宽字符。

示例

#include <iostream>
#include <cwchar>
#include <clocale>
#include <locale>

int main()
{
    wchar_t ar[4] = {L'1', L'2', L'3', L'4'};
    std::wmemset(ar, L'\U0001f34c', 2); // 以 🍌 替换 [12]
    std::wmemset(ar+2, L'蕉', 2); // 以 蕉 替换 [34]

    std::setlocale(LC_ALL, "en_US.utf8");
    std::wcout.imbue(std::locale("en_US.utf8"));
    std::wcout << std::wstring(ar, 4) << '\n';
}

可能的输出：

🍌🍌蕉蕉

参阅

memset | 以一个字符填充缓冲区 (函数)
wmemcpy | 在两个不重叠数组间复制一定量宽字符 (函数)
fill_n | 将一个给定值复制赋值给一个范围内的 N 个元素 (函数模板)


std 符号索引

< cpp

此页面尝试列出所有来自标准库，在命名空间 std:: 下可用的符号。符号书写如下：

  • 函数名带 () 。
  • 模板名带 <> 。

来自 std:: 的子命名空间的符号（例如 chrono ）不列于此，但命名空间名链接到对应的页面。

宏符号及被移出标准库的符号列于另外的页面。

_ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

宏

_ (下划线)

_Exit() (C++11 起)

A

abs() (int)
abs() (float)
abs<>() (std::complex)
abs<>() (std::valarray)
acos()
acos<>() (std::complex) (C++11 起)
acos<>() (std::valarray)
acosf() (C++11 起)
acosh() (C++11 起)
acosh<>() (std::complex) (C++11 起)
acoshf() (C++11 起)
acoshl() (C++11 起)
acosl() (C++11 起)
accumulate<>()
add_const<> (C++11 起)
add_const_t<> (C++14 起)
add_cv<> (C++11 起)
add_cv_t<> (C++14 起)
add_pointer<> (C++11 起)
add_pointer_t<> (C++14 起)
add_lvalue_reference<> (C++11 起)
add_lvalue_reference_t<> (C++14 起)
add_rvalue_reference<> (C++11 起)
add_rvalue_reference_t<> (C++14 起)
add_volatile<> (C++11 起)
add_volatile_t<> (C++14 起)
addressof<>() (C++11 起)
adjacent_difference<>()
adjacent_find<>()
adopt_lock (C++11 起)
adopt_lock_t (C++11 起)
advance<>()
align() (C++11 起)
align_val_t (C++17 起)
aligned_alloc() (C++17 起)
aligned_storage<> (C++11 起)
aligned_storage_t<> (C++14 起)
aligned_union<> (C++11 起)
aligned_union_t<> (C++14 起)
alignment_of<> (C++11 起)
alignment_of_v<> (C++17 起)
all_of<>() (C++11 起)
allocate_at_least<>() (C++23 起)
allocate_shared<>() (C++11 起)
allocate_shared_for_overwrite<>() (C++20 起)
allocation_result<> (C++23 起)
allocator<>
allocator_arg (C++11 起)
allocator_arg_t (C++11 起)
allocator_traits<> (C++11 起)
any (C++17 起)
any_cast<>() (C++17 起)
any_of<>() (C++11 起)
apply<>() (C++17 起)
arg<>()
array<> (C++11 起)
as_bytes<>() (C++20 起)
as_const<>() (C++17 起)
as_writable_bytes<>() (C++20 起)
asctime()
asin()
asin<>() (std::complex) (C++11 起)
asin<>() (std::valarray)
asinf() (C++11 起)
asinh() (C++11 起)
asinh<>() (std::complex) (C++11 起)
asinhf() (C++11 起)
asinhl() (C++11 起)
asinl() (C++11 起)
assignable_from<> (C++20 起)
assoc_laguerre() (C++17 起)
assoc_laguerref() (C++17 起)
assoc_laguerrel() (C++17 起)
assoc_legendre() (C++17 起)
assoc_legendref() (C++17 起)
assoc_legendrel() (C++17 起)
assume_aligned<>() (C++20 起)
async<>() (C++11 起)
at_quick_exit() (C++11 起)
atan()
atan<>() (std::complex) (C++11 起)
atan<>() (std::valarray)
atan2()
atan2<>() (std::valarray)
atan2f() (C++11 起)
atan2l() (C++11 起)
atanf() (C++11 起)
atanh() (C++11 起)
atanh<>() (std::complex) (C++11 起)
atanhf() (C++11 起)
atanhl() (C++11 起)
atanl() (C++11 起)
atexit()
atof()
atoi()
atol()
atoll() (C++11 起)

atomic<> (C++11 起)

atomic<> 全特化及 typedef ：
atomic_bool (C++11 起)
atomic_char (C++11 起)
atomic_char16_t (C++11 起)
atomic_char32_t (C++11 起)
atomic_char8_t (C++20 起)
atomic_int (C++11 起)
atomic_int8_t (C++11 起)
atomic_int16_t (C++11 起)
atomic_int32_t (C++11 起)
atomic_int64_t (C++11 起)
atomic_int_fast8_t (C++11 起)
atomic_int_fast16_t (C++11 起)
atomic_int_fast32_t (C++11 起)
atomic_int_fast64_t (C++11 起)
atomic_int_least8_t (C++11 起)
atomic_int_least16_t (C++11 起)
atomic_int_least32_t (C++11 起)
atomic_int_least64_t (C++11 起)
atomic_intmax_t (C++11 起)
atomic_intptr_t (C++11 起)
atomic_llong (C++11 起)
atomic_long (C++11 起)
atomic_ptrdiff_t (C++11 起)
atomic_schar (C++11 起)
atomic_short (C++11 起)
atomic_signed_lock_free (C++20 起)
atomic_size_t (C++11 起)
atomic_uchar (C++11 起)
atomic_uint (C++11 起)
atomic_uint8_t (C++11 起)
atomic_uint16_t (C++11 起)
atomic_uint32_t (C++11 起)
atomic_uint64_t (C++11 起)
atomic_uint_fast8_t (C++11 起)
atomic_uint_fast16_t (C++11 起)
atomic_uint_fast32_t (C++11 起)
atomic_uint_fast64_t (C++11 起)
atomic_uint_least8_t (C++11 起)
atomic_uint_least16_t (C++11 起)
atomic_uint_least32_t (C++11 起)
atomic_uint_least64_t (C++11 起)
atomic_uintmax_t (C++11 起)
atomic_uintptr_t (C++11 起)
atomic_ullong (C++11 起)
atomic_ulong (C++11 起)
atomic_unsigned_lock_free (C++20 起)
atomic_ushort (C++11 起)
atomic_wchar_t (C++11 起)

atomic_compare_exchange_strong<>() (C++11 起)
atomic_compare_exchange_strong<>() (std::shared_ptr) (C++11 起)(C++20 中弃用)
atomic_compare_exchange_strong_explicit<>() (C++11 起)
atomic_compare_exchange_strong_explicit<>() (std::shared_ptr) (C++11 起)(C++20 中弃用)
atomic_compare_exchange_weak<>() (C++11 起)
atomic_compare_exchange_weak<>() (std::shared_ptr) (C++11 起)(C++20 中弃用)
atomic_compare_exchange_weak_explicit<>() (C++11 起)
atomic_compare_exchange_weak_explicit<>() (std::shared_ptr) (C++11 起)(C++20 中弃用)
atomic_exchange<>() (C++11 起)
atomic_exchange<>() (std::shared_ptr) (C++11 起)(C++20 中弃用)
atomic_exchange_explicit<>() (C++11 起)
atomic_exchange_explicit<>() (std::shared_ptr) (C++11 起)(C++20 中弃用)
atomic_fetch_add<>() (C++11 起)
atomic_fetch_add_explicit<>() (C++11 起)
atomic_fetch_and<>() (C++11 起)
atomic_fetch_and_explicit<>() (C++11 起)
atomic_fetch_or<>() (C++11 起)
atomic_fetch_or_explicit<>() (C++11 起)
atomic_fetch_sub<>() (C++11 起)
atomic_fetch_sub_explicit<>() (C++11 起)
atomic_fetch_xor<>() (C++11 起)
atomic_fetch_xor_explicit<>() (C++11 起)
atomic_flag (C++11 起)
atomic_flag_clear() (C++11 起)
atomic_flag_clear_explicit() (C++11 起)
atomic_flag_notify_all() (C++20 起)
atomic_flag_notify_one() (C++20 起)
atomic_flag_test() (C++20 起)
atomic_flag_test_explicit() (C++20 起)
atomic_flag_test_and_set() (C++11 起)
atomic_flag_test_and_set_explicit() (C++11 起)
atomic_flag_wait() (C++20 起)
atomic_flag_wait_explicit() (C++20 起)
atomic_init<>() (C++11 起)(C++20 中弃用)
atomic_is_lock_free<>() (C++11 起)
atomic_is_lock_free<>() (std::shared_ptr) (C++11 起)(C++20 中弃用)
atomic_load<>() (C++11 起)
atomic_load<>() (std::shared_ptr) (C++11 起)(C++20 中弃用)
atomic_load_explicit<>() (C++11 起)
atomic_load_explicit<>() (std::shared_ptr) (C++11 起)(C++20 中弃用)
atomic_notify_all<>() (C++20 起)
atomic_notify_one<>() (C++20 起)
atomic_ref<> (C++20 起)
atomic_signal_fence() (C++11 起)
atomic_store<>() (C++11 起)
atomic_store<>() (std::shared_ptr) (C++11 起)(C++20 中弃用)
atomic_store_explicit<>() (C++11 起)
atomic_store_explicit<>() (std::shared_ptr) (C++11 起)(C++20 中弃用)
atomic_thread_fence() (C++11 起)
atomic_wait<>() (C++20 起)
atomic_wait_explicit<>() (C++20 起)
atto (C++11 起)

B

back_insert_iterator<>
back_inserter<>()
bad_alloc
bad_any_cast (C++17 起)
bad_array_new_length (C++11 起)
bad_cast
bad_exception
bad_function_call (C++11 起)
bad_optional_access (C++17 起)
bad_typeid
bad_variant_access (C++17 起)
bad_weak_ptr (C++11 起)
barrier<> (C++20 起)
basic_common_reference<> (C++20 起)
basic_filebuf<>
basic_format_arg<> (C++20 起)
basic_format_args<> (C++20 起)
basic_format_context<> (C++20 起)
basic_format_parse_context<> (C++20 起)
basic_fstream<>
basic_ifstream<>
basic_istream<>
basic_ios<>
basic_iostream<>
basic_ispanstream<> (C++23 起)
basic_istringstream<>
basic_ofstream<>
basic_ostream<>
basic_ospanstream<> (C++23 起)
basic_ostringstream<>
basic_osyncstream<> (C++20 起)
basic_regex<> (C++11 起)
basic_spanbuf<> (C++23 起)
basic_spanstream<> (C++23 起)
basic_stacktrace<> (C++23 起)
basic_streambuf<>
basic_string<>
basic_string_view<> (C++17 起)
basic_stringbuf<>
basic_stringstream<>
basic_syncbuf<> (C++20 起)
begin<>() (C++11 起) (iterator)
bernoulli_distribution<> (C++11 起)
beta() (C++17 起)
betaf() (C++17 起)
betal() (C++17 起)
bidirectional_iterator<> (C++20 起)
bidirectional_iterator_tag
binary_search<>()
binary_semaphore (C++20 起)
bind<>() (C++11 起)
bind_front<>() (C++20 起)
binomial_distribution<> (C++11 起)
bit_and<>
bit_cast<>() (C++20 起)
bit_ceil<>() (C++20 起)
bit_floor<>() (C++20 起)
bit_not<> (C++14 起)
bit_or<>
bit_width<>() (C++20 起)
bit_xor<>
bitset<>
bool_constant<> (C++17 起)
boolalpha()
boyer_moore_horspool_searcher<> (C++17 起)
boyer_moore_searcher<> (C++17 起)
bsearch()
btowc()
byte (C++17 起)
byteswap<>() (C++23 起)

C

c16rtomb() (C++11 起)
c32rtomb() (C++11 起)
c8rtomb() (C++20 起)
call_once<>() (C++11 起)
calloc()
cauchy_distribution<> (C++11 起)
cbegin<>() (C++14 起)
cbrt() (C++11 起)
cbrtf() (C++11 起)
cbrtl() (C++11 起)
ceil()
ceilf() (C++11 起)
ceill() (C++11 起)
cend<>() (C++14 起)
centi (C++11 起)
cerr
char_traits<>
chars_format (C++17 起)
chi_squared_distribution<> (C++11 起)
▶ chrono (C++11 起)
▶ chrono_literals (C++14 起)
cin
clamp<>() (C++17 起)
clearerr()
clock()
clock_t
clog
cmatch (C++11 起)
cmp_equal<>() (C++20 起)
cmp_greater<>() (C++20 起)
cmp_greater_equal<>() (C++20 起)
cmp_less<>() (C++20 起)
cmp_less_equal<>() (C++20 起)
cmp_not_equal<>() (C++20 起)
codecvt<>
codecvt_base
codecvt_byname<>
codecvt_mode (C++11 起)(C++17 中弃用)
codecvt_utf16<> (C++11 起)(C++17 中弃用)
codecvt_utf8<> (C++11 起)(C++17 中弃用)
codecvt_utf8_utf16<> (C++11 起)(C++17 中弃用)
collate<>
collate_byname<>
common_comparison_category<> (C++20 起)
common_comparison_category_t<> (C++20 起)
common_iterator<> (C++20 起)
common_reference<> (C++20 起)
common_reference_t<> (C++20 起)
common_reference_with<> (C++20 起)
common_type<> (C++11 起)
common_type_t<> (C++14 起)
common_with (C++20 起)
comp_ellint_1() (C++17 起)
comp_ellint_1f() (C++17 起)
comp_ellint_1l() (C++17 起)
comp_ellint_2() (C++17 起)
comp_ellint_2f() (C++17 起)
comp_ellint_2l() (C++17 起)
comp_ellint_3() (C++17 起)
comp_ellint_3f() (C++17 起)
comp_ellint_3l() (C++17 起)
compare_partial_order_fallback (C++20 起)
compare_strong_order_fallback (C++20 起)
compare_three_way (C++20 起)
compare_three_way_result<> (C++20 起)
compare_three_way_result_t<> (C++20 起)
compare_weak_order_fallback (C++20 起)
complex<>
▶ complex_literals (C++14 起)
conditional<> (C++11 起)
conditional_t<> (C++14 起)
condition_variable (C++11 起)
condition_variable_any (C++11 起)
conjunction<> (C++17 起)
conjunction_v<> (C++17 起)
conj<>()
construct_at<>() (C++20 起)
constructible_from<> (C++20 起)
consume_header (C++11 起)(C++17 中弃用)
contiguous_iterator<> (C++20 起)
contiguous_iterator_tag (C++20 起)
convertible_to (C++20 起)
copy<>()
copy_backward<>()
copy_constructible (C++20 起)
copy_if<>() (C++11 起)
copy_n<>() (C++11 起)
copyable<> (C++20 起)
copysign() (C++11 起)
copysignf() (C++11 起)
copysignl() (C++11 起)
const_pointer_cast<>() (C++11 起)
coroutine_handle<> (C++20 起)
coroutine_traits<> (C++20 起)
cos()
cos<>() (std::complex)
cos<>() (std::valarray)
cosf() (C++11 起)
cosh()
cosh<>() (std::complex)
cosh<>() (std::valarray)
coshf() (C++11 起)
coshl() (C++11 起)
cosl() (C++11 起)
count<>()
count_if<>()
counted_iterator<> (C++20 起)
counting_semaphore<> (C++20 起)
countl_one<>() (C++20 起)
countl_zero<>() (C++20 起)
countr_one<>() (C++20 起)
countr_zero<>() (C++20 起)
cout
crbegin<>() (C++14 起)
cref<>() (C++11 起)
cregex_iterator (C++11 起)
cregex_token_iterator (C++11 起)
crend<>() (C++14 起)
csub_match (C++11 起)
ctime()
ctype<>
ctype<> (char)
ctype_base
ctype_byname<>
current_exception() (C++11 起)
cv_status (C++11 起)
cyl_bessel_i() (C++17 起)
cyl_bessel_if() (C++17 起)
cyl_bessel_il() (C++17 起)
cyl_bessel_j() (C++17 起)
cyl_bessel_jf() (C++17 起)
cyl_bessel_jl() (C++17 起)
cyl_bessel_k() (C++17 起)
cyl_bessel_kf() (C++17 起)
cyl_bessel_kl() (C++17 起)
cyl_neumann() (C++17 起)
cyl_neumannf() (C++17 起)
cyl_neumannl() (C++17 起)

D

data<>() (C++17 起)
dec()
deca (C++11 起)
decay<> (C++11 起)
decay_t<> (C++14 起)
deci (C++11 起)
declval<>() (C++11 起)
default_delete (C++11 起)
default_initializable<> (C++20 起)
default_random_engine (C++11 起)
default_searcher<> (C++17 起)
default_sentinel (C++20 起)
default_sentinel_t (C++20 起)
defaultfloat() (C++11 起)
defer_lock (C++11 起)
defer_lock_t (C++11 起)
denorm_absent
denorm_indeterminate
denorm_present
deque<>
derived_from<> (C++20 起)
destroy<>() (C++17 起)
destroy_at<>() (C++17 起)
destroy_n<>() (C++17 起)
destroying_delete (C++20 起)
destroying_delete_t (C++20 起)
destructble (C++20 起)
difftime()
disable_sized_sentinel_for<> (C++20 起)
discrete_distribution<> (C++11 起)
discard_block_engine<> (C++11 起)
disjunction<> (C++17 起)
disjunction_v<> (C++17 起)
distance<>()
div()
div_t
divides<>
domain_error
double_t (C++11 起)
dynamic_extent (C++20 起)
dynamic_pointer_cast<>() (C++11 起)

E

ellint_1() (C++17 起)
ellint_1f() (C++17 起)
ellint_1l() (C++17 起)
ellint_2() (C++17 起)
ellint_2f() (C++17 起)
ellint_2l() (C++17 起)
ellint_3() (C++17 起)
ellint_3f() (C++17 起)
ellint_3l() (C++17 起)
emit_on_flush<>() (C++20 起)
empty<>() (C++17 起)
enable_if<> (C++11 起)
enable_if_t<> (C++14 起)
enable_shared_from_this<> (C++11 起)
end<>() (C++11 起) (iterator)
endian (C++20 起)
endl<>()
ends<>()
equal<>()
equal_range<>()
equal_to<>
equality_comparable<> (C++20 起)
equality_comparable_with<> (C++20 起)
equivalence_relation<> (C++20 起)
erase<>() (C++20 起)
erase_if<>() (C++20 起)
erf() (C++11 起)
erfc() (C++11 起)
erfcf() (C++11 起)
erfcl() (C++11 起)
erff() (C++11 起)
erfl() (C++11 起)
errc (C++11 起)
error_category (C++11 起)
error_code (C++11 起)
error_condition (C++11 起)
exa (C++11 起)
exception
exception_ptr (C++11 起)
exchange<>() (C++14 起)
exclusive_scan<>() (C++17 起)
▶ execution (C++17 起)
exit()
exp()
exp<>() (std::complex)
exp<>() (std::valarray)
exp2() (C++11 起)
exp2f() (C++11 起)
exp2l() (C++11 起)
expf() (C++11 起)
expint() (C++17 起)
expintf() (C++17 起)
expintl() (C++17 起)
expl() (C++11 起)
expm1() (C++11 起)
expm1f() (C++11 起)
expm1l() (C++11 起)
exponential_distribution<> (C++11 起)
extent<> (C++11 起)
extent_v<> (C++17 起)
extreme_value_distribution<> (C++11 起)

F

fabs()
fabsf() (C++11 起)
fabsl() (C++11 起)
false_type (C++11 起)
fclose()
fdim() (C++11 起)
fdimf() (C++11 起)
fdiml() (C++11 起)
feclearexcept() (C++11 起)
fegetenv() (C++11 起)
fegetexceptflag() (C++11 起)
fegetround() (C++11 起)
feholdexcept() (C++11 起)
femto (C++11 起)
fenv_t (C++11 起)
feof()
feraiseexcept() (C++11 起)
ferror()
fesetenv() (C++11 起)
fesetexceptflag() (C++11 起)
fesetround() (C++11 起)
fetestexcept() (C++11 起)
feupdateenv() (C++11 起)
fexcept_t (C++11 起)
fflush()
fgetc()
fgetpos()
fgets()
fgetwc()
fgetws()
FILE
filebuf
▶ filesystem (C++17 起)
fill<>()
fill_n<>()
find<>()
find_end<>()
find_first_of<>()
find_if<>()
find_if_not<>() (C++11 起)
fisher_f_distribution<> (C++11 起)
fixed()
float_denorm_style
float_round_style
float_t (C++11 起)
floating_point<> (C++20 起)
floor()
floorf() (C++11 起)
floorl() (C++11 起)
flush<>()
flush_emit<>() (C++20 起)
fma() (C++11 起)
fmaf() (C++11 起)
fmal() (C++11 起)
fmax() (C++11 起)
fmaxf() (C++11 起)
fmaxl() (C++11 起)
fmin() (C++11 起)
fminf() (C++11 起)
fminl() (C++11 起)
fmod()
fmodf() (C++11 起)
fmodl() (C++11 起)
fopen()
for_each<>()
for_each_n<>() (C++17 起)
format<>() (C++20 起)
format_args (C++20 起)
format_context (C++20 起)
format_error() (C++20 起)
format_parse_context (C++20 起)
format_to<>() (C++20 起)
format_to_n<>() (C++20 起)
format_to_n_result<> (C++20 起)
formatted_size<>() (C++20 起)
formatter<> (C++20 起)
forward<>() (C++11 起)
forward_as_tuple<>() (C++11 起)
forward_iterator<> (C++20 起)
forward_iterator_tag
forward_list<> (C++11 起)
fpclassify() (C++11 起)
fpos<>
fpos_t
fprintf()
fputc()
fputs()
fputwc()
fputws()
fread()
free()
freopen()
frexp()
frexpf() (C++11 起)
frexpl() (C++11 起)
from_chars() (C++17 起)
from_chars_result (C++17 起)
front_insert_iterator<>
front_inserter<>()
fscanf()
fseek()
fsetpos()
fstream
ftell()
function<> (C++11 起)
future<> (C++11 起)
future_category() (C++11 起)
future_errc (C++11 起)
future_error (C++11 起)
future_status (C++11 起)
fwide()
fwprintf()
fwrite()
fwscanf()

G

gamma_distribution<> (C++11 起)
gcd<>() (C++17 起)
generate<>()
generate_canonical<> (C++11 起)
generate_header (C++11 起)(C++17 中弃用)
generate_n<>()
generic_category() (C++11 起)
geometric_distribution<> (C++11 起)
get<>() (std::array) (C++11 起)
get<>() (std::pair) (C++11 起)
get<>() (std::ranges::subrange) (C++20 起)
get<>() (std::tuple) (C++11 起)
get<>() (std::variant) (C++17 起)
get_deleter<>() (C++11 起)
get_if<>() (C++17 起)
get_money<>() (C++11 起)
get_new_handler() (C++11 起)
get_terminate() (C++11 起)
get_time<>() (C++11 起)
getline<>()
getc()
getchar()
getenv()
getwc()
getwchar()
giga (C++11 起)
gmtime()
greater<>
greater_equal<>
gslice
gslice_array<>

H

hardware_constructive_interference_size (C++17 起)
hardware_destructive_interference_size (C++17 起)
has_facet<>()
has_single_bit<>() (C++20 起)
has_unique_object_representations<> (C++17 起)
has_unique_object_representations_v<> (C++17 起)
has_virtual_destructor<> (C++11 起)
has_virtual_destructor_v<> (C++17 起)
hash<> (C++11 起)
hecto (C++11 起)
hermite() (C++17 起)
hermitef() (C++17 起)
hermitel() (C++17 起)
hex()
hexfloat() (C++11 起)
holds_alternative<>() (C++17 起)
hypot() (C++11 起)
hypotf() (C++11 起)
hypotl() (C++11 起)

I

identity (C++20 起)
ifstream
ignore (C++11 起)
ilogb() (C++11 起)
ilogbf() (C++11 起)
ilogbl() (C++11 起)
imag<>()
imaxabs() (C++11 起)
imaxdiv() (C++11 起)
imaxdiv_t (C++11 起)
in_place (C++17 起)
in_place_index<> (C++17 起)
in_place_index_t<> (C++17 起)
in_place_t (C++17 起)
in_place_type<> (C++17 起)
in_place_type_t<> (C++17 起)
in_range<>() (C++20 起)
includes<>()
inclusive_scan<>() (C++17 起)
incrementable<> (C++20 起)
incrementable_traits<> (C++20 起)
independent_bits_engine<> (C++11 起)
indirect_array<>
indirect_binary_predicate<> (C++20 起)
indirect_equivalence_relation<> (C++20 起)
indirect_result_t<> (C++20 起)
indirect_strict_weak_order<> (C++20 起)
indirect_unary_predicate<> (C++20 起)
indirectly_comparable<> (C++20 起)
indirectly_copyable<> (C++20 起)
indirectly_copyable_storable<> (C++20 起)
indirectly_movable<> (C++20 起)
indirectly_movable_storable<> (C++20 起)
indirectly_readable<> (C++20 起)
indirectly_readable_traits<> (C++20 起)
indirectly_regular_unary_invocable<> (C++20 起)
indirectly_swappable<> (C++20 起)
indirectly_unary_invocable<> (C++20 起)
indirectly_writable<> (C++20 起)
initializer_list<> (C++11 起)
inner_product<>()
inout_ptr<>() (C++23 起)
inout_ptr_t<> (C++23 起)
inplace_merge<>()
input_iterator<> (C++20 起)
input_iterator_tag
input_or_output_iterator<> (C++20 起)
insert_iterator<>
inserter<>()
int_fast16_t (C++11 起)
int_fast32_t (C++11 起)
int_fast64_t (C++11 起)
int_fast8_t (C++11 起)
int_least16_t (C++11 起)
int_least32_t (C++11 起)
int_least64_t (C++11 起)
int_least8_t (C++11 起)
int16_t (C++11 起)
int32_t (C++11 起)
int64_t (C++11 起)
int8_t (C++11 起)
integer_sequence<> (C++14 起)
integral<> (C++20 起)
integral_constant<> (C++11 起)
internal()
intmax_t (C++11 起)
intptr_t (C++11 起)
invalid_argument
invocable<> (C++20 起)
invoke<>() (C++17 起)
invoke_r<>() (C++23 起)
invoke_result<> (C++17 起)
invoke_result_t<> (C++17 起)
io_errc (C++11 起)
ios
ios_base
iostream
iostream_category (C++11 起)
iota<>() (C++11 起)
is_abstract<> (C++11 起)
is_abstract_v<> (C++17 起)
is_aggregate<> (C++17 起)
is_aggregate_v<> (C++17 起)
is_arithmetic<> (C++11 起)
is_arithmetic_v<> (C++17 起)
is_array<> (C++11 起)
is_array_v<> (C++17 起)
is_assignable<> (C++11 起)
is_assignable_v<> (C++17 起)
is_base_of<> (C++11 起)
is_base_of_v<> (C++17 起)
is_bind_expression<> (C++11 起)
is_bind_expression_v<> (C++17 起)
is_bounded_array<> (C++20 起)
is_bounded_array_v<> (C++20 起)
is_class<> (C++11 起)
is_class_v<> (C++17 起)
is_compound<> (C++11 起)
is_compound_v<> (C++17 起)
is_const<> (C++11 起)
is_const_v<> (C++17 起)
is_constant_evaluated() (C++20 起)
is_constructible<> (C++11 起)
is_constructible_v<> (C++17 起)
is_convertible<> (C++11 起)
is_convertible_v<> (C++17 起)
is_copy_assignable<> (C++11 起)
is_copy_assignable_v<> (C++17 起)
is_copy_constructible<> (C++11 起)
is_copy_constructible_v<> (C++17 起)
is_corresponding_member<>() (C++20 起)
is_default_constructible<> (C++11 起)
is_default_constructible_v<> (C++17 起)
is_destructible<> (C++11 起)
is_destructible_v<> (C++17 起)
is_empty<> (C++11 起)
is_empty_v<> (C++17 起)
is_enum<> (C++11 起)
is_enum_v<> (C++17 起)
is_eq() (C++20 起)
is_error_code_enum<>() (C++11 起)
is_error_condition_enum (C++11 起)
is_error_condition_enum_v (C++17 起)
is_execution_policy<> (C++17 起)
is_execution_policy_v<> (C++17 起)
is_final<> (C++14 起)
is_final_v<> (C++17 起)
is_floating_point<> (C++11 起)
is_floating_point_v<> (C++17 起)
is_function<> (C++11 起)
is_function_v<> (C++17 起)
is_fundamental<> (C++11 起)
is_fundamental_v<> (C++17 起)
is_gt() (C++20 起)
is_gteq() (C++20 起)
is_heap<>() (C++11 起)
is_heap_until<>() (C++11 起)
is_integral<> (C++11 起)
is_integral_v<> (C++17 起)
is_invocable<> (C++17 起)
is_invocable_r<> (C++17 起)
is_invocable_r_v<> (C++17 起)
is_invocable_v<> (C++17 起)
is_layout_compatible<> (C++20 起)
is_layout_compatible_v<> (C++20 起)
is_lt() (C++20 起)
is_lteq() (C++20 起)
is_lvalue_reference<> (C++11 起)
is_lvalue_reference_v<> (C++17 起)
is_member_function_pointer<> (C++11 起)
is_member_function_pointer_v<> (C++17 起)
is_member_object_pointer<> (C++11 起)
is_member_object_pointer_v<> (C++17 起)
is_member_pointer<> (C++11 起)
is_member_pointer_v<> (C++17 起)
is_move_assignable<> (C++11 起)
is_move_assignable_v<> (C++17 起)
is_move_constructible<> (C++11 起)
is_move_constructible_v<> (C++17 起)
is_neq() (C++20 起)
is_nothrow_assignable<> (C++11 起)
is_nothrow_assignable_v<> (C++17 起)
is_nothrow_constructible<> (C++11 起)
is_nothrow_constructible_v<> (C++17 起)
is_nothrow_convertible<> (C++20 起)
is_nothrow_convertible_v<> (C++20 起)
is_nothrow_copy_assignable<> (C++11 起)
is_nothrow_copy_assignable_v<> (C++17 起)
is_nothrow_copy_constructible<> (C++11 起)
is_nothrow_copy_constructible_v<> (C++17 起)
is_nothrow_default_constructible<> (C++11 起)
is_nothrow_default_constructible_v<> (C++17 起)
is_nothrow_destructible<> (C++11 起)
is_nothrow_destructible_v<> (C++17 起)
is_nothrow_invocable<> (C++17 起)
is_nothrow_invocable_r<> (C++17 起)
is_nothrow_invocable_r_v<> (C++17 起)
is_nothrow_invocable_v<> (C++17 起)
is_nothrow_move_assignable<> (C++11 起)
is_nothrow_move_assignable_v<> (C++17 起)
is_nothrow_move_constructible<> (C++11 起)
is_nothrow_move_constructible_v<> (C++17 起)
is_nothrow_swappable<> (C++17 起)
is_nothrow_swappable_v<> (C++17 起)
is_nothrow_swappable_with<> (C++17 起)
is_nothrow_swappable_with_v<> (C++17 起)
is_null_pointer<> (C++11 起)
is_null_pointer_v<> (C++17 起)
is_object<> (C++11 起)
is_object_v<> (C++17 起)
is_partitioned<>() (C++11 起)
is_permutation<>() (C++11 起)
is_placeholder<> (C++11 起)
is_placeholder_v<> (C++17 起)
is_pod<> (C++11 起)(C++20 中弃用)
is_pod_v<> (C++17 起)(C++20 中弃用)
is_pointer<> (C++11 起)
is_pointer_v<> (C++17 起)
is_pointer_interconvertible_base_of<> (C++20 起)
is_pointer_interconvertible_base_of_v<> (C++20 起)
is_pointer_interconvertible_with_class<>() (C++20 起)
is_polymorphic<> (C++11 起)
is_polymorphic_v<> (C++17 起)
is_reference<> (C++11 起)
is_reference_v<> (C++17 起)
is_rvalue_reference<> (C++11 起)
is_rvalue_reference_v<> (C++17 起)
is_same<> (C++11 起)
is_same_v<> (C++17 起)
is_scalar<> (C++11 起)
is_scalar_v<> (C++17 起)
is_scoped_enum<> (C++23 起)
is_scoped_enum_v<> (C++23 起)
is_signed<> (C++11 起)
is_signed_v<> (C++17 起)
is_sorted<>() (C++11 起)
is_sorted_until<>() (C++11 起)
is_standard_layout<> (C++11 起)
is_standard_layout_v<> (C++17 起)
is_swappable<> (C++17 起)
is_swappable_v<> (C++17 起)
is_swappable_with<> (C++17 起)
is_swappable_with_v<> (C++17 起)
is_trivial<> (C++11 起)
is_trivial_v<> (C++17 起)
is_trivially_assignable<> (C++11 起)
is_trivially_assignable_v<> (C++17 起)
is_trivially_constructible<> (C++11 起)
is_trivially_constructible_v<> (C++17 起)
is_trivially_copyable<> (C++11 起)
is_trivially_copyable_v<> (C++17 起)
is_trivially_copy_assignable<> (C++11 起)
is_trivially_copy_assignable_v<> (C++17 起)
is_trivially_copy_constructible<> (C++11 起)
is_trivially_copy_constructible_v<> (C++17 起)
is_trivially_default_constructible<> (C++11 起)
is_trivially_default_constructible_v<> (C++17 起)
is_trivially_destructible<> (C++11 起)
is_trivially_destructible_v<> (C++17 起)
is_trivially_move_assignable<> (C++11 起)
is_trivially_move_assignable_v<> (C++17 起)
is_trivially_move_constructible<> (C++11 起)
is_trivially_move_constructible_v<> (C++17 起)
is_unbounded_array<> (C++20 起)
is_unbounded_array_v<> (C++20 起)
is_union<> (C++11 起)
is_union_v<> (C++17 起)
is_unsigned<> (C++11 起)
is_unsigned_v<> (C++17 起)
is_void<> (C++11 起)
is_void_v<> (C++17 起)
is_volatile<> (C++11 起)
is_volatile_v<> (C++17 起)
isalnum()
isalnum<>() (locale)
isalpha()
isalpha<>() (locale)
isblank() (C++11 起)
isblank<>() (locale) (C++11 起)
iscntrl()
iscntrl<>() (locale)
isdigit()
isdigit<>() (locale)
isfinite() (C++11 起)
isgraph()
isgraph<>() (locale)
isgreater() (C++11 起)
isgreaterequal() (C++11 起)
isinf() (C++11 起)
isless() (C++11 起)
islessequal() (C++11 起)
islessgreater() (C++11 起)
islower()
islower<>() (locale)
isnan() (C++11 起)
isnormal() (C++11 起)
ispanstream (C++23 起)
isprint()
isprint<>() (locale)
ispunct()
ispunct<>() (locale)
isspace()
isspace<>() (locale)
istream
istreambuf_iterator<>
istream_iterator<>
istringstream
istrstream (C++98 中弃用)
isunordered() (C++11 起)
isupper()
isupper<>() (locale)
iswalnum()
iswalpha()
iswblank() (C++11 起)
iswcntrl()
iswctype()
iswdigit()
iswgraph()
iswlower()
iswprint()
iswpunct()
iswspace()
iswupper()
iswxdigit()
isxdigit()
isxdigit<>() (locale)
iter_common_reference_t<> (C++20 起)
iter_difference_t<> (C++20 起)
iter_reference_t<> (C++20 起)
iter_rvalue_reference_t<> (C++20 起)
iter_swap<>()
iter_value_t<> (C++20 起)
iterator<> (C++17 中弃用)
iterator_traits<>

J

jmp_buf
jthread (C++20 起)

K

kill_dependency<>() (C++11 起)
kilo (C++11 起)
knuth_b (C++11 起)

L

labs()
laguerre() (C++17 起)
laguerref() (C++17 起)
laguerrel() (C++17 起)
latch (C++20 起)
launch (C++11 起)
launder<>() (C++17 起)
lcm<>() (C++17 起)
lconv
ldexp()
ldexpf() (C++11 起)
ldexpl() (C++11 起)
ldiv()
ldiv_t
left()
legendre() (C++17 起)
legendref() (C++17 起)
legendrel() (C++17 起)
length_error
lerp() (C++20 起)
less<>
less_equal<>
lexicographical_compare<>()
lexicographical_compare_three_way<>() (C++20 起)
lgamma() (C++11 起)
lgammaf() (C++11 起)
lgammal() (C++11 起)
linear_congruential_engine<> (C++11 起)
list<>
▶ literals (C++14 起)
little_endian (C++11 起)(C++17 中弃用)
llabs() (C++11 起)
lldiv() (C++11 起)
lldiv_t (C++11 起)
llrint() (C++11 起)
llrintf() (C++11 起)
llrintl() (C++11 起)
llround() (C++11 起)
llroundf() (C++11 起)
llroundl() (C++11 起)
locale
localeconv()
localtime()
lock<>() (C++11 起)
lock_guard<> (C++11 起)
log()
log<>() (std::complex)
log<>() (std::valarray)
log10()
log10<>() (std::complex)
log10<>() (std::valarray)
log10f() (C++11 起)
log10l() (C++11 起)
log1p() (C++11 起)
log1pf() (C++11 起)
log1pl() (C++11 起)
log2() (C++11 起)
log2f() (C++11 起)
log2l() (C++11 起)
logb() (C++11 起)
logbf() (C++11 起)
logbl() (C++11 起)
logf() (C++11 起)
logic_error
logical_and<>
logical_not<>
logical_or<>
logl() (C++11 起)
lognormal_distribution<> (C++11 起)
longjmp()
lower_bound<>()
lrint() (C++11 起)
lrintf() (C++11 起)
lrintl() (C++11 起)
lround() (C++11 起)
lroundf() (C++11 起)
lroundl() (C++11 起)

M

make_any<>() (C++17 起)
make_error_code (std::errc) (C++11 起)
make_error_code (std::io_errc) (C++11 起)
make_error_condition (std::errc) (C++11 起)
make_error_condition (std::io_errc) (C++11 起)
make_exception_ptr<>() (C++11 起)
make_format_args<>() (C++20 起)
make_from_tuple<>() (C++17 起)
make_heap<>()
make_move_iterator<>() (C++11 起)
make_obj_using_allocator<>() (C++20 起)
make_optional<>() (C++17 起)
make_pair<>
make_reverse_iterator<>() (C++14 起)
make_shared<>() (C++11 起)
make_shared_for_overwrite<>() (C++20 起)
make_signed<> (C++11 起)
make_signed_t<> (C++14 起)
make_tuple<>() (C++11 起)
make_unique<>() (C++14 起)
make_unique_for_overwrite<>() (C++20 起)
make_unsigned<> (C++11 起)
make_unsigned_t<> (C++14 起)
make_wformat_args<>() (C++20 起)
malloc()
map<>
mask_array<>
match_results<> (C++11 起)
max<>()
max_align_t (C++11 起)
max_element<>()
mblen()
mbrlen()
mbrtoc16() (C++11 起)
mbrtoc32() (C++11 起)
mbrtoc8() (C++20 起)
mbrtowc()
mbsinit()
mbsrtowcs()
mbstate_t
mbstowcs()
mbtowc()
mega (C++11 起)
mem_fn<>() (C++11 起)
memchr()
memcmp()
memcpy()
memmove()
memory_order (C++11 起)
memory_order_acq_rel (C++11 起)
memory_order_acquire (C++11 起)
memory_order_consume (C++11 起)
memory_order_relaxed (C++11 起)
memory_order_release (C++11 起)
memory_order_seq_cst (C++11 起)
memset()
merge<>()
mergeable<> (C++20 起)
mersenne_twister_engine<> (C++11 起)
messages<>
messages_base
messages_byname<>
micro (C++11 起)
midpoint<>() (C++20 起)
milli (C++11 起)
min<>()
min_element<>()
minmax<>() (C++11 起)
minmax_element<>() (C++11 起)
minstd_rand (C++11 起)
minstd_rand0 (C++11 起)
minus<>
mismatch<>()
mktime()
modf()
modff() (C++11 起)
modfl() (C++11 起)
modulus<>
money_base
money_get<>
moneypunct<>
moneypunct_byname<>
money_put<>
monostate (C++17 起)
movable<> (C++20 起)
move<>() (algorithm) (C++11 起)
move<>() (utility) (C++11 起)
move_backward<>() (C++11 起)
move_constructible<> (C++20 起)
move_if_noexcept<>() (C++11 起)
move_iterator<> (C++11 起)
move_only_function<> (C++23 起)
move_sentinel<> (C++20 起)
mt19937 (C++11 起)
mt19937_64 (C++11 起)
multimap<>
multiplies<>
multiset<>
mutex (C++11 起)

N

nan() (C++11 起)
nanf() (C++11 起)
nanl() (C++11 起)
nano (C++11 起)
nearbyint() (C++11 起)
nearbyintf() (C++11 起)
nearbyintl() (C++11 起)
negate<>
negation<> (C++17 起)
negation_v<> (C++17 起)
negative_binomial_distribution<> (C++11 起)
nested_exception (C++11 起)
new_handler
next<>() (C++11 起)
next_permutation<>()
nextafter() (C++11 起)
nextafterf() (C++11 起)
nextafterl() (C++11 起)
nexttoward() (C++11 起)
nexttowardf() (C++11 起)
nexttowardl() (C++11 起)
noemit_on_flush<>() (C++20 起)
noboolalpha()
none_of<>() (C++11 起)
noop_coroutine() (C++20 起)
noop_coroutine_handle (C++20 起)
noop_coroutine_promise (C++20 起)
norm<>()
normal_distribution<> (C++11 起)
noshowbase()
noshowpoint()
noshowpos()
noskipws()
nostopstate (C++20 起)
nostopstate_t (C++20 起)
not_equal_to<>
not_fn<>() (C++17 起)
nothrow
nothrow_t
notify_all_at_thread_exit() (C++11 起)
nounitbuf()
nouppercase()
nth_element<>()
nullopt (C++17 起)
nullopt_t (C++17 起)
nullptr_t (C++11 起)
numeric_limits<>
num_get<>
▶ numbers (C++20 起)
numpunct<>
numpunct_byname<>
num_put<>

O

oct()
once_flag (C++11 起)
ofstream
optional<> (C++17 起)
ospanstream (C++23 起)
ostream
ostreambuf_iterator<>
ostream_iterator<>
ostringstream
ostrstream (C++98 中弃用)
osyncstream (C++20 起)
out_of_range
out_ptr<>() (C++23 起)
out_ptr_t<> (C++23 起)
output_iterator<> (C++20 起)
output_iterator_tag
overflow_error
owner_less<> (C++11 起)

P

packaged_task<> (C++11 起)
pair<>
partial_order (C++20 起)
partial_ordering (C++20 起)
partial_sort<>()
partial_sort_copy<>()
partial_sum<>()
partition<>()
partition_copy<>() (C++11 起)
partition_point<>() (C++11 起)
permutable<> (C++20 起)
perror()
peta (C++11 起)
pico (C++11 起)
piecewise_constant_distribution<> (C++11 起)
piecewise_construct (C++11 起)
piecewise_construct_t (C++11 起)
piecewise_linear_distribution<> (C++11 起)
▶ placeholders (C++11 起)
plus<>
▶ pmr (C++17 起)
pointer_traits<> (C++11 起)
poisson_distribution<> (C++11 起)
polymorphic_allocator<> (C++17 起)
polar<>()
pop_heap<>()
popcount<>() (C++20 起)
pow()
pow<>() (std::complex)
pow<>() (std::valarray)
powf() (C++11 起)
powl() (C++11 起)
predicate<> (C++20 起)
prev<>() (C++11 起)
prev_permutation<>()
printf()
priority_queue<>
proj<>() (C++11 起)
projected<> (C++20 起)
promise<> (C++11 起)
ptrdiff_t
push_heap<>()
put_money<>() (C++11 起)
put_time<>() (C++11 起)
putc()
putchar()
puts()
putwc()
putwchar()

Q

qsort()
queue<>
quick_exit() (C++11 起)
quoted<>() (C++14 起)

R

raise()
rand()
random_access_iterator<> (C++20 起)
random_access_iterator_tag
random_device (C++11 起)
range_error
▶ ranges (C++20 起)
ranlux24 (C++11 起)
ranlux24_base (C++11 起)
ranlux48 (C++11 起)
ranlux48_base (C++11 起)
rank<> (C++11 起)
rank_v<> (C++17 起)
ratio (C++11 起)
ratio_add<> (C++11 起)
ratio_divide<> (C++11 起)
ratio_equal<> (C++11 起)
ratio_equal_v<> (C++17 起)
ratio_greater<> (C++11 起)
ratio_greater_equal<> (C++11 起)
ratio_greater_equal_v<> (C++17 起)
ratio_greater_v<> (C++17 起)
ratio_less<> (C++11 起)
ratio_less_equal<> (C++11 起)
ratio_less_equal_v<> (C++17 起)
ratio_less_v<> (C++17 起)
ratio_multiply<> (C++11 起)
ratio_not_equal<> (C++11 起)
ratio_not_equal_v<> (C++17 起)
ratio_subtract<> (C++11 起)
rbegin<>() (C++14 起)
real<>()
realloc()
recursive_mutex (C++11 起)
recursive_timed_mutex (C++11 起)
reduce<>() (C++17 起)
ref<>() (C++11 起)
reference_wrapper<> (C++11 起)
regex (C++11 起)
▶ regex_constants (C++11 起)
regex_error (C++11 起)
regex_iterator<> (C++11 起)
regex_match<> (C++11 起)
regex_replace<> (C++11 起)
regex_search<> (C++11 起)
regex_token_iterator<> (C++11 起)
regex_traits<> (C++11 起)
regular<> (C++20 起)
regular_invocable<> (C++20 起)
reinterpret_pointer_cast<>() (C++11 起)
▶ rel_ops (C++20 中弃用)
relation<> (C++20 起)
remainder() (C++11 起)
remainderf() (C++11 起)
remainderl() (C++11 起)
remove()
remove<>() (algorithm)
remove_if<>()
remove_all_extents<> (C++11 起)
remove_all_extents_t<> (C++14 起)
remove_const<> (C++11 起)
remove_const_t<> (C++14 起)
remove_copy<>()
remove_copy_if<>()
remove_cv<> (C++11 起)
remove_cv_t<> (C++14 起)
remove_cvref<> (C++20 起)
remove_cvref_t<> (C++20 起)
remove_extent<> (C++11 起)
remove_extent_t<> (C++14 起)
remove_pointer<> (C++11 起)
remove_pointer_t<> (C++14 起)
remove_reference<> (C++11 起)
remove_reference_t<> (C++14 起)
remove_volatile<> (C++11 起)
remove_volatile_t<> (C++14 起)
remquo() (C++11 起)
remquof() (C++11 起)
remquol() (C++11 起)
rend<>() (C++14 起)
rename()
replace<>()
replace_copy<>()
replace_copy_if<>()
replace_if<>()
resetiosflags()
rethrow_exception() (C++11 起)
rethrow_if_nested<>() (C++11 起)
reverse<>()
reverse_copy<>()
reverse_iterator<>
rewind()
riemann_zeta() (C++17 起)
riemann_zetaf() (C++17 起)
riemann_zetal() (C++17 起)
right()
rint() (C++11 起)
rintf() (C++11 起)
rintl() (C++11 起)
rotate<>()
rotate_copy<>()
rotl<>() (C++20 起)
rotr<>() (C++20 起)
round() (C++11 起)
roundf() (C++11 起)
roundl() (C++11 起)
round_indeterminate
round_to_nearest
round_toward_infinity
round_toward_neg_infinity
round_toward_zero
runtime_error

S

same_as<> (C++20 起)
sample<>() (C++17 起)
scalbln() (C++11 起)
scalblnf() (C++11 起)
scalblnl() (C++11 起)
scalbn() (C++11 起)
scalbnf() (C++11 起)
scalbnl() (C++11 起)
scanf()
scientific()
scoped_allocator_adaptor<> (C++11 起)
scoped_lock (C++17 起)
search<>()
search_n<>()
seed_seq (C++11 起)
semiregular<> (C++20 起)
sentinel_for<> (C++20 起)
set<>
set_difference<>()
set_intersection<>()
set_new_handler()
set_symmetric_difference<>()
set_terminate()
set_union<>()
setbase()
setbuf()
setfill<>()
setiosflags()
setlocale()
setprecision()
setvbuf()
setw()
shared_future<> (C++11 起)
shared_lock<> (C++14 起)
shared_mutex (C++17 起)
shared_ptr<> (C++11 起)
shared_timed_mutex (C++14 起)
shift_left<>() (C++20 起)
shift_right<>() (C++20 起)
showbase()
showpoint()
showpos()
shuffle<>() (C++11 起)
shuffle_order_engine<> (C++11 起)
sig_atomic_t
signal()
signbit() (C++11 起)
signed_integral<> (C++20 起)
sin()
sin<>() (std::complex)
sin<>() (std::valarray)
sinf() (C++11 起)
sinh()
sinh<>() (std::complex)
sinh<>() (std::valarray)
sinhf() (C++11 起)
sinhl() (C++11 起)
sinl() (C++11 起)
size<>() (C++17 起)
size_t
sized_sentinel_for<> (C++20 起)
skipws()
slice
slice_array<>
smatch (C++11 起)
snprintf() (C++11 起)
sort<>()
sort_heap<>()
sortable<> (C++20 起)
source_location (C++20 起)
span<> (C++20 起)
spanbuf (C++23 起)
spanstream (C++23 起)
sph_bessel() (C++17 起)
sph_besself() (C++17 起)
sph_bessell() (C++17 起)
sph_legendre() (C++17 起)
sph_legendref() (C++17 起)
sph_legendrel() (C++17 起)
sph_neumann() (C++17 起)
sph_neumannf() (C++17 起)
sph_neumannl() (C++17 起)
sprintf()
sqrt()
sqrt<>() (std::complex)
sqrt<>() (std::valarray)
sqrtf() (C++11 起)
sqrtl() (C++11 起)
srand()
sregex_iterator (C++11 起)
sregex_token_iterator (C++11 起)
sscanf()
ssize<>() (C++20 起)
ssub_match (C++11 起)
stable_partition<>()
stable_sort<>()
stack<>
stacktrace (C++23 起)
stacktrace_entry (C++23 起)
static_pointer_cast<>() (C++11 起)
stod() (C++11 起)
stof() (C++11 起)
stoi() (C++11 起)
stol() (C++11 起)
stold() (C++11 起)
stoll() (C++11 起)
stoul() (C++11 起)
stoull() (C++11 起)
stop_callback<> (C++20 起)
stop_source (C++20 起)
stop_token (C++20 起)
strcat()
strchr()
strcmp()
strcoll()
strcpy()
strcspn()
streambuf
streamoff
streampos
streamsize
strerror()
strftime()
strict_weak_order<> (C++20 起)
string
▶ string_literals (C++14 起)
string_view (C++17 起)
▶ string_view_literals (C++17 起)
stringbuf
stringstream
strlen()
strncat()
strncmp()
strncpy()
strong_order (C++20 起)
strong_ordering (C++20 起)
strpbrk()
strrchr()
strspn()
strstr()
strstream (C++98 中弃用)
strstreambuf (C++98 中弃用)
strtod()
strtof() (C++11 起)
strtoimax() (C++11 起)
strtok()
strtol()
strtold()
strtoll() (C++11 起)
strtoul()
strtoull() (C++11 起)
strtoumax() (C++11 起)
strxfrm()
syncbuf (C++20 起)
student_t_distribution<> (C++11 起)
sub_match<> (C++11 起)
subtract_with_carry_engine<> (C++11 起)
suspend_always (C++20 起)
suspend_never (C++20 起)
swap<>()
swap_ranges<>()
swappable<> (C++20 起)
swappable_with<> (C++20 起)
swprintf()
swscanf()
system()
system_category (C++11 起)
system_error (C++11 起)

T

tan()
tan<>() (std::complex)
tan<>() (std::valarray)
tan()
tanf() (C++11 起)
tanh()
tanh<>() (std::complex)
tanh<>() (std::valarray)
tanhf() (C++11 起)
tanhl() (C++11 起)
tanl() (C++11 起)
tera (C++11 起)
terminate()
terminate_handler
tgamma() (C++11 起)
tgammaf() (C++11 起)
tgammal() (C++11 起)
▶ this_thread
thread (C++11 起)
three_way_comparable<> (C++20 起)
three_way_comparable_with<> (C++20 起)
throw_with_nested<>() (C++11 起)
tie<>() (C++11 起)
time()
time_base
time_get<>
time_get_byname<>
time_put<>
time_put_byname<>
time_t
timed_mutex (C++11 起)
timespec (C++17 起)
timespec_get() (C++17 起)
tm
tmpfile()
tmpnam()
to_address<>() (C++20 起)
to_array<>() (C++20 起)
to_chars() (C++17 起)
to_chars_result (C++17 起)
to_integer<>() (C++17 起)
to_string() (C++11 起)
to_wstring() (C++11 起)
tolower()
tolower<>() (locale)
totally_ordered<> (C++20 起)
totally_ordered_with<> (C++20 起)
toupper()
toupper<>() (locale)
to_underlying<>() (C++23 起)
towctrans()
towlower()
towupper()
transform<>()
transform_exclusive_scan<>() (C++17 起)
transform_inclusive_scan<>() (C++17 起)
transform_reduce<>() (C++17 起)
true_type (C++11 起)
trunc() (C++11 起)
truncf() (C++11 起)
truncl() (C++11 起)
try_lock<>() (C++11 起)
try_to_lock (C++11 起)
try_to_lock_t (C++11 起)
tuple<> (C++11 起)
tuple_cat<>() (C++11 起)
tuple_element<> (C++11 起)
tuple_element<> (std::array) (C++11 起)
tuple_element<> (std::pair) (C++11 起)
tuple_element<> (std::ranges::subrange) (C++20 起)
tuple_element<> (std::tuple) (C++11 起)
tuple_element_t<> (C++14 起)
tuple_size<> (C++11 起)
tuple_size<> (std::array) (C++11 起)
tuple_size<> (std::pair) (C++11 起)
tuple_size<> (std::ranges::subrange) (C++20 起)
tuple_size<> (std::tuple) (C++11 起)
tuple_size_v<> (C++17 起)
type_identity<> (C++20 起)
type_identity_t<> (C++20 起)
type_index (C++11 起)
type_info

U

u16streampos (C++11 起)
u16string (C++11 起)
u16string_view (C++17 起)
u32streampos (C++11 起)
u32string (C++11 起)
u32string_view (C++17 起)
u8streampos (C++20 起)
u8string (C++20 起)
u8string_view (C++20 起)
uint_fast16_t (C++11 起)
uint_fast32_t (C++11 起)
uint_fast64_t (C++11 起)
uint_fast8_t (C++11 起)
uint_least16_t (C++11 起)
uint_least32_t (C++11 起)
uint_least64_t (C++11 起)
uint_least8_t (C++11 起)
uint16_t (C++11 起)
uint32_t (C++11 起)
uint64_t (C++11 起)
uint8_t (C++11 起)
uintmax_t (C++11 起)
uintptr_t (C++11 起)
uncaught_exceptions (C++17 起)
underflow_error
underlying_type<> (C++11 起)
underlying_type_t<> (C++14 起)
ungetc()
ungetwc()
uniform_int_distribution<> (C++11 起)
uniform_random_bit_generator<> (C++20 起)
uniform_real_distribution<> (C++11 起)
uninitialized_construct_using_allocator<>() (C++20 起)
uninitialized_copy<>()
uninitialized_copy_n<>() (C++11 起)
uninitialized_default_construct<>() (C++17 起)
uninitialized_default_construct_n<>() (C++17 起)
uninitialized_fill<>()
uninitialized_fill_n<>()
uninitialized_move<>() (C++17 起)
uninitialized_move_n<>() (C++17 起)
uninitialized_value_construct<>() (C++17 起)
uninitialized_value_construct_n<>() (C++17 起)
unique<>()
unique_copy<>()
unique_lock<> (C++11 起)
unique_ptr<> (C++11 起)
unitbuf()
unordered_map<> (C++11 起)
unordered_multimap<> (C++11 起)
unordered_multiset<> (C++11 起)
unordered_set<> (C++11 起)
unreachable_sentinel (C++20 起)
unreachable_sentinel_t (C++20 起)
unsigned_integral<> (C++20 起)
unwrap_ref_decay<> (C++20 起)
unwrap_ref_decay_t<> (C++20 起)
unwrap_reference<> (C++20 起)
unwrap_reference_t<> (C++20 起)
upper_bound<>()
uppercase()
use_facet<>()
uses_allocator<> (C++11 起)
uses_allocator_v<> (C++17 起)
uses_allocator_construction_args<>() (C++20 起)

V

va_list
valarray<>
variant<> (C++17 起)
variant_alternative<> (C++17 起)
variant_alternative_t<> (C++17 起)
variant_npos (C++17 起)
variant_size<> (C++17 起)
variant_size_v<> (C++17 起)
vector<>
vformat() (C++20 起)
vformat_to<>() (C++20 起)
vfprintf()
vfscanf() (C++11 起)
vfwprintf()
vfwscanf() (C++11 起)
▶ views (C++20 起)
visit<>() (C++17 起)
visit_format_arg<>() (C++20 起)
void_t (C++17 起)
vprintf()
vscanf() (C++11 起)
vsnprintf() (C++11 起)
vsprintf()
vsscanf() (C++11 起)
vswprintf()
vswscanf() (C++11 起)
vwprintf()
vwscanf() (C++11 起)

W

wbuffer_convert<> (C++11 起)(C++17 中弃用)
wcerr
wcin
wclog
wcmatch (C++11 起)
wcout
wcregex_iterator (C++11 起)
wcregex_token_iterator (C++11 起)
wcrtomb()
wcscat()
wcschr()
wcscmp()
wcscoll()
wcscpy()
wcscspn()
wcsftime()
wcslen()
wcsncat()
wcsncmp()
wcsncpy()
wcspbrk()
wcsrchr()
wcsrtombs()
wcsspn()
wcsstr()
wcstod()
wcstof() (C++11 起)
wcstoimax() (C++11 起)
wcstok()
wcstol()
wcstold() (C++11 起)
wcstoll() (C++11 起)
wcstombs()
wcstoul()
wcstoull() (C++11 起)
wcstoumax() (C++11 起)
wcsub_match (C++11 起)
wcsxfrm()
wctob()
wctomb()
wctrans()
wctrans_t
wctype()
wctype_t
weak_order (C++20 起)
weak_ordering (C++20 起)
weak_ptr<> (C++11 起)
weakly_incrementable<> (C++20 起)
weibull_distribution<> (C++11 起)
wfilebuf
wformat_args (C++20 起)
wformat_context (C++20 起)
wformat_parse_context (C++20 起)
wfstream
wifstream
wint_t
wios
wiostream
wispanstream (C++23 起)
wistream
wistringstream
wmemchr()
wmemcmp()
wmemcpy()
wmemmove()
wmemset()
wofstream
wospanstream (C++23 起)
wostream
wosyncstream (C++20 起)
ws<>()
wspanbuf (C++23 起)
wspanstream (C++23 起)
wstreambuf
wstreampos
wostringstream
wprintf()
wregex (C++11 起)
wscanf()
wsmatch (C++11 起)
wsregex_iterator (C++11 起)
wsregex_token_iterator (C++11 起)
wssub_match (C++11 起)
wstring
wstring_convert<> (C++11 起)(C++17 中弃用)
wstring_view<> (C++17 起)
wstringbuf
wstringstream
wsyncbuf (C++20 起)

X

Y

yocto (C++11 起)
yotta (C++11 起)

Z

zepto (C++11 起)
zetta (C++11 起)

参阅


std::chrono 符号索引

< cpp‎ | symbol index

此页面尝试列出所有来自标准库，可用于命名空间 std::chrono:: 的符号。符号以下列方式书写：

  • 函数名带 () 。
  • 模板名带 <> 。

A C D F G H I J L M N O P R S T U W Y Z

A

abs<>() (C++17 起)
ambiguous_local_time (C++20 起)
April (C++20 起)
August (C++20 起)

C

ceil<>() (std::chrono::duration) (C++17 起)
ceil<>() (std::chrono::time_point) (C++17 起)
choose (C++20 起)
clock_cast<>() (C++20 起)
clock_time_conversion<> (C++20 起)
current_zone() (C++20 起)

D

day (C++20 起)
December (C++20 起)
duration<> (C++11 起)
duration_cast<>() (C++11 起)
duration_values<> (C++11 起)

F

February (C++20 起)
file_clock (C++20 起)
file_seconds (C++20 起)
file_time (C++20 起)
floor<>() (std::chrono::duration) (C++17 起)
floor<>() (std::chrono::time_point) (C++17 起)
Friday (C++20 起)
from_stream<>() (std::chrono::day) (C++20 起)
from_stream<>() (std::chrono::file_time) (C++20 起)
from_stream<>() (std::chrono::gps_time) (C++20 起)
from_stream<>() (std::chrono::local_time) (C++20 起)
from_stream<>() (std::chrono::month) (C++20 起)
from_stream<>() (std::chrono::month_day) (C++20 起)
from_stream<>() (std::chrono::sys_time) (C++20 起)
from_stream<>() (std::chrono::tai_time) (C++20 起)
from_stream<>() (std::chrono::utc_time) (C++20 起)
from_stream<>() (std::chrono::weekday) (C++20 起)
from_stream<>() (std::chrono::year) (C++20 起)
from_stream<>() (std::chrono::year_month) (C++20 起)
from_stream<>() (std::chrono::year_month_day) (C++20 起)

G

get_leap_second_info (C++20 起)
get_tzdb() (C++20 起)
get_tzdb_list() (C++20 起)
gps_clock (C++20 起)
gps_seconds (C++20 起)
gps_time (C++20 起)

H

hh_mm_ss<> (C++20 起)
high_resolution_clock (C++11 起)
hours (C++11 起)

I

is_am (C++20 起)
is_clock<> (C++20 起)
is_clock_v<> (C++20 起)
is_pm (C++20 起)

J

January (C++20 起)
July (C++20 起)
June (C++20 起)

L

last (C++20 起)
last_spec (C++20 起)
leap_second (C++20 起)
leap_second_info (C++20 起)
local_info (C++20 起)
local_seconds (C++20 起)
local_t (C++20 起)
local_time (C++20 起)
local_time_format<>() (C++20 起)
locate_zone() (C++20 起)

M

make12 (C++20 起)
make24 (C++20 起)
March (C++20 起)
May (C++20 起)
microseconds (C++11 起)
milliseconds (C++11 起)
minutes (C++11 起)
Monday (C++20 起)
month (C++20 起)
month_day (C++20 起)
month_day_last (C++20 起)
month_weekday (C++20 起)
month_weekday_last (C++20 起)

N

nanoseconds (C++11 起)
nonexistent_local_time (C++20 起)
November (C++20 起)

O

October (C++20 起)

P

parse<>() (C++20 起)

R

reload_tzdb() (C++20 起)
remote_version() (C++20 起)
round<>() (std::chrono::duration) (C++17 起)
round<>() (std::chrono::time_point) (C++17 起)

S

Saturday (C++20 起)
seconds (C++11 起)
September (C++20 起)
steady_clock (C++11 起)
Sunday (C++20 起)
sys_info (C++20 起)
sys_days (C++20 起)
sys_seconds (C++20 起)
sys_time (C++20 起)
system_clock (C++11 起)

T

tai_clock (C++20 起)
tai_seconds (C++20 起)
tai_time (C++20 起)
Thursday (C++20 起)
time_point<> (C++11 起)
time_point_cast<>() (C++11 起)
time_zone() (C++20 起)
time_zone_link (C++20 起)
treat_as_floating_point<> (C++11 起)
treat_as_floating_point_v<> (C++17 起)
Tuesday (C++20 起)
tzdb (C++20 起)
tzdb_list (C++20 起)

U

utc_clock (C++20 起)
utc_seconds (C++20 起)
utc_time (C++20 起)

W

Wednesday (C++20 起)
weekday (C++20 起)
weekday_indexed (C++20 起)
weekday_last (C++20 起)

Y

year (C++20 起)
year_month (C++20 起)
year_month_day (C++20 起)
year_month_day_last (C++20 起)
year_month_weekday (C++20 起)
year_month_weekday_last (C++20 起)

Z

zoned_seconds (C++20 起)
zoned_time<> (C++20 起)
zoned_traits<> (C++20 起)


std::literals::chrono_literals 符号索引

< cpp‎ | symbol index

此页面尝试列出所有来自标准库，可用于命名空间 std::literals::chrono_literals:: 的符号。符号以下列方式书写：

  • 函数名带 () 。
  • 模板带 <> 。

注解

这些运算符声明于命名空间 std::literals::chrono_literals ，其中 literals 与 chrono_literals 为内联命名空间。能通过 using namespace std::literals 、 using namespace std::chrono_literals 及 using namespace std::literals::chrono_literals 取得对这些运算符的访问。

另外，在命名空间 std::chrono 中，标准库提供 using namespace literals::chrono_literals; 指令，故若程序员使用 using namespace std::chrono; 取得对 chrono 库中的类的访问，则对应的字面量运算符亦变为可见。

D H M N S U Y

D

d (C++20 起)

H

h (C++14 起)

M

min (C++14 起)
ms (C++14 起)

N

ns (C++14 起)

S

s (C++14 起)

U

us (C++14 起)

Y

y (C++20 起)


std::literals::complex_literals 符号索引

< cpp‎ | symbol index

此页面试图列出所有来自标准库，可用于命名空间 std::literals::complex_literals:: 的符号。符号以下列方式书写：

  • 函数名带 () 。
  • 模板带 <> 。

注解

这些运算符声明于命名空间 std::literals::complex_literals ，其中 literals 和 complex_literals 均为内联命名空间。能以 using namespace std::literals 、 using namespace std::complex_literals 和 using namespace std::literals::complex_literals 获得对这些运算符的访问。

I

I

i (C++14 起)
if (C++14 起)
il (C++14 起)


std::execution 符号索引

< cpp‎ | symbol index

此页面试图列出所有来自标准库，可用于命名空间 std::execution:: 的符号。符号以下列方式书写：

  • 函数名带 () 。
  • 模板带 <> 。

P S U

P

par (C++17 起)
par_unseq (C++17 起)
parallel_policy (C++17 起)
parallel_unsequenced_policy (C++17 起)

S

seq (C++17 起)
sequenced_policy (C++17 起)

U

unseq (C++20 起)
unsequenced_policy (C++20 起)


std::filesystem 符号索引

< cpp‎ | symbol index

此页面尝试列出所有来自标准库，在命名空间 std::filesystem:: 中的可用符号。符号书写如下：

  • 函数名带 () 。
  • 模板名带 <> 。

A C D E F H I L P R S T U W

A

absolute() (C++17 起)

C

canonical() (C++17 起)
copy() (C++17 起)
copy_file() (C++17 起)
copy_options (C++17 起)
copy_symlink() (C++17 起)
create_directory() (C++17 起)
create_directory_symlink() (C++17 起)
create_directories() (C++17 起)
create_hard_link() (C++17 起)
create_symlink() (C++17 起)
current_path() (C++17 起)

D

directory_entry (C++17 起)
directory_iterator (C++17 起)
directory_options (C++17 起)

E

equivalent() (C++17 起)
exists() (C++17 起)

F

file_size() (C++17 起)
file_status (C++17 起)
filesystem_error (C++17 起)
file_time_type (C++17 起)
file_type (C++17 起)

H

hard_link_count() (C++17 起)

I

is_block_file() (C++17 起)
is_character_file() (C++17 起)
is_directory() (C++17 起)
is_empty() (C++17 起)
is_fifo() (C++17 起)
is_other() (C++17 起)
is_regular_file() (C++17 起)
is_socket() (C++17 起)
is_symlink() (C++17 起)

L

last_write_time() (C++17 起)

P

path (C++17 起)
permissions() (C++17 起)
perms (C++17 起)
perm_options (C++17 起)
proximate() (C++17 起)

R

read_symlink() (C++17 起)
recursive_directory_iterator (C++17 起)
relative() (C++17 起)
remove() (C++17 起)
remove_all() (C++17 起)
rename() (C++17 起)
resize_file() (C++17 起)

S

space() (C++17 起)
space_info (C++17 起)
status() (C++17 起)
status_known() (C++17 起)
symlink_status() (C++17 起)

T

temp_directory_path() (C++17 起)

U

u8path<>() (C++17 起)(C++20 中弃用)

W

weakly_canonical() (C++17 起)


std::literals 符号索引

< cpp‎ | symbol index

此页面试图列出所有来自标准库，可用于命名空间 std::literals:: 的符号。符号以下列方式书写：

  • 函数名带 () 。
  • 模板带 <> 。

C S

C

▶ chrono_literals (C++14 起)
▶ complex_literals (C++14 起)

S

▶ string_literals (C++14 起)
▶ string_view_literals (C++17 起)


宏符号索引

< cpp‎ | symbol index

此页面尝试列出所有来自标准库的可用宏符号。符号书写如下：

  • 仿函数宏带 () 。

_ A B C D E F H I K L M N O P R S T U V W

_ (下划线)

__alignas_is_defined (C++11 起)
__bool_true_false_are_defined (C++11 起)
__cpp_lib_adaptor_iterator_pair_constructor (C++23 起)
__cpp_lib_addressof_constexpr (C++20 起)
__cpp_lib_allocate_at_least (C++23 起)
__cpp_lib_allocator_traits_is_always_equal (C++20 起)
__cpp_lib_any (C++20 起)
__cpp_lib_apply (C++20 起)
__cpp_lib_array_constexpr (C++20 起)
__cpp_lib_as_const (C++20 起)
__cpp_lib_assume_aligned (C++20 起)
__cpp_lib_atomic_flag_test (C++20 起)
__cpp_lib_atomic_float (C++20 起)
__cpp_lib_atomic_is_always_lock_free (C++20 起)
__cpp_lib_atomic_lock_free_type_aliases (C++20 起)
__cpp_lib_atomic_ref (C++20 起)
__cpp_lib_atomic_shared_ptr (C++20 起)
__cpp_lib_atomic_value_initialization (C++20 起)
__cpp_lib_atomic_wait (C++20 起)
__cpp_lib_barrier (C++20 起)
__cpp_lib_bind_front (C++20 起)
__cpp_lib_bit_cast (C++20 起)
__cpp_lib_bitops (C++20 起)
__cpp_lib_bool_constant (C++20 起)
__cpp_lib_bounded_array_traits (C++20 起)
__cpp_lib_boyer_moore_searcher (C++20 起)
__cpp_lib_byte (C++20 起)
__cpp_lib_char8_t (C++20 起)
__cpp_lib_chrono (C++20 起)
__cpp_lib_chrono_udls (C++20 起)
__cpp_lib_clamp (C++20 起)
__cpp_lib_complex_udls (C++20 起)
__cpp_lib_concepts (C++20 起)
__cpp_lib_constexpr_algorithms (C++20 起)
__cpp_lib_constexpr_complex (C++20 起)
__cpp_lib_constexpr_dynamic_alloc (C++20 起)
__cpp_lib_constexpr_functional (C++20 起)
__cpp_lib_constexpr_invoke (C++20 起)
__cpp_lib_constexpr_iterator (C++20 起)
__cpp_lib_constexpr (C++20 起)
__cpp_lib_constexpr_memory (C++20 起)
__cpp_lib_constexpr_numeric (C++20 起)
__cpp_lib_constexpr_string (C++20 起)
__cpp_lib_constexpr_string_view (C++20 起)
__cpp_lib_constexpr_swap_algorithms (C++20 起)
__cpp_lib_constexpr_tuple (C++20 起)
__cpp_lib_constexpr_typeinfo (C++23 起)
__cpp_lib_constexpr_utility (C++20 起)
__cpp_lib_constexpr_vector (C++20 起)
__cpp_lib_coroutine (C++20 起)
__cpp_lib_destroying_delete (C++20 起)
__cpp_lib_enable_shared_from_this (C++20 起)
__cpp_lib_endian (C++20 起)
__cpp_lib_erase_if (C++20 起)
__cpp_lib_exchange_function (C++20 起)
__cpp_lib_execution (C++20 起)
__cpp_lib_filesystem (C++20 起)
__cpp_lib_format (C++20 起)
__cpp_lib_gcd_lcm (C++20 起)
__cpp_lib_generic_associative_lookup (C++20 起)
__cpp_lib_generic_unordered_lookup (C++20 起)
__cpp_lib_hardware_interference_size (C++20 起)
__cpp_lib_has_unique_object_representations (C++20 起)
__cpp_lib_hypot (C++20 起)
__cpp_lib_incomplete_container_elements (C++20 起)
__cpp_lib_integer_comparison_functions (C++20 起)
__cpp_lib_integer_sequence (C++20 起)
__cpp_lib_integral_constant_callable (C++20 起)
__cpp_lib_interpolate (C++20 起)
__cpp_lib_int_pow2 (C++20 起)
__cpp_lib_invoke (C++20 起)
__cpp_lib_invoke_r (C++23 起)
__cpp_lib_is_aggregate (C++20 起)
__cpp_lib_is_constant_evaluated (C++20 起)
__cpp_lib_is_final (C++20 起)
__cpp_lib_is_invocable (C++20 起)
__cpp_lib_is_layout_compatible (C++20 起)
__cpp_lib_is_nothrow_convertible (C++20 起)
__cpp_lib_is_null_pointer (C++20 起)
__cpp_lib_is_pointer_interconvertible (C++20 起)
__cpp_lib_is_scoped_enum (C++20 起)
__cpp_lib_is_swappable (C++20 起)
__cpp_lib_jthread (C++20 起)
__cpp_lib_latch (C++20 起)
__cpp_lib_launder (C++20 起)
__cpp_lib_list_remove_return_type (C++20 起)
__cpp_lib_logical_traits (C++20 起)
__cpp_lib_make_from_tuple (C++20 起)
__cpp_lib_make_reverse_iterator (C++20 起)
__cpp_lib_make_unique (C++20 起)
__cpp_lib_map_try_emplace (C++20 起)
__cpp_lib_math_constants (C++20 起)
__cpp_lib_math_special_functions (C++20 起)
__cpp_lib_memory_resource (C++20 起)
__cpp_lib_node_extract (C++20 起)
__cpp_lib_nonmember_container_access (C++20 起)
__cpp_lib_not_fn (C++20 起)
__cpp_lib_null_iterators (C++20 起)
__cpp_lib_optional (C++20 起)
__cpp_lib_parallel_algorithm (C++20 起)
__cpp_lib_polymorphic_allocator (C++20 起)
__cpp_lib_quoted_string_io (C++20 起)
__cpp_lib_ranges (C++20 起)
__cpp_lib_ranges_starts_ends_with (C++23 起)
__cpp_lib_raw_memory_algorithms (C++20 起)
__cpp_lib_remove_cvref (C++20 起)
__cpp_lib_result_of_sfinae (C++20 起)
__cpp_lib_robust_nonmodifying_seq_ops (C++20 起)
__cpp_lib_sample (C++20 起)
__cpp_lib_scoped_lock (C++20 起)
__cpp_lib_semaphore (C++20 起)
__cpp_lib_shared_mutex (C++20 起)
__cpp_lib_shared_ptr_arrays (C++20 起)
__cpp_lib_shared_ptr_weak_type (C++20 起)
__cpp_lib_shared_timed_mutex (C++20 起)
__cpp_lib_shift (C++20 起)
__cpp_lib_smart_ptr_for_overwrite (C++20 起)
__cpp_lib_source_location (C++20 起)
__cpp_lib_spaceship (C++20 起)
__cpp_lib_span (C++20 起)
__cpp_lib_spanstream (C++23 起)
__cpp_lib_ssize (C++20 起)
__cpp_lib_stacktrace (C++23 起)
__cpp_lib_starts_ends_with (C++20 起)
__cpp_lib_stdatomic_h (C++23 起)
__cpp_lib_string_contains (C++23 起)
__cpp_lib_string_udls (C++20 起)
__cpp_lib_string_view (C++20 起)
__cpp_lib_syncbuf (C++20 起)
__cpp_lib_three_way_comparison (C++20 起)
__cpp_lib_to_address (C++20 起)
__cpp_lib_to_array (C++20 起)
__cpp_lib_to_chars (C++20 起)
__cpp_lib_to_underlying (C++23 起)
__cpp_lib_transformation_trait_aliases (C++20 起)
__cpp_lib_transparent_operators (C++20 起)
__cpp_lib_tuple_element_t (C++20 起)
__cpp_lib_tuples_by_type (C++20 起)
__cpp_lib_type_identity (C++20 起)
__cpp_lib_type_trait_variable_templates (C++20 起)
__cpp_lib_uncaught_exceptions (C++20 起)
__cpp_lib_unordered_map_try_emplace (C++20 起)
__cpp_lib_unwrap_ref (C++20 起)
__cpp_lib_variant (C++20 起)
__cpp_lib_void_t (C++20 起)
_IOFBF
_IOLBF
_IONBF

A

assert()
ATOMIC_BOOL_LOCK_FREE (C++11 起)
ATOMIC_CHAR_LOCK_FREE (C++11 起)
ATOMIC_CHAR16_T_LOCK_FREE (C++11 起)
ATOMIC_CHAR32_T_LOCK_FREE (C++11 起)
ATOMIC_CHAR8_T_LOCK_FREE (C++20 起)
ATOMIC_FLAG_INIT (C++11 起)(C++20 中弃用)
ATOMIC_INT_LOCK_FREE (C++11 起)
ATOMIC_LLONG_LOCK_FREE (C++11 起)
ATOMIC_LONG_LOCK_FREE (C++11 起)
ATOMIC_POINTER_LOCK_FREE (C++11 起)
ATOMIC_SHORT_LOCK_FREE (C++11 起)
ATOMIC_VAR_INIT() (C++11 起)(C++20 中弃用)
ATOMIC_WCHAR_T_LOCK_FREE (C++11 起)

B

BUFSIZ

C

CHAR_BIT
CHAR_MAX
CHAR_MIN
CLOCKS_PER_SEC

D

DBL_DECIMAL_DIG (C++17 起)
DBL_DIG
DBL_EPSILON
DBL_HAS_SUBNORM (C++17 起)
DBL_MANT_DIG
DBL_MAX
DBL_MAX_10_EXP
DBL_MAX_EXP
DBL_MIN
DBL_MIN_10_EXP
DBL_MIN_EXP
DBL_TRUE_MIN (C++17 起)
DECIMAL_DIG (C++11 起)

E

E2BIG (C++11 起)
EACCES (C++11 起)
EADDRINUSE (C++11 起)
EADDRNOTAVAIL (C++11 起)
EAFNOSUPPORT (C++11 起)
EAGAIN (C++11 起)
EALREADY (C++11 起)
EBADF (C++11 起)
EBADMSG (C++11 起)
EBUSY (C++11 起)
ECANCELED (C++11 起)
ECHILD (C++11 起)
ECONNABORTED (C++11 起)
ECONNREFUSED (C++11 起)
ECONNRESET (C++11 起)
EDEADLK (C++11 起)
EDESTADDRREQ (C++11 起)
EDOM
EEXIST (C++11 起)
EFAULT (C++11 起)
EFBIG (C++11 起)
EHOSTUNREACH (C++11 起)
EIDRM (C++11 起)
EILSEQ (C++11 起)
EINPROGRESS (C++11 起)
EINTR (C++11 起)
EINVAL (C++11 起)
EIO (C++11 起)
EISCONN (C++11 起)
EISDIR (C++11 起)
ELOOP (C++11 起)
EMFILE (C++11 起)
EMLINK (C++11 起)
EMSGSIZE (C++11 起)
ENAMETOOLONG (C++11 起)
ENETDOWN (C++11 起)
ENETRESET (C++11 起)
ENETUNREACH (C++11 起)
ENFILE (C++11 起)
ENOBUFS (C++11 起)
ENODATA (C++11 起)
ENODEV (C++11 起)
ENOENT (C++11 起)
ENOEXEC (C++11 起)
ENOLCK (C++11 起)
ENOLINK (C++11 起)
ENOMEM (C++11 起)
ENOMSG (C++11 起)
ENOPROTOOPT (C++11 起)
ENOSPC (C++11 起)
ENOSR (C++11 起)
ENOSTR (C++11 起)
ENOSYS (C++11 起)
ENOTCONN (C++11 起)
ENOTDIR (C++11 起)
ENOTEMPTY (C++11 起)
ENOTRECOVERABLE (C++11 起)
ENOTSOCK (C++11 起)
ENOTSUP (C++11 起)
ENOTTY (C++11 起)
ENXIO (C++11 起)
EOF
EOPNOTSUPP (C++11 起)
EOVERFLOW (C++11 起)
EOWNERDEAD (C++11 起)
EPERM (C++11 起)
EPIPE (C++11 起)
EPROTO (C++11 起)
EPROTONOSUPPORT (C++11 起)
EPROTOTYPE (C++11 起)
ERANGE
EROFS (C++11 起)
errno
ESPIPE (C++11 起)
ESRCH (C++11 起)
ETIME (C++11 起)
ETIMEDOUT (C++11 起)
ETXTBSY (C++11 起)
EWOULDBLOCK (C++11 起)
EXDEV (C++11 起)
EXIT_FAILURE
EXIT_SUCCESS

F

FE_ALL_EXCEPT (C++11 起)
FE_DFL_ENV (C++11 起)
FE_DIVBYZERO (C++11 起)
FE_DOWNWARD (C++11 起)
FE_INEXACT (C++11 起)
FE_INVALID (C++11 起)
FE_OVERFLOW (C++11 起)
FE_TONEAREST (C++11 起)
FE_TOWARDZERO (C++11 起)
FE_UNDERFLOW (C++11 起)
FE_UPWARD (C++11 起)
FILENAME_MAX
FLT_DECIMAL_DIG (C++17 起)
FLT_DIG
FLT_EPSILON
FLT_EVAL_METHOD (C++11 起)
FLT_HAS_SUBNORM (C++17 起)
FLT_MANT_DIG
FLT_MAX
FLT_MAX_10_EXP
FLT_MAX_EXP
FLT_MIN
FLT_MIN_10_EXP
FLT_MIN_EXP
FLT_RADIX
FLT_ROUNDS
FLT_TRUE_MIN (C++17 起)
FOPEN_MAX
FP_FAST_FMA (C++11 起)
FP_FAST_FMAF (C++11 起)
FP_FAST_FMAL (C++11 起)
FP_ILOGB0 (C++11 起)
FP_ILOGBNAN (C++11 起)
FP_SUBNORMAL (C++11 起)
FP_ZERO (C++11 起)
FP_INFINITE (C++11 起)
FP_NAN (C++11 起)
FP_NORMAL (C++11 起)

H

HUGE_VAL
HUGE_VALF (C++11 起)
HUGE_VALL (C++11 起)

I

INFINITY (C++11 起)
INT_FAST16_MAX (C++11 起)
INT_FAST16_MIN (C++11 起)
INT_FAST32_MAX (C++11 起)
INT_FAST32_MIN (C++11 起)
INT_FAST64_MAX (C++11 起)
INT_FAST64_MIN (C++11 起)
INT_FAST8_MAX (C++11 起)
INT_FAST8_MIN (C++11 起)
INT_LEAST16_MAX (C++11 起)
INT_LEAST16_MIN (C++11 起)
INT_LEAST32_MAX (C++11 起)
INT_LEAST32_MIN (C++11 起)
INT_LEAST64_MAX (C++11 起)
INT_LEAST64_MIN (C++11 起)
INT_LEAST8_MAX (C++11 起)
INT_LEAST8_MIN (C++11 起)
INT_MAX
INT_MIN
INT16_C() (C++11 起)
INT16_MAX (C++11 起)
INT16_MIN (C++11 起)
INT32_C() (C++11 起)
INT32_MAX (C++11 起)
INT32_MIN (C++11 起)
INT64_C() (C++11 起)
INT64_MAX (C++11 起)
INT64_MIN (C++11 起)
INT8_C() (C++11 起)
INT8_MAX (C++11 起)
INT8_MIN (C++11 起)
INTMAX_C() (C++11 起)
INTMAX_MAX (C++11 起)
INTMAX_MIN (C++11 起)
INTPTR_MAX (C++11 起)
INTPTR_MIN (C++11 起)

L

L_tmpnam
LC_ALL
LC_COLLATE
LC_CTYPE
LC_MONETARY
LC_NUMERIC
LC_TIME
LDBL_DECIMAL_DIG (C++17 起)
LDBL_DIG
LDBL_EPSILON
LDBL_HAS_SUBNORM (C++17 起)
LDBL_MANT_DIG
LDBL_MAX
LDBL_MAX_10_EXP
LDBL_MAX_EXP
LDBL_MIN
LDBL_MIN_10_EXP
LDBL_MIN_EXP
LDBL_TRUE_MIN (C++17 起)
LLONG_MAX (C++11 起)
LLONG_MIN (C++11 起)
LONG_MAX
LONG_MIN

M

MATH_ERREXCEPT (C++11 起)
math_errhandling (C++11 起)
MATH_ERRNO (C++11 起)
MB_CUR_MAX
MB_LEN_MAX

N

NAN (C++11 起)
NULL

O

offsetof()
ONCE_FLAG_INIT (C++11 起)

P

PRId16 (C++11 起)
PRId32 (C++11 起)
PRId64 (C++11 起)
PRId8 (C++11 起)
PRIdFAST16 (C++11 起)
PRIdFAST32 (C++11 起)
PRIdFAST64 (C++11 起)
PRIdFAST8 (C++11 起)
PRIdLEAST16 (C++11 起)
PRIdLEAST32 (C++11 起)
PRIdLEAST64 (C++11 起)
PRIdLEAST8 (C++11 起)
PRIdMAX (C++11 起)
PRIdPTR (C++11 起)
PRIi16 (C++11 起)
PRIi32 (C++11 起)
PRIi64 (C++11 起)
PRIi8 (C++11 起)
PRIiFAST16 (C++11 起)
PRIiFAST32 (C++11 起)
PRIiFAST64 (C++11 起)
PRIiFAST8 (C++11 起)
PRIiLEAST16 (C++11 起)
PRIiLEAST32 (C++11 起)
PRIiLEAST64 (C++11 起)
PRIiLEAST8 (C++11 起)
PRIiMAX (C++11 起)
PRIiPTR (C++11 起)
PRIo16 (C++11 起)
PRIo32 (C++11 起)
PRIo64 (C++11 起)
PRIo8 (C++11 起)
PRIoFAST16 (C++11 起)
PRIoFAST32 (C++11 起)
PRIoFAST64 (C++11 起)
PRIoFAST8 (C++11 起)
PRIoLEAST16 (C++11 起)
PRIoLEAST32 (C++11 起)
PRIoLEAST64 (C++11 起)
PRIoLEAST8 (C++11 起)
PRIoMAX (C++11 起)
PRIoPTR (C++11 起)
PRIu16 (C++11 起)
PRIu32 (C++11 起)
PRIu64 (C++11 起)
PRIu8 (C++11 起)
PRIuFAST16 (C++11 起)
PRIuFAST32 (C++11 起)
PRIuFAST64 (C++11 起)
PRIuFAST8 (C++11 起)
PRIuLEAST16 (C++11 起)
PRIuLEAST32 (C++11 起)
PRIuLEAST64 (C++11 起)
PRIuLEAST8 (C++11 起)
PRIuMAX (C++11 起)
PRIuPTR (C++11 起)
PRIx16 (C++11 起)
PRIX16 (C++11 起)
PRIx32 (C++11 起)
PRIX32 (C++11 起)
PRIx64 (C++11 起)
PRIX64 (C++11 起)
PRIx8 (C++11 起)
PRIX8 (C++11 起)
PRIxFAST16 (C++11 起)
PRIXFAST16 (C++11 起)
PRIxFAST32 (C++11 起)
PRIXFAST32 (C++11 起)
PRIxFAST64 (C++11 起)
PRIXFAST64 (C++11 起)
PRIxFAST8 (C++11 起)
PRIXFAST8 (C++11 起)
PRIxLEAST16 (C++11 起)
PRIXLEAST16 (C++11 起)
PRIxLEAST32 (C++11 起)
PRIXLEAST32 (C++11 起)
PRIxLEAST64 (C++11 起)
PRIXLEAST64 (C++11 起)
PRIxLEAST8 (C++11 起)
PRIXLEAST8 (C++11 起)
PRIxMAX (C++11 起)
PRIXMAX (C++11 起)
PRIxPTR (C++11 起)
PRIXPTR (C++11 起)
PTRDIFF_MAX (C++11 起)
PTRDIFF_MIN (C++11 起)

R

RAND_MAX

S

SCHAR_MAX
SCHAR_MIN
SCNd16 (C++11 起)
SCNd32 (C++11 起)
SCNd64 (C++11 起)
SCNd8 (C++11 起)
SCNdFAST16 (C++11 起)
SCNdFAST32 (C++11 起)
SCNdFAST64 (C++11 起)
SCNdFAST8 (C++11 起)
SCNdLEAST16 (C++11 起)
SCNdLEAST32 (C++11 起)
SCNdLEAST64 (C++11 起)
SCNdLEAST8 (C++11 起)
SCNdMAX (C++11 起)
SCNdPTR (C++11 起)
SCNi16 (C++11 起)
SCNi32 (C++11 起)
SCNi64 (C++11 起)
SCNi8 (C++11 起)
SCNiFAST16 (C++11 起)
SCNiFAST32 (C++11 起)
SCNiFAST64 (C++11 起)
SCNiFAST8 (C++11 起)
SCNiLEAST16 (C++11 起)
SCNiLEAST32 (C++11 起)
SCNiLEAST64 (C++11 起)
SCNiLEAST8 (C++11 起)
SCNiMAX (C++11 起)
SCNiPTR (C++11 起)
SCNo16 (C++11 起)
SCNo32 (C++11 起)
SCNo64 (C++11 起)
SCNo8 (C++11 起)
SCNoFAST16 (C++11 起)
SCNoFAST32 (C++11 起)
SCNoFAST64 (C++11 起)
SCNoFAST8 (C++11 起)
SCNoLEAST16 (C++11 起)
SCNoLEAST32 (C++11 起)
SCNoLEAST64 (C++11 起)
SCNoLEAST8 (C++11 起)
SCNoMAX (C++11 起)
SCNoPTR (C++11 起)
SCNu16 (C++11 起)
SCNu32 (C++11 起)
SCNu64 (C++11 起)
SCNu8 (C++11 起)
SCNuFAST16 (C++11 起)
SCNuFAST32 (C++11 起)
SCNuFAST64 (C++11 起)
SCNuFAST8 (C++11 起)
SCNuLEAST16 (C++11 起)
SCNuLEAST32 (C++11 起)
SCNuLEAST64 (C++11 起)
SCNuLEAST8 (C++11 起)
SCNuMAX (C++11 起)
SCNuPTR (C++11 起)
SCNx16 (C++11 起)
SCNx32 (C++11 起)
SCNx64 (C++11 起)
SCNx8 (C++11 起)
SCNxFAST16 (C++11 起)
SCNxFAST32 (C++11 起)
SCNxFAST64 (C++11 起)
SCNxFAST8 (C++11 起)
SCNxLEAST16 (C++11 起)
SCNxLEAST32 (C++11 起)
SCNxLEAST64 (C++11 起)
SCNxLEAST8 (C++11 起)
SCNxMAX (C++11 起)
SCNxPTR (C++11 起)
SEEK_CUR
SEEK_END
SEEK_SET
setjmp()
SHRT_MAX
SHRT_MIN
SIG_ATOMIC_MAX (C++11 起)
SIG_ATOMIC_MIN (C++11 起)
SIG_DFL
SIG_ERR
SIG_IGN
SIGABRT
SIGFPE
SIGILL
SIGINT
SIGSEGV
SIGTERM
SIZE_MAX (C++11 起)
stderr
stdin
stdout

T

TIME_UTC (C++17 起)
TMP_MAX

U

UCHAR_MAX
UINT_FAST16_MAX (C++11 起)
UINT_FAST32_MAX (C++11 起)
UINT_FAST64_MAX (C++11 起)
UINT_FAST8_MAX (C++11 起)
UINT_LEAST16_MAX (C++11 起)
UINT_LEAST32_MAX (C++11 起)
UINT_LEAST64_MAX (C++11 起)
UINT_LEAST8_MAX (C++11 起)
UINT_MAX
UINT16_C() (C++11 起)
UINT16_MAX (C++11 起)
UINT32_C() (C++11 起)
UINT32_MAX (C++11 起)
UINT64_MAX (C++11 起)
UINT64_C() (C++11 起)
UINT8_C() (C++11 起)
UINT8_MAX (C++11 起)
UINTMAX_C() (C++11 起)
UINTMAX_MAX (C++11 起)
UINTPTR_MAX (C++11 起)
ULLONG_MAX (C++11 起)
ULONG_MAX
USHRT_MAX

V

va_arg()
va_copy() (C++11 起)
va_end()
va_start()

W

WCHAR_MAX (C++11 起)
WCHAR_MIN (C++11 起)
WEOF
WINT_MAX (C++11 起)
WINT_MIN (C++11 起)

参阅


std::numbers 符号索引

< cpp‎ | symbol index

此页面尝试列出所有来自标准库，在命名空间 std::numbers:: 中的可用符号。符号书写如下：

  • 函数名带 () 。
  • 模板名带 <> 。

E I L P S

E

e (C++20 起)
e_v<> (C++20 起)
egamma (C++20 起)
egamma_v<> (C++20 起)

I

inv_pi (C++20 起)
inv_pi_v<> (C++20 起)
inv_sqrt3 (C++20 起)
inv_sqrt3_v<> (C++20 起)
inv_sqrtpi (C++20 起)
inv_sqrtpi_v<> (C++20 起)

L

ln10 (C++20 起)
ln10_v<> (C++20 起)
ln2 (C++20 起)
ln2_v<> (C++20 起)
log10e (C++20 起)
log10e_v<> (C++20 起)
log2e (C++20 起)
log2e_v<> (C++20 起)

P

phi (C++20 起)
phi_v<> (C++20 起)
pi (C++20 起)
pi_v<> (C++20 起)

S

sqrt2 (C++20 起)
sqrt2_v<> (C++20 起)
sqrt3 (C++20 起)
sqrt3_v<> (C++20 起)


std::placeholders 符号索引

< cpp‎ | symbol index

此页面尝试列出所有来自标准库，在命名空间 std::placeholders:: 中的可用符号。符号书写如下：

  • 函数名带 () 。
  • 模板名带 <> 。

_

_ (下划线)

_1, _2, ..., _N (C++11 起)


std::pmr 符号索引

< cpp‎ | symbol index

此页面尝试列出所有来自标准库，在命名空间 std::pmr:: 中的可用符号。符号书写如下：

  • 函数名带 () 。
  • 模板名带 <> 。

B D F G L M N P S U V W

B

basic_string<> (C++17 起)

D

deque<> (C++17 起)

F

forward_list<> (C++17 起)

G

get_default_resource() (C++17 起)

L

list<> (C++17 起)

M

map<> (C++17 起)
memory_resource (C++17 起)
monotonic_buffer_resource (C++17 起)
multimap<> (C++17 起)
multiset<> (C++17 起)

N

new_delete_resource() (C++17 起)
null_memory_resource() (C++17 起)

P

polymorphic_allocator<> (C++17 起)
pool_options (C++17 起)

S

set<> (C++17 起)
set_default_resource() (C++17 起)
stacktrace (C++23 起)
string (C++17 起)
synchronized_pool_resource (C++17 起)

U

u16string<> (C++17 起)
u32string<> (C++17 起)
u8string<> (C++20 起)
unordered_map<> (C++17 起)
unordered_multimap<> (C++17 起)
unordered_multiset<> (C++17 起)
unordered_set<> (C++17 起)
unsynchronized_pool_resource (C++17 起)

V

vector<> (C++17 起)

W

wstring (C++17 起)


std::ranges 符号索引

< cpp‎ | symbol index

此页面试图列出所有来自标准库，可用于命名空间 std::ranges:: 的符号。符号以下列方式书写：

  • 函数名带 () 。
  • 模板带 <> 。

A B C D E F G I J K L M N O P R S T U V W Z

A

adjacent_find (C++23 起)
adjacent_transform_view<> (C++23 起)
adjacent_view<> (C++20 起)
advance (C++20 起)
all_of (C++20 起)
any_of (C++20 起)

B

basic_istream_view<> (C++20 起)
begin (C++20 起)
bidirectional_range<> (C++20 起)
binary_transform_result<> (C++20 起)
borrowed_iterator_t<> (C++20 起)
borrowed_range<> (C++20 起)
borrowed_subrange_t<> (C++20 起)

C

cbegin (C++20 起)
cdata (C++20 起)
cend (C++20 起)
clamp (C++20 起)
common_range<> (C++20 起)
common_view<> (C++20 起)
construct_at (C++20 起)
contiguous_range<> (C++20 起)
copy (C++20 起)
copy_backward (C++20 起)
copy_backward_result<> (C++20 起)
copy_if (C++20 起)
copy_if_result<> (C++20 起)
copy_n (C++20 起)
copy_n_result<> (C++20 起)
copy_result<> (C++20 起)
count (C++20 起)
count_if (C++20 起)
crbegin (C++20 起)
crend (C++20 起)

D

dangling (C++20 起)
data (C++20 起)
destroy (C++20 起)
destroy_at (C++20 起)
destroy_n (C++20 起)
disable_sized_range<> (C++20 起)
distance (C++20 起)
drop_view<> (C++20 起)
drop_while_view<> (C++20 起)

E

elements_view<> (C++20 起)
empty (C++20 起)
empty_view<> (C++20 起)
enable_borrowed_range<> (C++20 起)
enable_view<> (C++20 起)
end (C++20 起)
ends_with (C++23 起)
equal (C++20 起)
equal_to (C++20 起)

F

fill (C++20 起)
fill_n (C++20 起)
filter_view<> (C++20 起)
find (C++20 起)
find_end (C++20 起)
find_first_of (C++20 起)
find_if (C++20 起)
find_if_not (C++20 起)
for_each (C++20 起)
for_each_n (C++20 起)
for_each_n_result<> (C++20 起)
for_each_result<> (C++20 起)
forward_range<> (C++20 起)

G

generate (C++20 起)
generate_n (C++20 起)
get<>() (std::ranges::subrange) (C++20 起)
greater (C++20 起)
greater_equal (C++20 起)

I

in_found_result<> (C++20 起)
in_fun_result<> (C++20 起)
in_in_out_result<> (C++20 起)
in_in_result<> (C++20 起)
in_out_out_result<> (C++20 起)
in_out_result<> (C++20 起)
includes (C++20 起)
inplace_merge (C++20 起)
input_range<> (C++20 起)
iota_view<> (C++20 起)
is_heap (C++20 起)
is_heap_until (C++20 起)
is_partitioned (C++20 起)
is_permutation (C++20 起)
is_sorted (C++20 起)
is_sorted_until (C++20 起)
istream_view<> (C++20 起)
iter_move (C++20 起)
iter_swap (C++20 起)
iterator_t<> (C++20 起)

J

join_view<> (C++20 起)

K

keys_view<> (C++20 起)

L

lazy_split_view<> (C++20 起)
less (C++20 起)
less_equal (C++20 起)
lexicographical_compare (C++20 起)

M

make_heap (C++20 起)
max (C++20 起)
max_element (C++20 起)
merge (C++20 起)
merge_result<> (C++20 起)
min (C++20 起)
min_element (C++20 起)
min_max_result<> (C++20 起)
minmax (C++20 起)
minmax_element (C++20 起)
minmax_element_result<> (C++20 起)
minmax_result<> (C++20 起)
mismatch (C++20 起)
mismatch_result<> (C++20 起)
move (C++20 起)
move_backward (C++20 起)
move_backward_result<> (C++20 起)
move_result<> (C++20 起)

N

next (C++20 起)
next_permutation (C++20 起)
next_permutation_result<> (C++20 起)
none_of (C++20 起)
not_equal_to (C++20 起)
nth_element (C++20 起)

O

output_range<> (C++20 起)
owning_view<> (C++20 起)

P

partial_sort (C++20 起)
partial_sort_copy (C++20 起)
partial_sort_copy_result<> (C++20 起)
partition (C++20 起)
partition_copy (C++20 起)
partition_copy_result<> (C++20 起)
partition_point (C++20 起)
pop_heap (C++20 起)
prev (C++20 起)
prev_permutation (C++20 起)
prev_permutation_result<> (C++20 起)
push_heap (C++20 起)

R

random_access_range<> (C++20 起)
range<> (C++20 起) (C++20 起)
range_difference_t<> (C++20 起)
range_reference_t<> (C++20 起)
range_rvalue_reference_t<> (C++20 起)
range_size_t<> (C++20 起)
range_value_t<> (C++20 起)
rbegin (C++20 起)
ref_view<> (C++20 起)
remove (C++20 起)
remove_copy (C++20 起)
remove_copy_if (C++20 起)
remove_copy_if_result<> (C++20 起)
remove_copy_result<> (C++20 起)
remove_if (C++20 起)
rend (C++20 起)
replace (C++20 起)
replace_copy (C++20 起)
replace_copy_if (C++20 起)
replace_copy_if_result<> (C++20 起)
replace_copy_result<> (C++20 起)
replace_if (C++20 起)
reverse (C++20 起)
reverse_copy (C++20 起)
reverse_copy_result<> (C++20 起)
reverse_view<> (C++20 起)
rotate (C++20 起)
rotate_copy (C++20 起)
rotate_copy_result<> (C++20 起)

S

sample (C++20 起)
search (C++20 起)
search_n (C++20 起)
sentinel_t<> (C++20 起)
set_difference (C++20 起)
set_difference_result<> (C++20 起)
set_intersection (C++20 起)
set_intersection_result<> (C++20 起)
set_symmetric_difference (C++20 起)
set_symmetric_difference_result<> (C++20 起)
set_union (C++20 起)
set_union_result<> (C++20 起)
shuffle (C++20 起)
single_view<> (C++20 起)
size (C++20 起)
sized_range<> (C++20 起)
sort (C++20 起)
sort_heap (C++20 起)
split_view<> (C++20 起)
ssize (C++20 起)
stable_partition (C++20 起)
stable_sort (C++20 起)
starts_with (C++23 起)
subrange<> (C++20 起)
subrange_kind (C++20 起)
swap (C++20 起)
swap_ranges (C++20 起)
swap_ranges_result<> (C++20 起)

T

take_view<> (C++20 起)
take_while_view<> (C++20 起)
transform (C++20 起)
transform_view<> (C++20 起)

U

unary_transform_result<> (C++20 起)
uninitialized_copy (C++20 起)
uninitialized_copy_n (C++20 起)
uninitialized_copy_n_result<> (C++20 起)
uninitialized_copy_result<> (C++20 起)
uninitialized_default_construct (C++20 起)
uninitialized_default_construct_n (C++20 起)
uninitialized_fill (C++20 起)
uninitialized_fill_n (C++20 起)
uninitialized_move (C++20 起)
uninitialized_move_n (C++20 起)
uninitialized_move_n_result<> (C++20 起)
uninitialized_move_result<> (C++20 起)
uninitialized_value_construct (C++20 起)
uninitialized_value_construct_n (C++20 起)
unique (C++20 起)
unique_copy (C++20 起)
unique_copy_result<> (C++20 起)

V

values_view<> (C++20 起)
view<> (C++20 起)
view_base (C++20 起)
view_interface<> (C++20 起)
viewable_range<> (C++20 起)
▶ views (C++20 起)

W

wistream_view<> (C++20 起)

Z

zip_transform_view<> (C++23 起)
zip_view<> (C++23 起)


std::regex_constants 符号索引

< cpp‎ | symbol index

此页面尝试列出所有来自标准库，在命名空间 std::regex_constants:: 中的可用符号。符号书写如下：

  • 函数名带 () 。
  • 模板名带 <> 。

A B C E F G I M N O S

A

awk (C++11 起)

B

basic (C++11 起)

C

collate (C++11 起)

E

ECMAScript (C++11 起)
egrep (C++11 起)
error_backref (C++11 起)
error_badbrace (C++11 起)
error_badrepeat (C++11 起)
error_brace (C++11 起)
error_brack (C++11 起)
error_collate (C++11 起)
error_complexity (C++11 起)
error_ctype (C++11 起)
error_escape (C++11 起)
error_paren (C++11 起)
error_range (C++11 起)
error_space (C++11 起)
error_stack (C++11 起)
error_type (C++11 起)
extended (C++11 起)

F

format_default (C++11 起)
format_first_only (C++11 起)
format_no_copy (C++11 起)
format_sed (C++11 起)

G

grep (C++11 起)

I

icase (C++11 起)

M

match_any (C++11 起)
match_continuous (C++11 起)
match_default (C++11 起)
match_flag_type (C++11 起)
match_not_bol (C++11 起)
match_not_bow (C++11 起)
match_not_eol (C++11 起)
match_not_eow (C++11 起)
match_not_null (C++11 起)
match_prev_avail (C++11 起)
multiline (C++17 起)

N

nosubs (C++11 起)

O

optimize (C++11 起)

S

syntax_option_type (C++11 起)


std::rel_ops 符号索引

< cpp‎ | symbol index

无来自标准库的可用于命名空间 std::rel_ops:: 的标识符。

此命名空间为自动生成比较运算符而存在，并且因为三路比较运算符而在 C++20 中被弃用。

参阅

operator!=operator>operator<=operator>=
(C++20 中弃用)
 自动生成基于用户定义的 operator== 和 operator< 的比较运算符
(函数模板)


std::literals::string_literals 符号索引

< cpp‎ | symbol index

此页面尝试列出所有来自标准库，可用于命名空间 std::literals::string_literals:: 的符号。符号以下列方式书写：

  • 函数名带 () 。
  • 模板带 <> 。

注解

这些运算符声明于命名空间 std::literals::string_literals ，其中 literals 与 string_literals 都是内联命名空间。对这些运算符的访问能用 using namespace std::literals 、 using namespace std::string_literals 及 using namespace std::literals::string_literals 获得。

std::chrono::duration 亦定义 operator""s 以表示字面量的秒，但它是算术字面量： 10.0s 与 10s 是十秒，但 "10"s 是字符串。

S

S

s (C++14 起)


std::literals::string_view_literals 符号索引

< cpp‎ | symbol index

此页面试图列出所有来自标准库，可用于命名空间 std::literals::string_view_literals:: 的符号。符号以下列方式书写：

  • 函数名带 () 。
  • 模板带 <> 。

注解

这些运算符声明于命名空间 std::literals::string_view_literals ，其中 literals 和 string_view_literals 均为内联命名空间。能以 using namespace std::literals 、 using namespace std::string_view_literals 和 using namespace std::literals::string_view_literals 获得对这些运算符的访问。

S

S

sv (C++17 起)


std::this_thread 符号索引

< cpp‎ | symbol index

此页面尝试列出所有来自标准库，在命名空间 std::this_thread:: 中的可用符号。符号书写如下：

  • 函数名带 () 。
  • 模板名带 <> 。

G S Y

G

get_id() (C++11 起)

S

sleep_for<>() (C++11 起)
sleep_until<>() (C++11 起)

Y

yield() (C++11 起)


std::ranges::views 符号索引

< cpp‎ | symbol index

此页面试图列出所有来自标准库，可用于命名空间 std::ranges::views:: 的符号。符号以下列方式书写：

  • 函数名带 () 。
  • 模板带 <> 。

注解

能用 std::views 访问 std::ranges::views 。

A C D E F I J K L R S T V Z

A

adjacent (C++23 起)
adjacent_transform (C++23 起)
all (C++20 起)
all_t (C++20 起)

C

common (C++20 起)
counted (C++20 起)

D

drop (C++20 起)
drop_while (C++20 起)

E

elements<> (C++20 起)
empty<> (C++20 起)

F

filter (C++20 起)

I

iota (C++20 起)
istream<> (C++20 起)

J

join (C++20 起)

K

keys (C++20 起)

L

lazy_split (C++20 起)

R

reverse (C++20 起)

S

single (C++20 起)
split (C++20 起)

T

take (C++20 起)
take_while (C++20 起)
transform (C++20 起)

V

values (C++20 起)

Z

zip (C++23 起)
zip_transform (C++23 起)


符号索引（被移除）

< cpp‎ | symbol index

此页面尝试列出所有可用于标准库，在命名空间 std:: 或在有作用域枚举或类的作用域中，但在下列标准中移除的标识符。符号书写如下：

  • 函数名带有 () 。
  • 模板名带有 <> 。

仍在其他类型中可用的成员名不列于此。

C++14 中移除

gets() (C++11 中弃用)

C++17 中移除

auto_ptr<> (C++11 中弃用)
binary_function<> (C++11 中弃用)
bind1st<>() (C++11 中弃用)
bind2nd<>() (C++11 中弃用)
binder1st<> (C++11 中弃用)
binder2nd<> (C++11 中弃用)
const_mem_fun_ref_t<> (C++11 中弃用)
const_mem_fun_t<> (C++11 中弃用)
const_mem_fun1_ref_t<> (C++11 中弃用)
const_mem_fun1_t<> (C++11 中弃用)
get_unexpected() (C++11 起)(C++11 中弃用)
mem_fun<>() (C++11 中弃用)
mem_fun_ref<>() (C++11 中弃用)
mem_fun_ref_t<> (C++11 中弃用)
mem_fun_t<> (C++11 中弃用)
mem_fun1_ref_t<> (C++11 中弃用)
mem_fun1_t<> (C++11 中弃用)
pointer_to_binary_function<> (C++11 中弃用)
pointer_to_unary_function<> (C++11 中弃用)
ptr_fun<>() (C++11 中弃用)
random_shuffle<>() (C++14 中弃用)
set_unexpected() (C++11 中弃用)
unary_function<> (C++11 中弃用)
unexpected() (C++11 中弃用)
unexpected_handler (C++11 中弃用)

成员名

io_state (C++98 中弃用)
open_mode (C++98 中弃用)
seek_dir (C++98 中弃用)
stossc() (C++98 中弃用)

C++20 中移除

binary_negate<> (C++17 中弃用)
get_temporary_buffer<>() (C++17 中弃用)
is_literal_type<> (C++11 起)(C++17 中弃用)
is_literal_type_v<> (C++17 起)(C++17 中弃用)
not1<>() (C++17 中弃用)
not2<>() (C++17 中弃用)
raw_storage_iterator<> (C++17 中弃用)
result_of<> (C++11 起)(C++17 中弃用)
result_of_t<> (C++14 起)(C++17 中弃用)
return_temporary_buffer<>() (C++17 中弃用)
unary_negate<> (C++17 中弃用)
uncaught_exception() (C++17 中弃用)

成员名

argument_type (C++17 中弃用)
first_argument_type (C++17 中弃用)
second_argument_type (C++17 中弃用)

C++23 中移除

declare_no_pointers() (C++11 起)
declare_reachable() (C++11 起)
get_pointer_safety() (C++11 起)
pointer_safety (C++11 起)
undeclare_no_pointers() (C++11 起)
undeclare_reachable<>() (C++11 起)

成员名

preferred (C++11 起)
strict (C++11 起)


线程支持库

< cpp

C++ 包含线程、互斥、条件变量和future的内建支持。

线程

线程使得程序能在数个处理器核心同时执行。

定义于头文件 <thread>
thread
(C++11)
 管理单独的线程
(类)
jthread
(C++20)
 有自动合并和取消支持的 std::thread
(类)
管理当前线程的函数
定义于命名空间 this_thread
yield
(C++11)
 建议实现重新调度各执行线程
(函数)
get_id
(C++11)
 返回当前线程的线程 id
(函数)
sleep_for
(C++11)
 使当前线程的执行停止指定的时间段
(函数)
sleep_until
(C++11)
 使当前线程的执行停止直到指定的时间点
(函数)

线程取消

定义于头文件 <stop_token>
stop_token (C++20) | 查询是否已经做出 std::jthread 取消请求的接口 (类)
stop_source (C++20) | 表示请求停止一个或多个 std::jthread 的类 (类)
stop_callback (C++20) | 在 std::jthread 取消上注册回调的接口 (类模板)
 (C++20 起)

缓存大小访问

定义于头文件 <new>
hardware_destructive_interference_sizehardware_constructive_interference_size
(C++17)
 避免假共享的最小偏移
促使真共享的最大偏移
(常量)

互斥

互斥算法避免多个线程同时访问共享资源。这会避免数据竞争，并提供线程间的同步支持。

定义于头文件 <mutex>
mutex
(C++11)
 提供基本互斥设施
(类)
timed_mutex
(C++11)
 提供互斥设施，实现有时限锁定
(类)
recursive_mutex
(C++11)
 提供能被同一线程递归锁定的互斥设施
(类)
recursive_timed_mutex
(C++11)
 提供能被同一线程递归锁定的互斥设施，并实现有时限锁定
(类)
定义于头文件 <shared_mutex>
shared_mutex
(C++17)
 提供共享互斥设施
(类)
shared_timed_mutex
(C++14)
 提供共享互斥设施并实现有时限锁定
(类)
通用互斥管理
定义于头文件 <mutex>
lock_guard
(C++11)
 实现严格基于作用域的互斥体所有权包装器
(类模板)
scoped_lock
(C++17)
 用于多个互斥体的免死锁 RAII 封装器
(类模板)
unique_lock
(C++11)
 实现可移动的互斥体所有权包装器
(类模板)
shared_lock
(C++14)
 实现可移动的共享互斥体所有权封装器
(类模板)
defer_lock_ttry_to_lock_tadopt_lock_t
(C++11)(C++11)(C++11)
 用于指定锁定策略的标签类型
(类)
defer_locktry_to_lockadopt_lock
(C++11)(C++11)(C++11)
 用于指定锁定策略的标签常量
(常量)
通用锁定算法
try_lock
(C++11)
 试图通过重复调用 try_lock 获得互斥体的所有权
(函数模板)
lock
(C++11)
 锁定指定的互斥体，若任何一个不可用则阻塞
(函数模板)
单次调用
once_flag
(C++11)
 确保 call_once 只调用函数一次的帮助对象
(类)
call_once
(C++11)
 仅调用函数一次，即使从多个线程调用
(函数模板)

条件变量

条件变量是允许多个线程相互交流的同步原语。它允许一定量的线程等待（可以定时）另一线程的提醒，然后再继续。条件变量始终关联到一个互斥。

定义于头文件 <condition_variable>
condition_variable (C++11) | 提供与 std::unique_lock 关联的条件变量 (类)
condition_variable_any (C++11) | 提供与任何锁类型关联的条件变量 (类)
notify_all_at_thread_exit (C++11) | 安排到在此线程完全结束时对 notify_all 的调用 (函数)
cv_status (C++11) | 列出条件变量上定时等待的可能结果 (枚举)

信号量

信号量 (semaphore) 是一种轻量的同步原件，用于制约对共享资源的并发访问。在可以使用两者时，信号量能比条件变量更有效率。

定义于头文件 <semaphore>
counting_semaphore (C++20) | 实现非负资源计数的信号量 (类模板)
binary_semaphore (C++20) | 仅拥有二个状态的信号量 (typedef)

闩与屏障

闩 (latch) 与屏障 (barrier) 是线程协调机制，允许任何数量的线程阻塞直至期待数量的线程到达该屏障。闩不能复用，屏障能重复使用。

定义于头文件 <latch>
latch (C++20) | 单次使用的线程屏障 (类)
定义于头文件 <barrier>
barrier (C++20) | 可复用的线程屏障 (类模板)

 (C++20 起)

Future

标准库提供了一些工具来获取异步任务（即在单独的线程中启动的函数）的返回值，并捕捉其所抛出的异常。这些值在共享状态中传递，其中异步任务可以写入其返回值或存储异常，而且可以由持有该引用该共享态的 std::future 或 std::shared_future 实例的线程检验、等待或是操作这个状态。

定义于头文件 <future>
promise
(C++11)
 存储一个值以进行异步获取
(类模板)
packaged_task
(C++11)
 打包一个函数，存储其返回值以进行异步获取
(类模板)
future
(C++11)
 等待被异步设置的值
(类模板)
shared_future
(C++11)
 等待被异步设置的值（可能为其他 future 所引用）
(类模板)
async
(C++11)
 异步运行一个函数（有可能在新线程中执行），并返回保有其结果的 std::future
(函数模板)
launch
(C++11)
 指定 std::async 所用的运行策略
(枚举)
future_status
(C++11)
 指定在 std::future 和 std::shared_future 上的定时等待的结果
(枚举)
Future 错误
future_error
(C++11)
 报告与 future 或 promise 有关的错误
(类)
future_category
(C++11)
 鉴别 future 错误类别
(函数)
future_errc
(C++11)
 鉴别 future 错误码
(枚举)

参阅


std::async

< cpp‎ | thread
定义于头文件 <future>
(1)
template< class Function, class... Args>

std::future < std::result_of_t < std::decay_t <Function>( std::decay_t <Args>...)>>

async( Function&& f, Args&&... args );
 (C++11 起)
(C++17 前)
template< class Function, class... Args>

std::future <std::invoke_result_t< std::decay_t <Function>,
std::decay_t <Args>...>>

async( Function&& f, Args&&... args );
 (C++17 起)
(C++20 前)
template< class Function, class... Args>

[[nodiscard]]
std::future <std::invoke_result_t< std::decay_t <Function>,
std::decay_t <Args>...>>

async( Function&& f, Args&&... args );
 (C++20 起)
(2)
template< class Function, class... Args >

std::future < std::result_of_t < std::decay_t <Function>( std::decay_t <Args>...)>>

async( std::launch policy, Function&& f, Args&&... args );
 (C++11 起)
(C++17 前)
template< class Function, class... Args >

std::future <std::invoke_result_t< std::decay_t <Function>,
std::decay_t <Args>...>>

async( std::launch policy, Function&& f, Args&&... args );
 (C++17 起)
(C++20 前)
template< class Function, class... Args >

[[nodiscard]]
std::future <std::invoke_result_t< std::decay_t <Function>,
std::decay_t <Args>...>>

async( std::launch policy, Function&& f, Args&&... args );
 (C++20 起)

函数模板 async 异步地运行函数 f （潜在地在可能是线程池一部分的分离线程中），并返回最终将保有该函数调用结果的 std::future 。

1) 表现如同以 policy 为 std::launch::async | std::launch::deferred 调用 (2) 。换言之， f 可能执行于另一线程，或者它可能在查询产生的 std::future 的值时同步运行。
2) 按照特定的执行策略 policy ，以参数 args 调用函数 f ：
  • 若设置 async 标志（即 (policy & std::launch::async ) != 0 ），则 async 在新的执行线程（初始化所有线程局域对象后）执行可调用对象 f ，如同产出 std::thread ( std::forward <F>(f), std::forward <Args>(args)...) ，除了若 f 返回值或抛出异常，则于可通过 async 返回给调用方的 std::future 访问的共享状态存储结果。
  • 若设置 deferred 标志（即 (policy & std::launch::deferred ) != 0 ），则 async 以同 std::thread 构造函数的方式转换 f 与 args... ，但不产出新的执行线程。而是进行惰性求值：在 async 所返回的 std::future 上首次调用非定时等待函数，将导致在当前线程（不必是最初调用 std::async 的线程）中，以 args... （作为右值传递）的副本调用 f （亦作为右值）的副本。将结果或异常置于关联到该 future 的共享状态，然后才令它就绪。对同一 std::future 的所有后续访问都会立即返回结果。
  • 若 policy 中设置了 std::launch::async 和 std::launch::deferred 两个标志，则进行异步执行还是惰性求值取决于实现。
  • 若 policy 中未设置 std::launch::async 或 std::launch::deferred 或任何实现定义策略标志，则行为未定义。

任何情况下，对 std::async 的调用同步于（定义于 std::memory_order ）对 f 的调用，且 f 的完成先序于令共享状态就绪。若选择 async 策略，则关联线程的完成同步于首个等待于共享状态上的函数的成功返回，或最后一个释放共享状态的函数的返回，两者的先到来者。若 std::decay <Function>::type 或 std::decay <Args>::type 中的每个类型不能从其对应的实参构造，则程序为谬构。

参数

f - 要调用的可调用 (Callable) 对象
args... - 传递给 f 的参数
policy - 位掩码值，每个单独位控制允许的执行方法
位 | 解释
std::launch::async | 启用异步求值
std::launch::deferred | 启用惰性求值

返回值

指代此次调用 std::async 所创建的共享状态的 std::future 。

异常

若运行策略等于 std::launch::async 且实现无法开始新线程（该情况下，若运行策略为 async|deferred 或设置了额外位，则它将回退到 deferred 或实现定义的策略），则抛出以 std::errc::resource_unavailable_try_again 为错误条件的 std::system_error ，或者若无法分配内部数据结构所用的内存，则为 std::bad_alloc 。

注解

实现可以通过在默认运行策略中启用额外（实现定义的）位，扩展 std::async 第一重载的行为。

实现定义的运行策略的例子是同步策略（在 async 调用内立即执行）和任务策略（类似 async ，但不清理线程局域对象）。

若从 std::async 获得的 std::future 未被移动或绑定到引用，则在完整表达式结尾， std::future 的析构函数将阻塞直至异步计算完成，实质上令如下代码同步：

std::async(std::launch::async, []{ f(); }); // 临时量的析构函数等待 f()
std::async(std::launch::async, []{ g(); }); // f() 完成前不开始

（注意，以调用 std::async 以外的方式获得的 std::future 的析构函数决不阻塞）

示例

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <future>
#include <string>
#include <mutex>

std::mutex m;
struct X {
    void foo(int i, const std::string& str) {
        std::lock_guard<std::mutex> lk(m);
        std::cout << str << ' ' << i << '\n';
    }
    void bar(const std::string& str) {
        std::lock_guard<std::mutex> lk(m);
        std::cout << str << '\n';
    }
    int operator()(int i) {
        std::lock_guard<std::mutex> lk(m);
        std::cout << i << '\n';
        return i + 10;
    }
};

template <typename RandomIt>
int parallel_sum(RandomIt beg, RandomIt end)
{
    auto len = end - beg;
    if (len < 1000)
        return std::accumulate(beg, end, 0);

    RandomIt mid = beg + len/2;
    auto handle = std::async(std::launch::async,
                             parallel_sum<RandomIt>, mid, end);
    int sum = parallel_sum(beg, mid);
    return sum + handle.get();
}

int main()
{
    std::vector<int> v(10000, 1);
    std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << '\n';

    X x;
    // 以默认策略调用 x.foo(42, "Hello") ：
    // 可能同时打印 "Hello 42" 或延迟执行
    auto a1 = std::async(&X::foo, &x, 42, "Hello");
    // 以 deferred 策略调用 x.bar("world!")
    // 调用 a2.get() 或 a2.wait() 时打印 "world!"
    auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!");
    // 以 async 策略调用 X()(43) ：
    // 同时打印 "43"
    auto a3 = std::async(std::launch::async, X(), 43);
    a2.wait();                     // 打印 "world!"
    std::cout << a3.get() << '\n'; // 打印 "53"
} // 若 a1 在此点未完成，则 a1 的析构函数在此打印 "Hello 42"

可能的输出：

The sum is 10000
43
world!
53
Hello 42

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2021 | C++11 | 返回类型不正确， deferred 的情况下参数的值类别不明 | 更正返回类型，明确使用右值
LWG 2120 | C++11 | 未设置标准或实现定义的策略的情况下行为不明 | 行为未定义
LWG 3476 | C++11 | 要求 Function 与 Args... 为可移动构造 (MoveConstructible) 而无指定的额外移动构造 | 移除要求


std::barrier

< cpp‎ | thread
定义于头文件 <barrier> |
template<class CompletionFunction = /* see below */> class barrier; | (C++20 起)

类模板 std::barrier 提供允许至多为期待数量的线程阻塞直至期待数量的线程到达该屏障。不同于 std::latch ，屏障可重用：一旦到达的线程从屏障阶段的同步点除阻，则可重用同一屏障。

屏障对象的生存期由屏障阶段的序列组成。每个阶段定义一个阶段同步点。在阶段中到达屏障的线程能通过调用 wait 在阶段同步点上阻塞，而且将保持阻塞直至运行阶段完成步骤。

屏障阶段由以下步骤组成：

  1. 每次调用 arrive 或 arrive_and_drop 减少期待计数。
  2. 期待计数抵达零时，运行阶段完成步骤。完成步骤调用完成函数对象，并除阻所有在阶段同步点上阻塞的线程。完成步骤的结束强先发生于所有从完成步骤所除阻的调用的返回。
    • 对于特化 std::barrier<> （使用默认模板实参），完成步骤作为对 arrive 或 arrive_and_drop 的导致期待计数抵达零的调用的一部分运行。
    • 对于其他特化，完成步骤在该阶段期间到达屏障的线程之一上运行。而若在完成步骤中调用屏障对象的 wait 以外的成员函数，则行为未定义。
  3. 完成步骤结束时，重置期待计数为构造中指定的值，可能为 arrive_and_drop 调用所调整，并开始下一阶段。

同时调用 barrier 的成员函数，除了析构函数，不引入数据竞争。

模板形参

CompletionFunction - 函数对象类型
-
CompletionFunction 必须满足可移动构造 (MoveConstructible) 和 可析构 (Destructible) 的要求。std::is_nothrow_invocable_v<CompletionFunction&> 必须为 true 。

CompletionFunction 的默认模板实参是未指定的函数对象类型，额外满足可默认构造 (DefaultConstructible) 的要求。以无参数调用其左值无效果。

每个屏障对象表现为如同它保有一个 CompletionFunction 类型的非静态数据成员 completion_ ，并在每个阶段完成步骤通过 completion_() 调用它。

成员类型

名称 | 定义
arrival_token | 未指定的对象类型，符合可移动构造 (MoveConstructible) 、可移动赋值 (MoveAssignable) 及可析构 (Destructible) 的要求

成员函数

(构造函数)
 构造 barrier
(公开成员函数)
(析构函数)
 销毁 barrier
(公开成员函数)
operator=
[被删除]
 barrier 不可赋值
(公开成员函数)
arrive
 到达屏障并减少期待计数
(公开成员函数)
wait
 在阶段同步点阻塞，直至运行其阶段完成步骤
(公开成员函数)
arrive_and_wait
 到达屏障并把期待计数减少一，然后阻塞直至当前阶段完成
(公开成员函数)
arrive_and_drop
 将后继阶段的初始期待计数和当前阶段的期待计数均减少一
(公开成员函数)
常量
max
[静态]
 实现所支持的期待计数的最大值
(公开静态成员函数)

示例

本节未完成
原因：暂无示例

参阅

latch
(C++20)
 单次使用的线程屏障
(类)


std::barrier<CompletionFunction>::arrive

< cpp‎ | thread‎ | barrier
[[nodiscard]] arrival_token arrive( std::ptrdiff_t n = 1 ); | (C++20 起)

构造一个于当前阶段的阶段同步点关联的 arrival_token 对象，然后将期待计数减少 n 。

此函数原子地执行。对此函数的调用强先发生于当前阶段的阶段完成步骤的开始。

若 n 小于或等于零，或大于当前屏障阶段的期待计数，则行为未定义。

参数

n - 要减少期待计数的值

返回值

构造的 arrival_token 对象。

异常

错误时抛出 std::system_error ，带有对互斥体类型允许的错误码。

注解

此函数能导致当前阶段的阶段完成步骤开始。

示例

本节未完成
原因：暂无示例

参阅

wait
 在阶段同步点阻塞，直至运行其阶段完成步骤
(公开成员函数)


std::barrier<CompletionFunction>::arrive_and_drop

< cpp‎ | thread‎ | barrier
void arrive_and_drop(); | (C++20 起)

将所有后继阶段的初始期待计数减少一，然后将当前阶段的期待计数减少一。

此函数原子地执行。对此函数的调用强先发生于当前阶段的阶段完成步骤的开始。

若当前阶段的期待计数为零则行为未定义。

参数

（无）

返回值

（无）

异常

错误时抛出 std::system_error ，带有对互斥体类型允许的错误码。

注解

此函数能导致当前阶段的阶段完成步骤开始。

若调用此函数前当前期待计数为零，则所有后继阶段的初始期待计数亦为零，这表示无法重用该 barrier 。

示例

本节未完成
原因：暂无示例


std::barrier<CompletionFunction>::arrive_and_wait

< cpp‎ | thread‎ | barrier
void arrive_and_wait(); | (C++20 起)

原子地将期待计数减少 1 ，然后在当前阶段的同步点阻塞直至运行当前阶段的阶段完成步骤。等价于 wait(arrive()); 。

若当前阶段的期待计数为零则行为未定义。

参数

（无）

返回值

（无）

异常

错误时抛出 std::system_error ，带有对互斥体类型允许的错误码。

注解

若在此函数的调用中当前期待计数被减少为零，则运行阶段完成步骤而此函数不阻塞。

若调用此函数前当前期待计数为零，则所有后继阶段的初始期待计数亦为零，这表示无法重用该 barrier 。

示例

本节未完成
原因：暂无示例


std::barrier<CompletionFunction>::barrier

< cpp‎ | thread‎ | barrier
constexpr explicit barrier( std::ptrdiff_t expected,
CompletionFunction f = CompletionFunction());
 (1) (C++20 起)
barrier( const barrier & ) = delete;
 (2) (C++20 起)
1) 设置每个阶段的初始期待计数及首阶段的当前期待计数为 expected ，以 std::move(f) 初始化完成函数对象，然后开始第一阶段。若 expected 为负或大于 max() 则行为未定义。
2) 复制构造函数被删除。 barrier 既不可复制亦不可移动。

参数

expected | - | 期待计数的初值
f | - | 要在在阶段完成步骤调用的完成函数对象

异常

1) 任何 CompletionFunction 的移动构造函数所抛的异常。

注解

容许 expected 为零。然而在这种 barrier 上调用析构函数以外的任何非静态成员函数导致未定义行为。换言之，这种 barrier 只能被销毁。


std::barrier<CompletionFunction>::max

< cpp‎ | thread‎ | barrier
static constexpr std::ptrdiff_t max() noexcept; | (C++20 起)

返回实现所支持的期待计数的最大值。

参数

（无）

返回值

实现所支持的期待计数的最大值。


std::barrier<CompletionFunction>::wait

< cpp‎ | thread‎ | barrier
void wait( arrival_token&& arrival ) const; | (C++20 起)

若 arrival 与 *this 的当前阶段的阶段同步点关联，则在与 arrival 关联的阶段同步点阻塞直至该同步点的阶段完成步骤运行。

否则，若 arrival 与 *this 的立即前一阶段的解读那同步点关联，则立即返回。

否则，即若 arrival 与 *this 的较早阶段或与 *this 以外的屏障对象的任何阶段的阶段同步点关联，行为未定义。

参数

arrival - 由先前在同一 barrier 上调用 arrive 获得的 arrival_token

返回值

（无）

异常

错误时抛出 std::system_error ，带有对互斥体类型允许的错误码。

示例

本节未完成
原因：暂无示例

参阅

arrive
 到达屏障并减少期待计数
(公开成员函数)


std::barrier<CompletionFunction>::~barrier

< cpp‎ | thread‎ | barrier
~barrier(); | (C++20 起)

销毁 barrier 。

注解

若有任何线程在同时调用 barrier 的成员函数则行为未定义。


std::call_once

< cpp‎ | thread
定义于头文件 <mutex> |
template< class Callable, class... Args > void call_once( std::once_flag & flag, Callable&& f, Args&&... args ); | (C++11 起)

准确执行一次可调用 (Callable) 对象 f ，即使同时从多个线程调用。

细节为：

  • 若在调用 call_once 的时刻， flag 指示已经调用了 f ，则 call_once 立即返回（称这种对 call_once 的调用为消极）。
  • 否则， call_once 以参数 std::forward <Args>(args)... 调用 std::forward <Callable>(f) （如同用 std::invoke ）。不同于 std::thread 构造函数或 std::async ，不移动或复制参数，因为不需要转移它们到另一执行线程（称这种对 call_once 的调用为积极）。
  • 若该调用抛异常，则传播异常给 call_once 的调用方，并且不翻转 flag ，以令其他调用将得到尝试（称这种对 call_once 的调用为异常）。
  • 若该调用正常返回（称这种对 call_once 的调用为返回），则翻转 flag ，并保证以同一 flag 对 call_once 的其他调用为消极。

同一 flag 上的所有积极调用组成单独全序，它们由零或多个异常调用后随一个返回调用组成。该顺序中，每个积极调用的结尾同步于下个积极调用。

从返回调用的返回同步于同一 flag 上的所有消极调用：这表示保证所有对 call_once 的同时调用都观察到积极调用所做的任何副效应，而无需额外同步。

参数

flag | - | 对象，对于它只有一个函数得到执行
f | - | 要调用的可调用 (Callable) 对象
args... | - | 传递给函数的参数

返回值

（无）

异常

  • 若任何条件阻止对 call_once 的调用按规定执行，则抛出 std::system_error
  • 任何 f 所抛的异常

注解

若对 call_once 的同时调用传递不同的 f ，则调用哪个 f 是未指定的。被选择函数运行于与传递它的 call_once 的调用相同的线程。

即使在从多个线程调用时，也保证函数局域静态对象的初始化仅出现一次，这可能比使用 std::call_once 的等价代码更为高效。

此函数的 POSIX 类似物是 pthread_once 。

示例

#include <iostream>
#include <thread>
#include <mutex>

std::once_flag flag1, flag2;

void simple_do_once()
{
    std::call_once(flag1, [](){ std::cout << "Simple example: called once\n"; });
}

void may_throw_function(bool do_throw)
{
  if (do_throw) {
    std::cout << "throw: call_once will retry\n"; // 这会出现多于一次
    throw std::exception();
  }
  std::cout << "Didn't throw, call_once will not attempt again\n"; // 保证一次
}

void do_once(bool do_throw)
{
  try {
    std::call_once(flag2, may_throw_function, do_throw);
  }
  catch (...) {
  }
}

int main()
{
    std::thread st1(simple_do_once);
    std::thread st2(simple_do_once);
    std::thread st3(simple_do_once);
    std::thread st4(simple_do_once);
    st1.join();
    st2.join();
    st3.join();
    st4.join();

    std::thread t1(do_once, true);
    std::thread t2(do_once, true);
    std::thread t3(do_once, false);
    std::thread t4(do_once, true);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

可能的输出：

Simple example: called once
throw: call_once will retry
throw: call_once will retry
Didn't throw, call_once will not attempt again

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2442 | C++11 | 在调用前复制并/或移动参数 | 不进行复制/移动

参阅

once_flag
(C++11)
 确保 call_once 只调用函数一次的帮助对象
(类)


std::condition_variable

< cpp‎ | thread
定义于头文件 <condition_variable> |
class condition_variable; | (C++11 起)

condition_variable 类是同步原语，能用于阻塞一个线程，或同时阻塞多个线程，直至另一线程修改共享变量（条件）并通知 condition_variable 。

有意修改变量的线程必须

  1. 获得 std::mutex （常通过 std::lock_guard ）
  2. 在保有锁时进行修改
  3. 在 std::condition_variable 上执行 notify_one 或 notify_all （不需要为通知保有锁）

即使共享变量是原子的，也必须在互斥下修改它，以正确地发布修改到等待的线程。

任何有意在 std::condition_variable 上等待的线程必须

  1. 在与用于保护共享变量者相同的互斥上获得 std::unique_lock < std::mutex >
  2. 执行下列之一：
  1. 检查条件，是否为已更新或提醒它的情况
  2. 执行 wait 、 wait_for 或 wait_until ，等待操作自动释放互斥，并悬挂线程的执行。
  3. condition_variable 被通知时，时限消失或虚假唤醒发生，线程被唤醒，且自动重获得互斥。之后线程应检查条件，若唤醒是虚假的，则继续等待。
或者
  1. 使用 wait 、 wait_for 及 wait_until 的有谓词重载，它们包揽以上三个步骤

std::condition_variable 只可与 std::unique_lock < std::mutex > 一同使用；此限制在一些平台上允许最大效率。 std::condition_variable_any 提供可与任何基本可锁定 (BasicLockable) 对象，例如 std::shared_lock 一同使用的条件变量。

condition_variable 容许 wait 、 wait_for 、 wait_until 、 notify_one 及 notify_all 成员函数的同时调用。

类 std::condition_variable 是标准布局类型 (StandardLayoutType) 。它非可复制构造 (CopyConstructible) 、可移动构造 (MoveConstructible) 、可复制赋值 (CopyAssignable) 或可移动赋值 (MoveAssignable) 。

成员类型

成员类型 | 定义
native_handle_type | 实现定义

成员函数

(构造函数)
 构造对象
(公开成员函数)
(析构函数)
 析构对象
(公开成员函数)
operator=
[被删除]
 不可复制赋值
(公开成员函数)
通知
notify_one
 通知一个等待的线程
(公开成员函数)
notify_all
 通知所有等待的线程
(公开成员函数)
等待
wait
 阻塞当前线程，直到条件变量被唤醒
(公开成员函数)
wait_for
 阻塞当前线程，直到条件变量被唤醒，或到指定时限时长后
(公开成员函数)
wait_until
 阻塞当前线程，直到条件变量被唤醒，或直到抵达指定时间点
(公开成员函数)
原生句柄
native_handle
 返回原生句柄
(公开成员函数)

示例

与 std::mutex 组合使用 condition_variable ，以促进线程间交流。

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;

void worker_thread()
{
    // 等待直至 main() 发送数据
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, []{return ready;});

    // 等待后，我们占有锁。
    std::cout << "Worker thread is processing data\n";
    data += " after processing";

    // 发送数据回 main()
    processed = true;
    std::cout << "Worker thread signals data processing completed\n";

    // 通知前完成手动解锁，以避免等待线程才被唤醒就阻塞（细节见 notify_one ）
    lk.unlock();
    cv.notify_one();
}

int main()
{
    std::thread worker(worker_thread);

    data = "Example data";
    // 发送数据到 worker 线程
    {
        std::lock_guard<std::mutex> lk(m);
        ready = true;
        std::cout << "main() signals data ready for processing\n";
    }
    cv.notify_one();

    // 等候 worker
    {
        std::unique_lock<std::mutex> lk(m);
        cv.wait(lk, []{return processed;});
    }
    std::cout << "Back in main(), data = " << data << '\n';

    worker.join();
}

输出：

main() signals data ready for processing
Worker thread is processing data
Worker thread signals data processing completed
Back in main(), data = Example data after processing


std::condition_variable::condition_variable

< cpp‎ | thread‎ | condition variable

condition_variable(); | (1) | (C++11 起)
condition_variable(const condition_variable&) = delete; | (2) | (C++11 起)

1) 构造 std::condition_variable 类型对象。

2) 复制构造函数被删除。

参数

（无）

异常

1) 可能抛出 std::system_error ，其 std::error_condition 若线程无权限创建条件变量，则等于 std::errc::operation_not_permitted ，若非内存资源限制阻止此初始化，则等于 std::errc::resource_unavailable_try_again ，或其他实现定义值。

参阅


std::condition_variable::native_handle

< cpp‎ | thread‎ | condition variable

native_handle_type native_handle(); | (C++11 起)

访问 *this 的原生句柄。

此函数结果的含义和类型是实现定义的。 POSIX 系统上，这可以是 pthread_cond_t* 类型值。 Windows 系统上，这可以是 PCONDITION_VARIABLE 。

参数

（无）

返回值

此条件变量的原生句柄。

参阅

native_handle | 返回底层实现定义的线程句柄 (std::thread 的公开成员函数)
native_handle | 返回底层实现定义的线程句柄 (std::jthread 的公开成员函数)


std::condition_variable::notify_all

< cpp‎ | thread‎ | condition variable

void notify_all() noexcept; | (C++11 起)

解阻塞全部当前等待于 *this 的线程。

参数

（无）

返回值

（无）

注意

notify_one()/notify_all() 的效果与 wait()/wait_for()/wait_until() 的三个原子部分的每一者（解锁+等待、唤醒和锁定）以能看做原子变量修改顺序单独全序发生：顺序对此单独的 condition_variable 是特定的。譬如，这使得 notify_one() 不可能被延迟并解锁正好在进行 notify_one() 调用后开始等待的线程。

通知线程不必保有与等待线程所保有者相同互斥的锁；实际上这么做是劣化，因为被通知线程将立即再次阻塞，以等待通知线程释放锁。

示例

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>

std::condition_variable cv;
std::mutex cv_m; // 此互斥用于三个目的：
                 // 1) 同步到 i 的访问
                 // 2) 同步到 std::cerr 的访问
                 // 3) 为条件变量 cv
int i = 0;

void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cerr << "Waiting... \n";
    cv.wait(lk, []{return i == 1;});
    std::cerr << "...finished waiting. i == 1\n";
}

void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lk(cv_m);
        std::cerr << "Notifying...\n";
    }
    cv.notify_all();

    std::this_thread::sleep_for(std::chrono::seconds(1));

    {
        std::lock_guard<std::mutex> lk(cv_m);
        i = 1;
        std::cerr << "Notifying again...\n";
    }
    cv.notify_all();
}

int main()
{
    std::thread t1(waits), t2(waits), t3(waits), t4(signals);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

可能的输出：

Waiting...
Waiting...
Waiting...
Notifying...
Notifying again...
...finished waiting. i == 1
...finished waiting. i == 1
...finished waiting. i == 1

参阅

notify_one
 通知一个等待的线程
(公开成员函数)


std::condition_variable::notify_one

< cpp‎ | thread‎ | condition variable

void notify_one() noexcept; | (C++11 起)

若任何线程在 *this 上等待，则调用 notify_one 会解阻塞等待线程之一。

参数

（无）

返回值

（无）

注意

notify_one()/notify_all() 的效果与 wait()/wait_for()/wait_until() 的三个原子部分的每一者（解锁+等待、唤醒和锁定）以能看做原子变量修改顺序单独全序发生：顺序对此单独的 condition_variable 是特定的。譬如，这使得 notify_one() 不可能被延迟并解锁正好在进行 notify_one() 调用后开始等待的线程。

通知线程不必保有等待线程所保有的同一互斥上的锁；实际上这么做是劣化，因为被通知线程将立即再次阻塞，等待通知线程释放锁。然而一些实现（尤其是许多 pthread 的实现）辨识此情形，在通知调用中，直接从条件变量队列转移等待线程到互斥队列，而不唤醒它，以避免此“急促并等待”场景。

然而，在要求精确调度事件时，可能必须在处于锁下时通知，例如，在若满足条件则线程将退出程序，导致析构通知线程的 condition_variable 的情况下。互斥解锁之后，但在通知前的虚假唤醒可能导致通知在被销毁对象上调用。

示例

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>

std::condition_variable cv;
std::mutex cv_m;
int i = 0;
bool done = false;

void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cout << "Waiting... \n";
    cv.wait(lk, []{return i == 1;});
    std::cout << "...finished waiting. i == 1\n";
    done = true;
}

void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Notifying falsely...\n";
    cv.notify_one(); // 等待线程被通知 i == 0.
                     // cv.wait 唤醒，检查 i ，再回到等待

    std::unique_lock<std::mutex> lk(cv_m);
    i = 1;
    while (!done)
    {
        std::cout << "Notifying true change...\n";
        lk.unlock();
        cv.notify_one(); // 等待线程被通知 i == 1 ， cv.wait 返回
        std::this_thread::sleep_for(std::chrono::seconds(1));
        lk.lock();
    }
}

int main()
{
    std::thread t1(waits), t2(signals);
    t1.join();
    t2.join();
}

可能的输出：

Waiting...
Notifying falsely...
Notifying true change...
...finished waiting. i == 1

参阅

notify_all
 通知所有等待的线程
(公开成员函数)


std::condition_variable::wait

< cpp‎ | thread‎ | condition variable

void wait( std::unique_lock < std::mutex >& lock ); | (1) | (C++11 起)
template< class Predicate > void wait( std::unique_lock < std::mutex >& lock, Predicate pred ); | (2) | (C++11 起)

wait 导致当前线程阻塞直至条件变量被通知，或虚假唤醒发生，可选地循环直至满足某谓词。

1) 原子地解锁 lock ，阻塞当前执行线程，并将它添加到于 *this 上等待的线程列表。线程将在执行 notify_all() 或 notify_one() 时被解除阻塞。解阻塞时，无关乎原因， lock 再次锁定且 wait 退出。
2) 等价于
while (!pred()) {
    wait(lock);
}
此重载可用于在等待特定条件成为 true 时忽略虚假唤醒。注意进入此方法前，必须得到 lock ， wait(lock) 退出后也会重获得它，即能以 lock 为对 pred() 访问的保障。

若这些函数不能满足后置条件（ lock.owns_lock() == true 且调用方线程锁定 lock.mutex() ），则调用 std::terminate 。例如，这可能在重锁定互斥抛异常的情况下发生。

参数

lock | - | std::unique_lock < std::mutex > 类型对象，必须为当前线程所锁定
pred | - | 等待是否应该持续则返回 ​false 的谓词。 谓词函数的签名应等价于如下者： bool pred();​

返回值

（无）

异常

1) 不抛出
2) 同 (1) 但亦会传播 pred 所抛的异常

注解

若当前线程未锁定 lock.mutex() ，则调用此函数是未定义行为。

若 lock.mutex() 与所有其他当前等待在同一条件变量上的线程所用的互斥不相同，则调用此函数是未定义行为。

notify_one()/notify_all() 的效果与 wait()/wait_for()/wait_until() 的三个原子部分的每一者（解锁+等待、唤醒和锁定）以能看做原子变量修改顺序单独全序发生：顺序对此单独的 condition_variable 是特定的。譬如，这使得 notify_one() 不可能被延迟并解锁正好在进行 notify_one() 调用后开始等待的线程。

示例

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>

std::condition_variable cv;
std::mutex cv_m; // 此互斥用于三个目的：
                 // 1) 同步到 i 的访问
                 // 2) 同步到 std::cerr 的访问
                 // 3) 为条件变量 cv
int i = 0;

void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cerr << "Waiting... \n";
    cv.wait(lk, []{return i == 1;});
    std::cerr << "...finished waiting. i == 1\n";
}

void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lk(cv_m);
        std::cerr << "Notifying...\n";
    }
    cv.notify_all();

    std::this_thread::sleep_for(std::chrono::seconds(1));

    {
        std::lock_guard<std::mutex> lk(cv_m);
        i = 1;
        std::cerr << "Notifying again...\n";
    }
    cv.notify_all();
}

int main()
{
    std::thread t1(waits), t2(waits), t3(waits), t4(signals);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

可能的输出：

Waiting...
Waiting...
Waiting...
Notifying...
Notifying again...
...finished waiting. i == 1
...finished waiting. i == 1
...finished waiting. i == 1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2135 | C++11 | wait 在解锁/重锁失败时抛异常 | 调用 std::terminate

参阅

wait_for | 阻塞当前线程，直到条件变量被唤醒，或到指定时限时长后 (公开成员函数)
wait_until | 阻塞当前线程，直到条件变量被唤醒，或直到抵达指定时间点 (公开成员函数)


std::condition_variable::wait_for

< cpp‎ | thread‎ | condition variable

template< class Rep, class Period >

std::cv_status wait_for( std::unique_lock < std::mutex >& lock,

const std::chrono::duration <Rep, Period>& rel_time);
 (1) (C++11 起)
template< class Rep, class Period, class Predicate >

bool wait_for( std::unique_lock < std::mutex >& lock,
const std::chrono::duration <Rep, Period>& rel_time,

Predicate pred);
 (2) (C++11 起)
1) 原子地释放 lock ，阻塞当前线程，并将它添加到等待在 *this 上的线程列表。线程将在执行 notify_all() 或 notify_one() 时，或度过相对时限 rel_time 时被解除阻塞。它亦可被虚假地解除阻塞。解阻塞时，无关缘由，重获得 lock 并退出 wait_for() 退出。
2) 等价于 return wait_until(lock, std::chrono::steady_clock::now() + rel_time, std::move(pred)); 。此重载可用于忽略虚假唤醒。

用稳定时钟度量时长。由于调度或资源争议，此函数可能阻塞长于 timeout_duration 。

若当前线程未锁定 lock.mutex() ，则调用此函数是未定义行为。

若 lock.mutex() 与所有其他当前等待在同一条件变量上的线程所用的互斥不相同，则调用此函数是未定义行为。

若这些函数不能满足后条件（ lock.owns_lock()==true 且调用方线程锁定 lock.mutex() ），则调用 std::terminate 。例如，这可能在重锁定互斥抛异常的情况下发生。

参数

lock | - | std::unique_lock < std::mutex > 类型对象，必须被当前线程锁定
rel_time | - | 表示等待所耗的最大时间的 std::chrono::duration 类型对象。注意 rel_time 必须足够小，以在加到 std::chrono::steady_clock::now() 时不溢出。
pred | - | 是否应该持续等待则返回 ​false 的谓词。 谓词函数的签名应等价于如下者： bool pred();​

返回值

1) 若经过 rel_time 所指定的关联时限则为 std::cv_status::timeout ，否则为 std::cv_status::no_timeout 。
2) 若经过 rel_time 时限后谓词 pred 仍求值为 false 则为 false ，否则为 true 。

异常

1) 执行期间时钟、时间点或时长可能抛出的任何异常（标准库提供的时钟、时间点和时长决不抛出）
2) 同 (1) ，但亦可传播 pred 所抛的异常

注解

即使在锁定时通知，重载 (1) 在因时限退出时也不对关联谓词的状态做出保证。

notify_one()/notify_all() 的效果与 wait()/wait_for()/wait_until() 的三个原子部分的每一者（解锁+等待、唤醒和锁定）以能看做原子变量修改顺序单独全序发生：顺序对此单独的 condition_variable 是特定的。譬如，这使得 notify_one() 不可能被延迟并解锁正好在进行 notify_one() 调用后开始等待的线程。

示例

#include <iostream>
#include <atomic>
#include <condition_variable>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;

std::condition_variable cv;
std::mutex cv_m;
int i;

void waits(int idx)
{
    std::unique_lock<std::mutex> lk(cv_m);
    if(cv.wait_for(lk, idx*100ms, []{return i == 1;}))
        std::cerr << "Thread " << idx << " finished waiting. i == " << i << '\n';
    else
        std::cerr << "Thread " << idx << " timed out. i == " << i << '\n';
}

void signals()
{
    std::this_thread::sleep_for(120ms);
    std::cerr << "Notifying...\n";
    cv.notify_all();
    std::this_thread::sleep_for(100ms);
    {
        std::lock_guard<std::mutex> lk(cv_m);
        i = 1;
    }
    std::cerr << "Notifying again...\n";
    cv.notify_all();
}

int main()
{
    std::thread t1(waits, 1), t2(waits, 2), t3(waits, 3), t4(signals);
    t1.join(); t2.join(), t3.join(), t4.join();
}

输出：

Thread 1 timed out. i == 0
Notifying...
Thread 2 timed out. i == 0
Notifying again...
Thread 3 finished waiting. i == 1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2093 | C++11 | 规范中缺失超时相关异常 | 已提及
LWG 2135 | C++11 | wait_for 在解锁/重锁失败时抛异常 | 调用 std::terminate

参阅

wait | 阻塞当前线程，直到条件变量被唤醒 (公开成员函数)
wait_until | 阻塞当前线程，直到条件变量被唤醒，或直到抵达指定时间点 (公开成员函数)


std::condition_variable::wait_until

< cpp‎ | thread‎ | condition variable

template< class Clock, class Duration >

std::cv_status
wait_until( std::unique_lock < std::mutex >& lock,

const std::chrono::time_point <Clock, Duration>& timeout_time );
 (1) (C++11 起)
template< class Clock, class Duration, class Pred >

bool wait_until( std::unique_lock < std::mutex >& lock,
const std::chrono::time_point <Clock, Duration>& timeout_time,

Pred pred );
 (2) (C++11 起)

wait_until 导致当前线程阻塞直至通知条件变量、抵达指定时间或虚假唤醒发生，可选的循环直至满足某谓词。

1) 原子地释放 lock ，阻塞当前线程，并将它添加到等待在 *this 上的线程列表。将在执行 notify_all() 或 notify_one() 时，或抵达绝对时间点 timeout_time 时解除阻塞线程。亦可能虚假地解除阻塞。解除阻塞时，无关缘由，重获得 lock 并退出 wait_for() 。
2) 等价于
while (!pred()) {
    if (wait_until(lock, timeout_time) == std::cv_status::timeout) {
        return pred();
    }
}
return true;
此重载可用于忽略虚假唤醒。

若当前线程未锁定 lock.mutex() ，则调用此函数是未定义行为。

若 lock.mutex() 与所有其他当前等待在同一条件变量上的线程所用的互斥不相同，则调用此函数是未定义行为。

若这些函数不能满足后条件（ lock.owns_lock()==true 且调用方线程锁定 lock.mutex() ），则调用 std::terminate 。例如，这可能在重锁定互斥抛异常的情况下发生。

Clock 必须符合时钟 (Clock) 要求。若 std::chrono::is_clock_v<Clock> 为 false 则程序为非良构。 (C++20 起)

参数

lock | - | std::unique_lock < std::mutex > 类型对象，必须被当前线程锁定
timeout_time | - | 表示停止等待时间的 std::chrono::time_point 类型对象
pred | - | 是否应该持续等待则返回 ​false 的谓词。 谓词函数的签名应等价于如下者： bool pred();​

返回值

1) 若抵达 timeout_time 指定的的绝对时间点则为 std::cv_status::timeout ，否则为 std::cv_status::no_timeout 。
2) 若度过 timeout_time 时限后 pred 仍求值为 false 则为 false ，否则为 true 。若已度过时限，则求值并返回 pred 的结果。

异常

1) 执行期间时钟、时间点或时长可能抛出的任何异常（标准库提供的时钟、时间点和时长决不抛出）
2) 同 (1) ，但亦可传播 pred 所抛的异常

注解

使用倾向 timeout_time 的时钟，不要求是单调时钟。若不连续地调节时钟，则不对此函数的行为保证，但既存实现将 timeout_time 从 Clock 转换到 std::chrono::system_clock ，并委托 POSIX pthread_cond_timedwait 以令等待忠实于系统时钟，但非用户提供 Clock 的调节。任何情况下，由于调度或资源争议延迟，函数可能等待长于抵达 timeout_time 。

即使使用的始终是 std::chrono::steady_clock 或另一单调时钟，系统时钟调节亦可能导致虚假唤醒。

notify_one()/notify_all() 的效果与 wait()/wait_for()/wait_until() 的三个原子部分的每一者（解锁+等待、唤醒和锁定）以能看做原子变量修改顺序单独全序发生：顺序对此单独的 condition_variable 是特定的。譬如，这使得 notify_one() 不可能被延迟并解锁正好在进行 notify_one() 调用后开始等待的线程。

示例

#include <iostream>
#include <atomic>
#include <condition_variable>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;

std::condition_variable cv;
std::mutex cv_m;
std::atomic<int> i{0};

void waits(int idx)
{
    std::unique_lock<std::mutex> lk(cv_m);
    auto now = std::chrono::system_clock::now();
    if(cv.wait_until(lk, now + idx*100ms, [](){return i == 1;}))
        std::cerr << "Thread " << idx << " finished waiting. i == " << i << '\n';
    else
        std::cerr << "Thread " << idx << " timed out. i == " << i << '\n';
}

void signals()
{
    std::this_thread::sleep_for(120ms);
    std::cerr << "Notifying...\n";
    cv.notify_all();
    std::this_thread::sleep_for(100ms);
    i = 1;
    std::cerr << "Notifying again...\n";
    cv.notify_all();
}

int main()
{
    std::thread t1(waits, 1), t2(waits, 2), t3(waits, 3), t4(signals);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

可能的输出：

Thread 1 timed out. i == 0
Notifying...
Thread 2 timed out. i == 0
Notifying again...
Thread 3 finished waiting. i == 1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2093 | C++11 | 规范中缺失超时相关异常 | 已提及
LWG 2135 | C++11 | wait_until 在解锁/重锁失败时抛异常 | 调用 std::terminate

参阅

wait | 阻塞当前线程，直到条件变量被唤醒 (公开成员函数)
wait_for | 阻塞当前线程，直到条件变量被唤醒，或到指定时限时长后 (公开成员函数)


std::condition_variable::~condition_variable

< cpp‎ | thread‎ | condition variable

~condition_variable(); | (C++11 起)

销毁 std::condition_variable 类型对象。

若已通知所有线程，调用析构函数才是安全的。不要求它们已退出其对应的等待函数：一些线程仍然可等待重获得关联锁，或在重获得后等待被调度到运行。

一旦析构函数开始，程序员就必须确保没有线程试图等待在 *this 上，特别是在等待线程在循环中调用等待函数，或使用接收谓词的等待函数的重载时。

参阅


std::condition_variable_any

< cpp‎ | thread
定义于头文件 <condition_variable> |
class condition_variable_any; | (C++11 起)

condition_variable_any 类是 std::condition_variable 的泛化。相对于只在 std::unique_lock < std::mutex > 上工作的 std::condition_variable ， condition_variable_any 能在任何满足基本可锁定 (BasicLockable) 要求的锁上工作。

条件变量语义描述见 std::condition_variable 。

类 std::condition_variable_any 是标准布局类型 (StandardLayoutType) 。它非可复制构造 (CopyConstructible) 、可移动构造 (MoveConstructible) 、可复制赋值 (CopyAssignable) 或可移动赋值 (MoveAssignable) 。

若锁是 std::unique_lock ，则 std::condition_variable 可能提供更好的性能。

成员函数

(构造函数)
 构造对象
(公开成员函数)
(析构函数)
 析构对象
(公开成员函数)
operator=
[被删除]
 不可复制赋值
(公开成员函数)
通知
notify_one
 通知一个等待的线程
(公开成员函数)
notify_all
 通知所有等待的线程
(公开成员函数)
等待
wait
 阻塞当前线程，直到条件变量被唤醒
(公开成员函数)
wait_for
 阻塞当前线程，直到条件变量被唤醒，或到指定时限时长后
(公开成员函数)
wait_until
 阻塞当前线程，直到条件变量被唤醒，或直到抵达指定时间点
(公开成员函数)

注解

std::condition_variable_any 能与 std::shared_lock 一同使用，以在 std::shared_mutex 上以共享所有权模式等待。

std::condition_variable_any 与定制可锁定 (Lockable) 类型的一种可行使用是提供便利的可中断等待：定制所操作将按期待锁定关联互斥，并在收到中断信号时进行必要的设置，以通知此条件变量。[1]

引用

  1. ↑ A. Williams (2012), "C++ concurrency in action" 9.2.4 Interupting a wait on std::condition_variable_any


std::condition_variable_any::condition_variable_any

< cpp‎ | thread‎ | condition variable any

condition_variable_any(); | (1) | (C++11 起)
condition_variable_any(const condition_variable_any&) = delete; | (2) | (C++11 起)

1) 构造 std::condition_variable_any 类型对象。

2) 复制构造函数被删除。

参数

（无）

异常

1) 可能抛出 std::system_error ，其 std::error_condition 若线程无权限创建条件变量，则等于 std::errc::operation_not_permitted ，若非内存资源限制阻止此初始化，则等于 std::errc::resource_unavailable_try_again ，或其他实现定义值。

参阅


std::condition_variable_any::notify_all

< cpp‎ | thread‎ | condition variable any

void notify_all() noexcept; | (C++11 起)

解阻塞全部当前等待于 *this 的线程。

参数

（无）

返回值

（无）

注意

notify_one()/notify_all() 的效果与 wait()/wait_for()/wait_until() 的三个原子部分的每一者（解锁+等待、唤醒和锁定）以能看做原子变量修改顺序单独全序发生：顺序对此单独的 condition_variable 是特定的。譬如，这使得 notify_one() 不可能被延迟并解锁正好在进行 notify_one() 调用后开始等待的线程。

通知线程不必保有与等待线程所保有者相同互斥的锁；实际上这么做是劣化，因为被通知线程将立即再次阻塞，以等待通知线程释放锁。

示例

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>

std::condition_variable_any cv;
std::mutex cv_m; // 此互斥用于三个目的：
                 // 1) 同步到 i 的访问
                 // 2) 同步到 std::cerr 的访问
                 // 3) 为条件变量 cv
int i = 0;

void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cerr << "Waiting... \n";
    cv.wait(lk, []{return i == 1;});
    std::cerr << "...finished waiting. i == 1\n";
}

void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lk(cv_m);
        std::cerr << "Notifying...\n";
    }
    cv.notify_all();

    std::this_thread::sleep_for(std::chrono::seconds(1));

    {
        std::lock_guard<std::mutex> lk(cv_m);
        i = 1;
        std::cerr << "Notifying again...\n";
    }
    cv.notify_all();
}

int main()
{
    std::thread t1(waits), t2(waits), t3(waits), t4(signals);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

可能的输出：

Waiting...
Waiting...
Waiting...
Notifying...
Notifying again...
...finished waiting. i == 1
...finished waiting. i == 1
...finished waiting. i == 1

参阅

notify_one
 通知一个等待的线程
(公开成员函数)


std::condition_variable_any::notify_one

< cpp‎ | thread‎ | condition variable any

void notify_one() noexcept; | (C++11 起)

若任何线程在 *this 上等待，则调用 notify_one 会解阻塞等待线程之一。

参数

（无）

返回值

（无）

注意

notify_one()/notify_all() 的效果与 wait()/wait_for()/wait_until() 的三个原子部分的每一者（解锁+等待、唤醒和锁定）以能看做原子变量修改顺序单独全序发生：顺序对此单独的 condition_variable 是特定的。譬如，这使得 notify_one() 不可能被延迟并解锁正好在进行 notify_one() 调用后开始等待的线程。

通知线程不必保有等待线程所保有的同一互斥上的锁；实际上这么做是劣化，因为被通知线程将立即再次阻塞，等待通知线程释放锁。然而一些实现（尤其是许多 pthread 的实现）辨识此情形，在通知调用中，直接从条件变量队列转移等待线程到互斥队列，而不唤醒它，以避免此“急促并等待”场景。

然而，在要求精确调度事件时，可能必须在处于锁下时通知，例如，在若满足条件则线程将退出程序，导致析构通知线程的 condition_variable 的情况下。互斥解锁之后，但在通知前的虚假唤醒可能导致通知在被销毁对象上调用。

示例

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>

std::condition_variable_any cv;
std::mutex cv_m;
int i = 0;
bool done = false;

void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cout << "Waiting... \n";
    cv.wait(lk, []{return i == 1;});
    std::cout << "...finished waiting. i == 1\n";
    done = true;
}

void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Notifying falsely...\n";
    cv.notify_one(); // 等待线程被通知 i == 0.
                     // cv.wait 唤醒，检查 i ，再回到等待

    std::unique_lock<std::mutex> lk(cv_m);
    i = 1;
    while (!done)
    {
        std::cout << "Notifying true change...\n";
        lk.unlock();
        cv.notify_one(); // 等待线程被通知 i == 1 ， cv.wait 返回
        std::this_thread::sleep_for(std::chrono::seconds(1));
        lk.lock();
    }
}

int main()
{
    std::thread t1(waits), t2(signals);
    t1.join();
    t2.join();
}

可能的输出：

Waiting...
Notifying falsely...
Notifying true change...
...finished waiting. i == 1

参阅

notify_all
 通知所有等待的线程
(公开成员函数)


std::condition_variable_any::wait

< cpp‎ | thread‎ | condition variable any

template< class Lock > void wait( Lock& lock ); | (1) | (C++11 起)
template< class Lock, class Predicate > void wait( Lock& lock, Predicate pred ); | (2) | (C++11 起)
template< class Lock, class Predicate > bool wait( Lock& lock, std::stop_token stoken, Predicate pred ); | (3) | (C++20 起)

wait 导致当前线程阻塞直至条件变量被通知，或虚假唤醒发生，可选地循环直至满足某谓词。

1) 原子地解锁 lock ，阻塞当前执行线程，并将它添加到于 *this 上等待的线程列表。线程将在执行 notify_all() 或 notify_one() 时被解除阻塞。解阻塞时，无关乎原因， lock 再次锁定且 wait 退出。
2) 等价于
while (!pred()) {
    wait(lock);
}
此重载可用于在等待特定条件成为 true 时忽略虚假唤醒。注意进入此方法前，必须得到 lock ， wait(lock) 退出后也会重获得它，即能以 lock 为对 pred() 访问的保障。
3) 可中断等待：在 wait() 期间注册 condition_variable_any ，使得若在给定的 stoken 的关联停止状态上作出停止请求，则提醒它；它等价于
while (!stoken.stop_requested()) {
    if (pred()) return true;
    wait(lock);
}
return pred();
注意返回值指示 pred 是否求值为 true ，无关乎是否作出了停止请求。

若这些函数不能满足后置条件（调用方线程锁定 lock ），则调用 std::terminate 。例如，这可能在重锁定互斥抛异常的情况下发生。

参数

lock | - | 任何满足基本可锁定 (BasicLockable) 要求的 Lock 类型对象，必须为当前线程所锁定
stoken | - | 注册中断所用的 std::stop_token
pred | - | 等待是否应该持续则返回 ​false 的谓词。 谓词函数的签名应等价于如下者： bool pred();​

返回值

1-2) （无）
3) pred()

异常

1) 不抛出
2) 同 (1) 但亦会传播 pred 所抛的异常
3) 同 (2)

注解

notify_one()/notify_all() 的效果与 wait()/wait_for()/wait_until() 的三个原子部分的每一者（解锁+等待、唤醒和锁定）以能看做原子变量修改顺序单独全序发生：顺序对此单独的 condition_variable 是特定的。譬如，这使得 notify_one() 不可能被延迟并解锁正好在进行 notify_one() 调用后开始等待的线程。

示例

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>

std::condition_variable_any cv;
std::mutex cv_m; // 此互斥用于三个目的：
                 // 1) 同步到 i 的访问
                 // 2) 同步到 std::cerr 的访问
                 // 3) 为条件变量 cv
int i = 0;

void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cerr << "Waiting... \n";
    cv.wait(lk, []{return i == 1;});
    std::cerr << "...finished waiting. i == 1\n";
}

void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lk(cv_m);
        std::cerr << "Notifying...\n";
    }
    cv.notify_all();

    std::this_thread::sleep_for(std::chrono::seconds(1));

    {
        std::lock_guard<std::mutex> lk(cv_m);
        i = 1;
        std::cerr << "Notifying again...\n";
    }
    cv.notify_all();
}

int main()
{
    std::thread t1(waits), t2(waits), t3(waits), t4(signals);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

可能的输出：

Waiting...
Waiting...
Waiting...
Notifying...
Notifying again...
...finished waiting. i == 1
...finished waiting. i == 1
...finished waiting. i == 1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2135 | C++11 | wait 在解锁/重锁失败时抛异常 | 调用 std::terminate

参阅

wait_for | 阻塞当前线程，直到条件变量被唤醒，或到指定时限时长后 (公开成员函数)
wait_until | 阻塞当前线程，直到条件变量被唤醒，或直到抵达指定时间点 (公开成员函数)


std::condition_variable_any::wait_for

< cpp‎ | thread‎ | condition variable any

template< class Lock, class Rep, class Period >

std::cv_status wait_for( Lock& lock,

const std::chrono::duration <Rep, Period>& rel_time);
 (1) (C++11 起)
template< class Lock, class Rep, class Period, class Predicate >

bool wait_for( Lock& lock,
const std::chrono::duration <Rep, Period>& rel_time,

Predicate pred);
 (2) (C++11 起)
template< class Lock, class Rep, class Period, class Predicate >

bool wait_for( Lock& lock,
std::stop_token stoken,
const std::chrono::duration <Rep, Period>& rel_time,

Predicate pred);
 (3) (C++20 起)
1) 原子地释放 lock ，阻塞当前线程，并将它添加到等待在 *this 上的线程列表。线程将在执行 notify_all() 或 notify_one() 时，或度过相对时限 rel_time 时被解除阻塞。它亦可被虚假地解除阻塞。解阻塞时，无关缘由，重获得 lock 并退出 wait_for() 退出。
2) 等价于 return wait_until(lock, std::chrono::steady_clock::now() + rel_time, std::move(pred)); 。此重载可用于忽略虚假唤醒。

用稳定时钟度量时长。由于调度或资源争议，此函数可能阻塞长于 timeout_duration 。

3) 等价于 return wait_until(lock, std::move(stoken), std::chrono::steady_clock::now() + rel_time, std::move(pred));

若这些函数不能满足后条件（调用方线程锁定 lock ），则调用 std::terminate 。例如，这可能在重锁定互斥抛异常的情况下发生。

参数

lock | - | 满足基本可锁定 (BasicLockable) 要求的 Lock 类型对象，必须为当前线程所锁定
stoken | - | 用于注册中断的 std::stop_token
rel_time | - | 表示等待所耗的最大时间的 std::chrono::duration 类型对象。注意 rel_time 必须足够小，以在加到 std::chrono::steady_clock::now() 时不溢出。
pred | - | 是否应该持续等待则返回 ​false 的谓词。 谓词函数的签名应等价于如下者： bool pred();​

返回值

1) 若经过 rel_time 所指定的关联时限则为 std::cv_status::timeout ，否则为 std::cv_status::no_timeout 。
2) 若经过 rel_time 时限后谓词 pred 仍求值为 false 则为 false ，否则为 true 。
3) pred() ，无关乎是否达到时限或停止请求。

异常

1) 执行期间时钟、时间点或时长可能抛出的任何异常（标准库提供的时钟、时间点和时长决不抛出）
2) 同 (1) ，但亦可传播 pred 所抛的异常
3) 同 (2)

注解

即使在锁定时通知，重载 (1) 在因时限退出时也不对关联谓词的状态做出保证。

notify_one()/notify_all() 的效果与 wait()/wait_for()/wait_until() 的三个原子部分的每一者（解锁+等待、唤醒和锁定）以能看做原子变量修改顺序单独全序发生：顺序对此单独的 condition_variable 是特定的。譬如，这使得 notify_one() 不可能被延迟并解锁正好在进行 notify_one() 调用后开始等待的线程。

示例

#include <iostream>
#include <atomic>
#include <condition_variable>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;

std::condition_variable_any cv;
std::mutex cv_m;
int i;

void waits(int idx)
{
    std::unique_lock<std::mutex> lk(cv_m);
    if(cv.wait_for(lk, idx*100ms, []{return i == 1;}))
        std::cerr << "Thread " << idx << " finished waiting. i == " << i << '\n';
    else
        std::cerr << "Thread " << idx << " timed out. i == " << i << '\n';
}

void signals()
{
    std::this_thread::sleep_for(120ms);
    std::cerr << "Notifying...\n";
    cv.notify_all();
    std::this_thread::sleep_for(100ms);
    {
        std::lock_guard<std::mutex> lk(cv_m);
        i = 1;
    }
    std::cerr << "Notifying again...\n";
    cv.notify_all();
}

int main()
{
    std::thread t1(waits, 1), t2(waits, 2), t3(waits, 3), t4(signals);
    t1.join(); t2.join(), t3.join(), t4.join();
}

输出：

Thread 1 timed out. i == 0
Notifying...
Thread 2 timed out. i == 0
Notifying again...
Thread 3 finished waiting. i == 1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2093 | C++11 | 规范中缺失超时相关异常 | 已提及
LWG 2135 | C++11 | wait_for 在解锁/重锁失败时抛异常 | 调用 std::terminate

参阅

wait | 阻塞当前线程，直到条件变量被唤醒 (公开成员函数)
wait_until | 阻塞当前线程，直到条件变量被唤醒，或直到抵达指定时间点 (公开成员函数)


std::condition_variable_any::wait_until

< cpp‎ | thread‎ | condition variable any

template< class Lock, class Clock, class Duration >

std::cv_status
wait_until( Lock& lock,

const std::chrono::time_point <Clock, Duration>& timeout_time );
 (1) (C++11 起)
template< class Lock, class Clock, class Duration, class Pred >

bool wait_until( Lock& lock,
const std::chrono::time_point <Clock, Duration>& timeout_time,

Pred pred );
 (2) (C++11 起)
template< class Lock, class Clock, class Duration, class Pred >

void wait_until( Lock& lock,
std::stop_token stoken,
const std::chrono::time_point <Clock, Duration>& timeout_time,

Pred pred );
 (3) (C++20 起)

wait_until 导致当前线程阻塞直至通知条件变量、抵达指定时间或虚假唤醒发生，可选的循环直至满足某谓词。

1) 原子地释放 lock ，阻塞当前线程，并将它添加到等待在 *this 上的线程列表。将在执行 notify_all() 或 notify_one() 时，或抵达绝对时间点 timeout_time 时解除阻塞线程。亦可能虚假地解除阻塞。解除阻塞时，无关缘由，重获得 lock 并退出 wait_for() 。
2) 等价于
while (!pred()) {
    if (wait_until(lock, timeout_time) == std::cv_status::timeout) {
        return pred();
    }
}
return true;
此重载可用于忽略虚假唤醒。

3) 可中断等待：在 wait_until() 期间注册 condition_variable_any ，使得若在给定的 stoken 的关联停止状态上作出停止请求则提醒它；然后它等价于
while (!stoken.stop_requested()) {
    if (pred())
        return true;
    if (wait_until(lock, timeout_time) == std::cv_status::timeout)
        return pred();
}
return pred();

若这些函数不能满足后条件（调用方线程锁定 lock ），则调用 std::terminate 。例如，这可能在重锁定互斥抛异常的情况下发生。

Clock 必须符合时钟 (Clock) 要求。若 std::chrono::is_clock_v<Clock> 为 false 则程序为非良构。 (C++20 起)

参数

lock | - | 满足基本可锁定 (BasicLockable) 要求的 Lock 类型对象，必须为当前线程所锁定
stoken | - | 用于注册中断的 std::stop_token
timeout_time | - | 表示停止等待时间的 std::chrono::time_point 类型对象
pred | - | 是否应该持续等待则返回 ​false 的谓词。 谓词函数的签名应等价于如下者： bool pred();​

返回值

1) 若抵达 timeout_time 指定的的绝对时间点则为 std::cv_status::timeout ，否则为 std::cv_status::no_timeout 。
2) 若度过 timeout_time 时限后 pred 仍求值为 false 则为 false ，否则为 true 。若已度过时限，则求值并返回 pred 的结果。
3) pred() ，无关乎是否到达实现或请求停止。

异常

1) 执行期间时钟、时间点或时长可能抛出的任何异常（标准库提供的时钟、时间点和时长决不抛出）
2) 同 (1) ，但亦可传播 pred 所抛的异常
3) 同 (2)

注解

使用倾向 timeout_time 的时钟，不要求是单调时钟。若不连续地调节时钟，则不对此函数的行为保证，但既存实现将 timeout_time 从 Clock 转换到 std::chrono::system_clock ，并委托 POSIX pthread_cond_timedwait 以令等待忠实于系统时钟，但非用户提供 Clock 的调节。任何情况下，由于调度或资源争议延迟，函数可能等待长于抵达 timeout_time 。

即使使用的始终是 std::chrono::steady_clock 或另一单调时钟，系统时钟调节亦可能导致虚假唤醒。

notify_one()/notify_all() 的效果与 wait()/wait_for()/wait_until() 的三个原子部分的每一者（解锁+等待、唤醒和锁定）以能看做原子变量修改顺序单独全序发生：顺序对此单独的 condition_variable 是特定的。譬如，这使得 notify_one() 不可能被延迟并解锁正好在进行 notify_one() 调用后开始等待的线程。

示例

#include <iostream>
#include <atomic>
#include <condition_variable>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;

std::condition_variable cv;
std::mutex cv_m;
std::atomic<int> i{0};

void waits(int idx)
{
    std::unique_lock<std::mutex> lk(cv_m);
    auto now = std::chrono::system_clock::now();
    if(cv.wait_until(lk, now + idx*100ms, [](){return i == 1;}))
        std::cerr << "Thread " << idx << " finished waiting. i == " << i << '\n';
    else
        std::cerr << "Thread " << idx << " timed out. i == " << i << '\n';
}

void signals()
{
    std::this_thread::sleep_for(120ms);
    std::cerr << "Notifying...\n";
    cv.notify_all();
    std::this_thread::sleep_for(100ms);
    i = 1;
    std::cerr << "Notifying again...\n";
    cv.notify_all();
}

int main()
{
    std::thread t1(waits, 1), t2(waits, 2), t3(waits, 3), t4(signals);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

可能的输出：

Thread 1 timed out. i == 0
Notifying...
Thread 2 timed out. i == 0
Notifying again...
Thread 3 finished waiting. i == 1

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2093 | C++11 | 规范中缺失超时相关异常 | 已提及
LWG 2135 | C++11 | wait_until 在解锁/重锁失败时抛异常 | 调用 std::terminate

参阅

wait | 阻塞当前线程，直到条件变量被唤醒 (公开成员函数)
wait_for | 阻塞当前线程，直到条件变量被唤醒，或到指定时限时长后 (公开成员函数)


std::condition_variable_any::~condition_variable_any

< cpp‎ | thread‎ | condition variable any

~condition_variable_any(); | (C++11 起)

销毁 std::condition_variable_any 类型对象。

若已通知所有线程，调用析构函数才是安全的。不要求它们已退出其对应的等待函数：一些线程仍然可等待重获得关联锁，或在重获得后等待被调度到运行。

一旦析构函数开始，程序员就必须确保没有线程试图等待在 *this 上，特别是在等待线程在循环中调用等待函数，或使用接收谓词的等待函数的重载时。

参阅


std::counting_semaphore, std::binary_semaphore

< cpp‎ | thread
定义于头文件 <semaphore>
template< std::ptrdiff_t LeastMaxValue = /* implementation-defined */>
class counting_semaphore;
 (1) (C++20 起)
using binary_semaphore = std::counting_semaphore<1>;
 (2) (C++20 起)
1) counting_semaphore 是一个轻量同步元件，能控制对共享资源的访问。不同于 std::mutex 、 counting_semaphore 允许同一资源有多于一个同时访问，至少允许 LeastMaxValue 个同时的访问者若LeastMaxValue 为负则程序为谬构。
2) binary_semaphore 是 std::counting_semaphore 的特化的别名，其 LeastMaxValue 为 1 。实现可能将 binary_semaphore 实现得比 std::counting_semaphore 的默认实现更高效。

counting_semaphore 含有由构造函数初始化的内部计数器。由调用 acquire() 与相关方法减少此计数器，而它通过调用 release() 增加。计数器为零时， acquire() 阻塞该计数器直至它增加，但 try_acquire() 不阻塞； try_acquire_for() 与 try_acquire_until() 阻塞直至计数器增加或到达时限。

类似 std::condition_variable 的 wait() ， counting_semaphore 的 try_acquire() 可能虚假地失败。

std::counting_semaphore 的特化非可默认构造 (DefaultConstructible) 、可复制构造 (CopyConstructible) 、可移动构造 (MoveConstructible) 、可复制赋值 (CopyAssignable) 或可移动赋值 (MoveAssignable) 。

成员函数

(构造函数)
 构造 counting_semaphore
(公开成员函数)
(析构函数)
 销毁 counting_semaphore
(公开成员函数)
operator=
[被删除]
 counting_semaphore 不可赋值
(公开成员函数)
操作
release
 增加内部计数器并除阻获取者
(公开成员函数)
acquire
 减少内部计数器或阻塞到直至能如此
(公开成员函数)
try_acquire
 尝试减少内部计数器而不阻塞
(公开成员函数)
try_acquire_for
 尝试减少内部计数器，至多阻塞一段时长
(公开成员函数)
try_acquire_until
 尝试减少内部计数器，阻塞直至一个时间点
(公开成员函数)
常量
max
[静态]
 返回内部计数器的最大可能值
(公开静态成员函数)

注解

如其名所示， LeastMaxValue 是最小的最大值，而非实际最大值。从而 max() 能产生大于 LeastMaxValue 的值。

不同于 std::mutex ， counting_semaphore 不捆绑到执行线程——能在不同于释放信号量的线程获取该信号量。能同时进行 counting_semaphore 上的所有操作而无需联系到任何特定的执行线程，除了不能同时执行，但能在一个不同的线程上执行析构函数。

信号量亦常用于发信/提醒而非互斥，通过初始化该信号量为 ​0​ 从而阻塞尝试 acquire() 的接收者，直至提醒者通过调用 release(n) “发信”。在此方面可把信号量当作 std::condition_variable 的替用品，通常它有更好的性能。

示例

#include <iostream>
#include <thread>
#include <chrono>
#include <semaphore>
using namespace std::literals;

// 全局二元信号量实例
// 设置对象计数为零
// 对象在未被发信状态
std::binary_semaphore smphSignal(0);

void ThreadProc()
{
    // 通过尝试减少信号量的计数等待来自主程序的信号
    smphSignal.acquire();

    // 此调用阻塞直至信号量的计数被从主程序增加

    std::cout << "[thread] Got the signal" << std::endl; // 回应消息

    // 等待 3 秒以模仿某种线程正在进行的工作
    std::this_thread::sleep_for(3s);

    std::cout << "[thread] Send the signal\n"; // 消息

    // 对主程序回复发信
    smphSignal.release();
}

int main()
{
    // 创建某个背景工作线程，它将长期存在
    std::jthread thrWorker(ThreadProc);

    std::cout << "[main] Send the signal\n"; // 消息

    // 通过增加信号量的计数对工作线程发信以开始工作
    smphSignal.release();

    // release() 后随 acquire() 可以阻止工作线程获取信号量，所以添加延迟：
    std::this_thread::sleep_for(50ms);

    // 通过试图减少信号量的计数等待直至工作线程完成工作
    smphSignal.acquire();

    std::cout << "[main] Got the signal\n"; // 回应消息
}

输出：

[main] Send the signal
[thread] Got the signal
[thread] Send the signal
[main] Got the signal


std::counting_semaphore<LeastMaxValue>::acquire

< cpp‎ | thread‎ | counting semaphore
void acquire(); | (C++20 起)

若内部计数器大于 ​0​ 则尝试将它减少 1 ；否则阻塞直至它大于 ​0​ 且能成功减少内部计数器。

前条件

（无）

参数

（无）

异常

可能抛出 std::system_error 。

示例

该示例可视化数个随机化线程在不多于 N 个活跃线程函数，而且其他可能在信号量上等待时的并发作业（ N 为信号量 desired 值）。

#include <array>
#include <chrono>
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <random>
#include <semaphore>
#include <thread>
#include <vector>
using namespace std::literals;

constexpr std::size_t       max_threads{10U}; // 更改并查看效果
constexpr std::ptrdiff_t    max_sema_threads{3}; // 对二元信号量为 {1}
std::counting_semaphore     semaphore{max_sema_threads};
constexpr auto              time_tick{10ms};

unsigned rnd() {
    static std::uniform_int_distribution<unsigned> distribution{2U, 9U}; // [延迟]
    static std::random_device engine;
    static std::mt19937 noise{engine()};
    return distribution(noise);
}

class alignas( 128 /*std::hardware_destructive_interference_size*/ ) Guide {
    inline static std::mutex cout_mutex;
    inline static std::chrono::time_point<std::chrono::high_resolution_clock> started_at;
    unsigned delay{rnd()}, occupy{rnd()}, wait_on_sema{};

  public:
    static void start_time() { started_at = std::chrono::high_resolution_clock::now(); }

    void initial_delay() { std::this_thread::sleep_for(delay * time_tick); }

    void occupy_sema() {
        wait_on_sema =
            static_cast<unsigned>(std::chrono::duration_cast<std::chrono::milliseconds>(
              std::chrono::high_resolution_clock::now() - started_at - delay * time_tick)
                .count() / time_tick.count());
        std::this_thread::sleep_for(occupy * time_tick);
    }

    void visualize(unsigned id, unsigned x_scale = 2) const {
        auto cout_n = [=] (auto str, unsigned n) {
            n *= x_scale;
            while (n-- > 0) { std::cout << str; }
        };
        std::lock_guard lk{cout_mutex};
        std::cout << "#" << std::setw(2) << id << " ";
        cout_n("░", delay);
        cout_n("▒", wait_on_sema);
        cout_n("█", occupy);
        std::cout << '\n';
    }

    static void show_info() {
        std::cout
            << "\nThreads: " << max_threads << ", Throughput: " << max_sema_threads
            << " │ Legend: initial delay ░░ │ wait state ▒▒ │ sema occupation ██ \n"
            << std::endl;
    }
};

std::array<Guide, max_threads> guides;

void workerThread(unsigned id) {
    guides[id].initial_delay(); // 模拟获取旗标前的某些工作
    semaphore.acquire();        // 等待直至空闲旗标槽可用
    guides[id].occupy_sema();   // 模拟获取旗标时的某些工作
    semaphore.release();
    guides[id].visualize(id);
}

int main() {
    std::vector<std::jthread> threads;
    threads.reserve(max_threads);

    Guide::show_info();
    Guide::start_time();

    for (auto id{0U}; id != max_threads; ++id) {
        threads.push_back(std::jthread(workerThread, id));
    }
}

可能的输出：

Default case: max_threads{10U}, max_sema_threads{3}

Threads: 10, Throughput: 3 │ Legend: initial delay ░░ │ wait state ▒▒ │ sema occupation ██

# 1 ░░░░██████
# 2 ░░░░████████
# 5 ░░░░░░██████████
# 8 ░░░░░░░░░░░░████████████
# 9 ░░░░░░░░░░░░██████████████
# 7 ░░░░░░░░░░░░▒▒▒▒████████████████
# 4 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒████████
# 6 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒██████████████████
# 3 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████
# 0 ░░░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████████████

──────────────────────────────────────────────────────────────────────────────────────────────────────────────
"Enough for everyone" case (no wait states!): max_threads{10U}, max_sema_threads{10}

Threads: 10, Throughput: 10 │ Legend: initial delay ░░ │ wait state ▒▒ │ sema occupation ██

# 4 ░░░░██████
# 5 ░░░░░░████
# 3 ░░░░██████████
# 1 ░░░░██████████
# 8 ░░░░░░░░████████████
# 6 ░░░░░░░░░░░░░░░░██████
# 7 ░░░░░░░░░░░░░░░░██████
# 9 ░░░░░░░░░░░░░░░░██████████
# 0 ░░░░░░░░░░░░██████████████████
# 2 ░░░░░░░░░░░░░░░░░░████████████

──────────────────────────────────────────────────────────────────────────────────────────────────────────────
Binary semaphore case: max_threads{10U}, max_sema_threads{1}

Threads: 10, Throughput: 1 │ Legend: initial delay ░░ │ wait state ▒▒ │ sema occupation ██

# 6 ░░░░████
# 5 ░░░░▒▒▒▒████
# 4 ░░░░░░░░░░▒▒██████████
# 7 ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒████████████████
# 2 ░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████
# 3 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████████
# 0 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████
# 1 ░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████
# 8 ░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████
# 9 ░░░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████████████


std::counting_semaphore<LeastMaxValue>::counting_semaphore

< cpp‎ | thread‎ | counting semaphore
constexpr explicit counting_semaphore( std::ptrdiff_t desired ); | (1) | (C++20 起)
counting_semaphore( const counting_semaphore& ) = delete; | (2) | (C++20 起)
1) 构造一个 std::counting_semaphore 类型对象，初始化其计数器的值为 desired 。
2) 复制构造函数被删除。

前条件

1) desired >= 0 与 desired <= max() 均为 true 。

参数

desired - 用于初始化 counting_semaphore 的计数器的值

异常

不抛出。


std::counting_semaphore<LeastMaxValue>::max

< cpp‎ | thread‎ | counting semaphore
constexpr std::ptrdiff_t max() noexcept; | (C++20 起)

返回内部计数器的最大可能值，它大于或等于 LeastMaxValue 。对于 binary_semaphore ， LeastMaxValue 等于 1 。

返回值

作为 std::ptrdiff_t 的内部计数器的最大可能值。


std::counting_semaphore<LeastMaxValue>::release

< cpp‎ | thread‎ | counting semaphore
void release( std::ptrdiff_t update = 1 ); | (C++20 起)

原子地将内部计数器的值增加 update 。任何等待计数器大于 ​0​ 的线程，如由于阻塞于 acquire 者，将继而被除阻。

前条件

update >= 0 与 update <= max() - counter 均为 true ，其中 counter 是内部计数器的值。

参数

update - 要更新计数器的数量

异常

可能抛出 std::system_error 。


std::counting_semaphore<LeastMaxValue>::try_acquire

< cpp‎ | thread‎ | counting semaphore
bool try_acquire() noexcept; | (C++20 起)

若内部计数器大于 ​0​ 则尝试原子地将它减少 1 ；不出现阻塞。

返回值

若减少内部计数器则为 true ，否则为 false 。

注解

允许实现未能减少计数器，即使它大于 ​0​ ——即允许它们虚假地失败并返回 false 。


std::counting_semaphore<LeastMaxValue>::try_acquire_for

< cpp‎ | thread‎ | counting semaphore
template<class Rep, class Period> bool try_acquire_for( const std::chrono::duration <Rep, Period>& rel_time ); | (C++20 起)

若内部计数器大于 ​0​ 则尝试原子地将它减少 1 ；否则阻塞直至它大于 ​​0​ 且能成功地减少内部计数器，或已经超出 rel_time 时间点。

前条件

（无）

参数

rel_time - 函数必须为失败等待到的最小时长

返回值

若减少内部计数器则为 true ，否则为 false 。

异常

可能抛出 std::system_error 或与到达时间相关的异常。

注解

实践中函数可能需要经过长于 rel_time 的时间才失败。

允许实现未能减少计数器，即使它大于 ​0​ ——即允许它们虚假地失败并返回 false 。


std::counting_semaphore<LeastMaxValue>::try_acquire_until

< cpp‎ | thread‎ | counting semaphore
template<class Clock, class Duration> bool try_acquire_until( const std::chrono::time_point <Clock, Duration>& abs_time ); | (C++20 起)

若内部计数器大于 ​0​ 则尝试原子地将它减少 1 ；否则阻塞直至它大于 ​​0​ 且能成功地减少内部计数器，或已经经过 abs_time 时间点。

若 std::chrono::is_clock_v<Clock> 为 false 则程序为非良构。

前条件

Clock 符合时钟 (Clock) 要求。

参数

abs_time - 函数必须为失败等待到的最早时间点

返回值

若减少内部计数器则为 true ，否则为 false 。

异常

可能抛出 std::system_error 或与到达时间相关的异常。

注解

实践中函数可能需要经过长于 abs_time 的时间才失败。

允许实现未能减少计数器，即使它大于 ​0​ ——即允许它们虚假地失败并返回 false 。


std::counting_semaphore<LeastMaxValue>::~counting_semaphore

< cpp‎ | thread‎ | counting semaphore
~counting_semaphore(); | (C++20 起)

销毁 counting_semaphore 对象。

若任何线程在此信号量上的同时调用任何其他成员函数，则行为未定义。这包括在 acquire() 、 try_acquire_for() 或 try_acquire_until() 中阻塞。


std::cv_status

< cpp‎ | thread
定义于头文件 <condition_variable> |
enum class cv_status; | (C++11 起)

带作用域枚举 std::cv_status 描述定时等待是否因时限返回。

std::cv_status 为 std::condition_variable 和 std::condition_variable_any 的 wait_for 和 wait_until 方法所用。

成员常量

常量 | 解释
no_timeout | 条件变量因 notify_all 、 notify_one 或虚假地被唤醒
timeout | 条件变量因时限耗尽被唤醒

参阅

wait_for | 阻塞当前线程，直到条件变量被唤醒，或到指定时限时长后 (std::condition_variable 的公开成员函数)
wait_for | 阻塞当前线程，直到条件变量被唤醒，或到指定时限时长后 (std::condition_variable_any 的公开成员函数)
wait_until | 阻塞当前线程，直到条件变量被唤醒，或直到抵达指定时间点 (std::condition_variable 的公开成员函数)
wait_until | 阻塞当前线程，直到条件变量被唤醒，或直到抵达指定时间点 (std::condition_variable_any 的公开成员函数)


std::future

< cpp‎ | thread
定义于头文件 <future> |  |
template< class T > class future; | (1) | (C++11 起)
template< class T > class future<T&>; | (2) | (C++11 起)
template<> class future<void>; | (3) | (C++11 起)

类模板 std::future 提供访问异步操作结果的机制：

  • （通过 std::async 、 std::packaged_task 或 std::promise 创建的）异步操作能提供一个 std::future 对象给该异步操作的创建者。
  • 然后，异步操作的创建者能用各种方法查询、等待或从 std::future 提取值。若异步操作仍未提供值，则这些方法可能阻塞。
  • 异步操作准备好发送结果给创建者时，它能通过修改链接到创建者的 std::future 的共享状态（例如 std::promise::set_value ）进行。

注意， std::future 所引用的共享状态不与另一异步返回对象共享（与 std::shared_future 相反）。

成员函数

(构造函数)
 构造 future 对象
(公开成员函数)
(析构函数)
 析构 future 对象
(公开成员函数)
operator=
 移动future对象
(公开成员函数)
share
 从 *this 转移共享状态给 shared_future 并返回它
(公开成员函数)
获取结果
get
 返回结果
(公开成员函数)
状态
valid
 检查 future 是否拥有共享状态
(公开成员函数)
wait
 等待结果变得可用
(公开成员函数)
wait_for
 等待结果，如果在指定的超时间隔后仍然无法得到结果，则返回。
(公开成员函数)
wait_until
 等待结果，如果在已经到达指定的时间点时仍然无法得到结果，则返回。
(公开成员函数)

示例

#include <iostream>
#include <future>
#include <thread>

int main()
{
    // 来自 packaged_task 的 future
    std::packaged_task<int()> task([](){ return 7; }); // 包装函数
    std::future<int> f1 = task.get_future();  // 获取 future
    std::thread(std::move(task)).detach(); // 在线程上运行

    // 来自 async() 的 future
    std::future<int> f2 = std::async(std::launch::async, [](){ return 8; });

    // 来自 promise 的 future
    std::promise<int> p;
    std::future<int> f3 = p.get_future();
    std::thread( [&p]{ p.set_value_at_thread_exit(9); }).detach();

    std::cout << "Waiting..." << std::flush;
    f1.wait();
    f2.wait();
    f3.wait();
    std::cout << "Done!\nResults are: "
              << f1.get() << ' ' << f2.get() << ' ' << f3.get() << '\n';
}

输出：

Waiting...Done!
Results are: 7 8 9

参阅

async (C++11) | 异步运行一个函数（有可能在新线程中执行），并返回保有其结果的 std::future (函数模板)
shared_future (C++11) | 等待被异步设置的值（可能为其他 future 所引用） (类模板)


std::future<T>::future

< cpp‎ | thread‎ | future
future() noexcept; | (1) | (C++11 起)
future( future&& other ) noexcept; | (2) | (C++11 起)
future( const future& other ) = delete; | (3) | (C++11 起)

构造 std::future 对象。

1) 默认构造函数。构造无共享状态的 std::future 。构造后， valid() == false 。
2) 移动构造函数。用移动语义，以 other 的共享状态构造 std::future 。构造后 other.valid() == false 。
3) std::future 不可复制构造 (CopyConstructible) 。

参数

other - 获得共享状态来源的另一 std::future


std::future_category

< cpp‎ | thread
定义于头文件 <future> |
const std::error_category & future_category() noexcept; | (C++11 起)

获得对于 future 和 promise 相关错误的静态 error_category 对象的引用。要求对象覆写虚函数 error_category::name() ，以返回指向字符串 "future" 的指针。它亦用于鉴别 std::future_error 类型异常中提供的 error_code 。

参数

（无）

返回值

到静态对象的引用，其运行时类型导出自 std::error_category 且未指定。

示例

本节未完成
原因：暂无示例

参阅

future_errc (C++11) | 鉴别 future 错误码 (枚举)
future_error (C++11) | 报告与 future 或 promise 有关的错误 (类)
error_category (C++11) | 错误类别的基类 (类)


std::future<T>::get

< cpp‎ | thread‎ | future

T get(); | (1) | (仅为泛型 future 模板的成员) (C++11 起)
T& get(); | (2) | (仅为 future<T&> 模板特化的成员) (C++11 起)
void get(); | (3) | (仅为 future<void> 模板特化的成员) (C++11 起)

get 方法等待直至 future 拥有合法结果并（依赖于使用哪个模板）获取它。它等效地调用 wait() 等待结果。

泛型模板和二个模板特化各含单个 get 版本。 get 的三个版本仅在返回类型有别。

若调用此函数前 valid() 为 false 则行为未定义。

释放任何共享状态。调用此方法后 valid() 为 false 。

参数

（无）

返回值

1) 存储于共享状态的值 v ，如同 std::move(v) 。
2) 存储于共享状态的值的引用。
3) 无。

异常

若 future 所引用的共享状态中存储异常（例如，通过调用 std::promise::set_exception() ），则抛出该异常。

注意

鼓励实现在调用前检测 valid() 为 false 的情况，并抛出以 std::future_errc::no_state 为 error_condition 的 std::future_error 。

示例

#include <thread>
#include <future>
#include <iostream>
#include <string>
#include <chrono>

std::string time() {
    static auto start = std::chrono::steady_clock::now();
    std::chrono::duration<double> d = std::chrono::steady_clock::now() - start;
    return "[" + std::to_string(d.count()) + "s]";
}
int main() {
    using namespace std::chrono_literals;
    {
        std::cout << time() << " launching thread\n";
        std::future<int> f = std::async(std::launch::async, []{
            std::this_thread::sleep_for(1s);
            return 7;
        });
        std::cout << time() << " waiting for the future, f.valid() == "
                  << f.valid() << "\n";
        int n = f.get();
        std::cout << time() << " future.get() returned with " << n << ". f.valid() = "
                  << f.valid() << '\n';
    }

    {
        std::cout << time() << " launching thread\n";
        std::future<int> f = std::async(std::launch::async, []{
            std::this_thread::sleep_for(1s);
            return true ? throw std::runtime_error("7") : 7;
        });
        std::cout << time() << " waiting for the future, f.valid() == "
                  << f.valid() << "\n";
        try {
            int n = f.get();
            std::cout << time() << " future.get() returned with " << n
                      << " f.valid() = " << f.valid() << '\n';
        } catch(const std::exception& e) {
            std::cout << time() << " caught exception " << e.what()
                      << ", f.valid() == " << f.valid() << "\n";
        }
    }
}

可能的输出：

[0.000004s] launching thread
[0.000461s] waiting for the future, f.valid() == 1
[1.001156s] future.get() returned with 7. f.valid() = 0
[1.001192s] launching thread
[1.001275s] waiting for the future, f.valid() == 1
[2.002356s] caught exception 7, f.valid() == 0

参阅

valid
 检查 future 是否拥有共享状态
(公开成员函数)


std::future<T>::operator=

< cpp‎ | thread‎ | future
future& operator=( future&& other ) noexcept; | (1) | (C++11 起)
future& operator=( const future& other ) = delete; | (2) | (C++11 起)

赋值另一 future 对象的内容。

1) 释放任何共享状态并移动赋值 other 的内容给 *this 。赋值后， other.valid() == false 且 this->valid() 将产生与 other.valid() 在赋值前相同的值。

2) std::future 不可复制赋值 (CopyAssignable) 。

参数

other - 将转移状态给 *this 的 std::future

返回值

*this


std::future<T>::share

< cpp‎ | thread‎ | future
std::shared_future <T> share() noexcept;

转移 *this 的共享状态，若存在，到 std::shared_future 对象。多个 std::shared_future 对象可引用同一共享对象，这对于 std::future 不可能。

在 std::future 上调用 share 后 valid() == false 。

参数

（无）

返回值

含有先前 *this 所保有的共享状态（若存在）的 std::shared_future 对象，如同以 std::shared_future <T>(std:move(*this)) 构造。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2556 | C++11 | share() 要求 valid() 为 true | 移除要求并使之为 noexcept

参阅

shared_future
(C++11)
 等待被异步设置的值（可能为其他 future 所引用）
(类模板)


std::future<T>::valid

< cpp‎ | thread‎ | future

bool valid() const noexcept; | (C++11 起)

检查期货是否指代共享状态。

这是非默认构造或被移动的期货（例如为 std::promise::get_future() 、 std::packaged_task::get_future() 或 std::async() 所返回）在首次调用 get() 或 share() 前的唯一情况。

若在不指代共享状态的 future 上调用任何析构函数、移动赋值运算符或 valid 以外的成员函数，则行为未定义（尽管鼓励实现在此情况下抛出指示 no_state 的 std::future_error ）。从 valid() 为 false 的 future 对象移动是合法的。

参数

（无）

返回值

若 *this 指代共享状态则为 true ，否则为 false 。

示例

#include <future>
#include <iostream>

int main() {
    std::promise<void> p;
    std::future<void> f = p.get_future();

    std::cout << std::boolalpha;

    std::cout << f.valid() << '\n';
    p.set_value();
    std::cout << f.valid() << '\n';
    f.get();
    std::cout << f.valid() << '\n';
}

输出：

true
true
false

参阅

wait
 等待结果变得可用
(公开成员函数)


std::future<T>::wait

< cpp‎ | thread‎ | future

void wait() const; | (C++11 起)

阻塞直至结果变得可用。调用后 valid() == true 。

若调用此函数前 valid () == false 则行为未定义。

参数

（无）

返回值

（无）

异常

可能抛出实现定义的异常。

注解

鼓励实现检测调用前 valid() == false 的情况并抛出以 std::future_errc::no_state 为 error_condition 的 std::future_error 。

示例

#include <chrono>
#include <iostream>
#include <future>
#include <thread>

int fib(int n)
{
  if (n < 3) return 1;
  else return fib(n-1) + fib(n-2);
}

int main()
{
    std::future<int> f1 = std::async(std::launch::async, [](){
        return fib(40);
    });
    std::future<int> f2 = std::async(std::launch::async, [](){
        return fib(43);
    });

    std::cout << "waiting... " << std::flush;
    const auto start = std::chrono::system_clock::now();

    f1.wait();
    f2.wait();

    const auto diff = std::chrono::system_clock::now() - start;
    std::cout << std::chrono::duration<double>(diff).count() << " seconds\n";

    std::cout << "f1: " << f1.get() << '\n';
    std::cout << "f2: " << f2.get() << '\n';
}

可能的输出：

waiting... 1.61803 seconds
f1: 102334155
f2: 433494437

参阅

wait_for | 等待结果，如果在指定的超时间隔后仍然无法得到结果，则返回。 (公开成员函数)
wait_until | 等待结果，如果在已经到达指定的时间点时仍然无法得到结果，则返回。 (公开成员函数)


std::future<T>::wait_for

< cpp‎ | thread‎ | future

template< class Rep, class Period > std::future_status wait_for( const std::chrono::duration <Rep,Period>& timeout_duration ) const; | (C++11 起)

等待结果变得可用。阻塞直至经过指定的 timeout_duration ，或结果变为可用，两者的先到来者。返回值鉴别结果的状态。

此函数可能由于调度或资源争议延迟而阻塞长于 timeout_duration 。

推荐标准库用稳定时钟度量时长。若实现用系统时钟代替，则等待时间可能也对时钟调整敏感。

若调用此函数前 valid() == false 则行为未定义。

参数

timeout_duration - 要阻塞的最大时长

返回值

常量 | 解释
future_status::deferred | 共享状态持有的函数正在延迟运行，结果将仅在显式请求时计算
future_status::ready | 共享状态就绪
future_status::timeout | 共享状态在经过指定的等待时间内仍未就绪

异常

时钟、时间点或时长在执行中可能抛的任何异常（标准库提供的时钟、时间点和时长决不抛出）。

注意

鼓励实现在调用前检测 valid == false 的情况并抛出以 future_errc::no_state 为 error_condition 的 future_error 。

示例

#include <iostream>
#include <future>
#include <thread>
#include <chrono>

int main()
{
    std::future<int> future = std::async(std::launch::async, [](){
        std::this_thread::sleep_for(std::chrono::seconds(3));
        return 8;
    });

    std::cout << "waiting...\n";
    std::future_status status;
    do {
        status = future.wait_for(std::chrono::seconds(1));
        if (status == std::future_status::deferred) {
            std::cout << "deferred\n";
        } else if (status == std::future_status::timeout) {
            std::cout << "timeout\n";
        } else if (status == std::future_status::ready) {
            std::cout << "ready!\n";
        }
    } while (status != std::future_status::ready);

    std::cout << "result is " << future.get() << '\n';
}

可能的输出：

waiting...
timeout
timeout
ready!
result is 8

参阅

wait | 等待结果变得可用 (公开成员函数)
wait_until | 等待结果，如果在已经到达指定的时间点时仍然无法得到结果，则返回。 (公开成员函数)


std::future<T>::wait_until

< cpp‎ | thread‎ | future

template< class Clock, class Duration > std::future_status wait_until( const std::chrono::time_point <Clock,Duration>& timeout_time ) const; | (C++11 起)

wait_until 等待结果变为可用。它阻塞直至抵达指定的 timeout_time ，或结果变为可用，两者的先到来者。返回值指示 wait_until 为何返回。

若调用此函数前 valid() 为 false ，或 Clock 不符合时钟 (Clock) 要求则行为未定义。若 std::chrono::is_clock_v<Clock> 为 false 则程序为非良构。 (C++20 起)

参数

timeout_time - 要阻塞到的最大时间点

返回值

常量 | 解释
future_status::deferred | 共享状态持有的函数正在延迟运行，结果将仅在显式请求时计算
future_status::ready | 共享状态就绪
future_status::timeout | 共享状态在经过指定的等待时间内仍未就绪

异常

时钟、时间点或时长在执行中可能抛的任何异常（标准库提供的时钟、时间点和时长决不抛出）。

注解

鼓励实现在调用前检测 valid() == false 的情况并抛出以 future_errc::no_state 为错误条件的 std::future_error 。

使用倾向 timeout_time 的时钟，不要求是单调时钟。若不连续地调节时钟，则不对此函数的行为保证，但既存实现将 timeout_time 从 Clock 转换到 std::chrono::system_clock ，并委托 POSIX pthread_cond_timedwait 以令等待忠实于系统时钟，但非用户提供 Clock 的调节。任何情况下，由于调度或资源争议延迟，函数可能等待长于抵达 timeout_time 。

示例

#include <iostream>
#include <future>
#include <thread>
#include <chrono>

int main()
{
    std::chrono::system_clock::time_point two_seconds_passed
        = std::chrono::system_clock::now() + std::chrono::seconds(2);

    // 做出花 1 秒完成的 future
    std::promise<int> p1;
    std::future<int> f_completes = p1.get_future();
    std::thread([](std::promise<int> p1)
                {
                    std::this_thread::sleep_for(std::chrono::seconds(1));
                    p1.set_value_at_thread_exit(9);
                },
                std::move(p1)
    ).detach();

    // 做出花 5 秒完成的 future
    std::promise<int> p2;
    std::future<int> f_times_out = p2.get_future();
    std::thread([](std::promise<int> p2)
                {
                    std::this_thread::sleep_for(std::chrono::seconds(5));
                    p2.set_value_at_thread_exit(8);
                },
                std::move(p2)
    ).detach();

    std::cout << "Waiting for 2 seconds..." << std::endl;

    if(std::future_status::ready == f_completes.wait_until(two_seconds_passed))
        { std::cout << "f_completes: " << f_completes.get() << "\n"; }
    else
        { std::cout << "f_completes did not complete!\n"; }

    if(std::future_status::ready == f_times_out.wait_until(two_seconds_passed))
        { std::cout << "f_times_out: " << f_times_out.get() << "\n"; }
    else
        { std::cout << "f_times_out did not complete!\n"; }

    std::cout << "Done!\n";
}

可能的输出：

Waiting for 2 seconds...
f_completes: 9
f_times_out did not complete!
Done!

参阅

wait | 等待结果变得可用 (公开成员函数)
wait_for | 等待结果，如果在指定的超时间隔后仍然无法得到结果，则返回。 (公开成员函数)


std::future<T>::~future

< cpp‎ | thread‎ | future
~future(); | (C++11 起)

释放任何共享状态。这表示

  • 若返回对象或提供方保有到其共享状态的最后引用，则析构共享状态；
  • 返回对象或提供方放弃到其共享状态的引用；
  • 这些动作将不会阻塞至共享状态变为准备，除了若以下为真则它可能阻塞：共享状态以到 std::async 的调用创建，共享状态仍未就绪，且 this 是到共享状态的最后引用。
 (C++14 起)


std::future_errc

< cpp‎ | thread
定义于头文件 <future> |
enum class future_errc { broken_promise = /* implementation-defined */, future_already_retrieved = /* implementation-defined */, promise_already_satisfied = /* implementation-defined */, no_state = /* implementation-defined */ }; | (C++11 起)

有作用域枚举 std::future_errc 定义 std::future 及相关类于 std::future_error 异常对象中报告的错误码。只要求四个错误码，尽管实现可以定义额外的错误码。因为提供了 std::is_error_code_enum 的恰当特化，故 std::future_errc 类型值可隐式转换为 std::error_code 。

所有错误码均相异且非零。

成员常量

常量 | 解释
broken_promise | 异步任务抛弃其共享状态
future_already_retrieved | 共享状态的内容已通过 std::future 访问
promise_already_satisfied | 试图两次存储值于共享状态
no_state | 试图访问无关联共享状态的 std::promise 或 std::future

非成员函数

make_error_code(std::future_errc) (C++11) | 构造一个 future error_code (函数)
make_error_condition(std::future_errc) (C++11) | 构造一个 future error_condition (函数)

辅助类

is_error_code_enum<std::future_errc>
(C++11)
 扩展类型特性 std::is_error_code_enum 以鉴别 future 错误码
(类模板)

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2056 | C++11 | broken_promise 曾被指定为约定上用于表示“无错误”的零 | 指定为非零

参阅

error_code (C++11) | 保有依赖于平台的错误码 (类)
error_condition (C++11) | 保有可移植的错误码 (类)


std::is_error_code_enum<std::future_errc>

< cpp‎ | thread‎ | future errc
定义于头文件 <future> |
template<> struct is_error_code_enum< std::future_errc > : std::true_type ; | (C++11 起)

指定 std::future_errc 是错误码枚举。这允许 std::error_code 自动转换。

参阅

is_error_code_enum
(C++11)
 鉴别类是否可作为 error_code 枚举
(类模板)


std::make_error_code(std::future_errc)

< cpp‎ | thread‎ | future errc
定义于头文件 <future> |
std::error_code make_error_code( std::future_errc e ); | (C++11 起)

从 std::future_errc 类型值构造 std::error_code 对象，如同以：

std::error_code (static_cast<int>(e), std::future_category ()).

此函数为 std::error_code 的构造函数在给定 std::future_errc 参数时所调用。

参数

e - 错误码号

返回值

保有来自 e 的 error_code 号并关联到 error_category "future" 的 std::error_code 。

示例

本节未完成
原因：暂无示例

参阅

error_code (C++11) | 保有依赖于平台的错误码 (类)
future_errc (C++11) | 鉴别 future 错误码 (枚举)


std::make_error_condition(std::future_errc)

< cpp‎ | thread‎ | future errc
定义于头文件 <future> |
std::error_condition make_error_condition( std::future_errc e ); | (C++11 起)

从 std::future_errc 类型值构造 std::error_condition 对象，如同用：

std::error_condition (static_cast<int>(e), std::future_category ()) 。

参数

e - 错误码号

返回值

保有关联到 error_category "future" ，保有来自 的 error_code 号 e 的 std::error_condition 类型值。

示例

本节未完成
原因：暂无示例

参阅

error_condition (C++11) | 保有可移植的错误码 (类)
future_errc (C++11) | 鉴别 future 错误码 (枚举)


std::future_error

< cpp‎ | thread
定义于头文件 <future> |
class future_error; | (C++11 起)

类 std::future_error 定义异常对象，它为处理异步执行和共享状态（ std::future 、 std::promise 等）的线程库中的函数在失败时抛出。同 std::system_error ，此异常携带与 std::error_code 兼容的错误码。

cpp/error/exception cpp/error/logic error

继承图

成员函数

(构造函数) | 创建 std::future_error 对象 (公开成员函数)
operator= | 替换 std::future_error 对象 (公开成员函数)
code | 返回错误码 (公开成员函数)
what | 返回对错误码指定的解释性字符串 (公开成员函数)

继承自 std::logic_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

示例

#include <future>
#include <iostream>

int main()
{
    std::future<int> empty;
    try {
        int n = empty.get(); // 行为未定义，但一些实现抛出 std::future_error
    } catch (const std::future_error& e) {
        std::cout << "Caught a future_error with code \"" << e.code()
                  << "\"\nMessage: \"" << e.what() << "\"\n";
    }
}

可能的输出：

Caught a future_error with code "future:3"
Message: "No associated state"

参阅

future_errc
(C++11)
 鉴别 future 错误码
(枚举)


std::future_error::code

< cpp‎ | thread‎ | future error
const std::error_code & code() const noexcept; | (C++11 起)

返回存储的错误码。

参数

（无）

返回值

存储的错误码。

参阅

what
 返回对错误码指定的解释性字符串
(公开成员函数)


std::future_error::future_error

< cpp‎ | thread‎ | future error
future_error( const future_error& other ) noexcept; | (1) | (C++11 起)
explicit future_error( std::future_errc ec ); | (2) | (C++17 起)
1) 复制构造函数，以 other 的内容初始化新 future_error 的内容。若 *this 与 other 均拥有动态类型 std::future_error 则 std::strcmp (what(), other.what()) == 0 。
2) 构造含错误码 std::make_error_code(ec) 的新 future_error 对象。

参数

other | - | 要复制的另一 future_error 对象
ec | - | 错误码

注解

C++17 前用户没有符合标准的构造 future_error 的方法，除了从另一 future_error 复制。 C++11 与 C++14 描述了仅为说明的接收 std::error_code 的公开构造函数，而一些实现提供这种构造函数。


std::future_error::operator=

< cpp‎ | thread‎ | future error
future_error& operator=( const future_error& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::future_error 则赋值后 std::strcmp (what(), other.what()) == 0 。

参数

other - 用以赋值的另一 future_error 对象

返回值

*this

示例

本节未完成
原因：暂无示例


std::future_error::what

< cpp‎ | thread‎ | future error
virtual const char* what() const noexcept; | (C++11 起)

返回解释性字符串。

参数

（无）

返回值

返回带解释信息的空终止字符串。

参阅

code
 返回错误码
(公开成员函数)


std::future_status

< cpp‎ | thread
定义于头文件 <future> |
enum class future_status { ready, timeout, deferred }; | (C++11 起)

指定 std::future 和 std::shared_future 的 wait_for 和 wait_until 函数所返回的 future 状态。

常量 | 解释
deferred | 共享状态持有的函数正在延迟运行，结果将仅在显式请求时计算
ready | 共享状态就绪
timeout | 共享状态在经过指定的等待时间内仍未就绪

参阅

wait_for | 等待结果，如果在指定的超时间隔后仍然无法得到结果，则返回。 (std::future<T> 的公开成员函数)
wait_for | 等待结果，如果在指定的超时间隔后仍然无法得到结果，则返回。 (std::shared_future<T> 的公开成员函数)
wait_until | 等待结果，如果在已经到达指定的时间点时仍然无法得到结果，则返回。 (std::future<T> 的公开成员函数)
wait_until | 等待结果，如果在已经到达指定的时间点时仍然无法得到结果，则返回。 (std::shared_future<T> 的公开成员函数)


std::this_thread::get_id

< cpp‎ | thread
定义于头文件 <thread> |
std::thread::id get_id() noexcept; | (C++11 起)

返回当前线程的 id 。

参数

（无）

返回值

当前线程的 id

示例

#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>

std::mutex g_display_mutex;

void foo()
{
    std::thread::id this_id = std::this_thread::get_id();

    g_display_mutex.lock();
    std::cout << "thread " << this_id << " sleeping...\n";
    g_display_mutex.unlock();

    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    std::thread t1(foo);
    std::thread t2(foo);

    t1.join();
    t2.join();
}

可能的输出：

thread 0x2384b312 sleeping...
thread 0x228a10fc sleeping...

参阅

get_id
 返回线程的 id
(std::{{{1}}} 的公开成员函数)


std::hardware_destructive_interference_size, std::hardware_constructive_interference_size

< cpp‎ | thread
定义于头文件 <new>
inline constexpr std::size_t
hardware_destructive_interference_size = /*implementation-defined*/;
 (1) (C++17 起)
inline constexpr std::size_t
hardware_constructive_interference_size = /*implementation-defined*/;
 (2) (C++17 起)
1) 二个对象间避免假数据共享的最小偏移。保证至少为 alignof( std::max_align_t )
struct keep_apart {
  alignas(std::hardware_destructive_interference_size) std::atomic<int> cat;
  alignas(std::hardware_destructive_interference_size) std::atomic<int> dog;
};
2) 鼓励真共享的最大连续内存大小。保证至少为 alignof( std::max_align_t )
struct together {
  std::atomic<int> dog;
  int puppy;
};
struct kennel {
  // 其他数据成员……
  alignas(sizeof(together)) together pack;
  // 其他数据成员……
};
static_assert(sizeof(together) <= std::hardware_constructive_interference_size);

注解

这些常量提供一种可移植的访问 L1 数据缓存线大小的方式。

示例

程序使用二个线程（原子地）写入给定全局对象的数据成员。第一个对象适合一条缓存线，这导致“硬件干涉”。第二个对象保持其数据成员在分离的缓存线上，故避免了线程写入后可能的“缓存同步”。

#include <atomic>
#include <chrono>
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <new>
#include <thread>

#ifdef __cpp_lib_hardware_interference_size
    using std::hardware_constructive_interference_size;
    using std::hardware_destructive_interference_size;
#else
    // 在 x86-64 │ L1_CACHE_BYTES │ L1_CACHE_SHIFT │ __cacheline_aligned │ ... 上为 64 字节
    constexpr std::size_t hardware_constructive_interference_size = 64;
    constexpr std::size_t hardware_destructive_interference_size = 64;
#endif

std::mutex cout_mutex;

constexpr int max_write_iterations{10'000'000}; // 性能评估时间调节

struct alignas(hardware_constructive_interference_size)
OneCacheLiner { // 占据一条缓存线
    std::atomic_uint64_t x{};
    std::atomic_uint64_t y{};
} oneCacheLiner;

struct TwoCacheLiner { // 占据二条缓存线
    alignas(hardware_destructive_interference_size) std::atomic_uint64_t x{};
    alignas(hardware_destructive_interference_size) std::atomic_uint64_t y{};
} twoCacheLiner;

inline auto now() noexcept { return std::chrono::high_resolution_clock::now(); }

template<bool xy>
void oneCacheLinerThread() {
    const auto start { now() };

    for (uint64_t count{}; count != max_write_iterations; ++count)
        if constexpr (xy)
             oneCacheLiner.x.fetch_add(1, std::memory_order_relaxed);
        else oneCacheLiner.y.fetch_add(1, std::memory_order_relaxed);

    const std::chrono::duration<double, std::milli> elapsed { now() - start };
    std::lock_guard lk{cout_mutex};
    std::cout << "oneCacheLinerThread() spent " << elapsed.count() << " ms\n";
    if constexpr (xy)
         oneCacheLiner.x = elapsed.count();
    else oneCacheLiner.y = elapsed.count();
}

template<bool xy>
void twoCacheLinerThread() {
    const auto start { now() };

    for (uint64_t count{}; count != max_write_iterations; ++count)
        if constexpr (xy)
             twoCacheLiner.x.fetch_add(1, std::memory_order_relaxed);
        else twoCacheLiner.y.fetch_add(1, std::memory_order_relaxed);

    const std::chrono::duration<double, std::milli> elapsed { now() - start };
    std::lock_guard lk{cout_mutex};
    std::cout << "twoCacheLinerThread() spent " << elapsed.count() << " ms\n";
    if constexpr (xy)
         twoCacheLiner.x = elapsed.count();
    else twoCacheLiner.y = elapsed.count();
}

int main() {
    std::cout << "__cpp_lib_hardware_interference_size "
#   ifdef __cpp_lib_hardware_interference_size
        " = " << __cpp_lib_hardware_interference_size << "\n";
#   else
        "is not defined, use 64 as fallback\n";
#   endif

    std::cout
        << "hardware_destructive_interference_size == "
        << hardware_destructive_interference_size << '\n'
        << "hardware_constructive_interference_size == "
        << hardware_constructive_interference_size << "\n\n";

    std::cout
        << std::fixed << std::setprecision(2)
        << "sizeof( OneCacheLiner ) == " << sizeof( OneCacheLiner ) << '\n'
        << "sizeof( TwoCacheLiner ) == " << sizeof( TwoCacheLiner ) << "\n\n";

    constexpr int max_runs{4};

    int oneCacheLiner_average{0};
    for (auto i{0}; i != max_runs; ++i) {
        std::thread th1{oneCacheLinerThread<0>};
        std::thread th2{oneCacheLinerThread<1>};
        th1.join(); th2.join();
        oneCacheLiner_average += oneCacheLiner.x + oneCacheLiner.y;
    }
    std::cout << "Average time: " << (oneCacheLiner_average / max_runs / 2) << " ms\n\n";

    int twoCacheLiner_average{0};
    for (auto i{0}; i != max_runs; ++i) {
        std::thread th1{twoCacheLinerThread<0>};
        std::thread th2{twoCacheLinerThread<1>};
        th1.join(); th2.join();
        twoCacheLiner_average += twoCacheLiner.x + twoCacheLiner.y;
    }
    std::cout << "Average time: " << (twoCacheLiner_average / max_runs / 2) << " ms\n\n";
}

可能的输出：

__cpp_lib_hardware_interference_size is not defined, use 64 as fallback
hardware_destructive_interference_size == 64
hardware_constructive_interference_size == 64

sizeof( OneCacheLiner ) == 64
sizeof( TwoCacheLiner ) == 128

oneCacheLinerThread() spent 634.25 ms
oneCacheLinerThread() spent 651.55 ms
oneCacheLinerThread() spent 990.23 ms
oneCacheLinerThread() spent 1033.94 ms
oneCacheLinerThread() spent 838.14 ms
oneCacheLinerThread() spent 883.25 ms
oneCacheLinerThread() spent 873.02 ms
oneCacheLinerThread() spent 914.26 ms
Average time: 852 ms

twoCacheLinerThread() spent 119.22 ms
twoCacheLinerThread() spent 127.91 ms
twoCacheLinerThread() spent 114.17 ms
twoCacheLinerThread() spent 126.41 ms
twoCacheLinerThread() spent 125.17 ms
twoCacheLinerThread() spent 126.06 ms
twoCacheLinerThread() spent 117.94 ms
twoCacheLinerThread() spent 129.03 ms
Average time: 122 ms

参阅

hardware_concurrency [静态] | 返回实现支持的并发线程数 (std::thread 的公开静态成员函数)
hardware_concurrency [静态] | 返回实现支持的并发线程数 (std::jthread 的公开静态成员函数)


std::jthread

< cpp‎ | thread
定义于头文件 <thread> |
class jthread; | (C++20 起)

类 jthread 表示单个执行线程。它拥有通常同 std::thread 的行为，除了 jthread 在析构时自动再结合，而且能在具体情况下取消/停止。

线程在构造关联的线程对象时（在任何操作系统调度延迟后）立即开始执行，始于作为构造函数参数提供的顶层函数。忽略顶层函数的返回值，而若它因抛异常退出，则调用 std::terminate 。顶层函数可经由 std::promise 向调用方交流其返回值或异常，或通过修改共享变量（要求同步，见 std::mutex 与 std::atomic ）。

不同于 std::thread ， jthread 逻辑上保有一个内部的 std::stop_source 类型私有成员，它维持共享停止状态。 jthread 的构造函数接受一个 std::stop_token 作为其首参数， jthread 将从其内部的 stop_source 传递它。这允许函数在其执行中检查是否已请求停止，而若已请求则返回。

std::jthread 对象亦可在不表示任何线程的状态（在默认构造、被移动、 detach 或 join 后），而执行线程可以与任何 jthread 对象关联（ detach 后）。

没有二个 std::jthread 对象可表示同一执行线程； std::jthread 非可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) ，尽管它为可移动构造 (MoveConstructible) 及可移动赋值 (MoveAssignable) 。

成员类型

成员类型 | 定义
id | std::thread::id
native_handle_type (可选) | std::thread::native_handle_type

成员函数

(构造函数)
 创建新的 jthread 对象
(公开成员函数)
(析构函数)
 若 joinable() 为 true ，则调用 request_stop() 然后 join() ；不论如何都会销毁 jthread 对象。
(公开成员函数)
operator=
 移动 jthread 对象
(公开成员函数)
观察器
joinable
 检查线程是否可合并，即潜在地运行于平行环境中
(公开成员函数)
get_id
 返回线程的 id
(公开成员函数)
native_handle
 返回底层实现定义的线程句柄
(公开成员函数)
hardware_concurrency
[静态]
 返回实现支持的并发线程数
(公开静态成员函数)
操作
join
 等待线程完成其执行
(公开成员函数)
detach
 容许线程从线程句柄独立开来执行
(公开成员函数)
swap
 交换二个 jthread 对象
(公开成员函数)
停止记号处理
get_stop_source
 返回与线程的停止状态关联的 stop_source 对象
(公开成员函数)
get_stop_token
 返回与线程的共享停止状态关联的 stop_token
(公开成员函数)
request_stop
 请求执行经由线程的共享停止状态停止
(公开成员函数)

非成员函数

swap(std::jthread)
(C++20)
 特化 std::swap 算法
(函数)


std::jthread::detach

< cpp‎ | thread‎ | jthread

void detach(); | (C++20 起)

从 jthread 对象分离执行线程，允许执行独立地持续。一旦该线程退出，则释放任何分配的资源。

调用 detach 后 *this 不再占有任何线程。

参数

（无）

返回值

（无）

后条件

joinable 为 false

异常

若 joinable() == false 或出现任何错误则为 std::system_error 。

示例

#include <iostream>
#include <chrono>
#include <thread>

void independentThread()
{
    std::cout << "Starting concurrent thread.\n";
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "Exiting concurrent thread.\n";
}

void threadCaller()
{
    std::cout << "Starting thread caller.\n";
    std::jthread t(independentThread);
    t.detach();
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Exiting thread caller.\n";
}

int main()
{
    threadCaller();
    std::this_thread::sleep_for(std::chrono::seconds(5));
}

可能的输出：

Starting thread caller.
Starting concurrent thread.
Exiting thread caller.
Exiting concurrent thread.

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 32.4.3.2 Members [thread.jthread.mem]

参阅

join | 等待线程完成其执行 (公开成员函数)
joinable | 检查线程是否可合并，即潜在地运行于平行环境中 (公开成员函数)


std::jthread::get_id

< cpp‎ | thread‎ | jthread

[[nodiscard]] std::jthread::id get_id() const noexcept; | (C++20 起)

返回标识与 *this 关联的线程的 std::jthread::id 。

参数

（无）

返回值

标识与 *this 关联的线程的 std::jthread::id 类型值。若无关联的线程，则返回默认构造的 std::jthread::id 。

示例

#include <iostream>
#include <thread>
#include <chrono>

void foo()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    std::jthread t1(foo);
    std::jthread::id t1_id = t1.get_id();

    std::jthread t2(foo);
    std::jthread::id t2_id = t2.get_id();

    std::cout << "t1's id: " << t1_id << '\n';
    std::cout << "t2's id: " << t2_id << '\n';

}

可能的输出：

t1's id: 0x35a7210f
t2's id: 0x35a311c4

参阅

id | 表示线程的 id (std::thread 的公开成员类)
joinable | 检查线程是否可合并，即潜在地运行于平行环境中 (公开成员函数)


std::jthread::get_stop_source

< cpp‎ | thread‎ | jthread
std::stop_source get_stop_source() const noexcept; | (C++20 起)

返回 std::stop_source ，拥有与 jthread 对象内部所保有者相同的共享停止状态。

参数

（无）

返回值

std::stop_source 类型值，与 jthread 对象内部保有的共享停止状态关联。

示例

本节未完成
原因：暂无示例


std::jthread::get_stop_token

< cpp‎ | thread‎ | jthread
std::stop_token get_stop_token() const noexcept; | (C++20 起)

返回 std::stop_token ，与 jthread 对象内部保有的同一共享停止状态关联。

参数

（无）

返回值

std::stop_token 类型值，与 jthread 对象内部保有的共享停止状态关联。

示例

本节未完成
原因：暂无示例


std::jthread::hardware_concurrency

< cpp‎ | thread‎ | jthread

[[nodiscard]] static unsigned int hardware_concurrency() noexcept; | (C++20 起)

返回实现支持的并发线程数。应该只把该值当做提示。

参数

（无）

返回值

支持的并发线程数。若该值非良定义或不可计算，则返回 ​0​ 。

示例

#include <iostream>
#include <thread>

int main() {
    unsigned int n = std::jthread::hardware_concurrency();
    std::cout << n << " concurrent threads are supported.\n";
}

可能的输出：

4 concurrent threads are supported.

参阅

hardware_destructive_interference_sizehardware_constructive_interference_size
(C++17)
 避免假共享的最小偏移
促使真共享的最大偏移
(常量)


std::jthread::join

< cpp‎ | thread‎ | jthread

void join(); | (C++20 起)

阻塞当前线程直至 *this 所标识的线程结束其执行。

*this 所标识的线程的完成同步于对应的从 join() 成功返回。

*this 自身上不进行同步。同时从多个线程在同一 jthread 对象上调用 join() 构成数据竞争，导致未定义行为。

参数

（无）

返回值

（无）

后条件

joinable() 为 false

异常

若出现错误则为 std::system_error 。

错误条件

  • 若 this->get_id() == std::this_thread::get_id () （检测到死锁）则为 resource_deadlock_would_occur
  • 若线程非法则为 no_such_process
  • 若 joinable() 为 false 则为 invalid_argument

示例

#include <iostream>
#include <thread>
#include <chrono>

void foo()
{
    // 模拟耗费大量资源的操作
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

void bar()
{
    // 模拟耗费大量资源的操作
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    std::cout << "starting first helper...\n";
    std::jthread helper1(foo);

    std::cout << "starting second helper...\n";
    std::jthread helper2(bar);

    std::cout << "waiting for helpers to finish..." << std::endl;
    helper1.join();
    helper2.join();

    std::cout << "done!\n";
}

输出：

starting first helper...
starting second helper...
waiting for helpers to finish...
done!

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 32.4.3.2 Members [thread.jthread.mem]

参阅

detach | 容许线程从线程句柄独立开来执行 (公开成员函数)
joinable | 检查线程是否可合并，即潜在地运行于平行环境中 (公开成员函数)


std::jthread::joinable

< cpp‎ | thread‎ | jthread

[[nodiscard]] bool joinable() const noexcept; | (C++20 起)

检查 std::jthread 对象是否标识活跃的执行线程。具体而言，若 get_id() != std::jthread::id() 则返回 true 。故默认构造的 jthread 不可结合。

结束执行代码，但仍未结合的线程仍被当作活跃的执行线程，从而可结合。

参数

（无）

返回值

若 jthread 对象标识活跃的执行线程则为 true ，否则为 false 。

示例

#include <iostream>
#include <thread>
#include <chrono>

void foo()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    std::jthread t;
    std::cout << "before starting, joinable: " << std::boolalpha << t.joinable()
              << '\n';

    t = std::thread(foo);
    std::cout << "after starting, joinable: " << t.joinable()
              << '\n';

    t.join();
    std::cout << "after joining, joinable: " << t.joinable()
              << '\n';
}

输出：

before starting, joinable: false
after starting, joinable: true
after joining, joinable: false

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 32.4.3.2 Members [thread.jthread.mem]

参阅

get_id | 返回线程的 id (公开成员函数)
join | 等待线程完成其执行 (公开成员函数)
detach | 容许线程从线程句柄独立开来执行 (公开成员函数)


std::jthread::jthread

< cpp‎ | thread‎ | jthread
jthread() noexcept; | (1) | (C++20 起)
jthread( jthread&& other ) noexcept; | (2) | (C++20 起)
template< class Function, class... Args > explicit jthread( Function&& f, Args&&... args ); | (3) | (C++20 起)
jthread( const jthread& ) = delete; | (4) | (C++20 起)

构造新 jthread 对象。

1) 构造不表示线程的新 jthread 对象。
2) 移动构造函数。构造的 jthread 对象表示之前由 other 表示的执行线程。此调用后 other 不再表示执行线程。
3) 创建与执行线程关联的新 jthread 对象。若函数 f 接受 std::stop_token 作为其首参数，则新执行线程开始执行
  • std::invoke (std::move(f_copy), get_stop_token(), std::move(args_copy)...) ，若该表达式合法；否则它开始执行
  • std::invoke (std::move(f_copy), std::move(args_copy)...) 。

任一情况下，

  • f_copy 为从 std::forward <Function>(f) 构造的 std::decay_t <Function> 类型对象，而
  • args_copy... 为从 std::forward <Args>(args)... 构造的 std::decay_t <Args>... 类型对象。
在调用方的环境执行这些对象的构造，故而在求值和移动/构造参数期间抛出的任何异常都在当前线程抛出，而不会开始新线程。若任何构造或 std::invoke 调用非法则程序非良构。
若 std::remove_cvref_t<Function> 与 jthread 为相同类型则此构造函数不参与重载决议。
构造函数的完成同步于（按 std::memory_order 中定义） f 的副本在新线程上调用的开始。
4) 复制构造函数被删除；线程不可复制。没有二个 std::jthread 对象可表示同一执行线程。

参数

other | - | 用以构造此 jthread 对象的另一 jthread 对象
f | - | 执行于新线程的可调用 (Callable) 对象
args... | - | 传递给函数的参数

后条件

1) get_id() 等于 std::jthread::id() （即 joinable() 返回 false ）而 get_stop_source().stop_possible() 为 false
2) other.get_id() 等于 std::jthread::id() 而 get_id() 返回构造开始前 other.get_id() 的值
3) get_id() 不等于 std::jthread::id() （即 joinable() 返回 true ），而 get_stop_source().stop_possible() 为 true 。

异常

3) 若不能开始线程则为 std::system_error 。异常可表示错误条件 std::errc::resource_unavailable_try_again 或另一实现特定的错误条件。

注解

按值复制或移动给线程函数的参数。若需要传递给线程函数引用参数，则必须包装它（例如用 std::ref 或 std::cref ）。

忽略来自函数的任何返回值。若函数抛异常，则调用 std::terminate 。为将返回值或异常传回调用线程，可使用 std::promise 或 std::async 。

示例

#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
using namespace std::literals;

void f1(int n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 1 executing\n";
        ++n;
        std::this_thread::sleep_for(10ms);
    }
}

void f2(int& n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 2 executing\n";
        ++n;
        std::this_thread::sleep_for(10ms);
    }
}

class foo
{
public:
    void bar()
    {
        for (int i = 0; i < 5; ++i) {
            std::cout << "Thread 3 executing\n";
            ++n;
            std::this_thread::sleep_for(10ms);
        }
    }
    int n = 0;
};

class baz
{
public:
    void operator()()
    {
        for (int i = 0; i < 5; ++i) {
            std::cout << "Thread 4 executing\n";
            ++n;
            std::this_thread::sleep_for(10ms);
        }
    }
    int n = 0;
};

int main()
{
    int n = 0;
    foo f;
    baz b;
    std::jthread t0; // t0 不是线程
    std::jthread t1(f1, n + 1); // 按值传递
    std::jthread t2a(f2, std::ref(n)); // 按引用传递
    std::jthread t2b(std::move(t2a)); // t2b 现在运行 f2() 。 t2a 不再是线程
    std::jthread t3(&foo::bar, &f); // t3 在对象 f 上运行 foo::bar()
    std::jthread t4(b); // t4 在对象 b 的副本上运行 baz::operator()
    t1.join();
    t2b.join();
    t3.join();
    std::cout << "Final value of n is " << n << '\n';
    std::cout << "Final value of f.n (foo::n) is " << f.n << '\n';
    std::cout << "Final value of b.n (baz::n) is " << b.n << '\n';
    // t4 在析构时结合
}

可能的输出：

Thread 2 executing
Thread 1 executing
Thread 4 executing
Thread 3 executing
Thread 3 executing
Thread 4 executing
Thread 2 executing
Thread 1 executing
Thread 3 executing
Thread 1 executing
Thread 4 executing
Thread 2 executing
Thread 3 executing
Thread 1 executing
Thread 4 executing
Thread 2 executing
Thread 3 executing
Thread 1 executing
Thread 4 executing
Thread 2 executing
Final value of n is 5
Final value of f.n (foo::n) is 5
Final value of b.n (bar::n) is 0

参阅

(构造函数)
 构造新的 thread 对象
(std::thread 的公开成员函数)


std::jthread::native_handle

< cpp‎ | thread‎ | jthread

[[nodiscard]] native_handle_type native_handle(); | (C++20 起) (可选)

返回实现定义的底层线程柄。

参数

（无）

返回值

表示线程的实现定义柄类型。

异常

可能抛出实现定义的异常。

示例

在 POSIX 系统上用 native_handle 启用 C++ 线程的实时调度

#include <thread>
#include <mutex>
#include <iostream>
#include <chrono>
#include <cstring>
#include <pthread.h>

std::mutex iomutex;
void f(int num)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));

    sched_param sch;
    int policy;
    pthread_getschedparam(pthread_self(), &policy, &sch);
    std::lock_guard<std::mutex> lk(iomutex);
    std::cout << "Thread " << num << " is executing at priority "
              << sch.sched_priority << '\n';
}

int main()
{
    std::jthread t1(f, 1), t2(f, 2);

    sched_param sch;
    int policy;
    pthread_getschedparam(t1.native_handle(), &policy, &sch);
    sch.sched_priority = 20;
    if (pthread_setschedparam(t1.native_handle(), SCHED_FIFO, &sch)) {
        std::cout << "Failed to setschedparam: " << std::strerror(errno) << '\n';
    }

}

输出：

Thread 2 is executing at priority 0
Thread 1 is executing at priority 20


std::jthread::operator=

< cpp‎ | thread‎ | jthread
std::jthread& operator=( std::jthread&& other ) noexcept; | (C++20 起)

若 *this 仍拥有关联的运行线程（即 joinable() == true ），则调用 request_stop() 然后调用 join() 。赋 other 的状态给 *this 并设置 other 为默认构造状态。

此调用后， this->get_id() 等于 other.get_id() 在调用前的值，关联的停止状态亦被移动，而 other 不再表示执行线程或拥有任何停止状态。

参数

other - 赋值给此 jthread 对象的另一 jthread 对象

返回值

*this


std::jthread::request_stop

< cpp‎ | thread‎ | jthread
bool request_stop() noexcept; | (C++20 起)

若内部停止状态尚未被请求停止，则对它发出停止请求。

原子地作出确定，而若请求了停止，则原子地更新共享状态以避免竞争条件，使得：

  • 能在同一共享状态的 std::stop_token 与 std::stop_source 上同时调用 stop_requested() 与 stop_possible()
  • 能从多个线程在同一 jthread 对象或与同一停止状态关联的其他 std::stop_source 对象上并发调用 request_stop() ，而将只有一个线程实际进行停止请求

然而，见注解节。

参数

（无）

返回值

若调用做出停止请求则为 true ，否则为 false 。

后条件

对于由 get_stop_token() 取得的 std::stop_token 或由 get_stop_source() 取得的 std::stop_source ， stop_requested() 为 true 。

注解

若 request_stop() 发出停止请求（即返回 true ），则将在发出 request_stop() 的同一线程上同步调用对同一共享停止状态注册的任何 std::stop_callbacks 。若任何回调的调用经由异常退出，则调用 std::terminate 。

若已作出停止请求，则此函数返回 false 。然而不保证正好对同一停止状态（成功）请求停止的另一线程或 std::stop_source 对象不仍然在调用 std::stop_callback 函数的中间。

若 request_stop() 发出停止请求（即返回 true ），则提醒所有用与 jthread 的内部停止状态关联的 stop_token 的可中断等待注册的、基类型为 std::condition_variable_any 的条件变量。

示例

本节未完成
原因：暂无示例


std::jthread::swap

< cpp‎ | thread‎ | jthread

void swap( std::jthread& other ) noexcept; | (C++20 起)

交换二个 jthread 对象的底层柄。

参数

other - 要与之交换的 jthread

返回值

（无）

示例

#include <iostream>
#include <thread>
#include <chrono>

void foo()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

void bar()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    std::jthread t1(foo);
    std::jthread t2(bar);

    std::cout << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';

    std::swap(t1, t2);

    std::cout << "after std::swap(t1, t2):" << '\n'
              << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';

    t1.swap(t2);

    std::cout << "after t1.swap(t2):" << '\n'
              << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';

}

可能的输出：

thread 1 id: 140185268262656
thread 2 id: 140185259869952
after std::swap(t1, t2):
thread 1 id: 140185259869952
thread 2 id: 140185268262656
after t1.swap(t2):
thread 1 id: 140185268262656
thread 2 id: 140185259869952

参阅

swap(std::jthread)
(C++20)
 特化 std::swap 算法
(函数)


swap(std::jthread)

< cpp‎ | thread‎ | jthread

friend void swap( jthread &lhs, jthread &rhs ) noexcept; | (C++20 起)

对 std::jthread 重载 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。此函数对通常无限定或有限定查找不可见，而只能在 std::jthread 为参数的关联类时由实参依赖查找找到。

参数

lhs, rhs - 要交换状态的 jthread

返回值

（无）

示例

#include <iostream>
#include <thread>
#include <chrono>

void foo()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

void bar()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    using std::swap;

    std::jthread t1(foo);
    std::jthread t2(bar);

    std::cout << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';

    swap(t1, t2);

    std::cout << "after std::swap(t1, t2):" << '\n'
              << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';

    t1.swap(t2);

    std::cout << "after t1.swap(t2):" << '\n'
              << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';

}

可能的输出：

thread 1 id: 1892
thread 2 id: 2584
after std::swap(t1, t2):
thread 1 id: 2584
thread 2 id: 1892
after t1.swap(t2):
thread 1 id: 1892
thread 2 id: 2584

参阅

swap
 交换二个 jthread 对象
(公开成员函数)


std::jthread::~jthread

< cpp‎ | thread‎ | jthread
~jthread(); | (C++20 起)

销毁 jthread 对象。

若 *this 拥有关联线程（ joinable() == true ），则调用 request_stop() 然后 join() 。

注解

若先前已请求 jthread 停止则 request_stop() 无效果。

jthread 在下列操作后无关联线程

  • 它为默认构造
  • 它被移动
  • 已调用 join()
  • 已调用 detach()


std::latch

< cpp‎ | thread
定义于头文件 <latch> |
class latch; | (C++20 起)

latch 是 std::ptrdiff_t 类型的向下计数器，它能用于同步线程。在创建时初始化计数器的值。

线程可能在 latch 上阻塞直至计数器减少到零。没有可能增加或重置计数器，这使得 latch 为单次使用的屏障。

同时调用 latch 的成员函数，除了析构函数，不引入数据竞争。

不同于 std::barrier ，参与线程能减少 std::latch 多于一次。

成员函数

(构造函数)
 构造 latch
(公开成员函数)
(析构函数)
 析构 latch
(公开成员函数)
operator=
[被删除]
 latch 不可赋值
(公开成员函数)
count_down
 以不阻塞的方式减少计数器
(公开成员函数)
try_wait
 测试内部计数器是否等于零
(公开成员函数)
wait
 阻塞直至计数器抵达零
(公开成员函数)
arrive_and_wait
 减少计数器并阻塞直至它抵达零
(公开成员函数)
常量
max
[静态]
 实现所支持的计数器最大值
(公开静态成员函数)

示例

本节未完成
原因：暂无示例

参阅

barrier
(C++20)
 可复用的线程屏障
(类模板)


std::latch::arrive_and_wait

< cpp‎ | thread‎ | latch
void arrive_and_wait( std::ptrdiff_t n = 1 ); | (C++20 起)

原子地减少内部计数器 n （若需要）并阻塞调用方线程直至计数器抵达零。等价于 count_down(n); wait(); 。

若 n 大于内部计数器的值或为负，则行为未定义。

参数

n - 内部计数器要减少的值

返回值

（无）

异常

错误时抛出 std::system_error ，带有对互斥体类型允许的错误码。


std::latch::count_down

< cpp‎ | thread‎ | latch
void count_down( std::ptrdiff_t n = 1 ); | (C++20 起)

原子地减少内部计数器 n 而不阻塞调用方。

若 n 大于内部计数器的值或为负，则行为未定义。

此操作强先发生于所有于此 latch 上除阻的调用。

参数

n - 内部计数器所自减的值

返回值

（无）

异常

错误时抛出 std::system_error ，带有对互斥体类型允许的错误码。


std::latch::latch

< cpp‎ | thread‎ | latch
constexpr explicit latch( std::ptrdiff_t expected ); | (1) | (C++20 起)
latch( const latch & ) = delete; | (2) | (C++20 起)
1) 构造 latch 并初始化其内部计数器。若 expected 为负或大于 max() 则行为未定义。
2) 复制构造函数被删除。 latch 既不可复制亦不可移动。

参数

expected - 内部计数器的初值

异常

不抛出。


std::latch::max

< cpp‎ | thread‎ | latch
static constexpr std::ptrdiff_t max() noexcept; | (C++20 起)

返回实现所支持的内部计数器的最大值。

参数

（无）

返回值

实现所支持的内部计数器的最大值。


std::latch::try_wait

< cpp‎ | thread‎ | latch
bool try_wait() const noexcept; | (C++20 起)

仅若内部计数器抵达零才返回 true 。即使内部计数器抵达零，此函数亦可能以非常低的概率虚假地返回 false 。

参数

（无）

返回值

以非常低的概率为 false ，否则为 cnt == 0 ，其中 cnt 是内部计数器的值。

注解

容许虚假结果的原因是为允许实现使用比 std::memory_order_seq_cst 宽松的内存顺序。


std::latch::wait

< cpp‎ | thread‎ | latch
void wait() const; | (C++20 起)

阻塞调用方线程直至内部计数器抵达 0 。若它已为零，则立即返回。

参数

（无）

返回值

（无）

异常

错误时抛出 std::system_error ，带有对互斥体类型允许的错误码。


std::latch::~latch

< cpp‎ | thread‎ | latch
~latch(); | (C++20 起)

销毁 latch 。

注解

若有任何线程在同时调用 latch 的成员函数则行为未定义。


std::launch

< cpp‎ | thread
定义于头文件 <future>
enum class launch : /* unspecified */ {

async = /* unspecified */,
deferred = /* unspecified */,
/* implementation-defined */

};
 (C++11 起)

指定 std::async 所指定的任务的的运行策略。 std::launch 是用作位掩码类型 (BitmaskType) 的枚举。

标准库定义下列代表单独位的常量：

常量 | 解释
std::launch::async | 运行新线程，以异步执行任务
std::launch::deferred | 调用方线程上首次请求其结果时执行任务（惰性求值）

另外，允许实现：

  • 定义额外的位和位掩码，以指定可应用于运行策略子集的任务交互上的限制，并
  • 对 std::async 的首个（默认）重载启用这些额外位掩码。

参阅

async
(C++11)
 异步运行一个函数（有可能在新线程中执行），并返回保有其结果的 std::future
(函数模板)


std::lock

< cpp‎ | thread
定义于头文件 <mutex> |
template< class Lockable1, class Lockable2, class... LockableN > void lock( Lockable1& lock1, Lockable2& lock2, LockableN&... lockn ); | (C++11 起)

锁定给定的可锁定 (Lockable) 对象 lock1 、 lock2 、 ... 、 lockn ，用免死锁算法避免死锁。

以对 lock 、 try_lock 和 unlock 的未指定系列调用锁定对象。若调用 lock 或 unlock 导致异常，则在重抛前对任何已锁的对象调用 unlock 。

参数

lock1, lock2, ... , lockn - 要锁定的可锁定 (Lockable) 对象

返回值

（无）

注意

Boost 提供此函数的一个版本，它接收以一对迭代器定义的可锁定 (Lockable) 对象序列。

std::scoped_lock 提供此函数的 RAII 包装，通常它比裸调用 std::lock 更好。

示例

下列示例用 std::lock 锁定互斥对，而不死锁。

#include <mutex>
#include <thread>
#include <iostream>
#include <vector>
#include <functional>
#include <chrono>
#include <string>

struct Employee {
    Employee(std::string id) : id(id) {}
    std::string id;
    std::vector<std::string> lunch_partners;
    std::mutex m;
    std::string output() const
    {
        std::string ret = "Employee " + id + " has lunch partners: ";
        for( const auto& partner : lunch_partners )
            ret += partner + " ";
        return ret;
    }
};

void send_mail(Employee &, Employee &)
{
    // 模拟耗时的发信操作
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

void assign_lunch_partner(Employee &e1, Employee &e2)
{
    static std::mutex io_mutex;
    {
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << e1.id << " and " << e2.id << " are waiting for locks" << std::endl;
    }

    // 用 std::lock 获得二个锁，而不担心对 assign_lunch_partner 的其他调用会死锁我们
    {
        std::lock(e1.m, e2.m);
        std::lock_guard<std::mutex> lk1(e1.m, std::adopt_lock);
        std::lock_guard<std::mutex> lk2(e2.m, std::adopt_lock);
// 等价代码（若需要 unique_locks ，例如对于条件变量）
//        std::unique_lock<std::mutex> lk1(e1.m, std::defer_lock);
//        std::unique_lock<std::mutex> lk2(e2.m, std::defer_lock);
//        std::lock(lk1, lk2);
// C++17 中可用的较优解法
//        std::scoped_lock lk(e1.m, e2.m);
        {
            std::lock_guard<std::mutex> lk(io_mutex);
            std::cout << e1.id << " and " << e2.id << " got locks" << std::endl;
        }
        e1.lunch_partners.push_back(e2.id);
        e2.lunch_partners.push_back(e1.id);
    }
    send_mail(e1, e2);
    send_mail(e2, e1);
}

int main()
{
    Employee alice("alice"), bob("bob"), christina("christina"), dave("dave");

    // 在平行线程指派，因为发邮件给用户告知午餐指派，会消耗长时间
    std::vector<std::thread> threads;
    threads.emplace_back(assign_lunch_partner, std::ref(alice), std::ref(bob));
    threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(bob));
    threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(alice));
    threads.emplace_back(assign_lunch_partner, std::ref(dave), std::ref(bob));

    for (auto &thread : threads) thread.join();
    std::cout << alice.output() << '\n'  << bob.output() << '\n'
              << christina.output() << '\n' << dave.output() << '\n';
}

可能的输出：

alice and bob are waiting for locks
alice and bob got locks
christina and bob are waiting for locks
christina and bob got locks
christina and alice are waiting for locks
christina and alice got locks
dave and bob are waiting for locks
dave and bob got locks
Employee alice has lunch partners: bob christina
Employee bob has lunch partners: alice christina dave
Employee christina has lunch partners: bob alice
Employee dave has lunch partners: bob

参阅

try_lock (C++11) | 试图通过重复调用 try_lock 获得互斥体的所有权 (函数模板)
scoped_lock (C++17) | 用于多个互斥体的免死锁 RAII 封装器 (类模板)


std::lock_guard

< cpp‎ | thread
定义于头文件 <mutex>
template< class Mutex >
class lock_guard;

类 lock_guard 是互斥体包装器，为在作用域块期间占有互斥提供便利 RAII 风格机制。

创建 lock_guard 对象时，它试图接收给定互斥的所有权。控制离开创建 lock_guard 对象的作用域时，销毁 lock_guard 并释放互斥。

lock_guard 类不可复制。

模板形参

Mutex - 要锁定的互斥。类型必须满足基本可锁定 (BasicLockable) 要求

成员类型

成员类型 | 定义
mutex_type | Mutex

成员函数

(构造函数) | 构造 lock_guard ，可选地锁定给定的互斥 (公开成员函数)
(析构函数) | 析构 lock_guard 对象，解锁底层互斥 (公开成员函数)
operator= [被删除] | 不可复制赋值 (公开成员函数)

注解

std::scoped_lock 给出 lock_guard 的一种替代，用避免死锁的算法提供锁定多个互斥体的能力。

 (C++17 起)

示例

#include <thread>
#include <mutex>
#include <iostream>

int g_i = 0;
std::mutex g_i_mutex;  // 保护 g_i

void safe_increment()
{
    std::lock_guard<std::mutex> lock(g_i_mutex);
    ++g_i;

    std::cout << std::this_thread::get_id() << ": " << g_i << '\n';

    // g_i_mutex 在锁离开作用域时自动释放
}

int main()
{
    std::cout << "main: " << g_i << '\n';

    std::thread t1(safe_increment);
    std::thread t2(safe_increment);

    t1.join();
    t2.join();

    std::cout << "main: " << g_i << '\n';
}

可能的输出：

main: 0
140641306900224: 1
140641298507520: 2
main: 2

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2981 | C++17 | 曾提供来自 lock_guard<Mutex> 的冗余推导指引 | 已移除

参阅

unique_lock (C++11) | 实现可移动的互斥体所有权包装器 (类模板)
scoped_lock (C++17) | 用于多个互斥体的免死锁 RAII 封装器 (类模板)


std::lock_guard<Mutex>::lock_guard

< cpp‎ | thread‎ | lock guard
explicit lock_guard( mutex_type& m ); | (1) | (C++11 起)
lock_guard( mutex_type& m, std::adopt_lock_t t ); | (2) | (C++11 起)
lock_guard( const lock_guard& ) = delete; | (3) | (C++11 起)

获得给定互斥 m 的所有权。

1) 等效地调用 m.lock() 。
2) 获得互斥 m 的所有权而不试图锁定它。若当前线程不在 m 上保有非共享锁（即由 lock、 try_lock、 try_lock_for 或 try_lock_until 取得的锁）则行为未定义。
3) 复制构造函数被删除。

若在 m 先于 lock_guard 对象被销毁，则行为未定义。

参数

m | - | 要获得所有权的共享互斥
t | - | 用于选择构造函数非锁定版本的标签参数

异常

1) 抛任何 m.lock() 所抛的异常
2) 不抛出


std::lock_guard<Mutex>::~lock_guard

< cpp‎ | thread‎ | lock guard
~lock_guard(); | (C++11 起)

释放所占有互斥的所有权。

等效地调用 m.unlock() ，其中 m 是传递个 lock_guard 的构造函数的互斥。


std::defer_lock, std::try_to_lock, std::adopt_lock

< cpp‎ | thread
定义于头文件 <mutex> |
constexpr std::defer_lock_t defer_lock {}; | (C++11 起) (C++17 前)
inline constexpr std::defer_lock_t defer_lock {}; | (C++17 起)
constexpr std::try_to_lock_t try_to_lock {}; | (C++11 起) (C++17 前)
inline constexpr std::try_to_lock_t try_to_lock {}; | (C++17 起)
constexpr std::adopt_lock_t adopt_lock {}; | (C++11 起) (C++17 前)
inline constexpr std::adopt_lock_t adopt_lock {}; | (C++17 起)

std::defer_lock 、 std::try_to_lock 和 std::adopt_lock 分别是空结构体标签类型 std::defer_lock_t 、 std::try_to_lock_t 和 std::adopt_lock_t 的实例。

它们用于为 std::lock_guard 、 std::unique_lock 及 std::shared_lock 指定锁定策略。

类型 | 效果
defer_lock_t | 不获得互斥的所有权
try_to_lock_t | 尝试获得互斥的所有权而不阻塞
adopt_lock_t | 假设调用方线程已拥有互斥的所有权

示例

#include <mutex>
#include <thread>

struct bank_account {
    explicit bank_account(int balance) : balance(balance) {}
    int balance;
    std::mutex m;
};

void transfer(bank_account &from, bank_account &to, int amount)
{
    // 锁定两个互斥而不死锁
    std::lock(from.m, to.m);
    // 保证二个已锁定互斥在作用域结尾解锁
    std::lock_guard<std::mutex> lock1(from.m, std::adopt_lock);
    std::lock_guard<std::mutex> lock2(to.m, std::adopt_lock);

// 等价方法：
//    std::unique_lock<std::mutex> lock1(from.m, std::defer_lock);
//    std::unique_lock<std::mutex> lock2(to.m, std::defer_lock);
//    std::lock(lock1, lock2);

    from.balance -= amount;
    to.balance += amount;
}

int main()
{
    bank_account my_account(100);
    bank_account your_account(50);

    std::thread t1(transfer, std::ref(my_account), std::ref(your_account), 10);
    std::thread t2(transfer, std::ref(your_account), std::ref(my_account), 5);

    t1.join();
    t2.join();
}

参阅

defer_lock_ttry_to_lock_tadopt_lock_t (C++11)(C++11)(C++11) | 用于指定锁定策略的标签类型 (类)
(构造函数) | 构造 lock_guard ，可选地锁定给定的互斥 (std::lock_guard<Mutex> 的公开成员函数)
(构造函数) | 构造 unique_lock ，可选地锁定提供的互斥 (std::unique_lock<Mutex> 的公开成员函数)


std::defer_lock_t, std::try_to_lock_t, std::adopt_lock_t

< cpp‎ | thread
定义于头文件 <mutex>
struct defer_lock_t { explicit defer_lock_t() = default; };

struct try_to_lock_t { explicit try_to_lock_t() = default; };

struct adopt_lock_t { explicit adopt_lock_t() = default; };
 (C++11 起)

std::defer_lock_t 、 std::try_to_lock_t 和 std::adopt_lock_t 是用于为 std::lock_guard 、 std::scoped_lock 、 std::unique_lock 和 std::shared_lock 指定锁定策略的空类标签类型。

类型 | 效果
defer_lock_t | 不获得互斥的所有权
try_to_lock_t | 尝试获得互斥的所有权而不阻塞
adopt_lock_t | 假设调用方线程已拥有互斥的所有权

示例

#include <mutex>
#include <thread>

struct bank_account {
    explicit bank_account(int balance) : balance(balance) {}
    int balance;
    std::mutex m;
};

void transfer(bank_account &from, bank_account &to, int amount)
{
    // 锁定两个互斥而不死锁
    std::lock(from.m, to.m);
    // 保证二个已锁定互斥在作用域结尾解锁
    std::lock_guard<std::mutex> lock1(from.m, std::adopt_lock);
    std::lock_guard<std::mutex> lock2(to.m, std::adopt_lock);

// 等价方法：
//    std::unique_lock<std::mutex> lock1(from.m, std::defer_lock);
//    std::unique_lock<std::mutex> lock2(to.m, std::defer_lock);
//    std::lock(lock1, lock2);

    from.balance -= amount;
    to.balance += amount;
}

int main()
{
    bank_account my_account(100);
    bank_account your_account(50);

    std::thread t1(transfer, std::ref(my_account), std::ref(your_account), 10);
    std::thread t2(transfer, std::ref(your_account), std::ref(my_account), 5);

    t1.join();
    t2.join();
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2510 | C++11 | 默认构造函数为非 explicit ，能导致歧义 | 使之为 explicit

参阅

defer_locktry_to_lockadopt_lock (C++11)(C++11)(C++11) | 用于指定锁定策略的标签常量 (常量)
(构造函数) | 构造 lock_guard ，可选地锁定给定的互斥 (std::lock_guard<Mutex> 的公开成员函数)
(构造函数) | 构造 unique_lock ，可选地锁定提供的互斥 (std::unique_lock<Mutex> 的公开成员函数)


std::mutex

< cpp‎ | thread
定义于头文件 <mutex> |
class mutex; | (C++11 起)

mutex 类是能用于保护共享数据免受从多个线程同时访问的同步原语。

mutex 提供排他性非递归所有权语义：

  • 调用方线程从它成功调用 lock 或 try_lock 开始，到它调用 unlock 为止占有 mutex 。
  • 线程占有 mutex 时，所有其他线程若试图要求 mutex 的所有权，则将阻塞（对于 lock 的调用）或收到 false 返回值（对于 try_lock ）.
  • 调用方线程在调用 lock 或 try_lock 前必须不占有 mutex 。

若 mutex 在仍为任何线程所占有时即被销毁，或在占有 mutex 时线程终止，则行为未定义。 mutex 类满足互斥体 (Mutex) 和标准布局类型 (StandardLayoutType) 的全部要求。

std::mutex 既不可复制亦不可移动。

成员类型

成员类型 | 定义
native_handle_type(可选) | 实现定义

成员函数

(构造函数)
 构造互斥
(公开成员函数)
(析构函数)
 销毁互斥
(公开成员函数)
operator=
[被删除]
 不可复制赋值
(公开成员函数)
锁定
lock
 锁定互斥，若互斥不可用则阻塞
(公开成员函数)
try_lock
 尝试锁定互斥，若互斥不可用则返回
(公开成员函数)
unlock
 解锁互斥
(公开成员函数)
原生句柄
native_handle
 返回底层实现定义的原生句柄
(公开成员函数)

注意

通常不直接使用 std::mutex ： std::unique_lock 、 std::lock_guard 或 std::scoped_lock (C++17 起)以更加异常安全的方式管理锁定。

示例

此示例展示 mutex 能如何用于在保护共享于二个线程间的 std::map 。

#include <iostream>
#include <map>
#include <string>
#include <chrono>
#include <thread>
#include <mutex>

std::map<std::string, std::string> g_pages;
std::mutex g_pages_mutex;

void save_page(const std::string &url)
{
    // 模拟长页面读取
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::string result = "fake content";

    std::lock_guard<std::mutex> guard(g_pages_mutex);
    g_pages[url] = result;
}

int main()
{
    std::thread t1(save_page, "http://foo");
    std::thread t2(save_page, "http://bar");
    t1.join();
    t2.join();

    // 现在访问g_pages是安全的，因为线程t1/t2生命周期已结束
    for (const auto &pair : g_pages) {
        std::cout << pair.first << " => " << pair.second << '\n';
    }
}

输出：

http://bar => fake content
http://foo => fake content


std::mutex::lock

< cpp‎ | thread‎ | mutex

void lock(); | (C++11 起)

锁定互斥。若另一线程已锁定互斥，则到 lock 的调用将阻塞执行，直至获得锁。

若 lock 为已占有 mutex 的线程调用，则行为未定义：例如，程序可能死锁。鼓励能检测非法使用的实现抛出以 resource_deadlock_would_occur 为错误条件的 std::system_error ，而不是死锁。

同一互斥上先前的 unlock() 操作同步于（定义于 std::memory_order ）此操作。

参数

（无）

返回值

（无）

异常

错误发生时抛出 std::system_error ，包括底层操作系统阻止 lock 满足其规定的错误。在抛出任何异常的情况下，不锁定互斥。

注意

通常不直接调用 lock() ：用 std::unique_lock 与 std::lock_guard 管理排他性锁定。

示例

此示例演示 lock 与 unlock 能如何用于保护共享数据。

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>

int g_num = 0;  // 为 g_num_mutex 所保护
std::mutex g_num_mutex;

void slow_increment(int id)
{
    for (int i = 0; i < 3; ++i) {
        g_num_mutex.lock();
        ++g_num;
        std::cout << id << " => " << g_num << '\n';
        g_num_mutex.unlock();

        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main()
{
    std::thread t1(slow_increment, 0);
    std::thread t2(slow_increment, 1);
    t1.join();
    t2.join();
}

可能的输出：

0 => 1
1 => 2
0 => 3
1 => 4
0 => 5
1 => 6

参阅

try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::mutex::mutex

< cpp‎ | thread‎ | mutex

mutex(); | (1) | (C++11 起)
mutex( const mutex& ) = delete; | (2) | (C++11 起)
1) 构造互斥。调用后互斥在未锁定状态。
2) 复制构造函数被删除。

参数

（无）

异常

若构造不成功则抛出 std::system_error 。

参阅


std::mutex::native_handle

< cpp‎ | thread‎ | mutex

native_handle_type native_handle(); | (C++11 起) (可选)

返回底层实现定义的原生句柄对象。

参数

（无）

返回值

实现定义的原生句柄对象。

异常

实现定义。

示例

本节未完成
原因：暂无示例


std::mutex::try_lock

< cpp‎ | thread‎ | mutex

bool try_lock(); | (C++11 起)

尝试锁定互斥。立即返回。成功获得锁时返回 true ，否则返回 false 。

允许此函数虚假地失败而返回 false ，即使互斥当前未为任何其他线程所锁定。

若已占有 mutex 的线程调用 try_lock ，则行为未定义。

若此操作返回 true ，则同一互斥上的先前 unlock() 操作同步于（定义于 std::memory_order ）它。注意若此操作返回 false ，则先前的 lock() 不与之同步。

参数

（无）

返回值

若成功取得锁则为 true ，否则为 false 。

异常

不抛出。

示例

#include <chrono>
#include <mutex>
#include <thread>
#include <iostream> // std::cout

std::chrono::milliseconds interval(100);

std::mutex mutex;
int job_shared = 0; // 两个线程都能修改 'job_shared',
    // mutex 将保护此变量

int job_exclusive = 0; // 只有一个线程能修改 'job_exclusive'
    // 不需要保护

// 此线程能修改 'job_shared' 和 'job_exclusive'
void job_1()
{
    std::this_thread::sleep_for(interval); // 令 'job_2' 持锁

    while (true) {
        // 尝试锁定 mutex 以修改 'job_shared'
        if (mutex.try_lock()) {
            std::cout << "job shared (" << job_shared << ")\n";
            mutex.unlock();
            return;
        } else {
            // 不能获取锁以修改 'job_shared'
            // 但有其他工作可做
            ++job_exclusive;
            std::cout << "job exclusive (" << job_exclusive << ")\n";
            std::this_thread::sleep_for(interval);
        }
    }
}

// 此线程只能修改 'job_shared'
void job_2()
{
    mutex.lock();
    std::this_thread::sleep_for(5 * interval);
    ++job_shared;
    mutex.unlock();
}

int main()
{
    std::thread thread_1(job_1);
    std::thread thread_2(job_2);

    thread_1.join();
    thread_2.join();
}

可能的输出：

job exclusive (1)
job exclusive (2)
job exclusive (3)
job exclusive (4)
job shared (1)

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::mutex::unlock

< cpp‎ | thread‎ | mutex

void unlock(); | (C++11 起)

解锁互斥。

互斥必须为当前执行线程所锁定，否则行为未定义。

此操作同步于（定义于 std::memory_order ）任何后继的取得同一互斥所有权的锁操作。

参数

（无）

返回值

（无）

异常

不抛出。

注解

通常不直接调用 unlock() ：用 std::unique_lock 与 std::lock_guard 管理互斥锁定。

示例

此示例演示 lock 与 unlock 能如何保护共享数据。

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>

int g_num = 0;  // 为 g_num_mutex 所保护
std::mutex g_num_mutex;

void slow_increment(int id)
{
    for (int i = 0; i < 3; ++i) {
        g_num_mutex.lock();
        ++g_num;
        std::cout << id << " => " << g_num << '\n';
        g_num_mutex.unlock();

        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main()
{
    std::thread t1(slow_increment, 0);
    std::thread t2(slow_increment, 1);
    t1.join();
    t2.join();
}

可能的输出：

0 => 1
1 => 2
0 => 3
1 => 4
0 => 5
1 => 6

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)


std::mutex::~mutex

< cpp‎ | thread‎ | mutex

~mutex();

销毁互斥。

若互斥为任何线程占有，或若任何线程在保有任何互斥的所有权时终止，则行为未定义。

参阅


std::notify_all_at_thread_exit

< cpp‎ | thread
定义于头文件 <condition_variable>
void notify_all_at_thread_exit( std::condition_variable & cond,
std::unique_lock < std::mutex > lk );
 (C++11 起)

notify_all_at_thread_exit 提供机制，通知其他线程给定的线程已完全完成，包括销毁所有 thread_local 对象。它操作如下：

  • 将先前获得的锁 lk 的所有权转移到内部存储。
  • 修改执行环境，以令当前线程退出时，如同以下列方式通知 condition_variable cond ：

lk.unlock();
cond.notify_all();

隐含的 lk.unlock 后序于（定义于 std::memory_order ）关联到当前线程的，所有拥有线程局域存储期的对象析构。

等价的效果可以用 std::promise 或 std::packaged_task 所提供的设施达成。

注意

若当前线程未锁定 lock.mutex() ，则调用此函数是未定义行为。

若 lock.mutex() 与所有其他等待在同一条件变量上的线程所用的互斥不相同，则调用此函数是未定义行为。

保有提供的锁 lk 直至线程退出。一旦调用此函数，则无更多线程可获得相同的锁，以在 cond 上等待。若某线程在此条件变量上等待，则它在虚假唤醒时不应试图释放和重获得锁。

典型使用情况中，此函数是被脱附线程所做的最后行动。

参数

cond | - | 在线程退出时通知的 conditional_variable
lk | - | 关联到 condition_variable cond 的锁

返回值

（无）

示例

此部分代码零碎地描绘 notify_all_at_thread_exit 能如何用于避免在线程局域对象处于被析构过程时，访问依赖于它们的数据：

#include <mutex>
#include <thread>
#include <condition_variable>

std::mutex m;
std::condition_variable cv;

bool ready = false;
ComplexType result;  // 一些任意类型

void thread_func()
{
    std::unique_lock<std::mutex> lk(m);
    // 用 thread_local 数据赋值给 result
    result = function_that_uses_thread_locals();
    ready = true;
    std::notify_all_at_thread_exit(cv, std::move(lk));
} // 1. 销毁 thread_local 对象， 2. 解锁互斥， 3. 通知 cv

int main()
{
    std::thread t(thread_func);
    t.detach();

    // 做其他工作
    // .…

    // 等待脱附的线程
    std::unique_lock<std::mutex> lk(m);
    while(!ready) {
        cv.wait(lk);
    }
    process(result); // result 已准备且 thread_local 析构函数已完成
}

参阅

set_value_at_thread_exit | 设置结果为指定值，同时仅在线程退出时分发提醒 (std::promise<R> 的公开成员函数)
make_ready_at_thread_exit | 执行函数，并确保结果仅在一旦当前线程退出时就绪 (std::packaged_task<R(Args...)> 的公开成员函数)


std::once_flag

< cpp‎ | thread
定义于头文件 <mutex> |
class once_flag; | (C++11 起)

类 std::once_flag 是 std::call_once 的辅助类。

传递给多个 std::call_once 调用的 std::once_flag 对象允许那些调用彼此协调，从而只令调用之一实际运行完成。

std::once_flag 既不可复制亦不可移动。

成员函数

std::once_flag::once_flag

constexpr once_flag() noexcept;

构造 once_flag 对象。设置内部状态为指示尚未调用函数。

参数

（无）

参阅

call_once
(C++11)
 仅调用函数一次，即使从多个线程调用
(函数模板)


std::packaged_task

< cpp‎ | thread
定义于头文件 <future> |  |
template< class > class packaged_task; // 不定义 | (1) | (C++11 起)
template< class R, class ...Args > class packaged_task<R(Args...)>; | (2) | (C++11 起)

类模板 std::packaged_task 包装任何可调用 (Callable) 目标（函数、 lambda 表达式、 bind 表达式或其他函数对象），使得能异步调用它。其返回值或所抛异常被存储于能通过 std::future 对象访问的共享状态中。

正如 std::function ， std::packaged_task 是多态、具分配器的容器：可在堆上或以提供的分配器分配存储的可调用对象。

成员函数

(构造函数)
 构造任务对象
(公开成员函数)
(析构函数)
 析构任务对象
(公开成员函数)
operator=
 移动任务对象
(公开成员函数)
valid
 检查任务对象是否拥有合法函数
(公开成员函数)
swap
 交换二个任务对象
(公开成员函数)
获取结果
get_future
 返回与承诺的结果关联的 std::future
(公开成员函数)
执行
operator()
 执行函数
(公开成员函数)
make_ready_at_thread_exit
 执行函数，并确保结果仅在一旦当前线程退出时就绪
(公开成员函数)
reset
 重置状态，抛弃任何先前执行的存储结果
(公开成员函数)

非成员函数

std::swap(std::packaged_task)
(C++11)
 特化 std::swap 算法
(函数模板)

辅助类

std::uses_allocator<std::packaged_task>
(C++11)(C++17 前)
 特化 std::uses_allocator 类型特征
(类模板特化)

推导指引 (C++17 起)

示例

#include <iostream>
#include <cmath>
#include <thread>
#include <future>
#include <functional>

// 避免对 std::pow 重载集消歧义的独有函数
int f(int x, int y) { return std::pow(x,y); }

void task_lambda()
{
    std::packaged_task<int(int,int)> task([](int a, int b) {
        return std::pow(a, b);
    });
    std::future<int> result = task.get_future();

    task(2, 9);

    std::cout << "task_lambda:\t" << result.get() << '\n';
}

void task_bind()
{
    std::packaged_task<int()> task(std::bind(f, 2, 11));
    std::future<int> result = task.get_future();

    task();

    std::cout << "task_bind:\t" << result.get() << '\n';
}

void task_thread()
{
    std::packaged_task<int(int,int)> task(f);
    std::future<int> result = task.get_future();

    std::thread task_td(std::move(task), 2, 10);
    task_td.join();

    std::cout << "task_thread:\t" << result.get() << '\n';
}

int main()
{
    task_lambda();
    task_bind();
    task_thread();
}

输出：

task_lambda: 512
task_bind:   2048
task_thread: 1024

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3117 | C++17 | packaged_task 的推导指引缺失 | 已添加

参阅

future
(C++11)
 等待被异步设置的值
(类模板)


std::packaged_task 的推导指引

< cpp‎ | thread‎ | packaged task
定义于头文件 <future> |  |
template<class R, class... Args> packaged_task(R(*)(Args...)) -> packaged_task<R(Args...)>; | (1) | (C++17 起)
template<class F> packaged_task(F) -> packaged_task</*see below*/>; | (2) | (C++17 起)
1) 为 std::packaged_task 提供此推导指引以允许从函数推导。
2) 此重载仅若 &F::operator() 在作为不求值运算数时为良构且 decltype(&F::operator()) 拥有形式 R(G::*)(A...) （可选地有 cv 限定，可选地有 noexcept ， 可选地有左值引用限定）而 G 为类类型才参与重载决议。推导类型为 std::packaged_task <R(A...)> 。

示例

#include <future>
int func(double) { return 0; }
int main() {
  std::packaged_task f{func}; // 推导出 packaged_task<int(double)>
  int i = 5;
  std::packaged_task g = [&](double) { return i; }; // 推导出 packaged_task<int(double)>
}


std::packaged_task<R(Args...)>::get_future

< cpp‎ | thread‎ | packaged task
std::future <R> get_future(); | (C++11 起)

返回与 *this 共享同一共享状态的 future 。

get_future 只能对每个 packaged_task 调用一次。

参数

（无）

返回值

与 *this 共享同一共享状态的 future 。

异常

遇到下列条件时为 std::future_error 。

  • 已通过调用 get_future 取得共享状态。设置 error_category 为 future_already_retrieved 。
  • *this 无共享状态。设置 error_category 为 no_state 。


std::packaged_task<R(Args...)>::make_ready_at_thread_exit

< cpp‎ | thread‎ | packaged task
void make_ready_at_thread_exit( ArgTypes... args ); | (C++11 起)

以转发的 args 为参数调用存储的任务。任务返回值或任何抛出的异常被存储于 *this 的共享状态。

仅在当前线程退出，并销毁所有线程局域存储期对象后，才令共享状态就绪。

参数

args - 调用时传递给存储任务的参数

返回值

（无）

异常

遇到下列条件时为 std::future_error ：

  • 已调用存储的任务。设置 error_category 为 promise_already_satisfied 。
  • *this 无共享状态。设置 error_category 为 no_state 。

示例

#include <future>
#include <iostream>
#include <chrono>
#include <thread>
#include <functional>
#include <utility>

void worker(std::future<void>& output)
{
    std::packaged_task<void(bool&)> my_task{ [](bool& done) { done=true; } };

    auto result = my_task.get_future();

    bool done = false;

    my_task.make_ready_at_thread_exit(done); // 立即执行任务

    std::cout << "worker: done = " << std::boolalpha << done << std::endl;

    auto status = result.wait_for(std::chrono::seconds(0));
    if (status == std::future_status::timeout)
        std::cout << "worker: result is not ready yet" << std::endl;

    output = std::move(result);
}

int main()
{
    std::future<void> result;

    std::thread{worker, std::ref(result)}.join();

    auto status = result.wait_for(std::chrono::seconds(0));
    if (status == std::future_status::ready)
        std::cout << "main: result is ready" << std::endl;
}

输出：

worker: done = true
worker: result is not ready yet
main: result is ready

参阅

operator()
 执行函数
(公开成员函数)


std::packaged_task<R(Args...)>::operator()

< cpp‎ | thread‎ | packaged task
void operator()( ArgTypes... args ); | (C++11 起)

以 args 为参数调用存储的任务。任务返回值或任何抛出的异常被存储于共享状态。令共享状态就绪，并解除阻塞任何等待此操作的线程。

参数

args - 调用时传递给存储任务的参数

返回值

（无）

异常

遇到下列条件时为 std::future_error ：

  • 已调用存储的任务。设置 error_category 为 promise_already_satisfied 。
  • *this 无共享状态。设置 error_category 为 no_state 。

注意

对 operator() 的成功调用同步于对任何与 *this 共享其共享状态的 std::future 或 std::shared_future 的任何成员函数调用。 | (C++14 前)
在共享状态已提供的同步保证外，无另外的同步保证。 | (C++14 起)

示例

本节未完成
原因：暂无示例

参阅

make_ready_at_thread_exit
 执行函数，并确保结果仅在一旦当前线程退出时就绪
(公开成员函数)


std::packaged_task<R(Args...)>::operator=

< cpp‎ | thread‎ | packaged task
packaged_task& operator=( const packaged_task& ) = delete; | (1) | (C++11 起)
packaged_task& operator=( packaged_task&& rhs ) noexcept; | (2) | (C++11 起)
1) 复制赋值运算符被删除， std::packaged_task 仅可移动。
2) 若存在则释放共享状态，销毁先前保有的任务，并将 rhs 所占有的共享状态和任务移动到 *this 。令 rhs 无共享状态，并拥有被移动后的任务。

参数

rhs - 移动来源的 std::packaged_task

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2067 | C++11 | 被删除的复制赋值运算符接收非 const 引用 | 使之为 const

示例

本节未完成
原因：暂无示例


std::packaged_task<R(Args...)>::packaged_task

< cpp‎ | thread‎ | packaged task
packaged_task() noexcept; | (1) | (C++11 起)
template <class F> explicit packaged_task( F&& f ); | (2) | (C++11 起)
template <class F, class Allocator> explicit packaged_task( std::allocator_arg_t, const Allocator& a, F&& f ); | (3) | (C++11 起) (C++17 前)
packaged_task( const packaged_task& ) = delete; | (4) | (C++11 起)
packaged_task( packaged_task&& rhs ) noexcept; | (5) | (C++11 起)

构造新的 std::packaged_task 对象。

1) 构造无任务且无共享状态的 std::packaged_task 对象。
2) 构造拥有共享状态和任务副本的 std::packaged_task 对象，以 std::forward <F>(f) 初始化副本。若 std::decay <F>::type 与 std::packaged_task <R(ArgTypes...)> 是同一类型，则此构造函数不参与重载决议。
3) 构造拥有共享状态和任务副本的 std::packaged_task 对象，以 std::forward <F>(f) 初始化副本。用提供的分配器分配存储任务所需的内存。 若 std::decay <F>::type 与 std::packaged_task <R(ArgTypes...)> 是同一类型，则此构造函数不参与重载决议。
4) 复制构造函数被删除， std::packaged_task 仅可移动。
5) 以 rhs 之前所占有的共享状态和任务构造 std::packaged_task ，令 rhs 留在无共享状态且拥有被移动后的任务的状态。

参数

f | - | 要执行的可调用目标（函数、成员函数、 lambda 表达式、函数对象）
a | - | 存储任务时所用的分配器
rhs | - | 要移动的 std::packaged_task

异常

2) f 的复制/移动构造函数所抛的任何异常，而若内存分配失败则可能为 std::bad_alloc 。
3) f 的复制/移动构造函数，而若内存分配失败则有分配器的 allocate 函数所抛的任何异常。

示例

#include <future>
#include <iostream>
#include <thread>

int fib(int n)
{
    if (n < 3) return 1;
    else return fib(n-1) + fib(n-2);
}

int main()
{
    std::packaged_task<int(int)> fib_task(&fib);

    std::cout << "starting task\n";
    auto result = fib_task.get_future();
    std::thread t(std::move(fib_task), 42);

    std::cout << "waiting for task to finish..." << std::endl;
    std::cout << result.get() << '\n';

    std::cout << "task complete\n";
    t.join();
}

输出：

starting task
waiting for task to finish...
267914296
task complete

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2067 | C++11 | 被删除的复制构造函数接收非 const 引用 | 使之为 const


std::packaged_task<R(Args...)>::reset

< cpp‎ | thread‎ | packaged task
void reset(); | (C++11 起)

重置状态，抛弃先前执行的结果。构造共享状态。

等价于 *this = packaged_task(std::move(f)) ，其中 f 是存储的任务。

参数

（无）

返回值

（无）

异常

  • 若 *this 无共享状态则为 std::future_error 。设置 error_condition 为 no_state 。
  • 若无足够内存以分配新的共享状态则为 std::bad_alloc 。
  • 新 packaged_task 的移动构造函数所抛的任何异常

示例

#include <iostream>
#include <cmath>
#include <thread>
#include <future>

int main()
{
    std::packaged_task<int(int,int)> task([](int a, int b) {
        return std::pow(a, b);
    });
    std::future<int> result = task.get_future();
    task(2, 9);
    std::cout << "2^9 = " << result.get() << '\n';

    task.reset();
    result = task.get_future();
    std::thread task_td(std::move(task), 2, 10);
    task_td.join();
    std::cout << "2^10 = " << result.get() << '\n';
}

输出：

2^9 = 512
2^10 = 1024


std::packaged_task<R(Args...)>::swap

< cpp‎ | thread‎ | packaged task
void swap( packaged_task& other ) noexcept; | (C++11 起)

交换 *this 与 other 的共享状态和存储的任务。

参数

other - 要交换状态的 packaged_task

返回值

（无）

参阅

std::swap(std::packaged_task)
(C++11)
 特化 std::swap 算法
(函数模板)


std::swap(std::packaged_task)

< cpp‎ | thread‎ | packaged task
template< class Function, class... Args >

void swap( packaged_task<Function(Args...)> &lhs,

packaged_task<Function(Args...)> &rhs ) noexcept;
 (C++11 起)

为 std::packaged_task 特化 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的 packaged_task

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

swap
 交换二个任务对象
(公开成员函数)


std::uses_allocator<std::packaged_task>

< cpp‎ | thread‎ | packaged task
template< class R, class Alloc > struct uses_allocator< std::packaged_task <R>, Alloc> : true_type { }; | (C++11 起) (C++17 中移除)

提供 std::uses_allocator 对 std::packaged_task 的特化。

继承自 std::integral_constant

成员常量

value
[静态]
 true
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

参阅

uses_allocator
(C++11)
 检查指定的类型是否支持使用分配器的构造
(类模板)


std::packaged_task<R(Args...)>::valid

< cpp‎ | thread‎ | packaged task
bool valid() const noexcept; | (C++11 起)

检查 *this 是否拥有共享状态。

参数

（无）

返回值

若 *this 拥有共享状态则为 true ，否则为 false 。


std::packaged_task<R(Args...)>::~packaged_task

< cpp‎ | thread‎ | packaged task
~packaged_task();

抛弃共享状态并销毁存储的任务对象。

同 std::promise::~promise ，若在令共享状态就绪前抛弃它，则存储以 std::future_errc::broken_promise 为 error_code 的 std::future_error 异常。

参数

（无）

示例

本节未完成
原因：暂无示例


std::promise

< cpp‎ | thread
定义于头文件 <future> |  |
template< class R > class promise; | (1) | (C++11 起)
template< class R > class promise<R&>; | (2) | (C++11 起)
template<> class promise<void>; | (3) | (C++11 起)
1) 空模板
2) 非 void 特化，用于在线程间交流对象
3) void 特化，用于交流无状态事件

类模板 std::promise 提供存储值或异常的设施，之后通过 std::promise 对象所创建的 std::future 对象异步获得结果。注意 std::promise 只应当使用一次。

每个 promise 与共享状态关联，共享状态含有一些状态信息和可能仍未求值的结果，它求值为值（可能为 void ）或求值为异常。 promise 可以对共享状态做三件事：

  • 使就绪： promise 存储结果或异常于共享状态。标记共享状态为就绪，并解除阻塞任何等待于与该共享状态关联的 future 上的线程。
  • 释放： promise 放弃其对共享状态的引用。若这是最后一个这种引用，则销毁共享状态。除非这是 std::async 所创建的未就绪的共享状态，否则此操作不阻塞。
  • 抛弃： promise 存储以 std::future_errc::broken_promise 为 error_code 的 std::future_error 类型异常，令共享状态为就绪，然后释放它。

promise 是 promise-future 交流通道的“推”端：存储值于共享状态的操作同步于（定义于 std::memory_order ）任何在共享状态上等待的函数（如 std::future::get ）的成功返回。其他情况下对共享状态的共时访问可能冲突：例如， std::shared_future::get 的多个调用方必须全都是只读，或提供外部同步。

成员函数

(构造函数)
 构造std::promise对象
(公开成员函数)
(析构函数)
 析构std::promise对象
(公开成员函数)
operator=
 赋值共享状态
(公开成员函数)
swap
 交换二个 promise 对象
(公开成员函数)
获取结果
get_future
 返回与承诺的结果关联的 future
(公开成员函数)
设置结果
set_value
 设置结果为指定值
(公开成员函数)
set_value_at_thread_exit
 设置结果为指定值，同时仅在线程退出时分发提醒
(公开成员函数)
set_exception
 设置结果为指示异常
(公开成员函数)
set_exception_at_thread_exit
 设置结果为指示异常，同时仅在线程退出时分发提醒
(公开成员函数)

非成员函数

std::swap(std::promise)
(C++11)
 特化 std::swap 算法
(函数模板)

辅助类

std::uses_allocator<std::promise>
(C++11)
 特化 std::uses_allocator 类型特征
(类模板特化)

示例

此示例展示能如何将 promise<int> 用作线程间信号。

#include <vector>
#include <thread>
#include <future>
#include <numeric>
#include <iostream>
#include <chrono>

void accumulate(std::vector<int>::iterator first,
                std::vector<int>::iterator last,
                std::promise<int> accumulate_promise)
{
    int sum = std::accumulate(first, last, 0);
    accumulate_promise.set_value(sum);  // 提醒 future
}

void do_work(std::promise<void> barrier)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    barrier.set_value();
}

int main()
{
    // 演示用 promise<int> 在线程间传递结果。
    std::vector<int> numbers = { 1, 2, 3, 4, 5, 6 };
    std::promise<int> accumulate_promise;
    std::future<int> accumulate_future = accumulate_promise.get_future();
    std::thread work_thread(accumulate, numbers.begin(), numbers.end(),
                            std::move(accumulate_promise));

    // future::get() 将等待直至该 future 拥有合法结果并取得它
    // 无需在 get() 前调用 wait()
    //accumulate_future.wait();  // 等待结果
    std::cout << "result=" << accumulate_future.get() << '\n';
    work_thread.join();  // wait for thread completion

    // 演示用 promise<void> 在线程间对状态发信号
    std::promise<void> barrier;
    std::future<void> barrier_future = barrier.get_future();
    std::thread new_work_thread(do_work, std::move(barrier));
    barrier_future.wait();
    new_work_thread.join();
}

输出：

result=21


std::promise<R>::get_future

< cpp‎ | thread‎ | promise
std::future <T> get_future(); | (C++11 起)

返回与 *this 关联同一状态的 future 对象。

若 *this 无共享状态，或已调用 get_future 则抛出异常。可使用 std::future::share 以获取 promise-future 交流通道的多个“弹出”端。

对此函数的调用与对 set_value 、 set_exception 、 set_value_at_thread_exit 或 set_exception_at_thread_exit 的调用不造成数据竞争（但它们不必彼此同步）。

参数

（无）

返回值

指代 *this 的共享状态的 future 。

异常

遇到下列条件时抛出 std::future_error ：

  • *this 无共享状态。设置 error_category 为 no_state 。
  • 已在与 *this 拥有同一共享状态的 promise 上调用 get_future() 。设置 error_category 为 future_already_retrieved 。


std::promise<R>::operator=

< cpp‎ | thread‎ | promise
promise& operator=( promise&& other ) noexcept; | (1) | (C++11 起)
promise& operator=( const promise& rhs ) = delete; | (2) | (C++11 起)

赋值内容。

1) 移动赋值运算符。首先，抛弃共享状态（如在 ~promise() 中），然后如同以执行 std::promise (std::move(other)).swap(*this) 对共享状态赋值。
2) std::promise 不可复制赋值。

参数

other - 另一 std::promise 对象，为获取状态的来源

返回值

*this


std::promise<R>::promise

< cpp‎ | thread‎ | promise
promise(); | (1) | (C++11 起)
template< class Alloc > promise( std::allocator_arg_t, const Alloc& alloc ); | (2) | (C++11 起)
promise( promise&& other ) noexcept; | (3) | (C++11 起)
promise( const promise& other ) = delete; | (4) | (C++11 起)

构造 std::promise 对象。

1) 默认构造函数，构造一个共享状态为空的 std::promise ；
2) 构造一个共享状态为空的 std::promise，由 alloc 分配共享状态， Alloc 必须满足分配器 (Allocator) 的要求；
3) 移动构造函数，用原属 other 的共享状态构造新的 std::promise 对象，使用移动语义。构造完毕后， other 无共享状态；
4) std::promise 不可复制。

参数

alloc | - | 分配器，用于分配共享状态；
other | - | 另一 std::promise 对象，作为获得共享状态的来源。

异常

1-2) 可能抛出实现定义的异常。


std::promise<R>::set_exception

< cpp‎ | thread‎ | promise
void set_exception( std::exception_ptr p ); | (C++11 起)

存储异常指针 p 到共享状态中，并令状态就绪。

set_value 、 set_exception 、 set_value_at_thread_exit 和 set_exception_at_thread_exit 的操作表现类似。在更新 promise 对象时获得单个与 promise 对象关联的互斥。

若无共享状态，或共享状态已存储值或异常，则抛出异常。

对此函数的调用和对 get_future 的调用不会造成数据竞争（但它们不需要彼此同步）。

参数

p - 要存储的异常指针。若 p 为空则行为未定义。

返回值

（无）

异常

遇到下列条件时为 std::future_error ：

  • *this 无共享状态。设置 error_category 为 no_state 。
  • 共享状态已存储值或异常。设置 error_category 为 promise_already_satisfied 。

示例

#include <thread>
#include <iostream>
#include <future>

int main()
{
    std::promise<int> p;
    std::future<int> f = p.get_future();

    std::thread t([&p]{
        try {
            // 可能抛出的代码
            throw std::runtime_error("Example");
        } catch(...) {
            try {
                // 存储任何抛出的异常于 promise
                p.set_exception(std::current_exception());
            } catch(...) {} // set_exception() 亦可能抛出
        }
    });

    try {
        std::cout << f.get();
    } catch(const std::exception& e) {
        std::cout << "Exception from the thread: " << e.what() << '\n';
    }
    t.join();
}

输出：

Exception from the thread: Example

参阅

set_exception_at_thread_exit
 设置结果为指示异常，同时仅在线程退出时分发提醒
(公开成员函数)


std::promise<R>::set_exception_at_thread_exit

< cpp‎ | thread‎ | promise
void set_exception_at_thread_exit( std::exception_ptr p ); | (C++11 起)

存储异常指针 p 到共享状态中，而不立即使状态就绪。在当前线程退出时，销毁所有拥有线程局域存储期的变量后，再零状态就绪。

set_value 、 set_exception 、 set_value_at_thread_exit 和 set_exception_at_thread_exit 的操作表现类似。在更新 promise 对象时获得单个与 promise 对象关联的互斥。

若无共享状态，或共享状态已存储值或异常，则抛出异常。

对此函数的调用和对 get_future 的调用不会造成数据竞争（但它们不需要彼此同步）。

参数

p - 要存储的异常指针。若 p 为空则行为未定义。

返回值

（无）

异常

遇到下列条件时为 std::future_error ：

  • *this 无共享状态。设置 error_category 为 no_state 。
  • 共享状态已存储值或异常。设置 error_category 为 promise_already_satisfied 。

示例

本节未完成
原因：暂无示例

参阅

set_exception
 设置结果为指示异常
(公开成员函数)


std::promise<R>::set_value

< cpp‎ | thread‎ | promise
void set_value( const R& value ); | (1) | (C++11 起) (仅为泛型 promise 模板的成员)
void set_value( R&& value ); | (2) | (C++11 起) (仅为泛型 promise 模板的成员)
void set_value( R& value ); | (3) | (C++11 起) (仅为 promise<R&> 模板特化的成员)
void set_value(); | (4) | (C++11 起) (仅为 promise<void> 模板特化的成员)
1-3) 原子地存储 value 到共享状态，并令状态就绪。
4) 使状态就绪。

set_value 、 set_exception 、 set_value_at_thread_exit 和 set_exception_at_thread_exit 的操作表现类似。在更新 promise 对象时获得单个与 promise 对象关联的互斥。

若无共享状态或共享状态已存储值或异常，则抛出异常。

对此函数的调用和对 get_future 的调用不会造成数据竞争（但它们不需要彼此同步）。

参数

value - 要存储于共享状态的值

返回值

（无）

异常

遇到下列条件时为 std::future_error ：

  • *this 无共享状态。设置 error_category 为 no_state 。
  • 共享状态已存储值或异常。设置 error_category 为 promise_already_satisfied 。

另外；

1, 3) value 的复制构造函数所抛的任何异常
2) value 的移动构造函数所抛的任何异常

示例

这显示能如何将 promise<void> 用于在线程间发信号。

#include <thread>
#include <future>
#include <cctype>
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <sstream>

int main()
{
    std::istringstream iss_numbers{"3 4 1 42 23 -23 93 2 -289 93"};
    std::istringstream iss_letters{" a 23 b,e a2 k k?a;si,ksa c"};

    std::vector<int> numbers;
    std::vector<char> letters;
    std::promise<void> numbers_promise, letters_promise;

    auto numbers_ready = numbers_promise.get_future();
    auto letter_ready = letters_promise.get_future();

    std::thread value_reader([&]
    {
        // I/O 操作。
        std::copy(std::istream_iterator<int>{iss_numbers},
                  std::istream_iterator<int>{},
                  std::back_inserter(numbers));

        // 为数字提醒。
        numbers_promise.set_value();

        std::copy_if(std::istreambuf_iterator<char>{iss_letters},
                     std::istreambuf_iterator<char>{},
                     std::back_inserter(letters),
                     ::isalpha);

        // 为字母提醒。
        letters_promise.set_value();
    });

    numbers_ready.wait();

    std::sort(numbers.begin(), numbers.end());

    if (letter_ready.wait_for(std::chrono::seconds(1)) ==
            std::future_status::timeout)
    {
        // 在获得字母的同时输出数
        for (int num : numbers) std::cout << num << ' ';
        numbers.clear(); //Numbers were already printed.
    }

    letter_ready.wait();
    std::sort(letters.begin(), letters.end());

    // 若已打印数，则不做任何事。
    for (int num : numbers) std::cout << num << ' ';
    std::cout << '\n';

    for (char let : letters) std::cout << let << ' ';
    std::cout << '\n';

    value_reader.join();
}

输出：

-289 -23 1 2 3 4 23 42 93 93
a a a a b c e i k k k s s

参阅

set_exception
 设置结果为指示异常
(公开成员函数)


std::promise<R>::set_value_at_thread_exit

< cpp‎ | thread‎ | promise
void set_value_at_thread_exit( const R& value ); | (1) | (C++11 起) (仅为泛型 promise 模板的成员)
void set_value_at_thread_exit( R&& value ); | (2) | (C++11 起) (仅为泛型 promise 模板的成员)
void set_value_at_thread_exit( R& value ); | (3) | (C++11 起) (仅为 promise<R&> 模板特化的成员)
void set_value_at_thread_exit(); | (4) | (C++11 起) (仅为 promise<void> 模板特化的成员)

原子地存储 value 到共享状态，而不立即令状态就绪。在当前线程退出时，销毁所有拥有线程局域存储期的对象后，再令状态就绪。

set_value 、 set_exception 、 set_value_at_thread_exit 和 set_exception_at_thread_exit 的操作表现类似。在更新 promise 对象时获得单个与 promise 对象关联的互斥。

若无共享状态或共享状态已存储值或异常，则抛出异常。

对此函数的调用和对 get_future 的调用不会造成数据竞争（但它们不需要彼此同步）。

参数

value - 要存储于共享状态的值

返回值

（无）

异常

遇到下列条件时为 std::future_error ：

  • *this 无共享状态。设置 error_category 为 no_state 。
  • 共享状态已存储值或异常。设置 error_category 为 promise_already_satisfied 。

另外；

1, 3) value 的复制构造函数所抛的任何异常
2) value 的移动构造函数所抛的任何异常

示例

#include <iostream>
#include <future>
#include <thread>

int main()
{
    using namespace std::chrono_literals;
    std::promise<int> p;
    std::future<int> f = p.get_future();
    std::thread([&p] {
          std::this_thread::sleep_for(1s);
          p.set_value_at_thread_exit(9);
    }).detach();

    std::cout << "Waiting..." << std::flush;
    f.wait();
    std::cout << "Done!\nResult is: " << f.get() << '\n';
}

输出：

Waiting...Done!
Result is: 9

参阅

set_value
 设置结果为指定值
(公开成员函数)


std::promise<R>::swap

< cpp‎ | thread‎ | promise
void swap( promise& other ) noexcept; | (C++11 起)

交换二个 std::promise 对象的内容。

参数

other - 与之交换的 std::promise 对象

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

std::swap(std::promise)
(C++11)
 特化 std::swap 算法
(函数模板)


std::swap(std::promise)

< cpp‎ | thread‎ | promise
定义于头文件 <future> |
template< class R > void swap( promise<R> &lhs, promise<R> &rhs ) noexcept; | (C++11 起)

为 std::promise 特化 std::swap 算法。交换 lhs 与 rhs 的共享状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的 promise

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

swap
 交换二个 promise 对象
(公开成员函数)


std::uses_allocator<std::promise>

< cpp‎ | thread‎ | promise
template< class R, class Alloc > struct uses_allocator< std::promise <R>, Alloc> : std::true_type { }; | (C++11 起)

为 std::promise 提供 std::uses_allocator 类型特性的特化。

继承自 std::integral_constant

成员常量

value
[静态]
 true
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

参阅

uses_allocator
(C++11)
 检查指定的类型是否支持使用分配器的构造
(类模板)


std::promise<R>::~promise

< cpp‎ | thread‎ | promise
~promise(); | (C++11 起)

抛弃共享状态：

  • 若共享状态就绪，则释放它。
  • 若共享状态未就绪，则存储以 std::future_errc::broken_promise 为 error_condition 的 std::future_error 类型异常对象，令共享状态就绪再释放它。


std::recursive_mutex

< cpp‎ | thread
定义于头文件 <mutex> |
class recursive_mutex; | (C++11 起)

recursive_mutex 类是同步原语，能用于保护共享数据免受从个多线程同时访问。

recursive_mutex 提供排他性递归所有权语义：

  • 调用方线程在从它成功调用 lock 或 try_lock 开始的时期里占有 recursive_mutex 。此时期间，线程可以进行对 lock 或 try_lock 的附加调用。所有权的时期在线程调用 unlock 匹配次数时结束。
  • 线程占有 recursive_mutex 时，若其他所有线程试图要求 recursive_mutex 的所有权，则它们将阻塞（对于调用 lock ）或收到 false 返回值（对于调用 try_lock ）。
  • 可锁定 recursive_mutex 次数的最大值是未指定的，但抵达该数后，对 lock 的调用将抛出 std::system_error 而对 try_lock 的调用将返回 false 。

若 recursive_mutex 在仍为某线程占有时被销毁，则程序行为未定义。 recursive_mutex 类满足互斥体 (Mutex) 和标准布局类型 (StandardLayoutType) 的所有要求。

成员类型

成员类型 | 定义
native_handle_type(可选) | 实现定义

成员函数

(构造函数)
 构造互斥
(公开成员函数)
(析构函数)
 销毁互斥
(公开成员函数)
operator=
[被删除]
 不可复制赋值
(公开成员函数)
锁定
lock
 锁定互斥，若互斥不可用则阻塞
(公开成员函数)
try_lock
 尝试锁定互斥，若互斥不可用则返回
(公开成员函数)
unlock
 解锁互斥
(公开成员函数)
原生句柄
native_handle
 返回底层实现定义的原生句柄
(公开成员函数)

示例

recursive_mutex 的使用场景之一是保护类中的共享状态，而类的成员函数可能相互调用

#include <iostream>
#include <thread>
#include <mutex>

class X {
    std::recursive_mutex m;
    std::string shared;
  public:
    void fun1() {
      std::lock_guard<std::recursive_mutex> lk(m);
      shared = "fun1";
      std::cout << "in fun1, shared variable is now " << shared << '\n';
    }
    void fun2() {
      std::lock_guard<std::recursive_mutex> lk(m);
      shared = "fun2";
      std::cout << "in fun2, shared variable is now " << shared << '\n';
      fun1(); // 递归锁在此处变得有用
      std::cout << "back in fun2, shared variable is " << shared << '\n';
    };
};

int main()
{
    X x;
    std::thread t1(&X::fun1, &x);
    std::thread t2(&X::fun2, &x);
    t1.join();
    t2.join();
}

可能的输出：

in fun1, shared variable is now fun1
in fun2, shared variable is now fun2
in fun1, shared variable is now fun1
back in fun2, shared variable is fun1


std::recursive_mutex::lock

< cpp‎ | thread‎ | recursive mutex

void lock(); | (C++11 起)

锁定互斥。若另一线程已锁定互斥，则到 lock 的调用将阻塞执行，直至获得锁。

线程可以在递归互斥上重复调用 lock 。在线程调用 unlock 匹配数量次后，所有权才会得到释放。

所有权的最大层数是未指定的。若超出此数，则可能抛 std::system_error 类型异常。

同一互斥上先前的 unlock() 操作同步于（定义于 std::memory_order ）此操作。

参数

（无）

返回值

（无）

异常

错误发生时抛出 std::system_error ，包括底层操作系统阻止 lock 满足其规定的错误。在抛出任何异常的情况下，不锁定互斥。

注意

通常不直接调用 lock() ：用 std::unique_lock 与 std::lock_guard 管理排他性锁定。

示例

此示例演示 lock 与 unlock 能如何用于保护共享数据。

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>

int g_num = 0;  // 为 g_num_mutex 所保护
std::mutex g_num_mutex;

void slow_increment(int id)
{
    for (int i = 0; i < 3; ++i) {
        g_num_mutex.lock();
        ++g_num;
        std::cout << id << " => " << g_num << '\n';
        g_num_mutex.unlock();

        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main()
{
    std::thread t1(slow_increment, 0);
    std::thread t2(slow_increment, 1);
    t1.join();
    t2.join();
}

可能的输出：

0 => 1
1 => 2
0 => 3
1 => 4
0 => 5
1 => 6

参阅

try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::recursive_mutex::native_handle

< cpp‎ | thread‎ | recursive mutex

native_handle_type native_handle(); | (C++11 起) (可选)

返回底层实现定义的原生句柄对象。

参数

（无）

返回值

实现定义的原生句柄对象。

异常

实现定义。

示例

本节未完成
原因：暂无示例


std::recursive_mutex::recursive_mutex

< cpp‎ | thread‎ | recursive mutex

recursive_mutex(); | (1) | (C++11 起)
recursive_mutex( const recursive_mutex& ) = delete; | (2) | (C++11 起)
1) 构造互斥。调用后互斥在未锁定状态。
2) 复制构造函数被删除。

参数

（无）

异常

若构造不成功则抛出 std::system_error 。

参阅


std::recursive_mutex::try_lock

< cpp‎ | thread‎ | recursive mutex

bool try_lock(); | (C++11 起)

尝试锁定互斥。立即返回。成功获得锁时返回 true ，否则返回 false 。

允许此函数虚假地失败而返回 false ，即使互斥当前未为任何其他线程所锁定。

线程可以重复调用 try_lock 。到 try_lock 的成功调用自增所有权计数：线程调用 unlock 匹配次数后互斥才会得到释放。

所有权层数的最大值是未指定的。若超出此数，则到 try_lock 的调用将返回 false 。

若此操作返回 true ，则同一互斥上的先前 unlock() 操作同步于（定义于 std::memory_order ）它。注意若此操作返回 false ，则先前的 lock() 不与之同步。

参数

（无）

返回值

若成功取得锁则为 true ，否则为 false 。

异常

不抛出。

示例

#include <iostream>
#include <mutex>

int main()
{
    std::recursive_mutex test;
    if (test.try_lock()) {
        std::cout << "lock acquired\n";
        test.unlock();
    } else {
        std::cout << "lock not acquired\n";
    }

    // 现在非递归互斥将从 try_lock 返回 false
    if (test.try_lock()) {
        std::cout << "lock acquired\n";
        test.unlock();
    } else {
        std::cout << "lock not acquired\n";
    }
}

输出：

lock acquired
lock acquired

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::recursive_mutex::unlock

< cpp‎ | thread‎ | recursive mutex

void unlock(); | (C++11 起)

若所有权等级为 1 （此线程对 lock() 的调用恰好比 unlock() 多一次 ）则解锁互斥，否则将所有权等级减少 1 。

互斥必须为当前执行线程所锁定，否则行为未定义。

此操作同步于（定义于 std::memory_order ）任何后继的取得同一互斥所有权的锁操作。

参数

（无）

返回值

（无）

异常

不抛出。

注解

通常不直接调用 unlock() ：用 std::unique_lock 与 std::lock_guard 管理互斥锁定。

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)


std::recursive_mutex::~recursive_mutex

< cpp‎ | thread‎ | recursive mutex

~recursive_mutex();

销毁互斥。

若互斥为任何线程占有，或若任何线程在保有任何互斥的所有权时终止，则行为未定义。

参阅


std::recursive_timed_mutex

< cpp‎ | thread
定义于头文件 <mutex> |
class recursive_timed_mutex; | (C++11 起)

recursive_timed_mutex 是同步原语，能用于保护共享数据免受从多个线程同时访问。

以类似 std::recursive_mutex 的方式， recursive_timed_mutex 提供排他性递归所有权语义。另外， recursive_timed_mutex 通过 try_lock_for 与 try_lock_until 方法，提供带时限地试图要求 recursive_timed_mutex 所有权的能力。

recursive_timed_mutex 类满足定时互斥体 (TimedMutex) 和标准布局类型 (StandardLayoutType) 的所有要求。

成员类型

成员类型 | 定义
native_handle_type(可选) | 实现定义

成员函数

(构造函数)
 构造互斥
(公开成员函数)
(析构函数)
 销毁互斥
(公开成员函数)
operator=
[被删除]
 不可复制赋值
(公开成员函数)
锁定
lock
 锁定互斥，若互斥不可用则阻塞
(公开成员函数)
try_lock
 尝试锁定互斥，若互斥不可用则返回
(公开成员函数)
try_lock_for
 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回
(公开成员函数)
try_lock_until
 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回
(公开成员函数)
unlock
 解锁互斥
(公开成员函数)
原生句柄
native_handle
 返回底层实现定义的原生句柄
(公开成员函数)


std::recursive_timed_mutex::lock

< cpp‎ | thread‎ | recursive timed mutex

void lock(); | (C++11 起)

锁定互斥。若另一线程已锁定互斥，则到 lock 的调用将阻塞执行，直至获得锁。

线程可以在递归互斥上重复调用 lock 。在线程调用 unlock 匹配数量次后，所有权才会得到释放。

所有权的最大层数是未指定的。若超出此数，则可能抛 std::system_error 类型异常。

同一互斥上先前的 unlock() 操作同步于（定义于 std::memory_order ）此操作。

参数

（无）

返回值

（无）

异常

错误发生时抛出 std::system_error ，包括底层操作系统阻止 lock 满足其规定的错误。在抛出任何异常的情况下，不锁定互斥。

注意

通常不直接调用 lock() ：用 std::unique_lock 与 std::lock_guard 管理排他性锁定。

示例

此示例演示 lock 与 unlock 能如何用于保护共享数据。

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>

int g_num = 0;  // 为 g_num_mutex 所保护
std::mutex g_num_mutex;

void slow_increment(int id)
{
    for (int i = 0; i < 3; ++i) {
        g_num_mutex.lock();
        ++g_num;
        std::cout << id << " => " << g_num << '\n';
        g_num_mutex.unlock();

        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main()
{
    std::thread t1(slow_increment, 0);
    std::thread t2(slow_increment, 1);
    t1.join();
    t2.join();
}

可能的输出：

0 => 1
1 => 2
0 => 3
1 => 4
0 => 5
1 => 6

参阅

try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
try_lock_for | 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回 (公开成员函数)
try_lock_until | 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::recursive_timed_mutex::native_handle

< cpp‎ | thread‎ | recursive timed mutex

native_handle_type native_handle(); | (C++11 起) (可选)

返回底层实现定义的原生句柄对象。

参数

（无）

返回值

实现定义的原生句柄对象。

异常

实现定义。

示例

本节未完成
原因：暂无示例


std::recursive_timed_mutex::recursive_timed_mutex

< cpp‎ | thread‎ | recursive timed mutex

recursive_timed_mutex(); | (1) | (C++11 起)
recursive_timed_mutex( const recursive_timed_mutex& ) = delete; | (2) | (C++11 起)
1) 构造互斥。调用后互斥在未锁定状态。
2) 复制构造函数被删除。

参数

（无）

异常

若构造不成功则抛出 std::system_error 。

参阅


std::recursive_timed_mutex::try_lock

< cpp‎ | thread‎ | recursive timed mutex

bool try_lock(); | (C++11 起)

尝试锁定互斥。立即返回。成功获得锁时返回 true ，否则返回 false 。

允许此函数虚假地失败而返回 false ，即使互斥当前未为任何其他线程所锁定。

线程可以重复调用 try_lock 。到 try_lock 的成功调用自增所有权计数：线程调用 unlock 匹配次数后互斥才会得到释放。

所有权层数的最大值是未指定的。若超出此数，则到 try_lock 的调用将返回 false 。

若此操作返回 true ，则同一互斥上的先前 unlock() 操作同步于（定义于 std::memory_order ）它。注意若此操作返回 false ，则先前的 lock() 不与之同步。

参数

（无）

返回值

若成功取得锁则为 true ，否则为 false 。

异常

不抛出。

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock_for | 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回 (公开成员函数)
try_lock_until | 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::recursive_timed_mutex::try_lock_for

< cpp‎ | thread‎ | recursive timed mutex

template< class Rep, class Period > bool try_lock_for( const std::chrono::duration <Rep,Period>& timeout_duration ); | (C++11 起)

尝试锁互斥。阻塞直到经过指定的 timeout_duration 或得到锁，取决于何者先到来。成功获得锁时返回 true ， 否则返回 false 。

若 timeout_duration 小于或等于 timeout_duration.zero() ，则函数表现同 try_lock() 。

由于调度或资源争议延迟，此函数可能阻塞长于 timeout_duration 。

标准推荐用 steady_clock 度量时长。若实现用 system_clock 代替，则等待时间亦可能对时钟调整敏感。

同 try_lock() ，允许此函数虚假地失败并返回 false ，即使在 timeout_duration 中某点互斥不为任何线程所锁定。

若此操作返回 true ，则同一互斥上先前的 unlock() 调用同步于（定义于 std::memory_order ）它。

线程可以在递归互斥上重复调用 try_lock_for 。对 try_lock_for 的成功调用增加所有权计数：仅在线程调用 unlock 匹配次数后才会释放互斥。

所有权等级数的最大值是未指定的。若超出此值，则到 try_lock_for 的调用将返回 false 。

参数

timeout_duration - 要阻塞的最大时长

返回值

若成功获得锁则为 true ，否则为 false 。

异常

执行期间时钟、时间点或时长可能抛出的异常（标准库提供的时钟、时间点和时长决不抛出）

示例

#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
#include <sstream>

std::mutex cout_mutex; // 控制到 std::cout 的访问
std::timed_mutex mutex;

void job(int id)
{
    using Ms = std::chrono::milliseconds;
    std::ostringstream stream;

    for (int i = 0; i < 3; ++i) {
        if (mutex.try_lock_for(Ms(100))) {
            stream << "success ";
            std::this_thread::sleep_for(Ms(100));
            mutex.unlock();
        } else {
            stream << "failed ";
        }
        std::this_thread::sleep_for(Ms(100));
    }

    std::lock_guard<std::mutex> lock(cout_mutex);
    std::cout << "[" << id << "] " << stream.str() << "\n";
}

int main()
{
    std::vector<std::thread> threads;
    for (int i = 0; i < 4; ++i) {
        threads.emplace_back(job, i);
    }

    for (auto& i: threads) {
        i.join();
    }
}

可能的输出：

[0] failed failed failed
[3] failed failed success
[2] failed success failed
[1] success failed success

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
try_lock_until | 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::recursive_timed_mutex::try_lock_until

< cpp‎ | thread‎ | recursive timed mutex

template< class Clock, class Duration > bool try_lock_until( const std::chrono::time_point <Clock,Duration>& timeout_time ); | (C++11 起)

尝试所互斥。阻塞直至抵达指定的 timeout_time 或得到锁，取决于何者先到来。成功获得锁时返回 true ，否则返回 false 。

若已经过 timeout_time ，则此函数表现同 try_lock() 。

Clock 必须符合时钟 (Clock) 要求。若 std::chrono::is_clock_v<Clock> 为 false 则程序为非良构。 (C++20 起)

标准推荐使用绑定到 timeout_time 的时钟，该情况下可以计入时钟的调整。从而在调用时刻，阻塞的时长可以，但也可以不，小于或大于 timeout_time - Clock::now() 。这取决于调整的方向以及实现是否尊重它。函数亦可能由于调度或资源纠纷延迟，而阻塞长于到抵达 timeout_time 之后。

同 try_lock() ，允许此函数虚假地失败并返回 false ，即使在 timeout_time 前的某点任何线程都不锁定互斥。

若此操作返回 true ，则同一互斥上先前的 unlock() 调用同步于（定义于 std::memory_order ）它。

线程可以在递归互斥上重复调用 try_lock_until 。对 try_lock_until 的成功调用增加所有权计数：仅在线程调用 unlock 匹配次数后才会释放互斥。

所有权等级数的最大值是未指定的。若超出此值，则到 try_lock_until 的调用将返回 false 。

参数

timeout_time - 要阻塞到的最大时间点

返回值

若成功获得锁则为 true ，否则为 false 。

异常

执行期间时钟、时间点或时长可能抛出的异常（标准库提供的时钟、时间点和时长决不抛出）

示例

此示例展示 10 秒的阻塞

#include <thread>
#include <iostream>
#include <chrono>
#include <mutex>

std::recursive_timed_mutex test_mutex;

void f()
{
    auto now=std::chrono::steady_clock::now();
    test_mutex.try_lock_until(now + std::chrono::seconds(10));
    std::cout << "hello world\n";
}

int main()
{
    std::lock_guard<std::recursive_timed_mutex> l(test_mutex);
    std::thread t(f);
    t.join();
}

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
try_lock_for | 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::recursive_timed_mutex::unlock

< cpp‎ | thread‎ | recursive timed mutex

void unlock(); | (C++11 起)

若所有权等级为 1 （此线程对 lock() 的调用恰好比 unlock() 多一次 ）则解锁互斥，否则将所有权等级减少 1 。

互斥必须为当前执行线程所锁定，否则行为未定义。

此操作同步于（定义于 std::memory_order ）任何后继的取得同一互斥所有权的锁操作。

参数

（无）

返回值

（无）

异常

不抛出。

注解

通常不直接调用 unlock() ：用 std::unique_lock 与 std::lock_guard 管理互斥锁定。

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
try_lock_for | 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回 (公开成员函数)
try_lock_until | 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回 (公开成员函数)


std::recursive_timed_mutex::~recursive_timed_mutex

< cpp‎ | thread‎ | recursive timed mutex

~recursive_timed_mutex();

销毁互斥。

若互斥为任何线程占有，或若任何线程在保有任何互斥的所有权时终止，则行为未定义。

参阅


std::scoped_lock

< cpp‎ | thread
定义于头文件 <mutex> |
template< class... MutexTypes > class scoped_lock; | (C++17 起)

类 scoped_lock 是提供便利 RAII 风格机制的互斥包装器，它在作用域块的存在期间占有一或多个互斥。

创建 scoped_lock 对象时，它试图取得给定互斥的所有权。控制离开创建 scoped_lock 对象的作用域时，析构 scoped_lock 并释放互斥。若给出数个互斥，则使用免死锁算法，如同以 std::lock 。

scoped_lock 类不可复制。

模板形参

MutexTypes - 要锁定的互斥类型。类型必须满足可锁定 (Lockable) 要求，除非 sizeof...(MutexTypes)==1 ，该情况下唯一的类型必须满足基本可锁定 (BasicLockable)

成员类型

成员类型 | 定义
mutex_type (若 sizeof...(MutexTypes)==1) | Mutex ， MutexTypes... 中的单独类型

成员函数

(构造函数) | 构造 scoped_lock ，可选地锁定给定的互斥 (公开成员函数)
(析构函数) | 析构 scoped_lock 对象，解锁底层互斥 (公开成员函数)
operator= [被删除] | 不可复制 (公开成员函数)

示例

以下示例用 std::scoped_lock 锁定互斥对而不死锁，且为 RAII 风格。

#include <mutex>
#include <thread>
#include <iostream>
#include <vector>
#include <functional>
#include <chrono>
#include <string>

struct Employee {
    Employee(std::string id) : id(id) {}
    std::string id;
    std::vector<std::string> lunch_partners;
    std::mutex m;
    std::string output() const
    {
        std::string ret = "Employee " + id + " has lunch partners: ";
        for( const auto& partner : lunch_partners )
            ret += partner + " ";
        return ret;
    }
};

void send_mail(Employee &, Employee &)
{
    // 模拟耗时的发信操作
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

void assign_lunch_partner(Employee &e1, Employee &e2)
{
    static std::mutex io_mutex;
    {
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << e1.id << " and " << e2.id << " are waiting for locks" << std::endl;
    }

    {
        // 用 std::scoped_lock 取得二个锁，而无需担心
        // 其他对 assign_lunch_partner 的调用死锁我们
        // 而且它亦提供便利的 RAII 风格机制

        std::scoped_lock lock(e1.m, e2.m);

        // 等价代码 1 （用 std::lock 和 std::lock_guard ）
        // std::lock(e1.m, e2.m);
        // std::lock_guard<std::mutex> lk1(e1.m, std::adopt_lock);
        // std::lock_guard<std::mutex> lk2(e2.m, std::adopt_lock);

        // 等价代码 2 （若需要 unique_lock ，例如对于条件变量）
        // std::unique_lock<std::mutex> lk1(e1.m, std::defer_lock);
        // std::unique_lock<std::mutex> lk2(e2.m, std::defer_lock);
        // std::lock(lk1, lk2);
        {
            std::lock_guard<std::mutex> lk(io_mutex);
            std::cout << e1.id << " and " << e2.id << " got locks" << std::endl;
        }
        e1.lunch_partners.push_back(e2.id);
        e2.lunch_partners.push_back(e1.id);
    }

    send_mail(e1, e2);
    send_mail(e2, e1);
}

int main()
{
    Employee alice("alice"), bob("bob"), christina("christina"), dave("dave");

    // 在并行线程中指派，因为就午餐指派发邮件消耗很长时间
    std::vector<std::thread> threads;
    threads.emplace_back(assign_lunch_partner, std::ref(alice), std::ref(bob));
    threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(bob));
    threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(alice));
    threads.emplace_back(assign_lunch_partner, std::ref(dave), std::ref(bob));

    for (auto &thread : threads) thread.join();
    std::cout << alice.output() << '\n'  << bob.output() << '\n'
              << christina.output() << '\n' << dave.output() << '\n';
}

可能的输出：

alice and bob are waiting for locks
alice and bob got locks
christina and bob are waiting for locks
christina and alice are waiting for locks
dave and bob are waiting for locks
dave and bob got locks
christina and alice got locks
christina and bob got locks
Employee alice has lunch partners: bob christina
Employee bob has lunch partners: alice dave christina
Employee christina has lunch partners: alice bob
Employee dave has lunch partners: bob

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2981 | C++17 | 曾提供来自 scoped_lock<MutexTypes...> 的冗余推导指引 | 已移除

参阅

unique_lock
(C++11)
 实现可移动的互斥体所有权包装器
(类模板)
lock_guard
(C++11)
 实现严格基于作用域的互斥体所有权包装器
(类模板)


std::scoped_lock<MutexTypes...>::scoped_lock

< cpp‎ | thread‎ | scoped lock
explicit scoped_lock( MutexTypes&... m ); | (1) | (C++17 起)
scoped_lock( std::adopt_lock_t, MutexTypes&... m ); | (2) | (C++17 起)
scoped_lock( const scoped_lock& ) = delete; | (3) | (C++17 起)

取得给定互斥 m 的所有权。

1) 若 sizeof...(MutexTypes) == 0 则不做任何事。否则若 sizeof...(MutexTypes) == 1 ，则等效地调用 m.lock() 。否则，等效地调用 std::lock (m...) 。
2) 取得互斥 m... 的所有权而不试图锁定任何互斥。除非当前线程在 m... 中的每个对象上保有一个非共享锁（即以 lock、 try_lock、 try_lock_for 或 try_lock_until 取得的锁），否则行为未定义。
3) 复制构造函数被删除。

若 m 在 scoped_lock 对象之前被销毁，则行为未定义。

参数

m - 要获得其所有权的互斥

异常

1) 抛出任何 m.lock() 所抛的异常
2) 不抛出

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0739R0 | C++17 | adopt_lock_t 参数在最后，妨碍类模板实参推导 | 移到最前


std::scoped_lock<MutexTypes...>::~scoped_lock

< cpp‎ | thread‎ | scoped lock
~scoped_lock(); | (C++17 起)

释放所占有互斥的所有权。

等效地在每个来自传递给 scoped_lock 构造函数的互斥包的互斥上调用 unlock() 。


std::shared_future

< cpp‎ | thread
定义于头文件 <future> |  |
template< class T > class shared_future; | (1) | (C++11 起)
template< class T > class shared_future<T&>; | (2) | (C++11 起)
template<> class shared_future<void>; | (3) | (C++11 起)

类模板 std::shared_future 提供访问异步操作结果的机制，类似 std::future ，除了允许多个线程等候同一共享状态。不同于仅可移动的 std::future （故只有一个实例能指代任何特定的异步结果），std::shared_future 可复制而且多个 shared_future 对象能指代同一共享状态。

若每个线程通过其自身的 shared_future 对象副本访问，则从多个线程访问同一共享状态是安全的。

成员函数

(构造函数)
 构造 future 对象
(公开成员函数)
(析构函数)
 销毁future对象
(公开成员函数)
operator=
 赋值内容
(公开成员函数)
获取结果
get
 返回结果
(公开成员函数)
状态
valid
 检查 future 是否拥有共享状态
(公开成员函数)
wait
 等待结果变得可用
(公开成员函数)
wait_for
 等待结果，如果在指定的超时间隔后仍然无法得到结果，则返回。
(公开成员函数)
wait_until
 等待结果，如果在已经到达指定的时间点时仍然无法得到结果，则返回。
(公开成员函数)

示例

shared_future 可用于同时向多个线程发信，类似 std::condition_variable::notify_all()

#include <iostream>
#include <future>
#include <chrono>

int main()
{
    std::promise<void> ready_promise, t1_ready_promise, t2_ready_promise;
    std::shared_future<void> ready_future(ready_promise.get_future());

    std::chrono::time_point<std::chrono::high_resolution_clock> start;

    auto fun1 = [&, ready_future]() -> std::chrono::duration<double, std::milli>
    {
        t1_ready_promise.set_value();
        ready_future.wait(); // 等待来自 main() 的信号
        return std::chrono::high_resolution_clock::now() - start;
    };

    auto fun2 = [&, ready_future]() -> std::chrono::duration<double, std::milli>
    {
        t2_ready_promise.set_value();
        ready_future.wait(); // 等待来自 main() 的信号
        return std::chrono::high_resolution_clock::now() - start;
    };

    auto result1 = std::async(std::launch::async, fun1);
    auto result2 = std::async(std::launch::async, fun2);

    // 等待线程变为就绪
    t1_ready_promise.get_future().wait();
    t2_ready_promise.get_future().wait();

    // 线程已就绪，开始时钟
    start = std::chrono::high_resolution_clock::now();

    // 向线程发信使之运行
    ready_promise.set_value();

    std::cout << "Thread 1 received the signal "
              << result1.get().count() << " ms after start\n"
              << "Thread 2 received the signal "
              << result2.get().count() << " ms after start\n";
}

可能的输出：

Thread 1 received the signal 0.072 ms after start
Thread 2 received the signal 0.041 ms after start


std::shared_future<T>::get

< cpp‎ | thread‎ | shared future

const T& get() const; | (1) | (仅为泛型 shared_future 模板的成员) (C++11 起)
T& get() const; | (2) | (仅为 shared_future<T&> 模板特化的成员) (C++11 起)
void get() const; | (3) | (仅为 shared_future<void> 模板特化的成员) (C++11 起)

get 方法等待直至 shared_future 拥有合法结果并（依赖于使用哪个模板）获取它。它等效地调用 wait() 等待结果。

泛型模板和二个模板特化各含单个 get 版本。 get 的三个版本仅在返回类型有别。

若调用此函数前 valid() 为 false 则行为未定义。

参数

（无）

返回值

1) 到存储于共享状态的值的 const 引用。销毁共享状态后，通过此引用访问值是未定义行为。
2) 存储于共享状态的值的引用。
3) 无。

异常

若 future 所引用的共享状态中存储异常（例如，通过调用 std::promise::set_exception() ），则抛出该异常。

注意

鼓励实现在调用前检测 valid() 为 false 的情况，并抛出以 std::future_errc::no_state 为 error_condition 的 std::future_error 。

示例

本节未完成
原因：暂无示例

参阅

valid
 检查 future 是否拥有共享状态
(公开成员函数)


std::shared_future<T>::operator=

< cpp‎ | thread‎ | shared future
 | (1) |
shared_future& operator=( const shared_future& other ); |  |  | (C++11 起) (C++17 前)
shared_future& operator=( const shared_future& other ) noexcept; |  |  | (C++17 起)
shared_future& operator=( shared_future&& other ) noexcept; | (2) | (C++11 起)

赋值另一 shared_future 的内容。

1) 释放任何共享状态并赋值 other 的内容给 *this 。赋值后， this->valid() == other.valid() 。
2) 释放任何共享状态并移动赋值 other 的内容给 *this 。赋值后， other.valid() == false 且 this->valid() 将产生与 other.valid() 在赋值前相同的值。

参数

other - 将转移状态给 *this 的 std::shared_future

返回值

*this


std::shared_future<T>::shared_future

< cpp‎ | thread‎ | shared future
shared_future() noexcept; | (1) | (C++11 起)
 | (2) |
shared_future( const shared_future& other ); |  |  | (C++11 起) (C++17 前)
shared_future( const shared_future& other ) noexcept; |  |  | (C++17 起)
shared_future( std::future <T>&& other ) noexcept; | (3) | (C++11 起)
shared_future( shared_future&& other ) noexcept; | (4) | (C++11 起)

构造新的 shared_future 。

1) 默认构造函数。构造空的 shared_future ，它不指代共享状态，即 valid() == false 。
2) 构造与 other 指代同一共享状态的 shared_future ，若有共享状态。
3-4) 转移 other 所保有的共享状态给 *this 。构造后， other.valid() == false 且 this->valid() 返回与 other.valid() 在构造前会返回者相同的值。

参数

other - 用以初始化的另一 future 对象


std::shared_future<T>::valid

< cpp‎ | thread‎ | shared future

bool valid() const noexcept; | (C++11 起)

检查期货是否指代共享状态。

这是非默认构造或被移动的期货的仅有情况。不同于 std::future ，调用 get() 时不非法化 std::shared_future 的共享状态。

若在不指代共享状态的 shared_future 上调用任何析构函数、复制赋值运算符、移动赋值运算符或 valid 以外的成员函数，则行为未定义（尽管鼓励实现在此情况下抛出指示 no_state 的 std::future_error ）。从 valid() 为 false 的 shared_future 对象移动或复制是合法的。

参数

（无）

返回值

若 *this 指代共享状态则为 true ，否则为 false 。

示例

#include <future>
#include <iostream>

int main() {
    std::promise<void> p;
    std::shared_future<void> f = p.get_future();

    std::cout << std::boolalpha;

    std::cout << f.valid() << '\n';
    p.set_value();
    std::cout << f.valid() << '\n';
    f.get();
    std::cout << f.valid() << '\n';
}

输出：

true
true
true

参阅

wait
 等待结果变得可用
(公开成员函数)


std::shared_future<T>::wait

< cpp‎ | thread‎ | shared future

void wait() const; | (C++11 起)

阻塞直至结果变得可用。调用后 valid() == true 。

若调用此函数前 valid () == false 则行为未定义。

参数

（无）

返回值

（无）

异常

可能抛出实现定义的异常。

注解

鼓励实现检测调用前 valid() == false 的情况并抛出以 std::future_errc::no_state 为 error_condition 的 std::future_error 。

在同一 std::shared_future 上从多个线程调调用 wait 不安全；有意图的使用是令每个等待于同一共享状态上的线程拥有一个 std::shared_future 的副本。

示例

#include <chrono>
#include <iostream>
#include <future>
#include <thread>

int fib(int n)
{
  if (n < 3) return 1;
  else return fib(n-1) + fib(n-2);
}

int main()
{
    std::shared_future<int> f1 = std::async(std::launch::async, [](){
        return fib(40);
    });
    std::shared_future<int> f2 = std::async(std::launch::async, [](){
        return fib(43);
    });

    std::cout << "waiting... " << std::flush;
    const auto start = std::chrono::system_clock::now();

    f1.wait();
    f2.wait();

    const auto diff = std::chrono::system_clock::now() - start;
    std::cout << std::chrono::duration<double>(diff).count() << " seconds\n";

    std::cout << "f1: " << f1.get() << '\n';
    std::cout << "f2: " << f2.get() << '\n';
}

可能的输出：

waiting... 1.61803 seconds
f1: 102334155
f2: 433494437

参阅

wait_for | 等待结果，如果在指定的超时间隔后仍然无法得到结果，则返回。 (公开成员函数)
wait_until | 等待结果，如果在已经到达指定的时间点时仍然无法得到结果，则返回。 (公开成员函数)


std::shared_future<T>::wait_for

< cpp‎ | thread‎ | shared future

template< class Rep, class Period > std::future_status wait_for( const std::chrono::duration <Rep,Period>& timeout_duration ) const; | (C++11 起)

等待结果变得可用。阻塞直至经过指定的 timeout_duration ，或结果变为可用，两者的先到来者。返回值鉴别结果的状态。

此函数可能由于调度或资源争议延迟而阻塞长于 timeout_duration 。

推荐标准库用稳定时钟度量时长。若实现用系统时钟代替，则等待时间可能也对时钟调整敏感。

若调用此函数前 valid() == false 则行为未定义。

参数

timeout_duration - 要阻塞的最大时长

返回值

常量 | 解释
future_status::deferred | 共享状态持有的函数正在延迟运行，结果将仅在显式请求时计算
future_status::ready | 共享状态就绪
future_status::timeout | 共享状态在经过指定的等待时间内仍未就绪

异常

时钟、时间点或时长在执行中可能抛的任何异常（标准库提供的时钟、时间点和时长决不抛出）。

注意

鼓励实现在调用前检测 valid == false 的情况并抛出以 future_errc::no_state 为 error_condition 的 future_error 。

示例

#include <iostream>
#include <future>
#include <thread>
#include <chrono>

int main()
{
    std::shared_future<int> future = std::async(std::launch::async, [](){
        std::this_thread::sleep_for(std::chrono::seconds(3));
        return 8;
    });

    std::cout << "waiting...\n";
    std::future_status status;
    do {
        status = future.wait_for(std::chrono::seconds(1));
        if (status == std::future_status::deferred) {
            std::cout << "deferred\n";
        } else if (status == std::future_status::timeout) {
            std::cout << "timeout\n";
        } else if (status == std::future_status::ready) {
            std::cout << "ready!\n";
        }
    } while (status != std::future_status::ready);

    std::cout << "result is " << future.get() << '\n';
}

可能的输出：

waiting...
timeout
timeout
ready!
result is 8

参阅

wait | 等待结果变得可用 (公开成员函数)
wait_until | 等待结果，如果在已经到达指定的时间点时仍然无法得到结果，则返回。 (公开成员函数)


std::shared_future<T>::wait_until

< cpp‎ | thread‎ | shared future

template< class Clock, class Duration > std::future_status wait_until( const std::chrono::time_point <Clock,Duration>& timeout_time ) const; | (C++11 起)

wait_until 等待结果变为可用。它阻塞直至抵达指定的 timeout_time ，或结果变为可用，两者的先到来者。返回值指示 wait_until 为何返回。

若调用此函数前 valid() 为 false ，或 Clock 不符合时钟 (Clock) 要求则行为未定义。若 std::chrono::is_clock_v<Clock> 为 false 则程序为非良构。 (C++20 起)

参数

timeout_time - 要阻塞到的最大时间点

返回值

常量 | 解释
future_status::deferred | 共享状态持有的函数正在延迟运行，结果将仅在显式请求时计算
future_status::ready | 共享状态就绪
future_status::timeout | 共享状态在经过指定的等待时间内仍未就绪

异常

时钟、时间点或时长在执行中可能抛的任何异常（标准库提供的时钟、时间点和时长决不抛出）。

注解

鼓励实现在调用前检测 valid() == false 的情况并抛出以 future_errc::no_state 为错误条件的 std::future_error 。

使用倾向 timeout_time 的时钟，不要求是单调时钟。若不连续地调节时钟，则不对此函数的行为保证，但既存实现将 timeout_time 从 Clock 转换到 std::chrono::system_clock ，并委托 POSIX pthread_cond_timedwait 以令等待忠实于系统时钟，但非用户提供 Clock 的调节。任何情况下，由于调度或资源争议延迟，函数可能等待长于抵达 timeout_time 。

示例

本节未完成
原因：暂无示例

参阅

wait | 等待结果变得可用 (公开成员函数)
wait_for | 等待结果，如果在指定的超时间隔后仍然无法得到结果，则返回。 (公开成员函数)


std::shared_future<T>::~shared_future

< cpp‎ | thread‎ | shared future
~shared_future(); | (C++11 起)

若 *this 是指代共享状态的最后一个对象，则销毁共享状态。否则不做任何事。


std::shared_lock

< cpp‎ | thread
定义于头文件 <shared_mutex> |
template< class Mutex > class shared_lock; | (C++14 起)

类 shared_lock 是通用共享互斥所有权包装器，允许延迟锁定、定时锁定和锁所有权的转移。锁定 shared_lock ，会以共享模式锁定关联的共享互斥（ std::unique_lock 可用于以排他性模式锁定）。

shared_lock 类可移动，但不可复制——它满足可移动构造 (MoveConstructible) 与可移动赋值 (MoveAssignable) 的要求，但不满足可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 。

shared_lock 符合可锁定 (Lockable) 要求。若 Mutex 符合可共享定时锁定 (SharedTimedLockable) 要求，则 shared_lock 亦符合 可定时锁定 (TimedLockable) 要求。

为以共享所有权模式等待于共享互斥，可使用 std::condition_variable_any （ std::condition_variable 要求 std::unique_lock 故而只能以唯一所有权模式等待）。

模板形参

Mutex - 要锁定的共享互斥类型。类型必须符合可共享锁定 (SharedLockable) 要求。

成员类型

类型 | 定义
mutex_type | Mutex

成员函数

(构造函数)
 构造 shared_lock ，可选地锁定提供的互斥
(公开成员函数)
(析构函数)
 解锁关联的互斥
(公开成员函数)
operator=
 若占有则解锁互斥，然后获得对方的所有权
(公开成员函数)
共享锁定
lock
 锁定关联的互斥
(公开成员函数)
try_lock
 尝试锁定关联的互斥
(公开成员函数)
try_lock_for
 尝试锁定关联的互斥，以指定时长
(公开成员函数)
try_lock_until
 尝试锁定关联的互斥，直至指定的时间点
(公开成员函数)
unlock
 解锁关联的互斥
(公开成员函数)
修改器
swap
 与另一 shared_lock 交换数据成员
(公开成员函数)
release
 解除关联 mutex 而不解锁
(公开成员函数)
观察器
mutex
 返回指向关联的互斥的指针
(公开成员函数)
owns_lock
 测试锁是否占有其关联的互斥
(公开成员函数)
operator bool
 测试锁是否占有其关联的互斥
(公开成员函数)

非成员函数

std::swap(std::shared_lock)
(C++14)
 std::swap 对 shared_lock 的特化
(函数模板)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2981 | C++17 | 曾提供来自 shared_lock<Mutex> 的冗余推导指引 | 已移除


std::shared_lock<Mutex>::lock

< cpp‎ | thread‎ | shared lock
void lock(); | (C++14 起)

以共享模式锁定关联互斥。等效于调用 mutex()->lock_shared() 。

参数

（无）

返回值

（无）

异常

  • 任何 mutex()->lock_shared() 抛出的异常
  • 若无关联互斥，则抛出以 std::errc::operation_not_permitted 为错误码的 std::system_error
  • 若关联互斥已为此 shared_lock 所锁定（即 owns_lock 返回 true ），则返回以 std::errc::resource_deadlock_would_occur 为错误码的 std::system_error

示例

本节未完成
原因：暂无示例

参阅

try_lock | 尝试锁定关联的互斥 (公开成员函数)
unlock | 解锁关联的互斥 (公开成员函数)


std::shared_lock<Mutex>::mutex

< cpp‎ | thread‎ | shared lock
mutex_type* mutex() const noexcept; | (C++14 起)

返回指向关联互斥的指针，或若无关联互斥则返回空指针。

参数

（无）

返回值

指向关联互斥的指针，或若无关联互斥则为空指针。

示例

本节未完成
原因：暂无示例


std::shared_lock<Mutex>::operator=

< cpp‎ | thread‎ | shared lock
shared_lock& operator=( shared_lock&& other ) noexcept; | (C++14 起)

移动赋值运算符。用移动语义以 other 的内容替换内容。

若在此调用前 *this 拥有关联的互斥（ mutex() 返回非空指针且）且获得了其所有权（ owns() 返回 true ），则通过调用 unlock_shared() 解锁互斥。

此调用后， other 无关联的互斥。

参数

other - 用以替换状态的另一 shared_lock

返回值

*this


std::shared_lock<Mutex>::operator bool

< cpp‎ | thread‎ | shared lock
explicit operator bool() const noexcept; | (C++14 起)

检查 *this 是否拥有已锁的互斥。等效于调用 owns_lock() 。

参数

（无）

返回值

若 *this 拥有关联互斥且已获得其共享所有权则为 true ，否则为 false 。

参阅

owns_lock
 测试锁是否占有其关联的互斥
(公开成员函数)


std::shared_lock<Mutex>::owns_lock

< cpp‎ | thread‎ | shared lock
bool owns_lock() const noexcept; | (C++14 起)

检查 *this 是否拥有已锁的互斥。

参数

（无）

返回值

若 *this 拥有关联互斥且已获得其共享所有权，则为 true ，否则为 false 。

参阅

operator bool
 测试锁是否占有其关联的互斥
(公开成员函数)


std::shared_lock<Mutex>::release

< cpp‎ | thread‎ | shared lock
mutex_type* release() noexcept; | (C++14 起)

打破关联互斥和 *this 的关联，若它存在。

没有锁被解锁。若 *this 在调用前曾保有关联互斥的所有权，则现在调用方为解锁互斥负责。

参数

（无）

返回值

指向关联互斥体的指针，或若无关联互斥体则为空指针。

示例

本节未完成
原因：暂无示例

参阅

unlock | 解锁关联的互斥 (公开成员函数)
release | 将关联互斥解关联而不解锁它 (std::unique_lock<Mutex> 的公开成员函数)


std::shared_lock<Mutex>::shared_lock

< cpp‎ | thread‎ | shared lock
shared_lock() noexcept; | (1) | (C++14 起)
shared_lock( shared_lock&& other ) noexcept; | (2) | (C++14 起)
explicit shared_lock( mutex_type& m ); | (3) | (C++14 起)
shared_lock( mutex_type& m, std::defer_lock_t t ) noexcept; | (4) | (C++14 起)
shared_lock( mutex_type& m, std::try_to_lock_t t ); | (5) | (C++14 起)
shared_lock( mutex_type& m, std::adopt_lock_t t ); | (6) | (C++14 起)
template< class Rep, class Period > shared_lock( mutex_type& m, const std::chrono::duration <Rep,Period>& timeout_duration ); | (7) | (C++14 起)
template< class Clock, class Duration > shared_lock( mutex_type& m, const std::chrono::time_point <Clock,Duration>& timeout_time ); | (8) | (C++14 起)

构造 shared_lock ，可选地锁定提供的互斥。

1) 构造 shared_lock ，不关联互斥。
2) 移动构造函数。以 other 的内容初始化 shared_lock 。令 other 不关联到互斥。
3-8) 构造 shared_lock ，以 m 为关联的互斥。另外：
3) 通过调用 m.lock_shared() ，以共享模式锁定关联的互斥。
4) 不锁定关联的互斥。
5) 尝试通过调用 m.try_lock_shared() ，以共享模式锁定关联的互斥而不阻塞。
6) 假设调用方线程已在 m 上持有共享锁（即由 lock_shared、 try_lock_shared、 try_lock_shared_for 或 try_lock_shared_until 取得的锁）。若非如此则行为未定义。
7) 尝试通过调用 m.try_lock_shared_for(timeout_duration) ，以共享模式锁定关联的互斥，这会阻塞直到经过指定的 timeout_duration 或取得锁，两者的先到来者。可能锁定长于 timeout_duration 。若 Mutex 不符合可共享定时锁定 (SharedTimedLockable) 要求则行为未定义。
8) 尝试通过调用 m.try_lock_shared_until(timeout_time) ，以共享模式锁定关联的互斥，这会阻塞直到抵达指定的 timeout_time 或取得锁，两者的先到来者。可能锁定长于到抵达 timeout_time 为止。若 Mutex 不符合可共享定时锁定 (SharedTimedLockable) 要求则行为未定义。

参数

other | - | 以之初始化状态的另一 shared_lock
m | - | 关联到所的互斥，可选地获得其所有权
t | - | 用于选择不同锁定策略的标签参数
timeout_duration | - | 要阻塞的最大时长
timeout_time | - | 要阻塞到的最大时间点

示例

#include <shared_mutex>
#include <iostream>
#include <thread>
#include <chrono>

std::shared_timed_mutex m;
int i = 10;
using namespace std::chrono;

void read()
{
   // 两个线程都获得对整数 i 的访问
   std::shared_lock<std::shared_timed_mutex> slk(m);
   std::cout << "read i as " << i << "...\n"; // 此不同步
   std::this_thread::sleep_for(10ms);
   std::cout << "woke up...\n";
}

int main()
{
   std::thread(read).join();
   std::thread(read).join();
   return 0;
}


std::shared_lock<Mutex>::swap

< cpp‎ | thread‎ | shared lock
template< class Mutex > void swap( shared_lock<Mutex>& other ) noexcept; | (C++14 起)

交换锁对象的内部状态。

参数

other - 要交换状态的锁

返回值

(none)

示例

本节未完成
原因：暂无示例

参阅

std::swap(std::shared_lock)
(C++14)
 std::swap 对 shared_lock 的特化
(函数模板)


std::swap(std::shared_lock)

< cpp‎ | thread‎ | shared lock
template< class Mutex > void swap( shared_lock<Mutex>& lhs, shared_lock<Mutex>& rhs ) noexcept; | (C++14 起)

为 std::shared_lock 特化 std::swap 算法。交换 lhs 与 rhs 的内部状态。等效于调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的锁包装器

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

swap
 与另一 shared_lock 交换数据成员
(公开成员函数)


std::shared_lock<Mutex>::try_lock

< cpp‎ | thread‎ | shared lock
bool try_lock(); | (C++14 起)

尝试以共享模式锁定关联互斥而不阻塞。等效于调用 mutex()->try_lock_shared() 。

若无关联互斥，或互斥已被锁定，则抛出 std::system_error 。

参数

（无）

返回值

若已成功得到互斥的所有权则为 true ，否则为 false 。

异常

  • 任何 mutex()->try_lock_shared() 所抛的异常
  • 若无关联互斥，则抛出以 std::errc::operation_not_permitted 为错误码的 std::system_error
  • 若互斥已被锁，则抛出以 std::errc::resource_deadlock_would_occur 为错误码的 std::system_error

示例

本节未完成
原因：暂无示例

参阅

try_lock | 尝试锁定关联的互斥 (公开成员函数)
lock | 锁定关联的互斥 (公开成员函数)
try_lock_for | 尝试锁定关联的互斥，以指定时长 (公开成员函数)
try_lock_until | 尝试锁定关联的互斥，直至指定的时间点 (公开成员函数)
unlock | 解锁关联的互斥 (公开成员函数)


std::shared_lock<Mutex>::try_lock_for

< cpp‎ | thread‎ | shared lock
template< class Rep, class Period > bool try_lock_for( const std::chrono::duration <Rep,Period>& timeout_duration ); | (C++14 起)

尝试以共享模式锁定关联互斥。阻塞直至经过 timeout_duration 或得到锁，之先来到者。成功获得锁时返回 true ，否则返回 false 。等效于调用 mutex()->try_lock_shared_for(timeout_duration) 。

由于调度或资源争夺延迟，此函数可能阻塞长于 timeout_duration 。

标准建议使用稳定时钟。若实现用系统时钟代替，则等待时间亦可能对时钟调节敏感。

若无关联互斥或互斥已被锁则抛出 std::system_error 。

若 Mutex 不符合可共享定时锁定 (SharedTimedLockable) 要求则行为未定义。

参数

timeout_duration - 要阻塞的最大时长

返回值

若已成功获得互斥的所有权则为 true ，否则为 false 。

异常

  • 任何 mutex()->try_lock_shared_for(timeout_duration) 所抛的异常
  • 若无关联互斥，则抛出以 std::errc::operation_not_permitted 为错误码的 std::system_error
  • 若互斥已被锁，则抛出以 std::errc::resource_deadlock_would_occur 为错误码的 std::system_error

示例

本节未完成
原因：暂无示例

参阅

try_lock_for | 试图锁定关联的可定时锁定 (TimedLockable) 互斥，若互斥在给定时长中不可用则返回 (std::unique_lock<Mutex> 的公开成员函数)
lock | 锁定关联的互斥 (公开成员函数)
try_lock | 尝试锁定关联的互斥 (公开成员函数)
try_lock_until | 尝试锁定关联的互斥，直至指定的时间点 (公开成员函数)
unlock | 解锁关联的互斥 (公开成员函数)


std::shared_lock<Mutex>::try_lock_until

< cpp‎ | thread‎ | shared lock
template< class Clock, class Duration > bool try_lock_until( const std::chrono::time_point <Clock,Duration>& timeout_time ); | (C++14 起)

试图以共享模式锁定关联互斥。阻塞直至抵达给定的 timeout_time 或得到互斥，之先到来者。成功获得互斥时返回 true ，否则返回 false 。可能阻塞长于直至抵达 timeout_time 。

等效地调用 mutex()->try_lock_shared_until(timeout_time) 。

若无关联互斥或已锁定互斥则返回 std::system_error 。

Clock 必须符合时钟 (Clock) 要求。若 Mutex 不符合可共享定时锁定 (SharedTimedLockable) 要求则行为未定义。若 std::chrono::is_clock_v<Clock> 为 false 则程序为非良构。 (C++20 起)

参数

timeout_time - 阻塞到的最大时间点

返回值

若已成功获得互斥的所有权则为 true ，否则为 false 。

异常

  • 任何 mutex()->try_lock_shared_for(timeout_time) 所抛的异常
  • 若无关联互斥，则抛出以 std::errc::operation_not_permitted 为错误码的 std::system_error
  • 若互斥已被锁，则抛出以 std::errc::resource_deadlock_would_occur 为错误码的 std::system_error

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定关联的互斥 (公开成员函数)
try_lock | 尝试锁定关联的互斥 (公开成员函数)
try_lock_for | 尝试锁定关联的互斥，以指定时长 (公开成员函数)
unlock | 解锁关联的互斥 (公开成员函数)
try_lock_until | 尝试锁定关联可定时锁定 (TimedLockable) 互斥，若抵达指定时间点互斥仍不可用则返回 (std::unique_lock<Mutex> 的公开成员函数)


std::shared_lock<Mutex>::unlock

< cpp‎ | thread‎ | shared lock
void unlock(); | (C++14 起)

从共享模式解锁关联互斥。等效于调用 mutex()->unlock_shared() 。

若无关联互斥或互斥未被锁则抛出 std::system_error 。

参数

（无）

返回值

（无）

异常

  • 任何 mutex()->unlock_shared() 抛出的异常
  • 若无关联互斥，则抛出以 std::errc::operation_not_permitted 为错误码的 std::system_error

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定关联的互斥 (公开成员函数)
release | 解除关联 mutex 而不解锁 (公开成员函数)


std::shared_lock<Mutex>::~shared_lock

< cpp‎ | thread‎ | shared lock
~shared_lock(); | (C++14 起)

销毁锁。

若 *this 有关联互斥（ mutex() 返回非空指针）且获得了其所有权（ owns() 返回 true ） ，则通过调用 unlock_shared() 解锁互斥。


std::shared_mutex

< cpp‎ | thread
定义于头文件 <shared_mutex> |
class shared_mutex; | (C++17 起)

shared_mutex 类是一个同步原语，可用于保护共享数据不被多个线程同时访问。与便于独占访问的其他互斥类型不同，shared_mutex 拥有二个访问级别：

  • 共享 - 多个线程能共享同一互斥的所有权。
  • 独占性 - 仅一个线程能占有互斥。

若一个线程已获取独占性锁（通过 lock 、 try_lock ），则无其他线程能获取该锁（包括共享的）。

仅当任何线程均未获取独占性锁时，共享锁能被多个线程获取（通过 lock_shared 、 try_lock_shared ）。

在一个线程内，同一时刻只能获取一个锁（共享或独占性）。

共享互斥体在能由任何数量的线程同时读共享数据，但一个线程只能在无其他线程同时读写时写同一数据时特别有用。

shared_mutex 类满足共享互斥体 (SharedMutex) 和标准布局类型 (StandardLayoutType) 的所有要求。

成员类型

成员类型 | 定义
native_handle_type(可选) | 实现定义

成员函数

(构造函数)
 构造互斥
(公开成员函数)
(析构函数)
 销毁互斥
(公开成员函数)
operator=
[被删除]
 不可复制赋值
(公开成员函数)
排他性锁定
lock
 锁定互斥，若互斥不可用则阻塞
(公开成员函数)
try_lock
 尝试锁定互斥，若互斥不可用则返回
(公开成员函数)
unlock
 解锁互斥
(公开成员函数)
共享锁定
lock_shared
 为共享所有权锁定互斥，若互斥不可用则阻塞
(公开成员函数)
try_lock_shared
 尝试为共享所有权锁定互斥，若互斥不可用则返回
(公开成员函数)
unlock_shared
 解锁互斥（共享所有权）
(公开成员函数)
原生句柄
native_handle
 返回底层实现定义的原生句柄
(公开成员函数)

示例

#include <iostream>
#include <mutex>  // 对于 std::unique_lock
#include <shared_mutex>
#include <thread>

class ThreadSafeCounter {
 public:
  ThreadSafeCounter() = default;

  // 多个线程/读者能同时读计数器的值。
  unsigned int get() const {
    std::shared_lock<std::shared_mutex> lock(mutex_);
    return value_;
  }

  // 只有一个线程/写者能增加/写线程的值。
  void increment() {
    std::unique_lock<std::shared_mutex> lock(mutex_);
    value_++;
  }

  // 只有一个线程/写者能重置/写线程的值。
  void reset() {
    std::unique_lock<std::shared_mutex> lock(mutex_);
    value_ = 0;
  }

 private:
  mutable std::shared_mutex mutex_;
  unsigned int value_ = 0;
};

int main() {
  ThreadSafeCounter counter;

  auto increment_and_print = [&counter]() {
    for (int i = 0; i < 3; i++) {
      counter.increment();
      std::cout << std::this_thread::get_id() << ' ' << counter.get() << '\n';

      // 注意：写入 std::cout 实际上也要由另一互斥同步。省略它以保持示例简洁。
    }
  };

  std::thread thread1(increment_and_print);
  std::thread thread2(increment_and_print);

  thread1.join();
  thread2.join();
}

// 解释：下列输出在单核机器上生成。 thread1 开始时，它首次进入循环并调用 increment() ，
// 随后调用 get() 。然而，在它能打印返回值到 std::cout 前，调度器将 thread1 置于休眠
// 并唤醒 thread2 ，它显然有足够时间一次运行全部三个循环迭代。再回到 thread1 ，它仍在首个
// 循环迭代中，它最终打印其局部的计数器副本的值，即 1 到 std::cout ，再运行剩下二个循环。
// 多核机器上，没有线程被置于休眠，且输出更可能为递增顺序。

可能的输出：

123084176803584 2
123084176803584 3
123084176803584 4
123084185655040 1
123084185655040 5
123084185655040 6

参阅

shared_timed_mutex
(C++14)
 提供共享互斥设施并实现有时限锁定
(类)


std::shared_mutex::lock

< cpp‎ | thread‎ | shared mutex

void lock(); | (C++17 起)

锁定互斥。若另一线程已锁定互斥，则到 lock 的调用将阻塞执行，直至获得锁。

若已以任何模式（共享或排他性）占有 mutex 的线程调用 lock ，则行为未定义。

同一互斥上先前的 unlock() 操作同步于（定义于 std::memory_order ）此操作。

参数

（无）

返回值

（无）

异常

错误发生时抛出 std::system_error ，包括底层操作系统阻止 lock 满足其规定的错误。在抛出任何异常的情况下，不锁定互斥。

注意

通常不直接调用 lock() ：用 std::unique_lock 与 std::lock_guard 管理排他性锁定。

共享互斥不支持直接从共享到唯一所有权模式的迁移：必须在以 lock() 获得排他性所有权之前用 unlock_shared() 交出共享锁。可为此目的使用 boost::upgrade_mutex 。

示例

此示例演示 lock 与 unlock 能如何用于保护共享数据。

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>

int g_num = 0;  // 为 g_num_mutex 所保护
std::mutex g_num_mutex;

void slow_increment(int id)
{
    for (int i = 0; i < 3; ++i) {
        g_num_mutex.lock();
        ++g_num;
        std::cout << id << " => " << g_num << '\n';
        g_num_mutex.unlock();

        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main()
{
    std::thread t1(slow_increment, 0);
    std::thread t2(slow_increment, 1);
    t1.join();
    t2.join();
}

可能的输出：

0 => 1
1 => 2
0 => 3
1 => 4
0 => 5
1 => 6

参阅

try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::shared_mutex::lock_shared

< cpp‎ | thread‎ | shared mutex
void lock_shared(); | (C++17 起)

获得互斥的共享所有权。若另一线程以排他性所有权保有互斥，则到 lock_shared 的调用将阻塞执行，直到能取得共享所有权。

若已以任何模式（排他性或共享）占有 mutex 的线程调用 lock_shared ，则行为未定义。

若多于实现定义最大数量的共享所有者已以共享模式锁定互斥，则 lock_shared 阻塞执行，直至共享所有者的数量减少。所有者的最大数量保证至少为 10000 。

同一互斥上先前的 unlock() 操作同步于（定义于 std::memory_order ）此操作。

参数

（无）

返回值

（无）

异常

出现错误时抛出 std::system_error ，包括来自底层系统将阻止 lock 满足规定的错误。在抛出任何异常的情况下，互斥不被锁定。

注意

通常不直接调用 lock_shared() ：用 std::shared_lock 管理共享锁定。

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock_shared | 尝试为共享所有权锁定互斥，若互斥不可用则返回 (公开成员函数)
unlock_shared | 解锁互斥（共享所有权） (公开成员函数)


std::shared_mutex::native_handle

< cpp‎ | thread‎ | shared mutex

native_handle_type native_handle(); | (C++17 起) (可选)

返回底层实现定义的原生句柄对象。

参数

（无）

返回值

实现定义的原生句柄对象。

异常

实现定义。

示例

本节未完成
原因：暂无示例


std::shared_mutex::shared_mutex

< cpp‎ | thread‎ | shared mutex

shared_mutex(); | (1) | (C++17 起)
shared_mutex( const shared_mutex& ) = delete; | (2) | (C++17 起)
1) 构造互斥。调用后互斥在未锁定状态。
2) 复制构造函数被删除。

参数

（无）

异常

若构造不成功则抛出 std::system_error 。

参阅


std::shared_mutex::try_lock

< cpp‎ | thread‎ | shared mutex

bool try_lock(); | (C++17 起)

尝试锁定互斥。立即返回。成功获得锁时返回 true ，否则返回 false 。

允许此函数虚假地失败而返回 false ，即使互斥当前未为任何其他线程所锁定。

若已以任何模式（共享或排他性）占有 mutex 的线程调用 try_lock ，则行为未定义。

若此操作返回 true ，则同一互斥上的先前 unlock() 操作同步于（定义于 std::memory_order ）它。注意若此操作返回 false ，则先前的 lock() 不与之同步。

参数

（无）

返回值

若成功取得锁则为 true ，否则为 false 。

异常

不抛出。

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::shared_mutex::try_lock_shared

< cpp‎ | thread‎ | shared mutex
bool try_lock_shared(); | (C++17 起)

尝试以共享模式锁定互斥。立即返回。成功获得锁时返回 true ，否则返回 false 。

允许此函数虚假地失败并返回 false ，即使互斥当前不为任何其他线程所排他性锁定。

若此操作返回 true ，则同一互斥上先前的 unlock() 操作同步于（定义于 std::memory_order ）它。

若调用方线程已以任何模式占有互斥，则行为未定义。

参数

（无）

返回值

若成功获得锁则为 true ，否则为 false 。

异常

不抛出。

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
unlock_shared | 解锁互斥（共享所有权） (公开成员函数)


std::shared_mutex::unlock

< cpp‎ | thread‎ | shared mutex

void unlock(); | (C++17 起)

解锁互斥。

互斥必须为当前执行线程所锁定，否则行为未定义。

此操作同步于（定义于 std::memory_order ）任何后继的取得同一互斥所有权的锁操作。

参数

（无）

返回值

（无）

异常

不抛出。

注解

通常不直接调用 unlock() ：用 std::unique_lock 与 std::lock_guard 管理互斥锁定。

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)


std::shared_mutex::unlock_shared

< cpp‎ | thread‎ | shared mutex
void unlock_shared(); | (C++17 起)

将互斥从调用方线程的共享所有权释放。

当前执行线程必须以共享模式锁定互斥，否则行为未定义。

此操作同步于（定义于 std::memory_order ）任何获得同一互斥所有权的 lock() 操作。

参数

（无）

返回值

（无）

异常

不抛出。

注解

通常不直接调用 unlock_shared() ：用 std::shared_lock 管理共享锁定。

示例

本节未完成
原因：暂无示例

参阅

lock_shared | 为共享所有权锁定互斥，若互斥不可用则阻塞 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::shared_mutex::~shared_mutex

< cpp‎ | thread‎ | shared mutex

~shared_mutex();

销毁互斥。

若互斥为任何线程占有，或若任何线程在保有任何互斥的所有权时终止，则行为未定义。

参阅


std::shared_timed_mutex

< cpp‎ | thread
定义于头文件 <shared_mutex> |
class shared_timed_mutex; | (C++14 起)

shared_timed_mutex 类是能用于保护数据免受多个线程同时访问的同步原语。与其他促进排他性访问的互斥类型相反，拥有二个层次的访问：

  • 共享 - 多个线程能共享同一互斥的所有权。
  • 排他性 - 仅一个线程能占有互斥。

共享互斥通常用于多个读线程能同时访问同一资源而不导致数据竞争，但只有一个写线程能访问的情形。

以类似 timed_mutex 的行为， shared_timed_mutex 提供通过 try_lock_for() 、 try_lock_until() 、 try_lock_shared_for() 、 try_lock_shared_until() 方法，试图带时限地要求 shared_timed_mutex 所有权的能力。

shared_timed_mutex 类满足共享定时互斥体 (SharedTimedMutex) 和标准布局类型 (StandardLayoutType) 的所有要求。

成员函数

(构造函数)
 构造互斥
(公开成员函数)
(析构函数)
 销毁互斥
(公开成员函数)
operator=
[被删除]
 不可复制赋值
(公开成员函数)
排他性锁定
lock
 锁定互斥，若互斥不可用则阻塞
(公开成员函数)
try_lock
 尝试锁定互斥，若互斥不可用则返回
(公开成员函数)
try_lock_for
 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回
(公开成员函数)
try_lock_until
 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回
(公开成员函数)
unlock
 解锁互斥
(公开成员函数)
共享锁定
lock_shared
 为共享所有权锁定互斥，若互斥不可用则阻塞
(公开成员函数)
try_lock_shared
 尝试为共享所有权锁定互斥，若互斥不可用则返回
(公开成员函数)
try_lock_shared_for
 尝试为共享所有权锁定互斥，若互斥在指定的时限时期中不可用则返回
(公开成员函数)
try_lock_shared_until
 尝试为共享所有权锁定互斥，若直至抵达指定时间点互斥不可用则返回
(公开成员函数)
unlock_shared
 解锁互斥（共享所有权）
(公开成员函数)

示例

本节未完成
原因：建立有动机的示例

复制赋值运算符，属于保有能处置多个读者，但只有一个写者的资源

#include <mutex>
#include <shared_mutex>

class R
{
    mutable std::shared_timed_mutex mut;
    /* 数据 */
public:
    R& operator=(const R& other)
    {
        // 要求排他性所有权以写入 *this
        std::unique_lock<std::shared_timed_mutex> lhs(mut, std::defer_lock);
        // 要求共享所有权以读取 other
        std::shared_lock<std::shared_timed_mutex> rhs(other.mut, std::defer_lock);
        std::lock(lhs, rhs);
        /* 赋值数据 */
        return *this;
    }
};

int main() {
    R r;
}


std::shared_timed_mutex::lock

< cpp‎ | thread‎ | shared timed mutex

void lock(); | (C++14 起)

锁定互斥。若另一线程已锁定互斥，则到 lock 的调用将阻塞执行，直至获得锁。

若已以任何模式（共享或排他性）占有 mutex 的线程调用 lock ，则行为未定义。

同一互斥上先前的 unlock() 操作同步于（定义于 std::memory_order ）此操作。

参数

（无）

返回值

（无）

异常

错误发生时抛出 std::system_error ，包括底层操作系统阻止 lock 满足其规定的错误。在抛出任何异常的情况下，不锁定互斥。

注意

通常不直接调用 lock() ：用 std::unique_lock 与 std::lock_guard 管理排他性锁定。

共享互斥不支持直接从共享到唯一所有权模式的迁移：必须在以 lock() 获得排他性所有权之前用 unlock_shared() 交出共享锁。可为此目的使用 boost::upgrade_mutex 。

示例

此示例演示 lock 与 unlock 能如何用于保护共享数据。

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>

int g_num = 0;  // 为 g_num_mutex 所保护
std::mutex g_num_mutex;

void slow_increment(int id)
{
    for (int i = 0; i < 3; ++i) {
        g_num_mutex.lock();
        ++g_num;
        std::cout << id << " => " << g_num << '\n';
        g_num_mutex.unlock();

        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main()
{
    std::thread t1(slow_increment, 0);
    std::thread t2(slow_increment, 1);
    t1.join();
    t2.join();
}

可能的输出：

0 => 1
1 => 2
0 => 3
1 => 4
0 => 5
1 => 6

参阅

try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::shared_timed_mutex::lock_shared

< cpp‎ | thread‎ | shared timed mutex
void lock_shared(); | (C++14 起)

获得互斥的共享所有权。若另一线程以排他性所有权保有互斥，则到 lock_shared 的调用将阻塞执行，直到能取得共享所有权。

若已以任何模式（排他性或共享）占有 mutex 的线程调用 lock_shared ，则行为未定义。

若多于实现定义最大数量的共享所有者已以共享模式锁定互斥，则 lock_shared 阻塞执行，直至共享所有者的数量减少。所有者的最大数量保证至少为 10000 。

同一互斥上先前的 unlock() 操作同步于（定义于 std::memory_order ）此操作。

参数

（无）

返回值

（无）

异常

出现错误时抛出 std::system_error ，包括来自底层系统将阻止 lock 满足规定的错误。在抛出任何异常的情况下，互斥不被锁定。

注意

通常不直接调用 lock_shared() ：用 std::shared_lock 管理共享锁定。

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock_shared | 尝试为共享所有权锁定互斥，若互斥不可用则返回 (公开成员函数)
unlock_shared | 解锁互斥（共享所有权） (公开成员函数)


std::shared_timed_mutex::shared_timed_mutex

< cpp‎ | thread‎ | shared timed mutex

shared_timed_mutex(); | (1) | (C++14 起)
shared_timed_mutex( const shared_timed_mutex& ) = delete; | (2) | (C++14 起)
1) 构造互斥。调用后互斥在未锁定状态。
2) 复制构造函数被删除。

参数

（无）

异常

若构造不成功则抛出 std::system_error 。

参阅


std::shared_timed_mutex::try_lock

< cpp‎ | thread‎ | shared timed mutex

bool try_lock(); | (C++14 起)

尝试锁定互斥。立即返回。成功获得锁时返回 true ，否则返回 false 。

允许此函数虚假地失败而返回 false ，即使互斥当前未为任何其他线程所锁定。

若已以任何模式（共享或排他性）占有 mutex 的线程调用 try_lock ，则行为未定义。

若此操作返回 true ，则同一互斥上的先前 unlock() 操作同步于（定义于 std::memory_order ）它。注意若此操作返回 false ，则先前的 lock() 不与之同步。

参数

（无）

返回值

若成功取得锁则为 true ，否则为 false 。

异常

不抛出。

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock_for | 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回 (公开成员函数)
try_lock_until | 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::shared_timed_mutex::try_lock_for

< cpp‎ | thread‎ | shared timed mutex

template< class Rep, class Period > bool try_lock_for( const std::chrono::duration <Rep,Period>& timeout_duration ); | (C++14 起)

尝试锁互斥。阻塞直到经过指定的 timeout_duration 或得到锁，取决于何者先到来。成功获得锁时返回 true ， 否则返回 false 。

若 timeout_duration 小于或等于 timeout_duration.zero() ，则函数表现同 try_lock() 。

由于调度或资源争议延迟，此函数可能阻塞长于 timeout_duration 。

标准推荐用 steady_clock 度量时长。若实现用 system_clock 代替，则等待时间亦可能对时钟调整敏感。

同 try_lock() ，允许此函数虚假地失败并返回 false ，即使在 timeout_duration 中某点互斥不为任何线程所锁定。

若此操作返回 true ，则同一互斥上先前的 unlock() 调用同步于（定义于 std::memory_order ）它。

若已以任何模式（共享或排他性）占有 mutex 的线程调用 try_lock_for ，则行为未定义。

参数

timeout_duration - 要阻塞的最大时长

返回值

若成功获得锁则为 true ，否则为 false 。

异常

执行期间时钟、时间点或时长可能抛出的异常（标准库提供的时钟、时间点和时长决不抛出）

示例

#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
#include <sstream>

std::mutex cout_mutex; // 控制到 std::cout 的访问
std::timed_mutex mutex;

void job(int id)
{
    using Ms = std::chrono::milliseconds;
    std::ostringstream stream;

    for (int i = 0; i < 3; ++i) {
        if (mutex.try_lock_for(Ms(100))) {
            stream << "success ";
            std::this_thread::sleep_for(Ms(100));
            mutex.unlock();
        } else {
            stream << "failed ";
        }
        std::this_thread::sleep_for(Ms(100));
    }

    std::lock_guard<std::mutex> lock(cout_mutex);
    std::cout << "[" << id << "] " << stream.str() << "\n";
}

int main()
{
    std::vector<std::thread> threads;
    for (int i = 0; i < 4; ++i) {
        threads.emplace_back(job, i);
    }

    for (auto& i: threads) {
        i.join();
    }
}

可能的输出：

[0] failed failed failed
[3] failed failed success
[2] failed success failed
[1] success failed success

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
try_lock_until | 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::shared_timed_mutex::try_lock_shared

< cpp‎ | thread‎ | shared timed mutex
bool try_lock_shared(); | (C++14 起)

尝试以共享模式锁定互斥。立即返回。成功获得互斥时返回 true ，否则返回 false 。

允许此函数虚假地失败而返回 false ，即使当前互斥未被另一线程排他地锁定。

若此操作返回 true ，则同一互斥上先前的 unlock() 操作同步于（定义于 std::memory_order ）它。

若调用方线程已以任何模式占有互斥，则行为未定义。

参数

（无）

返回值

若成功获得锁则为 true ，否则为 false 。

异常

不抛出。

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
unlock_shared | 解锁互斥（共享所有权） (公开成员函数)


std::shared_timed_mutex::try_lock_shared_for

< cpp‎ | thread‎ | shared timed mutex
template< class Rep, class Period > bool try_lock_shared_for( const std::chrono::duration <Rep,Period>& timeout_duration ); | (C++14 起)

尝试以共享模式锁定互斥。阻塞直至经过指定的 timeout_duration 或得到互斥，之先到来者。成功获得互斥时返回 true ，否则返回 false 。

若 timeout_duration 小于或等于 timeout_duration.zero() ，则函数表现同 try_lock_shared() 。

由于调度或资源争议延迟，此函数可能阻塞长于 timeout_duration 。

标准建议用稳定时钟度量时长。若实现用系统时钟代替，则等待时间亦可能对时钟调整敏感。

同 try_lock_shared() ，允许此函数虚假地失败而返回 false ，即使在 timeout_duration 期间某点互斥不为任何其他线程所锁定。

若此操作返回 true ，则同一互斥上先前的 unlock() 操作同步于（定义于 std::memory_order ）它。

若已以任何模式（共享或排他性）占有 mutex 的线程调用 try_lock_shared_for ，则行为未定义。

参数

timeout_duration - 要阻塞的最大时长

返回值

若成功获得锁则为 true ，否则为 false 。

异常

任何时钟、时间点或时长在执行中抛出的异常（标准库提供的时钟、时间点及时长决不抛出）

示例

本节未完成
原因：暂无示例

参阅

try_lock_shared | 尝试为共享所有权锁定互斥，若互斥不可用则返回 (公开成员函数)
try_lock_shared_until | 尝试为共享所有权锁定互斥，若直至抵达指定时间点互斥不可用则返回 (公开成员函数)
try_lock_for | 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回 (公开成员函数)


std::shared_timed_mutex::try_lock_shared_until

< cpp‎ | thread‎ | shared timed mutex
template< class Clock, class Duration > bool try_lock_shared_until( const std::chrono::time_point <Clock,Duration>& timeout_time ); | (C++14 起)

尝试以共享模式锁定互斥。阻塞直至抵达 timeout_time 或得到互斥，之先到来者。成功获得互斥时返回 true ，否则返回 false 。

若已经过 timeout_time ，则此函数表现同 try_lock_shared() 。

Clock 必须符合时钟 (Clock) 要求。若 std::chrono::is_clock_v<Clock> 为 false 则程序为非良构。 (C++20 起)

标准推荐使用绑定到 timeout_time 的时钟，该情况下可以计入时钟的调整。从而在调用时刻，阻塞的时长可以，但也可以不，小于或大于 timeout_time - Clock::now() 。这取决于调整的方向以及实现是否尊重它。函数亦可能由于调度或资源纠纷延迟，而阻塞长于到抵达 timeout_time 之后。

同 try_lock_shared() ，允许此函数虚假地失败而返回 false ，即使在 timeout_time 前某点互斥不为任何其他线程所锁定。

若此操作返回 true ，则同一互斥上先前的 unlock() 操作同步于（定义于 std::memory_order ）它。

若已以任何模式（共享或排他性）占有 mutex 的线程调用 try_lock_shared_until ，则行为未定义。

参数

timeout_time - 要阻塞到的最大时间点

返回值

若成功获得锁则为 true ，否则为 false 。

异常

任何时钟、时间点或时长在执行中抛出的异常（标准库提供的时钟、时间点及时长决不抛出）

示例

本节未完成
原因：暂无示例

参阅

try_lock_until | 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回 (公开成员函数)
try_lock_shared | 尝试为共享所有权锁定互斥，若互斥不可用则返回 (公开成员函数)
try_lock_shared_for | 尝试为共享所有权锁定互斥，若互斥在指定的时限时期中不可用则返回 (公开成员函数)


std::shared_timed_mutex::try_lock_until

< cpp‎ | thread‎ | shared timed mutex

template< class Clock, class Duration > bool try_lock_until( const std::chrono::time_point <Clock,Duration>& timeout_time ); | (C++14 起)

尝试所互斥。阻塞直至抵达指定的 timeout_time 或得到锁，取决于何者先到来。成功获得锁时返回 true ，否则返回 false 。

若已经过 timeout_time ，则此函数表现同 try_lock() 。

Clock 必须符合时钟 (Clock) 要求。若 std::chrono::is_clock_v<Clock> 为 false 则程序为非良构。 (C++20 起)

标准推荐使用绑定到 timeout_time 的时钟，该情况下可以计入时钟的调整。从而在调用时刻，阻塞的时长可以，但也可以不，小于或大于 timeout_time - Clock::now() 。这取决于调整的方向以及实现是否尊重它。函数亦可能由于调度或资源纠纷延迟，而阻塞长于到抵达 timeout_time 之后。

同 try_lock() ，允许此函数虚假地失败并返回 false ，即使在 timeout_time 前的某点任何线程都不锁定互斥。

若此操作返回 true ，则同一互斥上先前的 unlock() 调用同步于（定义于 std::memory_order ）它。

若已以任何模式（共享或排他性）占有 mutex 的线程调用 try_lock_until ，则行为未定义。

参数

timeout_time - 要阻塞到的最大时间点

返回值

若成功获得锁则为 true ，否则为 false 。

异常

执行期间时钟、时间点或时长可能抛出的异常（标准库提供的时钟、时间点和时长决不抛出）

示例

此示例展示 10 秒的阻塞

#include <thread>
#include <iostream>
#include <chrono>
#include <mutex>

std::shared_timed_mutex test_mutex;

void f()
{
    auto now=std::chrono::steady_clock::now();
    test_mutex.try_lock_until(now + std::chrono::seconds(10));
    std::cout << "hello world\n";
}

int main()
{
    std::lock_guard<std::shared_timed_mutex> l(test_mutex);
    std::thread t(f);
    t.join();
}

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
try_lock_for | 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::shared_timed_mutex::unlock

< cpp‎ | thread‎ | shared timed mutex

void unlock(); | (C++14 起)

解锁互斥。

互斥必须为当前执行线程所锁定，否则行为未定义。

此操作同步于（定义于 std::memory_order ）任何后继的取得同一互斥所有权的锁操作。

参数

（无）

返回值

（无）

异常

不抛出。

注解

通常不直接调用 unlock() ：用 std::unique_lock 与 std::lock_guard 管理互斥锁定。

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
try_lock_for | 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回 (公开成员函数)
try_lock_until | 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回 (公开成员函数)


std::shared_timed_mutex::unlock_shared

< cpp‎ | thread‎ | shared timed mutex
void unlock_shared(); | (C++14 起)

由调用方线程，从共享所有权释放互斥。

当前执行线程必须以共享模式锁定互斥，否则行为未定义。

此操作同步于（定义于 std::memory_order ）任何获得同一互斥所有权的后继 lock() 操作。

参数

（无）

返回值

（无）

异常

不抛出。

注解

通常不直接调用 unlock_shared() ：用 std::shared_lock 管理共享锁定。

示例

本节未完成
原因：暂无示例

参阅

lock_shared | 为共享所有权锁定互斥，若互斥不可用则阻塞 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::shared_timed_mutex::~shared_timed_mutex

< cpp‎ | thread‎ | shared timed mutex

~shared_timed_mutex();

销毁互斥。

若互斥为任何线程占有，或若任何线程在保有任何互斥的所有权时终止，则行为未定义。

参阅


std::this_thread::sleep_for

< cpp‎ | thread
定义于头文件 <thread> |
template< class Rep, class Period > void sleep_for( const std::chrono::duration <Rep, Period>& sleep_duration ); | (C++11 起)

阻塞当前线程执行，至少经过指定的 sleep_duration 。

此函数可能阻塞长于 sleep_duration ，因为调度或资源争议延迟。

标准库建议用稳定时钟度量时长。若实现用系统时间代替，则等待时间亦可能对时钟调节敏感。

参数

sleep_duration - 要睡眠的时长

返回值

（无）

异常

任何时钟、 time_point 或 duration 在执行间抛出的异常（标准库提供的时钟、时间点和时长决不抛出）。

示例

#include <iostream>
#include <chrono>
#include <thread>

int main()
{
    using namespace std::chrono_literals;
    std::cout << "Hello waiter\n" << std::flush;
    auto start = std::chrono::high_resolution_clock::now();
    std::this_thread::sleep_for(2000ms);
    auto end = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double, std::milli> elapsed = end-start;
    std::cout << "Waited " << elapsed.count() << " ms\n";
}

可能的输出：

Hello waiter
Waited 2000.12 ms

参阅

sleep_until
(C++11)
 使当前线程的执行停止直到指定的时间点
(函数)


std::this_thread::sleep_until

< cpp‎ | thread
定义于头文件 <thread> |
template< class Clock, class Duration > void sleep_until( const std::chrono::time_point <Clock,Duration>& sleep_time ); | (C++11 起)

阻塞当前线程，直至抵达指定的 sleep_time 。

Clock 必须符合时钟 (Clock) 要求。若 std::chrono::is_clock_v<Clock> 为 false 则程序为非良构。 (C++20 起)

标准推荐使用绑定到 sleep_time 的时钟，该情况下可以计入时钟的调整。从而在调用时刻，阻塞的时长可以，但也可以不，小于或大于 sleep_time - Clock::now() 。这取决于调整的方向以及实现是否尊重它。函数亦可能由于调度或资源纠纷延迟，而阻塞长于到抵达 sleep_time 之后。

参数

sleep_time - 要阻塞到的时间

返回值

（无）

异常

任何 Clock 或 Duration 可能抛出的异常（标准库提供的时钟和时长决不抛出）

参阅

sleep_for
(C++11)
 使当前线程的执行停止指定的时间段
(函数)


std::stop_callback

< cpp‎ | thread
定义于头文件 <stop_token> |
template< class Callback > class stop_callback; | (C++20 起)

stop_callback 类模板提供对关联的 std::stop_token 对象注册回调函数的 RAII 对象类型，使得将在 std::stop_token 的关联 std::stop_source 被请求停止时调用回调函数。

在对该 stop_callback 的关联 std::stop_token 的std::stop_source 成功调用 request_stop() 的同一线程调用经由 stop_callback 构造函数注册的回调函数；或若在构造函数的注册前已请求停止，则在构造 stop_callback 的线程调用回调函数。

能在同一或不同线程同时对同一 std::stop_token 创建多于一个 stop_callback 。不提供对执行它们所用顺序的保证，但将同步调用它们；除了对已对 std::stop_token 请求停止后构造的 stop_callback 如前述。

若调用的回调经由异常退出，则调用 std::terminate 。

std::stop_callback 非可复制构造 (CopyConstructible) 、可复制赋值 (CopyAssignable) 、可移动构造 (MoveConstructible) 亦非可移动赋值 (MoveAssignable) 。

模板形参 Callback 类型必须为 invocable 且 destructible 。忽略任何返回值。

成员类型

类型 | 定义
callback_type | Callback

成员函数

(构造函数) | 构造新的 stop_callback 对象 (公开成员函数)
(析构函数) | 析构 stop_callback 对象 (公开成员函数)
operator= [被删除] | stop_callback 不可赋值 (公开成员函数)

推导指引

示例

本节未完成
原因：暂无示例


std::stop_callback 的推导指引

< cpp‎ | thread‎ | stop callback
定义于头文件 <stop_token> |
template<class Callback> stop_callback(std::stop_token, Callback) -> stop_callback<Callback>; | (C++20 起)

为 std::stop_callback 提供一个推导指引以允许从可调用类型参数推导。

示例

本节未完成
原因：暂无示例


std::stop_callback<Callback>::stop_callback

< cpp‎ | thread‎ | stop callback
template<class C> explicit stop_callback( const std::stop_token& st, C&& cb ) noexcept(/*see below*/); | (1) | (C++20 起)
template<class C> explicit stop_callback( std::stop_token&& st, C&& cb ) noexcept(/*see below*/); | (2) | (C++20 起)
stop_callback( const stop_callback& ) = delete; | (3) | (C++20 起)
stop_callback( stop_callback& ) = delete; | (4) | (C++20 起)

构造新的 stop_callback 对象，保存并注册 cb 回调函数到给定的 std::stop_token 的关联状态中，为了之后若在关联的 std::stop_source 的关联停止状态上请求停止则调用

1) 对给定的 st （复制），给定可调用回调函数 cb 构造 stop_callback 。
2) 对给定的 st （移动），给定可调用回调函数 cb 构造 stop_callback 。
3-4) stop_callback 既非可复制构造 (CopyConstructible) 亦非可移动构造 (MoveConstructible) 。

两个构造函数仅若 Callback 与 C 满足 std::constructible_from<Callback, C> 的 constructible_from 才参与重载决议。若 Callback 与 C 满足概念但不满足其语义要求，则行为未定义。

参数

st | - | 用于注册此 stop_callback 对象 std::stop_token 的对象
cb | - | 若请求停止则调用的函数类型

异常

1-2)
noexcept 说明：
noexcept( std::is_nothrow_constructible_v <Callback, C>)
任何构造函数初始化给定的回调到 stop_callback 对象中抛出的异常。

注解

若对传入的 std::stop_token 为 st.stop_requested() == true ，则在构造函数返回前于当前线程调用回调函数。


std::stop_source

< cpp‎ | thread
定义于头文件 <stop_token> |
class stop_source; | (C++20 起)

stop_source 类提供发出停止请求的方式，例如为了 std::jthread 取消。对一个 stop_source 对象作出的停止请求对所有拥有同一关联状态的 stop_source 与 std::stop_token 可见；调用任何对关联 std::stop_token 注册的 std::stop_callback ；并且唤醒任何在关联 std::stop_token 上等待的 std::condition_variable_any 对象。

一旦请求停止，则不能撤销。额外的停止请求无效果。

成员函数

(构造函数)
 构造新的 stop_source 对象
(公开成员函数)
(析构函数)
 析构 stop_source 对象
(公开成员函数)
operator=
 赋值 stop_source 对象
(公开成员函数)
修改器
request_stop
 对关联停止状态做出停止请求，若它存在
(公开成员函数)
swap
 交换二个 stop_source 对象
(公开成员函数)
观察器
get_token
 返回关联停止状态的 stop_token
(公开成员函数)
stop_requested
 检查是否已请求关联停止状态停止
(公开成员函数)
stop_possible
 检查能否请求关联停止状态停止
(公开成员函数)

非成员函数

operator== | 比较二个 std::stop_source 对象 (函数)
swap(std::stop_source) (C++20) | 特化 std::swap 算法 (函数)

辅助常量

nostopstate
(C++20)
 用于 stop_source 构造函数的 std::nostopstate_t 实例
(常量)

辅助类

nostopstate_t
(C++20)
 用于 stop_source 构造函数的占位符类型
(类)

注解

为 std::jthread 取消的目的，应该用 get_stop_source() 从 std::jthread 对象取得 stop_source 对象；或者应该直接从 std::jthread 对象用 request_stop() 请求停止。然后这将使用传入 std::jthread 所调用函数（即其线程上正在执行的函数）的参数的同一关联停止状态。

然而，对于其他用途，能用默认构造函数分离构造 stop_source ，这会创建新的停止状态。

示例

本节未完成
原因：暂无示例


std::stop_source::get_token

< cpp‎ | thread‎ | stop source
[[nodiscard]] std::stop_token get_token() const noexcept; | (C++20 起)

若 stop_source 拥有停止状态，则返回与 stop_source 的停止状态关联的 stop_token 对象；否则返回默认构造（空）的 stop_token 。

参数

（无）

返回值

stop_token 对象，若 this->stop_possible() == false 则会为空

示例

本节未完成
原因：暂无示例


std::nostopstate

< cpp‎ | thread‎ | stop source
定义于头文件 <stop_token> |
inline constexpr std::nostopstate_t nostopstate{}; | (C++20 起)

这是用于构造空 std::stop_source 的 std::nostopstate_t 常量对象实例，作为非默认构造函数中的占位值。


std::nostopstate_t

< cpp‎ | thread‎ | stop source
定义于头文件 <stop_token>
struct nostopstate_t {

explicit nostopstate_t() = default;

};
 (C++20 起)

有意用于 std::stop_source 非默认构造函数中的占位符，使得构造的空 std::stop_source 无关联停止状态的单位类型。


std::stop_source::operator=

< cpp‎ | thread‎ | stop source
std::stop_source& operator=( const std::stop_source& other ) noexcept; | (1) | (C++20 起)
std::stop_source& operator=( std::stop_source&& other ) noexcept; | (2) | (C++20 起)

以 other 的停止状态替换停止状态。

1) 复制赋值 other 的停止状态给 *this 的。等价于 stop_source(other).swap(*this) 。
2) 移动赋值 other 的停止状态给 *this 的。赋值后， *this 含有 other 先前的停止状态，而 other 无停止状态。等价于 stop_source(std::move(other)).swap(*this) 。

参数

other - 要共享停止状态或获得停止状态的另一 stop_source 对象


operator==(std::stop_source)

< cpp‎ | thread‎ | stop source
[[nodiscard]] friend bool operator==( const stop_source& lhs, const stop_source& rhs ) noexcept; | (C++20 起)

比较二个 stop_source 值。

此函数对通常无限定或有限定查找不可见，而只能在 std::stop_source 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

参数

lhs, rhs - 要比较的 stop_source

返回值

若 lhs 与 rhs 拥有同一停止状态或均无停止状态则为 true ，否则为 false


std::stop_source::request_stop

< cpp‎ | thread‎ | stop source
bool request_stop() noexcept; | (C++20 起)

若 stop_source 对象拥有停止状态且未被请求停止，则发出停止请求给停止状态。

原子地作出确定，而若请求了停止，则原子地更新共享状态以避免竞争条件，使得：

  • 能在同一共享状态的 std::stop_token 与 std::stop_source 上同时调用 stop_requested() 与 stop_possible() ；
  • 能从多个线程在同一 jthread 对象或与同一停止状态关联的其他 std::stop_source 对象上并发调用 request_stop() ，而将只有一个线程实际进行停止请求。

然而，见注解节。

参数

（无）

返回值

若 stop_source 对象拥有停止状态且此调用做出停止请求则为 true ，否则为 false 。

后条件

stop_possible() 为 false 或 stop_requested() 为 true 。

注解

若 request_stop() 发出停止请求（即返回 true ），则将在发出 request_stop() 的同一线程上同步调用对同一共享停止状态注册的任何 std::stop_callback 。若任何回调的调用经由异常退出，则调用 std::terminate 。

若 stop_source 对象拥有停止状态但已作出停止请求，则此函数返回 false 。然而不保证正好对同一停止状态（成功）请求停止的另一 stop_source 不仍然在调用 std::stop_callback 函数的中间。

若 request_stop() 发出停止请求（即返回 true ），则提醒所有用与 stop_source 的停止状态关联的 stop_token 的可中断等待注册的、基类型为 std::condition_variable_any 的条件变量。

示例

本节未完成
原因：暂无示例


std::stop_source::stop_possible

< cpp‎ | thread‎ | stop source
[[nodiscard]] bool stop_possible() const noexcept; | (C++20 起)

检查 stop_source 对象是否拥有停止状态。

参数

（无）

返回值

若 stop_source 对象拥有停止状态则为 true ，否则为 false 。

注解

若 stop_source 对象拥有停止状态且已作出停止请求，则此函数仍返回 true 。

示例

本节未完成
原因：暂无示例


std::stop_source::stop_requested

< cpp‎ | thread‎ | stop source
[[nodiscard]] bool stop_requested() const noexcept; | (C++20 起)

检查 stop_source 对象是否拥有停止状态且该状态已收到停止请求。

参数

（无）

返回值

若 stop_source 对象拥有停止状态且该状态已收到停止请求则为 true ，否则为 false 。

示例

本节未完成
原因：暂无示例


std::stop_source::stop_source

< cpp‎ | thread‎ | stop source
stop_source(); | (1) | (C++20 起)
explicit stop_source( std::nostopstate_t nss ) noexcept; | (2) | (C++20 起)
stop_source( const stop_source& other ) noexcept; | (3) | (C++20 起)
stop_source( stop_source&& other ) noexcept; | (4) | (C++20 起)

构造新的 stop_source 对象。

1) 构造拥有新停止状态的 stop_source 。
2) 构造无关联停止状态的空 stop_source 。
3) 复制构造函数。构造拥有与 other 相同的关联停止状态的 stop_source 。
4) 移动构造函数。构造拥有与 other 相同的关联停止状态的 stop_source ；将 other 设为空。

参数

nss | - | 用于构造空 stop_source 的 std::nostopstate_t 占位对象
other | - | 用于构造此 stop_source 对象的另一 stop_source 对象

后条件

1) stop_possible() 为 true 而 stop_requested() 为 false
2) stop_possible() 与 stop_requested() 均为 false
3) *this 与 other 共享同一关联停止状态且比较相等
4) *this 拥有 other 先前的关联停止状态，而 other.stop_possible() 为 false

异常

1) 若不能为停止状态分配内存则为 std::bad_alloc


std::stop_source::swap

< cpp‎ | thread‎ | stop source
void swap( std::stop_source& other ) noexcept; | (C++20 起)

交换 *this 与 other 的停止状态。

参数

other - 要与之交换内容的 stop_source

返回值

（无）


swap(std::stop_source)

< cpp‎ | thread‎ | stop source
friend void swap( stop_source &lhs, stop_source &rhs ) noexcept; | (C++20 起)

对 std::stop_source 重载 std::swap 算法。交换 lhs 与 rhs 的停止状态。等效地调用 lhs.swap(rhs) 。

此函数对通常无限定或有限定查找不可见，而只能在 std::stop_source 为参数的关联类时由实参依赖查找找到。

参数

lhs, rhs - 要交换的 stop_source

返回值

（无）


std::stop_source::~stop_source

< cpp‎ | thread‎ | stop source
~stop_source(); | (C++20 起)

销毁 stop_source 对象。

若 *this 拥有关联停止状态，则释放其所有权。


std::stop_token

< cpp‎ | thread
定义于头文件 <stop_token> |
class stop_token; | (C++20 起)

stop_token 类提供是否已经或能对其所关联的 std::stop_source 对象作出停止请求的方法。它实质上是关联停止状态的线程安全“视图”。

亦能传递 stop_token 给 std::stop_callback 的构造函数，使得若 stop_token 的关联 std::stop_source 被请求停止则将调用该回调。。而且能传递 stop_token 给 std::condition_variable_any 的可中断等待函数，以便若请求停止则中断该条件变量的等待。

成员函数

(构造函数)
 构造新的 stop_token 对象
(公开成员函数)
(析构函数)
 销毁 stop_token 对象
(公开成员函数)
operator=
 赋值 stop_token 对象
(公开成员函数)
修改器
swap
 交换二个 stop_token 对象
(公开成员函数)
观察器
stop_requested
 检查是否已请求关联停止状态停止
(公开成员函数)
stop_possible
 检查能否请求关联停止状态停止
(公开成员函数)

非成员函数

operator== | 比较二个 std::stop_token 对象 (函数)
swap(std::stop_token) (C++20) | 特化 std::swap 算法 (函数)

注解

一般不会独立构造 stop_token 对象，而是从 std::jthread 或 std::stop_source 取得它。这使它共享与 std::jthread 或 std::stop_source 的相同的关联停止状态。

示例

#include <thread>
#include <iostream>

using namespace std::literals::chrono_literals;

void f(std::stop_token stop_token, int value)
{
    while (!stop_token.stop_requested()) {
        std::cout << value++ << ' ' << std::flush;
        std::this_thread::sleep_for(200ms);
    }
    std::cout << std::endl;
}

int main()
{
    std::jthread thread(f, 5); // 打印 5 6 7 8... 约 3 秒
    std::this_thread::sleep_for(3s);
    // jthread 的析构函数调用 request_stop() 与 join() 。
}

可能的输出：

5 6 7 8 9 10 11 12 13 14 15 16 17 18 19


std::stop_token::operator=

< cpp‎ | thread‎ | stop token
std::stop_token& operator=( const std::stop_token& other ) noexcept; | (1) | (C++20 起)
std::stop_token& operator=( std::stop_token&& other ) noexcept; | (2) | (C++20 起)

以 other 的关联停止状态替换关联停止状态。

1) 复制赋值 other 的关联停止状态给 *this 的。等价于 stop_token(other).swap(*this) 。
2) 移动赋值 other 的关联停止状态给 *this 的。赋值后 *this 含有先前 other 的关联停止状态，而 other 无关联停止状态。等价于 stop_token(std::move(other)).swap(*this) 。

异常

（无）


operator==(std::stop_token)

< cpp‎ | thread‎ | stop token
[[nodiscard]] friend bool operator==( const stop_token& lhs, const stop_token& rhs ) noexcept; | (C++20 起)

比较二个 stop_token 值。

此函数对通常无限定或有限定查找不可见，而只能在 std::stop_token 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

参数

lhs, rhs - 要比较的 stop_token

返回值

若 lhs 与 rhs 拥有同一关联停止状态则为 true ，否则为 false


std::stop_token::stop_possible

< cpp‎ | thread‎ | stop token
[[nodiscard]] bool stop_possible() const noexcept; | (C++20 起)

检查 stop_token 对象是否拥有关联状态，而该状态已被请求停止或拥有关联的 std::stop_source 对象。

默认构造的 stop_token 无关联停止状态，从而不能请求停止；若未作出停止请求，则不存在 std::stop_source 对象的关联停止状态亦不能请求停止。

参数

（无）

返回值

若 stop_token 对象无关联停止状态，或仍未收到停止请求且无关联的 std::stop_source 对象则为 false ；否则为 true 。

注解

若 stop_token 拥有关联停止状态且已作出停止请求，则此函数仍返回 true 。

若 stop_token 对象拥有来自 std::jthread 的关联停止状态——例如 stop_token 是通过在 std::jthread 对象上调用 get_stop_token() 取得的——则此函数始终返回 true 。 std::jthread 始终拥有内部的 std::stop_source 对象，即使该线程的调用函数不检查它。

示例

本节未完成
原因：暂无示例


std::stop_token::stop_requested

< cpp‎ | thread‎ | stop token
[[nodiscard]] bool stop_requested() const noexcept; | (C++20 起)

检查 stop_token 对象是否拥有关联停止状态且该状态已收到停止请求。默认构造的 stop_token 无关联停止状态，从而未有停止请求。

参数

（无）

返回值

若该 stop_token 对象拥有关联停止状态且该状态已收到停止请求则为 true ，否则为 false 。

示例

本节未完成
原因：暂无示例


std::stop_token::stop_token

< cpp‎ | thread‎ | stop token
stop_token() noexcept; | (1) | (C++20 起)
stop_token( const stop_token& other ) noexcept; | (2) | (C++20 起)
stop_token( stop_token&& other ) noexcept; | (3) | (C++20 起)

构造新的 stop_token 对象。

1) 构造无关联停止状态的空 stop_token 。
2) 复制构造函数。构造关联停止状态与 other 相同的 stop_token 。
3) 移动构造函数。构造关联停止状态与 other 相同的 stop_token ；将 other 置于空状态。

参数

other - 用于构造此 stop_token 对象的另一 stop_token 对象

后条件

1) stop_possible() 与 stop_requested() 均为 false
2) *this 与 other 共享同一停止状态且比较相等
3) *this 拥有 other 先前的停止状态，而 other.stop_possible() 为 false


std::stop_token::swap

< cpp‎ | thread‎ | stop token
void swap( std::stop_token& other ) noexcept; | (C++20 起)

交换 *this 与 other 的关联停止状态。

参数

other - 要与之交换内容的 stop_token

返回值

（无）


swap(std::stop_token)

< cpp‎ | thread‎ | stop token
friend void swap( stop_token &lhs, stop_token &rhs ) noexcept; | (C++20 起)

对 std::stop_token 重载 std::swap 算法。交换 lhs 与 rhs 的关联停止状态。等效地调用 lhs.swap(rhs) 。

此函数对通常无限定或有限定查找不可见，而只能在 std::stop_token 为参数的关联类时由实参依赖查找找到。

参数

lhs, rhs - 要交换的 stop_token

返回值

（无）


std::stop_token::~stop_token

< cpp‎ | thread‎ | stop token
~stop_token(); | (C++20 起)

销毁 stop_token 对象。

若 *this 拥有关联停止状态，则释放其所有权。


std::thread

< cpp‎ | thread
定义于头文件 <thread> |
class thread; | (C++11 起)

类 thread 表示单个执行线程。线程允许多个函数同时执行。

线程在构造关联的线程对象时立即开始执行（等待任何OS调度延迟），从提供给作为构造函数参数的顶层函数开始。顶层函数的返回值将被忽略，而且若它以抛异常终止，则调用 std::terminate 。顶层函数可以通过 std::promise 或通过修改共享变量（可能需要同步，见 std::mutex 与 std::atomic ）将其返回值或异常传递给调用方。

std::thread 对象也可能处于不表示任何线程的状态（默认构造、被移动、 detach 或 join 后），并且执行线程可能与任何 thread 对象无关（ detach 后）。

没有两个 std::thread 对象会表示同一执行线程； std::thread 不是可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 的，尽管它可移动构造 (MoveConstructible) 且可移动赋值 (MoveAssignable) 。

成员类型

成员类型 | 定义
native_handle_type (可选) | 实现定义

成员类

id
 表示线程的 id
(公开成员类)

成员函数

(构造函数)
 构造新的 thread 对象
(公开成员函数)
(析构函数)
 析构 thread 对象，必须合并或分离底层线程
(公开成员函数)
operator=
 移动 thread 对象
(公开成员函数)
观察器
joinable
 检查线程是否可合并，即潜在地运行于平行环境中
(公开成员函数)
get_id
 返回线程的 id
(公开成员函数)
native_handle
 返回底层实现定义的线程句柄
(公开成员函数)
hardware_concurrency
[静态]
 返回实现支持的并发线程数
(公开静态成员函数)
操作
join
 等待线程完成其执行
(公开成员函数)
detach
 容许线程从线程句柄独立开来执行
(公开成员函数)
swap
 交换二个 thread 对象
(公开成员函数)

非成员函数

std::swap(std::thread)
(C++11)
 特化 std::swap 算法
(函数)


std::thread::detach

< cpp‎ | thread‎ | thread

void detach(); | (C++11 起)

从 thread 对象分离执行线程，允许执行独立地持续。一旦该线程退出，则释放任何分配的资源。

调用 detach 后 *this 不再占有任何线程。

参数

（无）

返回值

（无）

后条件

joinable 为 false

异常

若 joinable() == false 或出现任何错误则为 std::system_error 。

示例

#include <iostream>
#include <chrono>
#include <thread>

void independentThread()
{
    std::cout << "Starting concurrent thread.\n";
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "Exiting concurrent thread.\n";
}

void threadCaller()
{
    std::cout << "Starting thread caller.\n";
    std::thread t(independentThread);
    t.detach();
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Exiting thread caller.\n";
}

int main()
{
    threadCaller();
    std::this_thread::sleep_for(std::chrono::seconds(5));
}

可能的输出：

Starting thread caller.
Starting concurrent thread.
Exiting thread caller.
Exiting concurrent thread.

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 32.4.2.5 Members [thread.thread.member]
  • C++17 标准（ISO/IEC 14882:2017）：
  • 33.3.2.5 thread members [thread.thread.member]
  • C++14 标准（ISO/IEC 14882:2014）：
  • 30.3.1.5 thread members [thread.thread.member]
  • C++11 标准（ISO/IEC 14882:2011）：
  • 30.3.1.5 thread members [thread.thread.member]

参阅

join | 等待线程完成其执行 (公开成员函数)
joinable | 检查线程是否可合并，即潜在地运行于平行环境中 (公开成员函数)


std::thread::get_id

< cpp‎ | thread‎ | thread

std::thread::id get_id() const noexcept; | (C++11 起)

返回标识与 *this 关联的线程的 std::thread::id 。

参数

（无）

返回值

标识与 *this 关联的线程的 std::thread::id 类型值。若无关联的线程，则返回默认构造的 std::thread::id 。

示例

#include <iostream>
#include <thread>
#include <chrono>

void foo()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    std::thread t1(foo);
    std::thread::id t1_id = t1.get_id();

    std::thread t2(foo);
    std::thread::id t2_id = t2.get_id();

    std::cout << "t1's id: " << t1_id << '\n';
    std::cout << "t2's id: " << t2_id << '\n';

    t1.join();
    t2.join();
}

可能的输出：

t1's id: 0x35a7210f
t2's id: 0x35a311c4

参阅

id | 表示线程的 id (公开成员类)
joinable | 检查线程是否可合并，即潜在地运行于平行环境中 (公开成员函数)


std::thread::hardware_concurrency

< cpp‎ | thread‎ | thread

static unsigned int hardware_concurrency() noexcept; | (C++11 起)

返回实现支持的并发线程数。应该只把该值当做提示。

参数

（无）

返回值

支持的并发线程数。若该值非良定义或不可计算，则返回 ​0​ 。

示例

#include <iostream>
#include <thread>

int main() {
    unsigned int n = std::thread::hardware_concurrency();
    std::cout << n << " concurrent threads are supported.\n";
}

可能的输出：

4 concurrent threads are supported.

参阅

hardware_destructive_interference_sizehardware_constructive_interference_size
(C++17)
 避免假共享的最小偏移
促使真共享的最大偏移
(常量)


std::thread::id

< cpp‎ | thread‎ | thread
定义于头文件 <thread> |
class thread::id; | (C++11 起)

类 thread::id 是轻量的可频繁复制类，它作为 std::thread 对象的唯一标识符工作。

此类的实例亦可保有不表示任何线程的特殊辨别值。一旦线程结束，则 std::thread::id 的值可为另一线程复用。

此类为用作包括有序和无序的关联容器的关键而设计。

成员函数

(构造函数)
 构造不表示线程的 id
(公开成员函数)

非成员函数

operator==operator!=operator< operator<= operator> operator>= operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 比较两个 thread::id 对象 (函数)
operator<< | 序列化 thread::id 对象 (函数模板)

辅助类

std::hash<std::thread::id>
 std::thread::id 的哈希支持
(类模板特化)

参阅

get_id | 返回线程的 id (公开成员函数)
get_id (C++11) | 返回当前线程的线程 id (函数)


std::hash<std::thread::id>

< cpp‎ | thread‎ | thread‎ | id
定义于头文件 <thread> |
template<> struct hash< std::thread::id >; | (C++11 起)

std::hash 对 std::thread::id 类的模板特化允许用户获得线程标识符的哈希。

示例

本节未完成
原因：有意义地使用哈希的示例
#include <iostream>
#include <thread>
#include <chrono>
#include <vector>
using namespace std::chrono_literals;
void foo()
{
    std::this_thread::sleep_for(10ms);
}

int main()
{
    std::vector<std::thread> v;
    for(int n = 0; n < 4; ++n)
        v.emplace_back(foo);

    std::hash<std::thread::id> hasher;
    for(auto& t : v) {
        std::cout << "thread " << t.get_id() << " hashes to " << hasher(t.get_id()) << '\n';
        t.join();
    }
}

可能的输出：

thread 139786440144640 hashes to 8905351942358389397
thread 139786431751936 hashes to 9222844670065909738
thread 139786423359232 hashes to 18199000599186780501
thread 139786414966528 hashes to 15386662774029264672

参阅

hash
(C++11)
 散列函数对象
(类模板)


std::thread::id::id

< cpp‎ | thread‎ | thread‎ | id
id() noexcept; | (C++11 起)

默认构造新的线程标识符。标识符不代表线程。

参数

（无）


operator==,!=,<,<=,>,>=,<=>(std::thread::id)

< cpp‎ | thread‎ | thread‎ | id
定义于头文件 <thread>
bool operator==( std::thread::id lhs, std::thread::id rhs ) noexcept;
 (1) (C++11 起)
bool operator!=( std::thread::id lhs, std::thread::id rhs ) noexcept;
 (2) (C++11 起)
(C++20 前)
bool operator< ( std::thread::id lhs, std::thread::id rhs ) noexcept;
 (3) (C++11 起)
(C++20 前)
bool operator<=( std::thread::id lhs, std::thread::id rhs ) noexcept;
 (4) (C++11 起)
(C++20 前)
bool operator> ( std::thread::id lhs, std::thread::id rhs ) noexcept;
 (5) (C++11 起)
(C++20 前)
bool operator>=( std::thread::id lhs, std::thread::id rhs ) noexcept;
 (6) (C++11 起)
(C++20 前)
std::strong_ordering operator<=>( std::thread::id lhs,
std::thread::id rhs ) noexcept;
 (7) (C++20 起)

比较二个线程标识符。

1-2) 检查 lhs 与 rhs 是否表示同一线程或均不表示线程。
3-7) 以未指明的全序比较 lhs 与 rhs 。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

参数

lhs, rhs - 要比较的线程标识符

返回值

1-6) 若对应关系成立则为 true ，否则为 false 。
7) 若在该全序中 lhs 小于 rhs 则为 std::strong_ordering::less ；否则若在该全序中 rhs 小于 lhs 则为 std::strong_ordering::greater ；否则为 std::strong_ordering::equal 。

复杂度

常数。

参阅


operator<<(std::thread::id)

< cpp‎ | thread‎ | thread‎ | id
定义于头文件 <thread>
template< class CharT, class Traits >

std::basic_ostream <CharT,Traits>&

operator<<( std::basic_ostream <CharT,Traits>& ost, thread::id id );
 (C++11 起)

写线程标识符 id 的文本表示到输出流 ost 。

若二个线程标识符表示相等，则它们拥有等同的文本表示；若它们比较不相等，则其表示有别。

参数

ost | - | 要插入数据的输出流
id | - | 线程标识符

返回值

ost

异常

可能抛出实现定义的异常。


std::thread::join

< cpp‎ | thread‎ | thread

void join(); | (C++11 起)

阻塞当前线程直至 *this 所标识的线程结束其执行。

*this 所标识的线程的完成同步于对应的从 join() 成功返回。

*this 自身上不进行同步。同时从多个线程在同一 thread 对象上调用 join() 构成数据竞争，导致未定义行为。

参数

（无）

返回值

（无）

后条件

joinable() 为 false

异常

若出现错误则为 std::system_error 。

错误条件

  • 若 this->get_id() == std::this_thread::get_id () （检测到死锁）则为 resource_deadlock_would_occur
  • 若线程非法则为 no_such_process
  • 若 joinable() 为 false 则为 invalid_argument

示例

#include <iostream>
#include <thread>
#include <chrono>

void foo()
{
    // 模拟耗费大量资源的操作
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

void bar()
{
    // 模拟耗费大量资源的操作
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    std::cout << "starting first helper...\n";
    std::thread helper1(foo);

    std::cout << "starting second helper...\n";
    std::thread helper2(bar);

    std::cout << "waiting for helpers to finish..." << std::endl;
    helper1.join();
    helper2.join();

    std::cout << "done!\n";
}

输出：

starting first helper...
starting second helper...
waiting for helpers to finish...
done!

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 32.4.2.5 Members [thread.thread.member]
  • C++17 标准（ISO/IEC 14882:2017）：
  • 33.3.2.5 thread members [thread.thread.member]
  • C++14 标准（ISO/IEC 14882:2014）：
  • 30.3.1.5 thread members [thread.thread.member]
  • C++11 标准（ISO/IEC 14882:2011）：
  • 30.3.1.5 thread members [thread.thread.member]

参阅

detach | 容许线程从线程句柄独立开来执行 (公开成员函数)
joinable | 检查线程是否可合并，即潜在地运行于平行环境中 (公开成员函数)


std::thread::joinable

< cpp‎ | thread‎ | thread

bool joinable() const noexcept; | (C++11 起)

检查 std::thread 对象是否标识活跃的执行线程。具体而言，若 get_id() != std::thread::id () 则返回 true 。故默认构造的 thread 不可结合。

结束执行代码，但仍未结合的线程仍被当作活跃的执行线程，从而可结合。

参数

（无）

返回值

若 thread 对象标识活跃的执行线程则为 true ，否则为 false 。

示例

#include <iostream>
#include <thread>
#include <chrono>

void foo()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    std::thread t;
    std::cout << "before starting, joinable: " << std::boolalpha << t.joinable()
              << '\n';

    t = std::thread(foo);
    std::cout << "after starting, joinable: " << t.joinable()
              << '\n';

    t.join();
    std::cout << "after joining, joinable: " << t.joinable()
              << '\n';
}

输出：

before starting, joinable: false
after starting, joinable: true
after joining, joinable: false

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 32.4.2.5 Members [thread.thread.member]
  • C++17 标准（ISO/IEC 14882:2017）：
  • 33.3.2.5 thread members [thread.thread.member]
  • C++14 标准（ISO/IEC 14882:2014）：
  • 30.3.1.5 thread members [thread.thread.member]
  • C++11 标准（ISO/IEC 14882:2011）：
  • 30.3.1.5 thread members [thread.thread.member]

参阅

get_id | 返回线程的 id (公开成员函数)
join | 等待线程完成其执行 (公开成员函数)
detach | 容许线程从线程句柄独立开来执行 (公开成员函数)


std::thread::native_handle

< cpp‎ | thread‎ | thread

native_handle_type native_handle(); | (C++11 起) (可选)

返回实现定义的底层线程柄。

参数

（无）

返回值

表示线程的实现定义柄类型。

异常

可能抛出实现定义的异常。

示例

在 POSIX 系统上用 native_handle 启用 C++ 线程的实时调度

#include <thread>
#include <mutex>
#include <iostream>
#include <chrono>
#include <cstring>
#include <pthread.h>

std::mutex iomutex;
void f(int num)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));

    sched_param sch;
    int policy;
    pthread_getschedparam(pthread_self(), &policy, &sch);
    std::lock_guard<std::mutex> lk(iomutex);
    std::cout << "Thread " << num << " is executing at priority "
              << sch.sched_priority << '\n';
}

int main()
{
    std::thread t1(f, 1), t2(f, 2);

    sched_param sch;
    int policy;
    pthread_getschedparam(t1.native_handle(), &policy, &sch);
    sch.sched_priority = 20;
    if (pthread_setschedparam(t1.native_handle(), SCHED_FIFO, &sch)) {
        std::cout << "Failed to setschedparam: " << std::strerror(errno) << '\n';
    }

    t1.join(); t2.join();
}

输出：

Thread 2 is executing at priority 0
Thread 1 is executing at priority 20


std::thread::operator=

< cpp‎ | thread‎ | thread
thread& operator=( thread&& other ) noexcept; | (C++11 起)

若 *this 仍拥有关联的运行中进程（即 joinable() == true ），则调用 std::terminate () 。否则，赋值 other 的状态给 *this 并设置 other 为默认构造的状态。

此调用后， this->get_id() 等于 other.get_id() 在调用前的值，而 other 不再表示执行的线程。

参数

other - 赋值给此 thread 对象的另一 thread 对象

返回值

*this


std::thread::swap

< cpp‎ | thread‎ | thread

void swap( std::thread & other ) noexcept; | (C++11 起)

交换二个 thread 对象的底层柄。

参数

other - 要与之交换的 thread

返回值

（无）

示例

#include <iostream>
#include <thread>
#include <chrono>

void foo()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

void bar()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    std::thread t1(foo);
    std::thread t2(bar);

    std::cout << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';

    std::swap(t1, t2);

    std::cout << "after std::swap(t1, t2):" << '\n'
              << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';

    t1.swap(t2);

    std::cout << "after t1.swap(t2):" << '\n'
              << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';

    t1.join();
    t2.join();
}

可能的输出：

thread 1 id: 140185268262656
thread 2 id: 140185259869952
after std::swap(t1, t2):
thread 1 id: 140185259869952
thread 2 id: 140185268262656
after t1.swap(t2):
thread 1 id: 140185268262656
thread 2 id: 140185259869952

参阅

std::swap(std::thread)
(C++11)
 特化 std::swap 算法
(函数)


std::swap(std::thread)

< cpp‎ | thread‎ | thread

void swap( std::thread &lhs, std::thread &rhs ) noexcept; | (C++11 起)

对 std::thread 重载 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的 thread

返回值

（无）

示例

#include <iostream>
#include <thread>
#include <chrono>

void foo()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

void bar()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    using std::swap;

    std::thread t1(foo);
    std::thread t2(bar);

    std::cout << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';

    swap(t1, t2);

    std::cout << "after std::swap(t1, t2):" << '\n'
              << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';

    t1.swap(t2);

    std::cout << "after t1.swap(t2):" << '\n'
              << "thread 1 id: " << t1.get_id() << '\n'
              << "thread 2 id: " << t2.get_id() << '\n';

    t1.join();
    t2.join();
}

可能的输出：

thread 1 id: 1892
thread 2 id: 2584
after std::swap(t1, t2):
thread 1 id: 2584
thread 2 id: 1892
after t1.swap(t2):
thread 1 id: 1892
thread 2 id: 2584

参阅

swap
 交换二个 thread 对象
(公开成员函数)


std::thread::thread

< cpp‎ | thread‎ | thread
thread() noexcept; | (1) | (C++11 起)
thread( thread&& other ) noexcept; | (2) | (C++11 起)
template< class Function, class... Args > explicit thread( Function&& f, Args&&... args ); | (3) | (C++11 起)
thread( const thread& ) = delete; | (4) | (C++11 起)

构造新的 thread 对象。

1) 构造不表示线程的新 thread 对象。
2) 移动构造函数。构造表示曾为 other 所表示的执行线程的 thread 对象。此调用后 other 不再表示执行线程。
3) 构造新的 std::thread 对象并将它与执行线程关联。新的执行线程开始执行 /*INVOKE*/(std::move(f_copy), std::move(args_copy)...) ，其中
  • /*INVOKE*/ 进行可调用 (Callable) 中指定的 INVOKE 操作，这能由 std::invoke 进行 (C++17 起)，而
  • f_copy 是类型为 std::decay <Function>::type 并从 std::forward <Function>(f) 构造的对象，而
  • args_copy... 是类型为 std::decay <Args>::type... 并从 std::forward <Args>(args)... 构造的对象。
这些对象的构造在调用方的环境执行，故而任何求值和复制/移动参数中抛出的异常被抛到当前线程，而不会开始新线程。若任何构造或 INVOKE 操作非法则程序非良构。
若 std::decay <Function>::type 与 thread 为同一类型，则此构造函数不参与重载决议。
构造函数的调用完成同步于（定义于 std::memory_order ）新的执行线程上 f 副本的调用开始。
4) 复制构造函数被删除； thread 不可复制。没有二个 std::thread 对象可表示同一执行线程。

参数

other | - | 用以构造此 thread 的另一 thread 对象
f | - | 执行于新线程的可调用 (Callable)
args... | - | 传递给新函数的参数

后条件

1) get_id() 等于 std::thread::id() （即 joinable 为 false ）
2) other.get_id() 等于 std::thread::id() 而 get_id() 返回构造开始前 other.get_id() 的值
3) get_id() 不等于 std::thread::id() （即 joinable 为 true ）

异常

3) 若不能开始线程则抛出 std::system_error 。异常可能表示错误条件 std::errc::resource_unavailable_try_again 或另一实现限定的错误条件。

注解

移动或按值复制线程函数的参数。若需要传递引用参数给线程函数，则必须包装它（例如用 std::ref 或 std::cref ）。

忽略来自函数的任何返回值。若函数抛异常，则调用 std::terminate 。为将返回值或异常传递回调用方线程，可使用 std::promise 或 std::async 。

示例

#include <iostream>
#include <utility>
#include <thread>
#include <chrono>

void f1(int n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 1 executing\n";
        ++n;
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}

void f2(int& n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 2 executing\n";
        ++n;
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}

class foo
{
public:
    void bar()
    {
        for (int i = 0; i < 5; ++i) {
            std::cout << "Thread 3 executing\n";
            ++n;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
    int n = 0;
};

class baz
{
public:
    void operator()()
    {
        for (int i = 0; i < 5; ++i) {
            std::cout << "Thread 4 executing\n";
            ++n;
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
    int n = 0;
};

int main()
{
    int n = 0;
    foo f;
    baz b;
    std::thread t1; // t1 不是线程
    std::thread t2(f1, n + 1); // 按值传递
    std::thread t3(f2, std::ref(n)); // 按引用传递
    std::thread t4(std::move(t3)); // t4 现在运行 f2() 。 t3 不再是线程
    std::thread t5(&foo::bar, &f); // t5 在对象 f 上运行 foo::bar()
    std::thread t6(b); // t6 在对象 b 的副本上运行 baz::operator()
    t2.join();
    t4.join();
    t5.join();
    t6.join();
    std::cout << "Final value of n is " << n << '\n';
    std::cout << "Final value of f.n (foo::n) is " << f.n << '\n';
    std::cout << "Final value of b.n (baz::n) is " << b.n << '\n';
}

可能的输出：

Thread 1 executing
Thread 2 executing
Thread 3 executing
Thread 4 executing
Thread 3 executing
Thread 1 executing
Thread 2 executing
Thread 4 executing
Thread 2 executing
Thread 3 executing
Thread 1 executing
Thread 4 executing
Thread 3 executing
Thread 2 executing
Thread 1 executing
Thread 4 executing
Thread 3 executing
Thread 1 executing
Thread 2 executing
Thread 4 executing
Final value of n is 5
Final value of f.n (foo::n) is 5
Final value of b.n (baz::n) is 0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2097 | C++11 | 接收一个可调用 (Callable) 对象的构造函数可能与移动构造函数有歧义 | 已约束

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 32.4.2.2 thread constructors [thread.thread.constr]
  • C++17 标准（ISO/IEC 14882:2017）：
  • 33.3.2.2 thread constructors [thread.thread.constr]
  • C++14 标准（ISO/IEC 14882:2014）：
  • 30.3.1.2 thread constructors [thread.thread.constr]
  • C++11 标准（ISO/IEC 14882:2011）：
  • 30.3.1.2 thread constructors [thread.thread.constr]

参阅

(构造函数)
 创建新的 jthread 对象
(std::jthread 的公开成员函数)


std::thread::~thread

< cpp‎ | thread‎ | thread
~thread(); | (C++11 起)

销毁 thread 对象。

若 *this 拥有关联线程（ joinable() == true ），则调用 std::terminate () 。

注解

在下列操作后 thread 对象无关联的线程（从而可安全销毁）

  • 被默认构造
  • 被移动
  • 已调用 join()
  • 已调用 detach()


std::timed_mutex

< cpp‎ | thread
定义于头文件 <mutex> |
class timed_mutex; | (C++11 起)

timed_mutex 类是能用于保护数据免受多个线程同时访问的同步原语。

以类似 mutex 的行为， timed_mutex 提供排他性非递归所有权语义。另外， timed_mutex 提供通过 try_lock_for() 和 try_lock_until() 方法试图带时限地要求 timed_mutex 所有权的能力。

timed_mutex 类满足定时互斥体 (TimedMutex) 与标准布局类型 (StandardLayoutType) 的所有要求。

成员类型

成员类型 | 定义
native_handle_type(可选) | 实现定义

成员函数

(构造函数)
 构造互斥
(公开成员函数)
(析构函数)
 销毁互斥
(公开成员函数)
operator=
[被删除]
 不可复制赋值
(公开成员函数)
锁定
lock
 锁定互斥，若互斥不可用则阻塞
(公开成员函数)
try_lock
 尝试锁定互斥，若互斥不可用则返回
(公开成员函数)
try_lock_for
 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回
(公开成员函数)
try_lock_until
 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回
(公开成员函数)
unlock
 解锁互斥
(公开成员函数)
原生句柄
native_handle
 返回底层实现定义的原生句柄
(公开成员函数)


std::timed_mutex::lock

< cpp‎ | thread‎ | timed mutex

void lock(); | (C++11 起)

锁定互斥。若另一线程已锁定互斥，则到 lock 的调用将阻塞执行，直至获得锁。

若 lock 为已占有 mutex 的线程调用，则行为未定义：例如，程序可能死锁。鼓励能检测非法使用的实现抛出以 resource_deadlock_would_occur 为错误条件的 std::system_error ，而不是死锁。

同一互斥上先前的 unlock() 操作同步于（定义于 std::memory_order ）此操作。

参数

（无）

返回值

（无）

异常

错误发生时抛出 std::system_error ，包括底层操作系统阻止 lock 满足其规定的错误。在抛出任何异常的情况下，不锁定互斥。

注意

通常不直接调用 lock() ：用 std::unique_lock 与 std::lock_guard 管理排他性锁定。

示例

此示例演示 lock 与 unlock 能如何用于保护共享数据。

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>

int g_num = 0;  // 为 g_num_mutex 所保护
std::mutex g_num_mutex;

void slow_increment(int id)
{
    for (int i = 0; i < 3; ++i) {
        g_num_mutex.lock();
        ++g_num;
        std::cout << id << " => " << g_num << '\n';
        g_num_mutex.unlock();

        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main()
{
    std::thread t1(slow_increment, 0);
    std::thread t2(slow_increment, 1);
    t1.join();
    t2.join();
}

可能的输出：

0 => 1
1 => 2
0 => 3
1 => 4
0 => 5
1 => 6

参阅

try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
try_lock_for | 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回 (公开成员函数)
try_lock_until | 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::timed_mutex::native_handle

< cpp‎ | thread‎ | timed mutex

native_handle_type native_handle(); | (C++11 起) (可选)

返回底层实现定义的原生句柄对象。

参数

（无）

返回值

实现定义的原生句柄对象。

异常

实现定义。

示例

本节未完成
原因：暂无示例


std::timed_mutex::timed_mutex

< cpp‎ | thread‎ | timed mutex

timed_mutex(); | (1) | (C++11 起)
timed_mutex( const timed_mutex& ) = delete; | (2) | (C++11 起)
1) 构造互斥。调用后互斥在未锁定状态。
2) 复制构造函数被删除。

参数

（无）

异常

若构造不成功则抛出 std::system_error 。

参阅


std::timed_mutex::try_lock

< cpp‎ | thread‎ | timed mutex

bool try_lock(); | (C++11 起)

尝试锁定互斥。立即返回。成功获得锁时返回 true ，否则返回 false 。

允许此函数虚假地失败而返回 false ，即使互斥当前未为任何其他线程所锁定。

若已占有 mutex 的线程调用 try_lock ，则行为未定义。

若此操作返回 true ，则同一互斥上的先前 unlock() 操作同步于（定义于 std::memory_order ）它。注意若此操作返回 false ，则先前的 lock() 不与之同步。

参数

（无）

返回值

若成功取得锁则为 true ，否则为 false 。

异常

不抛出。

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock_for | 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回 (公开成员函数)
try_lock_until | 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::timed_mutex::try_lock_for

< cpp‎ | thread‎ | timed mutex

template< class Rep, class Period > bool try_lock_for( const std::chrono::duration <Rep,Period>& timeout_duration ); | (C++11 起)

尝试锁互斥。阻塞直到经过指定的 timeout_duration 或得到锁，取决于何者先到来。成功获得锁时返回 true ， 否则返回 false 。

若 timeout_duration 小于或等于 timeout_duration.zero() ，则函数表现同 try_lock() 。

由于调度或资源争议延迟，此函数可能阻塞长于 timeout_duration 。

标准推荐用 steady_clock 度量时长。若实现用 system_clock 代替，则等待时间亦可能对时钟调整敏感。

同 try_lock() ，允许此函数虚假地失败并返回 false ，即使在 timeout_duration 中某点互斥不为任何线程所锁定。

若此操作返回 true ，则同一互斥上先前的 unlock() 调用同步于（定义于 std::memory_order ）它。

若已占有 mutex 的线程调用 try_lock_for ，则行为未定义。

参数

timeout_duration - 要阻塞的最大时长

返回值

若成功获得锁则为 true ，否则为 false 。

异常

执行期间时钟、时间点或时长可能抛出的异常（标准库提供的时钟、时间点和时长决不抛出）

示例

#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
#include <sstream>

std::mutex cout_mutex; // 控制到 std::cout 的访问
std::timed_mutex mutex;

void job(int id)
{
    using Ms = std::chrono::milliseconds;
    std::ostringstream stream;

    for (int i = 0; i < 3; ++i) {
        if (mutex.try_lock_for(Ms(100))) {
            stream << "success ";
            std::this_thread::sleep_for(Ms(100));
            mutex.unlock();
        } else {
            stream << "failed ";
        }
        std::this_thread::sleep_for(Ms(100));
    }

    std::lock_guard<std::mutex> lock(cout_mutex);
    std::cout << "[" << id << "] " << stream.str() << "\n";
}

int main()
{
    std::vector<std::thread> threads;
    for (int i = 0; i < 4; ++i) {
        threads.emplace_back(job, i);
    }

    for (auto& i: threads) {
        i.join();
    }
}

可能的输出：

[0] failed failed failed
[3] failed failed success
[2] failed success failed
[1] success failed success

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
try_lock_until | 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::timed_mutex::try_lock_until

< cpp‎ | thread‎ | timed mutex

template< class Clock, class Duration > bool try_lock_until( const std::chrono::time_point <Clock,Duration>& timeout_time ); | (C++11 起)

尝试所互斥。阻塞直至抵达指定的 timeout_time 或得到锁，取决于何者先到来。成功获得锁时返回 true ，否则返回 false 。

若已经过 timeout_time ，则此函数表现同 try_lock() 。

Clock 必须符合时钟 (Clock) 要求。若 std::chrono::is_clock_v<Clock> 为 false 则程序为非良构。 (C++20 起)

标准推荐使用绑定到 timeout_time 的时钟，该情况下可以计入时钟的调整。从而在调用时刻，阻塞的时长可以，但也可以不，小于或大于 timeout_time - Clock::now() 。这取决于调整的方向以及实现是否尊重它。函数亦可能由于调度或资源纠纷延迟，而阻塞长于到抵达 timeout_time 之后。

同 try_lock() ，允许此函数虚假地失败并返回 false ，即使在 timeout_time 前的某点任何线程都不锁定互斥。

若此操作返回 true ，则同一互斥上先前的 unlock() 调用同步于（定义于 std::memory_order ）它。

若已占有 mutex 的线程调用 try_lock_until ，则行为未定义。

参数

timeout_time - 要阻塞到的最大时间点

返回值

若成功获得锁则为 true ，否则为 false 。

异常

执行期间时钟、时间点或时长可能抛出的异常（标准库提供的时钟、时间点和时长决不抛出）

示例

此示例展示 10 秒的阻塞

#include <thread>
#include <iostream>
#include <chrono>
#include <mutex>

std::timed_mutex test_mutex;

void f()
{
    auto now=std::chrono::steady_clock::now();
    test_mutex.try_lock_until(now + std::chrono::seconds(10));
    std::cout << "hello world\n";
}

int main()
{
    std::lock_guard<std::timed_mutex> l(test_mutex);
    std::thread t(f);
    t.join();
}

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
try_lock_for | 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回 (公开成员函数)
unlock | 解锁互斥 (公开成员函数)


std::timed_mutex::unlock

< cpp‎ | thread‎ | timed mutex

void unlock(); | (C++11 起)

解锁互斥。

互斥必须为当前执行线程所锁定，否则行为未定义。

此操作同步于（定义于 std::memory_order ）任何后继的取得同一互斥所有权的锁操作。

参数

（无）

返回值

（无）

异常

不抛出。

注解

通常不直接调用 unlock() ：用 std::unique_lock 与 std::lock_guard 管理互斥锁定。

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定互斥，若互斥不可用则阻塞 (公开成员函数)
try_lock | 尝试锁定互斥，若互斥不可用则返回 (公开成员函数)
try_lock_for | 尝试锁定互斥，若互斥在指定的时限时期中不可用则返回 (公开成员函数)
try_lock_until | 尝试锁定互斥，若直至抵达指定时间点互斥不可用则返回 (公开成员函数)


std::timed_mutex::~timed_mutex

< cpp‎ | thread‎ | timed mutex

~timed_mutex();

销毁互斥。

若互斥为任何线程占有，或若任何线程在保有任何互斥的所有权时终止，则行为未定义。

参阅


std::try_lock

< cpp‎ | thread
定义于头文件 <mutex> |
template< class Lockable1, class Lockable2, class... LockableN > int try_lock( Lockable1& lock1, Lockable2& lock2, LockableN&... lockn ); | (C++11 起)

尝试锁定每个给定的可锁定 (Lockable) 对象 lock1、 lock2、 ...、 lockn ，通过以从头开始的顺序调用 try_lock 。

若调用 try_lock 失败，则不再进一步调用 try_lock ，并对任何已锁对象调用 unlock ，返回锁定失败对象的 0 底下标。

若调用 try_lock 抛出异常，则在重抛前对任何已锁对象调用 unlock 。

参数

lock1, lock2, ... , lockn - 要锁定的可锁定 (Lockable) 对象

返回值

成功时为 -1 ，否则为锁定失败对象的 0 底下标值。

示例

下列示例用 std::try_lock 周期地记录并重置运行于分离线程的计数器。

#include <mutex>
#include <vector>
#include <thread>
#include <iostream>
#include <functional>
#include <chrono>

int main()
{
    int foo_count = 0;
    std::mutex foo_count_mutex;
    int bar_count = 0;
    std::mutex bar_count_mutex;
    int overall_count = 0;
    bool done = false;
    std::mutex done_mutex;

    auto increment = [](int &counter, std::mutex &m,  const char *desc) {
        for (int i = 0; i < 10; ++i) {
            std::unique_lock<std::mutex> lock(m);
            ++counter;
            std::cout << desc << ": " << counter << '\n';
            lock.unlock();
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    };

    std::thread increment_foo(increment, std::ref(foo_count),
        std::ref(foo_count_mutex), "foo");
    std::thread increment_bar(increment, std::ref(bar_count),
        std::ref(bar_count_mutex), "bar");

    std::thread update_overall([&]() {
        done_mutex.lock();
        while (!done) {
            done_mutex.unlock();
            int result = std::try_lock(foo_count_mutex, bar_count_mutex);
            if (result == -1) {
                overall_count += foo_count + bar_count;
                foo_count = 0;
                bar_count = 0;
                std::cout << "overall: " << overall_count << '\n';
                foo_count_mutex.unlock();
                bar_count_mutex.unlock();
            }
            std::this_thread::sleep_for(std::chrono::seconds(2));
            done_mutex.lock();
        }
        done_mutex.unlock();
    });

    increment_foo.join();
    increment_bar.join();
    done_mutex.lock();
    done = true;
    done_mutex.unlock();
    update_overall.join();

    std::cout << "Done processing\n"
              << "foo: " << foo_count << '\n'
              << "bar: " << bar_count << '\n'
              << "overall: " << overall_count << '\n';
}

可能的输出：

bar: 1
foo: 1
foo: 2
bar: 2
foo: 3
overall: 5
bar: 1
foo: 1
bar: 2
foo: 2
bar: 3
overall: 10
bar: 1
foo: 1
bar: 2
foo: 2
overall: 14
bar: 1
foo: 1
bar: 2
overall: 17
foo: 1
bar: 1
foo: 2
overall: 20
Done processing
foo: 0
bar: 0
overall: 20

参阅

lock
(C++11)
 锁定指定的互斥体，若任何一个不可用则阻塞
(函数模板)


std::unique_lock

< cpp‎ | thread
定义于头文件 <mutex> |
template< class Mutex > class unique_lock; | (C++11 起)

类 unique_lock 是通用互斥包装器，允许延迟锁定、锁定的有时限尝试、递归锁定、所有权转移和与条件变量一同使用。

类 unique_lock 可移动，但不可复制——它满足可移动构造 (MoveConstructible) 和可移动赋值 (MoveAssignable) 但不满足可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 。

类 unique_lock 满足基本可锁定 (BasicLockable) 要求。若 Mutex 满足可锁定 (Lockable) 要求，则 unique_lock 亦满足可锁定 (Lockable) 要求（例如：能用于 std::lock ） ；若 Mutex 满足可定时锁定 (TimedLockable) 要求，则 unique_lock 亦满足可定时锁定 (TimedLockable) 要求。

模板形参

Mutex - 要锁定的互斥类型。类型必须满足基本可锁定 (BasicLockable) 要求

成员类型

类型 | 定义
mutex_type | Mutex

成员函数

(构造函数)
 构造 unique_lock ，可选地锁定提供的互斥
(公开成员函数)
(析构函数)
 若占有关联互斥，则解锁之
(公开成员函数)
operator=
 若占有则解锁互斥，并取得另一者的所有权
(公开成员函数)
锁定
lock
 锁定关联互斥
(公开成员函数)
try_lock
 尝试锁定关联互斥，若互斥不可用则返回
(公开成员函数)
try_lock_for
 试图锁定关联的可定时锁定 (TimedLockable) 互斥，若互斥在给定时长中不可用则返回
(公开成员函数)
try_lock_until
 尝试锁定关联可定时锁定 (TimedLockable) 互斥，若抵达指定时间点互斥仍不可用则返回
(公开成员函数)
unlock
 解锁关联互斥
(公开成员函数)
修改器
swap
 与另一 std::unique_lock 交换状态
(公开成员函数)
release
 将关联互斥解关联而不解锁它
(公开成员函数)
观察器
mutex
 返回指向关联互斥的指针
(公开成员函数)
owns_lock
 测试锁是否占有其关联互斥
(公开成员函数)
operator bool
 测试锁是否占有其关联互斥
(公开成员函数)

非成员函数

std::swap(std::unique_lock)
(C++11)
 std::swap 对 unique_lock 的特化
(函数模板)

示例

#include <mutex>
#include <thread>
#include <chrono>

struct Box {
    explicit Box(int num) : num_things{num} {}

    int num_things;
    std::mutex m;
};

void transfer(Box &from, Box &to, int num)
{
    // 仍未实际取锁
    std::unique_lock<std::mutex> lock1(from.m, std::defer_lock);
    std::unique_lock<std::mutex> lock2(to.m, std::defer_lock);

    // 锁两个 unique_lock 而不死锁
    std::lock(lock1, lock2);

    from.num_things -= num;
    to.num_things += num;

    // 'from.m' 与 'to.m' 互斥解锁于 'unique_lock' 析构函数
}

int main()
{
    Box acc1(100);
    Box acc2(50);

    std::thread t1(transfer, std::ref(acc1), std::ref(acc2), 10);
    std::thread t2(transfer, std::ref(acc2), std::ref(acc1), 5);

    t1.join();
    t2.join();
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2981 | C++17 | 曾提供来自 unique_lock<Mutex> 的冗余推导指引 | 已移除

参阅

lock_guard (C++11) | 实现严格基于作用域的互斥体所有权包装器 (类模板)
scoped_lock (C++17) | 用于多个互斥体的免死锁 RAII 封装器 (类模板)


std::unique_lock<Mutex>::lock

< cpp‎ | thread‎ | unique lock
void lock(); | (C++11 起)

锁定关联互斥。等效地调用 mutex()->lock() 。

参数

（无）

返回值

（无）

异常

  • 任何 mutex()->lock() 所抛的异常
  • 若无关联互斥，则为以 std::errc::operation_not_permitted 为错误码的 std::system_error
  • 若关联互斥已为此 unique_lock 所锁定（换言之， owns_lock 为 true ），则为以 std::errc::resource_deadlock_would_occur 为错误码的 std::system_error

示例

下列示例用 lock 重获得被解锁的互斥。

#include <mutex>
#include <thread>
#include <iostream>
#include <vector>
#include <chrono>

int main()
{
    int counter = 0;
    std::mutex counter_mutex;
    std::vector<std::thread> threads;

    auto worker_task = [&](int id) {
        std::unique_lock<std::mutex> lock(counter_mutex);
        ++counter;
        std::cout << id << ", initial counter: " << counter << '\n';
        lock.unlock();

        // 我们模拟昂贵操作时不保有锁
        std::this_thread::sleep_for(std::chrono::seconds(1));

        lock.lock();
        ++counter;
        std::cout << id << ", final counter: " << counter << '\n';
    };

    for (int i = 0; i < 10; ++i) threads.emplace_back(worker_task, i);

    for (auto &thread : threads) thread.join();
}

可能的输出：

0, initial counter: 1
1, initial counter: 2
2, initial counter: 3
3, initial counter: 4
4, initial counter: 5
5, initial counter: 6
6, initial counter: 7
7, initial counter: 8
8, initial counter: 9
9, initial counter: 10
6, final counter: 11
3, final counter: 12
4, final counter: 13
2, final counter: 14
5, final counter: 15
0, final counter: 16
1, final counter: 17
7, final counter: 18
9, final counter: 19
8, final counter: 20

参阅

try_lock | 尝试锁定关联互斥，若互斥不可用则返回 (公开成员函数)
unlock | 解锁关联互斥 (公开成员函数)


std::unique_lock<Mutex>::mutex

< cpp‎ | thread‎ | unique lock
mutex_type* mutex() const noexcept; | (C++11 起)

返回指向关联互斥的指针，或若无关联互斥则返回空指针。

参数

（无）

返回值

指向关联互斥的指针，或若无关联互斥则为空指针。

示例

本节未完成
原因：暂无示例


std::unique_lock<Mutex>::operator=

< cpp‎ | thread‎ | unique lock
unique_lock& operator=( unique_lock&& other ); | (C++11 起)

移动赋值运算符。用移动语义以 other 的内容替换内容。

若调用前 *this 拥有关联互斥并获得其所有权，则解锁互斥。

参数

other - 以之替换状态的另一 unique_lock

返回值

*this

异常

不抛出


std::unique_lock<Mutex>::operator bool

< cpp‎ | thread‎ | unique lock
explicit operator bool() const noexcept; | (C++11 起)

检查 *this 是否占有锁定的互斥。等效地调用 owns_lock() 。

参数

（无）

返回值

若 *this 拥有关联互斥且已获得其所有权则为 true ，否则为 false 。

参阅

owns_lock
 测试锁是否占有其关联互斥
(公开成员函数)


std::unique_lock<Mutex>::owns_lock

< cpp‎ | thread‎ | unique lock
bool owns_lock() const noexcept; | (C++11 起)

检查 *this 是否占有锁定的互斥。

参数

（无）

返回值

若 *this 拥有关联互斥且已获得其所有权则为 true ，否则为 false 。

参阅

operator bool
 测试锁是否占有其关联互斥
(公开成员函数)


std::unique_lock<Mutex>::release

< cpp‎ | thread‎ | unique lock
mutex_type* release() noexcept; | (C++11 起)

打断关联互斥与 *this 的关联，若存在。

不锁定互斥。若 *this 在调用前曾保有关联互斥的所有权，则现在是调用方负责解锁互斥。

参数

（无）

返回值

指向关联互斥体的指针或若无关联互斥体则为空指针。

示例

本节未完成
原因：暂无示例

参阅

unlock
 解锁关联互斥
(公开成员函数)


std::unique_lock<Mutex>::swap

< cpp‎ | thread‎ | unique lock
void swap( unique_lock& other ) noexcept; | (C++11 起)

交换锁对象的内部状态。

参数

other - 要交换状态的锁

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

std::swap(std::unique_lock)
(C++11)
 std::swap 对 unique_lock 的特化
(函数模板)


std::swap(std::unique_lock)

< cpp‎ | thread‎ | unique lock
template< class Mutex > void swap( unique_lock<Mutex>& lhs, unique_lock<Mutex>& rhs ) noexcept; | (C++11 起)

为 std::unique_lock 特化 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的锁包装器

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

swap
 与另一 std::unique_lock 交换状态
(公开成员函数)


std::unique_lock<Mutex>::try_lock

< cpp‎ | thread‎ | unique lock
bool try_lock(); | (C++11 起)

尝试锁定关联互斥而不阻塞。等效地调用 mutex()->try_lock() 。

若无关联互斥或关联互斥已被此 std::unique_lock 锁定则抛出 std::system_error 。

参数

（无）

返回值

若成功得到互斥的所有权则为 true ，否则为 false 。

异常

  • 任何 mutex()->try_lock() 可能抛出的异常（互斥体 (Mutex) 类型在 try_lock 中不抛异常，但自定义的可锁定 (Lockable) 可以）
  • 若无关联互斥，则为以 std::errc::operation_not_permitted 为错误码的 std::system_error
  • 若关联互斥已被此 std::unique_lock 锁定，则为以 std::errc::resource_deadlock_would_occur 为错误码的 std::system_error

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定关联互斥 (公开成员函数)
try_lock_for | 试图锁定关联的可定时锁定 (TimedLockable) 互斥，若互斥在给定时长中不可用则返回 (公开成员函数)
try_lock_until | 尝试锁定关联可定时锁定 (TimedLockable) 互斥，若抵达指定时间点互斥仍不可用则返回 (公开成员函数)
unlock | 解锁关联互斥 (公开成员函数)


std::unique_lock<Mutex>::try_lock_for

< cpp‎ | thread‎ | unique lock
template< class Rep, class Period > bool try_lock_for( const std::chrono::duration <Rep,Period>& timeout_duration ); | (C++11 起)

尝试锁定关联互斥。阻塞直至经过指定的 timeout_duration 或获得锁，之先到来者。成功获得锁时返回 true ，否则返回 false 。等效地调用 mutex()->try_lock_for(timeout_duration) 。

由于调度或资源争议延迟，此函数可能阻塞长于 timeout_duration 。

标准建议用稳定时钟度量时长。若实现用系统时钟代替，则等待时间亦可能对时钟调节敏感。

若无关联互斥或若此 std::unique_lock 已锁定互斥则抛出 std::system_error 。

参数

timeout_duration - 要阻塞的最大时长

返回值

若成功获得得到互斥锁有权则为 true ，否则为 false 。

异常

  • 任何 mutex()->try_lock_for(timeout_duration) 抛出的异常
  • 若无关联互斥，则为以 std::errc::operation_not_permitted 为错误码的 std::system_error
  • 若已锁定互斥，则为以 std::errc::resource_deadlock_would_occur 为错误码的 std::system_error

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定关联互斥 (公开成员函数)
try_lock | 尝试锁定关联互斥，若互斥不可用则返回 (公开成员函数)
try_lock_until | 尝试锁定关联可定时锁定 (TimedLockable) 互斥，若抵达指定时间点互斥仍不可用则返回 (公开成员函数)
unlock | 解锁关联互斥 (公开成员函数)


std::unique_lock<Mutex>::try_lock_until

< cpp‎ | thread‎ | unique lock
template< class Clock, class Duration > bool try_lock_until( const std::chrono::time_point <Clock,Duration>& timeout_time ); | (C++11 起)

尝试锁定关联互斥（即接收其所有权）。阻塞直至抵达指定的 timeout_time 或获得锁，之先到来者。成功获得锁时返回 true ，否则返回 false 。可能阻塞长于直至抵达 timeout_time 。

等效地调用 mutex()->try_lock_until(timeout_time) 。

若无关联互斥或同一线程已锁定互斥则抛出 std::system_error 。

Clock 必须符合时钟 (Clock) 要求。若 std::chrono::is_clock_v<Clock> 为 false 则程序为非良构。 (C++20 起)

参数

timeout_time - 要阻塞到的最大时间点

返回值

若成功获得得到互斥锁有权则为 true ，否则为 false 。

异常

  • mutex()->try_lock_until(timeout_time) 所抛出的任何异常
  • 若无关联互斥，则为以 std::errc::operation_not_permitted 为错误码的 std::system_error
  • 若已锁定互斥，则为以 std::errc::resource_deadlock_would_occur 为错误码的 std::system_error

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定关联互斥 (公开成员函数)
try_lock | 尝试锁定关联互斥，若互斥不可用则返回 (公开成员函数)
try_lock_for | 试图锁定关联的可定时锁定 (TimedLockable) 互斥，若互斥在给定时长中不可用则返回 (公开成员函数)
unlock | 解锁关联互斥 (公开成员函数)


std::unique_lock<Mutex>::unique_lock

< cpp‎ | thread‎ | unique lock
unique_lock() noexcept; | (1) | (C++11 起)
unique_lock( unique_lock&& other ) noexcept; | (2) | (C++11 起)
explicit unique_lock( mutex_type& m ); | (3) | (C++11 起)
unique_lock( mutex_type& m, std::defer_lock_t t ) noexcept; | (4) | (C++11 起)
unique_lock( mutex_type& m, std::try_to_lock_t t ); | (5) | (C++11 起)
unique_lock( mutex_type& m, std::adopt_lock_t t ); | (6) | (C++11 起)
template< class Rep, class Period > unique_lock( mutex_type& m, const std::chrono::duration <Rep,Period>& timeout_duration ); | (7) | (C++11 起)
template< class Clock, class Duration > unique_lock( mutex_type& m, const std::chrono::time_point <Clock,Duration>& timeout_time ); | (8) | (C++11 起)

构造 unique_lock ，可选地锁定提供的互斥。

1) 构造无关联互斥的 unique_lock 。
2) 移动构造函数。以 other 的内容初始化 unique_lock 。令 other 无关联互斥。
3-8) 构造以 m 为关联互斥的 unique_lock 。另外：
3) 通过调用 m.lock() 锁定关联互斥。
4) 不锁定关联互斥。
5) 通过调用 m.try_lock() 尝试锁定关联互斥而不阻塞。若 Mutex 不满足可锁定 (Lockable) 则行为未定义。
6) 假定调用方线程已保有 m 上的非共享锁（即由 lock、 try_lock、 try_lock_for 或 try_lock_until 取得的锁）。若非如此则行为未定义。
7) 通过调用 m.try_lock_for(timeout_duration) 尝试锁定关联互斥。阻塞到经过指定的 timeout_duration 或获得锁这两个事件的先到来者为止。可能阻塞长于 timeout_duration 。若 Mutex 不满足可定时锁定 (TimedLockable) 则行为未定义。
8) 通过调用 m.try_lock_until(timeout_time) 尝试锁定关联互斥。阻塞到抵达指定的 timeout_time 或获得锁这两个事件的先到来者为止。可能阻塞长于抵达 timeout_time 。若 Mutex 不满足可定时锁定 (TimedLockable) 则行为未定义。

参数

other | - | 用以初始化状态的另一 unique_lock
m | - | 与锁关联且可选的获得所有权的互斥
t | - | 用于选择拥有不同锁定策略的构造函数的标签参数
timeout_duration | - | 要阻塞的最大时长
timeout_time | - | 要阻塞到的最大时间点

示例

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
std::mutex m_a, m_b, m_c;
int a, b, c = 1;
void update()
{
    {   // 注意：可用 std::lock_guard 或 atomic<int> 代替
        std::unique_lock<std::mutex> lk(m_a);
        a++;
    }

    { // 注意：细节和替代品见 std::lock 及 std::scoped_lock
      std::unique_lock<std::mutex> lk_b(m_b, std::defer_lock);
      std::unique_lock<std::mutex> lk_c(m_c, std::defer_lock);
      std::lock(lk_b, lk_c);
      b = std::exchange(c, b+c);
   }
}

int main()
{
  std::vector<std::thread> threads;
  for (unsigned i = 0; i < 12; ++i)
    threads.emplace_back(update);

  for (auto& i: threads)
    i.join();

  std::cout << a << "'th and " << a+1 << "'th Fibonacci numbers: "
            << b << " and " << c << '\n';
}

输出：

12'th and 13'th Fibonacci numbers: 144 and 233


std::unique_lock<Mutex>::unlock

< cpp‎ | thread‎ | unique lock
void unlock(); | (C++11 起)

解锁关联互斥并释放所有权。

若无关联互斥或互斥未被锁则抛出 std::system_error 。

参数

（无）

返回值

（无）

异常

  • mutex()->unlock() 所抛的任何异常
  • 若无关联互斥或关联互斥未被锁，则抛出以 std::system_error 为错误码的 std::errc::operation_not_permitted

示例

本节未完成
原因：暂无示例

参阅

lock | 锁定关联互斥 (公开成员函数)
release | 将关联互斥解关联而不解锁它 (公开成员函数)


std::unique_lock<Mutex>::~unique_lock

< cpp‎ | thread‎ | unique lock
~unique_lock(); | (C++11 起)

销毁锁。若 *this 拥有关联互斥且获得了其所有权，则解锁互斥。


std::this_thread::yield

< cpp‎ | thread
定义于头文件 <thread> |
void yield() noexcept; | (C++11 起)

提供提示给实现，以重调度线程的执行，允许其他线程运行。

参数

（无）

返回值

（无）

注意

此函数的准确性为依赖于实现，特别是使用中的 OS 调度器机制和系统状态。例如，先进先出实时调度器（ Linux 的 SCHED_FIFO ）将悬挂当前线程并将它放到准备运行的同优先级线程的队列尾（而若无其他线程在同优先级，则 yield 无效果）。

示例

#include <iostream>
#include <chrono>
#include <thread>

// 建议其他线程运行一小段时间的“忙睡眠”
void little_sleep(std::chrono::microseconds us)
{
    auto start = std::chrono::high_resolution_clock::now();
    auto end = start + us;
    do {
        std::this_thread::yield();
    } while (std::chrono::high_resolution_clock::now() < end);
}

int main()
{
    auto start = std::chrono::high_resolution_clock::now();

    little_sleep(std::chrono::microseconds(100));

    auto elapsed = std::chrono::high_resolution_clock::now() - start;
    std::cout << "waited for "
              << std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count()
              << " microseconds\n";
}

可能的输出：

waited for 128 microseconds

参阅


类型支持（基本类型、RTTI、类型特性）

< cpp

（类型系统综述可参阅类型）

基本类型

语言定义的基础类型

附加性基本类型及宏

定义于头文件 <cstddef>
size_t | sizeof 运算符返回的无符号整数类型 (typedef)
ptrdiff_t | 在两个指针相减时返回的有符号整数类型 (typedef)
nullptr_t (C++11) | 空指针字面量 nullptr 的类型 (typedef)
NULL | 实现定义的空指针常量 (宏常量)
max_align_t (C++11) | 具有不小于任何基础类型的内存对齐需求的平凡类型 (typedef)
offsetof | 从标准布局类型的起始到其指定成员的字节偏移量 (宏函数)
byte (C++17) | 字节类型 (枚举)
定义于头文件 <cstdbool> (C++20 前)
定义于头文件 <stdbool.h>
__bool_true_false_are_defined (C++11) | C 兼容宏常量，展开成整数字面量 1 (宏常量)
定义于头文件 <cstdalign> (C++20 前)
定义于头文件 <stdalign.h>
__alignas_is_defined (C++11) | C 兼容宏常量，展开成整数字面量 1 (宏常量)

定宽整数 (C++11 起)

数值极限

定义于头文件 <limits>
numeric_limits
 提供查询所有基础数值类型的性质的接口。
(类模板)

C 数值极限接口

运行时类型识别

定义于头文件 <typeinfo>
type_info | 含有某个类型的信息，由实现生成。 这是 typeid 运算符所返回的类。 (类)
bad_typeid | 当 typeid 表达式中的实参为空值时抛出的异常 (类)
bad_cast | 由非法的 dynamic_cast 表达式抛出的异常，即引用类型转型失败 (类)
定义于头文件 <typeindex>
type_index (C++11) | 针对 type_info 对象的包装，它能用作关联容器和无序关联容器的索引。 (类)

类型特性(C++11 起)

类型特性定义一个编译时基于模板的结构，以查询或修改类型的属性。

试图特化定义于 <type_traits> 头文件的模板导致未定义行为，除了 std::common_type 可依照其所描述特化。

定义于<type_traits>头文件的模板可以用不完整类型实例化，除非另外有指定，尽管通常禁止以不完整类型实例化标准库模板。

类型属性

定义于头文件 <type_traits>
基础类型类别
is_void
(C++11)
 检查类型是否为 void
(类模板)
is_null_pointer
(C++14)
 检查类型是否为 std::nullptr_t
(类模板)
is_integral
(C++11)
 检查类型是否为整型
(类模板)
is_floating_point
(C++11)
 检查类型是否是浮点类型
(类模板)
is_array
(C++11)
 检查类型是否是数组类型
(类模板)
is_enum
(C++11)
 检查类型是否是枚举类型
(类模板)
is_union
(C++11)
 检查类型是否为联合体类型
(类模板)
is_class
(C++11)
 检查类型是否非联合类类型
(类模板)
is_function
(C++11)
 检查是否为函数类型
(类模板)
is_pointer
(C++11)
 检查类型是否为指针类型
(类模板)
is_lvalue_reference
(C++11)
 检查类型是否为左值引用
(类模板)
is_rvalue_reference
(C++11)
 检查类型是否为右值引用
(类模板)
is_member_object_pointer
(C++11)
 检查类型是否为指向非静态成员对象的指针
(类模板)
is_member_function_pointer
(C++11)
 检查类型是否为指向非静态成员函数的指针
(类模板)
复合类型类别
is_fundamental
(C++11)
 检查是否是基础类型
(类模板)
is_arithmetic
(C++11)
 检查类型是否为算术类型
(类模板)
is_scalar
(C++11)
 检查类型是否为标量类型
(类模板)
is_object
(C++11)
 检查是否是对象类型
(类模板)
is_compound
(C++11)
 检查是否为复合类型
(类模板)
is_reference
(C++11)
 检查类型是否为左值引用或右值引用
(类模板)
is_member_pointer
(C++11)
 检查类型是否为指向非静态成员函数或对象的指针类型
(类模板)
类型属性
is_const
(C++11)
 检查类型是否为 const 限定
(类模板)
is_volatile
(C++11)
 检查类型是否为 volatile 限定
(类模板)
is_trivial
(C++11)
 检查类型是否平凡
(类模板)
is_trivially_copyable
(C++11)
 检查类型是否可平凡复制
(类模板)
is_standard_layout
(C++11)
 检查是否是一个标准布局类型
(类模板)
is_pod
(C++11)(C++20 中弃用)
 检查类型是否为简旧数据（POD）类型
(类模板)
is_literal_type
(C++11)(C++17 中弃用)(C++20 中移除)
 检查类型是否为字面类型
(类模板)
has_unique_object_representations
(C++17)
 检查是否该类型对象的每一位都对其值有贡献
(类模板)
has_strong_structural_equality
(C++20)
 检查类型是否拥有强结构相等性
(类模板)
is_empty
(C++11)
 检查类型是否为类（但非联合体）类型且无非静态数据成员
(类模板)
is_polymorphic
(C++11)
 检查类型是否为多态类类型
(类模板)
is_abstract
(C++11)
 检查类型是否为抽象类类型
(类模板)
is_final
(C++14)
 检查类型是否为 final 类类型
(类模板)
is_aggregate
(C++17)
 检查类型是否聚合类型
(类模板)
is_signed
(C++11)
 检查类型是否为有符号算术类型
(类模板)
is_unsigned
(C++11)
 检查类型是否为无符号算术类型
(类模板)
is_bounded_array
(C++20)
 检查类型是否为有已知边界的数组类型
(类模板)
is_unbounded_array
(C++20)
 检查类型是否为有未知边界的数组类型
(类模板)
is_scoped_enum
(C++23)
 检查类型是否为有作用域枚举类型
(类模板)
受支持操作
is_constructibleis_trivially_constructibleis_nothrow_constructible
(C++11)(C++11)(C++11)
 检查类型是否带有针对特定实参的构造函数
(类模板)
is_default_constructibleis_trivially_default_constructibleis_nothrow_default_constructible
(C++11)(C++11)(C++11)
 检查类型是否有默认构造函数
(类模板)
is_copy_constructibleis_trivially_copy_constructibleis_nothrow_copy_constructible
(C++11)(C++11)(C++11)
 检查类型是否拥有复制构造函数
(类模板)
is_move_constructibleis_trivially_move_constructibleis_nothrow_move_constructible
(C++11)(C++11)(C++11)
 检查类型是否能从右值引用构造
(类模板)
is_assignableis_trivially_assignableis_nothrow_assignable
(C++11)(C++11)(C++11)
 检查类型是否拥有针对特定实参的赋值运算符
(类模板)
is_copy_assignableis_trivially_copy_assignableis_nothrow_copy_assignable
(C++11)(C++11)(C++11)
 检查类型是否拥有复制赋值运算符
(类模板)
is_move_assignableis_trivially_move_assignableis_nothrow_move_assignable
(C++11)(C++11)(C++11)
 检查类型是否有拥有移动赋值运算符
(类模板)
is_destructibleis_trivially_destructibleis_nothrow_destructible
(C++11)(C++11)(C++11)
 检查类型是否拥有未被弃置的析构函数
(类模板)
has_virtual_destructor
(C++11)
 检查类型是否拥有虚析构函数
(类模板)
is_swappable_withis_swappableis_nothrow_swappable_withis_nothrow_swappable
(C++17)(C++17)(C++17)(C++17)
 检查一个类型的对象是否能与同类型或不同类型的对象交换
(类模板)
属性查询
alignment_of
(C++11)
 获取类型的对齐要求
(类模板)
rank
(C++11)
 获取数组类型的维数
(类模板)
extent
(C++11)
 获取数组类型在指定维度的大小
(类模板)
类型关系
is_same
(C++11)
 检查两个类型是否相同
(类模板)
is_base_of
(C++11)
 检查一个类型是否派生自另一个类型
(类模板)
is_convertibleis_nothrow_convertible
(C++11)(C++20)
 检查是否能转换一个类型为另一类型
(类模板)
is_invocableis_invocable_ris_nothrow_invocableis_nothrow_invocable_r
(C++17)
 检查类型能否以给定的实参类型调用（如同以 std::invoke）
(类模板)
is_layout_compatible
(C++20)
 检查二个类型是否布局兼容
(类模板)
is_pointer_interconvertible_base_of
(C++20)
 检查一个类型是否为另一类型的指针可互转换（起始）基类
(类模板)
is_pointer_interconvertible_with_class
(C++20)
 检查一个类型的对象是否与该类型的指定子对象指针可互转换
(函数模板)
is_corresponding_member
(C++20)
 检查二个指定成员是否在二个指定类型中的公共起始序列中彼此对应
(函数模板)

类型修改

类型修改模板通过应用修改到模板参数，创建新类型定义。结果类型可以通过成员 typedef type 访问。

定义于头文件 <type_traits>
常-易变性指定器
remove_cvremove_constremove_volatile
(C++11)(C++11)(C++11)
 从给定类型移除 const 或/与 volatile 限定符
(类模板)
add_cvadd_constadd_volatile
(C++11)(C++11)(C++11)
 添加 const 或/与 volatile 限定符到给定类型
(类模板)
引用
remove_reference
(C++11)
 从给定类型移除引用
(类模板)
add_lvalue_referenceadd_rvalue_reference
(C++11)(C++11)
 向给定类型添加左值或右值引用
(类模板)
指针
remove_pointer
(C++11)
 移除给定类型的一层指针
(类模板)
add_pointer
(C++11)
 对给定类型添加一层指针
(类模板)
符号修改器
make_signed
(C++11)
 使给定的整型类型有符号
(类模板)
make_unsigned
(C++11)
 使给定的整型类型无符号
(类模板)
数组
remove_extent
(C++11)
 从给定数组类型移除一个维度
(类模板)
remove_all_extents
(C++11)
 移除给定数组类型的所有维度
(类模板)

杂项变换

定义于头文件 <type_traits>
aligned_storage (C++11) | 定义适于用作给定大小的类型的未初始化存储的类型 (类模板)
aligned_union (C++11) | 定义适于用作所有给定类型的未初始化存储的类型 (类模板)
decay (C++11) | 实施当按值传递实参给函数时所进行的类型变换 (类模板)
remove_cvref (C++20) | 将 std::remove_cv 与 std::remove_reference 结合 (类模板)
enable_if (C++11) | 条件性地从重载决议移除函数重载或模板特化 (类模板)
conditional (C++11) | 基于编译时布尔值选择一个类型或另一个 (类模板)
common_type (C++11) | 确定一组类型的公共类型 (类模板)
common_referencebasic_common_reference (C++20) | 确定类型组的共用引用类型 (类模板)
underlying_type (C++11) | 获取给定枚举类型的底层整数类型 (类模板)
result_ofinvoke_result (C++11)(C++20 中移除)(C++17) | 推导以一组实参调用一个可调用对象的结果类型 (类模板)
void_t (C++17) | void 变参别名模板 (别名模板)
type_identity (C++20) | 返回不更改的类型实参 (类模板)

特性上的运算

定义于头文件 <type_traits>
conjunction (C++17) | 变参的逻辑与元函数 (类模板)
disjunction (C++17) | 变参的逻辑或元函数 (类模板)
negation (C++17) | 逻辑非元函数 (类模板)

辅助类

定义于头文件 <type_traits>
integral_constantbool_constant
(C++11)(C++17)
 具有指定值的指定类型的编译期常量
(类模板)

标准提供 std::integral_constant 对类型 bool 的二个特化：

定义于头文件 <type_traits>
类型 | 定义
true_type | std::integral_constant <bool, true>
false_type | std::integral_constant <bool, false>

常量求值语境 (C++20 起)

定义于头文件 <type_traits>
is_constant_evaluated
(C++20)
 检测调用是否在常量求值的语境内发生
(函数)

参阅


NULL

< cpp‎ | types
定义于头文件 <clocale>
定义于头文件 <cstddef>
定义于头文件 <cstdio>
定义于头文件 <cstdlib>
定义于头文件 <cstring>
定义于头文件 <ctime>
定义于头文件 <cwchar>
#define NULL /*implementation-defined*/

宏 NULL 是实现定义的空指针常量，可为

求值为零的整数类型字面常量表达式 右值 | (C++11 前)
零值整数字面量，或为 std::nullptr_t 类型纯右值 | (C++11 起)

空指针常量可以隐式转换为任何指针类型；这种转换结果是该类型的空指针值。若空指针常量拥有整数类型，它亦可转换为 std::nullptr_t 类型纯右值。

可能的实现

#define NULL 0
// C++11 起
#define NULL nullptr

注解

C 中，宏 NULL 可以拥有类型 void* ，但这在 C++ 中不允许。

一些实现定义 NULL 为拥有下列属性的编译器扩展 __null ：

  • __null 等价于零值的整数字面量（从而与 C++ 标准兼容）并拥有与 void* 相同的大小，例如它在 ILP32/LP64 平台上分别等价于 ​0​/0L ；
  • 从 __null 到算术类型，包括 __null 自身的类型的转换，可能触发警告。

示例

#include <cstddef>
#include <type_traits>
#include <iostream>
class S;
int main()
{
    int* p = NULL;
    int* p2 = static_cast<std::nullptr_t>(NULL);
    void(*f)(int) = NULL;
    int S::*mp = NULL;
    void(S::*mfp)(int) = NULL;
    auto nullvar = NULL; // 以 gcc/clang 编译时可以触发警告

    if constexpr(std::is_same_v<decltype(NULL), std::nullptr_t>) {
        std::cout << "NULL implemented with type std::nullptr_t\n";
    } else {
        std::cout << "NULL implemented using an integral type\n";
    }

    [](auto...){}(p, p2, f, mp, mfp, nullvar); //< 垃圾“未使用”值
}

可能的输出：

NULL implemented using an integral type

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 903 | C++11 | 曾允许零值的表达式，如 1-1 | 只允许字面的零

参阅

nullptr (C++11) | 指定空指针值的指针字面量
nullptr_t (C++11) | 空指针字面量 nullptr 的类型 (typedef)


std::add_cv, std::add_const, std::add_volatile

< cpp‎ | types
定义于头文件 <type_traits> |  |
template< class T > struct add_cv; | (1) | (C++11 起)
template< class T > struct add_const; | (2) | (C++11 起)
template< class T > struct add_volatile; | (3) | (C++11 起)

提供同 T 的成员 typedef type ，除了它拥有添加的 cv 限定符（除非 T 是函数、引用或已拥有 cv 限定符）。

1) 添加 const 和 volatile
2) 添加 const
3) 添加 volatile

添加此页面上描述的任何模板的特化的程序行为未定义。

成员类型

名称 | 定义
type | 带 cv 限定符的类型 T

辅助类型

template< class T > using add_cv_t = typename add_cv<T>::type; | (C++14 起)
template< class T > using add_const_t = typename add_const<T>::type; | (C++14 起)
template< class T > using add_volatile_t = typename add_volatile<T>::type; | (C++14 起)

可能的实现

template<class T> struct add_cv { typedef const volatile T type; };

template<class T> struct add_const { typedef const T type; };

template<class T> struct add_volatile { typedef volatile T type; };

注解

这些变换特征能用于在模板实参推导中建立非推导语境：

template<class T>
void f(const T&, const T&);

template<class T>
void g(const T&, std::add_const_t<T>&);

f(4.2, 0); // 错误：对 'T' 推导出冲突的类型
g(4.2, 0); // OK ：调用 g<double>

示例

#include <iostream>
#include <type_traits>

struct foo
{
    void m() { std::cout << "Non-cv\n"; }
    void m() const { std::cout << "Const\n"; }
    void m() volatile { std::cout << "Volatile\n"; }
    void m() const volatile { std::cout << "Const-volatile\n"; }
};

int main()
{
    foo{}.m();
    std::add_const<foo>::type{}.m();
    std::add_volatile<foo>::type{}.m();
    std::add_cv<foo>::type{}.m();
}

输出：

Non-cv
Const
Volatile
Const-volatile

参阅

is_const (C++11) | 检查类型是否为 const 限定 (类模板)
is_volatile (C++11) | 检查类型是否为 volatile 限定 (类模板)
remove_cvremove_constremove_volatile (C++11)(C++11)(C++11) | 从给定类型移除 const 或/与 volatile 限定符 (类模板)
as_const (C++17) | 获得到其实参的 const 引用 (函数模板)


std::add_pointer

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct add_pointer; | (C++11 起)

若 T 为引用类型，则提供成员 typedef type ，其为指向被引用类型的指针。

否则，若 T 指名对象类型、无 cv 或引用限定的函数类型或（可有 cv 限定的） void 类型，则提供成员 typedef type ，其为类型 T* 。

否则（若 T 为 cv 或引用限定的函数类型），提供成员 typedef type ，其为类型 T 。

添加 add_pointer 的特化的程序行为未定义。

成员类型

名称 | 定义
type | 指向 T 或 T 所引用类型的指针

辅助类型

template< class T > using add_pointer_t = typename add_pointer<T>::type; | (C++14 起)

可能的实现

namespace detail {

template <class T>
struct type_identity { using type = T; }; // 或使用 std::type_identity (C++20 起)

template <class T>
auto try_add_pointer(int) -> type_identity<typename std::remove_reference<T>::type*>;
template <class T>
auto try_add_pointer(...) -> type_identity<T>;

} // namespace detail

template <class T>
struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {};

示例

#include <iostream>
#include <type_traits>

int main()
{
    int i = 123;
    int& ri = i;
    typedef std::add_pointer<decltype(i)>::type IntPtr;
    typedef std::add_pointer<decltype(ri)>::type IntPtr2;
    IntPtr pi = &i;
    std::cout << "i = " << i << "\n";
    std::cout << "*pi = " << *pi << "\n";

    static_assert(std::is_pointer<IntPtr>::value, "IntPtr should be a pointer");
    static_assert(std::is_same<IntPtr, int*>::value, "IntPtr should be a pointer to int");
    static_assert(std::is_same<IntPtr2, IntPtr>::value, "IntPtr2 should be equal to IntPtr");

    typedef std::remove_pointer<IntPtr>::type IntAgain;
    IntAgain j = i;
    std::cout << "j = " << j << "\n";

    static_assert(!std::is_pointer<IntAgain>::value, "IntAgain should not be a pointer");
    static_assert(std::is_same<IntAgain, int>::value, "IntAgain should be equal to int");
}

输出：

i = 123
*pi = 123
j = 123

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2101 | C++11 | 曾要求 std::add_pointer 产生指向 cv 或引用限定的函数类型的指针。 | 产生 cv 或引用限定的函数类型自身。

参阅

is_pointer (C++11) | 检查类型是否为指针类型 (类模板)
remove_pointer (C++11) | 移除给定类型的一层指针 (类模板)


std::add_lvalue_reference, std::add_rvalue_reference

< cpp‎ | types
定义于头文件 <type_traits> |  |
template< class T > struct add_lvalue_reference; | (1) | (C++11 起)
template< class T > struct add_rvalue_reference; | (2) | (C++11 起)

创建 T 的左值或右值引用类型。

1) 若 T 是对象或无 cv 或引用限定符的函数类型，则提供成员 typedef type ，其为 T& 。若 T 是到某类型 U 的右值引用，则 type 为 U& 。否则， type 为 T 。
2) 若 T 是对象或无 cv 或引用限定符的函数类型，则提供成员 typedef type ，其为 T&& ，否则 type 为 T 。

添加此页面上描述的任何模板的特化的程序行为未定义。

成员类型

名称 | 定义
type | 到 T 的引用，或若不允许则为 T

辅助类型

template< class T > using add_lvalue_reference_t = typename add_lvalue_reference<T>::type; | (C++14 起)
template< class T > using add_rvalue_reference_t = typename add_rvalue_reference<T>::type; | (C++14 起)

注解

这些类型变换遵从引用折叠规则：

  • std::add_lvalue_reference<T&>::type 是 T&
  • std::add_lvalue_reference<T&&>::type 是 T&
  • std::add_rvalue_reference<T&>::type 是 T&
  • std::add_rvalue_reference<T&&>::type 是 T&&

与直接使用 T& 的主要区别是 std::add_lvalue_reference<void>::type 为 void ，而 void& 导致编译错误。

可能的实现

namespace detail {

template <class T>
struct type_identity { using type = T; }; // 或使用 std::type_identity (C++20 起)

template <class T>
auto try_add_lvalue_reference(int) -> type_identity<T&>;
template <class T>
auto try_add_lvalue_reference(...) -> type_identity<T>;

template <class T>
auto try_add_rvalue_reference(int) -> type_identity<T&&>;
template <class T>
auto try_add_rvalue_reference(...) -> type_identity<T>;

} // namespace detail

template <class T>
struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference<T>(0)) {};

template <class T>
struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) {};

示例

#include <iostream>
#include <type_traits>

int main() {
   using nonref = int;
   using lref = typename std::add_lvalue_reference<nonref>::type;
   using rref = typename std::add_rvalue_reference<nonref>::type;

   std::cout << std::boolalpha;
   std::cout << std::is_lvalue_reference<nonref>::value << '\n';
   std::cout << std::is_lvalue_reference<lref>::value << '\n';
   std::cout << std::is_rvalue_reference<rref>::value << '\n';
}

输出：

false
true
true

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2101 | C++11 | 曾要求这些变换特性产生到 cv 或引用限定的函数类型的引用。 | 产生 cv 或引用限定的函数类型自身。

参阅

is_reference (C++11) | 检查类型是否为左值引用或右值引用 (类模板)
remove_reference (C++11) | 从给定类型移除引用 (类模板)
remove_cvref (C++20) | 将 std::remove_cv 与 std::remove_reference 结合 (类模板)


std::aligned_storage

< cpp‎ | types
定义于头文件 <type_traits>
template< std::size_t Len, std::size_t Align = /*default-alignment*/ >
struct aligned_storage;
 (C++11 起)

提供嵌套类型 type ，其为平凡的 标准布局类型，适于作为任何大小至多为 Len 且对齐要求为 Align 的因数的对象的未初始化存储。

Align 的默认值是任何大小至多为 Len 的对象的最强（最大）对齐要求。若不使用默认值，则 Align 对于某类型 T 必须为 alignof(T) 的值，否则行为未定义。

若 Len == 0 则行为未定义。

是否支持任何扩展对齐是实现定义的。

添加 aligned_storage 的特化的程序行为未定义。

成员类型

名称 | 定义
type | 长度至少为 Len 并拥有对齐要求 Align 的平凡兼标准布局类型

辅助类型

template< std::size_t Len, std::size_t Align = /*default-alignment*/ >
using aligned_storage_t = typename aligned_storage<Len, Align>::type;
 (C++14 起)

注解

std::aligned_storage<>::type 所定义的类型能用于创建适合保有给定类型对象的未初始化内存块，可选地对齐严格于其自然对齐要求，例如在缓存或页边界上。

同任何其他未初始化存储，通过使用布置 new 创建对象，并以显式的析构函数调用销毁。

可能的实现

除了默认实参， aligned_storage 能通过 alignas 表达：

template<std::size_t Len, std::size_t Align /* 未实现默认对齐 */>
struct aligned_storage {
    struct type {
        alignas(Align) unsigned char data[Len];
    };
};

示例

原始的静态 vector 类，演示于对齐存储中创建、访问及析构对象

#include <new>
#include <iostream>
#include <type_traits>
#include <string>

template<class T, std::size_t N>
class static_vector
{
    // N 个 T 的正确对齐的未初始化存储
    std::aligned_storage_t<sizeof(T), alignof(T)> data[N];
    std::size_t m_size = 0;

public:
    // 在对齐的存储中创建对象
    template<typename ...Args> void emplace_back(Args&&... args)
    {
        if( m_size >= N ) // 可能的错误处理
            throw std::bad_alloc{};

        // 用原位 operator new 在对齐的存储中构造值
        ::new(&data[m_size]) T(std::forward<Args>(args)...);
        ++m_size;
    }

    // 在对齐的存储中访问对象
    const T& operator[](std::size_t pos) const
    {
        // 注意：在 P0137R1 中的对象模型更改后需要 std::launder
        return *std::launder(reinterpret_cast<const T*>(&data[pos]));
    }

    // 从对齐的存储中销毁对象
    ~static_vector()
    {
        for(std::size_t pos = 0; pos < m_size; ++pos) {
            // 注意：在 P0137R1 中的对象模型更改后需要 std::launder
            std::destroy_at(std::launder(reinterpret_cast<T*>(&data[pos])));
        }
    }
};

int main()
{
    static_vector<std::string, 10> v1;
    v1.emplace_back(5, '*');
    v1.emplace_back(10, '*');
    std::cout << v1[0] << '\n' << v1[1] << '\n';
}

输出：

*****
**********

参阅

alignas 说明符 (C++11) | 指定该变量的存储应该按指定量对齐
alignment_of (C++11) | 获取类型的对齐要求 (类模板)
aligned_union (C++11) | 定义适于用作所有给定类型的未初始化存储的类型 (类模板)
max_align_t (C++11) | 具有不小于任何基础类型的内存对齐需求的平凡类型 (typedef)
launder (C++17) | 指针优化屏障 (函数模板)


std::aligned_union

< cpp‎ | types
定义于头文件 <type_traits>
template< std::size_t Len, class... Types >
struct aligned_union;
 (C++11 起)

提供嵌套类型 type ，它是平凡的 标准布局类型，且其大小和对齐适合用作任何列于 Types 的类型的一个对象的未初始化存储。存储的大小至少为 Len 。 std::aligned_union 亦确定所有 Types 中最严格（最大）的对齐要求，使之可用作常量 alignment_value 。

若 sizeof...(Types) == 0 或若 Types 中的任何类型不是完整对象类型，则行为未定义。

是否支持任何扩展对齐是实现定义的。

添加 aligned_union 的特化的程序行为未定义。

成员类型

名称 | 定义
type | 适用于存储来自 Types 的任何类型的平凡兼标准布局类型

辅助类型

template< std::size_t Len, class... Types >
using aligned_union_t = typename aligned_union<Len,Types...>::type;
 (C++14 起)

成员常量

alignment_value
[静态]
 所有 Types 的最严格对齐
(公开静态成员常量)

可能的实现

#include <algorithm>
template <std::size_t Len, class... Types>
struct aligned_union
{
    static constexpr std::size_t alignment_value = std::max({alignof(Types)...});

    struct type
    {
      alignas(alignment_value) char _s[std::max({Len, sizeof(Types)...})];
    };
};

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2979 | C++11 | 不要求完整类型 | 要求完整类型

参阅

alignment_of (C++11) | 获取类型的对齐要求 (类模板)
aligned_storage (C++11) | 定义适于用作给定大小的类型的未初始化存储的类型 (类模板)


std::alignment_of

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct alignment_of; | (C++11 起)

提供等于 T 类型对齐要求的成员常量 value ，如同用 alignof 表达式获得。若 T 是数组类型，则返回元素类型的对齐要求，若 T 是引用类型，则返回备用用类型的对齐要求。

若 alignof(T) 不是合法表达式，则行为未定义。

添加 alignment_of 或 alignment_of_v (C++17 起) 的特化的程序行为未定义。

辅助变量模板

template< class T > inline constexpr std::size_t alignment_of_v = alignment_of<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 alignof(T)
(公开静态成员常量)

成员函数

operator std::size_t | 转换对象为 std::size_t ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | std::size_t
type | std::integral_constant < std::size_t, value>

可能的实现

template< class T >
struct alignment_of : std::integral_constant<
                          std::size_t,
                          alignof(T)
                       > {};

注解

此类型特征早于 alignof 关键词出现，该关键词能用于较简明地获得相同值。

示例

#include <iostream>
#include <type_traits>

class A {};

int main()
{
    std::cout << std::alignment_of<A>::value << '\n';
    std::cout << std::alignment_of<int>() << '\n'; // 另一种语法
    std::cout << std::alignment_of_v<double> << '\n'; // c++17 另一种语法
}

可能的输出：

1
4
8

参阅

alignof 运算符 (C++11) | 查询类型的对齐要求
aligned_storage (C++11) | 定义适于用作给定大小的类型的未初始化存储的类型 (类模板)
aligned_union (C++11) | 定义适于用作所有给定类型的未初始化存储的类型 (类模板)
max_align_t (C++11) | 具有不小于任何基础类型的内存对齐需求的平凡类型 (typedef)


std::bad_cast

< cpp‎ | types
定义于头文件 <typeinfo>
class bad_cast : public std::exception ;

在 dynamic_cast 对引用类型运行时检查失败（例如因为类型并非以继承关联）时，还有若请求的刻面不存在于本地环境时从 std::use_facet 抛出此类型异常。

cpp/error/exception

继承图

成员函数

(构造函数) | 构造新的 bad_cast 对象 (公开成员函数)
operator= | 替换 bad_cast 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::bad_cast::bad_cast

 | (1)
bad_cast() throw(); |  | (C++11 前)
bad_cast() noexcept; |  | (C++11 起)
 | (2)
bad_cast( const bad_cast& other ) throw(); |  | (C++11 前)
bad_cast( const bad_cast& other ) noexcept; |  | (C++11 起)

构造新的拥有实现定义的空终止字节字符串的 bad_cast 对象，字符串能通过 what() 访问。

1) 默认构造函数。
2) 复制构造函数。若 *this 与 other 均拥有动态类型 std::bad_cast 则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 要复制的另一异常对象

std::bad_cast::operator=

bad_cast& operator=( const bad_cast& other ) throw(); | (C++11 前)
bad_cast& operator=( const bad_cast& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::bad_cast 则赋值后 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 用以赋值的另一异常对象

返回值

*this

std::bad_cast::what

virtual const char* what() const throw(); | (C++11 前)
virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

示例

#include <iostream>
#include <typeinfo>

struct Foo { virtual ~Foo() {} };
struct Bar { virtual ~Bar() {} };

int main()
{
    Bar b;
    try {
        Foo& f = dynamic_cast<Foo&>(b);
    } catch(const std::bad_cast& e)
    {
        std::cout << e.what() << '\n';
    }
}

可能的输出：

Bad dynamic cast


std::bad_typeid

< cpp‎ | types
定义于头文件 <typeinfo>
class bad_typeid : public std::exception ;

此类型的异常在应用 typeid 运算符到多态类型的空指针值时抛出。

cpp/error/exception

继承图

成员函数

(构造函数) | 构造新的 bad_typeid 对象 (公开成员函数)
operator= | 替换 bad_typeid 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::bad_typeid::bad_typeid

 | (1)
bad_typeid() throw(); |  | (C++11 前)
bad_typeid() noexcept; |  | (C++11 起)
 | (2)
bad_typeid( const bad_typeid& other ) throw(); |  | (C++11 前)
bad_typeid( const bad_typeid& other ) noexcept; |  | (C++11 起)

构造新的拥有实现定义的空终止字节字符串的 bad_typeid 对象，字符串能通过 what() 访问。

1) 默认构造函数。
2) 复制构造函数。若 *this 与 other 均拥有动态类型 std::bad_typeid 则 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 要复制的另一异常对象

std::bad_typeid::operator=

bad_typeid& operator=( const bad_typeid& other ) throw(); | (C++11 前)
bad_typeid& operator=( const bad_typeid& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::bad_typeid 则赋值后 std::strcmp (what(), other.what()) == 0 。 (C++11 起)

参数

other - 用以赋值的另一异常对象

返回值

*this

std::bad_typeid::what

virtual const char* what() const throw(); | (C++11 前)
virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

示例

#include <iostream>
#include <typeinfo>

struct S { // 类型必须是多态
    virtual void f();
};

int main()
{
    S* p = nullptr;
    try {
        std::cout << typeid(*p).name() << '\n';
    } catch(const std::bad_typeid& e) {
        std::cout << e.what() << '\n';
    }
}

可能的输出：

Attempted a typeid of NULL pointer!


std::byte

< cpp‎ | types
定义于头文件 <cstddef> |
enum class byte : unsigned char {} ; | (C++17 起)

std::byte 是一种独立类型，它实现指定于 C++ 语言定义中的字节的概念。

同 char 与 unsigned char ，它能用于访问其他对象所占据的生内存（对象表示），但不同于这些类型，它不是字符类型且非算术类型。 byte 只是位的汇集，而且只对它定义逐位运算符。

非成员函数

std::to_integer

template <class IntegerType> constexpr IntegerType to_integer(std::byte b) noexcept; | (C++17 起)

等价于： return IntegerType(b); 此重载仅若 std::is_integral_v <IntegerType> 为 true 才参与重载决议。

std::operator<<=,operator>>=

template <class IntegerType> constexpr std::byte& operator<<=(std::byte& b, IntegerType shift) noexcept; | (1) | (C++17 起)
template <class IntegerType> constexpr std::byte& operator>>=(std::byte& b, IntegerType shift) noexcept; | (2) | (C++17 起)
1) 等价于： return b = b << shift; 此重载仅若 std::is_integral_v <IntegerType> 为 true 才参与重载决议。
2) 等价于： return b = b >> shift; 此重载仅若 std::is_integral_v <IntegerType> 为 true 才参与重载决议。

std::operator<<,operator>>

template <class IntegerType> constexpr std::byte operator <<(std::byte b, IntegerType shift) noexcept; | (1) | (C++17 起)
template <class IntegerType> constexpr std::byte operator >>(std::byte b, IntegerType shift) noexcept; | (2) | (C++17 起)
1) 等价于： return std::byte(static_cast<unsigned int>(b) << shift); 此重载仅若 std::is_integral_v <IntegerType> 为 true 才参与重载决议。
2) 等价于： return std::byte(static_cast<unsigned int>(b) >> shift);

此重载仅若 std::is_integral_v <IntegerType> 为 true 才参与重载决议。

std::operator|=,operator&=,operator^=

constexpr std::byte& operator|=(std::byte& l, std::byte r) noexcept; | (1) | (C++17 起)
constexpr std::byte& operator&=(std::byte& l, std::byte r) noexcept; | (2) | (C++17 起)
constexpr std::byte& operator^=(std::byte& l, std::byte r) noexcept; | (3) | (C++17 起)
1) 等价于： return l = l | r; 。
2) 等价于： return l = l & r; 。
3) 等价于： return l = l ^ r; 。

std::operator|,operator&,operator^,operator~

constexpr std::byte operator|(std::byte l, std::byte r) noexcept; | (1) | (C++17 起)
constexpr std::byte operator&(std::byte l, std::byte r) noexcept; | (2) | (C++17 起)
constexpr std::byte operator^(std::byte l, std::byte r) noexcept; | (3) | (C++17 起)
constexpr std::byte operator~(std::byte b) noexcept; | (4) | (C++17 起)
1) 等价于： return std::byte(static_cast<unsigned int>(l) |
static_cast<unsigned int>(r)); 。
2) 等价于： return std::byte(static_cast<unsigned int>(l) &
static_cast<unsigned int>(r)); 。
3) 等价于： return std::byte(static_cast<unsigned int>(l) ^
static_cast<unsigned int>(r)); 。
4) 等价于： return std::byte(~static_cast<unsigned int>(b)); 。

注意

由于 C++17 放松的 enum class 初始化规则，能用 std::byte{n} 转换数值 n 为 byte 值。

能用 std::to_integer 转换 byte 为数值（例如生成对象的整数哈希）。

示例

#include <iostream>
#include <cstddef>

int main()
{
    std::byte b{42};
    std::cout << std::to_integer<int>(b) << "\n";

    // b *= 2 编译错误
    b <<= 1;
    std::cout << std::to_integer<int>(b) << "\n";
}

输出：

42
84


C 数值极限接口

< cpp‎ | types

参阅 std::numeric_limits 接口。

定义于头文件 <cstdint>
PTRDIFF_MIN (C++11) | std::ptrdiff_t 类型对象的最小值 (宏常量)
PTRDIFF_MAX (C++11) | std::ptrdiff_t 类型对象的最大值 (宏常量)
SIZE_MAX (C++11) | std::size_t 类型对象的最大值 (宏常量)
SIG_ATOMIC_MIN (C++11) | std::sig_atomic_t 类型对象的最小值 (宏常量)
SIG_ATOMIC_MAX (C++11) | std::sig_atomic_t 类型对象的最大值 (宏常量)
WCHAR_MIN (C++11) | wchar_t 类型对象的最小值 (宏常量)
WCHAR_MAX (C++11) | wchar_t 类型对象的最大值 (宏常量)
WINT_MIN (C++11) | std::wint_t 类型对象的最小值 (宏常量)
WINT_MAX (C++11) | std::wint_t 类型对象的最大值 (宏常量)

注意：自立实现可能缺少 std::sig_atomic_t 与/或 std::wint_t typedef 名，此情况下相应地缺少 SIG_ATOMIC_* 与/或 WINT_* 宏。

整数类型极限

定义于头文件 <climits>
CHAR_BIT | 字节的位数 (宏常量)
MB_LEN_MAX | 多字节字符的最大字节数 (宏常量)
CHAR_MIN | char 的最小值 (宏常量)
CHAR_MAX | char 的最大值 (宏常量)
SCHAR_MINSHRT_MININT_MINLONG_MINLLONG_MIN (C++11) | 分别为 signed char、short、int、long 及 long long 的最小值 (宏常量)
SCHAR_MAXSHRT_MAXINT_MAXLONG_MAXLLONG_MAX (C++11) | 分别为 signed char、short、int、long 及 long long 的最大值 (宏常量)
UCHAR_MAXUSHRT_MAXUINT_MAXULONG_MAXULLONG_MAX (C++11) | 分别为 unsigned char、unsigned short、unsigned int、 unsigned long 及 unsigned long long 的最大值 (宏常量)

注意：这些常量，除了 CHAR_BIT 和 MB_LEN_MAX ，都要求其类型匹配整数提升的结果，一如应用于它们所描述的类型的对象： CHAR_MAX 可能拥有类型 int 或 unsigned int ，但决非 char 。同样地 USHRT_MAX 可能不拥有无符号类型：其类型可能是 int 。

浮点类型极限

定义于头文件 <cfloat>
FLT_RADIX | 所有三种浮点类型的表示所用的基数（整数底） (宏常量)
DECIMAL_DIG (C++11) | 从 long double 转换到至少有 DECIMAL_DIG 位数字的十进制表示，再转换回 long double 为恒等转换：这是序列化/反序列化 long double 所要求的十进制精度（参阅 std::numeric_limits::max_digits10） (宏常量)
FLT_DECIMAL_DIGDBL_DECIMAL_DIGLDBL_DECIMAL_DIG (C++17) | 从 float/double/long double 转换到至少有 FLT_DECIMAL_DIG/DBL_DECIMAL_DIG/LDBL_DECIMAL_DIG 位数字的十进制，再转换回原类型为恒等转换：这是序列化/反序列化浮点值所要求的十进制精度（参阅 std::numeric_limits::max_digits10）。分别定义为至少 6、10 和 10，对于 IEEE float 为 9，对于 IEEE double 为 17。 (宏常量)
FLT_MINDBL_MINLDBL_MIN | 分别为 float、double 与 long double 的最小规格化正数值 (宏常量)
FLT_TRUE_MINDBL_TRUE_MINLDBL_TRUE_MIN (C++17) | 分别为 float、double 与 long double 的最小正数值 (宏常量)
FLT_MAXDBL_MAXLDBL_MAX | 分别为 float、double 与 long double 的最大有限值 (宏常量)
FLT_EPSILONDBL_EPSILONLDBL_EPSILON | 分别为 1.0 和 float、double 及 long double 的下一个可表示值之差 (宏常量)
FLT_DIGDBL_DIGLDBL_DIG | 保证能在文本→ float/double/long double →文本的往返转换中保留而不会因舍入或溢出发生改变的的十进制位数（解释参阅 std::numeric_limits::digits10） (宏常量)
FLT_MANT_DIGDBL_MANT_DIGLDBL_MANT_DIG | 分别为能无精度损失地表示成 float、double 及 long double 的基数 FLT_RADIX 的数字位数 (宏常量)
FLT_MIN_EXPDBL_MIN_EXPLDBL_MIN_EXP | 分别为能够使FLT_RADIX 的该整数减一次幂为规格化的 float、double 与 long double 的最小负整数 (宏常量)
FLT_MIN_10_EXPDBL_MIN_10_EXPLDBL_MIN_10_EXP | 分别为能够使 10 的该整数减一次幂为规格化的 float、double 与 long double 的最小负整数 (宏常量)
FLT_MAX_EXPDBL_MAX_EXPLDBL_MAX_EXP | 分别为能够使 FLT_RADIX 的该整数减一次幂为可表示的有限的 float、double 与 long double 的最大正整数 (宏常量)
FLT_MAX_10_EXPDBL_MAX_10_EXPLDBL_MAX_10_EXP | 分别为能够使 10 的该整数减一次幂为可表示的有限的 float、double 与 long double 的最大正整数 (宏常量)
FLT_ROUNDS | 浮点算术的默认舍入模式 (宏常量)
FLT_EVAL_METHOD (C++11) | 指定进行所有算术运算所用的精度 (宏常量)
FLT_HAS_SUBNORMDBL_HAS_SUBNORMLDBL_HAS_SUBNORM (C++17) | 指明类型是否支持非正规数值：-1 为不确定，0 为不支持，1 为支持。 (宏常量)

参阅

  • 定宽整数类型
  • 算术类型
  • C++ 类型系统综述
  • 类型支持（基础类型、 RTTI 、类型特性）


FLT_EVAL_METHOD

< cpp‎ | types‎ | climits
定义于头文件 <cfloat> |
#define FLT_EVAL_METHOD /* implementation defined */ | (C++11 起)

指定异于赋值和转型的浮点算术运算中所用的精度。

值 | 解释
-1 外的负值 | 实现定义行为
-1 | 默认精度未知
0 | 以所用类型的范围和精度进行所有运算和常量求值。而且， float_t 和 double_t 分别等价于 float 和 double
1 | 以 double 的范围和精度进行所有运算和常量求值。而且， float_t 和 double_t 都等价于 double
2 | 以 long double 的范围和精度进行所有运算和常量求值。而且， float_t 和 double_t 都等价于 long double

注意

无关乎 FLT_EVAL_METHOD 的值，任何浮点表达式都可以被缩短，即如同所有中间结果拥有无限范围和精度一般进行（除非关闭 #pragma STDC FP_CONTRACT ）

转型和复制会剥除任何额外的范围和精度：这模拟从扩展精度 FPU 寄存器存储值到标准大小内存位置的动作。

参阅


FLT_ROUNDS

< cpp‎ | types‎ | climits
定义于头文件 <cfloat>
#define FLT_ROUNDS /* implementation defined */

指定浮点算术运算的当前舍入方向。

值 | 解释
-1 | 默认舍入方向未知
0 | 向零， FE_TOWARDZERO
1 | 向最近， FE_TONEAREST
2 | 向正无穷大， FE_UPWARD
3 | 向负无穷大， FE_DOWNWARD
其他值 | 实现定义行为

注意

舍入模式能以 std::fesetround 更改，而 FLT_ROUNDS 反应该更改。

FLT_ROUNDS 的可能值反映 std::numeric_limits::round_style 所返回的 std::float_round_style 的可能值。

参阅

float_round_style | 指示浮点舍入模式 (枚举)
fegetroundfesetround (C++11)(C++11) | 获取或设置舍入方向 (函数)


std::common_reference

< cpp‎ | types
定义于头文件 <type_traits> |
template< class... T > struct common_reference; | (C++20 起)

确定类型 T... 的共用引用类型，即 T... 中所有类型能转换或绑定到的类型。若这种类型存在（如按照后述规则所确定），则成员 type 指名该类型。否则，无成员 type 。若 T... 中的任何类型为（可有 cv 限定的） void 以外的不完整类型，则行为未定义。

给定引用类型是， common_reference 试图寻找所有提供的引用类型都能绑定到的引用类型，但若找不到这种引用类型，则可能返回非引用类型。

  • 若 sizeof...(T) 为零，则无成员 type 。
  • 若 sizeof...(T) 为一（即 T... 仅含一个类型 T0 ），则成员 type 指名与 T0 相同的类型。
  • 若 sizeof...(T) 为二（即 T... 含二个类型 T1 和 T2 ），则：
    • 若 T1 和 T2 都是引用类型，而 T1 和 T2 的简单共用引用类型 S 存在，则成员类型 type 指名 S ；
    • 否则，若 std::basic_common_reference<std::remove_cvref_t<T1>, std::remove_cvref_t<T2>, T1Q, T2Q>::type 存在，其中 TiQ 是一元别名模板，满足 TiQ<U> 为 U 带上 Ti 的 cv 及引用限定符，则成员类型 type 指名该类型；
    • 否则，若 decltype(false? val<T1>() : val<T2>()) 是合法类型，其中 val 为函数模板 template<class T> T val(); ，则成员类型 type 指名该类型；
    • 否则，若 std::common_type_t <T1, T2> 为合法类型，则成员类型 type 代表该类型；
    • 否则，无成员 type 。
  • 若 sizeof...(T) 大于二（即 T... 由 T1, T2, R... 组成），则若 std::common_reference_t<T1, T2> 存在，且 std::common_reference_t<std::common_reference_t<T1, T2>, R...> 存在，则成员类型 type 指代它。所有其他情况下，无成员类型 type 。

二个引用类型 T1 和 T2 的简单共用引用类型定义如下：

  • 若 T1 为 cv1 X & 而 T2 为 cv2 Y & （即都是左值引用）：则其简单共用引用类型为 decltype(false? std::declval <cv12 X &>() : std::declval <cv12 Y &>()) ，其中 cv12 为 cv1 与 cv2 的联合，若该类型存在且为引用类型；
  • 若 T1 a与 T2 均为右值引用类型：若 T1 & 和 T2 & 的简单共用引用类型（按照前一条确定）存在，则令 C 代表该类型的对应右值引用类型。若 std::is_convertible_v <T1, C> 与 std::is_convertible_v <T2, C> 均为 true ，则 T1 与 T2 的简单共用引用类型为 C 。
  • 否则，二个类型之一必须为左值引用类型 A & 而另一个必须为右值引用类型 B && （ A 与 B 可为 cv 限定）。令 D 代表 A & 与 B const & 的简单共用引用类型，若它存在。若 D 存在且 std::is_convertible_v <B &&, D> 为 true ，则简单共用引用类型为 D 。
  • 否则，无简单共用引用类型。

成员类型

名称 | 定义
type | 所有 T... 的共用引用类型

辅助类型

template< class... T >
using common_reference_t = typename std::common_reference<T...>::type;
template< class T, class U, template<class> class TQual, template<class> class UQual >
struct basic_common_reference { };

类模板 basic_common_reference 是定制点，允许用户影响 common_reference 对用户定义类型（常为代理引用）的结果。初等模板为空。

特化

若 std::is_same_v <T, std::decay_t <T>> 与 std::is_same_v <U, std::decay_t <U>> 皆为 true ，且它们至少有一个依赖于程序定义类型，则程序可以在前二个形参 T 和 U 上特化 std::basic_common_reference<T, U, TQual, UQual> 。

若这种特化拥有名为 type 的成员，则有限定标识 std::basic_common_reference<T, U, TQual, UQual>::type 必须合法并指名 TQual<T> 和 UQual<U> 都能转换到的类型的公开且无歧义的成员类型。另外， std::basic_common_reference<T, U, TQual, UQual>::type 和 std::basic_common_reference<U, T, UQual, TQual>::type 必须代表同一类型。

程序不可在第三或第四形参上特化 basic_common_reference ，亦不可特化 common_reference 自身。以违背这些规则的方式添加特化的程序拥有未定义行为。

注解

本节未完成

示例

本节未完成
原因：暂无示例

参阅

common_type (C++11) | 确定一组类型的公共类型 (类模板)
common_reference_with (C++20) | 指定两个类型共有一个公共引用类型 (概念)


std::common_type

< cpp‎ | types
定义于头文件 <type_traits> |
template< class... T > struct common_type; | (C++11 起)

确定所有类型 T... 的共用类型，即所有 T... 都能隐式转换到的类型。若这种类型（根据后述规则确定）存在，则成员 type 指名该类型。否则，无成员 type 。

  • 若 sizeof...(T) 为零，则无成员 type 。
  • 若 sizeof...(T) 为一（即 T... 只含一个类型 T0 ），则成员 type 指名与 std::common_type<T0, T0>::type 相同的类型，若它存在；否则无成员 type 。
  • 若 sizeof...(T) 为二（即 T... 含恰好二个成员 T1 与 T2 ），则
  • 若应用 std::decay 到至少 T1 与 T2 中至少一个类型后产生相异类型，则成员 type 指名与 std::common_type< std::decay <T1>::type, std::decay <T2>::type>::type 相同的类型，若它存在；若不存在，则无成员 type 。
  • 否则，若有对 std::common_type<T1, T2> 的用户定义特化，则使用该特化；
  • 否则， 若 std::decay <decltype(false ? std::declval <T1>() : std::declval <T2>())>::type 是合法类型，则成员 type 代表该类型；
  • 否则，若 std::decay <decltype(false ? std::declval <CR1>() : std::declval <CR2>())>::type 为合法类型，其中 CR1 与 CR2 分别为 const std::remove_reference_t <T1>& 与 const std::remove_reference_t <T2>&，则成员 type 代表该类型；
 (C++20 起)
  • 否则，无成员 type 。
  • 若 sizeof...(T) 大于二（即 T... 由类型 T1, T2, R... 组成），则若 std::common_type<T1, T2>::type 存在，则成员 type 指代 std::common_type<std::common_type<T1, T2>::type, R...>::type ，若存在这种类型。其他所有情况下，无成员 type 。

参数包 T 中的类型应均为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

成员类型

名称 | 定义
type | 所有 T... 的共用类型

辅助类型

template< class... T > using common_type_t = typename common_type<T...>::type; | (C++14 起)

特化

用户可为类型 T1 与 T2 特化 common_type ，只要

  • T1 与 T2 至少一个依赖于用户定义类型，且
  • std::decay 对于 T1 和 T2 都是同等变换。

若这种特化拥有名为 type 的成员，则有限定标识 std::common_type<T1, T2>::type 必须合法并指名一个 T1 和 T2 都能显式转换到的，无 cv 限定且非引用的类型。而且， std::common_type<T1, T2>::type 与 std::common_type<T2, T1>::type 必须指代同一类型。

以违背这些规则的方式添加 common_type 特化的程序拥有未定义行为。

注意添加特化到来自 <type_traits> 的任何其他模板（除了 std::basic_common_reference ） (C++20 起)的程序行为未定义。

标准库已提供下列特化：

std::common_type<std::chrono::duration> (C++11) | 特化 std::common_type 特征 (类模板特化)
std::common_type<std::chrono::time_point> (C++11) | 特化 std::common_type 特征 (类模板特化)

可能的实现

// 主模板（用于零个类型）
template<class...>
struct common_type {};

//////// 一个类型
template<class T>
struct common_type<T> : common_type<T, T> {};

namespace detail {
template<class...>
using void_t = void;

template<class T1, class T2>
using conditional_result_t = decltype(false ? std::declval<T1>() : std::declval<T2>());

template<class, class, class = void>
struct decay_conditional_result {};
template<class T1, class T2>
struct decay_conditional_result<T1, T2, void_t<conditional_result_t<T1, T2>>>
    : std::decay<conditional_result_t<T1, T2>> {};

template<class T>
using add_cref_t = // C++20 起使用
    typename std::add_lvalue_reference<
        const typename std::remove_reference<T>::type>::type;

template<class T1, class T2, class = void>
struct common_type_2_impl : decay_conditional_result<add_cref_t<T1>, add_cref_t<T2>> {};

// C++11 实现：
// template<class, class, class = void>
// struct common_type_2_impl {};

template<class T1, class T2>
struct common_type_2_impl<T1, T2, void_t<conditional_result_t<
    typename std::decay<T1>::type,
    typename std::decay<T2>::type>>>
    : decay_conditional_result<typename std::decay<T1>::type,
                               typename std::decay<T2>::type> {};
}

//////// 二个类型
struct common_type<T1, T2>
    : std::conditional<std::is_same<T1, typename std::decay<T1>::type>::value &&
                       std::is_same<T2, typename std::decay<T2>::type>::value,
                       detail::common_type_2_impl<T1, T2>,
                       common_type<typename std::decay<T1>::type,
                                   typename std::decay<T2>::type>>::type {};

//////// 三个及以上类型
namespace detail {
template<class AlwaysVoid, class T1, class T2, class...R>
struct common_type_multi_impl {};
template<class T1, class T2, class...R>
struct common_type_multi_impl<void_t<typename common_type<T1, T2>::type>, T1, T2, R...>
    : common_type<typename common_type<T1, T2>::type, R...> {};
}

template<class T1, class T2, class... R>
struct common_type<T1, T2, R...>
    : detail::common_type_multi_impl<void, T1, T2, R...> {};

注解

对于不是提升目标的算术类型，共用类型可视为如 T0() + T1() + ... + Tn() 的（可以为混合模式的）算术表达式的类型。

示例

演示用户定义类上的混合模式算术

#include <iostream>
#include <type_traits>

template <class T>
struct Number { T n; };

template <class T, class U>
Number<typename std::common_type<T, U>::type> operator+(const Number<T>& lhs,
                                                        const Number<U>& rhs)
{
    return {lhs.n + rhs.n};
}

int main()
{
    Number<int> i1 = {1}, i2 = {2};
    Number<double> d1 = {2.3}, d2 = {3.5};
    std::cout << "i1i2: " << (i1 + i2).n << "\ni1d2: " << (i1 + d2).n << '\n'
              << "d1i2: " << (d1 + i2).n << "\nd1d2: " << (d1 + d2).n << '\n';
}

输出：

i1i2: 3
i1d2: 4.5
d1i2: 4.3
d1d2: 5.8

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2141 | C++11 | common_type<int, int>::type 为 int&& | 退化了结果类型
LWG 2408 | C++11 | common_type 非 SFINAE 友好 | 令之为 SFINAE 友好
LWG 2460 | C++11 | common_type 特化的书写近乎不可能 | 减少了需要的特化数量


std::conditional

< cpp‎ | types
定义于头文件 <type_traits> |
template< bool B, class T, class F > struct conditional; | (C++11 起)

提供成员 typedef type ，若 B 在编译时为 true 则定义为 T ，或若 B 为 false 则定义为 F 。

添加 conditional 的特化的程序行为未定义。

成员类型

成员类型 | 定义
type | 若 B == true 则为 T ，若 B == false 则为 F

辅助类型

template< bool B, class T, class F > using conditional_t = typename conditional<B,T,F>::type; | (C++14 起)

可能的实现

template<bool B, class T, class F>
struct conditional { typedef T type; };

template<class T, class F>
struct conditional<false, T, F> { typedef F type; };

示例

#include <iostream>
#include <type_traits>
#include <typeinfo>

int main()
{
    typedef std::conditional<true, int, double>::type Type1;
    typedef std::conditional<false, int, double>::type Type2;
    typedef std::conditional<sizeof(int) >= sizeof(double), int, double>::type Type3;

    std::cout << typeid(Type1).name() << '\n';
    std::cout << typeid(Type2).name() << '\n';
    std::cout << typeid(Type3).name() << '\n';
}

可能的输出：

int
double
double

参阅

enable_if
(C++11)
 条件性地从重载决议移除函数重载或模板特化
(类模板)


std::conjunction

< cpp‎ | types
定义于头文件 <type_traits> |
template<class... B> struct conjunction; | (C++17 起)

组成类型特性 B... 的逻辑合取，等效地在特性序列上进行逻辑与。

特化 std::conjunction<B1, ..., BN> 有一个公开且无歧义的基类，即

  • 若 sizeof...(B) == 0 ，则是 std::true_type ；否则
  • 若 B1, ..., BN 中有 bool(Bi::value) == false ，则为首个 Bi ，否则若无这种类型，则为 BN 。

不隐藏 conjunction 及 operator= 以外的基类成员名，而它们在 conjunction 中无歧义地可用。

合取是短路的：若存在模板类型参数 Bi 满足 bool(Bi::value) == false ，则实例化 conjunction<B1, ..., BN>::value 不要求 j > i 的 Bj::value 的实例化。

添加 conjunction 或 conjunction_v 的特化的程序行为未定义。

模板形参

B... - 每个要实例化 Bi::value 的模板参数 Bi 必须可用作基类，且定义了可转换到 bool 的成员 value

辅助变量模板

template<class... B> inline constexpr bool conjunction_v = conjunction<B...>::value; | (C++17 起)

可能的实现

template<class...> struct conjunction : std::true_type { };
template<class B1> struct conjunction<B1> : B1 { };
template<class B1, class... Bn>
struct conjunction<B1, Bn...>
    : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};

注解

conjunction 的特化不需要继承自 std::true_type 或 std::false_type ：它简单地继承自首个 B ，其 ::value 显式转换为 bool 后为 false ，或在它们都转换为 true 时继承自最后的 B 。例如， std::conjunction< std::integral_constant <int, 2>, std::integral_constant <int, 4>>::value 为 4 。

conjunction 的短路实例化异于折叠表达式：类似 (... && Bs::value) 的折叠表达式实例化 Bs 中的每个 B ，而 std::conjunction_v<Bs...> 一旦能确定值就停止实例化。若之后的类型实例化代价高昂，或以错误类型实例化时能导致硬错误，则这特别有用。

示例

#include <iostream>
#include <type_traits>

// 若所有 Ts... 都拥有等同于 T 的类型，则启用 func
template<typename T, typename... Ts>
std::enable_if_t<std::conjunction_v<std::is_same<T, Ts>...>>
func(T, Ts...) {
    std::cout << "all types in pack are T\n";
}

// 否则
template<typename T, typename... Ts>
std::enable_if_t<!std::conjunction_v<std::is_same<T, Ts>...>>
func(T, Ts...) {
    std::cout << "not all types in pack are T\n";
}

int main() {
    func(1, 2, 3);
    func(1, 2, "hello!");
}

输出：

all types in pack are T
not all types in pack are T

参阅

negation (C++17) | 逻辑非元函数 (类模板)
disjunction (C++17) | 变参的逻辑或元函数 (类模板)


std::decay

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct decay; | (C++11 起)

对类型 T 应用左值到右值、数组到指针及函数到指针隐式转换，移除 cv 限定符，并定义结果类型为成员 typedef type 。正式而言：

  • 若T 指名“ U 的数组”或“到 U 的数组的引用”类型，则成员 typedef type 为 U* 。
  • 否则，若 T 为函数类型 F 或到它的引用，则成员 typedef type 为std::add_pointer <F>::type 。
  • 否则，成员 typedef type 为 std::remove_cv < std::remove_reference <T>::type>::type 。

这些转换模仿在以值传递时，应用到所有函数参数的类型转换。

添加 decay 的特化的程序行为未定义。

成员类型

名称 | 定义
type | 应用退化类型转换到 T 的结果

辅助类型

template< class T > using decay_t = typename decay<T>::type; | (C++14 起)

可能的实现

template< class T >
struct decay {
private:
    typedef typename std::remove_reference<T>::type U;
public:
    typedef typename std::conditional<
        std::is_array<U>::value,
        typename std::remove_extent<U>::type*,
        typename std::conditional<
            std::is_function<U>::value,
            typename std::add_pointer<U>::type,
            typename std::remove_cv<U>::type
        >::type
    >::type type;
};

示例

#include <iostream>
#include <type_traits>

template <typename T, typename U>
struct decay_equiv :
    std::is_same<typename std::decay<T>::type, U>::type
{};

int main()
{
    std::cout << std::boolalpha
              << decay_equiv<int, int>::value << '\n'
              << decay_equiv<int&, int>::value << '\n'
              << decay_equiv<int&&, int>::value << '\n'
              << decay_equiv<const int&, int>::value << '\n'
              << decay_equiv<int[2], int*>::value << '\n'
              << decay_equiv<int(int), int(*)(int)>::value << '\n';
}

输出：

true
true
true
true
true
true

参阅

remove_cvref (C++20) | 将 std::remove_cv 与 std::remove_reference 结合 (类模板)
隐式转换 | 数组到指针、函数到指针、左值到右值转换


std::disjunction

< cpp‎ | types
定义于头文件 <type_traits> |  |
template<class... B> struct disjunction; | (1) | (C++17 起)

组成类型特性 B... 的逻辑析取，等效地在特性序列上进行逻辑或。

特化 std::disjunction<B1, ..., BN> 有一个公开且无歧义的基类，即

  • 若 sizeof...(B) == 0 ，则为 std::false_type ；否则
  • 若 B1, ..., BN 中有 bool(Bi::value) == true ，则为首个 Bi ，或者若无这种类型则为 BN 。

不隐藏 disjunction 和 operator= 以外的基类成员名，而它们在 disjunction 中无歧义地可用。

析取是短路的：若存在模板类型参数 Bi 满足 bool(Bi::value) != false，则实例化 disjunction<B1, ..., BN>::value 不要求 j > i 的 Bj::value 的实例化。

添加 disjunction 或 disjunction_v 的特化的程序行为未定义。

模板形参

B... - 每个要实例化 Bi::value 的模板参数 Bi 必须可用作基类，且定义了可转换到 bool 的成员 value

辅助变量模板

template<class... B> inline constexpr bool disjunction_v = disjunction<B...>::value; | (C++17 起)

可能的实现

template<class...> struct disjunction : std::false_type { };
template<class B1> struct disjunction<B1> : B1 { };
template<class B1, class... Bn>
struct disjunction<B1, Bn...>
    : std::conditional_t<bool(B1::value), B1, disjunction<Bn...>>  { };

注解

disjunction 的特化不需要继承自 std::true_type 或 std::false_type ：它简单地继承自首个 B ，其 ::value 在显式转换为 bool 后为 true ，或在它们都转换为 false 时继承自最后的 B 。例如， std::disjunction< std::integral_constant <int, 2>, std::integral_constant <int, 4>>::value 为 2 。

disjunction 的短路实例化异于折叠表达式：如 (... || Bs::value) 的折叠表达式实例化 Bs 中的每个 B ，而 std::disjunction_v<Bs...> 一旦能确定值就停止实例化。这在之后的类型实例化代价高昂，或以错误的类型实例化能导致硬错误时特别有用。

示例

{{example|code=

#include <type_traits>
#include <cstdint>
#include <string>

// values_equal<a, b, T>::value 为 true 当且仅当 a == b 。
template <auto V1, decltype(V1) V2, typename T>
struct values_equal : std::bool_constant<V1 == V2> {
  using type = T;
};

// default_type<T>::value 始终为 true
template <typename T>
struct default_type : std::true_type {
  using type = T;
};

// 现在我们可以像 switch 语句一样使用 disjunction ：
template <int I>
using int_of_size = typename std::disjunction<  //
    values_equal<I, 1, std::int8_t>,            //
    values_equal<I, 2, std::int16_t>,           //
    values_equal<I, 4, std::int32_t>,           //
    values_equal<I, 8, std::int64_t>,           //
    default_type<void>                          // 必须在最后！
    >::type;

static_assert(sizeof(int_of_size<1>) == 1);
static_assert(sizeof(int_of_size<2>) == 2);
static_assert(sizeof(int_of_size<4>) == 4);
static_assert(sizeof(int_of_size<8>) == 8);
static_assert(std::is_same_v<int_of_size<13>, void>);

// 检查 Foo 是否可从 double 构造将导致硬错误
struct Foo {
    template<class T>
    struct sfinae_unfriendly_check { static_assert(!std::is_same_v<T, double>); };

    template<class T>
    Foo(T, sfinae_unfriendly_check<T> = {} );
};

template<class... Ts>
struct first_constructible {
    template<class T, class...Args>
    struct is_constructible_x : std::is_constructible<T, Args...> {
        using type = T;
    };
    struct fallback {
        static constexpr bool value = true;
        using type = void; // 若找不到则用于返回的类型
    };

    template<class... Args>
    using with = typename std::disjunction<is_constructible_x<Ts, Args...>...,
                                           fallback>::type;
};

// OK ，不实例化 is_constructible<Foo, double>
static_assert(std::is_same_v<first_constructible<std::string, int, Foo>::with<double>,
                             int>);

static_assert(std::is_same_v<first_constructible<std::string, int>::with<>, std::string>);
static_assert(std::is_same_v<first_constructible<std::string, int>::with<const char*>,
                             std::string>);
static_assert(std::is_same_v<first_constructible<std::string, int>::with<void*>, void>);

int main() { }

参阅

negation (C++17) | 逻辑非元函数 (类模板)
conjunction (C++17) | 变参的逻辑与元函数 (类模板)


std::enable_if

< cpp‎ | types
定义于头文件 <type_traits> |
template< bool B, class T = void > struct enable_if; | (C++11 起)

若 B 为 true ，则 std::enable_if 拥有等同于 T 的公开成员 typedef type ；否则，无该成员 typedef 。

此元函数是活用 SFINAE ，基于类型特性条件性地从重载决议移除函数，并对不同类型特性提供分离的函数重载与特化的便利方法。 std::enable_if 可用作额外的函数参数（不可应用于运算符重载）、返回类型（不可应用于构造函数与析构函数），或类模板或函数模板形参。

添加 enable_if 的特化的程序行为未定义。

成员类型

类型 | 定义
type | 依赖 B 的值，为 T 或无此成员

辅助类型

template< bool B, class T = void > using enable_if_t = typename enable_if<B,T>::type; | (C++14 起)

可能的实现

template<bool B, class T = void>
struct enable_if {};

template<class T>
struct enable_if<true, T> { typedef T type; };

注解

常见错误是声明二个函数模板，而它们仅于其默认模板实参相异。这是无效的，因为这些函数声明被当做同一函数模板的再声明（默认模板实参不为函数模板等价所考虑）。

/* WRONG */

struct T {
    enum { int_t,float_t } m_type;
    template <typename Integer,
              typename = std::enable_if_t<std::is_integral_v<Integer>>
    >
    T(Integer) : m_type(int_t) {}

    template <typename Floating,
              typename = std::enable_if_t<std::is_floating_point_v<Floating>>
    >
    T(Floating) : m_type(float_t) {} // 错误：不能重载
};

/* RIGHT */

struct T {
    enum { int_t,float_t } m_type;
    template <typename Integer,
              std::enable_if_t<std::is_integral_v<Integer>, int> = 0
    >
    T(Integer) : m_type(int_t) {}

    template <typename Floating,
              std::enable_if_t<std::is_floating_point_v<Floating>, int> = 0
    >
    T(Floating) : m_type(float_t) {} // OK
};

于命名空间函数模板作用域的模板非类型形参中使用 enable_if 时需留意。某些 ABI 规范，如 Itanium ABI ，不于重整中包含非类型模板形参的实例化依赖部分。这表示可能以相同重整名归纳二个相异的函数模板特化，并且错误地相互链接。例如：

// 第一个翻译单元

struct X {
    enum { value1 = true, value2 = true };
};

template<class T, std::enable_if_t<T::value1, int> = 0>
void func() {} // #1

template void func<X>(); // #2

// 第二个翻译单元

struct X {
    enum { value1 = true, value2 = true };
};

template<class T, std::enable_if_t<T::value2, int> = 0>
void func() {} // #3

template void func<X>(); //#4

函数模板 #1 与 #3 拥有不同签名，且为不同的模板。不过 #2 与 #4 尽管是不同函数模板的实例化，却于 Itanium C++ ABI 拥有相同的重整名（ _Z4funcI1XLi0EEvv ），这表示链接器会错误地认为它们是同一实体。

示例

#include <type_traits>
#include <new>
#include <iostream>
#include <string>

namespace detail {

void* voidify(const volatile void* ptr) noexcept { return const_cast<void*>(ptr); }

}

// #1 ，经由返回类型启用
template<class T>
typename std::enable_if<std::is_trivially_default_constructible<T>::value>::type
    construct(T*)
{
    std::cout << "default constructing trivially default constructible T\n";
}

// 同上
template<class T>
typename std::enable_if<!std::is_trivially_default_constructible<T>::value>::type
    construct(T* p)
{
    std::cout << "default constructing non-trivially default constructible T\n";
    ::new(detail::voidify(p)) T;
}

// #2
template<class T, class... Args>
std::enable_if_t<std::is_constructible<T, Args&&...>::value> // Using helper type
    construct(T* p, Args&&... args)
{
    std::cout << "constructing T with operation\n";
    ::new(detail::voidify(p)) T(static_cast<Args&&>(args)...);
}

// #3 ，经由参数启用
template<class T>
void destroy(
    T*,
    typename std::enable_if<
        std::is_trivially_destructible<T>::value
    >::type* = 0
){
    std::cout << "destroying trivially destructible T\n";
}

// #4 ，经由非类型模板形参启用
template<class T,
         typename std::enable_if<
             !std::is_trivially_destructible<T>{} &&
             (std::is_class<T>{} || std::is_union<T>{}),
            int>::type = 0>
void destroy(T* t)
{
    std::cout << "destroying non-trivially destructible T\n";
    t->~T();
}

// #5 ，经由类型模板形参启用
template<class T,
        typename = std::enable_if_t<std::is_array<T>::value> >
void destroy(T* t) // 注：不修改函数签名
{
    for(std::size_t i = 0; i < std::extent<T>::value; ++i) {
        destroy((*t)[i]);
    }
}
/*
template<class T,
        typename = std::enable_if_t<std::is_void<T>::value> >
void destroy(T* t){} // 错误：函数签名与 #5 相同
*/

// 经由模板形参启用 A 的偏特化
template<class T, class Enable = void>
class A {}; // 初等模板

template<class T>
class A<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
}; // 浮点类型的特化

int main()
{
    std::aligned_union_t<0,int,std::string> u;

    construct(reinterpret_cast<int*>(&u));
    destroy(reinterpret_cast<int*>(&u));

    construct(reinterpret_cast<std::string*>(&u),"Hello");
    destroy(reinterpret_cast<std::string*>(&u));

    A<int>{}; // OK ：匹配初等模板
    A<double>{}; // OK ：匹配偏特化+
}

输出：

default constructing trivially default constructible T
destroying trivially destructible T
constructing T with operation
destroying non-trivially destructible T

参阅

void_t
(C++17)
 void 变参别名模板
(别名模板)
  • static_assert
  • SFINAE


std::endian

< cpp‎ | types
定义于头文件 <bit> |
enum class endian { little = /*implementation-defined*/, big = /*implementation-defined*/, native = /*implementation-defined*/ }; | (C++20 起)

指示所有标量类型的端序：

  • 若所有标量类型均为小端，则 std::endian::native 等于 std::endian::little
  • 若所有标量类型均为大端，则 std::endian::native 等于 std::endian::big

亦支持极端情况：

  • 若所有标量类型拥有等于 1 的 sizeof ，则端序无影响，且 std::endian::little, std::endian::big 及 std::endian::native 三个值相同
  • 若平台使用混合端序，则 std::endian::native 既不等于 std::endian::big 亦不等于 std::endian::little

可能的实现

enum class endian
{
#ifdef _WIN32
    little = 0,
    big    = 1,
    native = little
#else
    little = __ORDER_LITTLE_ENDIAN__,
    big    = __ORDER_BIG_ENDIAN__,
    native = __BYTE_ORDER__
#endif
};

示例

#include <bit>
#include <iostream>

int main() {

    if constexpr (std::endian::native == std::endian::big)
        std::cout << "big-endian\n";
    else if constexpr (std::endian::native == std::endian::little)
        std::cout << "little-endian\n";
    else std::cout << "mixed-endian\n";
}

可能的输出：

little-endian

参阅

byteswap
(C++23)
 反转给定整数值中的字节
(函数模板)


std::extent

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T, unsigned N = 0> struct extent; | (C++11 起)

若 T 是数组类型，则提供等于数组第 N 维元素数量的成员常量 value ，若 N 在 [0, std::rank<T>::value) 中。对于任何其他类型，或若 T 是在其首维度未知边界数组且 N 为 0 ，则 value 为 0 。

添加 extent 或 extent_v (C++17 起) 的特化的程序行为未定义。

辅助变量模板

template< class T, unsigned N = 0 > inline constexpr std::size_t extent_v = extent<T, N>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 T 的第 N 维的元素数
(公开静态成员常量)

成员函数

operator std::size_t | 转换对象为 std::size_t ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | std::size_t
type | std::integral_constant < std::size_t, value>

可能的实现

template<class T, unsigned N = 0>
struct extent : std::integral_constant<std::size_t, 0> {};

template<class T>
struct extent<T[], 0> : std::integral_constant<std::size_t, 0> {};

template<class T, unsigned N>
struct extent<T[], N> : std::extent<T, N-1> {};

template<class T, std::size_t I>
struct extent<T[I], 0> : std::integral_constant<std::size_t, I> {};

template<class T, std::size_t I, unsigned N>
struct extent<T[I], N> : std::extent<T, N-1> {};

示例

#include <iostream>
#include <type_traits>

int main()
{
    std::cout << std::extent<int[3]>::value << '\n'; // < 默认维度为 0
    std::cout << std::extent<int[3][4], 0>::value << '\n';
    std::cout << std::extent<int[3][4], 1>::value << '\n';
    std::cout << std::extent<int[3][4], 2>::value << '\n';
    std::cout << std::extent<int[]>::value << '\n';

    const auto ext = std::extent<int[9]>{};
    std::cout << ext << '\n'; // < 隐式转换到 std::size_t

    const int ints[] = {1,2,3,4};
    std::cout << std::extent<decltype(ints)>::value << '\n'; // < 数组大小
}

输出：

3
3
4
0
0
9
4

参阅

is_array (C++11) | 检查类型是否是数组类型 (类模板)
rank (C++11) | 获取数组类型的维数 (类模板)
remove_extent (C++11) | 从给定数组类型移除一个维度 (类模板)
remove_all_extents (C++11) | 移除给定数组类型的所有维度 (类模板)


std::has_strong_structural_equality

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct has_strong_structural_equality; | (C++20 起)

若 T 拥有强结构相等性，则提供等于 true 的成员常量 value 。对于任何其他类型 value 为 false 。

添加 has_strong_structural_equality 或 has_strong_structural_equality_v 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool has_strong_structural_equality_v = has_strong_structural_equality<T>::value; | (C++20 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 拥有强结构相等性则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注解

此类型特征可用于检查一个类型能否用作非类型模板形参。

示例

#include <type_traits>
#include <cstring>
#include <algorithm>
#include <iostream>

template<std::size_t N>
struct fixed_string {
    constexpr fixed_string(const char (&s)[N + 1])
    {
        std::copy_n(s, N + 1, m_data);
    }
    bool operator==(const fixed_string&) const = default;

    char m_data[N + 1];
};

template<std::size_t N>
struct broken_fixed_string {
    constexpr broken_fixed_string(const char (&s)[N + 1])
    {
        std::copy_n(s, N + 1, m_data);
    }
    bool operator==(const broken_fixed_string &rhs) const
    {
        return std::memcmp(m_data, rhs.m_data, N + 1) == 0;
    }

    char m_data[N + 1];
};

int main()
{
    std::cout
        << std::boolalpha
        << std::has_strong_structural_equality_v<fixed_string<42>> << '\n'
        << std::has_strong_structural_equality_v<broken_fixed_string<42>> << '\n';
}

输出：

true
false

参阅


std::has_unique_object_representations

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct has_unique_object_representations; | (C++17 起)

若 T 为可平凡复制 (TriviallyCopyable) ，且若任意二个拥有相同值的 T 类型对象拥有相同的对象表示，则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

为此特性的目的，若二个数组的元素拥有相同值，则数组拥有相同值，若二个非联合体类的子对象拥有相同值，则它们拥有相同值，而若二个联合体拥有相同的活跃成员，且该成员值相同，则它们拥有相同值。

标量类型是否满足此特性是实现定义的，但保证不使用填充位的无符号 (C++20 前)整数类型拥有唯一对象表示。

若 T 为 void （可以有 cv 限定）或未知边界数组外的不完整类型，则行为未定义。

添加 has_unique_object_representations 或 has_unique_object_representations_v 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool has_unique_object_representations_v = has_unique_object_representations<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 拥有唯一对象表示则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注意

引入此特性，是为了能够确定是否能通过哈希一个类型的对象表示，正确地哈希该类型。

示例

#include <iostream>
#include <type_traits>

struct bar
{
    int a;
    int b;
};

struct foo
{
    char c;
    float f;
    short st;
    int i;
};

int main()
{
     std::cout  << std::boolalpha
                << "Does foo have unique object representations? "
                << std::has_unique_object_representations_v<foo> << '\n'
                << "Does bar have unique object representations? "
                << std::has_unique_object_representations_v<bar> << '\n';
}

可能的输出：

Does foo have unique object representations? false
Does bar have unique object representations? true

参阅

is_standard_layout (C++11) | 检查是否是一个标准布局类型 (类模板)
hash (C++11) | 散列函数对象 (类模板)


std::has_virtual_destructor

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct has_virtual_destructor; | (C++11 起)

若 T 是拥有虚析构函数的类型，则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

若 T 是非联合类类型，则 T 应为完整类型；否则行为未定义。

添加 has_virtual_destructor 或 has_virtual_destructor_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool has_virtual_destructor_v = has_virtual_destructor<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 拥有虚析构函数则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注解

若类拥有公开虚析构函数，则可以从它派生，且可以通过指向基类的指针安全地删除派生类（ GotW #18 ）

示例

#include <iostream>
#include <type_traits>
#include <string>
#include <stdexcept>

int main()
{
    std::cout << std::boolalpha
              << "std::string has a virtual destructor? "
              << std::has_virtual_destructor<std::string>::value << '\n'
              << "std::runtime_error has a virtual destructor? "
              << std::has_virtual_destructor<std::runtime_error>::value << '\n';
}

输出：

std::string has a virtual destructor? false
std::runtime_error has a virtual destructor? true

参阅

is_destructibleis_trivially_destructibleis_nothrow_destructible
(C++11)(C++11)(C++11)
 检查类型是否拥有未被弃置的析构函数
(类模板)


定宽整数类型 (C++11 起)

< cpp‎ | types

类型

定义于头文件 <cstdint>
int8_tint16_tint32_tint64_t (可选) | 分别为宽度恰为 8、16、32 和 64 位的有符号整数类型 无填充位并对负值使用补码 （仅若实现支持该类型才提供） (typedef)
int_fast8_tint_fast16_tint_fast32_tint_fast64_t | 分别为宽度至少有 8、16、32 和 64 位的最快的有符号整数类型 (typedef)
int_least8_tint_least16_tint_least32_tint_least64_t | 分别为宽度至少有 8、16、32 和 64 位的最小的有符号整数类型 (typedef)
intmax_t | 最大宽度的有符号整数类型 (typedef)
intptr_t (可选) | 足以保有指针的有符号整数类型 (typedef)
uint8_tuint16_tuint32_tuint64_t (可选) | 宽度恰为 8、16、32 和 64 位的无符号整数类型 （仅若实现支持该类型才提供） (typedef)
uint_fast8_tuint_fast16_tuint_fast32_tuint_fast64_t | 分别为宽度至少有 8、16、32 和 64 位的最快无符号整数类型 (typedef)
uint_least8_tuint_least16_tuint_least32_tuint_least64_t | 分别为宽度至少有 8、16、32 和 64 位的最小无符号整数类型 (typedef)
uintmax_t | 最大宽度的无符号整数类型 (typedef)
uintptr_t (可选) | 足以保有指针的无符号整数类型 (typedef)

实现可在 N 不是 8、 16、 32 或 64 时定义 typedef 名 intN_t、 int_fastN_t、 int_leastN_t、 uintN_t、 uint_fastN_t 及 uint_leastN_t 。形为 intN_t 的 typedef 名仅若实现支持有该宽度而无填充的整数类型才可以得以定义。从而 uint24_t 代表宽度准确地为 24 位的无符号整数类型。

下面列出的每个宏当且仅当实现定义对应的 typedef 名时才得以定义。宏 INTN_C 与 UINTN_C 分别对应 typedef 名 int_leastN_t 与 uint_leastN_t 。

宏常量

定义于头文件 <cstdint>
有符号整数：最小值
INT8_MININT16_MININT32_MININT64_MIN
(可选)
 int8_t、int16_t、int32_t、int64_t 类型对象的最小值
(宏常量)
INT_FAST8_MININT_FAST16_MININT_FAST32_MININT_FAST64_MIN
 int_fast8_t、int_fast16_t、int_fast32_t、int_fast64_t 类型对象的最小值
(宏常量)
INT_LEAST8_MININT_LEAST16_MININT_LEAST32_MININT_LEAST64_MIN
 int_least8_t、int_least16_t、int_least32_t、int_least64_t 类型对象的最小值
(宏常量)
INTPTR_MIN
(可选)
 intptr_t 类型对象的最小值
(宏常量)
INTMAX_MIN
 intmax_t 类型对象的最小值
(宏常量)
有符号整数：最大值
INT8_MAXINT16_MAXINT32_MAXINT64_MAX
(可选)
 int8_t、int16_t、int32_t、int64_t 类型对象的最大值
(宏常量)
INT_FAST8_MAXINT_FAST16_MAXINT_FAST32_MAXINT_FAST64_MAX
 int_fast8_t、int_fast16_t、int_fast32_t、int_fast64_t 类型对象的最大值
(宏常量)
INT_LEAST8_MAXINT_LEAST16_MAXINT_LEAST32_MAXINT_LEAST64_MAX
 int_least8_t、int_least16_t、int_least32_t、int_least64_t 类型对象的最大值
(宏常量)
INTPTR_MAX
(可选)
 intptr_t 类型对象的最大值
(宏常量)
INTMAX_MAX
 intmax_t 类型对象的最大值
(宏常量)
无符号整数：最大值
UINT8_MAXUINT16_MAXUINT32_MAXUINT64_MAX
(可选)
 uint8_t、uint16_t、uint32_t、uint64_t 类型对象的最大值
(宏常量)
UINT_FAST8_MAXUINT_FAST16_MAXUINT_FAST32_MAXUINT_FAST64_MAX
 uint_fast8_t、uint_fast16_t、uint_fast32_t、uint_fast64_t 类型对象的最大值
(宏常量)
UINT_LEAST8_MAXUINT_LEAST16_MAXUINT_LEAST32_MAXUINT_LEAST64_MAX
 uint_least8_t、uint_least16_t、uint_least32_t、uint_least64_t 类型对象的最大值
(宏常量)
UINTPTR_MAX
(可选)
 uintptr_t 类型对象的最大值
(宏常量)
UINTMAX_MAX
 uintmax_t 类型对象的最大值
(宏常量)

最小宽度整数常量的函数宏

INT8_CINT16_CINT32_CINT64_C | 展开成拥有其实参所指定的值且类型分别为 int_least8_t、int_least16_t、int_least32_t、int_least64_t 的提升类型的整数常量表达式 (宏函数)
INTMAX_C | 展开成拥有其实参所指定的值且类型为 intmax_t 的整数常量表达式 (宏函数)
UINT8_CUINT16_CUINT32_CUINT64_C | 展开成拥有其实参所指定的值且类型分别为 uint_least8_t、uint_least16_t、uint_least32_t、uint_least64_t 的提升类型的整数常量表达式 (宏函数)
UINTMAX_C | 展开成拥有其实参所指定的值且类型为 uintmax_t 的整数常量表达式 (宏函数)
#include <cstdint>
UINT64_C(0x123) // 展开成类型为 uint64_t 而值为 0x123 的字面量

格式宏常量

定义于头文件 <cinttypes>

std::fprintf 系列函数的格式宏常量

此处列出的每个 PRI 宏当且仅当实现定义对应的 typedef 名才得以定义。

int 或 unsigned int 的等价者 | 描述 | 数据类型的宏
 |  | std::int x_t | std::int_least x_t | std::int_fast x_t | std::intmax_t | std::intptr_t
d | 有符号十进制整数值的输出 | PRIdx | PRIdLEASTx | PRIdFASTx | PRIdMAX | PRIdPTR
i |  | PRIix | PRIiLEASTx | PRIiFASTx | PRIiMAX | PRIiPTR
u | 无符号十进制整数值的输出 | PRIux | PRIuLEASTx | PRIuFASTx | PRIuMAX | PRIuPTR
o | 无符号八进制整数值的输出 | PRIox | PRIoLEASTx | PRIoFASTx | PRIoMAX | PRIoPTR
x | 无符号小写十六进制整数值的输出 | PRIxx | PRIxLEASTx | PRIxFASTx | PRIxMAX | PRIxPTR
X | 无符号大写十六进制整数值的输出 | PRIXx | PRIXLEASTx | PRIXFASTx | PRIXMAX | PRIXPTR

std::fscanf 系列函数的格式宏常量

此处列出的每个 SCN 宏当且仅当实现定义对应的 typedef 名且拥有适合该类型的 std::fscanf 长度修饰符才得以定义。

int 或 unsigned int 的等价者 | 描述 | 数据类型的宏
 |  | std::int x_t | std::int_least x_t | std::int_fast x_t | std::intmax_t | std::intptr_t
d | 有符号十进制整数值的输入 | SCNdx | SCNdLEASTx | SCNdFASTx | SCNdMAX | SCNdPTR
i | 有符号整数值的输入 | SCNix | SCNiLEASTx | SCNiFASTx | SCNiMAX | SCNiPTR
u | 无符号十进制整数值的输入 | SCNux | SCNuLEASTx | SCNuFASTx | SCNuMAX | SCNuPTR
o | 无符号八进制整数值的输入 | SCNox | SCNoLEASTx | SCNoFASTx | SCNoMAX | SCNoPTR
x | 无符号十六进制整数值的输入 | SCNxx | SCNxLEASTx | SCNxFASTx | SCNxMAX | SCNxPTR

注解

因为 C++ 转译立即后随字符串字面量的字符为用户定义字面量，诸如 printf("%"PRId64"\n",n); 的 C 代码在 C++ 中非法，并在 PRId64 前要求空格。

C99 标准建议 C++ 实现不应定义上述极限、常量或格式化宏，除非在包含相对的 C 头文件（ stdint.h 或 inttypes.h ）前（分别）定义宏 __STDC_LIMIT_MACROS 、 __STDC_CONSTANT_MACROS 或 __STDC_FORMAT_MACROS 。此建议未被采纳，并在 C11 中被移除。然而，某些实现（例如 glibc 2.17 ）尝试应用此规则，而可能需要定义 __STDC 宏； C++ 编译器可以通过在某些环境自动定义它们来做变通。

示例

#include <cstdio>
#include <cinttypes>

int main()
{
    std::printf("%zu\n", sizeof(std::int64_t));
    std::printf("%s\n", PRId64);
    std::printf("%+" PRId64 "\n", INT64_MIN);
    std::printf("%+" PRId64 "\n", INT64_MAX);

    std::int64_t n = 7;
    std::printf("%+" PRId64 "\n", n);
}

可能的输出：

8
lld
-9223372036854775808
+9223372036854775807
+7

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2820 | C++11 | 可选的 typedef 名与宏的要求与 C 不一致 | 使得一致

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 17.4 Integer types [cstdint]
  • 29.12.2 Header <cinttypes> synopsis [cinttypes.syn]
  • C++17 标准（ISO/IEC 14882:2017）：
  • 21.4 Integer types [cstdint]
  • 30.11.2 Header <cinttypes> synopsis [cinttypes.syn]
  • C++14 标准（ISO/IEC 14882:2014）：
  • 18.4 Integer types [cstdint]
  • 27.9.2 C library files [c.files]
  • C++11 标准（ISO/IEC 14882:2011）：
  • 18.4 Integer types [cstdint]
  • 27.9.2 C library files [c.files]

参阅

  • 基础类型


std::integral_constant

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T, T v > struct integral_constant; | (C++11 起)

std::integral_constant 包装特定类型的静态常量。它是 C++ 类型特征的基类。

添加 integral_constant 的特化的程序行为未定义。

辅助模板

为 T 为 bool 的常用情况定义辅助别名模板 std::bool_constant 。

template <bool B>
using bool_constant = integral_constant<bool, B>;
(C++17 起)

为其中 T 为 bool 的二种常用情形提供 typedef ：

定义于头文件 <type_traits>
类型 | 定义
true_type | std::integral_constant<bool, true>
false_type | std::integral_constant<bool, false>

成员类型

类型 | 定义
value_type | T
type | std::integral_constant<T,v>

成员常量

名称 | 值
constexpr T value [静态] | T 类型的值为 v 的静态常量 (公开静态成员常量)

成员函数

operator value_type | 返回包装的值 (公开成员函数)
operator() (C++14) | 返回包装的值 (公开成员函数)

std::integral_constant::operator value_type

constexpr operator value_type() const noexcept;

转换函数。返回包装的值。

std::integral_constant::operator()

constexpr value_type operator()() const noexcept; | (C++14 起)

返回包装的值。此函数允许 std::integral_constant 被用作编译时函数对象的源。

可能的实现

template<class T, T v>
struct integral_constant {
    static constexpr T value = v;
    using value_type = T;
    using type = integral_constant; // 使用注入类名
    constexpr operator value_type() const noexcept { return value; }
    constexpr value_type operator()() const noexcept { return value; } // C++14 起
};

示例

#include <iostream>
#include <type_traits>

int main()
{
    typedef std::integral_constant<int, 2> two_t;
    typedef std::integral_constant<int, 4> four_t;

//  static_assert(std::is_same<two_t, four_t>::value,
//                "two_t and four_t are not equal!");
//  error: static assertion failed: "two_t and four_t are not equal!"

    static_assert(two_t::value*2 == four_t::value,
       "2*2 != 4"
    );

    enum class my_e {
       e1,
       e2
    };
    typedef std::integral_constant<my_e, my_e::e1> my_e_e1;
    typedef std::integral_constant<my_e, my_e::e2> my_e_e2;

//  static_assert(my_e_e1::value == my_e::e2,
//               "my_e_e1::value != my_e::e2");
//  error: static assertion failed: "my_e_e1::value != my_e::e2"

    static_assert(std::is_same<my_e_e1, my_e_e2>::value,
                  "my_e_e1 != my_e_e2");
}


std::is_abstract

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_abstract; | (C++11 起)

若 T 为抽象类（即声明或继承至少一个纯虚函数的非联合类类型），则提供等于 true 的成员常量 value 。对于其他类型， value 为 false 。

若 T 是非联合类类型，则 T 应为完整类型；否则行为未定义。

添加 is_abstract 或 is_abstract_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_abstract_v = is_abstract<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为抽象类类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <iostream>
#include <type_traits>

struct A {
    int m;
};

struct B {
    virtual void foo();
};

struct C {
    virtual void foo() = 0;
};

struct D : C {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_abstract<A>::value << '\n';
    std::cout << std::is_abstract<B>::value << '\n';
    std::cout << std::is_abstract<C>::value << '\n';
    std::cout << std::is_abstract<D>::value << '\n';
}

输出：

false
false
true
true

参阅

is_class (C++11) | 检查类型是否非联合类类型 (类模板)
is_polymorphic (C++11) | 检查类型是否为多态类类型 (类模板)


std::is_aggregate

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_aggregate; | (C++17 起)

检查 T 是否为聚合类型。若 T 为聚合类型，则成员常量 value 等于 true ，否则为 false 。

若 std::remove_all_extents_t <T> 是异于（可以有 cv 限定的） void 的不完整类型，则行为未定义。

添加 is_aggregate 或 is_aggregate_v 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_aggregate_v = is_aggregate<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T为聚合类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <type_traits>
#include <new>
#include <utility>

// 于 p 所指向的未初始化内存构造 T
// 用聚合体的列表初始化，否则使用非列表初始化
template<class T, class... Args>
T* construct(T* p, Args&&... args) {
    if constexpr(std::is_aggregate_v<T>) {
        return ::new (static_cast<void*>(p)) T{std::forward<Args>(args)...};
    }
    else {
        return ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
    }
}

struct A { int x, y; };
struct B { B(int, const char*) { } };

int main() {
    std::aligned_union_t<1, A, B> storage;
    A* a = construct(reinterpret_cast<A*>(&storage), 1, 2);
    B* b = construct(reinterpret_cast<B*>(&storage), 1, "hello");
}


std::is_arithmetic

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_arithmetic; | (C++11 起)

若 T 为算术类型（即整数类型或浮点类型）或其 cv 限定版本，则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

添加 is_arithmetic 或 is_arithmetic_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为算术类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注解

算术类型是算术运算符（ + 、 - 、 * 、 / ）为之定义的内建类型（可能与通常算术转换结合）

为所有算术类型提供 std::numeric_limits 的特化。

可能的实现

template< class T >
struct is_arithmetic : std::integral_constant<bool,
                                              std::is_integral<T>::value ||
                                              std::is_floating_point<T>::value> {};

示例

#include <iostream>
#include <type_traits>

class A {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << "A:           " <<  std::is_arithmetic<A>::value << '\n';
    std::cout << "bool:        " <<  std::is_arithmetic<bool>::value << '\n';
    std::cout << "int:         " <<  std::is_arithmetic<int>::value << '\n';
    std::cout << "int const:   " <<  std::is_arithmetic<int const>::value << '\n';
    std::cout << "int &:       " <<  std::is_arithmetic<int&>::value << '\n';
    std::cout << "int *:       " <<  std::is_arithmetic<int*>::value << '\n';
    std::cout << "float:       " <<  std::is_arithmetic<float>::value << '\n';
    std::cout << "float const: " <<  std::is_arithmetic<float const>::value << '\n';
    std::cout << "float &:     " <<  std::is_arithmetic<float&>::value << '\n';
    std::cout << "float *:     " <<  std::is_arithmetic<float*>::value << '\n';
    std::cout << "char:        " <<  std::is_arithmetic<char>::value << '\n';
    std::cout << "char const:  " <<  std::is_arithmetic<char const>::value << '\n';
    std::cout << "char &:      " <<  std::is_arithmetic<char&>::value << '\n';
    std::cout << "char *:      " <<  std::is_arithmetic<char*>::value << '\n';
}

输出：

A:           false
bool:        true
int:         true
int const:   true
int &:       false
int *:       false
float:       true
float const: true
float &:     false
float *:     false
char:        true
char const:  true
char &:      false
char *:      false

参阅

is_integral (C++11) | 检查类型是否为整型 (类模板)
is_floating_point (C++11) | 检查类型是否是浮点类型 (类模板)


std::is_array

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_array; | (C++11 起)

检查 T 是否数组类型。若 T 为数组类型，则提供等于 true 的成员常量 value 。否则， value 等于 false 。

添加 is_array 或 is_array_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_array_v = is_array<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为数组类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template<class T>
struct is_array : std::false_type {};

template<class T>
struct is_array<T[]> : std::true_type {};

template<class T, std::size_t N>
struct is_array<T[N]> : std::true_type {};

示例

#include <array>
#include <iostream>
#include <type_traits>

class A {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_array<A>::value << '\n';
    std::cout << std::is_array<A[]>::value << '\n';
    std::cout << std::is_array<A[3]>::value << '\n';
    std::cout << std::is_array<float>::value << '\n';
    std::cout << std::is_array<int>::value << '\n';
    std::cout << std::is_array<int[]>::value << '\n';
    std::cout << std::is_array<int[3]>::value << '\n';
    std::cout << std::is_array<std::array<int, 3>>::value << '\n';
}

输出：

false
true
true
false
false
true
true
false

参阅

is_bounded_array (C++20) | 检查类型是否为有已知边界的数组类型 (类模板)
is_unbounded_array (C++20) | 检查类型是否为有未知边界的数组类型 (类模板)
rank (C++11) | 获取数组类型的维数 (类模板)
extent (C++11) | 获取数组类型在指定维度的大小 (类模板)
remove_extent (C++11) | 从给定数组类型移除一个维度 (类模板)
remove_all_extents (C++11) | 移除给定数组类型的所有维度 (类模板)


std::is_assignable, std::is_trivially_assignable, std::is_nothrow_assignable

< cpp‎ | types
定义于头文件 <type_traits> |  |
template< class T, class U > struct is_assignable; | (1) | (C++11 起)
template< class T, class U > struct is_trivially_assignable; | (2) | (C++11 起)
template< class T, class U > struct is_nothrow_assignable; | (3) | (C++11 起)
1) 若表达式 std::declval <T>() = std::declval <U>() 在不求值语境为良态，则提供等于 true 的成员常量 value 。否则， value 为 false 。如同从与不关联到任一方的语境进行访问检查。
2) 同 (1) ，但赋值表达式的求值将不调用任何非平凡的操作。为此检查的目的，对 std::declval 的调用被认为是平凡，且不是 std::declval 的 odr 使用。
3) 同 (1) ，但复制表达式的求值将不调用任何不是 noexcept 的操作。

T 与 U 应均为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

添加此页面上描述的任何模板的特化的程序行为未定义。

辅助变量模板

template< class T, class U > inline constexpr bool is_assignable_v = is_assignable<T, U>::value; | (C++17 起)
template< class T, class U > inline constexpr bool is_trivially_assignable_v = is_trivially_assignable<T, U>::value; | (C++17 起)
template< class T, class U > inline constexpr bool is_nothrow_assignable_v = is_nothrow_assignable<T, U>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 可从 U 赋值则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注意

此特性不检查任何赋值表达式立即语境之外的任何事物：若 T 或 U 的使用会触发模板特化，生成隐式定义的成员函数，而它们拥有错误，则实际赋值可能无法编译，即使 std::is_assignable<T,U>::value 通过编译并求值为 true 。

示例

#include <iostream>
#include <string>
#include <type_traits>
struct Ex1 { int n; };
int main() {
    std::cout << std::boolalpha
              << "int is assignable from int? "
              << std::is_assignable<int, int>::value << '\n' // 1 = 1; wouldn't compile
              << "int& is assignable from int? "
              << std::is_assignable<int&, int>::value << '\n' // int a; a = 1; works
              << "int is assignable from double? "
              << std::is_assignable<int, double>::value << '\n'
              << "int& is nothrow assignable from double? "
              << std::is_nothrow_assignable<int&, double>::value << '\n'
              << "string is assignable from double? "
              << std::is_assignable<std::string, double>::value << '\n'
              << "Ex1& is trivially assignable from const Ex1&? "
              << std::is_trivially_assignable<Ex1&, const Ex1&>::value << '\n';
}

输出：

int is assignable from int? false
int& is assignable from int? true
int is assignable from double? false
int& is nothrow assignable from double? true
string is assignable from double? true
Ex1& is trivially assignable from const Ex1&? true

参阅

is_copy_assignableis_trivially_copy_assignableis_nothrow_copy_assignable (C++11)(C++11)(C++11) | 检查类型是否拥有复制赋值运算符 (类模板)
is_move_assignableis_trivially_move_assignableis_nothrow_move_assignable (C++11)(C++11)(C++11) | 检查类型是否有拥有移动赋值运算符 (类模板)


std::is_base_of

< cpp‎ | types
定义于头文件 <type_traits> |
template< class Base, class Derived > struct is_base_of; | (C++11 起)

若 Derived 派生自 Base 或为同一非联合类（均忽略 cv 限定），则提供等于 true 的成员常量 value 。否则 value 为 false 。

若 Base 和 Derived 都是非联合类类型，且它们不是同一类型（忽略 cv 限定），则 Derived 应是完整类型；否则行为未定义。

添加 is_base_of 或 is_base_of_v (C++17 起) 的特化的程序行为未定义。

辅助变量模板

template< class Base, class Derived > inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 Derived 派生自 Base 或为同一非联合类（均忽略 cv 限定）则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注解

即使 A 是 B 的私有、受保护或有歧义基类， std::is_base_of<A, B>::value 亦为 true 。许多情况下， std::is_convertible <B*, A*> 是更适合的测试。

尽管没有类是其自身的基类， std::is_base_of<T, T>::value 亦为 true ，因为此特性的目的是模拟“是（ is-a ）”关系，而 T 是 T 。尽管如此， std::is_base_of<int, int>::value 为 false ，因为仅类参与此特性所模拟的关系。

可能的实现

namespace details {
    template <typename B>
    std::true_type  test_pre_ptr_convertible(const volatile B*);
    template <typename>
    std::false_type test_pre_ptr_convertible(const volatile void*);

    template <typename, typename>
    auto test_pre_is_base_of(...) -> std::true_type;
    template <typename B, typename D>
    auto test_pre_is_base_of(int) ->
        decltype(test_pre_ptr_convertible<B>(static_cast<D*>(nullptr)));
}

template <typename Base, typename Derived>
struct is_base_of :
    std::integral_constant<
        bool,
        std::is_class<Base>::value && std::is_class<Derived>::value &&
        decltype(details::test_pre_is_base_of<Base, Derived>(0))::value
    > { };

示例

#include <iostream>
#include <type_traits>

class A {};

class B : A {};

class C {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << "a2b: " << std::is_base_of<A, B>::value << '\n';
    std::cout << "b2a: " << std::is_base_of<B, A>::value << '\n';
    std::cout << "c2b: " << std::is_base_of<C, B>::value << '\n';
    std::cout << "same type: " << std::is_base_of<C, C>::value << '\n';
}

输出：

a2b: true
b2a: false
c2b: false
same type: true

参阅

is_convertibleis_nothrow_convertible
(C++11)(C++20)
 检查是否能转换一个类型为另一类型
(类模板)


std::is_bounded_array

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_bounded_array; | (C++20 起)

检查 T 是否为拥有已知边界的数组类型。若 T 是有已知边界的数组则提供等于 true 的成员常量 value 。否则 value 等于 false 。

添加 is_bounded_array 或 is_bounded_array_v 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_bounded_array_v = is_bounded_array<T>::value; | (C++20 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为拥有已知边界的数组类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template<class T>
struct is_bounded_array: std::false_type {};

template<class T, std::size_t N>
struct is_bounded_array<T[N]> : std::true_type {};

示例

#include <iostream>
#include <type_traits>

class A {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_bounded_array_v<A> << '\n';
    std::cout << std::is_bounded_array_v<A[]> << '\n';
    std::cout << std::is_bounded_array_v<A[3]> << '\n';
    std::cout << std::is_bounded_array_v<float> << '\n';
    std::cout << std::is_bounded_array_v<int> << '\n';
    std::cout << std::is_bounded_array_v<int[]> << '\n';
    std::cout << std::is_bounded_array_v<int[3]> << '\n';
}

输出：

false
false
true
false
false
false
true

参阅

is_array (C++11) | 检查类型是否是数组类型 (类模板)
is_unbounded_array (C++20) | 检查类型是否为有未知边界的数组类型 (类模板)
extent (C++11) | 获取数组类型在指定维度的大小 (类模板)


std::is_class

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_class; | (C++11 起)

检查 T 是否为非联合类类型。若 T 为类类型（但非联合体），则提供等于 true 的成员常量 value 。否则， value 等于 false 。

注意以 struct 关键词声明的类型是类，故此特性对“结构体”为 true 。

添加 is_class 或 is_class_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_class_v = is_class<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为非联合类类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

namespace detail {
template <class T>
std::integral_constant<bool, !std::is_union<T>::value> test(int T::*);

template <class>
std::false_type test(...);
}

template <class T>
struct is_class : decltype(detail::test<T>(nullptr))
{};

示例

#include <iostream>
#include <type_traits>

struct A {};

class B {};

enum class C {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_class<A>::value << '\n';
    std::cout << std::is_class<B>::value << '\n';
    std::cout << std::is_class<C>::value << '\n';
    std::cout << std::is_class<int>::value << '\n';
}

输出：

true
true
false
false

参阅

is_union
(C++11)
 检查类型是否为联合体类型
(类模板)


std::is_compound

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_compound; | (C++11 起)

若 T 是复合类型（即数组、函数、对象指针、函数指针、成员对象指针、成员函数指针、引用、类、联合体或枚举，含任何 cv 限定变体），则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

添加 is_compound 或 is_compound_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_compound_v = is_compound<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为复合类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注意

复合类型是从基础类型构造的类型。任何 C++ 类型为基础或复合之一。

可能的实现

template< class T >
struct is_compound : std::integral_constant<bool, !std::is_fundamental<T>::value> {};

示例

#include <iostream>
#include <type_traits>

int main() {
    class cls {};
    std::cout << (std::is_compound<cls>::value
                     ? "T is compound"
                     : "T is not a compound") << '\n';
    std::cout << (std::is_compound<int>::value
                     ? "T is compound"
                     : "T is not a compound") << '\n';
}

输出：

T is compound
T is not a compound

参阅

is_fundamental (C++11) | 检查是否是基础类型 (类模板)
is_scalar (C++11) | 检查类型是否为标量类型 (类模板)
is_object (C++11) | 检查是否是对象类型 (类模板)
is_array (C++11) | 检查类型是否是数组类型 (类模板)


std::is_const

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_const; | (C++11 起)

若 T 为 const 限定类型（即 const 或 const volatile ），则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

添加 is_const 或 is_const_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_const_v = is_const<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为 const 限定类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注意

若 T 为引用类型则 is_const<T>::value 始终为 false 。检查可能为引用的类型的常性的正确方式是移除引用： is_const<typename remove_reference<T>::type> 。

可能的实现

template<class T> struct is_const          : std::false_type {};
template<class T> struct is_const<const T> : std::true_type {};

示例

#include <iostream>
#include <type_traits>

int main()
{
    std::cout << std::boolalpha
        << std::is_const_v<int> << '\n' // false
        << std::is_const_v<const int> << '\n' // true
        << std::is_const_v<const int*> /*false*/
        << " because the pointer itself can be changed but not the int pointed at\n"
        << std::is_const_v<int* const> /*true*/
        << " because the pointer itself can't be changed but the int pointed at can\n"
        << std::is_const_v<const int&> << '\n' // false
        << std::is_const_v<std::remove_reference_t<const int&>> << '\n' // true
        ;
}

输出：

false
true
false because the pointer itself can be changed but not the int pointed at
true because the pointer itself can't be changed but the int pointed at can
false
true

参阅

is_volatile (C++11) | 检查类型是否为 volatile 限定 (类模板)
as_const (C++17) | 获得到其实参的 const 引用 (函数模板)


std::is_constant_evaluated

< cpp‎ | types
定义于头文件 <type_traits> |
constexpr bool is_constant_evaluated() noexcept; | (C++20 起)

检查函数调用是否出现在常量求值的场合。若对调用的求值出现在明显常量求值的表达式或类型转换的求值中，返回 true ，否则返回 false 。

在测试下列变量的初始化器是否为常量初始化器时，编译期可能首先试探性地对初始化器常量求值：

  • 引用或 const 限定的整数或枚举类型的变量
    • 若初始化器为常量表达式，则变量可用于常量表达式
  • 静态及线程局域变量
    • 若初始化器的所有子表达式（包括构造函数及隐式转换）均为常量表达式，则进行静态初始化，这能由 constinit 断言

不建议依赖此时的结果。

int y;
const int a = std::is_constant_evaluated() ? y : 1;
// 试探性常量求值失败，常量求值被舍弃。
// 变量 a 动态初始化为 1

const int b = std::is_constant_evaluated() ? 2 : y;
// 常量求值（std::is_constant_evaluation() == true）成功。
// 变量 b 静态初始化为 2

参数

（无）

返回值

若对调用的求值出现在明显常量求值的表达式或类型转换的求值中，返回 true ，否则返回 false 。

可能的实现

// 此实现要求 C++23 if consteval 。
constexpr bool is_constant_evaluated() noexcept
{
    if consteval {
        return true;
    }
    else {
        return false;
    }
}

注解

std::is_constant_evaluated() 直接作为 static_assert 声明和 constexpr if 语句的条件时，返回值总是 true 。

由于 if consteval 不在 C++20 中， is_constant_evaluated 常由编译器扩展实现。

示例

#include <type_traits>
#include <cmath>
#include <iostream>

constexpr double power(double b, int x)
{
    if (std::is_constant_evaluated() && !(b == 0.0 && x < 0)) {
        // 常量求值语境：使用 constexpr 友好的算法。
        if (x == 0)
            return 1.0;
        double r = 1.0, p = x > 0 ? b : 1.0 / b;
        auto u = unsigned(x > 0 ? x : -x);
        while (u != 0) {
            if (u & 1) r *= p;
            u /= 2;
            p *= p;
        }
        return r;
    } else {
        // 令代码生成器生成。
        return std::pow(b, double(x));
    }
}

int main()
{
    // 常量表达式语句
    constexpr double kilo = power(10.0, 3);
    int n = 3;
    // 非常量表达式，因为 n 不能在常量表达式语境中转换成右值
    // 等价于 std::pow(10.0, double(n))
    double mucho = power(10.0, n);

    std::cout << kilo << " " << mucho << "\n"; // (3)
}

输出：

1000 1000

参阅

constexpr 说明符 (C++11) | 指定变量或函数的值能在编译时计算
consteval 说明符 (C++20) | 指定函数为立即函数，即对该函数的每次调用必须在常量求值中
constinit 说明符 (C++20) | 断言变量拥有静态初始化，即零初始化与常量初始化


std::is_constructible, std::is_trivially_constructible, std::is_nothrow_constructible

< cpp‎ | types
定义于头文件 <type_traits> |  |
template< class T, class... Args > struct is_constructible; | (1) | (C++11 起)
template< class T, class... Args > struct is_trivially_constructible; | (2) | (C++11 起)
template< class T, class... Args > struct is_nothrow_constructible; | (3) | (C++11 起)
1) 若 T 是对象或引用类型，且变量定义 T obj( std::declval <Args>()...); 为良构，则提供等于 true 的成员常量 value 。所有其他情况下， value 为 false 。
为此检查的目的，决不转译变量定义为函数声明，且不认为 std::declval 是 odr 使用。如同从与 T 和任何 Args 中类型无关的语境进行访问检查。仅考虑变量定义的立即语境的合法性。
2) 同 (1) ，但变量定义不调用任何非平凡操作。为此检查的目的，对 std::declval 的调用被认为是平凡的。
3) 同 (1) ，但变量定义为 noexcept 。

T 与参数包 Args 中的所有类型应均为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

添加此页面上描述的任何模板的特化的程序行为未定义。

辅助变量模板

template< class T, class... Args > inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value; | (C++17 起)
template< class T, class... Args > inline constexpr bool is_trivially_constructible_v = is_trivially_constructible<T, Args...>::value; | (C++17 起)
template< class T, class... Args > inline constexpr bool is_nothrow_constructible_v = is_nothrow_constructible<T, Args...>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 可从 Args... 构造则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注解

多数实现中， is_nothrow_constructible 亦检查析构函数是否抛出，因为它等效于 noexcept(T(arg)) 。同样的情况应用于 is_trivially_constructible ，在这些实现中亦要求析构函数为平凡： GCC 漏洞 51452 、 LWG 问题 2116 。

示例

#include <iostream>
#include <type_traits>

class Foo {
    int v1;
    double v2;
 public:
    Foo(int n) : v1(n), v2() {}
    Foo(int n, double f) noexcept : v1(n), v2(f) {}
};

int main() {
    std::cout << "Foo is ...\n" << std::boolalpha
              << "\tTrivially-constructible from const Foo&? "
              << std::is_trivially_constructible<Foo, const Foo&>::value << '\n'
              << "\tTrivially-constructible from int? "
              << std::is_trivially_constructible<Foo, int>::value << '\n'
              << "\tConstructible from int? "
              << std::is_constructible<Foo, int>::value << '\n'
              << "\tNothrow-constructible from int? "
              << std::is_nothrow_constructible<Foo, int>::value << '\n'
              << "\tNothrow-constructible from int and double? "
              << std::is_nothrow_constructible<Foo, int, double>::value << '\n';
}

输出：

Foo is ...
        Trivially-constructible from const Foo&? true
        Trivially-constructible from int? false
        Constructible from int? true
        Nothrow-constructible from int? false
        Nothrow-constructible from int and double? true

参阅

is_default_constructibleis_trivially_default_constructibleis_nothrow_default_constructible (C++11)(C++11)(C++11) | 检查类型是否有默认构造函数 (类模板)
is_copy_constructibleis_trivially_copy_constructibleis_nothrow_copy_constructible (C++11)(C++11)(C++11) | 检查类型是否拥有复制构造函数 (类模板)
is_move_constructibleis_trivially_move_constructibleis_nothrow_move_constructible (C++11)(C++11)(C++11) | 检查类型是否能从右值引用构造 (类模板)
uses_allocator (C++11) | 检查指定的类型是否支持使用分配器的构造 (类模板)


std::is_convertible, std::is_nothrow_convertible

< cpp‎ | types
定义于头文件 <type_traits> |  |
template< class From, class To > struct is_convertible; | (1) | (C++11 起)
template< class From, class To > struct is_nothrow_convertible; | (2) | (C++20 起)
1) 若虚构函数定义 To test() { return std::declval <From>(); } 为良构，（即 std::declval <From>() 能用隐式转换转换为 To ，或 From 和 To 均为可有 cv 限定的 void ），则提供等于 true 的成员常量 value 。否则 value 为 false 。为此检查的目的，不认为 return 语句中的 std::declval 是 odr 使用。
如同从无关乎任一类型的语境中进行访问检查。仅考虑 return 语句中的表达式（包含转换到返回类型）的立即语境的合法性。
2) 同 (1) ，但转换亦为 noexcept 。

From 与 To 应均为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

添加此页面上描述的任何模板的特化的程序行为未定义。

辅助变量模板

template< class From, class To > inline constexpr bool is_convertible_v = is_convertible<From, To>::value; | (C++17 起)
template< class From, class To > inline constexpr bool is_nothrow_convertible_v = is_nothrow_convertible<From, To>::value; | (C++20 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 From 可转换为 To 则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

版本一
namespace detail {

template<class T>
auto test_returnable(int) -> decltype(
    void(static_cast<T(*)()>(nullptr)), std::true_type{}
);
template<class>
auto test_returnable(...) -> std::false_type;

template<class From, class To>
auto test_implicitly_convertible(int) -> decltype(
    void(std::declval<void(&)(To)>()(std::declval<From>())), std::true_type{}
);
template<class, class>
auto test_implicitly_convertible(...) -> std::false_type;

} // namespace detail

template<class From, class To>
struct is_convertible : std::integral_constant<bool,
    (decltype(detail::test_returnable<To>(0))::value &&
     decltype(detail::test_implicitly_convertible<From, To>(0))::value) ||
    (std::is_void<From>::value && std::is_void<To>::value)
> {};
版本二
template<class From, class To>
struct is_nothrow_convertible : std::conjunction<std::is_void<From>, std::is_void<To>> {};

template<class From, class To>
    requires
        requires {
            static_cast<To(*)()>(nullptr);
            { std::declval<void(&)(To) noexcept>()(std::declval<From>()) } noexcept;
        }
struct is_nothrow_convertible<From, To> : std::true_type {};

注解

对引用类型、 void 类型、数组类型和函数类型给出良好定义的结果。

当前标准未指定是否认为转换所产生的对象（结果对象或绑定到引用的临时量）的析构是转换的一部分。此为 LWG 问题 3400 。

所有已知实现都将析构当作转换的一部分，如 P0758R1 中提议。

示例

#include <iostream>
#include <type_traits>

class E { public: template<class T> E(T&&) { } };

int main()
{
    class A {};
    class B : public A {};
    class C {};
    class D { public: operator C() { return c; }  C c; };

    bool b2a = std::is_convertible<B*, A*>::value;
    bool a2b = std::is_convertible<A*, B*>::value;
    bool b2c = std::is_convertible<B*, C*>::value;
    bool d2c = std::is_convertible<D, C>::value;

    // 完美转发构造函数使类能从任何类型转换

    bool everything2e = std::is_convertible<A, E>::value; //< B, C, D 等

    std::cout << std::boolalpha;

    std::cout << b2a << '\n';
    std::cout << a2b << '\n';
    std::cout << b2c << '\n';
    std::cout << d2c << '\n';
    std::cout << '\n';
    std::cout << everything2e << '\n';
}

输出：

true
false
false
true

true

参阅


std::is_copy_assignable, std::is_trivially_copy_assignable, std::is_nothrow_copy_assignable

< cpp‎ | types
定义于头文件 <type_traits> |  |
template< class T > struct is_copy_assignable; | (1) | (C++11 起)
template< class T > struct is_trivially_copy_assignable; | (2) | (C++11 起)
template< class T > struct is_nothrow_copy_assignable; | (3) | (C++11 起)
1) 若 T 不是可引用类型（即可为 cv 限定的 void 或带 cv-qualifier-seq 或 ref-qualifier 的函数类型），则提供等于 false 的成员常量 value 。否则，提供等于 std::is_assignable <T&, const T&>::value 的成员常量 value 。
2) 同 (1) ，但使用 std::is_trivially_assignable <T&, const T&>
3) 同 (1) ，但使用 std::is_nothrow_assignable <T&, const T&>

T 应为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

添加此页面上描述的任何模板的特化的程序行为未定义。

辅助变量模板

template< class T > inline constexpr bool is_copy_assignable_v = is_copy_assignable<T>::value; | (C++17 起)
template< class T > inline constexpr bool is_trivially_copy_assignable_v = is_trivially_copy_assignable<T>::value; | (C++17 起)
template< class T > inline constexpr bool is_nothrow_copy_assignable_v = is_nothrow_copy_assignable<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 可复制赋值则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template< class T>
struct is_copy_assignable
    : std::is_assignable< typename std::add_lvalue_reference<T>::type,
                          typename std::add_lvalue_reference<const T>::type> {};

template< class T>
struct is_trivially_copy_assignable
    : std::is_trivially_assignable< typename std::add_lvalue_reference<T>::type,
                                    typename std::add_lvalue_reference<const T>::type> {};

template< class T>
struct is_nothrow_copy_assignable
    : std::is_nothrow_assignable< typename std::add_lvalue_reference<T>::type,
                                  typename std::add_lvalue_reference<const T>::type> {};

注解

特征 std::is_copy_assignable 不如可复制赋值 (CopyAssignable) 严格，因为它不检查赋值的结果类型（对于可复制赋值 (CopyAssignable) 类型必须是 T 类型的左值）且不检查赋值表达式保留未更改的语义要求。它亦不检查 T 是否满足对所有可复制赋值 (CopyAssignable) 类型要求的可移动赋值 (MoveAssignable) 。

示例

#include <iostream>
#include <utility>
#include <type_traits>
struct Foo { int n; };
int main() {
    std::cout << std::boolalpha
              << "Foo is trivally copy-assignable? "
              << std::is_trivially_copy_assignable<Foo>::value << '\n'
              << "int[2] is copy-assignable? "
              << std::is_copy_assignable<int[2]>::value << '\n'
              << "int is nothrow copy-assignable? "
              << std::is_nothrow_copy_assignable<int>::value << '\n';
}

输出：

Foo is trivally copy-assignable? true
int[2] is copy-assignable? false
int is nothrow copy-assignable? true

参阅

is_assignableis_trivially_assignableis_nothrow_assignable (C++11)(C++11)(C++11) | 检查类型是否拥有针对特定实参的赋值运算符 (类模板)
is_move_assignableis_trivially_move_assignableis_nothrow_move_assignable (C++11)(C++11)(C++11) | 检查类型是否有拥有移动赋值运算符 (类模板)


std::is_copy_constructible, std::is_trivially_copy_constructible, std::is_nothrow_copy_constructible

< cpp‎ | types
定义于头文件 <type_traits> |  |
template< class T > struct is_copy_constructible; | (1) | (C++11 起)
template< class T > struct is_trivially_copy_constructible; | (2) | (C++11 起)
template< class T > struct is_nothrow_copy_constructible; | (3) | (C++11 起)
1) 若 T 不是可引用类型（即可为 cv 限定的 void 或带 cv-qualifier-seq 或 ref-qualifier 的函数类型），则提供等于 false 的成员常量 value 。否则，提供等于 std::is_constructible <T, const T&>::value 的成员常量 value 。
2) 同 (1) ，但使用 std::is_trivially_constructible <T, const T&> 。
3) 同 (1) ，但使用 std::is_nothrow_constructible <T, const T&> 。

T 应为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

添加此页面上描述的任何模板的特化的程序行为未定义。

辅助变量模板

template< class T > inline constexpr bool is_copy_constructible_v = is_copy_constructible<T>::value; | (C++17 起)
template< class T > inline constexpr bool is_trivially_copy_constructible_v = is_trivially_copy_constructible<T>::value; | (C++17 起)
template< class T > inline constexpr bool is_nothrow_copy_constructible_v = is_nothrow_copy_constructible<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 可复制构造则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template<class T>
struct is_copy_constructible :
    std::is_constructible<T, typename std::add_lvalue_reference<
        typename std::add_const<T>::type>::type> {};

template<class T>
struct is_trivially_copy_constructible :
    std::is_trivially_constructible<T, typename std::add_lvalue_reference<
        typename std::add_const<T>::type>::type> {};

template<class T>
struct is_nothrow_copy_constructible :
    std::is_nothrow_constructible<T, typename std::add_lvalue_reference<
        typename std::add_const<T>::type>::type> {};

注解

多数实现中， is_nothrow_copy_constructible 亦检查析构函数是否抛出，因为它等效于 noexcept(T(arg)) 。同样的情况应用于 is_trivially_copy_constructible ，它在这些实现中亦要求析构函数为平凡： GCC 漏洞 51452 、 LWG 问题 2116。

示例

#include <iostream>
#include <type_traits>

struct Ex1 {
    std::string str; // 成员拥有非平凡复制构造函数
};
struct Ex2 {
    int n;
    Ex2(const Ex2&) = default; // 平凡且不抛出
};

int main() {
    std::cout << std::boolalpha << "Ex1 is copy-constructible? "
              << std::is_copy_constructible<Ex1>::value << '\n'
              << "Ex1 is trivially copy-constructible? "
              << std::is_trivially_copy_constructible<Ex1>::value << '\n'
              << "Ex2 is trivially copy-constructible? "
              << std::is_trivially_copy_constructible<Ex2>::value << '\n'
              << "Ex2 is nothrow copy-constructible? "
              << std::is_nothrow_copy_constructible<Ex2>::value << '\n';
}

输出：

Ex1 is copy-constructible? true
Ex1 is trivially copy-constructible? false
Ex2 is trivially copy-constructible? true
Ex2 is nothrow copy-constructible? true

参阅

is_constructibleis_trivially_constructibleis_nothrow_constructible (C++11)(C++11)(C++11) | 检查类型是否带有针对特定实参的构造函数 (类模板)
is_default_constructibleis_trivially_default_constructibleis_nothrow_default_constructible (C++11)(C++11)(C++11) | 检查类型是否有默认构造函数 (类模板)
is_move_constructibleis_trivially_move_constructibleis_nothrow_move_constructible (C++11)(C++11)(C++11) | 检查类型是否能从右值引用构造 (类模板)


std::is_corresponding_member

< cpp‎ | types
定义于头文件 <type_traits> |
template<class S1, class S2, class M1, class M2> constexpr bool is_corresponding_member( M1 S1::* mp, M2 S2::* mq ) noexcept; | (C++20 起)

确定 mp 与 mq 是否指代 S1 与 S2 的公共起始序列中的对应成员。若 S1 或 S2 为不完整类型则程序为谬构。

若 S1 或 S2 不是标准布局类型 (StandardLayoutType) ，或若 M1 或 M2 不是对象类型，或若 mp 或 mq 等于 nullptr ，则结果始终为 false 。

参数

mp, mq - 要检测的成员指针

返回值

若 mp 与 mq 指代 S1 与 S2 的公共起始序列中的对应成员则为 true ，否则为 false 。

注解

成员指针表达式 &S::m 的类型并非始终是 M S::* ，其中 m 的类型为 M ，因为 m 可能是从 S 的基类继承的成员。能指定前两个模板实参以避免潜在地令人诧异的结果。

示例

#include <type_traits>
#include <iostream>

struct Foo { int x; };
struct Bar { int y; double z; };

struct Baz : Foo, Bar {}; // 非标准布局

int main()
{
    std::cout << std::boolalpha
        << std::is_same_v<decltype(&Baz::x), int Foo::*> << '\n'
        << std::is_same_v<decltype(&Baz::y), int Bar::*> << '\n'
        << std::is_corresponding_member(&Foo::x, &Bar::y) << '\n'
        << std::is_corresponding_member(&Baz::x, &Baz::y) << '\n'
        << std::is_corresponding_member<Baz, Baz>(&Baz::x, &Baz::y) << '\n';
}

输出：

true
true
true
true
false

参阅

is_standard_layout (C++11) | 检查是否是一个标准布局类型 (类模板)
is_layout_compatible (C++20) | 检查二个类型是否布局兼容 (类模板)
is_member_object_pointer (C++11) | 检查类型是否为指向非静态成员对象的指针 (类模板)


std::is_default_constructible, std::is_trivially_default_constructible, std::is_nothrow_default_constructible

< cpp‎ | types
定义于头文件 <type_traits> |  |
template< class T > struct is_default_constructible; | (1) | (C++11 起)
template< class T > struct is_trivially_default_constructible; | (2) | (C++11 起)
template< class T > struct is_nothrow_default_constructible; | (3) | (C++11 起)
1) 若 std::is_constructible <T>::value 为 true ，则提供等于 true 的成员常量 value ，否则 value 为 false 。
2) 若 std::is_trivially_constructible <T>::value 为 true ，则提供等于 true 的成员常量 value ，否则 value 为 false 。
3) 若 std::is_nothrow_constructible <T>::value 为 true ，则提供等于 true 的成员常量 value ，否则 value 为 false 。

T 应为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

添加此页面上描述的任何模板的特化的程序行为未定义。

辅助变量模板

template< class T > inline constexpr bool is_default_constructible_v = is_default_constructible<T>::value; | (C++17 起)
template< class T > inline constexpr bool is_trivially_default_constructible_v = is_trivially_default_constructible<T>::value; | (C++17 起)
template< class T > inline constexpr bool is_nothrow_default_constructible_v = is_nothrow_default_constructible<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 可默认构造则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template< class T>
struct is_default_constructible : std::is_constructible<T> {};

template< class T>
struct is_trivially_default_constructible : std::is_trivially_constructible<T> {};

template< class T>
struct is_nothrow_default_constructible : std::is_nothrow_constructible<T> {};

注解

多数实现中， is_nothrow_default_constructible 亦检查析构函数是否抛出，因为它等效于 noexcept(T()) 。同样的情况应用于 is_trivially_default_constructible ，它在这些实现中亦要求析构函数为平凡： GCC 漏洞 51452 、 LWG 问题 2116。

示例

#include <iostream>
#include <type_traits>

struct Ex1 {
    std::string str; // 成员拥有非平凡默认构造函数
};
struct Ex2 {
    int n;
    Ex2() = default; // 平凡且不抛出
};

int main() {
    std::cout << std::boolalpha << "Ex1 is default-constructible? "
              << std::is_default_constructible<Ex1>::value << '\n'
              << "Ex1 is trivially default-constructible? "
              << std::is_trivially_default_constructible<Ex1>::value << '\n'
              << "Ex2 is trivially default-constructible? "
              << std::is_trivially_default_constructible<Ex2>::value << '\n'
              << "Ex2 is nothrow default-constructible? "
              << std::is_nothrow_default_constructible<Ex2>::value << '\n';
}

输出：

Ex1 is default-constructible? true
Ex1 is trivially default-constructible? false
Ex2 is trivially default-constructible? true
Ex2 is nothrow default-constructible? true

参阅

is_constructibleis_trivially_constructibleis_nothrow_constructible (C++11)(C++11)(C++11) | 检查类型是否带有针对特定实参的构造函数 (类模板)
is_copy_constructibleis_trivially_copy_constructibleis_nothrow_copy_constructible (C++11)(C++11)(C++11) | 检查类型是否拥有复制构造函数 (类模板)
is_move_constructibleis_trivially_move_constructibleis_nothrow_move_constructible (C++11)(C++11)(C++11) | 检查类型是否能从右值引用构造 (类模板)


std::is_destructible, std::is_trivially_destructible, std::is_nothrow_destructible

< cpp‎ | types
定义于头文件 <type_traits> |  |
template< class T > struct is_destructible; | (1) | (C++11 起)
template< class T > struct is_trivially_destructible; | (2) | (C++11 起)
template< class T > struct is_nothrow_destructible; | (3) | (C++11 起)

1) 若 T 是引用类型，则提供等于 true 的成员常量 value

若 T 是不完整类型（包含 void ）或函数类型，则 value 等于 false 。

若 T 是对象类型，则对于等于 std::remove_all_extents <T>::type 的类型 U ，若表达式 std::declval <U&>().~U() 在不求值语境合法，则 value 等于 true 。否则， value 等于 false 。

2) 同 1) ，并且 std::remove_all_extents <T>::type 要么是非类类型，要么是拥有平凡析构函数的类类型。

3) 同 1) ，但析构函数为 noexcept 。

T 应为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

添加此页面上描述的任何模板的特化的程序行为未定义。

辅助变量模板

template< class T > inline constexpr bool is_destructible_v = is_destructible<T>::value; | (C++17 起)
template< class T > inline constexpr bool is_trivially_destructible_v = is_trivially_destructible<T>::value; | (C++17 起)
template< class T > inline constexpr bool is_nothrow_destructible_v = is_nothrow_destructible<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 可析构则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注解

因为若析构函数在栈回溯中抛出异常则 C++ 程序终止（通常是无法预期的），所有实用的析构函数均为不抛出，即使它们不声明为 noexcept 。所有 C++ 标准库中能找到的析构函数都是不抛出的。

可平凡析构对象所占用的存储可以重用而无需调用析构函数。

示例

#include <iostream>
#include <string>
#include <type_traits>
struct Foo {
   std::string str;
   ~Foo() noexcept {};
};
struct Bar {
    ~Bar() = default;
};
int main() {
    std::cout << std::boolalpha
              << "std::string is destructible? "
              << std::is_destructible<std::string>::value << '\n'
              << "Foo is nothrow destructible? "
              << std::is_nothrow_destructible<Foo>::value << '\n'
              << "Bar is trivally destructible? "
              << std::is_trivially_destructible<Bar>::value << '\n';
}

输出：

std::string is destructible? true
Foo is nothrow destructible? true
Bar is trivally destructible? true

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2049 | C++11 | 规范无法完整，由于虚构的包装结构体 | 使之完整

参阅

is_constructibleis_trivially_constructibleis_nothrow_constructible (C++11)(C++11)(C++11) | 检查类型是否带有针对特定实参的构造函数 (类模板)
has_virtual_destructor (C++11) | 检查类型是否拥有虚析构函数 (类模板)


std::is_empty

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_empty; | (C++11 起)

若 T 是空类类型（即无异于 0 大小位域的非静态数据成员、无虚函数、无虚基类，且无非空基类的非联合类类型），则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

若 T 是非联合类类型，则 T 应是完整类型；否则行为未定义。

添加 is_empty 或 is_empty_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_empty_v = is_empty<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为空类类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注解

因为空基类优化，从空类类型继承通常不增加类的大小。

std::is_empty<T> 及所有其他类型特征均为空类。

示例

#include <iostream>
#include <type_traits>

struct A {};

struct B {
    int m;
};

struct C {
    static int m;
};

struct D {
    virtual ~D();
};

union E {};

struct F {
    [[no_unique_address]] E e;
};

struct G {
    int:0;
    // C++ 标准允许“作为特殊情况，无名的长度为零的位域指定下个位域在分配单元边界对齐。
    // 仅当声明无名位域时宽度可为零。”
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << "A " << std::is_empty<A>::value << '\n';
    std::cout << "B " << std::is_empty<B>::value << '\n';
    std::cout << "C " << std::is_empty<C>::value << '\n';
    std::cout << "D " << std::is_empty<D>::value << '\n';
    std::cout << "E " << std::is_empty<E>::value << '\n';
    std::cout << "F " << std::is_empty<F>::value << '\n'; // 结果依赖 ABI
    std::cout << "G " << std::is_empty<F>::value << '\n'; // 0 宽度的无名位域
}

可能的输出：

A true
B false
C true
D false
E false
F true
G true

参阅

is_class
(C++11)
 检查类型是否非联合类类型
(类模板)


std::is_enum

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_enum; | (C++11 起)

检查 T 是否为枚举类型。若 T 为枚举类型，则提供等于 true 的成员常量 value 。否则， value 等于 false 。

添加 is_enum 或 is_enum_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_enum_v = is_enum<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为枚举类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <iostream>
#include <type_traits>

class A {};

enum E {};

enum class Ec : int {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_enum<A>::value << '\n';
    std::cout << std::is_enum<E>::value << '\n';
    std::cout << std::is_enum<Ec>::value << '\n';
    std::cout << std::is_enum<int>::value << '\n';
}

输出：

false
true
true
false

参阅

is_integral (C++11) | 检查类型是否为整型 (类模板)
is_arithmetic (C++11) | 检查类型是否为算术类型 (类模板)
is_scalar (C++11) | 检查类型是否为标量类型 (类模板)
is_scoped_enum (C++23) | 检查类型是否为有作用域枚举类型 (类模板)


std::is_final

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_final; | (C++14 起)

若 T 为 final 类（即以 final 指定符声明的类），则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

若 T 为类类型，则 T 应为完整类型；否则行为未定义。

添加 is_final 或 is_final_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_final_v = is_final<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为 final 类类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注意

不能以 final 类为基类。

能标记联合体为 final （而 std::is_final 将检测它），尽管任何情况下都不能以联合体为基类。

示例

#include <iostream>
#include <type_traits>

class A {};
class B final {};

int main()
{
    std::cout
        << std::boolalpha
        << std::is_final<A>::value << '\n'
        << std::is_final<B>::value << '\n';
}

输出：

false
true

参阅

is_class (C++11) | 检查类型是否非联合类类型 (类模板)
is_polymorphic (C++11) | 检查类型是否为多态类类型 (类模板)


std::is_floating_point

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_floating_point; | (C++11 起)

检查 T 是否为浮点类型。若 T 为 float 、 double 、 long double 为浮点类型，包含任何 cv 限定变体，则提供等于 true 的成员常量 value 。否则， value 等于 false 。

添加 is_floating_point 或 is_floating_point_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_floating_point_v = is_floating_point<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为浮点类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template< class T >
struct is_floating_point
     : std::integral_constant<
         bool,
         std::is_same<float, typename std::remove_cv<T>::type>::value  ||
         std::is_same<double, typename std::remove_cv<T>::type>::value  ||
         std::is_same<long double, typename std::remove_cv<T>::type>::value
     > {};

示例

#include <iostream>
#include <type_traits>

class A {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_floating_point<A>::value << '\n';
    std::cout << std::is_floating_point<float>::value << '\n';
    std::cout << std::is_floating_point<float&>::value << '\n';
    std::cout << std::is_floating_point<double>::value << '\n';
    std::cout << std::is_floating_point<double&>::value << '\n';
    std::cout << std::is_floating_point<int>::value << '\n';
}

输出：

false
true
false
true
false
false

参阅

is_iec559 [静态] | 鉴别 IEC 559/IEEE 754 浮点类型 (std::numeric_limits<T> 的公开静态成员常量)
is_integral (C++11) | 检查类型是否为整型 (类模板)
is_arithmetic (C++11) | 检查类型是否为算术类型 (类模板)


std::is_function

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_function; | (C++11 起)

检查 T 是否为函数类型。如 std::function 、 lambda 、有重载 operator() 的类和指向函数指针不是函数类型。若 T 为函数类型，则提供等于 true 的成员常量 value 。否则， value 等于 false 。

添加 is_function 或 is_function_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_function_v = is_function<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为函数类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注解

std::is_function 能以更简单的方式实现。 libc++ 、 libstdc++ 及 MS STL 的新版本使用类似以下的实现：

template<class T>
struct is_function : std::integral_constant<
    bool,
    !std::is_const<const T>::value && !std::is_reference<T>::value
> {};

下面展示的实现是为教学目的的，因为它会展现大量的函数类型种类。

可能的实现

// 初等模板
template<class>
struct is_function : std::false_type { };

// 对常规函数的特化
template<class Ret, class... Args>
struct is_function<Ret(Args...)> : std::true_type {};

// 对变参数函数，如 std::printf 的特化
template<class Ret, class... Args>
struct is_function<Ret(Args......)> : std::true_type {};

// 对拥有 cv 限定符的函数类型的特化
template<class Ret, class... Args>
struct is_function<Ret(Args...) const> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile> : std::true_type {};

// 对拥有引用限定符的函数类型的特化
template<class Ret, class... Args>
struct is_function<Ret(Args...) &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile &> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile &&> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile &&> : std::true_type {};

// 对所有以上的 noexcept 版本的特化（ C++17 及之后）

template<class Ret, class... Args>
struct is_function<Ret(Args...) noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile & noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) && noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const && noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile && noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile && noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) && noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const && noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile && noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile && noexcept> : std::true_type {};

示例

#include <iostream>
#include <type_traits>

struct A {
    int fun() const&;
};

template<typename>
struct PM_traits {};

template<class T, class U>
struct PM_traits<U T::*> {
    using member_type = U;
};

int f();

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_function<A>::value << '\n';
    std::cout << std::is_function<int(int)>::value << '\n';
    std::cout << std::is_function<decltype(f)>::value << '\n';
    std::cout << std::is_function<int>::value << '\n';

    using T = PM_traits<decltype(&A::fun)>::member_type; // T 为 int() const&
    std::cout << std::is_function<T>::value << '\n';
}

输出：

false
true
true
false
true

参阅

is_invocableis_invocable_ris_nothrow_invocableis_nothrow_invocable_r (C++17) | 检查类型能否以给定的实参类型调用（如同以 std::invoke） (类模板)
is_object (C++11) | 检查是否是对象类型 (类模板)
is_class (C++11) | 检查类型是否非联合类类型 (类模板)


std::is_fundamental

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_fundamental; | (C++11 起)

若 T 为基础类型（即算术类型、 void 或 nullptr_t ），则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

添加 is_fundamental 或 is_fundamental_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_fundamental_v = is_fundamental<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为基础类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template< class T >
struct is_fundamental
  : std::integral_constant<
        bool,
        std::is_arithmetic<T>::value ||
        std::is_void<T>::value  ||
        std::is_same<std::nullptr_t, typename std::remove_cv<T>::type>::value
> {};

示例

#include <iostream>
#include <type_traits>

class A {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << "A\t"      << std::is_fundamental<A>::value << '\n';
    std::cout << "int\t"    << std::is_fundamental<int>::value << '\n';
    std::cout << "int&\t"   << std::is_fundamental<int&>::value << '\n';
    std::cout << "int*\t"   << std::is_fundamental<int*>::value << '\n';
    std::cout << "float\t"  << std::is_fundamental<float>::value << '\n';
    std::cout << "float&\t" << std::is_fundamental<float&>::value << '\n';
    std::cout << "float*\t" << std::is_fundamental<float*>::value << '\n';
}

输出：

A      false
int     true
int&        false
int*    false
float   true
float&      false
float*  false

参阅

is_compound (C++11) | 检查是否为复合类型 (类模板)
is_arithmetic (C++11) | 检查类型是否为算术类型 (类模板)
is_void (C++11) | 检查类型是否为 void (类模板)


std::is_integral

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_integral; | (C++11 起)

检查 T 是否为整数类型。若 T 为 bool、 char、 char8_t (C++20 起)、 char16_t、 char32_t、 wchar_t、 short、 int、 long、 long long 类型，或任何实现定义的扩展整数类型，包含任何有符号、无符号及 cv 限定的变体。则提供等于 true 的成员常量 value 。否则， value 等于 false 。

添加 is_integral 或 is_integral_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_integral_v = is_integral<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为整数类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <iostream>
#include <type_traits>

class A {};

enum E : int {};

template <class T>
T f(T i)
{
    static_assert(std::is_integral<T>::value, "Integral required.");
    return i;
}

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_integral<A>::value << '\n';
    std::cout << std::is_integral<E>::value << '\n';
    std::cout << std::is_integral<float>::value << '\n';
    std::cout << std::is_integral<int>::value << '\n';
    std::cout << std::is_integral<bool>::value << '\n';
    std::cout << f(123) << '\n';
}

输出：

false
false
false
true
true
123

参阅

integral (C++20) | 指定类型为整型类型 (概念)
is_integer [静态] | 鉴别整数类型 (std::numeric_limits<T> 的公开静态成员常量)
is_floating_point (C++11) | 检查类型是否是浮点类型 (类模板)
is_arithmetic (C++11) | 检查类型是否为算术类型 (类模板)
is_enum (C++11) | 检查类型是否是枚举类型 (类模板)


std::is_invocable, std::is_invocable_r, std::is_nothrow_invocable, std::is_nothrow_invocable_r

< cpp‎ | types
定义于头文件 <type_traits> |  |
template <class Fn, class... ArgTypes> struct is_invocable; | (1) | (C++17 起)
template <class R, class Fn, class... ArgTypes> struct is_invocable_r; | (2) | (C++17 起)
template <class Fn, class... ArgTypes> struct is_nothrow_invocable; | (3) | (C++17 起)
template <class R, class Fn, class... ArgTypes> struct is_nothrow_invocable_r; | (4) | (C++17 起)
1) 确定是否能以参数 ArgTypes... 调用 Fn 。正式而言，确定 INVOKE(declval<Fn>(), declval<ArgTypes>()...) 在被当做不求值运算数时是否为良式，其中 INVOKE 是 可调用 (Callable) 中定义的运算。
2) 确定是否能以参数 ArgTypes... 调用 Fn 并生成可转换为 R 的结果。正式而言，确定 INVOKE<R>(declval<Fn>(), declval<ArgTypes>()...) 在被当做不求值运算数时是否为良式，其中 INVOKE 是 可调用 (Callable) 中定义的运算。
3) 确定是否能以参数 ArgTypes... 调用 Fn （同 (1) ），并已知这种调用不抛任何异常。
4) 确定是否能以参数 ArgTypes... 调用 Fn 并生成可转换为 R 的结果（同 (2) ），并已知这种调用（包括转换）不抛任何异常。

Fn, R 与参数包 ArgTypes 中的所有类型应均为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

添加此页面上描述的任何模板的特化的程序行为未定义。

辅助变量模板

定义于头文件 <type_traits> |  |
template <class Fn, class... ArgTypes> inline constexpr bool is_invocable_v = std::is_invocable<Fn, ArgTypes...>::value; | (1) | (C++17 起)
template <class R, class Fn, class... ArgTypes> inline constexpr bool is_invocable_r_v = std::is_invocable_r<R, Fn, ArgTypes...>::value; | (2) | (C++17 起)
template <class Fn, class... ArgTypes> inline constexpr bool is_nothrow_invocable_v = std::is_nothrow_invocable<Fn, ArgTypes...>::value; | (3) | (C++17 起)
template <class R, class Fn, class... ArgTypes> inline constexpr bool is_nothrow_invocable_r_v = std::is_nothrow_invocable_r<R, Fn, ArgTypes...>::value; | (4) | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 INVOKE<R>(declval<Fn>(), declval<ArgTypes>()...) 在被当做不求值运算数时为良式 则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <type_traits>

auto func2(char) -> int (*)()
{
    return nullptr;
}

int main()
{
    static_assert( std::is_invocable<int()>::value );
    static_assert( std::is_invocable_r<int, int()>::value );
    static_assert( std::is_invocable_r<void, void(int), int>::value );
    static_assert( std::is_invocable_r<int(*)(), decltype(func2), char>::value );
}

参阅

invokeinvoke_r (C++17)(C++23) | 以给定实参和可能指定的返回类型 (C++23 起)调用任意可调用 (Callable) 对象 (函数模板)
result_ofinvoke_result (C++11)(C++20 中移除)(C++17) | 推导以一组实参调用一个可调用对象的结果类型 (类模板)
declval (C++11) | 获取到其实参的引用，用于不求值语境中 (函数模板)


std::is_layout_compatible

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T, class U > struct is_layout_compatible; | (C++20 起)

若 T 与 U 是布局兼容的类型，则提供等于 true 的成员常量 value 。否则 value 为 false 。

每个类型均与其任何 cv 限定版本布局兼容，即使它不是对象类型。

T 与 U 应均为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

添加 is_layout_compatible 或 is_layout_compatible_v 的特化的程序行为未定义。

辅助变量模板

template< class T, class U > inline constexpr bool is_layout_compatible_v = is_layout_compatible<T, U>::value; | (C++20 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 与 U 布局兼容则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注解

有符号整数类型与其无符号对应非布局兼容。 char 既不与 signed char 亦不与 unsigned char 布局兼容。

相似类型非布局兼容，若它们在忽略顶层 cv 限定后不是同一类型。

枚举类型与其底层类型非布局兼容。

布局兼容但不相同（忽略 cv 限定）的元素类型的数组类型非布局兼容，即使它们拥有相等的长度。

示例

#include <type_traits>
#include <iostream>

struct Foo {
    int x;
    char y;
};

class Bar {
    const int u = 42;
    volatile char v = '*';
};

enum E0 : int {};
enum class E1 : int {};

int main()
{
    std::cout << std::boolalpha
        << std::is_layout_compatible_v<const void, volatile void> << '\n'
        << std::is_layout_compatible_v<Foo, Bar> << '\n'
        << std::is_layout_compatible_v<Foo[2], Bar[2]> << '\n'
        << std::is_layout_compatible_v<int, E0> << '\n'
        << std::is_layout_compatible_v<E0, E1> << '\n'
        << std::is_layout_compatible_v<long, unsigned long> << '\n'
        << std::is_layout_compatible_v<char*, const char*> << '\n'
        << std::is_layout_compatible_v<char*, char* const> << '\n';
}

输出：

true
true
false
false
true
false
false
true

参阅

is_standard_layout
(C++11)
 检查是否是一个标准布局类型
(类模板)


std::is_literal_type

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_literal_type; | (C++11 起) (C++17 中弃用) (C++20 中移除)

若 T 满足所有字面类型 (LiteralType) 的要求，则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

若 std::remove_all_extents_t <T> 为不完整类型且非（可有 cv 限定的） void 则行为未定义。

添加 is_literal_type 或 is_literal_type_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_literal_type_v = is_literal_type<T>::value; | (C++17 起) (弃用) (C++20 中移除)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为字面类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注意

唯有字面类型能作为 constexpr 函数的参数或返回类型。只有字面类能拥有 constexpr 成员函数。

示例

#include <iostream>
#include <type_traits>

struct A {
    int m;
};

struct B {
    virtual ~B();
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_literal_type<A>::value << '\n';
    std::cout << std::is_literal_type<B>::value << '\n';
}

输出：

true
false

参阅


std::is_lvalue_reference

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_lvalue_reference; | (C++11 起)

检查 T 是否为左值引用类型。若 T 是左值引用类型，则提供等于 true 的成员常量 value ，否则， value 等于 false 。

添加 is_lvalue_reference 或 is_lvalue_reference_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_lvalue_reference_v = is_lvalue_reference<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为左值引用类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template<class T> struct is_lvalue_reference     : std::false_type {};
template<class T> struct is_lvalue_reference<T&> : std::true_type {};

示例

#include <iostream>
#include <type_traits>

class A {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_lvalue_reference<A>::value << '\n';
    std::cout << std::is_lvalue_reference<A&>::value << '\n';
    std::cout << std::is_lvalue_reference<A&&>::value << '\n';
    std::cout << std::is_lvalue_reference<int>::value << '\n';
    std::cout << std::is_lvalue_reference<int&>::value << '\n';
    std::cout << std::is_lvalue_reference<int&&>::value << '\n';
}

输出：

false
true
false
false
true
false

参阅

is_reference (C++11) | 检查类型是否为左值引用或右值引用 (类模板)
is_rvalue_reference (C++11) | 检查类型是否为右值引用 (类模板)


std::is_member_function_pointer

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_member_function_pointer; | (C++11 起)

检查 T 是否为非静态成员函数指针。若 T 为非静态成员函数指针类型，则提供等于 true 的成员常量 value 。否则， value 等于 false 。

添加 is_member_function_pointer 或 is_member_function_pointer_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_member_function_pointer_v = is_member_function_pointer<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为成员函数指针类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template< class T >
struct is_member_function_pointer_helper : std::false_type {};

template< class T, class U>
struct is_member_function_pointer_helper<T U::*> : std::is_function<T> {};

template< class T >
struct is_member_function_pointer
  : is_member_function_pointer_helper< typename std::remove_cv<T>::type > {};

示例

#include <type_traits>

class A {
public:
    void member() { }
};

int main()
{
    // 若 A::member 是数据成员而非函数，则在编译时失败
    static_assert(std::is_member_function_pointer<decltype(&A::member)>::value,
                  "A::member is not a member function.");
}

参阅

is_pointer (C++11) | 检查类型是否为指针类型 (类模板)
is_member_object_pointer (C++11) | 检查类型是否为指向非静态成员对象的指针 (类模板)
is_member_pointer (C++11) | 检查类型是否为指向非静态成员函数或对象的指针类型 (类模板)


std::is_member_object_pointer

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_member_object_pointer; | (C++11 起)

检查 T 是否为非静态成员对象指针。若 T 是非静态成员对象指针类型，则提供等于 true 的成员常量 value 。否则， value 等于 false 。

添加 is_member_object_pointer 或 is_member_object_pointer_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_member_object_pointer_v = is_member_object_pointer<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为指向成员对象指针则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template<class T>
struct is_member_object_pointer : std::integral_constant<
                                      bool,
                                      std::is_member_pointer<T>::value &&
                                      !std::is_member_function_pointer<T>::value
                                  > {};

示例

本节未完成
原因：简化
#include <iostream>
#include <type_traits>

int main() {
    class cls {};
    std::cout << (std::is_member_object_pointer<int(cls::*)>::value
                     ? "T is member object pointer"
                     : "T is not a member object pointer") << '\n';
    std::cout << (std::is_member_object_pointer<int(cls::*)()>::value
                     ? "T is member object pointer"
                     : "T is not a member object pointer") << '\n';
}

输出：

T is member object pointer
T is not a member object pointer

参阅

is_pointer (C++11) | 检查类型是否为指针类型 (类模板)
is_member_pointer (C++11) | 检查类型是否为指向非静态成员函数或对象的指针类型 (类模板)
is_member_function_pointer (C++11) | 检查类型是否为指向非静态成员函数的指针 (类模板)


std::is_member_pointer

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_member_pointer; | (C++11 起)

若 T 为指向非静态成员对象或非静态成员函数的指针，则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

添加 is_member_pointer 或 is_member_pointer_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_member_pointer_v = is_member_pointer<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为成员指针类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template< class T >
struct is_member_pointer_helper         : std::false_type {};

template< class T, class U >
struct is_member_pointer_helper<T U::*> : std::true_type {};

template< class T >
struct is_member_pointer :
    is_member_pointer_helper<typename std::remove_cv<T>::type> {};

示例

本节未完成
原因：简化
#include <iostream>
#include <type_traits>

int main() {
    class cls {};
    std::cout << (std::is_member_pointer<int(cls::*)>::value
                     ? "T is member pointer"
                     : "T is not a member pointer") << '\n';
    std::cout << (std::is_member_pointer<int>::value
                     ? "T is member pointer"
                     : "T is not a member pointer") << '\n';
}

输出：

T is member pointer
T is not a member pointer

参阅

is_pointer (C++11) | 检查类型是否为指针类型 (类模板)
is_member_object_pointer (C++11) | 检查类型是否为指向非静态成员对象的指针 (类模板)
is_member_function_pointer (C++11) | 检查类型是否为指向非静态成员函数的指针 (类模板)


std::is_move_assignable, std::is_trivially_move_assignable, std::is_nothrow_move_assignable

< cpp‎ | types
定义于头文件 <type_traits> |  |
template< class T > struct is_move_assignable; | (1) | (C++11 起)
template< class T > struct is_trivially_move_assignable; | (2) | (C++11 起)
template< class T > struct is_nothrow_move_assignable; | (3) | (C++11 起)
1) 若 T 不是可引用类型（即可为 cv 限定的 void 或带 cv-qualifier-seq 或 ref-qualifier 的函数类型），则提供等于 false 的成员常量 value 。否则，提供等于 std::is_assignable <T&, T&&>::value 的成员常量 value 。
2) 同 (1) ，但使用 std::is_trivially_assignable <T&, T&&>
3) 同 (1) ，但使用 std::is_nothrow_assignable <T&, T&&>

T 应为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

添加此页面上描述的任何模板的特化的程序行为未定义。

辅助变量模板

template< class T > inline constexpr bool is_move_assignable_v = is_move_assignable<T>::value; | (C++17 起)
template< class T > inline constexpr bool is_trivially_move_assignable_v = is_trivially_move_assignable<T>::value; | (C++17 起)
template< class T > inline constexpr bool is_nothrow_move_assignable_v = is_nothrow_move_assignable<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 可移动赋值则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template< class T>
struct is_move_assignable
    : std::is_assignable< typename std::add_lvalue_reference<T>::type,
                          typename std::add_rvalue_reference<T>::type> {};

template< class T>
struct is_trivially_move_assignable
    : std::is_trivially_assignable< typename std::add_lvalue_reference<T>::type,
                                    typename std::add_rvalue_reference<T>::type> {};

template< class T>
struct is_nothrow_move_assignable
    : std::is_nothrow_assignable< typename std::add_lvalue_reference<T>::type,
                                  typename std::add_rvalue_reference<T>::type> {};

注解

特征 std::is_move_assignable 不如可移动赋值 (MoveAssignable) 严格，因为它既不检查赋值的结果类型（对于可移动赋值 (MoveAssignable) 类型必须是 T& ），也不检查赋值后目标的值等于赋值前源的值的语义要求。

为满足此特征，类型不必实现移动赋值运算符，细节见可移动赋值 (MoveAssignable) 。

示例

#include <iostream>
#include <string>
#include <type_traits>
struct Foo { int n; };
struct NoMove {
    // 避免默认的移动赋值运算符的隐式定义
    // 然而，该类仍然可移动赋值，因为
    // 其复制赋值运算符能绑定到右值参数
    NoMove& operator=(const NoMove&) { return *this; }
};
int main() {
    std::cout << std::boolalpha
              << "std::string is nothrow move-assignable? "
              << std::is_nothrow_move_assignable<std::string>::value << '\n'
              << "int[2] is move-assignable? "
              << std::is_move_assignable<int[2]>::value << '\n'
              << "Foo is trivally move-assignable? "
              << std::is_trivially_move_assignable<Foo>::value << '\n';

    std::cout << std::boolalpha
              << "NoMove is move-assignable? "
              << std::is_move_assignable<NoMove>::value << '\n'
              << "NoMove is nothrow move-assignable? "
              << std::is_nothrow_move_assignable<NoMove>::value << '\n';
}

输出：

std::string is nothrow move-assignable? true
int[2] is move-assignable? false
Foo is trivially move-assignable? true
NoMove is move-assignable? true
NoMove is nothrow move-assignable? false

参阅

is_assignableis_trivially_assignableis_nothrow_assignable (C++11)(C++11)(C++11) | 检查类型是否拥有针对特定实参的赋值运算符 (类模板)
is_copy_assignableis_trivially_copy_assignableis_nothrow_copy_assignable (C++11)(C++11)(C++11) | 检查类型是否拥有复制赋值运算符 (类模板)


std::is_move_constructible, std::is_trivially_move_constructible, std::is_nothrow_move_constructible

< cpp‎ | types
定义于头文件 <type_traits> |  |
template< class T > struct is_move_constructible; | (1) | (C++11 起)
template< class T > struct is_trivially_move_constructible; | (2) | (C++11 起)
template< class T > struct is_nothrow_move_constructible; | (3) | (C++11 起)
1) 若 T 不是可引用类型（即可为 cv 限定的 void 或带 cv-qualifier-seq 或 ref-qualifier 的函数类型），则提供等于 false 的成员常量 value 。否则，提供等于 std::is_constructible <T, T&&>::value 的成员常量 value。
2) 同 (1) ，但使用 std::is_trivially_constructible <T, T&&> 。
3) 同 (1) ，但使用 std::is_nothrow_constructible <T, T&&> 。

T 应为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

添加此页面上描述的任何模板的特化的程序行为未定义。

辅助变量模板

template< class T > inline constexpr bool is_move_constructible_v = is_move_constructible<T>::value; | (C++17 起)
template< class T > inline constexpr bool is_trivially_move_constructible_v = is_trivially_move_constructible<T>::value; | (C++17 起)
template< class T > inline constexpr bool is_nothrow_move_constructible_v = is_nothrow_move_constructible<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为可移动构造则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template<class T>
struct is_move_constructible :
      std::is_constructible<T, typename std::add_rvalue_reference<T>::type> {};

template<class T>
struct is_trivially_move_constructible :
     std::is_trivially_constructible<T, typename std::add_rvalue_reference<T>::type> {};

template<class T>
struct is_nothrow_move_constructible :
     std::is_nothrow_constructible<T, typename std::add_rvalue_reference<T>::type> {};

注解

无移动构造函数的但有接受 const T& 参数的复制构造函数的类型，满足 std::is_move_constructible 。

移动构造函数通常是 noexcept ，因为否则它们就不可用于任何提供强异常保证的代码中。

多数实现中， is_nothrow_move_constructible 亦检查析构函数是否抛出，因为它等效于 noexcept(T(arg)) 。同样的情况应用于 is_trivially_move_constructible ，它在这些实现中亦要求析构函数为平凡： GCC 漏洞 51452 、 LWG 问题 2116。

示例

#include <iostream>
#include <type_traits>

struct Ex1 {
    std::string str; // 成员拥有非平凡而不抛出的移动构造函数
};
struct Ex2 {
    int n;
    Ex2(Ex2&&) = default; // 平凡且不抛出
};
struct NoMove {
    // 避免默认移动构造函数的隐式声明
    // 然而，该类仍为可移动构造因为复制构造函数能绑定到右值参数
    NoMove(const NoMove&) {}
};

int main() {
    std::cout << std::boolalpha << "Ex1 is move-constructible? "
              << std::is_move_constructible<Ex1>::value << '\n'
              << "Ex1 is trivially move-constructible? "
              << std::is_trivially_move_constructible<Ex1>::value << '\n'
              << "Ex1 is nothrow move-constructible? "
              << std::is_nothrow_move_constructible<Ex1>::value << '\n'
              << "Ex2 is trivially move-constructible? "
              << std::is_trivially_move_constructible<Ex2>::value << '\n'
              << "Ex2 is nothrow move-constructible? "
              << std::is_nothrow_move_constructible<Ex2>::value << '\n';

    std::cout << std::boolalpha
              << "NoMove is move-constructible? "
              << std::is_move_constructible<NoMove>::value << '\n'
              << "NoMove is nothrow move-constructible? "
              << std::is_nothrow_move_constructible<NoMove>::value << '\n';
}

输出：

Ex1 is move-constructible? true
Ex1 is trivially move-constructible? false
Ex1 is nothrow move-constructible? true
Ex2 is trivially move-constructible? true
Ex2 is nothrow move-constructible? true
NoMove is move-constructible? true
NoMove is nothrow move-constructible? false

参阅

is_constructibleis_trivially_constructibleis_nothrow_constructible (C++11)(C++11)(C++11) | 检查类型是否带有针对特定实参的构造函数 (类模板)
is_default_constructibleis_trivially_default_constructibleis_nothrow_default_constructible (C++11)(C++11)(C++11) | 检查类型是否有默认构造函数 (类模板)
is_copy_constructibleis_trivially_copy_constructibleis_nothrow_copy_constructible (C++11)(C++11)(C++11) | 检查类型是否拥有复制构造函数 (类模板)
move_if_noexcept (C++11) | 若移动构造函数不抛出则获得右值引用 (函数模板)


std::is_null_pointer

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_null_pointer; | (C++14 起)

检查 T 是否为 std::nullptr_t 类型。

若 T 为 std::nullptr_t 、 const std::nullptr_t 、 volatile std::nullptr_t 或 const volatile std::nullptr_t 类型，则提供等于 true 的成员常量 value 。

否则， value 等于 false 。

添加 is_null_pointer 或 is_null_pointer_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_null_pointer_v = is_null_pointer<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为（可有 cv 限定的） std::nullptr_t 类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template< class T >
struct is_null_pointer : std::is_same<std::nullptr_t, std::remove_cv_t<T>> {};

注意

对于 std::nullptr_t ， std::is_pointer 为 false ，因为它不是内建指针类型。

示例

#include <iostream>
#include <type_traits>

int main()
{
    std::cout << std::boolalpha
              << std::is_null_pointer< decltype(nullptr) >::value << ' '
              << std::is_null_pointer< int* >::value << '\n'
              << std::is_pointer< decltype(nullptr) >::value << ' '
              << std::is_pointer<int*>::value << '\n';
}

输出：

true false
false true

参阅

is_void (C++11) | 检查类型是否为 void (类模板)
is_array (C++11) | 检查类型是否是数组类型 (类模板)
is_pointer (C++11) | 检查类型是否为指针类型 (类模板)
is_enum (C++11) | 检查类型是否是枚举类型 (类模板)
is_union (C++11) | 检查类型是否为联合体类型 (类模板)
is_class (C++11) | 检查类型是否非联合类类型 (类模板)
is_function (C++11) | 检查是否为函数类型 (类模板)
is_object (C++11) | 检查是否是对象类型 (类模板)


std::is_object

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_object; | (C++11 起)

若 T 为对象类型（即任何函数、引用或 void 类型外的可有 cv 限定的类型），则提供等于 true 的成员常量 value 。对于任何其他类型， value 等于 false 。

添加 is_object 或 is_object_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_object_v = is_object<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为对象类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template< class T>
struct is_object : std::integral_constant<bool,
                     std::is_scalar<T>::value ||
                     std::is_array<T>::value  ||
                     std::is_union<T>::value  ||
                     std::is_class<T>::value> {};

示例

#include <iostream>
#include <type_traits>

int main() {
    class cls {};
    std::cout << std::boolalpha;
    std::cout << std::is_object<int>::value << '\n';
    std::cout << std::is_object<int&>::value << '\n';
    std::cout << std::is_object<cls>::value << '\n';
    std::cout << std::is_object<cls&>::value << '\n';
}

输出：

true
false
true
false

参阅

is_scalar (C++11) | 检查类型是否为标量类型 (类模板)
is_array (C++11) | 检查类型是否是数组类型 (类模板)
is_union (C++11) | 检查类型是否为联合体类型 (类模板)
is_class (C++11) | 检查类型是否非联合类类型 (类模板)


std::is_pod

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_pod; | (C++11 起) (C++20 中弃用)

若 T 是简旧数据类型 (PODType) ，即既是平凡又是标准布局，则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

若 std::remove_all_extents_t <T> 是不完整类型且非（可为 cv 限定的） void 则行为未定义。

添加 is_pod 或 is_pod_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_pod_v = is_pod<T>::value; | (C++17 起) (C++20 中弃用)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为 POD 类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <iostream>
#include <type_traits>

struct A {
    int m;
};

struct B {
    int m1;
private:
    int m2;
};

struct C {
    virtual void foo();
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_pod<A>::value << '\n';
    std::cout << std::is_pod<B>::value << '\n';
    std::cout << std::is_pod<C>::value << '\n';
}

输出：

true
false
false

参阅

is_standard_layout (C++11) | 检查是否是一个标准布局类型 (类模板)
is_trivial (C++11) | 检查类型是否平凡 (类模板)


std::is_pointer

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_pointer; | (C++11 起)

检查 T 是否为指向对象指针或指向函数指针（但不是指向成员/成员函数指针）。若 T 是对象/函数指针类型，则提供等于 true 的成员常量 value 。否则， value 等于 false 。

添加 is_pointer 或 is_pointer_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_pointer_v = is_pointer<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为指针类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template<class T>
struct is_pointer_helper : std::false_type {};

template<class T>
struct is_pointer_helper<T*> : std::true_type {};

template<class T>
struct is_pointer : is_pointer_helper< typename std::remove_cv<T>::type > {};

示例

#include <iostream>
#include <type_traits>

class A {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_pointer<A>::value << '\n';
    std::cout << std::is_pointer<A *>::value << '\n';
    std::cout << std::is_pointer<A &>::value << '\n';
    std::cout << std::is_pointer<int>::value << '\n';
    std::cout << std::is_pointer<int *>::value << '\n';
    std::cout << std::is_pointer<int **>::value << '\n';
    std::cout << std::is_pointer<int[10]>::value << '\n';
    std::cout << std::is_pointer<std::nullptr_t>::value << '\n';
}

输出：

false
true
false
false
true
true
false
false

参阅

is_member_pointer (C++11) | 检查类型是否为指向非静态成员函数或对象的指针类型 (类模板)
is_member_object_pointer (C++11) | 检查类型是否为指向非静态成员对象的指针 (类模板)
is_member_function_pointer (C++11) | 检查类型是否为指向非静态成员函数的指针 (类模板)
is_array (C++11) | 检查类型是否是数组类型 (类模板)
is_scalar (C++11) | 检查类型是否为标量类型 (类模板)


std::is_pointer_interconvertible_base_of

< cpp‎ | types
定义于头文件 <type_traits> |
template< class Base, class Derived > struct is_pointer_interconvertible_base_of; | (C++20 起)

若 Derived 无歧义地派生自 Base 且每个 Derived 对象均与其 Base 子对象指针可互转换，或它们均为相同的非联合类类型（两种情况下都忽略 cv 限定），则提供等于 true 的成员常量 value 。否则 value 为 false 。

若 Base 与 Derived 均为非联合类类型且不是同一类型（忽略 cv 限定），则 Derived 应当为完整类型；否则行为未定义。

添加 is_pointer_interconvertible_base_of 或 is_pointer_interconvertible_base_of_v 的特化的程序行为未定义。

辅助变量模板

template< class Base, class Derived > inline constexpr bool is_pointer_interconvertible_base_of_v = is_pointer_interconvertible_base_of<Base, Derived>::value; | (C++20 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 Derived 无歧义地派生自 Base 且每个 Derived 对象均与其 Base 子对象指针可互转换，或它们均为相同的非联合类类型（两种情况下都忽略 cv 限定）则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注解

即使 T 为 U 的私有或受保护基类， std::is_pointer_interconvertible_base_of_v<T, U> 亦可能为 true 。

令

  • U 为完整对象类型，
  • T 为 cv 限定不少于 U 的完整对象类型，
  • u 为任何合法的 U 左值，

则 reinterpret_cast<T&>(u) 始终有良定义的结果，若 std::is_pointer_interconvertible_base_of_v<T, U> 为 true 。

若 T 与 U 不是同一类型（忽略 cv 限定）且 T 为 U 的指针可互转换基类，则 std::is_standard_layout_v <T> 与 std::is_standard_layout_v <U> 均为 true 。

若 T 为空类类型，则 T 的所有基类（若存在）均为 T 的指针可互转换基类。

若 T 为非空标准布局类类型，则 T 的所有非空基类（若存在）均为 T 的指针可互转换基类，此情况下某些空空基类亦可能为指针可互转换基类。

示例

#include <iostream>
#include <type_traits>

struct Foo {};

struct Bar {};

class Baz : Foo, public Bar {
    int x;
};

class NonStdLayout : public Baz {
    int y;
};

int main()
{
    std::cout << std::boolalpha
        << std::is_pointer_interconvertible_base_of_v<Bar, Baz> << '\n'
        << std::is_pointer_interconvertible_base_of_v<Foo, Baz> << '\n';
        << std::is_pointer_interconvertible_base_of_v<Baz, NonStdLayout> << '\n'
        << std::is_pointer_interconvertible_base_of_v<NonStdLayout, NonStdLayout> << '\n';
}

输出：

true
true
false
true

参阅

is_base_of (C++11) | 检查一个类型是否派生自另一个类型 (类模板)
is_empty (C++11) | 检查类型是否为类（但非联合体）类型且无非静态数据成员 (类模板)
is_standard_layout (C++11) | 检查是否是一个标准布局类型 (类模板)


std::is_pointer_interconvertible_with_class

< cpp‎ | types
定义于头文件 <type_traits> |
template<class S, class M> constexpr bool is_pointer_interconvertible_with_class( M S::* mp ) noexcept; | (C++20 起)

给定 S 类型对象 s ，确定是否 s.*mp 指代 s 的子对象且 s 与其子对象 s.*mp 指针可互转换。若 S 不是完整类型则程序为谬构。

若 S 不是标准布局类型 (StandardLayoutType) ，或 M 不是对象类型，或 mp 等于 nullptr ，则结果始终为 false 。

参数

mp - 要检测的成员指针

返回值

若 s.*mp 指代 s 的子对象且 s 与其子对象 s.*mp 指针可互转换则为 true ，否则为 false ，其中 s 是 S 类型对象。

注解

成员指针表达式 &S::m 的类型并非始终是 M S::* ，其中 m 的类型为 M ，因为 m 可能是从 S 的基类继承的成员。能指定第一模板实参以避免潜在地令人诧异的结果。

若存在 M S::* 类型值 mp 使得 std::is_pointer_interconvertible_with_class(mp) == true ，则 reinterpret_cast<M&>(s) 拥有良定义结果且与 s.*mp 指代同一子对象，其中 s 是合法的 S 类型左值。

在常用平台上，若 std::is_pointer_interconvertible_with_class(mp) == true ，则 mp 的位模式为全零。

示例

#include <type_traits>
#include <iostream>

struct Foo { int x; };
struct Bar { int y; };

struct Baz : Foo, Bar {}; // 非标准布局

int main()
{
    std::cout << std::boolalpha
        << std::is_same_v<decltype(&Baz::x), int Baz::*>
        << std::is_pointer_interconvertible_with_class(&Baz::x) << '\n'
        << std::is_pointer_interconvertible_with_class<Baz>(&Baz::x) << '\n';
}

输出：

false
true
false

参阅

is_standard_layout (C++11) | 检查是否是一个标准布局类型 (类模板)
is_member_object_pointer (C++11) | 检查类型是否为指向非静态成员对象的指针 (类模板)


std::is_polymorphic

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_polymorphic; | (C++11 起)

若 T 为多态类（即声明或继承至少一个虚函数的非联合类），则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

若 T 是非联合类类型，则 T 应为完整类型；否则行为未定义。

添加 is_polymorphic 或 is_polymorphic_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_polymorphic_v = is_polymorphic<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 是多态类类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

namespace detail {

template <class T>
std::true_type detect_is_polymorphic(
    decltype(dynamic_cast<const volatile void*>(static_cast<T*>(nullptr)))
);
template <class T>
std::false_type detect_is_polymorphic(...);

} // namespace detail

template <class T>
struct is_polymorphic : decltype(detail::detect_is_polymorphic<T>(nullptr)) {};

示例

#include <iostream>
#include <type_traits>

struct A {
    int m;
};

struct B {
    virtual void foo();
};

struct C : B {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_polymorphic<A>::value << '\n';
    std::cout << std::is_polymorphic<B>::value << '\n';
    std::cout << std::is_polymorphic<C>::value << '\n';
}

输出：

false
true
true

参阅

is_class (C++11) | 检查类型是否非联合类类型 (类模板)
is_abstract (C++11) | 检查类型是否为抽象类类型 (类模板)


std::is_reference

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_reference; | (C++11 起)

若 T 是引用类型（左值引用或右值引用），则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

添加 is_reference 或 is_reference_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_reference_v = is_reference<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 是引用类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template <class T> struct is_reference      : std::false_type {};
template <class T> struct is_reference<T&>  : std::true_type {};
template <class T> struct is_reference<T&&> : std::true_type {};

示例

#include <iostream>
#include <type_traits>

class A {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_reference<A>::value << '\n';
    std::cout << std::is_reference<A&>::value << '\n';
    std::cout << std::is_reference<A&&>::value << '\n';
    std::cout << std::is_reference<int>::value << '\n';
    std::cout << std::is_reference<int&>::value << '\n';
    std::cout << std::is_reference<int&&>::value << '\n';
}

输出：

false
true
true
false
true
true

参阅

is_lvalue_reference (C++11) | 检查类型是否为左值引用 (类模板)
is_rvalue_reference (C++11) | 检查类型是否为右值引用 (类模板)


std::is_rvalue_reference

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_rvalue_reference; | (C++11 起)

检查 T 是否为右值引用类型。若 T 是右值引用类型，则提供等于 true 的成员常量 value ，否则， value 等于 false 。

添加 is_rvalue_reference 或 is_rvalue_reference_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_rvalue_reference_v = is_rvalue_reference<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为右值引用类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template <class T> struct is_rvalue_reference      : std::false_type {};
template <class T> struct is_rvalue_reference<T&&> : std::true_type {};

示例

#include <iostream>
#include <type_traits>

class A {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_rvalue_reference<A>::value << '\n';
    std::cout << std::is_rvalue_reference<A&>::value << '\n';
    std::cout << std::is_rvalue_reference<A&&>::value << '\n';
    std::cout << std::is_rvalue_reference<int>::value << '\n';
    std::cout << std::is_rvalue_reference<int&>::value << '\n';
    std::cout << std::is_rvalue_reference<int&&>::value << '\n';
}

输出：

false
false
true
false
false
true

参阅

is_lvalue_reference (C++11) | 检查类型是否为左值引用 (类模板)
is_reference (C++11) | 检查类型是否为左值引用或右值引用 (类模板)


std::is_same

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T, class U > struct is_same; | (C++11 起)

若 T 与 U 指名同一类型（考虑 const/volatile 限定），则提供等于 true 的成员常量 value 。否则 value 为 false 。

满足交换律，即对于任何二个类型 T 与 U ， is_same<T, U>::value == true 当且仅当 is_same<U, T>::value == true 。

添加 is_same 或 is_same_v (C++17 起) 的特化的程序行为未定义。

辅助变量模板

template< class T, class U > inline constexpr bool is_same_v = is_same<T, U>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 与 U 是同一类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template<class T, class U>
struct is_same : std::false_type {};

template<class T>
struct is_same<T, T> : std::true_type {};

示例

#include <iostream>
#include <type_traits>
#include <cstdint>

void print_separator()
{
    std::cout << "-----\n";
}

int main()
{
    std::cout << std::boolalpha;

    // 一些实现定义状况
    std::cout << std::is_same<int, std::int32_t>::value << '\n';
    // 若 'int' 为 32 位则通常为 true
    std::cout << std::is_same<int, std::int64_t>::value << '\n';
    // 若使用 ILP64 数据模型则可能为 true

    print_separator();

    // 'float' 决非整数类型
    std::cout << std::is_same<float, std::int32_t>::value << '\n'; // false

    print_separator();

    // 'int' 为隐式的 'signed'
    std::cout << std::is_same<int, int>::value << "\n";          // true
    std::cout << std::is_same<int, unsigned int>::value << "\n"; // false
    std::cout << std::is_same<int, signed int>::value << "\n";   // true

    print_separator();

    // 不同于其他类型， 'char' 既非 'unsigned' 亦非 'signed'
    std::cout << std::is_same<char, char>::value << "\n";          // true
    std::cout << std::is_same<char, unsigned char>::value << "\n"; // false
    std::cout << std::is_same<char, signed char>::value << "\n";   // false
}

输出：

true
false
false
-----
true
false
true
-----
true
false
false

参阅

same_as (C++20) | 指定一个类型与另一类型相同 (概念)
is_integral (C++11) | 检查类型是否为整型 (类模板)
make_signed (C++11) | 使给定的整型类型有符号 (类模板)
make_unsigned (C++11) | 使给定的整型类型无符号 (类模板)
decltype 说明符 (C++11) | 获得表达式或实体的类型


std::is_scalar

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_scalar; | (C++11 起)

若 T 为标量类型（即可有 cv 限定的算术、指针、指向成员指针、枚举或 std::nullptr_t 类型），则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

添加 is_scalar 或 is_scalar_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_scalar_v = is_scalar<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 是标量类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注意

C++ 内存模型中的每个独立内存位置，包括语言特性所用的隐藏内存位置（如虚表指针），都拥有标量类型（或为相邻的零长位域序列）。表达式求值中的副效应排序、线程间同步和依赖顺序全部都基于标量对象定义。

可能的实现

template< class T >
struct is_scalar : std::integral_constant<bool,
                     std::is_arithmetic<T>::value     ||
                     std::is_enum<T>::value           ||
                     std::is_pointer<T>::value        ||
                     std::is_member_pointer<T>::value ||
                     std::is_null_pointer<T>::value> {};

示例

#include <iostream>
#include <type_traits>

int main() {
    class cls {};
    std::cout << (std::is_scalar<int>::value
                     ? "T is a scalar"
                     : "T is not a scalar") << '\n';
    std::cout << (std::is_scalar<cls>::value
                     ? "T is a scalar"
                     : "T is not a scalar") << '\n';
}

输出：

T is a scalar
T is not a scalar

参阅

is_arithmetic (C++11) | 检查类型是否为算术类型 (类模板)
is_enum (C++11) | 检查类型是否是枚举类型 (类模板)
is_pointer (C++11) | 检查类型是否为指针类型 (类模板)
is_member_pointer (C++11) | 检查类型是否为指向非静态成员函数或对象的指针类型 (类模板)


std::is_scoped_enum

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_scoped_enum; | (C++23 起)

检查 T 是否为有作用域枚举类型。若 为有作用域枚举类型则提供等于 true 的成员常量 value 。否则 value 等于 false 。

添加 is_scoped_enum 或 is_scoped_enum_v 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_scoped_enum_v = is_scoped_enum<T>::value; | (C++23 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为有作用域枚举类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <iostream>
#include <type_traits>

class A {};

enum E {};

enum struct Es { oz };

enum class Ec : int {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_scoped_enum_v<A> << '\n';
    std::cout << std::is_scoped_enum_v<E> << '\n';
    std::cout << std::is_scoped_enum_v<Es> << '\n';
    std::cout << std::is_scoped_enum_v<Ec> << '\n';
    std::cout << std::is_scoped_enum_v<int> << '\n';
}

输出：

false
false
true
true
false

参阅

is_integral (C++11) | 检查类型是否为整型 (类模板)
is_arithmetic (C++11) | 检查类型是否为算术类型 (类模板)
is_scalar (C++11) | 检查类型是否为标量类型 (类模板)
is_enum (C++11) | 检查类型是否是枚举类型 (类模板)


std::is_signed

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_signed; | (C++11 起)

若 T 是算术类型且 T(-1) < T(0) ，则提供等于 true 的成员常量 value ：这对于浮点类型和有符号整数类型产生 true ，并对无符号整数类型和 bool 类型产生 false 。

对于任何其他类型， value 为 false 。

添加 is_signed 或 is_signed_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_signed_v = is_signed<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为有符号算术类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

namespace detail {
template<typename T,bool = std::is_arithmetic<T>::value>
struct is_signed : std::integral_constant<bool, T(-1) < T(0)> {};

template<typename T>
struct is_signed<T,false> : std::false_type {};
} // namespace detail

template<typename T>
struct is_signed : detail::is_signed<T>::type {};

示例

#include <iostream>
#include <type_traits>

class A {};
enum B : int {};
enum class C : int {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_signed<A>::value << '\n';
    std::cout << std::is_signed<float>::value << '\n';
    std::cout << std::is_signed<signed int>::value << '\n';
    std::cout << std::is_signed<unsigned int>::value << '\n';
    std::cout << std::is_signed<B>::value << '\n';
    std::cout << std::is_signed<C>::value << '\n';

    // 简短的形式:
    std::cout << std::is_signed<signed int>() << '\n';
    std::cout << std::is_signed<unsigned int>() << '\n';
}

输出：

false
true
true
false
false
false
true
false

参阅

is_unsigned (C++11) | 检查类型是否为无符号算术类型 (类模板)
is_signed [静态] | 鉴别有符号类型 (std::numeric_limits<T> 的公开静态成员常量)
is_arithmetic (C++11) | 检查类型是否为算术类型 (类模板)
make_signed (C++11) | 使给定的整型类型有符号 (类模板)
make_unsigned (C++11) | 使给定的整型类型无符号 (类模板)


std::is_standard_layout

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_standard_layout; | (C++11 起)

若 T 为标准布局类型（即标量类型、标准布局类、或这种类型/类的数组，可以有 cv 限定），则提供等于 true 的成员常量 value 。对任何其他类型， value 为 false 。

标准布局类是满足标准布局类型 (StandardLayoutType) 的类。

若 std::remove_all_extents_t <T> 是不完整类型且非（可有 cv 限定的） void 则行为未定义。

添加 is_standard_layout 或 is_standard_layout_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_standard_layout_v = is_standard_layout<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为标准布局类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注解

指向标准布局类的指针能转换（以 reinterpret_cast ）成指向其首个非静态数据成员的指针，反之亦然。

若标准布局联合体保有二个或多个标准布局结构体，则允许查看它们的公共前导部分。

宏 offsetof 只保证能用于标准布局类。

示例

#include <iostream>
#include <type_traits>

struct A {
    int m;
};

struct B {
    int m1;
private:
    int m2;
};

struct C {
    virtual void foo();
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_standard_layout<A>::value << '\n';
    std::cout << std::is_standard_layout<B>::value << '\n';
    std::cout << std::is_standard_layout<C>::value << '\n';
}

输出：

true
false
false

参阅

is_trivially_copyable (C++11) | 检查类型是否可平凡复制 (类模板)
is_pod (C++11)(C++20 中弃用) | 检查类型是否为简旧数据（POD）类型 (类模板)
offsetof | 从标准布局类型的起始到其指定成员的字节偏移量 (宏函数)


std::is_swappable_with, std::is_swappable, std::is_nothrow_swappable_with, std::is_nothrow_swappable

< cpp‎ | types
定义于头文件 <type_traits> |  |
template< class T, class U > struct is_swappable_with; | (1) | (C++17 起)
template< class T > struct is_swappable; | (2) | (C++17 起)
template< class T, class U > struct is_nothrow_swappable_with; | (3) | (C++17 起)
template< class T > struct is_nothrow_swappable; | (4) | (C++17 起)
1) 若表达式 swap( std::declval <T>(), std::declval <U>()) 及 swap( std::declval <U>(), std::declval <T>()) 在使用 using std::swap ; （见 可交换 (Swappable) ）后的不求值语境中均为良构，则提供等于 true 的成员常量 value 。否则 value 为 false 。如同从与任一类型皆无关的语境进行访问检查。
2) 若 T 不是可解引用类型（即可为 cv 限定的 void 或拥有 cv-qualifier-seq 或 ref-qualifier 的函数类型），则提供等于 false 的成员常量 value 。否则，提供等于 std::is_swappable_with <T&, T&>::value 的成员常量 value 。
3) 同 (1) ，但已知来自 (1) 的两个表达式求值都不抛异常。
4) 同 (2) ，但使用 is_nothrow_swappable_with 。

T 与 U 应均为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

添加此页面上描述的任何模板的特化的程序行为未定义。

辅助变量模板

template <class T, class U> inline constexpr bool is_swappable_with_v = is_swappable_with<T, U>::value; | (C++17 起)
template <class T> inline constexpr bool is_swappable_v = is_swappable<T>::value; | (C++17 起)
template <class T, class U> inline constexpr bool is_nothrow_swappable_with_v = is_nothrow_swappable_with<T, U>::value; | (C++17 起)
template <class T> inline constexpr bool is_nothrow_swappable_v = is_nothrow_swappable<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若T 可与 U 交换则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注解

此特征不检查 swap 表达式的立即语境外的内容：若 T 或 U 的使用会触发模板特化，生成隐式定义的特定成员函数等，而它们有错误，则即使 std::is_swappable_with<T,U>::value 通过编译且求值为 true ，实际的 swap 也可能无法编译。

示例

本节未完成
原因：暂无示例

参阅

swap | 交换两个对象的值 (函数模板)
is_move_assignableis_trivially_move_assignableis_nothrow_move_assignable (C++11)(C++11)(C++11) | 检查类型是否有拥有移动赋值运算符 (类模板)


std::is_trivial

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_trivial; | (C++11 起)

若 T 为平凡类型 (TrivialType) （即标量类型、有平凡默认构造函数的可平凡复制类，或这些类/类型的数组，可有 cv 限定），则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

若 std::remove_all_extents_t <T> 是（可有 cv 限定的） void 以外的不完整类型，则行为未定义。

添加 is_trivial 或 is_trivial_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_trivial_v = is_trivial<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为平凡类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template< class T >
struct is_trivial : std::integral_constant<
    bool,
    std::is_trivially_copyable<T>::value &&
    std::is_trivially_default_constructible<T>::value
> {};

示例

#include <iostream>
#include <type_traits>

struct A {
    int m;
};

struct B {
    B() {}
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_trivial<A>::value << '\n';
    std::cout << std::is_trivial<B>::value << '\n';
}

输出：

true
false

参阅

is_trivially_copyable
(C++11)
 检查类型是否可平凡复制
(类模板)


std::is_trivially_copyable

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_trivially_copyable; | (C++11 起)

若 T 为可平凡复制 (TriviallyCopyable) 类型，则提供等于 true 的成员常量 value 。对于任何其他类型， value 是 false 。

仅有的可平凡复制类型是标量类型、可平凡复制类及这些类型/类的数组（可以为 cv 限定）。

若 std::remove_all_extents_t <T> 是非（可有 cv 限定的） void 的不完整类型，则行为未定义。

添加 is_trivially_copyable 或 is_trivially_copyable_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_trivially_copyable_v = is_trivially_copyable<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 是可平凡复制对象则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

注解

可平凡复制类型的，非潜在重叠子对象的对象是仅有的能以 std::memcpy 安全复制或以 std::ofstream::write()/std::ifstream::read() 序列化自/到二进制文件的对象。

示例

#include <iostream>
#include <type_traits>

struct A {
    int m;
};

struct B {
    B(const B&) {}
};

struct C {
    virtual void foo();
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_trivially_copyable<A>::value << '\n';
    std::cout << std::is_trivially_copyable<B>::value << '\n';
    std::cout << std::is_trivially_copyable<C>::value << '\n';
}

输出：

true
false
false

参阅

is_trivial
(C++11)
 检查类型是否平凡
(类模板)


std::is_unbounded_array

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_unbounded_array; | (C++20 起)

检查 T 是否为未知边界数组类型。若 T 是有未知边界的数组类型则提供等于 true, 的成员常量 value 。否则 value 等于 false 。

添加 is_unbounded_array 或 is_unbounded_array_v 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_unbounded_array_v = is_unbounded_array<T>::value; | (C++20 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 是有未知边界的数组类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template<class T>
struct is_unbounded_array: std::false_type {};

template<class T>
struct is_unbounded_array<T[]> : std::true_type {};

示例

#include <iostream>
#include <type_traits>

class A {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_unbounded_array_v<A> << '\n';
    std::cout << std::is_unbounded_array_v<A[]> << '\n';
    std::cout << std::is_unbounded_array_v<A[3]> << '\n';
    std::cout << std::is_unbounded_array_v<float> << '\n';
    std::cout << std::is_unbounded_array_v<int> << '\n';
    std::cout << std::is_unbounded_array_v<int[]> << '\n';
    std::cout << std::is_unbounded_array_v<int[3]> << '\n';
}

输出：

false
true
false
false
false
true
false

参阅

is_array (C++11) | 检查类型是否是数组类型 (类模板)
is_bounded_array (C++20) | 检查类型是否为有已知边界的数组类型 (类模板)
extent (C++11) | 获取数组类型在指定维度的大小 (类模板)


std::is_union

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_union; | (C++11 起)

检查 T 是否为联合体类型。若 T 为联合体类型，则提供等于 true 的成员常量 value 。否则 value ，等于 false 。

添加 is_union 或 is_union_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_union_v = is_union<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为联合体类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <iostream>
#include <type_traits>

struct A {};

typedef union {
    int a;
    float b;
} B;

struct C {
    B d;
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_union<A>::value << '\n';
    std::cout << std::is_union<B>::value << '\n';
    std::cout << std::is_union<C>::value << '\n';
    std::cout << std::is_union<int>::value << '\n';
}

输出：

false
true
false
false

参阅

is_class
(C++11)
 检查类型是否非联合类类型
(类模板)


std::is_unsigned

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_unsigned; | (C++11 起)

若 T 是算术类型且 T(0) < T(-1) ，则提供等于 true 的成员常量 value ：这对无符号整数类型和 bool 类型产生 true 并对有符号整数类型和浮点类型产生 false 。

对于任何其他类型， value 为 false 。

添加 is_unsigned 或 is_unsigned_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_unsigned_v = is_unsigned<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为无符号算术类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

namespace detail {
template<typename T,bool = std::is_arithmetic<T>::value>
struct is_unsigned : std::integral_constant<bool, T(0) < T(-1)> {};

template<typename T>
struct is_unsigned<T,false> : std::false_type {};
} // namespace detail

template<typename T>
struct is_unsigned : detail::is_unsigned<T>::type {};

示例

#include <iostream>
#include <type_traits>

class A {};
enum B : unsigned {};
enum class C : unsigned {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_unsigned<A>::value << '\n';
    std::cout << std::is_unsigned<float>::value << '\n';
    std::cout << std::is_unsigned<signed int>::value << '\n';
    std::cout << std::is_unsigned<unsigned int>::value << '\n';
    std::cout << std::is_unsigned<B>::value << '\n';
    std::cout << std::is_unsigned<C>::value << '\n';
}

输出：

false
false
false
true
false
false

参阅

is_signed (C++11) | 检查类型是否为有符号算术类型 (类模板)
is_arithmetic (C++11) | 检查类型是否为算术类型 (类模板)
make_signed (C++11) | 使给定的整型类型有符号 (类模板)
make_unsigned (C++11) | 使给定的整型类型无符号 (类模板)


std::is_void

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_void; | (C++11 起)

检查 T 是否为 void 类型。若 T 是类型 void 、 const void 、 volatile void 或 const volatile void ，则提供等于 true 的成员常量 value。否则， value 等于 false 。

添加 is_void 或 is_void_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_void_v = is_void<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为 void 类型（可有 cv 限定）则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template< class T >
struct is_void : std::is_same<void, typename std::remove_cv<T>::type> {};

示例

#include <iostream>
#include <type_traits>

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_void<void>::value << '\n';
    std::cout << std::is_void<int>::value << '\n';
}

输出：

true
false

参阅

is_array (C++11) | 检查类型是否是数组类型 (类模板)
is_pointer (C++11) | 检查类型是否为指针类型 (类模板)
is_enum (C++11) | 检查类型是否是枚举类型 (类模板)
is_union (C++11) | 检查类型是否为联合体类型 (类模板)
is_class (C++11) | 检查类型是否非联合类类型 (类模板)
is_function (C++11) | 检查是否为函数类型 (类模板)
is_object (C++11) | 检查是否是对象类型 (类模板)


std::is_volatile

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct is_volatile; | (C++11 起)

若 T 为 volatile 限定类型（即 volatile 或 const volatile ），则提供等于 true 的成员常量 value 。对于任何其他类型， value 为 false 。

添加 is_volatile 或 is_volatile_v (C++17 起) 的特化的程序行为未定义。

模板形参

T - 要检查的类型

辅助变量模板

template< class T > inline constexpr bool is_volatile_v = is_volatile<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 为 volatile 限定类型则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template<class T> struct is_volatile             : std::false_type {};
template<class T> struct is_volatile<volatile T> : std::true_type {};

示例

#include <iostream>
#include <type_traits>

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::is_volatile<int>::value << '\n';
    std::cout << std::is_volatile<volatile int>::value  << '\n';
}

输出：

false
true

参阅

is_const
(C++11)
 检查类型是否为 const 限定
(类模板)


std::make_signed

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct make_signed; | (C++11 起)

若 T 是整数（除 bool ）或枚举类型，则提供是对应 T 的有符号整数类型的成员 typedef type ，它拥有相同的 cv 限定符。

若 T 为有符号或无符号的 char 、 short 、 int 、 long 、 long long ；则提供来自此列表的对应 T 的有符号类型。

若 T 为枚举类型或 char 、 wchar_t 、 char8_t (C++20 起)、 char16_t 、 char32_t ；则提供与 T 有相同 sizeof 的有最小等级的有符号整数类型。

否则，行为未定义。 | (C++20 前)
否则，程序为非良构。 | (C++20 起)

添加 make_signed 的特化的程序行为未定义。

成员类型

名称 | 定义
type | 对应 T 的有符号整数类型

辅助类型

template< class T > using make_signed_t = typename make_signed<T>::type; | (C++14 起)

示例

#include <iostream>
#include <type_traits>

int main() {
    typedef std::make_signed<char>::type char_type;
    typedef std::make_signed<int>::type int_type;
    typedef std::make_signed<volatile long>::type long_type;

    bool ok1 = std::is_same<char_type, signed char>::value;
    bool ok2 = std::is_same<int_type, signed int>::value;
    bool ok3 = std::is_same<long_type, volatile signed long>::value;

    std::cout << std::boolalpha
    << "char_type is 'signed char'?          : " << ok1 << '\n'
    << "int_type  is 'signed int'?           : " << ok2 << '\n'
    << "long_type is 'volatile signed long'? : " << ok3 << '\n';
}

输出：

char_type is 'signed char'?          : true
int_type  is 'signed int'?           : true
long_type is 'volatile signed long'? : true

参阅

is_signed (C++11) | 检查类型是否为有符号算术类型 (类模板)
is_unsigned (C++11) | 检查类型是否为无符号算术类型 (类模板)
make_unsigned (C++11) | 使给定的整型类型无符号 (类模板)


std::make_unsigned

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct make_unsigned; | (C++11 起)

若 T 是整数（除 bool ）或枚举类型，则提供成员 typedef type ，它是对应 T 的拥有相同 cv 限定符的无符号整数类型。

若 T 为有符号或无符号的 char 、 short 、 int 、 long 、 long long ；则提供来自此列表的对应 T 的无符号类型。

若 T 为枚举类型或 char 、 wchar_t 、 char8_t (C++20 起)、 char16_t 、 char32_t ；则提供与 T 有相同 sizeof 的有最小等级的无符号整数类型。

否则，行为未定义。 | (C++20 前)
否则，程序为非良构。 | (C++20 起)

添加 make_unsigned 的特化的程序行为未定义。

成员类型

成员 | 定义
type | 对应 T 的无符号整数类型

辅助类型

template< class T > using make_unsigned_t = typename make_unsigned<T>::type; | (C++14 起)

示例

#include <iostream>
#include <type_traits>

int main() {
    typedef std::make_unsigned<char>::type char_type;
    typedef std::make_unsigned<int>::type int_type;
    typedef std::make_unsigned<volatile long>::type long_type;

    bool ok1 = std::is_same<char_type, unsigned char>::value;
    bool ok2 = std::is_same<int_type, unsigned int>::value;
    bool ok3 = std::is_same<long_type, volatile unsigned long>::value;

    std::cout << std::boolalpha
    << "char_type is 'unsigned char'?          : " << ok1 << '\n'
    << "int_type  is 'unsigned int'?           : " << ok2 << '\n'
    << "long_type is 'volatile unsigned long'? : " << ok3 << '\n';
}

输出：

char_type is 'unsigned char'?          : true
int_type  is 'unsigned int'?           : true
long_type is 'volatile unsigned long'? : true

参阅

is_signed (C++11) | 检查类型是否为有符号算术类型 (类模板)
is_unsigned (C++11) | 检查类型是否为无符号算术类型 (类模板)
make_signed (C++11) | 使给定的整型类型有符号 (类模板)


std::max_align_t

< cpp‎ | types
定义于头文件 <cstddef> |
typedef /*implementation-defined*/ max_align_t; | (C++11 起)

std::max_align_t 是一个平凡的 标准布局类型，其对齐要求至少与每个标量类型一样严格（一样大）。

注意

分配函数，如 std::malloc 所返回的指针，适于为任何对象对齐，这表示其对齐至少与 std::max_align_t 一样严格。

std::max_align_t 通常是最大标量类型的同义词，在大多数平台上是 long double ，而其对齐要求是 8 或 16 。

示例

#include <iostream>
#include <cstddef>
int main()
{
    std::cout << alignof(std::max_align_t) << '\n';
}

可能的输出：

16

参阅

alignof 运算符 (C++11) | 查询类型的对齐要求
alignment_of (C++11) | 获取类型的对齐要求 (类模板)
is_scalar (C++11) | 检查类型是否为标量类型 (类模板)


std::negation

< cpp‎ | types
定义于头文件 <type_traits> |
template<class B> struct negation; | (C++17 起)

构建类型特性 B 的逻辑否定。

类型 std::negation<B> 是基特征为 std::bool_constant <!bool(B::value)> 的一元类型特征 (UnaryTypeTrait) 。

添加 negation 或 negation_v 的特化的程序行为未定义。

模板形参

B - 使得表达式 bool(B::value) 为合法常量表达式的任何类型

辅助变量模板

template<class B> inline constexpr bool negation_v = negation<B>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 B 拥有在隐式转换为 bool 时等于 false 的 ::value 则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

可能的实现

template<class B>
struct negation : std::bool_constant<!bool(B::value)> { };

示例

#include <iostream>
#include <type_traits>

static_assert(
    std::is_same<
        std::bool_constant<false>,
        typename std::negation<std::bool_constant<true>>::type>::value,
    "");
static_assert(
    std::is_same<
        std::bool_constant<true>,
        typename std::negation<std::bool_constant<false>>::type>::value,
    "");

int main()
{
    std::cout << std::boolalpha;
    std::cout << std::negation<std::bool_constant<true>>::value << '\n';
    std::cout << std::negation<std::bool_constant<false>>::value << '\n';
}

输出：

false
true

参阅

conjunction (C++17) | 变参的逻辑与元函数 (类模板)
disjunction (C++17) | 变参的逻辑或元函数 (类模板)
integral_constantbool_constant (C++11)(C++17) | 具有指定值的指定类型的编译期常量 (类模板)


std::nullptr_t

< cpp‎ | types
定义于头文件 <cstddef> |
typedef decltype(nullptr) nullptr_t; | (C++11 起)

std::nullptr_t 是空指针字面量 nullptr 的类型。它是既非指针类型亦非指向成员指针类型的独立类型。

注解

包含 <stddef.h> 时 nullptr_t 在全局命名空间可用，即使它不是 C 的一部分。

示例

若二个重载接受不同指针类型，则需要 std::nullptr_t 的重载以接受空指针常量。

#include <cstddef>
#include <iostream>

void f(int*)
{
   std::cout << "Pointer to integer overload\n";
}

void f(double*)
{
   std::cout << "Pointer to double overload\n";
}

void f(std::nullptr_t)
{
   std::cout << "null pointer overload\n";
}

int main()
{
    int* pi {}; double* pd {};

    f(pi);
    f(pd);
    f(nullptr); // 无 void f(nullptr_t) 可能有歧义
    // f(0);    // 歧义调用：三个函数全部为候选
    // f(NULL); // 若 NULL 是整数空指针常量则为歧义
                // （如在大部分实现中的情况）
}

输出：

Pointer to integer overload
Pointer to double overload
null pointer overload

参阅

nullptr (C++11) | 指定空指针值的指针字面量
NULL | 实现定义的空指针常量 (宏常量)
is_null_pointer (C++14) | 检查类型是否为 std::nullptr_t (类模板)


std::numeric_limits

< cpp‎ | types
定义于头文件 <limits>
template< class T > class numeric_limits;

numeric_limits 类模板提供查询各种算术类型属性的标准化方式（例如 int 类型的最大可能值是 std::numeric_limits<int>::max() ）。

通过 numeric_limits 模板的特化提供此信息。标准库为所有算术类型制定可用的特化：

定义于头文件 <limits> |
template<> class numeric_limits<bool>; |
template<> class numeric_limits<char>; |
template<> class numeric_limits<signed char>; |
template<> class numeric_limits<unsigned char>; |
template<> class numeric_limits<wchar_t>; |
template<> class numeric_limits<char8_t>; | (C++20 起)
template<> class numeric_limits<char16_t>; | (C++11 起)
template<> class numeric_limits<char32_t>; | (C++11 起)
template<> class numeric_limits<short>; |
template<> class numeric_limits<unsigned short>; |
template<> class numeric_limits<int>; |
template<> class numeric_limits<unsigned int>; |
template<> class numeric_limits<long>; |
template<> class numeric_limits<unsigned long>; |
template<> class numeric_limits<long long>; | (C++11 起)
template<> class numeric_limits<unsigned long long>; | (C++11 起)
template<> class numeric_limits<float>; |
template<> class numeric_limits<double>; |
template<> class numeric_limits<long double>; |

亦对所有整数类类型提供特化。

 (C++20 起)

另外，对于每个存在特化的 cv 无限定类型的每个 cv 限定版本存在特化，等同于非限定的特化，例如提供 std::numeric_limits<const int> 、 std::numeric_limits<volatile int> 和 std::numeric_limits<const volatile int> ，且它们等价于 std::numeric_limits<int> 。

作为算术类型别名的标准库类型（例如 std::size_t 或 std::streamsize ）也可以用 std::numeric_limits 类型特性检测。

非算术标准类型，例如 std::complex <T> 或 std::nullptr_t ，无特化。

实现可以对实现指定的类型提供 std::numeric_limits 的特化：例如 GCC 提供 std::numeric_limits<__int128> 。非标准库可以为库所提供的类型添加特化，例如 OpenEXR 为 16 位浮点类型提供 std::numeric_limits<half> 。

模板参数

T - 要获取数值属性的类型

成员常量

is_specialized [静态] | 鉴别 std::numeric_limits 是否为该类型特化 (公开静态成员常量)
is_signed [静态] | 鉴别有符号类型 (公开静态成员常量)
is_integer [静态] | 鉴别整数类型 (公开静态成员常量)
is_exact [静态] | 鉴别准确表示的类型 (公开静态成员常量)
has_infinity [静态] | 鉴别能表示特殊值“正无穷大”的浮点类型 (公开静态成员常量)
has_quiet_NaN [静态] | 鉴别能表示特殊值“安静的非数”（ NaN ）的浮点类型 (公开静态成员常量)
has_signaling_NaN [静态] | 鉴别能表示特殊值“发信的非数”（ NaN ）的浮点类型 (公开静态成员常量)
has_denorm [静态] | 鉴别浮点类型所用的非正规风格 (公开静态成员常量)
has_denorm_loss [静态] | 鉴别浮点类型是否检测精度损失为非正规损失，而非不准确结果 (公开静态成员常量)
round_style [静态] | 鉴别类型所用的舍入模式 (公开静态成员常量)
is_iec559 [静态] | 鉴别 IEC 559/IEEE 754 浮点类型 (公开静态成员常量)
is_bounded [静态] | 鉴别表示有限值集合的类型 (公开静态成员常量)
is_modulo [静态] | 鉴别以模算术处理溢出的类型 (公开静态成员常量)
digits [静态] | 能无更改地表示的 radix 位数 (公开静态成员常量)
digits10 [静态] | 能无更改地表示的十进制位数 (公开静态成员常量)
max_digits10 [静态] (C++11) | 区别所有此类型值所需的十进制位数 (公开静态成员常量)
radix [静态] | 给定类型的表示所用的基或整数底 (公开静态成员常量)
min_exponent [静态] | 底的该数次幂是合法正规浮点值的最小负数加一 (公开静态成员常量)
min_exponent10 [静态] | 10 的该数次幂是合法正规浮点值的最小负数 (公开静态成员常量)
max_exponent [静态] | 底的该数次幂是合法有限浮点值的最大整数加一 (公开静态成员常量)
max_exponent10 [静态] | 10 的该数次幂是合法有限浮点值的最大整数 (公开静态成员常量)
traps [静态] | 鉴别可能导致算术运算出现陷阱的类型 (公开静态成员常量)
tinyness_before [静态] | 鉴别检测舍入前是否非正规的浮点类型 (公开静态成员常量)

成员函数

min [静态] | 返回给定类型的最小有限值 (公开静态成员函数)
lowest [静态] (C++11) | 返回给定类型的最低有限值 (公开静态成员函数)
max [静态] | 返回给定类型的最大有限值 (公开静态成员函数)
epsilon [静态] | 返回 1.0 与给定类型的下个可表示值的差 (公开静态成员函数)
round_error [静态] | 返回给定浮点类型的最大舍入误差 (公开静态成员函数)
infinity [静态] | 返回给定类型的正无穷大值 (公开静态成员函数)
quiet_NaN [静态] | 返回给定浮点类型的安静 NaN 值 (公开静态成员函数)
signaling_NaN [静态] | 返回给定浮点类型的发信的 NaN (公开静态成员函数)
denorm_min [静态] | 返回给定浮点类型的最小正非正规值 (公开静态成员函数)

辅助类

float_round_style | 指示浮点舍入模式 (枚举)
float_denorm_style | 指示浮点非规格化模式 (枚举)

与 C 库宏常量的关系

特化 std::numeric_limits<T> 其中 T 为 | 成员
 | min() | lowest() (C++11) | max() | radix
bool | false | false | true | 2
char | CHAR_MIN | CHAR_MIN | CHAR_MAX | 2
signed char | SCHAR_MIN | SCHAR_MIN | SCHAR_MAX | 2
unsigned char | ​0​ | ​0​ | UCHAR_MAX | 2
wchar_t | WCHAR_MIN | WCHAR_MIN | WCHAR_MAX | 2
char8_t | ​0​ | ​0​ | UCHAR_MAX | 2
char16_t | ​0​ | ​0​ | UINT_LEAST16_MAX | 2
char32_t | ​0​ | ​0​ | UINT_LEAST32_MAX | 2
short | SHRT_MIN | SHRT_MIN | SHRT_MAX | 2
signed short
unsigned short | ​0​ | ​0​ | USHRT_MAX | 2
int | INT_MIN | INT_MIN | INT_MAX | 2
signed int
unsigned int | ​0​ | ​0​ | UINT_MAX | 2
long | LONG_MIN | LONG_MIN | LONG_MAX | 2
signed long
unsigned long | ​0​ | ​0​ | ULONG_MAX | 2
long long | LLONG_MIN | LLONG_MIN | LLONG_MAX | 2
signed long long
unsigned long long | ​0​ | ​0​ | ULLONG_MAX | 2

特化 std::numeric_limits<T> 其中 T 为 | 成员
 | min() | lowest() (C++11) | max() | epsilon() | digits | digits10
float | FLT_MIN | - FLT_MAX | FLT_MAX | FLT_EPSILON | FLT_MANT_DIG | FLT_DIG
double | DBL_MIN | - DBL_MAX | DBL_MAX | DBL_EPSILON | DBL_MANT_DIG | DBL_DIG
long double | LDBL_MIN | - LDBL_MAX | LDBL_MAX | LDBL_EPSILON | LDBL_MANT_DIG | LDBL_DIG
特化 std::numeric_limits<T> 其中 T 为 | 成员（续）
 | min_exponent | min_exponent10 | max_exponent | max_exponent10 | radix
float | FLT_MIN_EXP | FLT_MIN_10_EXP | FLT_MAX_EXP | FLT_MAX_10_EXP | FLT_RADIX
double | DBL_MIN_EXP | DBL_MIN_10_EXP | DBL_MAX_EXP | DBL_MAX_10_EXP | FLT_RADIX
long double | LDBL_MIN_EXP | LDBL_MIN_10_EXP | LDBL_MAX_EXP | LDBL_MAX_10_EXP | FLT_RADIX

示例

#include <limits>
#include <iostream>

int main()
{
    std::cout
        << "type\t│ lowest()\t│ min()\t\t│ max()\n"
        << "bool\t│ "
        << std::numeric_limits<bool>::lowest() << "\t\t│ "
        << std::numeric_limits<bool>::min() << "\t\t│ "
        << std::numeric_limits<bool>::max() << '\n'
        << "uchar\t│ "
        << +std::numeric_limits<unsigned char>::lowest() << "\t\t│ "
        << +std::numeric_limits<unsigned char>::min() << "\t\t│ "
        << +std::numeric_limits<unsigned char>::max() << '\n'
        << "int\t│ "
        << std::numeric_limits<int>::lowest() << "\t│ "
        << std::numeric_limits<int>::min() << "\t│ "
        << std::numeric_limits<int>::max() << '\n'
        << "float\t│ "
        << std::numeric_limits<float>::lowest() << "\t│ "
        << std::numeric_limits<float>::min() << "\t│ "
        << std::numeric_limits<float>::max() << '\n'
        << "double\t│ "
        << std::numeric_limits<double>::lowest() << "\t│ "
        << std::numeric_limits<double>::min() << "\t│ "
        << std::numeric_limits<double>::max() << '\n';
}

可能的输出：

type   │ lowest()      │ min()         │ max()
bool    │ 0             │ 0             │ 1
uchar   │ 0             │ 0             │ 255
int     │ -2147483648   │ -2147483648   │ 2147483647
float   │ -3.40282e+38  │ 1.17549e-38   │ 3.40282e+38
double  │ -1.79769e+308 │ 2.22507e-308  │ 1.79769e+308

参阅

  • 定宽整数类型
  • 算术类型
  • C++ 类型系统概览
  • 类型支持（基础类型、 RTTI 、类型特性）


std::numeric_limits<T>::denorm_min

< cpp‎ | types‎ | numeric limits
static T denorm_min() throw(); | (C++11 前)
static constexpr T denorm_min() noexcept; | (C++11 起)

若 std::numeric_limits <T>::has_denorm != std::denorm_absent 则返回 T 类型的最小正非正规值，否则返回 std::numeric_limits <T>::min() 。仅对浮点类型有意义。

返回值

T | std::numeric_limits <T>::denorm_min()
/* non-specialized */ | T()
bool | false
char | ​0​
signed char | ​0​
unsigned char | ​0​
wchar_t | ​0​
char8_t (C++20) | ​0​
char16_t (C++11) | ​0​
char32_t (C++11) | ​0​
short | ​0​
unsigned short | ​0​
int | ​0​
unsigned int | ​0​
long | ​0​
unsigned long | ​0​
long long (C++11) | ​0​
unsigned long long (C++11) | ​0​
float | FLT_TRUE_MIN （若 std::numeric_limits <float>::is_iec559 为 true 则为 \(\scriptsize 2^{-149}\)2-149 ）
double | DBL_TRUE_MIN （若 std::numeric_limits <double>::is_iec559 为 true 则为 \(\scriptsize 2^{-1074}\)2-1074 ）
long double | LDBL_TRUE_MIN

示例

演示 denorm_min() 的底层位结构

#include <cstdint>
#include <cstring>
#include <limits>
#include <cassert>
int main()
{
    // 最小非正规值拥有符号位 = 0 ，指数 = 0
    // 且仅有尾数的最小有效数字位为 1
    std::uint32_t denorm_bits = 0x0001;
    float denorm_float;
    std::memcpy(&denorm_float, &denorm_bits, sizeof(float));

    assert(denorm_float == std::numeric_limits<float>::denorm_min());

    std::cout << "float\tmin()\t\tdenorm_min()\n";
    std::cout << "\t" << std::numeric_limits<float>::min() << '\t';
    std::cout <<         std::numeric_limits<float>::denorm_min() << '\n';

    std::cout << "double\tmin()\t\tdenorm_min()\n";
    std::cout << "\t" << std::numeric_limits<double>::min() << '\t';
    std::cout <<         std::numeric_limits<double>::denorm_min() << '\n';
}

输出：

float  min()           denorm_min()
        1.17549e-38     1.4013e-45
double  min()           denorm_min()
        2.22507e-308    4.94066e-324

参阅

min [静态] | 返回给定类型的最小有限值 (公开静态成员函数)
has_denorm [静态] | 鉴别浮点类型所用的非正规风格 (公开静态成员常量)
lowest [静态] (C++11) | 返回给定类型的最低有限值 (公开静态成员函数)


std::numeric_limits<T>::digits

< cpp‎ | types‎ | numeric limits
static const int digits; | (C++11 前)
static constexpr int digits; | (C++11 起)

std::numeric_limits <T>::digits 的值是能无更改地表示类型 T 的 radix 底位数。对于整数类型，这是不含符号位和填充位（若存在）的位数。对于浮点类型，这是尾数的位数（对于 IEC 559/IEEE 754 实现，这是存储尾数的位数加一，因为尾数有隐藏的前导 1 和二进制小数点）。

标准特化

T | std::numeric_limits <T>::digits 的值（假设无填充位）
/* non-specialized */ | ​0​
bool | 1
char | CHAR_BIT - std::numeric_limits <char>::is_signed
signed char | CHAR_BIT - 1
unsigned char | CHAR_BIT
wchar_t | CHAR_BIT *sizeof(wchar_t) - std::numeric_limits <wchar_t>::is_signed
char8_t (C++20) | CHAR_BIT
char16_t (C++11) | CHAR_BIT *sizeof(char16_t)
char32_t (C++11) | CHAR_BIT *sizeof(char32_t)
short | CHAR_BIT *sizeof(short)-1
unsigned short | CHAR_BIT *sizeof(short)
int | CHAR_BIT *sizeof(int)-1
unsigned int | CHAR_BIT *sizeof(int)
long | CHAR_BIT *sizeof(long)-1
unsigned long | CHAR_BIT *sizeof(long)
long long (C++11) | CHAR_BIT *sizeof(long long)-1
unsigned long long (C++11) | CHAR_BIT *sizeof(long long)
float | FLT_MANT_DIG
double | DBL_MANT_DIG
long double | LDBL_MANT_DIG

参阅

radix [静态] | 给定类型的表示所用的基或整数底 (公开静态成员常量)
min_exponent [静态] | 底的该数次幂是合法正规浮点值的最小负数加一 (公开静态成员常量)
max_exponent [静态] | 底的该数次幂是合法有限浮点值的最大整数加一 (公开静态成员常量)


std::numeric_limits<T>::digits10

< cpp‎ | types‎ | numeric limits
static const int digits10; | (C++11 前)
static constexpr int digits10 | (C++11 起)

std::numeric_limits <T>::digits10 的值是类型 T 能无更改地表示的底 10 位数，即任何拥有这么多十进制有效数字的数能转换成 T 的值并转换回十进制形式，而不因舍入或上溢而更改。对于底 radix 类型，它是 digits （对于浮点类型是 digits-1 ）的值乘 \(\small \log_{10}{radix}\)log
10(radix) 并向下取整。

标准特化

T | std::numeric_limits <T>::digits10 的值
/* non-specialized */ | ​0​
bool | ​0​
char | std::numeric_limits <char>::digits * std::log10 (2)
signed char | std::numeric_limits <signed char>::digits * std::log10 (2)
unsigned char | std::numeric_limits <unsigned char>::digits * std::log10 (2)
wchar_t | std::numeric_limits <wchar_t>::digits * std::log10 (2)
char8_t (C++20) | std::numeric_limits <char8_t>::digits * std::log10 (2)
char16_t (C++11) | std::numeric_limits <char16_t>::digits * std::log10 (2)
char32_t (C++11) | std::numeric_limits <char32_t>::digits * std::log10 (2)
short | std::numeric_limits <short>::digits * std::log10 (2)
unsigned short | std::numeric_limits <unsigned short>::digits * std::log10 (2)
int | std::numeric_limits <int>::digits * std::log10 (2)
unsigned int | std::numeric_limits <unsigned int>::digits * std::log10 (2)
long | std::numeric_limits <long>::digits * std::log10 (2)
unsigned long | std::numeric_limits <unsigned long>::digits * std::log10 (2)
long long (C++11) | std::numeric_limits <long long>::digits * std::log10 (2)
unsigned long long (C++11) | std::numeric_limits <unsigned long long>::digits * std::log10 (2)
float | FLT_DIG /* IEEE float 为 6 */
double | DBL_DIG /* IEEE double 为 15 */
long double | LDBL_DIG /* 80 位 Intel long double 为 18； IEEE 四倍精度为 33 */

示例

8 位二进制类型能准确表示任何二位十进制数，但不能表示 3 位十进制数 256..999 。 digits10 对 8 位类型的值是 2 （ 8 * std::log10 (2) 为 2.41 ）

标准 32 位 IEEE 754 浮点类型拥有 24 位小数部分（写出 23 位，隐含一位），这可以建议它能表示 7 位十进制数字（ 24 * std::log10 (2) 为 7.22 ），但相对误差不统一，且一些有 7 位十进制数的浮点值不能在转换到 32 位浮点再转换回来后生存：最小的正数例子是 8.589973e9 ，它在来回舍入后变成 8.589974e9 。这些误差在表示中不能超过一位，而 digits10 按 (24-1)* std::log10 (2) 计算，即 6.92 。向下取整结果导致值 6 。

类似地，16 字符串 9007199254740993 在文本->double->文本回环中不保持，它变为 9007199254740992 ： 64 位 IEEE 754 double 类型仅保证 15 位的舍入回环。

参阅

radix [静态] | 给定类型的表示所用的基或整数底 (公开静态成员常量)
digits [静态] | 能无更改地表示的 radix 位数 (公开静态成员常量)
min_exponent [静态] | 底的该数次幂是合法正规浮点值的最小负数加一 (公开静态成员常量)
max_exponent [静态] | 底的该数次幂是合法有限浮点值的最大整数加一 (公开静态成员常量)


std::numeric_limits<T>::epsilon

< cpp‎ | types‎ | numeric limits
static T epsilon() throw(); | (C++11 前)
static constexpr T epsilon() noexcept; | (C++11 起)

返回机器 epsilon ，即 1.0 与浮点类型 T 的下个可表示值的差。它仅若 std::numeric_limits <T>::is_integer == false 才有意义。

返回值

T | std::numeric_limits <T>::epsilon()
/* non-specialized */ | T()
bool | false
char | ​0​
signed char | ​0​
unsigned char | ​0​
wchar_t | ​0​
char8_t (C++20) | ​0​
char16_t (C++11) | ​0​
char32_t (C++11) | ​0​
short | ​0​
unsigned short | ​0​
int | ​0​
unsigned int | ​0​
long | ​0​
unsigned long | ​0​
long long (C++11) | ​0​
unsigned long long(C++11) | ​0​
float | FLT_EPSILON
double | DBL_EPSILON
long double | LDBL_EPSILON

示例

演示用机器 epsilon 比较浮点值是否相等

#include <cmath>
#include <limits>
#include <iomanip>
#include <iostream>
#include <type_traits>
#include <algorithm>

template<class T>
typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type
    almost_equal(T x, T y, int ulp)
{
    // the machine epsilon has to be scaled to the magnitude of the values used
    // and multiplied by the desired precision in ULPs (units in the last place)
    return std::abs(x-y) <= std::numeric_limits<T>::epsilon() * std::abs(x+y) * ulp
        // unless the result is subnormal
        || std::abs(x-y) < std::numeric_limits<T>::min();
}

int main()
{
    double d1 = 0.2;
    double d2 = 1 / std::sqrt(5) / std::sqrt(5);
    std::cout << std::fixed << std::setprecision(20)
        << "d1=" << d1 << "\nd2=" << d2 << '\n';

    if(d1 == d2)
        std::cout << "d1 == d2\n";
    else
        std::cout << "d1 != d2\n";

    if(almost_equal(d1, d2, 2))
        std::cout << "d1 almost equals d2\n";
    else
        std::cout << "d1 does not almost equal d2\n";
}

输出：

d1=0.20000000000000001110
d2=0.19999999999999998335
d1 != d2
d1 almost equals d2

参阅

nextafternextafterfnextafterlnexttowardnexttowardfnexttowardl
(C++11)(C++11) (C++11)(C++11)(C++11)(C++11)
 趋向给定值的下个可表示浮点值
(函数)


std::float_denorm_style

< cpp‎ | types‎ | numeric limits
定义于头文件 <limits>
enum float_denorm_style {

denorm_indeterminate = -1,
denorm_absent = 0,
denorm_present = 1

};

std::float_denorm_style 类型的枚举常量指示浮点类型对非正规值的支持。

枚举常量

名称 | 定义
std::denorm_indeterminate | 无法确定是否支持非正规值
std::denorm_absent | 类型不支持非正规值
std::denorm_present | 类型允许非正规值

参阅

has_denorm
[静态]
 鉴别浮点类型所用的非正规风格
(公开静态成员常量)


std::float_round_style

< cpp‎ | types‎ | numeric limits
定义于头文件 <limits>
enum float_round_style {

round_indeterminate = -1,
round_toward_zero = 0,
round_to_nearest = 1,
round_toward_infinity = 2,
round_toward_neg_infinity = 3

};

std::float_round_style 类型的枚举常量指示浮点算术在凡将表达式结果存储于浮点类型对象时所用的舍入模式。值为：

枚举常量

名称 | 定义
std::round_indeterminate | 无法确定舍入风格
std::round_toward_zero | 向零舍入
std::round_to_nearest | 向最近可表示值舍入
std::round_toward_infinity | 向正无穷大舍入
std::round_toward_neg_infinity | 向负无穷大舍入

参阅

round_style [静态] | 鉴别类型所用的舍入模式 (公开静态成员常量)
FE_DOWNWARDFE_TONEARESTFE_TOWARDZEROFE_UPWARD (C++11) | 浮点舍入方向 (宏常量)


std::numeric_limits<T>::has_denorm

< cpp‎ | types‎ | numeric limits
static const std::float_denorm_style has_denorm; | (C++11 前)
static constexpr std::float_denorm_style has_denorm; | (C++11 起)

std::numeric_limits <T>::has_denorm 的值鉴别浮点类型如何支持非正规值。

标准特化

T | std::numeric_limits <T>::has_denorm 的值
/* non-specialized */ | std::denorm_absent
bool | std::denorm_absent
char | std::denorm_absent
signed char | std::denorm_absent
unsigned char | std::denorm_absent
wchar_t | std::denorm_absent
char8_t (C++20) | std::denorm_absent
char16_t (C++11) | std::denorm_absent
char32_t (C++11) | std::denorm_absent
short | std::denorm_absent
unsigned short | std::denorm_absent
int | std::denorm_absent
unsigned int | std::denorm_absent
long | std::denorm_absent
unsigned long | std::denorm_absent
long long (C++11) | std::denorm_absent
unsigned long long (C++11) | std::denorm_absent
float | 通常为 std::denorm_present
double | 通常为 std::denorm_present
long double | 通常为 std::denorm_present

参阅

denorm_min [静态] | 返回给定浮点类型的最小正非正规值 (公开静态成员函数)
float_denorm_style | 指示浮点非规格化模式 (枚举)


std::numeric_limits<T>::has_denorm_loss

< cpp‎ | types‎ | numeric limits
static const bool has_denorm_loss; | (C++11 前)
static constexpr bool has_denorm_loss; | (C++11 起)

std::numeric_limits <T>::has_denorm_loss 的值对于所有检测在创建非正规数时的精度损失为非正规化损失，而非不准确结果（见后述）的浮点类型 T 为 true 。

标准特化

T | std::numeric_limits <T>::has_denorm_loss 的值
/* non-specialized */ | false
bool | false
char | false
signed char | false
unsigned char | false
wchar_t | false
char8_t (C++20) | false
char16_t (C++11) | false
char32_t (C++11) | false
short | false
unsigned short | false
int | false
unsigned int | false
long | false
unsigned long | false
long long (C++11) | false
unsigned long long (C++11) | false
float | 实现定义
double | 实现定义
long double | 实现定义

注解

遵从标准的非正规数的 IEEE 754 浮点实现要求若出现关联到创建这种数的精度损失，则检测它，而且可以以二种有别的方式进行：

  1. 非正规化损失：产生的结果异于假如指数范围无界的情况下计算出的结果。
  2. 不准确结果：产生的结果异于假如指数范围和精度均无界的情况下计算出的结果。

不存在非正规化损失机制的实现（精度损失在舍入后检测为不准确结果），而此选项在 IEEE 标准 754 的 2008 修订版被移除。

libstdc++、 libc++、 libCstd 及 stlport4 为所有浮点类型定义此常量为 false 。 Microsoft Visual Studio 为所有浮点类型定义它为 true 。

同任何浮点计算，精度损失可能引发 FE_INEXACT

示例

本节未完成
原因：暂无示例

参阅

tinyness_before [静态] | 鉴别检测舍入前是否非正规的浮点类型 (公开静态成员常量)
has_denorm [静态] | 鉴别浮点类型所用的非正规风格 (公开静态成员常量)


std::numeric_limits<T>::has_infinity

< cpp‎ | types‎ | numeric limits
static const bool has_infinity; | (C++11 前)
static constexpr bool has_infinity; | (C++11 起)

std::numeric_limits <T>::has_infinity 的值对所有能够表示正无穷大为独立特殊值的类型 T 为 true 。此常量对所有浮点类型有意义，且保证若 std::numeric_limits <T>::is_iec559 == true 则为 true 。

标准特化

T | std::numeric_limits <T>::has_infinity 的值
/* non-specialized */ | false
bool | false
char | false
signed char | false
unsigned char | false
wchar_t | false
char8_t (C++20) | false
char16_t (C++11) | false
char32_t (C++11) | false
short | false
unsigned short | false
int | false
unsigned int | false
long | false
unsigned long | false
long long (C++11) | false
unsigned long long (C++11) | false
float | 通常为 true
double | 通常为 true
long double | 通常为 true

参阅

infinity [静态] | 返回给定类型的正无穷大值 (公开静态成员函数)
has_quiet_NaN [静态] | 鉴别能表示特殊值“安静的非数”（ NaN ）的浮点类型 (公开静态成员常量)
has_signaling_NaN [静态] | 鉴别能表示特殊值“发信的非数”（ NaN ）的浮点类型 (公开静态成员常量)


std::numeric_limits<T>::has_quiet_NaN

< cpp‎ | types‎ | numeric limits
static const bool has_quiet_NaN;
static constexpr bool has_quiet_NaN;

std::numeric_limits <T>::has_quiet_NaN 的值对所有能够表示特殊值“安静的非数”的类型 T 为 true 。此常量对所有浮点类型有意义，并保证若 std::numeric_limits <T>::is_iec559 == true 则为 true 。

标准特化

T | std::numeric_limits <T>::has_quiet_NaN 的值
/* non-specialized */ | false
bool | false
char | false
signed char | false
unsigned char | false
wchar_t | false
char8_t (C++20) | false
char16_t (C++11) | false
char32_t (C++11) | false
short | false
unsigned short | false
int | false
unsigned int | false
long | false
unsigned long | false
long long (C++11) | false
unsigned long long (C++11) | false
float | 通常为 true
double | 通常为 true
long double | 通常为 true

参阅

quiet_NaN [静态] | 返回给定浮点类型的安静 NaN 值 (公开静态成员函数)
has_infinity [静态] | 鉴别能表示特殊值“正无穷大”的浮点类型 (公开静态成员常量)
has_signaling_NaN [静态] | 鉴别能表示特殊值“发信的非数”（ NaN ）的浮点类型 (公开静态成员常量)


std::numeric_limits<T>::has_signaling_NaN

< cpp‎ | types‎ | numeric limits
static const bool has_signaling_NaN;
static constexpr bool has_signaling_NaN;

std::numeric_limits <T>::has_signaling_NaN 的值对所有能够表示特殊值“发信的非数”的类型 T 为 true 。此常量对所有浮点类型有意义，并保证若 std::numeric_limits <T>::is_iec559 == true 则为 true 。

标准特化

T | std::numeric_limits <T>::has_signaling_NaN 的值
/* non-specialized */ | false
bool | false
char | false
signed char | false
unsigned char | false
wchar_t | false
char8_t (C++20) | false
char16_t (C++11) | false
char32_t (C++11) | false
short | false
unsigned short | false
int | false
unsigned int | false
long | false
unsigned long | false
long long (C++11) | false
unsigned long long (C++11) | false
float | 通常为 true
double | 通常为 true
long double | 通常为 true

参阅

quiet_NaN [静态] | 返回给定浮点类型的安静 NaN 值 (公开静态成员函数)
has_infinity [静态] | 鉴别能表示特殊值“正无穷大”的浮点类型 (公开静态成员常量)
has_quiet_NaN [静态] | 鉴别能表示特殊值“安静的非数”（ NaN ）的浮点类型 (公开静态成员常量)


std::numeric_limits<T>::infinity

< cpp‎ | types‎ | numeric limits
static T infinity() throw(); | (C++11 前)
static constexpr T infinity() noexcept; | (C++11 起)

返回浮点类型 T 所表示的特殊值“正无穷大”。仅若 std::numeric_limits <T>::has_infinity == true 才有意义。在最常见的浮点数二进制表示 IEEE 754 中，正无穷大是所有指数位为 1 而所有尾数位为 0 的值。

返回值

T | std::numeric_limits <T>::infinity()
/* non-specialized */ | T()
bool | false
char | ​0​
signed char | ​0​
unsigned char | ​0​
wchar_t | ​0​
char8_t (C++20) | ​0​
char16_t (C++11) | ​0​
char32_t (C++11) | ​0​
short | ​0​
unsigned short | ​0​
int | ​0​
unsigned int | ​0​
long | ​0​
unsigned long | ​0​
long long (C++11) | ​0​
unsigned long long (C++11) | ​0​
float | HUGE_VALF
double | HUGE_VAL
long double | HUGE_VALL

示例

#include <iostream>
#include <limits>
int main()
{
    double max = std::numeric_limits<double>::max();
    double inf = std::numeric_limits<double>::infinity();

    if(inf > max)
        std::cout << inf << " is greater than " << max << '\n';
}

输出：

inf is greater than 1.79769e+308

参阅

has_infinity
[静态]
 鉴别能表示特殊值“正无穷大”的浮点类型
(公开静态成员常量)


std::numeric_limits<T>::is_bounded

< cpp‎ | types‎ | numeric limits
static const bool is_bounded; | (C++11 前)
static constexpr bool is_bounded; | (C++11 起)

std::numeric_limits <T>::is_bounded 对所有表示有限的值集合的算术类型 T 为 true 。所有基础类型均有界，不过此常量会在 std::numeric_limits 对库提供的任意精度算术类型的特化中为 false 。

标准特化

T | std::numeric_limits <T>::is_bounded 的值
/* non-specialized */ | false
bool | true
char | true
signed char | true
unsigned char | true
wchar_t | true
char8_t (C++20) | true
char16_t (C++11) | true
char32_t (C++11) | true
short | true
unsigned short | true
int | true
unsigned int | true
long | true
unsigned long | true
long long (C++11) | true
unsigned long long (C++11) | true
float | true
double | true
long double | true

参阅

is_integer [静态] | 鉴别整数类型 (公开静态成员常量)
is_signed [静态] | 鉴别有符号类型 (公开静态成员常量)
is_exact [静态] | 鉴别准确表示的类型 (公开静态成员常量)


std::numeric_limits<T>::is_exact

< cpp‎ | types‎ | numeric limits
static const bool is_exact; | (C++11 前)
static constexpr bool is_exact; | (C++11 起)

std::numeric_limits <T>::is_exact 的值对所有使用准确表示的算术类型 T 为 true 。

标准特化

T | std::numeric_limits <T>::is_exact 的值
/* non-specialized */ | false
bool | true
char | true
signed char | true
unsigned char | true
wchar_t | true
char8_t (C++20) | true
char16_t (C++11) | true
char32_t (C++11) | true
short | true
unsigned short | true
int | true
unsigned int | true
long | true
unsigned long | true
long long (C++11) | true
unsigned long long (C++11) | true
float | false
double | false
long double | false

注解

尽管对于所有 std::numeric_limits <T>::is_exact==true 的基础类型 T 都是整数类型，库可以定义非整数的准确类型，例如表示分数的有理数算术类型。

参阅

is_integer [静态] | 鉴别整数类型 (公开静态成员常量)
is_signed [静态] | 鉴别有符号类型 (公开静态成员常量)
is_bounded [静态] | 鉴别表示有限值集合的类型 (公开静态成员常量)


std::numeric_limits<T>::is_iec559

< cpp‎ | types‎ | numeric limits
static const bool is_iec559; | (C++11 前)
static constexpr bool is_iec559; | (C++11 起)

std::numeric_limits <T>::is_iec559 的值对于所有符合 IEC 559 （ IEEE 754 ）标准要求的浮点类型 T 为 true 。若 std::numeric_limits <T>::is_iec559 为 true ，则 std::numeric_limits <T>::has_infinity 、 std::numeric_limits <T>::has_quiet_NaN 与 std::numeric_limits <T>::has_signaling_NaN 亦为 true 。

标准特化

T | std::numeric_limits <T>::is_iec559 的值
/* non-specialized */ | false
bool | false
char | false
signed char | false
unsigned char | false
wchar_t | false
char8_t (C++20) | false
char16_t (C++11) | false
char32_t (C++11) | false
short | false
unsigned short | false
int | false
unsigned int | false
long | false
unsigned long | false
long long (C++11) | false
unsigned long long (C++11) | false
float | 通常为 true
double | 通常为 true
long double | 通常为 true

参阅

has_infinity [静态] | 鉴别能表示特殊值“正无穷大”的浮点类型 (公开静态成员常量)
has_quiet_NaN [静态] | 鉴别能表示特殊值“安静的非数”（ NaN ）的浮点类型 (公开静态成员常量)
has_signaling_NaN [静态] | 鉴别能表示特殊值“发信的非数”（ NaN ）的浮点类型 (公开静态成员常量)


std::numeric_limits<T>::is_integer

< cpp‎ | types‎ | numeric limits
static const bool is_integer; | (C++11 前)
static constexpr bool is_integer; | (C++11 起)

std::numeric_limits <T>::is_integer 的值对所有整数算术类型 T 为 true ，对其他为 false 。此常量对所有特化有意义。

标准特化

T | std::numeric_limits <T>::is_integer 的值
/* non-specialized */ | false
bool | true
char | true
signed char | true
unsigned char | true
wchar_t | true
char8_t (C++20) | true
char16_t (C++11) | true
char32_t (C++11) | true
short | true
unsigned short | true
int | true
unsigned int | true
long | true
unsigned long | true
long long (C++11) | true
unsigned long long (C++11) | true
float | false
double | false
long double | false

示例

#include <cstddef>
#include <cstdint>
#include <numeric>

int main()
{
    static_assert(
            std::numeric_limits<bool>::is_integer
        &&  std::numeric_limits<std::size_t>::is_integer
        &&  std::numeric_limits<std::int32_t>::is_integer
        &&  std::numeric_limits<std::int64_t>::is_integer
        &&  std::numeric_limits<decltype(42)>::is_integer
        && !std::numeric_limits<float>::is_integer
        && !std::numeric_limits<double>::is_integer
        && !std::numeric_limits<long double>::is_integer
        && !std::numeric_limits<decltype([](){})>::is_integer // P0315R4
    );
}

参阅

is_integral (C++11) | 检查类型是否为整型 (类模板)
is_signed [静态] | 鉴别有符号类型 (公开静态成员常量)
is_exact [静态] | 鉴别准确表示的类型 (公开静态成员常量)
is_bounded [静态] | 鉴别表示有限值集合的类型 (公开静态成员常量)


std::numeric_limits<T>::is_modulo

< cpp‎ | types‎ | numeric limits
static const bool is_modulo; | (C++11 前)
static constexpr bool is_modulo; | (C++11 起)

std::numeric_limits <T>::is_modulo 对所有可能 (C++11 前)以模算术处理溢出的算术类型 T 为 true 。模算术即若此类型的加法、减法、乘法或除法结果会落在范围 [min(), max()] 外，则这种运算返回的结果与期望值相差 max()-min()+1 的整数倍。

is_modulo 对有符号整数类型为 false ，除非实现定义有符号整数溢出为回绕。

 (C++11 起)

标准特化

T | std::numeric_limits <T>::is_modulo 的值
/* non-specialized */ | false
bool | false
char | 实现定义
signed char | 实现定义
unsigned char | true
wchar_t | 实现定义
char8_t (C++20) | true
char16_t (C++11) | true
char32_t (C++11) | true
short | 实现定义
unsigned short | true
int | 实现定义
unsigned int | true
long | 实现定义
unsigned long | true
long long (C++11) | 实现定义
unsigned long long (C++11) | true
float | false
double | false
long double | false

注解

尽管 C++11 标准仍然说“在大多数机器上，这对于有符号整数为 true ”，这是缺陷而且已被更正。准确措辞从 C++03 到 C++11 的更改使得 true 值不再与有符号整数溢出上的未定义行为兼容。因此，依赖于有符号溢出为未定义（为了优化机会）的实现现在对有符号整数设置 is_modulo 为 false 。见示例 GCC PR 22200 。

示例

演示模类型的行为

#include <iostream>
#include <type_traits>
#include <limits>

template<class T>
typename std::enable_if<std::numeric_limits<T>::is_modulo>::type
    check_overflow()
{
    std::cout << "\nmax value is " << std::numeric_limits<T>::max() << '\n'
              << "min value is " << std::numeric_limits<T>::min() << '\n'
              << "max value + 1 is " << std::numeric_limits<T>::max()+1 << '\n';
}

int main()
{
    check_overflow<int>();
    check_overflow<unsigned long>();
    // check_overflow<float>(); // 编译时错误，非模类型
}

可能的输出：

max value is 2147483647
min value is -2147483648
max value + 1 is -2147483648

max value is 18446744073709551615
min value is 0
max value + 1 is 0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2422 | C++11 | 曾在大多数机器上要求 is_modulo 对有符号整数类型为 true | 对有符号整数类型要求为 false ， 除非定义有符号整数溢出为回绕

参阅

is_integer [静态] | 鉴别整数类型 (公开静态成员常量)
is_iec559 [静态] | 鉴别 IEC 559/IEEE 754 浮点类型 (公开静态成员常量)
is_exact [静态] | 鉴别准确表示的类型 (公开静态成员常量)


std::numeric_limits<T>::is_signed

< cpp‎ | types‎ | numeric limits
static const bool is_signed; | (C++11 前)
static constexpr bool is_signed; | (C++11 起)

std::numeric_limits <T>::is_signed 的值对所有有符号算数类型 T 为 true ，而对无符号类型为 false 。此常量对所有特化有意义。

标准特化

T | std::numeric_limits <T>::is_signed 的值
/* non-specialized */ | false
bool | false
char | 实现定义
signed char | true
unsigned char | false
wchar_t | 实现定义
char8_t (C++20) | false
char16_t (C++11) | false
char32_t (C++11) | false
short | true
unsigned short | false
int | true
unsigned int | false
long | true
unsigned long | false
long long (C++11) | true
unsigned long long (C++11) | false
float | true
double | true
long double | true

参阅

is_signed (C++11) | 检查类型是否为有符号算术类型 (类模板)
is_integer [静态] | 鉴别整数类型 (公开静态成员常量)
is_exact [静态] | 鉴别准确表示的类型 (公开静态成员常量)
is_bounded [静态] | 鉴别表示有限值集合的类型 (公开静态成员常量)


std::numeric_limits<T>::is_specialized

< cpp‎ | types‎ | numeric limits
static const bool is_specialized; | (C++11 前)
static constexpr bool is_specialized; | (C++11 起)

std::numeric_limits <T>::is_specialized 的值对所有存在 std::numeric_limits 特化的 T 为 true 。

标准特化

T | std::numeric_limits <T>::is_specialized 的值
/* non-specialized */ | false
bool | true
char | true
signed char | true
unsigned char | true
wchar_t | true
char8_t (C++20) | true
char16_t (C++11) | true
char32_t (C++11) | true
short | true
unsigned short | true
int | true
unsigned int | true
long | true
unsigned long | true
long long (C++11) | true
unsigned long long (C++11) | true
float | true
double | true
long double | true

参阅

is_integer [静态] | 鉴别整数类型 (公开静态成员常量)
is_iec559 [静态] | 鉴别 IEC 559/IEEE 754 浮点类型 (公开静态成员常量)
is_exact [静态] | 鉴别准确表示的类型 (公开静态成员常量)
is_bounded [静态] | 鉴别表示有限值集合的类型 (公开静态成员常量)


std::numeric_limits<T>::lowest

< cpp‎ | types‎ | numeric limits
static constexpr T lowest() noexcept; | (C++11 起)

返回数值类型 T 可表示的最低有限值，即满足无其他有限值 y 符合 y < x 的有限值 x 。这对于浮点类型不同于 std::numeric_limits <T>::min() 。仅对有界类型有意义。

返回值

T | std::numeric_limits <T>::lowest()
/* non-specialized */ (C++11) | T()
bool (C++11) | false
char (C++11) | CHAR_MIN
signed char (C++11) | SCHAR_MIN
unsigned char (C++11) | ​0​
wchar_t (C++11) | WCHAR_MIN
char8_t (C++20) | ​0​
char16_t (C++11) | ​0​
char32_t (C++11) | ​0​
short (C++11) | SHRT_MIN
unsigned short (C++11) | ​0​
int (C++11) | INT_MIN
unsigned int (C++11) | ​0​
long (C++11) | LONG_MIN
unsigned long (C++11) | ​0​
long long (C++11) | LLONG_MIN
unsigned long long (C++11) | ​0​
float (C++11) | - FLT_MAX
double (C++11) | - DBL_MAX
long double (C++11) | - LDBL_MAX

注解

对每个标准 C++ 浮点类型 T 均有 std::numeric_limits <T>::lowest() == - std::numeric_limits <T>::max() ，但这不必对任何第三方特化成立。

示例

为浮点类型演示 min 、 max 及 lowest

#include <limits>
#include <iostream>
int main()
{

    std::cout << "std::numeric_limits<T>::min():\n"
              << "\tfloat: " << std::numeric_limits<float>::min()
              << " or " << std::hexfloat << std::numeric_limits<float>::min() << '\n'
              << "\tdouble: " << std::defaultfloat << std::numeric_limits<double>::min()
              << " or " << std::hexfloat << std::numeric_limits<double>::min() << '\n';
    std::cout << "std::numeric_limits<T>::lowest():\n"
              << "\tfloat: " << std::defaultfloat << std::numeric_limits<float>::lowest()
              << " or " << std::hexfloat << std::numeric_limits<float>::lowest() << '\n'
              << "\tdouble: " << std::defaultfloat << std::numeric_limits<double>::lowest()
              << " or " << std::hexfloat << std::numeric_limits<double>::lowest() << '\n';
    std::cout << "std::numeric_limits<T>::max():\n"
              << "\tfloat: " << std::defaultfloat << std::numeric_limits<float>::max()
              << " or " << std::hexfloat << std::numeric_limits<float>::max() << '\n'
              << "\tdouble: " << std::defaultfloat << std::numeric_limits<double>::max()
              << " or " << std::hexfloat << std::numeric_limits<double>::max() << '\n';
}

输出：

std::numeric_limits<T>::min():
        float: 1.17549e-38 or 0x1p-126
        double: 2.22507e-308 or 0x1p-1022
std::numeric_limits<T>::lowest():
        float: -3.40282e+38 or -0x1.fffffep+127
        double: -1.79769e+308 or -0x1.fffffffffffffp+1023
std::numeric_limits<T>::max():
        float: 3.40282e+38 or 0x1.fffffep+127
        double: 1.79769e+308 or 0x1.fffffffffffffp+1023

参阅

min [静态] | 返回给定类型的最小有限值 (公开静态成员函数)
denorm_min [静态] | 返回给定浮点类型的最小正非正规值 (公开静态成员函数)
max [静态] | 返回给定类型的最大有限值 (公开静态成员函数)


std::numeric_limits<T>::max

< cpp‎ | types‎ | numeric limits
定义于头文件 <limits> |
static T max() throw(); | (C++11 前)
static constexpr T max() noexcept; | (C++11 起)

返回数值类型 T 所能表示的最大有限值。对所有有界类型有意义。

返回值

T | std::numeric_limits <T>::max()
/* non-specialized */ | T()
bool | true
char | CHAR_MAX
signed char | SCHAR_MAX
unsigned char | UCHAR_MAX
wchar_t | WCHAR_MAX
char8_t (C++20) | UCHAR_MAX
char16_t (C++11) | UINT_LEAST16_MAX
char32_t (C++11) | UINT_LEAST32_MAX
short | SHRT_MAX
unsigned short | USHRT_MAX
int | INT_MAX
unsigned int | UINT_MAX
long | LONG_MAX
unsigned long | ULONG_MAX
long long (C++11) | LLONG_MAX
unsigned long long (C++11) | ULLONG_MAX
float | FLT_MAX
double | DBL_MAX
long double | LDBL_MAX

示例

以一些基本类型和一些标准库 typedef 演示 max() 的使用（输出是系统限定的）

#include <limits>
#include <cstddef>
#include <iostream>
int main()
{
    std::cout << "short: " << std::dec << std::numeric_limits<short>::max()
              << " or " << std::hex << std::showbase << std::numeric_limits<short>::max() << '\n'
              << "int: " << std::dec << std::numeric_limits<int>::max()
              << " or " << std::hex << std::numeric_limits<int>::max() << '\n' << std::dec
              << "streamsize: " << std::dec << std::numeric_limits<std::streamsize>::max()
              << " or " << std::hex << std::numeric_limits<std::streamsize>::max() << '\n'
              << "size_t: " << std::dec << std::numeric_limits<std::size_t>::max()
              << " or " << std::hex << std::numeric_limits<std::size_t>::max() << '\n'
              << "float: " << std::numeric_limits<float>::max()
              << " or " << std::hexfloat << std::numeric_limits<float>::max() << '\n'
              << "double: " << std::defaultfloat << std::numeric_limits<double>::max()
              << " or " << std::hexfloat << std::numeric_limits<double>::max() << '\n';
}

可能的输出：

short: 32767 or 0x7fff
int: 2147483647 or 0x7fffffff
streamsize: 9223372036854775807 or 0x7fffffffffffffff
size_t: 18446744073709551615 or 0xffffffffffffffff
float: 3.40282e+38 or 0x1.fffffep+127
double: 1.79769e+308 or 0x1.fffffffffffffp+1023

参阅

lowest [静态] (C++11) | 返回给定类型的最低有限值 (公开静态成员函数)
min [静态] | 返回给定类型的最小有限值 (公开静态成员函数)


std::numeric_limits<T>::max_digits10

< cpp‎ | types‎ | numeric limits
static constexpr int max_digits10 | (C++11 起)

std::numeric_limits <T>::max_digits10 的值是唯一地表示所有类型 T 值的底 10 位数，是为序列化/反序列化到文本所需。此常量对所有浮点类型有意义。

标准特化

T | std::numeric_limits <T>::max_digits10 的值
/* non-specialized */ (C++11) | ​0​
bool (C++11) | ​0​
char (C++11) | ​0​
signed char (C++11) | ​0​
unsigned char (C++11) | ​0​
wchar_t (C++11) | ​0​
char8_t (C++20) | ​0​
char16_t (C++11) | ​0​
char32_t (C++11) | ​0​
short (C++11) | ​0​
unsigned short (C++11) | ​0​
int (C++11) | ​0​
unsigned int (C++11) | ​0​
long (C++11) | ​0​
unsigned long (C++11) | ​0​
long long (C++11) | ​0​
unsigned long long (C++11) | ​0​
float (C++11) | FLT_DECIMAL_DIG 或 std::ceil ( std::numeric_limits <float>::digits * std::log10 (2) + 1)
double (C++11) | DBL_DECIMAL_DIG 或 std::ceil ( std::numeric_limits <double>::digits * std::log10 (2) + 1)
long double (C++11) | DECIMAL_DIG 或 LDBL_DECIMAL_DIG 或 std::ceil ( std::numeric_limits <long double>::digits * std::log10 (2) + 1)

注解

不同于多数数学运算，只要用至少 max_digits10 （对于 float 为 9 ，对于 double 为 17 ）位，则从浮点值转换到文本并转换回来是准确的：保证产生同一浮点值，即使不确定的文本表示不准确。以小数点记法，可能需要超过一百个十进制小数位表示 float 的精确值。

示例

#include <limits>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <iostream>

int main()
{
    float value = 10.0000086;

    constexpr auto digits10 = std::numeric_limits<decltype(value)>::digits10;
    constexpr auto max_digits10 = std::numeric_limits<decltype(value)>::max_digits10;
    constexpr auto submax_digits10 = max_digits10 - 1;

    std::cout
        << "float:\n"
        << "       digits10 is " << digits10 << " digits" << '\n'
        << "   max_digits10 is " << max_digits10 << " digits" << '\n'
        << "submax_digits10 is " << submax_digits10 << " digits" << '\n'
        << '\n';

    const auto original_precision = std::cout.precision();
    for( auto i = 0; i < 5; ++i )
    {
        std::cout
            << "   max_digits10: " << std::setprecision(max_digits10) << value << '\n'
            << "submax_digits10: " << std::setprecision(submax_digits10) << value << '\n'
            << '\n';

        value = std::nextafter( value, std::numeric_limits<decltype(value)>::max() );
    }
    std::cout.precision( original_precision );

    return 0;
}

输出：

float:
       digits10 is 6 digits
   max_digits10 is 9 digits
submax_digits10 is 8 digits

   max_digits10: 10.0000086
submax_digits10: 10.000009

   max_digits10: 10.0000095
submax_digits10: 10.00001

   max_digits10: 10.0000105
submax_digits10: 10.00001

   max_digits10: 10.0000114
submax_digits10: 10.000011

   max_digits10: 10.0000124
submax_digits10: 10.000012

参阅

radix [静态] | 给定类型的表示所用的基或整数底 (公开静态成员常量)
digits [静态] | 能无更改地表示的 radix 位数 (公开静态成员常量)
digits10 [静态] | 能无更改地表示的十进制位数 (公开静态成员常量)
min_exponent [静态] | 底的该数次幂是合法正规浮点值的最小负数加一 (公开静态成员常量)
max_exponent [静态] | 底的该数次幂是合法有限浮点值的最大整数加一 (公开静态成员常量)


std::numeric_limits<T>::max_exponent

< cpp‎ | types‎ | numeric limits
static const int max_exponent10; | (C++11 前)
static constexpr int max_exponent10; | (C++11 起)

std::numeric_limits <T>::max_exponent 的值是满足 \(\scriptsize r^{n-1}\)rn-1
 是浮点类型 T 的可表示有限值最大正整数 n ，其中 r 是 std::numeric_limits <T>::radix 。

标准特化

T | std::numeric_limits <T>::max_exponent 的值
/* non-specialized */ | ​0​
bool | ​0​
char | ​0​
signed char | ​0​
unsigned char | ​0​
wchar_t | ​0​
char8_t (C++20) | ​0​
char16_t (C++11) | ​0​
char32_t (C++11) | ​0​
short | ​0​
unsigned short | ​0​
int | ​0​
unsigned int | ​0​
long | ​0​
unsigned long | ​0​
long long (C++11) | ​0​
unsigned long long (C++11) | ​0​
float | FLT_MAX_EXP
double | DBL_MAX_EXP
long double | LDBL_MAX_EXP

示例

为 float 类型演示 max_exponent、 max_exponent10 和 max() 的关系：

#include <iostream>
#include <limits>
int main()
{
    std::cout << "max() = " << std::numeric_limits<float>::max() << '\n'
              << "max_exponent10 = " << std::numeric_limits<float>::max_exponent10 << '\n'
              << std::hexfloat
              << "max() = " << std::numeric_limits<float>::max() << '\n'
              << "max_exponent = " << std::numeric_limits<float>::max_exponent << '\n';
}

输出：

max() = 3.40282e+38
max_exponent10 = 38
max() = 0x1.fffffep+127
max_exponent = 128

参阅

min_exponent10 [静态] | 10 的该数次幂是合法正规浮点值的最小负数 (公开静态成员常量)
min_exponent [静态] | 底的该数次幂是合法正规浮点值的最小负数加一 (公开静态成员常量)
max_exponent10 [静态] | 10 的该数次幂是合法有限浮点值的最大整数 (公开静态成员常量)


std::numeric_limits<T>::max_exponent10

< cpp‎ | types‎ | numeric limits
static const int max_exponent10; | (C++11 前)
static constexpr int max_exponent10; | (C++11 起)

std::numeric_limits <T>::max_exponent10 的值是满足 \(\scriptsize 10^n\)10n
 是浮点类型 T 的可表示有限值的最大正整数 n 。

标准特化

T | std::numeric_limits <T>::max_exponent10 的值
/* non-specialized */ | ​0​
bool | ​0​
char | ​0​
signed char | ​0​
unsigned char | ​0​
wchar_t | ​0​
char8_t (C++20) | ​0​
char16_t (C++11) | ​0​
char32_t (C++11) | ​0​
short | ​0​
unsigned short | ​0​
int | ​0​
unsigned int | ​0​
long | ​0​
unsigned long | ​0​
long long (C++11) | ​0​
unsigned long long (C++11) | ​0​
float | FLT_MAX_10_EXP
double | DBL_MAX_10_EXP
long double | LDBL_MAX_10_EXP

示例

为 float 类型演示 max_exponent、 max_exponent10 及 max() 的关系：

#include <iostream>
int main()
{
    std::cout << "max() = " << std::numeric_limits<float>::max() << '\n'
              << "max_exponent10 = " << std::numeric_limits<float>::max_exponent10 << '\n'
              << std::hexfloat
              << "max() = " << std::numeric_limits<float>::max() << '\n'
              << "max_exponent = " << std::numeric_limits<float>::max_exponent << '\n';
}

输出：

max() = 3.40282e+38
max_exponent10 = 38
max() = 0x1.fffffep+127
max_exponent = 128

参阅

max_exponent [静态] | 底的该数次幂是合法有限浮点值的最大整数加一 (公开静态成员常量)
min_exponent [静态] | 底的该数次幂是合法正规浮点值的最小负数加一 (公开静态成员常量)
min_exponent10 [静态] | 10 的该数次幂是合法正规浮点值的最小负数 (公开静态成员常量)


std::numeric_limits<T>::min

< cpp‎ | types‎ | numeric limits
定义于头文件 <limits> |
static T min() throw(); | (C++11 前)
static constexpr T min() noexcept; | (C++11 起)

返回数值类型 T 可表示的最小有限值。

对于有非正规的浮点类型， min 返回最小正正规值。注意此行为可能是非预期的，特别是在与 min 对整数类型的行为比较时。为找到没有比它更小的值的值，请用 numeric_limits::lowest 。

min 仅对有界类型和无界无符号类型意义，即表示负值的无限集的类型无有意义的最小值。

返回值

T | std::numeric_limits <T>::min()
/* non-specialized */ | T()
bool | false
char | CHAR_MIN
signed char | SCHAR_MIN
unsigned char | ​0​
wchar_t | WCHAR_MIN
char8_t (C++20) | ​0​
char16_t (C++11) | ​0​
char32_t (C++11) | ​0​
short | SHRT_MIN
unsigned short | ​0​
int | INT_MIN
unsigned int | ​0​
long | LONG_MIN
unsigned long | ​0​
long long (C++11) | LLONG_MIN
unsigned long long (C++11) | ​0​
float | FLT_MIN
double | DBL_MIN
long double | LDBL_MIN

示例

演示以 typedef 类型使用，及整数和浮点类型间结果符号的差异

#include <limits>
#include <cstddef>
#include <iostream>

int main()
{
    std::cout
        << "short: " << std::dec << std::numeric_limits<short>::min()
        << " or " << std::hex << std::showbase
        << std::numeric_limits<short>::min() << '\n'

        << "int: " << std::dec << std::numeric_limits<int>::min() << std::showbase
        << " or " << std::hex << std::numeric_limits<int>::min() << '\n' << std::dec

        << "ptrdiff_t: " << std::numeric_limits<std::ptrdiff_t>::min() << std::showbase
        << " or " << std::hex << std::numeric_limits<std::ptrdiff_t>::min() << '\n'

        << "float: " << std::numeric_limits<float>::min()
        << " or " << std::hexfloat << std::numeric_limits<float>::min() << '\n'

        << "double: " << std::defaultfloat << std::numeric_limits<double>::min()
        << " or " << std::hexfloat << std::numeric_limits<double>::min() << '\n';
}

可能的输出：

short: -32768 or 0x8000
int: -2147483648 or 0x80000000
ptrdiff_t: -9223372036854775808 or 0x8000000000000000
float: 1.17549e-38 or 0x1p-126
double: 2.22507e-308 or 0x1p-1022

参阅

lowest [静态] (C++11) | 返回给定类型的最低有限值 (公开静态成员函数)
denorm_min [静态] | 返回给定浮点类型的最小正非正规值 (公开静态成员函数)
max [静态] | 返回给定类型的最大有限值 (公开静态成员函数)


std::numeric_limits<T>::min_exponent

< cpp‎ | types‎ | numeric limits
static const int min_exponent; | (C++11 前)
static constexpr int min_exponent; | (C++11 起)

std::numeric_limits <T>::min_exponent 的值是满足 \(\scriptsize r^{n-1}\)rn-1
 是浮点类型 T 合法正规值的最低负数 n ，其中 r 是 std::numeric_limits <T>::radix 。

标准特化

T | std::numeric_limits <T>::min_exponent 的值
/* non-specialized */ | ​0​
bool | ​0​
char | ​0​
signed char | ​0​
unsigned char | ​0​
wchar_t | ​0​
char8_t (C++20) | ​0​
char16_t (C++11) | ​0​
char32_t (C++11) | ​0​
short | ​0​
unsigned short | ​0​
int | ​0​
unsigned int | ​0​
long | ​0​
unsigned long | ​0​
long long (C++11) | ​0​
unsigned long long (C++11) | ​0​
float | FLT_MIN_EXP
double | DBL_MIN_EXP
long double | LDBL_MIN_EXP

示例

为 float 类型演示 min_exponent、 min_exponent10、 min 及 radix 的关系：

#include <iostream>
int main()
{
    std::cout << "min() = " << std::numeric_limits<float>::min() << '\n'
              << "min_exponent10 = " << std::numeric_limits<float>::min_exponent10 << '\n'
              << std::hexfloat
              << "min() = " << std::numeric_limits<float>::min() << '\n'
              << "min_exponent = " << std::numeric_limits<float>::min_exponent << '\n';
}

输出：

min() = 1.17549e-38
min_exponent10 = -37
min() = 0x1p-126
min_exponent = -125

参阅

radix [静态] | 给定类型的表示所用的基或整数底 (公开静态成员常量)
min_exponent10 [静态] | 10 的该数次幂是合法正规浮点值的最小负数 (公开静态成员常量)
max_exponent [静态] | 底的该数次幂是合法有限浮点值的最大整数加一 (公开静态成员常量)
max_exponent10 [静态] | 10 的该数次幂是合法有限浮点值的最大整数 (公开静态成员常量)


std::numeric_limits<T>::min_exponent10

< cpp‎ | types‎ | numeric limits
static const int min_exponent10; | (C++11 前)
static constexpr int min_exponent10; | (C++11 起)

std::numeric_limits <T>::min_exponent10 的值是满足 \(\scriptsize 10^n\)10n
 是浮点类型 T 的合法正规值的最低负数 n 。

标准特化

T | std::numeric_limits <T>::min_exponent10 的值
/* non-specialized */ | ​0​
bool | ​0​
char | ​0​
signed char | ​0​
unsigned char | ​0​
wchar_t | ​0​
char8_t (C++20) | ​0​
char16_t (C++11) | ​0​
char32_t (C++11) | ​0​
short | ​0​
unsigned short | ​0​
int | ​0​
unsigned int | ​0​
long | ​0​
unsigned long | ​0​
long long (C++11) | ​0​
unsigned long long (C++11) | ​0​
float | FLT_MIN_10_EXP
double | DBL_MIN_10_EXP
long double | LDBL_MIN_10_EXP

示例

为 float 类型演示 min_exponent、 min_exponent10、 min 及 radix 的关系：

#include <iostream>
int main()
{
    std::cout << "min() = " << std::numeric_limits<float>::min() << '\n'
              << "min_exponent10 = " << std::numeric_limits<float>::min_exponent10 << '\n'
              << std::hexfloat
              << "min() = " << std::numeric_limits<float>::min() << '\n'
              << "min_exponent = " << std::numeric_limits<float>::min_exponent << '\n';
}

输出：

min() = 1.17549e-38
min_exponent10 = -37
min() = 0x1p-126
min_exponent = -125

参阅

min_exponent [静态] | 底的该数次幂是合法正规浮点值的最小负数加一 (公开静态成员常量)
max_exponent [静态] | 底的该数次幂是合法有限浮点值的最大整数加一 (公开静态成员常量)
max_exponent10 [静态] | 10 的该数次幂是合法有限浮点值的最大整数 (公开静态成员常量)


std::numeric_limits<T>::quiet_NaN

< cpp‎ | types‎ | numeric limits
static T quiet_NaN() throw(); | (C++11 前)
static constexpr T quiet_NaN() noexcept; | (C++11 起)

返回特殊值“安静的非数”，以浮点类型 T 表示。仅若 std::numeric_limits <T>::has_quiet_NaN == true 才有意义。在最常见的浮点数二进制表示 IEEE 754 中，任何所有指数位均为 1 且至少有一位尾数位为 1 的值表示 NaN 。何种尾数值表示安静或发信的 NaN ，及符号位是否有意义，是实现定义的。

返回值

T | std::numeric_limits <T>::quiet_NaN()
/* non-specialized */ | T()
bool | false
char | ​0​
signed char | ​0​
unsigned char | ​0​
wchar_t | ​0​
char8_t (C++20) | ​0​
char16_t (C++11) | ​0​
char32_t (C++11) | ​0​
short | ​0​
unsigned short | ​0​
int | ​0​
unsigned int | ​0​
long | ​0​
unsigned long | ​0​
long long (C++11) | ​0​
unsigned long long (C++11) | ​0​
float | 实现定义（可为 NAN ）
double | 实现定义
long double | 实现定义

注解

NaN 与自身决不比较相等。复制 NaN 可能不保留其位表示。

示例

数种生成 NaN 的方式（输出字符串是编译器指定的）

#include <iostream>
#include <limits>
#include <cmath>

int main()
{
    std::cout << std::numeric_limits<double>::quiet_NaN() << ' '
              << std::numeric_limits<double>::signaling_NaN() << ' '
              << std::acos(2) << ' '
              << std::tgamma(-1) << ' '
              << std::log(-1) << ' '
              << std::sqrt(-1) << ' '
              << 0 / 0.0 << '\n';

    std::cout << "NaN == NaN? " << std::boolalpha
              << ( std::numeric_limits<double>::quiet_NaN()
                   == std::numeric_limits<double>::quiet_NaN() ) << '\n';
}

输出：

nan nan nan nan nan -nan -nan
NaN == NaN? false

参阅

has_quiet_NaN [静态] | 鉴别能表示特殊值“安静的非数”（ NaN ）的浮点类型 (公开静态成员常量)
signaling_NaN [静态] | 返回给定浮点类型的发信的 NaN (公开静态成员函数)
nannanfnanl (C++11)(C++11)(C++11) | 非数（NaN） (函数)
isnan (C++11) | 检查给定的数是否 NaN (函数)


std::numeric_limits<T>::radix

< cpp‎ | types‎ | numeric limits
static const int radix; | (C++11 前)
static constexpr int radix; | (C++11 起)

std::numeric_limits <T>::radix 的值是用于表示该类型的数字系统的底。对于所有二进制数值类型为 2 ，但它可以，譬如对 IEEE 754 十进制浮点类型或第三方二进制编码十进制整数为 10 。此常量对所有特化有意义。

标准特化

T | std::numeric_limits <T>::radix 的值
/* non-specialized */ | ​0​
bool | 2
char | 2
signed char | 2
unsigned char | 2
wchar_t | 2
char8_t (C++20) | 2
char16_t (C++11) | 2
char32_t (C++11) | 2
short | 2
unsigned short | 2
int | 2
unsigned int | 2
long | 2
unsigned long | 2
long long (C++11) | 2
unsigned long long (C++11) | 2
float | FLT_RADIX
double | FLT_RADIX
long double | FLT_RADIX

参阅

digits [静态] | 能无更改地表示的 radix 位数 (公开静态成员常量)
min_exponent [静态] | 底的该数次幂是合法正规浮点值的最小负数加一 (公开静态成员常量)
max_exponent [静态] | 底的该数次幂是合法有限浮点值的最大整数加一 (公开静态成员常量)


std::numeric_limits<T>::round_error

< cpp‎ | types‎ | numeric limits
static T round_error() throw(); | (C++11 前)
static constexpr T round_error() noexcept; | (C++11 起)

返回以 ULP （最后位置单位）表示的最大可能舍入错误，其为 ISO 10967 定义，可以从 0.5 （舍入到最近位）变化到 1.0 （舍入到零或无穷大）。它仅若 std::numeric_limits <T>::is_integer == false 才有意义。

返回值

T | std::numeric_limits <T>::round_error()
/* non-specialized */ | T()
bool | false
char | ​0​
signed char | ​0​
unsigned char | ​0​
wchar_t | ​0​
char8_t (C++20) | ​0​
char16_t (C++11) | ​0​
char32_t (C++11) | ​0​
short | ​0​
unsigned short | ​0​
int | ​0​
unsigned int | ​0​
long | ​0​
unsigned long | ​0​
long long (C++11) | ​0​
unsigned long long (C++11) | ​0​
float | 0.5F
double | 0.5
long double | 0.5L

参阅

round_style
[静态]
 鉴别类型所用的舍入模式
(公开静态成员常量)


std::numeric_limits<T>::round_style

< cpp‎ | types‎ | numeric limits
static const std::float_round_style round_style; | (C++11 前)
static constexpr std::float_round_style round_style; | (C++11 起)

std::numeric_limits <T>::round_style 的值鉴别浮点类型 T 在凡将不能以 T 的值表示的值存储于该类型的对象时所用的舍入模式。

标准特化

T | std::numeric_limits <T>::round_style 的值
/* non-specialized */ | std::round_toward_zero
bool | std::round_toward_zero
char | std::round_toward_zero
signed char | std::round_toward_zero
unsigned char | std::round_toward_zero
wchar_t | std::round_toward_zero
char8_t (C++20) | std::round_toward_zero
char16_t (C++11) | std::round_toward_zero
char32_t (C++11) | std::round_toward_zero
short | std::round_toward_zero
unsigned short | std::round_toward_zero
int | std::round_toward_zero
unsigned int | std::round_toward_zero
long | std::round_toward_zero
unsigned long | std::round_toward_zero
long long (C++11) | std::round_toward_zero
unsigned long long (C++11) | std::round_toward_zero
float | 通常为 std::round_to_nearest
double | 通常为 std::round_to_nearest
long double | 通常为 std::round_to_nearest

注解

这些值是常量，且不反映 std::fesetround 所做的舍入模式更改。可从 FLT_ROUNDS 或 std::fegetround 获得更改后的值。

示例

十进制值 0.1 不能表示成二进制浮点类型。在存储于 IEEE-754 double 时，它落入 0x1.9999999999999*2-4
 与 0x1.999999999999a*2-4
 之间。舍入到最近可表示结果导致 0x1.999999999999a*2-4
 。

同样地，十进制值 0.3 在 0x1.3333333333333*2-2
 与 0x1.3333333333334*2-2
 之间，舍入到最近值后存储为 0x1.3333333333333*2-2
 。

#include <iostream>
#include <limits>
int main()
{
    std::cout << std::hexfloat << "The decimal 0.1 is stored in a double as "
              << 0.1 << '\n'
              << "The decimal 0.3 is stored in a double as "
              << 0.3 << '\n'
              << "The rounding style is " << std::numeric_limits<double>::round_style << '\n';
}

输出：

The decimal 0.1 is stored in a double as 0x1.999999999999ap-4
The decimal 0.3 is stored in a double as 0x1.3333333333333p-2
The rounding style is 1

参阅

float_round_style
 指示浮点舍入模式
(枚举)


std::numeric_limits<T>::signaling_NaN

< cpp‎ | types‎ | numeric limits
static T signaling_NaN() throw(); | (C++11 前)
static constexpr T signaling_NaN() noexcept; | (C++11 起)

返回特殊值“发信的非数”，以浮点类型 T 表示。仅若 std::numeric_limits <T>::has_signaling_NaN == true 才有意义。在最常见的浮点数二进制表示 IEEE 754 中，任何所有指数位均为 1 且至少有一位尾数位为 1 的值表示 NaN 。何种尾数位的值表示安静或发信的 NaN ，及符号位是否有意义，是实现定义的。

返回值

T | std::numeric_limits <T>::signaling_NaN()
/* non-specialized */ | T()
bool | false
char | ​0​
signed char | ​0​
unsigned char | ​0​
wchar_t | ​0​
char8_t (C++20) | ​0​
char16_t (C++11) | ​0​
char32_t (C++11) | ​0​
short | ​0​
unsigned short | ​0​
int | ​0​
unsigned int | ​0​
long | ​0​
unsigned long | ​0​
long long (C++11) | ​0​
unsigned long long (C++11) | ​0​
float | 实现定义（可为 FLT_SNAN ）
double | 实现定义（可为 DBL_SNAN ）
long double | 实现定义（可为 LDBL_SNAN ）

注解

NaN 决不与自身比较相等。 IEEE-754 不要求复制 NaN 保留其位表示（符号与载荷），尽管大多数实现都会保留。

当发信 NaN 被用于算术表达式的参数时，可能引发适当的浮点异常，而且 NaN 被“安静化”，即表达式返回安静的 NaN 。

示例

演示用发信的 NaN 引发浮点异常

#include <iostream>
#include <limits>
#include <cfenv>
#pragma STDC_FENV_ACCESS on
void show_fe_exceptions()
{
    int n = std::fetestexcept(FE_ALL_EXCEPT);
    if(n & FE_INVALID) std::cout << "FE_INVALID is raised\n";
    else if(n == 0)    std::cout << "no exceptions are raised\n";
    std::feclearexcept(FE_ALL_EXCEPT);
}
int main()
{
    double snan = std::numeric_limits<double>::signaling_NaN();
    std::cout << "After sNaN was obtained ";
    show_fe_exceptions();
    double qnan = snan * 2.0;
    std::cout << "After sNaN was multiplied by 2 ";
    show_fe_exceptions();
    double qnan2 = qnan * 2.0;
    std::cout << "After the quieted NaN was multiplied by 2 ";
    show_fe_exceptions();
    std::cout << "The result is " << qnan2 << '\n';
}

输出：

After sNaN was obtained no exceptions are raised
After sNaN was multiplied by 2 FE_INVALID is raised
After the quieted NaN was multiplied by 2 no exceptions are raised
The result is nan

参阅

has_signaling_NaN [静态] | 鉴别能表示特殊值“发信的非数”（ NaN ）的浮点类型 (公开静态成员常量)
quiet_NaN [静态] | 返回给定浮点类型的安静 NaN 值 (公开静态成员函数)
isnan (C++11) | 检查给定的数是否 NaN (函数)


std::numeric_limits<T>::tinyness_before

< cpp‎ | types‎ | numeric limits
static const bool tinyness_before; | (C++11 前)
static constexpr bool tinyness_before; | (C++11 起)

std::numeric_limits <T>::tinyness_before 的值对所有测试浮点表达式在舍入前下溢的浮点类型 T 为 true 。

标准特化

T | std::numeric_limits <T>::tinyness_before 的值
/* non-specialized */ | false
bool | false
char | false
signed char | false
unsigned char | false
wchar_t | false
char8_t (C++20) | false
char16_t (C++11) | false
char32_t (C++11) | false
short | false
unsigned short | false
int | false
unsigned int | false
long | false
unsigned long | false
long long (C++11) | false
unsigned long long (C++11) | false
float | 实现定义
double | 实现定义
long double | 实现定义

注解

符合标准的 IEEE 754 浮点实现要求检测浮点下溢，并在执行处有二种可选的情形

  1. 若假如以指数范围和精度均为无界的计算，产生绝对值小于 std::numeric_limits <T>::min() 的结果，则发生下溢（并且可能引发 FE_UNDERFLOW ）。这种实现在舍入前检测是否较小（如 UltraSparc 、 POWER ）。
  2. 若舍入到目标浮点类型（即舍入到 std::numeric_limits <T>::digits 位）后，结果的绝对值小于 std::numeric_limits <T>::min() ，则发生下溢（并且可能引发 FE_UNDERFLOW ）。正式地说，假如以指数范围和精度均为无界的计算，非零结果的绝对值小于 std::numeric_limits <T>::min() 。这种实现在舍入后检测是否较小（如 SuperSparc ）

示例

最大非正规数乘 1.0 加上一个机器 epsilon 在舍入前给出小值 0x0.fffffffffffff8p-1022 ，而非舍入后的正规值 1p-1022 。用于执行此测试的实现（ IBM Power7 ）检测摄入前是否较小。

#include <iostream>
#include <limits>
#include <cmath>
#include <cfenv>
int main()
{
    std::cout << "Tinyness before: " << std::boolalpha
              << std::numeric_limits<double>::tinyness_before << '\n';

    double denorm_max = std::nextafter(std::numeric_limits<double>::min(), 0);
    double multiplier = 1 + std::numeric_limits<double>::epsilon();

    std::feclearexcept(FE_ALL_EXCEPT);

    double result = denorm_max*multiplier; // 仅若 tinyness_before 才下溢

    if(std::fetestexcept(FE_UNDERFLOW))
        std::cout << "Underflow detected\n";

    std::cout << std::hexfloat << denorm_max << " x " << multiplier  <<  " = "
              << result << '\n';
}

可能的输出：

Tinyness before: true
Underflow detected
0xf.ffffffffffffp-1030 x 0x1.0000000000001p+0 = 0x1p-1022

参阅

has_denorm_loss [静态] | 鉴别浮点类型是否检测精度损失为非正规损失，而非不准确结果 (公开静态成员常量)
has_denorm [静态] | 鉴别浮点类型所用的非正规风格 (公开静态成员常量)


std::numeric_limits<T>::traps

< cpp‎ | types‎ | numeric limits
static const bool traps; | (C++11 前)
static constexpr bool traps; | (C++11 起)

std::numeric_limits <T>::traps 的值，对所有至少有一个若用作算术运算参数则会生成陷阱的值的算术类型 T 为 true 。

标准特化

T | std::numeric_limits <T>::traps 的值
/* non-specialized */ | false
bool | false
char | 通常为 true
signed char | 通常为 true
unsigned char | 通常为 true
wchar_t | 通常为 true
char8_t (C++20) | 通常为 true
char16_t (C++11) | 通常为 true
char32_t (C++11) | 通常为 true
short | 通常为 true
unsigned short | 通常为 true
int | 通常为 true
unsigned int | 通常为 true
long | 通常为 true
unsigned long | 通常为 true
long long (C++11) | 通常为 true
unsigned long long (C++11) | 通常为 true
float | 通常为 false
double | 通常为 false
long double | 通常为 false

注解

大多数平台上，除以零始终会产生陷阱，而对所有支持值 0 的整数类型， std::numeric_limits <T>::traps 为 true 。例外是类型 bool ：即使除以 false 因为从 bool 整数提升到 int 而产生陷阱，这也是零值的 int 所产生的陷阱。零不是 bool 的值。

大多数平台上，浮点异常可以在运行时开关（例如 Linux 上的 feenableexcept() 或 Windows 上的 _controlfp ），该情况下 std::numeric_limits <T>::traps 对浮点类型的值反映程序启动时的浮点陷阱设施，它在大多数现代系统上为 false 。 DEC Alpha 程序可以是例外，若不以 -ieee 编译程序，则为 true 。

参阅

浮点环境
tinyness_before [静态] | 鉴别检测舍入前是否非正规的浮点类型 (公开静态成员常量)
has_denorm_loss [静态] | 鉴别浮点类型是否检测精度损失为非正规损失，而非不准确结果 (公开静态成员常量)


offsetof

< cpp‎ | types
定义于头文件 <cstddef>
#define offsetof(type, member) /*implementation-defined*/

宏 offsetof 展开成 std::size_t 类型的整数常量表达式，其值是从指定类型对象开始到其指定子对象的字节数偏移，若有填充字节则包括之。

给定拥有静态存储期的 type 类型对象 o ， o.member 应当为指代 o 的子对象的左值常量表达式。否则行为未定义。特别是若 member 为静态数据成员、位域或成员函数，则行为未定义。

若 type 不是简旧数据类型 (PODType) (C++11 前)标准布局类型 (C++11 起)，则行为未定义 (C++17 前) offsetof 宏的使用为条件性支持 (C++17 起)。

表达式 offsetof(type, member) 决不为类型待决，而且它为值待决当且仅当 type 为待决类型。

异常

offsetof 不抛出异常。

表达式 noexcept(offsetof(type, member)) 始终求值为 true 。

 (C++11 起)

注解

标准布局类型的首个成员的偏移始终是零（空基类优化是强制的）。

 (C++11 起)

offsetof 不能以标准 C++ 实现，并要求编译器支持： GCC 、 LLVM 。

不限制 member 为直接成员。它能指代给定成员的子对象，例如数组成员的元素。这是由 C DR 496 指定的。

C23 中指定在 offsetof 中定义新类型为未定义行为，而这种用法仅为一些实现的 C++ 模式支持： ICC 与 GCC 的一些旧版本支持 offsetof(struct Foo { int a; }, a) ，而所有已知实现都拒绝 offsetof(struct Foo { int a, b; }, a) ，因为 Foo 定义中的逗号。

示例

#include <iostream>
#include <cstddef>
struct S {
    char c;
    double d;
};
int main()
{
    std::cout << "the first element is at offset " << offsetof(S, c) << '\n'
              << "the double is at offset " << offsetof(S, d) << '\n';
}

可能的输出：

the first element is at offset 0
the double is at offset 8

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 273 | C++98 | 若重载了一元 operator& 则 offsetof 可能无法工作 | 即使重载了 operator& 也要求它正确工作

参阅

size_t | sizeof 运算符返回的无符号整数类型 (typedef)
is_standard_layout (C++11) | 检查是否是一个标准布局类型 (类模板)


std::ptrdiff_t

< cpp‎ | types
定义于头文件 <cstddef>
typedef /*implementation-defined*/ ptrdiff_t;

std::ptrdiff_t 是二个指针相减结果的有符号整数类型。

std::ptrdiff_t 的位宽不小于 17 。

 (C++11 起)

注解

std::ptrdiff_t 被用于指针算术及数组下标，若负值可行。使用其他类型，如 int 的程序，可能诸如 64 位的系统上失败，在当下标超过 INT_MAX 或依赖 32 位模算术时。

在用 C++ 容器库工作时，迭代器的差的准确类型是成员 typedef difference_type ，它常与 std::ptrdiff_t 相同。

只有指向同一数组元素的指针（含指向数组结尾后一位置的指针）可以相减。

若数组过大（大于 PTRDIFF_MAX 个元素，而小于 SIZE_MAX 字节），则二个指针的差可能无法以 std::ptrdiff_t 表示，二个这种指针相减的结果是未定义的。

对于短于 PTRDIFF_MAX 的 char 数组， std::ptrdiff_t 表现为 std::size_t 的有符号对应物：它可以存储数组的大小，而且在多数平台上等同于 std::intptr_t 。

示例

#include <cstddef>
#include <iostream>
int main()
{
    const std::size_t N = 10;
    int* a = new int[N];
    int* end = a + N;
    for (std::ptrdiff_t i = N; i > 0; --i)
        std::cout << (*(end - i) = i) << ' ';
    delete[] a;
}

输出：

10 9 8 7 6 5 4 3 2 1

参阅

size_t | sizeof 运算符返回的无符号整数类型 (typedef)
offsetof | 从标准布局类型的起始到其指定成员的字节偏移量 (宏函数)


std::rank

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct rank; | (C++11 起)

若 T 是数组类型，则提供等于该数组维数的成员常量 value 。对于任何其他类型， value 为 0 。

添加 rank 或 rank_v (C++17 起) 的特化的程序行为未定义。

辅助变量模板

template< class T > inline constexpr std::size_t rank_v = rank<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 T 的维数或零
(公开静态成员常量)

成员函数

operator std::size_t | 转换对象为 std::size_t ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | std::size_t
type | std::integral_constant < std::size_t, value>

可能的实现

template<class T>
struct rank : public std::integral_constant<std::size_t, 0> {};

template<class T>
struct rank<T[]> : public std::integral_constant<std::size_t, rank<T>::value + 1> {};

template<class T, std::size_t N>
struct rank<T[N]> : public std::integral_constant<std::size_t, rank<T>::value + 1> {};

示例

#include <iostream>
#include <type_traits>

int main()
{
    std::cout << std::rank<int[1][2][3]>::value << '\n';
    std::cout << std::rank<int[][2][3][4]>::value << '\n';
    std::cout << std::rank<int>::value << '\n';
}

输出：

3
4
0

参阅

is_array (C++11) | 检查类型是否是数组类型 (类模板)
extent (C++11) | 获取数组类型在指定维度的大小 (类模板)
remove_extent (C++11) | 从给定数组类型移除一个维度 (类模板)
remove_all_extents (C++11) | 移除给定数组类型的所有维度 (类模板)


std::remove_all_extents

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct remove_all_extents; | (C++11 起)

若 T 是某类型 X 的多维数组，则提供等于 X 的成员 typedef type ，否则 type 为 T 。

添加 remove_all_extents 的特化的程序行为未定义。

成员类型

名称 | 定义
type | T 的元素类型

辅助类型

template< class T > using remove_all_extents_t = typename remove_all_extents<T>::type; | (C++14 起)

可能的实现

template<class T>
struct remove_all_extents { typedef T type;};

template<class T>
struct remove_all_extents<T[]> {
    typedef typename remove_all_extents<T>::type type;
};

template<class T, std::size_t N>
struct remove_all_extents<T[N]> {
    typedef typename remove_all_extents<T>::type type;
};

示例

#include <iostream>
#include <type_traits>
#include <typeinfo>

template<class A>
void foo(const A&)
{
    typedef typename std::remove_all_extents<A>::type Type;
    std::cout << "underlying type: " << typeid(Type).name() << '\n';
}

int main()
{
    float a1[1][2][3];
    int a2[3][2];
    float a3[1][1][1][1][2];
    double a4[2][3];

    foo(a1);
    foo(a2);
    foo(a3);
    foo(a4);
}

可能的输出：

underlying type: f
underlying type: i
underlying type: f
underlying type: d

参阅

is_array (C++11) | 检查类型是否是数组类型 (类模板)
rank (C++11) | 获取数组类型的维数 (类模板)
extent (C++11) | 获取数组类型在指定维度的大小 (类模板)
remove_extent (C++11) | 从给定数组类型移除一个维度 (类模板)


std::remove_cv, std::remove_const, std::remove_volatile

< cpp‎ | types
定义于头文件 <type_traits> |  |
template< class T > struct remove_cv; | (1) | (C++11 起)
template< class T > struct remove_const; | (2) | (C++11 起)
template< class T > struct remove_volatile; | (3) | (C++11 起)

提供与 T 相同的成员 typedef type ，除了其最顶层 cv 限定符被移除。

1) 移除最顶层 const 、最顶层 volatile 或两者，若存在。
2) 移除最顶层 const
3) 移除最顶层 volatile

添加此页面上描述的任何模板的特化的程序行为未定义。

成员类型

名称 | 定义
type | 无 cv 限定符的 T

辅助类型

template< class T > using remove_cv_t = typename remove_cv<T>::type; | (C++14 起)
template< class T > using remove_const_t = typename remove_const<T>::type; | (C++14 起)
template< class T > using remove_volatile_t = typename remove_volatile<T>::type; | (C++14 起)

可能的实现

template< class T > struct remove_cv                   { typedef T type; };
template< class T > struct remove_cv<const T>          { typedef T type; };
template< class T > struct remove_cv<volatile T>       { typedef T type; };
template< class T > struct remove_cv<const volatile T> { typedef T type; };

template< class T > struct remove_const                { typedef T type; };
template< class T > struct remove_const<const T>       { typedef T type; };

template< class T > struct remove_volatile             { typedef T type; };
template< class T > struct remove_volatile<volatile T> { typedef T type; };

示例

从 const volatile int * 移除 const/volatile 不修改该类型，因为该指针自身既非 const 亦非 volatile 。

#include <iostream>
#include <type_traits>

int main() {
    typedef std::remove_cv<const int>::type type1;
    typedef std::remove_cv<volatile int>::type type2;
    typedef std::remove_cv<const volatile int>::type type3;
    typedef std::remove_cv<const volatile int*>::type type4;
    typedef std::remove_cv<int * const volatile>::type type5;

    std::cout << "test1 " << (std::is_same<int, type1>::value
        ? "passed" : "failed") << '\n';
    std::cout << "test2 " << (std::is_same<int, type2>::value
        ? "passed" : "failed") << '\n';
    std::cout << "test3 " << (std::is_same<int, type3>::value
        ? "passed" : "failed") << '\n';
    std::cout << "test4 " << (std::is_same<const volatile int*, type4>::value
        ? "passed" : "failed") << '\n';
    std::cout << "test5 " << (std::is_same<int*, type5>::value
        ? "passed" : "failed") << '\n';
}

输出：

test1 passed
test2 passed
test3 passed
test4 passed
test5 passed

参阅

is_const (C++11) | 检查类型是否为 const 限定 (类模板)
is_volatile (C++11) | 检查类型是否为 volatile 限定 (类模板)
add_cvadd_constadd_volatile (C++11)(C++11)(C++11) | 添加 const 或/与 volatile 限定符到给定类型 (类模板)
remove_cvref (C++20) | 将 std::remove_cv 与 std::remove_reference 结合 (类模板)


std::remove_cvref

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct remove_cvref; | (C++20 起)

若类型 T 为引用类型，则提供成员 type ，它是移除了其最顶层 cv 限定符的 T 所引用的类型。否则 type 为移除最顶层 cv 限定符的 T 。

添加 remove_cvref 的特化的程序行为未定义。

成员类型

名称 | 定义
type | T 所引用的类型，或若 T 不是引用则为其自身，移除顶层 cv 限定符

辅助类型

template< class T > using remove_cvref_t = typename remove_cvref<T>::type; | (C++20 起)

可能的实现

template< class T >
struct remove_cvref {
    typedef std::remove_cv_t<std::remove_reference_t<T>> type;
};

示例

#include <iostream>
#include <type_traits>

int main()
{
    std::cout << std::boolalpha
              << std::is_same_v<std::remove_cvref_t<int>, int> << '\n'
              << std::is_same_v<std::remove_cvref_t<int&>, int> << '\n'
              << std::is_same_v<std::remove_cvref_t<int&&>, int> << '\n'
              << std::is_same_v<std::remove_cvref_t<const int&>, int> << '\n'
              << std::is_same_v<std::remove_cvref_t<const int[2]>, int[2]> << '\n'
              << std::is_same_v<std::remove_cvref_t<const int(&)[2]>, int[2]> << '\n'
              << std::is_same_v<std::remove_cvref_t<int(int)>, int(int)> << '\n';
}

输出：

true
true
true
true
true
true
true

参阅

remove_cvremove_constremove_volatile (C++11)(C++11)(C++11) | 从给定类型移除 const 或/与 volatile 限定符 (类模板)
remove_reference (C++11) | 从给定类型移除引用 (类模板)
decay (C++11) | 实施当按值传递实参给函数时所进行的类型变换 (类模板)


std::remove_extent

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct remove_extent; | (C++11 起)

若 T 是某类型 X 的数组，则提供等于 X 的成员 typedef type ，否则 type 为 T 。注意若 T 是多维数组，则只移除第一维。

添加 remove_extent 的特化的程序行为未定义。

成员类型

类型 | 定义
type | T 的元素类型

辅助类型

template< class T > using remove_extent_t = typename remove_extent<T>::type; | (C++14 起)

可能的实现

template<class T>
struct remove_extent { typedef T type; };

template<class T>
struct remove_extent<T[]> { typedef T type; };

template<class T, std::size_t N>
struct remove_extent<T[N]> { typedef T type; };

示例

#include <iostream>
#include <iterator>
#include <algorithm>
#include <type_traits>

template<class A>
typename std::enable_if< std::rank<A>::value == 1 >::type
print_1d(const A& a)
{
    copy(a, a+std::extent<A>::value,
         std::ostream_iterator<typename std::remove_extent<A>::type>(std::cout, " "));
    std::cout << '\n';
}

int main()
{
    int a[][3] = {{1,2,3},{4,5,6}};
//  print_1d(a); // 编译时错误
    print_1d(a[1]);
}

输出：

4 5 6

参阅

is_array (C++11) | 检查类型是否是数组类型 (类模板)
rank (C++11) | 获取数组类型的维数 (类模板)
extent (C++11) | 获取数组类型在指定维度的大小 (类模板)
remove_all_extents (C++11) | 移除给定数组类型的所有维度 (类模板)


std::remove_pointer

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct remove_pointer; | (C++11 起)

提供成员 typedef type ，其为 T 所指向的类型，或若 T 不是指针，则 type 与 T 相同。

添加 remove_pointer 的特化的程序行为未定义。

成员类型

名称 | 定义
type | T 所指向的类型，或若 T 不是指针则为 T

辅助类型

template< class T > using remove_pointer_t = typename remove_pointer<T>::type; | (C++14 起)

可能的实现

template< class T > struct remove_pointer                    {typedef T type;};
template< class T > struct remove_pointer<T*>                {typedef T type;};
template< class T > struct remove_pointer<T* const>          {typedef T type;};
template< class T > struct remove_pointer<T* volatile>       {typedef T type;};
template< class T > struct remove_pointer<T* const volatile> {typedef T type;};

示例

#include <iostream>
#include <type_traits>

template<class T1, class T2>
void print_is_same()
{
    std::cout << std::is_same<T1, T2>() << '\n';
}

void print_separator()
{
    std::cout << "-----\n";
}

int main()
{
    std::cout << std::boolalpha;

    print_is_same<int, int>();   // true
    print_is_same<int, int*>();  // false
    print_is_same<int, int**>(); // false

    print_separator();

    print_is_same<int, std::remove_pointer<int>::type>();   // true
    print_is_same<int, std::remove_pointer<int*>::type>();  // true
    print_is_same<int, std::remove_pointer<int**>::type>(); // false

    print_separator();

    print_is_same<int, std::remove_pointer<int* const>::type>();          // true
    print_is_same<int, std::remove_pointer<int* volatile>::type>();       // true
    print_is_same<int, std::remove_pointer<int* const volatile>::type>(); // true
}

输出：

true
false
false
-----
true
true
false
-----
true
true
true

参阅

is_pointer (C++11) | 检查类型是否为指针类型 (类模板)
add_pointer (C++11) | 对给定类型添加一层指针 (类模板)


std::remove_reference

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct remove_reference; | (C++11 起)

若类型 T 为引用类型，则提供成员 typedef type ，其为 T 所引用的类型。否则 type 为 T 。

添加 remove_reference 的特化的程序行为未定义。

成员类型

名称 | 定义
type | T 所引用的类型，或若 T 不是引用则为 T

辅助类型

template< class T > using remove_reference_t = typename remove_reference<T>::type; | (C++14 起)

可能的实现

template< class T > struct remove_reference      {typedef T type;};
template< class T > struct remove_reference<T&>  {typedef T type;};
template< class T > struct remove_reference<T&&> {typedef T type;};

示例

#include <iostream> // std::cout
#include <type_traits> // std::is_same

template<class T1, class T2>
void print_is_same() {
  std::cout << std::is_same<T1, T2>() << '\n';
}

int main() {
  std::cout << std::boolalpha;

  print_is_same<int, int>();
  print_is_same<int, int &>();
  print_is_same<int, int &&>();

  print_is_same<int, std::remove_reference<int>::type>();
  print_is_same<int, std::remove_reference<int &>::type>();
  print_is_same<int, std::remove_reference<int &&>::type>();
}

输出：

true
false
false
true
true
true

参阅

is_reference (C++11) | 检查类型是否为左值引用或右值引用 (类模板)
add_lvalue_referenceadd_rvalue_reference (C++11)(C++11) | 向给定类型添加左值或右值引用 (类模板)
remove_cvref (C++20) | 将 std::remove_cv 与 std::remove_reference 结合 (类模板)


std::result_of, std::invoke_result

< cpp‎ | types
定义于头文件 <type_traits> |  |
template< class > class result_of; // 不定义 template< class F, class... ArgTypes > class result_of<F(ArgTypes...)>; | (1) | (C++11 起) (C++17 中弃用) (C++20 中移除)
template< class F, class... ArgTypes> class invoke_result; | (2) | (C++17 起)

在编译时推导 INVOKE 表达式的返回类型。

F 必须是可调用类型、到函数引用或到可调用类型的引用。以 ArgTypes... 调用 F 必须是良构表达式。 | (C++11 起) (C++14 前)
F 和 ArgTypes 中的所有类型可以是任何完整类型、未知边界数组或（可有 cv 限定的） void | (C++14 起)

添加此页面上描述的任何模板的特化的程序行为未定义。

成员类型

成员类型 | 定义
type | 若以参数 ArgTypes... 调用可调用 (Callable) 类型 F 的返回类型。仅若 F 能以参数 ArgTypes... 在不求值语境中调用才得到定义。 (C++14 起)

辅助类型

template< class T > using result_of_t = typename result_of<T>::type; | (1) | (C++14 起) (C++17 中弃用) (C++20 中移除)
template< class F, class... ArgTypes> using invoke_result_t = typename invoke_result<F, ArgTypes...>::type; | (2) | (C++17 起)

可能的实现

namespace detail {
template <class T>
struct is_reference_wrapper : std::false_type {};
template <class U>
struct is_reference_wrapper<std::reference_wrapper<U>> : std::true_type {};

template <class Base, class T, class Derived, class... Args>
auto INVOKE(T Base::*pmf, Derived&& ref, Args&&... args)
 -> typename std::enable_if<std::is_function<T>::value &&
                     std::is_base_of<Base, typename std::decay<Derived>::type>::value,
    decltype((std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...))>::type;

template <class Base, class T, class RefWrap, class... Args>
auto INVOKE(T Base::*pmf, RefWrap&& ref, Args&&... args)
 -> typename std::enable_if<std::is_function<T>::value &&
                     is_reference_wrapper<typename std::decay<RefWrap>::type>::value,
    decltype((ref.get().*pmf)(std::forward<Args>(args)...))>::type;

template <class Base, class T, class Pointer, class... Args>
auto INVOKE(T Base::*pmf, Pointer&& ptr, Args&&... args)
 -> typename std::enable_if<std::is_function<T>::value &&
                     !is_reference_wrapper<typename std::decay<Pointer>::type>::value &&
                     !std::is_base_of<Base, typename std::decay<Pointer>::type>::value,
    decltype(((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...))>::type;

template <class Base, class T, class Derived>
auto INVOKE(T Base::*pmd, Derived&& ref)
 -> typename std::enable_if<!std::is_function<T>::value &&
                     std::is_base_of<Base, typename std::decay<Derived>::type>::value,
    decltype(std::forward<Derived>(ref).*pmd)>::type;

template <class Base, class T, class RefWrap>
auto INVOKE(T Base::*pmd, RefWrap&& ref)
 -> typename std::enable_if<!std::is_function<T>::value &&
                     is_reference_wrapper<typename std::decay<RefWrap>::type>::value,
    decltype(ref.get().*pmd)>::type;

template <class Base, class T, class Pointer>
auto INVOKE(T Base::*pmd, Pointer&& ptr)
 -> typename std::enable_if<!std::is_function<T>::value &&
                     !is_reference_wrapper<typename std::decay<Pointer>::type>::value &&
                     !std::is_base_of<Base, typename std::decay<Pointer>::type>::value,
    decltype((*std::forward<Pointer>(ptr)).*pmd)>::type;

template <class F, class... Args>
auto INVOKE(F&& f, Args&&... args)
 -> typename std::enable_if<!std::is_member_pointer<typename std::decay<F>::type>::value,
    decltype(std::forward<F>(f)(std::forward<Args>(args)...))>::type;
} // namespace detail

// 最小 C++11 实现：
template <class> struct result_of;
template <class F, class... ArgTypes>
struct result_of<F(ArgTypes...)> {
    using type = decltype(detail::INVOKE(std::declval<F>(), std::declval<ArgTypes>()...));
};

// 符合 C++14 的实现（亦为合法的 C++11 实现）：
namespace detail {
template <typename AlwaysVoid, typename, typename...>
struct invoke_result { };
template <typename F, typename...Args>
struct invoke_result<decltype(void(detail::INVOKE(std::declval<F>(), std::declval<Args>()...))),
                 F, Args...> {
    using type = decltype(detail::INVOKE(std::declval<F>(), std::declval<Args>()...));
};
} // namespace detail

template <class> struct result_of;
template <class F, class... ArgTypes>
struct result_of<F(ArgTypes...)> : detail::invoke_result<void, F, ArgTypes...> {};

template <class F, class... ArgTypes>
struct invoke_result : detail::invoke_result<void, F, ArgTypes...> {};

注解

在 C++11 中规范时， std::result_of 的行为在 INVOKE(std::declval<F>(), std::declval<ArgTypes>()...) 为病式时（例如 F 完全不可调用时）未定义。 C++14 更改为 SFINAE （ F 不可调用时， std::result_of<F(ArgTypes...)> 简单地无 type 成员）。

std::result_of 后的动机是确定调用可调用 (Callable) 类型的结果，尤其是结果类型对不同参数集不同的情况。

F(Args...) 是以 Args... 为参数而以 F 为返回类型的函数类型。因而， std::result_of 承受了许多怪异，导致它在 C++17 中被 std::invoke_result 取代而被弃用：

  • F 不能是函数类型或数组类型（但能是到它们的引用）；
  • 若任何 Args 拥有“ T 的数组”类型或函数类型 T ，则它被自动调整为 T* ；
  • F 或任何 Args... 都不能是抽象类类型；
  • 若任何 Args... 拥有顶层 cv 限定符，则舍弃之；
  • Args... 均不可为 void 。

为避免这些怪异，常以 F 和 Args... 的引用类型使用 result_of 。例如：

template<class F, class... Args>
std::result_of_t<F&&(Args&&...)> // 替代错误的 std::result_of_t<F(Args...)>
  my_invoke(F&& f, Args&&... args) {
    /* implementation */
}

示例

#include <type_traits>
#include <iostream>

struct S {
    double operator()(char, int&);
    float operator()(int) { return 1.0;}
};

template<class T>
typename std::result_of<T(int)>::type f(T& t)
{
    std::cout << "overload of f for callable T\n";
    return t(0);
}

template<class T, class U>
int f(U u)
{
    std::cout << "overload of f for non-callable T\n";
    return u;
}

int main()
{
    // 以 char 和 int 参数调用 S 的结果是 double
    std::result_of<S(char, int&)>::type d = 3.14; // d 拥有 double 类型
    static_assert(std::is_same<decltype(d), double>::value, "");

    // 以 int 参数调用 S 的结果是 float
    std::result_of<S(int)>::type x = 3.14; // x 拥有 float 类型
    static_assert(std::is_same<decltype(x), float>::value, "");

    // result_of 能以指向成员函数的指针以如下方式使用
    struct C { double Func(char, int&); };
    std::result_of<decltype(&C::Func)(C, char, int&)>::type g = 3.14;
    static_assert(std::is_same<decltype(g), double>::value, "");

    f<C>(1); // C++11 中可能编译失败； C++14 中调用不可调用重载
}

输出：

overload of f for non-callable T

参阅

invokeinvoke_r (C++17)(C++23) | 以给定实参和可能指定的返回类型 (C++23 起)调用任意可调用 (Callable) 对象 (函数模板)
is_invocableis_invocable_ris_nothrow_invocableis_nothrow_invocable_r (C++17) | 检查类型能否以给定的实参类型调用（如同以 std::invoke） (类模板)
declval (C++11) | 获取到其实参的引用，用于不求值语境中 (函数模板)


std::size_t

< cpp‎ | types
定义于头文件 <cstddef> |
定义于头文件 <cstdio> |
定义于头文件 <cstdlib> |
定义于头文件 <cstring> |
定义于头文件 <ctime> |
定义于头文件 <cuchar> | (C++17 起)
定义于头文件 <cwchar> |
typedef /*implementation-defined*/ size_t; |

std::size_t 是 sizeof 运算符还有 sizeof... 运算符和 alignof 运算符 (C++11 起)所返回的无符号整数类型。

std::size_t 的位宽不小于 16 。

 (C++11 起)

注解

std::size_t 可以存放下理论上可能存在的对象的最大大小，该对象可以是任何类型，包括数组。大小无法以 std::size_t 表示的类型是非良构的。 (C++14 起)在许多平台上（使用分段寻址的系统除外），std::size_t 可以存放下任何非成员的指针，此时可以视作其与 std::uintptr_t 同义。

std::size_t 通常被用于数组索引和循环计数。使用其它类型来进行数组索引操作的程序可能会在某些情况下出错，例如在 64 位系统中使用 unsigned int 进行索引时，如果索引号超过 UINT_MAX 或者依赖于 32 位取模运算的话，程序就会出错。

在对诸如 std::string、std::vector 等 C++ 容器进行索引操作时，正确的类型是该容器的成员 typedef size_type，而该类型通常被定义为与 std::size_t 相同。

示例

#include <cstddef>
#include <iostream>

int main()
{
    const std::size_t N = 10;
    int* a = new int[N];

    for (std::size_t n = 0; n < N; ++n)
        a[n] = n;
    for (std::size_t n = N; n-- > 0;) // 对于无符号类型的逆向循环技巧。
        std::cout << a[n] << " ";

    delete[] a;
}

输出：

9 8 7 6 5 4 3 2 1 0

参阅

ptrdiff_t | 在两个指针相减时返回的有符号整数类型 (typedef)
offsetof | 从标准布局类型的起始到其指定成员的字节偏移量 (宏函数)


std::type_identity

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct type_identity; | (C++20 起)

提供指名 T 的成员 typedef type （即恒等变换）。

添加 type_identity 的特化的程序行为未定义。

成员类型

名称 | 定义
type | T

辅助类型

template< class T > using type_identity_t = typename type_identity<T>::type; | (C++20 起)

可能的实现

template< class T >
struct type_identity {
    using type = T;
};

注解

type_identity 能用于在模板实参推导中建立非推导语境：

template<class T>
void f(T, T);

template<class T>
void g(T, std::type_identity_t<T>);

f(4.2, 0); // 错误：对 'T' 推导出冲突的类型
g(4.2, 0); // OK ：调用 g<double>

示例

#include <iostream>
#include <type_traits>

template <class T>
T foo(T a, T b) {
  return a + b;
}

template <class T>
T bar(T a, std::type_identity_t<T> b) {
  return a + b;
}

int main() {
  // foo(4.2, 1);                    // 错误：对 'T' 推导的类型冲突
  std::cout << bar(4.2, 1) << '\n';  // OK ：调用 bar<double>
}

输出：

5.2


std::type_index

< cpp‎ | types
定义于头文件 <typeindex> |
class type_index; | (C++11 起)

type_index 类是一个围绕 std::type_info 的包装类，它可用作关联与无序关联容器的索引。它与 type_info 对象的关系通过一个指针维系，故而 type_index 为可复制构造 (CopyConstructible) 且为可复制赋值 (CopyAssignable) 。

成员函数

(构造函数) | 构造对象 (公开成员函数)
(析构函数) (隐式声明) | 销毁 type_index 对象 (公开成员函数)
operator= (隐式声明) | 对 type_index 对象赋值 (公开成员函数)
operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20) | 比较底层 std::type_info 对象 (公开成员函数)
hash_code | 返回哈希码 (公开成员函数)
name | 返回关联到底层 type_info 对象的实现定义名称 (公开成员函数)

辅助类

std::hash<std::type_index>
(C++11)
 std::type_index 的散列支持
(类模板特化)

示例

下面的程序是一个有效的类型-值映射的示例。

#include <iostream>
#include <typeinfo>
#include <typeindex>
#include <unordered_map>
#include <string>
#include <memory>

struct A {
    virtual ~A() {}
};

struct B : A {};
struct C : A {};

int main()
{
    std::unordered_map<std::type_index, std::string> type_names;

    type_names[std::type_index(typeid(int))] = "int";
    type_names[std::type_index(typeid(double))] = "double";
    type_names[std::type_index(typeid(A))] = "A";
    type_names[std::type_index(typeid(B))] = "B";
    type_names[std::type_index(typeid(C))] = "C";

    int i;
    double d;
    A a;

    // 注意我们正在存储指向类型 A 的指针
    std::unique_ptr<A> b(new B);
    std::unique_ptr<A> c(new C);

    std::cout << "i is " << type_names[std::type_index(typeid(i))] << '\n';
    std::cout << "d is " << type_names[std::type_index(typeid(d))] << '\n';
    std::cout << "a is " << type_names[std::type_index(typeid(a))] << '\n';
    std::cout << "b is " << type_names[std::type_index(typeid(*b))] << '\n';
    std::cout << "c is " << type_names[std::type_index(typeid(*c))] << '\n';
}

输出：

i is int
d is double
a is A
b is B
c is C

参阅

type_info
 含有某个类型的信息，由实现生成。
这是 typeid 运算符所返回的类。
(类)


std::hash<std::type_index>

< cpp‎ | types‎ | type index
定义于头文件 <typeindex> |
template<> struct hash<type_index>; | (C++11 起)

std::hash 对 std::type_index 的模板特化允许用户获得 std::type_index 类型对象的哈希。

成员 operator() 等效地返回与 hash_code() 相同的值。

参阅

hash_code
 返回哈希码
(公开成员函数)


std::type_index::hash_code

< cpp‎ | types‎ | type index
std::size_t hash_code() const noexcept; | (C++11 起)

返回关联的 std::type_info 对象的散列码。等价于直接调用 type_info::hash_code 。

参数

（无）

返回值

关联的 std::type_info 对象的散列码。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2144 | C++11 | 未要求 type_index::hash_code 为 noexcept | 已要求

参阅

std::hash<std::type_index>
(C++11)
 std::type_index 的散列支持
(类模板特化)


std::type_index::name

< cpp‎ | types‎ | type index
const char* name() const noexcept; | (C++11 起)

返回关联的 std::type_info 对象名称。等价于直接调用 std::type_info::name() 。

参数

（无）

返回值

关联的 std::type_info 对象名称。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2144 | C++11 | 未要求 type_index::name 为 noexcept | 已要求


std::type_index::operator==,!=,<,<=,>,>=,<=>

< cpp‎ | types‎ | type index
bool operator==( const type_index& rhs ) const noexcept; | (1) | (C++11 起)
bool operator!=( const type_index& rhs ) const noexcept; | (2) | (C++11 起) (C++20 前)
bool operator<( const type_index& rhs ) const noexcept; | (3) | (C++11 起)
bool operator<=( const type_index& rhs ) const noexcept; | (4) | (C++11 起)
bool operator>( const type_index& rhs ) const noexcept; | (5) | (C++11 起)
bool operator>=( const type_index& rhs ) const noexcept; | (6) | (C++11 起)
std::strong_ordering operator<=>( const type_index& rhs ) const noexcept; | (7) | (C++20 起)

比较底层 std::type_info 对象。

1-2) 检查底层的 std::type_info对象是否表示同一类型。
3-7) 按实现定义顺序的定义，比较底层 std::type_info 对象。比较由 type_info::before 执行。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

rhs - 要比较的另一 type_index 对象

返回值

1) 若底层 std::type_info 对象表示同一类型则为 true ，否则为 false 。
2) 若底层 std::type_info 对象不表示同一类型则为 true ，否则为 false 。
3-6) 若底层 std::type_info 所表示的类型按对应顺序排列，则为 true ，否则为 false 。
7) 若底层 std::type_info 对象表示同一类型则为 std::strong_ordering::equal ，否则若 *this 的底层 std::type_info 对象在实现定义顺序中前趋 rhs 的则为 std::strong_ordering::less ，否则为 std::strong_ordering::greater 。


std::type_index::type_index

< cpp‎ | types‎ | type index
type_index( const std::type_info & info ) noexcept; | (C++11 起)

从 std::type_info 对象构造 type_index。

参数

info - type_info 对象

示例

本节未完成
原因：暂无示例


std::type_info

< cpp‎ | types
定义于头文件 <typeinfo>
class type_info;

类 type_info 保有一个类型的实现指定信息，包括类型的名称和比较二个类型相等的方法或相对顺序。这是 typeid 运算符所返回的类。

type_info 既不满足可复制构造 (CopyConstructible) 也不满足可复制赋值 (CopyAssignable) 。

成员函数

(构造函数) [被删除] | 无默认或复制构造函数 (公开成员函数)
(析构函数) [虚] | 虚析构函数使 type_info 为多态类 (虚公开成员函数)
operator= [被删除] | 不能复制赋值 (公开成员函数)
operator==operator!= (C++20 中移除) | 检查对象是否指代相同类型 (公开成员函数)
before | 检查在实现定义的顺序中，被指代类型是否在另一个 type_info 对象之前，即对被指代类型排序 (公开成员函数)
hash_code (C++11) | 返回对于同一类型相同的值 (公开成员函数)
name | 类型的实现定义名称 (公开成员函数)

参阅

type_index
(C++11)
 针对 type_info 对象的包装，它能用作关联容器和无序关联容器的索引。
(类)


std::type_info::before

< cpp‎ | types‎ | type info
bool before( const type_info& rhs ) const; | (C++11 前)
bool before( const type_info& rhs ) const noexcept; | (C++11 起)

若此 type_info 的类型在实现的对照顺序中列于 rhs 的类型之前则返回 true 。不给出保证，特别是对照顺序可以在同一程序的调用之间改变。

参数

rhs - 要比较的另一个类型信息对象

返回值

若此 type_info 的类型在实现的对照顺序中列于 rhs 的类型之前则为 true 。

示例

#include <iostream>
#include <typeinfo>

int main()
{
    if(typeid(int).before(typeid(char)))
        std::cout << "int goes before char in this implementation.\n";
    else
        std::cout << "char goes before int in this implementation.\n";
}

可能的输出：

char goes before int in this implementation.

参阅

operator==operator!=
(C++20 中移除)
 检查对象是否指代相同类型
(公开成员函数)


std::type_info::hash_code

< cpp‎ | types‎ | type info
std::size_t hash_code() const noexcept; | (C++11 起)

返回未指定值，使得指代同一类型的所有 type_info 对象的 hash_code() 相同。

不给出其他保证：指代不同类型的 type_info 对象可以拥有相同的 hash_code （尽管标准推荐实现尽可能避免这点），而同一类型的 hash_code 可在相同程序的各次不同调用间改变。

参数

（无）

返回值

对所有指代同一类型的 type_info 对象等同的值。

示例

下列程序是一个有效的不使用 std::type_index 的类型值映射示例。

#include <iostream>
#include <typeinfo>
#include <unordered_map>
#include <string>
#include <functional>
#include <memory>

struct A {
    virtual ~A() {}
};

struct B : A {};
struct C : A {};

using TypeInfoRef = std::reference_wrapper<const std::type_info>;

struct Hasher {
    std::size_t operator()(TypeInfoRef code) const
    {
        return code.get().hash_code();
    }
};

struct EqualTo {
    bool operator()(TypeInfoRef lhs, TypeInfoRef rhs) const
    {
        return lhs.get() == rhs.get();
    }
};

int main()
{
    std::unordered_map<TypeInfoRef, std::string, Hasher, EqualTo> type_names;

    type_names[typeid(int)] = "int";
    type_names[typeid(double)] = "double";
    type_names[typeid(A)] = "A";
    type_names[typeid(B)] = "B";
    type_names[typeid(C)] = "C";

    int i;
    double d;
    A a;

    // 注意我们存储指向 A 的指针
    std::unique_ptr<A> b(new B);
    std::unique_ptr<A> c(new C);

    std::cout << "i is " << type_names[typeid(i)] << '\n';
    std::cout << "d is " << type_names[typeid(d)] << '\n';
    std::cout << "a is " << type_names[typeid(a)] << '\n';
    std::cout << "b is " << type_names[typeid(*b)] << '\n';
    std::cout << "c is " << type_names[typeid(*c)] << '\n';
}

输出：

i is int
d is double
a is A
b is B
c is C

参阅

operator==operator!= (C++20 中移除) | 检查对象是否指代相同类型 (公开成员函数)
name | 类型的实现定义名称 (公开成员函数)


std::type_info::name

< cpp‎ | types‎ | type info
const char* name() const; | (C++11 前)
const char* name() const noexcept; | (C++11 起)

返回实现定义的，含有类型名称的空终止字符串。不给出保证，尤其是返回的字符串对于数个类型可以相同，而且在同一程序的调用之间改变。

参数

（无）

返回值

含有类型名称的空终止字符串。

注意

返回指针所指向的数组的生存期未指定，但实践中只要给定类型的 RTTI 数据结构存在，它就得到保持，这拥有应用程序生存期，除非从动态库加载它（可被卸载）。

一些实现（如 MSVC 、 IBM 、 Oracle ）生成人类可读的类型名。其他的，最值得注意的是 gcc 与 clang ，返回重整名，这是由 Itanium C++ ABI 指定的。重整名可以用实现指定的 API 转换到人类可读的形式，例如直接用 abi::__cxa_demangle 或通过 boost::core::demangle 。它亦可通过命令行工具 c++filt -t 输送往管道。

示例

#include <iostream>
#include <typeinfo>

struct Base { virtual ~Base() = default; };
struct Derived : Base {};

int main() {
        Base b1;
        Derived d1;

        const Base *pb = &b1;
        std::cout << typeid(*pb).name() << '\n';
        pb = &d1;
        std::cout << typeid(*pb).name() << '\n';
}

可能的输出：

4Base
7Derived

参阅

hash_code
(C++11)
 返回对于同一类型相同的值
(公开成员函数)


std::type_info::operator==, std::type_info::operator!=

< cpp‎ | types‎ | type info
bool operator==( const type_info& rhs ) const; | (C++11 前)
bool operator==( const type_info& rhs ) const noexcept; | (C++11 起) (C++23 前)
constexpr bool operator==( const type_info& rhs ) const noexcept; | (C++23 起)
bool operator!=( const type_info& rhs ) const; | (C++11 前)
bool operator!=( const type_info& rhs ) const noexcept; | (C++11 起) (C++20 前)

检查对象是否指代相同类型。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

rhs - 要比较的另一个类型信息对象

返回值

若比较关系成立则为 true ，否则为 false

示例

#include <iostream>
#include <typeinfo>
#include <string>
#include <utility>

class person
{
  public:

   person(std::string n) : _name(std::move(n)) {}
   virtual const std::string& name() const{ return _name; }

  private:

    std::string _name;
};

class employee : public person
{
   public:

     employee(std::string n, std::string p) :
         person(std::move(n)), _profession(std::move(p)) {}

     const std::string& profession() const { return _profession; }

   private:

     std::string _profession;
};

void somefunc(const person& p)
{
   if(typeid(person) == typeid(p))
   {
      std::cout << p.name() << " is not an employee\n";
   }
   else if(typeid(employee) == typeid(p))
   {
      std::cout << p.name() << " is an employee ";
      auto& emp = dynamic_cast<const employee&>(p);
      std::cout << "who works in " << emp.profession() << '\n';
   }
}
int main()
{
   somefunc(employee{"Paul","Economics"});
   somefunc(person{"Kate"});

#  if defined(__cpp_lib_constexpr_typeinfo) // C++23
   if constexpr (typeid(employee) != typeid(person)) {
      std::cout << "class `employee` != class `person`\n";
   }
#  endif
}

输出：

Paul is an employee who works in Economics
Kate is not an employee

参阅

before
 检查在实现定义的顺序中，被指代类型是否在另一个 type_info 对象之前，即对被指代类型排序
(公开成员函数)


std::type_info::~type_info

< cpp‎ | types‎ | type info
virtual ~type_info();

销毁 std::type_info 类型对象。此构造函数为公开虚，使得 std::type_info 为多态类。

注解

std::type_info 对象的动态类型可以由 typeid 运算符检验。

实现在程序结束时是否对任何 std::type_info 调用此析构函数是未指定的。


std::underlying_type

< cpp‎ | types
定义于头文件 <type_traits> |
template< class T > struct underlying_type; | (C++11 起)

若 T 是完整枚举类型，则提供指名 T 底层类型的成员 typedef type 。

否则，行为未定义。 | (C++20 前)
否则，若 T 不是枚举类型，则无成员 type 。否则（ T 为不完整枚举类型）程序为谬构。 | (C++20 起)

添加 underlying_type 的特化的程序行为未定义。

成员类型

名称 | 定义
type | T 的底层类型

辅助类型

template< class T > using underlying_type_t = typename underlying_type<T>::type; | (C++14 起)

注解

每个枚举类型都拥有底层类型，它可以是

1. 显式指定（有作用域和无作用域枚举均可）

2. 省略，该情况下对于有作用域枚举是 int ，或（对于无作用域枚举）是足以表示枚举所有值的实现定义的整数类型

示例

#include <iostream>
#include <type_traits>

enum e1 {};
enum class e2 {};
enum class e3: unsigned {};
enum class e4: int {};

int main() {

  constexpr bool e1_t = std::is_same_v< std::underlying_type_t<e1>, int >;
  constexpr bool e2_t = std::is_same_v< std::underlying_type_t<e2>, int >;
  constexpr bool e3_t = std::is_same_v< std::underlying_type_t<e3>, int >;
  constexpr bool e4_t = std::is_same_v< std::underlying_type_t<e4>, int >;

  std::cout
    << "underlying type for 'e1' is " << (e1_t ? "int" : "non-int") << '\n'
    << "underlying type for 'e2' is " << (e2_t ? "int" : "non-int") << '\n'
    << "underlying type for 'e3' is " << (e3_t ? "int" : "non-int") << '\n'
    << "underlying type for 'e4' is " << (e4_t ? "int" : "non-int") << '\n'
    ;
}

可能的输出：

underlying type for 'e1' is non-int
underlying type for 'e2' is int
underlying type for 'e3' is non-int
underlying type for 'e4' is int

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2396 | C++11 | 允许不完整枚举类型 | 要求完整枚举类型

参阅

to_underlying
(C++23)
 转换枚举到其底层类型
(函数模板)


std::void_t

< cpp‎ | types
定义于头文件 <type_traits> |
template< class... > using void_t = void; | (C++17 起)

将任意类型的序列映射到类型 void 的工具元函数。

注解

模板元编程中，用此元函数检测 SFINAE 语境中的非良构类型：

// 主模板处理无嵌套 ::type 成员的类型：
template< class, class = void >
struct has_type_member : std::false_type { };

// 特化识别拥有嵌套 ::type 成员的类型：
template< class T >
struct has_type_member<T, std::void_t<typename T::type>> : std::true_type { };

它亦可用于检测表达式的合法性：

// 主模板处理不支持前置自增的类型：
template< class, class = void >
struct has_pre_increment_member : std::false_type { };
// 特化识别支持前置自增的类型：
template< class T >
struct has_pre_increment_member<T,
           std::void_t<decltype( ++std::declval<T&>() )>
       > : std::true_type { };

直至 CWG 1558 （ C++11 缺陷）前，别名模板中未使用的参数不保证 SFINAE 且可被忽略，故早期编译器要求 void_t 的更复杂定义，例如：

template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;

示例

#include <iostream>
#include <type_traits>
#include <vector>
#include <map>

class A {};

template <typename T, typename = void>
struct is_iterable : std::false_type {};
template <typename T>
struct is_iterable<T, std::void_t<decltype(std::declval<T>().begin()),
                                  decltype(std::declval<T>().end())>>
    : std::true_type {};

// 迭代器特性，其 value_type 始终为被迭代容器的 value_type ，
// 即使用 value_type 为 void 的 back_insert_iterator

template <typename T, typename = void>
struct iterator_trait
: std::iterator_traits<T> {};
template <typename T>
struct iterator_trait<T, std::void_t<typename T::container_type>>
: std::iterator_traits<typename T::container_type::iterator> {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << is_iterable<std::vector<double>>::value << '\n';
    std::cout << is_iterable<std::map<int, double>>::value << '\n';
    std::cout << is_iterable<double>::value << '\n';
    std::cout << is_iterable<A>::value << '\n';

    std::vector<int> v;

    std::cout << std::is_same<iterator_trait<decltype(std::back_inserter(v))>::value_type
    , iterator_trait<decltype(v.cbegin())>::value_type >::value << '\n';
}

输出：

true
true
false
false
true

参阅

enable_if
(C++11)
 条件性地从重载决议移除函数重载或模板特化
(类模板)


工具库

< cpp

C++ 包含了各种工具库，提供了诸如位计数和部分函数应用的功能。这些库大致可以分为两类：

  • 语言支持库
  • 通用库

语言支持

语言支持库中所提供的类和函数与语言特性紧密相关，用以支持语言中的一些常见的惯用法。

类型支持

基本类型（如 std::size_t 、 std::nullptr_t ）、 RTTI （如 std::type_info ）、类型特性（如 std::is_integral 、 std::rank ）。

实现属性

头文件 <version> 提供关于 C++ 标准库的实现依赖信息（例如版本号和发行日期）。它亦定义特性测试宏。

 (C++20 起)

程序工具

终止（如 std::abort 、 std::atexit ）、环境（如 std::system ）、信号（如 std::raise ）。

动态内存管理

智能指针（如 std::shared_ptr ）、分配器（如 std::allocator 或 std::pmr::memory_resource ）、C 风格内存管理（如 std::malloc ）。

对象访问

定义于头文件 <new>
launder
(C++17)
 指针优化屏障
(函数模板)

错误处理

异常（如 std::exception、std::terminate ）、断言（如 assert ）。

源码信息捕获

定义于头文件 <source_location>
source_location
(C++20)
 表示关于源码的信息，例如文件名、行号以及函数名的类
(类)

初始化器列表

定义于头文件 <initializer_list>
initializer_list
(C++11)
 在列表初始化中创建临时数组然后引用它
(类模板)

三路比较

定义于头文件 <compare>
three_way_comparablethree_way_comparable_with (C++20) | 指定运算符 <=> 在给定类型上产生一致的结果 (概念)
partial_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符，不可替换，并允许不可比较的值 (类)
weak_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符且不可替换 (类)
strong_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符且可替换 (类)
is_eqis_neqis_ltis_lteqis_gtis_gteq (C++20) | 具名比较函数 (函数)
compare_three_way (C++20) | 实现 x <=> y 的函数对象 (类)
compare_three_way_result (C++20) | 获得三路比较运算符 <=> 在给定类型上的结果 (类模板)
common_comparison_category (C++20) | 给定的全部类型都能转换到的最强比较类别 (类模板)
strong_order (C++20) | 进行三路比较并产生 std::strong_ordering 类型结果 (定制点对象)
weak_order (C++20) | 进行三路比较并产生 std::weak_ordering 类型结果 (定制点对象)
partial_order (C++20) | 进行三路比较并产生 std::partial_ordering 类型结果 (定制点对象)
compare_strong_order_fallback (C++20) | 进行三路比较并产生 std::strong_ordering 类型的结果，即使 operator<=> 不可用 (定制点对象)
compare_weak_order_fallback (C++20) | 进行三路比较并产生 std::weak_ordering 类型的结果，即使 operator<=> 不可用 (定制点对象)
compare_partial_order_fallback (C++20) | 进行三路比较并产生 std::partial_ordering 类型的结果，即使 operator<=> 不可用 (定制点对象)

协程支持

用于协程支持的类型，例如 std::coroutine_traits、 std::coroutine_handle。

 (C++20 起)

变参数函数

支持接受任意数量参数的函数（例如通过 va_start 、 va_arg 、 va_end ）。

通用工具

swap 与类型运算

定义于头文件 <utility>
swap | 交换两个对象的值 (函数模板)
exchange (C++14) | 将实参替换为一个新值，并返回其先前值 (函数模板)
forward (C++11) | 转发一个函数实参 (函数模板)
move (C++11) | 获得右值引用 (函数模板)
move_if_noexcept (C++11) | 若移动构造函数不抛出则获得右值引用 (函数模板)
as_const (C++17) | 获得到其实参的 const 引用 (函数模板)
declval (C++11) | 获取到其实参的引用，用于不求值语境中 (函数模板)
to_underlying (C++23) | 转换枚举到其底层类型 (函数模板)
定义于头文件 <concepts>
ranges::swap (C++20) | 交换两个对象的值 (定制点对象)

整数比较函数

定义于头文件 <utility>
cmp_equalcmp_not_equalcmp_lesscmp_greatercmp_less_equalcmp_greater_equal (C++20) | 比较二个整数值，而无转换所致的值更改 (函数模板)
in_range (C++20) | 检查整数值是否在给定整数类型的范围内 (函数模板)

关系运算符

定义于头文件 <utility>
定义于命名空间 std::rel_ops
operator!=operator>operator<=operator>=
(C++20 中弃用)
 自动生成基于用户定义的 operator== 和 operator< 的比较运算符
(函数模板)

对与元组

定义于头文件 <utility>
pair | 实现二元组，即一对值 (类模板)
piecewise_construct_t (C++11) | 用于为逐段构造选择正确函数重载的标签类型 (类)
piecewise_construct (C++11) | 用于为逐段构造的函数消歧义的 piecewise_construct_t 类型的对象 (常量)
integer_sequence (C++14) | 实现编译时整数数列 (类模板)
定义于头文件 <tuple>
tuple (C++11) | 实现固定大小的容器，它保有类型可以相异的元素 (类模板)
apply (C++17) | 以一个实参的元组来调用函数 (函数模板)
make_from_tuple (C++17) | 以一个实参元组构造对象 (函数模板)
定义于头文件 <tuple>
定义于头文件 <utility>
定义于头文件 <array>
定义于头文件 <ranges>
tuple_size (C++11) | 获得元组式类型的元素数 (类模板)
tuple_element (C++11) | 获得元组式类型的元素类型 (类模板)

optional 、 variant 与 any

定义于头文件 <optional>
optional (C++17) | 可能或可能不保有一个对象的包装器 (类模板)
定义于头文件 <variant>
variant (C++17) | 类型安全的可辨识联合体 (类模板)
定义于头文件 <any>
any (C++17) | 可保有任何可复制构造 (CopyConstructible) 类型的实例的对象。 (类)
定义于头文件 <utility>
in_place in_place_type in_place_index in_place_t in_place_type_t in_place_index_t (C++17) | 原位构造标签 (类模板)

位集合

定义于头文件 <bitset>
bitset
 实现常量长度的位数组
(类模板)

函数对象

部分函数应用（如 std::bind ）及相关工具：用于绑定的工具，如 std::ref 与 std::placeholders 、多态函数包装器： std::function 、预定义函数对象（如 std::plus 、 std::equal_to ）、方法到函数转换器 std::mem_fn 。

散列支持

定义于头文件 <functional>
hash
(C++11)
 散列函数对象
(类模板)

日期和时间

时间跟踪（如 std::chrono::time_point 、 std::chrono::duration ）， C 风格日期和时间（如 std::time 、 std::clock ）。

初等字符串转换

除了 C++ I/O 库、 C I/O 库、 C++ 字符串转换函数和 C 字符串转换函数提供的复杂的本地环境依赖的分析器和格式化器外，头文件 <charconv> 提供对于算术类型的轻量、不依赖本地环境、不分配、不抛出的分析器和格式化器。

定义于头文件 <charconv>
to_chars (C++17) | 转换整数或浮点值到字符序列 (函数)
from_chars (C++17) | 转换字符序列到整数或浮点值 (函数)
chars_format (C++17) | 指定 std::to_chars 和 std::from_chars 所用的格式 (枚举)

格式化库

类型安全的格式化设施。

定义于头文件 <format>
format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
format_to (C++20) | 通过输出迭代器写其参数的格式化表示 (函数模板)
format_to_n (C++20) | 通过输出迭代器写其参数的格式化表示，不超出指定的大小 (函数模板)
formatted_size (C++20) | 确定存储其参数的格式化表示所需的字符数 (函数模板)
vformat (C++20) | std::format 的使用类型擦除的参数表示的非模板变体 (函数)
vformat_to (C++20) | std::format_to 的使用类型擦除的参数表示的非模板变体 (函数模板)
formatter (C++20) | 定义给定类型的格式化规则的类模板 (类模板)
format_error (C++20) | 格式化错误时抛出的异常类型 (类)

栈踪

定义于头文件 <stacktrace>
stacktrace_entry (C++23) | 栈踪中求值的表示 (类)
basic_stacktrace (C++23) | 由栈踪条目组成的调用序列的近似表示 (类模板)


std::any

< cpp‎ | utility
定义于头文件 <any> |
class any; | (C++17 起)

类 any 描述用于任何类型的单个值的类型安全容器。

1) 类 any 的对象存储任何满足构造函数要求的类型的一个实例或为空，而这被称为 any 类对象的状态。存储的实例被称作所含对象。若两个状态均为空，或均为非空且其所含对象等价，则两个状态等价。
2) 非成员 any_cast 函数提供对所含对象的类型安全访问。

鼓励实现避免小对象的动态分配，但这种优化仅可以应用于 std::is_nothrow_move_constructible 对其返回 true 的类型。

成员函数

(构造函数)
 构造 any 对象
(公开成员函数)
operator=
 赋值 any 对象
(公开成员函数)
(析构函数)
 销毁 any 对象
(公开成员函数)
修改器
emplace
 更改所含对象，直接构造新对象
(公开成员函数)
reset
 销毁所含对象
(公开成员函数)
swap
 交换二个 any 对象
(公开成员函数)
观察器
has_value
 检查对象是否含有值
(公开成员函数)
type
 返回所含值的 typeid
(公开成员函数)

非成员函数

std::swap(std::any) (C++17) | 特化 std::swap 算法 (函数)
any_cast (C++17) | 对被容纳对象的类型安全访问 (函数模板)
make_any (C++17) | 创建 any 对象 (函数模板)

辅助类

bad_any_cast
(C++17)
 当类型不匹配时按值返回形式的 any_cast 所抛出的异常
(类)

示例

#include <any>
#include <iostream>

int main()
{
    std::cout << std::boolalpha;

    // any 类型
    std::any a = 1;
    std::cout << a.type().name() << ": " << std::any_cast<int>(a) << '\n';
    a = 3.14;
    std::cout << a.type().name() << ": " << std::any_cast<double>(a) << '\n';
    a = true;
    std::cout << a.type().name() << ": " << std::any_cast<bool>(a) << '\n';

    // 有误的转型
    try
    {
        a = 1;
        std::cout << std::any_cast<float>(a) << '\n';
    }
    catch (const std::bad_any_cast& e)
    {
        std::cout << e.what() << '\n';
    }

    // 拥有值
    a = 1;
    if (a.has_value())
    {
        std::cout << a.type().name() << '\n';
    }

    // 重置
    a.reset();
    if (!a.has_value())
    {
        std::cout << "no value\n";
    }

    // 指向所含数据的指针
    a = 1;
    int* i = std::any_cast<int>(&a);
    std::cout << *i << "\n";
}

可能的输出：

i: 1
d: 3.14
b: true
bad any_cast
i
no value
1

参阅

function (C++11) | 包装具有指定函数调用签名的任意可复制构造类型的可调用对象 (类模板)
variant (C++17) | 类型安全的可辨识联合体 (类模板)


std::any::any

< cpp‎ | utility‎ | any
constexpr any() noexcept;
 (1) (C++17 起)
any( const any& other );
 (2) (C++17 起)
any( any&& other ) noexcept;
 (3) (C++17 起)
template< class ValueType >
any( ValueType&& value );
 (4) (C++17 起)
template< class ValueType, class... Args >
explicit any( std::in_place_type_t <ValueType>, Args&&... args );
 (5) (C++17 起)
template< class ValueType, class U, class... Args >

explicit any( std::in_place_type_t <ValueType>, std::initializer_list <U> il,

Args&&... args );
 (6) (C++17 起)

构造新的 any 对象。

1) 构造空对象。
2-3) 复制 (2) 或移动 (3) other 的内容进新实例，从而任何内容的类型和值都等于构造函数调用前的 other 所拥有者，或者若 other 为空则内容为空。正式地说，
2) 若 other 为空，则构造的对象为空。否则，等价于 any(std::in_place_type<T>, std::any_cast <const T&>(other)) ，其中 T 是 other 中含有的对象类型。
3) 若 other 为空，则构造的对象为空，否则，构造的对象含 other 中容纳的对象，或从 other 中的对象构造的同类型对象，考虑该对象是否为右值。
4) 构造对象，其初始内容为 std::decay_t <ValueType> 类型对象，从 std::forward <ValueType>(value) 直接初始化它。
  • 此重载仅若 std::decay_t <ValueType> 既非与 any 相同类型，亦非std::in_place_type_t 的特化，且 std::is_copy_constructible_v < std::decay_t <ValueType>> 为true 才参与重载决议。
5) 构造对象，其初始内容为 std::decay_t<ValueType> 类型对象，从 std::forward <Args>(args)... 直接非列表初始化它。
  • 此重载仅若 std::is_constructible_v < std::decay_t <ValueType>, Args...> 与 std::is_copy_constructible_v < std::decay_t <ValueType>> 皆为 true 才参与重载决议。
6) 构造对象，其初始内容为 std::decay_t<ValueType> 类型对象，从 il, std::forward <Args>(args)... 直接非列表初始化它。
  • 此重载仅若 std::is_constructible_v < std::decay_t <ValueType>, std::initializer_list <U>&, Args...> 与 std::is_copy_constructible_v < std::decay_t <ValueType>> 皆为 true 才参与重载决议。

模板形参

ValueType - 所含的值类型
类型要求
-
std::decay_t<ValueType> 必须满足可复制构造 (CopyConstructible) 的要求。

参数

other | - | 另一个用以复制或移动的 any 对象
value | - | 初始化所含的值
il, args | - | 传递给所含对象的构造函数的参数

异常

2,4,5,6) 抛出任何所含类型的构造函数所抛出的异常

注解

默认构造函数为 constexpr ，故静态 std::any 在任何动态非局部初始化开始之前，作为静态非局部初始化的一部分初始化。这使得在任何静态对象的构造函数中使用 std::any 对象是安全的。

参阅

operator=
 赋值 any 对象
(公开成员函数)


std::any_cast

< cpp‎ | utility‎ | any
template<class T> T any_cast(const any& operand); | (1) | (C++17 起)
template<class T> T any_cast(any& operand); | (2) | (C++17 起)
template<class T> T any_cast(any&& operand); | (3) | (C++17 起)
template<class T> const T* any_cast(const any* operand) noexcept; | (4) | (C++17 起)
template<class T> T* any_cast(any* operand) noexcept; | (5) | (C++17 起)

进行对所含有对象的类型安全访问。

令 U 为 std::remove_cv_t < std::remove_reference_t <T>> 。

1) 若 is_constructible_v<T, const U&> 非 true 则程序为病式。
2) 若 is_constructible_v<T, U&> 非 true 则程序为病式。
3) 若 is_constructible_v<T, U> 非 true 则程序为病式。

参数

operand - 目标 any 对象

返回值

1-2) 返回 static_cast<T>(*std::any_cast<U>(&operand)) 。
3) 返回 static_cast<T>(std::move(*std::any_cast<U>(&operand))) 。
4-5) 若 operand 不是空指针，且请求的 T 的 typeid 匹配 operand 的 typeid ，则为指向所含值的指针，否则为空指针。

异常

1-3) 若请求的 T 的 typeid 不匹配 operand 内容的 typeid ，则抛出 std::bad_any_cast 。

示例

#include <string>
#include <iostream>
#include <any>
#include <utility>

int main()
{
    // 简单示例

    auto a = std::any(12);

    std::cout << std::any_cast<int>(a) << '\n';

    try {
        std::cout << std::any_cast<std::string>(a) << '\n';
    }
    catch(const std::bad_any_cast& e) {
        std::cout << e.what() << '\n';
    }

    // 指针示例

    if (int* i = std::any_cast<int>(&a)) {
       std::cout << "a is int: " << *i << '\n';
    } else if (std::string* s = std::any_cast<std::string>(&a)) {
       std::cout << "a is std::string: " << *s << '\n';
    } else {
       std::cout << "a is another type or unset\n";
    }

    // 进阶示例

    a = std::string("hello");

    auto& ra = std::any_cast<std::string&>(a); //< 引用
    ra[1] = 'o';

    std::cout << "a: "
        << std::any_cast<const std::string&>(a) << '\n'; //< const 引用

    auto b = std::any_cast<std::string&&>(std::move(a)); //< 右值引用

    // 注意： 'b' 是移动构造的 std::string ， 'a' 被置于合法但未指定的状态

    std::cout << "a: " << *std::any_cast<std::string>(&a) //< 指针
        << "b: " << b << '\n';
}

可能的输出：

12
bad any_cast
a is int: 12
a: hollo
a: b: hollo


std::bad_any_cast

< cpp‎ | utility‎ | any
定义于头文件 <any> |
class bad_any_cast : public std::bad_cast ; | (C++17 起)

定义 std::any_cast 在失败时以值返回形式抛出的对象的类型。

成员函数

(构造函数) | 构造新的 bad_any_cast 对象 (公开成员函数)
operator= | 替换 bad_any_cast 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::bad_any_cast::bad_any_cast

bad_any_cast() noexcept; | (1) | (C++17 起)
bad_any_cast( const bad_any_cast& other ) noexcept; | (2) | (C++17 起)

构造新的拥有实现定义的空终止字节字符串的 bad_any_cast 对象，字符串能通过 what() 访问。

1) 默认构造函数。
2) 复制构造函数。若 *this 与 other 均拥有动态类型 std::bad_any_cast 则 std::strcmp (what(), other.what()) == 0 。

参数

other - 要复制的另一异常对象

std::bad_any_cast::operator=

bad_any_cast& operator=( const bad_any_cast& other ) noexcept; | (C++17 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::bad_any_cast 则赋值后 std::strcmp (what(), other.what()) == 0 。

参数

other - 用以赋值的另一异常对象

返回值

*this

std::bad_any_cast::what

virtual const char* what() const noexcept; | (C++17 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::bad_cast

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)


std::any::emplace

< cpp‎ | utility‎ | any
template< class ValueType, class... Args > std::decay_t <ValueType>& emplace( Args&&... args ); | (1) | (C++17 起)
template< class ValueType, class U, class... Args > std::decay_t <ValueType>& emplace( std::initializer_list <U> il, Args&&... args ); | (2) | (C++17 起)

更改所含对象为从参数构造的 std::decay_t <ValueType> 类型对象。

首先用 reset() 销毁当前所含对象（若存在），然后：

1) 构造从 std::forward <Args>(args)... 直接非列表初始化的 std::decay_t <ValueType> 类型对象为所含对象。
  • 此重载仅若 std::is_constructible_v < std::decay_t <ValueType>, Args...> 与 std::is_copy_constructible_v < std::decay_t <ValueType>> 皆为 true 才参与重载决议。
2) 构造从 il, std::forward <Args>(args)... 直接非列表初始化的 std::decay_t <ValueType> 类型对象所含对象。
  • 此重载仅若 std::is_constructible_v < std::decay_t <ValueType>, std::initializer_list <U>&, Args...> 与 std::is_copy_constructible_v < std::decay_t <ValueType>> 皆为 true 才参与重载决议。

模板形参

ValueType - 所含的值类型
类型要求
-
std::decay_t<ValueType> 必须满足可复制构造 (CopyConstructible) 的要求。

返回值

到新的所含对象的引用。

异常

抛出 T 构造函数所抛的任何异常。若抛出异常，则销毁先前所含对象（若存在），而 *this 不含值。

示例

#include <algorithm>
#include <any>
#include <iostream>
#include <string>
#include <vector>

class Star
{
    std::string name;
    int id;

public:
    Star(std::string name, int id) : name { name }, id { id }
    {
        std::cout << "Star::Star(string, int)\n";
    }

    void print() const
    {
        std::cout << "Star{ \"" << name << "\" : " << id << " };\n";
    }
};

auto main() -> int
{
    std::any celestial;
    // (1) emplace( Args&&... args );
    celestial.emplace<Star>("Procyon", 2943);
    const auto* star = std::any_cast<Star>(&celestial);
    star->print();

    std::any av;
    // (2) emplace( std::initializer_list<U> il, Args&&... args );
    av.emplace<std::vector<char>>({ 'C', '+', '+', '1', '7' } /* 无参数 */ );
    std::cout << av.type().name() << '\n';
    const auto* va = std::any_cast<std::vector<char>>(&av);
    std::for_each(va->cbegin(), va->cend(), [](char const& c) { std::cout << c; });
    std::cout << '\n';
}

可能的输出：

Star::Star(string, int)
Star{ "Procyon" : 2943 };
St6vectorIcSaIcEE
C++17

参阅

(构造函数) | 构造 any 对象 (公开成员函数)
reset | 销毁所含对象 (公开成员函数)


std::any::has_value

< cpp‎ | utility‎ | any
bool has_value() const noexcept; | (C++17 起)

检查对象是否含有值。

参数

（无）

返回值

若实例含值则为 true ，否则为 false 。

示例

#include <any>
#include <iostream>
#include <string>

int main()
{
    std::boolalpha(std::cout);

    std::any a0;
    std::cout << "a0.has_value(): " << a0.has_value() << "\n";

    std::any a1 = 42;
    std::cout << "a1.has_value(): " << a1.has_value() << '\n';
    std::cout << "a1 = " << std::any_cast<int>(a1) << '\n';
    a1.reset();
    std::cout << "a1.has_value(): " << a1.has_value() << '\n';

    auto a2 = std::make_any<std::string>("Milky Way");
    std::cout << "a2.has_value(): " << a2.has_value() << '\n';
    std::cout << "a2 = \"" << std::any_cast<std::string&>(a2) << "\"\n";
    a2.reset();
    std::cout << "a2.has_value(): " << a2.has_value() << '\n';
}

输出：

a0.has_value(): false
a1.has_value(): true
a1 = 42
a1.has_value(): false
a2.has_value(): true
a2 = "Milky Way"
a2.has_value(): false

参阅

reset
 销毁所含对象
(公开成员函数)


std::make_any

< cpp‎ | utility‎ | any
template< class T, class... Args > std::any make_any( Args&&... args ); | (1) | (C++17 起)
template< class T, class U, class... Args > std::any make_any( std::initializer_list <U> il, Args&&... args ); | (2) | (C++17 起)

构造含 T 类型对象的 any 对象，传递提供的参数给 T 的构造函数。

1) 等价于 return std::any (std::in_place_type<T>, std::forward <Args>(args)...);
2) 等价于 return std::any (std::in_place_type<T>, il, std::forward <Args>(args)...);

示例

#include <any>
#include <complex>
#include <functional>
#include <iostream>
#include <string>

int main()
{
    auto a0 = std::make_any<std::string>("Hello, std::any!\n");
    auto a1 = std::make_any<std::complex<double>>(0.1, 2.3);

    std::cout << std::any_cast<std::string&>(a0);
    std::cout << std::any_cast<std::complex<double>&>(a1) << '\n';

    using lambda = std::function<void(void)>;

    // 把 lambda 放入 std::any。尝试 #1 （失败）。
    std::any a2 = [] { std::cout << "Lambda #1.\n"; };
    std::cout << "a2.type() = \"" << a2.type().name() << "\"\n";

    // any_cast 转型到 <void(void)> 但实际类型不是
    // std::function ……，而是 ~ main::{lambda()#1} ，且它对
    // 每个 lambda 唯一。所以这会抛出……
    try {
        std::any_cast<lambda>(a2)();
    }
    catch (std::bad_any_cast const& ex) {
        std::cout << ex.what() << '\n';
    }

    // 将 lambda 放入 std::any 中。尝试 #2 （成功）
    auto a3 = std::make_any<lambda>([] { std::cout << "Lambda #2.\n"; });
    std::cout << "a3.type() = \"" << a3.type().name() << "\"\n";
    std::any_cast<lambda>(a3)();
}

可能的输出：

Hello, std::any!
(0.1,2.3)
a2.type() = "Z4mainEUlvE_"
bad any_cast
a3.type() = "St8functionIFvvEE"
Lambda #2.

参阅

(构造函数) | 构造 any 对象 (公开成员函数)
any_cast (C++17) | 对被容纳对象的类型安全访问 (函数模板)


std::any::operator=

< cpp‎ | utility‎ | any
any& operator=( const any& rhs ); | (1) | (C++17 起)
any& operator=( any&& rhs ) noexcept; | (2) | (C++17 起)
template<typename ValueType> any& operator=( ValueType&& rhs ); | (3) | (C++17 起)

将内容赋值给所含值。

1) 以复制 rhs 的状态赋值，如同用 any(rhs).swap(*this) 。
2) 以移动 rhs 的状态赋值，如同用 any(std::move(rhs)).swap(*this) 。赋值后 rhs 留在合法但未指定的状态。
3) 以 rhs 的类型和值赋值，如同用 any( std::forward <ValueType>(rhs)).swap(*this) 。此重载仅若 std::decay_t <ValueType> 与 any 不是同一类型且 std::is_copy_constructible_v < std::decay_t <ValueType>> 为 true才参与重载决议。

模板参数

ValueType - 被含有的值类型
类型要求
-
std::decay_t<ValueType> 必须满足可复制构造 (CopyConstructible) 的要求。

参数

rhs - 要赋值给其所含值的对象

返回值

*this

异常

1,3) 抛出 bad_alloc 或任何所含类型的构造函数所抛出的异常。若抛出异常，则无效应（强异常保证）。

参阅

(构造函数)
 构造 any 对象
(公开成员函数)


std::any::reset

< cpp‎ | utility‎ | any
void reset() noexcept; | (C++17 起)

若非空，则销毁所含对象。

参数

（无）

返回值

（无）

参阅

has_value
 检查对象是否含有值
(公开成员函数)


std::any::swap

< cpp‎ | utility‎ | any
void swap(any& other) noexcept; | (C++17 起)

交换二个 any 对象的内容。

参数

other - 要交换的对象

返回值

（无）


std::swap(std::any)

< cpp‎ | utility‎ | any
void swap(any& lhs, any& rhs) noexcept; | (C++17 起)

为 std::any 重载 std::swap 算法。调用 lhs.swap(rhs) 交换二个 any 对象。

参数

lhs, rhs - 要交换的对象

返回值

（无）

参阅

swap
 交换二个 any 对象
(公开成员函数)


std::any::type

< cpp‎ | utility‎ | any
const std::type_info & type() const noexcept; | (C++17 起)

查询所含类型。

参数

（无）

返回值

若实例非空则为所含值的 typeid ，否则为 typeid(void) 。

示例

示例演示在编译和运行时注册新观览器的 std::any 观览器手法。

#include <type_traits>
#include <any>
#include <functional>
#include <iomanip>
#include <iostream>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <vector>

template<class T, class F>
inline std::pair<const std::type_index, std::function<void(std::any const&)>>
    to_any_visitor(F const &f)
{
    return {
        std::type_index(typeid(T)),
        [g = f](std::any const &a)
        {
            if constexpr (std::is_void_v<T>)
                g();
            else
                g(std::any_cast<T const&>(a));
        }
    };
}

static std::unordered_map<
    std::type_index, std::function<void(std::any const&)>>
    any_visitor {
        to_any_visitor<void>([]{ std::cout << "{}"; }),
        to_any_visitor<int>([](int x){ std::cout << x; }),
        to_any_visitor<unsigned>([](unsigned x){ std::cout << x; }),
        to_any_visitor<float>([](float x){ std::cout << x; }),
        to_any_visitor<double>([](double x){ std::cout << x; }),
        to_any_visitor<char const*>([](char const *s)
            { std::cout << std::quoted(s); }),
        // ……添加更多你的类型的特化……
    };

inline void process(const std::any& a)
{
    if (const auto it = any_visitor.find(std::type_index(a.type()));
        it != any_visitor.cend()) {
        it->second(a);
    } else {
        std::cout << "Unregistered type "<< std::quoted(a.type().name());
    }
}

template<class T, class F>
    inline void register_any_visitor(F const& f)
{
    std::cout << "Register visitor for type "
              << std::quoted(typeid(T).name()) << '\n';
    any_visitor.insert(to_any_visitor<T>(f));
}

auto main() -> int
{
    std::vector<std::any> va { {}, 42, 123u, 3.14159f, 2.71828, "C++17", };

    std::cout << "{ ";
    for (const std::any& a : va) {
        process(a);
        std::cout << ", ";
    }
    std::cout << "}\n";

    process(std::any(0xFULL)); //< 反注册 "y" 的类型（ unsigned long long ）
    std::cout << '\n';

    register_any_visitor<unsigned long long>([](auto x) {
        std::cout << std::hex << std::showbase << x;
    });

    process(std::any(0xFULL)); //< OK ： 0xf
    std::cout << '\n';
}

可能的输出：

{ {}, 42, 123, 3.14159, 2.71828, "C++17", }
Unregistered type "y"
Register visitor for type "y"
0xf

参阅

type_index
(C++11)
 针对 type_info 对象的包装，它能用作关联容器和无序关联容器的索引。
(类)


std::any::~any

< cpp‎ | utility‎ | any
~any(); | (C++17 起)

若存在则销毁所含对象，如同通过调用 reset() 。

参阅

reset
 销毁所含对象
(公开成员函数)


std::apply

< cpp‎ | utility
定义于头文件 <tuple> |
template <class F, class Tuple> constexpr decltype(auto) apply(F&& f, Tuple&& t); | (C++17 起)

以参数的元组调用可调用 (Callable) 对象 f 。

参数

f | - | 要调用的可调用 (Callable) 对象
t | - | 以其元素为 f 的参数的元组

返回值

f 所返回的值。

注解

元组不必是 std::tuple ，可以为任何支持 std::get 和 std::tuple_size 的类型所替代；特别是可以用 std::array 和 std::pair 。

可能的实现

namespace detail {
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>)
{
    // 此实现从 C++20 起合法（经由 P1065R2 ）
    // C++17 中，实际上在此需要 std::invoke 的 constexpr 对应
    return std::invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...);
}
}  // namespace detail

template <class F, class Tuple>
constexpr decltype(auto) apply(F&& f, Tuple&& t)
{
    return detail::apply_impl(
        std::forward<F>(f), std::forward<Tuple>(t),
        std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
}

示例

#include <iostream>
#include <tuple>
#include <utility>

int add(int first, int second) { return first + second; }

template<typename T>
T add_generic(T first, T second) { return first + second; }

auto add_lambda = [](auto first, auto second) { return first + second; };

template<typename... Ts>
std::ostream& operator<<(std::ostream& os, std::tuple<Ts...> const& theTuple)
{
    std::apply
    (
        [&os](Ts const&... tupleArgs)
        {
            os << '[';
            std::size_t n{0};
            ((os << tupleArgs << (++n != sizeof...(Ts) ? ", " : "")), ...);
            os << ']';
        }, theTuple
    );
    return os;
}

int main()
{
    // OK
    std::cout << std::apply(add, std::pair(1, 2)) << '\n';

    // 错误：无法推导函数类型
    // std::cout << std::apply(add_generic, std::make_pair(2.0f, 3.0f)) << '\n';

    // OK
    std::cout << std::apply(add_lambda, std::pair(2.0f, 3.0f)) << '\n';

    // 进阶示例
    std::tuple myTuple(25, "Hello", 9.31f, 'c');
    std::cout << myTuple << '\n';
}

输出：

3
5
[25, Hello, 9.31, c]

参阅

make_tuple | 创建一个 tuple 对象，其类型根据各实参类型定义 (函数模板)
forward_as_tuple | 创建转发引用的 tuple (函数模板)
make_from_tuple (C++17) | 以一个实参元组构造对象 (函数模板)
invokeinvoke_r (C++17)(C++23) | 以给定实参和可能指定的返回类型 (C++23 起)调用任意可调用 (Callable) 对象 (函数模板)


std::as_const

< cpp‎ | utility
定义于头文件 <utility> |  |
template <class T> constexpr std::add_const_t <T>& as_const(T& t) noexcept; | (1) | (C++17 起)
template <class T> void as_const(const T&&) = delete; | (2) | (C++17 起)
1) 将左值引用组成 t 的 const 类型
2) 删除 const 右值引用重载，以禁止右值参数

可能的实现

template <class T>
constexpr std::add_const_t<T>& as_const(T& t) noexcept
{
    return t;
}

示例

#include <string>
#include <cassert>
#include <utility>
#include <type_traits>

int main()
{
    std::string mutableString = "Hello World!";
    auto&& constRef = std::as_const(mutableString);

//  mutableString.clear(); // OK
//  constRef.clear(); // 错误： 'constRef' 有 'const' 限定，但 'clear' 不标记为 const

    assert( &constRef == &mutableString );
    assert( &std::as_const( mutableString ) == &mutableString );

    using ExprType = std::remove_reference_t<decltype(std::as_const(mutableString))>;

    static_assert(std::is_same_v<std::remove_const_t<ExprType>, std::string>,
            "ExprType should be some kind of string." );
    static_assert(!std::is_same_v<ExprType, std::string>,
            "ExprType shouldn't be a mutable string." );
}

参阅

is_const (C++11) | 检查类型是否为 const 限定 (类模板)
add_cvadd_constadd_volatile (C++11)(C++11)(C++11) | 添加 const 或/与 volatile 限定符到给定类型 (类模板)
remove_cvremove_constremove_volatile (C++11)(C++11)(C++11) | 从给定类型移除 const 或/与 volatile 限定符 (类模板)


std::basic_stacktrace

< cpp‎ | utility
定义于头文件 <stacktrace>
template< class Allocator >
class basic_stacktrace;
 (1) (C++23 起)
using stacktrace =
std::basic_stacktrace< std::allocator <std::stacktrace_entry>>;
 (2) (C++23 起)
namespace pmr {

using stacktrace =
std::basic_stacktrace<std::polymorphic_allocator<std::stacktrace_enty>>;

}
 (3) (C++23 起)
1) basic_stacktrace 类模板表示整个栈踪或其给定部分的快照。它满足知分配器容器 (AllocatorAwareContainer) 、序列容器 (SequenceContainer) 及可逆容器 (ReversibleContainer) 的要求，除了仅支持移动、复制、交换和 const 限定的顺序容器上的操作，以及比较函数的语义不同于对容器所要求的语义。
2) 使用默认 std::allocator 的 basic_stacktrace 的便利类型别名。
3) 使用多态分配器的 basic_stacktrace 的便利类型别名。

当前执行线程中的当前求值 \(\small{ {x}_{0} }\)x0 的调用序列是求值的序列 \(\small{ ({x}_{0}, \dots, {x}_{n})}\)(x0, ..., xn) ，它使得对于 \(\small{i \ge 0}\)i≥0 ， \(\small{ {x}_{i} }\)xi 在函数调用 \(\small{ {x}_{i+1} }\)xi+1 内。

栈踪是调用序列的近似表示，由栈踪条目组成。

每个栈踪条目表示栈踪中的一个求值。在 C++ 标准库中它由 std::stacktrace_entry 表示。

模板形参

Allocator - 用于获取/释放内存及构造/销毁该内存中的元素的分配器。类型必须符合分配器 (Allocator) 的要求。若 Allocator::value_type 不是 std::stacktrace_entry 则程序非良构。

成员类型

成员类型 | 定义
value_type(C++23) | std::stacktrace_entry
const_reference(C++23) | const value_type&
reference(C++23) | value_type&
const_iterator(C++23) | 实现定义的常老式随机访问迭代器 (LegacyRandomAccessIterator) 类型，实现 random_access_iterator
iterator(C++23) | const_iterator
reverse_iterator(C++23) | std::reverse_iterator <iterator>
reverse_const_iterator(C++23) | std::reverse_iterator <const_iterator>
difference_type(C++23) | 实现定义的有符号整数类型
size_type(C++23) | 实现定义的无符号整数类型
allocator_type(C++23) | Allocator

成员函数

(构造函数)
(C++23)
 创建新的 basic_stacktrace
(公开成员函数)
(析构函数)
(C++23)
 销毁 basic_stacktrace
(公开成员函数)
operator=
(C++23)
 赋值给 basic_stacktrace
(公开成员函数)
current
[静态] (C++23)
 获得当前栈踪或其给定部分
(公开静态成员函数)
get_allocator
(C++23)
 返回关联的分配器
(公开成员函数)
迭代器
begincbegin
(C++23)
 返回指向起始的迭代器
(公开成员函数)
endcend
(C++23)
 返回指向末尾的迭代器
(公开成员函数)
rbegincrbegin
(C++23)
 返回指向起始的逆向迭代器
(公开成员函数)
rendcrend
(C++23)
 返回指向末尾的迭代器
(公开成员函数)
容量
empty
(C++23)
 检查 basic_stacktrace 是否为空
(公开成员函数)
size
(C++23)
 返回栈踪条目的数量
(公开成员函数)
max_size
(C++23)
 返回栈踪条目的最大可能数量
(公开成员函数)
元素访问
operator[]
(C++23)
 访问指定的栈踪条目
(公开成员函数)
at
(C++23)
 访问指定的栈踪条目，带边界检查
(公开成员函数)
修改器
swap
(C++23)
 交换内容
(公开成员函数)

非成员函数

operator==operator<=> (C++23) | 比较二个 basic_stacktrace 值的大小与内容 (函数模板)
std::swap(std::basic_stacktrace) (C++23) | 特化 std::swap 算法 (函数模板)
to_string (C++23) | 返回拥有 basic_stacktrace 的描述的字符串 (函数模板)
operator<< (C++23) | 进行 basic_stracktrace 的流输出 (函数模板)

辅助类

std::hash<std::basic_stacktrace>
(C++23)
 std::basic_stacktrace 的散列支持
(类模板特化)

注解

定制分配器的支持是为在热路径上或嵌入式环境中使用 basic_stacktrace 而提供的。用户能在栈或其他适合的位置分配 stacktrace_entry 对象。

std::basic_stacktrace 所拥有的 std::stacktrace_entry 对象序列是不可变的，而且要么为空，要么表示整个栈踪的一个连续区间。

boost::stacktrace::basic_stacktrace （可用于 Boost.Stacktrace ）能在 std::basic_stacktrace 不可用时作为代替。

示例

本节未完成
原因：暂无示例

参阅

stacktrace_entry
(C++23)
 栈踪中求值的表示
(类)


std::basic_stacktrace<Allocator>::at

< cpp‎ | utility‎ | basic stacktrace
const_reference at( size_type pos ) const; | (C++23 起)

返回位于指定位置 pos 的条目，进行边界检查。

若 pos 不在栈踪的范围内，则抛出 std::out_of_range 类型的异常。

参数

pos - 要返回的栈踪条目的位置

返回值

到请求的条目的引用。

异常

若 pos >= size() 则为 std::out_of_range 。

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

operator[]
(C++23)
 访问指定的栈踪条目
(公开成员函数)


std::basic_stacktrace<Allocator>::basic_stacktrace

< cpp‎ | utility‎ | basic stacktrace
basic_stacktrace() noexcept(/* see below */); | (1) | (C++23 起)
explicit basic_stacktrace( const allocator_type& alloc ) noexcept; | (2) | (C++23 起)
basic_stacktrace( const basic_stacktrace& other ); | (3) | (C++23 起)
basic_stacktrace( basic_stacktrace&& other ) noexcept; | (4) | (C++23 起)
basic_stacktrace( const basic_stacktrace& other, const allocator_type& alloc ); | (5) | (C++23 起)
basic_stacktrace( basic_stacktrace&& other, const allocator_type& alloc ); | (6) | (C++23 起)

构造空的 basic_stacktrace ，或从 other 复制/移动。

1) 默认构造函数。构造带默认构造的分配器的空 basic_stacktrace 。
2) 以 alloc 为分配器构造空 basic_stacktrace 。
3) 复制构造函数。以 other 的内容副本构造 basic_stacktrace ，如同通过调用 std::allocator_traits <allocator_type>::select_on_container_copy_construction(other.get_allocator()) 获得分配器。
4) 移动构造函数。用移动语义以 other 的内容构造 basic_stacktrace 。从 other 的分配器移动构造分配器。构造后， other 被置于合法但未指定的状态。
5) 同复制构造函数，除了以 alloc 为分配器。
6) 若 alloc == other.get_allocator() 则表现同移动构造函数。否则，用 alloc 分配内存并进行逐元素移动。以 alloc 为分配器。

(3,5,6) 在分配失败时可能抛出异常或构造空的 basic_stacktrace 。

参数

alloc | - | 用于构造的 basic_stacktrace 的所有内存分配的分配器
other | - | 要复制/移动的另一 basic_stacktrace

异常

1)
noexcept 说明：
noexcept( std::is_nothrow_default_constructible_v <allocator_type>)
3,5,6) 可能传播分配失败时抛出的异常。

复杂度

1-2) 常数。
3) 与 other 的大小成线性。
4) 常数。
5) 与 other 的大小成线性。
6) 若 alloc != other.get_allocator() 则与 other 的大小成线性，否则为常数。

注解

在容器移动构造（重载 (4) ）后，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

本节未完成
原因：暂无示例

参阅

operator= (C++23) | 赋值给 basic_stacktrace (公开成员函数)
current [静态] (C++23) | 获得当前栈踪或其给定部分 (公开静态成员函数)


std::basic_stacktrace<Allocator>::begin, std::basic_stacktrace<Allocator>::cbegin

< cpp‎ | utility‎ | basic stacktrace
const_iterator begin() const noexcept; | (1) | (C++23 起)
const_iterator cbegin() const noexcept; | (2) | (C++23 起)

返回指向 basic_stacktrace 首个条目的迭代器。

若 basic_stacktrace 为空，则返回的迭代器等于 end() 。

参数

（无）

返回值

指向首个条目的迭代器。

复杂度

常数。

示例

#include <algorithm>
#include <iostream>
#include <stacktrace>

int main()
{
    auto trace       = std::stacktrace::current();
    auto empty_trace = std::stacktrace{};

    // 打印 stacktrace 。
    std::for_each(trace.begin(), trace.end(),
                  [](const auto& f) { std::cout << f << '\n'; });

    if (empty_trace.begin() == empty_trace.end())
        std::cout << "stacktrace 'empty_trace' is indeed empty.\n";
}

可能的输出：

0x0000000000402BA8 in ./prog.exe
__libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
0x0000000000402A29 in ./prog.exe
stacktrace 'empty_trace' is indeed empty.

参阅

endcend
(C++23)
 返回指向末尾的迭代器
(公开成员函数)


std::basic_stacktrace<Allocator>::current

< cpp‎ | utility‎ | basic stacktrace
static basic_stacktrace current( const allocator_type& alloc = allocator_type() ) noexcept; | (1) | (C++23 起)
static basic_stacktrace current( size_type skip, const allocator_type& alloc = allocator_type() ) noexcept; | (2) | (C++23 起)
static basic_stacktrace current( size_type skip, size_type max_depth, const allocator_type& alloc = allocator_type() ) noexcept; | (3) | (C++23 起)

令 s[i] (0 ≤ i < n) 代表当前执行线程中当前求值的第 i+1 个栈踪条目，其中 n 为栈踪中的栈踪条目数。

1) 试图创建由 s[0]、 s[1] …… s[n - 1] 组成的 basic_stacktrace 。
2) 试图创建由 s[m]、 s[m + 1] …… s[n - 1] 组成的 basic_stacktrace ，其中 m 为 min(skip, n) 。
3) 试图创建由 s[m]、 s[m + 1] …… s[o - 1] 组成的 basic_stacktrace ，其中 m 为 min(skip, n) 而 o 为 min(skip + max_depth, n) 。若 skip + max_depth < skip （即 skip + max_depth 的数学结果上溢）则行为未定义。

所有情况下，存储 alloc 到创建的 basic_stacktrace 中并用它分配栈踪条目的存储。

参数

alloc | - | 用于构造的 basic_stacktrace 的所有内存分配的分配器
skip | - | 要跳过的栈踪条目数
max_depth | - | 栈踪条目的最大深度

返回值

若分配成功则为如上描述的 basic_stacktrace 。

否则为空的 basic_stacktrace 。

示例

本节未完成
原因：暂无示例

参阅

(构造函数) (C++23) | 创建新的 basic_stacktrace (公开成员函数)
current [静态] | 构造对应调用点位置的新 source_location (std::source_location 的公开静态成员函数)


std::basic_stacktrace<Allocator>::empty

< cpp‎ | utility‎ | basic stacktrace
[[nodiscard]] bool empty() const noexcept; | (C++23 起)

检查栈踪是否无栈踪条目。

参数

（无）

返回值

若栈踪为空则为 true ，否则为 false 。

复杂度

常数。

示例

#include <stacktrace>
#include <iostream>

int main()
{
    std::cout << std::boolalpha;
    std::stacktrace bktr;
    std::cout << "Initially, bktr.empty(): " << bktr.empty() << '\n';

    bktr = std::stacktrace::current();
    std::cout << "After getting entries, bktr.empty(): " << bktr.empty() << '\n';
}

可能的输出：

Initially, bktr.empty(): true
After getting entries, bktr.empty(): false

参阅

size
(C++23)
 返回栈踪条目的数量
(公开成员函数)


std::basic_stacktrace<Allocator>::end, std::basic_stacktrace<Allocator>::cend

< cpp‎ | utility‎ | basic stacktrace
const_iterator end() const noexcept; | (1) | (C++23 起)
const_iterator cend() const noexcept; | (2) | (C++23 起)

返回指向 basic_stacktrace 的最后条目后一位置的迭代器。

此迭代器表现为占位符；试图解引用它导致未定义行为。

参数

（无）

返回值

尾迭代器。

复杂度

常数。

示例

#include <algorithm>
#include <iostream>
#include <stacktrace>

int main()
{
    auto trace       = std::stacktrace::current();
    auto empty_trace = std::stacktrace{};

    // 打印 stacktrace 。
    std::for_each(trace.begin(), trace.end(),
                  [](const auto& f) { std::cout << f << '\n'; });

    if (empty_trace.begin() == empty_trace.end())
        std::cout << "stacktrace 'empty_trace' is indeed empty.\n";
}

可能的输出：

0x0000000000402BA8 in ./prog.exe
__libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
0x0000000000402A29 in ./prog.exe
stacktrace 'empty_trace' is indeed empty.

参阅

begincbegin
(C++23)
 返回指向起始的迭代器
(公开成员函数)


std::basic_stacktrace<Allocator>::get_allocator

< cpp‎ | utility‎ | basic stacktrace
allocator_type get_allocator() const noexcept; | (C++23 起)

返回与 basic_stacktrace 关联的分配器。

参数

（无）

返回值

关联的分配器。

复杂度

常数。


std::hash(std::basic_stacktrace)

< cpp‎ | utility‎ | basic stacktrace
定义于头文件 <stacktrace> |
template< class Allocator > struct hash<std::basic_stacktrace<Allocator>>; | (C++23 起)

std::hash 对 std::basic_stacktrace 的模板特化允许用户获得 std::basic_stacktrace 类型值的哈希。

此特化的 operator() 为 noexcept 。

示例

本节未完成
原因：暂无示例

参阅

hash (C++11) | 散列函数对象 (类模板)
std::hash<std::stacktrace_entry> (C++23) | std::stacktrace_entry 的散列支持 (类模板特化)


std::basic_stacktrace<Allocator>::max_size

< cpp‎ | utility‎ | basic stacktrace
size_type max_size() const noexcept; | (C++23 起)

返回底层容器（常为 std::vector ）由于系统或库实现限制能保有的最大元素数，即最大的底层容器的 std::distance (begin(), end()) 。

参数

（无）

返回值

最大元素数。

复杂度

常数。

注解

此值常反映底层容器大小的理论极限，至多为 std::numeric_limits <difference_type>::max() 。运行时容器大小可能被可用 RAM 总量限制到一个小于 max_size() 的值。

示例

#include <iostream>
#include <stacktrace>

int main()
{
    std::stacktrace trace;
    std::cout << "Maximum size of a 'basic_stacktrace' is " << trace.max_size() << "\n";
}

可能的输出：

Maximum size of a 'basic_stacktrace' is 1152921504606846975

参阅

size
(C++23)
 返回栈踪条目的数量
(公开成员函数)


std::basic_stacktrace<Allocator>::operator=

< cpp‎ | utility‎ | basic stacktrace
basic_stacktrace& operator=( const basic_stacktrace& other );
 (1) (C++23 起)
basic_stacktrace& operator=( basic_stacktrace&& other )
noexcept(/* see below */);
 (2) (C++23 起)

替换 basic_stacktrace 的内容。

1) 复制赋值运算符。以 other 的副本替换内容。
若 std::allocator_traits <allocator_type>::propagate_on_container_copy_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若 *this 的分配器在赋值后将与其旧值比较不相等，则用旧分配器解分配内存，然后在复制条目前用新分配器分配内存。否则，在可行时可能复用 *this 所拥有的内存。
2) 移动赋值运算符。用移动语义以 other 的内容替换内容（即从 other 移动 other 中的数据到 *this 中）。之后 other 在合法但未指定的状态。
若 std::allocator_traits <allocator_type>::propagate_on_container_move_assignment::value 为 true ，则用 other 的分配器的副本替换 *this 的分配器。若它为 false 且 *this 与 other 的分配器不比较相等，则 *this 不能接管 other 所拥有的内存的所有权且必须单独地移动赋值每个条目，并用其自身的分配器按需分配额外内存。

任何情况下，原属于 *this 的栈踪条目要么被销毁，要么被逐元素赋值替换。

若实现强化异常说明，则在分配失败时 *this 可能被设为空。

参数

other - 用作源的另一 basic_stacktrace

返回值

*this

复杂度

1) 与 *this 和 other 的大小成线性。
2) 与 *this 的大小成线性，除非分配器不比较相等且不传播，该情况下与 *this 和 other 的大小成线性。

异常

1) 可能抛出实现定义的异常。
2)
noexcept 说明：
noexcept( std::allocator_traits <Allocator>::propagate_on_container_move_assignment::value
|| std::allocator_traits <Allocator>::is_always_equal::value)

注解

在容器移动赋值（重载 (2) ）后，除非不兼容的分配器强制逐元素移动赋值，指向 other 的引用及迭代器（除了尾迭代器）保持合法，但指代现于 *this 中的元素。当前标准由 [container.requirements.general]/12 中的总括陈述作出此保证，而 LWG 2321 正在考虑更严格的保证。

示例

本节未完成
原因：暂无示例

参阅

(构造函数)
(C++23)
 创建新的 basic_stacktrace
(公开成员函数)


std::basic_stacktrace<Allocator>::operator[]

< cpp‎ | utility‎ | basic stacktrace
const_reference operator[]( size_type pos ) const; | (C++23 起)

返回位于指定位置 pos 的条目。不进行边界检查。

若 pos 不在栈踪的范围内，即 pos >= size() ，则行为未定义。

参数

pos - 要返回的栈踪条目的位置

返回值

到请求的条目的引用。

异常

不抛出。

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

at
(C++23)
 访问指定的栈踪条目，带边界检查
(公开成员函数)


operator==, operator<=>(std::basic_stacktrace)

< cpp‎ | utility‎ | basic stacktrace
template< class Allocator2 > friend bool operator==( const basic_stacktrace& lhs, const basic_stacktrace<Allocator2>& rhs ) noexcept; | (1) | (C++23 起)
template< class Allocator2 > friend std::strong_ordering operator<=>( const basic_stacktrace& lhs, const basic_stacktrace<Allocator2>& rhs ) noexcept; | (2) | (C++23 起)
1) 检查 lhs 与 rhs 的内容是否相等，即它们拥有相同元素数且 lhs 中的元素比较等于 rhs 中相同位置的元素。
等价于 return std::equal (lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); 。
2) 返回 lhs 与 rhs 中的栈踪条目数的相对顺序，若它们不相等。否则（若 lhs 与 rhs 的元素数相等），则返回 lhs 与 rhs 的元素的字典序。
等价于
if (auto cmp = lhs.size() <=> rhs.size(); cmp != 0)

return cmp;
else
return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(),

rhs.begin(), rhs.end()); 。

这些函数模板对通常无限定或有限定查找不可见，而只能在 std::basic_stacktrace<Allocator> 为参数的关联类时由实参依赖查找找到。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

参数

lhs, rhs - 要比较内容的 basic_stacktrace

返回值

1) 若 lhs 与 rhs 的内容相等则为 true ，否则为 false 。
2) lhs.size() <=> rhs.size() ，若结果不是 std::strong_order::equal ，否则为 lhs 与 rhs 的元素的字典序。

复杂度

1-2) 若 lhs 与 rhs 大小不同则为常数，否则与 lhs 的大小成线性。

示例

本节未完成
原因：暂无示例


std::operator<<(std::basic_stacktrace)

< cpp‎ | utility‎ | basic stacktrace
定义于头文件 <stacktrace>
template< class CharT, class Traits, class Allocator >

std::basic_ostream <CharT, Traits>& operator<<( std::basic_ostream <CharT, Traits>& os,

const std::basic_stacktrace<Allocator>& st );
 (C++23 起)

插入 st 的描述到输出流 os 中。等价于 return os << std::to_string (st); 。

参数

os | - | 输出流
st | - | 要插入其描述的 basic_stacktrace

返回值

os 。

异常

可能抛出实现定义的异常。

注解

由于 std::string 只能由 std::ostream 输出（例如不能由 std::wostream ），这等效地要求 os 的类型为 std::ostream & 。

示例

#include <stacktrace>
#include <iostream>

int main()
{
    std::cout << "The stacktrace obtained in the main function:\n";
    std::cout << std::stacktrace::current() << '\n';
    []{
        std::cout << "The stacktrace obtained in a nested lambda:\n";
        std::cout << std::stacktrace::current() << '\n';
    }();
}

可能的输出：

The stacktrace obtained in the main function:
 0# 0x0000000000402E7B in ./prog.exe
 1# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
 2# 0x0000000000402CD9 in ./prog.exe

The stacktrace obtained in a nested lambda:
 0# 0x0000000000402DDA in ./prog.exe
 1# 0x0000000000402EB2 in ./prog.exe
 2# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
 3# 0x0000000000402CD9 in ./prog.exe

参阅

operator<<
(C++23)
 进行 stacktrace_entry 的流输出
(函数模板)


std::basic_stacktrace<Allocator>::rbegin, std::basic_stacktrace<Allocator>::crbegin

< cpp‎ | utility‎ | basic stacktrace
const_reverse_iterator rbegin() const noexcept; | (1) | (C++23 起)
const_reverse_iterator crbegin() const noexcept; | (2) | (C++23 起)

返回指向逆向的 basic_stacktrace 的首条目的逆向迭代器。它对应原本 basic_stacktrace 的末尾条目。若 basic_stacktrace 为空，则返回的迭代器等于 rend() 。

参数

（无）

返回值

指向首条目的逆向迭代器。

复杂度

常数。

示例

#include <algorithm>
#include <iostream>
#include <stacktrace>

int main()
{
    auto trace       = std::stacktrace::current();
    auto empty_trace = std::stacktrace{};

    // 打印 stacktrace 。
    std::for_each(trace.rbegin(), trace.rend(),
                  [](const auto& f) { std::cout << f << '\n'; });

    if (empty_trace.rbegin() == empty_trace.rend())
        std::cout << "stacktrace 'empty_trace' is indeed empty.\n";
}

可能的输出：

0x0000000000402A29 in ./prog.exe
__libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
0x0000000000402BA5 in ./prog.exe
stacktrace 'empty_trace' is indeed empty.

参阅

rendcrend
(C++23)
 返回指向末尾的迭代器
(公开成员函数)


std::basic_stacktrace<Allocator>::rend, std::basic_stacktrace<Allocator>::crend

< cpp‎ | utility‎ | basic stacktrace
const_reverse_iterator rend() const noexcept; | (1) | (C++23 起)
const_reverse_iterator crend() const noexcept; | (2) | (C++23 起)

返回指向逆向 basic_stacktrace 的末尾条目后一位置的逆向迭代器。它对应原本 basic_stacktrace 的首条目之前的迭代器。此迭代器表现为占位符，试图解引用它导致未定义行为。

参数

（无）

返回值

逆向 basic_stacktrace 的尾迭代器。

复杂度

常数。

示例

#include <algorithm>
#include <iostream>
#include <stacktrace>

int main()
{
    auto trace       = std::stacktrace::current();
    auto empty_trace = std::stacktrace{};

    // 打印 stacktrace 。
    std::for_each(trace.rbegin(), trace.rend(),
                  [](const auto& f) { std::cout << f << '\n'; });

    if (empty_trace.rbegin() == empty_trace.rend())
        std::cout << "stacktrace 'empty_trace' is indeed empty.\n";
}

可能的输出：

0x0000000000402A29 in ./prog.exe
__libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
0x0000000000402BA5 in ./prog.exe
stacktrace 'empty_trace' is indeed empty.

参阅

rbegincrbegin
(C++23)
 返回指向起始的逆向迭代器
(公开成员函数)


std::basic_stacktrace<Allocator>::size

< cpp‎ | utility‎ | basic stacktrace
size_type size() const noexcept; | (C++23 起)

返回栈踪中的条目数。

参数

（无）

返回值

栈踪中的条目数。

复杂度

常数。

示例

以下代码用 size 显示当前栈踪中的条目数：

#include <stacktrace>
#include <iostream>

int main()
{
    auto trace = std::stacktrace::current();

    std::cout << "trace contains " << trace.size() << " entries.\n";
}

可能的输出：

trace contains 3 entries.

参阅

empty (C++23) | 检查 basic_stacktrace 是否为空 (公开成员函数)
max_size (C++23) | 返回栈踪条目的最大可能数量 (公开成员函数)


std::basic_stacktrace<Allocator>::swap

< cpp‎ | utility‎ | basic stacktrace
void swap( basic_stacktrace& other ) noexcept(/* see below */); | (C++23 起)

将内容与 other 的交换。不在单独的 stacktrace_entry 对象上调用任何移动、复制或交换操作。

所有迭代器和引用保持合法。尾后迭代器被非法化。

若 std::allocator_traits <allocator_type>::propagate_on_container_swap::value 为 true ，则用对非成员 swap 的无限定调用交换分配器。否则，不交换它们（且若 get_allocator() != other.get_allocator() ，则行为未定义）。

参数

other - 要交换内容的 basic_stacktrace

返回值

（无）

异常

noexcept 说明：
noexcept( std::allocator_traits <Allocator>::propagate_on_container_swap::value
|| std::allocator_traits <Allocator>::is_always_equal::value)

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

std::swap(std::basic_stacktrace)
(C++23)
 特化 std::swap 算法
(函数模板)


std::swap(std::basic_stacktrace)

< cpp‎ | utility‎ | basic stacktrace
定义于头文件 <stacktrace>
template< class Allocator >

void swap( std::basic_stacktrace<Allocator>& lhs, std::basic_stacktrace<Allocator>& rhs )

noexcept(noexcept(lhs.swap(rhs)));
 (C++23 起)

对 std::basic_stacktrace 特化 std::swap 算法。交换 lhs 与 rhs 的内容。等价于 lhs.swap(rhs); 。

参数

lhs, rhs - 要交换内容的栈踪

返回值

（无）

复杂度

常数。

示例

本节未完成
原因：暂无示例

参阅

swap
(C++23)
 交换内容
(公开成员函数)


std::to_string

< cpp‎ | utility‎ | basic stacktrace
定义于头文件 <stacktrace> |
template< class Allocator > std::string to_string( const std::basic_stacktrace<Allocator>& st ); | (C++23 起)

返回带有 st 的描述的字符串。

basic_stacktrace 的描述常含有其条目的描述，尽管不要求描述的行数等于 size() 。

参数

st - 要返回其描述的 basic_stacktrace

返回值

带有 st 的描述的字符串。

异常

可能抛出实现定义的异常。

注解

不提供对此函数的定制分配器支持，因为实现通常要求平台特定的分配、系统调用和大量 CPU 集中工作，而定制分配器不会对此函数提供便利，因为平台特定的操作耗费的时间数量级多于分配。

示例

#include <stacktrace>
#include <string>
#include <iostream>

int main()
{
    auto trace = std::stacktrace::current();
    std::cout << std::to_string(trace) << '\n';
}

可能的输出：

 0# 0x0000000000402D97 in ./prog.exe
 1# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
 2# 0x0000000000402CA9 in ./prog.exe

参阅

to_string
(C++23)
 返回拥有 stacktrace_entry 的描述的字符串
(函数)


std::basic_stacktrace<Allocator>::~basic_stacktrace

< cpp‎ | utility‎ | basic stacktrace
~basic_stacktrace(); | (C++23 起)

销毁 basic_stacktrace 。调用其所保有的 std::stacktrace_entry 对象的析构函数并释放使用的存储。

复杂度

与 basic_stacktrace 的大小成线性。


std::bitset

< cpp‎ | utility
定义于头文件 <bitset>
template< std::size_t N >
class bitset;

类模板 bitset 表示一个 N 位的固定大小序列。可以用标准逻辑运算符操作bitset，并将它与字符串和整数相互转换。

bitset 满足可复制构造 (CopyConstructible) 及可复制赋值 (CopyAssignable) 的要求。

模板形参

N - 要为 bitset 分配存储的位数

成员类型

reference
 表示到一个位的引用的代理类
(类)

成员函数

(构造函数)
 构造 bitset
(公开成员函数)
operator==operator!=
(C++20 中移除)
 比较其内容
(公开成员函数)
元素访问
operator[]
 访问指定的位
(公开成员函数)
test
 访问特定位
(公开成员函数)
allanynone
(C++11)
检查是否所有、任一或无位被设为 true
(公开成员函数)
count
 返回设置为 true 的位的数量
(公开成员函数)
容量
size
 返回位集保有的位数
(公开成员函数)
修改器
operator&=operator|=operator^=operator~
 进行二进制与、或、异或及非
(公开成员函数)
operator<<=operator>>=operator<<operator>>
 进行二进制左移和右移
(公开成员函数)
set
 将位置为 true 或者提供的值
(公开成员函数)
reset
 将位置为 false
(公开成员函数)
flip
 翻转位的值
(公开成员函数)
转换
to_string
 返回数据的字符串表示
(公开成员函数)
to_ulong
 返回数据的 unsigned long 整数表示
(公开成员函数)
to_ullong
(C++11)
 返回数据的 unsigned long long 整数表示
(公开成员函数)

非成员函数

operator&operator|operator^ | 在 bitset 上执行二元逻辑操作 (函数)
operator<<operator>> | 执行 bitset 的流输入和输出 (函数)

辅助类

std::hash<std::bitset>
(C++11)
 std::bitset 的散列支持
(类模板特化)

注解

若在编译时 bitset 的大小未知，则可使用 std::vector<bool> 或 boost::dynamic_bitset 。

示例

#include <bitset>
#include <cassert>
#include <iostream>

int main()
{
    // 构造函数：
    constexpr std::bitset<4> b1;
    constexpr std::bitset<4> b2{0xA}; // == 0B1010
    std::bitset<4> b3{"0011"}; // 尚不能为 constexpr
    std::bitset<8> b4{"ABBA", /*length*/4, /*0:*/'A', /*1:*/'B'}; // == 0B0000'0110

    // 能打印出 bitset 到流：
    std::cout << "b1:" << b1 << "; b2:" << b2 << "; b3:" << b3 << "; b4:" << b4 << '\n';

    // bitset 支持逐位运算：
    b3 |= 0b0100; assert(b3 == 0b0111);
    b3 &= 0b0011; assert(b3 == 0b0011);
    b3 ^= std::bitset<4>{0b1100}; assert(b3 == 0b1111);

    // 整个集合上的操作：
    b3.reset(); assert(b3 == 0);
    b3.set(); assert(b3 == 0b1111);
    assert(b3.all() && b3.any() && !b3.none());
    b3.flip(); assert(b3 == 0);

    // 单独位上的操作：
    b3.set(/* position = */ 1, true); assert(b3 == 0b0010);
    b3.set(/* position = */ 1, false); assert(b3 == 0);
    b3.flip(/* position = */ 2); assert(b3 == 0b0100);
    b3.reset(/* position = */ 2); assert(b3 == 0);

    // 支持下标 operator[] ：
    b3[2] = true; assert(true == b3[2]);

    // 其他操作：
    assert(b3.count() == 1);
    assert(b3.size() == 4);
    assert(b3.to_ullong() == 0b0100ULL);
    assert(b3.to_string() == "0100");
}

输出：

b1:0000; b2:1010; b3:0011; b4:00000110

参阅

vector<bool> | 节省空间的动态 bitset (类模板特化)
位操纵 (C++20) | 用于访问、操纵和处理单独的位和位序列的工具


std::bitset<N>::all, std::bitset<N>::any, std::bitset<N>::none

< cpp‎ | utility‎ | bitset
bool all() const noexcept; | (1) | (C++11 起)
 | (2) |
bool any() const; |  |  | (C++11 前)
bool any() const noexcept; |  |  | (C++11 起)
 | (3) |
bool none() const; |  |  | (C++11 前)
bool none() const noexcept; |  |  | (C++11 起)

检查是否全部、任一或无位被设为 true 。

1) 检查是否全部位被设为 true 。
2) 检查是否任一位被设为 true 。
3) 检查是否无位被设为 true 。

参数

（无）

返回值

1) 若全部位被设为 true 则为 true ，否则为 false
2) 若任何一位被设为 true 则为 true ，否则为 false
3) 若无位被设为 true 则为 true ，否则为 false

示例

#include <iostream>
#include <bitset>

int main()
{
    std::bitset<4> b1("0000");
    std::bitset<4> b2("0101");
    std::bitset<4> b3("1111");

    std::cout << "bitset\t" << "all\t" << "any\t" << "none\n";
    std::cout << b1 << '\t' << b1.all() << '\t' << b1.any() << '\t' << b1.none() << '\n';
    std::cout << b2 << '\t' << b2.all() << '\t' << b2.any() << '\t' << b2.none() << '\n';
    std::cout << b3 << '\t' << b3.all() << '\t' << b3.any() << '\t' << b3.none() << '\n';
}

输出：

bitset  all     any     none
0000    0       0       1
0101    0       1       0
1111    1       1       0

参阅

count | 返回设置为 true 的位的数量 (公开成员函数)
popcount (C++20) | 计量无符号整数中为 1 的位的数量 (函数模板)


std::bitset<N>::bitset

< cpp‎ | utility‎ | bitset
(1)
bitset();
 (C++11 前)
constexpr bitset() noexcept;
 (C++11 起)
(2)
bitset( unsigned long val );
 (C++11 前)
constexpr bitset( unsigned long long val ) noexcept;
 (C++11 起)
(3)
template< class CharT, class Traits, class Alloc >

explicit bitset( const std::basic_string <CharT,Traits,Alloc>& str,
typename std::basic_string <CharT,Traits,Alloc>::size_type
pos = 0,
typename std::basic_string <CharT,Traits,Alloc>::size_type

n = std::basic_string <CharT,Traits,Alloc>::npos);
 (C++11 前)
template< class CharT, class Traits, class Alloc >

explicit bitset( const std::basic_string <CharT,Traits,Alloc>& str,
typename std::basic_string <CharT,Traits,Alloc>::size_type
pos = 0,
typename std::basic_string <CharT,Traits,Alloc>::size_type
n = std::basic_string <CharT,Traits,Alloc>::npos,
CharT zero = CharT('0'),

CharT one = CharT('1'));
 (C++11 起)
template< class CharT >

explicit bitset( const CharT* str,
typename std::basic_string <CharT>::size_type
n = std::basic_string <CharT>::npos,
CharT zero = CharT('0'),

CharT one = CharT('1'));
 (4) (C++11 起)

从数个数据源之一构造新的 bitset ：

1) 默认构造函数。构造所有位设为零的 bitset 。
2) 构造 bitset ，初始化其首（最右、最低） M 位位置为对应 val 的位值，其中 M 是 unsigned long long 的位数和正在构造的 bitset 中的位数 N 的较小者。若 M 小于 N （ bitset 长于 32 (C++11 前)64 (C++11 起) 位，对于典型的 unsigned long (C++11 起)long 实现），则剩余位位置被初始化为零。
3) 用 std::basic_string str 中的字符构造 bitset 。能提供可选的起始位置 pos 和长度 n ，以及指代设置（ one ）和不设置（ zero ）位的替代值的字符。用 Traits::eq() 比较字符值。
初始化字符串的有效长度是 min(n, str.size() - pos) 。
若 pos > str.size() ，则构造函数抛出 std::out_of_range 。若 str 中检验到的任何字符非 zero 或 one ，则抛出 std::invalid_argument 。
4) 同 (3) ，但用 CharT* 代替 std::basic_string 。等价于 bitset(n == basic_string<CharT>::npos ? basic_string<CharT>(str) : basic_string<CharT>(str, n), 0, n, zero, one) 。

参数

val | - | 用于初始化 bitset 的数字
str | - | 用于初始化 bitset 的字符串
pos | - | str 中的起始偏移
n | - | 使用来自 str 的字符数
one | - | 设置位于 str 中的替用字符
zero | - | 不设置位于 str 中的替用字符

异常

3) 若 pos > str.size() 则为 std::out_of_range ，若任何字符非一或零则为 std::invalid_argument
4) std::invalid_argument ，若任何字符非一或零

示例

#include <bitset>
#include <string>
#include <iostream>
#include <climits>

int main()
{
    // 空构造函数
    std::bitset<8> b1; // [0,0,0,0,0,0,0,0]

    // unsigned long long 构造函数
    std::bitset<8> b2(42);          // [0,0,1,0,1,0,1,0]
    std::bitset<70> bl(ULLONG_MAX); // [0,0,0,0,0,0,1,1,1,...,1,1,1] in C++11
    std::bitset<8> bs(0xfff0);      // [1,1,1,1,0,0,0,0]

    // string 构造函数
    std::string bit_string = "110010";
    std::bitset<8> b3(bit_string);       // [0,0,1,1,0,0,1,0]
    std::bitset<8> b4(bit_string, 2);    // [0,0,0,0,0,0,1,0]
    std::bitset<8> b5(bit_string, 2, 3); // [0,0,0,0,0,0,0,1]

    // 使用自定义零/一数字的 string 构造函数
    std::string alpha_bit_string = "aBaaBBaB";
    std::bitset<8> b6(alpha_bit_string, 0, alpha_bit_string.size(),
                      'a', 'B');         // [0,1,0,0,1,1,0,1]

    // 使用自定义数字的 char* 构造函数
    std::bitset<8> b7("XXXXYYYY", 8, 'X', 'Y'); // [0,0,0,0,1,1,1,1]

    std::cout << b1 << '\n' << b2 << '\n' << bl << '\n' << bs << '\n'
              << b3 << '\n' << b4 << '\n' << b5 << '\n' << b6 << '\n'
              << b7 << '\n';
}

可能的输出：

00000000
00101010
0000001111111111111111111111111111111111111111111111111111111111111111
11110000
00110010
00000010
00000001
01001101
00001111

参阅

set | 将位置为 true 或者提供的值 (公开成员函数)
reset | 将位置为 false (公开成员函数)


std::bitset<N>::count

< cpp‎ | utility‎ | bitset
std::size_t count() const; | (C++11 前)
std::size_t count() const noexcept; | (C++11 起)

返回设为 true 的位数。

参数

（无）

返回值

设为 true 的位数。

示例

#include <iostream>
#include <bitset>

int main()
{
    std::bitset<8> b("00010010");
    std::cout << "initial value: " << b << '\n';

    // 寻找首个未设置的位
    std::size_t idx = 0;
    while (idx < b.size() && b.test(idx)) ++idx;

    // 继续设置位直至 bitset 有一半被填充
    while (idx < b.size() && b.count() < b.size()/2) {
        b.set(idx);
        std::cout << "setting bit " << idx << ": " << b << '\n';
        while (idx < b.size() && b.test(idx)) ++idx;
    }

}

输出：

initial value: 00010010
setting bit 0: 00010011
setting bit 2: 00010111

参阅

size | 返回位集保有的位数 (公开成员函数)
popcount (C++20) | 计量无符号整数中为 1 的位的数量 (函数模板)


std::bitset<N>::flip

< cpp‎ | utility‎ | bitset
 | (1)
bitset& flip(); |  | (C++11 前)
bitset& flip() noexcept; |  | (C++11 起)
bitset& flip( std::size_t pos ); | (2)

翻转位，即更改 true 值为 false 并更改 false 值为 true 。等价于在 bitset 一部分或全体上的逻辑非。

1) 翻转所有位（类似 operator~ ，但是在原位）。
2) 翻转在 pos 的位。

参数

pos - 要翻转的位的位置

返回值

*this

异常

2) 若 pos 不对应 bitset 内的合法位置则抛出 std::out_of_range 。

示例

#include <iostream>
#include <bitset>

int main()
{
    std::bitset<4> b;

    std::cout << b << "\n";
    std::cout << b.flip(0) << '\n';
    std::cout << b.flip(2) << '\n';
    std::cout << b.flip() << '\n';
}

输出：

0000
0001
0101
1010

参阅

set | 将位置为 true 或者提供的值 (公开成员函数)
reset | 将位置为 false (公开成员函数)
operator&=operator|=operator^=operator~ | 进行二进制与、或、异或及非 (公开成员函数)


std::hash(std::bitset)

< cpp‎ | utility‎ | bitset
定义于头文件 <bitset> |
template< std::size_t N> struct hash< std::bitset <N>>; | (C++11 起)

std::hash 对 std::bitset <N> 的模板特化允许用户获得 std::bitset <N> 类型的对象的哈希。

示例

下列代码展示用于数个 bitset 上的哈希函数的一种可能输出：

#include <iostream>
#include <bitset>
#include <functional>

int main()
{
    std::bitset<4> b1(1);
    std::bitset<4> b2(2);
    std::bitset<4> b3(b2);

    std::hash<std::bitset<4>> hash_fn;

    std::cout << hash_fn(b1) << '\n';
    std::cout << hash_fn(b2) << '\n';
    std::cout << hash_fn(b3) << '\n';
}

输出：

67918732
118251589
118251589

参阅

hash
(C++11)
 散列函数对象
(类模板)


std::bitset<N>::operator[]

< cpp‎ | utility‎ | bitset
 | (1)
bool operator[]( std::size_t pos ) const; |  | (C++11 前)
constexpr bool operator[]( std::size_t pos ) const; |  | (C++11 起)
reference operator[]( std::size_t pos ); | (2)

访问位于位置 pos 的位。首版本返回位的值，第二版本返回允许修改位的值的 std::bitset::reference 对象。

不同于 test() ，它不抛异常：若 pos 在边界外则行为未定义。

参数

pos - 要返回的位的位置

返回值

1) 请求位的值

2) std::bitset::reference 类型对象，允许写入请求位。

异常

（无）

示例

#include <iostream>
#include <bitset>

int main()
{
    std::bitset<8> b1(42);
    for (std::size_t i = 0; i < b1.size(); ++i) {
        std::cout << "b1[" << i << "]: " << b1[i] << '\n';
    }
    b1[0] = true; // 通过 bitset::reference 修改首位
    std::cout << "After setting bit 0, the bitset holds " << b1 << '\n';
}

输出：

b1[0]: 0
b1[1]: 1
b1[2]: 0
b1[3]: 1
b1[4]: 0
b1[5]: 1
b1[6]: 0
b1[7]: 0
After setting bit 0, the bitset holds 00101011

参阅

test
 访问特定位
(公开成员函数)


std::bitset<N>::operator==, std::bitset<N>::operator!=

< cpp‎ | utility‎ | bitset
 | (1)
bool operator==( const bitset& rhs ) const; |  | (C++11 前)
bool operator==( const bitset& rhs ) const noexcept; |  | (C++11 起)
 | (2)
bool operator!=( const bitset& rhs ) const; |  | (C++11 前)
bool operator!=( const bitset& rhs ) const noexcept; |  | (C++11 起) (C++20 前)
1) 若 *this 与 rhs 中的所有位相等则返回 true 。
2) 若 *this 与 rhs 中的任何位不相等则返回 true 。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

rhs - 要比较的 bitset

返回值

1) 若 *this 中每位都等于 rhs 中对应位的值则为 true ，否则为 false
2) 若 !(*this == rhs) 则为 true ，否则为 false

示例

比较二个 bitset 以确定它们是否等同：

#include <iostream>
#include <bitset>

int main()
{
    std::bitset<4> b1(3); // [0,0,1,1]
    std::bitset<4> b2(b1);
    std::bitset<4> b3(4); // [0,1,0,0]

    std::cout << std::boolalpha;
    std::cout << "b1 == b2: " << (b1 == b2) << '\n';
    std::cout << "b1 == b3: " << (b1 == b3) << '\n';
    std::cout << "b1 != b3: " << (b1 != b3) << '\n';

//  b1 == std::bitset<3>{}; // 编译时错误：不兼容类型
}

输出：

b1 == b2: true
b1 == b3: false
b1 != b3: true


std::bitset<N>::operator&=,|=,^=,~

< cpp‎ | utility‎ | bitset
 | (1)
bitset& operator&=( const bitset& other ); |  | (C++11 前)
bitset& operator&=( const bitset& other ) noexcept; |  | (C++11 起)
 | (2)
bitset& operator|=( const bitset& other ); |  | (C++11 前)
bitset& operator|=( const bitset& other ) noexcept; |  | (C++11 起)
 | (3)
bitset& operator^=( const bitset& other ); |  | (C++11 前)
bitset& operator^=( const bitset& other ) noexcept; |  | (C++11 起)
 | (4)
bitset operator~() const; |  | (C++11 前)
bitset operator~() const noexcept; |  | (C++11 起)

进行二进制与、或、异或及非。

1) 设置位为 *this 与 other 的位的对应对上二进制与的结果。
2) 设置位为 *this 与 other 的位的对应对上二进制或的结果。
3) 设置位为 *this 与 other 的位的对应对上二进制异或的结果。
4) 返回翻转所有位的 *this 的临时副本（二进制非）。

注意 &=、 |= 和 ^= 仅对拥有相同大小 N 的 bitset 定义。

参数

other - 另一 bitset

返回值

1-3) *this 。
4) std::bitset <N>(*this).flip() 。

示例

#include <iostream>
#include <string>
#include <bitset>

int main()
{
    const std::string pattern_str{"1001"};
    std::bitset<16> pattern{pattern_str}, dest;

    for (std::size_t i = dest.size()/pattern_str.size(); i != 0; --i) {
        dest <<= pattern_str.size();
        dest |= pattern;
        std::cout << dest << " (i = " << i << ")\n";
    }

    std::cout << ~dest << " (~dest)\n";
}

输出：

0000000000001001 (i = 4)
0000000010011001 (i = 3)
0000100110011001 (i = 2)
1001100110011001 (i = 1)
0110011001100110 (~dest)

参阅

operator<<=operator>>=operator<<operator>>
 进行二进制左移和右移
(公开成员函数)


operator&,|,^(std::bitset)

< cpp‎ | utility‎ | bitset
定义于头文件 <bitset>
(1)
template< std::size_t N >
std::bitset <N> operator&( const std::bitset <N>& lhs, const std::bitset <N>& rhs );
 (C++11 前)
template< std::size_t N >
std::bitset <N> operator&( const std::bitset <N>& lhs, const std::bitset <N>& rhs ) noexcept;
 (C++11 起)
(2)
template< std::size_t N >
std::bitset <N> operator|( const std::bitset <N>& lhs, const std::bitset <N>& rhs );
 (C++11 前)
template< std::size_t N >
std::bitset <N> operator|( const std::bitset <N>& lhs, const std::bitset <N>& rhs ) noexcept;
 (C++11 起)
(3)
template< std::size_t N >
std::bitset <N> operator^( const std::bitset <N>& lhs, const std::bitset <N>& rhs );
 (C++11 前)
template< std::size_t N >
std::bitset <N> operator^( const std::bitset <N>& lhs, const std::bitset <N>& rhs ) noexcept;
 (C++11 起)

进行二个 bitset lhs 和 rhs 间的二进制与、或及异或。

1) 返回含 lhs 和 rhs 的位对应对上的二进制与结果的 std::bitset <N> 。
2) 返回含 lhs 和 rhs 的位对应对上的二进制或结果的 std::bitset <N> 。
3) 返回含 lhs 和 rhs 的位对应对上的二进制异或结果的 std::bitset <N> 。

参数

lhs | - | 运算符左侧的 bitset
rhs | - | 运算符右侧的 bitset

返回值

1) std::bitset <N>(lhs) &= rhs
2) std::bitset <N>(lhs) |= rhs
3) std::bitset <N>(lhs) ^= rhs

示例

#include <bitset>
#include <iostream>

int main()
{
    std::bitset<4> b1("0110");
    std::bitset<4> b2("0011");
    std::cout << "b1 & b2: " << (b1 & b2) << '\n';
    std::cout << "b1 | b2: " << (b1 | b2) << '\n';
    std::cout << "b1 ^ b2: " << (b1 ^ b2) << '\n';
}

输出：

b1 & b2: 0010
b1 | b2: 0111
b1 ^ b2: 0101

参阅

operator&=operator|=operator^=operator~
 进行二进制与、或、异或及非
(公开成员函数)


std::bitset<N>::operator<<,<<=,>>,>>=

< cpp‎ | utility‎ | bitset
 | (1)
bitset operator<<( std::size_t pos ) const; |  | (C++11 前)
bitset operator<<( std::size_t pos ) const noexcept; |  | (C++11 起)
 | (2)
bitset& operator<<=( std::size_t pos ); |  | (C++11 前)
bitset& operator<<=( std::size_t pos ) noexcept; |  | (C++11 起)
 | (3)
bitset operator>>( std::size_t pos ) const; |  | (C++11 前)
bitset operator>>( std::size_t pos ) const noexcept; |  | (C++11 起)
 | (4)
bitset& operator>>=( std::size_t pos ); |  | (C++11 前)
bitset& operator>>=( std::size_t pos ) noexcept; |  | (C++11 起)

进行二进制左移和二进制右移。移入零。

1-2) 进行二进制左移。 (2) 是破坏性的，即对当前对象进行迁移。
3-4) 进行二进制右移。 (4) 是破坏性的，即对当前对象进行迁移。

参数

pos - 移动位的位置数

返回值

1,3) 含有被迁移位的新 bitset 对象
2,4) *this

示例

#include <iostream>
#include <bitset>

int main()
{
    std::bitset<8> b("01110010");
    std::cout << "initial value: " << b << '\n';

    while (b.any()) {
        while (!b.test(0)) {
            b >>= 1;
        }
        std::cout << b << '\n';
        b >>= 1;
    }
}

输出：

initial value: 01110010
00111001
00000111
00000011
00000001

参阅

rotl (C++20) | 计算逐位左旋转的结果 (函数模板)
rotr (C++20) | 计算逐位右旋转的结果 (函数模板)
operator&=operator|=operator^=operator~ | 进行二进制与、或、异或及非 (公开成员函数)


operator<<,>>(std::bitset)

< cpp‎ | utility‎ | bitset
定义于头文件 <bitset>
template <class CharT, class Traits, size_t N>

std::basic_ostream <CharT, Traits>& operator<<( std::basic_ostream <CharT, Traits>& os,

const std::bitset <N>& x);
 (1)
template <class CharT, class Traits, size_t N>

std::basic_istream <CharT, Traits>& operator>>( std::basic_istream <CharT, Traits>& is,

std::bitset <N>& x);
 (2)

从字符流插入或释出 bitset 。

1) 写 bitset x 入字符流 os ，如同首先用 to_string() 将它转换成 std::basic_string <CharT,Traits> ，再用 operator<< （对字符串是有格式输出函数 (FormattedOutputFunction) ）将它写入 os 。为一与零使用的字符，通过以 '1' 和 '0' 为参数调用 std::use_facet < std::ctype <CharT>(os.getloc()).widen() 从当前感染的本地环境获得。
2) 表现为有格式输入函数 (FormattedInputFunction) 。构造并检查 sentry 对象，这可能跳过前导空白符，之后从 is 释出至多 N 个字符，并存储字符于 bitset x 。

释出字符直至

  • 已读取 N 个字符
  • 文件尾发生于 is ，或
  • 下个字符既非 is.widen('0') 亦非 is.widen('1') 。

若 N > 0 且未释出字符，则调用 is.setstate(ios_base::failbit) 。

参数

os | - | 要写入的字符流
is | - | 要读取的字符流
x | - | 要读取或写入的 bitset

返回值

操作于上的字符流，例如 os 或 is 。

示例

#include <bitset>
#include <iostream>
#include <sstream>

int main()
{
    std::string bit_string = "001101";
    std::istringstream bit_stream(bit_string);

    std::bitset<3> b1;
    bit_stream >> b1; // 读取 "001" ，流仍保有 "101"
    std::cout << b1 << '\n';

    std::bitset<8> b2;
    bit_stream >> b2; // 读取 "101" ，产出 8 位集为 "00000101"
    std::cout << b2 << '\n';
}

输出：

001
00000101

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3199 | C++98 | 释出 std::bitset<0> 始终设置 failbit | 这种释出始终不设置 failbit

参阅

operator<<=operator>>=operator<<operator>>
 进行二进制左移和右移
(公开成员函数)


std::bitset<N>::reference

< cpp‎ | utility‎ | bitset
class reference;

std::bitset 类包含 std::bitset::reference 作为可公开访问的嵌套类。此类用作允许用户与 bitset 的单个位交互的代理对象，因为标准 C++ 类型（如引用和指针）没有内建指定单个位的足够精度。

std::bitset::reference 的基本用途是提供能从 operator[] 返回的左值。

任何通过 std::bitset::reference 对 bitset 的读或写潜在地读或写整个底层 bitset 。

成员函数

(构造函数) | 构造引用。只对 std::bitset 自身可访问 (私有成员函数)
(析构函数) | 销毁引用 (公开成员函数)
operator= | 赋值 bool 给被引用位 (公开成员函数)
operator bool | 返回被引用位 (公开成员函数)
operator~ | 返回翻转的被引用位 (公开成员函数)
flip | 翻转被引用位 (公开成员函数)

std::bitset<N>::reference::~reference

~reference();

销毁引用。

std::bitset<N>::reference::operator=

 | (1)
reference& operator=( bool x ); |  | (C++11 前)
reference& operator=( bool x ) noexcept; |  | (C++11 起)
 | (2)
reference& operator=( const reference& x ); |  | (C++11 前)
reference& operator=( const reference& x ) noexcept; |  | (C++11 起)

赋值给被引用位。

参数

x - 要赋值的值

返回值

*this

std::bitset<N>::reference::operator bool

operator bool() const; | (C++11 前)
operator bool() const noexcept; | (C++11 起)

返回被引用位的值。

参数

（无）

返回值

被引用位。

std::bitset<N>::reference::operator~

bool operator~() const; | (C++11 前)
bool operator~() const noexcept; | (C++11 起)

返回被引用位的翻转。

参数

（无）

返回值

被引用位的翻转。

std::bitset<N>::reference::flip

reference& flip(); | (C++11 前)
reference& flip() noexcept; | (C++11 起)

翻转被引用位。

参数

（无）

返回值

*this

示例

#include <bitset>
#include <iostream>

int main()
{
    std::bitset<4> bs( 0b1110 );

    std::bitset<4>::reference ref = bs[2]; // auto ref = bs[2];

    auto info = [&](int n) {
        std::cout << n << ") bs: " << bs << "; ref bit: " << ref << '\n';
    };

    info(1);
    ref = false;
    info(2);
    ref = true;
    info(3);
    ref.flip();
    info(4);
    ref = bs[1]; // operator=( const reference& x )
    info(5);

    std::cout << "6) ~ref bit: " << ~ref << '\n';
}

输出：

1) bs: 1110; ref bit: 1
2) bs: 1010; ref bit: 0
3) bs: 1110; ref bit: 1
4) bs: 1010; ref bit: 0
5) bs: 1110; ref bit: 1
6) ~ref bit: 0

参阅

operator[]
 访问指定的位
(公开成员函数)


std::bitset<N>::reset

< cpp‎ | utility‎ | bitset
 | (1)
bitset& reset(); |  | (C++11 前)
bitset& reset() noexcept; |  | (C++11 起)
bitset& reset( std::size_t pos ); | (2)

设置位为 false 。

1) 设置所有位为 false 。
2) 设置在 pos 的位为 false 。

参数

pos - 要设置的位的位置

返回值

*this

异常

2) 若 pos 不对应 bitset 内合法的位置则抛出 std::out_of_range

示例

#include <iostream>
#include <bitset>

int main()
{
    std::bitset<8> b(42);
    std::cout << "Bitset is         " << b << '\n';
    b.reset(1);
    std::cout << "After b.reset(1): " << b << '\n';
    b.reset();
    std::cout << "After b.reset():  " << b << '\n';
}

输出：

Bitset is         00101010
After b.reset(1): 00101000
After b.reset():  00000000

参阅

set | 将位置为 true 或者提供的值 (公开成员函数)
flip | 翻转位的值 (公开成员函数)


std::bitset<N>::set

< cpp‎ | utility‎ | bitset
 | (1)
bitset& set(); |  | (C++11 前)
bitset& set() noexcept; |  | (C++11 起)
bitset& set( std::size_t pos, bool value = true ); | (2)

设置所有位为 true 或到指定值。

1) 设置所有位为 true 。
2) 设置在 pos 的位为值 value 。

参数

pos | - | 要设置的位的位置（从最低到最高）
value | - | 对位设置的值

返回值

*this

异常

2) 若 pos 不对应 bitset 内的合法位置则抛出 std::out_of_range 。

示例

#include <iostream>
#include <bitset>

int main()
{
    std::bitset<8> b;
    for (size_t i = 1; i < b.size(); i += 2) {
        b.set(i);
    }
    std::cout << b << '\n';
}

输出：

10101010

参阅

reset | 将位置为 false (公开成员函数)
flip | 翻转位的值 (公开成员函数)


std::bitset<N>::size

< cpp‎ | utility‎ | bitset
std::size_t size() const; | (C++11 前)
constexpr std::size_t size() const noexcept; | (C++11 起)

返回 bitset 所保有的位数。

参数

（无）

返回值

bitset 所保有的位数，即模板形参 N 。

示例

#include <bitset>
#include <iostream>

int main() {
    std::cout << std::bitset<0x400>().size() << '\n';
}

输出：

1024

参阅

count
 返回设置为 true 的位的数量
(公开成员函数)


std::bitset<N>::test

< cpp‎ | utility‎ | bitset
bool test( std::size_t pos ) const;

返回位于位置 pos 的位的值。

不同于 operator[] ，它进行边界检查，且若 pos 不对应 bitset 中的合法位置则抛出 std::out_of_range 。

参数

pos - 要返回的位的位置

返回值

若所求位被设置则为 true ，否则为 false 。

异常

若 pos 不对应 bitset 中的合法位置则抛出 std::out_of_range 。

示例

#include <iostream>
#include <bitset>

int main()
{
    std::bitset<10> b1("1111010000");

    std::size_t idx = 0;
    while (idx < b1.size() && !b1.test(idx)) {
      ++idx;
    }

    if (idx < b1.size()) {
        std::cout << "first set bit at index " << idx << '\n';
    } else {
        std::cout << "no set bits\n";
    }
}

输出：

first set bit at index 4

参阅

operator[] | 访问指定的位 (公开成员函数)
popcount (C++20) | 计量无符号整数中为 1 的位的数量 (函数模板)
has_single_bit (C++20) | 检查一个数是否为二的整数次幂 (函数模板)


std::bitset<N>::to_string

< cpp‎ | utility‎ | bitset
template<

class CharT,
class Traits,
class Alloc

> std::basic_string <CharT,Traits,Allocator> to_string() const;
 (C++11 前)
template<

class CharT = char,
class Traits = std::char_traits <CharT>,
class Allocator = std::allocator <CharT>
> std::basic_string <CharT,Traits,Allocator>

to_string(CharT zero = CharT('0'), CharT one = CharT('1')) const;
 (C++11 起)

转换 bitset 的内容为 string 。用 zero 表示拥有值 false 的位，以 one 表示拥有值 true 的位。

产生的字符串含 N 个字符，其首字符对应最末（第 N-1 ）位而其尾字符对应首位。

参数

zero | - | 用于表示 false 的字符
one | - | 用于表示 true 的字符

返回值

转换出的字符串

异常

可能从 std::string 构造函数抛出 std::bad_alloc 。

示例

#include <iostream>
#include <bitset>
int main()
{
    std::bitset<8> b(42);
    std::cout << b.to_string() << '\n'
              << b.to_string('*') << '\n'
              << b.to_string('O', 'X') << '\n';
}

输出：

00101010
**1*1*1*
OOXOXOXO

参阅

to_ulong | 返回数据的 unsigned long 整数表示 (公开成员函数)
to_ullong (C++11) | 返回数据的 unsigned long long 整数表示 (公开成员函数)


std::bitset<N>::to_ullong

< cpp‎ | utility‎ | bitset
unsigned long long to_ullong() const | (C++11 起)

转换 bitset 的内容为 unsigned long long 整数。

bitset 的首位对应数的最低位，而尾位对应最高位。

参数

（无）

返回值

转换出的整数

异常

若值不能以 unsigned long long 表示则为 std::overflow_error 。

示例

#include <iostream>
#include <bitset>
#include <limits>

int main()
{
    std::bitset<std::numeric_limits<unsigned long long>::digits> b(
        0x123456789abcdef0LL
    );

    std::cout << b << "  " << std::hex << b.to_ullong() << '\n';
    b.flip();
    std::cout << b << "  " << b.to_ullong() << '\n';
}

输出：

0001001000110100010101100111100010011010101111001101111011110000  123456789abcdef0
1110110111001011101010011000011101100101010000110010000100001111  edcba9876543210f

参阅

to_string | 返回数据的字符串表示 (公开成员函数)
to_ulong | 返回数据的 unsigned long 整数表示 (公开成员函数)


std::bitset<N>::to_ulong

< cpp‎ | utility‎ | bitset
unsigned long to_ulong() const

转换 bitset 的内容为 unsigned long 整数。

bitset 的首位对应数的最低位，而尾位对应最高位。

参数

（无）

返回值

转换出的整数

异常

若值不能以 unsigned long 表示则抛出 std::overflow_error 。

示例

#include <iostream>
#include <bitset>

int main()
{
    for (unsigned long i = 0; i < 10; ++i) {
        std::bitset<5> b(i);
        std::bitset<5> b_inverted = ~b;
        std::cout << i << '\t';
        std::cout << b << '\t';
        std::cout << b_inverted << '\t';
        std::cout << b_inverted.to_ulong() << '\n';
    }
}

输出：

0      00000   11111   31
1       00001   11110   30
2       00010   11101   29
3       00011   11100   28
4       00100   11011   27
5       00101   11010   26
6       00110   11001   25
7       00111   11000   24
8       01000   10111   23
9       01001   10110   22

参阅

to_string | 返回数据的字符串表示 (公开成员函数)
to_ullong (C++11) | 返回数据的 unsigned long long 整数表示 (公开成员函数)


std::chars_format

< cpp‎ | utility
定义于头文件 <charconv> |
enum class chars_format { scientific = /*unspecified*/, fixed = /*unspecified*/, hex = /*unspecified*/, general = fixed | scientific }; | (C++17 起)

用于为 std::to_chars 及 std::from_chars 指定浮点格式的位掩码类型 (BitmaskType) 。

参阅

to_chars (C++17) | 转换整数或浮点值到字符序列 (函数)
from_chars (C++17) | 转换字符序列到整数或浮点值 (函数)


std::common_comparison_category

< cpp‎ | utility
定义于头文件 <compare>
template<class... Ts>

struct common_comparison_category {
using type = /*see below*/ ;

};
 (C++20 起)

类模板 std::common_comparison_category 为所有模板实参 Ts... 所能转换到的最强比较类别提供别名（作为成员 typedef type ）。

详细而言， n 个类型 T0...Tn-1 的公共比较类型 U 定义如下：

  • 若任何 Ti 不是比较类别类型（ std::partial_ordering 、 std::weak_ordering 、 std::strong_ordering ），则 U 为 void 。
  • 否则，若至少一个 Ti 为 std::partial_ordering ，则 U 为 std::partial_ordering
  • 否则，若至少一个 Ti 为 std::weak_ordering ，则 U 为 std::weak_ordering
  • 否则（若每个 Ti 均为 std::strong_ordering 或列表为空），则 U 为 std::strong_ordering 。

模板形参

...Ts - 可为空的类型列表

辅助模板

template< class... Ts > using common_comparison_category_t = typename common_comparison_category<Ts...>::type; | (C++20 起)

成员类型

成员类型 | 定义
type | 最强的公共比较类别（定义如上）

可能的实现

namespace detail {

template<unsigned int>
struct common_cmpcat_base     { using type = void; };
template<>
struct common_cmpcat_base<0u> { using type = std::strong_ordering; };
template<>
struct common_cmpcat_base<2u> { using type = std::partial_ordering; };
template<>
struct common_cmpcat_base<4u> { using type = std::weak_ordering; };
template<>
struct common_cmpcat_base<6u> { using type = std::partial_ordering; };

} // namespace detail

template<class...Ts>
struct common_comparison_category :
    detail::common_cmpcat_base<(0u | ... |
        (std::is_same_v<Ts, std::strong_ordering>  ? 0u :
         std::is_same_v<Ts, std::weak_ordering>    ? 4u :
         std::is_same_v<Ts, std::partial_ordering> ? 2u : 1u)
    )> {};

示例

本节未完成
原因：暂无示例

参阅

strong_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符且可替换 (类)
weak_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符且不可替换 (类)
partial_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符，不可替换，并允许不可比较的值 (类)


std::compare_partial_order_fallback

< cpp‎ | utility
定义于头文件 <compare>
inline namespace /* unspecified */ {

inline constexpr /* unspecified */
compare_partial_order_fallback = /* unspecified */;

}
 (C++20 起)
调用签名
template< class T, class U >

requires /* see below */
constexpr std::partial_ordering

compare_partial_order_fallback(T&& t, U&& u) noexcept(/* see below */);

进行 t 与 u 上的三路比较并产生 std::partial_ordering 类型值，即使运算符 <=> 不可用。

设 t 与 u 为表达式而 T 与 U 分别代表 decltype((t)) 与 decltype((u)) ，则 std::compare_partial_order_fallback(t, u) 表达式等价于：

  • 若 std::is_same_v < std::decay_t <T>, std::decay_t <U>> 为 true ：
    • std::partial_order(t, u) ，若它为良构表达式；
    • 否则，为
t == u ? std::partial_ordering::equivalent :
t < u  ? std::partial_ordering::less :
u < t  ? std::partial_ordering::greater :
         std::partial_ordering::unordered
若 t == u、 t < u 与 u < t 均良构且可转换为 bool ，除了只求值 t 与 u 一次。
  • 所有其他情况下， std::compare_partial_order_fallback(t, u) 为非良构，这能在出现于模板实例化的立即语境时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 std::compare_partial_order_fallback 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __compare_partial_order_fallback_fn 表示其类型的 cv 无限定版本。

__compare_partial_order_fallback_fn 的所有实例均相等。在相同参数上调用类型 __compare_partial_order_fallback_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 std::compare_partial_order_fallback 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 std::compare_partial_order_fallback 的参数要求，则 __compare_partial_order_fallback_fn 实现 std::invocable<__compare_partial_order_fallback_fn, Args...>、 std::invocable<const __compare_partial_order_fallback_fn, Args...>、 std::invocable<__compare_partial_order_fallback_fn&, Args...> 及 std::invocable<const __compare_partial_order_fallback_fn&, Args...> 。否则， __compare_partial_order_fallback_fn 的函数调用运算符不参与重载决议。

示例

本节未完成
原因：暂无示例

参阅

partial_order
(C++20)
 进行三路比较并产生 std::partial_ordering 类型结果
(定制点对象)


std::compare_strong_order_fallback

< cpp‎ | utility
定义于头文件 <compare>
inline namespace /* unspecified */ {

inline constexpr /* unspecified */
compare_strong_order_fallback = /* unspecified */;

}
 (C++20 起)
调用签名
template< class T, class U >

requires /* see below */
constexpr std::strong_ordering

compare_strong_order_fallback(T&& t, U&& u) noexcept(/* see below */);

进行 t 与 u 上的三路比较并产生 std::strong_ordering 类型结果，即使运算符 <=> 不可用。

令 t 与 u 为表达式且 T 与 U 分别代表 decltype((t)) 与 decltype((u)) ，则 std::compare_strong_order_fallback(t, u) 表达式等价于：

  • 若 std::is_same_v < std::decay_t <T>, std::decay_t <U>> 为 true ：
    • std::strong_order(t, u) ，若它为良构；
    • 否则为
t == u ? std::strong_ordering::equal :
t < u  ? std::strong_ordering::less :
         std::strong_ordering::greater
若 t == u 与 t < u 均为良构且可转换为 bool ，除了仅求值 t 与 u 一次。
  • 所有其他情况下， std::compare_strong_order_fallback(t, u) 为非良构，这能在出现于模板实例化的立即语境时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 std::compare_strong_order_fallback 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __compare_strong_order_fallback_fn 表示其类型的 cv 无限定版本。

__compare_strong_order_fallback_fn 的所有实例均相等。在相同参数上调用类型 __compare_strong_order_fallback_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 std::compare_strong_order_fallback 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 std::compare_strong_order_fallback 的参数要求，则 __compare_strong_order_fallback_fn 实现 std::invocable<__compare_strong_order_fallback_fn, Args...>、 std::invocable<const __compare_strong_order_fallback_fn, Args...>、 std::invocable<__compare_strong_order_fallback_fn&, Args...> 及 std::invocable<const __compare_strong_order_fallback_fn&, Args...> 。否则， __compare_strong_order_fallback_fn 的函数调用运算符不参与重载决议。

示例

本节未完成
原因：暂无示例

参阅

strong_order
(C++20)
 进行三路比较并产生 std::strong_ordering 类型结果
(定制点对象)


std::compare_three_way

< cpp‎ | utility
定义于头文件 <compare> |
定义于头文件 <functional> |
struct compare_three_way; | (C++20 起)

进行比较的函数对象。从实参类型推导函数调用运算符的形参类型与返回类型。

实现定义的指针上的严格全序

若参数间的 <=> 运算符调用指针的内建比较运算符，则函数调用运算符产生实现定义的指针上的严格全序，即使内建的 <=> 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 <、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void 时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way

成员类型

成员类型 | 定义
is_transparent | /* 未指明 */

成员函数

operator()
 获得两个参数上的三路比较结果
(公开成员函数)

std::compare_three_way::operator()

template<class T, class U>

requires std::three_way_comparable_with<T, U> // 有不同的语义要求

constexpr auto operator()(T&& t, U&& u) const;

比较 t 与 u ，等价于 return std::forward <T>(t) <=> std::forward <U>(u); ，除非该表达式解析到调用比较指针的内建 operator<=> 。

当函数调用不调用内建的比较指针的运算符时，若 std::three_way_comparable_with<T, U> 未得到满足则行为未定义。

当函数调用会使用比较 P 类型指针的内建运算符时，替而以下列方式确定结果：

  • 若第一参数的（可能为转换后的）值在 P 类型的所有指针值上的实现定义严格全序中前趋第二参数的（可能为转换后的）值，则返回 std::strong_ordering::less 。此严格全序与内建运算符 < 、 > 、 <= 及 >= 所施加的偏序一致。
  • 否则，若第二参数的（可能为转换后的）值在同一严格全序中前趋第一参数的（可能为转换后的）值，则返回 std::strong_ordering::greater 。
  • 否则返回 std::strong_ordering::equal 。

行为未定义，除非从 T 和 U 到 P 的转换序列均保持相等性（见后述）。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

示例

#include <iostream>
#include <compare>

struct Rational_2 {
    int num;
    int den; // > 0
};

constexpr std::weak_ordering operator<=>(Rational_2 lhs, Rational_2 rhs)
{
    return lhs.num * rhs.den <=> rhs.num * lhs.den;
}

void print(std::weak_ordering value)
{
    if (value == 0)
        std::cout << "equal\n";
    else if (value < 0)
        std::cout << "less\n";
    else
        std::cout << "greater\n";
}

int main()
{
    Rational_2 c{6,5};
    Rational_2 d{8,7};
    print(c <=> d);
    print(std::compare_three_way{}(c,d));
}

输出：

greater
greater

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3530 | C++20 | 在比较指针时放松了语法检查 | 仅放松语义要求

参阅

ranges::equal_to (C++20) | 实现 x == y 的函数对象 (类)
ranges::not_equal_to (C++20) | 实现 x != y 的函数对象 (类)
ranges::less (C++20) | 实现 x < y 的函数对象 (类)
ranges::greater (C++20) | 实现 x > y 的函数对象 (类)
ranges::less_equal (C++20) | 实现 x <= y 的函数对象 (类)
ranges::greater_equal (C++20) | 实现 x >= y 的函数对象 (类)


std::compare_three_way_result

< cpp‎ | utility
定义于头文件 <compare> |
template<class T, class U = T> struct compare_three_way_result; | (C++20 起)

令 t 与 u 分别代表 const std::remove_reference_t <T> 与 const std::remove_reference_t <U> 类型的左值，若表达式 t <=> u 良构，则提供等于 decltype(t <=> u) 的成员 typedef type ，否则无成员 type 。

添加 compare_three_way_result 的特化的程序行为未定义。

成员类型

名字 | 定义
type | operator<=> 在 T 与 U 的 const 限定左值上的结果类型

辅助类型

template<class T, class U = T> using compare_three_way_result_t = typename compare_three_way_result<T>::type; | (C++20 起)

可能的实现

// 由 Casey Carter 推荐
// 参阅： https://github.com/microsoft/STL/pull/385#discussion_r357894054
template<class T, class U = T>
using compare_three_way_result_t = decltype(
    std::declval<const std::remove_reference_t<T>&>() <=>
    std::declval<const std::remove_reference_t<U>&>()
);

template<class T, class U = T>
struct compare_three_way_result {};

template<class T, class U>
    requires requires { typename compare_three_way_result_t<T, U>; }
struct compare_three_way_result {
    using type = compare_three_way_result_t<T, U>;
};

示例

#include <compare>
#include <type_traits>
#include <iostream>

template <class Ord>
void print_cmp_type()
{
    if constexpr (std::is_same_v<Ord, std::strong_ordering>)
        std::cout << "strong ordering\n";
    else if constexpr (std::is_same_v<Ord, std::weak_ordering>)
        std::cout << "weak ordering\n";
    else if constexpr (std::is_same_v<Ord, std::partial_ordering>)
        std::cout << "partial ordering\n";
    else
        std::cout << "illegal comparison result type\n";
}

int main()
{
    print_cmp_type<std::compare_three_way_result_t<int>>();
    print_cmp_type<std::compare_three_way_result_t<double>>();
}

输出：

strong ordering
partial ordering

参阅

partial_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符，不可替换，并允许不可比较的值 (类)
weak_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符且不可替换 (类)
strong_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符且可替换 (类)


std::compare_weak_order_fallback

< cpp‎ | utility
定义于头文件 <compare>
inline namespace /* unspecified */ {

inline constexpr /* unspecified */
compare_weak_order_fallback = /* unspecified */;

}
 (C++20 起)
调用签名
template< class T, class U >

requires /* see below */
constexpr std::weak_ordering

compare_weak_order_fallback(T&& t, U&& u) noexcept(/* see below */);

进行 t 与 u 上的三路比较并产生 std::weak_ordering 类型结果，即使运算符 <=> 不可用。

设 t 与 u 为表达式而 T 与 U 分别代表 decltype((t)) 与 decltype((u)) ， std::compare_weak_order_fallback(t, u) 表达式等价于：

  • 若 std::is_same_v < std::decay_t <T>, std::decay_t <U>> 为 true ：
    • std::weak_order(t, u) ，若它为良构的表达式；
    • 否则，为
t == u ? std::weak_ordering::equivalent :
t < u  ? std::weak_ordering::less :
         std::weak_ordering::greater
若 t == u 与 t < u 均为良构且可转换到 bool ，除了只求值 t 与 u 一次。
  • 所有其他情况下 std::compare_weak_order_fallback(t, u) 为非良构，这能在出现于模板实例化的立即语境时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 std::compare_weak_order_fallback 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __compare_weak_order_fallback_fn 表示其类型的 cv 无限定版本。

__compare_weak_order_fallback_fn 的所有实例均相等。在相同参数上调用类型 __compare_weak_order_fallback_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 std::compare_weak_order_fallback 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 std::compare_weak_order_fallback 的参数要求，则 __compare_weak_order_fallback_fn 实现 std::invocable<__compare_weak_order_fallback_fn, Args...>、 std::invocable<const __compare_weak_order_fallback_fn, Args...>、 std::invocable<__compare_weak_order_fallback_fn&, Args...> 及 std::invocable<const __compare_weak_order_fallback_fn&, Args...> 。否则， __compare_weak_order_fallback_fn 的函数调用运算符不参与重载决议。

示例

#include <iostream>
#include <compare>

// 不支持 <=>
struct Rational_1 {
    int num;
    int den; // > 0
};

inline constexpr bool operator<(Rational_1 lhs, Rational_1 rhs)
{
    return lhs.num * rhs.den < rhs.num * lhs.den;
}

inline constexpr bool operator==(Rational_1 lhs, Rational_1 rhs)
{
    return lhs.num * rhs.den == rhs.num * lhs.den;
}

// 支持 <=>
struct Rational_2 {
    int num;
    int den; // > 0
};

inline constexpr std::weak_ordering operator<=>(Rational_2 lhs, Rational_2 rhs)
{
    return lhs.num * rhs.den <=> rhs.num * lhs.den;
}

void print(std::weak_ordering value)
{
    if (value == 0)
        std::cout << "equal\n";
    else if (value < 0)
        std::cout << "less\n";
    else
        std::cout << "greater\n";
}

int main()
{
    Rational_1 a{1, 2};
    Rational_1 b{3, 4};
//  print(a <=> b);                // 不起效
    print(std::compare_weak_order_fallback(a, b)); // 起效，默认到 < 与 ==

    Rational_2 c{6, 5};
    Rational_2 d{8, 7};
    print(c <=> d);                // 起效
    print(std::compare_weak_order_fallback(c, d)); // 起效
}

输出：

less
greater
greater

参阅

weak_order
(C++20)
 进行三路比较并产生 std::weak_ordering 类型结果
(定制点对象)


std::is_eq, std::is_neq, std::is_lt, std::is_gt, std::is_lteq, std::is_gteq

< cpp‎ | utility
定义于头文件 <compare> |  |
constexpr bool is_eq(std::partial_ordering cmp) noexcept; | (1) | (C++20 起)
constexpr bool is_neq(std::partial_ordering cmp) noexcept; | (2) | (C++20 起)
constexpr bool is_lt(std::partial_ordering cmp) noexcept; | (3) | (C++20 起)
constexpr bool is_lteq(std::partial_ordering cmp) noexcept; | (4) | (C++20 起)
constexpr bool is_gt(std::partial_ordering cmp) noexcept; | (5) | (C++20 起)
constexpr bool is_gteq(std::partial_ordering cmp) noexcept | (6) | (C++20 起)

这些函数取三路比较的结果，并转换为六个关系运算符的结果之一。

具体而言，这些函数返回

1) cmp == 0
2) cmp != 0
3) cmp < 0
4) cmp <= 0
5) cmp > 0
6) cmp >= 0

参数

cmp - 三路比较结果

返回值

对应比较关系的 bool 结果

示例

本节未完成
原因：暂无示例

参阅

partial_ordering
(C++20)
 三路比较的结果类型，支持所有 6 种运算符，不可替换，并允许不可比较的值
(类)


std::partial_order

< cpp‎ | utility
定义于头文件 <compare>
inline namespace /* unspecified */ {

inline constexpr /* unspecified */ partial_order = /* unspecified */;

}
 (C++20 起)
调用签名
template< class T, class U >

requires /* see below */
constexpr std::partial_ordering

partial_order(T&& t, U&& u) noexcept(/* see below */);

用三路比较比较二个值并产生 std::partial_ordering 类型结果。

设 t 与 u 为表达式而 T 与 U 分别代表 decltype((t)) 与 decltype((u)) ，则 std::partial_order(t, u) 表达式等价于：

  • 若 std::is_same_v < std::decay_t <T>, std::decay_t <U>> 为 true ：
    • std::partial_ordering(partial_order(t, u)) ，若它在不包含 std::partial_order 的声明的语境中进行重载决议的情况下为良构的表达式，
    • 否则为 std::partial_ordering(std::compare_three_way()(t, u)) ，若它为良构，
    • 否则为 std::partial_ordering(std::weak_order(t, u)) ，若它为良构。
  • 所有其他情况下，该表达式为非良构，这能在出现于模板实例化的立即语境时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 std::partial_order 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __partial_order_fn 表示其类型的 cv 无限定版本。

__partial_order_fn 的所有实例均相等。在相同参数上调用类型 __partial_order_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 std::partial_order 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 std::partial_order 的参数要求，则 __partial_order_fn 实现 std::invocable<__partial_order_fn, Args...>、 std::invocable<const __partial_order_fn, Args...>、 std::invocable<__partial_order_fn&, Args...> 及 std::invocable<const __partial_order_fn&, Args...> 。否则， __partial_order_fn 的函数调用运算符不参与重载决议。

注解

示例

本节未完成
原因：暂无示例

参阅

partial_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符，不可替换，并允许不可比较的值 (类)
strong_order (C++20) | 进行三路比较并产生 std::strong_ordering 类型结果 (定制点对象)
weak_order (C++20) | 进行三路比较并产生 std::weak_ordering 类型结果 (定制点对象)
compare_partial_order_fallback (C++20) | 进行三路比较并产生 std::partial_ordering 类型的结果，即使 operator<=> 不可用 (定制点对象)


std::partial_ordering

< cpp‎ | utility
定义于头文件 <compare> |
class partial_ordering; | (C++20 起)

类类型 std::partial_ordering 是这种三路比较的结果类型：

  • 接纳所有六个关系运算符（ == 、 != 、 < 、 <= 、 > 、 >= ）
  • 不隐含可替换性：若 a 等价于 b ，则 f(a) 可能不等价于 f(b) 。这里 f 所指代的函数仅可经由参数的公开 const 成员读取显著的比较状态。换言之，等价的值可能可区别。
  • 接纳不可比较值： a < b 、 a == b 和 a > b 可以均为 false

常量

类型 std::partial_ordering 拥有四个合法值，实现为其类型的 const 静态数据成员：

成员常量 | 定义
less(inline constexpr) [静态] | std::partial_ordering 类型合法值，指示小于（先序）关系 (公开静态成员常量)
equivalent(inline constexpr) [静态] | std::partial_ordering 类型合法值，指示等价（既非先序亦非后序） (公开静态成员常量)
greater(inline constexpr) [静态] | std::partial_ordering 类型合法值，指示大于（后序）关系 (公开静态成员常量)
unordered(inline constexpr) [静态] | std::partial_ordering 类型合法值，指示与不可比较值的关系 (公开静态成员常量)

转换

std::partial_ordering 不可隐式转换其他比较类别类型，而 std::strong_ordering 和 std::weak_ordering 均可隐式转换为 partial_ordering 。

比较

比较运算符在此类型值和字面量 ​0​ 间定义。这支持用表达式 a <=> b == 0 或 a <=> b < 0 转换三路比较的结果为布尔关系；见 std::is_eq 、 std::is_lt 等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::partial_ordering 为参数的关联类时由实参依赖查找找到。

若程序试图将 partial_ordering 与任何异于整数字面量 ​0​ 的内容比较，则其行为未定义。

operator==operator<operator>operator<=operator>=operator<=>
 与零或 partial_ordering 比较
(函数)

operator==

friend constexpr bool operator==(partial_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator==(partial_ordering v, partial_ordering w) noexcept = default; | (2)

参数

v, w | - | 要检查的 std::partial_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 equivalent 则为 true ，而若 v 为 unordered 、 less 或 greater 则为 false 。
2) 若两个参数持有相同值则为 true ，否则为 false 。

operator<

friend constexpr bool operator<(partial_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator<(/*unspecified*/ u, partial_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::partial_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 less 则为 true ，而若 v 为 greater 、 equivalent 或 unordered 则为 false 。
2) 若 v 为 greater 则为 true ，而若 v 为 less 、 equivalent 或 unordered 则为 false 。

operator<=

friend constexpr bool operator<=(partial_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator<=(/*unspecified*/ u, partial_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::partial_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 less 或 equivalent 则为 true ，而若 v 为 greater 或 unordered 则为 false 。
2) 若 v 为 greater 或 equivalent 则为 true ，而若 v 为 less 或 unordered 则为 false 。

operator>

friend constexpr bool operator>(partial_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator>(/*unspecified*/ u, partial_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::partial_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 greater 则为 true ，而若 v 为 less 、 equivalent 或 unordered 则为 false 。
2) 若 v 为 less 则为 true ，而若 v 为 greater 、 equivalent 或 unordered 则为 false 。

operator>=

friend constexpr bool operator>=(partial_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator>=(/*unspecified*/ u, partial_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::partial_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 greater 或 equivalent 则为 true ，而若 v 为 less 或 unordered 则为 false 。
2) 若 v 为 less 或 equivalent 则为 true ，而若 v 为 greater 或 unordered 则为 false 。

operator<=>

friend constexpr partial_ordering operator<=>(partial_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr partial_ordering operator<=>(/*unspecified*/ u, partial_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::partial_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) v 。
2) 若 v 为 less 则为 greater ，若 v 为 greater 则为 less ，否则为 v 。

注意

浮点值之间的内建运算符 <=> 使用此顺序：正零与负零比较为 equivalent ，但能辨别，而 NaN 值与任何其他值比较为 unordered 。

示例

本节未完成
原因：暂无示例

参阅

strong_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符且可替换 (类)
weak_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符且不可替换 (类)


std::strong_order

< cpp‎ | utility
定义于头文件 <compare>
inline namespace /* unspecified */ {

inline constexpr /* unspecified */ strong_order = /* unspecified */;

}
 (C++20 起)
调用签名
template< class T, class U >

requires /* see below */

constexpr std::strong_ordering strong_order(T&& t, U&& u) noexcept(/* see below */);

用三路比较比较二个值并产生 std::strong_ordering 类型结果。

设 t 与 u 为表达式， T 与 U 分别指代 decltype((t)) 与 decltype((u)) ，则 std::strong_order(t, u) 表达式等价于：

  • 若 std::is_same_v < std::decay_t <T>, std::decay_t <U>> 为 true ：
    • std::strong_ordering(strong_order(t, u)) ，若在不包含 std::strong_order 的声明的语境中进行重载决议的情况下该表达式为良构，
    • 否则，若 T 为浮点类型：
      • 若 std::numeric_limits <T>::is_iec559 为 true ，则进行浮点值的 ISO/IEC/IEEE 60559 totalOrder 比较并返回 std::strong_ordering 类型值作为结果（注意：此比较能区别正与负零及有不同表示的 NaN ），
      • 否则，产生与 T 的比较运算符所观察的顺序一致的 std::strong_ordering 类型值，
    • 否则为 std::strong_ordering(std::compare_three_way()(t, u)) ，若它为良构。
  • 所有其他情况下，表达式为非良构，这能在出现于模板实例化的立即语境时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 std::strong_order 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __strong_order_fn 表示其类型的 cv 无限定版本。

__strong_order_fn 的所有实例均相等。在相同参数上调用类型 __strong_order_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 std::strong_order 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 std::strong_order 的参数要求，则 __strong_order_fn 实现 std::invocable<__strong_order_fn, Args...>、 std::invocable<const __strong_order_fn, Args...>、 std::invocable<__strong_order_fn&, Args...> 及 std::invocable<const __strong_order_fn&, Args...> 。否则， __strong_order_fn 的函数调用运算符不参与重载决议。

注解

IEEE 浮点类型的严格全序

令 x 与 y 为相同 IEEE 浮点类型的值，而 total_order_less(x, y) 为指示在 ISO/IEC/IEEE 60559 中的 totalOrder 所定义的严格全序中 x 是否前趋于 y 的布尔结果。

total_order_less(x, y) || total_order_less(y, x) == false 当且仅当 x 与 y 拥有同一位模式。

  • 若 x 与 y 均非 NaN ：
    • 若 x < y ，则 total_order_less(x, y) == true ；
    • 若 x > y ，则 total_order_less(x, y) == false ；
    • 若 x == y ，
      • 若 x 为负零且 y 为正零，则 total_order_less(x, y) == true ，
      • 若 x 非零且 x 的指数域小于 y 的，则 total_order_less(x, y) == (x > 0) （仅对十进制浮点数有意义）；
  • 若 x 或 y 为 NaN ：
    • 若 x 为负 NaN 且 y 不是负 NaN ，则 total_order_less(x, y) == true ，
    • 若 x 不是正 NaN 且 y 为正 NaN ，则 total_order_less(x, y) == true ，
    • 若 x 与 y 均为拥有相同符号的 NaN 且 x 的尾数域小于 y 的，则 total_order_less(x, y) == ! std::signbit (x) 。

示例

本节未完成
原因：暂无示例

参阅

strong_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符且可替换 (类)
weak_order (C++20) | 进行三路比较并产生 std::weak_ordering 类型结果 (定制点对象)
partial_order (C++20) | 进行三路比较并产生 std::partial_ordering 类型结果 (定制点对象)
compare_strong_order_fallback (C++20) | 进行三路比较并产生 std::strong_ordering 类型的结果，即使 operator<=> 不可用 (定制点对象)


std::strong_ordering

< cpp‎ | utility
定义于头文件 <compare> |
class strong_ordering; | (C++20 起)

类类型 std::strong_ordering 是这种三路比较的结果类型

  • 接纳所有六个关系运算符（ == 、 != 、 < 、 <= 、 > 、 >= ）
  • 隐含可替换性：若 a 等价于 b ，则 f(a) 亦等价于 f(b) 。这里 f 所指代的函数仅可经由参数的公开 const 成员读取显著的比较状态。换言之，等价的值不可区别。
  • 不允许不可比较值： a < b 、 a == b 和 a > b 必须恰有一个为 true

常量

std::strong_ordering 类型拥有四个合法值，实现为其类型的 const 静态数据成员：

成员常量 | 定义
less(inline constexpr) [静态] | std::strong_ordering 类型合法值，指示小于（先序）关系 (公开静态成员常量)
equivalent(inline constexpr) [静态] | std::strong_ordering 类型合法值，指示等价（既非先序亦非后序），等于 equal (公开静态成员常量)
equal(inline constexpr) [静态] | std::strong_ordering 类型合法值，指示等价（既非先序亦非后序），等于 equivalent (公开静态成员常量)
greater(inline constexpr) [静态] | std::strong_ordering 类型合法值，指示大于（后序）关系 (公开静态成员常量)

转换

std::strong_ordering 是三个比较类别的最强者：它不能从任何其他类别隐式转换，而能隐式转换到其他二种类别。

operator partial_ordering
 到 std::partial_ordering 的隐式转换
(公开成员函数)

std::strong_ordering::operator partial_ordering

constexpr operator partial_ordering() const noexcept;

返回值

若 v 为 less 则为 std::partial_ordering::less ，若 v 为 greater 则为 std::partial_ordering::greater ，若 v 为 equal 或 equivalent 则为 std::partial_ordering::equivalent 。

operator weak_ordering
 到 std::weak_ordering 的隐式转换
(公开成员函数)

std::strong_ordering::operator weak_ordering

constexpr operator weak_ordering() const noexcept;

返回值

若 v 为 less 则为 std::weak_ordering::less ，若 v 为 greater 则为 std::weak_ordering::greater ，若 v 为 equal 或 equivalent. 则为 std::weak_ordering::equivalent 。

比较

比较运算符在此类型值和字面量 ​0​ 间定义。这支持用表达式 a <=> b == 0 或 a <=> b < 0 转换三路比较的结果为布尔关系；见 std::is_eq 、 std::is_lt 等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::strong_ordering 为参数的关联类时由实参依赖查找找到。

若程序试图将 strong_ordering 与任何异于整数字面量 ​0​ 的内容比较，则其行为未定义。

operator==operator<operator>operator<=operator>=operator<=>
 与零或 strong_order 比较
(函数)

operator==

friend constexpr bool operator==(strong_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator==(strong_ordering v, strong_ordering w) noexcept = default; | (2)

参数

v, w | - | 要检查的 std::strong_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 equivalent 或 equal 则为 true ，若 v 为 less 或 greater 则为 false 。
2) 若两个参数持有相同值则为 true ，否则为 false 。注意 equal 等于 equivalent 。

operator!=

friend constexpr bool operator!=(strong_ordering v, /*unspecified*/ u) noexcept;
friend constexpr bool operator!=(/*unspecified*/ u, strong_ordering v) noexcept;

参数

v | - | 要检查的 std::strong_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

若 v 为 less 或 greater 则为 true ，而若 v 为 equivalent 或 equal 则为 false 。

operator<

friend constexpr bool operator<(strong_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator<(/*unspecified*/ u, strong_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::strong_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 less 则为 true ，而若 v 为 greater 、 equivalent 或 equal 则为 false 。
2) 若 v 为 greater 则为 true ，而若 v 为 less 、 equivalent 或 equal 则为 false 。

operator<=

friend constexpr bool operator<=(strong_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator<=(/*unspecified*/ u, strong_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::strong_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 less 、 equivalent 或 equal 则为 true ，而若 v 为 greater 则为 false 。
2) 若 v 为 greater 、 equivalent 或 equal 则为 true ，而若 v 为 less 则为 false 。

operator>

friend constexpr bool operator>(strong_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator>(/*unspecified*/ u, strong_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::strong_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 greater 则为 true ，而若 v 为 less 、 equivalent 或 equal 则为 false 。
2) 若 v 为 less 则为 true ，而若 v 为 greater 、 equivalent 或 equal 则为 false 。

operator>=

friend constexpr bool operator>=(strong_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator>=(/*unspecified*/ u, strong_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::strong_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 greater 、 equivalent 或 equal 则为 true ，而若 v 为 less 则为 false 。
2) 若 v 为 less 、 equivalent 或 equal 则为 true ，而若 v 为 greater 则为 false 。

operator<=>

friend constexpr strong_ordering operator<=>(strong_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr strong_ordering operator<=>(/*unspecified*/ u, strong_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::strong_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) v 。
2) 若 v 为 less 则为 greater ，若 v 为 greater 则为 less ，否则为 v 。

示例

本节未完成
原因：暂无示例

参阅

weak_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符且不可替换 (类)
partial_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符，不可替换，并允许不可比较的值 (类)


std::three_way_comparable, std::three_way_comparable_with

< cpp‎ | utility
定义于头文件 <compare>
template<class T, class Cat = std::partial_ordering>

concept three_way_comparable =
__WeaklyEqualityComparableWith<T, T> &&
__PartiallyOrderedWith<T, T> &&
requires(const std::remove_reference_t <T>& a,
const std::remove_reference_t <T>& b) {
{ a <=> b } -> __ComparesAs<Cat>;

};
 (1) (C++20 起)
template<class T, class U, class Cat = std::partial_ordering>

concept three_way_comparable_with =
std::three_way_comparable<T, Cat> &&
std::three_way_comparable<U, Cat> &&
std::common_reference_with<
const std::remove_reference_t <T>&,
const std::remove_reference_t <U>&> &&
std::three_way_comparable<
std::common_reference_t<
const std::remove_reference_t <T>&,
const std::remove_reference_t <U>&>, Cat> &&
__WeaklyEqualityComparableWith<T, U> &&
__PartiallyOrderedWith<T, U> &&
requires(const std::remove_reference_t <T>& t,
const std::remove_reference_t <U>& u) {
{ t <=> u } -> __ComparesAs<Cat>;
{ u <=> t } -> __ComparesAs<Cat>;

};
 (2) (C++20 起)
template<class T, class Cat>

concept __ComparesAs = // 仅用于阐释

std::same_as<std::common_comparison_category_t<T, Cat>, Cat>;
 (3) (C++20 起)
1) 概念 std::three_way_comparable 指定三路比较运算符 <=> 在 T 上生成与 Cat 所蕴含的比较类别一致的结果。
2) 概念 three_way_comparable_with<T, U, Cat> 指定三路比较运算符 <=> 在（可能混合的） T 与 U 上操作数上生成与 Cat 所蕴含的比较类别一致的结果。比较混合的操作数生成的结果等价于比较转换到其功用类型的操作数。

在两个定义中， __WeaklyEqualityComparableWith 与 __PartiallyOrderedWith 分别为亦为 equality_comparable 与 totally_ordered 所用的仅用于阐释的概念。

语义要求

这些概念仅若其所蕴含的概念均被实现才得到实现。

1) T 与 Cat 实现 std::three_way_comparable<T, Cat> ，仅若给定 const std::remove_reference_t <T> 类型左值 a 与 b ，下列为真：
  • (a <=> b == 0) == bool(a == b) ，
  • (a <=> b != 0) == bool(a != b) ，
  • ((a <=> b) <=> 0) 与 (0 <=> (b <=> a)) 相等，
  • bool(a > b) == bool(b < a) ，
  • bool(a >= b) == !bool(a < b) ，
  • bool(a <= b) == !bool(b < a) ，
  • (a <=> b < 0) == bool(a < b) ，
  • (a <=> b > 0) == bool(a > b) ，
  • (a <=> b <= 0) == bool(a <= b) ，且
  • (a <=> b >= 0) == bool(a >= b) ；而
  • 若 Cat 可转换为 std::strong_ordering ，则 T 实现 totally_ordered 。
2) T 、 U 及 Cat 实现 std::three_way_comparable_with<T, U, Cat> 仅若给定
  • t ， const std::remove_reference_t <T> 类型左值，与
  • u ， const std::remove_reference_t <U> 类型左值

令 C 为 std::common_reference_t<const std::remove_reference_t <T>&, const std::remove_reference_t <U>&> ，下列为真：

  • t <=> u 与 u <=> t 拥有相同定义域；
  • ((t <=> u) <=> 0) 与 (0 <=> (u <=> t)) 相等；
  • (t <=> u == 0) == bool(t == u) ，
  • (t <=> u != 0) == bool(t != u) ，
  • Cat(t <=> u) == Cat(C(t) <=> C(u)) ，
  • (t <=> u < 0) == bool(t < u) ，
  • (t <=> u > 0) == bool(t > u) ，
  • (t <=> u <= 0) == bool(t <= u) ，且
  • (t <=> u >= 0) == bool(t >= u) ；而
  • 若 Cat 可转换为 std::strong_ordering ，则 T 与 U 实现 std::totally_ordered_with<T, U> 。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

除非另外提醒，每个用于 requires 表达式中的表达式都要求保持相等性且稳定，而表达式的求值必须只修改其非常操作数。必须不修改常操作数。

隐式表达式变种

使用不修改某 const 左值运算数的表达式的 requires 表达式亦隐式要求该表达式的额外变种对给定运算数接受非 const 左值或（可为 const 的）右值，除非以有区别的语义显式要求这种表达式变种。这些隐式表达式变种必须符合与声明的表达式的相同的语义。不指定实现以何种程度校验变种的语法。

参阅

equality_comparableequality_comparable_with (C++20) | 指定运算符 == 为等价关系 (概念)
totally_orderedtotally_ordered_with (C++20) | 指定比较运算符在该类型上产生全序 (概念)


std::weak_order

< cpp‎ | utility
定义于头文件 <compare>
inline namespace /* unspecified */ {

inline constexpr /* unspecified */ weak_order = /* unspecified */;

}
 (C++20 起)
调用签名
template< class T, class U >

requires /* see below */

constexpr std::weak_ordering weak_order(T&& t, U&& u) noexcept(/* see below */);

用三路比较比较二个值并产生 std::weak_ordering 类型结果。

设 t 与 u 为表达式而 T 与 U 分别代表 decltype((t)) 与 decltype((u)) 类型的值，则 std::weak_order(t, u) 表达式等价于：

  • 若 std::is_same_v < std::decay_t <T>, std::decay_t <U>> 为 true ：
    • std::weak_ordering(weak_order(t, u)) ，若在不包含 std::weak_order 的声明的语境中进行重载决议的情况下它为良构的表达式，
    • 否则，若 T 为浮点类型：
      • 若 std::numeric_limits <T>::is_iec559 为 true ，则进行浮点值的弱序比较（见后述）并返回 std::weak_ordering 类型值作为结果，
      • 否则，产生与 T 的比较运算符所观察的顺序一致的 std::weak_ordering 类型值，
    • 否则为 std::weak_ordering(std::compare_three_way()(t, u)) ，若它为良构，
    • 否则为 std::weak_ordering(std::strong_order(t, u)) ，若它为良构。
  • 所有其他情况下，该表达式为非良构，这能在出现于模板实例化的立即语境时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 std::weak_order 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __weak_order_fn 表示其类型的 cv 无限定版本。

__weak_order_fn 的所有实例均相等。在相同参数上调用类型 __weak_order_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 std::weak_order 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 std::weak_order 的参数要求，则 __weak_order_fn 实现 std::invocable<__weak_order_fn, Args...>、 std::invocable<const __weak_order_fn, Args...>、 std::invocable<__weak_order_fn&, Args...> 及 std::invocable<const __weak_order_fn&, Args...> 。否则， __weak_order_fn 的函数调用运算符不参与重载决议。

注解

IEEE 浮点类型的严格弱序

设 x 与 y 表示相同 IEEE 浮点类型的值，而 weak_order_less(x, y) 为指示在 C++标准定义的严格弱序中 x 是否前趋于 y 的布尔结果。

  • 若 x 与 y 均非 NaN ，则 weak_order_less(x, y) == true 当且仅当 x < y ，即相等浮点值的所有表示等价；
  • 若 x 为负 NaN 且 y 不是负 NaN ，则 weak_order_less(x, y) == true ；
  • 若 x 不是正 NaN 且 y 为正 NaN ，则 weak_order_less(x, y) == true ；
  • 若 x 与 y 均为拥有同一符号的 NaN ，则 weak_order_less(x, y) || weak_order_less(y, x) == false ，即所有符号相同的 NaN 等价。

示例

本节未完成
原因：暂无示例

参阅

weak_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符且不可替换 (类)
strong_order (C++20) | 进行三路比较并产生 std::strong_ordering 类型结果 (定制点对象)
partial_order (C++20) | 进行三路比较并产生 std::partial_ordering 类型结果 (定制点对象)
compare_weak_order_fallback (C++20) | 进行三路比较并产生 std::weak_ordering 类型的结果，即使 operator<=> 不可用 (定制点对象)


std::weak_ordering

< cpp‎ | utility
定义于头文件 <compare> |
class weak_ordering; | (C++20 起)

类类型 std::weak_ordering 是这种三路比较的结果类型：

  • 接纳所有六个关系运算符（ == 、 != 、 < 、 <= 、 > 、 >= ）
  • 不隐含可替换性：若 a 等价于 b ，则 f(a) 可能不等价于 f(b) 。这里 f 所指代的函数仅可经由参数的公开 const 成员读取显著的比较状态。换言之，等价的值可能可区别。
  • 不允许不可比较值： a < b 、 a == b 和 a > b 必须恰有一个为 true

常量

类型 std::weak_ordering 有三个合法值，实现为其类型的 const 静态数据成员：

成员常量 | 定义
less(inline constexpr) [静态] | std::weak_ordering 类型合法值，指示小于（先序）关系 (公开静态成员常量)
equivalent(inline constexpr) [静态] | std::weak_ordering 类型合法值，指示等价（既非先序亦非后序） (公开静态成员常量)
greater(inline constexpr) [静态] | std::weak_ordering 类型合法值，指示大于（后序）关系 (公开静态成员常量)

转换

std::weak_ordering 可隐式转换为 std::partial_ordering ，而 std::strong_ordering 可隐式转换为 weak_ordering 。

operator partial_ordering
 到 std::partial_ordering 的隐式转换
(公开成员函数)

std::weak_ordering::operator partial_ordering

constexpr operator partial_ordering() const noexcept;

返回值

若 v 为 less 则为 std::partial_ordering::less ，若 v 为 greater 则为 std::partial_ordering::greater ，若 v 为 equivalent 则为 std::partial_ordering::equivalent 。

比较

比较运算符在此类型值和字面量 ​0​ 间定义。这支持用表达式 a <=> b == 0 或 a <=> b < 0 转换三路比较的结果为布尔关系；见 std::is_eq 、 std::is_lt 等。

这些函数对通常无限定或有限定查找不可见，而只能在 std::weak_ordering 为参数的关联类时由实参依赖查找找到。

若程序试图将 weak_ordering 与任何异于整数字面量 ​0​ 的内容比较，则其行为未定义。

operator==operator<operator>operator<=operator>=operator<=>
 与零或 weak_ordering 比较
(函数)

operator==

friend constexpr bool operator==(weak_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator==(weak_ordering v, weak_ordering w) noexcept = default; | (2)

参数

v, w | - | 要检查的 std::weak_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 equivalent 则为 true ，若 v 为 less 或 greater 则为 false 。
2) 若两个参数持有相同值则为 true ，否则为 false 。

operator<

friend constexpr bool operator<(weak_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator<(/*unspecified*/ u, weak_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::weak_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 less 则为 true ，而若 v 为 greater 或 equivalent 则为 false 。
2) 若 v 为 greater 则为 true ，而若 v 为 less 或 equivalent 则为 false 。

operator<=

friend constexpr bool operator<=(weak_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator<=(/*unspecified*/ u, weak_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::weak_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 less 或 equivalent 则为 true ，而若 v 为 greater 则为 false 。
2) 若 v 为 greater 或 equivalent 则为 true ，而若 v 为 less 则为 false 。

operator>

friend constexpr bool operator>(weak_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator>(/*unspecified*/ u, weak_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::weak_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 greater 则为 true ，而若 v 为 less 或 equivalent 则为 false 。
2) 若 v 为 less 则为 true ，而若 v 为 greater 或 equivalent 则为 false 。

operator>=

friend constexpr bool operator>=(weak_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr bool operator>=(/*unspecified*/ u, weak_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::weak_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) 若 v 为 greater 或 equivalent 则为 true ，而若 v 为 less 则为 false 。
1) 若 v 为 less 或 equivalent 则为 true ，而若 v 为 greater 则为 false 。

operator<=>

friend constexpr weak_ordering operator<=>(weak_ordering v, /*unspecified*/ u) noexcept; | (1)
friend constexpr weak_ordering operator<=>(/*unspecified*/ u, weak_ordering v) noexcept; | (2)

参数

v | - | 要检查的 std::weak_ordering 值
u | - | 任何接受字面零实参的类型的不使用形参

返回值

1) v 。
2) 若 v 为 less 则为 greater ，若 v 为 greater 则为 less ，否则为 v 。

示例

本节未完成
原因：暂无示例

参阅

strong_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符且可替换 (类)
partial_ordering (C++20) | 三路比较的结果类型，支持所有 6 种运算符，不可替换，并允许不可比较的值 (类)


std::declval

< cpp‎ | utility
定义于头文件 <utility> |
template<class T> typename std::add_rvalue_reference <T>::type declval() noexcept; | (C++11 起)

将任意类型 T 转换成引用类型，令在 decltype 表达式中不必经过构造函数就能使用成员函数。

通常在模板中使用 declval ，模板接受的模板实参通常可能无构造函数，但有同一成员函数，均返回所需类型。

注意， declval 只能用于不求值语境，且不要求有定义；求值包含此函数的表达式是错误。通常，若 odr 使用此函数被则程序为病式。

参数

（无）

返回值

不能被调用，因此不会返回一个值。返回类型是 T&& ，除非 T 是（可有 cv 限定的） void ，此情况下返回类型是 T 。

示例

#include <utility>
#include <iostream>

struct Default { int foo() const { return 1; } };

struct NonDefault
{
    NonDefault() = delete;
    int foo() const { return 1; }
};

int main()
{
    decltype(Default().foo()) n1 = 1;                   // n1 的类型是 int
//  decltype(NonDefault().foo()) n2 = n1;               // 错误：无默认构造函数
    decltype(std::declval<NonDefault>().foo()) n2 = n1; // n2 的类型是 int
    std::cout << "n1 = " << n1 << '\n'
              << "n2 = " << n2 << '\n';
}

输出：

n1 = 1
n2 = 1

参阅

decltype 说明符 (C++11) | 获得表达式或实体的类型
result_ofinvoke_result (C++11)(C++20 中移除)(C++17) | 推导以一组实参调用一个可调用对象的结果类型 (类模板)


std::exchange

< cpp‎ | utility
定义于头文件 <utility> |
template< class T, class U = T > T exchange( T& obj, U&& new_value ); | (C++14 起) (C++20 前)
template< class T, class U = T > constexpr T exchange( T& obj, U&& new_value ); | (C++20 起) (C++23 前)
template< class T, class U = T > constexpr T exchange( T& obj, U&& new_value ) noexcept(/* see below */); | (C++23 起)

以 new_value 替换 obj 的值，并返回 obj 的旧值。

参数

obj | - | 要替换值的对象
new_value | - | 要赋给 obj 的值
类型要求
- T 必须满足可移动构造 (MoveConstructible) 的要求。而且必须能移动赋值 U 类型对象给 T 类型对象

返回值

obj 的旧值

异常

（无） | (C++23 前)
noexcept 说明： noexcept( std::is_nothrow_move_constructible_v <T> && std::is_nothrow_assignable_v <T&, U> ) | (C++23 起)

可能的实现

template<class T, class U = T>
constexpr // C++20 起
T exchange(T& obj, U&& new_value) noexcept(
    std::is_nothrow_move_constructible<T>::value && std::is_nothrow_assignable<T&, U>::value
)
{
    T old_value = std::move(obj);
    obj = std::forward<U>(new_value);
    return old_value;
}

注解

能在实现移动赋值运算符和移动构造函数时使用此函数：

struct S
{
  int n;

  S(S&& other) noexcept : n{std::exchange(other.n, 0)}
  {}

  S& operator=(S&& other) noexcept
  {
    if(this != &other)
        n = std::exchange(other.n, 0); // 移动 n ，并于 other.n 留下零
    return *this;
  }
};

示例

#include <iostream>
#include <utility>
#include <vector>
#include <iterator>

class stream
{
  public:

   using flags_type = int;

  public:

    flags_type flags() const
    { return flags_; }

    /// 以 newf 替换 flags_ 并返回旧值。
    flags_type flags(flags_type newf)
    { return std::exchange(flags_, newf); }

  private:

    flags_type flags_ = 0;
};

void f() { std::cout << "f()"; }

int main()
{
   stream s;

   std::cout << s.flags() << '\n';
   std::cout << s.flags(12) << '\n';
   std::cout << s.flags() << "\n\n";

   std::vector<int> v;

   // 因为第二模板形参有默认值，故能以花括号初始化列器表为第二参数。
   // 下方表达式等价于 std::exchange(v, std::vector<int>{1,2,3,4});

   std::exchange(v, {1,2,3,4});

   std::copy(begin(v),end(v), std::ostream_iterator<int>(std::cout,", "));

   std::cout << "\n\n";

   void (*fun)();

   // 模板形参的默认值亦使得能以通常函数为第二参数。
   // 下方表达式等价于 std::exchange(fun, static_cast<void(*)()>(f))
   std::exchange(fun,f);
   fun();
}

输出：

0
0
12

1, 2, 3, 4,

f()

参阅

swap | 交换两个对象的值 (函数模板)
atomic_exchangeatomic_exchange_explicit (C++11)(C++11) | 原子地以非原子实参的值替换原子对象的值，并返回该原子对象的旧值 (函数模板)


库特性测试宏 (C++20)

< cpp‎ | utility

若包含头文件 <version> 或指定于表中的头文件之一，则定义对应的宏。

宏名 | 值 | 头文件
__cpp_lib_addressof_constexpr | 201603L | <memory>
__cpp_lib_allocator_traits_is_always_equal | 201411L | <memory> <scoped_allocator> <string> <deque> <forward_list> <list> <vector> <map> <set> <unordered_map> <unordered_set>
__cpp_lib_any | 201606L | <any>
__cpp_lib_apply | 201603L | <tuple>
__cpp_lib_array_constexpr | 201811L | <iterator> <array>
__cpp_lib_as_const | 201510L | <utility>
__cpp_lib_assume_aligned | 201811L | <memory>
__cpp_lib_atomic_flag_test | 201907L | <atomic>
__cpp_lib_atomic_float | 201711L | <atomic>
__cpp_lib_atomic_is_always_lock_free | 201603L | <atomic>
__cpp_lib_atomic_lock_free_type_aliases | 201907L | <atomic>
__cpp_lib_atomic_ref | 201806L | <atomic>
__cpp_lib_atomic_shared_ptr | 201711L | <memory>
__cpp_lib_atomic_value_initialization | 201911L | <atomic> <memory>
__cpp_lib_atomic_wait | 201907L | <atomic>
__cpp_lib_barrier | 201907L | <barrier>
__cpp_lib_bind_front | 201907L | <functional>
__cpp_lib_bit_cast | 201806L | <bit>
__cpp_lib_bitops | 201907L | <bit>
__cpp_lib_bool_constant | 201505L | <type_traits>
__cpp_lib_bounded_array_traits | 201902L | <type_traits>
__cpp_lib_boyer_moore_searcher | 201603L | <functional>
__cpp_lib_byte | 201603L | <cstddef>
__cpp_lib_char8_t | 201907L | <atomic> <filesystem> <istream> <limits> <locale> <ostream> <string> <string_view>
__cpp_lib_chrono | 201907L | <chrono>
__cpp_lib_chrono_udls | 201304L | <chrono>
__cpp_lib_clamp | 201603L | <algorithm>
__cpp_lib_complex_udls | 201309L | <complex>
__cpp_lib_concepts | 201907L | <concepts>
__cpp_lib_constexpr_algorithms | 201806L | <algorithm>
__cpp_lib_constexpr_complex | 201711L | <complex>
__cpp_lib_constexpr_dynamic_alloc | 201907L | <memory>
__cpp_lib_constexpr_functional | 201907L | <functional>
__cpp_lib_constexpr_iterator | 201811L | <iterator>
__cpp_lib_constexpr_memory | 201811L | <memory>
__cpp_lib_constexpr_numeric | 201911L | <numeric>
__cpp_lib_constexpr_string | 201907L | <string>
__cpp_lib_constexpr_string_view | 201811L | <string_view>
__cpp_lib_constexpr_tuple | 201811L | <tuple>
__cpp_lib_constexpr_utility | 201811L | <utility>
__cpp_lib_constexpr_vector | 201907L | <vector>
__cpp_lib_destroying_delete | 201806L | <new>
__cpp_lib_enable_shared_from_this | 201603L | <memory>
__cpp_lib_endian | 201907L | <bit>
__cpp_lib_erase_if | 201811L | <string> <deque> <forward_list> <list> <vector> <map> <set> <unordered_map> <unordered_set>
__cpp_lib_exchange_function | 201304L | <utility>
__cpp_lib_execution | 201902L | <execution>
__cpp_lib_filesystem | 201703L | <filesystem>
__cpp_lib_format | 201907L | <format>
__cpp_lib_gcd_lcm | 201606L | <numeric>
__cpp_lib_generic_associative_lookup | 201304L | <map> <set>
__cpp_lib_generic_unordered_lookup | 201811L | <unordered_map> <unordered_set>
__cpp_lib_hardware_interference_size | 201703L | <new>
__cpp_lib_has_unique_object_representations | 201606L | <type_traits>
__cpp_lib_hypot | 201603L | <cmath>
__cpp_lib_incomplete_container_elements | 201505L | <forward_list> <list> <vector>
__cpp_lib_int_pow2 | 201806L | <bit>
__cpp_lib_integer_sequence | 201304L | <utility>
__cpp_lib_integral_constant_callable | 201304L | <type_traits>
__cpp_lib_interpolate | 201902L | <cmath> <numeric>
__cpp_lib_invoke | 201411L | <functional>
__cpp_lib_is_aggregate | 201703L | <type_traits>
__cpp_lib_is_constant_evaluated | 201811L | <type_traits>
__cpp_lib_is_final | 201402L | <type_traits>
__cpp_lib_is_invocable | 201703L | <type_traits>
__cpp_lib_is_layout_compatible | 201907L | <type_traits>
__cpp_lib_is_null_pointer | 201309L | <type_traits>
__cpp_lib_is_pointer_interconvertible | 201907L | <type_traits>
__cpp_lib_is_swappable | 201603L | <type_traits>
__cpp_lib_jthread | 201911L | <stop_token> <thread>
__cpp_lib_latch | 201907L | <latch>
__cpp_lib_launder | 201606L | <new>
__cpp_lib_list_remove_return_type | 201806L | <forward_list> <list>
__cpp_lib_logical_traits | 201510L | <type_traits>
__cpp_lib_make_from_tuple | 201606L | <tuple>
__cpp_lib_make_reverse_iterator | 201402L | <iterator>
__cpp_lib_make_unique | 201304L | <memory>
__cpp_lib_map_try_emplace | 201411L | <map>
__cpp_lib_math_constants | 201907L | <numbers>
__cpp_lib_math_special_functions | 201603L | <cmath>
__cpp_lib_memory_resource | 201603L | <memory_resource>
__cpp_lib_node_extract | 201606L | <map> <set> <unordered_map> <unordered_set>
__cpp_lib_nonmember_container_access | 201411L | <iterator> <array> <deque> <forward_list> <list> <map> <regex> <set> <string> <unordered_map> <unordered_set> <vector>
__cpp_lib_not_fn | 201603L | <functional>
__cpp_lib_nothrow_convertible | 201806L | <type_traits>
__cpp_lib_null_iterators | 201304L | <iterator>
__cpp_lib_optional | 201606L | <optional>
__cpp_lib_parallel_algorithm | 201603L | <algorithm> <numeric>
__cpp_lib_polymorphic_allocator | 201902L | <memory>
__cpp_lib_quoted_string_io | 201304L | <iomanip>
__cpp_lib_ranges | 201911L | <algorithm> <functional> <iterator> <memory> <ranges>
__cpp_lib_raw_memory_algorithms | 201606L | <memory>
__cpp_lib_remove_cvref | 201711L | <type_traits>
__cpp_lib_result_of_sfinae | 201210L | <type_traits> <functional>
__cpp_lib_robust_nonmodifying_seq_ops | 201304L | <algorithm>
__cpp_lib_sample | 201603L | <algorithm>
__cpp_lib_scoped_lock | 201703L | <mutex>
__cpp_lib_semaphore | 201907L | <semaphore>
__cpp_lib_shared_mutex | 201505L | <shared_mutex>
__cpp_lib_shared_ptr_arrays | 201707L | <memory>
__cpp_lib_shared_ptr_weak_type | 201606L | <memory>
__cpp_lib_shared_timed_mutex | 201402L | <shared_mutex>
__cpp_lib_shift | 201806L | <algorithm>
__cpp_lib_smart_ptr_for_overwrite | 201811L | <memory>
__cpp_lib_source_location | 201907L | <source_location>
__cpp_lib_span | 201902L | <span>
__cpp_lib_ssize | 201902L | <iterator>
__cpp_lib_starts_ends_with | 201711L | <string> <string_view>
__cpp_lib_string_udls | 201304L | <string>
__cpp_lib_string_view | 201803L | <string> <string_view>
__cpp_lib_syncbuf | 201803L | <syncstream>
__cpp_lib_three_way_comparison | 201907L | <compare>
__cpp_lib_to_address | 201711L | <memory>
__cpp_lib_to_array | 201907L | <array>
__cpp_lib_to_chars | 201611L | <charconv>
__cpp_lib_transformation_trait_aliases | 201304L | <type_traits>
__cpp_lib_transparent_operators | 201510L | <memory> <functional>
__cpp_lib_tuple_element_t | 201402L | <tuple>
__cpp_lib_tuples_by_type | 201304L | <tuple> <utility>
__cpp_lib_type_identity | 201806L | <type_traits>
__cpp_lib_type_trait_variable_templates | 201510L | <type_traits>
__cpp_lib_uncaught_exceptions | 201411L | <exception>
__cpp_lib_unordered_map_try_emplace | 201411L | <unordered_map>
__cpp_lib_unwrap_ref | 201811L | <type_traits>
__cpp_lib_variant | 201606L | <variant>
__cpp_lib_void_t | 201411L | <type_traits>


格式化库 (C++20)

< cpp‎ | utility

文本格式化库提供 printf 函数族的安全且可扩展的替用品。有意使之补充既存的 C++ I/O 流库并复用其基础设施，例如对用户定义类型重载的流插入运算符。

示例：

std::string message = std::format("The answer is {}.", 42);

格式化函数

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
format_to (C++20) | 通过输出迭代器写其参数的格式化表示 (函数模板)
format_to_n (C++20) | 通过输出迭代器写其参数的格式化表示，不超出指定的大小 (函数模板)
formatted_size (C++20) | 确定存储其参数的格式化表示所需的字符数 (函数模板)

扩展性支持与实现细节

vformat (C++20) | std::format 的使用类型擦除的参数表示的非模板变体 (函数)
vformat_to (C++20) | std::format_to 的使用类型擦除的参数表示的非模板变体 (函数模板)
basic_format_arg (C++20) | 提供对用户定义格式化器的格式化参数的访问的类模板 (类模板)
formatter (C++20) | 定义给定类型的格式化规则的类模板 (类模板)
basic_format_parse_contextformat_parse_contextwformat_parse_context (C++20)(C++20)(C++20) | 格式化字符串分析器状态 (类模板)
basic_format_contextformat_contextwformat_context (C++20)(C++20)(C++20) | 格式化状态，包括所有格式化参数和输出迭代器 (类模板)
visit_format_arg (C++20) | 用户定义格式化器的参数观览接口 (函数模板)
make_format_argsmake_wformat_args (C++20)(C++20) | 创建引用所有格式化参数的类型擦除对象，可转换到 format_args (函数模板)
basic_format_argsformat_argswformat_args (C++20)(C++20)(C++20) | 提供对所有格式化参数的访问的类 (类模板)
format_error (C++20) | 格式化错误时抛出的异常类型 (类)


std::basic_format_arg

< cpp‎ | utility‎ | format
定义于头文件 <format> |
template<class Context> class basic_format_arg; | (C++20 起)

提供到格式化参数的访问。

basic_format_arg 对象通常由 std::make_format_args 创建并通过 std::visit_format_arg 访问。

basic_format_arg 对象表现为如同存储一个下列类型的 std::variant ：

  • std::monostate （仅若对象为默认构造的）
  • bool
  • Context::char_type
  • int
  • unsigned int
  • long long int
  • unsigned long long int
  • float
  • double
  • long double
  • const Context::char_type*
  • std::basic_string_view <Context::char_type>
  • const void*
  • basic_format_arg::handle

成员类

类型 | 定义
handle | 允许格式化用户定义类型的对象的类型擦除包装 (类)

成员函数

(构造函数) | 构造 std::basic_format_arg (公开成员函数)
operator bool | 检查当前对象是否保有格式化参数 (公开成员函数)

非成员函数

visit_format_arg
(C++20)
 用户定义格式化器的参数观览接口
(函数模板)

std::basic_format_arg::handle

template<class Context>
class basic_format_arg<Context>::handle;

允许格式化用户定义类型的对象。

成员函数

format
 以给定的环境格式化被引用对象
(公开成员函数)

std::basic_format_arg::handle::format

void format(std::basic_format_parse_context<Context::char_type>& parse_ctx,
Context& format_ctx) const;

令 T 为关联的格式化参数的类型， ref 为指代该格式化参数的 const T& 。等价于：

typename Context::template formatter_type<T> f;
parse_ctx.advance_to(f.parse(parse_ctx));
format_ctx.advance_to(f.format(ref, format_ctx));

std::basic_format_arg::basic_format_arg

basic_format_arg() noexcept;

默认构造函数。构造不保有格式化参数的 basic_format_arg 。存储的对象拥有 std::monostate 类型。

为创建保有格式化参数的 basic_format_arg ，必须使用 std::make_format_args 。

std::basic_format_arg::operator bool

explicit operator bool() const noexcept;

检查 *this 是否保有格式化参数。

若 *this 保有格式化参数（即存储的对象不拥有 std::monostate 类型）则返回 true ，否则返回 false 。

示例

本节未完成
原因：暂无示例

参阅


std::basic_format_args

< cpp‎ | utility‎ | format
定义于头文件 <format> |  |
template<class Context> class basic_format_args; | (1) | (C++20 起)
using format_args = basic_format_args<std::format_context>; | (2) | (C++20 起)
using wformat_args = basic_format_args<std::wformat_context>; | (3) | (C++20 起)

提供到格式化参数的访问。

成员函数

(构造函数) | 构造 basic_format_args 对象 (公开成员函数)
get | 返回位于给定下标的格式化参数 (公开成员函数)

std::basic_format_args::basic_format_args

basic_format_args() noexcept; | (1)
template<class... Args> basic_format_args(const /*format-arg-store*/<Context, Args...>& store) noexcept; | (2)
1) 构造不保有任何格式化参数的 basic_format_args 对象。
2) 从调用 std::make_format_args 或 std::make_wformat_args 的结果构造 basic_format_args 对象。

std::basic_format_args 拥有引用语义。程序员负责确保 *this 不会比 store 活得更久（从而不应比 std::make_format_args 或 std::make_wformat_args 的参数存活更久）。

std::basic_format_args::get

std::basic_format_arg<Context> get( std::size_t i) const noexcept;

返回保有 args 中第 i 参数的 std::basic_format_arg ，其中 args 是传递给 std::make_format_args 或 std::make_wformat_args 的形参包。

若无足够的参数（即 *this 为默认构造或 i 不小于格式化参数数），则返回默认构造的 std::basic_format_arg （保有 std::monostate 对象）。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2216R3 | C++20 | 由于 vformat_to 的过度参数化提供了 format_args_t | 已移除

参阅


std::basic_format_context

< cpp‎ | utility‎ | format
定义于头文件 <format> |  |
template<class OutputIt, class CharT> class basic_format_context; | (1) | (C++20 起)
using format_context = basic_format_context</* unspecified */, char>; | (2) | (C++20 起)
using wformat_context = basic_format_context</* unspecified */, wchar_t>; | (3) | (C++20 起)

提供到由格式化参数和输出迭代器组成的格式化状态的访问。

若 OutputIt 不实现 std::output_iterator<const CharT&> 则行为未定义。

2) 未指明的模板实参是后附到 std::string 的输出迭代器，例如 std::back_insert_iterator < std::string > 。鼓励实现使用到支持后附到任何连续存储且大小可变的容器的类型擦除缓冲。
3) 未指明的模板实参是后附到 std::wstring 的输出迭代器。

成员类型

类型 | 定义
iterator | OutputIt
char_type | CharT

成员别名模版

类型 | 定义
formatter_type<T> | std::formatter<T, CharT>

成员函数

arg | 返回位于给定下标的参数 (公开成员函数)
locale | 返回用于本地环境特定格式化的本地环境 (公开成员函数)
out | 返回指向输出缓冲区的迭代器 (公开成员函数)
advance_to | 推进输出迭代器到给定位置 (公开成员函数)

std::basic_format_context::arg

std::basic_format_arg<basic_format_context> arg( std::size_t id) const;

返回保有 args 中第 id 元素的 std::basic_format_arg ，其中 args 是参数包或传递给格式化函数的 std::basic_format_args 对象。

若 id 不小于格式化参数的数量，则返回默认构造的 std::basic_format_arg （保有一个 std::monostate 对象）。

std::basic_format_context::locale

std::locale locale();

返回传递给格式化函数的本地环境，或若格式化函数不接收本地环境返回默认构造的 std::locale 。

std::basic_format_context::out

iterator out();

返回指向输出缓冲区的迭代器。从存储的迭代器移动构造结果。

std::basic_format_context::advance_to

void advance_to(iterator it);

移动赋值 it 给存储的输出迭代器。调用 advance_to 后，对 out() 的后继调用将返回 it 的副本。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3567 | C++20 | basic_format_context 无法用于仅移动的迭代器类型 | 使之移动迭代器

参阅


std::basic_format_parse_context

< cpp‎ | utility‎ | format
定义于头文件 <format> |  |
template<class CharT> class basic_format_parse_context; | (1) | (C++20 起)
using format_parse_context = basic_format_parse_context<char>; | (2) | (C++20 起)
using wformat_parse_context = basic_format_parse_context<wchar_t>; | (3) | (C++20 起)

提供到分析由正在分析的格式字符串范围，和自动下标参数计数组成的格式字符串分析状态的访问。

分析格式说明时，传递 basic_format_parse_context 实例给格式化器 (Formatter) 。

成员类型

类型 | 定义
char_type | CharT
iterator | std::basic_string_view <CharT>::const_iterator
const_iterator | std::basic_string_view <CharT>::const_iterator

成员函数

(构造函数) | 从格式字符串和参数计数构造 std::basic_format_parse_context (公开成员函数)
operator= [被删除] | std::basic_format_parse_context 不可复制 (公开成员函数)
begin | 返回指向格式字符串范围起始的迭代器 (公开成员函数)
end | 返回指向格式字符串范围末尾的迭代器 (公开成员函数)
advance_to | 使起始迭代器前进到给定位置 (公开成员函数)
next_arg_id | 进入自动索引模式，并返回下一个参数下标 (公开成员函数)
check_arg_id | 进入手动索引模式，检查给定参数下标是否在范围中 (公开成员函数)

std::basic_format_parse_context::basic_format_parse_context

constexpr explicit basic_format_parse_context( std::basic_string_view <CharT> fmt,
std::size_t num_args = 0) noexcept;
 (1)
basic_format_parse_context(const basic_format_parse_context&) = delete;
 (2)
1) 构造 std::basic_format_parse_context 实例。初始化格式字符串范围为 [fmt.begin(), fmt.end()) ，并初始化参数计数为 num_args 。
2) 复制构造函数被删除。 std::basic_format_parse_context 不可复制。

std::basic_format_parse_context::begin

constexpr const_iterator begin() const noexcept;

返回指向格式字符串范围起始的迭代器。

std::basic_format_parse_context::end

constexpr const_iterator end() const noexcept;

返回指向格式字符串范围末尾的迭代器。

std::basic_format_parse_context::advance_to

constexpr void advance_to(const_iterator it);

设置格式字符串范围的起始为 it 。调用 advance_to 后，对 begin() 的后继调用将返回 it 的副本。

若 end() 从 it 不可达则行为未定义。

std::basic_format_parse_context::next_arg_id

constexpr std::size_t next_arg_id();

进入自动参数索引模式，并返回从 0 开始的下个参数下标。

若 *this 已进入手动参数索引模式，则抛出 std::format_error 。

std::basic_format_parse_context::check_arg_id

constexpr void check_arg_id( std::size_t id);

进入手动参数索引模式。

若 *this 以进入自动参数索引模式，则抛出 std::format_error 。

若 id 大于或等于构造函数中提供的参数数量，则该调用不是常量表达式。

示例

本节未完成
原因：暂无示例

参阅


std::format

< cpp‎ | utility‎ | format
定义于头文件 <format>
template< class... Args >
std::string format( /*format_string<Args...>*/ fmt, const Args&... args );
 (1) (C++20 起)
template< class... Args >
std::wstring format( /*wformat_string<Args...>*/ fmt, const Args&... args );
 (2) (C++20 起)
template< class... Args >

std::string format( const std::locale & loc,

/*format_string<Args...>*/ fmt, const Args&... args );
 (3) (C++20 起)
template< class... Args >

std::wstring format( const std::locale & loc,

/*wformat_string<Args...>*/ fmt, const Args&... args );
 (4) (C++20 起)

按照格式字符串 fmt 格式化 args ，并返回作为 string 的结果。 loc 若存在，则用于本地环境特定的格式化。

若对 Args 中的任一 Ti ， std::formatter<Ti, CharT> 不满足格式化器 (Formatter) 要求则行为未定义，其中 CharT 是对重载 (1,3) 为 char ，对重载 (2,4) 为 wchar_t 。

参数

fmt -
未指定类型的形参，其初始化仅若实参可转换成 std::string_view （对于 (1,3) ）或 std::wstring_view （对于 (2,4) ），而转换结果是常量表达式和 Args 的合法格式字符串才合法。格式字符串由以下内容组成：
  • 通常字符（除了 { 与 } ），它们被不加修改地复制到输出，
  • 转义序列 {{ 与 }} ，它们在输出中被分别替换成 { 与 } ，以及
  • 替换域。

每个替换域拥有下列格式：

  • 引入的 { 字符；
  • (可选) arg-id ，一个非负数；
  • (可选) 冒号（ : ）后随格式说明；
  • 终止的 } 字符。

arg-id 指定用于格式化其值的 args 中的参数的下标；若省略 arg-id ，则按顺序使用参数。格式字符串中的 arg-id 必须全部存在或全部被省略。混合手动和自动指定下标是错误。

格式说明由对应参数特化的 std::formatter 定义。

  • 对于基本类型和标准字符串类型，格式说明为标准格式说明；
  • 对于标准日期和时间类型，格式说明为 chrono 格式说明；
  • 对于用户定义类型，格式说明由用户定义的 std::formatter 特化决定。
args... - 要格式化的参数
loc - 用于本地环境特定格式化的 std::locale

返回值

保有格式化结果的 string 对象。

异常

在分配失败时抛出 std::bad_alloc 。并且会传播任何格式化器所抛的异常。

注解

提供多于格式字符串所要求的参数不是错误：

std::format("{} {}!", "Hello", "world", "something"); // OK ：产生 "Hello world!"

自 P2216R3 起，格式字符串不是常量表达式是错误。此情况下可使用 std::vformat 。

std::string f(std::string_view runtime_format_string) {
    // return std::format(runtime_format_string, "foo", "bar"); // 错误
    return std::vformat(runtime_format_string, std::make_format_args("foo", "bar")); // OK
}

示例

#include <format>
#include <iostream>
#include <string>
#include <string_view>

template <typename... Args>
std::string dyna_print(std::string_view rt_fmt_str, Args&&... args) {
    return std::vformat(rt_fmt_str, std::make_format_args(args...));
}

int main() {
    std::cout << std::format("Hello {}!\n", "world");

    std::string fmt;
    for (int i{}; i != 3; ++i) {
        fmt += "{} "; // 构造格式化字符串
        std::cout << fmt << " : ";
        std::cout << dyna_print(fmt, "alpha", 'Z', 3.14, "unused");
        std::cout << '\n';
    }
}

输出：

Hello world!
{}  : alpha
{} {}  : alpha Z
{} {} {}  : alpha Z 3.14

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2216R3 | C++20 | 对非法格式字符串抛出 std::format_error | 非法格式字符串导致编译时错误

参阅

format_to (C++20) | 通过输出迭代器写其参数的格式化表示 (函数模板)
format_to_n (C++20) | 通过输出迭代器写其参数的格式化表示，不超出指定的大小 (函数模板)


std::format_error

< cpp‎ | utility‎ | format
定义于头文件 <format> |
class format_error; | (C++20 起)

定义抛出以报告格式化库中错误的异常对象类型。

cpp/error/exception cpp/error/runtime error

继承图

成员函数

(构造函数) | 构造拥有给定消息的新 format_error 对象 (公开成员函数)
operator= | 替换 format_error 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::format_error::format_error

format_error( const std::string & what_arg ); | (1) | (C++20 起)
format_error( const char* what_arg ); | (2) | (C++20 起)
format_error( const format_error& other ) noexcept; | (3) | (C++20 起)
1-2) 构造以 what_arg 为解释字符串的异常对象，解释字符串能通过 what() 访问。
3) 复制构造函数。若 *this 与 other 均拥有动态类型 std::format_error 则 std::strcmp (what(), other.what()) == 0 。

参数

what_arg | - | 解释字符串
other | - | 要复制的另一异常对象

异常

1-2) 可能抛出 std::bad_alloc

注解

因为不容许复制 std::format_error 抛出异常，通常将此消息在内部存储为分离分配的引用计数字符串。这也是构造函数不接收 std::string&& 参数的理由：无论如何它必须复制内容。

std::format_error::operator=

format_error& operator=( const format_error& other ) noexcept; | (C++20 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::format_error 则赋值后 std::strcmp (what(), other.what()) == 0 。

参数

other - 用以赋值的另一异常对象

返回值

*this

std::format_error::what

virtual const char* what() const noexcept; | (C++20 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::runtime_error

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

示例

本节未完成
原因：暂无示例

参阅


std::format_to

< cpp‎ | utility‎ | format
定义于头文件 <format>
template< class OutputIt, class... Args >
OutputIt format_to( OutputIt out, /*format_string<Args...>*/ fmt, const Args&... args );
 (1) (C++20 起)
template< class OutputIt, class... Args >
OutputIt format_to( OutputIt out, /*wformat_string<Args...>*/ fmt, const Args&... args );
 (2) (C++20 起)
template< class OutputIt, class... Args >

OutputIt format_to( OutputIt out, const std::locale & loc,

/*format_string<Args...>*/ fmt, const Args&... args );
 (3) (C++20 起)
template< class OutputIt, class... Args >

OutputIt format_to( OutputIt out, const std::locale & loc,

/*wformat_string<Args...>*/ fmt, const Args&... args );
 (4) (C++20 起)

按照格式字符串 fmt 格式化 args ，并写结果到输出迭代器 out 。 loc 若存在则用于本地环境特定的格式化。

令 CharT 对重载 (1,3) 为 char ，对重载 wchar_t 为 (2,4) 。

这些重载仅若 OutputIt 满足概念 std::output_iterator<const CharT&> 才参与重载决议。

若 OutputIt 不实现（满足其语义要求）概念 std::output_iterator<const CharT&> ，或若对 Args 中任何 Ti ， std::formatter<Ti, CharT> 不满足格式化器 (Formatter) 要求则行为未定义。

参数

out - 指向输出缓冲区的迭代器
fmt -
未指定类型的形参，其初始化仅若实参可转换成 std::string_view （对于 (1,3) ）或 std::wstring_view （对于 (2,4) ），而转换结果是常量表达式和 Args 的合法格式字符串才合法。格式字符串由以下内容组成：
  • 通常字符（除了 { 与 } ），它们被不加修改地复制到输出，
  • 转义序列 {{ 与 }} ，它们在输出中被分别替换成 { 与 } ，以及
  • 替换域。

每个替换域拥有下列格式：

  • 引入的 { 字符；
  • (可选) arg-id ，一个非负数；
  • (可选) 冒号（ : ）后随格式说明；
  • 终止的 } 字符。

arg-id 指定用于格式化其值的 args 中的参数的下标；若省略 arg-id ，则按顺序使用参数。格式字符串中的 arg-id 必须全部存在或全部被省略。混合手动和自动指定下标是错误。

格式说明由对应参数特化的 std::formatter 定义。

  • 对于基本类型和标准字符串类型，格式说明为标准格式说明；
  • 对于标准日期和时间类型，格式说明为 chrono 格式说明；
  • 对于用户定义类型，格式说明由用户定义的 std::formatter 特化决定。
args... - 要格式化的参数
loc - 用于本地环境特定的格式化的 std::locale

返回值

输出范围末尾后一位置的迭代器。

异常

传播格式化器或迭代器操作所抛的任何异常。

注解

自 P2216R3 起，格式字符串不是常量表达式是错误。此情况下可使用 std::vformat_to 。

示例

#include <format>
#include <iostream>
#include <iterator>
#include <string>

auto main() -> int
{
    std::string buffer;

    std::format_to(
        std::back_inserter(buffer), //< OutputIt
        "Hello, C++{}!\n",          //< fmt
        "20");                      //< arg
    std::cout << buffer;
    buffer.clear();

    std::format_to(
        std::back_inserter(buffer), //< OutputIt
        "Hello, {0}::{1}!{2}",      //< fmt
        "std",                      //< arg {0}
        "format_to()",              //< arg {1}
        "\n",                       //< arg {2}
        "extra param(s)...");       //< 不使用
    std::cout << buffer;

    std::wstring wbuffer;
    std::format_to(
        std::back_inserter(wbuffer),//< OutputIt
        L"Hello, {2}::{1}!{0}",     //< fmt
        L"\n",                      //< arg {0}
        L"format_to()",             //< arg {1}
        L"std",                     //< arg {2}
        L"...is not..."             //< 不使用
        L"...an error!");           //< 不使用
    std::wcout << wbuffer;
}

输出：

Hello, C++20!
Hello, std::format_to()!
Hello, std::format_to()!

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2216R3 | C++20 | 对非法格式字符串抛出 std::format_error | 非法格式字符串导致编译时错误

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
format_to_n (C++20) | 通过输出迭代器写其参数的格式化表示，不超出指定的大小 (函数模板)


std::format_to_n

< cpp‎ | utility‎ | format
定义于头文件 <format>
template< class OutputIt, class... Args >

std::format_to_n_result<OutputIt>
format_to_n( OutputIt out, std::iter_difference_t<OutputIt> n,

/*format_string<Args...>*/ fmt, const Args&... args );
 (1) (C++20 起)
template< class OutputIt, class... Args >

std::format_to_n_result<OutputIt>
format_to_n( OutputIt out, std::iter_difference_t<OutputIt> n,

/*wformat_string<Args...>*/ fmt, const Args&... args );
 (2) (C++20 起)
template< class OutputIt, class... Args >

std::format_to_n_result<OutputIt>
format_to_n( OutputIt out, std::iter_difference_t<OutputIt> n,

const std::locale & loc, /*format_string<Args...>*/ fmt, const Args&... args );
 (3) (C++20 起)
template< class OutputIt, class... Args >

std::format_to_n_result<OutputIt>
format_to_n( OutputIt out, std::iter_difference_t<OutputIt> n,

const std::locale & loc, /*wformat_string<Args...>*/ fmt, const Args&... args );
 (4) (C++20 起)
template< class OutputIt >

struct format_to_n_result {
OutputIt out;
std::iter_difference_t<OutputIt> size;

};
 (5) (C++20 起)

按照格式字符串 fmt 格式化 args ，并写结果到输出迭代器 out 。至多写 n 个字符。 loc 若存在则用于本地环境特定的格式化。

令 CharT 对重载 (1,3) 为 char ，对重载 wchar_t 为 (2,4) 。

这些重载仅若 OutputIt 满足概念 std::output_iterator<const CharT&> 才参与重载决议。若 OutputIt 不实现（满足其语义要求）概念 std::output_iterator<const CharT&> ，或若对 Args 中任何 Ti ， std::formatter<Ti, CharT> 不满足格式化器 (Formatter) 要求则行为未定义。

5) std::format_to_n_result 无基类或 out、 size 及隐式声明的特殊成员函数以外的成员。

参数

out - 指向输出缓冲区的迭代器
n - 写入输出缓冲区的最大字符数
fmt -
未指定类型的形参，其初始化仅若实参可转换成 std::string_view （对于 (1,3) ）或 std::wstring_view （对于 (2,4) ），而转换结果是常量表达式和 Args 的合法格式字符串才合法。格式字符串由以下内容组成：
  • 通常字符（除了 { 与 } ），它们被不加修改地复制到输出，
  • 转义序列 {{ 与 }} ，它们在输出中被分别替换成 { 与 } ，以及
  • 替换域。

每个替换域拥有下列格式：

  • 引入的 { 字符；
  • (可选) arg-id ，一个非负数；
  • (可选) 冒号（ : ）后随格式说明；
  • 终止的 } 字符。

arg-id 指定用于格式化其值的 args 中的参数的下标；若省略 arg-id ，则按顺序使用参数。格式字符串中的 arg-id 必须全部存在或全部被省略。混合手动和自动指定下标是错误。

格式说明由对应参数特化的 std::formatter 定义。

  • 对于基本类型和标准字符串类型，格式说明为标准格式说明；
  • 对于标准日期和时间类型，格式说明为 chrono 格式说明；
  • 对于用户定义类型，格式说明由用户定义的 std::formatter 特化决定。
args... - 要格式化的参数
loc - 用于本地环境特定的格式化的 std::locale

返回值

format_to_n_result ，其 out 成员为指向输出范围末尾后一位置的迭代器，而 size 成员为总（不截断）的输出大小。

异常

传播格式化器或迭代器操作所抛的任何异常。

示例

#include <format>
#include <string_view>
#include <iostream>

int main()
{
    char buffer[64];

    const auto result =
        std::format_to_n(buffer, std::size(buffer),
                         "Hubble's H{0} {1} {2} miles/sec/mpc.",
                         "\u2080", "\u2245", 42);

    std::cout << "Buffer: \"" << std::string_view{buffer, result.size} << "\"\n"
              << "Buffer size = " << std::size(buffer) << '\n'
              << "Untruncated output size = " << result.size << '\n';
}

输出：

Buffer: "Hubble's H₀ ≅ 42 miles/sec/mpc."
Buffer size = 64
Untruncated output size = 35

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2216R3 | C++20 | 对非法格式字符串抛出 std::format_error | 非法格式字符串导致编译时错误

参阅

format (C++20) | 在新 string 中存储参数的格式化表示 (函数模板)
format_to (C++20) | 通过输出迭代器写其参数的格式化表示 (函数模板)
formatted_size (C++20) | 确定存储其参数的格式化表示所需的字符数 (函数模板)


std::formatted_size

< cpp‎ | utility‎ | format
定义于头文件 <format>
template< class... Args >
std::size_t formatted_size( /*format_string<Args...>*/ fmt, const Args&... args );
 (1) (C++20 起)
template< class... Args >
std::size_t formatted_size( /*wformat_string<Args...>*/ fmt, const Args&... args );
 (2) (C++20 起)
template< class... Args >

std::size_t formatted_size( const std::locale & loc,

/*format_string<Args...>*/ fmt, const Args&... args );
 (3) (C++20 起)
template< class... Args >

std::size_t formatted_size( const std::locale & loc,

/*wformat_string<Args...>*/ fmt, const Args&... args );
 (4) (C++20 起)

确定按照格式字符串 fmt 格式化 args 得到的有格式字符串的总字符数。 loc 若存在则用于本地环境特定的格式化。

若对 Args 中任何 Ti ， std::formatter<Ti, CharT> 不满足格式化器 (Formatter) 要求则行为未定义。

参数

fmt -
未指定类型的形参，其初始化仅若实参可转换成 std::string_view （对于 (1,3) ）或 std::wstring_view （对于 (2,4) ），而转换结果是常量表达式和 Args 的合法格式字符串才合法。格式字符串由以下内容组成：
  • 通常字符（除了 { 与 } ），它们被不加修改地复制到输出，
  • 转义序列 {{ 与 }} ，它们在输出中被分别替换成 { 与 } ，以及
  • 替换域。

每个替换域拥有下列格式：

  • 引入的 { 字符；
  • (可选) arg-id ，一个非负数；
  • (可选) 冒号（ : ）后随格式说明；
  • 终止的 } 字符。

arg-id 指定用于格式化其值的 args 中的参数的下标；若省略 arg-id ，则按顺序使用参数。格式字符串中的 arg-id 必须全部存在或全部被省略。混合手动和自动指定下标是错误。

格式说明由对应参数特化的 std::formatter 定义。

  • 对于基本类型和标准字符串类型，格式说明为标准格式说明；
  • 对于标准日期和时间类型，格式说明为 chrono 格式说明；
  • 对于用户定义类型，格式说明由用户定义的 std::formatter 特化决定。
args... - 要格式化的参数
loc - 用于本地环境特定的格式化的 std::locale

返回值

有格式字符串中的总字符数。

异常

传播格式化器所抛的任何异常。

示例

#include <format>
#include <iostream>
#include <vector>
#include <string_view>

int main()
{
    using namespace std::literals::string_view_literals;

    constexpr auto fmt_str { "Hubble's H{0} {1} {2:*^4} miles/sec/mpc."sv };
    constexpr auto sub_zero { "₀"sv };  // { "\u2080"sv } => { 0xe2, 0x82, 0x80 };
    constexpr auto aprox_equ { "≅"sv }; // { "\u2245"sv } => { 0xe2, 0x89, 0x85 };
    constexpr int Ho { 42 }; // H₀

    const auto min_buffer_size = std::formatted_size(fmt_str, sub_zero, aprox_equ, Ho);

    std::cout << "Min buffer size = " << min_buffer_size << '\n';

    // 以 std::vector 为动态缓冲区。注：缓冲区不包含尾随 '\0' 。
    std::vector<char> buffer(min_buffer_size);

    std::format_to_n(buffer.data(), buffer.size(), fmt_str, sub_zero, aprox_equ, Ho);

    std::cout << "Buffer: \"" << std::string_view{buffer.data(), min_buffer_size} << "\"\n";

    // 或者我们能通过添加尾随 '\0' 直接打印缓冲区。
    buffer.push_back('\0');
    std::cout << "Buffer: \"" << buffer.data() << "\"\n";
}

输出：

Min buffer size = 37
Buffer: "Hubble's H₀ ≅ *42* miles/sec/mpc."
Buffer: "Hubble's H₀ ≅ *42* miles/sec/mpc."

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2216R3 | C++20 | 对非法格式字符串抛出 std::format_error | 非法格式字符串导致编译时错误

参阅

format_to (C++20) | 通过输出迭代器写其参数的格式化表示 (函数模板)
format_to_n (C++20) | 通过输出迭代器写其参数的格式化表示，不超出指定的大小 (函数模板)


std::formatter

< cpp‎ | utility‎ | format
定义于头文件 <format> |
template<class T, class CharT = char> struct formatter; | (C++20 起)

formatter 的被启用特化对给定类型定义格式化规则。被启用特化必须满足格式化器 (Formatter) 要求。尤其是它们定义可调用实体 parse 与 format 。

对每组未对其启用特化 std::formatter<T, CharT> 的类型 T 与 CharT ，该特化是完整类型且被禁用。

被禁用特化不满足格式化器 (Formatter) 要求，且下列值均为 false ：

  • std::is_default_constructible_v
  • std::is_copy_constructible_v
  • std::is_move_constructible_v
  • std::is_copy_assignable_v
  • std::is_move_assignable_v

对基本类型和字符串类型的标准特化

以下列表中， CharT 为 char 或 wchar_t ， ArithmeticT 是任何 cv 无限定的算术类型，除了 char、 wchar_t、 char8_t、 char16_t 或 char32_t 。

template<> struct formatter<char, char>;

template<> struct formatter<char, wchar_t>;
template<> struct formatter<wchar_t, wchar_t>;

template<> struct formatter<CharT*, CharT>;
template<> struct formatter<const CharT*, CharT>;
template< std::size_t N> struct formatter<const CharT[N], CharT>;
template<class Traits, class Alloc>
struct formatter< std::basic_string <CharT, Traits, Alloc>, CharT>;
template<class Traits>
struct formatter< std::basic_string_view <CharT, Traits>, CharT>;

template<> struct formatter<ArithmeticT, CharT>;

template<> struct formatter< std::nullptr_t, CharT>;
template<> struct formatter<void*, CharT>;

template<> struct formatter<const void*, CharT>;

对其他指针和指向成员指针的格式化器被禁用。

如 std::formatter<wchar_t, char> 和 std::formatter<const char*, wchar_t> 这些会要求编码转换的特化被禁用。

标准格式说明

对于基本类型和字符串类型，格式说明基于 Python 中的格式说明。

格式说明的语法是：

填充与对齐(可选) 符号(可选) #(可选) 0(可选) 宽度(可选) 精度(可选) L(可选) 类型(可选)

符号 、 # 及 0 选项仅当使用整数或浮点显示类型时合法。

填充与对齐

填充与对齐 是一个可选的填充字符（可为任何 { 或 } 外的的字符），后随对齐选项 < 、 > 、 ^ 之一。对齐选项的意义如下：

  • < ：强制域对齐到可用空间起始。这在使用非整数非浮点显示类型时为默认。
  • > ：强制域对齐到可用空间末尾。这在使用整数或浮点显示类型时为默认。
  • ^ ：强制域在可用空间中央，通过在值的前面插入 ⌊
    n
    2
    ⌋ 个字符，后面插入 ⌈
    n
    2
    ⌉ 个字符，其中 n 是待插入的总字符数。
char c = 120;
auto s0 = std::format("{:6}", 42);    // s0 的值为 "    42"
auto s1 = std::format("{:6}", 'x');   // s1 的值为 "x     "
auto s2 = std::format("{:*<6}", 'x'); // s2 的值为 "x*****"
auto s3 = std::format("{:*>6}", 'x'); // s3 的值为 "*****x"
auto s4 = std::format("{:*^6}", 'x'); // s4 的值为 "**x***"
auto s5 = std::format("{:6d}", c);    // s5 的值为 "   120"
auto s6 = std::format("{:6}", true);  // s6 的值为 "true  "
符号、 # 与 0

符号 选项能为下列之一：

  • + ：指示符号应该一同用于非负数和负数。在非负数的输出值前插入 + 号。
  • - ：指示符号应该仅用于负数（这是默认行为）。
  • 空格：指示应对非负数使用前导空格，而对负数使用负号。

负零被当作负数。

符号 选项应用于浮点无穷大和 NaN 。

double inf = std::numeric_limits<double>::infinity();
double nan = std::numeric_limits<double>::quiet_NaN();
auto s0 = std::format("{0:},{0:+},{0:-},{0: }", 1);   // s0 的值为 "1,+1,1, 1"
auto s1 = std::format("{0:},{0:+},{0:-},{0: }", -1);  // s1 的值为 "-1,-1,-1,-1"
auto s2 = std::format("{0:},{0:+},{0:-},{0: }", inf); // s2 的值为 "inf,+inf,inf, inf"
auto s3 = std::format("{0:},{0:+},{0:-},{0: }", nan); // s3 的值为 "nan,+nan,nan, nan"

# 选项导致将替用形式用于转换。

  • 对于整数类型，使用二进制、八进制或十六进制显示类型时，替用形式插入前缀（ 0b 、 0 或 0x ）到输出值中，若有符号则于符号（可为空格）前，否则于输出值前。
  • 对于浮点类型，替用形式导致有限值的转换结果始终含有小数点字符，即使其后无数位。正常情况下，小数点字符仅若有数位后随它才出现于转换结果。另外，对于 g 与 G 转换，不从结果移除尾随的零。

0 选项以前导零填充域（后随任何符号或底）到域宽，除了应用到无穷大或 NaN 时。若 0 字符与对齐选项一同出现，则忽略 0 字符。

char c = 120;
auto s1 = std::format("{:+06d}", c);   // s1 的值为 "+00120"
auto s2 = std::format("{:#06x}", 0xa); // s2 的值为 "0x000a"
auto s3 = std::format("{:<06}", -42);  // s3 的值为 "-42   " （因 < 对齐忽略 0 ）
宽度与精度

宽度 为正十进制数，或嵌套的替换域（ {} 或 {n} ）。宽度若存在则指定最小域宽。

精度 为点（ . ）后随非负十进制数或嵌套的替换域。此域指示精度或最大域大小。它仅能用于浮点与字符串类型。对于浮点类型，此域指定格式化精度。对于字符串类型，它提供要复制到输出的字符串前缀的估计宽度（见后述）的上界。对于以 Unicode 编码的字符串，复制到输出的文本是整个扩展字素集群的，使得估计宽度不大于精度的最长前缀。

若 宽度 或 精度 中使用嵌套的替换域，而对应的参数不是整数类型，或为负，或对于 宽度 为零，则抛出 std::format_error 类型异常。

float pi = 3.14f;
auto s1 = std::format("{:10f}", pi);           // s1 = "  3.140000" （宽度 = 10 ）
auto s2 = std::format("{:{}f}", pi, 10);       // s2 = "  3.140000" （宽度 = 10 ）
auto s3 = std::format("{:.5f}", pi);           // s3 = "3.14000" （精度 = 5 ）
auto s4 = std::format("{:.{}f}", pi, 5);       // s4 = "3.14000" （精度 = 5 ）
auto s5 = std::format("{:10.5f}", pi);         // s5 = "   3.14000"
                                               // （宽度 = 10 ，精度 = 5 ）
auto s6 = std::format("{:{}.{}f}", pi, 10, 5); // s6 = "   3.14000"
                                               // （宽度 = 10 ，精度 = 5 ）

auto b1 = std::format("{:{}f}", pi, 10.0);     // 抛出：宽度不是整数类型
auto b2 = std::format("{:{}f}", pi, -10);      // 抛出：宽度为负
auto b3 = std::format("{:.{}f}", pi, 5.0);     // 抛出：精度不是整数类型

对于字符串类型，宽度定义为适合将它显示到终端的估计列位置数值。

就宽度计算目的，假设字符串用实现定义的编码。宽度计算的方法是未指定的，但对于以 Unicode 的字符串，实现应该估计字符串的宽度为其扩展字素集群中首个码位的估计宽度之和。若 Unicode 码位在下列范围内，则估计宽度为 2 ，否则为 1 ：

  • U+1100 - U+115F
  • U+2329 - U+232A
  • U+2E80 - U+303E
  • U+3040 - U+A4CF
  • U+AC00 - U+D7A3
  • U+F900 - U+FAFF
  • U+FE10 - U+FE19
  • U+FE30 - U+FE6F
  • U+FF00 - U+FF60
  • U+FFE0 - U+FFE6
  • U+1F300 - U+1F64F
  • U+1F900 - U+1F9FF
  • U+20000 - U+2FFFD
  • U+30000 - U+3FFFD
auto s1 = std::format("{:.^5s}",   "🐱");      // s1 = ".🐱.."
auto s2 = std::format("{:.5s}",    "🐱🐱🐱");  // s2 = "🐱🐱"
auto s3 = std::format("{:.<5.5s}", "🐱🐱🐱");  // s3 = "🐱🐱."
L （本地环境特定的格式化）

L 选项导致使用本地环境特定的形式。此选项仅对算术类型合法。

  • 对于整数类型，本地环境特定形式按照环境的本地环境，插入适合的数位组分隔字符。
  • 对于浮点类型，本地环境特定形式按照环境的本地环境，插入适合的数位组和底分隔字符。
  • 对于 bool 的文本表示，本地环境特定形式使用如同通过 std::numpunct::truename 或 std::numpunct::falsename 获得的字符串。
类型

类型 选项确定应该如何显示数据。

可用的字符串显示类型为：

  • 无、 s ：复制字符串到输出。

可用的 char 、 wchar_t 与 bool 外的整数类型的整数显示类型为：

  • b ：二进制格式。如同通过调用 std::to_chars(first, last, value, 2) 产生输出。底前缀为 0b 。
  • B ：同 b ，除了底前缀为 0B 。
  • c ：复制字符 static_cast<CharT>(value) 到输出，其中 CharT 是格式字符串的字符类型。若值不在 CharT 的可表示值的范围中则抛出 std::format_error 。
  • d ：十进制格式。如同通过调用 std::to_chars(first, last, value) 产生输出。
  • o ：八进制格式。如同通过调用 std::to_chars(first, last, value, 8).产生输出。若对应参数值非零则底前缀为 0 ，否则为空。
  • x ：十六进制格式。如同通过调用 std::to_chars(first, last, value, 16) 产生输出。底前缀为 0x 。
  • X ：同 x ，除了对 9 以上的数字使用大写字母且底前缀为 0X 。
  • 无：同 d 。

可用的 char 及 wchar_t 表示类型为：

  • 无、 c ：复制字符到输出。
  • b 、 B 、 d 、 o 、 x 、 X ：使用整数表示类型。

可用的 bool 表示类型为：

  • 无、 s ：复制文本表示（ true 或 false 或本地环境特定形式）到输出。
  • b 、 B 、 c 、 d 、 o 、 x 、 X ：以值 static_cast<unsigned char>(value) 使用整数表示类型。

可用的浮点表示类型为：

  • a ：若指定精度，则如同通过调用 std::to_chars(first, last, value, std::chars_format::hex, precision) 产生输出，其中 precision 是指定的精度，否则如同通过 std::to_chars(first, last, value, std::chars_format::hex) 产生输出。
  • A ：同 a ，除了对 9 以上的数字使用大写字母并用 P 指示指数。
  • e ：如同通过调用 std::to_chars(first, last, value, std::chars_format::scientific, precision) 产生输出，其中 precision 为指定的精度，或若未指定精度则为 6 。
  • E ：同 e ，除了用 E 指示指数。
  • f 、 F ：如同通过调用 std::to_chars(first, last, value, std::chars_format::fixed, precision) 产生输出，其中 precision 为指定的精度，或若未指定精度则为 6 。
  • g ：如同通过调用 std::to_chars(first, last, value, std::chars_format::general, precision) 产生输出，其中 precision 为指定的精度，或若未指定精度则为 6 。
  • G ：同 g ，除了用 E 指示指数。
  • 无：若指定精度，则如同通过调用 std::to_chars(first, last, value, std::chars_format::general, precision) 产生输出，其中 precision 为指定的精度；否则如同通过调用 std::to_chars(first, last, value) 产生输出。

对于小写表示类型，分别格式化无穷大和 NaN 为 inf 与 nan 。对于大写表示类型，分别格式化无穷大和 NaN 为 INF 与 NAN 。

可用的指针表示类型（亦用于 std::nullptr_t ）为：

  • 无、 p ：若定义 std::uintptr_t ，则如同通过调用 std::to_chars(first, last, reinterpret_cast< std::uintptr_t >(value), 16) 产生输出，并添加前缀 0x 到输出；否则输出为实现定义。

库类型的标准特化

std::formatter<std::chrono::duration> (C++20) | std::formatter 的特化，按提供的格式格式化 duration (类模板特化)
std::formatter<std::chrono::sys_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 sys_time (类模板特化)
std::formatter<std::chrono::utc_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 utc_time (类模板特化)
std::formatter<std::chrono::tai_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 tai_time (类模板特化)
std::formatter<std::chrono::gps_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 gps_time (类模板特化)
std::formatter<std::chrono::file_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 file_time (类模板特化)
std::formatter<std::chrono::local_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 local_time (类模板特化)
std::formatter<std::chrono::day> (C++20) | std::formatter 的特化，按照提供的格式格式化 day (类模板特化)
std::formatter<std::chrono::month> (C++20) | std::formatter 的特化，按照提供的格式格式化 month (类模板特化)
std::formatter<std::chrono::year> (C++20) | std::formatter 的特化，按照提供的格式格式化 year (类模板特化)
std::formatter<std::chrono::weekday> (C++20) | std::formatter 的特化，按照提供的格式格式化 weekday (类模板特化)
std::formatter<std::chrono::weekday_indexed> (C++20) | std::formatter 的特化，按照提供的格式格式化 weekday_indexed (类模板特化)
std::formatter<std::chrono::weekday_last> (C++20) | std::formatter 的特化，按照提供的格式格式化 weekday_last (类模板特化)
std::formatter<std::chrono::month_day> (C++20) | std::formatter 的特化，按照提供的格式格式化 month_day (类模板特化)
std::formatter<std::chrono::month_day_last> (C++20) | std::formatter 的特化，按照提供的格式格式化 month_day_last (类模板特化)
std::formatter<std::chrono::month_weekday> (C++20) | std::formatter 的特化，按照提供的格式格式化 month_weekday (类模板特化)
std::formatter<std::chrono::month_weekday_last> (C++20) | std::formatter 的特化，按照提供的格式格式化 month_weekday_last (类模板特化)
std::formatter<std::chrono::year_month> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month (类模板特化)
std::formatter<std::chrono::year_month_day> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month_day (类模板特化)
std::formatter<std::chrono::year_month_day_last> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month_day_last (类模板特化)
std::formatter<std::chrono::year_month_weekday> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month_weekday (类模板特化)
std::formatter<std::chrono::year_month_weekday_last> (C++20) | std::formatter 的特化，按照提供的格式格式化 year_month_weekday_last (类模板特化)
std::formatter<std::chrono::hh_mm_ss> (C++20) | std::formatter 的特化，按照提供的格式格式化 hh_mm_ss (类模板特化)
std::formatter<std::chrono::sys_info> (C++20) | std::formatter 的特化，按照提供的格式格式化 sys_info (类模板特化)
std::formatter<std::chrono::local_info> (C++20) | std::formatter 的特化，按照提供的格式格式化 local_info (类模板特化)
std::formatter<std::chrono::zoned_time> (C++20) | std::formatter 的特化，按照提供的格式格式化 zoned_time (类模板特化)

示例

#include <format>
#include <iostream>

// 类型 T 的包装
template<class T>
struct Box {
    T value;
};

// 能用被包装值的格式说明格式化包装 Box<T>
template<class T, class CharT>
struct std::formatter<Box<T>, CharT> : std::formatter<T, CharT> {
    // 从基类继承 parse()

    // 通过以被包装值调用基类实现定义 format()
    template<class FormatContext>
    auto format(Box<T> t, FormatContext& fc) {
        return std::formatter<T, CharT>::format(t.value, fc);
    }
};

int main() {
    Box<int> v = { 42 };
    std::cout << std::format("{:#x}", v);
}

输出：

0x2a

参阅

basic_format_contextformat_contextwformat_context
(C++20)(C++20)(C++20)
 格式化状态，包括所有格式化参数和输出迭代器
(类模板)


std::make_format_args, std::make_wformat_args

< cpp‎ | utility‎ | format
定义于头文件 <format>
template<class Context = std::format_context, class... Args>
/*format-arg-store*/<Context, Args...> make_format_args(const Args&... args);
 (1) (C++20 起)
template<class... Args>
/*format-arg-store*/<std::wformat_context, Args...> make_wformat_args(const Args&... args);
 (2) (C++20 起)

返回存储格式化参数的数组，并可隐式转换到 std::basic_format_args<Context> 的对象。

若对 Args 中的任何 Ti ， typename Context::template formatter_type<Ti> 不满足格式化器 (Formatter) 要求，则行为未定义。

参数

args... - 用作格式化参数的值

返回

保有格式化参数的对象。

注解

格式化参数对用户定义类型拥有引用语义而且不延长 args 的生命期。程序员负责确保 args 比返回值存活更久。通常结果仅用作格式化函数的参数。

示例

本节未完成
原因：暂无示例

参阅


std::vformat

< cpp‎ | utility‎ | format
定义于头文件 <format> |  |
std::string vformat( std::string_view fmt, std::format_args args); | (1) | (C++20 起)
std::wstring vformat( std::wstring_view fmt, std::wformat_args args); | (2) | (C++20 起)
std::string vformat(const std::locale & loc, std::string_view fmt, std::format_args args); | (3) | (C++20 起)
std::wstring vformat(const std::locale & loc, std::wstring_view fmt, std::wformat_args args); | (4) | (C++20 起)

按照格式字符串 fmt 格式化 args ，并返回作为 string 的结果。 loc 若存在，则用于本地环境特定的格式化。

参数

fmt -
表示格式字符串的字符串视图。格式字符串由以下内容组成：
  • 通常字符（除了 { 与 } ），它们被不加修改地复制到输出，
  • 转义序列 {{ 与 }} ，它们在输出中被分别替换成 { 与 } ，以及
  • 替换域。

每个替换域拥有下列格式：

  • 引入的 { 字符；
  • (可选) arg-id ，一个非负数；
  • (可选) 冒号（ : ）后随格式说明；
  • 终止的 } 字符。

arg-id 指定用于格式化其值的 args 中的参数的下标；若省略 arg-id ，则按顺序使用参数。格式字符串中的 arg-id 必须全部存在或全部被省略。混合手动和自动指定下标是错误。

格式说明由对应参数特化的 std::formatter 定义。

  • 对于基本类型和标准字符串类型，格式说明为标准格式说明；
  • 对于标准日期和时间类型，格式说明为 chrono 格式说明；
  • 对于用户定义类型，格式说明由用户定义的 std::formatter 特化决定。
args... - 要格式化的参数
loc - 用于本地环境特定格式化的 std::locale

返回值

保有格式化结果的 string 对象。

异常

若 fmt 对于提供的参数不是合法的格式字符串则抛出 std::format_error ，在分配失败时抛出 std::bad_alloc 。并传播格式化器或迭代器操作所抛的任何异常。

示例

本节未完成
原因：暂无示例

参阅


std::vformat_to

< cpp‎ | utility‎ | format
定义于头文件 <format>
template< class OutputIt >
OutputIt vformat_to( OutputIt out, std::string_view fmt, std::format_args args );
 (1) (C++20 起)
template< class OutputIt >
OutputIt vformat_to( OutputIt out, std::wstring_view fmt, std::wformat_args args );
 (2) (C++20 起)
template< class OutputIt >

OutputIt vformat_to( OutputIt out, const std::locale & loc,

std::string_view fmt, std::format_args args );
 (3) (C++20 起)
template< class OutputIt >

OutputIt vformat_to( OutputIt out, const std::locale & loc,

std::wstring_view fmt, std::wformat_args args );
 (4) (C++20 起)

按照格式字符串 fmt 格式化 args ，并写结果到输出迭代器 out 。 loc 若存在则用于本地环境特定的格式化。

令 CharT 为 decltype(fmt)::char_type （对重载 (1,3) 为 char ，对重载 wchar_t 为 (2,4) ）。

这些重载仅若 OutputIt 满足概念 std::output_iterator<const CharT&> 才参与重载决议。若 OutputIt 不实现（满足其语义要求）概念 std::output_iterator<const CharT&> ，或若对 Args 中任何 Ti ， std::formatter<Ti, CharT> 不满足格式化器 (Formatter) 要求则行为未定义。

参数

out - 指向输出缓冲区的迭代器
fmt -
表示格式字符串的字符串视图。格式字符串由以下内容组成：
  • 通常字符（除了 { 与 } ），它们被不加修改地复制到输出，
  • 转义序列 {{ 与 }} ，它们在输出中被分别替换成 { 与 } ，以及
  • 替换域。

每个替换域拥有下列格式：

  • 引入的 { 字符；
  • (可选) arg-id ，一个非负数；
  • (可选) 冒号（ : ）后随格式说明；
  • 终止的 } 字符。

arg-id 指定用于格式化其值的 args 中的参数的下标；若省略 arg-id ，则按顺序使用参数。格式字符串中的 arg-id 必须全部存在或全部被省略。混合手动和自动指定下标是错误。

格式说明由对应参数特化的 std::formatter 定义。

  • 对于基本类型和标准字符串类型，格式说明为标准格式说明；
  • 对于标准日期和时间类型，格式说明为 chrono 格式说明；
  • 对于用户定义类型，格式说明由用户定义的 std::formatter 特化决定。
args... - 要格式化的参数
loc - 用于本地环境特定的格式化的 std::locale

返回值

输出范围末尾后一位置的迭代器。

异常

若 fmt 对于提供的参数不是合法的格式字符串则抛出 std::format_error 。并且会传播格式化器或迭代器操作所抛的任何异常。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2216R3 | C++20 | args 的类型在 OutputIt 上参数化 | 不参数化

参阅


std::visit_format_arg

< cpp‎ | utility‎ | format
定义于头文件 <format> |
template<class Visitor, class Context> /*see below*/ visit_format_arg(Visitor&& vis, std::basic_format_arg<Context> arg); | (C++20 起)

应用 vis 到 arg 中含有的对象。等价于

std::visit ( std::forward <Visitor>(vis), value)

其中 value 是存储于 arg 的 std::variant 。

参数

vis | - | 接受来自 arg 的每个可能可选项的可调用 (Callable)
arg | - | 要观览的 std::basic_format_arg

返回值

选择的观览器调用所返回的值。

示例

本节未完成
原因：暂无示例

参阅


std::forward

< cpp‎ | utility
定义于头文件 <utility> |
 | (1)
template< class T > T&& forward( typename std::remove_reference <T>::type& t ) noexcept; |  | (C++11 起) (C++14 前)
template< class T > constexpr T&& forward( std::remove_reference_t <T>& t ) noexcept; |  | (C++14 起)
 | (2)
template< class T > T&& forward( typename std::remove_reference <T>::type&& t ) noexcept; |  | (C++11 起) (C++14 前)
template< class T > constexpr T&& forward( std::remove_reference_t <T>&& t ) noexcept; |  | (C++14 起)
1) 转发左值为左值或右值，依赖于 T

当 t 是转发引用（作为到无 cv 限定函数模板形参的右值引用的函数实参），此重载将参数以在传递给调用方函数时的值类别转发给另一个函数。

例如，若用于如下的包装器，则模板表现为下方所描述：

template<class T>
void wrapper(T&& arg)
{
    // arg 始终是左值
    foo(std::forward<T>(arg)); // 转发为左值或右值，依赖于 T
}
  • 若对 wrapper() 的调用传递右值 std::string ，则推导 T 为 std::string （非 std::string& 或 std::string&& ，且 std::forward 确保将右值引用传递给 foo 。
  • 若对 wrapper() 的调用传递 const 左值 std::string ，则推导 T 为 const std::string& ，且 std::forward 确保将 const 左值引用传递给 foo 。
  • 若对 wrapper() 的调用传递非 const 左值 std::string ，则推导 T 为 std::string& ，且 std::forward 确保将非 const 左值引用传递给 foo 。
2) 转发右值为右值并禁止右值的转发为左值

此重载令转发表达式（如函数调用）的结果可行，结果可以是右值或左值，同转发引用参数的原始值类别。

例如，若包装器不仅转发其参数，还在参数上调用成员函数，并转发其结果：

// 转换包装器
template<class T>
void wrapper(T&& arg)
{
    foo(forward<decltype(forward<T>(arg).get())>(forward<T>(arg).get()));
}

其中 arg 的类型可以是

struct Arg
{
    int i = 1;
    int  get() && { return i; } // 此重载的调用为右值
    int& get() &  { return i; } // 此重载的调用为左值
};

试图转发右值为左值，例如通过以左值引用类型 T 实例化形式 (2) ，会产生编译时错误。

注意

转发引用背后的特殊规则（ T&& 用作函数参数）见模板实参推导，其他细节见转发引用。

参数

t - 要转发的对象

返回值

static_cast<T&&>(t)

示例

此示例演示参数到类 T 构造函数实参的完美转发。并展示参数包的完美转发。

#include <iostream>
#include <memory>
#include <utility>

struct A {
    A(int&& n) { std::cout << "rvalue overload, n=" << n << "\n"; }
    A(int& n)  { std::cout << "lvalue overload, n=" << n << "\n"; }
};

class B {
public:
    template<class T1, class T2, class T3>
    B(T1&& t1, T2&& t2, T3&& t3) :
        a1_{std::forward<T1>(t1)},
        a2_{std::forward<T2>(t2)},
        a3_{std::forward<T3>(t3)}
    {
    }

private:
    A a1_, a2_, a3_;
};

template<class T, class U>
std::unique_ptr<T> make_unique1(U&& u)
{
    return std::unique_ptr<T>(new T(std::forward<U>(u)));
}

template<class T, class... U>
std::unique_ptr<T> make_unique2(U&&... u)
{
    return std::unique_ptr<T>(new T(std::forward<U>(u)...));
}

int main()
{
    auto p1 = make_unique1<A>(2); // 右值
    int i = 1;
    auto p2 = make_unique1<A>(i); // 左值

    std::cout << "B\n";
    auto t = make_unique2<B>(2, i, 3);
}

输出：

rvalue overload, n=2
lvalue overload, n=1
B
rvalue overload, n=2
lvalue overload, n=1
rvalue overload, n=3

复杂度

常数

参阅

move (C++11) | 获得右值引用 (函数模板)
move_if_noexcept (C++11) | 若移动构造函数不抛出则获得右值引用 (函数模板)


std::from_chars, std::from_chars_result

< cpp‎ | utility
定义于头文件 <charconv>
std::from_chars_result from_chars(const char* first, const char* last,
/*see below*/& value, int base = 10);
 (1) (C++17 起)
std::from_chars_result from_chars(const char* first, const char* last, float& value,
std::chars_format fmt = std::chars_format::general);
 (2) (C++17 起)
std::from_chars_result from_chars(const char* first, const char* last, double& value,
std::chars_format fmt = std::chars_format::general);
 (3) (C++17 起)
std::from_chars_result from_chars(const char* first, const char* last, long double& value,
std::chars_format fmt = std::chars_format::general);
 (4) (C++17 起)
辅助类型
struct from_chars_result {

const char* ptr;
std::errc ec;

};
 (5) (C++17 起)

按照后述模式分析字符序列 [first,last) 。若无字符匹配模式或若按照分析匹配字符获得的值不能以 value 的类型表示，则不修改 value ，否则将匹配模式的字符转译成算术值的文本表示，并将值存储于 value 。

1) 整数分析函数：期待等同于 std::strtol 于默认（ "C" ）本地环境所使用者相同的模式，并给定非零整数底，除了
  • 对底 16 不识别 "0x" 或 "0X" 前缀
  • 仅识别负号（不识别正号），而且只针对 value 的有符号整数类型。
库为所有有符号和无符号整数类型和 char 提供重载，这些类型是参数 value 的被引用类型。
2-4) 浮点分析函数：期待期待等同于 std::strtod 于默认（ "C" ）本地环境所使用者相同的模式，除了
  • 不识别指数外的正号（在起始位置只允许出现负号）
  • 若 fmt 设置了 std::chars_format::scientific 而无 std::chars_format::fixed ，则要求指数部分（否则可选）
  • 若 fmt 设置了 std::chars_format::fixed 而无 std::chars_format::scientific ，则不允许可选的指数部分
  • 若 fmt 为 std::chars_format::hex ，则不允许前缀 "0x" 或 "0X" （字符串 "0x123" 分析为值 "0" 和未分析的剩余 "x123" ）。
任何情况下，按照 std::round_to_nearest 舍入后，结果值是至多二个最接近匹配模式的字符串的值的浮点值之一。
5) 返回值类型（见后述返回值）。 std::from_chars_result 无基类或 ptr 、 ec 及隐式声明的特殊成员函数以外的成员。

参数

first, last | - | 要分析的合法字符范围
value | - | 存储被分析值的输出参数，若分析成功
base | - | 使用的整数基底： 2 与 36 间的值（含上下限）。
fmt | - | 使用的浮点格式， std::chars_format 类型的位掩码

返回值

成功时，返回 from_chars_result 类型的值，其 ptr 指向首个不匹配模式的字符，或若所有字符皆匹配则指向拥有等于 last 的值，其 ec 被值初始化。

若无可匹配的模式，则返回 from_chars_result 类型的值，其 ptr 等于 first 且 ec 等于 std::errc::invalid_argument 。不修改 value 。

若模式匹配，但被分析值不在 value 的类型所表示的范围内，则返回 from_chars_result 类型的值，其 ec 等于 std::errc::result_out_of_range 且 ptr 指向首个不匹配模式的字符。不修改 value 。

operator==(std::from_chars_result)

friend bool operator==( const from_chars_result&, const from_chars_result& ) = default; | (C++20 起)

检查两个参数的 ptr 与 ec 是否分别相等。

此函数对通常无限定或有限定查找不可见，而只能在 std::from_chars_result 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

异常

不抛出。

注解

不同于 C++ 和 C 库中的其他格式化函数， std::from_chars 是独立于本地环境、不分配、不抛出的。它只提供其他库（例如 std::sscanf ）所用策略的一个小子集。它的目的是在常见的高吞吐量环境，例如基于文本的交换（ JSON 或 XML ）中，允许尽可能快的实现。

仅当两个函数都来自同一实现的情况下，才保证 std::from_chars 能恢复每个由 to_chars 格式化的浮点值。

由无后随数位的符号组成的模式被当做不匹配任何内容的模式。

示例

#include <iostream>
#include <charconv>
#include <array>

int main()
{
    std::array<char, 10> str{"42"};
    int result;
    std::from_chars( str.data(), str.data()+str.size(),result );
    std::cout << result;
    return 0;
}

输出：

42

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2955 | C++17 | 此函数在 <utility> 并使用 std::error_code | 移动到 <charconv> 并使用 std::errc
LWG 3373 | C++17 | from_chars_result 可能拥有额外的成员 | 禁止额外的成员

参阅

to_chars (C++17) | 转换整数或浮点值到字符序列 (函数)
stoistolstoll (C++11)(C++11)(C++11) | 转换字符串为有符号整数 (函数)
stofstodstold (C++11)(C++11)(C++11) | 转换字符串为浮点值 (函数)
strtolstrtoll (C++11) | 转换字节字符串为整数值 (函数)
strtofstrtodstrtold | 转换字节字符串为浮点值 (函数)
scanffscanfsscanf | 从 stdin、文件流或缓冲区读取有格式输入 (函数)
operator>> | 提取带格式数据 (std::basic_istream<CharT,Traits> 的公开成员函数)


函数对象

< cpp‎ | utility

任何定义了函数调用操作符的对象都是函数对象。C++ 支持创建、操作新的函数对象，同时也提供了许多内置的函数对象。

函数包装器

std::function 提供存储任意类型函数对象的支持。

function (C++11) | 包装具有指定函数调用签名的任意可复制构造类型的可调用对象 (类模板)
move_only_function (C++23) | 包装具有指定函数调用签名的任意类型的可调用对象 (类模板)
bad_function_call (C++11) | 调用空的 std::function 时抛出的异常 (类)
mem_fn (C++11) | 从成员指针创建出函数对象 (函数模板)

函数调用

std::invoke 能以给定参数调用任何可调用 (Callable) 对象。

invokeinvoke_r
(C++17)(C++23)
 以给定实参和可能指定的返回类型 (C++23 起)调用任意可调用 (Callable) 对象
(函数模板)

恒等

std::identity 是恒等函数对象：它返回其不修改的参数。

identity
(C++20)
 返回其未修改的参数的函数对象
(类)

部分函数应用

std::bind_front 与 std::bind 提供部分函数应用的支持，即绑定参数到函数以创建新函数。

bind_front (C++20) | 按顺序绑定一定数量的参数到函数对象 (函数模板)
bind (C++11) | 绑定一或多个实参到函数对象 (函数模板)
is_bind_expression (C++11) | 指示对象为 std::bind 表达式，或能被用作这种表达式 (类模板)
is_placeholder (C++11) | 表明一个对象是标准占位符，或者可以用作标准占位符 (类模板)
定义于命名空间 std::placeholders
_1, _2, _3, _4, ... (C++11) | 用作 std::bind 表达式中的未绑定实参的占位符 (常量)

取反器

std::not_fn 创建对传递给它的可调用对象的结果取反的函数对象。

not_fn
(C++17)
 创建返回其保有的函数对象的结果之补的函数对象
(函数模板)

搜索器

提供实现数种字符串搜索算法的搜索器。它们能直接使用或用于 std::search 。

default_searcher (C++17) | 标准 C++ 库搜索算法实现 (类模板)
boyer_moore_searcher (C++17) | Boyer-Moore 搜索算法实现 (类模板)
boyer_moore_horspool_searcher (C++17) | Boyer-Moore-Horspool 搜索算法实现 (类模板)

引用包装器

引用包装器允许存储引用到可复制的函数对象中：

reference_wrapper (C++11) | 可复制构造 (CopyConstructible) 且可复制赋值 (CopyAssignable) 的引用包装器 (类模板)
refcref (C++11)(C++11) | 创建具有从其实参推导的类型的 std::reference_wrapper (函数模板)
unwrap_referenceunwrap_ref_decay (C++20)(C++20) | 获取包装于 std::reference_wrapper 的引用类型 (类模板)

运算符函数对象

C++ 针对常用的算术和逻辑运算定义了很多函数对象：

算术运算
plus
 实现 x + y 的函数对象
(类模板)
minus
 实现 x - y 的函数对象
(类模板)
multiplies
 实现 x * y 的函数对象
(类模板)
divides
 实现 x / y 的函数对象
(类模板)
modulus
 实现 x % y 的函数对象
(类模板)
negate
 实现 -x 的函数对象
(类模板)
比较
equal_to
 实现 x == y 的函数对象
(类模板)
not_equal_to
 实现 x != y 的函数对象
(类模板)
greater
 实现 x > y 的函数对象
(类模板)
less
 实现 x < y 的函数对象
(类模板)
greater_equal
 实现 x >= y 的函数对象
(类模板)
less_equal
 实现 x <= y 的函数对象
(类模板)
逻辑运算
logical_and
 实现 x && y 的函数对象
(类模板)
logical_or
 实现 x || y 的函数对象
(类模板)
logical_not
 实现 !x 的函数对象
(类模板)
位运算
bit_and
 实现 x & y 的函数对象
(类模板)
bit_or
 实现 x | y 的函数对象
(类模板)
bit_xor
 实现 x ^ y 的函数对象
(类模板)
bit_not
(C++14)
 实现 ~x 的函数对象
(类模板)

受约束的比较函数对象

C++20 定义一组受约束的比较函数对象。相等运算符 (ranges::equal_to 与 ranges::not_equal_to) 要求参数类型实现 equality_comparable_with 。关系运算符（ ranges::less 、 ranges::greater 、 ranges::less_equal 及 ranges::greater_equal ）要求参数类型实现 totally_ordered_with 。三路比较运算符（ compare_three_way ）要求参数类型实现 three_way_comparable_with 。

ranges::equal_to (C++20) | 实现 x == y 的函数对象 (类)
ranges::not_equal_to (C++20) | 实现 x != y 的函数对象 (类)
ranges::less (C++20) | 实现 x < y 的函数对象 (类)
ranges::greater (C++20) | 实现 x > y 的函数对象 (类)
ranges::less_equal (C++20) | 实现 x <= y 的函数对象 (类)
ranges::greater_equal (C++20) | 实现 x >= y 的函数对象 (类)
compare_three_way (C++20) | 实现 x <=> y 的函数对象 (类)

旧式绑定器与适配器

早期提供功能支持的几个工具在 C++11 中弃用，并于 C++17 中移除（旧否定器于 C++17 中弃用并于 C++20 中移除）：

基类
unary_function
(C++11 中弃用)(C++17 中移除)
 与适配器兼容的一元函数基类
(类模板)
binary_function
(C++11 中弃用)(C++17 中移除)
 与适配器兼容的二元函数基类
(类模板)
绑定器
binder1stbinder2nd
(C++11 中弃用)(C++17 中移除)
 持有一个二元函数及其实参之一的函数对象
(类模板)
bind1stbind2nd
(C++11 中弃用)(C++17 中移除)
 将一个实参绑定到二元函数
(函数模板)
函数适配器
pointer_to_unary_function
(C++11 中弃用)(C++17 中移除)
 适配器兼容的包装，用于包装一元函数的指针
(类模板)
pointer_to_binary_function
(C++11 中弃用)(C++17 中移除)
 适配器兼容的包装，用于包装二元函数的指针
(类模板)
ptr_fun
(C++11 中弃用)(C++17 中移除)
 从函数指针创建与适配器兼容的函数对象包装器
(函数模板)
mem_fun_tmem_fun1_tconst_mem_fun_tconst_mem_fun1_t
(C++11 中弃用)(C++17 中移除)
 指向零元或一元成员函数指针的包装器，可以一个对象指针调用
(类模板)
mem_fun
(C++11 中弃用)(C++17 中移除)
 从成员函数指针创建包装器，可以一个对象指针调用
(函数模板)
mem_fun_ref_tmem_fun1_ref_tconst_mem_fun_ref_tconst_mem_fun1_ref_t
(C++11 中弃用)(C++17 中移除)
 指向零元或一元成员函数指针的包装器，可以一个对象引用调用
(类模板)
mem_fun_ref
(C++11 中弃用)(C++17 中移除)
 从成员函数指针创建包装器，能以一个对象引用调用
(函数模板)
unary_negate
(C++17 中弃用)(C++20 中移除)
 包装器函数对象，返回所持有的一元谓词的补
(类模板)
binary_negate
(C++17 中弃用)(C++20 中移除)
 包装器函数对象，返回所持有的二元谓词的补
(类模板)
not1
(C++17 中弃用)(C++20 中移除)
 构造定制的 std::unary_negate 对象
(函数模板)
not2
(C++17 中弃用)(C++20 中移除)
 构造定制的 std::binary_negate 对象
(函数模板)


std::bad_function_call

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
class bad_function_call; | (C++11 起)

std::bad_function_call 是若函数包装器无目标，则 std::function::operator() 将抛出的异常类型。

cpp/error/exception std-bad function call-inheritance.svg

继承图

成员函数

(构造函数) | 构造新的 bad_function_call 对象 (公开成员函数)
operator= | 替换 bad_function_call 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::bad_function_call::bad_function_call

bad_function_call() noexcept; | (1) | (C++11 起)
bad_function_call( const bad_function_call& other ) noexcept; | (2) | (C++11 起)

构造新的拥有实现定义的空终止字节字符串的 bad_function_call 对象，字符串能通过 what() 访问。

1) 默认构造函数。
2) 复制构造函数。若 *this 与 other 均拥有动态类型 std::bad_function_call 则 std::strcmp (what(), other.what()) == 0 。

参数

other - 要复制的另一异常对象

std::bad_function_call::operator=

bad_function_call& operator=( const bad_function_call& other ) noexcept; | (C++11 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::bad_function_call 则赋值后 std::strcmp (what(), other.what()) == 0 。

参数

other - 用以赋值的另一异常对象

返回值

*this

std::bad_function_call::what

virtual const char* what() const noexcept; | (C++11 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

示例

#include <iostream>
#include <functional>

int main()
{
    std::function<int()> f = nullptr;
    try {
        f();
    } catch(const std::bad_function_call& e) {
        std::cout << e.what() << '\n';
    }
}

可能的输出：

bad function call

参阅

function
(C++11)
 包装具有指定函数调用签名的任意可复制构造类型的可调用对象
(类模板)


std::binary_function

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class Arg1, class Arg2, class Result > struct binary_function; | (C++11 中弃用) (C++17 中移除)

binary_function 是用于创建拥有二个参数的函数对象的基类。

binary_function 不定义 operator() ；它期待导出类将定义此运算符。 binary_function 只提供三个类型—— first_argument_type 、 second_argument_type 和 result_type ——为模板形参所定义。

一些标准库函数适配器，如 std::not2 要求其适配的函数对象必须定义这些类型； std::not2 要求要适配的函数对象必须拥有二个名为 first_argument_type 和 second_argument_type 的类型。从 binary_function 导出接受二个参数的函数对象是令它们与那些适配器兼容的简便方式。

binary_function 于 C++11 弃用并于 C++17 移除。

成员类型

类型 | 定义
first_argument_type | Arg1
second_argument_type | Arg2
result_type | Result

示例

#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>

struct same : std::binary_function<int, int, bool>
{
    bool operator()(int a, int b) const { return a == b; }
};

int main()
{
    std::vector<int> v1{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::vector<int> v2{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
    std::vector<bool> v3(v1.size());

    std::transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), std::not2(same()));

    std::cout << std::boolalpha;
    for (std::size_t i = 0; i < v1.size(); ++i)
        std::cout << v1[i] << ' ' << v2[i] << ' ' << v3[i] << '\n';
}

输出：

0 10 true
1 9 true
2 8 true
3 7 true
4 6 true
5 5 false
6 4 true
7 3 true
8 2 true
9 1 true
10 0 true

参阅

function (C++11) | 包装具有指定函数调用签名的任意可复制构造类型的可调用对象 (类模板)
ptr_fun (C++11 中弃用)(C++17 中移除) | 从函数指针创建与适配器兼容的函数对象包装器 (函数模板)
pointer_to_binary_function (C++11 中弃用)(C++17 中移除) | 适配器兼容的包装，用于包装二元函数的指针 (类模板)
unary_function (C++11 中弃用)(C++17 中移除) | 与适配器兼容的一元函数基类 (类模板)


std::binary_negate

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class Predicate > struct binary_negate : public std::binary_function < Predicate::first_argument_type, Predicate::second_argument_type, bool >; | (C++11 前)
template< class Predicate > struct binary_negate; | (C++11 起) (C++17 中弃用) (C++20 中移除)

binary_negate 是返回其所保有的二元谓词的补的包装函数对象。

二元谓词必须定义二个成员类型， first_argument_type 和 second_argument_type ，可转换为谓词参数类型。从 std::owner_less 、 std::ref 、 std::cref 、 std::plus 、 std::minus 、 std::multiplies 、 std::divides 、 std::modulus 、 std::equal_to 、 std::not_equal_to 、 std::greater 、 std::less 、 std::greater_equal 、 std::less_equal 、 std::logical_not 、 std::logical_or 、 std::bit_and 、 std::bit_or 、 std::bit_xor 、 std::mem_fn 、 std::map::value_comp 、 std::multimap::value_comp 、 std::function 或对 std::not2 调用获得的函数对象定义这些类型，和导出自弃用的 std::binary_function 的函数对象一样。

binary_negate 对象简单地以辅助函数 std::not2 创建。

成员类型

类型 | 定义
first_argument_type | Predicate::first_argument_type
second_argument_type | Predicate::second_argument_type
result_type | bool

成员函数

(构造函数) | 以提供的谓词构造新的 binary_negate 对象 (公开成员函数)
operator() | 返回调用存储的谓词结果的逻辑补 (公开成员函数)

std::binary_negate::binary_negate

explicit binary_negate( Predicate const& pred ); | (C++14 前)
explicit constexpr binary_negate( Predicate const& pred ); | (C++14 起)

构造的 binary_negate 函数对象，拥有存储的谓词 pred 。

参数

pred - 谓词函数对象

std::binary_negate::operator()

bool operator()( first_argument_type const& x,
second_argument_type const& y ) const;
 (C++14 前)
constexpr bool operator()( first_argument_type const& x,
second_argument_type const& y ) const;
 (C++14 起)

返回调用 pred(x, y) 结果的逻辑补。

参数

x | - | 通过谓词传递的第一参数
y | - | 通过谓词传递的第二参数

返回值

调用 pred(x, y) 结果的逻辑补。

示例

#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>

struct same : std::binary_function<int, int, bool>
{
    bool operator()(int a, int b) const { return a == b; }
};

int main()
{
    std::vector<int> v1;
    std::vector<int> v2;
    for (int i = 0; i < 10; ++i) v1.push_back(i);
    for (int i = 0; i < 10; ++i) v2.push_back(10 - i);

    std::vector<bool> v3(v1.size());

    std::binary_negate<same> not_same((same()));

    std::transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), not_same);

    /* C++11 解法：
        // 用 std::function<bool (int, int)>
        std::function<bool (int, int)> not_same =
            [](int x, int y)->bool{ return !same()(x, y); };

        std::transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), not_same);
    */

    std::cout.setf(std::ios_base::boolalpha);
    for (int i = 0; i < 10; ++i)
        std::cout << v1[i] << ' ' << v2[i] << ' ' << v3[i] << '\n';
}

输出：

0 10 true
1 9 true
2 8 true
3 7 true
4 6 true
5 5 false
6 4 true
7 3 true
8 2 true
9 1 true

参阅

binary_function (C++11 中弃用)(C++17 中移除) | 与适配器兼容的二元函数基类 (类模板)
function (C++11) | 包装具有指定函数调用签名的任意可复制构造类型的可调用对象 (类模板)
not2 (C++17 中弃用)(C++20 中移除) | 构造定制的 std::binary_negate 对象 (函数模板)
ptr_fun (C++11 中弃用)(C++17 中移除) | 从函数指针创建与适配器兼容的函数对象包装器 (函数模板)
unary_negate (C++17 中弃用)(C++20 中移除) | 包装器函数对象，返回所持有的一元谓词的补 (类模板)


std::bind

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
 | (1)
template< class F, class... Args > /*unspecified*/ bind( F&& f, Args&&... args ); |  | (C++11 起) (C++20 前)
template< class F, class... Args > constexpr /*unspecified*/ bind( F&& f, Args&&... args ); |  | (C++20 起)
 | (2)
template< class R, class F, class... Args > /*unspecified*/ bind( F&& f, Args&&... args ); |  | (C++11 起) (C++20 前)
template< class R, class F, class... Args > constexpr /*unspecified*/ bind( F&& f, Args&&... args ); |  | (C++20 起)

函数模板 bind 生成 f 的转发调用包装器。调用此包装器等价于以一些绑定到 args 的参数调用 f 。

参数

f | - | 可调用 (Callable) 对象（函数对象、指向函数指针、到函数引用、指向成员函数指针或指向数据成员指针）
args | - | 要绑定的参数列表，未绑定参数为命名空间 std::placeholders 的占位符 _1, _2, _3... 所替换

返回值

未指定类型 T 的函数对象，满足 std::is_bind_expression <T>::value == true 。它有下列属性：

std::bind 返回类型

成员对象

std::bind 的返回类型保有从 std::forward <F>(f) 构造的 std::decay <F>::type 类型成员对象，和对于每个 args... 类型为 std::decay <Arg_i>::type 的各一个对象，类似地从 std::forward <Arg_i>(arg_i) 构造。

构造函数

若 std::bind 的返回类型的所有成员类型（说明如上）为可复制构造 (CopyConstructible) ，则它为可复制构造 (CopyConstructible) ，否则为可移动构造 (MoveConstructible) 。类型定义下列成员：

成员类型 result_type

1) (C++17 中弃用) 若 F 是指向函数或指向成员函数指针，则 result_type 是 F 的返回类型。若 F 是有嵌套 typedef result_type 的类类型，则 result_type 是 F::result_type 。否则不定义 result_type 。

2) (C++17 中弃用) result_type 准确地为 R 。

 (C++20 前)

成员函数 operator()

给定从先前到 bind 调用获得的对象 g ，从函数调用表达式 g(u1, u2, ... uM) 调用它时，发生被存储对象的调用，如同以 std::invoke (fd, std::forward <V1>(v1), std::forward <V2>(v2), ..., std::forward <VN>(vN)) ，其中 fd 是 std::decay_t <F> 类型值，受绑定 v1, v2, ..., vN 参数的值和类型按以下方式确定。

  • 若存储的参数 arg 拥有类型 std::reference_wrapper <T> （例如，在起始的到 bind 调用中使用了 std::ref 或 std::cref ），则上述 std::invoke 调用中的 vn 是 arg.get() 且同一调用中的类型 Vn 是 T& ：存储的参数按引用传递进入被调用的函数对象。
  • 若存储的参数 arg 拥有类型 T 并满足 std::is_bind_expression <T>::value == true （例如，直接传递到起始的对 bind 调用的另一 bind 表达式），则 bind 进行函数组合：不是传递该 bind 子表达式将返回的函数对象，而是饥渴地调用该子表达式，并将其返回值传递给外层可调用对象。若 bind 子表达式拥有任何占位符参数，则将它们与外层 bind 共享（从 u1, u2, ... 中选出）。特别是，上述 std::invoke 调用中的参数 vn 是 arg(std::forward<Uj>(uj)...) 而同一调用中的类型 Vn 是 std::result_of_t <T cv &(Uj&&...)>&& （ cv 限定与 g 的相同）。
  • 若存储的参数 arg 拥有类型 T 并满足 std::is_placeholder <T>::value != 0 （表示以如 std::placeholders::_1, _2, _3, ... 的占位符为到 bind 初始调用的参数），则将占位符所指示的参数（ _1 的 u1 、 _2 的 u2 等）传递给可调用对象：上述 std::invoke 调用中的参数 vn 是 std::forward <Uj>(uj) 而同一调用中对应类型 Vn 是 Uj&& 。
  • 否则，普通的存储参数 arg 作为左值参数传递给：上述 std::invoke 调用中的参数 vn 单纯地是 arg 且对应类型 Vn 是 T cv & ，其中 cv 是与 g 相同的 cv 限定。

若提供于到 g() 调用的一些参数不匹配存储于 g 的任何占位符，则求值并忽略未使用的参数。

若 g 为 volatile 限定（即其 cv 限定符是 volatile 或 const volatile ），则行为未定义。

异常

仅若从 std::forward <F>(f) 构造 std::decay <F>::type 抛出，或从 std::forward <Arg_i>(arg_i) 构造对应的任何 std::decay <Arg_i>::type 抛出才抛出异常，其中 Arg_i 是 Args... args 中第 i 个类型，而 arg_i 是第 i 个参数。

注解

如可调用 (Callable) 中描述，调用指向非静态成员函数指针或指向非静态数据成员指针时，首参数必须是引用或指针（可以包含智能指针，如 std::shared_ptr 与 std::unique_ptr），指向将访问其成员的对象。

到 bind 的参数被复制或移动，而且决不按引用传递，除非包装于 std::ref 或 std::cref 。

允许同一 bind 表达式中的多重占位符（例如多个 _1 ），但结果仅若对应参数（ u1 ）是左值或不可移动右值才良好定义。

示例

#include <random>
#include <iostream>
#include <memory>
#include <functional>

void f(int n1, int n2, int n3, const int& n4, int n5)
{
    std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}

int g(int n1)
{
    return n1;
}

struct Foo {
    void print_sum(int n1, int n2)
    {
        std::cout << n1+n2 << '\n';
    }
    int data = 10;
};

int main()
{
    using namespace std::placeholders;  // 对于 _1, _2, _3...

    // 演示参数重排序和按引用传递
    int n = 7;
    // （ _1 与 _2 来自 std::placeholders ，并表示将来会传递给 f1 的参数）
    auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
    n = 10;
    f1(1, 2, 1001); // 1 为 _1 所绑定， 2 为 _2 所绑定，不使用 1001
                    // 进行到 f(2, 42, 1, n, 7) 的调用

    // 嵌套 bind 子表达式共享占位符
    auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
    f2(10, 11, 12); // 进行到 f(12, g(12), 12, 4, 5); 的调用

    // 常见使用情况：以分布绑定 RNG
    std::default_random_engine e;
    std::uniform_int_distribution<> d(0, 10);
    std::function<int()> rnd = std::bind(d, e); // e 的一个副本存储于 rnd
    for(int n=0; n<10; ++n)
        std::cout << rnd() << ' ';
    std::cout << '\n';

    // 绑定指向成员函数指针
    Foo foo;
    auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
    f3(5);

    // 绑定指向数据成员指针
    auto f4 = std::bind(&Foo::data, _1);
    std::cout << f4(foo) << '\n';

    // 智能指针亦能用于调用被引用对象的成员
    std::cout << f4(std::make_shared<Foo>(foo)) << '\n'
              << f4(std::make_unique<Foo>(foo)) << '\n';
}

输出：

2 42 1 10 7
12 12 12 4 5
1 5 0 2 0 8 2 2 10 8
100
10
10
10

参阅

bind_front (C++20) | 按顺序绑定一定数量的参数到函数对象 (函数模板)
_1, _2, _3, _4, ... (C++11) | 用作 std::bind 表达式中的未绑定实参的占位符 (常量)
mem_fn (C++11) | 从成员指针创建出函数对象 (函数模板)


std::bind1st, std::bind2nd

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |  |
template< class F, class T > std::binder1st<F> bind1st( const F& f, const T& x ); | (1) | (C++11 中弃用) (C++17 中移除)
template< class F, class T > std::binder2nd<F> bind2nd( const F& f, const T& x ); | (2) | (C++11 中弃用) (C++17 中移除)

绑定给定参数 x 到给定二元函数对象 f 的第一或第二参变量。即，在产生的包装器内存储 x ，若调用它，则将 x 传递为 f 的第一或第二参数。

1) 绑定 f 的第一参数到 x 。等效地调用 std::binder1st<F>(f, typename F::first_argument_type(x)) 。
2) 绑定 f 的第二参数到 x 。等效地调用 std::binder2nd<F>(f, typename F::second_argument_type(x)) 。

参数

f | - | 指向要绑定参数到的函数的指针
x | - | 绑定到 f 的参数

返回值

包装 f 和 x 的函数对象。

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <functional>
#include <cmath>
#include <cstddef>
#include <vector>

int main()
{
    std::vector<double> a = {0, 30, 45, 60, 90, 180};
    std::vector<double> r(a.size());
    const double pi = std::acos(-1); // C++20 起使用 std::numbers::pi

    std::transform(a.begin(), a.end(), r.begin(),
        std::bind1st(std::multiplies<double>(), pi / 180.));
//  等价的 lambda 为： [pi](double a){ return a*pi / 180.; });

    for(std::size_t n = 0; n < a.size(); ++n)
        std::cout << std::setw(3) << a[n] << "° = " << std::fixed << r[n]
                  << " rad\n" << std::defaultfloat;
}

输出：

  0° = 0.000000 rad
 30° = 0.523599 rad
 45° = 0.785398 rad
 60° = 1.047198 rad
 90° = 1.570796 rad
180° = 3.141593 rad

参阅

binder1stbinder2nd (C++11 中弃用)(C++17 中移除) | 持有一个二元函数及其实参之一的函数对象 (类模板)
bind_front (C++20) | 按顺序绑定一定数量的参数到函数对象 (函数模板)


std::bind_front

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template <class F, class... Args> constexpr /*unspecified*/ bind_front( F&& f, Args&&... args ); | (C++20 起)

函数模板 bind_front 为 f 生成转发调用包装。调用此包装等价于绑定首 sizeof...(Args) 个参数到 args 再调用 f 。

换言之 std::bind_front(f, bound_args...)(call_args...) 等价于 std::invoke (f, bound_args..., call_args....) 。

若下列任一为 false 则程序为非良构：

  • std::is_constructible_v < std::decay_t <F>, F>
  • std::is_move_constructible_v < std::decay_t <F>>
  • ( std::is_constructible_v < std::decay_t <Args>, Args> && ...)
  • ( std::is_move_constructible_v < std::decay_t <Args>> && ...)

参数

f | - | 将绑定某些参数到的可调用 (Callable) 对象（函数对象、指向函数指针、到函数的引用、指向成员函数指针或指向数据成员指针）
args | - | 参数列表，绑定首 sizeof...(Args) 个参数到 f
类型要求
- std::decay_t<F> 与 std::decay_t<Args>... 中的每个类型 必须满足可移动构造 (MoveConstructible) 的要求。

返回值

未指定的 T 类型函数对象，除了二次以相同参数调用 std::bind_front 返回的类型相同。

返回的对象（调用包装）有下列属性：

std::bind_front 返回类型

成员对象

返回的对象表现为如同它保有从 std::forward <F>(f) 直接非列表初始化的 std::decay_t <F> 类型成员对象 fd ，以及用 std::tuple < std::decay_t <Args>...>( std::forward <Args>(args)...) 构造的 std::tuple 对象 tup （这会解包任何 std::reference_wrapper ），除了返回对象的赋值行为未指定，且名称只为说明。

构造函数

std::bind_front 的构造函数表现为其赋值/移动构造函数进行逐成员复制/移动。若其所有成员对象（指定如上）为可复制构造 (CopyConstructible) )则它为 可复制构造 (CopyConstructible) ，否则为可移动构造 (MoveConstructible) 。

成员函数 operator()

给定从先前调用 bind_front(f, args...) 获得的对象 G ，在函数调用表达式 g(call_args...) 中调用指代 G 的泛左值 g 时，发生存储对象的调用，如同用

std::invoke(g.fd, std::get<Ns>(g.tup)..., call_args...)

，其中

  • Ns 是整数包 0, 1, ..., (sizeof...(Args) - 1)
  • g 若在调用表达式中是左值，则在 std::invoke 表达式中是左值，否则是右值。从而 std::move(g)(call_args...) 能移动绑定的参数到调用中，而 g(call_args...) 会复制。

若 g 拥有 volatile 限定类型则行为未定义。

若其所调用的 std::invoke 表达式为 noexcept 则成员 operator() 为 noexcept （换言之，它保持底层调用运算符的异常说明）。

异常

仅若构造存储的函数对象或任何绑定的参数时抛出才会抛出。

注解

有意令此函数取代 std::bind 。不同于 std::bind ，它不支持任意参数重排，而且不特别处理嵌套的 bind 表达式或 std::reference_wrapper 。另一方面，它注重调用包装对象的值类别，并传播底层调用运算符的异常规定。

如 std::invoke 中描述，调用指向非静态成员函数指针或指向非静态数据成员指针时，首参数必须是到要访问其成员的对象的引用或指针（可以包含智能指针，如 std::shared_ptr 与 std::unique_ptr ）。

复制或移动给 std::bind_front 的参数，而决不按引用传递，除非用 std::ref 或 std::cref 包装它们。

示例

#include <functional>
#include <iostream>

int minus(int a, int b){
    return a-b;
}

struct S
{
  int val;
  int minus(int arg) const noexcept { return val - arg; }
};

int main()
{
    auto fifty_minus = std::bind_front(minus, 50);
    std::cout << fifty_minus (3) << '\n';

    auto member_minus = std::bind_front(&S::minus, S{50});

    std::cout << member_minus (3) << '\n';

    // 保持 noexcept 说明！
    static_assert(! noexcept(fifty_minus (3)));
    static_assert(noexcept(member_minus (3)));

    // 绑定 lambda
    auto plus = [](int a, int b) { return a+b; };
    auto forty_plus = std::bind_front(plus, 40);
    std::cout << forty_plus(7) << '\n';
}

输出：

47
47
47

参阅

bind (C++11) | 绑定一或多个实参到函数对象 (函数模板)
mem_fn (C++11) | 从成员指针创建出函数对象 (函数模板)


std::binder1st, std::binder2nd

< cpp‎ | utility‎ | functional
定义于头文件 <functional>
template< class Fn >

class binder1st : public std::unary_function <typename Fn::second_argument_type,
typename Fn::result_type> {
protected:

Fn op;
typename Fn::first_argument_type value;

public:

binder1st(const Fn& fn,
const typename Fn::first_argument_type& value);

typename Fn::result_type
operator()(const typename Fn::second_argument_type& x) const;

typename Fn::result_type
operator()(typename Fn::second_argument_type& x) const;

};
 (1) (C++11 中弃用)
(C++17 中移除)
template< class Fn >

class binder2nd : public unary_function<typename Fn::first_argument_type,
typename Fn::result_type> {
protected:
Fn op;
typename Fn::second_argument_type value;
public:
binder2nd(const Fn& fn,
const typename Fn::second_argument_type& value);

typename Fn::result_type
operator()(const typename Fn::first_argument_type& x) const;

typename Fn::result_type
operator()(typename Fn::first_argument_type& x) const;

};
 (2) (C++11 中弃用)
(C++17 中移除)

绑定实参到二元函数的函数对象。

在构造时将形参的值传递给对象并在对象中存储。凡在通过 operator() 调用函数对象时，均将存储的值作为实参之一传递，将另一实参作为 operator() 的实参传递。产生的函数对象是一元函数。

1) 绑定第一参数为在对象构造时给定的值 value 。
2) 绑定第二参数为在对象构造时给定的值 value 。

示例

#include <iostream>
#include <functional>
#include <cmath>
#include <vector>
const double pi = std::acos(-1);
int main()
{
    // C++11 中弃用， C++17 中移除
    std::binder1st<std::multiplies<double>> f1 = std::bind1st(
                                                   std::multiplies<double>(), pi / 180.);

    // C++11 替代
    auto f2 = [](double a){ return a*pi/180.; };

    for(double n : {0, 30, 45, 60, 90, 180})
        std::cout << n << " deg = " << f1(n) << " rad (using binder) "
                                    << f2(n) << " rad (using lambda)\n";
}

输出：

0 deg = 0 rad (using binder) 0 rad (using lambda)
30 deg = 0.523599 rad (using binder) 0.523599 rad (using lambda)
45 deg = 0.785398 rad (using binder) 0.785398 rad (using lambda)
60 deg = 1.0472 rad (using binder) 1.0472 rad (using lambda)
90 deg = 1.5708 rad (using binder) 1.5708 rad (using lambda)
180 deg = 3.14159 rad (using binder) 3.14159 rad (using lambda)

参阅

bind1stbind2nd
(C++11 中弃用)(C++17 中移除)
 将一个实参绑定到二元函数
(函数模板)


std::bit_and

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct bit_and; | (C++14 前)
template< class T = void > struct bit_and; | (C++14 起)

进行逐位与的函数对象。等效地调用类型 T 上的 operator& 。

特化

标准库提供 std::bit_and 在不指定 T 时的特化，它使得参数类型和返回类型留待推导。

bit_and<void>
(C++14)
 实现 x & y 并推导参数和返回类型的函数对象
(类模板特化)
(C++14 起)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | T
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, T> 获得。

 (C++11 前)

成员函数

operator()
 返回二个参数逐位与的结果
(公开成员函数)

std::bit_and::operator()

T operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr T operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

返回 lhs 和 rhs 逐位与的结果。

参数

lhs, rhs - 要计算逐位与的值

返回值

lhs & rhs 的结果。

异常

可能抛出实现定义的异常。

可能的实现

constexpr T operator()(const T &lhs, const T &rhs) const
{
    return lhs & rhs;
}


std::bit_and<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class bit_and<void>; | (C++14 起)

std::bit_and <> 是 std::bit_and 的特化，拥有推导出的参数和返回类型。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 应用 operator& 到 lhs 和 rhs
(公开成员函数)

std::bit_and<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) & std::forward <U>(rhs));

返回 lhs & rhs 的结果。

参数

lhs, rhs - 为之计算逐位与的值

返回值

lhs & rhs 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::bit_not

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T = void > struct bit_not; | (C++14 起)

提供进行逐位非的函数对象。等效地调用类型 T 的 operator~ 。

特化

bit_not<void>
(C++14)
 实现 ~x 的函数对象，推导参数及返回类型
(类模板特化)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | T
argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::unary_function <T, T> 获得。

 (C++11 前)

成员函数

operator()
 返回其参数逐位非的结果
(公开成员函数)

std::bit_not::operator()

constexpr T operator()( const T& arg ) const;

返回 arg 逐位非的结果。

参数

arg - 要计算逐位非的值

返回值

~arg 的结果

异常

可能抛出实现定义的异常。

可能的实现

constexpr T operator()(const T& arg) const
{
    return ~arg;
}

注解

尽管 std::bit_not 是经由 C++11 后的提案 N3421 添加的，它（除了其通透特化 std::bit_not<> ）被常见实现当做 LWG 问题 660 的解决方案的一部分，从而在其 C++98/03 模式可用。


std::bit_not<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class bit_not<void>; | (C++14 起)

std::bit_not <> 是拥有推导出的参数和模板类型的 std::bit_not 特化。

成员类型

成员类型 | 定义
is_transparent | /* unspecified */

成员函数

operator()
 应用 operator~ 到其参数
(公开成员函数)

std::bit_not<>::operator()

template< class T >

constexpr auto operator()( T&& arg ) const

-> decltype(~std::forward <T>(lhs));

返回 ~arg 的结果。

参数

arg - 要应用逐位非的值

返回值

~arg 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::bit_or

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct bit_or; | (C++14 前)
template< class T = void > struct bit_or; | (C++14 起)

进行逐位或的函数对象。等效地在类型 T 上调用 operator| 。

特化

标准库提供 std::bit_or 在不指定 T 时的特化，这使得参数类型和返回类型留待推导。

bit_or<void>
(C++14)
 实现 x | y 并推导参数和返回类型的函数对象
(类模板特化)
(C++14 起)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | T
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, T> 获得。

 (C++11 前)

成员函数

operator()
 返回二个参数逐位或的结果
(公开成员函数)

std::bit_or::operator()

T operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr T operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

返回 lhs 和 rhs 逐位或的结果。

参数

lhs, rhs - 要计算逐位或的值

返回值

lhs | rhs 的结果。

异常

可能抛出实现定义的异常。

可能的实现

constexpr T operator()(const T &lhs, const T &rhs) const
{
    return lhs | rhs;
}


std::bit_or<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class bit_or<void>; | (C++14 起)

std::bit_or <> 是 std::bit_or 的特化，拥有待推导的参数和返回类型。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 应用 operator| 到 lhs 与 rhs
(公开成员函数)

std::bit_or<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) | std::forward <U>(rhs));

返回 std::forward <T>(lhs) | std::forward <U>(rhs) 的结果。

参数

lhs, rhs - 为之计算逐位或的值

返回值

std::forward <T>(lhs) | std::forward <U>(rhs) 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::bit_xor

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct bit_xor; | (C++14 前)
template< class T = void > struct bit_xor; | (C++14 起)

进行逐位异或的函数对象。等效地调用类型 T 上的 operator^ 。

特化

标准化提供 std::bit_xor 在不指定 T 时的特化，它使得参数类型和返回类型留待推导。

bit_xor<void>
(C++14)
 实现 x ^ y 并推导参数和返回类型的函数对象
(类模板特化)
(C++14 起)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | T
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, T> 获得。

 (C++11 前)

成员函数

operator()
 返回二个参数逐位异或的结果
(公开成员函数)

std::bit_xor::operator()

T operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr T operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

返回 lhs 与 rhs 逐位异或的结果。

参数

lhs, rhs - 要计算逐位异或的值

返回值

lhs ^ rhs 的结果。

异常

可能抛出实现定义的异常。

可能的实现

constexpr T operator()(const T &lhs, const T &rhs) const
{
    return lhs ^ rhs;
}


std::bit_xor<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class bit_xor<void>; | (C++14 起)

std::bit_xor<> 是 std::bit_xor 的特化，拥有待推导的参数和返回类型。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 应用 operator^ 到 lhs 和 rhs
(公开成员函数)

std::bit_xor<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) ^ std::forward <U>(rhs));

返回 lhs ^ rhs 的结果。

参数

lhs, rhs - 要计算逐位异或的值

返回值

lhs ^ rhs 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::boyer_moore_horspool_searcher

< cpp‎ | utility‎ | functional
定义于头文件 <functional>
template< class RandomIt1,

class Hash = std::hash <typename std::iterator_traits <RandomIt1>::value_type>,
class BinaryPredicate = std::equal_to <> >

class boyer_moore_horspool_searcher;
 (C++17 起)

适用于 std::search 的搜索器 (Searcher) 的重载，实现了 Boyer-Moore-Horspool 字符串搜索算法。

boyer_moore_horspool_searcher 为可复制构造 (CopyConstructible) 及可复制赋值 (CopyAssignable) 。

RandomIt1 必须满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。

成员函数

std::boyer_moore_horspool_searcher::boyer_moore_horspool_searcher

boyer_moore_horspool_searcher( RandomIt1 pat_first,

RandomIt1 pat_last,
Hash hf = Hash(),

BinaryPredicate pred = BinaryPredicate());

通过存储 pat_first 、 pat_last 、 hf 和 pred 的副本构造一个 boyer_moore_horspool_searcher ，安装任何需要的内部数据结构。

RandomIt1 的值必须是可默认构造 (DefaultConstructible) 、可复制构造 (CopyConstructible) 及可复制赋值 (CopyAssignable) 。

对于任意二个 std::iterator_traits <RandomIt1>::value_type 类型的值 A 和 B ，若 pred(A, B) == true ，则 hf(A) == hf(B) 应为 true 。

参数

pat_first, pat_last | - | 表示要搜索的字符串的一对迭代器
hf | - | 用于哈希字符串元素的可调用对象
pred | - | 确定相等的可调用对象

异常

任何会为下列者抛出的异常

  • RandomIt1 的复制构造函数；
  • RandomIt1 的 value_type 的默认构造函数、复制构造函数或复制赋值运算符；或
  • BinaryPredicate 或 Hash 的复制构造函数或函数调用运算符.

若为内部数据结构请求的附加内存无法分配，则亦可能抛出 std::bad_alloc 。

std::boyer_moore_horspool_searcher::operator()

template< class RandomIt2 >
std::pair <RandomIt2,RandomIt2> operator()( RandomIt2 first, RandomIt2 last ) const;

std::search 的搜索器（Searcher）重载调用的该成员函数，以进行用此搜索器的搜索。 RandomIt2 必须满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。

RandomIt1 与 RandomIt2 必须拥有相同的值类型。

参数

first, last - 指代要被检验的字符串的一对迭代器

返回值

若模式（ [pat_first, pat_last) ）为空，则返回 make_pair(first, first) 。

否则，返回于 [first, last) 中指向首及尾后一位的一对迭代器，其中定位了与 [pat_first, pat_last) 由 pred 所定义比较相等的子序列，否则返回 make_pair(last, last) 。

示例

#include <iostream>
#include <string>
#include <algorithm>
#include <functional>

int main()
{
    std::string in = "Lorem ipsum dolor sit amet, consectetur adipiscing elit,"
                     " sed do eiusmod tempor incididunt ut labore et dolore magna aliqua";
    std::string needle = "pisci";
    auto it = std::search(in.begin(), in.end(),
                   std::boyer_moore_horspool_searcher(
                       needle.begin(), needle.end()));
    if(it != in.end())
        std::cout << "The string " << needle << " found at offset "
                  << it - in.begin() << '\n';
    else
        std::cout << "The string " << needle << " not found\n";
}

输出：

The string pisci found at offset 43

参阅

search
 搜索一个元素范围
(函数模板)


std::boyer_moore_searcher

< cpp‎ | utility‎ | functional
定义于头文件 <functional>
template< class RandomIt1,

class Hash = std::hash <typename std::iterator_traits <RandomIt1>::value_type>,
class BinaryPredicate = std::equal_to <> >

class boyer_moore_searcher;
 (C++17 起)

适用于 std::search 的搜索器 (Searcher) 的重载，实现了 Boyer-Moore 字符串搜索算法。

boyer_moore_searcher 为可复制构造 (CopyConstructible) 及可复制赋值 (CopyAssignable) 。

RandomIt1 必须满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。

成员函数

std::boyer_moore_searcher::boyer_moore_searcher

boyer_moore_searcher( RandomIt1 pat_first,

RandomIt1 pat_last,
Hash hf = Hash(),

BinaryPredicate pred = BinaryPredicate());

通过存储 pat_first 、 pat_last 、 hf 和 pred 的副本构造一个 boyer_moore_searcher ，安装任何需要的内部数据结构。

RandomIt1 的值必须是可默认构造 (DefaultConstructible) 、可复制构造 (CopyConstructible) 及可复制赋值 (CopyAssignable) 。

对于任意二个 std::iterator_traits <RandomIt1>::value_type 类型的值 A 和 B ，若 pred(A, B) == true ，则 hf(A) == hf(B) 应为 true 。

参数

pat_first, pat_last | - | 表示要搜索的字符串的一对迭代器
hf | - | 用于哈希字符串元素的可调用对象
pred | - | 确定相等的可调用对象

异常

任何会为下列者抛出的异常

  • RandomIt1 的复制构造函数；
  • RandomIt1 的 value_type 的默认构造函数、复制构造函数与复制赋值运算符；或
  • BinaryPredicate 与 Hash 的复制构造函数或函数调用运算符.

若为内部数据结构请求的附加内存无法分配，则亦可能抛出 std::bad_alloc 。

std::boyer_moore_searcher::operator()

template< class RandomIt2 >
std::pair <RandomIt2,RandomIt2> operator()( RandomIt2 first, RandomIt2 last ) const;

std::search 的搜索器（Searcher）重载调用的该成员函数，以进行用此搜索器的搜索。 RandomIt2 必须满足老式随机访问迭代器 (LegacyRandomAccessIterator) 的要求。

RandomIt1 与 RandomIt2 必须拥有相同的值类型。

参数

first, last - 指代要被检验的字符串的一对迭代器

返回值

若模式（ [pat_first, pat_last) ）为空，则返回 make_pair(first, first) 。

否则，返回于 [first, last) 中指向首及尾后一位的一对迭代器，其中定位了与 [pat_first, pat_last) 由 pred 所定义比较相等的子序列，否则返回 make_pair(last, last) 。

示例

#include <iostream>
#include <string>
#include <algorithm>
#include <functional>

int main()
{
    std::string in = "Lorem ipsum dolor sit amet, consectetur adipiscing elit,"
                     " sed do eiusmod tempor incididunt ut labore et dolore magna aliqua";
    std::string needle = "pisci";
    auto it = std::search(in.begin(), in.end(),
                   std::boyer_moore_searcher(
                       needle.begin(), needle.end()));
    if(it != in.end())
        std::cout << "The string " << needle << " found at offset "
                  << it - in.begin() << '\n';
    else
        std::cout << "The string " << needle << " not found\n";
}

输出：

The string pisci found at offset 43

参阅

search
 搜索一个元素范围
(函数模板)


std::default_searcher

< cpp‎ | utility‎ | functional
定义于头文件 <functional>
template< class ForwardIt, class BinaryPredicate = std::equal_to <> >
class default_searcher;
 (C++17 起)

适合用于 std::search 的搜索器 (Searcher) 重载的类，它将搜索操作委派到 C++17 前标准库的 std::search 。

default_searcher 是为可复制构造 (CopyConstructible) 及可复制赋值 (CopyAssignable) 。

成员函数

std::default_searcher::default_searcher

default_searcher( ForwardIt pat_first, ForwardIt pat_last, BinaryPredicate pred = BinaryPredicate()); | (C++17 起) (C++20 前)
constexpr default_searcher( ForwardIt pat_first, ForwardIt pat_last, BinaryPredicate pred = BinaryPredicate()); | (C++20 起)

以存储 pat_first 、 pat_last 及 pred 的副本构造一个 default_searcher

参数

pat_first, pat_last | - | 指代要搜索的串的一对迭代器
pred | - | 用于检测相等的可调用对象

异常

任何 BinaryPredicate 或 ForwardIt 的复制构造函数可能抛出的异常。

std::default_searcher::operator()

template< class ForwardIt2 >

std::pair <ForwardIt2, ForwardIt2>

operator()( ForwardIt2 first, ForwardIt2 last ) const;
 (C++17 起)
(C++20 前)
template< class ForwardIt2 >

constexpr std::pair <ForwardIt2, ForwardIt2>

operator()( ForwardIt2 first, ForwardIt2 last ) const;
 (C++20 起)

std::search 的搜索器 (搜索器 (Searcher) ) 重载调用此函数以进行用此搜索器的搜索。

返回一对迭代器 i, j ，其中 i 为 std::search (first, last, pat_first, pat_last, pred) 且 j 为 std::next (i, std::distance (pat_first, pat_last)) ，除非 std::search 返回 last （无匹配），此情况下 j 也等于 last 。

参数

first, last - 指代要检验的字符串的一对迭代器

返回值

分别指向 [first, last) 中首位置和尾后一位的一对迭代器，其中定位的子序列按 pred 所定义与 [pat_first, pat_last) 比较相等，其他情况返回一对 last 的副本。

示例

#include <iostream>
#include <string>
#include <algorithm>
#include <functional>

int main()
{
    std::string in = "Lorem ipsum dolor sit amet, consectetur adipiscing elit,"
                     " sed do eiusmod tempor incididunt ut labore et dolore magna aliqua";
    std::string needle = "pisci";
    auto it = std::search(in.begin(), in.end(),
                   std::default_searcher(
                       needle.begin(), needle.end()));
    if(it != in.end())
        std::cout << "The string " << needle << " found at offset "
                  << it - in.begin() << '\n';
    else
        std::cout << "The string " << needle << " not found\n";
}

输出：

The string pisci found at offset 43

参阅

search
 搜索一个元素范围
(函数模板)


std::divides

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct divides; | (C++14 前)
template< class T = void > struct divides; | (C++14 起)

进行除法的函数对象。等效地调用二个 T 类型实例上的 operator/ 。

特化

标准库提供 std::divides 在未指定 T 时的特化，使参数类型和返回类型留待推导。

divides<void>
(C++14)
 进行 x / y 并推导参数和返回类型的函数对象
(类模板特化)
(C++14 起)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | T
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, T> 获得。

 (C++11 前)

成员函数

operator()
 返回首参数除以第二参数的结果
(公开成员函数)

std::divides::operator()

T operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr T operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

返回 lhs 除以 rhs 的结果。

参数

lhs, rhs - 要以一个除另一个的值

返回值

lhs / rhs 的结果。

异常

可能抛出实现定义的异常。

可能的实现

constexpr T operator()(const T &lhs, const T &rhs) const
{
    return lhs / rhs;
}


std::divides<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class divides<void>; | (C++14 起)

std::divides <> 是 std::divides 的特化，推导其参数和返回类型。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 返回二个参数的商
(公开成员函数)

std::divides<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) / std::forward <U>(rhs));

返回 lhs 除以 rhs 的结果（或重载 operator/ 的所为）。

参数

lhs, rhs - 要除的值

返回值

lhs / rhs 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

参数

本节未完成
原因：暂无示例


std::equal_to

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct equal_to; | (C++14 前)
template< class T = void > struct equal_to; | (C++14 起)

进行比较的函数对象。调用类型 T 上的 operator== ，除非特化。

特化

标准库提供 std::equal_to 在未指定 T 时的特化，这使得参数类型和返回类型留待推导。

equal_to<void>
(C++14)
 实现 x == y 并推导参数和返回类型的函数对象
(类模板特化)
(C++14 起)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | bool
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, bool> 获得。

 (C++11 前)

成员函数

operator()
 检查参数是否相等
(公开成员函数)

std::equal_to::operator()

bool operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr bool operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

检查 lhs 是否等于 rhs 。

参数

lhs, rhs - 要比较的值

返回值

若 lhs == rhs 则为 true ，否则为 false 。

异常

可能抛出实现定义的异常。

可能的实现

constexpr bool operator()(const T &lhs, const T &rhs) const
{
    return lhs == rhs;
}


std::equal_to<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class equal_to<void>; | (C++14 起)

std::equal_to <> 是拥有待推导参数和返回类型的 std::equal_to 特化。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 测试二个参数是否比较相等
(公开成员函数)

std::equal_to<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) == std::forward <U>(rhs));

返回 lhs 与 rhs 间等于比较的结果。

参数

lhs, rhs - 要比较的值

返回值

std::forward <T>(lhs) == std::forward <U>(rhs) 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::function

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class > class function; /* 未定义 */ | (C++11 起)
template< class R, class... Args > class function<R(Args...)>; | (C++11 起)

类模板 std::function 是通用多态函数包装器。 std::function 的实例能存储、复制及调用任何可复制构造 (CopyConstructible) 的可调用 (Callable) 目标——函数、 lambda 表达式、 bind 表达式或其他函数对象，还有指向成员函数指针和指向数据成员指针。

存储的可调用对象被称为 std::function 的目标。若 std::function 不含目标，则称它为空。调用空 std::function 的目标导致抛出 std::bad_function_call 异常。

std::function 满足可复制构造 (CopyConstructible) 和可复制赋值 (CopyAssignable) 。

成员类型

类型 | 定义
result_type | R
argument_type(C++17 中弃用)(C++20 中移除) | 若 sizeof...(Args)==1 且 T 是 Args... 中首个且唯一的类型，则为 T
first_argument_type(C++17 中弃用)(C++20 中移除) | 若 sizeof...(Args)==2 且 T1 是 Args... 中二个类型的第一个，则为 T1
second_argument_type(C++17 中弃用)(C++20 中移除) | 若 sizeof...(Args)==2 且 T2 是 Args... 中二个类型的第二个，则为 T2

成员函数

(构造函数)
 构造新的 std::function 实例
(公开成员函数)
(析构函数)
 析构 std::function 实例
(公开成员函数)
operator=
 为内容赋值
(公开成员函数)
swap
 交换内容
(公开成员函数)
assign
(C++17 中移除)
 为内容赋值一个新的目标
(公开成员函数)
operator bool
 检查是否包含了有效的目标
(公开成员函数)
operator()
 调用其目标
(公开成员函数)
目标访问
target_type
 获得 std::function 所存储的目标的typeid
(公开成员函数)
target
 获得指向 std::function 所存储的目标的指针
(公开成员函数)

非成员函数

std::swap(std::function) (C++11) | 特化 std::swap 算法 (函数模板)
operator==operator!= (C++20 中移除) | 比较 std::function 和 nullptr (函数模板)

辅助类

std::uses_allocator<std::function>
(C++11) (C++17 前)
 特化 std::uses_allocator 类型特性
(类模板特化)

推导指引 (C++17 起)

注解

当结果类型为引用的 std::function 从无尾随返回类型的 lambda 表达式初始化时需要留心。由于 auto 推导的起效方式，这种 lambda 表达式将始终返回纯右值。故而结果引用将始终绑定到生命期在 std::function::operator() 返回时结束的临时量。

std::function<const int&()> F([]{ return 42; });
int x = F(); // 未定义行为： F() 的结果是悬垂引用

示例

#include <functional>
#include <iostream>

struct Foo {
    Foo(int num) : num_(num) {}
    void print_add(int i) const { std::cout << num_+i << '\n'; }
    int num_;
};

void print_num(int i)
{
    std::cout << i << '\n';
}

struct PrintNum {
    void operator()(int i) const
    {
        std::cout << i << '\n';
    }
};

int main()
{
    // 存储自由函数
    std::function<void(int)> f_display = print_num;
    f_display(-9);

    // 存储 lambda
    std::function<void()> f_display_42 = []() { print_num(42); };
    f_display_42();

    // 存储到 std::bind 调用的结果
    std::function<void()> f_display_31337 = std::bind(print_num, 31337);
    f_display_31337();

    // 存储到成员函数的调用
    std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;
    const Foo foo(314159);
    f_add_display(foo, 1);
    f_add_display(314159, 1);

    // 存储到数据成员访问器的调用
    std::function<int(Foo const&)> f_num = &Foo::num_;
    std::cout << "num_: " << f_num(foo) << '\n';

    // 存储到成员函数及对象的调用
    using std::placeholders::_1;
    std::function<void(int)> f_add_display2 = std::bind( &Foo::print_add, foo, _1 );
    f_add_display2(2);

    // 存储到成员函数和对象指针的调用
    std::function<void(int)> f_add_display3 = std::bind( &Foo::print_add, &foo, _1 );
    f_add_display3(3);

    // 存储到函数对象的调用
    std::function<void(int)> f_display_obj = PrintNum();
    f_display_obj(18);

    auto factorial = [](int n) {
        // 存储 lambda 对象以模拟“递归 lambda ”，注意额外开销
        std::function<int(int)> fac = [&](int n){ return (n < 2) ? 1 : n*fac(n-1); };
        // note that "auto fac = [&](int n){...};" does not work in recursive calls
        return fac(n);
    };
    for (int i{5}; i != 8; ++i) { std::cout << i << "! = " << factorial(i) << ";  "; }
}

可能的输出：

-9
42
31337
314160
314160
num_: 314159
314161
314162
18
5! = 120;  6! = 720;  7! = 5040;

参阅

move_only_function (C++23) | 包装具有指定函数调用签名的任意类型的可调用对象 (类模板)
bad_function_call (C++11) | 调用空的 std::function 时抛出的异常 (类)
mem_fn (C++11) | 从成员指针创建出函数对象 (函数模板)


std::function<R(Args...)>::assign

< cpp‎ | utility‎ | functional‎ | function
template< class F, class Alloc > void assign( F&& f, const Alloc& alloc ); | (C++11 起) (C++17 中移除)

以目标初始化 f 。用 alloc 为 function 会使用的任何内部数据结构分配内存。

等价于 function( std::allocator_arg, alloc, std::forward <F>(f)).swap(*this); 。

参数

f | - | 用以初始化目标的可调用函数
alloc | - | 用于为内部数据结构分配内存的分配器

返回值

（无）

异常

可能抛出实现定义的异常。

参阅

operator=
 为内容赋值
(公开成员函数)


std::function 的推导指引

< cpp‎ | utility‎ | functional‎ | function
定义于头文件 <functional> |  |
template<class R, class... ArgTypes> function(R(*)(ArgTypes...)) -> function<R(ArgTypes...)>; | (1) | (C++17 起)
template<class F> function(F) -> function</*see below*/>; | (2) | (C++17 起)
1) 为 std::function 提供此推导指引以允许从函数推导。
2) 此重载仅若 &F::operator() 在作为不求值运算数时为良构且 decltype(&F::operator()) 拥有形式 R(G::*)(A...) （可选地有 cv 限定，可选地有 noexcept ， 可选地有左值引用限定）而 G 为类类型才参与重载决议。推导类型为 std::function <R(A...)> 。

注解

这些推导指引所推导的类型可能在之后的标准版本中更改（特别是若在之后的版本中添加 noexcept 支持到 std::function 则这可能发生）。

示例

#include <functional>
int func(double) { return 0; }
int main() {
  std::function f{func}; // 指引 #1 推导 function<int(double)>
  int i = 5;
  std::function g = [&](double) { return i; }; // 指引 #2 推导 function<int(double)>
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3238 | C++17 | (2) 的行为不明确 | 使之明确


std::function<R(Args...)>::function

< cpp‎ | utility‎ | functional‎ | function
function() noexcept;
 (1) (C++11 起)
function( std::nullptr_t ) noexcept;
 (2) (C++11 起)
function( const function& other );
 (3) (C++11 起)
(4)
function( function&& other );
 (C++11 起)
(C++20 前)
function( function&& other ) noexcept;
 (C++20 起)
template< class F >
function( F&& f );
 (5) (C++11 起)
template< class Alloc >
function( std::allocator_arg_t, const Alloc& alloc ) noexcept;
 (6) (C++11 起)
(C++17 中移除)
template< class Alloc >

function( std::allocator_arg_t, const Alloc& alloc,

std::nullptr_t ) noexcept;
 (7) (C++11 起)
(C++17 中移除)
template< class Alloc >

function( std::allocator_arg_t, const Alloc& alloc,

const function& other );
 (8) (C++11 起)
(C++17 中移除)
template< class Alloc >

function( std::allocator_arg_t, const Alloc& alloc,

function&& other );
 (9) (C++11 起)
(C++17 中移除)
template< class F, class Alloc >
function( std::allocator_arg_t, const Alloc& alloc, F f );
 (10) (C++11 起)
(C++17 中移除)

从各种资源构造 std::function 。

1-2) 构造空 function 。
3-4) 复制 (3) 或移动 (4) other 的目标到 *this 的目标。若 other 为空，则调用后 *this 将亦为空。对于 (4) ， other 在调用后处于合法但未指定的状态。
5) 以 std::forward <F>(f) 初始化目标。目标的类型为 std::decay <F>::type 。若 f 是空指针、指向成员的空指针或某 std::function 特化的空值，则 *this 在此调用后将为空。此构造函数不参与重载决议，除非目标类型与 function 不相同，且其左值对参数类型 Args... 和返回类型 R 可调用 (Callable) 。若目标类型不可复制构造或目标的初始化非良构，则程序非良构。
6-10) 同 (1-5) ，除了将 alloc 用于分配任何 function 会用到的内部数据结构的内存。

目标是函数指针或 std::reference_wrapper 时，保证使用小对象优化，即始终直接存储这些目标于 std::function 对象中，不发生动态内存分配。可以构造其他大对象于动态分配的存储中，并由 std::function 对象通过指针访问。

参数

other | - | 用于初始化 *this 的函数对象
f | - | 用于初始化 *this 的可调用对象
alloc | - | 用于内部内存分配的分配器 (Allocator)
类型要求
- std::decay<F>::type 必须满足可调用 (Callable) 和 可复制构造 (CopyConstructible) 的要求。
- Alloc 必须满足分配器 (Allocator) 的要求。

异常

3,8,9) 若 other 的目标是函数指针或 std::reference_wrapper 则不抛出异常，否则可能抛出 std::bad_alloc 或用于复制或移动存储的可调用对象的构造函数所抛的异常。
4) 若 other 的目标是函数指针或 std::reference_wrapper 则不抛出异常，否则可能抛出 std::bad_alloc 或用于复制或移动存储的可调用对象的构造函数所抛的异常。
 (C++20 前)
5,10) 若 f 是函数指针或 std::reference_wrapper 则不抛异常，否则可能抛出 std::bad_alloc 或存储的可调用对象的复制构造函数所抛的异常。

注解

std::function 的分配器支持说明贫乏，且实现不一致。一些实现完全不提供重载 (6-10) ，一些提供重载但忽略提供的分配器参数，而一些实现提供重载并将提供的分配器用于构造，但不在重赋值 std::function 时使用。结果， C++17 中移除了分配器支持。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2132 | C++11 | 接收一个可调用 (Callable) 对象的构造函数可能有歧义 | 已约束
LWG 2774 | C++11 | 接收一个可调用 (Callable) 对象的函数进行一次额外移动 | 已消除

参阅

(构造函数)
(C++23)
 构造新的 std::move_only_function 对象
(std::move_only_function<R(Args...) cv ref noexcept(noex)> 的公开成员函数)


std::function<R(Args...)>::operator()

< cpp‎ | utility‎ | functional‎ | function
R operator()( Args... args ) const; | (C++11 起)

以参数 args 调用存储的可调用函数目标。

等效于进行 INVOKE<R>(f, std::forward <Args>(args)...) ，其中 f 是 *this 的目标对象，且 INVOKE 是描述于可调用 (Callable) 的操作。

参数

args - 传递给存储的可调用函数目标的参数

返回值

若 R 为 void 则为无。否则为存储的可调用对象的调用返回值。

异常

  • 若不存储可调用函数目标，即 !*this == true ，则抛出 std::bad_function_call 。

示例

下列示例展示能如何将 std::function 按值传递给另一函数。而且，它演示 std::function 能如何存储 lambda 。

#include <iostream>
#include <functional>

void call(std::function<int()> f)  // 能按值传递
{
    std::cout << f() << '\n';
}

int normal_function()
{
    return 42;
}

int main()
{
    int n = 1;
    std::function<int()> f = [&n](){ return n; };
    call(f);

    n = 2;
    call(f);

    f = normal_function;
    call(f);
}

输出：

1
2
42

参阅

operator() (C++23) | 调用目标 (std::move_only_function<R(Args...) cv ref noexcept(noex)> 的公开成员函数)
operator() | 调用其所存储的函数 (std::reference_wrapper<T> 的公开成员函数)
bad_function_call (C++11) | 调用空的 std::function 时抛出的异常 (类)
invokeinvoke_r (C++17)(C++23) | 以给定实参和可能指定的返回类型 (C++23 起)调用任意可调用 (Callable) 对象 (函数模板)


std::function<R(Args...)>::operator=

< cpp‎ | utility‎ | functional‎ | function
function& operator=( const function& other ); | (1) | (C++11 起)
function& operator=( function&& other ); | (2) | (C++11 起)
function& operator=( std::nullptr_t ) noexcept; | (3) | (C++11 起)
template< class F > function& operator=( F&& f ); | (4) | (C++11 起)
template< class F > function& operator=( std::reference_wrapper <F> f ) noexcept; | (5) | (C++11 起)

赋值新目标给 std::function 。

1) 赋值 other 的目标副本，如同以执行 function(other).swap(*this);
2) 移动 other 的目标到 *this 。 other 在有未指定值的合法状态。
3) 舍弃当前目标。 *this 在调用后为空。
4) 设置 *this 的目标为可调用的 f ，如同以执行 function( std::forward <F>(f)).swap(*this); 。此运算符不参与重载决议，除非 f 对于参数类型 Args... 和返回类型 R 可调用 (Callable) 。
5) 设置 *this 的目标为 f 的副本，如同以执行 function(f).swap(*this);

参数

other | - | 要复制其目标的另一 std::function 对象
f | - | 用以初始化目标的可调用对象
类型要求
- F 必须满足可调用 (Callable) 的要求。

返回值

*this

注解

虽然 C++17 中从 std::function 移除了以前的分配器支持，这些赋值运算符使用默认分配器，而不是 *this 或 other 的分配器（见 LWG 问题 2386 ）。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2132 | C++11 | 接收一个可调用 (Callable) 对象的重载可能有歧义 | 已约束
LWG 2401 | C++11 | 未要求源自 std::nullptr_t 的构造函数为 noexcept | 已要求

参阅

operator= (C++23) | 替换或销毁目标 (std::move_only_function<R(Args...) cv ref noexcept(noex)> 的公开成员函数)
assign (C++17 中移除) | 为内容赋值一个新的目标 (公开成员函数)


std::function<R(Args...)>::operator bool

< cpp‎ | utility‎ | functional‎ | function
explicit operator bool() const noexcept; | (C++11 起)

检查 *this 是否存储可调用函数对象，即非空。

参数

（无）

返回值

若 *this 存储可调用函数对象则为 true ，否则为 false 。

示例

#include <functional>
#include <iostream>

void sampleFunction()
{
    std::cout << "This is the sample function!\n";
}

void checkFunc( std::function<void()> &func )
{
    // 用 operator bool 确定可调用目标是否可用。
    if( func )
    {
        std::cout << "Function is not empty! Calling function.\n";
        func();
    }
    else
    {
        std::cout << "Function is empty. Nothing to do.\n";
    }
}

int main()
{
    std::function<void()> f1;
    std::function<void()> f2( sampleFunction );

    std::cout << "f1: ";
    checkFunc( f1 );

    std::cout << "f2: ";
    checkFunc( f2 );
}

输出：

f1: Function is empty. Nothing to do.
f2: Function is not empty! Calling function.
This is the sample function!

参阅

operator bool
(C++23)
 检查 std::move_only_function 是否拥有目标
(std::move_only_function<R(Args...) cv ref noexcept(noex)> 的公开成员函数)


operator==,!=(std::function)

< cpp‎ | utility‎ | functional‎ | function
定义于头文件 <functional>
template< class R, class... ArgTypes >

bool operator==( const std::function <R(ArgTypes...)>& f,

std::nullptr_t ) noexcept;
 (1) (C++11 起)
template< class R, class... ArgTypes >

bool operator==( std::nullptr_t,

const std::function <R(ArgTypes...)>& f ) noexcept;
 (2) (C++11 起)
(C++20 前)
template< class R, class... ArgTypes >

bool operator!=( const std::function <R(ArgTypes...)>& f,

std::nullptr_t ) noexcept;
 (3) (C++11 起)
(C++20 前)
template< class R, class... ArgTypes >

bool operator!=( std::nullptr_t,

const std::function <R(ArgTypes...)>& f ) noexcept;
 (4) (C++11 起)
(C++20 前)

与空指针比较 std::function 。空 function （即无可调用目标的 function ）比较相等，非空 function 比较不相等。

!= 运算符从 operator== 合成。

 (C++20 起)

参数

f - 要比较的 std::function

返回值

1-2) !f
3-4) (bool) f

示例

#include <functional>
#include <iostream>

using SomeVoidFunc = std::function<void(int)>;

class C {
public:
    C(SomeVoidFunc void_func = nullptr) :
        void_func_(void_func)
    {
        if (void_func_ == nullptr) { // 与 nullptr 的特化比较
            void_func_ = std::bind(&C::default_func, this, std::placeholders::_1);
        }
        void_func_(7);
    }

    void default_func(int i) { std::cout << i << '\n'; };

private:
    SomeVoidFunc void_func_;
};

void user_func(int i)
{
    std::cout << (i + 1) << '\n';
}

int main()
{
    C c1;
    C c2(user_func);
}

输出：

7
8

参阅

operator==
(C++23)
 比较 std::move_only_function 与 nullptr
(函数)


std::function<R(Args...)>::swap

< cpp‎ | utility‎ | functional‎ | function
void swap( function& other ) noexcept; | (C++11 起)

交换 *this 与 other 存储的可调用对象。

参数

other - 要与之互换存储可调用对象的函数包装

返回值

（无）

参阅

swap
(C++23)
 交换二个 std::move_only_function 对象的目标
(std::move_only_function<R(Args...) cv ref noexcept(noex)> 的公开成员函数)


std::swap(std::function)

< cpp‎ | utility‎ | functional‎ | function
定义于头文件 <functional> |
template< class R, class... Args > void swap( std::function <R(Args...)> &lhs, std::function <R(Args...)> &rhs ) noexcept; | (C++11 起)

为 std::function 特化 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs - 要交换状态的多态函数封装器

返回值

（无）

示例

#include <functional>
#include <iostream>

void foo(const char* str, int x) {
    std::cout << "foo(\"" << str << "\", " << x << ")\n";
}

void bar(const char* str, int x) {
    std::cout << "bar(\"" << str << "\", " << x << ")\n";
}

int main()
{
    std::function<void(const char*, int)> f1{ foo };
    std::function<void(const char*, int)> f2{ bar };

    f1("f1", 1);
    f2("f2", 2);

    std::cout << "std::swap(f1, f2);\n";
    std::swap(f1, f2);

    f1("f1", 1);
    f2("f2", 2);
}

输出：

foo("f1", 1)
bar("f2", 2)
std::swap(f1, f2);
bar("f1", 1)
foo("f2", 2)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2062 | C++11 | 未要求 swap 对 function 的重载为 noexcept | 已要求

参阅

swap | 交换内容 (公开成员函数)
swap(std::move_only_function) (C++23) | 重载 std::swap 算法 (函数)


std::function<R(Args...)>::target

< cpp‎ | utility‎ | functional‎ | function
template< class T > T* target() noexcept; | (1) | (C++11 起)
template< class T > const T* target() const noexcept; | (2) | (C++11 起)

返回指向存储的可调用函数目标的指针。

参数

（无）

返回值

若 target_type() == typeid(T) 则为指向存储的函数的指针，否则为空指针。

示例

#include <functional>
#include <iostream>

int f(int, int) { return 1; }
int g(int, int) { return 2; }
void test(std::function<int(int, int)> const& arg)
{
    std::cout << "test function: ";
    if (arg.target<std::plus<int>>())
        std::cout << "it is plus\n";
    if (arg.target<std::minus<int>>())
        std::cout << "it is minus\n";

    int (*const* ptr)(int, int) = arg.target<int(*)(int, int)>();
    if (ptr && *ptr == f)
        std::cout << "it is the function f\n";
    if (ptr && *ptr == g)
        std::cout << "it is the function g\n";
}

int main()
{
    test(std::function<int(int, int)>(std::plus<int>()));
    test(std::function<int(int, int)>(std::minus<int>()));
    test(std::function<int(int, int)>(f));
    test(std::function<int(int, int)>(g));
}

输出：

test function: it is plus
test function: it is minus
test function: it is the function f
test function: it is the function g

参阅

target_type
 获得 std::function 所存储的目标的typeid
(公开成员函数)


std::function<R(Args...)>::target_type

< cpp‎ | utility‎ | functional‎ | function
const std::type_info & target_type() const noexcept; | (C++11 起)

返回存储的函数的类型。

参数

（无）

返回值

若存储的函数拥有 T 类型，则为 typeid(T) ，否则为 typeid(void) 。

示例

#include <functional>
#include <iostream>

int f(int a) { return -a; }
void g(double) {}
int main()
{
    // fn1 与 fn2 拥有相同类型，但其目标不如此
    std::function<int(int)> fn1(f),
                            fn2([](int a) {return -a;});
    std::cout << fn1.target_type().name() << '\n'
              << fn2.target_type().name() << '\n';

    // C++17 起推导指引（ CTAD ）可用
    std::cout << std::function{g}.target_type().name() << '\n';
}

可能的输出：

PFiiE
Z4mainEUliE_
PFvdE

参阅

target
 获得指向 std::function 所存储的目标的指针
(公开成员函数)


std::uses_allocator<std::function>

< cpp‎ | utility‎ | functional‎ | function
定义于头文件 <functional> |
template< class R, class... ArgTypes, class Alloc > struct uses_allocator< std::function <R(ArgTypes...)>, Alloc> : std::true_type { }; | (C++11 起) (C++17 前)

std::uses_allocator 的此特化告知其他库组件，所有 std::function 类型对象支持 uses-allocator 构造，即使它们无嵌套的 allocator_type 。

注意

std::function 的分配器支持说明贫乏，且实现不一致。一些实现完全不提供 uses-allocator 构造 ，一些提供重载但忽略提供的分配器参数，而一些实现提供重载并将提供的分配器用于构造，但不在重赋值 std::function 时使用。结果， C++17 中移除了分配器支持。

继承自 std::integral_constant

成员常量

value
[静态]
 true
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

参阅

uses_allocator
(C++11)
 检查指定的类型是否支持使用分配器的构造
(类模板)


std::function<R(Args...)>::~function

< cpp‎ | utility‎ | functional‎ | function
~function(); | (C++11 起)

销毁 std::function 对象。若 std::function 非空，则亦销毁其目标。

参阅

(析构函数)
(C++23)
 销毁 std::move_only_function 对象
(std::move_only_function<R(Args...) cv ref noexcept(noex)> 的公开成员函数)


std::greater

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct greater; | (C++14 前)
template< class T = void > struct greater; | (C++14 起)

实现比较的函数对象。调用类型 T 上的 operator> ，除非特化。

实现定义的指针上的严格全序

std::greater 对任何指针类型的特化产生实现定义的严格全序，即使内建的 > 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 (C++20 起)<、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void (C++14 起)时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way
 (C++20 起)

特化

greater<void>
(C++14)
 实现 x > y 并推导参数和返回类型的函数对象
(类模板特化)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | bool
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, bool> 获得。

 (C++11 前)

成员函数

operator()
 检查第一参数是否大于第二个
(公开成员函数)

std::greater::operator()

bool operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr bool operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

检查 lhs 是否大于 rhs 。

参数

lhs, rhs - 要比较的值

返回值

对于不是指针类型的 T ，若 lhs < rhs 则为 true ，否则为 false 。

对于是指针类型的 T ，若 lhs 在实现定义的严格全序中后继 rhs 则为 true ，否则为 false 。

异常

可能抛出实现定义的异常。

可能的实现

constexpr bool operator()(const T &lhs, const T &rhs) const
{
    return lhs > rhs; // 假定实现使用平坦地址空间
}

参阅

less
 实现 x < y 的函数对象
(类模板)


std::greater_equal

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct greater_equal; | (C++14 前)
template< class T = void > struct greater_equal; | (C++14 起)

进行比较的函数对象。调用类型 T 上的 operator>= ，除非特化。

实现定义的指针上的严格全序

std::greater_equal 对任何指针类型的特化产生实现定义的严格全序，即使内建的 >= 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 (C++20 起)<、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void (C++14 起)时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way
 (C++20 起)

特化

greater_equal<void>
(C++14)
 实现 x >= y 并推导参数和返回类型的函数对象
(类模板特化)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | bool
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, bool> 获得。

 (C++11 前)

成员函数

operator()
 检查第一参数是否大于或等于第二个
(公开成员函数)

std::greater_equal::operator()

bool operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr bool operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

检查 lhs 是否大于或等于 rhs 。

参数

lhs, rhs - 要比较的值

返回值

对于不是指针类型的 T ，若 lhs >= rhs 则为 true ，否则为 false 。

对于是指针类型的 T ，若 lhs 在实现定义的严格全序中不前驱 rhs 则为 true ，否则为 false 。

异常

可能抛出实现定义的异常。

可能的实现

constexpr bool operator()(const T &lhs, const T &rhs) const
{
    return lhs >= rhs; // 假定实现使用平坦地址空间
}


std::greater_equal<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class greater_equal<void>; | (C++14 起)

std::greater_equal <> 是 std::greater_equal 的特化，拥有待推导的参数和返回类型。

实现定义的指针上的严格全序

若参数间的 >= 运算符调用指针的内建比较运算符，则函数调用运算符产生实现定义的指针上的严格全序，即使内建的 >= 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 (C++20 起)<、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void 时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way
 (C++20 起)

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 测试 lhs 是否大于或等于 rhs
(公开成员函数)

std::greater_equal<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) >= std::forward <U>(rhs));

返回 std::forward <T>(lhs) >= std::forward <U>(rhs) 的结果。

参数

lhs, rhs - 要比较的值

返回值

std::forward <T>(lhs) >= std::forward <U>(rhs) 的结果。

若两个实参的比较解析到指针类型的内建比较运算符，则在转换两个实参到指针后用实现定义的严格全序进行比较。

异常

可能抛出实现定义的异常。

注解

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::greater<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class greater<void>; | (C++14 起)

std::greater <> 是 std::greater 的特化，拥有待推导的参数和返回类型。

实现定义的指针上的严格全序

若参数间的 > 运算符调用指针的内建比较运算符，则函数调用运算符产生实现定义的指针上的严格全序，即使内建的 > 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 (C++20 起)<、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void 时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way
 (C++20 起)

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 测试 lhs 是否比较大于 rhs
(公开成员函数)

std::greater<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) > std::forward <U>(rhs));

返回 std::forward <T>(lhs) > std::forward <U>(rhs) 的结果。

参数

lhs, rhs - 要比较的值

返回值

std::forward <T>(lhs) > std::forward <U>(rhs) 的结果。

若两个实参的比较解析到指针类型的内建比较运算符，则在转换两个实参到指针后用实现定义的严格全序进行比较。

异常

可能抛出实现定义的异常。

注解

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::identity

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
struct identity; | (C++20 起)

std::identity 是函数对象类型，其 operator() 返回其不更改的参数。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 返回不更改的参数
(公开成员函数)

std::identity::operator()

template< class T>
constexpr T&& operator()( T&& t ) const noexcept;

返回 std::forward <T>(t) 。

参数

t - 要返回的参数

返回值

std::forward <T>(t) 。

注解

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

std::identity 在受约束算法中担当默认投影。通常不需要直接使用它。

示例

#include <algorithm>
#include <functional>
#include <iostream>
#include <ranges>
#include <string>
#include <vector>

struct Pair {
    int n; std::string s;
    friend std::ostream& operator<< (std::ostream& os, const Pair& p) {
        return os << "{ " << p.n << ", " << p.s << " }";
    }
};

// 范围打印器能打印投影（修改）后的范围元素。
template <std::ranges::input_range R,
          typename Projection = std::identity> //<- 注意默认投影
void print(std::string_view const rem, R&& r, Projection proj = {}) {
    std::cout << rem << "{ ";
    std::ranges::for_each(r, [](const auto& o){ std::cout << o << ' '; }, proj);
    std::cout << "}\n";
}

int main()
{
    const std::vector<Pair> v{ {1, "one"}, {2, "two"}, {3, "three"} };

    print("Print using std::identity as a projection: ", v);
    print("Project the Pair::n: ", v, &Pair::n);
    print("Project the Pair::s: ", v, &Pair::s);
    print("Print using custom closure as a projection: ", v,
        [](Pair const& p) { return std::to_string(p.n) + ':' + p.s; });
}

输出：

Print using std::identity as a projection: { { 1, one } { 2, two } { 3, three } }
Project the Pair::n: { 1 2 3 }
Project the Pair::s: { one two three }
Print using custom closure as a projection: { 1:one 2:two 3:three }

参阅

type_identity
(C++20)
 返回不更改的类型实参
(类模板)


std::invoke, std::invoke_r

< cpp‎ | utility‎ | functional
定义于头文件 <functional>
(1)
template< class F, class... Args >

std::invoke_result_t<F, Args...>

invoke( F&& f, Args&&... args ) noexcept(/* see below */);
 (C++17 起)
(C++20 前)
template< class F, class... Args >

constexpr std::invoke_result_t<F, Args...>

invoke( F&& f, Args&&... args ) noexcept(/* see below */);
 (C++20 起)
template< class R, class F, class... Args >
constexpr R invoke_r(F&& f, Args&&... args) noexcept(/* see below */);
 (2) (C++23 起)
1) 以参数 f 调用可调用 (Callable) 对象。如同以 INVOKE( std::forward <F>(f), std::forward <Args>(args)...) 。此重载仅若 std::is_invocable_v<F, Args...> 为 true 才参与重载决议。
2) 同 (1) ，除了若 R 不是可为 cv 限定的 void 则将结果隐式转换到 R ，否则舍弃结果。此重载仅若 std::is_invocable_r_v<R, F, Args...> 为 true 才参与重载决议。

操作 INVOKE(f, t1, t2, ..., tN) 定义如下：

  • 若 f 是类 T 的指向成员函数的指针：
  • 若 std::is_base_of <T, std::decay_t <decltype(t1)>>::value 为 true ，则 INVOKE(f, t1, t2, ..., tN) 等价于 (t1.*f)(t2, ..., tN)
  • 若 std::decay_t <decltype(t1)> 是 std::reference_wrapper 的特化，则 INVOKE(f, t1, t2, ..., tN) 等价于 (t1.get().*f)(t2, ..., tN)
  • 若 t1 不满足前述项目，则 INVOKE(f, t1, t2, ..., tN) 等价于 ((*t1).*f)(t2, ..., tN).
  • 否则，若 N == 1 且 f 是类 T 的指向数据成员的指针：
  • 若 std::is_base_of <T, std::decay_t <decltype(t1)>>::value 为 true ，则 INVOKE(f, t1) 等价于 t1.*f
  • 若 std::decay_t <decltype(t1)> 是 std::reference_wrapper 的特化，则 INVOKE(f, t1) 等价于 t1.get().*f
  • 若 t1 不满足前述项目，则 INVOKE(f, t1) 等价于 (*t1).*f
  • 否则， INVOKE(f, t1, t2, ..., tN) 等价于 f(t1, t2, ..., tN) （即 f 是一个函数对象 (FunctionObject) ）

参数

f | - | 要调用的可调用 (Callable) 对象
args | - | 传递给 f 的参数

返回值

1) f 返回的值。
2) f 返回的值隐式转换成 R ，若 R 不是 void 。否则为无。

异常

1)
noexcept 说明：
noexcept(std::is_nothrow_invocable_v<F, Args...>)
2)
noexcept 说明：
noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>)

可能的实现

版本一
namespace detail {
template<class>
constexpr bool is_reference_wrapper_v = false;
template<class U>
constexpr bool is_reference_wrapper_v<std::reference_wrapper<U>> = true;

template<class C, class Pointed, class T1, class... Args>
constexpr decltype(auto) invoke_memptr(Pointed C::* f, T1&& t1, Args&&... args)
{
    if constexpr (std::is_function_v<Pointed>) {
        if constexpr (std::is_base_of_v<C, std::decay_t<T1>>)
            return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
        else if constexpr (is_reference_wrapper_v<std::decay_t<T1>>)
            return (t1.get().*f)(std::forward<Args>(args)...);
        else
            return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
    } else {
        static_assert(std::is_object_v<Pointed> && sizeof...(args) == 0);
        if constexpr (std::is_base_of_v<C, std::decay_t<T1>>)
            return std::forward<T1>(t1).*f;
        else if constexpr (is_reference_wrapper_v<std::decay_t<T1>>)
            return t1.get().*f;
        else
            return (*std::forward<T1>(t1)).*f;
    }
}
} // namespace detail

template<class F, class... Args>
constexpr std::invoke_result_t<F, Args...> invoke(F&& f, Args&&... args)
    noexcept(std::is_nothrow_invocable_v<F, Args...>)
{
    if constexpr (std::is_member_pointer_v<std::decay_t<F>>)
        return detail::invoke_memptr(f, std::forward<Args>(args)...);
    else
        return std::forward<F>(f)(std::forward<Args>(args)...);
}
版本二
template<class R, class F, class... Args>
    requires std::is_invocable_r_v<R, F, Args...>
constexpr R invoke_r(F&& f, Args&&... args)
    noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>)
{
    if constexpr (std::is_void_v<R>)
        std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
    else
        return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
}

示例

#include <functional>
#include <iostream>
#include <type_traits>

struct Foo {
    Foo(int num) : num_(num) {}
    void print_add(int i) const { std::cout << num_+i << '\n'; }
    int num_;
};

void print_num(int i)
{
    std::cout << i << '\n';
}

struct PrintNum {
    void operator()(int i) const
    {
        std::cout << i << '\n';
    }
};

int main()
{
    // 调用自由函数
    std::invoke(print_num, -9);

    // 调用 lambda
    std::invoke([]() { print_num(42); });

    // 调用成员函数
    const Foo foo(314159);
    std::invoke(&Foo::print_add, foo, 1);

    // 调用（访问）数据成员
    std::cout << "num_: " << std::invoke(&Foo::num_, foo) << '\n';

    // 调用函数对象
    std::invoke(PrintNum(), 18);

#   if defined(__cpp_lib_invoke_r)
    auto add = [](int x, int y) { return x + y; };
    auto ret = std::invoke_r<float>(add, 11, 22);
    static_assert(std::is_same<decltype(ret), float>());
    std::cout << ret << '\n';
    std::invoke_r<void>(print_num, 44);
#   endif
}

可能的输出：

-9
42
314160
num_: 314159
18
33
44

参阅

mem_fn (C++11) | 从成员指针创建出函数对象 (函数模板)
result_ofinvoke_result (C++11)(C++20 中移除)(C++17) | 推导以一组实参调用一个可调用对象的结果类型 (类模板)
is_invocableis_invocable_ris_nothrow_invocableis_nothrow_invocable_r (C++17) | 检查类型能否以给定的实参类型调用（如同以 std::invoke） (类模板)
apply (C++17) | 以一个实参的元组来调用函数 (函数模板)


std::is_bind_expression

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct is_bind_expression; | (C++11 起)

若 T 是调用 std::bind 产生的类型，则此模板从 std::true_type 导出。对于任何其他类型，此模板从 std::false_type 导出。

此模板可对用户定义类型 T 特化，以实现一元类型特征 (UnaryTypeTrait) ，其基特征为 std::true_type 指示 T 应被处理成如同它是 bind 子表达式的类型：调用 bind 生成的函数对象时，此类型的被绑定参数将作为函数对象调用，且将被给予传递给 bind 生成对象的所有未绑定参数。

辅助变量模板

template< class T > inline constexpr bool is_bind_expression_v = is_bind_expression<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 若 T 是 std::bind 生成的函数对象则为 true ，否则为 false
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

#include <iostream>
#include <type_traits>
#include <functional>

struct MyBind {
    typedef int result_type;
    int operator()(int a, int b) const { return a + b; }
};

namespace std {
    template<>
    struct is_bind_expression<MyBind> : public true_type {};
}

int f(int n1, int n2)
{
    return n1+n2;
}

int main()
{
    // 如同 bind(f, bind(MyBind::operator(), _1, _2), 2)
    auto b = std::bind(f, MyBind(), 2);

    std::cout << "Adding 2 to the sum of 10 and 11 gives " << b(10, 11) << '\n';
}

输出：

Adding 2 to the sum of 10 and 11 gives 23

参阅

bind
(C++11)
 绑定一或多个实参到函数对象
(函数模板)


std::is_placeholder

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct is_placeholder; | (C++11 起)

若 T 是标准占位符（ _1 、 _2 、 _3 ……）的类型，则此模板分别派生自 std::integral_constant <int,1> 、 std::integral_constant <int,2> 、 std::integral_constant <int,3> 。

若 T 不是标准占位符类型，则此模板派生自 std::integral_constant <int,0> 。

可以为任何用户定义 T 类型特化模板：特化必须满足一元类型特征 (UnaryTypeTrait) ，拥有 std::integral_constant <int, N> 而 N > 0 指示 T 应被处理成第 N 个占位符类型的基特征。

std::bind 用 std::is_placeholder 检测未绑定参数的占位符。

辅助变量模板

template< class T > inline constexpr int is_placeholder_v = is_placeholder<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 占位符值，或对于非占位符类型为 0
(公开静态成员常量)

成员函数

operator int | 转换对象为 int ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | int
type | std::integral_constant <int, value>

示例

#include <iostream>
#include <type_traits>
#include <functional>

struct My_2 {
} my_2;

namespace std {
    template<>
    struct is_placeholder<My_2> : public integral_constant<int, 2> {};
}

int f(int n1, int n2)
{
    return n1+n2;
}

int main()
{
    std::cout << "Standard placeholder _5 is for the argument number "
              << std::is_placeholder<decltype(std::placeholders::_5)>::value
              << '\n';

    auto b = std::bind(f, my_2, 2);
    std::cout << "Adding 2 to 11 selected with a custom placeholder gives "
              << b(10, 11) // 忽略首参数，即 10
              << '\n';
}

输出：

Standard placeholder _5 is for the argument number 5
Adding 2 to 11 selected with a custom placeholder gives 13

参阅

bind (C++11) | 绑定一或多个实参到函数对象 (函数模板)
_1, _2, _3, _4, ... (C++11) | 用作 std::bind 表达式中的未绑定实参的占位符 (常量)


std::less

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct less; | (C++14 前)
template< class T = void > struct less; | (C++14 起)

进行比较的函数对象。调用类型 T 上的 operator< ，除非特化。

实现定义的指针上的严格全序

std::less 对任何指针类型的特化产生实现定义的严格全序，即使内建的 < 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 (C++20 起)<、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void (C++14 起)时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way
 (C++20 起)

特化

less<void>
(C++14)
 实现 x < y 并推导参数和返回类型的函数对象
(类模板特化)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | bool
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, bool> 获得。

 (C++11 前)

成员函数

operator()
 检查第一参数是否小于第二个
(公开成员函数)

std::less::operator()

bool operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr bool operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

检查 lhs 是否小于 rhs 。

参数

lhs, rhs - 要比较的值

返回值

对于不是指针类型的 T ，若 lhs < rhs 则为 true ，否则为 false 。

对于是指针类型的 T ，若 lhs 在实现定义的严格全序中前驱 rhs 则为 true ，否则为 false 。

异常

可能抛出实现定义的异常。

可能的实现

constexpr bool operator()(const T &lhs, const T &rhs) const
{
    return lhs < rhs; // 假定实现使用平坦地址空间
}

示例

#include <functional>
#include <iostream>

template <typename A, typename B, typename C = std::less<>>
bool fun(A a, B b, C cmp = C{})
{
    return cmp(a, b);
}

int main()
{
    std::cout
      << std::boolalpha
      << fun(1, 2)   << ' ' // true
      << fun(1.0, 1) << ' ' // false
      << fun(1, 2.0) << ' ' // true
      << std::less<int>{}(5, 5.6)    << ' ' // false ： 5 < 5 （警告：隐式转换）
      << std::less<double>{}(5, 5.6) << ' ' // true  ： 5.0 < 5.6
      << std::less<int>{}(5.6, 5.7)  << ' ' // false ： 5 < 5 （警告：隐式转换）
      << std::less{}(5, 5.6)         << ' ' // true  ： less<void>: 5.0 < 5.6
      << '\n';
}

输出：

true false true false true false true

参阅

owner_less (C++11) | 提供基于所有者的，共享指针和弱指针的混合类型的排序 (类模板)
greater | 实现 x > y 的函数对象 (类模板)


std::less_equal

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct less_equal; | (C++14 前)
template< class T = void > struct less_equal; | (C++14 起)

进行比较的函数对象。调用类型 T 上的 operator<= ，除非特化。

实现定义的指针上的严格全序

std::less_equal 对任何指针类型的特化产生实现定义的严格全序，即使内建的 <= 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 (C++20 起)<、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void (C++14 起)时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way
 (C++20 起)

特化

less_equal<void>
(C++14)
 实现 x <= y 并推导参数和返回类型的函数对象
(类模板特化)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | bool
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, bool> 获得。

 (C++11 前)

成员函数

operator()
 检查第一参数是否小于或等于第二个
(公开成员函数)

std::less_equal::operator()

bool operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr bool operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

检查 lhs 是否小于或等于 rhs 。

参数

lhs, rhs - 要比较的值

返回值

对于不是指针类型的 T ，若 lhs <= rhs 则为 true ，否则为 false 。

对于是指针类型的 T ，若 lhs 在实现定义的严格全序中不后继 rhs 则为 true ，否则为 false 。

异常

可能抛出实现定义的异常。

可能的实现

constexpr bool operator()(const T &lhs, const T &rhs) const
{
    return lhs <= rhs; // 假定实现使用平坦地址空间
}


std::less_equal<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class less_equal<void>; | (C++14 起)

std::less_equal <> 是 std::less_equal 的特化，拥有待推导的参数和返回类型。

实现定义的指针上的严格全序

若参数间的 <= 运算符调用指针的内建比较运算符，则函数调用运算符产生实现定义的指针上的严格全序，即使内建的 <= 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 (C++20 起)<、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void 时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way
 (C++20 起)

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 测试 lhs 是否比较小于或等于 rhs
(公开成员函数)

std::less_equal<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) <= std::forward <U>(rhs));

返回 std::forward <T>(lhs) <= std::forward <U>(rhs) 的结果。

参数

lhs, rhs - 要比较的值

返回值

std::forward <T>(lhs) <= std::forward <U>(rhs) 的结果。

若两个实参的比较解析到指针类型的内建比较运算符，则在转换两个实参到指针后用实现定义的严格全序进行比较。

异常

可能抛出实现定义的异常。

注解

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::less<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class less<void>; | (C++14 起)

std::less <> 是 std::less 的特化，拥有待推导的参数和返回类型。

实现定义的指针上的严格全序

若参数间的 < 运算符调用指针的内建比较运算符，则函数调用运算符产生实现定义的指针上的严格全序，即使内建的 < 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 (C++20 起)<、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void 时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way
 (C++20 起)

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 测试 lhs 是否比较小于 rhs
(公开成员函数)

std::less<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) < std::forward <U>(rhs));

返回 std::forward <T>(lhs) < std::forward <U>(rhs) 的结果。

参数

lhs, rhs - 要比较的值

返回值

std::forward <T>(lhs) < std::forward <U>(rhs) 的结果。

若两个实参的比较解析到指针类型的内建比较运算符，则在转换两个实参到指针后用实现定义的严格全序进行比较。

异常

可能抛出实现定义的异常。

注解

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::logical_and

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct logical_and; | (C++14 前)
template< class T = void > struct logical_and; | (C++14 起)

进行逻辑与（逻辑合取）的函数对象。等效地调用类型 T 上的 operator&& 。

特化

标准库提供 std::logical_and 在不指定 T 时的特化，它使得参数类型和返回类型留待推导。

logical_and<void>
(C++14)
 实现 x && y 并推导参数和返回类型的函数对象
(类模板特化)
(C++14 起)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | bool
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, bool> 获得。

 (C++11 前)

成员函数

operator()
 返回二个参数的逻辑与
(公开成员函数)

std::logical_and::operator()

bool operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr bool operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

返回 lhs 和 rhs 的逻辑与。

参数

lhs, rhs - 要计算其逻辑与的值

返回值

lhs && rhs 的结果。

异常

可能抛出实现定义的异常。

可能的实现

constexpr bool operator()(const T &lhs, const T &rhs) const
{
    return lhs && rhs;
}


std::logical_and<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class logical_and<void>; | (C++14 起)

std::logical_and <> 是 std::logical_and 拥有待推导参数和返回类型的特化。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 应用 operator&& 到 lhs 和 rhs
(公开成员函数)

std::logical_and<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) && std::forward <U>(rhs));

返回 lhs && rhs 的结果。

参数

lhs, rhs - 要逻辑与的值

返回值

lhs && rhs 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::logical_not

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct logical_not; | (C++14 前)
template< class T = void > struct logical_not; | (C++14 起)

实现逻辑非（逻辑取反）的函数对象。等效地调用类型 T 的 operator! 。

特化

标准库提供 std::logical_not 在不指定 T 时的特化，它使得参数类型和返回类型留待推导。

logical_not<void>
(C++14)
 实现 !x 并推导参数和返回类型的函数对象
(类模板特化)
(C++14 起)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | bool
argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::unary_function <T, bool> 获得。

 (C++11 前)

成员函数

operator()
 返回参数的逻辑非
(公开成员函数)

std::logical_not::operator()

bool operator()( const T& arg ) const; | (C++14 前)
constexpr bool operator()( const T& arg ) const; | (C++14 起)

返回 arg 的逻辑非。

参数

arg - 要计算逻辑非的值

返回值

!arg 的结果。

异常

可能抛出实现定义的异常。

可能的实现

const bool operator()(const T &arg) const
{
    return !arg;
}


std::logical_not<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class logical_not<void>; | (C++14 起)

std::logical_not <> 是 std::logical_not 的特化，拥有待推导的参数和返回类型。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

Member functions

operator()
 到其参数
(公开成员函数)

std::logical_not<>::operator()

template< class T >

constexpr auto operator()( T&& arg ) const

-> decltype(! std::forward <T>(arg));

返回 !arg 的结果。

参数

arg - 应用逻辑非到的值

返回值

!arg 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::logical_or

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct logical_or; | (C++14 前)
template< class T = void > struct logical_or; | (C++14 起)

实现逻辑或（逻辑析取）的函数对象。等效地调用类型 T 上的 operator|| 。

特化

标准库提供 std::logical_or 在不指定 T 时的特化，它使得参数类型和返回类型留待推导。

logical_or<void>
(C++14)
 实现 x || y 并推导参数和返回类型的函数对象
(类模板特化)
(C++14 起)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | bool
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, bool> 获得。

 (C++11 前)

成员函数

operator()
 返回二个参数的逻辑或
(公开成员函数)

std::logical_or::operator()

bool operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr bool operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

返回 lhs 和 rhs 的逻辑或。

参数

lhs, rhs - 要计算其逻辑或的值

返回值

lhs || rhs 的结果。

异常

可能抛出实现定义的异常。

可能的实现

constexpr bool operator()(const T &lhs, const T &rhs) const
{
    return lhs || rhs;
}


std::logical_or<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class logical_or<void>; | (C++14 起)

std::logical_or <> 是 std::logical_or 的特化，拥有待推导的参数和返回类型。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 应用 operator|| 到 lhs 和 rhs
(公开成员函数)

std::logical_or<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) || std::forward <U>(rhs));

返回 std::forward <T>(lhs) || std::forward <U>(rhs) 的结果。

参数

lhs, rhs - 要逻辑或的值

返回值

std::forward <T>(lhs) || std::forward <U>(rhs) 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::mem_fn

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class M, class T > /*unspecified*/ mem_fn(M T::* pm) noexcept; | (C++11 起) (C++20 前)
template< class M, class T > constexpr /*unspecified*/ mem_fn(M T::* pm) noexcept; | (C++20 起)

函数模板 std::mem_fn 生成指向成员指针的包装对象，它可以存储、复制及调用指向成员指针。到对象的引用和指针（含智能指针）可在调用 std::mem_fn 时使用。

参数

pm - 指向被包装成员的指针

返回值

std::mem_fn 返回未指定类型的调用包装，该类型拥有下列成员：

std::mem_fn 返回类型

成员类型

类型 | 定义
result_type(C++17 中弃用) | 若 pm 为指向成员函数的指针，则为 pm 的返回类型，对指向成员对象的指针不定义
argument_type(C++17 中弃用) | 若 pm 是指向无参数成员函数的指针则为 T* ，可有 cv 限定
first_argument_type(C++17 中弃用) | 若 pm 是指向接收一个参数的成员函数的指针则为 T*
second_argument_type(C++17 中弃用) | 若 pm 是指向接收一个 T1 类型参数的成员函数的指针则为 T1
 (C++20 前)

成员函数

template<class... Args>

/* see below */ operator()(Args&&... args) /* cvref-qualifiers */

noexcept(/* see below */);
 (C++20 前)
template<class... Args>

constexpr /* see below */ operator()(Args&&... args) /* cvref-qualifiers */

noexcept(/* see below */);
 (C++20 起)

令 fn 为以指向成员的指针 pm 调用std::mem_fn 所返回的调用包装器。则表达式 fn(t, a2, ..., aN) 等价于 INVOKE(pm, t, a2, ..., aN) ，其中 INVOKE 是定义于可调用 (Callable) 的操作。

从而 operator() 的返回类型是std::result_of <decltype(pm)(Args&&...)>::type，或等价地为 std::invoke_result_t<decltype(pm), Args&&...> ，而 noexcept 说明符中的值等于 std::is_nothrow_invocable_v<decltype(pm), Args&&...>) (C++17 起)。

完美转发 args 中的每个参数，如同用 std::forward <Args>(args)... 。

示例

用 mem_fn 存储执行成员函数和成员对象：

#include <functional>
#include <iostream>

struct Foo {
    void display_greeting() {
        std::cout << "Hello, world.\n";
    }
    void display_number(int i) {
        std::cout << "number: " << i << '\n';
    }
    int data = 7;
};

int main() {
    Foo f;

    auto greet = std::mem_fn(&Foo::display_greeting);
    greet(&f);

    auto print_num = std::mem_fn(&Foo::display_number);
    print_num(&f, 42);

    auto access_data = std::mem_fn(&Foo::data);
    std::cout << "data: " << access_data(&f) << '\n';
}

输出：

Hello, world.
number: 42
data: 7

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2048 | C++11 | 提供了不需要的重载 | 已移除
LWG 2489 | C++11 | 未要求 noexcept | 已要求

参阅

function (C++11) | 包装具有指定函数调用签名的任意可复制构造类型的可调用对象 (类模板)
bind (C++11) | 绑定一或多个实参到函数对象 (函数模板)


std::mem_fun

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |  |
template< class Res, class T > std::mem_fun_t<Res,T> mem_fun( Res (T::*f)() ); | (1) | (C++11 中弃用) (C++17 中移除)
template< class Res, class T > std::const_mem_fun_t<Res,T> mem_fun( Res (T::*f)() const ); | (1) | (C++11 中弃用) (C++17 中移除)
template< class Res, class T, class Arg > std::mem_fun1_t<Res,T,Arg> mem_fun( Res (T::*f)(Arg) ); | (2) | (C++11 中弃用) (C++17 中移除)
template< class Res, class T, class Arg > std::const_mem_fun1_t<Res,T,Arg> mem_fun( Res (T::*f)(Arg) const ); | (2) | (C++11 中弃用) (C++17 中移除)

创建成员函数包装对象，从模板实参推导类型。包装对象期待到指向 T 类型对象的指针作为其 operator() 的首个参数。

1) 等效地调用 std::mem_fun_t<S,T>(f) 或 std::const_mem_fun_t<S,T>(f) 。
2) 等效地调用 std::mem_fun1_t<S,T>(f) 或 std::const_mem_fun1_t<S,T>(f) 。

此函数与相关类型于 C++11 弃用并于 C++17 移除，为了让位给更通用的 std::mem_fn 与 std::bind ，它们都从成员函数创建可调用类型的兼容适配器的函数对象。

参数

f - 指向要创建包装的成员函数的指针

返回值

包装 f 的函数对象。

异常

可能抛出实现定义的异常。

注解

std::mem_fun 与 std::mem_fun_ref 的区别是前者产生的函数包装期待指向对象指针，而后者——期待引用。

示例

本节未完成
原因：暂无示例

参阅

mem_fn (C++11) | 从成员指针创建出函数对象 (函数模板)
mem_fun_ref (C++11 中弃用)(C++17 中移除) | 从成员函数指针创建包装器，能以一个对象引用调用 (函数模板)


std::mem_fun_ref

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |  |
template< class Res, class T > std::mem_fun_ref_t<Res,T> mem_fun_ref( Res (T::*f)() ); | (1) | (C++11 中弃用) (C++17 中移除)
template< class Res, class T > std::const_mem_fun_ref_t<Res,T> mem_fun_ref( Res (T::*f)() const ); | (1) | (C++11 中弃用) (C++17 中移除)
template< class Res, class T, class Arg > std::mem_fun1_ref_t<Res,T,Arg> mem_fun_ref( Res (T::*f)(Arg) ); | (2) | (C++11 中弃用) (C++17 中移除)
template< class Res, class T, class Arg > std::const_mem_fun1_ref_t<Res,T,Arg> mem_fun_ref( Res (T::*f)(Arg) const ); | (2) | (C++11 中弃用) (C++17 中移除)

创建成员函数包装对象，从模板实参推导类型。包装对象期待到 T 类型的引用作为其 operator() 的首个参数。

1) 等效地调用 std::mem_fun_ref_t<S,T>(f) 或 std::const_mem_fun_ref_t<S,T>(f) 。
2) 等效地调用 std::mem_fun1_ref_t<S,T>(f) 或 std::const_mem_fun1_ref_t<S,T>(f) 。

此函数与相关类型于 C++11 弃用并于 C++17 移除，为了让位给更通用的 std::mem_fn 与 std::bind ，它们都从成员函数创建可调用类型的兼容适配器的函数对象。

参数

f - 指向要创建包装的成员函数的指针

返回值

包装 f 的函数对象。

异常

可能抛出实现定义的异常。

注解

std::mem_fun 与 std::mem_fun_ref 的区别是前者产生的函数包装期待指向对象指针，而后者——期待引用。

示例

用 std::mem_fun_ref 绑定 std::string 的成员函数 size() 。

#include <functional>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
#include <iostream>

int main()
{
    std::vector<std::string> v = {"once", "upon", "a", "time"};
    std::transform(v.begin(), v.end(),
                   std::ostream_iterator<std::size_t>(std::cout, " "),
                   std::mem_fun_ref(&std::string::size));
}

输出：

4 4 1 4

参阅

mem_fun
(C++11 中弃用)(C++17 中移除)
 从成员函数指针创建包装器，可以一个对象指针调用
(函数模板)


std::mem_fun_ref_t, std::mem_fun1_ref_t, std::const_mem_fun_ref_t, std::const_mem_fun1_ref_t

< cpp‎ | utility‎ | functional
template< class S, class T >

class mem_fun_ref_t : public unary_function<T,S> {
public:
explicit mem_fun_ref_t(S (T::*p)());
S operator()(T& p) const;

};
 (1) (C++11 中弃用)
(C++17 中移除)
template< class S, class T >

class const_mem_fun_ref_t : public unary_function<T,S> {
public:
explicit const_mem_fun_ref_t(S (T::*p)() const);
S operator()(const T& p) const;

};
 (2) (C++11 中弃用)
(C++17 中移除)
template< class S, class T, class A >

class mem_fun1_ref_t : public binary_function<T,A,S> {
public:
explicit mem_fun1_ref_t(S (T::*p)(A));
S operator()(T& p, A x) const;

};
 (3) (C++11 中弃用)
(C++17 中移除)
template< class S, class T, class A >

class const_mem_fun1_ref_t : public binary_function<T,A,S> {
public:
explicit const_mem_fun1_ref_t(S (T::*p)(A) const);
S operator()(const T& p, A x) const;

};
 (4) (C++11 中弃用)
(C++17 中移除)

围绕成员函数指针的包装器。将要调用其成员函数的类实例作为引用传递给 operator() 。

1) 包装无参数的非 const 成员函数。
2) 包装无参数的 const 成员函数。
3) 包装有单参数的非 const 成员函数。
4) 包装有单参数的 const 成员函数。

参阅

mem_fun_ref (C++11 中弃用)(C++17 中移除) | 从成员函数指针创建包装器，能以一个对象引用调用 (函数模板)
mem_fun_tmem_fun1_tconst_mem_fun_tconst_mem_fun1_t (C++11 中弃用)(C++17 中移除) | 指向零元或一元成员函数指针的包装器，可以一个对象指针调用 (类模板)


std::mem_fun_t, std::mem_fun1_t, std::const_mem_fun_t, std::const_mem_fun1_t

< cpp‎ | utility‎ | functional
template< class S, class T >

class mem_fun_t : public unary_function<T*,S> {
public:
explicit mem_fun_t(S (T::*p)());
S operator()(T* p) const;

};
 (1) (C++11 中弃用)
(C++17 中移除)
template< class S, class T >

class const_mem_fun_t : public unary_function<const T*,S> {
public:
explicit const_mem_fun_t(S (T::*p)() const);
S operator()(const T* p) const;

};
 (2) (C++11 中弃用)
(C++17 中移除)
template< class S, class T, class Arg >

class mem_fun1_t : public binary_function<T*,A,S> {
public:
explicit mem_fun1_t(S (T::*p)(A));
S operator()(T* p, A x) const;

};
 (3) (C++11 中弃用)
(C++17 中移除)
template< class S, class T, class A >

class const_mem_fun1_t : public binary_function<const T*,A,S> {
public:
explicit const_mem_fun1_t(S (T::*p)(A) const);
S operator()(const T* p, A x) const;

};
 (4) (C++11 中弃用)
(C++17 中移除)

围绕成员函数指针的包装器。将要调用其成员函数的类实例作为指针传递给 operator() 。

1) 包装无参数的非 const 成员函数。
2) 包装无参数的 const 成员函数。
3) 包装有单参数的非 const 成员函数。
4) 包装有单参数的 const 成员函数。

参阅

mem_fun (C++11 中弃用)(C++17 中移除) | 从成员函数指针创建包装器，可以一个对象指针调用 (函数模板)
mem_fun_ref_tmem_fun1_ref_tconst_mem_fun_ref_tconst_mem_fun1_ref_t (C++11 中弃用)(C++17 中移除) | 指向零元或一元成员函数指针的包装器，可以一个对象引用调用 (类模板)


std::minus

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct minus; | (C++14 前)
template< class T = void > struct minus; | (C++14 起)

进行减法的函数对象。等效于在二个 T 类型实例上调用 operator- 。

特化

标准库提供未指定 T 时的 std::minus 特化，它令参数类型和返回类型有待推导。

minus<void>
(C++14)
 实现 x - y 的函数对象，推导参数与返回类型
(类模板特化)
(C++14 起)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | T
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, T> 获得。

 (C++11 前)

成员函数

operator()
 返回二个参数的差
(公开成员函数)

std::minus::operator()

T operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr T operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

返回 lhs 与 rhs 的差。

参数

lhs, rhs - 从一者减去另一者的值

返回值

lhs - rhs 的结果。

异常

可能抛出实现定义的异常。

可能的实现

constexpr T operator()(const T &lhs, const T &rhs) const
{
    return lhs - rhs;
}


std::minus<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class minus<void>; | (C++14 起)

std::minus <> 是 std::minus 的特化，推导出其参数与返回类型。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 返回二个参数的差
(公开成员函数)

std::minus<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) - std::forward <U>(rhs));

返回从 lhs 减去 rhs 的结果（或若被重载则为 operator- 所为）。

参数

lhs, rhs - 要相减的值

返回值

lhs - rhs 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::modulus

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct modulus; | (C++14 前)
template< class T = void > struct modulus; | (C++14 起)

计算除法余数的函数对象。为类型 T 实现 operator% 。

特化

标准库提供 std::modulus 在不指定 T 时的特化，使参数类型和返回类型留待推导。

modulus<void>
(C++14)
 实现 x % y 并推导参数和返回类型的函数对象
(类模板特化)
(C++14 起)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | T
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, T> 获得。

 (C++11 前)

成员函数

operator()
 返回首参数除以第二参数的余数
(公开成员函数)

std::modulus::operator()

T operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr T operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

返回 lhs 除以 rhs 的余数。

参数

lhs, rhs - 以一个除另一个的值

返回值

lhs % rhs 的结果。

异常

可能抛出实现定义的异常。

可能的实现

constexpr T operator()(const T &lhs, const T &rhs) const
{
    return lhs % rhs;
}

参阅

fmodfmodffmodl (C++11)(C++11) | 浮点除法运算的余数 (函数)
remainderremainderfremainderl (C++11)(C++11)(C++11) | 除法运算的有符号余数 (函数)


std::modulus<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class modulus<void>; | (C++14 起)

std::modulus <> 是 std::modulus 的特化，其参数与返回类型留待推导。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 返回二个参数的模
(公开成员函数)

std::modulus<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) % std::forward <U>(rhs));

返回 lhs 除以 rhs 的余数（或重载 operator% 之所为）。

参数

lhs, rhs - 要除的值

返回值

lhs % rhs 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::move_only_function

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class... > class move_only_function; // 不定义 | (C++23 起)
template< class R, class... Args > class move_only_function<R(Args...)>; template< class R, class... Args > class move_only_function<R(Args...) noexcept>; template< class R, class... Args > class move_only_function<R(Args...) &>; template< class R, class... Args > class move_only_function<R(Args...) & noexcept>; template< class R, class... Args > class move_only_function<R(Args...) &&>; template< class R, class... Args > class move_only_function<R(Args...) && noexcept>; template< class R, class... Args > class move_only_function<R(Args...) const>; template< class R, class... Args > class move_only_function<R(Args...) const noexcept>; template< class R, class... Args > class move_only_function<R(Args...) const &>; template< class R, class... Args > class move_only_function<R(Args...) const & noexcept>; template< class R, class... Args > class move_only_function<R(Args...) const &&>; template< class R, class... Args > class move_only_function<R(Args...) const && noexcept>; | (C++23 起)

类模板 std::move_only_function 是通用的多态函数包装。 std::move_only_function 对象存储并调用任何可构造（不要求为可移动构造）的可调用 (Callable) 目标——函数、 lambda 表达式、 bind 表达式或其他函数对象，以及成员函数指针和成员对象指针。

称存储的可调用对象为 std::move_only_function 的目标。若 std::move_only_function 不含目标，则称之为空。不同于 std::function ，调用空的 std::move_only_function 导致未定义行为。

std::move_only_functions 支持在其模板形参中提供的不含 volatile 的每种 cv 限定符、引用限定符及 noexcept 说明符的组合。这些限定符与说明符（若存在）被添加到其 operator() 。

std::move_only_function 满足可移动构造 (MoveConstructible) 与可移动赋值 (MoveAssignable) 的要求，但不满足可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 。

成员类型

类型 | 定义
result_type | R

成员函数

(构造函数) (C++23) | 构造新的 std::move_only_function 对象 (公开成员函数)
(析构函数) (C++23) | 销毁 std::move_only_function 对象 (公开成员函数)
operator= (C++23) | 替换或销毁目标 (公开成员函数)
swap (C++23) | 交换二个 std::move_only_function 对象的目标 (公开成员函数)
operator bool (C++23) | 检查 std::move_only_function 是否拥有目标 (公开成员函数)
operator() (C++23) | 调用目标 (公开成员函数)

非成员函数

swap(std::move_only_function) (C++23) | 重载 std::swap 算法 (函数)
operator== (C++23) | 比较 std::move_only_function 与 nullptr (函数)

注解

推荐实现存储有较小大小的可调用对象于 std::move_only_function 对象内部。这种小对象优化等效地对于函数指针和 std::reference_wrapper 特化要求，并且只能应用到 std::is_nothrow_move_constructible_v <T> 为 true 的类型 T 。

类似 std::function ，若 R 为能绑定到右值的引用类型，则 std::move_only_function 可能包装按值返回的函数对象，该情况下对这种 std::move_only_function 的调用始终返回悬垂引用。

std::move_only_function<const int&() const> uf([]{ return 42; });
int x = uf(); // 未定义行为： uf() 的结果为悬垂引用

示例

本节未完成
原因：暂无示例

参阅

function
(C++11)
 包装具有指定函数调用签名的任意可复制构造类型的可调用对象
(类模板)


std::move_only_function<R(Args...) cv ref noexcept(noex)>::move_only_function

< cpp‎ | utility‎ | functional‎ | move only function
move_only_function() noexcept;
 (1) (C++23 起)
move_only_function( std::nullptr_t ) noexcept;
 (2) (C++23 起)
move_only_function( move_only_function&& other ) noexcept;
 (3) (C++23 起)
move_only_function( const move_only_function& ) = delete;
 (4) (C++23 起)
template< class F >
move_only_function( F&& f );
 (5) (C++23 起)
template< class T, class... CArgs >
explicit move_only_function( std::in_place_type_t <T>, CArgs&&... args );
 (6) (C++23 起)
template< class T, class U, class... CArgs >

explicit move_only_function( std::in_place_type_t <T>,

std::initializer_list <U> il, CArgs&&... args );
 (7) (C++23 起)

创建新的 std::move_only_function 。

1-2) 默认构造函数与接收 nullptr 的构造函数构造空的 std::move_only_function 。
3) 移动构造函数构造目标为 other 的目标的 std::move_only_function 。移动构造后 other 在拥有未指定值的合法状态。
4) 复制构造函数被删除。 std::move_only_function 不满足可复制构造 (CopyConstructible) 。
5) 令 VT 为 std::decay_t <F> 。若 f 为空函数指针、空成员函数指针或空 std::move_only_function （可为任何特化），则构造空的 std::move_only_function 。否则，构造目标具有 VT 类型并以 std::forward <F>(f) 直接非列表初始化的 std::move_only_function 。
  • 此重载仅若 VT 既非 move_only_function 亦非 std::in_place_type_t 的特化，且 /*is-callable-from*/<VT> 为 true 才参与重载决议。
  • 若 std::is_constructible_v <VT, F> 非 true 则程序非良构。
6) 令 VT 为 std::decay_t <T> 。构造目标具有 VT 类型并以 std::forward <CArgs>(args)... 直接非列表初始化的 std::move_only_function 。
  • 此重载仅若 std::is_constructible_v <VT, CArgs...> 与 /*is-callable-from*/<VT> （见后述）均为 true 才参与重载决议。
  • 若 VT 与 T 不是同一类型则程序非良构。
7) 令 VT 为 std::decay_t <T> 。构造目标具有 VT 类型并以 il, std::forward <CArgs>(args)... 直接非列表初始化的 std::move_only_function 。
  • 此重载仅若 std::is_constructible_v <VT, std::initializer_list <U>&, CArgs...> 与 /*is-callable-from*/<VT> （见后述）均为 true 才参与重载决议。
  • 若 VT 与 T 不是同一类型则程序非良构。

对于构造函数 (5-7) ，若 VT 不满足可析构 (Destructible) 要求或若 std::is_move_constructible_v <VT> 为 true 但不满足可移动构造 (MoveConstructible) 要求则行为未定义。

常量 /*is-callable-from*/<VT> 以如下方式取决于 std::move_only_function 的模板形参中的 cv、 ref 及 noex ：

cv ref noexcept(noex) | /*is-callable-from*/<VT>
noexcept(false) std::is_invocable_r_v<R, VT, Args...> &&

std::is_invocable_r_v<R, VT&, Args...>
noexcept(true) std::is_nothrow_invocable_r_v<R, VT, Args...> &&

std::is_nothrow_invocable_r_v<R, VT&, Args...>
const noexcept(false) std::is_invocable_r_v<R, const VT, Args...> &&

std::is_invocable_r_v<R, const VT&, Args...>
const noexcept(true) std::is_nothrow_invocable_r_v<R, const VT, Args...> &&

std::is_nothrow_invocable_r_v<R, const VT&, Args...>
& noexcept(false) | std::is_invocable_r_v<R, VT&, Args...>
& noexcept(true) | std::is_nothrow_invocable_r_v<R, VT&, Args...>
const & noexcept(false) | std::is_invocable_r_v<R, const VT&, Args...>
const & noexcept(true) | std::is_nothrow_invocable_r_v<R, const VT&, Args...>
&& noexcept(false) | std::is_invocable_r_v<R, VT, Args...>
&& noexcept(true) | std::is_nothrow_invocable_r_v<R, VT, Args...>
const && noexcept(false) | std::is_invocable_r_v<R, const VT, Args...>
const && noexcept(true) | std::is_nothrow_invocable_r_v<R, const VT, Args...>

参数

other | - | 要移动的另一 std::move_only_function
f | - | 要包装的函数或可调用 (Callable) 对象
args | - | 构造目标对象的参数
il | - | 构造目标对象的 std::initializer_list

异常

5-7) 可能在分配失败时抛出 std::bad_alloc 或传播初始化目标时抛出的异常。若 VT 为函数指针类型或 std::reference_wrapper 的特化则不抛异常。

示例

本节未完成
原因：暂无示例

参阅

(构造函数)
 构造新的 std::function 实例
(std::function<R(Args...)> 的公开成员函数)


std::move_only_function<R(Args...) cv ref noexcept(noex)>::operator()

< cpp‎ | utility‎ | functional‎ | move only function
R operator()( Args... args ) /*cv*/ /*ref*/ noexcept(/*noex*/); | (C++23 起)

以参数 args 调用存储的可调用对象。 operator() 的 /*cv*/、 /*ref*/ 及 /*noex*/ 部分等同于 std::move_only_function 的模板形参的这些部分。

等价于 return std::invoke_r<R>(/*cv-ref-cast*/(f), std::forward <Args>(args)...); ，其中 f 是指代 *this 的目标对象的无 cv 限定左值，而 /*cv-ref-cast*/(f) 等价于：

  • f ，若 cv ref 为空或 & ，或
  • std::as_const (f) ，若 cv ref 为 const 或 const & ，或
  • std::move(f) ，若 cv ref 为 && ，或
  • std::move( std::as_const (f)) ，若 cv ref 为 const && 。

若 *this 为空则行为未定义。

参数

args - 传递给存储的可调用目标的参数

返回值

std::invoke_r<R>(/*cv-ref-cast*/(f), std::forward <Args>(args)...) 。

异常

传播底层函数调用所抛的异常。

示例

以下示例展示能如何按值传递 std::move_only_function 给其他函数。并且显示 std::move_only_function 能如何存储 lambda 。

#include <iostream>
#include <functional>

void call(std::move_only_function<int() const> f)  // 能按值传递
{
    std::cout << f() << '\n';
}

int normal_function()
{
    return 42;
}

int main()
{
    int n = 1;
    auto lambda = [&n](){ return n; };
    std::move_only_function<int() const> f = lambda;
    call(std::move(f));

    n = 2;
    call(lambda);

    f = normal_function;
    call(std::move(f));
}

输出：

1
2
42

参阅

operator() | 调用其目标 (std::function<R(Args...)> 的公开成员函数)
operator() | 调用其所存储的函数 (std::reference_wrapper<T> 的公开成员函数)
invokeinvoke_r (C++17)(C++23) | 以给定实参和可能指定的返回类型 (C++23 起)调用任意可调用 (Callable) 对象 (函数模板)


std::move_only_function<R(Args...) cv ref noexcept(noex)>::operator=

< cpp‎ | utility‎ | functional‎ | move only function
move_only_function& operator=( move_only_function&& other ); | (1) | (C++23 起)
move_only_function& operator=( const move_only_function& ) = delete; | (2) | (C++23 起)
move_only_function& operator=( std::nullptr_t ) noexcept; | (3) | (C++23 起)
template< class F > move_only_function& operator=( F&& f ); | (4) | (C++23 起)

指派新目标给 std::move_only_function 或销毁其目标。

1) 通过 auto(std::move(other)).swap(*this) 移动 other 的目标给 *this 或若 other 为空则销毁 *this 的目标（若存在）。移动赋值后 other 在有未指定值的合法状态。
2) 复制赋值运算符被删除。 std::move_only_function 不满足可复制赋值 (CopyAssignable) 。
3) 若当前目标存在则销毁它。调用后 *this 为空。
4) 如同通过执行 move_only_function( std::forward <F>(f)).swap(*this); 设置 *this 的目标为可调用对象 f ，或若 f 为空函数指针、空成员函数指针或空 std::move_only_function 则销毁当前目标。此重载仅若 move_only_function 可从 F 构造才参与重载决议。若选择的构造函数调用非良构或有未定义行为，则程序非良构或有未定义行为。

参数

other | - | 要移动目标的 std::move_only_function 对象
f | - | 用以初始化新目标的可调用对象

返回值

*this

注解

有意不要求移动赋值运算符为 noexcept ，以为将来的知分配器的 move_only_function 留出余地。

参阅

operator=
 为内容赋值
(std::function<R(Args...)> 的公开成员函数)


operator==(std::move_only_function)

< cpp‎ | utility‎ | functional‎ | move only function
friend bool operator==( const move_only_function& f, std::nullptr_t ) noexcept; | (C++23 起)

将 std::move_only_function 与 std::nullptr_t 比较。空包装（即无可调用目标的包装）比较相等，非空包装比较不相等。

此函数对通常无限定或有限定查找不可见，而只能在 std::move_only_function<FunctionType> 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

参数

f - 要比较的 std::move_only_function

返回值

!f 。

示例

#include <functional>
#include <iostream>

using SomeVoidFunc = std::move_only_function<void(int) const>;

class C {
public:
    C() = default;
    C(SomeVoidFunc func) : void_func_(std::move(func)) {}

    void default_func(int i) const { std::cout << i << '\n'; };

    void operator()() const
    {
        if (void_func_ == nullptr) // 与 nullptr 的特殊比较
            default_func(7);
        else
            void_func_(7);
    }

private:
    SomeVoidFunc void_func_{};
};

void user_func(int i)
{
    std::cout << (i + 1) << '\n';
}

int main()
{
    C c1;
    C c2(user_func);
    c1();
    c2();
}

输出：

7
8

参阅

operator==operator!=
(C++20 中移除)
 比较 std::function 和 nullptr
(函数模板)


std::move_only_function<R(Args...) cv ref noexcept(noex)>::operator bool

< cpp‎ | utility‎ | functional‎ | move only function
explicit operator bool() const noexcept; | (C++23 起)

检查 *this 是否存储可调用目标，即非空。

参数

(none)

返回值

若 *this 存储可调用目标则为 true ，否则为 false 。

示例

#include <functional>
#include <iostream>

void sampleFunction()
{
    std::cout << "This is the sample function!\n";
}

void checkFunc( std::move_only_function<void() const> const &func )
{
    // Use operator bool to determine if callable target is available.
    if( func ) {
        std::cout << "Function is not empty! Calling function.\n";
        func();
    }
    else {
        std::cout << "Function is empty. Nothing to do.\n";
    }
}

int main()
{
    std::move_only_function<void() const> f1{};
    std::move_only_function<void() const> f2{ sampleFunction };

    std::cout << "f1: ";
    checkFunc(f1);

    std::cout << "f2: ";
    checkFunc(f2);
}

输出：

f1: Function is empty. Nothing to do.
f2: Function is not empty! Calling function.
This is the sample function!

参阅

operator bool
 检查是否包含了有效的目标
(std::function<R(Args...)> 的公开成员函数)


std::move_only_function<R(Args...) cv ref noexcept(noex)>::swap

< cpp‎ | utility‎ | functional‎ | move only function
void swap( move_only_function& other ) noexcept; | (C++23 起)

交换 *this 与 other 存储的可调用对象。

参数

other - 要与之交换存储的可调用对象的函数包装

返回值

（无）

参阅

swap
 交换内容
(std::function<R(Args...)> 的公开成员函数)


swap(std::move_only_function)

< cpp‎ | utility‎ | functional‎ | move only function
friend void swap( move_only_function& lhs, move_only_function& rhs ) noexcept; | (C++23 起)

对 std::move_only_function 重载 std::swap 算法。交换 lhs 与 rhs 的状态。等效于调用 lhs.swap(rhs) 。

此函数对通常无限定或有限定查找不可见，而只能在 std::move_only_function<FunctionType> 为参数的关联类时由实参依赖查找找到。

参数

lhs, rhs - 要交换状态的 std::move_only_function 对象

返回值

（无）

示例

#include <concepts>
#include <functional>
#include <iostream>

void foo(const char* str, int x) {
    std::cout << "foo(\"" << str << "\", " << x << ")\n";
}

void bar(const char* str, int x) {
    std::cout << "bar(\"" << str << "\", " << x << ")\n";
}

int main()
{
    std::move_only_function<void(const char*, int) const> f1{ foo };
    std::move_only_function<void(const char*, int) const> f2{ bar };

    f1("f1", 1);
    f2("f2", 2);

    std::cout << "std::ranges::swap(f1, f2);\n";
    std::ranges::swap(f1, f2); // finds the hidden friend

    f1("f1", 1);
    f2("f2", 2);
}

输出：

foo("f1", 1)
bar("f2", 2)
std::ranges::swap(f1, f2);
bar("f1", 1)
foo("f2", 2)

参阅

swap (C++23) | 交换二个 std::move_only_function 对象的目标 (公开成员函数)
std::swap(std::function) (C++11) | 特化 std::swap 算法 (函数模板)


std::move_only_function<R(Args...) cv ref noexcept(noex)>::~move_only_function

< cpp‎ | utility‎ | functional‎ | move only function
~move_only_function(); | (C++23 起)

销毁 std::move_only_function 对象。若 std::move_only_function 非空，则亦销毁其目标。

参数

(析构函数)
 析构 std::function 实例
(std::function<R(Args...)> 的公开成员函数)


std::multiplies

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct multiplies; | (C++14 前)
template< class T = void > struct multiplies; | (C++14 起)

进行乘法的函数对象。等效地在二个 T 类型实例上调用 operator* 。

特化

标准库提供 std::multiplies 在不指定 T 时的特化，这使得参数类型和返回类型留待推导。

multiplies<void>
(C++14)
 实现 x * y 并推导参数和返回类型的函数对象
(类模板特化)
(C++14 起)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | T
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, T> 获得。

 (C++11 前)

成员函数

operator()
 返回二个参数的积
(公开成员函数)

std::multiplies::operator()

T operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr T operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

返回 lhs 与 rhs 的积。

参数

lhs, rhs - 要相乘的值

返回值

lhs * rhs 的结果。

异常

可能抛出实现定义的异常。

可能的实现

constexpr T operator()(const T &lhs, const T &rhs) const
{
    return lhs * rhs;
}


std::multiplies<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class multiplies<void>; | (C++14 起)

std::multiplies <> 是 std::multiplies 留待推导参数和返回类型的特化。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 返回二个参数的积
(公开成员函数)

std::multiplies<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) * std::forward <U>(rhs));

返回 lhs 乘以 rhs 的结果（或重载的 operator* 所为）。

参数

lhs, rhs - 要乘的值

返回值

lhs * rhs 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

实例

本节未完成
原因：暂无示例


std::negate

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct negate; | (C++14 前)
template< class T = void > struct negate; | (C++14 起)

进行取负的函数对象。等效地在 T 类型实例上调用 operator- 。

特化

标准库提供 std::negate 在不指定 T 时的特化，使参数类型和返回类型留待推导。

negate<void>
(C++14)
 实现 -x 并推导参数和返回类型的函数对象
(类模板特化)
(C++14 起)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | T
argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::unary_function <T, T> 获得。

 (C++11 前)

成员函数

operator()
 返回参数的相反数
(公开成员函数)

std::negate::operator()

T operator()( const T& arg ) const; | (C++14 前)
constexpr T operator()( const T& arg ) const; | (C++14 起)

返回 arg 的相反数。

参数

arg - 要计算相反数的值

返回值

-arg 的结果。

异常

可能抛出实现定义的异常。

可能的实现

constexpr T operator()(const T &arg) const
{
    return -arg;
}


std::negate<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class negate<void>; | (C++14 起)

std::negate <> 是 std::negate 的特化，其参数与返回类型留待推导。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 返回其负的参数
(公开成员函数)

std::negate<>::operator()

template< class T >

constexpr auto operator()( T&& arg ) const

-> decltype(- std::forward <T>(arg));

返回对 arg 求负的结果（或重载的 operator- 之所为）。

参数

arg - 要求负的值

返回值

-arg 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::not1

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class Predicate > std::unary_negate <Predicate> not1(const Predicate& pred); | (C++14 前)
template< class Predicate > constexpr std::unary_negate <Predicate> not1(const Predicate& pred); | (C++14 起) (C++17 中弃用) (C++20 中移除)

not1 是用于创建返回传递的一元谓词的补的函数对象。创建的函数对象类型为 std::unary_negate <Predicate> 。

一元谓词类型必须定义成员类型 argument_type ，它可转换为谓词的参数类型。从 std::ref 、 std::cref 、 std::negate 、 std::logical_not 、 std::mem_fn 、 std::function 、 std::hash 或调用另一 std::not1 获得的 unary_function 对象定义此类型，如同从弃用的 std::unary_function 导出的函数对象。

参数

pred - 一元谓词

返回值

std::not1 返回以 pred 构造的 std::unary_negate <Predicate> 类型对象。

异常

无。

示例

#include <algorithm>
#include <numeric>
#include <iterator>
#include <functional>
#include <iostream>
#include <vector>

struct LessThan7 : std::unary_function<int, bool>
{
    bool operator()(int i) const { return i < 7; }
};

int main()
{
    std::vector<int> v(10);
    std::iota(begin(v), end(v), 0);

    std::cout << std::count_if(begin(v), end(v), std::not1(LessThan7())) << "\n";

    // 同上，但使用 std::function
    std::function<bool(int)> less_than_9 = [](int x){ return x < 9; };
    std::cout << std::count_if(begin(v), end(v), std::not1(less_than_9)) << "\n";
}

输出：

3
1

参阅

not_fn (C++17) | 创建返回其保有的函数对象的结果之补的函数对象 (函数模板)
unary_negate (C++17 中弃用)(C++20 中移除) | 包装器函数对象，返回所持有的一元谓词的补 (类模板)
function (C++11) | 包装具有指定函数调用签名的任意可复制构造类型的可调用对象 (类模板)
not2 (C++17 中弃用)(C++20 中移除) | 构造定制的 std::binary_negate 对象 (函数模板)
ptr_fun (C++11 中弃用)(C++17 中移除) | 从函数指针创建与适配器兼容的函数对象包装器 (函数模板)
unary_function (C++11 中弃用)(C++17 中移除) | 与适配器兼容的一元函数基类 (类模板)


std::not2

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class Predicate > std::binary_negate <Predicate> not2(const Predicate& pred); | (C++14 前)
template< class Predicate > constexpr std::binary_negate <Predicate> not2(const Predicate& pred); | (C++14 起) (C++17 中弃用) (C++20 中移除)

not2 是创建函数对象的帮助函数，它返回传递的二元谓词函数的补。创建的函数对象拥有 std::binary_negate <Predicate> 类型。

二元谓词类型必须定义二个成员类型， first_argument_type 和 second_argument_type ，可转换为谓词参数类型。从 std::owner_less 、 std::ref 、 std::cref 、 std::plus 、 std::minus 、 std::multiplies 、 std::divides 、 std::modulus 、 std::equal_to 、 std::not_equal_to 、 std::greater 、 std::less 、 std::greater_equal 、 std::less_equal 、 std::logical_not 、 std::logical_or 、 std::bit_and 、 std::bit_or 、 std::bit_xor 、 std::mem_fn 、 std::map::value_comp 、 std::multimap::value_comp 、 std::function 或对 std::not2 调用获得的函数对象定义这些类型，和导出自弃用的 std::binary_function 的函数对象一样。

参数

pred - 二元谓词

返回值

std::not2 返回以 pred 构造的 std::binary_negate <Predicate> 类型对象。

异常

无。

示例

#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>

struct old_same : std::binary_function<int, int, bool>
{
    bool operator()(int a, int b) const { return a == b; }
};

struct new_same
{
    bool operator()(int a, int b) const { return a == b; }
};

bool same_fn(int a, int b)
{
    return a == b;
}

int main()
{
    std::vector<int> v1{0, 1, 2};
    std::vector<int> v2{2, 1, 0};
    std::vector<bool> v3(v1.size());

    std::cout << "negating a binary_function:\n";
    std::transform(v1.begin(), v1.end(), v2.begin(), v3.begin(),
                   std::not2(old_same()));

    std::cout << std::boolalpha;
    for (std::size_t i = 0; i < v1.size(); ++i)
        std::cout << v1[i] << ' ' << v2[i] << ' ' << v3[i] << '\n';

    std::cout << "negating a standard functor:\n";
    std::transform(v1.begin(), v1.end(), v2.begin(), v3.begin(),
                   std::not2(std::equal_to<int>()));

    for (std::size_t i = 0; i < v1.size(); ++i)
        std::cout << v1[i] << ' ' << v2[i] << ' ' << v3[i] << '\n';

    std::cout << "negating a std::function:\n";
    std::transform(v1.begin(), v1.end(), v2.begin(), v3.begin(),
                   std::not2(std::function<bool(int,int)>(new_same())));

    for (std::size_t i = 0; i < v1.size(); ++i)
        std::cout << v1[i] << ' ' << v2[i] << ' ' << v3[i] << '\n';

    std::cout << "negating a std::reference_wrapper:\n";
    std::transform(v1.begin(), v1.end(), v2.begin(), v3.begin(),
                   std::not2(std::ref(same_fn)));

    for (std::size_t i = 0; i < v1.size(); ++i)
        std::cout << v1[i] << ' ' << v2[i] << ' ' << v3[i] << '\n';

}

输出：

negating a binary_function:
0 2 true
1 1 false
2 0 true
negating a standard functor:
0 2 true
1 1 false
2 0 true
negating a std::function:
0 2 true
1 1 false
2 0 true
negating a std::reference_wrapper:
0 2 true
1 1 false
2 0 true

参阅

not_fn (C++17) | 创建返回其保有的函数对象的结果之补的函数对象 (函数模板)
binary_negate (C++17 中弃用)(C++20 中移除) | 包装器函数对象，返回所持有的二元谓词的补 (类模板)
function (C++11) | 包装具有指定函数调用签名的任意可复制构造类型的可调用对象 (类模板)
not1 (C++17 中弃用)(C++20 中移除) | 构造定制的 std::unary_negate 对象 (函数模板)
ptr_fun (C++11 中弃用)(C++17 中移除) | 从函数指针创建与适配器兼容的函数对象包装器 (函数模板)
binary_function (C++11 中弃用)(C++17 中移除) | 与适配器兼容的二元函数基类 (类模板)


std::not_equal_to

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct not_equal_to; | (C++14 前)
template< class T = void > struct not_equal_to; | (C++14 起)

进行比较的函数对象。除非特化，调用类型 T 上的 operator!= 。

特化

标准库提供n std::not_equal_to 在不指定 T 时的特化，令参数类型和返回类型留待推导。

not_equal_to<void>
(C++14)
 实现 x != y 并推导参数和返回类型的函数对象
(类模板特化)
(C++14 起)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | bool
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, bool> 获得。

 (C++11 前)

成员函数

operator()
 检查参数是否不相等
(公开成员函数)

std::not_equal_to::operator()

bool operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr bool operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

检查 lhs 是否不等于 rhs 。

参数

lhs, rhs - 要比较的值

返回值

若 lhs != rhs 则为 true ，否则为 false 。

异常

可能抛出实现定义的异常。

可能的实现

constexpr bool operator()(const T &lhs, const T &rhs) const
{
    return lhs != rhs;
}


std::not_equal_to<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class not_equal_to<void>; | (C++14 起)

std::not_equal_to <> 是拥有待推导参数和返回类型的 std::not_equal_to 特化。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 测试二个参数是否不比较相等
(公开成员函数)

std::not_equal_to<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) != std::forward <U>(rhs));

返回 lhs 与 rhs 间不等比较的结果。

参数

lhs, rhs - 要比较的值

返回值

lhs != rhs 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

本节未完成
原因：暂无示例


std::not_fn

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class F> /*unspecified*/ not_fn( F&& f ); | (C++17 起) (C++20 前)
template< class F> constexpr /*unspecified*/ not_fn( F&& f ); | (C++20 起)

构造一个转发调用包装器，返回其所保有的可调用对象的逻辑非。

参数

f - 构造包装器所保有的可调用 (Callable) 对象的来源对象
类型要求
-
std::decay_t<F> 必须满足可调用 (Callable) 和 可移动构造 (MoveConstructible) 的要求。
-
要求 std::is_constructible_v < std::decay_t <F>, F> 为 true

返回值

未指定类型 T 的函数对象。它拥有下列成员：

std::not_fn 返回类型

成员对象

std::not_fn 的返回类型保有一个 std::decay_t <F> 类型的成员对象。

构造函数

(1)
explicit T(F&& f); // 仅用于阐释
 (C++17 起)
(C++20 前)
explicit constexpr T(F&& f); // 仅用于阐释
 (C++20 起)
T(T&& f) = default;
T(const T& f) = default;
 (2)
1) 构造函数从 std::forward <F>(f) 直接非列表初始化成员对象（类型为 std::decay_t <F> ）。抛出任何所选构造函数所抛的异常
2) 因为要求 std::decay_t <F> 可移动构造 (MoveConstructible) ，故返回的调用包装器始终为可移动构造 (MoveConstructible) ，并且若 std::decay_t <F> 为可复制构造 (CopyConstructible) ，则为可复制构造 (CopyConstructible) 。

成员函数 operator()

(1)
template<class... Args> auto operator()(Args&&... args) &

-> decltype(
! std::declval <std::invoke_result_t< std::decay_t <F>&, Args...>>());
template<class... Args> auto operator()(Args&&... args) const&
-> decltype(

! std::declval <std::invoke_result_t< std::decay_t <F> const&, Args...>>());
 (C++17 起)
(C++20 前)
template<class... Args> constexpr auto operator()(Args&&... args) &

noexcept(/*see below*/)
-> decltype(
! std::declval <std::invoke_result_t< std::decay_t <F>&, Args...>>());
template<class... Args> constexpr auto operator()(Args&&... args) const&
noexcept(/*see below*/)
-> decltype(

! std::declval <std::invoke_result_t< std::decay_t <F> const&, Args...>>());
 (C++20 起)
(2)
template<class... Args> auto operator()(Args&&... args) &&

-> decltype(
! std::declval <std::invoke_result_t< std::decay_t <F>, Args...>>());
template<class... Args> auto operator()(Args&&... args) const&&
-> decltype(

! std::declval <std::invoke_result_t< std::decay_t <F> const, Args...>>());
 (C++17 起)
(C++20 前)
template<class... Args> constexpr auto operator()(Args&&... args) &&

noexcept(/*see below*/)
-> decltype(
! std::declval <std::invoke_result_t< std::decay_t <F>, Args...>>());
template<class... Args> constexpr auto operator()(Args&&... args) const&&
noexcept(/*see below*/)
-> decltype(

! std::declval <std::invoke_result_t< std::decay_t <F> const, Args...>>());
 (C++20 起)
1) 等价于 return ! std::invoke (fd, std::forward <Args>(args)...) 2) 等价于 return ! std::invoke (std::move(fd), std::forward <Args>(args)...) | (C++17 起) (C++20 前)
1) 表达式等价于 ! std::invoke (fd, std::forward <Args>(args)...) 2) 表达式等价于 ! std::invoke (std::move(fd), std::forward <Args>(args)...) | (C++20 起)

其中 fd 是 std::decay_t<F> 类型的成员对象

异常

不抛出异常，除非 fd 的构造抛出异常。

可能的实现

namespace detail {
    template<class F>
    struct not_fn_t {
        F f;
        template<class... Args>
        constexpr auto operator()(Args&&... args) &
            noexcept(noexcept(!std::invoke(f, std::forward<Args>(args)...)))
            -> decltype(!std::invoke(f, std::forward<Args>(args)...))
        {
            return !std::invoke(f, std::forward<Args>(args)...);
        }

        template<class... Args>
        constexpr auto operator()(Args&&... args) const&
            noexcept(noexcept(!std::invoke(f, std::forward<Args>(args)...)))
            -> decltype(!std::invoke(f, std::forward<Args>(args)...))
        {
            return !std::invoke(f, std::forward<Args>(args)...);
        }

        template<class... Args>
        constexpr auto operator()(Args&&... args) &&
            noexcept(noexcept(!std::invoke(std::move(f), std::forward<Args>(args)...)))
            -> decltype(!std::invoke(std::move(f), std::forward<Args>(args)...))
        {
            return !std::invoke(std::move(f), std::forward<Args>(args)...);
        }

        template<class... Args>
        constexpr auto operator()(Args&&... args) const&&
            noexcept(noexcept(!std::invoke(std::move(f), std::forward<Args>(args)...)))
            -> decltype(!std::invoke(std::move(f), std::forward<Args>(args)...))
        {
            return !std::invoke(std::move(f), std::forward<Args>(args)...);
        }
    };
}

template<class F>
constexpr detail::not_fn_t<std::decay_t<F>> not_fn(F&& f)
{
    return { std::forward<F>(f) };
}

注解

not_fn 的目的是取代 C++03 时代的取反器 std::not1 及 std::not2 。

示例

本节未完成
原因：暂无示例

参阅

not1 (C++17 中弃用)(C++20 中移除) | 构造定制的 std::unary_negate 对象 (函数模板)
not2 (C++17 中弃用)(C++20 中移除) | 构造定制的 std::binary_negate 对象 (函数模板)


std::placeholders::_1, std::placeholders::_2, ..., std::placeholders::_N

< cpp‎ | utility‎ | functional
定义于头文件 <functional>
/*see below*/ _1;

/*see below*/ _2;
.
.

/*see below*/ _N;

std::placeholders 命名空间含有占位对象 [_1, . . . _N] ，其中 N 是实现定义的最大数字。

于 std::bind 表达式用作参数时，占位符对象被存储于生成的函数对象，而以未绑定参数调用函数对象时，每个占位符 _N 被对应的第 N 个未绑定参数替换。

每个占位符如同以 extern /*unspecified*/ _1; 声明。 | (C++17 前)
鼓励实现如同以 inline constexpr /*unspecified*/ _1; 声明占位符，尽管标准仍然允许以 extern /*unspecified*/ _1; 声明它们。 | (C++17 起)

占位符对象的类型可默认构造 (DefaultConstructible) 且可复制构造 (CopyConstructible) ，其默认复制/移动构造函数不抛异常，且对于任何占位符 _N ，类型 std::is_placeholder <decltype(_N)> 有定义且从 std::integral_constant <int, N> 导出。

示例

下列代码展示以占位符参数创建函数对象。

#include <functional>
#include <string>
#include <iostream>

void goodbye(const std::string& s)
{
    std::cout << "Goodbye " << s << '\n';
}

class Object {
public:
    void hello(const std::string& s)
    {
        std::cout << "Hello " << s << '\n';
    }
};

int main(int argc, char* argv[])
{
    typedef std::function<void(const std::string&)> ExampleFunction;
    Object instance;
    std::string str("World");
    ExampleFunction f = std::bind(&Object::hello, &instance,
                                  std::placeholders::_1);

    // 等价于 instance.hello(str)
    f(str);
    f = std::bind(&goodbye, std::placeholders::_1);

    // 等价于 goodbye(str)
    f(str);
    return 0;
}

输出：

Hello World
Goodbye World

参阅

bind (C++11) | 绑定一或多个实参到函数对象 (函数模板)
is_placeholder (C++11) | 表明一个对象是标准占位符，或者可以用作标准占位符 (类模板)
ignore | 用 tie 解包 tuple 时用来跳过元素的占位符 (常量)


std::plus

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > struct plus; | (C++14 前)
template< class T = void > struct plus; | (C++14 起)

进行加法的函数对象。等效地调用 T 类型的二个实例上的 operator+ 。

特化

标准库在不指定 T 时提供 std::plus 的特化，这令参数类型和返回类型需要被推导。

plus<void>
(C++14)
 实现 x + y 的函数对象，推导参数及返回类型
(类模板特化)
(C++14 起)

成员类型

类型 | 定义
result_type (C++17 中弃用)(C++20 中移除) | T
first_argument_type (C++17 中弃用)(C++20 中移除) | T
second_argument_type (C++17 中弃用)(C++20 中移除) | T

这些成员类型由公开继承 std::binary_function <T, T, T> 获得。

 (C++11 前)

成员函数

operator()
 返回两个实参的和
(公开成员函数)

std::plus::operator()

T operator()( const T& lhs, const T& rhs ) const; | (C++14 前)
constexpr T operator()( const T& lhs, const T& rhs ) const; | (C++14 起)

返回 lhs 与 rhs 的和。

参数

lhs, rhs - 要求和的值

返回值

lhs + rhs 的结果。

异常

可能抛出实现定义的异常。

可能的实现

constexpr T operator()(const T &lhs, const T &rhs) const
{
    return lhs + rhs;
}


std::plus<void>

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template<> class plus<void>; | (C++14 起)

std::plus <> 是推导参数和返回类型的 std::plus 特化。

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 返回二个参数的和
(公开成员函数)

std::plus<>::operator()

template< class T, class U>

constexpr auto operator()( T&& lhs, U&& rhs ) const

-> decltype( std::forward <T>(lhs) + std::forward <U>(rhs));

返回 lhs 与 rhs 的和。

参数

lhs, rhs - 要求和的值

返回值

lhs + rhs 的结果。

注意

成员类型 is_transparent 指示调用方，此函数对象是一个通透函数对象：它接受任意类型的参数并使用完美转发，这在将函数对象在多种语境中，或以右值参数使用时，避免不需要的复制和转换。特别是，诸如 std::set::find 和 std::set::lower_bound 的模板函数在其 Compare 类型上使用此类型。

示例

#include <functional>
#include <iostream>

int main()
{
    std::string a = "Hello ";
    const char* b = "world";
    std::cout << std::plus<>{}(a, b) << '\n';
}

输出：

Hello world


std::pointer_to_binary_function

< cpp‎ | utility‎ | functional
template< class Arg1, class Arg2, class Result > class pointer_to_binary_function : public std::binary_function <Arg1, Arg2, Result>; | (C++11 中弃用) (C++17 中移除)

std::pointer_to_binary_function 是表现为环绕二元函数的包装器的函数对象。

成员函数

(构造函数) | 以提供的函数构造新的 pointer_to_binary_function 对象 (公开成员函数)
operator() | 调用被存储的函数 (公开成员函数)

std::pointer_to_binary_function::pointer_to_binary_function

explicit pointer_to_binary_function( Result (*f)(Arg1,Arg2) );

构造 pointer_to_binary_function 函数对象，存储函数 f 。

参数

f - 要存储的指向函数指针

std::pointer_to_binary_function::operator()

Result operator()( Arg1 x1, Arg2 x2 ) const;

调用被存储的函数。

参数

x1, x2 - 传递给函数的参数

返回值

被调用函数的返回值。

参阅

pointer_to_unary_function (C++11 中弃用)(C++17 中移除) | 适配器兼容的包装，用于包装一元函数的指针 (类模板)
ptr_fun (C++11 中弃用)(C++17 中移除) | 从函数指针创建与适配器兼容的函数对象包装器 (函数模板)


std::pointer_to_unary_function

< cpp‎ | utility‎ | functional
template< class Arg, class Result > class pointer_to_unary_function : public std::unary_function <Arg, Result>; | (C++11 中弃用) (C++17 中移除)

std::pointer_to_unary_function 是表现为环绕一元函数的包装器的函数对象。

成员函数

(构造函数) | 以提供的函数构造 pointer_to_unary_function 对象 (公开成员函数)
operator() | 调用存储的函数 (公开成员函数)

std::pointer_to_unary_function::pointer_to_unary_function

explicit pointer_to_unary_function( Result (*f)(Arg) );

构造 pointer_to_unary_function 函数对象，存储函数 f 。

参数

f - 要存储的指向函数指针

std::pointer_to_unary_function::operator()

Result operator()( Arg x ) const;

调用存储的函数。

参数

x - 传递给函数的参数

返回值

被调用函数的返回值。

参阅

pointer_to_binary_function (C++11 中弃用)(C++17 中移除) | 适配器兼容的包装，用于包装二元函数的指针 (类模板)
ptr_fun (C++11 中弃用)(C++17 中移除) | 从函数指针创建与适配器兼容的函数对象包装器 (函数模板)


std::ptr_fun

< cpp‎ | utility‎ | functional
定义于头文件 <functional>
template< class Arg, class Result >

std::pointer_to_unary_function<Arg,Result>

ptr_fun( Result (*f)(Arg) );
 (1) (C++11 中弃用)
(C++17 中移除)
template< class Arg1, class Arg2, class Result >

std::pointer_to_binary_function<Arg1,Arg2,Result>

ptr_fun( Result (*f)(Arg1, Arg2) );
 (2) (C++11 中弃用)
(C++17 中移除)

创建函数包装器对象（ std::pointer_to_unary_function 或 std::pointer_to_binary_function ），从模板实参推导目标类型。

1) 等效地调用 std::pointer_to_unary_function<Arg,Result>(f) 。
2) 等效地调用 std::pointer_to_binary_function<Arg1,Arg2,Result>(f) 。

此函数与关联类型从 C++11 起被弃用，因为使用更通用的 std::function 和 std::ref 更好，它们都可以从简单函数创建与适配器兼容的函数对象。

参数

f - 为之创建包装的指向函数指针

返回值

包装 f 的函数对象。

异常

可能抛出实现定义的异常。

示例

#include <string>
#include <iostream>
#include <algorithm>
#include <functional>

bool isvowel(char c)
{
    return std::string("aeoiuAEIOU").find(c) != std::string::npos;
}

int main()
{
    std::string s = "Hello, world!";
    std::copy_if(s.begin(), s.end(), std::ostreambuf_iterator<char>(std::cout),
                 std::not1(std::ptr_fun(isvowel)));
// C++11 替用方案：
//               std::not1(std::cref(isvowel)));
//               std::not1(std::function<bool(char)>(isvowel)));
// C++17 替用方案：
//               std::not_fn(isvowel));

}

输出：

Hll, wrld!


std::ranges::equal_to

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
struct equal_to; | (C++20 起)

进行比较的函数对象。从参数推导函数调用运算符的形参类型（但非返回类型）。

实现定义的指针上的严格全序

若参数间的 = 运算符调用指针的内建比较运算符，则函数调用运算符产生实现定义的指针上的严格全序，即使内建的 = 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 <、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void 时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 检查参数是否相等
(公开成员函数)

std::ranges::equal_to::operator()

template< class T, class U >

requires std::equality_comparable_with<T, U> // 有不同的语义要求

constexpr bool operator()(T&& t, U&& u) const;

比较 t 与 u ，等价于 return std::forward <T>(t) == std::forward <U>(u); ，除非该表达式解析成调用比较指针的内建 operator== 。

当函数调用不调用内建的比较指针的运算符时，若 std::equality_comparable_with<T, U> 未得到满足则行为未定义。

调用比较类型 P 指针的内建运算符时，结果以如下方式确定：

  • 若第一参数的（可能为转换后的）值与第二参数的（可能为转换后的）值之一在 P 类型的所有指针值上的实现定义严格全序中前趋另一者，则返回 false 。此严格全序与内建运算符 < 、 > 、 <= 及 >= 所施加的偏序一致。
  • 否则（无一前趋另一者），返回 true 。

行为未定义，除非从 T 与 U 到 P 的转换序列均保持相等性（见下方）。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

注解

不同于 std::equal_to ， std::ranges::equal_to 要求 == 与 != 均合法（经由 equality_comparable_with 约束）。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3530 | C++20 | 在比较指针时放松了语法检查 | 仅放松语义要求

参阅

equal_to
 实现 x == y 的函数对象
(类模板)


std::ranges::greater

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
struct greater; | (C++20 起)

进行比较的函数对象。从实参推导函数调用运算符的形参类型（但非返回类型）。

实现定义的指针上的严格全序

若参数间的 < 运算符调用指针的内建比较运算符，则函数调用运算符产生实现定义的指针上的严格全序，即使内建的 < 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 <、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void 时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 检查第一参数是否大于第二参数
(公开成员函数)

std::ranges::greater::operator()

template< class T, class U >

requires std::totally_ordered_with<T, U> // 有不同的语义要求

constexpr bool operator()(T&& t, U&& u) const;

比较 t 与 u 。等价于 return ranges::less{}( std::forward <U>(u), std::forward <T>(t)); 。

注解

不同于 std::greater ， std::ranges::greater 要求全部六个比较运算符 < 、 <= 、 > 、 >= 、 == 及 != 合法（经由 totally_ordered_with 约束），并且完全以 std::ranges::less 定义。然而实现有直接使用 operator> 的自由，因为那些概念要求比较运算符的结果一致。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3530 | C++20 | 在比较指针时放松了语法检查 | 仅放松语义要求

参阅

greater
 实现 x > y 的函数对象
(类模板)


std::ranges::greater_equal

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
struct greater_equal; | (C++20 起)

进行比较的函数对象。从实参推导函数调用运算符的形参类型（但非返回类型）。

实现定义的指针上的严格全序

若参数间的 < 运算符调用指针的内建比较运算符，则函数调用运算符产生实现定义的指针上的严格全序，即使内建的 < 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 <、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void 时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 检查第一参数是否大于或等于第二个
(公开成员函数)

std::ranges::greater_equal::operator()

template< class T, class U >

requires std::totally_ordered_with<T, U> // 有不同的语义要求

constexpr bool operator()(T&& t, U&& u) const;

比较 t 与 u 。等价于 return !ranges::less{}( std::forward <T>(t), std::forward <U>(u)); 。

注解

不同于 std::greater_equal ， std::ranges::greater_equal 要求全部六个比较运算符 < 、 <= 、 > 、 >= 、 == 及 != 合法（经由 totally_ordered_with 约束），并且完全以 std::ranges::less 定义。然而实现有直接使用 operator>= 的自由，因为那些概念要求比较运算符的结果一致。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3530 | C++20 | 在比较指针时放松了语法检查 | 仅放松语义要求

参阅

greater_equal
 实现 x >= y 的函数对象
(类模板)


std::ranges::less

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
struct less; | (C++20 起)

进行比较的函数对象。从实参推导函数调用运算符的形参类型（但非返回类型）。

实现定义的指针上的严格全序

若参数间的 < 运算符调用指针的内建比较运算符，则函数调用运算符产生实现定义的指针上的严格全序，即使内建的 < 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 <、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void 时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 检查第一参数是否小于第二参数
(公开成员函数)

std::ranges::less::operator()

template< class T, class U >

requires std::totally_ordered_with<T, U> // 有不同的语义要求

constexpr bool operator()(T&& t, U&& u) const;

比较 t 与 u ，等价于 return std::forward <T>(t) < std::forward <U>(u); ，除非该表达式解析成调用比较指针的内建 operator< 。

当函数调用不调用内建的比较指针的运算符时，若 std::totally_ordered_with<T, U> 未得到满足则行为未定义。

调用可能会使用比较 P 类型指针的内建运算符时，转而以如下方式确定结果：

  • 若在 P 类型的所有指针值上的实现定义严格全序中，（可能为转换后的）第一参数的值前趋（可能为转换后的）第二参数的值，则返回 true 。此严格全序与内建运算符 < 、 > 、 <= 及 >= 所施加的偏序一致。
  • 否则返回 false 。

行为未定义，除非从 T 与 U 到 P 的转换序列均保持相等性（见下方）。

相等性保持

若表达式对给定的相等输入产生相等输出，则它保持相等性。

  • 表达式的输入由其操作数组成。
  • 表达式的输出由其结果和表达式所修改的所有操作数（若存在）组成。

在标准概念的规范中，操作数定义为仅包含下列内容的最大子表达式：

  • 标识表达式，及
  • 对 std::move 、 std::forward 与 std::declval 的调用。

每个操作数的 cv 限定与值类别，是通过假设每个模板类型形参代表一个 cv 无限定的非数组对象类型确定的。

进一步要求每个要求保持相等性的表达式都稳定：这种表达式带相同输入对象的二次求值必须拥有相等的输出，而无任何对这些输入对象的显式中间修改。

注解

不同于 std::less ， std::ranges::less 要求全部六个比较运算符 < 、 <= 、 > 、 >= 、 == 及 != 合法（经由 totally_ordered_with 约束）。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3530 | C++20 | 在比较指针时放松了语法检查 | 仅放松语义要求

参阅

less
 实现 x < y 的函数对象
(类模板)


std::ranges::less_equal

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
struct less_equal; | (C++20 起)

进行比较的函数对象。从实参推导函数调用运算符的形参类型（但非返回类型）。

实现定义的指针上的严格全序

若参数间的 < 运算符调用指针的内建比较运算符，则函数调用运算符产生实现定义的指针上的严格全序，即使内建的 < 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 <、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void 时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 检查第一参数是否小于或等于第二个
(公开成员函数)

std::ranges::less_equal::operator()

template< class T, class U >

requires std::totally_ordered_with<T, U> // 有不同的语义要求

constexpr bool operator()(T&& t, U&& u) const;

比较 t 与 u 。等价于 return !ranges::less{}( std::forward <U>(u), std::forward <T>(t)); 。

注解

不同于 std::less_equal ， std::ranges::less_equal 要求全部六个比较运算符 < 、 <= 、 > 、 >= 、 == 及 != 合法（经由 totally_ordered_with 约束），并且完全以 std::ranges::less 定义。然而实现有直接使用 operator<= 的自由，因为那些概念要求比较运算符的结果一致。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3530 | C++20 | 在比较指针时放松了语法检查 | 仅放松语义要求

参阅

less_equal
 实现 x <= y 的函数对象
(类模板)


std::ranges::not_equal_to

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
struct not_equal_to; | (C++20 起)

进行比较的函数对象。从实参推导函数调用运算符的形参类型（但非返回类型）。

实现定义的指针上的严格全序

若参数间的 = 运算符调用指针的内建比较运算符，则函数调用运算符产生实现定义的指针上的严格全序，即使内建的 = 运算符不如此。

实现定义的严格全序与比较运算符（ <=>、 <、 >、 <= 及 >= ）所施加的偏序一致，并在下列标准函数对象间一致：

  • std::less、 std::greater、 std::less_equal 及 std::greater_equal ，当模板实参为指针类型或 void 时
  • std::ranges::equal_to、 std::ranges::not_equal_to、 std::ranges::less、 std::ranges::greater、 std::ranges::less_equal、 std::ranges::greater_equal 及 std::compare_three_way

成员类型

成员类型 | 定义
is_transparent | /* 未指定 */

成员函数

operator()
 检查参数是否不相等
(公开成员函数)

std::ranges::not_equal_to::operator()

template< class T, class U >

requires std::equality_comparable_with<T, U> // 有不同的语义要求

constexpr bool operator()(T&& t, U&& u) const;

比较 t 与 u 。等价于 return !ranges::equal_to{}( std::forward <T>(t), std::forward <U>(u)); 。

注解

不同于 std::not_equal_to ， std::ranges::not_equal_to 要求 == 与 != 均合法（经由 equality_comparable_with 约束），并且完全以 std::ranges::equal_to 定义。然而，实现有直接使用 operator!= 的自由，因为那些概念要求 == 与 != 的结果一致。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3530 | C++20 | 在比较指针时放松了语法检查 | 仅放松语义要求

参阅

not_equal_to
 实现 x != y 的函数对象
(类模板)


std::ref, std::cref

< cpp‎ | utility‎ | functional
定义于头文件 <functional>
(1)
template< class T >
std::reference_wrapper <T> ref( T& t ) noexcept;
 (C++11 起)
(C++20 前)
template< class T >
constexpr std::reference_wrapper <T> ref( T& t ) noexcept;
 (C++20 起)
(2)
template< class T >

std::reference_wrapper <T>

ref( std::reference_wrapper <T> t ) noexcept;
 (C++11 起)
(C++20 前)
template< class T >

constexpr std::reference_wrapper <T>

ref( std::reference_wrapper <T> t ) noexcept;
 (C++20 起)
template< class T >
void ref( const T&& ) = delete;
 (3) (C++11 起)
(4)
template< class T >
std::reference_wrapper <const T> cref( const T& t ) noexcept;
 (C++11 起)
(C++20 前)
template< class T >
constexpr std::reference_wrapper <const T> cref( const T& t ) noexcept;
 (C++20 起)
(5)
template< class T >

std::reference_wrapper <const T>

cref( std::reference_wrapper <T> t ) noexcept;
 (C++11 起)
(C++20 前)
template< class T >

constexpr std::reference_wrapper <const T>

cref( std::reference_wrapper <T> t ) noexcept;
 (C++20 起)
template< class T >
void cref( const T&& ) = delete;
 (6) (C++11 起)

函数模板 ref 与 cref 是生成 std::reference_wrapper 类型对象的帮助函数，它们用模板实参推导确定结果的模板实参。

T 可为不完整类型。

 (C++20 起)

参数

t - 需要被包装的到对象的左值引用，或 std::reference_wrapper 的实例

返回值

1) std::reference_wrapper <T>(t)
2) t
4) std::reference_wrapper <const T>(t)
5) t
3,6) 右值引用包装器被删除。

示例

#include <functional>
#include <iostream>

void f(int& n1, int& n2, const int& n3)
{
    std::cout << "In function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
    ++n1; // 增加存储于函数对象的 n1 副本
    ++n2; // 增加 main() 的 n2
    // ++n3; // 编译错误
}

int main()
{
    int n1 = 1, n2 = 2, n3 = 3;
    std::function<void()> bound_f = std::bind(f, n1, std::ref(n2), std::cref(n3));
    n1 = 10;
    n2 = 11;
    n3 = 12;
    std::cout << "Before function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
    bound_f();
    std::cout << "After function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
}

输出：

Before function: 10 11 12
In function: 1 11 12
After function: 10 12 12

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3146 | C++11 | 解包装重载有时导致错误 | 使之始终合法

参阅

reference_wrapper
(C++11)
 可复制构造 (CopyConstructible) 且可复制赋值 (CopyAssignable) 的引用包装器
(类模板)


std::reference_wrapper

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class T > class reference_wrapper; | (C++11 起)

std::reference_wrapper 是包装引用于可复制、可赋值对象的类模板。它常用作将引用存储入无法正常保有引用的标准容器（类似 std::vector ）的机制。

特别是， std::reference_wrapper 是围绕到类型 T 的对象引用或函数引用的可复制构造 (CopyConstructible) 且可复制赋值 (CopyAssignable) 的包装器。 std::reference_wrapper 的实例是对象（它们可被复制或存储于容器），但它们能隐式转换成 T& ，故能以之为以引用接收底层类型的函数的参数。

若存储的引用可调用 (Callable) ，则可以相同参数调用 std::reference_wrapper 。

辅助函数 std::ref 与 std::cref 常用于生成 std::reference_wrapper 对象。

std::reference_wrapper 亦用于按引用传递对象给 std::bind 或 std::thread 的构造函数。

保证 std::reference_wrapper 为可平凡复制 (TriviallyCopyable) 。

 (C++17 起)

T 可为不完整类型。

 (C++20 起)

成员类型

类型 | 定义
type | T
result_type(C++17 中弃用)(C++20 中移除) | 若 T 为函数则为 T 的返回类型。否则不定义。
argument_type(C++17 中弃用)(C++20 中移除) | 1) 若 T 为接受一个 A1 类型参数的函数或指向函数指针，则 argument_type 为 A1 。 2) 若 T 是不接收参数的指向类 T0 成员函数的指针，则 argument_type 为 T0* ，可能有 cv 限定 3) 若 T 是拥有成员类型 T::argument_type 的类类型，则 argument_type 为其别名
first_argument_type(C++17 中弃用)(C++20 中移除) | 1) 若 T 是接收二个 A1 与 A2 类型参数的函数或指向函数指针，则 first_argument_type 为 A1 。 2) 若 T 是接收一个参数的指向 T0 成员函数指针，则 first_argument_type 为 T0* ，可能有 cv 限定 3) 若 T 是拥有成员类型 T::first_argument_type 的类类型，则 first_argument_type 为其别名
second_argument_type(C++17 中弃用)(C++20 中移除) | 1) 若 T 是接收二个 A1 与 A2 类型参数的函数或指向函数指针，则 second_argument_type 为 A2 。 2) 若 T 是接收一个 A1 类型参数的指向 T0 成员函数指针，则 second_argument_type 为 A1 ，可有 cv 限定 3) 若 T 是拥有成员类型 T::second_argument_type 的类类型，则 second_argument_type 为其别名

成员函数

(构造函数) | 存储引用于新的 std::reference_wrapper 对象 (公开成员函数)
operator= | 重绑定 std::reference_wrapper (公开成员函数)
getoperator T& | 访问存储的引用 (公开成员函数)
operator() | 调用其所存储的函数 (公开成员函数)

推导指引 (C++17 起)

可能的实现

namespace detail {
template <class T> T& FUN(T& t) noexcept { return t; }
template <class T> void FUN(T&&) = delete;
}

template <class T>
class reference_wrapper {
public:
  // 类型
  using type = T;

  // 构造/复制/销毁
  template <class U, class = decltype(
    detail::FUN<T>(std::declval<U>()),
    std::enable_if_t<!std::is_same_v<reference_wrapper, std::remove_cvref_t<U>>>()
  )>
  constexpr reference_wrapper(U&& u) noexcept(noexcept(detail::FUN<T>(std::forward<U>(u))))
    : _ptr(std::addressof(detail::FUN<T>(std::forward<U>(u)))) {}
  reference_wrapper(const reference_wrapper&) noexcept = default;

  // 赋值
  reference_wrapper& operator=(const reference_wrapper& x) noexcept = default;

  // 访问
  constexpr operator T& () const noexcept { return *_ptr; }
  constexpr T& get() const noexcept { return *_ptr; }

  template< class... ArgTypes >
  constexpr std::invoke_result_t<T&, ArgTypes...>
    operator() ( ArgTypes&&... args ) const {
    return std::invoke(get(), std::forward<ArgTypes>(args)...);
  }

private:
  T* _ptr;
};

// 推导指引
template<class T>
reference_wrapper(T&) -> reference_wrapper<T>;

示例

演示将 reference_wrapper 作为引用的容器使用，这令用多重下标访问同一容器可行

#include <algorithm>
#include <list>
#include <vector>
#include <iostream>
#include <numeric>
#include <random>
#include <functional>

int main()
{
    std::list<int> l(10);
    std::iota(l.begin(), l.end(), -4);

    std::vector<std::reference_wrapper<int>> v(l.begin(), l.end());
    // 不能在 list 上用 shuffle （要求随机访问），但能在 vector 上使用它
    std::shuffle(v.begin(), v.end(), std::mt19937{std::random_device{}()});

    std::cout << "Contents of the list: ";
    for (int n : l) std::cout << n << ' '; std::cout << '\n';

    std::cout << "Contents of the list, as seen through a shuffled vector: ";
    for (int i : v) std::cout << i << ' '; std::cout << '\n';

    std::cout << "Doubling the values in the initial list...\n";
    for (int& i : l) {
        i *= 2;
    }

    std::cout << "Contents of the list, as seen through a shuffled vector: ";
    for (int i : v) std::cout << i << ' '; std::cout << '\n';
}

可能的输出：

Contents of the list: -4 -3 -2 -1 0 1 2 3 4 5
Contents of the list, as seen through a shuffled vector: -1 2 -2 1 5 0 3 -3 -4 4
Doubling the values in the initial list...
Contents of the list, as seen through a shuffled vector: -2 4 -4 2 10 0 6 -6 -8 8

参阅

refcref (C++11)(C++11) | 创建具有从其实参推导的类型的 std::reference_wrapper (函数模板)
bind (C++11) | 绑定一或多个实参到函数对象 (函数模板)


std::reference_wrapper 的推导指引

< cpp‎ | utility‎ | functional‎ | reference wrapper
定义于头文件 <functional> |
template<typename T> reference_wrapper(T&) -> reference_wrapper<T>; | (C++17 起)

为 std::reference_wrapper 提供推导指引以支持单独类模板形参的推导。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2981 | C++17 | 提供了来自 reference_wrapper<T> 的冗余推导指引 | 已移除
LWG 2993 | C++17 | 移除了用于类模板实参推导的缺陷决议 | 添加推导指引以补偿


std::reference_wrapper<T>::get, std::reference_wrapper<T>::operator T&

< cpp‎ | utility‎ | functional‎ | reference wrapper
operator T& () const noexcept; | (C++11 起) (C++20 前)
constexpr operator T& () const noexcept; | (C++20 起)
T& get() const noexcept; | (C++11 起) (C++20 前)
constexpr T& get() const noexcept; | (C++20 起)

返回存储的引用。

参数

（无）

返回值

存储的引用。

参阅

operator()
 调用其所存储的函数
(公开成员函数)


std::reference_wrapper<T>::operator()

< cpp‎ | utility‎ | functional‎ | reference wrapper
template< class... ArgTypes >

typename std::result_of <T&(ArgTypes&&...)>::type

operator() ( ArgTypes&&... args ) const;
 (C++11 起)
(C++17 前)
template< class... ArgTypes >

std::invoke_result_t<T&, ArgTypes...>

operator() ( ArgTypes&&... args ) const;
 (C++17 起)
(C++20 前)
template< class... ArgTypes >

constexpr std::invoke_result_t<T&, ArgTypes...>

operator() ( ArgTypes&&... args ) const;
 (C++20 起)

调用存储其引用的可调用 (Callable) 对象。仅若存储的引用指向可调用 (Callable) 对象，此函数才可用。

T 必须是完整类型。

参数

args - 传递给被调用函数的参数

返回值

被调用函数的返回值。

异常

可能抛出实现定义的异常。

示例

#include <iostream>
#include <functional>

void f1()
{
    std::cout << "reference to function called\n";
}
void f2(int n)
{
    std::cout << "bind expression called with " << n << " as the argument\n";
}

int main()
{
    std::reference_wrapper<void()> ref1 = std::ref(f1);
    ref1();

    auto b = std::bind(f2, std::placeholders::_1);
    auto ref2 = std::ref(b);
    ref2(7);

    auto c = []{std::cout << "lambda function called\n"; };
    auto ref3 = std::ref(c);
    ref3();
}

输出：

reference to function called
bind expression called with 7 as the argument
lambda function called

参阅

getoperator T&
 访问存储的引用
(公开成员函数)


std::reference_wrapper<T>::operator=

< cpp‎ | utility‎ | functional‎ | reference wrapper
reference_wrapper& operator=( const reference_wrapper& other ) noexcept; | (C++11 起) (C++20 前)
constexpr reference_wrapper& operator=( const reference_wrapper& other ) noexcept; | (C++20 起)

复制赋值运算符。丢弃当前引用，并存储到 other.get() 的引用。

参数

other - 要复制的 reference_wrapper

返回值

*this


std::reference_wrapper<T>::reference_wrapper

< cpp‎ | utility‎ | functional‎ | reference wrapper
 | (1)
template< class U > reference_wrapper( U&& x ) noexcept(/*see below*/) ; |  | (C++20 前)
template< class U > constexpr reference_wrapper( U&& x ) noexcept(/*see below*/) ; |  | (C++20 起)
 | (2)
reference_wrapper( const reference_wrapper& other ) noexcept; |  | (C++20 前)
constexpr reference_wrapper( const reference_wrapper& other ) noexcept; |  | (C++20 起)

构造新的引用包装。

1) 如同用 T& t = std::forward <U>(x); 转换 x 为 T& ，然后存储到 t 的引用。此重载仅若 typename std::decay <U>::type 与 reference_wrapper 不是同一类型且表达式 FUN( std::declval <U>()) 为良式才参与重载决议，其中 FUN 指名虚构函数集
void FUN(T&) noexcept;
void FUN(T&&) = delete;
2) 复制构造函数。存储到 other.get() 的引用。

参数

x | - | 要包装的对象
other | - | 另一 reference_wrapper

异常

1)
noexcept 说明：
noexcept(noexcept(FUN( std::declval <U>())))
，其中 FUN 是以上描述中的虚构函数集。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2993 | C++11 | 被删除的 reference_wrapper(T&&) 构造函数在某些情况下干涉重载决议 | 替换成构造函数模板


std::unary_function

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template <typename ArgumentType, typename ResultType> struct unary_function; | (C++11 中弃用) (C++17 中移除)

unary_function 是用于创建拥有一个参数的函数的基类。

unary_function 不定义 operator() ；它期待导出类定义此运算符。 unary_function 只提供二个类型—— argument_type 和 result_type ——为模板形参所定义。

一些标准库函数适配器，如 std::not1 ，要求它们适配的函数对象已定义某些类型； std::not1 要求要适配的函数对象拥有名为 argument_type 的类型。从 unary_function 导出函数对象是令它们与那些适配器兼容的简易方式。

unary_function 在 C++11 中被弃用。

成员类型

类型 | 定义
argument_type | ArgumentType
result_type | ResultType

示例

#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>

struct less_than_7 : std::unary_function<int, bool>
{
    bool operator()(int i) const { return i < 7; }
};

int main()
{
    std::vector<int> v;
    for (int i = 0; i < 10; ++i) v.push_back(i);

    std::cout << std::count_if(v.begin(), v.end(), std::not1(less_than_7()));

    /* C++11 解法：
        // 用某方法转型到 std::function<bool (int)> ——即使以 lambda
        std::cout << std::count_if(v.begin(), v.end(),
            std::not1(std::function<bool (int)>([](int i){ return i < 7; }))
        );
    */
}

输出：

3

参阅

function (C++11) | 包装具有指定函数调用签名的任意可复制构造类型的可调用对象 (类模板)
ptr_fun (C++11 中弃用)(C++17 中移除) | 从函数指针创建与适配器兼容的函数对象包装器 (函数模板)
pointer_to_unary_function (C++11 中弃用)(C++17 中移除) | 适配器兼容的包装，用于包装一元函数的指针 (类模板)
binary_function (C++11 中弃用)(C++17 中移除) | 与适配器兼容的二元函数基类 (类模板)


std::unary_negate

< cpp‎ | utility‎ | functional
定义于头文件 <functional> |
template< class Predicate > struct unary_negate : public std::unary_function <Predicate::argument_type, bool>; | (C++11 前)
template< class Predicate > struct unary_negate; | (C++11 起) (C++17 中弃用) (C++20 中移除)

unary_negate 是返回其所保有的一元谓词的逻辑补的包装函数对象。

一元谓词必须定义成员类型 argument_type ，它要可转换为谓词的参数类型。从 std::ref 、 std::cref 、 std::negate 、 std::logical_not 、 std::mem_fn 、 std::function 、 std::hash 或调用 std::not1 获得的一元函数对象已定义此类型，导出自启用的 std::unary_function 的函数对象亦然。

unary_negate 简单地以辅助函数 std::not1 构造。

成员函数

类型 | 定义
argument_type | Predicate::argument_type
result_type | bool

成员函数

(构造函数) | 以提供的谓词构造新的 unary_negate 对象 (公开成员函数)
operator() | 返回调用存储的谓词结果的逻辑补 (公开成员函数)

std::unary_negate::unary_negate

explicit unary_negate( Predicate const& pred ); | (C++14 前)
explicit constexpr unary_negate( Predicate const& pred ); | (C++14 起)

以存储的谓词 pred 构造 unary_negate 函数对象。

参数

pred - 谓词函数对象

std::unary_negate::operator()

bool operator()( argument_type const& x ) const; | (C++14 前)
constexpr bool operator()( argument_type const& x ) const; | (C++14 起)

返回调用 pred(x) 结果的逻辑补。

参数

x - 传递给谓词的参数

返回值

调用 pred(x) 结果的逻辑补。

示例

#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>

struct less_than_7 : std::unary_function<int, bool>
{
    bool operator()(int i) const { return i < 7; }
};

int main()
{
    std::vector<int> v;
    for (int i = 0; i < 10; ++i) v.push_back(i);

    std::unary_negate<less_than_7> not_less_than_7((less_than_7()));

    std::cout << std::count_if(v.begin(), v.end(), not_less_than_7);

    /* C++11 解法：
        // 用 std::function<bool (int)>
        std::function<bool (int)> not_less_than_7 =
            [](int x)->bool{ return !less_than_7()(x); };

        std::cout << std::count_if(v.begin(), v.end(), not_less_than_7);
    */
}

输出：

3

参阅

binary_negate (C++17 中弃用)(C++20 中移除) | 包装器函数对象，返回所持有的二元谓词的补 (类模板)
function (C++11) | 包装具有指定函数调用签名的任意可复制构造类型的可调用对象 (类模板)
not1 (C++17 中弃用)(C++20 中移除) | 构造定制的 std::unary_negate 对象 (函数模板)
ptr_fun (C++11 中弃用)(C++17 中移除) | 从函数指针创建与适配器兼容的函数对象包装器 (函数模板)
unary_function (C++11 中弃用)(C++17 中移除) | 与适配器兼容的一元函数基类 (类模板)


std::unwrap_reference, std::unwrap_ref_decay

< cpp‎ | utility‎ | functional
定义于头文件 <type_traits> |  |
定义于头文件 <functional> |  |
template< class T > struct unwrap_reference; | (1) | (C++20 起)
template< class T > struct unwrap_ref_decay; | (2) | (C++20 起)
1) 若 T 为某类型 U 的 std::reference_wrapper <U> ，则提供指名 U& 的成员 typedef type ；否则提供指名 T 的成员 typedef type 。
2) 若 T 为某类型 U 的 std::reference_wrapper <U> ，忽略 cv 限定和引用，则提供指名 U& 的成员 typedef type ；否则提供指名 std::decay_t<T> 的成员 typedef type 。

添加此页面上描述的任何模板的特化的程序行为未定义。

成员类型

名称 | 定义
type | 1) 若 T 为 std::reference_wrapper <U> 则为 U& ；否则为 T 2) 若 std::decay_t<T> 为 std::reference_wrapper <U> 则为 U& ；否则为 std::decay_t<T>

辅助类型

template<class T> using unwrap_reference_t = typename unwrap_reference<T>::type; | (1) | (C++20 起)
template<class T> using unwrap_ref_decay_t = typename unwrap_ref_decay<T>::type; | (2) | (C++20 起)

可能的实现

template <class T>
struct unwrap_reference { using type = T; };
template <class U>
struct unwrap_reference<std::reference_wrapper<U>> { using type = U&; };

template< class T >
struct unwrap_ref_decay : std::unwrap_reference<std::decay_t<T>> {};

注解

std::unwrap_ref_decay 进行与 std::make_pair 及 std::make_tuple 所用者相同的变换。

示例

本节未完成
原因：暂无示例

参阅

reference_wrapper (C++11) | 可复制构造 (CopyConstructible) 且可复制赋值 (CopyAssignable) 的引用包装器 (类模板)
make_pair | 创建一个 pair 对象，其类型根据各实参类型定义 (函数模板)
make_tuple | 创建一个 tuple 对象，其类型根据各实参类型定义 (函数模板)


std::hash

< cpp‎ | utility
定义于头文件 <functional> |
template< class Key > struct hash; | (C++11 起)

此模板的每个特化为启用（“无污染”）或为禁用（“中毒”）。

hash 函数模板的启用的特化定义一个实现散列函数的函数对象。此函数对象的实例满足散列 (Hash) 。特别是它们定义满足下列条件的 operator() ：

  1. 接收 Key 类型的单个参数
  2. 返回表示参数散列值的 std::size_t 类型。
  3. 调用时不抛出异常。
  4. 对于二个相等的参数 k1 与 k2 ， std::hash<Key>()(k1) == std::hash<Key>()(k2) 。
  5. 对于二个相异而不相等的参数 k1 与 k2 ， std::hash<Key>()(k1) == std::hash<Key>()(k2) 的概率应非常小，接近 1.0/ std::numeric_limits < std::size_t >::max() 。

库函数提供的 hash 的所有显式和部分特化可默认构造 (DefaultConstructible) 、可复制赋值 (CopyAssignable) 、可交换 (Swappable) 且可析构 (Destructible) 。用户提供的 hash 特化亦必须满足这些要求。

无序关联容器 std::unordered_set 、 std::unordered_multiset 、 std::unordered_map 、 std::unordered_multimap 以该模板 std::hash 的特化为默认散列函数。

对于每个既非库亦非用户提供的数据类型的 Key 启用特化的函数 std::hash<Key>，特化存在且被禁用。被禁用特化不满足散列 (Hash) ，不满足函数对象 (FunctionObject) ，且下列值全为 false ：

  • std::is_default_constructible <std::hash<Key>>::value
  • std::is_copy_constructible <std::hash<Key>>::value
  • std::is_move_constructible <std::hash<Key>>::value
  • std::is_copy_assignable <std::hash<Key>>::value
  • std::is_move_assignable <std::hash<Key>>::value

换言之，它们存在但无法使用。

注解

除了上述指定的情况外，散列函数的实现方式是实现定义的。（比如， gcc 的实现）。需要注意，某些散列函数的实现过于简单，甚至是直接将对象映射至自身。这可能会造成严重的后果。换言之，这些散列函数可以用于无序关联容器，但它们不一定安全/抗碰撞。

散列函数仅要求在程序的单次执行中对同样的输入返回同样的结果；这允许避免碰撞拒绝服务攻击的加盐哈希。

没有对 C 字符串的特化。 std::hash<const char*> 产生指针值（内存地址）的散列值，它不检验任何字符数组的内容。

成员类型

成员类型 | 定义
argument_type(C++17 中弃用) | Key
result_type(C++17 中弃用) | std::size_t
 (C++20 前)

成员函数

(构造函数) | 构造散列函数对象 (公开成员函数)
operator() | 计算参数的散列值 (公开成员函数)

基本类型的标准特化

定义于头文件 <functional>
template<> struct hash<bool>;

template<> struct hash<char>;
template<> struct hash<signed char>;
template<> struct hash<unsigned char>;
template<> struct hash<char8_t>; // C++20
template<> struct hash<char16_t>;
template<> struct hash<char32_t>;
template<> struct hash<wchar_t>;
template<> struct hash<short>;
template<> struct hash<unsigned short>;
template<> struct hash<int>;
template<> struct hash<unsigned int>;
template<> struct hash<long>;
template<> struct hash<long long>;
template<> struct hash<unsigned long>;
template<> struct hash<unsigned long long>;
template<> struct hash<float>;
template<> struct hash<double>;
template<> struct hash<long double>;
template<> struct hash< std::nullptr_t >;

template< class T > struct hash<T*>;

在上述之外，标准库对所有（有作用域或无作用域）枚举类型提供特化。可以（但不要求）实现为 std::hash< std::underlying_type <Enum>::type> 。

标准库提供 std::hash 对 std::nullptr_t 和所有无 cv 限定算术类型（包含任何扩展整数类型）、所有枚举类型和所有指针类型的启用特化。

每个声明模板 std::hash 标准库头文件提供上述启用特化。这些头文件包括 <string>、 <system_error>、 <bitset>、 <memory>、 <typeindex>、 <vector>、 <thread> 、 <optional> 、 <variant>、 <string_view> (C++17 起)、 <coroutine> (C++20 起)、 <stacktrace> (C++23 起) 。

此模板的标准库特化的所有成员函数均为 noexcept ，除了 std::hash<std::optional> 、 std::hash<std::variant> 和 std::hash<std::unique_ptr> 的成员函数。

 (C++17 起)

库类型的标准特化

std::hash<std::string>std::hash<std::u8string>std::hash<std::u16string>std::hash<std::u32string>std::hash<std::wstring>std::hash<std::pmr::string>std::hash<std::pmr::u8string>std::hash<std::pmr::u16string>std::hash<std::pmr::u32string>std::hash<std::pmr::wstring> (C++11)(C++20)(C++11)(C++11)(C++11)(C++17)(C++20)(C++17)(C++17)(C++17) | string 的散列支持 (类模板特化)
std::hash<std::error_code> (C++11) | std::error_code 的散列支持 (类模板特化)
std::hash<std::bitset> (C++11) | std::bitset 的散列支持 (类模板特化)
std::hash<std::unique_ptr> (C++11) | std::unique_ptr 的散列支持 (类模板特化)
std::hash<std::shared_ptr> (C++11) | std::shared_ptr 的散列支持 (类模板特化)
std::hash<std::type_index> (C++11) | std::type_index 的散列支持 (类模板特化)
std::hash<std::vector<bool>> (C++11) | std::vector<bool> 的散列支持 (类模板特化)
std::hash<std::thread::id> (C++11) | std::thread::id 的散列支持 (类模板特化)
std::hash<std::optional> (C++17) | 特化 std::hash 算法 (类模板特化)
std::hash<std::variant> (C++17) | 特化 std::hash 算法 (类模板特化)
std::hash<std::string_view>std::hash<std::wstring_view>std::hash<std::u8string_view>std::hash<std::u16string_view>std::hash<std::u32string_view> (C++17)(C++17)(C++20)(C++17)(C++17) | string_view 的散列支持 (类模板特化)
std::hash<std::error_condition> (C++17) | std::error_condition 的哈希支持 (类模板特化)
std::hash<std::coroutine_handle> (C++20) | std::coroutine_handle 的散列支持 (类模板特化)
std::hash<std::basic_stacktrace> (C++23) | std::basic_stacktrace 的散列支持 (类模板特化)
std::hash<std::stacktrace_entry> (C++23) | std::stacktrace_entry 的散列支持 (类模板特化)

注意：对 std::pair 和标准容器类型的特化，还有组合哈希的工具函数可用于 boost.hash

示例

#include <iostream>
#include <iomanip>
#include <functional>
#include <string>
#include <unordered_set>

struct S {
    std::string first_name;
    std::string last_name;
};
bool operator==(const S& lhs, const S& rhs) {
    return lhs.first_name == rhs.first_name && lhs.last_name == rhs.last_name;
}

// 自定义散列函数能是独立函数对象：
struct MyHash
{
    std::size_t operator()(S const& s) const
    {
        std::size_t h1 = std::hash<std::string>{}(s.first_name);
        std::size_t h2 = std::hash<std::string>{}(s.last_name);
        return h1 ^ (h2 << 1); // 或使用 boost::hash_combine （见讨论）
    }
};

// std::hash 的自定义特化能注入 namespace std
namespace std
{
    template<> struct hash<S>
    {
        typedef S argument_type;
        typedef std::size_t result_type;
        result_type operator()(argument_type const& s) const
        {
            result_type const h1 ( std::hash<std::string>{}(s.first_name) );
            result_type const h2 ( std::hash<std::string>{}(s.last_name) );
            return h1 ^ (h2 << 1); // 或使用 boost::hash_combine （见讨论）
        }
    };
}

int main()
{
    std::string str = "Meet the new boss...";
    std::size_t str_hash = std::hash<std::string>{}(str);
    std::cout << "hash(" << std::quoted(str) << ") = " << str_hash << '\n';

    S obj = { "Hubert", "Farnsworth"};
    // 使用独立的函数对象
    std::cout << "hash(" << std::quoted(obj.first_name) << ", "
              << std::quoted(obj.last_name) << ") = "
              << MyHash{}(obj) << " (using MyHash)\n" << std::setw(31) << "or "
              << std::hash<S>{}(obj) << " (using injected std::hash<S> specialization)\n";

    // 自定义散列函数令在无序容器中使用自定义类型可行
    // 此示例将使用注入的 std::hash 特化，
    // 若要使用 MyHash 替代，则将其作为第二模板参数传递
    std::unordered_set<S> names = {obj, {"Bender", "Rodriguez"}, {"Leela", "Turanga"} };
    for(auto& s: names)
        std::cout << std::quoted(s.first_name) << ' ' << std::quoted(s.last_name) << '\n';
}

可能的输出：

hash("Meet the new boss...") = 1861821886482076440
hash("Hubert", "Farnsworth") = 17622465712001802105 (using MyHash)
                            or 17622465712001802105 (using injected std::hash<S> specialization)
"Turanga" "Leela"
"Bender" "Rodriguez"
"Hubert" "Farnsworth"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2148 | C++11 | 缺失对枚举的特化 | 已提供
LWG 2543 | C++11 | hash 可能不是 SFINAE 友好的 | 通过禁用的特化使之为 SFINAE 友好
LWG 2817 | C++11 | 缺失对 nullptr_t 的特化 | 已提供


std::hash::hash

< cpp‎ | utility‎ | hash

std::hash 类应为可默认构造 (DefaultConstructible) 、可复制构造 (CopyConstructible) 且可析构 (Destructible) 。

本节未完成


std::hash<Key>::operator()

< cpp‎ | utility‎ | hash

std::hash 的特化应定义满足下列条件的 operator() ：

  • 接收单个 key 类型的参数 Key 。
  • 返回表示 key 哈希值的 std::size_t 类型值。
  • 对于二个相等的参数 k1 与 k2 ， std::hash <Key>()(k1) == std::hash <Key>()(k2) 。
  • 对于二个相异而不等的参数 k1 与 k2 ， std::hash <Key>()(k1) == std::hash <Key>()(k2) 的概率应该非常小，接近 1.0/ std::numeric_limits <size_t>::max() 。

参数

key - 要被哈希的对象

返回值

表示哈希值的 std::size_t

异常

哈希函数不应抛异常。

示例

下列代码演示如何为自定义类特化 std::hash 模板。

#include <functional>
#include <iostream>
#include <string>

struct Employee {
  std::string name;
  unsigned int ID;
};

namespace std {
template <>
class hash<Employee> {
 public:
  size_t operator()(const Employee &employee) const
  {
    // 用 Fowler-Noll-Vo hash 哈希函数的变体计算 employee 的哈希
    size_t result = 2166136261;

    for (size_t i = 0, ie = employee.name.size(); i != ie; ++i) {
      result = (result * 16777619) ^ employee.name[i];
    }

    return result ^ (employee.ID << 1);
  }
};
}

int main()
{
  Employee employee;
  employee.name = "Zaphod Beeblebrox";
  employee.ID = 42;

  std::hash<Employee> hash_fn;
  std::cout << hash_fn(employee) << '\n';
}

输出：

177237019


std::in_place, std::in_place_type, std::in_place_index, std::in_place_t, std::in_place_type_t, std::in_place_index_t

< cpp‎ | utility
定义于头文件 <utility>
struct in_place_t {

explicit in_place_t() = default;
};

inline constexpr in_place_t in_place{};
 (C++17 起)
template <class T> struct in_place_type_t {

explicit in_place_type_t() = default;
};
template <class T>

inline constexpr in_place_type_t<T> in_place_type{};
 (C++17 起)
template < std::size_t I> struct in_place_index_t {

explicit in_place_index_t() = default;
};
template < std::size_t I>

inline constexpr in_place_index_t<I> in_place_index{};
 (C++17 起)

std::in_place 、 std::in_place_type 和 std::in_place_index 是消歧义标签，能传递给 std::optional 、 std::variant 和 std::any 的构造函数，以指示应该原位构造对象，以及（对于后二者）要构造的对象的类型。

对应的类型/类型模板 std::in_place_t 、 std::in_place_type_t 和 std::in_place_index_t 能用于构造函数的参数列表中，以匹配有意的标签。

参阅

optional (C++17) | 可能或可能不保有一个对象的包装器 (类模板)
variant (C++17) | 类型安全的可辨识联合体 (类模板)
any (C++17) | 可保有任何可复制构造 (CopyConstructible) 类型的实例的对象。 (类)


std::in_range

< cpp‎ | utility
定义于头文件 <utility> |
template< class R, class T > constexpr bool in_range( T t ) noexcept; | (C++20 起)

若 t 的值在能以 R 表示的值的范围内，即 t 能转换到 R 而无数据损失则为 true 。

若 T 或 R 不是有符号或无符号整数类型（包括标准整数类型与扩展整数类型），则为编译时错误。

参数

t - 要测试的值

返回值

若 t 的值可以 R 表示则为 true ，否则为 false 。

可能的实现

template< class R, class T >
constexpr bool in_range( T t ) noexcept
{
    return std::cmp_greater_equal(t, std::numeric_limits<R>::min()) &&
        std::cmp_less_equal(t, std::numeric_limits<R>::max());
}

注解

此函数不能用于枚举（包括 std::byte ）、 char 、 char8_t 、 char16_t 、 char32_t 、 wchar_t 及 bool 。

示例

#include <utility>
#include <iostream>
#include <iomanip>

int main()
{
    std::cout << std::boolalpha;

    std::cout << std::in_range<std::size_t>(-1) << '\n';
    std::cout << std::in_range<std::size_t>(42) << '\n';
}

输出：

false
true


std::initializer_list

< cpp‎ | utility

（勿与成员初始化器列表混淆）

定义于头文件 <initializer_list> |
template< class T > class initializer_list; | (C++11 起)

std::initializer_list<T> 类型对象是一个访问 const T 类型对象数组的轻量代理对象。

std::initializer_list 对象在这些时候自动构造：

  • 用花括号初始化器列表 列表初始化一个对象，其中对应构造函数接受一个 std::initializer_list 参数
  • 以花括号初始化器列表为赋值的右运算数，或函数调用参数，而对应的赋值运算符/函数接受 std::initializer_list 参数
  • 绑定花括号初始化器列表到 auto ，包括在范围 for 循环中

initializer_list 可由一对指针或指针与其长度实现。复制一个 std::initializer_list 不会复制其底层对象。

底层数组是 const T[N] 类型的临时数组，其中每个元素都从原始初始化器列表的对应元素复制初始化（除非窄化转换非法）。底层数组的生存期与任何其他临时对象相同，除了从数组初始化 initializer_list 对象会延长数组的生存期，恰如绑定引用到临时量（有例外，例如对于初始化非静态类成员）。底层数组可以分配在只读内存。

若声明了 std::initializer_list 的显式或偏特化则程序为谬构。

成员类型

成员类型 | 定义
value_type | T
reference | const T&
const_reference | const T&
size_type | std::size_t
iterator | const T*
const_iterator | const T*

成员函数

(构造函数)
 创建空的 initializer_list
(公开成员函数)
容量
size
 返回 initializer_list 中的元素数目
(公开成员函数)
迭代器
begin
 返回指向首元素的指针
(公开成员函数)
end
 返回指向末元素后一位置的指针
(公开成员函数)

非成员函数

std::begin(std::initializer_list)
(C++11)
 特化 std::begin
(函数模板)
std::end(std::initializer_list)
(C++11)
 特化 std::end
(函数模板)
对 std::initializer_list 重载的自由函数模板
rbegincrbegin
(C++14)
 返回指向一个容器或数组的逆向迭代器
(函数模板)
rendcrend
(C++14)
 返回容器或数组的逆向尾迭代器
(函数模板)
empty
(C++17)
 检查容器是否为空
(函数模板)
data
(C++17)
 获得指向底层数组的指针
(函数模板)

示例

#include <iostream>
#include <vector>
#include <initializer_list>

template <class T>
struct S {
    std::vector<T> v;
    S(std::initializer_list<T> l) : v(l) {
         std::cout << "constructed with a " << l.size() << "-element list\n";
    }
    void append(std::initializer_list<T> l) {
        v.insert(v.end(), l.begin(), l.end());
    }
    std::pair<const T*, std::size_t> c_arr() const {
        return {&v[0], v.size()};  // 在 return 语句中复制列表初始化
                                   // 这不使用 std::initializer_list
    }
};

template <typename T>
void templated_fn(T) {}

int main()
{
    S<int> s = {1, 2, 3, 4, 5}; // 复制初始化
    s.append({6, 7, 8});      // 函数调用中的列表初始化

    std::cout << "The vector size is now " << s.c_arr().second << " ints:\n";

    for (auto n : s.v)
        std::cout << n << ' ';
    std::cout << '\n';

    std::cout << "Range-for over brace-init-list: \n";

    for (int x : {-1, -2, -3}) // auto 的规则令此带范围 for 工作
        std::cout << x << ' ';
    std::cout << '\n';

    auto al = {10, 11, 12};   // auto 的特殊规则

    std::cout << "The list bound to auto has size() = " << al.size() << '\n';

//    templated_fn({1, 2, 3}); // 编译错误！“ {1, 2, 3} ”不是表达式，
                             // 它无类型，故 T 无法推导
    templated_fn<std::initializer_list<int>>({1, 2, 3}); // OK
    templated_fn<std::vector<int>>({1, 2, 3});           // 也 OK
}

输出：

constructed with a 5-element list
The vector size is now 8 ints:
1 2 3 4 5 6 7 8
Range-for over brace-init-list:
-1 -2 -3
The list bound to auto has size() = 3

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 1290 | C++11 | initializer_list 所引用的底层数组的生存期未正确指定 | 指定为同临时对象
CWG 1418 | C++11 | 底层数组的类型缺少 const | 添加 const
LWG 2129 | C++11 | 允许特化 initializer_list 但不保证能用 | 使之为谬构

参阅

span (C++20) | 对象的连续序列上的无所有权视图 (类模板)
basic_string_view (C++17) | 只读的字符串视图 (类模板)


std::initializer_list<T>::begin

< cpp‎ | utility‎ | initializer list
const T* begin() const noexcept; | (C++11 起) (C++14 前)
constexpr const T* begin() const noexcept; | (C++14 起)

返回指向 intializer_list 首元素的指针。

若 initializer_list 为空，则 begin() 与 end() 的值是未指定的，但一定相同。

参数

（无）

返回值

指向 initializer_list 中首元素的指针

复杂度

常数

参阅

end
 返回指向末元素后一位置的指针
(公开成员函数)


std::begin(std::initializer_list)

< cpp‎ | utility‎ | initializer list
定义于头文件 <initializer_list> |
template< class E > const E* begin( std::initializer_list <E> il ) noexcept; | (C++11 起) (C++14 前)
template< class E > constexpr const E* begin( std::initializer_list <E> il ) noexcept; | (C++14 起)

std::begin 对 initializer_list 的重载返回指向 il 首元素的指针。

参数

il - initializer_list

返回值

il.begin()

示例

#include <iostream>
#include <initializer_list>

int main()
{
    std::initializer_list<int> il = {3, 1, 4, 1};
    for(auto it = std::begin(il); it != std::end(il); ++it) {
        std::cout << *it << '\n';
    }
}

输出：

3
1
4
1

参阅

begin
 返回指向首元素的指针
(公开成员函数)


std::initializer_list<T>::end

< cpp‎ | utility‎ | initializer list
const T* end() const noexcept; | (C++11 起) (C++14 前)
constexpr const T* end() const noexcept; | (C++14 起)

返回指向 initializer_list 末元素后一位置的指针，即 begin() + size() 。

若 initializer_list 为空，则 begin() 与 end() 的值是未指定的，但一定相同。

参数

（无）

返回值

指向 initializer_list 末元素后一位置的指针

复杂度

常数

参阅

begin
 返回指向首元素的指针
(公开成员函数)


std::end(std::initializer_list)

< cpp‎ | utility‎ | initializer list
定义于头文件 <initializer_list> |
template< class E > const E* end( std::initializer_list <E> il ) noexcept; | (C++11 起) (C++14 前)
template< class E > constexpr const E* end( std::initializer_list <E> il ) noexcept; | (C++14 起)

std::end 对 initializer_list 的重载返回指向 il 末元素后一位置的指针。

参数

il - initializer_list

返回值

il.end()

示例

#include <iostream>

int main()
{
    // 基于范围的 for 用 std::begin 和 std::end 迭代给定范围；
    // 此情况下，它是一个 initializer_list
    for (int i : {3, 1, 4, 1}) {
        std::cout << i << '\n';
    }
}

输出：

3
1
4
1

参阅

end
 返回指向末元素后一位置的指针
(公开成员函数)


std::initializer_list<T>::initializer_list

< cpp‎ | utility‎ | initializer list
initializer_list() noexcept; | (C++11 起) (C++14 前)
constexpr initializer_list() noexcept; | (C++14 起)

构造空的 initializer_list 。

参数

（无）

复杂度

常数

示例

#include <iostream>
#include <initializer_list>

int main()
{
    std::initializer_list<int> empty_list;
    std::cout << "empty_list.size(): " << empty_list.size() << '\n';

    // 用列表初始化创建初始化器列表
    std::initializer_list<int> digits {1, 2, 3, 4, 5};
    std::cout << "digits.size(): " << digits.size() << '\n';

    // auto 的特殊规则表示‘ fraction ’拥有类型
    // type std::initializer_list<double>
    auto fractions = {3.14159, 2.71828};
    std::cout << "fractions.size(): " << fractions.size() << '\n';
}

输出：

empty_list.size(): 0
digits.size(): 5
fractions.size(): 2

注意

尽管缺少构造函数，创建非空初始化器列表亦是可能的。在这些时候隐式构造 std::initializer_list 实例：

  • 花括号初始化列表用于列表初始化时，包括函数调用列表初始化和赋值表达式
  • 花括号初始化列表被绑定到 auto 时，包括在有范围 for 循环中


std::initializer_list<T>::size

< cpp‎ | utility‎ | initializer list
size_type size() const noexcept; | (C++11 起) (C++14 前)
constexpr size_type size() const noexcept; | (C++14 起)

返回 initializer_list 中的元素数，即 std::distance (begin(), end()) 。

参数

（无）

返回值

initializer_list 中的元素数。

复杂度

常数。

示例

#include <initializer_list>
int main() { static_assert(std::initializer_list{1,2,3,4}.size() == 4); }


std::cmp_equal, cmp_not_equal, cmp_less, cmp_greater, cmp_less_equal, cmp_greater_equal

< cpp‎ | utility
定义于头文件 <utility> |  |
template< class T, class U > constexpr bool cmp_equal( T t, U u ) noexcept; | (1) | (C++20 起)
template< class T, class U > constexpr bool cmp_not_equal( T t, U u ) noexcept; | (2) | (C++20 起)
template< class T, class U > constexpr bool cmp_less( T t, U u ) noexcept; | (3) | (C++20 起)
template< class T, class U > constexpr bool cmp_greater( T t, U u ) noexcept; | (4) | (C++20 起)
template< class T, class U > constexpr bool cmp_less_equal( T t, U u ) noexcept; | (5) | (C++20 起)
template< class T, class U > constexpr bool cmp_greater_equal( T t, U u ) noexcept; | (6) | (C++20 起)

比较二个整数 t 与 u 的值。不同于内建比较运算符，负有符号整数始终比较小于（且不等于）无符号整数：该比较相对于有损整数转换是安全的。

-1 > 0u; // true
std::cmp_greater(-1, 0u); // false

若 T 或 U 不是有符号或无符号整数类型（包括标准整数类型与扩展整数类型），则为编译时错误。

参数

t | - | 左侧参数
u | - | 右侧参数

返回值

1) 若 t 等于 u 则为 true 。
2) 若 t 不等于 u 则为 true 。
3) 若 t 小于 u 则为 true 。
4) 若 t 大于 u 则为 true 。
5) 若 t 小于或等于 u 则为 true 。
6) 若 t 大于或等于 u 则为 true 。

可能的实现

template< class T, class U >
constexpr bool cmp_equal( T t, U u ) noexcept
{
    using UT = std::make_unsigned_t<T>;
    using UU = std::make_unsigned_t<U>;
    if constexpr (std::is_signed_v<T> == std::is_signed_v<U>)
        return t == u;
    else if constexpr (std::is_signed_v<T>)
        return t < 0 ? false : UT(t) == u;
    else
        return u < 0 ? false : t == UU(u);
}

template< class T, class U >
constexpr bool cmp_not_equal( T t, U u ) noexcept
{
    return !cmp_equal(t, u);
}

template< class T, class U >
constexpr bool cmp_less( T t, U u ) noexcept
{
    using UT = std::make_unsigned_t<T>;
    using UU = std::make_unsigned_t<U>;
    if constexpr (std::is_signed_v<T> == std::is_signed_v<U>)
        return t < u;
    else if constexpr (std::is_signed_v<T>)
        return t < 0 ? true : UT(t) < u;
    else
        return u < 0 ? false : t < UU(u);
}

template< class T, class U >
constexpr bool cmp_greater( T t, U u ) noexcept
{
    return cmp_less(u, t);
}

template< class T, class U >
constexpr bool cmp_less_equal( T t, U u ) noexcept
{
    return !cmp_greater(t, u);
}

template< class T, class U >
constexpr bool cmp_greater_equal( T t, U u ) noexcept
{
    return !cmp_less(t, u);
}

注解

这些函数不能用于比较枚举（包括 std::byte ）、 char 、 char8_t 、 char16_t 、 char32_t 、 wchar_t 及 bool 。

示例

本节未完成
原因：暂无示例


std::integer_sequence

< cpp‎ | utility
定义于头文件 <utility> |
template< class T, T... Ints > struct integer_sequence; | (C++14 起)

类模板 std::integer_sequence 表示一个编译时的整数序列。在用作函数模板的实参时，能推导参数包 Ints 并将它用于包展开。

模板形参

T | - | 用于序列元素的整数类型
...Ints | - | 表示序列的非类型形参包

成员类型

成员类型 | 定义
value_type | T

成员函数

size
[静态]
 返回 Ints 中的元素数
(公开静态成员函数)

std::integer_sequence::size

static constexpr std::size_t size() noexcept;

返回 Ints 中的元素数。等价于 sizeof...(Ints) 。

参数

（无）

返回值

Ints 中的元素数。

辅助模板

为帮助 T 为 std::size_t 的常用情况，定义辅助别名模板 std::index_sequence 。

template< std::size_t... Ints>
using index_sequence = std::integer_sequence< std::size_t, Ints...>;

分别定义辅助别名模板 std::make_integer_sequence 与 std::make_index_sequence 以简化以 0, 1, 2, ..., N-1 为 Ints 创建 std::integer_sequence 与 std::index_sequence 类型：

template<class T, T N>
using make_integer_sequence = std::integer_sequence<T, /* a sequence 0, 1, 2, ..., N-1 */ >;
template< std::size_t N>
using make_index_sequence = std::make_integer_sequence< std::size_t, N>;

若 N 为负则程序为谬构。若 N 为零，则指示类型为 integer_sequence<T> 。

定义辅助类模板 std::index_sequence_for ，以转换任何类型参数包为同长度的下标序列：

template<class... T>
using index_sequence_for = std::make_index_sequence<sizeof...(T)>;

示例

注意：另一示例见 std::apply 中可能的实现。

#include <tuple>
#include <iostream>
#include <array>
#include <utility>

// 调试辅助
template<typename T, T... ints>
void print_sequence(std::integer_sequence<T, ints...> int_seq)
{
    std::cout << "The sequence of size " << int_seq.size() << ": ";
    ((std::cout << ints << ' '),...);
    std::cout << '\n';
}

// 转换数组为 tuple
template<typename Array, std::size_t... I>
auto a2t_impl(const Array& a, std::index_sequence<I...>)
{
    return std::make_tuple(a[I]...);
}

template<typename T, std::size_t N, typename Indices = std::make_index_sequence<N>>
auto a2t(const std::array<T, N>& a)
{
    return a2t_impl(a, Indices{});
}

// 漂亮地打印 tuple

template<class Ch, class Tr, class Tuple, std::size_t... Is>
void print_tuple_impl(std::basic_ostream<Ch,Tr>& os,
                      const Tuple& t,
                      std::index_sequence<Is...>)
{
    ((os << (Is == 0? "" : ", ") << std::get<Is>(t)), ...);
}

template<class Ch, class Tr, class... Args>
auto& operator<<(std::basic_ostream<Ch, Tr>& os, const std::tuple<Args...>& t)
{
    os << "(";
    print_tuple_impl(os, t, std::index_sequence_for<Args...>{});
    return os << ")";
}

int main()
{
    print_sequence(std::integer_sequence<unsigned, 9, 2, 5, 1, 9, 1, 6>{});
    print_sequence(std::make_integer_sequence<int, 20>{});
    print_sequence(std::make_index_sequence<10>{});
    print_sequence(std::index_sequence_for<float, std::iostream, char>{});

    std::array<int, 4> array = {1,2,3,4};

    // 转换 array 为 tuple
    auto tuple = a2t(array);
    static_assert(std::is_same<decltype(tuple),
                               std::tuple<int, int, int, int>>::value, "");

    // 打印到 cout
    std::cout << tuple << '\n';
}

输出：

The sequence of size 7: 9 2 5 1 9 1 6
The sequence of size 20: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
The sequence of size 10: 0 1 2 3 4 5 6 7 8 9
The sequence of size 3: 0 1 2
(1, 2, 3, 4)


std::launder

< cpp‎ | utility
定义于头文件 <new> |
template <class T> constexpr T* launder(T* p) noexcept; | (C++17 起) (C++20 前)
template <class T> [[nodiscard]] constexpr T* launder(T* p) noexcept; | (C++20 起)

获得指向位于 p 所表示地址的对象的指针。

正式而言，给定

  • 表示内存中一个字节的地址 A 的指针 p
  • 一个位于地址 A 的对象 X
  • X 在其生存期内
  • X 的类型与 T 相同，忽略每层的 cv 限定符
  • 能通过结果触及的每个字节都能通过 p 触及（若字节在与 Y 指针可互转换的对象 Z 的存储内，或在以 Z 为元素的立即外围数组内，则能通过指向对象 Y 的指针触及这些字节）。

则 std::launder(p) 返回 T* 类型的值，它指向对象 X 。否则行为未定义。

若 T 是函数类型或（可有 cv 限定的） void 则程序为谬构。

std::launder 可用于核心常量表达式，当且仅当其（转换后的）参数的值在函数调用的位置可使用。换言之， std::launder 不放松常量求值中的限制。

注解

std::launder 在其参数上无效果。必须用其返回值访问对象。从而，舍弃返回值始终是错误。

std::launder 的典型用途包括：

  • 获得指向在同类型既存对象的存储中创建的对象的指针，这里不能重用指向旧对象的指针（例如，因为任一对象为基类子对象）；
  • 获得指向对象的指针，该对象由布置 new 从指向为该对象提供存储的对象的指针创建。

可触及性限制确保不能用 std::launder 访问不可通过原指针访问的字节，从而干涉编译器的逃逸分析。

int x[10];
auto p = std::launder(reinterpret_cast<int(*)[10]>(&x[0])); // OK

int x2[2][10];
auto p2 = std::launder(reinterpret_cast<int(*)[10]>(&x2[0][0]));
// 未定义行为：可通过产生的指向 x2[0] 的指针触及 x2[1] ，但不可从源触及

struct X { int a[10]; } x3, x4[2]; // 标准布局；假定无填充
auto p3 = std::launder(reinterpret_cast<int(*)[10]>(&x3.a[0])); // OK
auto p4 = std::launder(reinterpret_cast<int(*)[10]>(&x4[0].a[0]));
// 未定义行为：可通过产生的指向 x4[0].a 的指针（它与 x4[0] 指针间可转换）触及 x4[1] ，但不可从源触及

struct Y { int a[10]; double y; } x5;
auto p5 = std::launder(reinterpret_cast<int(*)[10]>(&x5.a[0]));
// 未定义行为：可通过产生的指向 x5.a 的指针触及 x5.y ，但不可从源触及

示例

#include <new>
#include <cstddef>
#include <cassert>

struct Y {
  int z;
};

struct A {
    virtual int transmogrify();
};

struct B : A {
    int transmogrify() override { new(this) A; return 2; }
};

int A::transmogrify() { new(this) B; return 1; }

static_assert(sizeof(B) == sizeof(A));

int main()
{
  // 情况 1 ：新对象无法为透明可替换，因为它是基类子对象而旧对象是完整对象。
  A i;
  int n = i.transmogrify();
  // int m = i.transmogrify(); // 未定义行为
  int m = std::launder(&i)->transmogrify(); // OK
  assert(m + n == 3);

  // 情况 2 ：通过指向字节数组的指针访问存储为该数组所提供的新对象。
  alignas(Y) std::byte s[sizeof(Y)];
  Y* q = new(&s) Y{2};
  const int f = reinterpret_cast<Y*>(&s)->z; // 类成员访问为未定义行为：
                                             // reinterpret_cast<Y*>(&s) 拥有值
                                             // “指向 s 的指针”而不指向 Y 对象
  const int g = q->z; // OK
  const int h = std::launder(reinterpret_cast<Y*>(&s))->z; // OK

  [f, g, h] {}; // 压制“未使用变量”警告；参阅 [[maybe_unused]] 。
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2859 | C++17 | 可触及的定义未考虑来自指针可互转换的对象的指针算术 | 已考虑
LWG 3495 | C++17 | launder 可以在常量表达式中令指向不活跃成员的指针可解引用 | 已禁止


std::make_from_tuple

< cpp‎ | utility
定义于头文件 <tuple> |
template <class T, class Tuple> constexpr T make_from_tuple(Tuple&& t); | (C++17 起)

构造 T 类型对象，以元组 t 的元素为构造函数的参数。

参数

t - 元组，其元素被用作 T 构造函数的参数

返回值

被构造的 T 对象。

注解

元组不必是 std::tuple ，可以为任何支持 std::get 和 std::tuple_size 的类型所替代；特别是可以用 std::array 和 std::pair 。

因为受保证的复制消除，不需要 T 为可移动。

可能的实现

namespace detail {
template <class T, class Tuple, std::size_t... I>
constexpr T make_from_tuple_impl( Tuple&& t, std::index_sequence<I...> )
{
    static_assert(std::is_constructible_v<T,
        decltype(std::get<I>(std::declval<Tuple>()))...>);
    return T(std::get<I>(std::forward<Tuple>(t))...);
}
} // namespace detail

template <class T, class Tuple>
constexpr T make_from_tuple( Tuple&& t )
{
    return detail::make_from_tuple_impl<T>(std::forward<Tuple>(t),
        std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
}

示例

#include <iostream>
#include <tuple>

struct Foo {
    Foo(int first, float second, int third) {
        std::cout << first << ", " << second << ", " << third << "\n";
    }
};

int main()
{
   auto tuple = std::make_tuple(42, 3.14f, 0);
   std::make_from_tuple<Foo>(std::move(tuple));
}

输出：

42, 3.14, 0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3528 | C++17 | 在 1-元组的情况下允许含有 reinterpret_cast 等的转型 | 不允许

参阅

make_tuple | 创建一个 tuple 对象，其类型根据各实参类型定义 (函数模板)
forward_as_tuple | 创建转发引用的 tuple (函数模板)
apply (C++17) | 以一个实参的元组来调用函数 (函数模板)


std::move

< cpp‎ | utility
定义于头文件 <utility> |
template< class T > typename std::remove_reference <T>::type&& move( T&& t ) noexcept; | (C++11 起) (C++14 前)
template< class T > constexpr std::remove_reference_t <T>&& move( T&& t ) noexcept; | (C++14 起)

std::move 用于指示对象 t 可以“被移动”，即允许从 t 到另一对象的有效率的资源传递。

特别是， std::move 生成标识其参数 t 的亡值表达式。它准确地等价于到右值引用类型的 static_cast 。

参数

t - 要被移动的对象

返回值

static_cast<typename std::remove_reference <T>::type&&>(t)

注解

以右值参数（如临时对象的纯右值或如 std::move 所产生者的亡值之一）调用函数时，重载决议选择接受右值引用参数的版本（包含移动构造函数、移动赋值运算符及常规成员函数，如 std::vector::push_back ）。若参数标识一个占有资源的对象，则这些重载拥有移动参数所保有的任何资源的选择，但不强求如此。例如，链表的移动构造函数可以复制指向表头的指针，并将 nullptr 存储到参数中，而非分配并复制逐个结点。

右值引用变量的名称是左值，而若要绑定到接受右值引用参数的重载，就必须转换到亡值，此乃移动构造函数与移动赋值运算符典型地使用 std::move 的原因：

// 简单的移动构造函数
A(A&& arg) : member(std::move(arg.member)) // 表达式 "arg.member" 为左值
{}
// 简单的移动赋值运算符
A& operator=(A&& other) {
     member = std::move(other.member);
     return *this;
}

一个例外是当函数参数类型是到模板形参的右值引用（“转发引用”或“通用引用”）时，该情况下转而使用 std::forward 。

除非另外指定，否则所有已被移动的标准库对象被置于合法但未指定的状态。即只有无前提的函数，例如赋值运算符，才能安全地在对象被移动后使用：

std::vector<std::string> v;
std::string str = "example";
v.push_back(std::move(str)); // str 现在合法但未指定
str.back(); // 若 size() == 0 则为未定义行为： back() 拥有前提 !empty()
str.clear(); // OK ， clear() 无前提

而且，以亡值参数调用的标准库函数可以假设该参数是到对象的唯一引用；若它从左值带 std::move 构造，则不进行别名检查。然而标准库类型的自移动赋值保证将对象置于合法（但未指定的）状态：

std::vector<int> v = {2, 3, 3};
v = std::move(v); // v 的值未指定

示例

#include <iostream>
#include <utility>
#include <vector>
#include <string>

int main()
{
    std::string str = "Hello";
    std::vector<std::string> v;

    // 使用 push_back(const T&) 重载，
    // 表示我们将带来复制 str 的成本
    v.push_back(str);
    std::cout << "After copy, str is \"" << str << "\"\n";

    // 使用右值引用 push_back(T&&) 重载，
    // 表示不复制字符串；而是
    // str 的内容被移动进 vector
    // 这个开销比较低，但也意味着 str 现在可能为空。
    v.push_back(std::move(str));
    std::cout << "After move, str is \"" << str << "\"\n";

    std::cout << "The contents of the vector are \"" << v[0]
                                         << "\", \"" << v[1] << "\"\n";
}

可能的输出：

After copy, str is "Hello"
After move, str is ""
The contents of the vector are "Hello", "Hello"

参阅

forward (C++11) | 转发一个函数实参 (函数模板)
move_if_noexcept (C++11) | 若移动构造函数不抛出则获得右值引用 (函数模板)
move (C++11) | 将某一范围的元素移动到一个新的位置 (函数模板)


std::move_if_noexcept

< cpp‎ | utility
定义于头文件 <utility>
template< class T >

typename std::conditional <
! std::is_nothrow_move_constructible <T>::value && std::is_copy_constructible <T>::value,
const T&,
T&&

>::type move_if_noexcept(T& x) noexcept;
 (C++11 起)
(C++14 前)
template< class T >

constexpr typename std::conditional <
! std::is_nothrow_move_constructible <T>::value && std::is_copy_constructible <T>::value,
const T&,
T&&

>::type move_if_noexcept(T& x) noexcept;
 (C++14 起)

若参数的移动构造函数不抛异常，则 move_if_noexcept 获得到参数的右值引用，否则获得左值引用。它典型地用于组合移动语义和强异常保证。

参数

x - 要移动或复制的对象

返回值

根据异常保证为 std::move(x) 或 x 。

注意

它可为如 std::vector::resize 这些必须分配新存储然后从旧存储移动或复制元素到新存储的函数所用。若在此操作中发生异常，则 std::vector::resize 撤销任何它做到此点的操作，这仅若使用 std::move_if_noexcept 确定使用移动构造还是复制构造才可行。（除非复制构造不可用，该情况下还是会使用移动构造，且可能抛弃强异常保证）

示例

#include <iostream>
#include <utility>

struct Bad
{
    Bad() {}
    Bad(Bad&&)  // 可能抛出
    {
        std::cout << "Throwing move constructor called\n";
    }
    Bad(const Bad&) // 亦可能抛出
    {
        std::cout << "Throwing copy constructor called\n";
    }
};

struct Good
{
    Good() {}
    Good(Good&&) noexcept // 将不抛出
    {
        std::cout << "Non-throwing move constructor called\n";
    }
    Good(const Good&) noexcept // 将不抛出
    {
        std::cout << "Non-throwing copy constructor called\n";
    }
};

int main()
{
    Good g;
    Bad b;
    Good g2 = std::move_if_noexcept(g);
    Bad b2 = std::move_if_noexcept(b);
}

输出：

Non-throwing move constructor called
Throwing copy constructor called

复杂度

常数

参阅

forward (C++11) | 转发一个函数实参 (函数模板)
move (C++11) | 获得右值引用 (函数模板)


std::optional

< cpp‎ | utility
定义于头文件 <optional> |
template< class T > class optional; | (C++17 起)

类模板 std::optional 管理一个可选的容纳值，既可以存在也可以不存在的值。

一种常见的 optional 使用情况是一个可能失败的函数的返回值。与其他手段，如 std::pair <T,bool> 相比， optional 良好地处理构造开销高昂的对象，并更加可读，因为它显式表达意图。

任何一个 optional<T> 的实例在给定时间点要么含值，要么不含值。

若一个 optional<T> 含值，则保证值作为 optional 对象所用空间的一部分分配，即不会发生动态内存分配。从而 optional 对象模拟一个对象，而非指针，尽管定义了 operator*() 和 operator->() 运算符。

当一个 optional<T> 对象被按语境转换成 bool 时，若对象含值则转换返回 true ，若对象不含值则返回 false 。

optional 对象在下列条件下含值：

  • 对象被以 T 类型值或另一含值的 optional 初始化/赋值。

对象在下列条件下不含值：

  • 对象被默认初始化。
  • 对象被以 std::nullopt_t 类型值或不含值的 optional 对象初始化/赋值。
  • 调用了成员函数 reset() 。

无引用的 optional ：若以引用类型实例化 optional 则程序非良构。不过，可用 T 类型的 std::reference_wrapper 的 optional 保有引用。另外，若以（可有 cv 限定的）标签类型 std::nullopt_t 或 std::in_place_t 实例化 optional 则程序非良构。

模板形参

T - 要为之管理状态的值的类型。该类型必须满足可析构 (Destructible) 的要求。（特别是不允许数组类型）

成员类型

成员类型 | 定义
value_type | T

成员函数

(构造函数)
 构造optional对象
(公开成员函数)
(析构函数)
 销毁容纳的值，若存在
(公开成员函数)
operator=
 对内容赋值
(公开成员函数)
观察器
operator->operator*
 访问所含值
(公开成员函数)
operator boolhas_value
 检查对象是否含值
(公开成员函数)
value
 返回所含值
(公开成员函数)
value_or
 若所含值可用则返回它，否则返回另一个值
(公开成员函数)
单子操作
and_then
(C++23)
 若所含值存在则返回给定的函数在其上的结果，否则返回空的 optional
(公开成员函数)
transform
(C++23)
 若所含值存在则返回含有变换后的所含值的 optional ，否则返回空的 optional
(公开成员函数)
or_else
(C++23)
 若 optional 含值则返回其自身，否则返回给定函数的结果
(公开成员函数)
修改器
swap
 交换内容
(公开成员函数)
reset
 销毁任何所含值
(公开成员函数)
emplace
 原位构造所含值
(公开成员函数)

非成员函数

operator==operator!=operator<operator<=operator>operator>=operator<=> (C++17)(C++17)(C++17)(C++17)(C++17)(C++17)(C++20) | 比较 optional 对象 (函数模板)
make_optional (C++17) | 创建一个 optional 对象 (函数模板)
std::swap(std::optional) (C++17) | 特化 std::swap 算法 (函数模板)

辅助类

std::hash<std::optional> (C++17) | 特化 std::hash 算法 (类模板特化)
nullopt_t (C++17) | 带未初始化状态的 optional 类型的指示器 (类)
bad_optional_access (C++17) | 指示进行了到不含值的 optional 的有检查访问的异常 (类)

辅助对象

nullopt (C++17) | nullopt_t 类型对象 (常量)
in_place in_place_type in_place_index in_place_t in_place_type_t in_place_index_t (C++17) | 原位构造标签 (类模板)

推导指引

示例

#include <string>
#include <functional>
#include <iostream>
#include <optional>

// optional 可用作可能失败的工厂的返回类型
std::optional<std::string> create(bool b) {
    if(b)
        return "Godzilla";
    else
        return {};
}

// 能用 std::nullopt 创建任何（空的） std::optional
auto create2(bool b) {
    return b ? std::optional<std::string>{"Godzilla"} : std::nullopt;
}

// std::reference_wrapper 可用于返回引用
auto create_ref(bool b) {
    static std::string value = "Godzilla";
    return b ? std::optional<std::reference_wrapper<std::string>>{value}
             : std::nullopt;
}

int main()
{
    std::cout << "create(false) returned "
              << create(false).value_or("empty") << '\n';

    // 返回 optional 的工厂函数可用作 while 和 if 的条件
    if (auto str = create2(true)) {
        std::cout << "create2(true) returned " << *str << '\n';
    }

    if (auto str = create_ref(true)) {
        // 用 get() 访问 reference_wrapper 的值
        std::cout << "create_ref(true) returned " << str->get() << '\n';
        str->get() = "Mothra";
        std::cout << "modifying it changed it to " << str->get() << '\n';
    }
}

输出：

create(false) returned empty
create2(true) returned Godzilla
create_ref(true) returned Godzilla
modifying it changed it to Mothra

参阅

variant (C++17) | 类型安全的可辨识联合体 (类模板)
any (C++17) | 可保有任何可复制构造 (CopyConstructible) 类型的实例的对象。 (类)


std::optional<T>::and_then

< cpp‎ | utility‎ | optional
template< class F > constexpr auto and_then( F&& f ) &; | (1) | (C++23 起)
template< class F > constexpr auto and_then( F&& f ) const&; | (2) | (C++23 起)
template< class F > constexpr auto and_then( F&& f ) &&; | (3) | (C++23 起)
template< class F > constexpr auto and_then( F&& f ) const&&; | (4) | (C++23 起)

若所含值存在则返回在其上调用 f 的结果。否则，返回返回类型的空值。

返回类型（见后述）必须为 std::optional 的特化。否则程序非良构。

1) 等价于
if (*this)

return std::invoke ( std::forward <F>(f), this->value());
else

return std::remove_cvref_t<std::invoke_result_t<F, T&>>(); 。
2) 等价于
if (*this)

return std::invoke ( std::forward <F>(f), this->value());
else

return std::remove_cvref_t<std::invoke_result_t<F, const T&>>(); 。
3) 等价于
if (*this)

return std::invoke ( std::forward <F>(f), std::move(this->value()));
else

return std::remove_cvref_t<std::invoke_result_t<F, T>>(); 。
4) 等价于
if (*this)

return std::invoke ( std::forward <F>(f), std::move(this->value()));
else

return std::remove_cvref_t<std::invoke_result_t<F, const T>>(); 。

参数

f - 适合的函数或可调用 (Callable) 对象，返回 std::optional

返回值

f 的结果或空的 std::optional ，如上所述。

注解

有些语言称此操作为 flatmap 。

示例

本节未完成
原因：暂无示例

参阅

value_or | 若所含值可用则返回它，否则返回另一个值 (公开成员函数)
transform (C++23) | 若所含值存在则返回含有变换后的所含值的 optional ，否则返回空的 optional (公开成员函数)
or_else (C++23) | 若 optional 含值则返回其自身，否则返回给定函数的结果 (公开成员函数)


std::bad_optional_access

< cpp‎ | utility‎ | optional
定义于头文件 <optional> |
class bad_optional_access; | (C++17 起)

定义 std::optional::value 在访问不含值的 optional 对象时所抛出的异常对象类型。

cpp/error/exception std-bad optional access-inheritance-lwg2806.svg

继承图

成员函数

(构造函数) | 构造新的 bad_optional_access 对象 (公开成员函数)
operator= | 替换 bad_optional_access 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::bad_optional_access::bad_optional_access

bad_optional_access() noexcept; | (1) | (C++17 起)
bad_optional_access( const bad_optional_access& other ) noexcept; | (2) | (C++17 起)

构造新的拥有实现定义的空终止字节字符串的 bad_optional_access 对象，字符串能通过 what() 访问。

1) 默认构造函数。
2) 复制构造函数。若 *this 与 other 均拥有动态类型 std::bad_optional_access 则 std::strcmp (what(), other.what()) == 0 。

参数

other - 要复制的另一异常对象

std::bad_optional_access::operator=

bad_optional_access& operator=( const bad_optional_access& other ) noexcept; | (C++17 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::bad_optional_access 则赋值后 std::strcmp (what(), other.what()) == 0 。

参数

other - 用以赋值的另一异常对象

返回值

*this

std::bad_optional_access::what

virtual const char* what() const noexcept; | (C++17 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)


std::optional 的推导指引

< cpp‎ | utility‎ | optional
定义于头文件 <optional> |
template<class T> optional(T) -> optional<T>; | (C++17 起)

为 std::optional 提供一个推导指引以处理隐式推导指引所遗漏的极端情况，尤其是不可复制参数和数组到指针转换。

示例

#include <optional>

int main()
{
    int a[2];
    std::optional oa{a}; // 用于此情况的显式推导指引
}


std::optional<T>::emplace

< cpp‎ | utility‎ | optional
 | (1)
template< class... Args > T& emplace( Args&&... args ); |  | (C++17 起) (C++20 前)
template< class... Args > constexpr T& emplace( Args&&... args ); |  | (C++20 起)
 | (2)
template< class U, class... Args > T& emplace( std::initializer_list <U> ilist, Args&&... args ); |  | (C++17 起) (C++20 前)
template< class U, class... Args > constexpr T& emplace( std::initializer_list <U> ilist, Args&&... args ); |  | (C++20 起)

原位构造所含值。若 *this 已在此调用前含值，则调用其析构函数销毁所含值。

1) 以 std::forward <Args>(args)... 为参数直接初始化（但不是直接列表初始化）所含值。
2) 以 ilist, std::forward <Args>(args)... 为参数直接初始化（但不是直接列表初始化）所含值。此重载仅若 std::is_constructible <T, std::initializer_list <U>&, Args&&...>::value 为 true 才参与重载决议。

参数

args... | - | 传递给构造函数的参数
ilist | - | 传递给构造函数的初始化器列表
类型要求
- 对于重载 (1) ， T 必须可从 Args... 构造
- 对于重载 (2) ， T 必须可从 std::initializer_list 及 Args... 构造

返回值

到新的被含有值的引用。

异常

选择的 T 构造函数所抛出的任何异常。若抛出异常，则 *this 在此调用后不含值（若先前存在所含值，则销毁它）。

示例

#include <optional>
#include <iostream>

struct A {
    std::string s;
    A(std::string str) : s(std::move(str))  { std::cout << " constructed\n"; }
    ~A() { std::cout << " destructed\n"; }
    A(const A& o) : s(o.s) { std::cout << " copy constructed\n"; }
    A(A&& o) : s(std::move(o.s)) { std::cout << " move constructed\n"; }
    A& operator=(const A& other) {
        s = other.s;
        std::cout << " copy assigned\n";
        return *this;
    }
    A& operator=(A&& other) {
        s = std::move(other.s);
        std::cout << " move assigned\n";
        return *this;
    }
};

int main()
{
    std::optional<A> opt;

    std::cout << "Assign:\n";
    opt = A("Lorem ipsum dolor sit amet, consectetur adipiscing elit nec.");

    std::cout << "Emplace:\n";
    // 由于 opt 含值，这亦将销毁该值
    opt.emplace("Lorem ipsum dolor sit amet, consectetur efficitur. ");

    std::cout << "End example\n";
}

输出：

Assign:
 constructed
 move constructed
 destructed
Emplace:
 destructed
 constructed
End example
 destructed

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2231R1 | C++20 | emplace 不是 constexpr ，而要求的操作在 C++20 中能为 constexpr | 使之为 constexpr

参阅

operator=
 对内容赋值
(公开成员函数)


std::hash <std::optional>

< cpp‎ | utility‎ | optional
定义于头文件 <optional> |
template<class T> struct hash< std::optional <T>>; | (C++17 起)

std::hash 对 std::optional 类的模板特化允许用户获得 optional 对象所含值的哈希值。

若启用了 std::hash<std::remove_const_t<T>> ，则启用特化 std::hash<optional<T>> 得到启用，反之禁用它。

在启用时，对于含值的 std::optional<T> 类型对象 o ， std::hash<std::optional<T>>()(o) 求值 std::hash<std::remove_const_t<T>>()(*o) 。对于不容纳值的 optional ，哈希值未指定。

此特化的成员函数不保证 noexcept ，因为底层类型的哈希可能抛出。

模板形参

T - optional 对象所含值的类型

示例

#include <optional>
#include <unordered_set>
#include <string>
#include <iostream>
using namespace std::literals;
int main()
{
    // hash<optional> 令 unordered_set 可以使用
    std::unordered_set<std::optional<std::string>> s = {
            "abc"s, std::nullopt, "def"s
    };

    for(const auto& o : s)
        std::cout << o.value_or("(null)") << ' ';
}

可能的输出：

def abc (null)

参阅

hash
(C++11)
 散列函数对象
(类模板)


std::make_optional

< cpp‎ | utility‎ | optional
定义于头文件 <optional> |  |
template< class T > constexpr std::optional < std::decay_t <T>> make_optional( T&& value ); | (1) | (C++17 起)
template< class T, class... Args > constexpr std::optional <T> make_optional( Args&&... args ); | (2) | (C++17 起)
template< class T, class U, class... Args > constexpr std::optional <T> make_optional( std::initializer_list <U> il, Args&&... args ); | (3) | (C++17 起)
1) 从value 创建 optional 对象。等效地调用 std::optional < std::decay_t <T>>( std::forward <T>(value)) 。
2) 从 args... 创建原位构造的 optional 对象。等价于 return std::optional <T>( std::in_place, std::forward <Args>(args)...); 。
3) 从 il 和 args... 创建原位构造的 optional 对象。等价于 return std::optional <T>( std::in_place, il, std::forward <Args>(args)...); 。

参数

value | - | 构造 optional 对象所用的值
il, args | - | 传递给 T 构造函数的参数。

返回值

构造的 optional 对象。

异常

抛出任何 T 的构造函数所抛的异常。

注解

对于重载 (2-3) T 不需要可移动，因为受保证的复制消除。

示例

#include <optional>
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>

int main()
{
    auto op1 = std::make_optional<std::vector<char>>({'a','b','c'});
    std::cout << "op1: ";
    for (char c: op1.value()){
        std::cout << c << ",";
    }
    auto op2 = std::make_optional<std::vector<int>>(5, 2);
    std::cout << "\nop2: ";
    for (int i: *op2){
        std::cout << i << ",";
    }
    std::string str{"hello world"};
    auto op3 = std::make_optional<std::string>(std::move(str));
    std::cout << "\nop3: " << quoted(op3.value_or("empty value")) << '\n';
    std::cout << "str: " << std::quoted(str) << '\n';
}

可能的输出：

op1: a,b,c,
op2: 2,2,2,2,2,
op3: "hello world"
str: ""

参阅

(构造函数)
 构造optional对象
(公开成员函数)


std::nullopt

< cpp‎ | utility‎ | optional
定义于头文件 <optional> |
inline constexpr nullopt_t nullopt{/*unspecified*/}; | (C++17 起)

std::nullopt 是 std::nullopt_t 类型常量，用于指示 optional 类型有未初始化状态。

参阅

nullopt_t
(C++17)
 带未初始化状态的 optional 类型的指示器
(类)


std::nullopt_t

< cpp‎ | utility‎ | optional
定义于头文件 <optional> |
struct nullopt_t; | (C++17 起)

std::nullopt_t 是空类类型，用于指示 optional 类型拥有未初始化状态。特别是 std::optional 有一个以 nullopt_t 为单参数的构造函数，它创建不含值的 optional 。

std::nullopt_t 必须是非聚合字面类型 (LiteralType) ，而且不能有默认构造函数或 initializer_list 构造函数。

它必须有一个接收实现定义字面类型的 constexpr 构造函数。

注解

nullopt_t 构造函数上的制约，在于支持 op = {}; 和 op = nullopt; 两者都是令 optional 不含对象的语法。

此类的一个可能实现是

struct nullopt_t {
    explicit constexpr nullopt_t(int) {}
};

参阅

nullopt
(C++17)
 nullopt_t 类型对象
(常量)


std::optional<T>::operator->, std::optional<T>::operator*

< cpp‎ | utility‎ | optional
constexpr const T* operator->() const noexcept; | (1) | (C++17 起)
constexpr T* operator->() noexcept; | (1) | (C++17 起)
constexpr const T& operator*() const& noexcept; | (2) | (C++17 起)
constexpr T& operator*() & noexcept; | (2) | (C++17 起)
constexpr const T&& operator*() const&& noexcept; | (2) | (C++17 起)
constexpr T&& operator*() && noexcept; | (2) | (C++17 起)

访问所含值。

1) 返回指向所含值的指针。
2) 返回到所含值的引用。

若 *this 不含值则行为未定义。

参数

（无）

返回值

指向所含值的指针或到它的引用。

注解

此运算符不检查 optional 是否含值！你能手动用 has_value() 或简单地用 operator bool() 做检查。另外，若需要有检查访问，可使用 value() 或 value_or() 。

示例

#include <optional>
#include <iostream>
#include <string>

int main()
{
    using namespace std::string_literals;

    std::optional<int> opt1 = 1;
    std::cout<< "opt1: "  << *opt1 << '\n';

    *opt1 = 2;
    std::cout<< "opt1: "  << *opt1 << '\n';

    std::optional<std::string> opt2 = "abc"s;
    std::cout<< "opt2: " << *opt2 << " size: " << opt2->size() << '\n';

    // 你能通过在到 optional 的右值上调用 operator* “取”其所含值

    auto taken = *std::move(opt2);
    std::cout << "taken: " << taken << " opt2: " << *opt2 << "size: " << opt2->size()  << '\n';
}

可能的输出：

opt1: 1
opt1: 2
opt2: abc size: 3
taken: abc opt2: size: 0

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2762 | C++17 | operator-> 与 operator* 可能为潜在抛出 | 使之为 noexcept

参阅

value | 返回所含值 (公开成员函数)
value_or | 若所含值可用则返回它，否则返回另一个值 (公开成员函数)


std::optional<T>::operator=

< cpp‎ | utility‎ | optional
 | (1) |
optional& operator=( std::nullopt_t ) noexcept; |  |  | (C++17 起) (C++20 前)
constexpr optional& operator=( std::nullopt_t ) noexcept; |  |  | (C++20 起)
constexpr optional& operator=( const optional& other ); | (2) | (C++17 起)
constexpr optional& operator=( optional&& other ) noexcept(/* see below */); | (3) | (C++17 起)
 | (4) |
template< class U = T > optional& operator=( U&& value ); |  |  | (C++17 起) (C++20 前)
template< class U = T > constexpr optional& operator=( U&& value ); |  |  | (C++20 起)
 | (5) |
template< class U > optional& operator=( const optional<U>& other ); |  |  | (C++17 起) (C++20 前)
template< class U > constexpr optional& operator=( const optional<U>& other ); |  |  | (C++20 起)
 | (6) |
template< class U > optional& operator=( optional<U>&& other ); |  |  | (C++17 起) (C++20 前)
template< class U > constexpr optional& operator=( optional<U>&& other ); |  |  | (C++20 起)

以 other 的内容替换 *this 的内容。

1) 若 *this 在调用前含值，则通过调用其析构函数销毁所含值，如同用 value().T::~T() 。此调用后 *this 不含值。
2-3) 赋值 other 的状态。
  • 若 *this 与 other 均不含值，则函数无效果。
  • 若 *this 含值，但 other 不含值，则通过调用其析构函数销毁被含有值。 *this 在此调用后不含值。
  • 若 other 含值，则取决于 *this 是否含值，以 *other(2) 或 std::move(*other)(3) 直接初始化直接初始化或赋值被含有值。注意被移动的 optional 仍然含值。
  • 重载 (2) 定义为被删除，除非 std::is_copy_constructible_v <T> 与 std::is_copy_assignable_v <T> 皆为 true 。若 std::is_trivially_copy_constructible_v <T> 、 std::is_trivially_copy_assignable_v <T> 及 std::is_trivially_destructible_v <T> 皆为 true 则它为平凡。
  • 重载 (3) 不参与重载决议，除非 std::is_move_constructible_v <T> 与 std::is_move_assignable_v <T> 皆为 true 。若 std::is_trivially_move_constructible_v <T> 、 std::is_trivially_move_assignable_v <T> 及 std::is_trivially_destructible_v <T> 皆为 true 则它为平凡。
4) 完美转发赋值：取决于 *this 在调用前是否含值，从 std::forward <U>(value) 直接初始化，或从 std::forward <U>(value) 赋值被含有值。该函数不参与重载决议，除非 std::decay_t <U> (C++20 前)std::remove_cvref_t<U> (C++20 起) 不是 std::optional <T> ， std::is_constructible_v <T, U> 为 true ， std::is_assignable_v <T&, U> 为 true ，且至少下列一项为真：
  • T 不是标量类型；
  • std::decay_t <U> 不是 T 。
5-6) 赋值 other 的状态。
  • 若 *this 与 other 皆不含值，则函数无效果。
  • 若 *this 容纳值，但 other 不含值，则通过调用其析构函数销毁被含有值。 *this 在此调用后不含值。
  • 若 other 含值，则取决于 *this 是否含值，以 *other(5) 或 std::move(*other)(6) 直接初始化或赋值被含有值。注意被移动的 optional 仍然含值。
  • 这些重载不参与重载决议，除非满足下列条件：
    • T 不可从任何 std::optional <U> 类型（可以为 const ）的表达式构造、转换、或赋值，即下列 12 个类型特性全为 false ：
      • std::is_constructible_v <T, std::optional <U>&>
      • std::is_constructible_v <T, const std::optional <U>&>
      • std::is_constructible_v <T, std::optional <U>&&>
      • std::is_constructible_v <T, const std::optional <U>&&>
      • std::is_convertible_v < std::optional <U>&, T>
      • std::is_convertible_v <const std::optional <U>&, T>
      • std::is_convertible_v < std::optional <U>&&, T>
      • std::is_convertible_v <const std::optional <U>&&, T>
      • std::is_assignable_v <T&, std::optional <U>&>
      • std::is_assignable_v <T&, const std::optional <U>&>
      • std::is_assignable_v <T&, std::optional <U>&&>
      • std::is_assignable_v <T&, const std::optional <U>&&>.
    • 对于重载 (5) ， std::is_constructible_v <T, const U&> 与 std::is_assignable_v <T&, const U&> 皆为 true 。
    • 对于重载 (6) ， std::is_constructible_v <T, U> 与 std::is_assignable_v <T&, U> 皆为 true 。

参数

other | - | 要赋值给被含有值的 optional 对象
value | - | 要赋值给被含有值的值

返回值

*this

异常

2-6) 抛出任何 T 的赋值运算符所抛的异常。若抛出异常，则 *this （还有情况 (2-3) 和 (5-6) 的 other ）的初始化状态不改变，即若对象含值，则它仍然含值，反之亦然。 value 和 *this 及 other 所含有的值的内容依赖于异常来源操作（复制构造函数、移动构造函数等）的异常安全保证。
(3) 拥有下列
noexcept 说明：
noexcept( std::is_nothrow_move_assignable_v <T> && std::is_nothrow_move_constructible_v <T>)

注解

optional 对象 op 可以通过 op = {}; 和 op = nullopt; 变成空 optional 。第一个表达式以 {} 构造空的 optional 对象并将它赋值给 op 。

示例

#include <optional>
#include <iostream>
int main()
{
    std::optional<const char*> s1 = "abc", s2; // 构造函数
    s2 = s1; // 赋值
    s1 = "def"; // 衰变赋值（ U = char[4], T = const char* ）
    std::cout << *s2 << ' ' << *s1 << '\n';
}

输出：

abc def

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0602R4 | C++17 | 即使底层操作平凡，复制/移动赋值运算符亦可能不平凡 | 要求传播平凡性
P2231R1 | C++20 | 转换赋值运算符不是 constexpr 而要求的操作在 C++20 中能是 | 使之为 constexpr

参阅

emplace
 原位构造所含值
(公开成员函数)


std::optional<T>::operator bool, std::optional<T>::has_value

< cpp‎ | utility‎ | optional
constexpr explicit operator bool() const noexcept; | (C++17 起)
constexpr bool has_value() const noexcept; | (C++17 起)

检查 *this 是否含值。

参数

（无）

返回值

若 *this 含值则为 true ，若 *this 不含值则 false 。


operator==, !=, <, <=, >, >=, <=>(std::optional)

< cpp‎ | utility‎ | optional
定义于头文件 <optional>
比较二个 optional 对象
template< class T, class U >
constexpr bool operator==( const optional<T>& lhs, const optional<U>& rhs );
 (1) (C++17 起)
template< class T, class U >
constexpr bool operator!=( const optional<T>& lhs, const optional<U>& rhs );
 (2) (C++17 起)
template< class T, class U >
constexpr bool operator<( const optional<T>& lhs, const optional<U>& rhs );
 (3) (C++17 起)
template< class T, class U >
constexpr bool operator<=( const optional<T>& lhs, const optional<U>& rhs );
 (4) (C++17 起)
template< class T, class U >
constexpr bool operator>( const optional<T>& lhs, const optional<U>& rhs );
 (5) (C++17 起)
template< class T, class U >
constexpr bool operator>=( const optional<T>& lhs, const optional<U>& rhs );
 (6) (C++17 起)
template< class T, std::three_way_comparable_with<T> U >

constexpr std::compare_three_way_result_t<T, U>

operator<=>( const optional<T>& lhs, const optional<U>& rhs );
 (7) (C++20 起)
比较一个 optional 对象与 nullopt
template< class T >
constexpr bool operator==( const optional<T>& opt, std::nullopt_t ) noexcept;
 (8) (C++17 起)
template< class T >
constexpr bool operator==( std::nullopt_t, const optional<T>& opt ) noexcept;
 (9) (C++17 起)
(C++20 前)
template< class T >
constexpr bool operator!=( const optional<T>& opt, std::nullopt_t ) noexcept;
 (10) (C++17 起)
(C++20 前)
template< class T >
constexpr bool operator!=( std::nullopt_t, const optional<T>& opt ) noexcept;
 (11) (C++17 起)
(C++20 前)
template< class T >
constexpr bool operator<( const optional<T>& opt, std::nullopt_t ) noexcept;
 (12) (C++17 起)
(C++20 前)
template< class T >
constexpr bool operator<( std::nullopt_t, const optional<T>& opt ) noexcept;
 (13) (C++17 起)
(C++20 前)
template< class T >
constexpr bool operator<=( const optional<T>& opt, std::nullopt_t ) noexcept;
 (14) (C++17 起)
(C++20 前)
template< class T >
constexpr bool operator<=( std::nullopt_t, const optional<T>& opt) noexcept;
 (15) (C++17 起)
(C++20 前)
template< class T >
constexpr bool operator>( const optional<T>& opt, std::nullopt_t ) noexcept;
 (16) (C++17 起)
(C++20 前)
template< class T >
constexpr bool operator>( std::nullopt_t, const optional<T>& opt ) noexcept;
 (17) (C++17 起)
(C++20 前)
template< class T >
constexpr bool operator>=( const optional<T>& opt, std::nullopt_t ) noexcept;
 (18) (C++17 起)
(C++20 前)
template< class T >
constexpr bool operator>=( std::nullopt_t, const optional<T>& opt ) noexcept;
 (19) (C++17 起)
(C++20 前)
template< class T >

constexpr std::strong_ordering

operator<=>( const optional<T>& opt, std::nullopt_t ) noexcept;
 (20) (C++20 起)
比较一个 optional 对象与一个 T
template< class T, class U >
constexpr bool operator==( const optional<T>& opt, const U& value);
 (21) (C++17 起)
template< class T, class U >
constexpr bool operator==( const T& value, const optional<U>& opt );
 (22) (C++17 起)
template< class T, class U >
constexpr bool operator!=( const optional<T>& opt, const U& value );
 (23) (C++17 起)
template< class T, class U >
constexpr bool operator!=( const T& value, const optional<U>& opt );
 (24) (C++17 起)
template< class T, class U >
constexpr bool operator<( const optional<T>& opt, const U& value );
 (25) (C++17 起)
template< class T, class U >
constexpr bool operator<( const T& value, const optional<U>& opt );
 (26) (C++17 起)
template< class T, class U >
constexpr bool operator<=( const optional<T>& opt, const U& value );
 (27) (C++17 起)
template< class T, class U >
constexpr bool operator<=( const T& value, const optional<U>& opt);
 (28) (C++17 起)
template< class T, class U >
constexpr bool operator>( const optional<T>& opt, const U& value );
 (29) (C++17 起)
template< class T, class U >
constexpr bool operator>( const T& value, const optional<U>& opt );
 (30) (C++17 起)
template< class T, class U >
constexpr bool operator>=( const optional<T>& opt, const U& value );
 (31) (C++17 起)
template< class T, class U >
constexpr bool operator>=( const T& value, const optional<U>& opt );
 (32) (C++17 起)
template< class T, std::three_way_comparable_with<T> U >

constexpr std::compare_three_way_result_t<T, U>

operator<=>( const optional<T>& opt, const U& value );
 (33) (C++20 起)

进行 optional 对象上的比较。

1-7) 比较二个 optional 对象， lhs 和 rhs 。仅若 lhs 与 rhs 都含值，才比较容纳的值（使用 T 对应的运算符）。否则，
  • 若且唯若 lhs 与 rhs 都不含值，才认为 lhs 等于 rhs 。
  • 若且唯若 rhs 含值且 lhs 不含值，才认为 lhs 小于 rhs 。
8-20) 比较 opt 与 nullopt 比较。与 (1-6) 中与不含值的 optional 比较时等价。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)
21-33) 比较 opt 与value 。仅若 opt 含值才比较值。否则认为 opt 小于 value 。若 *opt 与 value 间的对应双路比较表达式非良构，或若结果不能转换为 bool ，则程序非良构。

参数

lhs, rhs, opt | - | 要比较的 optional 对象
value | - | 与所含值比较的值

返回值

1) 若 bool(lhs) != bool(rhs) ，返回 false ；

否则，若 bool(lhs) == false （且 bool(rhs) == false 亦然），返回 true ；

否则，返回 *lhs == *rhs。
2) 若 bool(lhs) != bool(rhs) ，返回 true ；

否则，若 bool(lhs) == false （且 bool(rhs) == false 亦然），返回 false ；

否则，返回 *lhs != *rhs 。
3) 若 bool(rhs) == false ，返回 false ；

否则，若 bool(lhs) == false ，返回 true ；

否则，返回 *lhs < *rhs 。
4) 若 bool(lhs) == false ，返回 true ；

否则，若 bool(rhs) == false ，返回 false ；

否则，返回 *lhs <= *rhs 。
5) 若 bool(lhs) == false ，返回 false ；

否则，若 bool(rhs) == false ，返回 true ；

否则，返回 *lhs > *rhs 。
6) 若 bool(rhs) == false ，返回 true ；

否则，若 bool(lhs) == false ，返回 false ；

否则，返回 *lhs >= *rhs 。
7) 若 bool(lhs) && bool(rhs) 为 true 则返回 *x <=> *y ；
否则，返回 bool(lhs) <=> bool(rhs) 。
8-9) 返回 !opt 。
10-11) 返回 bool(opt) 。
12) 返回 false 。
13) 返回 bool(opt) 。
14) 返回 !opt 。
15) 返回 true 。
16) 返回 bool(opt) 。
17) 返回 false 。
18) 返回 true 。
19) 返回 !opt 。
20) 返回 bool(opt) <=> false 。
21) 返回 bool(opt) ? *opt == value : false 。
22) 返回 bool(opt) ? value == *opt : false 。
23) 返回 bool(opt) ? *opt != value : true 。
24) 返回 bool(opt) ? value != *opt : true 。
25) 返回 bool(opt) ? *opt < value : true 。
26) 返回 bool(opt) ? value < *opt : false 。
27) 返回 bool(opt) ? *opt <= value : true 。
28) 返回 bool(opt) ? value <= *opt : false 。
29) 返回 bool(opt) ? *opt > value : false 。
30) 返回 bool(opt) ? value > *opt : true 。
31) 返回 bool(opt) ? *opt >= value : false 。
32) 返回 bool(opt) ? value >= *opt : true 。
33) 返回 bool(opt) ? *opt <=> value : std::strong_ordering::less 。

异常

1-7) 可能抛出实现定义的异常。
21-33) 在比较抛出时抛出其所抛出的异常。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2945 | C++17 | “与 T 比较”情况的模板形参顺序不一致 | 使之一致


std::optional<T>::optional

< cpp‎ | utility‎ | optional
constexpr optional() noexcept;
constexpr optional( std::nullopt_t ) noexcept;
 (1) (C++17 起)
constexpr optional( const optional& other );
 (2) (C++17 起)
constexpr optional( optional&& other ) noexcept(/* see below */);
 (3) (C++17 起)
(4)
template < class U >
optional( const optional<U>& other );
 (C++17 起)
(C++20 前)
(条件性 explicit)
template < class U >
constexpr optional( const optional<U>& other );
 (C++20 起)
(条件性 explicit)
(5)
template < class U >
optional( optional<U>&& other );
 (C++17 起)
(C++20 前)
(条件性 explicit)
template < class U >
constexpr optional( optional<U>&& other );
 (C++20 起)
(条件性 explicit)
template< class... Args >
constexpr explicit optional( std::in_place_t, Args&&... args );
 (6) (C++17 起)
template< class U, class... Args >

constexpr explicit optional( std::in_place_t,
std::initializer_list <U> ilist,

Args&&... args );
 (7) (C++17 起)
template < class U = T >
constexpr optional( U&& value );
 (8) (C++17 起)
(条件性 explicit)

构造新的 optional 对象。

1) 构造不含值的对象。
2) 复制构造函数：若 other 含值，则初始化所含值，如同以表达式 *other 直接初始化（但不是直接列表初始化） T 类型对象。若 other 不含值，则构造一个不含值的对象。
  • 若 std::is_copy_constructible_v <T> 为 false 则定义此构造函数为被删除。
  • 若 std::is_trivially_copy_constructible_v <T> 为 true ，则它是平凡构造函数。
3) 移动构造函数：若 other 含值，则初始化所含值，如同以表达式 std::move(*other) 直接初始化（但不是直接列表初始化） T 类型对象，且不令 other 为空：被移动源的 optional 仍然含值，但该值自身是被移动的。
  • 若 other 不含值，则构造一个不含值的对象。此构造函数不参与重载决议，除非 std::is_move_constructible_v <T> 为 true
  • 。若 std::is_trivially_move_constructible_v <T> 为 true ，则它是平凡构造函数。
4) 转换复制构造函数：若 other 不含值，则构造不含值的 optional 对象。否则，构造含值的 optional 对象，如同以表达式 *other 直接初始化（但不是直接列表初始化） T 类型对象一般初始化。
  • 此构造函数不参与重载决议，除非满足下列条件：
    • std::is_constructible_v <T, const U&> 为 true 。
    • T 不可从任何 std::optional <U> （可为 const ）类型表达式构造或转换，即下列 8 个类型特征均为 false ：
      • std::is_constructible_v <T, std::optional <U>&>
      • std::is_constructible_v <T, const std::optional <U>&>
      • std::is_constructible_v <T, std::optional <U>&&>
      • std::is_constructible_v <T, const std::optional <U>&&>
      • std::is_convertible_v < std::optional <U>&, T>
      • std::is_convertible_v <const std::optional <U>&, T>
      • std::is_convertible_v < std::optional <U>&&, T>
      • std::is_convertible_v <const std::optional <U>&&, T>
  • 此构造函数为 explicit 若且唯若 std::is_convertible_v <const U&, T> 为 false 。
5) 转换移动构造函数：若 other 不含值，则构造不含值的 optional 对象。否则，构造含值的 optional 对象，如同以表达式 std::move(*other) 直接初始化（但不是直接列表初始化） T 类型对象一般初始化。
  • 此构造函数不参与重载决议，除非满足下列条件：
    • std::is_constructible_v <T, U&&> 为 true 。
    • T 不可从任何std::optional <U> （可为 const ）类型表达式构造或转换，即下列 8 个类型特征均为 false ：
      • std::is_constructible_v <T, std::optional <U>&>
      • std::is_constructible_v <T, const std::optional <U>&>
      • std::is_constructible_v <T, std::optional <U>&&>
      • std::is_constructible_v <T, const std::optional <U>&&>
      • std::is_convertible_v < std::optional <U>&, T>
      • std::is_convertible_v <const std::optional <U>&, T>
      • std::is_convertible_v < std::optional <U>&&, T>
      • std::is_convertible_v <const std::optional <U>&&, T>
  • 此构造函数为 explicit ，若且唯若 std::is_convertible_v <U&&, T> 为 false 。
6) 构造一个含值的对象，如同从参数 std::forward <Args>(args)... 直接初始化（但不是直接列表初始化） T 类型对象一般初始化。
  • 若选择的 T 构造函数为 constexpr 构造函数，则此构造函数为 constexpr 构造函数。
  • 该函数仅若 std::is_constructible_v <T, Args...> 为 true 才参与重载决议。
7) 构造一个含值的对象，如同从参数 ilist, std::forward <Args>(args)... 直接初始化（但不是直接列表初始化） T 类型对象一般初始化。
  • 若选择的 T 构造函数为 constexpr 构造函数，则此构造函数为 constexpr 构造函数。
  • 该函数仅若 std::is_constructible_v <T, std::initializer_list <U>&, Args&&...> 为 true 才参与重载决议。
8) 构造一个含值的对象，如同从参数 std::forward <U>(value) 直接初始化（但不是直接列表初始化） T 类型对象一般初始化。
  • 若选择的 T 构造函数为 constexpr 构造函数，则此构造函数为 constexpr 构造函数。
  • 此构造函数仅若 std::is_constructible_v <T, U&&> 为 true 且 std::decay_t <U> (C++20 前)std::remove_cvref_t<U> (C++20 起) 既非 std::in_place_t 亦非 std::optional <T> 才参与重载决议。
  • 此构造函数为 explicit 若且唯若 std::is_convertible_v <U&&, T> 为 false 。

参数

other | - | 要复制其所含值的另一 optional 对象
value | - | 初始化所含值所用的值
args... | - | 初始化所含值所用的参数
ilist | - | 初始化所含值所用的 initializer_list

异常

2) 抛出任何 T 的构造函数所抛的异常。
3) 抛出任何 T 的构造函数所抛的异常。拥有下列
noexcept 说明：
noexcept( std::is_nothrow_move_constructible <T>::value)
4-8) 抛出任何 T 的构造函数所抛的异常。

示例

#include <optional>
#include <iostream>
#include <string>
int main()
{
    std::optional<int> o1, // 空
                       o2 = 1, // 从右值初始化
                       o3 = o2; // 复制构造函数

    // 调用 std::string( initializer_list<CharT> ) 构造函数
    std::optional<std::string> o4(std::in_place, {'a', 'b', 'c'});

    // 调用 std::string( size_type count, CharT ch ) 构造函数
    std::optional<std::string> o5(std::in_place, 3, 'A');

    // 从 std::string 移动构造，用推导指引拾取类型

    std::optional o6(std::string{"deduction"});

    std::cout << *o2 << ' ' << *o3 << ' ' << *o4 << ' ' << *o5  << ' ' << *o6 << '\n';
}

输出：

1 1 abc AAA deduction

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P0602R4 | C++17 | 即使底层构造函数平凡，复制/移动构造函数亦可能不平凡 | 要求传播平凡性
P2231R1 | C++20 | 源自另一 optional 的转换构造函数不是 constexpr 而要求的操作在 C++20 中能是 | 使之为 constexpr

参阅

make_optional
(C++17)
 创建一个 optional 对象
(函数模板)


std::optional<T>::or_else

< cpp‎ | utility‎ | optional
template< class F > constexpr optional or_else( F&& f ) const&; | (1) | (C++23 起)
template< class F > constexpr optional or_else( F&& f ) &&; | (2) | (C++23 起)

若 *this 含值则返回它。否则返回 f 的结果。

若 std::remove_cvref_t<std::invoke_result_t<F>> 与 std::optional <T> 不是同一类型则程序非良构。

1) 等价于 return *this ? *this : std::forward <F>(f)(); 。此重载仅若 std::copy_constructible<T> 与 std::invocable<F> 均得到实现才参与重载决议。
2) 等价于 return *this ? std::move(*this) : std::forward <F>(f)(); 。此重载仅若 std::move_constructible<T> 与 std::invocable<F> 均得到实现才参与重载决议。

参数

f - 返回 std::optional <T> 的函数或可调用 (Callable) 对象

返回值

*this 或 f 的结果，如上所示。

示例

本节未完成
原因：暂无示例

参阅

value_or | 若所含值可用则返回它，否则返回另一个值 (公开成员函数)
and_then (C++23) | 若所含值存在则返回给定的函数在其上的结果，否则返回空的 optional (公开成员函数)
transform (C++23) | 若所含值存在则返回含有变换后的所含值的 optional ，否则返回空的 optional (公开成员函数)


std::optional<T>::reset

< cpp‎ | utility‎ | optional
void reset() noexcept; | (C++17 起) (C++20 前)
constexpr void reset() noexcept; | (C++20 起)

若 *this 含值，则如同用 value().T::~T() 销毁此值。否则无效果。

*this 在此调用后不含值。

示例

#include <optional>
#include <iostream>

struct A {
    std::string s;
    A(std::string str) : s(std::move(str))  { std::cout << " constructed\n"; }
    ~A() { std::cout << " destructed\n"; }
    A(const A& o) : s(o.s) { std::cout << " copy constructed\n"; }
    A(A&& o) : s(std::move(o.s)) { std::cout << " move constructed\n"; }
    A& operator=(const A& other) {
        s = other.s;
        std::cout << " copy assigned\n";
        return *this;
    }
    A& operator=(A&& other) {
        s = std::move(other.s);
        std::cout << " move assigned\n";
        return *this;
    }
};

int main()
{
    std::cout << "Create empty optional:\n";
    std::optional<A> opt;

    std::cout << "Construct and assign value:\n";
    opt = A("Lorem ipsum dolor sit amet, consectetur adipiscing elit nec.");

    std::cout << "Reset optional:\n";
    opt.reset();
    std::cout << "End example\n";
}

输出：

Create empty optional:
Construct and assign value:
 constructed
 move constructed
 destructed
Reset optional:
 destructed
End example

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2231R1 | C++20 | reset 不是 constexpr 而 C++20 中允许非平凡析构在 constexpr 中 | 使之为 constexpr

参阅

operator=
 对内容赋值
(公开成员函数)


std::optional<T>::swap

< cpp‎ | utility‎ | optional
void swap( optional& other ) noexcept(/* see below */); | (C++17 起) (C++20 前)
constexpr void swap( optional& other ) noexcept(/* see below */); | (C++20 起)

与 other 交换内容。

  • 若 *this 和 other 均不含值，则函数无效果。
  • 若 *this 与 other 仅有一个含值（称此对象为 in ，另一者为 un ），则从 std::move(*in) 直接初始化 un 所含值，随后如同通过 in->T::~T() 析构 in 所含值。此调用后， in 不含值； un 含值。
  • 若 *this 与 other 均含值，则通过调用 std::swap (**this, *other) 交换所含值。 T 左值必须满足可交换 (Swappable) 。

若 std::is_move_constructible_v <T> 为 false 则程序非良构。

参数

other - 要交换内容的 optional 对象

返回值

（无）

异常

noexcept 说明：
noexcept( std::is_nothrow_move_constructible_v <T> &&
std::is_nothrow_swappable_v <T>)

在抛异常的情况下， *this 和 other 所含值的状态由 T 的 swap 或 T 的移动构造函数的异常安全保证确定，取决于所调用者。对于 *this 和 other ，若对象含值，则令它继续含值，反之亦然。

示例

#include <iostream>
#include <string>
#include <optional>

int main()
{
    std::optional<std::string> opt1("First example text");
    std::optional<std::string> opt2("2nd text");

    enum Swap { Before, After };
    auto print_opts = [&](Swap e) {
        std::cout << (e == Before ? "Before swap:\n" : "After swap:\n");
        std::cout << "opt1 contains '" << opt1.value_or("") << "'\n";
        std::cout << "opt2 contains '" << opt2.value_or("") << "'\n";
        std::cout << (e == Before ? "---SWAP---\n": "\n");
    };

    print_opts(Before);
    opt1.swap(opt2);
    print_opts(After);

    // 在仅一者含值时交换
    opt1 = "Lorem ipsum dolor sit amet, consectetur tincidunt.";
    opt2.reset();

    print_opts(Before);
    opt1.swap(opt2);
    print_opts(After);
}

输出：

Before swap:
opt1 contains 'First example text'
opt2 contains '2nd text'
---SWAP---
After swap:
opt1 contains '2nd text'
opt2 contains 'First example text'

Before swap:
opt1 contains 'Lorem ipsum dolor sit amet, consectetur tincidunt.'
opt2 contains ''
---SWAP---
After swap:
opt1 contains ''
opt2 contains 'Lorem ipsum dolor sit amet, consectetur tincidunt.'

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2231R1 | C++20 | swap 不是 constexpr 而要求的操作在 C++20 中能为 constexpr | 使之为 constexpr

参阅

std::swap(std::optional)
(C++17)
 特化 std::swap 算法
(函数模板)


std::swap(std::optional)

< cpp‎ | utility‎ | optional
定义于头文件 <optional>
template< class T >

void swap( std::optional <T>& lhs,

std::optional <T>& rhs ) noexcept(/* see below */);
 (C++17 起)
(C++20 前)
template< class T >

constexpr void swap( std::optional <T>& lhs,

std::optional <T>& rhs ) noexcept(/* see below */);
 (C++20 起)

对 std::optional 重载 std::swap 算法。交换 lhs 与 rhs 的状态。等效地调用 lhs.swap(rhs) 。

此重载仅若 std::is_move_constructible_v <T> 与 std::is_swappable_v <T> 皆为true 才参与重载决议。

参数

lhs, rhs - 要交换状态的 optional 对象

返回值

（无）

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))

示例

#include <iostream>
#include <optional>
#include <string>

int main()
{
    std::optional<std::string> a{"██████"}, b{"▒▒▒▒▒▒"};

    auto print = [&](auto const& s) {
        std::cout
            << s << "\t"
            << "a = " << a.value_or("(null)") << "  "
            << "b = " << b.value_or("(null)") << '\n';
    };

    print("Initially:");
    std::swap(a, b);
    print("swap(a, b):");
    a.reset();
    print("\n""a.reset():");
    std::swap(a, b);
    print("swap(a, b):");
}

输出：

Initially:     a = ██████  b = ▒▒▒▒▒▒
swap(a, b):     a = ▒▒▒▒▒▒  b = ██████

a.reset():      a = (null)  b = ██████
swap(a, b):     a = ██████  b = (null)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2231R1 | C++20 | swap 不是 constexpr 而要求的操作在 C++20 中能为 constexpr | 使之为 constexpr

参阅

swap
 交换内容
(公开成员函数)


std::optional<T>::transform

< cpp‎ | utility‎ | optional
template< class F > constexpr auto transform( F&& f ) &; | (1) | (C++23 起)
template< class F > constexpr auto transform( F&& f ) const&; | (2) | (C++23 起)
template< class F > constexpr auto transform( F&& f ) &&; | (3) | (C++23 起)
template< class F > constexpr auto transform( F&& f ) const&&; | (4) | (C++23 起)

若 *this 含值则返回含有 f 在所含值上调用结果的 std::optional 。否则返回这种类型的空 std::optional 。

结果的所含值类型（以下以 U 代表）必须为非数组对象类型，且必须不是 std::in_place_t 或 std::nullopt_t 。否则程序非良构。

1) 令 U 为 std::remove_cv_t <std::invoke_result_t<F, T&>> 。若 *this 含值，则返回所含值从 std::invoke ( std::forward <F>(f), this->value()) 直接非列表初始化的 std::optional <U> 。否则返回空的 std::optional <U> 。
若变量定义 U x( std::invoke ( std::forward <F>(f), this->value())); 非良构则程序非良构。
2) 同 (1) ，除了 U 为 std::remove_cv_t <std::invoke_result_t<F, const T&>> 。
3) 令 U 为 std::remove_cv_t <std::invoke_result_t<F, T>> 。若 *this 含值，则返回所含值从 std::invoke ( std::forward <F>(f), std::move(this->value())) 直接非列表初始化的 std::optional <U> 。否则返回空的 std::optional <U> 。
若变量定义 U x( std::invoke ( std::forward <F>(f), std::move(this->value()))); 非良构则程序非良构。
4) 同 (3) ，除了 U 为 std::remove_cv_t <std::invoke_result_t<F, const T>> 。

参数

f - 适合的函数或可调用 (Callable) 对象

返回值

含有 f 的结果的 std::optional 或空 std::optional ，如上所属。

注解

因为 transform 直接在正确的位置构造 U 对象，而非将它传递给构造函数， std::is_move_constructible_v <U> 能为 false 。

有些语言称此操作为 map 。

示例

本节未完成
原因：暂无示例

参阅

value_or | 若所含值可用则返回它，否则返回另一个值 (公开成员函数)
and_then (C++23) | 若所含值存在则返回给定的函数在其上的结果，否则返回空的 optional (公开成员函数)
or_else (C++23) | 若 optional 含值则返回其自身，否则返回给定函数的结果 (公开成员函数)


std::optional<T>::value

< cpp‎ | utility‎ | optional
constexpr T& value() &;
constexpr const T& value() const&;
 (1) (C++17 起)
constexpr T&& value() &&;
constexpr const T&& value() const&&;
 (2) (C++17 起)

若 *this 含值，则返回到所含值引用。

否则，抛出 std::bad_optional_access 异常。

参数

（无）

返回值

到所含值的引用。

异常

若 *this 不含值则抛出 std::bad_optional_access 。

注解

解引用运算符 operator*() 不检查此 optional 是否含值，它可能比 value() 更有效率。

示例

#include <optional>
#include <iostream>
int main()
{
    std::optional<int> opt = {};

    try {
        int n = opt.value();
    } catch(const std::exception& e) {
        std::cout << e.what() << '\n';
    }
}

可能的输出：

bad optional access

参阅

value_or | 若所含值可用则返回它，否则返回另一个值 (公开成员函数)
operator->operator* | 访问所含值 (公开成员函数)
bad_optional_access (C++17) | 指示进行了到不含值的 optional 的有检查访问的异常 (类)


std::optional<T>::value_or

< cpp‎ | utility‎ | optional
template< class U > constexpr T value_or( U&& default_value ) const&; | (1) | (C++17 起)
template< class U > constexpr T value_or( U&& default_value ) &&; | (2) | (C++17 起)

若 *this 拥有值则返回其所含的值，否则返回 default_value 。

1) 等价于 bool(*this) ? **this : static_cast<T>( std::forward <U>(default_value))
2) 等价于 bool(*this) ? std::move(**this) : static_cast<T>( std::forward <U>(default_value))

参数

default_value - 用于 *this 为空情况的值
类型要求
-
为使用重载 (1) ， T 必须满足可复制构造 (CopyConstructible) 的要求。
-
为使用重载 (2) ， T 必须满足可移动构造 (MoveConstructible) 的要求。
-
U&& 必须可转换为 T

返回值

若 *this 拥有值则为其当前值，否则为 default_value 。

异常

返回值 T 的被选择构造函数所抛的任何异常。

示例

#include <optional>
#include <iostream>
#include <cstdlib>

std::optional<const char*> maybe_getenv(const char* n)
{
    if(const char* x = std::getenv(n))
       return x;
    else
       return {};
}
int main()
{
     std::cout << maybe_getenv("MYPWD").value_or("(none)") << '\n';
}

可能的输出：

(none)

参阅

value
 返回所含值
(公开成员函数)


std::optional<T>::~optional

< cpp‎ | utility‎ | optional
~optional(); | (C++17 起) (C++20 前)
constexpr ~optional(); | (C++20 起)

若对象含值且类型 T 非可平凡析构（见 std::is_trivially_destructible ），则如同以 value().T::~T() 一般，通过调用其析构函数销毁所含值。

否则，不做任何事。

注解

若 T 为可平凡析构，则此析构函数亦为平凡，故 std::optional <T> 亦为可平凡析构。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2231R1 | C++20 | 析构函数不是 constexpr ，而非平凡析构函数在 C++20 中能为 constexpr | 使之为 constexpr


std::pair

< cpp‎ | utility
定义于头文件 <utility>
template<

class T1,
class T2

> struct pair;

std::pair 是类模板，提供在一个单元存储两个相异类型对象的途径。 pair 是 std::tuple 的拥有两个元素的特殊情况。

若 T1 与 T2 都不是可能有 cv 限定的拥有非平凡析构函数的类类型，或其数组，则 pair 的析构函数为平凡。

模板形参

T1, T2 - pair 所存储的元素类型。

成员类型

成员类型 | 定义
first_type | T1
second_type | T2

成员对象

成员名 | 类型
first | T1
second | T2

成员函数

(构造函数) | 构造新的 pair (公开成员函数)
operator= | 对 内容赋值 (公开成员函数)
swap (C++11) | 交换内容 (公开成员函数)

非成员函数

make_pair | 创建一个 pair 对象，其类型根据各实参类型定义 (函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 按字典序比较 pair 中的值 (函数模板)
std::swap(std::pair) (C++11) | 特化 std::swap 算法 (函数模板)
std::get(std::pair) (C++11) | 访问 pair 的一个元素 (函数模板)

辅助类

std::tuple_size<std::pair> (C++11) | 获得 pair 的大小 (类模板特化)
std::tuple_element<std::pair> (C++11) | 获得 pair 中元素的类型 (类模板特化)

推导指引 (C++17 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2796 | C++98 | pair 的析构函数的平凡性未指明 | 已指明

参阅

tuple (C++11) | 实现固定大小的容器，它保有类型可以相异的元素 (类模板)
tie | 创建左值引用的 tuple，或将 tuple 解包为独立对象 (函数模板)


std::pair 的推导指引

< cpp‎ | utility‎ | pair
定义于头文件 <utility> |
template<class T1, class T2> pair(T1, T2) -> pair<T1, T2>; | (C++17 起)

为 std::pair 提供一个推导指引，以涵盖隐式推导指引所遗漏的极端情况。

特别是不可复制参数及数组到指针转换。

示例

#include <utility>

int main()
{
    int a[2], b[3];
    std::pair p{a, b}; // 显示推导指引用于此情况
}


std::get(std::pair)

< cpp‎ | utility‎ | pair
定义于头文件 <utility>
(1)
template< std::size_t I, class T1, class T2 >

typename std::tuple_element <I, std::pair <T1,T2> >::type&

get( std::pair <T1, T2>& p ) noexcept;
 (C++11 起)
(C++14 前)
template< std::size_t I, class T1, class T2 >

constexpr std::tuple_element_t <I, std::pair <T1,T2> >&

get( std::pair <T1, T2>& p ) noexcept;
 (C++14 起)
(2)
template< std::size_t I, class T1, class T2 >

const typename std::tuple_element <I, std::pair <T1,T2> >::type&

get( const std::pair <T1,T2>& p ) noexcept;
 (C++11 起)
(C++14 前)
template< std::size_t I, class T1, class T2 >

constexpr const std::tuple_element_t <I, std::pair <T1,T2> >&

get( const std::pair <T1,T2>& p ) noexcept;
 (C++14 起)
(3)
template< std::size_t I, class T1, class T2 >

typename std::tuple_element <I, std::pair <T1,T2> >::type&&

get( std::pair <T1,T2>&& p ) noexcept;
 (C++11 起)
(C++14 前)
template< std::size_t I, class T1, class T2 >

constexpr std::tuple_element_t <I, std::pair <T1,T2> >&&

get( std::pair <T1,T2>&& p ) noexcept;
 (C++14 起)
(4)
template< std::size_t I, class T1, class T2 >

const typename std::tuple_element <I, std::pair <T1,T2> >::type&&

get( const std::pair <T1,T2>&& p ) noexcept;
 (C++11 起)
(C++14 前)
template< std::size_t I, class T1, class T2 >

constexpr const std::tuple_element_t <I, std::pair <T1,T2> >&&

get( const std::pair <T1,T2>&& p ) noexcept;
 (C++14 起)
template <class T, class U>
constexpr T& get( std::pair <T, U>& p) noexcept;
 (5) (C++14 起)
template <class T, class U>
constexpr const T& get(const std::pair <T, U>& p) noexcept;
 (6) (C++14 起)
template <class T, class U>
constexpr T&& get( std::pair <T, U>&& p) noexcept;
 (7) (C++14 起)
template <class T, class U>
constexpr const T&& get(const std::pair <T, U>&& p) noexcept;
 (8) (C++14 起)
template <class T, class U>
constexpr T& get( std::pair <U, T>& p) noexcept;
 (9) (C++14 起)
template <class T, class U>
constexpr const T& get(const std::pair <U, T>& p) noexcept;
 (10) (C++14 起)
template <class T, class U>
constexpr T&& get( std::pair <U, T>&& p) noexcept;
 (11) (C++14 起)
template <class T, class U>
constexpr const T&& get(const std::pair <U, T>&& p) noexcept;
 (12) (C++14 起)

用仿 tuple 的接口从 pair 提取元素。

若序号 I 不是 0 或 1 则基于范围的重载 (1-4) 无法编译。

若类型 T 与 U 相同则基于类型的重载 (5-12) 无法编译。

参数

p - 要提取内容的 pair

返回值

1-4) 若 I==0 则返回到 p.first 的引用，若 I==1 则返回到 p.second 的引用。
5-8) 返回到 p.first 的引用。
9-12) 返回到 p.second 的引用。

示例

#include <iostream>
#include <utility>

int main()
{
    auto p = std::make_pair(1, 3.14);
    std::cout << '(' << std::get<0>(p) << ", " << std::get<1>(p) << ")\n";
    std::cout << '(' << std::get<int>(p) << ", " << std::get<double>(p) << ")\n";
}

输出：

(1, 3.14)
(1, 3.14)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2485 | C++11 （按索引） C++14 （按类型） | 无对于 const pair&& 的重载 | 添加重载

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
std::get(std::tuple) | 元组式访问指定的元素 (函数模板)
std::get(std::array) | 访问 array 的一个元素 (函数模板)
std::get(std::variant) (C++17) | 以给定索引或类型（若类型唯一）读取 variant 的值，错误时抛出异常 (函数模板)


std::make_pair

< cpp‎ | utility‎ | pair
定义于头文件 <utility> |
template< class T1, class T2 > std::pair <T1,T2> make_pair( T1 t, T2 u ); | (C++11 前)
template< class T1, class T2 > std::pair <V1,V2> make_pair( T1&& t, T2&& u ); | (C++11 起) (C++14 前)
template< class T1, class T2 > constexpr std::pair <V1,V2> make_pair( T1&& t, T2&& u ); | (C++14 起)

构造 std::pair 对象，从参数类型推导目标类型。

推导结果类型 V1 与 V2 是 std::decay <T1>::type 与 std::decay <T2>::type （应用到按值传递的函数参数的通常类型变换），除非应用 std::decay 到某类型 X 产生 std::reference_wrapper <X> ，此情况下推导结果类型是 X& 。

 (C++11 起)

参数

t, u - 构造 pair 所用的值

返回值

含有指定值的 std::pair 对象。

示例

#include <iostream>
#include <utility>
#include <functional>

int main()
{
    int n = 1;
    int a[5] = {1, 2, 3, 4, 5};

    // 从二个 int 建造 pair
    auto p1 = std::make_pair(n, a[1]);
    std::cout << "The value of p1 is "
              << "(" << p1.first << ", " << p1.second << ")\n";

    // 从到 int 的引用和数组（退化成指针）建造 pair
    auto p2 = std::make_pair(std::ref(n), a);
    n = 7;
    std::cout << "The value of p2 is "
              << "(" << p2.first << ", " << *(p2.second + 2) << ")\n";
}

输出：

The value of p1 is (1, 2)
The value of p2 is (7, 3)

参阅

unwrap_referenceunwrap_ref_decay
(C++20)(C++20)
 获取包装于 std::reference_wrapper 的引用类型
(类模板)


std::pair<T1,T2>::operator=

< cpp‎ | utility‎ | pair
 | (1)
pair& operator=( const pair& other ); |  | (C++20 前)
constexpr pair& operator=( const pair& other ); |  | (C++20 起)
 | (2)
template< class U1, class U2 > pair& operator=( const pair<U1,U2>& other ); |  | (C++11 起) (C++20 前)
template< class U1, class U2 > constexpr pair& operator=( const pair<U1,U2>& other ); |  | (C++20 起)
 | (3)
pair& operator=( pair&& other ) noexcept(/* see below */); |  | (C++11 起) (C++20 前)
constexpr pair& operator=( pair&& other ) noexcept(/* see below */); |  | (C++20 起)
 | (4)
template< class U1, class U2 > pair& operator=( pair<U1,U2>&& other ); |  | (C++11 起) (C++20 前)
template< class U1, class U2 > constexpr pair& operator=( pair<U1,U2>&& other ); |  | (C++20 起)

替换 pair 的内容。

1) 复制赋值运算符。以 other 内容的副本替换内容。
  • 此赋值运算符被隐式声明。若 first_type 或 second_type 之一为 const 限定类型，或引用类型，或拥有不可访问的复制赋值运算符的类类型，或这种类的数组类型，则使用此赋值运算符令程序为谬构。
 (C++11 前)
  • 若 std::is_copy_assignable <first_type>::value 或 std::is_copy_assignable <second_type>::value 之一为 false ，则定义此重载为被删除。
 (C++11 起)
2) 赋值 other.first 给 first ， other.second 给 second
此重载仅若 std::is_assignable <first_type&, const U1&>::value 与 std::is_assignable <second_type&, const U2&>::value 均为 true 才参与重载决议。
3) 移动赋值运算符。用移动语义以 other 的内容替换内容。
此重载仅若 std::is_move_assignable <first_type>::value 与 std::is_move_assignable <second_type>::value 均为 true 才参与重载决议。
4) 赋值 std::forward <U1>(p.first) 给 first ， std::forward <U2>(p.second) 给 second 。
此重载仅若 std::is_assignable <first_type&, U1>::value 与 std::is_assignable <second_type&, U2>::value 均为 true 才参与重载决议。

参数

other - 替换此 pair 的值的 pair

返回值

*this

异常

1-2) 可能抛出实现定义的异常。
3)
noexcept 说明：
noexcept(

std::is_nothrow_move_assignable <T1>::value &&
std::is_nothrow_move_assignable <T2>::value

)
4) 可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2729 | C++11 | pair::operator= 未被约束并可能导致不必要的未定义行为 | 已约束

参阅


operator==,!=,<,<=,>,>=,<=>(std::pair)

< cpp‎ | utility‎ | pair
定义于头文件 <utility>
(1)
template< class T1, class T2 >
bool operator==( const std::pair <T1,T2>& lhs, const std::pair <T1,T2>& rhs );
 (C++14 前)
template< class T1, class T2 >

constexpr bool operator==( const std::pair <T1,T2>& lhs,

const std::pair <T1,T2>& rhs );
 (C++14 起)
(2)
template< class T1, class T2 >
bool operator!=( const std::pair <T1,T2>& lhs, const std::pair <T1,T2>& rhs );
 (C++14 前)
template< class T1, class T2 >

constexpr bool operator!=( const std::pair <T1,T2>& lhs,

const std::pair <T1,T2>& rhs );
 (C++14 起)
(C++20 前)
(3)
template< class T1, class T2 >
bool operator<( const std::pair <T1,T2>& lhs, const std::pair <T1,T2>& rhs );
 (C++14 前)
template< class T1, class T2 >

constexpr bool operator<( const std::pair <T1,T2>& lhs,

const std::pair <T1,T2>& rhs );
 (C++14 起)
(C++20 前)
(4)
template< class T1, class T2 >
bool operator<=( const std::pair <T1,T2>& lhs, const std::pair <T1,T2>& rhs );
 (C++14 前)
template< class T1, class T2 >

constexpr bool operator<=( const std::pair <T1,T2>& lhs,

const std::pair <T1,T2>& rhs );
 (C++14 起)
(C++20 前)
(5)
template< class T1, class T2 >
bool operator>( const std::pair <T1,T2>& lhs, const std::pair <T1,T2>& rhs );
 (C++14 前)
template< class T1, class T2 >

constexpr bool operator>( const std::pair <T1,T2>& lhs,

const std::pair <T1,T2>& rhs );
 (C++14 起)
(C++20 前)
(6)
template< class T1, class T2 >
bool operator>=( const std::pair <T1,T2>& lhs, const std::pair <T1,T2>& rhs );
 (C++14 前)
template< class T1, class T2 >

constexpr bool operator>=( const std::pair <T1,T2>& lhs,

const std::pair <T1,T2>& rhs );
 (C++14 起)
(C++20 前)
template< class T1, class T2 >

constexpr /* see below */ operator<=>( const std::pair <T1,T2>& lhs,

const std::pair <T1,T2>& rhs );
 (7) (C++20 起)
1-2) 测试 lhs 和 rhs 的两个元素是否均相等，即比较 lhs.first 和 rhs.first 及 lhs.second 和 rhs.second
3-6) 用 operator< 按字典序比较 lhs 和 rhs ，即比较首元素，然后仅若它们等价，再比较第二元素。
7) 用合成三路比较按字典序比较 lhs 和 rhs ，即比较首元素，然后仅若它们等价，再比较第二元素。
返回类型为 T1 与 T2 上的合成三路比较类型的结果类型的共用比较类别类型。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

合成三路比较

给定对象类型 T ，分别作为左操作数和右操作数的二个 const T 左值 lhs 与 rhs ，合成三路比较定义为：

  • 若满足 std::three_way_comparable_with<T, T> ，则等价于 lhs <=> rhs;
  • 否则，若以 operator< 比较二个 const T 左值为良构且结果类型满足 boolean-testable ，则等价于
lhs < rhs ? std::weak_ordering::less :
rhs < lhs ? std::weak_ordering::greater :
            std::weak_ordering::equivalent
  • 否则不定义合成三路比较，这使得 operator<=> 不参与重载决议。

若 three_way_comparable_with 或 boolean-testable 被满足但未被实现，则 operator<=> 的行为未定义。

 (C++20 起)

参数

lhs, rhs - 要比较的 pair

返回值

1) 若 lhs.first == rhs.first 且 lhs.second == rhs.second 则为 true ，否则为 false
2) !(lhs == rhs)
3) 若 lhs.first<rhs.first 则返回 true 。否则，若 rhs.first<lhs.first 则返回 false 。否则，若 lhs.second<rhs.second 则返回 true 。否则返回 false 。
4) !(rhs < lhs)
5) rhs < lhs
6) !(lhs < rhs)
7) 若 synth_three_way(lhs.first, rhs.first) 不等于 0 则为它，否则为 synth_three_way(lhs.second, rhs.second) ，其中 synth_three_way 是仅用于阐释的进行合成三路比较的函数对象。

示例

因为 operator< 为 pair 定义，故 pair 的容器能排序。

#include <iostream>
#include <utility>
#include <vector>
#include <algorithm>
#include <string>

int main()
{
    std::vector<std::pair<int, std::string>> v = { {2, "baz"},
                                                   {2, "bar"},
                                                   {1, "foo"} };
    std::sort(v.begin(), v.end());

    for(auto p: v) {
        std::cout << "(" << p.first << "," << p.second << ")\n";
    }
}

输出：

(1,foo)
(2,bar)
(2,baz)


std::pair<T1,T2>::pair

< cpp‎ | utility‎ | pair
(1)
pair();
 (C++11 前)
constexpr pair();
 (C++11 起)
(条件性 explicit)
(2)
pair( const T1& x, const T2& y );
 (C++11 前)
pair( const T1& x, const T2& y );
 (C++11 起)
(C++14 前)
(条件性 explicit)
constexpr pair( const T1& x, const T2& y );
 (C++14 起)
(条件性 explicit)
(3)
template< class U1, class U2 >
pair( U1&& x, U2&& y );
 (C++11 起)
(C++14 前)
(条件性 explicit)
template< class U1, class U2 >
constexpr pair( U1&& x, U2&& y );
 (C++14 起)
(C++23 前)
(条件性 explicit)
template< class U1 = T1, class U2 = T2 >
constexpr pair( U1&& x, U2&& y );
 (C++23 起)
(条件性 explicit)
(4)
template< class U1, class U2 >
pair( const pair<U1, U2>& p );
 (C++11 前)
template< class U1, class U2 >
pair( const pair<U1, U2>& p );
 (C++11 起)
(C++14 前)
(条件性 explicit)
template< class U1, class U2 >
constexpr pair( const pair<U1, U2>& p );
 (C++14 起)
(条件性 explicit)
(5)
template< class U1, class U2 >
pair( pair<U1, U2>&& p );
 (C++11 起)
(C++14 前)
(条件性 explicit)
template< class U1, class U2 >
constexpr pair( pair<U1, U2>&& p );
 (C++14 起)
(条件性 explicit)
(6)
template< class... Args1, class... Args2 >

pair( std::piecewise_construct_t,
std::tuple <Args1...> first_args,

std::tuple <Args2...> second_args );
 (C++11 起)
(C++20 前)
template< class... Args1, class... Args2 >

constexpr pair( std::piecewise_construct_t,
std::tuple <Args1...> first_args,

std::tuple <Args2...> second_args );
 (C++20 起)
pair( const pair& p ) = default;
 (7)
pair( pair&& p ) = default;
 (8) (C++11 起)

构造新的 pair 。

1) 默认构造函数。值初始化 pair 的两个元素 first 和 second 。
  • 此构造函数参与重载决议，当且仅当 std::is_default_constructible_v <first_type> 与 std::is_default_constructible_v <second_type> 均为 true 。
  • 此构造函数为 explicit ，当且仅当 first_type 或 second_type 不可隐式默认构造。
 (C++11 起)
2) 以 x 初始化 first 并以 y 初始化 second 。
  • 此构造函数参与重载决议，当且仅当 std::is_copy_constructible_v <first_type> 与 std::is_copy_constructible_v <second_type> 均为 true 。
  • 此构造函数为 explicit ，当且仅当 std::is_convertible_v <const first_type&, first_type> 为 false 或 std::is_convertible_v <const second_type&, second_type> 为 false 。
 (C++11 起)
3) 以 std::forward <U1>(x) 初始化 first 并以 std::forward <U2>(y) 初始化 second 。
  • 此构造函数参与重载决议，当且仅当 std::is_constructible_v <first_type, U1&&> 和 std::is_constructible_v <second_type, U2&&> 均为 true 。
  • 此构造函数为 explicit ，当且仅当 std::is_convertible_v <U1&&, first_type> 为 false 或 std::is_convertible_v <U2&&, second_type> 为 false 。
4) 以 p.first 初始化 first 并以 p.second 初始化 second 。
  • 此构造函数参与重载决议，当且仅当 std::is_constructible_v <first_type, const U1&> 和 std::is_constructible_v <second_type, const U2&> 均为 true 。
  • 此构造函数为 explicit ，当且仅当 std::is_convertible_v <const U1&, first_type> 为 false 或 std::is_convertible_v <const U2&, second_type> 为 false 。
 (C++11 起)
5) 以 std::forward <U1>(p.first) 初始化 first 并以 std::forward <U2>(p.second) 初始化 second 。
  • 此构造函数参与重载决议，当且仅当 std::is_constructible_v <first_type, U1&&> 和 std::is_constructible_v <second_type, U2&&> 均为 true 。
  • 此构造函数为 explicit ，当且仅当 std::is_convertible_v <U1&&, first_type> 为 false 或 std::is_convertible_v <U2&&, second_type> 为 false 。
6) 转发 first_args 的元素到 first 的构造函数并转发 second_args 的元素到 second 的构造函数。这是能用于构造不可复制不可移动类型的 pair 的仅有的非默认构造函数。
7) 复制构造函数为隐式声明 (C++11 前)默认化，且若两个元素的复制满足 constexpr 函数的要求则为 constexpr (C++11 起)。
8) 移动构造函数为默认化，且若两个元素的移动满足 constexpr 函数的要求则为 constexpr 。

参数

x | - | 初始化此 pair 首元素的值
y | - | 初始化此 pair 第二元素的值
p | - | 用于初始化此 pair 两个元素的值的 pair
first_args | - | 初始化此 pair 首元素的构造函数参数的 tuple
second_args | - | 初始化此 pair 第二元素的构造函数参数的 tuple

异常

不抛异常，除非指定操作之一（如元素的构造）抛出。

示例

#include <utility>
#include <string>
#include <complex>
#include <tuple>
#include <iostream>

int main()
{
    auto print = [](auto rem, auto const& pair) {
        std::cout << rem << "(" << pair.first << ", " << pair.second << ")\n";
    };

    std::pair<int, float> p1;
    print("(1) Value-initialized: ", p1);

    std::pair<int, double> p2{42, 3.1415};
    print("(2) Initialized with two values: ", p2);

    std::pair<char, int> p4{p2};
    print("(4) Implicitly converted: ", p4);

    std::pair<std::complex<double>, std::string> p6{
                    std::piecewise_construct,
                    std::forward_as_tuple(0.123, 7.7),
                    std::forward_as_tuple(10, 'a')};
    print("(6) Piecewise constructed: ", p6);
}

可能的输出：

(1) Value-initialized: (0, 0)
(2) Initialized with two values: (42, 3.1415)
(4) Implicitly converted: (*, 3)
(6) Piecewise constructed: ((0.123,7.7), aaaaaaaaaa)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
N4387 | C++11 | 某些构造函数曾为 explicit ，阻止了有用的行为 | 使大多数构造函数为条件性 explicit
LWG 2510 | C++11 | 默认构造函数为隐式 | 使之为条件性 explicit

参阅

make_pair
 创建一个 pair 对象，其类型根据各实参类型定义
(函数模板)


std::pair<T1,T2>::swap

< cpp‎ | utility‎ | pair
void swap(pair& other) noexcept(/* see below */); | (C++11 起) (C++20 前)
constexpr void swap(pair& other) noexcept(/* see below */); | (C++20 起)

交换 first 与 other.first 及 second 与 other.second 。

参数

other - 要交换值的 pair

返回值

（无）

异常

noexcept 说明：
noexcept(

noexcept(swap(first, other.first)) &&
noexcept(swap(second, other.second))

)

在上述表达式中，按照与 C++17 std::is_nothrow_swappable 特性所用的相同方式查找标识符 swap 。

 (C++17 前)
noexcept 说明：
noexcept(

std::is_nothrow_swappable_v <first_type> &&
std::is_nothrow_swappable_v <second_type>

)
 (C++17 起)

示例

#include <iostream>
#include <utility>
#include <string>
int main()
{
    std::pair<int, std::string> p1, p2;
    p1 = std::make_pair(10, "test");
    p2.swap(p1);
    std::cout << "(" << p2.first << ", " << p2.second << ")\n";
}

输出：

(10, test)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2456 | C++11 | noexcept 指定曾为病式 | 令之有效

参阅

swap
 交换两个对象的值
(函数模板)


std::swap(std::pair)

< cpp‎ | utility‎ | pair
定义于头文件 <utility> |
template< class T1, class T2 > void swap( pair<T1,T2>& x, pair<T1,T2>& y ) noexcept(/* see below */); | (C++11 起) (C++20 前)
template< class T1, class T2 > constexpr void swap( pair<T1,T2>& x, pair<T1,T2>& y ) noexcept(/* see below */); | (C++20 起)

交换 x 与 y 的内容。等价于 x.swap(y) 。

此函数仅若 std::is_swappable_v <first_type> && std::is_swappable_v <second_type> 为 true 才参与重载决议。

 (C++17 起)

参数

x, y - 要交换内容的 pair

返回值

（无）

异常

noexcept 说明：
noexcept(noexcept(x.swap(y)))

参阅

swap
 交换两个对象的值
(函数模板)


std::tuple_element<std::pair>

< cpp‎ | utility‎ | pair
定义于头文件 <utility>
template< std::size_t I, class T1, class T2 >
struct tuple_element<I, std::pair <T1, T2>>;
 (C++11 起)

std::tuple_element 对 pair 的部分特化使用类 tuple 语法，提供 pair 元素类型的编译时访问。若 I >= 2 则程序为病式。

成员类型

成员类型 | 定义
type | I == 0 则为 T1 I == 1 则为 T2

可能的实现

template<std::size_t I, typename T>
  struct tuple_element;

template<std::size_t I, typename T1, typename T2>
  struct tuple_element<I, std::pair<T1,T2> >
  {
     static_assert(I < 2, "std::pair has only 2 elements!");
  };

template<typename T1, typename T2>
  struct tuple_element<0, std::pair<T1,T2> >
  {
     using type = T1;
  };

template<typename T1, typename T2>
  struct tuple_element<1, std::pair<T1,T2> >
  {
     using type = T2;
  };

示例

#include <tuple>
#include <iostream>
#include <string>

namespace detail {

template <std::size_t>
struct index_tag { explicit constexpr index_tag() = default; };

template <class T, class U>
constexpr T get_val_dispatch(std::pair<T, U> const& pair, index_tag<0>)
{
    return pair.first;
}

template <class T, class U>
constexpr U get_val_dispatch(std::pair<T, U> const& pair, index_tag<1>)
{
    return pair.second;
}

} // namespace detail

template <std::size_t N, class T, class U>
auto constexpr get_val(std::pair<T, U> const& pair)
    -> typename std::tuple_element<N, std::pair<T, U>>::type
{
    return detail::get_val_dispatch(pair, detail::index_tag<N>{});
}

int main()
{
    auto var = std::make_pair(1, std::string{"one"});

    std::cout << get_val<0>(var) << " = " << get_val<1>(var);
}

输出：

1 = one

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2974 | C++11 | 越界下标使用不定义的初等模板 | 使之为非良构（硬错误）

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
std::tuple_element<std::tuple> (C++11) | 获得指定元素的类型 (类模板特化)
std::tuple_element<std::array> (C++11) | 获得 array 元素的类型 (类模板特化)
std::tuple_size<std::pair> (C++11) | 获得 pair 的大小 (类模板特化)


std::tuple_size<std::pair>

< cpp‎ | utility‎ | pair
定义于头文件 <utility>
template <class T1, class T2>

struct tuple_size< std::pair <T1, T2>>

: std::integral_constant < std::size_t, 2> { };
 (C++11 起)

std::tuple_size 对 pair 的部分特化提供使用类 tuple 语法，在编译时获得 pair 中元素数的方法，该数总是 2 。

继承自 std::integral_constant

成员常量

value
[静态]
 常数值 2
(公开静态成员常量)

成员函数

operator std::size_t | 转换对象为 std::size_t ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | std::size_t
type | std::integral_constant < std::size_t, value>

示例

#include <iostream>
#include <utility>
#include <tuple>

template<class T>
void test(T t)
{
    int a[std::tuple_size<T>::value]; // 可用于编译时
    std::cout << std::tuple_size<T>::value << '\n'; // 或运行时
}

int main()
{
    test(std::make_tuple(1, 2, 3.14));
    test(std::make_pair(1, 3.14));
}

输出：

3
2

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2313 | C++11 | 未要求对 pair 的特化派生自 integral_constant | 已要求

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
std::tuple_size<std::tuple> (C++11) | 在编译时获得 tuple 的大小 (类模板特化)
std::tuple_size<std::array> (C++11) | 获得 array 的大小 (类模板特化)
std::tuple_element<std::pair> (C++11) | 获得 pair 中元素的类型 (类模板特化)


std::piecewise_construct

< cpp‎ | utility
定义于头文件 <utility> |
constexpr std::piecewise_construct_t piecewise_construct{}; | (C++11 起) (C++17 前)
inline constexpr std::piecewise_construct_t piecewise_construct{}; | (C++17 起)

常量 std::piecewise_construct 是空的结构体标签类型 std::piecewise_construct_t 的实例。

示例

#include <iostream>
#include <utility>
#include <tuple>

struct Foo {
    Foo(std::tuple<int, float>)
    {
        std::cout << "Constructed a Foo from a tuple\n";
    }
    Foo(int, float)
    {
        std::cout << "Constructed a Foo from an int and a float\n";
    }
};

int main()
{
    std::tuple<int, float> t(1, 3.14);
    std::pair<Foo, Foo> p1(t, t);
    std::pair<Foo, Foo> p2(std::piecewise_construct, t, t);
}

输出：

Constructed a Foo from a tuple
Constructed a Foo from a tuple
Constructed a Foo from an int and a float
Constructed a Foo from an int and a float

参阅

piecewise_construct_t (C++11) | 用于为逐段构造选择正确函数重载的标签类型 (类)
(构造函数) | 构造新的 pair (std::pair<T1,T2> 的公开成员函数)


std::piecewise_construct_t

< cpp‎ | utility
定义于头文件 <utility> |
struct piecewise_construct_t { explicit piecewise_construct_t() = default; }; | (C++11 起)

std::piecewise_construct_t 是用于在接收二个 tuple 参数的不同函数间消歧义的空类标签类型。

不使用 std::piecewise_construct_t 的重载假设每个 tuple 参数各变成一个 pair 的元素。使用 std::piecewise_construct_t 的重载假设每个 tuple 参数用于逐块构造一个指定类型的新对象，而它将成为 pair 的元素。

示例

#include <iostream>
#include <utility>
#include <tuple>

struct Foo {
    Foo(std::tuple<int, float>)
    {
        std::cout << "Constructed a Foo from a tuple\n";
    }
    Foo(int, float)
    {
        std::cout << "Constructed a Foo from an int and a float\n";
    }
};

int main()
{
    std::tuple<int, float> t(1, 3.14);
    std::pair<Foo, Foo> p1(t, t);
    std::pair<Foo, Foo> p2(std::piecewise_construct, t, t);
}

输出：

Constructed a Foo from a tuple
Constructed a Foo from a tuple
Constructed a Foo from an int and a float
Constructed a Foo from an int and a float

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2510 | C++11 | 默认构造函数为非 explicit ，能导致歧义 | 使之为 explicit

参阅

piecewise_construct (C++11) | 用于为逐段构造的函数消歧义的 piecewise_construct_t 类型的对象 (常量)
(构造函数) | 构造新的 pair (std::pair<T1,T2> 的公开成员函数)


程序支持工具

< cpp‎ | utility

程序终止

下列函数管理程序终止和资源清理。

定义于头文件 <cstdlib>
abort | 导致非正常的程序终止（不进行清理） (函数)
exit | 导致正常的程序终止并进行清理 (函数)
quick_exit (C++11) | 导致快速程序终止，不进行完全的清理 (函数)
_Exit (C++11) | 导致正常的程序终止，不进行清理 (函数)
atexit | 注册将于调用 std::exit() 时被调用的函数 (函数)
at_quick_exit (C++11) | 注册将于调用 quick_exit 时被调用的函数 (函数)
EXIT_SUCCESSEXIT_FAILURE | 指示程序执行的执行状态 (宏常量)

与环境交流

system | 调用宿主环境的命令处理器 (函数)
getenv | 访问环境变量列表 (函数)

信号

为信号管理提供数个函数与宏常量。

定义于头文件 <csignal>
signal
 为特定信号设置信号处理函数
(函数)
raise
 为特定信号运行信号处理函数
(函数)
sig_atomic_t
 能从非同步信号处理函数作为原子实体访问的整数类型
(typedef)
SIG_DFLSIG_IGN
 定义信号处理策略
(宏常量)
SIG_ERR
 signal 的返回值，说明遇到错误
(宏常量)
信号类型
SIGABRTSIGFPESIGILLSIGINTSIGSEGVSIGTERM
 定义信号类型
(宏常量)

非局部跳转

定义于头文件 <csetjmp>
setjmp
 保存语境
(宏函数)
longjmp
 跳转到指定位置
(函数)
类型
jmp_buf
 执行语境类型
(typedef)

参阅


EXIT_SUCCESS, EXIT_FAILURE

< cpp‎ | utility‎ | program
定义于头文件 <cstdlib>
#define EXIT_SUCCESS /*implementation defined*/
#define EXIT_FAILURE /*implementation defined*/

EXIT_SUCCESS 与 EXIT_FAILURE 展开成能用做 std::exit 函数的参数（从而能用做从 main 函数返回的值），并指示程序执行状态的整数常量表达式。

常量 | 描述
EXIT_SUCCESS | 程序的成功执行
EXIT_FAILURE | 程序的不成功执行

注意

EXIT_SUCCESS 与值零均指示成功的程序执行状态（见 std::exit ），尽管不要求 EXIT_SUCCESS 等于零。

参阅


SIG_ERR

< cpp‎ | utility‎ | program
定义于头文件 <csignal>
#define SIG_ERR /* implementation defined */

void (*)(int) 类型的值。为 std::signal 返回时，指示发生错误。

参阅

signal
 为特定信号设置信号处理函数
(函数)


SIG_DFL, SIG_IGN

< cpp‎ | utility‎ | program
定义于头文件 <csignal>
#define SIG_DFL /*implementation defined*/
#define SIG_IGN /*implementation defined*/

SIG_DFL 与 SIG_IGN 宏展开成不等于任何函数地址的整数常量表达式。宏为 std::signal () 函数定义信号处理策略。

常量 | 解释
SIG_DFL | 默认信号处理
SIG_IGN | 忽略信号

参阅


SIGTERM, SIGSEGV, SIGINT, SIGILL, SIGABRT, SIGFPE

< cpp‎ | utility‎ | program
定义于头文件 <csignal>
#define SIGTERM /*implementation defined*/
#define SIGSEGV /*implementation defined*/
#define SIGINT /*implementation defined*/
#define SIGILL /*implementation defined*/
#define SIGABRT /*implementation defined*/
#define SIGFPE /*implementation defined*/

上述每个宏都展开成有不同值的整数常量表达式，各代表发送给程序的不同信号。

常量 | 解释
SIGTERM | 发送给程序的终止请求
SIGSEGV | 非法内存访问（分段错误）
SIGINT | 外部中断，通常为用户所起始
SIGILL | 非法程序映像，例如非法指令
SIGABRT | 异常终止条件，例如为 std::abort() 所起始
SIGFPE | 错误算术运算，例如除以零

注意

附加的信号名为 POSIX 所指定

参阅

signal | 为特定信号设置信号处理函数 (函数)
raise | 为特定信号运行信号处理函数 (函数)


std::_Exit

< cpp‎ | utility‎ | program
定义于头文件 <cstdlib> |
[[noreturn]] void _Exit( int exit_code ) noexcept; | (C++11 起)

导致正常程序终止出现，而不清理资源。

不调用拥有自动、线程局域和静态存储期对象的析构函数。不调用传递给 std::at_quick_exit() 或 std::atexit() 的函数。是否关闭打开的资源，例如文件，是实现定义的。

若 exit_code 为 0 或 EXIT_SUCCESS ，则返回宿主环境指示成功终止的实现定义状态。若 exit_code 为 EXIT_FAILURE ，则返回指示不成功终止的实现定义状态。其他情况下返回实现定义状态值。

参数

exit_code - 程序的退出状态

返回值

（无）

示例

#include <iostream>

class Static {
public:
    ~Static()
    {
        std::cout << "Static dtor\n";
    }
};

class Local {
public:
    ~Local()
    {
        std::cout << "Local dtor\n";
    }
};

Static static_variable; // 此对象的析构函数将*不*被调用

void atexit_handler()
{
    std::cout << "atexit handler\n";
}

int main()
{
    Local local_variable; // 将*不*调用析构函数

    // 将*不*调用处理函数
    const int result = std::atexit(atexit_handler);

    if (result != 0) {
        std::cerr << "atexit registration failed\n";
        return EXIT_FAILURE;
    }

    std::cout << "test" << std::endl; // 从 std::endl 冲入
        // 需要再次，否则不会打印内容
    std::_Exit(EXIT_FAILURE);
}

输出：

test

参阅

abort | 导致非正常的程序终止（不进行清理） (函数)
exit | 导致正常的程序终止并进行清理 (函数)


std::abort

< cpp‎ | utility‎ | program
定义于头文件 <cstdlib> |
void abort(); | (C++11 前)
[[noreturn]] void abort() noexcept; | (C++11 起)

导致不正常程序终止，除非传递给 std::signal 的信号处理函数正在捕捉 SIGABRT ，且该处理函数不返回。

不调用拥有自动、线程局域 (C++11 起)和静态存储期的对象的析构函数。亦不调用以 std::atexit() 和 std::at_quick_exit (C++11 起) 注册的函数。是否关闭打开的资源，例如文件是实现定义的。返回给宿主环境指示不成功执行的实现定义状态。

参数

（无）

返回值

（无）

异常

不抛出。

注解

POSIX 指定 abort() 函数撤除阻塞，或忽略 SIGABRT 信号。

某些编译器内建子程序，例如 __builtin_trap （ gcc、 clang 及 icc ）或 __debugbreak （ msvc ），能用于尽可能快地终止程序。

示例

#include <csignal>
#include <iostream>
#include <cstdlib>

class Tester {
public:
    Tester()  { std::cout << "Tester ctor\n"; }
    ~Tester() { std::cout << "Tester dtor\n"; }
};

Tester static_tester; // 不调用析构函数

void signal_handler(int signal)
{
    if (signal == SIGABRT) {
        std::cerr << "SIGABRT received\n";
    } else {
        std::cerr << "Unexpected signal " << signal << " received\n";
    }
    std::_Exit(EXIT_FAILURE);
}

int main()
{
    Tester automatic_tester; // 不调用析构函数

    // 安装处理函数
    auto previous_handler = std::signal(SIGABRT, signal_handler);
    if (previous_handler == SIG_ERR) {
        std::cerr << "Setup failed\n";
        return EXIT_FAILURE;
    }

    std::abort();  // 引发 SIGABRT
    std::cout << "This code is unreachable\n";
}

输出：

Tester ctor
Tester ctor
SIGABRT received

参阅

exit | 导致正常的程序终止并进行清理 (函数)
atexit | 注册将于调用 std::exit() 时被调用的函数 (函数)
quick_exit (C++11) | 导致快速程序终止，不进行完全的清理 (函数)
at_quick_exit (C++11) | 注册将于调用 quick_exit 时被调用的函数 (函数)
signal | 为特定信号设置信号处理函数 (函数)
terminate | 异常处理失败时调用的函数 (函数)


std::at_quick_exit

< cpp‎ | utility‎ | program
定义于头文件 <cstdlib>
int at_quick_exit( /*atexit-handler*/* func ) noexcept;
int at_quick_exit( /*c-atexit-handler*/* func ) noexcept;
 (1) (C++11 起)
extern "C++" using /*atexit-handler*/ = void(); // 仅用于阐释
extern "C" using /*c-atexit-handler*/ = void(); // 仅用于阐释
 (2)

注册 func 所指向的函数，使得在快速程序终止时调用它（通过 std::quick_exit ）。

从多个线程调用此函数不引起数据竞争。实现要支持至少注册 32 个函数。

正常程序终止时不调用注册的函数。若需要在该情况下调用函数，则必须使用 std::atexit 。

参数

func - 指向要在快速程序终止时调用的函数的指针

返回值

若注册成功则为 ​0​ ，否则为非零值。

注解

二个重载有别，因为参数 func 类型有别（语言链接是其类型的一部分）。

示例

本节未完成
原因：暂无示例

参阅

abort | 导致非正常的程序终止（不进行清理） (函数)
exit | 导致正常的程序终止并进行清理 (函数)
atexit | 注册将于调用 std::exit() 时被调用的函数 (函数)
quick_exit (C++11) | 导致快速程序终止，不进行完全的清理 (函数)


std::atexit

< cpp‎ | utility‎ | program
定义于头文件 <cstdlib>
(1)
int atexit( /*c-atexit-handler*/* func );
int atexit( /*atexit-handler*/* func );
 (C++11 前)
int atexit( /*c-atexit-handler*/* func ) noexcept;
int atexit( /*atexit-handler*/* func ) noexcept;
 (C++11 起)
extern "C++" using /*atexit-handler*/ = void(); // 仅为说明
extern "C" using /*c-atexit-handler*/ = void(); // 仅为说明
 (2)

注册 func 所指向的函数，使得在正常程序中止（通过 std::exit() 或从 main 函数返回）时调用它。

可能在静态对象析构期间以逆序调用函数：若 A 先于 B 被注册，则对 B 的调用先进行于对 A 的调用。同样的规则应用于静态对象构造函数和到 atexit 的调用：见 std::exit 。 | (C++11 前)
函数可能与拥有静态存储期的对象的析构函数，或彼此间并发调用，这保持保证若 A 的注册先序于 B 的注册，则对 B 的调用先序于对 A 的调用，同样的规则应用于静态对象构造函数和到 atexit 的调用：见 std::exit 。 | (C++11 起)

可以注册同一函数多于一次。

若函数通过异常退出，则调用 std::terminate 。

atexit 是线程安全的：从数个线程调用函数不引入数据竞争。

保证实现支持注册至少 32 个函数。准确限制是实现定义的。

参数

func - 指向正常程序终止时要调用的函数的指针

返回值

若注册成功则为 ​0​ ，否则为非零值。

注解

二个重载有别，因为参数 func 类型有别（语言链接是其类型的一部分）。

示例

#include <iostream>
#include <cstdlib>

void atexit_handler_1()
{
    std::cout << "at exit #1\n";
}

void atexit_handler_2()
{
    std::cout << "at exit #2\n";
}

int main()
{
    const int result_1 = std::atexit(atexit_handler_1);
    const int result_2 = std::atexit(atexit_handler_2);

    if ((result_1 != 0) || (result_2 != 0)) {
        std::cerr << "Registration failed\n";
        return EXIT_FAILURE;
    }

    std::cout << "returning from main\n";
    return EXIT_SUCCESS;
}

输出：

returning from main
at exit #2
at exit #1

参阅

abort | 导致非正常的程序终止（不进行清理） (函数)
exit | 导致正常的程序终止并进行清理 (函数)
quick_exit (C++11) | 导致快速程序终止，不进行完全的清理 (函数)
at_quick_exit (C++11) | 注册将于调用 quick_exit 时被调用的函数 (函数)


std::exit

< cpp‎ | utility‎ | program
定义于头文件 <cstdlib> |
void exit( int exit_code ); | (C++11 前)
[[noreturn]] void exit( int exit_code ); | (C++11 起)

导致正常程序终止发生。

进行一些清理步骤：

1) 以其动态初始化完成或构造函数完成的逆序，调用拥有静态存储期的对象的析构函数，并以注册的逆序（从尾到首）调用传递给 std::atexit 的函数。 a) 任何静态对象，之初始化完成先于 std::atexit 对某函数 F 调用者，将于程序终止期间后于 F 的调用销毁。 b) 任何静态对象，之初始化开始后于 std::atexit 对某函数 F 调用者，将于程序终止期间先于 F 的调用销毁（这包含从该静态对象的构造函数调用 std::atexit 的情况）。 | (C++11 前)
1) 拥有关联到当前线程的线程局域存储期的对象的析构函数、拥有静态存储期的对象的析构函数及以 std::atexit 注册的函数并发执行，同时保持下列保证： a) 线程局域对象的最末析构函数先序于静态对象的首个析构函数。 b) 若线程局域或静态对象 A 的构造函数或动态初始化完成先序于线程局域或静态对象 B ，则 B 的析构完成先序于 A 的析构开始。 c) 若静态对象 A 的初始化完成先序于 std::atexit 对某函数 F 的调用，则在终止期间到 F 的调用先序于 A 的析构开始。 d) 若 std::atexit 对某函数 F 的调用先序于静态对象 A 的初始化完成，则终止期间 A 的析构开始先序于 F 的调用。 e) 若 std::atexit 对某函数 F1 的调用先序于 std::atexit 对某函数 F2 的调用，则终止期间 F2 的调用先序于 F1 的调用。 | (C++11 起)
  • 以上内容中，
  • 若任何以 atexit 注册的函数或任何静态/线程局域对象的析构函数抛出异常，则调用 std::terminate 。
  • 若编译器将对象动态初始化提升到非局部初始化的静态初始化阶段，则析构顺序忠实于其本应有的动态初始化。
  • 若函数局域（块作用域）静态对象被销毁，然后该函数从另一静态对象被调用，且控制流经过该对象的定义（或若它被间接使用，则是经过指针或引用），则行为未定义。
  • 若函数局域（块作用域）静态对象在对象或数组的构造期间初始化，则仅在销毁该类的所有子对象或该数组的所有元素后才销毁它。
2) 冲入并关闭所有 C 流
3) 移除 std::tmpfile 所创建的文件
4) 将控制返回给宿主环境。若 exit_code 为 0 或 EXIT_SUCCESS ，则返回实现定义的指示成功终止的状态。若 exit_code 为 EXIT_FAILURE ，则返回实现定义的指示不成功终止的状态。任何其他情况下返回实现定义的状态值。

不回溯栈：不调用拥有自动存储期变量的析构函数。

与 main 函数的关系

从 main 函数以 return 语句或以抵达函数尾返回，会进行正常函数终止（调用拥有自动存储期的对象的析构函数），再执行 std::exit ，将 return 语句的参数（或若使用隐式 return 则为 ​0​ ）作为 exit_code 传递。

参数

exit_code - 程序的退出状态

返回值

（无）

示例

#include <iostream>
#include <cstdlib>

class Static {
public:

    ~Static()
    {
        std::cout << "Static dtor\n";
    }
};

class Local {
public:
    ~Local()
    {
        std::cout << "Local dtor\n";
    }
};

Static static_variable; // *将*调用此对象的析构函数

void atexit_handler()
{
    std::cout << "atexit handler\n";
}

int main()
{
    Local local_variable; // 将*不*调用此对象的析构函数
    const int result = std::atexit(atexit_handler); // 将调用处理函数

    if (result != 0) {
        std::cerr << "atexit registration failed\n";
        return EXIT_FAILURE;
    }

    std::cout << "test\n";
    std::exit(EXIT_FAILURE);
}

输出：

test
atexit handler
Static dtor

参阅

abort | 导致非正常的程序终止（不进行清理） (函数)
atexit | 注册将于调用 std::exit() 时被调用的函数 (函数)
quick_exit (C++11) | 导致快速程序终止，不进行完全的清理 (函数)
at_quick_exit (C++11) | 注册将于调用 quick_exit 时被调用的函数 (函数)


std::getenv

< cpp‎ | utility‎ | program
定义于头文件 <cstdlib>
char* getenv( const char* env_var );

于宿主环境（操作系统）提供的环境列表搜索匹配 env_var 所指向的 C 字符串，并返回指向与匹配的列表成员关联的 C 字符串的指针。

不要求此函数为线程安全。到 getenv 的另一调用，还有到 POSIX 函数 setenv() 、 unsetenv() 及 putenv() 的调用可能非法化先前调用所返回的指针，或修改从先前调用得到的字符串。 | (C++11 前)
只要无其他函数修改宿主环境，则此函数为线程安全（从多个线程调用它不引入数据竞争）。尤其是若无同步地调用，则 POSIX 函数 setenv() 、 unsetenv() 及 putenv() 会引入数据竞争。 | (C++11 起)

修改 getenv 所返回的字符串引起未定义行为。

参数

env_var - 标识要查找的环境变量名的空终止字符串

返回值

标识环境变量值的字符串，或若找不到这种字符串则为空指针。

注解

POSIX 系统上，环境变量亦可通过于 <unistd.h> 声明为 extern char **environ; 的全局变量 environ ，及通过可选的 main 函数第三参数 envp 访问。

示例

#include <iostream>
#include <cstdlib>

int main()
{
    if(const char* env_p = std::getenv("PATH"))
        std::cout << "Your PATH is: " << env_p << '\n';
}

可能的输出：

Your PATH is: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

参阅


std::jmp_buf

< cpp‎ | utility‎ | program
定义于头文件 <csetjmp>
typedef /* unspecified */ jmp_buf;

std::jmp_buf 类型是适合存储信息，以恢复到调用方环境的数组类型。存储的信息足以恢复在程序的正确块的信息，和该块的调用。浮点状态标志，或打开的文件，或任何其他数据不存储于 jmp_buf 类型对象。

参阅

setjmp | 保存语境 (宏函数)
longjmp | 跳转到指定位置 (函数)


std::longjmp

< cpp‎ | utility‎ | program
定义于头文件 <csetjmp> |
void longjmp( std::jmp_buf env, int status ); | (C++17 前)
[[noreturn]] void longjmp( std::jmp_buf env, int status ); | (C++17 起)

加载先前的 setjmp 调用所保存的执行环境 env 。此函数不返回。控制被转移到设置了 env 的宏 setjmp 的调用点。该 setjmp 随后返回作为 status 传递的值。

若调用了 setjmp 的函数已退出，则行为未定义（换言之，仅允许在调用栈向上长跳）

不调用任何自动对象的析构函数。若以 throw 替换 std::longjmp 且以 catch 替换 setjmp 会执行任何自动对象的非平凡析构函数，则这种 std::longjmp 的行为未定义。

参数

env | - | 指代 setjmp 所保存的函数执行状态的变量
status | - | 从 setjmp 返回的值。若它等于 ​0​ ，则以用 1 代替

返回值

（无）

注意

longjmp 是 C 中处理函数无法有意义返回处的错误条件的机制。 C++ 通常为此目的使用异常处理。

示例

#include <iostream>
#include <csetjmp>

std::jmp_buf jump_buffer;

[[noreturn]] void a(int count)
{
    std::cout << "a(" << count << ") called\n";
    std::longjmp(jump_buffer, count+1);  // setjump() 将返回 count+1
}

int main()
{
    volatile int count = 0; // 必须为 setjmp 设定局部变量为 volatile
    if (setjmp(jump_buffer) != 9) {
        a(count++);  // This will cause setjmp() to exit
    }
}

输出：

a(0) called
a(1) called
a(2) called
a(3) called
a(4) called
a(5) called
a(6) called
a(7) called
a(8) called

参阅

setjmp
 保存语境
(宏函数)


std::quick_exit

< cpp‎ | utility‎ | program
定义于头文件 <cstdlib> |
[[noreturn]] void quick_exit( int exit_code ) noexcept; | (C++11 起)

导致正常程序终止发生，而不完全清理资源。

以注册顺序的逆序调用传递给 std::at_quick_exit 的函数。若异常试图传播出任何这些函数，则调用 std::terminate 。调用注册的函数后，调用 std::_Exit (exit_code) 。

不调用传递给 std::atexit 的函数。

参数

exit_code - 程序的退出状态

返回值

（无）

示例

本节未完成
原因：暂无示例

参阅

abort | 导致非正常的程序终止（不进行清理） (函数)
exit | 导致正常的程序终止并进行清理 (函数)
atexit | 注册将于调用 std::exit() 时被调用的函数 (函数)
at_quick_exit (C++11) | 注册将于调用 quick_exit 时被调用的函数 (函数)


std::raise

< cpp‎ | utility‎ | program
定义于头文件 <csignal>
int raise( int sig );

发送信号 sig 给程序。调用信号处理函数（用 std::signal() 函数指定）。

若仍未用 std::signal() 设置用户定义的处理策略，则忽略信号还是调用默认处理函数是实现定义的。

参数

sig - 要发送的信号。可以是实现定义值或下列值之一：
SIGABRTSIGFPESIGILLSIGINTSIGSEGVSIGTERM
 定义信号类型
(宏常量)

返回值

成功时为 ​0​ ，失败时为非零值。

示例

#include <csignal>
#include <iostream>

void signal_handler(int signal)
{
    std::cout << "Received signal " << signal << '\n';
}

int main()
{
    // 安装信号处理函数
    std::signal(SIGTERM, signal_handler);

    std::cout << "Sending signal " << SIGTERM << '\n';
    std::raise(SIGTERM);
}

可能的输出：

Sending signal 15
Received signal 15

参阅

signal
 为特定信号设置信号处理函数
(函数)


setjmp

< cpp‎ | utility‎ | program
定义于头文件 <csetjmp>
#define setjmp(env) /* implementation-defined */

保存当前执行环境到 std::jmp_buf 类型变量 env 。std::longjmp 函数稍后可用此变量恢复当前执行环境。即在调用 std::longjmp 函数时，执行在构造了传递给 std::longjmp 的 std::jmp_buf 特定调用点继续。该情况下 setjmp 返回传递给 std::longjmp 的值。

setjmp 的调用必须只出现在下列语境之一：

  • if 、 switch 、 while 、 do-while 、 for 语句的整个控制表达式
switch(setjmp(env)) { ..
  • 比较或等于运算符的操作数之一，而另一操作数是整数常量表达式，产生的表达式是 if 、 switch 、 while 、 do-while 、 for 语句的整个控制表达式。
if(setjmp(env) > 0) { ...
  • 一元 ! 运算符的操作数，产生的表达式是 if 、 switch 、 while 、 do-while 、 for 语句的整个控制表达式。
while(!setjmp(env)) { ...
  • 表达式语句（可以转型到 void ）的整个表达式。
setjmp(env);

若 setjmp 出现于任何其他语境，则行为未定义。

一旦返回到 setjmp 的作用域，所有可访问对象、浮点状态标志及其他抽象机组件拥有与在执行 std::longjmp 时相同的值，除了含有 setjmp 调用的函数中的非 volatile 局部对象，在 setjmp 调用后更改它们，则其值不确定。

参数

env - 保存程序执行状态的变量。

返回值

若宏被原始代码调用且执行环境存储于 env 则返回 ​0​ 。

若刚进行了非局部跳转则返回非零值。返回值同传递给 std::longjmp 的值。

注解

上述要求禁止在数据流中使用 setjmp 的返回值（例如以之初始化或赋值对象）。只能将返回值用于控制流或舍弃。

示例

#include <iostream>
#include <csetjmp>

std::jmp_buf jump_buffer;

[[noreturn]] void a(int count)
{
    std::cout << "a(" << count << ") called\n";
    std::longjmp(jump_buffer, count+1);  // setjump() 将返回 count+1
}

int main()
{
    volatile int count = 0; // 在 setjmp 作用域中被修改的局部变量必须是 volatile
    if (setjmp(jump_buffer) != 9) { // 在一个 if 内不等于常量表达式
        a(++count);  // 这会导致 setjmp() 退出
    }
}

输出：

a(1) called
a(2) called
a(3) called
a(4) called
a(5) called
a(6) called
a(7) called
a(8) called

参阅

longjmp
 跳转到指定位置
(函数)


std::sig_atomic_t

< cpp‎ | utility‎ | program
定义于头文件 <csignal>
typedef /* unspecified */ sig_atomic_t;

即使在信号所为的异步中断的存在中，都能作为原子实体访问的整数类型。

注解

在引入 std::atomic 和 std::atomic_signal_fence 的 C++11 前，严格遵从程序在信号处理函数所能做的唯有赋值给 volatile static std::sig_atomic_t 变量并立即返回。

参阅

signal | 为特定信号设置信号处理函数 (函数)
atomic_signal_fence (C++11) | 线程与执行于同一线程的信号处理函数间的栅栏 (函数)


std::signal

< cpp‎ | utility‎ | program
定义于头文件 <csignal> |
/*signal-handler*/* signal(int sig, /*signal-handler*/* handler); | (1)
extern "C" using /*signal-handler*/ = void(int); // 仅为说明 | (2)

为信号 sig 设置处理函数。可设置信号处理函数以令默认处理发生、信号被忽略或用户定义函数得到调用。

当信号处理函数被设为函数，且信号发生时，在信号处理函数开始之前是否立即执行 std::signal(sig, SIG_DFL ) 是实现定义的。而且实现可以避免某些信号的实现定义集在信号处理函数运行时出现。

对于某些信号，程序开始时是否调用 std::signal(sig, SIG_IGN ) 所实现定义的。对于剩余函数，实现必须调用 std::signal(sig, SIG_DFL ) 。

（注意： POSIX 引入了 sigaction 以标准化这些实现定义行为）

参数

sig - 要设置信号处理函数的信号。它可以是实现定义值或下例值之一：
SIGABRTSIGFPESIGILLSIGINTSIGSEGVSIGTERM
 定义信号类型
(宏常量)

handler - 信号处理函数。这必须是下列之一：
  • SIG_DFL 宏。信号处理函数被设为默认信号处理函数。
  • SIG_IGN 宏。忽略信号。
  • 指向函数指针。函数签名必须等价于如下：
extern "C" void fun(int sig);

返回值

成功时为先前的信号处理函数，失败时为 SIG_ERR （某些实现上能禁用设置信号处理函数）。

信号处理函数

下列限制被加诸被安装为信号处理函数的用户定义函数。

若信号处理函数不作为 std::abort 或 std::raise （异步信号）的结果调用，则行为未定义，若

  • 信号处理函数调用任何标准库中的函数，除了
  • std::abort
  • std::_Exit
  • std::quick_exit
  • std::signal ，以当前处理的信号的数字为首参数（异步处理函数能重注册其自身，但不能注册其他函数）。
  • 信号处理函数涉及任何拥有静态或线程局域(C++11 起)存储期的对象，且其类型不是 std::atomic(C++11 起) 或 volatile std::sig_atomic_t.
 (C++17 前)

若任何信号处理函数进行任何下列操作，则行为未定义：

  • 调用任何库函数，除了下列信号安全函数（注意，尤其是动态分配函数不是信号安全的）：
  • std::atomic 的成员函数和来自 <atomic> 的非成员函数，若它们所操作的原子类型是免锁的。函数 std::atomic_is_lock_free 及 std::atomic::is_lock_free 对所有原子类型信号安全。
  • std::signal ，以当前处理的信号的数字为首参数（异步处理函数能重注册其自身，但不能注册其他函数）。
  • std::numeric_limits 的函数
  • std::_Exit
  • std::abort
  • std::quick_exit
  • std::initializer_list 的成员函数及 std::begin 与 std::end 的 std::initializer_list 重载
  • std::forward 、 std::move 、 std::move_if_noexcept
  • 所有来自 <type_traits> 的函数
  • std::memcpy 与 std::memmove
  • 访问拥有线程存储期的对象
  • dynamic_cast 表达式
  • throw 表达式
  • 进入 try 块，包含函数 try 块
  • 初始化进行动态非局部初始化的静态变量（包含延迟直至首次 ODR 使用者）
  • 等待任何有静态存储期变量的初始化完成，由于另一线程共时初始化之
 (C++17 起)

若在处理 SIGFPE 、 SIGILL 、 SIGSEGV 或任何实现定义的指定计算性异常的其他信号时，用户定义函数返回，则行为未定义。

若信号处理函数作为 std::abort 或 std::raise （异步调用）的结果调用，则行为未定义，若信号处理函数调用 std::raise 。

在信号处理函数入口，浮点环境的状态和所有对象的值都是未指定的，除了

  • volatile std::sig_atomic_t 类型对象
  • 无锁 std::atomic 类型对象(C++11 起)
  • 通过 std::atomic_signal_fence 设为可见的副效应(C++11 起)

从信号处理函数返回时，任何信号处理函数所修改的，非 volatile std::sig_atomic_t 或免锁 std::atomic 对象的值是不确定的。

 (C++14 前)

对函数 signal() 的调用同步于任何信号处理函数调用的结果。

若信号处理函数作为到 std::raise （同步）的调用结果执行，则处理函数的执行后序于 std::raise 的调用并先序于从它返回，并与 std::raise 运行于同一线程。其他信号处理函数的执行对于程序其余部分是无序的，并且运行于未指定的线程。

若对同一 volatile std::sig_atomic_t 类型对象的二次访问出现于同一线程，则它们不导致数据竞争，即使在信号处理函数中出现一或多次。 对每次信号处理函数调用，调用信号处理函数的线程所进行的求值可分为二组 A 与 B ，满足 B 中无求值先发生于 A 中的求值，且这种 volatile std::sig_atomic_t 对象的求值采用该值，如同 A 中所有求值先发生于信号函数的执行，且信号函数的求值先发生于 B 中所有求值。

 (C++14 起)

注意

POSIX 要求 signal 为线程安全，且指定一个异步信号安全库函数的列表，它们能从任何信号处理函数调用。

信号处理函数被期待拥有 C 链接，而且通常只使用 C 与 C++ 的公共子集。拥有 C++ 链接的函数能否用作信号处理函数是实现定义的。

示例

#include <csignal>
#include <iostream>

namespace
{
  volatile std::sig_atomic_t gSignalStatus;
}

void signal_handler(int signal)
{
  gSignalStatus = signal;
}

int main()
{
  // 安装信号处理函数
  std::signal(SIGINT, signal_handler);

  std::cout << "SignalValue: " << gSignalStatus << '\n';
  std::cout << "Sending signal " << SIGINT << '\n';
  std::raise(SIGINT);
  std::cout << "SignalValue: " << gSignalStatus << '\n';
}

可能的输出：

SignalValue: 0
Sending signal 2
SignalValue: 2

参阅

raise | 为特定信号运行信号处理函数 (函数)
atomic_signal_fence (C++11) | 线程与执行于同一线程的信号处理函数间的栅栏 (函数)


std::system

< cpp‎ | utility‎ | program
定义于头文件 <cstdlib>
int system( const char* command );

以参数 command 调用运行环境的命令处理器（例如 /bin/sh 、 cmd.exe 、 command.com ）。返回相应实现的定义值（通常是被调用程序所返回的值）。

若 command 为空，则检查运行环境是否有命令处理器，并当且仅当命令行存在才返回非零。

参数

command - 标识要运行于命令处理器的命令字符串。若给出空指针，则检查命令处理器的存在性

返回值

实现定义值。若 command 为空指针，则当且仅当命令处理器存在才返回非零值。

注意

POSIX 系统上，可用 WEXITSTATUS 和 WSTOPSIG 分解返回值。

相关的 POSIX 函数 popen 使调用方可获取到 command 生成的输出。

示例

#include <cstdlib>
#include <fstream>
#include <iostream>

int main()
{
    std::system("ls -l >test.txt"); // 执行 UNIX 命令 "ls -l >test.txt"
    std::cout << std::ifstream("test.txt").rdbuf();
}

可能的输出：

total 16
-rwxr-xr-x 1 2001 2000 8859 Sep 30 20:52 a.out
-rw-rw-rw- 1 2001 2000  161 Sep 30 20:52 main.cpp
-rw-r--r-- 1 2001 2000    0 Sep 30 20:52 test.txt

参阅


std::ranges::swap

< cpp‎ | utility
定义于头文件 <concepts>
inline namespace /* unspecified */ {

inline constexpr /* unspecified */ swap = /* unspecified */;

}
 (C++20 起)
(定制点对象)
调用签名
template< class T, class U >

requires /* see below */

constexpr void swap(T&& t, U&& u) noexcept(/* see below */);

交换 t 和 u 所引用的值。

调用 ranges::swap ：

  1. 表达式等价于 (void)swap( std::forward <T>(t), std::forward <U>(u)) ，若以下列候选进行重载决议则该表达式合法：
    • template<class T> void swap(T&, T&) = delete;
    • template<class T, std::size_t N> void swap(T(&)[N], T(&)[N]) = delete;
    • 实参依赖查找所找到的任何 swap 的声明。
    若重载决议所选择的函数不交换 t 和 u 所引用的值，则程序为谬构；不要求诊断。
  2. 否则表达式等价于 (void)ranges::swap_ranges(t, u) ，除了 noexcept(ranges::swap(t), ranges::swap(u)) 等于 noexcept(ranges::swap(*t, *u)) ，若 T 和 U 为到相等长度（但元素类型可能不同）的数组类型的左值引用，且 ranges::swap(*t, *u) 为合法表达式；
  3. 否则如同用 V v(std::move(t)); t = std::move(u); u = std::move(v); 交换其被引用值，若 T 与 U 均为 V& ，而 V 是满足 std::move_constructible<V> 和 std::assignable_from<V&, V> 的某个类型，
    • 调用是否为潜在抛出由上述操作指定。
    • 若上述操作与以交换 u 与 v 进行的上述操作均可用于常量求值，则调用为常量子表达式。
    若任一概念未被实现，则程序为谬构；不要求诊断。
  4. 所有其他情况下，对 ranges::swap 的调用为谬构，这能在 ranges::swap(t, u) 出现于模板实例化的立即语境时导致替换失败。

表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

定制点对象

名字 ranges::swap 代表一个定制点对象，它是字面 semiregular 类类型的 const 函数对象。为说明目的，以 __swap_fn 表示其类型的 cv 无限定版本。

__swap_fn 的所有实例均相等。在相同参数上调用类型 __swap_fn 的不同实例的效果是等价的，无关乎指代该实例的表达式是左值还是右值，以及是否为 const 限定（然而不要求 volatile 限定的实例可调用）。从而能自由地复制 ranges::swap 并且能彼此替代地使用其副本。

给定类型集合 Args... ，若 std::declval <Args>()... 满足上面对于 ranges::swap 的参数要求，则 __swap_fn 实现 std::invocable<__swap_fn, Args...>、 std::invocable<const __swap_fn, Args...>、 std::invocable<__swap_fn&, Args...> 及 std::invocable<const __swap_fn&, Args...> 。否则， __swap_fn 的函数调用运算符不参与重载决议。

示例

#include <array>
#include <concepts>
#include <iostream>
#include <ranges>
#include <string_view>
#include <vector>

void print(std::string_view const name,
           std::ranges::common_range auto const& p,
           std::ranges::common_range auto const& q)
{
    std::cout << name << "1{ ";
    for (auto const& i : p) std::cout << i << ' ';
    std::cout << "}, " << name << "2{ ";
    for (auto const& i : q) std::cout << i << ' ';
    std::cout << "}\n";
}

void print(std::string_view const name, int p, int q)
{
    std::cout << name << "1 = " << p << ", " << name << "2 = " << q << '\n';
}

int main()
{
    std::vector a1{10,11,12}, a2{13,14};
    std::ranges::swap(a1, a2);
    print("a", a1, a2);

    std::array b1{15,16,17}, b2{18,19,20};
    std::ranges::swap(b1, b2);
    print("b", b1, b2);

    // std::array c1{1,2,3}; std::array c2{4,5};
    // std::ranges::swap(c1, c2); // 错误：类型不匹配

    int d1[]{21,22,23}, d2[]{24,25,26};
    std::ranges::swap(d1, d2);
    print("d", d1, d2);

    // int e1[]{1,2,3}, e2[]{4,5};
    // std::ranges::swap(e1, e2); // 错误：类型不匹配

    // char f1[]{1,2,3};
    // int  f2[]{4,5,6};
    // std::ranges::swap(f1, f2); // 错误：类型不匹配

    int g1{27}, g2{28};
    std::ranges::swap(g1, g2);
    print("g", g1, g2);
}

输出：

a1{ 13 14 }, a2{ 10 11 12 }
b1{ 18 19 20 }, b2{ 15 16 17 }
d1{ 24 25 26 }, d2{ 21 22 23 }
g1 = 28, g2 = 27

参阅

swappableswappable_with (C++20) | 指定一个类型能进行交换，或两个类型能彼此交换 (概念)
swap | 交换两个对象的值 (函数模板)


std::rel_ops::operator!=,>,<=,>=

< cpp‎ | utility
定义于头文件 <utility> |  |
template< class T > bool operator!=( const T& lhs, const T& rhs ); | (1) | (C++20 中弃用)
template< class T > bool operator>( const T& lhs, const T& rhs ); | (2) | (C++20 中弃用)
template< class T > bool operator<=( const T& lhs, const T& rhs ); | (3) | (C++20 中弃用)
template< class T > bool operator>=( const T& lhs, const T& rhs ); | (4) | (C++20 中弃用)

给定用户为类型 T 对象提供的 operator== 和 operator< ，实现其他比较运算符的通常语义。

1) 用 operator== 实现 operator!= 。

2) 用 operator< 实现 operator> 。

3) 用 operator< 实现 operator<= 。

4) 用 operator< 实现 operator>= 。

参数

lhs | - | 左侧参数
rhs | - | 右侧参数

返回值

1) 若 lhs 不等于 rhs 则返回 true 。

2) 若 lhs 大于 rhs 则返回 true 。

3) 若 lhs 小于或等于 rhs 则返回 true 。

4) 若 lhs 大于或等于 rhs 则返回 true 。

可能的实现

版本一
namespace rel_ops {
    template< class T >
    bool operator!=( const T& lhs, const T& rhs )
    {
        return !(lhs == rhs);
    }
}
版本二
namespace rel_ops {
    template< class T >
    bool operator>( const T& lhs, const T& rhs )
    {
        return rhs < lhs;
    }
}
版本三
namespace rel_ops {
    template< class T >
    bool operator<=( const T& lhs, const T& rhs )
    {
        return !(rhs < lhs);
    }
}
版本四
namespace rel_ops {
    template< class T >
    bool operator>=( const T& lhs, const T& rhs )
    {
        return !(lhs < rhs);
    }
}

注解

Boost.operators 提供更为通用的 std::rel_ops 替代品。

C++20 起， std::rel_ops 由于让位给 operator<=> 而被弃用。

示例

#include <iostream>
#include <utility>

struct Foo {
    int n;
};

bool operator==(const Foo& lhs, const Foo& rhs)
{
    return lhs.n == rhs.n;
}

bool operator<(const Foo& lhs, const Foo& rhs)
{
    return lhs.n < rhs.n;
}

int main()
{
    Foo f1 = {1};
    Foo f2 = {2};
    using namespace std::rel_ops;

    std::cout << std::boolalpha;
    std::cout << "not equal?     : " << (f1 != f2) << '\n';
    std::cout << "greater?       : " << (f1 > f2) << '\n';
    std::cout << "less equal?    : " << (f1 <= f2) << '\n';
    std::cout << "greater equal? : " << (f1 >= f2) << '\n';
}

输出：

not equal?     : true
greater?       : false
less equal?    : true
greater equal? : false


std::source_location

< cpp‎ | utility
定义于头文件 <source_location> |
struct source_location; | (C++20 起)

source_location 类表示关于源码的具体信息，例如文件名、行号以及函数名。以前，希望获得关于调用位置的信息（用于记录、测试或调试目的）的函数必须使用宏，以令如 __LINE__ 与 __FILE__ 的预定义宏于调用方的环境展开。 source_location 类提供更好的替代。

source_location 符合可默认构造 (DefaultConstructible) 、可复制构造 (CopyConstructible) 、可复制赋值 (CopyAssignable) 及可析构 (Destructible) 要求。 source_location 的左值符合可交换 (Swappable) 要求。 另外，下列条件为 true ：

  • std::is_nothrow_move_constructible_v <std::source_location> 、
  • std::is_nothrow_move_assignable_v <std::source_location> 及
  • std::is_nothrow_swappable_v <std::source_location> 。

有意令 source_location 拥有较小的大小并且能高效复制。

source_location 的复制/移动构造函数与复制/移动赋值运算符是否为平凡和/或 constexpr 是未指明的。

成员函数

创建
(构造函数)
 构造拥有实现定义的值的新 source_location
(公开成员函数)
current
[静态]
 构造对应调用点位置的新 source_location
(公开静态成员函数)
域访问
line
 返回此对象所表示的行号
(公开成员函数)
column
 返回此对象所表示的列号
(公开成员函数)
file_name
 返回此对象所表示的文件名
(公开成员函数)
function_name
 返回此对象表示的函数名，若它存在
(公开成员函数)

示例

#include <iostream>
#include <string_view>
#include <source_location>

void log(std::string_view message,
         const std::source_location& location = std::source_location::current())
{
    std::cout << "info:"
              << location.file_name() << ':'
              << location.line() << ' '
              << message << '\n';
}

int main()
{
    log("Hello world!");
}

可能的输出：

info:main.cpp:15 Hello world!

参阅

stacktrace_entry
(C++23)
 栈踪中求值的表示
(类)


std::source_location::column

< cpp‎ | utility‎ | source location
constexpr std::uint_least32_t column() const noexcept; | (C++20 起)

返回表示从此对象所表示的行起始的偏移的实现定义值（即列号）。列号预设为从 1 开始。

参数

（无）

返回值

表示从此对象所表示的行起始的偏移的实现定义值（即列号）。

鼓励实现在列号未知时使用 0 。

示例

#include <iostream>
#include <string_view>
#include <source_location>

template<typename T = std::source_location>
inline void pos(const T& location = T::current())
{
    std::cout
        << "("
        << location.line()
        << ':'
        << location.column()
        << ") ";
}

auto main() -> int
{
    pos(); std::cout << "Proxima\n";
    pos(); std::cout << "Centauri\n";
}

可能的输出：

(18:5) Proxima
(19:5) Centauri

参阅

line | 返回此对象所表示的行号 (公开成员函数)
file_name | 返回此对象所表示的文件名 (公开成员函数)
function_name | 返回此对象表示的函数名，若它存在 (公开成员函数)


std::source_location::current

< cpp‎ | utility‎ | source location
static consteval source_location current() noexcept; | (C++20 起)

构造对应调用位置的新的 source_location 对象。

参数

（无）

返回值

若直接调用 current() （通过指名 current() 的函数调用），则它返回对应调用位置的拥有实现定义值的 source_location 对象。该值应当以同预定义宏 __LINE__ 与 __FILE__ 的方式受 #line 预处理指令影响。

若在默认成员初始化器中使用 current() ，则返回值对应初始化该数据成员的构造函数定义或聚合初始化的位置。

若 current() 用于默认参数，则返回值对应对 current() 的调用的调用点位置。

若以任何其他方式调用 current() ，则返回值未指定。

注解

std::source_location::current 通常要求编译器的内建实现。

示例

#include <source_location>
#include <iostream>

struct src_rec {
    std::source_location srcl = std::source_location::current();
    int dummy = 0;

    src_rec(std::source_location loc = std::source_location::current()) :
        srcl(loc)    // 成员的值指代调用函数的位置
    {}
    src_rec(int i) : // 成员的值指代此位置
        dummy(i)
    {}
    src_rec(double)  // 成员的值指代此位置
    {}
};

std::source_location src_clone(std::source_location a = std::source_location::current())
{
    return a;
}

std::source_location src_make()
{
    std::source_location b = std::source_location::current();
    return b;
}

int main()
{
    src_rec srec0;
    src_rec srec1(0);
    src_rec srec2(0.0);
    auto s0 = std::source_location::current();
    auto s1 = src_clone(s0);
    auto s2 = src_clone();
    auto s3 = src_make();

    std::cout
        << srec0.srcl.line() << ' ' << srec0.srcl.function_name() << '\n'
        << srec1.srcl.line() << ' ' << srec1.srcl.function_name() << '\n'
        << srec2.srcl.line() << ' ' << srec2.srcl.function_name() << '\n'
        << s0.line() << ' ' << s0.function_name() << '\n'
        << s1.line() << ' ' << s1.function_name() << '\n'
        << s2.line() << ' ' << s2.function_name() << '\n'
        << s3.line() << ' ' << s3.function_name() << '\n';
}

可能的输出：

31 int main()
12 src_rec::src_rec(int)
15 src_rec::src_rec(double)
34 int main()
34 int main()
36 int main()
25 std::source_location src_make()

参阅

(构造函数) | 构造拥有实现定义的值的新 source_location (公开成员函数)
current [静态] (C++23) | 获得当前栈踪或其给定部分 (std::basic_stacktrace<Allocator> 的公开静态成员函数)


std::source_location::file_name

< cpp‎ | utility‎ | source location
constexpr const char* file_name() const noexcept; | (C++20 起)

返回此对象所表示的当前源文件名，表示为空终止字节字符串。

参数

（无）

返回值

此对象所表示的当前源文件名，表示为空终止字节字符串。

示例

#if __has_include(<source_location>)
#include <source_location>
using std::source_location;
#elif __has_include(<experimental/source_location>)
#include <experimental/source_location>
using std::experimental::source_location;
#else
#error "<source_location> not found"
#endif

#include <iostream>

inline void print_this_file_name(
    const source_location& location = source_location::current())
{
    // 文件名含有此函数的调用点。
    std::cout << "File: " << location.file_name() << '\n';
}

auto main() -> int
{
    print_this_file_name();
}

可能的输出：

File: main.cpp

参阅

line | 返回此对象所表示的行号 (公开成员函数)
column | 返回此对象所表示的列号 (公开成员函数)
function_name | 返回此对象表示的函数名，若它存在 (公开成员函数)
source_file (C++23) | 获取词法上含有求值为该 stacktrace_entry 所表示的表达式或语句的源文件名 (std::stacktrace_entry 的公开成员函数)


std::source_location::function_name

< cpp‎ | utility‎ | source location
constexpr const char* function_name() const noexcept; | (C++20 起)

返回与此对象所表示的位置关联的函数名，若存在。

参数

（无）

返回值

若此对象表示函数体内的位置，则返回对应函数名的实现定义的空终止字节字符串。

否则，返回空字符串。

示例

以下示例展示能如何用 std::source_location::function_name() 打印函数、构造函数、析构函数或重载的 operator() 的名字。

#include <iostream>
#include <string_view>
#include <source_location>

inline void function_name(
    const std::string_view signature = "()",
    const std::source_location& location = std::source_location::current())
{
    std::cout << location.function_name(); // <- 调用方之名！
    if (!signature.empty())
        std::cout << signature;
    std::cout << '\n';
}

void foo() { function_name(); }

struct S {
    S() { function_name(); }
    S(int) { function_name("(int)"); }
    S& operator=(S const&) { function_name("(const S&)"); return *this; }
    S& operator=(S&&) { function_name("(S&&)"); return *this; }
    ~S() { function_name(); }
};

auto main() -> int
{
    foo();
    S p;
    S q{42};
    p = q;
    p = std::move(q);
}

输出：

foo()
S()
S(int)
operator=(const S&)
operator=(S&&)
~S()
~S()

参阅

line | 返回此对象所表示的行号 (公开成员函数)
column | 返回此对象所表示的列号 (公开成员函数)
file_name | 返回此对象所表示的文件名 (公开成员函数)


std::source_location::line

< cpp‎ | utility‎ | source location
constexpr std::uint_least32_t line() const noexcept; | (C++20 起)

返回此对象所表示的行号。

参数

（无）

返回值

此对象所表示的行号。

鼓励实现在行号未知时返回 0 。

示例

#include <iostream>
#include <string_view>
#include <source_location>

inline void cur_line(
    const std::string_view message = "",
    const std::source_location& location = std::source_location::current())
{
    std::cout
        << location.line() // <- 调用点行号
        << ") "
        << message;
}

auto main() -> int
{
    cur_line("++" "\n");
    cur_line(); std::cout << "Hello," "\n";
    cur_line(); std::cout << "C++20!" "\n";
    cur_line("--" "\n");
}

输出：

18) ++
19) Hello,
20) C++20!
21) --

参阅

column | 返回此对象所表示的列号 (公开成员函数)
file_name | 返回此对象所表示的文件名 (公开成员函数)
function_name | 返回此对象表示的函数名，若它存在 (公开成员函数)
source_line (C++23) | 获取词法上与该 stacktrace_entry 所表示的求值相关的行号 (std::stacktrace_entry 的公开成员函数)


std::source_location::source_location

< cpp‎ | utility‎ | source location
constexpr source_location() noexcept; | (1) | (C++20 起)
source_location( const source_location& other ); | (2) | (C++20 起)
source_location( source_location&& other ) noexcept; | (3) | (C++20 起)
1) 构造拥有未指明值的 source_location 对象。
2-3) 复制与移动构造函数。它们是否为平凡和/或 constexpr 是未指定的。

参数

other - 用以复制或移动的另一 source_location

参阅

current [静态] | 构造对应调用点位置的新 source_location (公开静态成员函数)
(构造函数) (C++23) | 构造新的 stacktrace_entry (std::stacktrace_entry 的公开成员函数)


std::stacktrace_entry

< cpp‎ | utility
定义于头文件 <stacktrace> |
class stacktrace_entry; | (C++23 起)

stacktrace_entry 类提供查询关于栈踪中求值的信息的操作。每个 stacktrace_entry 对象要么为空，要么表示一个栈踪中的求值。

stacktrace_entry 实现 std::regular 与 std::three_way_comparable<std::strong_ordering> 。

成员类型

native_handle_type(C++23) 实现定义的原生柄类型

成员函数

(构造函数)
(C++23)
 构造新的 stacktrace_entry
(公开成员函数)
(析构函数)
(C++23)
 销毁 stacktrace_entry
(公开成员函数)
operator=
(C++23)
 赋值一个 stacktrace_entry 的内容给另一个
(公开成员函数)
观察器
native_handle
(C++23)
 获取 stacktrace_entry 的实现定义的原生柄
(公开成员函数)
operator bool
(C++23)
 检查 stacktrace_entry 是否为空
(公开成员函数)
查询
description
(C++23)
 获取 stacktrace_entry 所表示的求值的描述
(公开成员函数)
source_file
(C++23)
 获取词法上含有求值为该 stacktrace_entry 所表示的表达式或语句的源文件名
(公开成员函数)
source_line
(C++23)
 获取词法上与该 stacktrace_entry 所表示的求值相关的行号
(公开成员函数)

非成员函数

operator==operator<=> (C++23) | 比较二个 stacktrace_entry 值 (函数)
to_string (C++23) | 返回拥有 stacktrace_entry 的描述的字符串 (函数)
operator<< (C++23) | 进行 stacktrace_entry 的流输出 (函数模板)

辅助类

std::hash<std::stacktrace_entry>
(C++23)
 std::stacktrace_entry 的散列支持
(类模板特化)

注解

boost::stacktrace::frame （可用于 Boost.Stacktrace ）能在 std::stacktrace_entry 不可用时作为代替。

示例

本节未完成
原因：暂无示例

参阅

basic_stacktrace (C++23) | 由栈踪条目组成的调用序列的近似表示 (类模板)
source_location (C++20) | 表示关于源码的信息，例如文件名、行号以及函数名的类 (类)


std::stacktrace_entry::description

< cpp‎ | utility‎ | stacktrace entry
std::string description() const; | (C++23 起)

成功时返回 *this 所表示的求值的描述，在分配失败以外的失败时，例如当 *this 为空时返回空字符串。

参数

（无）

返回值

成功时为被表示的求值的描述，分配失败以外的失败时为空字符串。

异常

若不能分配内部数据结构或结果字符串的内存则抛出 std::bad_alloc 。

注解

不提供对此函数的定制分配器支持，因为实现通常要求平台特定的分配、系统调用和大量 CPU 集中工作，而定制分配器不会对此函数提供便利，因为平台特定的操作耗费的时间数量级多于分配。

示例

本节未完成
原因：暂无示例


std::hash(std::stacktrace_entry)

< cpp‎ | utility‎ | stacktrace entry
定义于头文件 <stacktrace> |
template<> struct hash<std::stacktrace_entry>; | (C++23 起)

std::hash 对 std::stacktrace_entry 的模板特化允许用户获得 std::stacktrace_entry 类型值的散列值。

此特化的 operator() 为 noexcept 。

示例

本节未完成
原因：暂无示例

参阅

hash (C++11) | 散列函数对象 (类模板)
std::hash<std::basic_stacktrace> (C++23) | std::basic_stacktrace 的散列支持 (类模板特化)


std::stacktrace_entry::native_handle

< cpp‎ | utility‎ | stacktrace entry
constexpr native_handle_type native_handle() const noexcept; | (C++23 起)

返回实现定义的底层原生柄。对未更改的 stacktrace_entry 对象相继调用此函数返回等同的值。

此函数的语义是实现定义的。

参数

（无）

返回值

底层原生柄。

示例

本节未完成
原因：暂无示例


std::stacktrace_entry::operator=

< cpp‎ | utility‎ | stacktrace entry
constexpr stacktrace_entry& operator=( const stacktrace_entry& other ) noexcept; | (C++23 起)

复制赋值运算符。以 other 的内容替换 *this 的内容。

参数

other - 作为赋值来源的另一 stacktrace_entry

返回值

*this 。


std::stacktrace_entry::operator bool

< cpp‎ | utility‎ | stacktrace entry
constexpr explicit operator bool() const noexcept; | (C++23 起)

检查 stacktrace_entry 是否为非空，即它表示栈踪中的求值。

参数

（无）

返回值

若 stacktrace_entry 为非空则为 true ，否则为 false 。

注解

非空的 stacktrace_entry 能从 std::basic_stacktrace::current 所创建的 std::basic_stacktrace 或这种 std::basic_stacktrace 的副本获得。

空的 stacktrace_entry 能由默认构造函数创建。

示例

本节未完成
原因：暂无示例


operator==, operator<=>(std::stacktrace_entry)

< cpp‎ | utility‎ | stacktrace entry
friend constexpr bool operator==( const stacktrace_entry& lhs,
const stacktrace_entry& rhs ) noexcept;
 (1) (C++23 起)
friend constexpr std::strong_ordering
operator<=>( const stacktrace_entry& lhs, const stacktrace_entry& rhs ) noexcept;
 (2) (C++23 起)
1) 比较 lhs 与 rhs 的相等性。二个 stacktrace_entry 值相等当且仅当它们表示同一栈踪条目，或均为空。
2) 获取 lhs 与 rhs 在的所有 stacktrace_entry 值上的未指定的严格全序中的相对顺序，该序与 operator== 所建立的等价关系一致。

这些函数对通常无限定或有限定查找不可见，而只能在 std::stacktrace_entry 为参数的关联类时由实参依赖查找找到。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

参数

lhs, rhs - 要比较的 stacktrace_entry 值

返回值

1) 若 lhs 与 rhs 比较相等则为 true ，否则为 false 。
2) 若 lhs 与 rhs 比较相等则为 std::strong_ordering::equal 。
否则，若 lhs 在严格全序中顺序先于 rhs 则为 std::strong_ordering::less 。
否则为 std::strong_ordering::greater （该情况下 rhs 在严格全序中顺序先于 lhs ）。

示例

本节未完成
原因：暂无示例


std::operator<<(std::stacktrace_entry)

< cpp‎ | utility‎ | stacktrace entry
定义于头文件 <stacktrace>
template< class CharT, class Traits >

std::basic_ostream <CharT, Traits>&

operator<<( std::basic_ostream <CharT, Traits>& os, const std::stacktrace_entry& f );
 (C++23 起)

插入 f 的描述到输出流 os 中。等价于 return os << std::to_string (f); 。

参数

os | - | 输出流
f | - | 要插入其描述的 stacktrace_entry

返回值

os 。

异常

可能抛出实现定义的异常。

注解

由于 std::string 只能由 std::ostream 输出（例如不能由 std::wostream ），这等效地要求 os 的类型为 std::ostream & 。

示例

#include <stacktrace>
#include <iostream>

int main()
{
    for (const auto &f : std::stacktrace::current())
        std::cout << f << '\n';
}

可能的输出：

0x0000000000402AA7 in ./prog.exe
__libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
0x00000000004029B9 in ./prog.exe

参阅

operator<<
(C++23)
 进行 basic_stracktrace 的流输出
(函数模板)


std::stacktrace_entry::source_file

< cpp‎ | utility‎ | stacktrace entry
std::string source_file() const; | (C++23 起)

返回词法上含有求值为 *this 所表示的表达式或语句的源文件的预设或实际名，或在分配失败以外的失败，例如 *this 为空时返回空字符串。

要么 source_file 返回预设源文件名且 source_line 返回预设行号，要么 source_file 返回实际源文件名且 source_line 返回实际行号。

参数

（无）

返回值

成功时为指定如上的源文件名，分配失败以外的失败时为空字符串。

异常

若不能分配内部数据结构或结果字符串的内存则抛出 std::bad_alloc 。

注解

源文件的预设名是预定义宏 __FILE__ 所展开的结果，而且能由 #line 指令更改。

本节未完成
原因：“实际名”的定义缺失（ LWG 问题 3507 ）

不提供对此函数的定制分配器支持，因为实现通常要求平台特定的分配、系统调用和大量 CPU 集中工作，而定制分配器不会对此函数提供便利，因为平台特定的操作耗费的时间数量级多于分配。

示例

本节未完成
原因：暂无示例

参阅

file_name
 返回此对象所表示的文件名
(std::source_location 的公开成员函数)


std::stacktrace_entry::source_line

< cpp‎ | utility‎ | stacktrace entry
std::uint_least32_t source_line() const; | (C++23 起)

成功时返回 *this 所表示的求值相关的基于 1 的行号，或在分配失败以外的失败时，例如当 *this 为空返回 0 。

要么 source_file 返回预设源文件名且 source_line 返回预设行号，要么 source_file 返回实际源文件名且 source_line 返回实际行号。

参数

（无）

返回值

成功时为指定如上的行号，分配失败以外的失败时为 0 。

异常

若不能分配内部数据结构的内存则抛出 std::bad_alloc 。

注解

预设行号是预定义宏 __LINE__ 所展开的结果，并且能由 #line 指令更改。

本节未完成
原因：“实际行号”的定义缺失（ LWG 问题 3507 ）

不要求此函数为 noexcept ，因为在某些平台上获取源行号要求分配。

示例

本节未完成
原因：暂无示例

参阅

line
 返回此对象所表示的行号
(std::source_location 的公开成员函数)


std::stacktrace_entry::stacktrace_entry

< cpp‎ | utility‎ | stacktrace entry
constexpr stacktrace_entry() noexcept; | (1) | (C++23 起)
constexpr stacktrace_entry( const stacktrace_entry& other ) noexcept; | (2) | (C++23 起)
1) 默认构造函数。创建空的 stacktrace_entry 。
2) 复制构造函数。创建 other 的副本。

参数

other - 要复制的另一 stacktrace_entry

注解

非空的 stacktrace_entry 能从 std::basic_stacktrace::current 所创建的 std::basic_stacktrace 或这种 std::basic_stacktrace 的副本获得。

示例

本节未完成
原因：暂无示例

参阅

(构造函数)
 构造拥有实现定义的值的新 source_location
(std::source_location 的公开成员函数)


std::to_string

< cpp‎ | utility‎ | stacktrace entry
定义于头文件 <stacktrace> |
std::string to_string( const std::stacktrace_entry& f ); | (C++23 起)

返回带有 f 的描述的字符串。

标准推荐描述应该提供关于求值的信息，包括来自 f.source_file() 与 f.source_line() 的信息。

参数

f - 要返回其描述的 stacktrace_entry

返回值

带有 f 的描述的字符串。

异常

可能抛出实现定义的异常。

注解

不提供对此函数的定制分配器支持，因为实现通常要求平台特定的分配、系统调用和大量 CPU 集中工作，而定制分配器不会对此函数提供便利，因为平台特定的操作耗费的时间数量级多于分配。

示例

#include <stacktrace>
#include <string>
#include <iostream>

int main()
{
    auto st = std::stacktrace::current();
    std::cout <<
        "Description of an empty stacktrace entry:\n" +
        std::to_string(std::stacktrace_entry{}) << '\n';
    if (st.size() > 0) {
        std::cout <<
            "Description of a non-empty stacktrace entry:\n" +
            std::to_string(st[0]) << '\n';
    }
}

可能的输出：

Description of an empty stacktrace entry:

Description of a non-empty stacktrace entry:
0x0000000000402DE9 in ./prog.exe

参阅

to_string
(C++23)
 返回拥有 basic_stacktrace 的描述的字符串
(函数模板)


std::to_chars, std::to_chars_result

< cpp‎ | utility
定义于头文件 <charconv>
std::to_chars_result to_chars(char* first, char* last,
/*see below*/ value, int base = 10);
 (1) (C++17 起)
std::to_chars_result to_chars(char*, char*, bool, int = 10) = delete;
 (2) (C++17 起)
std::to_chars_result to_chars(char* first, char* last, float value);

std::to_chars_result to_chars(char* first, char* last, double value);

std::to_chars_result to_chars(char* first, char* last, long double value);
 (3) (C++17 起)
std::to_chars_result to_chars(char* first, char* last, float value,

std::chars_format fmt);
std::to_chars_result to_chars(char* first, char* last, double value,
std::chars_format fmt);
std::to_chars_result to_chars(char* first, char* last, long double value,

std::chars_format fmt);
 (4) (C++17 起)
std::to_chars_result to_chars(char* first, char* last, float value,

std::chars_format fmt, int precision);
std::to_chars_result to_chars(char* first, char* last, double value,
std::chars_format fmt, int precision);
std::to_chars_result to_chars(char* first, char* last, long double value,

std::chars_format fmt, int precision);
 (5) (C++17 起)
辅助类型
struct to_chars_result {

char* ptr;
std::errc ec;

};
 (6) (C++17 起)

通过成功填充范围 [first, last) ，转换 value 为字符串，要求 [first, last) 是合法范围。

1) 整数格式化函数： value 以给定基底 base 转换成数位的字符串（无冗余的前导零）。范围 10..35 （含上下限）中的数字被表示成小写字母 a..z 。若值小于零，则表示以负号起始。库提供所有有符号及无符号整数和 char 类型作为参数 value 类型的重载。
2) bool 的重载被删除。 to_chars 拒绝 bool 类型参数，因为假如允许则结果会是 "0"/"1" 而非 "false"/"true" 。
3) 如同用 std::sprintf 于默认（ "C" ）本地环境转换值为字符串。转换指定符是 f 或 e ，根据最短表示方式的要求选择（两者相当时优先选择 f ）：字符串表示由小数点（若存在）前至少有一位，且用对应的 std::from_chars 分析该表示能准确恢复值的，最小数量的字符组成。若有数个这种表示，则选择到 value 的差最小者，用根据 std::round_to_nearest 的舍入解决任何剩余倾向
4) 同 (3) ，但若 fmt 为 std::chars_format::fixed 则如同对应 printf 的转换指定为 f ，若 fmt 为 std::chars_format::scientific 则为 e ，若 fmt 为 std::chars_format::hex 则为 a （但结果无前导 "0x" ），且若 fmt 为 chars_format::general 则为 g 。
5) 同 (4) ，除了精度以参数 precision 指定，而非以最短表示要求。
6) 返回类型（见后述返回值）。 std::to_chars_result 无基类或 ptr 、 ec 及隐式声明的特殊成员函数以外的成员。

参数

first, last | - | 要写入的字符范围
value | - | 要转换到其字符串表示的值
base | - | 使用的整数基底： 2 与 36 间的值（含上下限）。
fmt | - | 使用的浮点格式， std::chars_format 类型的位掩码
precision | - | 使用的浮点精度

返回值

成功时，返回 to_chars_result 类型的值，其 ec 等于值初始化的 std::errc ，且其 ptr 是指向被写入字符尾后一位置的指针。注意该字符串不是空终止的。

错误时，返回 to_chars_result 类型的值，它在 ec 保有 std::errc::value_too_large 于 ，在 ptr 保有 last ，并于范围 [first, last) 中留下未指定状态的内容。

operator==(std::to_chars_result)

friend bool operator==( const to_chars_result&, const to_chars_result& ) = default; | (C++20 起)

检查两个参数的 ptr 与 ec 是否分别相等。

此函数对通常无限定或有限定查找不可见，而只能在 std::to_chars_result 为参数的关联类时由实参依赖查找找到。

!= 运算符从 operator== 合成。

异常

不抛出。

注解

不同于 C++ 和 C 库中的其他格式化函数， std::to_chars 是独立于本地环境、不分配、不抛出的。它只提供其他库（例如 std::sprintf ）所用策略的一个小子集。它的目的是在常见的高吞吐量环境，例如基于文本的交换（ JSON 或 XML ）中，允许尽可能快的实现。

仅当两个函数都来自同一实现的情况下，才保证 std::from_chars 能恢复每个由 to_chars 格式化的浮点值。

若想要格式化 bool 值为 "0"/"1" ，则要求将它显式转型为另一整数类型。

示例

#include <iostream>
#include <charconv>
#include <system_error>
#include <string_view>
#include <array>

int main()
{
    std::array<char, 10> str;

    if(auto [p, ec] = std::to_chars(str.data(), str.data() + str.size(), 42);
       ec == std::errc())
        std::cout << std::string_view(str.data(), p - str.data());
}

输出：

42

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2955 | C++17 | 此函数在 <utility> 且使用 std::error_code | 移动到 <charconv> 并使用 std::errc
LWG 3266 | C++17 | 曾接受 bool 实参并将它提升到 int | 由被删除的重载拒绝
LWG 3373 | C++17 | to_chars_result 可能拥有额外的成员 | 禁止额外的成员

参阅

from_chars (C++17) | 转换字符序列到整数或浮点值 (函数)
to_string (C++11) | 转换整数或浮点值为 string (函数)
printffprintfsprintfsnprintf (C++11) | 打印有格式输出到 stdout、文件流或缓冲区 (函数)
operator<< | 插入带格式数据 (std::basic_ostream<CharT,Traits> 的公开成员函数)


std::to_underlying

< cpp‎ | utility
定义于头文件 <utility> |
template< class Enum > constexpr std::underlying_type_t <Enum> to_underlying( Enum e ) noexcept; | (C++23 起)

转换枚举到其底层类型。等价于 return static_cast< std::underlying_type_t <Enum>>(e); 。

参数

e - 要转换的枚举值

返回值

Enum 的底层类型的整数值，从 e 转换得到。

注解

std::to_underlying 能用于避免将枚举类型转换成其底层类型以外的整数类型。

示例

#include <cstdint>
#include <iomanip>
#include <iostream>
#include <type_traits>
#include <utility>

namespace cxx {
#if defined(__cpp_lib_to_underlying)
    using std::to_underlying;
#else
    template <class Enum>
    constexpr std::underlying_type_t<Enum>
    to_underlying(Enum e) noexcept {
        return static_cast<std::underlying_type_t<Enum>>(e);
    }
#endif
}

int main()
{
    enum class E1 : char { e };
    static_assert(std::is_same_v<char, decltype(cxx::to_underlying(E1::e))>);
    enum struct E2 : long { e };
    static_assert(std::is_same_v<long, decltype(cxx::to_underlying(E2::e))>);
    enum E3 : unsigned { e };
    static_assert(std::is_same_v<unsigned, decltype(cxx::to_underlying(e))>);

    enum class ColorMask : std::uint32_t {
        red = 0xFF, green = (red << 8), blue = (green << 8), alpha = (blue << 8)
    };
    std::cout << std::hex << std::uppercase << std::setfill('0')
        << std::setw(8) << cxx::to_underlying(ColorMask::red) << '\n'
        << std::setw(8) << cxx::to_underlying(ColorMask::green) << '\n'
        << std::setw(8) << cxx::to_underlying(ColorMask::blue) << '\n'
        << std::setw(8) << cxx::to_underlying(ColorMask::alpha) << '\n';

//  std::underlying_type_t<ColorMask> x = ColorMask::alpha; // 错误：无已知转换
    [[maybe_unused]]
    std::underlying_type_t<ColorMask> y = cxx::to_underlying(ColorMask::alpha); // OK
}

输出：

000000FF
0000FF00
00FF0000
FF000000

参阅

underlying_type
(C++11)
 获取给定枚举类型的底层整数类型
(类模板)


std::tuple

< cpp‎ | utility
定义于头文件 <tuple> |
template< class... Types > class tuple; | (C++11 起)

类模板 std::tuple 是固定大小的异类值汇集。它是 std::pair 的推广。

若 std::is_trivially_destructible <Ti>::value 对 Types 中的每个 Ti 为 true ，则 tuple 的析构函数为平凡。

模板形参

Types... - tuple 所存储的元素的类型。支持空列表。

成员函数

(构造函数) | 构造新的 tuple (公开成员函数)
operator= | 赋值一个 tuple 的内容给另一个 (公开成员函数)
swap | 交换两个 tuple 的内容 (公开成员函数)

非成员函数

make_tuple | 创建一个 tuple 对象，其类型根据各实参类型定义 (函数模板)
tie | 创建左值引用的 tuple，或将 tuple 解包为独立对象 (函数模板)
forward_as_tuple | 创建转发引用的 tuple (函数模板)
tuple_cat | 通过连接任意数量的元组来创建一个tuple (函数模板)
std::get(std::tuple) | 元组式访问指定的元素 (函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=> (C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20) | 按字典顺序比较 tuple 中的值 (函数模板)
std::swap(std::tuple) (C++11) | 特化 std::swap 算法 (函数模板)

辅助类

std::tuple_size<std::tuple> (C++11) | 在编译时获得 tuple 的大小 (类模板特化)
std::tuple_element<std::tuple> (C++11) | 获得指定元素的类型 (类模板特化)
std::uses_allocator<std::tuple> (C++11) | 特化 std::uses_allocator 类型特征 (类模板特化)
ignore | 用 tie 解包 tuple 时用来跳过元素的占位符 (常量)

推导指引 (C++17 起)

注解

N4387 （作为对 C++11 的缺陷报告应用）前，函数不能用复制列表初始化返回 tuple ：

std::tuple<int, int> foo_tuple()
{
  return {1, -1};  // N4387 前错误
  return std::tuple<int, int>{1, -1};  // 始终有效
  return std::make_tuple(1, -1); // 始终有效
}

示例

#include <tuple>
#include <iostream>
#include <string>
#include <stdexcept>

std::tuple<double, char, std::string> get_student(int id)
{
    if (id == 0) return std::make_tuple(3.8, 'A', "Lisa Simpson");
    if (id == 1) return std::make_tuple(2.9, 'C', "Milhouse Van Houten");
    if (id == 2) return std::make_tuple(1.7, 'D', "Ralph Wiggum");
    throw std::invalid_argument("id");
}

int main()
{
    auto student0 = get_student(0);
    std::cout << "ID: 0, "
              << "GPA: " << std::get<0>(student0) << ", "
              << "grade: " << std::get<1>(student0) << ", "
              << "name: " << std::get<2>(student0) << '\n';

    double gpa1;
    char grade1;
    std::string name1;
    std::tie(gpa1, grade1, name1) = get_student(1);
    std::cout << "ID: 1, "
              << "GPA: " << gpa1 << ", "
              << "grade: " << grade1 << ", "
              << "name: " << name1 << '\n';

    // C++17 结构化绑定：
    auto [ gpa2, grade2, name2 ] = get_student(2);
    std::cout << "ID: 2, "
              << "GPA: " << gpa2 << ", "
              << "grade: " << grade2 << ", "
              << "name: " << name2 << '\n';
}

输出：

ID: 0, GPA: 3.8, grade: A, name: Lisa Simpson
ID: 1, GPA: 2.9, grade: C, name: Milhouse Van Houten
ID: 2, GPA: 1.7, grade: D, name: Ralph Wiggum

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2796 | C++11 | tuple 的析构函数的平凡性未指明 | 已指明

引用

  • C++20 标准（ISO/IEC 14882:2020）：
  • 20.5 Tuples [tuple]
  • C++17 标准（ISO/IEC 14882:2017）：
  • 23.5 Tuples [tuple]
  • C++14 标准（ISO/IEC 14882:2014）：
  • 20.4 Tuples [tuple]
  • C++11 标准（ISO/IEC 14882:2011）：
  • 20.4 Tuples [tuple]


std::tuple 的推导指引

< cpp‎ | utility‎ | tuple
定义于头文件 <tuple> |  |
template<class... UTypes> tuple(UTypes...) -> tuple<UTypes...>; | (1) | (C++17 起)
template<class T1, class T2> tuple( std::pair <T1, T2>) -> tuple<T1, T2>; | (2) | (C++17 起)
template<class Alloc, class... UTypes> tuple( std::allocator_arg_t, Alloc, UTypes...) -> tuple<UTypes...>; | (3) | (C++17 起)
template<class Alloc, class T1, class T2> tuple( std::allocator_arg_t, Alloc, std::pair <T1, T2>) -> tuple<T1, T2>; | (4) | (C++17 起)
template<class Alloc, class... UTypes> tuple( std::allocator_arg_t, Alloc, tuple<UTypes...>) -> tuple<UTypes...>; | (5) | (C++17 起)

为 std::tuple 提供这些推导指引，以涵盖隐式推导指引缺失的极端情况，特别是不可复制参数和数组到指针转换。

示例

#include <tuple>
int main()
{
    int a[2], b[3], c[4];
    std::tuple t1{a, b, c}; // 用于此场合的显式推导指引
}


std::forward_as_tuple

< cpp‎ | utility‎ | tuple
定义于头文件 <tuple> |
template< class... Types > tuple<Types&&...> forward_as_tuple( Types&&... args ) noexcept; | (C++11 起) (C++14 前)
template< class... Types > constexpr tuple<Types&&...> forward_as_tuple( Types&&... args ) noexcept; | (C++14 起)

构造到 args 中参数的，适于转发成函数参数的引用的 tuple 。该 tuple 在以右值为参数时拥有右值引用数据成员，否则拥有左值引用数据成员。

参数

args - 构造 tuple 所用的零或更多参数

返回值

如同以 std::tuple <Types&&...>( std::forward <Types>(args)...) 创建的 std::tuple 对象。

注意

若参数是临时量，则 forward_as_tuple 不延续其生存期；必须在完整表达式结尾前使用它们。

示例

#include <iostream>
#include <map>
#include <tuple>
#include <string>

int main()
{
    std::map<int, std::string> m;

    m.emplace(std::piecewise_construct,
              std::forward_as_tuple(10),
              std::forward_as_tuple(20, 'a'));
    std::cout << "m[10] = " << m[10] << '\n';

    // 下面是错误：它产生保有二个悬垂引用的 std::tuple<int&&, char&&>
    //
    // auto t = std::forward_as_tuple(20, 'a');
    // m.emplace(std::piecewise_construct, std::forward_as_tuple(10), t);
}

输出：

m[10] = aaaaaaaaaaaaaaaaaaaa

参阅

make_tuple | 创建一个 tuple 对象，其类型根据各实参类型定义 (函数模板)
tie | 创建左值引用的 tuple，或将 tuple 解包为独立对象 (函数模板)
tuple_cat | 通过连接任意数量的元组来创建一个tuple (函数模板)
apply (C++17) | 以一个实参的元组来调用函数 (函数模板)


std::get(std::tuple)

< cpp‎ | utility‎ | tuple
定义于头文件 <tuple>
template< std::size_t I, class... Types >

typename std::tuple_element <I, tuple<Types...> >::type&

get( tuple<Types...>& t ) noexcept;
 (1) (C++11 起)
(C++14 起为 constexpr)
template< std::size_t I, class... Types >

typename std::tuple_element <I, tuple<Types...> >::type&&

get( tuple<Types...>&& t ) noexcept;
 (2) (C++11 起)
(C++14 起为 constexpr)
template< std::size_t I, class... Types >

typename std::tuple_element <I, tuple<Types...> >::type const&

get( const tuple<Types...>& t ) noexcept;
 (3) (C++11 起)
(C++14 起为 constexpr)
template< std::size_t I, class... Types >

typename std::tuple_element <I, tuple<Types...> >::type const&&

get( const tuple<Types...>&& t ) noexcept;
 (4) (C++11 起)
(C++14 起为 constexpr)
template< class T, class... Types >
constexpr T& get(tuple<Types...>& t) noexcept;
 (5) (C++14 起)
template< class T, class... Types >
constexpr T&& get(tuple<Types...>&& t) noexcept;
 (6) (C++14 起)
template< class T, class... Types >
constexpr const T& get(const tuple<Types...>& t) noexcept;
 (7) (C++14 起)
template< class T, class... Types >
constexpr const T&& get(const tuple<Types...>&& t) noexcept;
 (8) (C++14 起)
1-4) 从 tuple 提取第 I 个元素。 I 是 [0, sizeof...(Types)) 中的整数值。
5-8) 提取 tuple t 的类型为 T 的元素。若 tuple 不恰好拥有一个该类型元素则编译失败。

参数

t - 要提取内容的 tuple

返回值

到 t 的被选中元素的引用。

示例

#include <iostream>
#include <string>
#include <tuple>

int main()
{
    auto t = std::make_tuple(1, "Foo", 3.14);
    // 基于下标的访问
    std::cout << "(" << std::get<0>(t) << ", " << std::get<1>(t)
              << ", " << std::get<2>(t) << ")\n";
    // 基于类型的访问（ C++14 起）
    std::cout << "(" << std::get<int>(t) << ", " << std::get<const char*>(t)
              << ", " << std::get<double>(t) << ")\n";
    // 注意： std::tie 和结构化绑定亦可用于分解 tuple
}

输出：

(1, Foo, 3.14)
(1, Foo, 3.14)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2485 | C++11 （按索引） C++14 （按类型） | 无对于 const tuple&& 的重载 | 添加重载

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
std::get(std::array) | 访问 array 的一个元素 (函数模板)
std::get(std::pair) (C++11) | 访问 pair 的一个元素 (函数模板)
std::get(std::variant) (C++17) | 以给定索引或类型（若类型唯一）读取 variant 的值，错误时抛出异常 (函数模板)


std::ignore

< cpp‎ | utility‎ | tuple
定义于头文件 <tuple> |
const /*unspecified*/ ignore; | (C++11 起) (C++17 前)
inline constexpr /*unspecified*/ ignore; | (C++17 起)

任何值均可赋给而无效果的未指定类型的对象。目的是令 std::tie 在解包 std::tuple 时作为不使用的参数的占位符使用。

可能的实现

namespace detail {
struct ignore_t {
    template <typename T>
    constexpr // C++14 起要求
    void operator=(T&&) const noexcept {}
};
}
inline constexpr detail::ignore_t ignore; // C++17 前仅 'const'

示例

解包 set.insert() 所返回的 pair ，但只保存布尔值。

#include <iostream>
#include <string>
#include <set>
#include <tuple>

int main()
{
    std::set<std::string> set_of_str;
    bool inserted = false;
    std::tie(std::ignore, inserted) = set_of_str.insert("Test");
    if (inserted) {
        std::cout << "Value was inserted successfully\n";
    }
}

输出：

Value was inserted successfully

参阅

tie
 创建左值引用的 tuple，或将 tuple 解包为独立对象
(函数模板)


std::make_tuple

< cpp‎ | utility‎ | tuple
定义于头文件 <tuple> |
template< class... Types > std::tuple <VTypes...> make_tuple( Types&&... args ); | (C++11 起) (C++14 起为 constexpr)

创建 tuple 对象，从参数类型推导目标类型。

对于每个 Types... 中的 Ti ， Vtypes... 中的对应类型 Vi 为 std::decay <Ti>::type ，除非应用 std::decay 对某些类型 X 导致 std::reference_wrapper <X> ，该情况下推导的类型为 X& 。

参数

args - 构造 tuple 所用的零或更多参数

返回值

含给定值的 std::tuple 对象，如同用 std::tuple <VTypes...>( std::forward <Types>(t)...). 创建

可能的实现

template <class T>
struct unwrap_refwrapper
{
    using type = T;
};

template <class T>
struct unwrap_refwrapper<std::reference_wrapper<T>>
{
    using type = T&;
};

template <class T>
using unwrap_decay_t = typename unwrap_refwrapper<typename std::decay<T>::type>::type;
// 或使用 std::unwrap_ref_decay_t （ C++20 起）

template <class... Types>
constexpr // since C++14
std::tuple<unwrap_decay_t<Types>...> make_tuple(Types&&... args)
{
    return std::tuple<unwrap_decay_t<Types>...>(std::forward<Types>(args)...);
}

示例

#include <iostream>
#include <tuple>
#include <functional>

std::tuple<int, int> f() // 此函数返回多值
{
    int x = 5;
    return std::make_tuple(x, 7); // return {x,7}; 于 C++17
}

int main()
{
    // 异类 tuple 构造
    int n = 1;
    auto t = std::make_tuple(10, "Test", 3.14, std::ref(n), n);
    n = 7;
    std::cout << "The value of t is "  << "("
              << std::get<0>(t) << ", " << std::get<1>(t) << ", "
              << std::get<2>(t) << ", " << std::get<3>(t) << ", "
              << std::get<4>(t) << ")\n";

    // 返回多值的函数
    int a, b;
    std::tie(a, b) = f();
    std::cout << a << " " << b << "\n";
}

输出：

The value of t is (10, Test, 3.14, 7, 1)
5 7

参阅

tie | 创建左值引用的 tuple，或将 tuple 解包为独立对象 (函数模板)
forward_as_tuple | 创建转发引用的 tuple (函数模板)
tuple_cat | 通过连接任意数量的元组来创建一个tuple (函数模板)
apply (C++17) | 以一个实参的元组来调用函数 (函数模板)
unwrap_referenceunwrap_ref_decay (C++20)(C++20) | 获取包装于 std::reference_wrapper 的引用类型 (类模板)


std::tuple<Types...>::operator=

< cpp‎ | utility‎ | tuple
 | (1)
tuple& operator=( const tuple& other ); |  | (C++11 起) (C++20 前)
constexpr tuple& operator=( const tuple& other ); |  | (C++20 起)
 | (2)
tuple& operator=( tuple&& other ) noexcept(/* see below */); |  | (C++11 起) (C++20 前)
constexpr tuple& operator=( tuple&& other ) noexcept(/* see below */); |  | (C++20 起)
 | (3)
template< class... UTypes > tuple& operator=( const tuple<UTypes...>& other ); |  | (C++11 起) (C++20 前)
template< class... UTypes > constexpr tuple& operator=( const tuple<UTypes...>& other ); |  | (C++20 起)
 | (4)
template< class... UTypes > tuple& operator=( tuple<UTypes...>&& other ); |  | (C++11 起) (C++20 前)
template< class... UTypes > constexpr tuple& operator=( tuple<UTypes...>&& other ); |  | (C++20 起)
 | (5)
template< class U1, class U2 > tuple& operator=( const std::pair <U1,U2>& p ); |  | (C++11 起) (C++20 前)
template< class U1, class U2 > constexpr tuple& operator=( const std::pair <U1,U2>& p ); |  | (C++20 起)
 | (6)
template< class U1, class U2 > tuple& operator=( std::pair <U1,U2>&& p ); |  | (C++11 起) (C++20 前)
template< class U1, class U2 > constexpr tuple& operator=( std::pair <U1,U2>&& p ); |  | (C++20 起)

以另一 tuple 或 pair 的内容替换 tuple 的内容。

1) 复制赋值运算符。复制赋值 other 的每个元素给 *this 的对应元素。
  • 定义此重载为被删除，除非 std::is_copy_assignable <T_i>::value 对 Types 中所有 T_i 为 true 。
2) 移动赋值运算符。对所有 i ，赋值 std::forward <Ti>(get<i>(other)) 给 get<i>(*this) 。
  • 此重载仅若 std::is_move_assignable <T_i>::value 对 Types 中所有 T_i 为 true 才参与重载决议。
3) 对所有 i ，赋 std::get<i>(other) 给 std::get<i>(*this) 。
  • 此重载仅若 sizeof...(UTypes) == sizeof...(Types) 且 std::is_assignable <T_i&, const U_i&>::value 对所有 Types 中的 T_i 和 UTypes 中的 U_i 的对应对均为 true 才参与重载决议。
4) 对所有 i ，赋 std::forward <Ui>(std::get<i>(other)) 给 std::get<i>(*this) 。
  • 此重载仅若 sizeof...(UTypes) == sizeof...(Types) 且 std::is_assignable <T_i&, U_i>::value 对所有 Types 中的 T_i 和 UTypes 中的 U_i 的对应对均为 true 才参与重载决议。
5) 赋 p.first 给 *this 的首元素并赋 p.second 给 *this 的第二元素。
  • 此重载仅若 sizeof...(Types) == 2 且 std::is_assignable <T_0&, const U1&>::value 与 std::is_assignable <T_1&, const U2&>::value 均为 true 才参与重载决议，其中 T_0 与 T_1 是组成 Types 的二个类型。
6) 赋 std::forward <U1>(p.first) 给 *this 的首元素并赋 std::forward <U2>(p.second) 给 *this 的第二元素。
  • 此重载仅若 sizeof...(Types) == 2 且 std::is_assignable <T_0&, U1>::value 与 std::is_assignable <T_1&, U2>::value 均为 true 才参与重载决议，其中 T_0 与 T_1 是组成 Types 的二个类型。

参数

other | - | 要替换此 tuple 内容的 tuple
p | - | 要替换此 2-tuple 内容的 pair

返回值

*this

异常

1) 可能抛出实现定义的异常。
2)
noexcept 说明：
noexcept(

std::is_nothrow_move_assignable <T0>::value &&
std::is_nothrow_move_assignable <T1>::value &&
std::is_nothrow_move_assignable <T2>::value &&
...

)
3-6) 可能抛出实现定义的异常。

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2729 | C++11 | tuple::operator= 未被约束并可能导致不必要的未定义行为 | 已约束

参阅


operator==,!=,<,<=,>,>=,<=>(std::tuple)

< cpp‎ | utility‎ | tuple
定义于头文件 <tuple>
(1)
template< class... TTypes, class... UTypes >

bool operator==( const std::tuple <TTypes...>& lhs,

const std::tuple <UTypes...>& rhs );
 (C++11 起)
(C++14 前)
template< class... TTypes, class... UTypes >

constexpr bool operator==( const std::tuple <TTypes...>& lhs,

const std::tuple <UTypes...>& rhs );
 (C++14 起)
(2)
template< class... TTypes, class... UTypes >

bool operator!=( const std::tuple <TTypes...>& lhs,

const std::tuple <UTypes...>& rhs );
 (C++11 起)
(C++14 前)
template< class... TTypes, class... UTypes >

constexpr bool operator!=( const std::tuple <TTypes...>& lhs,

const std::tuple <UTypes...>& rhs );
 (C++14 起)
(C++20 前)
(3)
template< class... TTypes, class... UTypes >

bool operator<( const std::tuple <TTypes...>& lhs,

const std::tuple <UTypes...>& rhs );
 (C++11 起)
(C++14 前)
template< class... TTypes, class... UTypes >

constexpr bool operator<( const std::tuple <TTypes...>& lhs,

const std::tuple <UTypes...>& rhs );
 (C++14 起)
(C++20 前)
(4)
template< class... TTypes, class... UTypes >

bool operator<=( const std::tuple <TTypes...>& lhs,

const std::tuple <UTypes...>& rhs );
 (C++11 起)
(C++14 前)
template< class... TTypes, class... UTypes >

constexpr bool operator<=( const std::tuple <TTypes...>& lhs,

const std::tuple <UTypes...>& rhs );
 (C++14 起)
(C++20 前)
(5)
template< class... TTypes, class... UTypes >

bool operator>( const std::tuple <TTypes...>& lhs,

const std::tuple <UTypes...>& rhs );
 (C++11 起)
(C++14 前)
template< class... TTypes, class... UTypes >

constexpr bool operator>( const std::tuple <TTypes...>& lhs,

const std::tuple <UTypes...>& rhs );
 (C++14 起)
(C++20 前)
(6)
template< class... TTypes, class... UTypes >

bool operator>=( const std::tuple <TTypes...>& lhs,

const std::tuple <UTypes...>& rhs );
 (C++11 起)
(C++14 前)
template< class... TTypes, class... UTypes >

constexpr bool operator>=( const std::tuple <TTypes...>& lhs,

const std::tuple <UTypes...>& rhs );
 (C++14 起)
(C++20 前)
template< class... TTypes, class... UTypes >

constexpr /* see below */ operator<=>( const std::tuple <TTypes...>& lhs,

const std::tuple <UTypes...>& rhs );
 (7) (C++20 起)
1-2) 比较 tuple lhs 的每个元素和 tuple rhs 的对应元素。
3-6) 用 operator< 以字典序比较 lhs 与 rhs ，即比较首元素，若等价则比较第二元素，若均等价则比较第三元素，以此类推。

对于非空 tuple ， (3) 等价于

if (std::get<0>(lhs) < std::get<0>(rhs)) return true;
if (std::get<0>(rhs) < std::get<0>(lhs)) return false;
if (std::get<1>(lhs) < std::get<1>(rhs)) return true;
if (std::get<1>(rhs) < std::get<1>(lhs)) return false;
...
return std::get<N - 1>(lhs) < std::get<N - 1>(rhs);
7) 用合成三路比较以字典序比较 lhs 与 rhs ，即比较首元素，若等价则比较第二元素，若均等价则比较第三元素，以此类推。

返回类型为 lhs 与 rhs 中的每对元素上的三路比较结果的共用比较类别类型。对于空 tuple ，返回类型为 std::strong_ordering 。
对于非空 tuple ， (7) 等价于

if (auto c = synth_three_way(std::get<0>(lhs), std::get<0>(lhs)); c != 0) return c;
if (auto c = synth_three_way(std::get<1>(lhs), std::get<1>(lhs)); c != 0) return c;
...
return synth_three_way(std::get<N - 1>(lhs), std::get<N - 1>(lhs));
其中 synth_three_way 是进行合成三路比较的仅用于阐释的函数对象。

sizeof...(TTypes) 与 sizeof...(UTypes) 必须相等，否则程序非良构，或对于 operator<=> ，该运算符函数不参与重载决议 (C++20 起)。以上代码中的 N 等于两者。

所有比较运算符是短路的；它们在确定结果所必须的比较之外不访问 tuple 元素。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

合成三路比较

给定二个对象类型 T 与 U 、作为左操作数的 const T 左值 t 、作为右操作数的 const U 左值 u ，合成三路比较定义为：

  • 若 std::three_way_comparable_with<T, U> 得到满足，则等价于 t <=> u ；
  • 否则，若以两种顺序比较 const T 左值与 const U 左值均为良构且结果类型满足 boolean-testable ，则等价于
t < u ? std::weak_ordering::less :
u < t ? std::weak_ordering::greater :
        std::weak_ordering::equivalent
  • 否则不定义合成三路比较，这使得 operator<=> 不参与重载决议。

若 three_way_comparable_with 或 boolean-testable 被满足但未被实现，则 operator<=> 的行为未定义。

 (C++20 起)

参数

lhs, rhs - 要比较的 tuple

返回值

1) 若对于所有 [0, sizeof...(Types)) 中的 i 有 std::get<i>(lhs) == std::get<i>(rhs) 则为 true ，否则为 false 。对二个空 tuple 返回 true 。
2) !(lhs == rhs)
3) 若 lhs 中的首个不等价元素小于 rhs 中的则为 true ，若 rhs 中的首个不等价元素小于 lhs 中的或无不等价元素则为 false 。对两个空 tuple 返回 false 。
4) !(rhs < lhs)
5) rhs < lhs
6) !(lhs < rhs)
7) 首对不等价元素间的关系，若存在不等价元素，否则为 std::strong_ordering::equal 。对两个空 tuple 返回 std::strong_ordering::equal 。

示例

因为 operator< 对 tuples 定义，故能排序 tuple 的容器。

#include <iostream>
#include <tuple>
#include <vector>
#include <algorithm>
int main()
{
    std::vector<std::tuple<int, std::string, float>> v;
    v.emplace_back(2, "baz", -0.1);
    v.emplace_back(2, "bar", 3.14);
    v.emplace_back(1, "foo", 100.1);
    std::sort(v.begin(), v.end());

    for(auto p: v) {
        std::cout << "(" << std::get<0>(p) << ", " << std::get<1>(p)
                  << ", " << std::get<2>(p) << ")\n";
    }
}

输出：

(1, foo, 100.1)
(2, bar, 3.14)
(2, baz, -0.1)

参阅


std::tuple<Types...>::swap

< cpp‎ | utility‎ | tuple
定义于头文件 <tuple> |
void swap( tuple& other ) noexcept(/* see below */); | (C++11 起) (C++20 前)
constexpr void swap( tuple& other ) noexcept(/* see below */); | (C++20 起)

对 *this 中的每个元素与 other 中其对应元素调用 swap （可以是 std::swap ，或通过 ADL 找到的）。

参数

other - 要交换值的 tuple

返回值

（无）

异常

noexcept 说明：
noexcept(

noexcept(swap( std::declval <T0&>>(), std::declval <T0&>())) &&
noexcept(swap( std::declval <T1&>>(), std::declval <T1&>())) &&
noexcept(swap( std::declval <T2&>>(), std::declval <T2&>())) &&
...

)

上述表达式中，以 C++17 std::is_nothrow_swappable 特性所用的相同方式查找标识符 swap 。

 (C++17 前)
noexcept 说明：
noexcept(

std::is_nothrow_swappable_v <T0> &&
std::is_nothrow_swappable_v <T1> &&
std::is_nothrow_swappable_v <T2> &&
...

)
 (C++17 起)

示例

#include <iostream>
#include <tuple>
#include <string>

int main()
{
    std::tuple<int, std::string, float> p1, p2;
    p1 = std::make_tuple(10, "test", 3.14);
    p2.swap(p1);
    std::cout << "("  << std::get<0>(p2)
              << ", " << std::get<1>(p2)
              << ", " << std::get<2>(p2) << ")\n";
}

输出：

(10, test, 3.14)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2456 | C++11 | noexcept 规定曾为病式 | 令它有效

参阅


std::swap(std::tuple)

< cpp‎ | utility‎ | tuple
定义于头文件 <tuple> |
template< class... Types > void swap( tuple<Types...>& lhs, tuple<Types...>& rhs ) noexcept(/* see below */); | (C++11 起) (C++20 前)
template< class... Types > constexpr void swap( tuple<Types...>& lhs, tuple<Types...>& rhs ) noexcept(/* see below */); | (C++20 起)

交换 lhs 与 rhs 的内容。等价于 lhs.swap(rhs) 。

此函数不参与重载决议，除非 std::is_swappable_v <Ti> 对来自从 0 到 sizeof...(Types) 的所有 i 为 true 。

 (C++17 起)

参数

lhs, rhs - 要交换内容的 tuple

返回值

（无）

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))

参阅


std::tie

< cpp‎ | utility‎ | tuple
定义于头文件 <tuple> |
template< class... Types > std::tuple <Types&...> tie( Types&... args ) noexcept; | (C++11 起) (C++14 前)
template< class... Types > constexpr std::tuple <Types&...> tie( Types&... args ) noexcept; | (C++14 起)

创建到其参数或 std::ignore 实例的左值引用的 tuple 。

参数

args - 构造 tuple 所用的零或更多左值参数

返回值

含左值引用的 std::tuple 对象。

可能的实现

template <typename... Args>
constexpr // C++14 起
std::tuple<Args&...> tie(Args&... args) noexcept {
    return {args...};
}

注解

std::tie 可用于解包 std::pair ，因为 std::tuple 拥有从 pair 的转换赋值：

bool result;
std::tie(std::ignore, result) = set.insert(value);

示例

std::tie 能用于引入字典序比较到结构体，或解包 tuple ：

#include <iostream>
#include <string>
#include <set>
#include <tuple>

struct S {
    int n;
    std::string s;
    float d;
    bool operator<(const S& rhs) const
    {
        // 比较 n 与 rhs.n,
        // 然后为 s 与 rhs.s,
        // 然后为 d 与 rhs.d
        return std::tie(n, s, d) < std::tie(rhs.n, rhs.s, rhs.d);
    }
};

int main()
{
    std::set<S> set_of_s; // S 为可比较小于 (LessThanComparable)

    S value{42, "Test", 3.14};
    std::set<S>::iterator iter;
    bool inserted;

    // 解包 insert 的返回值为 iter 与 inserted
    std::tie(iter, inserted) = set_of_s.insert(value);

    if (inserted)
        std::cout << "Value was inserted successfully\n";
}

输出：

Value was inserted successfully

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
make_tuple | 创建一个 tuple 对象，其类型根据各实参类型定义 (函数模板)
forward_as_tuple | 创建转发引用的 tuple (函数模板)
tuple_cat | 通过连接任意数量的元组来创建一个tuple (函数模板)
ignore | 用 tie 解包 tuple 时用来跳过元素的占位符 (常量)


std::tuple<Types...>::tuple

< cpp‎ | utility‎ | tuple
定义于头文件 <tuple>
constexpr tuple();
 (1) (C++11 起)
(条件性 explicit)
tuple( const Types&... args );
 (2) (C++11 起)
(C++14 起为 constexpr)
(条件性 explicit)
template< class... UTypes >
tuple( UTypes&&... args );
 (3) (C++11 起)
(C++14 起为 constexpr)
(条件性 explicit)
template< class... UTypes >
tuple( const tuple<UTypes...>& other );
 (4) (C++11 起)
(C++14 起为 constexpr)
(条件性 explicit)
template <class... UTypes>
tuple( tuple<UTypes...>&& other );
 (5) (C++11 起)
(C++14 起为 constexpr)
(条件性 explicit)
template< class U1, class U2 >
tuple( const pair<U1,U2>& p );
 (6) (C++11 起)
(C++14 起为 constexpr)
(条件性 explicit)
template< class U1, class U2 >
tuple( pair<U1,U2>&& p );
 (7) (C++11 起)
(C++14 起为 constexpr)
(条件性 explicit)
tuple( const tuple& other ) = default;
 (8) (C++11 起)
tuple( tuple&& other ) = default;
 (9) (C++11 起)
template< class Alloc >
tuple( std::allocator_arg_t, const Alloc& a );
 (10) (C++11 起)
(C++20 起为 constexpr)
(条件性 explicit)
template< class Alloc >

tuple( std::allocator_arg_t, const Alloc& a,

const Types&... args );
 (11) (C++11 起)
(C++20 起为 constexpr)
(条件性 explicit)
template< class Alloc, class... UTypes >

tuple( std::allocator_arg_t, const Alloc& a,

UTypes&&... args );
 (12) (C++11 起)
(C++20 起为 constexpr)
(条件性 explicit)
template <class Alloc, class... UTypes>

tuple( std::allocator_arg_t, const Alloc& a,

const tuple<UTypes...>& other );
 (13) (C++11 起)
(C++20 起为 constexpr)
(条件性 explicit)
template< class Alloc, class... UTypes >

tuple( std::allocator_arg_t, const Alloc& a,

tuple<UTypes...>&& other );
 (14) (C++11 起)
(C++20 起为 constexpr)
(条件性 explicit)
template< class Alloc, class U1, class U2 >

tuple( std::allocator_arg_t, const Alloc& a,

const pair<U1, U2>& p );
 (15) (C++11 起)
(C++20 起为 constexpr)
(条件性 explicit)
template< class Alloc, class U1, class U2 >

tuple( std::allocator_arg_t, const Alloc& a,

pair<U1, U2>&& p );
 (16) (C++11 起)
(C++20 起为 constexpr)
(条件性 explicit)
template< class Alloc >

tuple( std::allocator_arg_t, const Alloc& a,

const tuple& other );
 (17) (C++11 起)
(C++20 起为 constexpr)
template< class Alloc >

tuple( std::allocator_arg_t, const Alloc& a,

tuple&& other );
 (18) (C++11 起)
(C++20 起为 constexpr)

构造新的 tuple 。

1) 默认构造函数。值初始化所有元素，若存在。若 sizeof...(Types) == 0 则默认构造函数为平凡。
  • 此重载仅若 std::is_default_constructible <Ti>::value 对所有 i 为 true 才参与重载决议。
  • 构造函数若且唯若对至少一个 i 有 Ti 不可从 {} 复制列表初始化才为 explicit 。
2) 直接构造函数。以对应参数初始化 tuple 的每个元素。
  • 此重载仅若 sizeof...(Types) >= 1 与 std::is_copy_constructible <Ti>::value 对所有 i 为 true 才参与重载决议。
  • 此构造函数若且唯若 std::is_convertible <const Ti&, Ti>::value 对至少一个 i 为 false 才为 explicit 。
3) 转换构造函数。以 std::forward <UTypes>(args) 中的对应值初始化 tuple 的每个元素。
  • 此重载仅若 sizeof...(Types) == sizeof...(UTypes) 且 sizeof...(Types) >= 1 与 std::is_constructible <Ti, Ui&&>::value 对所有 i 为 true 才参与重载决议。
  • 构造函数若且唯若才 std::is_convertible <Ui&&, Ti>::value 对至少一个 i 为 false 为 explicit 。
4) 转换复制构造函数。对 sizeof...(UTypes) 中所有 i ，以 std::get<i>(other) 初始化 tuple 的第 i 个元素。
  • 此重载仅若
    • sizeof...(Types) == sizeof...(UTypes) 且
    • std::is_constructible_v <Ti, const Ui&> 对所有 i 为 true 且
    • 以下之一成立
      • sizeof...(Types) != 1 或
      • （ Types... 展开成 T 且 UTypes... 展开成 U 时） std::is_convertible_v <const tuple<U>&, T> 、 std::is_constructible_v <T, const tuple<U>&> 与 std::is_same_v <T, U> 均为 false 才参与重载决议。
  • 构造函数若且唯若 std::is_convertible <const Ui&, Ti>::value 对至少一个 i 为 false 才为 explicit 。
5) 转换移动构造函数。对 sizeof...(UTypes) 中所有 i ，以 std::forward <Ui>(std::get<i>(other)) 初始化 tuple 的第 i 个元素。
  • 此重载仅若
    • sizeof...(Types) == sizeof...(UTypes) 且
    • std::is_constructible_v <Ti, Ui&&> 对所有 i 为 true 且
    • 以下之一成立
      • sizeof...(Types) != 1 或
      • （ Types... 展开成 T 且 UTypes... 展开成 U 时） std::is_convertible_v <tuple<U>, T> 、 std::is_constructible_v <T, tuple<U>> 与 std::is_same_v <T, U> 均为 false 才参与重载决议。
  • 构造函数若且唯若 std::is_convertible <Ui&&, Ti>::value 对至少一个 i 为 false 才为 explicit 。
6) pair 复制构造函数。构造 2-tuple ，从 p.first 构造第一个元素，从 p.second 构造第二个元素。
  • 此重载仅若 sizeof...(Types) == 2 与 std::is_constructible <T0,const U1&>::value 与 std::is_constructible <T1, const U2&>::value 均为 true 才参与重载决议。
  • 构造函数若且唯若 std::is_convertible <const U1&, T0>::value 或 std::is_convertible <const U2&, T1>::value 为 false 才为 explicit 。
7) pair 移动构造函数。构造 2-tuple ，从 std::forward <U1>(p.first) 构造第一个元素，从 std::forward <U2>(p.second) 构造第二个元素。
  • 此重载仅若 sizeof...(Types) == 2 与 std::is_constructible <T0, U1&&>::value 与 std::is_constructible <T1, U2&&>::value 均为 true 才参与重载决议。
  • 构造函数若且唯若 std::is_convertible <U1&&, T0>::value 或 std::convertible<U2&&, T1>::value 为 false 才为 explicit 。
8) 隐式定义的复制构造函数。以 other 的对应元素初始化 tuple 的每个元素。
  • 若此函数进行的每个操作都是 constexpr ，则它是 constexpr 。对于空 tuple std::tuple <> ，它是 constexpr 。
  • std::is_copy_constructible <Ti>::value 必须对所有 i 为 true ，否则行为未定义 (C++20 前)程序为谬构 (C++20 起)。
9) 隐式定义的移动构造函数。以 std::forward <Ui>(std::get<i>(other)) 构造 tuple 的第 i 个元素。
若此函数进行的每个操作都是 constexpr ，则它是 constexpr 。对于空 tuple std::tuple <> ，它是 constexpr 。
  • std::is_move_constructible <Ti>::value 必须对所有 i 为 true ，否则行为未定义 (C++20 前)此重载不参与重载决议 (C++20 起)。
10-18) 等同于 (1-9) ，除了以使用分配器构造创建每个元素每个元素，即以分配器对象 a 为额外参数传递给每个 std::uses_allocator <Ui, Alloc>::value 为 true 的对象的构造函数。

参数

args | - | 用于初始化 tuple 每个元素的值
other | - | 用于初始化 tuple 每个元素的值的 tuple
p | - | 用于初始化此 2-tuple 的两个元素的值的 pair
a | - | 用于使用分配器构造的分配器

注解

条件性 explicit 的构造函数使得可以用列表初始化语法于复制初始化语境构造 tuple ：

std::tuple<int, int> foo_tuple()
{
  return {1, -1};  // N4387 前错误
  return std::make_tuple(1, -1); // 始终工作
}

注意若列表中某元素不可隐式转换成目标 tuple 中的对应元素，则构造函数变为 explicit 。

using namespace std::chrono;
void launch_rocket_at(std::tuple<hours, minutes, seconds>);

launch_rocket_at({hours(1), minutes(2), seconds(3)}); // OK
launch_rocket_at({1, 2, 3}); // 错误： int 不可隐式转换成 duration
launch_rocket_at(std::tuple<hours, minutes, seconds>{1, 2, 3}); // OK

示例

#include <iostream>
#include <string>
#include <vector>
#include <tuple>
#include <memory>

// 打印任何大小 tuple 的辅助函数
template<class Tuple, std::size_t N>
struct TuplePrinter {
    static void print(const Tuple& t)
    {
        TuplePrinter<Tuple, N-1>::print(t);
        std::cout << ", " << std::get<N-1>(t);
    }
};

template<class Tuple>
struct TuplePrinter<Tuple, 1>{
    static void print(const Tuple& t)
    {
        std::cout << std::get<0>(t);
    }
};

template<class... Args>
void print(const std::tuple<Args...>& t)
{
    std::cout << "(";
    TuplePrinter<decltype(t), sizeof...(Args)>::print(t);
    std::cout << ")\n";
}
// 辅助函数结束

int main()
{
    std::tuple<int, std::string, double> t1;
    std::cout << "Value-initialized: "; print(t1);
    std::tuple<int, std::string, double> t2(42, "Test", -3.14);
    std::cout << "Initialized with values: "; print(t2);
    std::tuple<char, std::string, int> t3(t2);
    std::cout << "Implicitly converted: "; print(t3);
    std::tuple<int, double> t4(std::make_pair(42, 3.14));
    std::cout << "Constructed from a pair"; print(t4);

    // 给出分配器 (Allocator) my_alloc ，带单参数构造函数 my_alloc(int)
    // 用 my_alloc(1) 于 vector 中分配 10 个 int
    std::vector<int, my_alloc> v(10, 1, my_alloc(1));
    // 用 my_alloc(2) 于 tuple 中的 vector 分配 10 个 int
    std::tuple<int, std::vector<int, my_alloc>, double> t5(std::allocator_arg,
                                                           my_alloc(2), 42, v,  -3.14);
}

可能的输出：

Value-initialized: (0, , 0)
Initialized with values: (42, Test, -3.14)
Implicitly converted: (*, Test, -3)
Constructed from a pair(42, 3.14)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
N4387 | C++11 | 某些构造函数曾为 explicit ，阻止了有用的行为 | 使大多数构造函数为条件性 explicit
LWG 2510 | C++11 | 默认构造函数为隐式 | 使之为条件性 explicit
LWG 3158 | C++11 | 对应默认构造函数的使用分配器构造函数为隐式 | 使之为条件性 explicit
LWG 3211 | C++11 | 未指定 tuple<> 的默认构造函数是否为平凡 | 要求为平凡

参阅

make_tuple | 创建一个 tuple 对象，其类型根据各实参类型定义 (函数模板)
tie | 创建左值引用的 tuple，或将 tuple 解包为独立对象 (函数模板)
forward_as_tuple | 创建转发引用的 tuple (函数模板)


std::tuple_cat

< cpp‎ | utility‎ | tuple
定义于头文件 <tuple> |
template< class... Tuples > std::tuple <CTypes...> tuple_cat(Tuples&&... args); | (C++11 起) (C++14 前)
template< class... Tuples > constexpr std::tuple <CTypes...> tuple_cat(Tuples&&... args); | (C++14 起)

构造所有 args 中的 tuple 所连接成 tuple 。

若 std::decay_t <Tuples>... 中的任何类型不是 std::tuple 的特化则行为未定义。然而，实现可以选择支持遵循仿 tuple 协议的类型（例如 std::array 与 std::pair ）。

参数

args - 要连接的零或更多 tuple

返回值

std::tuple 对象，由所有参数 tuple 的所有元素组成，对于每个独立元素构造自 std::get<i>( std::forward <Ti>(arg)) 。

示例

#include <iostream>
#include <tuple>
#include <string>

// 打印任何大小 tuple 的帮助函数
template<class Tuple, std::size_t N>
struct TuplePrinter {
    static void print(const Tuple& t)
    {
        TuplePrinter<Tuple, N-1>::print(t);
        std::cout << ", " << std::get<N-1>(t);
    }
};

template<class Tuple>
struct TuplePrinter<Tuple, 1> {
    static void print(const Tuple& t)
    {
        std::cout << std::get<0>(t);
    }
};

template<class... Args>
void print(const std::tuple<Args...>& t)
{
    std::cout << "(";
    TuplePrinter<decltype(t), sizeof...(Args)>::print(t);
    std::cout << ")\n";
}
// 结束帮助函数

int main()
{
    std::tuple<int, std::string, float> t1(10, "Test", 3.14);
    int n = 7;
    auto t2 = std::tuple_cat(t1, std::make_tuple("Foo", "bar"), t1, std::tie(n));
    n = 10;
    print(t2);
}

输出：

(10, Test, 3.14, Foo, bar, 10, Test, 3.14, 10)

参阅

make_tuple | 创建一个 tuple 对象，其类型根据各实参类型定义 (函数模板)
tie | 创建左值引用的 tuple，或将 tuple 解包为独立对象 (函数模板)
forward_as_tuple | 创建转发引用的 tuple (函数模板)


std::tuple_element<std::tuple>

< cpp‎ | utility‎ | tuple
定义于头文件 <tuple>
template< std::size_t I, class... Types >
class tuple_element< I, tuple<Types...> >;
 (C++11 起)

提供 tuple 元素类型的编译时带下标访问。

成员类型

成员类型 | 定义
type | tuple 的第 I 元素的类型，其中 I 在 [0, sizeof...(Types)) 中

可能的实现

template< std::size_t I, class T >
struct tuple_element;

// 递归情况
template< std::size_t I, class Head, class... Tail >
struct tuple_element<I, std::tuple<Head, Tail...>>
    : std::tuple_element<I-1, std::tuple<Tail...>> { };

// 基础情况
template< class Head, class... Tail >
struct tuple_element<0, std::tuple<Head, Tail...>> {
   using type = Head;
};

示例

#include <iostream>
#include <tuple>

template <class... Args>
struct type_list
{
   template <std::size_t N>
   using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
};

int main()
{
   std::cout << std::boolalpha;
   type_list<int, char, bool>::type<2> x = true;
   std::cout << x << '\n';
}

输出：

true

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
tuple_size (C++11) | 获得元组式类型的元素数 (类模板)
std::get(std::tuple) | 元组式访问指定的元素 (函数模板)


std::tuple_size<std::tuple>

< cpp‎ | utility‎ | tuple
定义于头文件 <tuple>
template< class... Types >

struct tuple_size< std::tuple <Types...> >

: std::integral_constant < std::size_t, sizeof...(Types)> { };
 (C++11 起)

提供对 tuple 中元素数量的访问，作为编译时常量表达式。

继承自 std::integral_constant

成员常量

value
[静态]
 sizeof...(Types)
(公开静态成员常量)

成员函数

operator std::size_t | 转换对象为 std::size_t ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | std::size_t
type | std::integral_constant < std::size_t, value>

示例

#include <iostream>
#include <tuple>

template <class T>
void test(T value)
{
    int a[std::tuple_size_v<T>]; // 能用于编译时

    std::cout << std::tuple_size<T>{} << ' ' // 或运行时
              << sizeof a << ' '
              << sizeof value << '\n';
}

int main()
{
    test(std::make_tuple(1, 2, 3.14));
}

可能的输出：

3 12 16

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
tuple_size (C++11) | 获得元组式类型的元素数 (类模板)
std::get(std::tuple) | 元组式访问指定的元素 (函数模板)


std::uses_allocator<std::tuple>

< cpp‎ | utility‎ | tuple
定义于头文件 <tuple> |
template< class... Types, class Alloc > struct uses_allocator< std::tuple <Types...>, Alloc > : std::true_type { }; | (C++11 起)

此 std::uses_allocator 的特化告诉其他库组件 tuples 支持使用分配器构造，即使它们无嵌套的 allocator_type.

继承自 std::integral_constant

成员常量

value
[静态]
 true
(公开静态成员常量)

成员函数

operator bool | 转换对象为 bool ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | bool
type | std::integral_constant <bool, value>

示例

// myalloc 是带接收 int 的单参数构造函数的有状态分配器（Allocator）。
// 它无默认构造函数

    typedef std::vector<int, myalloc<int>> innervector_t;
    typedef std::tuple<int, innervector_t> elem_t;
    typedef std::scoped_allocator_adaptor< myalloc<elem_t>, myalloc<int>> Alloc;
    Alloc a(1,2);
    std::vector<elem_t, Alloc> v(a);
    v.resize(1);                  // 对 v 的元素用分配器 #1
    std::get<1>(v[0]).resize(10); // 对 innervector_t 用分配器 #2

参阅

uses_allocator
(C++11)
 检查指定的类型是否支持使用分配器的构造
(类模板)


std::tuple_element

< cpp‎ | utility
定义于头文件 <tuple>
定义于头文件 <array>
定义于头文件 <utility>
定义于头文件 <ranges>
(C++20 起)
template< std::size_t I, class T >
struct tuple_element; // 不定义
 (1) (C++11 起)
template< std::size_t I, class T >

struct tuple_element< I, const T > {
using type = typename
std::add_const <typename std::tuple_element <I, T>::type>::type;

};
 (2) (C++11 起)
template< std::size_t I, class T >

struct tuple_element< I, volatile T > {
using type = typename
std::add_volatile <typename std::tuple_element <I, T>::type>::type;

};
 (3) (C++11 起)
(C++20 中弃用)
template< std::size_t I, class T >

struct tuple_element< I, const volatile T > {
using type = typename
std::add_cv <typename std::tuple_element <I, T>::type>::type;

};
 (4) (C++11 起)
(C++20 中弃用)

提供对元组式类型的元素类型的编译时下标访问。

1) 不定义主模板。要求显式（全）或部分特化以令类型为元组式。
2-4) 对 cv 限定类型的特化默认简单地添加对应的 cv 限定符。

std::tuple_element 与核心语言交互：它能在元组式情况下提供结构化绑定支持。

 (C++17 起)

特化

标准库对标准库类型提供下列特化：

std::tuple_element<std::tuple> (C++11) | 获得指定元素的类型 (类模板特化)
std::tuple_element<std::pair> (C++11) | 获得 pair 中元素的类型 (类模板特化)
std::tuple_element<std::array> (C++11) | 获得 array 元素的类型 (类模板特化)
std::tuple_element<std::ranges::subrange> (C++20) | 获得 std::ranges::subrange 的迭代器或哨位的类型 (类模板特化)

用户可以对程序定义类型特化 std::tuple_size 以令它们为元组式。

在 get 函数返回引用成员或到子对象的引用的通常情况下，只需要定制对 cv 无限定类型的特化。

成员类型

成员类型 | 定义
type | 对标准特化，为元组式类型 T 的第 I 个元素，其中 I 在 [0, std::tuple_size <T>::value) 中

辅助类型

定义于头文件 <tuple>
template < std::size_t I, class T>
using tuple_element_t = typename tuple_element<I, T>::type;
 (C++14 起)

示例

#include <array>
#include <cstddef>
#include <iostream>
#include <ranges>
#include <tuple>
#include <type_traits>
#include <utility>

template <typename T1, typename T2, typename T3>
    struct Triple { T1 t1; T2 t2; T3 t3; };

// A specialization of std::tuple_element for program-defined type Triple:
template <std::size_t I, typename T1, typename T2, typename T3>
    struct std::tuple_element<I, Triple<T1, T2, T3>> { static_assert(I < 4); };
template <typename T1, typename T2, typename T3>
    struct std::tuple_element<0, Triple<T1, T2, T3>> { using type = T1; };
template <typename T1, typename T2, typename T3>
    struct std::tuple_element<1, Triple<T1, T2, T3>> { using type = T2; };
template <typename T1, typename T2, typename T3>
    struct std::tuple_element<2, Triple<T1, T2, T3>> { using type = T3; };

template <typename... Args> struct TripleTypes {
    static_assert(3 == sizeof...(Args), "Expected exactly 3 type names!");
    template <std::size_t N>
        using type = typename std::tuple_element_t<N, Triple<Args...>>;
};

int main()
{
    TripleTypes<char, int, float>::type<1> i{42};
    std::cout << i << '\n';

    using Tri = Triple<int, char, short>; //< Program-defined type
    static_assert(std::is_same_v<std::tuple_element_t<0, Tri>, int> &&
                  std::is_same_v<std::tuple_element_t<1, Tri>, char> &&
                  std::is_same_v<std::tuple_element_t<2, Tri>, short>);

    using Tuple = std::tuple<int, char, short>;
    static_assert(std::is_same_v<std::tuple_element_t<0, Tuple>, int> &&
                  std::is_same_v<std::tuple_element_t<1, Tuple>, char> &&
                  std::is_same_v<std::tuple_element_t<2, Tuple>, short>);

    using Array3 = std::array<int, 3>;
    static_assert(std::is_same_v<std::tuple_element_t<0, Array3>, int> &&
                  std::is_same_v<std::tuple_element_t<1, Array3>, int> &&
                  std::is_same_v<std::tuple_element_t<2, Array3>, int>);

    using Pair = std::pair<Tuple, Tri>;
    static_assert(std::is_same_v<std::tuple_element_t<0, Pair>, Tuple> &&
                  std::is_same_v<std::tuple_element_t<1, Pair>, Tri>);

    using Sub = std::ranges::subrange<int*, int*>;
    static_assert(std::is_same_v<std::tuple_element_t<0, Sub>, int*> &&
                  std::is_same_v<std::tuple_element_t<1, Sub>, int*>);
}

输出：

42

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2212 | C++11 | 未在某些头文件中要求对 cv 类型的特化，这导致歧义 | 已要求

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
tuple_size (C++11) | 获得元组式类型的元素数 (类模板)
tuple_cat | 通过连接任意数量的元组来创建一个tuple (函数模板)


std::tuple_size

< cpp‎ | utility
定义于头文件 <tuple> |  |
定义于头文件 <array> |  |
定义于头文件 <utility> |  |
定义于头文件 <ranges> |  | (C++20 起)
template< class T > struct tuple_size; // 不定义 | (1) | (C++11 起)
template< class T > struct tuple_size< const T > : std::integral_constant < std::size_t, std::tuple_size <T>::value> { }; | (2) | (C++11 起)
template< class T > struct tuple_size< volatile T > : std::integral_constant < std::size_t, std::tuple_size <T>::value> { }; | (3) | (C++11 起) (C++20 中弃用)
template< class T > struct tuple_size< const volatile T > : std::integral_constant < std::size_t, std::tuple_size <T>::value> { }; | (4) | (C++11 起) (C++20 中弃用)

提供作为常量表达式的元组式类型中元素数的访问。

1) 不定义主模板。要求显式（全）或部分特化以令类型为元组式。
2-4) 对 cv 限定类型的特化默认复用对应 cv 无限定版本的 value 。

std::tuple_size 与核心语言交互：它能在元组式情况中提供结构化绑定支持。

(2-4) 为 SFINAE 友好：若在作为不求值操作数时 std::tuple_size <T>::value 为非良构，则它们不提供成员 value 。如同在与 tuple_size 和 T 无关的场景进行访问检查。仅考虑表达式的立即语境的合法性。这允许

#include <utility>
struct X { int a, b; };
const auto [x, y] = X(); // 结构化绑定声明首先尝试 tuple_size<const X> ，而它尝试
                         // tuple_size<X>::value ，然后遇到软错误，绑定到公开数据成员
 (C++17 起)

特化

标准库对标准库类型提供下列特化：

std::tuple_size<std::tuple> (C++11) | 在编译时获得 tuple 的大小 (类模板特化)
std::tuple_size<std::pair> (C++11) | 获得 pair 的大小 (类模板特化)
std::tuple_size<std::array> (C++11) | 获得 array 的大小 (类模板特化)
std::tuple_size<std::ranges::subrange> (C++20) | 获得 std::ranges::subrange 的组分数量 (类模板特化)

std::tuple_size 的所有特化满足基特征为 std::integral_constant < std::size_t, N> 某个 N 的一元类型特征 (UnaryTypeTrait) 。

用户可以对程序定义类型特化 std::tuple_size 以令它们为元组式。程序定义特化必须满足上述要求。

通常只需要定制对 cv 无限定类型的特化。

辅助变量模板

定义于头文件 <tuple> |
template< class T > inline constexpr std::size_t tuple_size_v = tuple_size<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 对于标准特化，为元组式类型 T 的元素数
(公开静态成员常量)

成员函数

operator std::size_t | 转换对象为 std::size_t ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | std::size_t
type | std::integral_constant < std::size_t, value>

示例

本节未完成
原因：暂无示例

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2212 | C++11 | 未在某些头文件中要求对 cv 类型的特化，这导致歧义 | 已要求

参阅

结构化绑定 (C++17) | 绑定指定的名字到初始化器的子对象或元组元素
tuple_element (C++11) | 获得元组式类型的元素类型 (类模板)
tuple_cat | 通过连接任意数量的元组来创建一个tuple (函数模板)


变参数函数

< cpp‎ | utility

变参数函数是接收可变数量参数的函数（例如 std::printf ）。

为声明变参数函数，省略号要出现在参数列表后，例如 int printf(const char* format, ...); ，可以前附可选的逗号。语法上的额外细节、自动参数转换及替用项见变参数。

为从函数体内访问可变参数，标准库提供下列库设施：

定义于头文件 <cstdarg>
va_start | 启用对可变函数实参的访问 (宏函数)
va_arg | 访问下一个可变函数实参 (宏函数)
va_copy (C++11) | 制造可变函数实参的副本 (宏函数)
va_end | 结束对可变函数实参的遍历 (宏函数)
va_list | 保有 va_start、va_arg、va_end 和 va_copy 所需的信息 (typedef)

示例

#include <iostream>
#include <cstdarg>

void simple_printf(const char* fmt...) // C 风格 "const char* fmt, ..." 亦合法
{
    va_list args;
    va_start(args, fmt);

    while (*fmt != '\0') {
        if (*fmt == 'd') {
            int i = va_arg(args, int);
            std::cout << i << '\n';
        } else if (*fmt == 'c') {
            // 注意自动转换到整数类型
            int c = va_arg(args, int);
            std::cout << static_cast<char>(c) << '\n';
        } else if (*fmt == 'f') {
            double d = va_arg(args, double);
            std::cout << d << '\n';
        }
        ++fmt;
    }

    va_end(args);
}

int main()
{
    simple_printf("dcff", 3, 'a', 1.999, 42.5);
}

输出：

3
a
1.999
42.5

参阅


va_arg

< cpp‎ | utility‎ | variadic
定义于头文件 <cstdarg>
T va_arg( std::va_list ap, T );

va_arg 宏展开成对应来自 std::va_list ap 的下个参数的 T 类型表达式。

在调用 va_arg 前， ap 必须为到 va_start 或 va_copy 的调用所初始化，中间不能夹带 va_end 的调用。 va_arg 宏的每次调用都修改 ap ，令它指向下个可变参数。

若 ap 中的下个参数类型（提升后）与 T 不兼容，则行为未定义，除非：

  • 一个类型是有符号整数类型，而另一类型是无符号整数类型，且值能用两个类型表示；或
  • 一个类型是指向 void 的指针，而另一类型是指向字符类型（ char 、 signed char 或 unsigned char ）的指针。

若在 ap 中无更多参数时调用 va_arg ，则行为未定义。

参数

ap | - | std::va_list 类型的实例
T | - | ap 中下个参数的类型

展开值

ap 中的下个可变参数

示例

#include <iostream>
#include <cstdarg>
#include <cmath>

double stddev(int count, ...)
{
    double sum = 0;
    double sum_sq = 0;
    std::va_list args;
    va_start(args, count);
    for (int i = 0; i < count; ++i) {
        double num = va_arg(args, double);
        sum += num;
        sum_sq += num*num;
    }
    va_end(args);
    return std::sqrt(sum_sq/count - (sum/count)*(sum/count));
}

int main()
{
    std::cout << stddev(4, 25.0, 27.3, 26.9, 25.7) << '\n';
}

输出：

0.920258

参阅

va_start | 启用对可变函数实参的访问 (宏函数)
va_copy (C++11) | 制造可变函数实参的副本 (宏函数)
va_end | 结束对可变函数实参的遍历 (宏函数)


va_copy

< cpp‎ | utility‎ | variadic
定义于头文件 <cstdarg> |
void va_copy( std::va_list dest, std::va_list src ); | (C++11 起)

va_copy 宏复制 src 到 dest 。

va_end 应当在函数返回前或任何 dest 的后继重初始化（通过对 va_start 或 va_copy 的调用）前对 dest 调用。

参数

dest | - | 要初始化的 std::va_list 类型实例
src | - | 将用于初始化 dest 的源 std::va_list

展开值

（无）

示例

#include <iostream>
#include <cstdarg>
#include <cmath>

double sample_stddev(int count, ...)
{
    double sum = 0;
    std::va_list args1;
    va_start(args1, count);
    std::va_list args2;
    va_copy(args2, args1);
    for (int i = 0; i < count; ++i) {
        double num = va_arg(args1, double);
        sum += num;
    }
    va_end(args1);
    double mean = sum / count;

    double sum_sq_diff = 0;
    for (int i = 0; i < count; ++i) {
        double num = va_arg(args2, double);
        sum_sq_diff += (num-mean) * (num-mean);
    }
    va_end(args2);
    return std::sqrt(sum_sq_diff / count);
}

int main()
{
    std::cout << sample_stddev(4, 25.0, 27.3, 26.9, 25.7) << '\n';
}

输出：

0.920258

参阅

va_start | 启用对可变函数实参的访问 (宏函数)
va_arg | 访问下一个可变函数实参 (宏函数)
va_end | 结束对可变函数实参的遍历 (宏函数)


va_end

< cpp‎ | utility‎ | variadic
定义于头文件 <cstdarg>
void va_end( va_list ap );

va_end 宏进行对为 va_start 或 va_copy 所初始化的 ap 对象的清理。 va_end 可以修改 ap 并令它不再可用。

若无对应的对 va_start 或 va_copy 的调用，或若 va_end 未在调用 va_start 或 va_copy 的函数返回前调用，则行为未定义。

参数

ap - 要清理的 va_list 类型实例

展开值

（无）

参阅

va_start | 启用对可变函数实参的访问 (宏函数)
va_copy (C++11) | 制造可变函数实参的副本 (宏函数)
va_arg | 访问下一个可变函数实参 (宏函数)


std::va_list

< cpp‎ | utility‎ | variadic
定义于头文件 <cstdarg>
typedef /* unspecified */ va_list;

va_list 是适用于保有宏 va_start 、 va_arg 及 va_end 所需信息的完整对象类型。

若创建 va_list 实例，并传递给另一函数，且通过 va_arg 在该函数中使用，则调用方函数的任何后继使用必须前附对 va_end 的调用。

传递指向 va_list 对象的指针给另一函数，并在函数返回后使用该对象是合法的。

参阅

va_start | 启用对可变函数实参的访问 (宏函数)
va_copy (C++11) | 制造可变函数实参的副本 (宏函数)
va_arg | 访问下一个可变函数实参 (宏函数)
va_end | 结束对可变函数实参的遍历 (宏函数)


va_start

< cpp‎ | utility‎ | variadic
定义于头文件 <cstdarg>
void va_start( std::va_list ap, parm_n );

va_start 宏允许访问后随具名参数 parm_n 的可变参数。

va_start 应当在任何对 va_arg 的调用前，以到合法 std::va_list 对象 ap 的实例调用。

若 parm_n 为包展开或源自 lambda 捕获的实体，则程序为非良构，不要求诊断。

 (C++11 起)

若 parm_n 以引用类型，或与来自默认参数提升的结果不兼容的类型声明，则行为未定义。

参数

ap | - | std::va_list 类型的实例
parm_n | - | 首个可变参数前紧接的具名参数

展开值

（无）

注解

要求 va_start 支持带重载的 operator& 的 parm_n 。

示例

#include <iostream>
#include <cstdarg>

int add_nums(int count, ...)
{
    int result = 0;
    std::va_list args;
    va_start(args, count);
    for (int i = 0; i < count; ++i) {
        result += va_arg(args, int);
    }
    va_end(args);
    return result;
}

int main()
{
    std::cout << add_nums(4, 25, 25, 50, 50) << '\n';
}

输出：

150

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
CWG 273 | C++98 | 若重载了一元 operator& 则 va_start 可能无法工作 | 即使重载了 operator& 也要求它正确工作

参阅

va_arg | 访问下一个可变函数实参 (宏函数)
va_end | 结束对可变函数实参的遍历 (宏函数)


std::variant

< cpp‎ | utility
定义于头文件 <variant> |
template <class... Types> class variant; | (C++17 起)

类模板 std::variant 表示一个类型安全的联合体。 std::variant 的一个实例在任意时刻要么保有其一个可选类型之一的值，要么在错误情况下无值（此状态难以达成，见 valueless_by_exception ）。

与联合体在聚合初始化中的行为一致, 若 variant 保有某个对象类型 T 的值，则直接于 variant 的对象表示中分配 T 的对象表示。不允许 variant 分配额外的（动态）内存。

variant 不容许保有引用、数组，或类型 void 。空 variant 亦为病式（可用 std::variant< std::monostate > 代替）。

variant 容许保有同一类型多于一次，而且可保有同一类型的不同 cv 限定版本。

同联合体，默认构造的 variant 保有其首个选项的值，除非该选项不是可默认构造的（该情况下 variant 亦非可默认构造：能用辅助类 std::monostate 使这种 variant 可默认构造）。

模板形参

Types - 可存储于此 variant 中的类型。所有类型必须满足可析构 (Destructible) 要求（特别是不允许数组类型和非对象类型）。

成员函数

(构造函数)
 构造 variant 对象
(公开成员函数)
(析构函数)
 析构 variant 同其所含的值
(公开成员函数)
operator=
 赋值 variant
(公开成员函数)
观察器
index
 返回 variant 所保有可选项的零基下标
(公开成员函数)
valueless_by_exception
 检查 variant 是否在非法状态
(公开成员函数)
修改器
emplace
 原位构造 variant 中的值
(公开成员函数)
swap
 与另一 variant 交换
(公开成员函数)

非成员函数

visit (C++17) | 以一或多个 variant 所保有的各实参调用所提供的函数对象 (函数模板)
holds_alternative (C++17) | 检查某个 variant 是否当前持有某个给定类型 (函数模板)
std::get(std::variant) (C++17) | 以给定索引或类型（若类型唯一）读取 variant 的值，错误时抛出异常 (函数模板)
get_if (C++17) | 以给定索引或类型（若其唯一），获得指向被指向的 variant 的值的指针，错误时返回空指针 (函数模板)
operator==operator!=operator<operator<=operator>operator>=operator<=> (C++17)(C++17)(C++17)(C++17)(C++17)(C++17)(C++20) | 以所含值比较 variant 对象 (函数模板)
std::swap(std::variant) (C++17) | 特化 std::swap 算法 (函数模板)

辅助类

monostate (C++17) | 用作非可默认构造类型的 variant 的首个可选项的占位符类型 (类)
bad_variant_access (C++17) | 非法地访问 variant 的值时抛出的异常 (类)
variant_sizevariant_size_v (C++17) | 在编译时获得 variant 可选项列表的大小 (类模板) (变量模板)
variant_alternativevariant_alternative_t (C++17) | 在编译时获得以其下标指定的可选项的类型 (类模板) (别名模板)
std::hash<std::variant> (C++17) | 特化 std::hash 算法 (类模板特化)

辅助对象

variant_npos
(C++17)
 非法状态的 variant 的下标
(常量)

示例

#include <variant>
#include <string>
#include <cassert>

int main()
{
    std::variant<int, float> v, w;
    v = 12; // v 含 int
    int i = std::get<int>(v);
    w = std::get<int>(v);
    w = std::get<0>(v); // 与前一行效果相同
    w = v; // 与前一行效果相同

//  std::get<double>(v); // 错误： [int, float] 中无 double
//  std::get<3>(v);      // 错误：合法下标值为 0 与 1

    try {
      std::get<float>(w); // w 含 int 而非 float ：将抛出
    }
    catch (const std::bad_variant_access&) {}

    using namespace std::literals;

    std::variant<std::string> x("abc"); // 转换构造函数在无歧义时起作用
    x = "def"; // 转换赋值在无歧义时亦起作用

    std::variant<std::string, void const*> y("abc");
    // 传递 char const * 时转换成 void const *
    assert(std::holds_alternative<void const*>(y)); // 成功
    y = "xyz"s;
    assert(std::holds_alternative<std::string>(y)); // 成功
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2901 | C++17 | 提供 std::uses_allocator 的特化，但 variant 不能正确支持分配器 | 移除特化

参阅

in_place in_place_type in_place_index in_place_t in_place_type_t in_place_index_t (C++17) | 原位构造标签 (类模板)
optional (C++17) | 可能或可能不保有一个对象的包装器 (类模板)
any (C++17) | 可保有任何可复制构造 (CopyConstructible) 类型的实例的对象。 (类)


std::bad_variant_access

< cpp‎ | utility‎ | variant
定义于头文件 <variant> |
class bad_variant_access : public std::exception | (C++17 起)

std::bad_variant_access 是下列情形中抛出的异常类型：

  • 以不匹配当前活跃可选项的下标或类型调用 std::get(std::variant)
  • 调用 std::visit 观览因异常无值 (valueless_by_exception) 的 variant

成员函数

(构造函数) | 构造新的 bad_variant_access 对象 (公开成员函数)
operator= | 替换 bad_variant_access 对象 (公开成员函数)
what | 返回解释字符串 (公开成员函数)

std::bad_variant_access::bad_variant_access

bad_variant_access() noexcept; | (1) | (C++17 起)
bad_variant_access( const bad_variant_access& other ) noexcept; | (2) | (C++17 起)

构造新的拥有实现定义的空终止字节字符串的 bad_variant_access 对象，字符串能通过 what() 访问。

1) 默认构造函数。
2) 复制构造函数。若 *this 与 other 均拥有动态类型 std::bad_variant_access 则 std::strcmp (what(), other.what()) == 0 。

参数

other - 要复制的另一异常对象

std::bad_variant_access::operator=

bad_variant_access& operator=( const bad_variant_access& other ) noexcept; | (C++17 起)

以 other 的内容赋值。若 *this 与 other 均拥有动态类型 std::bad_variant_access 则赋值后 std::strcmp (what(), other.what()) == 0 。

参数

other - 用以赋值的另一异常对象

返回值

*this

std::bad_variant_access::what

virtual const char* what() const noexcept; | (C++17 起)

返回解释字符串。

参数

（无）

返回值

指向有解释信息的空终止字符串的指针。该字符串适合转换并显示为 std::wstring 。保证该指针至少到获得它来源的异常对象被销毁，或在该异常对象上调用非 const 成员函数（例如复制赋值运算符）为止合法。

注解

允许但不要求实现覆写 what() 。

继承自 std::exception

成员函数

(析构函数) [虚] | 析构该异常对象 (std::exception 的虚公开成员函数)
what [虚] | 返回解释性字符串 (std::exception 的虚公开成员函数)

示例

#include <variant>
#include <iostream>

int main()
{
    std::variant<int, float> v;
    v = 12;
    try {
      std::get<float>(v);
    }
    catch(const std::bad_variant_access& e) {
        std::cout << e.what() << '\n';
    }
}

可能的输出：

bad_variant_access

参阅

std::get(std::variant) (C++17) | 以给定索引或类型（若类型唯一）读取 variant 的值，错误时抛出异常 (函数模板)
visit (C++17) | 以一或多个 variant 所保有的各实参调用所提供的函数对象 (函数模板)


std::variant<Types...>::emplace

< cpp‎ | utility‎ | variant
(1)
template <class T, class... Args>
T& emplace(Args&&... args);
 (C++17 起)
(C++20 前)
template <class T, class... Args>
constexpr T& emplace(Args&&... args);
 (C++20 起)
(2)
template <class T, class U, class... Args>
T& emplace( std::initializer_list <U> il, Args&&... args );
 (C++17 起)
(C++20 前)
template <class T, class U, class... Args>
constexpr T& emplace( std::initializer_list <U> il, Args&&... args );
 (C++20 起)
(3)
template < std::size_t I, class... Args>
std::variant_alternative_t <I, variant>& emplace( Args&&... args );
 (C++17 起)
(C++20 前)
template < std::size_t I, class... Args>
constexpr std::variant_alternative_t <I, variant>& emplace( Args&&... args );
 (C++20 起)
(4)
template < std::size_t I, class U, class... Args>

std::variant_alternative_t <I, variant>&

emplace( std::initializer_list <U> il, Args&&... args );
 (C++17 起)
(C++20 前)
template < std::size_t I, class U, class... Args>

constexpr std::variant_alternative_t <I, variant>&

emplace( std::initializer_list <U> il, Args&&... args );
 (C++20 起)

在既存的 variant 对象中原位构造新值。

1) 等价于 emplace<I>( std::forward <Args>(args)...) ，其中 I 是 T 在 Types... 中的零基下标。此重载仅若 std::is_constructible_v <T, Args...> 为 true ，且 T 在 Types... 中准确出现一次才参与重载决议。
2) 等价于 emplace<I>(il, std::forward <Args>(args)...) ，其中 I 是 T 在 Types... 中的零基下标。此重载仅若 std::is_constructible_v <T, std::initializer_list &<U>&, Args...> 为 true ，且 T 在 Types... 中准确出现一次才参与重载决议。
3) 首先，销毁当前所含值（若存在）。然后如同以参数 std::forward <Args>(args)... 构造 T_I 类型值一般直接初始化所含值。若抛出异常，则 *this 可能变为因异常无值。此重载仅若 std::is_constructible_v <T_I, Args...> 为 true 才参与重载决议。若 I 不小于 sizeof...(Types) 则行为未定义。
4) 首先，销毁当前所含值（若存在）。然后如同以参数 il, std::forward <Args>(args)... 构造 T_I 类型值一般直接初始化所含值。若抛出异常，则 *this 可能变为因异常无值。此重载仅若 std::is_constructible_v <T_I, std::initializer_list <U>&, Args...> 为 true 才参与重载决议。若 I 不小于 sizeof...(Types) 则行为未定义。

参数

args | - | 构造新值时使用的构造函数参数
il | - | 构造新值时使用的 initializer_list 参数

返回值

到新的所含值的引用。

异常

1-4) 任何初始化所含值期间可能抛出的异常。

示例

#include <iostream>
#include <string>
#include <variant>

int main()
{
    std::variant<std::string> v1;
    v1.emplace<0>("abc"); // OK
    std::cout << std::get<0>(v1) << '\n';
    v1.emplace<std::string>("def"); // OK
    std::cout << std::get<0>(v1) << '\n';

    std::variant<std::string, std::string> v2;
    v2.emplace<1>("ghi"); // OK
    std::cout << std::get<1>(v2) << '\n';
    // v2.emplace<std::string>("abc"); -> 错误
}

输出：

abc
def
ghi

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2231R1 | C++20 | emplace 不是 constexpr ，而要求的操作在 C++20 中能为 constexpr | 使之为 constexpr

参阅

operator=
 赋值 variant
(公开成员函数)


std::get (std::variant)

< cpp‎ | utility‎ | variant
定义于头文件 <variant>
(1) | (C++17 起)
template< std::size_t I, class... Types >

constexpr std::variant_alternative_t <I, std::variant <Types...>>&

get( std::variant <Types...>& v );
template< std::size_t I, class... Types >

constexpr std::variant_alternative_t <I, std::variant <Types...>>&&

get( std::variant <Types...>&& v );
template< std::size_t I, class... Types >

constexpr const std::variant_alternative_t <I, std::variant <Types...>>&

get( const std::variant <Types...>& v );
template< std::size_t I, class... Types >

constexpr const std::variant_alternative_t <I, std::variant <Types...>>&

get( const std::variant <Types...>&& v );
(2) | (C++17 起)
template< class T, class... Types >
constexpr T& get( std::variant <Types...>& v );
template< class T, class... Types >
constexpr T&& get( std::variant <Types...>&& v );
template< class T, class... Types >
constexpr const T& get( const std::variant <Types...>& v );
template< class T, class... Types >
constexpr const T&& get( const std::variant <Types...>&& v );
1) 基于下标的值访问器：若 v.index() == I ，则返回到存储于 v 的值的引用。否则抛出 std::bad_variant_access 。若 I 不是 varian 的合法下标，则此调用为病式。
2) 基于类型的值访问器：若 v 保有可选项 T ，则返回到存储于 v 的值的引用。否则抛出 std::bad_variant_access 。若 T 不是 Types... 中唯一存在的元素，则此调用为病式。

模板形参

I | - | 要查找的下标
T | - | 要查找的唯一类型
Types... | - | 构成 variant 的类型

参数

v - 一个 variant

返回值

到存储于 variant 中的值的引用。

异常

1,2) 错误时抛 std::bad_variant_access 。

示例

#include <variant>
#include <string>

int main()
{
    std::variant<int, float> v{12}, w;
    int i = std::get<int>(v);
    w = std::get<int>(v);
    w = std::get<0>(v); // 效果同前一行

//  std::get<double>(v); // 错误： [int, float] 中无 double
//  std::get<3>(v);      // 错误：合法的 index 值是 0 和 1

    try {
      std::get<float>(w); // w 含有 int ，非 float ：将抛出异常
    }
    catch (std::bad_variant_access&) {}
}

参阅

get_if (C++17) | 以给定索引或类型（若其唯一），获得指向被指向的 variant 的值的指针，错误时返回空指针 (函数模板)
std::get(std::tuple) | 元组式访问指定的元素 (函数模板)
std::get(std::array) | 访问 array 的一个元素 (函数模板)
std::get(std::pair) (C++11) | 访问 pair 的一个元素 (函数模板)


std::get_if

< cpp‎ | utility‎ | variant
定义于头文件 <variant>
(1) | (C++17 起)
template< std::size_t I, class... Types >

constexpr std::add_pointer_t < std::variant_alternative_t <I, std::variant <Types...>>>

get_if( std::variant <Types...>* pv ) noexcept;
template< std::size_t I, class... Types >

constexpr std::add_pointer_t <const std::variant_alternative_t <I, variant<Types...>>>

get_if( const std::variant <Types...>* pv ) noexcept;
(2) | (C++17 起)
template< class T, class... Types >
constexpr std::add_pointer_t <T> get_if( std::variant <Types...>* pv ) noexcept;
template< class T, class... Types >
constexpr std::add_pointer_t <const T> get_if( const std::variant <Types...>* pv ) noexcept;
1) 基于下标的不抛出访问器：若 pv 不是空指针且 pv->index() == I ，则返回指向存储于 pv 所指向的 variant 中的值的指针。否则，返回空指针值。若 I 不是 variant 的合法下标，则此调用为病式。
2) 基于类型的不抛出访问器：等价于 (1) ，其中 I 是 T 在 Types... 中的零基下标。若 T 不是 Types... 中的唯一存在的元素，则此调用为病式。

参数

I | - | 要查找的下标
Type | - | 要查找的类型
pv | - | 指向 variant 的指针

返回值

指向存储于被指向的 variant 中值的指针，错误时为空指针。

示例

#include <variant>
#include <iostream>

int main()
{
    std::variant<int, float> v{12};

    if(auto pval = std::get_if<int>(&v))
      std::cout << "variant value: " << *pval << '\n';
    else
      std::cout << "failed to get value!" << '\n';
}

输出：

variant value: 12

参阅

std::get(std::variant)
(C++17)
 以给定索引或类型（若类型唯一）读取 variant 的值，错误时抛出异常
(函数模板)


std::hash <std::variant>

< cpp‎ | utility‎ | variant
定义于头文件 <variant> |
template <class... Types> struct hash< std::variant <Types...>>; | (C++17 起)

std::hash 对 std::variant 模板的模板特化允许用户获得 variant 对象的哈希。

若启用 std::hash<std::remove_const_t<Types>>... 中的每个特化，则启用特化 std::hash<std::variant<Types...>> （见 std::hash ），否则禁用它。

不保证此特化的成员函数为 noexcept 。

模板形参

Types - variant 对象所支持的可选项类型

注意

不同于 std::hash<std::optional> ， variant 的哈希通常不会哈希所含的值；这使得可能辨别保有同一值为不同可选项的 std::variant <int, int> 。

示例

本节未完成
原因：暂无示例

参阅

hash
(C++11)
 散列函数对象
(类模板)


std::holds_alternative

< cpp‎ | utility‎ | variant
定义于头文件 <variant> |
template< class T, class... Types > constexpr bool holds_alternative( const std::variant <Types...>& v ) noexcept; | (C++17 起)

检查 variant v 是否保有可选项 T 。若 T 不在 Types... 准确出现一次，则此调用为病式。

参数

v - 要检验的 variant

返回值

若 variant 当前保有可选项 T 则为 true ，否则为 false 。

示例

#include <variant>
#include <string>
#include <iostream>
int main()
{
    std::variant<int, std::string> v = "abc";
    std::cout << std::boolalpha
              << "variant holds int? "
              << std::holds_alternative<int>(v) << '\n'
              << "variant holds string? "
              << std::holds_alternative<std::string>(v) << '\n';
}

输出：

variant holds int? false
variant holds string? true

参阅

index | 返回 variant 所保有可选项的零基下标 (公开成员函数)
std::get(std::variant) (C++17) | 以给定索引或类型（若类型唯一）读取 variant 的值，错误时抛出异常 (函数模板)


std::variant<Types...>::index

< cpp‎ | utility‎ | variant
constexpr std::size_t index() const noexcept; | (C++17 起)

返回 variant 当前所保有的可选项的零基下标。

若 variant 因异常无值（ valueless_by_exception ），则返回 variant_npos 。

示例

#include <variant>
#include <string>
#include <iostream>
int main()
{
    std::variant<int, std::string> v = "abc";

    std::cout << "v.index = " << v.index() << '\n';

    v = {};

    std::cout << "v.index = " << v.index() << '\n';
}

输出：

v.index = 1
v.index = 0

参阅

holds_alternative (C++17) | 检查某个 variant 是否当前持有某个给定类型 (函数模板)
std::get(std::variant) (C++17) | 以给定索引或类型（若类型唯一）读取 variant 的值，错误时抛出异常 (函数模板)


std::monostate

< cpp‎ | utility‎ | variant
定义于头文件 <variant> |
struct monostate { }; | (C++17 起)

有意为行为良好的 std::variant 中空可选项所用的单位类型。具体而言，非可默认构造的 variant 可以列 std::monostate 为其首个可选项：这使得 variant 自身可默认构造。

成员函数

(构造函数) (隐式声明) | 平凡隐式默认/复制/移动构造函数 (公开成员函数)
(析构函数) (隐式声明) | 平凡隐式析构函数 (公开成员函数)
operator= (隐式声明) | 平凡隐式复制/移动赋值 (公开成员函数)

非成员函数

std::operator==, !=, <, <=, >, >=, <=>(std::monostate)

constexpr bool operator==(monostate, monostate) noexcept { return true; }
 (C++17 起)
constexpr bool operator!=(monostate, monostate) noexcept { return false; }

constexpr bool operator<(monostate, monostate) noexcept { return false; }
constexpr bool operator>(monostate, monostate) noexcept { return false; }
constexpr bool operator<=(monostate, monostate) noexcept { return true; }

constexpr bool operator>=(monostate, monostate) noexcept { return true; }
 (C++17 起)
(C++20 前)
constexpr std::strong_ordering operator<=>(monostate, monostate) noexcept
{ return std::strong_ordering::equal; }
 (C++20 起)

所有 std::monostate 实例比较相等。

<、 <=、 >、 >= 及 != 运算符分别从 operator<=> 与 operator== 合成。

 (C++20 起)

辅助类

std::hash<std::monostate>

template <> struct std::hash <monostate>;

为 std::monostate 特化 std::hash 算法

示例

#include <variant>
#include <iostream>

struct S
{
    S(int i) : i(i) {}
    int i;
};

int main() {

    // 若无 monostate 类型则此声明将失败。
    // 这是因为 S 不可默认构造。

    std::variant<std::monostate, S> var;

    // var.index() 现为 0 ——首个元素
    // std::get<S> 将抛异常！我等需要赋一个值

    var = 12;

    std::cout << std::get<S>(var).i << '\n';
}

输出：

12

参阅

(构造函数)
 构造 variant 对象
(公开成员函数)


std::variant<Types...>::operator=

< cpp‎ | utility‎ | variant
constexpr variant& operator=( const variant& rhs ); | (1) | (C++17 起)
constexpr variant& operator=( variant&& rhs ) noexcept(/* see below */); | (2) | (C++17 起)
 | (3) |
template< class T > variant& operator=( T&& t ) noexcept(/* see below */); |  |  | (C++17 起) (C++20 前)
template< class T > constexpr variant& operator=( T&& t ) noexcept(/* see below */); |  |  | (C++20 起)

给既存的 variant 对象赋新值。

1) 复制赋值：
  • 若 *this 与 rhs 均因异常无值，则不做任何事。
  • 否则，若 rhs 无值，但 *this 非无值，则销毁 *this 中所含值并使之无值。
  • 否则，若 rhs 保有同 *this 的可选项，则赋值 rhs 中含有的值给 *this 。若抛出异常，则 *this 不变为无值：值取决于该可选项的复制赋值的异常安全保证。
  • 否则，若 rhs 的可选项为 nothrow 可复制构造或非 nothrow 可移动构造（分别由 std::is_nothrow_copy_constructible 和 std::is_nothrow_move_constructible 确定），则等价于 this->emplace<rhs.index()>(get<rhs.index()>(rhs)) 。若 emplace 内的复制构造抛异常，则 *this 可能变为因异常无值（ valueless_by_exception ）。
  • 否则，等价于 this->operator=(variant(rhs)) 。
定义此重载为被删除，除非 std::is_copy_constructible_v <T_i> 与 std::is_copy_assignable_v <T_i> 对 Types... 中所有 T_i 均为 true 。若 std::is_trivially_copy_constructible_v <T_i> 、 std::is_trivially_copy_assignable_v <T_i> 及 std::is_trivially_destructible_v <T_i> 对 Types... 中所有 T_i 均为 true 则此重载为平凡。
2) 移动赋值：
  • 若 *this 与 rhs 均因异常无值，则不做任何事
  • 否则，若 rhs 无值，但 *this 非无值，则销毁 *this 中所含值并使之无值
  • 否则，若 rhs 保有与 *this 相同的可选项，则赋值 std::get<j>(std::move(rhs)) 给中所含值 *this ，其中 j 为 index() 。若抛出异常，则 *this 不变为无值：值依赖于可该选项的移动赋值的异常安全保证。
  • 否则（若 rhs 与 *this 保有不同可选项），等价于 this->emplace<rhs.index()>(get<rhs.index()>(std::move(rhs))) 。若 T_i 的移动构造函数抛出异常，则 *this 变为因异常无值。
此重载仅若 std::is_move_constructible_v<T_i> 与 std::is_move_assignable_v <T_i> 对 Types... 中所有 T_i 为 true 才参与重载决议。若 std::is_trivially_move_constructible_v <T_i> 、 std::is_trivially_move_assignable_v <T_i> 及 std::is_trivially_destructible_v <T_i> 对 Types... 中所有 T_i 均为 true 则此重载为平凡。
3) 转换赋值：
  • 确定若有对每个来自 Types... 的 T_i 的虚构重载函数 F(T_i) 同时在作用域中，则重载决议是否为表达式 F( std::forward <T>(t)) 选择可选项类型 T_j ，除了：
  • 仅若声明 T_i x[] = { std::forward <T>(t) }; 对某个虚设变量 x 合法才考虑 F(T_i) ；
  • 若 T_i 是（可有 cv 限定的） bool ，则仅若 std:remove_cvref_t<T> 亦为 bool 才考虑 F(T_i) 。
  • 若 *this 已保有 T_j ，则赋值 std::forward <T>(t) 为 *this 中所含值。若抛出异常，则 *this 不变为无值：值取决于被调用赋值的异常安全保证。
  • 否则，若 std::is_nothrow_constructible_v <T_j, T> || ! std::is_nothrow_move_constructible_v <T_j> 为 true ，则等价于 this->emplace<j>( std::forward <T>(t)) 。若 emplace 内的初始化抛异常，则 *this 可能变为因异常无值。
  • 否则，等价于 this->emplace<j>(T_j( std::forward <T>(t))) 。
此重载仅若 std::decay_t <T> (C++20 前)std::remove_cvref_t<T> (C++20 起) 不是与 variant 相同的类型，且 std::is_assignable_v <T_j&, T> 为 true 且 std::is_constructible_v <T_j, T> 为 true 而且表达式 F( std::forward <T>(t)) （其中 F 为上述虚构函数集）为良构才参与重载决议。
std::variant<string> v1;
v1 = "abc"; // OK
std::variant<std::string, std::string> v2;
v2 = "abc"; // 错误
std::variant <std::string, bool> v3;
v3 = "abc"; // OK ：选择 string ； bool 不是候选
std::variant<float, long, double> v4; // 保有 float
v4 = 0; // OK ：保有 long ； float 与 double 不是候选

参数

rhs | - | 另一 variant
t | - | 可转换成 variant 的可选项之一的值

返回值

*this

异常

1) 可能抛出任何可选项的赋值及复制/移动初始化所抛的异常。
2)
noexcept 说明：
noexcept((( std::is_nothrow_move_constructible_v <Types> &&
std::is_nothrow_move_assignable_v <Types>) && ...))
3)
noexcept 说明：
noexcept( std::is_nothrow_assignable_v <T_j&, T> && std::is_nothrow_constructible_v <T_j, T>)

示例

#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>

std::ostream& operator<<(std::ostream& os, std::variant<int, std::string> const& va)
{
    os << ": { ";

    std::visit([&](auto&& arg) {
        using T = std::decay_t<decltype(arg)>;
        if constexpr (std::is_same_v<T, int>)
            os << arg;
        else if constexpr (std::is_same_v<T, std::string>)
            os << std::quoted(arg);
    }, va);

    return os << " };\n";
}

int main()
{
    std::variant<int, std::string> a{2017}, b{"CppCon"};
    std::cout << "a" << a << "b" << b << '\n';

    std::cout << "(1) operator=( const variant& rhs )\n";
    a = b;
    std::cout << "a" << a << "b" << b << '\n';

    std::cout << "(2) operator=( variant&& rhs )\n";
    a = std::move(b);
    std::cout << "a" << a << "b" << b << '\n';

    std::cout << "(3) operator=( T&& t ), where T is int\n";
    a = 2019;
    std::cout << "a" << a << '\n';

    std::cout << "(3) operator=( T&& t ), where T is std::string\n";
    std::string s{"CppNow"};
    std::cout << "s: " << std::quoted(s) << '\n';
    a = std::move(s);
    std::cout << "a" << a << "s: " << std::quoted(s) << '\n';
}

可能的输出：

a: { 2017 };
b: { "CppCon" };

(1) operator=( const variant& rhs )
a: { "CppCon" };
b: { "CppCon" };

(2) operator=( variant&& rhs )
a: { "CppCon" };
b: { "" };

(3) operator=( T&& t ), where T is int
a: { 2019 };

(3) operator=( T&& t ), where T is std::string
s: "CppNow"
a: { "CppNow" };
s: ""

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3024 | C++17 | 若任何成员类型不可复制则复制赋值运算符不参与重载决议 | 改为定义为被删除
P0602R4 | C++17 | 即使底层操作平凡，复制/移动运算符亦可能不平凡 | 要求传播平凡性
P0608R3 | C++17 | 转换赋值盲目地组成重载集，导致不想要的转换 | 不考虑窄化和布尔转换
P2231R1 | C++20 | 转换赋值不是 constexpr 而要求的操作在 C++20 中可以是 | 使之为 constexpr
LWG 3585 | C++17 | 转换赋值有时意外地非良构，因为无可用的移动赋值 | 使之良构

参阅

emplace
 原位构造 variant 中的值
(公开成员函数)


operator==, !=, <, <=, >, >=, <=>(std::variant)

< cpp‎ | utility‎ | variant
定义于头文件 <variant>
template< class... Types >

constexpr bool operator==( const std::variant <Types...>& v,

const std::variant <Types...>& w );
 (1) (C++17 起)
template< class... Types >

constexpr bool operator!=( const std::variant <Types...>& v,

const std::variant <Types...>& w );
 (2) (C++17 起)
template< class... Types >

constexpr bool operator<( const std::variant <Types...>& v,

const std::variant <Types...>& w );
 (3) (C++17 起)
template< class... Types >

constexpr bool operator>( const std::variant <Types...>& v,

const std::variant <Types...>& w );
 (4) (C++17 起)
template< class... Types >

constexpr bool operator<=( const std::variant <Types...>& v,

const std::variant <Types...>& w );
 (5) (C++17 起)
template< class... Types >

constexpr bool operator>=( const std::variant <Types...>& v,

const std::variant <Types...>& w );
 (6) (C++17 起)
template< class... Types >

constexpr std::common_comparison_category_t<
std::compare_three_way_result_t<Types>...>
operator<=>( const std::variant <Types...>& v,

const std::variant <Types...>& w );
 (7) (C++20 起)
1) variant 的相等运算符：
  • 若 v.index() != w.index() ，则返回 false ；
  • 否则，若 v.valueless_by_exception() ，则返回 true ；
  • 否则返回 std::get<v.index()>(v) == std::get<v.index()>(w) 。若对于任何一个 i ， std::get<i>(v) == std::get<i>(w) 不是返回值能转换为 bool 的合法表达式，则行为未定义 (C++20 前)程序为谬构 (C++20 起)。
2) variant 的不相等运算符：
  • 若 v.index() != w.index() ，则返回 true ；
  • 否则，若 v.valueless_by_exception() ，则返回 false ；
  • 否则返回 std::get<v.index()>(v) != std::get<v.index()>(w) 。若对于任何一个 i ， std::get<i>(v) != std::get<i>(w) 不是返回值能转换为 bool 的合法表达式，则行为未定义 (C++20 前)程序为谬构 (C++20 起)。
3) variant 的小于运算符：
  • 若 w.valueless_by_exception() ，则返回 false ；
  • 否则，若 v.valueless_by_exception() ，则返回 true ；
  • 否则，若 v.index() < w.index() ，则返回true ；
  • 否则，若 v.index() > w.index() ，则返回false ；
  • 否则返回 std::get<v.index()>(v) < std::get<v.index()>(w) 。若对于任何一个 i ， std::get<i>(v) < std::get<i>(w) 不是返回值能转换为 bool 的合法表达式，则行为未定义 (C++20 前)程序为谬构 (C++20 起)。
4) variant 的大于运算符：
  • 若 v.valueless_by_exception() ，则返回 false ；
  • 否则，若 w.valueless_by_exception() ，则返回 true ；
  • 否则，若 v.index() > w.index() ，则返回 true ；
  • 否则，若 v.index() < w.index() ，则返回 false ；
  • 否则返回 std::get<v.index()>(v) > std::get<v.index()>(w) 。若对于任何一个 i ， std::get<i>(v) > std::get<i>(w) 不是返回值能转换为 bool 的合法表达式，则行为未定义 (C++20 前)程序为谬构 (C++20 起)。
5) variant 的小于或等于运算符：
  • 若 v.valueless_by_exception() ，则返回 true ；
  • 否则，若 w.valueless_by_exception() ，则返回 false ；
  • 否则，若 v.index() < w.index() ，则返回true；
  • 否则，若 v.index() > w.index() ，则返回false；
  • 否则返回 std::get<v.index()>(v) <= std::get<v.index()>(w) 。若对于任何一个 i ， std::get<i>(v) <= std::get<i>(w) 不是返回值能转换为 bool 的合法表达式，则行为未定义 (C++20 前)程序为谬构 (C++20 起)。
6) variant 的大于或等于运算符：
  • 若 w.valueless_by_exception() ，则返回 true ；
  • 否则，若 v.valueless_by_exception() ，则返回 false ；
  • 否则，若 v.index() > w.index() ，则返回 true ；
  • 否则，若 v.index() < w.index() ，则返回 false ；
  • 否则返回 std::get<v.index()>(v) >= std::get<v.index()>(w) 。若对于任何一个 i ， std::get<i>(v) >= std::get<i>(w) 不是返回值能转换为 bool 的合法表达式，则行为未定义 (C++20 前)程序为谬构 (C++20 起)。
7) variant 的三路比较运算符：
  • 若 v.valueless_by_exception() 与 w.valueless_by_exception() 均为 true ，则返回 std::strong_ordering::equal ；
  • 否则，若 v.valueless_by_exception() 为 true ，则返回 std::strong_ordering::less ；
  • 否则，若 w.valueless_by_exception() 为 true ，则返回 std::strong_ordering::greater ；
  • 否则，若 v.index() != w.index() ，则返回 v.index() <=> w.index() ；
  • 否则等价于 std::get<v.index()>(v) <=> std::get<v.index()>(w) 。

参数

v,w - 要比较的 variant

返回值

描述于上的比较结果。

示例

本节未完成
原因：暂无示例

参阅

operator==operator!=operator<operator<=operator>operator>=operator<=>
(C++17)(C++17)(C++17)(C++17)(C++17)(C++17)(C++20)
 比较 optional 对象
(函数模板)


std::variant<Types...>::swap

< cpp‎ | utility‎ | variant
void swap( variant& rhs ) noexcept(/* see below */); | (C++17 起) (C++20 前)
constexpr void swap( variant& rhs ) noexcept(/* see below */); | (C++20 起)

交换二个 variant 对象。

  • 若 *this 和 rhs 均因异常无值，则不做任何事；
  • 否则，若 *this 与 rhs 保有同一可选项，则调用 swap(std::get<i>(*this), std:get<i>(rhs)) ，其中 i 等于 index() 。若抛出异常，则值的状态依赖于被调用交换函数的异常安全；
  • 否则，交换 rhs 与 *this 的值。若抛出异常，则 *this 与 rhs 的状态依赖于 variant 移动构造函数的异常安全。

除非对于所有 Types... 中的 T_i ， T_i 左值可交换 (Swappable) 且 std::is_move_constructible_v <T_i> 为 true ，否则行为未定义。

参数

rhs - 要交换的 variant 对象

返回值

（无）

异常

若 this->index() == rhs.index() ，则可能抛出任何 swap(std::get<i>(*this), std::get<i>(rhs)) 所抛的异常，其中 i 等于 index() 。

否则，可能抛出任何当前 *this 与 rhs 所保有的可选项的移动构造函数所抛的异常。

noexcept 说明：
noexcept((( std::is_nothrow_move_constructible_v <Types> &&
std::is_nothrow_swappable_v <Types>) && ...))

示例

#include <variant>
#include <string>
#include <iostream>

int main()
{
    std::variant<int, std::string> v1{2}, v2{"abc"};
    std::visit([] (auto&& x) { std::cout << x << ' '; }, v1);
    std::visit([] (auto&& x) { std::cout << x << '\n'; }, v2);
    v1.swap(v2);
    std::visit([] (auto&& x) { std::cout << x << ' '; }, v1);
    std::visit([] (auto&& x) { std::cout << x << '\n'; }, v2);
}

输出：

2 abc
abc 2

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2231R1 | C++20 | swap 不是 constexpr ，而要求的操作在 C++20 中能为 constexpr | 使之为 constexpr


std::swap(std::variant)

< cpp‎ | utility‎ | variant
定义于头文件 <variant>
template <class... Types>

void swap( std::variant <Types...>& lhs,

std::variant <Types...>& rhs ) noexcept(/* see below */);
 (C++17 起)
(C++20 前)
template <class... Types>

constexpr void swap( std::variant <Types...>& lhs,

std::variant <Types...>& rhs ) noexcept(/* see below */);
 (C++20 起)

为 std::variant 重载 std::swap 算法。等效地调用 lhs.swap(rhs) 。

此重载仅若 std::is_move_constructible_v <T_i> 与 std::is_swappable_v <T_i> 对于所有 Types... 中的 T_i 皆为 true 才参与重载决议。

参数

lhs, rhs - 要交换值的 variant 对象

返回值

（无）

异常

noexcept 说明：
noexcept(noexcept(lhs.swap(rhs)))

示例

#include <variant>
#include <string>
#include <iostream>

auto print = [](auto const& v, char term = '\n') {
    std::visit([](auto&& o) { std::cout << o; }, v);
    std::cout << term;
};

int main()
{
    std::variant<int, std::string> v1{123}, v2{"XYZ"};
    print(v1, ' ');
    print(v2);

    std::swap(v1, v2);
    print(v1, ' ');
    print(v2);

    std::variant<double, std::string> v3{3.14};
    // std::swap(v1, v3); // 错误： ~ 不一致的形参包
}

输出：

123 XYZ
XYZ 123

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2231R1 | C++20 | swap 不是 constexpr ，而要求的操作在 C++20 中能为 constexpr | 使之为 constexpr

参阅

swap
 与另一 variant 交换
(公开成员函数)


std::variant<Types...>::valueless_by_exception

< cpp‎ | utility‎ | variant
constexpr bool valueless_by_exception() const noexcept; | (C++17 起)

当且仅当 variant 保有值时返回 false 。

注解

variant 可以在下列情形中变得无值：

  • （保证）在移动赋值中，移动初始化所含值时抛出异常
  • （可选）在复制赋值中，复制初始化所含值时抛出异常
  • （可选）在类型更改赋值期间，初始化所含值时抛出异常
  • （可选）在类型更改 emplace 期间，初始化所含值时抛出异常

因为 variant 决不容许分配动态内存，故在这些情况下不可能保留先前的值。

这还应用到非类类型的 variant ：

struct S {
    operator int() { throw 42; }
};
std::variant<float, int> v{12.f}; // OK
v.emplace<1>(S()); // v 可能为无值

因异常无值的 variant 被当做在非法态： index 返回 variant_npos ， get 与 visit 抛出 bad_variant_access 。

示例

#include <cassert>
#include <iostream>
#include <stdexcept>
#include <string>
#include <variant>

struct Demo {
    Demo(int) {}
    Demo(const Demo&) { throw std::domain_error("copy ctor"); }
    Demo& operator= (const Demo&) = default;
};

int main()
{
    std::variant<std::string, Demo> var{"str"};
    assert(var.index() == 0);
    assert(std::get<0>(var) == "str");
    assert(var.valueless_by_exception() == false);

    try {
        var = Demo{666};
    } catch (const std::domain_error& ex) {
        std::cout << "1) Exception: " << ex.what() << '\n';
    }
    assert(var.index() == std::variant_npos);
    assert(var.valueless_by_exception() == true);

    // 现在 var “无值”，此为 var 的初始化过程中引发的异常导致的非法状态。

    try {
        std::get<1>(var);
    } catch (const std::bad_variant_access& ex) {
        std::cout << "2) Exception: " << ex.what() << '\n';
    }

    var = "str2";
    assert(var.index() == 0);
    assert(std::get<0>(var) == "str2");
    assert(var.valueless_by_exception() == false);
}

可能的输出：

1) Exception: copy ctor
2) Exception: std::get: variant is valueless

参阅

std::get(std::variant) (C++17) | 以给定索引或类型（若类型唯一）读取 variant 的值，错误时抛出异常 (函数模板)
index | 返回 variant 所保有可选项的零基下标 (公开成员函数)
bad_variant_access (C++17) | 非法地访问 variant 的值时抛出的异常 (类)


std::variant<Types...>::variant

< cpp‎ | utility‎ | variant
constexpr variant() noexcept(/* see below */);
 (1) (C++17 起)
constexpr variant( const variant& other );
 (2) (C++17 起)
constexpr variant( variant&& other ) noexcept(/* see below */);
 (3) (C++17 起)
template< class T >
constexpr variant( T&& t ) noexcept(/* see below */);
 (4) (C++17 起)
template< class T, class... Args >
constexpr explicit variant( std::in_place_type_t <T>, Args&&... args );
 (5) (C++17 起)
template< class T, class U, class... Args >

constexpr explicit variant( std::in_place_type_t <T>,

std::initializer_list <U> il, Args&&... args );
 (6) (C++17 起)
template< std::size_t I, class... Args >
constexpr explicit variant( std::in_place_index_t <I>, Args&&... args );
 (7) (C++17 起)
template< std::size_t I, class U, class... Args >

constexpr explicit variant( std::in_place_index_t <I>,

std::initializer_list <U> il, Args&&... args );
 (8) (C++17 起)

构造新的 variant 对象。

1) 默认构造函数。构造 variant ，保有首个可选项的值初始化的值（ index() 为零）。
  • 当且仅当可选项类型 T_0 的值初始化满足 constexpr 函数的要求，此构造函数才为 constexpr 。
  • 此重载仅若 std::is_default_constructible_v <T_0> 为 true 才参与重载决议。
2) 复制构造函数。若 other 非因异常无值，则构造一个保有与 other 相同可选项的 variant ，并以 std::get<other.index()>(other) 直接初始化所含值。否则，初始化一个因异常无值的 variant 。
  • 此构造函数定义为被删除，除非 std::is_copy_constructible_v <T_i> 对于所有 Types... 中的 T_i 为 true 。
  • 若 std::is_trivially_copy_constructible_v <T_i> 对 Types... 中的所有 T_i 为 true 则它为平凡。
3) 移动构造函数。若 other 非因异常无值，则构造一个保有与 other 相同可选项的 variant 并以 std::get<other.index()>(std::move(other)) 直接初始化所含值。否则，初始化一个因异常无值的 variant。
  • 此重载仅若 std::is_move_constructible_v <T_i> 对于所有Types... 中的 T_i 为 true 才参与重载决议。
  • 若 std::is_trivially_move_constructible_v <T_i> 对 Types... 中的所有 T_i 为 true 则它为平凡。
4) 转换构造函数。构造保有会被重载决议对表达式 F( std::forward <T>(t)) 选择的可选项 T_j ，假设对来自 Types... 中的每个 T_i 同时存在一个虚构函数 F(T_i) 的重载，除了：
  • 仅若声明 T_i x[] = { std::forward <T>(t) }; 对某个虚设变量 x 才考虑 F(T_i) ；
  • 若 T_i 是（可有 cv 限定的） bool ，则仅若 std::decay_t <T> (C++20 前)std::remove_cvref_t<T> (C++20 起) 亦为 bool 才考虑 F(T_i) 。
如同用直接非列表初始化从 std::forward <T>(t) 直接初始化所含值。
  • 此重载仅若
    • sizeof...(Types) > 0 ，
    • std::decay_t <U> (C++20 前)std::remove_cvref_t<U> (C++20 起) 既不与 variant 为同一类型，亦非 std::in_place_type_t 或 std::in_place_index_t 的特化，
    • std::is_constructible_v <T_j, T> 为 true ，
    • 且表达式 F( std::forward <T>(t)) （令 F 为上述虚构函数的重载集）为良构才参与重载决议。
  • 若 T_j 的被选择构造函数为 constexpr 构造函数，则此构造函数为 constexpr 构造函数。
std::variant<std::string> v("abc"); // OK
std::variant<std::string, std::string> w("abc"); // 谬构
std::variant<std::string, const char*> x("abc"); // OK ：选择 const char*
std::variant<std::string, bool> y("abc"); // OK ：选择 string ； bool 不是候选
std::variant<float, long, double> z = 0; // OK ：保有 long
                                         // float 与 double 不是候选
5) 构造一个有指定可选项类型 T 的 variant 并以参数 std::forward <Args>(args)... 初始化所含值。
  • 若 T 的被选择构造函数是 constexpr 构造函数，则此构造函数亦为 constexpr 构造函数。
  • 此重载仅若 Types... 中正好出现一次 T 且 std::is_constructible_v <T, Args...> 为 true 才参与重载决议。
6) 构造一个有指定可选项类型 T 的 variant 并以参数 il, std::forward <Args>(args)... 初始化所含值。
  • 若 T 的被选择构造函数是 constexpr 构造函数，则此构造函数亦为 constexpr 构造函数。
  • 此重载仅若 Types... 中正好出现一次 T 且 std::is_constructible_v <T, initializer_list<U>&, Args...> 为 true 才参与重载决议。
7) 构造一个有下标 I 所指定的可选项类型 {{tt|T_i} }的 variant 并以参数std::forward <Args>(args)... 初始化所含值。
  • 若 T_i 的被选择构造函数是 constexpr 构造函数，则此构造函数亦为 constexpr 构造函数。
  • 此重载仅若 I < sizeof...(Types) 与 std::is_constructible_v <T_i, Args...> 皆为 true 才参与重载决议。
8) 构造一个有下标 I 所指定的可选项类型 T_i 的 variant 并以参数 il, std::forward <Args>(args)... 初始化所含值。
  • 若 T_i 的被选择构造函数是 constexpr 构造函数，则此构造函数亦为 constexpr 构造函数。
  • 此重载仅若 I < sizeof...(Types) 与 std::is_constructible_v <T_i, std::initializer_list <U>&, Args...> 皆为 true 才参与重载决议。

参数

other | - | 另一个要复制/移动其所含值的 variant 对象
t | - | 用以初始化被所含值的值
args... | - | 用以初始化被所含值的参数
il | - | 用以初始化被所含值的初始化器列表
a | - | 传递给被所含值的分配器

异常

1) 可能抛出首个可选项的值初始化所抛的任何异常。
noexcept 说明：
noexcept( std::is_nothrow_default_constructible_v <T_0>)
2) 可能抛出直接初始化任何 Types... 中的 T_i 所抛的任何异常。
3) 可能抛出移动构造任何 Types... 中的 T_i 所抛的任何异常。
noexcept 说明：
noexcept( ( std::is_nothrow_move_constructible_v <Types> && ...))
4) 可能抛出初始化所选可选项T_j所抛的任何异常。
noexcept 说明：
noexcept( std::is_nothrow_constructible_v <T_j, T>)
5-8) 可能抛出调用所选可选项的所选构造函数所抛的任何异常。

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2901 | C++17 | 提供具分配器构造函数但 variant 不能正确支持分配器 | 移除构造函数
P0739R0 | C++17 | 转换构造函数模板与类模板实参推导交互困难 | 添加了制约
LWG 3024 | C++17 | 若任何成员类型非可复制，则复制构造函数不参与重载决议 | 改为定义为被删除
P0602R4 | C++17 | 即使底层构造函数平凡，复制/移动构造函数亦可为非平凡 | 要求传播平凡性
P0608R3 | C++17 | 转换构造函数盲目地组成重载集，导致不想要的转换 | 不考虑窄化与布尔转换

示例

本节未完成
原因：暂无示例


std::variant_alternative, std::variant_alternative_t

< cpp‎ | utility‎ | variant
定义于头文件 <variant>
template < std::size_t I, class T>
struct variant_alternative; /* undefined */
 (1) (C++17 起)
template < std::size_t I, class... Types>
struct variant_alternative<I, variant<Types...>>;
 (2) (C++17 起)
template < std::size_t I, class T> class variant_alternative<I, const T>;
 (3) (C++17 起)
template < std::size_t I, class T>

class variant_alternative<I, volatile T>;
template < std::size_t I, class T>

class variant_alternative<I, const volatile T>;
 (3) (C++17 起)
(C++20 中弃用)

提供对可有 cv 限定 variant 的类型编译时下标访问，将 variant 的 cv 限定与可选项的 cv 限定（若存在）相结合。

正式而言，

2) 满足拥有成员 typedef type 等于序号为 I 的可选项类型的变换特征 (TransformationTrait) 要求
3) 满足拥有成员 typedef type 分别为 std::add_const_t <std::variant_alternative_t<I,T>> 、 std::add_volatile_t <std::variant_alternative_t<I,T>> 和 std::add_cv_t <std::variant_alternative_t<I,T>> 的变换特征 (TransformationTrait) 要求

成员类型

成员类型 | 定义
type | variant 的第 I 的可选项的类型，其中 I 必须在 [0, sizeof...(Types)) 中，否则程序为谬构

辅助别名模板

template <size_t I, class T> using variant_alternative_t = typename variant_alternative<I, T>::type; | (C++17 起)

示例

#include <variant>
#include <iostream>

using my_variant = std::variant<int, float>;
static_assert(std::is_same_v
    <int,   std::variant_alternative_t<0, my_variant>>);
static_assert(std::is_same_v
    <float, std::variant_alternative_t<1, my_variant>>);
// variant 类型上的 cv 限定传播给提取出的可选项类型。
static_assert(std::is_same_v
    <const int, std::variant_alternative_t<0, const my_variant>>);

int main()
{
    std::cout << "All static assertions passed\n";
}

输出：

All static assertions passed.

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 2974 | C++17 | 越界下标导致未定义行为 | 使之为谬构

参阅

variant_sizevariant_size_v (C++17) | 在编译时获得 variant 可选项列表的大小 (类模板) (变量模板)
std::tuple_element<std::tuple> (C++11) | 获得指定元素的类型 (类模板特化)


std::variant_npos

< cpp‎ | utility‎ | variant
定义于头文件 <variant> |
inline constexpr std::size_t variant_npos = -1; | (C++17 起)

这是一个等于类型 std::size_t 最大可表示值的特殊值，用作 index() 在 valueless_by_exception() 为 true 时的返回值指示。

参阅

index | 返回 variant 所保有可选项的零基下标 (公开成员函数)
valueless_by_exception | 检查 variant 是否在非法状态 (公开成员函数)


std::variant_size, std::variant_size_v

< cpp‎ | utility‎ | variant
定义于头文件 <variant>
template <class T>
struct variant_size; /* undefined */
 (1) (C++17 起)
template <class... Types>

struct variant_size< std::variant <Types...>>

: std::integral_constant < std::size_t, sizeof...(Types)> { };
 (2) (C++17 起)
template <class T> class variant_size<const T>;
 (3) (C++17 起)
template <class T> class variant_size<volatile T>;
template <class T> class variant_size<const volatile T>;
 (3) (C++17 起)
(C++20 中弃用)

提供作为编译时常量表达式，对可有 cv 限定的 variant 中可选项数量的访问。

正式地，

2) 满足基特征为 std::integral_constant<std::size_t, sizeof...(Types)> 的一元类型特征 (UnaryTypeTrait) 要求
3) 满足基特征为 std::integral_constant<std::size_t, variant_size<T>> 的一元类型特征 (UnaryTypeTrait) 要求

辅助变量模板

template <class T> inline constexpr std::size_t variant_size_v = std::variant_size<T>::value; | (C++17 起)

继承自 std::integral_constant

成员常量

value
[静态]
 sizeof...(Types)
(公开静态成员常量)

成员函数

operator std::size_t | 转换对象为 std::size_t ，返回 value (公开成员函数)
operator() (C++14) | 返回 value (公开成员函数)

成员类型

类型 | 定义
value_type | std::size_t
type | std::integral_constant < std::size_t, value>

注解

所有 std::variant_size 的特化都满足以某些 N 的 std::integral_constant<std::size_t, N> 为基特征的一元类型特征 (UnaryTypeTrait) 。

示例

#include <any>
#include <cstdio>
#include <variant>

static_assert(std::variant_size_v<std::variant<>> == 0);
static_assert(std::variant_size_v<std::variant<int>> == 1);
static_assert(std::variant_size_v<std::variant<int, int>> == 2);
static_assert(std::variant_size_v<std::variant<int, int, int>> == 3);
static_assert(std::variant_size_v<std::variant<int, float, double>> == 3);
static_assert(std::variant_size_v<std::variant<std::monostate, void>> == 2);
static_assert(std::variant_size_v<std::variant<const int, const float>> == 2);
static_assert(std::variant_size_v<std::variant<std::variant<std::any>>> == 1);

int main() { std::puts("All static assertions passed."); }

输出：

All static assertions passed.

参阅

variant_alternativevariant_alternative_t (C++17) | 在编译时获得以其下标指定的可选项的类型 (类模板) (别名模板)
std::tuple_size<std::tuple> (C++11) | 在编译时获得 tuple 的大小 (类模板特化)


std::visit

< cpp‎ | utility‎ | variant
定义于头文件 <variant> |  |
template <class Visitor, class... Variants> constexpr /*see below*/ visit(Visitor&& vis, Variants&&... vars); | (1) | (C++17 起)
template <class R, class Visitor, class... Variants> constexpr R visit(Visitor&& vis, Variants&&... vars); | (2) | (C++20 起)

应用观览器 vis 到 variant 变量组 vars 。

这些重载仅若 std::remove_reference_t <Variants>... 中的每个类型均为（可为 const 限定的） std::variant 的特化，或（可为 const 限定）的类 C ，满足恰有一个 std::variant 特化是 C 的基类且它是公开且无歧义的基类才参与重载决议。

等效于返回

std::invoke ( std::forward <Visitor>(vis),
std::get<is>( std::forward <VariantBases>(vars))...)

，其中 VariantBases... 中的每个类型是确定如上的唯一 std::variant 特化，除了若对应的实参拥有 const 限定类型，为左值或右值，则分别添加 const 、 & 或 && 到它，而 is... 是 std::forward <VariantBases>(vars).index()... 。

1) 如同用 decltype 从返回的表达式推导返回类型。若上述调用不是对于所有 variant 的所有可选项类型均为同一类型和值类别的合法表达式，则调用为谬构。
2) 返回类型为 R 。若 R 是（可有 cv 限定的） void ，则舍弃 invoke 表达式的结果。

参数

vis | - | 接受每个 variant 的每个可能可选项的可调用 (Callable) 对象
vars | - | 传递给观览器的 variant 列表

返回值

1) 观览器的所选调用所返回的值，转换成所有可行的 std::invoke 表达式的共用类型。
2) 若 R 为（可有 cv 限定的） void 则为无；否则为选择的观览器调用所返回的值，再隐式转换成 R 。

异常

若任何 vars 中的 variant 为因异常无值（ valueless_by_exception ），则抛出 std::bad_variant_access 。如同通过 ( std::forward <VariantBases>(vars).valueless_by_exception() || ...) 确定任何 variant 为因异常无值。

复杂度

当 variant 的数量为零或一时，可调用对象的调用在常数时间内实现，即它不取决于 sizeof...(Types) 。

若 variant 的数量大于 1 ，则可调用对象的调用没有复杂度要求。

注解

令 n 为 (1 * ... * std::variant_size_v < std::remove_reference_t <VariantBases>>)，实现通常会为每个 std::visit 的特化生成等价于有 n 个函数指针的（可能多维的）数组的表，这与虚函数的实现类似。

实现亦可为 std::visit 生成有 n 个分支的 switch 语句（例如 MSVC STL 实现在 n 不大于 256 时使用 switch 语句）。

在典型实现上，能认为调用 vis 的时间复杂度等于访问（可能多维的）数组中的元素，或执行 switch 语句的时间复杂度。

示例

#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>

// 要观览的 variant
using var_t = std::variant<int, long, double, std::string>;

// 观览器 #3 的辅助常量
template<class> inline constexpr bool always_false_v = false;

// 观览器 #4 的辅助类型
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
// 显式推导指引（ C++20 起不需要）
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

int main() {
    std::vector<var_t> vec = {10, 15l, 1.5, "hello"};
    for(auto&& v: vec) {
        // 1. void 观览器，仅为其副效应调用
        std::visit([](auto&& arg){std::cout << arg;}, v);

        // 2. 返回值的观览器，返回另一 variant 的常见模式
        var_t w = std::visit([](auto&& arg) -> var_t {return arg + arg;}, v);

        std::cout << ". After doubling, variant holds ";
        // 3. 类型匹配观览器：亦能为带 4 个重载的 operator() 的类
        std::visit([](auto&& arg) {
            using T = std::decay_t<decltype(arg)>;
            if constexpr (std::is_same_v<T, int>)
                std::cout << "int with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, long>)
                std::cout << "long with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, double>)
                std::cout << "double with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, std::string>)
                std::cout << "std::string with value " << std::quoted(arg) << '\n';
            else
                static_assert(always_false_v<T>, "non-exhaustive visitor!");
        }, w);
    }

    for (auto&& v: vec) {
        // 4. 另一种类型匹配观览器：有三个重载的 operator() 的类
        // 注：此情况下 '(auto arg)' 模板 operator() 将绑定到 'int' 与 'long' ，
        //    但若它不存在则 '(double arg)' operator() *亦将* 绑定到 'int' 与 'long' ，
        //    因为两者均可隐式转换成 double 。使用此形式时应留心以正确处理隐式转换。
        std::visit(overloaded {
            [](auto arg) { std::cout << arg << ' '; },
            [](double arg) { std::cout << std::fixed << arg << ' '; },
            [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
        }, v);
    }
}

输出：

10. After doubling, variant holds int with value 20
15. After doubling, variant holds long with value 30
1.5. After doubling, variant holds double with value 3
hello. After doubling, variant holds std::string with value "hellohello"
10 15 1.500000 "hello"

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
LWG 3052 | C++17 | 若 Variants 中的任何类型不是 std::variant 则效果未指定 | 已指定

参阅

swap
 与另一 variant 交换
(公开成员函数)


std::variant<Types...>::~variant

< cpp‎ | utility‎ | variant
~variant(); | (C++17 起) (C++20 前)
constexpr ~variant(); | (C++20 起)

若 valueless_by_exception() 为 true ，则不做任何事。否则销毁当前所含值。

若对于所有 Types... 中的 T_i ， std::is_trivially_destructible_v <T_i> 为 true ，则此析构函数为平凡。

示例

#include <variant>
#include <cstdio>

int main()
{
    struct X { ~X() { puts("X::~X();"); } };
    struct Y { ~Y() { puts("Y::~Y();"); } };

    {
        puts("entering block #1");
        std::variant<X,Y> var;
        puts("leaving block #1");
    }

    {
        puts("entering block #2");
        std::variant<X,Y> var{ std::in_place_index_t<1>{} }; // constructs var(Y)
        puts("leaving block #2");
    }
}

输出：

entering block #1
leaving block #1
X::~X();
entering block #2
leaving block #2
Y::~Y();

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
P2231R1 | C++20 | 析构函数不是 constexpr ，而非平凡析构函数在 C++20 中能为 constexpr | 使之为 constexpr


cppreference.com

C 和 C++ 参考手册

C++ 参考手册
C++98, C++03, C++11, C++14, C++17, C++20, C++23 │ 编译器支持 C++11, C++14, C++17, C++20, C++23

自立实现

语言

基本概念
关键词
预处理器
表达式
声明
初始化
函数
语句
类
重载
模板
异常

头文件

具名要求

功能特性测试宏 (C++20)

语言支持库

源代码信息 (C++20)
类型支持 − 特性 (C++11)
程序工具
协程支持 (C++20)
三路比较 (C++20)
numeric_limits − type_info
initializer_list (C++11)

概念库 (C++20)

诊断库

通用工具库

智能指针和分配器
unique_ptr (C++11)
shared_ptr‏‎‏‎ (C++11)
日期和时间
函数对象 − hash (C++11)
字符串转换 (C++17)
工具函数
pair − tuple (C++11)
optional (C++17) − any (C++17)
variant (C++17) − format (C++20)
basic_stacktrace (C++23)

字符串库

basic_string
basic_string_view (C++17)
空终止字符串：
字节 − 多字节 − 宽

容器库

array (C++11) − vector − deque
map − unordered_map (C++11)
set − unordered_set (C++11)
priority_queue − span (C++20)
其他容器：
顺序 − 关联
无序关联 − 适配器

迭代器库

范围库 (C++20)

算法库

数值库

常用数学函数
数学特殊函数 (C++17)
数学常数 (C++20)
数值算法
伪随机数生成
浮点环境 (C++11)
位操纵 (C++20)
complex − valarray
ratio (C++11)

本地化库

输入/输出库

基于流的 I/O
同步输出 (C++20)
I/O 操纵符

文件系统库 (C++17)

正则表达式库 (C++11)

basic_regex − 算法

原子操作库 (C++11)

atomic − atomic_flag
atomic_ref (C++20)

线程支持库 (C++11)

thread‏‎ − mutex‏‎
condition_variable‏‎
技术规范

标准库扩展 (库基础 TS)

resource_adaptor — invocation_type

标准库扩展 v2 (库基础 TS v2)

propagate_const — ostream_joiner — randint
observer_ptr — 检测手法

标准库扩展 v3 (库基础 TS v3)

scope_exit — scope_fail — scope_success — unique_resource

并发库扩展 (并发 TS) — 事务性内存 (TM TS)
反射 (反射 TS)
外部链接 − 非 ANSI/ISO 库 − 索引 − std 符号索引

C 参考手册
C89, C95, C99, C11, C17, C23

语言

基本概念
关键词
预处理器
表达式
声明
初始化
函数
语句

头文件

类型支持

程序工具

变参数函数

错误处理

动态内存管理

日期和时间工具

字符串库

以空字符结尾的字符串：
字节 − 多字节 − 宽

算法

数值

常用数学函数
浮点环境 (C99)
伪随机数生成
复数算术 (C99)
泛型数学 (C99)

输入/输出支持

本地化支持

原子操作库 (C11)

线程支持库 (C11)
技术规范

动态内存扩展 (动态内存 TR)
浮点扩展，部分 1 (FP 扩展1 TS)
浮点扩展，部分 4 (FP 扩展4 TS)
外部链接 − 非 ANSI/ISO 库 − 索引 − 符号索引
双语术语表
新闻
  • 2019-06-07 ：离线归档的新版本
  • 2018-10-28 ：离线归档的新版本
  • 2018-03-11 ：离线归档的新版本
  • 2017-12-20 ：离线归档（中文）的新版本。
支持我们 − FAQ